1353358Sdim//===-- addsf3.S - Adds two single precision floating pointer numbers-----===//
2353358Sdim//
3353358Sdim// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4353358Sdim// See https://llvm.org/LICENSE.txt for license information.
5353358Sdim// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6353358Sdim//
7353358Sdim//===----------------------------------------------------------------------===//
8353358Sdim//
9353358Sdim// This file implements the __addsf3 (single precision floating pointer number
10353358Sdim// addition with the IEEE-754 default rounding (to nearest, ties to even)
11353358Sdim// function for the ARM Thumb1 ISA.
12353358Sdim//
13353358Sdim//===----------------------------------------------------------------------===//
14317021Sdim
15317021Sdim#include "../assembly.h"
16317021Sdim#define significandBits 23
17317021Sdim#define typeWidth 32
18317021Sdim
19317021Sdim	.syntax unified
20317021Sdim	.text
21317021Sdim  .thumb
22317021Sdim  .p2align 2
23317021Sdim
24317021SdimDEFINE_AEABI_FUNCTION_ALIAS(__aeabi_fadd, __addsf3)
25317021Sdim
26317021SdimDEFINE_COMPILERRT_THUMB_FUNCTION(__addsf3)
27317021Sdim  push {r4, r5, r6, r7, lr}
28317021Sdim  // Get the absolute value of a and b.
29317021Sdim  lsls r2, r0, #1
30317021Sdim  lsls r3, r1, #1
31353358Sdim  lsrs r2, r2, #1  // aAbs
32317021Sdim  beq  LOCAL_LABEL(a_zero_nan_inf)
33353358Sdim  lsrs r3, r3, #1  // bAbs
34317021Sdim  beq  LOCAL_LABEL(zero_nan_inf)
35317021Sdim
36317021Sdim  // Detect if a or b is infinity or Nan.
37317021Sdim  lsrs r6, r2, #(significandBits)
38317021Sdim  lsrs r7, r3, #(significandBits)
39317021Sdim  cmp  r6, #0xFF
40317021Sdim  beq  LOCAL_LABEL(zero_nan_inf)
41317021Sdim  cmp  r7, #0xFF
42317021Sdim  beq  LOCAL_LABEL(zero_nan_inf)
43317021Sdim
44317021Sdim  // Swap Rep and Abs so that a and aAbs has the larger absolute value.
45317021Sdim  cmp r2, r3
46317021Sdim  bhs LOCAL_LABEL(no_swap)
47317021Sdim  movs r4, r0
48317021Sdim  movs r5, r2
49317021Sdim  movs r0, r1
50317021Sdim  movs r2, r3
51317021Sdim  movs r1, r4
52317021Sdim  movs r3, r5
53317021SdimLOCAL_LABEL(no_swap):
54317021Sdim
55317021Sdim  // Get the significands and shift them to give us round, guard and sticky.
56317021Sdim  lsls r4, r0, #(typeWidth - significandBits)
57353358Sdim  lsrs r4, r4, #(typeWidth - significandBits - 3) // aSignificand << 3
58317021Sdim  lsls r5, r1, #(typeWidth - significandBits)
59353358Sdim  lsrs r5, r5, #(typeWidth - significandBits - 3) // bSignificand << 3
60317021Sdim
61317021Sdim  // Get the implicitBit.
62317021Sdim  movs r6, #1
63317021Sdim  lsls r6, r6, #(significandBits + 3)
64317021Sdim
65317021Sdim  // Get aExponent and set implicit bit if necessary.
66317021Sdim  lsrs r2, r2, #(significandBits)
67317021Sdim  beq LOCAL_LABEL(a_done_implicit_bit)
68317021Sdim  orrs r4, r6
69317021SdimLOCAL_LABEL(a_done_implicit_bit):
70317021Sdim
71317021Sdim  // Get bExponent and set implicit bit if necessary.
72317021Sdim  lsrs r3, r3, #(significandBits)
73317021Sdim  beq LOCAL_LABEL(b_done_implicit_bit)
74317021Sdim  orrs r5, r6
75317021SdimLOCAL_LABEL(b_done_implicit_bit):
76317021Sdim
77317021Sdim  // Get the difference in exponents.
78317021Sdim  subs r6, r2, r3
79317021Sdim  beq LOCAL_LABEL(done_align)
80317021Sdim
81317021Sdim  // If b is denormal, then a must be normal as align > 0, and we only need to
82317021Sdim  // right shift bSignificand by (align - 1) bits.
83317021Sdim  cmp  r3, #0
84317021Sdim  bne  1f
85317021Sdim  subs r6, r6, #1
86317021Sdim1:
87317021Sdim
88317021Sdim  // No longer needs bExponent. r3 is dead here.
89317021Sdim  // Set sticky bits of b: sticky = bSignificand << (typeWidth - align).
90317021Sdim  movs r3, #(typeWidth)
91317021Sdim  subs r3, r3, r6
92317021Sdim  movs r7, r5
93317021Sdim  lsls r7, r3
94317021Sdim  beq 1f
95317021Sdim  movs r7, #1
96317021Sdim1:
97317021Sdim
98317021Sdim  // bSignificand = bSignificand >> align | sticky;
99317021Sdim  lsrs r5, r6
100317021Sdim  orrs r5, r7
101317021Sdim  bne LOCAL_LABEL(done_align)
102317021Sdim  movs r5, #1 //  sticky; b is known to be non-zero.
103317021Sdim
104317021SdimLOCAL_LABEL(done_align):
105317021Sdim  // isSubtraction = (aRep ^ bRep) >> 31;
106317021Sdim  movs r7, r0
107317021Sdim  eors r7, r1
108317021Sdim  lsrs r7, #31
109317021Sdim  bne LOCAL_LABEL(do_substraction)
110317021Sdim
111317021Sdim  // Same sign, do Addition.
112317021Sdim
113317021Sdim  // aSignificand += bSignificand;
114317021Sdim  adds r4, r4, r5
115317021Sdim
116317021Sdim  // Check carry bit.
117317021Sdim  movs r6, #1
118317021Sdim  lsls r6, r6, #(significandBits + 3 + 1)
119317021Sdim  movs r7, r4
120317021Sdim  ands r7, r6
121317021Sdim  beq LOCAL_LABEL(form_result)
122317021Sdim  // If the addition carried up, we need to right-shift the result and
123317021Sdim  // adjust the exponent.
124317021Sdim  movs r7, r4
125317021Sdim  movs r6, #1
126317021Sdim  ands r7, r6 // sticky = aSignificand & 1;
127317021Sdim  lsrs r4, #1
128317021Sdim  orrs r4, r7  // result Significand
129317021Sdim  adds r2, #1  // result Exponent
130317021Sdim  // If we have overflowed the type, return +/- infinity.
131317021Sdim  cmp  r2, 0xFF
132317021Sdim  beq  LOCAL_LABEL(ret_inf)
133317021Sdim
134317021SdimLOCAL_LABEL(form_result):
135317021Sdim  // Shift the sign, exponent and significand into place.
136317021Sdim  lsrs r0, #(typeWidth - 1)
137317021Sdim  lsls r0, #(typeWidth - 1) // Get Sign.
138317021Sdim  lsls r2, #(significandBits)
139317021Sdim  orrs r0, r2
140317021Sdim  movs r1, r4
141317021Sdim  lsls r4, #(typeWidth - significandBits - 3)
142317021Sdim  lsrs r4, #(typeWidth - significandBits)
143317021Sdim  orrs r0, r4
144317021Sdim
145317021Sdim  // Final rounding.  The result may overflow to infinity, but that is the
146317021Sdim  // correct result in that case.
147317021Sdim  // roundGuardSticky = aSignificand & 0x7;
148317021Sdim  movs r2, #0x7
149317021Sdim  ands r1, r2
150317021Sdim  // if (roundGuardSticky > 0x4) result++;
151317021Sdim
152317021Sdim  cmp r1, #0x4
153317021Sdim  blt LOCAL_LABEL(done_round)
154317021Sdim  beq 1f
155317021Sdim  adds r0, #1
156317021Sdim  pop {r4, r5, r6, r7, pc}
157317021Sdim1:
158317021Sdim
159317021Sdim  // if (roundGuardSticky == 0x4) result += result & 1;
160317021Sdim  movs r1, r0
161317021Sdim  lsrs r1, #1
162317021Sdim  bcc  LOCAL_LABEL(done_round)
163317021Sdim  adds r0, r0, #1
164317021SdimLOCAL_LABEL(done_round):
165317021Sdim  pop {r4, r5, r6, r7, pc}
166317021Sdim
167317021SdimLOCAL_LABEL(do_substraction):
168317021Sdim  subs r4, r4, r5 // aSignificand -= bSignificand;
169317021Sdim  beq  LOCAL_LABEL(ret_zero)
170317021Sdim  movs r6, r4
171317021Sdim  cmp  r2, 0
172317021Sdim  beq  LOCAL_LABEL(form_result) // if a's exp is 0, no need to normalize.
173317021Sdim  // If partial cancellation occured, we need to left-shift the result
174317021Sdim  // and adjust the exponent:
175317021Sdim  lsrs r6, r6, #(significandBits + 3)
176317021Sdim  bne LOCAL_LABEL(form_result)
177317021Sdim
178317021Sdim  push {r0, r1, r2, r3}
179317021Sdim  movs r0, r4
180344779Sdim  bl   SYMBOL_NAME(__clzsi2)
181317021Sdim  movs r5, r0
182317021Sdim  pop {r0, r1, r2, r3}
183317021Sdim  // shift = rep_clz(aSignificand) - rep_clz(implicitBit << 3);
184317021Sdim  subs r5, r5, #(typeWidth - significandBits - 3 - 1)
185317021Sdim  // aSignificand <<= shift; aExponent -= shift;
186317021Sdim  lsls r4, r5
187317021Sdim  subs  r2, r2, r5
188317021Sdim  bgt LOCAL_LABEL(form_result)
189317021Sdim
190317021Sdim  // Do normalization if aExponent <= 0.
191317021Sdim  movs r6, #1
192317021Sdim  subs r6, r6, r2 // 1 - aExponent;
193317021Sdim  movs r2, #0 // aExponent = 0;
194317021Sdim  movs r3, #(typeWidth) // bExponent is dead.
195317021Sdim  subs r3, r3, r6
196317021Sdim  movs r7, r4
197317021Sdim  lsls r7, r3  // stickyBit = (bool)(aSignificant << (typeWidth - align))
198317021Sdim  beq 1f
199317021Sdim  movs r7, #1
200317021Sdim1:
201353358Sdim  lsrs r4, r6 // aSignificand >> shift
202317021Sdim  orrs r4, r7
203317021Sdim  b LOCAL_LABEL(form_result)
204317021Sdim
205317021SdimLOCAL_LABEL(ret_zero):
206317021Sdim  movs r0, #0
207317021Sdim  pop {r4, r5, r6, r7, pc}
208317021Sdim
209317021Sdim
210317021SdimLOCAL_LABEL(a_zero_nan_inf):
211317021Sdim  lsrs r3, r3, #1
212317021Sdim
213317021SdimLOCAL_LABEL(zero_nan_inf):
214317021Sdim  // Here  r2 has aAbs, r3 has bAbs
215317021Sdim  movs r4, #0xFF
216317021Sdim  lsls r4, r4, #(significandBits) // Make +inf.
217317021Sdim
218317021Sdim  cmp r2, r4
219317021Sdim  bhi LOCAL_LABEL(a_is_nan)
220317021Sdim  cmp r3, r4
221317021Sdim  bhi LOCAL_LABEL(b_is_nan)
222317021Sdim
223317021Sdim  cmp r2, r4
224317021Sdim  bne LOCAL_LABEL(a_is_rational)
225317021Sdim  // aAbs is INF.
226317021Sdim  eors r1, r0 // aRep ^ bRep.
227317021Sdim  movs r6, #1
228317021Sdim  lsls r6, r6, #(typeWidth - 1) // get sign mask.
229317021Sdim  cmp r1, r6 // if they only differ on sign bit, it's -INF + INF
230317021Sdim  beq LOCAL_LABEL(a_is_nan)
231317021Sdim  pop {r4, r5, r6, r7, pc}
232317021Sdim
233317021SdimLOCAL_LABEL(a_is_rational):
234317021Sdim  cmp r3, r4
235317021Sdim  bne LOCAL_LABEL(b_is_rational)
236317021Sdim  movs r0, r1
237317021Sdim  pop {r4, r5, r6, r7, pc}
238317021Sdim
239317021SdimLOCAL_LABEL(b_is_rational):
240317021Sdim  // either a or b or both are zero.
241317021Sdim  adds r4, r2, r3
242317021Sdim  beq  LOCAL_LABEL(both_zero)
243317021Sdim  cmp r2, #0 // is absA 0 ?
244317021Sdim  beq LOCAL_LABEL(ret_b)
245317021Sdim  pop {r4, r5, r6, r7, pc}
246317021Sdim
247317021SdimLOCAL_LABEL(both_zero):
248317021Sdim  ands r0, r1 // +0 + -0 = +0
249317021Sdim  pop {r4, r5, r6, r7, pc}
250317021Sdim
251317021SdimLOCAL_LABEL(ret_b):
252317021Sdim  movs r0, r1
253317021Sdim
254317021SdimLOCAL_LABEL(ret):
255317021Sdim  pop {r4, r5, r6, r7, pc}
256317021Sdim
257317021SdimLOCAL_LABEL(b_is_nan):
258317021Sdim  movs r0, r1
259317021SdimLOCAL_LABEL(a_is_nan):
260317021Sdim  movs r1, #1
261317021Sdim  lsls r1, r1, #(significandBits -1) // r1 is quiet bit.
262317021Sdim  orrs r0, r1
263317021Sdim  pop {r4, r5, r6, r7, pc}
264317021Sdim
265317021SdimLOCAL_LABEL(ret_inf):
266317021Sdim  movs r4, #0xFF
267317021Sdim  lsls r4, r4, #(significandBits)
268317021Sdim  orrs r0, r4
269317021Sdim  lsrs r0, r0, #(significandBits)
270317021Sdim  lsls r0, r0, #(significandBits)
271317021Sdim  pop {r4, r5, r6, r7, pc}
272317021Sdim
273317021Sdim
274317021SdimEND_COMPILERRT_FUNCTION(__addsf3)
275317021Sdim
276317021SdimNO_EXEC_STACK_DIRECTIVE
277