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