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