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