authorgravatar for thatlemon@gmail.comLemonBoy <thatlemon@gmail.com> 2021-11-01 19:26:32+01:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-11-04 14:30:35-04:00
logd03e9d0b8347a74d674bdafadb71e7ddd8fdfad1
tree497835a372d774c00ac1181f20886eaf94f6b34d
parent77ffffc7cc2c22ede60876281ea5d1cdfdf7afa2

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

6 files changed, 57 insertions(+), 22 deletions(-)

lib/std/special/compiler_rt/extendXfYf2.zig+13-10
...@@ -1,6 +1,7 @@...@@ -1,6 +1,7 @@
1const std = @import("std");1const std = @import("std");
2const builtin = @import("builtin");2const builtin = @import("builtin");
3const is_test = builtin.is_test;3const is_test = builtin.is_test;
4const native_arch = builtin.cpu.arch;
45
5pub fn __extendsfdf2(a: f32) callconv(.C) f64 {6pub fn __extendsfdf2(a: f32) callconv(.C) f64 {
6 return extendXfYf2(f64, f32, @bitCast(u32, a));7 return extendXfYf2(f64, f32, @bitCast(u32, a));
...@@ -14,12 +15,16 @@ pub fn __extendsftf2(a: f32) callconv(.C) f128 {...@@ -14,12 +15,16 @@ pub fn __extendsftf2(a: f32) callconv(.C) f128 {
14 return extendXfYf2(f128, f32, @bitCast(u32, a));15 return extendXfYf2(f128, f32, @bitCast(u32, a));
15}16}
1617
17pub fn __extendhfsf2(a: u16) callconv(.C) f32 {18// AArch64 is the only ABI (at the moment) to support f16 arguments without the
18 return extendXfYf2(f32, f16, a);19// need for extending them to wider fp types.
20pub const F16T = if (native_arch.isAARCH64()) f16 else u16;
21
22pub fn __extendhfsf2(a: F16T) callconv(.C) f32 {
23 return extendXfYf2(f32, f16, @bitCast(u16, a));
19}24}
2025
21pub fn __extendhftf2(a: u16) callconv(.C) f128 {26pub fn __extendhftf2(a: F16T) callconv(.C) f128 {
22 return extendXfYf2(f128, f16, a);27 return extendXfYf2(f128, f16, @bitCast(u16, a));
23}28}
2429
25pub fn __extendxftf2(a: c_longdouble) callconv(.C) f128 {30pub fn __extendxftf2(a: c_longdouble) callconv(.C) f128 {
...@@ -29,16 +34,14 @@ pub fn __extendxftf2(a: c_longdouble) callconv(.C) f128 {...@@ -29,16 +34,14 @@ pub fn __extendxftf2(a: c_longdouble) callconv(.C) f128 {
2934
30pub fn __aeabi_h2f(arg: u16) callconv(.AAPCS) f32 {35pub fn __aeabi_h2f(arg: u16) callconv(.AAPCS) f32 {
31 @setRuntimeSafety(false);36 @setRuntimeSafety(false);
32 return @call(.{ .modifier = .always_inline }, __extendhfsf2, .{arg});37 return @call(.{ .modifier = .always_inline }, extendXfYf2, .{ f32, f16, arg });
33}38}
3439
35pub fn __aeabi_f2d(arg: f32) callconv(.AAPCS) f64 {40pub fn __aeabi_f2d(arg: f32) callconv(.AAPCS) f64 {
36 @setRuntimeSafety(false);41 @setRuntimeSafety(false);
37 return @call(.{ .modifier = .always_inline }, __extendsfdf2, .{arg});42 return @call(.{ .modifier = .always_inline }, extendXfYf2, .{ f64, f32, @bitCast(u32, arg) });
38}43}
3944
40const CHAR_BIT = 8;
41
42inline fn extendXfYf2(comptime dst_t: type, comptime src_t: type, a: std.meta.Int(.unsigned, @typeInfo(src_t).Float.bits)) dst_t {45inline fn extendXfYf2(comptime dst_t: type, comptime src_t: type, a: std.meta.Int(.unsigned, @typeInfo(src_t).Float.bits)) dst_t {
43 @setRuntimeSafety(builtin.is_test);46 @setRuntimeSafety(builtin.is_test);
4447
...@@ -50,7 +53,7 @@ inline fn extendXfYf2(comptime dst_t: type, comptime src_t: type, a: std.meta.In...@@ -50,7 +53,7 @@ inline fn extendXfYf2(comptime dst_t: type, comptime src_t: type, a: std.meta.In
5053
51 // Various constants whose values follow from the type parameters.54 // Various constants whose values follow from the type parameters.
52 // Any reasonable optimizer will fold and propagate all of these.55 // Any reasonable optimizer will fold and propagate all of these.
53 const srcBits = @sizeOf(src_t) * CHAR_BIT;56 const srcBits = @bitSizeOf(src_t);
54 const srcExpBits = srcBits - srcSigBits - 1;57 const srcExpBits = srcBits - srcSigBits - 1;
55 const srcInfExp = (1 << srcExpBits) - 1;58 const srcInfExp = (1 << srcExpBits) - 1;
56 const srcExpBias = srcInfExp >> 1;59 const srcExpBias = srcInfExp >> 1;
...@@ -62,7 +65,7 @@ inline fn extendXfYf2(comptime dst_t: type, comptime src_t: type, a: std.meta.In...@@ -62,7 +65,7 @@ inline fn extendXfYf2(comptime dst_t: type, comptime src_t: type, a: std.meta.In
62 const srcQNaN = 1 << (srcSigBits - 1);65 const srcQNaN = 1 << (srcSigBits - 1);
63 const srcNaNCode = srcQNaN - 1;66 const srcNaNCode = srcQNaN - 1;
6467
65 const dstBits = @sizeOf(dst_t) * CHAR_BIT;68 const dstBits = @bitSizeOf(dst_t);
66 const dstExpBits = dstBits - dstSigBits - 1;69 const dstExpBits = dstBits - dstSigBits - 1;
67 const dstInfExp = (1 << dstExpBits) - 1;70 const dstInfExp = (1 << dstExpBits) - 1;
68 const dstExpBias = dstInfExp >> 1;71 const dstExpBias = dstInfExp >> 1;
lib/std/special/compiler_rt/extendXfYf2_test.zig+3-2
...@@ -3,6 +3,7 @@ const __extendhfsf2 = @import("extendXfYf2.zig").__extendhfsf2;...@@ -3,6 +3,7 @@ const __extendhfsf2 = @import("extendXfYf2.zig").__extendhfsf2;
3const __extendhftf2 = @import("extendXfYf2.zig").__extendhftf2;3const __extendhftf2 = @import("extendXfYf2.zig").__extendhftf2;
4const __extendsftf2 = @import("extendXfYf2.zig").__extendsftf2;4const __extendsftf2 = @import("extendXfYf2.zig").__extendsftf2;
5const __extenddftf2 = @import("extendXfYf2.zig").__extenddftf2;5const __extenddftf2 = @import("extendXfYf2.zig").__extenddftf2;
6const F16T = @import("extendXfYf2.zig").F16T;
67
7fn test__extenddftf2(a: f64, expectedHi: u64, expectedLo: u64) !void {8fn test__extenddftf2(a: f64, expectedHi: u64, expectedLo: u64) !void {
8 const x = __extenddftf2(a);9 const x = __extenddftf2(a);
...@@ -27,7 +28,7 @@ fn test__extenddftf2(a: f64, expectedHi: u64, expectedLo: u64) !void {...@@ -27,7 +28,7 @@ fn test__extenddftf2(a: f64, expectedHi: u64, expectedLo: u64) !void {
27}28}
2829
29fn test__extendhfsf2(a: u16, expected: u32) !void {30fn test__extendhfsf2(a: u16, expected: u32) !void {
30 const x = __extendhfsf2(a);31 const x = __extendhfsf2(@bitCast(F16T, a));
31 const rep = @bitCast(u32, x);32 const rep = @bitCast(u32, x);
3233
33 if (rep == expected) {34 if (rep == expected) {
...@@ -159,7 +160,7 @@ fn makeInf32() f32 {...@@ -159,7 +160,7 @@ fn makeInf32() f32 {
159}160}
160161
161fn test__extendhftf2(a: u16, expectedHi: u64, expectedLo: u64) !void {162fn test__extendhftf2(a: u16, expectedHi: u64, expectedLo: u64) !void {
162 const x = __extendhftf2(a);163 const x = __extendhftf2(@bitCast(F16T, a));
163164
164 const rep = @bitCast(u128, x);165 const rep = @bitCast(u128, x);
165 const hi = @intCast(u64, rep >> 64);166 const hi = @intCast(u64, rep >> 64);
lib/std/special/compiler_rt/truncXfYf2.zig+12-6
...@@ -1,15 +1,21 @@...@@ -1,15 +1,21 @@
1const std = @import("std");1const std = @import("std");
2const builtin = @import("builtin");
3const native_arch = builtin.cpu.arch;
24
3pub fn __truncsfhf2(a: f32) callconv(.C) u16 {5// AArch64 is the only ABI (at the moment) to support f16 arguments without the
4 return @bitCast(u16, @call(.{ .modifier = .always_inline }, truncXfYf2, .{ f16, f32, a }));6// need for extending them to wider fp types.
7pub const F16T = if (native_arch.isAARCH64()) f16 else u16;
8
9pub fn __truncsfhf2(a: f32) callconv(.C) F16T {
10 return @bitCast(F16T, @call(.{ .modifier = .always_inline }, truncXfYf2, .{ f16, f32, a }));
5}11}
612
7pub fn __truncdfhf2(a: f64) callconv(.C) u16 {13pub fn __truncdfhf2(a: f64) callconv(.C) F16T {
8 return @bitCast(u16, @call(.{ .modifier = .always_inline }, truncXfYf2, .{ f16, f64, a }));14 return @bitCast(F16T, @call(.{ .modifier = .always_inline }, truncXfYf2, .{ f16, f64, a }));
9}15}
1016
11pub fn __trunctfhf2(a: f128) callconv(.C) u16 {17pub fn __trunctfhf2(a: f128) callconv(.C) F16T {
12 return @bitCast(u16, @call(.{ .modifier = .always_inline }, truncXfYf2, .{ f16, f128, a }));18 return @bitCast(F16T, @call(.{ .modifier = .always_inline }, truncXfYf2, .{ f16, f128, a }));
13}19}
1420
15pub fn __trunctfsf2(a: f128) callconv(.C) f32 {21pub fn __trunctfsf2(a: f128) callconv(.C) f32 {
lib/std/special/compiler_rt/truncXfYf2_test.zig+2-2
...@@ -1,7 +1,7 @@...@@ -1,7 +1,7 @@
1const __truncsfhf2 = @import("truncXfYf2.zig").__truncsfhf2;1const __truncsfhf2 = @import("truncXfYf2.zig").__truncsfhf2;
22
3fn test__truncsfhf2(a: u32, expected: u16) !void {3fn test__truncsfhf2(a: u32, expected: u16) !void {
4 const actual = __truncsfhf2(@bitCast(f32, a));4 const actual = @bitCast(u16, __truncsfhf2(@bitCast(f32, a)));
55
6 if (actual == expected) {6 if (actual == expected) {
7 return;7 return;
...@@ -82,7 +82,7 @@ fn test__truncdfhf2(a: f64, expected: u16) void {...@@ -82,7 +82,7 @@ fn test__truncdfhf2(a: f64, expected: u16) void {
82}82}
8383
84fn test__truncdfhf2_raw(a: u64, expected: u16) void {84fn test__truncdfhf2_raw(a: u64, expected: u16) void {
85 const actual = __truncdfhf2(@bitCast(f64, a));85 const actual = @bitCast(u16, __truncdfhf2(@bitCast(f64, a)));
8686
87 if (actual == expected) {87 if (actual == expected) {
88 return;88 return;
test/behavior/cast_stage1.zig+26
...@@ -263,6 +263,32 @@ test "cast *[1][*]const u8 to [*]const ?[*]const u8" {...@@ -263,6 +263,32 @@ test "cast *[1][*]const u8 to [*]const ?[*]const u8" {
263 try expect(mem.eql(u8, std.mem.spanZ(@ptrCast([*:0]const u8, x[0].?)), "window name"));263 try expect(mem.eql(u8, std.mem.spanZ(@ptrCast([*:0]const u8, x[0].?)), "window name"));
264}264}
265265
266test "cast f16 to wider types" {
267 const S = struct {
268 fn doTheTest() !void {
269 var x: f16 = 1234.0;
270 try std.testing.expectEqual(@as(f32, 1234.0), x);
271 try std.testing.expectEqual(@as(f64, 1234.0), x);
272 try std.testing.expectEqual(@as(f128, 1234.0), x);
273 }
274 };
275 try S.doTheTest();
276 comptime try S.doTheTest();
277}
278
279test "cast f128 to narrower types" {
280 const S = struct {
281 fn doTheTest() !void {
282 var x: f128 = 1234.0;
283 try std.testing.expectEqual(@as(f16, 1234.0), @floatCast(f16, x));
284 try std.testing.expectEqual(@as(f32, 1234.0), @floatCast(f32, x));
285 try std.testing.expectEqual(@as(f64, 1234.0), @floatCast(f64, x));
286 }
287 };
288 try S.doTheTest();
289 comptime try S.doTheTest();
290}
291
266test "vector casts" {292test "vector casts" {
267 const S = struct {293 const S = struct {
268 fn doTheTest() !void {294 fn doTheTest() !void {
test/behavior/muladd.zig+1-2
...@@ -24,8 +24,7 @@ fn testMulAdd() !void {...@@ -24,8 +24,7 @@ fn testMulAdd() !void {
24 var c: f64 = 6.25;24 var c: f64 = 6.25;
25 try expect(@mulAdd(f64, a, b, c) == 20);25 try expect(@mulAdd(f64, a, b, c) == 20);
26 }26 }
27 // TODO https://github.com/ziglang/zig/issues/990027 {
28 if (@import("builtin").cpu.arch != .aarch64) {
29 var a: f16 = 5.5;28 var a: f16 = 5.5;
30 var b: f128 = 2.5;29 var b: f128 = 2.5;
31 var c: f128 = 6.25;30 var c: f128 = 6.25;