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

source code of compiler-rt/lib/builtins/arm/addsf3.S