Commit e02acc0288

Andrew Kelley <andrew@ziglang.org>
2021-02-27 23:57:01
tools/update_cpu_features: better patching API
With this change, added & modified cpus & features participate in the same pruning system, and sorting takes into account the zig name, not the pre-modified llvm name. The modified target files in this commit are due to the improved sorting and pruning. The script now fully supports extra cpus & features.
1 parent 9082d76
lib/std/target/amdgpu.zig
@@ -41,8 +41,8 @@ pub const Feature = enum {
     get_wave_id_inst,
     gfx10,
     gfx10_3_insts,
-    gfx10_insts,
     gfx10_b_encoding,
+    gfx10_insts,
     gfx7_gfx8_gfx9_insts,
     gfx8_insts,
     gfx9,
@@ -347,16 +347,16 @@ pub const all_features = blk: {
         .description = "Additional instructions for GFX10.3",
         .dependencies = featureSet(&[_]Feature{}),
     };
-    result[@enumToInt(Feature.gfx10_insts)] = .{
-        .llvm_name = "gfx10-insts",
-        .description = "Additional instructions for GFX10+",
-        .dependencies = featureSet(&[_]Feature{}),
-    };
     result[@enumToInt(Feature.gfx10_b_encoding)] = .{
         .llvm_name = "gfx10_b-encoding",
         .description = "Encoding format GFX10_B",
         .dependencies = featureSet(&[_]Feature{}),
     };
+    result[@enumToInt(Feature.gfx10_insts)] = .{
+        .llvm_name = "gfx10-insts",
+        .description = "Additional instructions for GFX10+",
+        .dependencies = featureSet(&[_]Feature{}),
+    };
     result[@enumToInt(Feature.gfx7_gfx8_gfx9_insts)] = .{
         .llvm_name = "gfx7-gfx8-gfx9-insts",
         .description = "Instructions shared in GFX7, GFX8, GFX9",
lib/std/target/powerpc.zig
@@ -56,10 +56,10 @@ pub const Feature = enum {
     power8_vector,
     power9_altivec,
     power9_vector,
-    ppc_postra_sched,
-    ppc_prera_sched,
     ppc4xx,
     ppc6xx,
+    ppc_postra_sched,
+    ppc_prera_sched,
     predictable_select_expensive,
     prefix_instrs,
     recipprec,
@@ -397,16 +397,6 @@ pub const all_features = blk: {
             .power9_altivec,
         }),
     };
-    result[@enumToInt(Feature.ppc_postra_sched)] = .{
-        .llvm_name = "ppc-postra-sched",
-        .description = "Use PowerPC post-RA scheduling strategy",
-        .dependencies = featureSet(&[_]Feature{}),
-    };
-    result[@enumToInt(Feature.ppc_prera_sched)] = .{
-        .llvm_name = "ppc-prera-sched",
-        .description = "Use PowerPC pre-RA scheduling strategy",
-        .dependencies = featureSet(&[_]Feature{}),
-    };
     result[@enumToInt(Feature.ppc4xx)] = .{
         .llvm_name = "ppc4xx",
         .description = "Enable PPC 4xx instructions",
@@ -417,6 +407,16 @@ pub const all_features = blk: {
         .description = "Enable PPC 6xx instructions",
         .dependencies = featureSet(&[_]Feature{}),
     };
+    result[@enumToInt(Feature.ppc_postra_sched)] = .{
+        .llvm_name = "ppc-postra-sched",
+        .description = "Use PowerPC post-RA scheduling strategy",
+        .dependencies = featureSet(&[_]Feature{}),
+    };
+    result[@enumToInt(Feature.ppc_prera_sched)] = .{
+        .llvm_name = "ppc-prera-sched",
+        .description = "Use PowerPC pre-RA scheduling strategy",
+        .dependencies = featureSet(&[_]Feature{}),
+    };
     result[@enumToInt(Feature.predictable_select_expensive)] = .{
         .llvm_name = "predictable-select-expensive",
         .description = "Prefer likely predicted branches over selects",
lib/std/target/riscv.zig
@@ -390,7 +390,6 @@ pub const cpu = struct {
             .a,
             .c,
             .d,
-            .f,
             .m,
         }),
     };
@@ -402,7 +401,6 @@ pub const cpu = struct {
             .a,
             .c,
             .d,
-            .f,
             .m,
         }),
     };
