Skip to content

Commit d5cf045

Browse files
committed
Auto merge of rust-lang#118310 - scottmcm:three-way-compare, r=<try>
Add `Ord::cmp` for primitives as a `BinOp` in MIR There are dozens of reasonable ways to implement `Ord::cmp` for integers using comparison, bit-ops, and branches. Those differences are irrelevant at the rust level, however, so we can make things better by adding `BinOp::Cmp` at the MIR level: 1. Exactly how to implement it is left up to the backends, so LLVM can use whatever pattern its optimizer best recognizes and cranelift can use whichever pattern codegens the fastest. 2. By not inlining those details for every use of `cmp`, we drastically reduce the amount of MIR generated for `derive`d `PartialOrd`, while also making it more amenable to MIR-level optimizations. Having extremely careful `if` ordering to μoptimize resource usage on broadwell (rust-lang#63767) is great, but it really feels to me like libcore is the wrong place to put that logic. Similarly, using subtraction [tricks](https://graphics.stanford.edu/~seander/bithacks.html#CopyIntegerSign) (rust-lang#105840) is arguably even nicer, but depends on the optimizer understanding it (llvm/llvm-project#73417) to be practical. Or maybe [bitor is better than add](https://discourse.llvm.org/t/representing-in-ir/67369/2?u=scottmcm)? But maybe only on a future version that [has `or disjoint` support](https://discourse.llvm.org/t/rfc-add-or-disjoint-flag/75036?u=scottmcm)? And just because one of those forms happens to be good for LLVM, there's no guarantee that it'd be the same form that GCC or Cranelift would rather see -- especially given their very different optimizers. Not to mention that if LLVM gets a spaceship intrinsic -- [which it should](https://rust-lang.zulipchat.com/#narrow/stream/131828-t-compiler/topic/Suboptimal.20inlining.20in.20std.20function.20.60binary_search.60/near/404250586) -- we'll need at least a rustc intrinsic to be able to call it. As for simplifying it in Rust, we now regularly inline `{integer}::partial_cmp`, but it's quite a large amount of IR. The best way to see that is with rust-lang@8811efa#diff-d134c32d028fbe2bf835fef2df9aca9d13332dd82284ff21ee7ebf717bfa4765R113 -- I added a new pre-codegen MIR test for a simple 3-tuple struct, and this PR change it from 36 locals and 26 basic blocks down to 24 locals and 8 basic blocks. Even better, as soon as the construct-`Some`-then-match-it-in-same-BB noise is cleaned up, this'll expose the `Cmp == 0` branches clearly in MIR, so that an InstCombine (rust-lang#105808) can simplify that to just a `BinOp::Eq` and thus fix some of our generated code perf issues. (Tracking that through today's `if a < b { Less } else if a == b { Equal } else { Greater }` would be *much* harder.) --- r? `@ghost` But first I should check that perf is ok with this ~~...and my true nemesis, tidy.~~
2 parents 3acb261 + 9cfc79a commit d5cf045

35 files changed

+557
-7
lines changed

compiler/rustc_codegen_cranelift/src/codegen_i128.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ pub(crate) fn maybe_codegen<'tcx>(
6868
Some(CValue::by_val(ret_val, lhs.layout()))
6969
}
7070
}
71-
BinOp::Lt | BinOp::Le | BinOp::Eq | BinOp::Ge | BinOp::Gt | BinOp::Ne => None,
71+
BinOp::Lt | BinOp::Le | BinOp::Eq | BinOp::Ge | BinOp::Gt | BinOp::Ne | BinOp::Cmp => None,
7272
BinOp::Shl | BinOp::ShlUnchecked | BinOp::Shr | BinOp::ShrUnchecked => None,
7373
}
7474
}
@@ -134,6 +134,7 @@ pub(crate) fn maybe_codegen_checked<'tcx>(
134134
BinOp::AddUnchecked | BinOp::SubUnchecked | BinOp::MulUnchecked => unreachable!(),
135135
BinOp::Offset => unreachable!("offset should only be used on pointers, not 128bit ints"),
136136
BinOp::Div | BinOp::Rem => unreachable!(),
137+
BinOp::Cmp => unreachable!(),
137138
BinOp::Lt | BinOp::Le | BinOp::Eq | BinOp::Ge | BinOp::Gt | BinOp::Ne => unreachable!(),
138139
BinOp::Shl | BinOp::ShlUnchecked | BinOp::Shr | BinOp::ShrUnchecked => unreachable!(),
139140
}

