authorgravatar for mlugg@mlugg.co.ukMatthew Lugg <mlugg@mlugg.co.uk> 2025-05-26 22:59:01+01:00
committergravatar for mlugg@mlugg.co.ukMatthew Lugg <mlugg@mlugg.co.uk> 2025-05-27 19:23:11+01:00
log92c63126e8a58235625cceaf0ea9e3d4eacfe513
treeab36da0c91e39622bdd8a9c49e2f636ee341878d
parent3ed9155f10b725e6d24c01f5ecbebf359f3599a7

compiler: tlv pointers are not comptime-known

Pointers to thread-local variables do not have their addresses known until runtime, so it is nonsensical for them to be comptime-known. There was logic in the compiler which was essentially attempting to treat them as not being comptime-known despite the pointer being an interned value. This was a bit of a mess, the check was frequent enough to actually show up in compiler profiles, and it was very awkward for backends to deal with, because they had to grapple with the fact that a "constant" they were lowering might actually require runtime operations. So, instead, do not consider these pointers to be comptime-known in *any* way. Never intern such a pointer; instead, when the address of a threadlocal is taken, emit an AIR instruction which computes the pointer at runtime. This avoids lots of special handling for TLVs across basically all codegen backends; of all somewhat-functional backends, the only one which wasn't improved by this change was the LLVM backend, because LLVM pretends this complexity around threadlocals doesn't exist. This change simplifies Sema and codegen, avoids a potential source of bugs, and potentially improves Sema performance very slightly by avoiding a non-trivial check on a hot path.

21 files changed, 242 insertions(+), 290 deletions(-)

