Auto merge of #112040 - cjgillot:separate-const-switch, r=oli-obk

Enable ConstGoto and SeparateConstSwitch passes by default

These 2 passes implement a limited form of jump-threading.
Filing this PR to see if enabling them would be lighter than https://github.com/rust-lang/rust/pull/107009.
This commit is contained in:
bors 2023-06-01 16:04:40 +00:00
commit 789dd0b2a2
6 changed files with 62 additions and 84 deletions

View file

@ -28,7 +28,7 @@ pub struct ConstGoto;
impl<'tcx> MirPass<'tcx> for ConstGoto {
fn is_enabled(&self, sess: &rustc_session::Session) -> bool {
sess.mir_opt_level() >= 4
sess.mir_opt_level() >= 2
}
fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {

View file

@ -103,7 +103,14 @@ impl<'tcx> MirPass<'tcx> for ConstProp {
// That would require a uniform one-def no-mutation analysis
// and RPO (or recursing when needing the value of a local).
let mut optimization_finder = ConstPropagator::new(body, dummy_body, tcx);
optimization_finder.visit_body(body);
// Traverse the body in reverse post-order, to ensure that `FullConstProp` locals are
// assigned before being read.
let postorder = body.basic_blocks.postorder().to_vec();
for bb in postorder.into_iter().rev() {
let data = &mut body.basic_blocks.as_mut_preserves_cfg()[bb];
optimization_finder.visit_basic_block_data(bb, data);
}
trace!("ConstProp done for {:?}", def_id);
}
@ -789,12 +796,6 @@ impl<'tcx> MutVisitor<'tcx> for ConstPropagator<'_, 'tcx> {
self.tcx
}
fn visit_body(&mut self, body: &mut Body<'tcx>) {
for (bb, data) in body.basic_blocks.as_mut_preserves_cfg().iter_enumerated_mut() {
self.visit_basic_block_data(bb, data);
}
}
fn visit_operand(&mut self, operand: &mut Operand<'tcx>, location: Location) {
self.super_operand(operand, location);
@ -885,14 +886,23 @@ impl<'tcx> MutVisitor<'tcx> for ConstPropagator<'_, 'tcx> {
}
}
StatementKind::StorageLive(local) => {
let frame = self.ecx.frame_mut();
frame.locals[local].value =
LocalValue::Live(interpret::Operand::Immediate(interpret::Immediate::Uninit));
}
StatementKind::StorageDead(local) => {
let frame = self.ecx.frame_mut();
frame.locals[local].value = LocalValue::Dead;
Self::remove_const(&mut self.ecx, local);
}
// We do not need to mark dead locals as such. For `FullConstProp` locals,
// this allows to propagate the single assigned value in this case:
// ```
// let x = SOME_CONST;
// if a {
// f(copy x);
// StorageDead(x);
// } else {
// g(copy x);
// StorageDead(x);
// }
// ```
//
// This may propagate a constant where the local would be uninit or dead.
// In both cases, this does not matter, as those reads would be UB anyway.
_ => {}
}
}

View file

@ -559,10 +559,13 @@ fn run_optimization_passes<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
// inst combine is after MatchBranchSimplification to clean up Ne(_1, false)
&multiple_return_terminators::MultipleReturnTerminators,
&instsimplify::InstSimplify,
&separate_const_switch::SeparateConstSwitch,
&simplify::SimplifyLocals::BeforeConstProp,
&copy_prop::CopyProp,
&ref_prop::ReferencePropagation,
// Perform `SeparateConstSwitch` after SSA-based analyses, as cloning blocks may
// destroy the SSA property. It should still happen before const-propagation, so the
// latter pass will leverage the created opportunities.
&separate_const_switch::SeparateConstSwitch,
&const_prop::ConstProp,
&dataflow_const_prop::DataflowConstProp,
//

View file

@ -46,7 +46,7 @@ pub struct SeparateConstSwitch;
impl<'tcx> MirPass<'tcx> for SeparateConstSwitch {
fn is_enabled(&self, sess: &rustc_session::Session) -> bool {
sess.mir_opt_level() >= 4
sess.mir_opt_level() >= 2
}
fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {