Path: blob/main/cranelift/codegen/src/ir/condcodes.rs
1693 views
//! Condition codes for the Cranelift code generator.1//!2//! A condition code here is an enumerated type that determined how to compare two numbers. There3//! are different rules for comparing integers and floating point numbers, so they use different4//! condition codes.56use core::fmt::{self, Display, Formatter};7use core::str::FromStr;89#[cfg(feature = "enable-serde")]10use serde_derive::{Deserialize, Serialize};1112/// Common traits of condition codes.13pub trait CondCode: Copy {14/// Get the complemented condition code of `self`.15///16/// The complemented condition code produces the opposite result for all comparisons.17/// That is, `cmp CC, x, y` is true if and only if `cmp CC.complement(), x, y` is false.18#[must_use]19fn complement(self) -> Self;2021/// Get the swapped args condition code for `self`.22///23/// The swapped args condition code produces the same result as swapping `x` and `y` in the24/// comparison. That is, `cmp CC, x, y` is the same as `cmp CC.swap_args(), y, x`.25#[must_use]26fn swap_args(self) -> Self;27}2829/// Condition code for comparing integers.30///31/// This condition code is used by the `icmp` instruction to compare integer values. There are32/// separate codes for comparing the integers as signed or unsigned numbers where it makes a33/// difference.34#[derive(Clone, Copy, PartialEq, Eq, Debug, Hash)]35#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]36pub enum IntCC {37/// `==`.38Equal,39/// `!=`.40NotEqual,41/// Signed `<`.42SignedLessThan,43/// Signed `>=`.44SignedGreaterThanOrEqual,45/// Signed `>`.46SignedGreaterThan,47/// Signed `<=`.48SignedLessThanOrEqual,49/// Unsigned `<`.50UnsignedLessThan,51/// Unsigned `>=`.52UnsignedGreaterThanOrEqual,53/// Unsigned `>`.54UnsignedGreaterThan,55/// Unsigned `<=`.56UnsignedLessThanOrEqual,57}5859impl CondCode for IntCC {60fn complement(self) -> Self {61use self::IntCC::*;62match self {63Equal => NotEqual,64NotEqual => Equal,65SignedLessThan => SignedGreaterThanOrEqual,66SignedGreaterThanOrEqual => SignedLessThan,67SignedGreaterThan => SignedLessThanOrEqual,68SignedLessThanOrEqual => SignedGreaterThan,69UnsignedLessThan => UnsignedGreaterThanOrEqual,70UnsignedGreaterThanOrEqual => UnsignedLessThan,71UnsignedGreaterThan => UnsignedLessThanOrEqual,72UnsignedLessThanOrEqual => UnsignedGreaterThan,73}74}7576fn swap_args(self) -> Self {77use self::IntCC::*;78match self {79Equal => Equal,80NotEqual => NotEqual,81SignedGreaterThan => SignedLessThan,82SignedGreaterThanOrEqual => SignedLessThanOrEqual,83SignedLessThan => SignedGreaterThan,84SignedLessThanOrEqual => SignedGreaterThanOrEqual,85UnsignedGreaterThan => UnsignedLessThan,86UnsignedGreaterThanOrEqual => UnsignedLessThanOrEqual,87UnsignedLessThan => UnsignedGreaterThan,88UnsignedLessThanOrEqual => UnsignedGreaterThanOrEqual,89}90}91}9293impl IntCC {94/// Returns a slice with all possible [IntCC] values.95pub fn all() -> &'static [IntCC] {96&[97IntCC::Equal,98IntCC::NotEqual,99IntCC::SignedLessThan,100IntCC::SignedGreaterThanOrEqual,101IntCC::SignedGreaterThan,102IntCC::SignedLessThanOrEqual,103IntCC::UnsignedLessThan,104IntCC::UnsignedGreaterThanOrEqual,105IntCC::UnsignedGreaterThan,106IntCC::UnsignedLessThanOrEqual,107]108}109110/// Get the corresponding IntCC with the equal component removed.111/// For conditions without a zero component, this is a no-op.112pub fn without_equal(self) -> Self {113use self::IntCC::*;114match self {115SignedGreaterThan | SignedGreaterThanOrEqual => SignedGreaterThan,116SignedLessThan | SignedLessThanOrEqual => SignedLessThan,117UnsignedGreaterThan | UnsignedGreaterThanOrEqual => UnsignedGreaterThan,118UnsignedLessThan | UnsignedLessThanOrEqual => UnsignedLessThan,119_ => self,120}121}122123/// Get the corresponding IntCC with the signed component removed.124/// For conditions without a signed component, this is a no-op.125pub fn unsigned(self) -> Self {126use self::IntCC::*;127match self {128SignedGreaterThan | UnsignedGreaterThan => UnsignedGreaterThan,129SignedGreaterThanOrEqual | UnsignedGreaterThanOrEqual => UnsignedGreaterThanOrEqual,130SignedLessThan | UnsignedLessThan => UnsignedLessThan,131SignedLessThanOrEqual | UnsignedLessThanOrEqual => UnsignedLessThanOrEqual,132_ => self,133}134}135136/// Get the corresponding string condition code for the IntCC object.137pub fn to_static_str(self) -> &'static str {138use self::IntCC::*;139match self {140Equal => "eq",141NotEqual => "ne",142SignedGreaterThan => "sgt",143SignedGreaterThanOrEqual => "sge",144SignedLessThan => "slt",145SignedLessThanOrEqual => "sle",146UnsignedGreaterThan => "ugt",147UnsignedGreaterThanOrEqual => "uge",148UnsignedLessThan => "ult",149UnsignedLessThanOrEqual => "ule",150}151}152}153154impl Display for IntCC {155fn fmt(&self, f: &mut Formatter) -> fmt::Result {156f.write_str(self.to_static_str())157}158}159160impl FromStr for IntCC {161type Err = ();162163fn from_str(s: &str) -> Result<Self, Self::Err> {164use self::IntCC::*;165match s {166"eq" => Ok(Equal),167"ne" => Ok(NotEqual),168"sge" => Ok(SignedGreaterThanOrEqual),169"sgt" => Ok(SignedGreaterThan),170"sle" => Ok(SignedLessThanOrEqual),171"slt" => Ok(SignedLessThan),172"uge" => Ok(UnsignedGreaterThanOrEqual),173"ugt" => Ok(UnsignedGreaterThan),174"ule" => Ok(UnsignedLessThanOrEqual),175"ult" => Ok(UnsignedLessThan),176_ => Err(()),177}178}179}180181/// Condition code for comparing floating point numbers.182///183/// This condition code is used by the `fcmp` instruction to compare floating point values. Two184/// IEEE floating point values relate in exactly one of four ways:185///186/// 1. `UN` - unordered when either value is NaN.187/// 2. `EQ` - equal numerical value.188/// 3. `LT` - `x` is less than `y`.189/// 4. `GT` - `x` is greater than `y`.190///191/// Note that `0.0` and `-0.0` relate as `EQ` because they both represent the number 0.192///193/// The condition codes described here are used to produce a single boolean value from the194/// comparison. The 14 condition codes here cover every possible combination of the relation above195/// except the impossible `!UN & !EQ & !LT & !GT` and the always true `UN | EQ | LT | GT`.196#[derive(Clone, Copy, PartialEq, Eq, Debug, Hash)]197#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]198pub enum FloatCC {199/// EQ | LT | GT200Ordered,201/// UN202Unordered,203204/// EQ205Equal,206/// The C '!=' operator is the inverse of '==': `NotEqual`.207/// UN | LT | GT208NotEqual,209/// LT | GT210OrderedNotEqual,211/// UN | EQ212UnorderedOrEqual,213214/// LT215LessThan,216/// LT | EQ217LessThanOrEqual,218/// GT219GreaterThan,220/// GT | EQ221GreaterThanOrEqual,222223/// UN | LT224UnorderedOrLessThan,225/// UN | LT | EQ226UnorderedOrLessThanOrEqual,227/// UN | GT228UnorderedOrGreaterThan,229/// UN | GT | EQ230UnorderedOrGreaterThanOrEqual,231}232233impl FloatCC {234/// Returns a slice with all possible [FloatCC] values.235pub fn all() -> &'static [FloatCC] {236&[237FloatCC::Ordered,238FloatCC::Unordered,239FloatCC::Equal,240FloatCC::NotEqual,241FloatCC::OrderedNotEqual,242FloatCC::UnorderedOrEqual,243FloatCC::LessThan,244FloatCC::LessThanOrEqual,245FloatCC::GreaterThan,246FloatCC::GreaterThanOrEqual,247FloatCC::UnorderedOrLessThan,248FloatCC::UnorderedOrLessThanOrEqual,249FloatCC::UnorderedOrGreaterThan,250FloatCC::UnorderedOrGreaterThanOrEqual,251]252}253}254255impl CondCode for FloatCC {256fn complement(self) -> Self {257use self::FloatCC::*;258match self {259Ordered => Unordered,260Unordered => Ordered,261Equal => NotEqual,262NotEqual => Equal,263OrderedNotEqual => UnorderedOrEqual,264UnorderedOrEqual => OrderedNotEqual,265LessThan => UnorderedOrGreaterThanOrEqual,266LessThanOrEqual => UnorderedOrGreaterThan,267GreaterThan => UnorderedOrLessThanOrEqual,268GreaterThanOrEqual => UnorderedOrLessThan,269UnorderedOrLessThan => GreaterThanOrEqual,270UnorderedOrLessThanOrEqual => GreaterThan,271UnorderedOrGreaterThan => LessThanOrEqual,272UnorderedOrGreaterThanOrEqual => LessThan,273}274}275fn swap_args(self) -> Self {276use self::FloatCC::*;277match self {278Ordered => Ordered,279Unordered => Unordered,280Equal => Equal,281NotEqual => NotEqual,282OrderedNotEqual => OrderedNotEqual,283UnorderedOrEqual => UnorderedOrEqual,284LessThan => GreaterThan,285LessThanOrEqual => GreaterThanOrEqual,286GreaterThan => LessThan,287GreaterThanOrEqual => LessThanOrEqual,288UnorderedOrLessThan => UnorderedOrGreaterThan,289UnorderedOrLessThanOrEqual => UnorderedOrGreaterThanOrEqual,290UnorderedOrGreaterThan => UnorderedOrLessThan,291UnorderedOrGreaterThanOrEqual => UnorderedOrLessThanOrEqual,292}293}294}295296impl Display for FloatCC {297fn fmt(&self, f: &mut Formatter) -> fmt::Result {298use self::FloatCC::*;299f.write_str(match *self {300Ordered => "ord",301Unordered => "uno",302Equal => "eq",303NotEqual => "ne",304OrderedNotEqual => "one",305UnorderedOrEqual => "ueq",306LessThan => "lt",307LessThanOrEqual => "le",308GreaterThan => "gt",309GreaterThanOrEqual => "ge",310UnorderedOrLessThan => "ult",311UnorderedOrLessThanOrEqual => "ule",312UnorderedOrGreaterThan => "ugt",313UnorderedOrGreaterThanOrEqual => "uge",314})315}316}317318impl FromStr for FloatCC {319type Err = ();320321fn from_str(s: &str) -> Result<Self, Self::Err> {322use self::FloatCC::*;323match s {324"ord" => Ok(Ordered),325"uno" => Ok(Unordered),326"eq" => Ok(Equal),327"ne" => Ok(NotEqual),328"one" => Ok(OrderedNotEqual),329"ueq" => Ok(UnorderedOrEqual),330"lt" => Ok(LessThan),331"le" => Ok(LessThanOrEqual),332"gt" => Ok(GreaterThan),333"ge" => Ok(GreaterThanOrEqual),334"ult" => Ok(UnorderedOrLessThan),335"ule" => Ok(UnorderedOrLessThanOrEqual),336"ugt" => Ok(UnorderedOrGreaterThan),337"uge" => Ok(UnorderedOrGreaterThanOrEqual),338_ => Err(()),339}340}341}342343#[cfg(test)]344mod tests {345use super::*;346use std::string::ToString;347348#[test]349fn int_complement() {350for r in IntCC::all() {351let cc = *r;352let inv = cc.complement();353assert!(cc != inv);354assert_eq!(inv.complement(), cc);355}356}357358#[test]359fn int_swap_args() {360for r in IntCC::all() {361let cc = *r;362let rev = cc.swap_args();363assert_eq!(rev.swap_args(), cc);364}365}366367#[test]368fn int_display() {369for r in IntCC::all() {370let cc = *r;371assert_eq!(cc.to_string().parse(), Ok(cc));372}373assert_eq!("bogus".parse::<IntCC>(), Err(()));374}375376#[test]377fn float_complement() {378for r in FloatCC::all() {379let cc = *r;380let inv = cc.complement();381assert!(cc != inv);382assert_eq!(inv.complement(), cc);383}384}385386#[test]387fn float_swap_args() {388for r in FloatCC::all() {389let cc = *r;390let rev = cc.swap_args();391assert_eq!(rev.swap_args(), cc);392}393}394395#[test]396fn float_display() {397for r in FloatCC::all() {398let cc = *r;399assert_eq!(cc.to_string().parse(), Ok(cc));400}401assert_eq!("bogus".parse::<FloatCC>(), Err(()));402}403}404405406