Commit a313f15384
Changed files (4)
src-self-hosted
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