From a313f153841df8caa3af8fc80966c8f61a856f51 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Sun, 19 Jan 2020 13:52:29 -0500 Subject: [PATCH] figure out zig0/stage1 and scanning for native CPU --- src-self-hosted/stage1.zig | 146 +++++++++++++++++++++++++++---------- src/main.cpp | 32 +++++--- src/userland.cpp | 46 ++++++++---- src/userland.h | 20 +++-- 4 files changed, 172 insertions(+), 72 deletions(-) diff --git a/src-self-hosted/stage1.zig b/src-self-hosted/stage1.zig index 952c7525615f2c3e46abc486064173643b52985f..f0593f8fce67a5a236b3af2a7ec22ed108791300 100644 --- a/src-self-hosted/stage1.zig +++ b/src-self-hosted/stage1.zig @@ -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); - - ptr.* = try Stage2CpuFeatures.initBaseline(std.heap.c_allocator); - errdefer ptr.deinit(); +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; +} - 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 diff --git a/src/main.cpp b/src/main.cpp index 42a3438def09a7d10986d911666bcd5f51850f3d..d5804e795c18578714698e6a9005cb301fe7cbbe 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -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); } } diff --git a/src/userland.cpp b/src/userland.cpp index 89ddecbedb1e12e7a81fadcc6da2d02d883e28cc..93944f0089c5d7f9c4d440b9183827b6a3325b97 100644 --- a/src/userland.cpp +++ b/src/userland.cpp @@ -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(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(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); } diff --git a/src/userland.h b/src/userland.h index 9afa04829918df95b87b061075ba42aa4d8b1315..1fd40039a658a3c751c96e008c605ffa288095dc 100644 --- a/src/userland.h +++ b/src/userland.h @@ -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 -- 2.54.0