fp_compare_impl.inc (4582B)
1 //===-- lib/fp_compare_impl.inc - Floating-point comparison -------*- C -*-===// 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 #include "fp_lib.h" 10 11 // CMP_RESULT and the LE_*/GE_* sentinels are precision-independent; emit 12 // them once per TU. The static inline comparators (__leXf2__ etc.) are 13 // per-precision and gated below. 14 #ifndef FP_COMPARE_COMMON_EMITTED 15 #define FP_COMPARE_COMMON_EMITTED 16 17 // GCC uses long (at least for x86_64) as the return type of the comparison 18 // functions. We need to ensure that the return value is sign-extended in the 19 // same way as GCC expects (since otherwise GCC-generated __builtin_isinf 20 // returns true for finite 128-bit floating-point numbers). 21 #ifdef __aarch64__ 22 // AArch64 GCC overrides libgcc_cmp_return to use int instead of long. 23 typedef int CMP_RESULT; 24 #elif __SIZEOF_POINTER__ == 8 && __SIZEOF_LONG__ == 4 25 // LLP64 ABIs use long long instead of long. 26 typedef long long CMP_RESULT; 27 #elif __AVR__ 28 // AVR uses a single byte for the return value. 29 typedef char CMP_RESULT; 30 #else 31 // Otherwise the comparison functions return long. 32 typedef long CMP_RESULT; 33 #endif 34 35 #if !defined(__clang__) && defined(__GNUC__) && !defined(__kit__) 36 // GCC uses a special __libgcc_cmp_return__ mode to define the return type, so 37 // check that we are ABI-compatible when compiling the builtins with GCC. 38 typedef int GCC_CMP_RESULT __attribute__((__mode__(__libgcc_cmp_return__))); 39 _Static_assert(sizeof(GCC_CMP_RESULT) == sizeof(CMP_RESULT), 40 "SOFTFP ABI not compatible with GCC"); 41 #endif 42 43 enum { 44 LE_LESS = -1, 45 LE_EQUAL = 0, 46 LE_GREATER = 1, 47 LE_UNORDERED = 1, 48 }; 49 50 enum { 51 GE_LESS = -1, 52 GE_EQUAL = 0, 53 GE_GREATER = 1, 54 GE_UNORDERED = -1 // Note: different from LE_UNORDERED 55 }; 56 57 #endif // FP_COMPARE_COMMON_EMITTED 58 59 // Bare-name aliases (re-set every inclusion, suffix-renamed via fp_lib). 60 #define __leXf2__ _FP_NAME(__leXf2__) 61 #define __geXf2__ _FP_NAME(__geXf2__) 62 #define __unordXf2__ _FP_NAME(__unordXf2__) 63 64 #if defined SINGLE_PRECISION && !defined FP_COMPARE_SF_EMITTED 65 #define FP_COMPARE_SF_EMITTED 66 #define _FP_COMPARE_EMIT 1 67 #elif defined DOUBLE_PRECISION && !defined FP_COMPARE_DF_EMITTED 68 #define FP_COMPARE_DF_EMITTED 69 #define _FP_COMPARE_EMIT 1 70 #elif defined QUAD_PRECISION && !defined FP_COMPARE_TF_EMITTED 71 #define FP_COMPARE_TF_EMITTED 72 #define _FP_COMPARE_EMIT 1 73 #endif 74 75 #ifdef _FP_COMPARE_EMIT 76 #undef _FP_COMPARE_EMIT 77 78 static inline CMP_RESULT __leXf2__(fp_t a, fp_t b) { 79 const srep_t aInt = toRep(a); 80 const srep_t bInt = toRep(b); 81 const rep_t aAbs = aInt & absMask; 82 const rep_t bAbs = bInt & absMask; 83 84 // If either a or b is NaN, they are unordered. 85 if (aAbs > infRep || bAbs > infRep) 86 return LE_UNORDERED; 87 88 // If a and b are both zeros, they are equal. 89 if ((aAbs | bAbs) == 0) 90 return LE_EQUAL; 91 92 // If at least one of a and b is positive, we get the same result comparing 93 // a and b as signed integers as we would with a floating-point compare. 94 if ((aInt & bInt) >= 0) { 95 if (aInt < bInt) 96 return LE_LESS; 97 else if (aInt == bInt) 98 return LE_EQUAL; 99 else 100 return LE_GREATER; 101 } else { 102 // Otherwise, both are negative, so we need to flip the sense of the 103 // comparison to get the correct result. (This assumes a twos- or ones- 104 // complement integer representation; if integers are represented in a 105 // sign-magnitude representation, then this flip is incorrect). 106 if (aInt > bInt) 107 return LE_LESS; 108 else if (aInt == bInt) 109 return LE_EQUAL; 110 else 111 return LE_GREATER; 112 } 113 } 114 115 static inline CMP_RESULT __geXf2__(fp_t a, fp_t b) { 116 const srep_t aInt = toRep(a); 117 const srep_t bInt = toRep(b); 118 const rep_t aAbs = aInt & absMask; 119 const rep_t bAbs = bInt & absMask; 120 121 if (aAbs > infRep || bAbs > infRep) 122 return GE_UNORDERED; 123 if ((aAbs | bAbs) == 0) 124 return GE_EQUAL; 125 if ((aInt & bInt) >= 0) { 126 if (aInt < bInt) 127 return GE_LESS; 128 else if (aInt == bInt) 129 return GE_EQUAL; 130 else 131 return GE_GREATER; 132 } else { 133 if (aInt > bInt) 134 return GE_LESS; 135 else if (aInt == bInt) 136 return GE_EQUAL; 137 else 138 return GE_GREATER; 139 } 140 } 141 142 static inline CMP_RESULT __unordXf2__(fp_t a, fp_t b) { 143 const rep_t aAbs = toRep(a) & absMask; 144 const rep_t bAbs = toRep(b) & absMask; 145 return aAbs > infRep || bAbs > infRep; 146 } 147 148 #endif // _FP_COMPARE_EMIT