mirror of
https://github.com/ziglang/zig.git
synced 2026-02-13 12:59:04 +00:00
Dwarf: emit info about inline call sites
This commit is contained in:
parent
ef90eb0d4d
commit
62f7276501
25
src/Air.zig
25
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,
|
||||
|
||||
@ -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;
|
||||
},
|
||||
|
||||
@ -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 });
|
||||
|
||||
@ -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;
|
||||
|
||||
21
src/Sema.zig
21
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, .{
|
||||
|
||||
@ -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)),
|
||||
} },
|
||||
});
|
||||
}
|
||||
|
||||
@ -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,
|
||||
});
|
||||
|
||||
|
||||
@ -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,
|
||||
});
|
||||
|
||||
|
||||
@ -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 => {},
|
||||
|
||||
@ -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 => {},
|
||||
|
||||
@ -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, &.{});
|
||||
}
|
||||
|
||||
@ -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 {
|
||||
|
||||
@ -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");
|
||||
|
||||
@ -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();
|
||||
|
||||
@ -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();
|
||||
|
||||
@ -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(),
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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 {
|
||||
|
||||
@ -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 = &.{
|
||||
|
||||
@ -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 {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user