Commit 7665401500

joachimschmidt557 <joachim.schmidt557@outlook.com>
2022-01-24 13:27:54
stage2 ARM: re-enable debug info for arguments
These were disabled during the MIR transition
1 parent 4e5495e
Changed files (3)
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;
 
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;
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.