lib/std/target/x86.zig
@@ -121,12 +121,12 @@ pub const Feature = enum {
     slow_unaligned_mem_32,
     soft_float,
     sse,
-    sse_unaligned_mem,
     sse2,
     sse3,
     sse4_1,
     sse4_2,
     sse4a,
+    sse_unaligned_mem,
     ssse3,
     tbm,
     tsxldtrk,
@@ -805,11 +805,6 @@ pub const all_features = blk: {
         .description = "Enable SSE instructions",
         .dependencies = featureSet(&[_]Feature{}),
     };
-    result[@enumToInt(Feature.sse_unaligned_mem)] = .{
-        .llvm_name = "sse-unaligned-mem",
-        .description = "Allow unaligned memory operands with SSE instructions",
-        .dependencies = featureSet(&[_]Feature{}),
-    };
     result[@enumToInt(Feature.sse2)] = .{
         .llvm_name = "sse2",
         .description = "Enable SSE2 instructions",
@@ -845,6 +840,11 @@ pub const all_features = blk: {
             .sse3,
         }),
     };
+    result[@enumToInt(Feature.sse_unaligned_mem)] = .{
+        .llvm_name = "sse-unaligned-mem",
+        .description = "Allow unaligned memory operands with SSE instructions",
+        .dependencies = featureSet(&[_]Feature{}),
+    };
     result[@enumToInt(Feature.ssse3)] = .{
         .llvm_name = "ssse3",
         .description = "Enable SSSE3 instructions",
@@ -962,6 +962,45 @@ pub const all_features = blk: {
 };
 
 pub const cpu = struct {
+    pub const _i386 = CpuModel{
+        .name = "_i386",
+        .llvm_name = "i386",
+        .features = featureSet(&[_]Feature{
+            .slow_unaligned_mem_16,
+            .vzeroupper,
+            .x87,
+        }),
+    };
+    pub const _i486 = CpuModel{
+        .name = "_i486",
+        .llvm_name = "i486",
+        .features = featureSet(&[_]Feature{
+            .slow_unaligned_mem_16,
+            .vzeroupper,
+            .x87,
+        }),
+    };
+    pub const _i586 = CpuModel{
+        .name = "_i586",
+        .llvm_name = "i586",
+        .features = featureSet(&[_]Feature{
+            .cx8,
+            .slow_unaligned_mem_16,
+            .vzeroupper,
+            .x87,
+        }),
+    };
+    pub const _i686 = CpuModel{
+        .name = "_i686",
+        .llvm_name = "i686",
+        .features = featureSet(&[_]Feature{
+            .cmov,
+            .cx8,
+            .slow_unaligned_mem_16,
+            .vzeroupper,
+            .x87,
+        }),
+    };
     pub const alderlake = CpuModel{
         .name = "alderlake",
         .llvm_name = "alderlake",
@@ -1049,43 +1088,45 @@ pub const cpu = struct {
             .x87,
         }),
     };
-    pub const athlon_4 = CpuModel{
-        .name = "athlon_4",
-        .llvm_name = "athlon-4",
+    pub const athlon64 = CpuModel{
+        .name = "athlon64",
+        .llvm_name = "athlon64",
         .features = featureSet(&[_]Feature{
             .@"3dnowa",
+            .@"64bit",
             .cmov,
             .cx8,
+            .fast_scalar_shift_masks,
             .fxsr,
             .nopl,
             .slow_shld,
             .slow_unaligned_mem_16,
-            .sse,
+            .sse2,
             .vzeroupper,
             .x87,
         }),
     };
-    pub const athlon_fx = CpuModel{
-        .name = "athlon_fx",
-        .llvm_name = "athlon-fx",
+    pub const athlon64_sse3 = CpuModel{
+        .name = "athlon64_sse3",
+        .llvm_name = "athlon64-sse3",
         .features = featureSet(&[_]Feature{
             .@"3dnowa",
             .@"64bit",
             .cmov,
-            .cx8,
+            .cx16,
             .fast_scalar_shift_masks,
             .fxsr,
             .nopl,
             .slow_shld,
             .slow_unaligned_mem_16,
-            .sse2,
+            .sse3,
             .vzeroupper,
             .x87,
         }),
     };
-    pub const athlon_mp = CpuModel{
-        .name = "athlon_mp",
-        .llvm_name = "athlon-mp",
+    pub const athlon_4 = CpuModel{
+        .name = "athlon_4",
+        .llvm_name = "athlon-4",
         .features = featureSet(&[_]Feature{
             .@"3dnowa",
             .cmov,
@@ -1099,23 +1140,27 @@ pub const cpu = struct {
             .x87,
         }),
     };
-    pub const athlon_tbird = CpuModel{
-        .name = "athlon_tbird",
-        .llvm_name = "athlon-tbird",
+    pub const athlon_fx = CpuModel{
+        .name = "athlon_fx",
+        .llvm_name = "athlon-fx",
         .features = featureSet(&[_]Feature{
             .@"3dnowa",
+            .@"64bit",
             .cmov,
             .cx8,
+            .fast_scalar_shift_masks,
+            .fxsr,
             .nopl,
             .slow_shld,
             .slow_unaligned_mem_16,
+            .sse2,
             .vzeroupper,
             .x87,
         }),
     };
-    pub const athlon_xp = CpuModel{
-        .name = "athlon_xp",
-        .llvm_name = "athlon-xp",
+    pub const athlon_mp = CpuModel{
+        .name = "athlon_mp",
+        .llvm_name = "athlon-mp",
         .features = featureSet(&[_]Feature{
             .@"3dnowa",
             .cmov,
@@ -1129,38 +1174,32 @@ pub const cpu = struct {
             .x87,
         }),
     };
-    pub const athlon64 = CpuModel{
-        .name = "athlon64",
-        .llvm_name = "athlon64",
+    pub const athlon_tbird = CpuModel{
+        .name = "athlon_tbird",
+        .llvm_name = "athlon-tbird",
         .features = featureSet(&[_]Feature{
             .@"3dnowa",
-            .@"64bit",
             .cmov,
             .cx8,
-            .fast_scalar_shift_masks,
-            .fxsr,
             .nopl,
             .slow_shld,
             .slow_unaligned_mem_16,
-            .sse2,
             .vzeroupper,
             .x87,
         }),
     };
-    pub const athlon64_sse3 = CpuModel{
-        .name = "athlon64_sse3",
-        .llvm_name = "athlon64-sse3",
+    pub const athlon_xp = CpuModel{
+        .name = "athlon_xp",
+        .llvm_name = "athlon-xp",
         .features = featureSet(&[_]Feature{
             .@"3dnowa",
-            .@"64bit",
             .cmov,
-            .cx16,
-            .fast_scalar_shift_masks,
+            .cx8,
             .fxsr,
             .nopl,
             .slow_shld,
             .slow_unaligned_mem_16,
-            .sse3,
+            .sse,
             .vzeroupper,
             .x87,
         }),
@@ -1637,33 +1676,22 @@ pub const cpu = struct {
             .xsaves,
         }),
     };
-    pub const core_avx_i = CpuModel{
-        .name = "core_avx_i",
-        .llvm_name = "core-avx-i",
+    pub const core2 = CpuModel{
+        .name = "core2",
+        .llvm_name = "core2",
         .features = featureSet(&[_]Feature{
             .@"64bit",
             .cmov,
             .cx16,
-            .f16c,
-            .false_deps_popcnt,
-            .fast_15bytenop,
-            .fast_scalar_fsqrt,
-            .fast_shld_rotate,
-            .fsgsbase,
             .fxsr,
-            .idivq_to_divl,
             .macrofusion,
             .mmx,
             .nopl,
-            .pclmul,
-            .popcnt,
-            .rdrnd,
             .sahf,
-            .slow_3ops_lea,
-            .slow_unaligned_mem_32,
+            .slow_unaligned_mem_16,
+            .ssse3,
             .vzeroupper,
             .x87,
-            .xsaveopt,
         }),
     };
     pub const core_avx2 = CpuModel{
@@ -1704,22 +1732,33 @@ pub const cpu = struct {
             .xsaveopt,
         }),
     };
-    pub const core2 = CpuModel{
-        .name = "core2",
-        .llvm_name = "core2",
+    pub const core_avx_i = CpuModel{
+        .name = "core_avx_i",
+        .llvm_name = "core-avx-i",
         .features = featureSet(&[_]Feature{
             .@"64bit",
             .cmov,
             .cx16,
+            .f16c,
+            .false_deps_popcnt,
+            .fast_15bytenop,
+            .fast_scalar_fsqrt,
+            .fast_shld_rotate,
+            .fsgsbase,
             .fxsr,
+            .idivq_to_divl,
             .macrofusion,
             .mmx,
             .nopl,
+            .pclmul,
+            .popcnt,
+            .rdrnd,
             .sahf,
-            .slow_unaligned_mem_16,
-            .ssse3,
+            .slow_3ops_lea,
+            .slow_unaligned_mem_32,
             .vzeroupper,
             .x87,
+            .xsaveopt,
         }),
     };
     pub const corei7 = CpuModel{
@@ -1900,45 +1939,6 @@ pub const cpu = struct {
             .xsaveopt,
         }),
     };
-    pub const _i386 = CpuModel{
-        .name = "_i386",
-        .llvm_name = "i386",
-        .features = featureSet(&[_]Feature{
-            .slow_unaligned_mem_16,
-            .vzeroupper,
-            .x87,
-        }),
-    };
-    pub const _i486 = CpuModel{
-        .name = "_i486",
-        .llvm_name = "i486",
-        .features = featureSet(&[_]Feature{
-            .slow_unaligned_mem_16,
-            .vzeroupper,
-            .x87,
-        }),
-    };
-    pub const _i586 = CpuModel{
-        .name = "_i586",
-        .llvm_name = "i586",
-        .features = featureSet(&[_]Feature{
-            .cx8,
-            .slow_unaligned_mem_16,
-            .vzeroupper,
-            .x87,
-        }),
-    };
-    pub const _i686 = CpuModel{
-        .name = "_i686",
-        .llvm_name = "i686",
-        .features = featureSet(&[_]Feature{
-            .cmov,
-            .cx8,
-            .slow_unaligned_mem_16,
-            .vzeroupper,
-            .x87,
-        }),
-    };
     pub const icelake_client = CpuModel{
         .name = "icelake_client",
         .llvm_name = "icelake-client",
@@ -2341,32 +2341,6 @@ pub const cpu = struct {
             .x87,
         }),
     };
-    pub const pentium_m = CpuModel{
-        .name = "pentium_m",
-        .llvm_name = "pentium-m",
-        .features = featureSet(&[_]Feature{
-            .cmov,
-            .cx8,
-            .fxsr,
-            .mmx,
-            .nopl,
-            .slow_unaligned_mem_16,
-            .sse2,
-            .vzeroupper,
-            .x87,
-        }),
-    };
-    pub const pentium_mmx = CpuModel{
-        .name = "pentium_mmx",
-        .llvm_name = "pentium-mmx",
-        .features = featureSet(&[_]Feature{
-            .cx8,
-            .mmx,
-            .slow_unaligned_mem_16,
-            .vzeroupper,
-            .x87,
-        }),
-    };
     pub const pentium2 = CpuModel{
         .name = "pentium2",
         .llvm_name = "pentium2",
@@ -2441,6 +2415,32 @@ pub const cpu = struct {
             .x87,
         }),
     };
+    pub const pentium_m = CpuModel{
+        .name = "pentium_m",
+        .llvm_name = "pentium-m",
+        .features = featureSet(&[_]Feature{
+            .cmov,
+            .cx8,
+            .fxsr,
+            .mmx,
+            .nopl,
+            .slow_unaligned_mem_16,
+            .sse2,
+            .vzeroupper,
+            .x87,
+        }),
+    };
+    pub const pentium_mmx = CpuModel{
+        .name = "pentium_mmx",
+        .llvm_name = "pentium-mmx",
+        .features = featureSet(&[_]Feature{
+            .cx8,
+            .mmx,
+            .slow_unaligned_mem_16,
+            .vzeroupper,
+            .x87,
+        }),
+    };
     pub const pentiumpro = CpuModel{
         .name = "pentiumpro",
         .llvm_name = "pentiumpro",
@@ -2894,21 +2894,21 @@ pub const cpu = struct {
             .x87,
         }),
     };
-    pub const winchip_c6 = CpuModel{
-        .name = "winchip_c6",
-        .llvm_name = "winchip-c6",
+    pub const winchip2 = CpuModel{
+        .name = "winchip2",
+        .llvm_name = "winchip2",
         .features = featureSet(&[_]Feature{
-            .mmx,
+            .@"3dnow",
             .slow_unaligned_mem_16,
             .vzeroupper,
             .x87,
         }),
     };
-    pub const winchip2 = CpuModel{
-        .name = "winchip2",
-        .llvm_name = "winchip2",
+    pub const winchip_c6 = CpuModel{
+        .name = "winchip_c6",
+        .llvm_name = "winchip-c6",
         .features = featureSet(&[_]Feature{
-            .@"3dnow",
+            .mmx,
             .slow_unaligned_mem_16,
             .vzeroupper,
             .x87,
tools/update_cpu_features.zig
@@ -4,25 +4,36 @@ 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,
     omit: bool = false,
     zig_name: ?[]const u8 = null,
     desc: ?[]const u8 = null,
+    extra_deps: []const []const u8 = &.{},
 };
 
-const ExtraCpu = struct {
+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,
+};
+
 const LlvmTarget = struct {
     zig_name: []const u8,
     llvm_name: []const u8,
     td_name: []const u8,
     feature_overrides: []const FeatureOverride = &.{},
-    extra_cpus: []const ExtraCpu = &.{},
+    extra_cpus: []const Cpu = &.{},
+    extra_features: []const Feature = &.{},
     branch_quota: ?usize = null,
 };
 
@@ -54,6 +65,25 @@ const llvm_targets = [_]LlvmTarget{
                 .llvm_name = "neoversev1",
                 .zig_name = "neoverse_v1",
             },
+            .{
+                .llvm_name = "exynosm3",
+                .zig_name = "exynos_m3",
+            },
+            .{
+                .llvm_name = "exynosm4",
+                .zig_name = "exynos_m4",
+            },
+            .{
+                .llvm_name = "v8.1a",
+                .extra_deps = &.{"v8a"},
+            },
+        },
+        .extra_features = &.{
+            .{
+                .zig_name = "v8a",
+                .desc = "Support ARM v8a instructions",
+                .deps = &.{ "fp_armv8", "neon" },
+            },
         },
     },
     .{
@@ -331,8 +361,9 @@ fn processOneTarget(job: Job) anyerror!void {
     render_progress.activate();
 
     const root_map = &tree.root.Object;
-    var all_features = std.ArrayList(*json.ObjectMap).init(arena);
-    var all_cpus = std.ArrayList(*json.ObjectMap).init(arena);
+    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();
         root_it: while (it.next()) |kv| {
@@ -342,23 +373,101 @@ fn processOneTarget(job: Job) anyerror!void {
             if (hasSuperclass(&kv.value.Object, "SubtargetFeature")) {
                 const llvm_name = kv.value.Object.get("Name").?.String;
                 if (llvm_name.len == 0) continue;
+
+                var zig_name = (try llvmNameToZigName(arena, llvm_target, llvm_name)) orelse
+                    continue :root_it;
+                var desc = kv.value.Object.get("Desc").?.String;
+                var deps = std.ArrayList([]const u8).init(arena);
+                const implies = kv.value.Object.get("Implies").?.Array;
+                for (implies.items) |imply| {
+                    const other_key = imply.Object.get("def").?.String;
+                    const other_obj = &root_map.getEntry(other_key).?.value.Object;
+                    const other_llvm_name = other_obj.get("Name").?.String;
+                    const other_zig_name = (try llvmNameToZigName(arena, llvm_target, other_llvm_name)) orelse continue;
+                    try deps.append(other_zig_name);
+                }
                 for (llvm_target.feature_overrides) |feature_override| {
                     if (mem.eql(u8, llvm_name, feature_override.llvm_name)) {
                         if (feature_override.omit) {
                             continue :root_it;
                         }
+                        if (feature_override.zig_name) |override_name| {
+                            zig_name = override_name;
+                        }
+                        if (feature_override.desc) |override_desc| {
+                            desc = override_desc;
+                        }
+                        for (feature_override.extra_deps) |extra_dep| {
+                            try deps.append(extra_dep);
+                        }
+                        break;
                     }
                 }
-
-                try all_features.append(&kv.value.Object);
+                const feature: Feature = .{
+                    .llvm_name = llvm_name,
+                    .zig_name = zig_name,
+                    .desc = desc,
+                    .deps = deps.items,
+                };
+                try features_table.put(zig_name, feature);
+                try all_features.append(feature);
             }
             if (hasSuperclass(&kv.value.Object, "Processor")) {
-                try all_cpus.append(&kv.value.Object);
+                const llvm_name = kv.value.Object.get("Name").?.String;
+                if (llvm_name.len == 0) continue;
+
+                var zig_name = (try llvmNameToZigName(arena, llvm_target, llvm_name)) orelse
+                    continue :root_it;
+                var deps = std.ArrayList([]const u8).init(arena);
+                const features = kv.value.Object.get("Features").?.Array;
+                for (features.items) |feature| {
+                    const feature_key = feature.Object.get("def").?.String;
+                    const feature_obj = &root_map.getEntry(feature_key).?.value.Object;
+                    const feature_llvm_name = feature_obj.get("Name").?.String;
+                    if (feature_llvm_name.len == 0) continue;
+                    const feature_zig_name = (try llvmNameToZigName(arena, llvm_target, feature_llvm_name)) orelse continue;
+                    try deps.append(feature_zig_name);
+                }
+                const tune_features = kv.value.Object.get("TuneFeatures").?.Array;
+                for (tune_features.items) |feature| {
+                    const feature_key = feature.Object.get("def").?.String;
+                    const feature_obj = &root_map.getEntry(feature_key).?.value.Object;
+                    const feature_llvm_name = feature_obj.get("Name").?.String;
+                    if (feature_llvm_name.len == 0) continue;
+                    const feature_zig_name = (try llvmNameToZigName(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 :root_it;
+                        }
+                        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,
+                });
             }
         }
     }
-    std.sort.sort(*json.ObjectMap, all_features.items, {}, objectLessThan);
-    std.sort.sort(*json.ObjectMap, all_cpus.items, {}, objectLessThan);
+    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);
+    }
+    std.sort.sort(Feature, all_features.items, {}, featureLessThan);
+    std.sort.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, .{});
@@ -389,10 +498,8 @@ fn processOneTarget(job: Job) anyerror!void {
         \\
     );
 
-    for (all_features.items) |obj| {
-        const llvm_name = obj.get("Name").?.String;
-        const zig_name = try llvmNameToZigName(arena, llvm_target, llvm_name);
-        try w.print("    {},\n", .{std.zig.fmtId(zig_name)});
+    for (all_features.items) |feature| {
+        try w.print("    {},\n", .{std.zig.fmtId(feature.zig_name)});
     }
 
     try w.writeAll(
@@ -413,45 +520,46 @@ fn processOneTarget(job: Job) anyerror!void {
         \\
     );
 
-    for (all_features.items) |obj| {
-        const llvm_name = obj.get("Name").?.String;
-        const llvm_description = obj.get("Desc").?.String;
-        const description = for (llvm_target.feature_overrides) |feature_override| {
-            if (mem.eql(u8, llvm_name, feature_override.llvm_name)) {
-                if (feature_override.desc) |desc| {
-                    break desc;
-                }
-            }
-        } else llvm_description;
-        const zig_name = try llvmNameToZigName(arena, llvm_target, llvm_name);
-        try w.print(
-            \\    result[@enumToInt(Feature.{})] = .{{
-            \\        .llvm_name = "{}",
-            \\        .description = "{}",
-            \\        .dependencies = featureSet(&[_]Feature{{
-        ,
-            .{
-                std.zig.fmtId(zig_name),
-                std.zig.fmtEscapes(llvm_name),
-                std.zig.fmtEscapes(description),
-            },
-        );
-        const implies = obj.get("Implies").?.Array;
+    for (all_features.items) |feature| {
+        if (feature.llvm_name) |llvm_name| {
+            try w.print(
+                \\    result[@enumToInt(Feature.{})] = .{{
+                \\        .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[@enumToInt(Feature.{})] = .{{
+                \\        .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 (implies.items) |imply| {
-            const other_key = imply.Object.get("def").?.String;
-            try deps_set.put(other_key, {});
+        for (feature.deps) |dep| {
+            try deps_set.put(dep, {});
         }
-        try pruneFeatures(arena, root_map, &deps_set);
-        var dependencies = std.ArrayList(*json.ObjectMap).init(arena);
+        try pruneFeatures(arena, features_table, &deps_set);
+        var dependencies = std.ArrayList([]const u8).init(arena);
         {
             var it = deps_set.iterator();
             while (it.next()) |entry| {
-                const other_obj = &root_map.getEntry(entry.key).?.value.Object;
-                try dependencies.append(other_obj);
+                try dependencies.append(entry.key);
             }
         }
-        std.sort.sort(*json.ObjectMap, dependencies.items, {}, objectLessThan);
+        std.sort.sort([]const u8, dependencies.items, {}, asciiLessThan);
 
         if (dependencies.items.len == 0) {
             try w.writeAll(
@@ -462,9 +570,7 @@ fn processOneTarget(job: Job) anyerror!void {
         } else {
             try w.writeAll("\n");
             for (dependencies.items) |dep| {
-                const other_llvm_name = dep.get("Name").?.String;
-                const other_zig_name = try llvmNameToZigName(arena, llvm_target, other_llvm_name);
-                try w.print("            .{},\n", .{std.zig.fmtId(other_zig_name)});
+                try w.print("            .{},\n", .{std.zig.fmtId(dep)});
             }
             try w.writeAll(
                 \\        }),
@@ -485,81 +591,42 @@ fn processOneTarget(job: Job) anyerror!void {
         \\pub const cpu = struct {
         \\
     );
-    for (llvm_target.extra_cpus) |extra_cpu| {
-        try w.print(
-            \\    pub const {} = CpuModel{{
-            \\        .name = "{}",
-            \\
-        , .{
-            std.zig.fmtId(extra_cpu.zig_name),
-            std.zig.fmtEscapes(extra_cpu.zig_name),
-        });
-        if (extra_cpu.llvm_name) |llvm_name| {
-            try w.print(
-                \\        .llvm_name = "{}",
-                \\        .features = featureSet(&[_]Feature{{
-            , .{std.zig.fmtEscapes(llvm_name)});
-        } else {
-            try w.writeAll(
-                \\        .llvm_name = null,
-                \\        .features = featureSet(&[_]Feature{
-            );
-        }
-        if (extra_cpu.features.len == 0) {
-            try w.writeAll(
-                \\}),
-                \\    };
-                \\
-            );
-        } else {
-            try w.writeAll("\n");
-            for (extra_cpu.features) |feature_zig_name| {
-                try w.print("            .{},\n", .{std.zig.fmtId(feature_zig_name)});
-            }
-            try w.writeAll(
-                \\        }),
-                \\    };
-                \\
-            );
-        }
-    }
-    for (all_cpus.items) |obj| {
-        const llvm_name = obj.get("Name").?.String;
+    for (all_cpus.items) |cpu| {
         var deps_set = std.StringHashMap(void).init(arena);
-
-        const features = obj.get("Features").?.Array;
-        for (features.items) |feature| {
-            const feature_key = feature.Object.get("def").?.String;
-            try deps_set.put(feature_key, {});
+        for (cpu.features) |feature_zig_name| {
+            try deps_set.put(feature_zig_name, {});
         }
-        const tune_features = obj.get("TuneFeatures").?.Array;
-        for (tune_features.items) |feature| {
-            const feature_key = feature.Object.get("def").?.String;
-            try deps_set.put(feature_key, {});
-        }
-        try pruneFeatures(arena, root_map, &deps_set);
-        var cpu_features = std.ArrayList(*json.ObjectMap).init(arena);
+        try pruneFeatures(arena, features_table, &deps_set);
+        var cpu_features = std.ArrayList([]const u8).init(arena);
         {
             var it = deps_set.iterator();
             while (it.next()) |entry| {
-                const feature_obj = &root_map.getEntry(entry.key).?.value.Object;
-                const feature_llvm_name = feature_obj.get("Name").?.String;
-                if (feature_llvm_name.len == 0) continue;
-                try cpu_features.append(feature_obj);
+                try cpu_features.append(entry.key);
             }
         }
-        std.sort.sort(*json.ObjectMap, cpu_features.items, {}, objectLessThan);
-        const zig_cpu_name = try llvmNameToZigName(arena, llvm_target, llvm_name);
-        try w.print(
-            \\    pub const {} = CpuModel{{
-            \\        .name = "{}",
-            \\        .llvm_name = "{}",
-            \\        .features = featureSet(&[_]Feature{{
-        , .{
-            std.zig.fmtId(zig_cpu_name),
-            std.zig.fmtEscapes(zig_cpu_name),
-            std.zig.fmtEscapes(llvm_name),
-        });
+        std.sort.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(
                 \\}),
@@ -568,9 +635,7 @@ fn processOneTarget(job: Job) anyerror!void {
             );
         } else {
             try w.writeAll("\n");
-            for (cpu_features.items) |feature_obj| {
-                const feature_llvm_name = feature_obj.get("Name").?.String;
-                const feature_zig_name = try llvmNameToZigName(arena, llvm_target, feature_llvm_name);
+            for (cpu_features.items) |feature_zig_name| {
                 try w.print("            .{},\n", .{std.zig.fmtId(feature_zig_name)});
             }
             try w.writeAll(
@@ -602,20 +667,26 @@ fn usageAndExit(file: fs.File, arg0: []const u8, code: u8) noreturn {
     std.process.exit(code);
 }
 
-fn objectLessThan(context: void, a: *json.ObjectMap, b: *json.ObjectMap) bool {
-    const a_key = a.get("Name").?.String;
-    const b_key = b.get("Name").?.String;
-    return std.ascii.lessThanIgnoreCase(a_key, b_key);
+fn featureLessThan(context: void, a: Feature, b: Feature) bool {
+    return std.ascii.lessThanIgnoreCase(a.zig_name, b.zig_name);
+}
+
+fn cpuLessThan(context: void, a: Cpu, b: Cpu) bool {
+    return std.ascii.lessThanIgnoreCase(a.zig_name, b.zig_name);
+}
+
+fn asciiLessThan(context: void, a: []const u8, b: []const u8) bool {
+    return std.ascii.lessThanIgnoreCase(a, b);
 }
 
 fn llvmNameToZigName(
     arena: *mem.Allocator,
     llvm_target: LlvmTarget,
     llvm_name: []const u8,
-) ![]const u8 {
+) !?[]const u8 {
     for (llvm_target.feature_overrides) |feature_override| {
         if (mem.eql(u8, feature_override.llvm_name, llvm_name)) {
-            assert(!feature_override.omit);
+            if (feature_override.omit) return null;
             return feature_override.zig_name orelse break;
         }
     }
@@ -640,7 +711,7 @@ fn hasSuperclass(obj: *json.ObjectMap, class_name: []const u8) bool {
 
 fn pruneFeatures(
     arena: *mem.Allocator,
-    root_map: *const json.ObjectMap,
+    features_table: std.StringHashMap(Feature),
     deps_set: *std.StringHashMap(void),
 ) !void {
     // For each element, recursively iterate over the dependencies and add
@@ -650,8 +721,8 @@ fn pruneFeatures(
     {
         var it = deps_set.iterator();
         while (it.next()) |entry| {
-            const other_obj = &root_map.getEntry(entry.key).?.value.Object;
-            try walkFeatures(root_map, &deletion_set, other_obj);
+            const feature = features_table.get(entry.key).?;
+            try walkFeatures(features_table, &deletion_set, feature);
         }
     }
     {
@@ -663,15 +734,13 @@ fn pruneFeatures(
 }
 
 fn walkFeatures(
-    root_map: *const json.ObjectMap,
+    features_table: std.StringHashMap(Feature),
     deletion_set: *std.StringHashMap(void),
-    feature: *json.ObjectMap,
+    feature: Feature,
 ) error{OutOfMemory}!void {
-    const implies = feature.get("Implies").?.Array;
-    for (implies.items) |imply| {
-        const other_key = imply.Object.get("def").?.String;
-        try deletion_set.put(other_key, {});
-        const other_obj = &root_map.getEntry(other_key).?.value.Object;
-        try walkFeatures(root_map, deletion_set, other_obj);
+    for (feature.deps) |dep| {
+        try deletion_set.put(dep, {});
+        const other_feature = features_table.get(dep).?;
+        try walkFeatures(features_table, deletion_set, other_feature);
     }
 }