1353358Sdim//===-- addsf3.S - Adds two single precision floating pointer numbers-----===// 2353358Sdim// 3353358Sdim// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4353358Sdim// See https://llvm.org/LICENSE.txt for license information. 5353358Sdim// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6353358Sdim// 7353358Sdim//===----------------------------------------------------------------------===// 8353358Sdim// 9353358Sdim// This file implements the __addsf3 (single precision floating pointer number 10353358Sdim// addition with the IEEE-754 default rounding (to nearest, ties to even) 11353358Sdim// function for the ARM Thumb1 ISA. 12353358Sdim// 13353358Sdim//===----------------------------------------------------------------------===// 14317021Sdim 15317021Sdim#include "../assembly.h" 16317021Sdim#define significandBits 23 17317021Sdim#define typeWidth 32 18317021Sdim 19317021Sdim .syntax unified 20317021Sdim .text 21317021Sdim .thumb 22317021Sdim .p2align 2 23317021Sdim 24317021SdimDEFINE_AEABI_FUNCTION_ALIAS(__aeabi_fadd, __addsf3) 25317021Sdim 26317021SdimDEFINE_COMPILERRT_THUMB_FUNCTION(__addsf3) 27317021Sdim push {r4, r5, r6, r7, lr} 28317021Sdim // Get the absolute value of a and b. 29317021Sdim lsls r2, r0, #1 30317021Sdim lsls r3, r1, #1 31353358Sdim lsrs r2, r2, #1 // aAbs 32317021Sdim beq LOCAL_LABEL(a_zero_nan_inf) 33353358Sdim lsrs r3, r3, #1 // bAbs 34317021Sdim beq LOCAL_LABEL(zero_nan_inf) 35317021Sdim 36317021Sdim // Detect if a or b is infinity or Nan. 37317021Sdim lsrs r6, r2, #(significandBits) 38317021Sdim lsrs r7, r3, #(significandBits) 39317021Sdim cmp r6, #0xFF 40317021Sdim beq LOCAL_LABEL(zero_nan_inf) 41317021Sdim cmp r7, #0xFF 42317021Sdim beq LOCAL_LABEL(zero_nan_inf) 43317021Sdim 44317021Sdim // Swap Rep and Abs so that a and aAbs has the larger absolute value. 45317021Sdim cmp r2, r3 46317021Sdim bhs LOCAL_LABEL(no_swap) 47317021Sdim movs r4, r0 48317021Sdim movs r5, r2 49317021Sdim movs r0, r1 50317021Sdim movs r2, r3 51317021Sdim movs r1, r4 52317021Sdim movs r3, r5 53317021SdimLOCAL_LABEL(no_swap): 54317021Sdim 55317021Sdim // Get the significands and shift them to give us round, guard and sticky. 56317021Sdim lsls r4, r0, #(typeWidth - significandBits) 57353358Sdim lsrs r4, r4, #(typeWidth - significandBits - 3) // aSignificand << 3 58317021Sdim lsls r5, r1, #(typeWidth - significandBits) 59353358Sdim lsrs r5, r5, #(typeWidth - significandBits - 3) // bSignificand << 3 60317021Sdim 61317021Sdim // Get the implicitBit. 62317021Sdim movs r6, #1 63317021Sdim lsls r6, r6, #(significandBits + 3) 64317021Sdim 65317021Sdim // Get aExponent and set implicit bit if necessary. 66317021Sdim lsrs r2, r2, #(significandBits) 67317021Sdim beq LOCAL_LABEL(a_done_implicit_bit) 68317021Sdim orrs r4, r6 69317021SdimLOCAL_LABEL(a_done_implicit_bit): 70317021Sdim 71317021Sdim // Get bExponent and set implicit bit if necessary. 72317021Sdim lsrs r3, r3, #(significandBits) 73317021Sdim beq LOCAL_LABEL(b_done_implicit_bit) 74317021Sdim orrs r5, r6 75317021SdimLOCAL_LABEL(b_done_implicit_bit): 76317021Sdim 77317021Sdim // Get the difference in exponents. 78317021Sdim subs r6, r2, r3 79317021Sdim beq LOCAL_LABEL(done_align) 80317021Sdim 81317021Sdim // If b is denormal, then a must be normal as align > 0, and we only need to 82317021Sdim // right shift bSignificand by (align - 1) bits. 83317021Sdim cmp r3, #0 84317021Sdim bne 1f 85317021Sdim subs r6, r6, #1 86317021Sdim1: 87317021Sdim 88317021Sdim // No longer needs bExponent. r3 is dead here. 89317021Sdim // Set sticky bits of b: sticky = bSignificand << (typeWidth - align). 90317021Sdim movs r3, #(typeWidth) 91317021Sdim subs r3, r3, r6 92317021Sdim movs r7, r5 93317021Sdim lsls r7, r3 94317021Sdim beq 1f 95317021Sdim movs r7, #1 96317021Sdim1: 97317021Sdim 98317021Sdim // bSignificand = bSignificand >> align | sticky; 99317021Sdim lsrs r5, r6 100317021Sdim orrs r5, r7 101317021Sdim bne LOCAL_LABEL(done_align) 102317021Sdim movs r5, #1 // sticky; b is known to be non-zero. 103317021Sdim 104317021SdimLOCAL_LABEL(done_align): 105317021Sdim // isSubtraction = (aRep ^ bRep) >> 31; 106317021Sdim movs r7, r0 107317021Sdim eors r7, r1 108317021Sdim lsrs r7, #31 109317021Sdim bne LOCAL_LABEL(do_substraction) 110317021Sdim 111317021Sdim // Same sign, do Addition. 112317021Sdim 113317021Sdim // aSignificand += bSignificand; 114317021Sdim adds r4, r4, r5 115317021Sdim 116317021Sdim // Check carry bit. 117317021Sdim movs r6, #1 118317021Sdim lsls r6, r6, #(significandBits + 3 + 1) 119317021Sdim movs r7, r4 120317021Sdim ands r7, r6 121317021Sdim beq LOCAL_LABEL(form_result) 122317021Sdim // If the addition carried up, we need to right-shift the result and 123317021Sdim // adjust the exponent. 124317021Sdim movs r7, r4 125317021Sdim movs r6, #1 126317021Sdim ands r7, r6 // sticky = aSignificand & 1; 127317021Sdim lsrs r4, #1 128317021Sdim orrs r4, r7 // result Significand 129317021Sdim adds r2, #1 // result Exponent 130317021Sdim // If we have overflowed the type, return +/- infinity. 131317021Sdim cmp r2, 0xFF 132317021Sdim beq LOCAL_LABEL(ret_inf) 133317021Sdim 134317021SdimLOCAL_LABEL(form_result): 135317021Sdim // Shift the sign, exponent and significand into place. 136317021Sdim lsrs r0, #(typeWidth - 1) 137317021Sdim lsls r0, #(typeWidth - 1) // Get Sign. 138317021Sdim lsls r2, #(significandBits) 139317021Sdim orrs r0, r2 140317021Sdim movs r1, r4 141317021Sdim lsls r4, #(typeWidth - significandBits - 3) 142317021Sdim lsrs r4, #(typeWidth - significandBits) 143317021Sdim orrs r0, r4 144317021Sdim 145317021Sdim // Final rounding. The result may overflow to infinity, but that is the 146317021Sdim // correct result in that case. 147317021Sdim // roundGuardSticky = aSignificand & 0x7; 148317021Sdim movs r2, #0x7 149317021Sdim ands r1, r2 150317021Sdim // if (roundGuardSticky > 0x4) result++; 151317021Sdim 152317021Sdim cmp r1, #0x4 153317021Sdim blt LOCAL_LABEL(done_round) 154317021Sdim beq 1f 155317021Sdim adds r0, #1 156317021Sdim pop {r4, r5, r6, r7, pc} 157317021Sdim1: 158317021Sdim 159317021Sdim // if (roundGuardSticky == 0x4) result += result & 1; 160317021Sdim movs r1, r0 161317021Sdim lsrs r1, #1 162317021Sdim bcc LOCAL_LABEL(done_round) 163317021Sdim adds r0, r0, #1 164317021SdimLOCAL_LABEL(done_round): 165317021Sdim pop {r4, r5, r6, r7, pc} 166317021Sdim 167317021SdimLOCAL_LABEL(do_substraction): 168317021Sdim subs r4, r4, r5 // aSignificand -= bSignificand; 169317021Sdim beq LOCAL_LABEL(ret_zero) 170317021Sdim movs r6, r4 171317021Sdim cmp r2, 0 172317021Sdim beq LOCAL_LABEL(form_result) // if a's exp is 0, no need to normalize. 173317021Sdim // If partial cancellation occured, we need to left-shift the result 174317021Sdim // and adjust the exponent: 175317021Sdim lsrs r6, r6, #(significandBits + 3) 176317021Sdim bne LOCAL_LABEL(form_result) 177317021Sdim 178317021Sdim push {r0, r1, r2, r3} 179317021Sdim movs r0, r4 180344779Sdim bl SYMBOL_NAME(__clzsi2) 181317021Sdim movs r5, r0 182317021Sdim pop {r0, r1, r2, r3} 183317021Sdim // shift = rep_clz(aSignificand) - rep_clz(implicitBit << 3); 184317021Sdim subs r5, r5, #(typeWidth - significandBits - 3 - 1) 185317021Sdim // aSignificand <<= shift; aExponent -= shift; 186317021Sdim lsls r4, r5 187317021Sdim subs r2, r2, r5 188317021Sdim bgt LOCAL_LABEL(form_result) 189317021Sdim 190317021Sdim // Do normalization if aExponent <= 0. 191317021Sdim movs r6, #1 192317021Sdim subs r6, r6, r2 // 1 - aExponent; 193317021Sdim movs r2, #0 // aExponent = 0; 194317021Sdim movs r3, #(typeWidth) // bExponent is dead. 195317021Sdim subs r3, r3, r6 196317021Sdim movs r7, r4 197317021Sdim lsls r7, r3 // stickyBit = (bool)(aSignificant << (typeWidth - align)) 198317021Sdim beq 1f 199317021Sdim movs r7, #1 200317021Sdim1: 201353358Sdim lsrs r4, r6 // aSignificand >> shift 202317021Sdim orrs r4, r7 203317021Sdim b LOCAL_LABEL(form_result) 204317021Sdim 205317021SdimLOCAL_LABEL(ret_zero): 206317021Sdim movs r0, #0 207317021Sdim pop {r4, r5, r6, r7, pc} 208317021Sdim 209317021Sdim 210317021SdimLOCAL_LABEL(a_zero_nan_inf): 211317021Sdim lsrs r3, r3, #1 212317021Sdim 213317021SdimLOCAL_LABEL(zero_nan_inf): 214317021Sdim // Here r2 has aAbs, r3 has bAbs 215317021Sdim movs r4, #0xFF 216317021Sdim lsls r4, r4, #(significandBits) // Make +inf. 217317021Sdim 218317021Sdim cmp r2, r4 219317021Sdim bhi LOCAL_LABEL(a_is_nan) 220317021Sdim cmp r3, r4 221317021Sdim bhi LOCAL_LABEL(b_is_nan) 222317021Sdim 223317021Sdim cmp r2, r4 224317021Sdim bne LOCAL_LABEL(a_is_rational) 225317021Sdim // aAbs is INF. 226317021Sdim eors r1, r0 // aRep ^ bRep. 227317021Sdim movs r6, #1 228317021Sdim lsls r6, r6, #(typeWidth - 1) // get sign mask. 229317021Sdim cmp r1, r6 // if they only differ on sign bit, it's -INF + INF 230317021Sdim beq LOCAL_LABEL(a_is_nan) 231317021Sdim pop {r4, r5, r6, r7, pc} 232317021Sdim 233317021SdimLOCAL_LABEL(a_is_rational): 234317021Sdim cmp r3, r4 235317021Sdim bne LOCAL_LABEL(b_is_rational) 236317021Sdim movs r0, r1 237317021Sdim pop {r4, r5, r6, r7, pc} 238317021Sdim 239317021SdimLOCAL_LABEL(b_is_rational): 240317021Sdim // either a or b or both are zero. 241317021Sdim adds r4, r2, r3 242317021Sdim beq LOCAL_LABEL(both_zero) 243317021Sdim cmp r2, #0 // is absA 0 ? 244317021Sdim beq LOCAL_LABEL(ret_b) 245317021Sdim pop {r4, r5, r6, r7, pc} 246317021Sdim 247317021SdimLOCAL_LABEL(both_zero): 248317021Sdim ands r0, r1 // +0 + -0 = +0 249317021Sdim pop {r4, r5, r6, r7, pc} 250317021Sdim 251317021SdimLOCAL_LABEL(ret_b): 252317021Sdim movs r0, r1 253317021Sdim 254317021SdimLOCAL_LABEL(ret): 255317021Sdim pop {r4, r5, r6, r7, pc} 256317021Sdim 257317021SdimLOCAL_LABEL(b_is_nan): 258317021Sdim movs r0, r1 259317021SdimLOCAL_LABEL(a_is_nan): 260317021Sdim movs r1, #1 261317021Sdim lsls r1, r1, #(significandBits -1) // r1 is quiet bit. 262317021Sdim orrs r0, r1 263317021Sdim pop {r4, r5, r6, r7, pc} 264317021Sdim 265317021SdimLOCAL_LABEL(ret_inf): 266317021Sdim movs r4, #0xFF 267317021Sdim lsls r4, r4, #(significandBits) 268317021Sdim orrs r0, r4 269317021Sdim lsrs r0, r0, #(significandBits) 270317021Sdim lsls r0, r0, #(significandBits) 271317021Sdim pop {r4, r5, r6, r7, pc} 272317021Sdim 273317021Sdim 274317021SdimEND_COMPILERRT_FUNCTION(__addsf3) 275317021Sdim 276317021SdimNO_EXEC_STACK_DIRECTIVE 277