diff options
| author | Guillaume Gomez <guillaume1.gomez@gmail.com> | 2024-02-29 17:08:37 +0100 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2024-02-29 17:08:37 +0100 |
| commit | 2e0a26a32a51faba018d70310869e73b2743c959 (patch) | |
| tree | 39d6003984b7d34801406e1f8e18ae6bdbea9ab8 | |
| parent | 9df7f26b1b0b3cfe7dc8224514d1685d11b1e495 (diff) | |
| parent | 7c6960e289c627bc5533c03769ff45b03a141be9 (diff) | |
| download | rust-2e0a26a32a51faba018d70310869e73b2743c959.tar.gz rust-2e0a26a32a51faba018d70310869e73b2743c959.zip | |
Rollup merge of #121376 - Nadrieril:mir-half-ranges, r=pnkfelix
Skip unnecessary comparison with half-open range patterns This is the last remaining detail in the implementation of half-open range patterns. Until now, a half-open range pattern like `10..` was converted to `10..T::MAX` before lowering to MIR, which generated an extra pointless comparison. With this PR we don't generate it.
| -rw-r--r-- | compiler/rustc_middle/src/thir.rs | 18 | ||||
| -rw-r--r-- | compiler/rustc_mir_build/src/build/matches/test.rs | 52 |
2 files changed, 32 insertions, 38 deletions
diff --git a/compiler/rustc_middle/src/thir.rs b/compiler/rustc_middle/src/thir.rs index 2ad592174f1..65875ff3f9a 100644 --- a/compiler/rustc_middle/src/thir.rs +++ b/compiler/rustc_middle/src/thir.rs @@ -815,7 +815,9 @@ pub enum PatKind<'tcx> { /// The boundaries must be of the same type and that type must be numeric. #[derive(Clone, Debug, PartialEq, HashStable, TypeVisitable)] pub struct PatRange<'tcx> { + /// Must not be `PosInfinity`. pub lo: PatRangeBoundary<'tcx>, + /// Must not be `NegInfinity`. pub hi: PatRangeBoundary<'tcx>, #[type_visitable(ignore)] pub end: RangeEnd, @@ -958,22 +960,6 @@ impl<'tcx> PatRangeBoundary<'tcx> { Self::NegInfinity | Self::PosInfinity => None, } } - #[inline] - pub fn to_const(self, ty: Ty<'tcx>, tcx: TyCtxt<'tcx>) -> mir::Const<'tcx> { - match self { - Self::Finite(value) => value, - Self::NegInfinity => { - // Unwrap is ok because the type is known to be numeric. - let c = ty.numeric_min_val(tcx).unwrap(); - mir::Const::from_ty_const(c, tcx) - } - Self::PosInfinity => { - // Unwrap is ok because the type is known to be numeric. - let c = ty.numeric_max_val(tcx).unwrap(); - mir::Const::from_ty_const(c, tcx) - } - } - } pub fn eval_bits(self, ty: Ty<'tcx>, tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>) -> u128 { match self { Self::Finite(value) => value.eval_bits(tcx, param_env), diff --git a/compiler/rustc_mir_build/src/build/matches/test.rs b/compiler/rustc_mir_build/src/build/matches/test.rs index 1c97de58863..1b6994966d1 100644 --- a/compiler/rustc_mir_build/src/build/matches/test.rs +++ b/compiler/rustc_mir_build/src/build/matches/test.rs @@ -291,33 +291,41 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { } TestKind::Range(ref range) => { - let lower_bound_success = self.cfg.start_new_block(); - + let [success, fail] = *target_blocks else { + bug!("`TestKind::Range` should have two target blocks"); + }; // Test `val` by computing `lo <= val && val <= hi`, using primitive comparisons. - // FIXME: skip useless comparison when the range is half-open. - let lo = range.lo.to_const(range.ty, self.tcx); - let hi = range.hi.to_const(range.ty, self.tcx); - let lo = self.literal_operand(test.span, lo); - let hi = self.literal_operand(test.span, hi); let val = Operand::Copy(place); - let [success, fail] = *target_blocks else { - bug!("`TestKind::Range` should have two target blocks"); + let intermediate_block = if !range.lo.is_finite() { + block + } else if !range.hi.is_finite() { + success + } else { + self.cfg.start_new_block() }; - self.compare( - block, - lower_bound_success, - fail, - source_info, - BinOp::Le, - lo, - val.clone(), - ); - let op = match range.end { - RangeEnd::Included => BinOp::Le, - RangeEnd::Excluded => BinOp::Lt, + + if let Some(lo) = range.lo.as_finite() { + let lo = self.literal_operand(test.span, lo); + self.compare( + block, + intermediate_block, + fail, + source_info, + BinOp::Le, + lo, + val.clone(), + ); }; - self.compare(lower_bound_success, success, fail, source_info, op, val, hi); + + if let Some(hi) = range.hi.as_finite() { + let hi = self.literal_operand(test.span, hi); + let op = match range.end { + RangeEnd::Included => BinOp::Le, + RangeEnd::Excluded => BinOp::Lt, + }; + self.compare(intermediate_block, success, fail, source_info, op, val, hi); + } } TestKind::Len { len, op } => { |
