Commit 92c63126e8
Changed files (21)
lib
std
src
arch
aarch64
arm
riscv64
sparc64
wasm
x86_64
Liveness
test
behavior
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 => {
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,
=> {
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),
};
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 },
},
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 => {
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 },
},
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);
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(
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;
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;
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,
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,
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) {
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) {
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,
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;
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 },
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,
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);
}
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
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