authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2024-09-11 17:41:55-07:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2024-09-11 17:41:55-07:00
log4fba7336a9038b4abf647caf822f89df717d3cc0
treed2a5e61671fefce3ba53454b46311ba77dc31b7a
parent218cf059dd215282aa96d6b4715e68d533a4238e
parentf1645772c1881a233ffcfc5072710040c4881deb
signaturebadge-check Signed by PGP key B5690EEEBB952194

Merge pull request #21269 from alexrp/soft-float

Fix soft float support, split musl triples by float ABI, and enable CI

13 files changed, 251 insertions(+), 43 deletions(-)

lib/compiler_rt/truncdfhf2.zig+1-2
......@@ -6,9 +6,8 @@ pub const panic = common.panic;
66comptime {
77 if (common.want_aeabi) {
88 @export(&__aeabi_d2h, .{ .name = "__aeabi_d2h", .linkage = common.linkage, .visibility = common.visibility });
9 } else {
10 @export(&__truncdfhf2, .{ .name = "__truncdfhf2", .linkage = common.linkage, .visibility = common.visibility });
119 }
10 @export(&__truncdfhf2, .{ .name = "__truncdfhf2", .linkage = common.linkage, .visibility = common.visibility });
1211}
1312
1413pub fn __truncdfhf2(a: f64) callconv(.C) common.F16T(f64) {
lib/std/Target.zig+8-7
......@@ -765,12 +765,13 @@ pub const Abi = enum {
765765
766766 pub inline fn floatAbi(abi: Abi) FloatAbi {
767767 return switch (abi) {
768 .gnueabihf,
769 .eabihf,
770 .musleabihf,
771 => .hard,
772 .ohos => .soft,
773 else => .soft,
768 .eabi,
769 .gnueabi,
770 .musleabi,
771 .gnusf,
772 .ohos,
773 => .soft,
774 else => .hard,
774775 };
775776 }
776777};
......@@ -1645,7 +1646,7 @@ pub const FloatAbi = enum {
16451646 soft,
16461647};
16471648
1648pub inline fn getFloatAbi(target: Target) FloatAbi {
1649pub inline fn floatAbi(target: Target) FloatAbi {
16491650 return target.abi.floatAbi();
16501651}
16511652
lib/std/math/gamma.zig+3
......@@ -3,6 +3,7 @@
33//
44// https://git.musl-libc.org/cgit/musl/tree/src/math/tgamma.c
55
6const builtin = @import("builtin");
67const std = @import("../std.zig");
78
89/// Returns the gamma function of x,
......@@ -262,6 +263,8 @@ test gamma {
262263}
263264
264265test "gamma.special" {
266 if (builtin.cpu.arch.isArmOrThumb() and builtin.target.floatAbi() == .soft) return error.SkipZigTest; // https://github.com/ziglang/zig/issues/21234
267
265268 inline for (&.{ f32, f64 }) |T| {
266269 try expect(std.math.isNan(gamma(T, -std.math.nan(T))));
267270 try expect(std.math.isNan(gamma(T, std.math.nan(T))));
lib/std/zig/system.zig+6
......@@ -384,6 +384,12 @@ pub fn resolveTargetQuery(query: Target.Query) DetectError!Target {
384384 query.cpu_features_add,
385385 query.cpu_features_sub,
386386 );
387
388 // https://github.com/llvm/llvm-project/issues/105978
389 if (result.cpu.arch.isArmOrThumb() and result.floatAbi() == .soft) {
390 result.cpu.features.removeFeature(@intFromEnum(Target.arm.Feature.vfp2));
391 }
392
387393 return result;
388394}
389395
lib/std/zig/target.zig+6-3
......@@ -46,17 +46,20 @@ pub const available_libcs = [_]ArchOsAbi{
4646 .{ .arch = .mips64, .os = .linux, .abi = .musl },
4747 .{ .arch = .mipsel, .os = .linux, .abi = .gnueabi },
4848 .{ .arch = .mipsel, .os = .linux, .abi = .gnueabihf },
49 .{ .arch = .mipsel, .os = .linux, .abi = .musl },
49 .{ .arch = .mipsel, .os = .linux, .abi = .musleabi },
50 .{ .arch = .mipsel, .os = .linux, .abi = .musleabihf },
5051 .{ .arch = .mips, .os = .linux, .abi = .gnueabi },
5152 .{ .arch = .mips, .os = .linux, .abi = .gnueabihf },
52 .{ .arch = .mips, .os = .linux, .abi = .musl },
53 .{ .arch = .mips, .os = .linux, .abi = .musleabi },
54 .{ .arch = .mips, .os = .linux, .abi = .musleabihf },
5355 .{ .arch = .powerpc64le, .os = .linux, .abi = .gnu, .glibc_min = .{ .major = 2, .minor = 19, .patch = 0 } },
5456 .{ .arch = .powerpc64le, .os = .linux, .abi = .musl },
5557 .{ .arch = .powerpc64, .os = .linux, .abi = .gnu },
5658 .{ .arch = .powerpc64, .os = .linux, .abi = .musl },
5759 .{ .arch = .powerpc, .os = .linux, .abi = .gnueabi },
5860 .{ .arch = .powerpc, .os = .linux, .abi = .gnueabihf },
59 .{ .arch = .powerpc, .os = .linux, .abi = .musl },
61 .{ .arch = .powerpc, .os = .linux, .abi = .musleabi },
62 .{ .arch = .powerpc, .os = .linux, .abi = .musleabihf },
6063 .{ .arch = .riscv32, .os = .linux, .abi = .gnu, .glibc_min = .{ .major = 2, .minor = 33, .patch = 0 } },
6164 .{ .arch = .riscv32, .os = .linux, .abi = .musl },
6265 .{ .arch = .riscv64, .os = .linux, .abi = .gnu, .glibc_min = .{ .major = 2, .minor = 27, .patch = 0 } },
src/Compilation.zig+25-4
......@@ -5484,6 +5484,9 @@ pub fn addCCArgs(
54845484 const is_enabled = target.cpu.features.isEnabled(index);
54855485
54865486 if (feature.llvm_name) |llvm_name| {
5487 // We communicate float ABI to Clang through the dedicated options further down.
5488 if (std.mem.eql(u8, llvm_name, "soft-float")) continue;
5489
54875490 argv.appendSliceAssumeCapacity(&[_][]const u8{ "-Xclang", "-target-feature", "-Xclang" });
54885491 const plus_or_minus = "-+"[@intFromBool(is_enabled)];
54895492 const arg = try std.fmt.allocPrint(arena, "{c}{s}", .{ plus_or_minus, llvm_name });
......@@ -5705,10 +5708,6 @@ pub fn addCCArgs(
57055708 if (target.cpu.model.llvm_name) |llvm_name| {
57065709 try argv.append(try std.fmt.allocPrint(arena, "-march={s}", .{llvm_name}));
57075710 }
5708
5709 if (std.Target.mips.featureSetHas(target.cpu.features, .soft_float)) {
5710 try argv.append("-msoft-float");
5711 }
57125711 },
57135712 else => {
57145713 // TODO
......@@ -5751,6 +5750,28 @@ pub fn addCCArgs(
57515750 try argv.append(try std.fmt.allocPrint(arena, "-mabi={s}", .{mabi}));
57525751 }
57535752
5753 // We might want to support -mfloat-abi=softfp for Arm and CSKY here in the future.
5754 if (target_util.clangSupportsFloatAbiArg(target)) {
5755 const fabi = @tagName(target.floatAbi());
5756
5757 try argv.append(switch (target.cpu.arch) {
5758 // For whatever reason, Clang doesn't support `-mfloat-abi` for s390x.
5759 .s390x => try std.fmt.allocPrint(arena, "-m{s}-float", .{fabi}),
5760 else => try std.fmt.allocPrint(arena, "-mfloat-abi={s}", .{fabi}),
5761 });
5762 }
5763
5764 if (target_util.clangSupportsNoImplicitFloatArg(target) and target.floatAbi() == .soft) {
5765 try argv.append("-mno-implicit-float");
5766 }
5767
5768 // https://github.com/llvm/llvm-project/issues/105972
5769 if (target.cpu.arch.isPowerPC() and target.floatAbi() == .soft) {
5770 try argv.append("-D__NO_FPRS__");
5771 try argv.append("-D_SOFT_FLOAT");
5772 try argv.append("-D_SOFT_DOUBLE");
5773 }
5774
57545775 if (out_dep_path) |p| {
57555776 try argv.appendSlice(&[_][]const u8{ "-MD", "-MV", "-MF", p });
57565777 }
src/codegen/llvm.zig+35-2
......@@ -1285,8 +1285,7 @@ pub const Object = struct {
12851285 .large => .Large,
12861286 };
12871287
1288 // TODO handle float ABI better- it should depend on the ABI portion of std.Target
1289 const float_abi: llvm.ABIType = .Default;
1288 const float_abi: llvm.ABIType = if (comp.root_mod.resolved_target.result.floatAbi() == .hard) .Hard else .Soft;
12901289
12911290 var target_machine = llvm.TargetMachine.create(
12921291 target,
......@@ -3110,6 +3109,30 @@ pub const Object = struct {
31103109 .value = .empty,
31113110 } }, &o.builder);
31123111 }
3112 if (target.floatAbi() == .soft) {
3113 // `use-soft-float` means "use software routines for floating point computations". In
3114 // other words, it configures how LLVM lowers basic float instructions like `fcmp`,
3115 // `fadd`, etc. The float calling convention is configured on `TargetMachine` and is
3116 // mostly an orthogonal concept, although obviously we do need hardware float operations
3117 // to actually be able to pass float values in float registers.
3118 //
3119 // Ideally, we would support something akin to the `-mfloat-abi=softfp` option that GCC
3120 // and Clang support for Arm32 and CSKY. We don't currently expose such an option in
3121 // Zig, and using CPU features as the source of truth for this makes for a miserable
3122 // user experience since people expect e.g. `arm-linux-gnueabi` to mean full soft float
3123 // unless the compiler has explicitly been told otherwise. (And note that our baseline
3124 // CPU models almost all include FPU features!)
3125 //
3126 // Revisit this at some point.
3127 try attributes.addFnAttr(.{ .string = .{
3128 .kind = try o.builder.string("use-soft-float"),
3129 .value = try o.builder.string("true"),
3130 } }, &o.builder);
3131
3132 // This prevents LLVM from using FPU/SIMD code for things like `memcpy`. As for the
3133 // above, this should be revisited if `softfp` support is added.
3134 try attributes.addFnAttr(.noimplicitfloat, &o.builder);
3135 }
31133136 }
31143137
31153138 fn resolveGlobalUav(
......@@ -12423,6 +12446,11 @@ fn backendSupportsF16(target: std.Target) bool {
1242312446 .riscv32,
1242412447 .s390x,
1242512448 => false,
12449 .arm,
12450 .armeb,
12451 .thumb,
12452 .thumbeb,
12453 => target.floatAbi() == .soft or std.Target.arm.featureSetHas(target.cpu.features, .fp_armv8),
1242612454 .aarch64,
1242712455 .aarch64_be,
1242812456 => std.Target.aarch64.featureSetHas(target.cpu.features, .fp_armv8),
......@@ -12445,6 +12473,11 @@ fn backendSupportsF128(target: std.Target) bool {
1244512473 .powerpc64,
1244612474 .powerpc64le,
1244712475 => target.os.tag != .aix,
12476 .arm,
12477 .armeb,
12478 .thumb,
12479 .thumbeb,
12480 => target.floatAbi() == .soft or std.Target.arm.featureSetHas(target.cpu.features, .fp_armv8),
1244812481 .aarch64,
1244912482 .aarch64_be,
1245012483 => std.Target.aarch64.featureSetHas(target.cpu.features, .fp_armv8),
src/musl.zig+1
......@@ -387,6 +387,7 @@ fn addCcArgs(
387387 "-fno-builtin",
388388 "-fexcess-precision=standard",
389389 "-frounding-math",
390 "-ffp-contract=off",
390391 "-fno-strict-aliasing",
391392 "-Wa,--noexecstack",
392393 "-D_XOPEN_SOURCE=700",
src/target.zig+42
......@@ -339,6 +339,48 @@ pub fn clangAssemblerSupportsMcpuArg(target: std.Target) bool {
339339 };
340340}
341341
342pub fn clangSupportsFloatAbiArg(target: std.Target) bool {
343 return switch (target.cpu.arch) {
344 .arm,
345 .armeb,
346 .thumb,
347 .thumbeb,
348 .csky,
349 .mips,
350 .mipsel,
351 .mips64,
352 .mips64el,
353 .powerpc,
354 .powerpcle,
355 .powerpc64,
356 .powerpc64le,
357 .s390x,
358 .sparc,
359 .sparc64,
360 => true,
361 // We use the target triple for LoongArch.
362 .loongarch32, .loongarch64 => false,
363 else => false,
364 };
365}
366
367pub fn clangSupportsNoImplicitFloatArg(target: std.Target) bool {
368 return switch (target.cpu.arch) {
369 .aarch64,
370 .aarch64_be,
371 .arm,
372 .armeb,
373 .thumb,
374 .thumbeb,
375 .riscv32,
376 .riscv64,
377 .x86,
378 .x86_64,
379 => true,
380 else => false,
381 };
382}
383
342384pub fn needUnwindTables(target: std.Target) bool {
343385 return target.os.tag == .windows or target.isDarwin() or std.debug.Dwarf.abi.supportsUnwinding(target);
344386}
test/behavior/floatop.zig+2
......@@ -126,6 +126,7 @@ test "cmp f16" {
126126 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;
127127 if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf and builtin.target.ofmt != .macho) return error.SkipZigTest;
128128 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
129 if (builtin.cpu.arch.isArmOrThumb() and builtin.target.floatAbi() == .soft) return error.SkipZigTest; // https://github.com/ziglang/zig/issues/21234
129130
130131 try testCmp(f16);
131132 try comptime testCmp(f16);
......@@ -134,6 +135,7 @@ test "cmp f16" {
134135test "cmp f32/f64" {
135136 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
136137 if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf and builtin.target.ofmt != .macho) return error.SkipZigTest;
138 if (builtin.cpu.arch.isArmOrThumb() and builtin.target.floatAbi() == .soft) return error.SkipZigTest; // https://github.com/ziglang/zig/issues/21234
137139
138140 try testCmp(f32);
139141 try comptime testCmp(f32);
test/behavior/math.zig+1
......@@ -1597,6 +1597,7 @@ test "NaN comparison" {
15971597 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
15981598 if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf and builtin.target.ofmt != .macho) return error.SkipZigTest;
15991599 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
1600 if (builtin.cpu.arch.isArmOrThumb() and builtin.target.floatAbi() == .soft) return error.SkipZigTest; // https://github.com/ziglang/zig/issues/21234
16001601
16011602 try testNanEqNan(f16);
16021603 try testNanEqNan(f32);
test/behavior/vector.zig+8-5
......@@ -1409,7 +1409,14 @@ test "store vector with memset" {
14091409 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
14101410
14111411 if (builtin.zig_backend == .stage2_llvm) {
1412 // LLVM 16 ERROR: "Converting bits to bytes lost precision"
1413 // https://github.com/ziglang/zig/issues/16177
14121414 switch (builtin.target.cpu.arch) {
1415 .arm,
1416 .armeb,
1417 .thumb,
1418 .thumbeb,
1419 => if (builtin.target.floatAbi() == .soft) return error.SkipZigTest,
14131420 .wasm32,
14141421 .mips,
14151422 .mipsel,
......@@ -1418,11 +1425,7 @@ test "store vector with memset" {
14181425 .riscv64,
14191426 .powerpc,
14201427 .powerpc64,
1421 => {
1422 // LLVM 16 ERROR: "Converting bits to bytes lost precision"
1423 // https://github.com/ziglang/zig/issues/16177
1424 return error.SkipZigTest;
1425 },
1428 => return error.SkipZigTest,
14261429 else => {},
14271430 }
14281431 }
test/tests.zig+113-20
......@@ -291,23 +291,49 @@ const test_targets = blk: {
291291 },
292292
293293 .{
294 .target = std.Target.Query.parse(.{
295 .arch_os_abi = "arm-linux-none",
296 .cpu_features = "generic+v8a",
297 }) catch unreachable,
294 .target = .{
295 .cpu_arch = .arm,
296 .os_tag = .linux,
297 .abi = .eabi,
298 },
299 },
300 .{
301 .target = .{
302 .cpu_arch = .arm,
303 .os_tag = .linux,
304 .abi = .eabihf,
305 },
306 },
307 .{
308 .target = .{
309 .cpu_arch = .arm,
310 .os_tag = .linux,
311 .abi = .musleabi,
312 },
313 .link_libc = true,
314 },
315 .{
316 .target = .{
317 .cpu_arch = .arm,
318 .os_tag = .linux,
319 .abi = .musleabihf,
320 },
321 .link_libc = true,
298322 },
299323 .{
300 .target = std.Target.Query.parse(.{
301 .arch_os_abi = "arm-linux-musleabihf",
302 .cpu_features = "generic+v8a",
303 }) catch unreachable,
324 .target = .{
325 .cpu_arch = .arm,
326 .os_tag = .linux,
327 .abi = .gnueabi,
328 },
304329 .link_libc = true,
305330 },
306331 .{
307 .target = std.Target.Query.parse(.{
308 .arch_os_abi = "arm-linux-gnueabihf",
309 .cpu_features = "generic+v8a",
310 }) catch unreachable,
332 .target = .{
333 .cpu_arch = .arm,
334 .os_tag = .linux,
335 .abi = .gnueabihf,
336 },
311337 .link_libc = true,
312338 },
313339
......@@ -315,7 +341,7 @@ const test_targets = blk: {
315341 .target = .{
316342 .cpu_arch = .mips,
317343 .os_tag = .linux,
318 .abi = .none,
344 .abi = .eabi,
319345 },
320346 .slow_backend = true,
321347 },
......@@ -323,7 +349,33 @@ const test_targets = blk: {
323349 .target = .{
324350 .cpu_arch = .mips,
325351 .os_tag = .linux,
326 .abi = .musl,
352 .abi = .eabihf,
353 },
354 .slow_backend = true,
355 },
356 .{
357 .target = .{
358 .cpu_arch = .mips,
359 .os_tag = .linux,
360 .abi = .musleabi,
361 },
362 .link_libc = true,
363 .slow_backend = true,
364 },
365 .{
366 .target = .{
367 .cpu_arch = .mips,
368 .os_tag = .linux,
369 .abi = .musleabihf,
370 },
371 .link_libc = true,
372 .slow_backend = true,
373 },
374 .{
375 .target = .{
376 .cpu_arch = .mips,
377 .os_tag = .linux,
378 .abi = .gnueabi,
327379 },
328380 .link_libc = true,
329381 .slow_backend = true,
......@@ -342,7 +394,7 @@ const test_targets = blk: {
342394 .target = .{
343395 .cpu_arch = .mipsel,
344396 .os_tag = .linux,
345 .abi = .none,
397 .abi = .eabi,
346398 },
347399 .slow_backend = true,
348400 },
......@@ -350,7 +402,33 @@ const test_targets = blk: {
350402 .target = .{
351403 .cpu_arch = .mipsel,
352404 .os_tag = .linux,
353 .abi = .musl,
405 .abi = .eabihf,
406 },
407 .slow_backend = true,
408 },
409 .{
410 .target = .{
411 .cpu_arch = .mipsel,
412 .os_tag = .linux,
413 .abi = .musleabi,
414 },
415 .link_libc = true,
416 .slow_backend = true,
417 },
418 .{
419 .target = .{
420 .cpu_arch = .mipsel,
421 .os_tag = .linux,
422 .abi = .musleabihf,
423 },
424 .link_libc = true,
425 .slow_backend = true,
426 },
427 .{
428 .target = .{
429 .cpu_arch = .mipsel,
430 .os_tag = .linux,
431 .abi = .gnueabi,
354432 },
355433 .link_libc = true,
356434 .slow_backend = true,
......@@ -417,14 +495,29 @@ const test_targets = blk: {
417495 .target = .{
418496 .cpu_arch = .powerpc,
419497 .os_tag = .linux,
420 .abi = .none,
498 .abi = .eabi,
421499 },
422500 },
423501 .{
424502 .target = .{
425503 .cpu_arch = .powerpc,
426504 .os_tag = .linux,
427 .abi = .musl,
505 .abi = .eabihf,
506 },
507 },
508 .{
509 .target = .{
510 .cpu_arch = .powerpc,
511 .os_tag = .linux,
512 .abi = .musleabi,
513 },
514 .link_libc = true,
515 },
516 .{
517 .target = .{
518 .cpu_arch = .powerpc,
519 .os_tag = .linux,
520 .abi = .musleabihf,
428521 },
429522 .link_libc = true,
430523 },
......@@ -661,7 +754,7 @@ const c_abi_targets = [_]CAbiTarget{
661754 .target = .{
662755 .cpu_arch = .mips,
663756 .os_tag = .linux,
664 .abi = .musl,
757 .abi = .musleabihf,
665758 },
666759 },
667760 .{
......@@ -682,7 +775,7 @@ const c_abi_targets = [_]CAbiTarget{
682775 .target = .{
683776 .cpu_arch = .powerpc,
684777 .os_tag = .linux,
685 .abi = .musl,
778 .abi = .musleabihf,
686779 },
687780 },
688781 .{