Commit d312dfc1f2

Jacob Young <jacobly0@users.noreply.github.com>
2025-06-09 08:36:32
codegen: make threadlocal logic consistent
1 parent 5611969
Changed files (5)
src/arch/x86_64/CodeGen.zig
@@ -163354,7 +163354,8 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {
             },
             .runtime_nav_ptr => {
                 const ty_nav = air_datas[@intFromEnum(inst)].ty_nav;
-                const is_threadlocal = ip.getNav(ty_nav.nav).isThreadlocal(ip);
+                const nav = ip.getNav(ty_nav.nav);
+                const is_threadlocal = zcu.comp.config.any_non_single_threaded and nav.isThreadlocal(ip);
                 if (is_threadlocal) if (cg.mod.pic) {
                     try cg.spillRegisters(&.{ .rdi, .rax });
                 } else {
src/arch/x86_64/Emit.zig
@@ -21,7 +21,8 @@ pub const Error = Lower.Error || error{
 } || link.File.UpdateDebugInfoError;
 
 pub fn emitMir(emit: *Emit) Error!void {
-    const gpa = emit.bin_file.comp.gpa;
+    const comp = emit.bin_file.comp;
+    const gpa = comp.gpa;
     try emit.code_offset_mapping.resize(gpa, emit.lower.mir.instructions.len);
     emit.relocs.clearRetainingCapacity();
     emit.table_relocs.clearRetainingCapacity();
@@ -99,12 +100,10 @@ pub fn emitMir(emit: *Emit) Error!void {
                     .inst => |inst| .{ .index = inst, .is_extern = false, .type = .inst },
                     .table => .{ .index = undefined, .is_extern = false, .type = .table },
                     .nav => |nav| {
-                        const ip = &emit.pt.zcu.intern_pool;
                         const sym_index = switch (try codegen.genNavRef(
                             emit.bin_file,
                             emit.pt,
                             emit.lower.src_loc,
-                            .fromInterned(ip.getNav(nav).typeOf(ip)),
                             nav,
                             emit.lower.target.*,
                         )) {
@@ -118,12 +117,13 @@ pub fn emitMir(emit: *Emit) Error!void {
                                 return error.EmitFail;
                             },
                         };
+                        const ip = &emit.pt.zcu.intern_pool;
                         break :target switch (ip.getNav(nav).status) {
                             .unresolved => unreachable,
                             .type_resolved => |type_resolved| .{
                                 .index = sym_index,
                                 .is_extern = false,
-                                .type = if (type_resolved.is_threadlocal) .tlv else .symbol,
+                                .type = if (type_resolved.is_threadlocal and comp.config.any_non_single_threaded) .tlv else .symbol,
                             },
                             .fully_resolved => |fully_resolved| switch (ip.indexToKey(fully_resolved.val)) {
                                 .@"extern" => |@"extern"| .{
@@ -132,7 +132,7 @@ pub fn emitMir(emit: *Emit) Error!void {
                                         .default => true,
                                         .hidden, .protected => false,
                                     },
-                                    .type = if (@"extern".is_threadlocal) .tlv else .symbol,
+                                    .type = if (@"extern".is_threadlocal and comp.config.any_non_single_threaded) .tlv else .symbol,
                                     .force_pcrel_direct = switch (@"extern".relocation) {
                                         .any => false,
                                         .pcrel => true,
@@ -141,7 +141,7 @@ pub fn emitMir(emit: *Emit) Error!void {
                                 .variable => |variable| .{
                                     .index = sym_index,
                                     .is_extern = false,
-                                    .type = if (variable.is_threadlocal) .tlv else .symbol,
+                                    .type = if (variable.is_threadlocal and comp.config.any_non_single_threaded) .tlv else .symbol,
                                 },
                                 else => .{ .index = sym_index, .is_extern = false, .type = .symbol },
                             },
@@ -292,12 +292,8 @@ pub fn emitMir(emit: *Emit) Error!void {
                 .branch, .tls => unreachable,
                 .tlv => {
                     if (emit.bin_file.cast(.elf)) |elf_file| {
-                        if (reloc.target.is_extern) {
-                            // TODO handle extern TLS vars, i.e., emit GD model
-                            return emit.fail("TODO implement extern {s} reloc for {s}", .{
-                                @tagName(reloc.target.type), @tagName(emit.bin_file.tag),
-                            });
-                        } else if (emit.pic) switch (lowered_inst.encoding.mnemonic) {
+                        // TODO handle extern TLS vars, i.e., emit GD model
+                        if (emit.pic) switch (lowered_inst.encoding.mnemonic) {
                             .lea, .mov => {
                                 // Here, we currently assume local dynamic TLS vars, and so
                                 // we emit LD model.
@@ -507,7 +503,6 @@ pub fn emitMir(emit: *Emit) Error!void {
                                     } };
                                 },
                                 .pseudo_dbg_arg_m, .pseudo_dbg_var_m => {
-                                    const ip = &emit.pt.zcu.intern_pool;
                                     const mem = emit.lower.mir.resolveMemoryExtra(mir_inst.data.x.payload).decode();
                                     break :loc .{ .plus = .{
                                         base: {
@@ -519,7 +514,6 @@ pub fn emitMir(emit: *Emit) Error!void {
                                                     emit.bin_file,
                                                     emit.pt,
                                                     emit.lower.src_loc,
-                                                    .fromInterned(ip.getNav(nav).typeOf(ip)),
                                                     nav,
                                                     emit.lower.target.*,
                                                 ) catch |err| switch (err) {
@@ -803,9 +797,6 @@ fn encodeInst(emit: *Emit, lowered_inst: Instruction, reloc_info: []const RelocI
             @tagName(reloc.target.type), @tagName(emit.bin_file.tag),
         }),
         .tls => if (emit.bin_file.cast(.elf)) |elf_file| {
-            if (reloc.target.is_extern) return emit.fail("TODO implement extern {s} reloc for {s}", .{
-                @tagName(reloc.target.type), @tagName(emit.bin_file.tag),
-            });
             const zo = elf_file.zigObjectPtr().?;
             const atom = zo.symbol(emit.atom_index).atom(elf_file).?;
             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
             @tagName(reloc.target.type), @tagName(emit.bin_file.tag),
         }),
         .tlv => if (emit.bin_file.cast(.elf)) |elf_file| {
-            if (reloc.target.is_extern) return emit.fail("TODO implement extern {s} reloc for {s}", .{
-                @tagName(reloc.target.type), @tagName(emit.bin_file.tag),
-            });
             const zo = elf_file.zigObjectPtr().?;
             const atom = zo.symbol(emit.atom_index).atom(elf_file).?;
             const r_type: std.elf.R_X86_64 = if (emit.pic) .DTPOFF32 else .TPOFF32;
src/link/Elf/ZigObject.zig
@@ -1142,7 +1142,6 @@ fn getNavShdrIndex(
     const gpa = elf_file.base.comp.gpa;
     const ptr_size = elf_file.ptrWidthBytes();
     const ip = &zcu.intern_pool;
-    const any_non_single_threaded = elf_file.base.comp.config.any_non_single_threaded;
     const nav_val = zcu.navValue(nav_index);
     if (ip.isFunctionType(nav_val.typeOf(zcu).toIntern())) {
         if (self.text_index) |symbol_index|
@@ -1162,7 +1161,7 @@ fn getNavShdrIndex(
         else => .{ true, false, nav_val.toIntern() },
     };
     const has_relocs = self.symbol(sym_index).atom(elf_file).?.relocs(elf_file).len > 0;
-    if (any_non_single_threaded and is_threadlocal) {
+    if (is_threadlocal and elf_file.base.comp.config.any_non_single_threaded) {
         const is_bss = !has_relocs and for (code) |byte| {
             if (byte != 0) break false;
         } else true;
@@ -1542,7 +1541,7 @@ pub fn updateNav(
                 nav.name.toSlice(ip),
                 @"extern".lib_name.toSlice(ip),
             );
-            if (@"extern".is_threadlocal) self.symbol(sym_index).flags.is_tls = true;
+            if (@"extern".is_threadlocal and elf_file.base.comp.config.any_non_single_threaded) self.symbol(sym_index).flags.is_tls = true;
             if (self.dwarf) |*dwarf| dwarf: {
                 var debug_wip_nav = try dwarf.initWipNav(pt, nav_index, sym_index) orelse break :dwarf;
                 defer debug_wip_nav.deinit();
src/link/MachO/ZigObject.zig
@@ -881,7 +881,7 @@ pub fn updateNav(
             const name = @"extern".name.toSlice(ip);
             const lib_name = @"extern".lib_name.toSlice(ip);
             const sym_index = try self.getGlobalSymbol(macho_file, name, lib_name);
-            if (@"extern".is_threadlocal) self.symbols.items[sym_index].flags.tlv = true;
+            if (@"extern".is_threadlocal and macho_file.base.comp.config.any_non_single_threaded) self.symbols.items[sym_index].flags.tlv = true;
             if (self.dwarf) |*dwarf| dwarf: {
                 var debug_wip_nav = try dwarf.initWipNav(pt, nav_index, sym_index) orelse break :dwarf;
                 defer debug_wip_nav.deinit();
@@ -1154,7 +1154,6 @@ fn getNavOutputSection(
 ) error{OutOfMemory}!u8 {
     _ = self;
     const ip = &zcu.intern_pool;
-    const any_non_single_threaded = macho_file.base.comp.config.any_non_single_threaded;
     const nav_val = zcu.navValue(nav_index);
     if (ip.isFunctionType(nav_val.typeOf(zcu).toIntern())) return macho_file.zig_text_sect_index.?;
     const is_const, const is_threadlocal, const nav_init = switch (ip.indexToKey(nav_val.toIntern())) {
@@ -1162,7 +1161,7 @@ fn getNavOutputSection(
         .@"extern" => |@"extern"| .{ @"extern".is_const, @"extern".is_threadlocal, .none },
         else => .{ true, false, nav_val.toIntern() },
     };
-    if (any_non_single_threaded and is_threadlocal) {
+    if (is_threadlocal and macho_file.base.comp.config.any_non_single_threaded) {
         for (code) |byte| {
             if (byte != 0) break;
         } else return macho_file.getSectionByName("__DATA", "__thread_bss") orelse try macho_file.addSection(
src/codegen.zig
@@ -955,47 +955,18 @@ pub fn genNavRef(
     lf: *link.File,
     pt: Zcu.PerThread,
     src_loc: Zcu.LazySrcLoc,
-    ty: Type,
     nav_index: InternPool.Nav.Index,
     target: std.Target,
 ) CodeGenError!GenResult {
     const zcu = pt.zcu;
     const ip = &zcu.intern_pool;
-    log.debug("genNavRef: ty = {}", .{ty.fmt(pt)});
-
-    if (!ty.isFnOrHasRuntimeBitsIgnoreComptime(zcu)) {
-        const imm: u64 = switch (@divExact(target.ptrBitWidth(), 8)) {
-            1 => 0xaa,
-            2 => 0xaaaa,
-            4 => 0xaaaaaaaa,
-            8 => 0xaaaaaaaaaaaaaaaa,
-            else => unreachable,
-        };
-        return .{ .mcv = .{ .immediate = imm } };
-    }
-
-    const comp = lf.comp;
-    const gpa = comp.gpa;
-
-    // TODO this feels clunky. Perhaps we should check for it in `genTypedValue`?
-    if (ty.castPtrToFn(zcu)) |fn_ty| {
-        if (zcu.typeToFunc(fn_ty).?.is_generic) {
-            return .{ .mcv = .{ .immediate = fn_ty.abiAlignment(zcu).toByteUnits().? } };
-        }
-    } else if (ty.zigTypeTag(zcu) == .pointer) {
-        const elem_ty = ty.elemType2(zcu);
-        if (!elem_ty.hasRuntimeBits(zcu)) {
-            return .{ .mcv = .{ .immediate = elem_ty.abiAlignment(zcu).toByteUnits().? } };
-        }
-    }
-
     const nav = ip.getNav(nav_index);
+    log.debug("genNavRef({})", .{nav.fqn.fmt(ip)});
+
     const lib_name, const linkage, const is_threadlocal = if (nav.getExtern(ip)) |e|
-        .{ e.lib_name, e.linkage, e.is_threadlocal and !zcu.navFileScope(nav_index).mod.?.single_threaded }
+        .{ e.lib_name, e.linkage, e.is_threadlocal and zcu.comp.config.any_non_single_threaded }
     else
         .{ .none, .internal, false };
-
-    const name = nav.name;
     if (lf.cast(.elf)) |elf_file| {
         const zo = elf_file.zigObjectPtr().?;
         switch (linkage) {
@@ -1005,7 +976,7 @@ pub fn genNavRef(
                 return .{ .mcv = .{ .lea_symbol = sym_index } };
             },
             .strong, .weak => {
-                const sym_index = try elf_file.getGlobalSymbol(name.toSlice(ip), lib_name.toSlice(ip));
+                const sym_index = try elf_file.getGlobalSymbol(nav.name.toSlice(ip), lib_name.toSlice(ip));
                 switch (linkage) {
                     .internal => unreachable,
                     .strong => {},
@@ -1026,7 +997,7 @@ pub fn genNavRef(
                 return .{ .mcv = .{ .lea_symbol = sym_index } };
             },
             .strong, .weak => {
-                const sym_index = try macho_file.getGlobalSymbol(name.toSlice(ip), lib_name.toSlice(ip));
+                const sym_index = try macho_file.getGlobalSymbol(nav.name.toSlice(ip), lib_name.toSlice(ip));
                 switch (linkage) {
                     .internal => unreachable,
                     .strong => {},
@@ -1047,8 +1018,8 @@ pub fn genNavRef(
                 return .{ .mcv = .{ .load_got = sym_index } };
             },
             .strong, .weak => {
-                const global_index = try coff_file.getGlobalSymbol(name.toSlice(ip), lib_name.toSlice(ip));
-                try coff_file.need_got_table.put(gpa, global_index, {}); // needs GOT
+                const global_index = try coff_file.getGlobalSymbol(nav.name.toSlice(ip), lib_name.toSlice(ip));
+                try coff_file.need_got_table.put(zcu.gpa, global_index, {}); // needs GOT
                 return .{ .mcv = .{ .load_got = link.File.Coff.global_symbol_bit | global_index } };
             },
             .link_once => unreachable,
@@ -1058,7 +1029,7 @@ pub fn genNavRef(
         const atom = p9.getAtom(atom_index);
         return .{ .mcv = .{ .memory = atom.getOffsetTableAddress(p9) } };
     } else {
-        const msg = try ErrorMsg.create(gpa, src_loc, "TODO genNavRef for target {}", .{target});
+        const msg = try ErrorMsg.create(zcu.gpa, src_loc, "TODO genNavRef for target {}", .{target});
         return .{ .fail = msg };
     }
 }
@@ -1071,12 +1042,11 @@ pub fn genTypedValue(
     val: Value,
     target: std.Target,
 ) CodeGenError!GenResult {
-    const ip = &pt.zcu.intern_pool;
     return switch (try lowerValue(pt, val, &target)) {
         .none => .{ .mcv = .none },
         .undef => .{ .mcv = .undef },
         .immediate => |imm| .{ .mcv = .{ .immediate = imm } },
-        .lea_nav => |nav| genNavRef(lf, pt, src_loc, .fromInterned(ip.getNav(nav).typeOf(ip)), nav, target),
+        .lea_nav => |nav| genNavRef(lf, pt, src_loc, nav, target),
         .lea_uav => |uav| switch (try lf.lowerUav(
             pt,
             uav.val,