commit 4fba7336a9038b4abf647caf822f89df717d3cc0 (tree)
parent 218cf059dd215282aa96d6b4715e68d533a4238e
Author: Andrew Kelley <andrew@ziglang.org>
Date: Wed, 11 Sep 2024 17:41:55 -0700
Merge pull request #21269 from alexrp/soft-float
Fix soft float support, split musl triples by float ABI, and enable CI
Diffstat:
13 files changed, 251 insertions(+), 43 deletions(-)
diff --git a/lib/compiler_rt/truncdfhf2.zig b/lib/compiler_rt/truncdfhf2.zig
@@ -6,9 +6,8 @@ pub const panic = common.panic;
comptime {
if (common.want_aeabi) {
@export(&__aeabi_d2h, .{ .name = "__aeabi_d2h", .linkage = common.linkage, .visibility = common.visibility });
- } else {
- @export(&__truncdfhf2, .{ .name = "__truncdfhf2", .linkage = common.linkage, .visibility = common.visibility });
}
+ @export(&__truncdfhf2, .{ .name = "__truncdfhf2", .linkage = common.linkage, .visibility = common.visibility });
}
pub fn __truncdfhf2(a: f64) callconv(.C) common.F16T(f64) {
diff --git a/lib/std/Target.zig b/lib/std/Target.zig
@@ -765,12 +765,13 @@ pub const Abi = enum {
pub inline fn floatAbi(abi: Abi) FloatAbi {
return switch (abi) {
- .gnueabihf,
- .eabihf,
- .musleabihf,
- => .hard,
- .ohos => .soft,
- else => .soft,
+ .eabi,
+ .gnueabi,
+ .musleabi,
+ .gnusf,
+ .ohos,
+ => .soft,
+ else => .hard,
};
}
};
@@ -1645,7 +1646,7 @@ pub const FloatAbi = enum {
soft,
};
-pub inline fn getFloatAbi(target: Target) FloatAbi {
+pub inline fn floatAbi(target: Target) FloatAbi {
return target.abi.floatAbi();
}
diff --git a/lib/std/math/gamma.zig b/lib/std/math/gamma.zig
@@ -3,6 +3,7 @@
//
// https://git.musl-libc.org/cgit/musl/tree/src/math/tgamma.c
+const builtin = @import("builtin");
const std = @import("../std.zig");
/// Returns the gamma function of x,
@@ -262,6 +263,8 @@ test gamma {
}
test "gamma.special" {
+ if (builtin.cpu.arch.isArmOrThumb() and builtin.target.floatAbi() == .soft) return error.SkipZigTest; // https://github.com/ziglang/zig/issues/21234
+
inline for (&.{ f32, f64 }) |T| {
try expect(std.math.isNan(gamma(T, -std.math.nan(T))));
try expect(std.math.isNan(gamma(T, std.math.nan(T))));
diff --git a/lib/std/zig/system.zig b/lib/std/zig/system.zig
@@ -384,6 +384,12 @@ pub fn resolveTargetQuery(query: Target.Query) DetectError!Target {
query.cpu_features_add,
query.cpu_features_sub,
);
+
+ // https://github.com/llvm/llvm-project/issues/105978
+ if (result.cpu.arch.isArmOrThumb() and result.floatAbi() == .soft) {
+ result.cpu.features.removeFeature(@intFromEnum(Target.arm.Feature.vfp2));
+ }
+
return result;
}
diff --git a/lib/std/zig/target.zig b/lib/std/zig/target.zig
@@ -46,17 +46,20 @@ pub const available_libcs = [_]ArchOsAbi{
.{ .arch = .mips64, .os = .linux, .abi = .musl },
.{ .arch = .mipsel, .os = .linux, .abi = .gnueabi },
.{ .arch = .mipsel, .os = .linux, .abi = .gnueabihf },
- .{ .arch = .mipsel, .os = .linux, .abi = .musl },
+ .{ .arch = .mipsel, .os = .linux, .abi = .musleabi },
+ .{ .arch = .mipsel, .os = .linux, .abi = .musleabihf },
.{ .arch = .mips, .os = .linux, .abi = .gnueabi },
.{ .arch = .mips, .os = .linux, .abi = .gnueabihf },
- .{ .arch = .mips, .os = .linux, .abi = .musl },
+ .{ .arch = .mips, .os = .linux, .abi = .musleabi },
+ .{ .arch = .mips, .os = .linux, .abi = .musleabihf },
.{ .arch = .powerpc64le, .os = .linux, .abi = .gnu, .glibc_min = .{ .major = 2, .minor = 19, .patch = 0 } },
.{ .arch = .powerpc64le, .os = .linux, .abi = .musl },
.{ .arch = .powerpc64, .os = .linux, .abi = .gnu },
.{ .arch = .powerpc64, .os = .linux, .abi = .musl },
.{ .arch = .powerpc, .os = .linux, .abi = .gnueabi },
.{ .arch = .powerpc, .os = .linux, .abi = .gnueabihf },
- .{ .arch = .powerpc, .os = .linux, .abi = .musl },
+ .{ .arch = .powerpc, .os = .linux, .abi = .musleabi },
+ .{ .arch = .powerpc, .os = .linux, .abi = .musleabihf },
.{ .arch = .riscv32, .os = .linux, .abi = .gnu, .glibc_min = .{ .major = 2, .minor = 33, .patch = 0 } },
.{ .arch = .riscv32, .os = .linux, .abi = .musl },
.{ .arch = .riscv64, .os = .linux, .abi = .gnu, .glibc_min = .{ .major = 2, .minor = 27, .patch = 0 } },
diff --git a/src/Compilation.zig b/src/Compilation.zig
@@ -5484,6 +5484,9 @@ pub fn addCCArgs(
const is_enabled = target.cpu.features.isEnabled(index);
if (feature.llvm_name) |llvm_name| {
+ // We communicate float ABI to Clang through the dedicated options further down.
+ if (std.mem.eql(u8, llvm_name, "soft-float")) continue;
+
argv.appendSliceAssumeCapacity(&[_][]const u8{ "-Xclang", "-target-feature", "-Xclang" });
const plus_or_minus = "-+"[@intFromBool(is_enabled)];
const arg = try std.fmt.allocPrint(arena, "{c}{s}", .{ plus_or_minus, llvm_name });
@@ -5705,10 +5708,6 @@ pub fn addCCArgs(
if (target.cpu.model.llvm_name) |llvm_name| {
try argv.append(try std.fmt.allocPrint(arena, "-march={s}", .{llvm_name}));
}
-
- if (std.Target.mips.featureSetHas(target.cpu.features, .soft_float)) {
- try argv.append("-msoft-float");
- }
},
else => {
// TODO
@@ -5751,6 +5750,28 @@ pub fn addCCArgs(
try argv.append(try std.fmt.allocPrint(arena, "-mabi={s}", .{mabi}));
}
+ // We might want to support -mfloat-abi=softfp for Arm and CSKY here in the future.
+ if (target_util.clangSupportsFloatAbiArg(target)) {
+ const fabi = @tagName(target.floatAbi());
+
+ try argv.append(switch (target.cpu.arch) {
+ // For whatever reason, Clang doesn't support `-mfloat-abi` for s390x.
+ .s390x => try std.fmt.allocPrint(arena, "-m{s}-float", .{fabi}),
+ else => try std.fmt.allocPrint(arena, "-mfloat-abi={s}", .{fabi}),
+ });
+ }
+
+ if (target_util.clangSupportsNoImplicitFloatArg(target) and target.floatAbi() == .soft) {
+ try argv.append("-mno-implicit-float");
+ }
+
+ // https://github.com/llvm/llvm-project/issues/105972
+ if (target.cpu.arch.isPowerPC() and target.floatAbi() == .soft) {
+ try argv.append("-D__NO_FPRS__");
+ try argv.append("-D_SOFT_FLOAT");
+ try argv.append("-D_SOFT_DOUBLE");
+ }
+
if (out_dep_path) |p| {
try argv.appendSlice(&[_][]const u8{ "-MD", "-MV", "-MF", p });
}
diff --git a/src/codegen/llvm.zig b/src/codegen/llvm.zig
@@ -1285,8 +1285,7 @@ pub const Object = struct {
.large => .Large,
};
- // TODO handle float ABI better- it should depend on the ABI portion of std.Target
- const float_abi: llvm.ABIType = .Default;
+ const float_abi: llvm.ABIType = if (comp.root_mod.resolved_target.result.floatAbi() == .hard) .Hard else .Soft;
var target_machine = llvm.TargetMachine.create(
target,
@@ -3110,6 +3109,30 @@ pub const Object = struct {
.value = .empty,
} }, &o.builder);
}
+ if (target.floatAbi() == .soft) {
+ // `use-soft-float` means "use software routines for floating point computations". In
+ // other words, it configures how LLVM lowers basic float instructions like `fcmp`,
+ // `fadd`, etc. The float calling convention is configured on `TargetMachine` and is
+ // mostly an orthogonal concept, although obviously we do need hardware float operations
+ // to actually be able to pass float values in float registers.
+ //
+ // Ideally, we would support something akin to the `-mfloat-abi=softfp` option that GCC
+ // and Clang support for Arm32 and CSKY. We don't currently expose such an option in
+ // Zig, and using CPU features as the source of truth for this makes for a miserable
+ // user experience since people expect e.g. `arm-linux-gnueabi` to mean full soft float
+ // unless the compiler has explicitly been told otherwise. (And note that our baseline
+ // CPU models almost all include FPU features!)
+ //
+ // Revisit this at some point.
+ try attributes.addFnAttr(.{ .string = .{
+ .kind = try o.builder.string("use-soft-float"),
+ .value = try o.builder.string("true"),
+ } }, &o.builder);
+
+ // This prevents LLVM from using FPU/SIMD code for things like `memcpy`. As for the
+ // above, this should be revisited if `softfp` support is added.
+ try attributes.addFnAttr(.noimplicitfloat, &o.builder);
+ }
}
fn resolveGlobalUav(
@@ -12423,6 +12446,11 @@ fn backendSupportsF16(target: std.Target) bool {
.riscv32,
.s390x,
=> false,
+ .arm,
+ .armeb,
+ .thumb,
+ .thumbeb,
+ => target.floatAbi() == .soft or std.Target.arm.featureSetHas(target.cpu.features, .fp_armv8),
.aarch64,
.aarch64_be,
=> std.Target.aarch64.featureSetHas(target.cpu.features, .fp_armv8),
@@ -12445,6 +12473,11 @@ fn backendSupportsF128(target: std.Target) bool {
.powerpc64,
.powerpc64le,
=> target.os.tag != .aix,
+ .arm,
+ .armeb,
+ .thumb,
+ .thumbeb,
+ => target.floatAbi() == .soft or std.Target.arm.featureSetHas(target.cpu.features, .fp_armv8),
.aarch64,
.aarch64_be,
=> std.Target.aarch64.featureSetHas(target.cpu.features, .fp_armv8),
diff --git a/src/musl.zig b/src/musl.zig
@@ -387,6 +387,7 @@ fn addCcArgs(
"-fno-builtin",
"-fexcess-precision=standard",
"-frounding-math",
+ "-ffp-contract=off",
"-fno-strict-aliasing",
"-Wa,--noexecstack",
"-D_XOPEN_SOURCE=700",
diff --git a/src/target.zig b/src/target.zig
@@ -339,6 +339,48 @@ pub fn clangAssemblerSupportsMcpuArg(target: std.Target) bool {
};
}
+pub fn clangSupportsFloatAbiArg(target: std.Target) bool {
+ return switch (target.cpu.arch) {
+ .arm,
+ .armeb,
+ .thumb,
+ .thumbeb,
+ .csky,
+ .mips,
+ .mipsel,
+ .mips64,
+ .mips64el,
+ .powerpc,
+ .powerpcle,
+ .powerpc64,
+ .powerpc64le,
+ .s390x,
+ .sparc,
+ .sparc64,
+ => true,
+ // We use the target triple for LoongArch.
+ .loongarch32, .loongarch64 => false,
+ else => false,
+ };
+}
+
+pub fn clangSupportsNoImplicitFloatArg(target: std.Target) bool {
+ return switch (target.cpu.arch) {
+ .aarch64,
+ .aarch64_be,
+ .arm,
+ .armeb,
+ .thumb,
+ .thumbeb,
+ .riscv32,
+ .riscv64,
+ .x86,
+ .x86_64,
+ => true,
+ else => false,
+ };
+}
+
pub fn needUnwindTables(target: std.Target) bool {
return target.os.tag == .windows or target.isDarwin() or std.debug.Dwarf.abi.supportsUnwinding(target);
}
diff --git a/test/behavior/floatop.zig b/test/behavior/floatop.zig
@@ -126,6 +126,7 @@ test "cmp f16" {
if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf and builtin.target.ofmt != .macho) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
+ if (builtin.cpu.arch.isArmOrThumb() and builtin.target.floatAbi() == .soft) return error.SkipZigTest; // https://github.com/ziglang/zig/issues/21234
try testCmp(f16);
try comptime testCmp(f16);
@@ -134,6 +135,7 @@ test "cmp f16" {
test "cmp f32/f64" {
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf and builtin.target.ofmt != .macho) return error.SkipZigTest;
+ if (builtin.cpu.arch.isArmOrThumb() and builtin.target.floatAbi() == .soft) return error.SkipZigTest; // https://github.com/ziglang/zig/issues/21234
try testCmp(f32);
try comptime testCmp(f32);
diff --git a/test/behavior/math.zig b/test/behavior/math.zig
@@ -1597,6 +1597,7 @@ test "NaN comparison" {
if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf and builtin.target.ofmt != .macho) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
+ if (builtin.cpu.arch.isArmOrThumb() and builtin.target.floatAbi() == .soft) return error.SkipZigTest; // https://github.com/ziglang/zig/issues/21234
try testNanEqNan(f16);
try testNanEqNan(f32);
diff --git a/test/behavior/vector.zig b/test/behavior/vector.zig
@@ -1409,7 +1409,14 @@ test "store vector with memset" {
if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_llvm) {
+ // LLVM 16 ERROR: "Converting bits to bytes lost precision"
+ // https://github.com/ziglang/zig/issues/16177
switch (builtin.target.cpu.arch) {
+ .arm,
+ .armeb,
+ .thumb,
+ .thumbeb,
+ => if (builtin.target.floatAbi() == .soft) return error.SkipZigTest,
.wasm32,
.mips,
.mipsel,
@@ -1418,11 +1425,7 @@ test "store vector with memset" {
.riscv64,
.powerpc,
.powerpc64,
- => {
- // LLVM 16 ERROR: "Converting bits to bytes lost precision"
- // https://github.com/ziglang/zig/issues/16177
- return error.SkipZigTest;
- },
+ => return error.SkipZigTest,
else => {},
}
}
diff --git a/test/tests.zig b/test/tests.zig
@@ -291,23 +291,49 @@ const test_targets = blk: {
},
.{
- .target = std.Target.Query.parse(.{
- .arch_os_abi = "arm-linux-none",
- .cpu_features = "generic+v8a",
- }) catch unreachable,
+ .target = .{
+ .cpu_arch = .arm,
+ .os_tag = .linux,
+ .abi = .eabi,
+ },
+ },
+ .{
+ .target = .{
+ .cpu_arch = .arm,
+ .os_tag = .linux,
+ .abi = .eabihf,
+ },
+ },
+ .{
+ .target = .{
+ .cpu_arch = .arm,
+ .os_tag = .linux,
+ .abi = .musleabi,
+ },
+ .link_libc = true,
+ },
+ .{
+ .target = .{
+ .cpu_arch = .arm,
+ .os_tag = .linux,
+ .abi = .musleabihf,
+ },
+ .link_libc = true,
},
.{
- .target = std.Target.Query.parse(.{
- .arch_os_abi = "arm-linux-musleabihf",
- .cpu_features = "generic+v8a",
- }) catch unreachable,
+ .target = .{
+ .cpu_arch = .arm,
+ .os_tag = .linux,
+ .abi = .gnueabi,
+ },
.link_libc = true,
},
.{
- .target = std.Target.Query.parse(.{
- .arch_os_abi = "arm-linux-gnueabihf",
- .cpu_features = "generic+v8a",
- }) catch unreachable,
+ .target = .{
+ .cpu_arch = .arm,
+ .os_tag = .linux,
+ .abi = .gnueabihf,
+ },
.link_libc = true,
},
@@ -315,7 +341,7 @@ const test_targets = blk: {
.target = .{
.cpu_arch = .mips,
.os_tag = .linux,
- .abi = .none,
+ .abi = .eabi,
},
.slow_backend = true,
},
@@ -323,7 +349,33 @@ const test_targets = blk: {
.target = .{
.cpu_arch = .mips,
.os_tag = .linux,
- .abi = .musl,
+ .abi = .eabihf,
+ },
+ .slow_backend = true,
+ },
+ .{
+ .target = .{
+ .cpu_arch = .mips,
+ .os_tag = .linux,
+ .abi = .musleabi,
+ },
+ .link_libc = true,
+ .slow_backend = true,
+ },
+ .{
+ .target = .{
+ .cpu_arch = .mips,
+ .os_tag = .linux,
+ .abi = .musleabihf,
+ },
+ .link_libc = true,
+ .slow_backend = true,
+ },
+ .{
+ .target = .{
+ .cpu_arch = .mips,
+ .os_tag = .linux,
+ .abi = .gnueabi,
},
.link_libc = true,
.slow_backend = true,
@@ -342,7 +394,7 @@ const test_targets = blk: {
.target = .{
.cpu_arch = .mipsel,
.os_tag = .linux,
- .abi = .none,
+ .abi = .eabi,
},
.slow_backend = true,
},
@@ -350,7 +402,33 @@ const test_targets = blk: {
.target = .{
.cpu_arch = .mipsel,
.os_tag = .linux,
- .abi = .musl,
+ .abi = .eabihf,
+ },
+ .slow_backend = true,
+ },
+ .{
+ .target = .{
+ .cpu_arch = .mipsel,
+ .os_tag = .linux,
+ .abi = .musleabi,
+ },
+ .link_libc = true,
+ .slow_backend = true,
+ },
+ .{
+ .target = .{
+ .cpu_arch = .mipsel,
+ .os_tag = .linux,
+ .abi = .musleabihf,
+ },
+ .link_libc = true,
+ .slow_backend = true,
+ },
+ .{
+ .target = .{
+ .cpu_arch = .mipsel,
+ .os_tag = .linux,
+ .abi = .gnueabi,
},
.link_libc = true,
.slow_backend = true,
@@ -417,14 +495,29 @@ const test_targets = blk: {
.target = .{
.cpu_arch = .powerpc,
.os_tag = .linux,
- .abi = .none,
+ .abi = .eabi,
},
},
.{
.target = .{
.cpu_arch = .powerpc,
.os_tag = .linux,
- .abi = .musl,
+ .abi = .eabihf,
+ },
+ },
+ .{
+ .target = .{
+ .cpu_arch = .powerpc,
+ .os_tag = .linux,
+ .abi = .musleabi,
+ },
+ .link_libc = true,
+ },
+ .{
+ .target = .{
+ .cpu_arch = .powerpc,
+ .os_tag = .linux,
+ .abi = .musleabihf,
},
.link_libc = true,
},
@@ -661,7 +754,7 @@ const c_abi_targets = [_]CAbiTarget{
.target = .{
.cpu_arch = .mips,
.os_tag = .linux,
- .abi = .musl,
+ .abi = .musleabihf,
},
},
.{
@@ -682,7 +775,7 @@ const c_abi_targets = [_]CAbiTarget{
.target = .{
.cpu_arch = .powerpc,
.os_tag = .linux,
- .abi = .musl,
+ .abi = .musleabihf,
},
},
.{