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