From c606ad4ce342fc8c69f94810b6d30b3d0fcc266f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20R=C3=B8nne=20Petersen?= Date: Sun, 23 Aug 2026 19:40:34 +0200 Subject: [PATCH] std.zig.llvm.Builder: add tripleForTarget(), init target_triple from it Users can now just pass a std.Target to Builder.init() rather than having to construct a target triple string themselves. This makes sense to do since we've already added std.Target knowledge to std.zig.llvm.Builder in the form of DataLayout anyway. closes https://codeberg.org/ziglang/zig/issues/36159 --- lib/std/zig/llvm/Builder.zig | 298 ++++++++++++++++++++++++++++++++++- src/Compilation.zig | 2 +- src/codegen/llvm.zig | 294 ---------------------------------- 3 files changed, 296 insertions(+), 298 deletions(-) diff --git a/lib/std/zig/llvm/Builder.zig b/lib/std/zig/llvm/Builder.zig index 93a1e4e438b6f5ca5b312db0417f0311f9e7460b..34e1bf7e6fe3c2644cb2b79449ba276aae9c6a58 100644 --- a/lib/std/zig/llvm/Builder.zig +++ b/lib/std/zig/llvm/Builder.zig @@ -84,9 +84,300 @@ pub const Options = struct { strip: bool = true, name: []const u8 = &.{}, target: *const std.Target = &builtin.target, - triple: []const u8 = &.{}, }; +fn subArchName(target: *const std.Target, comptime family: std.Target.Cpu.Arch.Family, mappings: anytype) ?[]const u8 { + inline for (mappings) |mapping| { + if (target.cpu.has(family, mapping[0])) return mapping[1]; + } + + return null; +} + +pub fn tripleForTarget(allocator: Allocator, target: *const std.Target) ![]const u8 { + var llvm_triple = std.array_list.Managed(u8).init(allocator); + defer llvm_triple.deinit(); + + const llvm_arch = switch (target.cpu.arch) { + .arm => "arm", + .armeb => "armeb", + .aarch64 => if (target.abi == .ilp32) "aarch64_32" else "aarch64", + .aarch64_be => "aarch64_be", + .arc => "arc", + .avr => "avr", + .bpfel => "bpfel", + .bpfeb => "bpfeb", + .csky => "csky", + .hexagon => "hexagon", + .loongarch32 => "loongarch32", + .loongarch64 => "loongarch64", + .m68k => "m68k", + // MIPS sub-architectures are a bit irregular, so we handle them manually here. + .mips => if (target.cpu.has(.mips, .mips32r6)) "mipsisa32r6" else "mips", + .mipsel => if (target.cpu.has(.mips, .mips32r6)) "mipsisa32r6el" else "mipsel", + .mips64 => if (target.cpu.has(.mips, .mips64r6)) "mipsisa64r6" else "mips64", + .mips64el => if (target.cpu.has(.mips, .mips64r6)) "mipsisa64r6el" else "mips64el", + .msp430 => "msp430", + .powerpc => "powerpc", + .powerpcle => "powerpcle", + .powerpc64 => "powerpc64", + .powerpc64le => "powerpc64le", + .amdgcn => "amdgcn", + .riscv32 => "riscv32", + .riscv32be => "riscv32be", + .riscv64 => "riscv64", + .riscv64be => "riscv64be", + .sparc => "sparc", + .sparc64 => "sparc64", + .s390x => "s390x", + .thumb => "thumb", + .thumbeb => "thumbeb", + .x86 => "i386", + .x86_64 => "x86_64", + .xcore => "xcore", + .xtensa => "xtensa", + .nvptx => "nvptx", + .nvptx64 => "nvptx64", + .spirv32 => switch (target.os.tag) { + .vulkan, .opengl => "spirv", + else => "spirv32", + }, + .spirv64 => "spirv64", + .lanai => "lanai", + .wasm32 => "wasm32", + .wasm64 => "wasm64", + .ve => "ve", + + .alpha, + .arceb, + .ez80, + .hppa, + .hppa64, + .kalimba, + .kvx, + .m88k, + .microblaze, + .microblazeel, + .or1k, + .propeller, + .sh, + .sheb, + .x86_16, + .xtensaeb, + => unreachable, // Gated by hasLlvmSupport(). + }; + + try llvm_triple.appendSlice(llvm_arch); + + const llvm_sub_arch: ?[]const u8 = switch (target.cpu.arch) { + .arm, .armeb, .thumb, .thumbeb => subArchName(target, .arm, .{ + .{ .v4t, "v4t" }, + .{ .v5t, "v5t" }, + .{ .v5te, "v5te" }, + .{ .v5tej, "v5tej" }, + .{ .v6, "v6" }, + .{ .v6k, "v6k" }, + .{ .v6kz, "v6kz" }, + .{ .v6m, "v6m" }, + .{ .v6t2, "v6t2" }, + .{ .v7a, "v7a" }, + .{ .v7em, "v7em" }, + .{ .v7m, "v7m" }, + .{ .v7r, "v7r" }, + .{ .v7ve, "v7ve" }, + .{ .v8a, "v8a" }, + .{ .v8_1a, "v8.1a" }, + .{ .v8_2a, "v8.2a" }, + .{ .v8_3a, "v8.3a" }, + .{ .v8_4a, "v8.4a" }, + .{ .v8_5a, "v8.5a" }, + .{ .v8_6a, "v8.6a" }, + .{ .v8_7a, "v8.7a" }, + .{ .v8_8a, "v8.8a" }, + .{ .v8_9a, "v8.9a" }, + .{ .v8m, "v8m.base" }, + .{ .v8m_main, "v8m.main" }, + .{ .v8_1m_main, "v8.1m.main" }, + .{ .v8r, "v8r" }, + .{ .v9a, "v9a" }, + .{ .v9_1a, "v9.1a" }, + .{ .v9_2a, "v9.2a" }, + .{ .v9_3a, "v9.3a" }, + .{ .v9_4a, "v9.4a" }, + .{ .v9_5a, "v9.5a" }, + .{ .v9_6a, "v9.6a" }, + .{ .v9_7a, "v9.7a" }, + }), + .powerpc => subArchName(target, .powerpc, .{ + .{ .spe, "spe" }, + }), + .spirv32, .spirv64 => subArchName(target, .spirv, .{ + .{ .v1_6, "1.6" }, + .{ .v1_5, "1.5" }, + .{ .v1_4, "1.4" }, + .{ .v1_3, "1.3" }, + .{ .v1_2, "1.2" }, + .{ .v1_1, "1.1" }, + }), + else => null, + }; + + if (llvm_sub_arch) |sub| try llvm_triple.appendSlice(sub); + try llvm_triple.append('-'); + + try llvm_triple.appendSlice(switch (target.os.tag) { + .driverkit, + .ios, + .maccatalyst, + .macos, + .tvos, + .visionos, + .watchos, + => "apple", + .ps4, + .ps5, + => "scei", + .amdhsa, + .amdpal, + => "amd", + .cuda, + .nvcl, + => "nvidia", + .mesa3d, + => "mesa", + else => "unknown", + }); + try llvm_triple.append('-'); + + const llvm_os = switch (target.os.tag) { + .dragonfly => "dragonfly", + .freebsd => "freebsd", + .fuchsia => "fuchsia", + .linux => "linux", + .netbsd => "netbsd", + .openbsd => "openbsd", + .illumos => "solaris", + .windows, .uefi => "windows", + .haiku => "haiku", + .rtems => "rtems", + .cuda => "cuda", + .nvcl => "nvcl", + .amdhsa => "amdhsa", + .ps3 => "lv2", + .ps4 => "ps4", + .ps5 => "ps5", + .mesa3d => "mesa3d", + .amdpal => "amdpal", + .hermit => "hermit", + .hurd => "hurd", + .wasi => "wasi", + .emscripten => "emscripten", + .macos => "macosx", + .ios, .maccatalyst => "ios", + .tvos => "tvos", + .watchos => "watchos", + .driverkit => "driverkit", + .visionos => "xros", + .serenity => "serenity", + .vulkan => "vulkan", + .managarm => "managarm", + + .contiki, + .freestanding, + .opencl, // https://llvm.org/docs/SPIRVUsage.html#target-triples + .opengl, + .other, + .plan9, + .psx, + .psp, + .vita, + .tios, + .@"3ds", + .wiiu, + .@"switch", + .ashetos, + => "unknown", + }; + try llvm_triple.appendSlice(llvm_os); + + switch (target.os.versionRange()) { + .none, + .windows, + => {}, + .semver => |ver| if (target.os.tag == .wasi and ver.min.major == 0) { + try llvm_triple.print("p{d}", .{ver.min.minor}); + } else if (target.os.tag != .amdhsa) { + try llvm_triple.print("{d}.{d}.{d}", .{ + ver.min.major, + ver.min.minor, + ver.min.patch, + }); + }, + inline .linux, .hurd => |ver| try llvm_triple.print("{d}.{d}.{d}", .{ + ver.range.min.major, + ver.range.min.minor, + ver.range.min.patch, + }), + } + try llvm_triple.append('-'); + + const llvm_abi = switch (target.abi) { + .none => if (target.os.tag == .maccatalyst) "macabi" else "unknown", + .gnu => "gnu", + .gnuabin32 => "gnuabin32", + .gnuabi64 => "gnuabi64", + .gnueabi => "gnueabi", + .gnueabihf => "gnueabihf", + .gnuf32 => "gnuf32", + .gnusf => "gnusf", + .gnux32 => "gnux32", + .ilp32 => "unknown", + .eabi => "eabi", + .eabihf => "eabihf", + .abin32 => "unknown", + .x32 => "muslx32", // https://github.com/ziglang/zig/issues/25649 + .android => "android", + .androideabi => "androideabi", + .musl => switch (target.os.tag) { + // For WASI/Emscripten, "musl" refers to the libc, not really the ABI. + // "unknown" provides better compatibility with LLVM-based tooling for these targets. + .wasi, .emscripten => "unknown", + else => "musl", + }, + .muslabin32 => "muslabin32", + .muslabi64 => "muslabi64", + .musleabi => "musleabi", + .musleabihf => "musleabihf", + .muslf32 => "muslf32", + .muslsf => "muslsf", + .muslx32 => "muslx32", + .msvc => "msvc", + .itanium => "itanium", + .simulator => "simulator", + .ohos, .ohoseabi => "ohos", + .call0 => "unknown", + }; + try llvm_triple.appendSlice(llvm_abi); + + switch (target.os.versionRange()) { + .none, + .semver, + .windows, + => {}, + inline .hurd, .linux => |ver| if (target.abi.isGnu()) { + try llvm_triple.print("{d}.{d}.{d}", .{ + ver.glibc.major, + ver.glibc.minor, + ver.glibc.patch, + }); + } else if (@TypeOf(ver) == std.Target.Os.LinuxVersionRange and target.abi.isAndroid()) { + try llvm_triple.print("{d}", .{ver.android}); + }, + } + + return llvm_triple.toOwnedSlice(); +} + pub const DataLayout = struct { endian: ?std.lang.Endian, int_specs: PrimitiveSpec.Map, @@ -9610,6 +9901,9 @@ pub fn init(options: Options) Allocator.Error!Builder { try self.string_indices.append(self.gpa, 0); assert(try self.string("") == .empty); + const llvm_triple = try tripleForTarget(self.gpa, options.target); + defer self.gpa.free(llvm_triple); + self.target_triple = try self.string(llvm_triple); self.data_layout = try .parseString(try self.string(DataLayout.stringForTarget(options.target)), &self); try self.strtab_string_indices.append(self.gpa, 0); @@ -9617,8 +9911,6 @@ pub fn init(options: Options) Allocator.Error!Builder { if (options.name.len > 0) self.source_filename = try self.string(options.name); - if (options.triple.len > 0) self.target_triple = try self.string(options.triple); - { const static_len = @typeInfo(Type).@"enum".field_names.len - 1; try self.type_map.ensureTotalCapacity(self.gpa, static_len); diff --git a/src/Compilation.zig b/src/Compilation.zig index fcb65eb66d89daedb4a2cd9e168a1461ad1486af..b8f2a1db98a4e836d150cfb1ef92a587833987d9 100644 --- a/src/Compilation.zig +++ b/src/Compilation.zig @@ -6574,7 +6574,7 @@ pub fn addCCArgs( try argv.append("-integrated-as"); } - const llvm_triple = try @import("codegen/llvm.zig").targetTriple(arena, target); + const llvm_triple = try std.zig.llvm.Builder.tripleForTarget(arena, target); try argv.appendSlice(&[_][]const u8{ "-target", llvm_triple }); if (target.cpu.arch.isThumb()) { diff --git a/src/codegen/llvm.zig b/src/codegen/llvm.zig index 4022a2b901c77443b977a4461e044de40a8230c9..a0cb2ac891f08409e40c780c1ec4049057dc887c 100644 --- a/src/codegen/llvm.zig +++ b/src/codegen/llvm.zig @@ -46,298 +46,6 @@ pub fn legalizeFeatures(target: *const std.Target) ?*const Air.Legalize.Features }; } -fn subArchName(target: *const std.Target, comptime family: std.Target.Cpu.Arch.Family, mappings: anytype) ?[]const u8 { - inline for (mappings) |mapping| { - if (target.cpu.has(family, mapping[0])) return mapping[1]; - } - - return null; -} - -pub fn targetTriple(allocator: Allocator, target: *const std.Target) ![]const u8 { - var llvm_triple = std.array_list.Managed(u8).init(allocator); - defer llvm_triple.deinit(); - - const llvm_arch = switch (target.cpu.arch) { - .arm => "arm", - .armeb => "armeb", - .aarch64 => if (target.abi == .ilp32) "aarch64_32" else "aarch64", - .aarch64_be => "aarch64_be", - .arc => "arc", - .avr => "avr", - .bpfel => "bpfel", - .bpfeb => "bpfeb", - .csky => "csky", - .hexagon => "hexagon", - .loongarch32 => "loongarch32", - .loongarch64 => "loongarch64", - .m68k => "m68k", - // MIPS sub-architectures are a bit irregular, so we handle them manually here. - .mips => if (target.cpu.has(.mips, .mips32r6)) "mipsisa32r6" else "mips", - .mipsel => if (target.cpu.has(.mips, .mips32r6)) "mipsisa32r6el" else "mipsel", - .mips64 => if (target.cpu.has(.mips, .mips64r6)) "mipsisa64r6" else "mips64", - .mips64el => if (target.cpu.has(.mips, .mips64r6)) "mipsisa64r6el" else "mips64el", - .msp430 => "msp430", - .powerpc => "powerpc", - .powerpcle => "powerpcle", - .powerpc64 => "powerpc64", - .powerpc64le => "powerpc64le", - .amdgcn => "amdgcn", - .riscv32 => "riscv32", - .riscv32be => "riscv32be", - .riscv64 => "riscv64", - .riscv64be => "riscv64be", - .sparc => "sparc", - .sparc64 => "sparc64", - .s390x => "s390x", - .thumb => "thumb", - .thumbeb => "thumbeb", - .x86 => "i386", - .x86_64 => "x86_64", - .xcore => "xcore", - .xtensa => "xtensa", - .nvptx => "nvptx", - .nvptx64 => "nvptx64", - .spirv32 => switch (target.os.tag) { - .vulkan, .opengl => "spirv", - else => "spirv32", - }, - .spirv64 => "spirv64", - .lanai => "lanai", - .wasm32 => "wasm32", - .wasm64 => "wasm64", - .ve => "ve", - - .alpha, - .arceb, - .ez80, - .hppa, - .hppa64, - .kalimba, - .kvx, - .m88k, - .microblaze, - .microblazeel, - .or1k, - .propeller, - .sh, - .sheb, - .x86_16, - .xtensaeb, - => unreachable, // Gated by hasLlvmSupport(). - }; - - try llvm_triple.appendSlice(llvm_arch); - - const llvm_sub_arch: ?[]const u8 = switch (target.cpu.arch) { - .arm, .armeb, .thumb, .thumbeb => subArchName(target, .arm, .{ - .{ .v4t, "v4t" }, - .{ .v5t, "v5t" }, - .{ .v5te, "v5te" }, - .{ .v5tej, "v5tej" }, - .{ .v6, "v6" }, - .{ .v6k, "v6k" }, - .{ .v6kz, "v6kz" }, - .{ .v6m, "v6m" }, - .{ .v6t2, "v6t2" }, - .{ .v7a, "v7a" }, - .{ .v7em, "v7em" }, - .{ .v7m, "v7m" }, - .{ .v7r, "v7r" }, - .{ .v7ve, "v7ve" }, - .{ .v8a, "v8a" }, - .{ .v8_1a, "v8.1a" }, - .{ .v8_2a, "v8.2a" }, - .{ .v8_3a, "v8.3a" }, - .{ .v8_4a, "v8.4a" }, - .{ .v8_5a, "v8.5a" }, - .{ .v8_6a, "v8.6a" }, - .{ .v8_7a, "v8.7a" }, - .{ .v8_8a, "v8.8a" }, - .{ .v8_9a, "v8.9a" }, - .{ .v8m, "v8m.base" }, - .{ .v8m_main, "v8m.main" }, - .{ .v8_1m_main, "v8.1m.main" }, - .{ .v8r, "v8r" }, - .{ .v9a, "v9a" }, - .{ .v9_1a, "v9.1a" }, - .{ .v9_2a, "v9.2a" }, - .{ .v9_3a, "v9.3a" }, - .{ .v9_4a, "v9.4a" }, - .{ .v9_5a, "v9.5a" }, - .{ .v9_6a, "v9.6a" }, - .{ .v9_7a, "v9.7a" }, - }), - .powerpc => subArchName(target, .powerpc, .{ - .{ .spe, "spe" }, - }), - .spirv32, .spirv64 => subArchName(target, .spirv, .{ - .{ .v1_6, "1.6" }, - .{ .v1_5, "1.5" }, - .{ .v1_4, "1.4" }, - .{ .v1_3, "1.3" }, - .{ .v1_2, "1.2" }, - .{ .v1_1, "1.1" }, - }), - else => null, - }; - - if (llvm_sub_arch) |sub| try llvm_triple.appendSlice(sub); - try llvm_triple.append('-'); - - try llvm_triple.appendSlice(switch (target.os.tag) { - .driverkit, - .ios, - .maccatalyst, - .macos, - .tvos, - .visionos, - .watchos, - => "apple", - .ps4, - .ps5, - => "scei", - .amdhsa, - .amdpal, - => "amd", - .cuda, - .nvcl, - => "nvidia", - .mesa3d, - => "mesa", - else => "unknown", - }); - try llvm_triple.append('-'); - - const llvm_os = switch (target.os.tag) { - .dragonfly => "dragonfly", - .freebsd => "freebsd", - .fuchsia => "fuchsia", - .linux => "linux", - .netbsd => "netbsd", - .openbsd => "openbsd", - .illumos => "solaris", - .windows, .uefi => "windows", - .haiku => "haiku", - .rtems => "rtems", - .cuda => "cuda", - .nvcl => "nvcl", - .amdhsa => "amdhsa", - .ps3 => "lv2", - .ps4 => "ps4", - .ps5 => "ps5", - .mesa3d => "mesa3d", - .amdpal => "amdpal", - .hermit => "hermit", - .hurd => "hurd", - .wasi => "wasi", - .emscripten => "emscripten", - .macos => "macosx", - .ios, .maccatalyst => "ios", - .tvos => "tvos", - .watchos => "watchos", - .driverkit => "driverkit", - .visionos => "xros", - .serenity => "serenity", - .vulkan => "vulkan", - .managarm => "managarm", - - .contiki, - .freestanding, - .opencl, // https://llvm.org/docs/SPIRVUsage.html#target-triples - .opengl, - .other, - .plan9, - .psx, - .psp, - .vita, - .tios, - .@"3ds", - .wiiu, - .@"switch", - .ashetos, - => "unknown", - }; - try llvm_triple.appendSlice(llvm_os); - - switch (target.os.versionRange()) { - .none, - .windows, - => {}, - .semver => |ver| if (target.os.tag == .wasi and ver.min.major == 0) { - try llvm_triple.print("p{d}", .{ver.min.minor}); - } else if (target.os.tag != .amdhsa) { - try llvm_triple.print("{d}.{d}.{d}", .{ - ver.min.major, - ver.min.minor, - ver.min.patch, - }); - }, - inline .linux, .hurd => |ver| try llvm_triple.print("{d}.{d}.{d}", .{ - ver.range.min.major, - ver.range.min.minor, - ver.range.min.patch, - }), - } - try llvm_triple.append('-'); - - const llvm_abi = switch (target.abi) { - .none => if (target.os.tag == .maccatalyst) "macabi" else "unknown", - .gnu => "gnu", - .gnuabin32 => "gnuabin32", - .gnuabi64 => "gnuabi64", - .gnueabi => "gnueabi", - .gnueabihf => "gnueabihf", - .gnuf32 => "gnuf32", - .gnusf => "gnusf", - .gnux32 => "gnux32", - .ilp32 => "unknown", - .eabi => "eabi", - .eabihf => "eabihf", - .abin32 => "unknown", - .x32 => "muslx32", // https://github.com/ziglang/zig/issues/25649 - .android => "android", - .androideabi => "androideabi", - .musl => switch (target.os.tag) { - // For WASI/Emscripten, "musl" refers to the libc, not really the ABI. - // "unknown" provides better compatibility with LLVM-based tooling for these targets. - .wasi, .emscripten => "unknown", - else => "musl", - }, - .muslabin32 => "muslabin32", - .muslabi64 => "muslabi64", - .musleabi => "musleabi", - .musleabihf => "musleabihf", - .muslf32 => "muslf32", - .muslsf => "muslsf", - .muslx32 => "muslx32", - .msvc => "msvc", - .itanium => "itanium", - .simulator => "simulator", - .ohos, .ohoseabi => "ohos", - .call0 => "unknown", - }; - try llvm_triple.appendSlice(llvm_abi); - - switch (target.os.versionRange()) { - .none, - .semver, - .windows, - => {}, - inline .hurd, .linux => |ver| if (target.abi.isGnu()) { - try llvm_triple.print("{d}.{d}.{d}", .{ - ver.glibc.major, - ver.glibc.minor, - ver.glibc.patch, - }); - } else if (@TypeOf(ver) == std.Target.Os.LinuxVersionRange and target.abi.isAndroid()) { - try llvm_triple.print("{d}", .{ver.android}); - }, - } - - return llvm_triple.toOwnedSlice(); -} - pub fn supportsTailCall(target: *const std.Target) bool { return switch (target.cpu.arch) { .wasm32, .wasm64 => target.cpu.has(.wasm, .tail_call), @@ -456,14 +164,12 @@ pub const Object = struct { const comp = zcu.comp; const gpa = comp.gpa; const target = zcu.getTarget(); - const llvm_target_triple = try targetTriple(arena, target); var builder = try Builder.init(.{ .allocator = gpa, .strip = comp.config.debug_format == .strip, .name = comp.root_name, .target = target, - .triple = llvm_target_triple, }); errdefer builder.deinit(); -- 2.54.0