Commit 8282f4271c
Changed files (10)
src-self-hosted
src-self-hosted/codegen/riscv64.zig
@@ -1,4 +1,5 @@
const std = @import("std");
+const DW = std.dwarf;
pub const instructions = struct {
pub const CallBreak = packed struct {
@@ -48,6 +49,10 @@ pub const RawRegister = enum(u8) {
x8, x9, x10, x11, x12, x13, x14, x15,
x16, x17, x18, x19, x20, x21, x22, x23,
x24, x25, x26, x27, x28, x29, x30, x31,
+
+ pub fn dwarfLocOp(reg: RawRegister) u8 {
+ return @enumToInt(reg) + DW.OP_reg0;
+ }
};
pub const Register = enum(u8) {
@@ -83,6 +88,10 @@ pub const Register = enum(u8) {
}
return null;
}
+
+ pub fn dwarfLocOp(reg: Register) u8 {
+ return @enumToInt(reg) + DW.OP_reg0;
+ }
};
// zig fmt: on
src-self-hosted/codegen/x86.zig
@@ -1,3 +1,6 @@
+const std = @import("std");
+const DW = std.dwarf;
+
// zig fmt: off
pub const Register = enum(u8) {
// 0 through 7, 32-bit registers. id is int value
@@ -37,8 +40,84 @@ pub const Register = enum(u8) {
else => null,
};
}
+
+ /// Convert from any register to its 32 bit alias.
+ pub fn to32(self: Register) Register {
+ return @intToEnum(Register, @as(u8, self.id()));
+ }
+
+ /// Convert from any register to its 16 bit alias.
+ pub fn to16(self: Register) Register {
+ return @intToEnum(Register, @as(u8, self.id()) + 8);
+ }
+
+ /// Convert from any register to its 8 bit alias.
+ pub fn to8(self: Register) Register {
+ return @intToEnum(Register, @as(u8, self.id()) + 16);
+ }
+
+
+ pub fn dwarfLocOp(reg: Register) u8 {
+ return switch (reg.to32()) {
+ .eax => DW.OP_reg0,
+ .ecx => DW.OP_reg1,
+ .edx => DW.OP_reg2,
+ .ebx => DW.OP_reg3,
+ .esp => DW.OP_reg4,
+ .ebp => DW.OP_reg5,
+ .esi => DW.OP_reg6,
+ .edi => DW.OP_reg7,
+ else => unreachable,
+ };
+ }
};
// zig fmt: on
pub const callee_preserved_regs = [_]Register{ .eax, .ecx, .edx, .esi, .edi };
+
+// TODO add these to Register enum and corresponding dwarfLocOp
+// // Return Address register. This is stored in `0(%esp, "")` and is not a physical register.
+// RA = (8, "RA"),
+//
+// ST0 = (11, "st0"),
+// ST1 = (12, "st1"),
+// ST2 = (13, "st2"),
+// ST3 = (14, "st3"),
+// ST4 = (15, "st4"),
+// ST5 = (16, "st5"),
+// ST6 = (17, "st6"),
+// ST7 = (18, "st7"),
+//
+// XMM0 = (21, "xmm0"),
+// XMM1 = (22, "xmm1"),
+// XMM2 = (23, "xmm2"),
+// XMM3 = (24, "xmm3"),
+// XMM4 = (25, "xmm4"),
+// XMM5 = (26, "xmm5"),
+// XMM6 = (27, "xmm6"),
+// XMM7 = (28, "xmm7"),
+//
+// MM0 = (29, "mm0"),
+// MM1 = (30, "mm1"),
+// MM2 = (31, "mm2"),
+// MM3 = (32, "mm3"),
+// MM4 = (33, "mm4"),
+// MM5 = (34, "mm5"),
+// MM6 = (35, "mm6"),
+// MM7 = (36, "mm7"),
+//
+// MXCSR = (39, "mxcsr"),
+//
+// ES = (40, "es"),
+// CS = (41, "cs"),
+// SS = (42, "ss"),
+// DS = (43, "ds"),
+// FS = (44, "fs"),
+// GS = (45, "gs"),
+//
+// TR = (48, "tr"),
+// LDTR = (49, "ldtr"),
+//
+// FS_BASE = (93, "fs.base"),
+// GS_BASE = (94, "gs.base"),
src-self-hosted/codegen/x86_64.zig
@@ -1,4 +1,6 @@
+const std = @import("std");
const Type = @import("../Type.zig");
+const DW = std.dwarf;
// zig fmt: off
@@ -101,6 +103,30 @@ pub const Register = enum(u8) {
pub fn to8(self: Register) Register {
return @intToEnum(Register, @as(u8, self.id()) + 48);
}
+
+ 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,
+
+ else => unreachable,
+ };
+ }
};
// zig fmt: on
@@ -109,3 +135,86 @@ pub const Register = enum(u8) {
pub const callee_preserved_regs = [_]Register{ .rax, .rcx, .rdx, .rsi, .rdi, .r8, .r9, .r10, .r11 };
pub const c_abi_int_param_regs = [_]Register{ .rdi, .rsi, .rdx, .rcx, .r8, .r9 };
pub const c_abi_int_return_regs = [_]Register{ .rax, .rdx };
+
+// TODO add these registers to the enum and populate dwarfLocOp
+// // Return Address register. This is stored in `0(%rsp, "")` and is not a physical register.
+// RA = (16, "RA"),
+//
+// XMM0 = (17, "xmm0"),
+// XMM1 = (18, "xmm1"),
+// XMM2 = (19, "xmm2"),
+// XMM3 = (20, "xmm3"),
+// XMM4 = (21, "xmm4"),
+// XMM5 = (22, "xmm5"),
+// XMM6 = (23, "xmm6"),
+// XMM7 = (24, "xmm7"),
+//
+// XMM8 = (25, "xmm8"),
+// XMM9 = (26, "xmm9"),
+// XMM10 = (27, "xmm10"),
+// XMM11 = (28, "xmm11"),
+// XMM12 = (29, "xmm12"),
+// XMM13 = (30, "xmm13"),
+// XMM14 = (31, "xmm14"),
+// XMM15 = (32, "xmm15"),
+//
+// ST0 = (33, "st0"),
+// ST1 = (34, "st1"),
+// ST2 = (35, "st2"),
+// ST3 = (36, "st3"),
+// ST4 = (37, "st4"),
+// ST5 = (38, "st5"),
+// ST6 = (39, "st6"),
+// ST7 = (40, "st7"),
+//
+// MM0 = (41, "mm0"),
+// MM1 = (42, "mm1"),
+// MM2 = (43, "mm2"),
+// MM3 = (44, "mm3"),
+// MM4 = (45, "mm4"),
+// MM5 = (46, "mm5"),
+// MM6 = (47, "mm6"),
+// MM7 = (48, "mm7"),
+//
+// RFLAGS = (49, "rFLAGS"),
+// ES = (50, "es"),
+// CS = (51, "cs"),
+// SS = (52, "ss"),
+// DS = (53, "ds"),
+// FS = (54, "fs"),
+// GS = (55, "gs"),
+//
+// FS_BASE = (58, "fs.base"),
+// GS_BASE = (59, "gs.base"),
+//
+// TR = (62, "tr"),
+// LDTR = (63, "ldtr"),
+// MXCSR = (64, "mxcsr"),
+// FCW = (65, "fcw"),
+// FSW = (66, "fsw"),
+//
+// XMM16 = (67, "xmm16"),
+// XMM17 = (68, "xmm17"),
+// XMM18 = (69, "xmm18"),
+// XMM19 = (70, "xmm19"),
+// XMM20 = (71, "xmm20"),
+// XMM21 = (72, "xmm21"),
+// XMM22 = (73, "xmm22"),
+// XMM23 = (74, "xmm23"),
+// XMM24 = (75, "xmm24"),
+// XMM25 = (76, "xmm25"),
+// XMM26 = (77, "xmm26"),
+// XMM27 = (78, "xmm27"),
+// XMM28 = (79, "xmm28"),
+// XMM29 = (80, "xmm29"),
+// XMM30 = (81, "xmm30"),
+// XMM31 = (82, "xmm31"),
+//
+// K0 = (118, "k0"),
+// K1 = (119, "k1"),
+// K2 = (120, "k2"),
+// K3 = (121, "k3"),
+// K4 = (122, "k4"),
+// K5 = (123, "k5"),
+// K6 = (124, "k6"),
+// K7 = (125, "k7"),
src-self-hosted/codegen.zig
@@ -51,6 +51,7 @@ pub fn generateSymbol(
code: *std.ArrayList(u8),
dbg_line: *std.ArrayList(u8),
dbg_info: *std.ArrayList(u8),
+ dbg_info_type_relocs: *link.File.Elf.DbgInfoTypeRelocsTable,
) GenerateSymbolError!Result {
const tracy = trace(@src());
defer tracy.end();
@@ -58,57 +59,57 @@ pub fn generateSymbol(
switch (typed_value.ty.zigTypeTag()) {
.Fn => {
switch (bin_file.base.options.target.cpu.arch) {
- //.arm => return Function(.arm).generateSymbol(bin_file, src, typed_value, code, dbg_line, dbg_info),
- //.armeb => return Function(.armeb).generateSymbol(bin_file, src, typed_value, code, dbg_line, dbg_info),
- //.aarch64 => return Function(.aarch64).generateSymbol(bin_file, src, typed_value, code, dbg_line, dbg_info),
- //.aarch64_be => return Function(.aarch64_be).generateSymbol(bin_file, src, typed_value, code, dbg_line, dbg_info),
- //.aarch64_32 => return Function(.aarch64_32).generateSymbol(bin_file, src, typed_value, code, dbg_line, dbg_info),
- //.arc => return Function(.arc).generateSymbol(bin_file, src, typed_value, code, dbg_line, dbg_info),
- //.avr => return Function(.avr).generateSymbol(bin_file, src, typed_value, code, dbg_line, dbg_info),
- //.bpfel => return Function(.bpfel).generateSymbol(bin_file, src, typed_value, code, dbg_line, dbg_info),
- //.bpfeb => return Function(.bpfeb).generateSymbol(bin_file, src, typed_value, code, dbg_line, dbg_info),
- //.hexagon => return Function(.hexagon).generateSymbol(bin_file, src, typed_value, code, dbg_line, dbg_info),
- //.mips => return Function(.mips).generateSymbol(bin_file, src, typed_value, code, dbg_line, dbg_info),
- //.mipsel => return Function(.mipsel).generateSymbol(bin_file, src, typed_value, code, dbg_line, dbg_info),
- //.mips64 => return Function(.mips64).generateSymbol(bin_file, src, typed_value, code, dbg_line, dbg_info),
- //.mips64el => return Function(.mips64el).generateSymbol(bin_file, src, typed_value, code, dbg_line, dbg_info),
- //.msp430 => return Function(.msp430).generateSymbol(bin_file, src, typed_value, code, dbg_line, dbg_info),
- //.powerpc => return Function(.powerpc).generateSymbol(bin_file, src, typed_value, code, dbg_line, dbg_info),
- //.powerpc64 => return Function(.powerpc64).generateSymbol(bin_file, src, typed_value, code, dbg_line, dbg_info),
- //.powerpc64le => return Function(.powerpc64le).generateSymbol(bin_file, src, typed_value, code, dbg_line, dbg_info),
- //.r600 => return Function(.r600).generateSymbol(bin_file, src, typed_value, code, dbg_line, dbg_info),
- //.amdgcn => return Function(.amdgcn).generateSymbol(bin_file, src, typed_value, code, dbg_line, dbg_info),
- //.riscv32 => return Function(.riscv32).generateSymbol(bin_file, src, typed_value, code, dbg_line, dbg_info),
- .riscv64 => return Function(.riscv64).generateSymbol(bin_file, src, typed_value, code, dbg_line, dbg_info),
- //.sparc => return Function(.sparc).generateSymbol(bin_file, src, typed_value, code, dbg_line, dbg_info),
- //.sparcv9 => return Function(.sparcv9).generateSymbol(bin_file, src, typed_value, code, dbg_line, dbg_info),
- //.sparcel => return Function(.sparcel).generateSymbol(bin_file, src, typed_value, code, dbg_line, dbg_info),
- //.s390x => return Function(.s390x).generateSymbol(bin_file, src, typed_value, code, dbg_line, dbg_info),
- //.tce => return Function(.tce).generateSymbol(bin_file, src, typed_value, code, dbg_line, dbg_info),
- //.tcele => return Function(.tcele).generateSymbol(bin_file, src, typed_value, code, dbg_line, dbg_info),
- //.thumb => return Function(.thumb).generateSymbol(bin_file, src, typed_value, code, dbg_line, dbg_info),
- //.thumbeb => return Function(.thumbeb).generateSymbol(bin_file, src, typed_value, code, dbg_line, dbg_info),
- //.i386 => return Function(.i386).generateSymbol(bin_file, src, typed_value, code, dbg_line, dbg_info),
- .x86_64 => return Function(.x86_64).generateSymbol(bin_file, src, typed_value, code, dbg_line, dbg_info),
- //.xcore => return Function(.xcore).generateSymbol(bin_file, src, typed_value, code, dbg_line, dbg_info),
- //.nvptx => return Function(.nvptx).generateSymbol(bin_file, src, typed_value, code, dbg_line, dbg_info),
- //.nvptx64 => return Function(.nvptx64).generateSymbol(bin_file, src, typed_value, code, dbg_line, dbg_info),
- //.le32 => return Function(.le32).generateSymbol(bin_file, src, typed_value, code, dbg_line, dbg_info),
- //.le64 => return Function(.le64).generateSymbol(bin_file, src, typed_value, code, dbg_line, dbg_info),
- //.amdil => return Function(.amdil).generateSymbol(bin_file, src, typed_value, code, dbg_line, dbg_info),
- //.amdil64 => return Function(.amdil64).generateSymbol(bin_file, src, typed_value, code, dbg_line, dbg_info),
- //.hsail => return Function(.hsail).generateSymbol(bin_file, src, typed_value, code, dbg_line, dbg_info),
- //.hsail64 => return Function(.hsail64).generateSymbol(bin_file, src, typed_value, code, dbg_line, dbg_info),
- //.spir => return Function(.spir).generateSymbol(bin_file, src, typed_value, code, dbg_line, dbg_info),
- //.spir64 => return Function(.spir64).generateSymbol(bin_file, src, typed_value, code, dbg_line, dbg_info),
- //.kalimba => return Function(.kalimba).generateSymbol(bin_file, src, typed_value, code, dbg_line, dbg_info),
- //.shave => return Function(.shave).generateSymbol(bin_file, src, typed_value, code, dbg_line, dbg_info),
- //.lanai => return Function(.lanai).generateSymbol(bin_file, src, typed_value, code, dbg_line, dbg_info),
- //.wasm32 => return Function(.wasm32).generateSymbol(bin_file, src, typed_value, code, dbg_line, dbg_info),
- //.wasm64 => return Function(.wasm64).generateSymbol(bin_file, src, typed_value, code, dbg_line, dbg_info),
- //.renderscript32 => return Function(.renderscript32).generateSymbol(bin_file, src, typed_value, code, dbg_line, dbg_info),
- //.renderscript64 => return Function(.renderscript64).generateSymbol(bin_file, src, typed_value, code, dbg_line, dbg_info),
- //.ve => return Function(.ve).generateSymbol(bin_file, src, typed_value, code, dbg_line, dbg_info),
+ //.arm => return Function(.arm).generateSymbol(bin_file, src, typed_value, code, dbg_line, dbg_info, dbg_info_type_relocs),
+ //.armeb => return Function(.armeb).generateSymbol(bin_file, src, typed_value, code, dbg_line, dbg_info, dbg_info_type_relocs),
+ //.aarch64 => return Function(.aarch64).generateSymbol(bin_file, src, typed_value, code, dbg_line, dbg_info, dbg_info_type_relocs),
+ //.aarch64_be => return Function(.aarch64_be).generateSymbol(bin_file, src, typed_value, code, dbg_line, dbg_info, dbg_info_type_relocs),
+ //.aarch64_32 => return Function(.aarch64_32).generateSymbol(bin_file, src, typed_value, code, dbg_line, dbg_info, dbg_info_type_relocs),
+ //.arc => return Function(.arc).generateSymbol(bin_file, src, typed_value, code, dbg_line, dbg_info, dbg_info_type_relocs),
+ //.avr => return Function(.avr).generateSymbol(bin_file, src, typed_value, code, dbg_line, dbg_info, dbg_info_type_relocs),
+ //.bpfel => return Function(.bpfel).generateSymbol(bin_file, src, typed_value, code, dbg_line, dbg_info, dbg_info_type_relocs),
+ //.bpfeb => return Function(.bpfeb).generateSymbol(bin_file, src, typed_value, code, dbg_line, dbg_info, dbg_info_type_relocs),
+ //.hexagon => return Function(.hexagon).generateSymbol(bin_file, src, typed_value, code, dbg_line, dbg_info, dbg_info_type_relocs),
+ //.mips => return Function(.mips).generateSymbol(bin_file, src, typed_value, code, dbg_line, dbg_info, dbg_info_type_relocs),
+ //.mipsel => return Function(.mipsel).generateSymbol(bin_file, src, typed_value, code, dbg_line, dbg_info, dbg_info_type_relocs),
+ //.mips64 => return Function(.mips64).generateSymbol(bin_file, src, typed_value, code, dbg_line, dbg_info, dbg_info_type_relocs),
+ //.mips64el => return Function(.mips64el).generateSymbol(bin_file, src, typed_value, code, dbg_line, dbg_info, dbg_info_type_relocs),
+ //.msp430 => return Function(.msp430).generateSymbol(bin_file, src, typed_value, code, dbg_line, dbg_info, dbg_info_type_relocs),
+ //.powerpc => return Function(.powerpc).generateSymbol(bin_file, src, typed_value, code, dbg_line, dbg_info, dbg_info_type_relocs),
+ //.powerpc64 => return Function(.powerpc64).generateSymbol(bin_file, src, typed_value, code, dbg_line, dbg_info, dbg_info_type_relocs),
+ //.powerpc64le => return Function(.powerpc64le).generateSymbol(bin_file, src, typed_value, code, dbg_line, dbg_info, dbg_info_type_relocs),
+ //.r600 => return Function(.r600).generateSymbol(bin_file, src, typed_value, code, dbg_line, dbg_info, dbg_info_type_relocs),
+ //.amdgcn => return Function(.amdgcn).generateSymbol(bin_file, src, typed_value, code, dbg_line, dbg_info, dbg_info_type_relocs),
+ //.riscv32 => return Function(.riscv32).generateSymbol(bin_file, src, typed_value, code, dbg_line, dbg_info, dbg_info_type_relocs),
+ .riscv64 => return Function(.riscv64).generateSymbol(bin_file, src, typed_value, code, dbg_line, dbg_info, dbg_info_type_relocs),
+ //.sparc => return Function(.sparc).generateSymbol(bin_file, src, typed_value, code, dbg_line, dbg_info, dbg_info_type_relocs),
+ //.sparcv9 => return Function(.sparcv9).generateSymbol(bin_file, src, typed_value, code, dbg_line, dbg_info, dbg_info_type_relocs),
+ //.sparcel => return Function(.sparcel).generateSymbol(bin_file, src, typed_value, code, dbg_line, dbg_info, dbg_info_type_relocs),
+ //.s390x => return Function(.s390x).generateSymbol(bin_file, src, typed_value, code, dbg_line, dbg_info, dbg_info_type_relocs),
+ //.tce => return Function(.tce).generateSymbol(bin_file, src, typed_value, code, dbg_line, dbg_info, dbg_info_type_relocs),
+ //.tcele => return Function(.tcele).generateSymbol(bin_file, src, typed_value, code, dbg_line, dbg_info, dbg_info_type_relocs),
+ //.thumb => return Function(.thumb).generateSymbol(bin_file, src, typed_value, code, dbg_line, dbg_info, dbg_info_type_relocs),
+ //.thumbeb => return Function(.thumbeb).generateSymbol(bin_file, src, typed_value, code, dbg_line, dbg_info, dbg_info_type_relocs),
+ //.i386 => return Function(.i386).generateSymbol(bin_file, src, typed_value, code, dbg_line, dbg_info, dbg_info_type_relocs),
+ .x86_64 => return Function(.x86_64).generateSymbol(bin_file, src, typed_value, code, dbg_line, dbg_info, dbg_info_type_relocs),
+ //.xcore => return Function(.xcore).generateSymbol(bin_file, src, typed_value, code, dbg_line, dbg_info, dbg_info_type_relocs),
+ //.nvptx => return Function(.nvptx).generateSymbol(bin_file, src, typed_value, code, dbg_line, dbg_info, dbg_info_type_relocs),
+ //.nvptx64 => return Function(.nvptx64).generateSymbol(bin_file, src, typed_value, code, dbg_line, dbg_info, dbg_info_type_relocs),
+ //.le32 => return Function(.le32).generateSymbol(bin_file, src, typed_value, code, dbg_line, dbg_info, dbg_info_type_relocs),
+ //.le64 => return Function(.le64).generateSymbol(bin_file, src, typed_value, code, dbg_line, dbg_info, dbg_info_type_relocs),
+ //.amdil => return Function(.amdil).generateSymbol(bin_file, src, typed_value, code, dbg_line, dbg_info, dbg_info_type_relocs),
+ //.amdil64 => return Function(.amdil64).generateSymbol(bin_file, src, typed_value, code, dbg_line, dbg_info, dbg_info_type_relocs),
+ //.hsail => return Function(.hsail).generateSymbol(bin_file, src, typed_value, code, dbg_line, dbg_info, dbg_info_type_relocs),
+ //.hsail64 => return Function(.hsail64).generateSymbol(bin_file, src, typed_value, code, dbg_line, dbg_info, dbg_info_type_relocs),
+ //.spir => return Function(.spir).generateSymbol(bin_file, src, typed_value, code, dbg_line, dbg_info, dbg_info_type_relocs),
+ //.spir64 => return Function(.spir64).generateSymbol(bin_file, src, typed_value, code, dbg_line, dbg_info, dbg_info_type_relocs),
+ //.kalimba => return Function(.kalimba).generateSymbol(bin_file, src, typed_value, code, dbg_line, dbg_info, dbg_info_type_relocs),
+ //.shave => return Function(.shave).generateSymbol(bin_file, src, typed_value, code, dbg_line, dbg_info, dbg_info_type_relocs),
+ //.lanai => return Function(.lanai).generateSymbol(bin_file, src, typed_value, code, dbg_line, dbg_info, dbg_info_type_relocs),
+ //.wasm32 => return Function(.wasm32).generateSymbol(bin_file, src, typed_value, code, dbg_line, dbg_info, dbg_info_type_relocs),
+ //.wasm64 => return Function(.wasm64).generateSymbol(bin_file, src, typed_value, code, dbg_line, dbg_info, dbg_info_type_relocs),
+ //.renderscript32 => return Function(.renderscript32).generateSymbol(bin_file, src, typed_value, code, dbg_line, dbg_info, dbg_info_type_relocs),
+ //.renderscript64 => return Function(.renderscript64).generateSymbol(bin_file, src, typed_value, code, dbg_line, dbg_info, dbg_info_type_relocs),
+ //.ve => return Function(.ve).generateSymbol(bin_file, src, typed_value, code, dbg_line, dbg_info, dbg_info_type_relocs),
else => @panic("Backend architectures that don't have good support yet are commented out, to improve compilation performance. If you are interested in one of these other backends feel free to uncomment them. Eventually these will be completed, but stage1 is slow and a memory hog."),
}
},
@@ -122,7 +123,7 @@ pub fn generateSymbol(
switch (try generateSymbol(bin_file, src, .{
.ty = typed_value.ty.elemType(),
.val = sentinel,
- }, code, dbg_line, dbg_info)) {
+ }, code, dbg_line, dbg_info, dbg_info_type_relocs)) {
.appended => return Result{ .appended = {} },
.externally_managed => |slice| {
code.appendSliceAssumeCapacity(slice);
@@ -225,6 +226,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
code: *std.ArrayList(u8),
dbg_line: *std.ArrayList(u8),
dbg_info: *std.ArrayList(u8),
+ dbg_info_type_relocs: *link.File.Elf.DbgInfoTypeRelocsTable,
err_msg: ?*ErrorMsg,
args: []MCValue,
ret_mcv: MCValue,
@@ -395,6 +397,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
code: *std.ArrayList(u8),
dbg_line: *std.ArrayList(u8),
dbg_info: *std.ArrayList(u8),
+ dbg_info_type_relocs: *link.File.Elf.DbgInfoTypeRelocsTable,
) GenerateSymbolError!Result {
const module_fn = typed_value.val.cast(Value.Payload.Function).?.func;
@@ -433,6 +436,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
.code = code,
.dbg_line = dbg_line,
.dbg_info = dbg_info,
+ .dbg_info_type_relocs = dbg_info_type_relocs,
.err_msg = null,
.args = undefined, // populated after `resolveCallingConventionValues`
.ret_mcv = undefined, // populated after `resolveCallingConventionValues`
@@ -610,6 +614,23 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
}
}
+ /// 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 {
+ assert(ty.hasCodeGenBits());
+ const index = self.dbg_info.items.len;
+ try self.dbg_info.resize(index + 4); // DW.AT_type, DW.FORM_ref4
+
+ const gop = try self.dbg_info_type_relocs.getOrPut(self.gpa, ty);
+ if (!gop.found_existing) {
+ gop.entry.value = .{
+ .off = undefined,
+ .relocs = .{},
+ };
+ }
+ try gop.entry.value.relocs.append(self.gpa, @intCast(u32, index));
+ }
+
fn genFuncInst(self: *Self, inst: *ir.Inst) !MCValue {
switch (inst.tag) {
.add => return self.genAdd(inst.castTag(.add).?),
@@ -1009,7 +1030,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
}
}
- fn genArg(self: *Self, inst: *ir.Inst.NoOp) !MCValue {
+ fn genArg(self: *Self, inst: *ir.Inst.Arg) !MCValue {
if (FreeRegInt == u0) {
return self.fail(inst.base.src, "TODO implement Register enum for {}", .{self.target.cpu.arch});
}
@@ -1022,10 +1043,20 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
const result = self.args[self.arg_index];
self.arg_index += 1;
+ const name_with_null = inst.name[0..mem.lenZ(inst.name) + 1];
switch (result) {
.register => |reg| {
branch.registers.putAssumeCapacityNoClobber(reg, .{ .inst = &inst.base });
branch.markRegUsed(reg);
+
+ try self.dbg_info.ensureCapacity(self.dbg_info.items.len + 8 + name_with_null.len);
+ self.dbg_info.appendAssumeCapacity(link.File.Elf.abbrev_parameter);
+ self.dbg_info.appendSliceAssumeCapacity(&[2]u8{ // DW.AT_location, DW.FORM_exprloc
+ 1, // ULEB128 dwarf expression length
+ reg.dwarfLocOp(),
+ });
+ try self.addDbgInfoTypeReloc(inst.base.ty); // DW.AT_type, DW.FORM_ref4
+ self.dbg_info.appendSliceAssumeCapacity(name_with_null); // DW.AT_name, DW.FORM_string
},
else => {},
}
src-self-hosted/ir.zig
@@ -87,7 +87,6 @@ pub const Inst = struct {
.alloc,
.retvoid,
.unreach,
- .arg,
.breakpoint,
.dbg_stmt,
=> NoOp,
@@ -115,6 +114,7 @@ pub const Inst = struct {
.store,
=> BinOp,
+ .arg => Arg,
.assembly => Assembly,
.block => Block,
.br => Br,
@@ -253,6 +253,20 @@ pub const Inst = struct {
}
};
+ pub const Arg = struct {
+ pub const base_tag = Tag.arg;
+
+ base: Inst,
+ name: [*:0]const u8,
+
+ pub fn operandCount(self: *const Arg) usize {
+ return 0;
+ }
+ pub fn getOperand(self: *const Arg, index: usize) ?*Inst {
+ return null;
+ }
+ };
+
pub const Assembly = struct {
pub const base_tag = Tag.assembly;
src-self-hosted/link.zig
@@ -391,6 +391,17 @@ pub const File = struct {
const minimum_text_block_size = 64;
const min_text_capacity = minimum_text_block_size * alloc_num / alloc_den;
+ pub const DbgInfoTypeRelocsTable = std.HashMapUnmanaged(Type, DbgInfoTypeReloc, Type.hash, Type.eql, true);
+
+ const DbgInfoTypeReloc = struct {
+ /// Offset from `TextBlock.dbg_info_off` (the buffer that is local to a Decl).
+ /// This is where the .debug_info tag for the type is.
+ off: u32,
+ /// Offset from `TextBlock.dbg_info_off` (the buffer that is local to a Decl).
+ /// List of DW.AT_type / DW.FORM_ref4 that points to the type.
+ relocs: std.ArrayListUnmanaged(u32),
+ };
+
pub const TextBlock = struct {
/// Each decl always gets a local symbol with the fully qualified name.
/// The vaddr and size are found here directly.
@@ -991,6 +1002,7 @@ pub const File = struct {
pub const abbrev_subprogram_retvoid = 3;
pub const abbrev_base_type = 4;
pub const abbrev_pad1 = 5;
+ pub const abbrev_parameter = 6;
/// Commit pending changes and write headers.
pub fn flush(self: *Elf) !void {
@@ -1044,6 +1056,12 @@ pub const File = struct {
abbrev_pad1, DW.TAG_unspecified_type, DW.CHILDREN_no, // header
0, 0, // table sentinel
+ abbrev_parameter, DW.TAG_formal_parameter, DW.CHILDREN_no, // header
+ DW.AT_location , DW.FORM_exprloc,
+ DW.AT_type , DW.FORM_ref4,
+ DW.AT_name , DW.FORM_string,
+ 0, 0, // table sentinel
+
0, 0, 0, // section sentinel
};
@@ -1088,7 +1106,8 @@ pub const File = struct {
// not including the initial length itself.
// We have to come back and write it later after we know the size.
const after_init_len = di_buf.items.len + init_len_size;
- const dbg_info_end = last_dbg_info_decl.dbg_info_off + last_dbg_info_decl.dbg_info_len;
+ // +1 for the final 0 that ends the compilation unit children.
+ const dbg_info_end = last_dbg_info_decl.dbg_info_off + last_dbg_info_decl.dbg_info_len + 1;
const init_len = dbg_info_end - after_init_len;
switch (self.ptr_width) {
.p32 => {
@@ -1138,7 +1157,7 @@ pub const File = struct {
@panic("TODO: handle .debug_info header exceeding its padding");
}
const jmp_amt = first_dbg_info_decl.dbg_info_off - di_buf.items.len;
- try self.pwriteDbgInfoNops(0, di_buf.items, jmp_amt, debug_info_sect.sh_offset);
+ try self.pwriteDbgInfoNops(0, di_buf.items, jmp_amt, false, debug_info_sect.sh_offset);
self.debug_info_header_dirty = false;
}
@@ -1858,12 +1877,19 @@ pub const File = struct {
var dbg_info_buffer = std.ArrayList(u8).init(self.base.allocator);
defer dbg_info_buffer.deinit();
+ var dbg_info_type_relocs: DbgInfoTypeRelocsTable = .{};
+ defer {
+ for (dbg_info_type_relocs.items()) |*entry| {
+ entry.value.relocs.deinit(self.base.allocator);
+ }
+ dbg_info_type_relocs.deinit(self.base.allocator);
+ }
+
const typed_value = decl.typed_value.most_recent.typed_value;
const is_fn: bool = switch (typed_value.ty.zigTypeTag()) {
.Fn => true,
else => false,
};
- var fn_ret_has_bits: bool = undefined;
if (is_fn) {
// For functions we need to add a prologue to the debug line program.
try dbg_line_buffer.ensureCapacity(26);
@@ -1919,7 +1945,8 @@ pub const File = struct {
const decl_name_with_null = decl.name[0..mem.lenZ(decl.name) + 1];
try dbg_info_buffer.ensureCapacity(dbg_info_buffer.items.len + 25 + decl_name_with_null.len);
- fn_ret_has_bits = typed_value.ty.fnReturnType().hasCodeGenBits();
+ const fn_ret_type = typed_value.ty.fnReturnType();
+ const fn_ret_has_bits = fn_ret_type.hasCodeGenBits();
if (fn_ret_has_bits) {
dbg_info_buffer.appendAssumeCapacity(abbrev_subprogram);
} else {
@@ -1933,14 +1960,21 @@ pub const File = struct {
assert(self.getRelocDbgInfoSubprogramHighPC() == dbg_info_buffer.items.len);
dbg_info_buffer.items.len += 4; // DW.AT_high_pc, DW.FORM_data4
if (fn_ret_has_bits) {
- assert(self.getRelocDbgInfoSubprogramRetType() == dbg_info_buffer.items.len);
+ const gop = try dbg_info_type_relocs.getOrPut(self.base.allocator, fn_ret_type);
+ if (!gop.found_existing) {
+ gop.entry.value = .{
+ .off = undefined,
+ .relocs = .{},
+ };
+ }
+ try gop.entry.value.relocs.append(self.base.allocator, @intCast(u32, dbg_info_buffer.items.len));
dbg_info_buffer.items.len += 4; // DW.AT_type, DW.FORM_ref4
}
dbg_info_buffer.appendSliceAssumeCapacity(decl_name_with_null); // DW.AT_name, DW.FORM_string
} else {
// TODO implement .debug_info for global variables
}
- const res = try codegen.generateSymbol(self, decl.src(), typed_value, &code_buffer, &dbg_line_buffer, &dbg_info_buffer);
+ const res = try codegen.generateSymbol(self, decl.src(), typed_value, &code_buffer, &dbg_line_buffer, &dbg_info_buffer, &dbg_info_type_relocs);
const code = switch (res) {
.externally_managed => |x| x,
.appended => code_buffer.items,
@@ -2011,7 +2045,6 @@ pub const File = struct {
const text_block = &decl.link.elf;
// If the Decl is a function, we need to update the .debug_line program.
- var fn_ret_type_index: usize = undefined;
if (is_fn) {
// Perform the relocations based on vaddr.
switch (self.ptr_width) {
@@ -2117,28 +2150,30 @@ pub const File = struct {
const file_pos = debug_line_sect.sh_offset + src_fn.off;
try self.pwriteDbgLineNops(prev_padding_size, dbg_line_buffer.items, next_padding_size, file_pos);
- // .debug_info
- try dbg_info_buffer.ensureCapacity(dbg_info_buffer.items.len + 2);
- // End the TAG_subprogram children.
- dbg_info_buffer.appendAssumeCapacity(0);
- if (fn_ret_has_bits) {
- // Now we do the return type of the function. The relocation must be performed
- // later after the offset for this subprogram is computed.
- fn_ret_type_index = dbg_info_buffer.items.len;
- try self.addDbgInfoType(typed_value.ty.fnReturnType(), &dbg_info_buffer);
- }
+ // .debug_info - End the TAG_subprogram children.
+ try dbg_info_buffer.append(0);
+ }
+
+ // Now we emit the .debug_info types of the Decl. These will count towards the size of
+ // the buffer, so we have to do it before computing the offset, and we can't perform the actual
+ // relocations yet.
+ for (dbg_info_type_relocs.items()) |*entry| {
+ entry.value.off = @intCast(u32, dbg_info_buffer.items.len);
+ try self.addDbgInfoType(entry.key, &dbg_info_buffer);
}
try self.updateDeclDebugInfoAllocation(text_block, @intCast(u32, dbg_info_buffer.items.len));
- if (is_fn and fn_ret_has_bits) {
- // Perform function return type relocation.
- mem.writeInt(
- u32,
- dbg_info_buffer.items[self.getRelocDbgInfoSubprogramRetType()..][0..4],
- text_block.dbg_info_off + @intCast(u32, fn_ret_type_index),
- target_endian,
- );
+ // Now that we have the offset assigned we can finally perform type relocations.
+ for (dbg_info_type_relocs.items()) |entry| {
+ for (entry.value.relocs.items) |off| {
+ mem.writeInt(
+ u32,
+ dbg_info_buffer.items[off..][0..4],
+ text_block.dbg_info_off + entry.value.off,
+ target_endian,
+ );
+ }
}
try self.writeDeclDebugInfo(text_block, dbg_info_buffer.items);
@@ -2151,7 +2186,8 @@ pub const File = struct {
/// Asserts the type has codegen bits.
fn addDbgInfoType(self: *Elf, ty: Type, dbg_info_buffer: *std.ArrayList(u8)) !void {
switch (ty.zigTypeTag()) {
- .Void, .NoReturn => unreachable,
+ .Void => unreachable,
+ .NoReturn => unreachable,
.Bool => {
try dbg_info_buffer.appendSlice(&[_]u8{
abbrev_base_type,
@@ -2201,7 +2237,7 @@ pub const File = struct {
text_block.dbg_info_next = null;
// Populate where it used to be with NOPs.
const file_pos = debug_info_sect.sh_offset + text_block.dbg_info_off;
- try self.pwriteDbgInfoNops(0, &[0]u8{}, text_block.dbg_info_len, file_pos);
+ try self.pwriteDbgInfoNops(0, &[0]u8{}, text_block.dbg_info_len, false, file_pos);
// TODO Look at the free list before appending at the end.
text_block.dbg_info_prev = last;
last.dbg_info_next = text_block;
@@ -2238,7 +2274,8 @@ pub const File = struct {
const debug_info_sect = &self.sections.items[self.debug_info_section_index.?];
const last_decl = self.dbg_info_decl_last.?;
- const needed_size = last_decl.dbg_info_off + last_decl.dbg_info_len;
+ // +1 for a trailing zero to end the children of the decl tag.
+ const needed_size = last_decl.dbg_info_off + last_decl.dbg_info_len + 1;
if (needed_size != debug_info_sect.sh_size) {
if (needed_size > self.allocatedSize(debug_info_sect.sh_offset)) {
const new_offset = self.findFreeSpace(needed_size, 1);
@@ -2265,10 +2302,13 @@ pub const File = struct {
else
0;
+ // To end the children of the decl tag.
+ const trailing_zero = text_block.dbg_info_next == null;
+
// We only have support for one compilation unit so far, so the offsets are directly
// from the .debug_info section.
const file_pos = debug_info_sect.sh_offset + text_block.dbg_info_off;
- try self.pwriteDbgInfoNops(prev_padding_size, dbg_info_buf, next_padding_size, file_pos);
+ try self.pwriteDbgInfoNops(prev_padding_size, dbg_info_buf, next_padding_size, trailing_zero, file_pos);
}
/// Must be called only after a successful call to `updateDecl`.
@@ -2598,10 +2638,6 @@ pub const File = struct {
return dbg_info_low_pc_reloc_index + self.ptrWidthBytes();
}
- fn getRelocDbgInfoSubprogramRetType(self: Elf) u32 {
- return self.getRelocDbgInfoSubprogramHighPC() + 4;
- }
-
fn dbgLineNeededHeaderBytes(self: Elf) u32 {
const directory_entry_format_count = 1;
const file_name_entry_format_count = 1;
@@ -2710,6 +2746,7 @@ pub const File = struct {
prev_padding_size: usize,
buf: []const u8,
next_padding_size: usize,
+ trailing_zero: bool,
offset: usize,
) !void {
const tracy = trace(@src());
@@ -2761,6 +2798,16 @@ pub const File = struct {
vec_index += 1;
}
}
+
+ if (trailing_zero) {
+ var zbuf = [1]u8{0};
+ vecs[vec_index] = .{
+ .iov_base = &zbuf,
+ .iov_len = zbuf.len,
+ };
+ vec_index += 1;
+ }
+
try self.base.file.?.pwritevAll(vecs[0..vec_index], offset - prev_padding_size);
}
src-self-hosted/Module.zig
@@ -1301,14 +1301,16 @@ fn astGenAndAnalyzeDecl(self: *Module, decl: *Decl) !bool {
for (fn_proto.params()) |param, i| {
const name_token = param.name_token.?;
const src = tree.token_locs[name_token].start;
- const param_name = tree.tokenSlice(name_token);
- const arg = try gen_scope_arena.allocator.create(zir.Inst.NoOp);
+ const param_name = tree.tokenSlice(name_token); // TODO: call identifierTokenString
+ const arg = try gen_scope_arena.allocator.create(zir.Inst.Arg);
arg.* = .{
.base = .{
.tag = .arg,
.src = src,
},
- .positionals = .{},
+ .positionals = .{
+ .name = param_name,
+ },
.kw_args = .{},
};
gen_scope.instructions.items[i] = &arg.base;
@@ -1934,6 +1936,20 @@ pub fn addBinOp(
return &inst.base;
}
+pub fn addArg(self: *Module, block: *Scope.Block, src: usize, ty: Type, name: [*:0]const u8) !*Inst {
+ const inst = try block.arena.create(Inst.Arg);
+ inst.* = .{
+ .base = .{
+ .tag = .arg,
+ .ty = ty,
+ .src = src,
+ },
+ .name = name,
+ };
+ try block.instructions.append(self.gpa, &inst.base);
+ return &inst.base;
+}
+
pub fn addBr(
self: *Module,
scope_block: *Scope.Block,
@@ -2535,7 +2551,7 @@ pub fn coerce(self: *Module, scope: *Scope, dest_type: Type, inst: *Inst) !*Inst
}
}
- return self.fail(scope, inst.src, "expected {}, found {}", .{ dest_type, inst.ty });
+ return self.fail(scope, inst.src, "expected {}, found {}", .{ dest_type, inst.ty });
}
pub fn storePtr(self: *Module, scope: *Scope, src: usize, ptr: *Inst, uncasted_value: *Inst) !*Inst {
src-self-hosted/type.zig
@@ -103,7 +103,6 @@ pub const Type = extern union {
}
pub fn eql(a: Type, b: Type) bool {
- //std.debug.warn("test {} == {}\n", .{ a, b });
// As a shortcut, if the small tags / addresses match, we're done.
if (a.tag_if_small_enough == b.tag_if_small_enough)
return true;
@@ -197,6 +196,71 @@ pub const Type = extern union {
}
}
+ pub fn hash(self: Type) u32 {
+ var hasher = std.hash.Wyhash.init(0);
+ const zig_type_tag = self.zigTypeTag();
+ std.hash.autoHash(&hasher, zig_type_tag);
+ switch (zig_type_tag) {
+ .Type,
+ .Void,
+ .Bool,
+ .NoReturn,
+ .ComptimeFloat,
+ .ComptimeInt,
+ .Undefined,
+ .Null,
+ => {}, // The zig type tag is all that is needed to distinguish.
+
+ .Pointer => {
+ // TODO implement more pointer type hashing
+ },
+ .Int => {
+ // Detect that e.g. u64 != usize, even if the bits match on a particular target.
+ if (self.isNamedInt()) {
+ std.hash.autoHash(&hasher, self.tag());
+ } else {
+ // Remaining cases are arbitrary sized integers.
+ // The target will not be branched upon, because we handled target-dependent cases above.
+ const info = self.intInfo(@as(Target, undefined));
+ std.hash.autoHash(&hasher, info.signed);
+ std.hash.autoHash(&hasher, info.bits);
+ }
+ },
+ .Array => {
+ std.hash.autoHash(&hasher, self.arrayLen());
+ std.hash.autoHash(&hasher, self.elemType().hash());
+ // TODO hash array sentinel
+ },
+ .Fn => {
+ std.hash.autoHash(&hasher, self.fnReturnType().hash());
+ std.hash.autoHash(&hasher, self.fnCallingConvention());
+ const params_len = self.fnParamLen();
+ std.hash.autoHash(&hasher, params_len);
+ var i: usize = 0;
+ while (i < params_len) : (i += 1) {
+ std.hash.autoHash(&hasher, self.fnParamType(i).hash());
+ }
+ },
+ .Float,
+ .Struct,
+ .Optional,
+ .ErrorUnion,
+ .ErrorSet,
+ .Enum,
+ .Union,
+ .BoundFn,
+ .Opaque,
+ .Frame,
+ .AnyFrame,
+ .Vector,
+ .EnumLiteral,
+ => {
+ // TODO implement more type hashing
+ },
+ }
+ return @truncate(u32, hasher.final());
+ }
+
pub fn copy(self: Type, allocator: *Allocator) error{OutOfMemory}!Type {
if (self.tag_if_small_enough < Tag.no_payload_count) {
return Type{ .tag_if_small_enough = self.tag_if_small_enough };
src-self-hosted/zir.zig
@@ -211,7 +211,6 @@ pub const Inst = struct {
pub fn Type(tag: Tag) type {
return switch (tag) {
- .arg,
.breakpoint,
.dbg_stmt,
.returnvoid,
@@ -268,6 +267,7 @@ pub const Inst = struct {
.xor,
=> BinOp,
+ .arg => Arg,
.block => Block,
.@"break" => Break,
.breakvoid => BreakVoid,
@@ -431,6 +431,16 @@ pub const Inst = struct {
kw_args: struct {},
};
+ pub const Arg = struct {
+ pub const base_tag = Tag.arg;
+ base: Inst,
+
+ positionals: struct {
+ name: []const u8,
+ },
+ kw_args: struct {},
+ };
+
pub const Block = struct {
pub const base_tag = Tag.block;
base: Inst,
@@ -1843,7 +1853,6 @@ const EmitZIR = struct {
const new_inst = switch (inst.tag) {
.constant => unreachable, // excluded from function bodies
- .arg => try self.emitNoOp(inst.src, .arg),
.breakpoint => try self.emitNoOp(inst.src, .breakpoint),
.unreach => try self.emitNoOp(inst.src, .@"unreachable"),
.retvoid => try self.emitNoOp(inst.src, .returnvoid),
@@ -1886,6 +1895,22 @@ const EmitZIR = struct {
break :blk &new_inst.base;
},
+ .arg => blk: {
+ const old_inst = inst.castTag(.arg).?;
+ const new_inst = try self.arena.allocator.create(Inst.Arg);
+ new_inst.* = .{
+ .base = .{
+ .src = inst.src,
+ .tag = .arg,
+ },
+ .positionals = .{
+ .name = try self.arena.allocator.dupe(u8, mem.spanZ(old_inst.name)),
+ },
+ .kw_args = .{},
+ };
+ break :blk &new_inst.base;
+ },
+
.block => blk: {
const old_inst = inst.castTag(.block).?;
const new_inst = try self.arena.allocator.create(Inst.Block);
src-self-hosted/zir_sema.zig
@@ -408,7 +408,7 @@ fn analyzeInstCompileError(mod: *Module, scope: *Scope, inst: *zir.Inst.CompileE
return mod.fail(scope, inst.base.src, "{}", .{inst.positionals.msg});
}
-fn analyzeInstArg(mod: *Module, scope: *Scope, inst: *zir.Inst.NoOp) InnerError!*Inst {
+fn analyzeInstArg(mod: *Module, scope: *Scope, inst: *zir.Inst.Arg) InnerError!*Inst {
const b = try mod.requireRuntimeBlock(scope, inst.base.src);
const fn_ty = b.func.?.owner_decl.typed_value.most_recent.typed_value.ty;
const param_index = b.instructions.items.len;
@@ -420,7 +420,8 @@ fn analyzeInstArg(mod: *Module, scope: *Scope, inst: *zir.Inst.NoOp) InnerError!
});
}
const param_type = fn_ty.fnParamType(param_index);
- return mod.addNoOp(b, inst.base.src, param_type, .arg);
+ const name = try scope.arena().dupeZ(u8, inst.positionals.name);
+ return mod.addArg(b, inst.base.src, param_type, name);
}
fn analyzeInstBlock(mod: *Module, scope: *Scope, inst: *zir.Inst.Block) InnerError!*Inst {