123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276 |
- //===-- addsf3.S - Adds two single precision floating pointer numbers-----===//
- //
- // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
- // See https://llvm.org/LICENSE.txt for license information.
- // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
- //
- //===----------------------------------------------------------------------===//
- //
- // This file implements the __addsf3 (single precision floating pointer number
- // addition with the IEEE-754 default rounding (to nearest, ties to even)
- // function for the ARM Thumb1 ISA.
- //
- //===----------------------------------------------------------------------===//
- #include "../assembly.h"
- #define significandBits 23
- #define typeWidth 32
- .syntax unified
- .text
- .thumb
- .p2align 2
- DEFINE_AEABI_FUNCTION_ALIAS(__aeabi_fadd, __addsf3)
- DEFINE_COMPILERRT_THUMB_FUNCTION(__addsf3)
- push {r4, r5, r6, r7, lr}
- // Get the absolute value of a and b.
- lsls r2, r0, #1
- lsls r3, r1, #1
- lsrs r2, r2, #1 // aAbs
- beq LOCAL_LABEL(a_zero_nan_inf)
- lsrs r3, r3, #1 // bAbs
- beq LOCAL_LABEL(zero_nan_inf)
- // Detect if a or b is infinity or Nan.
- lsrs r6, r2, #(significandBits)
- lsrs r7, r3, #(significandBits)
- cmp r6, #0xFF
- beq LOCAL_LABEL(zero_nan_inf)
- cmp r7, #0xFF
- beq LOCAL_LABEL(zero_nan_inf)
- // Swap Rep and Abs so that a and aAbs has the larger absolute value.
- cmp r2, r3
- bhs LOCAL_LABEL(no_swap)
- movs r4, r0
- movs r5, r2
- movs r0, r1
- movs r2, r3
- movs r1, r4
- movs r3, r5
- LOCAL_LABEL(no_swap):
- // Get the significands and shift them to give us round, guard and sticky.
- lsls r4, r0, #(typeWidth - significandBits)
- lsrs r4, r4, #(typeWidth - significandBits - 3) // aSignificand << 3
- lsls r5, r1, #(typeWidth - significandBits)
- lsrs r5, r5, #(typeWidth - significandBits - 3) // bSignificand << 3
- // Get the implicitBit.
- movs r6, #1
- lsls r6, r6, #(significandBits + 3)
- // Get aExponent and set implicit bit if necessary.
- lsrs r2, r2, #(significandBits)
- beq LOCAL_LABEL(a_done_implicit_bit)
- orrs r4, r6
- LOCAL_LABEL(a_done_implicit_bit):
- // Get bExponent and set implicit bit if necessary.
- lsrs r3, r3, #(significandBits)
- beq LOCAL_LABEL(b_done_implicit_bit)
- orrs r5, r6
- LOCAL_LABEL(b_done_implicit_bit):
- // Get the difference in exponents.
- subs r6, r2, r3
- beq LOCAL_LABEL(done_align)
- // If b is denormal, then a must be normal as align > 0, and we only need to
- // right shift bSignificand by (align - 1) bits.
- cmp r3, #0
- bne 1f
- subs r6, r6, #1
- 1:
- // No longer needs bExponent. r3 is dead here.
- // Set sticky bits of b: sticky = bSignificand << (typeWidth - align).
- movs r3, #(typeWidth)
- subs r3, r3, r6
- movs r7, r5
- lsls r7, r3
- beq 1f
- movs r7, #1
- 1:
- // bSignificand = bSignificand >> align | sticky;
- lsrs r5, r6
- orrs r5, r7
- bne LOCAL_LABEL(done_align)
- movs r5, #1 // sticky; b is known to be non-zero.
- LOCAL_LABEL(done_align):
- // isSubtraction = (aRep ^ bRep) >> 31;
- movs r7, r0
- eors r7, r1
- lsrs r7, #31
- bne LOCAL_LABEL(do_substraction)
- // Same sign, do Addition.
- // aSignificand += bSignificand;
- adds r4, r4, r5
- // Check carry bit.
- movs r6, #1
- lsls r6, r6, #(significandBits + 3 + 1)
- movs r7, r4
- ands r7, r6
- beq LOCAL_LABEL(form_result)
- // If the addition carried up, we need to right-shift the result and
- // adjust the exponent.
- movs r7, r4
- movs r6, #1
- ands r7, r6 // sticky = aSignificand & 1;
- lsrs r4, #1
- orrs r4, r7 // result Significand
- adds r2, #1 // result Exponent
- // If we have overflowed the type, return +/- infinity.
- cmp r2, 0xFF
- beq LOCAL_LABEL(ret_inf)
- LOCAL_LABEL(form_result):
- // Shift the sign, exponent and significand into place.
- lsrs r0, #(typeWidth - 1)
- lsls r0, #(typeWidth - 1) // Get Sign.
- lsls r2, #(significandBits)
- orrs r0, r2
- movs r1, r4
- lsls r4, #(typeWidth - significandBits - 3)
- lsrs r4, #(typeWidth - significandBits)
- orrs r0, r4
- // Final rounding. The result may overflow to infinity, but that is the
- // correct result in that case.
- // roundGuardSticky = aSignificand & 0x7;
- movs r2, #0x7
- ands r1, r2
- // if (roundGuardSticky > 0x4) result++;
- cmp r1, #0x4
- blt LOCAL_LABEL(done_round)
- beq 1f
- adds r0, #1
- pop {r4, r5, r6, r7, pc}
- 1:
- // if (roundGuardSticky == 0x4) result += result & 1;
- movs r1, r0
- lsrs r1, #1
- bcc LOCAL_LABEL(done_round)
- adds r0, r0, #1
- LOCAL_LABEL(done_round):
- pop {r4, r5, r6, r7, pc}
- LOCAL_LABEL(do_substraction):
- subs r4, r4, r5 // aSignificand -= bSignificand;
- beq LOCAL_LABEL(ret_zero)
- movs r6, r4
- cmp r2, 0
- beq LOCAL_LABEL(form_result) // if a's exp is 0, no need to normalize.
- // If partial cancellation occured, we need to left-shift the result
- // and adjust the exponent:
- lsrs r6, r6, #(significandBits + 3)
- bne LOCAL_LABEL(form_result)
- push {r0, r1, r2, r3}
- movs r0, r4
- bl SYMBOL_NAME(__clzsi2)
- movs r5, r0
- pop {r0, r1, r2, r3}
- // shift = rep_clz(aSignificand) - rep_clz(implicitBit << 3);
- subs r5, r5, #(typeWidth - significandBits - 3 - 1)
- // aSignificand <<= shift; aExponent -= shift;
- lsls r4, r5
- subs r2, r2, r5
- bgt LOCAL_LABEL(form_result)
- // Do normalization if aExponent <= 0.
- movs r6, #1
- subs r6, r6, r2 // 1 - aExponent;
- movs r2, #0 // aExponent = 0;
- movs r3, #(typeWidth) // bExponent is dead.
- subs r3, r3, r6
- movs r7, r4
- lsls r7, r3 // stickyBit = (bool)(aSignificant << (typeWidth - align))
- beq 1f
- movs r7, #1
- 1:
- lsrs r4, r6 // aSignificand >> shift
- orrs r4, r7
- b LOCAL_LABEL(form_result)
- LOCAL_LABEL(ret_zero):
- movs r0, #0
- pop {r4, r5, r6, r7, pc}
- LOCAL_LABEL(a_zero_nan_inf):
- lsrs r3, r3, #1
- LOCAL_LABEL(zero_nan_inf):
- // Here r2 has aAbs, r3 has bAbs
- movs r4, #0xFF
- lsls r4, r4, #(significandBits) // Make +inf.
- cmp r2, r4
- bhi LOCAL_LABEL(a_is_nan)
- cmp r3, r4
- bhi LOCAL_LABEL(b_is_nan)
- cmp r2, r4
- bne LOCAL_LABEL(a_is_rational)
- // aAbs is INF.
- eors r1, r0 // aRep ^ bRep.
- movs r6, #1
- lsls r6, r6, #(typeWidth - 1) // get sign mask.
- cmp r1, r6 // if they only differ on sign bit, it's -INF + INF
- beq LOCAL_LABEL(a_is_nan)
- pop {r4, r5, r6, r7, pc}
- LOCAL_LABEL(a_is_rational):
- cmp r3, r4
- bne LOCAL_LABEL(b_is_rational)
- movs r0, r1
- pop {r4, r5, r6, r7, pc}
- LOCAL_LABEL(b_is_rational):
- // either a or b or both are zero.
- adds r4, r2, r3
- beq LOCAL_LABEL(both_zero)
- cmp r2, #0 // is absA 0 ?
- beq LOCAL_LABEL(ret_b)
- pop {r4, r5, r6, r7, pc}
- LOCAL_LABEL(both_zero):
- ands r0, r1 // +0 + -0 = +0
- pop {r4, r5, r6, r7, pc}
- LOCAL_LABEL(ret_b):
- movs r0, r1
- LOCAL_LABEL(ret):
- pop {r4, r5, r6, r7, pc}
- LOCAL_LABEL(b_is_nan):
- movs r0, r1
- LOCAL_LABEL(a_is_nan):
- movs r1, #1
- lsls r1, r1, #(significandBits -1) // r1 is quiet bit.
- orrs r0, r1
- pop {r4, r5, r6, r7, pc}
- LOCAL_LABEL(ret_inf):
- movs r4, #0xFF
- lsls r4, r4, #(significandBits)
- orrs r0, r4
- lsrs r0, r0, #(significandBits)
- lsls r0, r0, #(significandBits)
- pop {r4, r5, r6, r7, pc}
- END_COMPILERRT_FUNCTION(__addsf3)
- NO_EXEC_STACK_DIRECTIVE
|