authorgravatar for jacobly@ziglang.orgJacob Young <jacobly@ziglang.org> 2026-08-11 01:43:20-04:00
committergravatar for jacobly@ziglang.orgJacob Young <jacobly@ziglang.org> 2026-09-03 11:00:55-04:00
log0bf3e08c705ec460c71d3b2261acb0b87aacd066
tree1c5b6358e923fa25d99ffa88563ab1d507411baf
parentabbec23e9cfb6549a2260fd447086dfd2935a350

x86_64: change how epilogue line info is emitted

This more closely matches the output of other compilers.

9 files changed, 161 insertions(+), 92 deletions(-)

src/codegen/riscv64/Emit.zig+1-2
...@@ -192,8 +192,7 @@ fn dbgAdvancePCAndLine(emit: *Emit, line: u32, column: u32) Error!void {...@@ -192,8 +192,7 @@ fn dbgAdvancePCAndLine(emit: *Emit, line: u32, column: u32) Error!void {
192 switch (emit.debug_output) {192 switch (emit.debug_output) {
193 inline .dwarf, .dwarf2 => |dw| {193 inline .dwarf, .dwarf2 => |dw| {
194 if (column != emit.prev_di_column) try dw.setColumn(column);194 if (column != emit.prev_di_column) try dw.setColumn(column);
195 if (delta_line == 0) return; // TODO: fix these edge cases.195 try dw.advanceLineAndPc(delta_line, delta_pc, false);
196 try dw.advancePcAndLine(delta_line, delta_pc);
197 emit.prev_di_line = line;196 emit.prev_di_line = line;
198 emit.prev_di_column = column;197 emit.prev_di_column = column;
199 emit.prev_di_pc = emit.w.end;198 emit.prev_di_pc = emit.w.end;
src/codegen/sparc64/Emit.zig+1-1
...@@ -497,7 +497,7 @@ fn dbgAdvancePCAndLine(emit: *Emit, line: u32, column: u32) !void {...@@ -497,7 +497,7 @@ fn dbgAdvancePCAndLine(emit: *Emit, line: u32, column: u32) !void {
497 const delta_pc: usize = emit.w.end - emit.prev_di_pc;497 const delta_pc: usize = emit.w.end - emit.prev_di_pc;
498 switch (emit.debug_output) {498 switch (emit.debug_output) {
499 inline .dwarf, .dwarf2 => |dbg_out| {499 inline .dwarf, .dwarf2 => |dbg_out| {
500 try dbg_out.advancePcAndLine(delta_line, delta_pc);500 try dbg_out.advanceLineAndPc(delta_line, delta_pc, false);
501 emit.prev_di_line = line;501 emit.prev_di_line = line;
502 emit.prev_di_column = column;502 emit.prev_di_column = column;
503 emit.prev_di_pc = emit.w.end;503 emit.prev_di_pc = emit.w.end;
src/codegen/x86_64/CodeGen.zig+18-23
...@@ -1072,20 +1072,12 @@ pub fn generate(...@@ -1072,20 +1072,12 @@ pub fn generate(
1072 );1072 );
1073 }1073 }
10741074
1075 function.gen(&file.zir.?, func_zir.inst, func.comptime_args, call_info.air_arg_count) catch |err| switch (err) {1075 function.gen(&file.zir.?, func_zir.inst, &func, call_info.air_arg_count) catch |err| switch (err) {
1076 error.OutOfRegisters => return function.fail("ran out of registers (Zig compiler bug)", .{}),1076 error.OutOfRegisters => return function.fail("ran out of registers (Zig compiler bug)", .{}),
1077 else => |e| return e,1077 else => |e| return e,
1078 };1078 };
10791079
1080 // Drop them off at the rbrace.1080 if (!mod.strip) _ = try function.asmPseudo(.pseudo_dbg_end_none);
1081 if (!mod.strip) _ = try function.addInst(.{
1082 .tag = .pseudo,
1083 .ops = .pseudo_dbg_line_line_column,
1084 .data = .{ .line_column = .{
1085 .line = func.rbrace_line,
1086 .column = func.rbrace_column,
1087 } },
1088 });
10891081
1090 try function.mir_extra.shrinkToLen(gpa);1082 try function.mir_extra.shrinkToLen(gpa);
1091 try function.mir_string_bytes.shrinkToLen(gpa);1083 try function.mir_string_bytes.shrinkToLen(gpa);
...@@ -1228,18 +1220,18 @@ fn formatWipMir(data: FormatWipMirData, w: *Writer) Writer.Error!void {...@@ -1228,18 +1220,18 @@ fn formatWipMir(data: FormatWipMirData, w: *Writer) Writer.Error!void {
1228 switch (mir_inst.ops) {1220 switch (mir_inst.ops) {
1229 else => unreachable,1221 else => unreachable,
1230 .pseudo_dbg_prologue_end_none,1222 .pseudo_dbg_prologue_end_none,
1231 .pseudo_dbg_epilogue_begin_none,
1232 .pseudo_dbg_enter_block_none,1223 .pseudo_dbg_enter_block_none,
1233 .pseudo_dbg_leave_block_none,1224 .pseudo_dbg_leave_block_none,
1225 .pseudo_dbg_end_none,
1234 .pseudo_dbg_arg_none,1226 .pseudo_dbg_arg_none,
1235 .pseudo_dbg_var_args_none,1227 .pseudo_dbg_var_args_none,
1236 .pseudo_dbg_var_none,1228 .pseudo_dbg_var_none,
1237 .pseudo_dead_none,1229 .pseudo_dead_none,
1238 => {},1230 => {},
1239 .pseudo_dbg_line_stmt_line_column, .pseudo_dbg_line_line_column => try w.print(1231 .pseudo_dbg_line_stmt_line_column,
1240 " {[line]d}, {[column]d}",1232 .pseudo_dbg_line_line_column,
1241 mir_inst.data.line_column,1233 .pseudo_dbg_epilogue_begin_line_column,
1242 ),1234 => try w.print(" {[line]d}, {[column]d}", mir_inst.data.line_column),
1243 .pseudo_dbg_enter_inline_func, .pseudo_dbg_leave_inline_func => try w.print(" {f}", .{1235 .pseudo_dbg_enter_inline_func, .pseudo_dbg_leave_inline_func => try w.print(" {f}", .{
1244 ip.getNav(ip.indexToKey(mir_inst.data.ip_index).func.owner_nav).name.fmt(ip),1236 ip.getNav(ip.indexToKey(mir_inst.data.ip_index).func.owner_nav).name.fmt(ip),
1245 }),1237 }),
...@@ -2069,7 +2061,7 @@ fn gen(...@@ -2069,7 +2061,7 @@ fn gen(
2069 self: *CodeGen,2061 self: *CodeGen,
2070 zir: *const std.zig.Zir,2062 zir: *const std.zig.Zir,
2071 func_zir_inst: std.zig.Zir.Inst.Index,2063 func_zir_inst: std.zig.Zir.Inst.Index,
2072 comptime_args: InternPool.Index.Slice,2064 func: *const InternPool.Key.Func,
2073 air_arg_count: u32,2065 air_arg_count: u32,
2074) InnerError!void {2066) InnerError!void {
2075 const pt = self.pt;2067 const pt = self.pt;
...@@ -2150,7 +2142,7 @@ fn gen(...@@ -2150,7 +2142,7 @@ fn gen(
21502142
2151 if (!self.mod.strip) try self.asmPseudo(.pseudo_dbg_prologue_end_none);2143 if (!self.mod.strip) try self.asmPseudo(.pseudo_dbg_prologue_end_none);
21522144
2153 try self.genMainBody(zir, func_zir_inst, comptime_args, air_arg_count);2145 try self.genMainBody(zir, func_zir_inst, func.comptime_args, air_arg_count);
21542146
2155 const epilogue = if (self.epilogue_relocs.items.len > 0) epilogue: {2147 const epilogue = if (self.epilogue_relocs.items.len > 0) epilogue: {
2156 var last_inst: Mir.Inst.Index = @intCast(self.mir_instructions.len - 1);2148 var last_inst: Mir.Inst.Index = @intCast(self.mir_instructions.len - 1);
...@@ -2165,7 +2157,14 @@ fn gen(...@@ -2165,7 +2157,14 @@ fn gen(
2165 }2157 }
2166 for (self.epilogue_relocs.items) |epilogue_reloc| self.performReloc(epilogue_reloc);2158 for (self.epilogue_relocs.items) |epilogue_reloc| self.performReloc(epilogue_reloc);
21672159
2168 if (!self.mod.strip) try self.asmPseudo(.pseudo_dbg_epilogue_begin_none);2160 if (!self.mod.strip) _ = try self.addInst(.{
2161 .tag = .pseudo,
2162 .ops = .pseudo_dbg_epilogue_begin_line_column,
2163 .data = .{ .line_column = .{
2164 .line = func.rbrace_line,
2165 .column = func.rbrace_column,
2166 } },
2167 });
2169 const backpatch_stack_dealloc = try self.asmPlaceholder();2168 const backpatch_stack_dealloc = try self.asmPlaceholder();
2170 const backpatch_pop_callee_preserved_regs = try self.asmPlaceholder();2169 const backpatch_pop_callee_preserved_regs = try self.asmPlaceholder();
2171 try self.asmRegister(.{ ._, .pop }, .rbp);2170 try self.asmRegister(.{ ._, .pop }, .rbp);
...@@ -2283,11 +2282,7 @@ fn gen(...@@ -2283,11 +2282,7 @@ fn gen(
2283 .data = .{ .reg_list = frame_layout.save_reg_list },2282 .data = .{ .reg_list = frame_layout.save_reg_list },
2284 });2283 });
2285 }2284 }
2286 } else {2285 } else try self.genMainBody(zir, func_zir_inst, func.comptime_args, air_arg_count);
2287 if (!self.mod.strip) try self.asmPseudo(.pseudo_dbg_prologue_end_none);
2288 try self.genMainBody(zir, func_zir_inst, comptime_args, air_arg_count);
2289 if (!self.mod.strip) try self.asmPseudo(.pseudo_dbg_epilogue_begin_none);
2290 }
2291}2286}
22922287
2293fn genMainBody(2288fn genMainBody(
src/codegen/x86_64/Emit.zig+23-9
...@@ -462,20 +462,25 @@ pub fn emitMir(emit: *Emit) Error!void {...@@ -462,20 +462,25 @@ pub fn emitMir(emit: *Emit) Error!void {
462 switch (mir_inst.ops) {462 switch (mir_inst.ops) {
463 else => unreachable,463 else => unreachable,
464 .pseudo_dbg_prologue_end_none => switch (emit.debug_output) {464 .pseudo_dbg_prologue_end_none => switch (emit.debug_output) {
465 inline .dwarf, .dwarf2 => |dwarf| try dwarf.setPrologueEnd(),465 inline .dwarf, .dwarf2 => |dwarf| {
466 try dwarf.setPrologueEnd();
467 log.debug("mirDbgPrologueEnd (line={d}, col={d})", .{
468 emit.prev_di_loc.line, emit.prev_di_loc.column,
469 });
470 },
466 .eh_frame, .none => {},471 .eh_frame, .none => {},
467 },472 },
468 .pseudo_dbg_line_stmt_line_column => try emit.dbgAdvancePcAndLine(.{473 .pseudo_dbg_line_stmt_line_column => try emit.dbgAdvanceLineAndPc(.{
469 .line = mir_inst.data.line_column.line,474 .line = mir_inst.data.line_column.line,
470 .column = mir_inst.data.line_column.column,475 .column = mir_inst.data.line_column.column,
471 .is_stmt = true,476 .is_stmt = true,
472 }),477 }),
473 .pseudo_dbg_line_line_column => try emit.dbgAdvancePcAndLine(.{478 .pseudo_dbg_line_line_column => try emit.dbgAdvanceLineAndPc(.{
474 .line = mir_inst.data.line_column.line,479 .line = mir_inst.data.line_column.line,
475 .column = mir_inst.data.line_column.column,480 .column = mir_inst.data.line_column.column,
476 .is_stmt = false,481 .is_stmt = false,
477 }),482 }),
478 .pseudo_dbg_epilogue_begin_none => {483 .pseudo_dbg_epilogue_begin_line_column => {
479 switch (emit.debug_output) {484 switch (emit.debug_output) {
480 inline .dwarf, .dwarf2 => |dwarf| {485 inline .dwarf, .dwarf2 => |dwarf| {
481 try dwarf.setEpilogueBegin();486 try dwarf.setEpilogueBegin();
...@@ -485,7 +490,10 @@ pub fn emitMir(emit: *Emit) Error!void {...@@ -485,7 +490,10 @@ pub fn emitMir(emit: *Emit) Error!void {
485 },490 },
486 .eh_frame, .none => {},491 .eh_frame, .none => {},
487 }492 }
488 try emit.dbgAdvancePcAndLine(emit.prev_di_loc);493 try emit.dbgAdvanceLineAndPc(.{
494 .line = mir_inst.data.line_column.line,
495 .column = mir_inst.data.line_column.column,
496 });
489 },497 },
490 .pseudo_dbg_enter_block_none => switch (emit.debug_output) {498 .pseudo_dbg_enter_block_none => switch (emit.debug_output) {
491 inline .dwarf, .dwarf2 => |dwarf| {499 inline .dwarf, .dwarf2 => |dwarf| {
...@@ -523,6 +531,11 @@ pub fn emitMir(emit: *Emit) Error!void {...@@ -523,6 +531,11 @@ pub fn emitMir(emit: *Emit) Error!void {
523 },531 },
524 .eh_frame, .none => {},532 .eh_frame, .none => {},
525 },533 },
534 .pseudo_dbg_end_none => try emit.dbgAdvanceLineAndPc(.{
535 .line = emit.prev_di_loc.line,
536 .column = emit.prev_di_loc.column,
537 .end = true,
538 }),
526 .pseudo_dbg_arg_none,539 .pseudo_dbg_arg_none,
527 .pseudo_dbg_arg_i_s,540 .pseudo_dbg_arg_i_s,
528 .pseudo_dbg_arg_i_u,541 .pseudo_dbg_arg_i_u,
...@@ -974,18 +987,19 @@ const TableReloc = struct {...@@ -974,18 +987,19 @@ const TableReloc = struct {
974const Loc = struct {987const Loc = struct {
975 line: u32,988 line: u32,
976 column: u32,989 column: u32,
977 is_stmt: bool,990 is_stmt: ?bool = null,
991 end: bool = false,
978};992};
979993
980fn dbgAdvancePcAndLine(emit: *Emit, loc: Loc) Error!void {994fn dbgAdvanceLineAndPc(emit: *Emit, loc: Loc) Error!void {
981 switch (emit.debug_output) {995 switch (emit.debug_output) {
982 inline .dwarf, .dwarf2 => |dwarf| {996 inline .dwarf, .dwarf2 => |dwarf| {
983 const delta_line = @as(i33, loc.line) - @as(i33, emit.prev_di_loc.line);997 const delta_line = @as(i33, loc.line) - @as(i33, emit.prev_di_loc.line);
984 const delta_pc: usize = emit.w.end - emit.prev_di_pc;998 const delta_pc: usize = emit.w.end - emit.prev_di_pc;
985 log.debug(" (advance pc={d} and line={d})", .{ delta_pc, delta_line });999 log.debug(" (advance pc={d} and line={d})", .{ delta_pc, delta_line });
986 if (loc.is_stmt != emit.prev_di_loc.is_stmt) try dwarf.negateStmt();1000 if (loc.is_stmt) |is_stmt| if (is_stmt != emit.prev_di_loc.is_stmt) try dwarf.negateStmt();
987 if (loc.column != emit.prev_di_loc.column) try dwarf.setColumn(loc.column);1001 if (loc.column != emit.prev_di_loc.column) try dwarf.setColumn(loc.column);
988 try dwarf.advancePcAndLine(delta_line, delta_pc);1002 try dwarf.advanceLineAndPc(delta_line, delta_pc, loc.end);
989 emit.prev_di_loc = loc;1003 emit.prev_di_loc = loc;
990 emit.prev_di_pc = emit.w.end;1004 emit.prev_di_pc = emit.w.end;
991 },1005 },
src/codegen/x86_64/Lower.zig+2-1
...@@ -314,11 +314,12 @@ pub fn lowerMir(lower: *Lower, index: Mir.Inst.Index) Error!struct {...@@ -314,11 +314,12 @@ pub fn lowerMir(lower: *Lower, index: Mir.Inst.Index) Error!struct {
314 .pseudo_dbg_prologue_end_none,314 .pseudo_dbg_prologue_end_none,
315 .pseudo_dbg_line_stmt_line_column,315 .pseudo_dbg_line_stmt_line_column,
316 .pseudo_dbg_line_line_column,316 .pseudo_dbg_line_line_column,
317 .pseudo_dbg_epilogue_begin_none,317 .pseudo_dbg_epilogue_begin_line_column,
318 .pseudo_dbg_enter_block_none,318 .pseudo_dbg_enter_block_none,
319 .pseudo_dbg_leave_block_none,319 .pseudo_dbg_leave_block_none,
320 .pseudo_dbg_enter_inline_func,320 .pseudo_dbg_enter_inline_func,
321 .pseudo_dbg_leave_inline_func,321 .pseudo_dbg_leave_inline_func,
322 .pseudo_dbg_end_none,
322 .pseudo_dbg_arg_none,323 .pseudo_dbg_arg_none,
323 .pseudo_dbg_arg_i_s,324 .pseudo_dbg_arg_i_s,
324 .pseudo_dbg_arg_i_u,325 .pseudo_dbg_arg_i_u,
src/codegen/x86_64/Mir.zig+13-10
...@@ -1519,30 +1519,33 @@ pub const Inst = struct {...@@ -1519,30 +1519,33 @@ pub const Inst = struct {
1519 /// Uses `bytes` payload.1519 /// Uses `bytes` payload.
1520 pseudo_cfi_escape_bytes,1520 pseudo_cfi_escape_bytes,
15211521
1522 /// End of prologue1522 /// End of prologue.
1523 /// Uses `none` payload.1523 /// Uses `none` payload.
1524 pseudo_dbg_prologue_end_none,1524 pseudo_dbg_prologue_end_none,
1525 /// Update debug line with is_stmt register set1525 /// Update debug line with is_stmt register set.
1526 /// Uses `line_column` payload.1526 /// Uses `line_column` payload.
1527 pseudo_dbg_line_stmt_line_column,1527 pseudo_dbg_line_stmt_line_column,
1528 /// Update debug line with is_stmt register clear1528 /// Update debug line with is_stmt register clear.
1529 /// Uses `line_column` payload.1529 /// Uses `line_column` payload.
1530 pseudo_dbg_line_line_column,1530 pseudo_dbg_line_line_column,
1531 /// Start of epilogue1531 /// Start of epilogue.
1532 /// Uses `none` payload.1532 /// Uses `line_column` payload.
1533 pseudo_dbg_epilogue_begin_none,1533 pseudo_dbg_epilogue_begin_line_column,
1534 /// Start of lexical block1534 /// Start of lexical block.
1535 /// Uses `none` payload.1535 /// Uses `none` payload.
1536 pseudo_dbg_enter_block_none,1536 pseudo_dbg_enter_block_none,
1537 /// End of lexical block1537 /// End of lexical block.
1538 /// Uses `none` payload.1538 /// Uses `none` payload.
1539 pseudo_dbg_leave_block_none,1539 pseudo_dbg_leave_block_none,
1540 /// Start of inline function1540 /// Start of inline function.
1541 /// Uses `ip_index` payload.1541 /// Uses `ip_index` payload.
1542 pseudo_dbg_enter_inline_func,1542 pseudo_dbg_enter_inline_func,
1543 /// End of inline function1543 /// End of inline function.
1544 /// Uses `ip_index` payload.1544 /// Uses `ip_index` payload.
1545 pseudo_dbg_leave_inline_func,1545 pseudo_dbg_leave_inline_func,
1546 /// End of function.
1547 /// Uses `none` payload.
1548 pseudo_dbg_end_none,
1546 /// Local argument.1549 /// Local argument.
1547 /// Uses `none` payload.1550 /// Uses `none` payload.
1548 pseudo_dbg_arg_none,1551 pseudo_dbg_arg_none,
src/link/Dwarf.zig+32-18
...@@ -1626,15 +1626,25 @@ pub const WipNav = struct {...@@ -1626,15 +1626,25 @@ pub const WipNav = struct {
1626 wip_nav.any_children = true;1626 wip_nav.any_children = true;
1627 }1627 }
16281628
1629 pub fn advancePcAndLine(wip_nav: *WipNav, delta_line: i33, delta_pc: u64) Allocator.Error!void {1629 pub fn advanceLineAndPc(
1630 return wip_nav.advancePcAndLineWriterError(delta_line, delta_pc) catch |err| switch (err) {1630 wip_nav: *WipNav,
1631 delta_line: i33,
1632 delta_pc: u64,
1633 end: bool,
1634 ) Allocator.Error!void {
1635 return wip_nav.advanceLineAndPcWriterError(
1636 delta_line,
1637 delta_pc,
1638 end,
1639 ) catch |err| switch (err) {
1631 error.WriteFailed => error.OutOfMemory,1640 error.WriteFailed => error.OutOfMemory,
1632 };1641 };
1633 }1642 }
1634 fn advancePcAndLineWriterError(1643 fn advanceLineAndPcWriterError(
1635 wip_nav: *WipNav,1644 wip_nav: *WipNav,
1636 delta_line: i33,1645 delta_line: i33,
1637 delta_pc: u64,1646 delta_pc: u64,
1647 end: bool,
1638 ) Writer.Error!void {1648 ) Writer.Error!void {
1639 const dlw = &wip_nav.debug_line.writer;1649 const dlw = &wip_nav.debug_line.writer;
16401650
...@@ -1654,20 +1664,30 @@ pub const WipNav = struct {...@@ -1654,20 +1664,30 @@ pub const WipNav = struct {
1654 const op_advance = @divExact(delta_pc, header.minimum_instruction_length) *1664 const op_advance = @divExact(delta_pc, header.minimum_instruction_length) *
1655 header.maximum_operations_per_instruction + delta_op;1665 header.maximum_operations_per_instruction + delta_op;
1656 const max_op_advance: u9 = (std.math.maxInt(u8) - header.opcode_base) / header.line_range;1666 const max_op_advance: u9 = (std.math.maxInt(u8) - header.opcode_base) / header.line_range;
1657 const remaining_op_advance: u8 = @intCast(if (op_advance >= 2 * max_op_advance) remaining: {1667 const remaining_op_advance: u8 = @intCast(if (end or
1658 try dlw.writeByte(DW.LNS.advance_pc);1668 op_advance >= 2 * max_op_advance)
1659 try dlw.writeUleb128(op_advance);1669 remaining: {
1670 if (op_advance == max_op_advance) {
1671 try dlw.writeByte(DW.LNS.const_add_pc);
1672 } else if (op_advance != 0) {
1673 try dlw.writeByte(DW.LNS.advance_pc);
1674 try dlw.writeUleb128(op_advance);
1675 } else assert(end);
1660 break :remaining 0;1676 break :remaining 0;
1661 } else if (op_advance >= max_op_advance) remaining: {1677 } else if (op_advance >= max_op_advance) remaining: {
1662 try dlw.writeByte(DW.LNS.const_add_pc);1678 try dlw.writeByte(DW.LNS.const_add_pc);
1663 break :remaining op_advance - max_op_advance;1679 break :remaining op_advance - max_op_advance;
1664 } else op_advance);1680 } else op_advance);
16651681
1666 if (remaining_delta_line == 0 and remaining_op_advance == 0)1682 if (remaining_delta_line != 0 or remaining_op_advance != 0) {
1667 try dlw.writeByte(DW.LNS.copy)1683 assert(!end);
1668 else
1669 try dlw.writeByte(@intCast((remaining_delta_line - header.line_base) +1684 try dlw.writeByte(@intCast((remaining_delta_line - header.line_base) +
1670 (header.line_range * remaining_op_advance) + header.opcode_base));1685 (header.line_range * remaining_op_advance) + header.opcode_base));
1686 } else if (end) {
1687 try dlw.writeByte(DW.LNS.extended_op);
1688 try dlw.writeUleb128(1);
1689 try dlw.writeByte(DW.LNE.end_sequence);
1690 } else try dlw.writeByte(DW.LNS.copy);
1671 }1691 }
16721692
1673 pub fn setColumn(wip_nav: *WipNav, column: u32) Allocator.Error!void {1693 pub fn setColumn(wip_nav: *WipNav, column: u32) Allocator.Error!void {
...@@ -2773,7 +2793,7 @@ fn initWipNavInner(...@@ -2773,7 +2793,7 @@ fn initWipNavInner(
2773 try dlw.writeByte(DW.LNS.set_column);2793 try dlw.writeByte(DW.LNS.set_column);
2774 try dlw.writeUleb128(func.lbrace_column + 1);2794 try dlw.writeUleb128(func.lbrace_column + 1);
27752795
2776 try wip_nav.advancePcAndLine(func.lbrace_line, 0);2796 try wip_nav.advanceLineAndPc(func.lbrace_line, 0, false);
2777 } else {2797 } else {
2778 try dlw.writeUleb128(1 + @backingInt(dwarf.address_size));2798 try dlw.writeUleb128(1 + @backingInt(dwarf.address_size));
2779 try dlw.writeByte(DW.LNE.set_address);2799 try dlw.writeByte(DW.LNE.set_address);
...@@ -2790,7 +2810,7 @@ fn initWipNavInner(...@@ -2790,7 +2810,7 @@ fn initWipNavInner(
2790 try dlw.writeByte(DW.LNS.set_column);2810 try dlw.writeByte(DW.LNS.set_column);
2791 try dlw.writeUleb128(func.lbrace_column + 1);2811 try dlw.writeUleb128(func.lbrace_column + 1);
27922812
2793 try wip_nav.advancePcAndLine(@intCast(decl.src_line + func.lbrace_line), 0);2813 try wip_nav.advanceLineAndPc(decl.src_line + func.lbrace_line, 0, false);
2794 }2814 }
2795 },2815 },
2796 else => {2816 else => {
...@@ -2982,13 +3002,7 @@ fn finishWipNavWriterError(...@@ -2982,13 +3002,7 @@ fn finishWipNavWriterError(
2982 log.debug("finishWipNav({f})", .{nav.fqn.fmt(ip)});3002 log.debug("finishWipNav({f})", .{nav.fqn.fmt(ip)});
29833003
2984 try dwarf.debug_info.section.replaceEntry(wip_nav.unit, wip_nav.entry, dwarf, wip_nav.debug_info.written());3004 try dwarf.debug_info.section.replaceEntry(wip_nav.unit, wip_nav.entry, dwarf, wip_nav.debug_info.written());
2985 const dlw = &wip_nav.debug_line.writer;3005 try dwarf.debug_line.section.replaceEntry(wip_nav.unit, wip_nav.entry, dwarf, wip_nav.debug_line.written());
2986 if (dlw.end > 0) {
2987 try dlw.writeByte(DW.LNS.extended_op);
2988 try dlw.writeUleb128(1);
2989 try dlw.writeByte(DW.LNE.end_sequence);
2990 try dwarf.debug_line.section.replaceEntry(wip_nav.unit, wip_nav.entry, dwarf, wip_nav.debug_line.written());
2991 }
2992 try dwarf.debug_loclists.section.replaceEntry(wip_nav.unit, wip_nav.entry, dwarf, wip_nav.debug_loclists.written());3006 try dwarf.debug_loclists.section.replaceEntry(wip_nav.unit, wip_nav.entry, dwarf, wip_nav.debug_loclists.written());
29933007
2994 try dwarf.const_pool.flushPending(pt, .{ .dwarf = dwarf });3008 try dwarf.const_pool.flushPending(pt, .{ .dwarf = dwarf });
src/link/Dwarf2.zig+70-27
...@@ -24,14 +24,15 @@ debug_str_offsets: StrOffsets,...@@ -24,14 +24,15 @@ debug_str_offsets: StrOffsets,
24pub const AddressSize = enum(u8) { @"32" = 4, @"64" = 8, _ };24pub const AddressSize = enum(u8) { @"32" = 4, @"64" = 8, _ };
2525
26pub const Unit = struct {26pub const Unit = struct {
27 dirs: std.array_hash_map.Auto(Unit.Index, void),
27 files: std.array_hash_map.Auto(Zcu.File.Index, void),28 files: std.array_hash_map.Auto(Zcu.File.Index, void),
28 files_changed: bool,
29 frame_ni: MappedFile.Node.Index.Optional,29 frame_ni: MappedFile.Node.Index.Optional,
30 cie_ni: MappedFile.Node.Index.Optional,30 cie_ni: MappedFile.Node.Index.Optional,
31 debug_info_ni: MappedFile.Node.Index.Optional,31 debug_info_ni: MappedFile.Node.Index.Optional,
32 debug_info_header_ni: MappedFile.Node.Index.Optional,32 debug_info_header_ni: MappedFile.Node.Index.Optional,
33 debug_line_ni: MappedFile.Node.Index.Optional,33 debug_line_ni: MappedFile.Node.Index.Optional,
34 debug_line_header_ni: MappedFile.Node.Index.Optional,34 debug_line_header_ni: MappedFile.Node.Index.Optional,
35 debug_line_header_changed: bool,
35 debug_rnglists_ni: MappedFile.Node.Index.Optional,36 debug_rnglists_ni: MappedFile.Node.Index.Optional,
36 debug_rnglists_offset: usize,37 debug_rnglists_offset: usize,
3738
...@@ -47,6 +48,15 @@ pub const Unit = struct {...@@ -47,6 +48,15 @@ pub const Unit = struct {
47 }48 }
48 };49 };
4950
51 pub const DirIndex = enum(u32) {
52 root = 0,
53 _,
54
55 fn get(di: DirIndex, unit: *Unit) Unit.Index {
56 return unit.dirs.keys()[@backingInt(di)];
57 }
58 };
59
50 pub const FileIndex = enum(u32) {60 pub const FileIndex = enum(u32) {
51 root = 0,61 root = 0,
52 _,62 _,
...@@ -56,19 +66,29 @@ pub const Unit = struct {...@@ -56,19 +66,29 @@ pub const Unit = struct {
56 }66 }
57 };67 };
5868
69 fn deinit(unit: *Unit, gpa: std.mem.Allocator) void {
70 unit.dirs.deinit(gpa);
71 unit.files.deinit(gpa);
72 unit.* = undefined;
73 }
74
59 fn getFile(75 fn getFile(
60 unit: *Unit,76 unit: *Unit,
61 gpa: std.mem.Allocator,77 gpa: std.mem.Allocator,
78 ui: Unit.Index,
62 zfi: Zcu.File.Index,79 zfi: Zcu.File.Index,
63 ) std.mem.Allocator.Error!FileIndex {80 ) std.mem.Allocator.Error!struct { DirIndex, FileIndex } {
64 const file_gop = try unit.files.getOrPut(gpa, zfi);81 try unit.dirs.ensureUnusedCapacity(gpa, 1);
65 if (!file_gop.found_existing) unit.files_changed = true;82 try unit.files.ensureUnusedCapacity(gpa, 1);
66 return @fromBackingInt(@intCast(file_gop.index));83 const dir_gop = unit.dirs.getOrPutAssumeCapacity(ui);
84 const file_gop = unit.files.getOrPutAssumeCapacity(zfi);
85 if (!dir_gop.found_existing or !file_gop.found_existing) unit.debug_line_header_changed = true;
86 return .{ @fromBackingInt(@intCast(dir_gop.index)), @fromBackingInt(@intCast(file_gop.index)) };
67 }87 }
6888
69 pub fn cleanFilesChanged(unit: *Unit) bool {89 pub fn cleanDebugLineHeaderChanged(unit: *Unit) bool {
70 defer unit.files_changed = false;90 defer unit.debug_line_header_changed = false;
71 return unit.files_changed;91 return unit.debug_line_header_changed;
72 }92 }
73};93};
7494
...@@ -623,7 +643,6 @@ pub const WipNav = struct {...@@ -623,7 +643,6 @@ pub const WipNav = struct {
623 const zf = zcu.fileByIndex(zfi);643 const zf = zcu.fileByIndex(zfi);
624 const inst_info = ip.getNav(nav).srcInst(ip).resolveFull(ip).?;644 const inst_info = ip.getNav(nav).srcInst(ip).resolveFull(ip).?;
625 const decl = zf.zir.?.getDeclaration(inst_info.inst);645 const decl = zf.zir.?.getDeclaration(inst_info.inst);
626 const mod = zf.mod.?;
627 const dlw = &debug.line_writer.interface;646 const dlw = &debug.line_writer.interface;
628 try dlw.writeByte(DW.LNS.extended_op);647 try dlw.writeByte(DW.LNS.extended_op);
629 if (zcu.comp.config.incremental) {648 if (zcu.comp.config.incremental) {
...@@ -637,20 +656,21 @@ pub const WipNav = struct {...@@ -637,20 +656,21 @@ pub const WipNav = struct {
637 try dlw.writeByte(DW.LNS.set_column);656 try dlw.writeByte(DW.LNS.set_column);
638 try dlw.writeUleb128(func.lbrace_column + 1);657 try dlw.writeUleb128(func.lbrace_column + 1);
639658
640 try debug.advancePcAndLine(func.lbrace_line, 0);659 try debug.advanceLineAndPc(func.lbrace_line, 0, false);
641 } else {660 } else {
642 try dlw.writeUleb128(1 + @backingInt(dwarf.address_size));661 try dlw.writeUleb128(1 + @backingInt(dwarf.address_size));
643 try dlw.writeByte(DW.LNE.set_address);662 try dlw.writeByte(DW.LNE.set_address);
644 try dwarf.symbolAddress(&debug.line_writer, debug.wip_nav.func_si, 0);663 try dwarf.symbolAddress(&debug.line_writer, debug.wip_nav.func_si, 0);
645664
646 const fi = try dwarf.getUnit(mod).get(dwarf).getFile(zcu.gpa, zfi);665 const unit = dwarf.getUnit(zf.mod.?);
666 _, const fi = try unit.get(dwarf).getFile(zcu.gpa, unit, zfi);
647 try dlw.writeByte(DW.LNS.set_file);667 try dlw.writeByte(DW.LNS.set_file);
648 try dlw.writeUleb128(@backingInt(fi));668 try dlw.writeUleb128(@backingInt(fi));
649669
650 try dlw.writeByte(DW.LNS.set_column);670 try dlw.writeByte(DW.LNS.set_column);
651 try dlw.writeUleb128(func.lbrace_column + 1);671 try dlw.writeUleb128(func.lbrace_column + 1);
652672
653 try debug.advancePcAndLine(@intCast(decl.src_line + func.lbrace_line), 0);673 try debug.advanceLineAndPc(decl.src_line + func.lbrace_line, 0, false);
654 }674 }
655 }675 }
656676
...@@ -678,9 +698,6 @@ pub const WipNav = struct {...@@ -678,9 +698,6 @@ pub const WipNav = struct {
678 }698 }
679 fn finishDebugLine(debug: *Debug) link.EmitError!void {699 fn finishDebugLine(debug: *Debug) link.EmitError!void {
680 const dlw = &debug.line_writer.interface;700 const dlw = &debug.line_writer.interface;
681 try dlw.writeByte(DW.LNS.extended_op);
682 try dlw.writeUleb128(1);
683 try dlw.writeByte(DW.LNE.end_sequence);
684 try genDebugLinePadding(dlw, dlw.unusedCapacityLen());701 try genDebugLinePadding(dlw, dlw.unusedCapacityLen());
685 }702 }
686703
...@@ -773,12 +790,22 @@ pub const WipNav = struct {...@@ -773,12 +790,22 @@ pub const WipNav = struct {
773 debug.any_children = true;790 debug.any_children = true;
774 }791 }
775792
776 pub fn advancePcAndLine(debug: *Debug, delta_line: i33, delta_pc: u64) link.Error!void {793 pub fn advanceLineAndPc(
777 return debug.advancePcAndLineInner(delta_line, delta_pc) catch |err| switch (err) {794 debug: *Debug,
795 delta_line: i33,
796 delta_pc: u64,
797 end: bool,
798 ) link.Error!void {
799 return debug.advanceLineAndPcInner(delta_line, delta_pc, end) catch |err| switch (err) {
778 error.WriteFailed => return debug.wip_nav.reportWriteError(&debug.line_writer),800 error.WriteFailed => return debug.wip_nav.reportWriteError(&debug.line_writer),
779 };801 };
780 }802 }
781 fn advancePcAndLineInner(debug: *Debug, delta_line: i33, delta_pc: u64) Writer.Error!void {803 fn advanceLineAndPcInner(
804 debug: *Debug,
805 delta_line: i33,
806 delta_pc: u64,
807 end: bool,
808 ) Writer.Error!void {
782 const dlw = &debug.line_writer.interface;809 const dlw = &debug.line_writer.interface;
783810
784 const header = debug.wip_nav.dwarf.debug_line.header;811 const header = debug.wip_nav.dwarf.debug_line.header;
...@@ -797,20 +824,30 @@ pub const WipNav = struct {...@@ -797,20 +824,30 @@ pub const WipNav = struct {
797 const op_advance = @divExact(delta_pc, header.minimum_instruction_length) *824 const op_advance = @divExact(delta_pc, header.minimum_instruction_length) *
798 header.maximum_operations_per_instruction + delta_op;825 header.maximum_operations_per_instruction + delta_op;
799 const max_op_advance: u9 = (std.math.maxInt(u8) - header.opcode_base) / header.line_range;826 const max_op_advance: u9 = (std.math.maxInt(u8) - header.opcode_base) / header.line_range;
800 const remaining_op_advance: u8 = @intCast(if (op_advance >= 2 * max_op_advance) remaining: {827 const remaining_op_advance: u8 = @intCast(if (end or
801 try dlw.writeByte(DW.LNS.advance_pc);828 op_advance >= 2 * max_op_advance)
802 try dlw.writeUleb128(op_advance);829 remaining: {
830 if (op_advance == max_op_advance) {
831 try dlw.writeByte(DW.LNS.const_add_pc);
832 } else if (op_advance != 0) {
833 try dlw.writeByte(DW.LNS.advance_pc);
834 try dlw.writeUleb128(op_advance);
835 } else assert(end);
803 break :remaining 0;836 break :remaining 0;
804 } else if (op_advance >= max_op_advance) remaining: {837 } else if (op_advance >= max_op_advance) remaining: {
805 try dlw.writeByte(DW.LNS.const_add_pc);838 try dlw.writeByte(DW.LNS.const_add_pc);
806 break :remaining op_advance - max_op_advance;839 break :remaining op_advance - max_op_advance;
807 } else op_advance);840 } else op_advance);
808841
809 if (remaining_delta_line == 0 and remaining_op_advance == 0)842 if (remaining_delta_line != 0 or remaining_op_advance != 0) {
810 try dlw.writeByte(DW.LNS.copy)843 assert(!end);
811 else
812 try dlw.writeByte(@intCast((remaining_delta_line - header.line_base) +844 try dlw.writeByte(@intCast((remaining_delta_line - header.line_base) +
813 (header.line_range * remaining_op_advance) + header.opcode_base));845 (header.line_range * remaining_op_advance) + header.opcode_base));
846 } else if (end) {
847 try dlw.writeByte(DW.LNS.extended_op);
848 try dlw.writeUleb128(1);
849 try dlw.writeByte(DW.LNE.end_sequence);
850 } else try dlw.writeByte(DW.LNS.copy);
814 }851 }
815852
816 pub fn setColumn(debug: *Debug, column: u32) link.Error!void {853 pub fn setColumn(debug: *Debug, column: u32) link.Error!void {
...@@ -1398,7 +1435,7 @@ pub fn init(lf: *link.File, format: DW.Format) Dwarf {...@@ -1398,7 +1435,7 @@ pub fn init(lf: *link.File, format: DW.Format) Dwarf {
1398pub fn deinit(dwarf: *Dwarf) void {1435pub fn deinit(dwarf: *Dwarf) void {
1399 const gpa = dwarf.lf.comp.gpa;1436 const gpa = dwarf.lf.comp.gpa;
1400 dwarf.const_pool.deinit(gpa);1437 dwarf.const_pool.deinit(gpa);
1401 for (dwarf.units.values()) |*unit| unit.files.deinit(gpa);1438 for (dwarf.units.values()) |*unit| unit.deinit(gpa);
1402 dwarf.units.deinit(gpa);1439 dwarf.units.deinit(gpa);
1403 dwarf.values.deinit(gpa);1440 dwarf.values.deinit(gpa);
1404 dwarf.globals.deinit(gpa);1441 dwarf.globals.deinit(gpa);
...@@ -1414,18 +1451,24 @@ pub fn initUnits(dwarf: *Dwarf, zcu: *Zcu) std.mem.Allocator.Error!void {...@@ -1414,18 +1451,24 @@ pub fn initUnits(dwarf: *Dwarf, zcu: *Zcu) std.mem.Allocator.Error!void {
1414 const unit_gop = dwarf.units.getOrPutAssumeCapacity(mod);1451 const unit_gop = dwarf.units.getOrPutAssumeCapacity(mod);
1415 assert(!unit_gop.found_existing);1452 assert(!unit_gop.found_existing);
1416 unit_gop.value_ptr.* = .{1453 unit_gop.value_ptr.* = .{
1454 .dirs = .empty,
1417 .files = .empty,1455 .files = .empty,
1418 .files_changed = true,
1419 .frame_ni = .none,1456 .frame_ni = .none,
1420 .cie_ni = .none,1457 .cie_ni = .none,
1421 .debug_info_ni = .none,1458 .debug_info_ni = .none,
1422 .debug_info_header_ni = .none,1459 .debug_info_header_ni = .none,
1423 .debug_line_ni = .none,1460 .debug_line_ni = .none,
1424 .debug_line_header_ni = .none,1461 .debug_line_header_ni = .none,
1462 .debug_line_header_changed = true,
1425 .debug_rnglists_ni = .none,1463 .debug_rnglists_ni = .none,
1426 .debug_rnglists_offset = undefined,1464 .debug_rnglists_offset = undefined,
1427 };1465 };
1428 assert(try unit_gop.value_ptr.getFile(zcu.gpa, root_zfi) == .root);1466 const root_di, const root_fi = try unit_gop.value_ptr.getFile(
1467 zcu.gpa,
1468 @fromBackingInt(@intCast(unit_gop.index)),
1469 root_zfi,
1470 );
1471 assert(root_di == .root and root_fi == .root);
1429 };1472 };
1430}1473}
14311474
src/link/Elf2.zig+1-1
...@@ -7205,7 +7205,7 @@ fn zcuFilesReadyInner(elf: *Elf, zcu: *Zcu) Error!void {...@@ -7205,7 +7205,7 @@ fn zcuFilesReadyInner(elf: *Elf, zcu: *Zcu) Error!void {
7205fn flushFiles(elf: *Elf) Error!void {7205fn flushFiles(elf: *Elf) Error!void {
7206 const gpa = elf.base.comp.gpa;7206 const gpa = elf.base.comp.gpa;
7207 if (elf.shndx.debug_line != .UNDEF) for (elf.dwarf.units.keys(), elf.dwarf.units.values()) |mod, *unit| {7207 if (elf.shndx.debug_line != .UNDEF) for (elf.dwarf.units.keys(), elf.dwarf.units.values()) |mod, *unit| {
7208 if (!unit.cleanFilesChanged()) continue;7208 if (!unit.cleanDebugLineHeaderChanged()) continue;
7209 const debug_line_header_ni = unit.debug_line_header_ni.unwrap().?;7209 const debug_line_header_ni = unit.debug_line_header_ni.unwrap().?;
7210 try debug_line_header_ni.moved(gpa, &elf.mf);7210 try debug_line_header_ni.moved(gpa, &elf.mf);
7211 try debug_line_header_ni.nextMoved(gpa, &elf.mf);7211 try debug_line_header_ni.nextMoved(gpa, &elf.mf);