277 lines · plain
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-exception6//7//===----------------------------------------------------------------------===//8//9// This file implements the __addsf3 (single precision floating pointer number10// 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 2317#define typeWidth 3218 19 .syntax unified20 .text21 .thumb22 .p2align 223 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, #130 lsls r3, r1, #131 lsrs r2, r2, #1 // aAbs32 beq LOCAL_LABEL(a_zero_nan_inf)33 lsrs r3, r3, #1 // bAbs34 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, #0xFF40 beq LOCAL_LABEL(zero_nan_inf)41 cmp r7, #0xFF42 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, r346 bhs LOCAL_LABEL(no_swap)47 movs r4, r048 movs r5, r249 movs r0, r150 movs r2, r351 movs r1, r452 movs r3, r553LOCAL_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 << 358 lsls r5, r1, #(typeWidth - significandBits)59 lsrs r5, r5, #(typeWidth - significandBits - 3) // bSignificand << 360 61 // Get the implicitBit.62 movs r6, #163 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, r669LOCAL_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, r675LOCAL_LABEL(b_done_implicit_bit):76 77 // Get the difference in exponents.78 subs r6, r2, r379 beq LOCAL_LABEL(done_align)80 81 // If b is denormal, then a must be normal as align > 0, and we only need to82 // right shift bSignificand by (align - 1) bits.83 cmp r3, #084 bne 1f85 subs r6, r6, #1861: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, r692 movs r7, r593 lsls r7, r394 beq 1f95 movs r7, #1961:97 98 // bSignificand = bSignificand >> align | sticky;99 lsrs r5, r6100 orrs r5, r7101 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, r0107 eors r7, r1108 lsrs r7, #31109 bne LOCAL_LABEL(do_substraction)110 111 // Same sign, do Addition.112 113 // aSignificand += bSignificand;114 adds r4, r4, r5115 116 // Check carry bit.117 movs r6, #1118 lsls r6, r6, #(significandBits + 3 + 1)119 movs r7, r4120 ands r7, r6121 beq LOCAL_LABEL(form_result)122 // If the addition carried up, we need to right-shift the result and123 // adjust the exponent.124 movs r7, r4125 movs r6, #1126 ands r7, r6 // sticky = aSignificand & 1;127 lsrs r4, #1128 orrs r4, r7 // result Significand129 adds r2, #1 // result Exponent130 // If we have overflowed the type, return +/- infinity.131 cmp r2, 0xFF132 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, r2140 movs r1, r4141 lsls r4, #(typeWidth - significandBits - 3)142 lsrs r4, #(typeWidth - significandBits)143 orrs r0, r4144 145 // Final rounding. The result may overflow to infinity, but that is the146 // correct result in that case.147 // roundGuardSticky = aSignificand & 0x7;148 movs r2, #0x7149 ands r1, r2150 // if (roundGuardSticky > 0x4) result++;151 152 cmp r1, #0x4153 blt LOCAL_LABEL(done_round)154 beq 1f155 adds r0, #1156 pop {r4, r5, r6, r7, pc}1571:158 159 // if (roundGuardSticky == 0x4) result += result & 1;160 movs r1, r0161 lsrs r1, #1162 bcc LOCAL_LABEL(done_round)163 adds r0, r0, #1164LOCAL_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, r4171 cmp r2, 0172 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 result174 // 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, r4180 bl SYMBOL_NAME(__clzsi2)181 movs r5, r0182 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, r5187 subs r2, r2, r5188 bgt LOCAL_LABEL(form_result)189 190 // Do normalization if aExponent <= 0.191 movs r6, #1192 subs r6, r6, r2 // 1 - aExponent;193 movs r2, #0 // aExponent = 0;194 movs r3, #(typeWidth) // bExponent is dead.195 subs r3, r3, r6196 movs r7, r4197 lsls r7, r3 // stickyBit = (bool)(aSignificant << (typeWidth - align))198 beq 1f199 movs r7, #12001:201 lsrs r4, r6 // aSignificand >> shift202 orrs r4, r7203 b LOCAL_LABEL(form_result)204 205LOCAL_LABEL(ret_zero):206 movs r0, #0207 pop {r4, r5, r6, r7, pc}208 209 210LOCAL_LABEL(a_zero_nan_inf):211 lsrs r3, r3, #1212 213LOCAL_LABEL(zero_nan_inf):214 // Here r2 has aAbs, r3 has bAbs215 movs r4, #0xFF216 lsls r4, r4, #(significandBits) // Make +inf.217 218 cmp r2, r4219 bhi LOCAL_LABEL(a_is_nan)220 cmp r3, r4221 bhi LOCAL_LABEL(b_is_nan)222 223 cmp r2, r4224 bne LOCAL_LABEL(a_is_rational)225 // aAbs is INF.226 eors r1, r0 // aRep ^ bRep.227 movs r6, #1228 lsls r6, r6, #(typeWidth - 1) // get sign mask.229 cmp r1, r6 // if they only differ on sign bit, it's -INF + INF230 beq LOCAL_LABEL(a_is_nan)231 pop {r4, r5, r6, r7, pc}232 233LOCAL_LABEL(a_is_rational):234 cmp r3, r4235 bne LOCAL_LABEL(b_is_rational)236 movs r0, r1237 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, r3242 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 = +0249 pop {r4, r5, r6, r7, pc}250 251LOCAL_LABEL(ret_b):252 movs r0, r1253 254LOCAL_LABEL(ret):255 pop {r4, r5, r6, r7, pc}256 257LOCAL_LABEL(b_is_nan):258 movs r0, r1259LOCAL_LABEL(a_is_nan):260 movs r1, #1261 lsls r1, r1, #(significandBits -1) // r1 is quiet bit.262 orrs r0, r1263 pop {r4, r5, r6, r7, pc}264 265LOCAL_LABEL(ret_inf):266 movs r4, #0xFF267 lsls r4, r4, #(significandBits)268 orrs r0, r4269 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_DIRECTIVE277