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