Skip to content

Commit 6fcc3dc

Browse files
committed
Even more optimal Ord implementation for integers
1 parent dfd43f0 commit 6fcc3dc

File tree

2 files changed

+69
-10
lines changed

2 files changed

+69
-10
lines changed

src/libcore/cmp.rs

+24-5
Original file line numberDiff line numberDiff line change
@@ -638,6 +638,22 @@ impl PartialOrd for Ordering {
638638
fn partial_cmp(&self, other: &Ordering) -> Option<Ordering> {
639639
(*self as i32).partial_cmp(&(*other as i32))
640640
}
641+
#[inline]
642+
fn lt(&self, other: &Ordering) -> bool {
643+
(*self as i32).lt(&(*other as i32))
644+
}
645+
#[inline]
646+
fn le(&self, other: &Ordering) -> bool {
647+
(*self as i32).le(&(*other as i32))
648+
}
649+
#[inline]
650+
fn gt(&self, other: &Ordering) -> bool {
651+
(*self as i32).gt(&(*other as i32))
652+
}
653+
#[inline]
654+
fn ge(&self, other: &Ordering) -> bool {
655+
(*self as i32).ge(&(*other as i32))
656+
}
641657
}
642658

643659
/// Trait for values that can be compared for a sort-order.
@@ -1012,11 +1028,14 @@ mod impls {
10121028
impl Ord for $t {
10131029
#[inline]
10141030
fn cmp(&self, other: &$t) -> Ordering {
1015-
// The order here is important to generate more optimal assembly.
1016-
// See <https://github.com/rust-lang/rust/issues/63758> for more info.
1017-
if *self < *other { Less }
1018-
else if *self == *other { Equal }
1019-
else { Greater }
1031+
// Like in `signum`, this approach allows the result to be
1032+
// computed with a simpler subtraction instead of needing a
1033+
// conditional move (which, as of 2018 x86 hardware, are never
1034+
// predicted), for a small cycles & code size improvement.
1035+
// See <https://github.com/rust-lang/rust/pull/64082> for more info.
1036+
let diff = (*self > *other) as i8 - (*self < *other) as i8;
1037+
// Sound because Ordering's three variants are {-1, 0, 1}.
1038+
unsafe { crate::mem::transmute(diff) }
10201039
}
10211040
}
10221041
)*)

src/test/codegen/integer-cmp.rs

+45-5
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
// This is test for more optimal Ord implementation for integers.
2-
// See <https://github.com/rust-lang/rust/issues/63758> for more info.
2+
// See <https://github.com/rust-lang/rust/pull/64082> for more info.
33

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

@@ -10,19 +10,59 @@ use std::cmp::Ordering;
1010
// CHECK-LABEL: @cmp_signed
1111
#[no_mangle]
1212
pub fn cmp_signed(a: i64, b: i64) -> Ordering {
13+
// CHECK: icmp sgt
14+
// CHECK: zext i1
1315
// CHECK: icmp slt
14-
// CHECK: icmp ne
1516
// CHECK: zext i1
16-
// CHECK: select i1
17+
// CHECK: sub nsw
18+
// CHECK-NOT: select
1719
a.cmp(&b)
1820
}
1921

2022
// CHECK-LABEL: @cmp_unsigned
2123
#[no_mangle]
2224
pub fn cmp_unsigned(a: u32, b: u32) -> Ordering {
25+
// CHECK: icmp ugt
26+
// CHECK: zext i1
2327
// CHECK: icmp ult
24-
// CHECK: icmp ne
2528
// CHECK: zext i1
26-
// CHECK: select i1
29+
// CHECK: sub nsw
30+
// CHECK-NOT: select
2731
a.cmp(&b)
2832
}
33+
34+
// CHECK-LABEL: @cmp_signed_lt
35+
#[no_mangle]
36+
pub fn cmp_signed_lt(a: &i64, b: &i64) -> bool {
37+
// CHECK: icmp slt
38+
// CHECK-NOT: sub
39+
// CHECK-NOT: select
40+
Ord::cmp(a, b) < Ordering::Equal
41+
}
42+
43+
// CHECK-LABEL: @cmp_unsigned_lt
44+
#[no_mangle]
45+
pub fn cmp_unsigned_lt(a: &u32, b: &u32) -> bool {
46+
// CHECK: icmp ult
47+
// CHECK-NOT: sub
48+
// CHECK-NOT: select
49+
Ord::cmp(a, b) < Ordering::Equal
50+
}
51+
52+
// CHECK-LABEL: @cmp_signed_eq
53+
#[no_mangle]
54+
pub fn cmp_signed_eq(a: &i64, b: &i64) -> bool {
55+
// CHECK: icmp eq
56+
// CHECK-NOT: sub
57+
// CHECK-NOT: select
58+
Ord::cmp(a, b) == Ordering::Equal
59+
}
60+
61+
// CHECK-LABEL: @cmp_unsigned_eq
62+
#[no_mangle]
63+
pub fn cmp_unsigned_eq(a: &u32, b: &u32) -> bool {
64+
// CHECK: icmp eq
65+
// CHECK-NOT: sub
66+
// CHECK-NOT: select
67+
Ord::cmp(a, b) == Ordering::Equal
68+
}

0 commit comments

Comments
 (0)