diff --git a/library/core/src/cmp.rs b/library/core/src/cmp.rs index 949896e574806..47ea199a835c5 100644 --- a/library/core/src/cmp.rs +++ b/library/core/src/cmp.rs @@ -360,12 +360,18 @@ impl Ordering { /// assert_eq!(Ordering::Equal.is_eq(), true); /// assert_eq!(Ordering::Greater.is_eq(), false); /// ``` - #[inline] + #[inline(always)] #[must_use] #[rustc_const_stable(feature = "ordering_helpers", since = "1.53.0")] #[stable(feature = "ordering_helpers", since = "1.53.0")] pub const fn is_eq(self) -> bool { - matches!(self, Equal) + // Implementation note: It appears (as of 2022-12) that LLVM has an + // easier time with a comparison against zero like this, as opposed + // to looking for the `Less` value (-1) specifically, maybe because + // it's not always obvious to it that -2 isn't possible. + // Thus this and its siblings below are written this way, rather + // than the potentially-more-obvious `matches!` version. + (self as i8) == 0 } /// Returns `true` if the ordering is not the `Equal` variant. @@ -379,12 +385,12 @@ impl Ordering { /// assert_eq!(Ordering::Equal.is_ne(), false); /// assert_eq!(Ordering::Greater.is_ne(), true); /// ``` - #[inline] + #[inline(always)] #[must_use] #[rustc_const_stable(feature = "ordering_helpers", since = "1.53.0")] #[stable(feature = "ordering_helpers", since = "1.53.0")] pub const fn is_ne(self) -> bool { - !matches!(self, Equal) + (self as i8) != 0 } /// Returns `true` if the ordering is the `Less` variant. @@ -398,12 +404,12 @@ impl Ordering { /// assert_eq!(Ordering::Equal.is_lt(), false); /// assert_eq!(Ordering::Greater.is_lt(), false); /// ``` - #[inline] + #[inline(always)] #[must_use] #[rustc_const_stable(feature = "ordering_helpers", since = "1.53.0")] #[stable(feature = "ordering_helpers", since = "1.53.0")] pub const fn is_lt(self) -> bool { - matches!(self, Less) + (self as i8) < 0 } /// Returns `true` if the ordering is the `Greater` variant. @@ -417,12 +423,12 @@ impl Ordering { /// assert_eq!(Ordering::Equal.is_gt(), false); /// assert_eq!(Ordering::Greater.is_gt(), true); /// ``` - #[inline] + #[inline(always)] #[must_use] #[rustc_const_stable(feature = "ordering_helpers", since = "1.53.0")] #[stable(feature = "ordering_helpers", since = "1.53.0")] pub const fn is_gt(self) -> bool { - matches!(self, Greater) + (self as i8) > 0 } /// Returns `true` if the ordering is either the `Less` or `Equal` variant. @@ -436,12 +442,12 @@ impl Ordering { /// assert_eq!(Ordering::Equal.is_le(), true); /// assert_eq!(Ordering::Greater.is_le(), false); /// ``` - #[inline] + #[inline(always)] #[must_use] #[rustc_const_stable(feature = "ordering_helpers", since = "1.53.0")] #[stable(feature = "ordering_helpers", since = "1.53.0")] pub const fn is_le(self) -> bool { - !matches!(self, Greater) + (self as i8) <= 0 } /// Returns `true` if the ordering is either the `Greater` or `Equal` variant. @@ -455,12 +461,12 @@ impl Ordering { /// assert_eq!(Ordering::Equal.is_ge(), true); /// assert_eq!(Ordering::Greater.is_ge(), true); /// ``` - #[inline] + #[inline(always)] #[must_use] #[rustc_const_stable(feature = "ordering_helpers", since = "1.53.0")] #[stable(feature = "ordering_helpers", since = "1.53.0")] pub const fn is_ge(self) -> bool { - !matches!(self, Less) + (self as i8) >= 0 } /// Reverses the `Ordering`. @@ -1124,7 +1130,7 @@ pub trait PartialOrd: PartialEq { #[must_use] #[stable(feature = "rust1", since = "1.0.0")] fn lt(&self, other: &Rhs) -> bool { - matches!(self.partial_cmp(other), Some(Less)) + if let Some(ordering) = self.partial_cmp(other) { ordering.is_lt() } else { false } } /// This method tests less than or equal to (for `self` and `other`) and is used by the `<=` @@ -1143,7 +1149,7 @@ pub trait PartialOrd: PartialEq { #[must_use] #[stable(feature = "rust1", since = "1.0.0")] fn le(&self, other: &Rhs) -> bool { - matches!(self.partial_cmp(other), Some(Less | Equal)) + if let Some(ordering) = self.partial_cmp(other) { ordering.is_le() } else { false } } /// This method tests greater than (for `self` and `other`) and is used by the `>` operator. @@ -1161,7 +1167,7 @@ pub trait PartialOrd: PartialEq { #[must_use] #[stable(feature = "rust1", since = "1.0.0")] fn gt(&self, other: &Rhs) -> bool { - matches!(self.partial_cmp(other), Some(Greater)) + if let Some(ordering) = self.partial_cmp(other) { ordering.is_gt() } else { false } } /// This method tests greater than or equal to (for `self` and `other`) and is used by the `>=` @@ -1180,7 +1186,7 @@ pub trait PartialOrd: PartialEq { #[must_use] #[stable(feature = "rust1", since = "1.0.0")] fn ge(&self, other: &Rhs) -> bool { - matches!(self.partial_cmp(other), Some(Greater | Equal)) + if let Some(ordering) = self.partial_cmp(other) { ordering.is_ge() } else { false } } } diff --git a/src/test/codegen/newtype-relational-operators.rs b/src/test/codegen/newtype-relational-operators.rs new file mode 100644 index 0000000000000..5cf6c3ac0a233 --- /dev/null +++ b/src/test/codegen/newtype-relational-operators.rs @@ -0,0 +1,49 @@ +// The `derive(PartialOrd)` for a newtype doesn't override `lt`/`le`/`gt`/`ge`. +// This double-checks that the `Option` intermediate values used +// in the operators for such a type all optimize away. + +// compile-flags: -C opt-level=1 +// min-llvm-version: 15.0 + +#![crate_type = "lib"] + +use std::cmp::Ordering; + +#[derive(PartialOrd, PartialEq)] +pub struct Foo(u16); + +// CHECK-LABEL: @check_lt +// CHECK-SAME: (i16 %[[A:.+]], i16 %[[B:.+]]) +#[no_mangle] +pub fn check_lt(a: Foo, b: Foo) -> bool { + // CHECK: %[[R:.+]] = icmp ult i16 %[[A]], %[[B]] + // CHECK-NEXT: ret i1 %[[R]] + a < b +} + +// CHECK-LABEL: @check_le +// CHECK-SAME: (i16 %[[A:.+]], i16 %[[B:.+]]) +#[no_mangle] +pub fn check_le(a: Foo, b: Foo) -> bool { + // CHECK: %[[R:.+]] = icmp ule i16 %[[A]], %[[B]] + // CHECK-NEXT: ret i1 %[[R]] + a <= b +} + +// CHECK-LABEL: @check_gt +// CHECK-SAME: (i16 %[[A:.+]], i16 %[[B:.+]]) +#[no_mangle] +pub fn check_gt(a: Foo, b: Foo) -> bool { + // CHECK: %[[R:.+]] = icmp ugt i16 %[[A]], %[[B]] + // CHECK-NEXT: ret i1 %[[R]] + a > b +} + +// CHECK-LABEL: @check_ge +// CHECK-SAME: (i16 %[[A:.+]], i16 %[[B:.+]]) +#[no_mangle] +pub fn check_ge(a: Foo, b: Foo) -> bool { + // CHECK: %[[R:.+]] = icmp uge i16 %[[A]], %[[B]] + // CHECK-NEXT: ret i1 %[[R]] + a >= b +}