compiler_builtins/float/
cmp.rs

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