about summary refs log tree commit diff
diff options
context:
space:
mode:
authorNicholas Nethercote <n.nethercote@gmail.com>2022-06-08 17:02:06 +1000
committerNicholas Nethercote <n.nethercote@gmail.com>2022-06-16 10:52:19 +1000
commitc4cd04480bdfca84274dcbe80dae710bdbe0bd59 (patch)
treecca237f77482894f9e28de254b9b3dc596fbf4ae
parent7e4ec35d0cc56ac3016e98909aad8688516a43f8 (diff)
downloadrust-c4cd04480bdfca84274dcbe80dae710bdbe0bd59.tar.gz
rust-c4cd04480bdfca84274dcbe80dae710bdbe0bd59.zip
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.
-rw-r--r--compiler/rustc_mir_build/src/build/matches/test.rs44
1 files changed, 19 insertions, 25 deletions
diff --git a/compiler/rustc_mir_build/src/build/matches/test.rs b/compiler/rustc_mir_build/src/build/matches/test.rs
index 62ee73993b8..d98837ad7df 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 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.
+                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),
+                    (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 }) => {