kit

kit
git clone https://git.ryansepassi.com/git/kit.git
Log | Files | Refs | README

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