diff options
| author | Andrew Kelley <andrew@ziglang.org> | 2024-01-02 14:11:27 -0800 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2024-01-02 14:11:27 -0800 |
| commit | 289ae45c1b58e952867c4fa1e246d0ef7bc2ff64 (patch) | |
| tree | 5dd034143a2354b7b44496e684f1c764e2f9664c /lib/std/target.zig | |
| parent | c89bb3e141ee215add0b52930d48bffd8dae8342 (diff) | |
| parent | c546ddb3edc557fae4b932e5239b9dcb66117832 (diff) | |
| download | zig-289ae45c1b58e952867c4fa1e246d0ef7bc2ff64.tar.gz zig-289ae45c1b58e952867c4fa1e246d0ef7bc2ff64.zip | |
Merge pull request #18160 from ziglang/std-build-module
Move many settings from being per-Compilation to being per-Module
Diffstat (limited to 'lib/std/target.zig')
| -rw-r--r-- | lib/std/target.zig | 2608 |
1 files changed, 0 insertions, 2608 deletions
diff --git a/lib/std/target.zig b/lib/std/target.zig deleted file mode 100644 index bb03c8e0cd..0000000000 --- a/lib/std/target.zig +++ /dev/null @@ -1,2608 +0,0 @@ -const std = @import("std.zig"); -const builtin = @import("builtin"); -const mem = std.mem; -const Version = std.SemanticVersion; - -pub const Target = struct { - cpu: Cpu, - os: Os, - abi: Abi, - ofmt: ObjectFormat, - - pub const Os = struct { - tag: Tag, - version_range: VersionRange, - - pub const Tag = enum { - freestanding, - ananas, - cloudabi, - dragonfly, - freebsd, - fuchsia, - ios, - kfreebsd, - linux, - lv2, - macos, - netbsd, - openbsd, - solaris, - uefi, - windows, - zos, - haiku, - minix, - rtems, - nacl, - aix, - cuda, - nvcl, - amdhsa, - ps4, - ps5, - elfiamcu, - tvos, - watchos, - driverkit, - mesa3d, - contiki, - amdpal, - hermit, - hurd, - wasi, - emscripten, - shadermodel, - liteos, - opencl, - glsl450, - vulkan, - plan9, - illumos, - other, - - pub inline fn isDarwin(tag: Tag) bool { - return switch (tag) { - .ios, .macos, .watchos, .tvos => true, - else => false, - }; - } - - pub inline fn isBSD(tag: Tag) bool { - return tag.isDarwin() or switch (tag) { - .kfreebsd, .freebsd, .openbsd, .netbsd, .dragonfly => true, - else => false, - }; - } - - pub inline fn isSolarish(tag: Tag) bool { - return tag == .solaris or tag == .illumos; - } - - pub fn dynamicLibSuffix(tag: Tag) [:0]const u8 { - if (tag.isDarwin()) { - return ".dylib"; - } - switch (tag) { - .windows => return ".dll", - else => return ".so", - } - } - - pub fn defaultVersionRange(tag: Tag, arch: Cpu.Arch) Os { - return .{ - .tag = tag, - .version_range = VersionRange.default(tag, arch), - }; - } - }; - - /// Based on NTDDI version constants from - /// https://docs.microsoft.com/en-us/cpp/porting/modifying-winver-and-win32-winnt - pub const WindowsVersion = enum(u32) { - nt4 = 0x04000000, - win2k = 0x05000000, - xp = 0x05010000, - ws2003 = 0x05020000, - vista = 0x06000000, - win7 = 0x06010000, - win8 = 0x06020000, - win8_1 = 0x06030000, - win10 = 0x0A000000, //aka win10_th1 - win10_th2 = 0x0A000001, - win10_rs1 = 0x0A000002, - win10_rs2 = 0x0A000003, - win10_rs3 = 0x0A000004, - win10_rs4 = 0x0A000005, - win10_rs5 = 0x0A000006, - win10_19h1 = 0x0A000007, - win10_vb = 0x0A000008, //aka win10_19h2 - win10_mn = 0x0A000009, //aka win10_20h1 - win10_fe = 0x0A00000A, //aka win10_20h2 - _, - - /// Latest Windows version that the Zig Standard Library is aware of - pub const latest = WindowsVersion.win10_fe; - - /// Compared against build numbers reported by the runtime to distinguish win10 versions, - /// where 0x0A000000 + index corresponds to the WindowsVersion u32 value. - pub const known_win10_build_numbers = [_]u32{ - 10240, //win10 aka win10_th1 - 10586, //win10_th2 - 14393, //win10_rs1 - 15063, //win10_rs2 - 16299, //win10_rs3 - 17134, //win10_rs4 - 17763, //win10_rs5 - 18362, //win10_19h1 - 18363, //win10_vb aka win10_19h2 - 19041, //win10_mn aka win10_20h1 - 19042, //win10_fe aka win10_20h2 - }; - - /// Returns whether the first version `self` is newer (greater) than or equal to the second version `ver`. - pub inline fn isAtLeast(self: WindowsVersion, ver: WindowsVersion) bool { - return @intFromEnum(self) >= @intFromEnum(ver); - } - - pub const Range = struct { - min: WindowsVersion, - max: WindowsVersion, - - pub inline fn includesVersion(self: Range, ver: WindowsVersion) bool { - return @intFromEnum(ver) >= @intFromEnum(self.min) and @intFromEnum(ver) <= @intFromEnum(self.max); - } - - /// Checks if system is guaranteed to be at least `version` or older than `version`. - /// Returns `null` if a runtime check is required. - pub inline fn isAtLeast(self: Range, ver: WindowsVersion) ?bool { - if (@intFromEnum(self.min) >= @intFromEnum(ver)) return true; - if (@intFromEnum(self.max) < @intFromEnum(ver)) return false; - return null; - } - }; - - /// This function is defined to serialize a Zig source code representation of this - /// type, that, when parsed, will deserialize into the same data. - pub fn format( - self: WindowsVersion, - comptime fmt: []const u8, - _: std.fmt.FormatOptions, - out_stream: anytype, - ) !void { - if (comptime std.mem.eql(u8, fmt, "s")) { - if (@intFromEnum(self) >= @intFromEnum(WindowsVersion.nt4) and @intFromEnum(self) <= @intFromEnum(WindowsVersion.latest)) { - try std.fmt.format(out_stream, ".{s}", .{@tagName(self)}); - } else { - // TODO this code path breaks zig triples, but it is used in `builtin` - try std.fmt.format(out_stream, "@enumFromInt(Target.Os.WindowsVersion, 0x{X:0>8})", .{@intFromEnum(self)}); - } - } else if (fmt.len == 0) { - if (@intFromEnum(self) >= @intFromEnum(WindowsVersion.nt4) and @intFromEnum(self) <= @intFromEnum(WindowsVersion.latest)) { - try std.fmt.format(out_stream, "WindowsVersion.{s}", .{@tagName(self)}); - } else { - try std.fmt.format(out_stream, "WindowsVersion(0x{X:0>8})", .{@intFromEnum(self)}); - } - } else { - std.fmt.invalidFmtError(fmt, self); - } - } - }; - - pub const LinuxVersionRange = struct { - range: Version.Range, - glibc: Version, - - pub inline fn includesVersion(self: LinuxVersionRange, ver: Version) bool { - return self.range.includesVersion(ver); - } - - /// Checks if system is guaranteed to be at least `version` or older than `version`. - /// Returns `null` if a runtime check is required. - pub inline fn isAtLeast(self: LinuxVersionRange, ver: Version) ?bool { - return self.range.isAtLeast(ver); - } - }; - - /// The version ranges here represent the minimum OS version to be supported - /// and the maximum OS version to be supported. The default values represent - /// the range that the Zig Standard Library bases its abstractions on. - /// - /// The minimum version of the range is the main setting to tweak for a target. - /// Usually, the maximum target OS version will remain the default, which is - /// the latest released version of the OS. - /// - /// To test at compile time if the target is guaranteed to support a given OS feature, - /// one should check that the minimum version of the range is greater than or equal to - /// the version the feature was introduced in. - /// - /// To test at compile time if the target certainly will not support a given OS feature, - /// one should check that the maximum version of the range is less than the version the - /// feature was introduced in. - /// - /// If neither of these cases apply, a runtime check should be used to determine if the - /// target supports a given OS feature. - /// - /// Binaries built with a given maximum version will continue to function on newer - /// operating system versions. However, such a binary may not take full advantage of the - /// newer operating system APIs. - /// - /// See `Os.isAtLeast`. - pub const VersionRange = union { - none: void, - semver: Version.Range, - linux: LinuxVersionRange, - windows: WindowsVersion.Range, - - /// The default `VersionRange` represents the range that the Zig Standard Library - /// bases its abstractions on. - pub fn default(tag: Tag, arch: Cpu.Arch) VersionRange { - switch (tag) { - .freestanding, - .ananas, - .cloudabi, - .fuchsia, - .kfreebsd, - .lv2, - .zos, - .haiku, - .minix, - .rtems, - .nacl, - .aix, - .cuda, - .nvcl, - .amdhsa, - .ps4, - .ps5, - .elfiamcu, - .mesa3d, - .contiki, - .amdpal, - .hermit, - .hurd, - .wasi, - .emscripten, - .driverkit, - .shadermodel, - .liteos, - .uefi, - .opencl, // TODO: OpenCL versions - .glsl450, // TODO: GLSL versions - .vulkan, - .plan9, - .illumos, - .other, - => return .{ .none = {} }, - - .freebsd => return .{ - .semver = Version.Range{ - .min = .{ .major = 12, .minor = 0, .patch = 0 }, - .max = .{ .major = 14, .minor = 0, .patch = 0 }, - }, - }, - .macos => return switch (arch) { - .aarch64 => VersionRange{ - .semver = .{ - .min = .{ .major = 11, .minor = 7, .patch = 1 }, - .max = .{ .major = 14, .minor = 1, .patch = 0 }, - }, - }, - .x86_64 => VersionRange{ - .semver = .{ - .min = .{ .major = 11, .minor = 7, .patch = 1 }, - .max = .{ .major = 14, .minor = 1, .patch = 0 }, - }, - }, - else => unreachable, - }, - .ios => return .{ - .semver = .{ - .min = .{ .major = 12, .minor = 0, .patch = 0 }, - .max = .{ .major = 17, .minor = 1, .patch = 0 }, - }, - }, - .watchos => return .{ - .semver = .{ - .min = .{ .major = 6, .minor = 0, .patch = 0 }, - .max = .{ .major = 10, .minor = 1, .patch = 0 }, - }, - }, - .tvos => return .{ - .semver = .{ - .min = .{ .major = 13, .minor = 0, .patch = 0 }, - .max = .{ .major = 17, .minor = 1, .patch = 0 }, - }, - }, - .netbsd => return .{ - .semver = .{ - .min = .{ .major = 8, .minor = 0, .patch = 0 }, - .max = .{ .major = 10, .minor = 0, .patch = 0 }, - }, - }, - .openbsd => return .{ - .semver = .{ - .min = .{ .major = 6, .minor = 8, .patch = 0 }, - .max = .{ .major = 7, .minor = 4, .patch = 0 }, - }, - }, - .dragonfly => return .{ - .semver = .{ - .min = .{ .major = 5, .minor = 8, .patch = 0 }, - .max = .{ .major = 6, .minor = 4, .patch = 0 }, - }, - }, - .solaris => return .{ - .semver = .{ - .min = .{ .major = 5, .minor = 11, .patch = 0 }, - .max = .{ .major = 5, .minor = 11, .patch = 0 }, - }, - }, - - .linux => return .{ - .linux = .{ - .range = .{ - .min = .{ .major = 4, .minor = 19, .patch = 0 }, - .max = .{ .major = 6, .minor = 5, .patch = 7 }, - }, - .glibc = .{ .major = 2, .minor = 28, .patch = 0 }, - }, - }, - - .windows => return .{ - .windows = .{ - .min = .win8_1, - .max = WindowsVersion.latest, - }, - }, - } - } - }; - - pub const TaggedVersionRange = union(enum) { - none: void, - semver: Version.Range, - linux: LinuxVersionRange, - windows: WindowsVersion.Range, - }; - - /// Provides a tagged union. `Target` does not store the tag because it is - /// redundant with the OS tag; this function abstracts that part away. - pub inline fn getVersionRange(self: Os) TaggedVersionRange { - switch (self.tag) { - .linux => return TaggedVersionRange{ .linux = self.version_range.linux }, - .windows => return TaggedVersionRange{ .windows = self.version_range.windows }, - - .freebsd, - .macos, - .ios, - .tvos, - .watchos, - .netbsd, - .openbsd, - .dragonfly, - .solaris, - => return TaggedVersionRange{ .semver = self.version_range.semver }, - - else => return .none, - } - } - - /// Checks if system is guaranteed to be at least `version` or older than `version`. - /// Returns `null` if a runtime check is required. - pub inline fn isAtLeast(self: Os, comptime tag: Tag, version: anytype) ?bool { - if (self.tag != tag) return false; - - return switch (tag) { - .linux => self.version_range.linux.isAtLeast(version), - .windows => self.version_range.windows.isAtLeast(version), - else => self.version_range.semver.isAtLeast(version), - }; - } - - /// On Darwin, we always link libSystem which contains libc. - /// Similarly on FreeBSD and NetBSD we always link system libc - /// since this is the stable syscall interface. - pub fn requiresLibC(os: Os) bool { - return switch (os.tag) { - .freebsd, - .netbsd, - .macos, - .ios, - .tvos, - .watchos, - .dragonfly, - .openbsd, - .haiku, - .solaris, - .illumos, - => true, - - .linux, - .windows, - .freestanding, - .ananas, - .cloudabi, - .fuchsia, - .kfreebsd, - .lv2, - .zos, - .minix, - .rtems, - .nacl, - .aix, - .cuda, - .nvcl, - .amdhsa, - .ps4, - .ps5, - .elfiamcu, - .mesa3d, - .contiki, - .amdpal, - .hermit, - .hurd, - .wasi, - .emscripten, - .driverkit, - .shadermodel, - .liteos, - .uefi, - .opencl, - .glsl450, - .vulkan, - .plan9, - .other, - => false, - }; - } - }; - - pub const aarch64 = @import("target/aarch64.zig"); - pub const arc = @import("target/arc.zig"); - pub const amdgpu = @import("target/amdgpu.zig"); - pub const arm = @import("target/arm.zig"); - pub const avr = @import("target/avr.zig"); - pub const bpf = @import("target/bpf.zig"); - pub const csky = @import("target/csky.zig"); - pub const hexagon = @import("target/hexagon.zig"); - pub const loongarch = @import("target/loongarch.zig"); - pub const m68k = @import("target/m68k.zig"); - pub const mips = @import("target/mips.zig"); - pub const msp430 = @import("target/msp430.zig"); - pub const nvptx = @import("target/nvptx.zig"); - pub const powerpc = @import("target/powerpc.zig"); - pub const riscv = @import("target/riscv.zig"); - pub const sparc = @import("target/sparc.zig"); - pub const spirv = @import("target/spirv.zig"); - pub const s390x = @import("target/s390x.zig"); - pub const ve = @import("target/ve.zig"); - pub const wasm = @import("target/wasm.zig"); - pub const x86 = @import("target/x86.zig"); - pub const xtensa = @import("target/xtensa.zig"); - - pub const Abi = enum { - none, - gnu, - gnuabin32, - gnuabi64, - gnueabi, - gnueabihf, - gnuf32, - gnuf64, - gnusf, - gnux32, - gnuilp32, - code16, - eabi, - eabihf, - android, - musl, - musleabi, - musleabihf, - muslx32, - msvc, - itanium, - cygnus, - coreclr, - simulator, - macabi, - pixel, - vertex, - geometry, - hull, - domain, - compute, - library, - raygeneration, - intersection, - anyhit, - closesthit, - miss, - callable, - mesh, - amplification, - - pub fn default(arch: Cpu.Arch, target_os: Os) Abi { - if (arch.isWasm()) { - return .musl; - } - switch (target_os.tag) { - .freestanding, - .ananas, - .cloudabi, - .dragonfly, - .lv2, - .zos, - .minix, - .rtems, - .nacl, - .aix, - .cuda, - .nvcl, - .amdhsa, - .ps4, - .ps5, - .elfiamcu, - .mesa3d, - .contiki, - .amdpal, - .hermit, - .other, - => return .eabi, - .openbsd, - .freebsd, - .fuchsia, - .kfreebsd, - .netbsd, - .hurd, - .haiku, - .windows, - => return .gnu, - .uefi => return .msvc, - .linux, - .wasi, - .emscripten, - => return .musl, - .opencl, // TODO: SPIR-V ABIs with Linkage capability - .glsl450, - .vulkan, - .plan9, // TODO specify abi - .macos, - .ios, - .tvos, - .watchos, - .driverkit, - .shadermodel, - .liteos, // TODO: audit this - .solaris, - .illumos, - => return .none, - } - } - - pub inline fn isGnu(abi: Abi) bool { - return switch (abi) { - .gnu, .gnuabin32, .gnuabi64, .gnueabi, .gnueabihf, .gnux32 => true, - else => false, - }; - } - - pub inline fn isMusl(abi: Abi) bool { - return switch (abi) { - .musl, .musleabi, .musleabihf => true, - else => false, - }; - } - - pub inline fn floatAbi(abi: Abi) FloatAbi { - return switch (abi) { - .gnueabihf, - .eabihf, - .musleabihf, - => .hard, - else => .soft, - }; - } - }; - - pub const ObjectFormat = enum { - /// Common Object File Format (Windows) - coff, - /// DirectX Container - dxcontainer, - /// Executable and Linking Format - elf, - /// macOS relocatables - macho, - /// Standard, Portable Intermediate Representation V - spirv, - /// WebAssembly - wasm, - /// C source code - c, - /// Intel IHEX - hex, - /// Machine code with no metadata. - raw, - /// Plan 9 from Bell Labs - plan9, - /// Nvidia PTX format - nvptx, - - pub fn fileExt(of: ObjectFormat, cpu_arch: Cpu.Arch) [:0]const u8 { - return switch (of) { - .coff => ".obj", - .elf, .macho, .wasm => ".o", - .c => ".c", - .spirv => ".spv", - .hex => ".ihex", - .raw => ".bin", - .plan9 => plan9Ext(cpu_arch), - .nvptx => ".ptx", - .dxcontainer => ".dxil", - }; - } - - pub fn default(os_tag: Os.Tag, cpu_arch: Cpu.Arch) ObjectFormat { - return switch (os_tag) { - .windows, .uefi => .coff, - .ios, .macos, .watchos, .tvos => .macho, - .plan9 => .plan9, - else => return switch (cpu_arch) { - .wasm32, .wasm64 => .wasm, - .spirv32, .spirv64 => .spirv, - .nvptx, .nvptx64 => .nvptx, - else => .elf, - }, - }; - } - }; - - pub const SubSystem = enum { - Console, - Windows, - Posix, - Native, - EfiApplication, - EfiBootServiceDriver, - EfiRom, - EfiRuntimeDriver, - }; - - pub const Cpu = struct { - /// Architecture - arch: Arch, - - /// The CPU model to target. It has a set of features - /// which are overridden with the `features` field. - model: *const Model, - - /// An explicit list of the entire CPU feature set. It may differ from the specific CPU model's features. - features: Feature.Set, - - pub const Feature = struct { - /// The bit index into `Set`. Has a default value of `undefined` because the canonical - /// structures are populated via comptime logic. - index: Set.Index = undefined, - - /// Has a default value of `undefined` because the canonical - /// structures are populated via comptime logic. - name: []const u8 = undefined, - - /// If this corresponds to an LLVM-recognized feature, this will be populated; - /// otherwise null. - llvm_name: ?[:0]const u8, - - /// Human-friendly UTF-8 text. - description: []const u8, - - /// Sparse `Set` of features this depends on. - dependencies: Set, - - /// A bit set of all the features. - pub const Set = struct { - ints: [usize_count]usize, - - pub const needed_bit_count = 288; - pub const byte_count = (needed_bit_count + 7) / 8; - pub const usize_count = (byte_count + (@sizeOf(usize) - 1)) / @sizeOf(usize); - pub const Index = std.math.Log2Int(std.meta.Int(.unsigned, usize_count * @bitSizeOf(usize))); - pub const ShiftInt = std.math.Log2Int(usize); - - pub const empty = Set{ .ints = [1]usize{0} ** usize_count }; - - pub fn isEmpty(set: Set) bool { - return for (set.ints) |x| { - if (x != 0) break false; - } else true; - } - - pub fn isEnabled(set: Set, arch_feature_index: Index) bool { - const usize_index = arch_feature_index / @bitSizeOf(usize); - const bit_index = @as(ShiftInt, @intCast(arch_feature_index % @bitSizeOf(usize))); - return (set.ints[usize_index] & (@as(usize, 1) << bit_index)) != 0; - } - - /// Adds the specified feature but not its dependencies. - pub fn addFeature(set: *Set, arch_feature_index: Index) void { - const usize_index = arch_feature_index / @bitSizeOf(usize); - const bit_index = @as(ShiftInt, @intCast(arch_feature_index % @bitSizeOf(usize))); - set.ints[usize_index] |= @as(usize, 1) << bit_index; - } - - /// Adds the specified feature set but not its dependencies. - pub fn addFeatureSet(set: *Set, other_set: Set) void { - switch (builtin.zig_backend) { - .stage2_x86_64 => { - for (&set.ints, other_set.ints) |*set_int, other_set_int| set_int.* |= other_set_int; - }, - else => { - set.ints = @as(@Vector(usize_count, usize), set.ints) | @as(@Vector(usize_count, usize), other_set.ints); - }, - } - } - - /// Removes the specified feature but not its dependents. - pub fn removeFeature(set: *Set, arch_feature_index: Index) void { - const usize_index = arch_feature_index / @bitSizeOf(usize); - const bit_index = @as(ShiftInt, @intCast(arch_feature_index % @bitSizeOf(usize))); - set.ints[usize_index] &= ~(@as(usize, 1) << bit_index); - } - - /// Removes the specified feature but not its dependents. - pub fn removeFeatureSet(set: *Set, other_set: Set) void { - switch (builtin.zig_backend) { - .stage2_x86_64 => { - for (&set.ints, other_set.ints) |*set_int, other_set_int| set_int.* &= ~other_set_int; - }, - else => { - set.ints = @as(@Vector(usize_count, usize), set.ints) & ~@as(@Vector(usize_count, usize), other_set.ints); - }, - } - } - - pub fn populateDependencies(set: *Set, all_features_list: []const Cpu.Feature) void { - @setEvalBranchQuota(1000000); - - var old = set.ints; - while (true) { - for (all_features_list, 0..) |feature, index_usize| { - const index = @as(Index, @intCast(index_usize)); - if (set.isEnabled(index)) { - set.addFeatureSet(feature.dependencies); - } - } - const nothing_changed = mem.eql(usize, &old, &set.ints); - if (nothing_changed) return; - old = set.ints; - } - } - - pub fn asBytes(set: *const Set) *const [byte_count]u8 { - return @as(*const [byte_count]u8, @ptrCast(&set.ints)); - } - - pub fn eql(set: Set, other_set: Set) bool { - return mem.eql(usize, &set.ints, &other_set.ints); - } - - pub fn isSuperSetOf(set: Set, other_set: Set) bool { - switch (builtin.zig_backend) { - .stage2_x86_64 => { - var result = true; - for (&set.ints, other_set.ints) |*set_int, other_set_int| - result = result and (set_int.* & other_set_int) == other_set_int; - return result; - }, - else => { - const V = @Vector(usize_count, usize); - const set_v: V = set.ints; - const other_v: V = other_set.ints; - return @reduce(.And, (set_v & other_v) == other_v); - }, - } - } - }; - - pub fn feature_set_fns(comptime F: type) type { - return struct { - /// Populates only the feature bits specified. - pub fn featureSet(features: []const F) Set { - var x = Set.empty; - for (features) |feature| { - x.addFeature(@intFromEnum(feature)); - } - return x; - } - - /// Returns true if the specified feature is enabled. - pub fn featureSetHas(set: Set, feature: F) bool { - return set.isEnabled(@intFromEnum(feature)); - } - - /// Returns true if any specified feature is enabled. - pub fn featureSetHasAny(set: Set, features: anytype) bool { - inline for (features) |feature| { - if (set.isEnabled(@intFromEnum(@as(F, feature)))) return true; - } - return false; - } - - /// Returns true if every specified feature is enabled. - pub fn featureSetHasAll(set: Set, features: anytype) bool { - inline for (features) |feature| { - if (!set.isEnabled(@intFromEnum(@as(F, feature)))) return false; - } - return true; - } - }; - } - }; - - pub const Arch = enum { - arm, - armeb, - aarch64, - aarch64_be, - aarch64_32, - arc, - avr, - bpfel, - bpfeb, - csky, - dxil, - hexagon, - loongarch32, - loongarch64, - m68k, - mips, - mipsel, - mips64, - mips64el, - msp430, - powerpc, - powerpcle, - powerpc64, - powerpc64le, - r600, - amdgcn, - riscv32, - riscv64, - sparc, - sparc64, - sparcel, - s390x, - tce, - tcele, - thumb, - thumbeb, - x86, - x86_64, - xcore, - xtensa, - nvptx, - nvptx64, - le32, - le64, - amdil, - amdil64, - hsail, - hsail64, - spir, - spir64, - spirv32, - spirv64, - kalimba, - shave, - lanai, - wasm32, - wasm64, - renderscript32, - renderscript64, - ve, - // Stage1 currently assumes that architectures above this comment - // map one-to-one with the ZigLLVM_ArchType enum. - spu_2, - - pub inline fn isX86(arch: Arch) bool { - return switch (arch) { - .x86, .x86_64 => true, - else => false, - }; - } - - pub inline fn isARM(arch: Arch) bool { - return switch (arch) { - .arm, .armeb => true, - else => false, - }; - } - - pub inline fn isAARCH64(arch: Arch) bool { - return switch (arch) { - .aarch64, .aarch64_be, .aarch64_32 => true, - else => false, - }; - } - - pub inline fn isThumb(arch: Arch) bool { - return switch (arch) { - .thumb, .thumbeb => true, - else => false, - }; - } - - pub inline fn isArmOrThumb(arch: Arch) bool { - return arch.isARM() or arch.isThumb(); - } - - pub inline fn isWasm(arch: Arch) bool { - return switch (arch) { - .wasm32, .wasm64 => true, - else => false, - }; - } - - pub inline fn isRISCV(arch: Arch) bool { - return switch (arch) { - .riscv32, .riscv64 => true, - else => false, - }; - } - - pub inline fn isMIPS(arch: Arch) bool { - return switch (arch) { - .mips, .mipsel, .mips64, .mips64el => true, - else => false, - }; - } - - pub inline fn isPPC(arch: Arch) bool { - return switch (arch) { - .powerpc, .powerpcle => true, - else => false, - }; - } - - pub inline fn isPPC64(arch: Arch) bool { - return switch (arch) { - .powerpc64, .powerpc64le => true, - else => false, - }; - } - - pub inline fn isSPARC(arch: Arch) bool { - return switch (arch) { - .sparc, .sparcel, .sparc64 => true, - else => false, - }; - } - - pub inline fn isSpirV(arch: Arch) bool { - return switch (arch) { - .spirv32, .spirv64 => true, - else => false, - }; - } - - pub inline fn isBpf(arch: Arch) bool { - return switch (arch) { - .bpfel, .bpfeb => true, - else => false, - }; - } - - pub inline fn isNvptx(arch: Arch) bool { - return switch (arch) { - .nvptx, .nvptx64 => true, - else => false, - }; - } - - pub fn parseCpuModel(arch: Arch, cpu_name: []const u8) !*const Cpu.Model { - for (arch.allCpuModels()) |cpu| { - if (mem.eql(u8, cpu_name, cpu.name)) { - return cpu; - } - } - return error.UnknownCpuModel; - } - - pub fn toElfMachine(arch: Arch) std.elf.EM { - return switch (arch) { - .avr => .AVR, - .msp430 => .MSP430, - .arc => .ARC, - .arm => .ARM, - .armeb => .ARM, - .hexagon => .HEXAGON, - .dxil => .NONE, - .m68k => .@"68K", - .le32 => .NONE, - .mips => .MIPS, - .mipsel => .MIPS_RS3_LE, - .powerpc, .powerpcle => .PPC, - .r600 => .NONE, - .riscv32 => .RISCV, - .sparc => .SPARC, - .sparcel => .SPARC, - .tce => .NONE, - .tcele => .NONE, - .thumb => .ARM, - .thumbeb => .ARM, - .x86 => .@"386", - .xcore => .XCORE, - .xtensa => .XTENSA, - .nvptx => .NONE, - .amdil => .NONE, - .hsail => .NONE, - .spir => .NONE, - .kalimba => .CSR_KALIMBA, - .shave => .NONE, - .lanai => .LANAI, - .wasm32 => .NONE, - .renderscript32 => .NONE, - .aarch64_32 => .AARCH64, - .aarch64 => .AARCH64, - .aarch64_be => .AARCH64, - .mips64 => .MIPS, - .mips64el => .MIPS_RS3_LE, - .powerpc64 => .PPC64, - .powerpc64le => .PPC64, - .riscv64 => .RISCV, - .x86_64 => .X86_64, - .nvptx64 => .NONE, - .le64 => .NONE, - .amdil64 => .NONE, - .hsail64 => .NONE, - .spir64 => .NONE, - .wasm64 => .NONE, - .renderscript64 => .NONE, - .amdgcn => .AMDGPU, - .bpfel => .BPF, - .bpfeb => .BPF, - .csky => .CSKY, - .sparc64 => .SPARCV9, - .s390x => .S390, - .ve => .NONE, - .spu_2 => .SPU_2, - .spirv32 => .NONE, - .spirv64 => .NONE, - .loongarch32 => .NONE, - .loongarch64 => .NONE, - }; - } - - pub fn toCoffMachine(arch: Arch) std.coff.MachineType { - return switch (arch) { - .avr => .Unknown, - .msp430 => .Unknown, - .arc => .Unknown, - .arm => .ARM, - .armeb => .Unknown, - .dxil => .Unknown, - .hexagon => .Unknown, - .m68k => .Unknown, - .le32 => .Unknown, - .mips => .Unknown, - .mipsel => .Unknown, - .powerpc, .powerpcle => .POWERPC, - .r600 => .Unknown, - .riscv32 => .RISCV32, - .sparc => .Unknown, - .sparcel => .Unknown, - .tce => .Unknown, - .tcele => .Unknown, - .thumb => .Thumb, - .thumbeb => .Thumb, - .x86 => .I386, - .xcore => .Unknown, - .xtensa => .Unknown, - .nvptx => .Unknown, - .amdil => .Unknown, - .hsail => .Unknown, - .spir => .Unknown, - .kalimba => .Unknown, - .shave => .Unknown, - .lanai => .Unknown, - .wasm32 => .Unknown, - .renderscript32 => .Unknown, - .aarch64_32 => .ARM64, - .aarch64 => .ARM64, - .aarch64_be => .ARM64, - .mips64 => .Unknown, - .mips64el => .Unknown, - .powerpc64 => .Unknown, - .powerpc64le => .Unknown, - .riscv64 => .RISCV64, - .x86_64 => .X64, - .nvptx64 => .Unknown, - .le64 => .Unknown, - .amdil64 => .Unknown, - .hsail64 => .Unknown, - .spir64 => .Unknown, - .wasm64 => .Unknown, - .renderscript64 => .Unknown, - .amdgcn => .Unknown, - .bpfel => .Unknown, - .bpfeb => .Unknown, - .csky => .Unknown, - .sparc64 => .Unknown, - .s390x => .Unknown, - .ve => .Unknown, - .spu_2 => .Unknown, - .spirv32 => .Unknown, - .spirv64 => .Unknown, - .loongarch32 => .Unknown, - .loongarch64 => .Unknown, - }; - } - - pub fn endian(arch: Arch) std.builtin.Endian { - return switch (arch) { - .avr, - .arm, - .aarch64_32, - .aarch64, - .amdgcn, - .amdil, - .amdil64, - .bpfel, - .csky, - .xtensa, - .hexagon, - .hsail, - .hsail64, - .kalimba, - .le32, - .le64, - .mipsel, - .mips64el, - .msp430, - .nvptx, - .nvptx64, - .sparcel, - .tcele, - .powerpcle, - .powerpc64le, - .r600, - .riscv32, - .riscv64, - .x86, - .x86_64, - .wasm32, - .wasm64, - .xcore, - .thumb, - .spir, - .spir64, - .renderscript32, - .renderscript64, - .shave, - .ve, - .spu_2, - // GPU bitness is opaque. For now, assume little endian. - .spirv32, - .spirv64, - .dxil, - .loongarch32, - .loongarch64, - .arc, - => .little, - - .armeb, - .aarch64_be, - .bpfeb, - .m68k, - .mips, - .mips64, - .powerpc, - .powerpc64, - .thumbeb, - .sparc, - .sparc64, - .tce, - .lanai, - .s390x, - => .big, - }; - } - - /// Returns whether this architecture supports the address space - pub fn supportsAddressSpace(arch: Arch, address_space: std.builtin.AddressSpace) bool { - const is_nvptx = arch == .nvptx or arch == .nvptx64; - const is_spirv = arch == .spirv32 or arch == .spirv64; - const is_gpu = is_nvptx or is_spirv or arch == .amdgcn; - return switch (address_space) { - .generic => true, - .fs, .gs, .ss => arch == .x86_64 or arch == .x86, - .global, .constant, .local, .shared => is_gpu, - .param => is_nvptx, - // TODO this should also check how many flash banks the cpu has - .flash, .flash1, .flash2, .flash3, .flash4, .flash5 => arch == .avr, - }; - } - - /// Returns a name that matches the lib/std/target/* source file name. - pub fn genericName(arch: Arch) []const u8 { - return switch (arch) { - .arm, .armeb, .thumb, .thumbeb => "arm", - .aarch64, .aarch64_be, .aarch64_32 => "aarch64", - .bpfel, .bpfeb => "bpf", - .loongarch32, .loongarch64 => "loongarch", - .mips, .mipsel, .mips64, .mips64el => "mips", - .powerpc, .powerpcle, .powerpc64, .powerpc64le => "powerpc", - .amdgcn => "amdgpu", - .riscv32, .riscv64 => "riscv", - .sparc, .sparc64, .sparcel => "sparc", - .s390x => "s390x", - .x86, .x86_64 => "x86", - .nvptx, .nvptx64 => "nvptx", - .wasm32, .wasm64 => "wasm", - .spirv32, .spirv64 => "spirv", - else => @tagName(arch), - }; - } - - /// All CPU features Zig is aware of, sorted lexicographically by name. - pub fn allFeaturesList(arch: Arch) []const Cpu.Feature { - return switch (arch) { - .arm, .armeb, .thumb, .thumbeb => &arm.all_features, - .aarch64, .aarch64_be, .aarch64_32 => &aarch64.all_features, - .arc => &arc.all_features, - .avr => &avr.all_features, - .bpfel, .bpfeb => &bpf.all_features, - .csky => &csky.all_features, - .hexagon => &hexagon.all_features, - .loongarch32, .loongarch64 => &loongarch.all_features, - .m68k => &m68k.all_features, - .mips, .mipsel, .mips64, .mips64el => &mips.all_features, - .msp430 => &msp430.all_features, - .powerpc, .powerpcle, .powerpc64, .powerpc64le => &powerpc.all_features, - .amdgcn => &amdgpu.all_features, - .riscv32, .riscv64 => &riscv.all_features, - .sparc, .sparc64, .sparcel => &sparc.all_features, - .spirv32, .spirv64 => &spirv.all_features, - .s390x => &s390x.all_features, - .x86, .x86_64 => &x86.all_features, - .xtensa => &xtensa.all_features, - .nvptx, .nvptx64 => &nvptx.all_features, - .ve => &ve.all_features, - .wasm32, .wasm64 => &wasm.all_features, - - else => &[0]Cpu.Feature{}, - }; - } - - /// All processors Zig is aware of, sorted lexicographically by name. - pub fn allCpuModels(arch: Arch) []const *const Cpu.Model { - return switch (arch) { - .arc => comptime allCpusFromDecls(arc.cpu), - .arm, .armeb, .thumb, .thumbeb => comptime allCpusFromDecls(arm.cpu), - .aarch64, .aarch64_be, .aarch64_32 => comptime allCpusFromDecls(aarch64.cpu), - .avr => comptime allCpusFromDecls(avr.cpu), - .bpfel, .bpfeb => comptime allCpusFromDecls(bpf.cpu), - .csky => comptime allCpusFromDecls(csky.cpu), - .hexagon => comptime allCpusFromDecls(hexagon.cpu), - .loongarch32, .loongarch64 => comptime allCpusFromDecls(loongarch.cpu), - .m68k => comptime allCpusFromDecls(m68k.cpu), - .mips, .mipsel, .mips64, .mips64el => comptime allCpusFromDecls(mips.cpu), - .msp430 => comptime allCpusFromDecls(msp430.cpu), - .powerpc, .powerpcle, .powerpc64, .powerpc64le => comptime allCpusFromDecls(powerpc.cpu), - .amdgcn => comptime allCpusFromDecls(amdgpu.cpu), - .riscv32, .riscv64 => comptime allCpusFromDecls(riscv.cpu), - .sparc, .sparc64, .sparcel => comptime allCpusFromDecls(sparc.cpu), - .spirv32, .spirv64 => comptime allCpusFromDecls(spirv.cpu), - .s390x => comptime allCpusFromDecls(s390x.cpu), - .x86, .x86_64 => comptime allCpusFromDecls(x86.cpu), - .xtensa => comptime allCpusFromDecls(xtensa.cpu), - .nvptx, .nvptx64 => comptime allCpusFromDecls(nvptx.cpu), - .ve => comptime allCpusFromDecls(ve.cpu), - .wasm32, .wasm64 => comptime allCpusFromDecls(wasm.cpu), - - else => &[0]*const Model{}, - }; - } - - fn allCpusFromDecls(comptime cpus: type) []const *const Cpu.Model { - const decls = @typeInfo(cpus).Struct.decls; - var array: [decls.len]*const Cpu.Model = undefined; - for (decls, 0..) |decl, i| { - array[i] = &@field(cpus, decl.name); - } - return &array; - } - }; - - pub const Model = struct { - name: []const u8, - llvm_name: ?[:0]const u8, - features: Feature.Set, - - pub fn toCpu(model: *const Model, arch: Arch) Cpu { - var features = model.features; - features.populateDependencies(arch.allFeaturesList()); - return .{ - .arch = arch, - .model = model, - .features = features, - }; - } - - pub fn generic(arch: Arch) *const Model { - const S = struct { - const generic_model = Model{ - .name = "generic", - .llvm_name = null, - .features = Cpu.Feature.Set.empty, - }; - }; - return switch (arch) { - .arm, .armeb, .thumb, .thumbeb => &arm.cpu.generic, - .aarch64, .aarch64_be, .aarch64_32 => &aarch64.cpu.generic, - .avr => &avr.cpu.avr2, - .bpfel, .bpfeb => &bpf.cpu.generic, - .hexagon => &hexagon.cpu.generic, - .loongarch32 => &loongarch.cpu.generic_la32, - .loongarch64 => &loongarch.cpu.generic_la64, - .m68k => &m68k.cpu.generic, - .mips, .mipsel => &mips.cpu.mips32, - .mips64, .mips64el => &mips.cpu.mips64, - .msp430 => &msp430.cpu.generic, - .powerpc => &powerpc.cpu.ppc, - .powerpcle => &powerpc.cpu.ppc, - .powerpc64 => &powerpc.cpu.ppc64, - .powerpc64le => &powerpc.cpu.ppc64le, - .amdgcn => &amdgpu.cpu.generic, - .riscv32 => &riscv.cpu.generic_rv32, - .riscv64 => &riscv.cpu.generic_rv64, - .spirv32, .spirv64 => &spirv.cpu.generic, - .sparc, .sparcel => &sparc.cpu.generic, - .sparc64 => &sparc.cpu.v9, // 64-bit SPARC needs v9 as the baseline - .s390x => &s390x.cpu.generic, - .x86 => &x86.cpu.i386, - .x86_64 => &x86.cpu.x86_64, - .nvptx, .nvptx64 => &nvptx.cpu.sm_20, - .ve => &ve.cpu.generic, - .wasm32, .wasm64 => &wasm.cpu.generic, - - else => &S.generic_model, - }; - } - - pub fn baseline(arch: Arch) *const Model { - return switch (arch) { - .arm, .armeb, .thumb, .thumbeb => &arm.cpu.baseline, - .riscv32 => &riscv.cpu.baseline_rv32, - .riscv64 => &riscv.cpu.baseline_rv64, - .x86 => &x86.cpu.pentium4, - .nvptx, .nvptx64 => &nvptx.cpu.sm_20, - .sparc, .sparcel => &sparc.cpu.v8, - - else => generic(arch), - }; - } - }; - - /// The "default" set of CPU features for cross-compiling. A conservative set - /// of features that is expected to be supported on most available hardware. - pub fn baseline(arch: Arch) Cpu { - return Model.baseline(arch).toCpu(arch); - } - }; - - pub fn zigTriple(self: Target, allocator: mem.Allocator) ![]u8 { - return std.zig.CrossTarget.fromTarget(self).zigTriple(allocator); - } - - pub fn linuxTripleSimple(allocator: mem.Allocator, cpu_arch: Cpu.Arch, os_tag: Os.Tag, abi: Abi) ![]u8 { - return std.fmt.allocPrint(allocator, "{s}-{s}-{s}", .{ @tagName(cpu_arch), @tagName(os_tag), @tagName(abi) }); - } - - pub fn linuxTriple(self: Target, allocator: mem.Allocator) ![]u8 { - return linuxTripleSimple(allocator, self.cpu.arch, self.os.tag, self.abi); - } - - pub fn exeFileExtSimple(cpu_arch: Cpu.Arch, os_tag: Os.Tag) [:0]const u8 { - return switch (os_tag) { - .windows => ".exe", - .uefi => ".efi", - .plan9 => plan9Ext(cpu_arch), - else => switch (cpu_arch) { - .wasm32, .wasm64 => ".wasm", - else => "", - }, - }; - } - - pub fn exeFileExt(self: Target) [:0]const u8 { - return exeFileExtSimple(self.cpu.arch, self.os.tag); - } - - pub fn staticLibSuffix_os_abi(os_tag: Os.Tag, abi: Abi) [:0]const u8 { - if (abi == .msvc) { - return ".lib"; - } - switch (os_tag) { - .windows, .uefi => return ".lib", - else => return ".a", - } - } - - pub fn staticLibSuffix(self: Target) [:0]const u8 { - return staticLibSuffix_os_abi(self.os.tag, self.abi); - } - - pub fn dynamicLibSuffix(self: Target) [:0]const u8 { - return self.os.tag.dynamicLibSuffix(); - } - - pub fn libPrefix_os_abi(os_tag: Os.Tag, abi: Abi) [:0]const u8 { - if (abi == .msvc) { - return ""; - } - switch (os_tag) { - .windows, .uefi => return "", - else => return "lib", - } - } - - pub fn libPrefix(self: Target) [:0]const u8 { - return libPrefix_os_abi(self.os.tag, self.abi); - } - - pub inline fn isMinGW(self: Target) bool { - return self.os.tag == .windows and self.isGnu(); - } - - pub inline fn isGnu(self: Target) bool { - return self.abi.isGnu(); - } - - pub inline fn isMusl(self: Target) bool { - return self.abi.isMusl(); - } - - pub inline fn isAndroid(self: Target) bool { - return self.abi == .android; - } - - pub inline fn isWasm(self: Target) bool { - return self.cpu.arch.isWasm(); - } - - pub inline fn isDarwin(self: Target) bool { - return self.os.tag.isDarwin(); - } - - pub inline fn isBSD(self: Target) bool { - return self.os.tag.isBSD(); - } - - pub inline fn isBpfFreestanding(self: Target) bool { - return self.cpu.arch.isBpf() and self.os.tag == .freestanding; - } - - pub inline fn isGnuLibC_os_tag_abi(os_tag: Os.Tag, abi: Abi) bool { - return os_tag == .linux and abi.isGnu(); - } - - pub inline fn isGnuLibC(self: Target) bool { - return isGnuLibC_os_tag_abi(self.os.tag, self.abi); - } - - pub inline fn supportsNewStackCall(self: Target) bool { - return !self.cpu.arch.isWasm(); - } - - pub inline fn isSpirV(self: Target) bool { - return self.cpu.arch.isSpirV(); - } - - pub const FloatAbi = enum { - hard, - soft, - }; - - pub inline fn getFloatAbi(self: Target) FloatAbi { - return self.abi.floatAbi(); - } - - pub inline fn hasDynamicLinker(self: Target) bool { - if (self.cpu.arch.isWasm()) { - return false; - } - switch (self.os.tag) { - .freestanding, - .ios, - .tvos, - .watchos, - .macos, - .uefi, - .windows, - .emscripten, - .opencl, - .glsl450, - .vulkan, - .plan9, - .other, - => return false, - else => return true, - } - } - - pub const DynamicLinker = struct { - /// Contains the memory used to store the dynamic linker path. This field should - /// not be used directly. See `get` and `set`. This field exists so that this API requires no allocator. - buffer: [255]u8 = undefined, - - /// Used to construct the dynamic linker path. This field should not be used - /// directly. See `get` and `set`. - max_byte: ?u8 = null, - - /// Asserts that the length is less than or equal to 255 bytes. - pub fn init(dl_or_null: ?[]const u8) DynamicLinker { - var result: DynamicLinker = undefined; - result.set(dl_or_null); - return result; - } - - /// The returned memory has the same lifetime as the `DynamicLinker`. - pub fn get(self: *const DynamicLinker) ?[]const u8 { - const m: usize = self.max_byte orelse return null; - return self.buffer[0 .. m + 1]; - } - - /// Asserts that the length is less than or equal to 255 bytes. - pub fn set(self: *DynamicLinker, dl_or_null: ?[]const u8) void { - if (dl_or_null) |dl| { - @memcpy(self.buffer[0..dl.len], dl); - self.max_byte = @as(u8, @intCast(dl.len - 1)); - } else { - self.max_byte = null; - } - } - }; - - pub fn standardDynamicLinkerPath(self: Target) DynamicLinker { - var result: DynamicLinker = .{}; - const S = struct { - fn print(r: *DynamicLinker, comptime fmt: []const u8, args: anytype) DynamicLinker { - r.max_byte = @as(u8, @intCast((std.fmt.bufPrint(&r.buffer, fmt, args) catch unreachable).len - 1)); - return r.*; - } - fn copy(r: *DynamicLinker, s: []const u8) DynamicLinker { - @memcpy(r.buffer[0..s.len], s); - r.max_byte = @as(u8, @intCast(s.len - 1)); - return r.*; - } - }; - const print = S.print; - const copy = S.copy; - - if (self.abi == .android) { - const suffix = if (self.ptrBitWidth() == 64) "64" else ""; - return print(&result, "/system/bin/linker{s}", .{suffix}); - } - - if (self.abi.isMusl()) { - const is_arm = switch (self.cpu.arch) { - .arm, .armeb, .thumb, .thumbeb => true, - else => false, - }; - const arch_part = switch (self.cpu.arch) { - .arm, .thumb => "arm", - .armeb, .thumbeb => "armeb", - else => |arch| @tagName(arch), - }; - const arch_suffix = if (is_arm and self.abi.floatAbi() == .hard) "hf" else ""; - return print(&result, "/lib/ld-musl-{s}{s}.so.1", .{ arch_part, arch_suffix }); - } - - switch (self.os.tag) { - .freebsd => return copy(&result, "/libexec/ld-elf.so.1"), - .netbsd => return copy(&result, "/libexec/ld.elf_so"), - .openbsd => return copy(&result, "/usr/libexec/ld.so"), - .dragonfly => return copy(&result, "/libexec/ld-elf.so.2"), - .solaris, .illumos => return copy(&result, "/lib/64/ld.so.1"), - .linux => switch (self.cpu.arch) { - .x86, - .sparc, - .sparcel, - => return copy(&result, "/lib/ld-linux.so.2"), - - .aarch64 => return copy(&result, "/lib/ld-linux-aarch64.so.1"), - .aarch64_be => return copy(&result, "/lib/ld-linux-aarch64_be.so.1"), - .aarch64_32 => return copy(&result, "/lib/ld-linux-aarch64_32.so.1"), - - .arm, - .armeb, - .thumb, - .thumbeb, - => return copy(&result, switch (self.abi.floatAbi()) { - .hard => "/lib/ld-linux-armhf.so.3", - else => "/lib/ld-linux.so.3", - }), - - .mips, - .mipsel, - .mips64, - .mips64el, - => { - const lib_suffix = switch (self.abi) { - .gnuabin32, .gnux32 => "32", - .gnuabi64 => "64", - else => "", - }; - const is_nan_2008 = mips.featureSetHas(self.cpu.features, .nan2008); - const loader = if (is_nan_2008) "ld-linux-mipsn8.so.1" else "ld.so.1"; - return print(&result, "/lib{s}/{s}", .{ lib_suffix, loader }); - }, - - .powerpc, .powerpcle => return copy(&result, "/lib/ld.so.1"), - .powerpc64, .powerpc64le => return copy(&result, "/lib64/ld64.so.2"), - .s390x => return copy(&result, "/lib64/ld64.so.1"), - .sparc64 => return copy(&result, "/lib64/ld-linux.so.2"), - .x86_64 => return copy(&result, switch (self.abi) { - .gnux32 => "/libx32/ld-linux-x32.so.2", - else => "/lib64/ld-linux-x86-64.so.2", - }), - - .riscv32 => return copy(&result, "/lib/ld-linux-riscv32-ilp32.so.1"), - .riscv64 => return copy(&result, "/lib/ld-linux-riscv64-lp64.so.1"), - - // Architectures in this list have been verified as not having a standard - // dynamic linker path. - .wasm32, - .wasm64, - .bpfel, - .bpfeb, - .nvptx, - .nvptx64, - .spu_2, - .avr, - .spirv32, - .spirv64, - => return result, - - // TODO go over each item in this list and either move it to the above list, or - // implement the standard dynamic linker path code for it. - .arc, - .csky, - .hexagon, - .m68k, - .msp430, - .r600, - .amdgcn, - .tce, - .tcele, - .xcore, - .le32, - .le64, - .amdil, - .amdil64, - .hsail, - .hsail64, - .spir, - .spir64, - .kalimba, - .shave, - .lanai, - .renderscript32, - .renderscript64, - .ve, - .dxil, - .loongarch32, - .loongarch64, - .xtensa, - => return result, - }, - - .ios, - .tvos, - .watchos, - .macos, - => return copy(&result, "/usr/lib/dyld"), - - // Operating systems in this list have been verified as not having a standard - // dynamic linker path. - .freestanding, - .uefi, - .windows, - .emscripten, - .wasi, - .opencl, - .glsl450, - .vulkan, - .other, - .plan9, - => return result, - - // TODO revisit when multi-arch for Haiku is available - .haiku => return copy(&result, "/system/runtime_loader"), - - // TODO go over each item in this list and either move it to the above list, or - // implement the standard dynamic linker path code for it. - .ananas, - .cloudabi, - .fuchsia, - .kfreebsd, - .lv2, - .zos, - .minix, - .rtems, - .nacl, - .aix, - .cuda, - .nvcl, - .amdhsa, - .ps4, - .ps5, - .elfiamcu, - .mesa3d, - .contiki, - .amdpal, - .hermit, - .hurd, - .driverkit, - .shadermodel, - .liteos, - => return result, - } - } - - /// 0c spim little-endian MIPS 3000 family - /// 1c 68000 Motorola MC68000 - /// 2c 68020 Motorola MC68020 - /// 5c arm little-endian ARM - /// 6c amd64 AMD64 and compatibles (e.g., Intel EM64T) - /// 7c arm64 ARM64 (ARMv8) - /// 8c 386 Intel x86, i486, Pentium, etc. - /// kc sparc Sun SPARC - /// qc power Power PC - /// vc mips big-endian MIPS 3000 family - pub fn plan9Ext(cpu_arch: Cpu.Arch) [:0]const u8 { - return switch (cpu_arch) { - .arm => ".5", - .x86_64 => ".6", - .aarch64 => ".7", - .x86 => ".8", - .sparc => ".k", - .powerpc, .powerpcle => ".q", - .mips, .mipsel => ".v", - // ISAs without designated characters get 'X' for lack of a better option. - else => ".X", - }; - } - - pub fn maxIntAlignment(target: Target) u16 { - return switch (target.cpu.arch) { - .avr => 1, - .msp430 => 2, - .xcore => 4, - - .arm, - .armeb, - .thumb, - .thumbeb, - .hexagon, - .mips, - .mipsel, - .powerpc, - .powerpcle, - .r600, - .amdgcn, - .riscv32, - .sparc, - .sparcel, - .s390x, - .lanai, - .wasm32, - .wasm64, - => 8, - - .x86 => if (target.ofmt == .c) 16 else return switch (target.os.tag) { - .windows, .uefi => 8, - else => 4, - }, - - // For these, LLVMABIAlignmentOfType(i128) reports 8. Note that 16 - // is a relevant number in three cases: - // 1. Different machine code instruction when loading into SIMD register. - // 2. The C ABI wants 16 for extern structs. - // 3. 16-byte cmpxchg needs 16-byte alignment. - // Same logic for powerpc64, mips64, sparc64. - .x86_64, - .powerpc64, - .powerpc64le, - .mips64, - .mips64el, - .sparc64, - => return switch (target.ofmt) { - .c => 16, - else => 8, - }, - - // Even LLVMABIAlignmentOfType(i128) agrees on these targets. - .aarch64, - .aarch64_be, - .aarch64_32, - .riscv64, - .bpfel, - .bpfeb, - .nvptx, - .nvptx64, - => 16, - - // Below this comment are unverified but based on the fact that C requires - // int128_t to be 16 bytes aligned, it's a safe default. - .spu_2, - .csky, - .arc, - .m68k, - .tce, - .tcele, - .le32, - .amdil, - .hsail, - .spir, - .kalimba, - .renderscript32, - .spirv32, - .shave, - .le64, - .amdil64, - .hsail64, - .spir64, - .renderscript64, - .ve, - .spirv64, - .dxil, - .loongarch32, - .loongarch64, - .xtensa, - => 16, - }; - } - - pub fn ptrBitWidth(target: Target) u16 { - switch (target.abi) { - .gnux32, .muslx32, .gnuabin32, .gnuilp32 => return 32, - .gnuabi64 => return 64, - else => {}, - } - switch (target.cpu.arch) { - .avr, - .msp430, - .spu_2, - => return 16, - - .arc, - .arm, - .armeb, - .csky, - .hexagon, - .m68k, - .le32, - .mips, - .mipsel, - .powerpc, - .powerpcle, - .r600, - .riscv32, - .sparcel, - .tce, - .tcele, - .thumb, - .thumbeb, - .x86, - .xcore, - .nvptx, - .amdil, - .hsail, - .spir, - .kalimba, - .shave, - .lanai, - .wasm32, - .renderscript32, - .aarch64_32, - .spirv32, - .loongarch32, - .dxil, - .xtensa, - => return 32, - - .aarch64, - .aarch64_be, - .mips64, - .mips64el, - .powerpc64, - .powerpc64le, - .riscv64, - .x86_64, - .nvptx64, - .le64, - .amdil64, - .hsail64, - .spir64, - .wasm64, - .renderscript64, - .amdgcn, - .bpfel, - .bpfeb, - .sparc64, - .s390x, - .ve, - .spirv64, - .loongarch64, - => return 64, - - .sparc => return if (std.Target.sparc.featureSetHas(target.cpu.features, .v9)) 64 else 32, - } - } - - pub fn stackAlignment(target: Target) u16 { - return switch (target.cpu.arch) { - .m68k => 2, - .amdgcn => 4, - .x86 => switch (target.os.tag) { - .windows, .uefi => 4, - else => 16, - }, - .arm, - .armeb, - .thumb, - .thumbeb, - .mips, - .mipsel, - .sparc, - .sparcel, - => 8, - .aarch64, - .aarch64_be, - .aarch64_32, - .bpfeb, - .bpfel, - .mips64, - .mips64el, - .riscv32, - .riscv64, - .sparc64, - .x86_64, - .ve, - .wasm32, - .wasm64, - => 16, - .powerpc64, - .powerpc64le, - => switch (target.os.tag) { - else => 8, - .linux => 16, - }, - else => @divExact(target.ptrBitWidth(), 8), - }; - } - - /// Default signedness of `char` for the native C compiler for this target - /// Note that char signedness is implementation-defined and many compilers provide - /// an option to override the default signedness e.g. GCC's -funsigned-char / -fsigned-char - pub fn charSignedness(target: Target) std.builtin.Signedness { - switch (target.cpu.arch) { - .aarch64, - .aarch64_32, - .aarch64_be, - .arm, - .armeb, - .thumb, - .thumbeb, - => return if (target.os.tag.isDarwin() or target.os.tag == .windows) .signed else .unsigned, - .powerpc, .powerpc64 => return if (target.os.tag.isDarwin()) .signed else .unsigned, - .powerpcle, - .powerpc64le, - .s390x, - .xcore, - .arc, - .msp430, - .riscv32, - .riscv64, - => return .unsigned, - else => return .signed, - } - } - - pub const CType = enum { - char, - short, - ushort, - int, - uint, - long, - ulong, - longlong, - ulonglong, - float, - double, - longdouble, - }; - - pub fn c_type_byte_size(t: Target, c_type: CType) u16 { - return switch (c_type) { - .char, - .short, - .ushort, - .int, - .uint, - .long, - .ulong, - .longlong, - .ulonglong, - .float, - .double, - => @divExact(c_type_bit_size(t, c_type), 8), - - .longdouble => switch (c_type_bit_size(t, c_type)) { - 16 => 2, - 32 => 4, - 64 => 8, - 80 => @as(u16, @intCast(mem.alignForward(usize, 10, c_type_alignment(t, .longdouble)))), - 128 => 16, - else => unreachable, - }, - }; - } - - pub fn c_type_bit_size(target: Target, c_type: CType) u16 { - switch (target.os.tag) { - .freestanding, .other => switch (target.cpu.arch) { - .msp430 => switch (c_type) { - .char => return 8, - .short, .ushort, .int, .uint => return 16, - .float, .long, .ulong => return 32, - .longlong, .ulonglong, .double, .longdouble => return 64, - }, - .avr => switch (c_type) { - .char => return 8, - .short, .ushort, .int, .uint => return 16, - .long, .ulong, .float, .double, .longdouble => return 32, - .longlong, .ulonglong => return 64, - }, - .tce, .tcele => switch (c_type) { - .char => return 8, - .short, .ushort => return 16, - .int, .uint, .long, .ulong, .longlong, .ulonglong => return 32, - .float, .double, .longdouble => return 32, - }, - .mips64, .mips64el => switch (c_type) { - .char => return 8, - .short, .ushort => return 16, - .int, .uint, .float => return 32, - .long, .ulong => return if (target.abi != .gnuabin32) 64 else 32, - .longlong, .ulonglong, .double => return 64, - .longdouble => return 128, - }, - .x86_64 => switch (c_type) { - .char => return 8, - .short, .ushort => return 16, - .int, .uint, .float => return 32, - .long, .ulong => switch (target.abi) { - .gnux32, .muslx32 => return 32, - else => return 64, - }, - .longlong, .ulonglong, .double => return 64, - .longdouble => return 80, - }, - else => switch (c_type) { - .char => return 8, - .short, .ushort => return 16, - .int, .uint, .float => return 32, - .long, .ulong => return target.ptrBitWidth(), - .longlong, .ulonglong, .double => return 64, - .longdouble => switch (target.cpu.arch) { - .x86 => switch (target.abi) { - .android => return 64, - else => return 80, - }, - - .powerpc, - .powerpcle, - .powerpc64, - .powerpc64le, - => switch (target.abi) { - .musl, - .musleabi, - .musleabihf, - .muslx32, - => return 64, - else => return 128, - }, - - .riscv32, - .riscv64, - .aarch64, - .aarch64_be, - .aarch64_32, - .s390x, - .sparc, - .sparc64, - .sparcel, - .wasm32, - .wasm64, - => return 128, - - else => return 64, - }, - }, - }, - - .linux, - .freebsd, - .netbsd, - .dragonfly, - .openbsd, - .wasi, - .emscripten, - .plan9, - .solaris, - .illumos, - .haiku, - .ananas, - .fuchsia, - .minix, - => switch (target.cpu.arch) { - .msp430 => switch (c_type) { - .char => return 8, - .short, .ushort, .int, .uint => return 16, - .long, .ulong, .float => return 32, - .longlong, .ulonglong, .double, .longdouble => return 64, - }, - .avr => switch (c_type) { - .char => return 8, - .short, .ushort, .int, .uint => return 16, - .long, .ulong, .float, .double, .longdouble => return 32, - .longlong, .ulonglong => return 64, - }, - .tce, .tcele => switch (c_type) { - .char => return 8, - .short, .ushort => return 16, - .int, .uint, .long, .ulong, .longlong, .ulonglong => return 32, - .float, .double, .longdouble => return 32, - }, - .mips64, .mips64el => switch (c_type) { - .char => return 8, - .short, .ushort => return 16, - .int, .uint, .float => return 32, - .long, .ulong => return if (target.abi != .gnuabin32) 64 else 32, - .longlong, .ulonglong, .double => return 64, - .longdouble => if (target.os.tag == .freebsd) return 64 else return 128, - }, - .x86_64 => switch (c_type) { - .char => return 8, - .short, .ushort => return 16, - .int, .uint, .float => return 32, - .long, .ulong => switch (target.abi) { - .gnux32, .muslx32 => return 32, - else => return 64, - }, - .longlong, .ulonglong, .double => return 64, - .longdouble => return 80, - }, - else => switch (c_type) { - .char => return 8, - .short, .ushort => return 16, - .int, .uint, .float => return 32, - .long, .ulong => return target.ptrBitWidth(), - .longlong, .ulonglong, .double => return 64, - .longdouble => switch (target.cpu.arch) { - .x86 => switch (target.abi) { - .android => return 64, - else => return 80, - }, - - .powerpc, - .powerpcle, - => switch (target.abi) { - .musl, - .musleabi, - .musleabihf, - .muslx32, - => return 64, - else => switch (target.os.tag) { - .freebsd, .netbsd, .openbsd => return 64, - else => return 128, - }, - }, - - .powerpc64, - .powerpc64le, - => switch (target.abi) { - .musl, - .musleabi, - .musleabihf, - .muslx32, - => return 64, - else => switch (target.os.tag) { - .freebsd, .openbsd => return 64, - else => return 128, - }, - }, - - .riscv32, - .riscv64, - .aarch64, - .aarch64_be, - .aarch64_32, - .s390x, - .mips64, - .mips64el, - .sparc, - .sparc64, - .sparcel, - .wasm32, - .wasm64, - => return 128, - - else => return 64, - }, - }, - }, - - .windows, .uefi => switch (target.cpu.arch) { - .x86 => switch (c_type) { - .char => return 8, - .short, .ushort => return 16, - .int, .uint, .float => return 32, - .long, .ulong => return 32, - .longlong, .ulonglong, .double => return 64, - .longdouble => switch (target.abi) { - .gnu, .gnuilp32, .cygnus => return 80, - else => return 64, - }, - }, - .x86_64 => switch (c_type) { - .char => return 8, - .short, .ushort => return 16, - .int, .uint, .float => return 32, - .long, .ulong => switch (target.abi) { - .cygnus => return 64, - else => return 32, - }, - .longlong, .ulonglong, .double => return 64, - .longdouble => switch (target.abi) { - .gnu, .gnuilp32, .cygnus => return 80, - else => return 64, - }, - }, - else => switch (c_type) { - .char => return 8, - .short, .ushort => return 16, - .int, .uint, .float => return 32, - .long, .ulong => return 32, - .longlong, .ulonglong, .double => return 64, - .longdouble => return 64, - }, - }, - - .macos, .ios, .tvos, .watchos => switch (c_type) { - .char => return 8, - .short, .ushort => return 16, - .int, .uint, .float => return 32, - .long, .ulong => switch (target.cpu.arch) { - .x86, .arm, .aarch64_32 => return 32, - .x86_64 => switch (target.abi) { - .gnux32, .muslx32 => return 32, - else => return 64, - }, - else => return 64, - }, - .longlong, .ulonglong, .double => return 64, - .longdouble => switch (target.cpu.arch) { - .x86 => switch (target.abi) { - .android => return 64, - else => return 80, - }, - .x86_64 => return 80, - else => return 64, - }, - }, - - .nvcl, .cuda => switch (c_type) { - .char => return 8, - .short, .ushort => return 16, - .int, .uint, .float => return 32, - .long, .ulong => switch (target.cpu.arch) { - .nvptx => return 32, - .nvptx64 => return 64, - else => return 64, - }, - .longlong, .ulonglong, .double => return 64, - .longdouble => return 64, - }, - - .amdhsa, .amdpal => switch (c_type) { - .char => return 8, - .short, .ushort => return 16, - .int, .uint, .float => return 32, - .long, .ulong, .longlong, .ulonglong, .double => return 64, - .longdouble => return 128, - }, - - .opencl => switch (c_type) { - .char => return 8, - .short, .ushort => return 16, - .int, .uint, .float => return 32, - .long, .ulong, .double => return 64, - .longlong, .ulonglong => return 128, - // Note: The OpenCL specification does not guarantee a particular size for long double, - // but clang uses 128 bits. - .longdouble => return 128, - }, - - .ps4, .ps5 => switch (c_type) { - .char => return 8, - .short, .ushort => return 16, - .int, .uint, .float => return 32, - .long, .ulong => return 64, - .longlong, .ulonglong, .double => return 64, - .longdouble => return 80, - }, - - .cloudabi, - .kfreebsd, - .lv2, - .zos, - .rtems, - .nacl, - .aix, - .elfiamcu, - .mesa3d, - .contiki, - .hermit, - .hurd, - .glsl450, - .vulkan, - .driverkit, - .shadermodel, - .liteos, - => @panic("TODO specify the C integer and float type sizes for this OS"), - } - } - - pub fn c_type_alignment(target: Target, c_type: CType) u16 { - // Overrides for unusual alignments - switch (target.cpu.arch) { - .avr => return 1, - .x86 => switch (target.os.tag) { - .windows, .uefi => switch (c_type) { - .longlong, .ulonglong, .double => return 8, - .longdouble => switch (target.abi) { - .gnu, .gnuilp32, .cygnus => return 4, - else => return 8, - }, - else => {}, - }, - else => {}, - }, - else => {}, - } - - // Next-power-of-two-aligned, up to a maximum. - return @min( - std.math.ceilPowerOfTwoAssert(u16, (c_type_bit_size(target, c_type) + 7) / 8), - switch (target.cpu.arch) { - .arm, .armeb, .thumb, .thumbeb => switch (target.os.tag) { - .netbsd => switch (target.abi) { - .gnueabi, - .gnueabihf, - .eabi, - .eabihf, - .android, - .musleabi, - .musleabihf, - => 8, - - else => @as(u16, 4), - }, - .ios, .tvos, .watchos => 4, - else => 8, - }, - - .msp430, - .avr, - => 2, - - .arc, - .csky, - .x86, - .xcore, - .dxil, - .loongarch32, - .tce, - .tcele, - .le32, - .amdil, - .hsail, - .spir, - .spirv32, - .kalimba, - .shave, - .renderscript32, - .ve, - .spu_2, - .xtensa, - => 4, - - .aarch64_32, - .amdgcn, - .amdil64, - .bpfel, - .bpfeb, - .hexagon, - .hsail64, - .loongarch64, - .m68k, - .mips, - .mipsel, - .sparc, - .sparcel, - .sparc64, - .lanai, - .le64, - .nvptx, - .nvptx64, - .r600, - .s390x, - .spir64, - .spirv64, - .renderscript64, - => 8, - - .aarch64, - .aarch64_be, - .mips64, - .mips64el, - .powerpc, - .powerpcle, - .powerpc64, - .powerpc64le, - .riscv32, - .riscv64, - .x86_64, - .wasm32, - .wasm64, - => 16, - }, - ); - } - - pub fn c_type_preferred_alignment(target: Target, c_type: CType) u16 { - // Overrides for unusual alignments - switch (target.cpu.arch) { - .arm, .armeb, .thumb, .thumbeb => switch (target.os.tag) { - .netbsd => switch (target.abi) { - .gnueabi, - .gnueabihf, - .eabi, - .eabihf, - .android, - .musleabi, - .musleabihf, - => {}, - - else => switch (c_type) { - .longdouble => return 4, - else => {}, - }, - }, - .ios, .tvos, .watchos => switch (c_type) { - .longdouble => return 4, - else => {}, - }, - else => {}, - }, - .arc => switch (c_type) { - .longdouble => return 4, - else => {}, - }, - .avr => switch (c_type) { - .char, .int, .uint, .long, .ulong, .float, .longdouble => return 1, - .short, .ushort => return 2, - .double => return 4, - .longlong, .ulonglong => return 8, - }, - .x86 => switch (target.os.tag) { - .windows, .uefi => switch (c_type) { - .longdouble => switch (target.abi) { - .gnu, .gnuilp32, .cygnus => return 4, - else => return 8, - }, - else => {}, - }, - else => switch (c_type) { - .longdouble => return 4, - else => {}, - }, - }, - else => {}, - } - - // Next-power-of-two-aligned, up to a maximum. - return @min( - std.math.ceilPowerOfTwoAssert(u16, (c_type_bit_size(target, c_type) + 7) / 8), - switch (target.cpu.arch) { - .msp430 => @as(u16, 2), - - .csky, - .xcore, - .dxil, - .loongarch32, - .tce, - .tcele, - .le32, - .amdil, - .hsail, - .spir, - .spirv32, - .kalimba, - .shave, - .renderscript32, - .ve, - .spu_2, - .xtensa, - => 4, - - .arc, - .arm, - .armeb, - .avr, - .thumb, - .thumbeb, - .aarch64_32, - .amdgcn, - .amdil64, - .bpfel, - .bpfeb, - .hexagon, - .hsail64, - .x86, - .loongarch64, - .m68k, - .mips, - .mipsel, - .sparc, - .sparcel, - .sparc64, - .lanai, - .le64, - .nvptx, - .nvptx64, - .r600, - .s390x, - .spir64, - .spirv64, - .renderscript64, - => 8, - - .aarch64, - .aarch64_be, - .mips64, - .mips64el, - .powerpc, - .powerpcle, - .powerpc64, - .powerpc64le, - .riscv32, - .riscv64, - .x86_64, - .wasm32, - .wasm64, - => 16, - }, - ); - } -}; - -test { - std.testing.refAllDecls(Target.Cpu.Arch); -} |
