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// GCC uses long (at least for x86_64) as the return type of the comparison 12// functions. We need to ensure that the return value is sign-extended in the 13// same way as GCC expects (since otherwise GCC-generated __builtin_isinf 14// returns true for finite 128-bit floating-point numbers). 15#ifdef __aarch64__ 16// AArch64 GCC overrides libgcc_cmp_return to use int instead of long. 17typedef int CMP_RESULT; 18#elif __SIZEOF_POINTER__ == 8 && __SIZEOF_LONG__ == 4 19// LLP64 ABIs use long long instead of long. 20typedef long long CMP_RESULT; 21#else 22// Otherwise the comparison functions return long. 23typedef long CMP_RESULT; 24#endif 25 26#if !defined(__clang__) && defined(__GNUC__) 27// GCC uses a special __libgcc_cmp_return__ mode to define the return type, so 28// check that we are ABI-compatible when compiling the builtins with GCC. 29typedef int GCC_CMP_RESULT __attribute__((__mode__(__libgcc_cmp_return__))); 30_Static_assert(sizeof(GCC_CMP_RESULT) == sizeof(CMP_RESULT), 31 "SOFTFP ABI not compatible with GCC"); 32#endif 33 34enum { 35 LE_LESS = -1, 36 LE_EQUAL = 0, 37 LE_GREATER = 1, 38 LE_UNORDERED = 1, 39}; 40 41static inline CMP_RESULT __leXf2__(fp_t a, fp_t b) { 42 const srep_t aInt = toRep(a); 43 const srep_t bInt = toRep(b); 44 const rep_t aAbs = aInt & absMask; 45 const rep_t bAbs = bInt & absMask; 46 47 // If either a or b is NaN, they are unordered. 48 if (aAbs > infRep || bAbs > infRep) 49 return LE_UNORDERED; 50 51 // If a and b are both zeros, they are equal. 52 if ((aAbs | bAbs) == 0) 53 return LE_EQUAL; 54 55 // If at least one of a and b is positive, we get the same result comparing 56 // a and b as signed integers as we would with a floating-point compare. 57 if ((aInt & bInt) >= 0) { 58 if (aInt < bInt) 59 return LE_LESS; 60 else if (aInt == bInt) 61 return LE_EQUAL; 62 else 63 return LE_GREATER; 64 } else { 65 // Otherwise, both are negative, so we need to flip the sense of the 66 // comparison to get the correct result. (This assumes a twos- or ones- 67 // complement integer representation; if integers are represented in a 68 // sign-magnitude representation, then this flip is incorrect). 69 if (aInt > bInt) 70 return LE_LESS; 71 else if (aInt == bInt) 72 return LE_EQUAL; 73 else 74 return LE_GREATER; 75 } 76} 77 78enum { 79 GE_LESS = -1, 80 GE_EQUAL = 0, 81 GE_GREATER = 1, 82 GE_UNORDERED = -1 // Note: different from LE_UNORDERED 83}; 84 85static inline CMP_RESULT __geXf2__(fp_t a, fp_t b) { 86 const srep_t aInt = toRep(a); 87 const srep_t bInt = toRep(b); 88 const rep_t aAbs = aInt & absMask; 89 const rep_t bAbs = bInt & absMask; 90 91 if (aAbs > infRep || bAbs > infRep) 92 return GE_UNORDERED; 93 if ((aAbs | bAbs) == 0) 94 return GE_EQUAL; 95 if ((aInt & bInt) >= 0) { 96 if (aInt < bInt) 97 return GE_LESS; 98 else if (aInt == bInt) 99 return GE_EQUAL; 100 else 101 return GE_GREATER; 102 } else { 103 if (aInt > bInt) 104 return GE_LESS; 105 else if (aInt == bInt) 106 return GE_EQUAL; 107 else 108 return GE_GREATER; 109 } 110} 111 112static inline CMP_RESULT __unordXf2__(fp_t a, fp_t b) { 113 const rep_t aAbs = toRep(a) & absMask; 114 const rep_t bAbs = toRep(b) & absMask; 115 return aAbs > infRep || bAbs > infRep; 116} 117