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...@@ -519,6 +519,7 @@ set(ZIG_STAGE2_SOURCES
519 src/Air/Legalize.zig519 src/Air/Legalize.zig
520 src/Air/Liveness.zig520 src/Air/Liveness.zig
521 src/Air/Liveness/Verify.zig521 src/Air/Liveness/Verify.zig
522 src/Air/print.zig
522 src/Air/types_resolved.zig523 src/Air/types_resolved.zig
523 src/Builtin.zig524 src/Builtin.zig
524 src/Compilation.zig525 src/Compilation.zig
...@@ -675,7 +676,6 @@ set(ZIG_STAGE2_SOURCES...@@ -675,7 +676,6 @@ set(ZIG_STAGE2_SOURCES
675 src/libs/mingw.zig676 src/libs/mingw.zig
676 src/libs/musl.zig677 src/libs/musl.zig
677 src/mutable_value.zig678 src/mutable_value.zig
678 src/print_air.zig
679 src/print_env.zig679 src/print_env.zig
680 src/print_targets.zig680 src/print_targets.zig
681 src/print_value.zig681 src/print_value.zig
lib/std/builtin.zig+13-2
...@@ -61,7 +61,7 @@ pub const StackTrace = struct {...@@ -61,7 +61,7 @@ pub const StackTrace = struct {
6161
62/// This data structure is used by the Zig language code generation and62/// This data structure is used by the Zig language code generation and
63/// therefore must be kept in sync with the compiler implementation.63/// therefore must be kept in sync with the compiler implementation.
64pub const GlobalLinkage = enum {64pub const GlobalLinkage = enum(u2) {
65 internal,65 internal,
66 strong,66 strong,
67 weak,67 weak,
...@@ -70,7 +70,7 @@ pub const GlobalLinkage = enum {...@@ -70,7 +70,7 @@ pub const GlobalLinkage = enum {
7070
71/// This data structure is used by the Zig language code generation and71/// This data structure is used by the Zig language code generation and
72/// therefore must be kept in sync with the compiler implementation.72/// therefore must be kept in sync with the compiler implementation.
73pub const SymbolVisibility = enum {73pub const SymbolVisibility = enum(u2) {
74 default,74 default,
75 hidden,75 hidden,
76 protected,76 protected,
...@@ -1030,8 +1030,19 @@ pub const ExternOptions = struct {...@@ -1030,8 +1030,19 @@ pub const ExternOptions = struct {
1030 name: []const u8,1030 name: []const u8,
1031 library_name: ?[]const u8 = null,1031 library_name: ?[]const u8 = null,
1032 linkage: GlobalLinkage = .strong,1032 linkage: GlobalLinkage = .strong,
1033 visibility: SymbolVisibility = .default,
1034 /// Setting this to `true` makes the `@extern` a runtime value.
1033 is_thread_local: bool = false,1035 is_thread_local: bool = false,
1034 is_dll_import: bool = false,1036 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 };
1035};1046};
10361047
1037/// This data structure is used by the Zig language code generation and1048/// 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 {...@@ -83,13 +83,16 @@ const RDebug = extern struct {
83 r_ldbase: usize,83 r_ldbase: usize,
84};84};
8585
86/// TODO make it possible to reference this same external symbol 2x so we don't need this86/// TODO fix comparisons of extern symbol pointers so we don't need this helper function.
87/// helper function.87pub fn get_DYNAMIC() ?[*]const elf.Dyn {
88pub fn get_DYNAMIC() ?[*]elf.Dyn {88 return @extern([*]const elf.Dyn, .{
89 return @extern([*]elf.Dyn, .{ .name = "_DYNAMIC", .linkage = .weak });89 .name = "_DYNAMIC",
90 .linkage = .weak,
91 .visibility = .hidden,
92 });
90}93}
9194
92pub fn linkmap_iterator(phdrs: []elf.Phdr) error{InvalidExe}!LinkMap.Iterator {95pub fn linkmap_iterator(phdrs: []const elf.Phdr) error{InvalidExe}!LinkMap.Iterator {
93 _ = phdrs;96 _ = phdrs;
94 const _DYNAMIC = get_DYNAMIC() orelse {97 const _DYNAMIC = get_DYNAMIC() orelse {
95 // No PT_DYNAMIC means this is either a statically-linked program or a98 // 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) {...@@ -39,167 +39,175 @@ const R_RELATIVE = switch (builtin.cpu.arch) {
39// Obtain a pointer to the _DYNAMIC array.39// Obtain a pointer to the _DYNAMIC array.
40// We have to compute its address as a PC-relative quantity not to require a40// We have to compute its address as a PC-relative quantity not to require a
41// relocation that, at this point, is not yet applied.41// relocation that, at this point, is not yet applied.
42inline fn getDynamicSymbol() [*]elf.Dyn {42inline fn getDynamicSymbol() [*]const elf.Dyn {
43 return switch (builtin.cpu.arch) {43 return switch (builtin.zig_backend) {
44 .x86 => asm volatile (44 else => switch (builtin.cpu.arch) {
45 \\ .weak _DYNAMIC45 .x86 => asm volatile (
46 \\ .hidden _DYNAMIC46 \\ .weak _DYNAMIC
47 \\ call 1f47 \\ .hidden _DYNAMIC
48 \\ 1: pop %[ret]48 \\ call 1f
49 \\ lea _DYNAMIC-1b(%[ret]), %[ret]49 \\ 1: pop %[ret]
50 : [ret] "=r" (-> [*]elf.Dyn),50 \\ lea _DYNAMIC-1b(%[ret]), %[ret]
51 ),51 : [ret] "=r" (-> [*]const elf.Dyn),
52 .x86_64 => asm volatile (52 ),
53 \\ .weak _DYNAMIC53 .x86_64 => asm volatile (
54 \\ .hidden _DYNAMIC54 \\ .weak _DYNAMIC
55 \\ lea _DYNAMIC(%%rip), %[ret]55 \\ .hidden _DYNAMIC
56 : [ret] "=r" (-> [*]elf.Dyn),56 \\ lea _DYNAMIC(%%rip), %[ret]
57 ),57 : [ret] "=r" (-> [*]const elf.Dyn),
58 .arc => asm volatile (58 ),
59 \\ .weak _DYNAMIC59 .arc => asm volatile (
60 \\ .hidden _DYNAMIC60 \\ .weak _DYNAMIC
61 \\ add %[ret], pcl, _DYNAMIC@pcl61 \\ .hidden _DYNAMIC
62 : [ret] "=r" (-> [*]elf.Dyn),62 \\ add %[ret], pcl, _DYNAMIC@pcl
63 ),63 : [ret] "=r" (-> [*]const elf.Dyn),
64 // Work around the limited offset range of `ldr`64 ),
65 .arm, .armeb, .thumb, .thumbeb => asm volatile (65 // Work around the limited offset range of `ldr`
66 \\ .weak _DYNAMIC66 .arm, .armeb, .thumb, .thumbeb => asm volatile (
67 \\ .hidden _DYNAMIC67 \\ .weak _DYNAMIC
68 \\ ldr %[ret], 1f68 \\ .hidden _DYNAMIC
69 \\ add %[ret], pc69 \\ ldr %[ret], 1f
70 \\ b 2f70 \\ add %[ret], pc
71 \\ 1: .word _DYNAMIC-1b71 \\ b 2f
72 \\ 2:72 \\ 1: .word _DYNAMIC-1b
73 : [ret] "=r" (-> [*]elf.Dyn),73 \\ 2:
74 ),74 : [ret] "=r" (-> [*]const elf.Dyn),
75 // A simple `adr` is not enough as it has a limited offset range75 ),
76 .aarch64, .aarch64_be => asm volatile (76 // A simple `adr` is not enough as it has a limited offset range
77 \\ .weak _DYNAMIC77 .aarch64, .aarch64_be => asm volatile (
78 \\ .hidden _DYNAMIC78 \\ .weak _DYNAMIC
79 \\ adrp %[ret], _DYNAMIC79 \\ .hidden _DYNAMIC
80 \\ add %[ret], %[ret], #:lo12:_DYNAMIC80 \\ adrp %[ret], _DYNAMIC
81 : [ret] "=r" (-> [*]elf.Dyn),81 \\ add %[ret], %[ret], #:lo12:_DYNAMIC
82 ),82 : [ret] "=r" (-> [*]const elf.Dyn),
83 // The CSKY ABI requires the gb register to point to the GOT. Additionally, the first83 ),
84 // entry in the GOT is defined to hold the address of _DYNAMIC.84 // The CSKY ABI requires the gb register to point to the GOT. Additionally, the first
85 .csky => asm volatile (85 // entry in the GOT is defined to hold the address of _DYNAMIC.
86 \\ mov %[ret], gb86 .csky => asm volatile (
87 \\ ldw %[ret], %[ret]87 \\ mov %[ret], gb
88 : [ret] "=r" (-> [*]elf.Dyn),88 \\ ldw %[ret], %[ret]
89 ),89 : [ret] "=r" (-> [*]const elf.Dyn),
90 .hexagon => asm volatile (90 ),
91 \\ .weak _DYNAMIC91 .hexagon => asm volatile (
92 \\ .hidden _DYNAMIC92 \\ .weak _DYNAMIC
93 \\ jump 1f93 \\ .hidden _DYNAMIC
94 \\ .word _DYNAMIC - .94 \\ jump 1f
95 \\ 1:95 \\ .word _DYNAMIC - .
96 \\ r1 = pc96 \\ 1:
97 \\ r1 = add(r1, #-4)97 \\ r1 = pc
98 \\ %[ret] = memw(r1)98 \\ r1 = add(r1, #-4)
99 \\ %[ret] = add(r1, %[ret])99 \\ %[ret] = memw(r1)
100 : [ret] "=r" (-> [*]elf.Dyn),100 \\ %[ret] = add(r1, %[ret])
101 :101 : [ret] "=r" (-> [*]const elf.Dyn),
102 : "r1"102 :
103 ),103 : "r1"
104 .loongarch32, .loongarch64 => asm volatile (104 ),
105 \\ .weak _DYNAMIC105 .loongarch32, .loongarch64 => asm volatile (
106 \\ .hidden _DYNAMIC106 \\ .weak _DYNAMIC
107 \\ la.local %[ret], _DYNAMIC107 \\ .hidden _DYNAMIC
108 : [ret] "=r" (-> [*]elf.Dyn),108 \\ la.local %[ret], _DYNAMIC
109 ),109 : [ret] "=r" (-> [*]const elf.Dyn),
110 // Note that the - 8 is needed because pc in the second lea instruction points into the110 ),
111 // middle of that instruction. (The first lea is 6 bytes, the second is 4 bytes.)111 // Note that the - 8 is needed because pc in the second lea instruction points into the
112 .m68k => asm volatile (112 // middle of that instruction. (The first lea is 6 bytes, the second is 4 bytes.)
113 \\ .weak _DYNAMIC113 .m68k => asm volatile (
114 \\ .hidden _DYNAMIC114 \\ .weak _DYNAMIC
115 \\ lea _DYNAMIC - . - 8, %[ret]115 \\ .hidden _DYNAMIC
116 \\ lea (%[ret], %%pc), %[ret]116 \\ lea _DYNAMIC - . - 8, %[ret]
117 : [ret] "=r" (-> [*]elf.Dyn),117 \\ lea (%[ret], %%pc), %[ret]
118 ),118 : [ret] "=r" (-> [*]const elf.Dyn),
119 .mips, .mipsel => asm volatile (119 ),
120 \\ .weak _DYNAMIC120 .mips, .mipsel => asm volatile (
121 \\ .hidden _DYNAMIC121 \\ .weak _DYNAMIC
122 \\ bal 1f122 \\ .hidden _DYNAMIC
123 \\ .gpword _DYNAMIC123 \\ bal 1f
124 \\ 1:124 \\ .gpword _DYNAMIC
125 \\ lw %[ret], 0($ra)125 \\ 1:
126 \\ addu %[ret], %[ret], $gp126 \\ lw %[ret], 0($ra)
127 : [ret] "=r" (-> [*]elf.Dyn),127 \\ addu %[ret], %[ret], $gp
128 :128 : [ret] "=r" (-> [*]const elf.Dyn),
129 : "lr"129 :
130 ),130 : "lr"
131 .mips64, .mips64el => asm volatile (131 ),
132 \\ .weak _DYNAMIC132 .mips64, .mips64el => asm volatile (
133 \\ .hidden _DYNAMIC133 \\ .weak _DYNAMIC
134 \\ .balign 8134 \\ .hidden _DYNAMIC
135 \\ bal 1f135 \\ .balign 8
136 \\ .gpdword _DYNAMIC136 \\ bal 1f
137 \\ 1:137 \\ .gpdword _DYNAMIC
138 \\ ld %[ret], 0($ra)138 \\ 1:
139 \\ daddu %[ret], %[ret], $gp139 \\ ld %[ret], 0($ra)
140 : [ret] "=r" (-> [*]elf.Dyn),140 \\ daddu %[ret], %[ret], $gp
141 :141 : [ret] "=r" (-> [*]const elf.Dyn),
142 : "lr"142 :
143 ),143 : "lr"
144 .powerpc, .powerpcle => asm volatile (144 ),
145 \\ .weak _DYNAMIC145 .powerpc, .powerpcle => asm volatile (
146 \\ .hidden _DYNAMIC146 \\ .weak _DYNAMIC
147 \\ bl 1f147 \\ .hidden _DYNAMIC
148 \\ .long _DYNAMIC - .148 \\ bl 1f
149 \\ 1:149 \\ .long _DYNAMIC - .
150 \\ mflr %[ret]150 \\ 1:
151 \\ lwz 4, 0(%[ret])151 \\ mflr %[ret]
152 \\ add %[ret], 4, %[ret]152 \\ lwz 4, 0(%[ret])
153 : [ret] "=r" (-> [*]elf.Dyn),153 \\ add %[ret], 4, %[ret]
154 :154 : [ret] "=r" (-> [*]const elf.Dyn),
155 : "lr", "r4"155 :
156 ),156 : "lr", "r4"
157 .powerpc64, .powerpc64le => asm volatile (157 ),
158 \\ .weak _DYNAMIC158 .powerpc64, .powerpc64le => asm volatile (
159 \\ .hidden _DYNAMIC159 \\ .weak _DYNAMIC
160 \\ bl 1f160 \\ .hidden _DYNAMIC
161 \\ .quad _DYNAMIC - .161 \\ bl 1f
162 \\ 1:162 \\ .quad _DYNAMIC - .
163 \\ mflr %[ret]163 \\ 1:
164 \\ ld 4, 0(%[ret])164 \\ mflr %[ret]
165 \\ add %[ret], 4, %[ret]165 \\ ld 4, 0(%[ret])
166 : [ret] "=r" (-> [*]elf.Dyn),166 \\ add %[ret], 4, %[ret]
167 :167 : [ret] "=r" (-> [*]const elf.Dyn),
168 : "lr", "r4"168 :
169 ),169 : "lr", "r4"
170 .riscv32, .riscv64 => asm volatile (170 ),
171 \\ .weak _DYNAMIC171 .riscv32, .riscv64 => asm volatile (
172 \\ .hidden _DYNAMIC172 \\ .weak _DYNAMIC
173 \\ lla %[ret], _DYNAMIC173 \\ .hidden _DYNAMIC
174 : [ret] "=r" (-> [*]elf.Dyn),174 \\ lla %[ret], _DYNAMIC
175 ),175 : [ret] "=r" (-> [*]const elf.Dyn),
176 .s390x => asm volatile (176 ),
177 \\ .weak _DYNAMIC177 .s390x => asm volatile (
178 \\ .hidden _DYNAMIC178 \\ .weak _DYNAMIC
179 \\ larl %[ret], 1f179 \\ .hidden _DYNAMIC
180 \\ ag %[ret], 0(%[ret])180 \\ larl %[ret], 1f
181 \\ jg 2f181 \\ ag %[ret], 0(%[ret])
182 \\ 1: .quad _DYNAMIC - .182 \\ jg 2f
183 \\ 2:183 \\ 1: .quad _DYNAMIC - .
184 : [ret] "=r" (-> [*]elf.Dyn),184 \\ 2:
185 ),185 : [ret] "=r" (-> [*]const elf.Dyn),
186 // The compiler does not necessarily have any obligation to load the `l7` register (pointing186 ),
187 // to the GOT), so do it ourselves just in case.187 // The compiler does not necessarily have any obligation to load the `l7` register (pointing
188 .sparc, .sparc64 => asm volatile (188 // to the GOT), so do it ourselves just in case.
189 \\ sethi %%hi(_GLOBAL_OFFSET_TABLE_ - 4), %%l7189 .sparc, .sparc64 => asm volatile (
190 \\ call 1f190 \\ sethi %%hi(_GLOBAL_OFFSET_TABLE_ - 4), %%l7
191 \\ add %%l7, %%lo(_GLOBAL_OFFSET_TABLE_ + 4), %%l7191 \\ call 1f
192 \\ 1:192 \\ add %%l7, %%lo(_GLOBAL_OFFSET_TABLE_ + 4), %%l7
193 \\ add %%l7, %%o7, %[ret]193 \\ 1:
194 : [ret] "=r" (-> [*]elf.Dyn),194 \\ add %%l7, %%o7, %[ret]
195 ),195 : [ret] "=r" (-> [*]const elf.Dyn),
196 else => {196 ),
197 @compileError("PIE startup is not yet supported for this target!");197 else => {
198 @compileError("PIE startup is not yet supported for this target!");
199 },
198 },200 },
201 .stage2_x86_64 => @extern([*]const elf.Dyn, .{
202 .name = "_DYNAMIC",
203 .linkage = .weak,
204 .visibility = .hidden,
205 .relocation = .pcrel,
206 }).?,
199 };207 };
200}208}
201209
202pub fn relocate(phdrs: []elf.Phdr) void {210pub fn relocate(phdrs: []const elf.Phdr) void {
203 @setRuntimeSafety(false);211 @setRuntimeSafety(false);
204 @disableInstrumentation();212 @disableInstrumentation();
205213
...@@ -256,10 +264,9 @@ pub fn relocate(phdrs: []elf.Phdr) void {...@@ -256,10 +264,9 @@ pub fn relocate(phdrs: []elf.Phdr) void {
256264
257 const rel = sorted_dynv[elf.DT_REL];265 const rel = sorted_dynv[elf.DT_REL];
258 if (rel != 0) {266 if (rel != 0) {
259 const rels = @call(.always_inline, std.mem.bytesAsSlice, .{267 const rels: []const elf.Rel = @alignCast(@ptrCast(
260 elf.Rel,268 @as([*]align(@alignOf(elf.Rel)) const u8, @ptrFromInt(base_addr + rel))[0..sorted_dynv[elf.DT_RELSZ]],
261 @as([*]u8, @ptrFromInt(base_addr + rel))[0..sorted_dynv[elf.DT_RELSZ]],269 ));
262 });
263 for (rels) |r| {270 for (rels) |r| {
264 if (r.r_type() != R_RELATIVE) continue;271 if (r.r_type() != R_RELATIVE) continue;
265 @as(*usize, @ptrFromInt(base_addr + r.r_offset)).* += base_addr;272 @as(*usize, @ptrFromInt(base_addr + r.r_offset)).* += base_addr;
...@@ -268,10 +275,9 @@ pub fn relocate(phdrs: []elf.Phdr) void {...@@ -268,10 +275,9 @@ pub fn relocate(phdrs: []elf.Phdr) void {
268275
269 const rela = sorted_dynv[elf.DT_RELA];276 const rela = sorted_dynv[elf.DT_RELA];
270 if (rela != 0) {277 if (rela != 0) {
271 const relas = @call(.always_inline, std.mem.bytesAsSlice, .{278 const relas: []const elf.Rela = @alignCast(@ptrCast(
272 elf.Rela,279 @as([*]align(@alignOf(elf.Rela)) const u8, @ptrFromInt(base_addr + rela))[0..sorted_dynv[elf.DT_RELASZ]],
273 @as([*]u8, @ptrFromInt(base_addr + rela))[0..sorted_dynv[elf.DT_RELASZ]],280 ));
274 });
275 for (relas) |r| {281 for (relas) |r| {
276 if (r.r_type() != R_RELATIVE) continue;282 if (r.r_type() != R_RELATIVE) continue;
277 @as(*usize, @ptrFromInt(base_addr + r.r_offset)).* = base_addr + @as(usize, @bitCast(r.r_addend));283 @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 {...@@ -280,10 +286,9 @@ pub fn relocate(phdrs: []elf.Phdr) void {
280286
281 const relr = sorted_dynv[elf.DT_RELR];287 const relr = sorted_dynv[elf.DT_RELR];
282 if (relr != 0) {288 if (relr != 0) {
283 const relrs = @call(.always_inline, std.mem.bytesAsSlice, .{289 const relrs: []const elf.Relr = @ptrCast(
284 elf.Relr,290 @as([*]align(@alignOf(elf.Relr)) const u8, @ptrFromInt(base_addr + relr))[0..sorted_dynv[elf.DT_RELRSZ]],
285 @as([*]u8, @ptrFromInt(base_addr + relr))[0..sorted_dynv[elf.DT_RELRSZ]],291 );
286 });
287 var current: [*]usize = undefined;292 var current: [*]usize = undefined;
288 for (relrs) |r| {293 for (relrs) |r| {
289 if ((r & 1) == 0) {294 if ((r & 1) == 0) {
lib/std/start.zig+6-6
...@@ -163,7 +163,7 @@ fn exit2(code: usize) noreturn {...@@ -163,7 +163,7 @@ fn exit2(code: usize) noreturn {
163 // exits(0)163 // exits(0)
164 .plan9 => std.os.plan9.exits(null),164 .plan9 => std.os.plan9.exits(null),
165 .windows => {165 .windows => {
166 std.os.windows.ntdll.RtlExitUserProcess(@as(u32, @truncate(code)));166 std.os.windows.ntdll.RtlExitUserProcess(@truncate(code));
167 },167 },
168 else => @compileError("TODO"),168 else => @compileError("TODO"),
169 }169 }
...@@ -511,7 +511,7 @@ fn posixCallMainAndExit(argc_argv_ptr: [*]usize) callconv(.c) noreturn {...@@ -511,7 +511,7 @@ fn posixCallMainAndExit(argc_argv_ptr: [*]usize) callconv(.c) noreturn {
511 // Code coverage instrumentation might try to use thread local variables.511 // Code coverage instrumentation might try to use thread local variables.
512 @disableInstrumentation();512 @disableInstrumentation();
513 const argc = argc_argv_ptr[0];513 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
516 const envp_optional: [*:null]?[*:0]u8 = @ptrCast(@alignCast(argv + argc + 1));516 const envp_optional: [*:null]?[*:0]u8 = @ptrCast(@alignCast(argv + argc + 1));
517 var envp_count: usize = 0;517 var envp_count: usize = 0;
...@@ -573,11 +573,11 @@ fn posixCallMainAndExit(argc_argv_ptr: [*]usize) callconv(.c) noreturn {...@@ -573,11 +573,11 @@ fn posixCallMainAndExit(argc_argv_ptr: [*]usize) callconv(.c) noreturn {
573 expandStackSize(phdrs);573 expandStackSize(phdrs);
574 }574 }
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, .{
577 .name = "__init_array_start",577 .name = "__init_array_start",
578 .linkage = .weak,578 .linkage = .weak,
579 });579 });
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, .{
581 .name = "__init_array_end",581 .name = "__init_array_end",
582 .linkage = .weak,582 .linkage = .weak,
583 });583 });
...@@ -651,7 +651,7 @@ fn main(c_argc: c_int, c_argv: [*][*:0]c_char, c_envp: [*:null]?[*:0]c_char) cal...@@ -651,7 +651,7 @@ fn main(c_argc: c_int, c_argv: [*][*:0]c_char, c_envp: [*:null]?[*:0]c_char) cal
651}651}
652652
653fn mainWithoutEnv(c_argc: c_int, c_argv: [*][*:0]c_char) callconv(.c) c_int {653fn 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)];
655 return callMain();655 return callMain();
656}656}
657657
...@@ -701,7 +701,7 @@ pub inline fn callMain() u8 {...@@ -701,7 +701,7 @@ pub inline fn callMain() u8 {
701pub fn call_wWinMain() std.os.windows.INT {701pub fn call_wWinMain() std.os.windows.INT {
702 const peb = std.os.windows.peb();702 const peb = std.os.windows.peb();
703 const MAIN_HINSTANCE = @typeInfo(@TypeOf(root.wWinMain)).@"fn".params[0].type.?;703 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);
705 const lpCmdLine: [*:0]u16 = @ptrCast(peb.ProcessParameters.CommandLine.Buffer);705 const lpCmdLine: [*:0]u16 = @ptrCast(peb.ProcessParameters.CommandLine.Buffer);
706706
707 // There are various types used for the 'show window' variable through the Win32 APIs:707 // 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) {...@@ -1823,6 +1823,14 @@ pub const Visibility = enum(u2) {
1823 hidden = 1,1823 hidden = 1,
1824 protected = 2,1824 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
1826 pub fn format(1834 pub fn format(
1827 self: Visibility,1835 self: Visibility,
1828 comptime _: []const u8,1836 comptime _: []const u8,
...@@ -2555,6 +2563,10 @@ pub const Variable = struct {...@@ -2555,6 +2563,10 @@ pub const Variable = struct {
2555 return self.ptrConst(builder).global.setLinkage(linkage, builder);2563 return self.ptrConst(builder).global.setLinkage(linkage, builder);
2556 }2564 }
25572565
2566 pub fn setVisibility(self: Index, visibility: Visibility, builder: *Builder) void {
2567 return self.ptrConst(builder).global.setVisibility(visibility, builder);
2568 }
2569
2558 pub fn setDllStorageClass(self: Index, class: DllStorageClass, builder: *Builder) void {2570 pub fn setDllStorageClass(self: Index, class: DllStorageClass, builder: *Builder) void {
2559 return self.ptrConst(builder).global.setDllStorageClass(class, builder);2571 return self.ptrConst(builder).global.setDllStorageClass(class, builder);
2560 }2572 }
lib/zig.h+9
...@@ -272,6 +272,15 @@...@@ -272,6 +272,15 @@
272#define zig_linksection_fn zig_linksection272#define zig_linksection_fn zig_linksection
273#endif273#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
275#if zig_has_builtin(unreachable) || defined(zig_gcc) || defined(zig_tinyc)284#if zig_has_builtin(unreachable) || defined(zig_gcc) || defined(zig_tinyc)
276#define zig_unreachable() __builtin_unreachable()285#define zig_unreachable() __builtin_unreachable()
277#elif defined(zig_msvc)286#elif defined(zig_msvc)
src/Air.zig+10-4
...@@ -13,6 +13,7 @@ const InternPool = @import("InternPool.zig");...@@ -13,6 +13,7 @@ const InternPool = @import("InternPool.zig");
13const Type = @import("Type.zig");13const Type = @import("Type.zig");
14const Value = @import("Value.zig");14const Value = @import("Value.zig");
15const Zcu = @import("Zcu.zig");15const Zcu = @import("Zcu.zig");
16const print = @import("Air/print.zig");
16const types_resolved = @import("Air/types_resolved.zig");17const types_resolved = @import("Air/types_resolved.zig");
1718
18pub const Legalize = @import("Air/Legalize.zig");19pub const Legalize = @import("Air/Legalize.zig");
...@@ -863,16 +864,17 @@ pub const Inst = struct {...@@ -863,16 +864,17 @@ pub const Inst = struct {
863 /// Uses the `vector_store_elem` field.864 /// Uses the `vector_store_elem` field.
864 vector_store_elem,865 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:
867 ///868 ///
868 /// * `threadlocal var`869 /// * `threadlocal var`
869 /// * `extern threadlocal var` (or corresponding `@extern`)870 /// * `extern threadlocal var` (or corresponding `@extern`)
870 /// * `@extern` with `.is_dll_import = true`871 /// * `@extern` with `.is_dll_import = true`
872 /// * `@extern` with `.relocation = .pcrel`
871 ///873 ///
872 /// Such pointers are runtime values, so cannot be represented with an InternPool index.874 /// Such pointers are runtime values, so cannot be represented with an InternPool index.
873 ///875 ///
874 /// Uses the `ty_nav` field.876 /// Uses the `ty_nav` field.
875 tlv_dllimport_ptr,877 runtime_nav_ptr,
876878
877 /// Implements @cVaArg builtin.879 /// Implements @cVaArg builtin.
878 /// Uses the `ty_op` field.880 /// Uses the `ty_op` field.
...@@ -1708,7 +1710,7 @@ pub fn typeOfIndex(air: *const Air, inst: Air.Inst.Index, ip: *const InternPool)...@@ -1708,7 +1710,7 @@ pub fn typeOfIndex(air: *const Air, inst: Air.Inst.Index, ip: *const InternPool)
1708 return .fromInterned(ip.indexToKey(err_union_ty.ip_index).error_union_type.payload_type);1710 return .fromInterned(ip.indexToKey(err_union_ty.ip_index).error_union_type.payload_type);
1709 },1711 },
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
1713 .work_item_id,1715 .work_item_id,
1714 .work_group_size,1716 .work_group_size,
...@@ -1983,7 +1985,7 @@ pub fn mustLower(air: Air, inst: Air.Inst.Index, ip: *const InternPool) bool {...@@ -1983,7 +1985,7 @@ pub fn mustLower(air: Air, inst: Air.Inst.Index, ip: *const InternPool) bool {
1983 .err_return_trace,1985 .err_return_trace,
1984 .addrspace_cast,1986 .addrspace_cast,
1985 .save_err_return_trace_index,1987 .save_err_return_trace_index,
1986 .tlv_dllimport_ptr,1988 .runtime_nav_ptr,
1987 .work_item_id,1989 .work_item_id,
1988 .work_group_size,1990 .work_group_size,
1989 .work_group_id,1991 .work_group_id,
...@@ -2141,6 +2143,10 @@ pub const typesFullyResolved = types_resolved.typesFullyResolved;...@@ -2141,6 +2143,10 @@ pub const typesFullyResolved = types_resolved.typesFullyResolved;
2141pub const typeFullyResolved = types_resolved.checkType;2143pub const typeFullyResolved = types_resolved.checkType;
2142pub const valFullyResolved = types_resolved.checkVal;2144pub const valFullyResolved = types_resolved.checkVal;
2143pub const legalize = Legalize.legalize;2145pub 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
2145pub const CoveragePoint = enum(u1) {2151pub const CoveragePoint = enum(u1) {
2146 /// Indicates the block is not a place of interest corresponding to2152 /// 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 {...@@ -622,7 +622,7 @@ fn legalizeBody(l: *Legalize, body_start: usize, body_len: usize) Error!void {
622 .addrspace_cast,622 .addrspace_cast,
623 .save_err_return_trace_index,623 .save_err_return_trace_index,
624 .vector_store_elem,624 .vector_store_elem,
625 .tlv_dllimport_ptr,625 .runtime_nav_ptr,
626 .c_va_arg,626 .c_va_arg,
627 .c_va_copy,627 .c_va_copy,
628 .c_va_end,628 .c_va_end,
src/Air/Liveness.zig+2-2
...@@ -339,7 +339,7 @@ pub fn categorizeOperand(...@@ -339,7 +339,7 @@ pub fn categorizeOperand(
339 .wasm_memory_size,339 .wasm_memory_size,
340 .err_return_trace,340 .err_return_trace,
341 .save_err_return_trace_index,341 .save_err_return_trace_index,
342 .tlv_dllimport_ptr,342 .runtime_nav_ptr,
343 .c_va_start,343 .c_va_start,
344 .work_item_id,344 .work_item_id,
345 .work_group_size,345 .work_group_size,
...@@ -972,7 +972,7 @@ fn analyzeInst(...@@ -972,7 +972,7 @@ fn analyzeInst(
972 .wasm_memory_size,972 .wasm_memory_size,
973 .err_return_trace,973 .err_return_trace,
974 .save_err_return_trace_index,974 .save_err_return_trace_index,
975 .tlv_dllimport_ptr,975 .runtime_nav_ptr,
976 .c_va_start,976 .c_va_start,
977 .work_item_id,977 .work_item_id,
978 .work_group_size,978 .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 {...@@ -63,7 +63,7 @@ fn verifyBody(self: *Verify, body: []const Air.Inst.Index) Error!void {
63 .wasm_memory_size,63 .wasm_memory_size,
64 .err_return_trace,64 .err_return_trace,
65 .save_err_return_trace_index,65 .save_err_return_trace_index,
66 .tlv_dllimport_ptr,66 .runtime_nav_ptr,
67 .c_va_start,67 .c_va_start,
68 .work_item_id,68 .work_item_id,
69 .work_group_size,69 .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 {...@@ -321,7 +321,7 @@ fn checkBody(air: Air, body: []const Air.Inst.Index, zcu: *Zcu) bool {
321 if (!checkRef(bin.rhs, zcu)) return false;321 if (!checkRef(bin.rhs, zcu)) return false;
322 },322 },
323323
324 .tlv_dllimport_ptr => {324 .runtime_nav_ptr => {
325 if (!checkType(.fromInterned(data.ty_nav.ty), zcu)) return false;325 if (!checkType(.fromInterned(data.ty_nav.ty), zcu)) return false;
326 },326 },
327327
src/Compilation/Config.zig+19-12
...@@ -345,11 +345,19 @@ pub fn resolve(options: Options) ResolveError!Config {...@@ -345,11 +345,19 @@ pub fn resolve(options: Options) ResolveError!Config {
345 } else false;345 } else false;
346 };346 };
347347
348 const is_dyn_lib = switch (options.output_mode) {
349 .Obj, .Exe => false,
350 .Lib => link_mode == .dynamic,
351 };
352
348 // Make a decision on whether to use LLVM backend for machine code generation.353 // Make a decision on whether to use LLVM backend for machine code generation.
349 // Note that using the LLVM backend does not necessarily mean using LLVM libraries.354 // Note that using the LLVM backend does not necessarily mean using LLVM libraries.
350 // For example, Zig can emit .bc and .ll files directly, and this is still considered355 // For example, Zig can emit .bc and .ll files directly, and this is still considered
351 // using "the LLVM backend".356 // 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
353 // If emitting to LLVM bitcode object format, must use LLVM backend.361 // If emitting to LLVM bitcode object format, must use LLVM backend.
354 if (options.emit_llvm_ir or options.emit_llvm_bc) {362 if (options.emit_llvm_ir or options.emit_llvm_bc) {
355 if (options.use_llvm == false)363 if (options.use_llvm == false)
...@@ -382,9 +390,9 @@ pub fn resolve(options: Options) ResolveError!Config {...@@ -382,9 +390,9 @@ pub fn resolve(options: Options) ResolveError!Config {
382 // Prefer LLVM for release builds.390 // Prefer LLVM for release builds.
383 if (root_optimize_mode != .Debug) break :b true;391 if (root_optimize_mode != .Debug) break :b true;
384392
385 // Self-hosted backends can't handle the inline assembly in std.pie yet393 // load_dynamic_library standalone test not passing on this combination
386 // https://github.com/ziglang/zig/issues/24046394 // https://github.com/ziglang/zig/issues/24080
387 if (pie) break :b true;395 if (target.os.tag == .macos and is_dyn_lib) break :b true;
388396
389 // At this point we would prefer to use our own self-hosted backend,397 // At this point we would prefer to use our own self-hosted backend,
390 // because the compilation speed is better than LLVM. But only do it if398 // because the compilation speed is better than LLVM. But only do it if
...@@ -392,13 +400,6 @@ pub fn resolve(options: Options) ResolveError!Config {...@@ -392,13 +400,6 @@ pub fn resolve(options: Options) ResolveError!Config {
392 break :b !target_util.selfHostedBackendIsAsRobustAsLlvm(target);400 break :b !target_util.selfHostedBackendIsAsRobustAsLlvm(target);
393 };401 };
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
402 if (options.emit_bin and options.have_zcu) {403 if (options.emit_bin and options.have_zcu) {
403 if (!use_lib_llvm and use_llvm) {404 if (!use_lib_llvm and use_llvm) {
404 // Explicit request to use LLVM to produce an object file, but without405 // Explicit request to use LLVM to produce an object file, but without
...@@ -435,7 +436,13 @@ pub fn resolve(options: Options) ResolveError!Config {...@@ -435,7 +436,13 @@ pub fn resolve(options: Options) ResolveError!Config {
435 }436 }
436437
437 if (options.use_lld) |x| break :b x;438 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;
439 };446 };
440447
441 const lto: std.zig.LtoMode = b: {448 const lto: std.zig.LtoMode = b: {
src/InternPool.zig+71-49
...@@ -526,10 +526,10 @@ pub const Nav = struct {...@@ -526,10 +526,10 @@ pub const Nav = struct {
526 /// The type of this `Nav` is resolved; the value is queued for resolution.526 /// The type of this `Nav` is resolved; the value is queued for resolution.
527 type_resolved: struct {527 type_resolved: struct {
528 type: InternPool.Index,528 type: InternPool.Index,
529 is_const: bool,
529 alignment: Alignment,530 alignment: Alignment,
530 @"linksection": OptionalNullTerminatedString,531 @"linksection": OptionalNullTerminatedString,
531 @"addrspace": std.builtin.AddressSpace,532 @"addrspace": std.builtin.AddressSpace,
532 is_const: bool,
533 is_threadlocal: bool,533 is_threadlocal: bool,
534 /// This field is whether this `Nav` is a literal `extern` definition.534 /// This field is whether this `Nav` is a literal `extern` definition.
535 /// It does *not* tell you whether this might alias an extern fn (see #21027).535 /// It does *not* tell you whether this might alias an extern fn (see #21027).
...@@ -538,6 +538,7 @@ pub const Nav = struct {...@@ -538,6 +538,7 @@ pub const Nav = struct {
538 /// The value of this `Nav` is resolved.538 /// The value of this `Nav` is resolved.
539 fully_resolved: struct {539 fully_resolved: struct {
540 val: InternPool.Index,540 val: InternPool.Index,
541 is_const: bool,
541 alignment: Alignment,542 alignment: Alignment,
542 @"linksection": OptionalNullTerminatedString,543 @"linksection": OptionalNullTerminatedString,
543 @"addrspace": std.builtin.AddressSpace,544 @"addrspace": std.builtin.AddressSpace,
...@@ -727,12 +728,12 @@ pub const Nav = struct {...@@ -727,12 +728,12 @@ pub const Nav = struct {
727 const Bits = packed struct(u16) {728 const Bits = packed struct(u16) {
728 status: enum(u2) { unresolved, type_resolved, fully_resolved, type_resolved_extern_decl },729 status: enum(u2) { unresolved, type_resolved, fully_resolved, type_resolved_extern_decl },
729 /// Populated only if `bits.status != .unresolved`.730 /// Populated only if `bits.status != .unresolved`.
731 is_const: bool,
732 /// Populated only if `bits.status != .unresolved`.
730 alignment: Alignment,733 alignment: Alignment,
731 /// Populated only if `bits.status != .unresolved`.734 /// Populated only if `bits.status != .unresolved`.
732 @"addrspace": std.builtin.AddressSpace,735 @"addrspace": std.builtin.AddressSpace,
733 /// Populated only if `bits.status == .type_resolved`.736 /// Populated only if `bits.status == .type_resolved`.
734 is_const: bool,
735 /// Populated only if `bits.status == .type_resolved`.
736 is_threadlocal: bool,737 is_threadlocal: bool,
737 is_usingnamespace: bool,738 is_usingnamespace: bool,
738 };739 };
...@@ -753,15 +754,16 @@ pub const Nav = struct {...@@ -753,15 +754,16 @@ pub const Nav = struct {
753 .unresolved => .unresolved,754 .unresolved => .unresolved,
754 .type_resolved, .type_resolved_extern_decl => .{ .type_resolved = .{755 .type_resolved, .type_resolved_extern_decl => .{ .type_resolved = .{
755 .type = repr.type_or_val,756 .type = repr.type_or_val,
757 .is_const = repr.bits.is_const,
756 .alignment = repr.bits.alignment,758 .alignment = repr.bits.alignment,
757 .@"linksection" = repr.@"linksection",759 .@"linksection" = repr.@"linksection",
758 .@"addrspace" = repr.bits.@"addrspace",760 .@"addrspace" = repr.bits.@"addrspace",
759 .is_const = repr.bits.is_const,
760 .is_threadlocal = repr.bits.is_threadlocal,761 .is_threadlocal = repr.bits.is_threadlocal,
761 .is_extern_decl = repr.bits.status == .type_resolved_extern_decl,762 .is_extern_decl = repr.bits.status == .type_resolved_extern_decl,
762 } },763 } },
763 .fully_resolved => .{ .fully_resolved = .{764 .fully_resolved => .{ .fully_resolved = .{
764 .val = repr.type_or_val,765 .val = repr.type_or_val,
766 .is_const = repr.bits.is_const,
765 .alignment = repr.bits.alignment,767 .alignment = repr.bits.alignment,
766 .@"linksection" = repr.@"linksection",768 .@"linksection" = repr.@"linksection",
767 .@"addrspace" = repr.bits.@"addrspace",769 .@"addrspace" = repr.bits.@"addrspace",
...@@ -792,26 +794,26 @@ pub const Nav = struct {...@@ -792,26 +794,26 @@ pub const Nav = struct {
792 .bits = switch (nav.status) {794 .bits = switch (nav.status) {
793 .unresolved => .{795 .unresolved => .{
794 .status = .unresolved,796 .status = .unresolved,
797 .is_const = false,
795 .alignment = .none,798 .alignment = .none,
796 .@"addrspace" = .generic,799 .@"addrspace" = .generic,
797 .is_usingnamespace = nav.is_usingnamespace,800 .is_usingnamespace = nav.is_usingnamespace,
798 .is_const = false,
799 .is_threadlocal = false,801 .is_threadlocal = false,
800 },802 },
801 .type_resolved => |r| .{803 .type_resolved => |r| .{
802 .status = if (r.is_extern_decl) .type_resolved_extern_decl else .type_resolved,804 .status = if (r.is_extern_decl) .type_resolved_extern_decl else .type_resolved,
805 .is_const = r.is_const,
803 .alignment = r.alignment,806 .alignment = r.alignment,
804 .@"addrspace" = r.@"addrspace",807 .@"addrspace" = r.@"addrspace",
805 .is_usingnamespace = nav.is_usingnamespace,808 .is_usingnamespace = nav.is_usingnamespace,
806 .is_const = r.is_const,
807 .is_threadlocal = r.is_threadlocal,809 .is_threadlocal = r.is_threadlocal,
808 },810 },
809 .fully_resolved => |r| .{811 .fully_resolved => |r| .{
810 .status = .fully_resolved,812 .status = .fully_resolved,
813 .is_const = r.is_const,
811 .alignment = r.alignment,814 .alignment = r.alignment,
812 .@"addrspace" = r.@"addrspace",815 .@"addrspace" = r.@"addrspace",
813 .is_usingnamespace = nav.is_usingnamespace,816 .is_usingnamespace = nav.is_usingnamespace,
814 .is_const = false,
815 .is_threadlocal = false,817 .is_threadlocal = false,
816 },818 },
817 },819 },
...@@ -2221,7 +2223,6 @@ pub const Key = union(enum) {...@@ -2221,7 +2223,6 @@ pub const Key = union(enum) {
2221 init: Index,2223 init: Index,
2222 owner_nav: Nav.Index,2224 owner_nav: Nav.Index,
2223 is_threadlocal: bool,2225 is_threadlocal: bool,
2224 is_weak_linkage: bool,
2225 };2226 };
22262227
2227 pub const Extern = struct {2228 pub const Extern = struct {
...@@ -2234,10 +2235,12 @@ pub const Key = union(enum) {...@@ -2234,10 +2235,12 @@ pub const Key = union(enum) {
2234 /// For example `extern "c" fn write(...) usize` would have 'c' as library name.2235 /// For example `extern "c" fn write(...) usize` would have 'c' as library name.
2235 /// Index into the string table bytes.2236 /// Index into the string table bytes.
2236 lib_name: OptionalNullTerminatedString,2237 lib_name: OptionalNullTerminatedString,
2237 is_const: bool,2238 linkage: std.builtin.GlobalLinkage,
2239 visibility: std.builtin.SymbolVisibility,
2238 is_threadlocal: bool,2240 is_threadlocal: bool,
2239 is_weak_linkage: bool,
2240 is_dll_import: bool,2241 is_dll_import: bool,
2242 relocation: std.builtin.ExternOptions.Relocation,
2243 is_const: bool,
2241 alignment: Alignment,2244 alignment: Alignment,
2242 @"addrspace": std.builtin.AddressSpace,2245 @"addrspace": std.builtin.AddressSpace,
2243 /// The ZIR instruction which created this extern; used only for source locations.2246 /// The ZIR instruction which created this extern; used only for source locations.
...@@ -2844,9 +2847,10 @@ pub const Key = union(enum) {...@@ -2844,9 +2847,10 @@ pub const Key = union(enum) {
28442847
2845 .@"extern" => |e| Hash.hash(seed, asBytes(&e.name) ++2848 .@"extern" => |e| Hash.hash(seed, asBytes(&e.name) ++
2846 asBytes(&e.ty) ++ asBytes(&e.lib_name) ++2849 asBytes(&e.ty) ++ asBytes(&e.lib_name) ++
2847 asBytes(&e.is_const) ++ asBytes(&e.is_threadlocal) ++2850 asBytes(&e.linkage) ++ asBytes(&e.visibility) ++
2848 asBytes(&e.is_weak_linkage) ++ asBytes(&e.alignment) ++2851 asBytes(&e.is_threadlocal) ++ asBytes(&e.is_dll_import) ++
2849 asBytes(&e.is_dll_import) ++ asBytes(&e.@"addrspace") ++2852 asBytes(&e.relocation) ++
2853 asBytes(&e.is_const) ++ asBytes(&e.alignment) ++ asBytes(&e.@"addrspace") ++
2850 asBytes(&e.zir_index)),2854 asBytes(&e.zir_index)),
2851 };2855 };
2852 }2856 }
...@@ -2928,21 +2932,22 @@ pub const Key = union(enum) {...@@ -2928,21 +2932,22 @@ pub const Key = union(enum) {
29282932
2929 .variable => |a_info| {2933 .variable => |a_info| {
2930 const b_info = b.variable;2934 const b_info = b.variable;
2931 return a_info.owner_nav == b_info.owner_nav and2935 return a_info.ty == b_info.ty and
2932 a_info.ty == b_info.ty and
2933 a_info.init == b_info.init and2936 a_info.init == b_info.init and
2934 a_info.is_threadlocal == b_info.is_threadlocal and2937 a_info.owner_nav == b_info.owner_nav and
2935 a_info.is_weak_linkage == b_info.is_weak_linkage;2938 a_info.is_threadlocal == b_info.is_threadlocal;
2936 },2939 },
2937 .@"extern" => |a_info| {2940 .@"extern" => |a_info| {
2938 const b_info = b.@"extern";2941 const b_info = b.@"extern";
2939 return a_info.name == b_info.name and2942 return a_info.name == b_info.name and
2940 a_info.ty == b_info.ty and2943 a_info.ty == b_info.ty and
2941 a_info.lib_name == b_info.lib_name and2944 a_info.lib_name == b_info.lib_name and
2942 a_info.is_const == b_info.is_const and2945 a_info.linkage == b_info.linkage and
2946 a_info.visibility == b_info.visibility and
2943 a_info.is_threadlocal == b_info.is_threadlocal and2947 a_info.is_threadlocal == b_info.is_threadlocal and
2944 a_info.is_weak_linkage == b_info.is_weak_linkage and
2945 a_info.is_dll_import == b_info.is_dll_import and2948 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
2946 a_info.alignment == b_info.alignment and2951 a_info.alignment == b_info.alignment and
2947 a_info.@"addrspace" == b_info.@"addrspace" and2952 a_info.@"addrspace" == b_info.@"addrspace" and
2948 a_info.zir_index == b_info.zir_index;2953 a_info.zir_index == b_info.zir_index;
...@@ -4889,6 +4894,7 @@ pub const Index = enum(u32) {...@@ -4889,6 +4894,7 @@ pub const Index = enum(u32) {
4889 float_c_longdouble_f128: struct { data: *Float128 },4894 float_c_longdouble_f128: struct { data: *Float128 },
4890 float_comptime_float: struct { data: *Float128 },4895 float_comptime_float: struct { data: *Float128 },
4891 variable: struct { data: *Tag.Variable },4896 variable: struct { data: *Tag.Variable },
4897 threadlocal_variable: struct { data: *Tag.Variable },
4892 @"extern": struct { data: *Tag.Extern },4898 @"extern": struct { data: *Tag.Extern },
4893 func_decl: struct {4899 func_decl: struct {
4894 const @"data.analysis.inferred_error_set" = opaque {};4900 const @"data.analysis.inferred_error_set" = opaque {};
...@@ -5548,6 +5554,9 @@ pub const Tag = enum(u8) {...@@ -5548,6 +5554,9 @@ pub const Tag = enum(u8) {
5548 /// A global variable.5554 /// A global variable.
5549 /// data is extra index to Variable.5555 /// data is extra index to Variable.
5550 variable,5556 variable,
5557 /// A global threadlocal variable.
5558 /// data is extra index to Variable.
5559 threadlocal_variable,
5551 /// An extern function or variable.5560 /// An extern function or variable.
5552 /// data is extra index to Extern.5561 /// data is extra index to Extern.
5553 /// Some parts of the key are stored in `owner_nav`.5562 /// Some parts of the key are stored in `owner_nav`.
...@@ -5863,6 +5872,7 @@ pub const Tag = enum(u8) {...@@ -5863,6 +5872,7 @@ pub const Tag = enum(u8) {
5863 .float_c_longdouble_f128 = .{ .summary = .@"@as(c_longdouble, {.payload%value})", .payload = f128 },5872 .float_c_longdouble_f128 = .{ .summary = .@"@as(c_longdouble, {.payload%value})", .payload = f128 },
5864 .float_comptime_float = .{ .summary = .@"{.payload%value}", .payload = f128 },5873 .float_comptime_float = .{ .summary = .@"{.payload%value}", .payload = f128 },
5865 .variable = .{ .summary = .@"{.payload.owner_nav.fqn%summary#\"}", .payload = Variable },5874 .variable = .{ .summary = .@"{.payload.owner_nav.fqn%summary#\"}", .payload = Variable },
5875 .threadlocal_variable = .{ .summary = .@"{.payload.owner_nav.fqn%summary#\"}", .payload = Variable },
5866 .@"extern" = .{ .summary = .@"{.payload.owner_nav.fqn%summary#\"}", .payload = Extern },5876 .@"extern" = .{ .summary = .@"{.payload.owner_nav.fqn%summary#\"}", .payload = Extern },
5867 .func_decl = .{5877 .func_decl = .{
5868 .summary = .@"{.payload.owner_nav.fqn%summary#\"}",5878 .summary = .@"{.payload.owner_nav.fqn%summary#\"}",
...@@ -5913,24 +5923,24 @@ pub const Tag = enum(u8) {...@@ -5913,24 +5923,24 @@ pub const Tag = enum(u8) {
5913 /// May be `none`.5923 /// May be `none`.
5914 init: Index,5924 init: Index,
5915 owner_nav: Nav.Index,5925 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 };
5925 };5926 };
59265927
5927 pub const Extern = struct {5928 pub const Extern = struct {
5928 // name, alignment, addrspace come from `owner_nav`.5929 // name, is_const, alignment, addrspace come from `owner_nav`.
5929 ty: Index,5930 ty: Index,
5930 lib_name: OptionalNullTerminatedString,5931 lib_name: OptionalNullTerminatedString,
5931 flags: Variable.Flags,5932 flags: Flags,
5932 owner_nav: Nav.Index,5933 owner_nav: Nav.Index,
5933 zir_index: TrackedInst.Index,5934 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 };
5934 };5944 };
59355945
5936 /// Trailing:5946 /// Trailing:
...@@ -7248,14 +7258,17 @@ pub fn indexToKey(ip: *const InternPool, index: Index) Key {...@@ -7248,14 +7258,17 @@ pub fn indexToKey(ip: *const InternPool, index: Index) Key {
7248 .ty = .comptime_float_type,7258 .ty = .comptime_float_type,
7249 .storage = .{ .f128 = extraData(unwrapped_index.getExtra(ip), Float128, data).get() },7259 .storage = .{ .f128 = extraData(unwrapped_index.getExtra(ip), Float128, data).get() },
7250 } },7260 } },
7251 .variable => {7261 .variable, .threadlocal_variable => {
7252 const extra = extraData(unwrapped_index.getExtra(ip), Tag.Variable, data);7262 const extra = extraData(unwrapped_index.getExtra(ip), Tag.Variable, data);
7253 return .{ .variable = .{7263 return .{ .variable = .{
7254 .ty = extra.ty,7264 .ty = extra.ty,
7255 .init = extra.init,7265 .init = extra.init,
7256 .owner_nav = extra.owner_nav,7266 .owner_nav = extra.owner_nav,
7257 .is_threadlocal = extra.flags.is_threadlocal,7267 .is_threadlocal = switch (item.tag) {
7258 .is_weak_linkage = extra.flags.is_weak_linkage,7268 else => unreachable,
7269 .variable => false,
7270 .threadlocal_variable => true,
7271 },
7259 } };7272 } };
7260 },7273 },
7261 .@"extern" => {7274 .@"extern" => {
...@@ -7265,10 +7278,12 @@ pub fn indexToKey(ip: *const InternPool, index: Index) Key {...@@ -7265,10 +7278,12 @@ pub fn indexToKey(ip: *const InternPool, index: Index) Key {
7265 .name = nav.name,7278 .name = nav.name,
7266 .ty = extra.ty,7279 .ty = extra.ty,
7267 .lib_name = extra.lib_name,7280 .lib_name = extra.lib_name,
7268 .is_const = extra.flags.is_const,7281 .linkage = extra.flags.linkage,
7282 .visibility = extra.flags.visibility,
7269 .is_threadlocal = extra.flags.is_threadlocal,7283 .is_threadlocal = extra.flags.is_threadlocal,
7270 .is_weak_linkage = extra.flags.is_weak_linkage,
7271 .is_dll_import = extra.flags.is_dll_import,7284 .is_dll_import = extra.flags.is_dll_import,
7285 .relocation = extra.flags.relocation,
7286 .is_const = nav.status.fully_resolved.is_const,
7272 .alignment = nav.status.fully_resolved.alignment,7287 .alignment = nav.status.fully_resolved.alignment,
7273 .@"addrspace" = nav.status.fully_resolved.@"addrspace",7288 .@"addrspace" = nav.status.fully_resolved.@"addrspace",
7274 .zir_index = extra.zir_index,7289 .zir_index = extra.zir_index,
...@@ -7895,17 +7910,14 @@ pub fn get(ip: *InternPool, gpa: Allocator, tid: Zcu.PerThread.Id, key: Key) All...@@ -7895,17 +7910,14 @@ pub fn get(ip: *InternPool, gpa: Allocator, tid: Zcu.PerThread.Id, key: Key) All
7895 const has_init = variable.init != .none;7910 const has_init = variable.init != .none;
7896 if (has_init) assert(variable.ty == ip.typeOf(variable.init));7911 if (has_init) assert(variable.ty == ip.typeOf(variable.init));
7897 items.appendAssumeCapacity(.{7912 items.appendAssumeCapacity(.{
7898 .tag = .variable,7913 .tag = switch (variable.is_threadlocal) {
7914 false => .variable,
7915 true => .threadlocal_variable,
7916 },
7899 .data = try addExtra(extra, Tag.Variable{7917 .data = try addExtra(extra, Tag.Variable{
7900 .ty = variable.ty,7918 .ty = variable.ty,
7901 .init = variable.init,7919 .init = variable.init,
7902 .owner_nav = variable.owner_nav,7920 .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 },
7909 }),7921 }),
7910 });7922 });
7911 },7923 },
...@@ -9128,6 +9140,7 @@ pub fn getExtern(...@@ -9128,6 +9140,7 @@ pub fn getExtern(
9128 .name = key.name,9140 .name = key.name,
9129 .fqn = key.name,9141 .fqn = key.name,
9130 .val = extern_index,9142 .val = extern_index,
9143 .is_const = key.is_const,
9131 .alignment = key.alignment,9144 .alignment = key.alignment,
9132 .@"linksection" = .none,9145 .@"linksection" = .none,
9133 .@"addrspace" = key.@"addrspace",9146 .@"addrspace" = key.@"addrspace",
...@@ -9136,10 +9149,11 @@ pub fn getExtern(...@@ -9136,10 +9149,11 @@ pub fn getExtern(
9136 .ty = key.ty,9149 .ty = key.ty,
9137 .lib_name = key.lib_name,9150 .lib_name = key.lib_name,
9138 .flags = .{9151 .flags = .{
9139 .is_const = key.is_const,9152 .linkage = key.linkage,
9153 .visibility = key.visibility,
9140 .is_threadlocal = key.is_threadlocal,9154 .is_threadlocal = key.is_threadlocal,
9141 .is_weak_linkage = key.is_weak_linkage,
9142 .is_dll_import = key.is_dll_import,9155 .is_dll_import = key.is_dll_import,
9156 .relocation = key.relocation,
9143 },9157 },
9144 .zir_index = key.zir_index,9158 .zir_index = key.zir_index,
9145 .owner_nav = owner_nav,9159 .owner_nav = owner_nav,
...@@ -9714,6 +9728,7 @@ fn finishFuncInstance(...@@ -9714,6 +9728,7 @@ fn finishFuncInstance(
9714 .name = nav_name,9728 .name = nav_name,
9715 .fqn = try ip.namespacePtr(fn_namespace).internFullyQualifiedName(ip, gpa, tid, nav_name),9729 .fqn = try ip.namespacePtr(fn_namespace).internFullyQualifiedName(ip, gpa, tid, nav_name),
9716 .val = func_index,9730 .val = func_index,
9731 .is_const = fn_owner_nav.status.fully_resolved.is_const,
9717 .alignment = fn_owner_nav.status.fully_resolved.alignment,9732 .alignment = fn_owner_nav.status.fully_resolved.alignment,
9718 .@"linksection" = fn_owner_nav.status.fully_resolved.@"linksection",9733 .@"linksection" = fn_owner_nav.status.fully_resolved.@"linksection",
9719 .@"addrspace" = fn_owner_nav.status.fully_resolved.@"addrspace",9734 .@"addrspace" = fn_owner_nav.status.fully_resolved.@"addrspace",
...@@ -10300,13 +10315,13 @@ fn addExtraAssumeCapacity(extra: Local.Extra.Mutable, item: anytype) u32 {...@@ -10300,13 +10315,13 @@ fn addExtraAssumeCapacity(extra: Local.Extra.Mutable, item: anytype) u32 {
10300 u32,10315 u32,
10301 i32,10316 i32,
10302 FuncAnalysis,10317 FuncAnalysis,
10318 Tag.Extern.Flags,
10303 Tag.TypePointer.Flags,10319 Tag.TypePointer.Flags,
10304 Tag.TypeFunction.Flags,10320 Tag.TypeFunction.Flags,
10305 Tag.TypePointer.PackedOffset,10321 Tag.TypePointer.PackedOffset,
10306 Tag.TypeUnion.Flags,10322 Tag.TypeUnion.Flags,
10307 Tag.TypeStruct.Flags,10323 Tag.TypeStruct.Flags,
10308 Tag.TypeStructPacked.Flags,10324 Tag.TypeStructPacked.Flags,
10309 Tag.Variable.Flags,
10310 => @bitCast(@field(item, field.name)),10325 => @bitCast(@field(item, field.name)),
1031110326
10312 else => @compileError("bad field type: " ++ @typeName(field.type)),10327 else => @compileError("bad field type: " ++ @typeName(field.type)),
...@@ -10361,13 +10376,13 @@ fn extraDataTrail(extra: Local.Extra, comptime T: type, index: u32) struct { dat...@@ -10361,13 +10376,13 @@ fn extraDataTrail(extra: Local.Extra, comptime T: type, index: u32) struct { dat
1036110376
10362 u32,10377 u32,
10363 i32,10378 i32,
10379 Tag.Extern.Flags,
10364 Tag.TypePointer.Flags,10380 Tag.TypePointer.Flags,
10365 Tag.TypeFunction.Flags,10381 Tag.TypeFunction.Flags,
10366 Tag.TypePointer.PackedOffset,10382 Tag.TypePointer.PackedOffset,
10367 Tag.TypeUnion.Flags,10383 Tag.TypeUnion.Flags,
10368 Tag.TypeStruct.Flags,10384 Tag.TypeStruct.Flags,
10369 Tag.TypeStructPacked.Flags,10385 Tag.TypeStructPacked.Flags,
10370 Tag.Variable.Flags,
10371 FuncAnalysis,10386 FuncAnalysis,
10372 => @bitCast(extra_item),10387 => @bitCast(extra_item),
1037310388
...@@ -11162,7 +11177,7 @@ fn dumpStatsFallible(ip: *const InternPool, arena: Allocator) anyerror!void {...@@ -11162,7 +11177,7 @@ fn dumpStatsFallible(ip: *const InternPool, arena: Allocator) anyerror!void {
11162 .float_c_longdouble_f80 => @sizeOf(Float80),11177 .float_c_longdouble_f80 => @sizeOf(Float80),
11163 .float_c_longdouble_f128 => @sizeOf(Float128),11178 .float_c_longdouble_f128 => @sizeOf(Float128),
11164 .float_comptime_float => @sizeOf(Float128),11179 .float_comptime_float => @sizeOf(Float128),
11165 .variable => @sizeOf(Tag.Variable),11180 .variable, .threadlocal_variable => @sizeOf(Tag.Variable),
11166 .@"extern" => @sizeOf(Tag.Extern),11181 .@"extern" => @sizeOf(Tag.Extern),
11167 .func_decl => @sizeOf(Tag.FuncDecl),11182 .func_decl => @sizeOf(Tag.FuncDecl),
11168 .func_instance => b: {11183 .func_instance => b: {
...@@ -11282,6 +11297,7 @@ fn dumpAllFallible(ip: *const InternPool) anyerror!void {...@@ -11282,6 +11297,7 @@ fn dumpAllFallible(ip: *const InternPool) anyerror!void {
11282 .float_c_longdouble_f128,11297 .float_c_longdouble_f128,
11283 .float_comptime_float,11298 .float_comptime_float,
11284 .variable,11299 .variable,
11300 .threadlocal_variable,
11285 .@"extern",11301 .@"extern",
11286 .func_decl,11302 .func_decl,
11287 .func_instance,11303 .func_instance,
...@@ -11414,6 +11430,7 @@ pub fn createNav(...@@ -11414,6 +11430,7 @@ pub fn createNav(
11414 name: NullTerminatedString,11430 name: NullTerminatedString,
11415 fqn: NullTerminatedString,11431 fqn: NullTerminatedString,
11416 val: InternPool.Index,11432 val: InternPool.Index,
11433 is_const: bool,
11417 alignment: Alignment,11434 alignment: Alignment,
11418 @"linksection": OptionalNullTerminatedString,11435 @"linksection": OptionalNullTerminatedString,
11419 @"addrspace": std.builtin.AddressSpace,11436 @"addrspace": std.builtin.AddressSpace,
...@@ -11430,6 +11447,7 @@ pub fn createNav(...@@ -11430,6 +11447,7 @@ pub fn createNav(
11430 .analysis = null,11447 .analysis = null,
11431 .status = .{ .fully_resolved = .{11448 .status = .{ .fully_resolved = .{
11432 .val = opts.val,11449 .val = opts.val,
11450 .is_const = opts.is_const,
11433 .alignment = opts.alignment,11451 .alignment = opts.alignment,
11434 .@"linksection" = opts.@"linksection",11452 .@"linksection" = opts.@"linksection",
11435 .@"addrspace" = opts.@"addrspace",11453 .@"addrspace" = opts.@"addrspace",
...@@ -11482,10 +11500,10 @@ pub fn resolveNavType(...@@ -11482,10 +11500,10 @@ pub fn resolveNavType(
11482 nav: Nav.Index,11500 nav: Nav.Index,
11483 resolved: struct {11501 resolved: struct {
11484 type: InternPool.Index,11502 type: InternPool.Index,
11503 is_const: bool,
11485 alignment: Alignment,11504 alignment: Alignment,
11486 @"linksection": OptionalNullTerminatedString,11505 @"linksection": OptionalNullTerminatedString,
11487 @"addrspace": std.builtin.AddressSpace,11506 @"addrspace": std.builtin.AddressSpace,
11488 is_const: bool,
11489 is_threadlocal: bool,11507 is_threadlocal: bool,
11490 is_extern_decl: bool,11508 is_extern_decl: bool,
11491 },11509 },
...@@ -11512,9 +11530,9 @@ pub fn resolveNavType(...@@ -11512,9 +11530,9 @@ pub fn resolveNavType(
1151211530
11513 var bits = nav_bits[unwrapped.index];11531 var bits = nav_bits[unwrapped.index];
11514 bits.status = if (resolved.is_extern_decl) .type_resolved_extern_decl else .type_resolved;11532 bits.status = if (resolved.is_extern_decl) .type_resolved_extern_decl else .type_resolved;
11533 bits.is_const = resolved.is_const;
11515 bits.alignment = resolved.alignment;11534 bits.alignment = resolved.alignment;
11516 bits.@"addrspace" = resolved.@"addrspace";11535 bits.@"addrspace" = resolved.@"addrspace";
11517 bits.is_const = resolved.is_const;
11518 bits.is_threadlocal = resolved.is_threadlocal;11536 bits.is_threadlocal = resolved.is_threadlocal;
11519 @atomicStore(Nav.Repr.Bits, &nav_bits[unwrapped.index], bits, .release);11537 @atomicStore(Nav.Repr.Bits, &nav_bits[unwrapped.index], bits, .release);
11520}11538}
...@@ -11526,6 +11544,7 @@ pub fn resolveNavValue(...@@ -11526,6 +11544,7 @@ pub fn resolveNavValue(
11526 nav: Nav.Index,11544 nav: Nav.Index,
11527 resolved: struct {11545 resolved: struct {
11528 val: InternPool.Index,11546 val: InternPool.Index,
11547 is_const: bool,
11529 alignment: Alignment,11548 alignment: Alignment,
11530 @"linksection": OptionalNullTerminatedString,11549 @"linksection": OptionalNullTerminatedString,
11531 @"addrspace": std.builtin.AddressSpace,11550 @"addrspace": std.builtin.AddressSpace,
...@@ -11553,6 +11572,7 @@ pub fn resolveNavValue(...@@ -11553,6 +11572,7 @@ pub fn resolveNavValue(
1155311572
11554 var bits = nav_bits[unwrapped.index];11573 var bits = nav_bits[unwrapped.index];
11555 bits.status = .fully_resolved;11574 bits.status = .fully_resolved;
11575 bits.is_const = resolved.is_const;
11556 bits.alignment = resolved.alignment;11576 bits.alignment = resolved.alignment;
11557 bits.@"addrspace" = resolved.@"addrspace";11577 bits.@"addrspace" = resolved.@"addrspace";
11558 @atomicStore(Nav.Repr.Bits, &nav_bits[unwrapped.index], bits, .release);11578 @atomicStore(Nav.Repr.Bits, &nav_bits[unwrapped.index], bits, .release);
...@@ -12007,6 +12027,7 @@ pub fn typeOf(ip: *const InternPool, index: Index) Index {...@@ -12007,6 +12027,7 @@ pub fn typeOf(ip: *const InternPool, index: Index) Index {
12007 .error_union_error,12027 .error_union_error,
12008 .enum_tag,12028 .enum_tag,
12009 .variable,12029 .variable,
12030 .threadlocal_variable,
12010 .@"extern",12031 .@"extern",
12011 .func_decl,12032 .func_decl,
12012 .func_instance,12033 .func_instance,
...@@ -12391,6 +12412,7 @@ pub fn zigTypeTag(ip: *const InternPool, index: Index) std.builtin.TypeId {...@@ -12391,6 +12412,7 @@ pub fn zigTypeTag(ip: *const InternPool, index: Index) std.builtin.TypeId {
12391 .float_c_longdouble_f128,12412 .float_c_longdouble_f128,
12392 .float_comptime_float,12413 .float_comptime_float,
12393 .variable,12414 .variable,
12415 .threadlocal_variable,
12394 .@"extern",12416 .@"extern",
12395 .func_decl,12417 .func_decl,
12396 .func_instance,12418 .func_instance,
src/Sema.zig+42-11
...@@ -26089,10 +26089,12 @@ fn resolveExternOptions(...@@ -26089,10 +26089,12 @@ fn resolveExternOptions(
26089 zir_ref: Zir.Inst.Ref,26089 zir_ref: Zir.Inst.Ref,
26090) CompileError!struct {26090) CompileError!struct {
26091 name: InternPool.NullTerminatedString,26091 name: InternPool.NullTerminatedString,
26092 library_name: InternPool.OptionalNullTerminatedString = .none,26092 library_name: InternPool.OptionalNullTerminatedString,
26093 linkage: std.builtin.GlobalLinkage = .strong,26093 linkage: std.builtin.GlobalLinkage,
26094 is_thread_local: bool = false,26094 visibility: std.builtin.SymbolVisibility,
26095 is_dll_import: bool = false,26095 is_thread_local: bool,
26096 is_dll_import: bool,
26097 relocation: std.builtin.ExternOptions.Relocation,
26096} {26098} {
26097 const pt = sema.pt;26099 const pt = sema.pt;
26098 const zcu = pt.zcu;26100 const zcu = pt.zcu;
...@@ -26105,8 +26107,10 @@ fn resolveExternOptions(...@@ -26105,8 +26107,10 @@ fn resolveExternOptions(
26105 const name_src = block.src(.{ .init_field_name = src.offset.node_offset_builtin_call_arg.builtin_call_node });26107 const name_src = block.src(.{ .init_field_name = src.offset.node_offset_builtin_call_arg.builtin_call_node });
26106 const library_src = block.src(.{ .init_field_library = src.offset.node_offset_builtin_call_arg.builtin_call_node });26108 const library_src = block.src(.{ .init_field_library = src.offset.node_offset_builtin_call_arg.builtin_call_node });
26107 const linkage_src = block.src(.{ .init_field_linkage = src.offset.node_offset_builtin_call_arg.builtin_call_node });26109 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 });
26108 const thread_local_src = block.src(.{ .init_field_thread_local = src.offset.node_offset_builtin_call_arg.builtin_call_node });26111 const thread_local_src = block.src(.{ .init_field_thread_local = src.offset.node_offset_builtin_call_arg.builtin_call_node });
26109 const dll_import_src = block.src(.{ .init_field_dll_import = src.offset.node_offset_builtin_call_arg.builtin_call_node });26112 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
26111 const name_ref = try sema.fieldVal(block, src, options, try ip.getOrPutString(gpa, pt.tid, "name", .no_embedded_nulls), name_src);26115 const name_ref = try sema.fieldVal(block, src, options, try ip.getOrPutString(gpa, pt.tid, "name", .no_embedded_nulls), name_src);
26112 const name = try sema.toConstString(block, name_src, name_ref, .{ .simple = .extern_options });26116 const name = try sema.toConstString(block, name_src, name_ref, .{ .simple = .extern_options });
...@@ -26118,6 +26122,10 @@ fn resolveExternOptions(...@@ -26118,6 +26122,10 @@ fn resolveExternOptions(
26118 const linkage_val = try sema.resolveConstDefinedValue(block, linkage_src, linkage_ref, .{ .simple = .extern_options });26122 const linkage_val = try sema.resolveConstDefinedValue(block, linkage_src, linkage_ref, .{ .simple = .extern_options });
26119 const linkage = try sema.interpretBuiltinType(block, linkage_src, linkage_val, std.builtin.GlobalLinkage);26123 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
26121 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);26129 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);
26122 const is_thread_local_val = try sema.resolveConstDefinedValue(block, thread_local_src, is_thread_local, .{ .simple = .extern_options });26130 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(...@@ -26133,6 +26141,10 @@ fn resolveExternOptions(
26133 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);26141 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);
26134 const is_dll_import_val = try sema.resolveConstDefinedValue(block, dll_import_src, is_dll_import_ref, .{ .simple = .extern_options });26142 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
26136 if (name.len == 0) {26148 if (name.len == 0) {
26137 return sema.fail(block, name_src, "extern symbol name cannot be empty", .{});26149 return sema.fail(block, name_src, "extern symbol name cannot be empty", .{});
26138 }26150 }
...@@ -26145,8 +26157,10 @@ fn resolveExternOptions(...@@ -26145,8 +26157,10 @@ fn resolveExternOptions(
26145 .name = try ip.getOrPutString(gpa, pt.tid, name, .no_embedded_nulls),26157 .name = try ip.getOrPutString(gpa, pt.tid, name, .no_embedded_nulls),
26146 .library_name = try ip.getOrPutStringOpt(gpa, pt.tid, library_name, .no_embedded_nulls),26158 .library_name = try ip.getOrPutStringOpt(gpa, pt.tid, library_name, .no_embedded_nulls),
26147 .linkage = linkage,26159 .linkage = linkage,
26160 .visibility = visibility,
26148 .is_thread_local = is_thread_local_val.toBool(),26161 .is_thread_local = is_thread_local_val.toBool(),
26149 .is_dll_import = is_dll_import_val.toBool(),26162 .is_dll_import = is_dll_import_val.toBool(),
26163 .relocation = relocation,
26150 };26164 };
26151}26165}
2615226166
...@@ -26178,6 +26192,17 @@ fn zirBuiltinExtern(...@@ -26178,6 +26192,17 @@ fn zirBuiltinExtern(
26178 }26192 }
2617926193
26180 const options = try sema.resolveExternOptions(block, options_src, extra.rhs);26194 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
26182 // TODO: error for threadlocal functions, non-const functions, etc26207 // TODO: error for threadlocal functions, non-const functions, etc
2618326208
...@@ -26190,10 +26215,12 @@ fn zirBuiltinExtern(...@@ -26190,10 +26215,12 @@ fn zirBuiltinExtern(
26190 .name = options.name,26215 .name = options.name,
26191 .ty = ptr_info.child,26216 .ty = ptr_info.child,
26192 .lib_name = options.library_name,26217 .lib_name = options.library_name,
26193 .is_const = ptr_info.flags.is_const,26218 .linkage = options.linkage,
26219 .visibility = options.visibility,
26194 .is_threadlocal = options.is_thread_local,26220 .is_threadlocal = options.is_thread_local,
26195 .is_weak_linkage = options.linkage == .weak,
26196 .is_dll_import = options.is_dll_import,26221 .is_dll_import = options.is_dll_import,
26222 .relocation = options.relocation,
26223 .is_const = ptr_info.flags.is_const,
26197 .alignment = ptr_info.flags.alignment,26224 .alignment = ptr_info.flags.alignment,
26198 .@"addrspace" = ptr_info.flags.address_space,26225 .@"addrspace" = ptr_info.flags.address_space,
26199 // This instruction is just for source locations.26226 // This instruction is just for source locations.
...@@ -31685,12 +31712,15 @@ fn analyzeNavRefInner(sema: *Sema, block: *Block, src: LazySrcLoc, orig_nav_inde...@@ -31685,12 +31712,15 @@ fn analyzeNavRefInner(sema: *Sema, block: *Block, src: LazySrcLoc, orig_nav_inde
3168531712
31686 const nav_status = ip.getNav(nav_index).status;31713 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) {
31689 .unresolved => unreachable,31716 .unresolved => unreachable,
31690 // dllimports go straight to `fully_resolved`; the only option is threadlocal31717 // dllimports go straight to `fully_resolved`; the only option is threadlocal
31691 .type_resolved => |r| r.is_threadlocal,31718 .type_resolved => |r| r.is_threadlocal,
31692 .fully_resolved => |r| switch (ip.indexToKey(r.val)) {31719 .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 },
31694 .variable => |v| v.is_threadlocal,31724 .variable => |v| v.is_threadlocal,
31695 else => false,31725 else => false,
31696 },31726 },
...@@ -31699,7 +31729,7 @@ fn analyzeNavRefInner(sema: *Sema, block: *Block, src: LazySrcLoc, orig_nav_inde...@@ -31699,7 +31729,7 @@ fn analyzeNavRefInner(sema: *Sema, block: *Block, src: LazySrcLoc, orig_nav_inde
31699 const ty, const alignment, const @"addrspace", const is_const = switch (nav_status) {31729 const ty, const alignment, const @"addrspace", const is_const = switch (nav_status) {
31700 .unresolved => unreachable,31730 .unresolved => unreachable,
31701 .type_resolved => |r| .{ r.type, r.alignment, r.@"addrspace", r.is_const },31731 .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 },
31703 };31733 };
31704 const ptr_ty = try pt.ptrTypeSema(.{31734 const ptr_ty = try pt.ptrTypeSema(.{
31705 .child = ty,31735 .child = ty,
...@@ -31710,10 +31740,10 @@ fn analyzeNavRefInner(sema: *Sema, block: *Block, src: LazySrcLoc, orig_nav_inde...@@ -31710,10 +31740,10 @@ fn analyzeNavRefInner(sema: *Sema, block: *Block, src: LazySrcLoc, orig_nav_inde
31710 },31740 },
31711 });31741 });
3171231742
31713 if (is_tlv_or_dllimport) {31743 if (is_runtime) {
31714 // This pointer is runtime-known; we need to emit an AIR instruction to create it.31744 // This pointer is runtime-known; we need to emit an AIR instruction to create it.
31715 return block.addInst(.{31745 return block.addInst(.{
31716 .tag = .tlv_dllimport_ptr,31746 .tag = .runtime_nav_ptr,
31717 .data = .{ .ty_nav = .{31747 .data = .{ .ty_nav = .{
31718 .ty = ptr_ty.toIntern(),31748 .ty = ptr_ty.toIntern(),
31719 .nav = nav_index,31749 .nav = nav_index,
...@@ -36432,6 +36462,7 @@ pub fn typeHasOnePossibleValue(sema: *Sema, ty: Type) CompileError!?Value {...@@ -36432,6 +36462,7 @@ pub fn typeHasOnePossibleValue(sema: *Sema, ty: Type) CompileError!?Value {
36432 .float_c_longdouble_f128,36462 .float_c_longdouble_f128,
36433 .float_comptime_float,36463 .float_comptime_float,
36434 .variable,36464 .variable,
36465 .threadlocal_variable,
36435 .@"extern",36466 .@"extern",
36436 .func_decl,36467 .func_decl,
36437 .func_instance,36468 .func_instance,
src/Zcu.zig+3-9
...@@ -2047,6 +2047,7 @@ pub const SrcLoc = struct {...@@ -2047,6 +2047,7 @@ pub const SrcLoc = struct {
2047 .init_field_library,2047 .init_field_library,
2048 .init_field_thread_local,2048 .init_field_thread_local,
2049 .init_field_dll_import,2049 .init_field_dll_import,
2050 .init_field_relocation,
2050 => |builtin_call_node| {2051 => |builtin_call_node| {
2051 const wanted = switch (src_loc.lazy) {2052 const wanted = switch (src_loc.lazy) {
2052 .init_field_name => "name",2053 .init_field_name => "name",
...@@ -2059,6 +2060,7 @@ pub const SrcLoc = struct {...@@ -2059,6 +2060,7 @@ pub const SrcLoc = struct {
2059 .init_field_library => "library",2060 .init_field_library => "library",
2060 .init_field_thread_local => "thread_local",2061 .init_field_thread_local => "thread_local",
2061 .init_field_dll_import => "dll_import",2062 .init_field_dll_import => "dll_import",
2063 .init_field_relocation => "relocation",
2062 else => unreachable,2064 else => unreachable,
2063 };2065 };
2064 const tree = try src_loc.file_scope.getTree(zcu);2066 const tree = try src_loc.file_scope.getTree(zcu);
...@@ -2506,6 +2508,7 @@ pub const LazySrcLoc = struct {...@@ -2506,6 +2508,7 @@ pub const LazySrcLoc = struct {
2506 init_field_library: Ast.Node.Offset,2508 init_field_library: Ast.Node.Offset,
2507 init_field_thread_local: Ast.Node.Offset,2509 init_field_thread_local: Ast.Node.Offset,
2508 init_field_dll_import: Ast.Node.Offset,2510 init_field_dll_import: Ast.Node.Offset,
2511 init_field_relocation: Ast.Node.Offset,
2509 /// The source location points to the value of an item in a specific2512 /// The source location points to the value of an item in a specific
2510 /// case of a `switch`.2513 /// case of a `switch`.
2511 switch_case_item: SwitchItem,2514 switch_case_item: SwitchItem,
...@@ -4562,15 +4565,6 @@ pub fn callconvSupported(zcu: *Zcu, cc: std.builtin.CallingConvention) union(enu...@@ -4562,15 +4565,6 @@ pub fn callconvSupported(zcu: *Zcu, cc: std.builtin.CallingConvention) union(enu
4562 return .ok;4565 return .ok;
4563}4566}
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
4574pub const CodegenFailError = error{4568pub const CodegenFailError = error{
4575 /// Indicates the error message has been already stored at `Zcu.failed_codegen`.4569 /// Indicates the error message has been already stored at `Zcu.failed_codegen`.
4576 CodegenFail,4570 CodegenFail,
src/Zcu/PerThread.zig+29-21
...@@ -1153,18 +1153,23 @@ fn analyzeNavVal(pt: Zcu.PerThread, nav_id: InternPool.Nav.Index) Zcu.CompileErr...@@ -1153,18 +1153,23 @@ fn analyzeNavVal(pt: Zcu.PerThread, nav_id: InternPool.Nav.Index) Zcu.CompileErr
1153 // First, we must resolve the declaration's type. To do this, we analyze the type body if available,1153 // First, we must resolve the declaration's type. To do this, we analyze the type body if available,
1154 // or otherwise, we analyze the value body, populating `early_val` in the process.1154 // 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) {
1157 .@"comptime" => unreachable, // this is not a Nav1157 .@"comptime" => unreachable, // this is not a Nav
1158 .unnamed_test, .@"test", .decltest => assert(nav_ty.zigTypeTag(zcu) == .@"fn"),1158 .unnamed_test, .@"test", .decltest => {
1159 .@"usingnamespace" => {},1159 assert(nav_ty.zigTypeTag(zcu) == .@"fn");
1160 .@"const" => {},1160 break :is_const true;
1161 .@"var" => try sema.validateVarType(1161 },
1162 &block,1162 .@"usingnamespace", .@"const" => true,
1163 if (zir_decl.type_body != null) ty_src else init_src,1163 .@"var" => {
1164 nav_ty,1164 try sema.validateVarType(
1165 zir_decl.linkage == .@"extern",1165 &block,
1166 ),1166 if (zir_decl.type_body != null) ty_src else init_src,
1167 }1167 nav_ty,
1168 zir_decl.linkage == .@"extern",
1169 );
1170 break :is_const false;
1171 },
1172 };
11681173
1169 // Now that we know the type, we can evaluate the alignment, linksection, and addrspace, to determine1174 // Now that we know the type, we can evaluate the alignment, linksection, and addrspace, to determine
1170 // the full pointer type of this declaration.1175 // the full pointer type of this declaration.
...@@ -1195,7 +1200,6 @@ fn analyzeNavVal(pt: Zcu.PerThread, nav_id: InternPool.Nav.Index) Zcu.CompileErr...@@ -1195,7 +1200,6 @@ fn analyzeNavVal(pt: Zcu.PerThread, nav_id: InternPool.Nav.Index) Zcu.CompileErr
1195 .init = final_val.?.toIntern(),1200 .init = final_val.?.toIntern(),
1196 .owner_nav = nav_id,1201 .owner_nav = nav_id,
1197 .is_threadlocal = zir_decl.is_threadlocal,1202 .is_threadlocal = zir_decl.is_threadlocal,
1198 .is_weak_linkage = false,
1199 } })),1203 } })),
1200 else => final_val.?,1204 else => final_val.?,
1201 },1205 },
...@@ -1212,10 +1216,12 @@ fn analyzeNavVal(pt: Zcu.PerThread, nav_id: InternPool.Nav.Index) Zcu.CompileErr...@@ -1212,10 +1216,12 @@ fn analyzeNavVal(pt: Zcu.PerThread, nav_id: InternPool.Nav.Index) Zcu.CompileErr
1212 .name = old_nav.name,1216 .name = old_nav.name,
1213 .ty = nav_ty.toIntern(),1217 .ty = nav_ty.toIntern(),
1214 .lib_name = try ip.getOrPutStringOpt(gpa, pt.tid, lib_name, .no_embedded_nulls),1218 .lib_name = try ip.getOrPutStringOpt(gpa, pt.tid, lib_name, .no_embedded_nulls),
1215 .is_const = zir_decl.kind == .@"const",
1216 .is_threadlocal = zir_decl.is_threadlocal,1219 .is_threadlocal = zir_decl.is_threadlocal,
1217 .is_weak_linkage = false,1220 .linkage = .strong,
1221 .visibility = .default,
1218 .is_dll_import = false,1222 .is_dll_import = false,
1223 .relocation = .any,
1224 .is_const = is_const,
1219 .alignment = modifiers.alignment,1225 .alignment = modifiers.alignment,
1220 .@"addrspace" = modifiers.@"addrspace",1226 .@"addrspace" = modifiers.@"addrspace",
1221 .zir_index = old_nav.analysis.?.zir_index, // `declaration` instruction1227 .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...@@ -1243,6 +1249,7 @@ fn analyzeNavVal(pt: Zcu.PerThread, nav_id: InternPool.Nav.Index) Zcu.CompileErr
1243 }1249 }
1244 ip.resolveNavValue(nav_id, .{1250 ip.resolveNavValue(nav_id, .{
1245 .val = nav_val.toIntern(),1251 .val = nav_val.toIntern(),
1252 .is_const = is_const,
1246 .alignment = .none,1253 .alignment = .none,
1247 .@"linksection" = .none,1254 .@"linksection" = .none,
1248 .@"addrspace" = .generic,1255 .@"addrspace" = .generic,
...@@ -1286,6 +1293,7 @@ fn analyzeNavVal(pt: Zcu.PerThread, nav_id: InternPool.Nav.Index) Zcu.CompileErr...@@ -1286,6 +1293,7 @@ fn analyzeNavVal(pt: Zcu.PerThread, nav_id: InternPool.Nav.Index) Zcu.CompileErr
12861293
1287 ip.resolveNavValue(nav_id, .{1294 ip.resolveNavValue(nav_id, .{
1288 .val = nav_val.toIntern(),1295 .val = nav_val.toIntern(),
1296 .is_const = is_const,
1289 .alignment = modifiers.alignment,1297 .alignment = modifiers.alignment,
1290 .@"linksection" = modifiers.@"linksection",1298 .@"linksection" = modifiers.@"linksection",
1291 .@"addrspace" = modifiers.@"addrspace",1299 .@"addrspace" = modifiers.@"addrspace",
...@@ -1515,8 +1523,6 @@ fn analyzeNavType(pt: Zcu.PerThread, nav_id: InternPool.Nav.Index) Zcu.CompileEr...@@ -1515,8 +1523,6 @@ fn analyzeNavType(pt: Zcu.PerThread, nav_id: InternPool.Nav.Index) Zcu.CompileEr
1515 // the pointer modifiers, i.e. alignment, linksection, addrspace.1523 // the pointer modifiers, i.e. alignment, linksection, addrspace.
1516 const modifiers = try sema.resolveNavPtrModifiers(&block, zir_decl, inst_resolved.inst, resolved_ty);1524 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.
1520 const is_const = switch (zir_decl.kind) {1526 const is_const = switch (zir_decl.kind) {
1521 .@"comptime" => unreachable,1527 .@"comptime" => unreachable,
1522 .unnamed_test, .@"test", .decltest, .@"usingnamespace", .@"const" => true,1528 .unnamed_test, .@"test", .decltest, .@"usingnamespace", .@"const" => true,
...@@ -1542,7 +1548,7 @@ fn analyzeNavType(pt: Zcu.PerThread, nav_id: InternPool.Nav.Index) Zcu.CompileEr...@@ -1542,7 +1548,7 @@ fn analyzeNavType(pt: Zcu.PerThread, nav_id: InternPool.Nav.Index) Zcu.CompileEr
1542 r.alignment != modifiers.alignment or1548 r.alignment != modifiers.alignment or
1543 r.@"linksection" != modifiers.@"linksection" or1549 r.@"linksection" != modifiers.@"linksection" or
1544 r.@"addrspace" != modifiers.@"addrspace" or1550 r.@"addrspace" != modifiers.@"addrspace" or
1545 zcu.navValIsConst(r.val) != is_const or1551 r.is_const != is_const or
1546 (old_nav.getExtern(ip) != null) != is_extern_decl,1552 (old_nav.getExtern(ip) != null) != is_extern_decl,
1547 };1553 };
15481554
...@@ -1550,10 +1556,10 @@ fn analyzeNavType(pt: Zcu.PerThread, nav_id: InternPool.Nav.Index) Zcu.CompileEr...@@ -1550,10 +1556,10 @@ fn analyzeNavType(pt: Zcu.PerThread, nav_id: InternPool.Nav.Index) Zcu.CompileEr
15501556
1551 ip.resolveNavType(nav_id, .{1557 ip.resolveNavType(nav_id, .{
1552 .type = resolved_ty.toIntern(),1558 .type = resolved_ty.toIntern(),
1559 .is_const = is_const,
1553 .alignment = modifiers.alignment,1560 .alignment = modifiers.alignment,
1554 .@"linksection" = modifiers.@"linksection",1561 .@"linksection" = modifiers.@"linksection",
1555 .@"addrspace" = modifiers.@"addrspace",1562 .@"addrspace" = modifiers.@"addrspace",
1556 .is_const = is_const,
1557 .is_threadlocal = zir_decl.is_threadlocal,1563 .is_threadlocal = zir_decl.is_threadlocal,
1558 .is_extern_decl = is_extern_decl,1564 .is_extern_decl = is_extern_decl,
1559 });1565 });
...@@ -1750,7 +1756,7 @@ pub fn linkerUpdateFunc(pt: Zcu.PerThread, func_index: InternPool.Index, air: *A...@@ -1750,7 +1756,7 @@ pub fn linkerUpdateFunc(pt: Zcu.PerThread, func_index: InternPool.Index, air: *A
17501756
1751 if (build_options.enable_debug_extensions and comp.verbose_air) {1757 if (build_options.enable_debug_extensions and comp.verbose_air) {
1752 std.debug.print("# Begin Function AIR: {}:\n", .{nav.fqn.fmt(ip)});1758 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);
1754 std.debug.print("# End Function AIR: {}\n\n", .{nav.fqn.fmt(ip)});1760 std.debug.print("# End Function AIR: {}\n\n", .{nav.fqn.fmt(ip)});
1755 }1761 }
17561762
...@@ -3577,8 +3583,10 @@ pub fn getCoerced(pt: Zcu.PerThread, val: Value, new_ty: Type) Allocator.Error!V...@@ -3577,8 +3583,10 @@ pub fn getCoerced(pt: Zcu.PerThread, val: Value, new_ty: Type) Allocator.Error!V
3577 .lib_name = e.lib_name,3583 .lib_name = e.lib_name,
3578 .is_const = e.is_const,3584 .is_const = e.is_const,
3579 .is_threadlocal = e.is_threadlocal,3585 .is_threadlocal = e.is_threadlocal,
3580 .is_weak_linkage = e.is_weak_linkage,3586 .linkage = e.linkage,
3587 .visibility = e.visibility,
3581 .is_dll_import = e.is_dll_import,3588 .is_dll_import = e.is_dll_import,
3589 .relocation = e.relocation,
3582 .alignment = e.alignment,3590 .alignment = e.alignment,
3583 .@"addrspace" = e.@"addrspace",3591 .@"addrspace" = e.@"addrspace",
3584 .zir_index = e.zir_index,3592 .zir_index = e.zir_index,
...@@ -3954,7 +3962,7 @@ pub fn navPtrType(pt: Zcu.PerThread, nav_id: InternPool.Nav.Index) Allocator.Err...@@ -3954,7 +3962,7 @@ pub fn navPtrType(pt: Zcu.PerThread, nav_id: InternPool.Nav.Index) Allocator.Err
3954 const ty, const alignment, const @"addrspace", const is_const = switch (ip.getNav(nav_id).status) {3962 const ty, const alignment, const @"addrspace", const is_const = switch (ip.getNav(nav_id).status) {
3955 .unresolved => unreachable,3963 .unresolved => unreachable,
3956 .type_resolved => |r| .{ r.type, r.alignment, r.@"addrspace", r.is_const },3964 .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 },
3958 };3966 };
3959 return pt.ptrType(.{3967 return pt.ptrType(.{
3960 .child = ty,3968 .child = ty,
src/arch/aarch64/CodeGen.zig+1-1
...@@ -880,7 +880,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {...@@ -880,7 +880,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
880 .is_named_enum_value => return self.fail("TODO implement is_named_enum_value", .{}),880 .is_named_enum_value => return self.fail("TODO implement is_named_enum_value", .{}),
881 .error_set_has_value => return self.fail("TODO implement error_set_has_value", .{}),881 .error_set_has_value => return self.fail("TODO implement error_set_has_value", .{}),
882 .vector_store_elem => return self.fail("TODO implement vector_store_elem", .{}),882 .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
885 .c_va_arg => return self.fail("TODO implement c_va_arg", .{}),885 .c_va_arg => return self.fail("TODO implement c_va_arg", .{}),
886 .c_va_copy => return self.fail("TODO implement c_va_copy", .{}),886 .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 {...@@ -869,7 +869,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
869 .is_named_enum_value => return self.fail("TODO implement is_named_enum_value", .{}),869 .is_named_enum_value => return self.fail("TODO implement is_named_enum_value", .{}),
870 .error_set_has_value => return self.fail("TODO implement error_set_has_value", .{}),870 .error_set_has_value => return self.fail("TODO implement error_set_has_value", .{}),
871 .vector_store_elem => return self.fail("TODO implement vector_store_elem", .{}),871 .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
874 .c_va_arg => return self.fail("TODO implement c_va_arg", .{}),874 .c_va_arg => return self.fail("TODO implement c_va_arg", .{}),
875 .c_va_copy => return self.fail("TODO implement c_va_copy", .{}),875 .c_va_copy => return self.fail("TODO implement c_va_copy", .{}),
src/arch/riscv64/CodeGen.zig+4-9
...@@ -1041,12 +1041,7 @@ fn formatAir(...@@ -1041,12 +1041,7 @@ fn formatAir(
1041 _: std.fmt.FormatOptions,1041 _: std.fmt.FormatOptions,
1042 writer: anytype,1042 writer: anytype,
1043) @TypeOf(writer).Error!void {1043) @TypeOf(writer).Error!void {
1044 @import("../../print_air.zig").dumpInst(1044 data.func.air.dumpInst(data.inst, data.func.pt, data.func.liveness);
1045 data.inst,
1046 data.func.pt,
1047 data.func.air,
1048 data.func.liveness,
1049 );
1050}1045}
1051fn fmtAir(func: *Func, inst: Air.Inst.Index) std.fmt.Formatter(formatAir) {1046fn fmtAir(func: *Func, inst: Air.Inst.Index) std.fmt.Formatter(formatAir) {
1052 return .{ .data = .{ .func = func, .inst = inst } };1047 return .{ .data = .{ .func = func, .inst = inst } };
...@@ -1656,7 +1651,7 @@ fn genBody(func: *Func, body: []const Air.Inst.Index) InnerError!void {...@@ -1656,7 +1651,7 @@ fn genBody(func: *Func, body: []const Air.Inst.Index) InnerError!void {
1656 .wrap_errunion_payload => try func.airWrapErrUnionPayload(inst),1651 .wrap_errunion_payload => try func.airWrapErrUnionPayload(inst),
1657 .wrap_errunion_err => try func.airWrapErrUnionErr(inst),1652 .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
1661 .add_optimized,1656 .add_optimized,
1662 .sub_optimized,1657 .sub_optimized,
...@@ -3626,7 +3621,7 @@ fn airWrapErrUnionErr(func: *Func, inst: Air.Inst.Index) !void {...@@ -3626,7 +3621,7 @@ fn airWrapErrUnionErr(func: *Func, inst: Air.Inst.Index) !void {
3626 return func.finishAir(inst, result, .{ ty_op.operand, .none, .none });3621 return func.finishAir(inst, result, .{ ty_op.operand, .none, .none });
3627}3622}
36283623
3629fn airTlvDllimportPtr(func: *Func, inst: Air.Inst.Index) !void {3624fn airRuntimeNavPtr(func: *Func, inst: Air.Inst.Index) !void {
3630 const zcu = func.pt.zcu;3625 const zcu = func.pt.zcu;
3631 const ip = &zcu.intern_pool;3626 const ip = &zcu.intern_pool;
3632 const ty_nav = func.air.instructions.items(.data)[@intFromEnum(inst)].ty_nav;3627 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 {...@@ -3641,7 +3636,7 @@ fn airTlvDllimportPtr(func: *Func, inst: Air.Inst.Index) !void {
3641 break :sym sym;3636 break :sym sym;
3642 }3637 }
3643 break :sym try zo.getOrCreateMetadataForNav(zcu, ty_nav.nav);3638 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
3646 const dest_mcv = try func.allocRegOrMem(ptr_ty, inst, true);3641 const dest_mcv = try func.allocRegOrMem(ptr_ty, inst, true);
3647 if (dest_mcv.isRegister()) {3642 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 {...@@ -723,7 +723,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
723 .is_named_enum_value => @panic("TODO implement is_named_enum_value"),723 .is_named_enum_value => @panic("TODO implement is_named_enum_value"),
724 .error_set_has_value => @panic("TODO implement error_set_has_value"),724 .error_set_has_value => @panic("TODO implement error_set_has_value"),
725 .vector_store_elem => @panic("TODO implement vector_store_elem"),725 .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
728 .c_va_arg => return self.fail("TODO implement c_va_arg", .{}),728 .c_va_arg => return self.fail("TODO implement c_va_arg", .{}),
729 .c_va_copy => return self.fail("TODO implement c_va_copy", .{}),729 .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 {...@@ -2057,7 +2057,7 @@ fn genInst(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
2057 .error_set_has_value => cg.airErrorSetHasValue(inst),2057 .error_set_has_value => cg.airErrorSetHasValue(inst),
2058 .frame_addr => cg.airFrameAddress(inst),2058 .frame_addr => cg.airFrameAddress(inst),
20592059
2060 .tlv_dllimport_ptr => cg.airTlvDllimportPtr(inst),2060 .runtime_nav_ptr => cg.airRuntimeNavPtr(inst),
20612061
2062 .assembly,2062 .assembly,
2063 .is_err_ptr,2063 .is_err_ptr,
...@@ -7616,7 +7616,7 @@ fn airFrameAddress(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {...@@ -7616,7 +7616,7 @@ fn airFrameAddress(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
7616 return cg.finishAir(inst, .stack, &.{});7616 return cg.finishAir(inst, .stack, &.{});
7617}7617}
76187618
7619fn airTlvDllimportPtr(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {7619fn airRuntimeNavPtr(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
7620 const ty_nav = cg.air.instructions.items(.data)[@intFromEnum(inst)].ty_nav;7620 const ty_nav = cg.air.instructions.items(.data)[@intFromEnum(inst)].ty_nav;
7621 const mod = cg.pt.zcu.navFileScope(cg.owner_nav).mod.?;7621 const mod = cg.pt.zcu.navFileScope(cg.owner_nav).mod.?;
7622 if (mod.single_threaded) {7622 if (mod.single_threaded) {
src/arch/x86_64/CodeGen.zig+173-42
...@@ -274,6 +274,12 @@ pub const MCValue = union(enum) {...@@ -274,6 +274,12 @@ pub const MCValue = union(enum) {
274 load_symbol: bits.SymbolOffset,274 load_symbol: bits.SymbolOffset,
275 /// The address of the memory location not-yet-allocated by the linker.275 /// The address of the memory location not-yet-allocated by the linker.
276 lea_symbol: bits.SymbolOffset,276 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,
277 /// The value is in memory at a constant offset from the address in a register.283 /// The value is in memory at a constant offset from the address in a register.
278 indirect: bits.RegisterOffset,284 indirect: bits.RegisterOffset,
279 /// The value is in memory.285 /// The value is in memory.
...@@ -314,6 +320,7 @@ pub const MCValue = union(enum) {...@@ -314,6 +320,7 @@ pub const MCValue = union(enum) {
314 .eflags,320 .eflags,
315 .register_overflow,321 .register_overflow,
316 .lea_symbol,322 .lea_symbol,
323 .lea_pcrel,
317 .lea_direct,324 .lea_direct,
318 .lea_got,325 .lea_got,
319 .lea_frame,326 .lea_frame,
...@@ -327,6 +334,7 @@ pub const MCValue = union(enum) {...@@ -327,6 +334,7 @@ pub const MCValue = union(enum) {
327 .register_quadruple,334 .register_quadruple,
328 .memory,335 .memory,
329 .load_symbol,336 .load_symbol,
337 .load_pcrel,
330 .load_got,338 .load_got,
331 .load_direct,339 .load_direct,
332 .indirect,340 .indirect,
...@@ -429,6 +437,7 @@ pub const MCValue = union(enum) {...@@ -429,6 +437,7 @@ pub const MCValue = union(enum) {
429 .register_overflow,437 .register_overflow,
430 .register_mask,438 .register_mask,
431 .lea_symbol,439 .lea_symbol,
440 .lea_pcrel,
432 .lea_direct,441 .lea_direct,
433 .lea_got,442 .lea_got,
434 .lea_frame,443 .lea_frame,
...@@ -445,6 +454,7 @@ pub const MCValue = union(enum) {...@@ -445,6 +454,7 @@ pub const MCValue = union(enum) {
445 .load_got => |sym_index| .{ .lea_got = sym_index },454 .load_got => |sym_index| .{ .lea_got = sym_index },
446 .load_frame => |frame_addr| .{ .lea_frame = frame_addr },455 .load_frame => |frame_addr| .{ .lea_frame = frame_addr },
447 .load_symbol => |sym_off| .{ .lea_symbol = sym_off },456 .load_symbol => |sym_off| .{ .lea_symbol = sym_off },
457 .load_pcrel => |sym_off| .{ .lea_pcrel = sym_off },
448 };458 };
449 }459 }
450460
...@@ -466,6 +476,7 @@ pub const MCValue = union(enum) {...@@ -466,6 +476,7 @@ pub const MCValue = union(enum) {
466 .load_got,476 .load_got,
467 .load_frame,477 .load_frame,
468 .load_symbol,478 .load_symbol,
479 .load_pcrel,
469 .elementwise_args,480 .elementwise_args,
470 .reserved_frame,481 .reserved_frame,
471 .air_ref,482 .air_ref,
...@@ -477,6 +488,7 @@ pub const MCValue = union(enum) {...@@ -477,6 +488,7 @@ pub const MCValue = union(enum) {
477 .lea_got => |sym_index| .{ .load_got = sym_index },488 .lea_got => |sym_index| .{ .load_got = sym_index },
478 .lea_frame => |frame_addr| .{ .load_frame = frame_addr },489 .lea_frame => |frame_addr| .{ .load_frame = frame_addr },
479 .lea_symbol => |sym_index| .{ .load_symbol = sym_index },490 .lea_symbol => |sym_index| .{ .load_symbol = sym_index },
491 .lea_pcrel => |sym_index| .{ .load_pcrel = sym_index },
480 };492 };
481 }493 }
482494
...@@ -505,6 +517,8 @@ pub const MCValue = union(enum) {...@@ -505,6 +517,8 @@ pub const MCValue = union(enum) {
505 .load_frame,517 .load_frame,
506 .load_symbol,518 .load_symbol,
507 .lea_symbol,519 .lea_symbol,
520 .load_pcrel,
521 .lea_pcrel,
508 => switch (off) {522 => switch (off) {
509 0 => mcv,523 0 => mcv,
510 else => unreachable, // not offsettable524 else => unreachable, // not offsettable
...@@ -543,6 +557,7 @@ pub const MCValue = union(enum) {...@@ -543,6 +557,7 @@ pub const MCValue = union(enum) {
543 .elementwise_args,557 .elementwise_args,
544 .reserved_frame,558 .reserved_frame,
545 .lea_symbol,559 .lea_symbol,
560 .lea_pcrel,
546 => unreachable,561 => unreachable,
547 .memory => |addr| if (std.math.cast(i32, @as(i64, @bitCast(addr)))) |small_addr| .{562 .memory => |addr| if (std.math.cast(i32, @as(i64, @bitCast(addr)))) |small_addr| .{
548 .base = .{ .reg = .ds },563 .base = .{ .reg = .ds },
...@@ -583,6 +598,18 @@ pub const MCValue = union(enum) {...@@ -583,6 +598,18 @@ pub const MCValue = union(enum) {
583 } },598 } },
584 };599 };
585 },600 },
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 },
586 .air_ref => |ref| (try function.resolveInst(ref)).mem(function, mod_rm),613 .air_ref => |ref| (try function.resolveInst(ref)).mem(function, mod_rm),
587 };614 };
588 }615 }
...@@ -618,6 +645,8 @@ pub const MCValue = union(enum) {...@@ -618,6 +645,8 @@ pub const MCValue = union(enum) {
618 }),645 }),
619 .load_symbol => |pl| try writer.print("[sym:{} + 0x{x}]", .{ pl.sym_index, pl.off }),646 .load_symbol => |pl| try writer.print("[sym:{} + 0x{x}]", .{ pl.sym_index, pl.off }),
620 .lea_symbol => |pl| try writer.print("sym:{} + 0x{x}", .{ pl.sym_index, pl.off }),647 .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 }),
621 .indirect => |pl| try writer.print("[{s} + 0x{x}]", .{ @tagName(pl.reg), pl.off }),650 .indirect => |pl| try writer.print("[{s} + 0x{x}]", .{ @tagName(pl.reg), pl.off }),
622 .load_direct => |pl| try writer.print("[direct:{d}]", .{pl}),651 .load_direct => |pl| try writer.print("[direct:{d}]", .{pl}),
623 .lea_direct => |pl| try writer.print("direct:{d}", .{pl}),652 .lea_direct => |pl| try writer.print("direct:{d}", .{pl}),
...@@ -655,6 +684,8 @@ const InstTracking = struct {...@@ -655,6 +684,8 @@ const InstTracking = struct {
655 .lea_frame,684 .lea_frame,
656 .load_symbol,685 .load_symbol,
657 .lea_symbol,686 .lea_symbol,
687 .load_pcrel,
688 .lea_pcrel,
658 => result,689 => result,
659 .dead,690 .dead,
660 .elementwise_args,691 .elementwise_args,
...@@ -755,6 +786,8 @@ const InstTracking = struct {...@@ -755,6 +786,8 @@ const InstTracking = struct {
755 .lea_frame,786 .lea_frame,
756 .load_symbol,787 .load_symbol,
757 .lea_symbol,788 .lea_symbol,
789 .load_pcrel,
790 .lea_pcrel,
758 => assert(std.meta.eql(self.long, target.long)),791 => assert(std.meta.eql(self.long, target.long)),
759 .dead,792 .dead,
760 .eflags,793 .eflags,
...@@ -1228,12 +1261,7 @@ fn formatAir(...@@ -1228,12 +1261,7 @@ fn formatAir(
1228 _: std.fmt.FormatOptions,1261 _: std.fmt.FormatOptions,
1229 writer: anytype,1262 writer: anytype,
1230) @TypeOf(writer).Error!void {1263) @TypeOf(writer).Error!void {
1231 @import("../../print_air.zig").dumpInst(1264 data.self.air.dumpInst(data.inst, data.self.pt, data.self.liveness);
1232 data.inst,
1233 data.self.pt,
1234 data.self.air,
1235 data.self.liveness,
1236 );
1237}1265}
1238fn fmtAir(self: *CodeGen, inst: Air.Inst.Index) std.fmt.Formatter(formatAir) {1266fn fmtAir(self: *CodeGen, inst: Air.Inst.Index) std.fmt.Formatter(formatAir) {
1239 return .{ .data = .{ .self = self, .inst = inst } };1267 return .{ .data = .{ .self = self, .inst = inst } };
...@@ -163487,31 +163515,49 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {...@@ -163487,31 +163515,49 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {
163487 };163515 };
163488 for (ops) |op| try op.die(cg);163516 for (ops) |op| try op.die(cg);
163489 },163517 },
163490 .tlv_dllimport_ptr => switch (cg.bin_file.tag) {163518 .runtime_nav_ptr => switch (cg.bin_file.tag) {
163491 .elf, .macho => {163519 .elf, .macho => {
163492 const ty_nav = air_datas[@intFromEnum(inst)].ty_nav;163520 const ty_nav = air_datas[@intFromEnum(inst)].ty_nav;
163493163521
163494 const nav = ip.getNav(ty_nav.nav);163522 const nav = ip.getNav(ty_nav.nav);
163495 const tlv_sym_index = sym: {163523 const sym_index, const relocation = sym: {
163496 if (cg.bin_file.cast(.elf)) |elf_file| {163524 if (cg.bin_file.cast(.elf)) |elf_file| {
163497 const zo = elf_file.zigObjectPtr().?;163525 const zo = elf_file.zigObjectPtr().?;
163498 if (nav.getExtern(ip)) |e| {163526 if (nav.getExtern(ip)) |e| {
163499 const sym = try elf_file.getGlobalSymbol(nav.name.toSlice(ip), e.lib_name.toSlice(ip));163527 const sym = try elf_file.getGlobalSymbol(nav.name.toSlice(ip), e.lib_name.toSlice(ip));
163500 zo.symbol(sym).flags.is_extern_ptr = true;163528 linkage: switch (e.linkage) {
163501 break :sym sym;163529 .internal => {},
163502 }163530 .strong => switch (e.visibility) {
163503 break :sym try zo.getOrCreateMetadataForNav(zcu, ty_nav.nav);163531 .default => zo.symbol(sym).flags.is_extern_ptr = true,
163504 }163532 .hidden, .protected => {},
163505 if (cg.bin_file.cast(.macho)) |macho_file| {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| {
163506 const zo = macho_file.getZigObject().?;163543 const zo = macho_file.getZigObject().?;
163507 if (nav.getExtern(ip)) |e| {163544 if (nav.getExtern(ip)) |e| {
163508 const sym = try macho_file.getGlobalSymbol(nav.name.toSlice(ip), e.lib_name.toSlice(ip));163545 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;163546 linkage: switch (e.linkage) {
163510 break :sym sym;163547 .internal => {},
163511 }163548 .strong => switch (e.visibility) {
163512 break :sym try zo.getOrCreateMetadataForNav(macho_file, ty_nav.nav);163549 .default => zo.symbols.items[sym].flags.is_extern_ptr = true,
163513 }163550 .hidden, .protected => {},
163514 unreachable;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;
163515 };163561 };
163516163562
163517 if (cg.mod.pic) {163563 if (cg.mod.pic) {
...@@ -163520,13 +163566,14 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {...@@ -163520,13 +163566,14 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {
163520 try cg.spillRegisters(&.{.rax});163566 try cg.spillRegisters(&.{.rax});
163521 }163567 }
163522163568
163523 var slot = try cg.tempInit(.usize, .{ .lea_symbol = .{163569 var slot = try cg.tempInit(.usize, switch (relocation) {
163524 .sym_index = tlv_sym_index,163570 .any => .{ .lea_symbol = .{ .sym_index = sym_index } },
163525 } });163571 .pcrel => .{ .lea_pcrel = .{ .sym_index = sym_index } },
163572 });
163526 while (try slot.toRegClass(true, .general_purpose, cg)) {}163573 while (try slot.toRegClass(true, .general_purpose, cg)) {}
163527 try slot.finish(inst, &.{}, &.{}, cg);163574 try slot.finish(inst, &.{}, &.{}, cg);
163528 },163575 },
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}),
163530 },163577 },
163531 .c_va_arg => try cg.airVaArg(inst),163578 .c_va_arg => try cg.airVaArg(inst),
163532 .c_va_copy => try cg.airVaCopy(inst),163579 .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...@@ -169189,6 +169236,7 @@ fn load(self: *CodeGen, dst_mcv: MCValue, ptr_ty: Type, ptr_mcv: MCValue) InnerE
169189 .register,169236 .register,
169190 .register_offset,169237 .register_offset,
169191 .lea_symbol,169238 .lea_symbol,
169239 .lea_pcrel,
169192 .lea_direct,169240 .lea_direct,
169193 .lea_got,169241 .lea_got,
169194 .lea_frame,169242 .lea_frame,
...@@ -169196,6 +169244,7 @@ fn load(self: *CodeGen, dst_mcv: MCValue, ptr_ty: Type, ptr_mcv: MCValue) InnerE...@@ -169196,6 +169244,7 @@ fn load(self: *CodeGen, dst_mcv: MCValue, ptr_ty: Type, ptr_mcv: MCValue) InnerE
169196 .memory,169244 .memory,
169197 .indirect,169245 .indirect,
169198 .load_symbol,169246 .load_symbol,
169247 .load_pcrel,
169199 .load_direct,169248 .load_direct,
169200 .load_got,169249 .load_got,
169201 .load_frame,169250 .load_frame,
...@@ -169407,6 +169456,7 @@ fn store(...@@ -169407,6 +169456,7 @@ fn store(
169407 .register,169456 .register,
169408 .register_offset,169457 .register_offset,
169409 .lea_symbol,169458 .lea_symbol,
169459 .lea_pcrel,
169410 .lea_direct,169460 .lea_direct,
169411 .lea_got,169461 .lea_got,
169412 .lea_frame,169462 .lea_frame,
...@@ -169414,6 +169464,7 @@ fn store(...@@ -169414,6 +169464,7 @@ fn store(
169414 .memory,169464 .memory,
169415 .indirect,169465 .indirect,
169416 .load_symbol,169466 .load_symbol,
169467 .load_pcrel,
169417 .load_direct,169468 .load_direct,
169418 .load_got,169469 .load_got,
169419 .load_frame,169470 .load_frame,
...@@ -169883,6 +169934,7 @@ fn genUnOpMir(self: *CodeGen, mir_tag: Mir.Inst.FixedTag, dst_ty: Type, dst_mcv:...@@ -169883,6 +169934,7 @@ fn genUnOpMir(self: *CodeGen, mir_tag: Mir.Inst.FixedTag, dst_ty: Type, dst_mcv:
169883 .register_overflow,169934 .register_overflow,
169884 .register_mask,169935 .register_mask,
169885 .lea_symbol,169936 .lea_symbol,
169937 .lea_pcrel,
169886 .lea_direct,169938 .lea_direct,
169887 .lea_got,169939 .lea_got,
169888 .lea_frame,169940 .lea_frame,
...@@ -169892,7 +169944,7 @@ fn genUnOpMir(self: *CodeGen, mir_tag: Mir.Inst.FixedTag, dst_ty: Type, dst_mcv:...@@ -169892,7 +169944,7 @@ fn genUnOpMir(self: *CodeGen, mir_tag: Mir.Inst.FixedTag, dst_ty: Type, dst_mcv:
169892 => unreachable, // unmodifiable destination169944 => unreachable, // unmodifiable destination
169893 .register => |dst_reg| try self.asmRegister(mir_tag, registerAlias(dst_reg, abi_size)),169945 .register => |dst_reg| try self.asmRegister(mir_tag, registerAlias(dst_reg, abi_size)),
169894 .register_pair, .register_triple, .register_quadruple => unreachable, // unimplemented169946 .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 => {
169896 const addr_reg = try self.register_manager.allocReg(null, abi.RegisterClass.gp);169948 const addr_reg = try self.register_manager.allocReg(null, abi.RegisterClass.gp);
169897 const addr_reg_lock = self.register_manager.lockRegAssumeUnused(addr_reg);169949 const addr_reg_lock = self.register_manager.lockRegAssumeUnused(addr_reg);
169898 defer self.register_manager.unlockReg(addr_reg_lock);169950 defer self.register_manager.unlockReg(addr_reg_lock);
...@@ -171552,6 +171604,8 @@ fn genBinOp(...@@ -171552,6 +171604,8 @@ fn genBinOp(
171552 .register_mask,171604 .register_mask,
171553 .load_symbol,171605 .load_symbol,
171554 .lea_symbol,171606 .lea_symbol,
171607 .load_pcrel,
171608 .lea_pcrel,
171555 .load_direct,171609 .load_direct,
171556 .lea_direct,171610 .lea_direct,
171557 .load_got,171611 .load_got,
...@@ -172740,6 +172794,7 @@ fn genBinOpMir(...@@ -172740,6 +172794,7 @@ fn genBinOpMir(
172740 .lea_got,172794 .lea_got,
172741 .lea_frame,172795 .lea_frame,
172742 .lea_symbol,172796 .lea_symbol,
172797 .lea_pcrel,
172743 .elementwise_args,172798 .elementwise_args,
172744 .reserved_frame,172799 .reserved_frame,
172745 .air_ref,172800 .air_ref,
...@@ -172831,6 +172886,8 @@ fn genBinOpMir(...@@ -172831,6 +172886,8 @@ fn genBinOpMir(
172831 .indirect,172886 .indirect,
172832 .load_symbol,172887 .load_symbol,
172833 .lea_symbol,172888 .lea_symbol,
172889 .load_pcrel,
172890 .lea_pcrel,
172834 .load_direct,172891 .load_direct,
172835 .lea_direct,172892 .lea_direct,
172836 .load_got,172893 .load_got,
...@@ -172906,7 +172963,7 @@ fn genBinOpMir(...@@ -172906,7 +172963,7 @@ fn genBinOpMir(
172906 }172963 }
172907 }172964 }
172908 },172965 },
172909 .memory, .indirect, .load_symbol, .load_got, .load_direct, .load_frame => {172966 .memory, .indirect, .load_symbol, .load_pcrel, .load_got, .load_direct, .load_frame => {
172910 const OpInfo = ?struct { addr_reg: Register, addr_lock: RegisterLock };172967 const OpInfo = ?struct { addr_reg: Register, addr_lock: RegisterLock };
172911 const limb_abi_size: u32 = @min(abi_size, 8);172968 const limb_abi_size: u32 = @min(abi_size, 8);
172912172969
...@@ -172953,8 +173010,9 @@ fn genBinOpMir(...@@ -172953,8 +173010,9 @@ fn genBinOpMir(
172953 .load_frame,173010 .load_frame,
172954 .lea_frame,173011 .lea_frame,
172955 .lea_symbol,173012 .lea_symbol,
173013 .lea_pcrel,
172956 => null,173014 => null,
172957 .memory, .load_symbol, .load_got, .load_direct => src: {173015 .memory, .load_symbol, .load_pcrel, .load_got, .load_direct => src: {
172958 switch (resolved_src_mcv) {173016 switch (resolved_src_mcv) {
172959 .memory => |addr| if (std.math.cast(i32, @as(i64, @bitCast(addr))) != null and173017 .memory => |addr| if (std.math.cast(i32, @as(i64, @bitCast(addr))) != null and
172960 std.math.cast(i32, @as(i64, @bitCast(addr)) + abi_size - limb_abi_size) != null)173018 std.math.cast(i32, @as(i64, @bitCast(addr)) + abi_size - limb_abi_size) != null)
...@@ -173093,6 +173151,8 @@ fn genBinOpMir(...@@ -173093,6 +173151,8 @@ fn genBinOpMir(
173093 .indirect,173151 .indirect,
173094 .load_symbol,173152 .load_symbol,
173095 .lea_symbol,173153 .lea_symbol,
173154 .load_pcrel,
173155 .lea_pcrel,
173096 .load_direct,173156 .load_direct,
173097 .lea_direct,173157 .lea_direct,
173098 .load_got,173158 .load_got,
...@@ -173160,6 +173220,7 @@ fn genIntMulComplexOpMir(self: *CodeGen, dst_ty: Type, dst_mcv: MCValue, src_mcv...@@ -173160,6 +173220,7 @@ fn genIntMulComplexOpMir(self: *CodeGen, dst_ty: Type, dst_mcv: MCValue, src_mcv
173160 .register_overflow,173220 .register_overflow,
173161 .register_mask,173221 .register_mask,
173162 .lea_symbol,173222 .lea_symbol,
173223 .lea_pcrel,
173163 .lea_direct,173224 .lea_direct,
173164 .lea_got,173225 .lea_got,
173165 .lea_frame,173226 .lea_frame,
...@@ -173222,6 +173283,8 @@ fn genIntMulComplexOpMir(self: *CodeGen, dst_ty: Type, dst_mcv: MCValue, src_mcv...@@ -173222,6 +173283,8 @@ fn genIntMulComplexOpMir(self: *CodeGen, dst_ty: Type, dst_mcv: MCValue, src_mcv
173222 .eflags,173283 .eflags,
173223 .load_symbol,173284 .load_symbol,
173224 .lea_symbol,173285 .lea_symbol,
173286 .load_pcrel,
173287 .lea_pcrel,
173225 .load_direct,173288 .load_direct,
173226 .lea_direct,173289 .lea_direct,
173227 .load_got,173290 .load_got,
...@@ -173281,7 +173344,7 @@ fn genIntMulComplexOpMir(self: *CodeGen, dst_ty: Type, dst_mcv: MCValue, src_mcv...@@ -173281,7 +173344,7 @@ fn genIntMulComplexOpMir(self: *CodeGen, dst_ty: Type, dst_mcv: MCValue, src_mcv
173281 }173344 }
173282 },173345 },
173283 .register_pair, .register_triple, .register_quadruple => unreachable, // unimplemented173346 .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 => {
173285 const tmp_reg = try self.copyToTmpRegister(dst_ty, dst_mcv);173348 const tmp_reg = try self.copyToTmpRegister(dst_ty, dst_mcv);
173286 const tmp_mcv = MCValue{ .register = tmp_reg };173349 const tmp_mcv = MCValue{ .register = tmp_reg };
173287 const tmp_lock = self.register_manager.lockRegAssumeUnused(tmp_reg);173350 const tmp_lock = self.register_manager.lockRegAssumeUnused(tmp_reg);
...@@ -173450,7 +173513,8 @@ fn genLocalDebugInfo(...@@ -173450,7 +173513,8 @@ fn genLocalDebugInfo(
173450 .disp = frame_addr.off,173513 .disp = frame_addr.off,
173451 } },173514 } },
173452 }),173515 }),
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, .{
173454 .base = .{ .reloc = sym_off.sym_index },173518 .base = .{ .reloc = sym_off.sym_index },
173455 .mod = .{ .rm = .{173519 .mod = .{ .rm = .{
173456 .size = .qword,173520 .size = .qword,
...@@ -174108,12 +174172,13 @@ fn airCmp(self: *CodeGen, inst: Air.Inst.Index, op: std.math.CompareOperator) !v...@@ -174108,12 +174172,13 @@ fn airCmp(self: *CodeGen, inst: Air.Inst.Index, op: std.math.CompareOperator) !v
174108 .lea_got,174172 .lea_got,
174109 .lea_frame,174173 .lea_frame,
174110 .lea_symbol,174174 .lea_symbol,
174175 .lea_pcrel,
174111 .elementwise_args,174176 .elementwise_args,
174112 .reserved_frame,174177 .reserved_frame,
174113 .air_ref,174178 .air_ref,
174114 => unreachable,174179 => unreachable,
174115 .register, .register_pair, .register_triple, .register_quadruple, .load_frame => null,174180 .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: {
174117 switch (resolved_dst_mcv) {174182 switch (resolved_dst_mcv) {
174118 .memory => |addr| if (std.math.cast(174183 .memory => |addr| if (std.math.cast(
174119 i32,174184 i32,
...@@ -174122,7 +174187,7 @@ fn airCmp(self: *CodeGen, inst: Air.Inst.Index, op: std.math.CompareOperator) !v...@@ -174122,7 +174187,7 @@ fn airCmp(self: *CodeGen, inst: Air.Inst.Index, op: std.math.CompareOperator) !v
174122 i32,174187 i32,
174123 @as(i64, @bitCast(addr)) + abi_size - 8,174188 @as(i64, @bitCast(addr)) + abi_size - 8,
174124 ) != null) break :dst null,174189 ) != null) break :dst null,
174125 .load_symbol, .load_got, .load_direct => {},174190 .load_symbol, .load_pcrel, .load_got, .load_direct => {},
174126 else => unreachable,174191 else => unreachable,
174127 }174192 }
174128174193
...@@ -174160,6 +174225,7 @@ fn airCmp(self: *CodeGen, inst: Air.Inst.Index, op: std.math.CompareOperator) !v...@@ -174160,6 +174225,7 @@ fn airCmp(self: *CodeGen, inst: Air.Inst.Index, op: std.math.CompareOperator) !v
174160 .register_mask,174225 .register_mask,
174161 .indirect,174226 .indirect,
174162 .lea_symbol,174227 .lea_symbol,
174228 .lea_pcrel,
174163 .lea_direct,174229 .lea_direct,
174164 .lea_got,174230 .lea_got,
174165 .lea_frame,174231 .lea_frame,
...@@ -174168,7 +174234,7 @@ fn airCmp(self: *CodeGen, inst: Air.Inst.Index, op: std.math.CompareOperator) !v...@@ -174168,7 +174234,7 @@ fn airCmp(self: *CodeGen, inst: Air.Inst.Index, op: std.math.CompareOperator) !v
174168 .air_ref,174234 .air_ref,
174169 => unreachable,174235 => unreachable,
174170 .register_pair, .register_triple, .register_quadruple, .load_frame => null,174236 .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: {
174172 switch (resolved_src_mcv) {174238 switch (resolved_src_mcv) {
174173 .memory => |addr| if (std.math.cast(174239 .memory => |addr| if (std.math.cast(
174174 i32,174240 i32,
...@@ -174177,7 +174243,7 @@ fn airCmp(self: *CodeGen, inst: Air.Inst.Index, op: std.math.CompareOperator) !v...@@ -174177,7 +174243,7 @@ fn airCmp(self: *CodeGen, inst: Air.Inst.Index, op: std.math.CompareOperator) !v
174177 i32,174243 i32,
174178 @as(i64, @bitCast(addr)) + abi_size - 8,174244 @as(i64, @bitCast(addr)) + abi_size - 8,
174179 ) != null) break :src null,174245 ) != null) break :src null,
174180 .load_symbol, .load_got, .load_direct => {},174246 .load_symbol, .load_pcrel, .load_got, .load_direct => {},
174181 else => unreachable,174247 else => unreachable,
174182 }174248 }
174183174249
...@@ -174568,6 +174634,7 @@ fn isNull(self: *CodeGen, inst: Air.Inst.Index, opt_ty: Type, opt_mcv: MCValue)...@@ -174568,6 +174634,7 @@ fn isNull(self: *CodeGen, inst: Air.Inst.Index, opt_ty: Type, opt_mcv: MCValue)
174568 .lea_direct,174634 .lea_direct,
174569 .lea_got,174635 .lea_got,
174570 .lea_symbol,174636 .lea_symbol,
174637 .lea_pcrel,
174571 .elementwise_args,174638 .elementwise_args,
174572 .reserved_frame,174639 .reserved_frame,
174573 .air_ref,174640 .air_ref,
...@@ -174616,6 +174683,7 @@ fn isNull(self: *CodeGen, inst: Air.Inst.Index, opt_ty: Type, opt_mcv: MCValue)...@@ -174616,6 +174683,7 @@ fn isNull(self: *CodeGen, inst: Air.Inst.Index, opt_ty: Type, opt_mcv: MCValue)
174616174683
174617 .memory,174684 .memory,
174618 .load_symbol,174685 .load_symbol,
174686 .load_pcrel,
174619 .load_got,174687 .load_got,
174620 .load_direct,174688 .load_direct,
174621 => {174689 => {
...@@ -176625,6 +176693,7 @@ fn genCopy(self: *CodeGen, ty: Type, dst_mcv: MCValue, src_mcv: MCValue, opts: C...@@ -176625,6 +176693,7 @@ fn genCopy(self: *CodeGen, ty: Type, dst_mcv: MCValue, src_mcv: MCValue, opts: C
176625 .lea_got,176693 .lea_got,
176626 .lea_frame,176694 .lea_frame,
176627 .lea_symbol,176695 .lea_symbol,
176696 .lea_pcrel,
176628 .elementwise_args,176697 .elementwise_args,
176629 .reserved_frame,176698 .reserved_frame,
176630 .air_ref,176699 .air_ref,
...@@ -176719,7 +176788,7 @@ fn genCopy(self: *CodeGen, ty: Type, dst_mcv: MCValue, src_mcv: MCValue, opts: C...@@ -176719,7 +176788,7 @@ fn genCopy(self: *CodeGen, ty: Type, dst_mcv: MCValue, src_mcv: MCValue, opts: C
176719 }176788 }
176720 return;176789 return;
176721 },176790 },
176722 .load_symbol, .load_direct, .load_got => {176791 .load_symbol, .load_pcrel, .load_direct, .load_got => {
176723 const src_addr_reg =176792 const src_addr_reg =
176724 (try self.register_manager.allocReg(null, abi.RegisterClass.gp)).to64();176793 (try self.register_manager.allocReg(null, abi.RegisterClass.gp)).to64();
176725 const src_addr_lock = self.register_manager.lockRegAssumeUnused(src_addr_reg);176794 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...@@ -176752,7 +176821,7 @@ fn genCopy(self: *CodeGen, ty: Type, dst_mcv: MCValue, src_mcv: MCValue, opts: C
176752 .undef => if (opts.safety and part_i > 0) .{ .register = dst_regs[0] } else .undef,176821 .undef => if (opts.safety and part_i > 0) .{ .register = dst_regs[0] } else .undef,
176753 dst_tag => |src_regs| .{ .register = src_regs[part_i] },176822 dst_tag => |src_regs| .{ .register = src_regs[part_i] },
176754 .memory, .indirect, .load_frame => src_mcv.address().offset(part_disp).deref(),176823 .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 = .{
176756 .reg = src_info.?.addr_reg,176825 .reg = src_info.?.addr_reg,
176757 .off = part_disp,176826 .off = part_disp,
176758 } },176827 } },
...@@ -176773,11 +176842,11 @@ fn genCopy(self: *CodeGen, ty: Type, dst_mcv: MCValue, src_mcv: MCValue, opts: C...@@ -176773,11 +176842,11 @@ fn genCopy(self: *CodeGen, ty: Type, dst_mcv: MCValue, src_mcv: MCValue, opts: C
176773 src_mcv,176842 src_mcv,
176774 opts,176843 opts,
176775 ),176844 ),
176776 .memory, .load_symbol, .load_direct, .load_got => {176845 .memory, .load_symbol, .load_pcrel, .load_direct, .load_got => {
176777 switch (dst_mcv) {176846 switch (dst_mcv) {
176778 .memory => |addr| if (std.math.cast(i32, @as(i64, @bitCast(addr)))) |small_addr|176847 .memory => |addr| if (std.math.cast(i32, @as(i64, @bitCast(addr)))) |small_addr|
176779 return self.genSetMem(.{ .reg = .ds }, small_addr, ty, src_mcv, opts),176848 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 => {},
176781 else => unreachable,176850 else => unreachable,
176782 }176851 }
176783176852
...@@ -177234,7 +177303,7 @@ fn genSetReg(...@@ -177234,7 +177303,7 @@ fn genSetReg(
177234 if (src_reg_mask.info.inverted) try self.asmRegister(.{ ._, .not }, registerAlias(bits_reg, abi_size));177303 if (src_reg_mask.info.inverted) try self.asmRegister(.{ ._, .not }, registerAlias(bits_reg, abi_size));
177235 try self.genSetReg(dst_reg, ty, .{ .register = bits_reg }, .{});177304 try self.genSetReg(dst_reg, ty, .{ .register = bits_reg }, .{});
177236 },177305 },
177237 .memory, .load_symbol, .load_direct, .load_got => {177306 .memory, .load_symbol, .load_pcrel, .load_direct, .load_got => {
177238 switch (src_mcv) {177307 switch (src_mcv) {
177239 .memory => |addr| if (std.math.cast(i32, @as(i64, @bitCast(addr)))) |small_addr|177308 .memory => |addr| if (std.math.cast(i32, @as(i64, @bitCast(addr)))) |small_addr|
177240 return (try self.moveStrategy(177309 return (try self.moveStrategy(
...@@ -177263,6 +177332,21 @@ fn genSetReg(...@@ -177263,6 +177332,21 @@ fn genSetReg(
177263 .segment, .mmx, .ip, .cr, .dr => unreachable,177332 .segment, .mmx, .ip, .cr, .dr => unreachable,
177264 .x87, .sse => {},177333 .x87, .sse => {},
177265 },177334 },
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 },
177266 .load_direct => |sym_index| switch (dst_reg.class()) {177350 .load_direct => |sym_index| switch (dst_reg.class()) {
177267 .general_purpose, .gphi => {177351 .general_purpose, .gphi => {
177268 _ = try self.addInst(.{177352 _ = try self.addInst(.{
...@@ -177313,6 +177397,28 @@ fn genSetReg(...@@ -177313,6 +177397,28 @@ fn genSetReg(
177313 @tagName(self.bin_file.tag),177397 @tagName(self.bin_file.tag),
177314 }),177398 }),
177315 },177399 },
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 },
177316 .lea_direct, .lea_got => |sym_index| _ = try self.addInst(.{177422 .lea_direct, .lea_got => |sym_index| _ = try self.addInst(.{
177317 .tag = switch (src_mcv) {177423 .tag = switch (src_mcv) {
177318 .lea_direct => .lea,177424 .lea_direct => .lea,
...@@ -177350,6 +177456,7 @@ fn genSetMem(...@@ -177350,6 +177456,7 @@ fn genSetMem(
177350 .frame => |base_frame_index| .{ .lea_frame = .{ .index = base_frame_index, .off = disp } },177456 .frame => |base_frame_index| .{ .lea_frame = .{ .index = base_frame_index, .off = disp } },
177351 .table, .rip_inst => unreachable,177457 .table, .rip_inst => unreachable,
177352 .reloc => |sym_index| .{ .lea_symbol = .{ .sym_index = sym_index, .off = disp } },177458 .reloc => |sym_index| .{ .lea_symbol = .{ .sym_index = sym_index, .off = disp } },
177459 .pcrel => |sym_index| .{ .lea_pcrel = .{ .sym_index = sym_index, .off = disp } },
177353 };177460 };
177354 switch (src_mcv) {177461 switch (src_mcv) {
177355 .none,177462 .none,
...@@ -177466,7 +177573,7 @@ fn genSetMem(...@@ -177466,7 +177573,7 @@ fn genSetMem(
177466 .off = disp,177573 .off = disp,
177467 }).compare(.gte, src_align),177574 }).compare(.gte, src_align),
177468 .table, .rip_inst => unreachable,177575 .table, .rip_inst => unreachable,
177469 .reloc => false,177576 .reloc, .pcrel => false,
177470 })).write(177577 })).write(
177471 self,177578 self,
177472 .{ .base = base, .mod = .{ .rm = .{177579 .{ .base = base, .mod = .{ .rm = .{
...@@ -177557,6 +177664,8 @@ fn genSetMem(...@@ -177557,6 +177664,8 @@ fn genSetMem(
177557 .lea_frame,177664 .lea_frame,
177558 .load_symbol,177665 .load_symbol,
177559 .lea_symbol,177666 .lea_symbol,
177667 .load_pcrel,
177668 .lea_pcrel,
177560 => switch (abi_size) {177669 => switch (abi_size) {
177561 0 => {},177670 0 => {},
177562 1, 2, 4, 8 => {177671 1, 2, 4, 8 => {
...@@ -178110,7 +178219,7 @@ fn airCmpxchg(self: *CodeGen, inst: Air.Inst.Index) !void {...@@ -178110,7 +178219,7 @@ fn airCmpxchg(self: *CodeGen, inst: Air.Inst.Index) !void {
178110 .off => return self.fail("TODO airCmpxchg with {s}", .{@tagName(ptr_mcv)}),178219 .off => return self.fail("TODO airCmpxchg with {s}", .{@tagName(ptr_mcv)}),
178111 }178220 }
178112 const ptr_lock = switch (ptr_mem.base) {178221 const ptr_lock = switch (ptr_mem.base) {
178113 .none, .frame, .reloc => null,178222 .none, .frame, .reloc, .pcrel => null,
178114 .reg => |reg| self.register_manager.lockReg(reg),178223 .reg => |reg| self.register_manager.lockReg(reg),
178115 .table, .rip_inst => unreachable,178224 .table, .rip_inst => unreachable,
178116 };178225 };
...@@ -178193,7 +178302,7 @@ fn atomicOp(...@@ -178193,7 +178302,7 @@ fn atomicOp(
178193 .off => return self.fail("TODO airCmpxchg with {s}", .{@tagName(ptr_mcv)}),178302 .off => return self.fail("TODO airCmpxchg with {s}", .{@tagName(ptr_mcv)}),
178194 }178303 }
178195 const mem_lock = switch (ptr_mem.base) {178304 const mem_lock = switch (ptr_mem.base) {
178196 .none, .frame, .reloc => null,178305 .none, .frame, .reloc, .pcrel => null,
178197 .reg => |reg| self.register_manager.lockReg(reg),178306 .reg => |reg| self.register_manager.lockReg(reg),
178198 .table, .rip_inst => unreachable,178307 .table, .rip_inst => unreachable,
178199 };178308 };
...@@ -182266,6 +182375,8 @@ const Temp = struct {...@@ -182266,6 +182375,8 @@ const Temp = struct {
182266 .memory,182375 .memory,
182267 .load_symbol,182376 .load_symbol,
182268 .lea_symbol,182377 .lea_symbol,
182378 .load_pcrel,
182379 .lea_pcrel,
182269 .indirect,182380 .indirect,
182270 .load_direct,182381 .load_direct,
182271 .lea_direct,182382 .lea_direct,
...@@ -182427,6 +182538,22 @@ const Temp = struct {...@@ -182427,6 +182538,22 @@ const Temp = struct {
182427 assert(limb_index == 0);182538 assert(limb_index == 0);
182428 new_temp_index.tracking(cg).* = .init(.{ .lea_symbol = sym_off });182539 new_temp_index.tracking(cg).* = .init(.{ .lea_symbol = sym_off });
182429 },182540 },
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 },
182430 .load_frame => |frame_addr| {182557 .load_frame => |frame_addr| {
182431 const new_reg =182558 const new_reg =
182432 try cg.register_manager.allocReg(new_temp_index.toIndex(), abi.RegisterClass.gp);182559 try cg.register_manager.allocReg(new_temp_index.toIndex(), abi.RegisterClass.gp);
...@@ -182721,11 +182848,12 @@ const Temp = struct {...@@ -182721,11 +182848,12 @@ const Temp = struct {
182721 .memory,182848 .memory,
182722 .indirect,182849 .indirect,
182723 .load_symbol,182850 .load_symbol,
182851 .load_pcrel,
182724 .load_direct,182852 .load_direct,
182725 .load_got,182853 .load_got,
182726 .load_frame,182854 .load_frame,
182727 => return temp.toRegClass(true, .general_purpose, cg),182855 => return temp.toRegClass(true, .general_purpose, cg),
182728 .lea_symbol => |sym_off| {182856 .lea_symbol, .lea_pcrel => |sym_off| {
182729 const off = sym_off.off;182857 const off = sym_off.off;
182730 // hack around linker relocation bugs182858 // hack around linker relocation bugs
182731 if (false and off == 0) return false;182859 if (false and off == 0) return false;
...@@ -187464,6 +187592,8 @@ const Temp = struct {...@@ -187464,6 +187592,8 @@ const Temp = struct {
187464 .memory,187592 .memory,
187465 .load_symbol,187593 .load_symbol,
187466 .lea_symbol,187594 .lea_symbol,
187595 .load_pcrel,
187596 .lea_pcrel,
187467 .indirect,187597 .indirect,
187468 .load_direct,187598 .load_direct,
187469 .lea_direct,187599 .lea_direct,
...@@ -190044,6 +190174,7 @@ const Select = struct {...@@ -190044,6 +190174,7 @@ const Select = struct {
190044 .register => |base_reg| .{ .reg = base_reg.toSize(.ptr, s.cg.target) },190174 .register => |base_reg| .{ .reg = base_reg.toSize(.ptr, s.cg.target) },
190045 .register_offset => |base_reg_off| .{ .reg = base_reg_off.reg.toSize(.ptr, s.cg.target) },190175 .register_offset => |base_reg_off| .{ .reg = base_reg_off.reg.toSize(.ptr, s.cg.target) },
190046 .lea_symbol => |base_sym_off| .{ .reloc = base_sym_off.sym_index },190176 .lea_symbol => |base_sym_off| .{ .reloc = base_sym_off.sym_index },
190177 .lea_pcrel => |base_sym_off| .{ .pcrel = base_sym_off.sym_index },
190047 },190178 },
190048 .mod = .{ .rm = .{190179 .mod = .{ .rm = .{
190049 .size = op.flags.base.size,190180 .size = op.flags.base.size,
src/arch/x86_64/Emit.zig+4-3
...@@ -189,12 +189,12 @@ pub fn emitMir(emit: *Emit) Error!void {...@@ -189,12 +189,12 @@ pub fn emitMir(emit: *Emit) Error!void {
189 .r_addend = lowered_relocs[0].off,189 .r_addend = lowered_relocs[0].off,
190 }, zo);190 }, zo);
191 },191 },
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| {
193 const zo = elf_file.zigObjectPtr().?;193 const zo = elf_file.zigObjectPtr().?;
194 const atom = zo.symbol(emit.atom_index).atom(elf_file).?;194 const atom = zo.symbol(emit.atom_index).atom(elf_file).?;
195 const sym = zo.symbol(sym_index);195 const sym = zo.symbol(sym_index);
196 if (emit.lower.pic) {196 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)
198 @intFromEnum(std.elf.R_X86_64.GOTPCREL)198 @intFromEnum(std.elf.R_X86_64.GOTPCREL)
199 else199 else
200 @intFromEnum(std.elf.R_X86_64.PC32);200 @intFromEnum(std.elf.R_X86_64.PC32);
...@@ -218,7 +218,7 @@ pub fn emitMir(emit: *Emit) Error!void {...@@ -218,7 +218,7 @@ pub fn emitMir(emit: *Emit) Error!void {
218 const zo = macho_file.getZigObject().?;218 const zo = macho_file.getZigObject().?;
219 const atom = zo.symbols.items[emit.atom_index].getAtom(macho_file).?;219 const atom = zo.symbols.items[emit.atom_index].getAtom(macho_file).?;
220 const sym = &zo.symbols.items[sym_index];220 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)
222 .got_load222 .got_load
223 else if (sym.flags.tlv)223 else if (sym.flags.tlv)
224 .tlv224 .tlv
...@@ -438,6 +438,7 @@ pub fn emitMir(emit: *Emit) Error!void {...@@ -438,6 +438,7 @@ pub fn emitMir(emit: *Emit) Error!void {
438 .reg => |reg| .{ .breg = reg.dwarfNum() },438 .reg => |reg| .{ .breg = reg.dwarfNum() },
439 .frame, .table, .rip_inst => unreachable,439 .frame, .table, .rip_inst => unreachable,
440 .reloc => |sym_index| .{ .addr_reloc = sym_index },440 .reloc => |sym_index| .{ .addr_reloc = sym_index },
441 .pcrel => unreachable,
441 };442 };
442 break :base &loc_buf[0];443 break :base &loc_buf[0];
443 },444 },
src/arch/x86_64/Lower.zig+19-2
...@@ -66,6 +66,7 @@ pub const Reloc = struct {...@@ -66,6 +66,7 @@ pub const Reloc = struct {
66 inst: Mir.Inst.Index,66 inst: Mir.Inst.Index,
67 table,67 table,
68 linker_reloc: u32,68 linker_reloc: u32,
69 linker_pcrel: u32,
69 linker_tlsld: u32,70 linker_tlsld: u32,
70 linker_dtpoff: u32,71 linker_dtpoff: u32,
71 linker_extern_fn: u32,72 linker_extern_fn: u32,
...@@ -421,9 +422,9 @@ fn emit(lower: *Lower, prefix: Prefix, mnemonic: Mnemonic, ops: []const Operand)...@@ -421,9 +422,9 @@ fn emit(lower: *Lower, prefix: Prefix, mnemonic: Mnemonic, ops: []const Operand)
421 for (emit_ops, ops, 0..) |*emit_op, op, op_index| {422 for (emit_ops, ops, 0..) |*emit_op, op, op_index| {
422 emit_op.* = switch (op) {423 emit_op.* = switch (op) {
423 else => op,424 else => op,
424 .mem => |mem_op| switch (mem_op.base()) {425 .mem => |mem_op| op: switch (mem_op.base()) {
425 else => op,426 else => op,
426 .reloc => |sym_index| op: {427 .reloc => |sym_index| {
427 assert(prefix == .none);428 assert(prefix == .none);
428 assert(mem_op.sib.disp == 0);429 assert(mem_op.sib.disp == 0);
429 assert(mem_op.sib.scale_index.scale == 0);430 assert(mem_op.sib.scale_index.scale == 0);
...@@ -559,6 +560,22 @@ fn emit(lower: *Lower, prefix: Prefix, mnemonic: Mnemonic, ops: []const Operand)...@@ -559,6 +560,22 @@ fn emit(lower: *Lower, prefix: Prefix, mnemonic: Mnemonic, ops: []const Operand)
559 return lower.fail("TODO: bin format '{s}'", .{@tagName(lower.bin_file.tag)});560 return lower.fail("TODO: bin format '{s}'", .{@tagName(lower.bin_file.tag)});
560 }561 }
561 },562 },
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 },
562 },579 },
563 };580 };
564 }581 }
src/arch/x86_64/Mir.zig+3-2
...@@ -1866,7 +1866,7 @@ pub const Memory = struct {...@@ -1866,7 +1866,7 @@ pub const Memory = struct {
1866 .none, .table => undefined,1866 .none, .table => undefined,
1867 .reg => |reg| @intFromEnum(reg),1867 .reg => |reg| @intFromEnum(reg),
1868 .frame => |frame_index| @intFromEnum(frame_index),1868 .frame => |frame_index| @intFromEnum(frame_index),
1869 .reloc => |sym_index| sym_index,1869 .reloc, .pcrel => |sym_index| sym_index,
1870 .rip_inst => |inst_index| inst_index,1870 .rip_inst => |inst_index| inst_index,
1871 },1871 },
1872 .off = switch (mem.mod) {1872 .off = switch (mem.mod) {
...@@ -1895,6 +1895,7 @@ pub const Memory = struct {...@@ -1895,6 +1895,7 @@ pub const Memory = struct {
1895 .frame => .{ .frame = @enumFromInt(mem.base) },1895 .frame => .{ .frame = @enumFromInt(mem.base) },
1896 .table => .table,1896 .table => .table,
1897 .reloc => .{ .reloc = mem.base },1897 .reloc => .{ .reloc = mem.base },
1898 .pcrel => .{ .pcrel = mem.base },
1898 .rip_inst => .{ .rip_inst = mem.base },1899 .rip_inst => .{ .rip_inst = mem.base },
1899 },1900 },
1900 .scale_index = switch (mem.info.index) {1901 .scale_index = switch (mem.info.index) {
...@@ -1959,7 +1960,7 @@ pub fn resolveFrameAddr(mir: Mir, frame_addr: bits.FrameAddr) bits.RegisterOffse...@@ -1959,7 +1960,7 @@ pub fn resolveFrameAddr(mir: Mir, frame_addr: bits.FrameAddr) bits.RegisterOffse
19591960
1960pub fn resolveFrameLoc(mir: Mir, mem: Memory) Memory {1961pub fn resolveFrameLoc(mir: Mir, mem: Memory) Memory {
1961 return switch (mem.info.base) {1962 return switch (mem.info.base) {
1962 .none, .reg, .table, .reloc, .rip_inst => mem,1963 .none, .reg, .table, .reloc, .pcrel, .rip_inst => mem,
1963 .frame => if (mir.frame_locs.len > 0) .{1964 .frame => if (mir.frame_locs.len > 0) .{
1964 .info = .{1965 .info = .{
1965 .base = .reg,1966 .base = .reg,
src/arch/x86_64/bits.zig+1
...@@ -762,6 +762,7 @@ pub const Memory = struct {...@@ -762,6 +762,7 @@ pub const Memory = struct {
762 frame: FrameIndex,762 frame: FrameIndex,
763 table,763 table,
764 reloc: u32,764 reloc: u32,
765 pcrel: u32,
765 rip_inst: Mir.Inst.Index,766 rip_inst: Mir.Inst.Index,
766767
767 pub const Tag = @typeInfo(Base).@"union".tag_type.?;768 pub const Tag = @typeInfo(Base).@"union".tag_type.?;
src/arch/x86_64/encoder.zig+4-3
...@@ -138,7 +138,7 @@ pub const Instruction = struct {...@@ -138,7 +138,7 @@ pub const Instruction = struct {
138 .moffs => true,138 .moffs => true,
139 .rip => false,139 .rip => false,
140 .sib => |s| switch (s.base) {140 .sib => |s| switch (s.base) {
141 .none, .frame, .table, .reloc, .rip_inst => false,141 .none, .frame, .table, .reloc, .pcrel, .rip_inst => false,
142 .reg => |reg| reg.isClass(.segment),142 .reg => |reg| reg.isClass(.segment),
143 },143 },
144 };144 };
...@@ -211,7 +211,7 @@ pub const Instruction = struct {...@@ -211,7 +211,7 @@ pub const Instruction = struct {
211 .none, .imm => 0b00,211 .none, .imm => 0b00,
212 .reg => |reg| @truncate(reg.enc() >> 3),212 .reg => |reg| @truncate(reg.enc() >> 3),
213 .mem => |mem| switch (mem.base()) {213 .mem => |mem| switch (mem.base()) {
214 .none, .frame, .table, .reloc, .rip_inst => 0b00, // rsp, rbp, and rip are not extended214 .none, .frame, .table, .reloc, .pcrel, .rip_inst => 0b00, // rsp, rbp, and rip are not extended
215 .reg => |reg| @truncate(reg.enc() >> 3),215 .reg => |reg| @truncate(reg.enc() >> 3),
216 },216 },
217 .bytes => unreachable,217 .bytes => unreachable,
...@@ -282,6 +282,7 @@ pub const Instruction = struct {...@@ -282,6 +282,7 @@ pub const Instruction = struct {
282 .frame => |frame_index| try writer.print("{}", .{frame_index}),282 .frame => |frame_index| try writer.print("{}", .{frame_index}),
283 .table => try writer.print("Table", .{}),283 .table => try writer.print("Table", .{}),
284 .reloc => |sym_index| try writer.print("Symbol({d})", .{sym_index}),284 .reloc => |sym_index| try writer.print("Symbol({d})", .{sym_index}),
285 .pcrel => |sym_index| try writer.print("PcRelSymbol({d})", .{sym_index}),
285 .rip_inst => |inst_index| try writer.print("RipInst({d})", .{inst_index}),286 .rip_inst => |inst_index| try writer.print("RipInst({d})", .{inst_index}),
286 }287 }
287 if (mem.scaleIndex()) |si| {288 if (mem.scaleIndex()) |si| {
...@@ -721,7 +722,7 @@ pub const Instruction = struct {...@@ -721,7 +722,7 @@ pub const Instruction = struct {
721 try encoder.modRm_indirectDisp32(operand_enc, 0);722 try encoder.modRm_indirectDisp32(operand_enc, 0);
722 try encoder.disp32(undefined);723 try encoder.disp32(undefined);
723 } else return error.CannotEncode,724 } else return error.CannotEncode,
724 .rip_inst => {725 .pcrel, .rip_inst => {
725 try encoder.modRm_RIPDisp32(operand_enc);726 try encoder.modRm_RIPDisp32(operand_enc);
726 try encoder.disp32(sib.disp);727 try encoder.disp32(sib.disp);
727 },728 },
src/codegen.zig+57-24
...@@ -921,41 +921,74 @@ fn genNavRef(...@@ -921,41 +921,74 @@ fn genNavRef(
921 const nav = ip.getNav(nav_index);921 const nav = ip.getNav(nav_index);
922 assert(!nav.isThreadlocal(ip));922 assert(!nav.isThreadlocal(ip));
923923
924 const is_extern, const lib_name = if (nav.getExtern(ip)) |e|924 const lib_name, const linkage, const visibility = if (nav.getExtern(ip)) |e|
925 .{ true, e.lib_name }925 .{ e.lib_name, e.linkage, e.visibility }
926 else926 else
927 .{ false, .none };927 .{ .none, .internal, .default };
928928
929 const name = nav.name;929 const name = nav.name;
930 if (lf.cast(.elf)) |elf_file| {930 if (lf.cast(.elf)) |elf_file| {
931 const zo = elf_file.zigObjectPtr().?;931 const zo = elf_file.zigObjectPtr().?;
932 if (is_extern) {932 switch (linkage) {
933 const sym_index = try elf_file.getGlobalSymbol(name.toSlice(ip), lib_name.toSlice(ip));933 .internal => {
934 zo.symbol(sym_index).flags.is_extern_ptr = true;934 const sym_index = try zo.getOrCreateMetadataForNav(zcu, nav_index);
935 return .{ .mcv = .{ .lea_symbol = sym_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,
936 }952 }
937 const sym_index = try zo.getOrCreateMetadataForNav(zcu, nav_index);
938 return .{ .mcv = .{ .lea_symbol = sym_index } };
939 } else if (lf.cast(.macho)) |macho_file| {953 } else if (lf.cast(.macho)) |macho_file| {
940 const zo = macho_file.getZigObject().?;954 const zo = macho_file.getZigObject().?;
941 if (is_extern) {955 switch (linkage) {
942 const sym_index = try macho_file.getGlobalSymbol(name.toSlice(ip), lib_name.toSlice(ip));956 .internal => {
943 zo.symbols.items[sym_index].flags.is_extern_ptr = true;957 const sym_index = try zo.getOrCreateMetadataForNav(macho_file, nav_index);
944 return .{ .mcv = .{ .lea_symbol = sym_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,
945 }976 }
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 } };
949 } else if (lf.cast(.coff)) |coff_file| {977 } else if (lf.cast(.coff)) |coff_file| {
950 if (is_extern) {978 // TODO audit this
951 // TODO audit this979 switch (linkage) {
952 const global_index = try coff_file.getGlobalSymbol(name.toSlice(ip), lib_name.toSlice(ip));980 .internal => {
953 try coff_file.need_got_table.put(gpa, global_index, {}); // needs GOT981 const atom_index = try coff_file.getOrCreateAtomForNav(nav_index);
954 return .{ .mcv = .{ .load_got = link.File.Coff.global_symbol_bit | global_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,
955 }991 }
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 } };
959 } else if (lf.cast(.plan9)) |p9| {992 } else if (lf.cast(.plan9)) |p9| {
960 const atom_index = try p9.seeNav(pt, nav_index);993 const atom_index = try p9.seeNav(pt, nav_index);
961 const atom = p9.getAtom(atom_index);994 const atom = p9.getAtom(atom_index);
src/codegen/c.zig+22-12
...@@ -2255,19 +2255,30 @@ pub const DeclGen = struct {...@@ -2255,19 +2255,30 @@ pub const DeclGen = struct {
2255 fn renderFwdDecl(2255 fn renderFwdDecl(
2256 dg: *DeclGen,2256 dg: *DeclGen,
2257 nav_index: InternPool.Nav.Index,2257 nav_index: InternPool.Nav.Index,
2258 flags: struct {2258 flags: packed struct {
2259 is_extern: bool,
2260 is_const: bool,2259 is_const: bool,
2261 is_threadlocal: bool,2260 is_threadlocal: bool,
2262 is_weak_linkage: bool,2261 linkage: std.builtin.GlobalLinkage,
2262 visibility: std.builtin.SymbolVisibility,
2263 },2263 },
2264 ) !void {2264 ) !void {
2265 const zcu = dg.pt.zcu;2265 const zcu = dg.pt.zcu;
2266 const ip = &zcu.intern_pool;2266 const ip = &zcu.intern_pool;
2267 const nav = ip.getNav(nav_index);2267 const nav = ip.getNav(nav_index);
2268 const fwd = dg.fwdDeclWriter();2268 const fwd = dg.fwdDeclWriter();
2269 try fwd.writeAll(if (flags.is_extern) "zig_extern " else "static ");2269 try fwd.writeAll(switch (flags.linkage) {
2270 if (flags.is_weak_linkage) try fwd.writeAll("zig_weak_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 }
2271 if (flags.is_threadlocal and !dg.mod.single_threaded) try fwd.writeAll("zig_threadlocal ");2282 if (flags.is_threadlocal and !dg.mod.single_threaded) try fwd.writeAll("zig_threadlocal ");
2272 try dg.renderTypeAndName(2283 try dg.renderTypeAndName(
2273 fwd,2284 fwd,
...@@ -2994,10 +3005,10 @@ pub fn genDecl(o: *Object) !void {...@@ -2994,10 +3005,10 @@ pub fn genDecl(o: *Object) !void {
2994 switch (ip.indexToKey(nav.status.fully_resolved.val)) {3005 switch (ip.indexToKey(nav.status.fully_resolved.val)) {
2995 .@"extern" => |@"extern"| {3006 .@"extern" => |@"extern"| {
2996 if (!ip.isFunctionType(nav_ty.toIntern())) return o.dg.renderFwdDecl(o.dg.pass.nav, .{3007 if (!ip.isFunctionType(nav_ty.toIntern())) return o.dg.renderFwdDecl(o.dg.pass.nav, .{
2997 .is_extern = true,
2998 .is_const = @"extern".is_const,3008 .is_const = @"extern".is_const,
2999 .is_threadlocal = @"extern".is_threadlocal,3009 .is_threadlocal = @"extern".is_threadlocal,
3000 .is_weak_linkage = @"extern".is_weak_linkage,3010 .linkage = @"extern".linkage,
3011 .visibility = @"extern".visibility,
3001 });3012 });
30023013
3003 const fwd = o.dg.fwdDeclWriter();3014 const fwd = o.dg.fwdDeclWriter();
...@@ -3016,13 +3027,12 @@ pub fn genDecl(o: *Object) !void {...@@ -3016,13 +3027,12 @@ pub fn genDecl(o: *Object) !void {
3016 },3027 },
3017 .variable => |variable| {3028 .variable => |variable| {
3018 try o.dg.renderFwdDecl(o.dg.pass.nav, .{3029 try o.dg.renderFwdDecl(o.dg.pass.nav, .{
3019 .is_extern = false,
3020 .is_const = false,3030 .is_const = false,
3021 .is_threadlocal = variable.is_threadlocal,3031 .is_threadlocal = variable.is_threadlocal,
3022 .is_weak_linkage = variable.is_weak_linkage,3032 .linkage = .internal,
3033 .visibility = .default,
3023 });3034 });
3024 const w = o.writer();3035 const w = o.writer();
3025 if (variable.is_weak_linkage) try w.writeAll("zig_weak_linkage ");
3026 if (variable.is_threadlocal and !o.dg.mod.single_threaded) try w.writeAll("zig_threadlocal ");3036 if (variable.is_threadlocal and !o.dg.mod.single_threaded) try w.writeAll("zig_threadlocal ");
3027 if (nav.status.fully_resolved.@"linksection".toSlice(&zcu.intern_pool)) |s|3037 if (nav.status.fully_resolved.@"linksection".toSlice(&zcu.intern_pool)) |s|
3028 try w.print("zig_linksection({s}) ", .{fmtStringLiteral(s, null)});3038 try w.print("zig_linksection({s}) ", .{fmtStringLiteral(s, null)});
...@@ -3467,7 +3477,7 @@ fn genBodyInner(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail,...@@ -3467,7 +3477,7 @@ fn genBodyInner(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail,
3467 .error_set_has_value => return f.fail("TODO: C backend: implement error_set_has_value", .{}),3477 .error_set_has_value => return f.fail("TODO: C backend: implement error_set_has_value", .{}),
3468 .vector_store_elem => return f.fail("TODO: C backend: implement vector_store_elem", .{}),3478 .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
3472 .c_va_start => try airCVaStart(f, inst),3482 .c_va_start => try airCVaStart(f, inst),
3473 .c_va_arg => try airCVaArg(f, inst),3483 .c_va_arg => try airCVaArg(f, inst),
...@@ -7672,7 +7682,7 @@ fn airMulAdd(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -7672,7 +7682,7 @@ fn airMulAdd(f: *Function, inst: Air.Inst.Index) !CValue {
7672 return local;7682 return local;
7673}7683}
76747684
7675fn airTlvDllimportPtr(f: *Function, inst: Air.Inst.Index) !CValue {7685fn airRuntimeNavPtr(f: *Function, inst: Air.Inst.Index) !CValue {
7676 const ty_nav = f.air.instructions.items(.data)[@intFromEnum(inst)].ty_nav;7686 const ty_nav = f.air.instructions.items(.data)[@intFromEnum(inst)].ty_nav;
7677 const writer = f.object.writer();7687 const writer = f.object.writer();
7678 const local = try f.allocLocal(inst, .fromInterned(ty_nav.ty));7688 const local = try f.allocLocal(inst, .fromInterned(ty_nav.ty));
src/codegen/llvm.zig+73-50
...@@ -2979,36 +2979,49 @@ pub const Object = struct {...@@ -2979,36 +2979,49 @@ pub const Object = struct {
2979 const zcu = pt.zcu;2979 const zcu = pt.zcu;
2980 const ip = &zcu.intern_pool;2980 const ip = &zcu.intern_pool;
2981 const nav = ip.getNav(nav_index);2981 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) {
2983 .unresolved => unreachable,2983 .unresolved => unreachable,
2984 .fully_resolved => |r| switch (ip.indexToKey(r.val)) {2984 .fully_resolved => |r| switch (ip.indexToKey(r.val)) {
2985 .variable => |variable| .{ false, variable.is_threadlocal, variable.is_weak_linkage, false },2985 .variable => |variable| .{ .internal, .default, variable.is_threadlocal, false },
2986 .@"extern" => |@"extern"| .{ true, @"extern".is_threadlocal, @"extern".is_weak_linkage, @"extern".is_dll_import },2986 .@"extern" => |@"extern"| .{ @"extern".linkage, .fromSymbolVisibility(@"extern".visibility), @"extern".is_threadlocal, @"extern".is_dll_import },
2987 else => .{ false, false, false, false },2987 else => .{ .internal, .default, false, false },
2988 },2988 },
2989 // This means it's a source declaration which is not `extern`!2989 // 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 },
2991 };2991 };
29922992
2993 const variable_index = try o.builder.addVariable(2993 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)),
2995 try o.lowerType(Type.fromInterned(nav.typeOf(ip))),2999 try o.lowerType(Type.fromInterned(nav.typeOf(ip))),
2996 toLlvmGlobalAddressSpace(nav.getAddrspace(), zcu.getTarget()),3000 toLlvmGlobalAddressSpace(nav.getAddrspace(), zcu.getTarget()),
2997 );3001 );
2998 gop.value_ptr.* = variable_index.ptrConst(&o.builder).global;3002 gop.value_ptr.* = variable_index.ptrConst(&o.builder).global;
29993003
3000 // This is needed for declarations created by `@extern`.3004 // This is needed for declarations created by `@extern`.
3001 if (is_extern) {3005 switch (linkage) {
3002 variable_index.setLinkage(.external, &o.builder);3006 .internal => {
3003 variable_index.setUnnamedAddr(.default, &o.builder);3007 variable_index.setLinkage(.internal, &o.builder);
3004 if (is_threadlocal and !zcu.navFileScope(nav_index).mod.?.single_threaded)3008 variable_index.setUnnamedAddr(.unnamed_addr, &o.builder);
3005 variable_index.setThreadLocal(.generaldynamic, &o.builder);3009 },
3006 if (is_weak_linkage) variable_index.setLinkage(.extern_weak, &o.builder);3010 .strong, .weak => {
3007 if (is_dll_import) variable_index.setDllStorageClass(.dllimport, &o.builder);3011 variable_index.setLinkage(switch (linkage) {
3008 } else {3012 .internal => unreachable,
3009 variable_index.setLinkage(.internal, &o.builder);3013 .strong => .external,
3010 variable_index.setUnnamedAddr(.unnamed_addr, &o.builder);3014 .weak => .extern_weak,
3011 }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);
3012 return variable_index;3025 return variable_index;
3013 }3026 }
30143027
...@@ -4530,14 +4543,14 @@ pub const NavGen = struct {...@@ -4530,14 +4543,14 @@ pub const NavGen = struct {
4530 const nav = ip.getNav(nav_index);4543 const nav = ip.getNav(nav_index);
4531 const resolved = nav.status.fully_resolved;4544 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)) {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)) {
4534 .variable => |variable| .{ false, .none, variable.is_threadlocal, variable.is_weak_linkage, false, false, variable.init, variable.owner_nav },4547 .variable => |variable| .{ .none, .internal, .default, variable.is_threadlocal, 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 },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 },
4536 else => .{ false, .none, false, false, false, true, resolved.val, nav_index },4549 else => .{ .none, .internal, .default, false, false, true, resolved.val, nav_index },
4537 };4550 };
4538 const ty = Type.fromInterned(nav.typeOf(ip));4551 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())) {
4541 _ = try o.resolveLlvmFunction(owner_nav);4554 _ = try o.resolveLlvmFunction(owner_nav);
4542 } else {4555 } else {
4543 const variable_index = try o.resolveGlobalNav(nav_index);4556 const variable_index = try o.resolveGlobalNav(nav_index);
...@@ -4549,6 +4562,7 @@ pub const NavGen = struct {...@@ -4549,6 +4562,7 @@ pub const NavGen = struct {
4549 .none => .no_init,4562 .none => .no_init,
4550 else => try o.lowerValue(init_val),4563 else => try o.lowerValue(init_val),
4551 }, &o.builder);4564 }, &o.builder);
4565 variable_index.setVisibility(visibility, &o.builder);
45524566
4553 const file_scope = zcu.navFileScopeIndex(nav_index);4567 const file_scope = zcu.navFileScopeIndex(nav_index);
4554 const mod = zcu.fileByIndex(file_scope).mod.?;4568 const mod = zcu.fileByIndex(file_scope).mod.?;
...@@ -4568,7 +4582,7 @@ pub const NavGen = struct {...@@ -4568,7 +4582,7 @@ pub const NavGen = struct {
4568 line_number,4582 line_number,
4569 try o.lowerDebugType(ty),4583 try o.lowerDebugType(ty),
4570 variable_index,4584 variable_index,
4571 .{ .local = !is_extern },4585 .{ .local = linkage == .internal },
4572 );4586 );
45734587
4574 const debug_expression = try o.builder.debugExpression(&.{});4588 const debug_expression = try o.builder.debugExpression(&.{});
...@@ -4583,38 +4597,47 @@ pub const NavGen = struct {...@@ -4583,38 +4597,47 @@ pub const NavGen = struct {
4583 }4597 }
4584 }4598 }
45854599
4586 if (is_extern) {4600 switch (linkage) {
4587 const global_index = o.nav_map.get(nav_index).?;4601 .internal => {},
4602 .strong, .weak => {
4603 const global_index = o.nav_map.get(nav_index).?;
45884604
4589 const decl_name = decl_name: {4605 const decl_name = decl_name: {
4590 if (zcu.getTarget().cpu.arch.isWasm() and ty.zigTypeTag(zcu) == .@"fn") {4606 if (zcu.getTarget().cpu.arch.isWasm() and ty.zigTypeTag(zcu) == .@"fn") {
4591 if (lib_name.toSlice(ip)) |lib_name_slice| {4607 if (lib_name.toSlice(ip)) |lib_name_slice| {
4592 if (!std.mem.eql(u8, lib_name_slice, "c")) {4608 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 });4609 break :decl_name try o.builder.strtabStringFmt("{}|{s}", .{ nav.name.fmt(ip), lib_name_slice });
4610 }
4594 }4611 }
4595 }4612 }
4596 }4613 break :decl_name try o.builder.strtabString(nav.name.toSlice(ip));
4597 break :decl_name try o.builder.strtabString(nav.name.toSlice(ip));4614 };
4598 };
45994615
4600 if (o.builder.getGlobal(decl_name)) |other_global| {4616 if (o.builder.getGlobal(decl_name)) |other_global| {
4601 if (other_global != global_index) {4617 if (other_global != global_index) {
4602 // Another global already has this name; just use it in place of this global.4618 // Another global already has this name; just use it in place of this global.
4603 try global_index.replace(other_global, &o.builder);4619 try global_index.replace(other_global, &o.builder);
4604 return;4620 return;
4621 }
4605 }4622 }
4606 }
46074623
4608 try global_index.rename(decl_name, &o.builder);4624 try global_index.rename(decl_name, &o.builder);
4609 global_index.setLinkage(.external, &o.builder);4625 global_index.setUnnamedAddr(.default, &o.builder);
4610 global_index.setUnnamedAddr(.default, &o.builder);4626 if (is_dll_import) {
4611 if (is_dll_import) {4627 global_index.setDllStorageClass(.dllimport, &o.builder);
4612 global_index.setDllStorageClass(.dllimport, &o.builder);4628 } else if (zcu.comp.config.dll_export_fns) {
4613 } else if (zcu.comp.config.dll_export_fns) {4629 global_index.setDllStorageClass(.default, &o.builder);
4614 global_index.setDllStorageClass(.default, &o.builder);4630 }
4615 }
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,
4618 }4641 }
4619 }4642 }
4620};4643};
...@@ -5023,7 +5046,7 @@ pub const FuncGen = struct {...@@ -5023,7 +5046,7 @@ pub const FuncGen = struct {
50235046
5024 .vector_store_elem => try self.airVectorStoreElem(inst),5047 .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
5028 .inferred_alloc, .inferred_alloc_comptime => unreachable,5051 .inferred_alloc, .inferred_alloc_comptime => unreachable,
50295052
...@@ -8122,7 +8145,7 @@ pub const FuncGen = struct {...@@ -8122,7 +8145,7 @@ pub const FuncGen = struct {
8122 return .none;8145 return .none;
8123 }8146 }
81248147
8125 fn airTlvDllimportPtr(fg: *FuncGen, inst: Air.Inst.Index) !Builder.Value {8148 fn airRuntimeNavPtr(fg: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
8126 const o = fg.ng.object;8149 const o = fg.ng.object;
8127 const ty_nav = fg.air.instructions.items(.data)[@intFromEnum(inst)].ty_nav;8150 const ty_nav = fg.air.instructions.items(.data)[@intFromEnum(inst)].ty_nav;
8128 const llvm_ptr_const = try o.lowerNavRefValue(ty_nav.nav);8151 const llvm_ptr_const = try o.lowerNavRefValue(ty_nav.nav);
src/link/Dwarf.zig+52-138
...@@ -785,7 +785,6 @@ const Entry = struct {...@@ -785,7 +785,6 @@ const Entry = struct {
785 }785 }
786786
787 const Index = enum(u32) {787 const Index = enum(u32) {
788 //got_proc,
789 _,788 _,
790789
791 const Optional = enum(u32) {790 const Optional = enum(u32) {
...@@ -1041,7 +1040,7 @@ const Entry = struct {...@@ -1041,7 +1040,7 @@ const Entry = struct {
1041 const symbol = zo.symbol(reloc.target_sym);1040 const symbol = zo.symbol(reloc.target_sym);
1042 try dwarf.resolveReloc(1041 try dwarf.resolveReloc(
1043 entry_off + reloc.source_off,1042 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)) -
1045 if (symbol.flags.is_tls) elf_file.dtpAddress() else 0),1044 if (symbol.flags.is_tls) elf_file.dtpAddress() else 0),
1046 @intFromEnum(dwarf.address_size),1045 @intFromEnum(dwarf.address_size),
1047 );1046 );
...@@ -1052,7 +1051,7 @@ const Entry = struct {...@@ -1052,7 +1051,7 @@ const Entry = struct {
1052 const ref = zo.getSymbolRef(reloc.target_sym, macho_file);1051 const ref = zo.getSymbolRef(reloc.target_sym, macho_file);
1053 try dwarf.resolveReloc(1052 try dwarf.resolveReloc(
1054 entry_off + reloc.source_off,1053 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)),
1056 @intFromEnum(dwarf.address_size),1055 @intFromEnum(dwarf.address_size),
1057 );1056 );
1058 }1057 }
...@@ -1081,27 +1080,12 @@ const CrossSectionReloc = struct {...@@ -1081,27 +1080,12 @@ const CrossSectionReloc = struct {
1081const ExternalReloc = struct {1080const ExternalReloc = struct {
1082 source_off: u32 = 0,1081 source_off: u32 = 0,
1083 target_sym: u32,1082 target_sym: u32,
1084 target_off: enum(u64) {1083 target_off: u64 = 0,
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,
1099};1084};
11001085
1101pub const Loc = union(enum) {1086pub const Loc = union(enum) {
1102 empty,1087 empty,
1103 addr_reloc: u32,1088 addr_reloc: u32,
1104 got_reloc: u32,
1105 deref: *const Loc,1089 deref: *const Loc,
1106 constu: u64,1090 constu: u64,
1107 consts: i64,1091 consts: i64,
...@@ -1166,10 +1150,6 @@ pub const Loc = union(enum) {...@@ -1166,10 +1150,6 @@ pub const Loc = union(enum) {
1166 try addr.write(adapter);1150 try addr.write(adapter);
1167 try writer.writeByte(DW.OP.deref);1151 try writer.writeByte(DW.OP.deref);
1168 },1152 },
1169 .got_reloc => |sym_index| {
1170 try writer.writeByte(DW.OP.const4s);
1171 try adapter.gotSym(sym_index);
1172 },
1173 .constu => |constu| if (std.math.cast(u5, constu)) |lit| {1153 .constu => |constu| if (std.math.cast(u5, constu)) |lit| {
1174 try writer.writeByte(@as(u8, DW.OP.lit0) + lit);1154 try writer.writeByte(@as(u8, DW.OP.lit0) + lit);
1175 } else if (std.math.cast(u8, constu)) |const1u| {1155 } else if (std.math.cast(u8, constu)) |const1u| {
...@@ -1766,9 +1746,6 @@ pub const WipNav = struct {...@@ -1766,9 +1746,6 @@ pub const WipNav = struct {
1766 fn endian(_: ExprLocCounter) std.builtin.Endian {1746 fn endian(_: ExprLocCounter) std.builtin.Endian {
1767 return @import("builtin").cpu.arch.endian();1747 return @import("builtin").cpu.arch.endian();
1768 }1748 }
1769 fn gotSym(counter: *ExprLocCounter, _: u32) error{}!void {
1770 counter.stream.bytes_written += 4;
1771 }
1772 fn addrSym(counter: *ExprLocCounter, _: u32) error{}!void {1749 fn addrSym(counter: *ExprLocCounter, _: u32) error{}!void {
1773 counter.stream.bytes_written += @intFromEnum(counter.address_size);1750 counter.stream.bytes_written += @intFromEnum(counter.address_size);
1774 }1751 }
...@@ -1789,14 +1766,6 @@ pub const WipNav = struct {...@@ -1789,14 +1766,6 @@ pub const WipNav = struct {
1789 fn endian(ctx: @This()) std.builtin.Endian {1766 fn endian(ctx: @This()) std.builtin.Endian {
1790 return ctx.wip_nav.dwarf.endian;1767 return ctx.wip_nav.dwarf.endian;
1791 }1768 }
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 }
1800 fn addrSym(ctx: @This(), sym_index: u32) UpdateError!void {1769 fn addrSym(ctx: @This(), sym_index: u32) UpdateError!void {
1801 try ctx.wip_nav.infoAddrSym(sym_index, 0);1770 try ctx.wip_nav.infoAddrSym(sym_index, 0);
1802 }1771 }
...@@ -1812,7 +1781,7 @@ pub const WipNav = struct {...@@ -1812,7 +1781,7 @@ pub const WipNav = struct {
1812 try wip_nav.infoExternalReloc(.{1781 try wip_nav.infoExternalReloc(.{
1813 .source_off = @intCast(wip_nav.debug_info.items.len),1782 .source_off = @intCast(wip_nav.debug_info.items.len),
1814 .target_sym = sym_index,1783 .target_sym = sym_index,
1815 .target_off = .rel(sym_off),1784 .target_off = sym_off,
1816 });1785 });
1817 try wip_nav.debug_info.appendNTimes(wip_nav.dwarf.gpa, 0, @intFromEnum(wip_nav.dwarf.address_size));1786 try wip_nav.debug_info.appendNTimes(wip_nav.dwarf.gpa, 0, @intFromEnum(wip_nav.dwarf.address_size));
1818 }1787 }
...@@ -1829,14 +1798,6 @@ pub const WipNav = struct {...@@ -1829,14 +1798,6 @@ pub const WipNav = struct {
1829 fn endian(ctx: @This()) std.builtin.Endian {1798 fn endian(ctx: @This()) std.builtin.Endian {
1830 return ctx.wip_nav.dwarf.endian;1799 return ctx.wip_nav.dwarf.endian;
1831 }1800 }
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 }
1840 fn addrSym(ctx: @This(), sym_index: u32) UpdateError!void {1801 fn addrSym(ctx: @This(), sym_index: u32) UpdateError!void {
1841 try ctx.wip_nav.frameAddrSym(sym_index, 0);1802 try ctx.wip_nav.frameAddrSym(sym_index, 0);
1842 }1803 }
...@@ -1852,7 +1813,7 @@ pub const WipNav = struct {...@@ -1852,7 +1813,7 @@ pub const WipNav = struct {
1852 try wip_nav.frameExternalReloc(.{1813 try wip_nav.frameExternalReloc(.{
1853 .source_off = @intCast(wip_nav.debug_frame.items.len),1814 .source_off = @intCast(wip_nav.debug_frame.items.len),
1854 .target_sym = sym_index,1815 .target_sym = sym_index,
1855 .target_off = .rel(sym_off),1816 .target_off = sym_off,
1856 });1817 });
1857 try wip_nav.debug_frame.appendNTimes(wip_nav.dwarf.gpa, 0, @intFromEnum(wip_nav.dwarf.address_size));1818 try wip_nav.debug_frame.appendNTimes(wip_nav.dwarf.gpa, 0, @intFromEnum(wip_nav.dwarf.address_size));
1858 }1819 }
...@@ -2338,81 +2299,50 @@ fn getUnit(dwarf: *Dwarf, mod: *Module) !Unit.Index {...@@ -2338,81 +2299,50 @@ fn getUnit(dwarf: *Dwarf, mod: *Module) !Unit.Index {
2338 const mod_gop = try dwarf.mods.getOrPut(dwarf.gpa, mod);2299 const mod_gop = try dwarf.mods.getOrPut(dwarf.gpa, mod);
2339 const unit: Unit.Index = @enumFromInt(mod_gop.index);2300 const unit: Unit.Index = @enumFromInt(mod_gop.index);
2340 if (!mod_gop.found_existing) {2301 if (!mod_gop.found_existing) {
2341 {2302 errdefer _ = dwarf.mods.pop();
2342 errdefer _ = dwarf.mods.pop();2303 mod_gop.value_ptr.* = .{
2343 mod_gop.value_ptr.* = .{2304 .root_dir_path = undefined,
2344 .root_dir_path = undefined,2305 .dirs = .empty,
2345 .dirs = .empty,2306 .files = .empty,
2346 .files = .empty,2307 };
2347 };2308 errdefer mod_gop.value_ptr.dirs.deinit(dwarf.gpa);
2348 errdefer mod_gop.value_ptr.dirs.deinit(dwarf.gpa);2309 try mod_gop.value_ptr.dirs.putNoClobber(dwarf.gpa, unit, {});
2349 try mod_gop.value_ptr.dirs.putNoClobber(dwarf.gpa, unit, {});2310 assert(try dwarf.debug_aranges.section.addUnit(
2350 assert(try dwarf.debug_aranges.section.addUnit(2311 DebugAranges.headerBytes(dwarf),
2351 DebugAranges.headerBytes(dwarf),2312 DebugAranges.trailerBytes(dwarf),
2352 DebugAranges.trailerBytes(dwarf),2313 dwarf,
2353 dwarf,2314 ) == unit);
2354 ) == unit);2315 errdefer dwarf.debug_aranges.section.popUnit(dwarf.gpa);
2355 errdefer dwarf.debug_aranges.section.popUnit(dwarf.gpa);2316 assert(try dwarf.debug_frame.section.addUnit(
2356 assert(try dwarf.debug_frame.section.addUnit(2317 DebugFrame.headerBytes(dwarf),
2357 DebugFrame.headerBytes(dwarf),2318 DebugFrame.trailerBytes(dwarf),
2358 DebugFrame.trailerBytes(dwarf),2319 dwarf,
2359 dwarf,2320 ) == unit);
2360 ) == unit);2321 errdefer dwarf.debug_frame.section.popUnit(dwarf.gpa);
2361 errdefer dwarf.debug_frame.section.popUnit(dwarf.gpa);2322 assert(try dwarf.debug_info.section.addUnit(
2362 assert(try dwarf.debug_info.section.addUnit(2323 DebugInfo.headerBytes(dwarf),
2363 DebugInfo.headerBytes(dwarf),2324 DebugInfo.trailer_bytes,
2364 DebugInfo.trailer_bytes,2325 dwarf,
2365 dwarf,2326 ) == unit);
2366 ) == unit);2327 errdefer dwarf.debug_info.section.popUnit(dwarf.gpa);
2367 errdefer dwarf.debug_info.section.popUnit(dwarf.gpa);2328 assert(try dwarf.debug_line.section.addUnit(
2368 assert(try dwarf.debug_line.section.addUnit(2329 DebugLine.headerBytes(dwarf, 5, 25),
2369 DebugLine.headerBytes(dwarf, 5, 25),2330 DebugLine.trailer_bytes,
2370 DebugLine.trailer_bytes,2331 dwarf,
2371 dwarf,2332 ) == unit);
2372 ) == unit);2333 errdefer dwarf.debug_line.section.popUnit(dwarf.gpa);
2373 errdefer dwarf.debug_line.section.popUnit(dwarf.gpa);2334 assert(try dwarf.debug_loclists.section.addUnit(
2374 assert(try dwarf.debug_loclists.section.addUnit(2335 DebugLocLists.headerBytes(dwarf),
2375 DebugLocLists.headerBytes(dwarf),2336 DebugLocLists.trailer_bytes,
2376 DebugLocLists.trailer_bytes,2337 dwarf,
2377 dwarf,2338 ) == unit);
2378 ) == unit);2339 errdefer dwarf.debug_loclists.section.popUnit(dwarf.gpa);
2379 errdefer dwarf.debug_loclists.section.popUnit(dwarf.gpa);2340 assert(try dwarf.debug_rnglists.section.addUnit(
2380 assert(try dwarf.debug_rnglists.section.addUnit(2341 DebugRngLists.headerBytes(dwarf),
2381 DebugRngLists.headerBytes(dwarf),2342 DebugRngLists.trailer_bytes,
2382 DebugRngLists.trailer_bytes,2343 dwarf,
2383 dwarf,2344 ) == unit);
2384 ) == unit);2345 errdefer dwarf.debug_rnglists.section.popUnit(dwarf.gpa);
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 //}
2416 }2346 }
2417 return unit;2347 return unit;
2418}2348}
...@@ -2510,16 +2440,7 @@ fn initWipNavInner(...@@ -2510,16 +2440,7 @@ fn initWipNavInner(
2510 try wip_nav.strp(nav.fqn.toSlice(ip));2440 try wip_nav.strp(nav.fqn.toSlice(ip));
2511 const ty: Type = nav_val.typeOf(zcu);2441 const ty: Type = nav_val.typeOf(zcu);
2512 const addr: Loc = .{ .addr_reloc = sym_index };2442 const addr: Loc = .{ .addr_reloc = sym_index };
2513 const loc: Loc = loc: {2443 const loc: Loc = if (decl.is_threadlocal) .{ .form_tls_address = &addr } else addr;
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 };
2523 switch (decl.kind) {2444 switch (decl.kind) {
2524 .unnamed_test, .@"test", .decltest, .@"comptime", .@"usingnamespace" => unreachable,2445 .unnamed_test, .@"test", .decltest, .@"comptime", .@"usingnamespace" => unreachable,
2525 .@"const" => {2446 .@"const" => {
...@@ -2605,7 +2526,7 @@ fn initWipNavInner(...@@ -2605,7 +2526,7 @@ fn initWipNavInner(
2605 try wip_nav.infoAddrSym(sym_index, 0);2526 try wip_nav.infoAddrSym(sym_index, 0);
2606 wip_nav.func_high_pc = @intCast(wip_nav.debug_info.items.len);2527 wip_nav.func_high_pc = @intCast(wip_nav.debug_info.items.len);
2607 try diw.writeInt(u32, 0, dwarf.endian);2528 try diw.writeInt(u32, 0, dwarf.endian);
2608 const target = file.mod.?.resolved_target.result;2529 const target = mod.resolved_target.result;
2609 try uleb128(diw, switch (nav.status.fully_resolved.alignment) {2530 try uleb128(diw, switch (nav.status.fully_resolved.alignment) {
2610 .none => target_info.defaultFunctionAlignment(target),2531 .none => target_info.defaultFunctionAlignment(target),
2611 else => |a| a.maxStrict(target_info.minFunctionAlignment(target)),2532 else => |a| a.maxStrict(target_info.minFunctionAlignment(target)),
...@@ -2742,7 +2663,7 @@ pub fn finishWipNavFunc(...@@ -2742,7 +2663,7 @@ pub fn finishWipNavFunc(
2742 .{2663 .{
2743 .source_off = 1 + @intFromEnum(dwarf.address_size),2664 .source_off = 1 + @intFromEnum(dwarf.address_size),
2744 .target_sym = wip_nav.func_sym_index,2665 .target_sym = wip_nav.func_sym_index,
2745 .target_off = .rel(code_size),2666 .target_off = code_size,
2746 },2667 },
2747 });2668 });
2748 try dwarf.debug_rnglists.section.replaceEntry(2669 try dwarf.debug_rnglists.section.replaceEntry(
...@@ -4981,7 +4902,6 @@ const AbbrevCode = enum {...@@ -4981,7 +4902,6 @@ const AbbrevCode = enum {
4981 comptime_value_field_comptime_state,4902 comptime_value_field_comptime_state,
4982 comptime_value_elem_runtime_bits,4903 comptime_value_elem_runtime_bits,
4983 comptime_value_elem_comptime_state,4904 comptime_value_elem_comptime_state,
4984 //proc,
49854905
4986 const decl_bytes = uleb128Bytes(@intFromEnum(AbbrevCode.decl_instance_func_generic));4906 const decl_bytes = uleb128Bytes(@intFromEnum(AbbrevCode.decl_instance_func_generic));
4987 comptime {4907 comptime {
...@@ -5851,12 +5771,6 @@ const AbbrevCode = enum {...@@ -5851,12 +5771,6 @@ const AbbrevCode = enum {
5851 .{ .ZIG_comptime_value, .ref_addr },5771 .{ .ZIG_comptime_value, .ref_addr },
5852 },5772 },
5853 },5773 },
5854 //.proc = .{
5855 // .tag = .dwarf_procedure,
5856 // .attrs = &.{
5857 // .{ .location, .exprloc },
5858 // },
5859 //},
5860 .null = undefined,5774 .null = undefined,
5861 });5775 });
5862};5776};
src/link/Elf.zig+25-17
...@@ -959,6 +959,12 @@ fn flushModuleInner(self: *Elf, arena: Allocator, tid: Zcu.PerThread.Id) !void {...@@ -959,6 +959,12 @@ fn flushModuleInner(self: *Elf, arena: Allocator, tid: Zcu.PerThread.Id) !void {
959 self.rela_plt.clearRetainingCapacity();959 self.rela_plt.clearRetainingCapacity();
960960
961 if (self.zigObjectPtr()) |zo| {961 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
962 var has_reloc_errors = false;968 var has_reloc_errors = false;
963 for (zo.atoms_indexes.items) |atom_index| {969 for (zo.atoms_indexes.items) |atom_index| {
964 const atom_ptr = zo.atom(atom_index) orelse continue;970 const atom_ptr = zo.atom(atom_index) orelse continue;
...@@ -969,7 +975,10 @@ fn flushModuleInner(self: *Elf, arena: Allocator, tid: Zcu.PerThread.Id) !void {...@@ -969,7 +975,10 @@ fn flushModuleInner(self: *Elf, arena: Allocator, tid: Zcu.PerThread.Id) !void {
969 const code = try zo.codeAlloc(self, atom_index);975 const code = try zo.codeAlloc(self, atom_index);
970 defer gpa.free(code);976 defer gpa.free(code);
971 const file_offset = atom_ptr.offset(self);977 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) {
973 error.RelocFailure, error.RelaxFailure => has_reloc_errors = true,982 error.RelocFailure, error.RelaxFailure => has_reloc_errors = true,
974 error.UnsupportedCpuArch => {983 error.UnsupportedCpuArch => {
975 try self.reportUnsupportedCpuArch();984 try self.reportUnsupportedCpuArch();
...@@ -980,6 +989,8 @@ fn flushModuleInner(self: *Elf, arena: Allocator, tid: Zcu.PerThread.Id) !void {...@@ -980,6 +989,8 @@ fn flushModuleInner(self: *Elf, arena: Allocator, tid: Zcu.PerThread.Id) !void {
980 try self.pwriteAll(code, file_offset);989 try self.pwriteAll(code, file_offset);
981 }990 }
982991
992 try self.reportUndefinedSymbols(&undefs);
993
983 if (has_reloc_errors) return error.LinkFailure;994 if (has_reloc_errors) return error.LinkFailure;
984 }995 }
985996
...@@ -1392,11 +1403,9 @@ fn scanRelocs(self: *Elf) !void {...@@ -1392,11 +1403,9 @@ fn scanRelocs(self: *Elf) !void {
1392 const gpa = self.base.comp.gpa;1403 const gpa = self.base.comp.gpa;
1393 const shared_objects = self.shared_objects.values();1404 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);
1396 defer {1407 defer {
1397 for (undefs.values()) |*refs| {1408 for (undefs.values()) |*refs| refs.deinit();
1398 refs.deinit();
1399 }
1400 undefs.deinit();1409 undefs.deinit();
1401 }1410 }
14021411
...@@ -2702,15 +2711,16 @@ fn initSyntheticSections(self: *Elf) !void {...@@ -2702,15 +2711,16 @@ fn initSyntheticSections(self: *Elf) !void {
2702 });2711 });
2703 }2712 }
27042713
2705 const needs_interp = blk: {2714 const is_exe_or_dyn_lib = switch (comp.config.output_mode) {
2706 // On Ubuntu with musl-gcc, we get a weird combo of options looking like this:2715 .Exe => true,
2707 // -dynamic-linker=<path> -static2716 .Lib => comp.config.link_mode == .dynamic,
2708 // In this case, if we do generate .interp section and segment, we will get2717 .Obj => false,
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;
2713 };2718 };
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
2714 if (needs_interp and self.section_indexes.interp == null) {2724 if (needs_interp and self.section_indexes.interp == null) {
2715 self.section_indexes.interp = try self.addSection(.{2725 self.section_indexes.interp = try self.addSection(.{
2716 .name = try self.insertShString(".interp"),2726 .name = try self.insertShString(".interp"),
...@@ -3707,11 +3717,9 @@ fn allocateSpecialPhdrs(self: *Elf) void {...@@ -3707,11 +3717,9 @@ fn allocateSpecialPhdrs(self: *Elf) void {
3707fn writeAtoms(self: *Elf) !void {3717fn writeAtoms(self: *Elf) !void {
3708 const gpa = self.base.comp.gpa;3718 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);
3711 defer {3721 defer {
3712 for (undefs.values()) |*refs| {3722 for (undefs.values()) |*refs| refs.deinit();
3713 refs.deinit();
3714 }
3715 undefs.deinit();3723 undefs.deinit();
3716 }3724 }
37173725
src/link/Elf/Atom.zig+3-3
...@@ -497,14 +497,14 @@ fn dynAbsRelocAction(symbol: *const Symbol, elf_file: *Elf) RelocAction {...@@ -497,14 +497,14 @@ fn dynAbsRelocAction(symbol: *const Symbol, elf_file: *Elf) RelocAction {
497}497}
498498
499fn outputType(elf_file: *Elf) u2 {499fn outputType(elf_file: *Elf) u2 {
500 const comp = elf_file.base.comp;
501 assert(!elf_file.base.isRelocatable());500 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) {
503 .Obj => unreachable,503 .Obj => unreachable,
504 .Lib => 0,504 .Lib => 0,
505 .Exe => switch (elf_file.getTarget().os.tag) {505 .Exe => switch (elf_file.getTarget().os.tag) {
506 .haiku => 0,506 .haiku => 0,
507 else => if (comp.config.pie) 1 else 2,507 else => if (config.pie) 1 else 2,
508 },508 },
509 };509 };
510}510}
src/link/Elf/ZigObject.zig+5-7
...@@ -463,11 +463,8 @@ pub fn flush(self: *ZigObject, elf_file: *Elf, tid: Zcu.PerThread.Id) !void {...@@ -463,11 +463,8 @@ pub fn flush(self: *ZigObject, elf_file: *Elf, tid: Zcu.PerThread.Id) !void {
463 for (entry.external_relocs.items) |reloc| {463 for (entry.external_relocs.items) |reloc| {
464 const target_sym = self.symbol(reloc.target_sym);464 const target_sym = self.symbol(reloc.target_sym);
465 const r_offset = entry_off + reloc.source_off;465 const r_offset = entry_off + reloc.source_off;
466 const r_addend: i64 = switch (reloc.target_off) {466 const r_addend: i64 = @intCast(reloc.target_off);
467 .none, .got => 0,467 const r_type = relocation.dwarf.externalRelocType(target_sym.*, sect_index, dwarf.address_size, cpu_arch);
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);
471 atom_ptr.addRelocAssumeCapacity(.{468 atom_ptr.addRelocAssumeCapacity(.{
472 .r_offset = r_offset,469 .r_offset = r_offset,
473 .r_addend = r_addend,470 .r_addend = r_addend,
...@@ -660,6 +657,7 @@ pub fn scanRelocs(self: *ZigObject, elf_file: *Elf, undefs: anytype) !void {...@@ -660,6 +657,7 @@ pub fn scanRelocs(self: *ZigObject, elf_file: *Elf, undefs: anytype) !void {
660 const atom_ptr = self.atom(atom_index) orelse continue;657 const atom_ptr = self.atom(atom_index) orelse continue;
661 if (!atom_ptr.alive) continue;658 if (!atom_ptr.alive) continue;
662 const shdr = atom_ptr.inputShdr(elf_file);659 const shdr = atom_ptr.inputShdr(elf_file);
660 if (shdr.sh_flags & elf.SHF_ALLOC == 0) continue;
663 if (shdr.sh_type == elf.SHT_NOBITS) continue;661 if (shdr.sh_type == elf.SHT_NOBITS) continue;
664 if (atom_ptr.scanRelocsRequiresCode(elf_file)) {662 if (atom_ptr.scanRelocsRequiresCode(elf_file)) {
665 // TODO ideally we don't have to fetch the code here.663 // TODO ideally we don't have to fetch the code here.
...@@ -950,7 +948,7 @@ pub fn getNavVAddr(...@@ -950,7 +948,7 @@ pub fn getNavVAddr(
950 .dwarf => |wip_nav| try wip_nav.infoExternalReloc(.{948 .dwarf => |wip_nav| try wip_nav.infoExternalReloc(.{
951 .source_off = @intCast(reloc_info.offset),949 .source_off = @intCast(reloc_info.offset),
952 .target_sym = this_sym_index,950 .target_sym = this_sym_index,
953 .target_off = .rel(reloc_info.addend),951 .target_off = reloc_info.addend,
954 }),952 }),
955 .plan9 => unreachable,953 .plan9 => unreachable,
956 .none => unreachable,954 .none => unreachable,
...@@ -983,7 +981,7 @@ pub fn getUavVAddr(...@@ -983,7 +981,7 @@ pub fn getUavVAddr(
983 .dwarf => |wip_nav| try wip_nav.infoExternalReloc(.{981 .dwarf => |wip_nav| try wip_nav.infoExternalReloc(.{
984 .source_off = @intCast(reloc_info.offset),982 .source_off = @intCast(reloc_info.offset),
985 .target_sym = sym_index,983 .target_sym = sym_index,
986 .target_off = .rel(reloc_info.addend),984 .target_off = reloc_info.addend,
987 }),985 }),
988 .plan9 => unreachable,986 .plan9 => unreachable,
989 .none => unreachable,987 .none => unreachable,
src/link/Elf/relocation.zig+1-2
...@@ -108,13 +108,12 @@ pub const dwarf = struct {...@@ -108,13 +108,12 @@ pub const dwarf = struct {
108108
109 pub fn externalRelocType(109 pub fn externalRelocType(
110 target: Symbol,110 target: Symbol,
111 is_got: bool,
112 source_section: Dwarf.Section.Index,111 source_section: Dwarf.Section.Index,
113 address_size: Dwarf.AddressSize,112 address_size: Dwarf.AddressSize,
114 cpu_arch: std.Target.Cpu.Arch,113 cpu_arch: std.Target.Cpu.Arch,
115 ) u32 {114 ) u32 {
116 return switch (cpu_arch) {115 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) {
118 else => switch (address_size) {117 else => switch (address_size) {
119 .@"32" => if (target.flags.is_tls) .DTPOFF32 else .@"32",118 .@"32" => if (target.flags.is_tls) .DTPOFF32 else .@"32",
120 .@"64" => if (target.flags.is_tls) .DTPOFF64 else .@"64",119 .@"64" => if (target.flags.is_tls) .DTPOFF64 else .@"64",
src/link/MachO/ZigObject.zig+2-2
...@@ -648,7 +648,7 @@ pub fn getNavVAddr(...@@ -648,7 +648,7 @@ pub fn getNavVAddr(
648 .dwarf => |wip_nav| try wip_nav.infoExternalReloc(.{648 .dwarf => |wip_nav| try wip_nav.infoExternalReloc(.{
649 .source_off = @intCast(reloc_info.offset),649 .source_off = @intCast(reloc_info.offset),
650 .target_sym = sym_index,650 .target_sym = sym_index,
651 .target_off = .rel(reloc_info.addend),651 .target_off = reloc_info.addend,
652 }),652 }),
653 .plan9 => unreachable,653 .plan9 => unreachable,
654 .none => unreachable,654 .none => unreachable,
...@@ -688,7 +688,7 @@ pub fn getUavVAddr(...@@ -688,7 +688,7 @@ pub fn getUavVAddr(
688 .dwarf => |wip_nav| try wip_nav.infoExternalReloc(.{688 .dwarf => |wip_nav| try wip_nav.infoExternalReloc(.{
689 .source_off = @intCast(reloc_info.offset),689 .source_off = @intCast(reloc_info.offset),
690 .target_sym = sym_index,690 .target_sym = sym_index,
691 .target_off = .rel(reloc_info.addend),691 .target_off = reloc_info.addend,
692 }),692 }),
693 .plan9 => unreachable,693 .plan9 => unreachable,
694 .none => unreachable,694 .none => unreachable,
src/link/Wasm.zig+1-1
...@@ -2376,7 +2376,7 @@ pub const FunctionImportId = enum(u32) {...@@ -2376,7 +2376,7 @@ pub const FunctionImportId = enum(u32) {
2376 const zcu = wasm.base.comp.zcu.?;2376 const zcu = wasm.base.comp.zcu.?;
2377 const ip = &zcu.intern_pool;2377 const ip = &zcu.intern_pool;
2378 const ext = ip.getNav(i.ptr(wasm).*).getResolvedExtern(ip).?;2378 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;
2380 },2380 },
2381 };2381 };
2382 }2382 }
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 {...@@ -117,9 +117,9 @@ export fn testMutablePointer() void {
117// tmp.zig:37:38: note: imported here117// tmp.zig:37:38: note: imported here
118// neg_inf.zon:1:1: error: expected type '?u8'118// neg_inf.zon:1:1: error: expected type '?u8'
119// tmp.zig:57:28: note: imported here119// 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'
121// tmp.zig:62:39: note: imported here121// 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'
123// tmp.zig:67:44: note: imported here123// 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'
125// tmp.zig:72:50: note: imported here125// 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 {...@@ -15,6 +15,6 @@ pub export fn entry() void {
15// error15// error
16//16//
17// :7:25: error: unable to resolve comptime value17// :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-known18// :7:25: note: initializer of comptime-only struct 'tmp.S.foo__anon_499.C' must be comptime-known
19// :4:16: note: struct requires comptime because of this field19// :4:16: note: struct requires comptime because of this field
20// :4:16: note: types are not available at runtime20// :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 {...@@ -16,5 +16,5 @@ pub export fn entry2() void {
16//16//
17// :3:6: error: no field or member function named 'copy' in '[]const u8'17// :3:6: error: no field or member function named 'copy' in '[]const u8'
18// :9:8: error: no field or member function named 'bar' in '@TypeOf(.{})'18// :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'
20// :12:6: note: struct declared here20// :12:6: note: struct declared here
test/cases/compile_errors/coerce_anon_struct.zig+1-1
...@@ -6,6 +6,6 @@ export fn foo() void {...@@ -6,6 +6,6 @@ export fn foo() void {
66
7// error7// error
8//8//
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'
10// :3:16: note: struct declared here10// :3:16: note: struct declared here
11// :1:11: note: struct declared here11// :1:11: note: struct declared here
test/cases/compile_errors/redundant_try.zig+2-2
...@@ -44,9 +44,9 @@ comptime {...@@ -44,9 +44,9 @@ comptime {
44//44//
45// :5:23: error: expected error union type, found 'comptime_int'45// :5:23: error: expected error union type, found 'comptime_int'
46// :10:23: error: expected error union type, found '@TypeOf(.{})'46// :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'
48// :15:23: note: struct declared here48// :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'
50// :20:27: note: struct declared here50// :20:27: note: struct declared here
51// :25:23: error: expected error union type, found 'struct { comptime *const [5:0]u8 = "hello" }'51// :25:23: error: expected error union type, found 'struct { comptime *const [5:0]u8 = "hello" }'
52// :31:13: error: expected error union type, found 'u32'52// :31:13: error: expected error union type, found 'u32'
test/tests.zig+5-4
...@@ -1598,7 +1598,9 @@ const c_abi_targets = blk: {...@@ -1598,7 +1598,9 @@ const c_abi_targets = blk: {
1598 break :blk [_]CAbiTarget{1598 break :blk [_]CAbiTarget{
1599 // Native Targets1599 // Native Targets
16001600
1601 .{},1601 .{
1602 .use_llvm = true,
1603 },
16021604
1603 // Linux Targets1605 // Linux Targets
16041606
...@@ -1837,7 +1839,6 @@ const c_abi_targets = blk: {...@@ -1837,7 +1839,6 @@ const c_abi_targets = blk: {
1837 .abi = .musl,1839 .abi = .musl,
1838 },1840 },
1839 .use_llvm = false,1841 .use_llvm = false,
1840 .use_lld = false,
1841 .c_defines = &.{"ZIG_BACKEND_STAGE2_X86_64"},1842 .c_defines = &.{"ZIG_BACKEND_STAGE2_X86_64"},
1842 },1843 },
1843 .{1844 .{
...@@ -1848,7 +1849,6 @@ const c_abi_targets = blk: {...@@ -1848,7 +1849,6 @@ const c_abi_targets = blk: {
1848 .abi = .musl,1849 .abi = .musl,
1849 },1850 },
1850 .use_llvm = false,1851 .use_llvm = false,
1851 .use_lld = false,
1852 .strip = true,1852 .strip = true,
1853 .c_defines = &.{"ZIG_BACKEND_STAGE2_X86_64"},1853 .c_defines = &.{"ZIG_BACKEND_STAGE2_X86_64"},
1854 },1854 },
...@@ -1860,7 +1860,6 @@ const c_abi_targets = blk: {...@@ -1860,7 +1860,6 @@ const c_abi_targets = blk: {
1860 .abi = .musl,1860 .abi = .musl,
1861 },1861 },
1862 .use_llvm = false,1862 .use_llvm = false,
1863 .use_lld = false,
1864 .pic = true,1863 .pic = true,
1865 .c_defines = &.{"ZIG_BACKEND_STAGE2_X86_64"},1864 .c_defines = &.{"ZIG_BACKEND_STAGE2_X86_64"},
1866 },1865 },
...@@ -1870,6 +1869,7 @@ const c_abi_targets = blk: {...@@ -1870,6 +1869,7 @@ const c_abi_targets = blk: {
1870 .os_tag = .linux,1869 .os_tag = .linux,
1871 .abi = .musl,1870 .abi = .musl,
1872 },1871 },
1872 .use_llvm = true,
1873 },1873 },
1874 .{1874 .{
1875 .target = .{1875 .target = .{
...@@ -1877,6 +1877,7 @@ const c_abi_targets = blk: {...@@ -1877,6 +1877,7 @@ const c_abi_targets = blk: {
1877 .os_tag = .linux,1877 .os_tag = .linux,
1878 .abi = .muslx32,1878 .abi = .muslx32,
1879 },1879 },
1880 .use_llvm = true,
1880 },1881 },
18811882
1882 // WASI Targets1883 // WASI Targets