| ... | @@ -3,6 +3,7 @@ | ... | @@ -3,6 +3,7 @@ |
| 3 | // https://github.com/llvm/llvm-project/blob/02d85149a05cb1f6dc49f0ba7a2ceca53718ae17/compiler-rt/lib/builtins/fp_add_impl.inc | 3 | // https://github.com/llvm/llvm-project/blob/02d85149a05cb1f6dc49f0ba7a2ceca53718ae17/compiler-rt/lib/builtins/fp_add_impl.inc |
| 4 | | 4 | |
| 5 | const std = @import("std"); | 5 | const std = @import("std"); |
| | 6 | const math = std.math; |
| 6 | const builtin = @import("builtin"); | 7 | const builtin = @import("builtin"); |
| 7 | const compiler_rt = @import("../compiler_rt.zig"); | 8 | const compiler_rt = @import("../compiler_rt.zig"); |
| 8 | | 9 | |
| ... | @@ -14,6 +15,16 @@ pub fn __adddf3(a: f64, b: f64) callconv(.C) f64 { | ... | @@ -14,6 +15,16 @@ pub fn __adddf3(a: f64, b: f64) callconv(.C) f64 { |
| 14 | return addXf3(f64, a, b); | 15 | return addXf3(f64, a, b); |
| 15 | } | 16 | } |
| 16 | | 17 | |
| | 18 | pub fn __addxf3(a: f80, b: f80) callconv(.C) f80 { |
| | 19 | return addXf3(f80, a, b); |
| | 20 | } |
| | 21 | |
| | 22 | pub fn __subxf3(a: f80, b: f80) callconv(.C) f80 { |
| | 23 | var b_rep = std.math.break_f80(b); |
| | 24 | b_rep.exp ^= 0x8000; |
| | 25 | return __addxf3(a, std.math.make_f80(b_rep)); |
| | 26 | } |
| | 27 | |
| 17 | pub fn __addtf3(a: f128, b: f128) callconv(.C) f128 { | 28 | pub fn __addtf3(a: f128, b: f128) callconv(.C) f128 { |
| 18 | return addXf3(f128, a, b); | 29 | return addXf3(f128, a, b); |
| 19 | } | 30 | } |
| ... | @@ -58,10 +69,10 @@ fn normalize(comptime T: type, significand: *std.meta.Int(.unsigned, @typeInfo(T | ... | @@ -58,10 +69,10 @@ fn normalize(comptime T: type, significand: *std.meta.Int(.unsigned, @typeInfo(T |
| 58 | const bits = @typeInfo(T).Float.bits; | 69 | const bits = @typeInfo(T).Float.bits; |
| 59 | const Z = std.meta.Int(.unsigned, bits); | 70 | const Z = std.meta.Int(.unsigned, bits); |
| 60 | const S = std.meta.Int(.unsigned, bits - @clz(Z, @as(Z, bits) - 1)); | 71 | const S = std.meta.Int(.unsigned, bits - @clz(Z, @as(Z, bits) - 1)); |
| 61 | const significandBits = std.math.floatMantissaBits(T); | 72 | const fractionalBits = math.floatFractionalBits(T); |
| 62 | const implicitBit = @as(Z, 1) << significandBits; | 73 | const integerBit = @as(Z, 1) << fractionalBits; |
| 63 | | 74 | |
| 64 | const shift = @clz(std.meta.Int(.unsigned, bits), significand.*) - @clz(Z, implicitBit); | 75 | const shift = @clz(std.meta.Int(.unsigned, bits), significand.*) - @clz(Z, integerBit); |
| 65 | significand.* <<= @intCast(S, shift); | 76 | significand.* <<= @intCast(S, shift); |
| 66 | return 1 - shift; | 77 | return 1 - shift; |
| 67 | } | 78 | } |
| ... | @@ -73,26 +84,26 @@ fn addXf3(comptime T: type, a: T, b: T) T { | ... | @@ -73,26 +84,26 @@ fn addXf3(comptime T: type, a: T, b: T) T { |
| 73 | const S = std.meta.Int(.unsigned, bits - @clz(Z, @as(Z, bits) - 1)); | 84 | const S = std.meta.Int(.unsigned, bits - @clz(Z, @as(Z, bits) - 1)); |
| 74 | | 85 | |
| 75 | const typeWidth = bits; | 86 | const typeWidth = bits; |
| 76 | const significandBits = std.math.floatMantissaBits(T); | 87 | const significandBits = math.floatMantissaBits(T); |
| 77 | const exponentBits = std.math.floatExponentBits(T); | 88 | const fractionalBits = math.floatFractionalBits(T); |
| | 89 | const exponentBits = math.floatExponentBits(T); |
| 78 | | 90 | |
| 79 | const signBit = (@as(Z, 1) << (significandBits + exponentBits)); | 91 | const signBit = (@as(Z, 1) << (significandBits + exponentBits)); |
| 80 | const maxExponent = ((1 << exponentBits) - 1); | 92 | const maxExponent = ((1 << exponentBits) - 1); |
| 81 | | 93 | |
| 82 | const implicitBit = (@as(Z, 1) << significandBits); | 94 | const integerBit = (@as(Z, 1) << fractionalBits); |
| 83 | const quietBit = implicitBit >> 1; | 95 | const quietBit = integerBit >> 1; |
| 84 | const significandMask = implicitBit - 1; | 96 | const significandMask = (@as(Z, 1) << significandBits) - 1; |
| 85 | | 97 | |
| 86 | const absMask = signBit - 1; | 98 | const absMask = signBit - 1; |
| 87 | const exponentMask = absMask ^ significandMask; | 99 | const qnanRep = @bitCast(Z, math.nan(T)) | quietBit; |
| 88 | const qnanRep = exponentMask | quietBit; | | |
| 89 | | 100 | |
| 90 | var aRep = @bitCast(Z, a); | 101 | var aRep = @bitCast(Z, a); |
| 91 | var bRep = @bitCast(Z, b); | 102 | var bRep = @bitCast(Z, b); |
| 92 | const aAbs = aRep & absMask; | 103 | const aAbs = aRep & absMask; |
| 93 | const bAbs = bRep & absMask; | 104 | const bAbs = bRep & absMask; |
| 94 | | 105 | |
| 95 | const infRep = @bitCast(Z, std.math.inf(T)); | 106 | const infRep = @bitCast(Z, math.inf(T)); |
| 96 | | 107 | |
| 97 | // Detect if a or b is zero, infinity, or NaN. | 108 | // Detect if a or b is zero, infinity, or NaN. |
| 98 | if (aAbs -% @as(Z, 1) >= infRep - @as(Z, 1) or | 109 | if (aAbs -% @as(Z, 1) >= infRep - @as(Z, 1) or |
| ... | @@ -157,12 +168,12 @@ fn addXf3(comptime T: type, a: T, b: T) T { | ... | @@ -157,12 +168,12 @@ fn addXf3(comptime T: type, a: T, b: T) T { |
| 157 | // implicit significand bit. (If we fell through from the denormal path it | 168 | // implicit significand bit. (If we fell through from the denormal path it |
| 158 | // was already set by normalize( ), but setting it twice won't hurt | 169 | // was already set by normalize( ), but setting it twice won't hurt |
| 159 | // anything.) | 170 | // anything.) |
| 160 | aSignificand = (aSignificand | implicitBit) << 3; | 171 | aSignificand = (aSignificand | integerBit) << 3; |
| 161 | bSignificand = (bSignificand | implicitBit) << 3; | 172 | bSignificand = (bSignificand | integerBit) << 3; |
| 162 | | 173 | |
| 163 | // Shift the significand of b by the difference in exponents, with a sticky | 174 | // Shift the significand of b by the difference in exponents, with a sticky |
| 164 | // bottom bit to get rounding correct. | 175 | // bottom bit to get rounding correct. |
| 165 | const @"align" = @intCast(Z, aExponent - bExponent); | 176 | const @"align" = @intCast(u32, aExponent - bExponent); |
| 166 | if (@"align" != 0) { | 177 | if (@"align" != 0) { |
| 167 | if (@"align" < typeWidth) { | 178 | if (@"align" < typeWidth) { |
| 168 | const sticky = if (bSignificand << @intCast(S, typeWidth - @"align") != 0) @as(Z, 1) else 0; | 179 | const sticky = if (bSignificand << @intCast(S, typeWidth - @"align") != 0) @as(Z, 1) else 0; |
| ... | @@ -178,8 +189,8 @@ fn addXf3(comptime T: type, a: T, b: T) T { | ... | @@ -178,8 +189,8 @@ fn addXf3(comptime T: type, a: T, b: T) T { |
| 178 | | 189 | |
| 179 | // If partial cancellation occured, we need to left-shift the result | 190 | // If partial cancellation occured, we need to left-shift the result |
| 180 | // and adjust the exponent: | 191 | // and adjust the exponent: |
| 181 | if (aSignificand < implicitBit << 3) { | 192 | if (aSignificand < integerBit << 3) { |
| 182 | const shift = @intCast(i32, @clz(Z, aSignificand)) - @intCast(i32, @clz(std.meta.Int(.unsigned, bits), implicitBit << 3)); | 193 | const shift = @intCast(i32, @clz(Z, aSignificand)) - @intCast(i32, @clz(std.meta.Int(.unsigned, bits), integerBit << 3)); |
| 183 | aSignificand <<= @intCast(S, shift); | 194 | aSignificand <<= @intCast(S, shift); |
| 184 | aExponent -= shift; | 195 | aExponent -= shift; |
| 185 | } | 196 | } |
| ... | @@ -188,7 +199,7 @@ fn addXf3(comptime T: type, a: T, b: T) T { | ... | @@ -188,7 +199,7 @@ fn addXf3(comptime T: type, a: T, b: T) T { |
| 188 | | 199 | |
| 189 | // If the addition carried up, we need to right-shift the result and | 200 | // If the addition carried up, we need to right-shift the result and |
| 190 | // adjust the exponent: | 201 | // adjust the exponent: |
| 191 | if (aSignificand & (implicitBit << 4) != 0) { | 202 | if (aSignificand & (integerBit << 4) != 0) { |
| 192 | const sticky = aSignificand & 1; | 203 | const sticky = aSignificand & 1; |
| 193 | aSignificand = aSignificand >> 1 | sticky; | 204 | aSignificand = aSignificand >> 1 | sticky; |
| 194 | aExponent += 1; | 205 | aExponent += 1; |
| ... | @@ -210,7 +221,7 @@ fn addXf3(comptime T: type, a: T, b: T) T { | ... | @@ -210,7 +221,7 @@ fn addXf3(comptime T: type, a: T, b: T) T { |
| 210 | // Low three bits are round, guard, and sticky. | 221 | // Low three bits are round, guard, and sticky. |
| 211 | const roundGuardSticky = aSignificand & 0x7; | 222 | const roundGuardSticky = aSignificand & 0x7; |
| 212 | | 223 | |
| 213 | // Shift the significand into place, and mask off the implicit bit. | 224 | // Shift the significand into place, and mask off the integer bit, if it's implicit. |
| 214 | var result = (aSignificand >> 3) & significandMask; | 225 | var result = (aSignificand >> 3) & significandMask; |
| 215 | | 226 | |
| 216 | // Insert the exponent and sign. | 227 | // Insert the exponent and sign. |
| ... | @@ -222,178 +233,12 @@ fn addXf3(comptime T: type, a: T, b: T) T { | ... | @@ -222,178 +233,12 @@ fn addXf3(comptime T: type, a: T, b: T) T { |
| 222 | if (roundGuardSticky > 0x4) result += 1; | 233 | if (roundGuardSticky > 0x4) result += 1; |
| 223 | if (roundGuardSticky == 0x4) result += result & 1; | 234 | if (roundGuardSticky == 0x4) result += result & 1; |
| 224 | | 235 | |
| 225 | return @bitCast(T, result); | 236 | // Restore any explicit integer bit, if it was rounded off |
| 226 | } | 237 | if (significandBits != fractionalBits) { |
| 227 | | 238 | if ((result >> significandBits) != 0) result |= integerBit; |
| 228 | fn normalize_f80(exp: *i32, significand: *u80) void { | | |
| 229 | const shift = @clz(u64, @truncate(u64, significand.*)); | | |
| 230 | significand.* = (significand.* << shift); | | |
| 231 | exp.* += -@as(i8, shift); | | |
| 232 | } | | |
| 233 | | | |
| 234 | pub fn __addxf3(a: f80, b: f80) callconv(.C) f80 { | | |
| 235 | var a_rep = std.math.break_f80(a); | | |
| 236 | var b_rep = std.math.break_f80(b); | | |
| 237 | var a_exp: i32 = a_rep.exp & 0x7FFF; | | |
| 238 | var b_exp: i32 = b_rep.exp & 0x7FFF; | | |
| 239 | | | |
| 240 | const significand_bits = std.math.floatMantissaBits(f80); | | |
| 241 | const int_bit = 0x8000000000000000; | | |
| 242 | const significand_mask = 0x7FFFFFFFFFFFFFFF; | | |
| 243 | const qnan_bit = 0xC000000000000000; | | |
| 244 | const max_exp = 0x7FFF; | | |
| 245 | const sign_bit = 0x8000; | | |
| 246 | | | |
| 247 | // Detect if a or b is infinity, or NaN. | | |
| 248 | if (a_exp == max_exp) { | | |
| 249 | if (a_rep.fraction ^ int_bit == 0) { | | |
| 250 | if (b_exp == max_exp and (b_rep.fraction ^ int_bit == 0)) { | | |
| 251 | // +/-infinity + -/+infinity = qNaN | | |
| 252 | return std.math.qnan_f80; | | |
| 253 | } | | |
| 254 | // +/-infinity + anything = +/- infinity | | |
| 255 | return a; | | |
| 256 | } else { | | |
| 257 | std.debug.assert(a_rep.fraction & significand_mask != 0); | | |
| 258 | // NaN + anything = qNaN | | |
| 259 | a_rep.fraction |= qnan_bit; | | |
| 260 | return std.math.make_f80(a_rep); | | |
| 261 | } | | |
| 262 | } | | |
| 263 | if (b_exp == max_exp) { | | |
| 264 | if (b_rep.fraction ^ int_bit == 0) { | | |
| 265 | // anything + +/-infinity = +/-infinity | | |
| 266 | return b; | | |
| 267 | } else { | | |
| 268 | std.debug.assert(b_rep.fraction & significand_mask != 0); | | |
| 269 | // anything + NaN = qNaN | | |
| 270 | b_rep.fraction |= qnan_bit; | | |
| 271 | return std.math.make_f80(b_rep); | | |
| 272 | } | | |
| 273 | } | | |
| 274 | | | |
| 275 | const a_zero = (a_rep.fraction | @bitCast(u32, a_exp)) == 0; | | |
| 276 | const b_zero = (b_rep.fraction | @bitCast(u32, b_exp)) == 0; | | |
| 277 | if (a_zero) { | | |
| 278 | // zero + anything = anything | | |
| 279 | if (b_zero) { | | |
| 280 | // but we need to get the sign right for zero + zero | | |
| 281 | a_rep.exp &= b_rep.exp; | | |
| 282 | return std.math.make_f80(a_rep); | | |
| 283 | } else { | | |
| 284 | return b; | | |
| 285 | } | | |
| 286 | } else if (b_zero) { | | |
| 287 | // anything + zero = anything | | |
| 288 | return a; | | |
| 289 | } | | |
| 290 | | | |
| 291 | var a_int: u80 = a_rep.fraction | (@as(u80, a_rep.exp & max_exp) << significand_bits); | | |
| 292 | var b_int: u80 = b_rep.fraction | (@as(u80, b_rep.exp & max_exp) << significand_bits); | | |
| 293 | | | |
| 294 | // Swap a and b if necessary so that a has the larger absolute value. | | |
| 295 | if (b_int > a_int) { | | |
| 296 | const temp = a_rep; | | |
| 297 | a_rep = b_rep; | | |
| 298 | b_rep = temp; | | |
| 299 | } | | |
| 300 | | | |
| 301 | // Extract the exponent and significand from the (possibly swapped) a and b. | | |
| 302 | a_exp = a_rep.exp & max_exp; | | |
| 303 | b_exp = b_rep.exp & max_exp; | | |
| 304 | a_int = a_rep.fraction; | | |
| 305 | b_int = b_rep.fraction; | | |
| 306 | | | |
| 307 | // Normalize any denormals, and adjust the exponent accordingly. | | |
| 308 | normalize_f80(&a_exp, &a_int); | | |
| 309 | normalize_f80(&b_exp, &b_int); | | |
| 310 | | | |
| 311 | // The sign of the result is the sign of the larger operand, a. If they | | |
| 312 | // have opposite signs, we are performing a subtraction; otherwise addition. | | |
| 313 | const result_sign = a_rep.exp & sign_bit; | | |
| 314 | const subtraction = (a_rep.exp ^ b_rep.exp) & sign_bit != 0; | | |
| 315 | | | |
| 316 | // Shift the significands to give us round, guard and sticky, and or in the | | |
| 317 | // implicit significand bit. (If we fell through from the denormal path it | | |
| 318 | // was already set by normalize( ), but setting it twice won't hurt | | |
| 319 | // anything.) | | |
| 320 | a_int = a_int << 3; | | |
| 321 | b_int = b_int << 3; | | |
| 322 | | | |
| 323 | // Shift the significand of b by the difference in exponents, with a sticky | | |
| 324 | // bottom bit to get rounding correct. | | |
| 325 | const @"align" = @intCast(u80, a_exp - b_exp); | | |
| 326 | if (@"align" != 0) { | | |
| 327 | if (@"align" < 80) { | | |
| 328 | const sticky = if (b_int << @intCast(u7, 80 - @"align") != 0) @as(u80, 1) else 0; | | |
| 329 | b_int = (b_int >> @truncate(u7, @"align")) | sticky; | | |
| 330 | } else { | | |
| 331 | b_int = 1; // sticky; b is known to be non-zero. | | |
| 332 | } | | |
| 333 | } | | |
| 334 | if (subtraction) { | | |
| 335 | a_int -= b_int; | | |
| 336 | // If a == -b, return +zero. | | |
| 337 | if (a_int == 0) return 0.0; | | |
| 338 | | | |
| 339 | // If partial cancellation occurred, we need to left-shift the result | | |
| 340 | // and adjust the exponent: | | |
| 341 | if (a_int < int_bit << 3) { | | |
| 342 | const shift = @intCast(i32, @clz(u80, a_int)) - @intCast(i32, @clz(u80, @as(u80, int_bit) << 3)); | | |
| 343 | a_int <<= @intCast(u7, shift); | | |
| 344 | a_exp -= shift; | | |
| 345 | } | | |
| 346 | } else { // addition | | |
| 347 | a_int += b_int; | | |
| 348 | | | |
| 349 | // If the addition carried up, we need to right-shift the result and | | |
| 350 | // adjust the exponent: | | |
| 351 | if (a_int & (int_bit << 4) != 0) { | | |
| 352 | const sticky = a_int & 1; | | |
| 353 | a_int = a_int >> 1 | sticky; | | |
| 354 | a_exp += 1; | | |
| 355 | } | | |
| 356 | } | 239 | } |
| 357 | | 240 | |
| 358 | // If we have overflowed the type, return +/- infinity: | 241 | return @bitCast(T, result); |
| 359 | if (a_exp >= max_exp) { | | |
| 360 | a_rep.exp = max_exp | result_sign; | | |
| 361 | a_rep.fraction = int_bit; // integer bit is set for +/-inf | | |
| 362 | return std.math.make_f80(a_rep); | | |
| 363 | } | | |
| 364 | | | |
| 365 | if (a_exp <= 0) { | | |
| 366 | // Result is denormal before rounding; the exponent is zero and we | | |
| 367 | // need to shift the significand. | | |
| 368 | const shift = @intCast(u80, 1 - a_exp); | | |
| 369 | const sticky = if (a_int << @intCast(u7, 80 - shift) != 0) @as(u1, 1) else 0; | | |
| 370 | a_int = a_int >> @intCast(u7, shift | sticky); | | |
| 371 | a_exp = 0; | | |
| 372 | } | | |
| 373 | | | |
| 374 | // Low three bits are round, guard, and sticky. | | |
| 375 | const round_guard_sticky = @truncate(u3, a_int); | | |
| 376 | | | |
| 377 | // Shift the significand into place. | | |
| 378 | a_int = @truncate(u64, a_int >> 3); | | |
| 379 | | | |
| 380 | // // Insert the exponent and sign. | | |
| 381 | a_int |= (@intCast(u80, a_exp) | result_sign) << significand_bits; | | |
| 382 | | | |
| 383 | // Final rounding. The result may overflow to infinity, but that is the | | |
| 384 | // correct result in that case. | | |
| 385 | if (round_guard_sticky > 0x4) a_int += 1; | | |
| 386 | if (round_guard_sticky == 0x4) a_int += a_int & 1; | | |
| 387 | | | |
| 388 | a_rep.fraction = @truncate(u64, a_int); | | |
| 389 | a_rep.exp = @truncate(u16, a_int >> significand_bits); | | |
| 390 | return std.math.make_f80(a_rep); | | |
| 391 | } | | |
| 392 | | | |
| 393 | pub fn __subxf3(a: f80, b: f80) callconv(.C) f80 { | | |
| 394 | var b_rep = std.math.break_f80(b); | | |
| 395 | b_rep.exp ^= 0x8000; | | |
| 396 | return __addxf3(a, std.math.make_f80(b_rep)); | | |
| 397 | } | 242 | } |
| 398 | | 243 | |
| 399 | test { | 244 | test { |