diff --git a/lib/std/target.zig b/lib/std/target.zig index 49913de2ee..e72a1a8452 100644 --- a/lib/std/target.zig +++ b/lib/std/target.zig @@ -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 { diff --git a/src-self-hosted/stage1.zig b/src-self-hosted/stage1.zig index e47103399c..e80b6ba123 100644 --- a/src-self-hosted/stage1.zig +++ b/src-self-hosted/stage1.zig @@ -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 }; }