authorgravatar for joachim.schmidt557@outlook.comJoachim Schmidt <joachim.schmidt557@outlook.com> 2021-10-31 09:20:55+01:00
committergravatar for joachim.schmidt557@outlook.comJoachim Schmidt <joachim.schmidt557@outlook.com> 2021-10-31 12:32:11+01:00
log0bdb367ee4330c12952642a3b9718e24430406cc
tree81fbb3b0d0efe8cfd7075aa65b94cc77809efaa9
parent9471e3da353baef541e620ac6853a8dcc1160614
signaturelock-open Commit is signed but in an unrecognized format.

stage2 AArch64: implement emit debug line info


3 files changed, 150 insertions(+), 90 deletions(-)

src/arch/aarch64/CodeGen.zig+40-90
......@@ -39,7 +39,6 @@ liveness: Liveness,
3939bin_file: *link.File,
4040target: *const std.Target,
4141mod_fn: *const Module.Fn,
42debug_output: DebugInfoOutput,
4342err_msg: ?*ErrorMsg,
4443args: []MCValue,
4544ret_mcv: MCValue,
......@@ -53,13 +52,9 @@ mir_instructions: std.MultiArrayList(Mir.Inst) = .{},
5352/// MIR extra data
5453mir_extra: std.ArrayListUnmanaged(u32) = .{},
5554
56prev_di_line: u32,
57prev_di_column: u32,
5855/// Byte offset within the source file of the ending curly.
5956end_di_line: u32,
6057end_di_column: u32,
61/// Relative to the beginning of `code`.
62prev_di_pc: usize,
6358
6459/// The value is an offset into the `Function` `code` from the beginning.
6560/// To perform the reloc, write 32-bit signed little-endian integer
......@@ -272,7 +267,6 @@ pub fn generate(
272267 .target = &bin_file.options.target,
273268 .bin_file = bin_file,
274269 .mod_fn = module_fn,
275 .debug_output = debug_output,
276270 .err_msg = null,
277271 .args = undefined, // populated after `resolveCallingConventionValues`
278272 .ret_mcv = undefined, // populated after `resolveCallingConventionValues`
......@@ -281,9 +275,6 @@ pub fn generate(
281275 .branch_stack = &branch_stack,
282276 .src_loc = src_loc,
283277 .stack_align = undefined,
284 .prev_di_pc = 0,
285 .prev_di_line = module_fn.lbrace_line,
286 .prev_di_column = module_fn.lbrace_column,
287278 .end_di_line = module_fn.rbrace_line,
288279 .end_di_column = module_fn.rbrace_column,
289280 };
......@@ -316,8 +307,12 @@ pub fn generate(
316307 var emit = Emit{
317308 .mir = mir,
318309 .bin_file = bin_file,
310 .debug_output = debug_output,
319311 .target = &bin_file.options.target,
320312 .code = code,
313 .prev_di_pc = 0,
314 .prev_di_line = module_fn.lbrace_line,
315 .prev_di_column = module_fn.lbrace_column,
321316 };
322317 try emit.emitMir();
323318
......@@ -386,7 +381,10 @@ fn gen(self: *Self) !void {
386381 .data = .{ .nop = {} },
387382 });
388383
389 try self.dbgSetPrologueEnd();
384 _ = try self.addInst(.{
385 .tag = .dbg_prologue_end,
386 .data = .{ .nop = {} },
387 });
390388
391389 try self.genBody(self.air.getMainBody());
392390
......@@ -402,7 +400,10 @@ fn gen(self: *Self) !void {
402400 return self.failSymbol("TODO AArch64: allow larger stacks", .{});
403401 }
404402
405 try self.dbgSetEpilogueBegin();
403 _ = try self.addInst(.{
404 .tag = .dbg_epilogue_begin,
405 .data = .{ .nop = {} },
406 });
406407
407408 // exitlude jumps
408409 if (self.exitlude_jump_relocs.items.len == 1) {
......@@ -442,13 +443,27 @@ fn gen(self: *Self) !void {
442443 .data = .{ .reg = .x30 },
443444 });
444445 } else {
445 try self.dbgSetPrologueEnd();
446 _ = try self.addInst(.{
447 .tag = .dbg_prologue_end,
448 .data = .{ .nop = {} },
449 });
450
446451 try self.genBody(self.air.getMainBody());
447 try self.dbgSetEpilogueBegin();
452
453 _ = try self.addInst(.{
454 .tag = .dbg_epilogue_begin,
455 .data = .{ .nop = {} },
456 });
448457 }
449458
450459 // Drop them off at the rbrace.
451 // try self.dbgAdvancePCAndLine(self.end_di_line, self.end_di_column);
460 _ = try self.addInst(.{
461 .tag = .dbg_line,
462 .data = .{ .dbg_line_column = .{
463 .line = self.end_di_line,
464 .column = self.end_di_column,
465 } },
466 });
452467}
453468
454469fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
......@@ -589,79 +604,6 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
589604 }
590605}
591606
592fn dbgSetPrologueEnd(self: *Self) InnerError!void {
593 switch (self.debug_output) {
594 .dwarf => |dbg_out| {
595 try dbg_out.dbg_line.append(DW.LNS.set_prologue_end);
596 // try self.dbgAdvancePCAndLine(self.prev_di_line, self.prev_di_column);
597 },
598 .plan9 => {},
599 .none => {},
600 }
601}
602
603fn dbgSetEpilogueBegin(self: *Self) InnerError!void {
604 switch (self.debug_output) {
605 .dwarf => |dbg_out| {
606 try dbg_out.dbg_line.append(DW.LNS.set_epilogue_begin);
607 // try self.dbgAdvancePCAndLine(self.prev_di_line, self.prev_di_column);
608 },
609 .plan9 => {},
610 .none => {},
611 }
612}
613
614fn dbgAdvancePCAndLine(self: *Self, line: u32, column: u32) InnerError!void {
615 const delta_line = @intCast(i32, line) - @intCast(i32, self.prev_di_line);
616 const delta_pc: usize = self.code.items.len - self.prev_di_pc;
617 switch (self.debug_output) {
618 .dwarf => |dbg_out| {
619 // TODO Look into using the DWARF special opcodes to compress this data.
620 // It lets you emit single-byte opcodes that add different numbers to
621 // both the PC and the line number at the same time.
622 try dbg_out.dbg_line.ensureUnusedCapacity(11);
623 dbg_out.dbg_line.appendAssumeCapacity(DW.LNS.advance_pc);
624 leb128.writeULEB128(dbg_out.dbg_line.writer(), delta_pc) catch unreachable;
625 if (delta_line != 0) {
626 dbg_out.dbg_line.appendAssumeCapacity(DW.LNS.advance_line);
627 leb128.writeILEB128(dbg_out.dbg_line.writer(), delta_line) catch unreachable;
628 }
629 dbg_out.dbg_line.appendAssumeCapacity(DW.LNS.copy);
630 self.prev_di_pc = self.code.items.len;
631 self.prev_di_line = line;
632 self.prev_di_column = column;
633 self.prev_di_pc = self.code.items.len;
634 },
635 .plan9 => |dbg_out| {
636 if (delta_pc <= 0) return; // only do this when the pc changes
637 // we have already checked the target in the linker to make sure it is compatable
638 const quant = @import("../../link/Plan9/aout.zig").getPCQuant(self.target.cpu.arch) catch unreachable;
639
640 // increasing the line number
641 try @import("../../link/Plan9.zig").changeLine(dbg_out.dbg_line, delta_line);
642 // increasing the pc
643 const d_pc_p9 = @intCast(i64, delta_pc) - quant;
644 if (d_pc_p9 > 0) {
645 // minus one because if its the last one, we want to leave space to change the line which is one quanta
646 try dbg_out.dbg_line.append(@intCast(u8, @divExact(d_pc_p9, quant) + 128) - quant);
647 if (dbg_out.pcop_change_index.*) |pci|
648 dbg_out.dbg_line.items[pci] += 1;
649 dbg_out.pcop_change_index.* = @intCast(u32, dbg_out.dbg_line.items.len - 1);
650 } else if (d_pc_p9 == 0) {
651 // we don't need to do anything, because adding the quant does it for us
652 } else unreachable;
653 if (dbg_out.start_line.* == null)
654 dbg_out.start_line.* = self.prev_di_line;
655 dbg_out.end_line.* = line;
656 // only do this if the pc changed
657 self.prev_di_line = line;
658 self.prev_di_column = column;
659 self.prev_di_pc = self.code.items.len;
660 },
661 .none => {},
662 }
663}
664
665607/// Asserts there is already capacity to insert into top branch inst_table.
666608fn processDeath(self: *Self, inst: Air.Inst.Index) void {
667609 const air_tags = self.air.instructions.items(.tag);
......@@ -1407,7 +1349,8 @@ fn airArg(self: *Self, inst: Air.Inst.Index) !void {
14071349 },
14081350 else => result,
14091351 };
1410 try self.genArgDbgInfo(inst, mcv);
1352 // TODO generate debug info
1353 // try self.genArgDbgInfo(inst, mcv);
14111354
14121355 if (self.liveness.isUnused(inst))
14131356 return self.finishAirBookkeeping();
......@@ -1698,8 +1641,15 @@ fn airCmp(self: *Self, inst: Air.Inst.Index, op: math.CompareOperator) !void {
16981641
16991642fn airDbgStmt(self: *Self, inst: Air.Inst.Index) !void {
17001643 const dbg_stmt = self.air.instructions.items(.data)[inst].dbg_stmt;
1701 _ = dbg_stmt;
1702 // try self.dbgAdvancePCAndLine(dbg_stmt.line, dbg_stmt.column);
1644
1645 _ = try self.addInst(.{
1646 .tag = .dbg_line,
1647 .data = .{ .dbg_line_column = .{
1648 .line = dbg_stmt.line,
1649 .column = dbg_stmt.column,
1650 } },
1651 });
1652
17031653 return self.finishAirBookkeeping();
17041654}
17051655
src/arch/aarch64/Emit.zig+97
......@@ -8,14 +8,23 @@ const Mir = @import("Mir.zig");
88const bits = @import("bits.zig");
99const link = @import("../../link.zig");
1010const assert = std.debug.assert;
11const DW = std.dwarf;
12const leb128 = std.leb;
1113const Instruction = bits.Instruction;
1214const Register = bits.Register;
15const DebugInfoOutput = @import("../../codegen.zig").DebugInfoOutput;
1316
1417mir: Mir,
1518bin_file: *link.File,
19debug_output: DebugInfoOutput,
1620target: *const std.Target,
1721code: *std.ArrayList(u8),
1822
23prev_di_line: u32,
24prev_di_column: u32,
25/// Relative to the beginning of `code`.
26prev_di_pc: usize,
27
1928pub fn emitMir(
2029 emit: *Emit,
2130) !void {
......@@ -38,6 +47,11 @@ pub fn emitMir(
3847
3948 .call_extern => try emit.mirCallExtern(inst),
4049
50 .dbg_line => try emit.mirDbgLine(inst),
51
52 .dbg_prologue_end => try emit.mirDebugPrologueEnd(),
53 .dbg_epilogue_begin => try emit.mirDebugEpilogueBegin(),
54
4155 .load_memory => try emit.mirLoadMemory(inst),
4256
4357 .ldp => try emit.mirLoadStoreRegisterPair(inst),
......@@ -80,6 +94,57 @@ fn moveImmediate(emit: *Emit, reg: Register, imm64: u64) !void {
8094 }
8195}
8296
97fn dbgAdvancePCAndLine(self: *Emit, line: u32, column: u32) !void {
98 const delta_line = @intCast(i32, line) - @intCast(i32, self.prev_di_line);
99 const delta_pc: usize = self.code.items.len - self.prev_di_pc;
100 switch (self.debug_output) {
101 .dwarf => |dbg_out| {
102 // TODO Look into using the DWARF special opcodes to compress this data.
103 // It lets you emit single-byte opcodes that add different numbers to
104 // both the PC and the line number at the same time.
105 try dbg_out.dbg_line.ensureUnusedCapacity(11);
106 dbg_out.dbg_line.appendAssumeCapacity(DW.LNS.advance_pc);
107 leb128.writeULEB128(dbg_out.dbg_line.writer(), delta_pc) catch unreachable;
108 if (delta_line != 0) {
109 dbg_out.dbg_line.appendAssumeCapacity(DW.LNS.advance_line);
110 leb128.writeILEB128(dbg_out.dbg_line.writer(), delta_line) catch unreachable;
111 }
112 dbg_out.dbg_line.appendAssumeCapacity(DW.LNS.copy);
113 self.prev_di_pc = self.code.items.len;
114 self.prev_di_line = line;
115 self.prev_di_column = column;
116 self.prev_di_pc = self.code.items.len;
117 },
118 .plan9 => |dbg_out| {
119 if (delta_pc <= 0) return; // only do this when the pc changes
120 // we have already checked the target in the linker to make sure it is compatable
121 const quant = @import("../../link/Plan9/aout.zig").getPCQuant(self.target.cpu.arch) catch unreachable;
122
123 // increasing the line number
124 try @import("../../link/Plan9.zig").changeLine(dbg_out.dbg_line, delta_line);
125 // increasing the pc
126 const d_pc_p9 = @intCast(i64, delta_pc) - quant;
127 if (d_pc_p9 > 0) {
128 // minus one because if its the last one, we want to leave space to change the line which is one quanta
129 try dbg_out.dbg_line.append(@intCast(u8, @divExact(d_pc_p9, quant) + 128) - quant);
130 if (dbg_out.pcop_change_index.*) |pci|
131 dbg_out.dbg_line.items[pci] += 1;
132 dbg_out.pcop_change_index.* = @intCast(u32, dbg_out.dbg_line.items.len - 1);
133 } else if (d_pc_p9 == 0) {
134 // we don't need to do anything, because adding the quant does it for us
135 } else unreachable;
136 if (dbg_out.start_line.* == null)
137 dbg_out.start_line.* = self.prev_di_line;
138 dbg_out.end_line.* = line;
139 // only do this if the pc changed
140 self.prev_di_line = line;
141 self.prev_di_column = column;
142 self.prev_di_pc = self.code.items.len;
143 },
144 .none => {},
145 }
146}
147
83148fn mirAddSubtractImmediate(emit: *Emit, inst: Mir.Inst.Index) !void {
84149 const tag = emit.mir.instructions.items(.tag)[inst];
85150 const rr_imm12_sh = emit.mir.instructions.items(.data)[inst].rr_imm12_sh;
......@@ -136,6 +201,38 @@ fn mirExceptionGeneration(emit: *Emit, inst: Mir.Inst.Index) !void {
136201 }
137202}
138203
204fn mirDbgLine(emit: *Emit, inst: Mir.Inst.Index) !void {
205 const tag = emit.mir.instructions.items(.tag)[inst];
206 const dbg_line_column = emit.mir.instructions.items(.data)[inst].dbg_line_column;
207
208 switch (tag) {
209 .dbg_line => try emit.dbgAdvancePCAndLine(dbg_line_column.line, dbg_line_column.column),
210 else => unreachable,
211 }
212}
213
214fn mirDebugPrologueEnd(self: *Emit) !void {
215 switch (self.debug_output) {
216 .dwarf => |dbg_out| {
217 try dbg_out.dbg_line.append(DW.LNS.set_prologue_end);
218 try self.dbgAdvancePCAndLine(self.prev_di_line, self.prev_di_column);
219 },
220 .plan9 => {},
221 .none => {},
222 }
223}
224
225fn mirDebugEpilogueBegin(self: *Emit) !void {
226 switch (self.debug_output) {
227 .dwarf => |dbg_out| {
228 try dbg_out.dbg_line.append(DW.LNS.set_epilogue_begin);
229 try self.dbgAdvancePCAndLine(self.prev_di_line, self.prev_di_column);
230 },
231 .plan9 => {},
232 .none => {},
233 }
234}
235
139236fn mirCallExtern(emit: *Emit, inst: Mir.Inst.Index) !void {
140237 assert(emit.mir.instructions.items(.tag)[inst] == .call_extern);
141238 const n_strx = emit.mir.instructions.items(.data)[inst].extern_fn;
src/arch/aarch64/Mir.zig+13
......@@ -36,6 +36,12 @@ pub const Inst = struct {
3636 brk,
3737 /// Pseudo-instruction: Call extern
3838 call_extern,
39 /// Pseudo-instruction: End of prologue
40 dbg_prologue_end,
41 /// Pseudo-instruction: Beginning of epilogue
42 dbg_epilogue_begin,
43 /// Pseudo-instruction: Update debug line
44 dbg_line,
3945 /// Psuedo-instruction: Load memory
4046 ///
4147 /// Payload is `LoadMemory`
......@@ -152,6 +158,13 @@ pub const Inst = struct {
152158 rn: Register,
153159 offset: bits.Instruction.LoadStorePairOffset,
154160 },
161 /// Debug info: line and column
162 ///
163 /// Used by e.g. dbg_line
164 dbg_line_column: struct {
165 line: u32,
166 column: u32,
167 },
155168 };
156169
157170 // Make sure we don't accidentally make instructions bigger than expected.