diff options
| author | Jakub Konka <kubkon@jakubkonka.com> | 2022-11-09 16:53:33 +0100 |
|---|---|---|
| committer | Jakub Konka <kubkon@jakubkonka.com> | 2022-11-09 18:35:06 +0100 |
| commit | df09d9c14a22098709bd8816e622e6dd785ac954 (patch) | |
| tree | 3ab43f2421eef00e709a33d27debde04a8f19285 /src | |
| parent | 02852098eebda52ce6373d0440cec4965e6d4478 (diff) | |
| download | zig-df09d9c14a22098709bd8816e622e6dd785ac954.tar.gz zig-df09d9c14a22098709bd8816e622e6dd785ac954.zip | |
x86_64: add DWARF encoding for vector registers
Clean up how we handle emitting of DWARF debug info for `x86_64`
codegen.
Diffstat (limited to 'src')
| -rw-r--r-- | src/arch/x86_64/CodeGen.zig | 138 | ||||
| -rw-r--r-- | src/arch/x86_64/bits.zig | 83 |
2 files changed, 134 insertions, 87 deletions
diff --git a/src/arch/x86_64/CodeGen.zig b/src/arch/x86_64/CodeGen.zig index 7b9ef863ae..2bafbfb3d7 100644 --- a/src/arch/x86_64/CodeGen.zig +++ b/src/arch/x86_64/CodeGen.zig @@ -3797,64 +3797,68 @@ fn airArg(self: *Self, inst: Air.Inst.Index) !void { const ty = self.air.typeOfIndex(inst); const mcv = self.args[arg_index]; const name = self.mod_fn.getParamName(self.bin_file.options.module.?, arg_index); - const name_with_null = name.ptr[0 .. name.len + 1]; if (self.liveness.isUnused(inst)) return self.finishAirBookkeeping(); - const dst_mcv: MCValue = blk: { - switch (mcv) { - .register => |reg| { - self.register_manager.getRegAssumeFree(reg.to64(), inst); - switch (self.debug_output) { - .dwarf => |dw| { - const dbg_info = &dw.dbg_info; - try dbg_info.ensureUnusedCapacity(3); - dbg_info.appendAssumeCapacity(@enumToInt(link.File.Dwarf.AbbrevKind.parameter)); - dbg_info.appendSliceAssumeCapacity(&[2]u8{ // DW.AT.location, DW.FORM.exprloc - 1, // ULEB128 dwarf expression length - reg.dwarfLocOp(), - }); - try dbg_info.ensureUnusedCapacity(5 + name_with_null.len); - try self.addDbgInfoTypeReloc(ty); // DW.AT.type, DW.FORM.ref4 - dbg_info.appendSliceAssumeCapacity(name_with_null); // DW.AT.name, DW.FORM.string - }, - .plan9 => {}, - .none => {}, - } - break :blk mcv; - }, - .stack_offset => |off| { - const offset = @intCast(i32, self.max_end_stack) - off + 16; - switch (self.debug_output) { - .dwarf => |dw| { - const dbg_info = &dw.dbg_info; - try dbg_info.ensureUnusedCapacity(8); - dbg_info.appendAssumeCapacity(@enumToInt(link.File.Dwarf.AbbrevKind.parameter)); - const fixup = dbg_info.items.len; - dbg_info.appendSliceAssumeCapacity(&[2]u8{ // DW.AT.location, DW.FORM.exprloc - 1, // we will backpatch it after we encode the displacement in LEB128 - DW.OP.breg6, // .rbp TODO handle -fomit-frame-pointer - }); - leb128.writeILEB128(dbg_info.writer(), offset) catch unreachable; - dbg_info.items[fixup] += @intCast(u8, dbg_info.items.len - fixup - 2); - try dbg_info.ensureUnusedCapacity(5 + name_with_null.len); - try self.addDbgInfoTypeReloc(ty); // DW.AT.type, DW.FORM.ref4 - dbg_info.appendSliceAssumeCapacity(name_with_null); // DW.AT.name, DW.FORM.string - - }, - .plan9 => {}, - .none => {}, - } - break :blk MCValue{ .stack_offset = -offset }; - }, - else => return self.fail("TODO implement arg for {}", .{mcv}), - } + const dst_mcv: MCValue = switch (mcv) { + .register => |reg| blk: { + self.register_manager.getRegAssumeFree(reg.to64(), inst); + break :blk MCValue{ .register = reg }; + }, + .stack_offset => |off| blk: { + const offset = @intCast(i32, self.max_end_stack) - off + 16; + break :blk MCValue{ .stack_offset = -offset }; + }, + else => return self.fail("TODO implement arg for {}", .{mcv}), }; + try self.genArgDbgInfo(ty, name, dst_mcv); return self.finishAir(inst, dst_mcv, .{ .none, .none, .none }); } +fn genArgDbgInfo(self: Self, ty: Type, name: [:0]const u8, mcv: MCValue) !void { + const name_with_null = name.ptr[0 .. name.len + 1]; + switch (self.debug_output) { + .dwarf => |dw| { + const dbg_info = &dw.dbg_info; + switch (mcv) { + .register => |reg| { + try dbg_info.ensureUnusedCapacity(3); + dbg_info.appendAssumeCapacity(@enumToInt(link.File.Dwarf.AbbrevKind.parameter)); + dbg_info.appendSliceAssumeCapacity(&[2]u8{ // DW.AT.location, DW.FORM.exprloc + 1, // ULEB128 dwarf expression length + reg.dwarfLocOp(), + }); + try dbg_info.ensureUnusedCapacity(5 + name_with_null.len); + try self.addDbgInfoTypeReloc(ty); // DW.AT.type, DW.FORM.ref4 + dbg_info.appendSliceAssumeCapacity(name_with_null); // DW.AT.name, DW.FORM.string + }, + + .stack_offset => |off| { + try dbg_info.ensureUnusedCapacity(8); + dbg_info.appendAssumeCapacity(@enumToInt(link.File.Dwarf.AbbrevKind.parameter)); + const fixup = dbg_info.items.len; + dbg_info.appendSliceAssumeCapacity(&[2]u8{ // DW.AT.location, DW.FORM.exprloc + 1, // we will backpatch it after we encode the displacement in LEB128 + Register.rbp.dwarfLocOpDeref(), // TODO handle -fomit-frame-pointer + }); + leb128.writeILEB128(dbg_info.writer(), -off) catch unreachable; + dbg_info.items[fixup] += @intCast(u8, dbg_info.items.len - fixup - 2); + try dbg_info.ensureUnusedCapacity(5 + name_with_null.len); + try self.addDbgInfoTypeReloc(ty); // DW.AT.type, DW.FORM.ref4 + dbg_info.appendSliceAssumeCapacity(name_with_null); // DW.AT.name, DW.FORM.string + + }, + + else => unreachable, // not a valid function parameter + } + }, + .plan9 => {}, + .none => {}, + } +} + fn airBreakpoint(self: *Self) !void { _ = try self.addInst(.{ .tag = .interrupt, @@ -4424,7 +4428,7 @@ fn airDbgVar(self: *Self, inst: Air.Inst.Index) !void { } fn genVarDbgInfo( - self: *Self, + self: Self, tag: Air.Inst.Tag, ty: Type, mcv: MCValue, @@ -4445,17 +4449,23 @@ fn genVarDbgInfo( reg.dwarfLocOp(), }); }, - .ptr_stack_offset, .stack_offset => |off| { + + .ptr_stack_offset, + .stack_offset, + => |off| { try dbg_info.ensureUnusedCapacity(7); const fixup = dbg_info.items.len; dbg_info.appendSliceAssumeCapacity(&[2]u8{ // DW.AT.location, DW.FORM.exprloc 1, // we will backpatch it after we encode the displacement in LEB128 - DW.OP.breg6, // .rbp TODO handle -fomit-frame-pointer + Register.rbp.dwarfLocOpDeref(), // TODO handle -fomit-frame-pointer }); leb128.writeILEB128(dbg_info.writer(), -off) catch unreachable; dbg_info.items[fixup] += @intCast(u8, dbg_info.items.len - fixup - 2); }, - .memory, .linker_load => { + + .memory, + .linker_load, + => { const ptr_width = @intCast(u8, @divExact(self.target.cpu.arch.ptrBitWidth(), 8)); const is_ptr = switch (tag) { .dbg_var_ptr => true, @@ -4494,27 +4504,23 @@ fn genVarDbgInfo( else => {}, } }, + .immediate => |x| { - const signedness: std.builtin.Signedness = blk: { - if (ty.zigTypeTag() != .Int) break :blk .unsigned; - break :blk ty.intInfo(self.target.*).signedness; - }; try dbg_info.ensureUnusedCapacity(2); const fixup = dbg_info.items.len; dbg_info.appendSliceAssumeCapacity(&[2]u8{ // DW.AT.location, DW.FORM.exprloc 1, - switch (signedness) { - .signed => DW.OP.consts, - .unsigned => DW.OP.constu, - }, + if (ty.isSignedInt()) DW.OP.consts else DW.OP.constu, }); - switch (signedness) { - .signed => try leb128.writeILEB128(dbg_info.writer(), @bitCast(i64, x)), - .unsigned => try leb128.writeULEB128(dbg_info.writer(), x), + if (ty.isSignedInt()) { + try leb128.writeILEB128(dbg_info.writer(), @bitCast(i64, x)); + } else { + try leb128.writeULEB128(dbg_info.writer(), x); } try dbg_info.append(DW.OP.stack_value); dbg_info.items[fixup] += @intCast(u8, dbg_info.items.len - fixup - 2); }, + .undef => { // DW.AT.location, DW.FORM.exprloc // uleb128(exprloc_len) @@ -4530,12 +4536,14 @@ fn genVarDbgInfo( dbg_info.appendSliceAssumeCapacity(implicit_value_len.items); dbg_info.appendNTimesAssumeCapacity(0xaa, abi_size); }, + .none => { try dbg_info.ensureUnusedCapacity(3); dbg_info.appendSliceAssumeCapacity(&[3]u8{ // DW.AT.location, DW.FORM.exprloc 2, DW.OP.lit0, DW.OP.stack_value, }); }, + else => { try dbg_info.ensureUnusedCapacity(2); dbg_info.appendSliceAssumeCapacity(&[2]u8{ // DW.AT.location, DW.FORM.exprloc @@ -4556,7 +4564,7 @@ fn genVarDbgInfo( /// 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 { +fn addDbgInfoTypeReloc(self: Self, ty: Type) !void { switch (self.debug_output) { .dwarf => |dw| { const dbg_info = &dw.dbg_info; diff --git a/src/arch/x86_64/bits.zig b/src/arch/x86_64/bits.zig index a2d523e84c..cc123b96b6 100644 --- a/src/arch/x86_64/bits.zig +++ b/src/arch/x86_64/bits.zig @@ -135,8 +135,6 @@ pub const Condition = enum(u5) { } }; -// zig fmt: off - /// Definitions of all of the general purpose x64 registers. The order is semantically meaningful. /// The registers are defined such that IDs go in descending order of 64-bit, /// 32-bit, 16-bit, and then 8-bit, and each set contains exactly sixteen @@ -152,6 +150,7 @@ pub const Condition = enum(u5) { /// The ID can be easily determined by figuring out what range the register is /// in, and then subtracting the base. pub const Register = enum(u7) { + // zig fmt: off // 0 through 15, 64-bit registers. 8-15 are extended. // id is just the int value. rax, rcx, rdx, rbx, rsp, rbp, rsi, rdi, @@ -184,6 +183,7 @@ pub const Register = enum(u7) { // Pseudo-value for MIR instructions. none, + // zig fmt: on pub fn id(self: Register) u7 { return switch (@enumToInt(self)) { @@ -192,7 +192,7 @@ pub const Register = enum(u7) { else => unreachable, }; } - + /// Returns the bit-width of the register. pub fn size(self: Register) u9 { return switch (@enumToInt(self)) { @@ -258,27 +258,66 @@ pub const Register = enum(u7) { } pub fn dwarfLocOp(self: Register) u8 { - return switch (self.to64()) { - .rax => DW.OP.reg0, - .rdx => DW.OP.reg1, - .rcx => DW.OP.reg2, - .rbx => DW.OP.reg3, - .rsi => DW.OP.reg4, - .rdi => DW.OP.reg5, - .rbp => DW.OP.reg6, - .rsp => DW.OP.reg7, - - .r8 => DW.OP.reg8, - .r9 => DW.OP.reg9, - .r10 => DW.OP.reg10, - .r11 => DW.OP.reg11, - .r12 => DW.OP.reg12, - .r13 => DW.OP.reg13, - .r14 => DW.OP.reg14, - .r15 => DW.OP.reg15, + switch (@enumToInt(self)) { + 0...63 => return switch (self.to64()) { + .rax => DW.OP.reg0, + .rdx => DW.OP.reg1, + .rcx => DW.OP.reg2, + .rbx => DW.OP.reg3, + .rsi => DW.OP.reg4, + .rdi => DW.OP.reg5, + .rbp => DW.OP.reg6, + .rsp => DW.OP.reg7, + + .r8 => DW.OP.reg8, + .r9 => DW.OP.reg9, + .r10 => DW.OP.reg10, + .r11 => DW.OP.reg11, + .r12 => DW.OP.reg12, + .r13 => DW.OP.reg13, + .r14 => DW.OP.reg14, + .r15 => DW.OP.reg15, + + else => unreachable, + }, + + 64...79 => return @as(u8, self.enc()) + DW.OP.reg17, else => unreachable, - }; + } + } + + /// DWARF encodings that push a value onto the DWARF stack that is either + /// the contents of a register or the result of adding the contents a given + /// register to a given signed offset. + pub fn dwarfLocOpDeref(self: Register) u8 { + switch (@enumToInt(self)) { + 0...63 => return switch (self.to64()) { + .rax => DW.OP.breg0, + .rdx => DW.OP.breg1, + .rcx => DW.OP.breg2, + .rbx => DW.OP.breg3, + .rsi => DW.OP.breg4, + .rdi => DW.OP.breg5, + .rbp => DW.OP.breg6, + .rsp => DW.OP.fbreg, + + .r8 => DW.OP.breg8, + .r9 => DW.OP.breg9, + .r10 => DW.OP.breg10, + .r11 => DW.OP.breg11, + .r12 => DW.OP.breg12, + .r13 => DW.OP.breg13, + .r14 => DW.OP.breg14, + .r15 => DW.OP.breg15, + + else => unreachable, + }, + + 64...79 => return @as(u8, self.enc()) + DW.OP.breg17, + + else => unreachable, + } } }; |
