stage2 ARM: re-enable debug info for arguments

These were disabled during the MIR transition
This commit is contained in:
joachimschmidt557 2022-01-24 13:27:54 +01:00 committed by Jakub Konka
parent 4e5495e443
commit 7665401500
3 changed files with 140 additions and 93 deletions

View File

@ -43,7 +43,7 @@ err_msg: ?*ErrorMsg,
args: []MCValue,
ret_mcv: MCValue,
fn_type: Type,
arg_index: usize,
arg_index: u32,
src_loc: Module.SrcLoc,
stack_align: u32,
@ -302,6 +302,7 @@ pub fn generate(
var emit = Emit{
.mir = mir,
.bin_file = bin_file,
.function = &function,
.debug_output = debug_output,
.target = &bin_file.options.target,
.src_loc = src_loc,
@ -706,29 +707,6 @@ fn ensureProcessDeathCapacity(self: *Self, additional_count: usize) !void {
try table.ensureUnusedCapacity(self.gpa, additional_count);
}
/// Adds a Type to the .debug_info at the current position. The bytes will be populated later,
/// after codegen for this symbol is done.
fn addDbgInfoTypeReloc(self: *Self, ty: Type) !void {
switch (self.debug_output) {
.dwarf => |dbg_out| {
assert(ty.hasCodeGenBits());
const index = dbg_out.dbg_info.items.len;
try dbg_out.dbg_info.resize(index + 4); // DW.AT.type, DW.FORM.ref4
const gop = try dbg_out.dbg_info_type_relocs.getOrPut(self.gpa, ty);
if (!gop.found_existing) {
gop.value_ptr.* = .{
.off = undefined,
.relocs = .{},
};
}
try gop.value_ptr.relocs.append(self.gpa, @intCast(u32, index));
},
.plan9 => {},
.none => {},
}
}
fn allocMem(self: *Self, inst: Air.Inst.Index, abi_size: u32, abi_align: u32) !u32 {
if (abi_align > self.stack_align)
self.stack_align = abi_align;
@ -1171,6 +1149,9 @@ fn airSlicePtr(self: *Self, inst: Air.Inst.Index) !void {
switch (mcv) {
.dead, .unreach => unreachable,
.register => unreachable, // a slice doesn't fit in one register
.stack_argument_offset => |off| {
break :result MCValue{ .stack_argument_offset = off };
},
.stack_offset => |off| {
break :result MCValue{ .stack_offset = off };
},
@ -1190,6 +1171,9 @@ fn airSliceLen(self: *Self, inst: Air.Inst.Index) !void {
switch (mcv) {
.dead, .unreach => unreachable,
.register => unreachable, // a slice doesn't fit in one register
.stack_argument_offset => |off| {
break :result MCValue{ .stack_argument_offset = off + 4 };
},
.stack_offset => |off| {
break :result MCValue{ .stack_offset = off + 4 };
},
@ -1208,7 +1192,6 @@ fn airPtrSliceLenPtr(self: *Self, inst: Air.Inst.Index) !void {
const mcv = try self.resolveInst(ty_op.operand);
switch (mcv) {
.dead, .unreach => unreachable,
.register => unreachable, // a slice doesn't fit in one register
.ptr_stack_offset => |off| {
break :result MCValue{ .ptr_stack_offset = off + 4 };
},
@ -1224,7 +1207,6 @@ fn airPtrSlicePtrPtr(self: *Self, inst: Air.Inst.Index) !void {
const mcv = try self.resolveInst(ty_op.operand);
switch (mcv) {
.dead, .unreach => unreachable,
.register => unreachable, // a slice doesn't fit in one register
.ptr_stack_offset => |off| {
break :result MCValue{ .ptr_stack_offset = off };
},
@ -2135,66 +2117,6 @@ fn genArmInlineMemcpy(
// end:
}
fn genArgDbgInfo(self: *Self, inst: Air.Inst.Index, mcv: MCValue) !void {
const ty_str = self.air.instructions.items(.data)[inst].ty_str;
const zir = &self.mod_fn.owner_decl.getFileScope().zir;
const name = zir.nullTerminatedString(ty_str.str);
const name_with_null = name.ptr[0 .. name.len + 1];
const ty = self.air.getRefType(ty_str.ty);
switch (mcv) {
.register => |reg| {
switch (self.debug_output) {
.dwarf => |dbg_out| {
try dbg_out.dbg_info.ensureUnusedCapacity(3);
dbg_out.dbg_info.appendAssumeCapacity(link.File.Elf.abbrev_parameter);
dbg_out.dbg_info.appendSliceAssumeCapacity(&[2]u8{ // DW.AT.location, DW.FORM.exprloc
1, // ULEB128 dwarf expression length
reg.dwarfLocOp(),
});
try dbg_out.dbg_info.ensureUnusedCapacity(5 + name_with_null.len);
try self.addDbgInfoTypeReloc(ty); // DW.AT.type, DW.FORM.ref4
dbg_out.dbg_info.appendSliceAssumeCapacity(name_with_null); // DW.AT.name, DW.FORM.string
},
.plan9 => {},
.none => {},
}
},
.stack_offset => |offset| {
switch (self.debug_output) {
.dwarf => |dbg_out| {
const abi_size = math.cast(u32, ty.abiSize(self.target.*)) catch {
return self.fail("type '{}' too big to fit into stack frame", .{ty});
};
const adjusted_stack_offset = math.negateCast(offset + abi_size) catch {
return self.fail("Stack offset too large for arguments", .{});
};
try dbg_out.dbg_info.append(link.File.Elf.abbrev_parameter);
// Get length of the LEB128 stack offset
var counting_writer = std.io.countingWriter(std.io.null_writer);
leb128.writeILEB128(counting_writer.writer(), adjusted_stack_offset) catch unreachable;
// DW.AT.location, DW.FORM.exprloc
// ULEB128 dwarf expression length
try leb128.writeULEB128(dbg_out.dbg_info.writer(), counting_writer.bytes_written + 1);
try dbg_out.dbg_info.append(DW.OP.breg11);
try leb128.writeILEB128(dbg_out.dbg_info.writer(), adjusted_stack_offset);
try dbg_out.dbg_info.ensureUnusedCapacity(5 + name_with_null.len);
try self.addDbgInfoTypeReloc(ty); // DW.AT.type, DW.FORM.ref4
dbg_out.dbg_info.appendSliceAssumeCapacity(name_with_null); // DW.AT.name, DW.FORM.string
},
.plan9 => {},
.none => {},
}
},
.stack_argument_offset => return self.fail("TODO genArgDbgInfo for stack_argument_offset", .{}),
else => {},
}
}
fn airArg(self: *Self, inst: Air.Inst.Index) !void {
const arg_index = self.arg_index;
self.arg_index += 1;
@ -2216,8 +2138,15 @@ fn airArg(self: *Self, inst: Air.Inst.Index) !void {
},
else => result,
};
// TODO generate debug info
// try self.genArgDbgInfo(inst, mcv);
_ = try self.addInst(.{
.tag = .dbg_arg,
.cond = undefined,
.data = .{ .dbg_arg_info = .{
.air_inst = inst,
.arg_index = arg_index,
} },
});
if (self.liveness.isUnused(inst))
return self.finishAirBookkeeping();
@ -3496,7 +3425,6 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void
}
},
.stack_argument_offset => |unadjusted_off| {
// TODO: maybe addressing from sp instead of fp
const abi_size = ty.abiSize(self.target.*);
const adj_off = unadjusted_off + abi_size;

View File

@ -8,6 +8,8 @@ const Mir = @import("Mir.zig");
const bits = @import("bits.zig");
const link = @import("../../link.zig");
const Module = @import("../../Module.zig");
const Air = @import("../../Air.zig");
const Type = @import("../../type.zig").Type;
const ErrorMsg = Module.ErrorMsg;
const assert = std.debug.assert;
const DW = std.dwarf;
@ -16,9 +18,11 @@ const Instruction = bits.Instruction;
const Register = bits.Register;
const log = std.log.scoped(.aarch64_emit);
const DebugInfoOutput = @import("../../codegen.zig").DebugInfoOutput;
const CodeGen = @import("CodeGen.zig");
mir: Mir,
bin_file: *link.File,
function: *const CodeGen,
debug_output: DebugInfoOutput,
target: *const std.Target,
err_msg: ?*ErrorMsg = null,
@ -95,6 +99,8 @@ pub fn emitMir(
.blx => try emit.mirBranchExchange(inst),
.bx => try emit.mirBranchExchange(inst),
.dbg_arg => try emit.mirDbgArg(inst),
.dbg_line => try emit.mirDbgLine(inst),
.dbg_prologue_end => try emit.mirDebugPrologueEnd(),
@ -106,9 +112,9 @@ pub fn emitMir(
.str => try emit.mirLoadStore(inst),
.strb => try emit.mirLoadStore(inst),
.ldr_stack_argument => try emit.mirLoadStack(inst),
.ldrb_stack_argument => try emit.mirLoadStack(inst),
.ldrh_stack_argument => try emit.mirLoadStack(inst),
.ldr_stack_argument => try emit.mirLoadStackArgument(inst),
.ldrb_stack_argument => try emit.mirLoadStackArgument(inst),
.ldrh_stack_argument => try emit.mirLoadStackArgument(inst),
.ldrh => try emit.mirLoadStoreExtra(inst),
.strh => try emit.mirLoadStoreExtra(inst),
@ -168,6 +174,7 @@ fn instructionSize(emit: *Emit, inst: Mir.Inst.Index) usize {
.dbg_line,
.dbg_epilogue_begin,
.dbg_prologue_end,
.dbg_arg,
=> return 0,
else => return 4,
}
@ -360,6 +367,98 @@ fn dbgAdvancePCAndLine(self: *Emit, line: u32, column: u32) !void {
}
}
/// Adds a Type to the .debug_info at the current position. The bytes will be populated later,
/// after codegen for this symbol is done.
fn addDbgInfoTypeReloc(self: *Emit, ty: Type) !void {
switch (self.debug_output) {
.dwarf => |dbg_out| {
assert(ty.hasCodeGenBits());
const index = dbg_out.dbg_info.items.len;
try dbg_out.dbg_info.resize(index + 4); // DW.AT.type, DW.FORM.ref4
const gop = try dbg_out.dbg_info_type_relocs.getOrPut(self.bin_file.allocator, ty);
if (!gop.found_existing) {
gop.value_ptr.* = .{
.off = undefined,
.relocs = .{},
};
}
try gop.value_ptr.relocs.append(self.bin_file.allocator, @intCast(u32, index));
},
.plan9 => {},
.none => {},
}
}
fn genArgDbgInfo(self: *Emit, inst: Air.Inst.Index, arg_index: u32) !void {
const mcv = self.function.args[arg_index];
const ty_str = self.function.air.instructions.items(.data)[inst].ty_str;
const zir = &self.function.mod_fn.owner_decl.getFileScope().zir;
const name = zir.nullTerminatedString(ty_str.str);
const name_with_null = name.ptr[0 .. name.len + 1];
const ty = self.function.air.getRefType(ty_str.ty);
switch (mcv) {
.register => |reg| {
switch (self.debug_output) {
.dwarf => |dbg_out| {
try dbg_out.dbg_info.ensureUnusedCapacity(3);
dbg_out.dbg_info.appendAssumeCapacity(link.File.Elf.abbrev_parameter);
dbg_out.dbg_info.appendSliceAssumeCapacity(&[2]u8{ // DW.AT.location, DW.FORM.exprloc
1, // ULEB128 dwarf expression length
reg.dwarfLocOp(),
});
try dbg_out.dbg_info.ensureUnusedCapacity(5 + name_with_null.len);
try self.addDbgInfoTypeReloc(ty); // DW.AT.type, DW.FORM.ref4
dbg_out.dbg_info.appendSliceAssumeCapacity(name_with_null); // DW.AT.name, DW.FORM.string
},
.plan9 => {},
.none => {},
}
},
.stack_offset,
.stack_argument_offset,
=> {
switch (self.debug_output) {
.dwarf => |dbg_out| {
const abi_size = math.cast(u32, ty.abiSize(self.target.*)) catch {
return self.fail("type '{}' too big to fit into stack frame", .{ty});
};
const adjusted_stack_offset = switch (mcv) {
.stack_offset => |offset| math.negateCast(offset + abi_size) catch {
return self.fail("Stack offset too large for arguments", .{});
},
.stack_argument_offset => |offset| math.cast(i32, self.prologue_stack_space - offset - abi_size) catch {
return self.fail("Stack offset too large for arguments", .{});
},
else => unreachable,
};
try dbg_out.dbg_info.append(link.File.Elf.abbrev_parameter);
// Get length of the LEB128 stack offset
var counting_writer = std.io.countingWriter(std.io.null_writer);
leb128.writeILEB128(counting_writer.writer(), adjusted_stack_offset) catch unreachable;
// DW.AT.location, DW.FORM.exprloc
// ULEB128 dwarf expression length
try leb128.writeULEB128(dbg_out.dbg_info.writer(), counting_writer.bytes_written + 1);
try dbg_out.dbg_info.append(DW.OP.breg11);
try leb128.writeILEB128(dbg_out.dbg_info.writer(), adjusted_stack_offset);
try dbg_out.dbg_info.ensureUnusedCapacity(5 + name_with_null.len);
try self.addDbgInfoTypeReloc(ty); // DW.AT.type, DW.FORM.ref4
dbg_out.dbg_info.appendSliceAssumeCapacity(name_with_null); // DW.AT.name, DW.FORM.string
},
.plan9 => {},
.none => {},
}
},
else => unreachable, // not a possible argument
}
}
fn mirDataProcessing(emit: *Emit, inst: Mir.Inst.Index) !void {
const tag = emit.mir.instructions.items(.tag)[inst];
const cond = emit.mir.instructions.items(.cond)[inst];
@ -430,6 +529,16 @@ fn mirBranchExchange(emit: *Emit, inst: Mir.Inst.Index) !void {
}
}
fn mirDbgArg(emit: *Emit, inst: Mir.Inst.Index) !void {
const tag = emit.mir.instructions.items(.tag)[inst];
const dbg_arg_info = emit.mir.instructions.items(.data)[inst].dbg_arg_info;
switch (tag) {
.dbg_arg => try emit.genArgDbgInfo(dbg_arg_info.air_inst, dbg_arg_info.arg_index),
else => unreachable,
}
}
fn mirDbgLine(emit: *Emit, inst: Mir.Inst.Index) !void {
const tag = emit.mir.instructions.items(.tag)[inst];
const dbg_line_column = emit.mir.instructions.items(.data)[inst].dbg_line_column;
@ -476,7 +585,7 @@ fn mirLoadStore(emit: *Emit, inst: Mir.Inst.Index) !void {
}
}
fn mirLoadStack(emit: *Emit, inst: Mir.Inst.Index) !void {
fn mirLoadStackArgument(emit: *Emit, inst: Mir.Inst.Index) !void {
const tag = emit.mir.instructions.items(.tag)[inst];
const cond = emit.mir.instructions.items(.cond)[inst];
const r_stack_offset = emit.mir.instructions.items(.data)[inst].r_stack_offset;

View File

@ -12,6 +12,7 @@ const builtin = @import("builtin");
const assert = std.debug.assert;
const bits = @import("bits.zig");
const Air = @import("../../Air.zig");
const Register = bits.Register;
instructions: std.MultiArrayList(Inst).Slice,
@ -41,6 +42,8 @@ pub const Inst = struct {
bx,
/// Compare
cmp,
/// Pseudo-instruction: Argument
dbg_arg,
/// Pseudo-instruction: End of prologue
dbg_prologue_end,
/// Pseudo-instruction: Beginning of epilogue
@ -195,6 +198,13 @@ pub const Inst = struct {
line: u32,
column: u32,
},
/// Debug info: argument
///
/// Used by e.g. dbg_arg
dbg_arg_info: struct {
air_inst: Air.Inst.Index,
arg_index: u32,
},
};
// Make sure we don't accidentally make instructions bigger than expected.