authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2022-11-09 16:53:33+01:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2022-11-09 18:35:06+01:00
logdf09d9c14a22098709bd8816e622e6dd785ac954
tree3ab43f2421eef00e709a33d27debde04a8f19285
parent02852098eebda52ce6373d0440cec4965e6d4478

x86_64: add DWARF encoding for vector registers

Clean up how we handle emitting of DWARF debug info for `x86_64` codegen.

2 files changed, 134 insertions(+), 87 deletions(-)

src/arch/x86_64/CodeGen.zig+73-65
......@@ -3797,64 +3797,68 @@ fn airArg(self: *Self, inst: Air.Inst.Index) !void {
37973797 const ty = self.air.typeOfIndex(inst);
37983798 const mcv = self.args[arg_index];
37993799 const name = self.mod_fn.getParamName(self.bin_file.options.module.?, arg_index);
3800 const name_with_null = name.ptr[0 .. name.len + 1];
38013800
38023801 if (self.liveness.isUnused(inst))
38033802 return self.finishAirBookkeeping();
38043803
3805 const dst_mcv: MCValue = blk: {
3806 switch (mcv) {
3807 .register => |reg| {
3808 self.register_manager.getRegAssumeFree(reg.to64(), inst);
3809 switch (self.debug_output) {
3810 .dwarf => |dw| {
3811 const dbg_info = &dw.dbg_info;
3812 try dbg_info.ensureUnusedCapacity(3);
3813 dbg_info.appendAssumeCapacity(@enumToInt(link.File.Dwarf.AbbrevKind.parameter));
3814 dbg_info.appendSliceAssumeCapacity(&[2]u8{ // DW.AT.location, DW.FORM.exprloc
3815 1, // ULEB128 dwarf expression length
3816 reg.dwarfLocOp(),
3817 });
3818 try dbg_info.ensureUnusedCapacity(5 + name_with_null.len);
3819 try self.addDbgInfoTypeReloc(ty); // DW.AT.type, DW.FORM.ref4
3820 dbg_info.appendSliceAssumeCapacity(name_with_null); // DW.AT.name, DW.FORM.string
3821 },
3822 .plan9 => {},
3823 .none => {},
3824 }
3825 break :blk mcv;
3826 },
3827 .stack_offset => |off| {
3828 const offset = @intCast(i32, self.max_end_stack) - off + 16;
3829 switch (self.debug_output) {
3830 .dwarf => |dw| {
3831 const dbg_info = &dw.dbg_info;
3832 try dbg_info.ensureUnusedCapacity(8);
3833 dbg_info.appendAssumeCapacity(@enumToInt(link.File.Dwarf.AbbrevKind.parameter));
3834 const fixup = dbg_info.items.len;
3835 dbg_info.appendSliceAssumeCapacity(&[2]u8{ // DW.AT.location, DW.FORM.exprloc
3836 1, // we will backpatch it after we encode the displacement in LEB128
3837 DW.OP.breg6, // .rbp TODO handle -fomit-frame-pointer
3838 });
3839 leb128.writeILEB128(dbg_info.writer(), offset) catch unreachable;
3840 dbg_info.items[fixup] += @intCast(u8, dbg_info.items.len - fixup - 2);
3841 try dbg_info.ensureUnusedCapacity(5 + name_with_null.len);
3842 try self.addDbgInfoTypeReloc(ty); // DW.AT.type, DW.FORM.ref4
3843 dbg_info.appendSliceAssumeCapacity(name_with_null); // DW.AT.name, DW.FORM.string
3844
3845 },
3846 .plan9 => {},
3847 .none => {},
3848 }
3849 break :blk MCValue{ .stack_offset = -offset };
3850 },
3851 else => return self.fail("TODO implement arg for {}", .{mcv}),
3852 }
3804 const dst_mcv: MCValue = switch (mcv) {
3805 .register => |reg| blk: {
3806 self.register_manager.getRegAssumeFree(reg.to64(), inst);
3807 break :blk MCValue{ .register = reg };
3808 },
3809 .stack_offset => |off| blk: {
3810 const offset = @intCast(i32, self.max_end_stack) - off + 16;
3811 break :blk MCValue{ .stack_offset = -offset };
3812 },
3813 else => return self.fail("TODO implement arg for {}", .{mcv}),
38533814 };
3815 try self.genArgDbgInfo(ty, name, dst_mcv);
38543816
38553817 return self.finishAir(inst, dst_mcv, .{ .none, .none, .none });
38563818}
38573819
3820fn genArgDbgInfo(self: Self, ty: Type, name: [:0]const u8, mcv: MCValue) !void {
3821 const name_with_null = name.ptr[0 .. name.len + 1];
3822 switch (self.debug_output) {
3823 .dwarf => |dw| {
3824 const dbg_info = &dw.dbg_info;
3825 switch (mcv) {
3826 .register => |reg| {
3827 try dbg_info.ensureUnusedCapacity(3);
3828 dbg_info.appendAssumeCapacity(@enumToInt(link.File.Dwarf.AbbrevKind.parameter));
3829 dbg_info.appendSliceAssumeCapacity(&[2]u8{ // DW.AT.location, DW.FORM.exprloc
3830 1, // ULEB128 dwarf expression length
3831 reg.dwarfLocOp(),
3832 });
3833 try dbg_info.ensureUnusedCapacity(5 + name_with_null.len);
3834 try self.addDbgInfoTypeReloc(ty); // DW.AT.type, DW.FORM.ref4
3835 dbg_info.appendSliceAssumeCapacity(name_with_null); // DW.AT.name, DW.FORM.string
3836 },
3837
3838 .stack_offset => |off| {
3839 try dbg_info.ensureUnusedCapacity(8);
3840 dbg_info.appendAssumeCapacity(@enumToInt(link.File.Dwarf.AbbrevKind.parameter));
3841 const fixup = dbg_info.items.len;
3842 dbg_info.appendSliceAssumeCapacity(&[2]u8{ // DW.AT.location, DW.FORM.exprloc
3843 1, // we will backpatch it after we encode the displacement in LEB128
3844 Register.rbp.dwarfLocOpDeref(), // TODO handle -fomit-frame-pointer
3845 });
3846 leb128.writeILEB128(dbg_info.writer(), -off) catch unreachable;
3847 dbg_info.items[fixup] += @intCast(u8, dbg_info.items.len - fixup - 2);
3848 try dbg_info.ensureUnusedCapacity(5 + name_with_null.len);
3849 try self.addDbgInfoTypeReloc(ty); // DW.AT.type, DW.FORM.ref4
3850 dbg_info.appendSliceAssumeCapacity(name_with_null); // DW.AT.name, DW.FORM.string
3851
3852 },
3853
3854 else => unreachable, // not a valid function parameter
3855 }
3856 },
3857 .plan9 => {},
3858 .none => {},
3859 }
3860}
3861
38583862fn airBreakpoint(self: *Self) !void {
38593863 _ = try self.addInst(.{
38603864 .tag = .interrupt,
......@@ -4424,7 +4428,7 @@ fn airDbgVar(self: *Self, inst: Air.Inst.Index) !void {
44244428}
44254429
44264430fn genVarDbgInfo(
4427 self: *Self,
4431 self: Self,
44284432 tag: Air.Inst.Tag,
44294433 ty: Type,
44304434 mcv: MCValue,
......@@ -4445,17 +4449,23 @@ fn genVarDbgInfo(
44454449 reg.dwarfLocOp(),
44464450 });
44474451 },
4448 .ptr_stack_offset, .stack_offset => |off| {
4452
4453 .ptr_stack_offset,
4454 .stack_offset,
4455 => |off| {
44494456 try dbg_info.ensureUnusedCapacity(7);
44504457 const fixup = dbg_info.items.len;
44514458 dbg_info.appendSliceAssumeCapacity(&[2]u8{ // DW.AT.location, DW.FORM.exprloc
44524459 1, // we will backpatch it after we encode the displacement in LEB128
4453 DW.OP.breg6, // .rbp TODO handle -fomit-frame-pointer
4460 Register.rbp.dwarfLocOpDeref(), // TODO handle -fomit-frame-pointer
44544461 });
44554462 leb128.writeILEB128(dbg_info.writer(), -off) catch unreachable;
44564463 dbg_info.items[fixup] += @intCast(u8, dbg_info.items.len - fixup - 2);
44574464 },
4458 .memory, .linker_load => {
4465
4466 .memory,
4467 .linker_load,
4468 => {
44594469 const ptr_width = @intCast(u8, @divExact(self.target.cpu.arch.ptrBitWidth(), 8));
44604470 const is_ptr = switch (tag) {
44614471 .dbg_var_ptr => true,
......@@ -4494,27 +4504,23 @@ fn genVarDbgInfo(
44944504 else => {},
44954505 }
44964506 },
4507
44974508 .immediate => |x| {
4498 const signedness: std.builtin.Signedness = blk: {
4499 if (ty.zigTypeTag() != .Int) break :blk .unsigned;
4500 break :blk ty.intInfo(self.target.*).signedness;
4501 };
45024509 try dbg_info.ensureUnusedCapacity(2);
45034510 const fixup = dbg_info.items.len;
45044511 dbg_info.appendSliceAssumeCapacity(&[2]u8{ // DW.AT.location, DW.FORM.exprloc
45054512 1,
4506 switch (signedness) {
4507 .signed => DW.OP.consts,
4508 .unsigned => DW.OP.constu,
4509 },
4513 if (ty.isSignedInt()) DW.OP.consts else DW.OP.constu,
45104514 });
4511 switch (signedness) {
4512 .signed => try leb128.writeILEB128(dbg_info.writer(), @bitCast(i64, x)),
4513 .unsigned => try leb128.writeULEB128(dbg_info.writer(), x),
4515 if (ty.isSignedInt()) {
4516 try leb128.writeILEB128(dbg_info.writer(), @bitCast(i64, x));
4517 } else {
4518 try leb128.writeULEB128(dbg_info.writer(), x);
45144519 }
45154520 try dbg_info.append(DW.OP.stack_value);
45164521 dbg_info.items[fixup] += @intCast(u8, dbg_info.items.len - fixup - 2);
45174522 },
4523
45184524 .undef => {
45194525 // DW.AT.location, DW.FORM.exprloc
45204526 // uleb128(exprloc_len)
......@@ -4530,12 +4536,14 @@ fn genVarDbgInfo(
45304536 dbg_info.appendSliceAssumeCapacity(implicit_value_len.items);
45314537 dbg_info.appendNTimesAssumeCapacity(0xaa, abi_size);
45324538 },
4539
45334540 .none => {
45344541 try dbg_info.ensureUnusedCapacity(3);
45354542 dbg_info.appendSliceAssumeCapacity(&[3]u8{ // DW.AT.location, DW.FORM.exprloc
45364543 2, DW.OP.lit0, DW.OP.stack_value,
45374544 });
45384545 },
4546
45394547 else => {
45404548 try dbg_info.ensureUnusedCapacity(2);
45414549 dbg_info.appendSliceAssumeCapacity(&[2]u8{ // DW.AT.location, DW.FORM.exprloc
......@@ -4556,7 +4564,7 @@ fn genVarDbgInfo(
45564564
45574565/// Adds a Type to the .debug_info at the current position. The bytes will be populated later,
45584566/// after codegen for this symbol is done.
4559fn addDbgInfoTypeReloc(self: *Self, ty: Type) !void {
4567fn addDbgInfoTypeReloc(self: Self, ty: Type) !void {
45604568 switch (self.debug_output) {
45614569 .dwarf => |dw| {
45624570 const dbg_info = &dw.dbg_info;
src/arch/x86_64/bits.zig+61-22
......@@ -135,8 +135,6 @@ pub const Condition = enum(u5) {
135135 }
136136};
137137
138// zig fmt: off
139
140138/// Definitions of all of the general purpose x64 registers. The order is semantically meaningful.
141139/// The registers are defined such that IDs go in descending order of 64-bit,
142140/// 32-bit, 16-bit, and then 8-bit, and each set contains exactly sixteen
......@@ -152,6 +150,7 @@ pub const Condition = enum(u5) {
152150/// The ID can be easily determined by figuring out what range the register is
153151/// in, and then subtracting the base.
154152pub const Register = enum(u7) {
153 // zig fmt: off
155154 // 0 through 15, 64-bit registers. 8-15 are extended.
156155 // id is just the int value.
157156 rax, rcx, rdx, rbx, rsp, rbp, rsi, rdi,
......@@ -184,6 +183,7 @@ pub const Register = enum(u7) {
184183
185184 // Pseudo-value for MIR instructions.
186185 none,
186 // zig fmt: on
187187
188188 pub fn id(self: Register) u7 {
189189 return switch (@enumToInt(self)) {
......@@ -192,7 +192,7 @@ pub const Register = enum(u7) {
192192 else => unreachable,
193193 };
194194 }
195
195
196196 /// Returns the bit-width of the register.
197197 pub fn size(self: Register) u9 {
198198 return switch (@enumToInt(self)) {
......@@ -258,27 +258,66 @@ pub const Register = enum(u7) {
258258 }
259259
260260 pub fn dwarfLocOp(self: Register) u8 {
261 return switch (self.to64()) {
262 .rax => DW.OP.reg0,
263 .rdx => DW.OP.reg1,
264 .rcx => DW.OP.reg2,
265 .rbx => DW.OP.reg3,
266 .rsi => DW.OP.reg4,
267 .rdi => DW.OP.reg5,
268 .rbp => DW.OP.reg6,
269 .rsp => DW.OP.reg7,
270
271 .r8 => DW.OP.reg8,
272 .r9 => DW.OP.reg9,
273 .r10 => DW.OP.reg10,
274 .r11 => DW.OP.reg11,
275 .r12 => DW.OP.reg12,
276 .r13 => DW.OP.reg13,
277 .r14 => DW.OP.reg14,
278 .r15 => DW.OP.reg15,
261 switch (@enumToInt(self)) {
262 0...63 => return switch (self.to64()) {
263 .rax => DW.OP.reg0,
264 .rdx => DW.OP.reg1,
265 .rcx => DW.OP.reg2,
266 .rbx => DW.OP.reg3,
267 .rsi => DW.OP.reg4,
268 .rdi => DW.OP.reg5,
269 .rbp => DW.OP.reg6,
270 .rsp => DW.OP.reg7,
271
272 .r8 => DW.OP.reg8,
273 .r9 => DW.OP.reg9,
274 .r10 => DW.OP.reg10,
275 .r11 => DW.OP.reg11,
276 .r12 => DW.OP.reg12,
277 .r13 => DW.OP.reg13,
278 .r14 => DW.OP.reg14,
279 .r15 => DW.OP.reg15,
280
281 else => unreachable,
282 },
283
284 64...79 => return @as(u8, self.enc()) + DW.OP.reg17,
279285
280286 else => unreachable,
281 };
287 }
288 }
289
290 /// DWARF encodings that push a value onto the DWARF stack that is either
291 /// the contents of a register or the result of adding the contents a given
292 /// register to a given signed offset.
293 pub fn dwarfLocOpDeref(self: Register) u8 {
294 switch (@enumToInt(self)) {
295 0...63 => return switch (self.to64()) {
296 .rax => DW.OP.breg0,
297 .rdx => DW.OP.breg1,
298 .rcx => DW.OP.breg2,
299 .rbx => DW.OP.breg3,
300 .rsi => DW.OP.breg4,
301 .rdi => DW.OP.breg5,
302 .rbp => DW.OP.breg6,
303 .rsp => DW.OP.fbreg,
304
305 .r8 => DW.OP.breg8,
306 .r9 => DW.OP.breg9,
307 .r10 => DW.OP.breg10,
308 .r11 => DW.OP.breg11,
309 .r12 => DW.OP.breg12,
310 .r13 => DW.OP.breg13,
311 .r14 => DW.OP.breg14,
312 .r15 => DW.OP.breg15,
313
314 else => unreachable,
315 },
316
317 64...79 => return @as(u8, self.enc()) + DW.OP.breg17,
318
319 else => unreachable,
320 }
282321 }
283322};
284323