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.
This commit is contained in:
Andrew Kelley 2021-02-27 15:57:01 -07:00
parent 9082d76168
commit e02acc0288
5 changed files with 362 additions and 295 deletions

View file

@ -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",

View file

@ -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",

View file

@ -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,
}),
};

View file

@ -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,6 +1088,42 @@ pub const cpu = struct {
.x87,
}),
};
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,
.sse2,
.vzeroupper,
.x87,
}),
};
pub const athlon64_sse3 = CpuModel{
.name = "athlon64_sse3",
.llvm_name = "athlon64-sse3",
.features = featureSet(&[_]Feature{
.@"3dnowa",
.@"64bit",
.cmov,
.cx16,
.fast_scalar_shift_masks,
.fxsr,
.nopl,
.slow_shld,
.slow_unaligned_mem_16,
.sse3,
.vzeroupper,
.x87,
}),
};
pub const athlon_4 = CpuModel{
.name = "athlon_4",
.llvm_name = "athlon-4",
@ -1129,42 +1204,6 @@ pub const cpu = struct {
.x87,
}),
};
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,
.sse2,
.vzeroupper,
.x87,
}),
};
pub const athlon64_sse3 = CpuModel{
.name = "athlon64_sse3",
.llvm_name = "athlon64-sse3",
.features = featureSet(&[_]Feature{
.@"3dnowa",
.@"64bit",
.cmov,
.cx16,
.fast_scalar_shift_masks,
.fxsr,
.nopl,
.slow_shld,
.slow_unaligned_mem_16,
.sse3,
.vzeroupper,
.x87,
}),
};
pub const atom = CpuModel{
.name = "atom",
.llvm_name = "atom",
@ -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,16 +2894,6 @@ pub const cpu = struct {
.x87,
}),
};
pub const winchip_c6 = CpuModel{
.name = "winchip_c6",
.llvm_name = "winchip-c6",
.features = featureSet(&[_]Feature{
.mmx,
.slow_unaligned_mem_16,
.vzeroupper,
.x87,
}),
};
pub const winchip2 = CpuModel{
.name = "winchip2",
.llvm_name = "winchip2",
@ -2914,6 +2904,16 @@ pub const cpu = struct {
.x87,
}),
};
pub const winchip_c6 = CpuModel{
.name = "winchip_c6",
.llvm_name = "winchip-c6",
.features = featureSet(&[_]Feature{
.mmx,
.slow_unaligned_mem_16,
.vzeroupper,
.x87,
}),
};
pub const x86_64 = CpuModel{
.name = "x86_64",
.llvm_name = "x86-64",

View file

@ -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;
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 (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),
},
);
}
try pruneFeatures(arena, root_map, &deps_set);
var dependencies = std.ArrayList(*json.ObjectMap).init(arena);
var deps_set = std.StringHashMap(void).init(arena);
for (feature.deps) |dep| {
try deps_set.put(dep, {});
}
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);
}
}