diff --git a/lib/std/debug.zig b/lib/std/debug.zig index 91ff367c2d..7b55a05db5 100644 --- a/lib/std/debug.zig +++ b/lib/std/debug.zig @@ -1530,6 +1530,12 @@ fn handleSegfaultWindows(info: *windows.EXCEPTION_POINTERS) callconv(.winapi) c_ } fn handleSegfaultWindowsExtra(info: *windows.EXCEPTION_POINTERS, msg: u8, label: ?[]const u8) noreturn { + // For backends that cannot handle the language features used by this segfault handler, we have a simpler one, + switch (builtin.zig_backend) { + .stage2_x86_64 => if (builtin.target.ofmt == .coff) @trap(), + else => {}, + } + comptime assert(windows.CONTEXT != void); nosuspend switch (panic_stage) { 0 => { diff --git a/src/Air.zig b/src/Air.zig index 86fc948fd8..6109e93aee 100644 --- a/src/Air.zig +++ b/src/Air.zig @@ -849,6 +849,17 @@ pub const Inst = struct { /// Uses the `vector_store_elem` field. vector_store_elem, + /// Compute a pointer to a threadlocal or dllimport `Nav`, meaning one of: + /// + /// * `threadlocal var` + /// * `extern threadlocal var` (or corresponding `@extern`) + /// * `@extern` with `.is_dll_import = true` + /// + /// Such pointers are runtime values, so cannot be represented with an InternPool index. + /// + /// Uses the `ty_nav` field. + tlv_dllimport_ptr, + /// Implements @cVaArg builtin. /// Uses the `ty_op` field. c_va_arg, @@ -1150,6 +1161,10 @@ pub const Inst = struct { // Index into a different array. payload: u32, }, + ty_nav: struct { + ty: InternPool.Index, + nav: InternPool.Nav.Index, + }, inferred_alloc_comptime: InferredAllocComptime, inferred_alloc: InferredAlloc, @@ -1604,6 +1619,8 @@ pub fn typeOfIndex(air: *const Air, inst: Air.Inst.Index, ip: *const InternPool) return Type.fromInterned(ip.indexToKey(err_union_ty.ip_index).error_union_type.payload_type); }, + .tlv_dllimport_ptr => return .fromInterned(datas[@intFromEnum(inst)].ty_nav.ty), + .work_item_id, .work_group_size, .work_group_id, @@ -1876,6 +1893,7 @@ pub fn mustLower(air: Air, inst: Air.Inst.Index, ip: *const InternPool) bool { .err_return_trace, .addrspace_cast, .save_err_return_trace_index, + .tlv_dllimport_ptr, .work_item_id, .work_group_size, .work_group_id, diff --git a/src/Air/types_resolved.zig b/src/Air/types_resolved.zig index bb3cc4c19f..fcc2667a29 100644 --- a/src/Air/types_resolved.zig +++ b/src/Air/types_resolved.zig @@ -311,6 +311,10 @@ fn checkBody(air: Air, body: []const Air.Inst.Index, zcu: *Zcu) bool { if (!checkRef(bin.rhs, zcu)) return false; }, + .tlv_dllimport_ptr => { + if (!checkType(.fromInterned(data.ty_nav.ty), zcu)) return false; + }, + .select, .mul_add, => { diff --git a/src/InternPool.zig b/src/InternPool.zig index f72244a929..7498f51fa4 100644 --- a/src/InternPool.zig +++ b/src/InternPool.zig @@ -12036,30 +12036,6 @@ pub fn isVariable(ip: *const InternPool, val: Index) bool { return val.unwrap(ip).getTag(ip) == .variable; } -pub fn getBackingNav(ip: *const InternPool, val: Index) Nav.Index.Optional { - var base = val; - while (true) { - const unwrapped_base = base.unwrap(ip); - const base_item = unwrapped_base.getItem(ip); - switch (base_item.tag) { - .ptr_nav => return @enumFromInt(unwrapped_base.getExtra(ip).view().items(.@"0")[ - base_item.data + std.meta.fieldIndex(PtrNav, "nav").? - ]), - inline .ptr_eu_payload, - .ptr_opt_payload, - .ptr_elem, - .ptr_field, - => |tag| base = @enumFromInt(unwrapped_base.getExtra(ip).view().items(.@"0")[ - base_item.data + std.meta.fieldIndex(tag.Payload(), "base").? - ]), - .ptr_slice => base = @enumFromInt(unwrapped_base.getExtra(ip).view().items(.@"0")[ - base_item.data + std.meta.fieldIndex(PtrSlice, "ptr").? - ]), - else => return .none, - } - } -} - pub fn getBackingAddrTag(ip: *const InternPool, val: Index) ?Key.Ptr.BaseAddr.Tag { var base = val; while (true) { diff --git a/src/Liveness.zig b/src/Liveness.zig index 87b63d93d5..9c47e12679 100644 --- a/src/Liveness.zig +++ b/src/Liveness.zig @@ -334,6 +334,7 @@ pub fn categorizeOperand( .wasm_memory_size, .err_return_trace, .save_err_return_trace_index, + .tlv_dllimport_ptr, .c_va_start, .work_item_id, .work_group_size, @@ -960,6 +961,7 @@ fn analyzeInst( .wasm_memory_size, .err_return_trace, .save_err_return_trace_index, + .tlv_dllimport_ptr, .c_va_start, .work_item_id, .work_group_size, diff --git a/src/Liveness/Verify.zig b/src/Liveness/Verify.zig index 449dbb63fb..1d61145b3c 100644 --- a/src/Liveness/Verify.zig +++ b/src/Liveness/Verify.zig @@ -62,6 +62,7 @@ fn verifyBody(self: *Verify, body: []const Air.Inst.Index) Error!void { .wasm_memory_size, .err_return_trace, .save_err_return_trace_index, + .tlv_dllimport_ptr, .c_va_start, .work_item_id, .work_group_size, diff --git a/src/Sema.zig b/src/Sema.zig index e7f47a1791..46dc8cf857 100644 --- a/src/Sema.zig +++ b/src/Sema.zig @@ -2223,10 +2223,7 @@ fn resolveValue(sema: *Sema, inst: Air.Inst.Ref) CompileError!?Value { if (inst.toInterned()) |ip_index| { const val: Value = .fromInterned(ip_index); - assert(val.getVariable(zcu) == null); - if (val.isPtrRuntimeValue(zcu)) return null; - return val; } else { // Runtime-known value. @@ -2295,31 +2292,12 @@ pub fn resolveFinalDeclValue( air_ref: Air.Inst.Ref, ) CompileError!Value { const zcu = sema.pt.zcu; - - const val = try sema.resolveValue(air_ref) orelse { - const is_runtime_ptr = rt_ptr: { - const ip_index = air_ref.toInterned() orelse break :rt_ptr false; - const val: Value = .fromInterned(ip_index); - break :rt_ptr val.isPtrRuntimeValue(zcu); - }; - - switch (sema.failWithNeededComptime(block, src, .{ .simple = .container_var_init })) { - error.AnalysisFail => |e| { - if (sema.err != null and is_runtime_ptr) { - try sema.errNote(src, sema.err.?, "threadlocal and dll imported variables have runtime-known addresses", .{}); - } - return e; - }, - else => |e| return e, - } - }; - + const val = try sema.resolveConstValue(block, src, air_ref, .{ .simple = .container_var_init }); if (val.canMutateComptimeVarState(zcu)) { const ip = &zcu.intern_pool; const nav = ip.getNav(sema.owner.unwrap().nav_val); return sema.failWithContainsReferenceToComptimeVar(block, src, nav.name, "global variable", val); } - return val; } @@ -26506,6 +26484,7 @@ fn zirBuiltinExtern( const zcu = pt.zcu; const ip = &zcu.intern_pool; const extra = sema.code.extraData(Zir.Inst.BinNode, extended.operand).data; + const src = block.nodeOffset(extra.node); const ty_src = block.builtinCallArgSrc(extra.node, 0); const options_src = block.builtinCallArgSrc(extra.node, 1); @@ -26560,17 +26539,15 @@ fn zirBuiltinExtern( }, .owner_nav = undefined, // ignored by `getExtern` }); - const extern_nav = ip.indexToKey(extern_val).@"extern".owner_nav; - return Air.internedToRef((try pt.getCoerced(Value.fromInterned(try pt.intern(.{ .ptr = .{ - .ty = switch (ip.indexToKey(ty.toIntern())) { - .ptr_type => ty.toIntern(), - .opt_type => |child_type| child_type, - else => unreachable, - }, - .base_addr = .{ .nav = extern_nav }, - .byte_offset = 0, - } })), ty)).toIntern()); + const uncasted_ptr = try sema.analyzeNavRef(block, src, ip.indexToKey(extern_val).@"extern".owner_nav); + // We want to cast to `ty`, but that isn't necessarily an allowed coercion. + if (try sema.resolveValue(uncasted_ptr)) |uncasted_ptr_val| { + const casted_ptr_val = try pt.getCoerced(uncasted_ptr_val, ty); + return Air.internedToRef(casted_ptr_val.toIntern()); + } else { + return block.addBitCast(ty, uncasted_ptr); + } } fn zirWorkItem( @@ -32037,7 +32014,20 @@ fn analyzeNavRefInner(sema: *Sema, block: *Block, src: LazySrcLoc, orig_nav_inde break :nav orig_nav_index; }; - const ty, const alignment, const @"addrspace", const is_const = switch (ip.getNav(nav_index).status) { + const nav_status = ip.getNav(nav_index).status; + + const is_tlv_or_dllimport = switch (nav_status) { + .unresolved => unreachable, + // dllimports go straight to `fully_resolved`; the only option is threadlocal + .type_resolved => |r| r.is_threadlocal, + .fully_resolved => |r| switch (ip.indexToKey(r.val)) { + .@"extern" => |e| e.is_threadlocal or e.is_dll_import, + .variable => |v| v.is_threadlocal, + else => false, + }, + }; + + const ty, const alignment, const @"addrspace", const is_const = switch (nav_status) { .unresolved => unreachable, .type_resolved => |r| .{ r.type, r.alignment, r.@"addrspace", r.is_const }, .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 .address_space = @"addrspace", }, }); + + if (is_tlv_or_dllimport) { + // This pointer is runtime-known; we need to emit an AIR instruction to create it. + return block.addInst(.{ + .tag = .tlv_dllimport_ptr, + .data = .{ .ty_nav = .{ + .ty = ptr_ty.toIntern(), + .nav = nav_index, + } }, + }); + } + if (is_ref) { try sema.maybeQueueFuncBodyAnalysis(block, src, nav_index); } + return Air.internedToRef((try pt.intern(.{ .ptr = .{ .ty = ptr_ty.toIntern(), .base_addr = .{ .nav = nav_index }, diff --git a/src/Value.zig b/src/Value.zig index 6d041bc5d2..55b047f7ca 100644 --- a/src/Value.zig +++ b/src/Value.zig @@ -1325,21 +1325,6 @@ pub fn isLazySize(val: Value, zcu: *Zcu) bool { }; } -pub fn isPtrRuntimeValue(val: Value, zcu: *Zcu) bool { - const ip = &zcu.intern_pool; - const nav = ip.getBackingNav(val.toIntern()).unwrap() orelse return false; - const nav_val = switch (ip.getNav(nav).status) { - .unresolved => unreachable, - .type_resolved => |r| return r.is_threadlocal, - .fully_resolved => |r| r.val, - }; - return switch (ip.indexToKey(nav_val)) { - .@"extern" => |e| e.is_threadlocal or e.is_dll_import, - .variable => |v| v.is_threadlocal, - else => false, - }; -} - // Asserts that the provided start/end are in-bounds. pub fn sliceArray( val: Value, diff --git a/src/arch/aarch64/CodeGen.zig b/src/arch/aarch64/CodeGen.zig index 741199159f..5c5ccfa6ae 100644 --- a/src/arch/aarch64/CodeGen.zig +++ b/src/arch/aarch64/CodeGen.zig @@ -876,6 +876,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { .is_named_enum_value => return self.fail("TODO implement is_named_enum_value", .{}), .error_set_has_value => return self.fail("TODO implement error_set_has_value", .{}), .vector_store_elem => return self.fail("TODO implement vector_store_elem", .{}), + .tlv_dllimport_ptr => return self.fail("TODO implement tlv_dllimport_ptr", .{}), .c_va_arg => return self.fail("TODO implement c_va_arg", .{}), .c_va_copy => return self.fail("TODO implement c_va_copy", .{}), @@ -6168,7 +6169,7 @@ fn genTypedValue(self: *Self, val: Value) InnerError!MCValue { .memory => |addr| .{ .memory = addr }, .load_got => |sym_index| .{ .linker_load = .{ .type = .got, .sym_index = sym_index } }, .load_direct => |sym_index| .{ .linker_load = .{ .type = .direct, .sym_index = sym_index } }, - .load_symbol, .load_tlv, .lea_symbol, .lea_direct => unreachable, // TODO + .load_symbol, .lea_symbol, .lea_direct => unreachable, // TODO }, .fail => |msg| return self.failMsg(msg), }; diff --git a/src/arch/arm/CodeGen.zig b/src/arch/arm/CodeGen.zig index 66c9a5ba09..c665e89a18 100644 --- a/src/arch/arm/CodeGen.zig +++ b/src/arch/arm/CodeGen.zig @@ -865,6 +865,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { .is_named_enum_value => return self.fail("TODO implement is_named_enum_value", .{}), .error_set_has_value => return self.fail("TODO implement error_set_has_value", .{}), .vector_store_elem => return self.fail("TODO implement vector_store_elem", .{}), + .tlv_dllimport_ptr => return self.fail("TODO implement tlv_dllimport_ptr", .{}), .c_va_arg => return self.fail("TODO implement c_va_arg", .{}), .c_va_copy => return self.fail("TODO implement c_va_copy", .{}), @@ -6135,7 +6136,7 @@ fn genTypedValue(self: *Self, val: Value) InnerError!MCValue { .mcv => |mcv| switch (mcv) { .none => .none, .undef => .undef, - .load_got, .load_symbol, .load_direct, .load_tlv, .lea_symbol, .lea_direct => unreachable, // TODO + .load_got, .load_symbol, .load_direct, .lea_symbol, .lea_direct => unreachable, // TODO .immediate => |imm| .{ .immediate = @truncate(imm) }, .memory => |addr| .{ .memory = addr }, }, diff --git a/src/arch/riscv64/CodeGen.zig b/src/arch/riscv64/CodeGen.zig index 2267816195..0d5a9103db 100644 --- a/src/arch/riscv64/CodeGen.zig +++ b/src/arch/riscv64/CodeGen.zig @@ -162,12 +162,8 @@ const MCValue = union(enum) { immediate: u64, /// The value doesn't exist in memory yet. load_symbol: SymbolOffset, - /// A TLV value. - load_tlv: u32, /// The address of the memory location not-yet-allocated by the linker. lea_symbol: SymbolOffset, - /// The address of a TLV value. - lea_tlv: u32, /// The value is in a target-specific register. register: Register, /// The value is split across two registers @@ -224,7 +220,6 @@ const MCValue = union(enum) { .lea_frame, .undef, .lea_symbol, - .lea_tlv, .air_ref, .reserved_frame, => false, @@ -233,7 +228,6 @@ const MCValue = union(enum) { .register_pair, .register_offset, .load_symbol, - .load_tlv, .indirect, => true, @@ -254,12 +248,10 @@ const MCValue = union(enum) { .undef, .air_ref, .lea_symbol, - .lea_tlv, .reserved_frame, => unreachable, // not in memory .load_symbol => |sym_off| .{ .lea_symbol = sym_off }, - .load_tlv => |sym| .{ .lea_tlv = sym }, .memory => |addr| .{ .immediate = addr }, .load_frame => |off| .{ .lea_frame = off }, .indirect => |reg_off| switch (reg_off.off) { @@ -281,7 +273,6 @@ const MCValue = union(enum) { .register_pair, .load_frame, .load_symbol, - .load_tlv, .reserved_frame, => unreachable, // not a pointer @@ -290,7 +281,6 @@ const MCValue = union(enum) { .register_offset => |reg_off| .{ .indirect = reg_off }, .lea_frame => |off| .{ .load_frame = off }, .lea_symbol => |sym_off| .{ .load_symbol = sym_off }, - .lea_tlv => |sym| .{ .load_tlv = sym }, }; } @@ -308,8 +298,6 @@ const MCValue = union(enum) { .indirect, .load_symbol, .lea_symbol, - .lea_tlv, - .load_tlv, => switch (off) { 0 => mcv, else => unreachable, @@ -367,8 +355,6 @@ const InstTracking = struct { .memory, .load_frame, .lea_frame, - .load_tlv, - .lea_tlv, .load_symbol, .lea_symbol, => result, @@ -424,8 +410,6 @@ const InstTracking = struct { .lea_frame, .load_symbol, .lea_symbol, - .load_tlv, - .lea_tlv, => inst_tracking.long, .dead, .register, @@ -454,8 +438,6 @@ const InstTracking = struct { .lea_frame, .load_symbol, .lea_symbol, - .load_tlv, - .lea_tlv, => assert(std.meta.eql(inst_tracking.long, target.long)), .load_frame, .reserved_frame, @@ -1665,6 +1647,8 @@ fn genBody(func: *Func, body: []const Air.Inst.Index) InnerError!void { .wrap_errunion_payload => try func.airWrapErrUnionPayload(inst), .wrap_errunion_err => try func.airWrapErrUnionErr(inst), + .tlv_dllimport_ptr => try func.airTlvDllimportPtr(inst), + .add_optimized, .sub_optimized, .mul_optimized, @@ -3620,6 +3604,50 @@ fn airWrapErrUnionErr(func: *Func, inst: Air.Inst.Index) !void { return func.finishAir(inst, result, .{ ty_op.operand, .none, .none }); } +fn airTlvDllimportPtr(func: *Func, inst: Air.Inst.Index) !void { + const zcu = func.pt.zcu; + const ip = &zcu.intern_pool; + const ty_nav = func.air.instructions.items(.data)[@intFromEnum(inst)].ty_nav; + const ptr_ty: Type = .fromInterned(ty_nav.ty); + + const nav = ip.getNav(ty_nav.nav); + const tlv_sym_index = if (func.bin_file.cast(.elf)) |elf_file| sym: { + const zo = elf_file.zigObjectPtr().?; + if (nav.getExtern(ip)) |e| { + const sym = try elf_file.getGlobalSymbol(nav.name.toSlice(ip), e.lib_name.toSlice(ip)); + zo.symbol(sym).flags.is_extern_ptr = true; + break :sym sym; + } + break :sym try zo.getOrCreateMetadataForNav(zcu, ty_nav.nav); + } else return func.fail("TODO tlv_dllimport_ptr on {}", .{func.bin_file.tag}); + + const dest_mcv = try func.allocRegOrMem(ptr_ty, inst, true); + if (dest_mcv.isRegister()) { + _ = try func.addInst(.{ + .tag = .pseudo_load_tlv, + .data = .{ .reloc = .{ + .register = dest_mcv.getReg().?, + .atom_index = try func.owner.getSymbolIndex(func), + .sym_index = tlv_sym_index, + } }, + }); + } else { + const tmp_reg, const tmp_lock = try func.allocReg(.int); + defer func.register_manager.unlockReg(tmp_lock); + _ = try func.addInst(.{ + .tag = .pseudo_load_tlv, + .data = .{ .reloc = .{ + .register = tmp_reg, + .atom_index = try func.owner.getSymbolIndex(func), + .sym_index = tlv_sym_index, + } }, + }); + try func.genCopy(ptr_ty, dest_mcv, .{ .register = tmp_reg }); + } + + return func.finishAir(inst, dest_mcv, .{ .none, .none, .none }); +} + fn airTry(func: *Func, inst: Air.Inst.Index) !void { const pl_op = func.air.instructions.items(.data)[@intFromEnum(inst)].pl_op; 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 .register_offset, .lea_frame, .lea_symbol, - .lea_tlv, => try func.genCopy(dst_ty, dst_mcv, ptr_mcv.deref()), .memory, .indirect, .load_symbol, .load_frame, - .load_tlv, => { const addr_reg = try func.copyToTmpRegister(ptr_ty, ptr_mcv); 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 { .register_offset, .lea_symbol, .lea_frame, - .lea_tlv, => try func.genCopy(src_ty, ptr_mcv.deref(), src_mcv), .memory, .indirect, .load_symbol, .load_frame, - .load_tlv, => { const addr_reg = try func.copyToTmpRegister(ptr_ty, ptr_mcv); 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 { ty, src_mcv, ), - .load_symbol, .load_tlv => { + .load_symbol => { const addr_reg, const addr_lock = try func.allocReg(.int); defer func.register_manager.unlockReg(addr_lock); @@ -7072,25 +7096,6 @@ fn genSetReg(func: *Func, ty: Type, reg: Register, src_mcv: MCValue) InnerError! try func.genSetReg(ty, addr_reg, src_mcv.address()); try func.genSetReg(ty, reg, .{ .indirect = .{ .reg = addr_reg } }); }, - .lea_tlv => |sym| { - const atom_index = try func.owner.getSymbolIndex(func); - - _ = try func.addInst(.{ - .tag = .pseudo_load_tlv, - .data = .{ .reloc = .{ - .register = reg, - .atom_index = atom_index, - .sym_index = sym, - } }, - }); - }, - .load_tlv => { - const addr_reg, const addr_lock = try func.allocReg(.int); - defer func.register_manager.unlockReg(addr_lock); - - try func.genSetReg(ty, addr_reg, src_mcv.address()); - try func.genSetReg(ty, reg, .{ .indirect = .{ .reg = addr_reg } }); - }, .air_ref => |ref| try func.genSetReg(ty, reg, try func.resolveInst(ref)), else => return func.fail("TODO: genSetReg {s}", .{@tagName(src_mcv)}), } @@ -7256,7 +7261,6 @@ fn genSetMem( return func.genSetMem(base, disp, ty, .{ .register = reg }); }, .air_ref => |src_ref| try func.genSetMem(base, disp, ty, try func.resolveInst(src_ref)), - else => return func.fail("TODO: genSetMem {s}", .{@tagName(src_mcv)}), } } @@ -8190,7 +8194,6 @@ fn genTypedValue(func: *Func, val: Value) InnerError!MCValue { .undef => unreachable, .lea_symbol => |sym_index| .{ .lea_symbol = .{ .sym = sym_index } }, .load_symbol => |sym_index| .{ .load_symbol = .{ .sym = sym_index } }, - .load_tlv => |sym_index| .{ .lea_tlv = sym_index }, .immediate => |imm| .{ .immediate = imm }, .memory => |addr| .{ .memory = addr }, .load_got, .load_direct, .lea_direct => { diff --git a/src/arch/sparc64/CodeGen.zig b/src/arch/sparc64/CodeGen.zig index 33dc2d5e40..4668d2acd4 100644 --- a/src/arch/sparc64/CodeGen.zig +++ b/src/arch/sparc64/CodeGen.zig @@ -719,6 +719,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { .is_named_enum_value => @panic("TODO implement is_named_enum_value"), .error_set_has_value => @panic("TODO implement error_set_has_value"), .vector_store_elem => @panic("TODO implement vector_store_elem"), + .tlv_dllimport_ptr => @panic("TODO implement tlv_dllimport_ptr"), .c_va_arg => return self.fail("TODO implement c_va_arg", .{}), .c_va_copy => return self.fail("TODO implement c_va_copy", .{}), @@ -4088,7 +4089,7 @@ fn genTypedValue(self: *Self, val: Value) InnerError!MCValue { .mcv => |mcv| switch (mcv) { .none => .none, .undef => .undef, - .load_got, .load_symbol, .load_direct, .load_tlv, .lea_symbol, .lea_direct => unreachable, // TODO + .load_got, .load_symbol, .load_direct, .lea_symbol, .lea_direct => unreachable, // TODO .immediate => |imm| .{ .immediate = imm }, .memory => |addr| .{ .memory = addr }, }, diff --git a/src/arch/wasm/CodeGen.zig b/src/arch/wasm/CodeGen.zig index 56bbb46974..c3be73bbca 100644 --- a/src/arch/wasm/CodeGen.zig +++ b/src/arch/wasm/CodeGen.zig @@ -2050,6 +2050,8 @@ fn genInst(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { .error_set_has_value => cg.airErrorSetHasValue(inst), .frame_addr => cg.airFrameAddress(inst), + .tlv_dllimport_ptr => cg.airTlvDllimportPtr(inst), + .assembly, .is_err_ptr, .is_non_err_ptr, @@ -7551,6 +7553,19 @@ fn airFrameAddress(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { return cg.finishAir(inst, .stack, &.{}); } +fn airTlvDllimportPtr(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { + const ty_nav = cg.air.instructions.items(.data)[@intFromEnum(inst)].ty_nav; + const mod = cg.pt.zcu.navFileScope(cg.owner_nav).mod.?; + if (mod.single_threaded) { + const result: WValue = .{ .nav_ref = .{ + .nav_index = ty_nav.nav, + .offset = 0, + } }; + return cg.finishAir(inst, result, &.{}); + } + return cg.fail("TODO: thread-local variables", .{}); +} + fn typeOf(cg: *CodeGen, inst: Air.Inst.Ref) Type { const zcu = cg.pt.zcu; return cg.air.typeOf(inst, &zcu.intern_pool); diff --git a/src/arch/x86_64/CodeGen.zig b/src/arch/x86_64/CodeGen.zig index 36c102cb5d..93bf26241d 100644 --- a/src/arch/x86_64/CodeGen.zig +++ b/src/arch/x86_64/CodeGen.zig @@ -204,12 +204,6 @@ pub const MCValue = union(enum) { /// The value is a pointer to a value referenced indirectly via GOT. /// Payload is a symbol index. lea_got: u32, - /// The value is a threadlocal variable. - /// Payload is a symbol index. - load_tlv: u32, - /// The value is a pointer to a threadlocal variable. - /// Payload is a symbol index. - lea_tlv: u32, /// The value stored at an offset from a frame index /// Payload is a frame address. load_frame: bits.FrameAddr, @@ -238,7 +232,6 @@ pub const MCValue = union(enum) { .lea_symbol, .lea_direct, .lea_got, - .lea_tlv, .lea_frame, .elementwise_regs_then_frame, .reserved_frame, @@ -252,7 +245,6 @@ pub const MCValue = union(enum) { .load_symbol, .load_got, .load_direct, - .load_tlv, .indirect, => true, .load_frame => |frame_addr| !frame_addr.index.isNamed(), @@ -355,7 +347,6 @@ pub const MCValue = union(enum) { .lea_symbol, .lea_direct, .lea_got, - .lea_tlv, .lea_frame, .elementwise_regs_then_frame, .reserved_frame, @@ -368,7 +359,6 @@ pub const MCValue = union(enum) { }, .load_direct => |sym_index| .{ .lea_direct = sym_index }, .load_got => |sym_index| .{ .lea_got = sym_index }, - .load_tlv => |sym_index| .{ .lea_tlv = sym_index }, .load_frame => |frame_addr| .{ .lea_frame = frame_addr }, .load_symbol => |sym_off| .{ .lea_symbol = sym_off }, }; @@ -390,7 +380,6 @@ pub const MCValue = union(enum) { .indirect, .load_direct, .load_got, - .load_tlv, .load_frame, .load_symbol, .elementwise_regs_then_frame, @@ -402,7 +391,6 @@ pub const MCValue = union(enum) { .register_offset => |reg_off| .{ .indirect = reg_off }, .lea_direct => |sym_index| .{ .load_direct = sym_index }, .lea_got => |sym_index| .{ .load_got = sym_index }, - .lea_tlv => |sym_index| .{ .load_tlv = sym_index }, .lea_frame => |frame_addr| .{ .load_frame = frame_addr }, .lea_symbol => |sym_index| .{ .load_symbol = sym_index }, }; @@ -430,8 +418,6 @@ pub const MCValue = union(enum) { .lea_direct, .load_got, .lea_got, - .load_tlv, - .lea_tlv, .load_frame, .load_symbol, .lea_symbol, @@ -469,8 +455,6 @@ pub const MCValue = union(enum) { .lea_direct, .load_got, .lea_got, - .load_tlv, - .lea_tlv, .lea_frame, .elementwise_regs_then_frame, .reserved_frame, @@ -555,8 +539,6 @@ pub const MCValue = union(enum) { .lea_direct => |pl| try writer.print("direct:{d}", .{pl}), .load_got => |pl| try writer.print("[got:{d}]", .{pl}), .lea_got => |pl| try writer.print("got:{d}", .{pl}), - .load_tlv => |pl| try writer.print("[tlv:{d}]", .{pl}), - .lea_tlv => |pl| try writer.print("tlv:{d}", .{pl}), .load_frame => |pl| try writer.print("[{} + 0x{x}]", .{ pl.index, pl.off }), .elementwise_regs_then_frame => |pl| try writer.print("elementwise:{d}:[{} + 0x{x}]", .{ pl.regs, pl.frame_index, pl.frame_off, @@ -585,8 +567,6 @@ const InstTracking = struct { .lea_direct, .load_got, .lea_got, - .load_tlv, - .lea_tlv, .load_frame, .lea_frame, .load_symbol, @@ -688,8 +668,6 @@ const InstTracking = struct { .lea_direct, .load_got, .lea_got, - .load_tlv, - .lea_tlv, .lea_frame, .load_symbol, .lea_symbol, @@ -120945,6 +120923,47 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { }; for (ops) |op| try op.die(cg); }, + .tlv_dllimport_ptr => switch (cg.bin_file.tag) { + .elf, .macho => { + const ty_nav = air_datas[@intFromEnum(inst)].ty_nav; + + const nav = ip.getNav(ty_nav.nav); + const tlv_sym_index = sym: { + if (cg.bin_file.cast(.elf)) |elf_file| { + const zo = elf_file.zigObjectPtr().?; + if (nav.getExtern(ip)) |e| { + const sym = try elf_file.getGlobalSymbol(nav.name.toSlice(ip), e.lib_name.toSlice(ip)); + zo.symbol(sym).flags.is_extern_ptr = true; + break :sym sym; + } + break :sym try zo.getOrCreateMetadataForNav(zcu, ty_nav.nav); + } + if (cg.bin_file.cast(.macho)) |macho_file| { + const zo = macho_file.getZigObject().?; + if (nav.getExtern(ip)) |e| { + const sym = try macho_file.getGlobalSymbol(nav.name.toSlice(ip), e.lib_name.toSlice(ip)); + zo.symbols.items[sym].flags.is_extern_ptr = true; + break :sym sym; + } + break :sym try zo.getOrCreateMetadataForNav(macho_file, ty_nav.nav); + } + unreachable; + }; + + if (cg.mod.pic) { + try cg.spillRegisters(&.{ .rdi, .rax }); + } else { + try cg.spillRegisters(&.{.rax}); + } + + var slot = try cg.tempInit(.usize, .{ .lea_symbol = .{ + .sym_index = tlv_sym_index, + } }); + while (try slot.toRegClass(true, .general_purpose, cg)) {} + try slot.finish(inst, &.{}, &.{}, cg); + }, + else => return cg.fail("TODO implement tlv/dllimport on {}", .{cg.bin_file.tag}), + }, .c_va_arg => try cg.airVaArg(inst), .c_va_copy => try cg.airVaCopy(inst), .c_va_end => try cg.airVaEnd(inst), @@ -124664,7 +124683,7 @@ fn airArrayElemVal(self: *CodeGen, inst: Air.Inst.Index) !void { }.to64(), ), }, - .memory, .load_symbol, .load_direct, .load_got, .load_tlv => switch (index_mcv) { + .memory, .load_symbol, .load_direct, .load_got => switch (index_mcv) { .immediate => |index_imm| try self.asmMemoryImmediate( .{ ._, .bt }, .{ @@ -124729,9 +124748,8 @@ fn airArrayElemVal(self: *CodeGen, inst: Air.Inst.Index) !void { .load_symbol, .load_direct, .load_got, - .load_tlv, => try self.genSetReg(addr_reg, .usize, array_mcv.address(), .{}), - .lea_symbol, .lea_direct, .lea_tlv => unreachable, + .lea_symbol, .lea_direct => unreachable, else => return self.fail("TODO airArrayElemVal_val for {s} of {}", .{ @tagName(array_mcv), array_ty.fmt(pt), }), @@ -126611,7 +126629,6 @@ fn load(self: *CodeGen, dst_mcv: MCValue, ptr_ty: Type, ptr_mcv: MCValue) InnerE .lea_symbol, .lea_direct, .lea_got, - .lea_tlv, .lea_frame, => try self.genCopy(dst_ty, dst_mcv, ptr_mcv.deref(), .{}), .memory, @@ -126619,7 +126636,6 @@ fn load(self: *CodeGen, dst_mcv: MCValue, ptr_ty: Type, ptr_mcv: MCValue) InnerE .load_symbol, .load_direct, .load_got, - .load_tlv, .load_frame, => { const addr_reg = try self.copyToTmpRegister(ptr_ty, ptr_mcv); @@ -126831,7 +126847,6 @@ fn store( .lea_symbol, .lea_direct, .lea_got, - .lea_tlv, .lea_frame, => try self.genCopy(src_ty, ptr_mcv.deref(), src_mcv, opts), .memory, @@ -126839,7 +126854,6 @@ fn store( .load_symbol, .load_direct, .load_got, - .load_tlv, .load_frame, => { 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: .lea_symbol, .lea_direct, .lea_got, - .lea_tlv, .lea_frame, .elementwise_regs_then_frame, .reserved_frame, @@ -127317,7 +127330,7 @@ fn genUnOpMir(self: *CodeGen, mir_tag: Mir.Inst.FixedTag, dst_ty: Type, dst_mcv: => unreachable, // unmodifiable destination .register => |dst_reg| try self.asmRegister(mir_tag, registerAlias(dst_reg, abi_size)), .register_pair, .register_triple, .register_quadruple => unreachable, // unimplemented - .memory, .load_symbol, .load_got, .load_direct, .load_tlv => { + .memory, .load_symbol, .load_got, .load_direct => { const addr_reg = try self.register_manager.allocReg(null, abi.RegisterClass.gp); const addr_reg_lock = self.register_manager.lockRegAssumeUnused(addr_reg); defer self.register_manager.unlockReg(addr_reg_lock); @@ -128922,8 +128935,6 @@ fn genBinOp( .lea_direct, .load_got, .lea_got, - .load_tlv, - .lea_tlv, .lea_frame, => true, .memory => |addr| std.math.cast(i32, @as(i64, @bitCast(addr))) == null, @@ -128983,8 +128994,6 @@ fn genBinOp( .lea_direct, .load_got, .lea_got, - .load_tlv, - .lea_tlv, .lea_frame, .elementwise_regs_then_frame, .reserved_frame, @@ -130167,7 +130176,6 @@ fn genBinOpMir( .register_mask, .lea_direct, .lea_got, - .lea_tlv, .lea_frame, .lea_symbol, .elementwise_regs_then_frame, @@ -130265,8 +130273,6 @@ fn genBinOpMir( .lea_direct, .load_got, .lea_got, - .load_tlv, - .lea_tlv, .load_frame, .lea_frame, => { @@ -130304,7 +130310,6 @@ fn genBinOpMir( .lea_symbol, .lea_direct, .lea_got, - .lea_tlv, .lea_frame, => { assert(off == 0); @@ -130320,7 +130325,6 @@ fn genBinOpMir( .load_symbol, .load_direct, .load_got, - .load_tlv, => { const ptr_ty = try pt.singleConstPtrType(ty); const addr_reg = try self.copyToTmpRegister(ptr_ty, src_mcv.address()); @@ -130340,13 +130344,13 @@ fn genBinOpMir( } } }, - .memory, .indirect, .load_symbol, .load_got, .load_direct, .load_tlv, .load_frame => { + .memory, .indirect, .load_symbol, .load_got, .load_direct, .load_frame => { const OpInfo = ?struct { addr_reg: Register, addr_lock: RegisterLock }; const limb_abi_size: u32 = @min(abi_size, 8); const dst_info: OpInfo = switch (dst_mcv) { else => unreachable, - .memory, .load_symbol, .load_got, .load_direct, .load_tlv => dst: { + .memory, .load_symbol, .load_got, .load_direct => dst: { const dst_addr_reg = (try self.register_manager.allocReg(null, abi.RegisterClass.gp)).to64(); const dst_addr_lock = self.register_manager.lockRegAssumeUnused(dst_addr_reg); @@ -130384,17 +130388,16 @@ fn genBinOpMir( .indirect, .lea_direct, .lea_got, - .lea_tlv, .load_frame, .lea_frame, .lea_symbol, => null, - .memory, .load_symbol, .load_got, .load_direct, .load_tlv => src: { + .memory, .load_symbol, .load_got, .load_direct => src: { switch (resolved_src_mcv) { .memory => |addr| if (std.math.cast(i32, @as(i64, @bitCast(addr))) != null and std.math.cast(i32, @as(i64, @bitCast(addr)) + abi_size - limb_abi_size) != null) break :src null, - .load_symbol, .load_got, .load_direct, .load_tlv => {}, + .load_symbol, .load_got, .load_direct => {}, else => unreachable, } @@ -130437,7 +130440,6 @@ fn genBinOpMir( .load_symbol, .load_got, .load_direct, - .load_tlv, => .{ .base = .{ .reg = dst_info.?.addr_reg }, .mod = .{ .rm = .{ @@ -130533,8 +130535,6 @@ fn genBinOpMir( .lea_direct, .load_got, .lea_got, - .load_tlv, - .lea_tlv, .load_frame, .lea_frame, => { @@ -130549,7 +130549,6 @@ fn genBinOpMir( .lea_symbol, .lea_direct, .lea_got, - .lea_tlv, .lea_frame, => switch (limb_i) { 0 => resolved_src_mcv, @@ -130601,7 +130600,6 @@ fn genIntMulComplexOpMir(self: *CodeGen, dst_ty: Type, dst_mcv: MCValue, src_mcv .lea_symbol, .lea_direct, .lea_got, - .lea_tlv, .lea_frame, .elementwise_regs_then_frame, .reserved_frame, @@ -130666,8 +130664,6 @@ fn genIntMulComplexOpMir(self: *CodeGen, dst_ty: Type, dst_mcv: MCValue, src_mcv .lea_direct, .load_got, .lea_got, - .load_tlv, - .lea_tlv, .lea_frame, => { 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 } }, .register_pair, .register_triple, .register_quadruple => unreachable, // unimplemented - .memory, .indirect, .load_symbol, .load_direct, .load_got, .load_tlv, .load_frame => { + .memory, .indirect, .load_symbol, .load_direct, .load_got, .load_frame => { const tmp_reg = try self.copyToTmpRegister(dst_ty, dst_mcv); const tmp_mcv = MCValue{ .register = tmp_reg }; const tmp_lock = self.register_manager.lockRegAssumeUnused(tmp_reg); @@ -130899,7 +130895,7 @@ fn genLocalDebugInfo( .disp = sym_off.off, } }, }), - .lea_direct, .lea_got, .lea_tlv => |sym_index| try self.asmAirMemory(.dbg_local, inst, .{ + .lea_direct, .lea_got => |sym_index| try self.asmAirMemory(.dbg_local, inst, .{ .base = .{ .reloc = sym_index }, .mod = .{ .rm = .{ .size = .qword } }, }), @@ -131548,7 +131544,6 @@ fn airCmp(self: *CodeGen, inst: Air.Inst.Index, op: std.math.CompareOperator) !v .indirect, .lea_direct, .lea_got, - .lea_tlv, .lea_frame, .lea_symbol, .elementwise_regs_then_frame, @@ -131556,7 +131551,7 @@ fn airCmp(self: *CodeGen, inst: Air.Inst.Index, op: std.math.CompareOperator) !v .air_ref, => unreachable, .register, .register_pair, .register_triple, .register_quadruple, .load_frame => null, - .memory, .load_symbol, .load_got, .load_direct, .load_tlv => dst: { + .memory, .load_symbol, .load_got, .load_direct => dst: { switch (resolved_dst_mcv) { .memory => |addr| if (std.math.cast( i32, @@ -131565,7 +131560,7 @@ fn airCmp(self: *CodeGen, inst: Air.Inst.Index, op: std.math.CompareOperator) !v i32, @as(i64, @bitCast(addr)) + abi_size - 8, ) != null) break :dst null, - .load_symbol, .load_got, .load_direct, .load_tlv => {}, + .load_symbol, .load_got, .load_direct => {}, else => unreachable, } @@ -131605,14 +131600,13 @@ fn airCmp(self: *CodeGen, inst: Air.Inst.Index, op: std.math.CompareOperator) !v .lea_symbol, .lea_direct, .lea_got, - .lea_tlv, .lea_frame, .elementwise_regs_then_frame, .reserved_frame, .air_ref, => unreachable, .register_pair, .register_triple, .register_quadruple, .load_frame => null, - .memory, .load_symbol, .load_got, .load_direct, .load_tlv => src: { + .memory, .load_symbol, .load_got, .load_direct => src: { switch (resolved_src_mcv) { .memory => |addr| if (std.math.cast( i32, @@ -131621,7 +131615,7 @@ fn airCmp(self: *CodeGen, inst: Air.Inst.Index, op: std.math.CompareOperator) !v i32, @as(i64, @bitCast(addr)) + abi_size - 8, ) != null) break :src null, - .load_symbol, .load_got, .load_direct, .load_tlv => {}, + .load_symbol, .load_got, .load_direct => {}, else => unreachable, } @@ -132011,7 +132005,6 @@ fn isNull(self: *CodeGen, inst: Air.Inst.Index, opt_ty: Type, opt_mcv: MCValue) .register_mask, .lea_direct, .lea_got, - .lea_tlv, .lea_symbol, .elementwise_regs_then_frame, .reserved_frame, @@ -132063,7 +132056,6 @@ fn isNull(self: *CodeGen, inst: Air.Inst.Index, opt_ty: Type, opt_mcv: MCValue) .load_symbol, .load_got, .load_direct, - .load_tlv, => { const addr_reg = (try self.register_manager.allocReg(null, abi.RegisterClass.gp)).to64(); const addr_reg_lock = self.register_manager.lockRegAssumeUnused(addr_reg); @@ -133105,7 +133097,7 @@ fn airAsm(self: *CodeGen, inst: Air.Inst.Index) !void { .memory => |addr| if (std.math.cast(i32, @as(i64, @bitCast(addr)))) |_| break :arg input_mcv, .indirect, .load_frame => break :arg input_mcv, - .load_symbol, .load_direct, .load_got, .load_tlv => {}, + .load_symbol, .load_direct, .load_got => {}, else => { const temp_mcv = try self.allocTempRegOrMem(ty, false); 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 .register_mask, .lea_direct, .lea_got, - .lea_tlv, .lea_frame, .lea_symbol, .elementwise_regs_then_frame, @@ -134159,7 +134150,7 @@ fn genCopy(self: *CodeGen, ty: Type, dst_mcv: MCValue, src_mcv: MCValue, opts: C } return; }, - .load_symbol, .load_direct, .load_got, .load_tlv => { + .load_symbol, .load_direct, .load_got => { const src_addr_reg = (try self.register_manager.allocReg(null, abi.RegisterClass.gp)).to64(); 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 .undef => if (opts.safety and part_i > 0) .{ .register = dst_regs[0] } else .undef, dst_tag => |src_regs| .{ .register = src_regs[part_i] }, .memory, .indirect, .load_frame => src_mcv.address().offset(part_disp).deref(), - .load_symbol, .load_direct, .load_got, .load_tlv => .{ .indirect = .{ + .load_symbol, .load_direct, .load_got => .{ .indirect = .{ .reg = src_info.?.addr_reg, .off = part_disp, } }, @@ -134213,11 +134204,11 @@ fn genCopy(self: *CodeGen, ty: Type, dst_mcv: MCValue, src_mcv: MCValue, opts: C src_mcv, opts, ), - .memory, .load_symbol, .load_direct, .load_got, .load_tlv => { + .memory, .load_symbol, .load_direct, .load_got => { switch (dst_mcv) { .memory => |addr| if (std.math.cast(i32, @as(i64, @bitCast(addr)))) |small_addr| return self.genSetMem(.{ .reg = .ds }, small_addr, ty, src_mcv, opts), - .load_symbol, .load_direct, .load_got, .load_tlv => {}, + .load_symbol, .load_direct, .load_got => {}, else => unreachable, } @@ -134639,7 +134630,7 @@ fn genSetReg( if (src_reg_mask.info.inverted) try self.asmRegister(.{ ._, .not }, registerAlias(bits_reg, abi_size)); try self.genSetReg(dst_reg, ty, .{ .register = bits_reg }, .{}); }, - .memory, .load_symbol, .load_direct, .load_got, .load_tlv => { + .memory, .load_symbol, .load_direct, .load_got => { switch (src_mcv) { .memory => |addr| if (std.math.cast(i32, @as(i64, @bitCast(addr)))) |small_addr| return (try self.moveStrategy( @@ -134683,7 +134674,7 @@ fn genSetReg( .segment, .mmx, .ip, .cr, .dr => unreachable, .x87, .sse => {}, }, - .load_got, .load_tlv => {}, + .load_got => {}, else => unreachable, } @@ -134734,7 +134725,6 @@ fn genSetReg( .payload = try self.addExtra(bits.SymbolOffset{ .sym_index = sym_index }), } }, }), - .lea_tlv => unreachable, // TODO: remove this .air_ref => |src_ref| try self.genSetReg(dst_reg, ty, try self.resolveInst(src_ref), opts), } } @@ -134952,8 +134942,6 @@ fn genSetMem( .lea_direct, .load_got, .lea_got, - .load_tlv, - .lea_tlv, .load_frame, .lea_frame, .load_symbol, @@ -138121,11 +138109,7 @@ fn airAggregateInit(self: *CodeGen, inst: Air.Inst.Index) !void { const elem_byte_off: i32 = @intCast(elem_off / elem_abi_bits * elem_abi_size); const elem_bit_off = elem_off % elem_abi_bits; const elem_mcv = try self.resolveInst(elem); - const mat_elem_mcv = switch (elem_mcv) { - .load_tlv => |sym_index| MCValue{ .lea_tlv = sym_index }, - else => elem_mcv, - }; - const elem_lock = switch (mat_elem_mcv) { + const elem_lock = switch (elem_mcv) { .register => |reg| self.register_manager.lockReg(reg), .immediate => |imm| lock: { if (imm == 0) continue; @@ -138137,7 +138121,7 @@ fn airAggregateInit(self: *CodeGen, inst: Air.Inst.Index) !void { const elem_extra_bits = self.regExtraBits(elem_ty); { - const temp_reg = try self.copyToTmpRegister(elem_ty, mat_elem_mcv); + const temp_reg = try self.copyToTmpRegister(elem_ty, elem_mcv); const temp_alias = registerAlias(temp_reg, elem_abi_size); const temp_lock = self.register_manager.lockRegAssumeUnused(temp_reg); defer self.register_manager.unlockReg(temp_lock); @@ -138160,7 +138144,7 @@ fn airAggregateInit(self: *CodeGen, inst: Air.Inst.Index) !void { ); } if (elem_bit_off > elem_extra_bits) { - const temp_reg = try self.copyToTmpRegister(elem_ty, mat_elem_mcv); + const temp_reg = try self.copyToTmpRegister(elem_ty, elem_mcv); const temp_alias = registerAlias(temp_reg, elem_abi_size); const temp_lock = self.register_manager.lockRegAssumeUnused(temp_reg); defer self.register_manager.unlockReg(temp_lock); @@ -138192,11 +138176,7 @@ fn airAggregateInit(self: *CodeGen, inst: Air.Inst.Index) !void { const elem_ty = result_ty.fieldType(elem_i, zcu); const elem_off: i32 = @intCast(result_ty.structFieldOffset(elem_i, zcu)); const elem_mcv = try self.resolveInst(elem); - const mat_elem_mcv = switch (elem_mcv) { - .load_tlv => |sym_index| MCValue{ .lea_tlv = sym_index }, - else => elem_mcv, - }; - try self.genSetMem(.{ .frame = frame_index }, elem_off, elem_ty, mat_elem_mcv, .{}); + try self.genSetMem(.{ .frame = frame_index }, elem_off, elem_ty, elem_mcv, .{}); } break :result .{ .load_frame = .{ .index = frame_index } }; }, @@ -138239,16 +138219,12 @@ fn airAggregateInit(self: *CodeGen, inst: Air.Inst.Index) !void { for (elements, 0..) |elem, elem_i| { const elem_mcv = try self.resolveInst(elem); - const mat_elem_mcv = switch (elem_mcv) { - .load_tlv => |sym_index| MCValue{ .lea_tlv = sym_index }, - else => elem_mcv, - }; const elem_off: i32 = @intCast(elem_size * elem_i); try self.genSetMem( .{ .frame = frame_index }, elem_off, elem_ty, - mat_elem_mcv, + elem_mcv, .{}, ); } @@ -138744,32 +138720,7 @@ fn resolveInst(self: *CodeGen, ref: Air.Inst.Ref) InnerError!MCValue { const mcv: MCValue = if (ref.toIndex()) |inst| mcv: { break :mcv self.inst_tracking.getPtr(inst).?.short; } else mcv: { - const const_mcv = try self.genTypedValue(.fromInterned(ref.toInterned().?)); - switch (const_mcv) { - .lea_tlv => |tlv_sym| switch (self.bin_file.tag) { - .elf, .macho => { - if (self.mod.pic) { - try self.spillRegisters(&.{ .rdi, .rax }); - } else { - try self.spillRegisters(&.{.rax}); - } - const frame_index = try self.allocFrameIndex(.init(.{ - .size = 8, - .alignment = .@"8", - })); - try self.genSetMem( - .{ .frame = frame_index }, - 0, - .usize, - .{ .lea_symbol = .{ .sym_index = tlv_sym } }, - .{}, - ); - break :mcv .{ .load_frame = .{ .index = frame_index } }; - }, - else => break :mcv const_mcv, - }, - else => break :mcv const_mcv, - } + break :mcv try self.genTypedValue(.fromInterned(ref.toInterned().?)); }; switch (mcv) { @@ -138819,7 +138770,6 @@ fn genResult(self: *CodeGen, res: codegen.GenResult) InnerError!MCValue { .load_direct => |sym_index| .{ .load_direct = sym_index }, .lea_direct => |sym_index| .{ .lea_direct = sym_index }, .load_got => |sym_index| .{ .lea_got = sym_index }, - .load_tlv => |sym_index| .{ .lea_tlv = sym_index }, }, .fail => |msg| return self.failMsg(msg), }; @@ -139686,8 +139636,6 @@ const Temp = struct { .lea_direct, .load_got, .lea_got, - .load_tlv, - .lea_tlv, .lea_frame, .elementwise_regs_then_frame, .reserved_frame, @@ -140133,7 +140081,6 @@ const Temp = struct { .register_offset, .lea_direct, .lea_got, - .lea_tlv, .lea_frame, => return false, .memory, @@ -140141,7 +140088,6 @@ const Temp = struct { .load_symbol, .load_direct, .load_got, - .load_tlv, .load_frame, => return temp.toRegClass(true, .general_purpose, cg), .lea_symbol => |sym_off| { @@ -145048,34 +144994,7 @@ fn tempFromOperand(cg: *CodeGen, op_ref: Air.Inst.Ref, op_dies: bool) InnerError if (op_ref.toIndex()) |op_inst| return .{ .index = op_inst }; const val = op_ref.toInterned().?; - return cg.tempInit(.fromInterned(ip.typeOf(val)), init: { - const const_mcv = try cg.genTypedValue(.fromInterned(val)); - switch (const_mcv) { - .lea_tlv => |tlv_sym| switch (cg.bin_file.tag) { - .elf, .macho => { - if (cg.mod.pic) { - try cg.spillRegisters(&.{ .rdi, .rax }); - } else { - try cg.spillRegisters(&.{.rax}); - } - const frame_index = try cg.allocFrameIndex(.init(.{ - .size = 8, - .alignment = .@"8", - })); - try cg.genSetMem( - .{ .frame = frame_index }, - 0, - .usize, - .{ .lea_symbol = .{ .sym_index = tlv_sym } }, - .{}, - ); - break :init .{ .load_frame = .{ .index = frame_index } }; - }, - else => break :init const_mcv, - }, - else => break :init const_mcv, - } - }); + return cg.tempInit(.fromInterned(ip.typeOf(val)), try cg.genTypedValue(.fromInterned(val))); } fn tempsFromOperandsInner( diff --git a/src/codegen.zig b/src/codegen.zig index c3be335acc..6577667c7c 100644 --- a/src/codegen.zig +++ b/src/codegen.zig @@ -818,10 +818,6 @@ pub const GenResult = union(enum) { /// The bit-width of the immediate may be smaller than `u64`. For example, on 32-bit targets /// such as ARM, the immediate will never exceed 32-bits. immediate: u64, - /// Threadlocal variable with address deferred until the linker allocates - /// everything in virtual memory. - /// Payload is a symbol index. - load_tlv: u32, /// Decl with address deferred until the linker allocates everything in virtual memory. /// Payload is a symbol index. load_direct: u32, @@ -883,13 +879,13 @@ fn genNavRef( } const nav = ip.getNav(nav_index); + assert(!nav.isThreadlocal(ip)); - const is_extern, const lib_name, const is_threadlocal = if (nav.getExtern(ip)) |e| - .{ true, e.lib_name, e.is_threadlocal } + const is_extern, const lib_name = if (nav.getExtern(ip)) |e| + .{ true, e.lib_name } else - .{ false, .none, nav.isThreadlocal(ip) }; + .{ false, .none }; - const single_threaded = zcu.navFileScope(nav_index).mod.?.single_threaded; const name = nav.name; if (lf.cast(.elf)) |elf_file| { const zo = elf_file.zigObjectPtr().?; @@ -899,9 +895,6 @@ fn genNavRef( return .{ .mcv = .{ .lea_symbol = sym_index } }; } const sym_index = try zo.getOrCreateMetadataForNav(zcu, nav_index); - if (!single_threaded and is_threadlocal) { - return .{ .mcv = .{ .load_tlv = sym_index } }; - } return .{ .mcv = .{ .lea_symbol = sym_index } }; } else if (lf.cast(.macho)) |macho_file| { const zo = macho_file.getZigObject().?; @@ -912,9 +905,6 @@ fn genNavRef( } const sym_index = try zo.getOrCreateMetadataForNav(macho_file, nav_index); const sym = zo.symbols.items[sym_index]; - if (!single_threaded and is_threadlocal) { - return .{ .mcv = .{ .load_tlv = sym.nlist_idx } }; - } return .{ .mcv = .{ .lea_symbol = sym.nlist_idx } }; } else if (lf.cast(.coff)) |coff_file| { if (is_extern) { diff --git a/src/codegen/c.zig b/src/codegen/c.zig index 891b84457e..075d9ba303 100644 --- a/src/codegen/c.zig +++ b/src/codegen/c.zig @@ -3453,6 +3453,8 @@ fn genBodyInner(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail, .error_set_has_value => return f.fail("TODO: C backend: implement error_set_has_value", .{}), .vector_store_elem => return f.fail("TODO: C backend: implement vector_store_elem", .{}), + .tlv_dllimport_ptr => try airTlvDllimportPtr(f, inst), + .c_va_start => try airCVaStart(f, inst), .c_va_arg => try airCVaArg(f, inst), .c_va_end => try airCVaEnd(f, inst), @@ -7617,6 +7619,17 @@ fn airMulAdd(f: *Function, inst: Air.Inst.Index) !CValue { return local; } +fn airTlvDllimportPtr(f: *Function, inst: Air.Inst.Index) !CValue { + const ty_nav = f.air.instructions.items(.data)[@intFromEnum(inst)].ty_nav; + const writer = f.object.writer(); + const local = try f.allocLocal(inst, .fromInterned(ty_nav.ty)); + try f.writeCValue(writer, local, .Other); + try writer.writeAll(" = "); + try f.object.dg.renderNav(writer, ty_nav.nav, .Other); + try writer.writeAll(";\n"); + return local; +} + fn airCVaStart(f: *Function, inst: Air.Inst.Index) !CValue { const pt = f.object.dg.pt; const zcu = pt.zcu; diff --git a/src/codegen/llvm.zig b/src/codegen/llvm.zig index e6926e8468..dc1a8edf56 100644 --- a/src/codegen/llvm.zig +++ b/src/codegen/llvm.zig @@ -5015,6 +5015,8 @@ pub const FuncGen = struct { .vector_store_elem => try self.airVectorStoreElem(inst), + .tlv_dllimport_ptr => try self.airTlvDllimportPtr(inst), + .inferred_alloc, .inferred_alloc_comptime => unreachable, .dbg_stmt => try self.airDbgStmt(inst), @@ -8112,6 +8114,13 @@ pub const FuncGen = struct { return .none; } + fn airTlvDllimportPtr(fg: *FuncGen, inst: Air.Inst.Index) !Builder.Value { + const o = fg.ng.object; + const ty_nav = fg.air.instructions.items(.data)[@intFromEnum(inst)].ty_nav; + const llvm_ptr_const = try o.lowerNavRefValue(ty_nav.nav); + return llvm_ptr_const.toValue(); + } + fn airMin(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value { const o = self.ng.object; const zcu = o.pt.zcu; diff --git a/src/print_air.zig b/src/print_air.zig index 3a5963f7c4..3436d915aa 100644 --- a/src/print_air.zig +++ b/src/print_air.zig @@ -320,6 +320,7 @@ const Writer = struct { .reduce, .reduce_optimized => try w.writeReduce(s, inst), .cmp_vector, .cmp_vector_optimized => try w.writeCmpVector(s, inst), .vector_store_elem => try w.writeVectorStoreElem(s, inst), + .tlv_dllimport_ptr => try w.writeTlvDllimportPtr(s, inst), .work_item_id, .work_group_size, @@ -552,6 +553,13 @@ const Writer = struct { try w.writeOperand(s, inst, 2, extra.rhs); } + fn writeTlvDllimportPtr(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void { + const ip = &w.pt.zcu.intern_pool; + const ty_nav = w.air.instructions.items(.data)[@intFromEnum(inst)].ty_nav; + try w.writeType(s, .fromInterned(ty_nav.ty)); + try s.print(", '{}'", .{ip.getNav(ty_nav.nav).fqn.fmt(ip)}); + } + fn writeAtomicLoad(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void { const atomic_load = w.air.instructions.items(.data)[@intFromEnum(inst)].atomic_load; diff --git a/test/behavior/threadlocal.zig b/test/behavior/threadlocal.zig index 9c3904644b..2d87048653 100644 --- a/test/behavior/threadlocal.zig +++ b/test/behavior/threadlocal.zig @@ -7,6 +7,8 @@ test "thread local variable" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt == .coff) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_x86_64 and builtin.os.tag == .macos) { // Fails due to register hazards. @@ -26,6 +28,7 @@ test "pointer to thread local array" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt == .coff) return error.SkipZigTest; // TODO const s = "Hello world"; @memcpy(buffer[0..s.len], s); @@ -40,6 +43,7 @@ test "reference a global threadlocal variable" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt == .coff) return error.SkipZigTest; // TODO _ = nrfx_uart_rx(&g_uart0); } diff --git a/test/cases/compile_errors/address_of_threadlocal_not_comptime_known.zig b/test/cases/compile_errors/address_of_threadlocal_not_comptime_known.zig index 904a31cddb..309d055280 100644 --- a/test/cases/compile_errors/address_of_threadlocal_not_comptime_known.zig +++ b/test/cases/compile_errors/address_of_threadlocal_not_comptime_known.zig @@ -6,9 +6,6 @@ pub export fn entry() void { } // error -// backend=stage2 -// target=native // // :2:36: error: unable to resolve comptime value // :2:36: note: initializer of container-level variable must be comptime-known -// :2:36: note: threadlocal and dll imported variables have runtime-known addresses diff --git a/test/cases/compile_errors/builtin_extern_in_comptime_scope.zig b/test/cases/compile_errors/builtin_extern_in_comptime_scope.zig index 66951a03a0..cf19075fa2 100644 --- a/test/cases/compile_errors/builtin_extern_in_comptime_scope.zig +++ b/test/cases/compile_errors/builtin_extern_in_comptime_scope.zig @@ -7,12 +7,8 @@ pub export fn entry2() void { _ = foo_dll; } // error -// backend=stage2 -// target=native // // :1:16: error: unable to resolve comptime value // :1:16: note: initializer of container-level variable must be comptime-known -// :1:16: note: threadlocal and dll imported variables have runtime-known addresses // :2:17: error: unable to resolve comptime value // :2:17: note: initializer of container-level variable must be comptime-known -// :2:17: note: threadlocal and dll imported variables have runtime-known addresses