xref: /openbsd-src/gnu/llvm/compiler-rt/lib/builtins/arm/addsf3.S (revision 3cab2bb3f667058bece8e38b12449a63a9d73c4b)
1*3cab2bb3Spatrick//===-- addsf3.S - Adds two single precision floating pointer numbers-----===//
2*3cab2bb3Spatrick//
3*3cab2bb3Spatrick// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*3cab2bb3Spatrick// See https://llvm.org/LICENSE.txt for license information.
5*3cab2bb3Spatrick// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6*3cab2bb3Spatrick//
7*3cab2bb3Spatrick//===----------------------------------------------------------------------===//
8*3cab2bb3Spatrick//
9*3cab2bb3Spatrick// This file implements the __addsf3 (single precision floating pointer number
10*3cab2bb3Spatrick// addition with the IEEE-754 default rounding (to nearest, ties to even)
11*3cab2bb3Spatrick// function for the ARM Thumb1 ISA.
12*3cab2bb3Spatrick//
13*3cab2bb3Spatrick//===----------------------------------------------------------------------===//
14*3cab2bb3Spatrick
15*3cab2bb3Spatrick#include "../assembly.h"
16*3cab2bb3Spatrick#define significandBits 23
17*3cab2bb3Spatrick#define typeWidth 32
18*3cab2bb3Spatrick
19*3cab2bb3Spatrick	.syntax unified
20*3cab2bb3Spatrick	.text
21*3cab2bb3Spatrick  .thumb
22*3cab2bb3Spatrick  .p2align 2
23*3cab2bb3Spatrick
24*3cab2bb3SpatrickDEFINE_AEABI_FUNCTION_ALIAS(__aeabi_fadd, __addsf3)
25*3cab2bb3Spatrick
26*3cab2bb3SpatrickDEFINE_COMPILERRT_THUMB_FUNCTION(__addsf3)
27*3cab2bb3Spatrick  push {r4, r5, r6, r7, lr}
28*3cab2bb3Spatrick  // Get the absolute value of a and b.
29*3cab2bb3Spatrick  lsls r2, r0, #1
30*3cab2bb3Spatrick  lsls r3, r1, #1
31*3cab2bb3Spatrick  lsrs r2, r2, #1  // aAbs
32*3cab2bb3Spatrick  beq  LOCAL_LABEL(a_zero_nan_inf)
33*3cab2bb3Spatrick  lsrs r3, r3, #1  // bAbs
34*3cab2bb3Spatrick  beq  LOCAL_LABEL(zero_nan_inf)
35*3cab2bb3Spatrick
36*3cab2bb3Spatrick  // Detect if a or b is infinity or Nan.
37*3cab2bb3Spatrick  lsrs r6, r2, #(significandBits)
38*3cab2bb3Spatrick  lsrs r7, r3, #(significandBits)
39*3cab2bb3Spatrick  cmp  r6, #0xFF
40*3cab2bb3Spatrick  beq  LOCAL_LABEL(zero_nan_inf)
41*3cab2bb3Spatrick  cmp  r7, #0xFF
42*3cab2bb3Spatrick  beq  LOCAL_LABEL(zero_nan_inf)
43*3cab2bb3Spatrick
44*3cab2bb3Spatrick  // Swap Rep and Abs so that a and aAbs has the larger absolute value.
45*3cab2bb3Spatrick  cmp r2, r3
46*3cab2bb3Spatrick  bhs LOCAL_LABEL(no_swap)
47*3cab2bb3Spatrick  movs r4, r0
48*3cab2bb3Spatrick  movs r5, r2
49*3cab2bb3Spatrick  movs r0, r1
50*3cab2bb3Spatrick  movs r2, r3
51*3cab2bb3Spatrick  movs r1, r4
52*3cab2bb3Spatrick  movs r3, r5
53*3cab2bb3SpatrickLOCAL_LABEL(no_swap):
54*3cab2bb3Spatrick
55*3cab2bb3Spatrick  // Get the significands and shift them to give us round, guard and sticky.
56*3cab2bb3Spatrick  lsls r4, r0, #(typeWidth - significandBits)
57*3cab2bb3Spatrick  lsrs r4, r4, #(typeWidth - significandBits - 3) // aSignificand << 3
58*3cab2bb3Spatrick  lsls r5, r1, #(typeWidth - significandBits)
59*3cab2bb3Spatrick  lsrs r5, r5, #(typeWidth - significandBits - 3) // bSignificand << 3
60*3cab2bb3Spatrick
61*3cab2bb3Spatrick  // Get the implicitBit.
62*3cab2bb3Spatrick  movs r6, #1
63*3cab2bb3Spatrick  lsls r6, r6, #(significandBits + 3)
64*3cab2bb3Spatrick
65*3cab2bb3Spatrick  // Get aExponent and set implicit bit if necessary.
66*3cab2bb3Spatrick  lsrs r2, r2, #(significandBits)
67*3cab2bb3Spatrick  beq LOCAL_LABEL(a_done_implicit_bit)
68*3cab2bb3Spatrick  orrs r4, r6
69*3cab2bb3SpatrickLOCAL_LABEL(a_done_implicit_bit):
70*3cab2bb3Spatrick
71*3cab2bb3Spatrick  // Get bExponent and set implicit bit if necessary.
72*3cab2bb3Spatrick  lsrs r3, r3, #(significandBits)
73*3cab2bb3Spatrick  beq LOCAL_LABEL(b_done_implicit_bit)
74*3cab2bb3Spatrick  orrs r5, r6
75*3cab2bb3SpatrickLOCAL_LABEL(b_done_implicit_bit):
76*3cab2bb3Spatrick
77*3cab2bb3Spatrick  // Get the difference in exponents.
78*3cab2bb3Spatrick  subs r6, r2, r3
79*3cab2bb3Spatrick  beq LOCAL_LABEL(done_align)
80*3cab2bb3Spatrick
81*3cab2bb3Spatrick  // If b is denormal, then a must be normal as align > 0, and we only need to
82*3cab2bb3Spatrick  // right shift bSignificand by (align - 1) bits.
83*3cab2bb3Spatrick  cmp  r3, #0
84*3cab2bb3Spatrick  bne  1f
85*3cab2bb3Spatrick  subs r6, r6, #1
86*3cab2bb3Spatrick1:
87*3cab2bb3Spatrick
88*3cab2bb3Spatrick  // No longer needs bExponent. r3 is dead here.
89*3cab2bb3Spatrick  // Set sticky bits of b: sticky = bSignificand << (typeWidth - align).
90*3cab2bb3Spatrick  movs r3, #(typeWidth)
91*3cab2bb3Spatrick  subs r3, r3, r6
92*3cab2bb3Spatrick  movs r7, r5
93*3cab2bb3Spatrick  lsls r7, r3
94*3cab2bb3Spatrick  beq 1f
95*3cab2bb3Spatrick  movs r7, #1
96*3cab2bb3Spatrick1:
97*3cab2bb3Spatrick
98*3cab2bb3Spatrick  // bSignificand = bSignificand >> align | sticky;
99*3cab2bb3Spatrick  lsrs r5, r6
100*3cab2bb3Spatrick  orrs r5, r7
101*3cab2bb3Spatrick  bne LOCAL_LABEL(done_align)
102*3cab2bb3Spatrick  movs r5, #1 //  sticky; b is known to be non-zero.
103*3cab2bb3Spatrick
104*3cab2bb3SpatrickLOCAL_LABEL(done_align):
105*3cab2bb3Spatrick  // isSubtraction = (aRep ^ bRep) >> 31;
106*3cab2bb3Spatrick  movs r7, r0
107*3cab2bb3Spatrick  eors r7, r1
108*3cab2bb3Spatrick  lsrs r7, #31
109*3cab2bb3Spatrick  bne LOCAL_LABEL(do_substraction)
110*3cab2bb3Spatrick
111*3cab2bb3Spatrick  // Same sign, do Addition.
112*3cab2bb3Spatrick
113*3cab2bb3Spatrick  // aSignificand += bSignificand;
114*3cab2bb3Spatrick  adds r4, r4, r5
115*3cab2bb3Spatrick
116*3cab2bb3Spatrick  // Check carry bit.
117*3cab2bb3Spatrick  movs r6, #1
118*3cab2bb3Spatrick  lsls r6, r6, #(significandBits + 3 + 1)
119*3cab2bb3Spatrick  movs r7, r4
120*3cab2bb3Spatrick  ands r7, r6
121*3cab2bb3Spatrick  beq LOCAL_LABEL(form_result)
122*3cab2bb3Spatrick  // If the addition carried up, we need to right-shift the result and
123*3cab2bb3Spatrick  // adjust the exponent.
124*3cab2bb3Spatrick  movs r7, r4
125*3cab2bb3Spatrick  movs r6, #1
126*3cab2bb3Spatrick  ands r7, r6 // sticky = aSignificand & 1;
127*3cab2bb3Spatrick  lsrs r4, #1
128*3cab2bb3Spatrick  orrs r4, r7  // result Significand
129*3cab2bb3Spatrick  adds r2, #1  // result Exponent
130*3cab2bb3Spatrick  // If we have overflowed the type, return +/- infinity.
131*3cab2bb3Spatrick  cmp  r2, 0xFF
132*3cab2bb3Spatrick  beq  LOCAL_LABEL(ret_inf)
133*3cab2bb3Spatrick
134*3cab2bb3SpatrickLOCAL_LABEL(form_result):
135*3cab2bb3Spatrick  // Shift the sign, exponent and significand into place.
136*3cab2bb3Spatrick  lsrs r0, #(typeWidth - 1)
137*3cab2bb3Spatrick  lsls r0, #(typeWidth - 1) // Get Sign.
138*3cab2bb3Spatrick  lsls r2, #(significandBits)
139*3cab2bb3Spatrick  orrs r0, r2
140*3cab2bb3Spatrick  movs r1, r4
141*3cab2bb3Spatrick  lsls r4, #(typeWidth - significandBits - 3)
142*3cab2bb3Spatrick  lsrs r4, #(typeWidth - significandBits)
143*3cab2bb3Spatrick  orrs r0, r4
144*3cab2bb3Spatrick
145*3cab2bb3Spatrick  // Final rounding.  The result may overflow to infinity, but that is the
146*3cab2bb3Spatrick  // correct result in that case.
147*3cab2bb3Spatrick  // roundGuardSticky = aSignificand & 0x7;
148*3cab2bb3Spatrick  movs r2, #0x7
149*3cab2bb3Spatrick  ands r1, r2
150*3cab2bb3Spatrick  // if (roundGuardSticky > 0x4) result++;
151*3cab2bb3Spatrick
152*3cab2bb3Spatrick  cmp r1, #0x4
153*3cab2bb3Spatrick  blt LOCAL_LABEL(done_round)
154*3cab2bb3Spatrick  beq 1f
155*3cab2bb3Spatrick  adds r0, #1
156*3cab2bb3Spatrick  pop {r4, r5, r6, r7, pc}
157*3cab2bb3Spatrick1:
158*3cab2bb3Spatrick
159*3cab2bb3Spatrick  // if (roundGuardSticky == 0x4) result += result & 1;
160*3cab2bb3Spatrick  movs r1, r0
161*3cab2bb3Spatrick  lsrs r1, #1
162*3cab2bb3Spatrick  bcc  LOCAL_LABEL(done_round)
163*3cab2bb3Spatrick  adds r0, r0, #1
164*3cab2bb3SpatrickLOCAL_LABEL(done_round):
165*3cab2bb3Spatrick  pop {r4, r5, r6, r7, pc}
166*3cab2bb3Spatrick
167*3cab2bb3SpatrickLOCAL_LABEL(do_substraction):
168*3cab2bb3Spatrick  subs r4, r4, r5 // aSignificand -= bSignificand;
169*3cab2bb3Spatrick  beq  LOCAL_LABEL(ret_zero)
170*3cab2bb3Spatrick  movs r6, r4
171*3cab2bb3Spatrick  cmp  r2, 0
172*3cab2bb3Spatrick  beq  LOCAL_LABEL(form_result) // if a's exp is 0, no need to normalize.
173*3cab2bb3Spatrick  // If partial cancellation occured, we need to left-shift the result
174*3cab2bb3Spatrick  // and adjust the exponent:
175*3cab2bb3Spatrick  lsrs r6, r6, #(significandBits + 3)
176*3cab2bb3Spatrick  bne LOCAL_LABEL(form_result)
177*3cab2bb3Spatrick
178*3cab2bb3Spatrick  push {r0, r1, r2, r3}
179*3cab2bb3Spatrick  movs r0, r4
180*3cab2bb3Spatrick  bl   SYMBOL_NAME(__clzsi2)
181*3cab2bb3Spatrick  movs r5, r0
182*3cab2bb3Spatrick  pop {r0, r1, r2, r3}
183*3cab2bb3Spatrick  // shift = rep_clz(aSignificand) - rep_clz(implicitBit << 3);
184*3cab2bb3Spatrick  subs r5, r5, #(typeWidth - significandBits - 3 - 1)
185*3cab2bb3Spatrick  // aSignificand <<= shift; aExponent -= shift;
186*3cab2bb3Spatrick  lsls r4, r5
187*3cab2bb3Spatrick  subs  r2, r2, r5
188*3cab2bb3Spatrick  bgt LOCAL_LABEL(form_result)
189*3cab2bb3Spatrick
190*3cab2bb3Spatrick  // Do normalization if aExponent <= 0.
191*3cab2bb3Spatrick  movs r6, #1
192*3cab2bb3Spatrick  subs r6, r6, r2 // 1 - aExponent;
193*3cab2bb3Spatrick  movs r2, #0 // aExponent = 0;
194*3cab2bb3Spatrick  movs r3, #(typeWidth) // bExponent is dead.
195*3cab2bb3Spatrick  subs r3, r3, r6
196*3cab2bb3Spatrick  movs r7, r4
197*3cab2bb3Spatrick  lsls r7, r3  // stickyBit = (bool)(aSignificant << (typeWidth - align))
198*3cab2bb3Spatrick  beq 1f
199*3cab2bb3Spatrick  movs r7, #1
200*3cab2bb3Spatrick1:
201*3cab2bb3Spatrick  lsrs r4, r6 // aSignificand >> shift
202*3cab2bb3Spatrick  orrs r4, r7
203*3cab2bb3Spatrick  b LOCAL_LABEL(form_result)
204*3cab2bb3Spatrick
205*3cab2bb3SpatrickLOCAL_LABEL(ret_zero):
206*3cab2bb3Spatrick  movs r0, #0
207*3cab2bb3Spatrick  pop {r4, r5, r6, r7, pc}
208*3cab2bb3Spatrick
209*3cab2bb3Spatrick
210*3cab2bb3SpatrickLOCAL_LABEL(a_zero_nan_inf):
211*3cab2bb3Spatrick  lsrs r3, r3, #1
212*3cab2bb3Spatrick
213*3cab2bb3SpatrickLOCAL_LABEL(zero_nan_inf):
214*3cab2bb3Spatrick  // Here  r2 has aAbs, r3 has bAbs
215*3cab2bb3Spatrick  movs r4, #0xFF
216*3cab2bb3Spatrick  lsls r4, r4, #(significandBits) // Make +inf.
217*3cab2bb3Spatrick
218*3cab2bb3Spatrick  cmp r2, r4
219*3cab2bb3Spatrick  bhi LOCAL_LABEL(a_is_nan)
220*3cab2bb3Spatrick  cmp r3, r4
221*3cab2bb3Spatrick  bhi LOCAL_LABEL(b_is_nan)
222*3cab2bb3Spatrick
223*3cab2bb3Spatrick  cmp r2, r4
224*3cab2bb3Spatrick  bne LOCAL_LABEL(a_is_rational)
225*3cab2bb3Spatrick  // aAbs is INF.
226*3cab2bb3Spatrick  eors r1, r0 // aRep ^ bRep.
227*3cab2bb3Spatrick  movs r6, #1
228*3cab2bb3Spatrick  lsls r6, r6, #(typeWidth - 1) // get sign mask.
229*3cab2bb3Spatrick  cmp r1, r6 // if they only differ on sign bit, it's -INF + INF
230*3cab2bb3Spatrick  beq LOCAL_LABEL(a_is_nan)
231*3cab2bb3Spatrick  pop {r4, r5, r6, r7, pc}
232*3cab2bb3Spatrick
233*3cab2bb3SpatrickLOCAL_LABEL(a_is_rational):
234*3cab2bb3Spatrick  cmp r3, r4
235*3cab2bb3Spatrick  bne LOCAL_LABEL(b_is_rational)
236*3cab2bb3Spatrick  movs r0, r1
237*3cab2bb3Spatrick  pop {r4, r5, r6, r7, pc}
238*3cab2bb3Spatrick
239*3cab2bb3SpatrickLOCAL_LABEL(b_is_rational):
240*3cab2bb3Spatrick  // either a or b or both are zero.
241*3cab2bb3Spatrick  adds r4, r2, r3
242*3cab2bb3Spatrick  beq  LOCAL_LABEL(both_zero)
243*3cab2bb3Spatrick  cmp r2, #0 // is absA 0 ?
244*3cab2bb3Spatrick  beq LOCAL_LABEL(ret_b)
245*3cab2bb3Spatrick  pop {r4, r5, r6, r7, pc}
246*3cab2bb3Spatrick
247*3cab2bb3SpatrickLOCAL_LABEL(both_zero):
248*3cab2bb3Spatrick  ands r0, r1 // +0 + -0 = +0
249*3cab2bb3Spatrick  pop {r4, r5, r6, r7, pc}
250*3cab2bb3Spatrick
251*3cab2bb3SpatrickLOCAL_LABEL(ret_b):
252*3cab2bb3Spatrick  movs r0, r1
253*3cab2bb3Spatrick
254*3cab2bb3SpatrickLOCAL_LABEL(ret):
255*3cab2bb3Spatrick  pop {r4, r5, r6, r7, pc}
256*3cab2bb3Spatrick
257*3cab2bb3SpatrickLOCAL_LABEL(b_is_nan):
258*3cab2bb3Spatrick  movs r0, r1
259*3cab2bb3SpatrickLOCAL_LABEL(a_is_nan):
260*3cab2bb3Spatrick  movs r1, #1
261*3cab2bb3Spatrick  lsls r1, r1, #(significandBits -1) // r1 is quiet bit.
262*3cab2bb3Spatrick  orrs r0, r1
263*3cab2bb3Spatrick  pop {r4, r5, r6, r7, pc}
264*3cab2bb3Spatrick
265*3cab2bb3SpatrickLOCAL_LABEL(ret_inf):
266*3cab2bb3Spatrick  movs r4, #0xFF
267*3cab2bb3Spatrick  lsls r4, r4, #(significandBits)
268*3cab2bb3Spatrick  orrs r0, r4
269*3cab2bb3Spatrick  lsrs r0, r0, #(significandBits)
270*3cab2bb3Spatrick  lsls r0, r0, #(significandBits)
271*3cab2bb3Spatrick  pop {r4, r5, r6, r7, pc}
272*3cab2bb3Spatrick
273*3cab2bb3Spatrick
274*3cab2bb3SpatrickEND_COMPILERRT_FUNCTION(__addsf3)
275*3cab2bb3Spatrick
276*3cab2bb3SpatrickNO_EXEC_STACK_DIRECTIVE
277