Separate the bool
case from other integers in TestKind
This commit is contained in:
parent
ef324565d0
commit
d6332ae79c
4 changed files with 59 additions and 65 deletions
|
@ -1091,21 +1091,18 @@ enum TestKind<'tcx> {
|
||||||
variants: BitSet<VariantIdx>,
|
variants: BitSet<VariantIdx>,
|
||||||
},
|
},
|
||||||
|
|
||||||
/// Test what value an integer, `bool`, or `char` has.
|
/// Test what value an integer or `char` has.
|
||||||
SwitchInt {
|
SwitchInt {
|
||||||
/// The type of the value that we're testing.
|
|
||||||
switch_ty: Ty<'tcx>,
|
|
||||||
/// The (ordered) set of values that we test for.
|
/// The (ordered) set of values that we test for.
|
||||||
///
|
///
|
||||||
/// For integers and `char`s we create a branch to each of the values in
|
/// We create a branch to each of the values in `options`, as well as an "otherwise" branch
|
||||||
/// `options`, as well as an "otherwise" branch for all other values, even
|
/// for all other values, even in the (rare) case that `options` is exhaustive.
|
||||||
/// in the (rare) case that `options` is exhaustive.
|
|
||||||
///
|
|
||||||
/// For `bool` we always generate two edges, one for `true` and one for
|
|
||||||
/// `false`.
|
|
||||||
options: FxIndexMap<Const<'tcx>, u128>,
|
options: FxIndexMap<Const<'tcx>, u128>,
|
||||||
},
|
},
|
||||||
|
|
||||||
|
/// Test what value a `bool` has.
|
||||||
|
If,
|
||||||
|
|
||||||
/// Test for equality with value, possibly after an unsizing coercion to
|
/// Test for equality with value, possibly after an unsizing coercion to
|
||||||
/// `ty`,
|
/// `ty`,
|
||||||
Eq {
|
Eq {
|
||||||
|
@ -1611,7 +1608,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||||
// a test like SwitchInt, we may want to add cases based on the candidates that are
|
// a test like SwitchInt, we may want to add cases based on the candidates that are
|
||||||
// available
|
// available
|
||||||
match test.kind {
|
match test.kind {
|
||||||
TestKind::SwitchInt { switch_ty: _, ref mut options } => {
|
TestKind::SwitchInt { ref mut options } => {
|
||||||
for candidate in candidates.iter() {
|
for candidate in candidates.iter() {
|
||||||
if !self.add_cases_to_switch(&match_place, candidate, options) {
|
if !self.add_cases_to_switch(&match_place, candidate, options) {
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -34,12 +34,12 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||||
TestKind::Switch { adt_def, variants: BitSet::new_empty(adt_def.variants().len()) }
|
TestKind::Switch { adt_def, variants: BitSet::new_empty(adt_def.variants().len()) }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TestCase::Constant { .. } if match_pair.pattern.ty.is_bool() => TestKind::If,
|
||||||
|
|
||||||
TestCase::Constant { .. } if is_switch_ty(match_pair.pattern.ty) => {
|
TestCase::Constant { .. } if is_switch_ty(match_pair.pattern.ty) => {
|
||||||
// For integers, we use a `SwitchInt` match, which allows
|
// For integers, we use a `SwitchInt` match, which allows
|
||||||
// us to handle more cases.
|
// us to handle more cases.
|
||||||
TestKind::SwitchInt {
|
TestKind::SwitchInt {
|
||||||
switch_ty: match_pair.pattern.ty,
|
|
||||||
|
|
||||||
// these maps are empty to start; cases are
|
// these maps are empty to start; cases are
|
||||||
// added below in add_cases_to_switch
|
// added below in add_cases_to_switch
|
||||||
options: Default::default(),
|
options: Default::default(),
|
||||||
|
@ -182,34 +182,29 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
TestKind::SwitchInt { switch_ty, ref options } => {
|
TestKind::SwitchInt { ref options } => {
|
||||||
let terminator = if *switch_ty.kind() == ty::Bool {
|
// The switch may be inexhaustive so we have a catch-all block
|
||||||
assert!(!options.is_empty() && options.len() <= 2);
|
debug_assert_eq!(options.len() + 1, target_blocks.len());
|
||||||
let [first_bb, second_bb] = *target_blocks else {
|
let otherwise_block = *target_blocks.last().unwrap();
|
||||||
bug!("`TestKind::SwitchInt` on `bool` should have two targets")
|
let switch_targets = SwitchTargets::new(
|
||||||
};
|
options.values().copied().zip(target_blocks),
|
||||||
let (true_bb, false_bb) = match options[0] {
|
otherwise_block,
|
||||||
1 => (first_bb, second_bb),
|
);
|
||||||
0 => (second_bb, first_bb),
|
let terminator = TerminatorKind::SwitchInt {
|
||||||
v => span_bug!(test.span, "expected boolean value but got {:?}", v),
|
discr: Operand::Copy(place),
|
||||||
};
|
targets: switch_targets,
|
||||||
TerminatorKind::if_(Operand::Copy(place), true_bb, false_bb)
|
|
||||||
} else {
|
|
||||||
// The switch may be inexhaustive so we have a catch all block
|
|
||||||
debug_assert_eq!(options.len() + 1, target_blocks.len());
|
|
||||||
let otherwise_block = *target_blocks.last().unwrap();
|
|
||||||
let switch_targets = SwitchTargets::new(
|
|
||||||
options.values().copied().zip(target_blocks),
|
|
||||||
otherwise_block,
|
|
||||||
);
|
|
||||||
TerminatorKind::SwitchInt {
|
|
||||||
discr: Operand::Copy(place),
|
|
||||||
targets: switch_targets,
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
self.cfg.terminate(block, self.source_info(match_start_span), terminator);
|
self.cfg.terminate(block, self.source_info(match_start_span), terminator);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TestKind::If => {
|
||||||
|
let [false_bb, true_bb] = *target_blocks else {
|
||||||
|
bug!("`TestKind::If` should have two targets")
|
||||||
|
};
|
||||||
|
let terminator = TerminatorKind::if_(Operand::Copy(place), true_bb, false_bb);
|
||||||
|
self.cfg.terminate(block, self.source_info(match_start_span), terminator);
|
||||||
|
}
|
||||||
|
|
||||||
TestKind::Eq { value, ty } => {
|
TestKind::Eq { value, ty } => {
|
||||||
let tcx = self.tcx;
|
let tcx = self.tcx;
|
||||||
let [success_block, fail_block] = *target_blocks else {
|
let [success_block, fail_block] = *target_blocks else {
|
||||||
|
@ -585,14 +580,14 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||||
//
|
//
|
||||||
// FIXME(#29623) we could use PatKind::Range to rule
|
// FIXME(#29623) we could use PatKind::Range to rule
|
||||||
// things out here, in some cases.
|
// things out here, in some cases.
|
||||||
(TestKind::SwitchInt { switch_ty: _, options }, TestCase::Constant { value })
|
(TestKind::SwitchInt { options }, TestCase::Constant { value })
|
||||||
if is_switch_ty(match_pair.pattern.ty) =>
|
if is_switch_ty(match_pair.pattern.ty) =>
|
||||||
{
|
{
|
||||||
fully_matched = true;
|
fully_matched = true;
|
||||||
let index = options.get_index_of(value).unwrap();
|
let index = options.get_index_of(value).unwrap();
|
||||||
Some(index)
|
Some(index)
|
||||||
}
|
}
|
||||||
(TestKind::SwitchInt { switch_ty: _, options }, TestCase::Range(range)) => {
|
(TestKind::SwitchInt { options }, TestCase::Range(range)) => {
|
||||||
fully_matched = false;
|
fully_matched = false;
|
||||||
let not_contained =
|
let not_contained =
|
||||||
self.values_not_contained_in_range(&*range, options).unwrap_or(false);
|
self.values_not_contained_in_range(&*range, options).unwrap_or(false);
|
||||||
|
@ -608,6 +603,18 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
|
(&TestKind::If, TestCase::Constant { value }) => {
|
||||||
|
fully_matched = true;
|
||||||
|
let value = value.try_eval_bool(self.tcx, self.param_env).unwrap_or_else(|| {
|
||||||
|
span_bug!(test.span, "expected boolean value but got {value:?}")
|
||||||
|
});
|
||||||
|
Some(value as usize)
|
||||||
|
}
|
||||||
|
(&TestKind::If, _) => {
|
||||||
|
fully_matched = false;
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
(
|
(
|
||||||
&TestKind::Len { len: test_len, op: BinOp::Eq },
|
&TestKind::Len { len: test_len, op: BinOp::Eq },
|
||||||
&TestCase::Slice { len, variable_length },
|
&TestCase::Slice { len, variable_length },
|
||||||
|
@ -755,7 +762,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||||
impl Test<'_> {
|
impl Test<'_> {
|
||||||
pub(super) fn targets(&self) -> usize {
|
pub(super) fn targets(&self) -> usize {
|
||||||
match self.kind {
|
match self.kind {
|
||||||
TestKind::Eq { .. } | TestKind::Range(_) | TestKind::Len { .. } => 2,
|
TestKind::Eq { .. } | TestKind::Range(_) | TestKind::Len { .. } | TestKind::If => 2,
|
||||||
TestKind::Switch { adt_def, .. } => {
|
TestKind::Switch { adt_def, .. } => {
|
||||||
// While the switch that we generate doesn't test for all
|
// While the switch that we generate doesn't test for all
|
||||||
// variants, we have a target for each variant and the
|
// variants, we have a target for each variant and the
|
||||||
|
@ -763,21 +770,13 @@ impl Test<'_> {
|
||||||
// specified have the same block.
|
// specified have the same block.
|
||||||
adt_def.variants().len() + 1
|
adt_def.variants().len() + 1
|
||||||
}
|
}
|
||||||
TestKind::SwitchInt { switch_ty, ref options, .. } => {
|
TestKind::SwitchInt { ref options } => options.len() + 1,
|
||||||
if switch_ty.is_bool() {
|
|
||||||
// `bool` is special cased in `perform_test` to always
|
|
||||||
// branch to two blocks.
|
|
||||||
2
|
|
||||||
} else {
|
|
||||||
options.len() + 1
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn is_switch_ty(ty: Ty<'_>) -> bool {
|
fn is_switch_ty(ty: Ty<'_>) -> bool {
|
||||||
ty.is_integral() || ty.is_char() || ty.is_bool()
|
ty.is_integral() || ty.is_char()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn trait_method<'tcx>(
|
fn trait_method<'tcx>(
|
||||||
|
|
|
@ -42,15 +42,11 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
bb2: {
|
bb2: {
|
||||||
- switchInt((_2.0: bool)) -> [0: bb4, otherwise: bb3];
|
- switchInt((_2.0: bool)) -> [0: bb3, otherwise: bb4];
|
||||||
+ switchInt((_2.0: bool)) -> [0: bb3, otherwise: bb17];
|
+ switchInt((_2.0: bool)) -> [0: bb3, otherwise: bb17];
|
||||||
}
|
}
|
||||||
|
|
||||||
bb3: {
|
bb3: {
|
||||||
- falseEdge -> [real: bb20, imaginary: bb4];
|
|
||||||
- }
|
|
||||||
-
|
|
||||||
- bb4: {
|
|
||||||
StorageLive(_15);
|
StorageLive(_15);
|
||||||
_15 = (_2.1: bool);
|
_15 = (_2.1: bool);
|
||||||
StorageLive(_16);
|
StorageLive(_16);
|
||||||
|
@ -59,8 +55,12 @@
|
||||||
+ goto -> bb16;
|
+ goto -> bb16;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bb4: {
|
||||||
|
- falseEdge -> [real: bb20, imaginary: bb3];
|
||||||
|
- }
|
||||||
|
-
|
||||||
- bb5: {
|
- bb5: {
|
||||||
- falseEdge -> [real: bb13, imaginary: bb3];
|
- falseEdge -> [real: bb13, imaginary: bb4];
|
||||||
- }
|
- }
|
||||||
-
|
-
|
||||||
- bb6: {
|
- bb6: {
|
||||||
|
@ -68,7 +68,6 @@
|
||||||
- }
|
- }
|
||||||
-
|
-
|
||||||
- bb7: {
|
- bb7: {
|
||||||
+ bb4: {
|
|
||||||
_0 = const 1_i32;
|
_0 = const 1_i32;
|
||||||
- drop(_7) -> [return: bb18, unwind: bb25];
|
- drop(_7) -> [return: bb18, unwind: bb25];
|
||||||
+ drop(_7) -> [return: bb15, unwind: bb22];
|
+ drop(_7) -> [return: bb15, unwind: bb22];
|
||||||
|
@ -184,7 +183,7 @@
|
||||||
StorageDead(_12);
|
StorageDead(_12);
|
||||||
StorageDead(_8);
|
StorageDead(_8);
|
||||||
StorageDead(_6);
|
StorageDead(_6);
|
||||||
- falseEdge -> [real: bb2, imaginary: bb3];
|
- falseEdge -> [real: bb2, imaginary: bb4];
|
||||||
+ goto -> bb2;
|
+ goto -> bb2;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -42,15 +42,11 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
bb2: {
|
bb2: {
|
||||||
- switchInt((_2.0: bool)) -> [0: bb4, otherwise: bb3];
|
- switchInt((_2.0: bool)) -> [0: bb3, otherwise: bb4];
|
||||||
+ switchInt((_2.0: bool)) -> [0: bb3, otherwise: bb17];
|
+ switchInt((_2.0: bool)) -> [0: bb3, otherwise: bb17];
|
||||||
}
|
}
|
||||||
|
|
||||||
bb3: {
|
bb3: {
|
||||||
- falseEdge -> [real: bb20, imaginary: bb4];
|
|
||||||
- }
|
|
||||||
-
|
|
||||||
- bb4: {
|
|
||||||
StorageLive(_15);
|
StorageLive(_15);
|
||||||
_15 = (_2.1: bool);
|
_15 = (_2.1: bool);
|
||||||
StorageLive(_16);
|
StorageLive(_16);
|
||||||
|
@ -59,8 +55,12 @@
|
||||||
+ goto -> bb16;
|
+ goto -> bb16;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bb4: {
|
||||||
|
- falseEdge -> [real: bb20, imaginary: bb3];
|
||||||
|
- }
|
||||||
|
-
|
||||||
- bb5: {
|
- bb5: {
|
||||||
- falseEdge -> [real: bb13, imaginary: bb3];
|
- falseEdge -> [real: bb13, imaginary: bb4];
|
||||||
- }
|
- }
|
||||||
-
|
-
|
||||||
- bb6: {
|
- bb6: {
|
||||||
|
@ -68,7 +68,6 @@
|
||||||
- }
|
- }
|
||||||
-
|
-
|
||||||
- bb7: {
|
- bb7: {
|
||||||
+ bb4: {
|
|
||||||
_0 = const 1_i32;
|
_0 = const 1_i32;
|
||||||
- drop(_7) -> [return: bb18, unwind: bb25];
|
- drop(_7) -> [return: bb18, unwind: bb25];
|
||||||
+ drop(_7) -> [return: bb15, unwind: bb22];
|
+ drop(_7) -> [return: bb15, unwind: bb22];
|
||||||
|
@ -184,7 +183,7 @@
|
||||||
StorageDead(_12);
|
StorageDead(_12);
|
||||||
StorageDead(_8);
|
StorageDead(_8);
|
||||||
StorageDead(_6);
|
StorageDead(_6);
|
||||||
- falseEdge -> [real: bb2, imaginary: bb3];
|
- falseEdge -> [real: bb2, imaginary: bb4];
|
||||||
+ goto -> bb2;
|
+ goto -> bb2;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue