Skip to content

Update some comparison codegen tests now that they pass in LLVM20 #137197

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Mar 1, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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()
}
Loading