diff --git a/src-self-hosted/stage1.zig b/src-self-hosted/stage1.zig index d01e424b0cac..62eb773dc16a 100644 --- a/src-self-hosted/stage1.zig +++ b/src-self-hosted/stage1.zig @@ -625,6 +625,63 @@ const Stage2TargetDetails = struct { llvm_features_str: [:0]const u8, builtin_str: [:0]const u8, + + const Self = @This(); + + fn initCpu(allocator: *std.mem.Allocator, arch: @TagType(std.Target.Arch), cpu: *const std.target.Cpu) !Self { + var builtin_str_buffer = try std.Buffer.init( + allocator, + "@import(\"std\").target.TargetDetails{.cpu=&@import(\"std\").target."); + defer builtin_str_buffer.deinit(); + + try builtin_str_buffer.append(@tagName(arch)); + try builtin_str_buffer.append(".cpu_"); + try builtin_str_buffer.append(cpu.name); + try builtin_str_buffer.append("};"); + return Self{ + .allocator = allocator, + .target_details = .{ + .cpu = cpu, + }, + .llvm_cpu_str = cpu.name, + .llvm_features_str = "", + .builtin_str = builtin_str_buffer.toOwnedSlice(), + }; + } + + fn initFeatures(allocator: *std.mem.Allocator, arch: @TagType(std.Target.Arch), features: []*const std.target.Feature) !Self { + var builtin_str_buffer = try std.Buffer.init( + allocator, + "@import(\"std\").target.TargetDetails{.features=&[_]*const @import(\"std\").target.Feature{\n"); + defer builtin_str_buffer.deinit(); + + var llvm_features_buffer = try std.Buffer.initSize(allocator, 0); + defer llvm_features_buffer.deinit(); + + for (features) |feature| { + try llvm_features_buffer.append("+"); + try llvm_features_buffer.append(feature.llvm_name); + try llvm_features_buffer.append(","); + + try builtin_str_buffer.append("&@import(\"std\").target."); + try builtin_str_buffer.append(@tagName(arch)); + try builtin_str_buffer.append(".feature_"); + try builtin_str_buffer.append(feature.name); + try builtin_str_buffer.append(","); + } + + try builtin_str_buffer.append("}};"); + + return Self{ + .allocator = allocator, + .target_details = std.target.TargetDetails{ + .features = features, + }, + .llvm_cpu_str = "", + .llvm_features_str = llvm_features_buffer.toOwnedSlice(), + .builtin_str = builtin_str_buffer.toOwnedSlice(), + }; + } }; // ABI warning @@ -658,32 +715,14 @@ export fn stage2_target_details_parse_features(arch_str: ?[*:0]const u8, feature } fn parseCpu(arch: @TagType(std.Target.Arch), str: []const u8) !*Stage2TargetDetails { + const allocator = std.heap.c_allocator; + const cpus = std.target.getCpusForArch(arch); for (cpus) |cpu| { if (std.mem.eql(u8, str, cpu.name)) { - const allocator = std.heap.c_allocator; - - var builtin_str_buffer = try std.Buffer.init( - allocator, - "@import(\"std\").target.TargetDetails{.cpu=&@import(\"std\").target."); - defer builtin_str_buffer.deinit(); - - try builtin_str_buffer.append(@tagName(arch)); - try builtin_str_buffer.append(".cpu_"); - try builtin_str_buffer.append(cpu.name); - try builtin_str_buffer.append("};"); - const ptr = try allocator.create(Stage2TargetDetails); - ptr.* = .{ - .allocator = allocator, - .target_details = .{ - .cpu = cpu, - }, - .llvm_cpu_str = cpu.name, - .llvm_features_str = "", - .builtin_str = builtin_str_buffer.toOwnedSlice(), - }; + ptr.* = try Stage2TargetDetails.initCpu(std.heap.c_allocator, arch, cpu); return ptr; } @@ -700,11 +739,6 @@ fn parseFeatures(arch: @TagType(std.Target.Arch), str: []const u8) !*Stage2Targe var features = std.ArrayList(*const std.target.Feature).init(allocator); defer features.deinit(); - var builtin_str_buffer = try std.Buffer.init( - allocator, - "@import(\"std\").target.TargetDetails{.features=&[_]*const @import(\"std\").target.Feature{\n"); - defer builtin_str_buffer.deinit(); - var start: usize = 0; while (start < str.len) { const next_comma_pos = std.mem.indexOfScalar(u8, str[start..], ',') orelse str.len - start; @@ -725,39 +759,15 @@ fn parseFeatures(arch: @TagType(std.Target.Arch), str: []const u8) !*Stage2Targe if (feature) |f| { features.append(f) catch @panic("out of memory"); - try builtin_str_buffer.append("&@import(\"std\").target."); - try builtin_str_buffer.append(@tagName(arch)); - try builtin_str_buffer.append(".feature_"); - try builtin_str_buffer.append(f.name); - try builtin_str_buffer.append(","); } else { return error.InvalidFeature; } } - try builtin_str_buffer.append("}};"); - const features_slice = features.toOwnedSlice(); - var llvm_features_buffer = try std.Buffer.initSize(allocator, 0); - defer llvm_features_buffer.deinit(); - - for (features_slice) |feature| { - try llvm_features_buffer.append("+"); - try llvm_features_buffer.append(feature.llvm_name); - try llvm_features_buffer.append(","); - } - const ptr = try allocator.create(Stage2TargetDetails); - ptr.* = Stage2TargetDetails{ - .allocator = allocator, - .target_details = std.target.TargetDetails{ - .features = features_slice, - }, - .llvm_cpu_str = "", - .llvm_features_str = llvm_features_buffer.toOwnedSlice(), - .builtin_str = builtin_str_buffer.toOwnedSlice(), - }; + ptr.* = try Stage2TargetDetails.initFeatures(allocator, arch, features_slice); return ptr; } @@ -800,3 +810,68 @@ export fn stage2_target_details_get_builtin_str(target_details: ?*const Stage2Ta return @as([*:0]const u8, ""); } + +const riscv_default_features: []*const std.target.Feature = &[_]*const std.target.Feature { + &std.target.riscv.feature_a, + &std.target.riscv.feature_c, + &std.target.riscv.feature_d, + &std.target.riscv.feature_f, + &std.target.riscv.feature_m, + &std.target.riscv.feature_relax, +}; + +const i386_default_features: []*const std.target.Feature = &[_]*const std.target.Feature { + &std.target.x86.feature_cmov, + &std.target.x86.feature_cx8, + &std.target.x86.feature_fxsr, + &std.target.x86.feature_mmx, + &std.target.x86.feature_nopl, + &std.target.x86.feature_sse, + &std.target.x86.feature_sse2, + &std.target.x86.feature_slowUnalignedMem16, + &std.target.x86.feature_x87, +}; + +// Same as above but without sse. +const i386_default_features_freestanding: []*const std.target.Feature = &[_]*const std.target.Feature { + &std.target.x86.feature_cmov, + &std.target.x86.feature_cx8, + &std.target.x86.feature_fxsr, + &std.target.x86.feature_mmx, + &std.target.x86.feature_nopl, + &std.target.x86.feature_slowUnalignedMem16, + &std.target.x86.feature_x87, +}; + +// ABI warning +export fn stage2_target_details_get_default(arch_str: ?[*:0]const u8, os_str: ?[*:0]const u8) ?*Stage2TargetDetails { + if (arch_str == null) return null; + if (os_str == null) return null; + + const arch = Target.parseArchTag(std.mem.toSliceConst(u8, arch_str.?)) catch return null; + const os = Target.parseOs(std.mem.toSliceConst(u8, os_str.?)) catch return null; + + return createDefaultTargetDetails(arch, os) catch return null; +} + +fn createDefaultTargetDetails(arch: @TagType(std.Target.Arch), os: std.Target.Os) !?*Stage2TargetDetails { + const allocator = std.heap.c_allocator; + + return switch (arch) { + .riscv32, .riscv64 => blk: { + const ptr = try allocator.create(Stage2TargetDetails); + ptr.* = try Stage2TargetDetails.initFeatures(allocator, arch, riscv_default_features); + break :blk ptr; + }, + .i386 => blk: { + const ptr = try allocator.create(Stage2TargetDetails); + const features = switch (os) { + .freestanding => i386_default_features_freestanding, + else => i386_default_features, + }; + ptr.* = try Stage2TargetDetails.initFeatures(allocator, arch, features); + break :blk ptr; + }, + else => null, + }; +} diff --git a/src/codegen.cpp b/src/codegen.cpp index c79a0e5f7c6c..9f4d140b89c3 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -8636,8 +8636,9 @@ static void init(CodeGen *g) { reloc_mode = LLVMRelocStatic; } - const char *target_specific_cpu_args; - const char *target_specific_features; + const char *target_specific_cpu_args = ""; + const char *target_specific_features = ""; + if (g->zig_target->is_native) { // LLVM creates invalid binaries on Windows sometimes. // See https://github.com/ziglang/zig/issues/508 @@ -8649,22 +8650,6 @@ static void init(CodeGen *g) { target_specific_cpu_args = ZigLLVMGetHostCPUName(); target_specific_features = ZigLLVMGetNativeFeatures(); } - } else if (target_is_riscv(g->zig_target)) { - // TODO https://github.com/ziglang/zig/issues/2883 - // Be aware of https://github.com/ziglang/zig/issues/3275 - target_specific_cpu_args = ""; - target_specific_features = riscv_default_features; - } else if (g->zig_target->arch == ZigLLVM_x86) { - // This is because we're really targeting i686 rather than i386. - // It's pretty much impossible to use many of the language features - // such as fp16 if you stick use the x87 only. This is also what clang - // uses as base cpu. - // TODO https://github.com/ziglang/zig/issues/2883 - target_specific_cpu_args = "pentium4"; - target_specific_features = (g->zig_target->os == OsFreestanding) ? "-sse": ""; - } else { - target_specific_cpu_args = ""; - target_specific_features = ""; } // Override CPU and features if defined by user. diff --git a/src/main.cpp b/src/main.cpp index 9ebcfd078547..0d766bd2773d 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1084,6 +1084,12 @@ int main(int argc, char **argv) { fprintf(stderr, "invalid --features value\n"); 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_details = stage2_target_details_get_default(target_arch_name(target.arch), target_os_name(target.os)); + } } if (output_dir != nullptr && enable_cache == CacheOptOn) { diff --git a/src/userland.cpp b/src/userland.cpp index 9481a3f0b3b2..0e173d7e7642 100644 --- a/src/userland.cpp +++ b/src/userland.cpp @@ -109,3 +109,6 @@ const char *stage2_target_details_get_llvm_features(const Stage2TargetDetails *t const char *stage2_target_details_get_builtin_str(const Stage2TargetDetails *target_details) { return ""; } +Stage2TargetDetails *stage2_target_details_get_default(const char *arch, const char *os) { + return nullptr; +} diff --git a/src/userland.h b/src/userland.h index 0315ac11170c..f954efd3fe0d 100644 --- a/src/userland.h +++ b/src/userland.h @@ -201,4 +201,7 @@ ZIG_EXTERN_C const char *stage2_target_details_get_llvm_features(const Stage2Tar // ABI warning ZIG_EXTERN_C const char *stage2_target_details_get_builtin_str(const Stage2TargetDetails *target_details); +// ABI warning +ZIG_EXTERN_C Stage2TargetDetails *stage2_target_details_get_default(const char *arch, const char *os); + #endif