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