Skip to content

Commit

Permalink
Even more optimal Ord implementation for integers
Browse files Browse the repository at this point in the history
  • Loading branch information
scottmcm committed Sep 2, 2019
1 parent dfd43f0 commit 6fcc3dc
Show file tree
Hide file tree
Showing 2 changed files with 69 additions and 10 deletions.
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
}

0 comments on commit 6fcc3dc

Please sign in to comment.