From 76654015009038a07f14b9eb8500bb84e9e28099 Mon Sep 17 00:00:00 2001 From: joachimschmidt557 Date: Mon, 24 Jan 2022 13:27:54 +0100 Subject: [PATCH] stage2 ARM: re-enable debug info for arguments These were disabled during the MIR transition --- src/arch/arm/CodeGen.zig | 106 ++++++----------------------------- src/arch/arm/Emit.zig | 117 +++++++++++++++++++++++++++++++++++++-- src/arch/arm/Mir.zig | 10 ++++ 3 files changed, 140 insertions(+), 93 deletions(-) diff --git a/src/arch/arm/CodeGen.zig b/src/arch/arm/CodeGen.zig index 265b6ac161..aa8720b717 100644 --- a/src/arch/arm/CodeGen.zig +++ b/src/arch/arm/CodeGen.zig @@ -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; diff --git a/src/arch/arm/Emit.zig b/src/arch/arm/Emit.zig index a41f58334b..cd9503e570 100644 --- a/src/arch/arm/Emit.zig +++ b/src/arch/arm/Emit.zig @@ -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; diff --git a/src/arch/arm/Mir.zig b/src/arch/arm/Mir.zig index b19186e003..e6f1bcb0a2 100644 --- a/src/arch/arm/Mir.zig +++ b/src/arch/arm/Mir.zig @@ -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.