Skip to content

Commit

Permalink
Unrolled build for rust-lang#137197
Browse files Browse the repository at this point in the history
Rollup merge of rust-lang#137197 - scottmcm:cmp-20, r=ibraheemdev

Update some comparison codegen tests now that they pass in LLVM20

Fixes rust-lang#106107

Needed one tweak to the default `PartialOrd::le` to get the test to pass.  Everything but the derived 2-field `le` test passes even without the change to the defaults in the trait.
  • Loading branch information
rust-timer authored Mar 1, 2025
2 parents aa3c2d7 + 3a3aede commit e916e24
Show file tree
Hide file tree
Showing 3 changed files with 82 additions and 25 deletions.
8 changes: 4 additions & 4 deletions library/core/src/cmp.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1369,7 +1369,7 @@ pub trait PartialOrd<Rhs: ?Sized = Self>: PartialEq<Rhs> {
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_diagnostic_item = "cmp_partialord_lt"]
fn lt(&self, other: &Rhs) -> bool {
matches!(self.partial_cmp(other), Some(Less))
self.partial_cmp(other).is_some_and(Ordering::is_lt)
}

/// Tests less than or equal to (for `self` and `other`) and is used by the
Expand All @@ -1387,7 +1387,7 @@ pub trait PartialOrd<Rhs: ?Sized = Self>: PartialEq<Rhs> {
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_diagnostic_item = "cmp_partialord_le"]
fn le(&self, other: &Rhs) -> bool {
matches!(self.partial_cmp(other), Some(Less | Equal))
self.partial_cmp(other).is_some_and(Ordering::is_le)
}

/// Tests greater than (for `self` and `other`) and is used by the `>`
Expand All @@ -1405,7 +1405,7 @@ pub trait PartialOrd<Rhs: ?Sized = Self>: PartialEq<Rhs> {
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_diagnostic_item = "cmp_partialord_gt"]
fn gt(&self, other: &Rhs) -> bool {
matches!(self.partial_cmp(other), Some(Greater))
self.partial_cmp(other).is_some_and(Ordering::is_gt)
}

/// Tests greater than or equal to (for `self` and `other`) and is used by
Expand All @@ -1423,7 +1423,7 @@ pub trait PartialOrd<Rhs: ?Sized = Self>: PartialEq<Rhs> {
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_diagnostic_item = "cmp_partialord_ge"]
fn ge(&self, other: &Rhs) -> bool {
matches!(self.partial_cmp(other), Some(Greater | Equal))
self.partial_cmp(other).is_some_and(Ordering::is_ge)
}
}

Expand Down
61 changes: 61 additions & 0 deletions tests/codegen/comparison-operators-2-struct.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
//@ compile-flags: -C opt-level=1
//@ min-llvm-version: 20

// The `derive(PartialOrd)` for a 2-field type doesn't override `lt`/`le`/`gt`/`ge`.
// This double-checks that the `Option<Ordering>` intermediate values used
// in the operators for such a type all optimize away.

#![crate_type = "lib"]

use std::cmp::Ordering;

#[derive(PartialOrd, PartialEq)]
pub struct Foo(i32, u32);

// CHECK-LABEL: @check_lt(
// CHECK-SAME: i32{{.+}}%[[A0:.+]], i32{{.+}}%[[A1:.+]], i32{{.+}}%[[B0:.+]], i32{{.+}}%[[B1:.+]])
#[no_mangle]
pub fn check_lt(a: Foo, b: Foo) -> bool {
// CHECK-DAG: %[[EQ:.+]] = icmp eq i32 %[[A0]], %[[B0]]
// CHECK-DAG: %[[R0:.+]] = icmp slt i32 %[[A0]], %[[B0]]
// CHECK-DAG: %[[R1:.+]] = icmp ult i32 %[[A1]], %[[B1]]
// CHECK: %[[R:.+]] = select i1 %[[EQ]], i1 %[[R1]], i1 %[[R0]]
// CHECK-NEXT: ret i1 %[[R]]
a < b
}

