1 | #![allow (unreachable_code)] |
2 | |
3 | use crate::float::Float; |
4 | use crate::int::MinInt; |
5 | use crate::support::cfg_if; |
6 | |
7 | // Taken from LLVM config: |
8 | // https://github.com/llvm/llvm-project/blob/0cf3c437c18ed27d9663d87804a9a15ff6874af2/compiler-rt/lib/builtins/fp_compare_impl.inc#L11-L27 |
9 | cfg_if! { |
10 | if #[cfg(any(target_arch = "aarch64" , target_arch = "arm64ec" ))] { |
11 | // Aarch64 uses `int` rather than a pointer-sized value. |
12 | pub type CmpResult = i32; |
13 | } else if #[cfg(target_arch = "avr" )] { |
14 | // AVR uses a single byte. |
15 | pub type CmpResult = i8; |
16 | } else { |
17 | // In compiler-rt, LLP64 ABIs use `long long` and everything else uses `long`. In effect, |
18 | // this means the return value is always pointer-sized. |
19 | pub type CmpResult = isize; |
20 | } |
21 | } |
22 | |
23 | #[derive (Clone, Copy)] |
24 | enum Result { |
25 | Less, |
26 | Equal, |
27 | Greater, |
28 | Unordered, |
29 | } |
30 | |
31 | impl Result { |
32 | fn to_le_abi(self) -> CmpResult { |
33 | match self { |
34 | Result::Less => -1, |
35 | Result::Equal => 0, |
36 | Result::Greater => 1, |
37 | Result::Unordered => 1, |
38 | } |
39 | } |
40 | |
41 | fn to_ge_abi(self) -> CmpResult { |
42 | match self { |
43 | Result::Less => -1, |
44 | Result::Equal => 0, |
45 | Result::Greater => 1, |
46 | Result::Unordered => -1, |
47 | } |
48 | } |
49 | } |
50 | |
51 | fn cmp<F: Float>(a: F, b: F) -> Result { |
52 | let one = F::Int::ONE; |
53 | let zero = F::Int::ZERO; |
54 | let szero = F::SignedInt::ZERO; |
55 | |
56 | let sign_bit = F::SIGN_MASK as F::Int; |
57 | let abs_mask = sign_bit - one; |
58 | let exponent_mask = F::EXP_MASK; |
59 | let inf_rep = exponent_mask; |
60 | |
61 | let a_rep = a.to_bits(); |
62 | let b_rep = b.to_bits(); |
63 | let a_abs = a_rep & abs_mask; |
64 | let b_abs = b_rep & abs_mask; |
65 | |
66 | // If either a or b is NaN, they are unordered. |
67 | if a_abs > inf_rep || b_abs > inf_rep { |
68 | return Result::Unordered; |
69 | } |
70 | |
71 | // If a and b are both zeros, they are equal. |
72 | if a_abs | b_abs == zero { |
73 | return Result::Equal; |
74 | } |
75 | |
76 | let a_srep = a.to_bits_signed(); |
77 | let b_srep = b.to_bits_signed(); |
78 | |
79 | // If at least one of a and b is positive, we get the same result comparing |
80 | // a and b as signed integers as we would with a fp_ting-point compare. |
81 | if a_srep & b_srep >= szero { |
82 | if a_srep < b_srep { |
83 | Result::Less |
84 | } else if a_srep == b_srep { |
85 | Result::Equal |
86 | } else { |
87 | Result::Greater |
88 | } |
89 | // Otherwise, both are negative, so we need to flip the sense of the |
90 | // comparison to get the correct result. (This assumes a twos- or ones- |
91 | // complement integer representation; if integers are represented in a |
92 | // sign-magnitude representation, then this flip is incorrect). |
93 | } else if a_srep > b_srep { |
94 | Result::Less |
95 | } else if a_srep == b_srep { |
96 | Result::Equal |
97 | } else { |
98 | Result::Greater |
99 | } |
100 | } |
101 | |
102 | fn unord<F: Float>(a: F, b: F) -> bool { |
103 | let one: ::Int = F::Int::ONE; |
104 | |
105 | let sign_bit: ::Int = F::SIGN_MASK as F::Int; |
106 | let abs_mask: ::Int = sign_bit - one; |
107 | let exponent_mask: ::Int = F::EXP_MASK; |
108 | let inf_rep: ::Int = exponent_mask; |
109 | |
110 | let a_rep: ::Int = a.to_bits(); |
111 | let b_rep: ::Int = b.to_bits(); |
112 | let a_abs: ::Int = a_rep & abs_mask; |
113 | let b_abs: ::Int = b_rep & abs_mask; |
114 | |
115 | a_abs > inf_rep || b_abs > inf_rep |
116 | } |
117 | |
118 | intrinsics! { |
119 | pub extern "C" fn __lesf2(a: f32, b: f32) -> crate::float::cmp::CmpResult { |
120 | cmp(a, b).to_le_abi() |
121 | } |
122 | |
123 | pub extern "C" fn __gesf2(a: f32, b: f32) -> crate::float::cmp::CmpResult { |
124 | cmp(a, b).to_ge_abi() |
125 | } |
126 | |
127 | #[arm_aeabi_alias = __aeabi_fcmpun] |
128 | pub extern "C" fn __unordsf2(a: f32, b: f32) -> crate::float::cmp::CmpResult { |
129 | unord(a, b) as crate::float::cmp::CmpResult |
130 | } |
131 | |
132 | pub extern "C" fn __eqsf2(a: f32, b: f32) -> crate::float::cmp::CmpResult { |
133 | cmp(a, b).to_le_abi() |
134 | } |
135 | |
136 | pub extern "C" fn __ltsf2(a: f32, b: f32) -> crate::float::cmp::CmpResult { |
137 | cmp(a, b).to_le_abi() |
138 | } |
139 | |
140 | pub extern "C" fn __nesf2(a: f32, b: f32) -> crate::float::cmp::CmpResult { |
141 | cmp(a, b).to_le_abi() |
142 | } |
143 | |
144 | pub extern "C" fn __gtsf2(a: f32, b: f32) -> crate::float::cmp::CmpResult { |
145 | cmp(a, b).to_ge_abi() |
146 | } |
147 | |
148 | pub extern "C" fn __ledf2(a: f64, b: f64) -> crate::float::cmp::CmpResult { |
149 | cmp(a, b).to_le_abi() |
150 | } |
151 | |
152 | pub extern "C" fn __gedf2(a: f64, b: f64) -> crate::float::cmp::CmpResult { |
153 | cmp(a, b).to_ge_abi() |
154 | } |
155 | |
156 | #[arm_aeabi_alias = __aeabi_dcmpun] |
157 | pub extern "C" fn __unorddf2(a: f64, b: f64) -> crate::float::cmp::CmpResult { |
158 | unord(a, b) as crate::float::cmp::CmpResult |
159 | } |
160 | |
161 | pub extern "C" fn __eqdf2(a: f64, b: f64) -> crate::float::cmp::CmpResult { |
162 | cmp(a, b).to_le_abi() |
163 | } |
164 | |
165 | pub extern "C" fn __ltdf2(a: f64, b: f64) -> crate::float::cmp::CmpResult { |
166 | cmp(a, b).to_le_abi() |
167 | } |
168 | |
169 | pub extern "C" fn __nedf2(a: f64, b: f64) -> crate::float::cmp::CmpResult { |
170 | cmp(a, b).to_le_abi() |
171 | } |
172 | |
173 | pub extern "C" fn __gtdf2(a: f64, b: f64) -> crate::float::cmp::CmpResult { |
174 | cmp(a, b).to_ge_abi() |
175 | } |
176 | } |
177 | |
178 | #[cfg (f128_enabled)] |
179 | intrinsics! { |
180 | #[ppc_alias = __lekf2] |
181 | pub extern "C" fn __letf2(a: f128, b: f128) -> crate::float::cmp::CmpResult { |
182 | cmp(a, b).to_le_abi() |
183 | } |
184 | |
185 | #[ppc_alias = __gekf2] |
186 | pub extern "C" fn __getf2(a: f128, b: f128) -> crate::float::cmp::CmpResult { |
187 | cmp(a, b).to_ge_abi() |
188 | } |
189 | |
190 | #[ppc_alias = __unordkf2] |
191 | pub extern "C" fn __unordtf2(a: f128, b: f128) -> crate::float::cmp::CmpResult { |
192 | unord(a, b) as crate::float::cmp::CmpResult |
193 | } |
194 | |
195 | #[ppc_alias = __eqkf2] |
196 | pub extern "C" fn __eqtf2(a: f128, b: f128) -> crate::float::cmp::CmpResult { |
197 | cmp(a, b).to_le_abi() |
198 | } |
199 | |
200 | #[ppc_alias = __ltkf2] |
201 | pub extern "C" fn __lttf2(a: f128, b: f128) -> crate::float::cmp::CmpResult { |
202 | cmp(a, b).to_le_abi() |
203 | } |
204 | |
205 | #[ppc_alias = __nekf2] |
206 | pub extern "C" fn __netf2(a: f128, b: f128) -> crate::float::cmp::CmpResult { |
207 | cmp(a, b).to_le_abi() |
208 | } |
209 | |
210 | #[ppc_alias = __gtkf2] |
211 | pub extern "C" fn __gttf2(a: f128, b: f128) -> crate::float::cmp::CmpResult { |
212 | cmp(a, b).to_ge_abi() |
213 | } |
214 | } |
215 | |
216 | #[cfg (target_arch = "arm" )] |
217 | intrinsics! { |
218 | pub extern "aapcs" fn __aeabi_fcmple(a: f32, b: f32) -> i32 { |
219 | (__lesf2(a, b) <= 0) as i32 |
220 | } |
221 | |
222 | pub extern "aapcs" fn __aeabi_fcmpge(a: f32, b: f32) -> i32 { |
223 | (__gesf2(a, b) >= 0) as i32 |
224 | } |
225 | |
226 | pub extern "aapcs" fn __aeabi_fcmpeq(a: f32, b: f32) -> i32 { |
227 | (__eqsf2(a, b) == 0) as i32 |
228 | } |
229 | |
230 | pub extern "aapcs" fn __aeabi_fcmplt(a: f32, b: f32) -> i32 { |
231 | (__ltsf2(a, b) < 0) as i32 |
232 | } |
233 | |
234 | pub extern "aapcs" fn __aeabi_fcmpgt(a: f32, b: f32) -> i32 { |
235 | (__gtsf2(a, b) > 0) as i32 |
236 | } |
237 | |
238 | pub extern "aapcs" fn __aeabi_dcmple(a: f64, b: f64) -> i32 { |
239 | (__ledf2(a, b) <= 0) as i32 |
240 | } |
241 | |
242 | pub extern "aapcs" fn __aeabi_dcmpge(a: f64, b: f64) -> i32 { |
243 | (__gedf2(a, b) >= 0) as i32 |
244 | } |
245 | |
246 | pub extern "aapcs" fn __aeabi_dcmpeq(a: f64, b: f64) -> i32 { |
247 | (__eqdf2(a, b) == 0) as i32 |
248 | } |
249 | |
250 | pub extern "aapcs" fn __aeabi_dcmplt(a: f64, b: f64) -> i32 { |
251 | (__ltdf2(a, b) < 0) as i32 |
252 | } |
253 | |
254 | pub extern "aapcs" fn __aeabi_dcmpgt(a: f64, b: f64) -> i32 { |
255 | (__gtdf2(a, b) > 0) as i32 |
256 | } |
257 | } |
258 | |