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 @@
11const std = @import("std");
22const builtin = @import("builtin");
33const is_test = builtin.is_test;
4const native_arch = builtin.cpu.arch;
45
56pub fn __extendsfdf2(a: f32) callconv(.C) f64 {
67 return extendXfYf2(f64, f32, @bitCast(u32, a));
......@@ -14,12 +15,16 @@ pub fn __extendsftf2(a: f32) callconv(.C) f128 {
1415 return extendXfYf2(f128, f32, @bitCast(u32, a));
1516}
1617
17pub fn __extendhfsf2(a: u16) callconv(.C) f32 {
18 return extendXfYf2(f32, f16, a);
18// AArch64 is the only ABI (at the moment) to support f16 arguments without the
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));
1924}
2025
21pub fn __extendhftf2(a: u16) callconv(.C) f128 {
22 return extendXfYf2(f128, f16, a);
26pub fn __extendhftf2(a: F16T) callconv(.C) f128 {
27 return extendXfYf2(f128, f16, @bitCast(u16, a));
2328}
2429
2530pub fn __extendxftf2(a: c_longdouble) callconv(.C) f128 {
......@@ -29,16 +34,14 @@ pub fn __extendxftf2(a: c_longdouble) callconv(.C) f128 {
2934
3035pub fn __aeabi_h2f(arg: u16) callconv(.AAPCS) f32 {
3136 @setRuntimeSafety(false);
32 return @call(.{ .modifier = .always_inline }, __extendhfsf2, .{arg});
37 return @call(.{ .modifier = .always_inline }, extendXfYf2, .{ f32, f16, arg });
3338}
3439
3540pub fn __aeabi_f2d(arg: f32) callconv(.AAPCS) f64 {
3641 @setRuntimeSafety(false);
37 return @call(.{ .modifier = .always_inline }, __extendsfdf2, .{arg});
42 return @call(.{ .modifier = .always_inline }, extendXfYf2, .{ f64, f32, @bitCast(u32, arg) });
3843}
3944
40const CHAR_BIT = 8;
41
4245inline fn extendXfYf2(comptime dst_t: type, comptime src_t: type, a: std.meta.Int(.unsigned, @typeInfo(src_t).Float.bits)) dst_t {
4346 @setRuntimeSafety(builtin.is_test);
4447
......@@ -50,7 +53,7 @@ inline fn extendXfYf2(comptime dst_t: type, comptime src_t: type, a: std.meta.In
5053
5154 // Various constants whose values follow from the type parameters.
5255 // Any reasonable optimizer will fold and propagate all of these.
53 const srcBits = @sizeOf(src_t) * CHAR_BIT;
56 const srcBits = @bitSizeOf(src_t);
5457 const srcExpBits = srcBits - srcSigBits - 1;
5558 const srcInfExp = (1 << srcExpBits) - 1;
5659 const srcExpBias = srcInfExp >> 1;
......@@ -62,7 +65,7 @@ inline fn extendXfYf2(comptime dst_t: type, comptime src_t: type, a: std.meta.In
6265 const srcQNaN = 1 << (srcSigBits - 1);
6366 const srcNaNCode = srcQNaN - 1;
6467
65 const dstBits = @sizeOf(dst_t) * CHAR_BIT;
68 const dstBits = @bitSizeOf(dst_t);
6669 const dstExpBits = dstBits - dstSigBits - 1;
6770 const dstInfExp = (1 << dstExpBits) - 1;
6871 const dstExpBias = dstInfExp >> 1;
lib/std/special/compiler_rt/extendXfYf2_test.zig+3-2
......@@ -3,6 +3,7 @@ const __extendhfsf2 = @import("extendXfYf2.zig").__extendhfsf2;
33const __extendhftf2 = @import("extendXfYf2.zig").__extendhftf2;
44const __extendsftf2 = @import("extendXfYf2.zig").__extendsftf2;
55const __extenddftf2 = @import("extendXfYf2.zig").__extenddftf2;
6const F16T = @import("extendXfYf2.zig").F16T;
67
78fn test__extenddftf2(a: f64, expectedHi: u64, expectedLo: u64) !void {
89 const x = __extenddftf2(a);
......@@ -27,7 +28,7 @@ fn test__extenddftf2(a: f64, expectedHi: u64, expectedLo: u64) !void {
2728}
2829
2930fn test__extendhfsf2(a: u16, expected: u32) !void {
30 const x = __extendhfsf2(a);
31 const x = __extendhfsf2(@bitCast(F16T, a));
3132 const rep = @bitCast(u32, x);
3233
3334 if (rep == expected) {
......@@ -159,7 +160,7 @@ fn makeInf32() f32 {
159160}
160161
161162fn test__extendhftf2(a: u16, expectedHi: u64, expectedLo: u64) !void {
162 const x = __extendhftf2(a);
163 const x = __extendhftf2(@bitCast(F16T, a));
163164
164165 const rep = @bitCast(u128, x);
165166 const hi = @intCast(u64, rep >> 64);
lib/std/special/compiler_rt/truncXfYf2.zig+12-6
......@@ -1,15 +1,21 @@
11const std = @import("std");
2const builtin = @import("builtin");
3const native_arch = builtin.cpu.arch;
24
3pub fn __truncsfhf2(a: f32) callconv(.C) u16 {
4 return @bitCast(u16, @call(.{ .modifier = .always_inline }, truncXfYf2, .{ f16, f32, a }));
5// AArch64 is the only ABI (at the moment) to support f16 arguments without the
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 }));
511}
612
7pub fn __truncdfhf2(a: f64) callconv(.C) u16 {
8 return @bitCast(u16, @call(.{ .modifier = .always_inline }, truncXfYf2, .{ f16, f64, a }));
13pub fn __truncdfhf2(a: f64) callconv(.C) F16T {
14 return @bitCast(F16T, @call(.{ .modifier = .always_inline }, truncXfYf2, .{ f16, f64, a }));
915}
1016
11pub fn __trunctfhf2(a: f128) callconv(.C) u16 {
12 return @bitCast(u16, @call(.{ .modifier = .always_inline }, truncXfYf2, .{ f16, f128, a }));
17pub fn __trunctfhf2(a: f128) callconv(.C) F16T {
18 return @bitCast(F16T, @call(.{ .modifier = .always_inline }, truncXfYf2, .{ f16, f128, a }));
1319}
1420
1521pub fn __trunctfsf2(a: f128) callconv(.C) f32 {
lib/std/special/compiler_rt/truncXfYf2_test.zig+2-2
......@@ -1,7 +1,7 @@
11const __truncsfhf2 = @import("truncXfYf2.zig").__truncsfhf2;
22
33fn test__truncsfhf2(a: u32, expected: u16) !void {
4 const actual = __truncsfhf2(@bitCast(f32, a));
4 const actual = @bitCast(u16, __truncsfhf2(@bitCast(f32, a)));
55
66 if (actual == expected) {
77 return;
......@@ -82,7 +82,7 @@ fn test__truncdfhf2(a: f64, expected: u16) void {
8282}
8383
8484fn 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
8787 if (actual == expected) {
8888 return;
test/behavior/cast_stage1.zig+26
......@@ -263,6 +263,32 @@ test "cast *[1][*]const u8 to [*]const ?[*]const u8" {
263263 try expect(mem.eql(u8, std.mem.spanZ(@ptrCast([*:0]const u8, x[0].?)), "window name"));
264264}
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
266292test "vector casts" {
267293 const S = struct {
268294 fn doTheTest() !void {
test/behavior/muladd.zig+1-2
......@@ -24,8 +24,7 @@ fn testMulAdd() !void {
2424 var c: f64 = 6.25;
2525 try expect(@mulAdd(f64, a, b, c) == 20);
2626 }
27 // TODO https://github.com/ziglang/zig/issues/9900
28 if (@import("builtin").cpu.arch != .aarch64) {
27 {
2928 var a: f16 = 5.5;
3029 var b: f128 = 2.5;
3130 var c: f128 = 6.25;