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_...@@ -1530,6 +1530,12 @@ fn handleSegfaultWindows(info: *windows.EXCEPTION_POINTERS) callconv(.winapi) c_
1530}1530}
15311531
1532fn handleSegfaultWindowsExtra(info: *windows.EXCEPTION_POINTERS, msg: u8, label: ?[]const u8) noreturn {1532fn 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
1533 comptime assert(windows.CONTEXT != void);1539 comptime assert(windows.CONTEXT != void);
1534 nosuspend switch (panic_stage) {1540 nosuspend switch (panic_stage) {
1535 0 => {1541 0 => {
src/Air.zig+18
...@@ -849,6 +849,17 @@ pub const Inst = struct {...@@ -849,6 +849,17 @@ pub const Inst = struct {
849 /// Uses the `vector_store_elem` field.849 /// Uses the `vector_store_elem` field.
850 vector_store_elem,850 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
852 /// Implements @cVaArg builtin.863 /// Implements @cVaArg builtin.
853 /// Uses the `ty_op` field.864 /// Uses the `ty_op` field.
854 c_va_arg,865 c_va_arg,
...@@ -1150,6 +1161,10 @@ pub const Inst = struct {...@@ -1150,6 +1161,10 @@ pub const Inst = struct {
1150 // Index into a different array.1161 // Index into a different array.
1151 payload: u32,1162 payload: u32,
1152 },1163 },
1164 ty_nav: struct {
1165 ty: InternPool.Index,
1166 nav: InternPool.Nav.Index,
1167 },
1153 inferred_alloc_comptime: InferredAllocComptime,1168 inferred_alloc_comptime: InferredAllocComptime,
1154 inferred_alloc: InferredAlloc,1169 inferred_alloc: InferredAlloc,
11551170
...@@ -1604,6 +1619,8 @@ pub fn typeOfIndex(air: *const Air, inst: Air.Inst.Index, ip: *const InternPool)...@@ -1604,6 +1619,8 @@ pub fn typeOfIndex(air: *const Air, inst: Air.Inst.Index, ip: *const InternPool)
1604 return Type.fromInterned(ip.indexToKey(err_union_ty.ip_index).error_union_type.payload_type);1619 return Type.fromInterned(ip.indexToKey(err_union_ty.ip_index).error_union_type.payload_type);
1605 },1620 },
16061621
1622 .tlv_dllimport_ptr => return .fromInterned(datas[@intFromEnum(inst)].ty_nav.ty),
1623
1607 .work_item_id,1624 .work_item_id,
1608 .work_group_size,1625 .work_group_size,
1609 .work_group_id,1626 .work_group_id,
...@@ -1876,6 +1893,7 @@ pub fn mustLower(air: Air, inst: Air.Inst.Index, ip: *const InternPool) bool {...@@ -1876,6 +1893,7 @@ pub fn mustLower(air: Air, inst: Air.Inst.Index, ip: *const InternPool) bool {
1876 .err_return_trace,1893 .err_return_trace,
1877 .addrspace_cast,1894 .addrspace_cast,
1878 .save_err_return_trace_index,1895 .save_err_return_trace_index,
1896 .tlv_dllimport_ptr,
1879 .work_item_id,1897 .work_item_id,
1880 .work_group_size,1898 .work_group_size,
1881 .work_group_id,1899 .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 {...@@ -311,6 +311,10 @@ fn checkBody(air: Air, body: []const Air.Inst.Index, zcu: *Zcu) bool {
311 if (!checkRef(bin.rhs, zcu)) return false;311 if (!checkRef(bin.rhs, zcu)) return false;
312 },312 },
313313
314 .tlv_dllimport_ptr => {
315 if (!checkType(.fromInterned(data.ty_nav.ty), zcu)) return false;
316 },
317
314 .select,318 .select,
315 .mul_add,319 .mul_add,
316 => {320 => {
src/InternPool.zig-24
...@@ -12036,30 +12036,6 @@ pub fn isVariable(ip: *const InternPool, val: Index) bool {...@@ -12036,30 +12036,6 @@ pub fn isVariable(ip: *const InternPool, val: Index) bool {
12036 return val.unwrap(ip).getTag(ip) == .variable;12036 return val.unwrap(ip).getTag(ip) == .variable;
12037}12037}
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
12063pub fn getBackingAddrTag(ip: *const InternPool, val: Index) ?Key.Ptr.BaseAddr.Tag {12039pub fn getBackingAddrTag(ip: *const InternPool, val: Index) ?Key.Ptr.BaseAddr.Tag {
12064 var base = val;12040 var base = val;
12065 while (true) {12041 while (true) {
src/Liveness.zig+2
...@@ -334,6 +334,7 @@ pub fn categorizeOperand(...@@ -334,6 +334,7 @@ pub fn categorizeOperand(
334 .wasm_memory_size,334 .wasm_memory_size,
335 .err_return_trace,335 .err_return_trace,
336 .save_err_return_trace_index,336 .save_err_return_trace_index,
337 .tlv_dllimport_ptr,
337 .c_va_start,338 .c_va_start,
338 .work_item_id,339 .work_item_id,
339 .work_group_size,340 .work_group_size,
...@@ -960,6 +961,7 @@ fn analyzeInst(...@@ -960,6 +961,7 @@ fn analyzeInst(
960 .wasm_memory_size,961 .wasm_memory_size,
961 .err_return_trace,962 .err_return_trace,
962 .save_err_return_trace_index,963 .save_err_return_trace_index,
964 .tlv_dllimport_ptr,
963 .c_va_start,965 .c_va_start,
964 .work_item_id,966 .work_item_id,
965 .work_group_size,967 .work_group_size,
src/Liveness/Verify.zig+1
...@@ -62,6 +62,7 @@ fn verifyBody(self: *Verify, body: []const Air.Inst.Index) Error!void {...@@ -62,6 +62,7 @@ fn verifyBody(self: *Verify, body: []const Air.Inst.Index) Error!void {
62 .wasm_memory_size,62 .wasm_memory_size,
63 .err_return_trace,63 .err_return_trace,
64 .save_err_return_trace_index,64 .save_err_return_trace_index,
65 .tlv_dllimport_ptr,
65 .c_va_start,66 .c_va_start,
66 .work_item_id,67 .work_item_id,
67 .work_group_size,68 .work_group_size,
src/Sema.zig+37-34
...@@ -2223,10 +2223,7 @@ fn resolveValue(sema: *Sema, inst: Air.Inst.Ref) CompileError!?Value {...@@ -2223,10 +2223,7 @@ fn resolveValue(sema: *Sema, inst: Air.Inst.Ref) CompileError!?Value {
22232223
2224 if (inst.toInterned()) |ip_index| {2224 if (inst.toInterned()) |ip_index| {
2225 const val: Value = .fromInterned(ip_index);2225 const val: Value = .fromInterned(ip_index);
2226
2227 assert(val.getVariable(zcu) == null);2226 assert(val.getVariable(zcu) == null);
2228 if (val.isPtrRuntimeValue(zcu)) return null;
2229
2230 return val;2227 return val;
2231 } else {2228 } else {
2232 // Runtime-known value.2229 // Runtime-known value.
...@@ -2295,31 +2292,12 @@ pub fn resolveFinalDeclValue(...@@ -2295,31 +2292,12 @@ pub fn resolveFinalDeclValue(
2295 air_ref: Air.Inst.Ref,2292 air_ref: Air.Inst.Ref,
2296) CompileError!Value {2293) CompileError!Value {
2297 const zcu = sema.pt.zcu;2294 const zcu = sema.pt.zcu;
22982295 const val = try sema.resolveConstValue(block, src, air_ref, .{ .simple = .container_var_init });
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
2317 if (val.canMutateComptimeVarState(zcu)) {2296 if (val.canMutateComptimeVarState(zcu)) {
2318 const ip = &zcu.intern_pool;2297 const ip = &zcu.intern_pool;
2319 const nav = ip.getNav(sema.owner.unwrap().nav_val);2298 const nav = ip.getNav(sema.owner.unwrap().nav_val);
2320 return sema.failWithContainsReferenceToComptimeVar(block, src, nav.name, "global variable", val);2299 return sema.failWithContainsReferenceToComptimeVar(block, src, nav.name, "global variable", val);
2321 }2300 }
2322
2323 return val;2301 return val;
2324}2302}
23252303
...@@ -26506,6 +26484,7 @@ fn zirBuiltinExtern(...@@ -26506,6 +26484,7 @@ fn zirBuiltinExtern(
26506 const zcu = pt.zcu;26484 const zcu = pt.zcu;
26507 const ip = &zcu.intern_pool;26485 const ip = &zcu.intern_pool;
26508 const extra = sema.code.extraData(Zir.Inst.BinNode, extended.operand).data;26486 const extra = sema.code.extraData(Zir.Inst.BinNode, extended.operand).data;
26487 const src = block.nodeOffset(extra.node);
26509 const ty_src = block.builtinCallArgSrc(extra.node, 0);26488 const ty_src = block.builtinCallArgSrc(extra.node, 0);
26510 const options_src = block.builtinCallArgSrc(extra.node, 1);26489 const options_src = block.builtinCallArgSrc(extra.node, 1);
2651126490
...@@ -26560,17 +26539,15 @@ fn zirBuiltinExtern(...@@ -26560,17 +26539,15 @@ fn zirBuiltinExtern(
26560 },26539 },
26561 .owner_nav = undefined, // ignored by `getExtern`26540 .owner_nav = undefined, // ignored by `getExtern`
26562 });26541 });
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 = .{26543 const uncasted_ptr = try sema.analyzeNavRef(block, src, ip.indexToKey(extern_val).@"extern".owner_nav);
26566 .ty = switch (ip.indexToKey(ty.toIntern())) {26544 // We want to cast to `ty`, but that isn't necessarily an allowed coercion.
26567 .ptr_type => ty.toIntern(),26545 if (try sema.resolveValue(uncasted_ptr)) |uncasted_ptr_val| {
26568 .opt_type => |child_type| child_type,26546 const casted_ptr_val = try pt.getCoerced(uncasted_ptr_val, ty);
26569 else => unreachable,26547 return Air.internedToRef(casted_ptr_val.toIntern());
26570 },26548 } else {
26571 .base_addr = .{ .nav = extern_nav },26549 return block.addBitCast(ty, uncasted_ptr);
26572 .byte_offset = 0,26550 }
26573 } })), ty)).toIntern());
26574}26551}
2657526552
26576fn zirWorkItem(26553fn zirWorkItem(
...@@ -32037,7 +32014,20 @@ fn analyzeNavRefInner(sema: *Sema, block: *Block, src: LazySrcLoc, orig_nav_inde...@@ -32037,7 +32014,20 @@ fn analyzeNavRefInner(sema: *Sema, block: *Block, src: LazySrcLoc, orig_nav_inde
32037 break :nav orig_nav_index;32014 break :nav orig_nav_index;
32038 };32015 };
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) {
32041 .unresolved => unreachable,32031 .unresolved => unreachable,
32042 .type_resolved => |r| .{ r.type, r.alignment, r.@"addrspace", r.is_const },32032 .type_resolved => |r| .{ r.type, r.alignment, r.@"addrspace", r.is_const },
32043 .fully_resolved => |r| .{ ip.typeOf(r.val), r.alignment, r.@"addrspace", zcu.navValIsConst(r.val) },32033 .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...@@ -32050,9 +32040,22 @@ fn analyzeNavRefInner(sema: *Sema, block: *Block, src: LazySrcLoc, orig_nav_inde
32050 .address_space = @"addrspace",32040 .address_space = @"addrspace",
32051 },32041 },
32052 });32042 });
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
32053 if (is_ref) {32055 if (is_ref) {
32054 try sema.maybeQueueFuncBodyAnalysis(block, src, nav_index);32056 try sema.maybeQueueFuncBodyAnalysis(block, src, nav_index);
32055 }32057 }
32058
32056 return Air.internedToRef((try pt.intern(.{ .ptr = .{32059 return Air.internedToRef((try pt.intern(.{ .ptr = .{
32057 .ty = ptr_ty.toIntern(),32060 .ty = ptr_ty.toIntern(),
32058 .base_addr = .{ .nav = nav_index },32061 .base_addr = .{ .nav = nav_index },
src/Value.zig-15
...@@ -1325,21 +1325,6 @@ pub fn isLazySize(val: Value, zcu: *Zcu) bool {...@@ -1325,21 +1325,6 @@ pub fn isLazySize(val: Value, zcu: *Zcu) bool {
1325 };1325 };
1326}1326}
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
1343// Asserts that the provided start/end are in-bounds.1328// Asserts that the provided start/end are in-bounds.
1344pub fn sliceArray(1329pub fn sliceArray(
1345 val: Value,1330 val: Value,
src/arch/aarch64/CodeGen.zig+2-1
...@@ -876,6 +876,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {...@@ -876,6 +876,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
876 .is_named_enum_value => return self.fail("TODO implement is_named_enum_value", .{}),876 .is_named_enum_value => return self.fail("TODO implement is_named_enum_value", .{}),
877 .error_set_has_value => return self.fail("TODO implement error_set_has_value", .{}),877 .error_set_has_value => return self.fail("TODO implement error_set_has_value", .{}),
878 .vector_store_elem => return self.fail("TODO implement vector_store_elem", .{}),878 .vector_store_elem => return self.fail("TODO implement vector_store_elem", .{}),
879 .tlv_dllimport_ptr => return self.fail("TODO implement tlv_dllimport_ptr", .{}),
879880
880 .c_va_arg => return self.fail("TODO implement c_va_arg", .{}),881 .c_va_arg => return self.fail("TODO implement c_va_arg", .{}),
881 .c_va_copy => return self.fail("TODO implement c_va_copy", .{}),882 .c_va_copy => return self.fail("TODO implement c_va_copy", .{}),
...@@ -6168,7 +6169,7 @@ fn genTypedValue(self: *Self, val: Value) InnerError!MCValue {...@@ -6168,7 +6169,7 @@ fn genTypedValue(self: *Self, val: Value) InnerError!MCValue {
6168 .memory => |addr| .{ .memory = addr },6169 .memory => |addr| .{ .memory = addr },
6169 .load_got => |sym_index| .{ .linker_load = .{ .type = .got, .sym_index = sym_index } },6170 .load_got => |sym_index| .{ .linker_load = .{ .type = .got, .sym_index = sym_index } },
6170 .load_direct => |sym_index| .{ .linker_load = .{ .type = .direct, .sym_index = sym_index } },6171 .load_direct => |sym_index| .{ .linker_load = .{ .type = .direct, .sym_index = sym_index } },
6171 .load_symbol, .load_tlv, .lea_symbol, .lea_direct => unreachable, // TODO6172 .load_symbol, .lea_symbol, .lea_direct => unreachable, // TODO
6172 },6173 },
6173 .fail => |msg| return self.failMsg(msg),6174 .fail => |msg| return self.failMsg(msg),
6174 };6175 };
src/arch/arm/CodeGen.zig+2-1
...@@ -865,6 +865,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {...@@ -865,6 +865,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
865 .is_named_enum_value => return self.fail("TODO implement is_named_enum_value", .{}),865 .is_named_enum_value => return self.fail("TODO implement is_named_enum_value", .{}),
866 .error_set_has_value => return self.fail("TODO implement error_set_has_value", .{}),866 .error_set_has_value => return self.fail("TODO implement error_set_has_value", .{}),
867 .vector_store_elem => return self.fail("TODO implement vector_store_elem", .{}),867 .vector_store_elem => return self.fail("TODO implement vector_store_elem", .{}),
868 .tlv_dllimport_ptr => return self.fail("TODO implement tlv_dllimport_ptr", .{}),
868869
869 .c_va_arg => return self.fail("TODO implement c_va_arg", .{}),870 .c_va_arg => return self.fail("TODO implement c_va_arg", .{}),
870 .c_va_copy => return self.fail("TODO implement c_va_copy", .{}),871 .c_va_copy => return self.fail("TODO implement c_va_copy", .{}),
...@@ -6135,7 +6136,7 @@ fn genTypedValue(self: *Self, val: Value) InnerError!MCValue {...@@ -6135,7 +6136,7 @@ fn genTypedValue(self: *Self, val: Value) InnerError!MCValue {
6135 .mcv => |mcv| switch (mcv) {6136 .mcv => |mcv| switch (mcv) {
6136 .none => .none,6137 .none => .none,
6137 .undef => .undef,6138 .undef => .undef,
6138 .load_got, .load_symbol, .load_direct, .load_tlv, .lea_symbol, .lea_direct => unreachable, // TODO6139 .load_got, .load_symbol, .load_direct, .lea_symbol, .lea_direct => unreachable, // TODO
6139 .immediate => |imm| .{ .immediate = @truncate(imm) },6140 .immediate => |imm| .{ .immediate = @truncate(imm) },
6140 .memory => |addr| .{ .memory = addr },6141 .memory => |addr| .{ .memory = addr },
6141 },6142 },
src/arch/riscv64/CodeGen.zig+47-44
...@@ -162,12 +162,8 @@ const MCValue = union(enum) {...@@ -162,12 +162,8 @@ const MCValue = union(enum) {
162 immediate: u64,162 immediate: u64,
163 /// The value doesn't exist in memory yet.163 /// The value doesn't exist in memory yet.
164 load_symbol: SymbolOffset,164 load_symbol: SymbolOffset,
165 /// A TLV value.
166 load_tlv: u32,
167 /// The address of the memory location not-yet-allocated by the linker.165 /// The address of the memory location not-yet-allocated by the linker.
168 lea_symbol: SymbolOffset,166 lea_symbol: SymbolOffset,
169 /// The address of a TLV value.
170 lea_tlv: u32,
171 /// The value is in a target-specific register.167 /// The value is in a target-specific register.
172 register: Register,168 register: Register,
173 /// The value is split across two registers169 /// The value is split across two registers
...@@ -224,7 +220,6 @@ const MCValue = union(enum) {...@@ -224,7 +220,6 @@ const MCValue = union(enum) {
224 .lea_frame,220 .lea_frame,
225 .undef,221 .undef,
226 .lea_symbol,222 .lea_symbol,
227 .lea_tlv,
228 .air_ref,223 .air_ref,
229 .reserved_frame,224 .reserved_frame,
230 => false,225 => false,
...@@ -233,7 +228,6 @@ const MCValue = union(enum) {...@@ -233,7 +228,6 @@ const MCValue = union(enum) {
233 .register_pair,228 .register_pair,
234 .register_offset,229 .register_offset,
235 .load_symbol,230 .load_symbol,
236 .load_tlv,
237 .indirect,231 .indirect,
238 => true,232 => true,
239233
...@@ -254,12 +248,10 @@ const MCValue = union(enum) {...@@ -254,12 +248,10 @@ const MCValue = union(enum) {
254 .undef,248 .undef,
255 .air_ref,249 .air_ref,
256 .lea_symbol,250 .lea_symbol,
257 .lea_tlv,
258 .reserved_frame,251 .reserved_frame,
259 => unreachable, // not in memory252 => unreachable, // not in memory
260253
261 .load_symbol => |sym_off| .{ .lea_symbol = sym_off },254 .load_symbol => |sym_off| .{ .lea_symbol = sym_off },
262 .load_tlv => |sym| .{ .lea_tlv = sym },
263 .memory => |addr| .{ .immediate = addr },255 .memory => |addr| .{ .immediate = addr },
264 .load_frame => |off| .{ .lea_frame = off },256 .load_frame => |off| .{ .lea_frame = off },
265 .indirect => |reg_off| switch (reg_off.off) {257 .indirect => |reg_off| switch (reg_off.off) {
...@@ -281,7 +273,6 @@ const MCValue = union(enum) {...@@ -281,7 +273,6 @@ const MCValue = union(enum) {
281 .register_pair,273 .register_pair,
282 .load_frame,274 .load_frame,
283 .load_symbol,275 .load_symbol,
284 .load_tlv,
285 .reserved_frame,276 .reserved_frame,
286 => unreachable, // not a pointer277 => unreachable, // not a pointer
287278
...@@ -290,7 +281,6 @@ const MCValue = union(enum) {...@@ -290,7 +281,6 @@ const MCValue = union(enum) {
290 .register_offset => |reg_off| .{ .indirect = reg_off },281 .register_offset => |reg_off| .{ .indirect = reg_off },
291 .lea_frame => |off| .{ .load_frame = off },282 .lea_frame => |off| .{ .load_frame = off },
292 .lea_symbol => |sym_off| .{ .load_symbol = sym_off },283 .lea_symbol => |sym_off| .{ .load_symbol = sym_off },
293 .lea_tlv => |sym| .{ .load_tlv = sym },
294 };284 };
295 }285 }
296286
...@@ -308,8 +298,6 @@ const MCValue = union(enum) {...@@ -308,8 +298,6 @@ const MCValue = union(enum) {
308 .indirect,298 .indirect,
309 .load_symbol,299 .load_symbol,
310 .lea_symbol,300 .lea_symbol,
311 .lea_tlv,
312 .load_tlv,
313 => switch (off) {301 => switch (off) {
314 0 => mcv,302 0 => mcv,
315 else => unreachable,303 else => unreachable,
...@@ -367,8 +355,6 @@ const InstTracking = struct {...@@ -367,8 +355,6 @@ const InstTracking = struct {
367 .memory,355 .memory,
368 .load_frame,356 .load_frame,
369 .lea_frame,357 .lea_frame,
370 .load_tlv,
371 .lea_tlv,
372 .load_symbol,358 .load_symbol,
373 .lea_symbol,359 .lea_symbol,
374 => result,360 => result,
...@@ -424,8 +410,6 @@ const InstTracking = struct {...@@ -424,8 +410,6 @@ const InstTracking = struct {
424 .lea_frame,410 .lea_frame,
425 .load_symbol,411 .load_symbol,
426 .lea_symbol,412 .lea_symbol,
427 .load_tlv,
428 .lea_tlv,
429 => inst_tracking.long,413 => inst_tracking.long,
430 .dead,414 .dead,
431 .register,415 .register,
...@@ -454,8 +438,6 @@ const InstTracking = struct {...@@ -454,8 +438,6 @@ const InstTracking = struct {
454 .lea_frame,438 .lea_frame,
455 .load_symbol,439 .load_symbol,
456 .lea_symbol,440 .lea_symbol,
457 .load_tlv,
458 .lea_tlv,
459 => assert(std.meta.eql(inst_tracking.long, target.long)),441 => assert(std.meta.eql(inst_tracking.long, target.long)),
460 .load_frame,442 .load_frame,
461 .reserved_frame,443 .reserved_frame,
...@@ -1665,6 +1647,8 @@ fn genBody(func: *Func, body: []const Air.Inst.Index) InnerError!void {...@@ -1665,6 +1647,8 @@ fn genBody(func: *Func, body: []const Air.Inst.Index) InnerError!void {
1665 .wrap_errunion_payload => try func.airWrapErrUnionPayload(inst),1647 .wrap_errunion_payload => try func.airWrapErrUnionPayload(inst),
1666 .wrap_errunion_err => try func.airWrapErrUnionErr(inst),1648 .wrap_errunion_err => try func.airWrapErrUnionErr(inst),
16671649
1650 .tlv_dllimport_ptr => try func.airTlvDllimportPtr(inst),
1651
1668 .add_optimized,1652 .add_optimized,
1669 .sub_optimized,1653 .sub_optimized,
1670 .mul_optimized,1654 .mul_optimized,
...@@ -3620,6 +3604,50 @@ fn airWrapErrUnionErr(func: *Func, inst: Air.Inst.Index) !void {...@@ -3620,6 +3604,50 @@ fn airWrapErrUnionErr(func: *Func, inst: Air.Inst.Index) !void {
3620 return func.finishAir(inst, result, .{ ty_op.operand, .none, .none });3604 return func.finishAir(inst, result, .{ ty_op.operand, .none, .none });
3621}3605}
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
3623fn airTry(func: *Func, inst: Air.Inst.Index) !void {3651fn airTry(func: *Func, inst: Air.Inst.Index) !void {
3624 const pl_op = func.air.instructions.items(.data)[@intFromEnum(inst)].pl_op;3652 const pl_op = func.air.instructions.items(.data)[@intFromEnum(inst)].pl_op;
3625 const extra = func.air.extraData(Air.Try, pl_op.payload);3653 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...@@ -4494,14 +4522,12 @@ fn load(func: *Func, dst_mcv: MCValue, ptr_mcv: MCValue, ptr_ty: Type) InnerErro
4494 .register_offset,4522 .register_offset,
4495 .lea_frame,4523 .lea_frame,
4496 .lea_symbol,4524 .lea_symbol,
4497 .lea_tlv,
4498 => try func.genCopy(dst_ty, dst_mcv, ptr_mcv.deref()),4525 => try func.genCopy(dst_ty, dst_mcv, ptr_mcv.deref()),
44994526
4500 .memory,4527 .memory,
4501 .indirect,4528 .indirect,
4502 .load_symbol,4529 .load_symbol,
4503 .load_frame,4530 .load_frame,
4504 .load_tlv,
4505 => {4531 => {
4506 const addr_reg = try func.copyToTmpRegister(ptr_ty, ptr_mcv);4532 const addr_reg = try func.copyToTmpRegister(ptr_ty, ptr_mcv);
4507 const addr_lock = func.register_manager.lockRegAssumeUnused(addr_reg);4533 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 {...@@ -4548,14 +4574,12 @@ fn store(func: *Func, ptr_mcv: MCValue, src_mcv: MCValue, ptr_ty: Type) !void {
4548 .register_offset,4574 .register_offset,
4549 .lea_symbol,4575 .lea_symbol,
4550 .lea_frame,4576 .lea_frame,
4551 .lea_tlv,
4552 => try func.genCopy(src_ty, ptr_mcv.deref(), src_mcv),4577 => try func.genCopy(src_ty, ptr_mcv.deref(), src_mcv),
45534578
4554 .memory,4579 .memory,
4555 .indirect,4580 .indirect,
4556 .load_symbol,4581 .load_symbol,
4557 .load_frame,4582 .load_frame,
4558 .load_tlv,
4559 => {4583 => {
4560 const addr_reg = try func.copyToTmpRegister(ptr_ty, ptr_mcv);4584 const addr_reg = try func.copyToTmpRegister(ptr_ty, ptr_mcv);
4561 const addr_lock = func.register_manager.lockRegAssumeUnused(addr_reg);4585 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 {...@@ -6544,7 +6568,7 @@ fn genCopy(func: *Func, ty: Type, dst_mcv: MCValue, src_mcv: MCValue) !void {
6544 ty,6568 ty,
6545 src_mcv,6569 src_mcv,
6546 ),6570 ),
6547 .load_symbol, .load_tlv => {6571 .load_symbol => {
6548 const addr_reg, const addr_lock = try func.allocReg(.int);6572 const addr_reg, const addr_lock = try func.allocReg(.int);
6549 defer func.register_manager.unlockReg(addr_lock);6573 defer func.register_manager.unlockReg(addr_lock);
65506574
...@@ -7072,25 +7096,6 @@ fn genSetReg(func: *Func, ty: Type, reg: Register, src_mcv: MCValue) InnerError!...@@ -7072,25 +7096,6 @@ fn genSetReg(func: *Func, ty: Type, reg: Register, src_mcv: MCValue) InnerError!
7072 try func.genSetReg(ty, addr_reg, src_mcv.address());7096 try func.genSetReg(ty, addr_reg, src_mcv.address());
7073 try func.genSetReg(ty, reg, .{ .indirect = .{ .reg = addr_reg } });7097 try func.genSetReg(ty, reg, .{ .indirect = .{ .reg = addr_reg } });
7074 },7098 },
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 },
7094 .air_ref => |ref| try func.genSetReg(ty, reg, try func.resolveInst(ref)),7099 .air_ref => |ref| try func.genSetReg(ty, reg, try func.resolveInst(ref)),
7095 else => return func.fail("TODO: genSetReg {s}", .{@tagName(src_mcv)}),7100 else => return func.fail("TODO: genSetReg {s}", .{@tagName(src_mcv)}),
7096 }7101 }
...@@ -7256,7 +7261,6 @@ fn genSetMem(...@@ -7256,7 +7261,6 @@ fn genSetMem(
7256 return func.genSetMem(base, disp, ty, .{ .register = reg });7261 return func.genSetMem(base, disp, ty, .{ .register = reg });
7257 },7262 },
7258 .air_ref => |src_ref| try func.genSetMem(base, disp, ty, try func.resolveInst(src_ref)),7263 .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)}),
7260 }7264 }
7261}7265}
72627266
...@@ -8190,7 +8194,6 @@ fn genTypedValue(func: *Func, val: Value) InnerError!MCValue {...@@ -8190,7 +8194,6 @@ fn genTypedValue(func: *Func, val: Value) InnerError!MCValue {
8190 .undef => unreachable,8194 .undef => unreachable,
8191 .lea_symbol => |sym_index| .{ .lea_symbol = .{ .sym = sym_index } },8195 .lea_symbol => |sym_index| .{ .lea_symbol = .{ .sym = sym_index } },
8192 .load_symbol => |sym_index| .{ .load_symbol = .{ .sym = sym_index } },8196 .load_symbol => |sym_index| .{ .load_symbol = .{ .sym = sym_index } },
8193 .load_tlv => |sym_index| .{ .lea_tlv = sym_index },
8194 .immediate => |imm| .{ .immediate = imm },8197 .immediate => |imm| .{ .immediate = imm },
8195 .memory => |addr| .{ .memory = addr },8198 .memory => |addr| .{ .memory = addr },
8196 .load_got, .load_direct, .lea_direct => {8199 .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 {...@@ -719,6 +719,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
719 .is_named_enum_value => @panic("TODO implement is_named_enum_value"),719 .is_named_enum_value => @panic("TODO implement is_named_enum_value"),
720 .error_set_has_value => @panic("TODO implement error_set_has_value"),720 .error_set_has_value => @panic("TODO implement error_set_has_value"),
721 .vector_store_elem => @panic("TODO implement vector_store_elem"),721 .vector_store_elem => @panic("TODO implement vector_store_elem"),
722 .tlv_dllimport_ptr => @panic("TODO implement tlv_dllimport_ptr"),
722723
723 .c_va_arg => return self.fail("TODO implement c_va_arg", .{}),724 .c_va_arg => return self.fail("TODO implement c_va_arg", .{}),
724 .c_va_copy => return self.fail("TODO implement c_va_copy", .{}),725 .c_va_copy => return self.fail("TODO implement c_va_copy", .{}),
...@@ -4088,7 +4089,7 @@ fn genTypedValue(self: *Self, val: Value) InnerError!MCValue {...@@ -4088,7 +4089,7 @@ fn genTypedValue(self: *Self, val: Value) InnerError!MCValue {
4088 .mcv => |mcv| switch (mcv) {4089 .mcv => |mcv| switch (mcv) {
4089 .none => .none,4090 .none => .none,
4090 .undef => .undef,4091 .undef => .undef,
4091 .load_got, .load_symbol, .load_direct, .load_tlv, .lea_symbol, .lea_direct => unreachable, // TODO4092 .load_got, .load_symbol, .load_direct, .lea_symbol, .lea_direct => unreachable, // TODO
4092 .immediate => |imm| .{ .immediate = imm },4093 .immediate => |imm| .{ .immediate = imm },
4093 .memory => |addr| .{ .memory = addr },4094 .memory => |addr| .{ .memory = addr },
4094 },4095 },
src/arch/wasm/CodeGen.zig+15
...@@ -2050,6 +2050,8 @@ fn genInst(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {...@@ -2050,6 +2050,8 @@ fn genInst(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
2050 .error_set_has_value => cg.airErrorSetHasValue(inst),2050 .error_set_has_value => cg.airErrorSetHasValue(inst),
2051 .frame_addr => cg.airFrameAddress(inst),2051 .frame_addr => cg.airFrameAddress(inst),
20522052
2053 .tlv_dllimport_ptr => cg.airTlvDllimportPtr(inst),
2054
2053 .assembly,2055 .assembly,
2054 .is_err_ptr,2056 .is_err_ptr,
2055 .is_non_err_ptr,2057 .is_non_err_ptr,
...@@ -7551,6 +7553,19 @@ fn airFrameAddress(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {...@@ -7551,6 +7553,19 @@ fn airFrameAddress(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
7551 return cg.finishAir(inst, .stack, &.{});7553 return cg.finishAir(inst, .stack, &.{});
7552}7554}
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
7554fn typeOf(cg: *CodeGen, inst: Air.Inst.Ref) Type {7569fn typeOf(cg: *CodeGen, inst: Air.Inst.Ref) Type {
7555 const zcu = cg.pt.zcu;7570 const zcu = cg.pt.zcu;
7556 return cg.air.typeOf(inst, &zcu.intern_pool);7571 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) {...@@ -204,12 +204,6 @@ pub const MCValue = union(enum) {
204 /// The value is a pointer to a value referenced indirectly via GOT.204 /// The value is a pointer to a value referenced indirectly via GOT.
205 /// Payload is a symbol index.205 /// Payload is a symbol index.
206 lea_got: u32,206 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,
213 /// The value stored at an offset from a frame index207 /// The value stored at an offset from a frame index
214 /// Payload is a frame address.208 /// Payload is a frame address.
215 load_frame: bits.FrameAddr,209 load_frame: bits.FrameAddr,
...@@ -238,7 +232,6 @@ pub const MCValue = union(enum) {...@@ -238,7 +232,6 @@ pub const MCValue = union(enum) {
238 .lea_symbol,232 .lea_symbol,
239 .lea_direct,233 .lea_direct,
240 .lea_got,234 .lea_got,
241 .lea_tlv,
242 .lea_frame,235 .lea_frame,
243 .elementwise_regs_then_frame,236 .elementwise_regs_then_frame,
244 .reserved_frame,237 .reserved_frame,
...@@ -252,7 +245,6 @@ pub const MCValue = union(enum) {...@@ -252,7 +245,6 @@ pub const MCValue = union(enum) {
252 .load_symbol,245 .load_symbol,
253 .load_got,246 .load_got,
254 .load_direct,247 .load_direct,
255 .load_tlv,
256 .indirect,248 .indirect,
257 => true,249 => true,
258 .load_frame => |frame_addr| !frame_addr.index.isNamed(),250 .load_frame => |frame_addr| !frame_addr.index.isNamed(),
...@@ -355,7 +347,6 @@ pub const MCValue = union(enum) {...@@ -355,7 +347,6 @@ pub const MCValue = union(enum) {
355 .lea_symbol,347 .lea_symbol,
356 .lea_direct,348 .lea_direct,
357 .lea_got,349 .lea_got,
358 .lea_tlv,
359 .lea_frame,350 .lea_frame,
360 .elementwise_regs_then_frame,351 .elementwise_regs_then_frame,
361 .reserved_frame,352 .reserved_frame,
...@@ -368,7 +359,6 @@ pub const MCValue = union(enum) {...@@ -368,7 +359,6 @@ pub const MCValue = union(enum) {
368 },359 },
369 .load_direct => |sym_index| .{ .lea_direct = sym_index },360 .load_direct => |sym_index| .{ .lea_direct = sym_index },
370 .load_got => |sym_index| .{ .lea_got = sym_index },361 .load_got => |sym_index| .{ .lea_got = sym_index },
371 .load_tlv => |sym_index| .{ .lea_tlv = sym_index },
372 .load_frame => |frame_addr| .{ .lea_frame = frame_addr },362 .load_frame => |frame_addr| .{ .lea_frame = frame_addr },
373 .load_symbol => |sym_off| .{ .lea_symbol = sym_off },363 .load_symbol => |sym_off| .{ .lea_symbol = sym_off },
374 };364 };
...@@ -390,7 +380,6 @@ pub const MCValue = union(enum) {...@@ -390,7 +380,6 @@ pub const MCValue = union(enum) {
390 .indirect,380 .indirect,
391 .load_direct,381 .load_direct,
392 .load_got,382 .load_got,
393 .load_tlv,
394 .load_frame,383 .load_frame,
395 .load_symbol,384 .load_symbol,
396 .elementwise_regs_then_frame,385 .elementwise_regs_then_frame,
...@@ -402,7 +391,6 @@ pub const MCValue = union(enum) {...@@ -402,7 +391,6 @@ pub const MCValue = union(enum) {
402 .register_offset => |reg_off| .{ .indirect = reg_off },391 .register_offset => |reg_off| .{ .indirect = reg_off },
403 .lea_direct => |sym_index| .{ .load_direct = sym_index },392 .lea_direct => |sym_index| .{ .load_direct = sym_index },
404 .lea_got => |sym_index| .{ .load_got = sym_index },393 .lea_got => |sym_index| .{ .load_got = sym_index },
405 .lea_tlv => |sym_index| .{ .load_tlv = sym_index },
406 .lea_frame => |frame_addr| .{ .load_frame = frame_addr },394 .lea_frame => |frame_addr| .{ .load_frame = frame_addr },
407 .lea_symbol => |sym_index| .{ .load_symbol = sym_index },395 .lea_symbol => |sym_index| .{ .load_symbol = sym_index },
408 };396 };
...@@ -430,8 +418,6 @@ pub const MCValue = union(enum) {...@@ -430,8 +418,6 @@ pub const MCValue = union(enum) {
430 .lea_direct,418 .lea_direct,
431 .load_got,419 .load_got,
432 .lea_got,420 .lea_got,
433 .load_tlv,
434 .lea_tlv,
435 .load_frame,421 .load_frame,
436 .load_symbol,422 .load_symbol,
437 .lea_symbol,423 .lea_symbol,
...@@ -469,8 +455,6 @@ pub const MCValue = union(enum) {...@@ -469,8 +455,6 @@ pub const MCValue = union(enum) {
469 .lea_direct,455 .lea_direct,
470 .load_got,456 .load_got,
471 .lea_got,457 .lea_got,
472 .load_tlv,
473 .lea_tlv,
474 .lea_frame,458 .lea_frame,
475 .elementwise_regs_then_frame,459 .elementwise_regs_then_frame,
476 .reserved_frame,460 .reserved_frame,
...@@ -555,8 +539,6 @@ pub const MCValue = union(enum) {...@@ -555,8 +539,6 @@ pub const MCValue = union(enum) {
555 .lea_direct => |pl| try writer.print("direct:{d}", .{pl}),539 .lea_direct => |pl| try writer.print("direct:{d}", .{pl}),
556 .load_got => |pl| try writer.print("[got:{d}]", .{pl}),540 .load_got => |pl| try writer.print("[got:{d}]", .{pl}),
557 .lea_got => |pl| try writer.print("got:{d}", .{pl}),541 .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}),
560 .load_frame => |pl| try writer.print("[{} + 0x{x}]", .{ pl.index, pl.off }),542 .load_frame => |pl| try writer.print("[{} + 0x{x}]", .{ pl.index, pl.off }),
561 .elementwise_regs_then_frame => |pl| try writer.print("elementwise:{d}:[{} + 0x{x}]", .{543 .elementwise_regs_then_frame => |pl| try writer.print("elementwise:{d}:[{} + 0x{x}]", .{
562 pl.regs, pl.frame_index, pl.frame_off,544 pl.regs, pl.frame_index, pl.frame_off,
...@@ -585,8 +567,6 @@ const InstTracking = struct {...@@ -585,8 +567,6 @@ const InstTracking = struct {
585 .lea_direct,567 .lea_direct,
586 .load_got,568 .load_got,
587 .lea_got,569 .lea_got,
588 .load_tlv,
589 .lea_tlv,
590 .load_frame,570 .load_frame,
591 .lea_frame,571 .lea_frame,
592 .load_symbol,572 .load_symbol,
...@@ -688,8 +668,6 @@ const InstTracking = struct {...@@ -688,8 +668,6 @@ const InstTracking = struct {
688 .lea_direct,668 .lea_direct,
689 .load_got,669 .load_got,
690 .lea_got,670 .lea_got,
691 .load_tlv,
692 .lea_tlv,
693 .lea_frame,671 .lea_frame,
694 .load_symbol,672 .load_symbol,
695 .lea_symbol,673 .lea_symbol,
...@@ -120945,6 +120923,47 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {...@@ -120945,6 +120923,47 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {
120945 };120923 };
120946 for (ops) |op| try op.die(cg);120924 for (ops) |op| try op.die(cg);
120947 },120925 },
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 },
120948 .c_va_arg => try cg.airVaArg(inst),120967 .c_va_arg => try cg.airVaArg(inst),
120949 .c_va_copy => try cg.airVaCopy(inst),120968 .c_va_copy => try cg.airVaCopy(inst),
120950 .c_va_end => try cg.airVaEnd(inst),120969 .c_va_end => try cg.airVaEnd(inst),
...@@ -124664,7 +124683,7 @@ fn airArrayElemVal(self: *CodeGen, inst: Air.Inst.Index) !void {...@@ -124664,7 +124683,7 @@ fn airArrayElemVal(self: *CodeGen, inst: Air.Inst.Index) !void {
124664 }.to64(),124683 }.to64(),
124665 ),124684 ),
124666 },124685 },
124667 .memory, .load_symbol, .load_direct, .load_got, .load_tlv => switch (index_mcv) {124686 .memory, .load_symbol, .load_direct, .load_got => switch (index_mcv) {
124668 .immediate => |index_imm| try self.asmMemoryImmediate(124687 .immediate => |index_imm| try self.asmMemoryImmediate(
124669 .{ ._, .bt },124688 .{ ._, .bt },
124670 .{124689 .{
...@@ -124729,9 +124748,8 @@ fn airArrayElemVal(self: *CodeGen, inst: Air.Inst.Index) !void {...@@ -124729,9 +124748,8 @@ fn airArrayElemVal(self: *CodeGen, inst: Air.Inst.Index) !void {
124729 .load_symbol,124748 .load_symbol,
124730 .load_direct,124749 .load_direct,
124731 .load_got,124750 .load_got,
124732 .load_tlv,
124733 => try self.genSetReg(addr_reg, .usize, array_mcv.address(), .{}),124751 => try self.genSetReg(addr_reg, .usize, array_mcv.address(), .{}),
124734 .lea_symbol, .lea_direct, .lea_tlv => unreachable,124752 .lea_symbol, .lea_direct => unreachable,
124735 else => return self.fail("TODO airArrayElemVal_val for {s} of {}", .{124753 else => return self.fail("TODO airArrayElemVal_val for {s} of {}", .{
124736 @tagName(array_mcv), array_ty.fmt(pt),124754 @tagName(array_mcv), array_ty.fmt(pt),
124737 }),124755 }),
...@@ -126611,7 +126629,6 @@ fn load(self: *CodeGen, dst_mcv: MCValue, ptr_ty: Type, ptr_mcv: MCValue) InnerE...@@ -126611,7 +126629,6 @@ fn load(self: *CodeGen, dst_mcv: MCValue, ptr_ty: Type, ptr_mcv: MCValue) InnerE
126611 .lea_symbol,126629 .lea_symbol,
126612 .lea_direct,126630 .lea_direct,
126613 .lea_got,126631 .lea_got,
126614 .lea_tlv,
126615 .lea_frame,126632 .lea_frame,
126616 => try self.genCopy(dst_ty, dst_mcv, ptr_mcv.deref(), .{}),126633 => try self.genCopy(dst_ty, dst_mcv, ptr_mcv.deref(), .{}),
126617 .memory,126634 .memory,
...@@ -126619,7 +126636,6 @@ fn load(self: *CodeGen, dst_mcv: MCValue, ptr_ty: Type, ptr_mcv: MCValue) InnerE...@@ -126619,7 +126636,6 @@ fn load(self: *CodeGen, dst_mcv: MCValue, ptr_ty: Type, ptr_mcv: MCValue) InnerE
126619 .load_symbol,126636 .load_symbol,
126620 .load_direct,126637 .load_direct,
126621 .load_got,126638 .load_got,
126622 .load_tlv,
126623 .load_frame,126639 .load_frame,
126624 => {126640 => {
126625 const addr_reg = try self.copyToTmpRegister(ptr_ty, ptr_mcv);126641 const addr_reg = try self.copyToTmpRegister(ptr_ty, ptr_mcv);
...@@ -126831,7 +126847,6 @@ fn store(...@@ -126831,7 +126847,6 @@ fn store(
126831 .lea_symbol,126847 .lea_symbol,
126832 .lea_direct,126848 .lea_direct,
126833 .lea_got,126849 .lea_got,
126834 .lea_tlv,
126835 .lea_frame,126850 .lea_frame,
126836 => try self.genCopy(src_ty, ptr_mcv.deref(), src_mcv, opts),126851 => try self.genCopy(src_ty, ptr_mcv.deref(), src_mcv, opts),
126837 .memory,126852 .memory,
...@@ -126839,7 +126854,6 @@ fn store(...@@ -126839,7 +126854,6 @@ fn store(
126839 .load_symbol,126854 .load_symbol,
126840 .load_direct,126855 .load_direct,
126841 .load_got,126856 .load_got,
126842 .load_tlv,
126843 .load_frame,126857 .load_frame,
126844 => {126858 => {
126845 const addr_reg = try self.copyToTmpRegister(ptr_ty, ptr_mcv);126859 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:...@@ -127309,7 +127323,6 @@ fn genUnOpMir(self: *CodeGen, mir_tag: Mir.Inst.FixedTag, dst_ty: Type, dst_mcv:
127309 .lea_symbol,127323 .lea_symbol,
127310 .lea_direct,127324 .lea_direct,
127311 .lea_got,127325 .lea_got,
127312 .lea_tlv,
127313 .lea_frame,127326 .lea_frame,
127314 .elementwise_regs_then_frame,127327 .elementwise_regs_then_frame,
127315 .reserved_frame,127328 .reserved_frame,
...@@ -127317,7 +127330,7 @@ fn genUnOpMir(self: *CodeGen, mir_tag: Mir.Inst.FixedTag, dst_ty: Type, dst_mcv:...@@ -127317,7 +127330,7 @@ fn genUnOpMir(self: *CodeGen, mir_tag: Mir.Inst.FixedTag, dst_ty: Type, dst_mcv:
127317 => unreachable, // unmodifiable destination127330 => unreachable, // unmodifiable destination
127318 .register => |dst_reg| try self.asmRegister(mir_tag, registerAlias(dst_reg, abi_size)),127331 .register => |dst_reg| try self.asmRegister(mir_tag, registerAlias(dst_reg, abi_size)),
127319 .register_pair, .register_triple, .register_quadruple => unreachable, // unimplemented127332 .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 => {
127321 const addr_reg = try self.register_manager.allocReg(null, abi.RegisterClass.gp);127334 const addr_reg = try self.register_manager.allocReg(null, abi.RegisterClass.gp);
127322 const addr_reg_lock = self.register_manager.lockRegAssumeUnused(addr_reg);127335 const addr_reg_lock = self.register_manager.lockRegAssumeUnused(addr_reg);
127323 defer self.register_manager.unlockReg(addr_reg_lock);127336 defer self.register_manager.unlockReg(addr_reg_lock);
...@@ -128922,8 +128935,6 @@ fn genBinOp(...@@ -128922,8 +128935,6 @@ fn genBinOp(
128922 .lea_direct,128935 .lea_direct,
128923 .load_got,128936 .load_got,
128924 .lea_got,128937 .lea_got,
128925 .load_tlv,
128926 .lea_tlv,
128927 .lea_frame,128938 .lea_frame,
128928 => true,128939 => true,
128929 .memory => |addr| std.math.cast(i32, @as(i64, @bitCast(addr))) == null,128940 .memory => |addr| std.math.cast(i32, @as(i64, @bitCast(addr))) == null,
...@@ -128983,8 +128994,6 @@ fn genBinOp(...@@ -128983,8 +128994,6 @@ fn genBinOp(
128983 .lea_direct,128994 .lea_direct,
128984 .load_got,128995 .load_got,
128985 .lea_got,128996 .lea_got,
128986 .load_tlv,
128987 .lea_tlv,
128988 .lea_frame,128997 .lea_frame,
128989 .elementwise_regs_then_frame,128998 .elementwise_regs_then_frame,
128990 .reserved_frame,128999 .reserved_frame,
...@@ -130167,7 +130176,6 @@ fn genBinOpMir(...@@ -130167,7 +130176,6 @@ fn genBinOpMir(
130167 .register_mask,130176 .register_mask,
130168 .lea_direct,130177 .lea_direct,
130169 .lea_got,130178 .lea_got,
130170 .lea_tlv,
130171 .lea_frame,130179 .lea_frame,
130172 .lea_symbol,130180 .lea_symbol,
130173 .elementwise_regs_then_frame,130181 .elementwise_regs_then_frame,
...@@ -130265,8 +130273,6 @@ fn genBinOpMir(...@@ -130265,8 +130273,6 @@ fn genBinOpMir(
130265 .lea_direct,130273 .lea_direct,
130266 .load_got,130274 .load_got,
130267 .lea_got,130275 .lea_got,
130268 .load_tlv,
130269 .lea_tlv,
130270 .load_frame,130276 .load_frame,
130271 .lea_frame,130277 .lea_frame,
130272 => {130278 => {
...@@ -130304,7 +130310,6 @@ fn genBinOpMir(...@@ -130304,7 +130310,6 @@ fn genBinOpMir(
130304 .lea_symbol,130310 .lea_symbol,
130305 .lea_direct,130311 .lea_direct,
130306 .lea_got,130312 .lea_got,
130307 .lea_tlv,
130308 .lea_frame,130313 .lea_frame,
130309 => {130314 => {
130310 assert(off == 0);130315 assert(off == 0);
...@@ -130320,7 +130325,6 @@ fn genBinOpMir(...@@ -130320,7 +130325,6 @@ fn genBinOpMir(
130320 .load_symbol,130325 .load_symbol,
130321 .load_direct,130326 .load_direct,
130322 .load_got,130327 .load_got,
130323 .load_tlv,
130324 => {130328 => {
130325 const ptr_ty = try pt.singleConstPtrType(ty);130329 const ptr_ty = try pt.singleConstPtrType(ty);
130326 const addr_reg = try self.copyToTmpRegister(ptr_ty, src_mcv.address());130330 const addr_reg = try self.copyToTmpRegister(ptr_ty, src_mcv.address());
...@@ -130340,13 +130344,13 @@ fn genBinOpMir(...@@ -130340,13 +130344,13 @@ fn genBinOpMir(
130340 }130344 }
130341 }130345 }
130342 },130346 },
130343 .memory, .indirect, .load_symbol, .load_got, .load_direct, .load_tlv, .load_frame => {130347 .memory, .indirect, .load_symbol, .load_got, .load_direct, .load_frame => {
130344 const OpInfo = ?struct { addr_reg: Register, addr_lock: RegisterLock };130348 const OpInfo = ?struct { addr_reg: Register, addr_lock: RegisterLock };
130345 const limb_abi_size: u32 = @min(abi_size, 8);130349 const limb_abi_size: u32 = @min(abi_size, 8);
130346130350
130347 const dst_info: OpInfo = switch (dst_mcv) {130351 const dst_info: OpInfo = switch (dst_mcv) {
130348 else => unreachable,130352 else => unreachable,
130349 .memory, .load_symbol, .load_got, .load_direct, .load_tlv => dst: {130353 .memory, .load_symbol, .load_got, .load_direct => dst: {
130350 const dst_addr_reg =130354 const dst_addr_reg =
130351 (try self.register_manager.allocReg(null, abi.RegisterClass.gp)).to64();130355 (try self.register_manager.allocReg(null, abi.RegisterClass.gp)).to64();
130352 const dst_addr_lock = self.register_manager.lockRegAssumeUnused(dst_addr_reg);130356 const dst_addr_lock = self.register_manager.lockRegAssumeUnused(dst_addr_reg);
...@@ -130384,17 +130388,16 @@ fn genBinOpMir(...@@ -130384,17 +130388,16 @@ fn genBinOpMir(
130384 .indirect,130388 .indirect,
130385 .lea_direct,130389 .lea_direct,
130386 .lea_got,130390 .lea_got,
130387 .lea_tlv,
130388 .load_frame,130391 .load_frame,
130389 .lea_frame,130392 .lea_frame,
130390 .lea_symbol,130393 .lea_symbol,
130391 => null,130394 => null,
130392 .memory, .load_symbol, .load_got, .load_direct, .load_tlv => src: {130395 .memory, .load_symbol, .load_got, .load_direct => src: {
130393 switch (resolved_src_mcv) {130396 switch (resolved_src_mcv) {
130394 .memory => |addr| if (std.math.cast(i32, @as(i64, @bitCast(addr))) != null and130397 .memory => |addr| if (std.math.cast(i32, @as(i64, @bitCast(addr))) != null and
130395 std.math.cast(i32, @as(i64, @bitCast(addr)) + abi_size - limb_abi_size) != null)130398 std.math.cast(i32, @as(i64, @bitCast(addr)) + abi_size - limb_abi_size) != null)
130396 break :src null,130399 break :src null,
130397 .load_symbol, .load_got, .load_direct, .load_tlv => {},130400 .load_symbol, .load_got, .load_direct => {},
130398 else => unreachable,130401 else => unreachable,
130399 }130402 }
130400130403
...@@ -130437,7 +130440,6 @@ fn genBinOpMir(...@@ -130437,7 +130440,6 @@ fn genBinOpMir(
130437 .load_symbol,130440 .load_symbol,
130438 .load_got,130441 .load_got,
130439 .load_direct,130442 .load_direct,
130440 .load_tlv,
130441 => .{130443 => .{
130442 .base = .{ .reg = dst_info.?.addr_reg },130444 .base = .{ .reg = dst_info.?.addr_reg },
130443 .mod = .{ .rm = .{130445 .mod = .{ .rm = .{
...@@ -130533,8 +130535,6 @@ fn genBinOpMir(...@@ -130533,8 +130535,6 @@ fn genBinOpMir(
130533 .lea_direct,130535 .lea_direct,
130534 .load_got,130536 .load_got,
130535 .lea_got,130537 .lea_got,
130536 .load_tlv,
130537 .lea_tlv,
130538 .load_frame,130538 .load_frame,
130539 .lea_frame,130539 .lea_frame,
130540 => {130540 => {
...@@ -130549,7 +130549,6 @@ fn genBinOpMir(...@@ -130549,7 +130549,6 @@ fn genBinOpMir(
130549 .lea_symbol,130549 .lea_symbol,
130550 .lea_direct,130550 .lea_direct,
130551 .lea_got,130551 .lea_got,
130552 .lea_tlv,
130553 .lea_frame,130552 .lea_frame,
130554 => switch (limb_i) {130553 => switch (limb_i) {
130555 0 => resolved_src_mcv,130554 0 => resolved_src_mcv,
...@@ -130601,7 +130600,6 @@ fn genIntMulComplexOpMir(self: *CodeGen, dst_ty: Type, dst_mcv: MCValue, src_mcv...@@ -130601,7 +130600,6 @@ fn genIntMulComplexOpMir(self: *CodeGen, dst_ty: Type, dst_mcv: MCValue, src_mcv
130601 .lea_symbol,130600 .lea_symbol,
130602 .lea_direct,130601 .lea_direct,
130603 .lea_got,130602 .lea_got,
130604 .lea_tlv,
130605 .lea_frame,130603 .lea_frame,
130606 .elementwise_regs_then_frame,130604 .elementwise_regs_then_frame,
130607 .reserved_frame,130605 .reserved_frame,
...@@ -130666,8 +130664,6 @@ fn genIntMulComplexOpMir(self: *CodeGen, dst_ty: Type, dst_mcv: MCValue, src_mcv...@@ -130666,8 +130664,6 @@ fn genIntMulComplexOpMir(self: *CodeGen, dst_ty: Type, dst_mcv: MCValue, src_mcv
130666 .lea_direct,130664 .lea_direct,
130667 .load_got,130665 .load_got,
130668 .lea_got,130666 .lea_got,
130669 .load_tlv,
130670 .lea_tlv,
130671 .lea_frame,130667 .lea_frame,
130672 => {130668 => {
130673 const src_reg = try self.copyToTmpRegister(dst_ty, resolved_src_mcv);130669 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...@@ -130723,7 +130719,7 @@ fn genIntMulComplexOpMir(self: *CodeGen, dst_ty: Type, dst_mcv: MCValue, src_mcv
130723 }130719 }
130724 },130720 },
130725 .register_pair, .register_triple, .register_quadruple => unreachable, // unimplemented130721 .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 => {
130727 const tmp_reg = try self.copyToTmpRegister(dst_ty, dst_mcv);130723 const tmp_reg = try self.copyToTmpRegister(dst_ty, dst_mcv);
130728 const tmp_mcv = MCValue{ .register = tmp_reg };130724 const tmp_mcv = MCValue{ .register = tmp_reg };
130729 const tmp_lock = self.register_manager.lockRegAssumeUnused(tmp_reg);130725 const tmp_lock = self.register_manager.lockRegAssumeUnused(tmp_reg);
...@@ -130899,7 +130895,7 @@ fn genLocalDebugInfo(...@@ -130899,7 +130895,7 @@ fn genLocalDebugInfo(
130899 .disp = sym_off.off,130895 .disp = sym_off.off,
130900 } },130896 } },
130901 }),130897 }),
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, .{
130903 .base = .{ .reloc = sym_index },130899 .base = .{ .reloc = sym_index },
130904 .mod = .{ .rm = .{ .size = .qword } },130900 .mod = .{ .rm = .{ .size = .qword } },
130905 }),130901 }),
...@@ -131548,7 +131544,6 @@ fn airCmp(self: *CodeGen, inst: Air.Inst.Index, op: std.math.CompareOperator) !v...@@ -131548,7 +131544,6 @@ fn airCmp(self: *CodeGen, inst: Air.Inst.Index, op: std.math.CompareOperator) !v
131548 .indirect,131544 .indirect,
131549 .lea_direct,131545 .lea_direct,
131550 .lea_got,131546 .lea_got,
131551 .lea_tlv,
131552 .lea_frame,131547 .lea_frame,
131553 .lea_symbol,131548 .lea_symbol,
131554 .elementwise_regs_then_frame,131549 .elementwise_regs_then_frame,
...@@ -131556,7 +131551,7 @@ fn airCmp(self: *CodeGen, inst: Air.Inst.Index, op: std.math.CompareOperator) !v...@@ -131556,7 +131551,7 @@ fn airCmp(self: *CodeGen, inst: Air.Inst.Index, op: std.math.CompareOperator) !v
131556 .air_ref,131551 .air_ref,
131557 => unreachable,131552 => unreachable,
131558 .register, .register_pair, .register_triple, .register_quadruple, .load_frame => null,131553 .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: {
131560 switch (resolved_dst_mcv) {131555 switch (resolved_dst_mcv) {
131561 .memory => |addr| if (std.math.cast(131556 .memory => |addr| if (std.math.cast(
131562 i32,131557 i32,
...@@ -131565,7 +131560,7 @@ fn airCmp(self: *CodeGen, inst: Air.Inst.Index, op: std.math.CompareOperator) !v...@@ -131565,7 +131560,7 @@ fn airCmp(self: *CodeGen, inst: Air.Inst.Index, op: std.math.CompareOperator) !v
131565 i32,131560 i32,
131566 @as(i64, @bitCast(addr)) + abi_size - 8,131561 @as(i64, @bitCast(addr)) + abi_size - 8,
131567 ) != null) break :dst null,131562 ) != null) break :dst null,
131568 .load_symbol, .load_got, .load_direct, .load_tlv => {},131563 .load_symbol, .load_got, .load_direct => {},
131569 else => unreachable,131564 else => unreachable,
131570 }131565 }
131571131566
...@@ -131605,14 +131600,13 @@ fn airCmp(self: *CodeGen, inst: Air.Inst.Index, op: std.math.CompareOperator) !v...@@ -131605,14 +131600,13 @@ fn airCmp(self: *CodeGen, inst: Air.Inst.Index, op: std.math.CompareOperator) !v
131605 .lea_symbol,131600 .lea_symbol,
131606 .lea_direct,131601 .lea_direct,
131607 .lea_got,131602 .lea_got,
131608 .lea_tlv,
131609 .lea_frame,131603 .lea_frame,
131610 .elementwise_regs_then_frame,131604 .elementwise_regs_then_frame,
131611 .reserved_frame,131605 .reserved_frame,
131612 .air_ref,131606 .air_ref,
131613 => unreachable,131607 => unreachable,
131614 .register_pair, .register_triple, .register_quadruple, .load_frame => null,131608 .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: {
131616 switch (resolved_src_mcv) {131610 switch (resolved_src_mcv) {
131617 .memory => |addr| if (std.math.cast(131611 .memory => |addr| if (std.math.cast(
131618 i32,131612 i32,
...@@ -131621,7 +131615,7 @@ fn airCmp(self: *CodeGen, inst: Air.Inst.Index, op: std.math.CompareOperator) !v...@@ -131621,7 +131615,7 @@ fn airCmp(self: *CodeGen, inst: Air.Inst.Index, op: std.math.CompareOperator) !v
131621 i32,131615 i32,
131622 @as(i64, @bitCast(addr)) + abi_size - 8,131616 @as(i64, @bitCast(addr)) + abi_size - 8,
131623 ) != null) break :src null,131617 ) != null) break :src null,
131624 .load_symbol, .load_got, .load_direct, .load_tlv => {},131618 .load_symbol, .load_got, .load_direct => {},
131625 else => unreachable,131619 else => unreachable,
131626 }131620 }
131627131621
...@@ -132011,7 +132005,6 @@ fn isNull(self: *CodeGen, inst: Air.Inst.Index, opt_ty: Type, opt_mcv: MCValue)...@@ -132011,7 +132005,6 @@ fn isNull(self: *CodeGen, inst: Air.Inst.Index, opt_ty: Type, opt_mcv: MCValue)
132011 .register_mask,132005 .register_mask,
132012 .lea_direct,132006 .lea_direct,
132013 .lea_got,132007 .lea_got,
132014 .lea_tlv,
132015 .lea_symbol,132008 .lea_symbol,
132016 .elementwise_regs_then_frame,132009 .elementwise_regs_then_frame,
132017 .reserved_frame,132010 .reserved_frame,
...@@ -132063,7 +132056,6 @@ fn isNull(self: *CodeGen, inst: Air.Inst.Index, opt_ty: Type, opt_mcv: MCValue)...@@ -132063,7 +132056,6 @@ fn isNull(self: *CodeGen, inst: Air.Inst.Index, opt_ty: Type, opt_mcv: MCValue)
132063 .load_symbol,132056 .load_symbol,
132064 .load_got,132057 .load_got,
132065 .load_direct,132058 .load_direct,
132066 .load_tlv,
132067 => {132059 => {
132068 const addr_reg = (try self.register_manager.allocReg(null, abi.RegisterClass.gp)).to64();132060 const addr_reg = (try self.register_manager.allocReg(null, abi.RegisterClass.gp)).to64();
132069 const addr_reg_lock = self.register_manager.lockRegAssumeUnused(addr_reg);132061 const addr_reg_lock = self.register_manager.lockRegAssumeUnused(addr_reg);
...@@ -133105,7 +133097,7 @@ fn airAsm(self: *CodeGen, inst: Air.Inst.Index) !void {...@@ -133105,7 +133097,7 @@ fn airAsm(self: *CodeGen, inst: Air.Inst.Index) !void {
133105 .memory => |addr| if (std.math.cast(i32, @as(i64, @bitCast(addr)))) |_|133097 .memory => |addr| if (std.math.cast(i32, @as(i64, @bitCast(addr)))) |_|
133106 break :arg input_mcv,133098 break :arg input_mcv,
133107 .indirect, .load_frame => break :arg input_mcv,133099 .indirect, .load_frame => break :arg input_mcv,
133108 .load_symbol, .load_direct, .load_got, .load_tlv => {},133100 .load_symbol, .load_direct, .load_got => {},
133109 else => {133101 else => {
133110 const temp_mcv = try self.allocTempRegOrMem(ty, false);133102 const temp_mcv = try self.allocTempRegOrMem(ty, false);
133111 try self.genCopy(ty, temp_mcv, input_mcv, .{});133103 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...@@ -134075,7 +134067,6 @@ fn genCopy(self: *CodeGen, ty: Type, dst_mcv: MCValue, src_mcv: MCValue, opts: C
134075 .register_mask,134067 .register_mask,
134076 .lea_direct,134068 .lea_direct,
134077 .lea_got,134069 .lea_got,
134078 .lea_tlv,
134079 .lea_frame,134070 .lea_frame,
134080 .lea_symbol,134071 .lea_symbol,
134081 .elementwise_regs_then_frame,134072 .elementwise_regs_then_frame,
...@@ -134159,7 +134150,7 @@ fn genCopy(self: *CodeGen, ty: Type, dst_mcv: MCValue, src_mcv: MCValue, opts: C...@@ -134159,7 +134150,7 @@ fn genCopy(self: *CodeGen, ty: Type, dst_mcv: MCValue, src_mcv: MCValue, opts: C
134159 }134150 }
134160 return;134151 return;
134161 },134152 },
134162 .load_symbol, .load_direct, .load_got, .load_tlv => {134153 .load_symbol, .load_direct, .load_got => {
134163 const src_addr_reg =134154 const src_addr_reg =
134164 (try self.register_manager.allocReg(null, abi.RegisterClass.gp)).to64();134155 (try self.register_manager.allocReg(null, abi.RegisterClass.gp)).to64();
134165 const src_addr_lock = self.register_manager.lockRegAssumeUnused(src_addr_reg);134156 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...@@ -134192,7 +134183,7 @@ fn genCopy(self: *CodeGen, ty: Type, dst_mcv: MCValue, src_mcv: MCValue, opts: C
134192 .undef => if (opts.safety and part_i > 0) .{ .register = dst_regs[0] } else .undef,134183 .undef => if (opts.safety and part_i > 0) .{ .register = dst_regs[0] } else .undef,
134193 dst_tag => |src_regs| .{ .register = src_regs[part_i] },134184 dst_tag => |src_regs| .{ .register = src_regs[part_i] },
134194 .memory, .indirect, .load_frame => src_mcv.address().offset(part_disp).deref(),134185 .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 = .{
134196 .reg = src_info.?.addr_reg,134187 .reg = src_info.?.addr_reg,
134197 .off = part_disp,134188 .off = part_disp,
134198 } },134189 } },
...@@ -134213,11 +134204,11 @@ fn genCopy(self: *CodeGen, ty: Type, dst_mcv: MCValue, src_mcv: MCValue, opts: C...@@ -134213,11 +134204,11 @@ fn genCopy(self: *CodeGen, ty: Type, dst_mcv: MCValue, src_mcv: MCValue, opts: C
134213 src_mcv,134204 src_mcv,
134214 opts,134205 opts,
134215 ),134206 ),
134216 .memory, .load_symbol, .load_direct, .load_got, .load_tlv => {134207 .memory, .load_symbol, .load_direct, .load_got => {
134217 switch (dst_mcv) {134208 switch (dst_mcv) {
134218 .memory => |addr| if (std.math.cast(i32, @as(i64, @bitCast(addr)))) |small_addr|134209 .memory => |addr| if (std.math.cast(i32, @as(i64, @bitCast(addr)))) |small_addr|
134219 return self.genSetMem(.{ .reg = .ds }, small_addr, ty, src_mcv, opts),134210 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 => {},
134221 else => unreachable,134212 else => unreachable,
134222 }134213 }
134223134214
...@@ -134639,7 +134630,7 @@ fn genSetReg(...@@ -134639,7 +134630,7 @@ fn genSetReg(
134639 if (src_reg_mask.info.inverted) try self.asmRegister(.{ ._, .not }, registerAlias(bits_reg, abi_size));134630 if (src_reg_mask.info.inverted) try self.asmRegister(.{ ._, .not }, registerAlias(bits_reg, abi_size));
134640 try self.genSetReg(dst_reg, ty, .{ .register = bits_reg }, .{});134631 try self.genSetReg(dst_reg, ty, .{ .register = bits_reg }, .{});
134641 },134632 },
134642 .memory, .load_symbol, .load_direct, .load_got, .load_tlv => {134633 .memory, .load_symbol, .load_direct, .load_got => {
134643 switch (src_mcv) {134634 switch (src_mcv) {
134644 .memory => |addr| if (std.math.cast(i32, @as(i64, @bitCast(addr)))) |small_addr|134635 .memory => |addr| if (std.math.cast(i32, @as(i64, @bitCast(addr)))) |small_addr|
134645 return (try self.moveStrategy(134636 return (try self.moveStrategy(
...@@ -134683,7 +134674,7 @@ fn genSetReg(...@@ -134683,7 +134674,7 @@ fn genSetReg(
134683 .segment, .mmx, .ip, .cr, .dr => unreachable,134674 .segment, .mmx, .ip, .cr, .dr => unreachable,
134684 .x87, .sse => {},134675 .x87, .sse => {},
134685 },134676 },
134686 .load_got, .load_tlv => {},134677 .load_got => {},
134687 else => unreachable,134678 else => unreachable,
134688 }134679 }
134689134680
...@@ -134734,7 +134725,6 @@ fn genSetReg(...@@ -134734,7 +134725,6 @@ fn genSetReg(
134734 .payload = try self.addExtra(bits.SymbolOffset{ .sym_index = sym_index }),134725 .payload = try self.addExtra(bits.SymbolOffset{ .sym_index = sym_index }),
134735 } },134726 } },
134736 }),134727 }),
134737 .lea_tlv => unreachable, // TODO: remove this
134738 .air_ref => |src_ref| try self.genSetReg(dst_reg, ty, try self.resolveInst(src_ref), opts),134728 .air_ref => |src_ref| try self.genSetReg(dst_reg, ty, try self.resolveInst(src_ref), opts),
134739 }134729 }
134740}134730}
...@@ -134952,8 +134942,6 @@ fn genSetMem(...@@ -134952,8 +134942,6 @@ fn genSetMem(
134952 .lea_direct,134942 .lea_direct,
134953 .load_got,134943 .load_got,
134954 .lea_got,134944 .lea_got,
134955 .load_tlv,
134956 .lea_tlv,
134957 .load_frame,134945 .load_frame,
134958 .lea_frame,134946 .lea_frame,
134959 .load_symbol,134947 .load_symbol,
...@@ -138121,11 +138109,7 @@ fn airAggregateInit(self: *CodeGen, inst: Air.Inst.Index) !void {...@@ -138121,11 +138109,7 @@ fn airAggregateInit(self: *CodeGen, inst: Air.Inst.Index) !void {
138121 const elem_byte_off: i32 = @intCast(elem_off / elem_abi_bits * elem_abi_size);138109 const elem_byte_off: i32 = @intCast(elem_off / elem_abi_bits * elem_abi_size);
138122 const elem_bit_off = elem_off % elem_abi_bits;138110 const elem_bit_off = elem_off % elem_abi_bits;
138123 const elem_mcv = try self.resolveInst(elem);138111 const elem_mcv = try self.resolveInst(elem);
138124 const mat_elem_mcv = switch (elem_mcv) {138112 const elem_lock = 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) {
138129 .register => |reg| self.register_manager.lockReg(reg),138113 .register => |reg| self.register_manager.lockReg(reg),
138130 .immediate => |imm| lock: {138114 .immediate => |imm| lock: {
138131 if (imm == 0) continue;138115 if (imm == 0) continue;
...@@ -138137,7 +138121,7 @@ fn airAggregateInit(self: *CodeGen, inst: Air.Inst.Index) !void {...@@ -138137,7 +138121,7 @@ fn airAggregateInit(self: *CodeGen, inst: Air.Inst.Index) !void {
138137138121
138138 const elem_extra_bits = self.regExtraBits(elem_ty);138122 const elem_extra_bits = self.regExtraBits(elem_ty);
138139 {138123 {
138140 const temp_reg = try self.copyToTmpRegister(elem_ty, mat_elem_mcv);138124 const temp_reg = try self.copyToTmpRegister(elem_ty, elem_mcv);
138141 const temp_alias = registerAlias(temp_reg, elem_abi_size);138125 const temp_alias = registerAlias(temp_reg, elem_abi_size);
138142 const temp_lock = self.register_manager.lockRegAssumeUnused(temp_reg);138126 const temp_lock = self.register_manager.lockRegAssumeUnused(temp_reg);
138143 defer self.register_manager.unlockReg(temp_lock);138127 defer self.register_manager.unlockReg(temp_lock);
...@@ -138160,7 +138144,7 @@ fn airAggregateInit(self: *CodeGen, inst: Air.Inst.Index) !void {...@@ -138160,7 +138144,7 @@ fn airAggregateInit(self: *CodeGen, inst: Air.Inst.Index) !void {
138160 );138144 );
138161 }138145 }
138162 if (elem_bit_off > elem_extra_bits) {138146 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);
138164 const temp_alias = registerAlias(temp_reg, elem_abi_size);138148 const temp_alias = registerAlias(temp_reg, elem_abi_size);
138165 const temp_lock = self.register_manager.lockRegAssumeUnused(temp_reg);138149 const temp_lock = self.register_manager.lockRegAssumeUnused(temp_reg);
138166 defer self.register_manager.unlockReg(temp_lock);138150 defer self.register_manager.unlockReg(temp_lock);
...@@ -138192,11 +138176,7 @@ fn airAggregateInit(self: *CodeGen, inst: Air.Inst.Index) !void {...@@ -138192,11 +138176,7 @@ fn airAggregateInit(self: *CodeGen, inst: Air.Inst.Index) !void {
138192 const elem_ty = result_ty.fieldType(elem_i, zcu);138176 const elem_ty = result_ty.fieldType(elem_i, zcu);
138193 const elem_off: i32 = @intCast(result_ty.structFieldOffset(elem_i, zcu));138177 const elem_off: i32 = @intCast(result_ty.structFieldOffset(elem_i, zcu));
138194 const elem_mcv = try self.resolveInst(elem);138178 const elem_mcv = try self.resolveInst(elem);
138195 const mat_elem_mcv = switch (elem_mcv) {138179 try self.genSetMem(.{ .frame = frame_index }, elem_off, elem_ty, 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, .{});
138200 }138180 }
138201 break :result .{ .load_frame = .{ .index = frame_index } };138181 break :result .{ .load_frame = .{ .index = frame_index } };
138202 },138182 },
...@@ -138239,16 +138219,12 @@ fn airAggregateInit(self: *CodeGen, inst: Air.Inst.Index) !void {...@@ -138239,16 +138219,12 @@ fn airAggregateInit(self: *CodeGen, inst: Air.Inst.Index) !void {
138239138219
138240 for (elements, 0..) |elem, elem_i| {138220 for (elements, 0..) |elem, elem_i| {
138241 const elem_mcv = try self.resolveInst(elem);138221 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 };
138246 const elem_off: i32 = @intCast(elem_size * elem_i);138222 const elem_off: i32 = @intCast(elem_size * elem_i);
138247 try self.genSetMem(138223 try self.genSetMem(
138248 .{ .frame = frame_index },138224 .{ .frame = frame_index },
138249 elem_off,138225 elem_off,
138250 elem_ty,138226 elem_ty,
138251 mat_elem_mcv,138227 elem_mcv,
138252 .{},138228 .{},
138253 );138229 );
138254 }138230 }
...@@ -138744,32 +138720,7 @@ fn resolveInst(self: *CodeGen, ref: Air.Inst.Ref) InnerError!MCValue {...@@ -138744,32 +138720,7 @@ fn resolveInst(self: *CodeGen, ref: Air.Inst.Ref) InnerError!MCValue {
138744 const mcv: MCValue = if (ref.toIndex()) |inst| mcv: {138720 const mcv: MCValue = if (ref.toIndex()) |inst| mcv: {
138745 break :mcv self.inst_tracking.getPtr(inst).?.short;138721 break :mcv self.inst_tracking.getPtr(inst).?.short;
138746 } else mcv: {138722 } else mcv: {
138747 const const_mcv = try self.genTypedValue(.fromInterned(ref.toInterned().?));138723 break :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 }
138773 };138724 };
138774138725
138775 switch (mcv) {138726 switch (mcv) {
...@@ -138819,7 +138770,6 @@ fn genResult(self: *CodeGen, res: codegen.GenResult) InnerError!MCValue {...@@ -138819,7 +138770,6 @@ fn genResult(self: *CodeGen, res: codegen.GenResult) InnerError!MCValue {
138819 .load_direct => |sym_index| .{ .load_direct = sym_index },138770 .load_direct => |sym_index| .{ .load_direct = sym_index },
138820 .lea_direct => |sym_index| .{ .lea_direct = sym_index },138771 .lea_direct => |sym_index| .{ .lea_direct = sym_index },
138821 .load_got => |sym_index| .{ .lea_got = sym_index },138772 .load_got => |sym_index| .{ .lea_got = sym_index },
138822 .load_tlv => |sym_index| .{ .lea_tlv = sym_index },
138823 },138773 },
138824 .fail => |msg| return self.failMsg(msg),138774 .fail => |msg| return self.failMsg(msg),
138825 };138775 };
...@@ -139686,8 +139636,6 @@ const Temp = struct {...@@ -139686,8 +139636,6 @@ const Temp = struct {
139686 .lea_direct,139636 .lea_direct,
139687 .load_got,139637 .load_got,
139688 .lea_got,139638 .lea_got,
139689 .load_tlv,
139690 .lea_tlv,
139691 .lea_frame,139639 .lea_frame,
139692 .elementwise_regs_then_frame,139640 .elementwise_regs_then_frame,
139693 .reserved_frame,139641 .reserved_frame,
...@@ -140133,7 +140081,6 @@ const Temp = struct {...@@ -140133,7 +140081,6 @@ const Temp = struct {
140133 .register_offset,140081 .register_offset,
140134 .lea_direct,140082 .lea_direct,
140135 .lea_got,140083 .lea_got,
140136 .lea_tlv,
140137 .lea_frame,140084 .lea_frame,
140138 => return false,140085 => return false,
140139 .memory,140086 .memory,
...@@ -140141,7 +140088,6 @@ const Temp = struct {...@@ -140141,7 +140088,6 @@ const Temp = struct {
140141 .load_symbol,140088 .load_symbol,
140142 .load_direct,140089 .load_direct,
140143 .load_got,140090 .load_got,
140144 .load_tlv,
140145 .load_frame,140091 .load_frame,
140146 => return temp.toRegClass(true, .general_purpose, cg),140092 => return temp.toRegClass(true, .general_purpose, cg),
140147 .lea_symbol => |sym_off| {140093 .lea_symbol => |sym_off| {
...@@ -145048,34 +144994,7 @@ fn tempFromOperand(cg: *CodeGen, op_ref: Air.Inst.Ref, op_dies: bool) InnerError...@@ -145048,34 +144994,7 @@ fn tempFromOperand(cg: *CodeGen, op_ref: Air.Inst.Ref, op_dies: bool) InnerError
145048144994
145049 if (op_ref.toIndex()) |op_inst| return .{ .index = op_inst };144995 if (op_ref.toIndex()) |op_inst| return .{ .index = op_inst };
145050 const val = op_ref.toInterned().?;144996 const val = op_ref.toInterned().?;
145051 return cg.tempInit(.fromInterned(ip.typeOf(val)), init: {144997 return cg.tempInit(.fromInterned(ip.typeOf(val)), try cg.genTypedValue(.fromInterned(val)));
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 });
145079}144998}
145080144999
145081fn tempsFromOperandsInner(145000fn tempsFromOperandsInner(
src/codegen.zig+4-14
...@@ -818,10 +818,6 @@ pub const GenResult = union(enum) {...@@ -818,10 +818,6 @@ pub const GenResult = union(enum) {
818 /// The bit-width of the immediate may be smaller than `u64`. For example, on 32-bit targets818 /// The bit-width of the immediate may be smaller than `u64`. For example, on 32-bit targets
819 /// such as ARM, the immediate will never exceed 32-bits.819 /// such as ARM, the immediate will never exceed 32-bits.
820 immediate: u64,820 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,
825 /// Decl with address deferred until the linker allocates everything in virtual memory.821 /// Decl with address deferred until the linker allocates everything in virtual memory.
826 /// Payload is a symbol index.822 /// Payload is a symbol index.
827 load_direct: u32,823 load_direct: u32,
...@@ -883,13 +879,13 @@ fn genNavRef(...@@ -883,13 +879,13 @@ fn genNavRef(
883 }879 }
884880
885 const nav = ip.getNav(nav_index);881 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|884 const is_extern, const lib_name = if (nav.getExtern(ip)) |e|
888 .{ true, e.lib_name, e.is_threadlocal }885 .{ true, e.lib_name }
889 else886 else
890 .{ false, .none, nav.isThreadlocal(ip) };887 .{ false, .none };
891888
892 const single_threaded = zcu.navFileScope(nav_index).mod.?.single_threaded;
893 const name = nav.name;889 const name = nav.name;
894 if (lf.cast(.elf)) |elf_file| {890 if (lf.cast(.elf)) |elf_file| {
895 const zo = elf_file.zigObjectPtr().?;891 const zo = elf_file.zigObjectPtr().?;
...@@ -899,9 +895,6 @@ fn genNavRef(...@@ -899,9 +895,6 @@ fn genNavRef(
899 return .{ .mcv = .{ .lea_symbol = sym_index } };895 return .{ .mcv = .{ .lea_symbol = sym_index } };
900 }896 }
901 const sym_index = try zo.getOrCreateMetadataForNav(zcu, nav_index);897 const sym_index = try zo.getOrCreateMetadataForNav(zcu, nav_index);
902 if (!single_threaded and is_threadlocal) {
903 return .{ .mcv = .{ .load_tlv = sym_index } };
904 }
905 return .{ .mcv = .{ .lea_symbol = sym_index } };898 return .{ .mcv = .{ .lea_symbol = sym_index } };
906 } else if (lf.cast(.macho)) |macho_file| {899 } else if (lf.cast(.macho)) |macho_file| {
907 const zo = macho_file.getZigObject().?;900 const zo = macho_file.getZigObject().?;
...@@ -912,9 +905,6 @@ fn genNavRef(...@@ -912,9 +905,6 @@ fn genNavRef(
912 }905 }
913 const sym_index = try zo.getOrCreateMetadataForNav(macho_file, nav_index);906 const sym_index = try zo.getOrCreateMetadataForNav(macho_file, nav_index);
914 const sym = zo.symbols.items[sym_index];907 const sym = zo.symbols.items[sym_index];
915 if (!single_threaded and is_threadlocal) {
916 return .{ .mcv = .{ .load_tlv = sym.nlist_idx } };
917 }
918 return .{ .mcv = .{ .lea_symbol = sym.nlist_idx } };908 return .{ .mcv = .{ .lea_symbol = sym.nlist_idx } };
919 } else if (lf.cast(.coff)) |coff_file| {909 } else if (lf.cast(.coff)) |coff_file| {
920 if (is_extern) {910 if (is_extern) {
src/codegen/c.zig+13
...@@ -3453,6 +3453,8 @@ fn genBodyInner(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail,...@@ -3453,6 +3453,8 @@ fn genBodyInner(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail,
3453 .error_set_has_value => return f.fail("TODO: C backend: implement error_set_has_value", .{}),3453 .error_set_has_value => return f.fail("TODO: C backend: implement error_set_has_value", .{}),
3454 .vector_store_elem => return f.fail("TODO: C backend: implement vector_store_elem", .{}),3454 .vector_store_elem => return f.fail("TODO: C backend: implement vector_store_elem", .{}),
34553455
3456 .tlv_dllimport_ptr => try airTlvDllimportPtr(f, inst),
3457
3456 .c_va_start => try airCVaStart(f, inst),3458 .c_va_start => try airCVaStart(f, inst),
3457 .c_va_arg => try airCVaArg(f, inst),3459 .c_va_arg => try airCVaArg(f, inst),
3458 .c_va_end => try airCVaEnd(f, inst),3460 .c_va_end => try airCVaEnd(f, inst),
...@@ -7617,6 +7619,17 @@ fn airMulAdd(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -7617,6 +7619,17 @@ fn airMulAdd(f: *Function, inst: Air.Inst.Index) !CValue {
7617 return local;7619 return local;
7618}7620}
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
7620fn airCVaStart(f: *Function, inst: Air.Inst.Index) !CValue {7633fn airCVaStart(f: *Function, inst: Air.Inst.Index) !CValue {
7621 const pt = f.object.dg.pt;7634 const pt = f.object.dg.pt;
7622 const zcu = pt.zcu;7635 const zcu = pt.zcu;
src/codegen/llvm.zig+9
...@@ -5015,6 +5015,8 @@ pub const FuncGen = struct {...@@ -5015,6 +5015,8 @@ pub const FuncGen = struct {
50155015
5016 .vector_store_elem => try self.airVectorStoreElem(inst),5016 .vector_store_elem => try self.airVectorStoreElem(inst),
50175017
5018 .tlv_dllimport_ptr => try self.airTlvDllimportPtr(inst),
5019
5018 .inferred_alloc, .inferred_alloc_comptime => unreachable,5020 .inferred_alloc, .inferred_alloc_comptime => unreachable,
50195021
5020 .dbg_stmt => try self.airDbgStmt(inst),5022 .dbg_stmt => try self.airDbgStmt(inst),
...@@ -8112,6 +8114,13 @@ pub const FuncGen = struct {...@@ -8112,6 +8114,13 @@ pub const FuncGen = struct {
8112 return .none;8114 return .none;
8113 }8115 }
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
8115 fn airMin(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {8124 fn airMin(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
8116 const o = self.ng.object;8125 const o = self.ng.object;
8117 const zcu = o.pt.zcu;8126 const zcu = o.pt.zcu;
src/print_air.zig+8
...@@ -320,6 +320,7 @@ const Writer = struct {...@@ -320,6 +320,7 @@ const Writer = struct {
320 .reduce, .reduce_optimized => try w.writeReduce(s, inst),320 .reduce, .reduce_optimized => try w.writeReduce(s, inst),
321 .cmp_vector, .cmp_vector_optimized => try w.writeCmpVector(s, inst),321 .cmp_vector, .cmp_vector_optimized => try w.writeCmpVector(s, inst),
322 .vector_store_elem => try w.writeVectorStoreElem(s, inst),322 .vector_store_elem => try w.writeVectorStoreElem(s, inst),
323 .tlv_dllimport_ptr => try w.writeTlvDllimportPtr(s, inst),
323324
324 .work_item_id,325 .work_item_id,
325 .work_group_size,326 .work_group_size,
...@@ -552,6 +553,13 @@ const Writer = struct {...@@ -552,6 +553,13 @@ const Writer = struct {
552 try w.writeOperand(s, inst, 2, extra.rhs);553 try w.writeOperand(s, inst, 2, extra.rhs);
553 }554 }
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
555 fn writeAtomicLoad(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {563 fn writeAtomicLoad(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {
556 const atomic_load = w.air.instructions.items(.data)[@intFromEnum(inst)].atomic_load;564 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" {...@@ -7,6 +7,8 @@ test "thread local variable" {
7 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO7 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
8 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO8 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
9 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO9 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
11 if (builtin.zig_backend == .stage2_x86_64 and builtin.os.tag == .macos) {13 if (builtin.zig_backend == .stage2_x86_64 and builtin.os.tag == .macos) {
12 // Fails due to register hazards.14 // Fails due to register hazards.
...@@ -26,6 +28,7 @@ test "pointer to thread local array" {...@@ -26,6 +28,7 @@ test "pointer to thread local array" {
26 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO28 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
27 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO29 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
28 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;30 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
30 const s = "Hello world";33 const s = "Hello world";
31 @memcpy(buffer[0..s.len], s);34 @memcpy(buffer[0..s.len], s);
...@@ -40,6 +43,7 @@ test "reference a global threadlocal variable" {...@@ -40,6 +43,7 @@ test "reference a global threadlocal variable" {
40 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO43 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
41 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO44 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
42 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;45 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
44 _ = nrfx_uart_rx(&g_uart0);48 _ = nrfx_uart_rx(&g_uart0);
45}49}
test/cases/compile_errors/address_of_threadlocal_not_comptime_known.zig-3
...@@ -6,9 +6,6 @@ pub export fn entry() void {...@@ -6,9 +6,6 @@ pub export fn entry() void {
6}6}
77
8// error8// error
9// backend=stage2
10// target=native
11//9//
12// :2:36: error: unable to resolve comptime value10// :2:36: error: unable to resolve comptime value
13// :2:36: note: initializer of container-level variable must be comptime-known11// :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 {...@@ -7,12 +7,8 @@ pub export fn entry2() void {
7 _ = foo_dll;7 _ = foo_dll;
8}8}
9// error9// error
10// backend=stage2
11// target=native
12//10//
13// :1:16: error: unable to resolve comptime value11// :1:16: error: unable to resolve comptime value
14// :1:16: note: initializer of container-level variable must be comptime-known12// :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
16// :2:17: error: unable to resolve comptime value13// :2:17: error: unable to resolve comptime value
17// :2:17: note: initializer of container-level variable must be comptime-known14// :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