mirror of
https://github.com/ziglang/zig.git
synced 2026-02-12 20:37:54 +00:00
add detect-cpu subcommand for debugging CPU features
This brings back `detectNativeCpuWithLLVM` so that we can troubleshoot during LLVM upgrades. closes #19793
This commit is contained in:
parent
06ee65af9e
commit
78002dbe47
@ -400,3 +400,9 @@ extern fn ZigLLVMWriteImportLibrary(
|
||||
output_lib_path: [*:0]const u8,
|
||||
kill_at: bool,
|
||||
) bool;
|
||||
|
||||
pub const GetHostCPUName = LLVMGetHostCPUName;
|
||||
extern fn LLVMGetHostCPUName() ?[*:0]u8;
|
||||
|
||||
pub const GetHostCPUFeatures = LLVMGetHostCPUFeatures;
|
||||
extern fn LLVMGetHostCPUFeatures() ?[*:0]u8;
|
||||
|
||||
142
src/main.zig
142
src/main.zig
@ -117,6 +117,7 @@ const debug_usage = normal_usage ++
|
||||
\\
|
||||
\\ changelist Compute mappings from old ZIR to new ZIR
|
||||
\\ dump-zir Dump a file containing cached ZIR
|
||||
\\ detect-cpu Compare Zig's CPU feature detection vs LLVM
|
||||
\\
|
||||
;
|
||||
|
||||
@ -352,6 +353,8 @@ fn mainArgs(gpa: Allocator, arena: Allocator, args: []const []const u8) !void {
|
||||
return io.getStdOut().writeAll(usage);
|
||||
} else if (mem.eql(u8, cmd, "ast-check")) {
|
||||
return cmdAstCheck(gpa, arena, cmd_args);
|
||||
} else if (mem.eql(u8, cmd, "detect-cpu")) {
|
||||
return cmdDetectCpu(gpa, arena, cmd_args);
|
||||
} else if (build_options.enable_debug_extensions and mem.eql(u8, cmd, "changelist")) {
|
||||
return cmdChangelist(gpa, arena, cmd_args);
|
||||
} else if (build_options.enable_debug_extensions and mem.eql(u8, cmd, "dump-zir")) {
|
||||
@ -6150,6 +6153,145 @@ fn cmdAstCheck(
|
||||
return @import("print_zir.zig").renderAsTextToFile(gpa, &file, io.getStdOut());
|
||||
}
|
||||
|
||||
fn cmdDetectCpu(
|
||||
gpa: Allocator,
|
||||
arena: Allocator,
|
||||
args: []const []const u8,
|
||||
) !void {
|
||||
_ = gpa;
|
||||
_ = arena;
|
||||
|
||||
const detect_cpu_usage =
|
||||
\\Usage: zig detect-cpu [--llvm]
|
||||
\\
|
||||
\\ Print the host CPU name and feature set to stdout.
|
||||
\\
|
||||
\\Options:
|
||||
\\ -h, --help Print this help and exit
|
||||
\\ --llvm Detect using LLVM API
|
||||
\\
|
||||
;
|
||||
|
||||
var use_llvm = false;
|
||||
|
||||
{
|
||||
var i: usize = 0;
|
||||
while (i < args.len) : (i += 1) {
|
||||
const arg = args[i];
|
||||
if (mem.startsWith(u8, arg, "-")) {
|
||||
if (mem.eql(u8, arg, "-h") or mem.eql(u8, arg, "--help")) {
|
||||
const stdout = io.getStdOut().writer();
|
||||
try stdout.writeAll(detect_cpu_usage);
|
||||
return cleanExit();
|
||||
} else if (mem.eql(u8, arg, "--llvm")) {
|
||||
use_llvm = true;
|
||||
} else {
|
||||
fatal("unrecognized parameter: '{s}'", .{arg});
|
||||
}
|
||||
} else {
|
||||
fatal("unexpected extra parameter: '{s}'", .{arg});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (use_llvm) {
|
||||
if (!build_options.have_llvm)
|
||||
fatal("compiler does not use LLVM; cannot compare CPU features with LLVM", .{});
|
||||
|
||||
const llvm = @import("codegen/llvm/bindings.zig");
|
||||
const name = llvm.GetHostCPUName() orelse fatal("LLVM could not figure out the host cpu name", .{});
|
||||
const features = llvm.GetHostCPUFeatures() orelse fatal("LLVM could not figure out the host cpu feature set", .{});
|
||||
const cpu = try detectNativeCpuWithLLVM(builtin.cpu.arch, name, features);
|
||||
try printCpu(cpu);
|
||||
} else {
|
||||
const host_target = std.zig.resolveTargetQueryOrFatal(.{});
|
||||
try printCpu(host_target.cpu);
|
||||
}
|
||||
}
|
||||
|
||||
fn detectNativeCpuWithLLVM(
|
||||
arch: std.Target.Cpu.Arch,
|
||||
llvm_cpu_name_z: ?[*:0]const u8,
|
||||
llvm_cpu_features_opt: ?[*:0]const u8,
|
||||
) !std.Target.Cpu {
|
||||
var result = std.Target.Cpu.baseline(arch);
|
||||
|
||||
if (llvm_cpu_name_z) |cpu_name_z| {
|
||||
const llvm_cpu_name = mem.span(cpu_name_z);
|
||||
|
||||
for (arch.allCpuModels()) |model| {
|
||||
const this_llvm_name = model.llvm_name orelse continue;
|
||||
if (mem.eql(u8, this_llvm_name, llvm_cpu_name)) {
|
||||
// Here we use the non-dependencies-populated set,
|
||||
// so that subtracting features later in this function
|
||||
// affect the prepopulated set.
|
||||
result = std.Target.Cpu{
|
||||
.arch = arch,
|
||||
.model = model,
|
||||
.features = model.features,
|
||||
};
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const all_features = arch.allFeaturesList();
|
||||
|
||||
if (llvm_cpu_features_opt) |llvm_cpu_features| {
|
||||
var it = mem.tokenizeScalar(u8, mem.span(llvm_cpu_features), ',');
|
||||
while (it.next()) |decorated_llvm_feat| {
|
||||
var op: enum {
|
||||
add,
|
||||
sub,
|
||||
} = undefined;
|
||||
var llvm_feat: []const u8 = undefined;
|
||||
if (mem.startsWith(u8, decorated_llvm_feat, "+")) {
|
||||
op = .add;
|
||||
llvm_feat = decorated_llvm_feat[1..];
|
||||
} else if (mem.startsWith(u8, decorated_llvm_feat, "-")) {
|
||||
op = .sub;
|
||||
llvm_feat = decorated_llvm_feat[1..];
|
||||
} else {
|
||||
return error.InvalidLlvmCpuFeaturesFormat;
|
||||
}
|
||||
for (all_features, 0..) |feature, index_usize| {
|
||||
const this_llvm_name = feature.llvm_name orelse continue;
|
||||
if (mem.eql(u8, llvm_feat, this_llvm_name)) {
|
||||
const index: std.Target.Cpu.Feature.Set.Index = @intCast(index_usize);
|
||||
switch (op) {
|
||||
.add => result.features.addFeature(index),
|
||||
.sub => result.features.removeFeature(index),
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
result.features.populateDependencies(all_features);
|
||||
return result;
|
||||
}
|
||||
|
||||
fn printCpu(cpu: std.Target.Cpu) !void {
|
||||
var bw = io.bufferedWriter(io.getStdOut().writer());
|
||||
const stdout = bw.writer();
|
||||
|
||||
if (cpu.model.llvm_name) |llvm_name| {
|
||||
try stdout.print("{s}\n", .{llvm_name});
|
||||
}
|
||||
|
||||
const all_features = cpu.arch.allFeaturesList();
|
||||
for (all_features, 0..) |feature, index_usize| {
|
||||
const llvm_name = feature.llvm_name orelse continue;
|
||||
const index: std.Target.Cpu.Feature.Set.Index = @intCast(index_usize);
|
||||
const is_enabled = cpu.features.isEnabled(index);
|
||||
const plus_or_minus = "-+"[@intFromBool(is_enabled)];
|
||||
try stdout.print("{c}{s}\n", .{ plus_or_minus, llvm_name });
|
||||
}
|
||||
|
||||
try bw.flush();
|
||||
}
|
||||
|
||||
/// This is only enabled for debug builds.
|
||||
fn cmdDumpZir(
|
||||
gpa: Allocator,
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user