From 7e4ec35d0cc56ac3016e98909aad8688516a43f8 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Wed, 8 Jun 2022 14:49:32 +1000 Subject: [PATCH 01/11] const_range_contains: avoid the second comparison if possible. This is a performance win for `unicode-normalization`. Also, I find the new formulation easier to read. --- .../rustc_mir_build/src/build/matches/test.rs | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/compiler/rustc_mir_build/src/build/matches/test.rs b/compiler/rustc_mir_build/src/build/matches/test.rs index 3774a3950352..62ee73993b8e 100644 --- a/compiler/rustc_mir_build/src/build/matches/test.rs +++ b/compiler/rustc_mir_build/src/build/matches/test.rs @@ -769,14 +769,17 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { use std::cmp::Ordering::*; let tcx = self.tcx; - - let a = compare_const_vals(tcx, range.lo, value, self.param_env, range.lo.ty())?; - let b = compare_const_vals(tcx, value, range.hi, self.param_env, range.lo.ty())?; - - match (b, range.end) { - (Less, _) | (Equal, RangeEnd::Included) if a != Greater => Some(true), - _ => Some(false), - } + let param_env = self.param_env; + let ty = range.lo.ty(); + // For performance, it's important to only do the second + // `compare_const_vals` if necessary. + Some( + matches!(compare_const_vals(tcx, range.lo, value, param_env, ty)?, Less | Equal) + && matches!( + (compare_const_vals(tcx, value, range.hi, param_env, ty)?, range.end), + (Less, _) | (Equal, RangeEnd::Included) + ), + ) } fn values_not_contained_in_range( From c4cd04480bdfca84274dcbe80dae710bdbe0bd59 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Wed, 8 Jun 2022 17:02:06 +1000 Subject: [PATCH 02/11] sort_candidates: avoid the second comparison if possible. This is a performance win for `unicode-normalization`. The commit also removes the closure, which isn't necessary. And reformulates the comparison into a form I find easier to read. --- .../rustc_mir_build/src/build/matches/test.rs | 42 ++++++++----------- 1 file changed, 18 insertions(+), 24 deletions(-) diff --git a/compiler/rustc_mir_build/src/build/matches/test.rs b/compiler/rustc_mir_build/src/build/matches/test.rs index 62ee73993b8e..d98837ad7dff 100644 --- a/compiler/rustc_mir_build/src/build/matches/test.rs +++ b/compiler/rustc_mir_build/src/build/matches/test.rs @@ -632,39 +632,33 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { } (&TestKind::Range(test), &PatKind::Range(pat)) => { + use std::cmp::Ordering::*; + if test == pat { self.candidate_without_match_pair(match_pair_index, candidate); return Some(0); } - let no_overlap = (|| { - use rustc_hir::RangeEnd::*; - use std::cmp::Ordering::*; + let tcx = self.tcx; + let test_ty = test.lo.ty(); - let tcx = self.tcx; - - let test_ty = test.lo.ty(); - let lo = compare_const_vals(tcx, test.lo, pat.hi, self.param_env, test_ty)?; - let hi = compare_const_vals(tcx, test.hi, pat.lo, self.param_env, test_ty)?; - - match (test.end, pat.end, lo, hi) { - // pat < test - (_, _, Greater, _) | - (_, Excluded, Equal, _) | - // pat > test - (_, _, _, Less) | - (Excluded, _, _, Equal) => Some(true), - _ => Some(false), - } - })(); - - if let Some(true) = no_overlap { - // Testing range does not overlap with pattern range, - // so the pattern can be matched only if this test fails. + // For performance, it's important to only do the second + // `compare_const_vals` if necessary. + let no_overlap = if matches!( + (compare_const_vals(tcx, test.hi, pat.lo, self.param_env, test_ty)?, test.end), + (Less, _) | (Equal, RangeEnd::Excluded) // test < pat + ) || matches!( + (compare_const_vals(tcx, test.lo, pat.hi, self.param_env, test_ty)?, pat.end), + (Greater, _) | (Equal, RangeEnd::Excluded) // test > pat + ) { Some(1) } else { None - } + }; + + // If the testing range does not overlap with pattern range, + // the pattern can be matched only if this test fails. + no_overlap } (&TestKind::Range(range), &PatKind::Constant { value }) => { From be6c36414226d8ff6ad5047870d6ec7a0b2bd505 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Thu, 9 Jun 2022 11:51:41 +1000 Subject: [PATCH 03/11] simplify_match_pair: avoid the second comparison if possible. Also, the `try_to_bits` always succeeds, so use `unwrap`. --- .../src/build/matches/simplify.rs | 21 +++++++++++-------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/compiler/rustc_mir_build/src/build/matches/simplify.rs b/compiler/rustc_mir_build/src/build/matches/simplify.rs index b4a0c965d6b7..c6298904140c 100644 --- a/compiler/rustc_mir_build/src/build/matches/simplify.rs +++ b/compiler/rustc_mir_build/src/build/matches/simplify.rs @@ -227,15 +227,18 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { _ => (None, 0), }; if let Some((min, max, sz)) = range { - if let (Some(lo), Some(hi)) = (lo.try_to_bits(sz), hi.try_to_bits(sz)) { - // We want to compare ranges numerically, but the order of the bitwise - // representation of signed integers does not match their numeric order. - // Thus, to correct the ordering, we need to shift the range of signed - // integers to correct the comparison. This is achieved by XORing with a - // bias (see pattern/_match.rs for another pertinent example of this - // pattern). - let (lo, hi) = (lo ^ bias, hi ^ bias); - if lo <= min && (hi > max || hi == max && end == RangeEnd::Included) { + // We want to compare ranges numerically, but the order of the bitwise + // representation of signed integers does not match their numeric order. Thus, + // to correct the ordering, we need to shift the range of signed integers to + // correct the comparison. This is achieved by XORing with a bias (see + // pattern/_match.rs for another pertinent example of this pattern). + // + // Also, for performance, it's important to only do the second `try_to_bits` if + // necessary. + let lo = lo.try_to_bits(sz).unwrap() ^ bias; + if lo <= min { + let hi = hi.try_to_bits(sz).unwrap() ^ bias; + if hi > max || hi == max && end == RangeEnd::Included { // Irrefutable pattern match. return Ok(()); } From d5a13e2ca0c45a7f25d783cc94e447246cb97afd Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Thu, 9 Jun 2022 09:08:04 +1000 Subject: [PATCH 04/11] Remove dead code from `compare_const_vals`. It's never executed when running the entire test suite. I think it's because of the early return at the top of the function if `a.ty() != ty` succeeds. --- compiler/rustc_mir_build/src/thir/pattern/mod.rs | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/compiler/rustc_mir_build/src/thir/pattern/mod.rs b/compiler/rustc_mir_build/src/thir/pattern/mod.rs index f5d957e30ff0..1c35e402a99e 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/mod.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/mod.rs @@ -15,7 +15,6 @@ use rustc_hir::def::{CtorOf, DefKind, Res}; use rustc_hir::pat_util::EnumerateAndAdjustIterator; use rustc_hir::RangeEnd; use rustc_index::vec::Idx; -use rustc_middle::mir::interpret::{get_slice_bytes, ConstValue}; use rustc_middle::mir::interpret::{ErrorHandled, LitToConstError, LitToConstInput}; use rustc_middle::mir::{self, UserTypeProjection}; use rustc_middle::mir::{BorrowKind, Field, Mutability}; @@ -795,15 +794,5 @@ pub(crate) fn compare_const_vals<'tcx>( }; } - if let ty::Str = ty.kind() && let ( - Some(a_val @ ConstValue::Slice { .. }), - Some(b_val @ ConstValue::Slice { .. }), - ) = (a.try_to_value(tcx), b.try_to_value(tcx)) - { - let a_bytes = get_slice_bytes(&tcx, a_val); - let b_bytes = get_slice_bytes(&tcx, b_val); - return from_bool(a_bytes == b_bytes); - } - fallback() } From 9b4b34a0a673a52991c9579488e6b083f17dd3f2 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Thu, 9 Jun 2022 09:24:08 +1000 Subject: [PATCH 05/11] Assert type equality of `a` and `b` in `compare_const_vals`. Because they're always equal. --- compiler/rustc_mir_build/src/thir/pattern/mod.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/compiler/rustc_mir_build/src/thir/pattern/mod.rs b/compiler/rustc_mir_build/src/thir/pattern/mod.rs index 1c35e402a99e..3161d95fff84 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/mod.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/mod.rs @@ -754,12 +754,14 @@ pub(crate) fn compare_const_vals<'tcx>( param_env: ty::ParamEnv<'tcx>, ty: Ty<'tcx>, ) -> Option { + assert_eq!(a.ty(), b.ty()); + let from_bool = |v: bool| v.then_some(Ordering::Equal); let fallback = || from_bool(a == b); // Use the fallback if any type differs - if a.ty() != b.ty() || a.ty() != ty { + if a.ty() != ty { return fallback(); } From b67635fdfd61d597f0145251dbe4ccb9c2487b8e Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Thu, 9 Jun 2022 09:27:12 +1000 Subject: [PATCH 06/11] Remove one use of `compare_const_vals`. A direct comparison has the same effect. This also avoids the need for a type test within `compare_const_vals`. --- .../src/thir/pattern/deconstruct_pat.rs | 11 +---------- compiler/rustc_mir_build/src/thir/pattern/mod.rs | 6 +----- 2 files changed, 2 insertions(+), 15 deletions(-) diff --git a/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs b/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs index 26532ae33d0c..d97da1c8e1dd 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs @@ -848,16 +848,7 @@ impl<'tcx> Constructor<'tcx> { (Str(self_val), Str(other_val)) => { // FIXME Once valtrees are available we can directly use the bytes // in the `Str` variant of the valtree for the comparison here. - match compare_const_vals( - pcx.cx.tcx, - *self_val, - *other_val, - pcx.cx.param_env, - pcx.ty, - ) { - Some(comparison) => comparison == Ordering::Equal, - None => false, - } + self_val == other_val } (Slice(self_slice), Slice(other_slice)) => self_slice.is_covered_by(*other_slice), diff --git a/compiler/rustc_mir_build/src/thir/pattern/mod.rs b/compiler/rustc_mir_build/src/thir/pattern/mod.rs index 3161d95fff84..1029d0903c7d 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/mod.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/mod.rs @@ -755,16 +755,12 @@ pub(crate) fn compare_const_vals<'tcx>( ty: Ty<'tcx>, ) -> Option { assert_eq!(a.ty(), b.ty()); + assert_eq!(a.ty(), ty); let from_bool = |v: bool| v.then_some(Ordering::Equal); let fallback = || from_bool(a == b); - // Use the fallback if any type differs - if a.ty() != ty { - return fallback(); - } - if a == b { return from_bool(true); } From fab85ddbebcd99867344f05b610dc74709abbe6d Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Thu, 9 Jun 2022 09:38:09 +1000 Subject: [PATCH 07/11] Inline and remove `fallback` closure. --- compiler/rustc_mir_build/src/thir/pattern/mod.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/compiler/rustc_mir_build/src/thir/pattern/mod.rs b/compiler/rustc_mir_build/src/thir/pattern/mod.rs index 1029d0903c7d..30c86355c882 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/mod.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/mod.rs @@ -759,8 +759,6 @@ pub(crate) fn compare_const_vals<'tcx>( let from_bool = |v: bool| v.then_some(Ordering::Equal); - let fallback = || from_bool(a == b); - if a == b { return from_bool(true); } @@ -792,5 +790,5 @@ pub(crate) fn compare_const_vals<'tcx>( }; } - fallback() + from_bool(a == b) } From 3ab6ef19386c8df6d43bd474f356d2bc38942350 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Thu, 9 Jun 2022 09:38:30 +1000 Subject: [PATCH 08/11] Remove `from_bool` closure. The code is clearer and simpler without it. Note that the `a == b` early return at the top of the function means the `a == b` test at the end of the function could never succeed. --- compiler/rustc_mir_build/src/thir/pattern/mod.rs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/compiler/rustc_mir_build/src/thir/pattern/mod.rs b/compiler/rustc_mir_build/src/thir/pattern/mod.rs index 30c86355c882..3e5e12d2286b 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/mod.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/mod.rs @@ -757,10 +757,8 @@ pub(crate) fn compare_const_vals<'tcx>( assert_eq!(a.ty(), b.ty()); assert_eq!(a.ty(), ty); - let from_bool = |v: bool| v.then_some(Ordering::Equal); - if a == b { - return from_bool(true); + return Some(Ordering::Equal); } let a_bits = a.try_eval_bits(tcx, param_env, ty); @@ -790,5 +788,5 @@ pub(crate) fn compare_const_vals<'tcx>( }; } - from_bool(a == b) + None } From 246a5e08bf6befc14f43ec6a30f2deb463f175aa Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Thu, 9 Jun 2022 09:46:23 +1000 Subject: [PATCH 09/11] Remove `ty` arg from `compare_const_vals`. It's now only used in no-longer-interesting assertion. --- compiler/rustc_mir_build/src/build/matches/test.rs | 14 ++++---------- .../src/thir/pattern/deconstruct_pat.rs | 10 ++-------- compiler/rustc_mir_build/src/thir/pattern/mod.rs | 5 ++--- 3 files changed, 8 insertions(+), 21 deletions(-) diff --git a/compiler/rustc_mir_build/src/build/matches/test.rs b/compiler/rustc_mir_build/src/build/matches/test.rs index d98837ad7dff..598da80c574a 100644 --- a/compiler/rustc_mir_build/src/build/matches/test.rs +++ b/compiler/rustc_mir_build/src/build/matches/test.rs @@ -639,16 +639,13 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { return Some(0); } - let tcx = self.tcx; - let test_ty = test.lo.ty(); - // For performance, it's important to only do the second // `compare_const_vals` if necessary. let no_overlap = if matches!( - (compare_const_vals(tcx, test.hi, pat.lo, self.param_env, test_ty)?, test.end), + (compare_const_vals(self.tcx, test.hi, pat.lo, self.param_env)?, test.end), (Less, _) | (Equal, RangeEnd::Excluded) // test < pat ) || matches!( - (compare_const_vals(tcx, test.lo, pat.hi, self.param_env, test_ty)?, pat.end), + (compare_const_vals(self.tcx, test.lo, pat.hi, self.param_env)?, pat.end), (Greater, _) | (Equal, RangeEnd::Excluded) // test > pat ) { Some(1) @@ -762,15 +759,12 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { ) -> Option { use std::cmp::Ordering::*; - let tcx = self.tcx; - let param_env = self.param_env; - let ty = range.lo.ty(); // For performance, it's important to only do the second // `compare_const_vals` if necessary. Some( - matches!(compare_const_vals(tcx, range.lo, value, param_env, ty)?, Less | Equal) + matches!(compare_const_vals(self.tcx, range.lo, value, self.param_env)?, Less | Equal) && matches!( - (compare_const_vals(tcx, value, range.hi, param_env, ty)?, range.end), + (compare_const_vals(self.tcx, value, range.hi, self.param_env)?, range.end), (Less, _) | (Equal, RangeEnd::Included) ), ) diff --git a/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs b/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs index d97da1c8e1dd..60db98073a3b 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs @@ -828,14 +828,8 @@ impl<'tcx> Constructor<'tcx> { FloatRange(other_from, other_to, other_end), ) => { match ( - compare_const_vals(pcx.cx.tcx, *self_to, *other_to, pcx.cx.param_env, pcx.ty), - compare_const_vals( - pcx.cx.tcx, - *self_from, - *other_from, - pcx.cx.param_env, - pcx.ty, - ), + compare_const_vals(pcx.cx.tcx, *self_to, *other_to, pcx.cx.param_env), + compare_const_vals(pcx.cx.tcx, *self_from, *other_from, pcx.cx.param_env), ) { (Some(to), Some(from)) => { (from == Ordering::Greater || from == Ordering::Equal) diff --git a/compiler/rustc_mir_build/src/thir/pattern/mod.rs b/compiler/rustc_mir_build/src/thir/pattern/mod.rs index 3e5e12d2286b..a72af8be83e4 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/mod.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/mod.rs @@ -128,7 +128,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> { ) -> PatKind<'tcx> { assert_eq!(lo.ty(), ty); assert_eq!(hi.ty(), ty); - let cmp = compare_const_vals(self.tcx, lo, hi, self.param_env, ty); + let cmp = compare_const_vals(self.tcx, lo, hi, self.param_env); match (end, cmp) { // `x..y` where `x < y`. // Non-empty because the range includes at least `x`. @@ -752,15 +752,14 @@ pub(crate) fn compare_const_vals<'tcx>( a: mir::ConstantKind<'tcx>, b: mir::ConstantKind<'tcx>, param_env: ty::ParamEnv<'tcx>, - ty: Ty<'tcx>, ) -> Option { assert_eq!(a.ty(), b.ty()); - assert_eq!(a.ty(), ty); if a == b { return Some(Ordering::Equal); } + let ty = a.ty(); let a_bits = a.try_eval_bits(tcx, param_env, ty); let b_bits = b.try_eval_bits(tcx, param_env, ty); From 73c52b724a07900808483a5f06b928d703097cf1 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Thu, 9 Jun 2022 11:15:03 +1000 Subject: [PATCH 10/11] compare_const_vals: Use infallible evaluation. Because these evaluations can never fail. --- .../rustc_mir_build/src/thir/pattern/mod.rs | 48 +++++++++---------- 1 file changed, 22 insertions(+), 26 deletions(-) diff --git a/compiler/rustc_mir_build/src/thir/pattern/mod.rs b/compiler/rustc_mir_build/src/thir/pattern/mod.rs index a72af8be83e4..d07a618f8155 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/mod.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/mod.rs @@ -760,32 +760,28 @@ pub(crate) fn compare_const_vals<'tcx>( } let ty = a.ty(); - let a_bits = a.try_eval_bits(tcx, param_env, ty); - let b_bits = b.try_eval_bits(tcx, param_env, ty); + let a = a.eval_bits(tcx, param_env, ty); + let b = b.eval_bits(tcx, param_env, ty); - if let (Some(a), Some(b)) = (a_bits, b_bits) { - use rustc_apfloat::Float; - return match *ty.kind() { - ty::Float(ty::FloatTy::F32) => { - let l = rustc_apfloat::ieee::Single::from_bits(a); - let r = rustc_apfloat::ieee::Single::from_bits(b); - l.partial_cmp(&r) - } - ty::Float(ty::FloatTy::F64) => { - let l = rustc_apfloat::ieee::Double::from_bits(a); - let r = rustc_apfloat::ieee::Double::from_bits(b); - l.partial_cmp(&r) - } - ty::Int(ity) => { - use rustc_middle::ty::layout::IntegerExt; - let size = rustc_target::abi::Integer::from_int_ty(&tcx, ity).size(); - let a = size.sign_extend(a); - let b = size.sign_extend(b); - Some((a as i128).cmp(&(b as i128))) - } - _ => Some(a.cmp(&b)), - }; + use rustc_apfloat::Float; + match *ty.kind() { + ty::Float(ty::FloatTy::F32) => { + let a = rustc_apfloat::ieee::Single::from_bits(a); + let b = rustc_apfloat::ieee::Single::from_bits(b); + a.partial_cmp(&b) + } + ty::Float(ty::FloatTy::F64) => { + let a = rustc_apfloat::ieee::Double::from_bits(a); + let b = rustc_apfloat::ieee::Double::from_bits(b); + a.partial_cmp(&b) + } + ty::Int(ity) => { + use rustc_middle::ty::layout::IntegerExt; + let size = rustc_target::abi::Integer::from_int_ty(&tcx, ity).size(); + let a = size.sign_extend(a); + let b = size.sign_extend(b); + Some((a as i128).cmp(&(b as i128))) + } + _ => Some(a.cmp(&b)), } - - None } From bdbf9b297b2d3372dfe70763643942e008933207 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Thu, 9 Jun 2022 10:23:39 +1000 Subject: [PATCH 11/11] compare_const_vals: add a special case for certain ranges. This commit removes the `a == b` early return, which isn't useful in practice, and replaces it with one that helps matches with many ranges, including char ranges. --- .../rustc_mir_build/src/thir/pattern/mod.rs | 23 +++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) diff --git a/compiler/rustc_mir_build/src/thir/pattern/mod.rs b/compiler/rustc_mir_build/src/thir/pattern/mod.rs index d07a618f8155..a13748a2d474 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/mod.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/mod.rs @@ -15,7 +15,9 @@ use rustc_hir::def::{CtorOf, DefKind, Res}; use rustc_hir::pat_util::EnumerateAndAdjustIterator; use rustc_hir::RangeEnd; use rustc_index::vec::Idx; -use rustc_middle::mir::interpret::{ErrorHandled, LitToConstError, LitToConstInput}; +use rustc_middle::mir::interpret::{ + ConstValue, ErrorHandled, LitToConstError, LitToConstInput, Scalar, +}; use rustc_middle::mir::{self, UserTypeProjection}; use rustc_middle::mir::{BorrowKind, Field, Mutability}; use rustc_middle::thir::{Ascription, BindingMode, FieldPat, LocalVarId, Pat, PatKind, PatRange}; @@ -755,11 +757,24 @@ pub(crate) fn compare_const_vals<'tcx>( ) -> Option { assert_eq!(a.ty(), b.ty()); - if a == b { - return Some(Ordering::Equal); + let ty = a.ty(); + + // This code is hot when compiling matches with many ranges. So we + // special-case extraction of evaluated scalars for speed, for types where + // raw data comparisons are appropriate. E.g. `unicode-normalization` has + // many ranges such as '\u{037A}'..='\u{037F}', and chars can be compared + // in this way. + match ty.kind() { + ty::Float(_) | ty::Int(_) => {} // require special handling, see below + _ => match (a, b) { + ( + mir::ConstantKind::Val(ConstValue::Scalar(Scalar::Int(a)), _a_ty), + mir::ConstantKind::Val(ConstValue::Scalar(Scalar::Int(b)), _b_ty), + ) => return Some(a.cmp(&b)), + _ => {} + }, } - let ty = a.ty(); let a = a.eval_bits(tcx, param_env, ty); let b = b.eval_bits(tcx, param_env, ty);