Skip to content
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

Even more optimal Ord implementation for integers #64082

Closed
wants to merge 1 commit into from
Closed
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
29 changes: 24 additions & 5 deletions src/libcore/cmp.rs
Original file line number Diff line number Diff line change
Expand Up @@ -638,6 +638,22 @@ impl PartialOrd for Ordering {
fn partial_cmp(&self, other: &Ordering) -> Option<Ordering> {
(*self as i32).partial_cmp(&(*other as i32))
}
#[inline]
fn lt(&self, other: &Ordering) -> bool {
(*self as i32).lt(&(*other as i32))
}
#[inline]
fn le(&self, other: &Ordering) -> bool {
(*self as i32).le(&(*other as i32))
}
#[inline]
fn gt(&self, other: &Ordering) -> bool {
(*self as i32).gt(&(*other as i32))
}
#[inline]
fn ge(&self, other: &Ordering) -> bool {
(*self as i32).ge(&(*other as i32))
}
}

/// Trait for values that can be compared for a sort-order.
Expand Down Expand Up @@ -1012,11 +1028,14 @@ mod impls {
impl Ord for $t {
#[inline]
fn cmp(&self, other: &$t) -> Ordering {
// The order here is important to generate more optimal assembly.
// See <https://github.com/rust-lang/rust/issues/63758> for more info.
if *self < *other { Less }
else if *self == *other { Equal }
else { Greater }
// Like in `signum`, this approach allows the result to be
// computed with a simpler subtraction instead of needing a
// conditional move (which, as of 2018 x86 hardware, are never
// predicted), for a small cycles & code size improvement.
// See <https://github.com/rust-lang/rust/pull/64082> for more info.
let diff = (*self > *other) as i8 - (*self < *other) as i8;
// Sound because Ordering's three variants are {-1, 0, 1}.
unsafe { crate::mem::transmute(diff) }
}
}
)*)
Expand Down
50 changes: 45 additions & 5 deletions src/test/codegen/integer-cmp.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// This is test for more optimal Ord implementation for integers.
// See <https://github.com/rust-lang/rust/issues/63758> for more info.
// See <https://github.com/rust-lang/rust/pull/64082> for more info.

// compile-flags: -C opt-level=3

Expand All @@ -10,19 +10,59 @@ use std::cmp::Ordering;
// CHECK-LABEL: @cmp_signed
#[no_mangle]
pub fn cmp_signed(a: i64, b: i64) -> Ordering {
// CHECK: icmp sgt
// CHECK: zext i1
// CHECK: icmp slt
// CHECK: icmp ne
// CHECK: zext i1
// CHECK: select i1
// CHECK: sub nsw
// CHECK-NOT: select
a.cmp(&b)
}

// CHECK-LABEL: @cmp_unsigned
#[no_mangle]
pub fn cmp_unsigned(a: u32, b: u32) -> Ordering {
// CHECK: icmp ugt
// CHECK: zext i1
// CHECK: icmp ult
// CHECK: icmp ne
// CHECK: zext i1
// CHECK: select i1
// CHECK: sub nsw
// CHECK-NOT: select
a.cmp(&b)
}

// CHECK-LABEL: @cmp_signed_lt
#[no_mangle]
pub fn cmp_signed_lt(a: &i64, b: &i64) -> bool {
// CHECK: icmp slt
// CHECK-NOT: sub
// CHECK-NOT: select
Ord::cmp(a, b) < Ordering::Equal
}

// CHECK-LABEL: @cmp_unsigned_lt
#[no_mangle]
pub fn cmp_unsigned_lt(a: &u32, b: &u32) -> bool {
// CHECK: icmp ult
// CHECK-NOT: sub
// CHECK-NOT: select
Ord::cmp(a, b) < Ordering::Equal
}

// CHECK-LABEL: @cmp_signed_eq
#[no_mangle]
pub fn cmp_signed_eq(a: &i64, b: &i64) -> bool {
// CHECK: icmp eq
// CHECK-NOT: sub
// CHECK-NOT: select
Ord::cmp(a, b) == Ordering::Equal
}

// CHECK-LABEL: @cmp_unsigned_eq
#[no_mangle]
pub fn cmp_unsigned_eq(a: &u32, b: &u32) -> bool {
// CHECK: icmp eq
// CHECK-NOT: sub
// CHECK-NOT: select
Ord::cmp(a, b) == Ordering::Equal
}