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