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