compiler/rustc_codegen_cranelift/src/num.rs

+23-2
Original file line numberDiff line numberDiff line change
@@ -40,13 +40,34 @@ pub(crate) fn bin_op_to_intcc(bin_op: BinOp, signed: bool) -> Option<IntCC> {
4040
})
4141
}
4242

43+
fn codegen_three_way_compare<'tcx>(
44+
fx: &mut FunctionCx<'_, '_, 'tcx>,
45+
signed: bool,
46+
lhs: Value,
47+
rhs: Value,
48+
) -> CValue<'tcx> {
49+
let gt_cc = crate::num::bin_op_to_intcc(BinOp::Gt, signed).unwrap();
50+
let lt_cc = crate::num::bin_op_to_intcc(BinOp::Lt, signed).unwrap();
51+
let gt = fx.bcx.ins().icmp(gt_cc, lhs, rhs);
52+
let lt = fx.bcx.ins().icmp(lt_cc, lhs, rhs);
53+
// Cranelift no longer has a single-bit type, so the comparison results
54+
// are already `I8`s, which we can subtract to get the -1/0/+1 we want.
55+
// See <https://github.com/bytecodealliance/wasmtime/pull/5031>.
56+
let val = fx.bcx.ins().isub(gt, lt);
57+
CValue::by_val(val, fx.layout_of(fx.tcx.ty_ordering_enum(Some(fx.mir.span))))
58+
}
59+
4360
fn codegen_compare_bin_op<'tcx>(
4461
fx: &mut FunctionCx<'_, '_, 'tcx>,
4562
bin_op: BinOp,
4663
signed: bool,
4764
lhs: Value,
4865
rhs: Value,
4966
) -> CValue<'tcx> {
67+
if bin_op == BinOp::Cmp {
68+
return codegen_three_way_compare(fx, signed, lhs, rhs);
69+
}
70+
5071
let intcc = crate::num::bin_op_to_intcc(bin_op, signed).unwrap();
5172
let val = fx.bcx.ins().icmp(intcc, lhs, rhs);
5273
CValue::by_val(val, fx.layout_of(fx.tcx.types.bool))
@@ -59,7 +80,7 @@ pub(crate) fn codegen_binop<'tcx>(
5980
in_rhs: CValue<'tcx>,
6081
) -> CValue<'tcx> {
6182
match bin_op {
62-
BinOp::Eq | BinOp::Lt | BinOp::Le | BinOp::Ne | BinOp::Ge | BinOp::Gt => {
83+
BinOp::Eq | BinOp::Lt | BinOp::Le | BinOp::Ne | BinOp::Ge | BinOp::Gt | BinOp::Cmp => {
6384
match in_lhs.layout().ty.kind() {
6485
ty::Bool | ty::Uint(_) | ty::Int(_) | ty::Char => {
6586
let signed = type_sign(in_lhs.layout().ty);
@@ -160,7 +181,7 @@ pub(crate) fn codegen_int_binop<'tcx>(
160181
}
161182
BinOp::Offset => unreachable!("Offset is not an integer operation"),
162183
// Compare binops handles by `codegen_binop`.
163-
BinOp::Eq | BinOp::Ne | BinOp::Lt | BinOp::Le | BinOp::Gt | BinOp::Ge => {
184+
BinOp::Eq | BinOp::Ne | BinOp::Lt | BinOp::Le | BinOp::Gt | BinOp::Ge | BinOp::Cmp => {
164185
unreachable!("{:?}({:?}, {:?})", bin_op, in_lhs.layout().ty, in_rhs.layout().ty);
165186
}
166187
};

compiler/rustc_codegen_gcc/src/common.rs

+4
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,10 @@ impl<'gcc, 'tcx> ConstMethods<'tcx> for CodegenCx<'gcc, 'tcx> {
104104
self.const_int(self.type_i32(), i as i64)
105105
}
106106

107+
fn const_i8(&self, i: i8) -> RValue<'gcc> {
108+
self.const_int(self.type_i8(), i as i64)
109+
}
110+
107111
fn const_u32(&self, i: u32) -> RValue<'gcc> {
108112
self.const_uint(self.type_u32(), i as u64)
109113
}

compiler/rustc_codegen_llvm/src/common.rs

+4
Original file line numberDiff line numberDiff line change
@@ -158,6 +158,10 @@ impl<'ll, 'tcx> ConstMethods<'tcx> for CodegenCx<'ll, 'tcx> {
158158
self.const_int(self.type_i32(), i as i64)
159159
}
160160