// CHECK-LABEL: @check_le(
// CHECK-SAME: i32{{.+}}%[[A0:.+]], i32{{.+}}%[[A1:.+]], i32{{.+}}%[[B0:.+]], i32{{.+}}%[[B1:.+]])
#[no_mangle]
pub fn check_le(a: Foo, b: Foo) -> bool {
// CHECK-DAG: %[[EQ:.+]] = icmp eq i32 %[[A0]], %[[B0]]
// CHECK-DAG: %[[R0:.+]] = icmp sle i32 %[[A0]], %[[B0]]
// CHECK-DAG: %[[R1:.+]] = icmp ule i32 %[[A1]], %[[B1]]
// CHECK: %[[R:.+]] = select i1 %[[EQ]], i1 %[[R1]], i1 %[[R0]]
// CHECK-NEXT: ret i1 %[[R]]
a <= b
}

// CHECK-LABEL: @check_gt(
// CHECK-SAME: i32{{.+}}%[[A0:.+]], i32{{.+}}%[[A1:.+]], i32{{.+}}%[[B0:.+]], i32{{.+}}%[[B1:.+]])
#[no_mangle]
pub fn check_gt(a: Foo, b: Foo) -> bool {
// CHECK-DAG: %[[EQ:.+]] = icmp eq i32 %[[A0]], %[[B0]]
// CHECK-DAG: %[[R0:.+]] = icmp sgt i32 %[[A0]], %[[B0]]
// CHECK-DAG: %[[R1:.+]] = icmp ugt i32 %[[A1]], %[[B1]]
// CHECK: %[[R:.+]] = select i1 %[[EQ]], i1 %[[R1]], i1 %[[R0]]
// CHECK-NEXT: ret i1 %[[R]]
a > b
}

// CHECK-LABEL: @check_ge(
// CHECK-SAME: i32{{.+}}%[[A0:.+]], i32{{.+}}%[[A1:.+]], i32{{.+}}%[[B0:.+]], i32{{.+}}%[[B1:.+]])
#[no_mangle]
pub fn check_ge(a: Foo, b: Foo) -> bool {
// CHECK-DAG: %[[EQ:.+]] = icmp eq i32 %[[A0]], %[[B0]]
// CHECK-DAG: %[[R0:.+]] = icmp sge i32 %[[A0]], %[[B0]]
// CHECK-DAG: %[[R1:.+]] = icmp uge i32 %[[A1]], %[[B1]]
// CHECK: %[[R:.+]] = select i1 %[[EQ]], i1 %[[R1]], i1 %[[R0]]
// CHECK-NEXT: ret i1 %[[R]]
a >= b
}
38 changes: 17 additions & 21 deletions tests/codegen/comparison-operators-2-tuple.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
//@ compile-flags: -C opt-level=1 -Z merge-functions=disabled
//@ only-x86_64
//@ min-llvm-version: 20

#![crate_type = "lib"]

Expand Down Expand Up @@ -65,12 +66,7 @@ pub fn check_ge_direct(a: TwoTuple, b: TwoTuple) -> bool {
}

//
// These ones are harder, since there are more intermediate values to remove.
//
// `<` seems to be getting lucky right now, so test that doesn't regress.
//
// The others, however, aren't managing to optimize away the extra `select`s yet.
// See <https://github.com/rust-lang/rust/issues/106107> for more about this.
// These used to not optimize as well, but thanks to LLVM 20 they work now 🎉
//

