From d03e9d0b8347a74d674bdafadb71e7ddd8fdfad1 Mon Sep 17 00:00:00 2001 From: LemonBoy Date: Mon, 1 Nov 2021 19:26:32 +0100 Subject: [PATCH] compiler-rt: Fix f16 API declarations to be consistent LLVM and compiler-rt must agree on how the parameters are passed, it turns out that in LLVM13 something changed and broke the test case for AArch64 systems. It has nothing to do with fma at all. Closes #9900 --- lib/std/special/compiler_rt/extendXfYf2.zig | 23 +++++++++------- .../special/compiler_rt/extendXfYf2_test.zig | 5 ++-- lib/std/special/compiler_rt/truncXfYf2.zig | 18 ++++++++----- .../special/compiler_rt/truncXfYf2_test.zig | 4 +-- test/behavior/cast_stage1.zig | 26 +++++++++++++++++++ test/behavior/muladd.zig | 3 +-- 6 files changed, 57 insertions(+), 22 deletions(-) diff --git a/lib/std/special/compiler_rt/extendXfYf2.zig b/lib/std/special/compiler_rt/extendXfYf2.zig index 9a2580e9ec79075043454785ef1d272ebeb14a8b..2c3f0c88fcfbb8e08123fcb567c99cfe3605e9da 100644 --- a/lib/std/special/compiler_rt/extendXfYf2.zig +++ b/lib/std/special/compiler_rt/extendXfYf2.zig @@ -1,6 +1,7 @@ const std = @import("std"); const builtin = @import("builtin"); const is_test = builtin.is_test; +const native_arch = builtin.cpu.arch; pub fn __extendsfdf2(a: f32) callconv(.C) f64 { return extendXfYf2(f64, f32, @bitCast(u32, a)); @@ -14,12 +15,16 @@ pub fn __extendsftf2(a: f32) callconv(.C) f128 { return extendXfYf2(f128, f32, @bitCast(u32, a)); } -pub fn __extendhfsf2(a: u16) callconv(.C) f32 { - return extendXfYf2(f32, f16, a); +// AArch64 is the only ABI (at the moment) to support f16 arguments without the +// need for extending them to wider fp types. +pub const F16T = if (native_arch.isAARCH64()) f16 else u16; + +pub fn __extendhfsf2(a: F16T) callconv(.C) f32 { + return extendXfYf2(f32, f16, @bitCast(u16, a)); } -pub fn __extendhftf2(a: u16) callconv(.C) f128 { - return extendXfYf2(f128, f16, a); +pub fn __extendhftf2(a: F16T) callconv(.C) f128 { + return extendXfYf2(f128, f16, @bitCast(u16, a)); } pub fn __extendxftf2(a: c_longdouble) callconv(.C) f128 { @@ -29,16 +34,14 @@ pub fn __extendxftf2(a: c_longdouble) callconv(.C) f128 { pub fn __aeabi_h2f(arg: u16) callconv(.AAPCS) f32 { @setRuntimeSafety(false); - return @call(.{ .modifier = .always_inline }, __extendhfsf2, .{arg}); + return @call(.{ .modifier = .always_inline }, extendXfYf2, .{ f32, f16, arg }); } pub fn __aeabi_f2d(arg: f32) callconv(.AAPCS) f64 { @setRuntimeSafety(false); - return @call(.{ .modifier = .always_inline }, __extendsfdf2, .{arg}); + return @call(.{ .modifier = .always_inline }, extendXfYf2, .{ f64, f32, @bitCast(u32, arg) }); } -const CHAR_BIT = 8; - inline fn extendXfYf2(comptime dst_t: type, comptime src_t: type, a: std.meta.Int(.unsigned, @typeInfo(src_t).Float.bits)) dst_t { @setRuntimeSafety(builtin.is_test); @@ -50,7 +53,7 @@ inline fn extendXfYf2(comptime dst_t: type, comptime src_t: type, a: std.meta.In // Various constants whose values follow from the type parameters. // Any reasonable optimizer will fold and propagate all of these. - const srcBits = @sizeOf(src_t) * CHAR_BIT; + const srcBits = @bitSizeOf(src_t); const srcExpBits = srcBits - srcSigBits - 1; const srcInfExp = (1 << srcExpBits) - 1; const srcExpBias = srcInfExp >> 1; @@ -62,7 +65,7 @@ inline fn extendXfYf2(comptime dst_t: type, comptime src_t: type, a: std.meta.In const srcQNaN = 1 << (srcSigBits - 1); const srcNaNCode = srcQNaN - 1; - const dstBits = @sizeOf(dst_t) * CHAR_BIT; + const dstBits = @bitSizeOf(dst_t); const dstExpBits = dstBits - dstSigBits - 1; const dstInfExp = (1 << dstExpBits) - 1; const dstExpBias = dstInfExp >> 1; diff --git a/lib/std/special/compiler_rt/extendXfYf2_test.zig b/lib/std/special/compiler_rt/extendXfYf2_test.zig index 89545576a206d5c79af50f10983e2b62e93f8603..d0c4f82e977f2f4b58c7846d25fec5af118bbd4f 100644 --- a/lib/std/special/compiler_rt/extendXfYf2_test.zig +++ b/lib/std/special/compiler_rt/extendXfYf2_test.zig @@ -3,6 +3,7 @@ const __extendhfsf2 = @import("extendXfYf2.zig").__extendhfsf2; const __extendhftf2 = @import("extendXfYf2.zig").__extendhftf2; const __extendsftf2 = @import("extendXfYf2.zig").__extendsftf2; const __extenddftf2 = @import("extendXfYf2.zig").__extenddftf2; +const F16T = @import("extendXfYf2.zig").F16T; fn test__extenddftf2(a: f64, expectedHi: u64, expectedLo: u64) !void { const x = __extenddftf2(a); @@ -27,7 +28,7 @@ fn test__extenddftf2(a: f64, expectedHi: u64, expectedLo: u64) !void { } fn test__extendhfsf2(a: u16, expected: u32) !void { - const x = __extendhfsf2(a); + const x = __extendhfsf2(@bitCast(F16T, a)); const rep = @bitCast(u32, x); if (rep == expected) { @@ -159,7 +160,7 @@ fn makeInf32() f32 { } fn test__extendhftf2(a: u16, expectedHi: u64, expectedLo: u64) !void { - const x = __extendhftf2(a); + const x = __extendhftf2(@bitCast(F16T, a)); const rep = @bitCast(u128, x); const hi = @intCast(u64, rep >> 64); diff --git a/lib/std/special/compiler_rt/truncXfYf2.zig b/lib/std/special/compiler_rt/truncXfYf2.zig index 3cad52426e6c443420dd4c2f39689dcdd8aa17cd..559ec0ec4f4550f30362fbe88c64354b55003633 100644 --- a/lib/std/special/compiler_rt/truncXfYf2.zig +++ b/lib/std/special/compiler_rt/truncXfYf2.zig @@ -1,15 +1,21 @@ const std = @import("std"); +const builtin = @import("builtin"); +const native_arch = builtin.cpu.arch; -pub fn __truncsfhf2(a: f32) callconv(.C) u16 { - return @bitCast(u16, @call(.{ .modifier = .always_inline }, truncXfYf2, .{ f16, f32, a })); +// AArch64 is the only ABI (at the moment) to support f16 arguments without the +// need for extending them to wider fp types. +pub const F16T = if (native_arch.isAARCH64()) f16 else u16; + +pub fn __truncsfhf2(a: f32) callconv(.C) F16T { + return @bitCast(F16T, @call(.{ .modifier = .always_inline }, truncXfYf2, .{ f16, f32, a })); } -pub fn __truncdfhf2(a: f64) callconv(.C) u16 { - return @bitCast(u16, @call(.{ .modifier = .always_inline }, truncXfYf2, .{ f16, f64, a })); +pub fn __truncdfhf2(a: f64) callconv(.C) F16T { + return @bitCast(F16T, @call(.{ .modifier = .always_inline }, truncXfYf2, .{ f16, f64, a })); } -pub fn __trunctfhf2(a: f128) callconv(.C) u16 { - return @bitCast(u16, @call(.{ .modifier = .always_inline }, truncXfYf2, .{ f16, f128, a })); +pub fn __trunctfhf2(a: f128) callconv(.C) F16T { + return @bitCast(F16T, @call(.{ .modifier = .always_inline }, truncXfYf2, .{ f16, f128, a })); } pub fn __trunctfsf2(a: f128) callconv(.C) f32 { diff --git a/lib/std/special/compiler_rt/truncXfYf2_test.zig b/lib/std/special/compiler_rt/truncXfYf2_test.zig index 23c83afd9fa7af739dff4ef34e140c11778abcfd..83ec8afab05f9927eaa512ee49b12c8864988983 100644 --- a/lib/std/special/compiler_rt/truncXfYf2_test.zig +++ b/lib/std/special/compiler_rt/truncXfYf2_test.zig @@ -1,7 +1,7 @@ const __truncsfhf2 = @import("truncXfYf2.zig").__truncsfhf2; fn test__truncsfhf2(a: u32, expected: u16) !void { - const actual = __truncsfhf2(@bitCast(f32, a)); + const actual = @bitCast(u16, __truncsfhf2(@bitCast(f32, a))); if (actual == expected) { return; @@ -82,7 +82,7 @@ fn test__truncdfhf2(a: f64, expected: u16) void { } fn test__truncdfhf2_raw(a: u64, expected: u16) void { - const actual = __truncdfhf2(@bitCast(f64, a)); + const actual = @bitCast(u16, __truncdfhf2(@bitCast(f64, a))); if (actual == expected) { return; diff --git a/test/behavior/cast_stage1.zig b/test/behavior/cast_stage1.zig index 1a5679bc0c285a205bdd5f26584550610d57df7f..f6bf975011025bcc43d546fe1606d1d2480c2360 100644 --- a/test/behavior/cast_stage1.zig +++ b/test/behavior/cast_stage1.zig @@ -263,6 +263,32 @@ test "cast *[1][*]const u8 to [*]const ?[*]const u8" { try expect(mem.eql(u8, std.mem.spanZ(@ptrCast([*:0]const u8, x[0].?)), "window name")); } +test "cast f16 to wider types" { + const S = struct { + fn doTheTest() !void { + var x: f16 = 1234.0; + try std.testing.expectEqual(@as(f32, 1234.0), x); + try std.testing.expectEqual(@as(f64, 1234.0), x); + try std.testing.expectEqual(@as(f128, 1234.0), x); + } + }; + try S.doTheTest(); + comptime try S.doTheTest(); +} + +test "cast f128 to narrower types" { + const S = struct { + fn doTheTest() !void { + var x: f128 = 1234.0; + try std.testing.expectEqual(@as(f16, 1234.0), @floatCast(f16, x)); + try std.testing.expectEqual(@as(f32, 1234.0), @floatCast(f32, x)); + try std.testing.expectEqual(@as(f64, 1234.0), @floatCast(f64, x)); + } + }; + try S.doTheTest(); + comptime try S.doTheTest(); +} + test "vector casts" { const S = struct { fn doTheTest() !void { diff --git a/test/behavior/muladd.zig b/test/behavior/muladd.zig index 5129303c92fa1d9ad5ede4c672e47141bcfc830f..eaa30324df47f7d508d07c06db50be65bb262995 100644 --- a/test/behavior/muladd.zig +++ b/test/behavior/muladd.zig @@ -24,8 +24,7 @@ fn testMulAdd() !void { var c: f64 = 6.25; try expect(@mulAdd(f64, a, b, c) == 20); } - // TODO https://github.com/ziglang/zig/issues/9900 - if (@import("builtin").cpu.arch != .aarch64) { + { var a: f16 = 5.5; var b: f128 = 2.5; var c: f128 = 6.25; -- 2.54.0