161+
fn const_i8(&self, i: i8) -> &'ll Value {
162+
self.const_int(self.type_i8(), i as i64)
163+
}
164+
161165
fn const_u32(&self, i: u32) -> &'ll Value {
162166
self.const_uint(self.type_i32(), i as u64)
163167
}

compiler/rustc_codegen_ssa/src/mir/rvalue.rs

+22
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ use crate::common::{self, IntPredicate};
77
use crate::traits::*;
88
use crate::MemFlags;
99

10+
use rustc_hir as hir;
1011
use rustc_middle::mir;
1112
use rustc_middle::mir::Operand;
1213
use rustc_middle::ty::cast::{CastTy, IntTy};
@@ -881,6 +882,27 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
881882
bx.icmp(base::bin_op_to_icmp_predicate(op.to_hir_binop(), is_signed), lhs, rhs)
882883
}
883884
}
885+
mir::BinOp::Cmp => {
886+
use std::cmp::Ordering;
887+
debug_assert!(!is_float);
888+
// FIXME: To avoid this PR changing behaviour, the operations used
889+
// here are those from <https://github.com/rust-lang/rust/pull/63767>,
890+
// as tested by `tests/codegen/integer-cmp.rs`.
891+
// Something in future might want to pick different ones. For example,
892+
// maybe the ones from Clang's `<=>` operator in C++20 (see
893+
// <https://github.com/llvm/llvm-project/issues/60012>) or once we
894+
// update to new LLVM, something to take advantage of the new folds in
895+
// <https://github.com/llvm/llvm-project/issues/59666>.
896+
let pred = |op| base::bin_op_to_icmp_predicate(op, is_signed);
897+
let is_lt = bx.icmp(pred(hir::BinOpKind::Lt), lhs, rhs);
898+
let is_ne = bx.icmp(pred(hir::BinOpKind::Ne), lhs, rhs);
899+
let ge = bx.select(
900+
is_ne,
901+
bx.cx().const_i8(Ordering::Greater as i8),
902+
bx.cx().const_i8(Ordering::Equal as i8),
903+
);
904+
bx.select(is_lt, bx.cx().const_i8(Ordering::Less as i8), ge)
905+
}
884906
}
885907
}
886908

compiler/rustc_codegen_ssa/src/traits/consts.rs

+1
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ pub trait ConstMethods<'tcx>: BackendTypes {
1919
fn const_bool(&self, val: bool) -> Self::Value;
2020
fn const_i16(&self, i: i16) -> Self::Value;
2121
fn const_i32(&self, i: i32) -> Self::Value;
22+
fn const_i8(&self, i: i8) -> Self::Value;
2223
fn const_u32(&self, i: u32) -> Self::Value;
2324
fn const_u64(&self, i: u64) -> Self::Value;
2425
fn const_u128(&self, i: u128) -> Self::Value;

compiler/rustc_const_eval/src/interpret/operand.rs

+7
Original file line numberDiff line numberDiff line change
@@ -224,6 +224,13 @@ impl<'tcx, Prov: Provenance> ImmTy<'tcx, Prov> {
224224
Self::from_scalar(Scalar::from_bool(b), layout)
225225
}
226226

227+
#[inline]
228+
pub fn from_ordering(c: std::cmp::Ordering, tcx: TyCtxt<'tcx>) -> Self {
229+
let ty = tcx.ty_ordering_enum(None);
230+
let layout = tcx.layout_of(ty::ParamEnv::reveal_all().and(ty)).unwrap();
231+
Self::from_scalar(Scalar::from_i8(c as i8), layout)
232+
}
233+
227234
#[inline]
228235
pub fn to_const_int(self) -> ConstInt {
229236
assert!(self.layout.ty.is_integral());

compiler/rustc_const_eval/src/interpret/operator.rs

+18
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,11 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
6161
}
6262

