authorgravatar for jacobly@ziglang.orgJacob Young <jacobly@ziglang.org> 2025-06-04 21:45:31-04:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2025-06-06 23:42:14-07:00
log0bf8617d963dc432ed0204b10285cc414becf2fd
treeb4a28f10bd66183cd949e6f0fbb4a786bfc1aa04
parent178ee8aef1b9f765da916f3e1e4cab66437f8e0a

x86_64: add support for pie executables


46 files changed, 1910 insertions(+), 1666 deletions(-)

CMakeLists.txt+1-1
......@@ -519,6 +519,7 @@ set(ZIG_STAGE2_SOURCES
519519 src/Air/Legalize.zig
520520 src/Air/Liveness.zig
521521 src/Air/Liveness/Verify.zig
522 src/Air/print.zig
522523 src/Air/types_resolved.zig
523524 src/Builtin.zig
524525 src/Compilation.zig
......@@ -675,7 +676,6 @@ set(ZIG_STAGE2_SOURCES
675676 src/libs/mingw.zig
676677 src/libs/musl.zig
677678 src/mutable_value.zig
678 src/print_air.zig
679679 src/print_env.zig
680680 src/print_targets.zig
681681 src/print_value.zig
lib/std/builtin.zig+13-2
......@@ -61,7 +61,7 @@ pub const StackTrace = struct {
6161
6262/// This data structure is used by the Zig language code generation and
6363/// therefore must be kept in sync with the compiler implementation.
64pub const GlobalLinkage = enum {
64pub const GlobalLinkage = enum(u2) {
6565 internal,
6666 strong,
6767 weak,
......@@ -70,7 +70,7 @@ pub const GlobalLinkage = enum {
7070
7171/// This data structure is used by the Zig language code generation and
7272/// therefore must be kept in sync with the compiler implementation.
73pub const SymbolVisibility = enum {
73pub const SymbolVisibility = enum(u2) {
7474 default,
7575 hidden,
7676 protected,
......@@ -1030,8 +1030,19 @@ pub const ExternOptions = struct {
10301030 name: []const u8,
10311031 library_name: ?[]const u8 = null,
10321032 linkage: GlobalLinkage = .strong,
1033 visibility: SymbolVisibility = .default,
1034 /// Setting this to `true` makes the `@extern` a runtime value.
10331035 is_thread_local: bool = false,
10341036 is_dll_import: bool = false,
1037 relocation: Relocation = .any,
1038
1039 pub const Relocation = enum(u1) {
1040 /// Any type of relocation is allowed.
1041 any,
1042 /// A program-counter-relative relocation is required.
1043 /// Using this value makes the `@extern` a runtime value.
1044 pcrel,
1045 };
10351046};
10361047
10371048/// This data structure is used by the Zig language code generation and
lib/std/dynamic_library.zig+8-5
......@@ -83,13 +83,16 @@ const RDebug = extern struct {
8383 r_ldbase: usize,
8484};
8585
86/// TODO make it possible to reference this same external symbol 2x so we don't need this
87/// helper function.
88pub fn get_DYNAMIC() ?[*]elf.Dyn {
89 return @extern([*]elf.Dyn, .{ .name = "_DYNAMIC", .linkage = .weak });
86/// TODO fix comparisons of extern symbol pointers so we don't need this helper function.
87pub fn get_DYNAMIC() ?[*]const elf.Dyn {
88 return @extern([*]const elf.Dyn, .{
89 .name = "_DYNAMIC",
90 .linkage = .weak,
91 .visibility = .hidden,
92 });
9093}
9194
92pub fn linkmap_iterator(phdrs: []elf.Phdr) error{InvalidExe}!LinkMap.Iterator {
95pub fn linkmap_iterator(phdrs: []const elf.Phdr) error{InvalidExe}!LinkMap.Iterator {
9396 _ = phdrs;
9497 const _DYNAMIC = get_DYNAMIC() orelse {
9598 // No PT_DYNAMIC means this is either a statically-linked program or a
lib/std/pie.zig+174-169
......@@ -39,167 +39,175 @@ const R_RELATIVE = switch (builtin.cpu.arch) {
3939// Obtain a pointer to the _DYNAMIC array.
4040// We have to compute its address as a PC-relative quantity not to require a
4141// relocation that, at this point, is not yet applied.
42inline fn getDynamicSymbol() [*]elf.Dyn {
43 return switch (builtin.cpu.arch) {
44 .x86 => asm volatile (
45 \\ .weak _DYNAMIC
46 \\ .hidden _DYNAMIC
47 \\ call 1f
48 \\ 1: pop %[ret]
49 \\ lea _DYNAMIC-1b(%[ret]), %[ret]
50 : [ret] "=r" (-> [*]elf.Dyn),
51 ),
52 .x86_64 => asm volatile (
53 \\ .weak _DYNAMIC
54 \\ .hidden _DYNAMIC
55 \\ lea _DYNAMIC(%%rip), %[ret]
56 : [ret] "=r" (-> [*]elf.Dyn),
57 ),
58 .arc => asm volatile (
59 \\ .weak _DYNAMIC
60 \\ .hidden _DYNAMIC
61 \\ add %[ret], pcl, _DYNAMIC@pcl
62 : [ret] "=r" (-> [*]elf.Dyn),
63 ),
64 // Work around the limited offset range of `ldr`
65 .arm, .armeb, .thumb, .thumbeb => asm volatile (
66 \\ .weak _DYNAMIC
67 \\ .hidden _DYNAMIC
68 \\ ldr %[ret], 1f
69 \\ add %[ret], pc
70 \\ b 2f
71 \\ 1: .word _DYNAMIC-1b
72 \\ 2:
73 : [ret] "=r" (-> [*]elf.Dyn),
74 ),
75 // A simple `adr` is not enough as it has a limited offset range
76 .aarch64, .aarch64_be => asm volatile (
77 \\ .weak _DYNAMIC
78 \\ .hidden _DYNAMIC
79 \\ adrp %[ret], _DYNAMIC
80 \\ add %[ret], %[ret], #:lo12:_DYNAMIC
81 : [ret] "=r" (-> [*]elf.Dyn),
82 ),
83 // The CSKY ABI requires the gb register to point to the GOT. Additionally, the first
84 // entry in the GOT is defined to hold the address of _DYNAMIC.
85 .csky => asm volatile (
86 \\ mov %[ret], gb
87 \\ ldw %[ret], %[ret]
88 : [ret] "=r" (-> [*]elf.Dyn),
89 ),
90 .hexagon => asm volatile (
91 \\ .weak _DYNAMIC
92 \\ .hidden _DYNAMIC
93 \\ jump 1f
94 \\ .word _DYNAMIC - .
95 \\ 1:
96 \\ r1 = pc
97 \\ r1 = add(r1, #-4)
98 \\ %[ret] = memw(r1)
99 \\ %[ret] = add(r1, %[ret])
100 : [ret] "=r" (-> [*]elf.Dyn),
101 :
102 : "r1"
103 ),
104 .loongarch32, .loongarch64 => asm volatile (
105 \\ .weak _DYNAMIC
106 \\ .hidden _DYNAMIC
107 \\ la.local %[ret], _DYNAMIC
108 : [ret] "=r" (-> [*]elf.Dyn),
109 ),
110 // Note that the - 8 is needed because pc in the second lea instruction points into the
111 // middle of that instruction. (The first lea is 6 bytes, the second is 4 bytes.)
112 .m68k => asm volatile (
113 \\ .weak _DYNAMIC
114 \\ .hidden _DYNAMIC
115 \\ lea _DYNAMIC - . - 8, %[ret]
116 \\ lea (%[ret], %%pc), %[ret]
117 : [ret] "=r" (-> [*]elf.Dyn),
118 ),
119 .mips, .mipsel => asm volatile (
120 \\ .weak _DYNAMIC
121 \\ .hidden _DYNAMIC
122 \\ bal 1f
123 \\ .gpword _DYNAMIC
124 \\ 1:
125 \\ lw %[ret], 0($ra)
126 \\ addu %[ret], %[ret], $gp
127 : [ret] "=r" (-> [*]elf.Dyn),
128 :
129 : "lr"
130 ),
131 .mips64, .mips64el => asm volatile (
132 \\ .weak _DYNAMIC
133 \\ .hidden _DYNAMIC
134 \\ .balign 8
135 \\ bal 1f
136 \\ .gpdword _DYNAMIC
137 \\ 1:
138 \\ ld %[ret], 0($ra)
139 \\ daddu %[ret], %[ret], $gp
140 : [ret] "=r" (-> [*]elf.Dyn),
141 :
142 : "lr"
143 ),
144 .powerpc, .powerpcle => asm volatile (
145 \\ .weak _DYNAMIC
146 \\ .hidden _DYNAMIC
147 \\ bl 1f
148 \\ .long _DYNAMIC - .
149 \\ 1:
150 \\ mflr %[ret]
151 \\ lwz 4, 0(%[ret])
152 \\ add %[ret], 4, %[ret]
153 : [ret] "=r" (-> [*]elf.Dyn),
154 :
155 : "lr", "r4"
156 ),
157 .powerpc64, .powerpc64le => asm volatile (
158 \\ .weak _DYNAMIC
159 \\ .hidden _DYNAMIC
160 \\ bl 1f
161 \\ .quad _DYNAMIC - .
162 \\ 1:
163 \\ mflr %[ret]
164 \\ ld 4, 0(%[ret])
165 \\ add %[ret], 4, %[ret]
166 : [ret] "=r" (-> [*]elf.Dyn),
167 :
168 : "lr", "r4"
169 ),
170 .riscv32, .riscv64 => asm volatile (
171 \\ .weak _DYNAMIC
172 \\ .hidden _DYNAMIC
173 \\ lla %[ret], _DYNAMIC
174 : [ret] "=r" (-> [*]elf.Dyn),
175 ),
176 .s390x => asm volatile (
177 \\ .weak _DYNAMIC
178 \\ .hidden _DYNAMIC
179 \\ larl %[ret], 1f
180 \\ ag %[ret], 0(%[ret])
181 \\ jg 2f
182 \\ 1: .quad _DYNAMIC - .
183 \\ 2:
184 : [ret] "=r" (-> [*]elf.Dyn),
185 ),
186 // The compiler does not necessarily have any obligation to load the `l7` register (pointing
187 // to the GOT), so do it ourselves just in case.
188 .sparc, .sparc64 => asm volatile (
189 \\ sethi %%hi(_GLOBAL_OFFSET_TABLE_ - 4), %%l7
190 \\ call 1f
191 \\ add %%l7, %%lo(_GLOBAL_OFFSET_TABLE_ + 4), %%l7
192 \\ 1:
193 \\ add %%l7, %%o7, %[ret]
194 : [ret] "=r" (-> [*]elf.Dyn),
195 ),
196 else => {
197 @compileError("PIE startup is not yet supported for this target!");
42inline fn getDynamicSymbol() [*]const elf.Dyn {
43 return switch (builtin.zig_backend) {
44 else => switch (builtin.cpu.arch) {
45 .x86 => asm volatile (
46 \\ .weak _DYNAMIC
47 \\ .hidden _DYNAMIC
48 \\ call 1f
49 \\ 1: pop %[ret]
50 \\ lea _DYNAMIC-1b(%[ret]), %[ret]
51 : [ret] "=r" (-> [*]const elf.Dyn),
52 ),
53 .x86_64 => asm volatile (
54 \\ .weak _DYNAMIC
55 \\ .hidden _DYNAMIC
56 \\ lea _DYNAMIC(%%rip), %[ret]
57 : [ret] "=r" (-> [*]const elf.Dyn),
58 ),
59 .arc => asm volatile (
60 \\ .weak _DYNAMIC
61 \\ .hidden _DYNAMIC
62 \\ add %[ret], pcl, _DYNAMIC@pcl
63 : [ret] "=r" (-> [*]const elf.Dyn),
64 ),
65 // Work around the limited offset range of `ldr`
66 .arm, .armeb, .thumb, .thumbeb => asm volatile (
67 \\ .weak _DYNAMIC
68 \\ .hidden _DYNAMIC
69 \\ ldr %[ret], 1f
70 \\ add %[ret], pc
71 \\ b 2f
72 \\ 1: .word _DYNAMIC-1b
73 \\ 2:
74 : [ret] "=r" (-> [*]const elf.Dyn),
75 ),
76 // A simple `adr` is not enough as it has a limited offset range
77 .aarch64, .aarch64_be => asm volatile (
78 \\ .weak _DYNAMIC
79 \\ .hidden _DYNAMIC
80 \\ adrp %[ret], _DYNAMIC
81 \\ add %[ret], %[ret], #:lo12:_DYNAMIC
82 : [ret] "=r" (-> [*]const elf.Dyn),
83 ),
84 // The CSKY ABI requires the gb register to point to the GOT. Additionally, the first
85 // entry in the GOT is defined to hold the address of _DYNAMIC.
86 .csky => asm volatile (
87 \\ mov %[ret], gb
88 \\ ldw %[ret], %[ret]
89 : [ret] "=r" (-> [*]const elf.Dyn),
90 ),
91 .hexagon => asm volatile (
92 \\ .weak _DYNAMIC
93 \\ .hidden _DYNAMIC
94 \\ jump 1f
95 \\ .word _DYNAMIC - .
96 \\ 1:
97 \\ r1 = pc
98 \\ r1 = add(r1, #-4)
99 \\ %[ret] = memw(r1)
100 \\ %[ret] = add(r1, %[ret])
101 : [ret] "=r" (-> [*]const elf.Dyn),
102 :
103 : "r1"
104 ),
105 .loongarch32, .loongarch64 => asm volatile (
106 \\ .weak _DYNAMIC
107 \\ .hidden _DYNAMIC
108 \\ la.local %[ret], _DYNAMIC
109 : [ret] "=r" (-> [*]const elf.Dyn),
110 ),
111 // Note that the - 8 is needed because pc in the second lea instruction points into the
112 // middle of that instruction. (The first lea is 6 bytes, the second is 4 bytes.)
113 .m68k => asm volatile (
114 \\ .weak _DYNAMIC
115 \\ .hidden _DYNAMIC
116 \\ lea _DYNAMIC - . - 8, %[ret]
117 \\ lea (%[ret], %%pc), %[ret]
118 : [ret] "=r" (-> [*]const elf.Dyn),
119 ),
120 .mips, .mipsel => asm volatile (
121 \\ .weak _DYNAMIC
122 \\ .hidden _DYNAMIC
123 \\ bal 1f
124 \\ .gpword _DYNAMIC
125 \\ 1:
126 \\ lw %[ret], 0($ra)
127 \\ addu %[ret], %[ret], $gp
128 : [ret] "=r" (-> [*]const elf.Dyn),
129 :
130 : "lr"
131 ),
132 .mips64, .mips64el => asm volatile (
133 \\ .weak _DYNAMIC
134 \\ .hidden _DYNAMIC
135 \\ .balign 8
136 \\ bal 1f
137 \\ .gpdword _DYNAMIC
138 \\ 1:
139 \\ ld %[ret], 0($ra)
140 \\ daddu %[ret], %[ret], $gp
141 : [ret] "=r" (-> [*]const elf.Dyn),
142 :
143 : "lr"
144 ),
145 .powerpc, .powerpcle => asm volatile (
146 \\ .weak _DYNAMIC
147 \\ .hidden _DYNAMIC
148 \\ bl 1f
149 \\ .long _DYNAMIC - .
150 \\ 1:
151 \\ mflr %[ret]
152 \\ lwz 4, 0(%[ret])
153 \\ add %[ret], 4, %[ret]
154 : [ret] "=r" (-> [*]const elf.Dyn),
155 :
156 : "lr", "r4"
157 ),
158 .powerpc64, .powerpc64le => asm volatile (
159 \\ .weak _DYNAMIC
160 \\ .hidden _DYNAMIC
161 \\ bl 1f
162 \\ .quad _DYNAMIC - .
163 \\ 1:
164 \\ mflr %[ret]
165 \\ ld 4, 0(%[ret])
166 \\ add %[ret], 4, %[ret]
167 : [ret] "=r" (-> [*]const elf.Dyn),
168 :
169 : "lr", "r4"
170 ),
171 .riscv32, .riscv64 => asm volatile (
172 \\ .weak _DYNAMIC
173 \\ .hidden _DYNAMIC
174 \\ lla %[ret], _DYNAMIC
175 : [ret] "=r" (-> [*]const elf.Dyn),
176 ),
177 .s390x => asm volatile (
178 \\ .weak _DYNAMIC
179 \\ .hidden _DYNAMIC
180 \\ larl %[ret], 1f
181 \\ ag %[ret], 0(%[ret])
182 \\ jg 2f
183 \\ 1: .quad _DYNAMIC - .
184 \\ 2:
185 : [ret] "=r" (-> [*]const elf.Dyn),
186 ),
187 // The compiler does not necessarily have any obligation to load the `l7` register (pointing
188 // to the GOT), so do it ourselves just in case.
189 .sparc, .sparc64 => asm volatile (
190 \\ sethi %%hi(_GLOBAL_OFFSET_TABLE_ - 4), %%l7
191 \\ call 1f
192 \\ add %%l7, %%lo(_GLOBAL_OFFSET_TABLE_ + 4), %%l7
193 \\ 1:
194 \\ add %%l7, %%o7, %[ret]
195 : [ret] "=r" (-> [*]const elf.Dyn),
196 ),
197 else => {
198 @compileError("PIE startup is not yet supported for this target!");
199 },
198200 },
201 .stage2_x86_64 => @extern([*]const elf.Dyn, .{
202 .name = "_DYNAMIC",
203 .linkage = .weak,
204 .visibility = .hidden,
205 .relocation = .pcrel,
206 }).?,
199207 };
200208}
201209
202pub fn relocate(phdrs: []elf.Phdr) void {
210pub fn relocate(phdrs: []const elf.Phdr) void {
203211 @setRuntimeSafety(false);
204212 @disableInstrumentation();
205213
......@@ -256,10 +264,9 @@ pub fn relocate(phdrs: []elf.Phdr) void {
256264
257265 const rel = sorted_dynv[elf.DT_REL];
258266 if (rel != 0) {
259 const rels = @call(.always_inline, std.mem.bytesAsSlice, .{
260 elf.Rel,
261 @as([*]u8, @ptrFromInt(base_addr + rel))[0..sorted_dynv[elf.DT_RELSZ]],
262 });
267 const rels: []const elf.Rel = @alignCast(@ptrCast(
268 @as([*]align(@alignOf(elf.Rel)) const u8, @ptrFromInt(base_addr + rel))[0..sorted_dynv[elf.DT_RELSZ]],
269 ));
263270 for (rels) |r| {
264271 if (r.r_type() != R_RELATIVE) continue;
265272 @as(*usize, @ptrFromInt(base_addr + r.r_offset)).* += base_addr;
......@@ -268,10 +275,9 @@ pub fn relocate(phdrs: []elf.Phdr) void {
268275
269276 const rela = sorted_dynv[elf.DT_RELA];
270277 if (rela != 0) {
271 const relas = @call(.always_inline, std.mem.bytesAsSlice, .{
272 elf.Rela,
273 @as([*]u8, @ptrFromInt(base_addr + rela))[0..sorted_dynv[elf.DT_RELASZ]],
274 });
278 const relas: []const elf.Rela = @alignCast(@ptrCast(
279 @as([*]align(@alignOf(elf.Rela)) const u8, @ptrFromInt(base_addr + rela))[0..sorted_dynv[elf.DT_RELASZ]],
280 ));
275281 for (relas) |r| {
276282 if (r.r_type() != R_RELATIVE) continue;
277283 @as(*usize, @ptrFromInt(base_addr + r.r_offset)).* = base_addr + @as(usize, @bitCast(r.r_addend));
......@@ -280,10 +286,9 @@ pub fn relocate(phdrs: []elf.Phdr) void {
280286
281287 const relr = sorted_dynv[elf.DT_RELR];
282288 if (relr != 0) {
283 const relrs = @call(.always_inline, std.mem.bytesAsSlice, .{
284 elf.Relr,
285 @as([*]u8, @ptrFromInt(base_addr + relr))[0..sorted_dynv[elf.DT_RELRSZ]],
286 });
289 const relrs: []const elf.Relr = @ptrCast(
290 @as([*]align(@alignOf(elf.Relr)) const u8, @ptrFromInt(base_addr + relr))[0..sorted_dynv[elf.DT_RELRSZ]],
291 );
287292 var current: [*]usize = undefined;
288293 for (relrs) |r| {
289294 if ((r & 1) == 0) {
lib/std/start.zig+6-6
......@@ -163,7 +163,7 @@ fn exit2(code: usize) noreturn {
163163 // exits(0)
164164 .plan9 => std.os.plan9.exits(null),
165165 .windows => {
166 std.os.windows.ntdll.RtlExitUserProcess(@as(u32, @truncate(code)));
166 std.os.windows.ntdll.RtlExitUserProcess(@truncate(code));
167167 },
168168 else => @compileError("TODO"),
169169 }
......@@ -511,7 +511,7 @@ fn posixCallMainAndExit(argc_argv_ptr: [*]usize) callconv(.c) noreturn {
511511 // Code coverage instrumentation might try to use thread local variables.
512512 @disableInstrumentation();
513513 const argc = argc_argv_ptr[0];
514 const argv = @as([*][*:0]u8, @ptrCast(argc_argv_ptr + 1));
514 const argv: [*][*:0]u8 = @ptrCast(argc_argv_ptr + 1);
515515
516516 const envp_optional: [*:null]?[*:0]u8 = @ptrCast(@alignCast(argv + argc + 1));
517517 var envp_count: usize = 0;
......@@ -573,11 +573,11 @@ fn posixCallMainAndExit(argc_argv_ptr: [*]usize) callconv(.c) noreturn {
573573 expandStackSize(phdrs);
574574 }
575575
576 const opt_init_array_start = @extern([*]*const fn () callconv(.c) void, .{
576 const opt_init_array_start = @extern([*]const *const fn () callconv(.c) void, .{
577577 .name = "__init_array_start",
578578 .linkage = .weak,
579579 });
580 const opt_init_array_end = @extern([*]*const fn () callconv(.c) void, .{
580 const opt_init_array_end = @extern([*]const *const fn () callconv(.c) void, .{
581581 .name = "__init_array_end",
582582 .linkage = .weak,
583583 });
......@@ -651,7 +651,7 @@ fn main(c_argc: c_int, c_argv: [*][*:0]c_char, c_envp: [*:null]?[*:0]c_char) cal
651651}
652652
653653fn mainWithoutEnv(c_argc: c_int, c_argv: [*][*:0]c_char) callconv(.c) c_int {
654 std.os.argv = @as([*][*:0]u8, @ptrCast(c_argv))[0..@as(usize, @intCast(c_argc))];
654 std.os.argv = @as([*][*:0]u8, @ptrCast(c_argv))[0..@intCast(c_argc)];
655655 return callMain();
656656}
657657
......@@ -701,7 +701,7 @@ pub inline fn callMain() u8 {
701701pub fn call_wWinMain() std.os.windows.INT {
702702 const peb = std.os.windows.peb();
703703 const MAIN_HINSTANCE = @typeInfo(@TypeOf(root.wWinMain)).@"fn".params[0].type.?;
704 const hInstance = @as(MAIN_HINSTANCE, @ptrCast(peb.ImageBaseAddress));
704 const hInstance: MAIN_HINSTANCE = @ptrCast(peb.ImageBaseAddress);
705705 const lpCmdLine: [*:0]u16 = @ptrCast(peb.ProcessParameters.CommandLine.Buffer);
706706
707707 // There are various types used for the 'show window' variable through the Win32 APIs:
lib/std/zig/llvm/Builder.zig+12
......@@ -1823,6 +1823,14 @@ pub const Visibility = enum(u2) {
18231823 hidden = 1,
18241824 protected = 2,
18251825
1826 pub fn fromSymbolVisibility(sv: std.builtin.SymbolVisibility) Visibility {
1827 return switch (sv) {
1828 .default => .default,
1829 .hidden => .hidden,
1830 .protected => .protected,
1831 };
1832 }
1833
18261834 pub fn format(
18271835 self: Visibility,
18281836 comptime _: []const u8,
......@@ -2555,6 +2563,10 @@ pub const Variable = struct {
25552563 return self.ptrConst(builder).global.setLinkage(linkage, builder);
25562564 }
25572565
2566 pub fn setVisibility(self: Index, visibility: Visibility, builder: *Builder) void {
2567 return self.ptrConst(builder).global.setVisibility(visibility, builder);
2568 }
2569
25582570 pub fn setDllStorageClass(self: Index, class: DllStorageClass, builder: *Builder) void {
25592571 return self.ptrConst(builder).global.setDllStorageClass(class, builder);
25602572 }
lib/zig.h+9
......@@ -272,6 +272,15 @@
272272#define zig_linksection_fn zig_linksection
273273#endif
274274
275#if zig_has_attribute(visibility)
276#define zig_visibility(name) __attribute__((visibility(#name)))
277#else
278#define zig_visibility(name) zig_visibility_##name
279#define zig_visibility_default
280#define zig_visibility_hidden zig_visibility_hidden_unavailable
281#define zig_visibility_protected zig_visibility_protected_unavailable
282#endif
283
275284#if zig_has_builtin(unreachable) || defined(zig_gcc) || defined(zig_tinyc)
276285#define zig_unreachable() __builtin_unreachable()
277286#elif defined(zig_msvc)
src/Air.zig+10-4
......@@ -13,6 +13,7 @@ const InternPool = @import("InternPool.zig");
1313const Type = @import("Type.zig");
1414const Value = @import("Value.zig");
1515const Zcu = @import("Zcu.zig");
16const print = @import("Air/print.zig");
1617const types_resolved = @import("Air/types_resolved.zig");
1718
1819pub const Legalize = @import("Air/Legalize.zig");
......@@ -863,16 +864,17 @@ pub const Inst = struct {
863864 /// Uses the `vector_store_elem` field.
864865 vector_store_elem,
865866
866 /// Compute a pointer to a threadlocal or dllimport `Nav`, meaning one of:
867 /// Compute a pointer to a `Nav` at runtime, always one of:
867868 ///
868869 /// * `threadlocal var`
869870 /// * `extern threadlocal var` (or corresponding `@extern`)
870871 /// * `@extern` with `.is_dll_import = true`
872 /// * `@extern` with `.relocation = .pcrel`
871873 ///
872874 /// Such pointers are runtime values, so cannot be represented with an InternPool index.
873875 ///
874876 /// Uses the `ty_nav` field.
875 tlv_dllimport_ptr,
877 runtime_nav_ptr,
876878
877879 /// Implements @cVaArg builtin.
878880 /// Uses the `ty_op` field.
......@@ -1708,7 +1710,7 @@ pub fn typeOfIndex(air: *const Air, inst: Air.Inst.Index, ip: *const InternPool)
17081710 return .fromInterned(ip.indexToKey(err_union_ty.ip_index).error_union_type.payload_type);
17091711 },
17101712
1711 .tlv_dllimport_ptr => return .fromInterned(datas[@intFromEnum(inst)].ty_nav.ty),
1713 .runtime_nav_ptr => return .fromInterned(datas[@intFromEnum(inst)].ty_nav.ty),
17121714
17131715 .work_item_id,
17141716 .work_group_size,
......@@ -1983,7 +1985,7 @@ pub fn mustLower(air: Air, inst: Air.Inst.Index, ip: *const InternPool) bool {
19831985 .err_return_trace,
19841986 .addrspace_cast,
19851987 .save_err_return_trace_index,
1986 .tlv_dllimport_ptr,
1988 .runtime_nav_ptr,
19871989 .work_item_id,
19881990 .work_group_size,
19891991 .work_group_id,
......@@ -2141,6 +2143,10 @@ pub const typesFullyResolved = types_resolved.typesFullyResolved;
21412143pub const typeFullyResolved = types_resolved.checkType;
21422144pub const valFullyResolved = types_resolved.checkVal;
21432145pub const legalize = Legalize.legalize;
2146pub const write = print.write;
2147pub const writeInst = print.writeInst;
2148pub const dump = print.dump;
2149pub const dumpInst = print.dumpInst;
21442150
21452151pub const CoveragePoint = enum(u1) {
21462152 /// Indicates the block is not a place of interest corresponding to
src/Air/Legalize.zig+1-1
......@@ -622,7 +622,7 @@ fn legalizeBody(l: *Legalize, body_start: usize, body_len: usize) Error!void {
622622 .addrspace_cast,
623623 .save_err_return_trace_index,
624624 .vector_store_elem,
625 .tlv_dllimport_ptr,
625 .runtime_nav_ptr,
626626 .c_va_arg,
627627 .c_va_copy,
628628 .c_va_end,
src/Air/Liveness.zig+2-2
......@@ -339,7 +339,7 @@ pub fn categorizeOperand(
339339 .wasm_memory_size,
340340 .err_return_trace,
341341 .save_err_return_trace_index,
342 .tlv_dllimport_ptr,
342 .runtime_nav_ptr,
343343 .c_va_start,
344344 .work_item_id,
345345 .work_group_size,
......@@ -972,7 +972,7 @@ fn analyzeInst(
972972 .wasm_memory_size,
973973 .err_return_trace,
974974 .save_err_return_trace_index,
975 .tlv_dllimport_ptr,
975 .runtime_nav_ptr,
976976 .c_va_start,
977977 .work_item_id,
978978 .work_group_size,
src/Air/Liveness/Verify.zig+1-1
......@@ -63,7 +63,7 @@ fn verifyBody(self: *Verify, body: []const Air.Inst.Index) Error!void {
6363 .wasm_memory_size,
6464 .err_return_trace,
6565 .save_err_return_trace_index,
66 .tlv_dllimport_ptr,
66 .runtime_nav_ptr,
6767 .c_va_start,
6868 .work_item_id,
6969 .work_group_size,
src/Air/print.zig created+1041
......@@ -0,0 +1,1041 @@
1const std = @import("std");
2const Allocator = std.mem.Allocator;
3const fmtIntSizeBin = std.fmt.fmtIntSizeBin;
4
5const build_options = @import("build_options");
6const Zcu = @import("../Zcu.zig");
7const Value = @import("../Value.zig");
8const Type = @import("../Type.zig");
9const Air = @import("../Air.zig");
10const InternPool = @import("../InternPool.zig");
11
12pub fn write(air: Air, stream: anytype, pt: Zcu.PerThread, liveness: ?Air.Liveness) void {
13 comptime std.debug.assert(build_options.enable_debug_extensions);
14 const instruction_bytes = air.instructions.len *
15 // Here we don't use @sizeOf(Air.Inst.Data) because it would include
16 // the debug safety tag but we want to measure release size.
17 (@sizeOf(Air.Inst.Tag) + 8);
18 const extra_bytes = air.extra.items.len * @sizeOf(u32);
19 const tomb_bytes = if (liveness) |l| l.tomb_bits.len * @sizeOf(usize) else 0;
20 const liveness_extra_bytes = if (liveness) |l| l.extra.len * @sizeOf(u32) else 0;
21 const liveness_special_bytes = if (liveness) |l| l.special.count() * 8 else 0;
22 const total_bytes = @sizeOf(Air) + instruction_bytes + extra_bytes +
23 @sizeOf(Air.Liveness) + liveness_extra_bytes +
24 liveness_special_bytes + tomb_bytes;
25
26 // zig fmt: off
27 stream.print(
28 \\# Total AIR+Liveness bytes: {}
29 \\# AIR Instructions: {d} ({})
30 \\# AIR Extra Data: {d} ({})
31 \\# Liveness tomb_bits: {}
32 \\# Liveness Extra Data: {d} ({})
33 \\# Liveness special table: {d} ({})
34 \\
35 , .{
36 fmtIntSizeBin(total_bytes),
37 air.instructions.len, fmtIntSizeBin(instruction_bytes),
38 air.extra.items.len, fmtIntSizeBin(extra_bytes),
39 fmtIntSizeBin(tomb_bytes),
40 if (liveness) |l| l.extra.len else 0, fmtIntSizeBin(liveness_extra_bytes),
41 if (liveness) |l| l.special.count() else 0, fmtIntSizeBin(liveness_special_bytes),
42 }) catch return;
43 // zig fmt: on
44
45 var writer: Writer = .{
46 .pt = pt,
47 .gpa = pt.zcu.gpa,
48 .air = air,
49 .liveness = liveness,
50 .indent = 2,
51 .skip_body = false,
52 };
53 writer.writeBody(stream, air.getMainBody()) catch return;
54}
55
56pub fn writeInst(
57 air: Air,
58 stream: anytype,
59 inst: Air.Inst.Index,
60 pt: Zcu.PerThread,
61 liveness: ?Air.Liveness,
62) void {
63 comptime std.debug.assert(build_options.enable_debug_extensions);
64 var writer: Writer = .{
65 .pt = pt,
66 .gpa = pt.zcu.gpa,
67 .air = air,
68 .liveness = liveness,
69 .indent = 2,
70 .skip_body = true,
71 };
72 writer.writeInst(stream, inst) catch return;
73}
74
75pub fn dump(air: Air, pt: Zcu.PerThread, liveness: ?Air.Liveness) void {
76 air.write(std.io.getStdErr().writer(), pt, liveness);
77}
78
79pub fn dumpInst(air: Air, inst: Air.Inst.Index, pt: Zcu.PerThread, liveness: ?Air.Liveness) void {
80 air.writeInst(std.io.getStdErr().writer(), inst, pt, liveness);
81}
82
83const Writer = struct {
84 pt: Zcu.PerThread,
85 gpa: Allocator,
86 air: Air,
87 liveness: ?Air.Liveness,
88 indent: usize,
89 skip_body: bool,
90
91 fn writeBody(w: *Writer, s: anytype, body: []const Air.Inst.Index) @TypeOf(s).Error!void {
92 for (body) |inst| {
93 try w.writeInst(s, inst);
94 try s.writeByte('\n');
95 }
96 }
97
98 fn writeInst(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {
99 const tag = w.air.instructions.items(.tag)[@intFromEnum(inst)];
100 try s.writeByteNTimes(' ', w.indent);
101 try s.print("{}{c}= {s}(", .{
102 inst,
103 @as(u8, if (if (w.liveness) |liveness| liveness.isUnused(inst) else false) '!' else ' '),
104 @tagName(tag),
105 });
106 switch (tag) {
107 .add,
108 .add_optimized,
109 .add_safe,
110 .add_wrap,
111 .add_sat,
112 .sub,
113 .sub_optimized,
114 .sub_safe,
115 .sub_wrap,
116 .sub_sat,
117 .mul,
118 .mul_optimized,
119 .mul_safe,
120 .mul_wrap,
121 .mul_sat,
122 .div_float,
123 .div_trunc,
124 .div_floor,
125 .div_exact,
126 .rem,
127 .mod,
128 .bit_and,
129 .bit_or,
130 .xor,
131 .cmp_lt,
132 .cmp_lte,
133 .cmp_eq,
134 .cmp_gte,
135 .cmp_gt,
136 .cmp_neq,
137 .bool_and,
138 .bool_or,
139 .store,
140 .store_safe,
141 .array_elem_val,
142 .slice_elem_val,
143 .ptr_elem_val,
144 .shl,
145 .shl_exact,
146 .shl_sat,
147 .shr,
148 .shr_exact,
149 .set_union_tag,
150 .min,
151 .max,
152 .div_float_optimized,
153 .div_trunc_optimized,
154 .div_floor_optimized,
155 .div_exact_optimized,
156 .rem_optimized,
157 .mod_optimized,
158 .cmp_lt_optimized,
159 .cmp_lte_optimized,
160 .cmp_eq_optimized,
161 .cmp_gte_optimized,
162 .cmp_gt_optimized,
163 .cmp_neq_optimized,
164 .memcpy,
165 .memmove,
166 .memset,
167 .memset_safe,
168 => try w.writeBinOp(s, inst),
169
170 .is_null,
171 .is_non_null,
172 .is_null_ptr,
173 .is_non_null_ptr,
174 .is_err,
175 .is_non_err,
176 .is_err_ptr,
177 .is_non_err_ptr,
178 .ret,
179 .ret_safe,
180 .ret_load,
181 .is_named_enum_value,
182 .tag_name,
183 .error_name,
184 .sqrt,
185 .sin,
186 .cos,
187 .tan,
188 .exp,
189 .exp2,
190 .log,
191 .log2,
192 .log10,
193 .floor,
194 .ceil,
195 .round,
196 .trunc_float,
197 .neg,
198 .neg_optimized,
199 .cmp_lt_errors_len,
200 .set_err_return_trace,
201 .c_va_end,
202 => try w.writeUnOp(s, inst),
203
204 .trap,
205 .breakpoint,
206 .dbg_empty_stmt,
207 .unreach,
208 .ret_addr,
209 .frame_addr,
210 .save_err_return_trace_index,
211 => try w.writeNoOp(s, inst),
212
213 .alloc,
214 .ret_ptr,
215 .err_return_trace,
216 .c_va_start,
217 => try w.writeTy(s, inst),
218
219 .arg => try w.writeArg(s, inst),
220
221 .not,
222 .bitcast,
223 .load,
224 .fptrunc,
225 .fpext,
226 .intcast,
227 .intcast_safe,
228 .trunc,
229 .optional_payload,
230 .optional_payload_ptr,
231 .optional_payload_ptr_set,
232 .errunion_payload_ptr_set,
233 .wrap_optional,
234 .unwrap_errunion_payload,
235 .unwrap_errunion_err,
236 .unwrap_errunion_payload_ptr,
237 .unwrap_errunion_err_ptr,
238 .wrap_errunion_payload,
239 .wrap_errunion_err,
240 .slice_ptr,
241 .slice_len,
242 .ptr_slice_len_ptr,
243 .ptr_slice_ptr_ptr,
244 .struct_field_ptr_index_0,
245 .struct_field_ptr_index_1,
246 .struct_field_ptr_index_2,
247 .struct_field_ptr_index_3,
248 .array_to_slice,
249 .float_from_int,
250 .splat,
251 .int_from_float,
252 .int_from_float_optimized,
253 .get_union_tag,
254 .clz,
255 .ctz,
256 .popcount,
257 .byte_swap,
258 .bit_reverse,
259 .abs,
260 .error_set_has_value,
261 .addrspace_cast,
262 .c_va_arg,
263 .c_va_copy,
264 => try w.writeTyOp(s, inst),
265
266 .block, .dbg_inline_block => try w.writeBlock(s, tag, inst),
267
268 .loop => try w.writeLoop(s, inst),
269
270 .slice,
271 .slice_elem_ptr,
272 .ptr_elem_ptr,
273 .ptr_add,
274 .ptr_sub,
275 .add_with_overflow,
276 .sub_with_overflow,
277 .mul_with_overflow,
278 .shl_with_overflow,
279 => try w.writeTyPlBin(s, inst),
280
281 .call,
282 .call_always_tail,
283 .call_never_tail,
284 .call_never_inline,
285 => try w.writeCall(s, inst),
286
287 .dbg_var_ptr,
288 .dbg_var_val,
289 .dbg_arg_inline,
290 => try w.writeDbgVar(s, inst),
291
292 .struct_field_ptr => try w.writeStructField(s, inst),
293 .struct_field_val => try w.writeStructField(s, inst),
294 .inferred_alloc => @panic("TODO"),
295 .inferred_alloc_comptime => @panic("TODO"),
296 .assembly => try w.writeAssembly(s, inst),
297 .dbg_stmt => try w.writeDbgStmt(s, inst),
298
299 .aggregate_init => try w.writeAggregateInit(s, inst),
300 .union_init => try w.writeUnionInit(s, inst),
301 .br => try w.writeBr(s, inst),
302 .switch_dispatch => try w.writeBr(s, inst),
303 .repeat => try w.writeRepeat(s, inst),
304 .cond_br => try w.writeCondBr(s, inst),
305 .@"try", .try_cold => try w.writeTry(s, inst),
306 .try_ptr, .try_ptr_cold => try w.writeTryPtr(s, inst),
307 .loop_switch_br, .switch_br => try w.writeSwitchBr(s, inst),
308 .cmpxchg_weak, .cmpxchg_strong => try w.writeCmpxchg(s, inst),
309 .atomic_load => try w.writeAtomicLoad(s, inst),
310 .prefetch => try w.writePrefetch(s, inst),
311 .atomic_store_unordered => try w.writeAtomicStore(s, inst, .unordered),
312 .atomic_store_monotonic => try w.writeAtomicStore(s, inst, .monotonic),
313 .atomic_store_release => try w.writeAtomicStore(s, inst, .release),
314 .atomic_store_seq_cst => try w.writeAtomicStore(s, inst, .seq_cst),
315 .atomic_rmw => try w.writeAtomicRmw(s, inst),
316 .field_parent_ptr => try w.writeFieldParentPtr(s, inst),
317 .wasm_memory_size => try w.writeWasmMemorySize(s, inst),
318 .wasm_memory_grow => try w.writeWasmMemoryGrow(s, inst),
319 .mul_add => try w.writeMulAdd(s, inst),
320 .select => try w.writeSelect(s, inst),
321 .shuffle_one => try w.writeShuffleOne(s, inst),
322 .shuffle_two => try w.writeShuffleTwo(s, inst),
323 .reduce, .reduce_optimized => try w.writeReduce(s, inst),
324 .cmp_vector, .cmp_vector_optimized => try w.writeCmpVector(s, inst),
325 .vector_store_elem => try w.writeVectorStoreElem(s, inst),
326 .runtime_nav_ptr => try w.writeRuntimeNavPtr(s, inst),
327
328 .work_item_id,
329 .work_group_size,
330 .work_group_id,
331 => try w.writeWorkDimension(s, inst),
332 }
333 try s.writeByte(')');
334 }
335
336 fn writeBinOp(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {
337 const bin_op = w.air.instructions.items(.data)[@intFromEnum(inst)].bin_op;
338 try w.writeOperand(s, inst, 0, bin_op.lhs);
339 try s.writeAll(", ");
340 try w.writeOperand(s, inst, 1, bin_op.rhs);
341 }
342
343 fn writeUnOp(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {
344 const un_op = w.air.instructions.items(.data)[@intFromEnum(inst)].un_op;
345 try w.writeOperand(s, inst, 0, un_op);
346 }
347
348 fn writeNoOp(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {
349 _ = w;
350 _ = inst;
351 // no-op, no argument to write
352 }
353
354 fn writeType(w: *Writer, s: anytype, ty: Type) !void {
355 return ty.print(s, w.pt);
356 }
357
358 fn writeTy(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {
359 const ty = w.air.instructions.items(.data)[@intFromEnum(inst)].ty;
360 try w.writeType(s, ty);
361 }
362
363 fn writeArg(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {
364 const arg = w.air.instructions.items(.data)[@intFromEnum(inst)].arg;
365 try w.writeType(s, arg.ty.toType());
366 switch (arg.name) {
367 .none => {},
368 _ => try s.print(", \"{}\"", .{std.zig.fmtEscapes(arg.name.toSlice(w.air))}),
369 }
370 }
371
372 fn writeTyOp(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {
373 const ty_op = w.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;
374 try w.writeType(s, ty_op.ty.toType());
375 try s.writeAll(", ");
376 try w.writeOperand(s, inst, 0, ty_op.operand);
377 }
378
379 fn writeBlock(w: *Writer, s: anytype, tag: Air.Inst.Tag, inst: Air.Inst.Index) @TypeOf(s).Error!void {
380 const ty_pl = w.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;
381 try w.writeType(s, ty_pl.ty.toType());
382 const body: []const Air.Inst.Index = @ptrCast(switch (tag) {
383 inline .block, .dbg_inline_block => |comptime_tag| body: {
384 const extra = w.air.extraData(switch (comptime_tag) {
385 .block => Air.Block,
386 .dbg_inline_block => Air.DbgInlineBlock,
387 else => unreachable,
388 }, ty_pl.payload);
389 switch (comptime_tag) {
390 .block => {},
391 .dbg_inline_block => {
392 try s.writeAll(", ");
393 try w.writeInstRef(s, Air.internedToRef(extra.data.func), false);
394 },
395 else => unreachable,
396 }
397 break :body w.air.extra.items[extra.end..][0..extra.data.body_len];
398 },
399 else => unreachable,
400 });
401 if (w.skip_body) return s.writeAll(", ...");
402 const liveness_block: Air.Liveness.BlockSlices = if (w.liveness) |liveness|
403 liveness.getBlock(inst)
404 else
405 .{ .deaths = &.{} };
406
407 try s.writeAll(", {\n");
408 const old_indent = w.indent;
409 w.indent += 2;
410 try w.writeBody(s, body);
411 w.indent = old_indent;
412 try s.writeByteNTimes(' ', w.indent);
413 try s.writeAll("}");
414
415 for (liveness_block.deaths) |operand| {
416 try s.print(" {}!", .{operand});
417 }
418 }
419
420 fn writeLoop(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {
421 const ty_pl = w.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;
422 const extra = w.air.extraData(Air.Block, ty_pl.payload);
423 const body: []const Air.Inst.Index = @ptrCast(w.air.extra.items[extra.end..][0..extra.data.body_len]);
424
425 try w.writeType(s, ty_pl.ty.toType());
426 if (w.skip_body) return s.writeAll(", ...");
427 try s.writeAll(", {\n");
428 const old_indent = w.indent;
429 w.indent += 2;
430 try w.writeBody(s, body);
431 w.indent = old_indent;
432 try s.writeByteNTimes(' ', w.indent);
433 try s.writeAll("}");
434 }
435
436 fn writeAggregateInit(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {
437 const zcu = w.pt.zcu;
438 const ty_pl = w.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;
439 const vector_ty = ty_pl.ty.toType();
440 const len = @as(usize, @intCast(vector_ty.arrayLen(zcu)));
441 const elements = @as([]const Air.Inst.Ref, @ptrCast(w.air.extra.items[ty_pl.payload..][0..len]));
442
443 try w.writeType(s, vector_ty);
444 try s.writeAll(", [");
445 for (elements, 0..) |elem, i| {
446 if (i != 0) try s.writeAll(", ");
447 try w.writeOperand(s, inst, i, elem);
448 }
449 try s.writeAll("]");
450 }
451
452 fn writeUnionInit(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {
453 const ty_pl = w.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;
454 const extra = w.air.extraData(Air.UnionInit, ty_pl.payload).data;
455
456 try s.print("{d}, ", .{extra.field_index});
457 try w.writeOperand(s, inst, 0, extra.init);
458 }
459
460 fn writeStructField(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {
461 const ty_pl = w.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;
462 const extra = w.air.extraData(Air.StructField, ty_pl.payload).data;
463
464 try w.writeOperand(s, inst, 0, extra.struct_operand);
465 try s.print(", {d}", .{extra.field_index});
466 }
467
468 fn writeTyPlBin(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {
469 const data = w.air.instructions.items(.data);
470 const ty_pl = data[@intFromEnum(inst)].ty_pl;
471 const extra = w.air.extraData(Air.Bin, ty_pl.payload).data;
472
473 const inst_ty = data[@intFromEnum(inst)].ty_pl.ty.toType();
474 try w.writeType(s, inst_ty);
475 try s.writeAll(", ");
476 try w.writeOperand(s, inst, 0, extra.lhs);
477 try s.writeAll(", ");
478 try w.writeOperand(s, inst, 1, extra.rhs);
479 }
480
481 fn writeCmpxchg(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {
482 const ty_pl = w.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;
483 const extra = w.air.extraData(Air.Cmpxchg, ty_pl.payload).data;
484
485 try w.writeOperand(s, inst, 0, extra.ptr);
486 try s.writeAll(", ");
487 try w.writeOperand(s, inst, 1, extra.expected_value);
488 try s.writeAll(", ");
489 try w.writeOperand(s, inst, 2, extra.new_value);
490 try s.print(", {s}, {s}", .{
491 @tagName(extra.successOrder()), @tagName(extra.failureOrder()),
492 });
493 }
494
495 fn writeMulAdd(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {
496 const pl_op = w.air.instructions.items(.data)[@intFromEnum(inst)].pl_op;
497 const extra = w.air.extraData(Air.Bin, pl_op.payload).data;
498
499 try w.writeOperand(s, inst, 0, extra.lhs);
500 try s.writeAll(", ");
501 try w.writeOperand(s, inst, 1, extra.rhs);
502 try s.writeAll(", ");
503 try w.writeOperand(s, inst, 2, pl_op.operand);
504 }
505
506 fn writeShuffleOne(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {
507 const unwrapped = w.air.unwrapShuffleOne(w.pt.zcu, inst);
508 try w.writeType(s, unwrapped.result_ty);
509 try s.writeAll(", ");
510 try w.writeOperand(s, inst, 0, unwrapped.operand);
511 try s.writeAll(", [");
512 for (unwrapped.mask, 0..) |mask_elem, mask_idx| {
513 if (mask_idx > 0) try s.writeAll(", ");
514 switch (mask_elem.unwrap()) {
515 .elem => |idx| try s.print("elem {d}", .{idx}),
516 .value => |val| try s.print("val {}", .{Value.fromInterned(val).fmtValue(w.pt)}),
517 }
518 }
519 try s.writeByte(']');
520 }
521
522 fn writeShuffleTwo(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {
523 const unwrapped = w.air.unwrapShuffleTwo(w.pt.zcu, inst);
524 try w.writeType(s, unwrapped.result_ty);
525 try s.writeAll(", ");
526 try w.writeOperand(s, inst, 0, unwrapped.operand_a);
527 try s.writeAll(", ");
528 try w.writeOperand(s, inst, 1, unwrapped.operand_b);
529 try s.writeAll(", [");
530 for (unwrapped.mask, 0..) |mask_elem, mask_idx| {
531 if (mask_idx > 0) try s.writeAll(", ");
532 switch (mask_elem.unwrap()) {
533 .a_elem => |idx| try s.print("a_elem {d}", .{idx}),
534 .b_elem => |idx| try s.print("b_elem {d}", .{idx}),
535 .undef => try s.writeAll("undef"),
536 }
537 }
538 try s.writeByte(']');
539 }
540
541 fn writeSelect(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {
542 const zcu = w.pt.zcu;
543 const pl_op = w.air.instructions.items(.data)[@intFromEnum(inst)].pl_op;
544 const extra = w.air.extraData(Air.Bin, pl_op.payload).data;
545
546 const elem_ty = w.typeOfIndex(inst).childType(zcu);
547 try w.writeType(s, elem_ty);
548 try s.writeAll(", ");
549 try w.writeOperand(s, inst, 0, pl_op.operand);
550 try s.writeAll(", ");
551 try w.writeOperand(s, inst, 1, extra.lhs);
552 try s.writeAll(", ");
553 try w.writeOperand(s, inst, 2, extra.rhs);
554 }
555
556 fn writeReduce(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {
557 const reduce = w.air.instructions.items(.data)[@intFromEnum(inst)].reduce;
558
559 try w.writeOperand(s, inst, 0, reduce.operand);
560 try s.print(", {s}", .{@tagName(reduce.operation)});
561 }
562
563 fn writeCmpVector(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {
564 const ty_pl = w.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;
565 const extra = w.air.extraData(Air.VectorCmp, ty_pl.payload).data;
566
567 try s.print("{s}, ", .{@tagName(extra.compareOperator())});
568 try w.writeOperand(s, inst, 0, extra.lhs);
569 try s.writeAll(", ");
570 try w.writeOperand(s, inst, 1, extra.rhs);
571 }
572
573 fn writeVectorStoreElem(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {
574 const data = w.air.instructions.items(.data)[@intFromEnum(inst)].vector_store_elem;
575 const extra = w.air.extraData(Air.VectorCmp, data.payload).data;
576
577 try w.writeOperand(s, inst, 0, data.vector_ptr);
578 try s.writeAll(", ");
579 try w.writeOperand(s, inst, 1, extra.lhs);
580 try s.writeAll(", ");
581 try w.writeOperand(s, inst, 2, extra.rhs);
582 }
583
584 fn writeRuntimeNavPtr(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {
585 const ip = &w.pt.zcu.intern_pool;
586 const ty_nav = w.air.instructions.items(.data)[@intFromEnum(inst)].ty_nav;
587 try w.writeType(s, .fromInterned(ty_nav.ty));
588 try s.print(", '{}'", .{ip.getNav(ty_nav.nav).fqn.fmt(ip)});
589 }
590
591 fn writeAtomicLoad(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {
592 const atomic_load = w.air.instructions.items(.data)[@intFromEnum(inst)].atomic_load;
593
594 try w.writeOperand(s, inst, 0, atomic_load.ptr);
595 try s.print(", {s}", .{@tagName(atomic_load.order)});
596 }
597
598 fn writePrefetch(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {
599 const prefetch = w.air.instructions.items(.data)[@intFromEnum(inst)].prefetch;
600
601 try w.writeOperand(s, inst, 0, prefetch.ptr);
602 try s.print(", {s}, {d}, {s}", .{
603 @tagName(prefetch.rw), prefetch.locality, @tagName(prefetch.cache),
604 });
605 }
606
607 fn writeAtomicStore(
608 w: *Writer,
609 s: anytype,
610 inst: Air.Inst.Index,
611 order: std.builtin.AtomicOrder,
612 ) @TypeOf(s).Error!void {
613 const bin_op = w.air.instructions.items(.data)[@intFromEnum(inst)].bin_op;
614 try w.writeOperand(s, inst, 0, bin_op.lhs);
615 try s.writeAll(", ");
616 try w.writeOperand(s, inst, 1, bin_op.rhs);
617 try s.print(", {s}", .{@tagName(order)});
618 }
619
620 fn writeAtomicRmw(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {
621 const pl_op = w.air.instructions.items(.data)[@intFromEnum(inst)].pl_op;
622 const extra = w.air.extraData(Air.AtomicRmw, pl_op.payload).data;
623
624 try w.writeOperand(s, inst, 0, pl_op.operand);
625 try s.writeAll(", ");
626 try w.writeOperand(s, inst, 1, extra.operand);
627 try s.print(", {s}, {s}", .{ @tagName(extra.op()), @tagName(extra.ordering()) });
628 }
629
630 fn writeFieldParentPtr(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {
631 const ty_pl = w.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;
632 const extra = w.air.extraData(Air.FieldParentPtr, ty_pl.payload).data;
633
634 try w.writeOperand(s, inst, 0, extra.field_ptr);
635 try s.print(", {d}", .{extra.field_index});
636 }
637
638 fn writeAssembly(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {
639 const ty_pl = w.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;
640 const extra = w.air.extraData(Air.Asm, ty_pl.payload);
641 const is_volatile = @as(u1, @truncate(extra.data.flags >> 31)) != 0;
642 const clobbers_len = @as(u31, @truncate(extra.data.flags));
643 var extra_i: usize = extra.end;
644 var op_index: usize = 0;
645
646 const ret_ty = w.typeOfIndex(inst);
647 try w.writeType(s, ret_ty);
648
649 if (is_volatile) {
650 try s.writeAll(", volatile");
651 }
652
653 const outputs = @as([]const Air.Inst.Ref, @ptrCast(w.air.extra.items[extra_i..][0..extra.data.outputs_len]));
654 extra_i += outputs.len;
655 const inputs = @as([]const Air.Inst.Ref, @ptrCast(w.air.extra.items[extra_i..][0..extra.data.inputs_len]));
656 extra_i += inputs.len;
657
658 for (outputs) |output| {
659 const extra_bytes = std.mem.sliceAsBytes(w.air.extra.items[extra_i..]);
660 const constraint = std.mem.sliceTo(extra_bytes, 0);
661 const name = std.mem.sliceTo(extra_bytes[constraint.len + 1 ..], 0);
662
663 // This equation accounts for the fact that even if we have exactly 4 bytes
664 // for the strings and their null terminators, we still use the next u32
665 // for the null terminator.
666 extra_i += (constraint.len + name.len + (2 + 3)) / 4;
667
668 if (output == .none) {
669 try s.print(", [{s}] -> {s}", .{ name, constraint });
670 } else {
671 try s.print(", [{s}] out {s} = (", .{ name, constraint });
672 try w.writeOperand(s, inst, op_index, output);
673 op_index += 1;
674 try s.writeByte(')');
675 }
676 }
677
678 for (inputs) |input| {
679 const extra_bytes = std.mem.sliceAsBytes(w.air.extra.items[extra_i..]);
680 const constraint = std.mem.sliceTo(extra_bytes, 0);
681 const name = std.mem.sliceTo(extra_bytes[constraint.len + 1 ..], 0);
682 // This equation accounts for the fact that even if we have exactly 4 bytes
683 // for the strings and their null terminators, we still use the next u32
684 // for the null terminator.
685 extra_i += (constraint.len + name.len + 1) / 4 + 1;
686
687 try s.print(", [{s}] in {s} = (", .{ name, constraint });
688 try w.writeOperand(s, inst, op_index, input);
689 op_index += 1;
690 try s.writeByte(')');
691 }
692
693 {
694 var clobber_i: u32 = 0;
695 while (clobber_i < clobbers_len) : (clobber_i += 1) {
696 const extra_bytes = std.mem.sliceAsBytes(w.air.extra.items[extra_i..]);
697 const clobber = std.mem.sliceTo(extra_bytes, 0);
698 // This equation accounts for the fact that even if we have exactly 4 bytes
699 // for the string, we still use the next u32 for the null terminator.
700 extra_i += clobber.len / 4 + 1;
701
702 try s.writeAll(", ~{");
703 try s.writeAll(clobber);
704 try s.writeAll("}");
705 }
706 }
707 const asm_source = std.mem.sliceAsBytes(w.air.extra.items[extra_i..])[0..extra.data.source_len];
708 try s.print(", \"{}\"", .{std.zig.fmtEscapes(asm_source)});
709 }
710
711 fn writeDbgStmt(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {
712 const dbg_stmt = w.air.instructions.items(.data)[@intFromEnum(inst)].dbg_stmt;
713 try s.print("{d}:{d}", .{ dbg_stmt.line + 1, dbg_stmt.column + 1 });
714 }
715
716 fn writeDbgVar(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {
717 const pl_op = w.air.instructions.items(.data)[@intFromEnum(inst)].pl_op;
718 try w.writeOperand(s, inst, 0, pl_op.operand);
719 const name: Air.NullTerminatedString = @enumFromInt(pl_op.payload);
720 try s.print(", \"{}\"", .{std.zig.fmtEscapes(name.toSlice(w.air))});
721 }
722
723 fn writeCall(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {
724 const pl_op = w.air.instructions.items(.data)[@intFromEnum(inst)].pl_op;
725 const extra = w.air.extraData(Air.Call, pl_op.payload);
726 const args = @as([]const Air.Inst.Ref, @ptrCast(w.air.extra.items[extra.end..][0..extra.data.args_len]));
727 try w.writeOperand(s, inst, 0, pl_op.operand);
728 try s.writeAll(", [");
729 for (args, 0..) |arg, i| {
730 if (i != 0) try s.writeAll(", ");
731 try w.writeOperand(s, inst, 1 + i, arg);
732 }
733 try s.writeAll("]");
734 }
735
736 fn writeBr(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {
737 const br = w.air.instructions.items(.data)[@intFromEnum(inst)].br;
738 try w.writeInstIndex(s, br.block_inst, false);
739 try s.writeAll(", ");
740 try w.writeOperand(s, inst, 0, br.operand);
741 }
742
743 fn writeRepeat(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {
744 const repeat = w.air.instructions.items(.data)[@intFromEnum(inst)].repeat;
745 try w.writeInstIndex(s, repeat.loop_inst, false);
746 }
747
748 fn writeTry(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {
749 const pl_op = w.air.instructions.items(.data)[@intFromEnum(inst)].pl_op;
750 const extra = w.air.extraData(Air.Try, pl_op.payload);
751 const body: []const Air.Inst.Index = @ptrCast(w.air.extra.items[extra.end..][0..extra.data.body_len]);
752 const liveness_condbr: Air.Liveness.CondBrSlices = if (w.liveness) |liveness|
753 liveness.getCondBr(inst)
754 else
755 .{ .then_deaths = &.{}, .else_deaths = &.{} };
756
757 try w.writeOperand(s, inst, 0, pl_op.operand);
758 if (w.skip_body) return s.writeAll(", ...");
759 try s.writeAll(", {\n");
760 const old_indent = w.indent;
761 w.indent += 2;
762
763 if (liveness_condbr.else_deaths.len != 0) {
764 try s.writeByteNTimes(' ', w.indent);
765 for (liveness_condbr.else_deaths, 0..) |operand, i| {
766 if (i != 0) try s.writeAll(" ");
767 try s.print("{}!", .{operand});
768 }
769 try s.writeAll("\n");
770 }
771 try w.writeBody(s, body);
772
773 w.indent = old_indent;
774 try s.writeByteNTimes(' ', w.indent);
775 try s.writeAll("}");
776
777 for (liveness_condbr.then_deaths) |operand| {
778 try s.print(" {}!", .{operand});
779 }
780 }
781
782 fn writeTryPtr(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {
783 const ty_pl = w.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;
784 const extra = w.air.extraData(Air.TryPtr, ty_pl.payload);
785 const body: []const Air.Inst.Index = @ptrCast(w.air.extra.items[extra.end..][0..extra.data.body_len]);
786 const liveness_condbr: Air.Liveness.CondBrSlices = if (w.liveness) |liveness|
787 liveness.getCondBr(inst)
788 else
789 .{ .then_deaths = &.{}, .else_deaths = &.{} };
790
791 try w.writeOperand(s, inst, 0, extra.data.ptr);
792
793 try s.writeAll(", ");
794 try w.writeType(s, ty_pl.ty.toType());
795 if (w.skip_body) return s.writeAll(", ...");
796 try s.writeAll(", {\n");
797 const old_indent = w.indent;
798 w.indent += 2;
799
800 if (liveness_condbr.else_deaths.len != 0) {
801 try s.writeByteNTimes(' ', w.indent);
802 for (liveness_condbr.else_deaths, 0..) |operand, i| {
803 if (i != 0) try s.writeAll(" ");
804 try s.print("{}!", .{operand});
805 }
806 try s.writeAll("\n");
807 }
808 try w.writeBody(s, body);
809
810 w.indent = old_indent;
811 try s.writeByteNTimes(' ', w.indent);
812 try s.writeAll("}");
813
814 for (liveness_condbr.then_deaths) |operand| {
815 try s.print(" {}!", .{operand});
816 }
817 }
818
819 fn writeCondBr(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {
820 const pl_op = w.air.instructions.items(.data)[@intFromEnum(inst)].pl_op;
821 const extra = w.air.extraData(Air.CondBr, pl_op.payload);
822 const then_body: []const Air.Inst.Index = @ptrCast(w.air.extra.items[extra.end..][0..extra.data.then_body_len]);
823 const else_body: []const Air.Inst.Index = @ptrCast(w.air.extra.items[extra.end + then_body.len ..][0..extra.data.else_body_len]);
824 const liveness_condbr: Air.Liveness.CondBrSlices = if (w.liveness) |liveness|
825 liveness.getCondBr(inst)
826 else
827 .{ .then_deaths = &.{}, .else_deaths = &.{} };
828
829 try w.writeOperand(s, inst, 0, pl_op.operand);
830 if (w.skip_body) return s.writeAll(", ...");
831 try s.writeAll(",");
832 if (extra.data.branch_hints.true != .none) {
833 try s.print(" {s}", .{@tagName(extra.data.branch_hints.true)});
834 }
835 if (extra.data.branch_hints.then_cov != .none) {
836 try s.print(" {s}", .{@tagName(extra.data.branch_hints.then_cov)});
837 }
838 try s.writeAll(" {\n");
839 const old_indent = w.indent;
840 w.indent += 2;
841
842 if (liveness_condbr.then_deaths.len != 0) {
843 try s.writeByteNTimes(' ', w.indent);
844 for (liveness_condbr.then_deaths, 0..) |operand, i| {
845 if (i != 0) try s.writeAll(" ");
846 try s.print("{}!", .{operand});
847 }
848 try s.writeAll("\n");
849 }
850
851 try w.writeBody(s, then_body);
852 try s.writeByteNTimes(' ', old_indent);
853 try s.writeAll("},");
854 if (extra.data.branch_hints.false != .none) {
855 try s.print(" {s}", .{@tagName(extra.data.branch_hints.false)});
856 }
857 if (extra.data.branch_hints.else_cov != .none) {
858 try s.print(" {s}", .{@tagName(extra.data.branch_hints.else_cov)});
859 }
860 try s.writeAll(" {\n");
861
862 if (liveness_condbr.else_deaths.len != 0) {
863 try s.writeByteNTimes(' ', w.indent);
864 for (liveness_condbr.else_deaths, 0..) |operand, i| {
865 if (i != 0) try s.writeAll(" ");
866 try s.print("{}!", .{operand});
867 }
868 try s.writeAll("\n");
869 }
870
871 try w.writeBody(s, else_body);
872 w.indent = old_indent;
873
874 try s.writeByteNTimes(' ', old_indent);
875 try s.writeAll("}");
876 }
877
878 fn writeSwitchBr(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {
879 const switch_br = w.air.unwrapSwitch(inst);
880
881 const liveness: Air.Liveness.SwitchBrTable = if (w.liveness) |liveness|
882 liveness.getSwitchBr(w.gpa, inst, switch_br.cases_len + 1) catch
883 @panic("out of memory")
884 else blk: {
885 const slice = w.gpa.alloc([]const Air.Inst.Index, switch_br.cases_len + 1) catch
886 @panic("out of memory");
887 @memset(slice, &.{});
888 break :blk .{ .deaths = slice };
889 };
890 defer w.gpa.free(liveness.deaths);
891
892 try w.writeOperand(s, inst, 0, switch_br.operand);
893 if (w.skip_body) return s.writeAll(", ...");
894 const old_indent = w.indent;
895 w.indent += 2;
896
897 var it = switch_br.iterateCases();
898 while (it.next()) |case| {
899 try s.writeAll(", [");
900 for (case.items, 0..) |item, item_i| {
901 if (item_i != 0) try s.writeAll(", ");
902 try w.writeInstRef(s, item, false);
903 }
904 for (case.ranges, 0..) |range, range_i| {
905 if (range_i != 0 or case.items.len != 0) try s.writeAll(", ");
906 try w.writeInstRef(s, range[0], false);
907 try s.writeAll("...");
908 try w.writeInstRef(s, range[1], false);
909 }
910 try s.writeAll("] ");
911 const hint = switch_br.getHint(case.idx);
912 if (hint != .none) {
913 try s.print(".{s} ", .{@tagName(hint)});
914 }
915 try s.writeAll("=> {\n");
916 w.indent += 2;
917
918 const deaths = liveness.deaths[case.idx];
919 if (deaths.len != 0) {
920 try s.writeByteNTimes(' ', w.indent);
921 for (deaths, 0..) |operand, i| {
922 if (i != 0) try s.writeAll(" ");
923 try s.print("{}!", .{operand});
924 }
925 try s.writeAll("\n");
926 }
927
928 try w.writeBody(s, case.body);
929 w.indent -= 2;
930 try s.writeByteNTimes(' ', w.indent);
931 try s.writeAll("}");
932 }
933
934 const else_body = it.elseBody();
935 if (else_body.len != 0) {
936 try s.writeAll(", else ");
937 const hint = switch_br.getElseHint();
938 if (hint != .none) {
939 try s.print(".{s} ", .{@tagName(hint)});
940 }
941 try s.writeAll("=> {\n");
942 w.indent += 2;
943
944 const deaths = liveness.deaths[liveness.deaths.len - 1];
945 if (deaths.len != 0) {
946 try s.writeByteNTimes(' ', w.indent);
947 for (deaths, 0..) |operand, i| {
948 if (i != 0) try s.writeAll(" ");
949 try s.print("{}!", .{operand});
950 }
951 try s.writeAll("\n");
952 }
953
954 try w.writeBody(s, else_body);
955 w.indent -= 2;
956 try s.writeByteNTimes(' ', w.indent);
957 try s.writeAll("}");
958 }
959
960 try s.writeAll("\n");
961 try s.writeByteNTimes(' ', old_indent);
962 }
963
964 fn writeWasmMemorySize(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {
965 const pl_op = w.air.instructions.items(.data)[@intFromEnum(inst)].pl_op;
966 try s.print("{d}", .{pl_op.payload});
967 }
968
969 fn writeWasmMemoryGrow(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {
970 const pl_op = w.air.instructions.items(.data)[@intFromEnum(inst)].pl_op;
971 try s.print("{d}, ", .{pl_op.payload});
972 try w.writeOperand(s, inst, 0, pl_op.operand);
973 }
974
975 fn writeWorkDimension(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {
976 const pl_op = w.air.instructions.items(.data)[@intFromEnum(inst)].pl_op;
977 try s.print("{d}", .{pl_op.payload});
978 }
979
980 fn writeOperand(
981 w: *Writer,
982 s: anytype,
983 inst: Air.Inst.Index,
984 op_index: usize,
985 operand: Air.Inst.Ref,
986 ) @TypeOf(s).Error!void {
987 const small_tomb_bits = Air.Liveness.bpi - 1;
988 const dies = if (w.liveness) |liveness| blk: {
989 if (op_index < small_tomb_bits)
990 break :blk liveness.operandDies(inst, @intCast(op_index));
991 var extra_index = liveness.special.get(inst).?;
992 var tomb_op_index: usize = small_tomb_bits;
993 while (true) {
994 const bits = liveness.extra[extra_index];
995 if (op_index < tomb_op_index + 31) {
996 break :blk @as(u1, @truncate(bits >> @as(u5, @intCast(op_index - tomb_op_index)))) != 0;
997 }
998 if ((bits >> 31) != 0) break :blk false;
999 extra_index += 1;
1000 tomb_op_index += 31;
1001 }
1002 } else false;
1003 return w.writeInstRef(s, operand, dies);
1004 }
1005
1006 fn writeInstRef(
1007 w: *Writer,
1008 s: anytype,
1009 operand: Air.Inst.Ref,
1010 dies: bool,
1011 ) @TypeOf(s).Error!void {
1012 if (@intFromEnum(operand) < InternPool.static_len) {
1013 return s.print("@{}", .{operand});
1014 } else if (operand.toInterned()) |ip_index| {
1015 const pt = w.pt;
1016 const ty = Type.fromInterned(pt.zcu.intern_pool.indexToKey(ip_index).typeOf());
1017 try s.print("<{}, {}>", .{
1018 ty.fmt(pt),
1019 Value.fromInterned(ip_index).fmtValue(pt),
1020 });
1021 } else {
1022 return w.writeInstIndex(s, operand.toIndex().?, dies);
1023 }
1024 }
1025
1026 fn writeInstIndex(
1027 w: *Writer,
1028 s: anytype,
1029 inst: Air.Inst.Index,
1030 dies: bool,
1031 ) @TypeOf(s).Error!void {
1032 _ = w;
1033 try s.print("{}", .{inst});
1034 if (dies) try s.writeByte('!');
1035 }
1036
1037 fn typeOfIndex(w: *Writer, inst: Air.Inst.Index) Type {
1038 const zcu = w.pt.zcu;
1039 return w.air.typeOfIndex(inst, &zcu.intern_pool);
1040 }
1041};
src/Air/types_resolved.zig+1-1
......@@ -321,7 +321,7 @@ fn checkBody(air: Air, body: []const Air.Inst.Index, zcu: *Zcu) bool {
321321 if (!checkRef(bin.rhs, zcu)) return false;
322322 },
323323
324 .tlv_dllimport_ptr => {
324 .runtime_nav_ptr => {
325325 if (!checkType(.fromInterned(data.ty_nav.ty), zcu)) return false;
326326 },
327327
src/Compilation/Config.zig+19-12
......@@ -345,11 +345,19 @@ pub fn resolve(options: Options) ResolveError!Config {
345345 } else false;
346346 };
347347
348 const is_dyn_lib = switch (options.output_mode) {
349 .Obj, .Exe => false,
350 .Lib => link_mode == .dynamic,
351 };
352
348353 // Make a decision on whether to use LLVM backend for machine code generation.
349354 // Note that using the LLVM backend does not necessarily mean using LLVM libraries.
350355 // For example, Zig can emit .bc and .ll files directly, and this is still considered
351356 // using "the LLVM backend".
352 const prefer_llvm = b: {
357 const use_llvm = b: {
358 // If we have no zig code to compile, no need for LLVM.
359 if (!options.have_zcu) break :b false;
360
353361 // If emitting to LLVM bitcode object format, must use LLVM backend.
354362 if (options.emit_llvm_ir or options.emit_llvm_bc) {
355363 if (options.use_llvm == false)
......@@ -382,9 +390,9 @@ pub fn resolve(options: Options) ResolveError!Config {
382390 // Prefer LLVM for release builds.
383391 if (root_optimize_mode != .Debug) break :b true;
384392
385 // Self-hosted backends can't handle the inline assembly in std.pie yet
386 // https://github.com/ziglang/zig/issues/24046
387 if (pie) break :b true;
393 // load_dynamic_library standalone test not passing on this combination
394 // https://github.com/ziglang/zig/issues/24080
395 if (target.os.tag == .macos and is_dyn_lib) break :b true;
388396
389397 // At this point we would prefer to use our own self-hosted backend,
390398 // because the compilation speed is better than LLVM. But only do it if
......@@ -392,13 +400,6 @@ pub fn resolve(options: Options) ResolveError!Config {
392400 break :b !target_util.selfHostedBackendIsAsRobustAsLlvm(target);
393401 };
394402
395 const use_llvm = b: {
396 // If we have no zig code to compile, no need for LLVM.
397 if (!options.have_zcu) break :b false;
398
399 break :b prefer_llvm;
400 };
401
402403 if (options.emit_bin and options.have_zcu) {
403404 if (!use_lib_llvm and use_llvm) {
404405 // Explicit request to use LLVM to produce an object file, but without
......@@ -435,7 +436,13 @@ pub fn resolve(options: Options) ResolveError!Config {
435436 }
436437
437438 if (options.use_lld) |x| break :b x;
438 break :b prefer_llvm;
439
440 // If we have no zig code to compile, no need for the self-hosted linker.
441 if (!options.have_zcu) break :b true;
442
443 // If we do have zig code, match the decision for whether to use the llvm backend,
444 // so that the llvm backend defaults to lld and the self-hosted backends do not.
445 break :b use_llvm;
439446 };
440447
441448 const lto: std.zig.LtoMode = b: {
src/InternPool.zig+71-49
......@@ -526,10 +526,10 @@ pub const Nav = struct {
526526 /// The type of this `Nav` is resolved; the value is queued for resolution.
527527 type_resolved: struct {
528528 type: InternPool.Index,
529 is_const: bool,
529530 alignment: Alignment,
530531 @"linksection": OptionalNullTerminatedString,
531532 @"addrspace": std.builtin.AddressSpace,
532 is_const: bool,
533533 is_threadlocal: bool,
534534 /// This field is whether this `Nav` is a literal `extern` definition.
535535 /// It does *not* tell you whether this might alias an extern fn (see #21027).
......@@ -538,6 +538,7 @@ pub const Nav = struct {
538538 /// The value of this `Nav` is resolved.
539539 fully_resolved: struct {
540540 val: InternPool.Index,
541 is_const: bool,
541542 alignment: Alignment,
542543 @"linksection": OptionalNullTerminatedString,
543544 @"addrspace": std.builtin.AddressSpace,
......@@ -727,12 +728,12 @@ pub const Nav = struct {
727728 const Bits = packed struct(u16) {
728729 status: enum(u2) { unresolved, type_resolved, fully_resolved, type_resolved_extern_decl },
729730 /// Populated only if `bits.status != .unresolved`.
731 is_const: bool,
732 /// Populated only if `bits.status != .unresolved`.
730733 alignment: Alignment,
731734 /// Populated only if `bits.status != .unresolved`.
732735 @"addrspace": std.builtin.AddressSpace,
733736 /// Populated only if `bits.status == .type_resolved`.
734 is_const: bool,
735 /// Populated only if `bits.status == .type_resolved`.
736737 is_threadlocal: bool,
737738 is_usingnamespace: bool,
738739 };
......@@ -753,15 +754,16 @@ pub const Nav = struct {
753754 .unresolved => .unresolved,
754755 .type_resolved, .type_resolved_extern_decl => .{ .type_resolved = .{
755756 .type = repr.type_or_val,
757 .is_const = repr.bits.is_const,
756758 .alignment = repr.bits.alignment,
757759 .@"linksection" = repr.@"linksection",
758760 .@"addrspace" = repr.bits.@"addrspace",
759 .is_const = repr.bits.is_const,
760761 .is_threadlocal = repr.bits.is_threadlocal,
761762 .is_extern_decl = repr.bits.status == .type_resolved_extern_decl,
762763 } },
763764 .fully_resolved => .{ .fully_resolved = .{
764765 .val = repr.type_or_val,
766 .is_const = repr.bits.is_const,
765767 .alignment = repr.bits.alignment,
766768 .@"linksection" = repr.@"linksection",
767769 .@"addrspace" = repr.bits.@"addrspace",
......@@ -792,26 +794,26 @@ pub const Nav = struct {
792794 .bits = switch (nav.status) {
793795 .unresolved => .{
794796 .status = .unresolved,
797 .is_const = false,
795798 .alignment = .none,
796799 .@"addrspace" = .generic,
797800 .is_usingnamespace = nav.is_usingnamespace,
798 .is_const = false,
799801 .is_threadlocal = false,
800802 },
801803 .type_resolved => |r| .{
802804 .status = if (r.is_extern_decl) .type_resolved_extern_decl else .type_resolved,
805 .is_const = r.is_const,
803806 .alignment = r.alignment,
804807 .@"addrspace" = r.@"addrspace",
805808 .is_usingnamespace = nav.is_usingnamespace,
806 .is_const = r.is_const,
807809 .is_threadlocal = r.is_threadlocal,
808810 },
809811 .fully_resolved => |r| .{
810812 .status = .fully_resolved,
813 .is_const = r.is_const,
811814 .alignment = r.alignment,
812815 .@"addrspace" = r.@"addrspace",
813816 .is_usingnamespace = nav.is_usingnamespace,
814 .is_const = false,
815817 .is_threadlocal = false,
816818 },
817819 },
......@@ -2221,7 +2223,6 @@ pub const Key = union(enum) {
22212223 init: Index,
22222224 owner_nav: Nav.Index,
22232225 is_threadlocal: bool,
2224 is_weak_linkage: bool,
22252226 };
22262227
22272228 pub const Extern = struct {
......@@ -2234,10 +2235,12 @@ pub const Key = union(enum) {
22342235 /// For example `extern "c" fn write(...) usize` would have 'c' as library name.
22352236 /// Index into the string table bytes.
22362237 lib_name: OptionalNullTerminatedString,
2237 is_const: bool,
2238 linkage: std.builtin.GlobalLinkage,
2239 visibility: std.builtin.SymbolVisibility,
22382240 is_threadlocal: bool,
2239 is_weak_linkage: bool,
22402241 is_dll_import: bool,
2242 relocation: std.builtin.ExternOptions.Relocation,
2243 is_const: bool,
22412244 alignment: Alignment,
22422245 @"addrspace": std.builtin.AddressSpace,
22432246 /// The ZIR instruction which created this extern; used only for source locations.
......@@ -2844,9 +2847,10 @@ pub const Key = union(enum) {
28442847
28452848 .@"extern" => |e| Hash.hash(seed, asBytes(&e.name) ++
28462849 asBytes(&e.ty) ++ asBytes(&e.lib_name) ++
2847 asBytes(&e.is_const) ++ asBytes(&e.is_threadlocal) ++
2848 asBytes(&e.is_weak_linkage) ++ asBytes(&e.alignment) ++
2849 asBytes(&e.is_dll_import) ++ asBytes(&e.@"addrspace") ++
2850 asBytes(&e.linkage) ++ asBytes(&e.visibility) ++
2851 asBytes(&e.is_threadlocal) ++ asBytes(&e.is_dll_import) ++
2852 asBytes(&e.relocation) ++
2853 asBytes(&e.is_const) ++ asBytes(&e.alignment) ++ asBytes(&e.@"addrspace") ++
28502854 asBytes(&e.zir_index)),
28512855 };
28522856 }
......@@ -2928,21 +2932,22 @@ pub const Key = union(enum) {
29282932
29292933 .variable => |a_info| {
29302934 const b_info = b.variable;
2931 return a_info.owner_nav == b_info.owner_nav and
2932 a_info.ty == b_info.ty and
2935 return a_info.ty == b_info.ty and
29332936 a_info.init == b_info.init and
2934 a_info.is_threadlocal == b_info.is_threadlocal and
2935 a_info.is_weak_linkage == b_info.is_weak_linkage;
2937 a_info.owner_nav == b_info.owner_nav and
2938 a_info.is_threadlocal == b_info.is_threadlocal;
29362939 },
29372940 .@"extern" => |a_info| {
29382941 const b_info = b.@"extern";
29392942 return a_info.name == b_info.name and
29402943 a_info.ty == b_info.ty and
29412944 a_info.lib_name == b_info.lib_name and
2942 a_info.is_const == b_info.is_const and
2945 a_info.linkage == b_info.linkage and
2946 a_info.visibility == b_info.visibility and
29432947 a_info.is_threadlocal == b_info.is_threadlocal and
2944 a_info.is_weak_linkage == b_info.is_weak_linkage and
29452948 a_info.is_dll_import == b_info.is_dll_import and
2949 a_info.relocation == b_info.relocation and
2950 a_info.is_const == b_info.is_const and
29462951 a_info.alignment == b_info.alignment and
29472952 a_info.@"addrspace" == b_info.@"addrspace" and
29482953 a_info.zir_index == b_info.zir_index;
......@@ -4889,6 +4894,7 @@ pub const Index = enum(u32) {
48894894 float_c_longdouble_f128: struct { data: *Float128 },
48904895 float_comptime_float: struct { data: *Float128 },
48914896 variable: struct { data: *Tag.Variable },
4897 threadlocal_variable: struct { data: *Tag.Variable },
48924898 @"extern": struct { data: *Tag.Extern },
48934899 func_decl: struct {
48944900 const @"data.analysis.inferred_error_set" = opaque {};
......@@ -5548,6 +5554,9 @@ pub const Tag = enum(u8) {
55485554 /// A global variable.
55495555 /// data is extra index to Variable.
55505556 variable,
5557 /// A global threadlocal variable.
5558 /// data is extra index to Variable.
5559 threadlocal_variable,
55515560 /// An extern function or variable.
55525561 /// data is extra index to Extern.
55535562 /// Some parts of the key are stored in `owner_nav`.
......@@ -5863,6 +5872,7 @@ pub const Tag = enum(u8) {
58635872 .float_c_longdouble_f128 = .{ .summary = .@"@as(c_longdouble, {.payload%value})", .payload = f128 },
58645873 .float_comptime_float = .{ .summary = .@"{.payload%value}", .payload = f128 },
58655874 .variable = .{ .summary = .@"{.payload.owner_nav.fqn%summary#\"}", .payload = Variable },
5875 .threadlocal_variable = .{ .summary = .@"{.payload.owner_nav.fqn%summary#\"}", .payload = Variable },
58665876 .@"extern" = .{ .summary = .@"{.payload.owner_nav.fqn%summary#\"}", .payload = Extern },
58675877 .func_decl = .{
58685878 .summary = .@"{.payload.owner_nav.fqn%summary#\"}",
......@@ -5913,24 +5923,24 @@ pub const Tag = enum(u8) {
59135923 /// May be `none`.
59145924 init: Index,
59155925 owner_nav: Nav.Index,
5916 flags: Flags,
5917
5918 pub const Flags = packed struct(u32) {
5919 is_const: bool,
5920 is_threadlocal: bool,
5921 is_weak_linkage: bool,
5922 is_dll_import: bool,
5923 _: u28 = 0,
5924 };
59255926 };
59265927
59275928 pub const Extern = struct {
5928 // name, alignment, addrspace come from `owner_nav`.
5929 // name, is_const, alignment, addrspace come from `owner_nav`.
59295930 ty: Index,
59305931 lib_name: OptionalNullTerminatedString,
5931 flags: Variable.Flags,
5932 flags: Flags,
59325933 owner_nav: Nav.Index,
59335934 zir_index: TrackedInst.Index,
5935
5936 pub const Flags = packed struct(u32) {
5937 linkage: std.builtin.GlobalLinkage,
5938 visibility: std.builtin.SymbolVisibility,
5939 is_threadlocal: bool,
5940 is_dll_import: bool,
5941 relocation: std.builtin.ExternOptions.Relocation,
5942 _: u25 = 0,
5943 };
59345944 };
59355945
59365946 /// Trailing:
......@@ -7248,14 +7258,17 @@ pub fn indexToKey(ip: *const InternPool, index: Index) Key {
72487258 .ty = .comptime_float_type,
72497259 .storage = .{ .f128 = extraData(unwrapped_index.getExtra(ip), Float128, data).get() },
72507260 } },
7251 .variable => {
7261 .variable, .threadlocal_variable => {
72527262 const extra = extraData(unwrapped_index.getExtra(ip), Tag.Variable, data);
72537263 return .{ .variable = .{
72547264 .ty = extra.ty,
72557265 .init = extra.init,
72567266 .owner_nav = extra.owner_nav,
7257 .is_threadlocal = extra.flags.is_threadlocal,
7258 .is_weak_linkage = extra.flags.is_weak_linkage,
7267 .is_threadlocal = switch (item.tag) {
7268 else => unreachable,
7269 .variable => false,
7270 .threadlocal_variable => true,
7271 },
72597272 } };
72607273 },
72617274 .@"extern" => {
......@@ -7265,10 +7278,12 @@ pub fn indexToKey(ip: *const InternPool, index: Index) Key {
72657278 .name = nav.name,
72667279 .ty = extra.ty,
72677280 .lib_name = extra.lib_name,
7268 .is_const = extra.flags.is_const,
7281 .linkage = extra.flags.linkage,
7282 .visibility = extra.flags.visibility,
72697283 .is_threadlocal = extra.flags.is_threadlocal,
7270 .is_weak_linkage = extra.flags.is_weak_linkage,
72717284 .is_dll_import = extra.flags.is_dll_import,
7285 .relocation = extra.flags.relocation,
7286 .is_const = nav.status.fully_resolved.is_const,
72727287 .alignment = nav.status.fully_resolved.alignment,
72737288 .@"addrspace" = nav.status.fully_resolved.@"addrspace",
72747289 .zir_index = extra.zir_index,
......@@ -7895,17 +7910,14 @@ pub fn get(ip: *InternPool, gpa: Allocator, tid: Zcu.PerThread.Id, key: Key) All
78957910 const has_init = variable.init != .none;
78967911 if (has_init) assert(variable.ty == ip.typeOf(variable.init));
78977912 items.appendAssumeCapacity(.{
7898 .tag = .variable,
7913 .tag = switch (variable.is_threadlocal) {
7914 false => .variable,
7915 true => .threadlocal_variable,
7916 },
78997917 .data = try addExtra(extra, Tag.Variable{
79007918 .ty = variable.ty,
79017919 .init = variable.init,
79027920 .owner_nav = variable.owner_nav,
7903 .flags = .{
7904 .is_const = false,
7905 .is_threadlocal = variable.is_threadlocal,
7906 .is_weak_linkage = variable.is_weak_linkage,
7907 .is_dll_import = false,
7908 },
79097921 }),
79107922 });
79117923 },
......@@ -9128,6 +9140,7 @@ pub fn getExtern(
91289140 .name = key.name,
91299141 .fqn = key.name,
91309142 .val = extern_index,
9143 .is_const = key.is_const,
91319144 .alignment = key.alignment,
91329145 .@"linksection" = .none,
91339146 .@"addrspace" = key.@"addrspace",
......@@ -9136,10 +9149,11 @@ pub fn getExtern(
91369149 .ty = key.ty,
91379150 .lib_name = key.lib_name,
91389151 .flags = .{
9139 .is_const = key.is_const,
9152 .linkage = key.linkage,
9153 .visibility = key.visibility,
91409154 .is_threadlocal = key.is_threadlocal,
9141 .is_weak_linkage = key.is_weak_linkage,
91429155 .is_dll_import = key.is_dll_import,
9156 .relocation = key.relocation,
91439157 },
91449158 .zir_index = key.zir_index,
91459159 .owner_nav = owner_nav,
......@@ -9714,6 +9728,7 @@ fn finishFuncInstance(
97149728 .name = nav_name,
97159729 .fqn = try ip.namespacePtr(fn_namespace).internFullyQualifiedName(ip, gpa, tid, nav_name),
97169730 .val = func_index,
9731 .is_const = fn_owner_nav.status.fully_resolved.is_const,
97179732 .alignment = fn_owner_nav.status.fully_resolved.alignment,
97189733 .@"linksection" = fn_owner_nav.status.fully_resolved.@"linksection",
97199734 .@"addrspace" = fn_owner_nav.status.fully_resolved.@"addrspace",
......@@ -10300,13 +10315,13 @@ fn addExtraAssumeCapacity(extra: Local.Extra.Mutable, item: anytype) u32 {
1030010315 u32,
1030110316 i32,
1030210317 FuncAnalysis,
10318 Tag.Extern.Flags,
1030310319 Tag.TypePointer.Flags,
1030410320 Tag.TypeFunction.Flags,
1030510321 Tag.TypePointer.PackedOffset,
1030610322 Tag.TypeUnion.Flags,
1030710323 Tag.TypeStruct.Flags,
1030810324 Tag.TypeStructPacked.Flags,
10309 Tag.Variable.Flags,
1031010325 => @bitCast(@field(item, field.name)),
1031110326
1031210327 else => @compileError("bad field type: " ++ @typeName(field.type)),
......@@ -10361,13 +10376,13 @@ fn extraDataTrail(extra: Local.Extra, comptime T: type, index: u32) struct { dat
1036110376
1036210377 u32,
1036310378 i32,
10379 Tag.Extern.Flags,
1036410380 Tag.TypePointer.Flags,
1036510381 Tag.TypeFunction.Flags,
1036610382 Tag.TypePointer.PackedOffset,
1036710383 Tag.TypeUnion.Flags,
1036810384 Tag.TypeStruct.Flags,
1036910385 Tag.TypeStructPacked.Flags,
10370 Tag.Variable.Flags,
1037110386 FuncAnalysis,
1037210387 => @bitCast(extra_item),
1037310388
......@@ -11162,7 +11177,7 @@ fn dumpStatsFallible(ip: *const InternPool, arena: Allocator) anyerror!void {
1116211177 .float_c_longdouble_f80 => @sizeOf(Float80),
1116311178 .float_c_longdouble_f128 => @sizeOf(Float128),
1116411179 .float_comptime_float => @sizeOf(Float128),
11165 .variable => @sizeOf(Tag.Variable),
11180 .variable, .threadlocal_variable => @sizeOf(Tag.Variable),
1116611181 .@"extern" => @sizeOf(Tag.Extern),
1116711182 .func_decl => @sizeOf(Tag.FuncDecl),
1116811183 .func_instance => b: {
......@@ -11282,6 +11297,7 @@ fn dumpAllFallible(ip: *const InternPool) anyerror!void {
1128211297 .float_c_longdouble_f128,
1128311298 .float_comptime_float,
1128411299 .variable,
11300 .threadlocal_variable,
1128511301 .@"extern",
1128611302 .func_decl,
1128711303 .func_instance,
......@@ -11414,6 +11430,7 @@ pub fn createNav(
1141411430 name: NullTerminatedString,
1141511431 fqn: NullTerminatedString,
1141611432 val: InternPool.Index,
11433 is_const: bool,
1141711434 alignment: Alignment,
1141811435 @"linksection": OptionalNullTerminatedString,
1141911436 @"addrspace": std.builtin.AddressSpace,
......@@ -11430,6 +11447,7 @@ pub fn createNav(
1143011447 .analysis = null,
1143111448 .status = .{ .fully_resolved = .{
1143211449 .val = opts.val,
11450 .is_const = opts.is_const,
1143311451 .alignment = opts.alignment,
1143411452 .@"linksection" = opts.@"linksection",
1143511453 .@"addrspace" = opts.@"addrspace",
......@@ -11482,10 +11500,10 @@ pub fn resolveNavType(
1148211500 nav: Nav.Index,
1148311501 resolved: struct {
1148411502 type: InternPool.Index,
11503 is_const: bool,
1148511504 alignment: Alignment,
1148611505 @"linksection": OptionalNullTerminatedString,
1148711506 @"addrspace": std.builtin.AddressSpace,
11488 is_const: bool,
1148911507 is_threadlocal: bool,
1149011508 is_extern_decl: bool,
1149111509 },
......@@ -11512,9 +11530,9 @@ pub fn resolveNavType(
1151211530
1151311531 var bits = nav_bits[unwrapped.index];
1151411532 bits.status = if (resolved.is_extern_decl) .type_resolved_extern_decl else .type_resolved;
11533 bits.is_const = resolved.is_const;
1151511534 bits.alignment = resolved.alignment;
1151611535 bits.@"addrspace" = resolved.@"addrspace";
11517 bits.is_const = resolved.is_const;
1151811536 bits.is_threadlocal = resolved.is_threadlocal;
1151911537 @atomicStore(Nav.Repr.Bits, &nav_bits[unwrapped.index], bits, .release);
1152011538}
......@@ -11526,6 +11544,7 @@ pub fn resolveNavValue(
1152611544 nav: Nav.Index,
1152711545 resolved: struct {
1152811546 val: InternPool.Index,
11547 is_const: bool,
1152911548 alignment: Alignment,
1153011549 @"linksection": OptionalNullTerminatedString,
1153111550 @"addrspace": std.builtin.AddressSpace,
......@@ -11553,6 +11572,7 @@ pub fn resolveNavValue(
1155311572
1155411573 var bits = nav_bits[unwrapped.index];
1155511574 bits.status = .fully_resolved;
11575 bits.is_const = resolved.is_const;
1155611576 bits.alignment = resolved.alignment;
1155711577 bits.@"addrspace" = resolved.@"addrspace";
1155811578 @atomicStore(Nav.Repr.Bits, &nav_bits[unwrapped.index], bits, .release);
......@@ -12007,6 +12027,7 @@ pub fn typeOf(ip: *const InternPool, index: Index) Index {
1200712027 .error_union_error,
1200812028 .enum_tag,
1200912029 .variable,
12030 .threadlocal_variable,
1201012031 .@"extern",
1201112032 .func_decl,
1201212033 .func_instance,
......@@ -12391,6 +12412,7 @@ pub fn zigTypeTag(ip: *const InternPool, index: Index) std.builtin.TypeId {
1239112412 .float_c_longdouble_f128,
1239212413 .float_comptime_float,
1239312414 .variable,
12415 .threadlocal_variable,
1239412416 .@"extern",
1239512417 .func_decl,
1239612418 .func_instance,
src/Sema.zig+42-11
......@@ -26089,10 +26089,12 @@ fn resolveExternOptions(
2608926089 zir_ref: Zir.Inst.Ref,
2609026090) CompileError!struct {
2609126091 name: InternPool.NullTerminatedString,
26092 library_name: InternPool.OptionalNullTerminatedString = .none,
26093 linkage: std.builtin.GlobalLinkage = .strong,
26094 is_thread_local: bool = false,
26095 is_dll_import: bool = false,
26092 library_name: InternPool.OptionalNullTerminatedString,
26093 linkage: std.builtin.GlobalLinkage,
26094 visibility: std.builtin.SymbolVisibility,
26095 is_thread_local: bool,
26096 is_dll_import: bool,
26097 relocation: std.builtin.ExternOptions.Relocation,
2609626098} {
2609726099 const pt = sema.pt;
2609826100 const zcu = pt.zcu;
......@@ -26105,8 +26107,10 @@ fn resolveExternOptions(
2610526107 const name_src = block.src(.{ .init_field_name = src.offset.node_offset_builtin_call_arg.builtin_call_node });
2610626108 const library_src = block.src(.{ .init_field_library = src.offset.node_offset_builtin_call_arg.builtin_call_node });
2610726109 const linkage_src = block.src(.{ .init_field_linkage = src.offset.node_offset_builtin_call_arg.builtin_call_node });
26110 const visibility_src = block.src(.{ .init_field_visibility = src.offset.node_offset_builtin_call_arg.builtin_call_node });
2610826111 const thread_local_src = block.src(.{ .init_field_thread_local = src.offset.node_offset_builtin_call_arg.builtin_call_node });
2610926112 const dll_import_src = block.src(.{ .init_field_dll_import = src.offset.node_offset_builtin_call_arg.builtin_call_node });
26113 const relocation_src = block.src(.{ .init_field_relocation = src.offset.node_offset_builtin_call_arg.builtin_call_node });
2611026114
2611126115 const name_ref = try sema.fieldVal(block, src, options, try ip.getOrPutString(gpa, pt.tid, "name", .no_embedded_nulls), name_src);
2611226116 const name = try sema.toConstString(block, name_src, name_ref, .{ .simple = .extern_options });
......@@ -26118,6 +26122,10 @@ fn resolveExternOptions(
2611826122 const linkage_val = try sema.resolveConstDefinedValue(block, linkage_src, linkage_ref, .{ .simple = .extern_options });
2611926123 const linkage = try sema.interpretBuiltinType(block, linkage_src, linkage_val, std.builtin.GlobalLinkage);
2612026124
26125 const visibility_ref = try sema.fieldVal(block, src, options, try ip.getOrPutString(gpa, pt.tid, "visibility", .no_embedded_nulls), visibility_src);
26126 const visibility_val = try sema.resolveConstDefinedValue(block, visibility_src, visibility_ref, .{ .simple = .extern_options });
26127 const visibility = try sema.interpretBuiltinType(block, visibility_src, visibility_val, std.builtin.SymbolVisibility);
26128
2612126129 const is_thread_local = try sema.fieldVal(block, src, options, try ip.getOrPutString(gpa, pt.tid, "is_thread_local", .no_embedded_nulls), thread_local_src);
2612226130 const is_thread_local_val = try sema.resolveConstDefinedValue(block, thread_local_src, is_thread_local, .{ .simple = .extern_options });
2612326131
......@@ -26133,6 +26141,10 @@ fn resolveExternOptions(
2613326141 const is_dll_import_ref = try sema.fieldVal(block, src, options, try ip.getOrPutString(gpa, pt.tid, "is_dll_import", .no_embedded_nulls), dll_import_src);
2613426142 const is_dll_import_val = try sema.resolveConstDefinedValue(block, dll_import_src, is_dll_import_ref, .{ .simple = .extern_options });
2613526143
26144 const relocation_ref = try sema.fieldVal(block, src, options, try ip.getOrPutString(gpa, pt.tid, "relocation", .no_embedded_nulls), relocation_src);
26145 const relocation_val = try sema.resolveConstDefinedValue(block, relocation_src, relocation_ref, .{ .simple = .extern_options });
26146 const relocation = try sema.interpretBuiltinType(block, relocation_src, relocation_val, std.builtin.ExternOptions.Relocation);
26147
2613626148 if (name.len == 0) {
2613726149 return sema.fail(block, name_src, "extern symbol name cannot be empty", .{});
2613826150 }
......@@ -26145,8 +26157,10 @@ fn resolveExternOptions(
2614526157 .name = try ip.getOrPutString(gpa, pt.tid, name, .no_embedded_nulls),
2614626158 .library_name = try ip.getOrPutStringOpt(gpa, pt.tid, library_name, .no_embedded_nulls),
2614726159 .linkage = linkage,
26160 .visibility = visibility,
2614826161 .is_thread_local = is_thread_local_val.toBool(),
2614926162 .is_dll_import = is_dll_import_val.toBool(),
26163 .relocation = relocation,
2615026164 };
2615126165}
2615226166
......@@ -26178,6 +26192,17 @@ fn zirBuiltinExtern(
2617826192 }
2617926193
2618026194 const options = try sema.resolveExternOptions(block, options_src, extra.rhs);
26195 switch (options.linkage) {
26196 .internal => if (options.visibility != .default) {
26197 return sema.fail(block, options_src, "internal symbol cannot have non-default visibility", .{});
26198 },
26199 .strong, .weak => {},
26200 .link_once => return sema.fail(block, options_src, "external symbol cannot have link once linkage", .{}),
26201 }
26202 switch (options.relocation) {
26203 .any => {},
26204 .pcrel => if (options.visibility == .default) return sema.fail(block, options_src, "cannot require a pc-relative relocation to a symbol with default visibility", .{}),
26205 }
2618126206
2618226207 // TODO: error for threadlocal functions, non-const functions, etc
2618326208
......@@ -26190,10 +26215,12 @@ fn zirBuiltinExtern(
2619026215 .name = options.name,
2619126216 .ty = ptr_info.child,
2619226217 .lib_name = options.library_name,
26193 .is_const = ptr_info.flags.is_const,
26218 .linkage = options.linkage,
26219 .visibility = options.visibility,
2619426220 .is_threadlocal = options.is_thread_local,
26195 .is_weak_linkage = options.linkage == .weak,
2619626221 .is_dll_import = options.is_dll_import,
26222 .relocation = options.relocation,
26223 .is_const = ptr_info.flags.is_const,
2619726224 .alignment = ptr_info.flags.alignment,
2619826225 .@"addrspace" = ptr_info.flags.address_space,
2619926226 // This instruction is just for source locations.
......@@ -31685,12 +31712,15 @@ fn analyzeNavRefInner(sema: *Sema, block: *Block, src: LazySrcLoc, orig_nav_inde
3168531712
3168631713 const nav_status = ip.getNav(nav_index).status;
3168731714
31688 const is_tlv_or_dllimport = switch (nav_status) {
31715 const is_runtime = switch (nav_status) {
3168931716 .unresolved => unreachable,
3169031717 // dllimports go straight to `fully_resolved`; the only option is threadlocal
3169131718 .type_resolved => |r| r.is_threadlocal,
3169231719 .fully_resolved => |r| switch (ip.indexToKey(r.val)) {
31693 .@"extern" => |e| e.is_threadlocal or e.is_dll_import,
31720 .@"extern" => |e| e.is_threadlocal or e.is_dll_import or switch (e.relocation) {
31721 .any => false,
31722 .pcrel => true,
31723 },
3169431724 .variable => |v| v.is_threadlocal,
3169531725 else => false,
3169631726 },
......@@ -31699,7 +31729,7 @@ fn analyzeNavRefInner(sema: *Sema, block: *Block, src: LazySrcLoc, orig_nav_inde
3169931729 const ty, const alignment, const @"addrspace", const is_const = switch (nav_status) {
3170031730 .unresolved => unreachable,
3170131731 .type_resolved => |r| .{ r.type, r.alignment, r.@"addrspace", r.is_const },
31702 .fully_resolved => |r| .{ ip.typeOf(r.val), r.alignment, r.@"addrspace", zcu.navValIsConst(r.val) },
31732 .fully_resolved => |r| .{ ip.typeOf(r.val), r.alignment, r.@"addrspace", r.is_const },
3170331733 };
3170431734 const ptr_ty = try pt.ptrTypeSema(.{
3170531735 .child = ty,
......@@ -31710,10 +31740,10 @@ fn analyzeNavRefInner(sema: *Sema, block: *Block, src: LazySrcLoc, orig_nav_inde
3171031740 },
3171131741 });
3171231742
31713 if (is_tlv_or_dllimport) {
31743 if (is_runtime) {
3171431744 // This pointer is runtime-known; we need to emit an AIR instruction to create it.
3171531745 return block.addInst(.{
31716 .tag = .tlv_dllimport_ptr,
31746 .tag = .runtime_nav_ptr,
3171731747 .data = .{ .ty_nav = .{
3171831748 .ty = ptr_ty.toIntern(),
3171931749 .nav = nav_index,
......@@ -36432,6 +36462,7 @@ pub fn typeHasOnePossibleValue(sema: *Sema, ty: Type) CompileError!?Value {
3643236462 .float_c_longdouble_f128,
3643336463 .float_comptime_float,
3643436464 .variable,
36465 .threadlocal_variable,
3643536466 .@"extern",
3643636467 .func_decl,
3643736468 .func_instance,
src/Zcu.zig+3-9
......@@ -2047,6 +2047,7 @@ pub const SrcLoc = struct {
20472047 .init_field_library,
20482048 .init_field_thread_local,
20492049 .init_field_dll_import,
2050 .init_field_relocation,
20502051 => |builtin_call_node| {
20512052 const wanted = switch (src_loc.lazy) {
20522053 .init_field_name => "name",
......@@ -2059,6 +2060,7 @@ pub const SrcLoc = struct {
20592060 .init_field_library => "library",
20602061 .init_field_thread_local => "thread_local",
20612062 .init_field_dll_import => "dll_import",
2063 .init_field_relocation => "relocation",
20622064 else => unreachable,
20632065 };
20642066 const tree = try src_loc.file_scope.getTree(zcu);
......@@ -2506,6 +2508,7 @@ pub const LazySrcLoc = struct {
25062508 init_field_library: Ast.Node.Offset,
25072509 init_field_thread_local: Ast.Node.Offset,
25082510 init_field_dll_import: Ast.Node.Offset,
2511 init_field_relocation: Ast.Node.Offset,
25092512 /// The source location points to the value of an item in a specific
25102513 /// case of a `switch`.
25112514 switch_case_item: SwitchItem,
......@@ -4562,15 +4565,6 @@ pub fn callconvSupported(zcu: *Zcu, cc: std.builtin.CallingConvention) union(enu
45624565 return .ok;
45634566}
45644567
4565/// Given that a `Nav` has value `val`, determine if a ref of that `Nav` gives a `const` pointer.
4566pub fn navValIsConst(zcu: *const Zcu, val: InternPool.Index) bool {
4567 return switch (zcu.intern_pool.indexToKey(val)) {
4568 .variable => false,
4569 .@"extern" => |e| e.is_const,
4570 else => true,
4571 };
4572}
4573
45744568pub const CodegenFailError = error{
45754569 /// Indicates the error message has been already stored at `Zcu.failed_codegen`.
45764570 CodegenFail,
src/Zcu/PerThread.zig+29-21
......@@ -1153,18 +1153,23 @@ fn analyzeNavVal(pt: Zcu.PerThread, nav_id: InternPool.Nav.Index) Zcu.CompileErr
11531153 // First, we must resolve the declaration's type. To do this, we analyze the type body if available,
11541154 // or otherwise, we analyze the value body, populating `early_val` in the process.
11551155
1156 switch (zir_decl.kind) {
1156 const is_const = is_const: switch (zir_decl.kind) {
11571157 .@"comptime" => unreachable, // this is not a Nav
1158 .unnamed_test, .@"test", .decltest => assert(nav_ty.zigTypeTag(zcu) == .@"fn"),
1159 .@"usingnamespace" => {},
1160 .@"const" => {},
1161 .@"var" => try sema.validateVarType(
1162 &block,
1163 if (zir_decl.type_body != null) ty_src else init_src,
1164 nav_ty,
1165 zir_decl.linkage == .@"extern",
1166 ),
1167 }
1158 .unnamed_test, .@"test", .decltest => {
1159 assert(nav_ty.zigTypeTag(zcu) == .@"fn");
1160 break :is_const true;
1161 },
1162 .@"usingnamespace", .@"const" => true,
1163 .@"var" => {
1164 try sema.validateVarType(
1165 &block,
1166 if (zir_decl.type_body != null) ty_src else init_src,
1167 nav_ty,
1168 zir_decl.linkage == .@"extern",
1169 );
1170 break :is_const false;
1171 },
1172 };
11681173
11691174 // Now that we know the type, we can evaluate the alignment, linksection, and addrspace, to determine
11701175 // the full pointer type of this declaration.
......@@ -1195,7 +1200,6 @@ fn analyzeNavVal(pt: Zcu.PerThread, nav_id: InternPool.Nav.Index) Zcu.CompileErr
11951200 .init = final_val.?.toIntern(),
11961201 .owner_nav = nav_id,
11971202 .is_threadlocal = zir_decl.is_threadlocal,
1198 .is_weak_linkage = false,
11991203 } })),
12001204 else => final_val.?,
12011205 },
......@@ -1212,10 +1216,12 @@ fn analyzeNavVal(pt: Zcu.PerThread, nav_id: InternPool.Nav.Index) Zcu.CompileErr
12121216 .name = old_nav.name,
12131217 .ty = nav_ty.toIntern(),
12141218 .lib_name = try ip.getOrPutStringOpt(gpa, pt.tid, lib_name, .no_embedded_nulls),
1215 .is_const = zir_decl.kind == .@"const",
12161219 .is_threadlocal = zir_decl.is_threadlocal,
1217 .is_weak_linkage = false,
1220 .linkage = .strong,
1221 .visibility = .default,
12181222 .is_dll_import = false,
1223 .relocation = .any,
1224 .is_const = is_const,
12191225 .alignment = modifiers.alignment,
12201226 .@"addrspace" = modifiers.@"addrspace",
12211227 .zir_index = old_nav.analysis.?.zir_index, // `declaration` instruction
......@@ -1243,6 +1249,7 @@ fn analyzeNavVal(pt: Zcu.PerThread, nav_id: InternPool.Nav.Index) Zcu.CompileErr
12431249 }
12441250 ip.resolveNavValue(nav_id, .{
12451251 .val = nav_val.toIntern(),
1252 .is_const = is_const,
12461253 .alignment = .none,
12471254 .@"linksection" = .none,
12481255 .@"addrspace" = .generic,
......@@ -1286,6 +1293,7 @@ fn analyzeNavVal(pt: Zcu.PerThread, nav_id: InternPool.Nav.Index) Zcu.CompileErr
12861293
12871294 ip.resolveNavValue(nav_id, .{
12881295 .val = nav_val.toIntern(),
1296 .is_const = is_const,
12891297 .alignment = modifiers.alignment,
12901298 .@"linksection" = modifiers.@"linksection",
12911299 .@"addrspace" = modifiers.@"addrspace",
......@@ -1515,8 +1523,6 @@ fn analyzeNavType(pt: Zcu.PerThread, nav_id: InternPool.Nav.Index) Zcu.CompileEr
15151523 // the pointer modifiers, i.e. alignment, linksection, addrspace.
15161524 const modifiers = try sema.resolveNavPtrModifiers(&block, zir_decl, inst_resolved.inst, resolved_ty);
15171525
1518 // Usually, we can infer this information from the resolved `Nav` value; see `Zcu.navValIsConst`.
1519 // However, since we don't have one, we need to quickly check the ZIR to figure this out.
15201526 const is_const = switch (zir_decl.kind) {
15211527 .@"comptime" => unreachable,
15221528 .unnamed_test, .@"test", .decltest, .@"usingnamespace", .@"const" => true,
......@@ -1542,7 +1548,7 @@ fn analyzeNavType(pt: Zcu.PerThread, nav_id: InternPool.Nav.Index) Zcu.CompileEr
15421548 r.alignment != modifiers.alignment or
15431549 r.@"linksection" != modifiers.@"linksection" or
15441550 r.@"addrspace" != modifiers.@"addrspace" or
1545 zcu.navValIsConst(r.val) != is_const or
1551 r.is_const != is_const or
15461552 (old_nav.getExtern(ip) != null) != is_extern_decl,
15471553 };
15481554
......@@ -1550,10 +1556,10 @@ fn analyzeNavType(pt: Zcu.PerThread, nav_id: InternPool.Nav.Index) Zcu.CompileEr
15501556
15511557 ip.resolveNavType(nav_id, .{
15521558 .type = resolved_ty.toIntern(),
1559 .is_const = is_const,
15531560 .alignment = modifiers.alignment,
15541561 .@"linksection" = modifiers.@"linksection",
15551562 .@"addrspace" = modifiers.@"addrspace",
1556 .is_const = is_const,
15571563 .is_threadlocal = zir_decl.is_threadlocal,
15581564 .is_extern_decl = is_extern_decl,
15591565 });
......@@ -1750,7 +1756,7 @@ pub fn linkerUpdateFunc(pt: Zcu.PerThread, func_index: InternPool.Index, air: *A
17501756
17511757 if (build_options.enable_debug_extensions and comp.verbose_air) {
17521758 std.debug.print("# Begin Function AIR: {}:\n", .{nav.fqn.fmt(ip)});
1753 @import("../print_air.zig").dump(pt, air.*, liveness);
1759 air.dump(pt, liveness);
17541760 std.debug.print("# End Function AIR: {}\n\n", .{nav.fqn.fmt(ip)});
17551761 }
17561762
......@@ -3577,8 +3583,10 @@ pub fn getCoerced(pt: Zcu.PerThread, val: Value, new_ty: Type) Allocator.Error!V
35773583 .lib_name = e.lib_name,
35783584 .is_const = e.is_const,
35793585 .is_threadlocal = e.is_threadlocal,
3580 .is_weak_linkage = e.is_weak_linkage,
3586 .linkage = e.linkage,
3587 .visibility = e.visibility,
35813588 .is_dll_import = e.is_dll_import,
3589 .relocation = e.relocation,
35823590 .alignment = e.alignment,
35833591 .@"addrspace" = e.@"addrspace",
35843592 .zir_index = e.zir_index,
......@@ -3954,7 +3962,7 @@ pub fn navPtrType(pt: Zcu.PerThread, nav_id: InternPool.Nav.Index) Allocator.Err
39543962 const ty, const alignment, const @"addrspace", const is_const = switch (ip.getNav(nav_id).status) {
39553963 .unresolved => unreachable,
39563964 .type_resolved => |r| .{ r.type, r.alignment, r.@"addrspace", r.is_const },
3957 .fully_resolved => |r| .{ ip.typeOf(r.val), r.alignment, r.@"addrspace", zcu.navValIsConst(r.val) },
3965 .fully_resolved => |r| .{ ip.typeOf(r.val), r.alignment, r.@"addrspace", r.is_const },
39583966 };
39593967 return pt.ptrType(.{
39603968 .child = ty,
src/arch/aarch64/CodeGen.zig+1-1
......@@ -880,7 +880,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
880880 .is_named_enum_value => return self.fail("TODO implement is_named_enum_value", .{}),
881881 .error_set_has_value => return self.fail("TODO implement error_set_has_value", .{}),
882882 .vector_store_elem => return self.fail("TODO implement vector_store_elem", .{}),
883 .tlv_dllimport_ptr => return self.fail("TODO implement tlv_dllimport_ptr", .{}),
883 .runtime_nav_ptr => return self.fail("TODO implement runtime_nav_ptr", .{}),
884884
885885 .c_va_arg => return self.fail("TODO implement c_va_arg", .{}),
886886 .c_va_copy => return self.fail("TODO implement c_va_copy", .{}),
src/arch/arm/CodeGen.zig+1-1
......@@ -869,7 +869,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
869869 .is_named_enum_value => return self.fail("TODO implement is_named_enum_value", .{}),
870870 .error_set_has_value => return self.fail("TODO implement error_set_has_value", .{}),
871871 .vector_store_elem => return self.fail("TODO implement vector_store_elem", .{}),
872 .tlv_dllimport_ptr => return self.fail("TODO implement tlv_dllimport_ptr", .{}),
872 .runtime_nav_ptr => return self.fail("TODO implement runtime_nav_ptr", .{}),
873873
874874 .c_va_arg => return self.fail("TODO implement c_va_arg", .{}),
875875 .c_va_copy => return self.fail("TODO implement c_va_copy", .{}),
src/arch/riscv64/CodeGen.zig+4-9
......@@ -1041,12 +1041,7 @@ fn formatAir(
10411041 _: std.fmt.FormatOptions,
10421042 writer: anytype,
10431043) @TypeOf(writer).Error!void {
1044 @import("../../print_air.zig").dumpInst(
1045 data.inst,
1046 data.func.pt,
1047 data.func.air,
1048 data.func.liveness,
1049 );
1044 data.func.air.dumpInst(data.inst, data.func.pt, data.func.liveness);
10501045}
10511046fn fmtAir(func: *Func, inst: Air.Inst.Index) std.fmt.Formatter(formatAir) {
10521047 return .{ .data = .{ .func = func, .inst = inst } };
......@@ -1656,7 +1651,7 @@ fn genBody(func: *Func, body: []const Air.Inst.Index) InnerError!void {
16561651 .wrap_errunion_payload => try func.airWrapErrUnionPayload(inst),
16571652 .wrap_errunion_err => try func.airWrapErrUnionErr(inst),
16581653
1659 .tlv_dllimport_ptr => try func.airTlvDllimportPtr(inst),
1654 .runtime_nav_ptr => try func.airRuntimeNavPtr(inst),
16601655
16611656 .add_optimized,
16621657 .sub_optimized,
......@@ -3626,7 +3621,7 @@ fn airWrapErrUnionErr(func: *Func, inst: Air.Inst.Index) !void {
36263621 return func.finishAir(inst, result, .{ ty_op.operand, .none, .none });
36273622}
36283623
3629fn airTlvDllimportPtr(func: *Func, inst: Air.Inst.Index) !void {
3624fn airRuntimeNavPtr(func: *Func, inst: Air.Inst.Index) !void {
36303625 const zcu = func.pt.zcu;
36313626 const ip = &zcu.intern_pool;
36323627 const ty_nav = func.air.instructions.items(.data)[@intFromEnum(inst)].ty_nav;
......@@ -3641,7 +3636,7 @@ fn airTlvDllimportPtr(func: *Func, inst: Air.Inst.Index) !void {
36413636 break :sym sym;
36423637 }
36433638 break :sym try zo.getOrCreateMetadataForNav(zcu, ty_nav.nav);
3644 } else return func.fail("TODO tlv_dllimport_ptr on {}", .{func.bin_file.tag});
3639 } else return func.fail("TODO runtime_nav_ptr on {}", .{func.bin_file.tag});
36453640
36463641 const dest_mcv = try func.allocRegOrMem(ptr_ty, inst, true);
36473642 if (dest_mcv.isRegister()) {
src/arch/sparc64/CodeGen.zig+1-1
......@@ -723,7 +723,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
723723 .is_named_enum_value => @panic("TODO implement is_named_enum_value"),
724724 .error_set_has_value => @panic("TODO implement error_set_has_value"),
725725 .vector_store_elem => @panic("TODO implement vector_store_elem"),
726 .tlv_dllimport_ptr => @panic("TODO implement tlv_dllimport_ptr"),
726 .runtime_nav_ptr => @panic("TODO implement runtime_nav_ptr"),
727727
728728 .c_va_arg => return self.fail("TODO implement c_va_arg", .{}),
729729 .c_va_copy => return self.fail("TODO implement c_va_copy", .{}),
src/arch/wasm/CodeGen.zig+2-2
......@@ -2057,7 +2057,7 @@ fn genInst(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
20572057 .error_set_has_value => cg.airErrorSetHasValue(inst),
20582058 .frame_addr => cg.airFrameAddress(inst),
20592059
2060 .tlv_dllimport_ptr => cg.airTlvDllimportPtr(inst),
2060 .runtime_nav_ptr => cg.airRuntimeNavPtr(inst),
20612061
20622062 .assembly,
20632063 .is_err_ptr,
......@@ -7616,7 +7616,7 @@ fn airFrameAddress(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
76167616 return cg.finishAir(inst, .stack, &.{});
76177617}
76187618
7619fn airTlvDllimportPtr(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
7619fn airRuntimeNavPtr(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
76207620 const ty_nav = cg.air.instructions.items(.data)[@intFromEnum(inst)].ty_nav;
76217621 const mod = cg.pt.zcu.navFileScope(cg.owner_nav).mod.?;
76227622 if (mod.single_threaded) {
src/arch/x86_64/CodeGen.zig+173-42
......@@ -274,6 +274,12 @@ pub const MCValue = union(enum) {
274274 load_symbol: bits.SymbolOffset,
275275 /// The address of the memory location not-yet-allocated by the linker.
276276 lea_symbol: bits.SymbolOffset,
277 /// The value is in memory at an address not-yet-allocated by the linker.
278 /// This must use a non-got pc-relative relocation.
279 load_pcrel: bits.SymbolOffset,
280 /// The address of the memory location not-yet-allocated by the linker.
281 /// This must use a non-got pc-relative relocation.
282 lea_pcrel: bits.SymbolOffset,
277283 /// The value is in memory at a constant offset from the address in a register.
278284 indirect: bits.RegisterOffset,
279285 /// The value is in memory.
......@@ -314,6 +320,7 @@ pub const MCValue = union(enum) {
314320 .eflags,
315321 .register_overflow,
316322 .lea_symbol,
323 .lea_pcrel,
317324 .lea_direct,
318325 .lea_got,
319326 .lea_frame,
......@@ -327,6 +334,7 @@ pub const MCValue = union(enum) {
327334 .register_quadruple,
328335 .memory,
329336 .load_symbol,
337 .load_pcrel,
330338 .load_got,
331339 .load_direct,
332340 .indirect,
......@@ -429,6 +437,7 @@ pub const MCValue = union(enum) {
429437 .register_overflow,
430438 .register_mask,
431439 .lea_symbol,
440 .lea_pcrel,
432441 .lea_direct,
433442 .lea_got,
434443 .lea_frame,
......@@ -445,6 +454,7 @@ pub const MCValue = union(enum) {
445454 .load_got => |sym_index| .{ .lea_got = sym_index },
446455 .load_frame => |frame_addr| .{ .lea_frame = frame_addr },
447456 .load_symbol => |sym_off| .{ .lea_symbol = sym_off },
457 .load_pcrel => |sym_off| .{ .lea_pcrel = sym_off },
448458 };
449459 }
450460
......@@ -466,6 +476,7 @@ pub const MCValue = union(enum) {
466476 .load_got,
467477 .load_frame,
468478 .load_symbol,
479 .load_pcrel,
469480 .elementwise_args,
470481 .reserved_frame,
471482 .air_ref,
......@@ -477,6 +488,7 @@ pub const MCValue = union(enum) {
477488 .lea_got => |sym_index| .{ .load_got = sym_index },
478489 .lea_frame => |frame_addr| .{ .load_frame = frame_addr },
479490 .lea_symbol => |sym_index| .{ .load_symbol = sym_index },
491 .lea_pcrel => |sym_index| .{ .load_pcrel = sym_index },
480492 };
481493 }
482494
......@@ -505,6 +517,8 @@ pub const MCValue = union(enum) {
505517 .load_frame,
506518 .load_symbol,
507519 .lea_symbol,
520 .load_pcrel,
521 .lea_pcrel,
508522 => switch (off) {
509523 0 => mcv,
510524 else => unreachable, // not offsettable
......@@ -543,6 +557,7 @@ pub const MCValue = union(enum) {
543557 .elementwise_args,
544558 .reserved_frame,
545559 .lea_symbol,
560 .lea_pcrel,
546561 => unreachable,
547562 .memory => |addr| if (std.math.cast(i32, @as(i64, @bitCast(addr)))) |small_addr| .{
548563 .base = .{ .reg = .ds },
......@@ -583,6 +598,18 @@ pub const MCValue = union(enum) {
583598 } },
584599 };
585600 },
601 .load_pcrel => |sym_off| {
602 assert(sym_off.off == 0);
603 return .{
604 .base = .{ .pcrel = sym_off.sym_index },
605 .mod = .{ .rm = .{
606 .size = mod_rm.size,
607 .index = mod_rm.index,
608 .scale = mod_rm.scale,
609 .disp = sym_off.off + mod_rm.disp,
610 } },
611 };
612 },
586613 .air_ref => |ref| (try function.resolveInst(ref)).mem(function, mod_rm),
587614 };
588615 }
......@@ -618,6 +645,8 @@ pub const MCValue = union(enum) {
618645 }),
619646 .load_symbol => |pl| try writer.print("[sym:{} + 0x{x}]", .{ pl.sym_index, pl.off }),
620647 .lea_symbol => |pl| try writer.print("sym:{} + 0x{x}", .{ pl.sym_index, pl.off }),
648 .load_pcrel => |pl| try writer.print("[sym@pcrel:{} + 0x{x}]", .{ pl.sym_index, pl.off }),
649 .lea_pcrel => |pl| try writer.print("sym@pcrel:{} + 0x{x}", .{ pl.sym_index, pl.off }),
621650 .indirect => |pl| try writer.print("[{s} + 0x{x}]", .{ @tagName(pl.reg), pl.off }),
622651 .load_direct => |pl| try writer.print("[direct:{d}]", .{pl}),
623652 .lea_direct => |pl| try writer.print("direct:{d}", .{pl}),
......@@ -655,6 +684,8 @@ const InstTracking = struct {
655684 .lea_frame,
656685 .load_symbol,
657686 .lea_symbol,
687 .load_pcrel,
688 .lea_pcrel,
658689 => result,
659690 .dead,
660691 .elementwise_args,
......@@ -755,6 +786,8 @@ const InstTracking = struct {
755786 .lea_frame,
756787 .load_symbol,
757788 .lea_symbol,
789 .load_pcrel,
790 .lea_pcrel,
758791 => assert(std.meta.eql(self.long, target.long)),
759792 .dead,
760793 .eflags,
......@@ -1228,12 +1261,7 @@ fn formatAir(
12281261 _: std.fmt.FormatOptions,
12291262 writer: anytype,
12301263) @TypeOf(writer).Error!void {
1231 @import("../../print_air.zig").dumpInst(
1232 data.inst,
1233 data.self.pt,
1234 data.self.air,
1235 data.self.liveness,
1236 );
1264 data.self.air.dumpInst(data.inst, data.self.pt, data.self.liveness);
12371265}
12381266fn fmtAir(self: *CodeGen, inst: Air.Inst.Index) std.fmt.Formatter(formatAir) {
12391267 return .{ .data = .{ .self = self, .inst = inst } };
......@@ -163487,31 +163515,49 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {
163487163515 };
163488163516 for (ops) |op| try op.die(cg);
163489163517 },
163490 .tlv_dllimport_ptr => switch (cg.bin_file.tag) {
163518 .runtime_nav_ptr => switch (cg.bin_file.tag) {
163491163519 .elf, .macho => {
163492163520 const ty_nav = air_datas[@intFromEnum(inst)].ty_nav;
163493163521
163494163522 const nav = ip.getNav(ty_nav.nav);
163495 const tlv_sym_index = sym: {
163523 const sym_index, const relocation = sym: {
163496163524 if (cg.bin_file.cast(.elf)) |elf_file| {
163497163525 const zo = elf_file.zigObjectPtr().?;
163498163526 if (nav.getExtern(ip)) |e| {
163499163527 const sym = try elf_file.getGlobalSymbol(nav.name.toSlice(ip), e.lib_name.toSlice(ip));
163500 zo.symbol(sym).flags.is_extern_ptr = true;
163501 break :sym sym;
163502 }
163503 break :sym try zo.getOrCreateMetadataForNav(zcu, ty_nav.nav);
163504 }
163505 if (cg.bin_file.cast(.macho)) |macho_file| {
163528 linkage: switch (e.linkage) {
163529 .internal => {},
163530 .strong => switch (e.visibility) {
163531 .default => zo.symbol(sym).flags.is_extern_ptr = true,
163532 .hidden, .protected => {},
163533 },
163534 .weak => {
163535 zo.symbol(sym).flags.weak = true;
163536 continue :linkage .strong;
163537 },
163538 .link_once => unreachable,
163539 }
163540 break :sym .{ sym, e.relocation };
163541 } else break :sym .{ try zo.getOrCreateMetadataForNav(zcu, ty_nav.nav), .any };
163542 } else if (cg.bin_file.cast(.macho)) |macho_file| {
163506163543 const zo = macho_file.getZigObject().?;
163507163544 if (nav.getExtern(ip)) |e| {
163508163545 const sym = try macho_file.getGlobalSymbol(nav.name.toSlice(ip), e.lib_name.toSlice(ip));
163509 zo.symbols.items[sym].flags.is_extern_ptr = true;
163510 break :sym sym;
163511 }
163512 break :sym try zo.getOrCreateMetadataForNav(macho_file, ty_nav.nav);
163513 }
163514 unreachable;
163546 linkage: switch (e.linkage) {
163547 .internal => {},
163548 .strong => switch (e.visibility) {
163549 .default => zo.symbols.items[sym].flags.is_extern_ptr = true,
163550 .hidden, .protected => {},
163551 },
163552 .weak => {
163553 zo.symbols.items[sym].flags.weak = true;
163554 continue :linkage .strong;
163555 },
163556 .link_once => unreachable,
163557 }
163558 break :sym .{ sym, e.relocation };
163559 } else break :sym .{ try zo.getOrCreateMetadataForNav(macho_file, ty_nav.nav), .any };
163560 } else unreachable;
163515163561 };
163516163562
163517163563 if (cg.mod.pic) {
......@@ -163520,13 +163566,14 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {
163520163566 try cg.spillRegisters(&.{.rax});
163521163567 }
163522163568
163523 var slot = try cg.tempInit(.usize, .{ .lea_symbol = .{
163524 .sym_index = tlv_sym_index,
163525 } });
163569 var slot = try cg.tempInit(.usize, switch (relocation) {
163570 .any => .{ .lea_symbol = .{ .sym_index = sym_index } },
163571 .pcrel => .{ .lea_pcrel = .{ .sym_index = sym_index } },
163572 });
163526163573 while (try slot.toRegClass(true, .general_purpose, cg)) {}
163527163574 try slot.finish(inst, &.{}, &.{}, cg);
163528163575 },
163529 else => return cg.fail("TODO implement tlv/dllimport on {}", .{cg.bin_file.tag}),
163576 else => return cg.fail("TODO implement runtime_nav_ptr on {}", .{cg.bin_file.tag}),
163530163577 },
163531163578 .c_va_arg => try cg.airVaArg(inst),
163532163579 .c_va_copy => try cg.airVaCopy(inst),
......@@ -169189,6 +169236,7 @@ fn load(self: *CodeGen, dst_mcv: MCValue, ptr_ty: Type, ptr_mcv: MCValue) InnerE
169189169236 .register,
169190169237 .register_offset,
169191169238 .lea_symbol,
169239 .lea_pcrel,
169192169240 .lea_direct,
169193169241 .lea_got,
169194169242 .lea_frame,
......@@ -169196,6 +169244,7 @@ fn load(self: *CodeGen, dst_mcv: MCValue, ptr_ty: Type, ptr_mcv: MCValue) InnerE
169196169244 .memory,
169197169245 .indirect,
169198169246 .load_symbol,
169247 .load_pcrel,
169199169248 .load_direct,
169200169249 .load_got,
169201169250 .load_frame,
......@@ -169407,6 +169456,7 @@ fn store(
169407169456 .register,
169408169457 .register_offset,
169409169458 .lea_symbol,
169459 .lea_pcrel,
169410169460 .lea_direct,
169411169461 .lea_got,
169412169462 .lea_frame,
......@@ -169414,6 +169464,7 @@ fn store(
169414169464 .memory,
169415169465 .indirect,
169416169466 .load_symbol,
169467 .load_pcrel,
169417169468 .load_direct,
169418169469 .load_got,
169419169470 .load_frame,
......@@ -169883,6 +169934,7 @@ fn genUnOpMir(self: *CodeGen, mir_tag: Mir.Inst.FixedTag, dst_ty: Type, dst_mcv:
169883169934 .register_overflow,
169884169935 .register_mask,
169885169936 .lea_symbol,
169937 .lea_pcrel,
169886169938 .lea_direct,
169887169939 .lea_got,
169888169940 .lea_frame,
......@@ -169892,7 +169944,7 @@ fn genUnOpMir(self: *CodeGen, mir_tag: Mir.Inst.FixedTag, dst_ty: Type, dst_mcv:
169892169944 => unreachable, // unmodifiable destination
169893169945 .register => |dst_reg| try self.asmRegister(mir_tag, registerAlias(dst_reg, abi_size)),
169894169946 .register_pair, .register_triple, .register_quadruple => unreachable, // unimplemented
169895 .memory, .load_symbol, .load_got, .load_direct => {
169947 .memory, .load_symbol, .load_pcrel, .load_got, .load_direct => {
169896169948 const addr_reg = try self.register_manager.allocReg(null, abi.RegisterClass.gp);
169897169949 const addr_reg_lock = self.register_manager.lockRegAssumeUnused(addr_reg);
169898169950 defer self.register_manager.unlockReg(addr_reg_lock);
......@@ -171552,6 +171604,8 @@ fn genBinOp(
171552171604 .register_mask,
171553171605 .load_symbol,
171554171606 .lea_symbol,
171607 .load_pcrel,
171608 .lea_pcrel,
171555171609 .load_direct,
171556171610 .lea_direct,
171557171611 .load_got,
......@@ -172740,6 +172794,7 @@ fn genBinOpMir(
172740172794 .lea_got,
172741172795 .lea_frame,
172742172796 .lea_symbol,
172797 .lea_pcrel,
172743172798 .elementwise_args,
172744172799 .reserved_frame,
172745172800 .air_ref,
......@@ -172831,6 +172886,8 @@ fn genBinOpMir(
172831172886 .indirect,
172832172887 .load_symbol,
172833172888 .lea_symbol,
172889 .load_pcrel,
172890 .lea_pcrel,
172834172891 .load_direct,
172835172892 .lea_direct,
172836172893 .load_got,
......@@ -172906,7 +172963,7 @@ fn genBinOpMir(
172906172963 }
172907172964 }
172908172965 },
172909 .memory, .indirect, .load_symbol, .load_got, .load_direct, .load_frame => {
172966 .memory, .indirect, .load_symbol, .load_pcrel, .load_got, .load_direct, .load_frame => {
172910172967 const OpInfo = ?struct { addr_reg: Register, addr_lock: RegisterLock };
172911172968 const limb_abi_size: u32 = @min(abi_size, 8);
172912172969
......@@ -172953,8 +173010,9 @@ fn genBinOpMir(
172953173010 .load_frame,
172954173011 .lea_frame,
172955173012 .lea_symbol,
173013 .lea_pcrel,
172956173014 => null,
172957 .memory, .load_symbol, .load_got, .load_direct => src: {
173015 .memory, .load_symbol, .load_pcrel, .load_got, .load_direct => src: {
172958173016 switch (resolved_src_mcv) {
172959173017 .memory => |addr| if (std.math.cast(i32, @as(i64, @bitCast(addr))) != null and
172960173018 std.math.cast(i32, @as(i64, @bitCast(addr)) + abi_size - limb_abi_size) != null)
......@@ -173093,6 +173151,8 @@ fn genBinOpMir(
173093173151 .indirect,
173094173152 .load_symbol,
173095173153 .lea_symbol,
173154 .load_pcrel,
173155 .lea_pcrel,
173096173156 .load_direct,
173097173157 .lea_direct,
173098173158 .load_got,
......@@ -173160,6 +173220,7 @@ fn genIntMulComplexOpMir(self: *CodeGen, dst_ty: Type, dst_mcv: MCValue, src_mcv
173160173220 .register_overflow,
173161173221 .register_mask,
173162173222 .lea_symbol,
173223 .lea_pcrel,
173163173224 .lea_direct,
173164173225 .lea_got,
173165173226 .lea_frame,
......@@ -173222,6 +173283,8 @@ fn genIntMulComplexOpMir(self: *CodeGen, dst_ty: Type, dst_mcv: MCValue, src_mcv
173222173283 .eflags,
173223173284 .load_symbol,
173224173285 .lea_symbol,
173286 .load_pcrel,
173287 .lea_pcrel,
173225173288 .load_direct,
173226173289 .lea_direct,
173227173290 .load_got,
......@@ -173281,7 +173344,7 @@ fn genIntMulComplexOpMir(self: *CodeGen, dst_ty: Type, dst_mcv: MCValue, src_mcv
173281173344 }
173282173345 },
173283173346 .register_pair, .register_triple, .register_quadruple => unreachable, // unimplemented
173284 .memory, .indirect, .load_symbol, .load_direct, .load_got, .load_frame => {
173347 .memory, .indirect, .load_symbol, .load_pcrel, .load_direct, .load_got, .load_frame => {
173285173348 const tmp_reg = try self.copyToTmpRegister(dst_ty, dst_mcv);
173286173349 const tmp_mcv = MCValue{ .register = tmp_reg };
173287173350 const tmp_lock = self.register_manager.lockRegAssumeUnused(tmp_reg);
......@@ -173450,7 +173513,8 @@ fn genLocalDebugInfo(
173450173513 .disp = frame_addr.off,
173451173514 } },
173452173515 }),
173453 .lea_symbol => |sym_off| try self.asmAirMemory(.dbg_local, inst, .{
173516 // debug info should explicitly ignore pcrel requirements
173517 .lea_symbol, .lea_pcrel => |sym_off| try self.asmAirMemory(.dbg_local, inst, .{
173454173518 .base = .{ .reloc = sym_off.sym_index },
173455173519 .mod = .{ .rm = .{
173456173520 .size = .qword,
......@@ -174108,12 +174172,13 @@ fn airCmp(self: *CodeGen, inst: Air.Inst.Index, op: std.math.CompareOperator) !v
174108174172 .lea_got,
174109174173 .lea_frame,
174110174174 .lea_symbol,
174175 .lea_pcrel,
174111174176 .elementwise_args,
174112174177 .reserved_frame,
174113174178 .air_ref,
174114174179 => unreachable,
174115174180 .register, .register_pair, .register_triple, .register_quadruple, .load_frame => null,
174116 .memory, .load_symbol, .load_got, .load_direct => dst: {
174181 .memory, .load_symbol, .load_pcrel, .load_got, .load_direct => dst: {
174117174182 switch (resolved_dst_mcv) {
174118174183 .memory => |addr| if (std.math.cast(
174119174184 i32,
......@@ -174122,7 +174187,7 @@ fn airCmp(self: *CodeGen, inst: Air.Inst.Index, op: std.math.CompareOperator) !v
174122174187 i32,
174123174188 @as(i64, @bitCast(addr)) + abi_size - 8,
174124174189 ) != null) break :dst null,
174125 .load_symbol, .load_got, .load_direct => {},
174190 .load_symbol, .load_pcrel, .load_got, .load_direct => {},
174126174191 else => unreachable,
174127174192 }
174128174193
......@@ -174160,6 +174225,7 @@ fn airCmp(self: *CodeGen, inst: Air.Inst.Index, op: std.math.CompareOperator) !v
174160174225 .register_mask,
174161174226 .indirect,
174162174227 .lea_symbol,
174228 .lea_pcrel,
174163174229 .lea_direct,
174164174230 .lea_got,
174165174231 .lea_frame,
......@@ -174168,7 +174234,7 @@ fn airCmp(self: *CodeGen, inst: Air.Inst.Index, op: std.math.CompareOperator) !v
174168174234 .air_ref,
174169174235 => unreachable,
174170174236 .register_pair, .register_triple, .register_quadruple, .load_frame => null,
174171 .memory, .load_symbol, .load_got, .load_direct => src: {
174237 .memory, .load_symbol, .load_pcrel, .load_got, .load_direct => src: {
174172174238 switch (resolved_src_mcv) {
174173174239 .memory => |addr| if (std.math.cast(
174174174240 i32,
......@@ -174177,7 +174243,7 @@ fn airCmp(self: *CodeGen, inst: Air.Inst.Index, op: std.math.CompareOperator) !v
174177174243 i32,
174178174244 @as(i64, @bitCast(addr)) + abi_size - 8,
174179174245 ) != null) break :src null,
174180 .load_symbol, .load_got, .load_direct => {},
174246 .load_symbol, .load_pcrel, .load_got, .load_direct => {},
174181174247 else => unreachable,
174182174248 }
174183174249
......@@ -174568,6 +174634,7 @@ fn isNull(self: *CodeGen, inst: Air.Inst.Index, opt_ty: Type, opt_mcv: MCValue)
174568174634 .lea_direct,
174569174635 .lea_got,
174570174636 .lea_symbol,
174637 .lea_pcrel,
174571174638 .elementwise_args,
174572174639 .reserved_frame,
174573174640 .air_ref,
......@@ -174616,6 +174683,7 @@ fn isNull(self: *CodeGen, inst: Air.Inst.Index, opt_ty: Type, opt_mcv: MCValue)
174616174683
174617174684 .memory,
174618174685 .load_symbol,
174686 .load_pcrel,
174619174687 .load_got,
174620174688 .load_direct,
174621174689 => {
......@@ -176625,6 +176693,7 @@ fn genCopy(self: *CodeGen, ty: Type, dst_mcv: MCValue, src_mcv: MCValue, opts: C
176625176693 .lea_got,
176626176694 .lea_frame,
176627176695 .lea_symbol,
176696 .lea_pcrel,
176628176697 .elementwise_args,
176629176698 .reserved_frame,
176630176699 .air_ref,
......@@ -176719,7 +176788,7 @@ fn genCopy(self: *CodeGen, ty: Type, dst_mcv: MCValue, src_mcv: MCValue, opts: C
176719176788 }
176720176789 return;
176721176790 },
176722 .load_symbol, .load_direct, .load_got => {
176791 .load_symbol, .load_pcrel, .load_direct, .load_got => {
176723176792 const src_addr_reg =
176724176793 (try self.register_manager.allocReg(null, abi.RegisterClass.gp)).to64();
176725176794 const src_addr_lock = self.register_manager.lockRegAssumeUnused(src_addr_reg);
......@@ -176752,7 +176821,7 @@ fn genCopy(self: *CodeGen, ty: Type, dst_mcv: MCValue, src_mcv: MCValue, opts: C
176752176821 .undef => if (opts.safety and part_i > 0) .{ .register = dst_regs[0] } else .undef,
176753176822 dst_tag => |src_regs| .{ .register = src_regs[part_i] },
176754176823 .memory, .indirect, .load_frame => src_mcv.address().offset(part_disp).deref(),
176755 .load_symbol, .load_direct, .load_got => .{ .indirect = .{
176824 .load_symbol, .load_pcrel, .load_direct, .load_got => .{ .indirect = .{
176756176825 .reg = src_info.?.addr_reg,
176757176826 .off = part_disp,
176758176827 } },
......@@ -176773,11 +176842,11 @@ fn genCopy(self: *CodeGen, ty: Type, dst_mcv: MCValue, src_mcv: MCValue, opts: C
176773176842 src_mcv,
176774176843 opts,
176775176844 ),
176776 .memory, .load_symbol, .load_direct, .load_got => {
176845 .memory, .load_symbol, .load_pcrel, .load_direct, .load_got => {
176777176846 switch (dst_mcv) {
176778176847 .memory => |addr| if (std.math.cast(i32, @as(i64, @bitCast(addr)))) |small_addr|
176779176848 return self.genSetMem(.{ .reg = .ds }, small_addr, ty, src_mcv, opts),
176780 .load_symbol, .load_direct, .load_got => {},
176849 .load_symbol, .load_pcrel, .load_direct, .load_got => {},
176781176850 else => unreachable,
176782176851 }
176783176852
......@@ -177234,7 +177303,7 @@ fn genSetReg(
177234177303 if (src_reg_mask.info.inverted) try self.asmRegister(.{ ._, .not }, registerAlias(bits_reg, abi_size));
177235177304 try self.genSetReg(dst_reg, ty, .{ .register = bits_reg }, .{});
177236177305 },
177237 .memory, .load_symbol, .load_direct, .load_got => {
177306 .memory, .load_symbol, .load_pcrel, .load_direct, .load_got => {
177238177307 switch (src_mcv) {
177239177308 .memory => |addr| if (std.math.cast(i32, @as(i64, @bitCast(addr)))) |small_addr|
177240177309 return (try self.moveStrategy(
......@@ -177263,6 +177332,21 @@ fn genSetReg(
177263177332 .segment, .mmx, .ip, .cr, .dr => unreachable,
177264177333 .x87, .sse => {},
177265177334 },
177335 .load_pcrel => |sym_off| switch (dst_reg.class()) {
177336 .general_purpose, .gphi => {
177337 assert(sym_off.off == 0);
177338 try self.asmRegisterMemory(.{ ._, .mov }, dst_alias, .{
177339 .base = .{ .pcrel = sym_off.sym_index },
177340 .mod = .{ .rm = .{
177341 .size = self.memSize(ty),
177342 .disp = sym_off.off,
177343 } },
177344 });
177345 return;
177346 },
177347 .segment, .mmx, .ip, .cr, .dr => unreachable,
177348 .x87, .sse => {},
177349 },
177266177350 .load_direct => |sym_index| switch (dst_reg.class()) {
177267177351 .general_purpose, .gphi => {
177268177352 _ = try self.addInst(.{
......@@ -177313,6 +177397,28 @@ fn genSetReg(
177313177397 @tagName(self.bin_file.tag),
177314177398 }),
177315177399 },
177400 .lea_pcrel => |sym_off| switch (self.bin_file.tag) {
177401 .elf, .macho => {
177402 try self.asmRegisterMemory(
177403 .{ ._, .lea },
177404 dst_reg.to64(),
177405 .{
177406 .base = .{ .pcrel = sym_off.sym_index },
177407 },
177408 );
177409 if (sym_off.off != 0) try self.asmRegisterMemory(
177410 .{ ._, .lea },
177411 dst_reg.to64(),
177412 .{
177413 .base = .{ .reg = dst_reg.to64() },
177414 .mod = .{ .rm = .{ .disp = sym_off.off } },
177415 },
177416 );
177417 },
177418 else => return self.fail("TODO emit symbol sequence on {s}", .{
177419 @tagName(self.bin_file.tag),
177420 }),
177421 },
177316177422 .lea_direct, .lea_got => |sym_index| _ = try self.addInst(.{
177317177423 .tag = switch (src_mcv) {
177318177424 .lea_direct => .lea,
......@@ -177350,6 +177456,7 @@ fn genSetMem(
177350177456 .frame => |base_frame_index| .{ .lea_frame = .{ .index = base_frame_index, .off = disp } },
177351177457 .table, .rip_inst => unreachable,
177352177458 .reloc => |sym_index| .{ .lea_symbol = .{ .sym_index = sym_index, .off = disp } },
177459 .pcrel => |sym_index| .{ .lea_pcrel = .{ .sym_index = sym_index, .off = disp } },
177353177460 };
177354177461 switch (src_mcv) {
177355177462 .none,
......@@ -177466,7 +177573,7 @@ fn genSetMem(
177466177573 .off = disp,
177467177574 }).compare(.gte, src_align),
177468177575 .table, .rip_inst => unreachable,
177469 .reloc => false,
177576 .reloc, .pcrel => false,
177470177577 })).write(
177471177578 self,
177472177579 .{ .base = base, .mod = .{ .rm = .{
......@@ -177557,6 +177664,8 @@ fn genSetMem(
177557177664 .lea_frame,
177558177665 .load_symbol,
177559177666 .lea_symbol,
177667 .load_pcrel,
177668 .lea_pcrel,
177560177669 => switch (abi_size) {
177561177670 0 => {},
177562177671 1, 2, 4, 8 => {
......@@ -178110,7 +178219,7 @@ fn airCmpxchg(self: *CodeGen, inst: Air.Inst.Index) !void {
178110178219 .off => return self.fail("TODO airCmpxchg with {s}", .{@tagName(ptr_mcv)}),
178111178220 }
178112178221 const ptr_lock = switch (ptr_mem.base) {
178113 .none, .frame, .reloc => null,
178222 .none, .frame, .reloc, .pcrel => null,
178114178223 .reg => |reg| self.register_manager.lockReg(reg),
178115178224 .table, .rip_inst => unreachable,
178116178225 };
......@@ -178193,7 +178302,7 @@ fn atomicOp(
178193178302 .off => return self.fail("TODO airCmpxchg with {s}", .{@tagName(ptr_mcv)}),
178194178303 }
178195178304 const mem_lock = switch (ptr_mem.base) {
178196 .none, .frame, .reloc => null,
178305 .none, .frame, .reloc, .pcrel => null,
178197178306 .reg => |reg| self.register_manager.lockReg(reg),
178198178307 .table, .rip_inst => unreachable,
178199178308 };
......@@ -182266,6 +182375,8 @@ const Temp = struct {
182266182375 .memory,
182267182376 .load_symbol,
182268182377 .lea_symbol,
182378 .load_pcrel,
182379 .lea_pcrel,
182269182380 .indirect,
182270182381 .load_direct,
182271182382 .lea_direct,
......@@ -182427,6 +182538,22 @@ const Temp = struct {
182427182538 assert(limb_index == 0);
182428182539 new_temp_index.tracking(cg).* = .init(.{ .lea_symbol = sym_off });
182429182540 },
182541 .load_pcrel => |sym_off| {
182542 const new_reg =
182543 try cg.register_manager.allocReg(new_temp_index.toIndex(), abi.RegisterClass.gp);
182544 new_temp_index.tracking(cg).* = .init(.{ .register = new_reg });
182545 try cg.asmRegisterMemory(.{ ._, .mov }, new_reg.to64(), .{
182546 .base = .{ .pcrel = sym_off.sym_index },
182547 .mod = .{ .rm = .{
182548 .size = .qword,
182549 .disp = sym_off.off + @as(u31, limb_index) * 8,
182550 } },
182551 });
182552 },
182553 .lea_pcrel => |sym_off| {
182554 assert(limb_index == 0);
182555 new_temp_index.tracking(cg).* = .init(.{ .lea_pcrel = sym_off });
182556 },
182430182557 .load_frame => |frame_addr| {
182431182558 const new_reg =
182432182559 try cg.register_manager.allocReg(new_temp_index.toIndex(), abi.RegisterClass.gp);
......@@ -182721,11 +182848,12 @@ const Temp = struct {
182721182848 .memory,
182722182849 .indirect,
182723182850 .load_symbol,
182851 .load_pcrel,
182724182852 .load_direct,
182725182853 .load_got,
182726182854 .load_frame,
182727182855 => return temp.toRegClass(true, .general_purpose, cg),
182728 .lea_symbol => |sym_off| {
182856 .lea_symbol, .lea_pcrel => |sym_off| {
182729182857 const off = sym_off.off;
182730182858 // hack around linker relocation bugs
182731182859 if (false and off == 0) return false;
......@@ -187464,6 +187592,8 @@ const Temp = struct {
187464187592 .memory,
187465187593 .load_symbol,
187466187594 .lea_symbol,
187595 .load_pcrel,
187596 .lea_pcrel,
187467187597 .indirect,
187468187598 .load_direct,
187469187599 .lea_direct,
......@@ -190044,6 +190174,7 @@ const Select = struct {
190044190174 .register => |base_reg| .{ .reg = base_reg.toSize(.ptr, s.cg.target) },
190045190175 .register_offset => |base_reg_off| .{ .reg = base_reg_off.reg.toSize(.ptr, s.cg.target) },
190046190176 .lea_symbol => |base_sym_off| .{ .reloc = base_sym_off.sym_index },
190177 .lea_pcrel => |base_sym_off| .{ .pcrel = base_sym_off.sym_index },
190047190178 },
190048190179 .mod = .{ .rm = .{
190049190180 .size = op.flags.base.size,
src/arch/x86_64/Emit.zig+4-3
......@@ -189,12 +189,12 @@ pub fn emitMir(emit: *Emit) Error!void {
189189 .r_addend = lowered_relocs[0].off,
190190 }, zo);
191191 },
192 .linker_reloc => |sym_index| if (emit.lower.bin_file.cast(.elf)) |elf_file| {
192 .linker_reloc, .linker_pcrel => |sym_index| if (emit.lower.bin_file.cast(.elf)) |elf_file| {
193193 const zo = elf_file.zigObjectPtr().?;
194194 const atom = zo.symbol(emit.atom_index).atom(elf_file).?;
195195 const sym = zo.symbol(sym_index);
196196 if (emit.lower.pic) {
197 const r_type: u32 = if (sym.flags.is_extern_ptr)
197 const r_type: u32 = if (sym.flags.is_extern_ptr and lowered_relocs[0].target != .linker_pcrel)
198198 @intFromEnum(std.elf.R_X86_64.GOTPCREL)
199199 else
200200 @intFromEnum(std.elf.R_X86_64.PC32);
......@@ -218,7 +218,7 @@ pub fn emitMir(emit: *Emit) Error!void {
218218 const zo = macho_file.getZigObject().?;
219219 const atom = zo.symbols.items[emit.atom_index].getAtom(macho_file).?;
220220 const sym = &zo.symbols.items[sym_index];
221 const @"type": link.File.MachO.Relocation.Type = if (sym.flags.is_extern_ptr)
221 const @"type": link.File.MachO.Relocation.Type = if (sym.flags.is_extern_ptr and lowered_relocs[0].target != .linker_pcrel)
222222 .got_load
223223 else if (sym.flags.tlv)
224224 .tlv
......@@ -438,6 +438,7 @@ pub fn emitMir(emit: *Emit) Error!void {
438438 .reg => |reg| .{ .breg = reg.dwarfNum() },
439439 .frame, .table, .rip_inst => unreachable,
440440 .reloc => |sym_index| .{ .addr_reloc = sym_index },
441 .pcrel => unreachable,
441442 };
442443 break :base &loc_buf[0];
443444 },
src/arch/x86_64/Lower.zig+19-2
......@@ -66,6 +66,7 @@ pub const Reloc = struct {
6666 inst: Mir.Inst.Index,
6767 table,
6868 linker_reloc: u32,
69 linker_pcrel: u32,
6970 linker_tlsld: u32,
7071 linker_dtpoff: u32,
7172 linker_extern_fn: u32,
......@@ -421,9 +422,9 @@ fn emit(lower: *Lower, prefix: Prefix, mnemonic: Mnemonic, ops: []const Operand)
421422 for (emit_ops, ops, 0..) |*emit_op, op, op_index| {
422423 emit_op.* = switch (op) {
423424 else => op,
424 .mem => |mem_op| switch (mem_op.base()) {
425 .mem => |mem_op| op: switch (mem_op.base()) {
425426 else => op,
426 .reloc => |sym_index| op: {
427 .reloc => |sym_index| {
427428 assert(prefix == .none);
428429 assert(mem_op.sib.disp == 0);
429430 assert(mem_op.sib.scale_index.scale == 0);
......@@ -559,6 +560,22 @@ fn emit(lower: *Lower, prefix: Prefix, mnemonic: Mnemonic, ops: []const Operand)
559560 return lower.fail("TODO: bin format '{s}'", .{@tagName(lower.bin_file.tag)});
560561 }
561562 },
563 .pcrel => |sym_index| {
564 assert(prefix == .none);
565 assert(mem_op.sib.disp == 0);
566 assert(mem_op.sib.scale_index.scale == 0);
567
568 _ = lower.reloc(@intCast(op_index), .{ .linker_pcrel = sym_index }, 0);
569 break :op switch (lower.bin_file.tag) {
570 .elf => op,
571 .macho => switch (mnemonic) {
572 .lea => .{ .mem = Memory.initRip(.none, 0) },
573 .mov => .{ .mem = Memory.initRip(mem_op.sib.ptr_size, 0) },
574 else => unreachable,
575 },
576 else => |tag| return lower.fail("TODO: bin format '{s}'", .{@tagName(tag)}),
577 };
578 },
562579 },
563580 };
564581 }
src/arch/x86_64/Mir.zig+3-2
......@@ -1866,7 +1866,7 @@ pub const Memory = struct {
18661866 .none, .table => undefined,
18671867 .reg => |reg| @intFromEnum(reg),
18681868 .frame => |frame_index| @intFromEnum(frame_index),
1869 .reloc => |sym_index| sym_index,
1869 .reloc, .pcrel => |sym_index| sym_index,
18701870 .rip_inst => |inst_index| inst_index,
18711871 },
18721872 .off = switch (mem.mod) {
......@@ -1895,6 +1895,7 @@ pub const Memory = struct {
18951895 .frame => .{ .frame = @enumFromInt(mem.base) },
18961896 .table => .table,
18971897 .reloc => .{ .reloc = mem.base },
1898 .pcrel => .{ .pcrel = mem.base },
18981899 .rip_inst => .{ .rip_inst = mem.base },
18991900 },
19001901 .scale_index = switch (mem.info.index) {
......@@ -1959,7 +1960,7 @@ pub fn resolveFrameAddr(mir: Mir, frame_addr: bits.FrameAddr) bits.RegisterOffse
19591960
19601961pub fn resolveFrameLoc(mir: Mir, mem: Memory) Memory {
19611962 return switch (mem.info.base) {
1962 .none, .reg, .table, .reloc, .rip_inst => mem,
1963 .none, .reg, .table, .reloc, .pcrel, .rip_inst => mem,
19631964 .frame => if (mir.frame_locs.len > 0) .{
19641965 .info = .{
19651966 .base = .reg,
src/arch/x86_64/bits.zig+1
......@@ -762,6 +762,7 @@ pub const Memory = struct {
762762 frame: FrameIndex,
763763 table,
764764 reloc: u32,
765 pcrel: u32,
765766 rip_inst: Mir.Inst.Index,
766767
767768 pub const Tag = @typeInfo(Base).@"union".tag_type.?;
src/arch/x86_64/encoder.zig+4-3
......@@ -138,7 +138,7 @@ pub const Instruction = struct {
138138 .moffs => true,
139139 .rip => false,
140140 .sib => |s| switch (s.base) {
141 .none, .frame, .table, .reloc, .rip_inst => false,
141 .none, .frame, .table, .reloc, .pcrel, .rip_inst => false,
142142 .reg => |reg| reg.isClass(.segment),
143143 },
144144 };
......@@ -211,7 +211,7 @@ pub const Instruction = struct {
211211 .none, .imm => 0b00,
212212 .reg => |reg| @truncate(reg.enc() >> 3),
213213 .mem => |mem| switch (mem.base()) {
214 .none, .frame, .table, .reloc, .rip_inst => 0b00, // rsp, rbp, and rip are not extended
214 .none, .frame, .table, .reloc, .pcrel, .rip_inst => 0b00, // rsp, rbp, and rip are not extended
215215 .reg => |reg| @truncate(reg.enc() >> 3),
216216 },
217217 .bytes => unreachable,
......@@ -282,6 +282,7 @@ pub const Instruction = struct {
282282 .frame => |frame_index| try writer.print("{}", .{frame_index}),
283283 .table => try writer.print("Table", .{}),
284284 .reloc => |sym_index| try writer.print("Symbol({d})", .{sym_index}),
285 .pcrel => |sym_index| try writer.print("PcRelSymbol({d})", .{sym_index}),
285286 .rip_inst => |inst_index| try writer.print("RipInst({d})", .{inst_index}),
286287 }
287288 if (mem.scaleIndex()) |si| {
......@@ -721,7 +722,7 @@ pub const Instruction = struct {
721722 try encoder.modRm_indirectDisp32(operand_enc, 0);
722723 try encoder.disp32(undefined);
723724 } else return error.CannotEncode,
724 .rip_inst => {
725 .pcrel, .rip_inst => {
725726 try encoder.modRm_RIPDisp32(operand_enc);
726727 try encoder.disp32(sib.disp);
727728 },
src/codegen.zig+57-24
......@@ -921,41 +921,74 @@ fn genNavRef(
921921 const nav = ip.getNav(nav_index);
922922 assert(!nav.isThreadlocal(ip));
923923
924 const is_extern, const lib_name = if (nav.getExtern(ip)) |e|
925 .{ true, e.lib_name }
924 const lib_name, const linkage, const visibility = if (nav.getExtern(ip)) |e|
925 .{ e.lib_name, e.linkage, e.visibility }
926926 else
927 .{ false, .none };
927 .{ .none, .internal, .default };
928928
929929 const name = nav.name;
930930 if (lf.cast(.elf)) |elf_file| {
931931 const zo = elf_file.zigObjectPtr().?;
932 if (is_extern) {
933 const sym_index = try elf_file.getGlobalSymbol(name.toSlice(ip), lib_name.toSlice(ip));
934 zo.symbol(sym_index).flags.is_extern_ptr = true;
935 return .{ .mcv = .{ .lea_symbol = sym_index } };
932 switch (linkage) {
933 .internal => {
934 const sym_index = try zo.getOrCreateMetadataForNav(zcu, nav_index);
935 return .{ .mcv = .{ .lea_symbol = sym_index } };
936 },
937 .strong, .weak => {
938 const sym_index = try elf_file.getGlobalSymbol(name.toSlice(ip), lib_name.toSlice(ip));
939 switch (linkage) {
940 .internal => unreachable,
941 .strong => {},
942 .weak => zo.symbol(sym_index).flags.weak = true,
943 .link_once => unreachable,
944 }
945 switch (visibility) {
946 .default => zo.symbol(sym_index).flags.is_extern_ptr = true,
947 .hidden, .protected => {},
948 }
949 return .{ .mcv = .{ .lea_symbol = sym_index } };
950 },
951 .link_once => unreachable,
936952 }
937 const sym_index = try zo.getOrCreateMetadataForNav(zcu, nav_index);
938 return .{ .mcv = .{ .lea_symbol = sym_index } };
939953 } else if (lf.cast(.macho)) |macho_file| {
940954 const zo = macho_file.getZigObject().?;
941 if (is_extern) {
942 const sym_index = try macho_file.getGlobalSymbol(name.toSlice(ip), lib_name.toSlice(ip));
943 zo.symbols.items[sym_index].flags.is_extern_ptr = true;
944 return .{ .mcv = .{ .lea_symbol = sym_index } };
955 switch (linkage) {
956 .internal => {
957 const sym_index = try zo.getOrCreateMetadataForNav(macho_file, nav_index);
958 const sym = zo.symbols.items[sym_index];
959 return .{ .mcv = .{ .lea_symbol = sym.nlist_idx } };
960 },
961 .strong, .weak => {
962 const sym_index = try macho_file.getGlobalSymbol(name.toSlice(ip), lib_name.toSlice(ip));
963 switch (linkage) {
964 .internal => unreachable,
965 .strong => {},
966 .weak => zo.symbols.items[sym_index].flags.weak = true,
967 .link_once => unreachable,
968 }
969 switch (visibility) {
970 .default => zo.symbols.items[sym_index].flags.is_extern_ptr = true,
971 .hidden, .protected => {},
972 }
973 return .{ .mcv = .{ .lea_symbol = sym_index } };
974 },
975 .link_once => unreachable,
945976 }
946 const sym_index = try zo.getOrCreateMetadataForNav(macho_file, nav_index);
947 const sym = zo.symbols.items[sym_index];
948 return .{ .mcv = .{ .lea_symbol = sym.nlist_idx } };
949977 } else if (lf.cast(.coff)) |coff_file| {
950 if (is_extern) {
951 // TODO audit this
952 const global_index = try coff_file.getGlobalSymbol(name.toSlice(ip), lib_name.toSlice(ip));
953 try coff_file.need_got_table.put(gpa, global_index, {}); // needs GOT
954 return .{ .mcv = .{ .load_got = link.File.Coff.global_symbol_bit | global_index } };
978 // TODO audit this
979 switch (linkage) {
980 .internal => {
981 const atom_index = try coff_file.getOrCreateAtomForNav(nav_index);
982 const sym_index = coff_file.getAtom(atom_index).getSymbolIndex().?;
983 return .{ .mcv = .{ .load_got = sym_index } };
984 },
985 .strong, .weak => {
986 const global_index = try coff_file.getGlobalSymbol(name.toSlice(ip), lib_name.toSlice(ip));
987 try coff_file.need_got_table.put(gpa, global_index, {}); // needs GOT
988 return .{ .mcv = .{ .load_got = link.File.Coff.global_symbol_bit | global_index } };
989 },
990 .link_once => unreachable,
955991 }
956 const atom_index = try coff_file.getOrCreateAtomForNav(nav_index);
957 const sym_index = coff_file.getAtom(atom_index).getSymbolIndex().?;
958 return .{ .mcv = .{ .load_got = sym_index } };
959992 } else if (lf.cast(.plan9)) |p9| {
960993 const atom_index = try p9.seeNav(pt, nav_index);
961994 const atom = p9.getAtom(atom_index);
src/codegen/c.zig+22-12
......@@ -2255,19 +2255,30 @@ pub const DeclGen = struct {
22552255 fn renderFwdDecl(
22562256 dg: *DeclGen,
22572257 nav_index: InternPool.Nav.Index,
2258 flags: struct {
2259 is_extern: bool,
2258 flags: packed struct {
22602259 is_const: bool,
22612260 is_threadlocal: bool,
2262 is_weak_linkage: bool,
2261 linkage: std.builtin.GlobalLinkage,
2262 visibility: std.builtin.SymbolVisibility,
22632263 },
22642264 ) !void {
22652265 const zcu = dg.pt.zcu;
22662266 const ip = &zcu.intern_pool;
22672267 const nav = ip.getNav(nav_index);
22682268 const fwd = dg.fwdDeclWriter();
2269 try fwd.writeAll(if (flags.is_extern) "zig_extern " else "static ");
2270 if (flags.is_weak_linkage) try fwd.writeAll("zig_weak_linkage ");
2269 try fwd.writeAll(switch (flags.linkage) {
2270 .internal => "static ",
2271 .strong, .weak, .link_once => "zig_extern ",
2272 });
2273 switch (flags.linkage) {
2274 .internal, .strong => {},
2275 .weak => try fwd.writeAll("zig_weak_linkage "),
2276 .link_once => return dg.fail("TODO: CBE: implement linkonce linkage?", .{}),
2277 }
2278 switch (flags.linkage) {
2279 .internal => {},
2280 .strong, .weak, .link_once => try fwd.print("zig_visibility({s}) ", .{@tagName(flags.visibility)}),
2281 }
22712282 if (flags.is_threadlocal and !dg.mod.single_threaded) try fwd.writeAll("zig_threadlocal ");
22722283 try dg.renderTypeAndName(
22732284 fwd,
......@@ -2994,10 +3005,10 @@ pub fn genDecl(o: *Object) !void {
29943005 switch (ip.indexToKey(nav.status.fully_resolved.val)) {
29953006 .@"extern" => |@"extern"| {
29963007 if (!ip.isFunctionType(nav_ty.toIntern())) return o.dg.renderFwdDecl(o.dg.pass.nav, .{
2997 .is_extern = true,
29983008 .is_const = @"extern".is_const,
29993009 .is_threadlocal = @"extern".is_threadlocal,
3000 .is_weak_linkage = @"extern".is_weak_linkage,
3010 .linkage = @"extern".linkage,
3011 .visibility = @"extern".visibility,
30013012 });
30023013
30033014 const fwd = o.dg.fwdDeclWriter();
......@@ -3016,13 +3027,12 @@ pub fn genDecl(o: *Object) !void {
30163027 },
30173028 .variable => |variable| {
30183029 try o.dg.renderFwdDecl(o.dg.pass.nav, .{
3019 .is_extern = false,
30203030 .is_const = false,
30213031 .is_threadlocal = variable.is_threadlocal,
3022 .is_weak_linkage = variable.is_weak_linkage,
3032 .linkage = .internal,
3033 .visibility = .default,
30233034 });
30243035 const w = o.writer();
3025 if (variable.is_weak_linkage) try w.writeAll("zig_weak_linkage ");
30263036 if (variable.is_threadlocal and !o.dg.mod.single_threaded) try w.writeAll("zig_threadlocal ");
30273037 if (nav.status.fully_resolved.@"linksection".toSlice(&zcu.intern_pool)) |s|
30283038 try w.print("zig_linksection({s}) ", .{fmtStringLiteral(s, null)});
......@@ -3467,7 +3477,7 @@ fn genBodyInner(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail,
34673477 .error_set_has_value => return f.fail("TODO: C backend: implement error_set_has_value", .{}),
34683478 .vector_store_elem => return f.fail("TODO: C backend: implement vector_store_elem", .{}),
34693479
3470 .tlv_dllimport_ptr => try airTlvDllimportPtr(f, inst),
3480 .runtime_nav_ptr => try airRuntimeNavPtr(f, inst),
34713481
34723482 .c_va_start => try airCVaStart(f, inst),
34733483 .c_va_arg => try airCVaArg(f, inst),
......@@ -7672,7 +7682,7 @@ fn airMulAdd(f: *Function, inst: Air.Inst.Index) !CValue {
76727682 return local;
76737683}
76747684
7675fn airTlvDllimportPtr(f: *Function, inst: Air.Inst.Index) !CValue {
7685fn airRuntimeNavPtr(f: *Function, inst: Air.Inst.Index) !CValue {
76767686 const ty_nav = f.air.instructions.items(.data)[@intFromEnum(inst)].ty_nav;
76777687 const writer = f.object.writer();
76787688 const local = try f.allocLocal(inst, .fromInterned(ty_nav.ty));
src/codegen/llvm.zig+73-50
......@@ -2979,36 +2979,49 @@ pub const Object = struct {
29792979 const zcu = pt.zcu;
29802980 const ip = &zcu.intern_pool;
29812981 const nav = ip.getNav(nav_index);
2982 const is_extern, const is_threadlocal, const is_weak_linkage, const is_dll_import = switch (nav.status) {
2982 const linkage: std.builtin.GlobalLinkage, const visibility: Builder.Visibility, const is_threadlocal, const is_dll_import = switch (nav.status) {
29832983 .unresolved => unreachable,
29842984 .fully_resolved => |r| switch (ip.indexToKey(r.val)) {
2985 .variable => |variable| .{ false, variable.is_threadlocal, variable.is_weak_linkage, false },
2986 .@"extern" => |@"extern"| .{ true, @"extern".is_threadlocal, @"extern".is_weak_linkage, @"extern".is_dll_import },
2987 else => .{ false, false, false, false },
2985 .variable => |variable| .{ .internal, .default, variable.is_threadlocal, false },
2986 .@"extern" => |@"extern"| .{ @"extern".linkage, .fromSymbolVisibility(@"extern".visibility), @"extern".is_threadlocal, @"extern".is_dll_import },
2987 else => .{ .internal, .default, false, false },
29882988 },
29892989 // This means it's a source declaration which is not `extern`!
2990 .type_resolved => |r| .{ false, r.is_threadlocal, false, false },
2990 .type_resolved => |r| .{ .internal, .default, r.is_threadlocal, false },
29912991 };
29922992
29932993 const variable_index = try o.builder.addVariable(
2994 try o.builder.strtabString((if (is_extern) nav.name else nav.fqn).toSlice(ip)),
2994 try o.builder.strtabString(switch (linkage) {
2995 .internal => nav.fqn,
2996 .strong, .weak => nav.name,
2997 .link_once => unreachable,
2998 }.toSlice(ip)),
29952999 try o.lowerType(Type.fromInterned(nav.typeOf(ip))),
29963000 toLlvmGlobalAddressSpace(nav.getAddrspace(), zcu.getTarget()),
29973001 );
29983002 gop.value_ptr.* = variable_index.ptrConst(&o.builder).global;
29993003
30003004 // This is needed for declarations created by `@extern`.
3001 if (is_extern) {
3002 variable_index.setLinkage(.external, &o.builder);
3003 variable_index.setUnnamedAddr(.default, &o.builder);
3004 if (is_threadlocal and !zcu.navFileScope(nav_index).mod.?.single_threaded)
3005 variable_index.setThreadLocal(.generaldynamic, &o.builder);
3006 if (is_weak_linkage) variable_index.setLinkage(.extern_weak, &o.builder);
3007 if (is_dll_import) variable_index.setDllStorageClass(.dllimport, &o.builder);
3008 } else {
3009 variable_index.setLinkage(.internal, &o.builder);
3010 variable_index.setUnnamedAddr(.unnamed_addr, &o.builder);
3011 }
3005 switch (linkage) {
3006 .internal => {
3007 variable_index.setLinkage(.internal, &o.builder);
3008 variable_index.setUnnamedAddr(.unnamed_addr, &o.builder);
3009 },
3010 .strong, .weak => {
3011 variable_index.setLinkage(switch (linkage) {
3012 .internal => unreachable,
3013 .strong => .external,
3014 .weak => .extern_weak,
3015 .link_once => unreachable,
3016 }, &o.builder);
3017 variable_index.setUnnamedAddr(.default, &o.builder);
3018 if (is_threadlocal and !zcu.navFileScope(nav_index).mod.?.single_threaded)
3019 variable_index.setThreadLocal(.generaldynamic, &o.builder);
3020 if (is_dll_import) variable_index.setDllStorageClass(.dllimport, &o.builder);
3021 },
3022 .link_once => unreachable,
3023 }
3024 variable_index.setVisibility(visibility, &o.builder);
30123025 return variable_index;
30133026 }
30143027
......@@ -4530,14 +4543,14 @@ pub const NavGen = struct {
45304543 const nav = ip.getNav(nav_index);
45314544 const resolved = nav.status.fully_resolved;
45324545
4533 const is_extern, const lib_name, const is_threadlocal, const is_weak_linkage, const is_dll_import, const is_const, const init_val, const owner_nav = switch (ip.indexToKey(resolved.val)) {
4534 .variable => |variable| .{ false, .none, variable.is_threadlocal, variable.is_weak_linkage, false, false, variable.init, variable.owner_nav },
4535 .@"extern" => |@"extern"| .{ true, @"extern".lib_name, @"extern".is_threadlocal, @"extern".is_weak_linkage, @"extern".is_dll_import, @"extern".is_const, .none, @"extern".owner_nav },
4536 else => .{ false, .none, false, false, false, true, resolved.val, nav_index },
4546 const lib_name, const linkage, const visibility: Builder.Visibility, const is_threadlocal, const is_dll_import, const is_const, const init_val, const owner_nav = switch (ip.indexToKey(resolved.val)) {
4547 .variable => |variable| .{ .none, .internal, .default, variable.is_threadlocal, false, false, variable.init, variable.owner_nav },
4548 .@"extern" => |@"extern"| .{ @"extern".lib_name, @"extern".linkage, .fromSymbolVisibility(@"extern".visibility), @"extern".is_threadlocal, @"extern".is_dll_import, @"extern".is_const, .none, @"extern".owner_nav },
4549 else => .{ .none, .internal, .default, false, false, true, resolved.val, nav_index },
45374550 };
45384551 const ty = Type.fromInterned(nav.typeOf(ip));
45394552
4540 if (is_extern and ip.isFunctionType(ty.toIntern())) {
4553 if (linkage != .internal and ip.isFunctionType(ty.toIntern())) {
45414554 _ = try o.resolveLlvmFunction(owner_nav);
45424555 } else {
45434556 const variable_index = try o.resolveGlobalNav(nav_index);
......@@ -4549,6 +4562,7 @@ pub const NavGen = struct {
45494562 .none => .no_init,
45504563 else => try o.lowerValue(init_val),
45514564 }, &o.builder);
4565 variable_index.setVisibility(visibility, &o.builder);
45524566
45534567 const file_scope = zcu.navFileScopeIndex(nav_index);
45544568 const mod = zcu.fileByIndex(file_scope).mod.?;
......@@ -4568,7 +4582,7 @@ pub const NavGen = struct {
45684582 line_number,
45694583 try o.lowerDebugType(ty),
45704584 variable_index,
4571 .{ .local = !is_extern },
4585 .{ .local = linkage == .internal },
45724586 );
45734587
45744588 const debug_expression = try o.builder.debugExpression(&.{});
......@@ -4583,38 +4597,47 @@ pub const NavGen = struct {
45834597 }
45844598 }
45854599
4586 if (is_extern) {
4587 const global_index = o.nav_map.get(nav_index).?;
4600 switch (linkage) {
4601 .internal => {},
4602 .strong, .weak => {
4603 const global_index = o.nav_map.get(nav_index).?;
45884604
4589 const decl_name = decl_name: {
4590 if (zcu.getTarget().cpu.arch.isWasm() and ty.zigTypeTag(zcu) == .@"fn") {
4591 if (lib_name.toSlice(ip)) |lib_name_slice| {
4592 if (!std.mem.eql(u8, lib_name_slice, "c")) {
4593 break :decl_name try o.builder.strtabStringFmt("{}|{s}", .{ nav.name.fmt(ip), lib_name_slice });
4605 const decl_name = decl_name: {
4606 if (zcu.getTarget().cpu.arch.isWasm() and ty.zigTypeTag(zcu) == .@"fn") {
4607 if (lib_name.toSlice(ip)) |lib_name_slice| {
4608 if (!std.mem.eql(u8, lib_name_slice, "c")) {
4609 break :decl_name try o.builder.strtabStringFmt("{}|{s}", .{ nav.name.fmt(ip), lib_name_slice });
4610 }
45944611 }
45954612 }
4596 }
4597 break :decl_name try o.builder.strtabString(nav.name.toSlice(ip));
4598 };
4613 break :decl_name try o.builder.strtabString(nav.name.toSlice(ip));
4614 };
45994615
4600 if (o.builder.getGlobal(decl_name)) |other_global| {
4601 if (other_global != global_index) {
4602 // Another global already has this name; just use it in place of this global.
4603 try global_index.replace(other_global, &o.builder);
4604 return;
4616 if (o.builder.getGlobal(decl_name)) |other_global| {
4617 if (other_global != global_index) {
4618 // Another global already has this name; just use it in place of this global.
4619 try global_index.replace(other_global, &o.builder);
4620 return;
4621 }
46054622 }
4606 }
46074623
4608 try global_index.rename(decl_name, &o.builder);
4609 global_index.setLinkage(.external, &o.builder);
4610 global_index.setUnnamedAddr(.default, &o.builder);
4611 if (is_dll_import) {
4612 global_index.setDllStorageClass(.dllimport, &o.builder);
4613 } else if (zcu.comp.config.dll_export_fns) {
4614 global_index.setDllStorageClass(.default, &o.builder);
4615 }
4624 try global_index.rename(decl_name, &o.builder);
4625 global_index.setUnnamedAddr(.default, &o.builder);
4626 if (is_dll_import) {
4627 global_index.setDllStorageClass(.dllimport, &o.builder);
4628 } else if (zcu.comp.config.dll_export_fns) {
4629 global_index.setDllStorageClass(.default, &o.builder);
4630 }
46164631
4617 if (is_weak_linkage) global_index.setLinkage(.extern_weak, &o.builder);
4632 global_index.setLinkage(switch (linkage) {
4633 .internal => unreachable,
4634 .strong => .external,
4635 .weak => .extern_weak,
4636 .link_once => unreachable,
4637 }, &o.builder);
4638 global_index.setVisibility(visibility, &o.builder);
4639 },
4640 .link_once => unreachable,
46184641 }
46194642 }
46204643};
......@@ -5023,7 +5046,7 @@ pub const FuncGen = struct {
50235046
50245047 .vector_store_elem => try self.airVectorStoreElem(inst),
50255048
5026 .tlv_dllimport_ptr => try self.airTlvDllimportPtr(inst),
5049 .runtime_nav_ptr => try self.airRuntimeNavPtr(inst),
50275050
50285051 .inferred_alloc, .inferred_alloc_comptime => unreachable,
50295052
......@@ -8122,7 +8145,7 @@ pub const FuncGen = struct {
81228145 return .none;
81238146 }
81248147
8125 fn airTlvDllimportPtr(fg: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
8148 fn airRuntimeNavPtr(fg: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
81268149 const o = fg.ng.object;
81278150 const ty_nav = fg.air.instructions.items(.data)[@intFromEnum(inst)].ty_nav;
81288151 const llvm_ptr_const = try o.lowerNavRefValue(ty_nav.nav);
src/link/Dwarf.zig+52-138
......@@ -785,7 +785,6 @@ const Entry = struct {
785785 }
786786
787787 const Index = enum(u32) {
788 //got_proc,
789788 _,
790789
791790 const Optional = enum(u32) {
......@@ -1041,7 +1040,7 @@ const Entry = struct {
10411040 const symbol = zo.symbol(reloc.target_sym);
10421041 try dwarf.resolveReloc(
10431042 entry_off + reloc.source_off,
1044 @bitCast(symbol.address(.{}, elf_file) + @as(i64, @intCast(@intFromEnum(reloc.target_off))) -
1043 @bitCast(symbol.address(.{}, elf_file) + @as(i64, @intCast(reloc.target_off)) -
10451044 if (symbol.flags.is_tls) elf_file.dtpAddress() else 0),
10461045 @intFromEnum(dwarf.address_size),
10471046 );
......@@ -1052,7 +1051,7 @@ const Entry = struct {
10521051 const ref = zo.getSymbolRef(reloc.target_sym, macho_file);
10531052 try dwarf.resolveReloc(
10541053 entry_off + reloc.source_off,
1055 ref.getSymbol(macho_file).?.getAddress(.{}, macho_file) + @as(i64, @intCast(@intFromEnum(reloc.target_off))),
1054 ref.getSymbol(macho_file).?.getAddress(.{}, macho_file) + @as(i64, @intCast(reloc.target_off)),
10561055 @intFromEnum(dwarf.address_size),
10571056 );
10581057 }
......@@ -1081,27 +1080,12 @@ const CrossSectionReloc = struct {
10811080const ExternalReloc = struct {
10821081 source_off: u32 = 0,
10831082 target_sym: u32,
1084 target_off: enum(u64) {
1085 none = 0,
1086 got = std.math.maxInt(i64) + 1,
1087 _,
1088
1089 pub fn rel(off: u64) @This() {
1090 const res: @This() = @enumFromInt(off);
1091 switch (res) {
1092 .none => {},
1093 _ => {},
1094 .got => unreachable, // assertion failure
1095 }
1096 return res;
1097 }
1098 } = .none,
1083 target_off: u64 = 0,
10991084};
11001085
11011086pub const Loc = union(enum) {
11021087 empty,
11031088 addr_reloc: u32,
1104 got_reloc: u32,
11051089 deref: *const Loc,
11061090 constu: u64,
11071091 consts: i64,
......@@ -1166,10 +1150,6 @@ pub const Loc = union(enum) {
11661150 try addr.write(adapter);
11671151 try writer.writeByte(DW.OP.deref);
11681152 },
1169 .got_reloc => |sym_index| {
1170 try writer.writeByte(DW.OP.const4s);
1171 try adapter.gotSym(sym_index);
1172 },
11731153 .constu => |constu| if (std.math.cast(u5, constu)) |lit| {
11741154 try writer.writeByte(@as(u8, DW.OP.lit0) + lit);
11751155 } else if (std.math.cast(u8, constu)) |const1u| {
......@@ -1766,9 +1746,6 @@ pub const WipNav = struct {
17661746 fn endian(_: ExprLocCounter) std.builtin.Endian {
17671747 return @import("builtin").cpu.arch.endian();
17681748 }
1769 fn gotSym(counter: *ExprLocCounter, _: u32) error{}!void {
1770 counter.stream.bytes_written += 4;
1771 }
17721749 fn addrSym(counter: *ExprLocCounter, _: u32) error{}!void {
17731750 counter.stream.bytes_written += @intFromEnum(counter.address_size);
17741751 }
......@@ -1789,14 +1766,6 @@ pub const WipNav = struct {
17891766 fn endian(ctx: @This()) std.builtin.Endian {
17901767 return ctx.wip_nav.dwarf.endian;
17911768 }
1792 fn gotSym(ctx: @This(), sym_index: u32) UpdateError!void {
1793 try ctx.wip_nav.infoExternalReloc(.{
1794 .source_off = @intCast(ctx.wip_nav.debug_info.items.len),
1795 .target_sym = sym_index,
1796 .target_off = .got,
1797 });
1798 try ctx.wip_nav.debug_info.appendNTimes(ctx.wip_nav.dwarf.gpa, 0, 4);
1799 }
18001769 fn addrSym(ctx: @This(), sym_index: u32) UpdateError!void {
18011770 try ctx.wip_nav.infoAddrSym(sym_index, 0);
18021771 }
......@@ -1812,7 +1781,7 @@ pub const WipNav = struct {
18121781 try wip_nav.infoExternalReloc(.{
18131782 .source_off = @intCast(wip_nav.debug_info.items.len),
18141783 .target_sym = sym_index,
1815 .target_off = .rel(sym_off),
1784 .target_off = sym_off,
18161785 });
18171786 try wip_nav.debug_info.appendNTimes(wip_nav.dwarf.gpa, 0, @intFromEnum(wip_nav.dwarf.address_size));
18181787 }
......@@ -1829,14 +1798,6 @@ pub const WipNav = struct {
18291798 fn endian(ctx: @This()) std.builtin.Endian {
18301799 return ctx.wip_nav.dwarf.endian;
18311800 }
1832 fn gotSym(ctx: @This(), sym_index: u32) UpdateError!void {
1833 try ctx.wip_nav.frameExternalReloc(.{
1834 .source_off = @intCast(ctx.wip_nav.debug_frame.items.len),
1835 .target_sym = sym_index,
1836 .target_off = .got,
1837 });
1838 try ctx.wip_nav.debug_frame.appendNTimes(ctx.wip_nav.dwarf.gpa, 0, 4);
1839 }
18401801 fn addrSym(ctx: @This(), sym_index: u32) UpdateError!void {
18411802 try ctx.wip_nav.frameAddrSym(sym_index, 0);
18421803 }
......@@ -1852,7 +1813,7 @@ pub const WipNav = struct {
18521813 try wip_nav.frameExternalReloc(.{
18531814 .source_off = @intCast(wip_nav.debug_frame.items.len),
18541815 .target_sym = sym_index,
1855 .target_off = .rel(sym_off),
1816 .target_off = sym_off,
18561817 });
18571818 try wip_nav.debug_frame.appendNTimes(wip_nav.dwarf.gpa, 0, @intFromEnum(wip_nav.dwarf.address_size));
18581819 }
......@@ -2338,81 +2299,50 @@ fn getUnit(dwarf: *Dwarf, mod: *Module) !Unit.Index {
23382299 const mod_gop = try dwarf.mods.getOrPut(dwarf.gpa, mod);
23392300 const unit: Unit.Index = @enumFromInt(mod_gop.index);
23402301 if (!mod_gop.found_existing) {
2341 {
2342 errdefer _ = dwarf.mods.pop();
2343 mod_gop.value_ptr.* = .{
2344 .root_dir_path = undefined,
2345 .dirs = .empty,
2346 .files = .empty,
2347 };
2348 errdefer mod_gop.value_ptr.dirs.deinit(dwarf.gpa);
2349 try mod_gop.value_ptr.dirs.putNoClobber(dwarf.gpa, unit, {});
2350 assert(try dwarf.debug_aranges.section.addUnit(
2351 DebugAranges.headerBytes(dwarf),
2352 DebugAranges.trailerBytes(dwarf),
2353 dwarf,
2354 ) == unit);
2355 errdefer dwarf.debug_aranges.section.popUnit(dwarf.gpa);
2356 assert(try dwarf.debug_frame.section.addUnit(
2357 DebugFrame.headerBytes(dwarf),
2358 DebugFrame.trailerBytes(dwarf),
2359 dwarf,
2360 ) == unit);
2361 errdefer dwarf.debug_frame.section.popUnit(dwarf.gpa);
2362 assert(try dwarf.debug_info.section.addUnit(
2363 DebugInfo.headerBytes(dwarf),
2364 DebugInfo.trailer_bytes,
2365 dwarf,
2366 ) == unit);
2367 errdefer dwarf.debug_info.section.popUnit(dwarf.gpa);
2368 assert(try dwarf.debug_line.section.addUnit(
2369 DebugLine.headerBytes(dwarf, 5, 25),
2370 DebugLine.trailer_bytes,
2371 dwarf,
2372 ) == unit);
2373 errdefer dwarf.debug_line.section.popUnit(dwarf.gpa);
2374 assert(try dwarf.debug_loclists.section.addUnit(
2375 DebugLocLists.headerBytes(dwarf),
2376 DebugLocLists.trailer_bytes,
2377 dwarf,
2378 ) == unit);
2379 errdefer dwarf.debug_loclists.section.popUnit(dwarf.gpa);
2380 assert(try dwarf.debug_rnglists.section.addUnit(
2381 DebugRngLists.headerBytes(dwarf),
2382 DebugRngLists.trailer_bytes,
2383 dwarf,
2384 ) == unit);
2385 errdefer dwarf.debug_rnglists.section.popUnit(dwarf.gpa);
2386 }
2387 //if (dwarf.bin_file.cast(.elf)) |elf_file| {
2388 // if (unit == .main) assert(try dwarf.addCommonEntry(unit) == .got_proc);
2389 // if (mod.pic and dwarf.debug_info.section.getUnit(.main).getEntry(.got_proc).len == 0) {
2390 // var wip_nav: WipNav = .{
2391 // .dwarf = dwarf,
2392 // .pt = undefined,
2393 // .unit = .main,
2394 // .entry = .got_proc,
2395 // .any_children = false,
2396 // .func = .none,
2397 // .func_sym_index = undefined,
2398 // .func_high_pc = undefined,
2399 // .blocks = undefined,
2400 // .cfi = undefined,
2401 // .debug_frame = .empty,
2402 // .debug_info = .empty,
2403 // .debug_line = .empty,
2404 // .debug_loclists = .empty,
2405 // .pending_lazy = .empty,
2406 // };
2407 // defer wip_nav.deinit();
2408 // try wip_nav.abbrevCode(.proc);
2409 // try wip_nav.infoExprLoc(.{ .deref = &.{ .plus = .{
2410 // &.empty,
2411 // &.{ .addr_reloc = try elf_file.zigObjectPtr().?.getGlobalSymbol(elf_file, "_GLOBAL_OFFSET_TABLE_", null) },
2412 // } } });
2413 // try dwarf.debug_info.section.replaceEntry(wip_nav.unit, wip_nav.entry, dwarf, wip_nav.debug_info.items);
2414 // }
2415 //}
2302 errdefer _ = dwarf.mods.pop();
2303 mod_gop.value_ptr.* = .{
2304 .root_dir_path = undefined,
2305 .dirs = .empty,
2306 .files = .empty,
2307 };
2308 errdefer mod_gop.value_ptr.dirs.deinit(dwarf.gpa);
2309 try mod_gop.value_ptr.dirs.putNoClobber(dwarf.gpa, unit, {});
2310 assert(try dwarf.debug_aranges.section.addUnit(
2311 DebugAranges.headerBytes(dwarf),
2312 DebugAranges.trailerBytes(dwarf),
2313 dwarf,
2314 ) == unit);
2315 errdefer dwarf.debug_aranges.section.popUnit(dwarf.gpa);
2316 assert(try dwarf.debug_frame.section.addUnit(
2317 DebugFrame.headerBytes(dwarf),
2318 DebugFrame.trailerBytes(dwarf),
2319 dwarf,
2320 ) == unit);
2321 errdefer dwarf.debug_frame.section.popUnit(dwarf.gpa);
2322 assert(try dwarf.debug_info.section.addUnit(
2323 DebugInfo.headerBytes(dwarf),
2324 DebugInfo.trailer_bytes,
2325 dwarf,
2326 ) == unit);
2327 errdefer dwarf.debug_info.section.popUnit(dwarf.gpa);
2328 assert(try dwarf.debug_line.section.addUnit(
2329 DebugLine.headerBytes(dwarf, 5, 25),
2330 DebugLine.trailer_bytes,
2331 dwarf,
2332 ) == unit);
2333 errdefer dwarf.debug_line.section.popUnit(dwarf.gpa);
2334 assert(try dwarf.debug_loclists.section.addUnit(
2335 DebugLocLists.headerBytes(dwarf),
2336 DebugLocLists.trailer_bytes,
2337 dwarf,
2338 ) == unit);
2339 errdefer dwarf.debug_loclists.section.popUnit(dwarf.gpa);
2340 assert(try dwarf.debug_rnglists.section.addUnit(
2341 DebugRngLists.headerBytes(dwarf),
2342 DebugRngLists.trailer_bytes,
2343 dwarf,
2344 ) == unit);
2345 errdefer dwarf.debug_rnglists.section.popUnit(dwarf.gpa);
24162346 }
24172347 return unit;
24182348}
......@@ -2510,16 +2440,7 @@ fn initWipNavInner(
25102440 try wip_nav.strp(nav.fqn.toSlice(ip));
25112441 const ty: Type = nav_val.typeOf(zcu);
25122442 const addr: Loc = .{ .addr_reloc = sym_index };
2513 const loc: Loc = loc: {
2514 if (dwarf.bin_file.cast(.elf)) |elf_file| if (decl.linkage == .@"extern" and mod.pic)
2515 // TODO: lldb doesn't support call :(
2516 //.{ .call = .{ .args = &.{.{ .got_reloc = sym_index }}, .unit = .main, .entry = .got_proc } }
2517 break :loc .{ .deref = &.{ .plus = .{
2518 &.{ .addr_reloc = try elf_file.zigObjectPtr().?.getGlobalSymbol(elf_file, "_GLOBAL_OFFSET_TABLE_", null) },
2519 &.{ .got_reloc = sym_index },
2520 } } };
2521 break :loc if (decl.is_threadlocal) .{ .form_tls_address = &addr } else addr;
2522 };
2443 const loc: Loc = if (decl.is_threadlocal) .{ .form_tls_address = &addr } else addr;
25232444 switch (decl.kind) {
25242445 .unnamed_test, .@"test", .decltest, .@"comptime", .@"usingnamespace" => unreachable,
25252446 .@"const" => {
......@@ -2605,7 +2526,7 @@ fn initWipNavInner(
26052526 try wip_nav.infoAddrSym(sym_index, 0);
26062527 wip_nav.func_high_pc = @intCast(wip_nav.debug_info.items.len);
26072528 try diw.writeInt(u32, 0, dwarf.endian);
2608 const target = file.mod.?.resolved_target.result;
2529 const target = mod.resolved_target.result;
26092530 try uleb128(diw, switch (nav.status.fully_resolved.alignment) {
26102531 .none => target_info.defaultFunctionAlignment(target),
26112532 else => |a| a.maxStrict(target_info.minFunctionAlignment(target)),
......@@ -2742,7 +2663,7 @@ pub fn finishWipNavFunc(
27422663 .{
27432664 .source_off = 1 + @intFromEnum(dwarf.address_size),
27442665 .target_sym = wip_nav.func_sym_index,
2745 .target_off = .rel(code_size),
2666 .target_off = code_size,
27462667 },
27472668 });
27482669 try dwarf.debug_rnglists.section.replaceEntry(
......@@ -4981,7 +4902,6 @@ const AbbrevCode = enum {
49814902 comptime_value_field_comptime_state,
49824903 comptime_value_elem_runtime_bits,
49834904 comptime_value_elem_comptime_state,
4984 //proc,
49854905
49864906 const decl_bytes = uleb128Bytes(@intFromEnum(AbbrevCode.decl_instance_func_generic));
49874907 comptime {
......@@ -5851,12 +5771,6 @@ const AbbrevCode = enum {
58515771 .{ .ZIG_comptime_value, .ref_addr },
58525772 },
58535773 },
5854 //.proc = .{
5855 // .tag = .dwarf_procedure,
5856 // .attrs = &.{
5857 // .{ .location, .exprloc },
5858 // },
5859 //},
58605774 .null = undefined,
58615775 });
58625776};
src/link/Elf.zig+25-17
......@@ -959,6 +959,12 @@ fn flushModuleInner(self: *Elf, arena: Allocator, tid: Zcu.PerThread.Id) !void {
959959 self.rela_plt.clearRetainingCapacity();
960960
961961 if (self.zigObjectPtr()) |zo| {
962 var undefs: std.AutoArrayHashMap(SymbolResolver.Index, std.ArrayList(Ref)) = .init(gpa);
963 defer {
964 for (undefs.values()) |*refs| refs.deinit();
965 undefs.deinit();
966 }
967
962968 var has_reloc_errors = false;
963969 for (zo.atoms_indexes.items) |atom_index| {
964970 const atom_ptr = zo.atom(atom_index) orelse continue;
......@@ -969,7 +975,10 @@ fn flushModuleInner(self: *Elf, arena: Allocator, tid: Zcu.PerThread.Id) !void {
969975 const code = try zo.codeAlloc(self, atom_index);
970976 defer gpa.free(code);
971977 const file_offset = atom_ptr.offset(self);
972 atom_ptr.resolveRelocsAlloc(self, code) catch |err| switch (err) {
978 (if (shdr.sh_flags & elf.SHF_ALLOC == 0)
979 atom_ptr.resolveRelocsNonAlloc(self, code, &undefs)
980 else
981 atom_ptr.resolveRelocsAlloc(self, code)) catch |err| switch (err) {
973982 error.RelocFailure, error.RelaxFailure => has_reloc_errors = true,
974983 error.UnsupportedCpuArch => {
975984 try self.reportUnsupportedCpuArch();
......@@ -980,6 +989,8 @@ fn flushModuleInner(self: *Elf, arena: Allocator, tid: Zcu.PerThread.Id) !void {
980989 try self.pwriteAll(code, file_offset);
981990 }
982991
992 try self.reportUndefinedSymbols(&undefs);
993
983994 if (has_reloc_errors) return error.LinkFailure;
984995 }
985996
......@@ -1392,11 +1403,9 @@ fn scanRelocs(self: *Elf) !void {
13921403 const gpa = self.base.comp.gpa;
13931404 const shared_objects = self.shared_objects.values();
13941405
1395 var undefs = std.AutoArrayHashMap(SymbolResolver.Index, std.ArrayList(Ref)).init(gpa);
1406 var undefs: std.AutoArrayHashMap(SymbolResolver.Index, std.ArrayList(Ref)) = .init(gpa);
13961407 defer {
1397 for (undefs.values()) |*refs| {
1398 refs.deinit();
1399 }
1408 for (undefs.values()) |*refs| refs.deinit();
14001409 undefs.deinit();
14011410 }
14021411
......@@ -2702,15 +2711,16 @@ fn initSyntheticSections(self: *Elf) !void {
27022711 });
27032712 }
27042713
2705 const needs_interp = blk: {
2706 // On Ubuntu with musl-gcc, we get a weird combo of options looking like this:
2707 // -dynamic-linker=<path> -static
2708 // In this case, if we do generate .interp section and segment, we will get
2709 // a segfault in the dynamic linker trying to load a binary that is static
2710 // and doesn't contain .dynamic section.
2711 if (self.base.isStatic() and !comp.config.pie) break :blk false;
2712 break :blk target.dynamic_linker.get() != null;
2714 const is_exe_or_dyn_lib = switch (comp.config.output_mode) {
2715 .Exe => true,
2716 .Lib => comp.config.link_mode == .dynamic,
2717 .Obj => false,
27132718 };
2719 const have_dynamic_linker = comp.config.link_mode == .dynamic and is_exe_or_dyn_lib and !target.dynamic_linker.eql(.none);
2720
2721 const needs_interp = have_dynamic_linker and
2722 (comp.config.link_libc or comp.root_mod.resolved_target.is_explicit_dynamic_linker);
2723
27142724 if (needs_interp and self.section_indexes.interp == null) {
27152725 self.section_indexes.interp = try self.addSection(.{
27162726 .name = try self.insertShString(".interp"),
......@@ -3707,11 +3717,9 @@ fn allocateSpecialPhdrs(self: *Elf) void {
37073717fn writeAtoms(self: *Elf) !void {
37083718 const gpa = self.base.comp.gpa;
37093719
3710 var undefs = std.AutoArrayHashMap(SymbolResolver.Index, std.ArrayList(Ref)).init(gpa);
3720 var undefs: std.AutoArrayHashMap(SymbolResolver.Index, std.ArrayList(Ref)) = .init(gpa);
37113721 defer {
3712 for (undefs.values()) |*refs| {
3713 refs.deinit();
3714 }
3722 for (undefs.values()) |*refs| refs.deinit();
37153723 undefs.deinit();
37163724 }
37173725
src/link/Elf/Atom.zig+3-3
......@@ -497,14 +497,14 @@ fn dynAbsRelocAction(symbol: *const Symbol, elf_file: *Elf) RelocAction {
497497}
498498
499499fn outputType(elf_file: *Elf) u2 {
500 const comp = elf_file.base.comp;
501500 assert(!elf_file.base.isRelocatable());
502 return switch (elf_file.base.comp.config.output_mode) {
501 const config = &elf_file.base.comp.config;
502 return switch (config.output_mode) {
503503 .Obj => unreachable,
504504 .Lib => 0,
505505 .Exe => switch (elf_file.getTarget().os.tag) {
506506 .haiku => 0,
507 else => if (comp.config.pie) 1 else 2,
507 else => if (config.pie) 1 else 2,
508508 },
509509 };
510510}
src/link/Elf/ZigObject.zig+5-7
......@@ -463,11 +463,8 @@ pub fn flush(self: *ZigObject, elf_file: *Elf, tid: Zcu.PerThread.Id) !void {
463463 for (entry.external_relocs.items) |reloc| {
464464 const target_sym = self.symbol(reloc.target_sym);
465465 const r_offset = entry_off + reloc.source_off;
466 const r_addend: i64 = switch (reloc.target_off) {
467 .none, .got => 0,
468 else => |off| @intCast(@intFromEnum(off)),
469 };
470 const r_type = relocation.dwarf.externalRelocType(target_sym.*, reloc.target_off == .got, sect_index, dwarf.address_size, cpu_arch);
466 const r_addend: i64 = @intCast(reloc.target_off);
467 const r_type = relocation.dwarf.externalRelocType(target_sym.*, sect_index, dwarf.address_size, cpu_arch);
471468 atom_ptr.addRelocAssumeCapacity(.{
472469 .r_offset = r_offset,
473470 .r_addend = r_addend,
......@@ -660,6 +657,7 @@ pub fn scanRelocs(self: *ZigObject, elf_file: *Elf, undefs: anytype) !void {
660657 const atom_ptr = self.atom(atom_index) orelse continue;
661658 if (!atom_ptr.alive) continue;
662659 const shdr = atom_ptr.inputShdr(elf_file);
660 if (shdr.sh_flags & elf.SHF_ALLOC == 0) continue;
663661 if (shdr.sh_type == elf.SHT_NOBITS) continue;
664662 if (atom_ptr.scanRelocsRequiresCode(elf_file)) {
665663 // TODO ideally we don't have to fetch the code here.
......@@ -950,7 +948,7 @@ pub fn getNavVAddr(
950948 .dwarf => |wip_nav| try wip_nav.infoExternalReloc(.{
951949 .source_off = @intCast(reloc_info.offset),
952950 .target_sym = this_sym_index,
953 .target_off = .rel(reloc_info.addend),
951 .target_off = reloc_info.addend,
954952 }),
955953 .plan9 => unreachable,
956954 .none => unreachable,
......@@ -983,7 +981,7 @@ pub fn getUavVAddr(
983981 .dwarf => |wip_nav| try wip_nav.infoExternalReloc(.{
984982 .source_off = @intCast(reloc_info.offset),
985983 .target_sym = sym_index,
986 .target_off = .rel(reloc_info.addend),
984 .target_off = reloc_info.addend,
987985 }),
988986 .plan9 => unreachable,
989987 .none => unreachable,
src/link/Elf/relocation.zig+1-2
......@@ -108,13 +108,12 @@ pub const dwarf = struct {
108108
109109 pub fn externalRelocType(
110110 target: Symbol,
111 is_got: bool,
112111 source_section: Dwarf.Section.Index,
113112 address_size: Dwarf.AddressSize,
114113 cpu_arch: std.Target.Cpu.Arch,
115114 ) u32 {
116115 return switch (cpu_arch) {
117 .x86_64 => @intFromEnum(@as(elf.R_X86_64, if (is_got) .GOT32 else switch (source_section) {
116 .x86_64 => @intFromEnum(@as(elf.R_X86_64, switch (source_section) {
118117 else => switch (address_size) {
119118 .@"32" => if (target.flags.is_tls) .DTPOFF32 else .@"32",
120119 .@"64" => if (target.flags.is_tls) .DTPOFF64 else .@"64",
src/link/MachO/ZigObject.zig+2-2
......@@ -648,7 +648,7 @@ pub fn getNavVAddr(
648648 .dwarf => |wip_nav| try wip_nav.infoExternalReloc(.{
649649 .source_off = @intCast(reloc_info.offset),
650650 .target_sym = sym_index,
651 .target_off = .rel(reloc_info.addend),
651 .target_off = reloc_info.addend,
652652 }),
653653 .plan9 => unreachable,
654654 .none => unreachable,
......@@ -688,7 +688,7 @@ pub fn getUavVAddr(
688688 .dwarf => |wip_nav| try wip_nav.infoExternalReloc(.{
689689 .source_off = @intCast(reloc_info.offset),
690690 .target_sym = sym_index,
691 .target_off = .rel(reloc_info.addend),
691 .target_off = reloc_info.addend,
692692 }),
693693 .plan9 => unreachable,
694694 .none => unreachable,
src/link/Wasm.zig+1-1
......@@ -2376,7 +2376,7 @@ pub const FunctionImportId = enum(u32) {
23762376 const zcu = wasm.base.comp.zcu.?;
23772377 const ip = &zcu.intern_pool;
23782378 const ext = ip.getNav(i.ptr(wasm).*).getResolvedExtern(ip).?;
2379 return !ext.is_weak_linkage and ext.lib_name != .none;
2379 return ext.linkage != .weak and ext.lib_name != .none;
23802380 },
23812381 };
23822382 }
src/print_air.zig deleted-1038
......@@ -1,1038 +0,0 @@
1const std = @import("std");
2const Allocator = std.mem.Allocator;
3const fmtIntSizeBin = std.fmt.fmtIntSizeBin;
4
5const Zcu = @import("Zcu.zig");
6const Value = @import("Value.zig");
7const Type = @import("Type.zig");
8const Air = @import("Air.zig");
9const InternPool = @import("InternPool.zig");
10
11pub fn write(stream: anytype, pt: Zcu.PerThread, air: Air, liveness: ?Air.Liveness) void {
12 const instruction_bytes = air.instructions.len *
13 // Here we don't use @sizeOf(Air.Inst.Data) because it would include
14 // the debug safety tag but we want to measure release size.
15 (@sizeOf(Air.Inst.Tag) + 8);
16 const extra_bytes = air.extra.items.len * @sizeOf(u32);
17 const tomb_bytes = if (liveness) |l| l.tomb_bits.len * @sizeOf(usize) else 0;
18 const liveness_extra_bytes = if (liveness) |l| l.extra.len * @sizeOf(u32) else 0;
19 const liveness_special_bytes = if (liveness) |l| l.special.count() * 8 else 0;
20 const total_bytes = @sizeOf(Air) + instruction_bytes + extra_bytes +
21 @sizeOf(Air.Liveness) + liveness_extra_bytes +
22 liveness_special_bytes + tomb_bytes;
23
24 // zig fmt: off
25 stream.print(
26 \\# Total AIR+Liveness bytes: {}
27 \\# AIR Instructions: {d} ({})
28 \\# AIR Extra Data: {d} ({})
29 \\# Liveness tomb_bits: {}
30 \\# Liveness Extra Data: {d} ({})
31 \\# Liveness special table: {d} ({})
32 \\
33 , .{
34 fmtIntSizeBin(total_bytes),
35 air.instructions.len, fmtIntSizeBin(instruction_bytes),
36 air.extra.items.len, fmtIntSizeBin(extra_bytes),
37 fmtIntSizeBin(tomb_bytes),
38 if (liveness) |l| l.extra.len else 0, fmtIntSizeBin(liveness_extra_bytes),
39 if (liveness) |l| l.special.count() else 0, fmtIntSizeBin(liveness_special_bytes),
40 }) catch return;
41 // zig fmt: on
42
43 var writer: Writer = .{
44 .pt = pt,
45 .gpa = pt.zcu.gpa,
46 .air = air,
47 .liveness = liveness,
48 .indent = 2,
49 .skip_body = false,
50 };
51 writer.writeBody(stream, air.getMainBody()) catch return;
52}
53
54pub fn writeInst(
55 stream: anytype,
56 inst: Air.Inst.Index,
57 pt: Zcu.PerThread,
58 air: Air,
59 liveness: ?Air.Liveness,
60) void {
61 var writer: Writer = .{
62 .pt = pt,
63 .gpa = pt.zcu.gpa,
64 .air = air,
65 .liveness = liveness,
66 .indent = 2,
67 .skip_body = true,
68 };
69 writer.writeInst(stream, inst) catch return;
70}
71
72pub fn dump(pt: Zcu.PerThread, air: Air, liveness: ?Air.Liveness) void {
73 write(std.io.getStdErr().writer(), pt, air, liveness);
74}
75
76pub fn dumpInst(inst: Air.Inst.Index, pt: Zcu.PerThread, air: Air, liveness: ?Air.Liveness) void {
77 writeInst(std.io.getStdErr().writer(), inst, pt, air, liveness);
78}
79
80const Writer = struct {
81 pt: Zcu.PerThread,
82 gpa: Allocator,
83 air: Air,
84 liveness: ?Air.Liveness,
85 indent: usize,
86 skip_body: bool,
87
88 fn writeBody(w: *Writer, s: anytype, body: []const Air.Inst.Index) @TypeOf(s).Error!void {
89 for (body) |inst| {
90 try w.writeInst(s, inst);
91 try s.writeByte('\n');
92 }
93 }
94
95 fn writeInst(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {
96 const tag = w.air.instructions.items(.tag)[@intFromEnum(inst)];
97 try s.writeByteNTimes(' ', w.indent);
98 try s.print("{}{c}= {s}(", .{
99 inst,
100 @as(u8, if (if (w.liveness) |liveness| liveness.isUnused(inst) else false) '!' else ' '),
101 @tagName(tag),
102 });
103 switch (tag) {
104 .add,
105 .add_optimized,
106 .add_safe,
107 .add_wrap,
108 .add_sat,
109 .sub,
110 .sub_optimized,
111 .sub_safe,
112 .sub_wrap,
113 .sub_sat,
114 .mul,
115 .mul_optimized,
116 .mul_safe,
117 .mul_wrap,
118 .mul_sat,
119 .div_float,
120 .div_trunc,
121 .div_floor,
122 .div_exact,
123 .rem,
124 .mod,
125 .bit_and,
126 .bit_or,
127 .xor,
128 .cmp_lt,
129 .cmp_lte,
130 .cmp_eq,
131 .cmp_gte,
132 .cmp_gt,
133 .cmp_neq,
134 .bool_and,
135 .bool_or,
136 .store,
137 .store_safe,
138 .array_elem_val,
139 .slice_elem_val,
140 .ptr_elem_val,
141 .shl,
142 .shl_exact,
143 .shl_sat,
144 .shr,
145 .shr_exact,
146 .set_union_tag,
147 .min,
148 .max,
149 .div_float_optimized,
150 .div_trunc_optimized,
151 .div_floor_optimized,
152 .div_exact_optimized,
153 .rem_optimized,
154 .mod_optimized,
155 .cmp_lt_optimized,
156 .cmp_lte_optimized,
157 .cmp_eq_optimized,
158 .cmp_gte_optimized,
159 .cmp_gt_optimized,
160 .cmp_neq_optimized,
161 .memcpy,
162 .memmove,
163 .memset,
164 .memset_safe,
165 => try w.writeBinOp(s, inst),
166
167 .is_null,
168 .is_non_null,
169 .is_null_ptr,
170 .is_non_null_ptr,
171 .is_err,
172 .is_non_err,
173 .is_err_ptr,
174 .is_non_err_ptr,
175 .ret,
176 .ret_safe,
177 .ret_load,
178 .is_named_enum_value,
179 .tag_name,
180 .error_name,
181 .sqrt,
182 .sin,
183 .cos,
184 .tan,
185 .exp,
186 .exp2,
187 .log,
188 .log2,
189 .log10,
190 .floor,
191 .ceil,
192 .round,
193 .trunc_float,
194 .neg,
195 .neg_optimized,
196 .cmp_lt_errors_len,
197 .set_err_return_trace,
198 .c_va_end,
199 => try w.writeUnOp(s, inst),
200
201 .trap,
202 .breakpoint,
203 .dbg_empty_stmt,
204 .unreach,
205 .ret_addr,
206 .frame_addr,
207 .save_err_return_trace_index,
208 => try w.writeNoOp(s, inst),
209
210 .alloc,
211 .ret_ptr,
212 .err_return_trace,
213 .c_va_start,
214 => try w.writeTy(s, inst),
215
216 .arg => try w.writeArg(s, inst),
217
218 .not,
219 .bitcast,
220 .load,
221 .fptrunc,
222 .fpext,
223 .intcast,
224 .intcast_safe,
225 .trunc,
226 .optional_payload,
227 .optional_payload_ptr,
228 .optional_payload_ptr_set,
229 .errunion_payload_ptr_set,
230 .wrap_optional,
231 .unwrap_errunion_payload,
232 .unwrap_errunion_err,
233 .unwrap_errunion_payload_ptr,
234 .unwrap_errunion_err_ptr,
235 .wrap_errunion_payload,
236 .wrap_errunion_err,
237 .slice_ptr,
238 .slice_len,
239 .ptr_slice_len_ptr,
240 .ptr_slice_ptr_ptr,
241 .struct_field_ptr_index_0,
242 .struct_field_ptr_index_1,
243 .struct_field_ptr_index_2,
244 .struct_field_ptr_index_3,
245 .array_to_slice,
246 .float_from_int,
247 .splat,
248 .int_from_float,
249 .int_from_float_optimized,
250 .get_union_tag,
251 .clz,
252 .ctz,
253 .popcount,
254 .byte_swap,
255 .bit_reverse,
256 .abs,
257 .error_set_has_value,
258 .addrspace_cast,
259 .c_va_arg,
260 .c_va_copy,
261 => try w.writeTyOp(s, inst),
262
263 .block, .dbg_inline_block => try w.writeBlock(s, tag, inst),
264
265 .loop => try w.writeLoop(s, inst),
266
267 .slice,
268 .slice_elem_ptr,
269 .ptr_elem_ptr,
270 .ptr_add,
271 .ptr_sub,
272 .add_with_overflow,
273 .sub_with_overflow,
274 .mul_with_overflow,
275 .shl_with_overflow,
276 => try w.writeTyPlBin(s, inst),
277
278 .call,
279 .call_always_tail,
280 .call_never_tail,
281 .call_never_inline,
282 => try w.writeCall(s, inst),
283
284 .dbg_var_ptr,
285 .dbg_var_val,
286 .dbg_arg_inline,
287 => try w.writeDbgVar(s, inst),
288
289 .struct_field_ptr => try w.writeStructField(s, inst),
290 .struct_field_val => try w.writeStructField(s, inst),
291 .inferred_alloc => @panic("TODO"),
292 .inferred_alloc_comptime => @panic("TODO"),
293 .assembly => try w.writeAssembly(s, inst),
294 .dbg_stmt => try w.writeDbgStmt(s, inst),
295
296 .aggregate_init => try w.writeAggregateInit(s, inst),
297 .union_init => try w.writeUnionInit(s, inst),
298 .br => try w.writeBr(s, inst),
299 .switch_dispatch => try w.writeBr(s, inst),
300 .repeat => try w.writeRepeat(s, inst),
301 .cond_br => try w.writeCondBr(s, inst),
302 .@"try", .try_cold => try w.writeTry(s, inst),
303 .try_ptr, .try_ptr_cold => try w.writeTryPtr(s, inst),
304 .loop_switch_br, .switch_br => try w.writeSwitchBr(s, inst),
305 .cmpxchg_weak, .cmpxchg_strong => try w.writeCmpxchg(s, inst),
306 .atomic_load => try w.writeAtomicLoad(s, inst),
307 .prefetch => try w.writePrefetch(s, inst),
308 .atomic_store_unordered => try w.writeAtomicStore(s, inst, .unordered),
309 .atomic_store_monotonic => try w.writeAtomicStore(s, inst, .monotonic),
310 .atomic_store_release => try w.writeAtomicStore(s, inst, .release),
311 .atomic_store_seq_cst => try w.writeAtomicStore(s, inst, .seq_cst),
312 .atomic_rmw => try w.writeAtomicRmw(s, inst),
313 .field_parent_ptr => try w.writeFieldParentPtr(s, inst),
314 .wasm_memory_size => try w.writeWasmMemorySize(s, inst),
315 .wasm_memory_grow => try w.writeWasmMemoryGrow(s, inst),
316 .mul_add => try w.writeMulAdd(s, inst),
317 .select => try w.writeSelect(s, inst),
318 .shuffle_one => try w.writeShuffleOne(s, inst),
319 .shuffle_two => try w.writeShuffleTwo(s, inst),
320 .reduce, .reduce_optimized => try w.writeReduce(s, inst),
321 .cmp_vector, .cmp_vector_optimized => try w.writeCmpVector(s, inst),
322 .vector_store_elem => try w.writeVectorStoreElem(s, inst),
323 .tlv_dllimport_ptr => try w.writeTlvDllimportPtr(s, inst),
324
325 .work_item_id,
326 .work_group_size,
327 .work_group_id,
328 => try w.writeWorkDimension(s, inst),
329 }
330 try s.writeByte(')');
331 }
332
333 fn writeBinOp(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {
334 const bin_op = w.air.instructions.items(.data)[@intFromEnum(inst)].bin_op;
335 try w.writeOperand(s, inst, 0, bin_op.lhs);
336 try s.writeAll(", ");
337 try w.writeOperand(s, inst, 1, bin_op.rhs);
338 }
339
340 fn writeUnOp(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {
341 const un_op = w.air.instructions.items(.data)[@intFromEnum(inst)].un_op;
342 try w.writeOperand(s, inst, 0, un_op);
343 }
344
345 fn writeNoOp(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {
346 _ = w;
347 _ = inst;
348 // no-op, no argument to write
349 }
350
351 fn writeType(w: *Writer, s: anytype, ty: Type) !void {
352 return ty.print(s, w.pt);
353 }
354
355 fn writeTy(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {
356 const ty = w.air.instructions.items(.data)[@intFromEnum(inst)].ty;
357 try w.writeType(s, ty);
358 }
359
360 fn writeArg(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {
361 const arg = w.air.instructions.items(.data)[@intFromEnum(inst)].arg;
362 try w.writeType(s, arg.ty.toType());
363 switch (arg.name) {
364 .none => {},
365 _ => try s.print(", \"{}\"", .{std.zig.fmtEscapes(arg.name.toSlice(w.air))}),
366 }
367 }
368
369 fn writeTyOp(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {
370 const ty_op = w.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;
371 try w.writeType(s, ty_op.ty.toType());
372 try s.writeAll(", ");
373 try w.writeOperand(s, inst, 0, ty_op.operand);
374 }
375
376 fn writeBlock(w: *Writer, s: anytype, tag: Air.Inst.Tag, inst: Air.Inst.Index) @TypeOf(s).Error!void {
377 const ty_pl = w.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;
378 try w.writeType(s, ty_pl.ty.toType());
379 const body: []const Air.Inst.Index = @ptrCast(switch (tag) {
380 inline .block, .dbg_inline_block => |comptime_tag| body: {
381 const extra = w.air.extraData(switch (comptime_tag) {
382 .block => Air.Block,
383 .dbg_inline_block => Air.DbgInlineBlock,
384 else => unreachable,
385 }, ty_pl.payload);
386 switch (comptime_tag) {
387 .block => {},
388 .dbg_inline_block => {
389 try s.writeAll(", ");
390 try w.writeInstRef(s, Air.internedToRef(extra.data.func), false);
391 },
392 else => unreachable,
393 }
394 break :body w.air.extra.items[extra.end..][0..extra.data.body_len];
395 },
396 else => unreachable,
397 });
398 if (w.skip_body) return s.writeAll(", ...");
399 const liveness_block: Air.Liveness.BlockSlices = if (w.liveness) |liveness|
400 liveness.getBlock(inst)
401 else
402 .{ .deaths = &.{} };
403
404 try s.writeAll(", {\n");
405 const old_indent = w.indent;
406 w.indent += 2;
407 try w.writeBody(s, body);
408 w.indent = old_indent;
409 try s.writeByteNTimes(' ', w.indent);
410 try s.writeAll("}");
411
412 for (liveness_block.deaths) |operand| {
413 try s.print(" {}!", .{operand});
414 }
415 }
416
417 fn writeLoop(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {
418 const ty_pl = w.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;
419 const extra = w.air.extraData(Air.Block, ty_pl.payload);
420 const body: []const Air.Inst.Index = @ptrCast(w.air.extra.items[extra.end..][0..extra.data.body_len]);
421
422 try w.writeType(s, ty_pl.ty.toType());
423 if (w.skip_body) return s.writeAll(", ...");
424 try s.writeAll(", {\n");
425 const old_indent = w.indent;
426 w.indent += 2;
427 try w.writeBody(s, body);
428 w.indent = old_indent;
429 try s.writeByteNTimes(' ', w.indent);
430 try s.writeAll("}");
431 }
432
433 fn writeAggregateInit(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {
434 const zcu = w.pt.zcu;
435 const ty_pl = w.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;
436 const vector_ty = ty_pl.ty.toType();
437 const len = @as(usize, @intCast(vector_ty.arrayLen(zcu)));
438 const elements = @as([]const Air.Inst.Ref, @ptrCast(w.air.extra.items[ty_pl.payload..][0..len]));
439
440 try w.writeType(s, vector_ty);
441 try s.writeAll(", [");
442 for (elements, 0..) |elem, i| {
443 if (i != 0) try s.writeAll(", ");
444 try w.writeOperand(s, inst, i, elem);
445 }
446 try s.writeAll("]");
447 }
448
449 fn writeUnionInit(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {
450 const ty_pl = w.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;
451 const extra = w.air.extraData(Air.UnionInit, ty_pl.payload).data;
452
453 try s.print("{d}, ", .{extra.field_index});
454 try w.writeOperand(s, inst, 0, extra.init);
455 }
456
457 fn writeStructField(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {
458 const ty_pl = w.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;
459 const extra = w.air.extraData(Air.StructField, ty_pl.payload).data;
460
461 try w.writeOperand(s, inst, 0, extra.struct_operand);
462 try s.print(", {d}", .{extra.field_index});
463 }
464
465 fn writeTyPlBin(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {
466 const data = w.air.instructions.items(.data);
467 const ty_pl = data[@intFromEnum(inst)].ty_pl;
468 const extra = w.air.extraData(Air.Bin, ty_pl.payload).data;
469
470 const inst_ty = data[@intFromEnum(inst)].ty_pl.ty.toType();
471 try w.writeType(s, inst_ty);
472 try s.writeAll(", ");
473 try w.writeOperand(s, inst, 0, extra.lhs);
474 try s.writeAll(", ");
475 try w.writeOperand(s, inst, 1, extra.rhs);
476 }
477
478 fn writeCmpxchg(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {
479 const ty_pl = w.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;
480 const extra = w.air.extraData(Air.Cmpxchg, ty_pl.payload).data;
481
482 try w.writeOperand(s, inst, 0, extra.ptr);
483 try s.writeAll(", ");
484 try w.writeOperand(s, inst, 1, extra.expected_value);
485 try s.writeAll(", ");
486 try w.writeOperand(s, inst, 2, extra.new_value);
487 try s.print(", {s}, {s}", .{
488 @tagName(extra.successOrder()), @tagName(extra.failureOrder()),
489 });
490 }
491
492 fn writeMulAdd(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {
493 const pl_op = w.air.instructions.items(.data)[@intFromEnum(inst)].pl_op;
494 const extra = w.air.extraData(Air.Bin, pl_op.payload).data;
495
496 try w.writeOperand(s, inst, 0, extra.lhs);
497 try s.writeAll(", ");
498 try w.writeOperand(s, inst, 1, extra.rhs);
499 try s.writeAll(", ");
500 try w.writeOperand(s, inst, 2, pl_op.operand);
501 }
502
503 fn writeShuffleOne(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {
504 const unwrapped = w.air.unwrapShuffleOne(w.pt.zcu, inst);
505 try w.writeType(s, unwrapped.result_ty);
506 try s.writeAll(", ");
507 try w.writeOperand(s, inst, 0, unwrapped.operand);
508 try s.writeAll(", [");
509 for (unwrapped.mask, 0..) |mask_elem, mask_idx| {
510 if (mask_idx > 0) try s.writeAll(", ");
511 switch (mask_elem.unwrap()) {
512 .elem => |idx| try s.print("elem {d}", .{idx}),
513 .value => |val| try s.print("val {}", .{Value.fromInterned(val).fmtValue(w.pt)}),
514 }
515 }
516 try s.writeByte(']');
517 }
518
519 fn writeShuffleTwo(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {
520 const unwrapped = w.air.unwrapShuffleTwo(w.pt.zcu, inst);
521 try w.writeType(s, unwrapped.result_ty);
522 try s.writeAll(", ");
523 try w.writeOperand(s, inst, 0, unwrapped.operand_a);
524 try s.writeAll(", ");
525 try w.writeOperand(s, inst, 1, unwrapped.operand_b);
526 try s.writeAll(", [");
527 for (unwrapped.mask, 0..) |mask_elem, mask_idx| {
528 if (mask_idx > 0) try s.writeAll(", ");
529 switch (mask_elem.unwrap()) {
530 .a_elem => |idx| try s.print("a_elem {d}", .{idx}),
531 .b_elem => |idx| try s.print("b_elem {d}", .{idx}),
532 .undef => try s.writeAll("undef"),
533 }
534 }
535 try s.writeByte(']');
536 }
537
538 fn writeSelect(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {
539 const zcu = w.pt.zcu;
540 const pl_op = w.air.instructions.items(.data)[@intFromEnum(inst)].pl_op;
541 const extra = w.air.extraData(Air.Bin, pl_op.payload).data;
542
543 const elem_ty = w.typeOfIndex(inst).childType(zcu);
544 try w.writeType(s, elem_ty);
545 try s.writeAll(", ");
546 try w.writeOperand(s, inst, 0, pl_op.operand);
547 try s.writeAll(", ");
548 try w.writeOperand(s, inst, 1, extra.lhs);
549 try s.writeAll(", ");
550 try w.writeOperand(s, inst, 2, extra.rhs);
551 }
552
553 fn writeReduce(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {
554 const reduce = w.air.instructions.items(.data)[@intFromEnum(inst)].reduce;
555
556 try w.writeOperand(s, inst, 0, reduce.operand);
557 try s.print(", {s}", .{@tagName(reduce.operation)});
558 }
559
560 fn writeCmpVector(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {
561 const ty_pl = w.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;
562 const extra = w.air.extraData(Air.VectorCmp, ty_pl.payload).data;
563
564 try s.print("{s}, ", .{@tagName(extra.compareOperator())});
565 try w.writeOperand(s, inst, 0, extra.lhs);
566 try s.writeAll(", ");
567 try w.writeOperand(s, inst, 1, extra.rhs);
568 }
569
570 fn writeVectorStoreElem(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {
571 const data = w.air.instructions.items(.data)[@intFromEnum(inst)].vector_store_elem;
572 const extra = w.air.extraData(Air.VectorCmp, data.payload).data;
573
574 try w.writeOperand(s, inst, 0, data.vector_ptr);
575 try s.writeAll(", ");
576 try w.writeOperand(s, inst, 1, extra.lhs);
577 try s.writeAll(", ");
578 try w.writeOperand(s, inst, 2, extra.rhs);
579 }
580
581 fn writeTlvDllimportPtr(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {
582 const ip = &w.pt.zcu.intern_pool;
583 const ty_nav = w.air.instructions.items(.data)[@intFromEnum(inst)].ty_nav;
584 try w.writeType(s, .fromInterned(ty_nav.ty));
585 try s.print(", '{}'", .{ip.getNav(ty_nav.nav).fqn.fmt(ip)});
586 }
587
588 fn writeAtomicLoad(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {
589 const atomic_load = w.air.instructions.items(.data)[@intFromEnum(inst)].atomic_load;
590
591 try w.writeOperand(s, inst, 0, atomic_load.ptr);
592 try s.print(", {s}", .{@tagName(atomic_load.order)});
593 }
594
595 fn writePrefetch(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {
596 const prefetch = w.air.instructions.items(.data)[@intFromEnum(inst)].prefetch;
597
598 try w.writeOperand(s, inst, 0, prefetch.ptr);
599 try s.print(", {s}, {d}, {s}", .{
600 @tagName(prefetch.rw), prefetch.locality, @tagName(prefetch.cache),
601 });
602 }
603
604 fn writeAtomicStore(
605 w: *Writer,
606 s: anytype,
607 inst: Air.Inst.Index,
608 order: std.builtin.AtomicOrder,
609 ) @TypeOf(s).Error!void {
610 const bin_op = w.air.instructions.items(.data)[@intFromEnum(inst)].bin_op;
611 try w.writeOperand(s, inst, 0, bin_op.lhs);
612 try s.writeAll(", ");
613 try w.writeOperand(s, inst, 1, bin_op.rhs);
614 try s.print(", {s}", .{@tagName(order)});
615 }
616
617 fn writeAtomicRmw(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {
618 const pl_op = w.air.instructions.items(.data)[@intFromEnum(inst)].pl_op;
619 const extra = w.air.extraData(Air.AtomicRmw, pl_op.payload).data;
620
621 try w.writeOperand(s, inst, 0, pl_op.operand);
622 try s.writeAll(", ");
623 try w.writeOperand(s, inst, 1, extra.operand);
624 try s.print(", {s}, {s}", .{ @tagName(extra.op()), @tagName(extra.ordering()) });
625 }
626
627 fn writeFieldParentPtr(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {
628 const ty_pl = w.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;
629 const extra = w.air.extraData(Air.FieldParentPtr, ty_pl.payload).data;
630
631 try w.writeOperand(s, inst, 0, extra.field_ptr);
632 try s.print(", {d}", .{extra.field_index});
633 }
634
635 fn writeAssembly(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {
636 const ty_pl = w.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;
637 const extra = w.air.extraData(Air.Asm, ty_pl.payload);
638 const is_volatile = @as(u1, @truncate(extra.data.flags >> 31)) != 0;
639 const clobbers_len = @as(u31, @truncate(extra.data.flags));
640 var extra_i: usize = extra.end;
641 var op_index: usize = 0;
642
643 const ret_ty = w.typeOfIndex(inst);
644 try w.writeType(s, ret_ty);
645
646 if (is_volatile) {
647 try s.writeAll(", volatile");
648 }
649
650 const outputs = @as([]const Air.Inst.Ref, @ptrCast(w.air.extra.items[extra_i..][0..extra.data.outputs_len]));
651 extra_i += outputs.len;
652 const inputs = @as([]const Air.Inst.Ref, @ptrCast(w.air.extra.items[extra_i..][0..extra.data.inputs_len]));
653 extra_i += inputs.len;
654
655 for (outputs) |output| {
656 const extra_bytes = std.mem.sliceAsBytes(w.air.extra.items[extra_i..]);
657 const constraint = std.mem.sliceTo(extra_bytes, 0);
658 const name = std.mem.sliceTo(extra_bytes[constraint.len + 1 ..], 0);
659
660 // This equation accounts for the fact that even if we have exactly 4 bytes
661 // for the strings and their null terminators, we still use the next u32
662 // for the null terminator.
663 extra_i += (constraint.len + name.len + (2 + 3)) / 4;
664
665 if (output == .none) {
666 try s.print(", [{s}] -> {s}", .{ name, constraint });
667 } else {
668 try s.print(", [{s}] out {s} = (", .{ name, constraint });
669 try w.writeOperand(s, inst, op_index, output);
670 op_index += 1;
671 try s.writeByte(')');
672 }
673 }
674
675 for (inputs) |input| {
676 const extra_bytes = std.mem.sliceAsBytes(w.air.extra.items[extra_i..]);
677 const constraint = std.mem.sliceTo(extra_bytes, 0);
678 const name = std.mem.sliceTo(extra_bytes[constraint.len + 1 ..], 0);
679 // This equation accounts for the fact that even if we have exactly 4 bytes
680 // for the strings and their null terminators, we still use the next u32
681 // for the null terminator.
682 extra_i += (constraint.len + name.len + 1) / 4 + 1;
683
684 try s.print(", [{s}] in {s} = (", .{ name, constraint });
685 try w.writeOperand(s, inst, op_index, input);
686 op_index += 1;
687 try s.writeByte(')');
688 }
689
690 {
691 var clobber_i: u32 = 0;
692 while (clobber_i < clobbers_len) : (clobber_i += 1) {
693 const extra_bytes = std.mem.sliceAsBytes(w.air.extra.items[extra_i..]);
694 const clobber = std.mem.sliceTo(extra_bytes, 0);
695 // This equation accounts for the fact that even if we have exactly 4 bytes
696 // for the string, we still use the next u32 for the null terminator.
697 extra_i += clobber.len / 4 + 1;
698
699 try s.writeAll(", ~{");
700 try s.writeAll(clobber);
701 try s.writeAll("}");
702 }
703 }
704 const asm_source = std.mem.sliceAsBytes(w.air.extra.items[extra_i..])[0..extra.data.source_len];
705 try s.print(", \"{}\"", .{std.zig.fmtEscapes(asm_source)});
706 }
707
708 fn writeDbgStmt(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {
709 const dbg_stmt = w.air.instructions.items(.data)[@intFromEnum(inst)].dbg_stmt;
710 try s.print("{d}:{d}", .{ dbg_stmt.line + 1, dbg_stmt.column + 1 });
711 }
712
713 fn writeDbgVar(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {
714 const pl_op = w.air.instructions.items(.data)[@intFromEnum(inst)].pl_op;
715 try w.writeOperand(s, inst, 0, pl_op.operand);
716 const name: Air.NullTerminatedString = @enumFromInt(pl_op.payload);
717 try s.print(", \"{}\"", .{std.zig.fmtEscapes(name.toSlice(w.air))});
718 }
719
720 fn writeCall(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {
721 const pl_op = w.air.instructions.items(.data)[@intFromEnum(inst)].pl_op;
722 const extra = w.air.extraData(Air.Call, pl_op.payload);
723 const args = @as([]const Air.Inst.Ref, @ptrCast(w.air.extra.items[extra.end..][0..extra.data.args_len]));
724 try w.writeOperand(s, inst, 0, pl_op.operand);
725 try s.writeAll(", [");
726 for (args, 0..) |arg, i| {
727 if (i != 0) try s.writeAll(", ");
728 try w.writeOperand(s, inst, 1 + i, arg);
729 }
730 try s.writeAll("]");
731 }
732
733 fn writeBr(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {
734 const br = w.air.instructions.items(.data)[@intFromEnum(inst)].br;
735 try w.writeInstIndex(s, br.block_inst, false);
736 try s.writeAll(", ");
737 try w.writeOperand(s, inst, 0, br.operand);
738 }
739
740 fn writeRepeat(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {
741 const repeat = w.air.instructions.items(.data)[@intFromEnum(inst)].repeat;
742 try w.writeInstIndex(s, repeat.loop_inst, false);
743 }
744
745 fn writeTry(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {
746 const pl_op = w.air.instructions.items(.data)[@intFromEnum(inst)].pl_op;
747 const extra = w.air.extraData(Air.Try, pl_op.payload);
748 const body: []const Air.Inst.Index = @ptrCast(w.air.extra.items[extra.end..][0..extra.data.body_len]);
749 const liveness_condbr: Air.Liveness.CondBrSlices = if (w.liveness) |liveness|
750 liveness.getCondBr(inst)
751 else
752 .{ .then_deaths = &.{}, .else_deaths = &.{} };
753
754 try w.writeOperand(s, inst, 0, pl_op.operand);
755 if (w.skip_body) return s.writeAll(", ...");
756 try s.writeAll(", {\n");
757 const old_indent = w.indent;
758 w.indent += 2;
759
760 if (liveness_condbr.else_deaths.len != 0) {
761 try s.writeByteNTimes(' ', w.indent);
762 for (liveness_condbr.else_deaths, 0..) |operand, i| {
763 if (i != 0) try s.writeAll(" ");
764 try s.print("{}!", .{operand});
765 }
766 try s.writeAll("\n");
767 }
768 try w.writeBody(s, body);
769
770 w.indent = old_indent;
771 try s.writeByteNTimes(' ', w.indent);
772 try s.writeAll("}");
773
774 for (liveness_condbr.then_deaths) |operand| {
775 try s.print(" {}!", .{operand});
776 }
777 }
778
779 fn writeTryPtr(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {
780 const ty_pl = w.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;
781 const extra = w.air.extraData(Air.TryPtr, ty_pl.payload);
782 const body: []const Air.Inst.Index = @ptrCast(w.air.extra.items[extra.end..][0..extra.data.body_len]);
783 const liveness_condbr: Air.Liveness.CondBrSlices = if (w.liveness) |liveness|
784 liveness.getCondBr(inst)
785 else
786 .{ .then_deaths = &.{}, .else_deaths = &.{} };
787
788 try w.writeOperand(s, inst, 0, extra.data.ptr);
789
790 try s.writeAll(", ");
791 try w.writeType(s, ty_pl.ty.toType());
792 if (w.skip_body) return s.writeAll(", ...");
793 try s.writeAll(", {\n");
794 const old_indent = w.indent;
795 w.indent += 2;
796
797 if (liveness_condbr.else_deaths.len != 0) {
798 try s.writeByteNTimes(' ', w.indent);
799 for (liveness_condbr.else_deaths, 0..) |operand, i| {
800 if (i != 0) try s.writeAll(" ");
801 try s.print("{}!", .{operand});
802 }
803 try s.writeAll("\n");
804 }
805 try w.writeBody(s, body);
806
807 w.indent = old_indent;
808 try s.writeByteNTimes(' ', w.indent);
809 try s.writeAll("}");
810
811 for (liveness_condbr.then_deaths) |operand| {
812 try s.print(" {}!", .{operand});
813 }
814 }
815
816 fn writeCondBr(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {
817 const pl_op = w.air.instructions.items(.data)[@intFromEnum(inst)].pl_op;
818 const extra = w.air.extraData(Air.CondBr, pl_op.payload);
819 const then_body: []const Air.Inst.Index = @ptrCast(w.air.extra.items[extra.end..][0..extra.data.then_body_len]);
820 const else_body: []const Air.Inst.Index = @ptrCast(w.air.extra.items[extra.end + then_body.len ..][0..extra.data.else_body_len]);
821 const liveness_condbr: Air.Liveness.CondBrSlices = if (w.liveness) |liveness|
822 liveness.getCondBr(inst)
823 else
824 .{ .then_deaths = &.{}, .else_deaths = &.{} };
825
826 try w.writeOperand(s, inst, 0, pl_op.operand);
827 if (w.skip_body) return s.writeAll(", ...");
828 try s.writeAll(",");
829 if (extra.data.branch_hints.true != .none) {
830 try s.print(" {s}", .{@tagName(extra.data.branch_hints.true)});
831 }
832 if (extra.data.branch_hints.then_cov != .none) {
833 try s.print(" {s}", .{@tagName(extra.data.branch_hints.then_cov)});
834 }
835 try s.writeAll(" {\n");
836 const old_indent = w.indent;
837 w.indent += 2;
838
839 if (liveness_condbr.then_deaths.len != 0) {
840 try s.writeByteNTimes(' ', w.indent);
841 for (liveness_condbr.then_deaths, 0..) |operand, i| {
842 if (i != 0) try s.writeAll(" ");
843 try s.print("{}!", .{operand});
844 }
845 try s.writeAll("\n");
846 }
847
848 try w.writeBody(s, then_body);
849 try s.writeByteNTimes(' ', old_indent);
850 try s.writeAll("},");
851 if (extra.data.branch_hints.false != .none) {
852 try s.print(" {s}", .{@tagName(extra.data.branch_hints.false)});
853 }
854 if (extra.data.branch_hints.else_cov != .none) {
855 try s.print(" {s}", .{@tagName(extra.data.branch_hints.else_cov)});
856 }
857 try s.writeAll(" {\n");
858
859 if (liveness_condbr.else_deaths.len != 0) {
860 try s.writeByteNTimes(' ', w.indent);
861 for (liveness_condbr.else_deaths, 0..) |operand, i| {
862 if (i != 0) try s.writeAll(" ");
863 try s.print("{}!", .{operand});
864 }
865 try s.writeAll("\n");
866 }
867
868 try w.writeBody(s, else_body);
869 w.indent = old_indent;
870
871 try s.writeByteNTimes(' ', old_indent);
872 try s.writeAll("}");
873 }
874
875 fn writeSwitchBr(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {
876 const switch_br = w.air.unwrapSwitch(inst);
877
878 const liveness: Air.Liveness.SwitchBrTable = if (w.liveness) |liveness|
879 liveness.getSwitchBr(w.gpa, inst, switch_br.cases_len + 1) catch
880 @panic("out of memory")
881 else blk: {
882 const slice = w.gpa.alloc([]const Air.Inst.Index, switch_br.cases_len + 1) catch
883 @panic("out of memory");
884 @memset(slice, &.{});
885 break :blk .{ .deaths = slice };
886 };
887 defer w.gpa.free(liveness.deaths);
888
889 try w.writeOperand(s, inst, 0, switch_br.operand);
890 if (w.skip_body) return s.writeAll(", ...");
891 const old_indent = w.indent;
892 w.indent += 2;
893
894 var it = switch_br.iterateCases();
895 while (it.next()) |case| {
896 try s.writeAll(", [");
897 for (case.items, 0..) |item, item_i| {
898 if (item_i != 0) try s.writeAll(", ");
899 try w.writeInstRef(s, item, false);
900 }
901 for (case.ranges, 0..) |range, range_i| {
902 if (range_i != 0 or case.items.len != 0) try s.writeAll(", ");
903 try w.writeInstRef(s, range[0], false);
904 try s.writeAll("...");
905 try w.writeInstRef(s, range[1], false);
906 }
907 try s.writeAll("] ");
908 const hint = switch_br.getHint(case.idx);
909 if (hint != .none) {
910 try s.print(".{s} ", .{@tagName(hint)});
911 }
912 try s.writeAll("=> {\n");
913 w.indent += 2;
914
915 const deaths = liveness.deaths[case.idx];
916 if (deaths.len != 0) {
917 try s.writeByteNTimes(' ', w.indent);
918 for (deaths, 0..) |operand, i| {
919 if (i != 0) try s.writeAll(" ");
920 try s.print("{}!", .{operand});
921 }
922 try s.writeAll("\n");
923 }
924
925 try w.writeBody(s, case.body);
926 w.indent -= 2;
927 try s.writeByteNTimes(' ', w.indent);
928 try s.writeAll("}");
929 }
930
931 const else_body = it.elseBody();
932 if (else_body.len != 0) {
933 try s.writeAll(", else ");
934 const hint = switch_br.getElseHint();
935 if (hint != .none) {
936 try s.print(".{s} ", .{@tagName(hint)});
937 }
938 try s.writeAll("=> {\n");
939 w.indent += 2;
940
941 const deaths = liveness.deaths[liveness.deaths.len - 1];
942 if (deaths.len != 0) {
943 try s.writeByteNTimes(' ', w.indent);
944 for (deaths, 0..) |operand, i| {
945 if (i != 0) try s.writeAll(" ");
946 try s.print("{}!", .{operand});
947 }
948 try s.writeAll("\n");
949 }
950
951 try w.writeBody(s, else_body);
952 w.indent -= 2;
953 try s.writeByteNTimes(' ', w.indent);
954 try s.writeAll("}");
955 }
956
957 try s.writeAll("\n");
958 try s.writeByteNTimes(' ', old_indent);
959 }
960
961 fn writeWasmMemorySize(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {
962 const pl_op = w.air.instructions.items(.data)[@intFromEnum(inst)].pl_op;
963 try s.print("{d}", .{pl_op.payload});
964 }
965
966 fn writeWasmMemoryGrow(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {
967 const pl_op = w.air.instructions.items(.data)[@intFromEnum(inst)].pl_op;
968 try s.print("{d}, ", .{pl_op.payload});
969 try w.writeOperand(s, inst, 0, pl_op.operand);
970 }
971
972 fn writeWorkDimension(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {
973 const pl_op = w.air.instructions.items(.data)[@intFromEnum(inst)].pl_op;
974 try s.print("{d}", .{pl_op.payload});
975 }
976
977 fn writeOperand(
978 w: *Writer,
979 s: anytype,
980 inst: Air.Inst.Index,
981 op_index: usize,
982 operand: Air.Inst.Ref,
983 ) @TypeOf(s).Error!void {
984 const small_tomb_bits = Air.Liveness.bpi - 1;
985 const dies = if (w.liveness) |liveness| blk: {
986 if (op_index < small_tomb_bits)
987 break :blk liveness.operandDies(inst, @intCast(op_index));
988 var extra_index = liveness.special.get(inst).?;
989 var tomb_op_index: usize = small_tomb_bits;
990 while (true) {
991 const bits = liveness.extra[extra_index];
992 if (op_index < tomb_op_index + 31) {
993 break :blk @as(u1, @truncate(bits >> @as(u5, @intCast(op_index - tomb_op_index)))) != 0;
994 }
995 if ((bits >> 31) != 0) break :blk false;
996 extra_index += 1;
997 tomb_op_index += 31;
998 }
999 } else false;
1000 return w.writeInstRef(s, operand, dies);
1001 }
1002
1003 fn writeInstRef(
1004 w: *Writer,
1005 s: anytype,
1006 operand: Air.Inst.Ref,
1007 dies: bool,
1008 ) @TypeOf(s).Error!void {
1009 if (@intFromEnum(operand) < InternPool.static_len) {
1010 return s.print("@{}", .{operand});
1011 } else if (operand.toInterned()) |ip_index| {
1012 const pt = w.pt;
1013 const ty = Type.fromInterned(pt.zcu.intern_pool.indexToKey(ip_index).typeOf());
1014 try s.print("<{}, {}>", .{
1015 ty.fmt(pt),
1016 Value.fromInterned(ip_index).fmtValue(pt),
1017 });
1018 } else {
1019 return w.writeInstIndex(s, operand.toIndex().?, dies);
1020 }
1021 }
1022
1023 fn writeInstIndex(
1024 w: *Writer,
1025 s: anytype,
1026 inst: Air.Inst.Index,
1027 dies: bool,
1028 ) @TypeOf(s).Error!void {
1029 _ = w;
1030 try s.print("{}", .{inst});
1031 if (dies) try s.writeByte('!');
1032 }
1033
1034 fn typeOfIndex(w: *Writer, inst: Air.Inst.Index) Type {
1035 const zcu = w.pt.zcu;
1036 return w.air.typeOfIndex(inst, &zcu.intern_pool);
1037 }
1038};
test/cases/compile_errors/@import_zon_bad_type.zig+3-3
......@@ -117,9 +117,9 @@ export fn testMutablePointer() void {
117117// tmp.zig:37:38: note: imported here
118118// neg_inf.zon:1:1: error: expected type '?u8'
119119// tmp.zig:57:28: note: imported here
120// neg_inf.zon:1:1: error: expected type 'tmp.testNonExhaustiveEnum__enum_522'
120// neg_inf.zon:1:1: error: expected type 'tmp.testNonExhaustiveEnum__enum_525'
121121// tmp.zig:62:39: note: imported here
122// neg_inf.zon:1:1: error: expected type 'tmp.testUntaggedUnion__union_524'
122// neg_inf.zon:1:1: error: expected type 'tmp.testUntaggedUnion__union_527'
123123// tmp.zig:67:44: note: imported here
124// neg_inf.zon:1:1: error: expected type 'tmp.testTaggedUnionVoid__union_527'
124// neg_inf.zon:1:1: error: expected type 'tmp.testTaggedUnionVoid__union_530'
125125// tmp.zig:72:50: note: imported here
test/cases/compile_errors/anytype_param_requires_comptime.zig+1-1
......@@ -15,6 +15,6 @@ pub export fn entry() void {
1515// error
1616//
1717// :7:25: error: unable to resolve comptime value
18// :7:25: note: initializer of comptime-only struct 'tmp.S.foo__anon_496.C' must be comptime-known
18// :7:25: note: initializer of comptime-only struct 'tmp.S.foo__anon_499.C' must be comptime-known
1919// :4:16: note: struct requires comptime because of this field
2020// :4:16: note: types are not available at runtime
test/cases/compile_errors/bogus_method_call_on_slice.zig+1-1
......@@ -16,5 +16,5 @@ pub export fn entry2() void {
1616//
1717// :3:6: error: no field or member function named 'copy' in '[]const u8'
1818// :9:8: error: no field or member function named 'bar' in '@TypeOf(.{})'
19// :12:18: error: no field or member function named 'bar' in 'tmp.entry2__struct_500'
19// :12:18: error: no field or member function named 'bar' in 'tmp.entry2__struct_503'
2020// :12:6: note: struct declared here
test/cases/compile_errors/coerce_anon_struct.zig+1-1
......@@ -6,6 +6,6 @@ export fn foo() void {
66
77// error
88//
9// :4:16: error: expected type 'tmp.T', found 'tmp.foo__struct_489'
9// :4:16: error: expected type 'tmp.T', found 'tmp.foo__struct_492'
1010// :3:16: note: struct declared here
1111// :1:11: note: struct declared here
test/cases/compile_errors/redundant_try.zig+2-2
......@@ -44,9 +44,9 @@ comptime {
4444//
4545// :5:23: error: expected error union type, found 'comptime_int'
4646// :10:23: error: expected error union type, found '@TypeOf(.{})'
47// :15:23: error: expected error union type, found 'tmp.test2__struct_526'
47// :15:23: error: expected error union type, found 'tmp.test2__struct_529'
4848// :15:23: note: struct declared here
49// :20:27: error: expected error union type, found 'tmp.test3__struct_528'
49// :20:27: error: expected error union type, found 'tmp.test3__struct_531'
5050// :20:27: note: struct declared here
5151// :25:23: error: expected error union type, found 'struct { comptime *const [5:0]u8 = "hello" }'
5252// :31:13: error: expected error union type, found 'u32'
test/tests.zig+5-4
......@@ -1598,7 +1598,9 @@ const c_abi_targets = blk: {
15981598 break :blk [_]CAbiTarget{
15991599 // Native Targets
16001600
1601 .{},
1601 .{
1602 .use_llvm = true,
1603 },
16021604
16031605 // Linux Targets
16041606
......@@ -1837,7 +1839,6 @@ const c_abi_targets = blk: {
18371839 .abi = .musl,
18381840 },
18391841 .use_llvm = false,
1840 .use_lld = false,
18411842 .c_defines = &.{"ZIG_BACKEND_STAGE2_X86_64"},
18421843 },
18431844 .{
......@@ -1848,7 +1849,6 @@ const c_abi_targets = blk: {
18481849 .abi = .musl,
18491850 },
18501851 .use_llvm = false,
1851 .use_lld = false,
18521852 .strip = true,
18531853 .c_defines = &.{"ZIG_BACKEND_STAGE2_X86_64"},
18541854 },
......@@ -1860,7 +1860,6 @@ const c_abi_targets = blk: {
18601860 .abi = .musl,
18611861 },
18621862 .use_llvm = false,
1863 .use_lld = false,
18641863 .pic = true,
18651864 .c_defines = &.{"ZIG_BACKEND_STAGE2_X86_64"},
18661865 },
......@@ -1870,6 +1869,7 @@ const c_abi_targets = blk: {
18701869 .os_tag = .linux,
18711870 .abi = .musl,
18721871 },
1872 .use_llvm = true,
18731873 },
18741874 .{
18751875 .target = .{
......@@ -1877,6 +1877,7 @@ const c_abi_targets = blk: {
18771877 .os_tag = .linux,
18781878 .abi = .muslx32,
18791879 },
1880 .use_llvm = true,
18801881 },
18811882
18821883 // WASI Targets