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