master
   1//! All the details about the machine that will be executing code.
   2//! Unlike `Query` which might leave some things as "default" or "host", this
   3//! data is fully resolved into a concrete set of OS versions, CPU features,
   4//! etc.
   5
   6cpu: Cpu,
   7os: Os,
   8abi: Abi,
   9ofmt: ObjectFormat,
  10dynamic_linker: DynamicLinker = DynamicLinker.none,
  11
  12pub const Query = @import("Target/Query.zig");
  13
  14pub const Os = struct {
  15    tag: Tag,
  16    version_range: VersionRange,
  17
  18    pub const Tag = enum {
  19        freestanding,
  20        other,
  21
  22        contiki,
  23        fuchsia,
  24        hermit,
  25        managarm,
  26
  27        haiku,
  28        hurd,
  29        illumos,
  30        linux,
  31        plan9,
  32        rtems,
  33        serenity,
  34
  35        dragonfly,
  36        freebsd,
  37        netbsd,
  38        openbsd,
  39
  40        driverkit,
  41        ios,
  42        maccatalyst,
  43        macos,
  44        tvos,
  45        visionos,
  46        watchos,
  47
  48        windows,
  49        uefi,
  50
  51        @"3ds",
  52
  53        ps3,
  54        ps4,
  55        ps5,
  56        vita,
  57
  58        emscripten,
  59        wasi,
  60
  61        amdhsa,
  62        amdpal,
  63        cuda,
  64        mesa3d,
  65        nvcl,
  66        opencl,
  67        opengl,
  68        vulkan,
  69
  70        // LLVM tags deliberately omitted:
  71        // - bridgeos
  72        // - cheriotrtos
  73        // - darwin
  74        // - kfreebsd
  75        // - nacl
  76        // - shadermodel
  77
  78        pub inline fn isDarwin(tag: Tag) bool {
  79            return switch (tag) {
  80                .driverkit,
  81                .ios,
  82                .maccatalyst,
  83                .macos,
  84                .tvos,
  85                .visionos,
  86                .watchos,
  87                => true,
  88                else => false,
  89            };
  90        }
  91
  92        pub inline fn isBSD(tag: Tag) bool {
  93            return tag.isDarwin() or switch (tag) {
  94                .freebsd, .openbsd, .netbsd, .dragonfly => true,
  95                else => false,
  96            };
  97        }
  98
  99        pub fn exeFileExt(tag: Tag, arch: Cpu.Arch) [:0]const u8 {
 100            return switch (tag) {
 101                .windows => ".exe",
 102                .uefi => ".efi",
 103                .plan9 => arch.plan9Ext(),
 104                else => switch (arch) {
 105                    .wasm32, .wasm64 => ".wasm",
 106                    else => "",
 107                },
 108            };
 109        }
 110
 111        pub fn staticLibSuffix(tag: Tag, abi: Abi) [:0]const u8 {
 112            return switch (abi) {
 113                .msvc, .itanium => ".lib",
 114                else => switch (tag) {
 115                    .windows, .uefi => ".lib",
 116                    else => ".a",
 117                },
 118            };
 119        }
 120
 121        pub fn dynamicLibSuffix(tag: Tag) [:0]const u8 {
 122            return switch (tag) {
 123                .windows, .uefi => ".dll",
 124                .driverkit,
 125                .ios,
 126                .maccatalyst,
 127                .macos,
 128                .tvos,
 129                .visionos,
 130                .watchos,
 131                => ".dylib",
 132                else => ".so",
 133            };
 134        }
 135
 136        pub fn libPrefix(tag: Os.Tag, abi: Abi) [:0]const u8 {
 137            return switch (abi) {
 138                .msvc, .itanium => "",
 139                else => switch (tag) {
 140                    .windows, .uefi => "",
 141                    else => "lib",
 142                },
 143            };
 144        }
 145
 146        pub fn defaultVersionRange(tag: Tag, arch: Cpu.Arch, abi: Abi) Os {
 147            return .{
 148                .tag = tag,
 149                .version_range = .default(arch, tag, abi),
 150            };
 151        }
 152
 153        pub inline fn versionRangeTag(tag: Tag) @typeInfo(TaggedVersionRange).@"union".tag_type.? {
 154            return switch (tag) {
 155                .freestanding,
 156                .other,
 157
 158                .managarm,
 159
 160                .haiku,
 161                .illumos,
 162                .plan9,
 163                .serenity,
 164
 165                .ps3,
 166                .ps4,
 167                .ps5,
 168
 169                .emscripten,
 170
 171                .mesa3d,
 172                => .none,
 173
 174                .contiki,
 175                .fuchsia,
 176                .hermit,
 177
 178                .rtems,
 179
 180                .dragonfly,
 181                .freebsd,
 182                .netbsd,
 183                .openbsd,
 184
 185                .driverkit,
 186                .ios,
 187                .maccatalyst,
 188                .macos,
 189                .tvos,
 190                .visionos,
 191                .watchos,
 192
 193                .uefi,
 194
 195                .@"3ds",
 196
 197                .vita,
 198
 199                .wasi,
 200
 201                .amdhsa,
 202                .amdpal,
 203                .cuda,
 204                .nvcl,
 205                .opencl,
 206                .opengl,
 207                .vulkan,
 208                => .semver,
 209
 210                .hurd => .hurd,
 211                .linux => .linux,
 212
 213                .windows => .windows,
 214            };
 215        }
 216    };
 217
 218    /// Based on NTDDI version constants from
 219    /// https://docs.microsoft.com/en-us/cpp/porting/modifying-winver-and-win32-winnt
 220    pub const WindowsVersion = enum(u32) {
 221        nt4 = 0x04000000,
 222        win2k = 0x05000000,
 223        xp = 0x05010000,
 224        ws2003 = 0x05020000,
 225        vista = 0x06000000,
 226        win7 = 0x06010000,
 227        win8 = 0x06020000,
 228        win8_1 = 0x06030000,
 229        win10 = 0x0A000000, //aka win10_th1
 230        win10_th2 = 0x0A000001,
 231        win10_rs1 = 0x0A000002,
 232        win10_rs2 = 0x0A000003,
 233        win10_rs3 = 0x0A000004,
 234        win10_rs4 = 0x0A000005,
 235        win10_rs5 = 0x0A000006,
 236        win10_19h1 = 0x0A000007,
 237        win10_vb = 0x0A000008, //aka win10_19h2
 238        win10_mn = 0x0A000009, //aka win10_20h1
 239        win10_fe = 0x0A00000A, //aka win10_20h2
 240        win10_co = 0x0A00000B, //aka win10_21h1
 241        win10_ni = 0x0A00000C, //aka win10_21h2
 242        win10_cu = 0x0A00000D, //aka win10_22h2
 243        win11_zn = 0x0A00000E, //aka win11_21h2
 244        win11_ga = 0x0A00000F, //aka win11_22h2
 245        win11_ge = 0x0A000010, //aka win11_23h2
 246        win11_dt = 0x0A000011, //aka win11_24h2
 247        _,
 248
 249        /// Latest Windows version that the Zig Standard Library is aware of
 250        pub const latest = WindowsVersion.win11_dt;
 251
 252        /// Compared against build numbers reported by the runtime to distinguish win10 versions,
 253        /// where 0x0A000000 + index corresponds to the WindowsVersion u32 value.
 254        pub const known_win10_build_numbers = [_]u32{
 255            10240, //win10 aka win10_th1
 256            10586, //win10_th2
 257            14393, //win10_rs1
 258            15063, //win10_rs2
 259            16299, //win10_rs3
 260            17134, //win10_rs4
 261            17763, //win10_rs5
 262            18362, //win10_19h1
 263            18363, //win10_vb aka win10_19h2
 264            19041, //win10_mn aka win10_20h1
 265            19042, //win10_fe aka win10_20h2
 266            19043, //win10_co aka win10_21h1
 267            19044, //win10_ni aka win10_21h2
 268            19045, //win10_cu aka win10_22h2
 269            22000, //win11_zn aka win11_21h2
 270            22621, //win11_ga aka win11_22h2
 271            22631, //win11_ge aka win11_23h2
 272            26100, //win11_dt aka win11_24h2
 273        };
 274
 275        /// Returns whether the first version `ver` is newer (greater) than or equal to the second version `ver`.
 276        pub inline fn isAtLeast(ver: WindowsVersion, min_ver: WindowsVersion) bool {
 277            return @intFromEnum(ver) >= @intFromEnum(min_ver);
 278        }
 279
 280        pub const Range = struct {
 281            min: WindowsVersion,
 282            max: WindowsVersion,
 283
 284            pub inline fn includesVersion(range: Range, ver: WindowsVersion) bool {
 285                return @intFromEnum(ver) >= @intFromEnum(range.min) and
 286                    @intFromEnum(ver) <= @intFromEnum(range.max);
 287            }
 288
 289            /// Checks if system is guaranteed to be at least `version` or older than `version`.
 290            /// Returns `null` if a runtime check is required.
 291            pub inline fn isAtLeast(range: Range, min_ver: WindowsVersion) ?bool {
 292                if (@intFromEnum(range.min) >= @intFromEnum(min_ver)) return true;
 293                if (@intFromEnum(range.max) < @intFromEnum(min_ver)) return false;
 294                return null;
 295            }
 296        };
 297
 298        pub fn parse(str: []const u8) !WindowsVersion {
 299            return std.meta.stringToEnum(WindowsVersion, str) orelse
 300                @enumFromInt(std.fmt.parseInt(u32, str, 0) catch
 301                    return error.InvalidOperatingSystemVersion);
 302        }
 303
 304        /// This function is defined to serialize a Zig source code representation of this
 305        /// type, that, when parsed, will deserialize into the same data.
 306        pub fn format(wv: WindowsVersion, w: *std.Io.Writer) std.Io.Writer.Error!void {
 307            if (std.enums.tagName(WindowsVersion, wv)) |name| {
 308                var vecs: [2][]const u8 = .{ ".", name };
 309                return w.writeVecAll(&vecs);
 310            } else {
 311                return w.print("@enumFromInt(0x{X:0>8})", .{wv});
 312            }
 313        }
 314    };
 315
 316    pub const HurdVersionRange = struct {
 317        range: std.SemanticVersion.Range,
 318        glibc: std.SemanticVersion,
 319
 320        pub inline fn includesVersion(range: HurdVersionRange, ver: std.SemanticVersion) bool {
 321            return range.range.includesVersion(ver);
 322        }
 323
 324        /// Checks if system is guaranteed to be at least `version` or older than `version`.
 325        /// Returns `null` if a runtime check is required.
 326        pub inline fn isAtLeast(range: HurdVersionRange, ver: std.SemanticVersion) ?bool {
 327            return range.range.isAtLeast(ver);
 328        }
 329    };
 330
 331    pub const LinuxVersionRange = struct {
 332        range: std.SemanticVersion.Range,
 333        glibc: std.SemanticVersion,
 334        /// Android API level.
 335        android: u32,
 336
 337        pub inline fn includesVersion(range: LinuxVersionRange, ver: std.SemanticVersion) bool {
 338            return range.range.includesVersion(ver);
 339        }
 340
 341        /// Checks if system is guaranteed to be at least `version` or older than `version`.
 342        /// Returns `null` if a runtime check is required.
 343        pub inline fn isAtLeast(range: LinuxVersionRange, ver: std.SemanticVersion) ?bool {
 344            return range.range.isAtLeast(ver);
 345        }
 346    };
 347
 348    /// The version ranges here represent the minimum OS version to be supported
 349    /// and the maximum OS version to be supported. The default values represent
 350    /// the range that the Zig Standard Library bases its abstractions on.
 351    ///
 352    /// The minimum version of the range is the main setting to tweak for a target.
 353    /// Usually, the maximum target OS version will remain the default, which is
 354    /// the latest released version of the OS.
 355    ///
 356    /// To test at compile time if the target is guaranteed to support a given OS feature,
 357    /// one should check that the minimum version of the range is greater than or equal to
 358    /// the version the feature was introduced in.
 359    ///
 360    /// To test at compile time if the target certainly will not support a given OS feature,
 361    /// one should check that the maximum version of the range is less than the version the
 362    /// feature was introduced in.
 363    ///
 364    /// If neither of these cases apply, a runtime check should be used to determine if the
 365    /// target supports a given OS feature.
 366    ///
 367    /// Binaries built with a given maximum version will continue to function on newer
 368    /// operating system versions. However, such a binary may not take full advantage of the
 369    /// newer operating system APIs.
 370    ///
 371    /// See `Os.isAtLeast`.
 372    pub const VersionRange = union {
 373        none: void,
 374        semver: std.SemanticVersion.Range,
 375        hurd: HurdVersionRange,
 376        linux: LinuxVersionRange,
 377        windows: WindowsVersion.Range,
 378
 379        /// The default `VersionRange` represents the range that the Zig Standard Library
 380        /// bases its abstractions on.
 381        pub fn default(arch: Cpu.Arch, tag: Tag, abi: Abi) VersionRange {
 382            return switch (tag) {
 383                .freestanding,
 384                .other,
 385
 386                .managarm,
 387
 388                .haiku,
 389                .illumos,
 390                .plan9,
 391                .serenity,
 392
 393                .ps3,
 394                .ps4,
 395                .ps5,
 396
 397                .emscripten,
 398
 399                .mesa3d,
 400                => .{ .none = {} },
 401
 402                .contiki => .{
 403                    .semver = .{
 404                        .min = .{ .major = 4, .minor = 0, .patch = 0 },
 405                        .max = .{ .major = 5, .minor = 1, .patch = 0 },
 406                    },
 407                },
 408                .fuchsia => .{
 409                    .semver = .{
 410                        .min = .{ .major = 1, .minor = 0, .patch = 0 },
 411                        .max = .{ .major = 28, .minor = 0, .patch = 0 },
 412                    },
 413                },
 414                .hermit => .{
 415                    .semver = .{
 416                        .min = .{ .major = 0, .minor = 5, .patch = 0 },
 417                        .max = .{ .major = 0, .minor = 11, .patch = 0 },
 418                    },
 419                },
 420
 421                .hurd => .{
 422                    .hurd = .{
 423                        .range = .{
 424                            .min = .{ .major = 0, .minor = 9, .patch = 0 },
 425                            .max = .{ .major = 0, .minor = 9, .patch = 0 },
 426                        },
 427                        .glibc = .{ .major = 2, .minor = 28, .patch = 0 },
 428                    },
 429                },
 430                .linux => .{
 431                    .linux = .{
 432                        .range = .{
 433                            .min = blk: {
 434                                const default_min: std.SemanticVersion = .{ .major = 5, .minor = 10, .patch = 0 };
 435
 436                                for (std.zig.target.available_libcs) |libc| {
 437                                    if (libc.arch != arch or libc.os != tag or libc.abi != abi) continue;
 438
 439                                    if (libc.os_ver) |min| {
 440                                        if (min.order(default_min) == .gt) break :blk min;
 441                                    }
 442                                }
 443
 444                                break :blk default_min;
 445                            },
 446                            .max = .{ .major = 6, .minor = 17, .patch = 0 },
 447                        },
 448                        .glibc = blk: {
 449                            // For 32-bit targets that traditionally used 32-bit time, we require
 450                            // glibc 2.34 for full 64-bit time support. For everything else, we only
 451                            // require glibc 2.31.
 452                            const default_min: std.SemanticVersion = switch (arch) {
 453                                .arm,
 454                                .armeb,
 455                                .csky,
 456                                .m68k,
 457                                .mips,
 458                                .mipsel,
 459                                .powerpc,
 460                                .sparc,
 461                                .x86,
 462                                => .{ .major = 2, .minor = 34, .patch = 0 },
 463                                .mips64,
 464                                .mips64el,
 465                                => if (abi == .gnuabin32)
 466                                    .{ .major = 2, .minor = 34, .patch = 0 }
 467                                else
 468                                    .{ .major = 2, .minor = 31, .patch = 0 },
 469                                else => .{ .major = 2, .minor = 31, .patch = 0 },
 470                            };
 471
 472                            for (std.zig.target.available_libcs) |libc| {
 473                                if (libc.os != tag or libc.arch != arch or libc.abi != abi) continue;
 474
 475                                if (libc.glibc_min) |min| {
 476                                    if (min.order(default_min) == .gt) break :blk min;
 477                                }
 478                            }
 479
 480                            break :blk default_min;
 481                        },
 482                        .android = 29,
 483                    },
 484                },
 485                .rtems => .{
 486                    .semver = .{
 487                        .min = .{ .major = 5, .minor = 1, .patch = 0 },
 488                        .max = .{ .major = 6, .minor = 1, .patch = 0 },
 489                    },
 490                },
 491
 492                .dragonfly => .{
 493                    .semver = .{
 494                        .min = .{ .major = 6, .minor = 0, .patch = 0 },
 495                        .max = .{ .major = 6, .minor = 4, .patch = 2 },
 496                    },
 497                },
 498                .freebsd => .{
 499                    .semver = .{
 500                        .min = blk: {
 501                            const default_min: std.SemanticVersion = .{ .major = 14, .minor = 0, .patch = 0 };
 502
 503                            for (std.zig.target.available_libcs) |libc| {
 504                                if (libc.arch != arch or libc.os != tag or libc.abi != abi) continue;
 505
 506                                if (libc.os_ver) |min| {
 507                                    if (min.order(default_min) == .gt) break :blk min;
 508                                }
 509                            }
 510
 511                            break :blk default_min;
 512                        },
 513                        .max = .{ .major = 14, .minor = 3, .patch = 0 },
 514                    },
 515                },
 516                .netbsd => .{
 517                    .semver = .{
 518                        .min = blk: {
 519                            const default_min: std.SemanticVersion = .{ .major = 10, .minor = 1, .patch = 0 };
 520
 521                            for (std.zig.target.available_libcs) |libc| {
 522                                if (libc.arch != arch or libc.os != tag or libc.abi != abi) continue;
 523
 524                                if (libc.os_ver) |min| {
 525                                    if (min.order(default_min) == .gt) break :blk min;
 526                                }
 527                            }
 528
 529                            break :blk default_min;
 530                        },
 531                        .max = .{ .major = 10, .minor = 1, .patch = 0 },
 532                    },
 533                },
 534                .openbsd => .{
 535                    .semver = .{
 536                        .min = .{ .major = 7, .minor = 7, .patch = 0 },
 537                        .max = .{ .major = 7, .minor = 8, .patch = 0 },
 538                    },
 539                },
 540
 541                .driverkit => .{
 542                    .semver = .{
 543                        .min = .{ .major = 20, .minor = 0, .patch = 0 },
 544                        .max = .{ .major = 25, .minor = 0, .patch = 0 },
 545                    },
 546                },
 547                .macos => .{
 548                    .semver = .{
 549                        .min = .{ .major = 13, .minor = 0, .patch = 0 },
 550                        .max = .{ .major = 15, .minor = 6, .patch = 0 },
 551                    },
 552                },
 553                .ios, .maccatalyst => .{
 554                    .semver = .{
 555                        .min = .{ .major = 15, .minor = 0, .patch = 0 },
 556                        .max = .{ .major = 18, .minor = 6, .patch = 0 },
 557                    },
 558                },
 559                .tvos => .{
 560                    .semver = .{
 561                        .min = .{ .major = 15, .minor = 0, .patch = 0 },
 562                        .max = .{ .major = 18, .minor = 5, .patch = 0 },
 563                    },
 564                },
 565                .visionos => .{
 566                    .semver = .{
 567                        .min = .{ .major = 1, .minor = 0, .patch = 0 },
 568                        .max = .{ .major = 2, .minor = 5, .patch = 0 },
 569                    },
 570                },
 571                .watchos => .{
 572                    .semver = .{
 573                        .min = .{ .major = 8, .minor = 0, .patch = 0 },
 574                        .max = .{ .major = 11, .minor = 6, .patch = 0 },
 575                    },
 576                },
 577
 578                .windows => .{
 579                    .windows = .{
 580                        .min = .win10,
 581                        .max = WindowsVersion.latest,
 582                    },
 583                },
 584                .uefi => .{
 585                    .semver = .{
 586                        .min = .{ .major = 2, .minor = 0, .patch = 0 },
 587                        .max = .{ .major = 2, .minor = 11, .patch = 0 },
 588                    },
 589                },
 590
 591                .@"3ds" => .{
 592                    .semver = .{
 593                        // These signify release versions (https://www.3dbrew.org/wiki/NCCH/Extended_Header#ARM11_Kernel_Capabilities)
 594                        // which are different from user-facing system versions (https://www.3dbrew.org/wiki/Home_Menu#System_Versions_List).
 595                        //
 596                        // Multiple system versions could refer to the same release version.
 597                        // The comment indicates the system version that release version was introduced (for minimum) and the latest (for maximum).
 598                        .min = .{ .major = 2, .minor = 27, .patch = 0 }, // 1.0.0-0
 599                        .max = .{ .major = 2, .minor = 58, .patch = 0 }, // 11.17.0-50
 600                    },
 601                },
 602
 603                .vita => .{
 604                    .semver = .{
 605                        // 1.3 is the first public release
 606                        .min = .{ .major = 1, .minor = 3, .patch = 0 },
 607                        .max = .{ .major = 3, .minor = 60, .patch = 0 },
 608                    },
 609                },
 610
 611                .wasi => .{
 612                    .semver = .{
 613                        .min = .{ .major = 0, .minor = 1, .patch = 0 },
 614                        .max = .{ .major = 0, .minor = 3, .patch = 0 },
 615                    },
 616                },
 617
 618                .amdhsa => .{
 619                    .semver = .{
 620                        .min = .{ .major = 5, .minor = 0, .patch = 0 },
 621                        .max = .{ .major = 7, .minor = 1, .patch = 0 },
 622                    },
 623                },
 624                .amdpal => .{
 625                    .semver = .{
 626                        .min = .{ .major = 1, .minor = 1, .patch = 0 },
 627                        .max = .{ .major = 3, .minor = 5, .patch = 0 },
 628                    },
 629                },
 630                .cuda => .{
 631                    .semver = .{
 632                        .min = .{ .major = 11, .minor = 0, .patch = 1 },
 633                        .max = .{ .major = 13, .minor = 0, .patch = 2 },
 634                    },
 635                },
 636                .nvcl,
 637                .opencl,
 638                => .{
 639                    .semver = .{
 640                        .min = .{ .major = 2, .minor = 2, .patch = 0 },
 641                        .max = .{ .major = 3, .minor = 0, .patch = 19 },
 642                    },
 643                },
 644                .opengl => .{
 645                    .semver = .{
 646                        .min = .{ .major = 4, .minor = 5, .patch = 0 },
 647                        .max = .{ .major = 4, .minor = 6, .patch = 0 },
 648                    },
 649                },
 650                .vulkan => .{
 651                    .semver = .{
 652                        .min = .{ .major = 1, .minor = 2, .patch = 0 },
 653                        .max = .{ .major = 1, .minor = 4, .patch = 331 },
 654                    },
 655                },
 656            };
 657        }
 658    };
 659
 660    pub const TaggedVersionRange = union(enum) {
 661        none: void,
 662        semver: std.SemanticVersion.Range,
 663        hurd: HurdVersionRange,
 664        linux: LinuxVersionRange,
 665        windows: WindowsVersion.Range,
 666
 667        pub fn gnuLibCVersion(range: TaggedVersionRange) ?std.SemanticVersion {
 668            return switch (range) {
 669                .none, .semver, .windows => null,
 670                .hurd => |h| h.glibc,
 671                .linux => |l| l.glibc,
 672            };
 673        }
 674    };
 675
 676    /// Provides a tagged union. `Target` does not store the tag because it is
 677    /// redundant with the OS tag; this function abstracts that part away.
 678    pub inline fn versionRange(os: Os) TaggedVersionRange {
 679        return switch (os.tag.versionRangeTag()) {
 680            .none => .{ .none = {} },
 681            .semver => .{ .semver = os.version_range.semver },
 682            .hurd => .{ .hurd = os.version_range.hurd },
 683            .linux => .{ .linux = os.version_range.linux },
 684            .windows => .{ .windows = os.version_range.windows },
 685        };
 686    }
 687
 688    /// Checks if system is guaranteed to be at least `version` or older than `version`.
 689    /// Returns `null` if a runtime check is required.
 690    pub inline fn isAtLeast(os: Os, comptime tag: Tag, ver: switch (tag.versionRangeTag()) {
 691        .none => void,
 692        .semver, .hurd, .linux => std.SemanticVersion,
 693        .windows => WindowsVersion,
 694    }) ?bool {
 695        return if (os.tag != tag) false else switch (tag.versionRangeTag()) {
 696            .none => true,
 697            inline .semver,
 698            .hurd,
 699            .linux,
 700            .windows,
 701            => |field| @field(os.version_range, @tagName(field)).isAtLeast(ver),
 702        };
 703    }
 704};
 705
 706pub const aarch64 = @import("Target/aarch64.zig");
 707pub const alpha = @import("Target/alpha.zig");
 708pub const amdgcn = @import("Target/amdgcn.zig");
 709pub const arc = @import("Target/arc.zig");
 710pub const arm = @import("Target/arm.zig");
 711pub const avr = @import("Target/avr.zig");
 712pub const bpf = @import("Target/bpf.zig");
 713pub const csky = @import("Target/csky.zig");
 714pub const hexagon = @import("Target/hexagon.zig");
 715pub const hppa = @import("Target/hppa.zig");
 716pub const kalimba = @import("Target/generic.zig");
 717pub const kvx = @import("Target/kvx.zig");
 718pub const lanai = @import("Target/lanai.zig");
 719pub const loongarch = @import("Target/loongarch.zig");
 720pub const m68k = @import("Target/m68k.zig");
 721pub const microblaze = @import("Target/generic.zig");
 722pub const mips = @import("Target/mips.zig");
 723pub const msp430 = @import("Target/msp430.zig");
 724pub const nvptx = @import("Target/nvptx.zig");
 725pub const or1k = @import("Target/generic.zig");
 726pub const powerpc = @import("Target/powerpc.zig");
 727pub const propeller = @import("Target/propeller.zig");
 728pub const riscv = @import("Target/riscv.zig");
 729pub const s390x = @import("Target/s390x.zig");
 730pub const sh = @import("Target/generic.zig");
 731pub const sparc = @import("Target/sparc.zig");
 732pub const spirv = @import("Target/spirv.zig");
 733pub const ve = @import("Target/ve.zig");
 734pub const wasm = @import("Target/wasm.zig");
 735pub const x86 = @import("Target/x86.zig");
 736pub const xcore = @import("Target/xcore.zig");
 737pub const xtensa = @import("Target/xtensa.zig");
 738
 739pub const Abi = enum {
 740    none,
 741    gnu,
 742    gnuabin32,
 743    gnuabi64,
 744    gnueabi,
 745    gnueabihf,
 746    gnuf32,
 747    gnusf,
 748    gnux32,
 749    eabi,
 750    eabihf,
 751    ilp32,
 752    android,
 753    androideabi,
 754    musl,
 755    muslabin32,
 756    muslabi64,
 757    musleabi,
 758    musleabihf,
 759    muslf32,
 760    muslsf,
 761    muslx32,
 762    msvc,
 763    itanium,
 764    simulator,
 765    ohos,
 766    ohoseabi,
 767
 768    // LLVM tags deliberately omitted:
 769    // - amplification
 770    // - anyhit
 771    // - callable
 772    // - closesthit
 773    // - compute
 774    // - coreclr
 775    // - domain
 776    // - geometry
 777    // - gnueabit64
 778    // - gnueabihft64
 779    // - gnuf64
 780    // - gnut64
 781    // - hull
 782    // - intersection
 783    // - library
 784    // - llvm
 785    // - mesh
 786    // - miss
 787    // - mlibc
 788    // - mtia
 789    // - pauthtest
 790    // - pixel
 791    // - raygeneration
 792    // - rootsignature
 793    // - vertex
 794
 795    pub fn default(arch: Cpu.Arch, os_tag: Os.Tag) Abi {
 796        return switch (os_tag) {
 797            .freestanding, .other => switch (arch) {
 798                // Soft float is usually a sane default for freestanding.
 799                .arm,
 800                .armeb,
 801                .csky,
 802                .hppa,
 803                .mips,
 804                .mipsel,
 805                .powerpc,
 806                .powerpcle,
 807                .sh,
 808                .sheb,
 809                .thumb,
 810                .thumbeb,
 811                => .eabi,
 812                else => .none,
 813            },
 814            .haiku => switch (arch) {
 815                .arm,
 816                .powerpc,
 817                => .eabihf,
 818                else => .none,
 819            },
 820            .hurd => .gnu,
 821            .linux => switch (arch) {
 822                .arm,
 823                .armeb,
 824                .powerpc,
 825                .powerpcle,
 826                .thumb,
 827                .thumbeb,
 828                => .musleabihf,
 829                .mips,
 830                .mipsel,
 831                => .musleabi,
 832                .mips64,
 833                .mips64el,
 834                => .muslabi64,
 835
 836                // No musl support.
 837                .arc,
 838                .arceb,
 839                => .gnu,
 840                .csky,
 841                => .gnueabi,
 842                .hppa,
 843                .sh,
 844                .sheb,
 845                => .gnueabihf,
 846
 847                // No glibc or musl support.
 848                .xtensa,
 849                .xtensaeb,
 850                => .none,
 851
 852                else => .musl,
 853            },
 854            .rtems => switch (arch) {
 855                .arm,
 856                .armeb,
 857                .thumb,
 858                .thumbeb,
 859                .mips,
 860                .mipsel,
 861                => .eabi,
 862                .powerpc,
 863                => .eabihf,
 864                else => .none,
 865            },
 866            .freebsd => switch (arch) {
 867                .arm,
 868                .powerpc,
 869                => .eabihf,
 870                else => .none,
 871            },
 872            .netbsd => switch (arch) {
 873                .arm,
 874                .armeb,
 875                .powerpc,
 876                => .eabihf,
 877                // Soft float tends to be more common for MIPS.
 878                .mips,
 879                .mipsel,
 880                => .eabi,
 881                else => .none,
 882            },
 883            .openbsd => switch (arch) {
 884                .arm,
 885                => .eabi,
 886                .powerpc,
 887                => .eabihf,
 888                else => .none,
 889            },
 890            .windows => .gnu,
 891            .uefi => .msvc,
 892            .@"3ds" => .eabihf,
 893            .vita => .eabihf,
 894            .wasi, .emscripten => .musl,
 895
 896            .contiki,
 897            .fuchsia,
 898            .hermit,
 899            .illumos,
 900            .managarm,
 901            .plan9,
 902            .serenity,
 903            .dragonfly,
 904            .driverkit,
 905            .ios,
 906            .maccatalyst,
 907            .macos,
 908            .tvos,
 909            .visionos,
 910            .watchos,
 911            .ps3,
 912            .ps4,
 913            .ps5,
 914            .amdhsa,
 915            .amdpal,
 916            .cuda,
 917            .mesa3d,
 918            .nvcl,
 919            .opencl,
 920            .opengl,
 921            .vulkan,
 922            => .none,
 923        };
 924    }
 925
 926    pub inline fn isGnu(abi: Abi) bool {
 927        return switch (abi) {
 928            .gnu,
 929            .gnuabin32,
 930            .gnuabi64,
 931            .gnueabi,
 932            .gnueabihf,
 933            .gnuf32,
 934            .gnusf,
 935            .gnux32,
 936            => true,
 937            else => false,
 938        };
 939    }
 940
 941    pub inline fn isMusl(abi: Abi) bool {
 942        return switch (abi) {
 943            .musl,
 944            .muslabin32,
 945            .muslabi64,
 946            .musleabi,
 947            .musleabihf,
 948            .muslf32,
 949            .muslsf,
 950            .muslx32,
 951            => true,
 952            else => abi.isOpenHarmony(),
 953        };
 954    }
 955
 956    pub inline fn isOpenHarmony(abi: Abi) bool {
 957        return switch (abi) {
 958            .ohos, .ohoseabi => true,
 959            else => false,
 960        };
 961    }
 962
 963    pub inline fn isAndroid(abi: Abi) bool {
 964        return switch (abi) {
 965            .android, .androideabi => true,
 966            else => false,
 967        };
 968    }
 969
 970    pub const Float = enum {
 971        hard,
 972        soft,
 973    };
 974
 975    pub inline fn float(abi: Abi) Float {
 976        return switch (abi) {
 977            .androideabi,
 978            .eabi,
 979            .gnueabi,
 980            .musleabi,
 981            .gnusf,
 982            .ohoseabi,
 983            => .soft,
 984            else => .hard,
 985        };
 986    }
 987};
 988
 989pub const ObjectFormat = enum {
 990    /// C source code.
 991    c,
 992    /// The Common Object File Format used by Windows and UEFI.
 993    coff,
 994    /// The Executable and Linkable Format used by many Unixes.
 995    elf,
 996    /// The Intel HEX format for storing binary code in ASCII text.
 997    hex,
 998    /// The Mach object format used by macOS and other Apple platforms.
 999    macho,
1000    /// The a.out format used by Plan 9 from Bell Labs.
1001    plan9,
1002    /// Machine code with no metadata.
1003    raw,
1004    /// The Khronos Group's Standard Portable Intermediate Representation V.
1005    spirv,
1006    /// The WebAssembly binary format.
1007    wasm,
1008
1009    // LLVM tags deliberately omitted:
1010    // - dxcontainer
1011
1012    pub fn fileExt(of: ObjectFormat, arch: Cpu.Arch) [:0]const u8 {
1013        return switch (of) {
1014            .c => ".c",
1015            .coff => ".obj",
1016            .elf, .macho, .wasm => ".o",
1017            .hex => ".ihex",
1018            .plan9 => arch.plan9Ext(),
1019            .raw => ".bin",
1020            .spirv => ".spv",
1021        };
1022    }
1023
1024    pub fn default(os_tag: Os.Tag, arch: Cpu.Arch) ObjectFormat {
1025        return switch (os_tag) {
1026            .driverkit, .ios, .maccatalyst, .macos, .tvos, .visionos, .watchos => .macho,
1027            .plan9 => .plan9,
1028            .uefi, .windows => .coff,
1029            else => switch (arch) {
1030                .spirv32, .spirv64 => .spirv,
1031                .wasm32, .wasm64 => .wasm,
1032                else => .elf,
1033            },
1034        };
1035    }
1036};
1037
1038pub fn toElfMachine(target: *const Target) std.elf.EM {
1039    return switch (target.cpu.arch) {
1040        .aarch64, .aarch64_be => .AARCH64,
1041        .alpha => .ALPHA,
1042        .amdgcn => .AMDGPU,
1043        .arc, .arceb => .ARC_COMPACT2,
1044        .arm, .armeb, .thumb, .thumbeb => .ARM,
1045        .avr => .AVR,
1046        .bpfeb, .bpfel => .BPF,
1047        .csky => .CSKY,
1048        .hexagon => .QDSP6,
1049        .hppa, .hppa64 => .PARISC,
1050        .kalimba => .CSR_KALIMBA,
1051        .kvx => .KVX,
1052        .lanai => .LANAI,
1053        .loongarch32, .loongarch64 => .LOONGARCH,
1054        .m68k => .@"68K",
1055        .microblaze, .microblazeel => .MICROBLAZE,
1056        .mips, .mips64, .mipsel, .mips64el => .MIPS,
1057        .msp430 => .MSP430,
1058        .or1k => .OR1K,
1059        .powerpc, .powerpcle => .PPC,
1060        .powerpc64, .powerpc64le => .PPC64,
1061        .propeller => .PROPELLER,
1062        .riscv32, .riscv32be, .riscv64, .riscv64be => .RISCV,
1063        .s390x => .S390,
1064        .sh, .sheb => .SH,
1065        .sparc => if (target.cpu.has(.sparc, .v9)) .SPARC32PLUS else .SPARC,
1066        .sparc64 => .SPARCV9,
1067        .ve => .VE,
1068        .x86_16, .x86 => .@"386",
1069        .x86_64 => .X86_64,
1070        .xcore => .XCORE,
1071        .xtensa, .xtensaeb => .XTENSA,
1072
1073        .nvptx,
1074        .nvptx64,
1075        .spirv32,
1076        .spirv64,
1077        .wasm32,
1078        .wasm64,
1079        => .NONE,
1080    };
1081}
1082
1083pub fn toCoffMachine(target: *const Target) std.coff.IMAGE.FILE.MACHINE {
1084    return switch (target.cpu.arch) {
1085        .alpha => .ALPHA64,
1086        .arm => .ARM,
1087        .thumb => .ARMNT,
1088        .aarch64 => .ARM64,
1089        .loongarch32 => .LOONGARCH32,
1090        .loongarch64 => .LOONGARCH64,
1091        .mips => .R3000BE,
1092        .mipsel => .R3000,
1093        .mips64el => .R4000,
1094        .powerpcle => .POWERPC,
1095        .riscv32 => .RISCV32,
1096        .riscv64 => .RISCV64,
1097        .sh => .SH3,
1098        .x86 => .I386,
1099        .x86_64 => .AMD64,
1100
1101        .aarch64_be,
1102        .amdgcn,
1103        .arc,
1104        .arceb,
1105        .armeb,
1106        .avr,
1107        .bpfeb,
1108        .bpfel,
1109        .csky,
1110        .hexagon,
1111        .hppa,
1112        .hppa64,
1113        .kalimba,
1114        .kvx,
1115        .lanai,
1116        .m68k,
1117        .microblaze,
1118        .microblazeel,
1119        .mips64,
1120        .msp430,
1121        .nvptx,
1122        .nvptx64,
1123        .or1k,
1124        .powerpc,
1125        .powerpc64,
1126        .powerpc64le,
1127        .propeller,
1128        .riscv32be,
1129        .riscv64be,
1130        .s390x,
1131        .sheb,
1132        .sparc,
1133        .sparc64,
1134        .spirv32,
1135        .spirv64,
1136        .thumbeb,
1137        .ve,
1138        .wasm32,
1139        .wasm64,
1140        .x86_16,
1141        .xcore,
1142        .xtensa,
1143        .xtensaeb,
1144        => .UNKNOWN,
1145    };
1146}
1147
1148/// Deprecated; use 'std.zig.Subsystem' instead. To be removed after 0.16.0 is tagged.
1149pub const SubSystem = std.zig.Subsystem;
1150
1151pub const Cpu = struct {
1152    /// Architecture
1153    arch: Arch,
1154
1155    /// The CPU model to target. It has a set of features
1156    /// which are overridden with the `features` field.
1157    model: *const Model,
1158
1159    /// An explicit list of the entire CPU feature set. It may differ from the specific CPU model's features.
1160    features: Feature.Set,
1161
1162    pub const Feature = struct {
1163        /// The bit index into `Set`. Has a default value of `undefined` because the canonical
1164        /// structures are populated via comptime logic.
1165        index: Set.Index = undefined,
1166
1167        /// Has a default value of `undefined` because the canonical
1168        /// structures are populated via comptime logic.
1169        name: []const u8 = undefined,
1170
1171        /// If this corresponds to an LLVM-recognized feature, this will be populated;
1172        /// otherwise null.
1173        llvm_name: ?[:0]const u8,
1174
1175        /// Human-friendly UTF-8 text.
1176        description: []const u8,
1177
1178        /// Sparse `Set` of features this depends on.
1179        dependencies: Set,
1180
1181        /// A bit set of all the features.
1182        pub const Set = struct {
1183            ints: [usize_count]usize,
1184
1185            pub const needed_bit_count = 317;
1186            pub const byte_count = (needed_bit_count + 7) / 8;
1187            pub const usize_count = (byte_count + (@sizeOf(usize) - 1)) / @sizeOf(usize);
1188            pub const Index = std.math.Log2Int(std.meta.Int(.unsigned, usize_count * @bitSizeOf(usize)));
1189            pub const ShiftInt = std.math.Log2Int(usize);
1190
1191            pub const empty: Set = .{ .ints = @splat(0) };
1192
1193            pub fn isEmpty(set: Set) bool {
1194                return for (set.ints) |x| {
1195                    if (x != 0) break false;
1196                } else true;
1197            }
1198
1199            pub fn count(set: Set) std.math.IntFittingRange(0, needed_bit_count) {
1200                var sum: usize = 0;
1201                for (set.ints) |x| sum += @popCount(x);
1202                return @intCast(sum);
1203            }
1204
1205            pub fn isEnabled(set: Set, arch_feature_index: Index) bool {
1206                const usize_index = arch_feature_index / @bitSizeOf(usize);
1207                const bit_index: ShiftInt = @intCast(arch_feature_index % @bitSizeOf(usize));
1208                return (set.ints[usize_index] & (@as(usize, 1) << bit_index)) != 0;
1209            }
1210
1211            /// Adds the specified feature but not its dependencies.
1212            pub fn addFeature(set: *Set, arch_feature_index: Index) void {
1213                const usize_index = arch_feature_index / @bitSizeOf(usize);
1214                const bit_index: ShiftInt = @intCast(arch_feature_index % @bitSizeOf(usize));
1215                set.ints[usize_index] |= @as(usize, 1) << bit_index;
1216            }
1217
1218            /// Adds the specified feature set but not its dependencies.
1219            pub fn addFeatureSet(set: *Set, other_set: Set) void {
1220                set.ints = @as(@Vector(usize_count, usize), set.ints) | @as(@Vector(usize_count, usize), other_set.ints);
1221            }
1222
1223            /// Removes the specified feature but not its dependents.
1224            pub fn removeFeature(set: *Set, arch_feature_index: Index) void {
1225                const usize_index = arch_feature_index / @bitSizeOf(usize);
1226                const bit_index: ShiftInt = @intCast(arch_feature_index % @bitSizeOf(usize));
1227                set.ints[usize_index] &= ~(@as(usize, 1) << bit_index);
1228            }
1229
1230            /// Removes the specified feature but not its dependents.
1231            pub fn removeFeatureSet(set: *Set, other_set: Set) void {
1232                set.ints = @as(@Vector(usize_count, usize), set.ints) & ~@as(@Vector(usize_count, usize), other_set.ints);
1233            }
1234
1235            pub fn populateDependencies(set: *Set, all_features_list: []const Cpu.Feature) void {
1236                @setEvalBranchQuota(1000000);
1237
1238                var old = set.ints;
1239                while (true) {
1240                    for (all_features_list, 0..) |feature, index_usize| {
1241                        const index: Index = @intCast(index_usize);
1242                        if (set.isEnabled(index)) {
1243                            set.addFeatureSet(feature.dependencies);
1244                        }
1245                    }
1246                    const nothing_changed = std.mem.eql(usize, &old, &set.ints);
1247                    if (nothing_changed) return;
1248                    old = set.ints;
1249                }
1250            }
1251
1252            pub fn asBytes(set: *const Set) *const [byte_count]u8 {
1253                return std.mem.sliceAsBytes(&set.ints)[0..byte_count];
1254            }
1255
1256            pub fn eql(set: Set, other_set: Set) bool {
1257                return std.mem.eql(usize, &set.ints, &other_set.ints);
1258            }
1259
1260            pub fn isSuperSetOf(set: Set, other_set: Set) bool {
1261                const V = @Vector(usize_count, usize);
1262                const set_v: V = set.ints;
1263                const other_v: V = other_set.ints;
1264                return @reduce(.And, (set_v & other_v) == other_v);
1265            }
1266        };
1267
1268        pub fn FeatureSetFns(comptime F: type) type {
1269            return struct {
1270                /// Populates only the feature bits specified.
1271                pub fn featureSet(features: []const F) Set {
1272                    var x = Set.empty;
1273                    for (features) |feature| {
1274                        x.addFeature(@intFromEnum(feature));
1275                    }
1276                    return x;
1277                }
1278
1279                /// Returns true if the specified feature is enabled.
1280                pub fn featureSetHas(set: Set, feature: F) bool {
1281                    return set.isEnabled(@intFromEnum(feature));
1282                }
1283
1284                /// Returns true if any specified feature is enabled.
1285                pub fn featureSetHasAny(set: Set, features: anytype) bool {
1286                    inline for (features) |feature| {
1287                        if (set.isEnabled(@intFromEnum(@as(F, feature)))) return true;
1288                    }
1289                    return false;
1290                }
1291
1292                /// Returns true if every specified feature is enabled.
1293                pub fn featureSetHasAll(set: Set, features: anytype) bool {
1294                    inline for (features) |feature| {
1295                        if (!set.isEnabled(@intFromEnum(@as(F, feature)))) return false;
1296                    }
1297                    return true;
1298                }
1299            };
1300        }
1301    };
1302
1303    pub const Arch = enum {
1304        aarch64,
1305        aarch64_be,
1306        alpha,
1307        amdgcn,
1308        arc,
1309        arceb,
1310        arm,
1311        armeb,
1312        avr,
1313        bpfeb,
1314        bpfel,
1315        csky,
1316        hexagon,
1317        hppa,
1318        hppa64,
1319        kalimba,
1320        kvx,
1321        lanai,
1322        loongarch32,
1323        loongarch64,
1324        m68k,
1325        microblaze,
1326        microblazeel,
1327        mips,
1328        mipsel,
1329        mips64,
1330        mips64el,
1331        msp430,
1332        nvptx,
1333        nvptx64,
1334        or1k,
1335        powerpc,
1336        powerpcle,
1337        powerpc64,
1338        powerpc64le,
1339        propeller,
1340        riscv32,
1341        riscv32be,
1342        riscv64,
1343        riscv64be,
1344        s390x,
1345        sh,
1346        sheb,
1347        sparc,
1348        sparc64,
1349        spirv32,
1350        spirv64,
1351        thumb,
1352        thumbeb,
1353        ve,
1354        wasm32,
1355        wasm64,
1356        x86_16,
1357        x86,
1358        x86_64,
1359        xcore,
1360        xtensa,
1361        xtensaeb,
1362
1363        // LLVM tags deliberately omitted:
1364        // - aarch64_32
1365        // - amdil
1366        // - amdil64
1367        // - dxil
1368        // - r600
1369        // - hsail
1370        // - hsail64
1371        // - renderscript32
1372        // - renderscript64
1373        // - shave
1374        // - sparcel
1375        // - spir
1376        // - spir64
1377        // - spirv
1378        // - tce
1379        // - tcele
1380
1381        /// An architecture family can encompass multiple architectures as represented by `Arch`.
1382        /// For a given family tag, it is guaranteed that an `std.Target.<tag>` namespace exists
1383        /// containing CPU model and feature data.
1384        pub const Family = enum {
1385            aarch64,
1386            alpha,
1387            amdgcn,
1388            arc,
1389            arm,
1390            avr,
1391            bpf,
1392            csky,
1393            hexagon,
1394            hppa,
1395            kalimba,
1396            kvx,
1397            lanai,
1398            loongarch,
1399            m68k,
1400            microblaze,
1401            mips,
1402            msp430,
1403            nvptx,
1404            or1k,
1405            powerpc,
1406            propeller,
1407            riscv,
1408            s390x,
1409            sh,
1410            sparc,
1411            spirv,
1412            ve,
1413            wasm,
1414            x86,
1415            xcore,
1416            xtensa,
1417        };
1418
1419        pub inline fn family(arch: Arch) Family {
1420            return switch (arch) {
1421                .aarch64, .aarch64_be => .aarch64,
1422                .alpha => .alpha,
1423                .amdgcn => .amdgcn,
1424                .arc, .arceb => .arc,
1425                .arm, .armeb, .thumb, .thumbeb => .arm,
1426                .avr => .avr,
1427                .bpfeb, .bpfel => .bpf,
1428                .csky => .csky,
1429                .hexagon => .hexagon,
1430                .hppa, .hppa64 => .hppa,
1431                .kalimba => .kalimba,
1432                .kvx => .kvx,
1433                .lanai => .lanai,
1434                .loongarch32, .loongarch64 => .loongarch,
1435                .m68k => .m68k,
1436                .microblaze, .microblazeel => .microblaze,
1437                .mips, .mipsel, .mips64, .mips64el => .mips,
1438                .msp430 => .msp430,
1439                .or1k => .or1k,
1440                .nvptx, .nvptx64 => .nvptx,
1441                .powerpc, .powerpcle, .powerpc64, .powerpc64le => .powerpc,
1442                .propeller => .propeller,
1443                .riscv32, .riscv32be, .riscv64, .riscv64be => .riscv,
1444                .s390x => .s390x,
1445                .sh, .sheb => .sh,
1446                .sparc, .sparc64 => .sparc,
1447                .spirv32, .spirv64 => .spirv,
1448                .ve => .ve,
1449                .wasm32, .wasm64 => .wasm,
1450                .x86_16, .x86, .x86_64 => .x86,
1451                .xcore => .xcore,
1452                .xtensa, .xtensaeb => .xtensa,
1453            };
1454        }
1455
1456        pub inline fn isX86(arch: Arch) bool {
1457            return switch (arch) {
1458                .x86_16, .x86, .x86_64 => true,
1459                else => false,
1460            };
1461        }
1462
1463        /// Note that this includes Thumb.
1464        pub inline fn isArm(arch: Arch) bool {
1465            return switch (arch) {
1466                .arm, .armeb => true,
1467                else => arch.isThumb(),
1468            };
1469        }
1470
1471        pub inline fn isThumb(arch: Arch) bool {
1472            return switch (arch) {
1473                .thumb, .thumbeb => true,
1474                else => false,
1475            };
1476        }
1477
1478        pub inline fn isAARCH64(arch: Arch) bool {
1479            return switch (arch) {
1480                .aarch64, .aarch64_be => true,
1481                else => false,
1482            };
1483        }
1484
1485        pub inline fn isArc(arch: Arch) bool {
1486            return switch (arch) {
1487                .arc, .arceb => true,
1488                else => false,
1489            };
1490        }
1491
1492        pub inline fn isHppa(arch: Arch) bool {
1493            return switch (arch) {
1494                .hppa, .hppa64 => true,
1495                else => false,
1496            };
1497        }
1498
1499        pub inline fn isWasm(arch: Arch) bool {
1500            return switch (arch) {
1501                .wasm32, .wasm64 => true,
1502                else => false,
1503            };
1504        }
1505
1506        pub inline fn isLoongArch(arch: Arch) bool {
1507            return switch (arch) {
1508                .loongarch32, .loongarch64 => true,
1509                else => false,
1510            };
1511        }
1512
1513        pub inline fn isRISCV(arch: Arch) bool {
1514            return arch.isRiscv32() or arch.isRiscv64();
1515        }
1516
1517        pub inline fn isRiscv32(arch: Arch) bool {
1518            return switch (arch) {
1519                .riscv32, .riscv32be => true,
1520                else => false,
1521            };
1522        }
1523
1524        pub inline fn isRiscv64(arch: Arch) bool {
1525            return switch (arch) {
1526                .riscv64, .riscv64be => true,
1527                else => false,
1528            };
1529        }
1530
1531        pub inline fn isMicroblaze(arch: Arch) bool {
1532            return switch (arch) {
1533                .microblaze, .microblazeel => true,
1534                else => false,
1535            };
1536        }
1537
1538        pub inline fn isMIPS(arch: Arch) bool {
1539            return arch.isMIPS32() or arch.isMIPS64();
1540        }
1541
1542        pub inline fn isMIPS32(arch: Arch) bool {
1543            return switch (arch) {
1544                .mips, .mipsel => true,
1545                else => false,
1546            };
1547        }
1548
1549        pub inline fn isMIPS64(arch: Arch) bool {
1550            return switch (arch) {
1551                .mips64, .mips64el => true,
1552                else => false,
1553            };
1554        }
1555
1556        pub inline fn isPowerPC(arch: Arch) bool {
1557            return arch.isPowerPC32() or arch.isPowerPC64();
1558        }
1559
1560        pub inline fn isPowerPC32(arch: Arch) bool {
1561            return switch (arch) {
1562                .powerpc, .powerpcle => true,
1563                else => false,
1564            };
1565        }
1566
1567        pub inline fn isPowerPC64(arch: Arch) bool {
1568            return switch (arch) {
1569                .powerpc64, .powerpc64le => true,
1570                else => false,
1571            };
1572        }
1573
1574        pub inline fn isSPARC(arch: Arch) bool {
1575            return switch (arch) {
1576                .sparc, .sparc64 => true,
1577                else => false,
1578            };
1579        }
1580
1581        pub inline fn isSpirV(arch: Arch) bool {
1582            return switch (arch) {
1583                .spirv32, .spirv64 => true,
1584                else => false,
1585            };
1586        }
1587
1588        pub inline fn isSh(arch: Arch) bool {
1589            return switch (arch) {
1590                .sh, .sheb => true,
1591                else => false,
1592            };
1593        }
1594
1595        pub inline fn isBpf(arch: Arch) bool {
1596            return switch (arch) {
1597                .bpfel, .bpfeb => true,
1598                else => false,
1599            };
1600        }
1601
1602        pub inline fn isNvptx(arch: Arch) bool {
1603            return switch (arch) {
1604                .nvptx, .nvptx64 => true,
1605                else => false,
1606            };
1607        }
1608
1609        pub inline fn isXtensa(arch: Arch) bool {
1610            return switch (arch) {
1611                .xtensa, .xtensaeb => true,
1612                else => false,
1613            };
1614        }
1615
1616        pub fn parseCpuModel(arch: Arch, cpu_name: []const u8) !*const Cpu.Model {
1617            for (arch.allCpuModels()) |cpu| {
1618                if (std.mem.eql(u8, cpu_name, cpu.name)) {
1619                    return cpu;
1620                }
1621            }
1622            return error.UnknownCpuModel;
1623        }
1624
1625        pub fn endian(arch: Arch) std.builtin.Endian {
1626            return switch (arch) {
1627                .aarch64,
1628                .alpha,
1629                .arm,
1630                .arc,
1631                .avr,
1632                .bpfel,
1633                .csky,
1634                .hexagon,
1635                .kalimba,
1636                .kvx,
1637                .loongarch32,
1638                .loongarch64,
1639                .microblazeel,
1640                .mipsel,
1641                .mips64el,
1642                .msp430,
1643                .powerpcle,
1644                .powerpc64le,
1645                .propeller,
1646                .riscv32,
1647                .riscv64,
1648                .sh,
1649                .thumb,
1650                .ve,
1651                .wasm32,
1652                .wasm64,
1653                .x86_16,
1654                .x86,
1655                .x86_64,
1656                .xcore,
1657                .xtensa,
1658                => .little,
1659
1660                .aarch64_be,
1661                .arceb,
1662                .armeb,
1663                .bpfeb,
1664                .hppa,
1665                .hppa64,
1666                .lanai,
1667                .m68k,
1668                .microblaze,
1669                .mips,
1670                .mips64,
1671                .or1k,
1672                .powerpc,
1673                .powerpc64,
1674                .riscv32be,
1675                .riscv64be,
1676                .s390x,
1677                .sheb,
1678                .thumbeb,
1679                .sparc,
1680                .sparc64,
1681                .xtensaeb,
1682                => .big,
1683
1684                // GPU endianness is opaque. For now, assume little endian.
1685                .amdgcn,
1686                .nvptx,
1687                .nvptx64,
1688                .spirv32,
1689                .spirv64,
1690                => .little,
1691            };
1692        }
1693
1694        /// All CPU features Zig is aware of, sorted lexicographically by name.
1695        pub fn allFeaturesList(arch: Arch) []const Cpu.Feature {
1696            return switch (arch.family()) {
1697                inline else => |f| &@field(Target, @tagName(f)).all_features,
1698            };
1699        }
1700
1701        /// All processors Zig is aware of, sorted lexicographically by name.
1702        pub fn allCpuModels(arch: Arch) []const *const Cpu.Model {
1703            return switch (arch.family()) {
1704                inline else => |f| comptime allCpusFromDecls(@field(Target, @tagName(f)).cpu),
1705            };
1706        }
1707
1708        fn allCpusFromDecls(comptime cpus: type) []const *const Cpu.Model {
1709            @setEvalBranchQuota(2000);
1710            const decls = @typeInfo(cpus).@"struct".decls;
1711            var array: [decls.len]*const Cpu.Model = undefined;
1712            for (decls, 0..) |decl, i| {
1713                array[i] = &@field(cpus, decl.name);
1714            }
1715            const finalized = array;
1716            return &finalized;
1717        }
1718
1719        /// 0c spim    little-endian MIPS 3000 family
1720        /// 1c 68000   Motorola MC68000
1721        /// 2c 68020   Motorola MC68020
1722        /// 5c arm     little-endian ARM
1723        /// 6c amd64   AMD64 and compatibles (e.g., Intel EM64T)
1724        /// 7c arm64   ARM64 (ARMv8)
1725        /// 8c 386     Intel x86, i486, Pentium, etc.
1726        /// kc sparc   Sun SPARC
1727        /// qc power   Power PC
1728        /// vc mips    big-endian MIPS 3000 family
1729        pub fn plan9Ext(arch: Cpu.Arch) [:0]const u8 {
1730            return switch (arch) {
1731                .arm => ".5",
1732                .x86_64 => ".6",
1733                .aarch64 => ".7",
1734                .x86 => ".8",
1735                .sparc => ".k",
1736                .powerpc, .powerpcle => ".q",
1737                .mips, .mipsel => ".v",
1738                // ISAs without designated characters get 'X' for lack of a better option.
1739                else => ".X",
1740            };
1741        }
1742
1743        /// Returns the array of `Arch` to which a specific `std.builtin.CallingConvention` applies.
1744        /// Asserts that `cc` is not `.auto`, `.@"async"`, `.naked`, or `.@"inline"`.
1745        pub fn fromCallingConvention(cc: std.builtin.CallingConvention.Tag) []const Arch {
1746            return switch (cc) {
1747                .auto,
1748                .async,
1749                .naked,
1750                .@"inline",
1751                => unreachable,
1752
1753                .x86_64_sysv,
1754                .x86_64_x32,
1755                .x86_64_win,
1756                .x86_64_regcall_v3_sysv,
1757                .x86_64_regcall_v4_win,
1758                .x86_64_vectorcall,
1759                .x86_64_interrupt,
1760                => &.{.x86_64},
1761
1762                .x86_sysv,
1763                .x86_win,
1764                .x86_stdcall,
1765                .x86_fastcall,
1766                .x86_thiscall,
1767                .x86_thiscall_mingw,
1768                .x86_regcall_v3,
1769                .x86_regcall_v4_win,
1770                .x86_vectorcall,
1771                .x86_interrupt,
1772                => &.{.x86},
1773
1774                .x86_16_cdecl,
1775                .x86_16_stdcall,
1776                .x86_16_regparmcall,
1777                .x86_16_interrupt,
1778                => &.{.x86_16},
1779
1780                .aarch64_aapcs,
1781                .aarch64_aapcs_darwin,
1782                .aarch64_aapcs_win,
1783                .aarch64_vfabi,
1784                .aarch64_vfabi_sve,
1785                => &.{ .aarch64, .aarch64_be },
1786
1787                .alpha_osf,
1788                => &.{.alpha},
1789
1790                .arm_aapcs,
1791                .arm_aapcs_vfp,
1792                .arm_interrupt,
1793                => &.{ .arm, .armeb, .thumb, .thumbeb },
1794
1795                .mips64_n64,
1796                .mips64_n32,
1797                .mips64_interrupt,
1798                => &.{ .mips64, .mips64el },
1799
1800                .mips_o32,
1801                .mips_interrupt,
1802                => &.{ .mips, .mipsel },
1803
1804                .riscv64_lp64,
1805                .riscv64_lp64_v,
1806                .riscv64_interrupt,
1807                => &.{ .riscv64, .riscv64be },
1808
1809                .riscv32_ilp32,
1810                .riscv32_ilp32_v,
1811                .riscv32_interrupt,
1812                => &.{ .riscv32, .riscv32be },
1813
1814                .sparc64_sysv,
1815                => &.{.sparc64},
1816
1817                .sparc_sysv,
1818                => &.{.sparc},
1819
1820                .powerpc64_elf,
1821                .powerpc64_elf_altivec,
1822                .powerpc64_elf_v2,
1823                => &.{ .powerpc64, .powerpc64le },
1824
1825                .powerpc_sysv,
1826                .powerpc_sysv_altivec,
1827                .powerpc_aix,
1828                .powerpc_aix_altivec,
1829                => &.{ .powerpc, .powerpcle },
1830
1831                .wasm_mvp,
1832                => &.{ .wasm64, .wasm32 },
1833
1834                .arc_sysv,
1835                .arc_interrupt,
1836                => &.{ .arc, .arceb },
1837
1838                .avr_gnu,
1839                .avr_builtin,
1840                .avr_signal,
1841                .avr_interrupt,
1842                => &.{.avr},
1843
1844                .bpf_std,
1845                => &.{ .bpfel, .bpfeb },
1846
1847                .csky_sysv,
1848                .csky_interrupt,
1849                => &.{.csky},
1850
1851                .hexagon_sysv,
1852                .hexagon_sysv_hvx,
1853                => &.{.hexagon},
1854
1855                .hppa_elf,
1856                => &.{.hppa},
1857
1858                .hppa64_elf,
1859                => &.{.hppa64},
1860
1861                .kvx_lp64,
1862                .kvx_ilp32,
1863                => &.{.kvx},
1864
1865                .lanai_sysv,
1866                => &.{.lanai},
1867
1868                .loongarch64_lp64,
1869                => &.{.loongarch64},
1870
1871                .loongarch32_ilp32,
1872                => &.{.loongarch32},
1873
1874                .m68k_sysv,
1875                .m68k_gnu,
1876                .m68k_rtd,
1877                .m68k_interrupt,
1878                => &.{.m68k},
1879
1880                .microblaze_std,
1881                .microblaze_interrupt,
1882                => &.{ .microblaze, .microblazeel },
1883
1884                .msp430_eabi,
1885                .msp430_interrupt,
1886                => &.{.msp430},
1887
1888                .or1k_sysv,
1889                => &.{.or1k},
1890
1891                .propeller_sysv,
1892                => &.{.propeller},
1893
1894                .s390x_sysv,
1895                .s390x_sysv_vx,
1896                => &.{.s390x},
1897
1898                .sh_gnu,
1899                .sh_renesas,
1900                .sh_interrupt,
1901                => &.{ .sh, .sheb },
1902
1903                .ve_sysv,
1904                => &.{.ve},
1905
1906                .xcore_xs1,
1907                .xcore_xs2,
1908                => &.{.xcore},
1909
1910                .xtensa_call0,
1911                .xtensa_windowed,
1912                => &.{ .xtensa, .xtensaeb },
1913
1914                .amdgcn_device,
1915                .amdgcn_kernel,
1916                .amdgcn_cs,
1917                => &.{.amdgcn},
1918
1919                .nvptx_device,
1920                .nvptx_kernel,
1921                => &.{ .nvptx, .nvptx64 },
1922
1923                .spirv_device,
1924                .spirv_kernel,
1925                .spirv_fragment,
1926                .spirv_vertex,
1927                => &.{ .spirv32, .spirv64 },
1928            };
1929        }
1930    };
1931
1932    pub const Model = struct {
1933        name: []const u8,
1934        llvm_name: ?[:0]const u8,
1935        features: Feature.Set,
1936
1937        pub fn toCpu(model: *const Model, arch: Arch) Cpu {
1938            var features = model.features;
1939            features.populateDependencies(arch.allFeaturesList());
1940            return .{
1941                .arch = arch,
1942                .model = model,
1943                .features = features,
1944            };
1945        }
1946
1947        /// Returns the most bare-bones CPU model that is valid for `arch`. Note that this function
1948        /// can return CPU models that are understood by LLVM, but *not* understood by Clang. If
1949        /// Clang compatibility is important, consider using `baseline` instead.
1950        pub fn generic(arch: Arch) *const Model {
1951            return switch (arch) {
1952                .alpha => &alpha.cpu.ev4,
1953                .amdgcn => &amdgcn.cpu.gfx600,
1954                .avr => &avr.cpu.avr1,
1955                .hppa => &hppa.cpu.ts_1,
1956                .hppa64 => &hppa.cpu.pa_8000,
1957                .kvx => &kvx.cpu.coolidge_v1,
1958                .loongarch32 => &loongarch.cpu.generic_la32,
1959                .loongarch64 => &loongarch.cpu.generic_la64,
1960                .mips, .mipsel => &mips.cpu.mips32,
1961                .mips64, .mips64el => &mips.cpu.mips64,
1962                .nvptx, .nvptx64 => &nvptx.cpu.sm_20,
1963                .powerpc, .powerpcle => &powerpc.cpu.ppc,
1964                .powerpc64, .powerpc64le => &powerpc.cpu.ppc64,
1965                .propeller => &propeller.cpu.p1,
1966                .riscv32, .riscv32be => &riscv.cpu.generic_rv32,
1967                .riscv64, .riscv64be => &riscv.cpu.generic_rv64,
1968                .sparc64 => &sparc.cpu.v9, // SPARC can only be 64-bit from v9 and up.
1969                .wasm32, .wasm64 => &wasm.cpu.mvp,
1970                .x86_16 => &x86.cpu.i86,
1971                .x86 => &x86.cpu.i386,
1972                .x86_64 => &x86.cpu.x86_64,
1973                inline else => |a| &@field(Target, @tagName(a.family())).cpu.generic,
1974            };
1975        }
1976
1977        /// Returns a conservative CPU model for `arch` that is expected to be compatible with the
1978        /// vast majority of hardware available. This function is guaranteed to return CPU models
1979        /// that are understood by both LLVM and Clang, unlike `generic`.
1980        ///
1981        /// For certain `os` values, this function will additionally bump the baseline higher than
1982        /// the baseline would be for `arch` in isolation; for example, for `aarch64-macos`, the
1983        /// baseline is considered to be `apple_m1`. To avoid this behavior entirely, pass
1984        /// `Os.Tag.freestanding`.
1985        pub fn baseline(arch: Arch, os: Os) *const Model {
1986            return switch (arch) {
1987                .alpha => &alpha.cpu.ev6,
1988                .amdgcn => &amdgcn.cpu.gfx906,
1989                .arm => switch (os.tag) {
1990                    .@"3ds" => &arm.cpu.mpcore,
1991                    .vita => &arm.cpu.cortex_a9,
1992                    else => &arm.cpu.baseline,
1993                },
1994                .thumb => switch (os.tag) {
1995                    .vita => &arm.cpu.cortex_a9,
1996                    else => &arm.cpu.baseline,
1997                },
1998                .armeb, .thumbeb => &arm.cpu.baseline,
1999                .aarch64 => switch (os.tag) {
2000                    .driverkit, .maccatalyst, .macos => &aarch64.cpu.apple_m1,
2001                    .ios, .tvos => &aarch64.cpu.apple_a7,
2002                    .visionos => &aarch64.cpu.apple_m2,
2003                    .watchos => &aarch64.cpu.apple_s4,
2004                    else => generic(arch),
2005                },
2006                .avr => &avr.cpu.avr2,
2007                .bpfel, .bpfeb => &bpf.cpu.v3,
2008                .csky => &csky.cpu.ck810, // gcc/clang do not have a generic csky model.
2009                .hexagon => &hexagon.cpu.hexagonv68, // gcc/clang do not have a generic hexagon model.
2010                .hppa => &hppa.cpu.pa_7300lc,
2011                .kvx => &kvx.cpu.coolidge_v2,
2012                .lanai => &lanai.cpu.v11, // clang does not have a generic lanai model.
2013                .loongarch64 => &loongarch.cpu.la64v1_0,
2014                .m68k => &m68k.cpu.M68000,
2015                .mips, .mipsel => &mips.cpu.mips32r2,
2016                .mips64, .mips64el => &mips.cpu.mips64r2,
2017                .msp430 => &msp430.cpu.msp430,
2018                .nvptx, .nvptx64 => &nvptx.cpu.sm_52,
2019                .powerpc64le => &powerpc.cpu.ppc64le,
2020                .riscv32, .riscv32be => &riscv.cpu.baseline_rv32,
2021                .riscv64, .riscv64be => &riscv.cpu.baseline_rv64,
2022                // gcc/clang do not have a generic s390x model.
2023                .s390x => &s390x.cpu.arch8,
2024                .sparc => &sparc.cpu.v9, // glibc does not work with 'plain' v8.
2025                .x86 => &x86.cpu.pentium4,
2026                .x86_64 => switch (os.tag) {
2027                    .driverkit, .maccatalyst => &x86.cpu.nehalem,
2028                    .macos => &x86.cpu.core2,
2029                    .ps4 => &x86.cpu.btver2,
2030                    .ps5 => &x86.cpu.znver2,
2031                    else => generic(arch),
2032                },
2033                .xcore => &xcore.cpu.xs1b_generic,
2034                .wasm32, .wasm64 => &wasm.cpu.lime1,
2035
2036                else => generic(arch),
2037            };
2038        }
2039    };
2040
2041    /// The "default" set of CPU features for cross-compiling. A conservative set
2042    /// of features that is expected to be supported on most available hardware.
2043    pub fn baseline(arch: Arch, os: Os) Cpu {
2044        return Model.baseline(arch, os).toCpu(arch);
2045    }
2046
2047    /// Returns true if `feature` is enabled.
2048    pub fn has(cpu: Cpu, comptime family: Arch.Family, feature: @field(Target, @tagName(family)).Feature) bool {
2049        if (family != cpu.arch.family()) return false;
2050        return cpu.features.isEnabled(@intFromEnum(feature));
2051    }
2052
2053    /// Returns true if any feature in `features` is enabled.
2054    pub fn hasAny(cpu: Cpu, comptime family: Arch.Family, features: []const @field(Target, @tagName(family)).Feature) bool {
2055        if (family != cpu.arch.family()) return false;
2056        for (features) |feature| {
2057            if (cpu.features.isEnabled(@intFromEnum(feature))) return true;
2058        }
2059        return false;
2060    }
2061
2062    /// Returns true if all features in `features` are enabled.
2063    pub fn hasAll(cpu: Cpu, comptime family: Arch.Family, features: []const @field(Target, @tagName(family)).Feature) bool {
2064        if (family != cpu.arch.family()) return false;
2065        for (features) |feature| {
2066            if (!cpu.features.isEnabled(@intFromEnum(feature))) return false;
2067        }
2068        return true;
2069    }
2070};
2071
2072pub fn zigTriple(target: *const Target, allocator: Allocator) Allocator.Error![]u8 {
2073    return Query.fromTarget(target).zigTriple(allocator);
2074}
2075
2076pub fn hurdTupleSimple(allocator: Allocator, arch: Cpu.Arch, abi: Abi) ![]u8 {
2077    return std.fmt.allocPrint(allocator, "{s}-{s}", .{ @tagName(arch), @tagName(abi) });
2078}
2079
2080pub fn hurdTuple(target: *const Target, allocator: Allocator) ![]u8 {
2081    return hurdTupleSimple(allocator, target.cpu.arch, target.abi);
2082}
2083
2084pub fn linuxTripleSimple(allocator: Allocator, arch: Cpu.Arch, os_tag: Os.Tag, abi: Abi) ![]u8 {
2085    return std.fmt.allocPrint(allocator, "{s}-{s}-{s}", .{ @tagName(arch), @tagName(os_tag), @tagName(abi) });
2086}
2087
2088pub fn linuxTriple(target: *const Target, allocator: Allocator) ![]u8 {
2089    return linuxTripleSimple(allocator, target.cpu.arch, target.os.tag, target.abi);
2090}
2091
2092pub fn exeFileExt(target: *const Target) [:0]const u8 {
2093    return target.os.tag.exeFileExt(target.cpu.arch);
2094}
2095
2096pub fn staticLibSuffix(target: *const Target) [:0]const u8 {
2097    return target.os.tag.staticLibSuffix(target.abi);
2098}
2099
2100pub fn dynamicLibSuffix(target: *const Target) [:0]const u8 {
2101    return target.os.tag.dynamicLibSuffix();
2102}
2103
2104pub fn libPrefix(target: *const Target) [:0]const u8 {
2105    return target.os.tag.libPrefix(target.abi);
2106}
2107
2108pub inline fn isMinGW(target: *const Target) bool {
2109    return target.os.tag == .windows and target.abi.isGnu();
2110}
2111
2112pub inline fn isGnuLibC(target: *const Target) bool {
2113    return switch (target.os.tag) {
2114        .hurd, .linux => target.abi.isGnu(),
2115        else => false,
2116    };
2117}
2118
2119pub inline fn isMuslLibC(target: *const Target) bool {
2120    return target.os.tag == .linux and target.abi.isMusl();
2121}
2122
2123pub inline fn isDarwinLibC(target: *const Target) bool {
2124    return switch (target.abi) {
2125        .none, .simulator => target.os.tag.isDarwin(),
2126        else => false,
2127    };
2128}
2129
2130pub inline fn isFreeBSDLibC(target: *const Target) bool {
2131    return switch (target.abi) {
2132        .none, .eabihf => target.os.tag == .freebsd,
2133        else => false,
2134    };
2135}
2136
2137pub inline fn isNetBSDLibC(target: *const Target) bool {
2138    return switch (target.abi) {
2139        .none, .eabi, .eabihf => target.os.tag == .netbsd,
2140        else => false,
2141    };
2142}
2143
2144pub inline fn isWasiLibC(target: *const Target) bool {
2145    return target.os.tag == .wasi and target.abi.isMusl();
2146}
2147
2148/// Does this target require linking libc? This may be the case if the target has an unstable
2149/// syscall interface, for example.
2150pub fn requiresLibC(target: *const Target) bool {
2151    return switch (target.os.tag) {
2152        .illumos,
2153        .driverkit,
2154        .ios,
2155        .maccatalyst,
2156        .macos,
2157        .tvos,
2158        .watchos,
2159        .visionos,
2160        .dragonfly,
2161        .openbsd,
2162        .haiku,
2163        .serenity,
2164        => true,
2165
2166        // Android API levels prior to 29 did not have native TLS support. For these API levels, TLS
2167        // is implemented through calls to `__emutls_get_address`. We provide this function in
2168        // compiler-rt, but it's implemented by way of `pthread_key_create` et al, so linking libc
2169        // is required.
2170        .linux => target.abi.isAndroid() and target.os.version_range.linux.android < 29,
2171
2172        .windows,
2173        .freebsd,
2174        .netbsd,
2175        .freestanding,
2176        .fuchsia,
2177        .managarm,
2178        .ps3,
2179        .rtems,
2180        .cuda,
2181        .nvcl,
2182        .amdhsa,
2183        .ps4,
2184        .ps5,
2185        .vita,
2186        .mesa3d,
2187        .contiki,
2188        .amdpal,
2189        .hermit,
2190        .hurd,
2191        .wasi,
2192        .emscripten,
2193        .uefi,
2194        .opencl,
2195        .opengl,
2196        .vulkan,
2197        .plan9,
2198        .other,
2199        .@"3ds",
2200        => false,
2201    };
2202}
2203
2204/// The places where a user can specify an address space attribute
2205pub const AddressSpaceContext = enum {
2206    /// A function is specified to be placed in a certain address space.
2207    function,
2208    /// A (global) variable is specified to be placed in a certain address space. In contrast to
2209    /// `.constant`, these values (and thus the address space they will be placed in) are required
2210    /// to be mutable.
2211    variable,
2212    /// A (global) constant value is specified to be placed in a certain address space. In contrast
2213    /// to `.variable`, values placed in this address space are not required to be mutable.
2214    constant,
2215    /// A pointer is ascripted to point into a certain address space.
2216    pointer,
2217};
2218
2219/// Returns whether this target supports `address_space`. If `context` is `null`, this
2220/// function simply answers the general question of whether the target has any concept
2221/// of `address_space`; if non-`null`, the function additionally checks whether
2222/// `address_space` is valid in that context.
2223pub fn supportsAddressSpace(
2224    target: Target,
2225    address_space: std.builtin.AddressSpace,
2226    context: ?AddressSpaceContext,
2227) bool {
2228    const arch = target.cpu.arch;
2229
2230    const is_nvptx = arch.isNvptx();
2231    const is_spirv = arch.isSpirV();
2232    const is_gpu = is_nvptx or is_spirv or arch == .amdgcn;
2233
2234    return switch (address_space) {
2235        .generic => true,
2236        .fs, .gs, .ss => (arch == .x86_64 or arch == .x86 or arch == .x86_16) and (context == null or context == .pointer),
2237        // Technically x86 can use segmentation...
2238        .far => (arch == .x86_16),
2239
2240        .flash, .flash1, .flash2, .flash3, .flash4, .flash5 => arch == .avr, // TODO this should also check how many flash banks the cpu has
2241        .cog, .hub => arch == .propeller,
2242        .lut => arch == .propeller and std.Target.propeller.featureSetHas(target.cpu.features, .p2),
2243
2244        .global, .local, .shared => is_gpu,
2245        .constant => is_gpu and (context == null or context == .constant),
2246        .param => is_nvptx,
2247        .input, .output, .uniform, .push_constant, .storage_buffer, .physical_storage_buffer => is_spirv,
2248    };
2249}
2250
2251pub const DynamicLinker = struct {
2252    /// Contains the memory used to store the dynamic linker path. This field
2253    /// should not be used directly. See `get` and `set`. This field exists so
2254    /// that this API requires no allocator.
2255    buffer: [255]u8,
2256
2257    /// Used to construct the dynamic linker path. This field should not be used
2258    /// directly. See `get` and `set`.
2259    len: u8,
2260
2261    pub const none: DynamicLinker = .{ .buffer = undefined, .len = 0 };
2262
2263    /// Asserts that the length is less than or equal to 255 bytes.
2264    pub fn init(maybe_path: ?[]const u8) DynamicLinker {
2265        var dl: DynamicLinker = undefined;
2266        dl.set(maybe_path);
2267        return dl;
2268    }
2269
2270    pub fn initFmt(comptime fmt_str: []const u8, args: anytype) !DynamicLinker {
2271        var dl: DynamicLinker = undefined;
2272        try dl.setFmt(fmt_str, args);
2273        return dl;
2274    }
2275
2276    /// The returned memory has the same lifetime as the `DynamicLinker`.
2277    pub fn get(dl: *const DynamicLinker) ?[]const u8 {
2278        return if (dl.len > 0) dl.buffer[0..dl.len] else null;
2279    }
2280
2281    /// Asserts that the length is less than or equal to 255 bytes.
2282    pub fn set(dl: *DynamicLinker, maybe_path: ?[]const u8) void {
2283        const path = maybe_path orelse "";
2284        @memcpy(dl.buffer[0..path.len], path);
2285        dl.len = @intCast(path.len);
2286    }
2287
2288    /// Asserts that the length is less than or equal to 255 bytes.
2289    pub fn setFmt(dl: *DynamicLinker, comptime fmt_str: []const u8, args: anytype) !void {
2290        dl.len = @intCast((try std.fmt.bufPrint(&dl.buffer, fmt_str, args)).len);
2291    }
2292
2293    pub fn eql(lhs: DynamicLinker, rhs: DynamicLinker) bool {
2294        return std.mem.eql(u8, lhs.buffer[0..lhs.len], rhs.buffer[0..rhs.len]);
2295    }
2296
2297    pub const Kind = enum {
2298        /// No dynamic linker.
2299        none,
2300        /// Dynamic linker path is determined by the arch/OS components.
2301        arch_os,
2302        /// Dynamic linker path is determined by the arch/OS/ABI components.
2303        arch_os_abi,
2304    };
2305
2306    pub fn kind(os: Os.Tag) Kind {
2307        return switch (os) {
2308            .fuchsia,
2309
2310            .haiku,
2311            .illumos,
2312            .serenity,
2313
2314            .dragonfly,
2315            .freebsd,
2316            .netbsd,
2317            .openbsd,
2318
2319            .driverkit,
2320            .ios,
2321            .maccatalyst,
2322            .macos,
2323            .tvos,
2324            .visionos,
2325            .watchos,
2326            => .arch_os,
2327            .hurd,
2328            .linux,
2329            => .arch_os_abi,
2330            .freestanding,
2331            .other,
2332
2333            .contiki,
2334            .hermit,
2335            .managarm, // Needs to be double-checked.
2336
2337            .plan9,
2338            .rtems,
2339
2340            .uefi,
2341            .windows,
2342
2343            .@"3ds",
2344
2345            .emscripten,
2346            .wasi,
2347
2348            .amdhsa,
2349            .amdpal,
2350            .cuda,
2351            .mesa3d,
2352            .nvcl,
2353            .opencl,
2354            .opengl,
2355            .vulkan,
2356
2357            .ps3,
2358            .ps4,
2359            .ps5,
2360            .vita,
2361            => .none,
2362        };
2363    }
2364
2365    /// The strictness of this function depends on the value of `kind(os.tag)`:
2366    ///
2367    /// * `.none`: Ignores all arguments and just returns `none`.
2368    /// * `.arch_os`: Ignores `abi` and returns the dynamic linker matching `cpu` and `os`.
2369    /// * `.arch_os_abi`: Returns the dynamic linker matching `cpu`, `os`, and `abi`.
2370    ///
2371    /// In the case of `.arch_os` in particular, callers should be aware that a valid dynamic linker
2372    /// being returned only means that the `cpu` + `os` combination represents a platform that
2373    /// actually exists and which has an established dynamic linker path that does not change with
2374    /// the ABI; it does not necessarily mean that `abi` makes any sense at all for that platform.
2375    /// The responsibility for determining whether `abi` is valid in this case rests with the
2376    /// caller. `Abi.default()` can be used to pick a best-effort default ABI for such platforms.
2377    pub fn standard(cpu: Cpu, os: Os, abi: Abi) DynamicLinker {
2378        return switch (os.tag) {
2379            .fuchsia => switch (cpu.arch) {
2380                .aarch64,
2381                .riscv64,
2382                .x86_64,
2383                => init("ld.so.1"), // Fuchsia is unusual in that `DT_INTERP` is just a basename.
2384                else => none,
2385            },
2386
2387            .haiku => switch (cpu.arch) {
2388                .arm,
2389                .aarch64,
2390                .m68k,
2391                .powerpc,
2392                .riscv64,
2393                .sparc64,
2394                .x86,
2395                .x86_64,
2396                => init("/system/runtime_loader"),
2397                else => none,
2398            },
2399
2400            .hurd => switch (cpu.arch) {
2401                .aarch64,
2402                .aarch64_be,
2403                => |arch| if (abi == .gnu) initFmt("/lib/ld-{s}.so.1", .{@tagName(arch)}) else none,
2404
2405                .x86 => if (abi == .gnu) init("/lib/ld.so.1") else none,
2406                .x86_64 => initFmt("/lib/ld-{s}.so.1", .{switch (abi) {
2407                    .gnu => "x86-64",
2408                    .gnux32 => "x32",
2409                    else => return none,
2410                }}),
2411
2412                else => none,
2413            },
2414
2415            .illumos,
2416            => switch (cpu.arch) {
2417                .x86,
2418                .x86_64,
2419                => initFmt("/lib/{s}ld.so.1", .{if (ptrBitWidth_cpu_abi(cpu, .none) == 64) "64/" else ""}),
2420                else => none,
2421            },
2422
2423            .linux => if (abi.isAndroid())
2424                switch (cpu.arch) {
2425                    .arm => if (abi == .androideabi) init("/system/bin/linker") else none,
2426
2427                    .aarch64,
2428                    .riscv64,
2429                    .x86,
2430                    .x86_64,
2431                    => if (abi == .android) initFmt("/system/bin/linker{s}", .{
2432                        if (ptrBitWidth_cpu_abi(cpu, abi) == 64) "64" else "",
2433                    }) else none,
2434
2435                    else => none,
2436                }
2437            else if (abi.isMusl())
2438                switch (cpu.arch) {
2439                    .arm,
2440                    .armeb,
2441                    .thumb,
2442                    .thumbeb,
2443                    => |arch| initFmt("/lib/ld-musl-arm{s}{s}.so.1", .{
2444                        if (arch == .armeb or arch == .thumbeb) "eb" else "",
2445                        switch (abi) {
2446                            .musleabi => "",
2447                            .musleabihf => "hf",
2448                            else => return none,
2449                        },
2450                    }),
2451
2452                    .loongarch32,
2453                    .loongarch64,
2454                    => |arch| initFmt("/lib/ld-musl-{s}{s}.so.1", .{
2455                        @tagName(arch),
2456                        switch (abi) {
2457                            .musl => "",
2458                            .muslf32 => "-sp",
2459                            .muslsf => "-sf",
2460                            else => return none,
2461                        },
2462                    }),
2463
2464                    .aarch64,
2465                    .aarch64_be,
2466                    .hexagon,
2467                    .kvx,
2468                    .m68k,
2469                    .microblaze,
2470                    .microblazeel,
2471                    .powerpc64,
2472                    .powerpc64le,
2473                    .s390x,
2474                    => |arch| if (abi == .musl) initFmt("/lib/ld-musl-{s}.so.1", .{@tagName(arch)}) else none,
2475
2476                    .mips,
2477                    .mipsel,
2478                    => |arch| initFmt("/lib/ld-musl-mips{s}{s}{s}.so.1", .{
2479                        if (cpu.has(.mips, .mips32r6)) "r6" else "",
2480                        if (arch == .mipsel) "el" else "",
2481                        switch (abi) {
2482                            .musleabi => "-sf",
2483                            .musleabihf => "",
2484                            else => return none,
2485                        },
2486                    }),
2487
2488                    .mips64,
2489                    .mips64el,
2490                    => |arch| initFmt("/lib/ld-musl-mips{s}{s}{s}.so.1", .{
2491                        switch (abi) {
2492                            .muslabi64 => "64",
2493                            .muslabin32 => "n32",
2494                            else => return none,
2495                        },
2496                        if (cpu.has(.mips, .mips64r6)) "r6" else "",
2497                        if (arch == .mips64el) "el" else "",
2498                    }),
2499
2500                    .powerpc => initFmt("/lib/ld-musl-powerpc{s}.so.1", .{switch (abi) {
2501                        .musleabi => "-sf",
2502                        .musleabihf => "",
2503                        else => return none,
2504                    }}),
2505
2506                    .sh,
2507                    .sheb,
2508                    => |arch| initFmt("/lib/ld-musl-{t}{s}.so.1", .{
2509                        arch,
2510                        switch (abi) {
2511                            .musleabi => "-nofpu",
2512                            .musleabihf => "",
2513                            else => return none,
2514                        },
2515                    }),
2516
2517                    .riscv32,
2518                    .riscv64,
2519                    => |arch| if (abi == .musl) initFmt("/lib/ld-musl-{s}{s}.so.1", .{
2520                        @tagName(arch),
2521                        if (cpu.has(.riscv, .d))
2522                            ""
2523                        else if (cpu.has(.riscv, .f))
2524                            "-sp"
2525                        else
2526                            "-sf",
2527                    }) else none,
2528
2529                    .x86 => if (abi == .musl) init("/lib/ld-musl-i386.so.1") else none,
2530
2531                    .x86_64 => initFmt("/lib/ld-musl-{s}.so.1", .{switch (abi) {
2532                        .musl => "x86_64",
2533                        .muslx32 => "x32",
2534                        else => return none,
2535                    }}),
2536
2537                    else => none,
2538                }
2539            else if (abi.isGnu())
2540                switch (cpu.arch) {
2541                    // TODO: `700` ABI support.
2542                    .arc,
2543                    .arceb,
2544                    => |arch| if (abi == .gnu) initFmt("/lib/ld-linux-{t}.so.2", .{arch}) else none,
2545
2546                    .arm,
2547                    .armeb,
2548                    .thumb,
2549                    .thumbeb,
2550                    => initFmt("/lib/ld-linux{s}.so.3", .{switch (abi) {
2551                        .gnueabi => "",
2552                        .gnueabihf => "-armhf",
2553                        else => return none,
2554                    }}),
2555
2556                    .aarch64,
2557                    .aarch64_be,
2558                    => |arch| if (abi == .gnu) initFmt("/lib/ld-linux-{s}.so.1", .{@tagName(arch)}) else none,
2559
2560                    // TODO: `-be` architecture support.
2561                    .csky => initFmt("/lib/ld-linux-cskyv2{s}.so.1", .{switch (abi) {
2562                        .gnueabi => "",
2563                        .gnueabihf => "-hf",
2564                        else => return none,
2565                    }}),
2566
2567                    .loongarch64 => initFmt("/lib64/ld-linux-loongarch-{s}.so.1", .{switch (abi) {
2568                        .gnu => "lp64d",
2569                        .gnuf32 => "lp64f",
2570                        .gnusf => "lp64s",
2571                        else => return none,
2572                    }}),
2573
2574                    .hppa,
2575                    .m68k,
2576                    .microblaze,
2577                    .microblazeel,
2578                    .xtensa,
2579                    .xtensaeb,
2580                    => if (abi == .gnu) init("/lib/ld.so.1") else none,
2581
2582                    .mips,
2583                    .mipsel,
2584                    => switch (abi) {
2585                        .gnueabi,
2586                        .gnueabihf,
2587                        => initFmt("/lib/ld{s}.so.1", .{
2588                            if (cpu.has(.mips, .nan2008)) "-linux-mipsn8" else "",
2589                        }),
2590                        else => none,
2591                    },
2592
2593                    .mips64,
2594                    .mips64el,
2595                    => initFmt("/lib{s}/ld{s}.so.1", .{
2596                        switch (abi) {
2597                            .gnuabi64 => "64",
2598                            .gnuabin32 => "32",
2599                            else => return none,
2600                        },
2601                        if (cpu.has(.mips, .nan2008)) "-linux-mipsn8" else "",
2602                    }),
2603
2604                    .powerpc => switch (abi) {
2605                        .gnueabi,
2606                        .gnueabihf,
2607                        => init("/lib/ld.so.1"),
2608                        else => none,
2609                    },
2610
2611                    .powerpc64,
2612                    .powerpc64le,
2613                    => if (abi == .gnu) init("/lib64/ld64.so.2") else none,
2614
2615                    .riscv32,
2616                    .riscv64,
2617                    => |arch| if (abi == .gnu) initFmt("/lib/ld-linux-{s}{s}.so.1", .{
2618                        switch (arch) {
2619                            .riscv32 => "riscv32-ilp32",
2620                            .riscv64 => "riscv64-lp64",
2621                            else => unreachable,
2622                        },
2623                        if (cpu.has(.riscv, .d))
2624                            "d"
2625                        else if (cpu.has(.riscv, .f))
2626                            "f"
2627                        else
2628                            "",
2629                    }) else none,
2630
2631                    .s390x => if (abi == .gnu) init("/lib/ld64.so.1") else none,
2632
2633                    .sh,
2634                    .sheb,
2635                    => switch (abi) {
2636                        .gnueabi,
2637                        .gnueabihf,
2638                        => init("/lib/ld-linux.so.2"),
2639                        else => none,
2640                    },
2641
2642                    .alpha,
2643                    .sparc,
2644                    .x86,
2645                    => if (abi == .gnu) init("/lib/ld-linux.so.2") else none,
2646
2647                    .sparc64 => if (abi == .gnu) init("/lib64/ld-linux.so.2") else none,
2648
2649                    .x86_64 => switch (abi) {
2650                        .gnu => init("/lib64/ld-linux-x86-64.so.2"),
2651                        .gnux32 => init("/libx32/ld-linux-x32.so.2"),
2652                        else => none,
2653                    },
2654
2655                    else => none,
2656                }
2657            else
2658                none, // Not a known Linux libc.
2659
2660            .serenity => switch (cpu.arch) {
2661                .aarch64,
2662                .riscv64,
2663                .x86_64,
2664                => init("/usr/lib/Loader.so"),
2665                else => none,
2666            },
2667
2668            .dragonfly => if (cpu.arch == .x86_64) initFmt("{s}/libexec/ld-elf.so.2", .{
2669                if (os.version_range.semver.isAtLeast(.{ .major = 3, .minor = 8, .patch = 0 }) orelse false)
2670                    ""
2671                else
2672                    "/usr",
2673            }) else none,
2674
2675            .freebsd => switch (cpu.arch) {
2676                .arm,
2677                .aarch64,
2678                .powerpc,
2679                .powerpc64,
2680                .powerpc64le,
2681                .riscv64,
2682                .x86,
2683                .x86_64,
2684                => initFmt("{s}/libexec/ld-elf.so.1", .{
2685                    if (os.version_range.semver.isAtLeast(.{ .major = 6, .minor = 0, .patch = 0 }) orelse false)
2686                        ""
2687                    else
2688                        "/usr",
2689                }),
2690                else => none,
2691            },
2692
2693            .netbsd => switch (cpu.arch) {
2694                .alpha,
2695                .arm,
2696                .armeb,
2697                .aarch64,
2698                .aarch64_be,
2699                .hppa,
2700                .m68k,
2701                .mips,
2702                .mipsel,
2703                .mips64,
2704                .mips64el,
2705                .powerpc,
2706                .sh,
2707                .sheb,
2708                .sparc,
2709                .sparc64,
2710                .x86,
2711                .x86_64,
2712                => init("/libexec/ld.elf_so"),
2713                else => none,
2714            },
2715
2716            .openbsd => switch (cpu.arch) {
2717                .alpha,
2718                .arm,
2719                .aarch64,
2720                .hppa,
2721                .mips64,
2722                .mips64el,
2723                .powerpc,
2724                .powerpc64,
2725                .riscv64,
2726                .sh,
2727                .sheb,
2728                .sparc64,
2729                .x86,
2730                .x86_64,
2731                => init("/usr/libexec/ld.so"),
2732                else => none,
2733            },
2734
2735            .driverkit,
2736            .ios,
2737            .maccatalyst,
2738            .macos,
2739            .tvos,
2740            .visionos,
2741            .watchos,
2742            => switch (cpu.arch) {
2743                .aarch64,
2744                .x86_64,
2745                => init("/usr/lib/dyld"),
2746                else => none,
2747            },
2748
2749            // Operating systems in this list have been verified as not having a standard
2750            // dynamic linker path.
2751            .freestanding,
2752            .other,
2753
2754            .contiki,
2755            .hermit,
2756
2757            .plan9,
2758            .rtems,
2759
2760            .uefi,
2761            .windows,
2762
2763            .@"3ds",
2764
2765            .vita,
2766
2767            .emscripten,
2768            .wasi,
2769
2770            .amdhsa,
2771            .amdpal,
2772            .cuda,
2773            .mesa3d,
2774            .nvcl,
2775            .opencl,
2776            .opengl,
2777            .vulkan,
2778            => none,
2779
2780            // TODO go over each item in this list and either move it to the above list, or
2781            // implement the standard dynamic linker path code for it.
2782            .managarm,
2783
2784            .ps3,
2785            .ps4,
2786            .ps5,
2787            => none,
2788        } catch unreachable;
2789    }
2790};
2791
2792pub fn standardDynamicLinkerPath(target: *const Target) DynamicLinker {
2793    return DynamicLinker.standard(target.cpu, target.os, target.abi);
2794}
2795
2796pub fn ptrBitWidth_cpu_abi(cpu: Cpu, abi: Abi) u16 {
2797    return ptrBitWidth_arch_abi(cpu.arch, abi);
2798}
2799
2800pub fn ptrBitWidth_arch_abi(cpu_arch: Cpu.Arch, abi: Abi) u16 {
2801    switch (abi) {
2802        .gnux32, .muslx32, .gnuabin32, .muslabin32, .ilp32 => return 32,
2803        .gnuabi64, .muslabi64 => return 64,
2804        else => {},
2805    }
2806    return switch (cpu_arch) {
2807        .avr,
2808        .msp430,
2809        .x86_16,
2810        => 16,
2811
2812        .arc,
2813        .arceb,
2814        .arm,
2815        .armeb,
2816        .csky,
2817        .hexagon,
2818        .hppa,
2819        .kalimba,
2820        .lanai,
2821        .loongarch32,
2822        .m68k,
2823        .microblaze,
2824        .microblazeel,
2825        .mips,
2826        .mipsel,
2827        .nvptx,
2828        .or1k,
2829        .powerpc,
2830        .powerpcle,
2831        .propeller,
2832        .riscv32,
2833        .riscv32be,
2834        .sh,
2835        .sheb,
2836        .sparc,
2837        .spirv32,
2838        .thumb,
2839        .thumbeb,
2840        .wasm32,
2841        .x86,
2842        .xcore,
2843        .xtensa,
2844        .xtensaeb,
2845        => 32,
2846
2847        .aarch64,
2848        .aarch64_be,
2849        .alpha,
2850        .amdgcn,
2851        .bpfeb,
2852        .bpfel,
2853        .hppa64,
2854        .kvx,
2855        .loongarch64,
2856        .mips64,
2857        .mips64el,
2858        .nvptx64,
2859        .powerpc64,
2860        .powerpc64le,
2861        .riscv64,
2862        .riscv64be,
2863        .s390x,
2864        .sparc64,
2865        .spirv64,
2866        .ve,
2867        .wasm64,
2868        .x86_64,
2869        => 64,
2870    };
2871}
2872
2873pub fn ptrBitWidth(target: *const Target) u16 {
2874    return ptrBitWidth_cpu_abi(target.cpu, target.abi);
2875}
2876
2877pub fn stackAlignment(target: *const Target) u16 {
2878    // Overrides for when the stack alignment is not equal to the pointer width.
2879    switch (target.cpu.arch) {
2880        .m68k,
2881        => return 2,
2882        .amdgcn,
2883        => return 4,
2884        .arm,
2885        .armeb,
2886        .hppa,
2887        .lanai,
2888        .mips,
2889        .mipsel,
2890        .sparc,
2891        .thumb,
2892        .thumbeb,
2893        => return 8,
2894        .aarch64,
2895        .aarch64_be,
2896        .alpha,
2897        .bpfeb,
2898        .bpfel,
2899        .hppa64,
2900        .loongarch32,
2901        .loongarch64,
2902        .mips64,
2903        .mips64el,
2904        .sparc64,
2905        .ve,
2906        .wasm32,
2907        .wasm64,
2908        .x86_64,
2909        => return 16,
2910        // Some of the following prongs should really be testing the ABI, but our current `Abi` enum
2911        // can't handle that level of nuance yet.
2912        .powerpc64,
2913        .powerpc64le,
2914        => if (target.os.tag == .linux) return 16,
2915        .riscv32,
2916        .riscv32be,
2917        .riscv64,
2918        .riscv64be,
2919        => if (!target.cpu.has(.riscv, .e)) return 16,
2920        .x86 => if (target.os.tag != .windows and target.os.tag != .uefi) return 16,
2921        .kvx => return 32,
2922        else => {},
2923    }
2924
2925    return @divExact(target.ptrBitWidth(), 8);
2926}
2927
2928pub const StackGrowth = enum {
2929    down,
2930    up,
2931};
2932
2933pub fn stackGrowth(target: *const Target) StackGrowth {
2934    // Strictly speaking, most architectures don't inherently define the stack growth direction; you
2935    // could quite easily argue that it is in fact a property of the ABI. However, that's just not
2936    // really how it plays out in the real world. And besides, we have no mechanism for indicating
2937    // a different stack growth ABI, nor a compelling use case for creating such a mechanism.
2938    return switch (target.cpu.arch) {
2939        .hppa,
2940        .hppa64,
2941        => .up,
2942        else => .down,
2943    };
2944}
2945
2946/// Default signedness of `char` for the native C compiler for this target
2947/// Note that char signedness is implementation-defined and many compilers provide
2948/// an option to override the default signedness e.g. GCC's -funsigned-char / -fsigned-char
2949pub fn cCharSignedness(target: *const Target) std.builtin.Signedness {
2950    if (target.os.tag.isDarwin() or target.os.tag == .windows or target.os.tag == .uefi) return .signed;
2951
2952    return switch (target.cpu.arch) {
2953        .aarch64,
2954        .aarch64_be,
2955        .arm,
2956        .armeb,
2957        .arc,
2958        .arceb,
2959        .csky,
2960        .hexagon,
2961        .msp430,
2962        .powerpc,
2963        .powerpcle,
2964        .powerpc64,
2965        .powerpc64le,
2966        .s390x,
2967        .riscv32,
2968        .riscv32be,
2969        .riscv64,
2970        .riscv64be,
2971        .thumb,
2972        .thumbeb,
2973        .xcore,
2974        .xtensa,
2975        .xtensaeb,
2976        => .unsigned,
2977        else => .signed,
2978    };
2979}
2980
2981pub const CType = enum {
2982    char,
2983    short,
2984    ushort,
2985    int,
2986    uint,
2987    long,
2988    ulong,
2989    longlong,
2990    ulonglong,
2991    float,
2992    double,
2993    longdouble,
2994};
2995
2996pub fn cTypeByteSize(t: *const Target, c_type: CType) u16 {
2997    return switch (c_type) {
2998        .char,
2999        .short,
3000        .ushort,
3001        .int,
3002        .uint,
3003        .long,
3004        .ulong,
3005        .longlong,
3006        .ulonglong,
3007        .float,
3008        .double,
3009        => @divExact(cTypeBitSize(t, c_type), 8),
3010
3011        .longdouble => switch (cTypeBitSize(t, c_type)) {
3012            16 => 2,
3013            32 => 4,
3014            64 => 8,
3015            80 => @intCast(std.mem.alignForward(usize, 10, cTypeAlignment(t, .longdouble))),
3016            128 => 16,
3017            else => unreachable,
3018        },
3019    };
3020}
3021
3022pub fn cTypeBitSize(target: *const Target, c_type: CType) u16 {
3023    switch (target.os.tag) {
3024        .freestanding, .other => switch (target.cpu.arch) {
3025            .msp430, .x86_16 => switch (c_type) {
3026                .char => return 8,
3027                .short, .ushort, .int, .uint => return 16,
3028                .float, .long, .ulong => return 32,
3029                .longlong, .ulonglong, .double, .longdouble => return 64,
3030            },
3031            .avr => switch (c_type) {
3032                .char => return 8,
3033                .short, .ushort, .int, .uint => return 16,
3034                .long, .ulong, .float, .double, .longdouble => return 32,
3035                .longlong, .ulonglong => return 64,
3036            },
3037            .mips64, .mips64el => switch (c_type) {
3038                .char => return 8,
3039                .short, .ushort => return 16,
3040                .int, .uint, .float => return 32,
3041                .long, .ulong => switch (target.abi) {
3042                    .gnuabin32, .muslabin32 => return 32,
3043                    else => return 64,
3044                },
3045                .longlong, .ulonglong, .double => return 64,
3046                .longdouble => return 128,
3047            },
3048            .x86_64 => switch (c_type) {
3049                .char => return 8,
3050                .short, .ushort => return 16,
3051                .int, .uint, .float => return 32,
3052                .long, .ulong => switch (target.abi) {
3053                    .gnux32, .muslx32 => return 32,
3054                    else => return 64,
3055                },
3056                .longlong, .ulonglong, .double => return 64,
3057                .longdouble => return 80,
3058            },
3059            else => switch (c_type) {
3060                .char => return 8,
3061                .short, .ushort => return 16,
3062                .int, .uint, .float => return 32,
3063                .long, .ulong => return target.ptrBitWidth(),
3064                .longlong, .ulonglong, .double => return 64,
3065                .longdouble => switch (target.cpu.arch) {
3066                    .x86 => switch (target.abi) {
3067                        .android => return 64,
3068                        else => return 80,
3069                    },
3070
3071                    .powerpc,
3072                    .powerpcle,
3073                    .powerpc64,
3074                    .powerpc64le,
3075                    => switch (target.abi) {
3076                        .musl,
3077                        .muslabin32,
3078                        .muslabi64,
3079                        .musleabi,
3080                        .musleabihf,
3081                        .muslx32,
3082                        => return 64,
3083                        else => return 128,
3084                    },
3085
3086                    .alpha,
3087                    .riscv32,
3088                    .riscv32be,
3089                    .riscv64,
3090                    .riscv64be,
3091                    .aarch64,
3092                    .aarch64_be,
3093                    .s390x,
3094                    .sparc64,
3095                    .wasm32,
3096                    .wasm64,
3097                    .loongarch32,
3098                    .loongarch64,
3099                    .ve,
3100                    => return 128,
3101
3102                    else => return 64,
3103                },
3104            },
3105        },
3106
3107        .fuchsia,
3108        .hermit,
3109
3110        .haiku,
3111        .hurd,
3112        .illumos,
3113        .linux,
3114        .plan9,
3115        .rtems,
3116        .serenity,
3117
3118        .freebsd,
3119        .dragonfly,
3120        .netbsd,
3121        .openbsd,
3122
3123        .wasi,
3124        .emscripten,
3125        => switch (target.cpu.arch) {
3126            .mips64, .mips64el => switch (c_type) {
3127                .char => return 8,
3128                .short, .ushort => return 16,
3129                .int, .uint, .float => return 32,
3130                .long, .ulong => switch (target.abi) {
3131                    .gnuabin32, .muslabin32 => return 32,
3132                    else => return 64,
3133                },
3134                .longlong, .ulonglong, .double => return 64,
3135                .longdouble => if (target.os.tag == .freebsd) return 64 else return 128,
3136            },
3137            .x86_64 => switch (c_type) {
3138                .char => return 8,
3139                .short, .ushort => return 16,
3140                .int, .uint, .float => return 32,
3141                .long, .ulong => switch (target.abi) {
3142                    .gnux32, .muslx32 => return 32,
3143                    else => return 64,
3144                },
3145                .longlong, .ulonglong, .double => return 64,
3146                .longdouble => return 80,
3147            },
3148            else => switch (c_type) {
3149                .char => return 8,
3150                .short, .ushort => return 16,
3151                .int, .uint, .float => return 32,
3152                .long, .ulong => return target.ptrBitWidth(),
3153                .longlong, .ulonglong, .double => return 64,
3154                .longdouble => switch (target.cpu.arch) {
3155                    .x86 => switch (target.abi) {
3156                        .android => return 64,
3157                        else => return 80,
3158                    },
3159
3160                    .powerpc,
3161                    .powerpcle,
3162                    => switch (target.abi) {
3163                        .musl,
3164                        .muslabin32,
3165                        .muslabi64,
3166                        .musleabi,
3167                        .musleabihf,
3168                        .muslx32,
3169                        => return 64,
3170                        else => switch (target.os.tag) {
3171                            .freebsd, .netbsd, .openbsd => return 64,
3172                            else => return 128,
3173                        },
3174                    },
3175
3176                    .powerpc64,
3177                    .powerpc64le,
3178                    => switch (target.abi) {
3179                        .musl,
3180                        .muslabin32,
3181                        .muslabi64,
3182                        .musleabi,
3183                        .musleabihf,
3184                        .muslx32,
3185                        => return 64,
3186                        else => switch (target.os.tag) {
3187                            .freebsd, .openbsd => return 64,
3188                            else => return 128,
3189                        },
3190                    },
3191
3192                    .alpha,
3193                    .riscv32,
3194                    .riscv32be,
3195                    .riscv64,
3196                    .riscv64be,
3197                    .aarch64,
3198                    .aarch64_be,
3199                    .s390x,
3200                    .mips64,
3201                    .mips64el,
3202                    .sparc64,
3203                    .wasm32,
3204                    .wasm64,
3205                    .loongarch32,
3206                    .loongarch64,
3207                    .ve,
3208                    => return 128,
3209
3210                    else => return 64,
3211                },
3212            },
3213        },
3214
3215        .windows, .uefi => switch (target.cpu.arch) {
3216            .x86 => switch (c_type) {
3217                .char => return 8,
3218                .short, .ushort => return 16,
3219                .int, .uint, .float => return 32,
3220                .long, .ulong => return 32,
3221                .longlong, .ulonglong, .double => return 64,
3222                .longdouble => switch (target.abi) {
3223                    .gnu, .ilp32 => return 80,
3224                    else => return 64,
3225                },
3226            },
3227            .x86_64 => switch (c_type) {
3228                .char => return 8,
3229                .short, .ushort => return 16,
3230                .int, .uint, .float => return 32,
3231                .long, .ulong => return 32,
3232                .longlong, .ulonglong, .double => return 64,
3233                .longdouble => switch (target.abi) {
3234                    .gnu, .ilp32 => return 80,
3235                    else => return 64,
3236                },
3237            },
3238            else => switch (c_type) {
3239                .char => return 8,
3240                .short, .ushort => return 16,
3241                .int, .uint, .float => return 32,
3242                .long, .ulong => return 32,
3243                .longlong, .ulonglong, .double => return 64,
3244                .longdouble => return 64,
3245            },
3246        },
3247
3248        .driverkit,
3249        .ios,
3250        .maccatalyst,
3251        .macos,
3252        .tvos,
3253        .visionos,
3254        .watchos,
3255        => switch (c_type) {
3256            .char => return 8,
3257            .short, .ushort => return 16,
3258            .int, .uint, .float => return 32,
3259            .long, .ulong => switch (target.cpu.arch) {
3260                .x86_64 => return 64,
3261                else => switch (target.abi) {
3262                    .ilp32 => return 32,
3263                    else => return 64,
3264                },
3265            },
3266            .longlong, .ulonglong, .double => return 64,
3267            .longdouble => switch (target.cpu.arch) {
3268                .x86_64 => return 80,
3269                else => return 64,
3270            },
3271        },
3272
3273        .nvcl, .cuda => switch (c_type) {
3274            .char => return 8,
3275            .short, .ushort => return 16,
3276            .int, .uint, .float => return 32,
3277            .long, .ulong => switch (target.cpu.arch) {
3278                .nvptx => return 32,
3279                .nvptx64 => return 64,
3280                else => return 64,
3281            },
3282            .longlong, .ulonglong, .double => return 64,
3283            .longdouble => return 64,
3284        },
3285
3286        .amdhsa, .amdpal, .mesa3d => switch (c_type) {
3287            .char => return 8,
3288            .short, .ushort => return 16,
3289            .int, .uint, .float => return 32,
3290            .long, .ulong, .longlong, .ulonglong, .double => return 64,
3291            .longdouble => return 128,
3292        },
3293
3294        .opencl, .vulkan => switch (c_type) {
3295            .char => return 8,
3296            .short, .ushort => return 16,
3297            .int, .uint, .float => return 32,
3298            .long, .ulong, .double => return 64,
3299            .longlong, .ulonglong => return 128,
3300            // Note: The OpenCL specification does not guarantee a particular size for long double,
3301            // but clang uses 128 bits.
3302            .longdouble => return 128,
3303        },
3304
3305        .@"3ds" => switch (c_type) {
3306            .char => return 8,
3307            .short, .ushort => return 16,
3308            .int, .uint, .float, .long, .ulong => return 32,
3309            .longlong, .ulonglong, .double, .longdouble => return 64,
3310        },
3311
3312        .ps4, .ps5 => switch (c_type) {
3313            .char => return 8,
3314            .short, .ushort => return 16,
3315            .int, .uint, .float => return 32,
3316            .long, .ulong => return 64,
3317            .longlong, .ulonglong, .double => return 64,
3318            .longdouble => return 80,
3319        },
3320        .vita => switch (c_type) {
3321            .char => return 8,
3322            .short, .ushort => return 16,
3323            .int, .uint, .float => return 32,
3324            .long, .ulong => return 64,
3325            .longlong, .ulonglong, .double, .longdouble => return 64,
3326        },
3327
3328        .ps3,
3329        .contiki,
3330        .managarm,
3331        .opengl,
3332        => @panic("specify the C integer and float type sizes for this OS"),
3333    }
3334}
3335
3336pub fn cTypeAlignment(target: *const Target, c_type: CType) u16 {
3337    // Overrides for unusual alignments
3338    switch (target.cpu.arch) {
3339        .avr => return 1,
3340        .x86 => switch (target.os.tag) {
3341            .windows, .uefi => switch (c_type) {
3342                .longlong, .ulonglong, .double => return 8,
3343                .longdouble => switch (target.abi) {
3344                    .gnu, .ilp32 => return 4,
3345                    else => return 8,
3346                },
3347                else => {},
3348            },
3349            else => {},
3350        },
3351        .m68k => switch (c_type) {
3352            .int, .uint, .long, .ulong => return 2,
3353            else => {},
3354        },
3355        .wasm32, .wasm64 => switch (target.os.tag) {
3356            .emscripten => switch (c_type) {
3357                .longdouble => return 8,
3358                else => {},
3359            },
3360            else => {},
3361        },
3362        else => {},
3363    }
3364
3365    // Next-power-of-two-aligned, up to a maximum.
3366    return @min(
3367        std.math.ceilPowerOfTwoAssert(u16, (cTypeBitSize(target, c_type) + 7) / 8),
3368        @as(u16, switch (target.cpu.arch) {
3369            .msp430,
3370            .x86_16,
3371            => 2,
3372
3373            .arc,
3374            .arceb,
3375            .csky,
3376            .kalimba,
3377            .microblaze,
3378            .microblazeel,
3379            .or1k,
3380            .propeller,
3381            .sh,
3382            .sheb,
3383            .x86,
3384            .xcore,
3385            .xtensa,
3386            .xtensaeb,
3387            => 4,
3388
3389            .amdgcn,
3390            .arm,
3391            .armeb,
3392            .bpfeb,
3393            .bpfel,
3394            .hexagon,
3395            .hppa,
3396            .lanai,
3397            .m68k,
3398            .mips,
3399            .mipsel,
3400            .nvptx,
3401            .nvptx64,
3402            .s390x,
3403            .sparc,
3404            .thumb,
3405            .thumbeb,
3406            => 8,
3407
3408            .aarch64,
3409            .aarch64_be,
3410            .alpha,
3411            .hppa64,
3412            .kvx,
3413            .loongarch32,
3414            .loongarch64,
3415            .mips64,
3416            .mips64el,
3417            .powerpc,
3418            .powerpcle,
3419            .powerpc64,
3420            .powerpc64le,
3421            .riscv32,
3422            .riscv32be,
3423            .riscv64,
3424            .riscv64be,
3425            .sparc64,
3426            .spirv32,
3427            .spirv64,
3428            .ve,
3429            .wasm32,
3430            .wasm64,
3431            .x86_64,
3432            => 16,
3433
3434            .avr,
3435            => unreachable, // Handled above.
3436        }),
3437    );
3438}
3439
3440pub fn cTypePreferredAlignment(target: *const Target, c_type: CType) u16 {
3441    // Overrides for unusual alignments
3442    switch (target.cpu.arch) {
3443        .arc, .arceb => switch (c_type) {
3444            .longdouble => return 4,
3445            else => {},
3446        },
3447        .avr => return 1,
3448        .x86 => switch (target.os.tag) {
3449            .windows, .uefi => switch (c_type) {
3450                .longdouble => switch (target.abi) {
3451                    .gnu, .ilp32 => return 4,
3452                    else => return 8,
3453                },
3454                else => {},
3455            },
3456            else => switch (c_type) {
3457                .longdouble => return 4,
3458                else => {},
3459            },
3460        },
3461        .m68k => switch (c_type) {
3462            .int, .uint, .long, .ulong => return 2,
3463            else => {},
3464        },
3465        .wasm32, .wasm64 => switch (target.os.tag) {
3466            .emscripten => switch (c_type) {
3467                .longdouble => return 8,
3468                else => {},
3469            },
3470            else => {},
3471        },
3472        else => {},
3473    }
3474
3475    // Next-power-of-two-aligned, up to a maximum.
3476    return @min(
3477        std.math.ceilPowerOfTwoAssert(u16, (cTypeBitSize(target, c_type) + 7) / 8),
3478        @as(u16, switch (target.cpu.arch) {
3479            .x86_16, .msp430 => 2,
3480
3481            .arc,
3482            .arceb,
3483            .csky,
3484            .kalimba,
3485            .microblaze,
3486            .microblazeel,
3487            .or1k,
3488            .propeller,
3489            .sh,
3490            .sheb,
3491            .xcore,
3492            .xtensa,
3493            .xtensaeb,
3494            => 4,
3495
3496            .amdgcn,
3497            .arm,
3498            .armeb,
3499            .bpfeb,
3500            .bpfel,
3501            .hexagon,
3502            .hppa,
3503            .lanai,
3504            .m68k,
3505            .mips,
3506            .mipsel,
3507            .nvptx,
3508            .nvptx64,
3509            .s390x,
3510            .sparc,
3511            .thumb,
3512            .thumbeb,
3513            .x86,
3514            => 8,
3515
3516            .aarch64,
3517            .aarch64_be,
3518            .alpha,
3519            .hppa64,
3520            .kvx,
3521            .loongarch32,
3522            .loongarch64,
3523            .mips64,
3524            .mips64el,
3525            .powerpc,
3526            .powerpcle,
3527            .powerpc64,
3528            .powerpc64le,
3529            .riscv32,
3530            .riscv32be,
3531            .riscv64,
3532            .riscv64be,
3533            .sparc64,
3534            .spirv32,
3535            .spirv64,
3536            .ve,
3537            .wasm32,
3538            .wasm64,
3539            .x86_64,
3540            => 16,
3541
3542            .avr,
3543            => unreachable, // Handled above.
3544        }),
3545    );
3546}
3547
3548pub fn cMaxIntAlignment(target: *const Target) u16 {
3549    return switch (target.cpu.arch) {
3550        .avr => 1,
3551
3552        .msp430, .x86_16 => 2,
3553
3554        .arc,
3555        .arceb,
3556        .csky,
3557        .kalimba,
3558        .microblaze,
3559        .microblazeel,
3560        .or1k,
3561        .propeller,
3562        .sh,
3563        .sheb,
3564        .xcore,
3565        => 4,
3566
3567        .arm,
3568        .armeb,
3569        .hexagon,
3570        .hppa,
3571        .lanai,
3572        .loongarch32,
3573        .m68k,
3574        .mips,
3575        .mipsel,
3576        .powerpc,
3577        .powerpcle,
3578        .riscv32,
3579        .riscv32be,
3580        .s390x,
3581        .sparc,
3582        .thumb,
3583        .thumbeb,
3584        .x86,
3585        .xtensa,
3586        .xtensaeb,
3587        => 8,
3588
3589        .aarch64,
3590        .aarch64_be,
3591        .alpha,
3592        .amdgcn,
3593        .bpfel,
3594        .bpfeb,
3595        .hppa64,
3596        .kvx,
3597        .loongarch64,
3598        .mips64,
3599        .mips64el,
3600        .nvptx,
3601        .nvptx64,
3602        .powerpc64,
3603        .powerpc64le,
3604        .riscv64,
3605        .riscv64be,
3606        .sparc64,
3607        .spirv32,
3608        .spirv64,
3609        .ve,
3610        .wasm32,
3611        .wasm64,
3612        .x86_64,
3613        => 16,
3614    };
3615}
3616
3617pub fn cCallingConvention(target: *const Target) ?std.builtin.CallingConvention {
3618    return switch (target.cpu.arch) {
3619        .x86_64 => switch (target.os.tag) {
3620            .windows, .uefi => .{ .x86_64_win = .{} },
3621            else => switch (target.abi) {
3622                .gnuabin32, .muslabin32 => .{ .x86_64_x32 = .{} },
3623                else => .{ .x86_64_sysv = .{} },
3624            },
3625        },
3626        .x86 => switch (target.os.tag) {
3627            .windows, .uefi => .{ .x86_win = .{} },
3628            else => .{ .x86_sysv = .{} },
3629        },
3630        .x86_16 => .{ .x86_16_cdecl = .{} },
3631        .aarch64, .aarch64_be => if (target.os.tag.isDarwin())
3632            .{ .aarch64_aapcs_darwin = .{} }
3633        else switch (target.os.tag) {
3634            .windows => .{ .aarch64_aapcs_win = .{} },
3635            else => .{ .aarch64_aapcs = .{} },
3636        },
3637        .alpha => .{ .alpha_osf = .{} },
3638        .arm, .armeb, .thumb, .thumbeb => switch (target.abi.float()) {
3639            .soft => .{ .arm_aapcs = .{} },
3640            .hard => .{ .arm_aapcs_vfp = .{} },
3641        },
3642        .mips64, .mips64el => switch (target.abi) {
3643            .gnuabin32, .muslabin32 => .{ .mips64_n32 = .{} },
3644            else => .{ .mips64_n64 = .{} },
3645        },
3646        .mips, .mipsel => .{ .mips_o32 = .{} },
3647        .riscv64, .riscv64be => .{ .riscv64_lp64 = .{} },
3648        .riscv32, .riscv32be => .{ .riscv32_ilp32 = .{} },
3649        .sparc64 => .{ .sparc64_sysv = .{} },
3650        .sparc => .{ .sparc_sysv = .{} },
3651        .powerpc64 => if (target.abi.isMusl())
3652            .{ .powerpc64_elf_v2 = .{} }
3653        else
3654            .{ .powerpc64_elf = .{} },
3655        .powerpc64le => .{ .powerpc64_elf_v2 = .{} },
3656        .powerpc, .powerpcle => .{ .powerpc_sysv = .{} },
3657        .wasm32, .wasm64 => .{ .wasm_mvp = .{} },
3658        .arc, .arceb => .{ .arc_sysv = .{} },
3659        .avr => .avr_gnu,
3660        .bpfel, .bpfeb => .{ .bpf_std = .{} },
3661        .csky => .{ .csky_sysv = .{} },
3662        .hexagon => .{ .hexagon_sysv = .{} },
3663        .hppa => .{ .hppa_elf = .{} },
3664        .hppa64 => .{ .hppa64_elf = .{} },
3665        .kalimba => null,
3666        .kvx => switch (target.abi) {
3667            .ilp32 => .{ .kvx_ilp32 = .{} },
3668            else => .{ .kvx_lp64 = .{} },
3669        },
3670        .lanai => .{ .lanai_sysv = .{} },
3671        .loongarch64 => .{ .loongarch64_lp64 = .{} },
3672        .loongarch32 => .{ .loongarch32_ilp32 = .{} },
3673        .m68k => if (target.abi.isGnu() or target.abi.isMusl())
3674            .{ .m68k_gnu = .{} }
3675        else
3676            .{ .m68k_sysv = .{} },
3677        .microblaze, .microblazeel => .{ .microblaze_std = .{} },
3678        .msp430 => .{ .msp430_eabi = .{} },
3679        .or1k => .{ .or1k_sysv = .{} },
3680        .propeller => .{ .propeller_sysv = .{} },
3681        .s390x => .{ .s390x_sysv = .{} },
3682        .sh, .sheb => .{ .sh_gnu = .{} },
3683        .ve => .{ .ve_sysv = .{} },
3684        .xcore => .{ .xcore_xs1 = .{} },
3685        .xtensa, .xtensaeb => .{ .xtensa_call0 = .{} },
3686        .amdgcn => .{ .amdgcn_device = .{} },
3687        .nvptx, .nvptx64 => .nvptx_device,
3688        .spirv32, .spirv64 => .spirv_device,
3689    };
3690}
3691
3692const Target = @This();
3693const std = @import("std.zig");
3694const builtin = @import("builtin");
3695const Allocator = std.mem.Allocator;
3696const assert = std.debug.assert;
3697
3698test {
3699    std.testing.refAllDecls(Cpu.Arch);
3700}