// CHECK-LABEL: @check_lt_via_cmp
Expand All @@ -89,34 +85,34 @@ pub fn check_lt_via_cmp(a: TwoTuple, b: TwoTuple) -> bool {
// CHECK-SAME: (i16 noundef %[[A0:.+]], i16 noundef %[[A1:.+]], i16 noundef %[[B0:.+]], i16 noundef %[[B1:.+]])
#[no_mangle]
pub fn check_le_via_cmp(a: TwoTuple, b: TwoTuple) -> bool {
// FIXME-CHECK-DAG: %[[EQ:.+]] = icmp eq i16 %[[A0]], %[[B0]]
// FIXME-CHECK-DAG: %[[CMP0:.+]] = icmp sle i16 %[[A0]], %[[B0]]
// FIXME-CHECK-DAG: %[[CMP1:.+]] = icmp ule i16 %[[A1]], %[[B1]]
// FIXME-CHECK: %[[R:.+]] = select i1 %[[EQ]], i1 %[[CMP1]], i1 %[[CMP0]]
// FIXME-CHECK: ret i1 %[[R]]
// CHECK-DAG: %[[EQ:.+]] = icmp eq i16 %[[A0]], %[[B0]]
// CHECK-DAG: %[[CMP0:.+]] = icmp sle i16 %[[A0]], %[[B0]]
// CHECK-DAG: %[[CMP1:.+]] = icmp ule i16 %[[A1]], %[[B1]]
// CHECK: %[[R:.+]] = select i1 %[[EQ]], i1 %[[CMP1]], i1 %[[CMP0]]
// CHECK: ret i1 %[[R]]
Ord::cmp(&a, &b).is_le()
}

// CHECK-LABEL: @check_gt_via_cmp
// CHECK-SAME: (i16 noundef %[[A0:.+]], i16 noundef %[[A1:.+]], i16 noundef %[[B0:.+]], i16 noundef %[[B1:.+]])
#[no_mangle]
pub fn check_gt_via_cmp(a: TwoTuple, b: TwoTuple) -> bool {
// FIXME-CHECK-DAG: %[[EQ:.+]] = icmp eq i16 %[[A0]], %[[B0]]
// FIXME-CHECK-DAG: %[[CMP0:.+]] = icmp sgt i16 %[[A0]], %[[B0]]
// FIXME-CHECK-DAG: %[[CMP1:.+]] = icmp ugt i16 %[[A1]], %[[B1]]
// FIXME-CHECK: %[[R:.+]] = select i1 %[[EQ]], i1 %[[CMP1]], i1 %[[CMP0]]
// FIXME-CHECK: ret i1 %[[R]]
// CHECK-DAG: %[[EQ:.+]] = icmp eq i16 %[[A0]], %[[B0]]
// CHECK-DAG: %[[CMP0:.+]] = icmp sgt i16 %[[A0]], %[[B0]]
// CHECK-DAG: %[[CMP1:.+]] = icmp ugt i16 %[[A1]], %[[B1]]
// CHECK: %[[R:.+]] = select i1 %[[EQ]], i1 %[[CMP1]], i1 %[[CMP0]]
// CHECK: ret i1 %[[R]]
Ord::cmp(&a, &b).is_gt()
}

// CHECK-LABEL: @check_ge_via_cmp
// CHECK-SAME: (i16 noundef %[[A0:.+]], i16 noundef %[[A1:.+]], i16 noundef %[[B0:.+]], i16 noundef %[[B1:.+]])
#[no_mangle]
pub fn check_ge_via_cmp(a: TwoTuple, b: TwoTuple) -> bool {
// FIXME-CHECK-DAG: %[[EQ:.+]] = icmp eq i16 %[[A0]], %[[B0]]
// FIXME-CHECK-DAG: %[[CMP0:.+]] = icmp sge i16 %[[A0]], %[[B0]]
// FIXME-CHECK-DAG: %[[CMP1:.+]] = icmp uge i16 %[[A1]], %[[B1]]
// FIXME-CHECK: %[[R:.+]] = select i1 %[[EQ]], i1 %[[CMP1]], i1 %[[CMP0]]
// FIXME-CHECK: ret i1 %[[R]]
// CHECK-DAG: %[[EQ:.+]] = icmp eq i16 %[[A0]], %[[B0]]
// CHECK-DAG: %[[CMP0:.+]] = icmp sge i16 %[[A0]], %[[B0]]
// CHECK-DAG: %[[CMP1:.+]] = icmp uge i16 %[[A1]], %[[B1]]
// CHECK: %[[R:.+]] = select i1 %[[EQ]], i1 %[[CMP1]], i1 %[[CMP0]]
// CHECK: ret i1 %[[R]]
Ord::cmp(&a, &b).is_ge()
}

0 comments on commit e916e24

Please sign in to comment.