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,...@@ -39,7 +39,6 @@ liveness: Liveness,
39bin_file: *link.File,39bin_file: *link.File,
40target: *const std.Target,40target: *const std.Target,
41mod_fn: *const Module.Fn,41mod_fn: *const Module.Fn,
42debug_output: DebugInfoOutput,
43err_msg: ?*ErrorMsg,42err_msg: ?*ErrorMsg,
44args: []MCValue,43args: []MCValue,
45ret_mcv: MCValue,44ret_mcv: MCValue,
...@@ -53,13 +52,9 @@ mir_instructions: std.MultiArrayList(Mir.Inst) = .{},...@@ -53,13 +52,9 @@ mir_instructions: std.MultiArrayList(Mir.Inst) = .{},
53/// MIR extra data52/// MIR extra data
54mir_extra: std.ArrayListUnmanaged(u32) = .{},53mir_extra: std.ArrayListUnmanaged(u32) = .{},
5554
56prev_di_line: u32,
57prev_di_column: u32,
58/// Byte offset within the source file of the ending curly.55/// Byte offset within the source file of the ending curly.
59end_di_line: u32,56end_di_line: u32,
60end_di_column: u32,57end_di_column: u32,
61/// Relative to the beginning of `code`.
62prev_di_pc: usize,
6358
64/// The value is an offset into the `Function` `code` from the beginning.59/// The value is an offset into the `Function` `code` from the beginning.
65/// To perform the reloc, write 32-bit signed little-endian integer60/// To perform the reloc, write 32-bit signed little-endian integer
...@@ -272,7 +267,6 @@ pub fn generate(...@@ -272,7 +267,6 @@ pub fn generate(
272 .target = &bin_file.options.target,267 .target = &bin_file.options.target,
273 .bin_file = bin_file,268 .bin_file = bin_file,
274 .mod_fn = module_fn,269 .mod_fn = module_fn,
275 .debug_output = debug_output,
276 .err_msg = null,270 .err_msg = null,
277 .args = undefined, // populated after `resolveCallingConventionValues`271 .args = undefined, // populated after `resolveCallingConventionValues`
278 .ret_mcv = undefined, // populated after `resolveCallingConventionValues`272 .ret_mcv = undefined, // populated after `resolveCallingConventionValues`
...@@ -281,9 +275,6 @@ pub fn generate(...@@ -281,9 +275,6 @@ pub fn generate(
281 .branch_stack = &branch_stack,275 .branch_stack = &branch_stack,
282 .src_loc = src_loc,276 .src_loc = src_loc,
283 .stack_align = undefined,277 .stack_align = undefined,
284 .prev_di_pc = 0,
285 .prev_di_line = module_fn.lbrace_line,
286 .prev_di_column = module_fn.lbrace_column,
287 .end_di_line = module_fn.rbrace_line,278 .end_di_line = module_fn.rbrace_line,
288 .end_di_column = module_fn.rbrace_column,279 .end_di_column = module_fn.rbrace_column,
289 };280 };
...@@ -316,8 +307,12 @@ pub fn generate(...@@ -316,8 +307,12 @@ pub fn generate(
316 var emit = Emit{307 var emit = Emit{
317 .mir = mir,308 .mir = mir,
318 .bin_file = bin_file,309 .bin_file = bin_file,
310 .debug_output = debug_output,
319 .target = &bin_file.options.target,311 .target = &bin_file.options.target,
320 .code = code,312 .code = code,
313 .prev_di_pc = 0,
314 .prev_di_line = module_fn.lbrace_line,
315 .prev_di_column = module_fn.lbrace_column,
321 };316 };
322 try emit.emitMir();317 try emit.emitMir();
323318
...@@ -386,7 +381,10 @@ fn gen(self: *Self) !void {...@@ -386,7 +381,10 @@ fn gen(self: *Self) !void {
386 .data = .{ .nop = {} },381 .data = .{ .nop = {} },
387 });382 });
388383
389 try self.dbgSetPrologueEnd();384 _ = try self.addInst(.{
385 .tag = .dbg_prologue_end,
386 .data = .{ .nop = {} },
387 });
390388
391 try self.genBody(self.air.getMainBody());389 try self.genBody(self.air.getMainBody());
392390
...@@ -402,7 +400,10 @@ fn gen(self: *Self) !void {...@@ -402,7 +400,10 @@ fn gen(self: *Self) !void {
402 return self.failSymbol("TODO AArch64: allow larger stacks", .{});400 return self.failSymbol("TODO AArch64: allow larger stacks", .{});
403 }401 }
404402
405 try self.dbgSetEpilogueBegin();403 _ = try self.addInst(.{
404 .tag = .dbg_epilogue_begin,
405 .data = .{ .nop = {} },
406 });
406407
407 // exitlude jumps408 // exitlude jumps
408 if (self.exitlude_jump_relocs.items.len == 1) {409 if (self.exitlude_jump_relocs.items.len == 1) {
...@@ -442,13 +443,27 @@ fn gen(self: *Self) !void {...@@ -442,13 +443,27 @@ fn gen(self: *Self) !void {
442 .data = .{ .reg = .x30 },443 .data = .{ .reg = .x30 },
443 });444 });
444 } else {445 } else {
445 try self.dbgSetPrologueEnd();446 _ = try self.addInst(.{
447 .tag = .dbg_prologue_end,
448 .data = .{ .nop = {} },
449 });
450
446 try self.genBody(self.air.getMainBody());451 try self.genBody(self.air.getMainBody());
447 try self.dbgSetEpilogueBegin();452
453 _ = try self.addInst(.{
454 .tag = .dbg_epilogue_begin,
455 .data = .{ .nop = {} },
456 });
448 }457 }
449458
450 // Drop them off at the rbrace.459 // 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 });
452}467}
453468
454fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {469fn 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 {...@@ -589,79 +604,6 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
589 }604 }
590}605}
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
665/// Asserts there is already capacity to insert into top branch inst_table.607/// Asserts there is already capacity to insert into top branch inst_table.
666fn processDeath(self: *Self, inst: Air.Inst.Index) void {608fn processDeath(self: *Self, inst: Air.Inst.Index) void {
667 const air_tags = self.air.instructions.items(.tag);609 const air_tags = self.air.instructions.items(.tag);
...@@ -1407,7 +1349,8 @@ fn airArg(self: *Self, inst: Air.Inst.Index) !void {...@@ -1407,7 +1349,8 @@ fn airArg(self: *Self, inst: Air.Inst.Index) !void {
1407 },1349 },
1408 else => result,1350 else => result,
1409 };1351 };
1410 try self.genArgDbgInfo(inst, mcv);1352 // TODO generate debug info
1353 // try self.genArgDbgInfo(inst, mcv);
14111354
1412 if (self.liveness.isUnused(inst))1355 if (self.liveness.isUnused(inst))
1413 return self.finishAirBookkeeping();1356 return self.finishAirBookkeeping();
...@@ -1698,8 +1641,15 @@ fn airCmp(self: *Self, inst: Air.Inst.Index, op: math.CompareOperator) !void {...@@ -1698,8 +1641,15 @@ fn airCmp(self: *Self, inst: Air.Inst.Index, op: math.CompareOperator) !void {
16981641
1699fn airDbgStmt(self: *Self, inst: Air.Inst.Index) !void {1642fn airDbgStmt(self: *Self, inst: Air.Inst.Index) !void {
1700 const dbg_stmt = self.air.instructions.items(.data)[inst].dbg_stmt;1643 const dbg_stmt = self.air.instructions.items(.data)[inst].dbg_stmt;
1701 _ = dbg_stmt;1644
1702 // try self.dbgAdvancePCAndLine(dbg_stmt.line, dbg_stmt.column);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
1703 return self.finishAirBookkeeping();1653 return self.finishAirBookkeeping();
1704}1654}
17051655
src/arch/aarch64/Emit.zig+97
...@@ -8,14 +8,23 @@ const Mir = @import("Mir.zig");...@@ -8,14 +8,23 @@ const Mir = @import("Mir.zig");
8const bits = @import("bits.zig");8const bits = @import("bits.zig");
9const link = @import("../../link.zig");9const link = @import("../../link.zig");
10const assert = std.debug.assert;10const assert = std.debug.assert;
11const DW = std.dwarf;
12const leb128 = std.leb;
11const Instruction = bits.Instruction;13const Instruction = bits.Instruction;
12const Register = bits.Register;14const Register = bits.Register;
15const DebugInfoOutput = @import("../../codegen.zig").DebugInfoOutput;
1316
14mir: Mir,17mir: Mir,
15bin_file: *link.File,18bin_file: *link.File,
19debug_output: DebugInfoOutput,
16target: *const std.Target,20target: *const std.Target,
17code: *std.ArrayList(u8),21code: *std.ArrayList(u8),
1822
23prev_di_line: u32,
24prev_di_column: u32,
25/// Relative to the beginning of `code`.
26prev_di_pc: usize,
27
19pub fn emitMir(28pub fn emitMir(
20 emit: *Emit,29 emit: *Emit,
21) !void {30) !void {
...@@ -38,6 +47,11 @@ pub fn emitMir(...@@ -38,6 +47,11 @@ pub fn emitMir(
3847
39 .call_extern => try emit.mirCallExtern(inst),48 .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
41 .load_memory => try emit.mirLoadMemory(inst),55 .load_memory => try emit.mirLoadMemory(inst),
4256
43 .ldp => try emit.mirLoadStoreRegisterPair(inst),57 .ldp => try emit.mirLoadStoreRegisterPair(inst),
...@@ -80,6 +94,57 @@ fn moveImmediate(emit: *Emit, reg: Register, imm64: u64) !void {...@@ -80,6 +94,57 @@ fn moveImmediate(emit: *Emit, reg: Register, imm64: u64) !void {
80 }94 }
81}95}
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
83fn mirAddSubtractImmediate(emit: *Emit, inst: Mir.Inst.Index) !void {148fn mirAddSubtractImmediate(emit: *Emit, inst: Mir.Inst.Index) !void {
84 const tag = emit.mir.instructions.items(.tag)[inst];149 const tag = emit.mir.instructions.items(.tag)[inst];
85 const rr_imm12_sh = emit.mir.instructions.items(.data)[inst].rr_imm12_sh;150 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 {...@@ -136,6 +201,38 @@ fn mirExceptionGeneration(emit: *Emit, inst: Mir.Inst.Index) !void {
136 }201 }
137}202}
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
139fn mirCallExtern(emit: *Emit, inst: Mir.Inst.Index) !void {236fn mirCallExtern(emit: *Emit, inst: Mir.Inst.Index) !void {
140 assert(emit.mir.instructions.items(.tag)[inst] == .call_extern);237 assert(emit.mir.instructions.items(.tag)[inst] == .call_extern);
141 const n_strx = emit.mir.instructions.items(.data)[inst].extern_fn;238 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 {...@@ -36,6 +36,12 @@ pub const Inst = struct {
36 brk,36 brk,
37 /// Pseudo-instruction: Call extern37 /// Pseudo-instruction: Call extern
38 call_extern,38 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,
39 /// Psuedo-instruction: Load memory45 /// Psuedo-instruction: Load memory
40 ///46 ///
41 /// Payload is `LoadMemory`47 /// Payload is `LoadMemory`
...@@ -152,6 +158,13 @@ pub const Inst = struct {...@@ -152,6 +158,13 @@ pub const Inst = struct {
152 rn: Register,158 rn: Register,
153 offset: bits.Instruction.LoadStorePairOffset,159 offset: bits.Instruction.LoadStorePairOffset,
154 },160 },
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 },
155 };168 };
156169
157 // Make sure we don't accidentally make instructions bigger than expected.170 // Make sure we don't accidentally make instructions bigger than expected.