master
   1const std = @import("std");
   2const builtin = @import("builtin");
   3const fs = std.fs;
   4const mem = std.mem;
   5const json = std.json;
   6const assert = std.debug.assert;
   7
   8// All references to other features are based on "zig name" as the key.
   9
  10const FeatureOverride = struct {
  11    llvm_name: []const u8,
  12    /// If true, completely omit the feature; as if it does not exist.
  13    omit: bool = false,
  14    /// If true, omit the feature, but all the dependencies of the feature
  15    /// are added in its place.
  16    flatten: bool = false,
  17    zig_name: ?[]const u8 = null,
  18    desc: ?[]const u8 = null,
  19    omit_deps: []const []const u8 = &.{},
  20    extra_deps: []const []const u8 = &.{},
  21};
  22
  23const Cpu = struct {
  24    llvm_name: ?[]const u8,
  25    zig_name: []const u8,
  26    features: []const []const u8,
  27};
  28
  29const Feature = struct {
  30    llvm_name: ?[]const u8 = null,
  31    zig_name: []const u8,
  32    desc: []const u8,
  33    deps: []const []const u8,
  34    flatten: bool = false,
  35};
  36
  37const ArchTarget = struct {
  38    zig_name: []const u8,
  39    llvm: ?struct {
  40        name: []const u8,
  41        td_name: []const u8,
  42    },
  43    feature_overrides: []const FeatureOverride = &.{},
  44    extra_cpus: []const Cpu = &.{},
  45    extra_features: []const Feature = &.{},
  46    omit_cpus: []const []const u8 = &.{},
  47    branch_quota: ?usize = null,
  48};
  49
  50const targets = [_]ArchTarget{
  51    .{
  52        .zig_name = "aarch64",
  53        .llvm = .{
  54            .name = "AArch64",
  55            .td_name = "AArch64",
  56        },
  57        .branch_quota = 2000,
  58        .feature_overrides = &.{
  59            .{
  60                .llvm_name = "all",
  61                .omit = true,
  62            },
  63            .{
  64                .llvm_name = "CONTEXTIDREL2",
  65                .zig_name = "contextidr_el2",
  66                .desc = "Enable RW operand Context ID Register (EL2)",
  67            },
  68            .{
  69                .llvm_name = "neoversee1",
  70                .flatten = true,
  71            },
  72            .{
  73                .llvm_name = "neoversen1",
  74                .flatten = true,
  75            },
  76            .{
  77                .llvm_name = "neoversen2",
  78                .flatten = true,
  79            },
  80            .{
  81                .llvm_name = "neoversen3",
  82                .flatten = true,
  83            },
  84            .{
  85                .llvm_name = "neoversev1",
  86                .flatten = true,
  87            },
  88            .{
  89                .llvm_name = "neoversev2",
  90                .flatten = true,
  91            },
  92            .{
  93                .llvm_name = "neoversev3",
  94                .flatten = true,
  95            },
  96            .{
  97                .llvm_name = "neoversev3AE",
  98                .flatten = true,
  99            },
 100            .{
 101                .llvm_name = "neoverse512tvb",
 102                .flatten = true,
 103            },
 104            .{
 105                .llvm_name = "oryon-1",
 106                .flatten = true,
 107            },
 108            .{
 109                .llvm_name = "exynosm3",
 110                .flatten = true,
 111            },
 112            .{
 113                .llvm_name = "exynosm4",
 114                .flatten = true,
 115            },
 116            .{
 117                .llvm_name = "a35",
 118                .flatten = true,
 119            },
 120            .{
 121                .llvm_name = "a53",
 122                .flatten = true,
 123            },
 124            .{
 125                .llvm_name = "a55",
 126                .flatten = true,
 127            },
 128            .{
 129                .llvm_name = "a57",
 130                .flatten = true,
 131            },
 132            .{
 133                .llvm_name = "a510",
 134                .flatten = true,
 135            },
 136            .{
 137                .llvm_name = "a520",
 138                .flatten = true,
 139            },
 140            .{
 141                .llvm_name = "a520ae",
 142                .flatten = true,
 143            },
 144            .{
 145                .llvm_name = "a64fx",
 146                .flatten = true,
 147            },
 148            .{
 149                .llvm_name = "a65",
 150                .flatten = true,
 151            },
 152            .{
 153                .llvm_name = "a72",
 154                .flatten = true,
 155            },
 156            .{
 157                .llvm_name = "a73",
 158                .flatten = true,
 159            },
 160            .{
 161                .llvm_name = "a75",
 162                .flatten = true,
 163            },
 164            .{
 165                .llvm_name = "a76",
 166                .flatten = true,
 167            },
 168            .{
 169                .llvm_name = "a77",
 170                .flatten = true,
 171            },
 172            .{
 173                .llvm_name = "a78",
 174                .flatten = true,
 175            },
 176            .{
 177                .llvm_name = "a78ae",
 178                .flatten = true,
 179            },
 180            .{
 181                .llvm_name = "a78c",
 182                .flatten = true,
 183            },
 184            .{
 185                .llvm_name = "a710",
 186                .flatten = true,
 187            },
 188            .{
 189                .llvm_name = "a715",
 190                .flatten = true,
 191            },
 192            .{
 193                .llvm_name = "a720",
 194                .flatten = true,
 195            },
 196            .{
 197                .llvm_name = "a720ae",
 198                .flatten = true,
 199            },
 200            .{
 201                .llvm_name = "ampere1a",
 202                .flatten = true,
 203            },
 204            .{
 205                .llvm_name = "apple-a7",
 206                .flatten = true,
 207            },
 208            .{
 209                .llvm_name = "apple-a10",
 210                .flatten = true,
 211            },
 212            .{
 213                .llvm_name = "apple-a11",
 214                .flatten = true,
 215            },
 216            .{
 217                .llvm_name = "apple-a12",
 218                .flatten = true,
 219            },
 220            .{
 221                .llvm_name = "apple-a13",
 222                .flatten = true,
 223            },
 224            .{
 225                .llvm_name = "apple-a14",
 226                .flatten = true,
 227            },
 228            .{
 229                .llvm_name = "apple-a15",
 230                .flatten = true,
 231            },
 232            .{
 233                .llvm_name = "apple-a16",
 234                .flatten = true,
 235            },
 236            .{
 237                .llvm_name = "apple-a17",
 238                .flatten = true,
 239            },
 240            .{
 241                .llvm_name = "apple-a7-sysreg",
 242                .flatten = true,
 243            },
 244            .{
 245                .llvm_name = "apple-m4",
 246                .flatten = true,
 247            },
 248            .{
 249                .llvm_name = "carmel",
 250                .flatten = true,
 251            },
 252            .{
 253                .llvm_name = "cortex-a725",
 254                .flatten = true,
 255            },
 256            .{
 257                .llvm_name = "cortex-a78",
 258                .flatten = true,
 259            },
 260            .{
 261                .llvm_name = "cortex-r82",
 262                .flatten = true,
 263            },
 264            .{
 265                .llvm_name = "cortex-r82ae",
 266                .flatten = true,
 267            },
 268            .{
 269                .llvm_name = "cortex-x1",
 270                .flatten = true,
 271            },
 272            .{
 273                .llvm_name = "cortex-x2",
 274                .flatten = true,
 275            },
 276            .{
 277                .llvm_name = "cortex-x3",
 278                .flatten = true,
 279            },
 280            .{
 281                .llvm_name = "cortex-x4",
 282                .flatten = true,
 283            },
 284            .{
 285                .llvm_name = "cortex-x925",
 286                .flatten = true,
 287            },
 288            .{
 289                .llvm_name = "falkor",
 290                .flatten = true,
 291            },
 292            .{
 293                .llvm_name = "kryo",
 294                .flatten = true,
 295            },
 296            .{
 297                .llvm_name = "saphira",
 298                .flatten = true,
 299            },
 300            .{
 301                .llvm_name = "thunderx",
 302                .flatten = true,
 303            },
 304            .{
 305                .llvm_name = "thunderx2t99",
 306                .flatten = true,
 307            },
 308            .{
 309                .llvm_name = "thunderx3t110",
 310                .flatten = true,
 311            },
 312            .{
 313                .llvm_name = "thunderxt81",
 314                .flatten = true,
 315            },
 316            .{
 317                .llvm_name = "thunderxt83",
 318                .flatten = true,
 319            },
 320            .{
 321                .llvm_name = "thunderxt88",
 322                .flatten = true,
 323            },
 324            .{
 325                .llvm_name = "tsv110",
 326                .flatten = true,
 327            },
 328            .{
 329                .llvm_name = "ampere1",
 330                .flatten = true,
 331            },
 332            .{
 333                .llvm_name = "ampere1b",
 334                .flatten = true,
 335            },
 336        },
 337        .extra_cpus = &.{
 338            .{
 339                .llvm_name = null,
 340                .zig_name = "exynos_m1",
 341                .features = &.{
 342                    "crc",
 343                    "crypto",
 344                    "exynos_cheap_as_move",
 345                    "force_32bit_jump_tables",
 346                    "fuse_aes",
 347                    "perfmon",
 348                    "slow_misaligned_128store",
 349                    "slow_paired_128",
 350                    "use_postra_scheduler",
 351                    "use_reciprocal_square_root",
 352                    "v8a",
 353                },
 354            },
 355            .{
 356                .llvm_name = null,
 357                .zig_name = "exynos_m2",
 358                .features = &.{
 359                    "crc",
 360                    "crypto",
 361                    "exynos_cheap_as_move",
 362                    "force_32bit_jump_tables",
 363                    "fuse_aes",
 364                    "perfmon",
 365                    "slow_misaligned_128store",
 366                    "slow_paired_128",
 367                    "use_postra_scheduler",
 368                    "v8a",
 369                },
 370            },
 371            .{
 372                .llvm_name = null,
 373                .zig_name = "xgene1",
 374                .features = &.{
 375                    "perfmon",
 376                    "v8a",
 377                },
 378            },
 379            .{
 380                .llvm_name = null,
 381                .zig_name = "emag",
 382                .features = &.{
 383                    "crc",
 384                    "crypto",
 385                    "perfmon",
 386                    "v8a",
 387                },
 388            },
 389        },
 390        .omit_cpus = &.{
 391            // Who thought this alias was a good idea? Upgrade your compiler and suddenly your
 392            // programs SIGILL because this changed meaning. Brilliant.
 393            "apple-latest",
 394        },
 395    },
 396    .{
 397        .zig_name = "alpha",
 398        .llvm = null,
 399        .extra_features = &.{
 400            .{
 401                .zig_name = "bwx",
 402                .desc = "Enable byte/word extensions",
 403                .deps = &.{},
 404            },
 405            .{
 406                .zig_name = "cix",
 407                .desc = "Enable counting extensions",
 408                .deps = &.{},
 409            },
 410            .{
 411                .zig_name = "fix",
 412                .desc = "Enable floating point move and square root extensions",
 413                .deps = &.{},
 414            },
 415            .{
 416                .zig_name = "max",
 417                .desc = "Enable motion video extensions",
 418                .deps = &.{},
 419            },
 420        },
 421        .extra_cpus = &.{
 422            .{
 423                .llvm_name = null,
 424                .zig_name = "ev4",
 425                .features = &.{},
 426            },
 427            .{
 428                .llvm_name = null,
 429                .zig_name = "ev45",
 430                .features = &.{},
 431            },
 432            .{
 433                .llvm_name = null,
 434                .zig_name = "ev5",
 435                .features = &.{},
 436            },
 437            .{
 438                .llvm_name = null,
 439                .zig_name = "ev56",
 440                .features = &.{
 441                    "bwx",
 442                },
 443            },
 444            .{
 445                .llvm_name = null,
 446                .zig_name = "pca56",
 447                .features = &.{
 448                    "bwx",
 449                    "max",
 450                },
 451            },
 452            .{
 453                .llvm_name = null,
 454                .zig_name = "ev6",
 455                .features = &.{
 456                    "bwx",
 457                    "fix",
 458                    "max",
 459                },
 460            },
 461            .{
 462                .llvm_name = null,
 463                .zig_name = "ev67",
 464                .features = &.{
 465                    "bwx",
 466                    "cix",
 467                    "fix",
 468                    "max",
 469                },
 470            },
 471        },
 472    },
 473    .{
 474        .zig_name = "amdgcn",
 475        .llvm = .{
 476            .name = "AMDGPU",
 477            .td_name = "AMDGPU",
 478        },
 479        .branch_quota = 2000,
 480        .feature_overrides = &.{
 481            .{
 482                .llvm_name = "DumpCode",
 483                .omit = true,
 484            },
 485            .{
 486                .llvm_name = "dumpcode",
 487                .omit = true,
 488            },
 489            .{
 490                .llvm_name = "enable-ds128",
 491                .zig_name = "ds128",
 492            },
 493            .{
 494                .llvm_name = "enable-flat-scratch",
 495                .zig_name = "flat_scratch",
 496            },
 497            .{
 498                .llvm_name = "enable-prt-strict-null",
 499                .zig_name = "prt_strict_null",
 500            },
 501        },
 502    },
 503    .{
 504        .zig_name = "arc",
 505        .llvm = .{
 506            .name = "ARC",
 507            .td_name = "ARC",
 508        },
 509    },
 510    .{
 511        .zig_name = "arm",
 512        .llvm = .{
 513            .name = "ARM",
 514            .td_name = "ARM",
 515        },
 516        .branch_quota = 10000,
 517        .feature_overrides = &.{
 518            .{
 519                .llvm_name = "exynos",
 520                .flatten = true,
 521            },
 522            .{
 523                .llvm_name = "cortex-a78",
 524                .flatten = true,
 525            },
 526            .{
 527                .llvm_name = "cortex-a78ae",
 528                .flatten = true,
 529            },
 530            .{
 531                .llvm_name = "cortex-a710",
 532                .flatten = true,
 533            },
 534            .{
 535                .llvm_name = "cortex-m4",
 536                .omit_deps = &.{"vfp4d16sp"},
 537            },
 538            .{
 539                .llvm_name = "cortex-m7",
 540                .omit_deps = &.{"fp_armv8d16"},
 541            },
 542            .{
 543                .llvm_name = "cortex-m33",
 544                .omit_deps = &.{ "fp_armv8d16sp", "dsp" },
 545            },
 546            .{
 547                .llvm_name = "cortex-m35p",
 548                .omit_deps = &.{ "fp_armv8d16sp", "dsp" },
 549            },
 550            .{
 551                .llvm_name = "cortex-m55",
 552                .omit_deps = &.{ "mve_fp", "fp_armv8d16" },
 553            },
 554            .{
 555                .llvm_name = "cortex-m85",
 556                .omit_deps = &.{ "mve_fp", "pacbti", "fp_armv8d16" },
 557            },
 558            .{
 559                .llvm_name = "cortex-x1c",
 560                .flatten = true,
 561            },
 562            .{
 563                .llvm_name = "r4",
 564                .flatten = true,
 565            },
 566            .{
 567                .llvm_name = "r52plus",
 568                .flatten = true,
 569            },
 570            .{
 571                .llvm_name = "r5",
 572                .flatten = true,
 573            },
 574            .{
 575                .llvm_name = "r52",
 576                .flatten = true,
 577            },
 578            .{
 579                .llvm_name = "r7",
 580                .flatten = true,
 581            },
 582            .{
 583                .llvm_name = "m3",
 584                .flatten = true,
 585            },
 586            .{
 587                .llvm_name = "m7",
 588                .flatten = true,
 589            },
 590            .{
 591                .llvm_name = "krait",
 592                .flatten = true,
 593            },
 594            .{
 595                .llvm_name = "kryo",
 596                .flatten = true,
 597            },
 598            .{
 599                .llvm_name = "swift",
 600                .flatten = true,
 601            },
 602            .{
 603                .llvm_name = "cortex-x1",
 604                .flatten = true,
 605            },
 606            .{
 607                .llvm_name = "neoverse-v1",
 608                .flatten = true,
 609            },
 610            .{
 611                .llvm_name = "a5",
 612                .flatten = true,
 613            },
 614            .{
 615                .llvm_name = "a7",
 616                .flatten = true,
 617            },
 618            .{
 619                .llvm_name = "a8",
 620                .flatten = true,
 621            },
 622            .{
 623                .llvm_name = "a9",
 624                .flatten = true,
 625            },
 626            .{
 627                .llvm_name = "a12",
 628                .flatten = true,
 629            },
 630            .{
 631                .llvm_name = "a15",
 632                .flatten = true,
 633            },
 634            .{
 635                .llvm_name = "a17",
 636                .flatten = true,
 637            },
 638            .{
 639                .llvm_name = "a32",
 640                .flatten = true,
 641            },
 642            .{
 643                .llvm_name = "a35",
 644                .flatten = true,
 645            },
 646            .{
 647                .llvm_name = "a53",
 648                .flatten = true,
 649            },
 650            .{
 651                .llvm_name = "a55",
 652                .flatten = true,
 653            },
 654            .{
 655                .llvm_name = "a57",
 656                .flatten = true,
 657            },
 658            .{
 659                .llvm_name = "a72",
 660                .flatten = true,
 661            },
 662            .{
 663                .llvm_name = "a73",
 664                .flatten = true,
 665            },
 666            .{
 667                .llvm_name = "a75",
 668                .flatten = true,
 669            },
 670            .{
 671                .llvm_name = "a76",
 672                .flatten = true,
 673            },
 674            .{
 675                .llvm_name = "a77",
 676                .flatten = true,
 677            },
 678            .{
 679                .llvm_name = "a78c",
 680                .flatten = true,
 681            },
 682            .{
 683                .llvm_name = "armv2",
 684                .zig_name = "v2",
 685                .extra_deps = &.{"strict_align"},
 686            },
 687            .{
 688                .llvm_name = "armv2a",
 689                .zig_name = "v2a",
 690                .extra_deps = &.{"strict_align"},
 691            },
 692            .{
 693                .llvm_name = "armv3",
 694                .zig_name = "v3",
 695                .extra_deps = &.{"strict_align"},
 696            },
 697            .{
 698                .llvm_name = "armv3m",
 699                .zig_name = "v3m",
 700                .extra_deps = &.{"strict_align"},
 701            },
 702            .{
 703                .llvm_name = "armv4",
 704                .zig_name = "v4",
 705                .extra_deps = &.{"strict_align"},
 706            },
 707            .{
 708                .llvm_name = "armv4t",
 709                .zig_name = "v4t",
 710                .extra_deps = &.{"strict_align"},
 711            },
 712            .{
 713                .llvm_name = "armv5t",
 714                .zig_name = "v5t",
 715                .extra_deps = &.{"strict_align"},
 716            },
 717            .{
 718                .llvm_name = "armv5te",
 719                .zig_name = "v5te",
 720                .extra_deps = &.{"strict_align"},
 721            },
 722            .{
 723                .llvm_name = "armv5tej",
 724                .zig_name = "v5tej",
 725                .extra_deps = &.{"strict_align"},
 726            },
 727            .{
 728                .llvm_name = "armv6",
 729                .zig_name = "v6",
 730            },
 731            .{
 732                .llvm_name = "armv6-m",
 733                .zig_name = "v6m",
 734            },
 735            .{
 736                .llvm_name = "armv6j",
 737                .zig_name = "v6j",
 738            },
 739            .{
 740                .llvm_name = "armv6k",
 741                .zig_name = "v6k",
 742            },
 743            .{
 744                .llvm_name = "armv6kz",
 745                .zig_name = "v6kz",
 746            },
 747            .{
 748                .llvm_name = "armv6s-m",
 749                .zig_name = "v6sm",
 750            },
 751            .{
 752                .llvm_name = "armv6t2",
 753                .zig_name = "v6t2",
 754            },
 755            .{
 756                .llvm_name = "armv7-a",
 757                .zig_name = "v7a",
 758            },
 759            .{
 760                .llvm_name = "armv7-m",
 761                .zig_name = "v7m",
 762            },
 763            .{
 764                .llvm_name = "armv7-r",
 765                .zig_name = "v7r",
 766            },
 767            .{
 768                .llvm_name = "armv7e-m",
 769                .zig_name = "v7em",
 770            },
 771            .{
 772                .llvm_name = "armv7k",
 773                .omit = true,
 774            },
 775            .{
 776                .llvm_name = "armv7s",
 777                .omit = true,
 778            },
 779            .{
 780                .llvm_name = "armv7ve",
 781                .zig_name = "v7ve",
 782            },
 783            .{
 784                .llvm_name = "armv8.1-a",
 785                .zig_name = "v8_1a",
 786            },
 787            .{
 788                .llvm_name = "armv8.1-m.main",
 789                .zig_name = "v8_1m_main",
 790            },
 791            .{
 792                .llvm_name = "armv8.2-a",
 793                .zig_name = "v8_2a",
 794            },
 795            .{
 796                .llvm_name = "armv8.3-a",
 797                .zig_name = "v8_3a",
 798            },
 799            .{
 800                .llvm_name = "armv8.4-a",
 801                .zig_name = "v8_4a",
 802            },
 803            .{
 804                .llvm_name = "armv8.5-a",
 805                .zig_name = "v8_5a",
 806            },
 807            .{
 808                .llvm_name = "armv8.6-a",
 809                .zig_name = "v8_6a",
 810            },
 811            .{
 812                .llvm_name = "armv8.7-a",
 813                .zig_name = "v8_7a",
 814            },
 815            .{
 816                .llvm_name = "armv8.8-a",
 817                .zig_name = "v8_8a",
 818            },
 819            .{
 820                .llvm_name = "armv8.9-a",
 821                .zig_name = "v8_9a",
 822            },
 823            .{
 824                .llvm_name = "armv8-a",
 825                .zig_name = "v8a",
 826            },
 827            .{
 828                .llvm_name = "armv8-m.base",
 829                .zig_name = "v8m",
 830            },
 831            .{
 832                .llvm_name = "armv8-m.main",
 833                .zig_name = "v8m_main",
 834            },
 835            .{
 836                .llvm_name = "armv8-r",
 837                .zig_name = "v8r",
 838            },
 839            .{
 840                .llvm_name = "armv9.1-a",
 841                .zig_name = "v9_1a",
 842            },
 843            .{
 844                .llvm_name = "armv9.2-a",
 845                .zig_name = "v9_2a",
 846            },
 847            .{
 848                .llvm_name = "armv9.3-a",
 849                .zig_name = "v9_3a",
 850            },
 851            .{
 852                .llvm_name = "armv9.4-a",
 853                .zig_name = "v9_4a",
 854            },
 855            .{
 856                .llvm_name = "armv9.5-a",
 857                .zig_name = "v9_5a",
 858            },
 859            .{
 860                .llvm_name = "armv9.6-a",
 861                .zig_name = "v9_6a",
 862            },
 863            .{
 864                .llvm_name = "armv9-a",
 865                .zig_name = "v9a",
 866            },
 867            .{
 868                .llvm_name = "v4t",
 869                .zig_name = "has_v4t",
 870            },
 871            .{
 872                .llvm_name = "v5t",
 873                .zig_name = "has_v5t",
 874            },
 875            .{
 876                .llvm_name = "v5te",
 877                .zig_name = "has_v5te",
 878            },
 879            .{
 880                .llvm_name = "v6",
 881                .zig_name = "has_v6",
 882            },
 883            .{
 884                .llvm_name = "v6k",
 885                .zig_name = "has_v6k",
 886            },
 887            .{
 888                .llvm_name = "v6m",
 889                .zig_name = "has_v6m",
 890            },
 891            .{
 892                .llvm_name = "v6t2",
 893                .zig_name = "has_v6t2",
 894            },
 895            .{
 896                .llvm_name = "v7",
 897                .zig_name = "has_v7",
 898            },
 899            .{
 900                .llvm_name = "v7clrex",
 901                .zig_name = "has_v7clrex",
 902            },
 903            .{
 904                .llvm_name = "v8",
 905                .zig_name = "has_v8",
 906            },
 907            .{
 908                .llvm_name = "v8m",
 909                .zig_name = "has_v8m",
 910            },
 911            .{
 912                .llvm_name = "v8m.main",
 913                .zig_name = "has_v8m_main",
 914            },
 915            .{
 916                .llvm_name = "v8.1a",
 917                .zig_name = "has_v8_1a",
 918            },
 919            .{
 920                .llvm_name = "v8.1m.main",
 921                .zig_name = "has_v8_1m_main",
 922            },
 923            .{
 924                .llvm_name = "v8.2a",
 925                .zig_name = "has_v8_2a",
 926            },
 927            .{
 928                .llvm_name = "v8.3a",
 929                .zig_name = "has_v8_3a",
 930            },
 931            .{
 932                .llvm_name = "v8.4a",
 933                .zig_name = "has_v8_4a",
 934            },
 935            .{
 936                .llvm_name = "v8.5a",
 937                .zig_name = "has_v8_5a",
 938            },
 939            .{
 940                .llvm_name = "v8.6a",
 941                .zig_name = "has_v8_6a",
 942            },
 943            .{
 944                .llvm_name = "v8.7a",
 945                .zig_name = "has_v8_7a",
 946            },
 947            .{
 948                .llvm_name = "v8.8a",
 949                .zig_name = "has_v8_8a",
 950            },
 951            .{
 952                .llvm_name = "v8.9a",
 953                .zig_name = "has_v8_9a",
 954            },
 955            .{
 956                .llvm_name = "v9a",
 957                .zig_name = "has_v9a",
 958            },
 959            .{
 960                .llvm_name = "v9.1a",
 961                .zig_name = "has_v9_1a",
 962            },
 963            .{
 964                .llvm_name = "v9.2a",
 965                .zig_name = "has_v9_2a",
 966            },
 967            .{
 968                .llvm_name = "v9.3a",
 969                .zig_name = "has_v9_3a",
 970            },
 971            .{
 972                .llvm_name = "v9.4a",
 973                .zig_name = "has_v9_4a",
 974            },
 975            .{
 976                .llvm_name = "v9.5a",
 977                .zig_name = "has_v9_5a",
 978            },
 979            .{
 980                .llvm_name = "v9.6a",
 981                .zig_name = "has_v9_6a",
 982            },
 983        },
 984        .extra_cpus = &.{
 985            .{
 986                .llvm_name = "generic",
 987                .zig_name = "baseline",
 988                .features = &.{"v7a"},
 989            },
 990            .{
 991                .llvm_name = null,
 992                .zig_name = "exynos_m1",
 993                .features = &.{ "v8a", "exynos" },
 994            },
 995            .{
 996                .llvm_name = null,
 997                .zig_name = "exynos_m2",
 998                .features = &.{ "v8a", "exynos" },
 999            },
1000        },
1001        .extra_features = &.{
1002            // LLVM removed support for v2 and v3 but zig wants to support targeting old hardware
1003            .{
1004                .zig_name = "v2",
1005                .desc = "ARMv2 architecture",
1006                .deps = &.{"strict_align"},
1007            },
1008            .{
1009                .zig_name = "v2a",
1010                .desc = "ARMv2a architecture",
1011                .deps = &.{"strict_align"},
1012            },
1013            .{
1014                .zig_name = "v3",
1015                .desc = "ARMv3 architecture",
1016                .deps = &.{"strict_align"},
1017            },
1018            .{
1019                .zig_name = "v3m",
1020                .desc = "ARMv3m architecture",
1021                .deps = &.{"strict_align"},
1022            },
1023        },
1024    },
1025    .{
1026        .zig_name = "avr",
1027        .llvm = .{
1028            .name = "AVR",
1029            .td_name = "AVR",
1030        },
1031    },
1032    .{
1033        .zig_name = "bpf",
1034        .llvm = .{
1035            .name = "BPF",
1036            .td_name = "BPF",
1037        },
1038    },
1039    .{
1040        .zig_name = "csky",
1041        .llvm = .{
1042            .name = "CSKY",
1043            .td_name = "CSKY",
1044        },
1045    },
1046    .{
1047        .zig_name = "hexagon",
1048        .llvm = .{
1049            .name = "Hexagon",
1050            .td_name = "Hexagon",
1051        },
1052    },
1053    .{
1054        .zig_name = "hppa",
1055        .llvm = null,
1056        .extra_features = &.{
1057            .{
1058                .zig_name = "64bit",
1059                .desc = "Enable 64-bit PA-RISC 2.0",
1060                .deps = &.{"v2_0"},
1061            },
1062            .{
1063                .zig_name = "max_1",
1064                .desc = "Enable MAX-1 multimedia acceleration extensions",
1065                .deps = &.{},
1066            },
1067            .{
1068                .zig_name = "max_2",
1069                .desc = "Enable MAX-2 multimedia acceleration extensions",
1070                .deps = &.{"max_1"},
1071            },
1072            .{
1073                .zig_name = "v1_1",
1074                .desc = "Enable ISA v1.1",
1075                .deps = &.{},
1076            },
1077            .{
1078                .zig_name = "v2_0",
1079                .desc = "Enable ISA v2.0",
1080                .deps = &.{ "max_2", "v1_1" },
1081            },
1082        },
1083        .extra_cpus = &.{
1084            .{
1085                .llvm_name = null,
1086                .zig_name = "ts_1",
1087                .features = &.{},
1088            },
1089            .{
1090                .llvm_name = null,
1091                .zig_name = "ns_1",
1092                .features = &.{},
1093            },
1094            .{
1095                .llvm_name = null,
1096                .zig_name = "ns_2",
1097                .features = &.{},
1098            },
1099            .{
1100                .llvm_name = null,
1101                .zig_name = "pcx",
1102                .features = &.{},
1103            },
1104            .{
1105                .llvm_name = null,
1106                .zig_name = "pa_7000",
1107                .features = &.{
1108                    "v1_1",
1109                },
1110            },
1111            .{
1112                .llvm_name = null,
1113                .zig_name = "pa_7100",
1114                .features = &.{
1115                    "v1_1",
1116                },
1117            },
1118            .{
1119                .llvm_name = null,
1120                .zig_name = "pa_7150",
1121                .features = &.{
1122                    "v1_1",
1123                },
1124            },
1125            .{
1126                .llvm_name = null,
1127                .zig_name = "pa_7100lc",
1128                .features = &.{
1129                    "max_1",
1130                    "v1_1",
1131                },
1132            },
1133            .{
1134                .llvm_name = null,
1135                .zig_name = "pa_7200",
1136                .features = &.{
1137                    "v1_1",
1138                },
1139            },
1140            .{
1141                .llvm_name = null,
1142                .zig_name = "pa_7300lc",
1143                .features = &.{
1144                    "max_1",
1145                    "v1_1",
1146                },
1147            },
1148            .{
1149                .llvm_name = null,
1150                .zig_name = "pa_8000",
1151                .features = &.{
1152                    "64bit",
1153                },
1154            },
1155            .{
1156                .llvm_name = null,
1157                .zig_name = "pa_8200",
1158                .features = &.{
1159                    "64bit",
1160                },
1161            },
1162            .{
1163                .llvm_name = null,
1164                .zig_name = "pa_8500",
1165                .features = &.{
1166                    "64bit",
1167                },
1168            },
1169            .{
1170                .llvm_name = null,
1171                .zig_name = "pa_8600",
1172                .features = &.{
1173                    "64bit",
1174                },
1175            },
1176            .{
1177                .llvm_name = null,
1178                .zig_name = "pa_8700",
1179                .features = &.{
1180                    "64bit",
1181                },
1182            },
1183            .{
1184                .llvm_name = null,
1185                .zig_name = "pa_8800",
1186                .features = &.{
1187                    "64bit",
1188                },
1189            },
1190            .{
1191                .llvm_name = null,
1192                .zig_name = "pa_8900",
1193                .features = &.{
1194                    "64bit",
1195                },
1196            },
1197        },
1198    },
1199    .{
1200        .zig_name = "kvx",
1201        .llvm = null,
1202        .extra_features = &.{
1203            .{
1204                .zig_name = "v3_1",
1205                .desc = "Enable ISA v3.1",
1206                .deps = &.{},
1207            },
1208            .{
1209                .zig_name = "v3_2",
1210                .desc = "Enable ISA v3.2",
1211                .deps = &.{"v3_1"},
1212            },
1213            .{
1214                .zig_name = "v4_1",
1215                .desc = "Enable ISA v4.1",
1216                .deps = &.{"v3_2"},
1217            },
1218        },
1219        .extra_cpus = &.{
1220            .{
1221                .llvm_name = null,
1222                .zig_name = "coolidge_v1",
1223                .features = &.{
1224                    "v3_1",
1225                },
1226            },
1227            .{
1228                .llvm_name = null,
1229                .zig_name = "coolidge_v2",
1230                .features = &.{
1231                    "v3_2",
1232                },
1233            },
1234        },
1235    },
1236    .{
1237        .zig_name = "lanai",
1238        .llvm = .{
1239            .name = "Lanai",
1240            .td_name = "Lanai",
1241        },
1242    },
1243    .{
1244        .zig_name = "loongarch",
1245        .llvm = .{
1246            .name = "LoongArch",
1247            .td_name = "LoongArch",
1248        },
1249        .extra_cpus = &.{
1250            .{
1251                .llvm_name = null,
1252                .zig_name = "la64v1_0",
1253                .features = &.{
1254                    "64bit",
1255                    "lsx",
1256                    "ual",
1257                },
1258            },
1259            .{
1260                .llvm_name = null,
1261                .zig_name = "la64v1_1",
1262                .features = &.{
1263                    "64bit",
1264                    "div32",
1265                    "frecipe",
1266                    "lam_bh",
1267                    "lamcas",
1268                    "ld_seq_sa",
1269                    "lsx",
1270                    "scq",
1271                    "ual",
1272                },
1273            },
1274        },
1275        .omit_cpus = &.{
1276            "generic",
1277            "loongarch64",
1278        },
1279    },
1280    .{
1281        .zig_name = "m68k",
1282        .llvm = .{
1283            .name = "M68k",
1284            .td_name = "M68k",
1285        },
1286    },
1287    .{
1288        .zig_name = "msp430",
1289        .llvm = .{
1290            .name = "MSP430",
1291            .td_name = "MSP430",
1292        },
1293    },
1294    .{
1295        .zig_name = "mips",
1296        .llvm = .{
1297            .name = "Mips",
1298            .td_name = "Mips",
1299        },
1300    },
1301    .{
1302        .zig_name = "nvptx",
1303        .llvm = .{
1304            .name = "NVPTX",
1305            .td_name = "NVPTX",
1306        },
1307    },
1308    .{
1309        .zig_name = "powerpc",
1310        .llvm = .{
1311            .name = "PowerPC",
1312            .td_name = "PPC",
1313        },
1314        .feature_overrides = &.{
1315            .{
1316                .llvm_name = "aix",
1317                .omit = true,
1318            },
1319            .{
1320                .llvm_name = "aix-shared-lib-tls-model-opt",
1321                .omit = true,
1322            },
1323            .{
1324                .llvm_name = "aix-small-local-dynamic-tls",
1325                .omit = true,
1326            },
1327            .{
1328                .llvm_name = "aix-small-local-exec-tls",
1329                .omit = true,
1330            },
1331            .{
1332                .llvm_name = "modern-aix-as",
1333                .omit = true,
1334            },
1335        },
1336        .omit_cpus = &.{
1337            "ppc32",
1338        },
1339    },
1340    .{
1341        .zig_name = "propeller",
1342        .llvm = null,
1343        .extra_features = &.{
1344            .{
1345                .zig_name = "p2",
1346                .desc = "Enable Propeller 2",
1347                .deps = &.{},
1348            },
1349        },
1350        .extra_cpus = &.{
1351            .{
1352                .llvm_name = null,
1353                .zig_name = "p1",
1354                .features = &.{},
1355            },
1356            .{
1357                .llvm_name = null,
1358                .zig_name = "p2",
1359                .features = &.{"p2"},
1360            },
1361        },
1362    },
1363    .{
1364        .zig_name = "spirv",
1365        .llvm = .{
1366            .name = "SPIRV",
1367            .td_name = "SPIRV",
1368        },
1369        .branch_quota = 2000,
1370        .extra_features = &.{
1371            .{
1372                .zig_name = "v1_0",
1373                .desc = "Enable version 1.0",
1374                .deps = &.{},
1375            },
1376            .{
1377                .zig_name = "v1_1",
1378                .desc = "Enable version 1.1",
1379                .deps = &.{"v1_0"},
1380            },
1381            .{
1382                .zig_name = "v1_2",
1383                .desc = "Enable version 1.2",
1384                .deps = &.{"v1_1"},
1385            },
1386            .{
1387                .zig_name = "v1_3",
1388                .desc = "Enable version 1.3",
1389                .deps = &.{"v1_2"},
1390            },
1391            .{
1392                .zig_name = "v1_4",
1393                .desc = "Enable version 1.4",
1394                .deps = &.{"v1_3"},
1395            },
1396            .{
1397                .zig_name = "v1_5",
1398                .desc = "Enable version 1.5",
1399                .deps = &.{"v1_4"},
1400            },
1401            .{
1402                .zig_name = "v1_6",
1403                .desc = "Enable version 1.6",
1404                .deps = &.{"v1_5"},
1405            },
1406            .{
1407                .zig_name = "int64",
1408                .desc = "Enable Int64 capability",
1409                .deps = &.{"v1_0"},
1410            },
1411            .{
1412                .zig_name = "float16",
1413                .desc = "Enable Float16 capability",
1414                .deps = &.{"v1_0"},
1415            },
1416            .{
1417                .zig_name = "float64",
1418                .desc = "Enable Float64 capability",
1419                .deps = &.{"v1_0"},
1420            },
1421            .{
1422                .zig_name = "storage_push_constant16",
1423                .desc = "Enable SPV_KHR_16bit_storage extension and the StoragePushConstant16 capability",
1424                .deps = &.{"v1_3"},
1425            },
1426            .{
1427                .zig_name = "arbitrary_precision_integers",
1428                .desc = "Enable SPV_INTEL_arbitrary_precision_integers extension and the ArbitraryPrecisionIntegersINTEL capability",
1429                .deps = &.{"v1_5"},
1430            },
1431            .{
1432                .zig_name = "generic_pointer",
1433                .desc = "Enable GenericPointer capability",
1434                .deps = &.{"v1_0"},
1435            },
1436            .{
1437                .zig_name = "vector16",
1438                .desc = "Enable Vector16 capability",
1439                .deps = &.{"v1_0"},
1440            },
1441            .{
1442                .zig_name = "variable_pointers",
1443                .desc = "Enable SPV_KHR_physical_storage_buffer extension and the PhysicalStorageBufferAddresses capability",
1444                .deps = &.{"v1_0"},
1445            },
1446        },
1447        .extra_cpus = &.{
1448            .{
1449                .llvm_name = null,
1450                .zig_name = "vulkan_v1_2",
1451                .features = &.{"v1_5"},
1452            },
1453            .{
1454                .llvm_name = null,
1455                .zig_name = "opencl_v2",
1456                .features = &.{"v1_2"},
1457            },
1458        },
1459    },
1460    .{
1461        .zig_name = "riscv",
1462        .llvm = .{
1463            .name = "RISCV",
1464            .td_name = "RISCV",
1465        },
1466        .branch_quota = 2000,
1467        .feature_overrides = &.{
1468            .{
1469                .llvm_name = "sifive7",
1470                .flatten = true,
1471            },
1472        },
1473        .extra_cpus = &.{
1474            .{
1475                .llvm_name = null,
1476                .zig_name = "baseline_rv32",
1477                .features = &.{ "32bit", "a", "c", "d", "f", "i", "m" },
1478            },
1479            .{
1480                .llvm_name = null,
1481                .zig_name = "baseline_rv64",
1482                .features = &.{ "64bit", "a", "c", "d", "f", "i", "m" },
1483            },
1484        },
1485    },
1486    .{
1487        .zig_name = "sparc",
1488        .llvm = .{
1489            .name = "Sparc",
1490            .td_name = "Sparc",
1491        },
1492    },
1493    .{
1494        .zig_name = "s390x",
1495        .llvm = .{
1496            .name = "SystemZ",
1497            .td_name = "SystemZ",
1498        },
1499    },
1500    .{
1501        .zig_name = "ve",
1502        .llvm = .{
1503            .name = "VE",
1504            .td_name = "VE",
1505        },
1506    },
1507    .{
1508        .zig_name = "wasm",
1509        .llvm = .{
1510            .name = "WebAssembly",
1511            .td_name = "WebAssembly",
1512        },
1513        // For whatever reason, LLVM's WebAssembly backend sets these implied features in code
1514        // rather than making them proper dependencies, so fix that here...
1515        .feature_overrides = &.{
1516            .{
1517                .llvm_name = "bulk-memory",
1518                .extra_deps = &.{"bulk_memory_opt"},
1519            },
1520            .{
1521                .llvm_name = "reference-types",
1522                .extra_deps = &.{"call_indirect_overlong"},
1523            },
1524        },
1525        .extra_features = &.{
1526            .{
1527                .zig_name = "nontrapping_bulk_memory_len0",
1528                .desc = "Bulk memory operations with a zero length do not trap",
1529                .deps = &.{"bulk_memory_opt"},
1530            },
1531        },
1532    },
1533    .{
1534        .zig_name = "x86",
1535        .llvm = .{
1536            .name = "X86",
1537            .td_name = "X86",
1538        },
1539        .feature_overrides = &.{
1540            .{
1541                .llvm_name = "64bit-mode",
1542                .omit = true,
1543            },
1544            // Remove these when LLVM removes AVX10.N-256 support.
1545            .{
1546                .llvm_name = "avx10.1-256",
1547                .flatten = true,
1548            },
1549            .{
1550                .llvm_name = "avx10.2-256",
1551                .flatten = true,
1552            },
1553            .{
1554                .llvm_name = "avx10.1-512",
1555                .zig_name = "avx10_1",
1556            },
1557            .{
1558                .llvm_name = "avx10.2-512",
1559                .zig_name = "avx10_2",
1560            },
1561            .{
1562                .llvm_name = "avx512f",
1563                .extra_deps = &.{"evex512"},
1564            },
1565            .{
1566                .llvm_name = "alderlake",
1567                .extra_deps = &.{ "smap", "smep" },
1568            },
1569            .{
1570                .llvm_name = "amdfam10",
1571                .extra_deps = &.{"3dnowa"},
1572            },
1573            .{
1574                .llvm_name = "arrowlake",
1575                .extra_deps = &.{ "smap", "smep" },
1576            },
1577            .{
1578                .llvm_name = "arrowlake-s",
1579                .extra_deps = &.{ "smap", "smep" },
1580            },
1581            .{
1582                .llvm_name = "athlon",
1583                .extra_deps = &.{"3dnowa"},
1584            },
1585            .{
1586                .llvm_name = "athlon64",
1587                .extra_deps = &.{"3dnowa"},
1588            },
1589            .{
1590                .llvm_name = "athlon64-sse3",
1591                .extra_deps = &.{"3dnowa"},
1592            },
1593            .{
1594                .llvm_name = "athlon-4",
1595                .extra_deps = &.{"3dnowa"},
1596            },
1597            .{
1598                .llvm_name = "athlon-fx",
1599                .extra_deps = &.{"3dnowa"},
1600            },
1601            .{
1602                .llvm_name = "athlon-mp",
1603                .extra_deps = &.{"3dnowa"},
1604            },
1605            .{
1606                .llvm_name = "athlon-tbird",
1607                .extra_deps = &.{"3dnowa"},
1608            },
1609            .{
1610                .llvm_name = "athlon-xp",
1611                .extra_deps = &.{"3dnowa"},
1612            },
1613            .{
1614                .llvm_name = "barcelona",
1615                .extra_deps = &.{ "3dnowa", "smap", "smep" },
1616            },
1617            .{
1618                .llvm_name = "broadwell",
1619                .extra_deps = &.{ "smap", "smep" },
1620            },
1621            .{
1622                .llvm_name = "c3",
1623                .extra_deps = &.{"3dnow"},
1624            },
1625            .{
1626                .llvm_name = "cannonlake",
1627                .extra_deps = &.{ "smap", "smep" },
1628            },
1629            .{
1630                .llvm_name = "cascadelake",
1631                .extra_deps = &.{ "smap", "smep" },
1632            },
1633            .{
1634                .llvm_name = "emeraldrapids",
1635                .extra_deps = &.{ "smap", "smep" },
1636            },
1637            .{
1638                .llvm_name = "geode",
1639                .extra_deps = &.{"3dnowa"},
1640            },
1641            .{
1642                .llvm_name = "goldmont",
1643                .extra_deps = &.{ "smap", "smep" },
1644            },
1645            .{
1646                .llvm_name = "goldmont_plus",
1647                .extra_deps = &.{ "smap", "smep" },
1648            },
1649            .{
1650                .llvm_name = "haswell",
1651                .extra_deps = &.{"smep"},
1652            },
1653            .{
1654                .llvm_name = "i386",
1655                .extra_deps = &.{"bsf_bsr_0_clobbers_result"},
1656            },
1657            .{
1658                .llvm_name = "i486",
1659                .extra_deps = &.{"bsf_bsr_0_clobbers_result"},
1660            },
1661            .{
1662                .llvm_name = "icelake_client",
1663                .extra_deps = &.{ "smap", "smep" },
1664            },
1665            .{
1666                .llvm_name = "icelake_server",
1667                .extra_deps = &.{ "smap", "smep" },
1668            },
1669            .{
1670                .llvm_name = "ivybridge",
1671                .extra_deps = &.{"smep"},
1672            },
1673            .{
1674                .llvm_name = "k6-2",
1675                .extra_deps = &.{"3dnow"},
1676            },
1677            .{
1678                .llvm_name = "k6-3",
1679                .extra_deps = &.{"3dnow"},
1680            },
1681            .{
1682                .llvm_name = "k8",
1683                .extra_deps = &.{"3dnowa"},
1684            },
1685            .{
1686                .llvm_name = "k8-sse3",
1687                .extra_deps = &.{"3dnowa"},
1688            },
1689            .{
1690                .llvm_name = "knl",
1691                .extra_deps = &.{
1692                    "avx512er",
1693                    "avx512pf",
1694                    "prefetchwt1",
1695                },
1696            },
1697            .{
1698                .llvm_name = "knm",
1699                .extra_deps = &.{
1700                    "avx512er",
1701                    "avx512pf",
1702                    "prefetchwt1",
1703                },
1704            },
1705            .{
1706                .llvm_name = "lakemont",
1707                .extra_deps = &.{"soft_float"},
1708            },
1709            .{
1710                .llvm_name = "meteorlake",
1711                .extra_deps = &.{ "smap", "smep" },
1712            },
1713            .{
1714                .llvm_name = "opteron",
1715                .extra_deps = &.{"3dnowa"},
1716            },
1717            .{
1718                .llvm_name = "opteron-sse3",
1719                .extra_deps = &.{"3dnowa"},
1720            },
1721            .{
1722                .llvm_name = "raptorlake",
1723                .extra_deps = &.{ "smap", "smep" },
1724            },
1725            .{
1726                .llvm_name = "rocketlake",
1727                .extra_deps = &.{ "smap", "smep" },
1728            },
1729            .{
1730                .llvm_name = "sapphirerapids",
1731                .extra_deps = &.{ "smap", "smep" },
1732            },
1733            .{
1734                .llvm_name = "silvermont",
1735                .extra_deps = &.{"smep"},
1736            },
1737            .{
1738                .llvm_name = "skx",
1739                .extra_deps = &.{ "smap", "smep" },
1740            },
1741            .{
1742                .llvm_name = "skylake",
1743                .extra_deps = &.{ "smap", "smep" },
1744            },
1745            .{
1746                .llvm_name = "skylake_avx512",
1747                .extra_deps = &.{ "smap", "smep" },
1748            },
1749            .{
1750                .llvm_name = "tigerlake",
1751                .extra_deps = &.{ "smap", "smep" },
1752            },
1753            .{
1754                .llvm_name = "winchip2",
1755                .extra_deps = &.{"3dnow"},
1756            },
1757            .{
1758                .llvm_name = "sse4.2",
1759                .extra_deps = &.{"crc32"},
1760            },
1761            .{
1762                .llvm_name = "znver1",
1763                .extra_deps = &.{ "smap", "smep" },
1764            },
1765            .{
1766                .llvm_name = "znver2",
1767                .extra_deps = &.{ "smap", "smep" },
1768            },
1769            .{
1770                .llvm_name = "znver3",
1771                .extra_deps = &.{ "smap", "smep" },
1772            },
1773            .{
1774                .llvm_name = "znver4",
1775                .extra_deps = &.{ "smap", "smep" },
1776            },
1777            .{
1778                .llvm_name = "znver5",
1779                .extra_deps = &.{ "smap", "smep" },
1780            },
1781        },
1782        .extra_features = &.{
1783            // Features removed from LLVM
1784            .{
1785                .zig_name = "3dnow",
1786                .desc = "Enable 3DNow! instructions",
1787                .deps = &.{"mmx"},
1788            },
1789            .{
1790                .zig_name = "3dnowa",
1791                .desc = "Enable 3DNow! Athlon instructions",
1792                .deps = &.{"3dnow"},
1793            },
1794            .{
1795                .zig_name = "avx512er",
1796                .desc = "Enable AVX-512 Exponential and Reciprocal Instructions",
1797                .deps = &.{"avx512f"},
1798            },
1799            .{
1800                .zig_name = "avx512pf",
1801                .desc = "Enable AVX-512 PreFetch Instructions",
1802                .deps = &.{"avx512f"},
1803            },
1804            .{
1805                .zig_name = "prefetchwt1",
1806                .desc = "Prefetch with Intent to Write and T1 Hint",
1807                .deps = &.{},
1808            },
1809            // Custom Zig features
1810            .{
1811                .zig_name = "bsf_bsr_0_clobbers_result",
1812                .desc = "BSF/BSR may clobber the lower 32-bits of the result register when the source is zero",
1813                .deps = &.{},
1814            },
1815            .{
1816                .zig_name = "smap",
1817                .desc = "Enable Supervisor Mode Access Prevention",
1818                .deps = &.{},
1819            },
1820            .{
1821                .zig_name = "smep",
1822                .desc = "Enable Supervisor Mode Execution Prevention",
1823                .deps = &.{},
1824            },
1825        },
1826        .extra_cpus = &.{
1827            .{
1828                .llvm_name = null,
1829                .zig_name = "i86",
1830                .features = &.{"16bit_mode"},
1831            },
1832        },
1833        .omit_cpus = &.{
1834            // LLVM defines a bunch of dumb aliases with foreach loops in X86.td.
1835            "pentium_mmx",
1836            "pentium_pro",
1837            "pentium_ii",
1838            "pentium_3m",
1839            "pentium_iii_no_xmm_regs",
1840            "pentium_iii",
1841            "pentium_m",
1842            "pentium4m",
1843            "pentium_4",
1844            "pentium_4_sse3",
1845            "core_2_duo_ssse3",
1846            "core_2_duo_sse4_1",
1847            "atom_sse4_2",
1848            "goldmont_plus",
1849            "core_i7_sse4_2",
1850            "core_aes_pclmulqdq",
1851            "corei7-avx",
1852            "core_2nd_gen_avx",
1853            "core-avx-i",
1854            "core_3rd_gen_avx",
1855            "core-avx2",
1856            "core_4th_gen_avx",
1857            "core_4th_gen_avx_tsx",
1858            "core_5th_gen_avx",
1859            "core_5th_gen_avx_tsx",
1860            "mic_avx512",
1861            "skylake_avx512",
1862            "icelake_client",
1863            "icelake_server",
1864            "graniterapids_d",
1865            "arrowlake_s",
1866        },
1867    },
1868    .{
1869        .zig_name = "xcore",
1870        .llvm = .{
1871            .name = "XCore",
1872            .td_name = "XCore",
1873        },
1874    },
1875    .{
1876        .zig_name = "xtensa",
1877        .llvm = .{
1878            .name = "Xtensa",
1879            .td_name = "Xtensa",
1880        },
1881    },
1882};
1883
1884pub fn main() anyerror!void {
1885    var arena_state = std.heap.ArenaAllocator.init(std.heap.page_allocator);
1886    defer arena_state.deinit();
1887    const arena = arena_state.allocator();
1888
1889    var args = try std.process.argsWithAllocator(arena);
1890    const args0 = args.next().?;
1891
1892    const llvm_tblgen_exe = args.next() orelse
1893        usageAndExit(args0, 1);
1894
1895    if (std.mem.eql(u8, llvm_tblgen_exe, "--help")) {
1896        usageAndExit(args0, 0);
1897    }
1898    if (std.mem.startsWith(u8, llvm_tblgen_exe, "-")) {
1899        usageAndExit(args0, 1);
1900    }
1901
1902    const llvm_src_root = args.next() orelse
1903        usageAndExit(args0, 1);
1904
1905    if (std.mem.startsWith(u8, llvm_src_root, "-")) {
1906        usageAndExit(args0, 1);
1907    }
1908
1909    const zig_src_root = args.next() orelse
1910        usageAndExit(args0, 1);
1911
1912    if (std.mem.startsWith(u8, zig_src_root, "-")) {
1913        usageAndExit(args0, 1);
1914    }
1915
1916    var filter: ?[]const u8 = null;
1917    if (args.next()) |arg| filter = arg;
1918
1919    // there shouldn't be any more argument after the optional filter
1920    if (args.skip()) usageAndExit(args0, 1);
1921
1922    var zig_src_dir = try fs.cwd().openDir(zig_src_root, .{});
1923    defer zig_src_dir.close();
1924
1925    const root_progress = std.Progress.start(.{ .estimated_total_items = targets.len });
1926    defer root_progress.end();
1927
1928    if (builtin.single_threaded) {
1929        for (targets) |target| {
1930            if (filter) |zig_name| if (!std.mem.eql(u8, target.zig_name, zig_name)) continue;
1931            try processOneTarget(.{
1932                .llvm_tblgen_exe = llvm_tblgen_exe,
1933                .llvm_src_root = llvm_src_root,
1934                .zig_src_dir = zig_src_dir,
1935                .root_progress = root_progress,
1936                .target = target,
1937            });
1938        }
1939    } else {
1940        var pool: std.Thread.Pool = undefined;
1941        try pool.init(.{ .allocator = arena, .n_jobs = targets.len });
1942        defer pool.deinit();
1943
1944        for (targets) |target| {
1945            if (filter) |zig_name| if (!std.mem.eql(u8, target.zig_name, zig_name)) continue;
1946            const job = Job{
1947                .llvm_tblgen_exe = llvm_tblgen_exe,
1948                .llvm_src_root = llvm_src_root,
1949                .zig_src_dir = zig_src_dir,
1950                .root_progress = root_progress,
1951                .target = target,
1952            };
1953            try pool.spawn(processOneTarget, .{job});
1954        }
1955    }
1956}
1957
1958const Job = struct {
1959    llvm_tblgen_exe: []const u8,
1960    llvm_src_root: []const u8,
1961    zig_src_dir: std.fs.Dir,
1962    root_progress: std.Progress.Node,
1963    target: ArchTarget,
1964};
1965
1966fn processOneTarget(job: Job) void {
1967    errdefer |err| std.debug.panic("panic: {s}", .{@errorName(err)});
1968    const target = job.target;
1969
1970    var arena_state = std.heap.ArenaAllocator.init(std.heap.page_allocator);
1971    defer arena_state.deinit();
1972    const arena = arena_state.allocator();
1973
1974    const progress_node = job.root_progress.start(target.zig_name, 3);
1975    defer progress_node.end();
1976
1977    var features_table = std.StringHashMap(Feature).init(arena);
1978    var all_features = std.array_list.Managed(Feature).init(arena);
1979    var all_cpus = std.array_list.Managed(Cpu).init(arena);
1980
1981    if (target.llvm) |llvm| {
1982        const tblgen_progress = progress_node.start("running llvm-tblgen", 0);
1983
1984        const child_args = [_][]const u8{
1985            job.llvm_tblgen_exe,
1986            "--dump-json",
1987            try std.fmt.allocPrint(arena, "{s}/llvm/lib/Target/{s}/{s}.td", .{
1988                job.llvm_src_root,
1989                llvm.name,
1990                llvm.td_name,
1991            }),
1992            try std.fmt.allocPrint(arena, "-I={s}/llvm/include", .{job.llvm_src_root}),
1993            try std.fmt.allocPrint(arena, "-I={s}/llvm/lib/Target/{s}", .{
1994                job.llvm_src_root, llvm.name,
1995            }),
1996        };
1997
1998        const child_result = try std.process.Child.run(.{
1999            .allocator = arena,
2000            .argv = &child_args,
2001            .max_output_bytes = 500 * 1024 * 1024,
2002        });
2003        tblgen_progress.end();
2004        if (child_result.stderr.len != 0) {
2005            std.debug.print("{s}\n", .{child_result.stderr});
2006        }
2007
2008        const json_text = switch (child_result.term) {
2009            .Exited => |code| if (code == 0) child_result.stdout else {
2010                std.debug.print("llvm-tblgen exited with code {d}\n", .{code});
2011                std.process.exit(1);
2012            },
2013            else => {
2014                std.debug.print("llvm-tblgen crashed\n", .{});
2015                std.process.exit(1);
2016            },
2017        };
2018
2019        const json_parse_progress = progress_node.start("parsing JSON", 0);
2020
2021        const parsed = try json.parseFromSlice(json.Value, arena, json_text, .{});
2022        defer parsed.deinit();
2023        const root_map = &parsed.value.object;
2024        json_parse_progress.end();
2025
2026        const collate_progress = progress_node.start("collating LLVM data", 0);
2027
2028        // So far, LLVM only has a few aliases for the same CPU.
2029        const Alias = struct {
2030            llvm: []const u8,
2031            zig: []const u8,
2032        };
2033        var cpu_aliases = std.StringHashMap(std.ArrayList(*Alias)).init(arena);
2034
2035        {
2036            var it = root_map.iterator();
2037            while (it.next()) |kv| {
2038                if (kv.key_ptr.len == 0) continue;
2039                if (kv.key_ptr.*[0] == '!') continue;
2040                if (kv.value_ptr.* != .object) continue;
2041                if (hasSuperclass(&kv.value_ptr.object, "ProcessorAlias")) {
2042                    // Note that `Name` is actually the alias, while `Alias` is the name that will have
2043                    // a full `Processor` object defined.
2044                    const llvm_alias = kv.value_ptr.object.get("Name").?.string;
2045                    const llvm_name = kv.value_ptr.object.get("Alias").?.string;
2046
2047                    const gop = try cpu_aliases.getOrPut(try llvmNameToZigName(arena, llvm_name));
2048
2049                    if (!gop.found_existing) {
2050                        gop.value_ptr.* = .empty;
2051                    }
2052
2053                    const alias = try arena.create(Alias);
2054                    alias.* = .{
2055                        .llvm = llvm_alias,
2056                        .zig = try llvmNameToZigName(arena, llvm_alias),
2057                    };
2058                    try gop.value_ptr.append(arena, alias);
2059                }
2060            }
2061        }
2062
2063        {
2064            var it = root_map.iterator();
2065            while (it.next()) |kv| {
2066                if (kv.key_ptr.len == 0) continue;
2067                if (kv.key_ptr.*[0] == '!') continue;
2068                if (kv.value_ptr.* != .object) continue;
2069                if (hasSuperclass(&kv.value_ptr.object, "SubtargetFeature")) {
2070                    const llvm_name = kv.value_ptr.object.get("Name").?.string;
2071                    if (llvm_name.len == 0) continue;
2072
2073                    var zig_name = try llvmNameToZigName(arena, llvm_name);
2074                    var desc = kv.value_ptr.object.get("Desc").?.string;
2075                    var deps = std.array_list.Managed([]const u8).init(arena);
2076                    var omit = false;
2077                    var flatten = false;
2078                    var omit_deps: []const []const u8 = &.{};
2079                    var extra_deps: []const []const u8 = &.{};
2080                    for (target.feature_overrides) |feature_override| {
2081                        if (mem.eql(u8, llvm_name, feature_override.llvm_name)) {
2082                            if (feature_override.omit) {
2083                                // Still put the feature into the table so that we can
2084                                // expand dependencies for the feature overrides marked `flatten`.
2085                                omit = true;
2086                            }
2087                            if (feature_override.flatten) {
2088                                flatten = true;
2089                            }
2090                            if (feature_override.zig_name) |override_name| {
2091                                zig_name = override_name;
2092                            }
2093                            if (feature_override.desc) |override_desc| {
2094                                desc = override_desc;
2095                            }
2096                            omit_deps = feature_override.omit_deps;
2097                            extra_deps = feature_override.extra_deps;
2098                            break;
2099                        }
2100                    }
2101                    const implies = kv.value_ptr.object.get("Implies").?.array;
2102                    for (implies.items) |imply| {
2103                        const other_key = imply.object.get("def").?.string;
2104                        const other_obj = root_map.get(other_key).?.object;
2105                        const other_llvm_name = other_obj.get("Name").?.string;
2106                        const other_zig_name = (try llvmFeatureNameToZigNameOmit(
2107                            arena,
2108                            target,
2109                            other_llvm_name,
2110                        )) orelse continue;
2111                        for (omit_deps) |omit_dep| {
2112                            if (mem.eql(u8, other_zig_name, omit_dep)) break;
2113                        } else {
2114                            try deps.append(other_zig_name);
2115                        }
2116                    }
2117                    // This is used by AArch64.
2118                    if (kv.value_ptr.object.get("DefaultExts")) |exts_val| {
2119                        for (exts_val.array.items) |ext| {
2120                            const other_key = ext.object.get("def").?.string;
2121                            const other_obj = root_map.get(other_key).?.object;
2122                            const other_llvm_name = other_obj.get("Name").?.string;
2123                            const other_zig_name = (try llvmFeatureNameToZigNameOmit(
2124                                arena,
2125                                target,
2126                                other_llvm_name,
2127                            )) orelse continue;
2128                            for (omit_deps) |omit_dep| {
2129                                if (mem.eql(u8, other_zig_name, omit_dep)) break;
2130                            } else {
2131                                try deps.append(other_zig_name);
2132                            }
2133                        }
2134                    }
2135                    for (extra_deps) |extra_dep| {
2136                        try deps.append(extra_dep);
2137                    }
2138                    const feature: Feature = .{
2139                        .llvm_name = llvm_name,
2140                        .zig_name = zig_name,
2141                        .desc = desc,
2142                        .deps = deps.items,
2143                        .flatten = flatten,
2144                    };
2145                    try features_table.put(zig_name, feature);
2146                    if (!omit and !flatten) {
2147                        try all_features.append(feature);
2148                    }
2149                }
2150                if (hasSuperclass(&kv.value_ptr.object, "Processor")) {
2151                    const llvm_name = kv.value_ptr.object.get("Name").?.string;
2152                    if (llvm_name.len == 0) continue;
2153                    const omitted = for (target.omit_cpus) |omit_cpu_name| {
2154                        if (mem.eql(u8, omit_cpu_name, llvm_name)) break true;
2155                    } else false;
2156                    if (omitted) continue;
2157
2158                    var zig_name = try llvmNameToZigName(arena, llvm_name);
2159                    var deps = std.array_list.Managed([]const u8).init(arena);
2160                    var omit_deps: []const []const u8 = &.{};
2161                    var extra_deps: []const []const u8 = &.{};
2162                    for (target.feature_overrides) |feature_override| {
2163                        if (mem.eql(u8, llvm_name, feature_override.llvm_name)) {
2164                            if (feature_override.omit) {
2165                                continue;
2166                            }
2167                            if (feature_override.zig_name) |override_name| {
2168                                zig_name = override_name;
2169                            }
2170                            omit_deps = feature_override.omit_deps;
2171                            extra_deps = feature_override.extra_deps;
2172                            break;
2173                        }
2174                    }
2175                    const features = kv.value_ptr.object.get("Features").?.array;
2176                    for (features.items) |feature| {
2177                        const feature_key = feature.object.get("def").?.string;
2178                        const feature_obj = root_map.get(feature_key).?.object;
2179                        const feature_llvm_name = feature_obj.get("Name").?.string;
2180                        if (feature_llvm_name.len == 0) continue;
2181                        const feature_zig_name = (try llvmFeatureNameToZigNameOmit(
2182                            arena,
2183                            target,
2184                            feature_llvm_name,
2185                        )) orelse continue;
2186                        for (omit_deps) |omit_dep| {
2187                            if (mem.eql(u8, feature_zig_name, omit_dep)) break;
2188                        } else {
2189                            try deps.append(feature_zig_name);
2190                        }
2191                    }
2192                    for (extra_deps) |extra_dep| {
2193                        try deps.append(extra_dep);
2194                    }
2195                    const tune_features = kv.value_ptr.object.get("TuneFeatures").?.array;
2196                    for (tune_features.items) |feature| {
2197                        const feature_key = feature.object.get("def").?.string;
2198                        const feature_obj = root_map.get(feature_key).?.object;
2199                        const feature_llvm_name = feature_obj.get("Name").?.string;
2200                        if (feature_llvm_name.len == 0) continue;
2201                        const feature_zig_name = (try llvmFeatureNameToZigNameOmit(
2202                            arena,
2203                            target,
2204                            feature_llvm_name,
2205                        )) orelse continue;
2206                        try deps.append(feature_zig_name);
2207                    }
2208                    try all_cpus.append(.{
2209                        .llvm_name = llvm_name,
2210                        .zig_name = zig_name,
2211                        .features = deps.items,
2212                    });
2213
2214                    if (cpu_aliases.get(zig_name)) |aliases| {
2215                        alias_it: for (aliases.items) |alias| {
2216                            for (target.omit_cpus) |omit_cpu_name| {
2217                                if (mem.eql(u8, omit_cpu_name, alias.llvm)) continue :alias_it;
2218                            }
2219
2220                            try all_cpus.append(.{
2221                                .llvm_name = alias.llvm,
2222                                .zig_name = alias.zig,
2223                                .features = deps.items,
2224                            });
2225                        }
2226                    }
2227                }
2228            }
2229        }
2230
2231        collate_progress.end();
2232    }
2233
2234    for (target.extra_features) |extra_feature| {
2235        try features_table.put(extra_feature.zig_name, extra_feature);
2236        try all_features.append(extra_feature);
2237    }
2238    for (target.extra_cpus) |extra_cpu| {
2239        try all_cpus.append(extra_cpu);
2240    }
2241    mem.sort(Feature, all_features.items, {}, featureLessThan);
2242    mem.sort(Cpu, all_cpus.items, {}, cpuLessThan);
2243
2244    const render_progress = progress_node.start("rendering Zig code", 0);
2245
2246    var target_dir = try job.zig_src_dir.openDir("lib/std/Target", .{});
2247    defer target_dir.close();
2248
2249    const zig_code_basename = try std.fmt.allocPrint(arena, "{s}.zig", .{target.zig_name});
2250    var zig_code_file = try target_dir.createFile(zig_code_basename, .{});
2251    defer zig_code_file.close();
2252
2253    var zig_code_file_buffer: [4096]u8 = undefined;
2254    var zig_code_file_writer = zig_code_file.writer(&zig_code_file_buffer);
2255    const w = &zig_code_file_writer.interface;
2256
2257    try w.writeAll(
2258        \\//! This file is auto-generated by tools/update_cpu_features.zig.
2259        \\
2260        \\const std = @import("../std.zig");
2261        \\const CpuFeature = std.Target.Cpu.Feature;
2262        \\const CpuModel = std.Target.Cpu.Model;
2263        \\
2264        \\pub const Feature = enum {
2265    );
2266
2267    for (all_features.items, 0..) |feature, i| {
2268        try w.print("\n    {f},", .{std.zig.fmtIdPU(feature.zig_name)});
2269
2270        if (i == all_features.items.len - 1) try w.writeAll("\n");
2271    }
2272
2273    try w.writeAll(
2274        \\};
2275        \\
2276        \\pub const featureSet = CpuFeature.FeatureSetFns(Feature).featureSet;
2277        \\pub const featureSetHas = CpuFeature.FeatureSetFns(Feature).featureSetHas;
2278        \\pub const featureSetHasAny = CpuFeature.FeatureSetFns(Feature).featureSetHasAny;
2279        \\pub const featureSetHasAll = CpuFeature.FeatureSetFns(Feature).featureSetHasAll;
2280        \\
2281        \\pub const all_features = blk: {
2282        \\
2283    );
2284    if (target.branch_quota) |branch_quota| {
2285        try w.print("    @setEvalBranchQuota({d});\n", .{branch_quota});
2286    }
2287    try w.writeAll(
2288        \\    const len = @typeInfo(Feature).@"enum".fields.len;
2289        \\    std.debug.assert(len <= CpuFeature.Set.needed_bit_count);
2290        \\    var result: [len]CpuFeature = undefined;
2291        \\
2292    );
2293
2294    for (all_features.items) |feature| {
2295        if (feature.llvm_name) |llvm_name| {
2296            try w.print(
2297                \\    result[@intFromEnum(Feature.{f})] = .{{
2298                \\        .llvm_name = "{f}",
2299                \\        .description = "{f}",
2300                \\        .dependencies = featureSet(&[_]Feature{{
2301            ,
2302                .{
2303                    std.zig.fmtIdPU(feature.zig_name),
2304                    std.zig.fmtString(llvm_name),
2305                    std.zig.fmtString(feature.desc),
2306                },
2307            );
2308        } else {
2309            try w.print(
2310                \\    result[@intFromEnum(Feature.{f})] = .{{
2311                \\        .llvm_name = null,
2312                \\        .description = "{f}",
2313                \\        .dependencies = featureSet(&[_]Feature{{
2314            ,
2315                .{
2316                    std.zig.fmtIdPU(feature.zig_name),
2317                    std.zig.fmtString(feature.desc),
2318                },
2319            );
2320        }
2321        var deps_set = std.StringHashMap(void).init(arena);
2322        for (feature.deps) |dep| {
2323            try putDep(&deps_set, features_table, dep);
2324        }
2325        try pruneFeatures(arena, features_table, &deps_set);
2326        var dependencies = std.array_list.Managed([]const u8).init(arena);
2327        {
2328            var it = deps_set.keyIterator();
2329            while (it.next()) |key| {
2330                try dependencies.append(key.*);
2331            }
2332        }
2333        mem.sort([]const u8, dependencies.items, {}, asciiLessThan);
2334
2335        if (dependencies.items.len == 0) {
2336            try w.writeAll(
2337                \\}),
2338                \\    };
2339                \\
2340            );
2341        } else {
2342            try w.writeAll("\n");
2343            for (dependencies.items) |dep| {
2344                try w.print("            .{f},\n", .{std.zig.fmtIdPU(dep)});
2345            }
2346            try w.writeAll(
2347                \\        }),
2348                \\    };
2349                \\
2350            );
2351        }
2352    }
2353    try w.writeAll(
2354        \\    const ti = @typeInfo(Feature);
2355        \\    for (&result, 0..) |*elem, i| {
2356        \\        elem.index = i;
2357        \\        elem.name = ti.@"enum".fields[i].name;
2358        \\    }
2359        \\    break :blk result;
2360        \\};
2361        \\
2362        \\pub const cpu = struct {
2363        \\
2364    );
2365    for (all_cpus.items) |cpu| {
2366        var deps_set = std.StringHashMap(void).init(arena);
2367        for (cpu.features) |feature_zig_name| {
2368            try putDep(&deps_set, features_table, feature_zig_name);
2369        }
2370        try pruneFeatures(arena, features_table, &deps_set);
2371        var cpu_features = std.array_list.Managed([]const u8).init(arena);
2372        {
2373            var it = deps_set.keyIterator();
2374            while (it.next()) |key| {
2375                try cpu_features.append(key.*);
2376            }
2377        }
2378        mem.sort([]const u8, cpu_features.items, {}, asciiLessThan);
2379        if (cpu.llvm_name) |llvm_name| {
2380            try w.print(
2381                \\    pub const {f}: CpuModel = .{{
2382                \\        .name = "{f}",
2383                \\        .llvm_name = "{f}",
2384                \\        .features = featureSet(&[_]Feature{{
2385            , .{
2386                std.zig.fmtId(cpu.zig_name),
2387                std.zig.fmtString(cpu.zig_name),
2388                std.zig.fmtString(llvm_name),
2389            });
2390        } else {
2391            try w.print(
2392                \\    pub const {f}: CpuModel = .{{
2393                \\        .name = "{f}",
2394                \\        .llvm_name = null,
2395                \\        .features = featureSet(&[_]Feature{{
2396            , .{
2397                std.zig.fmtId(cpu.zig_name),
2398                std.zig.fmtString(cpu.zig_name),
2399            });
2400        }
2401        if (cpu_features.items.len == 0) {
2402            try w.writeAll(
2403                \\}),
2404                \\    };
2405                \\
2406            );
2407        } else {
2408            try w.writeAll("\n");
2409            for (cpu_features.items) |feature_zig_name| {
2410                try w.print("            .{f},\n", .{std.zig.fmtIdPU(feature_zig_name)});
2411            }
2412            try w.writeAll(
2413                \\        }),
2414                \\    };
2415                \\
2416            );
2417        }
2418    }
2419
2420    try w.writeAll(
2421        \\};
2422        \\
2423    );
2424    try w.flush();
2425
2426    render_progress.end();
2427}
2428
2429fn usageAndExit(arg0: []const u8, code: u8) noreturn {
2430    const stderr, _ = std.debug.lockStderrWriter(&.{});
2431    stderr.print(
2432        \\Usage: {s} /path/to/llvm-tblgen /path/git/llvm-project /path/git/zig [zig_name filter]
2433        \\
2434        \\Updates lib/std/target/<target>.zig from llvm/lib/Target/<Target>/<Target>.td .
2435        \\
2436        \\On a less beefy system, or when debugging, compile with -fsingle-threaded.
2437        \\
2438    , .{arg0}) catch std.process.exit(1);
2439    std.process.exit(code);
2440}
2441
2442fn featureLessThan(_: void, a: Feature, b: Feature) bool {
2443    return std.ascii.lessThanIgnoreCase(a.zig_name, b.zig_name);
2444}
2445
2446fn cpuLessThan(_: void, a: Cpu, b: Cpu) bool {
2447    return std.ascii.lessThanIgnoreCase(a.zig_name, b.zig_name);
2448}
2449
2450fn asciiLessThan(_: void, a: []const u8, b: []const u8) bool {
2451    return std.ascii.lessThanIgnoreCase(a, b);
2452}
2453
2454fn llvmNameToZigName(arena: mem.Allocator, llvm_name: []const u8) ![]const u8 {
2455    const duped = try arena.dupe(u8, llvm_name);
2456    for (duped) |*byte| switch (byte.*) {
2457        '-', '.' => byte.* = '_',
2458        else => continue,
2459    };
2460    return duped;
2461}
2462
2463fn llvmFeatureNameToZigNameOmit(
2464    arena: mem.Allocator,
2465    target: ArchTarget,
2466    llvm_name: []const u8,
2467) !?[]const u8 {
2468    for (target.feature_overrides) |feature_override| {
2469        if (mem.eql(u8, feature_override.llvm_name, llvm_name)) {
2470            if (feature_override.omit) return null;
2471            return feature_override.zig_name orelse break;
2472        }
2473    }
2474    return try llvmNameToZigName(arena, llvm_name);
2475}
2476
2477fn hasSuperclass(obj: *const json.ObjectMap, class_name: []const u8) bool {
2478    const superclasses_json = obj.get("!superclasses") orelse return false;
2479    for (superclasses_json.array.items) |superclass_json| {
2480        const superclass = superclass_json.string;
2481        if (std.mem.eql(u8, superclass, class_name)) {
2482            return true;
2483        }
2484    }
2485    return false;
2486}
2487
2488fn pruneFeatures(
2489    arena: mem.Allocator,
2490    features_table: std.StringHashMap(Feature),
2491    deps_set: *std.StringHashMap(void),
2492) !void {
2493    // For each element, recursively iterate over the dependencies and add
2494    // everything we find to a "deletion set".
2495    // Then, iterate over the deletion set and delete all that stuff from `deps_set`.
2496    var deletion_set = std.StringHashMap(void).init(arena);
2497    {
2498        var it = deps_set.keyIterator();
2499        while (it.next()) |key| {
2500            const feature = features_table.get(key.*).?;
2501            try walkFeatures(features_table, &deletion_set, feature);
2502        }
2503    }
2504    {
2505        var it = deletion_set.keyIterator();
2506        while (it.next()) |key| {
2507            _ = deps_set.remove(key.*);
2508        }
2509    }
2510}
2511
2512fn walkFeatures(
2513    features_table: std.StringHashMap(Feature),
2514    deletion_set: *std.StringHashMap(void),
2515    feature: Feature,
2516) error{OutOfMemory}!void {
2517    for (feature.deps) |dep| {
2518        try deletion_set.put(dep, {});
2519        const other_feature = features_table.get(dep).?;
2520        try walkFeatures(features_table, deletion_set, other_feature);
2521    }
2522}
2523
2524fn putDep(
2525    deps_set: *std.StringHashMap(void),
2526    features_table: std.StringHashMap(Feature),
2527    zig_feature_name: []const u8,
2528) error{OutOfMemory}!void {
2529    const feature = features_table.get(zig_feature_name).?;
2530    if (feature.flatten) {
2531        for (feature.deps) |dep| {
2532            try putDep(deps_set, features_table, dep);
2533        }
2534    } else {
2535        try deps_set.put(zig_feature_name, {});
2536    }
2537}