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_derive::{Deserialize, Serialize};
12 
13 /// Common traits of condition codes.
14 pub 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]
complement(self) -> Self20     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]
swap_args(self) -> Self27     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))]
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 }
59 
60 impl CondCode for IntCC {
complement(self) -> Self61     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 
swap_args(self) -> Self77     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 
94 impl IntCC {
95     /// Returns a slice with all possible [IntCC] values.
all() -> &'static [IntCC]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.
without_equal(self) -> Self113     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.
unsigned(self) -> Self126     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.
to_static_str(self) -> &'static str138     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 
155 impl Display for IntCC {
fmt(&self, f: &mut Formatter) -> fmt::Result156     fn fmt(&self, f: &mut Formatter) -> fmt::Result {
157         f.write_str(self.to_static_str())
158     }
159 }
160 
161 impl FromStr for IntCC {
162     type Err = ();
163 
from_str(s: &str) -> Result<Self, Self::Err>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))]
199 pub 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 
234 impl FloatCC {
235     /// Returns a slice with all possible [FloatCC] values.
all() -> &'static [FloatCC]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 
256 impl CondCode for FloatCC {
complement(self) -> Self257     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     }
swap_args(self) -> Self276     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 
297 impl Display for FloatCC {
fmt(&self, f: &mut Formatter) -> fmt::Result298     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 
319 impl FromStr for FloatCC {
320     type Err = ();
321 
from_str(s: &str) -> Result<Self, Self::Err>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)]
345 mod tests {
346     use super::*;
347     use alloc::string::ToString;
348 
349     #[test]
int_complement()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]
int_swap_args()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]
int_display()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]
float_complement()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]
float_swap_args()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]
float_display()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 }
405