Commit 67d48b94d6
Changed files (26)
lib/std/target/aarch64.zig → lib/std/Target/aarch64.zig
File renamed without changes
lib/std/target/amdgpu.zig → lib/std/Target/amdgpu.zig
File renamed without changes
lib/std/target/arc.zig → lib/std/Target/arc.zig
File renamed without changes
lib/std/target/arm.zig → lib/std/Target/arm.zig
File renamed without changes
lib/std/target/avr.zig → lib/std/Target/avr.zig
File renamed without changes
lib/std/target/bpf.zig → lib/std/Target/bpf.zig
File renamed without changes
lib/std/target/csky.zig → lib/std/Target/csky.zig
File renamed without changes
lib/std/target/hexagon.zig → lib/std/Target/hexagon.zig
File renamed without changes
lib/std/target/loongarch.zig → lib/std/Target/loongarch.zig
File renamed without changes
lib/std/target/m68k.zig → lib/std/Target/m68k.zig
File renamed without changes
lib/std/target/mips.zig → lib/std/Target/mips.zig
File renamed without changes
lib/std/target/msp430.zig → lib/std/Target/msp430.zig
File renamed without changes
lib/std/target/nvptx.zig → lib/std/Target/nvptx.zig
File renamed without changes
lib/std/target/powerpc.zig → lib/std/Target/powerpc.zig
File renamed without changes
lib/std/target/riscv.zig → lib/std/Target/riscv.zig
File renamed without changes
lib/std/target/s390x.zig → lib/std/Target/s390x.zig
File renamed without changes
lib/std/target/sparc.zig → lib/std/Target/sparc.zig
File renamed without changes
lib/std/target/spirv.zig → lib/std/Target/spirv.zig
File renamed without changes
lib/std/target/ve.zig → lib/std/Target/ve.zig
File renamed without changes
lib/std/target/wasm.zig → lib/std/Target/wasm.zig
File renamed without changes
lib/std/target/x86.zig → lib/std/Target/x86.zig
File renamed without changes
lib/std/target/xtensa.zig → lib/std/Target/xtensa.zig
File renamed without changes
lib/std/std.zig
@@ -47,7 +47,7 @@ pub const StringArrayHashMap = array_hash_map.StringArrayHashMap;
pub const StringArrayHashMapUnmanaged = array_hash_map.StringArrayHashMapUnmanaged;
/// deprecated: use `DoublyLinkedList`.
pub const TailQueue = DoublyLinkedList;
-pub const Target = @import("target.zig").Target;
+pub const Target = @import("Target.zig");
pub const Thread = @import("Thread.zig");
pub const Treap = @import("treap.zig").Treap;
pub const Tz = tz.Tz;
lib/std/Target.zig
@@ -0,0 +1,2696 @@
+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: std.SemanticVersion.Range,
+ glibc: std.SemanticVersion,
+
+ pub inline fn includesVersion(self: LinuxVersionRange, ver: std.SemanticVersion) 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: std.SemanticVersion) ?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: std.SemanticVersion.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 = std.SemanticVersion.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: std.SemanticVersion.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 = std.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 std.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 (std.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: Allocator) ![]u8 {
+ return std.zig.CrossTarget.fromTarget(self).zigTriple(allocator);
+}
+
+pub fn linuxTripleSimple(allocator: 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: 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(std.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,
+ },
+ );
+}
+
+pub fn is_libc_lib_name(target: std.Target, name: []const u8) bool {
+ const ignore_case = target.os.tag == .macos or target.os.tag == .windows;
+
+ if (eqlIgnoreCase(ignore_case, name, "c"))
+ return true;
+
+ if (target.isMinGW()) {
+ if (eqlIgnoreCase(ignore_case, name, "m"))
+ return true;
+ if (eqlIgnoreCase(ignore_case, name, "uuid"))
+ return true;
+ if (eqlIgnoreCase(ignore_case, name, "mingw32"))
+ return true;
+ if (eqlIgnoreCase(ignore_case, name, "msvcrt-os"))
+ return true;
+ if (eqlIgnoreCase(ignore_case, name, "mingwex"))
+ return true;
+
+ return false;
+ }
+
+ if (target.abi.isGnu() or target.abi.isMusl()) {
+ if (eqlIgnoreCase(ignore_case, name, "m"))
+ return true;
+ if (eqlIgnoreCase(ignore_case, name, "rt"))
+ return true;
+ if (eqlIgnoreCase(ignore_case, name, "pthread"))
+ return true;
+ if (eqlIgnoreCase(ignore_case, name, "util"))
+ return true;
+ if (eqlIgnoreCase(ignore_case, name, "xnet"))
+ return true;
+ if (eqlIgnoreCase(ignore_case, name, "resolv"))
+ return true;
+ if (eqlIgnoreCase(ignore_case, name, "dl"))
+ return true;
+ }
+
+ if (target.abi.isMusl()) {
+ if (eqlIgnoreCase(ignore_case, name, "crypt"))
+ return true;
+ }
+
+ if (target.os.tag.isDarwin()) {
+ if (eqlIgnoreCase(ignore_case, name, "System"))
+ return true;
+ if (eqlIgnoreCase(ignore_case, name, "c"))
+ return true;
+ if (eqlIgnoreCase(ignore_case, name, "dbm"))
+ return true;
+ if (eqlIgnoreCase(ignore_case, name, "dl"))
+ return true;
+ if (eqlIgnoreCase(ignore_case, name, "info"))
+ return true;
+ if (eqlIgnoreCase(ignore_case, name, "m"))
+ return true;
+ if (eqlIgnoreCase(ignore_case, name, "poll"))
+ return true;
+ if (eqlIgnoreCase(ignore_case, name, "proc"))
+ return true;
+ if (eqlIgnoreCase(ignore_case, name, "pthread"))
+ return true;
+ if (eqlIgnoreCase(ignore_case, name, "rpcsvc"))
+ return true;
+ }
+
+ if (target.os.isAtLeast(.macos, .{ .major = 10, .minor = 8, .patch = 0 }) orelse false) {
+ if (eqlIgnoreCase(ignore_case, name, "mx"))
+ return true;
+ }
+
+ return false;
+}
+
+pub fn is_libcpp_lib_name(target: std.Target, name: []const u8) bool {
+ const ignore_case = target.os.tag.isDarwin() or target.os.tag == .windows;
+
+ return eqlIgnoreCase(ignore_case, name, "c++") or
+ eqlIgnoreCase(ignore_case, name, "stdc++") or
+ eqlIgnoreCase(ignore_case, name, "c++abi");
+}
+
+fn eqlIgnoreCase(ignore_case: bool, a: []const u8, b: []const u8) bool {
+ if (ignore_case) {
+ return std.ascii.eqlIgnoreCase(a, b);
+ } else {
+ return std.mem.eql(u8, a, b);
+ }
+}
+
+const Target = @This();
+const std = @import("std.zig");
+const builtin = @import("builtin");
+const Allocator = std.mem.Allocator;
+
+test {
+ std.testing.refAllDecls(Cpu.Arch);
+}
lib/std/target.zig
@@ -1,2698 +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,
- },
- );
- }
-
- pub fn is_libc_lib_name(target: std.Target, name: []const u8) bool {
- const ignore_case = target.os.tag == .macos or target.os.tag == .windows;
-
- if (eqlIgnoreCase(ignore_case, name, "c"))
- return true;
-
- if (target.isMinGW()) {
- if (eqlIgnoreCase(ignore_case, name, "m"))
- return true;
- if (eqlIgnoreCase(ignore_case, name, "uuid"))
- return true;
- if (eqlIgnoreCase(ignore_case, name, "mingw32"))
- return true;
- if (eqlIgnoreCase(ignore_case, name, "msvcrt-os"))
- return true;
- if (eqlIgnoreCase(ignore_case, name, "mingwex"))
- return true;
-
- return false;
- }
-
- if (target.abi.isGnu() or target.abi.isMusl()) {
- if (eqlIgnoreCase(ignore_case, name, "m"))
- return true;
- if (eqlIgnoreCase(ignore_case, name, "rt"))
- return true;
- if (eqlIgnoreCase(ignore_case, name, "pthread"))
- return true;
- if (eqlIgnoreCase(ignore_case, name, "util"))
- return true;
- if (eqlIgnoreCase(ignore_case, name, "xnet"))
- return true;
- if (eqlIgnoreCase(ignore_case, name, "resolv"))
- return true;
- if (eqlIgnoreCase(ignore_case, name, "dl"))
- return true;
- }
-
- if (target.abi.isMusl()) {
- if (eqlIgnoreCase(ignore_case, name, "crypt"))
- return true;
- }
-
- if (target.os.tag.isDarwin()) {
- if (eqlIgnoreCase(ignore_case, name, "System"))
- return true;
- if (eqlIgnoreCase(ignore_case, name, "c"))
- return true;
- if (eqlIgnoreCase(ignore_case, name, "dbm"))
- return true;
- if (eqlIgnoreCase(ignore_case, name, "dl"))
- return true;
- if (eqlIgnoreCase(ignore_case, name, "info"))
- return true;
- if (eqlIgnoreCase(ignore_case, name, "m"))
- return true;
- if (eqlIgnoreCase(ignore_case, name, "poll"))
- return true;
- if (eqlIgnoreCase(ignore_case, name, "proc"))
- return true;
- if (eqlIgnoreCase(ignore_case, name, "pthread"))
- return true;
- if (eqlIgnoreCase(ignore_case, name, "rpcsvc"))
- return true;
- }
-
- if (target.os.isAtLeast(.macos, .{ .major = 10, .minor = 8, .patch = 0 }) orelse false) {
- if (eqlIgnoreCase(ignore_case, name, "mx"))
- return true;
- }
-
- return false;
- }
-
- pub fn is_libcpp_lib_name(target: std.Target, name: []const u8) bool {
- const ignore_case = target.os.tag.isDarwin() or target.os.tag == .windows;
-
- return eqlIgnoreCase(ignore_case, name, "c++") or
- eqlIgnoreCase(ignore_case, name, "stdc++") or
- eqlIgnoreCase(ignore_case, name, "c++abi");
- }
-};
-
-fn eqlIgnoreCase(ignore_case: bool, a: []const u8, b: []const u8) bool {
- if (ignore_case) {
- return std.ascii.eqlIgnoreCase(a, b);
- } else {
- return std.mem.eql(u8, a, b);
- }
-}
-
-test {
- std.testing.refAllDecls(Target.Cpu.Arch);
-}
CMakeLists.txt
@@ -480,22 +480,22 @@ set(ZIG_STAGE2_SOURCES
"${CMAKE_SOURCE_DIR}/lib/compiler_rt/unordtf2.zig"
"${CMAKE_SOURCE_DIR}/lib/std/start.zig"
"${CMAKE_SOURCE_DIR}/lib/std/std.zig"
- "${CMAKE_SOURCE_DIR}/lib/std/target.zig"
- "${CMAKE_SOURCE_DIR}/lib/std/target/aarch64.zig"
- "${CMAKE_SOURCE_DIR}/lib/std/target/amdgpu.zig"
- "${CMAKE_SOURCE_DIR}/lib/std/target/arm.zig"
- "${CMAKE_SOURCE_DIR}/lib/std/target/avr.zig"
- "${CMAKE_SOURCE_DIR}/lib/std/target/bpf.zig"
- "${CMAKE_SOURCE_DIR}/lib/std/target/hexagon.zig"
- "${CMAKE_SOURCE_DIR}/lib/std/target/mips.zig"
- "${CMAKE_SOURCE_DIR}/lib/std/target/msp430.zig"
- "${CMAKE_SOURCE_DIR}/lib/std/target/nvptx.zig"
- "${CMAKE_SOURCE_DIR}/lib/std/target/powerpc.zig"
- "${CMAKE_SOURCE_DIR}/lib/std/target/riscv.zig"
- "${CMAKE_SOURCE_DIR}/lib/std/target/sparc.zig"
- "${CMAKE_SOURCE_DIR}/lib/std/target/s390x.zig"
- "${CMAKE_SOURCE_DIR}/lib/std/target/wasm.zig"
- "${CMAKE_SOURCE_DIR}/lib/std/target/x86.zig"
+ "${CMAKE_SOURCE_DIR}/lib/std/Target.zig"
+ "${CMAKE_SOURCE_DIR}/lib/std/Target/aarch64.zig"
+ "${CMAKE_SOURCE_DIR}/lib/std/Target/amdgpu.zig"
+ "${CMAKE_SOURCE_DIR}/lib/std/Target/arm.zig"
+ "${CMAKE_SOURCE_DIR}/lib/std/Target/avr.zig"
+ "${CMAKE_SOURCE_DIR}/lib/std/Target/bpf.zig"
+ "${CMAKE_SOURCE_DIR}/lib/std/Target/hexagon.zig"
+ "${CMAKE_SOURCE_DIR}/lib/std/Target/mips.zig"
+ "${CMAKE_SOURCE_DIR}/lib/std/Target/msp430.zig"
+ "${CMAKE_SOURCE_DIR}/lib/std/Target/nvptx.zig"
+ "${CMAKE_SOURCE_DIR}/lib/std/Target/powerpc.zig"
+ "${CMAKE_SOURCE_DIR}/lib/std/Target/riscv.zig"
+ "${CMAKE_SOURCE_DIR}/lib/std/Target/sparc.zig"
+ "${CMAKE_SOURCE_DIR}/lib/std/Target/s390x.zig"
+ "${CMAKE_SOURCE_DIR}/lib/std/Target/wasm.zig"
+ "${CMAKE_SOURCE_DIR}/lib/std/Target/x86.zig"
"${CMAKE_SOURCE_DIR}/lib/std/Thread.zig"
"${CMAKE_SOURCE_DIR}/lib/std/Thread/Futex.zig"
"${CMAKE_SOURCE_DIR}/lib/std/Thread/Mutex.zig"