fp_compare_impl.inc 3.5 KB

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