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