Skip to main content

cranelift_codegen_shared/
condcodes.rs

1//! Condition codes for the Cranelift code generator.
2//!
3//! A condition code here is an enumerated type that determined how to compare two numbers. There
4//! are different rules for comparing integers and floating point numbers, so they use different
5//! condition codes.
6
7use core::fmt::{self, Display, Formatter};
8use core::str::FromStr;
9
10/// Common traits of condition codes.
11pub trait CondCode: Copy {
12    /// Get the inverse condition code of `self`.
13    ///
14    /// The inverse condition code produces the opposite result for all comparisons.
15    /// That is, `cmp CC, x, y` is true if and only if `cmp CC.inverse(), x, y` is false.
16    #[must_use]
17    fn inverse(self) -> Self;
18
19    /// Get the reversed condition code for `self`.
20    ///
21    /// The reversed condition code produces the same result as swapping `x` and `y` in the
22    /// comparison. That is, `cmp CC, x, y` is the same as `cmp CC.reverse(), y, x`.
23    #[must_use]
24    fn reverse(self) -> Self;
25}
26
27/// Condition code for comparing integers.
28///
29/// This condition code is used by the `icmp` instruction to compare integer values. There are
30/// separate codes for comparing the integers as signed or unsigned numbers where it makes a
31/// difference.
32#[derive(Clone, Copy, PartialEq, Eq, Debug, Hash)]
33pub enum IntCC {
34    /// `==`.
35    Equal,
36    /// `!=`.
37    NotEqual,
38    /// Signed `<`.
39    SignedLessThan,
40    /// Signed `>=`.
41    SignedGreaterThanOrEqual,
42    /// Signed `>`.
43    SignedGreaterThan,
44    /// Signed `<=`.
45    SignedLessThanOrEqual,
46    /// Unsigned `<`.
47    UnsignedLessThan,
48    /// Unsigned `>=`.
49    UnsignedGreaterThanOrEqual,
50    /// Unsigned `>`.
51    UnsignedGreaterThan,
52    /// Unsigned `<=`.
53    UnsignedLessThanOrEqual,
54    /// Signed Overflow.
55    Overflow,
56    /// Signed No Overflow.
57    NotOverflow,
58}
59
60impl CondCode for IntCC {
61    fn inverse(self) -> Self {
62        use self::IntCC::*;
63        match self {
64            Equal => NotEqual,
65            NotEqual => Equal,
66            SignedLessThan => SignedGreaterThanOrEqual,
67            SignedGreaterThanOrEqual => SignedLessThan,
68            SignedGreaterThan => SignedLessThanOrEqual,
69            SignedLessThanOrEqual => SignedGreaterThan,
70            UnsignedLessThan => UnsignedGreaterThanOrEqual,
71            UnsignedGreaterThanOrEqual => UnsignedLessThan,
72            UnsignedGreaterThan => UnsignedLessThanOrEqual,
73            UnsignedLessThanOrEqual => UnsignedGreaterThan,
74            Overflow => NotOverflow,
75            NotOverflow => Overflow,
76        }
77    }
78
79    fn reverse(self) -> Self {
80        use self::IntCC::*;
81        match self {
82            Equal => Equal,
83            NotEqual => NotEqual,
84            SignedGreaterThan => SignedLessThan,
85            SignedGreaterThanOrEqual => SignedLessThanOrEqual,
86            SignedLessThan => SignedGreaterThan,
87            SignedLessThanOrEqual => SignedGreaterThanOrEqual,
88            UnsignedGreaterThan => UnsignedLessThan,
89            UnsignedGreaterThanOrEqual => UnsignedLessThanOrEqual,
90            UnsignedLessThan => UnsignedGreaterThan,
91            UnsignedLessThanOrEqual => UnsignedGreaterThanOrEqual,
92            Overflow => Overflow,
93            NotOverflow => NotOverflow,
94        }
95    }
96}
97
98impl IntCC {
99    /// Get the corresponding IntCC with the equal component removed.
100    /// For conditions without a zero component, this is a no-op.
101    pub fn without_equal(self) -> Self {
102        use self::IntCC::*;
103        match self {
104            SignedGreaterThan | SignedGreaterThanOrEqual => SignedGreaterThan,
105            SignedLessThan | SignedLessThanOrEqual => SignedLessThan,
106            UnsignedGreaterThan | UnsignedGreaterThanOrEqual => UnsignedGreaterThan,
107            UnsignedLessThan | UnsignedLessThanOrEqual => UnsignedLessThan,
108            _ => self,
109        }
110    }
111
112    /// Get the corresponding IntCC with the signed component removed.
113    /// For conditions without a signed component, this is a no-op.
114    pub fn unsigned(self) -> Self {
115        use self::IntCC::*;
116        match self {
117            SignedGreaterThan | UnsignedGreaterThan => UnsignedGreaterThan,
118            SignedGreaterThanOrEqual | UnsignedGreaterThanOrEqual => UnsignedGreaterThanOrEqual,
119            SignedLessThan | UnsignedLessThan => UnsignedLessThan,
120            SignedLessThanOrEqual | UnsignedLessThanOrEqual => UnsignedLessThanOrEqual,
121            _ => self,
122        }
123    }
124
125    /// Get the corresponding string condition code for the IntCC object.
126    pub fn to_static_str(self) -> &'static str {
127        use self::IntCC::*;
128        match self {
129            Equal => "eq",
130            NotEqual => "ne",
131            SignedGreaterThan => "sgt",
132            SignedGreaterThanOrEqual => "sge",
133            SignedLessThan => "slt",
134            SignedLessThanOrEqual => "sle",
135            UnsignedGreaterThan => "ugt",
136            UnsignedGreaterThanOrEqual => "uge",
137            UnsignedLessThan => "ult",
138            UnsignedLessThanOrEqual => "ule",
139            Overflow => "of",
140            NotOverflow => "nof",
141        }
142    }
143}
144
145impl Display for IntCC {
146    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
147        f.write_str(self.to_static_str())
148    }
149}
150
151impl FromStr for IntCC {
152    type Err = ();
153
154    fn from_str(s: &str) -> Result<Self, Self::Err> {
155        use self::IntCC::*;
156        match s {
157            "eq" => Ok(Equal),
158            "ne" => Ok(NotEqual),
159            "sge" => Ok(SignedGreaterThanOrEqual),
160            "sgt" => Ok(SignedGreaterThan),
161            "sle" => Ok(SignedLessThanOrEqual),
162            "slt" => Ok(SignedLessThan),
163            "uge" => Ok(UnsignedGreaterThanOrEqual),
164            "ugt" => Ok(UnsignedGreaterThan),
165            "ule" => Ok(UnsignedLessThanOrEqual),
166            "ult" => Ok(UnsignedLessThan),
167            "of" => Ok(Overflow),
168            "nof" => Ok(NotOverflow),
169            _ => Err(()),
170        }
171    }
172}
173
174/// Condition code for comparing floating point numbers.
175///
176/// This condition code is used by the `fcmp` instruction to compare floating point values. Two
177/// IEEE floating point values relate in exactly one of four ways:
178///
179/// 1. `UN` - unordered when either value is NaN.
180/// 2. `EQ` - equal numerical value.
181/// 3. `LT` - `x` is less than `y`.
182/// 4. `GT` - `x` is greater than `y`.
183///
184/// Note that `0.0` and `-0.0` relate as `EQ` because they both represent the number 0.
185///
186/// The condition codes described here are used to produce a single boolean value from the
187/// comparison. The 14 condition codes here cover every possible combination of the relation above
188/// except the impossible `!UN & !EQ & !LT & !GT` and the always true `UN | EQ | LT | GT`.
189#[derive(Clone, Copy, PartialEq, Eq, Debug, Hash)]
190pub enum FloatCC {
191    /// EQ | LT | GT
192    Ordered,
193    /// UN
194    Unordered,
195
196    /// EQ
197    Equal,
198    /// The C '!=' operator is the inverse of '==': `NotEqual`.
199    /// UN | LT | GT
200    NotEqual,
201    /// LT | GT
202    OrderedNotEqual,
203    /// UN | EQ
204    UnorderedOrEqual,
205
206    /// LT
207    LessThan,
208    /// LT | EQ
209    LessThanOrEqual,
210    /// GT
211    GreaterThan,
212    /// GT | EQ
213    GreaterThanOrEqual,
214
215    /// UN | LT
216    UnorderedOrLessThan,
217    /// UN | LT | EQ
218    UnorderedOrLessThanOrEqual,
219    /// UN | GT
220    UnorderedOrGreaterThan,
221    /// UN | GT | EQ
222    UnorderedOrGreaterThanOrEqual,
223}
224
225impl CondCode for FloatCC {
226    fn inverse(self) -> Self {
227        use self::FloatCC::*;
228        match self {
229            Ordered => Unordered,
230            Unordered => Ordered,
231            Equal => NotEqual,
232            NotEqual => Equal,
233            OrderedNotEqual => UnorderedOrEqual,
234            UnorderedOrEqual => OrderedNotEqual,
235            LessThan => UnorderedOrGreaterThanOrEqual,
236            LessThanOrEqual => UnorderedOrGreaterThan,
237            GreaterThan => UnorderedOrLessThanOrEqual,
238            GreaterThanOrEqual => UnorderedOrLessThan,
239            UnorderedOrLessThan => GreaterThanOrEqual,
240            UnorderedOrLessThanOrEqual => GreaterThan,
241            UnorderedOrGreaterThan => LessThanOrEqual,
242            UnorderedOrGreaterThanOrEqual => LessThan,
243        }
244    }
245    fn reverse(self) -> Self {
246        use self::FloatCC::*;
247        match self {
248            Ordered => Ordered,
249            Unordered => Unordered,
250            Equal => Equal,
251            NotEqual => NotEqual,
252            OrderedNotEqual => OrderedNotEqual,
253            UnorderedOrEqual => UnorderedOrEqual,
254            LessThan => GreaterThan,
255            LessThanOrEqual => GreaterThanOrEqual,
256            GreaterThan => LessThan,
257            GreaterThanOrEqual => LessThanOrEqual,
258            UnorderedOrLessThan => UnorderedOrGreaterThan,
259            UnorderedOrLessThanOrEqual => UnorderedOrGreaterThanOrEqual,
260            UnorderedOrGreaterThan => UnorderedOrLessThan,
261            UnorderedOrGreaterThanOrEqual => UnorderedOrLessThanOrEqual,
262        }
263    }
264}
265
266impl Display for FloatCC {
267    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
268        use self::FloatCC::*;
269        f.write_str(match *self {
270            Ordered => "ord",
271            Unordered => "uno",
272            Equal => "eq",
273            NotEqual => "ne",
274            OrderedNotEqual => "one",
275            UnorderedOrEqual => "ueq",
276            LessThan => "lt",
277            LessThanOrEqual => "le",
278            GreaterThan => "gt",
279            GreaterThanOrEqual => "ge",
280            UnorderedOrLessThan => "ult",
281            UnorderedOrLessThanOrEqual => "ule",
282            UnorderedOrGreaterThan => "ugt",
283            UnorderedOrGreaterThanOrEqual => "uge",
284        })
285    }
286}
287
288impl FromStr for FloatCC {
289    type Err = ();
290
291    fn from_str(s: &str) -> Result<Self, Self::Err> {
292        use self::FloatCC::*;
293        match s {
294            "ord" => Ok(Ordered),
295            "uno" => Ok(Unordered),
296            "eq" => Ok(Equal),
297            "ne" => Ok(NotEqual),
298            "one" => Ok(OrderedNotEqual),
299            "ueq" => Ok(UnorderedOrEqual),
300            "lt" => Ok(LessThan),
301            "le" => Ok(LessThanOrEqual),
302            "gt" => Ok(GreaterThan),
303            "ge" => Ok(GreaterThanOrEqual),
304            "ult" => Ok(UnorderedOrLessThan),
305            "ule" => Ok(UnorderedOrLessThanOrEqual),
306            "ugt" => Ok(UnorderedOrGreaterThan),
307            "uge" => Ok(UnorderedOrGreaterThanOrEqual),
308            _ => Err(()),
309        }
310    }
311}
312
313#[cfg(test)]
314mod tests {
315    use super::*;
316    use std::string::ToString;
317
318    static INT_ALL: [IntCC; 12] = [
319        IntCC::Equal,
320        IntCC::NotEqual,
321        IntCC::SignedLessThan,
322        IntCC::SignedGreaterThanOrEqual,
323        IntCC::SignedGreaterThan,
324        IntCC::SignedLessThanOrEqual,
325        IntCC::UnsignedLessThan,
326        IntCC::UnsignedGreaterThanOrEqual,
327        IntCC::UnsignedGreaterThan,
328        IntCC::UnsignedLessThanOrEqual,
329        IntCC::Overflow,
330        IntCC::NotOverflow,
331    ];
332
333    #[test]
334    fn int_inverse() {
335        for r in &INT_ALL {
336            let cc = *r;
337            let inv = cc.inverse();
338            assert!(cc != inv);
339            assert_eq!(inv.inverse(), cc);
340        }
341    }
342
343    #[test]
344    fn int_reverse() {
345        for r in &INT_ALL {
346            let cc = *r;
347            let rev = cc.reverse();
348            assert_eq!(rev.reverse(), cc);
349        }
350    }
351
352    #[test]
353    fn int_display() {
354        for r in &INT_ALL {
355            let cc = *r;
356            assert_eq!(cc.to_string().parse(), Ok(cc));
357        }
358        assert_eq!("bogus".parse::<IntCC>(), Err(()));
359    }
360
361    static FLOAT_ALL: [FloatCC; 14] = [
362        FloatCC::Ordered,
363        FloatCC::Unordered,
364        FloatCC::Equal,
365        FloatCC::NotEqual,
366        FloatCC::OrderedNotEqual,
367        FloatCC::UnorderedOrEqual,
368        FloatCC::LessThan,
369        FloatCC::LessThanOrEqual,
370        FloatCC::GreaterThan,
371        FloatCC::GreaterThanOrEqual,
372        FloatCC::UnorderedOrLessThan,
373        FloatCC::UnorderedOrLessThanOrEqual,
374        FloatCC::UnorderedOrGreaterThan,
375        FloatCC::UnorderedOrGreaterThanOrEqual,
376    ];
377
378    #[test]
379    fn float_inverse() {
380        for r in &FLOAT_ALL {
381            let cc = *r;
382            let inv = cc.inverse();
383            assert!(cc != inv);
384            assert_eq!(inv.inverse(), cc);
385        }
386    }
387
388    #[test]
389    fn float_reverse() {
390        for r in &FLOAT_ALL {
391            let cc = *r;
392            let rev = cc.reverse();
393            assert_eq!(rev.reverse(), cc);
394        }
395    }
396
397    #[test]
398    fn float_display() {
399        for r in &FLOAT_ALL {
400            let cc = *r;
401            assert_eq!(cc.to_string().parse(), Ok(cc));
402        }
403        assert_eq!("bogus".parse::<FloatCC>(), Err(()));
404    }
405}