Dwarf: emit info about inline call sites

This commit is contained in:
Jacob Young 2024-08-19 14:56:17 -04:00
parent ef90eb0d4d
commit 62f7276501
21 changed files with 543 additions and 255 deletions

View File

@ -456,6 +456,8 @@ pub const Inst = struct {
/// Same as `dbg_var_ptr` except the local is a const, not a var, and the
/// operand is the local's value.
dbg_var_val,
/// Same as `dbg_var_val` except the local is an inline function argument.
dbg_arg_inline,
/// ?T => bool
/// Result type is always bool.
/// Uses the `un_op` field.
@ -1022,10 +1024,7 @@ pub const Inst = struct {
ty: Ref,
/// Index into `extra` of a null-terminated string representing the parameter name.
/// This is `.none` if debug info is stripped.
name: enum(u32) {
none = std.math.maxInt(u32),
_,
},
name: NullTerminatedString,
},
ty_op: struct {
ty: Ref,
@ -1440,6 +1439,7 @@ pub fn typeOfIndex(air: *const Air, inst: Air.Inst.Index, ip: *const InternPool)
.dbg_stmt,
.dbg_var_ptr,
.dbg_var_val,
.dbg_arg_inline,
.store,
.store_safe,
.fence,
@ -1562,14 +1562,16 @@ pub fn value(air: Air, inst: Inst.Ref, pt: Zcu.PerThread) !?Value {
return air.typeOfIndex(index, &pt.zcu.intern_pool).onePossibleValue(pt);
}
pub fn nullTerminatedString(air: Air, index: usize) [:0]const u8 {
const bytes = std.mem.sliceAsBytes(air.extra[index..]);
var end: usize = 0;
while (bytes[end] != 0) {
end += 1;
pub const NullTerminatedString = enum(u32) {
none = std.math.maxInt(u32),
_,
pub fn toSlice(nts: NullTerminatedString, air: Air) [:0]const u8 {
if (nts == .none) return "";
const bytes = std.mem.sliceAsBytes(air.extra[@intFromEnum(nts)..]);
return bytes[0..std.mem.indexOfScalar(u8, bytes, 0).? :0];
}
return bytes[0..end :0];
}
};
/// Returns whether the given instruction must always be lowered, for instance
/// because it can cause side effects. If an instruction does not need to be
@ -1596,6 +1598,7 @@ pub fn mustLower(air: Air, inst: Air.Inst.Index, ip: *const InternPool) bool {
.dbg_inline_block,
.dbg_var_ptr,
.dbg_var_val,
.dbg_arg_inline,
.ret,
.ret_safe,
.ret_load,

View File

@ -339,6 +339,7 @@ fn checkBody(air: Air, body: []const Air.Inst.Index, zcu: *Zcu) bool {
.dbg_var_ptr,
.dbg_var_val,
.dbg_arg_inline,
=> {
if (!checkRef(data.pl_op.operand, zcu)) return false;
},

View File

@ -464,6 +464,7 @@ pub fn categorizeOperand(
.dbg_var_ptr,
.dbg_var_val,
.dbg_arg_inline,
=> {
const o = air_datas[@intFromEnum(inst)].pl_op.operand;
if (o == operand_ref) return matchOperandSmallIndex(l, inst, 0, .none);
@ -1097,6 +1098,7 @@ fn analyzeInst(
.dbg_var_ptr,
.dbg_var_val,
.dbg_arg_inline,
=> {
const operand = inst_datas[@intFromEnum(inst)].pl_op.operand;
return analyzeOperands(a, pass, data, inst, .{ operand, .none, .none });

View File

@ -157,6 +157,7 @@ fn verifyBody(self: *Verify, body: []const Air.Inst.Index) Error!void {
},
.dbg_var_ptr,
.dbg_var_val,
.dbg_arg_inline,
.wasm_memory_grow,
=> {
const pl_op = data[@intFromEnum(inst)].pl_op;

View File

@ -376,7 +376,7 @@ pub const Block = struct {
c_import_buf: ?*std.ArrayList(u8) = null,
/// If not `null`, this boolean is set when a `dbg_var_ptr` or `dbg_var_val`
/// If not `null`, this boolean is set when a `dbg_var_ptr`, `dbg_var_val`, or `dbg_arg_inline`.
/// instruction is emitted. It signals that the innermost lexically
/// enclosing `block`/`block_inline` should be translated into a real AIR
/// `block` in order for codegen to match lexical scoping for debug vars.
@ -6567,7 +6567,7 @@ fn addDbgVar(
const operand_ty = sema.typeOf(operand);
const val_ty = switch (air_tag) {
.dbg_var_ptr => operand_ty.childType(mod),
.dbg_var_val => operand_ty,
.dbg_var_val, .dbg_arg_inline => operand_ty,
else => unreachable,
};
if (try sema.typeRequiresComptime(val_ty)) return;
@ -6586,25 +6586,26 @@ fn addDbgVar(
if (block.need_debug_scope) |ptr| ptr.* = true;
// Add the name to the AIR.
const name_extra_index = try sema.appendAirString(name);
const name_nts = try sema.appendAirString(name);
_ = try block.addInst(.{
.tag = air_tag,
.data = .{ .pl_op = .{
.payload = name_extra_index,
.payload = @intFromEnum(name_nts),
.operand = operand,
} },
});
}
pub fn appendAirString(sema: *Sema, str: []const u8) Allocator.Error!u32 {
const str_extra_index: u32 = @intCast(sema.air_extra.items.len);
pub fn appendAirString(sema: *Sema, str: []const u8) Allocator.Error!Air.NullTerminatedString {
if (str.len == 0) return .none;
const nts: Air.NullTerminatedString = @enumFromInt(sema.air_extra.items.len);
const elements_used = str.len / 4 + 1;
const elements = try sema.air_extra.addManyAsSlice(sema.gpa, elements_used);
const buffer = mem.sliceAsBytes(elements);
@memcpy(buffer[0..str.len], str);
buffer[str.len] = 0;
return str_extra_index;
return nts;
}
fn zirDeclRef(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
@ -7748,14 +7749,14 @@ fn analyzeCall(
const param_name = sema.code.nullTerminatedString(extra.data.name);
const inst = sema.inst_map.get(param).?;
try sema.addDbgVar(&child_block, inst, .dbg_var_val, param_name);
try sema.addDbgVar(&child_block, inst, .dbg_arg_inline, param_name);
},
.param_anytype, .param_anytype_comptime => {
const inst_data = sema.code.instructions.items(.data)[@intFromEnum(param)].str_tok;
const param_name = inst_data.get(sema.code);
const inst = sema.inst_map.get(param).?;
try sema.addDbgVar(&child_block, inst, .dbg_var_val, param_name);
try sema.addDbgVar(&child_block, inst, .dbg_arg_inline, param_name);
},
else => continue,
};
@ -8266,7 +8267,7 @@ fn instantiateGenericCall(
.name = if (child_block.ownerModule().strip)
.none
else
@enumFromInt(try sema.appendAirString(fn_zir.nullTerminatedString(param_name))),
try sema.appendAirString(fn_zir.nullTerminatedString(param_name)),
} },
}));
try child_block.params.append(sema.arena, .{

View File

@ -1241,7 +1241,10 @@ fn semaCau(pt: Zcu.PerThread, cau_index: InternPool.Cau.Index) !SemaCauResult {
}
const nav_already_populated, const queue_linker_work = switch (ip.indexToKey(decl_val.toIntern())) {
.func => |f| .{ f.owner_nav == nav_index, false },
.func => |f| status: {
const func_type = ip.indexToKey(f.ty).func_type;
break :status .{ f.owner_nav == nav_index, func_type.is_generic or func_type.cc == .Inline };
},
.variable => |v| .{ false, v.owner_nav == nav_index },
.@"extern" => .{ false, false },
else => .{ false, true },
@ -2158,7 +2161,7 @@ fn analyzeFnBody(pt: Zcu.PerThread, func_index: InternPool.Index) Zcu.SemaError!
.name = if (inner_block.ownerModule().strip)
.none
else
@enumFromInt(try sema.appendAirString(sema.code.nullTerminatedString(param_name))),
try sema.appendAirString(sema.code.nullTerminatedString(param_name)),
} },
});
}

View File

@ -170,7 +170,9 @@ const DbgInfoReloc = struct {
fn genDbgInfo(reloc: DbgInfoReloc, function: Self) !void {
switch (reloc.tag) {
.arg => try reloc.genArgDbgInfo(function),
.arg,
.dbg_arg_inline,
=> try reloc.genArgDbgInfo(function),
.dbg_var_ptr,
.dbg_var_val,
@ -201,7 +203,7 @@ const DbgInfoReloc = struct {
else => unreachable, // not a possible argument
};
try dw.genVarDebugInfo(.local_arg, reloc.name, reloc.ty, loc);
try dw.genLocalDebugInfo(.local_arg, reloc.name, reloc.ty, loc);
},
.plan9 => {},
.none => {},
@ -237,7 +239,7 @@ const DbgInfoReloc = struct {
break :blk .empty;
},
};
try dwarf.genVarDebugInfo(.local_var, reloc.name, reloc.ty, loc);
try dwarf.genLocalDebugInfo(.local_var, reloc.name, reloc.ty, loc);
},
.plan9 => {},
.none => {},
@ -799,6 +801,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
.dbg_inline_block => try self.airDbgInlineBlock(inst),
.dbg_var_ptr,
.dbg_var_val,
.dbg_arg_inline,
=> try self.airDbgVar(inst),
.call => try self.airCall(inst, .auto),
@ -4220,17 +4223,13 @@ fn airArg(self: *Self, inst: Air.Inst.Index) !void {
const ty = self.typeOfIndex(inst);
const tag = self.air.instructions.items(.tag)[@intFromEnum(inst)];
const name_nts = self.air.instructions.items(.data)[@intFromEnum(inst)].arg.name;
if (name_nts != .none) {
const name = self.air.nullTerminatedString(@intFromEnum(name_nts));
try self.dbg_info_relocs.append(self.gpa, .{
.tag = tag,
.ty = ty,
.name = name,
.mcv = self.args[arg_index],
});
}
const name = self.air.instructions.items(.data)[@intFromEnum(inst)].arg.name;
if (name != .none) try self.dbg_info_relocs.append(self.gpa, .{
.tag = tag,
.ty = ty,
.name = name.toSlice(self.air),
.mcv = self.args[arg_index],
});
const result: MCValue = if (self.liveness.isUnused(inst)) .dead else self.args[arg_index];
return self.finishAir(inst, result, .{ .none, .none, .none });
@ -4644,14 +4643,14 @@ fn airDbgVar(self: *Self, inst: Air.Inst.Index) !void {
const tag = self.air.instructions.items(.tag)[@intFromEnum(inst)];
const ty = self.typeOf(operand);
const mcv = try self.resolveInst(operand);
const name = self.air.nullTerminatedString(pl_op.payload);
const name: Air.NullTerminatedString = @enumFromInt(pl_op.payload);
log.debug("airDbgVar: %{d}: {}, {}", .{ inst, ty.fmtDebug(), mcv });
try self.dbg_info_relocs.append(self.gpa, .{
.tag = tag,
.ty = ty,
.name = name,
.name = name.toSlice(self.air),
.mcv = mcv,
});

View File

@ -248,7 +248,9 @@ const DbgInfoReloc = struct {
fn genDbgInfo(reloc: DbgInfoReloc, function: Self) !void {
switch (reloc.tag) {
.arg => try reloc.genArgDbgInfo(function),
.arg,
.dbg_arg_inline,
=> try reloc.genArgDbgInfo(function),
.dbg_var_ptr,
.dbg_var_val,
@ -279,7 +281,7 @@ const DbgInfoReloc = struct {
else => unreachable, // not a possible argument
};
try dw.genVarDebugInfo(.local_arg, reloc.name, reloc.ty, loc);
try dw.genLocalDebugInfo(.local_arg, reloc.name, reloc.ty, loc);
},
.plan9 => {},
.none => {},
@ -315,7 +317,7 @@ const DbgInfoReloc = struct {
break :blk .empty;
},
};
try dw.genVarDebugInfo(.local_var, reloc.name, reloc.ty, loc);
try dw.genLocalDebugInfo(.local_var, reloc.name, reloc.ty, loc);
},
.plan9 => {},
.none => {},
@ -786,6 +788,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
.dbg_inline_block => try self.airDbgInlineBlock(inst),
.dbg_var_ptr,
.dbg_var_val,
.dbg_arg_inline,
=> try self.airDbgVar(inst),
.call => try self.airCall(inst, .auto),
@ -4199,16 +4202,13 @@ fn airArg(self: *Self, inst: Air.Inst.Index) !void {
const ty = self.typeOfIndex(inst);
const tag = self.air.instructions.items(.tag)[@intFromEnum(inst)];
const name_nts = self.air.instructions.items(.data)[@intFromEnum(inst)].arg.name;
if (name_nts != .none) {
const name = self.air.nullTerminatedString(@intFromEnum(name_nts));
try self.dbg_info_relocs.append(self.gpa, .{
.tag = tag,
.ty = ty,
.name = name,
.mcv = self.args[arg_index],
});
}
const name = self.air.instructions.items(.data)[@intFromEnum(inst)].arg.name;
if (name != .none) try self.dbg_info_relocs.append(self.gpa, .{
.tag = tag,
.ty = ty,
.name = name.toSlice(self.air),
.mcv = self.args[arg_index],
});
const result: MCValue = if (self.liveness.isUnused(inst)) .dead else self.args[arg_index];
return self.finishAir(inst, result, .{ .none, .none, .none });
@ -4612,14 +4612,14 @@ fn airDbgVar(self: *Self, inst: Air.Inst.Index) !void {
const tag = self.air.instructions.items(.tag)[@intFromEnum(inst)];
const ty = self.typeOf(operand);
const mcv = try self.resolveInst(operand);
const name = self.air.nullTerminatedString(pl_op.payload);
const name: Air.NullTerminatedString = @enumFromInt(pl_op.payload);
log.debug("airDbgVar: %{d}: {}, {}", .{ inst, ty.fmtDebug(), mcv });
try self.dbg_info_relocs.append(self.gpa, .{
.tag = tag,
.ty = ty,
.name = name,
.name = name.toSlice(self.air),
.mcv = mcv,
});

View File

@ -1644,6 +1644,7 @@ fn genBody(func: *Func, body: []const Air.Inst.Index) InnerError!void {
.dbg_var_ptr,
.dbg_var_val,
.dbg_arg_inline,
=> try func.airDbgVar(inst),
.dbg_inline_block => try func.airDbgInlineBlock(inst),
@ -4673,11 +4674,15 @@ fn genArgDbgInfo(func: Func, inst: Air.Inst.Index, mcv: MCValue) !void {
const arg = func.air.instructions.items(.data)[@intFromEnum(inst)].arg;
const ty = arg.ty.toType();
if (arg.name == .none) return;
const name = func.air.nullTerminatedString(@intFromEnum(arg.name));
switch (func.debug_output) {
.dwarf => |dw| switch (mcv) {
.register => |reg| try dw.genVarDebugInfo(.local_arg, name, ty, .{ .reg = reg.dwarfNum() }),
.register => |reg| try dw.genLocalDebugInfo(
.local_arg,
arg.name.toSlice(func.air),
ty,
.{ .reg = reg.dwarfNum() },
),
.load_frame => {},
else => {},
},
@ -5179,16 +5184,17 @@ fn airDbgVar(func: *Func, inst: Air.Inst.Index) !void {
const operand = pl_op.operand;
const ty = func.typeOf(operand);
const mcv = try func.resolveInst(operand);
const name: Air.NullTerminatedString = @enumFromInt(pl_op.payload);
const name = func.air.nullTerminatedString(pl_op.payload);
try func.genVarDbgInfo(ty, mcv, name);
const tag = func.air.instructions.items(.tag)[@intFromEnum(inst)];
try func.genVarDbgInfo(tag, ty, mcv, name.toSlice(func.air));
return func.finishAir(inst, .unreach, .{ operand, .none, .none });
}
fn genVarDbgInfo(
func: Func,
tag: Air.Inst.Tag,
ty: Type,
mcv: MCValue,
name: []const u8,
@ -5205,7 +5211,11 @@ fn genVarDbgInfo(
break :blk .empty;
},
};
try dwarf.genVarDebugInfo(.local_var, name, ty, loc);
try dwarf.genLocalDebugInfo(switch (tag) {
else => unreachable,
.dbg_var_ptr, .dbg_var_val => .local_var,
.dbg_arg_inline => .local_arg,
}, name, ty, loc);
},
.plan9 => {},
.none => {},

View File

@ -643,6 +643,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
.dbg_inline_block => try self.airDbgInlineBlock(inst),
.dbg_var_ptr,
.dbg_var_val,
.dbg_arg_inline,
=> try self.airDbgVar(inst),
.call => try self.airCall(inst, .auto),
@ -1662,7 +1663,7 @@ fn airDbgStmt(self: *Self, inst: Air.Inst.Index) !void {
fn airDbgVar(self: *Self, inst: Air.Inst.Index) !void {
const pl_op = self.air.instructions.items(.data)[@intFromEnum(inst)].pl_op;
const name = self.air.nullTerminatedString(pl_op.payload);
const name: Air.NullTerminatedString = @enumFromInt(pl_op.payload);
const operand = pl_op.operand;
// TODO emit debug info for this variable
_ = name;
@ -3582,13 +3583,15 @@ fn genArgDbgInfo(self: Self, inst: Air.Inst.Index, mcv: MCValue) !void {
const arg = self.air.instructions.items(.data)[@intFromEnum(inst)].arg;
const ty = arg.ty.toType();
if (arg.name == .none) return;
const name = self.air.nullTerminatedString(@intFromEnum(arg.name));
switch (self.debug_output) {
.dwarf => |dw| switch (mcv) {
.register => |reg| try dw.genVarDebugInfo(.local_arg, name, ty, .{
.reg = reg.dwarfNum(),
}),
.register => |reg| try dw.genLocalDebugInfo(
.local_arg,
arg.name.toSlice(self.air),
ty,
.{ .reg = reg.dwarfNum() },
),
else => {},
},
else => {},

View File

@ -1917,8 +1917,9 @@ fn genInst(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
.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_var_ptr => func.airDbgVar(inst, .local_var, true),
.dbg_var_val => func.airDbgVar(inst, .local_var, false),
.dbg_arg_inline => func.airDbgVar(inst, .local_arg, false),
.call => func.airCall(inst, .auto),
.call_always_tail => func.airCall(inst, .always_tail),
@ -2585,13 +2586,13 @@ fn airArg(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
switch (func.debug_output) {
.dwarf => |dwarf| {
const name_nts = func.air.instructions.items(.data)[@intFromEnum(inst)].arg.name;
if (name_nts != .none) {
const name = func.air.nullTerminatedString(@intFromEnum(name_nts));
try dwarf.genVarDebugInfo(.local_arg, name, arg_ty, .{
.wasm_ext = .{ .local = arg.local.value },
});
}
const name = func.air.instructions.items(.data)[@intFromEnum(inst)].arg.name;
if (name != .none) try dwarf.genLocalDebugInfo(
.local_arg,
name.toSlice(func.air),
arg_ty,
.{ .wasm_ext = .{ .local = arg.local.value } },
);
},
else => {},
}
@ -6454,7 +6455,12 @@ fn airDbgInlineBlock(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
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 {
fn airDbgVar(
func: *CodeGen,
inst: Air.Inst.Index,
local_tag: link.File.Dwarf.WipNav.LocalTag,
is_ptr: bool,
) InnerError!void {
_ = is_ptr;
if (func.debug_output != .dwarf) return func.finishAir(inst, .none, &.{});
@ -6464,8 +6470,8 @@ fn airDbgVar(func: *CodeGen, inst: Air.Inst.Index, is_ptr: bool) InnerError!void
log.debug("airDbgVar: %{d}: {}, {}", .{ inst, ty.fmtDebug(), operand });
const name = func.air.nullTerminatedString(pl_op.payload);
log.debug(" var name = ({s})", .{name});
const name: Air.NullTerminatedString = @enumFromInt(pl_op.payload);
log.debug(" var name = ({s})", .{name.toSlice(func.air)});
const loc: link.File.Dwarf.Loc = switch (operand) {
.local => |local| .{ .wasm_ext = .{ .local = local.value } },
@ -6474,7 +6480,7 @@ fn airDbgVar(func: *CodeGen, inst: Air.Inst.Index, is_ptr: bool) InnerError!void
break :blk .empty;
},
};
try func.debug_output.dwarf.genVarDebugInfo(.local_var, name, ty, loc);
try func.debug_output.dwarf.genLocalDebugInfo(local_tag, name.toSlice(func.air), ty, loc);
return func.finishAir(inst, .none, &.{});
}

View File

@ -81,9 +81,6 @@ mir_instructions: std.MultiArrayList(Mir.Inst) = .{},
/// MIR extra data
mir_extra: std.ArrayListUnmanaged(u32) = .{},
stack_args: std.ArrayListUnmanaged(StackVar) = .{},
stack_vars: std.ArrayListUnmanaged(StackVar) = .{},
/// Byte offset within the source file of the ending curly.
end_di_line: u32,
end_di_column: u32,
@ -728,12 +725,6 @@ const InstTracking = struct {
}
};
const StackVar = struct {
name: []const u8,
type: Type,
frame_addr: FrameAddr,
};
const FrameAlloc = struct {
abi_size: u31,
spill_pad: u3,
@ -839,8 +830,6 @@ pub fn generate(
function.exitlude_jump_relocs.deinit(gpa);
function.mir_instructions.deinit(gpa);
function.mir_extra.deinit(gpa);
function.stack_args.deinit(gpa);
function.stack_vars.deinit(gpa);
}
wip_mir_log.debug("{}:", .{fmtNav(func.owner_nav, ip)});
@ -913,9 +902,6 @@ pub fn generate(
else => |e| return e,
};
try function.genStackVarDebugInfo(.local_arg, function.stack_args.items);
try function.genStackVarDebugInfo(.local_var, function.stack_vars.items);
var mir: Mir = .{
.instructions = function.mir_instructions.toOwnedSlice(),
.extra = try function.mir_extra.toOwnedSlice(gpa),
@ -924,6 +910,7 @@ pub fn generate(
defer mir.deinit(gpa);
var emit: Emit = .{
.air = function.air,
.lower = .{
.bin_file = bin_file,
.allocator = gpa,
@ -1013,14 +1000,15 @@ pub fn generateLazy(
else => |e| return e,
};
var mir = Mir{
var mir: Mir = .{
.instructions = function.mir_instructions.toOwnedSlice(),
.extra = try function.mir_extra.toOwnedSlice(gpa),
.frame_locs = function.frame_locs.toOwnedSlice(),
};
defer mir.deinit(gpa);
var emit = Emit{
var emit: Emit = .{
.air = function.air,
.lower = .{
.bin_file = bin_file,
.allocator = gpa,
@ -1116,7 +1104,7 @@ fn formatWipMir(
) @TypeOf(writer).Error!void {
const comp = data.self.bin_file.comp;
const mod = comp.root_mod;
var lower = Lower{
var lower: Lower = .{
.bin_file = data.self.bin_file,
.allocator = data.self.gpa,
.mir = .{
@ -1357,6 +1345,56 @@ fn asmPlaceholder(self: *Self) !Mir.Inst.Index {
});
}
const MirTagAir = enum { dbg_local };
fn asmAir(self: *Self, tag: MirTagAir, inst: Air.Inst.Index) !void {
_ = try self.addInst(.{
.tag = .pseudo,
.ops = switch (tag) {
.dbg_local => .pseudo_dbg_local_a,
},
.data = .{ .a = .{ .air_inst = inst } },
});
}
fn asmAirImmediate(self: *Self, tag: MirTagAir, inst: Air.Inst.Index, imm: Immediate) !void {
const ops: Mir.Inst.Ops, const i: u32 = switch (imm) {
.signed => |s| .{ switch (tag) {
.dbg_local => .pseudo_dbg_local_ai_s,
}, @bitCast(s) },
.unsigned => |u| if (math.cast(u32, u)) |small|
.{ switch (tag) {
.dbg_local => .pseudo_dbg_local_ai_u,
}, small }
else
.{ switch (tag) {
.dbg_local => .pseudo_dbg_local_ai_64,
}, try self.addExtra(Mir.Imm64.encode(u)) },
.reloc => unreachable,
};
_ = try self.addInst(.{
.tag = .pseudo,
.ops = ops,
.data = .{ .ai = .{
.air_inst = inst,
.i = i,
} },
});
}
fn asmAirMemory(self: *Self, tag: MirTagAir, inst: Air.Inst.Index, m: Memory) !void {
_ = try self.addInst(.{
.tag = .pseudo,
.ops = switch (tag) {
.dbg_local => .pseudo_dbg_local_am,
},
.data = .{ .ax = .{
.air_inst = inst,
.payload = try self.addExtra(Mir.Memory.encode(m)),
} },
});
}
fn asmOpOnly(self: *Self, tag: Mir.Inst.FixedTag) !void {
_ = try self.addInst(.{
.tag = tag[1],
@ -1424,31 +1462,22 @@ fn asmRegisterRegister(self: *Self, tag: Mir.Inst.FixedTag, reg1: Register, reg2
}
fn asmRegisterImmediate(self: *Self, tag: Mir.Inst.FixedTag, reg: Register, imm: Immediate) !void {
const ops: Mir.Inst.Ops = switch (imm) {
.signed => .ri_s,
.unsigned => |u| if (math.cast(u32, u)) |_| .ri_u else .ri64,
const ops: Mir.Inst.Ops, const i: u32 = switch (imm) {
.signed => |s| .{ .ri_s, @bitCast(s) },
.unsigned => |u| if (math.cast(u32, u)) |small|
.{ .ri_u, small }
else
.{ .ri_64, try self.addExtra(Mir.Imm64.encode(imm.unsigned)) },
.reloc => unreachable,
};
_ = try self.addInst(.{
.tag = tag[1],
.ops = ops,
.data = switch (ops) {
.ri_s, .ri_u => .{ .ri = .{
.fixes = tag[0],
.r1 = reg,
.i = switch (imm) {
.signed => |s| @bitCast(s),
.unsigned => |u| @intCast(u),
.reloc => unreachable,
},
} },
.ri64 => .{ .rx = .{
.fixes = tag[0],
.r1 = reg,
.payload = try self.addExtra(Mir.Imm64.encode(imm.unsigned)),
} },
else => unreachable,
},
.data = .{ .ri = .{
.fixes = tag[0],
.r1 = reg,
.i = i,
} },
});
}
@ -2158,6 +2187,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
.dbg_inline_block => try self.airDbgInlineBlock(inst),
.dbg_var_ptr,
.dbg_var_val,
.dbg_arg_inline,
=> try self.airDbgVar(inst),
.call => try self.airCall(inst, .auto),
@ -11951,87 +11981,59 @@ fn airArg(self: *Self, inst: Air.Inst.Index) !void {
fn airDbgArg(self: *Self, inst: Air.Inst.Index) !void {
defer self.finishAirBookkeeping();
if (self.debug_output == .none) return;
const name_nts = self.air.instructions.items(.data)[@intFromEnum(inst)].arg.name;
const name = self.air.nullTerminatedString(@intFromEnum(name_nts));
if (name.len > 0) {
const arg_ty = self.typeOfIndex(inst);
const arg_mcv = self.getResolvedInstValue(inst).short;
try self.genVarDebugInfo(.local_arg, .dbg_var_val, name, arg_ty, arg_mcv);
}
const name = self.air.instructions.items(.data)[@intFromEnum(inst)].arg.name;
if (name != .none) try self.genLocalDebugInfo(inst, self.getResolvedInstValue(inst).short);
if (self.liveness.isUnused(inst)) try self.processDeath(inst);
}
fn genVarDebugInfo(
fn genLocalDebugInfo(
self: *Self,
var_tag: link.File.Dwarf.WipNav.VarTag,
tag: Air.Inst.Tag,
name: []const u8,
ty: Type,
inst: Air.Inst.Index,
mcv: MCValue,
) !void {
const stack_vars = switch (var_tag) {
.local_arg => &self.stack_args,
.local_var => &self.stack_vars,
};
switch (self.debug_output) {
.dwarf => |dwarf| switch (tag) {
else => unreachable,
.dbg_var_ptr => {
const var_ty = ty.childType(self.pt.zcu);
switch (mcv) {
else => {
log.info("dbg_var_ptr({s}({}))", .{ @tagName(mcv), mcv });
unreachable;
},
.unreach, .dead, .elementwise_regs_then_frame, .reserved_frame, .air_ref => unreachable,
.lea_frame => |frame_addr| try stack_vars.append(self.gpa, .{
.name = name,
.type = var_ty,
.frame_addr = frame_addr,
}),
.lea_symbol => |sym_off| try dwarf.genVarDebugInfo(var_tag, name, var_ty, .{ .plus = .{
&.{ .addr = .{ .sym = sym_off.sym } },
&.{ .consts = sym_off.off },
} }),
}
},
.dbg_var_val => switch (mcv) {
.none => try dwarf.genVarDebugInfo(var_tag, name, ty, .empty),
if (self.debug_output == .none) return;
switch (self.air.instructions.items(.tag)[@intFromEnum(inst)]) {
else => unreachable,
.arg, .dbg_arg_inline, .dbg_var_val => |tag| {
switch (mcv) {
.none => try self.asmAir(.dbg_local, inst),
.unreach, .dead, .elementwise_regs_then_frame, .reserved_frame, .air_ref => unreachable,
.immediate => |immediate| try dwarf.genVarDebugInfo(var_tag, name, ty, .{ .stack_value = &.{
.constu = immediate,
} }),
.immediate => |imm| try self.asmAirImmediate(.dbg_local, inst, Immediate.u(imm)),
else => {
const ty = switch (tag) {
else => unreachable,
.arg => self.typeOfIndex(inst),
.dbg_arg_inline, .dbg_var_val => self.typeOf(
self.air.instructions.items(.data)[@intFromEnum(inst)].pl_op.operand,
),
};
const frame_index = try self.allocFrameIndex(FrameAlloc.initSpill(ty, self.pt));
try self.genSetMem(.{ .frame = frame_index }, 0, ty, mcv, .{});
try stack_vars.append(self.gpa, .{
.name = name,
.type = ty,
.frame_addr = .{ .index = frame_index },
try self.asmAirMemory(.dbg_local, inst, .{
.base = .{ .frame = frame_index },
.mod = .{ .rm = .{ .size = .qword } },
});
},
},
}
},
.plan9 => {},
.none => {},
}
}
fn genStackVarDebugInfo(
self: Self,
var_tag: link.File.Dwarf.WipNav.VarTag,
stack_vars: []const StackVar,
) !void {
switch (self.debug_output) {
.dwarf => |dwarf| for (stack_vars) |stack_var| {
const frame_loc = self.frame_locs.get(@intFromEnum(stack_var.frame_addr.index));
try dwarf.genVarDebugInfo(var_tag, stack_var.name, stack_var.type, .{ .plus = .{
&.{ .breg = frame_loc.base.dwarfNum() },
&.{ .consts = @as(i33, frame_loc.disp) + stack_var.frame_addr.off },
} });
.dbg_var_ptr => switch (mcv) {
else => unreachable,
.unreach, .dead, .elementwise_regs_then_frame, .reserved_frame, .air_ref => unreachable,
.lea_frame => |frame_addr| try self.asmAirMemory(.dbg_local, inst, .{
.base = .{ .frame = frame_addr.index },
.mod = .{ .rm = .{
.size = .qword,
.disp = frame_addr.off,
} },
}),
.lea_symbol => |sym_off| try self.asmAirMemory(.dbg_local, inst, .{
.base = .{ .reloc = .{ .atom_index = undefined, .sym_index = sym_off.sym } },
.mod = .{ .rm = .{
.size = .qword,
.disp = sym_off.off,
} },
}),
},
.plan9 => {},
.none => {},
}
}
@ -13060,29 +13062,21 @@ fn airDbgInlineBlock(self: *Self, inst: Air.Inst.Index) !void {
self.inline_func = extra.data.func;
_ = try self.addInst(.{
.tag = .pseudo,
.ops = .pseudo_dbg_inline_func,
.ops = .pseudo_dbg_enter_inline_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,
.ops = .pseudo_dbg_leave_inline_func,
.data = .{ .func = old_inline_func },
});
}
fn airDbgVar(self: *Self, inst: Air.Inst.Index) !void {
const pl_op = self.air.instructions.items(.data)[@intFromEnum(inst)].pl_op;
const operand = pl_op.operand;
const ty = self.typeOf(operand);
const mcv = try self.resolveInst(operand);
const name = self.air.nullTerminatedString(pl_op.payload);
const tag = self.air.instructions.items(.tag)[@intFromEnum(inst)];
try self.genVarDebugInfo(.local_var, tag, name, ty, mcv);
return self.finishAir(inst, .unreach, .{ operand, .none, .none });
try self.genLocalDebugInfo(inst, try self.resolveInst(pl_op.operand));
return self.finishAir(inst, .unreach, .{ pl_op.operand, .none, .none });
}
fn genCondBrMir(self: *Self, ty: Type, mcv: MCValue) !Mir.Inst.Index {

View File

@ -1,5 +1,6 @@
//! This file contains the functionality for emitting x86_64 MIR as machine code
air: Air,
lower: Lower,
debug_output: DebugInfoOutput,
code: *std.ArrayList(u8),
@ -232,13 +233,96 @@ pub fn emitMir(emit: *Emit) Error!void {
.none => {},
}
},
.pseudo_dbg_inline_func => {
.pseudo_dbg_enter_inline_func => {
switch (emit.debug_output) {
.dwarf => |dw| {
log.debug("mirDbgInline (line={d}, col={d})", .{
log.debug("mirDbgEnterInline (line={d}, col={d})", .{
emit.prev_di_line, emit.prev_di_column,
});
try dw.setInlineFunc(mir_inst.data.func);
try dw.enterInlineFunc(mir_inst.data.func, emit.code.items.len, emit.prev_di_line, emit.prev_di_column);
},
.plan9 => {},
.none => {},
}
},
.pseudo_dbg_leave_inline_func => {
switch (emit.debug_output) {
.dwarf => |dw| {
log.debug("mirDbgLeaveInline (line={d}, col={d})", .{
emit.prev_di_line, emit.prev_di_column,
});
try dw.leaveInlineFunc(mir_inst.data.func, emit.code.items.len);
},
.plan9 => {},
.none => {},
}
},
.pseudo_dbg_local_a,
.pseudo_dbg_local_ai_s,
.pseudo_dbg_local_ai_u,
.pseudo_dbg_local_ai_64,
.pseudo_dbg_local_am,
=> {
switch (emit.debug_output) {
.dwarf => |dw| {
var loc_buf: [2]link.File.Dwarf.Loc = undefined;
const air_inst_index, const loc: link.File.Dwarf.Loc = switch (mir_inst.ops) {
else => unreachable,
.pseudo_dbg_local_a => .{ mir_inst.data.a.air_inst, .empty },
.pseudo_dbg_local_ai_s,
.pseudo_dbg_local_ai_u,
.pseudo_dbg_local_ai_64,
=> .{ mir_inst.data.ai.air_inst, .{ .stack_value = stack_value: {
loc_buf[0] = switch (emit.lower.imm(mir_inst.ops, mir_inst.data.ai.i)) {
.signed => |s| .{ .consts = s },
.unsigned => |u| .{ .constu = u },
};
break :stack_value &loc_buf[0];
} } },
.pseudo_dbg_local_am => loc: {
const mem = emit.lower.mem(mir_inst.data.ax.payload);
break :loc .{ mir_inst.data.ax.air_inst, .{ .plus = .{
base: {
loc_buf[0] = switch (mem.base()) {
.none => .{ .constu = 0 },
.reg => |reg| .{ .breg = reg.dwarfNum() },
.frame => unreachable,
.reloc => |reloc| .{ .addr = .{ .sym = reloc.sym_index } },
};
break :base &loc_buf[0];
},
disp: {
loc_buf[1] = switch (mem.disp()) {
.signed => |s| .{ .consts = s },
.unsigned => |u| .{ .constu = u },
};
break :disp &loc_buf[1];
},
} } };
},
};
const ip = &emit.lower.bin_file.comp.module.?.intern_pool;
const air_inst = emit.air.instructions.get(@intFromEnum(air_inst_index));
const name: Air.NullTerminatedString = switch (air_inst.tag) {
else => unreachable,
.arg => air_inst.data.arg.name,
.dbg_var_ptr, .dbg_var_val, .dbg_arg_inline => @enumFromInt(air_inst.data.pl_op.payload),
};
try dw.genLocalDebugInfo(
switch (air_inst.tag) {
else => unreachable,
.arg, .dbg_arg_inline => .local_arg,
.dbg_var_ptr, .dbg_var_val => .local_var,
},
name.toSlice(emit.air),
switch (air_inst.tag) {
else => unreachable,
.arg => emit.air.typeOfIndex(air_inst_index, ip),
.dbg_var_ptr => emit.air.typeOf(air_inst.data.pl_op.operand, ip).childTypeIp(ip),
.dbg_var_val, .dbg_arg_inline => emit.air.typeOf(air_inst.data.pl_op.operand, ip),
},
loc,
);
},
.plan9 => {},
.none => {},
@ -285,7 +369,7 @@ fn fixupRelocs(emit: *Emit) Error!void {
const target = emit.code_offset_mapping.get(reloc.target) orelse
return emit.fail("JMP/CALL relocation target not found!", .{});
const disp = @as(i64, @intCast(target)) - @as(i64, @intCast(reloc.source + reloc.length));
mem.writeInt(i32, emit.code.items[reloc.offset..][0..4], @intCast(disp), .little);
std.mem.writeInt(i32, emit.code.items[reloc.offset..][0..4], @intCast(disp), .little);
}
}
@ -340,9 +424,9 @@ fn dbgAdvancePCAndLine(emit: *Emit, line: u32, column: u32) Error!void {
const link = @import("../../link.zig");
const log = std.log.scoped(.emit);
const mem = std.mem;
const std = @import("std");
const Air = @import("../../Air.zig");
const DebugInfoOutput = @import("../../codegen.zig").DebugInfoOutput;
const Emit = @This();
const Lower = @import("Lower.zig");

View File

@ -4,10 +4,10 @@ bin_file: *link.File,
output_mode: std.builtin.OutputMode,
link_mode: std.builtin.LinkMode,
pic: bool,
allocator: Allocator,
allocator: std.mem.Allocator,
mir: Mir,
cc: std.builtin.CallingConvention,
err_msg: ?*ErrorMsg = null,
err_msg: ?*Zcu.ErrorMsg = null,
src_loc: Zcu.LazySrcLoc,
result_insts_len: u8 = undefined,
result_relocs_len: u8 = undefined,
@ -267,7 +267,13 @@ pub fn lowerMir(lower: *Lower, index: Mir.Inst.Index) Error!struct {
.pseudo_dbg_prologue_end_none,
.pseudo_dbg_line_line_column,
.pseudo_dbg_epilogue_begin_none,
.pseudo_dbg_inline_func,
.pseudo_dbg_enter_inline_func,
.pseudo_dbg_leave_inline_func,
.pseudo_dbg_local_a,
.pseudo_dbg_local_ai_s,
.pseudo_dbg_local_ai_u,
.pseudo_dbg_local_ai_64,
.pseudo_dbg_local_am,
.pseudo_dead_none,
=> {},
else => unreachable,
@ -283,17 +289,18 @@ pub fn lowerMir(lower: *Lower, index: Mir.Inst.Index) Error!struct {
pub fn fail(lower: *Lower, comptime format: []const u8, args: anytype) Error {
@setCold(true);
assert(lower.err_msg == null);
lower.err_msg = try ErrorMsg.create(lower.allocator, lower.src_loc, format, args);
lower.err_msg = try Zcu.ErrorMsg.create(lower.allocator, lower.src_loc, format, args);
return error.LowerFail;
}
fn imm(lower: Lower, ops: Mir.Inst.Ops, i: u32) Immediate {
pub fn imm(lower: Lower, ops: Mir.Inst.Ops, i: u32) Immediate {
return switch (ops) {
.rri_s,
.ri_s,
.i_s,
.mi_s,
.rmi_s,
.pseudo_dbg_local_ai_s,
=> Immediate.s(@bitCast(i)),
.rrri,
@ -306,15 +313,18 @@ fn imm(lower: Lower, ops: Mir.Inst.Ops, i: u32) Immediate {
.mri,
.rrm,
.rrmi,
.pseudo_dbg_local_ai_u,
=> Immediate.u(i),
.ri64 => Immediate.u(lower.mir.extraData(Mir.Imm64, i).data.decode()),
.ri_64,
.pseudo_dbg_local_ai_64,
=> Immediate.u(lower.mir.extraData(Mir.Imm64, i).data.decode()),
else => unreachable,
};
}
fn mem(lower: Lower, payload: u32) Memory {
pub fn mem(lower: Lower, payload: u32) Memory {
return lower.mir.resolveFrameLoc(lower.mir.extraData(Mir.Memory, payload).data).decode();
}
@ -490,8 +500,8 @@ fn generic(lower: *Lower, inst: Mir.Inst) Error!void {
.rrrr => inst.data.rrrr.fixes,
.rrri => inst.data.rrri.fixes,
.rri_s, .rri_u => inst.data.rri.fixes,
.ri_s, .ri_u => inst.data.ri.fixes,
.ri64, .rm, .rmi_s, .mr => inst.data.rx.fixes,
.ri_s, .ri_u, .ri_64 => inst.data.ri.fixes,
.rm, .rmi_s, .mr => inst.data.rx.fixes,
.mrr, .rrm, .rmr => inst.data.rrx.fixes,
.rmi, .mri => inst.data.rix.fixes,
.rrmr => inst.data.rrrx.fixes,
@ -554,14 +564,10 @@ fn generic(lower: *Lower, inst: Mir.Inst) Error!void {
.{ .reg = inst.data.rrri.r3 },
.{ .imm = lower.imm(inst.ops, inst.data.rrri.i) },
},
.ri_s, .ri_u => &.{
.ri_s, .ri_u, .ri_64 => &.{
.{ .reg = inst.data.ri.r1 },
.{ .imm = lower.imm(inst.ops, inst.data.ri.i) },
},
.ri64 => &.{
.{ .reg = inst.data.rx.r1 },
.{ .imm = lower.imm(inst.ops, inst.data.rx.payload) },
},
.rri_s, .rri_u => &.{
.{ .reg = inst.data.rri.r1 },
.{ .reg = inst.data.rri.r2 },
@ -670,9 +676,6 @@ const encoder = @import("encoder.zig");
const link = @import("../../link.zig");
const std = @import("std");
const Air = @import("../../Air.zig");
const Allocator = std.mem.Allocator;
const ErrorMsg = Zcu.ErrorMsg;
const Immediate = Instruction.Immediate;
const Instruction = encoder.Instruction;
const Lower = @This();

View File

@ -760,8 +760,8 @@ pub const Inst = struct {
/// Uses `ri` payload.
ri_u,
/// Register, 64-bit unsigned immediate operands.
/// Uses `rx` payload with payload type `Imm64`.
ri64,
/// Uses `ri` payload with `i` index of extra data of type `Imm64`.
ri_64,
/// Immediate (sign-extended) operand.
/// Uses `imm` payload.
i_s,
@ -796,7 +796,7 @@ pub const Inst = struct {
/// Uses `rrix` payload with extra data of type `Memory`.
rrmi,
/// Single memory operand.
/// Uses `x` with extra data of type `Memory`.
/// Uses `x` payload with extra data of type `Memory`.
m,
/// Memory, immediate (sign-extend) operands.
/// Uses `x` payload with extra data of type `Imm32` followed by `Memory`.
@ -868,16 +868,16 @@ pub const Inst = struct {
pseudo_j_nz_or_p_inst,
/// Probe alignment
/// Uses `ri` payload
/// Uses `ri` payload.
pseudo_probe_align_ri_s,
/// Probe adjust unrolled
/// Uses `ri` payload
/// Uses `ri` payload.
pseudo_probe_adjust_unrolled_ri_s,
/// Probe adjust setup
/// Uses `rri` payload
/// Uses `rri` payload.
pseudo_probe_adjust_setup_rri_s,
/// Probe adjust loop
/// Uses `rr` payload
/// Uses `rr` payload.
pseudo_probe_adjust_loop_rr,
/// Push registers
/// Uses `reg_list` payload.
@ -893,8 +893,25 @@ pub const Inst = struct {
pseudo_dbg_line_line_column,
/// Start of epilogue
pseudo_dbg_epilogue_begin_none,
/// Start or end of inline function
pseudo_dbg_inline_func,
/// Start of inline function
pseudo_dbg_enter_inline_func,
/// End of inline function
pseudo_dbg_leave_inline_func,
/// Local argument or variable.
/// Uses `a` payload.
pseudo_dbg_local_a,
/// Local argument or variable.
/// Uses `ai` payload.
pseudo_dbg_local_ai_s,
/// Local argument or variable.
/// Uses `ai` payload.
pseudo_dbg_local_ai_u,
/// Local argument or variable.
/// Uses `ax` payload with extra data of type `Imm64`.
pseudo_dbg_local_ai_64,
/// Local argument or variable.
/// Uses `ax` payload with extra data of type `Memory`.
pseudo_dbg_local_am,
/// Tombstone
/// Emitter should skip this instruction.
@ -997,6 +1014,17 @@ pub const Inst = struct {
fixes: Fixes = ._,
payload: u32,
},
a: struct {
air_inst: Air.Inst.Index,
},
ai: struct {
air_inst: Air.Inst.Index,
i: u32,
},
ax: struct {
air_inst: Air.Inst.Index,
payload: u32,
},
/// Relocation for the linker where:
/// * `atom_index` is the index of the source
/// * `sym_index` is the index of the target
@ -1225,6 +1253,7 @@ const builtin = @import("builtin");
const encoder = @import("encoder.zig");
const std = @import("std");
const Air = @import("../../Air.zig");
const IntegerBitSet = std.bit_set.IntegerBitSet;
const InternPool = @import("../../InternPool.zig");
const Mir = @This();

View File

@ -128,8 +128,8 @@ pub const Instruction = struct {
} };
}
pub fn rip(ptr_size: PtrSize, disp: i32) Memory {
return .{ .rip = .{ .ptr_size = ptr_size, .disp = disp } };
pub fn rip(ptr_size: PtrSize, displacement: i32) Memory {
return .{ .rip = .{ .ptr_size = ptr_size, .disp = displacement } };
}
pub fn isSegmentRegister(mem: Memory) bool {
@ -158,6 +158,14 @@ pub const Instruction = struct {
};
}
pub fn disp(mem: Memory) Immediate {
return switch (mem) {
.sib => |s| Immediate.s(s.disp),
.rip => |r| Immediate.s(r.disp),
.moffs => |m| Immediate.u(m.offset),
};
}
pub fn bitSize(mem: Memory) u64 {
return switch (mem) {
.rip => |r| r.ptr_size.bitSize(),

View File

@ -3293,7 +3293,7 @@ fn genBodyInner(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail,
.dbg_stmt => try airDbgStmt(f, inst),
.dbg_inline_block => try airDbgInlineBlock(f, inst),
.dbg_var_ptr, .dbg_var_val => try airDbgVar(f, inst),
.dbg_var_ptr, .dbg_var_val, .dbg_arg_inline => try airDbgVar(f, inst),
.call => try airCall(f, inst, .auto),
.call_always_tail => .none,
@ -4590,14 +4590,15 @@ fn airDbgInlineBlock(f: *Function, inst: Air.Inst.Index) !CValue {
fn airDbgVar(f: *Function, inst: Air.Inst.Index) !CValue {
const pt = f.object.dg.pt;
const zcu = pt.zcu;
const tag = f.air.instructions.items(.tag)[@intFromEnum(inst)];
const pl_op = f.air.instructions.items(.data)[@intFromEnum(inst)].pl_op;
const name = f.air.nullTerminatedString(pl_op.payload);
const name: Air.NullTerminatedString = @enumFromInt(pl_op.payload);
const operand_is_undef = if (try f.air.value(pl_op.operand, pt)) |v| v.isUndefDeep(zcu) else false;
if (!operand_is_undef) _ = try f.resolveInst(pl_op.operand);
try reap(f, inst, &.{pl_op.operand});
const writer = f.object.writer();
try writer.print("/* var:{s} */\n", .{name});
try writer.print("/* {s}:{s} */\n", .{ @tagName(tag), name.toSlice(f.air) });
return .none;
}

View File

@ -1665,6 +1665,7 @@ pub const Object = struct {
.ret_ptr = ret_ptr,
.args = args.items,
.arg_index = 0,
.arg_inline_index = 0,
.func_inst_table = .{},
.blocks = .{},
.sync_scope = if (owner_mod.single_threaded) .singlethread else .system,
@ -4769,7 +4770,8 @@ pub const FuncGen = struct {
/// it omits 0-bit types. If the function uses sret as the first parameter,
/// this slice does not include it.
args: []const Builder.Value,
arg_index: usize,
arg_index: u32,
arg_inline_index: u32,
err_ret_trace: Builder.Value = .none,
@ -5082,7 +5084,8 @@ pub const FuncGen = struct {
.dbg_stmt => try self.airDbgStmt(inst),
.dbg_inline_block => try self.airDbgInlineBlock(inst),
.dbg_var_ptr => try self.airDbgVarPtr(inst),
.dbg_var_val => try self.airDbgVarVal(inst),
.dbg_var_val => try self.airDbgVarVal(inst, false),
.dbg_arg_inline => try self.airDbgVarVal(inst, true),
.c_va_arg => try self.airCVaArg(inst),
.c_va_copy => try self.airCVaCopy(inst),
@ -6677,6 +6680,7 @@ pub const FuncGen = struct {
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);
self.arg_inline_index = 0;
return self.lowerBlock(inst, extra.data.func, @ptrCast(self.air.extra[extra.end..][0..extra.data.body_len]));
}
@ -6685,11 +6689,11 @@ pub const FuncGen = struct {
const mod = o.pt.zcu;
const pl_op = self.air.instructions.items(.data)[@intFromEnum(inst)].pl_op;
const operand = try self.resolveInst(pl_op.operand);
const name = self.air.nullTerminatedString(pl_op.payload);
const name: Air.NullTerminatedString = @enumFromInt(pl_op.payload);
const ptr_ty = self.typeOf(pl_op.operand);
const debug_local_var = try o.builder.debugLocalVar(
try o.builder.metadataString(name),
try o.builder.metadataString(name.toSlice(self.air)),
self.file,
self.scope,
self.prev_dbg_line,
@ -6712,15 +6716,25 @@ pub const FuncGen = struct {
return .none;
}
fn airDbgVarVal(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
fn airDbgVarVal(self: *FuncGen, inst: Air.Inst.Index, is_arg: bool) !Builder.Value {
const o = self.ng.object;
const pl_op = self.air.instructions.items(.data)[@intFromEnum(inst)].pl_op;
const operand = try self.resolveInst(pl_op.operand);
const operand_ty = self.typeOf(pl_op.operand);
const name = self.air.nullTerminatedString(pl_op.payload);
const name: Air.NullTerminatedString = @enumFromInt(pl_op.payload);
const debug_local_var = try o.builder.debugLocalVar(
try o.builder.metadataString(name),
const debug_local_var = if (is_arg) try o.builder.debugParameter(
try o.builder.metadataString(name.toSlice(self.air)),
self.file,
self.scope,
self.prev_dbg_line,
try o.lowerDebugType(operand_ty),
arg_no: {
self.arg_inline_index += 1;
break :arg_no self.arg_inline_index;
},
) else try o.builder.debugLocalVar(
try o.builder.metadataString(name.toSlice(self.air)),
self.file,
self.scope,
self.prev_dbg_line,
@ -8835,12 +8849,12 @@ pub const FuncGen = struct {
const lbrace_col = func.lbrace_column + 1;
const debug_parameter = try o.builder.debugParameter(
try o.builder.metadataString(self.air.nullTerminatedString(@intFromEnum(name))),
try o.builder.metadataString(name.toSlice(self.air)),
self.file,
self.scope,
lbrace_line,
try o.lowerDebugType(inst_ty),
@intCast(self.arg_index),
self.arg_index,
);
const old_location = self.wip.debug_location;

View File

@ -6366,8 +6366,8 @@ const NavGen = struct {
fn airDbgVar(self: *NavGen, inst: Air.Inst.Index) !void {
const pl_op = self.air.instructions.items(.data)[@intFromEnum(inst)].pl_op;
const target_id = try self.resolve(pl_op.operand);
const name = self.air.nullTerminatedString(pl_op.payload);
try self.spv.debugName(target_id, name);
const name: Air.NullTerminatedString = @enumFromInt(pl_op.payload);
try self.spv.debugName(target_id, name.toSlice(self.air));
}
fn airAssembly(self: *NavGen, inst: Air.Inst.Index) !?IdRef {

View File

@ -986,7 +986,9 @@ pub const WipNav = struct {
entry: Entry.Index,
any_children: bool,
func: InternPool.Index,
func_sym_index: u32,
func_high_reloc: u32,
inlined_funcs_high_reloc: std.ArrayListUnmanaged(u32),
debug_info: std.ArrayListUnmanaged(u8),
debug_line: std.ArrayListUnmanaged(u8),
debug_loclists: std.ArrayListUnmanaged(u8),
@ -994,6 +996,7 @@ pub const WipNav = struct {
pub fn deinit(wip_nav: *WipNav) void {
const gpa = wip_nav.dwarf.gpa;
if (wip_nav.func != .none) wip_nav.inlined_funcs_high_reloc.deinit(gpa);
wip_nav.debug_info.deinit(gpa);
wip_nav.debug_line.deinit(gpa);
wip_nav.debug_loclists.deinit(gpa);
@ -1004,10 +1007,10 @@ pub const WipNav = struct {
return wip_nav.debug_info.writer(wip_nav.dwarf.gpa);
}
pub const VarTag = enum { local_arg, local_var };
pub fn genVarDebugInfo(
pub const LocalTag = enum { local_arg, local_var };
pub fn genLocalDebugInfo(
wip_nav: *WipNav,
tag: VarTag,
tag: LocalTag,
name: []const u8,
ty: Type,
loc: Loc,
@ -1078,7 +1081,45 @@ pub const WipNav = struct {
try dlw.writeByte(DW.LNS.set_epilogue_begin);
}
pub fn enterInlineFunc(wip_nav: *WipNav, func: InternPool.Index, code_off: u64, line: u32, column: u32) UpdateError!void {
const dwarf = wip_nav.dwarf;
const zcu = wip_nav.pt.zcu;
const diw = wip_nav.debug_info.writer(dwarf.gpa);
try wip_nav.inlined_funcs_high_reloc.ensureUnusedCapacity(dwarf.gpa, 1);
const external_relocs = &dwarf.debug_info.section.getUnit(wip_nav.unit).external_relocs;
try external_relocs.ensureUnusedCapacity(dwarf.gpa, 2);
try uleb128(diw, @intFromEnum(AbbrevCode.inlined_func));
try wip_nav.refNav(zcu.funcInfo(func).owner_nav);
try uleb128(diw, zcu.navSrcLine(zcu.funcInfo(wip_nav.func).owner_nav) + line + 1);
try uleb128(diw, column);
external_relocs.appendAssumeCapacity(.{
.source_entry = wip_nav.entry,
.source_off = @intCast(wip_nav.debug_info.items.len),
.target_sym = wip_nav.func_sym_index,
.target_off = code_off,
});
try diw.writeByteNTimes(0, @intFromEnum(dwarf.address_size));
wip_nav.inlined_funcs_high_reloc.appendAssumeCapacity(@intCast(external_relocs.items.len));
external_relocs.appendAssumeCapacity(.{
.source_entry = wip_nav.entry,
.source_off = @intCast(wip_nav.debug_info.items.len),
.target_sym = wip_nav.func_sym_index,
.target_off = undefined,
});
try diw.writeByteNTimes(0, @intFromEnum(dwarf.address_size));
try wip_nav.setInlineFunc(func);
}
pub fn leaveInlineFunc(wip_nav: *WipNav, func: InternPool.Index, code_off: u64) UpdateError!void {
const external_relocs = &wip_nav.dwarf.debug_info.section.getUnit(wip_nav.unit).external_relocs;
external_relocs.items[wip_nav.inlined_funcs_high_reloc.pop()].target_off = code_off;
try uleb128(wip_nav.debug_info.writer(wip_nav.dwarf.gpa), @intFromEnum(AbbrevCode.null));
try wip_nav.setInlineFunc(func);
}
pub fn setInlineFunc(wip_nav: *WipNav, func: InternPool.Index) UpdateError!void {
wip_nav.any_children = true;
const zcu = wip_nav.pt.zcu;
const dwarf = wip_nav.dwarf;
if (wip_nav.func == func) return;
@ -1217,6 +1258,15 @@ pub const WipNav = struct {
try wip_nav.infoSectionOffset(.debug_info, unit, entry, 0);
}
fn refNav(wip_nav: *WipNav, nav_index: InternPool.Nav.Index) UpdateError!void {
const zcu = wip_nav.pt.zcu;
const ip = &zcu.intern_pool;
const unit = try wip_nav.dwarf.getUnit(zcu.fileByIndex(ip.getNav(nav_index).srcInst(ip).resolveFile(ip)).mod);
const nav_gop = try wip_nav.dwarf.navs.getOrPut(wip_nav.dwarf.gpa, nav_index);
if (!nav_gop.found_existing) nav_gop.value_ptr.* = try wip_nav.dwarf.addCommonEntry(unit);
try wip_nav.infoSectionOffset(.debug_info, unit, nav_gop.value_ptr.*, 0);
}
fn refForward(wip_nav: *WipNav) std.mem.Allocator.Error!u32 {
const dwarf = wip_nav.dwarf;
const cross_entry_relocs = &dwarf.debug_info.section.getUnit(wip_nav.unit).cross_entry_relocs;
@ -1554,7 +1604,9 @@ pub fn initWipNav(dwarf: *Dwarf, pt: Zcu.PerThread, nav_index: InternPool.Nav.In
.entry = nav_gop.value_ptr.*,
.any_children = false,
.func = .none,
.func_sym_index = undefined,
.func_high_reloc = undefined,
.inlined_funcs_high_reloc = undefined,
.debug_info = .{},
.debug_line = .{},
.debug_loclists = .{},
@ -1694,6 +1746,8 @@ pub fn initWipNav(dwarf: *Dwarf, pt: Zcu.PerThread, nav_index: InternPool.Nav.In
const func_type = ip.indexToKey(func.ty).func_type;
wip_nav.func = nav_val.toIntern();
wip_nav.func_sym_index = sym_index;
wip_nav.inlined_funcs_high_reloc = .{};
const diw = wip_nav.debug_info.writer(dwarf.gpa);
try uleb128(diw, @intFromEnum(AbbrevCode.decl_func));
@ -1706,17 +1760,19 @@ pub fn initWipNav(dwarf: *Dwarf, pt: Zcu.PerThread, nav_index: InternPool.Nav.In
try wip_nav.strp(nav.fqn.toSlice(ip));
try wip_nav.refType(Type.fromInterned(func_type.return_type));
const external_relocs = &dwarf.debug_info.section.getUnit(unit).external_relocs;
try external_relocs.append(dwarf.gpa, .{
try external_relocs.ensureUnusedCapacity(dwarf.gpa, 2);
external_relocs.appendAssumeCapacity(.{
.source_entry = wip_nav.entry,
.source_off = @intCast(wip_nav.debug_info.items.len),
.target_sym = sym_index,
});
try diw.writeByteNTimes(0, @intFromEnum(dwarf.address_size));
wip_nav.func_high_reloc = @intCast(external_relocs.items.len);
try external_relocs.append(dwarf.gpa, .{
external_relocs.appendAssumeCapacity(.{
.source_entry = wip_nav.entry,
.source_off = @intCast(wip_nav.debug_info.items.len),
.target_sym = sym_index,
.target_off = undefined,
});
try diw.writeByteNTimes(0, @intFromEnum(dwarf.address_size));
try uleb128(diw, nav.status.resolved.alignment.toByteUnits() orelse
@ -1779,7 +1835,8 @@ pub fn finishWipNav(
log.debug("finishWipNav({})", .{nav.fqn.fmt(ip)});
if (wip_nav.func != .none) {
dwarf.debug_info.section.getUnit(wip_nav.unit).external_relocs.items[wip_nav.func_high_reloc].target_off = sym.size;
const external_relocs = &dwarf.debug_info.section.getUnit(wip_nav.unit).external_relocs;
external_relocs.items[wip_nav.func_high_reloc].target_off = sym.size;
if (wip_nav.any_children) {
const diw = wip_nav.debug_info.writer(dwarf.gpa);
try uleb128(diw, @intFromEnum(AbbrevCode.null));
@ -1864,7 +1921,9 @@ pub fn updateComptimeNav(dwarf: *Dwarf, pt: Zcu.PerThread, nav_index: InternPool
.entry = undefined,
.any_children = false,
.func = .none,
.func_sym_index = undefined,
.func_high_reloc = undefined,
.inlined_funcs_high_reloc = undefined,
.debug_info = .{},
.debug_line = .{},
.debug_loclists = .{},
@ -1875,6 +1934,40 @@ pub fn updateComptimeNav(dwarf: *Dwarf, pt: Zcu.PerThread, nav_index: InternPool
const nav_gop = try dwarf.navs.getOrPut(dwarf.gpa, nav_index);
errdefer _ = dwarf.navs.pop();
switch (ip.indexToKey(nav_val.toIntern())) {
.func => |func| {
const parent_type, const accessibility: u8 = if (nav.analysis_owner.unwrap()) |cau| parent: {
const parent_namespace_ptr = ip.namespacePtr(ip.getCau(cau).namespace);
break :parent .{
parent_namespace_ptr.owner_type,
if (parent_namespace_ptr.pub_decls.containsContext(nav_index, .{ .zcu = zcu }))
DW.ACCESS.public
else if (parent_namespace_ptr.priv_decls.containsContext(nav_index, .{ .zcu = zcu }))
DW.ACCESS.private
else
unreachable,
};
} else .{ zcu.fileRootType(inst_info.file), DW.ACCESS.private };
if (!nav_gop.found_existing) nav_gop.value_ptr.* = try dwarf.addCommonEntry(unit);
wip_nav.entry = nav_gop.value_ptr.*;
const func_type = ip.indexToKey(func.ty).func_type;
const diw = wip_nav.debug_info.writer(dwarf.gpa);
try uleb128(diw, @intFromEnum(@as(AbbrevCode, if (func_type.param_types.len > 0 and func_type.is_var_args) .decl_func_generic else .decl_func_generic_empty)));
try wip_nav.refType(Type.fromInterned(parent_type));
assert(wip_nav.debug_info.items.len == DebugInfo.declEntryLineOff(dwarf));
try diw.writeInt(u32, @intCast(loc.line + 1), dwarf.endian);
try uleb128(diw, loc.column + 1);
try diw.writeByte(accessibility);
try wip_nav.strp(nav.name.toSlice(ip));
try wip_nav.refType(Type.fromInterned(func_type.return_type));
for (0..func_type.param_types.len) |param_index| {
try uleb128(diw, @intFromEnum(AbbrevCode.func_type_param));
try wip_nav.refType(Type.fromInterned(func_type.param_types.get(ip)[param_index]));
}
if (func_type.is_var_args) try uleb128(diw, @intFromEnum(AbbrevCode.is_var_args));
try uleb128(diw, @intFromEnum(AbbrevCode.null));
},
.struct_type => done: {
const loaded_struct = ip.loadStructType(nav_val.toIntern());
@ -2277,7 +2370,9 @@ fn updateType(
.entry = dwarf.types.get(type_index).?,
.any_children = false,
.func = .none,
.func_sym_index = undefined,
.func_high_reloc = undefined,
.inlined_funcs_high_reloc = undefined,
.debug_info = .{},
.debug_line = .{},
.debug_loclists = .{},
@ -2678,7 +2773,9 @@ pub fn updateContainerType(dwarf: *Dwarf, pt: Zcu.PerThread, type_index: InternP
.entry = type_gop.value_ptr.*,
.any_children = false,
.func = .none,
.func_sym_index = undefined,
.func_high_reloc = undefined,
.inlined_funcs_high_reloc = undefined,
.debug_info = .{},
.debug_line = .{},
.debug_loclists = .{},
@ -2739,7 +2836,9 @@ pub fn updateContainerType(dwarf: *Dwarf, pt: Zcu.PerThread, type_index: InternP
.entry = type_gop.value_ptr.*,
.any_children = false,
.func = .none,
.func_sym_index = undefined,
.func_high_reloc = undefined,
.inlined_funcs_high_reloc = undefined,
.debug_info = .{},
.debug_line = .{},
.debug_loclists = .{},
@ -2913,7 +3012,9 @@ pub fn flushModule(dwarf: *Dwarf, pt: Zcu.PerThread) FlushError!void {
.entry = entry,
.any_children = false,
.func = .none,
.func_sym_index = undefined,
.func_high_reloc = undefined,
.inlined_funcs_high_reloc = undefined,
.debug_info = .{},
.debug_line = .{},
.debug_loclists = .{},
@ -3283,6 +3384,8 @@ const AbbrevCode = enum(u8) {
decl_var,
decl_func,
decl_func_empty,
decl_func_generic,
decl_func_generic_empty,
// the rest are unrestricted
compile_unit,
module,
@ -3317,10 +3420,11 @@ const AbbrevCode = enum(u8) {
struct_type,
packed_struct_type,
union_type,
inlined_func,
local_arg,
local_var,
const decl_bytes = uleb128Bytes(@intFromEnum(AbbrevCode.decl_func_empty));
const decl_bytes = uleb128Bytes(@intFromEnum(AbbrevCode.decl_func_generic_empty));
const Attr = struct {
DeclValEnum(DW.AT),
@ -3424,6 +3528,19 @@ const AbbrevCode = enum(u8) {
.{ .noreturn, .flag },
},
},
.decl_func_generic = .{
.tag = .subprogram,
.children = true,
.attrs = decl_abbrev_common_attrs ++ .{
.{ .type, .ref_addr },
},
},
.decl_func_generic_empty = .{
.tag = .subprogram,
.attrs = decl_abbrev_common_attrs ++ .{
.{ .type, .ref_addr },
},
},
.compile_unit = .{
.tag = .compile_unit,
.children = true,
@ -3679,6 +3796,17 @@ const AbbrevCode = enum(u8) {
.{ .alignment, .udata },
},
},
.inlined_func = .{
.tag = .inlined_subroutine,
.children = true,
.attrs = &.{
.{ .abstract_origin, .ref_addr },
.{ .call_line, .udata },
.{ .call_column, .udata },
.{ .low_pc, .addr },
.{ .high_pc, .addr },
},
},
.local_arg = .{
.tag = .formal_parameter,
.attrs = &.{

View File

@ -283,6 +283,7 @@ const Writer = struct {
.dbg_var_ptr,
.dbg_var_val,
.dbg_arg_inline,
=> try w.writeDbgVar(s, inst),
.struct_field_ptr => try w.writeStructField(s, inst),
@ -358,10 +359,7 @@ const Writer = struct {
try w.writeType(s, arg.ty.toType());
switch (arg.name) {
.none => {},
_ => {
const name = w.air.nullTerminatedString(@intFromEnum(arg.name));
try s.print(", \"{}\"", .{std.zig.fmtEscapes(name)});
},
_ => try s.print(", \"{}\"", .{std.zig.fmtEscapes(arg.name.toSlice(w.air))}),
}
}
@ -686,8 +684,8 @@ const Writer = struct {
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);
const name = w.air.nullTerminatedString(pl_op.payload);
try s.print(", \"{}\"", .{std.zig.fmtEscapes(name)});
const name: Air.NullTerminatedString = @enumFromInt(pl_op.payload);
try s.print(", \"{}\"", .{std.zig.fmtEscapes(name.toSlice(w.air))});
}
fn writeCall(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {