Add CPU feature check to standardTargetOptions

If there is a mismatch of CPU features provided
compared to the whitelist, then will fail the build and
print what the expected CPU model is and the feature
set for the model. Also prints what features need to be
removed.
This commit is contained in:
Edward Dean 2021-02-24 19:45:45 +00:00 committed by Andrew Kelley
parent 45212e3b33
commit 7ba175cd8b
2 changed files with 66 additions and 10 deletions

View File

@ -640,12 +640,18 @@ pub const Builder = struct {
const mcpu = self.option([]const u8, "cpu", "Target CPU"); const mcpu = self.option([]const u8, "cpu", "Target CPU");
const triple = maybe_triple orelse return args.default_target; const triple = maybe_triple orelse return args.default_target;
const cpu_features = self.option(
[]const u8,
"mcpu",
"The list of CPU features to add or subtract",
);
var diags: CrossTarget.ParseOptions.Diagnostics = .{}; var diags: CrossTarget.ParseOptions.Diagnostics = .{};
const selected_target = CrossTarget.parse(.{ const selected_target = CrossTarget.parse(.{
.arch_os_abi = triple, .arch_os_abi = triple,
.cpu_features = mcpu, .cpu_features = mcpu,
.diagnostics = &diags, .diagnostics = &diags,
.cpu_features = cpu_features,
}) catch |err| switch (err) { }) catch |err| switch (err) {
error.UnknownCpuModel => { error.UnknownCpuModel => {
warn("Unknown CPU: '{s}'\nAvailable CPUs for architecture '{s}':\n", .{ warn("Unknown CPU: '{s}'\nAvailable CPUs for architecture '{s}':\n", .{
@ -699,20 +705,63 @@ pub const Builder = struct {
if (args.whitelist) |list| whitelist_check: { if (args.whitelist) |list| whitelist_check: {
// Make sure it's a match of one of the list. // Make sure it's a match of one of the list.
var mismatch_triple = true;
var mismatch_cpu_features = true;
var whitelist_item = CrossTarget{};
for (list) |t| { for (list) |t| {
mismatch_cpu_features = true;
mismatch_triple = true;
const t_triple = t.zigTriple(self.allocator) catch unreachable; const t_triple = t.zigTriple(self.allocator) catch unreachable;
if (mem.eql(u8, t_triple, selected_canonicalized_triple)) { if (mem.eql(u8, t_triple, selected_canonicalized_triple)) {
break :whitelist_check; mismatch_triple = false;
whitelist_item = t;
if (t.getCpuFeatures().subSet(selected_target.getCpuFeatures())) {
mismatch_cpu_features = false;
break :whitelist_check;
} else {
break;
}
} }
} }
warn("Chosen target '{s}' does not match one of the supported targets:\n", .{ if (mismatch_triple) {
selected_canonicalized_triple, warn("Chosen target '{s}' does not match one of the supported targets:\n", .{
}); selected_canonicalized_triple,
for (list) |t| { });
const t_triple = t.zigTriple(self.allocator) catch unreachable; for (list) |t| {
warn(" {s}\n", .{t_triple}); const t_triple = t.zigTriple(self.allocator) catch unreachable;
warn(" {s}\n", .{t_triple});
}
warn("\n", .{});
} else { // mismatch_cpu_features
const whitelist_cpu = whitelist_item.getCpu();
const selected_cpu = selected_target.getCpu();
warn("Chosen CPU model '{s}' does not match one of the supported targets:\n", .{
selected_cpu.model.name,
});
warn(" Supported feature Set: ", .{});
const all_features = whitelist_cpu.arch.allFeaturesList();
var populated_cpu_features = whitelist_cpu.model.features;
populated_cpu_features.populateDependencies(all_features);
for (all_features) |feature, i_usize| {
const i = @intCast(std.Target.Cpu.Feature.Set.Index, i_usize);
const in_cpu_set = populated_cpu_features.isEnabled(i);
if (in_cpu_set) {
warn("{s} ", .{feature.name});
}
}
warn("\n", .{});
warn(" Remove: ", .{});
for (all_features) |feature, i_usize| {
const i = @intCast(std.Target.Cpu.Feature.Set.Index, i_usize);
const in_cpu_set = populated_cpu_features.isEnabled(i);
const in_actual_set = selected_cpu.features.isEnabled(i);
if (in_actual_set and !in_cpu_set) {
warn("{s} ", .{feature.name});
}
}
warn("\n", .{});
} }
warn("\n", .{});
self.markInvalidUserInput(); self.markInvalidUserInput();
return args.default_target; return args.default_target;
} }

View File

@ -664,8 +664,15 @@ pub const Target = struct {
return @ptrCast(*const [byte_count]u8, &set.ints); return @ptrCast(*const [byte_count]u8, &set.ints);
} }
pub fn eql(set: Set, other: Set) bool { pub fn eql(set: Set, other_set: Set) bool {
return mem.eql(usize, &set.ints, &other.ints); return mem.eql(usize, &set.ints, &other_set.ints);
}
/// Is the other set a sub set of this set
pub fn subSet(set: Set, other_set: Set) bool {
return std.meta.eql((@as(std.meta.Vector(usize_count, usize), set.ints) &
@as(std.meta.Vector(usize_count, usize), other_set.ints)),
@as(std.meta.Vector(usize_count, usize), other_set.ints));
} }
}; };