figure out zig0/stage1 and scanning for native CPU

master
Andrew Kelley 2020-01-19 13:52:29 -05:00
parent a867b43366
commit a313f15384
No known key found for this signature in database
GPG Key ID: 7C5F548F728501A9
4 changed files with 172 additions and 72 deletions

View File

@ -632,24 +632,77 @@ const Stage2CpuFeatures = struct {
const Self = @This();
fn initBaseline(allocator: *mem.Allocator) !Self {
const builtin_str = try std.fmt.allocPrint0(allocator, "CpuFeatures.baseline;\n");
fn createBaseline(allocator: *mem.Allocator) !*Self {
const self = try allocator.create(Self);
errdefer allocator.destroy(self);
const builtin_str = try std.fmt.allocPrint0(allocator, ".baseline;\n");
errdefer allocator.free(builtin_str);
const cache_hash = try std.fmt.allocPrint0(allocator, "\n\n");
errdefer allocator.free(cache_hash);
return Self{
self.* = Self{
.allocator = allocator,
.cpu_features = .{ .cpu = cpu },
.cpu_features = .baseline,
.llvm_cpu_name = null,
.llvm_features_str = null,
.builtin_str = builtin_str,
.cache_hash = cache_hash,
};
return self;
}
fn initCpu(allocator: *mem.Allocator, arch: Target.Arch, cpu: *const Target.Cpu) !Self {
fn createFromLLVM(
allocator: *mem.Allocator,
arch: [*:0]const u8,
llvm_cpu_name_z: [*:0]const u8,
llvm_cpu_features: [*:0]const u8,
) !*Self {
const arch = try Target.parseArchSub(mem.toSliceConst(u8, arch_name));
const llvm_cpu_name = mem.toSliceConst(u8, llvm_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 createFromCpu(allocator, arch, cpu);
}
}
var set = arch.baselineFeatures();
var it = mem.tokenize(mem.toSliceConst(u8, 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 (arch.allFeaturesList()) |feature, index| {
if (mem.eql(u8, feature_name, feature.name)) {
switch (op) {
.add => set |= 1 << index,
.sub => set &= ~@as(Target.Cpu.Feature.Set, 1 << index),
}
break;
}
}
}
return createFromCpuFeatures(allocator, arch, set);
}
fn createFromCpu(allocator: *mem.Allocator, arch: Target.Arch, cpu: *const Target.Cpu) !*Self {
const self = try allocator.create(Self);
errdefer allocator.destroy(self);
const builtin_str = try std.fmt.allocPrint0(
allocator,
"CpuFeatures{{ .cpu = &Arch.{}.cpu.{} }};\n",
@ -661,7 +714,7 @@ const Stage2CpuFeatures = struct {
const cache_hash = try std.fmt.allocPrint0(allocator, "{}\n{x}", cpu.name, cpu.features);
errdefer allocator.free(cache_hash);
return Self{
self.* = Self{
.allocator = allocator,
.cpu_features = .{ .cpu = cpu },
.llvm_cpu_name = cpu.llvm_name,
@ -669,13 +722,17 @@ const Stage2CpuFeatures = struct {
.builtin_str = builtin_str,
.cache_hash = cache_hash,
};
return self;
}
fn initFeatures(
fn createFromCpuFeatures(
allocator: *mem.Allocator,
arch: Target.Arch,
features: Target.Cpu.Feature.Set,
) !Self {
) !*Self {
const self = try allocator.create(Self);
errdefer allocator.destroy(self);
const cache_hash = try std.fmt.allocPrint0(allocator, "\n{x}", features);
errdefer allocator.free(cache_hash);
@ -719,7 +776,7 @@ const Stage2CpuFeatures = struct {
try builtin_str_buffer.append("})};\n");
return Self{
self.* = Self{
.allocator = allocator,
.cpu_features = .{ .features = features },
.llvm_cpu_name = null,
@ -727,68 +784,77 @@ const Stage2CpuFeatures = struct {
.builtin_str = builtin_str_buffer.toOwnedSlice(),
.cache_hash = cache_hash,
};
return self;
}
fn deinit(self: *Self) void {
fn destroy(self: *Self) void {
self.allocator.free(self.cache_hash);
self.allocator.free(self.builtin_str);
if (self.llvm_features_str) |llvm_features_str| self.allocator.free(llvm_features_str);
self.* = undefined;
self.allocator.destroy(self);
}
};
// ABI warning
export fn stage2_cpu_features_parse_cpu(arch_name: [*:0]const u8, cpu_name: [*:0]const u8) *Stage2CpuFeatures {
return parseCpu(arch_name, cpu_name) catch |err| switch (err) {
error.OutOfMemory => @panic("out of memory"),
export fn stage2_cpu_features_parse_cpu(
result: **Stage2CpuFeatures,
arch_name: [*:0]const u8,
cpu_name: [*:0]const u8,
) Error {
result.* = parseCpu(arch_name, cpu_name) catch |err| switch (err) {
error.OutOfMemory => return .OutOfMemory,
};
return .None;
}
fn parseCpu(arch_name: [*:0]const u8, cpu_name: [*:0]const u8) !*Stage2CpuFeatures {
const arch = try Target.parseArchSub(mem.toSliceConst(u8, arch_name));
const cpu = try arch.parseCpu(mem.toSliceConst(u8, cpu_name));
const ptr = try allocator.create(Stage2CpuFeatures);
errdefer std.heap.c_allocator.destroy(ptr);
ptr.* = try Stage2CpuFeatures.initCpu(std.heap.c_allocator, arch, cpu);
errdefer ptr.deinit();
return ptr;
return Stage2CpuFeatures.createFromCpu(std.heap.c_allocator, arch, cpu);
}
// ABI warning
export fn stage2_cpu_features_parse_features(
result: **Stage2CpuFeatures,
arch_name: [*:0]const u8,
features_text: [*:0]const u8,
) *Stage2CpuFeatures {
return parseFeatures(arch_name, features_text) catch |err| switch (err) {
error.OutOfMemory => @panic("out of memory"),
) Error {
result.* = parseFeatures(arch_name, features_text) catch |err| switch (err) {
error.OutOfMemory => return .OutOfMemory,
};
return .None;
}
fn parseFeatures(arch_name: [*:0]const u8, features_text: [*:0]const u8) !*Stage2CpuFeatures {
const arch = try Target.parseArchSub(mem.toSliceConst(u8, arch_name));
const set = try arch.parseCpuFeatureSet(mem.toSliceConst(u8, features_text));
const ptr = try std.heap.c_allocator.create(Stage2CpuFeatures);
errdefer std.heap.c_allocator.destroy(ptr);
ptr.* = try Stage2CpuFeatures.initFeatures(std.heap.c_allocator, arch, set);
errdefer ptr.deinit();
return ptr;
return Stage2CpuFeatures.createFromCpuFeatures(std.heap.c_allocator, arch, set);
}
// ABI warning
export fn stage2_cpu_features_baseline() *Stage2CpuFeatures {
const ptr = try std.heap.c_allocator.create(Stage2CpuFeatures);
errdefer std.heap.c_allocator.destroy(ptr);
export fn stage2_cpu_features_baseline(result: **Stage2CpuFeatures) Error {
result.* = Stage2CpuFeatures.createBaseline(std.heap.c_allocator) catch |err| switch (err) {
error.OutOfMemory => return .OutOfMemory,
};
return .None;
}
ptr.* = try Stage2CpuFeatures.initBaseline(std.heap.c_allocator);
errdefer ptr.deinit();
return ptr;
// ABI warning
export fn stage2_cpu_features_llvm(
result: **Stage2CpuFeatures,
arch_name: [*:0]const u8,
llvm_cpu_name: [*:0]const u8,
llvm_cpu_features: [*:0]const u8,
) Error {
result.* = Stage2CpuFeatures.createFromLLVM(
std.heap.c_allocator,
arch_name,
llvm_cpu_name,
llvm_cpu_features,
) catch |err| switch (err) {
error.OutOfMemory => return .OutOfMemory,
};
return .None;
}
// ABI warning

View File

@ -100,8 +100,8 @@ static int print_full_usage(const char *arg0, FILE *file, int return_code) {
" --override-lib-dir [arg] override path to Zig lib directory\n"
" -ffunction-sections places each function in a separate section\n"
" -D[macro]=[value] define C [macro] to [value] (1 if [value] omitted)\n"
" --cpu [cpu] compile for [cpu] on the current target\n"
" --features [feature_str] compile with features in [feature_str] on the current target\n"
" -target-cpu [cpu] target one specific CPU by name\n"
" -target-feature [features] specify the set of CPU features to target\n"
"\n"
"Link Options:\n"
" --bundle-compiler-rt for static libraries, include compiler-rt symbols\n"
@ -1078,22 +1078,30 @@ int main(int argc, char **argv) {
fprintf(stderr, "-target-cpu and -target-feature options not allowed together\n");
return main_exit(root_progress_node, EXIT_FAILURE);
} else if (cpu) {
target.cpu_features = stage2_cpu_features_parse_cpu(target_arch_name(target.arch), cpu);
if (!target.cpu_features) {
fprintf(stderr, "invalid -target-cpu value\n");
if ((err = stage2_cpu_features_parse_cpu(&target.cpu_features, target_arch_name(target.arch), cpu))) {
fprintf(stderr, "-target-cpu error: %s\n", err_str(err));
return main_exit(root_progress_node, EXIT_FAILURE);
}
} else if (features) {
target.cpu_features = stage2_cpu_features_parse_features(target_arch_name(target.arch), features);
if (!target.cpu_features) {
fprintf(stderr, "invalid -target-feature value\n");
if ((err = stage2_cpu_features_parse_features(&target.cpu_features, target_arch_name(target.arch),
features)))
{
fprintf(stderr, "-target-feature error: %s\n", err_str(err));
return main_exit(root_progress_node, EXIT_FAILURE);
}
} else if (target.is_native) {
const char *cpu_name = ZigLLVMGetHostCPUName();
const char *cpu_features = ZigLLVMGetNativeFeatures();
if ((err = stage2_cpu_features_llvm(&target.cpu_features, target_arch_name(target.arch),
cpu_name, cpu_features)))
{
fprintf(stderr, "unable to determine native CPU features: %s\n", err_str(err));
return main_exit(root_progress_node, EXIT_FAILURE);
}
} else {
// If no details are specified and we are not native, load
// cross-compilation default features.
if (!target.is_native) {
target.cpu_features = stage2_cpu_features_baseline();
if ((err = stage2_cpu_features_baseline(&target.cpu_features))) {
fprintf(stderr, "unable to determine baseline CPU features: %s\n", err_str(err));
return main_exit(root_progress_node, EXIT_FAILURE);
}
}

View File

@ -98,35 +98,55 @@ void stage2_list_cpus_for_arch(const char *arch_name_ptr, size_t arch_name_len,
const char *msg = "stage0 called stage2_list_cpus_for_arch";
stage2_panic(msg, strlen(msg));
}
Stage2CpuFeatures *stage2_cpu_features_parse_cpu(const char *arch, const char *str) {
struct Stage2CpuFeatures {
const char *llvm_cpu_name;
const char *llvm_cpu_features;
const char *builtin_str;
const char *cache_hash;
};
Error stage2_cpu_features_parse_cpu(Stage2CpuFeatures **out, const char *arch, const char *str) {
const char *msg = "stage0 called stage2_cpu_features_parse_cpu";
stage2_panic(msg, strlen(msg));
}
Stage2CpuFeatures *stage2_cpu_features_parse_features(const char *arch, const char *str) {
Error stage2_cpu_features_parse_features(Stage2CpuFeatures **out, const char *arch, const char *str) {
const char *msg = "stage0 called stage2_cpu_features_parse_features";
stage2_panic(msg, strlen(msg));
}
Stage2CpuFeatures *stage2_cpu_features_baseline(void) {
const char *msg = "stage0 called stage2_cpu_features_baseline";
stage2_panic(msg, strlen(msg));
Error stage2_cpu_features_baseline(Stage2CpuFeatures **out) {
Stage2CpuFeatures *result = allocate<Stage2CpuFeatures>(1, "Stage2CpuFeatures");
result->builtin_str = ".baseline;\n";
result->cache_hash = "\n\n";
*out = result;
return ErrorNone;
}
Error stage2_cpu_features_llvm(Stage2CpuFeatures **out, const char *arch,
const char *llvm_cpu_name, const char *llvm_features)
{
Stage2CpuFeatures *result = allocate<Stage2CpuFeatures>(1, "Stage2CpuFeatures");
result->llvm_cpu_name = llvm_cpu_name;
result->llvm_cpu_features = llvm_features;
result->builtin_str = ".baseline;\n";
result->cache_hash = "native\n\n";
*out = result;
return ErrorNone;
}
void stage2_cpu_features_get_cache_hash(const Stage2CpuFeatures *cpu_features,
const char **ptr, size_t *len)
{
const char *msg = "stage0 called stage2_cpu_features_get_cache_hash";
stage2_panic(msg, strlen(msg));
*ptr = cpu_features->cache_hash;
*len = strlen(cpu_features->cache_hash);
}
const char *stage2_cpu_features_get_llvm_cpu(const Stage2CpuFeatures *cpu_features) {
const char *msg = "stage0 called stage2_cpu_features_get_llvm_cpu";
stage2_panic(msg, strlen(msg));
return cpu_features->llvm_cpu_name;
}
const char *stage2_cpu_features_get_llvm_features(const Stage2CpuFeatures *cpu_features) {
const char *msg = "stage0 called stage2_cpu_features_get_llvm_features";
stage2_panic(msg, strlen(msg));
return cpu_features->llvm_cpu_features;
}
void stage2_cpu_features_get_builtin_str(const Stage2CpuFeatures *cpu_features,
const char **ptr, size_t *len)
{
const char *msg = "stage0 called stage2_cpu_features_get_builtin_str";
stage2_panic(msg, strlen(msg));
*ptr = cpu_features->builtin_str;
*len = strlen(cpu_features->builtin_str);
}

View File

@ -184,26 +184,32 @@ ZIG_EXTERN_C void stage2_list_cpus_for_arch(const char *arch_name_ptr, size_t ar
struct Stage2CpuFeatures;
// ABI warning
ZIG_EXTERN_C Stage2CpuFeatures *stage2_cpu_features_parse_cpu(const char *arch, const char *cpu_name);
ZIG_EXTERN_C Error stage2_cpu_features_parse_cpu(struct Stage2CpuFeatures **result,
const char *arch, const char *cpu_name);
// ABI warning
ZIG_EXTERN_C Stage2CpuFeatures *stage2_cpu_features_parse_features(const char *arch, const char *features);
ZIG_EXTERN_C Error stage2_cpu_features_parse_features(struct Stage2CpuFeatures **result,
const char *arch, const char *features);
// ABI warning
ZIG_EXTERN_C Stage2CpuFeatures *stage2_cpu_features_baseline(void);
ZIG_EXTERN_C Error stage2_cpu_features_baseline(struct Stage2CpuFeatures **result);
// ABI warning
ZIG_EXTERN_C const char *stage2_cpu_features_get_llvm_cpu(const Stage2CpuFeatures *cpu_features);
ZIG_EXTERN_C Error stage2_cpu_features_llvm(struct Stage2CpuFeatures **result,
const char *arch, const char *llvm_cpu_name, const char *llvm_features);
// ABI warning
ZIG_EXTERN_C const char *stage2_cpu_features_get_llvm_features(const Stage2CpuFeatures *cpu_features);
ZIG_EXTERN_C const char *stage2_cpu_features_get_llvm_cpu(const struct Stage2CpuFeatures *cpu_features);
// ABI warning
ZIG_EXTERN_C void stage2_cpu_features_get_builtin_str(const Stage2CpuFeatures *cpu_features,
ZIG_EXTERN_C const char *stage2_cpu_features_get_llvm_features(const struct Stage2CpuFeatures *cpu_features);
// ABI warning
ZIG_EXTERN_C void stage2_cpu_features_get_builtin_str(const struct Stage2CpuFeatures *cpu_features,
const char **ptr, size_t *len);
// ABI warning
ZIG_EXTERN_C void stage2_cpu_features_get_cache_hash(const Stage2CpuFeatures *cpu_features,
ZIG_EXTERN_C void stage2_cpu_features_get_cache_hash(const struct Stage2CpuFeatures *cpu_features,
const char **ptr, size_t *len);
#endif