Commit a313f15384

Andrew Kelley <andrew@ziglang.org>
2020-01-19 19:52:29
figure out zig0/stage1 and scanning for native CPU
1 parent a867b43
Changed files (4)
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);
         }
     }
 
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<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);
 }
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
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 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 initCpu(allocator: *mem.Allocator, arch: Target.Arch, cpu: *const Target.Cpu) !Self {
+    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