Skip to content

Commit 6e541b8

Browse files
committed
Handle more terminators.
1 parent 5da457a commit 6e541b8

5 files changed

+95
-27
lines changed

compiler/rustc_mir_transform/src/jump_threading.rs

Lines changed: 71 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -234,21 +234,17 @@ impl<'tcx, 'a> TOFinder<'tcx, 'a> {
234234

235235
let predecessors = &self.body.basic_blocks.predecessors()[bb];
236236
if let &[pred] = &predecessors[..] && bb != START_BLOCK {
237-
match &self.body.basic_blocks[pred].terminator().kind {
238-
TerminatorKind::Goto { .. } => self.find_opportunity(pred, state, cost, depth),
239-
TerminatorKind::SwitchInt { discr, targets } => {
240-
self.process_switch_int(state, discr, targets, bb);
237+
let term = self.body.basic_blocks[pred].terminator();
238+
match term.kind {
239+
TerminatorKind::SwitchInt { ref discr, ref targets } => {
240+
self.process_switch_int(discr, targets, bb, &mut state);
241+
self.find_opportunity(pred, state, cost, depth + 1);
241242
}
242-
_ => {}
243+
_ => self.recurse_through_terminator(pred, &state, &cost, depth),
243244
}
244245
} else {
245246
for &pred in predecessors {
246-
if matches!(
247-
self.body.basic_blocks[pred].terminator().kind,
248-
TerminatorKind::Goto { .. }
249-
) {
250-
self.find_opportunity(pred, state.clone(), cost.clone(), depth + 1);
251-
}
247+
self.recurse_through_terminator(pred, &state, &cost, depth);
252248
}
253249
}
254250

@@ -464,43 +460,97 @@ impl<'tcx, 'a> TOFinder<'tcx, 'a> {
464460
None
465461
}
466462

463+
#[instrument(level = "trace", skip(self, cost))]
464+
fn recurse_through_terminator(
465+
&mut self,
466+
bb: BasicBlock,
467+
state: &State<ConditionSet<'a>>,
468+
cost: &CostChecker<'_, 'tcx>,
469+
depth: usize,
470+
) {
471+
let register_opportunity = |c: Condition| {
472+
debug!(?bb, ?c.target, "register");
473+
self.opportunities.push(ThreadingOpportunity { chain: vec![bb], target: c.target })
474+
};
475+
476+
let term = self.body.basic_blocks[bb].terminator();
477+
let place_to_flood = match term.kind {
478+
// We come from a target, so those are not possible.
479+
TerminatorKind::UnwindResume
480+
| TerminatorKind::UnwindTerminate(_)
481+
| TerminatorKind::Return
482+
| TerminatorKind::Unreachable
483+
| TerminatorKind::GeneratorDrop => bug!("{term:?} has no terminators"),
484+
// Disallowed during optimizations.
485+
TerminatorKind::FalseEdge { .. }
486+
| TerminatorKind::FalseUnwind { .. }
487+
| TerminatorKind::Yield { .. } => bug!("{term:?} invalid"),
488+
// Cannot reason about inline asm.
489+
TerminatorKind::InlineAsm { .. } => return,
490+
// `SwitchInt` is handled specially.
491+
TerminatorKind::SwitchInt { .. } => return,
492+
// We can recurse, no thing particular to do.
493+
TerminatorKind::Goto { .. } => None,
494+
// Flood the overwritten place, and progress through.
495+
TerminatorKind::Drop { place: destination, .. }
496+
| TerminatorKind::Call { destination, .. } => Some(destination),
497+
// Treat as an `assume(cond == expected)`.
498+
TerminatorKind::Assert { ref cond, expected, .. } => {
499+
if let Some(place) = cond.place()
500+
&& let Some(conditions) = state.try_get(place.as_ref(), self.map)
501+
{
502+
let expected = if expected { ScalarInt::TRUE } else { ScalarInt::FALSE };
503+
conditions.iter_matches(expected).for_each(register_opportunity);
504+
}
505+
None
506+
}
507+
};
508+
509+
// We can recurse through this terminator.
510+
let mut state = state.clone();
511+
if let Some(place_to_flood) = place_to_flood {
512+
state.flood_with(place_to_flood.as_ref(), self.map, ConditionSet::default());
513+
}
514+
self.find_opportunity(bb, state, cost.clone(), depth + 1);
515+
}
516+
467517
#[instrument(level = "trace", skip(self))]
468518
fn process_switch_int(
469519
&mut self,
470-
state: State<ConditionSet<'a>>,
471520
discr: &Operand<'tcx>,
472521
targets: &SwitchTargets,
473-
bb: BasicBlock,
522+
target_bb: BasicBlock,
523+
state: &mut State<ConditionSet<'a>>,
474524
) -> Option<!> {
475-
debug_assert_ne!(bb, START_BLOCK);
476-
debug_assert_eq!(self.body.basic_blocks.predecessors()[bb].len(), 1);
525+
debug_assert_ne!(target_bb, START_BLOCK);
526+
debug_assert_eq!(self.body.basic_blocks.predecessors()[target_bb].len(), 1);
477527

478528
let discr = discr.place()?;
479529
let discr_ty = discr.ty(self.body, self.tcx).ty;
480530
let discr_layout = self.tcx.layout_of(self.param_env.and(discr_ty)).ok()?;
481531
let conditions = state.try_get(discr.as_ref(), self.map)?;
482532

483-
if let Some((value, _)) = targets.iter().find(|&(_, target)| target == bb) {
533+
if let Some((value, _)) = targets.iter().find(|&(_, target)| target == target_bb) {
484534
let value = ScalarInt::try_from_uint(value, discr_layout.size)?;
485-
debug_assert_eq!(targets.iter().filter(|&(_, target)| target == bb).count(), 1);
535+
debug_assert_eq!(targets.iter().filter(|&(_, target)| target == target_bb).count(), 1);
486536

487-
// We are inside `bb`. Since we have a single predecessor, we know we passed
537+
// We are inside `target_bb`. Since we have a single predecessor, we know we passed
488538
// through the `SwitchInt` before arriving here. Therefore, we know that
489539
// `discr == value`. If one condition can be fulfilled by `discr == value`,
490540
// that's an opportunity.
491541
for c in conditions.iter_matches(value) {
492-
debug!(?bb, ?c.target, "register");
542+
debug!(?target_bb, ?c.target, "register");
493543
self.opportunities.push(ThreadingOpportunity { chain: vec![], target: c.target });
494544
}
495-
} else if bb == targets.otherwise() {
545+
} else if target_bb == targets.otherwise() {
496546
let (value, _, _) = targets.as_static_if()?;
497547
let value = ScalarInt::try_from_uint(value, discr_layout.size)?;
498548

499549
// Likewise, we know that `discr != value`. That's a must weaker information,
500550
// so we can only match the exact same condition.
501551
for c in conditions.iter() {
502552
if c.value == value && c.polarity == false {
503-
debug!(?bb, ?c.target, "register");
553+
debug!(?target_bb, ?c.target, "register");
504554
self.opportunities
505555
.push(ThreadingOpportunity { chain: vec![], target: c.target });
506556
}

tests/mir-opt/jump_threading.disappearing_bb.JumpThreading.panic-abort.diff

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -43,15 +43,20 @@
4343
}
4444

4545
bb7: {
46-
goto -> bb5;
46+
- goto -> bb5;
47+
+ goto -> bb10;
4748
}
4849

4950
bb8: {
50-
goto -> bb6;
51+
+ goto -> bb6;
5152
+ }
5253
+
5354
+ bb9: {
5455
+ goto -> bb5;
56+
+ }
57+
+
58+
+ bb10: {
59+
goto -> bb6;
5560
}
5661
}
5762

tests/mir-opt/jump_threading.disappearing_bb.JumpThreading.panic-unwind.diff

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -43,15 +43,20 @@
4343
}
4444

4545
bb7: {
46-
goto -> bb5;
46+
- goto -> bb5;
47+
+ goto -> bb10;
4748
}
4849

4950
bb8: {
50-
goto -> bb6;
51+
+ goto -> bb6;
5152
+ }
5253
+
5354
+ bb9: {
5455
+ goto -> bb5;
56+
+ }
57+
+
58+
+ bb10: {
59+
goto -> bb6;
5560
}
5661
}
5762

tests/mir-opt/jump_threading.renumbered_bb.JumpThreading.panic-abort.diff

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,11 @@
4747
+ }
4848
+
4949
+ bb8: {
50-
+ goto -> bb4;
50+
+ goto -> bb9;
51+
+ }
52+
+
53+
+ bb9: {
54+
+ goto -> bb6;
5155
}
5256
}
5357

tests/mir-opt/jump_threading.renumbered_bb.JumpThreading.panic-unwind.diff

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,11 @@
4747
+ }
4848
+
4949
+ bb8: {
50-
+ goto -> bb4;
50+
+ goto -> bb9;
51+
+ }
52+
+
53+
+ bb9: {
54+
+ goto -> bb6;
5155
}
5256
}
5357

0 commit comments

Comments
 (0)