Skip to content

Commit

Permalink
Rollup merge of #121376 - Nadrieril:mir-half-ranges, r=pnkfelix
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
GuillaumeGomez committed Feb 29, 2024
2 parents 9df7f26 + 7c6960e commit 2e0a26a
Show file tree
Hide file tree
Showing 2 changed files with 32 additions and 38 deletions.
18 changes: 2 additions & 16 deletions compiler/rustc_middle/src/thir.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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),
Expand Down
52 changes: 30 additions & 22 deletions compiler/rustc_mir_build/src/build/matches/test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 } => {
Expand Down

0 comments on commit 2e0a26a

Please sign in to comment.