262 lines · plain
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-exception6//7//===----------------------------------------------------------------------===//8//9// This file implements the following soft-fp_t comparison routines:10//11// __eqsf2 __gesf2 __unordsf212// __lesf2 __gtsf213// __ltsf214// __nesf215//16// The semantics of the routines grouped in each column are identical, so there17// 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 < b22// 0 if a == b23// 1 if a > b24// 1 if either a or b is NaN25//26// __gesf2(a,b) returns -1 if a < b27// 0 if a == b28// 1 if a > b29// -1 if either a or b is NaN30//31// __unordsf2(a,b) returns 0 if both a and b are numbers32// 1 if either a or b is NaN33//34// Note that __lesf2( ) and __gesf2( ) are identical except in their handling of35// NaN values.36//37//===----------------------------------------------------------------------===//38 39#include "../assembly.h"40 41 .syntax unified42 .text43 DEFINE_CODE_STATE44 45 .macro COMPARESF2_FUNCTION_BODY handle_nan:req46#if defined(COMPILER_RT_ARMHF_TARGET)47 vmov r0, s048 vmov r1, s149#endif50 // Make copies of a and b with the sign bit shifted off the top. These will51 // be used to detect zeros and NaNs.52#if defined(USE_THUMB_1)53 push {r6, lr}54 lsls r2, r0, #155 lsls r3, r1, #156#else57 mov r2, r0, lsl #158 mov r3, r1, lsl #159#endif60 61 // We do the comparison in three stages (ignoring NaN values for the time62 // being). First, we orr the absolute values of a and b; this sets the Z63 // flag if both a and b are zero (of either sign). The shift of r3 doesn't64 // effect this at all, but it *does* make sure that the C flag is clear for65 // the subsequent operations.66#if defined(USE_THUMB_1)67 lsrs r6, r3, #168 orrs r6, r269#else70 orrs r12, r2, r3, lsr #171#endif72 // Next, we check if a and b have the same or different signs. If they have73 // opposite signs, this eor will set the N flag.74#if defined(USE_THUMB_1)75 beq 1f76 movs r6, r077 eors r6, r1781:79#else80 it ne81 eorsne r12, r0, r182#endif83 84 // If a and b are equal (either both zeros or bit identical; again, we're85 // ignoring NaNs for now), this subtract will zero out r0. If they have the86 // same sign, the flags are updated as they would be for a comparison of the87 // absolute values of a and b.88#if defined(USE_THUMB_1)89 bmi 1f90 subs r0, r2, r3911:92#else93 it pl94 subspl r0, r2, r395#endif96 97 // If a is smaller in magnitude than b and both have the same sign, place98 // the negation of the sign of b in r0. Thus, if both are negative and99 // a > b, this sets r0 to 0; if both are positive and a < b, this sets100 // 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 is104 // still clear from the shift argument in orrs; if a is positive and b105 // negative, this places 0 in r0; if a is negative and b positive, -1 is106 // placed in r0.107#if defined(USE_THUMB_1)108 bhs 1f109 // Here if a and b have the same sign and absA < absB, the result is thus110 // b < 0 ? 1 : -1. Same if a and b have the opposite sign (ignoring Nan).111 movs r0, #1112 lsrs r1, #31113 bne LOCAL_LABEL(CHECK_NAN\@)114 negs r0, r0115 b LOCAL_LABEL(CHECK_NAN\@)1161:117#else118 it lo119 mvnlo r0, r1, asr #31120#endif121 122 // If a is greater in magnitude than b and both have the same sign, place123 // the sign of b in r0. Thus, if both are negative and a < b, -1 is placed124 // in r0, which is the desired result. Conversely, if both are positive125 // and a > b, zero is placed in r0.126#if defined(USE_THUMB_1)127 bls 1f128 // Here both have the same sign and absA > absB.129 movs r0, #1130 lsrs r1, #31131 beq LOCAL_LABEL(CHECK_NAN\@)132 negs r0, r01331:134#else135 it hi136 movhi r0, r1, asr #31137#endif138 139 // If you've been keeping track, at this point r0 contains -1 if a < b and140 // 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 value142 // 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 ne146 orrne r0, r0, #1147#endif148 149 // Finally, we need to deal with NaNs. If either argument is NaN, replace150 // the value in r0 with 1.151#if defined(USE_THUMB_1)152LOCAL_LABEL(CHECK_NAN\@):153 movs r6, #0xff154 lsls r6, #24155 cmp r2, r6156 bhi 1f157 cmp r3, r61581:159 bls 2f160 \handle_nan1612:162 pop {r6, pc}163#else164 cmp r2, #0xff000000165 ite ls166 cmpls r3, #0xff000000167 \handle_nan168 JMP(lr)169#endif170 .endm171 172@ int __eqsf2(float a, float b)173 174 .p2align 2175DEFINE_COMPILERRT_FUNCTION(__eqsf2)176 177 .macro __eqsf2_handle_nan178#if defined(USE_THUMB_1)179 movs r0, #1180#else181 movhi r0, #1182#endif183 .endm184 185COMPARESF2_FUNCTION_BODY __eqsf2_handle_nan186 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 compatibility195DEFINE_COMPILERRT_FUNCTION_ALIAS(__cmpsf2, __lesf2)196#endif197 198@ int __gtsf2(float a, float b)199 200 .p2align 2201DEFINE_COMPILERRT_FUNCTION(__gtsf2)202 203 .macro __gtsf2_handle_nan204#if defined(USE_THUMB_1)205 movs r0, #1206 negs r0, r0207#else208 movhi r0, #-1209#endif210 .endm211 212COMPARESF2_FUNCTION_BODY __gtsf2_handle_nan213 214END_COMPILERRT_FUNCTION(__gtsf2)215 216DEFINE_COMPILERRT_FUNCTION_ALIAS(__gesf2, __gtsf2)217 218@ int __unordsf2(float a, float b)219 220 .p2align 2221DEFINE_COMPILERRT_FUNCTION(__unordsf2)222 223#if defined(COMPILER_RT_ARMHF_TARGET)224 vmov r0, s0225 vmov r1, s1226#endif227 // Return 1 for NaN values, 0 otherwise.228 lsls r2, r0, #1229 lsls r3, r1, #1230 movs r0, #0231#if defined(USE_THUMB_1)232 movs r1, #0xff233 lsls r1, #24234 cmp r2, r1235 bhi 1f236 cmp r3, r12371:238 bls 2f239 movs r0, #12402:241#else242 cmp r2, #0xff000000243 ite ls244 cmpls r3, #0xff000000245 movhi r0, #1246#endif247 JMP(lr)248END_COMPILERRT_FUNCTION(__unordsf2)249 250#if defined(COMPILER_RT_ARMHF_TARGET)251DEFINE_COMPILERRT_FUNCTION(__aeabi_fcmpun)252 vmov s0, r0253 vmov s1, r1254 b SYMBOL_NAME(__unordsf2)255END_COMPILERRT_FUNCTION(__aeabi_fcmpun)256#else257DEFINE_AEABI_FUNCTION_ALIAS(__aeabi_fcmpun, __unordsf2)258#endif259 260NO_EXEC_STACK_DIRECTIVE261 262