authorgravatar for jacobly@ziglang.orgJacob Young <jacobly@ziglang.org> 2025-06-09 02:36:32-04:00
committergravatar for mlugg@mlugg.co.ukMatthew Lugg <mlugg@mlugg.co.uk> 2025-06-12 17:51:29+01:00
logd312dfc1f21a9194dd06c1d45f653bdaf823d2f6
tree8fb63f9b4c650c44ad3dadf41139cb585995c3c5
parent56119699bf5fbb44d844d4ad181d51629f754be8
signaturelock-open Commit is signed but in an unrecognized format.

codegen: make threadlocal logic consistent


5 files changed, 23 insertions(+), 66 deletions(-)

src/arch/x86_64/CodeGen.zig+2-1
......@@ -163354,7 +163354,8 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {
163354163354 },
163355163355 .runtime_nav_ptr => {
163356163356 const ty_nav = air_datas[@intFromEnum(inst)].ty_nav;
163357 const is_threadlocal = ip.getNav(ty_nav.nav).isThreadlocal(ip);
163357 const nav = ip.getNav(ty_nav.nav);
163358 const is_threadlocal = zcu.comp.config.any_non_single_threaded and nav.isThreadlocal(ip);
163358163359 if (is_threadlocal) if (cg.mod.pic) {
163359163360 try cg.spillRegisters(&.{ .rdi, .rax });
163360163361 } else {
src/arch/x86_64/Emit.zig+8-20
......@@ -21,7 +21,8 @@ pub const Error = Lower.Error || error{
2121} || link.File.UpdateDebugInfoError;
2222
2323pub fn emitMir(emit: *Emit) Error!void {
24 const gpa = emit.bin_file.comp.gpa;
24 const comp = emit.bin_file.comp;
25 const gpa = comp.gpa;
2526 try emit.code_offset_mapping.resize(gpa, emit.lower.mir.instructions.len);
2627 emit.relocs.clearRetainingCapacity();
2728 emit.table_relocs.clearRetainingCapacity();
......@@ -99,12 +100,10 @@ pub fn emitMir(emit: *Emit) Error!void {
99100 .inst => |inst| .{ .index = inst, .is_extern = false, .type = .inst },
100101 .table => .{ .index = undefined, .is_extern = false, .type = .table },
101102 .nav => |nav| {
102 const ip = &emit.pt.zcu.intern_pool;
103103 const sym_index = switch (try codegen.genNavRef(
104104 emit.bin_file,
105105 emit.pt,
106106 emit.lower.src_loc,
107 .fromInterned(ip.getNav(nav).typeOf(ip)),
108107 nav,
109108 emit.lower.target.*,
110109 )) {
......@@ -118,12 +117,13 @@ pub fn emitMir(emit: *Emit) Error!void {
118117 return error.EmitFail;
119118 },
120119 };
120 const ip = &emit.pt.zcu.intern_pool;
121121 break :target switch (ip.getNav(nav).status) {
122122 .unresolved => unreachable,
123123 .type_resolved => |type_resolved| .{
124124 .index = sym_index,
125125 .is_extern = false,
126 .type = if (type_resolved.is_threadlocal) .tlv else .symbol,
126 .type = if (type_resolved.is_threadlocal and comp.config.any_non_single_threaded) .tlv else .symbol,
127127 },
128128 .fully_resolved => |fully_resolved| switch (ip.indexToKey(fully_resolved.val)) {
129129 .@"extern" => |@"extern"| .{
......@@ -132,7 +132,7 @@ pub fn emitMir(emit: *Emit) Error!void {
132132 .default => true,
133133 .hidden, .protected => false,
134134 },
135 .type = if (@"extern".is_threadlocal) .tlv else .symbol,
135 .type = if (@"extern".is_threadlocal and comp.config.any_non_single_threaded) .tlv else .symbol,
136136 .force_pcrel_direct = switch (@"extern".relocation) {
137137 .any => false,
138138 .pcrel => true,
......@@ -141,7 +141,7 @@ pub fn emitMir(emit: *Emit) Error!void {
141141 .variable => |variable| .{
142142 .index = sym_index,
143143 .is_extern = false,
144 .type = if (variable.is_threadlocal) .tlv else .symbol,
144 .type = if (variable.is_threadlocal and comp.config.any_non_single_threaded) .tlv else .symbol,
145145 },
146146 else => .{ .index = sym_index, .is_extern = false, .type = .symbol },
147147 },
......@@ -292,12 +292,8 @@ pub fn emitMir(emit: *Emit) Error!void {
292292 .branch, .tls => unreachable,
293293 .tlv => {
294294 if (emit.bin_file.cast(.elf)) |elf_file| {
295 if (reloc.target.is_extern) {
296 // TODO handle extern TLS vars, i.e., emit GD model
297 return emit.fail("TODO implement extern {s} reloc for {s}", .{
298 @tagName(reloc.target.type), @tagName(emit.bin_file.tag),
299 });
300 } else if (emit.pic) switch (lowered_inst.encoding.mnemonic) {
295 // TODO handle extern TLS vars, i.e., emit GD model
296 if (emit.pic) switch (lowered_inst.encoding.mnemonic) {
301297 .lea, .mov => {
302298 // Here, we currently assume local dynamic TLS vars, and so
303299 // we emit LD model.
......@@ -507,7 +503,6 @@ pub fn emitMir(emit: *Emit) Error!void {
507503 } };
508504 },
509505 .pseudo_dbg_arg_m, .pseudo_dbg_var_m => {
510 const ip = &emit.pt.zcu.intern_pool;
511506 const mem = emit.lower.mir.resolveMemoryExtra(mir_inst.data.x.payload).decode();
512507 break :loc .{ .plus = .{
513508 base: {
......@@ -519,7 +514,6 @@ pub fn emitMir(emit: *Emit) Error!void {
519514 emit.bin_file,
520515 emit.pt,
521516 emit.lower.src_loc,
522 .fromInterned(ip.getNav(nav).typeOf(ip)),
523517 nav,
524518 emit.lower.target.*,
525519 ) catch |err| switch (err) {
......@@ -803,9 +797,6 @@ fn encodeInst(emit: *Emit, lowered_inst: Instruction, reloc_info: []const RelocI
803797 @tagName(reloc.target.type), @tagName(emit.bin_file.tag),
804798 }),
805799 .tls => if (emit.bin_file.cast(.elf)) |elf_file| {
806 if (reloc.target.is_extern) return emit.fail("TODO implement extern {s} reloc for {s}", .{
807 @tagName(reloc.target.type), @tagName(emit.bin_file.tag),
808 });
809800 const zo = elf_file.zigObjectPtr().?;
810801 const atom = zo.symbol(emit.atom_index).atom(elf_file).?;
811802 const r_type: std.elf.R_X86_64 = if (emit.pic) .TLSLD else unreachable;
......@@ -818,9 +809,6 @@ fn encodeInst(emit: *Emit, lowered_inst: Instruction, reloc_info: []const RelocI
818809 @tagName(reloc.target.type), @tagName(emit.bin_file.tag),
819810 }),
820811 .tlv => if (emit.bin_file.cast(.elf)) |elf_file| {
821 if (reloc.target.is_extern) return emit.fail("TODO implement extern {s} reloc for {s}", .{
822 @tagName(reloc.target.type), @tagName(emit.bin_file.tag),
823 });
824812 const zo = elf_file.zigObjectPtr().?;
825813 const atom = zo.symbol(emit.atom_index).atom(elf_file).?;
826814 const r_type: std.elf.R_X86_64 = if (emit.pic) .DTPOFF32 else .TPOFF32;
src/codegen.zig+9-39
......@@ -955,47 +955,18 @@ pub fn genNavRef(
955955 lf: *link.File,
956956 pt: Zcu.PerThread,
957957 src_loc: Zcu.LazySrcLoc,
958 ty: Type,
959958 nav_index: InternPool.Nav.Index,
960959 target: std.Target,
961960) CodeGenError!GenResult {
962961 const zcu = pt.zcu;
963962 const ip = &zcu.intern_pool;
964 log.debug("genNavRef: ty = {}", .{ty.fmt(pt)});
965
966 if (!ty.isFnOrHasRuntimeBitsIgnoreComptime(zcu)) {
967 const imm: u64 = switch (@divExact(target.ptrBitWidth(), 8)) {
968 1 => 0xaa,
969 2 => 0xaaaa,
970 4 => 0xaaaaaaaa,
971 8 => 0xaaaaaaaaaaaaaaaa,
972 else => unreachable,
973 };
974 return .{ .mcv = .{ .immediate = imm } };
975 }
976
977 const comp = lf.comp;
978 const gpa = comp.gpa;
979
980 // TODO this feels clunky. Perhaps we should check for it in `genTypedValue`?
981 if (ty.castPtrToFn(zcu)) |fn_ty| {
982 if (zcu.typeToFunc(fn_ty).?.is_generic) {
983 return .{ .mcv = .{ .immediate = fn_ty.abiAlignment(zcu).toByteUnits().? } };
984 }
985 } else if (ty.zigTypeTag(zcu) == .pointer) {
986 const elem_ty = ty.elemType2(zcu);
987 if (!elem_ty.hasRuntimeBits(zcu)) {
988 return .{ .mcv = .{ .immediate = elem_ty.abiAlignment(zcu).toByteUnits().? } };
989 }
990 }
991
992963 const nav = ip.getNav(nav_index);
964 log.debug("genNavRef({})", .{nav.fqn.fmt(ip)});
965
993966 const lib_name, const linkage, const is_threadlocal = if (nav.getExtern(ip)) |e|
994 .{ e.lib_name, e.linkage, e.is_threadlocal and !zcu.navFileScope(nav_index).mod.?.single_threaded }
967 .{ e.lib_name, e.linkage, e.is_threadlocal and zcu.comp.config.any_non_single_threaded }
995968 else
996969 .{ .none, .internal, false };
997
998 const name = nav.name;
999970 if (lf.cast(.elf)) |elf_file| {
1000971 const zo = elf_file.zigObjectPtr().?;
1001972 switch (linkage) {
......@@ -1005,7 +976,7 @@ pub fn genNavRef(
1005976 return .{ .mcv = .{ .lea_symbol = sym_index } };
1006977 },
1007978 .strong, .weak => {
1008 const sym_index = try elf_file.getGlobalSymbol(name.toSlice(ip), lib_name.toSlice(ip));
979 const sym_index = try elf_file.getGlobalSymbol(nav.name.toSlice(ip), lib_name.toSlice(ip));
1009980 switch (linkage) {
1010981 .internal => unreachable,
1011982 .strong => {},
......@@ -1026,7 +997,7 @@ pub fn genNavRef(
1026997 return .{ .mcv = .{ .lea_symbol = sym_index } };
1027998 },
1028999 .strong, .weak => {
1029 const sym_index = try macho_file.getGlobalSymbol(name.toSlice(ip), lib_name.toSlice(ip));
1000 const sym_index = try macho_file.getGlobalSymbol(nav.name.toSlice(ip), lib_name.toSlice(ip));
10301001 switch (linkage) {
10311002 .internal => unreachable,
10321003 .strong => {},
......@@ -1047,8 +1018,8 @@ pub fn genNavRef(
10471018 return .{ .mcv = .{ .load_got = sym_index } };
10481019 },
10491020 .strong, .weak => {
1050 const global_index = try coff_file.getGlobalSymbol(name.toSlice(ip), lib_name.toSlice(ip));
1051 try coff_file.need_got_table.put(gpa, global_index, {}); // needs GOT
1021 const global_index = try coff_file.getGlobalSymbol(nav.name.toSlice(ip), lib_name.toSlice(ip));
1022 try coff_file.need_got_table.put(zcu.gpa, global_index, {}); // needs GOT
10521023 return .{ .mcv = .{ .load_got = link.File.Coff.global_symbol_bit | global_index } };
10531024 },
10541025 .link_once => unreachable,
......@@ -1058,7 +1029,7 @@ pub fn genNavRef(
10581029 const atom = p9.getAtom(atom_index);
10591030 return .{ .mcv = .{ .memory = atom.getOffsetTableAddress(p9) } };
10601031 } else {
1061 const msg = try ErrorMsg.create(gpa, src_loc, "TODO genNavRef for target {}", .{target});
1032 const msg = try ErrorMsg.create(zcu.gpa, src_loc, "TODO genNavRef for target {}", .{target});
10621033 return .{ .fail = msg };
10631034 }
10641035}
......@@ -1071,12 +1042,11 @@ pub fn genTypedValue(
10711042 val: Value,
10721043 target: std.Target,
10731044) CodeGenError!GenResult {
1074 const ip = &pt.zcu.intern_pool;
10751045 return switch (try lowerValue(pt, val, &target)) {
10761046 .none => .{ .mcv = .none },
10771047 .undef => .{ .mcv = .undef },
10781048 .immediate => |imm| .{ .mcv = .{ .immediate = imm } },
1079 .lea_nav => |nav| genNavRef(lf, pt, src_loc, .fromInterned(ip.getNav(nav).typeOf(ip)), nav, target),
1049 .lea_nav => |nav| genNavRef(lf, pt, src_loc, nav, target),
10801050 .lea_uav => |uav| switch (try lf.lowerUav(
10811051 pt,
10821052 uav.val,
src/link/Elf/ZigObject.zig+2-3
......@@ -1142,7 +1142,6 @@ fn getNavShdrIndex(
11421142 const gpa = elf_file.base.comp.gpa;
11431143 const ptr_size = elf_file.ptrWidthBytes();
11441144 const ip = &zcu.intern_pool;
1145 const any_non_single_threaded = elf_file.base.comp.config.any_non_single_threaded;
11461145 const nav_val = zcu.navValue(nav_index);
11471146 if (ip.isFunctionType(nav_val.typeOf(zcu).toIntern())) {
11481147 if (self.text_index) |symbol_index|
......@@ -1162,7 +1161,7 @@ fn getNavShdrIndex(
11621161 else => .{ true, false, nav_val.toIntern() },
11631162 };
11641163 const has_relocs = self.symbol(sym_index).atom(elf_file).?.relocs(elf_file).len > 0;
1165 if (any_non_single_threaded and is_threadlocal) {
1164 if (is_threadlocal and elf_file.base.comp.config.any_non_single_threaded) {
11661165 const is_bss = !has_relocs and for (code) |byte| {
11671166 if (byte != 0) break false;
11681167 } else true;
......@@ -1542,7 +1541,7 @@ pub fn updateNav(
15421541 nav.name.toSlice(ip),
15431542 @"extern".lib_name.toSlice(ip),
15441543 );
1545 if (@"extern".is_threadlocal) self.symbol(sym_index).flags.is_tls = true;
1544 if (@"extern".is_threadlocal and elf_file.base.comp.config.any_non_single_threaded) self.symbol(sym_index).flags.is_tls = true;
15461545 if (self.dwarf) |*dwarf| dwarf: {
15471546 var debug_wip_nav = try dwarf.initWipNav(pt, nav_index, sym_index) orelse break :dwarf;
15481547 defer debug_wip_nav.deinit();
src/link/MachO/ZigObject.zig+2-3
......@@ -881,7 +881,7 @@ pub fn updateNav(
881881 const name = @"extern".name.toSlice(ip);
882882 const lib_name = @"extern".lib_name.toSlice(ip);
883883 const sym_index = try self.getGlobalSymbol(macho_file, name, lib_name);
884 if (@"extern".is_threadlocal) self.symbols.items[sym_index].flags.tlv = true;
884 if (@"extern".is_threadlocal and macho_file.base.comp.config.any_non_single_threaded) self.symbols.items[sym_index].flags.tlv = true;
885885 if (self.dwarf) |*dwarf| dwarf: {
886886 var debug_wip_nav = try dwarf.initWipNav(pt, nav_index, sym_index) orelse break :dwarf;
887887 defer debug_wip_nav.deinit();
......@@ -1154,7 +1154,6 @@ fn getNavOutputSection(
11541154) error{OutOfMemory}!u8 {
11551155 _ = self;
11561156 const ip = &zcu.intern_pool;
1157 const any_non_single_threaded = macho_file.base.comp.config.any_non_single_threaded;
11581157 const nav_val = zcu.navValue(nav_index);
11591158 if (ip.isFunctionType(nav_val.typeOf(zcu).toIntern())) return macho_file.zig_text_sect_index.?;
11601159 const is_const, const is_threadlocal, const nav_init = switch (ip.indexToKey(nav_val.toIntern())) {
......@@ -1162,7 +1161,7 @@ fn getNavOutputSection(
11621161 .@"extern" => |@"extern"| .{ @"extern".is_const, @"extern".is_threadlocal, .none },
11631162 else => .{ true, false, nav_val.toIntern() },
11641163 };
1165 if (any_non_single_threaded and is_threadlocal) {
1164 if (is_threadlocal and macho_file.base.comp.config.any_non_single_threaded) {
11661165 for (code) |byte| {
11671166 if (byte != 0) break;
11681167 } else return macho_file.getSectionByName("__DATA", "__thread_bss") orelse try macho_file.addSection(