srctree

Jacob Young parent 671c2acf aa688567
Air: replace `.dbg_inline_*` with `.dbg_inline_block`

This prevents the possibility of not emitting a .dbg_inline_endinstruction and reduces the allocation requirements of the backends.

Closes #19093

inlinesplit
src/Air.zig added: 428, removed: 359, total 69
@@ -443,12 +443,9 @@ pub const Inst = struct {
/// Result type is always void.
/// Uses the `dbg_stmt` field.
dbg_stmt,
/// Marks the start of an inline call.
/// Uses the `ty_fn` field.
dbg_inline_begin,
/// Marks the end of an inline call.
/// Uses the `ty_fn` field.
dbg_inline_end,
/// A block that represents an inlined function call.
/// Uses the `ty_pl` field. Payload is `DbgInlineBlock`.
dbg_inline_block,
/// 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.
/// Result type is always void.
@@ -1051,10 +1048,6 @@ pub const Inst = struct {
// Index into a different array.
payload: u32,
},
ty_fn: struct {
ty: Ref,
func: InternPool.Index,
},
br: struct {
block_inst: Index,
operand: Ref,
@@ -1117,6 +1110,12 @@ pub const Block = struct {
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`.
pub const Call = struct {
args_len: u32,
@@ -1371,6 +1370,7 @@ pub fn typeOfIndex(air: *const Air, inst: Air.Inst.Index, ip: *const InternPool)
 
.assembly,
.block,
.dbg_inline_block,
.struct_field_ptr,
.struct_field_val,
.slice_elem_ptr,
@@ -1448,8 +1448,6 @@ pub fn typeOfIndex(air: *const Air, inst: Air.Inst.Index, ip: *const InternPool)
 
.breakpoint,
.dbg_stmt,
.dbg_inline_begin,
.dbg_inline_end,
.dbg_var_ptr,
.dbg_var_val,
.store,
@@ -1606,8 +1604,7 @@ pub fn mustLower(air: Air, inst: Air.Inst.Index, ip: *const InternPool) bool {
.@"try",
.try_ptr,
.dbg_stmt,
.dbg_inline_begin,
.dbg_inline_end,
.dbg_inline_block,
.dbg_var_ptr,
.dbg_var_val,
.ret,
 
src/Liveness.zig added: 428, removed: 359, total 69
@@ -327,8 +327,6 @@ pub fn categorizeOperand(
.trap,
.breakpoint,
.dbg_stmt,
.dbg_inline_begin,
.dbg_inline_end,
.unreach,
.ret_addr,
.frame_addr,
@@ -604,9 +602,19 @@ pub fn categorizeOperand(
.assembly => {
return .complex;
},
.block => {
const extra = air.extraData(Air.Block, air_datas[@intFromEnum(inst)].ty_pl.payload);
const body: []const Air.Inst.Index = @ptrCast(air.extra[extra.end..][0..extra.data.body_len]);
.block, .dbg_inline_block => |tag| {
const ty_pl = air_datas[@intFromEnum(inst)].ty_pl;
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) {
// Peephole optimization for "panic-like" conditionals, which have
@@ -963,8 +971,6 @@ fn analyzeInst(
.ret_ptr,
.breakpoint,
.dbg_stmt,
.dbg_inline_begin,
.dbg_inline_end,
.fence,
.ret_addr,
.frame_addr,
@@ -1235,7 +1241,15 @@ fn analyzeInst(
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),
 
.@"try" => return analyzeInstCondBr(a, pass, data, inst, .@"try"),
@@ -1369,12 +1383,9 @@ fn analyzeInstBlock(
comptime pass: LivenessPass,
data: *LivenessPassData(pass),
inst: Air.Inst.Index,
ty: Air.Inst.Ref,
body: []const Air.Inst.Index,
) !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;
 
// 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
// 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
const block_scope = data.block_scopes.get(inst).?;
const num_deaths = data.live_set.count() - block_scope.live_set.count();
 
src/Liveness/Verify.zig added: 428, removed: 359, total 69
@@ -29,7 +29,7 @@ const LiveMap = std.AutoHashMapUnmanaged(Air.Inst.Index, void);
 
fn verifyBody(self: *Verify, body: []const Air.Inst.Index) Error!void {
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);
for (body) |inst| {
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;
}
 
switch (tag[@intFromEnum(inst)]) {
switch (tags[@intFromEnum(inst)]) {
// no operands
.arg,
.alloc,
@@ -46,8 +46,6 @@ fn verifyBody(self: *Verify, body: []const Air.Inst.Index) Error!void {
.ret_ptr,
.breakpoint,
.dbg_stmt,
.dbg_inline_begin,
.dbg_inline_end,
.fence,
.ret_addr,
.frame_addr,
@@ -431,11 +429,20 @@ fn verifyBody(self: *Verify, body: []const Air.Inst.Index) Error!void {
}
try self.verifyInst(inst);
},
.block => {
.block, .dbg_inline_block => |tag| {
const ty_pl = data[@intFromEnum(inst)].ty_pl;
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(self.air.extra[extra.end..][0..extra.data.body_len]);
const block_body: []const Air.Inst.Index = @ptrCast(switch (tag) {
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);
 
var orig_live = try self.live.clone(self.gpa);
 
src/Sema.zig added: 428, removed: 359, total 69
@@ -5939,6 +5939,7 @@ fn resolveBlockBody(
if (child_block.is_comptime) {
return sema.resolveInlineBody(child_block, body, body_inst);
} else {
assert(sema.air_instructions.items(.tag)[@intFromEnum(merges.block_inst)] == .block);
var need_debug_scope = false;
child_block.need_debug_scope = &need_debug_scope;
if (sema.analyzeBodyInner(child_block, body)) |_| {
@@ -6002,18 +6003,44 @@ fn resolveAnalyzedBlock(
assert(child_block.instructions.items.len != 0);
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) {
// No need for a block instruction. We can put the new instructions
// directly into the parent block.
if (need_debug_scope) {
// The code following this block is unreachable, as the block has no
// merges, so we don't necessarily need to emit this as an AIR block.
// 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;
switch (block_tag) {
.block => {
// No need for a block instruction. We can put the new instructions
// directly into the parent block.
if (need_debug_scope) {
// The code following this block is unreachable, as the block has no
// merges, so we don't necessarily need to emit this as an AIR block.
// 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 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| {
// 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.Block).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.Block{
.body_len = @intCast(child_block.instructions.items.len),
}),
} };
switch (block_tag) {
.block => {
try sema.air_extra.ensureUnusedCapacity(gpa, @typeInfo(Air.Block).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.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));
// Rewrite the break to just give value {}; the value is
// comptime-known and will be returned directly.
@@ -6079,14 +6122,30 @@ fn resolveAnalyzedBlock(
return sema.failWithOwnedErrorMsg(child_block, msg);
}
const ty_inst = Air.internedToRef(resolved_ty.toIntern());
try sema.air_extra.ensureUnusedCapacity(gpa, @typeInfo(Air.Block).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.Block{
.body_len = @intCast(child_block.instructions.items.len),
}),
} };
switch (block_tag) {
.block => {
try sema.air_extra.ensureUnusedCapacity(gpa, @typeInfo(Air.Block).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.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));
// 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.
@@ -7379,7 +7438,6 @@ fn analyzeCall(
.needed_comptime_reason = "function being called at comptime must be comptime-known",
.block_comptime_reason = comptime_reason,
});
const prev_fn_index = sema.func_index;
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", .{
@as([]const u8, if (is_comptime_call) "comptime" else "inline"),
@@ -7415,9 +7473,10 @@ fn analyzeCall(
// set to in the `Block`.
// This block instruction will be used to capture the return value from the
// 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);
try sema.air_instructions.append(gpa, .{
.tag = .block,
.tag = if (need_debug_scope) .dbg_inline_block else .block,
.data = undefined,
});
// 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();
const new_func_resolved_ty = try mod.funcType(new_fn_info);
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);
for (fn_info.param_body) |param| switch (zir_tags[@intFromEnum(param)]) {
.param, .param_comptime => {
@@ -7626,21 +7682,9 @@ fn analyzeCall(
error.ComptimeReturn => break :result inlining.comptime_result,
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) {
const result_val = try sema.resolveConstValue(block, .unneeded, result, undefined);
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 {
const mod = sema.mod;
const int_type = sema.code.instructions.items(.data)[@intFromEnum(inst)].int_type;
 
src/arch/aarch64/CodeGen.zig added: 428, removed: 359, total 69
@@ -747,7 +747,6 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
.frame_addr => try self.airFrameAddress(inst),
.fence => try self.airFence(),
.cond_br => try self.airCondBr(inst),
.dbg_stmt => try self.airDbgStmt(inst),
.fptrunc => try self.airFptrunc(inst),
.fpext => try self.airFpext(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_ptr => try self.airTryPtr(inst),
 
.dbg_stmt => try self.airDbgStmt(inst),
.dbg_inline_block => try self.airDbgInlineBlock(inst),
.dbg_var_ptr,
.dbg_var_val,
=> try self.airDbgVar(inst),
 
.dbg_inline_begin,
.dbg_inline_end,
=> try self.airDbgInline(inst),
 
.call => try self.airCall(inst, .auto),
.call_always_tail => try self.airCall(inst, .always_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();
}
 
fn airDbgInline(self: *Self, inst: Air.Inst.Index) !void {
const ty_fn = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_fn;
fn airDbgInlineBlock(self: *Self, inst: Air.Inst.Index) !void {
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
_ = 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 {
@@ -5042,6 +5040,12 @@ fn jump(self: *Self, inst: Mir.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, .{
// A block is a setup to be able to jump to the end.
.relocs = .{},
@@ -5054,9 +5058,6 @@ fn airBlock(self: *Self, inst: Air.Inst.Index) !void {
});
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
try self.genBody(body);
 
 
src/arch/arm/CodeGen.zig added: 428, removed: 359, total 69
@@ -733,7 +733,6 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
.frame_addr => try self.airFrameAddress(inst),
.fence => try self.airFence(),
.cond_br => try self.airCondBr(inst),
.dbg_stmt => try self.airDbgStmt(inst),
.fptrunc => try self.airFptrunc(inst),
.fpext => try self.airFpext(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_ptr => try self.airTryPtr(inst),
 
.dbg_stmt => try self.airDbgStmt(inst),
.dbg_inline_block => try self.airDbgInlineBlock(inst),
.dbg_var_ptr,
.dbg_var_val,
=> try self.airDbgVar(inst),
 
.dbg_inline_begin,
.dbg_inline_end,
=> try self.airDbgInline(inst),
 
.call => try self.airCall(inst, .auto),
.call_always_tail => try self.airCall(inst, .always_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();
}
 
fn airDbgInline(self: *Self, inst: Air.Inst.Index) !void {
const ty_fn = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_fn;
fn airDbgInlineBlock(self: *Self, inst: Air.Inst.Index) !void {
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
_ = 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 {
@@ -4973,6 +4971,12 @@ fn jump(self: *Self, inst: Mir.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, .{
// A block is a setup to be able to jump to the end.
.relocs = .{},
@@ -4985,9 +4989,6 @@ fn airBlock(self: *Self, inst: Air.Inst.Index) !void {
});
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
try self.genBody(body);
 
 
src/arch/riscv64/CodeGen.zig added: 428, removed: 359, total 69
@@ -566,7 +566,6 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
.frame_addr => try self.airFrameAddress(inst),
.fence => try self.airFence(),
.cond_br => try self.airCondBr(inst),
.dbg_stmt => try self.airDbgStmt(inst),
.fptrunc => try self.airFptrunc(inst),
.fpext => try self.airFpext(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_ptr => @panic("TODO"),
 
.dbg_stmt => try self.airDbgStmt(inst),
.dbg_inline_block => try self.airDbgInlineBlock(inst),
.dbg_var_ptr,
.dbg_var_val,
=> try self.airDbgVar(inst),
 
.dbg_inline_begin,
.dbg_inline_end,
=> try self.airDbgInline(inst),
 
.call => try self.airCall(inst, .auto),
.call_always_tail => try self.airCall(inst, .always_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();
}
 
fn airDbgInline(self: *Self, inst: Air.Inst.Index) !void {
const ty_fn = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_fn;
fn airDbgInlineBlock(self: *Self, inst: Air.Inst.Index) !void {
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
_ = 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 {
@@ -2060,6 +2058,12 @@ fn jump(self: *Self, index: usize) !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, .{
// A block is a setup to be able to jump to the end.
.relocs = .{},
@@ -2071,10 +2075,6 @@ fn airBlock(self: *Self, inst: Air.Inst.Index) !void {
.mcv = MCValue{ .none = {} },
});
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
try self.genBody(body);
 
 
src/arch/sparc64/CodeGen.zig added: 428, removed: 359, total 69
@@ -579,7 +579,6 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
.frame_addr => @panic("TODO try self.airFrameAddress(inst)"),
.fence => try self.airFence(inst),
.cond_br => try self.airCondBr(inst),
.dbg_stmt => try self.airDbgStmt(inst),
.fptrunc => @panic("TODO try self.airFptrunc(inst)"),
.fpext => @panic("TODO try self.airFpext(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_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_val,
=> try self.airDbgVar(inst),
 
.dbg_inline_begin,
.dbg_inline_end,
=> try self.airDbgInline(inst),
 
.call => try self.airCall(inst, .auto),
.call_always_tail => try self.airCall(inst, .always_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 {
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, .{
// A block is a setup to be able to jump to the end.
.relocs = .{},
@@ -1139,9 +1142,6 @@ fn airBlock(self: *Self, inst: Air.Inst.Index) !void {
});
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
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 });
}
 
fn airDbgInline(self: *Self, inst: Air.Inst.Index) !void {
const ty_fn = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_fn;
fn airDbgInlineBlock(self: *Self, inst: Air.Inst.Index) !void {
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
_ = 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 {
 
src/arch/wasm/CodeGen.zig added: 428, removed: 359, total 69
@@ -1910,16 +1910,11 @@ fn genInst(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
.@"try" => func.airTry(inst),
.try_ptr => func.airTryPtr(inst),
 
// TODO
.dbg_inline_begin,
.dbg_inline_end,
=> func.finishAir(inst, .none, &.{}),
 
.dbg_stmt => func.airDbgStmt(inst),
.dbg_inline_block => func.airDbgInlineBlock(inst),
.dbg_var_ptr => func.airDbgVar(inst, true),
.dbg_var_val => func.airDbgVar(inst, false),
 
.dbg_stmt => func.airDbgStmt(inst),
 
.call => func.airCall(inst, .auto),
.call_always_tail => func.airCall(inst, .always_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 {
const mod = func.bin_file.base.comp.module.?;
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 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
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});
}
 
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, &.{});
 
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, &.{});
}
 
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 {
const pl_op = func.air.instructions.items(.data)[@intFromEnum(inst)].pl_op;
const err_union = try func.resolveInst(pl_op.operand);
 
src/arch/x86_64/CodeGen.zig added: 428, removed: 359, total 69
@@ -58,6 +58,7 @@ bin_file: *link.File,
debug_output: DebugInfoOutput,
target: *const std.Target,
owner: Owner,
inline_func: InternPool.Index,
mod: *Package.Module,
err_msg: ?*ErrorMsg,
args: []MCValue,
@@ -820,6 +821,7 @@ pub fn generate(
.bin_file = bin_file,
.debug_output = debug_output,
.owner = .{ .func_index = func_index },
.inline_func = func_index,
.err_msg = null,
.args = undefined, // populated after `resolveCallingConventionValues`
.va_info = undefined, // populated after `resolveCallingConventionValues`
@@ -987,6 +989,7 @@ pub fn generateLazy(
.bin_file = bin_file,
.debug_output = debug_output,
.owner = .{ .lazy_sym = lazy_sym },
.inline_func = undefined,
.err_msg = null,
.args = 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),
.fence => try self.airFence(inst),
.cond_br => try self.airCondBr(inst),
.dbg_stmt => try self.airDbgStmt(inst),
.fptrunc => try self.airFptrunc(inst),
.fpext => try self.airFpext(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_ptr => try self.airTryPtr(inst),
 
.dbg_stmt => try self.airDbgStmt(inst),
.dbg_inline_block => try self.airDbgInlineBlock(inst),
.dbg_var_ptr,
.dbg_var_val,
=> try self.airDbgVar(inst),
 
.dbg_inline_begin,
.dbg_inline_end,
=> try self.airDbgInline(inst),
 
.call => try self.airCall(inst, .auto),
.call_always_tail => try self.airCall(inst, .always_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();
}
 
fn airDbgInline(self: *Self, inst: Air.Inst.Index) !void {
const ty_fn = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_fn;
fn airDbgInlineBlock(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.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(.{
.tag = .pseudo,
.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 {
@@ -13407,6 +13416,12 @@ fn airLoop(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.
const inst_tracking_i = self.inst_tracking.count();
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() });
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
try self.genBody(body);
 
 
src/codegen/c.zig added: 428, removed: 359, total 69
@@ -2554,9 +2554,9 @@ pub fn genTypeDecl(
.suffix,
.{},
);
try writer.writeAll("; // ");
try writer.writeAll("; /* ");
try mod.declPtr(owner_decl).renderFullyQualifiedName(mod, writer);
try writer.writeByte('\n');
try writer.writeAll(" */\n");
},
 
.anon_struct,
@@ -3215,7 +3215,6 @@ fn genBodyInner(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail,
.assembly => try airAsm(f, inst),
.block => try airBlock(f, inst),
.bitcast => try airBitcast(f, inst),
.dbg_stmt => try airDbgStmt(f, inst),
.intcast => try airIntCast(f, inst),
.trunc => try airTrunc(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_ptr => try airTryPtr(f, inst),
 
.dbg_var_ptr,
.dbg_var_val,
=> try airDbgVar(f, inst),
 
.dbg_inline_begin,
.dbg_inline_end,
=> try airDbgInline(f, inst),
.dbg_stmt => try airDbgStmt(f, inst),
.dbg_inline_block => try airDbgInlineBlock(f, inst),
.dbg_var_ptr, .dbg_var_val => try airDbgVar(f, inst),
 
.call => try airCall(f, inst, .auto),
.call_always_tail => .none,
@@ -4497,15 +4492,16 @@ fn airDbgStmt(f: *Function, inst: Air.Inst.Index) !CValue {
return .none;
}
 
fn airDbgInline(f: *Function, inst: Air.Inst.Index) !CValue {
const ty_fn = f.air.instructions.items(.data)[@intFromEnum(inst)].ty_fn;
fn airDbgInlineBlock(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 extra = f.air.extraData(Air.DbgInlineBlock, ty_pl.payload);
const owner_decl = mod.funcOwnerDeclPtr(extra.data.func);
const writer = f.object.writer();
const owner_decl = mod.funcOwnerDeclPtr(ty_fn.func);
try writer.print("/* dbg func:{s} */\n", .{
mod.intern_pool.stringToSlice(owner_decl.name),
});
return .none;
try writer.writeAll("/* ");
try owner_decl.renderFullyQualifiedName(mod, writer);
try writer.writeAll(" */ ");
return lowerBlock(f, inst, @ptrCast(f.air.extra[extra.end..][0..extra.data.body_len]));
}
 
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 {
const mod = f.object.dg.module;
const ty_pl = f.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;
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 block_id: usize = f.next_block_index;
 
src/codegen/llvm.zig added: 428, removed: 359, total 69
@@ -4762,11 +4762,7 @@ pub const FuncGen = struct {
file: Builder.Metadata,
scope: Builder.Metadata,
 
inlined: std.ArrayListUnmanaged(struct {
base_line: u32,
location: Builder.DebugLocation,
scope: Builder.Metadata,
}) = .{},
inlined: Builder.DebugLocation = .no_location,
 
base_line: u32,
prev_dbg_line: c_uint,
@@ -4811,7 +4807,6 @@ pub const FuncGen = struct {
 
fn deinit(self: *FuncGen) void {
self.wip.deinit();
self.inlined.deinit(self.gpa);
self.func_inst_table.deinit(self.gpa);
self.blocks.deinit(self.gpa);
}
@@ -5107,8 +5102,7 @@ pub const FuncGen = struct {
 
.unreach => try self.airUnreach(inst),
.dbg_stmt => try self.airDbgStmt(inst),
.dbg_inline_begin => try self.airDbgInlineBegin(inst),
.dbg_inline_end => try self.airDbgInlineEnd(inst),
.dbg_inline_block => try self.airDbgInlineBlock(inst),
.dbg_var_ptr => try self.airDbgVarPtr(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);
 
const old_file = self.file;
const old_inlined = self.inlined;
const old_base_line = self.base_line;
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(
old_scope,
self.scope,
self.file,
self.prev_dbg_line,
self.prev_dbg_column,
);
try self.genBody(body);
self.scope = old_scope;
}
 
pub const CallAttr = enum {
@@ -5820,15 +5878,23 @@ pub const FuncGen = struct {
}
 
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 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);
 
if (inst_ty.isNoReturn(mod)) {
try self.genBodyDebugScope(body);
try self.genBodyDebugScope(maybe_inline_func, body);
return .none;
}
 
@@ -5844,7 +5910,7 @@ pub const FuncGen = struct {
});
defer assert(self.blocks.remove(inst));
 
try self.genBodyDebugScope(body);
try self.genBodyDebugScope(maybe_inline_func, body);
 
self.wip.cursor = .{ .block = parent_bb };
 
@@ -5903,10 +5969,10 @@ pub const FuncGen = struct {
_ = try self.wip.brCond(cond, then_block, else_block);
 
self.wip.cursor = .{ .block = then_block };
try self.genBodyDebugScope(then_body);
try self.genBodyDebugScope(null, then_body);
 
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.
return .none;
@@ -5987,7 +6053,7 @@ pub const FuncGen = struct {
_ = try fg.wip.brCond(is_err, return_block, continue_block);
 
fg.wip.cursor = .{ .block = return_block };
try fg.genBodyDebugScope(body);
try fg.genBodyDebugScope(null, body);
 
fg.wip.cursor = .{ .block = continue_block };
}
@@ -6060,13 +6126,13 @@ pub const FuncGen = struct {
}
 
self.wip.cursor = .{ .block = case_block };
try self.genBodyDebugScope(case_body);
try self.genBodyDebugScope(null, case_body);
}
 
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]);
if (else_body.len != 0) {
try self.genBodyDebugScope(else_body);
try self.genBodyDebugScope(null, else_body);
} else {
_ = try self.wip.@"unreachable"();
}
@@ -6085,7 +6151,7 @@ pub const FuncGen = struct {
_ = try self.wip.br(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
// 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_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 = .{
.location = .{
.line = self.prev_dbg_line,
.column = self.prev_dbg_column,
.scope = self.scope,
.inlined_at = inlined_at_location,
.inlined_at = try self.inlined.toMetadata(self.wip.builder),
},
};
 
return .none;
}
 
fn airDbgInlineBegin(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
const o = self.dg.object;
const zcu = o.module;
 
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 airDbgInlineBlock(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
const ty_pl = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;
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]));
}
 
fn airDbgVarPtr(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
 
src/codegen/spirv.zig added: 428, removed: 359, total 69
@@ -208,6 +208,7 @@ pub const Object = struct {
false => .{ .unstructured = .{} },
},
.current_block_label = undefined,
.base_line = decl.src_line,
};
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.
func: SpvModule.Fn = .{},
 
/// Stack of the base offsets of the current decl, which is what `dbg_stmt` is relative to.
/// This is a stack to keep track of inline functions.
base_line_stack: std.ArrayListUnmanaged(u32) = .{},
/// The base offset of the current decl, which is what `dbg_stmt` is relative to.
base_line: u32,
 
/// If `gen` returned `Error.CodegenFail`, this contains an explanatory message.
/// Memory is owned by `module.gpa`.
@@ -401,7 +401,6 @@ const DeclGen = struct {
self.wip_pointers.deinit(self.gpa);
self.control_flow.deinit(self.gpa);
self.func.deinit(self.gpa);
self.base_line_stack.deinit(self.gpa);
}
 
/// 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;
 
try self.base_line_stack.append(self.gpa, decl.src_line);
 
if (decl.val.getFunction(mod)) |_| {
assert(decl.ty.zigTypeTag(mod) == .Fn);
const fn_info = mod.typeToFunc(decl.ty).?;
@@ -2317,8 +2314,7 @@ const DeclGen = struct {
.unreach, .trap => return self.airUnreach(),
 
.dbg_stmt => return self.airDbgStmt(inst),
.dbg_inline_begin => return self.airDbgInlineBegin(inst),
.dbg_inline_end => return self.airDbgInlineEnd(inst),
.dbg_inline_block => try self.airDbgInlineBlock(inst),
.dbg_var_ptr, .dbg_var_val => return self.airDbgVar(inst),
 
.unwrap_errunion_err => try self.airErrUnionErr(inst),
@@ -4311,6 +4307,12 @@ const DeclGen = struct {
}
 
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
// 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,
@@ -4320,10 +4322,6 @@ const DeclGen = struct {
 
const mod = self.module;
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 cf = switch (self.control_flow) {
@@ -5157,25 +5155,22 @@ const DeclGen = struct {
const decl = mod.declPtr(self.decl_index);
const path = decl.getFileScope(mod).sub_file_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, .{
.file = src_fname_id,
.line = base_line + dbg_stmt.line + 1,
.line = self.base_line + dbg_stmt.line + 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 fn_ty = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_fn;
const decl_index = mod.funcInfo(fn_ty.func).owner_decl;
const decl = mod.declPtr(decl_index);
try self.base_line_stack.append(self.gpa, decl.src_line);
}
 
fn airDbgInlineEnd(self: *DeclGen, inst: Air.Inst.Index) !void {
_ = inst;
_ = self.base_line_stack.pop();
const inst_datas = self.air.instructions.items(.data);
const extra = self.air.extraData(Air.DbgInlineBlock, inst_datas[@intFromEnum(inst)].ty_pl.payload);
const decl = mod.funcOwnerDeclPtr(extra.data.func);
const old_base_line = self.base_line;
defer self.base_line = old_base_line;
self.base_line = decl.src_line;
return self.lowerBlock(inst, @ptrCast(self.air.extra[extra.end..][0..extra.data.body_len]));
}
 
fn airDbgVar(self: *DeclGen, inst: Air.Inst.Index) !void {
 
src/print_air.zig added: 428, removed: 359, total 69
@@ -260,7 +260,7 @@ const Writer = struct {
.c_va_copy,
=> 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),
 
@@ -292,7 +292,6 @@ const Writer = struct {
.assembly => try w.writeAssembly(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),
.union_init => try w.writeUnionInit(s, inst),
.br => try w.writeBr(s, inst),
@@ -367,17 +366,34 @@ const Writer = struct {
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 extra = w.air.extraData(Air.Block, ty_pl.payload);
const body: []const Air.Inst.Index = @ptrCast(w.air.extra[extra.end..][0..extra.data.body_len]);
try w.writeType(s, ty_pl.ty.toType());
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|
liveness.getBlock(inst)
else
Liveness.BlockSlices{ .deaths = &.{} };
 
try w.writeType(s, ty_pl.ty.toType());
if (w.skip_body) return s.writeAll(", ...");
try s.writeAll(", {\n");
const old_indent = w.indent;
w.indent += 2;
@@ -661,13 +677,6 @@ const Writer = struct {
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 {
const pl_op = w.air.instructions.items(.data)[@intFromEnum(inst)].pl_op;
try w.writeOperand(s, inst, 0, pl_op.operand);
 
test/behavior/switch.zig added: 428, removed: 359, total 69
@@ -913,3 +913,20 @@ test "switch prong captures range" {
S.a(&arr, 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),
}
}