lib/std/debug.zig+6
......@@ -1530,6 +1530,12 @@ fn handleSegfaultWindows(info: *windows.EXCEPTION_POINTERS) callconv(.winapi) c_
15301530}
15311531
15321532fn handleSegfaultWindowsExtra(info: *windows.EXCEPTION_POINTERS, msg: u8, label: ?[]const u8) noreturn {
1533 // For backends that cannot handle the language features used by this segfault handler, we have a simpler one,
1534 switch (builtin.zig_backend) {
1535 .stage2_x86_64 => if (builtin.target.ofmt == .coff) @trap(),
1536 else => {},
1537 }
1538
15331539 comptime assert(windows.CONTEXT != void);
15341540 nosuspend switch (panic_stage) {
15351541 0 => {
src/Air.zig+18
......@@ -849,6 +849,17 @@ pub const Inst = struct {
849849 /// Uses the `vector_store_elem` field.
850850 vector_store_elem,
851851
852 /// Compute a pointer to a threadlocal or dllimport `Nav`, meaning one of:
853 ///
854 /// * `threadlocal var`
855 /// * `extern threadlocal var` (or corresponding `@extern`)
856 /// * `@extern` with `.is_dll_import = true`
857 ///
858 /// Such pointers are runtime values, so cannot be represented with an InternPool index.
859 ///
860 /// Uses the `ty_nav` field.
861 tlv_dllimport_ptr,
862
852863 /// Implements @cVaArg builtin.
853864 /// Uses the `ty_op` field.
854865 c_va_arg,
......@@ -1150,6 +1161,10 @@ pub const Inst = struct {
11501161 // Index into a different array.
11511162 payload: u32,
11521163 },
1164 ty_nav: struct {
1165 ty: InternPool.Index,
1166 nav: InternPool.Nav.Index,
1167 },
11531168 inferred_alloc_comptime: InferredAllocComptime,
11541169 inferred_alloc: InferredAlloc,
11551170
......@@ -1604,6 +1619,8 @@ pub fn typeOfIndex(air: *const Air, inst: Air.Inst.Index, ip: *const InternPool)
16041619 return Type.fromInterned(ip.indexToKey(err_union_ty.ip_index).error_union_type.payload_type);
16051620 },
16061621
1622 .tlv_dllimport_ptr => return .fromInterned(datas[@intFromEnum(inst)].ty_nav.ty),
1623
16071624 .work_item_id,
16081625 .work_group_size,
16091626 .work_group_id,
......@@ -1876,6 +1893,7 @@ pub fn mustLower(air: Air, inst: Air.Inst.Index, ip: *const InternPool) bool {
18761893 .err_return_trace,
18771894 .addrspace_cast,
18781895 .save_err_return_trace_index,
1896 .tlv_dllimport_ptr,
18791897 .work_item_id,
18801898 .work_group_size,
18811899 .work_group_id,
src/Air/types_resolved.zig+4
......@@ -311,6 +311,10 @@ fn checkBody(air: Air, body: []const Air.Inst.Index, zcu: *Zcu) bool {
311311 if (!checkRef(bin.rhs, zcu)) return false;
312312 },
313313
314 .tlv_dllimport_ptr => {
315 if (!checkType(.fromInterned(data.ty_nav.ty), zcu)) return false;
316 },
317
314318 .select,
315319 .mul_add,
316320 => {
src/InternPool.zig-24
......@@ -12036,30 +12036,6 @@ pub fn isVariable(ip: *const InternPool, val: Index) bool {
1203612036 return val.unwrap(ip).getTag(ip) == .variable;
1203712037}
1203812038
12039pub fn getBackingNav(ip: *const InternPool, val: Index) Nav.Index.Optional {
12040 var base = val;
12041 while (true) {
12042 const unwrapped_base = base.unwrap(ip);
12043 const base_item = unwrapped_base.getItem(ip);
12044 switch (base_item.tag) {
12045 .ptr_nav => return @enumFromInt(unwrapped_base.getExtra(ip).view().items(.@"0")[
12046 base_item.data + std.meta.fieldIndex(PtrNav, "nav").?
12047 ]),
12048 inline .ptr_eu_payload,
12049 .ptr_opt_payload,
12050 .ptr_elem,
12051 .ptr_field,
12052 => |tag| base = @enumFromInt(unwrapped_base.getExtra(ip).view().items(.@"0")[
12053 base_item.data + std.meta.fieldIndex(tag.Payload(), "base").?
12054 ]),
12055 .ptr_slice => base = @enumFromInt(unwrapped_base.getExtra(ip).view().items(.@"0")[
12056 base_item.data + std.meta.fieldIndex(PtrSlice, "ptr").?
12057 ]),
12058 else => return .none,
12059 }
12060 }
12061}
12062
1206312039pub fn getBackingAddrTag(ip: *const InternPool, val: Index) ?Key.Ptr.BaseAddr.Tag {
1206412040 var base = val;
1206512041 while (true) {
src/Liveness.zig+2
......@@ -334,6 +334,7 @@ pub fn categorizeOperand(
334334 .wasm_memory_size,
335335 .err_return_trace,
336336 .save_err_return_trace_index,
337 .tlv_dllimport_ptr,
337338 .c_va_start,
338339 .work_item_id,
339340 .work_group_size,
......@@ -960,6 +961,7 @@ fn analyzeInst(
960961 .wasm_memory_size,
961962 .err_return_trace,
962963 .save_err_return_trace_index,
964 .tlv_dllimport_ptr,
963965 .c_va_start,
964966 .work_item_id,
965967 .work_group_size,
src/Liveness/Verify.zig+1
......@@ -62,6 +62,7 @@ fn verifyBody(self: *Verify, body: []const Air.Inst.Index) Error!void {
6262 .wasm_memory_size,
6363 .err_return_trace,
6464 .save_err_return_trace_index,
65 .tlv_dllimport_ptr,
6566 .c_va_start,
6667 .work_item_id,
6768 .work_group_size,
src/Sema.zig+37-34
......@@ -2223,10 +2223,7 @@ fn resolveValue(sema: *Sema, inst: Air.Inst.Ref) CompileError!?Value {
22232223
22242224 if (inst.toInterned()) |ip_index| {
22252225 const val: Value = .fromInterned(ip_index);
2226
22272226 assert(val.getVariable(zcu) == null);
2228 if (val.isPtrRuntimeValue(zcu)) return null;
2229
22302227 return val;
22312228 } else {
22322229 // Runtime-known value.
......@@ -2295,31 +2292,12 @@ pub fn resolveFinalDeclValue(
22952292 air_ref: Air.Inst.Ref,
22962293) CompileError!Value {
22972294 const zcu = sema.pt.zcu;
2298
2299 const val = try sema.resolveValue(air_ref) orelse {
2300 const is_runtime_ptr = rt_ptr: {
2301 const ip_index = air_ref.toInterned() orelse break :rt_ptr false;
2302 const val: Value = .fromInterned(ip_index);
2303 break :rt_ptr val.isPtrRuntimeValue(zcu);
2304 };
2305
2306 switch (sema.failWithNeededComptime(block, src, .{ .simple = .container_var_init })) {
2307 error.AnalysisFail => |e| {
2308 if (sema.err != null and is_runtime_ptr) {
2309 try sema.errNote(src, sema.err.?, "threadlocal and dll imported variables have runtime-known addresses", .{});
2310 }
2311 return e;
2312 },
2313 else => |e| return e,
2314 }
2315 };
2316
2295 const val = try sema.resolveConstValue(block, src, air_ref, .{ .simple = .container_var_init });
23172296 if (val.canMutateComptimeVarState(zcu)) {
23182297 const ip = &zcu.intern_pool;
23192298 const nav = ip.getNav(sema.owner.unwrap().nav_val);
23202299 return sema.failWithContainsReferenceToComptimeVar(block, src, nav.name, "global variable", val);
23212300 }
2322
23232301 return val;
23242302}
23252303
......@@ -26506,6 +26484,7 @@ fn zirBuiltinExtern(
2650626484 const zcu = pt.zcu;
2650726485 const ip = &zcu.intern_pool;
2650826486 const extra = sema.code.extraData(Zir.Inst.BinNode, extended.operand).data;
26487 const src = block.nodeOffset(extra.node);
2650926488 const ty_src = block.builtinCallArgSrc(extra.node, 0);
2651026489 const options_src = block.builtinCallArgSrc(extra.node, 1);
2651126490
......@@ -26560,17 +26539,15 @@ fn zirBuiltinExtern(
2656026539 },
2656126540 .owner_nav = undefined, // ignored by `getExtern`
2656226541 });
26563 const extern_nav = ip.indexToKey(extern_val).@"extern".owner_nav;
2656426542
26565 return Air.internedToRef((try pt.getCoerced(Value.fromInterned(try pt.intern(.{ .ptr = .{
26566 .ty = switch (ip.indexToKey(ty.toIntern())) {
26567 .ptr_type => ty.toIntern(),
26568 .opt_type => |child_type| child_type,
26569 else => unreachable,
26570 },
26571 .base_addr = .{ .nav = extern_nav },
26572 .byte_offset = 0,
26573 } })), ty)).toIntern());
26543 const uncasted_ptr = try sema.analyzeNavRef(block, src, ip.indexToKey(extern_val).@"extern".owner_nav);
26544 // We want to cast to `ty`, but that isn't necessarily an allowed coercion.
26545 if (try sema.resolveValue(uncasted_ptr)) |uncasted_ptr_val| {
26546 const casted_ptr_val = try pt.getCoerced(uncasted_ptr_val, ty);
26547 return Air.internedToRef(casted_ptr_val.toIntern());
26548 } else {
26549 return block.addBitCast(ty, uncasted_ptr);
26550 }
2657426551}
2657526552
2657626553fn zirWorkItem(
......@@ -32037,7 +32014,20 @@ fn analyzeNavRefInner(sema: *Sema, block: *Block, src: LazySrcLoc, orig_nav_inde
3203732014 break :nav orig_nav_index;
3203832015 };
3203932016
32040 const ty, const alignment, const @"addrspace", const is_const = switch (ip.getNav(nav_index).status) {
32017 const nav_status = ip.getNav(nav_index).status;
32018
32019 const is_tlv_or_dllimport = switch (nav_status) {
32020 .unresolved => unreachable,
32021 // dllimports go straight to `fully_resolved`; the only option is threadlocal
32022 .type_resolved => |r| r.is_threadlocal,
32023 .fully_resolved => |r| switch (ip.indexToKey(r.val)) {
32024 .@"extern" => |e| e.is_threadlocal or e.is_dll_import,
32025 .variable => |v| v.is_threadlocal,
32026 else => false,
32027 },
32028 };
32029
32030 const ty, const alignment, const @"addrspace", const is_const = switch (nav_status) {
3204132031 .unresolved => unreachable,
3204232032 .type_resolved => |r| .{ r.type, r.alignment, r.@"addrspace", r.is_const },
3204332033 .fully_resolved => |r| .{ ip.typeOf(r.val), r.alignment, r.@"addrspace", zcu.navValIsConst(r.val) },
......@@ -32050,9 +32040,22 @@ fn analyzeNavRefInner(sema: *Sema, block: *Block, src: LazySrcLoc, orig_nav_inde
3205032040 .address_space = @"addrspace",
3205132041 },
3205232042 });
32043
32044 if (is_tlv_or_dllimport) {
32045 // This pointer is runtime-known; we need to emit an AIR instruction to create it.
32046 return block.addInst(.{
32047 .tag = .tlv_dllimport_ptr,
32048 .data = .{ .ty_nav = .{
32049 .ty = ptr_ty.toIntern(),
32050 .nav = nav_index,
32051 } },
32052 });
32053 }
32054
3205332055 if (is_ref) {
3205432056 try sema.maybeQueueFuncBodyAnalysis(block, src, nav_index);
3205532057 }
32058
3205632059 return Air.internedToRef((try pt.intern(.{ .ptr = .{
3205732060 .ty = ptr_ty.toIntern(),
3205832061 .base_addr = .{ .nav = nav_index },
src/Value.zig-15
......@@ -1325,21 +1325,6 @@ pub fn isLazySize(val: Value, zcu: *Zcu) bool {
13251325 };
13261326}
13271327
1328pub fn isPtrRuntimeValue(val: Value, zcu: *Zcu) bool {
1329 const ip = &zcu.intern_pool;
1330 const nav = ip.getBackingNav(val.toIntern()).unwrap() orelse return false;
1331 const nav_val = switch (ip.getNav(nav).status) {
1332 .unresolved => unreachable,
1333 .type_resolved => |r| return r.is_threadlocal,
1334 .fully_resolved => |r| r.val,
1335 };
1336 return switch (ip.indexToKey(nav_val)) {
1337 .@"extern" => |e| e.is_threadlocal or e.is_dll_import,
1338 .variable => |v| v.is_threadlocal,
1339 else => false,
1340 };
1341}
1342
13431328// Asserts that the provided start/end are in-bounds.
13441329pub fn sliceArray(
13451330 val: Value,
src/arch/aarch64/CodeGen.zig+2-1
......@@ -876,6 +876,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
876876 .is_named_enum_value => return self.fail("TODO implement is_named_enum_value", .{}),
877877 .error_set_has_value => return self.fail("TODO implement error_set_has_value", .{}),
878878 .vector_store_elem => return self.fail("TODO implement vector_store_elem", .{}),
879 .tlv_dllimport_ptr => return self.fail("TODO implement tlv_dllimport_ptr", .{}),
879880
880881 .c_va_arg => return self.fail("TODO implement c_va_arg", .{}),
881882 .c_va_copy => return self.fail("TODO implement c_va_copy", .{}),
......@@ -6168,7 +6169,7 @@ fn genTypedValue(self: *Self, val: Value) InnerError!MCValue {
61686169 .memory => |addr| .{ .memory = addr },
61696170 .load_got => |sym_index| .{ .linker_load = .{ .type = .got, .sym_index = sym_index } },
61706171 .load_direct => |sym_index| .{ .linker_load = .{ .type = .direct, .sym_index = sym_index } },
6171 .load_symbol, .load_tlv, .lea_symbol, .lea_direct => unreachable, // TODO
6172 .load_symbol, .lea_symbol, .lea_direct => unreachable, // TODO
61726173 },
61736174 .fail => |msg| return self.failMsg(msg),
61746175 };
src/arch/arm/CodeGen.zig+2-1
......@@ -865,6 +865,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
865865 .is_named_enum_value => return self.fail("TODO implement is_named_enum_value", .{}),
866866 .error_set_has_value => return self.fail("TODO implement error_set_has_value", .{}),
867867 .vector_store_elem => return self.fail("TODO implement vector_store_elem", .{}),
868 .tlv_dllimport_ptr => return self.fail("TODO implement tlv_dllimport_ptr", .{}),
868869
869870 .c_va_arg => return self.fail("TODO implement c_va_arg", .{}),
870871 .c_va_copy => return self.fail("TODO implement c_va_copy", .{}),
......@@ -6135,7 +6136,7 @@ fn genTypedValue(self: *Self, val: Value) InnerError!MCValue {
61356136 .mcv => |mcv| switch (mcv) {
61366137 .none => .none,
61376138 .undef => .undef,
6138 .load_got, .load_symbol, .load_direct, .load_tlv, .lea_symbol, .lea_direct => unreachable, // TODO
6139 .load_got, .load_symbol, .load_direct, .lea_symbol, .lea_direct => unreachable, // TODO
61396140 .immediate => |imm| .{ .immediate = @truncate(imm) },
61406141 .memory => |addr| .{ .memory = addr },
61416142 },
src/arch/riscv64/CodeGen.zig+47-44
......@@ -162,12 +162,8 @@ const MCValue = union(enum) {
162162 immediate: u64,
163163 /// The value doesn't exist in memory yet.
164164 load_symbol: SymbolOffset,
165 /// A TLV value.
166 load_tlv: u32,
167165 /// The address of the memory location not-yet-allocated by the linker.
168166 lea_symbol: SymbolOffset,
169 /// The address of a TLV value.
170 lea_tlv: u32,
171167 /// The value is in a target-specific register.
172168 register: Register,
173169 /// The value is split across two registers
......@@ -224,7 +220,6 @@ const MCValue = union(enum) {
224220 .lea_frame,
225221 .undef,
226222 .lea_symbol,
227 .lea_tlv,
228223 .air_ref,
229224 .reserved_frame,
230225 => false,
......@@ -233,7 +228,6 @@ const MCValue = union(enum) {
233228 .register_pair,
234229 .register_offset,
235230 .load_symbol,
236 .load_tlv,
237231 .indirect,
238232 => true,
239233
......@@ -254,12 +248,10 @@ const MCValue = union(enum) {
254248 .undef,
255249 .air_ref,
256250 .lea_symbol,
257 .lea_tlv,
258251 .reserved_frame,
259252 => unreachable, // not in memory
260253
261254 .load_symbol => |sym_off| .{ .lea_symbol = sym_off },
262 .load_tlv => |sym| .{ .lea_tlv = sym },
263255 .memory => |addr| .{ .immediate = addr },
264256 .load_frame => |off| .{ .lea_frame = off },
265257 .indirect => |reg_off| switch (reg_off.off) {
......@@ -281,7 +273,6 @@ const MCValue = union(enum) {
281273 .register_pair,
282274 .load_frame,
283275 .load_symbol,
284 .load_tlv,
285276 .reserved_frame,
286277 => unreachable, // not a pointer
287278
......@@ -290,7 +281,6 @@ const MCValue = union(enum) {
290281 .register_offset => |reg_off| .{ .indirect = reg_off },
291282 .lea_frame => |off| .{ .load_frame = off },
292283 .lea_symbol => |sym_off| .{ .load_symbol = sym_off },
293 .lea_tlv => |sym| .{ .load_tlv = sym },
294284 };
295285 }
296286
......@@ -308,8 +298,6 @@ const MCValue = union(enum) {
308298 .indirect,
309299 .load_symbol,
310300 .lea_symbol,
311 .lea_tlv,
312 .load_tlv,
313301 => switch (off) {
314302 0 => mcv,
315303 else => unreachable,
......@@ -367,8 +355,6 @@ const InstTracking = struct {
367355 .memory,
368356 .load_frame,
369357 .lea_frame,
370 .load_tlv,
371 .lea_tlv,
372358 .load_symbol,
373359 .lea_symbol,
374360 => result,
......@@ -424,8 +410,6 @@ const InstTracking = struct {
424410 .lea_frame,
425411 .load_symbol,
426412 .lea_symbol,
427 .load_tlv,
428 .lea_tlv,
429413 => inst_tracking.long,
430414 .dead,
431415 .register,
......@@ -454,8 +438,6 @@ const InstTracking = struct {
454438 .lea_frame,
455439 .load_symbol,
456440 .lea_symbol,
457 .load_tlv,
458 .lea_tlv,
459441 => assert(std.meta.eql(inst_tracking.long, target.long)),
460442 .load_frame,
461443 .reserved_frame,
......@@ -1665,6 +1647,8 @@ fn genBody(func: *Func, body: []const Air.Inst.Index) InnerError!void {
16651647 .wrap_errunion_payload => try func.airWrapErrUnionPayload(inst),
16661648 .wrap_errunion_err => try func.airWrapErrUnionErr(inst),
16671649
1650 .tlv_dllimport_ptr => try func.airTlvDllimportPtr(inst),
1651
16681652 .add_optimized,
16691653 .sub_optimized,
16701654 .mul_optimized,
......@@ -3620,6 +3604,50 @@ fn airWrapErrUnionErr(func: *Func, inst: Air.Inst.Index) !void {
36203604 return func.finishAir(inst, result, .{ ty_op.operand, .none, .none });
36213605}
36223606
3607fn airTlvDllimportPtr(func: *Func, inst: Air.Inst.Index) !void {
3608 const zcu = func.pt.zcu;
3609 const ip = &zcu.intern_pool;
3610 const ty_nav = func.air.instructions.items(.data)[@intFromEnum(inst)].ty_nav;
3611 const ptr_ty: Type = .fromInterned(ty_nav.ty);
3612
3613 const nav = ip.getNav(ty_nav.nav);
3614 const tlv_sym_index = if (func.bin_file.cast(.elf)) |elf_file| sym: {
3615 const zo = elf_file.zigObjectPtr().?;
3616 if (nav.getExtern(ip)) |e| {
3617 const sym = try elf_file.getGlobalSymbol(nav.name.toSlice(ip), e.lib_name.toSlice(ip));
3618 zo.symbol(sym).flags.is_extern_ptr = true;
3619 break :sym sym;
3620 }
3621 break :sym try zo.getOrCreateMetadataForNav(zcu, ty_nav.nav);
3622 } else return func.fail("TODO tlv_dllimport_ptr on {}", .{func.bin_file.tag});
3623
3624 const dest_mcv = try func.allocRegOrMem(ptr_ty, inst, true);
3625 if (dest_mcv.isRegister()) {
3626 _ = try func.addInst(.{
3627 .tag = .pseudo_load_tlv,
3628 .data = .{ .reloc = .{
3629 .register = dest_mcv.getReg().?,
3630 .atom_index = try func.owner.getSymbolIndex(func),
3631 .sym_index = tlv_sym_index,
3632 } },
3633 });
3634 } else {
3635 const tmp_reg, const tmp_lock = try func.allocReg(.int);
3636 defer func.register_manager.unlockReg(tmp_lock);
3637 _ = try func.addInst(.{
3638 .tag = .pseudo_load_tlv,
3639 .data = .{ .reloc = .{
3640 .register = tmp_reg,
3641 .atom_index = try func.owner.getSymbolIndex(func),
3642 .sym_index = tlv_sym_index,
3643 } },
3644 });
3645 try func.genCopy(ptr_ty, dest_mcv, .{ .register = tmp_reg });
3646 }
3647
3648 return func.finishAir(inst, dest_mcv, .{ .none, .none, .none });
3649}
3650
36233651fn airTry(func: *Func, inst: Air.Inst.Index) !void {
36243652 const pl_op = func.air.instructions.items(.data)[@intFromEnum(inst)].pl_op;
36253653 const extra = func.air.extraData(Air.Try, pl_op.payload);
......@@ -4494,14 +4522,12 @@ fn load(func: *Func, dst_mcv: MCValue, ptr_mcv: MCValue, ptr_ty: Type) InnerErro
44944522 .register_offset,
44954523 .lea_frame,
44964524 .lea_symbol,
4497 .lea_tlv,
44984525 => try func.genCopy(dst_ty, dst_mcv, ptr_mcv.deref()),
44994526
45004527 .memory,
45014528 .indirect,
45024529 .load_symbol,
45034530 .load_frame,
4504 .load_tlv,
45054531 => {
45064532 const addr_reg = try func.copyToTmpRegister(ptr_ty, ptr_mcv);
45074533 const addr_lock = func.register_manager.lockRegAssumeUnused(addr_reg);
......@@ -4548,14 +4574,12 @@ fn store(func: *Func, ptr_mcv: MCValue, src_mcv: MCValue, ptr_ty: Type) !void {
45484574 .register_offset,
45494575 .lea_symbol,
45504576 .lea_frame,
4551 .lea_tlv,
45524577 => try func.genCopy(src_ty, ptr_mcv.deref(), src_mcv),
45534578
45544579 .memory,
45554580 .indirect,
45564581 .load_symbol,
45574582 .load_frame,
4558 .load_tlv,
45594583 => {
45604584 const addr_reg = try func.copyToTmpRegister(ptr_ty, ptr_mcv);
45614585 const addr_lock = func.register_manager.lockRegAssumeUnused(addr_reg);
......@@ -6544,7 +6568,7 @@ fn genCopy(func: *Func, ty: Type, dst_mcv: MCValue, src_mcv: MCValue) !void {
65446568 ty,
65456569 src_mcv,
65466570 ),
6547 .load_symbol, .load_tlv => {
6571 .load_symbol => {
65486572 const addr_reg, const addr_lock = try func.allocReg(.int);
65496573 defer func.register_manager.unlockReg(addr_lock);
65506574
......@@ -7072,25 +7096,6 @@ fn genSetReg(func: *Func, ty: Type, reg: Register, src_mcv: MCValue) InnerError!
70727096 try func.genSetReg(ty, addr_reg, src_mcv.address());
70737097 try func.genSetReg(ty, reg, .{ .indirect = .{ .reg = addr_reg } });
70747098 },
7075 .lea_tlv => |sym| {
7076 const atom_index = try func.owner.getSymbolIndex(func);
7077
7078 _ = try func.addInst(.{
7079 .tag = .pseudo_load_tlv,
7080 .data = .{ .reloc = .{
7081 .register = reg,
7082 .atom_index = atom_index,
7083 .sym_index = sym,
7084 } },
7085 });
7086 },
7087 .load_tlv => {
7088 const addr_reg, const addr_lock = try func.allocReg(.int);
7089 defer func.register_manager.unlockReg(addr_lock);
7090
7091 try func.genSetReg(ty, addr_reg, src_mcv.address());
7092 try func.genSetReg(ty, reg, .{ .indirect = .{ .reg = addr_reg } });
7093 },
70947099 .air_ref => |ref| try func.genSetReg(ty, reg, try func.resolveInst(ref)),
70957100 else => return func.fail("TODO: genSetReg {s}", .{@tagName(src_mcv)}),
70967101 }
......@@ -7256,7 +7261,6 @@ fn genSetMem(
72567261 return func.genSetMem(base, disp, ty, .{ .register = reg });
72577262 },
72587263 .air_ref => |src_ref| try func.genSetMem(base, disp, ty, try func.resolveInst(src_ref)),
7259 else => return func.fail("TODO: genSetMem {s}", .{@tagName(src_mcv)}),
72607264 }
72617265}
72627266
......@@ -8190,7 +8194,6 @@ fn genTypedValue(func: *Func, val: Value) InnerError!MCValue {
81908194 .undef => unreachable,
81918195 .lea_symbol => |sym_index| .{ .lea_symbol = .{ .sym = sym_index } },
81928196 .load_symbol => |sym_index| .{ .load_symbol = .{ .sym = sym_index } },
8193 .load_tlv => |sym_index| .{ .lea_tlv = sym_index },
81948197 .immediate => |imm| .{ .immediate = imm },
81958198 .memory => |addr| .{ .memory = addr },
81968199 .load_got, .load_direct, .lea_direct => {
src/arch/sparc64/CodeGen.zig+2-1
......@@ -719,6 +719,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
719719 .is_named_enum_value => @panic("TODO implement is_named_enum_value"),
720720 .error_set_has_value => @panic("TODO implement error_set_has_value"),
721721 .vector_store_elem => @panic("TODO implement vector_store_elem"),
722 .tlv_dllimport_ptr => @panic("TODO implement tlv_dllimport_ptr"),
722723
723724 .c_va_arg => return self.fail("TODO implement c_va_arg", .{}),
724725 .c_va_copy => return self.fail("TODO implement c_va_copy", .{}),
......@@ -4088,7 +4089,7 @@ fn genTypedValue(self: *Self, val: Value) InnerError!MCValue {
40884089 .mcv => |mcv| switch (mcv) {
40894090 .none => .none,
40904091 .undef => .undef,
4091 .load_got, .load_symbol, .load_direct, .load_tlv, .lea_symbol, .lea_direct => unreachable, // TODO
4092 .load_got, .load_symbol, .load_direct, .lea_symbol, .lea_direct => unreachable, // TODO
40924093 .immediate => |imm| .{ .immediate = imm },
40934094 .memory => |addr| .{ .memory = addr },
40944095 },
src/arch/wasm/CodeGen.zig+15
......@@ -2050,6 +2050,8 @@ fn genInst(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
20502050 .error_set_has_value => cg.airErrorSetHasValue(inst),
20512051 .frame_addr => cg.airFrameAddress(inst),
20522052
2053 .tlv_dllimport_ptr => cg.airTlvDllimportPtr(inst),
2054
20532055 .assembly,
20542056 .is_err_ptr,
20552057 .is_non_err_ptr,
......@@ -7551,6 +7553,19 @@ fn airFrameAddress(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
75517553 return cg.finishAir(inst, .stack, &.{});
75527554}
75537555
7556fn airTlvDllimportPtr(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
7557 const ty_nav = cg.air.instructions.items(.data)[@intFromEnum(inst)].ty_nav;
7558 const mod = cg.pt.zcu.navFileScope(cg.owner_nav).mod.?;
7559 if (mod.single_threaded) {
7560 const result: WValue = .{ .nav_ref = .{
7561 .nav_index = ty_nav.nav,
7562 .offset = 0,
7563 } };
7564 return cg.finishAir(inst, result, &.{});
7565 }
7566 return cg.fail("TODO: thread-local variables", .{});
7567}
7568
75547569fn typeOf(cg: *CodeGen, inst: Air.Inst.Ref) Type {
75557570 const zcu = cg.pt.zcu;
75567571 return cg.air.typeOf(inst, &zcu.intern_pool);
src/arch/x86_64/CodeGen.zig+68-149
......@@ -204,12 +204,6 @@ pub const MCValue = union(enum) {
204204 /// The value is a pointer to a value referenced indirectly via GOT.
205205 /// Payload is a symbol index.
206206 lea_got: u32,
207 /// The value is a threadlocal variable.
208 /// Payload is a symbol index.
209 load_tlv: u32,
210 /// The value is a pointer to a threadlocal variable.
211 /// Payload is a symbol index.
212 lea_tlv: u32,
213207 /// The value stored at an offset from a frame index
214208 /// Payload is a frame address.
215209 load_frame: bits.FrameAddr,
......@@ -238,7 +232,6 @@ pub const MCValue = union(enum) {
238232 .lea_symbol,
239233 .lea_direct,
240234 .lea_got,
241 .lea_tlv,
242235 .lea_frame,
243236 .elementwise_regs_then_frame,
244237 .reserved_frame,
......@@ -252,7 +245,6 @@ pub const MCValue = union(enum) {
252245 .load_symbol,
253246 .load_got,
254247 .load_direct,
255 .load_tlv,
256248 .indirect,
257249 => true,
258250 .load_frame => |frame_addr| !frame_addr.index.isNamed(),
......@@ -355,7 +347,6 @@ pub const MCValue = union(enum) {
355347 .lea_symbol,
356348 .lea_direct,
357349 .lea_got,
358 .lea_tlv,
359350 .lea_frame,
360351 .elementwise_regs_then_frame,
361352 .reserved_frame,
......@@ -368,7 +359,6 @@ pub const MCValue = union(enum) {
368359 },
369360 .load_direct => |sym_index| .{ .lea_direct = sym_index },
370361 .load_got => |sym_index| .{ .lea_got = sym_index },
371 .load_tlv => |sym_index| .{ .lea_tlv = sym_index },
372362 .load_frame => |frame_addr| .{ .lea_frame = frame_addr },
373363 .load_symbol => |sym_off| .{ .lea_symbol = sym_off },
374364 };
......@@ -390,7 +380,6 @@ pub const MCValue = union(enum) {
390380 .indirect,
391381 .load_direct,
392382 .load_got,
393 .load_tlv,
394383 .load_frame,
395384 .load_symbol,
396385 .elementwise_regs_then_frame,
......@@ -402,7 +391,6 @@ pub const MCValue = union(enum) {
402391 .register_offset => |reg_off| .{ .indirect = reg_off },
403392 .lea_direct => |sym_index| .{ .load_direct = sym_index },
404393 .lea_got => |sym_index| .{ .load_got = sym_index },
405 .lea_tlv => |sym_index| .{ .load_tlv = sym_index },
406394 .lea_frame => |frame_addr| .{ .load_frame = frame_addr },
407395 .lea_symbol => |sym_index| .{ .load_symbol = sym_index },
408396 };
......@@ -430,8 +418,6 @@ pub const MCValue = union(enum) {
430418 .lea_direct,
431419 .load_got,
432420 .lea_got,
433 .load_tlv,
434 .lea_tlv,
435421 .load_frame,
436422 .load_symbol,
437423 .lea_symbol,
......@@ -469,8 +455,6 @@ pub const MCValue = union(enum) {
469455 .lea_direct,
470456 .load_got,
471457 .lea_got,
472 .load_tlv,
473 .lea_tlv,
474458 .lea_frame,
475459 .elementwise_regs_then_frame,
476460 .reserved_frame,
......@@ -555,8 +539,6 @@ pub const MCValue = union(enum) {
555539 .lea_direct => |pl| try writer.print("direct:{d}", .{pl}),
556540 .load_got => |pl| try writer.print("[got:{d}]", .{pl}),
557541 .lea_got => |pl| try writer.print("got:{d}", .{pl}),
558 .load_tlv => |pl| try writer.print("[tlv:{d}]", .{pl}),
559 .lea_tlv => |pl| try writer.print("tlv:{d}", .{pl}),
560542 .load_frame => |pl| try writer.print("[{} + 0x{x}]", .{ pl.index, pl.off }),
561543 .elementwise_regs_then_frame => |pl| try writer.print("elementwise:{d}:[{} + 0x{x}]", .{
562544 pl.regs, pl.frame_index, pl.frame_off,
......@@ -585,8 +567,6 @@ const InstTracking = struct {
585567 .lea_direct,
586568 .load_got,
587569 .lea_got,
588 .load_tlv,
589 .lea_tlv,
590570 .load_frame,
591571 .lea_frame,
592572 .load_symbol,
......@@ -688,8 +668,6 @@ const InstTracking = struct {
688668 .lea_direct,
689669 .load_got,
690670 .lea_got,
691 .load_tlv,
692 .lea_tlv,
693671 .lea_frame,
694672 .load_symbol,
695673 .lea_symbol,
......@@ -120945,6 +120923,47 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {
120945120923 };
120946120924 for (ops) |op| try op.die(cg);
120947120925 },
120926 .tlv_dllimport_ptr => switch (cg.bin_file.tag) {
120927 .elf, .macho => {
120928 const ty_nav = air_datas[@intFromEnum(inst)].ty_nav;
120929
120930 const nav = ip.getNav(ty_nav.nav);
120931 const tlv_sym_index = sym: {
120932 if (cg.bin_file.cast(.elf)) |elf_file| {
120933 const zo = elf_file.zigObjectPtr().?;
120934 if (nav.getExtern(ip)) |e| {
120935 const sym = try elf_file.getGlobalSymbol(nav.name.toSlice(ip), e.lib_name.toSlice(ip));
120936 zo.symbol(sym).flags.is_extern_ptr = true;
120937 break :sym sym;
120938 }
120939 break :sym try zo.getOrCreateMetadataForNav(zcu, ty_nav.nav);
120940 }
120941 if (cg.bin_file.cast(.macho)) |macho_file| {
120942 const zo = macho_file.getZigObject().?;
120943 if (nav.getExtern(ip)) |e| {
120944 const sym = try macho_file.getGlobalSymbol(nav.name.toSlice(ip), e.lib_name.toSlice(ip));
120945 zo.symbols.items[sym].flags.is_extern_ptr = true;
120946 break :sym sym;
120947 }
120948 break :sym try zo.getOrCreateMetadataForNav(macho_file, ty_nav.nav);
120949 }
120950 unreachable;
120951 };
120952
120953 if (cg.mod.pic) {
120954 try cg.spillRegisters(&.{ .rdi, .rax });
120955 } else {
120956 try cg.spillRegisters(&.{.rax});
120957 }
120958
120959 var slot = try cg.tempInit(.usize, .{ .lea_symbol = .{
120960 .sym_index = tlv_sym_index,
120961 } });
120962 while (try slot.toRegClass(true, .general_purpose, cg)) {}
120963 try slot.finish(inst, &.{}, &.{}, cg);
120964 },
120965 else => return cg.fail("TODO implement tlv/dllimport on {}", .{cg.bin_file.tag}),
120966 },
120948120967 .c_va_arg => try cg.airVaArg(inst),
120949120968 .c_va_copy => try cg.airVaCopy(inst),
120950120969 .c_va_end => try cg.airVaEnd(inst),
......@@ -124664,7 +124683,7 @@ fn airArrayElemVal(self: *CodeGen, inst: Air.Inst.Index) !void {
124664124683 }.to64(),
124665124684 ),
124666124685 },
124667 .memory, .load_symbol, .load_direct, .load_got, .load_tlv => switch (index_mcv) {
124686 .memory, .load_symbol, .load_direct, .load_got => switch (index_mcv) {
124668124687 .immediate => |index_imm| try self.asmMemoryImmediate(
124669124688 .{ ._, .bt },
124670124689 .{
......@@ -124729,9 +124748,8 @@ fn airArrayElemVal(self: *CodeGen, inst: Air.Inst.Index) !void {
124729124748 .load_symbol,
124730124749 .load_direct,
124731124750 .load_got,
124732 .load_tlv,
124733124751 => try self.genSetReg(addr_reg, .usize, array_mcv.address(), .{}),
124734 .lea_symbol, .lea_direct, .lea_tlv => unreachable,
124752 .lea_symbol, .lea_direct => unreachable,
124735124753 else => return self.fail("TODO airArrayElemVal_val for {s} of {}", .{
124736124754 @tagName(array_mcv), array_ty.fmt(pt),
124737124755 }),
......@@ -126611,7 +126629,6 @@ fn load(self: *CodeGen, dst_mcv: MCValue, ptr_ty: Type, ptr_mcv: MCValue) InnerE
126611126629 .lea_symbol,
126612126630 .lea_direct,
126613126631 .lea_got,
126614 .lea_tlv,
126615126632 .lea_frame,
126616126633 => try self.genCopy(dst_ty, dst_mcv, ptr_mcv.deref(), .{}),
126617126634 .memory,
......@@ -126619,7 +126636,6 @@ fn load(self: *CodeGen, dst_mcv: MCValue, ptr_ty: Type, ptr_mcv: MCValue) InnerE
126619126636 .load_symbol,
126620126637 .load_direct,
126621126638 .load_got,
126622 .load_tlv,
126623126639 .load_frame,
126624126640 => {
126625126641 const addr_reg = try self.copyToTmpRegister(ptr_ty, ptr_mcv);
......@@ -126831,7 +126847,6 @@ fn store(
126831126847 .lea_symbol,
126832126848 .lea_direct,
126833126849 .lea_got,
126834 .lea_tlv,
126835126850 .lea_frame,
126836126851 => try self.genCopy(src_ty, ptr_mcv.deref(), src_mcv, opts),
126837126852 .memory,
......@@ -126839,7 +126854,6 @@ fn store(
126839126854 .load_symbol,
126840126855 .load_direct,
126841126856 .load_got,
126842 .load_tlv,
126843126857 .load_frame,
126844126858 => {
126845126859 const addr_reg = try self.copyToTmpRegister(ptr_ty, ptr_mcv);
......@@ -127309,7 +127323,6 @@ fn genUnOpMir(self: *CodeGen, mir_tag: Mir.Inst.FixedTag, dst_ty: Type, dst_mcv:
127309127323 .lea_symbol,
127310127324 .lea_direct,
127311127325 .lea_got,
127312 .lea_tlv,
127313127326 .lea_frame,
127314127327 .elementwise_regs_then_frame,
127315127328 .reserved_frame,
......@@ -127317,7 +127330,7 @@ fn genUnOpMir(self: *CodeGen, mir_tag: Mir.Inst.FixedTag, dst_ty: Type, dst_mcv:
127317127330 => unreachable, // unmodifiable destination
127318127331 .register => |dst_reg| try self.asmRegister(mir_tag, registerAlias(dst_reg, abi_size)),
127319127332 .register_pair, .register_triple, .register_quadruple => unreachable, // unimplemented
127320 .memory, .load_symbol, .load_got, .load_direct, .load_tlv => {
127333 .memory, .load_symbol, .load_got, .load_direct => {
127321127334 const addr_reg = try self.register_manager.allocReg(null, abi.RegisterClass.gp);
127322127335 const addr_reg_lock = self.register_manager.lockRegAssumeUnused(addr_reg);
127323127336 defer self.register_manager.unlockReg(addr_reg_lock);
......@@ -128922,8 +128935,6 @@ fn genBinOp(
128922128935 .lea_direct,
128923128936 .load_got,
128924128937 .lea_got,
128925 .load_tlv,
128926 .lea_tlv,
128927128938 .lea_frame,
128928128939 => true,
128929128940 .memory => |addr| std.math.cast(i32, @as(i64, @bitCast(addr))) == null,
......@@ -128983,8 +128994,6 @@ fn genBinOp(
128983128994 .lea_direct,
128984128995 .load_got,
128985128996 .lea_got,
128986 .load_tlv,
128987 .lea_tlv,
128988128997 .lea_frame,
128989128998 .elementwise_regs_then_frame,
128990128999 .reserved_frame,
......@@ -130167,7 +130176,6 @@ fn genBinOpMir(
130167130176 .register_mask,
130168130177 .lea_direct,
130169130178 .lea_got,
130170 .lea_tlv,
130171130179 .lea_frame,
130172130180 .lea_symbol,
130173130181 .elementwise_regs_then_frame,
......@@ -130265,8 +130273,6 @@ fn genBinOpMir(
130265130273 .lea_direct,
130266130274 .load_got,
130267130275 .lea_got,
130268 .load_tlv,
130269 .lea_tlv,
130270130276 .load_frame,
130271130277 .lea_frame,
130272130278 => {
......@@ -130304,7 +130310,6 @@ fn genBinOpMir(
130304130310 .lea_symbol,
130305130311 .lea_direct,
130306130312 .lea_got,
130307 .lea_tlv,
130308130313 .lea_frame,
130309130314 => {
130310130315 assert(off == 0);
......@@ -130320,7 +130325,6 @@ fn genBinOpMir(
130320130325 .load_symbol,
130321130326 .load_direct,
130322130327 .load_got,
130323 .load_tlv,
130324130328 => {
130325130329 const ptr_ty = try pt.singleConstPtrType(ty);
130326130330 const addr_reg = try self.copyToTmpRegister(ptr_ty, src_mcv.address());
......@@ -130340,13 +130344,13 @@ fn genBinOpMir(
130340130344 }
130341130345 }
130342130346 },
130343 .memory, .indirect, .load_symbol, .load_got, .load_direct, .load_tlv, .load_frame => {
130347 .memory, .indirect, .load_symbol, .load_got, .load_direct, .load_frame => {
130344130348 const OpInfo = ?struct { addr_reg: Register, addr_lock: RegisterLock };
130345130349 const limb_abi_size: u32 = @min(abi_size, 8);
130346130350
130347130351 const dst_info: OpInfo = switch (dst_mcv) {
130348130352 else => unreachable,
130349 .memory, .load_symbol, .load_got, .load_direct, .load_tlv => dst: {
130353 .memory, .load_symbol, .load_got, .load_direct => dst: {
130350130354 const dst_addr_reg =
130351130355 (try self.register_manager.allocReg(null, abi.RegisterClass.gp)).to64();
130352130356 const dst_addr_lock = self.register_manager.lockRegAssumeUnused(dst_addr_reg);
......@@ -130384,17 +130388,16 @@ fn genBinOpMir(
130384130388 .indirect,
130385130389 .lea_direct,
130386130390 .lea_got,
130387 .lea_tlv,
130388130391 .load_frame,
130389130392 .lea_frame,
130390130393 .lea_symbol,
130391130394 => null,
130392 .memory, .load_symbol, .load_got, .load_direct, .load_tlv => src: {
130395 .memory, .load_symbol, .load_got, .load_direct => src: {
130393130396 switch (resolved_src_mcv) {
130394130397 .memory => |addr| if (std.math.cast(i32, @as(i64, @bitCast(addr))) != null and
130395130398 std.math.cast(i32, @as(i64, @bitCast(addr)) + abi_size - limb_abi_size) != null)
130396130399 break :src null,
130397 .load_symbol, .load_got, .load_direct, .load_tlv => {},
130400 .load_symbol, .load_got, .load_direct => {},
130398130401 else => unreachable,
130399130402 }
130400130403
......@@ -130437,7 +130440,6 @@ fn genBinOpMir(
130437130440 .load_symbol,
130438130441 .load_got,
130439130442 .load_direct,
130440 .load_tlv,
130441130443 => .{
130442130444 .base = .{ .reg = dst_info.?.addr_reg },
130443130445 .mod = .{ .rm = .{
......@@ -130533,8 +130535,6 @@ fn genBinOpMir(
130533130535 .lea_direct,
130534130536 .load_got,
130535130537 .lea_got,
130536 .load_tlv,
130537 .lea_tlv,
130538130538 .load_frame,
130539130539 .lea_frame,
130540130540 => {
......@@ -130549,7 +130549,6 @@ fn genBinOpMir(
130549130549 .lea_symbol,
130550130550 .lea_direct,
130551130551 .lea_got,
130552 .lea_tlv,
130553130552 .lea_frame,
130554130553 => switch (limb_i) {
130555130554 0 => resolved_src_mcv,
......@@ -130601,7 +130600,6 @@ fn genIntMulComplexOpMir(self: *CodeGen, dst_ty: Type, dst_mcv: MCValue, src_mcv
130601130600 .lea_symbol,
130602130601 .lea_direct,
130603130602 .lea_got,
130604 .lea_tlv,
130605130603 .lea_frame,
130606130604 .elementwise_regs_then_frame,
130607130605 .reserved_frame,
......@@ -130666,8 +130664,6 @@ fn genIntMulComplexOpMir(self: *CodeGen, dst_ty: Type, dst_mcv: MCValue, src_mcv
130666130664 .lea_direct,
130667130665 .load_got,
130668130666 .lea_got,
130669 .load_tlv,
130670 .lea_tlv,
130671130667 .lea_frame,
130672130668 => {
130673130669 const src_reg = try self.copyToTmpRegister(dst_ty, resolved_src_mcv);
......@@ -130723,7 +130719,7 @@ fn genIntMulComplexOpMir(self: *CodeGen, dst_ty: Type, dst_mcv: MCValue, src_mcv
130723130719 }
130724130720 },
130725130721 .register_pair, .register_triple, .register_quadruple => unreachable, // unimplemented
130726 .memory, .indirect, .load_symbol, .load_direct, .load_got, .load_tlv, .load_frame => {
130722 .memory, .indirect, .load_symbol, .load_direct, .load_got, .load_frame => {
130727130723 const tmp_reg = try self.copyToTmpRegister(dst_ty, dst_mcv);
130728130724 const tmp_mcv = MCValue{ .register = tmp_reg };
130729130725 const tmp_lock = self.register_manager.lockRegAssumeUnused(tmp_reg);
......@@ -130899,7 +130895,7 @@ fn genLocalDebugInfo(
130899130895 .disp = sym_off.off,
130900130896 } },
130901130897 }),
130902 .lea_direct, .lea_got, .lea_tlv => |sym_index| try self.asmAirMemory(.dbg_local, inst, .{
130898 .lea_direct, .lea_got => |sym_index| try self.asmAirMemory(.dbg_local, inst, .{
130903130899 .base = .{ .reloc = sym_index },
130904130900 .mod = .{ .rm = .{ .size = .qword } },
130905130901 }),
......@@ -131548,7 +131544,6 @@ fn airCmp(self: *CodeGen, inst: Air.Inst.Index, op: std.math.CompareOperator) !v
131548131544 .indirect,
131549131545 .lea_direct,
131550131546 .lea_got,
131551 .lea_tlv,
131552131547 .lea_frame,
131553131548 .lea_symbol,
131554131549 .elementwise_regs_then_frame,
......@@ -131556,7 +131551,7 @@ fn airCmp(self: *CodeGen, inst: Air.Inst.Index, op: std.math.CompareOperator) !v
131556131551 .air_ref,
131557131552 => unreachable,
131558131553 .register, .register_pair, .register_triple, .register_quadruple, .load_frame => null,
131559 .memory, .load_symbol, .load_got, .load_direct, .load_tlv => dst: {
131554 .memory, .load_symbol, .load_got, .load_direct => dst: {
131560131555 switch (resolved_dst_mcv) {
131561131556 .memory => |addr| if (std.math.cast(
131562131557 i32,
......@@ -131565,7 +131560,7 @@ fn airCmp(self: *CodeGen, inst: Air.Inst.Index, op: std.math.CompareOperator) !v
131565131560 i32,
131566131561 @as(i64, @bitCast(addr)) + abi_size - 8,
131567131562 ) != null) break :dst null,
131568 .load_symbol, .load_got, .load_direct, .load_tlv => {},
131563 .load_symbol, .load_got, .load_direct => {},
131569131564 else => unreachable,
131570131565 }
131571131566
......@@ -131605,14 +131600,13 @@ fn airCmp(self: *CodeGen, inst: Air.Inst.Index, op: std.math.CompareOperator) !v
131605131600 .lea_symbol,
131606131601 .lea_direct,
131607131602 .lea_got,
131608 .lea_tlv,
131609131603 .lea_frame,
131610131604 .elementwise_regs_then_frame,
131611131605 .reserved_frame,
131612131606 .air_ref,
131613131607 => unreachable,
131614131608 .register_pair, .register_triple, .register_quadruple, .load_frame => null,
131615 .memory, .load_symbol, .load_got, .load_direct, .load_tlv => src: {
131609 .memory, .load_symbol, .load_got, .load_direct => src: {
131616131610 switch (resolved_src_mcv) {
131617131611 .memory => |addr| if (std.math.cast(
131618131612 i32,
......@@ -131621,7 +131615,7 @@ fn airCmp(self: *CodeGen, inst: Air.Inst.Index, op: std.math.CompareOperator) !v
131621131615 i32,
131622131616 @as(i64, @bitCast(addr)) + abi_size - 8,
131623131617 ) != null) break :src null,
131624 .load_symbol, .load_got, .load_direct, .load_tlv => {},
131618 .load_symbol, .load_got, .load_direct => {},
131625131619 else => unreachable,
131626131620 }
131627131621
......@@ -132011,7 +132005,6 @@ fn isNull(self: *CodeGen, inst: Air.Inst.Index, opt_ty: Type, opt_mcv: MCValue)
132011132005 .register_mask,
132012132006 .lea_direct,
132013132007 .lea_got,
132014 .lea_tlv,
132015132008 .lea_symbol,
132016132009 .elementwise_regs_then_frame,
132017132010 .reserved_frame,
......@@ -132063,7 +132056,6 @@ fn isNull(self: *CodeGen, inst: Air.Inst.Index, opt_ty: Type, opt_mcv: MCValue)
132063132056 .load_symbol,
132064132057 .load_got,
132065132058 .load_direct,
132066 .load_tlv,
132067132059 => {
132068132060 const addr_reg = (try self.register_manager.allocReg(null, abi.RegisterClass.gp)).to64();
132069132061 const addr_reg_lock = self.register_manager.lockRegAssumeUnused(addr_reg);
......@@ -133105,7 +133097,7 @@ fn airAsm(self: *CodeGen, inst: Air.Inst.Index) !void {
133105133097 .memory => |addr| if (std.math.cast(i32, @as(i64, @bitCast(addr)))) |_|
133106133098 break :arg input_mcv,
133107133099 .indirect, .load_frame => break :arg input_mcv,
133108 .load_symbol, .load_direct, .load_got, .load_tlv => {},
133100 .load_symbol, .load_direct, .load_got => {},
133109133101 else => {
133110133102 const temp_mcv = try self.allocTempRegOrMem(ty, false);
133111133103 try self.genCopy(ty, temp_mcv, input_mcv, .{});
......@@ -134075,7 +134067,6 @@ fn genCopy(self: *CodeGen, ty: Type, dst_mcv: MCValue, src_mcv: MCValue, opts: C
134075134067 .register_mask,
134076134068 .lea_direct,
134077134069 .lea_got,
134078 .lea_tlv,
134079134070 .lea_frame,
134080134071 .lea_symbol,
134081134072 .elementwise_regs_then_frame,
......@@ -134159,7 +134150,7 @@ fn genCopy(self: *CodeGen, ty: Type, dst_mcv: MCValue, src_mcv: MCValue, opts: C
134159134150 }
134160134151 return;
134161134152 },
134162 .load_symbol, .load_direct, .load_got, .load_tlv => {
134153 .load_symbol, .load_direct, .load_got => {
134163134154 const src_addr_reg =
134164134155 (try self.register_manager.allocReg(null, abi.RegisterClass.gp)).to64();
134165134156 const src_addr_lock = self.register_manager.lockRegAssumeUnused(src_addr_reg);
......@@ -134192,7 +134183,7 @@ fn genCopy(self: *CodeGen, ty: Type, dst_mcv: MCValue, src_mcv: MCValue, opts: C
134192134183 .undef => if (opts.safety and part_i > 0) .{ .register = dst_regs[0] } else .undef,
134193134184 dst_tag => |src_regs| .{ .register = src_regs[part_i] },
134194134185 .memory, .indirect, .load_frame => src_mcv.address().offset(part_disp).deref(),
134195 .load_symbol, .load_direct, .load_got, .load_tlv => .{ .indirect = .{
134186 .load_symbol, .load_direct, .load_got => .{ .indirect = .{
134196134187 .reg = src_info.?.addr_reg,
134197134188 .off = part_disp,
134198134189 } },
......@@ -134213,11 +134204,11 @@ fn genCopy(self: *CodeGen, ty: Type, dst_mcv: MCValue, src_mcv: MCValue, opts: C
134213134204 src_mcv,
134214134205 opts,
134215134206 ),
134216 .memory, .load_symbol, .load_direct, .load_got, .load_tlv => {
134207 .memory, .load_symbol, .load_direct, .load_got => {
134217134208 switch (dst_mcv) {
134218134209 .memory => |addr| if (std.math.cast(i32, @as(i64, @bitCast(addr)))) |small_addr|
134219134210 return self.genSetMem(.{ .reg = .ds }, small_addr, ty, src_mcv, opts),
134220 .load_symbol, .load_direct, .load_got, .load_tlv => {},
134211 .load_symbol, .load_direct, .load_got => {},
134221134212 else => unreachable,
134222134213 }
134223134214
......@@ -134639,7 +134630,7 @@ fn genSetReg(
134639134630 if (src_reg_mask.info.inverted) try self.asmRegister(.{ ._, .not }, registerAlias(bits_reg, abi_size));
134640134631 try self.genSetReg(dst_reg, ty, .{ .register = bits_reg }, .{});
134641134632 },
134642 .memory, .load_symbol, .load_direct, .load_got, .load_tlv => {
134633 .memory, .load_symbol, .load_direct, .load_got => {
134643134634 switch (src_mcv) {
134644134635 .memory => |addr| if (std.math.cast(i32, @as(i64, @bitCast(addr)))) |small_addr|
134645134636 return (try self.moveStrategy(
......@@ -134683,7 +134674,7 @@ fn genSetReg(
134683134674 .segment, .mmx, .ip, .cr, .dr => unreachable,
134684134675 .x87, .sse => {},
134685134676 },
134686 .load_got, .load_tlv => {},
134677 .load_got => {},
134687134678 else => unreachable,
134688134679 }
134689134680
......@@ -134734,7 +134725,6 @@ fn genSetReg(
134734134725 .payload = try self.addExtra(bits.SymbolOffset{ .sym_index = sym_index }),
134735134726 } },
134736134727 }),
134737 .lea_tlv => unreachable, // TODO: remove this
134738134728 .air_ref => |src_ref| try self.genSetReg(dst_reg, ty, try self.resolveInst(src_ref), opts),
134739134729 }
134740134730}
......@@ -134952,8 +134942,6 @@ fn genSetMem(
134952134942 .lea_direct,
134953134943 .load_got,
134954134944 .lea_got,
134955 .load_tlv,
134956 .lea_tlv,
134957134945 .load_frame,
134958134946 .lea_frame,
134959134947 .load_symbol,
......@@ -138121,11 +138109,7 @@ fn airAggregateInit(self: *CodeGen, inst: Air.Inst.Index) !void {
138121138109 const elem_byte_off: i32 = @intCast(elem_off / elem_abi_bits * elem_abi_size);
138122138110 const elem_bit_off = elem_off % elem_abi_bits;
138123138111 const elem_mcv = try self.resolveInst(elem);
138124 const mat_elem_mcv = switch (elem_mcv) {
138125 .load_tlv => |sym_index| MCValue{ .lea_tlv = sym_index },
138126 else => elem_mcv,
138127 };
138128 const elem_lock = switch (mat_elem_mcv) {
138112 const elem_lock = switch (elem_mcv) {
138129138113 .register => |reg| self.register_manager.lockReg(reg),
138130138114 .immediate => |imm| lock: {
138131138115 if (imm == 0) continue;
......@@ -138137,7 +138121,7 @@ fn airAggregateInit(self: *CodeGen, inst: Air.Inst.Index) !void {
138137138121
138138138122 const elem_extra_bits = self.regExtraBits(elem_ty);
138139138123 {
138140 const temp_reg = try self.copyToTmpRegister(elem_ty, mat_elem_mcv);
138124 const temp_reg = try self.copyToTmpRegister(elem_ty, elem_mcv);
138141138125 const temp_alias = registerAlias(temp_reg, elem_abi_size);
138142138126 const temp_lock = self.register_manager.lockRegAssumeUnused(temp_reg);
138143138127 defer self.register_manager.unlockReg(temp_lock);
......@@ -138160,7 +138144,7 @@ fn airAggregateInit(self: *CodeGen, inst: Air.Inst.Index) !void {
138160138144 );
138161138145 }
138162138146 if (elem_bit_off > elem_extra_bits) {
138163 const temp_reg = try self.copyToTmpRegister(elem_ty, mat_elem_mcv);
138147 const temp_reg = try self.copyToTmpRegister(elem_ty, elem_mcv);
138164138148 const temp_alias = registerAlias(temp_reg, elem_abi_size);
138165138149 const temp_lock = self.register_manager.lockRegAssumeUnused(temp_reg);
138166138150 defer self.register_manager.unlockReg(temp_lock);
......@@ -138192,11 +138176,7 @@ fn airAggregateInit(self: *CodeGen, inst: Air.Inst.Index) !void {
138192138176 const elem_ty = result_ty.fieldType(elem_i, zcu);
138193138177 const elem_off: i32 = @intCast(result_ty.structFieldOffset(elem_i, zcu));
138194138178 const elem_mcv = try self.resolveInst(elem);
138195 const mat_elem_mcv = switch (elem_mcv) {
138196 .load_tlv => |sym_index| MCValue{ .lea_tlv = sym_index },
138197 else => elem_mcv,
138198 };
138199 try self.genSetMem(.{ .frame = frame_index }, elem_off, elem_ty, mat_elem_mcv, .{});
138179 try self.genSetMem(.{ .frame = frame_index }, elem_off, elem_ty, elem_mcv, .{});
138200138180 }
138201138181 break :result .{ .load_frame = .{ .index = frame_index } };
138202138182 },
......@@ -138239,16 +138219,12 @@ fn airAggregateInit(self: *CodeGen, inst: Air.Inst.Index) !void {
138239138219
138240138220 for (elements, 0..) |elem, elem_i| {
138241138221 const elem_mcv = try self.resolveInst(elem);
138242 const mat_elem_mcv = switch (elem_mcv) {
138243 .load_tlv => |sym_index| MCValue{ .lea_tlv = sym_index },
138244 else => elem_mcv,
138245 };
138246138222 const elem_off: i32 = @intCast(elem_size * elem_i);
138247138223 try self.genSetMem(
138248138224 .{ .frame = frame_index },
138249138225 elem_off,
138250138226 elem_ty,
138251 mat_elem_mcv,
138227 elem_mcv,
138252138228 .{},
138253138229 );
138254138230 }
......@@ -138744,32 +138720,7 @@ fn resolveInst(self: *CodeGen, ref: Air.Inst.Ref) InnerError!MCValue {
138744138720 const mcv: MCValue = if (ref.toIndex()) |inst| mcv: {
138745138721 break :mcv self.inst_tracking.getPtr(inst).?.short;
138746138722 } else mcv: {
138747 const const_mcv = try self.genTypedValue(.fromInterned(ref.toInterned().?));
138748 switch (const_mcv) {
138749 .lea_tlv => |tlv_sym| switch (self.bin_file.tag) {
138750 .elf, .macho => {
138751 if (self.mod.pic) {
138752 try self.spillRegisters(&.{ .rdi, .rax });
138753 } else {
138754 try self.spillRegisters(&.{.rax});
138755 }
138756 const frame_index = try self.allocFrameIndex(.init(.{
138757 .size = 8,
138758 .alignment = .@"8",
138759 }));
138760 try self.genSetMem(
138761 .{ .frame = frame_index },
138762 0,
138763 .usize,
138764 .{ .lea_symbol = .{ .sym_index = tlv_sym } },
138765 .{},
138766 );
138767 break :mcv .{ .load_frame = .{ .index = frame_index } };
138768 },
138769 else => break :mcv const_mcv,
138770 },
138771 else => break :mcv const_mcv,
138772 }
138723 break :mcv try self.genTypedValue(.fromInterned(ref.toInterned().?));
138773138724 };
138774138725
138775138726 switch (mcv) {
......@@ -138819,7 +138770,6 @@ fn genResult(self: *CodeGen, res: codegen.GenResult) InnerError!MCValue {
138819138770 .load_direct => |sym_index| .{ .load_direct = sym_index },
138820138771 .lea_direct => |sym_index| .{ .lea_direct = sym_index },
138821138772 .load_got => |sym_index| .{ .lea_got = sym_index },
138822 .load_tlv => |sym_index| .{ .lea_tlv = sym_index },
138823138773 },
138824138774 .fail => |msg| return self.failMsg(msg),
138825138775 };
......@@ -139686,8 +139636,6 @@ const Temp = struct {
139686139636 .lea_direct,
139687139637 .load_got,
139688139638 .lea_got,
139689 .load_tlv,
139690 .lea_tlv,
139691139639 .lea_frame,
139692139640 .elementwise_regs_then_frame,
139693139641 .reserved_frame,
......@@ -140133,7 +140081,6 @@ const Temp = struct {
140133140081 .register_offset,
140134140082 .lea_direct,
140135140083 .lea_got,
140136 .lea_tlv,
140137140084 .lea_frame,
140138140085 => return false,
140139140086 .memory,
......@@ -140141,7 +140088,6 @@ const Temp = struct {
140141140088 .load_symbol,
140142140089 .load_direct,
140143140090 .load_got,
140144 .load_tlv,
140145140091 .load_frame,
140146140092 => return temp.toRegClass(true, .general_purpose, cg),
140147140093 .lea_symbol => |sym_off| {
......@@ -145048,34 +144994,7 @@ fn tempFromOperand(cg: *CodeGen, op_ref: Air.Inst.Ref, op_dies: bool) InnerError
145048144994
145049144995 if (op_ref.toIndex()) |op_inst| return .{ .index = op_inst };
145050144996 const val = op_ref.toInterned().?;
145051 return cg.tempInit(.fromInterned(ip.typeOf(val)), init: {
145052 const const_mcv = try cg.genTypedValue(.fromInterned(val));
145053 switch (const_mcv) {
145054 .lea_tlv => |tlv_sym| switch (cg.bin_file.tag) {
145055 .elf, .macho => {
145056 if (cg.mod.pic) {
145057 try cg.spillRegisters(&.{ .rdi, .rax });
145058 } else {
145059 try cg.spillRegisters(&.{.rax});
145060 }
145061 const frame_index = try cg.allocFrameIndex(.init(.{
145062 .size = 8,
145063 .alignment = .@"8",
145064 }));
145065 try cg.genSetMem(
145066 .{ .frame = frame_index },
145067 0,
145068 .usize,
145069 .{ .lea_symbol = .{ .sym_index = tlv_sym } },
145070 .{},
145071 );
145072 break :init .{ .load_frame = .{ .index = frame_index } };
145073 },
145074 else => break :init const_mcv,
145075 },
145076 else => break :init const_mcv,
145077 }
145078 });
144997 return cg.tempInit(.fromInterned(ip.typeOf(val)), try cg.genTypedValue(.fromInterned(val)));
145079144998}
145080144999
145081145000fn tempsFromOperandsInner(
src/codegen.zig+4-14
......@@ -818,10 +818,6 @@ pub const GenResult = union(enum) {
818818 /// The bit-width of the immediate may be smaller than `u64`. For example, on 32-bit targets
819819 /// such as ARM, the immediate will never exceed 32-bits.
820820 immediate: u64,
821 /// Threadlocal variable with address deferred until the linker allocates
822 /// everything in virtual memory.
823 /// Payload is a symbol index.
824 load_tlv: u32,
825821 /// Decl with address deferred until the linker allocates everything in virtual memory.
826822 /// Payload is a symbol index.
827823 load_direct: u32,
......@@ -883,13 +879,13 @@ fn genNavRef(
883879 }
884880
885881 const nav = ip.getNav(nav_index);
882 assert(!nav.isThreadlocal(ip));
886883
887 const is_extern, const lib_name, const is_threadlocal = if (nav.getExtern(ip)) |e|
888 .{ true, e.lib_name, e.is_threadlocal }
884 const is_extern, const lib_name = if (nav.getExtern(ip)) |e|
885 .{ true, e.lib_name }
889886 else
890 .{ false, .none, nav.isThreadlocal(ip) };
887 .{ false, .none };
891888
892 const single_threaded = zcu.navFileScope(nav_index).mod.?.single_threaded;
893889 const name = nav.name;
894890 if (lf.cast(.elf)) |elf_file| {
895891 const zo = elf_file.zigObjectPtr().?;
......@@ -899,9 +895,6 @@ fn genNavRef(
899895 return .{ .mcv = .{ .lea_symbol = sym_index } };
900896 }
901897 const sym_index = try zo.getOrCreateMetadataForNav(zcu, nav_index);
902 if (!single_threaded and is_threadlocal) {
903 return .{ .mcv = .{ .load_tlv = sym_index } };
904 }
905898 return .{ .mcv = .{ .lea_symbol = sym_index } };
906899 } else if (lf.cast(.macho)) |macho_file| {
907900 const zo = macho_file.getZigObject().?;
......@@ -912,9 +905,6 @@ fn genNavRef(
912905 }
913906 const sym_index = try zo.getOrCreateMetadataForNav(macho_file, nav_index);
914907 const sym = zo.symbols.items[sym_index];
915 if (!single_threaded and is_threadlocal) {
916 return .{ .mcv = .{ .load_tlv = sym.nlist_idx } };
917 }
918908 return .{ .mcv = .{ .lea_symbol = sym.nlist_idx } };
919909 } else if (lf.cast(.coff)) |coff_file| {
920910 if (is_extern) {
src/codegen/c.zig+13
......@@ -3453,6 +3453,8 @@ fn genBodyInner(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail,
34533453 .error_set_has_value => return f.fail("TODO: C backend: implement error_set_has_value", .{}),
34543454 .vector_store_elem => return f.fail("TODO: C backend: implement vector_store_elem", .{}),
34553455
3456 .tlv_dllimport_ptr => try airTlvDllimportPtr(f, inst),
3457
34563458 .c_va_start => try airCVaStart(f, inst),
34573459 .c_va_arg => try airCVaArg(f, inst),
34583460 .c_va_end => try airCVaEnd(f, inst),
......@@ -7617,6 +7619,17 @@ fn airMulAdd(f: *Function, inst: Air.Inst.Index) !CValue {
76177619 return local;
76187620}
76197621
7622fn airTlvDllimportPtr(f: *Function, inst: Air.Inst.Index) !CValue {
7623 const ty_nav = f.air.instructions.items(.data)[@intFromEnum(inst)].ty_nav;
7624 const writer = f.object.writer();
7625 const local = try f.allocLocal(inst, .fromInterned(ty_nav.ty));
7626 try f.writeCValue(writer, local, .Other);
7627 try writer.writeAll(" = ");
7628 try f.object.dg.renderNav(writer, ty_nav.nav, .Other);
7629 try writer.writeAll(";\n");
7630 return local;
7631}
7632
76207633fn airCVaStart(f: *Function, inst: Air.Inst.Index) !CValue {
76217634 const pt = f.object.dg.pt;
76227635 const zcu = pt.zcu;
src/codegen/llvm.zig+9
......@@ -5015,6 +5015,8 @@ pub const FuncGen = struct {
50155015
50165016 .vector_store_elem => try self.airVectorStoreElem(inst),
50175017
5018 .tlv_dllimport_ptr => try self.airTlvDllimportPtr(inst),
5019
50185020 .inferred_alloc, .inferred_alloc_comptime => unreachable,
50195021
50205022 .dbg_stmt => try self.airDbgStmt(inst),
......@@ -8112,6 +8114,13 @@ pub const FuncGen = struct {
81128114 return .none;
81138115 }
81148116
8117 fn airTlvDllimportPtr(fg: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
8118 const o = fg.ng.object;
8119 const ty_nav = fg.air.instructions.items(.data)[@intFromEnum(inst)].ty_nav;
8120 const llvm_ptr_const = try o.lowerNavRefValue(ty_nav.nav);
8121 return llvm_ptr_const.toValue();
8122 }
8123
81158124 fn airMin(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
81168125 const o = self.ng.object;
81178126 const zcu = o.pt.zcu;
src/print_air.zig+8
......@@ -320,6 +320,7 @@ const Writer = struct {
320320 .reduce, .reduce_optimized => try w.writeReduce(s, inst),
321321 .cmp_vector, .cmp_vector_optimized => try w.writeCmpVector(s, inst),
322322 .vector_store_elem => try w.writeVectorStoreElem(s, inst),
323 .tlv_dllimport_ptr => try w.writeTlvDllimportPtr(s, inst),
323324
324325 .work_item_id,
325326 .work_group_size,
......@@ -552,6 +553,13 @@ const Writer = struct {
552553 try w.writeOperand(s, inst, 2, extra.rhs);
553554 }
554555
556 fn writeTlvDllimportPtr(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {
557 const ip = &w.pt.zcu.intern_pool;
558 const ty_nav = w.air.instructions.items(.data)[@intFromEnum(inst)].ty_nav;
559 try w.writeType(s, .fromInterned(ty_nav.ty));
560 try s.print(", '{}'", .{ip.getNav(ty_nav.nav).fqn.fmt(ip)});
561 }
562
555563 fn writeAtomicLoad(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {
556564 const atomic_load = w.air.instructions.items(.data)[@intFromEnum(inst)].atomic_load;
557565
test/behavior/threadlocal.zig+4
......@@ -7,6 +7,8 @@ test "thread local variable" {
77 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
88 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
99 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
10 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
11 if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt == .coff) return error.SkipZigTest; // TODO
1012
1113 if (builtin.zig_backend == .stage2_x86_64 and builtin.os.tag == .macos) {
1214 // Fails due to register hazards.
......@@ -26,6 +28,7 @@ test "pointer to thread local array" {
2628 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
2729 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
2830 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
31 if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt == .coff) return error.SkipZigTest; // TODO
2932
3033 const s = "Hello world";
3134 @memcpy(buffer[0..s.len], s);
......@@ -40,6 +43,7 @@ test "reference a global threadlocal variable" {
4043 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
4144 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
4245 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
46 if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt == .coff) return error.SkipZigTest; // TODO
4347
4448 _ = nrfx_uart_rx(&g_uart0);
4549}
test/cases/compile_errors/address_of_threadlocal_not_comptime_known.zig-3
......@@ -6,9 +6,6 @@ pub export fn entry() void {
66}
77
88// error
9// backend=stage2
10// target=native
119//
1210// :2:36: error: unable to resolve comptime value
1311// :2:36: note: initializer of container-level variable must be comptime-known
14// :2:36: note: threadlocal and dll imported variables have runtime-known addresses
test/cases/compile_errors/builtin_extern_in_comptime_scope.zig-4
......@@ -7,12 +7,8 @@ pub export fn entry2() void {
77 _ = foo_dll;
88}
99// error
10// backend=stage2
11// target=native
1210//
1311// :1:16: error: unable to resolve comptime value
1412// :1:16: note: initializer of container-level variable must be comptime-known
15// :1:16: note: threadlocal and dll imported variables have runtime-known addresses
1613// :2:17: error: unable to resolve comptime value
1714// :2:17: note: initializer of container-level variable must be comptime-known
18// :2:17: note: threadlocal and dll imported variables have runtime-known addresses