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