zig

fork of https://codeberg.org/ziglang/zig
Log | Files | Refs | README | LICENSE

blob e00a1c15 (88743B) - Raw


      1 const std = @import("std.zig");
      2 const builtin = @import("builtin");
      3 const mem = std.mem;
      4 const Version = std.SemanticVersion;
      5 
      6 /// TODO Nearly all the functions in this namespace would be
      7 /// better off if https://github.com/ziglang/zig/issues/425
      8 /// was solved.
      9 pub const Target = struct {
     10     cpu: Cpu,
     11     os: Os,
     12     abi: Abi,
     13     ofmt: ObjectFormat,
     14 
     15     pub const Os = struct {
     16         tag: Tag,
     17         version_range: VersionRange,
     18 
     19         pub const Tag = enum {
     20             freestanding,
     21             ananas,
     22             cloudabi,
     23             dragonfly,
     24             freebsd,
     25             fuchsia,
     26             ios,
     27             kfreebsd,
     28             linux,
     29             lv2,
     30             macos,
     31             netbsd,
     32             openbsd,
     33             solaris,
     34             windows,
     35             zos,
     36             haiku,
     37             minix,
     38             rtems,
     39             nacl,
     40             aix,
     41             cuda,
     42             nvcl,
     43             amdhsa,
     44             ps4,
     45             ps5,
     46             elfiamcu,
     47             tvos,
     48             watchos,
     49             driverkit,
     50             mesa3d,
     51             contiki,
     52             amdpal,
     53             hermit,
     54             hurd,
     55             wasi,
     56             emscripten,
     57             shadermodel,
     58             uefi,
     59             opencl,
     60             glsl450,
     61             vulkan,
     62             plan9,
     63             other,
     64 
     65             pub fn isDarwin(tag: Tag) bool {
     66                 return switch (tag) {
     67                     .ios, .macos, .watchos, .tvos => true,
     68                     else => false,
     69                 };
     70             }
     71 
     72             pub fn isBSD(tag: Tag) bool {
     73                 return tag.isDarwin() or switch (tag) {
     74                     .kfreebsd, .freebsd, .openbsd, .netbsd, .dragonfly => true,
     75                     else => false,
     76                 };
     77             }
     78 
     79             pub fn dynamicLibSuffix(tag: Tag) [:0]const u8 {
     80                 if (tag.isDarwin()) {
     81                     return ".dylib";
     82                 }
     83                 switch (tag) {
     84                     .windows => return ".dll",
     85                     else => return ".so",
     86                 }
     87             }
     88 
     89             pub fn defaultVersionRange(tag: Tag, arch: Cpu.Arch) Os {
     90                 return .{
     91                     .tag = tag,
     92                     .version_range = VersionRange.default(tag, arch),
     93                 };
     94             }
     95         };
     96 
     97         /// Based on NTDDI version constants from
     98         /// https://docs.microsoft.com/en-us/cpp/porting/modifying-winver-and-win32-winnt
     99         pub const WindowsVersion = enum(u32) {
    100             nt4 = 0x04000000,
    101             win2k = 0x05000000,
    102             xp = 0x05010000,
    103             ws2003 = 0x05020000,
    104             vista = 0x06000000,
    105             win7 = 0x06010000,
    106             win8 = 0x06020000,
    107             win8_1 = 0x06030000,
    108             win10 = 0x0A000000, //aka win10_th1
    109             win10_th2 = 0x0A000001,
    110             win10_rs1 = 0x0A000002,
    111             win10_rs2 = 0x0A000003,
    112             win10_rs3 = 0x0A000004,
    113             win10_rs4 = 0x0A000005,
    114             win10_rs5 = 0x0A000006,
    115             win10_19h1 = 0x0A000007,
    116             win10_vb = 0x0A000008, //aka win10_19h2
    117             win10_mn = 0x0A000009, //aka win10_20h1
    118             win10_fe = 0x0A00000A, //aka win10_20h2
    119             _,
    120 
    121             /// Latest Windows version that the Zig Standard Library is aware of
    122             pub const latest = WindowsVersion.win10_fe;
    123 
    124             /// Compared against build numbers reported by the runtime to distinguish win10 versions,
    125             /// where 0x0A000000 + index corresponds to the WindowsVersion u32 value.
    126             pub const known_win10_build_numbers = [_]u32{
    127                 10240, //win10 aka win10_th1
    128                 10586, //win10_th2
    129                 14393, //win10_rs1
    130                 15063, //win10_rs2
    131                 16299, //win10_rs3
    132                 17134, //win10_rs4
    133                 17763, //win10_rs5
    134                 18362, //win10_19h1
    135                 18363, //win10_vb aka win10_19h2
    136                 19041, //win10_mn aka win10_20h1
    137                 19042, //win10_fe aka win10_20h2
    138             };
    139 
    140             /// Returns whether the first version `self` is newer (greater) than or equal to the second version `ver`.
    141             pub fn isAtLeast(self: WindowsVersion, ver: WindowsVersion) bool {
    142                 return @intFromEnum(self) >= @intFromEnum(ver);
    143             }
    144 
    145             pub const Range = struct {
    146                 min: WindowsVersion,
    147                 max: WindowsVersion,
    148 
    149                 pub fn includesVersion(self: Range, ver: WindowsVersion) bool {
    150                     return @intFromEnum(ver) >= @intFromEnum(self.min) and @intFromEnum(ver) <= @intFromEnum(self.max);
    151                 }
    152 
    153                 /// Checks if system is guaranteed to be at least `version` or older than `version`.
    154                 /// Returns `null` if a runtime check is required.
    155                 pub fn isAtLeast(self: Range, ver: WindowsVersion) ?bool {
    156                     if (@intFromEnum(self.min) >= @intFromEnum(ver)) return true;
    157                     if (@intFromEnum(self.max) < @intFromEnum(ver)) return false;
    158                     return null;
    159                 }
    160             };
    161 
    162             /// This function is defined to serialize a Zig source code representation of this
    163             /// type, that, when parsed, will deserialize into the same data.
    164             pub fn format(
    165                 self: WindowsVersion,
    166                 comptime fmt: []const u8,
    167                 _: std.fmt.FormatOptions,
    168                 out_stream: anytype,
    169             ) !void {
    170                 if (comptime std.mem.eql(u8, fmt, "s")) {
    171                     if (@intFromEnum(self) >= @intFromEnum(WindowsVersion.nt4) and @intFromEnum(self) <= @intFromEnum(WindowsVersion.latest)) {
    172                         try std.fmt.format(out_stream, ".{s}", .{@tagName(self)});
    173                     } else {
    174                         // TODO this code path breaks zig triples, but it is used in `builtin`
    175                         try std.fmt.format(out_stream, "@enumFromInt(Target.Os.WindowsVersion, 0x{X:0>8})", .{@intFromEnum(self)});
    176                     }
    177                 } else if (fmt.len == 0) {
    178                     if (@intFromEnum(self) >= @intFromEnum(WindowsVersion.nt4) and @intFromEnum(self) <= @intFromEnum(WindowsVersion.latest)) {
    179                         try std.fmt.format(out_stream, "WindowsVersion.{s}", .{@tagName(self)});
    180                     } else {
    181                         try std.fmt.format(out_stream, "WindowsVersion(0x{X:0>8})", .{@intFromEnum(self)});
    182                     }
    183                 } else {
    184                     std.fmt.invalidFmtError(fmt, self);
    185                 }
    186             }
    187         };
    188 
    189         pub const LinuxVersionRange = struct {
    190             range: Version.Range,
    191             glibc: Version,
    192 
    193             pub fn includesVersion(self: LinuxVersionRange, ver: Version) bool {
    194                 return self.range.includesVersion(ver);
    195             }
    196 
    197             /// Checks if system is guaranteed to be at least `version` or older than `version`.
    198             /// Returns `null` if a runtime check is required.
    199             pub fn isAtLeast(self: LinuxVersionRange, ver: Version) ?bool {
    200                 return self.range.isAtLeast(ver);
    201             }
    202         };
    203 
    204         /// The version ranges here represent the minimum OS version to be supported
    205         /// and the maximum OS version to be supported. The default values represent
    206         /// the range that the Zig Standard Library bases its abstractions on.
    207         ///
    208         /// The minimum version of the range is the main setting to tweak for a target.
    209         /// Usually, the maximum target OS version will remain the default, which is
    210         /// the latest released version of the OS.
    211         ///
    212         /// To test at compile time if the target is guaranteed to support a given OS feature,
    213         /// one should check that the minimum version of the range is greater than or equal to
    214         /// the version the feature was introduced in.
    215         ///
    216         /// To test at compile time if the target certainly will not support a given OS feature,
    217         /// one should check that the maximum version of the range is less than the version the
    218         /// feature was introduced in.
    219         ///
    220         /// If neither of these cases apply, a runtime check should be used to determine if the
    221         /// target supports a given OS feature.
    222         ///
    223         /// Binaries built with a given maximum version will continue to function on newer
    224         /// operating system versions. However, such a binary may not take full advantage of the
    225         /// newer operating system APIs.
    226         ///
    227         /// See `Os.isAtLeast`.
    228         pub const VersionRange = union {
    229             none: void,
    230             semver: Version.Range,
    231             linux: LinuxVersionRange,
    232             windows: WindowsVersion.Range,
    233 
    234             /// The default `VersionRange` represents the range that the Zig Standard Library
    235             /// bases its abstractions on.
    236             pub fn default(tag: Tag, arch: Cpu.Arch) VersionRange {
    237                 switch (tag) {
    238                     .freestanding,
    239                     .ananas,
    240                     .cloudabi,
    241                     .fuchsia,
    242                     .kfreebsd,
    243                     .lv2,
    244                     .zos,
    245                     .haiku,
    246                     .minix,
    247                     .rtems,
    248                     .nacl,
    249                     .aix,
    250                     .cuda,
    251                     .nvcl,
    252                     .amdhsa,
    253                     .ps4,
    254                     .ps5,
    255                     .elfiamcu,
    256                     .mesa3d,
    257                     .contiki,
    258                     .amdpal,
    259                     .hermit,
    260                     .hurd,
    261                     .wasi,
    262                     .emscripten,
    263                     .driverkit,
    264                     .shadermodel,
    265                     .uefi,
    266                     .opencl, // TODO: OpenCL versions
    267                     .glsl450, // TODO: GLSL versions
    268                     .vulkan,
    269                     .plan9,
    270                     .other,
    271                     => return .{ .none = {} },
    272 
    273                     .freebsd => return .{
    274                         .semver = Version.Range{
    275                             .min = .{ .major = 12, .minor = 0, .patch = 0 },
    276                             .max = .{ .major = 13, .minor = 1, .patch = 0 },
    277                         },
    278                     },
    279                     .macos => return switch (arch) {
    280                         .aarch64 => VersionRange{
    281                             .semver = .{
    282                                 .min = .{ .major = 11, .minor = 7, .patch = 1 },
    283                                 .max = .{ .major = 13, .minor = 3, .patch = 0 },
    284                             },
    285                         },
    286                         .x86_64 => VersionRange{
    287                             .semver = .{
    288                                 .min = .{ .major = 11, .minor = 7, .patch = 1 },
    289                                 .max = .{ .major = 13, .minor = 3, .patch = 0 },
    290                             },
    291                         },
    292                         else => unreachable,
    293                     },
    294                     .ios => return .{
    295                         .semver = .{
    296                             .min = .{ .major = 12, .minor = 0, .patch = 0 },
    297                             .max = .{ .major = 13, .minor = 4, .patch = 0 },
    298                         },
    299                     },
    300                     .watchos => return .{
    301                         .semver = .{
    302                             .min = .{ .major = 6, .minor = 0, .patch = 0 },
    303                             .max = .{ .major = 6, .minor = 2, .patch = 0 },
    304                         },
    305                     },
    306                     .tvos => return .{
    307                         .semver = .{
    308                             .min = .{ .major = 13, .minor = 0, .patch = 0 },
    309                             .max = .{ .major = 13, .minor = 4, .patch = 0 },
    310                         },
    311                     },
    312                     .netbsd => return .{
    313                         .semver = .{
    314                             .min = .{ .major = 8, .minor = 0, .patch = 0 },
    315                             .max = .{ .major = 10, .minor = 0, .patch = 0 },
    316                         },
    317                     },
    318                     .openbsd => return .{
    319                         .semver = .{
    320                             .min = .{ .major = 6, .minor = 8, .patch = 0 },
    321                             .max = .{ .major = 7, .minor = 2, .patch = 0 },
    322                         },
    323                     },
    324                     .dragonfly => return .{
    325                         .semver = .{
    326                             .min = .{ .major = 5, .minor = 8, .patch = 0 },
    327                             .max = .{ .major = 6, .minor = 4, .patch = 0 },
    328                         },
    329                     },
    330                     .solaris => return .{
    331                         .semver = .{
    332                             .min = .{ .major = 5, .minor = 11, .patch = 0 },
    333                             .max = .{ .major = 5, .minor = 11, .patch = 0 },
    334                         },
    335                     },
    336 
    337                     .linux => return .{
    338                         .linux = .{
    339                             .range = .{
    340                                 .min = .{ .major = 3, .minor = 16, .patch = 0 },
    341                                 .max = .{ .major = 5, .minor = 10, .patch = 81 },
    342                             },
    343                             .glibc = .{ .major = 2, .minor = 19, .patch = 0 },
    344                         },
    345                     },
    346 
    347                     .windows => return .{
    348                         .windows = .{
    349                             .min = .win8_1,
    350                             .max = WindowsVersion.latest,
    351                         },
    352                     },
    353                 }
    354             }
    355         };
    356 
    357         pub const TaggedVersionRange = union(enum) {
    358             none: void,
    359             semver: Version.Range,
    360             linux: LinuxVersionRange,
    361             windows: WindowsVersion.Range,
    362         };
    363 
    364         /// Provides a tagged union. `Target` does not store the tag because it is
    365         /// redundant with the OS tag; this function abstracts that part away.
    366         pub fn getVersionRange(self: Os) TaggedVersionRange {
    367             switch (self.tag) {
    368                 .linux => return TaggedVersionRange{ .linux = self.version_range.linux },
    369                 .windows => return TaggedVersionRange{ .windows = self.version_range.windows },
    370 
    371                 .freebsd,
    372                 .macos,
    373                 .ios,
    374                 .tvos,
    375                 .watchos,
    376                 .netbsd,
    377                 .openbsd,
    378                 .dragonfly,
    379                 .solaris,
    380                 => return TaggedVersionRange{ .semver = self.version_range.semver },
    381 
    382                 else => return .none,
    383             }
    384         }
    385 
    386         /// Checks if system is guaranteed to be at least `version` or older than `version`.
    387         /// Returns `null` if a runtime check is required.
    388         pub fn isAtLeast(self: Os, comptime tag: Tag, version: anytype) ?bool {
    389             if (self.tag != tag) return false;
    390 
    391             return switch (tag) {
    392                 .linux => self.version_range.linux.isAtLeast(version),
    393                 .windows => self.version_range.windows.isAtLeast(version),
    394                 else => self.version_range.semver.isAtLeast(version),
    395             };
    396         }
    397 
    398         /// On Darwin, we always link libSystem which contains libc.
    399         /// Similarly on FreeBSD and NetBSD we always link system libc
    400         /// since this is the stable syscall interface.
    401         pub fn requiresLibC(os: Os) bool {
    402             return switch (os.tag) {
    403                 .freebsd,
    404                 .netbsd,
    405                 .macos,
    406                 .ios,
    407                 .tvos,
    408                 .watchos,
    409                 .dragonfly,
    410                 .openbsd,
    411                 .haiku,
    412                 .solaris,
    413                 => true,
    414 
    415                 .linux,
    416                 .windows,
    417                 .freestanding,
    418                 .ananas,
    419                 .cloudabi,
    420                 .fuchsia,
    421                 .kfreebsd,
    422                 .lv2,
    423                 .zos,
    424                 .minix,
    425                 .rtems,
    426                 .nacl,
    427                 .aix,
    428                 .cuda,
    429                 .nvcl,
    430                 .amdhsa,
    431                 .ps4,
    432                 .ps5,
    433                 .elfiamcu,
    434                 .mesa3d,
    435                 .contiki,
    436                 .amdpal,
    437                 .hermit,
    438                 .hurd,
    439                 .wasi,
    440                 .emscripten,
    441                 .driverkit,
    442                 .shadermodel,
    443                 .uefi,
    444                 .opencl,
    445                 .glsl450,
    446                 .vulkan,
    447                 .plan9,
    448                 .other,
    449                 => false,
    450             };
    451         }
    452     };
    453 
    454     pub const aarch64 = @import("target/aarch64.zig");
    455     pub const arc = @import("target/arc.zig");
    456     pub const amdgpu = @import("target/amdgpu.zig");
    457     pub const arm = @import("target/arm.zig");
    458     pub const avr = @import("target/avr.zig");
    459     pub const bpf = @import("target/bpf.zig");
    460     pub const csky = @import("target/csky.zig");
    461     pub const hexagon = @import("target/hexagon.zig");
    462     pub const loongarch = @import("target/loongarch.zig");
    463     pub const m68k = @import("target/m68k.zig");
    464     pub const mips = @import("target/mips.zig");
    465     pub const msp430 = @import("target/msp430.zig");
    466     pub const nvptx = @import("target/nvptx.zig");
    467     pub const powerpc = @import("target/powerpc.zig");
    468     pub const riscv = @import("target/riscv.zig");
    469     pub const sparc = @import("target/sparc.zig");
    470     pub const spirv = @import("target/spirv.zig");
    471     pub const s390x = @import("target/s390x.zig");
    472     pub const ve = @import("target/ve.zig");
    473     pub const wasm = @import("target/wasm.zig");
    474     pub const x86 = @import("target/x86.zig");
    475     pub const xtensa = @import("target/xtensa.zig");
    476 
    477     pub const Abi = enum {
    478         none,
    479         gnu,
    480         gnuabin32,
    481         gnuabi64,
    482         gnueabi,
    483         gnueabihf,
    484         gnuf32,
    485         gnuf64,
    486         gnusf,
    487         gnux32,
    488         gnuilp32,
    489         code16,
    490         eabi,
    491         eabihf,
    492         android,
    493         musl,
    494         musleabi,
    495         musleabihf,
    496         muslx32,
    497         msvc,
    498         itanium,
    499         cygnus,
    500         coreclr,
    501         simulator,
    502         macabi,
    503         pixel,
    504         vertex,
    505         geometry,
    506         hull,
    507         domain,
    508         compute,
    509         library,
    510         raygeneration,
    511         intersection,
    512         anyhit,
    513         closesthit,
    514         miss,
    515         callable,
    516         mesh,
    517         amplification,
    518 
    519         pub fn default(arch: Cpu.Arch, target_os: Os) Abi {
    520             if (arch.isWasm()) {
    521                 return .musl;
    522             }
    523             switch (target_os.tag) {
    524                 .freestanding,
    525                 .ananas,
    526                 .cloudabi,
    527                 .dragonfly,
    528                 .lv2,
    529                 .solaris,
    530                 .zos,
    531                 .minix,
    532                 .rtems,
    533                 .nacl,
    534                 .aix,
    535                 .cuda,
    536                 .nvcl,
    537                 .amdhsa,
    538                 .ps4,
    539                 .ps5,
    540                 .elfiamcu,
    541                 .mesa3d,
    542                 .contiki,
    543                 .amdpal,
    544                 .hermit,
    545                 .other,
    546                 => return .eabi,
    547                 .openbsd,
    548                 .freebsd,
    549                 .fuchsia,
    550                 .kfreebsd,
    551                 .netbsd,
    552                 .hurd,
    553                 .haiku,
    554                 .windows,
    555                 => return .gnu,
    556                 .uefi => return .msvc,
    557                 .linux,
    558                 .wasi,
    559                 .emscripten,
    560                 => return .musl,
    561                 .opencl, // TODO: SPIR-V ABIs with Linkage capability
    562                 .glsl450,
    563                 .vulkan,
    564                 .plan9, // TODO specify abi
    565                 .macos,
    566                 .ios,
    567                 .tvos,
    568                 .watchos,
    569                 .driverkit,
    570                 .shadermodel,
    571                 => return .none,
    572             }
    573         }
    574 
    575         pub fn isGnu(abi: Abi) bool {
    576             return switch (abi) {
    577                 .gnu, .gnuabin32, .gnuabi64, .gnueabi, .gnueabihf, .gnux32 => true,
    578                 else => false,
    579             };
    580         }
    581 
    582         pub fn isMusl(abi: Abi) bool {
    583             return switch (abi) {
    584                 .musl, .musleabi, .musleabihf => true,
    585                 else => false,
    586             };
    587         }
    588 
    589         pub fn floatAbi(abi: Abi) FloatAbi {
    590             return switch (abi) {
    591                 .gnueabihf,
    592                 .eabihf,
    593                 .musleabihf,
    594                 => .hard,
    595                 else => .soft,
    596             };
    597         }
    598     };
    599 
    600     pub const ObjectFormat = enum {
    601         /// Common Object File Format (Windows)
    602         coff,
    603         /// DirectX Container
    604         dxcontainer,
    605         /// Executable and Linking Format
    606         elf,
    607         /// macOS relocatables
    608         macho,
    609         /// Standard, Portable Intermediate Representation V
    610         spirv,
    611         /// WebAssembly
    612         wasm,
    613         /// C source code
    614         c,
    615         /// Intel IHEX
    616         hex,
    617         /// Machine code with no metadata.
    618         raw,
    619         /// Plan 9 from Bell Labs
    620         plan9,
    621         /// Nvidia PTX format
    622         nvptx,
    623 
    624         pub fn fileExt(of: ObjectFormat, cpu_arch: Cpu.Arch) [:0]const u8 {
    625             return switch (of) {
    626                 .coff => ".obj",
    627                 .elf, .macho, .wasm => ".o",
    628                 .c => ".c",
    629                 .spirv => ".spv",
    630                 .hex => ".ihex",
    631                 .raw => ".bin",
    632                 .plan9 => plan9Ext(cpu_arch),
    633                 .nvptx => ".ptx",
    634                 .dxcontainer => ".dxil",
    635             };
    636         }
    637 
    638         pub fn default(os_tag: Os.Tag, cpu_arch: Cpu.Arch) ObjectFormat {
    639             return switch (os_tag) {
    640                 .windows, .uefi => .coff,
    641                 .ios, .macos, .watchos, .tvos => .macho,
    642                 .plan9 => .plan9,
    643                 else => return switch (cpu_arch) {
    644                     .wasm32, .wasm64 => .wasm,
    645                     .spirv32, .spirv64 => .spirv,
    646                     .nvptx, .nvptx64 => .nvptx,
    647                     else => .elf,
    648                 },
    649             };
    650         }
    651     };
    652 
    653     pub const SubSystem = enum {
    654         Console,
    655         Windows,
    656         Posix,
    657         Native,
    658         EfiApplication,
    659         EfiBootServiceDriver,
    660         EfiRom,
    661         EfiRuntimeDriver,
    662     };
    663 
    664     pub const Cpu = struct {
    665         /// Architecture
    666         arch: Arch,
    667 
    668         /// The CPU model to target. It has a set of features
    669         /// which are overridden with the `features` field.
    670         model: *const Model,
    671 
    672         /// An explicit list of the entire CPU feature set. It may differ from the specific CPU model's features.
    673         features: Feature.Set,
    674 
    675         pub const Feature = struct {
    676             /// The bit index into `Set`. Has a default value of `undefined` because the canonical
    677             /// structures are populated via comptime logic.
    678             index: Set.Index = undefined,
    679 
    680             /// Has a default value of `undefined` because the canonical
    681             /// structures are populated via comptime logic.
    682             name: []const u8 = undefined,
    683 
    684             /// If this corresponds to an LLVM-recognized feature, this will be populated;
    685             /// otherwise null.
    686             llvm_name: ?[:0]const u8,
    687 
    688             /// Human-friendly UTF-8 text.
    689             description: []const u8,
    690 
    691             /// Sparse `Set` of features this depends on.
    692             dependencies: Set,
    693 
    694             /// A bit set of all the features.
    695             pub const Set = struct {
    696                 ints: [usize_count]usize,
    697 
    698                 pub const needed_bit_count = 288;
    699                 pub const byte_count = (needed_bit_count + 7) / 8;
    700                 pub const usize_count = (byte_count + (@sizeOf(usize) - 1)) / @sizeOf(usize);
    701                 pub const Index = std.math.Log2Int(std.meta.Int(.unsigned, usize_count * @bitSizeOf(usize)));
    702                 pub const ShiftInt = std.math.Log2Int(usize);
    703 
    704                 pub const empty = Set{ .ints = [1]usize{0} ** usize_count };
    705 
    706                 pub fn isEmpty(set: Set) bool {
    707                     return for (set.ints) |x| {
    708                         if (x != 0) break false;
    709                     } else true;
    710                 }
    711 
    712                 pub fn isEnabled(set: Set, arch_feature_index: Index) bool {
    713                     const usize_index = arch_feature_index / @bitSizeOf(usize);
    714                     const bit_index = @as(ShiftInt, @intCast(arch_feature_index % @bitSizeOf(usize)));
    715                     return (set.ints[usize_index] & (@as(usize, 1) << bit_index)) != 0;
    716                 }
    717 
    718                 /// Adds the specified feature but not its dependencies.
    719                 pub fn addFeature(set: *Set, arch_feature_index: Index) void {
    720                     const usize_index = arch_feature_index / @bitSizeOf(usize);
    721                     const bit_index = @as(ShiftInt, @intCast(arch_feature_index % @bitSizeOf(usize)));
    722                     set.ints[usize_index] |= @as(usize, 1) << bit_index;
    723                 }
    724 
    725                 /// Adds the specified feature set but not its dependencies.
    726                 pub fn addFeatureSet(set: *Set, other_set: Set) void {
    727                     set.ints = @as(@Vector(usize_count, usize), set.ints) | @as(@Vector(usize_count, usize), other_set.ints);
    728                 }
    729 
    730                 /// Removes the specified feature but not its dependents.
    731                 pub fn removeFeature(set: *Set, arch_feature_index: Index) void {
    732                     const usize_index = arch_feature_index / @bitSizeOf(usize);
    733                     const bit_index = @as(ShiftInt, @intCast(arch_feature_index % @bitSizeOf(usize)));
    734                     set.ints[usize_index] &= ~(@as(usize, 1) << bit_index);
    735                 }
    736 
    737                 /// Removes the specified feature but not its dependents.
    738                 pub fn removeFeatureSet(set: *Set, other_set: Set) void {
    739                     set.ints = @as(@Vector(usize_count, usize), set.ints) & ~@as(@Vector(usize_count, usize), other_set.ints);
    740                 }
    741 
    742                 pub fn populateDependencies(set: *Set, all_features_list: []const Cpu.Feature) void {
    743                     @setEvalBranchQuota(1000000);
    744 
    745                     var old = set.ints;
    746                     while (true) {
    747                         for (all_features_list, 0..) |feature, index_usize| {
    748                             const index = @as(Index, @intCast(index_usize));
    749                             if (set.isEnabled(index)) {
    750                                 set.addFeatureSet(feature.dependencies);
    751                             }
    752                         }
    753                         const nothing_changed = mem.eql(usize, &old, &set.ints);
    754                         if (nothing_changed) return;
    755                         old = set.ints;
    756                     }
    757                 }
    758 
    759                 pub fn asBytes(set: *const Set) *const [byte_count]u8 {
    760                     return @as(*const [byte_count]u8, @ptrCast(&set.ints));
    761                 }
    762 
    763                 pub fn eql(set: Set, other_set: Set) bool {
    764                     return mem.eql(usize, &set.ints, &other_set.ints);
    765                 }
    766 
    767                 pub fn isSuperSetOf(set: Set, other_set: Set) bool {
    768                     const V = @Vector(usize_count, usize);
    769                     const set_v: V = set.ints;
    770                     const other_v: V = other_set.ints;
    771                     return @reduce(.And, (set_v & other_v) == other_v);
    772                 }
    773             };
    774 
    775             pub fn feature_set_fns(comptime F: type) type {
    776                 return struct {
    777                     /// Populates only the feature bits specified.
    778                     pub fn featureSet(features: []const F) Set {
    779                         var x = Set.empty;
    780                         for (features) |feature| {
    781                             x.addFeature(@intFromEnum(feature));
    782                         }
    783                         return x;
    784                     }
    785 
    786                     /// Returns true if the specified feature is enabled.
    787                     pub fn featureSetHas(set: Set, feature: F) bool {
    788                         return set.isEnabled(@intFromEnum(feature));
    789                     }
    790 
    791                     /// Returns true if any specified feature is enabled.
    792                     pub fn featureSetHasAny(set: Set, features: anytype) bool {
    793                         comptime std.debug.assert(std.meta.trait.isIndexable(@TypeOf(features)));
    794                         inline for (features) |feature| {
    795                             if (set.isEnabled(@intFromEnum(@as(F, feature)))) return true;
    796                         }
    797                         return false;
    798                     }
    799 
    800                     /// Returns true if every specified feature is enabled.
    801                     pub fn featureSetHasAll(set: Set, features: anytype) bool {
    802                         comptime std.debug.assert(std.meta.trait.isIndexable(@TypeOf(features)));
    803                         inline for (features) |feature| {
    804                             if (!set.isEnabled(@intFromEnum(@as(F, feature)))) return false;
    805                         }
    806                         return true;
    807                     }
    808                 };
    809             }
    810         };
    811 
    812         pub const Arch = enum {
    813             arm,
    814             armeb,
    815             aarch64,
    816             aarch64_be,
    817             aarch64_32,
    818             arc,
    819             avr,
    820             bpfel,
    821             bpfeb,
    822             csky,
    823             dxil,
    824             hexagon,
    825             loongarch32,
    826             loongarch64,
    827             m68k,
    828             mips,
    829             mipsel,
    830             mips64,
    831             mips64el,
    832             msp430,
    833             powerpc,
    834             powerpcle,
    835             powerpc64,
    836             powerpc64le,
    837             r600,
    838             amdgcn,
    839             riscv32,
    840             riscv64,
    841             sparc,
    842             sparc64,
    843             sparcel,
    844             s390x,
    845             tce,
    846             tcele,
    847             thumb,
    848             thumbeb,
    849             x86,
    850             x86_64,
    851             xcore,
    852             xtensa,
    853             nvptx,
    854             nvptx64,
    855             le32,
    856             le64,
    857             amdil,
    858             amdil64,
    859             hsail,
    860             hsail64,
    861             spir,
    862             spir64,
    863             spirv32,
    864             spirv64,
    865             kalimba,
    866             shave,
    867             lanai,
    868             wasm32,
    869             wasm64,
    870             renderscript32,
    871             renderscript64,
    872             ve,
    873             // Stage1 currently assumes that architectures above this comment
    874             // map one-to-one with the ZigLLVM_ArchType enum.
    875             spu_2,
    876 
    877             pub fn isX86(arch: Arch) bool {
    878                 return switch (arch) {
    879                     .x86, .x86_64 => true,
    880                     else => false,
    881                 };
    882             }
    883 
    884             pub fn isARM(arch: Arch) bool {
    885                 return switch (arch) {
    886                     .arm, .armeb => true,
    887                     else => false,
    888                 };
    889             }
    890 
    891             pub fn isAARCH64(arch: Arch) bool {
    892                 return switch (arch) {
    893                     .aarch64, .aarch64_be, .aarch64_32 => true,
    894                     else => false,
    895                 };
    896             }
    897 
    898             pub fn isThumb(arch: Arch) bool {
    899                 return switch (arch) {
    900                     .thumb, .thumbeb => true,
    901                     else => false,
    902                 };
    903             }
    904 
    905             pub fn isWasm(arch: Arch) bool {
    906                 return switch (arch) {
    907                     .wasm32, .wasm64 => true,
    908                     else => false,
    909                 };
    910             }
    911 
    912             pub fn isRISCV(arch: Arch) bool {
    913                 return switch (arch) {
    914                     .riscv32, .riscv64 => true,
    915                     else => false,
    916                 };
    917             }
    918 
    919             pub fn isMIPS(arch: Arch) bool {
    920                 return switch (arch) {
    921                     .mips, .mipsel, .mips64, .mips64el => true,
    922                     else => false,
    923                 };
    924             }
    925 
    926             pub fn isPPC(arch: Arch) bool {
    927                 return switch (arch) {
    928                     .powerpc, .powerpcle => true,
    929                     else => false,
    930                 };
    931             }
    932 
    933             pub fn isPPC64(arch: Arch) bool {
    934                 return switch (arch) {
    935                     .powerpc64, .powerpc64le => true,
    936                     else => false,
    937                 };
    938             }
    939 
    940             pub fn isSPARC(arch: Arch) bool {
    941                 return switch (arch) {
    942                     .sparc, .sparcel, .sparc64 => true,
    943                     else => false,
    944                 };
    945             }
    946 
    947             pub fn isSpirV(arch: Arch) bool {
    948                 return switch (arch) {
    949                     .spirv32, .spirv64 => true,
    950                     else => false,
    951                 };
    952             }
    953 
    954             pub fn isBpf(arch: Arch) bool {
    955                 return switch (arch) {
    956                     .bpfel, .bpfeb => true,
    957                     else => false,
    958                 };
    959             }
    960 
    961             pub fn isNvptx(arch: Arch) bool {
    962                 return switch (arch) {
    963                     .nvptx, .nvptx64 => true,
    964                     else => false,
    965                 };
    966             }
    967 
    968             pub fn parseCpuModel(arch: Arch, cpu_name: []const u8) !*const Cpu.Model {
    969                 for (arch.allCpuModels()) |cpu| {
    970                     if (mem.eql(u8, cpu_name, cpu.name)) {
    971                         return cpu;
    972                     }
    973                 }
    974                 return error.UnknownCpuModel;
    975             }
    976 
    977             pub fn toElfMachine(arch: Arch) std.elf.EM {
    978                 return switch (arch) {
    979                     .avr => .AVR,
    980                     .msp430 => .MSP430,
    981                     .arc => .ARC,
    982                     .arm => .ARM,
    983                     .armeb => .ARM,
    984                     .hexagon => .HEXAGON,
    985                     .dxil => .NONE,
    986                     .m68k => .@"68K",
    987                     .le32 => .NONE,
    988                     .mips => .MIPS,
    989                     .mipsel => .MIPS_RS3_LE,
    990                     .powerpc, .powerpcle => .PPC,
    991                     .r600 => .NONE,
    992                     .riscv32 => .RISCV,
    993                     .sparc => .SPARC,
    994                     .sparcel => .SPARC,
    995                     .tce => .NONE,
    996                     .tcele => .NONE,
    997                     .thumb => .ARM,
    998                     .thumbeb => .ARM,
    999                     .x86 => .@"386",
   1000                     .xcore => .XCORE,
   1001                     .xtensa => .XTENSA,
   1002                     .nvptx => .NONE,
   1003                     .amdil => .NONE,
   1004                     .hsail => .NONE,
   1005                     .spir => .NONE,
   1006                     .kalimba => .CSR_KALIMBA,
   1007                     .shave => .NONE,
   1008                     .lanai => .LANAI,
   1009                     .wasm32 => .NONE,
   1010                     .renderscript32 => .NONE,
   1011                     .aarch64_32 => .AARCH64,
   1012                     .aarch64 => .AARCH64,
   1013                     .aarch64_be => .AARCH64,
   1014                     .mips64 => .MIPS,
   1015                     .mips64el => .MIPS_RS3_LE,
   1016                     .powerpc64 => .PPC64,
   1017                     .powerpc64le => .PPC64,
   1018                     .riscv64 => .RISCV,
   1019                     .x86_64 => .X86_64,
   1020                     .nvptx64 => .NONE,
   1021                     .le64 => .NONE,
   1022                     .amdil64 => .NONE,
   1023                     .hsail64 => .NONE,
   1024                     .spir64 => .NONE,
   1025                     .wasm64 => .NONE,
   1026                     .renderscript64 => .NONE,
   1027                     .amdgcn => .AMDGPU,
   1028                     .bpfel => .BPF,
   1029                     .bpfeb => .BPF,
   1030                     .csky => .CSKY,
   1031                     .sparc64 => .SPARCV9,
   1032                     .s390x => .S390,
   1033                     .ve => .NONE,
   1034                     .spu_2 => .SPU_2,
   1035                     .spirv32 => .NONE,
   1036                     .spirv64 => .NONE,
   1037                     .loongarch32 => .NONE,
   1038                     .loongarch64 => .NONE,
   1039                 };
   1040             }
   1041 
   1042             pub fn toCoffMachine(arch: Arch) std.coff.MachineType {
   1043                 return switch (arch) {
   1044                     .avr => .Unknown,
   1045                     .msp430 => .Unknown,
   1046                     .arc => .Unknown,
   1047                     .arm => .ARM,
   1048                     .armeb => .Unknown,
   1049                     .dxil => .Unknown,
   1050                     .hexagon => .Unknown,
   1051                     .m68k => .Unknown,
   1052                     .le32 => .Unknown,
   1053                     .mips => .Unknown,
   1054                     .mipsel => .Unknown,
   1055                     .powerpc, .powerpcle => .POWERPC,
   1056                     .r600 => .Unknown,
   1057                     .riscv32 => .RISCV32,
   1058                     .sparc => .Unknown,
   1059                     .sparcel => .Unknown,
   1060                     .tce => .Unknown,
   1061                     .tcele => .Unknown,
   1062                     .thumb => .Thumb,
   1063                     .thumbeb => .Thumb,
   1064                     .x86 => .I386,
   1065                     .xcore => .Unknown,
   1066                     .xtensa => .Unknown,
   1067                     .nvptx => .Unknown,
   1068                     .amdil => .Unknown,
   1069                     .hsail => .Unknown,
   1070                     .spir => .Unknown,
   1071                     .kalimba => .Unknown,
   1072                     .shave => .Unknown,
   1073                     .lanai => .Unknown,
   1074                     .wasm32 => .Unknown,
   1075                     .renderscript32 => .Unknown,
   1076                     .aarch64_32 => .ARM64,
   1077                     .aarch64 => .ARM64,
   1078                     .aarch64_be => .ARM64,
   1079                     .mips64 => .Unknown,
   1080                     .mips64el => .Unknown,
   1081                     .powerpc64 => .Unknown,
   1082                     .powerpc64le => .Unknown,
   1083                     .riscv64 => .RISCV64,
   1084                     .x86_64 => .X64,
   1085                     .nvptx64 => .Unknown,
   1086                     .le64 => .Unknown,
   1087                     .amdil64 => .Unknown,
   1088                     .hsail64 => .Unknown,
   1089                     .spir64 => .Unknown,
   1090                     .wasm64 => .Unknown,
   1091                     .renderscript64 => .Unknown,
   1092                     .amdgcn => .Unknown,
   1093                     .bpfel => .Unknown,
   1094                     .bpfeb => .Unknown,
   1095                     .csky => .Unknown,
   1096                     .sparc64 => .Unknown,
   1097                     .s390x => .Unknown,
   1098                     .ve => .Unknown,
   1099                     .spu_2 => .Unknown,
   1100                     .spirv32 => .Unknown,
   1101                     .spirv64 => .Unknown,
   1102                     .loongarch32 => .Unknown,
   1103                     .loongarch64 => .Unknown,
   1104                 };
   1105             }
   1106 
   1107             pub fn endian(arch: Arch) std.builtin.Endian {
   1108                 return switch (arch) {
   1109                     .avr,
   1110                     .arm,
   1111                     .aarch64_32,
   1112                     .aarch64,
   1113                     .amdgcn,
   1114                     .amdil,
   1115                     .amdil64,
   1116                     .bpfel,
   1117                     .csky,
   1118                     .xtensa,
   1119                     .hexagon,
   1120                     .hsail,
   1121                     .hsail64,
   1122                     .kalimba,
   1123                     .le32,
   1124                     .le64,
   1125                     .mipsel,
   1126                     .mips64el,
   1127                     .msp430,
   1128                     .nvptx,
   1129                     .nvptx64,
   1130                     .sparcel,
   1131                     .tcele,
   1132                     .powerpcle,
   1133                     .powerpc64le,
   1134                     .r600,
   1135                     .riscv32,
   1136                     .riscv64,
   1137                     .x86,
   1138                     .x86_64,
   1139                     .wasm32,
   1140                     .wasm64,
   1141                     .xcore,
   1142                     .thumb,
   1143                     .spir,
   1144                     .spir64,
   1145                     .renderscript32,
   1146                     .renderscript64,
   1147                     .shave,
   1148                     .ve,
   1149                     .spu_2,
   1150                     // GPU bitness is opaque. For now, assume little endian.
   1151                     .spirv32,
   1152                     .spirv64,
   1153                     .dxil,
   1154                     .loongarch32,
   1155                     .loongarch64,
   1156                     => .Little,
   1157 
   1158                     .arc,
   1159                     .armeb,
   1160                     .aarch64_be,
   1161                     .bpfeb,
   1162                     .m68k,
   1163                     .mips,
   1164                     .mips64,
   1165                     .powerpc,
   1166                     .powerpc64,
   1167                     .thumbeb,
   1168                     .sparc,
   1169                     .sparc64,
   1170                     .tce,
   1171                     .lanai,
   1172                     .s390x,
   1173                     => .Big,
   1174                 };
   1175             }
   1176 
   1177             /// Returns whether this architecture supports the address space
   1178             pub fn supportsAddressSpace(arch: Arch, address_space: std.builtin.AddressSpace) bool {
   1179                 const is_nvptx = arch == .nvptx or arch == .nvptx64;
   1180                 const is_spirv = arch == .spirv32 or arch == .spirv64;
   1181                 const is_gpu = is_nvptx or is_spirv or arch == .amdgcn;
   1182                 return switch (address_space) {
   1183                     .generic => true,
   1184                     .fs, .gs, .ss => arch == .x86_64 or arch == .x86,
   1185                     .global, .constant, .local, .shared => is_gpu,
   1186                     .param => is_nvptx,
   1187                     // TODO this should also check how many flash banks the cpu has
   1188                     .flash, .flash1, .flash2, .flash3, .flash4, .flash5 => arch == .avr,
   1189                 };
   1190             }
   1191 
   1192             /// Returns a name that matches the lib/std/target/* source file name.
   1193             pub fn genericName(arch: Arch) []const u8 {
   1194                 return switch (arch) {
   1195                     .arm, .armeb, .thumb, .thumbeb => "arm",
   1196                     .aarch64, .aarch64_be, .aarch64_32 => "aarch64",
   1197                     .bpfel, .bpfeb => "bpf",
   1198                     .loongarch32, .loongarch64 => "loongarch",
   1199                     .mips, .mipsel, .mips64, .mips64el => "mips",
   1200                     .powerpc, .powerpcle, .powerpc64, .powerpc64le => "powerpc",
   1201                     .amdgcn => "amdgpu",
   1202                     .riscv32, .riscv64 => "riscv",
   1203                     .sparc, .sparc64, .sparcel => "sparc",
   1204                     .s390x => "s390x",
   1205                     .x86, .x86_64 => "x86",
   1206                     .nvptx, .nvptx64 => "nvptx",
   1207                     .wasm32, .wasm64 => "wasm",
   1208                     .spirv32, .spirv64 => "spirv",
   1209                     else => @tagName(arch),
   1210                 };
   1211             }
   1212 
   1213             /// All CPU features Zig is aware of, sorted lexicographically by name.
   1214             pub fn allFeaturesList(arch: Arch) []const Cpu.Feature {
   1215                 return switch (arch) {
   1216                     .arm, .armeb, .thumb, .thumbeb => &arm.all_features,
   1217                     .aarch64, .aarch64_be, .aarch64_32 => &aarch64.all_features,
   1218                     .arc => &arc.all_features,
   1219                     .avr => &avr.all_features,
   1220                     .bpfel, .bpfeb => &bpf.all_features,
   1221                     .csky => &csky.all_features,
   1222                     .hexagon => &hexagon.all_features,
   1223                     .loongarch32, .loongarch64 => &loongarch.all_features,
   1224                     .m68k => &m68k.all_features,
   1225                     .mips, .mipsel, .mips64, .mips64el => &mips.all_features,
   1226                     .msp430 => &msp430.all_features,
   1227                     .powerpc, .powerpcle, .powerpc64, .powerpc64le => &powerpc.all_features,
   1228                     .amdgcn => &amdgpu.all_features,
   1229                     .riscv32, .riscv64 => &riscv.all_features,
   1230                     .sparc, .sparc64, .sparcel => &sparc.all_features,
   1231                     .spirv32, .spirv64 => &spirv.all_features,
   1232                     .s390x => &s390x.all_features,
   1233                     .x86, .x86_64 => &x86.all_features,
   1234                     .xtensa => &xtensa.all_features,
   1235                     .nvptx, .nvptx64 => &nvptx.all_features,
   1236                     .ve => &ve.all_features,
   1237                     .wasm32, .wasm64 => &wasm.all_features,
   1238 
   1239                     else => &[0]Cpu.Feature{},
   1240                 };
   1241             }
   1242 
   1243             /// All processors Zig is aware of, sorted lexicographically by name.
   1244             pub fn allCpuModels(arch: Arch) []const *const Cpu.Model {
   1245                 return switch (arch) {
   1246                     .arc => comptime allCpusFromDecls(arc.cpu),
   1247                     .arm, .armeb, .thumb, .thumbeb => comptime allCpusFromDecls(arm.cpu),
   1248                     .aarch64, .aarch64_be, .aarch64_32 => comptime allCpusFromDecls(aarch64.cpu),
   1249                     .avr => comptime allCpusFromDecls(avr.cpu),
   1250                     .bpfel, .bpfeb => comptime allCpusFromDecls(bpf.cpu),
   1251                     .csky => comptime allCpusFromDecls(csky.cpu),
   1252                     .hexagon => comptime allCpusFromDecls(hexagon.cpu),
   1253                     .loongarch32, .loongarch64 => comptime allCpusFromDecls(loongarch.cpu),
   1254                     .m68k => comptime allCpusFromDecls(m68k.cpu),
   1255                     .mips, .mipsel, .mips64, .mips64el => comptime allCpusFromDecls(mips.cpu),
   1256                     .msp430 => comptime allCpusFromDecls(msp430.cpu),
   1257                     .powerpc, .powerpcle, .powerpc64, .powerpc64le => comptime allCpusFromDecls(powerpc.cpu),
   1258                     .amdgcn => comptime allCpusFromDecls(amdgpu.cpu),
   1259                     .riscv32, .riscv64 => comptime allCpusFromDecls(riscv.cpu),
   1260                     .sparc, .sparc64, .sparcel => comptime allCpusFromDecls(sparc.cpu),
   1261                     .spirv32, .spirv64 => comptime allCpusFromDecls(spirv.cpu),
   1262                     .s390x => comptime allCpusFromDecls(s390x.cpu),
   1263                     .x86, .x86_64 => comptime allCpusFromDecls(x86.cpu),
   1264                     .xtensa => comptime allCpusFromDecls(xtensa.cpu),
   1265                     .nvptx, .nvptx64 => comptime allCpusFromDecls(nvptx.cpu),
   1266                     .ve => comptime allCpusFromDecls(ve.cpu),
   1267                     .wasm32, .wasm64 => comptime allCpusFromDecls(wasm.cpu),
   1268 
   1269                     else => &[0]*const Model{},
   1270                 };
   1271             }
   1272 
   1273             fn allCpusFromDecls(comptime cpus: type) []const *const Cpu.Model {
   1274                 const decls = @typeInfo(cpus).Struct.decls;
   1275                 var array: [decls.len]*const Cpu.Model = undefined;
   1276                 for (decls, 0..) |decl, i| {
   1277                     array[i] = &@field(cpus, decl.name);
   1278                 }
   1279                 return &array;
   1280             }
   1281         };
   1282 
   1283         pub const Model = struct {
   1284             name: []const u8,
   1285             llvm_name: ?[:0]const u8,
   1286             features: Feature.Set,
   1287 
   1288             pub fn toCpu(model: *const Model, arch: Arch) Cpu {
   1289                 var features = model.features;
   1290                 features.populateDependencies(arch.allFeaturesList());
   1291                 return .{
   1292                     .arch = arch,
   1293                     .model = model,
   1294                     .features = features,
   1295                 };
   1296             }
   1297 
   1298             pub fn generic(arch: Arch) *const Model {
   1299                 const S = struct {
   1300                     const generic_model = Model{
   1301                         .name = "generic",
   1302                         .llvm_name = null,
   1303                         .features = Cpu.Feature.Set.empty,
   1304                     };
   1305                 };
   1306                 return switch (arch) {
   1307                     .arm, .armeb, .thumb, .thumbeb => &arm.cpu.generic,
   1308                     .aarch64, .aarch64_be, .aarch64_32 => &aarch64.cpu.generic,
   1309                     .avr => &avr.cpu.avr2,
   1310                     .bpfel, .bpfeb => &bpf.cpu.generic,
   1311                     .hexagon => &hexagon.cpu.generic,
   1312                     .loongarch32 => &loongarch.cpu.generic_la32,
   1313                     .loongarch64 => &loongarch.cpu.generic_la64,
   1314                     .m68k => &m68k.cpu.generic,
   1315                     .mips, .mipsel => &mips.cpu.mips32,
   1316                     .mips64, .mips64el => &mips.cpu.mips64,
   1317                     .msp430 => &msp430.cpu.generic,
   1318                     .powerpc => &powerpc.cpu.ppc,
   1319                     .powerpcle => &powerpc.cpu.ppc,
   1320                     .powerpc64 => &powerpc.cpu.ppc64,
   1321                     .powerpc64le => &powerpc.cpu.ppc64le,
   1322                     .amdgcn => &amdgpu.cpu.generic,
   1323                     .riscv32 => &riscv.cpu.generic_rv32,
   1324                     .riscv64 => &riscv.cpu.generic_rv64,
   1325                     .spirv32, .spirv64 => &spirv.cpu.generic,
   1326                     .sparc, .sparcel => &sparc.cpu.generic,
   1327                     .sparc64 => &sparc.cpu.v9, // 64-bit SPARC needs v9 as the baseline
   1328                     .s390x => &s390x.cpu.generic,
   1329                     .x86 => &x86.cpu.i386,
   1330                     .x86_64 => &x86.cpu.x86_64,
   1331                     .nvptx, .nvptx64 => &nvptx.cpu.sm_20,
   1332                     .ve => &ve.cpu.generic,
   1333                     .wasm32, .wasm64 => &wasm.cpu.generic,
   1334 
   1335                     else => &S.generic_model,
   1336                 };
   1337             }
   1338 
   1339             pub fn baseline(arch: Arch) *const Model {
   1340                 return switch (arch) {
   1341                     .arm, .armeb, .thumb, .thumbeb => &arm.cpu.baseline,
   1342                     .riscv32 => &riscv.cpu.baseline_rv32,
   1343                     .riscv64 => &riscv.cpu.baseline_rv64,
   1344                     .x86 => &x86.cpu.pentium4,
   1345                     .nvptx, .nvptx64 => &nvptx.cpu.sm_20,
   1346                     .sparc, .sparcel => &sparc.cpu.v8,
   1347 
   1348                     else => generic(arch),
   1349                 };
   1350             }
   1351         };
   1352 
   1353         /// The "default" set of CPU features for cross-compiling. A conservative set
   1354         /// of features that is expected to be supported on most available hardware.
   1355         pub fn baseline(arch: Arch) Cpu {
   1356             return Model.baseline(arch).toCpu(arch);
   1357         }
   1358     };
   1359 
   1360     pub fn zigTriple(self: Target, allocator: mem.Allocator) ![]u8 {
   1361         return std.zig.CrossTarget.fromTarget(self).zigTriple(allocator);
   1362     }
   1363 
   1364     pub fn linuxTripleSimple(allocator: mem.Allocator, cpu_arch: Cpu.Arch, os_tag: Os.Tag, abi: Abi) ![]u8 {
   1365         return std.fmt.allocPrint(allocator, "{s}-{s}-{s}", .{ @tagName(cpu_arch), @tagName(os_tag), @tagName(abi) });
   1366     }
   1367 
   1368     pub fn linuxTriple(self: Target, allocator: mem.Allocator) ![]u8 {
   1369         return linuxTripleSimple(allocator, self.cpu.arch, self.os.tag, self.abi);
   1370     }
   1371 
   1372     pub fn exeFileExtSimple(cpu_arch: Cpu.Arch, os_tag: Os.Tag) [:0]const u8 {
   1373         return switch (os_tag) {
   1374             .windows => ".exe",
   1375             .uefi => ".efi",
   1376             .plan9 => plan9Ext(cpu_arch),
   1377             else => switch (cpu_arch) {
   1378                 .wasm32, .wasm64 => ".wasm",
   1379                 else => "",
   1380             },
   1381         };
   1382     }
   1383 
   1384     pub fn exeFileExt(self: Target) [:0]const u8 {
   1385         return exeFileExtSimple(self.cpu.arch, self.os.tag);
   1386     }
   1387 
   1388     pub fn staticLibSuffix_os_abi(os_tag: Os.Tag, abi: Abi) [:0]const u8 {
   1389         if (abi == .msvc) {
   1390             return ".lib";
   1391         }
   1392         switch (os_tag) {
   1393             .windows, .uefi => return ".lib",
   1394             else => return ".a",
   1395         }
   1396     }
   1397 
   1398     pub fn staticLibSuffix(self: Target) [:0]const u8 {
   1399         return staticLibSuffix_os_abi(self.os.tag, self.abi);
   1400     }
   1401 
   1402     pub fn dynamicLibSuffix(self: Target) [:0]const u8 {
   1403         return self.os.tag.dynamicLibSuffix();
   1404     }
   1405 
   1406     pub fn libPrefix_os_abi(os_tag: Os.Tag, abi: Abi) [:0]const u8 {
   1407         if (abi == .msvc) {
   1408             return "";
   1409         }
   1410         switch (os_tag) {
   1411             .windows, .uefi => return "",
   1412             else => return "lib",
   1413         }
   1414     }
   1415 
   1416     pub fn libPrefix(self: Target) [:0]const u8 {
   1417         return libPrefix_os_abi(self.os.tag, self.abi);
   1418     }
   1419 
   1420     pub fn isMinGW(self: Target) bool {
   1421         return self.os.tag == .windows and self.isGnu();
   1422     }
   1423 
   1424     pub fn isGnu(self: Target) bool {
   1425         return self.abi.isGnu();
   1426     }
   1427 
   1428     pub fn isMusl(self: Target) bool {
   1429         return self.abi.isMusl();
   1430     }
   1431 
   1432     pub fn isAndroid(self: Target) bool {
   1433         return self.abi == .android;
   1434     }
   1435 
   1436     pub fn isWasm(self: Target) bool {
   1437         return self.cpu.arch.isWasm();
   1438     }
   1439 
   1440     pub fn isDarwin(self: Target) bool {
   1441         return self.os.tag.isDarwin();
   1442     }
   1443 
   1444     pub fn isBSD(self: Target) bool {
   1445         return self.os.tag.isBSD();
   1446     }
   1447 
   1448     pub fn isBpfFreestanding(self: Target) bool {
   1449         return self.cpu.arch.isBpf() and self.os.tag == .freestanding;
   1450     }
   1451 
   1452     pub fn isGnuLibC_os_tag_abi(os_tag: Os.Tag, abi: Abi) bool {
   1453         return os_tag == .linux and abi.isGnu();
   1454     }
   1455 
   1456     pub fn isGnuLibC(self: Target) bool {
   1457         return isGnuLibC_os_tag_abi(self.os.tag, self.abi);
   1458     }
   1459 
   1460     pub fn supportsNewStackCall(self: Target) bool {
   1461         return !self.cpu.arch.isWasm();
   1462     }
   1463 
   1464     pub fn isSpirV(self: Target) bool {
   1465         return self.cpu.arch.isSpirV();
   1466     }
   1467 
   1468     pub const FloatAbi = enum {
   1469         hard,
   1470         soft,
   1471         soft_fp,
   1472     };
   1473 
   1474     pub fn getFloatAbi(self: Target) FloatAbi {
   1475         return self.abi.floatAbi();
   1476     }
   1477 
   1478     pub fn hasDynamicLinker(self: Target) bool {
   1479         if (self.cpu.arch.isWasm()) {
   1480             return false;
   1481         }
   1482         switch (self.os.tag) {
   1483             .freestanding,
   1484             .ios,
   1485             .tvos,
   1486             .watchos,
   1487             .macos,
   1488             .uefi,
   1489             .windows,
   1490             .emscripten,
   1491             .opencl,
   1492             .glsl450,
   1493             .vulkan,
   1494             .plan9,
   1495             .other,
   1496             => return false,
   1497             else => return true,
   1498         }
   1499     }
   1500 
   1501     pub const DynamicLinker = struct {
   1502         /// Contains the memory used to store the dynamic linker path. This field should
   1503         /// not be used directly. See `get` and `set`. This field exists so that this API requires no allocator.
   1504         buffer: [255]u8 = undefined,
   1505 
   1506         /// Used to construct the dynamic linker path. This field should not be used
   1507         /// directly. See `get` and `set`.
   1508         max_byte: ?u8 = null,
   1509 
   1510         /// Asserts that the length is less than or equal to 255 bytes.
   1511         pub fn init(dl_or_null: ?[]const u8) DynamicLinker {
   1512             var result: DynamicLinker = undefined;
   1513             result.set(dl_or_null);
   1514             return result;
   1515         }
   1516 
   1517         /// The returned memory has the same lifetime as the `DynamicLinker`.
   1518         pub fn get(self: *const DynamicLinker) ?[]const u8 {
   1519             const m: usize = self.max_byte orelse return null;
   1520             return self.buffer[0 .. m + 1];
   1521         }
   1522 
   1523         /// Asserts that the length is less than or equal to 255 bytes.
   1524         pub fn set(self: *DynamicLinker, dl_or_null: ?[]const u8) void {
   1525             if (dl_or_null) |dl| {
   1526                 @memcpy(self.buffer[0..dl.len], dl);
   1527                 self.max_byte = @as(u8, @intCast(dl.len - 1));
   1528             } else {
   1529                 self.max_byte = null;
   1530             }
   1531         }
   1532     };
   1533 
   1534     pub fn standardDynamicLinkerPath(self: Target) DynamicLinker {
   1535         var result: DynamicLinker = .{};
   1536         const S = struct {
   1537             fn print(r: *DynamicLinker, comptime fmt: []const u8, args: anytype) DynamicLinker {
   1538                 r.max_byte = @as(u8, @intCast((std.fmt.bufPrint(&r.buffer, fmt, args) catch unreachable).len - 1));
   1539                 return r.*;
   1540             }
   1541             fn copy(r: *DynamicLinker, s: []const u8) DynamicLinker {
   1542                 @memcpy(r.buffer[0..s.len], s);
   1543                 r.max_byte = @as(u8, @intCast(s.len - 1));
   1544                 return r.*;
   1545             }
   1546         };
   1547         const print = S.print;
   1548         const copy = S.copy;
   1549 
   1550         if (self.abi == .android) {
   1551             const suffix = if (self.ptrBitWidth() == 64) "64" else "";
   1552             return print(&result, "/system/bin/linker{s}", .{suffix});
   1553         }
   1554 
   1555         if (self.abi.isMusl()) {
   1556             const is_arm = switch (self.cpu.arch) {
   1557                 .arm, .armeb, .thumb, .thumbeb => true,
   1558                 else => false,
   1559             };
   1560             const arch_part = switch (self.cpu.arch) {
   1561                 .arm, .thumb => "arm",
   1562                 .armeb, .thumbeb => "armeb",
   1563                 else => |arch| @tagName(arch),
   1564             };
   1565             const arch_suffix = if (is_arm and self.abi.floatAbi() == .hard) "hf" else "";
   1566             return print(&result, "/lib/ld-musl-{s}{s}.so.1", .{ arch_part, arch_suffix });
   1567         }
   1568 
   1569         switch (self.os.tag) {
   1570             .freebsd => return copy(&result, "/libexec/ld-elf.so.1"),
   1571             .netbsd => return copy(&result, "/libexec/ld.elf_so"),
   1572             .openbsd => return copy(&result, "/usr/libexec/ld.so"),
   1573             .dragonfly => return copy(&result, "/libexec/ld-elf.so.2"),
   1574             .solaris => return copy(&result, "/lib/64/ld.so.1"),
   1575             .linux => switch (self.cpu.arch) {
   1576                 .x86,
   1577                 .sparc,
   1578                 .sparcel,
   1579                 => return copy(&result, "/lib/ld-linux.so.2"),
   1580 
   1581                 .aarch64 => return copy(&result, "/lib/ld-linux-aarch64.so.1"),
   1582                 .aarch64_be => return copy(&result, "/lib/ld-linux-aarch64_be.so.1"),
   1583                 .aarch64_32 => return copy(&result, "/lib/ld-linux-aarch64_32.so.1"),
   1584 
   1585                 .arm,
   1586                 .armeb,
   1587                 .thumb,
   1588                 .thumbeb,
   1589                 => return copy(&result, switch (self.abi.floatAbi()) {
   1590                     .hard => "/lib/ld-linux-armhf.so.3",
   1591                     else => "/lib/ld-linux.so.3",
   1592                 }),
   1593 
   1594                 .mips,
   1595                 .mipsel,
   1596                 .mips64,
   1597                 .mips64el,
   1598                 => {
   1599                     const lib_suffix = switch (self.abi) {
   1600                         .gnuabin32, .gnux32 => "32",
   1601                         .gnuabi64 => "64",
   1602                         else => "",
   1603                     };
   1604                     const is_nan_2008 = mips.featureSetHas(self.cpu.features, .nan2008);
   1605                     const loader = if (is_nan_2008) "ld-linux-mipsn8.so.1" else "ld.so.1";
   1606                     return print(&result, "/lib{s}/{s}", .{ lib_suffix, loader });
   1607                 },
   1608 
   1609                 .powerpc, .powerpcle => return copy(&result, "/lib/ld.so.1"),
   1610                 .powerpc64, .powerpc64le => return copy(&result, "/lib64/ld64.so.2"),
   1611                 .s390x => return copy(&result, "/lib64/ld64.so.1"),
   1612                 .sparc64 => return copy(&result, "/lib64/ld-linux.so.2"),
   1613                 .x86_64 => return copy(&result, switch (self.abi) {
   1614                     .gnux32 => "/libx32/ld-linux-x32.so.2",
   1615                     else => "/lib64/ld-linux-x86-64.so.2",
   1616                 }),
   1617 
   1618                 .riscv32 => return copy(&result, "/lib/ld-linux-riscv32-ilp32.so.1"),
   1619                 .riscv64 => return copy(&result, "/lib/ld-linux-riscv64-lp64.so.1"),
   1620 
   1621                 // Architectures in this list have been verified as not having a standard
   1622                 // dynamic linker path.
   1623                 .wasm32,
   1624                 .wasm64,
   1625                 .bpfel,
   1626                 .bpfeb,
   1627                 .nvptx,
   1628                 .nvptx64,
   1629                 .spu_2,
   1630                 .avr,
   1631                 .spirv32,
   1632                 .spirv64,
   1633                 => return result,
   1634 
   1635                 // TODO go over each item in this list and either move it to the above list, or
   1636                 // implement the standard dynamic linker path code for it.
   1637                 .arc,
   1638                 .csky,
   1639                 .hexagon,
   1640                 .m68k,
   1641                 .msp430,
   1642                 .r600,
   1643                 .amdgcn,
   1644                 .tce,
   1645                 .tcele,
   1646                 .xcore,
   1647                 .le32,
   1648                 .le64,
   1649                 .amdil,
   1650                 .amdil64,
   1651                 .hsail,
   1652                 .hsail64,
   1653                 .spir,
   1654                 .spir64,
   1655                 .kalimba,
   1656                 .shave,
   1657                 .lanai,
   1658                 .renderscript32,
   1659                 .renderscript64,
   1660                 .ve,
   1661                 .dxil,
   1662                 .loongarch32,
   1663                 .loongarch64,
   1664                 .xtensa,
   1665                 => return result,
   1666             },
   1667 
   1668             .ios,
   1669             .tvos,
   1670             .watchos,
   1671             .macos,
   1672             => return copy(&result, "/usr/lib/dyld"),
   1673 
   1674             // Operating systems in this list have been verified as not having a standard
   1675             // dynamic linker path.
   1676             .freestanding,
   1677             .uefi,
   1678             .windows,
   1679             .emscripten,
   1680             .wasi,
   1681             .opencl,
   1682             .glsl450,
   1683             .vulkan,
   1684             .other,
   1685             .plan9,
   1686             => return result,
   1687 
   1688             // TODO revisit when multi-arch for Haiku is available
   1689             .haiku => return copy(&result, "/system/runtime_loader"),
   1690 
   1691             // TODO go over each item in this list and either move it to the above list, or
   1692             // implement the standard dynamic linker path code for it.
   1693             .ananas,
   1694             .cloudabi,
   1695             .fuchsia,
   1696             .kfreebsd,
   1697             .lv2,
   1698             .zos,
   1699             .minix,
   1700             .rtems,
   1701             .nacl,
   1702             .aix,
   1703             .cuda,
   1704             .nvcl,
   1705             .amdhsa,
   1706             .ps4,
   1707             .ps5,
   1708             .elfiamcu,
   1709             .mesa3d,
   1710             .contiki,
   1711             .amdpal,
   1712             .hermit,
   1713             .hurd,
   1714             .driverkit,
   1715             .shadermodel,
   1716             => return result,
   1717         }
   1718     }
   1719 
   1720     /// 0c spim    little-endian MIPS 3000 family
   1721     /// 1c 68000   Motorola MC68000
   1722     /// 2c 68020   Motorola MC68020
   1723     /// 5c arm     little-endian ARM
   1724     /// 6c amd64   AMD64 and compatibles (e.g., Intel EM64T)
   1725     /// 7c arm64   ARM64 (ARMv8)
   1726     /// 8c 386     Intel x86, i486, Pentium, etc.
   1727     /// kc sparc   Sun SPARC
   1728     /// qc power   Power PC
   1729     /// vc mips    big-endian MIPS 3000 family
   1730     pub fn plan9Ext(cpu_arch: Cpu.Arch) [:0]const u8 {
   1731         return switch (cpu_arch) {
   1732             .arm => ".5",
   1733             .x86_64 => ".6",
   1734             .aarch64 => ".7",
   1735             .x86 => ".8",
   1736             .sparc => ".k",
   1737             .powerpc, .powerpcle => ".q",
   1738             .mips, .mipsel => ".v",
   1739             // ISAs without designated characters get 'X' for lack of a better option.
   1740             else => ".X",
   1741         };
   1742     }
   1743 
   1744     pub inline fn maxIntAlignment(target: Target) u16 {
   1745         return switch (target.cpu.arch) {
   1746             .avr => 1,
   1747             .msp430 => 2,
   1748             .xcore => 4,
   1749 
   1750             .arm,
   1751             .armeb,
   1752             .thumb,
   1753             .thumbeb,
   1754             .hexagon,
   1755             .mips,
   1756             .mipsel,
   1757             .powerpc,
   1758             .powerpcle,
   1759             .r600,
   1760             .amdgcn,
   1761             .riscv32,
   1762             .sparc,
   1763             .sparcel,
   1764             .s390x,
   1765             .lanai,
   1766             .wasm32,
   1767             .wasm64,
   1768             => 8,
   1769 
   1770             .x86 => if (target.ofmt == .c) 16 else return switch (target.os.tag) {
   1771                 .windows, .uefi => 8,
   1772                 else => 4,
   1773             },
   1774 
   1775             // For these, LLVMABIAlignmentOfType(i128) reports 8. Note that 16
   1776             // is a relevant number in three cases:
   1777             // 1. Different machine code instruction when loading into SIMD register.
   1778             // 2. The C ABI wants 16 for extern structs.
   1779             // 3. 16-byte cmpxchg needs 16-byte alignment.
   1780             // Same logic for powerpc64, mips64, sparc64.
   1781             .x86_64,
   1782             .powerpc64,
   1783             .powerpc64le,
   1784             .mips64,
   1785             .mips64el,
   1786             .sparc64,
   1787             => return switch (target.ofmt) {
   1788                 .c => 16,
   1789                 else => 8,
   1790             },
   1791 
   1792             // Even LLVMABIAlignmentOfType(i128) agrees on these targets.
   1793             .aarch64,
   1794             .aarch64_be,
   1795             .aarch64_32,
   1796             .riscv64,
   1797             .bpfel,
   1798             .bpfeb,
   1799             .nvptx,
   1800             .nvptx64,
   1801             => 16,
   1802 
   1803             // Below this comment are unverified but based on the fact that C requires
   1804             // int128_t to be 16 bytes aligned, it's a safe default.
   1805             .spu_2,
   1806             .csky,
   1807             .arc,
   1808             .m68k,
   1809             .tce,
   1810             .tcele,
   1811             .le32,
   1812             .amdil,
   1813             .hsail,
   1814             .spir,
   1815             .kalimba,
   1816             .renderscript32,
   1817             .spirv32,
   1818             .shave,
   1819             .le64,
   1820             .amdil64,
   1821             .hsail64,
   1822             .spir64,
   1823             .renderscript64,
   1824             .ve,
   1825             .spirv64,
   1826             .dxil,
   1827             .loongarch32,
   1828             .loongarch64,
   1829             .xtensa,
   1830             => 16,
   1831         };
   1832     }
   1833 
   1834     pub fn ptrBitWidth(target: Target) u16 {
   1835         switch (target.abi) {
   1836             .gnux32, .muslx32, .gnuabin32, .gnuilp32 => return 32,
   1837             .gnuabi64 => return 64,
   1838             else => {},
   1839         }
   1840         switch (target.cpu.arch) {
   1841             .avr,
   1842             .msp430,
   1843             .spu_2,
   1844             => return 16,
   1845 
   1846             .arc,
   1847             .arm,
   1848             .armeb,
   1849             .csky,
   1850             .hexagon,
   1851             .m68k,
   1852             .le32,
   1853             .mips,
   1854             .mipsel,
   1855             .powerpc,
   1856             .powerpcle,
   1857             .r600,
   1858             .riscv32,
   1859             .sparcel,
   1860             .tce,
   1861             .tcele,
   1862             .thumb,
   1863             .thumbeb,
   1864             .x86,
   1865             .xcore,
   1866             .nvptx,
   1867             .amdil,
   1868             .hsail,
   1869             .spir,
   1870             .kalimba,
   1871             .shave,
   1872             .lanai,
   1873             .wasm32,
   1874             .renderscript32,
   1875             .aarch64_32,
   1876             .spirv32,
   1877             .loongarch32,
   1878             .dxil,
   1879             .xtensa,
   1880             => return 32,
   1881 
   1882             .aarch64,
   1883             .aarch64_be,
   1884             .mips64,
   1885             .mips64el,
   1886             .powerpc64,
   1887             .powerpc64le,
   1888             .riscv64,
   1889             .x86_64,
   1890             .nvptx64,
   1891             .le64,
   1892             .amdil64,
   1893             .hsail64,
   1894             .spir64,
   1895             .wasm64,
   1896             .renderscript64,
   1897             .amdgcn,
   1898             .bpfel,
   1899             .bpfeb,
   1900             .sparc64,
   1901             .s390x,
   1902             .ve,
   1903             .spirv64,
   1904             .loongarch64,
   1905             => return 64,
   1906 
   1907             .sparc => return if (std.Target.sparc.featureSetHas(target.cpu.features, .v9)) 64 else 32,
   1908         }
   1909     }
   1910 
   1911     pub fn stackAlignment(target: Target) u16 {
   1912         return switch (target.cpu.arch) {
   1913             .amdgcn => 4,
   1914             .x86 => switch (target.os.tag) {
   1915                 .windows => 4,
   1916                 else => 16,
   1917             },
   1918             .arm,
   1919             .armeb,
   1920             .thumb,
   1921             .thumbeb,
   1922             .mips,
   1923             .mipsel,
   1924             .sparc,
   1925             .sparcel,
   1926             => 8,
   1927             .aarch64,
   1928             .aarch64_be,
   1929             .aarch64_32,
   1930             .bpfeb,
   1931             .bpfel,
   1932             .mips64,
   1933             .mips64el,
   1934             .powerpc64,
   1935             .powerpc64le,
   1936             .riscv32,
   1937             .riscv64,
   1938             .sparc64,
   1939             .x86_64,
   1940             .ve,
   1941             .wasm32,
   1942             .wasm64,
   1943             => 16,
   1944             else => @divExact(target.ptrBitWidth(), 8),
   1945         };
   1946     }
   1947 
   1948     /// Default signedness of `char` for the native C compiler for this target
   1949     /// Note that char signedness is implementation-defined and many compilers provide
   1950     /// an option to override the default signedness e.g. GCC's -funsigned-char / -fsigned-char
   1951     pub fn charSignedness(target: Target) std.builtin.Signedness {
   1952         switch (target.cpu.arch) {
   1953             .aarch64,
   1954             .aarch64_32,
   1955             .aarch64_be,
   1956             .arm,
   1957             .armeb,
   1958             .thumb,
   1959             .thumbeb,
   1960             => return if (target.os.tag.isDarwin() or target.os.tag == .windows) .signed else .unsigned,
   1961             .powerpc, .powerpc64 => return if (target.os.tag.isDarwin()) .signed else .unsigned,
   1962             .powerpc64le,
   1963             .s390x,
   1964             .xcore,
   1965             .arc,
   1966             .msp430,
   1967             .riscv32,
   1968             .riscv64,
   1969             => return .unsigned,
   1970             else => return .signed,
   1971         }
   1972     }
   1973 
   1974     pub const CType = enum {
   1975         char,
   1976         short,
   1977         ushort,
   1978         int,
   1979         uint,
   1980         long,
   1981         ulong,
   1982         longlong,
   1983         ulonglong,
   1984         float,
   1985         double,
   1986         longdouble,
   1987     };
   1988 
   1989     pub fn c_type_byte_size(t: Target, c_type: CType) u16 {
   1990         return switch (c_type) {
   1991             .char,
   1992             .short,
   1993             .ushort,
   1994             .int,
   1995             .uint,
   1996             .long,
   1997             .ulong,
   1998             .longlong,
   1999             .ulonglong,
   2000             .float,
   2001             .double,
   2002             => @divExact(c_type_bit_size(t, c_type), 8),
   2003 
   2004             .longdouble => switch (c_type_bit_size(t, c_type)) {
   2005                 16 => 2,
   2006                 32 => 4,
   2007                 64 => 8,
   2008                 80 => @as(u16, @intCast(mem.alignForward(usize, 10, c_type_alignment(t, .longdouble)))),
   2009                 128 => 16,
   2010                 else => unreachable,
   2011             },
   2012         };
   2013     }
   2014 
   2015     pub fn c_type_bit_size(target: Target, c_type: CType) u16 {
   2016         switch (target.os.tag) {
   2017             .freestanding, .other => switch (target.cpu.arch) {
   2018                 .msp430 => switch (c_type) {
   2019                     .char => return 8,
   2020                     .short, .ushort, .int, .uint => return 16,
   2021                     .float, .long, .ulong => return 32,
   2022                     .longlong, .ulonglong, .double, .longdouble => return 64,
   2023                 },
   2024                 .avr => switch (c_type) {
   2025                     .char => return 8,
   2026                     .short, .ushort, .int, .uint => return 16,
   2027                     .long, .ulong, .float, .double, .longdouble => return 32,
   2028                     .longlong, .ulonglong => return 64,
   2029                 },
   2030                 .tce, .tcele => switch (c_type) {
   2031                     .char => return 8,
   2032                     .short, .ushort => return 16,
   2033                     .int, .uint, .long, .ulong, .longlong, .ulonglong => return 32,
   2034                     .float, .double, .longdouble => return 32,
   2035                 },
   2036                 .mips64, .mips64el => switch (c_type) {
   2037                     .char => return 8,
   2038                     .short, .ushort => return 16,
   2039                     .int, .uint, .float => return 32,
   2040                     .long, .ulong => return if (target.abi != .gnuabin32) 64 else 32,
   2041                     .longlong, .ulonglong, .double => return 64,
   2042                     .longdouble => return 128,
   2043                 },
   2044                 .x86_64 => switch (c_type) {
   2045                     .char => return 8,
   2046                     .short, .ushort => return 16,
   2047                     .int, .uint, .float => return 32,
   2048                     .long, .ulong => switch (target.abi) {
   2049                         .gnux32, .muslx32 => return 32,
   2050                         else => return 64,
   2051                     },
   2052                     .longlong, .ulonglong, .double => return 64,
   2053                     .longdouble => return 80,
   2054                 },
   2055                 else => switch (c_type) {
   2056                     .char => return 8,
   2057                     .short, .ushort => return 16,
   2058                     .int, .uint, .float => return 32,
   2059                     .long, .ulong => return target.ptrBitWidth(),
   2060                     .longlong, .ulonglong, .double => return 64,
   2061                     .longdouble => switch (target.cpu.arch) {
   2062                         .x86 => switch (target.abi) {
   2063                             .android => return 64,
   2064                             else => return 80,
   2065                         },
   2066 
   2067                         .powerpc,
   2068                         .powerpcle,
   2069                         .powerpc64,
   2070                         .powerpc64le,
   2071                         => switch (target.abi) {
   2072                             .musl,
   2073                             .musleabi,
   2074                             .musleabihf,
   2075                             .muslx32,
   2076                             => return 64,
   2077                             else => return 128,
   2078                         },
   2079 
   2080                         .riscv32,
   2081                         .riscv64,
   2082                         .aarch64,
   2083                         .aarch64_be,
   2084                         .aarch64_32,
   2085                         .s390x,
   2086                         .sparc,
   2087                         .sparc64,
   2088                         .sparcel,
   2089                         .wasm32,
   2090                         .wasm64,
   2091                         => return 128,
   2092 
   2093                         else => return 64,
   2094                     },
   2095                 },
   2096             },
   2097 
   2098             .linux,
   2099             .freebsd,
   2100             .netbsd,
   2101             .dragonfly,
   2102             .openbsd,
   2103             .wasi,
   2104             .emscripten,
   2105             .plan9,
   2106             .solaris,
   2107             .haiku,
   2108             .ananas,
   2109             .fuchsia,
   2110             .minix,
   2111             => switch (target.cpu.arch) {
   2112                 .msp430 => switch (c_type) {
   2113                     .char => return 8,
   2114                     .short, .ushort, .int, .uint => return 16,
   2115                     .long, .ulong, .float => return 32,
   2116                     .longlong, .ulonglong, .double, .longdouble => return 64,
   2117                 },
   2118                 .avr => switch (c_type) {
   2119                     .char => return 8,
   2120                     .short, .ushort, .int, .uint => return 16,
   2121                     .long, .ulong, .float, .double, .longdouble => return 32,
   2122                     .longlong, .ulonglong => return 64,
   2123                 },
   2124                 .tce, .tcele => switch (c_type) {
   2125                     .char => return 8,
   2126                     .short, .ushort => return 16,
   2127                     .int, .uint, .long, .ulong, .longlong, .ulonglong => return 32,
   2128                     .float, .double, .longdouble => return 32,
   2129                 },
   2130                 .mips64, .mips64el => switch (c_type) {
   2131                     .char => return 8,
   2132                     .short, .ushort => return 16,
   2133                     .int, .uint, .float => return 32,
   2134                     .long, .ulong => return if (target.abi != .gnuabin32) 64 else 32,
   2135                     .longlong, .ulonglong, .double => return 64,
   2136                     .longdouble => if (target.os.tag == .freebsd) return 64 else return 128,
   2137                 },
   2138                 .x86_64 => switch (c_type) {
   2139                     .char => return 8,
   2140                     .short, .ushort => return 16,
   2141                     .int, .uint, .float => return 32,
   2142                     .long, .ulong => switch (target.abi) {
   2143                         .gnux32, .muslx32 => return 32,
   2144                         else => return 64,
   2145                     },
   2146                     .longlong, .ulonglong, .double => return 64,
   2147                     .longdouble => return 80,
   2148                 },
   2149                 else => switch (c_type) {
   2150                     .char => return 8,
   2151                     .short, .ushort => return 16,
   2152                     .int, .uint, .float => return 32,
   2153                     .long, .ulong => return target.ptrBitWidth(),
   2154                     .longlong, .ulonglong, .double => return 64,
   2155                     .longdouble => switch (target.cpu.arch) {
   2156                         .x86 => switch (target.abi) {
   2157                             .android => return 64,
   2158                             else => return 80,
   2159                         },
   2160 
   2161                         .powerpc,
   2162                         .powerpcle,
   2163                         => switch (target.abi) {
   2164                             .musl,
   2165                             .musleabi,
   2166                             .musleabihf,
   2167                             .muslx32,
   2168                             => return 64,
   2169                             else => switch (target.os.tag) {
   2170                                 .freebsd, .netbsd, .openbsd => return 64,
   2171                                 else => return 128,
   2172                             },
   2173                         },
   2174 
   2175                         .powerpc64,
   2176                         .powerpc64le,
   2177                         => switch (target.abi) {
   2178                             .musl,
   2179                             .musleabi,
   2180                             .musleabihf,
   2181                             .muslx32,
   2182                             => return 64,
   2183                             else => switch (target.os.tag) {
   2184                                 .freebsd, .openbsd => return 64,
   2185                                 else => return 128,
   2186                             },
   2187                         },
   2188 
   2189                         .riscv32,
   2190                         .riscv64,
   2191                         .aarch64,
   2192                         .aarch64_be,
   2193                         .aarch64_32,
   2194                         .s390x,
   2195                         .mips64,
   2196                         .mips64el,
   2197                         .sparc,
   2198                         .sparc64,
   2199                         .sparcel,
   2200                         .wasm32,
   2201                         .wasm64,
   2202                         => return 128,
   2203 
   2204                         else => return 64,
   2205                     },
   2206                 },
   2207             },
   2208 
   2209             .windows, .uefi => switch (target.cpu.arch) {
   2210                 .x86 => switch (c_type) {
   2211                     .char => return 8,
   2212                     .short, .ushort => return 16,
   2213                     .int, .uint, .float => return 32,
   2214                     .long, .ulong => return 32,
   2215                     .longlong, .ulonglong, .double => return 64,
   2216                     .longdouble => switch (target.abi) {
   2217                         .gnu, .gnuilp32, .cygnus => return 80,
   2218                         else => return 64,
   2219                     },
   2220                 },
   2221                 .x86_64 => switch (c_type) {
   2222                     .char => return 8,
   2223                     .short, .ushort => return 16,
   2224                     .int, .uint, .float => return 32,
   2225                     .long, .ulong => switch (target.abi) {
   2226                         .cygnus => return 64,
   2227                         else => return 32,
   2228                     },
   2229                     .longlong, .ulonglong, .double => return 64,
   2230                     .longdouble => switch (target.abi) {
   2231                         .gnu, .gnuilp32, .cygnus => return 80,
   2232                         else => return 64,
   2233                     },
   2234                 },
   2235                 else => switch (c_type) {
   2236                     .char => return 8,
   2237                     .short, .ushort => return 16,
   2238                     .int, .uint, .float => return 32,
   2239                     .long, .ulong => return 32,
   2240                     .longlong, .ulonglong, .double => return 64,
   2241                     .longdouble => return 64,
   2242                 },
   2243             },
   2244 
   2245             .macos, .ios, .tvos, .watchos => switch (c_type) {
   2246                 .char => return 8,
   2247                 .short, .ushort => return 16,
   2248                 .int, .uint, .float => return 32,
   2249                 .long, .ulong => switch (target.cpu.arch) {
   2250                     .x86, .arm, .aarch64_32 => return 32,
   2251                     .x86_64 => switch (target.abi) {
   2252                         .gnux32, .muslx32 => return 32,
   2253                         else => return 64,
   2254                     },
   2255                     else => return 64,
   2256                 },
   2257                 .longlong, .ulonglong, .double => return 64,
   2258                 .longdouble => switch (target.cpu.arch) {
   2259                     .x86 => switch (target.abi) {
   2260                         .android => return 64,
   2261                         else => return 80,
   2262                     },
   2263                     .x86_64 => return 80,
   2264                     else => return 64,
   2265                 },
   2266             },
   2267 
   2268             .nvcl, .cuda => switch (c_type) {
   2269                 .char => return 8,
   2270                 .short, .ushort => return 16,
   2271                 .int, .uint, .float => return 32,
   2272                 .long, .ulong => switch (target.cpu.arch) {
   2273                     .nvptx => return 32,
   2274                     .nvptx64 => return 64,
   2275                     else => return 64,
   2276                 },
   2277                 .longlong, .ulonglong, .double => return 64,
   2278                 .longdouble => return 64,
   2279             },
   2280 
   2281             .amdhsa, .amdpal => switch (c_type) {
   2282                 .char => return 8,
   2283                 .short, .ushort => return 16,
   2284                 .int, .uint, .float => return 32,
   2285                 .long, .ulong, .longlong, .ulonglong, .double => return 64,
   2286                 .longdouble => return 128,
   2287             },
   2288 
   2289             .opencl => switch (c_type) {
   2290                 .char => return 8,
   2291                 .short, .ushort => return 16,
   2292                 .int, .uint, .float => return 32,
   2293                 .long, .ulong, .double => return 64,
   2294                 .longlong, .ulonglong => return 128,
   2295                 // Note: The OpenCL specification does not guarantee a particular size for long double,
   2296                 // but clang uses 128 bits.
   2297                 .longdouble => return 128,
   2298             },
   2299 
   2300             .ps4, .ps5 => switch (c_type) {
   2301                 .char => return 8,
   2302                 .short, .ushort => return 16,
   2303                 .int, .uint, .float => return 32,
   2304                 .long, .ulong => return 64,
   2305                 .longlong, .ulonglong, .double => return 64,
   2306                 .longdouble => return 80,
   2307             },
   2308 
   2309             .cloudabi,
   2310             .kfreebsd,
   2311             .lv2,
   2312             .zos,
   2313             .rtems,
   2314             .nacl,
   2315             .aix,
   2316             .elfiamcu,
   2317             .mesa3d,
   2318             .contiki,
   2319             .hermit,
   2320             .hurd,
   2321             .glsl450,
   2322             .vulkan,
   2323             .driverkit,
   2324             .shadermodel,
   2325             => @panic("TODO specify the C integer and float type sizes for this OS"),
   2326         }
   2327     }
   2328 
   2329     pub fn c_type_alignment(target: Target, c_type: CType) u16 {
   2330         // Overrides for unusual alignments
   2331         switch (target.cpu.arch) {
   2332             .avr => return 1,
   2333             .x86 => switch (target.os.tag) {
   2334                 .windows, .uefi => switch (c_type) {
   2335                     .longlong, .ulonglong, .double => return 8,
   2336                     .longdouble => switch (target.abi) {
   2337                         .gnu, .gnuilp32, .cygnus => return 4,
   2338                         else => return 8,
   2339                     },
   2340                     else => {},
   2341                 },
   2342                 else => {},
   2343             },
   2344             else => {},
   2345         }
   2346 
   2347         // Next-power-of-two-aligned, up to a maximum.
   2348         return @min(
   2349             std.math.ceilPowerOfTwoAssert(u16, (c_type_bit_size(target, c_type) + 7) / 8),
   2350             switch (target.cpu.arch) {
   2351                 .arm, .armeb, .thumb, .thumbeb => switch (target.os.tag) {
   2352                     .netbsd => switch (target.abi) {
   2353                         .gnueabi,
   2354                         .gnueabihf,
   2355                         .eabi,
   2356                         .eabihf,
   2357                         .android,
   2358                         .musleabi,
   2359                         .musleabihf,
   2360                         => 8,
   2361 
   2362                         else => @as(u16, 4),
   2363                     },
   2364                     .ios, .tvos, .watchos => 4,
   2365                     else => 8,
   2366                 },
   2367 
   2368                 .msp430,
   2369                 .avr,
   2370                 => 2,
   2371 
   2372                 .arc,
   2373                 .csky,
   2374                 .x86,
   2375                 .xcore,
   2376                 .dxil,
   2377                 .loongarch32,
   2378                 .tce,
   2379                 .tcele,
   2380                 .le32,
   2381                 .amdil,
   2382                 .hsail,
   2383                 .spir,
   2384                 .spirv32,
   2385                 .kalimba,
   2386                 .shave,
   2387                 .renderscript32,
   2388                 .ve,
   2389                 .spu_2,
   2390                 .xtensa,
   2391                 => 4,
   2392 
   2393                 .aarch64_32,
   2394                 .amdgcn,
   2395                 .amdil64,
   2396                 .bpfel,
   2397                 .bpfeb,
   2398                 .hexagon,
   2399                 .hsail64,
   2400                 .loongarch64,
   2401                 .m68k,
   2402                 .mips,
   2403                 .mipsel,
   2404                 .sparc,
   2405                 .sparcel,
   2406                 .sparc64,
   2407                 .lanai,
   2408                 .le64,
   2409                 .nvptx,
   2410                 .nvptx64,
   2411                 .r600,
   2412                 .s390x,
   2413                 .spir64,
   2414                 .spirv64,
   2415                 .renderscript64,
   2416                 => 8,
   2417 
   2418                 .aarch64,
   2419                 .aarch64_be,
   2420                 .mips64,
   2421                 .mips64el,
   2422                 .powerpc,
   2423                 .powerpcle,
   2424                 .powerpc64,
   2425                 .powerpc64le,
   2426                 .riscv32,
   2427                 .riscv64,
   2428                 .x86_64,
   2429                 .wasm32,
   2430                 .wasm64,
   2431                 => 16,
   2432             },
   2433         );
   2434     }
   2435 
   2436     pub fn c_type_preferred_alignment(target: Target, c_type: CType) u16 {
   2437         // Overrides for unusual alignments
   2438         switch (target.cpu.arch) {
   2439             .arm, .armeb, .thumb, .thumbeb => switch (target.os.tag) {
   2440                 .netbsd => switch (target.abi) {
   2441                     .gnueabi,
   2442                     .gnueabihf,
   2443                     .eabi,
   2444                     .eabihf,
   2445                     .android,
   2446                     .musleabi,
   2447                     .musleabihf,
   2448                     => {},
   2449 
   2450                     else => switch (c_type) {
   2451                         .longdouble => return 4,
   2452                         else => {},
   2453                     },
   2454                 },
   2455                 .ios, .tvos, .watchos => switch (c_type) {
   2456                     .longdouble => return 4,
   2457                     else => {},
   2458                 },
   2459                 else => {},
   2460             },
   2461             .arc => switch (c_type) {
   2462                 .longdouble => return 4,
   2463                 else => {},
   2464             },
   2465             .avr => switch (c_type) {
   2466                 .char, .int, .uint, .long, .ulong, .float, .longdouble => return 1,
   2467                 .short, .ushort => return 2,
   2468                 .double => return 4,
   2469                 .longlong, .ulonglong => return 8,
   2470             },
   2471             .x86 => switch (target.os.tag) {
   2472                 .windows, .uefi => switch (c_type) {
   2473                     .longdouble => switch (target.abi) {
   2474                         .gnu, .gnuilp32, .cygnus => return 4,
   2475                         else => return 8,
   2476                     },
   2477                     else => {},
   2478                 },
   2479                 else => switch (c_type) {
   2480                     .longdouble => return 4,
   2481                     else => {},
   2482                 },
   2483             },
   2484             else => {},
   2485         }
   2486 
   2487         // Next-power-of-two-aligned, up to a maximum.
   2488         return @min(
   2489             std.math.ceilPowerOfTwoAssert(u16, (c_type_bit_size(target, c_type) + 7) / 8),
   2490             switch (target.cpu.arch) {
   2491                 .msp430 => @as(u16, 2),
   2492 
   2493                 .csky,
   2494                 .xcore,
   2495                 .dxil,
   2496                 .loongarch32,
   2497                 .tce,
   2498                 .tcele,
   2499                 .le32,
   2500                 .amdil,
   2501                 .hsail,
   2502                 .spir,
   2503                 .spirv32,
   2504                 .kalimba,
   2505                 .shave,
   2506                 .renderscript32,
   2507                 .ve,
   2508                 .spu_2,
   2509                 .xtensa,
   2510                 => 4,
   2511 
   2512                 .arc,
   2513                 .arm,
   2514                 .armeb,
   2515                 .avr,
   2516                 .thumb,
   2517                 .thumbeb,
   2518                 .aarch64_32,
   2519                 .amdgcn,
   2520                 .amdil64,
   2521                 .bpfel,
   2522                 .bpfeb,
   2523                 .hexagon,
   2524                 .hsail64,
   2525                 .x86,
   2526                 .loongarch64,
   2527                 .m68k,
   2528                 .mips,
   2529                 .mipsel,
   2530                 .sparc,
   2531                 .sparcel,
   2532                 .sparc64,
   2533                 .lanai,
   2534                 .le64,
   2535                 .nvptx,
   2536                 .nvptx64,
   2537                 .r600,
   2538                 .s390x,
   2539                 .spir64,
   2540                 .spirv64,
   2541                 .renderscript64,
   2542                 => 8,
   2543 
   2544                 .aarch64,
   2545                 .aarch64_be,
   2546                 .mips64,
   2547                 .mips64el,
   2548                 .powerpc,
   2549                 .powerpcle,
   2550                 .powerpc64,
   2551                 .powerpc64le,
   2552                 .riscv32,
   2553                 .riscv64,
   2554                 .x86_64,
   2555                 .wasm32,
   2556                 .wasm64,
   2557                 => 16,
   2558             },
   2559         );
   2560     }
   2561 };
   2562 
   2563 test {
   2564     std.testing.refAllDecls(Target.Cpu.Arch);
   2565 }