6363
impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
64+
fn three_way_compare<T: Ord>(&self, lhs: T, rhs: T) -> (ImmTy<'tcx, M::Provenance>, bool) {
65+
let res = Ord::cmp(&lhs, &rhs);
66+
return (ImmTy::from_ordering(res, *self.tcx), false);
67+
}
68+
6469
fn binary_char_op(
6570
&self,
6671
bin_op: mir::BinOp,
@@ -69,6 +74,10 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
6974
) -> (ImmTy<'tcx, M::Provenance>, bool) {
7075
use rustc_middle::mir::BinOp::*;
7176

77+
if bin_op == Cmp {
78+
return self.three_way_compare(l, r);
79+
}
80+
7281
let res = match bin_op {
7382
Eq => l == r,
7483
Ne => l != r,
@@ -231,6 +240,11 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
231240
let r = self.sign_extend(r, right_layout) as i128;
232241
return Ok((ImmTy::from_bool(op(&l, &r), *self.tcx), false));
233242
}
243+
if bin_op == Cmp {
244+
let l = self.sign_extend(l, left_layout) as i128;
245+
let r = self.sign_extend(r, right_layout) as i128;
246+
return Ok(self.three_way_compare(l, r));
247+
}
234248
let op: Option<fn(i128, i128) -> (i128, bool)> = match bin_op {
235249
Div if r == 0 => throw_ub!(DivisionByZero),
236250
Rem if r == 0 => throw_ub!(RemainderByZero),
@@ -270,6 +284,10 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
270284
}
271285
}
272286

