1
Fork 0

Update MIR with MirPatch in UninhabitedEnumBranching

This commit is contained in:
DianQK 2024-02-28 22:35:41 +08:00
parent 3d7f8b4e5b
commit b5bd98d540
No known key found for this signature in database
GPG key ID: 46BDB1AC96C48912
15 changed files with 165 additions and 175 deletions

View file

@ -2,8 +2,9 @@
use crate::MirPass;
use rustc_data_structures::fx::FxHashSet;
use rustc_middle::mir::patch::MirPatch;
use rustc_middle::mir::{
BasicBlockData, Body, Local, Operand, Rvalue, StatementKind, Terminator, TerminatorKind,
BasicBlockData, Body, Local, Operand, Rvalue, StatementKind, TerminatorKind,
};
use rustc_middle::ty::layout::TyAndLayout;
use rustc_middle::ty::{Ty, TyCtxt};
@ -77,8 +78,8 @@ impl<'tcx> MirPass<'tcx> for UninhabitedEnumBranching {
fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
trace!("UninhabitedEnumBranching starting for {:?}", body.source);
let mut removable_switchs = Vec::new();
let mut otherwise_is_last_variant_switchs = Vec::new();
let mut unreachable_targets = Vec::new();
let mut patch = MirPatch::new(body);
for (bb, bb_data) in body.basic_blocks.iter_enumerated() {
trace!("processing block {:?}", bb);
@ -107,49 +108,41 @@ impl<'tcx> MirPass<'tcx> for UninhabitedEnumBranching {
trace!("allowed_variants = {:?}", allowed_variants);
let terminator = bb_data.terminator();
let TerminatorKind::SwitchInt { targets, .. } = &terminator.kind else { bug!() };
unreachable_targets.clear();
let TerminatorKind::SwitchInt { targets, discr } = &bb_data.terminator().kind else {
bug!()
};
for (index, (val, _)) in targets.iter().enumerate() {
if !allowed_variants.remove(&val) {
removable_switchs.push((bb, index));
unreachable_targets.push(index);
}
}
if allowed_variants.is_empty() {
removable_switchs.push((bb, targets.iter().count()));
} else if allowed_variants.len() == 1
&& !body.basic_blocks[targets.otherwise()].is_empty_unreachable()
{
#[allow(rustc::potential_query_instability)]
let last_variant = *allowed_variants.iter().next().unwrap();
otherwise_is_last_variant_switchs.push((bb, last_variant));
let replace_otherwise_to_unreachable = allowed_variants.len() <= 1
&& !body.basic_blocks[targets.otherwise()].is_empty_unreachable();
if unreachable_targets.is_empty() && !replace_otherwise_to_unreachable {
continue;
}
let unreachable_block = patch.unreachable_no_cleanup_block();
let mut targets = targets.clone();
if replace_otherwise_to_unreachable {
let otherwise_is_last_variant = !allowed_variants.is_empty();
if otherwise_is_last_variant {
#[allow(rustc::potential_query_instability)]
let last_variant = *allowed_variants.iter().next().unwrap();
targets.add_target(last_variant, targets.otherwise());
}
unreachable_targets.push(targets.iter().count());
}
for index in unreachable_targets.iter() {
targets.all_targets_mut()[*index] = unreachable_block;
}
patch.patch_terminator(bb, TerminatorKind::SwitchInt { targets, discr: discr.clone() });
}
for (bb, last_variant) in otherwise_is_last_variant_switchs {
let bb_data = &mut body.basic_blocks.as_mut()[bb];
let terminator = bb_data.terminator_mut();
let TerminatorKind::SwitchInt { targets, .. } = &mut terminator.kind else { bug!() };
targets.add_target(last_variant, targets.otherwise());
removable_switchs.push((bb, targets.iter().count()));
}
if removable_switchs.is_empty() {
return;
}
let new_block = BasicBlockData::new(Some(Terminator {
source_info: body.basic_blocks[removable_switchs[0].0].terminator().source_info,
kind: TerminatorKind::Unreachable,
}));
let unreachable_block = body.basic_blocks.as_mut().push(new_block);
for (bb, index) in removable_switchs {
let bb = &mut body.basic_blocks.as_mut()[bb];
let terminator = bb.terminator_mut();
let TerminatorKind::SwitchInt { targets, .. } = &mut terminator.kind else { bug!() };
targets.all_targets_mut()[index] = unreachable_block;
}
patch.apply(body);
}
}