zig

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

blob 9391d590 (84104B) - Raw


      1 const std = @import("std.zig");
      2 const builtin = @import("builtin");
      3 const mem = std.mem;
      4 const Version = std.builtin.Version;
      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 @enumToInt(self) >= @enumToInt(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 @enumToInt(ver) >= @enumToInt(self.min) and @enumToInt(ver) <= @enumToInt(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 (@enumToInt(self.min) >= @enumToInt(ver)) return true;
    157                     if (@enumToInt(self.max) < @enumToInt(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 (@enumToInt(self) >= @enumToInt(WindowsVersion.nt4) and @enumToInt(self) <= @enumToInt(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, "@intToEnum(Target.Os.WindowsVersion, 0x{X:0>8})", .{@enumToInt(self)});
    176                     }
    177                 } else if (fmt.len == 0) {
    178                     if (@enumToInt(self) >= @enumToInt(WindowsVersion.nt4) and @enumToInt(self) <= @enumToInt(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})", .{@enumToInt(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 },
    276                             .max = .{ .major = 13, .minor = 1 },
    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 },
    284                             },
    285                         },
    286                         .x86_64 => VersionRange{
    287                             .semver = .{
    288                                 .min = .{ .major = 11, .minor = 7, .patch = 1 },
    289                                 .max = .{ .major = 13, .minor = 3 },
    290                             },
    291                         },
    292                         else => unreachable,
    293                     },
    294                     .ios => return .{
    295                         .semver = .{
    296                             .min = .{ .major = 12, .minor = 0 },
    297                             .max = .{ .major = 13, .minor = 4, .patch = 0 },
    298                         },
    299                     },
    300                     .watchos => return .{
    301                         .semver = .{
    302                             .min = .{ .major = 6, .minor = 0 },
    303                             .max = .{ .major = 6, .minor = 2, .patch = 0 },
    304                         },
    305                     },
    306                     .tvos => return .{
    307                         .semver = .{
    308                             .min = .{ .major = 13, .minor = 0 },
    309                             .max = .{ .major = 13, .minor = 4, .patch = 0 },
    310                         },
    311                     },
    312                     .netbsd => return .{
    313                         .semver = .{
    314                             .min = .{ .major = 8, .minor = 0 },
    315                             .max = .{ .major = 10, .minor = 0 },
    316                         },
    317                     },
    318                     .openbsd => return .{
    319                         .semver = .{
    320                             .min = .{ .major = 6, .minor = 8 },
    321                             .max = .{ .major = 7, .minor = 2 },
    322                         },
    323                     },
    324                     .dragonfly => return .{
    325                         .semver = .{
    326                             .min = .{ .major = 5, .minor = 8 },
    327                             .max = .{ .major = 6, .minor = 4 },
    328                         },
    329                     },
    330                     .solaris => return .{
    331                         .semver = .{
    332                             .min = .{ .major = 5, .minor = 11 },
    333                             .max = .{ .major = 5, .minor = 11 },
    334                         },
    335                     },
    336 
    337                     .linux => return .{
    338                         .linux = .{
    339                             .range = .{
    340                                 .min = .{ .major = 3, .minor = 16 },
    341                                 .max = .{ .major = 5, .minor = 10, .patch = 81 },
    342                             },
    343                             .glibc = .{ .major = 2, .minor = 19 },
    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 m68k = @import("target/m68k.zig");
    463     pub const mips = @import("target/mips.zig");
    464     pub const msp430 = @import("target/msp430.zig");
    465     pub const nvptx = @import("target/nvptx.zig");
    466     pub const powerpc = @import("target/powerpc.zig");
    467     pub const riscv = @import("target/riscv.zig");
    468     pub const sparc = @import("target/sparc.zig");
    469     pub const spirv = @import("target/spirv.zig");
    470     pub const s390x = @import("target/s390x.zig");
    471     pub const ve = @import("target/ve.zig");
    472     pub const wasm = @import("target/wasm.zig");
    473     pub const x86 = @import("target/x86.zig");
    474 
    475     pub const Abi = enum {
    476         none,
    477         gnu,
    478         gnuabin32,
    479         gnuabi64,
    480         gnueabi,
    481         gnueabihf,
    482         gnux32,
    483         gnuilp32,
    484         code16,
    485         eabi,
    486         eabihf,
    487         android,
    488         musl,
    489         musleabi,
    490         musleabihf,
    491         muslx32,
    492         msvc,
    493         itanium,
    494         cygnus,
    495         coreclr,
    496         simulator,
    497         macabi,
    498         pixel,
    499         vertex,
    500         geometry,
    501         hull,
    502         domain,
    503         compute,
    504         library,
    505         raygeneration,
    506         intersection,
    507         anyhit,
    508         closesthit,
    509         miss,
    510         callable,
    511         mesh,
    512         amplification,
    513 
    514         pub fn default(arch: Cpu.Arch, target_os: Os) Abi {
    515             if (arch.isWasm()) {
    516                 return .musl;
    517             }
    518             switch (target_os.tag) {
    519                 .freestanding,
    520                 .ananas,
    521                 .cloudabi,
    522                 .dragonfly,
    523                 .lv2,
    524                 .solaris,
    525                 .zos,
    526                 .minix,
    527                 .rtems,
    528                 .nacl,
    529                 .aix,
    530                 .cuda,
    531                 .nvcl,
    532                 .amdhsa,
    533                 .ps4,
    534                 .ps5,
    535                 .elfiamcu,
    536                 .mesa3d,
    537                 .contiki,
    538                 .amdpal,
    539                 .hermit,
    540                 .other,
    541                 => return .eabi,
    542                 .openbsd,
    543                 .freebsd,
    544                 .fuchsia,
    545                 .kfreebsd,
    546                 .netbsd,
    547                 .hurd,
    548                 .haiku,
    549                 .windows,
    550                 => return .gnu,
    551                 .uefi => return .msvc,
    552                 .linux,
    553                 .wasi,
    554                 .emscripten,
    555                 => return .musl,
    556                 .opencl, // TODO: SPIR-V ABIs with Linkage capability
    557                 .glsl450,
    558                 .vulkan,
    559                 .plan9, // TODO specify abi
    560                 .macos,
    561                 .ios,
    562                 .tvos,
    563                 .watchos,
    564                 .driverkit,
    565                 .shadermodel,
    566                 => return .none,
    567             }
    568         }
    569 
    570         pub fn isGnu(abi: Abi) bool {
    571             return switch (abi) {
    572                 .gnu, .gnuabin32, .gnuabi64, .gnueabi, .gnueabihf, .gnux32 => true,
    573                 else => false,
    574             };
    575         }
    576 
    577         pub fn isMusl(abi: Abi) bool {
    578             return switch (abi) {
    579                 .musl, .musleabi, .musleabihf => true,
    580                 else => false,
    581             };
    582         }
    583 
    584         pub fn floatAbi(abi: Abi) FloatAbi {
    585             return switch (abi) {
    586                 .gnueabihf,
    587                 .eabihf,
    588                 .musleabihf,
    589                 => .hard,
    590                 else => .soft,
    591             };
    592         }
    593     };
    594 
    595     pub const ObjectFormat = enum {
    596         /// Common Object File Format (Windows)
    597         coff,
    598         /// DirectX Container
    599         dxcontainer,
    600         /// Executable and Linking Format
    601         elf,
    602         /// macOS relocatables
    603         macho,
    604         /// Standard, Portable Intermediate Representation V
    605         spirv,
    606         /// WebAssembly
    607         wasm,
    608         /// C source code
    609         c,
    610         /// Intel IHEX
    611         hex,
    612         /// Machine code with no metadata.
    613         raw,
    614         /// Plan 9 from Bell Labs
    615         plan9,
    616         /// Nvidia PTX format
    617         nvptx,
    618 
    619         pub fn fileExt(of: ObjectFormat, cpu_arch: Cpu.Arch) [:0]const u8 {
    620             return switch (of) {
    621                 .coff => ".obj",
    622                 .elf, .macho, .wasm => ".o",
    623                 .c => ".c",
    624                 .spirv => ".spv",
    625                 .hex => ".ihex",
    626                 .raw => ".bin",
    627                 .plan9 => plan9Ext(cpu_arch),
    628                 .nvptx => ".ptx",
    629                 .dxcontainer => ".dxil",
    630             };
    631         }
    632 
    633         pub fn default(os_tag: Os.Tag, cpu_arch: Cpu.Arch) ObjectFormat {
    634             return switch (os_tag) {
    635                 .windows, .uefi => .coff,
    636                 .ios, .macos, .watchos, .tvos => .macho,
    637                 .plan9 => .plan9,
    638                 else => return switch (cpu_arch) {
    639                     .wasm32, .wasm64 => .wasm,
    640                     .spirv32, .spirv64 => .spirv,
    641                     .nvptx, .nvptx64 => .nvptx,
    642                     else => .elf,
    643                 },
    644             };
    645         }
    646     };
    647 
    648     pub const SubSystem = enum {
    649         Console,
    650         Windows,
    651         Posix,
    652         Native,
    653         EfiApplication,
    654         EfiBootServiceDriver,
    655         EfiRom,
    656         EfiRuntimeDriver,
    657     };
    658 
    659     pub const Cpu = struct {
    660         /// Architecture
    661         arch: Arch,
    662 
    663         /// The CPU model to target. It has a set of features
    664         /// which are overridden with the `features` field.
    665         model: *const Model,
    666 
    667         /// An explicit list of the entire CPU feature set. It may differ from the specific CPU model's features.
    668         features: Feature.Set,
    669 
    670         pub const Feature = struct {
    671             /// The bit index into `Set`. Has a default value of `undefined` because the canonical
    672             /// structures are populated via comptime logic.
    673             index: Set.Index = undefined,
    674 
    675             /// Has a default value of `undefined` because the canonical
    676             /// structures are populated via comptime logic.
    677             name: []const u8 = undefined,
    678 
    679             /// If this corresponds to an LLVM-recognized feature, this will be populated;
    680             /// otherwise null.
    681             llvm_name: ?[:0]const u8,
    682 
    683             /// Human-friendly UTF-8 text.
    684             description: []const u8,
    685 
    686             /// Sparse `Set` of features this depends on.
    687             dependencies: Set,
    688 
    689             /// A bit set of all the features.
    690             pub const Set = struct {
    691                 ints: [usize_count]usize,
    692 
    693                 pub const needed_bit_count = 288;
    694                 pub const byte_count = (needed_bit_count + 7) / 8;
    695                 pub const usize_count = (byte_count + (@sizeOf(usize) - 1)) / @sizeOf(usize);
    696                 pub const Index = std.math.Log2Int(std.meta.Int(.unsigned, usize_count * @bitSizeOf(usize)));
    697                 pub const ShiftInt = std.math.Log2Int(usize);
    698 
    699                 pub const empty = Set{ .ints = [1]usize{0} ** usize_count };
    700 
    701                 pub fn isEmpty(set: Set) bool {
    702                     return for (set.ints) |x| {
    703                         if (x != 0) break false;
    704                     } else true;
    705                 }
    706 
    707                 pub fn isEnabled(set: Set, arch_feature_index: Index) bool {
    708                     const usize_index = arch_feature_index / @bitSizeOf(usize);
    709                     const bit_index = @intCast(ShiftInt, arch_feature_index % @bitSizeOf(usize));
    710                     return (set.ints[usize_index] & (@as(usize, 1) << bit_index)) != 0;
    711                 }
    712 
    713                 /// Adds the specified feature but not its dependencies.
    714                 pub fn addFeature(set: *Set, arch_feature_index: Index) void {
    715                     const usize_index = arch_feature_index / @bitSizeOf(usize);
    716                     const bit_index = @intCast(ShiftInt, arch_feature_index % @bitSizeOf(usize));
    717                     set.ints[usize_index] |= @as(usize, 1) << bit_index;
    718                 }
    719 
    720                 /// Adds the specified feature set but not its dependencies.
    721                 pub fn addFeatureSet(set: *Set, other_set: Set) void {
    722                     set.ints = @as(@Vector(usize_count, usize), set.ints) | @as(@Vector(usize_count, usize), other_set.ints);
    723                 }
    724 
    725                 /// Removes the specified feature but not its dependents.
    726                 pub fn removeFeature(set: *Set, arch_feature_index: Index) void {
    727                     const usize_index = arch_feature_index / @bitSizeOf(usize);
    728                     const bit_index = @intCast(ShiftInt, arch_feature_index % @bitSizeOf(usize));
    729                     set.ints[usize_index] &= ~(@as(usize, 1) << bit_index);
    730                 }
    731 
    732                 /// Removes the specified feature but not its dependents.
    733                 pub fn removeFeatureSet(set: *Set, other_set: Set) void {
    734                     set.ints = @as(@Vector(usize_count, usize), set.ints) & ~@as(@Vector(usize_count, usize), other_set.ints);
    735                 }
    736 
    737                 pub fn populateDependencies(set: *Set, all_features_list: []const Cpu.Feature) void {
    738                     @setEvalBranchQuota(1000000);
    739 
    740                     var old = set.ints;
    741                     while (true) {
    742                         for (all_features_list, 0..) |feature, index_usize| {
    743                             const index = @intCast(Index, index_usize);
    744                             if (set.isEnabled(index)) {
    745                                 set.addFeatureSet(feature.dependencies);
    746                             }
    747                         }
    748                         const nothing_changed = mem.eql(usize, &old, &set.ints);
    749                         if (nothing_changed) return;
    750                         old = set.ints;
    751                     }
    752                 }
    753 
    754                 pub fn asBytes(set: *const Set) *const [byte_count]u8 {
    755                     return @ptrCast(*const [byte_count]u8, &set.ints);
    756                 }
    757 
    758                 pub fn eql(set: Set, other_set: Set) bool {
    759                     return mem.eql(usize, &set.ints, &other_set.ints);
    760                 }
    761 
    762                 pub fn isSuperSetOf(set: Set, other_set: Set) bool {
    763                     const V = @Vector(usize_count, usize);
    764                     const set_v: V = set.ints;
    765                     const other_v: V = other_set.ints;
    766                     return @reduce(.And, (set_v & other_v) == other_v);
    767                 }
    768             };
    769 
    770             pub fn feature_set_fns(comptime F: type) type {
    771                 return struct {
    772                     /// Populates only the feature bits specified.
    773                     pub fn featureSet(features: []const F) Set {
    774                         var x = Set.empty;
    775                         for (features) |feature| {
    776                             x.addFeature(@enumToInt(feature));
    777                         }
    778                         return x;
    779                     }
    780 
    781                     /// Returns true if the specified feature is enabled.
    782                     pub fn featureSetHas(set: Set, feature: F) bool {
    783                         return set.isEnabled(@enumToInt(feature));
    784                     }
    785 
    786                     /// Returns true if any specified feature is enabled.
    787                     pub fn featureSetHasAny(set: Set, features: anytype) bool {
    788                         comptime std.debug.assert(std.meta.trait.isIndexable(@TypeOf(features)));
    789                         inline for (features) |feature| {
    790                             if (set.isEnabled(@enumToInt(@as(F, feature)))) return true;
    791                         }
    792                         return false;
    793                     }
    794 
    795                     /// Returns true if every specified feature is enabled.
    796                     pub fn featureSetHasAll(set: Set, features: anytype) bool {
    797                         comptime std.debug.assert(std.meta.trait.isIndexable(@TypeOf(features)));
    798                         inline for (features) |feature| {
    799                             if (!set.isEnabled(@enumToInt(@as(F, feature)))) return false;
    800                         }
    801                         return true;
    802                     }
    803                 };
    804             }
    805         };
    806 
    807         pub const Arch = enum {
    808             arm,
    809             armeb,
    810             aarch64,
    811             aarch64_be,
    812             aarch64_32,
    813             arc,
    814             avr,
    815             bpfel,
    816             bpfeb,
    817             csky,
    818             dxil,
    819             hexagon,
    820             loongarch32,
    821             loongarch64,
    822             m68k,
    823             mips,
    824             mipsel,
    825             mips64,
    826             mips64el,
    827             msp430,
    828             powerpc,
    829             powerpcle,
    830             powerpc64,
    831             powerpc64le,
    832             r600,
    833             amdgcn,
    834             riscv32,
    835             riscv64,
    836             sparc,
    837             sparc64,
    838             sparcel,
    839             s390x,
    840             tce,
    841             tcele,
    842             thumb,
    843             thumbeb,
    844             x86,
    845             x86_64,
    846             xcore,
    847             nvptx,
    848             nvptx64,
    849             le32,
    850             le64,
    851             amdil,
    852             amdil64,
    853             hsail,
    854             hsail64,
    855             spir,
    856             spir64,
    857             spirv32,
    858             spirv64,
    859             kalimba,
    860             shave,
    861             lanai,
    862             wasm32,
    863             wasm64,
    864             renderscript32,
    865             renderscript64,
    866             ve,
    867             // Stage1 currently assumes that architectures above this comment
    868             // map one-to-one with the ZigLLVM_ArchType enum.
    869             spu_2,
    870 
    871             pub fn isX86(arch: Arch) bool {
    872                 return switch (arch) {
    873                     .x86, .x86_64 => true,
    874                     else => false,
    875                 };
    876             }
    877 
    878             pub fn isARM(arch: Arch) bool {
    879                 return switch (arch) {
    880                     .arm, .armeb => true,
    881                     else => false,
    882                 };
    883             }
    884 
    885             pub fn isAARCH64(arch: Arch) bool {
    886                 return switch (arch) {
    887                     .aarch64, .aarch64_be, .aarch64_32 => true,
    888                     else => false,
    889                 };
    890             }
    891 
    892             pub fn isThumb(arch: Arch) bool {
    893                 return switch (arch) {
    894                     .thumb, .thumbeb => true,
    895                     else => false,
    896                 };
    897             }
    898 
    899             pub fn isWasm(arch: Arch) bool {
    900                 return switch (arch) {
    901                     .wasm32, .wasm64 => true,
    902                     else => false,
    903                 };
    904             }
    905 
    906             pub fn isRISCV(arch: Arch) bool {
    907                 return switch (arch) {
    908                     .riscv32, .riscv64 => true,
    909                     else => false,
    910                 };
    911             }
    912 
    913             pub fn isMIPS(arch: Arch) bool {
    914                 return switch (arch) {
    915                     .mips, .mipsel, .mips64, .mips64el => true,
    916                     else => false,
    917                 };
    918             }
    919 
    920             pub fn isPPC(arch: Arch) bool {
    921                 return switch (arch) {
    922                     .powerpc, .powerpcle => true,
    923                     else => false,
    924                 };
    925             }
    926 
    927             pub fn isPPC64(arch: Arch) bool {
    928                 return switch (arch) {
    929                     .powerpc64, .powerpc64le => true,
    930                     else => false,
    931                 };
    932             }
    933 
    934             pub fn isSPARC(arch: Arch) bool {
    935                 return switch (arch) {
    936                     .sparc, .sparcel, .sparc64 => true,
    937                     else => false,
    938                 };
    939             }
    940 
    941             pub fn isSPIRV(arch: Arch) bool {
    942                 return switch (arch) {
    943                     .spirv32, .spirv64 => true,
    944                     else => false,
    945                 };
    946             }
    947 
    948             pub fn isBpf(arch: Arch) bool {
    949                 return switch (arch) {
    950                     .bpfel, .bpfeb => true,
    951                     else => false,
    952                 };
    953             }
    954 
    955             pub fn isNvptx(arch: Arch) bool {
    956                 return switch (arch) {
    957                     .nvptx, .nvptx64 => true,
    958                     else => false,
    959                 };
    960             }
    961 
    962             pub fn parseCpuModel(arch: Arch, cpu_name: []const u8) !*const Cpu.Model {
    963                 for (arch.allCpuModels()) |cpu| {
    964                     if (mem.eql(u8, cpu_name, cpu.name)) {
    965                         return cpu;
    966                     }
    967                 }
    968                 return error.UnknownCpuModel;
    969             }
    970 
    971             pub fn toElfMachine(arch: Arch) std.elf.EM {
    972                 return switch (arch) {
    973                     .avr => .AVR,
    974                     .msp430 => .MSP430,
    975                     .arc => .ARC,
    976                     .arm => .ARM,
    977                     .armeb => .ARM,
    978                     .hexagon => .HEXAGON,
    979                     .dxil => .NONE,
    980                     .m68k => .@"68K",
    981                     .le32 => .NONE,
    982                     .mips => .MIPS,
    983                     .mipsel => .MIPS_RS3_LE,
    984                     .powerpc, .powerpcle => .PPC,
    985                     .r600 => .NONE,
    986                     .riscv32 => .RISCV,
    987                     .sparc => .SPARC,
    988                     .sparcel => .SPARC,
    989                     .tce => .NONE,
    990                     .tcele => .NONE,
    991                     .thumb => .ARM,
    992                     .thumbeb => .ARM,
    993                     .x86 => .@"386",
    994                     .xcore => .XCORE,
    995                     .nvptx => .NONE,
    996                     .amdil => .NONE,
    997                     .hsail => .NONE,
    998                     .spir => .NONE,
    999                     .kalimba => .CSR_KALIMBA,
   1000                     .shave => .NONE,
   1001                     .lanai => .LANAI,
   1002                     .wasm32 => .NONE,
   1003                     .renderscript32 => .NONE,
   1004                     .aarch64_32 => .AARCH64,
   1005                     .aarch64 => .AARCH64,
   1006                     .aarch64_be => .AARCH64,
   1007                     .mips64 => .MIPS,
   1008                     .mips64el => .MIPS_RS3_LE,
   1009                     .powerpc64 => .PPC64,
   1010                     .powerpc64le => .PPC64,
   1011                     .riscv64 => .RISCV,
   1012                     .x86_64 => .X86_64,
   1013                     .nvptx64 => .NONE,
   1014                     .le64 => .NONE,
   1015                     .amdil64 => .NONE,
   1016                     .hsail64 => .NONE,
   1017                     .spir64 => .NONE,
   1018                     .wasm64 => .NONE,
   1019                     .renderscript64 => .NONE,
   1020                     .amdgcn => .NONE,
   1021                     .bpfel => .BPF,
   1022                     .bpfeb => .BPF,
   1023                     .csky => .CSKY,
   1024                     .sparc64 => .SPARCV9,
   1025                     .s390x => .S390,
   1026                     .ve => .NONE,
   1027                     .spu_2 => .SPU_2,
   1028                     .spirv32 => .NONE,
   1029                     .spirv64 => .NONE,
   1030                     .loongarch32 => .NONE,
   1031                     .loongarch64 => .NONE,
   1032                 };
   1033             }
   1034 
   1035             pub fn toCoffMachine(arch: Arch) std.coff.MachineType {
   1036                 return switch (arch) {
   1037                     .avr => .Unknown,
   1038                     .msp430 => .Unknown,
   1039                     .arc => .Unknown,
   1040                     .arm => .ARM,
   1041                     .armeb => .Unknown,
   1042                     .dxil => .Unknown,
   1043                     .hexagon => .Unknown,
   1044                     .m68k => .Unknown,
   1045                     .le32 => .Unknown,
   1046                     .mips => .Unknown,
   1047                     .mipsel => .Unknown,
   1048                     .powerpc, .powerpcle => .POWERPC,
   1049                     .r600 => .Unknown,
   1050                     .riscv32 => .RISCV32,
   1051                     .sparc => .Unknown,
   1052                     .sparcel => .Unknown,
   1053                     .tce => .Unknown,
   1054                     .tcele => .Unknown,
   1055                     .thumb => .Thumb,
   1056                     .thumbeb => .Thumb,
   1057                     .x86 => .I386,
   1058                     .xcore => .Unknown,
   1059                     .nvptx => .Unknown,
   1060                     .amdil => .Unknown,
   1061                     .hsail => .Unknown,
   1062                     .spir => .Unknown,
   1063                     .kalimba => .Unknown,
   1064                     .shave => .Unknown,
   1065                     .lanai => .Unknown,
   1066                     .wasm32 => .Unknown,
   1067                     .renderscript32 => .Unknown,
   1068                     .aarch64_32 => .ARM64,
   1069                     .aarch64 => .ARM64,
   1070                     .aarch64_be => .Unknown,
   1071                     .mips64 => .Unknown,
   1072                     .mips64el => .Unknown,
   1073                     .powerpc64 => .Unknown,
   1074                     .powerpc64le => .Unknown,
   1075                     .riscv64 => .RISCV64,
   1076                     .x86_64 => .X64,
   1077                     .nvptx64 => .Unknown,
   1078                     .le64 => .Unknown,
   1079                     .amdil64 => .Unknown,
   1080                     .hsail64 => .Unknown,
   1081                     .spir64 => .Unknown,
   1082                     .wasm64 => .Unknown,
   1083                     .renderscript64 => .Unknown,
   1084                     .amdgcn => .Unknown,
   1085                     .bpfel => .Unknown,
   1086                     .bpfeb => .Unknown,
   1087                     .csky => .Unknown,
   1088                     .sparc64 => .Unknown,
   1089                     .s390x => .Unknown,
   1090                     .ve => .Unknown,
   1091                     .spu_2 => .Unknown,
   1092                     .spirv32 => .Unknown,
   1093                     .spirv64 => .Unknown,
   1094                     .loongarch32 => .Unknown,
   1095                     .loongarch64 => .Unknown,
   1096                 };
   1097             }
   1098 
   1099             pub fn endian(arch: Arch) std.builtin.Endian {
   1100                 return switch (arch) {
   1101                     .avr,
   1102                     .arm,
   1103                     .aarch64_32,
   1104                     .aarch64,
   1105                     .amdgcn,
   1106                     .amdil,
   1107                     .amdil64,
   1108                     .bpfel,
   1109                     .csky,
   1110                     .hexagon,
   1111                     .hsail,
   1112                     .hsail64,
   1113                     .kalimba,
   1114                     .le32,
   1115                     .le64,
   1116                     .mipsel,
   1117                     .mips64el,
   1118                     .msp430,
   1119                     .nvptx,
   1120                     .nvptx64,
   1121                     .sparcel,
   1122                     .tcele,
   1123                     .powerpcle,
   1124                     .powerpc64le,
   1125                     .r600,
   1126                     .riscv32,
   1127                     .riscv64,
   1128                     .x86,
   1129                     .x86_64,
   1130                     .wasm32,
   1131                     .wasm64,
   1132                     .xcore,
   1133                     .thumb,
   1134                     .spir,
   1135                     .spir64,
   1136                     .renderscript32,
   1137                     .renderscript64,
   1138                     .shave,
   1139                     .ve,
   1140                     .spu_2,
   1141                     // GPU bitness is opaque. For now, assume little endian.
   1142                     .spirv32,
   1143                     .spirv64,
   1144                     .dxil,
   1145                     .loongarch32,
   1146                     .loongarch64,
   1147                     => .Little,
   1148 
   1149                     .arc,
   1150                     .armeb,
   1151                     .aarch64_be,
   1152                     .bpfeb,
   1153                     .m68k,
   1154                     .mips,
   1155                     .mips64,
   1156                     .powerpc,
   1157                     .powerpc64,
   1158                     .thumbeb,
   1159                     .sparc,
   1160                     .sparc64,
   1161                     .tce,
   1162                     .lanai,
   1163                     .s390x,
   1164                     => .Big,
   1165                 };
   1166             }
   1167 
   1168             /// Returns whether this architecture supports the address space
   1169             pub fn supportsAddressSpace(arch: Arch, address_space: std.builtin.AddressSpace) bool {
   1170                 const is_nvptx = arch == .nvptx or arch == .nvptx64;
   1171                 const is_spirv = arch == .spirv32 or arch == .spirv64;
   1172                 const is_gpu = is_nvptx or is_spirv or arch == .amdgcn;
   1173                 return switch (address_space) {
   1174                     .generic => true,
   1175                     .fs, .gs, .ss => arch == .x86_64 or arch == .x86,
   1176                     .global, .constant, .local, .shared => is_gpu,
   1177                     .param => is_nvptx,
   1178                     // TODO this should also check how many flash banks the cpu has
   1179                     .flash, .flash1, .flash2, .flash3, .flash4, .flash5 => arch == .avr,
   1180                 };
   1181             }
   1182 
   1183             pub fn ptrBitWidth(arch: Arch) u16 {
   1184                 switch (arch) {
   1185                     .avr,
   1186                     .msp430,
   1187                     .spu_2,
   1188                     => return 16,
   1189 
   1190                     .arc,
   1191                     .arm,
   1192                     .armeb,
   1193                     .csky,
   1194                     .hexagon,
   1195                     .m68k,
   1196                     .le32,
   1197                     .mips,
   1198                     .mipsel,
   1199                     .powerpc,
   1200                     .powerpcle,
   1201                     .r600,
   1202                     .riscv32,
   1203                     .sparc,
   1204                     .sparcel,
   1205                     .tce,
   1206                     .tcele,
   1207                     .thumb,
   1208                     .thumbeb,
   1209                     .x86,
   1210                     .xcore,
   1211                     .nvptx,
   1212                     .amdil,
   1213                     .hsail,
   1214                     .spir,
   1215                     .kalimba,
   1216                     .shave,
   1217                     .lanai,
   1218                     .wasm32,
   1219                     .renderscript32,
   1220                     .aarch64_32,
   1221                     .spirv32,
   1222                     .loongarch32,
   1223                     .dxil,
   1224                     => return 32,
   1225 
   1226                     .aarch64,
   1227                     .aarch64_be,
   1228                     .mips64,
   1229                     .mips64el,
   1230                     .powerpc64,
   1231                     .powerpc64le,
   1232                     .riscv64,
   1233                     .x86_64,
   1234                     .nvptx64,
   1235                     .le64,
   1236                     .amdil64,
   1237                     .hsail64,
   1238                     .spir64,
   1239                     .wasm64,
   1240                     .renderscript64,
   1241                     .amdgcn,
   1242                     .bpfel,
   1243                     .bpfeb,
   1244                     .sparc64,
   1245                     .s390x,
   1246                     .ve,
   1247                     .spirv64,
   1248                     .loongarch64,
   1249                     => return 64,
   1250                 }
   1251             }
   1252 
   1253             /// Returns a name that matches the lib/std/target/* source file name.
   1254             pub fn genericName(arch: Arch) []const u8 {
   1255                 return switch (arch) {
   1256                     .arm, .armeb, .thumb, .thumbeb => "arm",
   1257                     .aarch64, .aarch64_be, .aarch64_32 => "aarch64",
   1258                     .bpfel, .bpfeb => "bpf",
   1259                     .mips, .mipsel, .mips64, .mips64el => "mips",
   1260                     .powerpc, .powerpcle, .powerpc64, .powerpc64le => "powerpc",
   1261                     .amdgcn => "amdgpu",
   1262                     .riscv32, .riscv64 => "riscv",
   1263                     .sparc, .sparc64, .sparcel => "sparc",
   1264                     .s390x => "s390x",
   1265                     .x86, .x86_64 => "x86",
   1266                     .nvptx, .nvptx64 => "nvptx",
   1267                     .wasm32, .wasm64 => "wasm",
   1268                     .spirv32, .spirv64 => "spir-v",
   1269                     else => @tagName(arch),
   1270                 };
   1271             }
   1272 
   1273             /// All CPU features Zig is aware of, sorted lexicographically by name.
   1274             pub fn allFeaturesList(arch: Arch) []const Cpu.Feature {
   1275                 return switch (arch) {
   1276                     .arm, .armeb, .thumb, .thumbeb => &arm.all_features,
   1277                     .aarch64, .aarch64_be, .aarch64_32 => &aarch64.all_features,
   1278                     .avr => &avr.all_features,
   1279                     .bpfel, .bpfeb => &bpf.all_features,
   1280                     .hexagon => &hexagon.all_features,
   1281                     .mips, .mipsel, .mips64, .mips64el => &mips.all_features,
   1282                     .msp430 => &msp430.all_features,
   1283                     .powerpc, .powerpcle, .powerpc64, .powerpc64le => &powerpc.all_features,
   1284                     .amdgcn => &amdgpu.all_features,
   1285                     .riscv32, .riscv64 => &riscv.all_features,
   1286                     .sparc, .sparc64, .sparcel => &sparc.all_features,
   1287                     .spirv32, .spirv64 => &spirv.all_features,
   1288                     .s390x => &s390x.all_features,
   1289                     .x86, .x86_64 => &x86.all_features,
   1290                     .nvptx, .nvptx64 => &nvptx.all_features,
   1291                     .ve => &ve.all_features,
   1292                     .wasm32, .wasm64 => &wasm.all_features,
   1293 
   1294                     else => &[0]Cpu.Feature{},
   1295                 };
   1296             }
   1297 
   1298             /// All processors Zig is aware of, sorted lexicographically by name.
   1299             pub fn allCpuModels(arch: Arch) []const *const Cpu.Model {
   1300                 return switch (arch) {
   1301                     .arm, .armeb, .thumb, .thumbeb => comptime allCpusFromDecls(arm.cpu),
   1302                     .aarch64, .aarch64_be, .aarch64_32 => comptime allCpusFromDecls(aarch64.cpu),
   1303                     .avr => comptime allCpusFromDecls(avr.cpu),
   1304                     .bpfel, .bpfeb => comptime allCpusFromDecls(bpf.cpu),
   1305                     .hexagon => comptime allCpusFromDecls(hexagon.cpu),
   1306                     .mips, .mipsel, .mips64, .mips64el => comptime allCpusFromDecls(mips.cpu),
   1307                     .msp430 => comptime allCpusFromDecls(msp430.cpu),
   1308                     .powerpc, .powerpcle, .powerpc64, .powerpc64le => comptime allCpusFromDecls(powerpc.cpu),
   1309                     .amdgcn => comptime allCpusFromDecls(amdgpu.cpu),
   1310                     .riscv32, .riscv64 => comptime allCpusFromDecls(riscv.cpu),
   1311                     .sparc, .sparc64, .sparcel => comptime allCpusFromDecls(sparc.cpu),
   1312                     .s390x => comptime allCpusFromDecls(s390x.cpu),
   1313                     .x86, .x86_64 => comptime allCpusFromDecls(x86.cpu),
   1314                     .nvptx, .nvptx64 => comptime allCpusFromDecls(nvptx.cpu),
   1315                     .ve => comptime allCpusFromDecls(ve.cpu),
   1316                     .wasm32, .wasm64 => comptime allCpusFromDecls(wasm.cpu),
   1317 
   1318                     else => &[0]*const Model{},
   1319                 };
   1320             }
   1321 
   1322             fn allCpusFromDecls(comptime cpus: type) []const *const Cpu.Model {
   1323                 const decls = @typeInfo(cpus).Struct.decls;
   1324                 var array: [decls.len]*const Cpu.Model = undefined;
   1325                 for (decls, 0..) |decl, i| {
   1326                     array[i] = &@field(cpus, decl.name);
   1327                 }
   1328                 return &array;
   1329             }
   1330         };
   1331 
   1332         pub const Model = struct {
   1333             name: []const u8,
   1334             llvm_name: ?[:0]const u8,
   1335             features: Feature.Set,
   1336 
   1337             pub fn toCpu(model: *const Model, arch: Arch) Cpu {
   1338                 var features = model.features;
   1339                 features.populateDependencies(arch.allFeaturesList());
   1340                 return .{
   1341                     .arch = arch,
   1342                     .model = model,
   1343                     .features = features,
   1344                 };
   1345             }
   1346 
   1347             pub fn generic(arch: Arch) *const Model {
   1348                 const S = struct {
   1349                     const generic_model = Model{
   1350                         .name = "generic",
   1351                         .llvm_name = null,
   1352                         .features = Cpu.Feature.Set.empty,
   1353                     };
   1354                 };
   1355                 return switch (arch) {
   1356                     .arm, .armeb, .thumb, .thumbeb => &arm.cpu.generic,
   1357                     .aarch64, .aarch64_be, .aarch64_32 => &aarch64.cpu.generic,
   1358                     .avr => &avr.cpu.avr2,
   1359                     .bpfel, .bpfeb => &bpf.cpu.generic,
   1360                     .hexagon => &hexagon.cpu.generic,
   1361                     .m68k => &m68k.cpu.generic,
   1362                     .mips, .mipsel => &mips.cpu.mips32,
   1363                     .mips64, .mips64el => &mips.cpu.mips64,
   1364                     .msp430 => &msp430.cpu.generic,
   1365                     .powerpc => &powerpc.cpu.ppc,
   1366                     .powerpcle => &powerpc.cpu.ppc,
   1367                     .powerpc64 => &powerpc.cpu.ppc64,
   1368                     .powerpc64le => &powerpc.cpu.ppc64le,
   1369                     .amdgcn => &amdgpu.cpu.generic,
   1370                     .riscv32 => &riscv.cpu.generic_rv32,
   1371                     .riscv64 => &riscv.cpu.generic_rv64,
   1372                     .sparc, .sparcel => &sparc.cpu.generic,
   1373                     .sparc64 => &sparc.cpu.v9, // 64-bit SPARC needs v9 as the baseline
   1374                     .s390x => &s390x.cpu.generic,
   1375                     .x86 => &x86.cpu.i386,
   1376                     .x86_64 => &x86.cpu.x86_64,
   1377                     .nvptx, .nvptx64 => &nvptx.cpu.sm_20,
   1378                     .ve => &ve.cpu.generic,
   1379                     .wasm32, .wasm64 => &wasm.cpu.generic,
   1380 
   1381                     else => &S.generic_model,
   1382                 };
   1383             }
   1384 
   1385             pub fn baseline(arch: Arch) *const Model {
   1386                 return switch (arch) {
   1387                     .arm, .armeb, .thumb, .thumbeb => &arm.cpu.baseline,
   1388                     .riscv32 => &riscv.cpu.baseline_rv32,
   1389                     .riscv64 => &riscv.cpu.baseline_rv64,
   1390                     .x86 => &x86.cpu.pentium4,
   1391                     .nvptx, .nvptx64 => &nvptx.cpu.sm_20,
   1392                     .sparc, .sparcel => &sparc.cpu.v8,
   1393 
   1394                     else => generic(arch),
   1395                 };
   1396             }
   1397         };
   1398 
   1399         /// The "default" set of CPU features for cross-compiling. A conservative set
   1400         /// of features that is expected to be supported on most available hardware.
   1401         pub fn baseline(arch: Arch) Cpu {
   1402             return Model.baseline(arch).toCpu(arch);
   1403         }
   1404     };
   1405 
   1406     pub const stack_align = 16;
   1407 
   1408     pub fn zigTriple(self: Target, allocator: mem.Allocator) ![]u8 {
   1409         return std.zig.CrossTarget.fromTarget(self).zigTriple(allocator);
   1410     }
   1411 
   1412     pub fn linuxTripleSimple(allocator: mem.Allocator, cpu_arch: Cpu.Arch, os_tag: Os.Tag, abi: Abi) ![]u8 {
   1413         return std.fmt.allocPrint(allocator, "{s}-{s}-{s}", .{ @tagName(cpu_arch), @tagName(os_tag), @tagName(abi) });
   1414     }
   1415 
   1416     pub fn linuxTriple(self: Target, allocator: mem.Allocator) ![]u8 {
   1417         return linuxTripleSimple(allocator, self.cpu.arch, self.os.tag, self.abi);
   1418     }
   1419 
   1420     pub fn exeFileExtSimple(cpu_arch: Cpu.Arch, os_tag: Os.Tag) [:0]const u8 {
   1421         return switch (os_tag) {
   1422             .windows => ".exe",
   1423             .uefi => ".efi",
   1424             .plan9 => plan9Ext(cpu_arch),
   1425             else => switch (cpu_arch) {
   1426                 .wasm32, .wasm64 => ".wasm",
   1427                 else => "",
   1428             },
   1429         };
   1430     }
   1431 
   1432     pub fn exeFileExt(self: Target) [:0]const u8 {
   1433         return exeFileExtSimple(self.cpu.arch, self.os.tag);
   1434     }
   1435 
   1436     pub fn staticLibSuffix_os_abi(os_tag: Os.Tag, abi: Abi) [:0]const u8 {
   1437         if (abi == .msvc) {
   1438             return ".lib";
   1439         }
   1440         switch (os_tag) {
   1441             .windows, .uefi => return ".lib",
   1442             else => return ".a",
   1443         }
   1444     }
   1445 
   1446     pub fn staticLibSuffix(self: Target) [:0]const u8 {
   1447         return staticLibSuffix_os_abi(self.os.tag, self.abi);
   1448     }
   1449 
   1450     pub fn dynamicLibSuffix(self: Target) [:0]const u8 {
   1451         return self.os.tag.dynamicLibSuffix();
   1452     }
   1453 
   1454     pub fn libPrefix_os_abi(os_tag: Os.Tag, abi: Abi) [:0]const u8 {
   1455         if (abi == .msvc) {
   1456             return "";
   1457         }
   1458         switch (os_tag) {
   1459             .windows, .uefi => return "",
   1460             else => return "lib",
   1461         }
   1462     }
   1463 
   1464     pub fn libPrefix(self: Target) [:0]const u8 {
   1465         return libPrefix_os_abi(self.os.tag, self.abi);
   1466     }
   1467 
   1468     pub fn isMinGW(self: Target) bool {
   1469         return self.os.tag == .windows and self.isGnu();
   1470     }
   1471 
   1472     pub fn isGnu(self: Target) bool {
   1473         return self.abi.isGnu();
   1474     }
   1475 
   1476     pub fn isMusl(self: Target) bool {
   1477         return self.abi.isMusl();
   1478     }
   1479 
   1480     pub fn isAndroid(self: Target) bool {
   1481         return self.abi == .android;
   1482     }
   1483 
   1484     pub fn isWasm(self: Target) bool {
   1485         return self.cpu.arch.isWasm();
   1486     }
   1487 
   1488     pub fn isDarwin(self: Target) bool {
   1489         return self.os.tag.isDarwin();
   1490     }
   1491 
   1492     pub fn isBSD(self: Target) bool {
   1493         return self.os.tag.isBSD();
   1494     }
   1495 
   1496     pub fn isBpfFreestanding(self: Target) bool {
   1497         return self.cpu.arch.isBpf() and self.os.tag == .freestanding;
   1498     }
   1499 
   1500     pub fn isGnuLibC_os_tag_abi(os_tag: Os.Tag, abi: Abi) bool {
   1501         return os_tag == .linux and abi.isGnu();
   1502     }
   1503 
   1504     pub fn isGnuLibC(self: Target) bool {
   1505         return isGnuLibC_os_tag_abi(self.os.tag, self.abi);
   1506     }
   1507 
   1508     pub fn supportsNewStackCall(self: Target) bool {
   1509         return !self.cpu.arch.isWasm();
   1510     }
   1511 
   1512     pub const FloatAbi = enum {
   1513         hard,
   1514         soft,
   1515         soft_fp,
   1516     };
   1517 
   1518     pub fn getFloatAbi(self: Target) FloatAbi {
   1519         return self.abi.floatAbi();
   1520     }
   1521 
   1522     pub fn hasDynamicLinker(self: Target) bool {
   1523         if (self.cpu.arch.isWasm()) {
   1524             return false;
   1525         }
   1526         switch (self.os.tag) {
   1527             .freestanding,
   1528             .ios,
   1529             .tvos,
   1530             .watchos,
   1531             .macos,
   1532             .uefi,
   1533             .windows,
   1534             .emscripten,
   1535             .opencl,
   1536             .glsl450,
   1537             .vulkan,
   1538             .plan9,
   1539             .other,
   1540             => return false,
   1541             else => return true,
   1542         }
   1543     }
   1544 
   1545     pub const DynamicLinker = struct {
   1546         /// Contains the memory used to store the dynamic linker path. This field should
   1547         /// not be used directly. See `get` and `set`. This field exists so that this API requires no allocator.
   1548         buffer: [255]u8 = undefined,
   1549 
   1550         /// Used to construct the dynamic linker path. This field should not be used
   1551         /// directly. See `get` and `set`.
   1552         max_byte: ?u8 = null,
   1553 
   1554         /// Asserts that the length is less than or equal to 255 bytes.
   1555         pub fn init(dl_or_null: ?[]const u8) DynamicLinker {
   1556             var result: DynamicLinker = undefined;
   1557             result.set(dl_or_null);
   1558             return result;
   1559         }
   1560 
   1561         /// The returned memory has the same lifetime as the `DynamicLinker`.
   1562         pub fn get(self: *const DynamicLinker) ?[]const u8 {
   1563             const m: usize = self.max_byte orelse return null;
   1564             return self.buffer[0 .. m + 1];
   1565         }
   1566 
   1567         /// Asserts that the length is less than or equal to 255 bytes.
   1568         pub fn set(self: *DynamicLinker, dl_or_null: ?[]const u8) void {
   1569             if (dl_or_null) |dl| {
   1570                 mem.copy(u8, &self.buffer, dl);
   1571                 self.max_byte = @intCast(u8, dl.len - 1);
   1572             } else {
   1573                 self.max_byte = null;
   1574             }
   1575         }
   1576     };
   1577 
   1578     pub fn standardDynamicLinkerPath(self: Target) DynamicLinker {
   1579         var result: DynamicLinker = .{};
   1580         const S = struct {
   1581             fn print(r: *DynamicLinker, comptime fmt: []const u8, args: anytype) DynamicLinker {
   1582                 r.max_byte = @intCast(u8, (std.fmt.bufPrint(&r.buffer, fmt, args) catch unreachable).len - 1);
   1583                 return r.*;
   1584             }
   1585             fn copy(r: *DynamicLinker, s: []const u8) DynamicLinker {
   1586                 mem.copy(u8, &r.buffer, s);
   1587                 r.max_byte = @intCast(u8, s.len - 1);
   1588                 return r.*;
   1589             }
   1590         };
   1591         const print = S.print;
   1592         const copy = S.copy;
   1593 
   1594         if (self.abi == .android) {
   1595             const suffix = if (self.cpu.arch.ptrBitWidth() == 64) "64" else "";
   1596             return print(&result, "/system/bin/linker{s}", .{suffix});
   1597         }
   1598 
   1599         if (self.abi.isMusl()) {
   1600             const is_arm = switch (self.cpu.arch) {
   1601                 .arm, .armeb, .thumb, .thumbeb => true,
   1602                 else => false,
   1603             };
   1604             const arch_part = switch (self.cpu.arch) {
   1605                 .arm, .thumb => "arm",
   1606                 .armeb, .thumbeb => "armeb",
   1607                 else => |arch| @tagName(arch),
   1608             };
   1609             const arch_suffix = if (is_arm and self.abi.floatAbi() == .hard) "hf" else "";
   1610             return print(&result, "/lib/ld-musl-{s}{s}.so.1", .{ arch_part, arch_suffix });
   1611         }
   1612 
   1613         switch (self.os.tag) {
   1614             .freebsd => return copy(&result, "/libexec/ld-elf.so.1"),
   1615             .netbsd => return copy(&result, "/libexec/ld.elf_so"),
   1616             .openbsd => return copy(&result, "/usr/libexec/ld.so"),
   1617             .dragonfly => return copy(&result, "/libexec/ld-elf.so.2"),
   1618             .solaris => return copy(&result, "/lib/64/ld.so.1"),
   1619             .linux => switch (self.cpu.arch) {
   1620                 .x86,
   1621                 .sparc,
   1622                 .sparcel,
   1623                 => return copy(&result, "/lib/ld-linux.so.2"),
   1624 
   1625                 .aarch64 => return copy(&result, "/lib/ld-linux-aarch64.so.1"),
   1626                 .aarch64_be => return copy(&result, "/lib/ld-linux-aarch64_be.so.1"),
   1627                 .aarch64_32 => return copy(&result, "/lib/ld-linux-aarch64_32.so.1"),
   1628 
   1629                 .arm,
   1630                 .armeb,
   1631                 .thumb,
   1632                 .thumbeb,
   1633                 => return copy(&result, switch (self.abi.floatAbi()) {
   1634                     .hard => "/lib/ld-linux-armhf.so.3",
   1635                     else => "/lib/ld-linux.so.3",
   1636                 }),
   1637 
   1638                 .mips,
   1639                 .mipsel,
   1640                 .mips64,
   1641                 .mips64el,
   1642                 => {
   1643                     const lib_suffix = switch (self.abi) {
   1644                         .gnuabin32, .gnux32 => "32",
   1645                         .gnuabi64 => "64",
   1646                         else => "",
   1647                     };
   1648                     const is_nan_2008 = mips.featureSetHas(self.cpu.features, .nan2008);
   1649                     const loader = if (is_nan_2008) "ld-linux-mipsn8.so.1" else "ld.so.1";
   1650                     return print(&result, "/lib{s}/{s}", .{ lib_suffix, loader });
   1651                 },
   1652 
   1653                 .powerpc, .powerpcle => return copy(&result, "/lib/ld.so.1"),
   1654                 .powerpc64, .powerpc64le => return copy(&result, "/lib64/ld64.so.2"),
   1655                 .s390x => return copy(&result, "/lib64/ld64.so.1"),
   1656                 .sparc64 => return copy(&result, "/lib64/ld-linux.so.2"),
   1657                 .x86_64 => return copy(&result, switch (self.abi) {
   1658                     .gnux32 => "/libx32/ld-linux-x32.so.2",
   1659                     else => "/lib64/ld-linux-x86-64.so.2",
   1660                 }),
   1661 
   1662                 .riscv32 => return copy(&result, "/lib/ld-linux-riscv32-ilp32.so.1"),
   1663                 .riscv64 => return copy(&result, "/lib/ld-linux-riscv64-lp64.so.1"),
   1664 
   1665                 // Architectures in this list have been verified as not having a standard
   1666                 // dynamic linker path.
   1667                 .wasm32,
   1668                 .wasm64,
   1669                 .bpfel,
   1670                 .bpfeb,
   1671                 .nvptx,
   1672                 .nvptx64,
   1673                 .spu_2,
   1674                 .avr,
   1675                 .spirv32,
   1676                 .spirv64,
   1677                 => return result,
   1678 
   1679                 // TODO go over each item in this list and either move it to the above list, or
   1680                 // implement the standard dynamic linker path code for it.
   1681                 .arc,
   1682                 .csky,
   1683                 .hexagon,
   1684                 .m68k,
   1685                 .msp430,
   1686                 .r600,
   1687                 .amdgcn,
   1688                 .tce,
   1689                 .tcele,
   1690                 .xcore,
   1691                 .le32,
   1692                 .le64,
   1693                 .amdil,
   1694                 .amdil64,
   1695                 .hsail,
   1696                 .hsail64,
   1697                 .spir,
   1698                 .spir64,
   1699                 .kalimba,
   1700                 .shave,
   1701                 .lanai,
   1702                 .renderscript32,
   1703                 .renderscript64,
   1704                 .ve,
   1705                 .dxil,
   1706                 .loongarch32,
   1707                 .loongarch64,
   1708                 => return result,
   1709             },
   1710 
   1711             .ios,
   1712             .tvos,
   1713             .watchos,
   1714             .macos,
   1715             => return copy(&result, "/usr/lib/dyld"),
   1716 
   1717             // Operating systems in this list have been verified as not having a standard
   1718             // dynamic linker path.
   1719             .freestanding,
   1720             .uefi,
   1721             .windows,
   1722             .emscripten,
   1723             .wasi,
   1724             .opencl,
   1725             .glsl450,
   1726             .vulkan,
   1727             .other,
   1728             .plan9,
   1729             => return result,
   1730 
   1731             // TODO revisit when multi-arch for Haiku is available
   1732             .haiku => return copy(&result, "/system/runtime_loader"),
   1733 
   1734             // TODO go over each item in this list and either move it to the above list, or
   1735             // implement the standard dynamic linker path code for it.
   1736             .ananas,
   1737             .cloudabi,
   1738             .fuchsia,
   1739             .kfreebsd,
   1740             .lv2,
   1741             .zos,
   1742             .minix,
   1743             .rtems,
   1744             .nacl,
   1745             .aix,
   1746             .cuda,
   1747             .nvcl,
   1748             .amdhsa,
   1749             .ps4,
   1750             .ps5,
   1751             .elfiamcu,
   1752             .mesa3d,
   1753             .contiki,
   1754             .amdpal,
   1755             .hermit,
   1756             .hurd,
   1757             .driverkit,
   1758             .shadermodel,
   1759             => return result,
   1760         }
   1761     }
   1762 
   1763     /// 0c spim    little-endian MIPS 3000 family
   1764     /// 1c 68000   Motorola MC68000
   1765     /// 2c 68020   Motorola MC68020
   1766     /// 5c arm     little-endian ARM
   1767     /// 6c amd64   AMD64 and compatibles (e.g., Intel EM64T)
   1768     /// 7c arm64   ARM64 (ARMv8)
   1769     /// 8c 386     Intel x86, i486, Pentium, etc.
   1770     /// kc sparc   Sun SPARC
   1771     /// qc power   Power PC
   1772     /// vc mips    big-endian MIPS 3000 family
   1773     pub fn plan9Ext(cpu_arch: Cpu.Arch) [:0]const u8 {
   1774         return switch (cpu_arch) {
   1775             .arm => ".5",
   1776             .x86_64 => ".6",
   1777             .aarch64 => ".7",
   1778             .x86 => ".8",
   1779             .sparc => ".k",
   1780             .powerpc, .powerpcle => ".q",
   1781             .mips, .mipsel => ".v",
   1782             // ISAs without designated characters get 'X' for lack of a better option.
   1783             else => ".X",
   1784         };
   1785     }
   1786 
   1787     pub inline fn maxIntAlignment(target: Target) u16 {
   1788         return switch (target.cpu.arch) {
   1789             .avr => 1,
   1790             .msp430 => 2,
   1791             .xcore => 4,
   1792 
   1793             .arm,
   1794             .armeb,
   1795             .thumb,
   1796             .thumbeb,
   1797             .hexagon,
   1798             .mips,
   1799             .mipsel,
   1800             .powerpc,
   1801             .powerpcle,
   1802             .r600,
   1803             .amdgcn,
   1804             .riscv32,
   1805             .sparc,
   1806             .sparcel,
   1807             .s390x,
   1808             .lanai,
   1809             .wasm32,
   1810             .wasm64,
   1811             => 8,
   1812 
   1813             .x86 => if (target.ofmt == .c) 16 else return switch (target.os.tag) {
   1814                 .windows, .uefi => 8,
   1815                 else => 4,
   1816             },
   1817 
   1818             // For these, LLVMABIAlignmentOfType(i128) reports 8. Note that 16
   1819             // is a relevant number in three cases:
   1820             // 1. Different machine code instruction when loading into SIMD register.
   1821             // 2. The C ABI wants 16 for extern structs.
   1822             // 3. 16-byte cmpxchg needs 16-byte alignment.
   1823             // Same logic for powerpc64, mips64, sparc64.
   1824             .x86_64,
   1825             .powerpc64,
   1826             .powerpc64le,
   1827             .mips64,
   1828             .mips64el,
   1829             .sparc64,
   1830             => return switch (target.ofmt) {
   1831                 .c => 16,
   1832                 else => 8,
   1833             },
   1834 
   1835             // Even LLVMABIAlignmentOfType(i128) agrees on these targets.
   1836             .aarch64,
   1837             .aarch64_be,
   1838             .aarch64_32,
   1839             .riscv64,
   1840             .bpfel,
   1841             .bpfeb,
   1842             .nvptx,
   1843             .nvptx64,
   1844             => 16,
   1845 
   1846             // Below this comment are unverified but based on the fact that C requires
   1847             // int128_t to be 16 bytes aligned, it's a safe default.
   1848             .spu_2,
   1849             .csky,
   1850             .arc,
   1851             .m68k,
   1852             .tce,
   1853             .tcele,
   1854             .le32,
   1855             .amdil,
   1856             .hsail,
   1857             .spir,
   1858             .kalimba,
   1859             .renderscript32,
   1860             .spirv32,
   1861             .shave,
   1862             .le64,
   1863             .amdil64,
   1864             .hsail64,
   1865             .spir64,
   1866             .renderscript64,
   1867             .ve,
   1868             .spirv64,
   1869             .dxil,
   1870             .loongarch32,
   1871             .loongarch64,
   1872             => 16,
   1873         };
   1874     }
   1875 
   1876     pub const CType = enum {
   1877         short,
   1878         ushort,
   1879         int,
   1880         uint,
   1881         long,
   1882         ulong,
   1883         longlong,
   1884         ulonglong,
   1885         float,
   1886         double,
   1887         longdouble,
   1888     };
   1889 
   1890     pub fn c_type_byte_size(t: Target, c_type: CType) u16 {
   1891         return switch (c_type) {
   1892             .short,
   1893             .ushort,
   1894             .int,
   1895             .uint,
   1896             .long,
   1897             .ulong,
   1898             .longlong,
   1899             .ulonglong,
   1900             => @divExact(c_type_bit_size(t, c_type), 8),
   1901 
   1902             .float => 4,
   1903             .double => 8,
   1904 
   1905             .longdouble => switch (c_type_bit_size(t, c_type)) {
   1906                 16 => 2,
   1907                 32 => 4,
   1908                 64 => 8,
   1909                 80 => @intCast(u16, mem.alignForward(10, c_type_alignment(t, .longdouble))),
   1910                 128 => 16,
   1911                 else => unreachable,
   1912             },
   1913         };
   1914     }
   1915 
   1916     pub fn c_type_bit_size(target: Target, c_type: CType) u16 {
   1917         switch (target.os.tag) {
   1918             .freestanding, .other => switch (target.cpu.arch) {
   1919                 .msp430 => switch (c_type) {
   1920                     .short, .ushort, .int, .uint => return 16,
   1921                     .float, .long, .ulong => return 32,
   1922                     .longlong, .ulonglong, .double, .longdouble => return 64,
   1923                 },
   1924                 .avr => switch (c_type) {
   1925                     .short, .ushort, .int, .uint => return 16,
   1926                     .long, .ulong, .float, .double, .longdouble => return 32,
   1927                     .longlong, .ulonglong => return 64,
   1928                 },
   1929                 .tce, .tcele => switch (c_type) {
   1930                     .short, .ushort => return 16,
   1931                     .int, .uint, .long, .ulong, .longlong, .ulonglong => return 32,
   1932                     .float, .double, .longdouble => return 32,
   1933                 },
   1934                 .mips64, .mips64el => switch (c_type) {
   1935                     .short, .ushort => return 16,
   1936                     .int, .uint, .float => return 32,
   1937                     .long, .ulong => return if (target.abi != .gnuabin32) 64 else 32,
   1938                     .longlong, .ulonglong, .double => return 64,
   1939                     .longdouble => return 128,
   1940                 },
   1941                 .x86_64 => switch (c_type) {
   1942                     .short, .ushort => return 16,
   1943                     .int, .uint, .float => return 32,
   1944                     .long, .ulong => switch (target.abi) {
   1945                         .gnux32, .muslx32 => return 32,
   1946                         else => return 64,
   1947                     },
   1948                     .longlong, .ulonglong, .double => return 64,
   1949                     .longdouble => return 80,
   1950                 },
   1951                 else => switch (c_type) {
   1952                     .short, .ushort => return 16,
   1953                     .int, .uint, .float => return 32,
   1954                     .long, .ulong => return target.cpu.arch.ptrBitWidth(),
   1955                     .longlong, .ulonglong, .double => return 64,
   1956                     .longdouble => switch (target.cpu.arch) {
   1957                         .x86 => switch (target.abi) {
   1958                             .android => return 64,
   1959                             else => return 80,
   1960                         },
   1961 
   1962                         .powerpc,
   1963                         .powerpcle,
   1964                         .powerpc64,
   1965                         .powerpc64le,
   1966                         => switch (target.abi) {
   1967                             .musl,
   1968                             .musleabi,
   1969                             .musleabihf,
   1970                             .muslx32,
   1971                             => return 64,
   1972                             else => return 128,
   1973                         },
   1974 
   1975                         .riscv32,
   1976                         .riscv64,
   1977                         .aarch64,
   1978                         .aarch64_be,
   1979                         .aarch64_32,
   1980                         .s390x,
   1981                         .sparc,
   1982                         .sparc64,
   1983                         .sparcel,
   1984                         .wasm32,
   1985                         .wasm64,
   1986                         => return 128,
   1987 
   1988                         else => return 64,
   1989                     },
   1990                 },
   1991             },
   1992 
   1993             .linux,
   1994             .freebsd,
   1995             .netbsd,
   1996             .dragonfly,
   1997             .openbsd,
   1998             .wasi,
   1999             .emscripten,
   2000             .plan9,
   2001             .solaris,
   2002             .haiku,
   2003             .ananas,
   2004             .fuchsia,
   2005             .minix,
   2006             => switch (target.cpu.arch) {
   2007                 .msp430 => switch (c_type) {
   2008                     .short, .ushort, .int, .uint => return 16,
   2009                     .long, .ulong, .float => return 32,
   2010                     .longlong, .ulonglong, .double, .longdouble => return 64,
   2011                 },
   2012                 .avr => switch (c_type) {
   2013                     .short, .ushort, .int, .uint => return 16,
   2014                     .long, .ulong, .float, .double, .longdouble => return 32,
   2015                     .longlong, .ulonglong => return 64,
   2016                 },
   2017                 .tce, .tcele => switch (c_type) {
   2018                     .short, .ushort => return 16,
   2019                     .int, .uint, .long, .ulong, .longlong, .ulonglong => return 32,
   2020                     .float, .double, .longdouble => return 32,
   2021                 },
   2022                 .mips64, .mips64el => switch (c_type) {
   2023                     .short, .ushort => return 16,
   2024                     .int, .uint, .float => return 32,
   2025                     .long, .ulong => return if (target.abi != .gnuabin32) 64 else 32,
   2026                     .longlong, .ulonglong, .double => return 64,
   2027                     .longdouble => if (target.os.tag == .freebsd) return 64 else return 128,
   2028                 },
   2029                 .x86_64 => switch (c_type) {
   2030                     .short, .ushort => return 16,
   2031                     .int, .uint, .float => return 32,
   2032                     .long, .ulong => switch (target.abi) {
   2033                         .gnux32, .muslx32 => return 32,
   2034                         else => return 64,
   2035                     },
   2036                     .longlong, .ulonglong, .double => return 64,
   2037                     .longdouble => return 80,
   2038                 },
   2039                 else => switch (c_type) {
   2040                     .short, .ushort => return 16,
   2041                     .int, .uint, .float => return 32,
   2042                     .long, .ulong => return target.cpu.arch.ptrBitWidth(),
   2043                     .longlong, .ulonglong, .double => return 64,
   2044                     .longdouble => switch (target.cpu.arch) {
   2045                         .x86 => switch (target.abi) {
   2046                             .android => return 64,
   2047                             else => return 80,
   2048                         },
   2049 
   2050                         .powerpc,
   2051                         .powerpcle,
   2052                         => switch (target.abi) {
   2053                             .musl,
   2054                             .musleabi,
   2055                             .musleabihf,
   2056                             .muslx32,
   2057                             => return 64,
   2058                             else => switch (target.os.tag) {
   2059                                 .freebsd, .netbsd, .openbsd => return 64,
   2060                                 else => return 128,
   2061                             },
   2062                         },
   2063 
   2064                         .powerpc64,
   2065                         .powerpc64le,
   2066                         => switch (target.abi) {
   2067                             .musl,
   2068                             .musleabi,
   2069                             .musleabihf,
   2070                             .muslx32,
   2071                             => return 64,
   2072                             else => switch (target.os.tag) {
   2073                                 .freebsd, .openbsd => return 64,
   2074                                 else => return 128,
   2075                             },
   2076                         },
   2077 
   2078                         .riscv32,
   2079                         .riscv64,
   2080                         .aarch64,
   2081                         .aarch64_be,
   2082                         .aarch64_32,
   2083                         .s390x,
   2084                         .mips64,
   2085                         .mips64el,
   2086                         .sparc,
   2087                         .sparc64,
   2088                         .sparcel,
   2089                         .wasm32,
   2090                         .wasm64,
   2091                         => return 128,
   2092 
   2093                         else => return 64,
   2094                     },
   2095                 },
   2096             },
   2097 
   2098             .windows, .uefi => switch (target.cpu.arch) {
   2099                 .x86 => switch (c_type) {
   2100                     .short, .ushort => return 16,
   2101                     .int, .uint, .float => return 32,
   2102                     .long, .ulong => return 32,
   2103                     .longlong, .ulonglong, .double => return 64,
   2104                     .longdouble => switch (target.abi) {
   2105                         .gnu, .gnuilp32, .cygnus => return 80,
   2106                         else => return 64,
   2107                     },
   2108                 },
   2109                 .x86_64 => switch (c_type) {
   2110                     .short, .ushort => return 16,
   2111                     .int, .uint, .float => return 32,
   2112                     .long, .ulong => switch (target.abi) {
   2113                         .cygnus => return 64,
   2114                         else => return 32,
   2115                     },
   2116                     .longlong, .ulonglong, .double => return 64,
   2117                     .longdouble => switch (target.abi) {
   2118                         .gnu, .gnuilp32, .cygnus => return 80,
   2119                         else => return 64,
   2120                     },
   2121                 },
   2122                 else => switch (c_type) {
   2123                     .short, .ushort => return 16,
   2124                     .int, .uint, .float => return 32,
   2125                     .long, .ulong => return 32,
   2126                     .longlong, .ulonglong, .double => return 64,
   2127                     .longdouble => return 64,
   2128                 },
   2129             },
   2130 
   2131             .macos, .ios, .tvos, .watchos => switch (c_type) {
   2132                 .short, .ushort => return 16,
   2133                 .int, .uint, .float => return 32,
   2134                 .long, .ulong => switch (target.cpu.arch) {
   2135                     .x86, .arm, .aarch64_32 => return 32,
   2136                     .x86_64 => switch (target.abi) {
   2137                         .gnux32, .muslx32 => return 32,
   2138                         else => return 64,
   2139                     },
   2140                     else => return 64,
   2141                 },
   2142                 .longlong, .ulonglong, .double => return 64,
   2143                 .longdouble => switch (target.cpu.arch) {
   2144                     .x86 => switch (target.abi) {
   2145                         .android => return 64,
   2146                         else => return 80,
   2147                     },
   2148                     .x86_64 => return 80,
   2149                     else => return 64,
   2150                 },
   2151             },
   2152 
   2153             .nvcl, .cuda => switch (c_type) {
   2154                 .short, .ushort => return 16,
   2155                 .int, .uint, .float => return 32,
   2156                 .long, .ulong => switch (target.cpu.arch) {
   2157                     .nvptx => return 32,
   2158                     .nvptx64 => return 64,
   2159                     else => return 64,
   2160                 },
   2161                 .longlong, .ulonglong, .double => return 64,
   2162                 .longdouble => return 64,
   2163             },
   2164 
   2165             .amdhsa, .amdpal => switch (c_type) {
   2166                 .short, .ushort => return 16,
   2167                 .int, .uint, .float => return 32,
   2168                 .long, .ulong, .longlong, .ulonglong, .double => return 64,
   2169                 .longdouble => return 128,
   2170             },
   2171 
   2172             .cloudabi,
   2173             .kfreebsd,
   2174             .lv2,
   2175             .zos,
   2176             .rtems,
   2177             .nacl,
   2178             .aix,
   2179             .ps4,
   2180             .ps5,
   2181             .elfiamcu,
   2182             .mesa3d,
   2183             .contiki,
   2184             .hermit,
   2185             .hurd,
   2186             .opencl,
   2187             .glsl450,
   2188             .vulkan,
   2189             .driverkit,
   2190             .shadermodel,
   2191             => @panic("TODO specify the C integer and float type sizes for this OS"),
   2192         }
   2193     }
   2194 
   2195     pub fn c_type_alignment(target: Target, c_type: CType) u16 {
   2196         // Overrides for unusual alignments
   2197         switch (target.cpu.arch) {
   2198             .avr => switch (c_type) {
   2199                 .short, .ushort => return 2,
   2200                 else => return 1,
   2201             },
   2202             .x86 => switch (target.os.tag) {
   2203                 .windows, .uefi => switch (c_type) {
   2204                     .longlong, .ulonglong, .double => return 8,
   2205                     .longdouble => switch (target.abi) {
   2206                         .gnu, .gnuilp32, .cygnus => return 4,
   2207                         else => return 8,
   2208                     },
   2209                     else => {},
   2210                 },
   2211                 else => {},
   2212             },
   2213             else => {},
   2214         }
   2215 
   2216         // Next-power-of-two-aligned, up to a maximum.
   2217         return @min(
   2218             std.math.ceilPowerOfTwoAssert(u16, (c_type_bit_size(target, c_type) + 7) / 8),
   2219             switch (target.cpu.arch) {
   2220                 .arm, .armeb, .thumb, .thumbeb => switch (target.os.tag) {
   2221                     .netbsd => switch (target.abi) {
   2222                         .gnueabi,
   2223                         .gnueabihf,
   2224                         .eabi,
   2225                         .eabihf,
   2226                         .android,
   2227                         .musleabi,
   2228                         .musleabihf,
   2229                         => 8,
   2230 
   2231                         else => @as(u16, 4),
   2232                     },
   2233                     .ios, .tvos, .watchos => 4,
   2234                     else => 8,
   2235                 },
   2236 
   2237                 .msp430,
   2238                 .avr,
   2239                 => 2,
   2240 
   2241                 .arc,
   2242                 .csky,
   2243                 .x86,
   2244                 .xcore,
   2245                 .dxil,
   2246                 .loongarch32,
   2247                 .tce,
   2248                 .tcele,
   2249                 .le32,
   2250                 .amdil,
   2251                 .hsail,
   2252                 .spir,
   2253                 .spirv32,
   2254                 .kalimba,
   2255                 .shave,
   2256                 .renderscript32,
   2257                 .ve,
   2258                 .spu_2,
   2259                 => 4,
   2260 
   2261                 .aarch64_32,
   2262                 .amdgcn,
   2263                 .amdil64,
   2264                 .bpfel,
   2265                 .bpfeb,
   2266                 .hexagon,
   2267                 .hsail64,
   2268                 .loongarch64,
   2269                 .m68k,
   2270                 .mips,
   2271                 .mipsel,
   2272                 .sparc,
   2273                 .sparcel,
   2274                 .sparc64,
   2275                 .lanai,
   2276                 .le64,
   2277                 .nvptx,
   2278                 .nvptx64,
   2279                 .r600,
   2280                 .s390x,
   2281                 .spir64,
   2282                 .spirv64,
   2283                 .renderscript64,
   2284                 => 8,
   2285 
   2286                 .aarch64,
   2287                 .aarch64_be,
   2288                 .mips64,
   2289                 .mips64el,
   2290                 .powerpc,
   2291                 .powerpcle,
   2292                 .powerpc64,
   2293                 .powerpc64le,
   2294                 .riscv32,
   2295                 .riscv64,
   2296                 .x86_64,
   2297                 .wasm32,
   2298                 .wasm64,
   2299                 => 16,
   2300             },
   2301         );
   2302     }
   2303 
   2304     pub fn c_type_preferred_alignment(target: Target, c_type: CType) u16 {
   2305         // Overrides for unusual alignments
   2306         switch (target.cpu.arch) {
   2307             .arm, .armeb, .thumb, .thumbeb => switch (target.os.tag) {
   2308                 .netbsd => switch (target.abi) {
   2309                     .gnueabi,
   2310                     .gnueabihf,
   2311                     .eabi,
   2312                     .eabihf,
   2313                     .android,
   2314                     .musleabi,
   2315                     .musleabihf,
   2316                     => {},
   2317 
   2318                     else => switch (c_type) {
   2319                         .longdouble => return 4,
   2320                         else => {},
   2321                     },
   2322                 },
   2323                 .ios, .tvos, .watchos => switch (c_type) {
   2324                     .longdouble => return 4,
   2325                     else => {},
   2326                 },
   2327                 else => {},
   2328             },
   2329             .arc => switch (c_type) {
   2330                 .longdouble => return 4,
   2331                 else => {},
   2332             },
   2333             .avr => switch (c_type) {
   2334                 .int, .uint, .long, .ulong, .float, .longdouble => return 1,
   2335                 .short, .ushort => return 2,
   2336                 .double => return 4,
   2337                 .longlong, .ulonglong => return 8,
   2338             },
   2339             .x86 => switch (target.os.tag) {
   2340                 .windows, .uefi => switch (c_type) {
   2341                     .longdouble => switch (target.abi) {
   2342                         .gnu, .gnuilp32, .cygnus => return 4,
   2343                         else => return 8,
   2344                     },
   2345                     else => {},
   2346                 },
   2347                 else => switch (c_type) {
   2348                     .longdouble => return 4,
   2349                     else => {},
   2350                 },
   2351             },
   2352             else => {},
   2353         }
   2354 
   2355         // Next-power-of-two-aligned, up to a maximum.
   2356         return @min(
   2357             std.math.ceilPowerOfTwoAssert(u16, (c_type_bit_size(target, c_type) + 7) / 8),
   2358             switch (target.cpu.arch) {
   2359                 .msp430 => @as(u16, 2),
   2360 
   2361                 .csky,
   2362                 .xcore,
   2363                 .dxil,
   2364                 .loongarch32,
   2365                 .tce,
   2366                 .tcele,
   2367                 .le32,
   2368                 .amdil,
   2369                 .hsail,
   2370                 .spir,
   2371                 .spirv32,
   2372                 .kalimba,
   2373                 .shave,
   2374                 .renderscript32,
   2375                 .ve,
   2376                 .spu_2,
   2377                 => 4,
   2378 
   2379                 .arc,
   2380                 .arm,
   2381                 .armeb,
   2382                 .avr,
   2383                 .thumb,
   2384                 .thumbeb,
   2385                 .aarch64_32,
   2386                 .amdgcn,
   2387                 .amdil64,
   2388                 .bpfel,
   2389                 .bpfeb,
   2390                 .hexagon,
   2391                 .hsail64,
   2392                 .x86,
   2393                 .loongarch64,
   2394                 .m68k,
   2395                 .mips,
   2396                 .mipsel,
   2397                 .sparc,
   2398                 .sparcel,
   2399                 .sparc64,
   2400                 .lanai,
   2401                 .le64,
   2402                 .nvptx,
   2403                 .nvptx64,
   2404                 .r600,
   2405                 .s390x,
   2406                 .spir64,
   2407                 .spirv64,
   2408                 .renderscript64,
   2409                 => 8,
   2410 
   2411                 .aarch64,
   2412                 .aarch64_be,
   2413                 .mips64,
   2414                 .mips64el,
   2415                 .powerpc,
   2416                 .powerpcle,
   2417                 .powerpc64,
   2418                 .powerpc64le,
   2419                 .riscv32,
   2420                 .riscv64,
   2421                 .x86_64,
   2422                 .wasm32,
   2423                 .wasm64,
   2424                 => 16,
   2425             },
   2426         );
   2427     }
   2428 };
   2429 
   2430 test {
   2431     std.testing.refAllDecls(Target.Cpu.Arch);
   2432 }