Air: replace .dbg_inline_* with .dbg_inline_block

This prevents the possibility of not emitting a `.dbg_inline_end`
instruction and reduces the allocation requirements of the backends.

Closes #19093
This commit is contained in:
Jacob Young 2024-03-02 19:49:20 +01:00 committed by Andrew Kelley
parent 671c2acf47
commit aa688567f5
15 changed files with 413 additions and 344 deletions

View File

@ -443,12 +443,9 @@ pub const Inst = struct {
/// Result type is always void. /// Result type is always void.
/// Uses the `dbg_stmt` field. /// Uses the `dbg_stmt` field.
dbg_stmt, dbg_stmt,
/// Marks the start of an inline call. /// A block that represents an inlined function call.
/// Uses the `ty_fn` field. /// Uses the `ty_pl` field. Payload is `DbgInlineBlock`.
dbg_inline_begin, dbg_inline_block,
/// Marks the end of an inline call.
/// Uses the `ty_fn` field.
dbg_inline_end,
/// Marks the beginning of a local variable. The operand is a pointer pointing /// Marks the beginning of a local variable. The operand is a pointer pointing
/// to the storage for the variable. The local may be a const or a var. /// to the storage for the variable. The local may be a const or a var.
/// Result type is always void. /// Result type is always void.
@ -1051,10 +1048,6 @@ pub const Inst = struct {
// Index into a different array. // Index into a different array.
payload: u32, payload: u32,
}, },
ty_fn: struct {
ty: Ref,
func: InternPool.Index,
},
br: struct { br: struct {
block_inst: Index, block_inst: Index,
operand: Ref, operand: Ref,
@ -1117,6 +1110,12 @@ pub const Block = struct {
body_len: u32, body_len: u32,
}; };
/// Trailing is a list of instruction indexes for every `body_len`.
pub const DbgInlineBlock = struct {
func: InternPool.Index,
body_len: u32,
};
/// Trailing is a list of `Inst.Ref` for every `args_len`. /// Trailing is a list of `Inst.Ref` for every `args_len`.
pub const Call = struct { pub const Call = struct {
args_len: u32, args_len: u32,
@ -1371,6 +1370,7 @@ pub fn typeOfIndex(air: *const Air, inst: Air.Inst.Index, ip: *const InternPool)
.assembly, .assembly,
.block, .block,
.dbg_inline_block,
.struct_field_ptr, .struct_field_ptr,
.struct_field_val, .struct_field_val,
.slice_elem_ptr, .slice_elem_ptr,
@ -1448,8 +1448,6 @@ pub fn typeOfIndex(air: *const Air, inst: Air.Inst.Index, ip: *const InternPool)
.breakpoint, .breakpoint,
.dbg_stmt, .dbg_stmt,
.dbg_inline_begin,
.dbg_inline_end,
.dbg_var_ptr, .dbg_var_ptr,
.dbg_var_val, .dbg_var_val,
.store, .store,
@ -1606,8 +1604,7 @@ pub fn mustLower(air: Air, inst: Air.Inst.Index, ip: *const InternPool) bool {
.@"try", .@"try",
.try_ptr, .try_ptr,
.dbg_stmt, .dbg_stmt,
.dbg_inline_begin, .dbg_inline_block,
.dbg_inline_end,
.dbg_var_ptr, .dbg_var_ptr,
.dbg_var_val, .dbg_var_val,
.ret, .ret,

View File

@ -327,8 +327,6 @@ pub fn categorizeOperand(
.trap, .trap,
.breakpoint, .breakpoint,
.dbg_stmt, .dbg_stmt,
.dbg_inline_begin,
.dbg_inline_end,
.unreach, .unreach,
.ret_addr, .ret_addr,
.frame_addr, .frame_addr,
@ -604,9 +602,19 @@ pub fn categorizeOperand(
.assembly => { .assembly => {
return .complex; return .complex;
}, },
.block => { .block, .dbg_inline_block => |tag| {
const extra = air.extraData(Air.Block, air_datas[@intFromEnum(inst)].ty_pl.payload); const ty_pl = air_datas[@intFromEnum(inst)].ty_pl;
const body: []const Air.Inst.Index = @ptrCast(air.extra[extra.end..][0..extra.data.body_len]); const body: []const Air.Inst.Index = @ptrCast(switch (tag) {
inline .block, .dbg_inline_block => |comptime_tag| body: {
const extra = air.extraData(switch (comptime_tag) {
.block => Air.Block,
.dbg_inline_block => Air.DbgInlineBlock,
else => unreachable,
}, ty_pl.payload);
break :body air.extra[extra.end..][0..extra.data.body_len];
},
else => unreachable,
});
if (body.len == 1 and air_tags[@intFromEnum(body[0])] == .cond_br) { if (body.len == 1 and air_tags[@intFromEnum(body[0])] == .cond_br) {
// Peephole optimization for "panic-like" conditionals, which have // Peephole optimization for "panic-like" conditionals, which have
@ -963,8 +971,6 @@ fn analyzeInst(
.ret_ptr, .ret_ptr,
.breakpoint, .breakpoint,
.dbg_stmt, .dbg_stmt,
.dbg_inline_begin,
.dbg_inline_end,
.fence, .fence,
.ret_addr, .ret_addr,
.frame_addr, .frame_addr,
@ -1235,7 +1241,15 @@ fn analyzeInst(
return big.finish(); return big.finish();
}, },
.block => return analyzeInstBlock(a, pass, data, inst), inline .block, .dbg_inline_block => |comptime_tag| {
const ty_pl = inst_datas[@intFromEnum(inst)].ty_pl;
const extra = a.air.extraData(switch (comptime_tag) {
.block => Air.Block,
.dbg_inline_block => Air.DbgInlineBlock,
else => unreachable,
}, ty_pl.payload);
return analyzeInstBlock(a, pass, data, inst, ty_pl.ty, @ptrCast(a.air.extra[extra.end..][0..extra.data.body_len]));
},
.loop => return analyzeInstLoop(a, pass, data, inst), .loop => return analyzeInstLoop(a, pass, data, inst),
.@"try" => return analyzeInstCondBr(a, pass, data, inst, .@"try"), .@"try" => return analyzeInstCondBr(a, pass, data, inst, .@"try"),
@ -1369,12 +1383,9 @@ fn analyzeInstBlock(
comptime pass: LivenessPass, comptime pass: LivenessPass,
data: *LivenessPassData(pass), data: *LivenessPassData(pass),
inst: Air.Inst.Index, inst: Air.Inst.Index,
ty: Air.Inst.Ref,
body: []const Air.Inst.Index,
) !void { ) !void {
const inst_datas = a.air.instructions.items(.data);
const ty_pl = inst_datas[@intFromEnum(inst)].ty_pl;
const extra = a.air.extraData(Air.Block, ty_pl.payload);
const body: []const Air.Inst.Index = @ptrCast(a.air.extra[extra.end..][0..extra.data.body_len]);
const gpa = a.gpa; const gpa = a.gpa;
// We actually want to do `analyzeOperands` *first*, since our result logically doesn't // We actually want to do `analyzeOperands` *first*, since our result logically doesn't
@ -1403,7 +1414,7 @@ fn analyzeInstBlock(
// If the block is noreturn, block deaths not only aren't useful, they're impossible to // If the block is noreturn, block deaths not only aren't useful, they're impossible to
// find: there could be more stuff alive after the block than before it! // find: there could be more stuff alive after the block than before it!
if (!a.intern_pool.isNoReturn(ty_pl.ty.toType().ip_index)) { if (!a.intern_pool.isNoReturn(ty.toType().toIntern())) {
// The block kills the difference in the live sets // The block kills the difference in the live sets
const block_scope = data.block_scopes.get(inst).?; const block_scope = data.block_scopes.get(inst).?;
const num_deaths = data.live_set.count() - block_scope.live_set.count(); const num_deaths = data.live_set.count() - block_scope.live_set.count();

View File

@ -29,7 +29,7 @@ const LiveMap = std.AutoHashMapUnmanaged(Air.Inst.Index, void);
fn verifyBody(self: *Verify, body: []const Air.Inst.Index) Error!void { fn verifyBody(self: *Verify, body: []const Air.Inst.Index) Error!void {
const ip = self.intern_pool; const ip = self.intern_pool;
const tag = self.air.instructions.items(.tag); const tags = self.air.instructions.items(.tag);
const data = self.air.instructions.items(.data); const data = self.air.instructions.items(.data);
for (body) |inst| { for (body) |inst| {
if (self.liveness.isUnused(inst) and !self.air.mustLower(inst, ip)) { if (self.liveness.isUnused(inst) and !self.air.mustLower(inst, ip)) {
@ -37,7 +37,7 @@ fn verifyBody(self: *Verify, body: []const Air.Inst.Index) Error!void {
continue; continue;
} }
switch (tag[@intFromEnum(inst)]) { switch (tags[@intFromEnum(inst)]) {
// no operands // no operands
.arg, .arg,
.alloc, .alloc,
@ -46,8 +46,6 @@ fn verifyBody(self: *Verify, body: []const Air.Inst.Index) Error!void {
.ret_ptr, .ret_ptr,
.breakpoint, .breakpoint,
.dbg_stmt, .dbg_stmt,
.dbg_inline_begin,
.dbg_inline_end,
.fence, .fence,
.ret_addr, .ret_addr,
.frame_addr, .frame_addr,
@ -431,11 +429,20 @@ fn verifyBody(self: *Verify, body: []const Air.Inst.Index) Error!void {
} }
try self.verifyInst(inst); try self.verifyInst(inst);
}, },
.block => { .block, .dbg_inline_block => |tag| {
const ty_pl = data[@intFromEnum(inst)].ty_pl; const ty_pl = data[@intFromEnum(inst)].ty_pl;
const block_ty = ty_pl.ty.toType(); const block_ty = ty_pl.ty.toType();
const extra = self.air.extraData(Air.Block, ty_pl.payload); const block_body: []const Air.Inst.Index = @ptrCast(switch (tag) {
const block_body: []const Air.Inst.Index = @ptrCast(self.air.extra[extra.end..][0..extra.data.body_len]); inline .block, .dbg_inline_block => |comptime_tag| body: {
const extra = self.air.extraData(switch (comptime_tag) {
.block => Air.Block,
.dbg_inline_block => Air.DbgInlineBlock,
else => unreachable,
}, ty_pl.payload);
break :body self.air.extra[extra.end..][0..extra.data.body_len];
},
else => unreachable,
});
const block_liveness = self.liveness.getBlock(inst); const block_liveness = self.liveness.getBlock(inst);
var orig_live = try self.live.clone(self.gpa); var orig_live = try self.live.clone(self.gpa);

View File

@ -5939,6 +5939,7 @@ fn resolveBlockBody(
if (child_block.is_comptime) { if (child_block.is_comptime) {
return sema.resolveInlineBody(child_block, body, body_inst); return sema.resolveInlineBody(child_block, body, body_inst);
} else { } else {
assert(sema.air_instructions.items(.tag)[@intFromEnum(merges.block_inst)] == .block);
var need_debug_scope = false; var need_debug_scope = false;
child_block.need_debug_scope = &need_debug_scope; child_block.need_debug_scope = &need_debug_scope;
if (sema.analyzeBodyInner(child_block, body)) |_| { if (sema.analyzeBodyInner(child_block, body)) |_| {
@ -6002,18 +6003,44 @@ fn resolveAnalyzedBlock(
assert(child_block.instructions.items.len != 0); assert(child_block.instructions.items.len != 0);
assert(sema.typeOf(child_block.instructions.items[child_block.instructions.items.len - 1].toRef()).isNoReturn(mod)); assert(sema.typeOf(child_block.instructions.items[child_block.instructions.items.len - 1].toRef()).isNoReturn(mod));
const block_tag = sema.air_instructions.items(.tag)[@intFromEnum(merges.block_inst)];
switch (block_tag) {
.block => {},
.dbg_inline_block => assert(need_debug_scope),
else => unreachable,
}
if (merges.results.items.len == 0) { if (merges.results.items.len == 0) {
// No need for a block instruction. We can put the new instructions switch (block_tag) {
// directly into the parent block. .block => {
if (need_debug_scope) { // No need for a block instruction. We can put the new instructions
// The code following this block is unreachable, as the block has no // directly into the parent block.
// merges, so we don't necessarily need to emit this as an AIR block. if (need_debug_scope) {
// However, we need a block *somewhere* to make the scoping correct, // The code following this block is unreachable, as the block has no
// so forward this request to the parent block. // merges, so we don't necessarily need to emit this as an AIR block.
if (parent_block.need_debug_scope) |ptr| ptr.* = true; // However, we need a block *somewhere* to make the scoping correct,
// so forward this request to the parent block.
if (parent_block.need_debug_scope) |ptr| ptr.* = true;
}
try parent_block.instructions.appendSlice(gpa, child_block.instructions.items);
return child_block.instructions.items[child_block.instructions.items.len - 1].toRef();
},
.dbg_inline_block => {
// Create a block containing all instruction from the body.
try parent_block.instructions.append(gpa, merges.block_inst);
try sema.air_extra.ensureUnusedCapacity(gpa, @typeInfo(Air.DbgInlineBlock).Struct.fields.len +
child_block.instructions.items.len);
sema.air_instructions.items(.data)[@intFromEnum(merges.block_inst)] = .{ .ty_pl = .{
.ty = .noreturn_type,
.payload = sema.addExtraAssumeCapacity(Air.DbgInlineBlock{
.func = child_block.inlining.?.func,
.body_len = @intCast(child_block.instructions.items.len),
}),
} };
sema.air_extra.appendSliceAssumeCapacity(@ptrCast(child_block.instructions.items));
return merges.block_inst.toRef();
},
else => unreachable,
} }
try parent_block.instructions.appendSlice(gpa, child_block.instructions.items);
return child_block.instructions.items[child_block.instructions.items.len - 1].toRef();
} }
if (merges.results.items.len == 1) { if (merges.results.items.len == 1) {
// If the `break` is trailing, we may be able to elide the AIR block here // If the `break` is trailing, we may be able to elide the AIR block here
@ -6036,14 +6063,30 @@ fn resolveAnalyzedBlock(
if (try sema.resolveValue(merges.results.items[0])) |result_val| { if (try sema.resolveValue(merges.results.items[0])) |result_val| {
// Create a block containing all instruction from the body. // Create a block containing all instruction from the body.
try parent_block.instructions.append(gpa, merges.block_inst); try parent_block.instructions.append(gpa, merges.block_inst);
try sema.air_extra.ensureUnusedCapacity(gpa, @typeInfo(Air.Block).Struct.fields.len + switch (block_tag) {
child_block.instructions.items.len); .block => {
sema.air_instructions.items(.data)[@intFromEnum(merges.block_inst)] = .{ .ty_pl = .{ try sema.air_extra.ensureUnusedCapacity(gpa, @typeInfo(Air.Block).Struct.fields.len +
.ty = .void_type, child_block.instructions.items.len);
.payload = sema.addExtraAssumeCapacity(Air.Block{ sema.air_instructions.items(.data)[@intFromEnum(merges.block_inst)] = .{ .ty_pl = .{
.body_len = @intCast(child_block.instructions.items.len), .ty = .void_type,
}), .payload = sema.addExtraAssumeCapacity(Air.Block{
} }; .body_len = @intCast(child_block.instructions.items.len),
}),
} };
},
.dbg_inline_block => {
try sema.air_extra.ensureUnusedCapacity(gpa, @typeInfo(Air.DbgInlineBlock).Struct.fields.len +
child_block.instructions.items.len);
sema.air_instructions.items(.data)[@intFromEnum(merges.block_inst)] = .{ .ty_pl = .{
.ty = .void_type,
.payload = sema.addExtraAssumeCapacity(Air.DbgInlineBlock{
.func = child_block.inlining.?.func,
.body_len = @intCast(child_block.instructions.items.len),
}),
} };
},
else => unreachable,
}
sema.air_extra.appendSliceAssumeCapacity(@ptrCast(child_block.instructions.items)); sema.air_extra.appendSliceAssumeCapacity(@ptrCast(child_block.instructions.items));
// Rewrite the break to just give value {}; the value is // Rewrite the break to just give value {}; the value is
// comptime-known and will be returned directly. // comptime-known and will be returned directly.
@ -6079,14 +6122,30 @@ fn resolveAnalyzedBlock(
return sema.failWithOwnedErrorMsg(child_block, msg); return sema.failWithOwnedErrorMsg(child_block, msg);
} }
const ty_inst = Air.internedToRef(resolved_ty.toIntern()); const ty_inst = Air.internedToRef(resolved_ty.toIntern());
try sema.air_extra.ensureUnusedCapacity(gpa, @typeInfo(Air.Block).Struct.fields.len + switch (block_tag) {
child_block.instructions.items.len); .block => {
sema.air_instructions.items(.data)[@intFromEnum(merges.block_inst)] = .{ .ty_pl = .{ try sema.air_extra.ensureUnusedCapacity(gpa, @typeInfo(Air.Block).Struct.fields.len +
.ty = ty_inst, child_block.instructions.items.len);
.payload = sema.addExtraAssumeCapacity(Air.Block{ sema.air_instructions.items(.data)[@intFromEnum(merges.block_inst)] = .{ .ty_pl = .{
.body_len = @intCast(child_block.instructions.items.len), .ty = ty_inst,
}), .payload = sema.addExtraAssumeCapacity(Air.Block{
} }; .body_len = @intCast(child_block.instructions.items.len),
}),
} };
},
.dbg_inline_block => {
try sema.air_extra.ensureUnusedCapacity(gpa, @typeInfo(Air.DbgInlineBlock).Struct.fields.len +
child_block.instructions.items.len);
sema.air_instructions.items(.data)[@intFromEnum(merges.block_inst)] = .{ .ty_pl = .{
.ty = ty_inst,
.payload = sema.addExtraAssumeCapacity(Air.DbgInlineBlock{
.func = child_block.inlining.?.func,
.body_len = @intCast(child_block.instructions.items.len),
}),
} };
},
else => unreachable,
}
sema.air_extra.appendSliceAssumeCapacity(@ptrCast(child_block.instructions.items)); sema.air_extra.appendSliceAssumeCapacity(@ptrCast(child_block.instructions.items));
// Now that the block has its type resolved, we need to go back into all the break // Now that the block has its type resolved, we need to go back into all the break
// instructions, and insert type coercion on the operands. // instructions, and insert type coercion on the operands.
@ -7379,7 +7438,6 @@ fn analyzeCall(
.needed_comptime_reason = "function being called at comptime must be comptime-known", .needed_comptime_reason = "function being called at comptime must be comptime-known",
.block_comptime_reason = comptime_reason, .block_comptime_reason = comptime_reason,
}); });
const prev_fn_index = sema.func_index;
const module_fn_index = switch (mod.intern_pool.indexToKey(func_val.toIntern())) { const module_fn_index = switch (mod.intern_pool.indexToKey(func_val.toIntern())) {
.extern_func => return sema.fail(block, call_src, "{s} call of extern function", .{ .extern_func => return sema.fail(block, call_src, "{s} call of extern function", .{
@as([]const u8, if (is_comptime_call) "comptime" else "inline"), @as([]const u8, if (is_comptime_call) "comptime" else "inline"),
@ -7415,9 +7473,10 @@ fn analyzeCall(
// set to in the `Block`. // set to in the `Block`.
// This block instruction will be used to capture the return value from the // This block instruction will be used to capture the return value from the
// inlined function. // inlined function.
const need_debug_scope = !is_comptime_call and !block.is_typeof and !block.ownerModule().strip;
const block_inst: Air.Inst.Index = @enumFromInt(sema.air_instructions.len); const block_inst: Air.Inst.Index = @enumFromInt(sema.air_instructions.len);
try sema.air_instructions.append(gpa, .{ try sema.air_instructions.append(gpa, .{
.tag = .block, .tag = if (need_debug_scope) .dbg_inline_block else .block,
.data = undefined, .data = undefined,
}); });
// This one is shared among sub-blocks within the same callee, but not // This one is shared among sub-blocks within the same callee, but not
@ -7584,10 +7643,7 @@ fn analyzeCall(
} }
new_fn_info.return_type = sema.fn_ret_ty.toIntern(); new_fn_info.return_type = sema.fn_ret_ty.toIntern();
const new_func_resolved_ty = try mod.funcType(new_fn_info);
if (!is_comptime_call and !block.is_typeof) { if (!is_comptime_call and !block.is_typeof) {
try emitDbgInline(block, prev_fn_index, module_fn_index, new_func_resolved_ty, .dbg_inline_begin);
const zir_tags = sema.code.instructions.items(.tag); const zir_tags = sema.code.instructions.items(.tag);
for (fn_info.param_body) |param| switch (zir_tags[@intFromEnum(param)]) { for (fn_info.param_body) |param| switch (zir_tags[@intFromEnum(param)]) {
.param, .param_comptime => { .param, .param_comptime => {
@ -7626,21 +7682,9 @@ fn analyzeCall(
error.ComptimeReturn => break :result inlining.comptime_result, error.ComptimeReturn => break :result inlining.comptime_result,
else => |e| return e, else => |e| return e,
}; };
break :result try sema.resolveAnalyzedBlock(block, call_src, &child_block, merges, false); break :result try sema.resolveAnalyzedBlock(block, call_src, &child_block, merges, need_debug_scope);
}; };
if (!is_comptime_call and !block.is_typeof and
sema.typeOf(result).zigTypeTag(mod) != .NoReturn)
{
try emitDbgInline(
block,
module_fn_index,
prev_fn_index,
mod.funcOwnerDeclPtr(sema.func_index).ty,
.dbg_inline_end,
);
}
if (should_memoize and is_comptime_call) { if (should_memoize and is_comptime_call) {
const result_val = try sema.resolveConstValue(block, .unneeded, result, undefined); const result_val = try sema.resolveConstValue(block, .unneeded, result, undefined);
const result_interned = try result_val.intern2(sema.fn_ret_ty, mod); const result_interned = try result_val.intern2(sema.fn_ret_ty, mod);
@ -8207,27 +8251,6 @@ fn resolveTupleLazyValues(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Type)
} }
} }
fn emitDbgInline(
block: *Block,
old_func: InternPool.Index,
new_func: InternPool.Index,
new_func_ty: Type,
tag: Air.Inst.Tag,
) CompileError!void {
if (block.ownerModule().strip) return;
// Recursive inline call; no dbg_inline needed.
if (old_func == new_func) return;
_ = try block.addInst(.{
.tag = tag,
.data = .{ .ty_fn = .{
.ty = Air.internedToRef(new_func_ty.toIntern()),
.func = new_func,
} },
});
}
fn zirIntType(sema: *Sema, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { fn zirIntType(sema: *Sema, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
const mod = sema.mod; const mod = sema.mod;
const int_type = sema.code.instructions.items(.data)[@intFromEnum(inst)].int_type; const int_type = sema.code.instructions.items(.data)[@intFromEnum(inst)].int_type;

View File

@ -747,7 +747,6 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
.frame_addr => try self.airFrameAddress(inst), .frame_addr => try self.airFrameAddress(inst),
.fence => try self.airFence(), .fence => try self.airFence(),
.cond_br => try self.airCondBr(inst), .cond_br => try self.airCondBr(inst),
.dbg_stmt => try self.airDbgStmt(inst),
.fptrunc => try self.airFptrunc(inst), .fptrunc => try self.airFptrunc(inst),
.fpext => try self.airFpext(inst), .fpext => try self.airFpext(inst),
.intcast => try self.airIntCast(inst), .intcast => try self.airIntCast(inst),
@ -805,14 +804,12 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
.@"try" => try self.airTry(inst), .@"try" => try self.airTry(inst),
.try_ptr => try self.airTryPtr(inst), .try_ptr => try self.airTryPtr(inst),
.dbg_stmt => try self.airDbgStmt(inst),
.dbg_inline_block => try self.airDbgInlineBlock(inst),
.dbg_var_ptr, .dbg_var_ptr,
.dbg_var_val, .dbg_var_val,
=> try self.airDbgVar(inst), => try self.airDbgVar(inst),
.dbg_inline_begin,
.dbg_inline_end,
=> try self.airDbgInline(inst),
.call => try self.airCall(inst, .auto), .call => try self.airCall(inst, .auto),
.call_always_tail => try self.airCall(inst, .always_tail), .call_always_tail => try self.airCall(inst, .always_tail),
.call_never_tail => try self.airCall(inst, .never_tail), .call_never_tail => try self.airCall(inst, .never_tail),
@ -4621,13 +4618,14 @@ fn airDbgStmt(self: *Self, inst: Air.Inst.Index) !void {
return self.finishAirBookkeeping(); return self.finishAirBookkeeping();
} }
fn airDbgInline(self: *Self, inst: Air.Inst.Index) !void { fn airDbgInlineBlock(self: *Self, inst: Air.Inst.Index) !void {
const ty_fn = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_fn;
const mod = self.bin_file.comp.module.?; const mod = self.bin_file.comp.module.?;
const func = mod.funcInfo(ty_fn.func); const ty_pl = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;
const extra = self.air.extraData(Air.DbgInlineBlock, ty_pl.payload);
const func = mod.funcInfo(extra.data.func);
// TODO emit debug info for function change // TODO emit debug info for function change
_ = func; _ = func;
return self.finishAir(inst, .dead, .{ .none, .none, .none }); try self.lowerBlock(inst, @ptrCast(self.air.extra[extra.end..][0..extra.data.body_len]));
} }
fn airDbgVar(self: *Self, inst: Air.Inst.Index) !void { fn airDbgVar(self: *Self, inst: Air.Inst.Index) !void {
@ -5042,6 +5040,12 @@ fn jump(self: *Self, inst: Mir.Inst.Index) !void {
} }
fn airBlock(self: *Self, inst: Air.Inst.Index) !void { fn airBlock(self: *Self, inst: Air.Inst.Index) !void {
const ty_pl = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;
const extra = self.air.extraData(Air.Block, ty_pl.payload);
try self.lowerBlock(inst, @ptrCast(self.air.extra[extra.end..][0..extra.data.body_len]));
}
fn lowerBlock(self: *Self, inst: Air.Inst.Index, body: []const Air.Inst.Index) !void {
try self.blocks.putNoClobber(self.gpa, inst, .{ try self.blocks.putNoClobber(self.gpa, inst, .{
// A block is a setup to be able to jump to the end. // A block is a setup to be able to jump to the end.
.relocs = .{}, .relocs = .{},
@ -5054,9 +5058,6 @@ fn airBlock(self: *Self, inst: Air.Inst.Index) !void {
}); });
defer self.blocks.getPtr(inst).?.relocs.deinit(self.gpa); defer self.blocks.getPtr(inst).?.relocs.deinit(self.gpa);
const ty_pl = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;
const extra = self.air.extraData(Air.Block, ty_pl.payload);
const body: []const Air.Inst.Index = @ptrCast(self.air.extra[extra.end..][0..extra.data.body_len]);
// TODO emit debug info lexical block // TODO emit debug info lexical block
try self.genBody(body); try self.genBody(body);

View File

@ -733,7 +733,6 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
.frame_addr => try self.airFrameAddress(inst), .frame_addr => try self.airFrameAddress(inst),
.fence => try self.airFence(), .fence => try self.airFence(),
.cond_br => try self.airCondBr(inst), .cond_br => try self.airCondBr(inst),
.dbg_stmt => try self.airDbgStmt(inst),
.fptrunc => try self.airFptrunc(inst), .fptrunc => try self.airFptrunc(inst),
.fpext => try self.airFpext(inst), .fpext => try self.airFpext(inst),
.intcast => try self.airIntCast(inst), .intcast => try self.airIntCast(inst),
@ -791,14 +790,12 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
.@"try" => try self.airTry(inst), .@"try" => try self.airTry(inst),
.try_ptr => try self.airTryPtr(inst), .try_ptr => try self.airTryPtr(inst),
.dbg_stmt => try self.airDbgStmt(inst),
.dbg_inline_block => try self.airDbgInlineBlock(inst),
.dbg_var_ptr, .dbg_var_ptr,
.dbg_var_val, .dbg_var_val,
=> try self.airDbgVar(inst), => try self.airDbgVar(inst),
.dbg_inline_begin,
.dbg_inline_end,
=> try self.airDbgInline(inst),
.call => try self.airCall(inst, .auto), .call => try self.airCall(inst, .auto),
.call_always_tail => try self.airCall(inst, .always_tail), .call_always_tail => try self.airCall(inst, .always_tail),
.call_never_tail => try self.airCall(inst, .never_tail), .call_never_tail => try self.airCall(inst, .never_tail),
@ -4574,13 +4571,14 @@ fn airDbgStmt(self: *Self, inst: Air.Inst.Index) !void {
return self.finishAirBookkeeping(); return self.finishAirBookkeeping();
} }
fn airDbgInline(self: *Self, inst: Air.Inst.Index) !void { fn airDbgInlineBlock(self: *Self, inst: Air.Inst.Index) !void {
const ty_fn = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_fn;
const mod = self.bin_file.comp.module.?; const mod = self.bin_file.comp.module.?;
const func = mod.funcInfo(ty_fn.func); const ty_pl = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;
const extra = self.air.extraData(Air.DbgInlineBlock, ty_pl.payload);
const func = mod.funcInfo(extra.data.func);
// TODO emit debug info for function change // TODO emit debug info for function change
_ = func; _ = func;
return self.finishAir(inst, .dead, .{ .none, .none, .none }); try self.lowerBlock(inst, @ptrCast(self.air.extra[extra.end..][0..extra.data.body_len]));
} }
fn airDbgVar(self: *Self, inst: Air.Inst.Index) !void { fn airDbgVar(self: *Self, inst: Air.Inst.Index) !void {
@ -4973,6 +4971,12 @@ fn jump(self: *Self, inst: Mir.Inst.Index) !void {
} }
fn airBlock(self: *Self, inst: Air.Inst.Index) !void { fn airBlock(self: *Self, inst: Air.Inst.Index) !void {
const ty_pl = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;
const extra = self.air.extraData(Air.Block, ty_pl.payload);
try self.lowerBlock(inst, @ptrCast(self.air.extra[extra.end..][0..extra.data.body_len]));
}
fn lowerBlock(self: *Self, inst: Air.Inst.Index, body: []const Air.Inst.Index) !void {
try self.blocks.putNoClobber(self.gpa, inst, .{ try self.blocks.putNoClobber(self.gpa, inst, .{
// A block is a setup to be able to jump to the end. // A block is a setup to be able to jump to the end.
.relocs = .{}, .relocs = .{},
@ -4985,9 +4989,6 @@ fn airBlock(self: *Self, inst: Air.Inst.Index) !void {
}); });
defer self.blocks.getPtr(inst).?.relocs.deinit(self.gpa); defer self.blocks.getPtr(inst).?.relocs.deinit(self.gpa);
const ty_pl = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;
const extra = self.air.extraData(Air.Block, ty_pl.payload);
const body: []const Air.Inst.Index = @ptrCast(self.air.extra[extra.end..][0..extra.data.body_len]);
// TODO emit debug info lexical block // TODO emit debug info lexical block
try self.genBody(body); try self.genBody(body);

View File

@ -566,7 +566,6 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
.frame_addr => try self.airFrameAddress(inst), .frame_addr => try self.airFrameAddress(inst),
.fence => try self.airFence(), .fence => try self.airFence(),
.cond_br => try self.airCondBr(inst), .cond_br => try self.airCondBr(inst),
.dbg_stmt => try self.airDbgStmt(inst),
.fptrunc => try self.airFptrunc(inst), .fptrunc => try self.airFptrunc(inst),
.fpext => try self.airFpext(inst), .fpext => try self.airFpext(inst),
.intcast => try self.airIntCast(inst), .intcast => try self.airIntCast(inst),
@ -624,14 +623,12 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
.@"try" => @panic("TODO"), .@"try" => @panic("TODO"),
.try_ptr => @panic("TODO"), .try_ptr => @panic("TODO"),
.dbg_stmt => try self.airDbgStmt(inst),
.dbg_inline_block => try self.airDbgInlineBlock(inst),
.dbg_var_ptr, .dbg_var_ptr,
.dbg_var_val, .dbg_var_val,
=> try self.airDbgVar(inst), => try self.airDbgVar(inst),
.dbg_inline_begin,
.dbg_inline_end,
=> try self.airDbgInline(inst),
.call => try self.airCall(inst, .auto), .call => try self.airCall(inst, .auto),
.call_always_tail => try self.airCall(inst, .always_tail), .call_always_tail => try self.airCall(inst, .always_tail),
.call_never_tail => try self.airCall(inst, .never_tail), .call_never_tail => try self.airCall(inst, .never_tail),
@ -1881,13 +1878,14 @@ fn airDbgStmt(self: *Self, inst: Air.Inst.Index) !void {
return self.finishAirBookkeeping(); return self.finishAirBookkeeping();
} }
fn airDbgInline(self: *Self, inst: Air.Inst.Index) !void { fn airDbgInlineBlock(self: *Self, inst: Air.Inst.Index) !void {
const ty_fn = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_fn;
const mod = self.bin_file.comp.module.?; const mod = self.bin_file.comp.module.?;
const func = mod.funcInfo(ty_fn.func); const ty_pl = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;
const extra = self.air.extraData(Air.DbgInlineBlock, ty_pl.payload);
const func = mod.funcInfo(extra.data.func);
// TODO emit debug info for function change // TODO emit debug info for function change
_ = func; _ = func;
return self.finishAir(inst, .dead, .{ .none, .none, .none }); try self.lowerBlock(inst, @ptrCast(self.air.extra[extra.end..][0..extra.data.body_len]));
} }
fn airDbgVar(self: *Self, inst: Air.Inst.Index) !void { fn airDbgVar(self: *Self, inst: Air.Inst.Index) !void {
@ -2060,6 +2058,12 @@ fn jump(self: *Self, index: usize) !void {
} }
fn airBlock(self: *Self, inst: Air.Inst.Index) !void { fn airBlock(self: *Self, inst: Air.Inst.Index) !void {
const ty_pl = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;
const extra = self.air.extraData(Air.Block, ty_pl.payload);
try self.lowerBlock(inst, @ptrCast(self.air.extra[extra.end..][0..extra.data.body_len]));
}
fn lowerBlock(self: *Self, inst: Air.Inst.Index, body: []const Air.Inst.Index) !void {
try self.blocks.putNoClobber(self.gpa, inst, .{ try self.blocks.putNoClobber(self.gpa, inst, .{
// A block is a setup to be able to jump to the end. // A block is a setup to be able to jump to the end.
.relocs = .{}, .relocs = .{},
@ -2071,10 +2075,6 @@ fn airBlock(self: *Self, inst: Air.Inst.Index) !void {
.mcv = MCValue{ .none = {} }, .mcv = MCValue{ .none = {} },
}); });
defer self.blocks.getPtr(inst).?.relocs.deinit(self.gpa); defer self.blocks.getPtr(inst).?.relocs.deinit(self.gpa);
const ty_pl = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;
const extra = self.air.extraData(Air.Block, ty_pl.payload);
const body: []const Air.Inst.Index = @ptrCast(self.air.extra[extra.end..][0..extra.data.body_len]);
// TODO emit debug info lexical block // TODO emit debug info lexical block
try self.genBody(body); try self.genBody(body);

View File

@ -579,7 +579,6 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
.frame_addr => @panic("TODO try self.airFrameAddress(inst)"), .frame_addr => @panic("TODO try self.airFrameAddress(inst)"),
.fence => try self.airFence(inst), .fence => try self.airFence(inst),
.cond_br => try self.airCondBr(inst), .cond_br => try self.airCondBr(inst),
.dbg_stmt => try self.airDbgStmt(inst),
.fptrunc => @panic("TODO try self.airFptrunc(inst)"), .fptrunc => @panic("TODO try self.airFptrunc(inst)"),
.fpext => @panic("TODO try self.airFpext(inst)"), .fpext => @panic("TODO try self.airFpext(inst)"),
.intcast => try self.airIntCast(inst), .intcast => try self.airIntCast(inst),
@ -637,14 +636,12 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
.@"try" => try self.airTry(inst), .@"try" => try self.airTry(inst),
.try_ptr => @panic("TODO try self.airTryPtr(inst)"), .try_ptr => @panic("TODO try self.airTryPtr(inst)"),
.dbg_stmt => try self.airDbgStmt(inst),
.dbg_inline_block => try self.airDbgInlineBlock(inst),
.dbg_var_ptr, .dbg_var_ptr,
.dbg_var_val, .dbg_var_val,
=> try self.airDbgVar(inst), => try self.airDbgVar(inst),
.dbg_inline_begin,
.dbg_inline_end,
=> try self.airDbgInline(inst),
.call => try self.airCall(inst, .auto), .call => try self.airCall(inst, .auto),
.call_always_tail => try self.airCall(inst, .always_tail), .call_always_tail => try self.airCall(inst, .always_tail),
.call_never_tail => try self.airCall(inst, .never_tail), .call_never_tail => try self.airCall(inst, .never_tail),
@ -1127,6 +1124,12 @@ fn airBitReverse(self: *Self, inst: Air.Inst.Index) !void {
} }
fn airBlock(self: *Self, inst: Air.Inst.Index) !void { fn airBlock(self: *Self, inst: Air.Inst.Index) !void {
const ty_pl = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;
const extra = self.air.extraData(Air.Block, ty_pl.payload);
try self.lowerBlock(inst, @ptrCast(self.air.extra[extra.end..][0..extra.data.body_len]));
}
fn lowerBlock(self: *Self, inst: Air.Inst.Index, body: []const Air.Inst.Index) !void {
try self.blocks.putNoClobber(self.gpa, inst, .{ try self.blocks.putNoClobber(self.gpa, inst, .{
// A block is a setup to be able to jump to the end. // A block is a setup to be able to jump to the end.
.relocs = .{}, .relocs = .{},
@ -1139,9 +1142,6 @@ fn airBlock(self: *Self, inst: Air.Inst.Index) !void {
}); });
defer self.blocks.getPtr(inst).?.relocs.deinit(self.gpa); defer self.blocks.getPtr(inst).?.relocs.deinit(self.gpa);
const ty_pl = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;
const extra = self.air.extraData(Air.Block, ty_pl.payload);
const body: []const Air.Inst.Index = @ptrCast(self.air.extra[extra.end..][0..extra.data.body_len]);
// TODO emit debug info lexical block // TODO emit debug info lexical block
try self.genBody(body); try self.genBody(body);
@ -1652,13 +1652,14 @@ fn airCtz(self: *Self, inst: Air.Inst.Index) !void {
return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
} }
fn airDbgInline(self: *Self, inst: Air.Inst.Index) !void { fn airDbgInlineBlock(self: *Self, inst: Air.Inst.Index) !void {
const ty_fn = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_fn;
const mod = self.bin_file.comp.module.?; const mod = self.bin_file.comp.module.?;
const func = mod.funcInfo(ty_fn.func); const ty_pl = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;
const extra = self.air.extraData(Air.DbgInlineBlock, ty_pl.payload);
const func = mod.funcInfo(extra.data.func);
// TODO emit debug info for function change // TODO emit debug info for function change
_ = func; _ = func;
return self.finishAir(inst, .dead, .{ .none, .none, .none }); try self.lowerBlock(inst, @ptrCast(self.air.extra[extra.end..][0..extra.data.body_len]));
} }
fn airDbgStmt(self: *Self, inst: Air.Inst.Index) !void { fn airDbgStmt(self: *Self, inst: Air.Inst.Index) !void {

View File

@ -1910,16 +1910,11 @@ fn genInst(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
.@"try" => func.airTry(inst), .@"try" => func.airTry(inst),
.try_ptr => func.airTryPtr(inst), .try_ptr => func.airTryPtr(inst),
// TODO .dbg_stmt => func.airDbgStmt(inst),
.dbg_inline_begin, .dbg_inline_block => func.airDbgInlineBlock(inst),
.dbg_inline_end,
=> func.finishAir(inst, .none, &.{}),
.dbg_var_ptr => func.airDbgVar(inst, true), .dbg_var_ptr => func.airDbgVar(inst, true),
.dbg_var_val => func.airDbgVar(inst, false), .dbg_var_val => func.airDbgVar(inst, false),
.dbg_stmt => func.airDbgStmt(inst),
.call => func.airCall(inst, .auto), .call => func.airCall(inst, .auto),
.call_always_tail => func.airCall(inst, .always_tail), .call_always_tail => func.airCall(inst, .always_tail),
.call_never_tail => func.airCall(inst, .never_tail), .call_never_tail => func.airCall(inst, .never_tail),
@ -3476,12 +3471,14 @@ fn intStorageAsI32(storage: InternPool.Key.Int.Storage, mod: *Module) i32 {
} }
fn airBlock(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { fn airBlock(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
const mod = func.bin_file.base.comp.module.?;
const ty_pl = func.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl; const ty_pl = func.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;
const block_ty = ty_pl.ty.toType();
const wasm_block_ty = genBlockType(block_ty, mod);
const extra = func.air.extraData(Air.Block, ty_pl.payload); const extra = func.air.extraData(Air.Block, ty_pl.payload);
const body: []const Air.Inst.Index = @ptrCast(func.air.extra[extra.end..][0..extra.data.body_len]); try func.lowerBlock(inst, ty_pl.ty.toType(), @ptrCast(func.air.extra[extra.end..][0..extra.data.body_len]));
}
fn lowerBlock(func: *CodeGen, inst: Air.Inst.Index, block_ty: Type, body: []const Air.Inst.Index) InnerError!void {
const mod = func.bin_file.base.comp.module.?;
const wasm_block_ty = genBlockType(block_ty, mod);
// if wasm_block_ty is non-empty, we create a register to store the temporary value // if wasm_block_ty is non-empty, we create a register to store the temporary value
const block_result: WValue = if (wasm_block_ty != wasm.block_empty) blk: { const block_result: WValue = if (wasm_block_ty != wasm.block_empty) blk: {
@ -6472,7 +6469,27 @@ fn airCtz(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
func.finishAir(inst, result, &.{ty_op.operand}); func.finishAir(inst, result, &.{ty_op.operand});
} }
fn airDbgVar(func: *CodeGen, inst: Air.Inst.Index, is_ptr: bool) !void { fn airDbgStmt(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
if (func.debug_output != .dwarf) return func.finishAir(inst, .none, &.{});
const dbg_stmt = func.air.instructions.items(.data)[@intFromEnum(inst)].dbg_stmt;
try func.addInst(.{ .tag = .dbg_line, .data = .{
.payload = try func.addExtra(Mir.DbgLineColumn{
.line = dbg_stmt.line,
.column = dbg_stmt.column,
}),
} });
func.finishAir(inst, .none, &.{});
}
fn airDbgInlineBlock(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
const ty_pl = func.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;
const extra = func.air.extraData(Air.DbgInlineBlock, ty_pl.payload);
// TODO
try func.lowerBlock(inst, ty_pl.ty.toType(), @ptrCast(func.air.extra[extra.end..][0..extra.data.body_len]));
}
fn airDbgVar(func: *CodeGen, inst: Air.Inst.Index, is_ptr: bool) InnerError!void {
if (func.debug_output != .dwarf) return func.finishAir(inst, .none, &.{}); if (func.debug_output != .dwarf) return func.finishAir(inst, .none, &.{});
const mod = func.bin_file.base.comp.module.?; const mod = func.bin_file.base.comp.module.?;
@ -6497,19 +6514,6 @@ fn airDbgVar(func: *CodeGen, inst: Air.Inst.Index, is_ptr: bool) !void {
func.finishAir(inst, .none, &.{}); func.finishAir(inst, .none, &.{});
} }
fn airDbgStmt(func: *CodeGen, inst: Air.Inst.Index) !void {
if (func.debug_output != .dwarf) return func.finishAir(inst, .none, &.{});
const dbg_stmt = func.air.instructions.items(.data)[@intFromEnum(inst)].dbg_stmt;
try func.addInst(.{ .tag = .dbg_line, .data = .{
.payload = try func.addExtra(Mir.DbgLineColumn{
.line = dbg_stmt.line,
.column = dbg_stmt.column,
}),
} });
func.finishAir(inst, .none, &.{});
}
fn airTry(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { fn airTry(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
const pl_op = func.air.instructions.items(.data)[@intFromEnum(inst)].pl_op; const pl_op = func.air.instructions.items(.data)[@intFromEnum(inst)].pl_op;
const err_union = try func.resolveInst(pl_op.operand); const err_union = try func.resolveInst(pl_op.operand);

View File

@ -58,6 +58,7 @@ bin_file: *link.File,
debug_output: DebugInfoOutput, debug_output: DebugInfoOutput,
target: *const std.Target, target: *const std.Target,
owner: Owner, owner: Owner,
inline_func: InternPool.Index,
mod: *Package.Module, mod: *Package.Module,
err_msg: ?*ErrorMsg, err_msg: ?*ErrorMsg,
args: []MCValue, args: []MCValue,
@ -820,6 +821,7 @@ pub fn generate(
.bin_file = bin_file, .bin_file = bin_file,
.debug_output = debug_output, .debug_output = debug_output,
.owner = .{ .func_index = func_index }, .owner = .{ .func_index = func_index },
.inline_func = func_index,
.err_msg = null, .err_msg = null,
.args = undefined, // populated after `resolveCallingConventionValues` .args = undefined, // populated after `resolveCallingConventionValues`
.va_info = undefined, // populated after `resolveCallingConventionValues` .va_info = undefined, // populated after `resolveCallingConventionValues`
@ -987,6 +989,7 @@ pub fn generateLazy(
.bin_file = bin_file, .bin_file = bin_file,
.debug_output = debug_output, .debug_output = debug_output,
.owner = .{ .lazy_sym = lazy_sym }, .owner = .{ .lazy_sym = lazy_sym },
.inline_func = undefined,
.err_msg = null, .err_msg = null,
.args = undefined, .args = undefined,
.va_info = undefined, .va_info = undefined,
@ -2042,7 +2045,6 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
.frame_addr => try self.airFrameAddress(inst), .frame_addr => try self.airFrameAddress(inst),
.fence => try self.airFence(inst), .fence => try self.airFence(inst),
.cond_br => try self.airCondBr(inst), .cond_br => try self.airCondBr(inst),
.dbg_stmt => try self.airDbgStmt(inst),
.fptrunc => try self.airFptrunc(inst), .fptrunc => try self.airFptrunc(inst),
.fpext => try self.airFpext(inst), .fpext => try self.airFpext(inst),
.intcast => try self.airIntCast(inst), .intcast => try self.airIntCast(inst),
@ -2098,14 +2100,12 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
.@"try" => try self.airTry(inst), .@"try" => try self.airTry(inst),
.try_ptr => try self.airTryPtr(inst), .try_ptr => try self.airTryPtr(inst),
.dbg_stmt => try self.airDbgStmt(inst),
.dbg_inline_block => try self.airDbgInlineBlock(inst),
.dbg_var_ptr, .dbg_var_ptr,
.dbg_var_val, .dbg_var_val,
=> try self.airDbgVar(inst), => try self.airDbgVar(inst),
.dbg_inline_begin,
.dbg_inline_end,
=> try self.airDbgInline(inst),
.call => try self.airCall(inst, .auto), .call => try self.airCall(inst, .auto),
.call_always_tail => try self.airCall(inst, .always_tail), .call_always_tail => try self.airCall(inst, .always_tail),
.call_never_tail => try self.airCall(inst, .never_tail), .call_never_tail => try self.airCall(inst, .never_tail),
@ -12962,14 +12962,23 @@ fn airDbgStmt(self: *Self, inst: Air.Inst.Index) !void {
self.finishAirBookkeeping(); self.finishAirBookkeeping();
} }
fn airDbgInline(self: *Self, inst: Air.Inst.Index) !void { fn airDbgInlineBlock(self: *Self, inst: Air.Inst.Index) !void {
const ty_fn = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_fn; const ty_pl = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;
const extra = self.air.extraData(Air.DbgInlineBlock, ty_pl.payload);
const old_inline_func = self.inline_func;
defer self.inline_func = old_inline_func;
self.inline_func = extra.data.func;
_ = try self.addInst(.{ _ = try self.addInst(.{
.tag = .pseudo, .tag = .pseudo,
.ops = .pseudo_dbg_inline_func, .ops = .pseudo_dbg_inline_func,
.data = .{ .func = ty_fn.func }, .data = .{ .func = extra.data.func },
});
try self.lowerBlock(inst, @ptrCast(self.air.extra[extra.end..][0..extra.data.body_len]));
_ = try self.addInst(.{
.tag = .pseudo,
.ops = .pseudo_dbg_inline_func,
.data = .{ .func = old_inline_func },
}); });
self.finishAirBookkeeping();
} }
fn airDbgVar(self: *Self, inst: Air.Inst.Index) !void { fn airDbgVar(self: *Self, inst: Air.Inst.Index) !void {
@ -13407,6 +13416,12 @@ fn airLoop(self: *Self, inst: Air.Inst.Index) !void {
} }
fn airBlock(self: *Self, inst: Air.Inst.Index) !void { fn airBlock(self: *Self, inst: Air.Inst.Index) !void {
const ty_pl = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;
const extra = self.air.extraData(Air.Block, ty_pl.payload);
try self.lowerBlock(inst, @ptrCast(self.air.extra[extra.end..][0..extra.data.body_len]));
}
fn lowerBlock(self: *Self, inst: Air.Inst.Index, body: []const Air.Inst.Index) !void {
// A block is a setup to be able to jump to the end. // A block is a setup to be able to jump to the end.
const inst_tracking_i = self.inst_tracking.count(); const inst_tracking_i = self.inst_tracking.count();
self.inst_tracking.putAssumeCapacityNoClobber(inst, InstTracking.init(.unreach)); self.inst_tracking.putAssumeCapacityNoClobber(inst, InstTracking.init(.unreach));
@ -13415,9 +13430,6 @@ fn airBlock(self: *Self, inst: Air.Inst.Index) !void {
try self.blocks.putNoClobber(self.gpa, inst, .{ .state = self.initRetroactiveState() }); try self.blocks.putNoClobber(self.gpa, inst, .{ .state = self.initRetroactiveState() });
const liveness = self.liveness.getBlock(inst); const liveness = self.liveness.getBlock(inst);
const ty_pl = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;
const extra = self.air.extraData(Air.Block, ty_pl.payload);
const body: []const Air.Inst.Index = @ptrCast(self.air.extra[extra.end..][0..extra.data.body_len]);
// TODO emit debug info lexical block // TODO emit debug info lexical block
try self.genBody(body); try self.genBody(body);

View File

@ -2554,9 +2554,9 @@ pub fn genTypeDecl(
.suffix, .suffix,
.{}, .{},
); );
try writer.writeAll("; // "); try writer.writeAll("; /* ");
try mod.declPtr(owner_decl).renderFullyQualifiedName(mod, writer); try mod.declPtr(owner_decl).renderFullyQualifiedName(mod, writer);
try writer.writeByte('\n'); try writer.writeAll(" */\n");
}, },
.anon_struct, .anon_struct,
@ -3215,7 +3215,6 @@ fn genBodyInner(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail,
.assembly => try airAsm(f, inst), .assembly => try airAsm(f, inst),
.block => try airBlock(f, inst), .block => try airBlock(f, inst),
.bitcast => try airBitcast(f, inst), .bitcast => try airBitcast(f, inst),
.dbg_stmt => try airDbgStmt(f, inst),
.intcast => try airIntCast(f, inst), .intcast => try airIntCast(f, inst),
.trunc => try airTrunc(f, inst), .trunc => try airTrunc(f, inst),
.int_from_bool => try airIntFromBool(f, inst), .int_from_bool => try airIntFromBool(f, inst),
@ -3259,13 +3258,9 @@ fn genBodyInner(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail,
.@"try" => try airTry(f, inst), .@"try" => try airTry(f, inst),
.try_ptr => try airTryPtr(f, inst), .try_ptr => try airTryPtr(f, inst),
.dbg_var_ptr, .dbg_stmt => try airDbgStmt(f, inst),
.dbg_var_val, .dbg_inline_block => try airDbgInlineBlock(f, inst),
=> try airDbgVar(f, inst), .dbg_var_ptr, .dbg_var_val => try airDbgVar(f, inst),
.dbg_inline_begin,
.dbg_inline_end,
=> try airDbgInline(f, inst),
.call => try airCall(f, inst, .auto), .call => try airCall(f, inst, .auto),
.call_always_tail => .none, .call_always_tail => .none,
@ -4497,15 +4492,16 @@ fn airDbgStmt(f: *Function, inst: Air.Inst.Index) !CValue {
return .none; return .none;
} }
fn airDbgInline(f: *Function, inst: Air.Inst.Index) !CValue { fn airDbgInlineBlock(f: *Function, inst: Air.Inst.Index) !CValue {
const ty_fn = f.air.instructions.items(.data)[@intFromEnum(inst)].ty_fn;
const mod = f.object.dg.module; const mod = f.object.dg.module;
const ty_pl = f.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;
const extra = f.air.extraData(Air.DbgInlineBlock, ty_pl.payload);
const owner_decl = mod.funcOwnerDeclPtr(extra.data.func);
const writer = f.object.writer(); const writer = f.object.writer();
const owner_decl = mod.funcOwnerDeclPtr(ty_fn.func); try writer.writeAll("/* ");
try writer.print("/* dbg func:{s} */\n", .{ try owner_decl.renderFullyQualifiedName(mod, writer);
mod.intern_pool.stringToSlice(owner_decl.name), try writer.writeAll(" */ ");
}); return lowerBlock(f, inst, @ptrCast(f.air.extra[extra.end..][0..extra.data.body_len]));
return .none;
} }
fn airDbgVar(f: *Function, inst: Air.Inst.Index) !CValue { fn airDbgVar(f: *Function, inst: Air.Inst.Index) !CValue {
@ -4522,10 +4518,13 @@ fn airDbgVar(f: *Function, inst: Air.Inst.Index) !CValue {
} }
fn airBlock(f: *Function, inst: Air.Inst.Index) !CValue { fn airBlock(f: *Function, inst: Air.Inst.Index) !CValue {
const mod = f.object.dg.module;
const ty_pl = f.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl; const ty_pl = f.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;
const extra = f.air.extraData(Air.Block, ty_pl.payload); const extra = f.air.extraData(Air.Block, ty_pl.payload);
const body: []const Air.Inst.Index = @ptrCast(f.air.extra[extra.end..][0..extra.data.body_len]); return lowerBlock(f, inst, @ptrCast(f.air.extra[extra.end..][0..extra.data.body_len]));
}
fn lowerBlock(f: *Function, inst: Air.Inst.Index, body: []const Air.Inst.Index) !CValue {
const mod = f.object.dg.module;
const liveness_block = f.liveness.getBlock(inst); const liveness_block = f.liveness.getBlock(inst);
const block_id: usize = f.next_block_index; const block_id: usize = f.next_block_index;

View File

@ -4762,11 +4762,7 @@ pub const FuncGen = struct {
file: Builder.Metadata, file: Builder.Metadata,
scope: Builder.Metadata, scope: Builder.Metadata,
inlined: std.ArrayListUnmanaged(struct { inlined: Builder.DebugLocation = .no_location,
base_line: u32,
location: Builder.DebugLocation,
scope: Builder.Metadata,
}) = .{},
base_line: u32, base_line: u32,
prev_dbg_line: c_uint, prev_dbg_line: c_uint,
@ -4811,7 +4807,6 @@ pub const FuncGen = struct {
fn deinit(self: *FuncGen) void { fn deinit(self: *FuncGen) void {
self.wip.deinit(); self.wip.deinit();
self.inlined.deinit(self.gpa);
self.func_inst_table.deinit(self.gpa); self.func_inst_table.deinit(self.gpa);
self.blocks.deinit(self.gpa); self.blocks.deinit(self.gpa);
} }
@ -5107,8 +5102,7 @@ pub const FuncGen = struct {
.unreach => try self.airUnreach(inst), .unreach => try self.airUnreach(inst),
.dbg_stmt => try self.airDbgStmt(inst), .dbg_stmt => try self.airDbgStmt(inst),
.dbg_inline_begin => try self.airDbgInlineBegin(inst), .dbg_inline_block => try self.airDbgInlineBlock(inst),
.dbg_inline_end => try self.airDbgInlineEnd(inst),
.dbg_var_ptr => try self.airDbgVarPtr(inst), .dbg_var_ptr => try self.airDbgVarPtr(inst),
.dbg_var_val => try self.airDbgVarVal(inst), .dbg_var_val => try self.airDbgVarVal(inst),
@ -5126,17 +5120,81 @@ pub const FuncGen = struct {
} }
} }
fn genBodyDebugScope(self: *FuncGen, body: []const Air.Inst.Index) Error!void { fn genBodyDebugScope(self: *FuncGen, maybe_inline_func: ?InternPool.Index, body: []const Air.Inst.Index) Error!void {
if (self.wip.strip) return self.genBody(body); if (self.wip.strip) return self.genBody(body);
const old_file = self.file;
const old_inlined = self.inlined;
const old_base_line = self.base_line;
const old_scope = self.scope; const old_scope = self.scope;
defer if (maybe_inline_func) |_| {
self.wip.debug_location = self.inlined;
self.file = old_file;
self.inlined = old_inlined;
self.base_line = old_base_line;
};
defer self.scope = old_scope;
if (maybe_inline_func) |inline_func| {
const o = self.dg.object;
const zcu = o.module;
const func = zcu.funcInfo(inline_func);
const decl_index = func.owner_decl;
const decl = zcu.declPtr(decl_index);
const namespace = zcu.namespacePtr(decl.src_namespace);
const owner_mod = namespace.file_scope.mod;
self.file = try o.getDebugFile(namespace.file_scope);
const line_number = decl.src_line + 1;
self.inlined = self.wip.debug_location;
const fqn = try decl.fullyQualifiedName(zcu);
const is_internal_linkage = !zcu.decl_exports.contains(decl_index);
const fn_ty = try zcu.funcType(.{
.param_types = &.{},
.return_type = .void_type,
});
self.scope = try o.builder.debugSubprogram(
self.file,
try o.builder.metadataString(zcu.intern_pool.stringToSlice(decl.name)),
try o.builder.metadataString(zcu.intern_pool.stringToSlice(fqn)),
line_number,
line_number + func.lbrace_line,
try o.lowerDebugType(fn_ty),
.{
.di_flags = .{ .StaticMember = true },
.sp_flags = .{
.Optimized = owner_mod.optimize_mode != .Debug,
.Definition = true,
.LocalToUnit = is_internal_linkage,
},
},
o.debug_compile_unit,
);
self.base_line = decl.src_line;
const inlined_at_location = try self.wip.debug_location.toMetadata(&o.builder);
self.wip.debug_location = .{
.location = .{
.line = line_number,
.column = 0,
.scope = self.scope,
.inlined_at = inlined_at_location,
},
};
}
self.scope = try self.dg.object.builder.debugLexicalBlock( self.scope = try self.dg.object.builder.debugLexicalBlock(
old_scope, self.scope,
self.file, self.file,
self.prev_dbg_line, self.prev_dbg_line,
self.prev_dbg_column, self.prev_dbg_column,
); );
try self.genBody(body); try self.genBody(body);
self.scope = old_scope;
} }
pub const CallAttr = enum { pub const CallAttr = enum {
@ -5820,15 +5878,23 @@ pub const FuncGen = struct {
} }
fn airBlock(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value { fn airBlock(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
const o = self.dg.object;
const mod = o.module;
const ty_pl = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl; const ty_pl = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;
const extra = self.air.extraData(Air.Block, ty_pl.payload); const extra = self.air.extraData(Air.Block, ty_pl.payload);
const body: []const Air.Inst.Index = @ptrCast(self.air.extra[extra.end..][0..extra.data.body_len]); return self.lowerBlock(inst, null, @ptrCast(self.air.extra[extra.end..][0..extra.data.body_len]));
}
fn lowerBlock(
self: *FuncGen,
inst: Air.Inst.Index,
maybe_inline_func: ?InternPool.Index,
body: []const Air.Inst.Index,
) !Builder.Value {
const o = self.dg.object;
const mod = o.module;
const inst_ty = self.typeOfIndex(inst); const inst_ty = self.typeOfIndex(inst);
if (inst_ty.isNoReturn(mod)) { if (inst_ty.isNoReturn(mod)) {
try self.genBodyDebugScope(body); try self.genBodyDebugScope(maybe_inline_func, body);
return .none; return .none;
} }
@ -5844,7 +5910,7 @@ pub const FuncGen = struct {
}); });
defer assert(self.blocks.remove(inst)); defer assert(self.blocks.remove(inst));
try self.genBodyDebugScope(body); try self.genBodyDebugScope(maybe_inline_func, body);
self.wip.cursor = .{ .block = parent_bb }; self.wip.cursor = .{ .block = parent_bb };
@ -5903,10 +5969,10 @@ pub const FuncGen = struct {
_ = try self.wip.brCond(cond, then_block, else_block); _ = try self.wip.brCond(cond, then_block, else_block);
self.wip.cursor = .{ .block = then_block }; self.wip.cursor = .{ .block = then_block };
try self.genBodyDebugScope(then_body); try self.genBodyDebugScope(null, then_body);
self.wip.cursor = .{ .block = else_block }; self.wip.cursor = .{ .block = else_block };
try self.genBodyDebugScope(else_body); try self.genBodyDebugScope(null, else_body);
// No need to reset the insert cursor since this instruction is noreturn. // No need to reset the insert cursor since this instruction is noreturn.
return .none; return .none;
@ -5987,7 +6053,7 @@ pub const FuncGen = struct {
_ = try fg.wip.brCond(is_err, return_block, continue_block); _ = try fg.wip.brCond(is_err, return_block, continue_block);
fg.wip.cursor = .{ .block = return_block }; fg.wip.cursor = .{ .block = return_block };
try fg.genBodyDebugScope(body); try fg.genBodyDebugScope(null, body);
fg.wip.cursor = .{ .block = continue_block }; fg.wip.cursor = .{ .block = continue_block };
} }
@ -6060,13 +6126,13 @@ pub const FuncGen = struct {
} }
self.wip.cursor = .{ .block = case_block }; self.wip.cursor = .{ .block = case_block };
try self.genBodyDebugScope(case_body); try self.genBodyDebugScope(null, case_body);
} }
self.wip.cursor = .{ .block = else_block }; self.wip.cursor = .{ .block = else_block };
const else_body: []const Air.Inst.Index = @ptrCast(self.air.extra[extra_index..][0..switch_br.data.else_body_len]); const else_body: []const Air.Inst.Index = @ptrCast(self.air.extra[extra_index..][0..switch_br.data.else_body_len]);
if (else_body.len != 0) { if (else_body.len != 0) {
try self.genBodyDebugScope(else_body); try self.genBodyDebugScope(null, else_body);
} else { } else {
_ = try self.wip.@"unreachable"(); _ = try self.wip.@"unreachable"();
} }
@ -6085,7 +6151,7 @@ pub const FuncGen = struct {
_ = try self.wip.br(loop_block); _ = try self.wip.br(loop_block);
self.wip.cursor = .{ .block = loop_block }; self.wip.cursor = .{ .block = loop_block };
try self.genBodyDebugScope(body); try self.genBodyDebugScope(null, body);
// TODO instead of this logic, change AIR to have the property that // TODO instead of this logic, change AIR to have the property that
// every block is guaranteed to end with a noreturn instruction. // every block is guaranteed to end with a noreturn instruction.
@ -6592,96 +6658,22 @@ pub const FuncGen = struct {
self.prev_dbg_line = @intCast(self.base_line + dbg_stmt.line + 1); self.prev_dbg_line = @intCast(self.base_line + dbg_stmt.line + 1);
self.prev_dbg_column = @intCast(dbg_stmt.column + 1); self.prev_dbg_column = @intCast(dbg_stmt.column + 1);
const inlined_at_location = if (self.inlined.getLastOrNull()) |inlined|
try inlined.location.toMetadata(self.wip.builder)
else
.none;
self.wip.debug_location = .{ self.wip.debug_location = .{
.location = .{ .location = .{
.line = self.prev_dbg_line, .line = self.prev_dbg_line,
.column = self.prev_dbg_column, .column = self.prev_dbg_column,
.scope = self.scope, .scope = self.scope,
.inlined_at = inlined_at_location, .inlined_at = try self.inlined.toMetadata(self.wip.builder),
}, },
}; };
return .none; return .none;
} }
fn airDbgInlineBegin(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value { fn airDbgInlineBlock(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
const o = self.dg.object; const ty_pl = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;
const zcu = o.module; const extra = self.air.extraData(Air.DbgInlineBlock, ty_pl.payload);
return self.lowerBlock(inst, extra.data.func, @ptrCast(self.air.extra[extra.end..][0..extra.data.body_len]));
const ty_fn = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_fn;
const func = zcu.funcInfo(ty_fn.func);
const decl_index = func.owner_decl;
const decl = zcu.declPtr(decl_index);
const namespace = zcu.namespacePtr(decl.src_namespace);
const owner_mod = namespace.file_scope.mod;
self.file = try o.getDebugFile(namespace.file_scope);
const line_number = decl.src_line + 1;
try self.inlined.append(self.gpa, .{
.location = self.wip.debug_location,
.scope = self.scope,
.base_line = self.base_line,
});
const fqn = try decl.fullyQualifiedName(zcu);
const is_internal_linkage = !zcu.decl_exports.contains(decl_index);
const fn_ty = try zcu.funcType(.{
.param_types = &.{},
.return_type = .void_type,
});
self.scope = try o.builder.debugSubprogram(
self.file,
try o.builder.metadataString(zcu.intern_pool.stringToSlice(decl.name)),
try o.builder.metadataString(zcu.intern_pool.stringToSlice(fqn)),
line_number,
line_number + func.lbrace_line,
try o.lowerDebugType(fn_ty),
.{
.di_flags = .{ .StaticMember = true },
.sp_flags = .{
.Optimized = owner_mod.optimize_mode != .Debug,
.Definition = true,
.LocalToUnit = is_internal_linkage,
},
},
o.debug_compile_unit,
);
self.base_line = decl.src_line;
const inlined_at_location = try self.wip.debug_location.toMetadata(&o.builder);
self.wip.debug_location = .{
.location = .{
.line = line_number,
.column = 0,
.scope = self.scope,
.inlined_at = inlined_at_location,
},
};
return .none;
}
fn airDbgInlineEnd(self: *FuncGen, inst: Air.Inst.Index) Allocator.Error!Builder.Value {
const o = self.dg.object;
const ty_fn = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_fn;
const mod = o.module;
const decl = mod.funcOwnerDeclPtr(ty_fn.func);
self.file = try o.getDebugFile(mod.namespacePtr(decl.src_namespace).file_scope);
const old = self.inlined.pop();
self.scope = old.scope;
self.base_line = old.base_line;
self.wip.debug_location = old.location;
return .none;
} }
fn airDbgVarPtr(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value { fn airDbgVarPtr(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {

View File

@ -208,6 +208,7 @@ pub const Object = struct {
false => .{ .unstructured = .{} }, false => .{ .unstructured = .{} },
}, },
.current_block_label = undefined, .current_block_label = undefined,
.base_line = decl.src_line,
}; };
defer decl_gen.deinit(); defer decl_gen.deinit();
@ -321,9 +322,8 @@ const DeclGen = struct {
/// The code (prologue and body) for the function we are currently generating code for. /// The code (prologue and body) for the function we are currently generating code for.
func: SpvModule.Fn = .{}, func: SpvModule.Fn = .{},
/// Stack of the base offsets of the current decl, which is what `dbg_stmt` is relative to. /// The base offset of the current decl, which is what `dbg_stmt` is relative to.
/// This is a stack to keep track of inline functions. base_line: u32,
base_line_stack: std.ArrayListUnmanaged(u32) = .{},
/// If `gen` returned `Error.CodegenFail`, this contains an explanatory message. /// If `gen` returned `Error.CodegenFail`, this contains an explanatory message.
/// Memory is owned by `module.gpa`. /// Memory is owned by `module.gpa`.
@ -401,7 +401,6 @@ const DeclGen = struct {
self.wip_pointers.deinit(self.gpa); self.wip_pointers.deinit(self.gpa);
self.control_flow.deinit(self.gpa); self.control_flow.deinit(self.gpa);
self.func.deinit(self.gpa); self.func.deinit(self.gpa);
self.base_line_stack.deinit(self.gpa);
} }
/// Return the target which we are currently compiling for. /// Return the target which we are currently compiling for.
@ -1959,8 +1958,6 @@ const DeclGen = struct {
const decl_id = self.spv.declPtr(spv_decl_index).result_id; const decl_id = self.spv.declPtr(spv_decl_index).result_id;
try self.base_line_stack.append(self.gpa, decl.src_line);
if (decl.val.getFunction(mod)) |_| { if (decl.val.getFunction(mod)) |_| {
assert(decl.ty.zigTypeTag(mod) == .Fn); assert(decl.ty.zigTypeTag(mod) == .Fn);
const fn_info = mod.typeToFunc(decl.ty).?; const fn_info = mod.typeToFunc(decl.ty).?;
@ -2317,8 +2314,7 @@ const DeclGen = struct {
.unreach, .trap => return self.airUnreach(), .unreach, .trap => return self.airUnreach(),
.dbg_stmt => return self.airDbgStmt(inst), .dbg_stmt => return self.airDbgStmt(inst),
.dbg_inline_begin => return self.airDbgInlineBegin(inst), .dbg_inline_block => try self.airDbgInlineBlock(inst),
.dbg_inline_end => return self.airDbgInlineEnd(inst),
.dbg_var_ptr, .dbg_var_val => return self.airDbgVar(inst), .dbg_var_ptr, .dbg_var_val => return self.airDbgVar(inst),
.unwrap_errunion_err => try self.airErrUnionErr(inst), .unwrap_errunion_err => try self.airErrUnionErr(inst),
@ -4311,6 +4307,12 @@ const DeclGen = struct {
} }
fn airBlock(self: *DeclGen, inst: Air.Inst.Index) !?IdRef { fn airBlock(self: *DeclGen, inst: Air.Inst.Index) !?IdRef {
const inst_datas = self.air.instructions.items(.data);
const extra = self.air.extraData(Air.Block, inst_datas[@intFromEnum(inst)].ty_pl.payload);
return self.lowerBlock(inst, @ptrCast(self.air.extra[extra.end..][0..extra.data.body_len]));
}
fn lowerBlock(self: *DeclGen, inst: Air.Inst.Index, body: []const Air.Inst.Index) !?IdRef {
// In AIR, a block doesn't really define an entry point like a block, but // In AIR, a block doesn't really define an entry point like a block, but
// more like a scope that breaks can jump out of and "return" a value from. // more like a scope that breaks can jump out of and "return" a value from.
// This cannot be directly modelled in SPIR-V, so in a block instruction, // This cannot be directly modelled in SPIR-V, so in a block instruction,
@ -4320,10 +4322,6 @@ const DeclGen = struct {
const mod = self.module; const mod = self.module;
const ty = self.typeOfIndex(inst); const ty = self.typeOfIndex(inst);
const inst_datas = self.air.instructions.items(.data);
const extra = self.air.extraData(Air.Block, inst_datas[@intFromEnum(inst)].ty_pl.payload);
const body: []const Air.Inst.Index =
@ptrCast(self.air.extra[extra.end..][0..extra.data.body_len]);
const have_block_result = ty.isFnOrHasRuntimeBitsIgnoreComptime(mod); const have_block_result = ty.isFnOrHasRuntimeBitsIgnoreComptime(mod);
const cf = switch (self.control_flow) { const cf = switch (self.control_flow) {
@ -5157,25 +5155,22 @@ const DeclGen = struct {
const decl = mod.declPtr(self.decl_index); const decl = mod.declPtr(self.decl_index);
const path = decl.getFileScope(mod).sub_file_path; const path = decl.getFileScope(mod).sub_file_path;
const src_fname_id = try self.spv.resolveSourceFileName(path); const src_fname_id = try self.spv.resolveSourceFileName(path);
const base_line = self.base_line_stack.getLast();
try self.func.body.emit(self.spv.gpa, .OpLine, .{ try self.func.body.emit(self.spv.gpa, .OpLine, .{
.file = src_fname_id, .file = src_fname_id,
.line = base_line + dbg_stmt.line + 1, .line = self.base_line + dbg_stmt.line + 1,
.column = dbg_stmt.column + 1, .column = dbg_stmt.column + 1,
}); });
} }
fn airDbgInlineBegin(self: *DeclGen, inst: Air.Inst.Index) !void { fn airDbgInlineBlock(self: *DeclGen, inst: Air.Inst.Index) !?IdRef {
const mod = self.module; const mod = self.module;
const fn_ty = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_fn; const inst_datas = self.air.instructions.items(.data);
const decl_index = mod.funcInfo(fn_ty.func).owner_decl; const extra = self.air.extraData(Air.DbgInlineBlock, inst_datas[@intFromEnum(inst)].ty_pl.payload);
const decl = mod.declPtr(decl_index); const decl = mod.funcOwnerDeclPtr(extra.data.func);
try self.base_line_stack.append(self.gpa, decl.src_line); const old_base_line = self.base_line;
} defer self.base_line = old_base_line;
self.base_line = decl.src_line;
fn airDbgInlineEnd(self: *DeclGen, inst: Air.Inst.Index) !void { return self.lowerBlock(inst, @ptrCast(self.air.extra[extra.end..][0..extra.data.body_len]));
_ = inst;
_ = self.base_line_stack.pop();
} }
fn airDbgVar(self: *DeclGen, inst: Air.Inst.Index) !void { fn airDbgVar(self: *DeclGen, inst: Air.Inst.Index) !void {

View File

@ -260,7 +260,7 @@ const Writer = struct {
.c_va_copy, .c_va_copy,
=> try w.writeTyOp(s, inst), => try w.writeTyOp(s, inst),
.block => try w.writeBlock(s, inst), .block, .dbg_inline_block => try w.writeBlock(s, tag, inst),
.loop => try w.writeLoop(s, inst), .loop => try w.writeLoop(s, inst),
@ -292,7 +292,6 @@ const Writer = struct {
.assembly => try w.writeAssembly(s, inst), .assembly => try w.writeAssembly(s, inst),
.dbg_stmt => try w.writeDbgStmt(s, inst), .dbg_stmt => try w.writeDbgStmt(s, inst),
.dbg_inline_begin, .dbg_inline_end => try w.writeDbgInline(s, inst),
.aggregate_init => try w.writeAggregateInit(s, inst), .aggregate_init => try w.writeAggregateInit(s, inst),
.union_init => try w.writeUnionInit(s, inst), .union_init => try w.writeUnionInit(s, inst),
.br => try w.writeBr(s, inst), .br => try w.writeBr(s, inst),
@ -367,17 +366,34 @@ const Writer = struct {
try w.writeOperand(s, inst, 0, ty_op.operand); try w.writeOperand(s, inst, 0, ty_op.operand);
} }
fn writeBlock(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void { fn writeBlock(w: *Writer, s: anytype, tag: Air.Inst.Tag, inst: Air.Inst.Index) @TypeOf(s).Error!void {
const ty_pl = w.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl; const ty_pl = w.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;
const extra = w.air.extraData(Air.Block, ty_pl.payload); try w.writeType(s, ty_pl.ty.toType());
const body: []const Air.Inst.Index = @ptrCast(w.air.extra[extra.end..][0..extra.data.body_len]); const body: []const Air.Inst.Index = @ptrCast(switch (tag) {
inline .block, .dbg_inline_block => |comptime_tag| body: {
const extra = w.air.extraData(switch (comptime_tag) {
.block => Air.Block,
.dbg_inline_block => Air.DbgInlineBlock,
else => unreachable,
}, ty_pl.payload);
switch (comptime_tag) {
.block => {},
.dbg_inline_block => {
try s.writeAll(", ");
try w.writeInstRef(s, Air.internedToRef(extra.data.func), false);
},
else => unreachable,
}
break :body w.air.extra[extra.end..][0..extra.data.body_len];
},
else => unreachable,
});
if (w.skip_body) return s.writeAll(", ...");
const liveness_block = if (w.liveness) |liveness| const liveness_block = if (w.liveness) |liveness|
liveness.getBlock(inst) liveness.getBlock(inst)
else else
Liveness.BlockSlices{ .deaths = &.{} }; Liveness.BlockSlices{ .deaths = &.{} };
try w.writeType(s, ty_pl.ty.toType());
if (w.skip_body) return s.writeAll(", ...");
try s.writeAll(", {\n"); try s.writeAll(", {\n");
const old_indent = w.indent; const old_indent = w.indent;
w.indent += 2; w.indent += 2;
@ -661,13 +677,6 @@ const Writer = struct {
try s.print("{d}:{d}", .{ dbg_stmt.line + 1, dbg_stmt.column + 1 }); try s.print("{d}:{d}", .{ dbg_stmt.line + 1, dbg_stmt.column + 1 });
} }
fn writeDbgInline(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {
const ty_fn = w.air.instructions.items(.data)[@intFromEnum(inst)].ty_fn;
const func_index = ty_fn.func;
const owner_decl = w.module.funcOwnerDeclPtr(func_index);
try s.print("{}", .{owner_decl.name.fmt(&w.module.intern_pool)});
}
fn writeDbgVar(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void { fn writeDbgVar(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {
const pl_op = w.air.instructions.items(.data)[@intFromEnum(inst)].pl_op; const pl_op = w.air.instructions.items(.data)[@intFromEnum(inst)].pl_op;
try w.writeOperand(s, inst, 0, pl_op.operand); try w.writeOperand(s, inst, 0, pl_op.operand);

View File

@ -913,3 +913,20 @@ test "switch prong captures range" {
S.a(&arr, 5); S.a(&arr, 5);
try expect(arr[5] == 5); try expect(arr[5] == 5);
} }
test "prong with inline call to unreachable" {
const U = union(enum) {
void: void,
bool: bool,
inline fn unreach() noreturn {
unreachable;
}
};
var u: U = undefined;
u = .{ .bool = true };
switch (u) {
.void => U.unreach(),
.bool => |ok| try expect(ok),
}
}