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