diff --git a/compiler-rt/lib/builtins/comparedf2.c b/compiler-rt/lib/builtins/comparedf2.c --- a/compiler-rt/lib/builtins/comparedf2.c +++ b/compiler-rt/lib/builtins/comparedf2.c @@ -39,46 +39,10 @@ #define DOUBLE_PRECISION #include "fp_lib.h" -enum LE_RESULT { LE_LESS = -1, LE_EQUAL = 0, LE_GREATER = 1, LE_UNORDERED = 1 }; +#include "fp_compare_impl.inc" -COMPILER_RT_ABI enum LE_RESULT __ledf2(fp_t a, fp_t b) { - - const srep_t aInt = toRep(a); - const srep_t bInt = toRep(b); - const rep_t aAbs = aInt & absMask; - const rep_t bAbs = bInt & absMask; - - // If either a or b is NaN, they are unordered. - if (aAbs > infRep || bAbs > infRep) - return LE_UNORDERED; - - // If a and b are both zeros, they are equal. - if ((aAbs | bAbs) == 0) - return LE_EQUAL; - - // If at least one of a and b is positive, we get the same result comparing - // a and b as signed integers as we would with a floating-point compare. - if ((aInt & bInt) >= 0) { - if (aInt < bInt) - return LE_LESS; - else if (aInt == bInt) - return LE_EQUAL; - else - return LE_GREATER; - } - - // Otherwise, both are negative, so we need to flip the sense of the - // comparison to get the correct result. (This assumes a twos- or ones- - // complement integer representation; if integers are represented in a - // sign-magnitude representation, then this flip is incorrect). - else { - if (aInt > bInt) - return LE_LESS; - else if (aInt == bInt) - return LE_EQUAL; - else - return LE_GREATER; - } +COMPILER_RT_ABI CMP_RESULT __ledf2(fp_t a, fp_t b) { + return __leXf2__(a, b); } #if defined(__ELF__) @@ -89,48 +53,16 @@ COMPILER_RT_ALIAS(__ledf2, __ltdf2) COMPILER_RT_ALIAS(__ledf2, __nedf2) -enum GE_RESULT { - GE_LESS = -1, - GE_EQUAL = 0, - GE_GREATER = 1, - GE_UNORDERED = -1 // Note: different from LE_UNORDERED -}; - -COMPILER_RT_ABI enum GE_RESULT __gedf2(fp_t a, fp_t b) { - - const srep_t aInt = toRep(a); - const srep_t bInt = toRep(b); - const rep_t aAbs = aInt & absMask; - const rep_t bAbs = bInt & absMask; - - if (aAbs > infRep || bAbs > infRep) - return GE_UNORDERED; - if ((aAbs | bAbs) == 0) - return GE_EQUAL; - if ((aInt & bInt) >= 0) { - if (aInt < bInt) - return GE_LESS; - else if (aInt == bInt) - return GE_EQUAL; - else - return GE_GREATER; - } else { - if (aInt > bInt) - return GE_LESS; - else if (aInt == bInt) - return GE_EQUAL; - else - return GE_GREATER; - } +COMPILER_RT_ABI CMP_RESULT __gedf2(fp_t a, fp_t b) { + return __geXf2__(a, b); } COMPILER_RT_ALIAS(__gedf2, __gtdf2) -COMPILER_RT_ABI int -__unorddf2(fp_t a, fp_t b) { - const rep_t aAbs = toRep(a) & absMask; - const rep_t bAbs = toRep(b) & absMask; - return aAbs > infRep || bAbs > infRep; +COMPILER_RT_ABI CMP_RESULT __unorddf2(fp_t a, fp_t b) { + const rep_t aAbs = toRep(a) & absMask; + const rep_t bAbs = toRep(b) & absMask; + return aAbs > infRep || bAbs > infRep; } #if defined(__ARM_EABI__) diff --git a/compiler-rt/lib/builtins/comparesf2.c b/compiler-rt/lib/builtins/comparesf2.c --- a/compiler-rt/lib/builtins/comparesf2.c +++ b/compiler-rt/lib/builtins/comparesf2.c @@ -39,46 +39,10 @@ #define SINGLE_PRECISION #include "fp_lib.h" -enum LE_RESULT { LE_LESS = -1, LE_EQUAL = 0, LE_GREATER = 1, LE_UNORDERED = 1 }; +#include "fp_compare_impl.inc" -COMPILER_RT_ABI enum LE_RESULT __lesf2(fp_t a, fp_t b) { - - const srep_t aInt = toRep(a); - const srep_t bInt = toRep(b); - const rep_t aAbs = aInt & absMask; - const rep_t bAbs = bInt & absMask; - - // If either a or b is NaN, they are unordered. - if (aAbs > infRep || bAbs > infRep) - return LE_UNORDERED; - - // If a and b are both zeros, they are equal. - if ((aAbs | bAbs) == 0) - return LE_EQUAL; - - // If at least one of a and b is positive, we get the same result comparing - // a and b as signed integers as we would with a fp_ting-point compare. - if ((aInt & bInt) >= 0) { - if (aInt < bInt) - return LE_LESS; - else if (aInt == bInt) - return LE_EQUAL; - else - return LE_GREATER; - } - - // Otherwise, both are negative, so we need to flip the sense of the - // comparison to get the correct result. (This assumes a twos- or ones- - // complement integer representation; if integers are represented in a - // sign-magnitude representation, then this flip is incorrect). - else { - if (aInt > bInt) - return LE_LESS; - else if (aInt == bInt) - return LE_EQUAL; - else - return LE_GREATER; - } +COMPILER_RT_ABI CMP_RESULT __lesf2(fp_t a, fp_t b) { + return __leXf2__(a, b); } #if defined(__ELF__) @@ -89,48 +53,16 @@ COMPILER_RT_ALIAS(__lesf2, __ltsf2) COMPILER_RT_ALIAS(__lesf2, __nesf2) -enum GE_RESULT { - GE_LESS = -1, - GE_EQUAL = 0, - GE_GREATER = 1, - GE_UNORDERED = -1 // Note: different from LE_UNORDERED -}; - -COMPILER_RT_ABI enum GE_RESULT __gesf2(fp_t a, fp_t b) { - - const srep_t aInt = toRep(a); - const srep_t bInt = toRep(b); - const rep_t aAbs = aInt & absMask; - const rep_t bAbs = bInt & absMask; - - if (aAbs > infRep || bAbs > infRep) - return GE_UNORDERED; - if ((aAbs | bAbs) == 0) - return GE_EQUAL; - if ((aInt & bInt) >= 0) { - if (aInt < bInt) - return GE_LESS; - else if (aInt == bInt) - return GE_EQUAL; - else - return GE_GREATER; - } else { - if (aInt > bInt) - return GE_LESS; - else if (aInt == bInt) - return GE_EQUAL; - else - return GE_GREATER; - } +COMPILER_RT_ABI CMP_RESULT __gesf2(fp_t a, fp_t b) { + return __geXf2__(a, b); } COMPILER_RT_ALIAS(__gesf2, __gtsf2) -COMPILER_RT_ABI int -__unordsf2(fp_t a, fp_t b) { - const rep_t aAbs = toRep(a) & absMask; - const rep_t bAbs = toRep(b) & absMask; - return aAbs > infRep || bAbs > infRep; +COMPILER_RT_ABI CMP_RESULT __unordsf2(fp_t a, fp_t b) { + const rep_t aAbs = toRep(a) & absMask; + const rep_t bAbs = toRep(b) & absMask; + return aAbs > infRep || bAbs > infRep; } #if defined(__ARM_EABI__) diff --git a/compiler-rt/lib/builtins/comparetf2.c b/compiler-rt/lib/builtins/comparetf2.c --- a/compiler-rt/lib/builtins/comparetf2.c +++ b/compiler-rt/lib/builtins/comparetf2.c @@ -40,44 +40,10 @@ #include "fp_lib.h" #if defined(CRT_HAS_128BIT) && defined(CRT_LDBL_128BIT) -enum LE_RESULT { LE_LESS = -1, LE_EQUAL = 0, LE_GREATER = 1, LE_UNORDERED = 1 }; +#include "fp_compare_impl.inc" -COMPILER_RT_ABI enum LE_RESULT __letf2(fp_t a, fp_t b) { - - const srep_t aInt = toRep(a); - const srep_t bInt = toRep(b); - const rep_t aAbs = aInt & absMask; - const rep_t bAbs = bInt & absMask; - - // If either a or b is NaN, they are unordered. - if (aAbs > infRep || bAbs > infRep) - return LE_UNORDERED; - - // If a and b are both zeros, they are equal. - if ((aAbs | bAbs) == 0) - return LE_EQUAL; - - // If at least one of a and b is positive, we get the same result comparing - // a and b as signed integers as we would with a floating-point compare. - if ((aInt & bInt) >= 0) { - if (aInt < bInt) - return LE_LESS; - else if (aInt == bInt) - return LE_EQUAL; - else - return LE_GREATER; - } else { - // Otherwise, both are negative, so we need to flip the sense of the - // comparison to get the correct result. (This assumes a twos- or ones- - // complement integer representation; if integers are represented in a - // sign-magnitude representation, then this flip is incorrect). - if (aInt > bInt) - return LE_LESS; - else if (aInt == bInt) - return LE_EQUAL; - else - return LE_GREATER; - } +COMPILER_RT_ABI CMP_RESULT __letf2(fp_t a, fp_t b) { + return __leXf2__(a, b); } #if defined(__ELF__) @@ -88,44 +54,13 @@ COMPILER_RT_ALIAS(__letf2, __lttf2) COMPILER_RT_ALIAS(__letf2, __netf2) -enum GE_RESULT { - GE_LESS = -1, - GE_EQUAL = 0, - GE_GREATER = 1, - GE_UNORDERED = -1 // Note: different from LE_UNORDERED -}; - -COMPILER_RT_ABI enum GE_RESULT __getf2(fp_t a, fp_t b) { - - const srep_t aInt = toRep(a); - const srep_t bInt = toRep(b); - const rep_t aAbs = aInt & absMask; - const rep_t bAbs = bInt & absMask; - - if (aAbs > infRep || bAbs > infRep) - return GE_UNORDERED; - if ((aAbs | bAbs) == 0) - return GE_EQUAL; - if ((aInt & bInt) >= 0) { - if (aInt < bInt) - return GE_LESS; - else if (aInt == bInt) - return GE_EQUAL; - else - return GE_GREATER; - } else { - if (aInt > bInt) - return GE_LESS; - else if (aInt == bInt) - return GE_EQUAL; - else - return GE_GREATER; - } +COMPILER_RT_ABI CMP_RESULT __getf2(fp_t a, fp_t b) { + return __geXf2__(a, b); } COMPILER_RT_ALIAS(__getf2, __gttf2) -COMPILER_RT_ABI int __unordtf2(fp_t a, fp_t b) { +COMPILER_RT_ABI CMP_RESULT __unordtf2(fp_t a, fp_t b) { const rep_t aAbs = toRep(a) & absMask; const rep_t bAbs = toRep(b) & absMask; return aAbs > infRep || bAbs > infRep; diff --git a/compiler-rt/lib/builtins/comparetf2.c b/compiler-rt/lib/builtins/fp_compare_impl.inc copy from compiler-rt/lib/builtins/comparetf2.c copy to compiler-rt/lib/builtins/fp_compare_impl.inc --- a/compiler-rt/lib/builtins/comparetf2.c +++ b/compiler-rt/lib/builtins/fp_compare_impl.inc @@ -1,49 +1,29 @@ -//===-- lib/comparetf2.c - Quad-precision comparisons -------------*- C -*-===// +//===-- lib/fp_compare_impl.inc - Floating-point comparison -------*- C -*-===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// -// -// // This file implements the following soft-float comparison routines: -// -// __eqtf2 __getf2 __unordtf2 -// __letf2 __gttf2 -// __lttf2 -// __netf2 -// -// The semantics of the routines grouped in each column are identical, so there -// is a single implementation for each, and wrappers to provide the other names. -// -// The main routines behave as follows: -// -// __letf2(a,b) returns -1 if a < b -// 0 if a == b -// 1 if a > b -// 1 if either a or b is NaN -// -// __getf2(a,b) returns -1 if a < b -// 0 if a == b -// 1 if a > b -// -1 if either a or b is NaN -// -// __unordtf2(a,b) returns 0 if both a and b are numbers -// 1 if either a or b is NaN -// -// Note that __letf2( ) and __getf2( ) are identical except in their handling of -// NaN values. -// -//===----------------------------------------------------------------------===// -#define QUAD_PRECISION #include "fp_lib.h" -#if defined(CRT_HAS_128BIT) && defined(CRT_LDBL_128BIT) -enum LE_RESULT { LE_LESS = -1, LE_EQUAL = 0, LE_GREATER = 1, LE_UNORDERED = 1 }; +// GCC uses long (at least for x86_64) as the return type of the comparison +// functions. We need to ensure that the return value is sign-extended in the +// same way as GCC expects (since otherwise GCC-generated __builtin_isinf +// returns true for finite 128-bit floating-point numbers). +typedef long CMP_RESULT; +#if !defined(__clang__) && defined(__GNUC__) +// GCC uses a special __libgcc_cmp_return__ mode to define the return type, so +// sanity-check that we are ABI-compatible when compiling with GCC. +typedef int __gcc_CMPtype __attribute__((mode(__libgcc_cmp_return__))); +_Static_assert(sizeof(__gcc_CMPtype) == sizeof(CMP_RESULT), + "SOFTFP ABI not compatible with GCC"); +#endif -COMPILER_RT_ABI enum LE_RESULT __letf2(fp_t a, fp_t b) { +enum _LE_RESULT { LE_LESS = -1, LE_EQUAL = 0, LE_GREATER = 1, LE_UNORDERED = 1 }; +static inline enum _LE_RESULT __leXf2__(fp_t a, fp_t b) { const srep_t aInt = toRep(a); const srep_t bInt = toRep(b); const rep_t aAbs = aInt & absMask; @@ -80,23 +60,14 @@ } } -#if defined(__ELF__) -// Alias for libgcc compatibility -COMPILER_RT_ALIAS(__letf2, __cmptf2) -#endif -COMPILER_RT_ALIAS(__letf2, __eqtf2) -COMPILER_RT_ALIAS(__letf2, __lttf2) -COMPILER_RT_ALIAS(__letf2, __netf2) - -enum GE_RESULT { +enum _GE_RESULT { GE_LESS = -1, GE_EQUAL = 0, GE_GREATER = 1, GE_UNORDERED = -1 // Note: different from LE_UNORDERED }; -COMPILER_RT_ABI enum GE_RESULT __getf2(fp_t a, fp_t b) { - +static inline enum _GE_RESULT __geXf2__(fp_t a, fp_t b) { const srep_t aInt = toRep(a); const srep_t bInt = toRep(b); const rep_t aAbs = aInt & absMask; @@ -122,13 +93,3 @@ return GE_GREATER; } } - -COMPILER_RT_ALIAS(__getf2, __gttf2) - -COMPILER_RT_ABI int __unordtf2(fp_t a, fp_t b) { - const rep_t aAbs = toRep(a) & absMask; - const rep_t bAbs = toRep(b) & absMask; - return aAbs > infRep || bAbs > infRep; -} - -#endif