1// Ported from: 2// 3// https://github.com/llvm/llvm-project/blob/02d85149a05cb1f6dc49f0ba7a2ceca53718ae17/compiler-rt/lib/builtins/fp_add_impl.inc 4 5const std = @import("std"); 6const builtin = @import("builtin"); 7const compiler_rt = @import("../compiler_rt.zig"); 8 9pub fn __addsf3(a: f32, b: f32) callconv(.C) f32 { 10 return addXf3(f32, a, b); 11} 12 13pub fn __adddf3(a: f64, b: f64) callconv(.C) f64 { 14 return addXf3(f64, a, b); 15} 16 17pub fn __addtf3(a: f128, b: f128) callconv(.C) f128 { 18 return addXf3(f128, a, b); 19} 20 21pub fn __subsf3(a: f32, b: f32) callconv(.C) f32 { 22 const neg_b = @bitCast(f32, @bitCast(u32, b) ^ (@as(u32, 1) << 31)); 23 return addXf3(f32, a, neg_b); 24} 25 26pub fn __subdf3(a: f64, b: f64) callconv(.C) f64 { 27 const neg_b = @bitCast(f64, @bitCast(u64, b) ^ (@as(u64, 1) << 63)); 28 return addXf3(f64, a, neg_b); 29} 30 31pub fn __subtf3(a: f128, b: f128) callconv(.C) f128 { 32 const neg_b = @bitCast(f128, @bitCast(u128, b) ^ (@as(u128, 1) << 127)); 33 return addXf3(f128, a, neg_b); 34} 35 36pub fn __aeabi_fadd(a: f32, b: f32) callconv(.AAPCS) f32 { 37 @setRuntimeSafety(false); 38 return @call(.{ .modifier = .always_inline }, __addsf3, .{ a, b }); 39} 40 41pub fn __aeabi_dadd(a: f64, b: f64) callconv(.AAPCS) f64 { 42 @setRuntimeSafety(false); 43 return @call(.{ .modifier = .always_inline }, __adddf3, .{ a, b }); 44} 45 46pub fn __aeabi_fsub(a: f32, b: f32) callconv(.AAPCS) f32 { 47 @setRuntimeSafety(false); 48 return @call(.{ .modifier = .always_inline }, __subsf3, .{ a, b }); 49} 50 51pub fn __aeabi_dsub(a: f64, b: f64) callconv(.AAPCS) f64 { 52 @setRuntimeSafety(false); 53 return @call(.{ .modifier = .always_inline }, __subdf3, .{ a, b }); 54} 55 56// TODO: restore inline keyword, see: https://github.com/ziglang/zig/issues/2154 57fn normalize(comptime T: type, significand: *std.meta.Int(.unsigned, @typeInfo(T).Float.bits)) i32 { 58 const bits = @typeInfo(T).Float.bits; 59 const Z = std.meta.Int(.unsigned, bits); 60 const S = std.meta.Int(.unsigned, bits - @clz(Z, @as(Z, bits) - 1)); 61 const significandBits = std.math.floatMantissaBits(T); 62 const implicitBit = @as(Z, 1) << significandBits; 63 64 const shift = @clz(std.meta.Int(.unsigned, bits), significand.*) - @clz(Z, implicitBit); 65 significand.* <<= @intCast(S, shift); 66 return 1 - shift; 67} 68 69// TODO: restore inline keyword, see: https://github.com/ziglang/zig/issues/2154 70fn addXf3(comptime T: type, a: T, b: T) T { 71 const bits = @typeInfo(T).Float.bits; 72 const Z = std.meta.Int(.unsigned, bits); 73 const S = std.meta.Int(.unsigned, bits - @clz(Z, @as(Z, bits) - 1)); 74 75 const typeWidth = bits; 76 const significandBits = std.math.floatMantissaBits(T); 77 const exponentBits = std.math.floatExponentBits(T); 78 79 const signBit = (@as(Z, 1) << (significandBits + exponentBits)); 80 const maxExponent = ((1 << exponentBits) - 1); 81 82 const implicitBit = (@as(Z, 1) << significandBits); 83 const quietBit = implicitBit >> 1; 84 const significandMask = implicitBit - 1; 85 86 const absMask = signBit - 1; 87 const exponentMask = absMask ^ significandMask; 88 const qnanRep = exponentMask | quietBit; 89 90 var aRep = @bitCast(Z, a); 91 var bRep = @bitCast(Z, b); 92 const aAbs = aRep & absMask; 93 const bAbs = bRep & absMask; 94 95 const infRep = @bitCast(Z, std.math.inf(T)); 96 97 // Detect if a or b is zero, infinity, or NaN. 98 if (aAbs -% @as(Z, 1) >= infRep - @as(Z, 1) or 99 bAbs -% @as(Z, 1) >= infRep - @as(Z, 1)) 100 { 101 // NaN + anything = qNaN 102 if (aAbs > infRep) return @bitCast(T, @bitCast(Z, a) | quietBit); 103 // anything + NaN = qNaN 104 if (bAbs > infRep) return @bitCast(T, @bitCast(Z, b) | quietBit); 105 106 if (aAbs == infRep) { 107 // +/-infinity + -/+infinity = qNaN 108 if ((@bitCast(Z, a) ^ @bitCast(Z, b)) == signBit) { 109 return @bitCast(T, qnanRep); 110 } 111 // +/-infinity + anything remaining = +/- infinity 112 else { 113 return a; 114 } 115 } 116 117 // anything remaining + +/-infinity = +/-infinity 118 if (bAbs == infRep) return b; 119 120 // zero + anything = anything 121 if (aAbs == 0) { 122 // but we need to get the sign right for zero + zero 123 if (bAbs == 0) { 124 return @bitCast(T, @bitCast(Z, a) & @bitCast(Z, b)); 125 } else { 126 return b; 127 } 128 } 129 130 // anything + zero = anything 131 if (bAbs == 0) return a; 132 } 133 134 // Swap a and b if necessary so that a has the larger absolute value. 135 if (bAbs > aAbs) { 136 const temp = aRep; 137 aRep = bRep; 138 bRep = temp; 139 } 140 141 // Extract the exponent and significand from the (possibly swapped) a and b. 142 var aExponent = @intCast(i32, (aRep >> significandBits) & maxExponent); 143 var bExponent = @intCast(i32, (bRep >> significandBits) & maxExponent); 144 var aSignificand = aRep & significandMask; 145 var bSignificand = bRep & significandMask; 146 147 // Normalize any denormals, and adjust the exponent accordingly. 148 if (aExponent == 0) aExponent = normalize(T, &aSignificand); 149 if (bExponent == 0) bExponent = normalize(T, &bSignificand); 150 151 // The sign of the result is the sign of the larger operand, a. If they 152 // have opposite signs, we are performing a subtraction; otherwise addition. 153 const resultSign = aRep & signBit; 154 const subtraction = (aRep ^ bRep) & signBit != 0; 155 156 // Shift the significands to give us round, guard and sticky, and or in the 157 // 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 159 // anything.) 160 aSignificand = (aSignificand | implicitBit) << 3; 161 bSignificand = (bSignificand | implicitBit) << 3; 162 163 // Shift the significand of b by the difference in exponents, with a sticky 164 // bottom bit to get rounding correct. 165 const @"align" = @intCast(Z, aExponent - bExponent); 166 if (@"align" != 0) { 167 if (@"align" < typeWidth) { 168 const sticky = if (bSignificand << @intCast(S, typeWidth - @"align") != 0) @as(Z, 1) else 0; 169 bSignificand = (bSignificand >> @truncate(S, @"align")) | sticky; 170 } else { 171 bSignificand = 1; // sticky; b is known to be non-zero. 172 } 173 } 174 if (subtraction) { 175 aSignificand -= bSignificand; 176 // If a == -b, return +zero. 177 if (aSignificand == 0) return @bitCast(T, @as(Z, 0)); 178 179 // If partial cancellation occured, we need to left-shift the result 180 // and adjust the exponent: 181 if (aSignificand < implicitBit << 3) { 182 const shift = @intCast(i32, @clz(Z, aSignificand)) - @intCast(i32, @clz(std.meta.Int(.unsigned, bits), implicitBit << 3)); 183 aSignificand <<= @intCast(S, shift); 184 aExponent -= shift; 185 } 186 } else { // addition 187 aSignificand += bSignificand; 188 189 // If the addition carried up, we need to right-shift the result and 190 // adjust the exponent: 191 if (aSignificand & (implicitBit << 4) != 0) { 192 const sticky = aSignificand & 1; 193 aSignificand = aSignificand >> 1 | sticky; 194 aExponent += 1; 195 } 196 } 197 198 // If we have overflowed the type, return +/- infinity: 199 if (aExponent >= maxExponent) return @bitCast(T, infRep | resultSign); 200 201 if (aExponent <= 0) { 202 // Result is denormal before rounding; the exponent is zero and we 203 // need to shift the significand. 204 const shift = @intCast(Z, 1 - aExponent); 205 const sticky = if (aSignificand << @intCast(S, typeWidth - shift) != 0) @as(Z, 1) else 0; 206 aSignificand = aSignificand >> @intCast(S, shift | sticky); 207 aExponent = 0; 208 } 209 210 // Low three bits are round, guard, and sticky. 211 const roundGuardSticky = aSignificand & 0x7; 212 213 // Shift the significand into place, and mask off the implicit bit. 214 var result = (aSignificand >> 3) & significandMask; 215 216 // Insert the exponent and sign. 217 result |= @intCast(Z, aExponent) << significandBits; 218 result |= resultSign; 219 220 // Final rounding. The result may overflow to infinity, but that is the 221 // correct result in that case. 222 if (roundGuardSticky > 0x4) result += 1; 223 if (roundGuardSticky == 0x4) result += result & 1; 224 225 return @bitCast(T, result); 226} 227 228test { 229 _ = @import("addXf3_test.zig"); 230} 231