zig/tools/update_cpu_features.zig
Alex Rønne Petersen fccf15fc9f std.Target: Remove armv7k/armv7s.
Like d1d95294fd, this is more Apple nonsense where
they abused the arch component of the triple to encode what's really an ABI.

Handling this correctly in Zig's target triple model would take quite a bit of
work. Fortunately, the last Armv7-based Apple Watch was released in 2017 and
these targets are now considered legacy. By the time Zig hits 1.0, they will be
a distant memory. So just remove them.
2024-11-02 10:25:40 +01:00

1867 lines
56 KiB
Zig

const std = @import("std");
const builtin = @import("builtin");
const fs = std.fs;
const mem = std.mem;
const json = std.json;
const assert = std.debug.assert;
// All references to other features are based on "zig name" as the key.
const FeatureOverride = struct {
llvm_name: []const u8,
/// If true, completely omit the feature; as if it does not exist.
omit: bool = false,
/// If true, omit the feature, but all the dependencies of the feature
/// are added in its place.
flatten: bool = false,
zig_name: ?[]const u8 = null,
desc: ?[]const u8 = null,
omit_deps: []const []const u8 = &.{},
extra_deps: []const []const u8 = &.{},
};
const Cpu = struct {
llvm_name: ?[]const u8,
zig_name: []const u8,
features: []const []const u8,
};
const Feature = struct {
llvm_name: ?[]const u8 = null,
zig_name: []const u8,
desc: []const u8,
deps: []const []const u8,
flatten: bool = false,
};
const LlvmTarget = struct {
zig_name: []const u8,
llvm_name: []const u8,
td_name: []const u8,
feature_overrides: []const FeatureOverride = &.{},
extra_cpus: []const Cpu = &.{},
extra_features: []const Feature = &.{},
omit_cpus: []const []const u8 = &.{},
branch_quota: ?usize = null,
};
const llvm_targets = [_]LlvmTarget{
.{
.zig_name = "aarch64",
.llvm_name = "AArch64",
.td_name = "AArch64.td",
.branch_quota = 2000,
.feature_overrides = &.{
.{
.llvm_name = "all",
.omit = true,
},
.{
.llvm_name = "CONTEXTIDREL2",
.zig_name = "contextidr_el2",
.desc = "Enable RW operand Context ID Register (EL2)",
},
.{
.llvm_name = "neoversee1",
.flatten = true,
},
.{
.llvm_name = "neoversen1",
.flatten = true,
},
.{
.llvm_name = "neoversen2",
.flatten = true,
},
.{
.llvm_name = "neoversen3",
.flatten = true,
},
.{
.llvm_name = "neoversev1",
.flatten = true,
},
.{
.llvm_name = "neoversev2",
.flatten = true,
},
.{
.llvm_name = "neoversev3",
.flatten = true,
},
.{
.llvm_name = "neoversev3AE",
.flatten = true,
},
.{
.llvm_name = "neoverse512tvb",
.flatten = true,
},
.{
.llvm_name = "oryon-1",
.flatten = true,
},
.{
.llvm_name = "exynosm3",
.flatten = true,
},
.{
.llvm_name = "exynosm4",
.flatten = true,
},
.{
.llvm_name = "a35",
.flatten = true,
},
.{
.llvm_name = "a53",
.flatten = true,
},
.{
.llvm_name = "a55",
.flatten = true,
},
.{
.llvm_name = "a57",
.flatten = true,
},
.{
.llvm_name = "a510",
.flatten = true,
},
.{
.llvm_name = "a520",
.flatten = true,
},
.{
.llvm_name = "a520ae",
.flatten = true,
},
.{
.llvm_name = "a64fx",
.flatten = true,
},
.{
.llvm_name = "a65",
.flatten = true,
},
.{
.llvm_name = "a72",
.flatten = true,
},
.{
.llvm_name = "a73",
.flatten = true,
},
.{
.llvm_name = "a75",
.flatten = true,
},
.{
.llvm_name = "a76",
.flatten = true,
},
.{
.llvm_name = "a77",
.flatten = true,
},
.{
.llvm_name = "a78",
.flatten = true,
},
.{
.llvm_name = "a78ae",
.flatten = true,
},
.{
.llvm_name = "a78c",
.flatten = true,
},
.{
.llvm_name = "a710",
.flatten = true,
},
.{
.llvm_name = "a715",
.flatten = true,
},
.{
.llvm_name = "a720",
.flatten = true,
},
.{
.llvm_name = "a720ae",
.flatten = true,
},
.{
.llvm_name = "ampere1a",
.flatten = true,
},
.{
.llvm_name = "apple-a7",
.flatten = true,
},
.{
.llvm_name = "apple-a10",
.flatten = true,
},
.{
.llvm_name = "apple-a11",
.flatten = true,
},
.{
.llvm_name = "apple-a12",
.flatten = true,
},
.{
.llvm_name = "apple-a13",
.flatten = true,
},
.{
.llvm_name = "apple-a14",
.flatten = true,
},
.{
.llvm_name = "apple-a15",
.flatten = true,
},
.{
.llvm_name = "apple-a16",
.flatten = true,
},
.{
.llvm_name = "apple-a17",
.flatten = true,
},
.{
.llvm_name = "apple-a7-sysreg",
.flatten = true,
},
.{
.llvm_name = "apple-m4",
.flatten = true,
},
.{
.llvm_name = "carmel",
.flatten = true,
},
.{
.llvm_name = "cortex-a725",
.flatten = true,
},
.{
.llvm_name = "cortex-a78",
.flatten = true,
},
.{
.llvm_name = "cortex-r82",
.flatten = true,
},
.{
.llvm_name = "cortex-r82ae",
.flatten = true,
},
.{
.llvm_name = "cortex-x1",
.flatten = true,
},
.{
.llvm_name = "cortex-x2",
.flatten = true,
},
.{
.llvm_name = "cortex-x3",
.flatten = true,
},
.{
.llvm_name = "cortex-x4",
.flatten = true,
},
.{
.llvm_name = "cortex-x925",
.flatten = true,
},
.{
.llvm_name = "falkor",
.flatten = true,
},
.{
.llvm_name = "kryo",
.flatten = true,
},
.{
.llvm_name = "saphira",
.flatten = true,
},
.{
.llvm_name = "thunderx",
.flatten = true,
},
.{
.llvm_name = "thunderx2t99",
.flatten = true,
},
.{
.llvm_name = "thunderx3t110",
.flatten = true,
},
.{
.llvm_name = "thunderxt81",
.flatten = true,
},
.{
.llvm_name = "thunderxt83",
.flatten = true,
},
.{
.llvm_name = "thunderxt88",
.flatten = true,
},
.{
.llvm_name = "tsv110",
.flatten = true,
},
.{
.llvm_name = "ampere1",
.flatten = true,
},
.{
.llvm_name = "ampere1b",
.flatten = true,
},
},
.extra_cpus = &.{
.{
.llvm_name = null,
.zig_name = "exynos_m1",
.features = &.{
"crc",
"crypto",
"exynos_cheap_as_move",
"force_32bit_jump_tables",
"fuse_aes",
"perfmon",
"slow_misaligned_128store",
"slow_paired_128",
"use_postra_scheduler",
"use_reciprocal_square_root",
"v8a",
},
},
.{
.llvm_name = null,
.zig_name = "exynos_m2",
.features = &.{
"crc",
"crypto",
"exynos_cheap_as_move",
"force_32bit_jump_tables",
"fuse_aes",
"perfmon",
"slow_misaligned_128store",
"slow_paired_128",
"use_postra_scheduler",
"v8a",
},
},
.{
.llvm_name = null,
.zig_name = "xgene1",
.features = &.{
"perfmon",
"v8a",
},
},
.{
.llvm_name = null,
.zig_name = "emag",
.features = &.{
"crc",
"crypto",
"perfmon",
"v8a",
},
},
},
.omit_cpus = &.{
// Who thought this alias was a good idea? Upgrade your compiler and suddenly your
// programs SIGILL because this changed meaning. Brilliant.
"apple-latest",
},
},
.{
.zig_name = "amdgpu",
.llvm_name = "AMDGPU",
.td_name = "AMDGPU.td",
.feature_overrides = &.{
.{
.llvm_name = "DumpCode",
.omit = true,
},
.{
.llvm_name = "dumpcode",
.omit = true,
},
.{
.llvm_name = "enable-ds128",
.zig_name = "ds128",
},
.{
.llvm_name = "enable-flat-scratch",
.zig_name = "flat_scratch",
},
.{
.llvm_name = "enable-prt-strict-null",
.zig_name = "prt_strict_null",
},
},
},
.{
.zig_name = "arc",
.llvm_name = "ARC",
.td_name = "ARC.td",
},
.{
.zig_name = "arm",
.llvm_name = "ARM",
.td_name = "ARM.td",
.branch_quota = 10000,
.extra_cpus = &.{
.{
.llvm_name = "generic",
.zig_name = "baseline",
.features = &.{"v7a"},
},
.{
.llvm_name = null,
.zig_name = "exynos_m1",
.features = &.{ "v8a", "exynos" },
},
.{
.llvm_name = null,
.zig_name = "exynos_m2",
.features = &.{ "v8a", "exynos" },
},
},
.feature_overrides = &.{
.{
.llvm_name = "exynos",
.flatten = true,
},
.{
.llvm_name = "cortex-a78",
.flatten = true,
},
.{
.llvm_name = "cortex-a78ae",
.flatten = true,
},
.{
.llvm_name = "cortex-a710",
.flatten = true,
},
.{
.llvm_name = "cortex-m4",
.omit_deps = &.{"vfp4d16sp"},
},
.{
.llvm_name = "cortex-m7",
.omit_deps = &.{"fp_armv8d16"},
},
.{
.llvm_name = "cortex-m33",
.omit_deps = &.{ "fp_armv8d16sp", "dsp" },
},
.{
.llvm_name = "cortex-m35p",
.omit_deps = &.{ "fp_armv8d16sp", "dsp" },
},
.{
.llvm_name = "cortex-m55",
.omit_deps = &.{ "mve_fp", "fp_armv8d16" },
},
.{
.llvm_name = "cortex-m85",
.omit_deps = &.{ "mve_fp", "pacbti", "fp_armv8d16" },
},
.{
.llvm_name = "cortex-x1c",
.flatten = true,
},
.{
.llvm_name = "r4",
.flatten = true,
},
.{
.llvm_name = "r52plus",
.flatten = true,
},
.{
.llvm_name = "r5",
.flatten = true,
},
.{
.llvm_name = "r52",
.flatten = true,
},
.{
.llvm_name = "r7",
.flatten = true,
},
.{
.llvm_name = "m3",
.flatten = true,
},
.{
.llvm_name = "m7",
.flatten = true,
},
.{
.llvm_name = "krait",
.flatten = true,
},
.{
.llvm_name = "kryo",
.flatten = true,
},
.{
.llvm_name = "swift",
.flatten = true,
},
.{
.llvm_name = "cortex-x1",
.flatten = true,
},
.{
.llvm_name = "neoverse-v1",
.flatten = true,
},
.{
.llvm_name = "a5",
.flatten = true,
},
.{
.llvm_name = "a7",
.flatten = true,
},
.{
.llvm_name = "a8",
.flatten = true,
},
.{
.llvm_name = "a9",
.flatten = true,
},
.{
.llvm_name = "a12",
.flatten = true,
},
.{
.llvm_name = "a15",
.flatten = true,
},
.{
.llvm_name = "a17",
.flatten = true,
},
.{
.llvm_name = "a32",
.flatten = true,
},
.{
.llvm_name = "a35",
.flatten = true,
},
.{
.llvm_name = "a53",
.flatten = true,
},
.{
.llvm_name = "a55",
.flatten = true,
},
.{
.llvm_name = "a57",
.flatten = true,
},
.{
.llvm_name = "a72",
.flatten = true,
},
.{
.llvm_name = "a73",
.flatten = true,
},
.{
.llvm_name = "a75",
.flatten = true,
},
.{
.llvm_name = "a76",
.flatten = true,
},
.{
.llvm_name = "a77",
.flatten = true,
},
.{
.llvm_name = "a78c",
.flatten = true,
},
.{
.llvm_name = "armv2",
.zig_name = "v2",
.extra_deps = &.{"strict_align"},
},
.{
.llvm_name = "armv2a",
.zig_name = "v2a",
.extra_deps = &.{"strict_align"},
},
.{
.llvm_name = "armv3",
.zig_name = "v3",
.extra_deps = &.{"strict_align"},
},
.{
.llvm_name = "armv3m",
.zig_name = "v3m",
.extra_deps = &.{"strict_align"},
},
.{
.llvm_name = "armv4",
.zig_name = "v4",
.extra_deps = &.{"strict_align"},
},
.{
.llvm_name = "armv4t",
.zig_name = "v4t",
.extra_deps = &.{"strict_align"},
},
.{
.llvm_name = "armv5t",
.zig_name = "v5t",
.extra_deps = &.{"strict_align"},
},
.{
.llvm_name = "armv5te",
.zig_name = "v5te",
.extra_deps = &.{"strict_align"},
},
.{
.llvm_name = "armv5tej",
.zig_name = "v5tej",
.extra_deps = &.{"strict_align"},
},
.{
.llvm_name = "armv6",
.zig_name = "v6",
},
.{
.llvm_name = "armv6-m",
.zig_name = "v6m",
},
.{
.llvm_name = "armv6j",
.zig_name = "v6j",
},
.{
.llvm_name = "armv6k",
.zig_name = "v6k",
},
.{
.llvm_name = "armv6kz",
.zig_name = "v6kz",
},
.{
.llvm_name = "armv6s-m",
.zig_name = "v6sm",
},
.{
.llvm_name = "armv6t2",
.zig_name = "v6t2",
},
.{
.llvm_name = "armv7-a",
.zig_name = "v7a",
},
.{
.llvm_name = "armv7-m",
.zig_name = "v7m",
},
.{
.llvm_name = "armv7-r",
.zig_name = "v7r",
},
.{
.llvm_name = "armv7e-m",
.zig_name = "v7em",
},
.{
.llvm_name = "armv7k",
.omit = true,
},
.{
.llvm_name = "armv7s",
.omit = true,
},
.{
.llvm_name = "armv7ve",
.zig_name = "v7ve",
},
.{
.llvm_name = "armv8.1-a",
.zig_name = "v8_1a",
},
.{
.llvm_name = "armv8.1-m.main",
.zig_name = "v8_1m_main",
},
.{
.llvm_name = "armv8.2-a",
.zig_name = "v8_2a",
},
.{
.llvm_name = "armv8.3-a",
.zig_name = "v8_3a",
},
.{
.llvm_name = "armv8.4-a",
.zig_name = "v8_4a",
},
.{
.llvm_name = "armv8.5-a",
.zig_name = "v8_5a",
},
.{
.llvm_name = "armv8.6-a",
.zig_name = "v8_6a",
},
.{
.llvm_name = "armv8.7-a",
.zig_name = "v8_7a",
},
.{
.llvm_name = "armv8.8-a",
.zig_name = "v8_8a",
},
.{
.llvm_name = "armv8.9-a",
.zig_name = "v8_9a",
},
.{
.llvm_name = "armv8-a",
.zig_name = "v8a",
},
.{
.llvm_name = "armv8-m.base",
.zig_name = "v8m",
},
.{
.llvm_name = "armv8-m.main",
.zig_name = "v8m_main",
},
.{
.llvm_name = "armv8-r",
.zig_name = "v8r",
},
.{
.llvm_name = "armv9.1-a",
.zig_name = "v9_1a",
},
.{
.llvm_name = "armv9.2-a",
.zig_name = "v9_2a",
},
.{
.llvm_name = "armv9.3-a",
.zig_name = "v9_3a",
},
.{
.llvm_name = "armv9.4-a",
.zig_name = "v9_4a",
},
.{
.llvm_name = "armv9.5-a",
.zig_name = "v9_5a",
},
.{
.llvm_name = "armv9-a",
.zig_name = "v9a",
},
.{
.llvm_name = "v4t",
.zig_name = "has_v4t",
},
.{
.llvm_name = "v5t",
.zig_name = "has_v5t",
},
.{
.llvm_name = "v5te",
.zig_name = "has_v5te",
},
.{
.llvm_name = "v6",
.zig_name = "has_v6",
},
.{
.llvm_name = "v6k",
.zig_name = "has_v6k",
},
.{
.llvm_name = "v6m",
.zig_name = "has_v6m",
},
.{
.llvm_name = "v6t2",
.zig_name = "has_v6t2",
},
.{
.llvm_name = "v7",
.zig_name = "has_v7",
},
.{
.llvm_name = "v7clrex",
.zig_name = "has_v7clrex",
},
.{
.llvm_name = "v8",
.zig_name = "has_v8",
},
.{
.llvm_name = "v8m",
.zig_name = "has_v8m",
},
.{
.llvm_name = "v8m.main",
.zig_name = "has_v8m_main",
},
.{
.llvm_name = "v8.1a",
.zig_name = "has_v8_1a",
},
.{
.llvm_name = "v8.1m.main",
.zig_name = "has_v8_1m_main",
},
.{
.llvm_name = "v8.2a",
.zig_name = "has_v8_2a",
},
.{
.llvm_name = "v8.3a",
.zig_name = "has_v8_3a",
},
.{
.llvm_name = "v8.4a",
.zig_name = "has_v8_4a",
},
.{
.llvm_name = "v8.5a",
.zig_name = "has_v8_5a",
},
.{
.llvm_name = "v8.6a",
.zig_name = "has_v8_6a",
},
.{
.llvm_name = "v8.7a",
.zig_name = "has_v8_7a",
},
.{
.llvm_name = "v8.8a",
.zig_name = "has_v8_8a",
},
.{
.llvm_name = "v8.9a",
.zig_name = "has_v8_9a",
},
.{
.llvm_name = "v9a",
.zig_name = "has_v9a",
},
.{
.llvm_name = "v9.1a",
.zig_name = "has_v9_1a",
},
.{
.llvm_name = "v9.2a",
.zig_name = "has_v9_2a",
},
.{
.llvm_name = "v9.3a",
.zig_name = "has_v9_3a",
},
.{
.llvm_name = "v9.4a",
.zig_name = "has_v9_4a",
},
.{
.llvm_name = "v9.5a",
.zig_name = "has_v9_5a",
},
},
// LLVM removed support for v2 and v3 but zig wants to support targeting old hardware
.extra_features = &.{
.{
.zig_name = "v2",
.desc = "ARMv2 architecture",
.deps = &.{"strict_align"},
},
.{
.zig_name = "v2a",
.desc = "ARMv2a architecture",
.deps = &.{"strict_align"},
},
.{
.zig_name = "v3",
.desc = "ARMv3 architecture",
.deps = &.{"strict_align"},
},
.{
.zig_name = "v3m",
.desc = "ARMv3m architecture",
.deps = &.{"strict_align"},
},
},
},
.{
.zig_name = "avr",
.llvm_name = "AVR",
.td_name = "AVR.td",
},
.{
.zig_name = "bpf",
.llvm_name = "BPF",
.td_name = "BPF.td",
},
.{
.zig_name = "csky",
.llvm_name = "CSKY",
.td_name = "CSKY.td",
},
.{
.zig_name = "hexagon",
.llvm_name = "Hexagon",
.td_name = "Hexagon.td",
},
.{
.zig_name = "lanai",
.llvm_name = "Lanai",
.td_name = "Lanai.td",
},
.{
.zig_name = "loongarch",
.llvm_name = "LoongArch",
.td_name = "LoongArch.td",
},
.{
.zig_name = "m68k",
.llvm_name = "M68k",
.td_name = "M68k.td",
},
.{
.zig_name = "msp430",
.llvm_name = "MSP430",
.td_name = "MSP430.td",
},
.{
.zig_name = "mips",
.llvm_name = "Mips",
.td_name = "Mips.td",
},
.{
.zig_name = "nvptx",
.llvm_name = "NVPTX",
.td_name = "NVPTX.td",
},
.{
.zig_name = "powerpc",
.llvm_name = "PowerPC",
.td_name = "PPC.td",
.omit_cpus = &.{
"ppc32",
},
},
.{
.zig_name = "riscv",
.llvm_name = "RISCV",
.td_name = "RISCV.td",
.branch_quota = 2000,
.feature_overrides = &.{
.{
.llvm_name = "sifive7",
.flatten = true,
},
},
.extra_cpus = &.{
.{
.llvm_name = null,
.zig_name = "baseline_rv32",
.features = &.{ "32bit", "a", "c", "d", "f", "i", "m" },
},
.{
.llvm_name = null,
.zig_name = "baseline_rv64",
.features = &.{ "64bit", "a", "c", "d", "f", "i", "m" },
},
},
},
.{
.zig_name = "sparc",
.llvm_name = "Sparc",
.td_name = "Sparc.td",
},
// TODO: merge tools/update_spirv_features.zig into this script
//.{
// .zig_name = "spirv",
// .llvm_name = "SPIRV",
// .td_name = "SPIRV.td",
//},
.{
.zig_name = "s390x",
.llvm_name = "SystemZ",
.td_name = "SystemZ.td",
},
.{
.zig_name = "ve",
.llvm_name = "VE",
.td_name = "VE.td",
},
.{
.zig_name = "wasm",
.llvm_name = "WebAssembly",
.td_name = "WebAssembly.td",
},
.{
.zig_name = "x86",
.llvm_name = "X86",
.td_name = "X86.td",
.feature_overrides = &.{
.{
.llvm_name = "64bit-mode",
.omit = true,
},
.{
.llvm_name = "amdfam10",
.extra_deps = &.{"3dnowa"},
},
.{
.llvm_name = "athlon",
.extra_deps = &.{"3dnowa"},
},
.{
.llvm_name = "athlon64",
.extra_deps = &.{"3dnowa"},
},
.{
.llvm_name = "athlon64-sse3",
.extra_deps = &.{"3dnowa"},
},
.{
.llvm_name = "athlon-4",
.extra_deps = &.{"3dnowa"},
},
.{
.llvm_name = "athlon-fx",
.extra_deps = &.{"3dnowa"},
},
.{
.llvm_name = "athlon-mp",
.extra_deps = &.{"3dnowa"},
},
.{
.llvm_name = "athlon-tbird",
.extra_deps = &.{"3dnowa"},
},
.{
.llvm_name = "athlon-xp",
.extra_deps = &.{"3dnowa"},
},
.{
.llvm_name = "barcelona",
.extra_deps = &.{"3dnowa"},
},
.{
.llvm_name = "c3",
.extra_deps = &.{"3dnow"},
},
.{
.llvm_name = "geode",
.extra_deps = &.{"3dnowa"},
},
.{
.llvm_name = "k6-2",
.extra_deps = &.{"3dnow"},
},
.{
.llvm_name = "k6-3",
.extra_deps = &.{"3dnow"},
},
.{
.llvm_name = "k8",
.extra_deps = &.{"3dnowa"},
},
.{
.llvm_name = "k8-sse3",
.extra_deps = &.{"3dnowa"},
},
.{
.llvm_name = "knl",
.extra_deps = &.{
"avx512er",
"avx512pf",
"prefetchwt1",
},
},
.{
.llvm_name = "knm",
.extra_deps = &.{
"avx512er",
"avx512pf",
"prefetchwt1",
},
},
.{
.llvm_name = "lakemont",
.extra_deps = &.{"soft_float"},
},
.{
.llvm_name = "opteron",
.extra_deps = &.{"3dnowa"},
},
.{
.llvm_name = "opteron-sse3",
.extra_deps = &.{"3dnowa"},
},
.{
.llvm_name = "winchip2",
.extra_deps = &.{"3dnow"},
},
},
// Features removed from LLVM
.extra_features = &.{
.{
.zig_name = "3dnow",
.desc = "Enable 3DNow! instructions",
.deps = &.{"mmx"},
},
.{
.zig_name = "3dnowa",
.desc = "Enable 3DNow! Athlon instructions",
.deps = &.{"3dnow"},
},
.{
.zig_name = "avx512er",
.desc = "Enable AVX-512 Exponential and Reciprocal Instructions",
.deps = &.{"avx512f"},
},
.{
.zig_name = "avx512pf",
.desc = "Enable AVX-512 PreFetch Instructions",
.deps = &.{"avx512f"},
},
.{
.zig_name = "prefetchwt1",
.desc = "Prefetch with Intent to Write and T1 Hint",
.deps = &.{},
},
},
.omit_cpus = &.{
// LLVM defines a bunch of dumb aliases with foreach loops in X86.td.
"pentium_mmx",
"pentium_pro",
"pentium_ii",
"pentium_3m",
"pentium_iii_no_xmm_regs",
"pentium_iii",
"pentium_m",
"pentium4m",
"pentium_4",
"pentium_4_sse3",
"core_2_duo_ssse3",
"core_2_duo_sse4_1",
"atom_sse4_2",
"goldmont_plus",
"core_i7_sse4_2",
"core_aes_pclmulqdq",
"corei7-avx",
"core_2nd_gen_avx",
"core-avx-i",
"core_3rd_gen_avx",
"core-avx2",
"core_4th_gen_avx",
"core_4th_gen_avx_tsx",
"core_5th_gen_avx",
"core_5th_gen_avx_tsx",
"mic_avx512",
"skylake_avx512",
"icelake_client",
"icelake_server",
"graniterapids_d",
"arrowlake_s",
},
},
.{
.zig_name = "xcore",
.llvm_name = "XCore",
.td_name = "XCore.td",
},
.{
.zig_name = "xtensa",
.llvm_name = "Xtensa",
.td_name = "Xtensa.td",
},
};
pub fn main() anyerror!void {
var arena_state = std.heap.ArenaAllocator.init(std.heap.page_allocator);
defer arena_state.deinit();
const arena = arena_state.allocator();
const args = try std.process.argsAlloc(arena);
if (args.len <= 1) {
usageAndExit(std.io.getStdErr(), args[0], 1);
}
if (std.mem.eql(u8, args[1], "--help")) {
usageAndExit(std.io.getStdOut(), args[0], 0);
}
if (args.len < 4) {
usageAndExit(std.io.getStdErr(), args[0], 1);
}
const llvm_tblgen_exe = args[1];
if (std.mem.startsWith(u8, llvm_tblgen_exe, "-")) {
usageAndExit(std.io.getStdErr(), args[0], 1);
}
const llvm_src_root = args[2];
if (std.mem.startsWith(u8, llvm_src_root, "-")) {
usageAndExit(std.io.getStdErr(), args[0], 1);
}
const zig_src_root = args[3];
if (std.mem.startsWith(u8, zig_src_root, "-")) {
usageAndExit(std.io.getStdErr(), args[0], 1);
}
var zig_src_dir = try fs.cwd().openDir(zig_src_root, .{});
defer zig_src_dir.close();
const root_progress = std.Progress.start(.{ .estimated_total_items = llvm_targets.len });
defer root_progress.end();
if (builtin.single_threaded) {
for (llvm_targets) |llvm_target| {
try processOneTarget(Job{
.llvm_tblgen_exe = llvm_tblgen_exe,
.llvm_src_root = llvm_src_root,
.zig_src_dir = zig_src_dir,
.root_progress = root_progress,
.llvm_target = llvm_target,
});
}
} else {
var threads = try arena.alloc(std.Thread, llvm_targets.len);
for (llvm_targets, 0..) |llvm_target, i| {
const job = Job{
.llvm_tblgen_exe = llvm_tblgen_exe,
.llvm_src_root = llvm_src_root,
.zig_src_dir = zig_src_dir,
.root_progress = root_progress,
.llvm_target = llvm_target,
};
threads[i] = try std.Thread.spawn(.{}, processOneTarget, .{job});
}
for (threads) |thread| {
thread.join();
}
}
}
const Job = struct {
llvm_tblgen_exe: []const u8,
llvm_src_root: []const u8,
zig_src_dir: std.fs.Dir,
root_progress: std.Progress.Node,
llvm_target: LlvmTarget,
};
fn processOneTarget(job: Job) anyerror!void {
const llvm_target = job.llvm_target;
var arena_state = std.heap.ArenaAllocator.init(std.heap.page_allocator);
defer arena_state.deinit();
const arena = arena_state.allocator();
const progress_node = job.root_progress.start(llvm_target.zig_name, 3);
defer progress_node.end();
const tblgen_progress = progress_node.start("invoke llvm-tblgen", 0);
const child_args = [_][]const u8{
job.llvm_tblgen_exe,
"--dump-json",
try std.fmt.allocPrint(arena, "{s}/llvm/lib/Target/{s}/{s}", .{
job.llvm_src_root,
llvm_target.llvm_name,
llvm_target.td_name,
}),
try std.fmt.allocPrint(arena, "-I={s}/llvm/include", .{job.llvm_src_root}),
try std.fmt.allocPrint(arena, "-I={s}/llvm/lib/Target/{s}", .{
job.llvm_src_root, llvm_target.llvm_name,
}),
};
const child_result = try std.process.Child.run(.{
.allocator = arena,
.argv = &child_args,
.max_output_bytes = 500 * 1024 * 1024,
});
tblgen_progress.end();
if (child_result.stderr.len != 0) {
std.debug.print("{s}\n", .{child_result.stderr});
}
const json_text = switch (child_result.term) {
.Exited => |code| if (code == 0) child_result.stdout else {
std.debug.print("llvm-tblgen exited with code {d}\n", .{code});
std.process.exit(1);
},
else => {
std.debug.print("llvm-tblgen crashed\n", .{});
std.process.exit(1);
},
};
const json_parse_progress = progress_node.start("parse JSON", 0);
const parsed = try json.parseFromSlice(json.Value, arena, json_text, .{});
defer parsed.deinit();
const root_map = &parsed.value.object;
json_parse_progress.end();
const render_progress = progress_node.start("render zig code", 0);
// So far LLVM has only had a few aliases for the same CPU.
var cpu_aliases = std.StringHashMap(std.SegmentedList(struct {
llvm: []const u8,
zig: []const u8,
}, 4)).init(arena);
{
var it = root_map.iterator();
while (it.next()) |kv| {
if (kv.key_ptr.len == 0) continue;
if (kv.key_ptr.*[0] == '!') continue;
if (kv.value_ptr.* != .object) continue;
if (hasSuperclass(&kv.value_ptr.object, "ProcessorAlias")) {
// Note that `Name` is actually the alias, while `Alias` is the name that will have
// a full `Processor` object defined.
const llvm_alias = kv.value_ptr.object.get("Name").?.string;
const llvm_name = kv.value_ptr.object.get("Alias").?.string;
const gop = try cpu_aliases.getOrPut(try llvmNameToZigName(arena, llvm_name));
if (!gop.found_existing) gop.value_ptr.* = .{};
try gop.value_ptr.append(arena, .{
.llvm = llvm_alias,
.zig = try llvmNameToZigName(arena, llvm_alias),
});
}
}
}
var features_table = std.StringHashMap(Feature).init(arena);
var all_features = std.ArrayList(Feature).init(arena);
var all_cpus = std.ArrayList(Cpu).init(arena);
{
var it = root_map.iterator();
while (it.next()) |kv| {
if (kv.key_ptr.len == 0) continue;
if (kv.key_ptr.*[0] == '!') continue;
if (kv.value_ptr.* != .object) continue;
if (hasSuperclass(&kv.value_ptr.object, "SubtargetFeature")) {
const llvm_name = kv.value_ptr.object.get("Name").?.string;
if (llvm_name.len == 0) continue;
var zig_name = try llvmNameToZigName(arena, llvm_name);
var desc = kv.value_ptr.object.get("Desc").?.string;
var deps = std.ArrayList([]const u8).init(arena);
var omit = false;
var flatten = false;
var omit_deps: []const []const u8 = &.{};
var extra_deps: []const []const u8 = &.{};
for (llvm_target.feature_overrides) |feature_override| {
if (mem.eql(u8, llvm_name, feature_override.llvm_name)) {
if (feature_override.omit) {
// Still put the feature into the table so that we can
// expand dependencies for the feature overrides marked `flatten`.
omit = true;
}
if (feature_override.flatten) {
flatten = true;
}
if (feature_override.zig_name) |override_name| {
zig_name = override_name;
}
if (feature_override.desc) |override_desc| {
desc = override_desc;
}
omit_deps = feature_override.omit_deps;
extra_deps = feature_override.extra_deps;
break;
}
}
const implies = kv.value_ptr.object.get("Implies").?.array;
for (implies.items) |imply| {
const other_key = imply.object.get("def").?.string;
const other_obj = &root_map.getPtr(other_key).?.object;
const other_llvm_name = other_obj.get("Name").?.string;
const other_zig_name = (try llvmFeatureNameToZigNameOmit(
arena,
llvm_target,
other_llvm_name,
)) orelse continue;
for (omit_deps) |omit_dep| {
if (mem.eql(u8, other_zig_name, omit_dep)) break;
} else {
try deps.append(other_zig_name);
}
}
// This is used by AArch64.
if (kv.value_ptr.object.get("DefaultExts")) |exts_val| {
for (exts_val.array.items) |ext| {
const other_key = ext.object.get("def").?.string;
const other_obj = &root_map.getPtr(other_key).?.object;
const other_llvm_name = other_obj.get("Name").?.string;
const other_zig_name = (try llvmFeatureNameToZigNameOmit(
arena,
llvm_target,
other_llvm_name,
)) orelse continue;
for (omit_deps) |omit_dep| {
if (mem.eql(u8, other_zig_name, omit_dep)) break;
} else {
try deps.append(other_zig_name);
}
}
}
for (extra_deps) |extra_dep| {
try deps.append(extra_dep);
}
const feature: Feature = .{
.llvm_name = llvm_name,
.zig_name = zig_name,
.desc = desc,
.deps = deps.items,
.flatten = flatten,
};
try features_table.put(zig_name, feature);
if (!omit and !flatten) {
try all_features.append(feature);
}
}
if (hasSuperclass(&kv.value_ptr.object, "Processor")) {
const llvm_name = kv.value_ptr.object.get("Name").?.string;
if (llvm_name.len == 0) continue;
const omitted = for (llvm_target.omit_cpus) |omit_cpu_name| {
if (mem.eql(u8, omit_cpu_name, llvm_name)) break true;
} else false;
if (omitted) continue;
var zig_name = try llvmNameToZigName(arena, llvm_name);
var deps = std.ArrayList([]const u8).init(arena);
var omit_deps: []const []const u8 = &.{};
var extra_deps: []const []const u8 = &.{};
for (llvm_target.feature_overrides) |feature_override| {
if (mem.eql(u8, llvm_name, feature_override.llvm_name)) {
if (feature_override.omit) {
continue;
}
if (feature_override.zig_name) |override_name| {
zig_name = override_name;
}
omit_deps = feature_override.omit_deps;
extra_deps = feature_override.extra_deps;
break;
}
}
const features = kv.value_ptr.object.get("Features").?.array;
for (features.items) |feature| {
const feature_key = feature.object.get("def").?.string;
const feature_obj = &root_map.getPtr(feature_key).?.object;
const feature_llvm_name = feature_obj.get("Name").?.string;
if (feature_llvm_name.len == 0) continue;
const feature_zig_name = (try llvmFeatureNameToZigNameOmit(
arena,
llvm_target,
feature_llvm_name,
)) orelse continue;
for (omit_deps) |omit_dep| {
if (mem.eql(u8, feature_zig_name, omit_dep)) break;
} else {
try deps.append(feature_zig_name);
}
}
for (extra_deps) |extra_dep| {
try deps.append(extra_dep);
}
const tune_features = kv.value_ptr.object.get("TuneFeatures").?.array;
for (tune_features.items) |feature| {
const feature_key = feature.object.get("def").?.string;
const feature_obj = &root_map.getPtr(feature_key).?.object;
const feature_llvm_name = feature_obj.get("Name").?.string;
if (feature_llvm_name.len == 0) continue;
const feature_zig_name = (try llvmFeatureNameToZigNameOmit(
arena,
llvm_target,
feature_llvm_name,
)) orelse continue;
try deps.append(feature_zig_name);
}
for (llvm_target.feature_overrides) |feature_override| {
if (mem.eql(u8, llvm_name, feature_override.llvm_name)) {
if (feature_override.omit) {
continue;
}
if (feature_override.zig_name) |override_name| {
zig_name = override_name;
}
for (feature_override.extra_deps) |extra_dep| {
try deps.append(extra_dep);
}
break;
}
}
try all_cpus.append(.{
.llvm_name = llvm_name,
.zig_name = zig_name,
.features = deps.items,
});
if (cpu_aliases.get(zig_name)) |aliases| {
var alias_it = aliases.constIterator(0);
alias_it: while (alias_it.next()) |alias| {
for (llvm_target.omit_cpus) |omit_cpu_name| {
if (mem.eql(u8, omit_cpu_name, alias.llvm)) continue :alias_it;
}
try all_cpus.append(.{
.llvm_name = alias.llvm,
.zig_name = alias.zig,
.features = deps.items,
});
}
}
}
}
}
for (llvm_target.extra_features) |extra_feature| {
try features_table.put(extra_feature.zig_name, extra_feature);
try all_features.append(extra_feature);
}
for (llvm_target.extra_cpus) |extra_cpu| {
try all_cpus.append(extra_cpu);
}
mem.sort(Feature, all_features.items, {}, featureLessThan);
mem.sort(Cpu, all_cpus.items, {}, cpuLessThan);
const target_sub_path = try fs.path.join(arena, &.{ "lib", "std", "Target" });
var target_dir = try job.zig_src_dir.makeOpenPath(target_sub_path, .{});
defer target_dir.close();
const zig_code_basename = try std.fmt.allocPrint(arena, "{s}.zig", .{llvm_target.zig_name});
var zig_code_file = try target_dir.createFile(zig_code_basename, .{});
defer zig_code_file.close();
var bw = std.io.bufferedWriter(zig_code_file.writer());
const w = bw.writer();
try w.writeAll(
\\//! This file is auto-generated by tools/update_cpu_features.zig.
\\
\\const std = @import("../std.zig");
\\const CpuFeature = std.Target.Cpu.Feature;
\\const CpuModel = std.Target.Cpu.Model;
\\
\\pub const Feature = enum {
);
for (all_features.items, 0..) |feature, i| {
try w.print("\n {p},", .{std.zig.fmtId(feature.zig_name)});
if (i == all_features.items.len - 1) try w.writeAll("\n");
}
try w.writeAll(
\\};
\\
\\pub const featureSet = CpuFeature.FeatureSetFns(Feature).featureSet;
\\pub const featureSetHas = CpuFeature.FeatureSetFns(Feature).featureSetHas;
\\pub const featureSetHasAny = CpuFeature.FeatureSetFns(Feature).featureSetHasAny;
\\pub const featureSetHasAll = CpuFeature.FeatureSetFns(Feature).featureSetHasAll;
\\
\\pub const all_features = blk: {
\\
);
if (llvm_target.branch_quota) |branch_quota| {
try w.print(" @setEvalBranchQuota({d});\n", .{branch_quota});
}
try w.writeAll(
\\ const len = @typeInfo(Feature).@"enum".fields.len;
\\ std.debug.assert(len <= CpuFeature.Set.needed_bit_count);
\\ var result: [len]CpuFeature = undefined;
\\
);
for (all_features.items) |feature| {
if (feature.llvm_name) |llvm_name| {
try w.print(
\\ result[@intFromEnum(Feature.{p_})] = .{{
\\ .llvm_name = "{}",
\\ .description = "{}",
\\ .dependencies = featureSet(&[_]Feature{{
,
.{
std.zig.fmtId(feature.zig_name),
std.zig.fmtEscapes(llvm_name),
std.zig.fmtEscapes(feature.desc),
},
);
} else {
try w.print(
\\ result[@intFromEnum(Feature.{p_})] = .{{
\\ .llvm_name = null,
\\ .description = "{}",
\\ .dependencies = featureSet(&[_]Feature{{
,
.{
std.zig.fmtId(feature.zig_name),
std.zig.fmtEscapes(feature.desc),
},
);
}
var deps_set = std.StringHashMap(void).init(arena);
for (feature.deps) |dep| {
try putDep(&deps_set, features_table, dep);
}
try pruneFeatures(arena, features_table, &deps_set);
var dependencies = std.ArrayList([]const u8).init(arena);
{
var it = deps_set.keyIterator();
while (it.next()) |key| {
try dependencies.append(key.*);
}
}
mem.sort([]const u8, dependencies.items, {}, asciiLessThan);
if (dependencies.items.len == 0) {
try w.writeAll(
\\}),
\\ };
\\
);
} else {
try w.writeAll("\n");
for (dependencies.items) |dep| {
try w.print(" .{p_},\n", .{std.zig.fmtId(dep)});
}
try w.writeAll(
\\ }),
\\ };
\\
);
}
}
try w.writeAll(
\\ const ti = @typeInfo(Feature);
\\ for (&result, 0..) |*elem, i| {
\\ elem.index = i;
\\ elem.name = ti.@"enum".fields[i].name;
\\ }
\\ break :blk result;
\\};
\\
\\pub const cpu = struct {
\\
);
for (all_cpus.items) |cpu| {
var deps_set = std.StringHashMap(void).init(arena);
for (cpu.features) |feature_zig_name| {
try putDep(&deps_set, features_table, feature_zig_name);
}
try pruneFeatures(arena, features_table, &deps_set);
var cpu_features = std.ArrayList([]const u8).init(arena);
{
var it = deps_set.keyIterator();
while (it.next()) |key| {
try cpu_features.append(key.*);
}
}
mem.sort([]const u8, cpu_features.items, {}, asciiLessThan);
if (cpu.llvm_name) |llvm_name| {
try w.print(
\\ pub const {} = CpuModel{{
\\ .name = "{}",
\\ .llvm_name = "{}",
\\ .features = featureSet(&[_]Feature{{
, .{
std.zig.fmtId(cpu.zig_name),
std.zig.fmtEscapes(cpu.zig_name),
std.zig.fmtEscapes(llvm_name),
});
} else {
try w.print(
\\ pub const {} = CpuModel{{
\\ .name = "{}",
\\ .llvm_name = null,
\\ .features = featureSet(&[_]Feature{{
, .{
std.zig.fmtId(cpu.zig_name),
std.zig.fmtEscapes(cpu.zig_name),
});
}
if (cpu_features.items.len == 0) {
try w.writeAll(
\\}),
\\ };
\\
);
} else {
try w.writeAll("\n");
for (cpu_features.items) |feature_zig_name| {
try w.print(" .{p_},\n", .{std.zig.fmtId(feature_zig_name)});
}
try w.writeAll(
\\ }),
\\ };
\\
);
}
}
try w.writeAll(
\\};
\\
);
try bw.flush();
render_progress.end();
}
fn usageAndExit(file: fs.File, arg0: []const u8, code: u8) noreturn {
file.writer().print(
\\Usage: {s} /path/to/llvm-tblgen /path/git/llvm-project /path/git/zig
\\
\\Updates lib/std/target/<target>.zig from llvm/lib/Target/<Target>/<Target>.td .
\\
\\On a less beefy system, or when debugging, compile with -fsingle-threaded.
\\
, .{arg0}) catch std.process.exit(1);
std.process.exit(code);
}
fn featureLessThan(context: void, a: Feature, b: Feature) bool {
_ = context;
return std.ascii.lessThanIgnoreCase(a.zig_name, b.zig_name);
}
fn cpuLessThan(context: void, a: Cpu, b: Cpu) bool {
_ = context;
return std.ascii.lessThanIgnoreCase(a.zig_name, b.zig_name);
}
fn asciiLessThan(context: void, a: []const u8, b: []const u8) bool {
_ = context;
return std.ascii.lessThanIgnoreCase(a, b);
}
fn llvmNameToZigName(arena: mem.Allocator, llvm_name: []const u8) ![]const u8 {
const duped = try arena.dupe(u8, llvm_name);
for (duped) |*byte| switch (byte.*) {
'-', '.' => byte.* = '_',
else => continue,
};
return duped;
}
fn llvmFeatureNameToZigNameOmit(
arena: mem.Allocator,
llvm_target: LlvmTarget,
llvm_name: []const u8,
) !?[]const u8 {
for (llvm_target.feature_overrides) |feature_override| {
if (mem.eql(u8, feature_override.llvm_name, llvm_name)) {
if (feature_override.omit) return null;
return feature_override.zig_name orelse break;
}
}
return try llvmNameToZigName(arena, llvm_name);
}
fn hasSuperclass(obj: *json.ObjectMap, class_name: []const u8) bool {
const superclasses_json = obj.get("!superclasses") orelse return false;
for (superclasses_json.array.items) |superclass_json| {
const superclass = superclass_json.string;
if (std.mem.eql(u8, superclass, class_name)) {
return true;
}
}
return false;
}
fn pruneFeatures(
arena: mem.Allocator,
features_table: std.StringHashMap(Feature),
deps_set: *std.StringHashMap(void),
) !void {
// For each element, recursively iterate over the dependencies and add
// everything we find to a "deletion set".
// Then, iterate over the deletion set and delete all that stuff from `deps_set`.
var deletion_set = std.StringHashMap(void).init(arena);
{
var it = deps_set.keyIterator();
while (it.next()) |key| {
const feature = features_table.get(key.*).?;
try walkFeatures(features_table, &deletion_set, feature);
}
}
{
var it = deletion_set.keyIterator();
while (it.next()) |key| {
_ = deps_set.remove(key.*);
}
}
}
fn walkFeatures(
features_table: std.StringHashMap(Feature),
deletion_set: *std.StringHashMap(void),
feature: Feature,
) error{OutOfMemory}!void {
for (feature.deps) |dep| {
try deletion_set.put(dep, {});
const other_feature = features_table.get(dep).?;
try walkFeatures(features_table, deletion_set, other_feature);
}
}
fn putDep(
deps_set: *std.StringHashMap(void),
features_table: std.StringHashMap(Feature),
zig_feature_name: []const u8,
) error{OutOfMemory}!void {
const feature = features_table.get(zig_feature_name).?;
if (feature.flatten) {
for (feature.deps) |dep| {
try putDep(deps_set, features_table, dep);
}
} else {
try deps_set.put(zig_feature_name, {});
}
}