Commit 62f7276501
Changed files (21)
src
arch
aarch64
arm
riscv64
sparc64
wasm
link
Liveness
src/Air/types_resolved.zig
@@ -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;
},
src/arch/aarch64/CodeGen.zig
@@ -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,
});
src/arch/arm/CodeGen.zig
@@ -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,
});
src/arch/riscv64/CodeGen.zig
@@ -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 => {},
src/arch/sparc64/CodeGen.zig
@@ -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 => {},
src/arch/wasm/CodeGen.zig
@@ -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, &.{});
}
src/arch/x86_64/CodeGen.zig
@@ -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 {
src/arch/x86_64/Emit.zig
@@ -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");
src/arch/x86_64/encoder.zig
@@ -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(),
src/arch/x86_64/Lower.zig
@@ -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();
src/arch/x86_64/Mir.zig
@@ -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();
src/codegen/c.zig
@@ -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;
}
src/codegen/llvm.zig
@@ -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;
src/codegen/spirv.zig
@@ -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 {
src/link/Dwarf.zig
@@ -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 = &.{
src/Liveness/Verify.zig
@@ -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;
src/Zcu/PerThread.zig
@@ -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)),
} },
});
}
src/Air.zig
@@ -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,
src/Liveness.zig
@@ -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 });
src/print_air.zig
@@ -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 {
src/Sema.zig
@@ -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, .{