From d312dfc1f21a9194dd06c1d45f653bdaf823d2f6 Mon Sep 17 00:00:00 2001 From: Jacob Young Date: Mon, 9 Jun 2025 02:36:32 -0400 Subject: [PATCH] codegen: make threadlocal logic consistent --- src/arch/x86_64/CodeGen.zig | 3 ++- src/arch/x86_64/Emit.zig | 28 ++++++--------------- src/codegen.zig | 48 +++++++----------------------------- src/link/Elf/ZigObject.zig | 5 ++-- src/link/MachO/ZigObject.zig | 5 ++-- 5 files changed, 23 insertions(+), 66 deletions(-) diff --git a/src/arch/x86_64/CodeGen.zig b/src/arch/x86_64/CodeGen.zig index 5d2dd08de7..4a0113fe36 100644 --- a/src/arch/x86_64/CodeGen.zig +++ b/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 { diff --git a/src/arch/x86_64/Emit.zig b/src/arch/x86_64/Emit.zig index ff6bf85ef3..8a9609dafc 100644 --- a/src/arch/x86_64/Emit.zig +++ b/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; diff --git a/src/codegen.zig b/src/codegen.zig index a977d3003f..df9c0b4464 100644 --- a/src/codegen.zig +++ b/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, diff --git a/src/link/Elf/ZigObject.zig b/src/link/Elf/ZigObject.zig index 9d70caa632..71b42819e2 100644 --- a/src/link/Elf/ZigObject.zig +++ b/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(); diff --git a/src/link/MachO/ZigObject.zig b/src/link/MachO/ZigObject.zig index 9b32bcde65..f9ecdc6fb5 100644 --- a/src/link/MachO/ZigObject.zig +++ b/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(