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