Skip to content

Commit 97a032e

Browse files
committed
Simplify bitwise operations
1 parent c388c11 commit 97a032e

File tree

1 file changed

+42
-27
lines changed

1 file changed

+42
-27
lines changed

src/librustc_mir/hair/pattern/_match.rs

Lines changed: 42 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -483,11 +483,11 @@ fn all_constructors<'a, 'tcx: 'a>(cx: &mut MatchCheckCtxt<'a, 'tcx>,
483483
ty::TyUint(_) if exhaustive_integer_patterns => {
484484
// FIXME(49937): refactor these bit manipulations into interpret.
485485
let bits = cx.tcx.layout_of(ty::ParamEnv::reveal_all().and(pcx.ty))
486-
.unwrap().size.bits() as u32;
487-
let max = (!0u128).wrapping_shr(128 - bits);
486+
.unwrap().size.bits() as u128;
487+
let max = !0u128 >> (128 - bits);
488488
value_constructors = true;
489-
vec![ConstantRange(ty::Const::from_bits(cx.tcx, 0u128, pcx.ty),
490-
ty::Const::from_bits(cx.tcx, max as u128, pcx.ty),
489+
vec![ConstantRange(ty::Const::from_bits(cx.tcx, 0, pcx.ty),
490+
ty::Const::from_bits(cx.tcx, max, pcx.ty),
491491
RangeEnd::Included)]
492492
}
493493
_ => {
@@ -604,21 +604,21 @@ fn max_slice_length<'p, 'a: 'p, 'tcx: 'a, I>(
604604
}
605605

606606
/// An inclusive interval, used for precise integer exhaustiveness checking.
607-
/// `Interval`s always store a contiguous range of integers. This means that
608-
/// signed values are encoded by offsetting them such that `0` represents the
609-
/// minimum value for the integer, regardless of sign.
610-
/// For example, the range `-128...127` is encoded as `0...255`.
607+
/// `IntRange`s always store a contiguous range. This means that values are
608+
/// encoded such that `0` encodes the minimum value for the integer,
609+
/// regardless of the signedness.
610+
/// For example, the pattern `-128...127i8` is encoded as `0..=255`.
611611
/// This makes comparisons and arithmetic on interval endpoints much more
612-
/// straightforward. See `offset_sign` for the conversion technique.
613-
struct Interval<'tcx> {
612+
/// straightforward. See `encode` and `decode` for details.
613+
struct IntRange<'tcx> {
614614
pub range: RangeInclusive<u128>,
615615
pub ty: Ty<'tcx>,
616616
}
617617

618-
impl<'tcx> Interval<'tcx> {
618+
impl<'tcx> IntRange<'tcx> {
619619
fn from_ctor(tcx: TyCtxt<'_, 'tcx, 'tcx>,
620620
ctor: &Constructor<'tcx>)
621-
-> Option<Interval<'tcx>> {
621+
-> Option<IntRange<'tcx>> {
622622
match ctor {
623623
ConstantRange(lo, hi, end) => {
624624
assert_eq!(lo.ty, hi.ty);
@@ -627,13 +627,13 @@ impl<'tcx> Interval<'tcx> {
627627
if let Some(hi) = hi.assert_bits(ty) {
628628
// Perform a shift if the underlying types are signed,
629629
// which makes the interval arithmetic simpler.
630-
let (lo, hi) = Self::offset_sign(tcx, ty, lo..=hi, true);
630+
let (lo, hi) = Self::encode(tcx, ty, lo..=hi);
631631
// Make sure the interval is well-formed.
632632
return if lo > hi || lo == hi && *end == RangeEnd::Excluded {
633633
None
634634
} else {
635635
let offset = (*end == RangeEnd::Excluded) as u128;
636-
Some(Interval { range: lo..=(hi - offset), ty })
636+
Some(IntRange { range: lo..=(hi - offset), ty })
637637
};
638638
}
639639
}
@@ -642,8 +642,8 @@ impl<'tcx> Interval<'tcx> {
642642
ConstantValue(val) => {
643643
let ty = val.ty;
644644
if let Some(val) = val.assert_bits(ty) {
645-
let (lo, hi) = Self::offset_sign(tcx, ty, val..=val, true);
646-
Some(Interval { range: lo..=hi, ty })
645+
let (lo, hi) = Self::encode(tcx, ty, val..=val);
646+
Some(IntRange { range: lo..=hi, ty })
647647
} else {
648648
None
649649
}
@@ -654,11 +654,11 @@ impl<'tcx> Interval<'tcx> {
654654
}
655655
}
656656

657-
fn offset_sign(tcx: TyCtxt<'_, 'tcx, 'tcx>,
658-
ty: Ty<'tcx>,
659-
range: RangeInclusive<u128>,
660-
encode: bool)
661-
-> (u128, u128) {
657+
fn convert(tcx: TyCtxt<'_, 'tcx, 'tcx>,
658+
ty: Ty<'tcx>,
659+
range: RangeInclusive<u128>,
660+
encode: bool)
661+
-> (u128, u128) {
662662
// We ensure that all integer values are contiguous: that is, that their
663663
// minimum value is represented by 0, so that comparisons and increments/
664664
// decrements on interval endpoints work consistently whether the endpoints
@@ -670,13 +670,14 @@ impl<'tcx> Interval<'tcx> {
670670
let bits = tcx.layout_of(ty::ParamEnv::reveal_all().and(ty))
671671
.unwrap().size.bits() as u128;
672672
let min = 1u128 << (bits - 1);
673-
let shift = 1u128.overflowing_shl(bits as u32);
674-
let mask = shift.0.wrapping_sub(1 + (shift.1 as u128));
673+
let mask = !0u128 >> (128 - bits);
675674
if encode {
676675
let offset = |x: u128| x.wrapping_sub(min) & mask;
677676
(offset(lo), offset(hi))
678677
} else {
679678
let offset = |x: u128| {
679+
// FIXME: this shouldn't be necessary once `print_miri_value`
680+
// sign-extends `TyInt`.
680681
interpret::sign_extend(tcx, x.wrapping_add(min) & mask, ty)
681682
.expect("layout error for TyInt")
682683
};
@@ -686,10 +687,24 @@ impl<'tcx> Interval<'tcx> {
686687
ty::TyUint(_) | ty::TyChar => {
687688
(lo, hi)
688689
}
689-
_ => bug!("`Interval` should only contain integer types")
690+
_ => bug!("`IntRange` should only contain integer types")
690691
}
691692
}
692693

694+
fn encode(tcx: TyCtxt<'_, 'tcx, 'tcx>,
695+
ty: Ty<'tcx>,
696+
range: RangeInclusive<u128>)
697+
-> (u128, u128) {
698+
Self::convert(tcx, ty, range, true)
699+
}
700+
701+
fn decode(tcx: TyCtxt<'_, 'tcx, 'tcx>,
702+
ty: Ty<'tcx>,
703+
range: RangeInclusive<u128>)
704+
-> (u128, u128) {
705+
Self::convert(tcx, ty, range, false)
706+
}
707+
693708
fn into_inner(self) -> (u128, u128) {
694709
self.range.into_inner()
695710
}
@@ -702,10 +717,10 @@ fn ranges_subtract_pattern<'a, 'tcx>(cx: &mut MatchCheckCtxt<'a, 'tcx>,
702717
pat_ctor: &Constructor<'tcx>,
703718
ranges: Vec<Constructor<'tcx>>)
704719
-> Vec<Constructor<'tcx>> {
705-
if let Some(pat_interval) = Interval::from_ctor(cx.tcx, pat_ctor) {
720+
if let Some(pat_interval) = IntRange::from_ctor(cx.tcx, pat_ctor) {
706721
let mut remaining_ranges = vec![];
707722
let mut ranges: Vec<_> = ranges.into_iter().filter_map(|r| {
708-
Interval::from_ctor(cx.tcx, &r).map(|i| i.into_inner())
723+
IntRange::from_ctor(cx.tcx, &r).map(|i| i.into_inner())
709724
}).collect();
710725
let ty = pat_interval.ty;
711726
let (pat_interval_lo, pat_interval_hi) = pat_interval.into_inner();
@@ -729,7 +744,7 @@ fn ranges_subtract_pattern<'a, 'tcx>(cx: &mut MatchCheckCtxt<'a, 'tcx>,
729744
}
730745
// Convert the remaining ranges from pairs to inclusive `ConstantRange`s.
731746
remaining_ranges.into_iter().map(|r| {
732-
let (lo, hi) = Interval::offset_sign(cx.tcx, ty, r, false);
747+
let (lo, hi) = IntRange::decode(cx.tcx, ty, r);
733748
ConstantRange(ty::Const::from_bits(cx.tcx, lo, ty),
734749
ty::Const::from_bits(cx.tcx, hi, ty),
735750
RangeEnd::Included)

0 commit comments

Comments
 (0)