| 1 | const std = @import("std"); |
| 2 | const math = std.math; |
| 3 | const compiler_rt = @import("../compiler_rt.zig"); |
| 4 | const symbol = compiler_rt.symbol; |
| 5 | const normalize = compiler_rt.normalize; |
| 6 | |
| 7 | comptime { |
| 8 | symbol(&__addhf3, "__addhf3"); |
| 9 | if (compiler_rt.want_aeabi) { |
| 10 | symbol(&__aeabi_fadd, "__aeabi_fadd"); |
| 11 | symbol(&__aeabi_dadd, "__aeabi_dadd"); |
| 12 | } else { |
| 13 | symbol(&__addsf3, "__addsf3"); |
| 14 | symbol(&__adddf3, "__adddf3"); |
| 15 | } |
| 16 | symbol(&__addxf3, "__addxf3"); |
| 17 | if (compiler_rt.want_ppc_abi) { |
| 18 | symbol(&__addtf3, "__addkf3"); |
| 19 | } else if (compiler_rt.want_sparc64_abi) { |
| 20 | symbol(&_Qp_add, "_Qp_add"); |
| 21 | } else if (compiler_rt.want_sparc32_abi) { |
| 22 | symbol(&__addtf3, "_Q_add"); |
| 23 | } else { |
| 24 | symbol(&__addtf3, "__addtf3"); |
| 25 | } |
| 26 | } |
| 27 | |
| 28 | fn __addhf3(a: compiler_rt.f16.Abi, b: compiler_rt.f16.Abi) callconv(.c) compiler_rt.f16.Abi { |
| 29 | return compiler_rt.f16.toAbi(add_f16(compiler_rt.f16.fromAbi(a), compiler_rt.f16.fromAbi(b))); |
| 30 | } |
| 31 | pub fn add_f16(a: f16, b: f16) f16 { |
| 32 | return addf3(f16, a, b); |
| 33 | } |
| 34 | |
| 35 | fn __addsf3(a: compiler_rt.f32.Abi, b: compiler_rt.f32.Abi) callconv(.c) compiler_rt.f32.Abi { |
| 36 | return compiler_rt.f32.toAbi(add_f32(compiler_rt.f32.fromAbi(a), compiler_rt.f32.fromAbi(b))); |
| 37 | } |
| 38 | fn __aeabi_fadd(a: f32, b: f32) callconv(.{ .arm_aapcs = .{} }) f32 { |
| 39 | return add_f32(a, b); |
| 40 | } |
| 41 | pub fn add_f32(a: f32, b: f32) f32 { |
| 42 | return addf3(f32, a, b); |
| 43 | } |
| 44 | |
| 45 | fn __adddf3(a: compiler_rt.f64.Abi, b: compiler_rt.f64.Abi) callconv(.c) compiler_rt.f64.Abi { |
| 46 | return compiler_rt.f64.toAbi(add_f64(compiler_rt.f64.fromAbi(a), compiler_rt.f64.fromAbi(b))); |
| 47 | } |
| 48 | fn __aeabi_dadd(a: f64, b: f64) callconv(.{ .arm_aapcs = .{} }) f64 { |
| 49 | return add_f64(a, b); |
| 50 | } |
| 51 | pub fn add_f64(a: f64, b: f64) f64 { |
| 52 | return addf3(f64, a, b); |
| 53 | } |
| 54 | |
| 55 | fn __addxf3(a: compiler_rt.f80.Abi, b: compiler_rt.f80.Abi) callconv(.c) compiler_rt.f80.Abi { |
| 56 | return compiler_rt.f80.toAbi(add_f80(compiler_rt.f80.fromAbi(a), compiler_rt.f80.fromAbi(b))); |
| 57 | } |
| 58 | pub fn add_f80(a: f80, b: f80) f80 { |
| 59 | return addf3(f80, a, b); |
| 60 | } |
| 61 | |
| 62 | fn __addtf3(a: compiler_rt.f128.Abi, b: compiler_rt.f128.Abi) callconv(.c) compiler_rt.f128.Abi { |
| 63 | return compiler_rt.f128.toAbi(add_f128(compiler_rt.f128.fromAbi(a), compiler_rt.f128.fromAbi(b))); |
| 64 | } |
| 65 | fn _Qp_add(c: *f128, a: *f128, b: *f128) callconv(.c) void { |
| 66 | c.* = add_f128(a.*, b.*); |
| 67 | } |
| 68 | pub fn add_f128(a: f128, b: f128) f128 { |
| 69 | return addf3(f128, a, b); |
| 70 | } |
| 71 | |
| 72 | comptime { |
| 73 | symbol(&__subhf3, "__subhf3"); |
| 74 | if (compiler_rt.want_aeabi) { |
| 75 | symbol(&__aeabi_fsub, "__aeabi_fsub"); |
| 76 | symbol(&__aeabi_dsub, "__aeabi_dsub"); |
| 77 | } else { |
| 78 | symbol(&__subsf3, "__subsf3"); |
| 79 | symbol(&__subdf3, "__subdf3"); |
| 80 | } |
| 81 | symbol(&__subxf3, "__subxf3"); |
| 82 | if (compiler_rt.want_ppc_abi) { |
| 83 | symbol(&__subtf3, "__subkf3"); |
| 84 | } else if (compiler_rt.want_sparc64_abi) { |
| 85 | symbol(&_Qp_sub, "_Qp_sub"); |
| 86 | } else if (compiler_rt.want_sparc32_abi) { |
| 87 | symbol(&__subtf3, "_Q_sub"); |
| 88 | } else { |
| 89 | symbol(&__subtf3, "__subtf3"); |
| 90 | } |
| 91 | } |
| 92 | |
| 93 | fn __subhf3(a: compiler_rt.f16.Abi, b: compiler_rt.f16.Abi) callconv(.c) compiler_rt.f16.Abi { |
| 94 | return compiler_rt.f16.toAbi(sub_f16(compiler_rt.f16.fromAbi(a), compiler_rt.f16.fromAbi(b))); |
| 95 | } |
| 96 | pub fn sub_f16(a: f16, b: f16) f16 { |
| 97 | return add_f16(a, compiler_rt.fneg(b)); |
| 98 | } |
| 99 | |
| 100 | fn __subsf3(a: compiler_rt.f32.Abi, b: compiler_rt.f32.Abi) callconv(.c) compiler_rt.f32.Abi { |
| 101 | return compiler_rt.f32.toAbi(sub_f32(compiler_rt.f32.fromAbi(a), compiler_rt.f32.fromAbi(b))); |
| 102 | } |
| 103 | fn __aeabi_fsub(a: f32, b: f32) callconv(.{ .arm_aapcs = .{} }) f32 { |
| 104 | return sub_f32(a, b); |
| 105 | } |
| 106 | pub fn sub_f32(a: f32, b: f32) f32 { |
| 107 | return add_f32(a, compiler_rt.fneg(b)); |
| 108 | } |
| 109 | |
| 110 | fn __subdf3(a: compiler_rt.f64.Abi, b: compiler_rt.f64.Abi) callconv(.c) compiler_rt.f64.Abi { |
| 111 | return compiler_rt.f64.toAbi(sub_f64(compiler_rt.f64.fromAbi(a), compiler_rt.f64.fromAbi(b))); |
| 112 | } |
| 113 | fn __aeabi_dsub(a: f64, b: f64) callconv(.{ .arm_aapcs = .{} }) f64 { |
| 114 | return sub_f64(a, b); |
| 115 | } |
| 116 | pub fn sub_f64(a: f64, b: f64) f64 { |
| 117 | return add_f64(a, compiler_rt.fneg(b)); |
| 118 | } |
| 119 | |
| 120 | fn __subxf3(a: compiler_rt.f80.Abi, b: compiler_rt.f80.Abi) callconv(.c) compiler_rt.f80.Abi { |
| 121 | return compiler_rt.f80.toAbi(sub_f80(compiler_rt.f80.fromAbi(a), compiler_rt.f80.fromAbi(b))); |
| 122 | } |
| 123 | pub fn sub_f80(a: f80, b: f80) f80 { |
| 124 | return add_f80(a, compiler_rt.fneg(b)); |
| 125 | } |
| 126 | |
| 127 | fn __subtf3(a: compiler_rt.f128.Abi, b: compiler_rt.f128.Abi) callconv(.c) compiler_rt.f128.Abi { |
| 128 | return compiler_rt.f128.toAbi(sub_f128(compiler_rt.f128.fromAbi(a), compiler_rt.f128.fromAbi(b))); |
| 129 | } |
| 130 | fn _Qp_sub(c: *f128, a: *const f128, b: *const f128) callconv(.c) void { |
| 131 | c.* = sub_f128(a.*, b.*); |
| 132 | } |
| 133 | pub fn sub_f128(a: f128, b: f128) f128 { |
| 134 | return add_f128(a, compiler_rt.fneg(b)); |
| 135 | } |
| 136 | |
| 137 | /// Ported from: |
| 138 | /// |
| 139 | /// https://github.com/llvm/llvm-project/blob/02d85149a05cb1f6dc49f0ba7a2ceca53718ae17/compiler-rt/lib/builtins/fp_add_impl.inc |
| 140 | inline fn addf3(comptime T: type, a: T, b: T) T { |
| 141 | const bits = @typeInfo(T).float.bits; |
| 142 | const Z = @Int(.unsigned, bits); |
| 143 | |
| 144 | const typeWidth = bits; |
| 145 | const significandBits = math.floatMantissaBits(T); |
| 146 | const fractionalBits = math.floatFractionalBits(T); |
| 147 | const exponentBits = math.floatExponentBits(T); |
| 148 | |
| 149 | const signBit = (@as(Z, 1) << (significandBits + exponentBits)); |
| 150 | const maxExponent = ((1 << exponentBits) - 1); |
| 151 | |
| 152 | const integerBit = (@as(Z, 1) << fractionalBits); |
| 153 | const quietBit = integerBit >> 1; |
| 154 | const significandMask = (@as(Z, 1) << significandBits) - 1; |
| 155 | |
| 156 | const absMask = signBit - 1; |
| 157 | const qnanRep = @as(Z, @bitCast(math.nan(T))) | quietBit; |
| 158 | |
| 159 | var aRep: Z = @bitCast(a); |
| 160 | var bRep: Z = @bitCast(b); |
| 161 | const aAbs = aRep & absMask; |
| 162 | const bAbs = bRep & absMask; |
| 163 | |
| 164 | const infRep: Z = @bitCast(math.inf(T)); |
| 165 | |
| 166 | // Detect if a or b is zero, infinity, or NaN. |
| 167 | if (aAbs -% @as(Z, 1) >= infRep - @as(Z, 1) or |
| 168 | bAbs -% @as(Z, 1) >= infRep - @as(Z, 1)) |
| 169 | { |
| 170 | // NaN + anything = qNaN |
| 171 | if (aAbs > infRep) return @bitCast(@as(Z, @bitCast(a)) | quietBit); |
| 172 | // anything + NaN = qNaN |
| 173 | if (bAbs > infRep) return @bitCast(@as(Z, @bitCast(b)) | quietBit); |
| 174 | |
| 175 | if (aAbs == infRep) { |
| 176 | // +/-infinity + -/+infinity = qNaN |
| 177 | if ((@as(Z, @bitCast(a)) ^ @as(Z, @bitCast(b))) == signBit) { |
| 178 | return @bitCast(qnanRep); |
| 179 | } |
| 180 | // +/-infinity + anything remaining = +/- infinity |
| 181 | else { |
| 182 | return a; |
| 183 | } |
| 184 | } |
| 185 | |
| 186 | // anything remaining + +/-infinity = +/-infinity |
| 187 | if (bAbs == infRep) return b; |
| 188 | |
| 189 | // zero + anything = anything |
| 190 | if (aAbs == 0) { |
| 191 | // but we need to get the sign right for zero + zero |
| 192 | if (bAbs == 0) { |
| 193 | return @bitCast(@as(Z, @bitCast(a)) & @as(Z, @bitCast(b))); |
| 194 | } else { |
| 195 | return b; |
| 196 | } |
| 197 | } |
| 198 | |
| 199 | // anything + zero = anything |
| 200 | if (bAbs == 0) return a; |
| 201 | } |
| 202 | |
| 203 | // Swap a and b if necessary so that a has the larger absolute value. |
| 204 | if (bAbs > aAbs) { |
| 205 | const temp = aRep; |
| 206 | aRep = bRep; |
| 207 | bRep = temp; |
| 208 | } |
| 209 | |
| 210 | // Extract the exponent and significand from the (possibly swapped) a and b. |
| 211 | var aExponent: i32 = @intCast((aRep >> significandBits) & maxExponent); |
| 212 | var bExponent: i32 = @intCast((bRep >> significandBits) & maxExponent); |
| 213 | var aSignificand = aRep & significandMask; |
| 214 | var bSignificand = bRep & significandMask; |
| 215 | |
| 216 | // Normalize any denormals, and adjust the exponent accordingly. |
| 217 | if (aExponent == 0) aExponent = normalize(T, &aSignificand); |
| 218 | if (bExponent == 0) bExponent = normalize(T, &bSignificand); |
| 219 | |
| 220 | // The sign of the result is the sign of the larger operand, a. If they |
| 221 | // have opposite signs, we are performing a subtraction; otherwise addition. |
| 222 | const resultSign = aRep & signBit; |
| 223 | const subtraction = (aRep ^ bRep) & signBit != 0; |
| 224 | |
| 225 | // Shift the significands to give us round, guard and sticky, and or in the |
| 226 | // implicit significand bit. (If we fell through from the denormal path it |
| 227 | // was already set by normalize( ), but setting it twice won't hurt |
| 228 | // anything.) |
| 229 | aSignificand = (aSignificand | integerBit) << 3; |
| 230 | bSignificand = (bSignificand | integerBit) << 3; |
| 231 | |
| 232 | // Shift the significand of b by the difference in exponents, with a sticky |
| 233 | // bottom bit to get rounding correct. |
| 234 | const @"align": u32 = @intCast(aExponent - bExponent); |
| 235 | if (@"align" != 0) { |
| 236 | if (@"align" < typeWidth) { |
| 237 | const sticky = if (bSignificand << @intCast(typeWidth - @"align") != 0) @as(Z, 1) else 0; |
| 238 | bSignificand = (bSignificand >> @truncate(@"align")) | sticky; |
| 239 | } else { |
| 240 | bSignificand = 1; // sticky; b is known to be non-zero. |
| 241 | } |
| 242 | } |
| 243 | if (subtraction) { |
| 244 | aSignificand -= bSignificand; |
| 245 | // If a == -b, return +zero. |
| 246 | if (aSignificand == 0) return @bitCast(@as(Z, 0)); |
| 247 | |
| 248 | // If partial cancellation occurred, we need to left-shift the result |
| 249 | // and adjust the exponent: |
| 250 | if (aSignificand < integerBit << 3) { |
| 251 | const shift = @as(i32, @intCast(@clz(aSignificand))) - @as(i32, @intCast(@clz(integerBit << 3))); |
| 252 | aSignificand <<= @intCast(shift); |
| 253 | aExponent -= shift; |
| 254 | } |
| 255 | } else { // addition |
| 256 | aSignificand += bSignificand; |
| 257 | |
| 258 | // If the addition carried up, we need to right-shift the result and |
| 259 | // adjust the exponent: |
| 260 | if (aSignificand & (integerBit << 4) != 0) { |
| 261 | const sticky = aSignificand & 1; |
| 262 | aSignificand = aSignificand >> 1 | sticky; |
| 263 | aExponent += 1; |
| 264 | } |
| 265 | } |
| 266 | |
| 267 | // If we have overflowed the type, return +/- infinity: |
| 268 | if (aExponent >= maxExponent) return @bitCast(infRep | resultSign); |
| 269 | |
| 270 | if (aExponent <= 0) { |
| 271 | // Result is denormal; the exponent and round/sticky bits are zero. |
| 272 | // All we need to do is shift the significand and apply the correct sign. |
| 273 | aSignificand >>= @intCast(4 - aExponent); |
| 274 | return @bitCast(resultSign | aSignificand); |
| 275 | } |
| 276 | |
| 277 | // Low three bits are round, guard, and sticky. |
| 278 | const roundGuardSticky = aSignificand & 0x7; |
| 279 | |
| 280 | // Shift the significand into place, and mask off the integer bit, if it's implicit. |
| 281 | var result = (aSignificand >> 3) & significandMask; |
| 282 | |
| 283 | // Insert the exponent and sign. |
| 284 | result |= @as(Z, @intCast(aExponent)) << significandBits; |
| 285 | result |= resultSign; |
| 286 | |
| 287 | // Final rounding. The result may overflow to infinity, but that is the |
| 288 | // correct result in that case. |
| 289 | if (roundGuardSticky > 0x4) result += 1; |
| 290 | if (roundGuardSticky == 0x4) result += result & 1; |
| 291 | |
| 292 | // Restore any explicit integer bit, if it was rounded off |
| 293 | if (significandBits != fractionalBits) { |
| 294 | if ((result >> significandBits) != 0) result |= integerBit; |
| 295 | } |
| 296 | |
| 297 | return @bitCast(result); |
| 298 | } |
| 299 | |
| 300 | test { |
| 301 | _ = @import("addf3_test.zig"); |
| 302 | } |