1// Ported from:
2//
3// https://github.com/llvm/llvm-project/blob/2ffb1b0413efa9a24eb3c49e710e36f92e2cb50b/compiler-rt/test/builtins/Unit/multf3_test.c
4
5const std = @import("std");
6const math = std.math;
7const qnan128: f128 = @bitCast(@as(u128, 0x7fff800000000000) << 64);
8const inf128: f128 = @bitCast(@as(u128, 0x7fff000000000000) << 64);
9
10const impl = @import("mulf3.zig");
11const mul_f16 = impl.mul_f16;
12const mul_f32 = impl.mul_f32;
13const mul_f64 = impl.mul_f64;
14const mul_f80 = impl.mul_f80;
15const mul_f128 = impl.mul_f128;
16
17// return true if equal
18// use two 64-bit integers instead of one 128-bit integer
19// because 128-bit integer constant can't be assigned directly
20fn compareResultLD(result: f128, expectedHi: u64, expectedLo: u64) bool {
21 const rep: u128 = @bitCast(result);
22 const hi: u64 = @intCast(rep >> 64);
23 const lo: u64 = @truncate(rep);
24
25 if (hi == expectedHi and lo == expectedLo) {
26 return true;
27 }
28 // test other possible NaN representation(signal NaN)
29 if (expectedHi == 0x7fff800000000000 and expectedLo == 0x0) {
30 if ((hi & 0x7fff000000000000) == 0x7fff000000000000 and
31 ((hi & 0xffffffffffff) > 0 or lo > 0))
32 {
33 return true;
34 }
35 }
36 return false;
37}
38
39fn test_mul_f128(a: f128, b: f128, expected_hi: u64, expected_lo: u64) !void {
40 const x = mul_f128(a, b);
41
42 if (compareResultLD(x, expected_hi, expected_lo))
43 return;
44
45 @panic("__multf3 test failure");
46}
47
48fn makeNaN128(rand: u64) f128 {
49 const int_result = @as(u128, 0x7fff000000000000 | (rand & 0xffffffffffff)) << 64;
50 return @bitCast(int_result);
51}
52test "multf3" {
53 // qNaN * any = qNaN
54 try test_mul_f128(qnan128, 0x1.23456789abcdefp+5, 0x7fff800000000000, 0x0);
55
56 // NaN * any = NaN
57 const a = makeNaN128(0x800030000000);
58 try test_mul_f128(a, 0x1.23456789abcdefp+5, 0x7fff800000000000, 0x0);
59 // inf * any = inf
60 try test_mul_f128(inf128, 0x1.23456789abcdefp+5, 0x7fff000000000000, 0x0);
61
62 // any * any
63 try test_mul_f128(
64 @as(f128, @bitCast(@as(u128, 0x40042eab345678439abcdefea5678234))),
65 @as(f128, @bitCast(@as(u128, 0x3ffeedcb34a235253948765432134675))),
66 0x400423e7f9e3c9fc,
67 0xd906c2c2a85777c4,
68 );
69
70 try test_mul_f128(
71 @as(f128, @bitCast(@as(u128, 0x3fcd353e45674d89abacc3a2ebf3ff50))),
72 @as(f128, @bitCast(@as(u128, 0x3ff6ed8764648369535adf4be3214568))),
73 0x3fc52a163c6223fc,
74 0xc94c4bf0430768b4,
75 );
76
77 try test_mul_f128(
78 0x1.234425696abcad34a35eeffefdcbap+456,
79 0x451.ed98d76e5d46e5f24323dff21ffp+600,
80 0x44293a91de5e0e94,
81 0xe8ed17cc2cdf64ac,
82 );
83
84 try test_mul_f128(
85 @as(f128, @bitCast(@as(u128, 0x3f154356473c82a9fabf2d22ace345df))),
86 @as(f128, @bitCast(@as(u128, 0x3e38eda98765476743ab21da23d45679))),
87 0x3d4f37c1a3137cae,
88 0xfc6807048bc2836a,
89 );
90
91 try test_mul_f128(0x1.23456734245345p-10000, 0x1.edcba524498724p-6497, 0x0, 0x0);
92
93 // Denormal operands.
94 try test_mul_f128(
95 0x0.0000000000000000000000000001p-16382,
96 0x1p16383,
97 0x3f90000000000000,
98 0x0,
99 );
100 try test_mul_f128(
101 0x1p16383,
102 0x0.0000000000000000000000000001p-16382,
103 0x3f90000000000000,
104 0x0,
105 );
106
107 try test_mul_f128(0x1.0000_0000_0000_0000_0000_0000_0001p+0, 0x1.8p+5, 0x4004_8000_0000_0000, 0x0000_0000_0000_0002);
108 try test_mul_f128(0x1.0000_0000_0000_0000_0000_0000_0002p+0, 0x1.8p+5, 0x4004_8000_0000_0000, 0x0000_0000_0000_0003);
109 try test_mul_f128(2.0, math.floatTrueMin(f128), 0x0000_0000_0000_0000, 0x0000_0000_0000_0002);
110}
111
112const qnan80: f80 = @bitCast(@as(u80, @bitCast(math.nan(f80))) | (1 << (math.floatFractionalBits(f80) - 1)));
113
114fn test_mul_f80(a: f80, b: f80, expected: u80) !void {
115 const x = mul_f80(a, b);
116 const rep: u80 = @bitCast(x);
117
118 if (rep == expected)
119 return;
120
121 if (math.isNan(@as(f80, @bitCast(expected))) and math.isNan(x))
122 return; // We don't currently test NaN payload propagation
123
124 return error.TestFailed;
125}
126
127test "mulxf3" {
128 // NaN * any = NaN
129 try test_mul_f80(qnan80, 0x1.23456789abcdefp+5, @as(u80, @bitCast(qnan80)));
130 try test_mul_f80(@as(f80, @bitCast(@as(u80, 0x7fff_8000_8000_3000_0000))), 0x1.23456789abcdefp+5, @as(u80, @bitCast(qnan80)));
131
132 // any * NaN = NaN
133 try test_mul_f80(0x1.23456789abcdefp+5, qnan80, @as(u80, @bitCast(qnan80)));
134 try test_mul_f80(0x1.23456789abcdefp+5, @as(f80, @bitCast(@as(u80, 0x7fff_8000_8000_3000_0000))), @as(u80, @bitCast(qnan80)));
135
136 // NaN * inf = NaN
137 try test_mul_f80(qnan80, math.inf(f80), @as(u80, @bitCast(qnan80)));
138
139 // inf * NaN = NaN
140 try test_mul_f80(math.inf(f80), qnan80, @as(u80, @bitCast(qnan80)));
141
142 // inf * inf = inf
143 try test_mul_f80(math.inf(f80), math.inf(f80), @as(u80, @bitCast(math.inf(f80))));
144
145 // inf * -inf = -inf
146 try test_mul_f80(math.inf(f80), -math.inf(f80), @as(u80, @bitCast(-math.inf(f80))));
147
148 // -inf + inf = -inf
149 try test_mul_f80(-math.inf(f80), math.inf(f80), @as(u80, @bitCast(-math.inf(f80))));
150
151 // inf * any = inf
152 try test_mul_f80(math.inf(f80), 0x1.2335653452436234723489432abcdefp+5, @as(u80, @bitCast(math.inf(f80))));
153
154 // any * inf = inf
155 try test_mul_f80(0x1.2335653452436234723489432abcdefp+5, math.inf(f80), @as(u80, @bitCast(math.inf(f80))));
156
157 // any * any
158 try test_mul_f80(0x1.0p+0, 0x1.dcba987654321p+5, 0x4004_ee5d_4c3b_2a19_0800);
159 try test_mul_f80(0x1.0000_0000_0000_0004p+0, 0x1.8p+5, 0x4004_C000_0000_0000_0003); // exact
160
161 try test_mul_f80(0x1.0000_0000_0000_0002p+0, 0x1.0p+5, 0x4004_8000_0000_0000_0001); // exact
162 try test_mul_f80(0x1.0000_0000_0000_0002p+0, 0x1.7ffep+5, 0x4004_BFFF_0000_0000_0001); // round down
163 try test_mul_f80(0x1.0000_0000_0000_0002p+0, 0x1.8p+5, 0x4004_C000_0000_0000_0002); // round up to even
164 try test_mul_f80(0x1.0000_0000_0000_0002p+0, 0x1.8002p+5, 0x4004_C001_0000_0000_0002); // round up
165 try test_mul_f80(0x1.0000_0000_0000_0002p+0, 0x1.0p+6, 0x4005_8000_0000_0000_0001); // exact
166
167 try test_mul_f80(0x1.0000_0001p+0, 0x1.0000_0001p+0, 0x3FFF_8000_0001_0000_0000); // round down to even
168 try test_mul_f80(0x1.0000_0001p+0, 0x1.0000_0001_0002p+0, 0x3FFF_8000_0001_0001_0001); // round up
169 try test_mul_f80(0x0.8000_0000_0000_0000p-16382, 2.0, 0x0001_8000_0000_0000_0000); // denormal -> normal
170 try test_mul_f80(0x0.7fff_ffff_ffff_fffep-16382, 0x2.0000_0000_0000_0008p0, 0x0001_8000_0000_0000_0000); // denormal -> normal
171 try test_mul_f80(0x0.7fff_ffff_ffff_fffep-16382, 0x1.0000_0000_0000_0000p0, 0x0000_3FFF_FFFF_FFFF_FFFF); // denormal -> denormal
172}