don't trust llvm's GetHostCPUName

comment from this commit reproduced here:

I have observed the CPU name reported by LLVM being incorrect. On
the SourceHut build services, LLVM 9.0 reports the CPU as "athlon-xp",
which is a 32-bit CPU, even though the system is 64-bit and the reported
CPU features include, among other things, +64bit.
So the strategy taken here is that we observe both reported CPU, and the
reported CPU features. The features are trusted more; but if the features
match exactly the features of the reported CPU, then we trust the reported CPU.
This commit is contained in:
Andrew Kelley
2020-01-21 22:01:24 -05:00
parent 830e0ba2d2
commit cbe9a51518
2 changed files with 35 additions and 12 deletions

View File

@@ -637,6 +637,10 @@ pub const Target = union(enum) {
pub fn asBytes(set: *const Set) *const [byte_count]u8 {
return @ptrCast(*const [byte_count]u8, &set.ints);
}
pub fn eql(set: Set, other: Set) bool {
return mem.eql(usize, &set.ints, &other.ints);
}
};
pub fn feature_set_fns(comptime F: type) type {

View File

@@ -540,27 +540,25 @@ export fn stage2_progress_update_node(node: *std.Progress.Node, done_count: usiz
node.context.maybeRefresh();
}
/// I have observed the CPU name reported by LLVM being incorrect. On
/// the SourceHut build services, LLVM 9.0 reports the CPU as "athlon-xp",
/// which is a 32-bit CPU, even though the system is 64-bit and the reported
/// CPU features include, among other things, +64bit.
/// So the strategy taken here is that we observe both reported CPU, and the
/// reported CPU features. The features are trusted more; but if the features
/// match exactly the features of the reported CPU, then we trust the reported CPU.
fn cpuFeaturesFromLLVM(
arch: Target.Arch,
llvm_cpu_name_z: ?[*:0]const u8,
llvm_cpu_features_opt: ?[*:0]const u8,
) !Target.CpuFeatures {
if (llvm_cpu_name_z) |cpu_name_z| {
const llvm_cpu_name = mem.toSliceConst(u8, cpu_name_z);
for (arch.allCpus()) |cpu| {
const this_llvm_name = cpu.llvm_name orelse continue;
if (mem.eql(u8, this_llvm_name, llvm_cpu_name)) {
return Target.CpuFeatures{ .cpu = cpu };
}
}
}
var set = arch.baselineFeatures();
const llvm_cpu_features = llvm_cpu_features_opt orelse return Target.CpuFeatures{
.features = set,
};
const all_features = arch.allFeaturesList();
var it = mem.tokenize(mem.toSliceConst(u8, llvm_cpu_features), ",");
while (it.next()) |decorated_llvm_feat| {
var op: enum {
@@ -577,7 +575,7 @@ fn cpuFeaturesFromLLVM(
} else {
return error.InvalidLlvmCpuFeaturesFormat;
}
for (arch.allFeaturesList()) |feature, index| {
for (all_features) |feature, index| {
const this_llvm_name = feature.llvm_name orelse continue;
if (mem.eql(u8, llvm_feat, this_llvm_name)) {
switch (op) {
@@ -588,6 +586,27 @@ fn cpuFeaturesFromLLVM(
}
}
}
if (llvm_cpu_name_z) |cpu_name_z| {
const llvm_cpu_name = mem.toSliceConst(u8, cpu_name_z);
for (arch.allCpus()) |cpu| {
const this_llvm_name = cpu.llvm_name orelse continue;
if (mem.eql(u8, this_llvm_name, llvm_cpu_name)) {
// Only trust the CPU if the reported features exactly match.
var populated_reported_features = set;
populated_reported_features.populateDependencies(all_features);
var populated_cpu_features = cpu.features;
populated_cpu_features.populateDependencies(all_features);
if (populated_reported_features.eql(populated_cpu_features)) {
return Target.CpuFeatures{ .cpu = cpu };
} else {
return Target.CpuFeatures{ .features = set };
}
}
}
}
return Target.CpuFeatures{ .features = set };
}