287+
if bin_op == Cmp {
288+
return Ok(self.three_way_compare(l, r));
289+
}
290+
273291
let val = match bin_op {
274292
Eq => ImmTy::from_bool(l == r, *self.tcx),
275293
Ne => ImmTy::from_bool(l != r, *self.tcx),

compiler/rustc_const_eval/src/transform/promote_consts.rs

+1
Original file line numberDiff line numberDiff line change
@@ -573,6 +573,7 @@ impl<'tcx> Validator<'_, 'tcx> {
573573
| BinOp::Lt
574574
| BinOp::Ge
575575
| BinOp::Gt
576+
| BinOp::Cmp
576577
| BinOp::Offset
577578
| BinOp::Add
578579
| BinOp::AddUnchecked

compiler/rustc_const_eval/src/transform/validate.rs

+9
Original file line numberDiff line numberDiff line change
@@ -932,6 +932,15 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
932932
)
933933
}
934934
}
935+
Cmp => {
936+
for x in [a, b] {
937+
check_kinds!(
938+
x,
939+
"Cannot three-way compare non-integer type {:?}",
940+
ty::Char | ty::Uint(..) | ty::Int(..)
941+
)
942+
}
943+
}
935944
AddUnchecked | SubUnchecked | MulUnchecked | Shl | ShlUnchecked | Shr
936945
| ShrUnchecked => {
937946
for x in [a, b] {

compiler/rustc_const_eval/src/util/mod.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ pub(crate) fn binop_left_homogeneous(op: mir::BinOp) -> bool {
1919
match op {
2020
Add | AddUnchecked | Sub | SubUnchecked | Mul | MulUnchecked | Div | Rem | BitXor
2121
| BitAnd | BitOr | Offset | Shl | ShlUnchecked | Shr | ShrUnchecked => true,
22-
Eq | Ne | Lt | Le | Gt | Ge => false,
22+
Eq | Ne | Lt | Le | Gt | Ge | Cmp => false,
2323
}
2424
}
2525

@@ -30,7 +30,7 @@ pub(crate) fn binop_right_homogeneous(op: mir::BinOp) -> bool {
3030
use rustc_middle::mir::BinOp::*;
3131
match op {
3232
Add | AddUnchecked | Sub | SubUnchecked | Mul | MulUnchecked | Div | Rem | BitXor
33-
| BitAnd | BitOr | Eq | Ne | Lt | Le | Gt | Ge => true,
33+
| BitAnd | BitOr | Eq | Ne | Lt | Le | Gt | Ge | Cmp => true,
3434
Offset | Shl | ShlUnchecked | Shr | ShrUnchecked => false,
3535
}
3636
}

compiler/rustc_hir/src/lang_items.rs

+1
Original file line numberDiff line numberDiff line change
@@ -217,6 +217,7 @@ language_item_table! {
217217
Unpin, sym::unpin, unpin_trait, Target::Trait, GenericRequirement::None;
218218
Pin, sym::pin, pin_type, Target::Struct, GenericRequirement::None;
219219

220+
OrderingEnum, sym::Ordering, ordering_enum, Target::Enum, GenericRequirement::Exact(0);
220221
PartialEq, sym::eq, eq_trait, Target::Trait, GenericRequirement::Exact(1);
221222
PartialOrd, sym::partial_ord, partial_ord_trait, Target::Trait, GenericRequirement::Exact(1);
222223
CVoid, sym::c_void, c_void, Target::Enum, GenericRequirement::None;

compiler/rustc_hir_analysis/src/check/intrinsic.rs

+5
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,7 @@ pub fn intrinsic_operation_unsafety(tcx: TyCtxt<'_>, intrinsic_id: DefId) -> hir
9898
| sym::cttz
9999
| sym::bswap
100100
| sym::bitreverse
101+
| sym::three_way_compare
101102
| sym::discriminant_value
102103
| sym::type_id
103104
| sym::likely
@@ -325,6 +326,10 @@ pub fn check_intrinsic_type(tcx: TyCtxt<'_>, it: &hir::ForeignItem<'_>) {
325326
| sym::bswap
326327
| sym::bitreverse => (1, vec![param(0)], param(0)),
327328

329+
sym::three_way_compare => {
330+
(1, vec![param(0), param(0)], tcx.ty_ordering_enum(Some(it.span)))
331+
}
332+
328333
sym::add_with_overflow | sym::sub_with_overflow | sym::mul_with_overflow => {
329334
(1, vec![param(0), param(0)], Ty::new_tup(tcx, &[param(0), tcx.types.bool]))
330335
}

compiler/rustc_middle/src/mir/syntax.rs

+2
Original file line numberDiff line numberDiff line change
@@ -1429,6 +1429,8 @@ pub enum BinOp {
14291429
Ge,
14301430
/// The `>` operator (greater than)
14311431
Gt,
1432+
/// The `<=>` operator (three-way comparison, like `Ord::cmp`)
1433+
Cmp,
14321434
/// The `ptr.offset` operator
14331435
Offset,
14341436
}

compiler/rustc_middle/src/mir/tcx.rs

+7-1
Original file line numberDiff line numberDiff line change
@@ -264,6 +264,11 @@ impl<'tcx> BinOp {
264264
&BinOp::Eq | &BinOp::Lt | &BinOp::Le | &BinOp::Ne | &BinOp::Ge | &BinOp::Gt => {
265265
tcx.types.bool
266266
}
267+
&BinOp::Cmp => {
268+
// these should be integer-like types of the same size.
269+
assert_eq!(lhs_ty, rhs_ty);
270+
tcx.ty_ordering_enum(None)
271+
}
267272
}
268273
}
269274
}
@@ -300,7 +305,8 @@ impl BinOp {
300305
BinOp::Gt => hir::BinOpKind::Gt,
301306
BinOp::Le => hir::BinOpKind::Le,
302307
BinOp::Ge => hir::BinOpKind::Ge,
303-
BinOp::AddUnchecked
308+
BinOp::Cmp
309+
| BinOp::AddUnchecked
304310
| BinOp::SubUnchecked
305311
| BinOp::MulUnchecked
306312
| BinOp::ShlUnchecked

compiler/rustc_middle/src/ty/context.rs

+7
Original file line numberDiff line numberDiff line change
@@ -784,6 +784,13 @@ impl<'tcx> TyCtxt<'tcx> {
784784
self.get_lang_items(())
785785
}
786786

787+
/// Gets a `Ty` representing the [`LangItem::OrderingEnum`]
788+
#[track_caller]
789+
pub fn ty_ordering_enum(self, span: Option<Span>) -> Ty<'tcx> {
790+
let ordering_enum = self.require_lang_item(hir::LangItem::OrderingEnum, span);
791+
self.type_of(ordering_enum).no_bound_vars().unwrap()
792+
}
793+
787794
/// Obtain the given diagnostic item's `DefId`. Use `is_diagnostic_item` if you just want to
788795
/// compare against another `DefId`, since `is_diagnostic_item` is cheaper.
789796
pub fn get_diagnostic_item(self, name: Symbol) -> Option<DefId> {

compiler/rustc_mir_transform/src/lower_intrinsics.rs

+2
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,7 @@ impl<'tcx> MirPass<'tcx> for LowerIntrinsics {
8181
sym::wrapping_add
8282
| sym::wrapping_sub
8383
| sym::wrapping_mul
84+
| sym::three_way_compare
8485
| sym::unchecked_add
8586
| sym::unchecked_sub
8687
| sym::unchecked_mul
@@ -100,6 +101,7 @@ impl<'tcx> MirPass<'tcx> for LowerIntrinsics {
100101
sym::wrapping_add => BinOp::Add,
101102
sym::wrapping_sub => BinOp::Sub,
102103
sym::wrapping_mul => BinOp::Mul,
104+
sym::three_way_compare => BinOp::Cmp,
103105
sym::unchecked_add => BinOp::AddUnchecked,
104106
sym::unchecked_sub => BinOp::SubUnchecked,
105107
sym::unchecked_mul => BinOp::MulUnchecked,

compiler/rustc_smir/src/rustc_smir/convert/mir.rs

+1
Original file line numberDiff line numberDiff line change
@@ -490,6 +490,7 @@ impl<'tcx> Stable<'tcx> for mir::BinOp {
490490
BinOp::Ne => stable_mir::mir::BinOp::Ne,
491491
BinOp::Ge => stable_mir::mir::BinOp::Ge,
492492
BinOp::Gt => stable_mir::mir::BinOp::Gt,
493+
BinOp::Cmp => stable_mir::mir::BinOp::Cmp,
493494
BinOp::Offset => stable_mir::mir::BinOp::Offset,
494495
}
495496
}

compiler/rustc_span/src/symbol.rs

+1
Original file line numberDiff line numberDiff line change
@@ -1658,6 +1658,7 @@ symbols! {
16581658
thread,
16591659
thread_local,
16601660
thread_local_macro,
1661+
three_way_compare,
16611662
thumb2,
16621663
thumb_mode: "thumb-mode",
16631664
tmm_reg,

compiler/rustc_ty_utils/src/consts.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,7 @@ fn check_binop(op: mir::BinOp) -> bool {
8282
match op {
8383
Add | AddUnchecked | Sub | SubUnchecked | Mul | MulUnchecked | Div | Rem | BitXor
8484
| BitAnd | BitOr | Shl | ShlUnchecked | Shr | ShrUnchecked | Eq | Lt | Le | Ne | Ge
85-
| Gt => true,
85+
| Gt | Cmp => true,
8686
Offset => false,
8787
}
8888
}

compiler/stable_mir/src/mir/body.rs

+1
Original file line numberDiff line numberDiff line change
@@ -208,6 +208,7 @@ pub enum BinOp {
208208
Ne,
209209
Ge,
210210
Gt,
211+
Cmp,
211212
Offset,
212213
}
213214

library/core/src/cmp.rs

+8
Original file line numberDiff line numberDiff line change
@@ -352,6 +352,7 @@ pub struct AssertParamIsEq<T: Eq + ?Sized> {
352352
/// ```
353353
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)]
354354
#[stable(feature = "rust1", since = "1.0.0")]
355+
#[cfg_attr(not(bootstrap), lang = "Ordering")]
355356
#[repr(i8)]
356357
pub enum Ordering {
357358
/// An ordering where a compared value is less than another.
@@ -1513,12 +1514,19 @@ mod impls {
15131514
impl Ord for $t {
15141515
#[inline]
15151516
fn cmp(&self, other: &$t) -> Ordering {
1517+
#[cfg(bootstrap)]
1518+
{
15161519
// The order here is important to generate more optimal assembly.
15171520
// See <https://github.com/rust-lang/rust/issues/63758> for more info.
15181521
if *self < *other { Less }
15191522
else if *self == *other { Equal }
15201523
else { Greater }
15211524
}
1525+
#[cfg(not(bootstrap))]
1526+
{
1527+
crate::intrinsics::three_way_compare(*self, *other)
1528+
}
1529+
}
15221530
}
15231531
)*)
15241532
}

0 commit comments

Comments
 (0)