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