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 
7 use core::fmt::{self, Display, Formatter};
8 use core::str::FromStr;
9 
10 /// Common traits of condition codes.
11 pub 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]
inverse(self) -> Self17     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]
reverse(self) -> Self24     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)]
33 pub 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 
60 impl CondCode for IntCC {
inverse(self) -> Self61     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 
reverse(self) -> Self79     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 
98 impl IntCC {
99     /// Get the corresponding IntCC with the equal component removed.
100     /// For conditions without a zero component, this is a no-op.
without_equal(self) -> Self101     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.
unsigned(self) -> Self114     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.
to_static_str(self) -> &'static str126     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 
145 impl Display for IntCC {
fmt(&self, f: &mut Formatter) -> fmt::Result146     fn fmt(&self, f: &mut Formatter) -> fmt::Result {
147         f.write_str(self.to_static_str())
148     }
149 }
150 
151 impl FromStr for IntCC {
152     type Err = ();
153 
from_str(s: &str) -> Result<Self, Self::Err>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)]
190 pub 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 
225 impl CondCode for FloatCC {
inverse(self) -> Self226     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     }
reverse(self) -> Self245     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 
266 impl Display for FloatCC {
fmt(&self, f: &mut Formatter) -> fmt::Result267     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 
288 impl FromStr for FloatCC {
289     type Err = ();
290 
from_str(s: &str) -> Result<Self, Self::Err>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)]
314 mod 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]
int_inverse()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]
int_reverse()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]
int_display()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]
float_inverse()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]
float_reverse()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]
float_display()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 }
406