1*3cab2bb3Spatrick//===-- comparesf2.S - Implement single-precision soft-float comparisons --===// 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 following soft-fp_t comparison routines: 10*3cab2bb3Spatrick// 11*3cab2bb3Spatrick// __eqsf2 __gesf2 __unordsf2 12*3cab2bb3Spatrick// __lesf2 __gtsf2 13*3cab2bb3Spatrick// __ltsf2 14*3cab2bb3Spatrick// __nesf2 15*3cab2bb3Spatrick// 16*3cab2bb3Spatrick// The semantics of the routines grouped in each column are identical, so there 17*3cab2bb3Spatrick// is a single implementation for each, with multiple names. 18*3cab2bb3Spatrick// 19*3cab2bb3Spatrick// The routines behave as follows: 20*3cab2bb3Spatrick// 21*3cab2bb3Spatrick// __lesf2(a,b) returns -1 if a < b 22*3cab2bb3Spatrick// 0 if a == b 23*3cab2bb3Spatrick// 1 if a > b 24*3cab2bb3Spatrick// 1 if either a or b is NaN 25*3cab2bb3Spatrick// 26*3cab2bb3Spatrick// __gesf2(a,b) returns -1 if a < b 27*3cab2bb3Spatrick// 0 if a == b 28*3cab2bb3Spatrick// 1 if a > b 29*3cab2bb3Spatrick// -1 if either a or b is NaN 30*3cab2bb3Spatrick// 31*3cab2bb3Spatrick// __unordsf2(a,b) returns 0 if both a and b are numbers 32*3cab2bb3Spatrick// 1 if either a or b is NaN 33*3cab2bb3Spatrick// 34*3cab2bb3Spatrick// Note that __lesf2( ) and __gesf2( ) are identical except in their handling of 35*3cab2bb3Spatrick// NaN values. 36*3cab2bb3Spatrick// 37*3cab2bb3Spatrick//===----------------------------------------------------------------------===// 38*3cab2bb3Spatrick 39*3cab2bb3Spatrick#include "../assembly.h" 40*3cab2bb3Spatrick 41*3cab2bb3Spatrick .syntax unified 42*3cab2bb3Spatrick .text 43*3cab2bb3Spatrick DEFINE_CODE_STATE 44*3cab2bb3Spatrick 45*3cab2bb3Spatrick .macro COMPARESF2_FUNCTION_BODY handle_nan:req 46*3cab2bb3Spatrick#if defined(COMPILER_RT_ARMHF_TARGET) 47*3cab2bb3Spatrick vmov r0, s0 48*3cab2bb3Spatrick vmov r1, s1 49*3cab2bb3Spatrick#endif 50*3cab2bb3Spatrick // Make copies of a and b with the sign bit shifted off the top. These will 51*3cab2bb3Spatrick // be used to detect zeros and NaNs. 52*3cab2bb3Spatrick#if defined(USE_THUMB_1) 53*3cab2bb3Spatrick push {r6, lr} 54*3cab2bb3Spatrick lsls r2, r0, #1 55*3cab2bb3Spatrick lsls r3, r1, #1 56*3cab2bb3Spatrick#else 57*3cab2bb3Spatrick mov r2, r0, lsl #1 58*3cab2bb3Spatrick mov r3, r1, lsl #1 59*3cab2bb3Spatrick#endif 60*3cab2bb3Spatrick 61*3cab2bb3Spatrick // We do the comparison in three stages (ignoring NaN values for the time 62*3cab2bb3Spatrick // being). First, we orr the absolute values of a and b; this sets the Z 63*3cab2bb3Spatrick // flag if both a and b are zero (of either sign). The shift of r3 doesn't 64*3cab2bb3Spatrick // effect this at all, but it *does* make sure that the C flag is clear for 65*3cab2bb3Spatrick // the subsequent operations. 66*3cab2bb3Spatrick#if defined(USE_THUMB_1) 67*3cab2bb3Spatrick lsrs r6, r3, #1 68*3cab2bb3Spatrick orrs r6, r2 69*3cab2bb3Spatrick#else 70*3cab2bb3Spatrick orrs r12, r2, r3, lsr #1 71*3cab2bb3Spatrick#endif 72*3cab2bb3Spatrick // Next, we check if a and b have the same or different signs. If they have 73*3cab2bb3Spatrick // opposite signs, this eor will set the N flag. 74*3cab2bb3Spatrick#if defined(USE_THUMB_1) 75*3cab2bb3Spatrick beq 1f 76*3cab2bb3Spatrick movs r6, r0 77*3cab2bb3Spatrick eors r6, r1 78*3cab2bb3Spatrick1: 79*3cab2bb3Spatrick#else 80*3cab2bb3Spatrick it ne 81*3cab2bb3Spatrick eorsne r12, r0, r1 82*3cab2bb3Spatrick#endif 83*3cab2bb3Spatrick 84*3cab2bb3Spatrick // If a and b are equal (either both zeros or bit identical; again, we're 85*3cab2bb3Spatrick // ignoring NaNs for now), this subtract will zero out r0. If they have the 86*3cab2bb3Spatrick // same sign, the flags are updated as they would be for a comparison of the 87*3cab2bb3Spatrick // absolute values of a and b. 88*3cab2bb3Spatrick#if defined(USE_THUMB_1) 89*3cab2bb3Spatrick bmi 1f 90*3cab2bb3Spatrick subs r0, r2, r3 91*3cab2bb3Spatrick1: 92*3cab2bb3Spatrick#else 93*3cab2bb3Spatrick it pl 94*3cab2bb3Spatrick subspl r0, r2, r3 95*3cab2bb3Spatrick#endif 96*3cab2bb3Spatrick 97*3cab2bb3Spatrick // If a is smaller in magnitude than b and both have the same sign, place 98*3cab2bb3Spatrick // the negation of the sign of b in r0. Thus, if both are negative and 99*3cab2bb3Spatrick // a > b, this sets r0 to 0; if both are positive and a < b, this sets 100*3cab2bb3Spatrick // r0 to -1. 101*3cab2bb3Spatrick // 102*3cab2bb3Spatrick // This is also done if a and b have opposite signs and are not both zero, 103*3cab2bb3Spatrick // because in that case the subtract was not performed and the C flag is 104*3cab2bb3Spatrick // still clear from the shift argument in orrs; if a is positive and b 105*3cab2bb3Spatrick // negative, this places 0 in r0; if a is negative and b positive, -1 is 106*3cab2bb3Spatrick // placed in r0. 107*3cab2bb3Spatrick#if defined(USE_THUMB_1) 108*3cab2bb3Spatrick bhs 1f 109*3cab2bb3Spatrick // Here if a and b have the same sign and absA < absB, the result is thus 110*3cab2bb3Spatrick // b < 0 ? 1 : -1. Same if a and b have the opposite sign (ignoring Nan). 111*3cab2bb3Spatrick movs r0, #1 112*3cab2bb3Spatrick lsrs r1, #31 113*3cab2bb3Spatrick bne LOCAL_LABEL(CHECK_NAN\@) 114*3cab2bb3Spatrick negs r0, r0 115*3cab2bb3Spatrick b LOCAL_LABEL(CHECK_NAN\@) 116*3cab2bb3Spatrick1: 117*3cab2bb3Spatrick#else 118*3cab2bb3Spatrick it lo 119*3cab2bb3Spatrick mvnlo r0, r1, asr #31 120*3cab2bb3Spatrick#endif 121*3cab2bb3Spatrick 122*3cab2bb3Spatrick // If a is greater in magnitude than b and both have the same sign, place 123*3cab2bb3Spatrick // the sign of b in r0. Thus, if both are negative and a < b, -1 is placed 124*3cab2bb3Spatrick // in r0, which is the desired result. Conversely, if both are positive 125*3cab2bb3Spatrick // and a > b, zero is placed in r0. 126*3cab2bb3Spatrick#if defined(USE_THUMB_1) 127*3cab2bb3Spatrick bls 1f 128*3cab2bb3Spatrick // Here both have the same sign and absA > absB. 129*3cab2bb3Spatrick movs r0, #1 130*3cab2bb3Spatrick lsrs r1, #31 131*3cab2bb3Spatrick beq LOCAL_LABEL(CHECK_NAN\@) 132*3cab2bb3Spatrick negs r0, r0 133*3cab2bb3Spatrick1: 134*3cab2bb3Spatrick#else 135*3cab2bb3Spatrick it hi 136*3cab2bb3Spatrick movhi r0, r1, asr #31 137*3cab2bb3Spatrick#endif 138*3cab2bb3Spatrick 139*3cab2bb3Spatrick // If you've been keeping track, at this point r0 contains -1 if a < b and 140*3cab2bb3Spatrick // 0 if a >= b. All that remains to be done is to set it to 1 if a > b. 141*3cab2bb3Spatrick // If a == b, then the Z flag is set, so we can get the correct final value 142*3cab2bb3Spatrick // into r0 by simply or'ing with 1 if Z is clear. 143*3cab2bb3Spatrick // For Thumb-1, r0 contains -1 if a < b, 0 if a > b and 0 if a == b. 144*3cab2bb3Spatrick#if !defined(USE_THUMB_1) 145*3cab2bb3Spatrick it ne 146*3cab2bb3Spatrick orrne r0, r0, #1 147*3cab2bb3Spatrick#endif 148*3cab2bb3Spatrick 149*3cab2bb3Spatrick // Finally, we need to deal with NaNs. If either argument is NaN, replace 150*3cab2bb3Spatrick // the value in r0 with 1. 151*3cab2bb3Spatrick#if defined(USE_THUMB_1) 152*3cab2bb3SpatrickLOCAL_LABEL(CHECK_NAN\@): 153*3cab2bb3Spatrick movs r6, #0xff 154*3cab2bb3Spatrick lsls r6, #24 155*3cab2bb3Spatrick cmp r2, r6 156*3cab2bb3Spatrick bhi 1f 157*3cab2bb3Spatrick cmp r3, r6 158*3cab2bb3Spatrick1: 159*3cab2bb3Spatrick bls 2f 160*3cab2bb3Spatrick \handle_nan 161*3cab2bb3Spatrick2: 162*3cab2bb3Spatrick pop {r6, pc} 163*3cab2bb3Spatrick#else 164*3cab2bb3Spatrick cmp r2, #0xff000000 165*3cab2bb3Spatrick ite ls 166*3cab2bb3Spatrick cmpls r3, #0xff000000 167*3cab2bb3Spatrick \handle_nan 168*3cab2bb3Spatrick JMP(lr) 169*3cab2bb3Spatrick#endif 170*3cab2bb3Spatrick .endm 171*3cab2bb3Spatrick 172*3cab2bb3Spatrick@ int __eqsf2(float a, float b) 173*3cab2bb3Spatrick 174*3cab2bb3Spatrick .p2align 2 175*3cab2bb3SpatrickDEFINE_COMPILERRT_FUNCTION(__eqsf2) 176*3cab2bb3Spatrick 177*3cab2bb3Spatrick .macro __eqsf2_handle_nan 178*3cab2bb3Spatrick#if defined(USE_THUMB_1) 179*3cab2bb3Spatrick movs r0, #1 180*3cab2bb3Spatrick#else 181*3cab2bb3Spatrick movhi r0, #1 182*3cab2bb3Spatrick#endif 183*3cab2bb3Spatrick .endm 184*3cab2bb3Spatrick 185*3cab2bb3SpatrickCOMPARESF2_FUNCTION_BODY __eqsf2_handle_nan 186*3cab2bb3Spatrick 187*3cab2bb3SpatrickEND_COMPILERRT_FUNCTION(__eqsf2) 188*3cab2bb3Spatrick 189*3cab2bb3SpatrickDEFINE_COMPILERRT_FUNCTION_ALIAS(__lesf2, __eqsf2) 190*3cab2bb3SpatrickDEFINE_COMPILERRT_FUNCTION_ALIAS(__ltsf2, __eqsf2) 191*3cab2bb3SpatrickDEFINE_COMPILERRT_FUNCTION_ALIAS(__nesf2, __eqsf2) 192*3cab2bb3Spatrick 193*3cab2bb3Spatrick#if defined(__ELF__) 194*3cab2bb3Spatrick// Alias for libgcc compatibility 195*3cab2bb3SpatrickDEFINE_COMPILERRT_FUNCTION_ALIAS(__cmpsf2, __lesf2) 196*3cab2bb3Spatrick#endif 197*3cab2bb3Spatrick 198*3cab2bb3Spatrick@ int __gtsf2(float a, float b) 199*3cab2bb3Spatrick 200*3cab2bb3Spatrick .p2align 2 201*3cab2bb3SpatrickDEFINE_COMPILERRT_FUNCTION(__gtsf2) 202*3cab2bb3Spatrick 203*3cab2bb3Spatrick .macro __gtsf2_handle_nan 204*3cab2bb3Spatrick#if defined(USE_THUMB_1) 205*3cab2bb3Spatrick movs r0, #1 206*3cab2bb3Spatrick negs r0, r0 207*3cab2bb3Spatrick#else 208*3cab2bb3Spatrick movhi r0, #-1 209*3cab2bb3Spatrick#endif 210*3cab2bb3Spatrick .endm 211*3cab2bb3Spatrick 212*3cab2bb3SpatrickCOMPARESF2_FUNCTION_BODY __gtsf2_handle_nan 213*3cab2bb3Spatrick 214*3cab2bb3SpatrickEND_COMPILERRT_FUNCTION(__gtsf2) 215*3cab2bb3Spatrick 216*3cab2bb3SpatrickDEFINE_COMPILERRT_FUNCTION_ALIAS(__gesf2, __gtsf2) 217*3cab2bb3Spatrick 218*3cab2bb3Spatrick@ int __unordsf2(float a, float b) 219*3cab2bb3Spatrick 220*3cab2bb3Spatrick .p2align 2 221*3cab2bb3SpatrickDEFINE_COMPILERRT_FUNCTION(__unordsf2) 222*3cab2bb3Spatrick 223*3cab2bb3Spatrick#if defined(COMPILER_RT_ARMHF_TARGET) 224*3cab2bb3Spatrick vmov r0, s0 225*3cab2bb3Spatrick vmov r1, s1 226*3cab2bb3Spatrick#endif 227*3cab2bb3Spatrick // Return 1 for NaN values, 0 otherwise. 228*3cab2bb3Spatrick lsls r2, r0, #1 229*3cab2bb3Spatrick lsls r3, r1, #1 230*3cab2bb3Spatrick movs r0, #0 231*3cab2bb3Spatrick#if defined(USE_THUMB_1) 232*3cab2bb3Spatrick movs r1, #0xff 233*3cab2bb3Spatrick lsls r1, #24 234*3cab2bb3Spatrick cmp r2, r1 235*3cab2bb3Spatrick bhi 1f 236*3cab2bb3Spatrick cmp r3, r1 237*3cab2bb3Spatrick1: 238*3cab2bb3Spatrick bls 2f 239*3cab2bb3Spatrick movs r0, #1 240*3cab2bb3Spatrick2: 241*3cab2bb3Spatrick#else 242*3cab2bb3Spatrick cmp r2, #0xff000000 243*3cab2bb3Spatrick ite ls 244*3cab2bb3Spatrick cmpls r3, #0xff000000 245*3cab2bb3Spatrick movhi r0, #1 246*3cab2bb3Spatrick#endif 247*3cab2bb3Spatrick JMP(lr) 248*3cab2bb3SpatrickEND_COMPILERRT_FUNCTION(__unordsf2) 249*3cab2bb3Spatrick 250*3cab2bb3Spatrick#if defined(COMPILER_RT_ARMHF_TARGET) 251*3cab2bb3SpatrickDEFINE_COMPILERRT_FUNCTION(__aeabi_fcmpun) 252*3cab2bb3Spatrick vmov s0, r0 253*3cab2bb3Spatrick vmov s1, r1 254*3cab2bb3Spatrick b SYMBOL_NAME(__unordsf2) 255*3cab2bb3SpatrickEND_COMPILERRT_FUNCTION(__aeabi_fcmpun) 256*3cab2bb3Spatrick#else 257*3cab2bb3SpatrickDEFINE_AEABI_FUNCTION_ALIAS(__aeabi_fcmpun, __unordsf2) 258*3cab2bb3Spatrick#endif 259*3cab2bb3Spatrick 260*3cab2bb3SpatrickNO_EXEC_STACK_DIRECTIVE 261*3cab2bb3Spatrick 262