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