| 1 | // Ported from: |
| 2 | // |
| 3 | // https://github.com/llvm/llvm-project/blob/2ffb1b0413efa9a24eb3c49e710e36f92e2cb50b/compiler-rt/test/builtins/Unit/multf3_test.c |
| 4 | |
| 5 | const std = @import("std"); |
| 6 | const math = std.math; |
| 7 | const qnan128: f128 = @bitCast(@as(u128, 0x7fff800000000000) << 64); |
| 8 | const inf128: f128 = @bitCast(@as(u128, 0x7fff000000000000) << 64); |
| 9 | |
| 10 | const impl = @import("mulf3.zig"); |
| 11 | const mul_f16 = impl.mul_f16; |
| 12 | const mul_f32 = impl.mul_f32; |
| 13 | const mul_f64 = impl.mul_f64; |
| 14 | const mul_f80 = impl.mul_f80; |
| 15 | const 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 |
| 20 | fn 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 | |
| 39 | fn 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 | |
| 48 | fn makeNaN128(rand: u64) f128 { |
| 49 | const int_result = @as(u128, 0x7fff000000000000 | (rand & 0xffffffffffff)) << 64; |
| 50 | return @bitCast(int_result); |
| 51 | } |
| 52 | test "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 | |
| 112 | const qnan80: f80 = @bitCast(@as(u80, @bitCast(math.nan(f80))) | (1 << (math.floatFractionalBits(f80) - 1))); |
| 113 | |
| 114 | fn 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 | |
| 127 | test "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 | } |