Skip to content

Commit bd5c438

Browse files
committed
Remove early exits from JumpThreading.
1 parent 191df20 commit bd5c438

File tree

1 file changed

+64
-71
lines changed

1 file changed

+64
-71
lines changed

compiler/rustc_mir_transform/src/jump_threading.rs

+64-71
Original file line numberDiff line numberDiff line change
@@ -90,11 +90,7 @@ impl<'tcx> crate::MirPass<'tcx> for JumpThreading {
9090
};
9191

9292
for bb in body.basic_blocks.indices() {
93-
let old_len = finder.opportunities.len();
94-
// If we have any const-eval errors discard any opportunities found
95-
if finder.start_from_switch(bb).is_none() {
96-
finder.opportunities.truncate(old_len);
97-
}
93+
finder.start_from_switch(bb);
9894
}
9995

10096
let opportunities = finder.opportunities;
@@ -201,28 +197,26 @@ impl<'a, 'tcx> TOFinder<'a, 'tcx> {
201197

202198
/// Recursion entry point to find threading opportunities.
203199
#[instrument(level = "trace", skip(self))]
204-
fn start_from_switch(&mut self, bb: BasicBlock) -> Option<()> {
200+
fn start_from_switch(&mut self, bb: BasicBlock) {
205201
let bbdata = &self.body[bb];
206202
if bbdata.is_cleanup || self.loop_headers.contains(bb) {
207-
return Some(());
203+
return;
208204
}
209-
let Some((discr, targets)) = bbdata.terminator().kind.as_switch() else { return Some(()) };
210-
let Some(discr) = discr.place() else { return Some(()) };
205+
let Some((discr, targets)) = bbdata.terminator().kind.as_switch() else { return };
206+
let Some(discr) = discr.place() else { return };
211207
debug!(?discr, ?bb);
212208

213209
let discr_ty = discr.ty(self.body, self.tcx).ty;
214-
let Ok(discr_layout) = self.ecx.layout_of(discr_ty) else {
215-
return Some(());
216-
};
210+
let Ok(discr_layout) = self.ecx.layout_of(discr_ty) else { return };
217211

218-
let Some(discr) = self.map.find(discr.as_ref()) else { return Some(()) };
212+
let Some(discr) = self.map.find(discr.as_ref()) else { return };
219213
debug!(?discr);
220214

221215
let cost = CostChecker::new(self.tcx, self.typing_env, None, self.body);
222216
let mut state = State::new_reachable();
223217

224218
let conds = if let Some((value, then, else_)) = targets.as_static_if() {
225-
let value = ScalarInt::try_from_uint(value, discr_layout.size)?;
219+
let Some(value) = ScalarInt::try_from_uint(value, discr_layout.size) else { return };
226220
self.arena.alloc_from_iter([
227221
Condition { value, polarity: Polarity::Eq, target: then },
228222
Condition { value, polarity: Polarity::Ne, target: else_ },
@@ -248,27 +242,27 @@ impl<'a, 'tcx> TOFinder<'a, 'tcx> {
248242
mut state: State<ConditionSet<'a>>,
249243
mut cost: CostChecker<'_, 'tcx>,
250244
depth: usize,
251-
) -> Option<()> {
245+
) {
252246
// Do not thread through loop headers.
253247
if self.loop_headers.contains(bb) {
254-
return Some(());
248+
return;
255249
}
256250

257251
debug!(cost = ?cost.cost());
258252
for (statement_index, stmt) in
259253
self.body.basic_blocks[bb].statements.iter().enumerate().rev()
260254
{
261255
if self.is_empty(&state) {
262-
return Some(());
256+
return;
263257
}
264258

265259
cost.visit_statement(stmt, Location { block: bb, statement_index });
266260
if cost.cost() > MAX_COST {
267-
return Some(());
261+
return;
268262
}
269263

270264
// Attempt to turn the `current_condition` on `lhs` into a condition on another place.
271-
self.process_statement(bb, stmt, &mut state)?;
265+
self.process_statement(bb, stmt, &mut state);
272266

273267
// When a statement mutates a place, assignments to that place that happen
274268
// above the mutation cannot fulfill a condition.
@@ -280,7 +274,7 @@ impl<'a, 'tcx> TOFinder<'a, 'tcx> {
280274
}
281275

282276
if self.is_empty(&state) || depth >= MAX_BACKTRACK {
283-
return Some(());
277+
return;
284278
}
285279

286280
let last_non_rec = self.opportunities.len();
@@ -293,9 +287,9 @@ impl<'a, 'tcx> TOFinder<'a, 'tcx> {
293287
match term.kind {
294288
TerminatorKind::SwitchInt { ref discr, ref targets } => {
295289
self.process_switch_int(discr, targets, bb, &mut state);
296-
self.find_opportunity(pred, state, cost, depth + 1)?;
290+
self.find_opportunity(pred, state, cost, depth + 1);
297291
}
298-
_ => self.recurse_through_terminator(pred, || state, &cost, depth)?,
292+
_ => self.recurse_through_terminator(pred, || state, &cost, depth),
299293
}
300294
} else if let &[ref predecessors @ .., last_pred] = &predecessors[..] {
301295
for &pred in predecessors {
@@ -320,13 +314,12 @@ impl<'a, 'tcx> TOFinder<'a, 'tcx> {
320314
let first = &mut new_tos[0];
321315
*first = ThreadingOpportunity { chain: vec![bb], target: first.target };
322316
self.opportunities.truncate(last_non_rec + 1);
323-
return Some(());
317+
return;
324318
}
325319

326320
for op in self.opportunities[last_non_rec..].iter_mut() {
327321
op.chain.push(bb);
328322
}
329-
Some(())
330323
}
331324

332325
/// Extract the mutated place from a statement.
@@ -440,23 +433,23 @@ impl<'a, 'tcx> TOFinder<'a, 'tcx> {
440433
lhs: PlaceIndex,
441434
rhs: &Operand<'tcx>,
442435
state: &mut State<ConditionSet<'a>>,
443-
) -> Option<()> {
436+
) {
444437
match rhs {
445438
// If we expect `lhs ?= A`, we have an opportunity if we assume `constant == A`.
446439
Operand::Constant(constant) => {
447-
let constant = self
448-
.ecx
449-
.eval_mir_constant(&constant.const_, constant.span, None)
450-
.discard_err()?;
440+
let Some(constant) =
441+
self.ecx.eval_mir_constant(&constant.const_, constant.span, None).discard_err()
442+
else {
443+
return;
444+
};
451445
self.process_constant(bb, lhs, constant, state);
452446
}
453447
// Transfer the conditions on the copied rhs.
454448
Operand::Move(rhs) | Operand::Copy(rhs) => {
455-
let Some(rhs) = self.map.find(rhs.as_ref()) else { return Some(()) };
449+
let Some(rhs) = self.map.find(rhs.as_ref()) else { return };
456450
state.insert_place_idx(rhs, lhs, &self.map);
457451
}
458452
}
459-
Some(())
460453
}
461454

462455
#[instrument(level = "trace", skip(self))]
@@ -466,26 +459,22 @@ impl<'a, 'tcx> TOFinder<'a, 'tcx> {
466459
lhs_place: &Place<'tcx>,
467460
rhs: &Rvalue<'tcx>,
468461
state: &mut State<ConditionSet<'a>>,
469-
) -> Option<()> {
470-
let Some(lhs) = self.map.find(lhs_place.as_ref()) else {
471-
return Some(());
472-
};
462+
) {
463+
let Some(lhs) = self.map.find(lhs_place.as_ref()) else { return };
473464
match rhs {
474-
Rvalue::Use(operand) => self.process_operand(bb, lhs, operand, state)?,
465+
Rvalue::Use(operand) => self.process_operand(bb, lhs, operand, state),
475466
// Transfer the conditions on the copy rhs.
476-
Rvalue::CopyForDeref(rhs) => {
477-
self.process_operand(bb, lhs, &Operand::Copy(*rhs), state)?
478-
}
467+
Rvalue::CopyForDeref(rhs) => self.process_operand(bb, lhs, &Operand::Copy(*rhs), state),
479468
Rvalue::Discriminant(rhs) => {
480-
let Some(rhs) = self.map.find_discr(rhs.as_ref()) else { return Some(()) };
469+
let Some(rhs) = self.map.find_discr(rhs.as_ref()) else { return };
481470
state.insert_place_idx(rhs, lhs, &self.map);
482471
}
483472
// If we expect `lhs ?= A`, we have an opportunity if we assume `constant == A`.
484473
Rvalue::Aggregate(box kind, operands) => {
485474
let agg_ty = lhs_place.ty(self.body, self.tcx).ty;
486475
let lhs = match kind {
487476
// Do not support unions.
488-
AggregateKind::Adt(.., Some(_)) => return Some(()),
477+
AggregateKind::Adt(.., Some(_)) => return,
489478
AggregateKind::Adt(_, variant_index, ..) if agg_ty.is_enum() => {
490479
if let Some(discr_target) = self.map.apply(lhs, TrackElem::Discriminant)
491480
&& let Some(discr_value) = self
@@ -498,31 +487,33 @@ impl<'a, 'tcx> TOFinder<'a, 'tcx> {
498487
if let Some(idx) = self.map.apply(lhs, TrackElem::Variant(*variant_index)) {
499488
idx
500489
} else {
501-
return Some(());
490+
return;
502491
}
503492
}
504493
_ => lhs,
505494
};
506495
for (field_index, operand) in operands.iter_enumerated() {
507496
if let Some(field) = self.map.apply(lhs, TrackElem::Field(field_index)) {
508-
self.process_operand(bb, field, operand, state)?;
497+
self.process_operand(bb, field, operand, state);
509498
}
510499
}
511500
}
512501
// Transfer the conditions on the copy rhs, after inverting the value of the condition.
513502
Rvalue::UnaryOp(UnOp::Not, Operand::Move(place) | Operand::Copy(place)) => {
514503
let layout = self.ecx.layout_of(place.ty(self.body, self.tcx).ty).unwrap();
515-
let Some(conditions) = state.try_get_idx(lhs, &self.map) else { return Some(()) };
516-
let Some(place) = self.map.find(place.as_ref()) else { return Some(()) };
517-
let conds = conditions.map(self.arena, |mut cond| {
504+
let Some(conditions) = state.try_get_idx(lhs, &self.map) else { return };
505+
let Some(place) = self.map.find(place.as_ref()) else { return };
506+
let Some(conds) = conditions.map(self.arena, |mut cond| {
518507
cond.value = self
519508
.ecx
520509
.unary_op(UnOp::Not, &ImmTy::from_scalar_int(cond.value, layout))
521510
.discard_err()?
522511
.to_scalar_int()
523512
.discard_err()?;
524513
Some(cond)
525-
})?;
514+
}) else {
515+
return;
516+
};
526517
state.insert_value_idx(place, conds, &self.map);
527518
}
528519
// We expect `lhs ?= A`. We found `lhs = Eq(rhs, B)`.
@@ -532,34 +523,38 @@ impl<'a, 'tcx> TOFinder<'a, 'tcx> {
532523
box (Operand::Move(place) | Operand::Copy(place), Operand::Constant(value))
533524
| box (Operand::Constant(value), Operand::Move(place) | Operand::Copy(place)),
534525
) => {
535-
let Some(conditions) = state.try_get_idx(lhs, &self.map) else { return Some(()) };
536-
let Some(place) = self.map.find(place.as_ref()) else { return Some(()) };
526+
let Some(conditions) = state.try_get_idx(lhs, &self.map) else { return };
527+
let Some(place) = self.map.find(place.as_ref()) else { return };
537528
let equals = match op {
538529
BinOp::Eq => ScalarInt::TRUE,
539530
BinOp::Ne => ScalarInt::FALSE,
540-
_ => return Some(()),
531+
_ => return,
541532
};
542533
if value.const_.ty().is_floating_point() {
543534
// Floating point equality does not follow bit-patterns.
544535
// -0.0 and NaN both have special rules for equality,
545536
// and therefore we cannot use integer comparisons for them.
546537
// Avoid handling them, though this could be extended in the future.
547-
return Some(());
538+
return;
548539
}
549-
let value = value.const_.try_eval_scalar_int(self.tcx, self.typing_env)?;
550-
let conds = conditions.map(self.arena, |c| {
540+
let Some(value) = value.const_.try_eval_scalar_int(self.tcx, self.typing_env)
541+
else {
542+
return;
543+
};
544+
let Some(conds) = conditions.map(self.arena, |c| {
551545
Some(Condition {
552546
value,
553547
polarity: if c.matches(equals) { Polarity::Eq } else { Polarity::Ne },
554548
..c
555549
})
556-
})?;
550+
}) else {
551+
return;
552+
};
557553
state.insert_value_idx(place, conds, &self.map);
558554
}
559555

560556
_ => {}
561557
}
562-
Some(())
563558
}
564559

565560
#[instrument(level = "trace", skip(self))]
@@ -568,7 +563,7 @@ impl<'a, 'tcx> TOFinder<'a, 'tcx> {
568563
bb: BasicBlock,
569564
stmt: &Statement<'tcx>,
570565
state: &mut State<ConditionSet<'a>>,
571-
) -> Option<()> {
566+
) {
572567
let register_opportunity = |c: Condition| {
573568
debug!(?bb, ?c.target, "register");
574569
self.opportunities.push(ThreadingOpportunity { chain: vec![bb], target: c.target })
@@ -581,32 +576,30 @@ impl<'a, 'tcx> TOFinder<'a, 'tcx> {
581576
// If we expect `discriminant(place) ?= A`,
582577
// we have an opportunity if `variant_index ?= A`.
583578
StatementKind::SetDiscriminant { box place, variant_index } => {
584-
let Some(discr_target) = self.map.find_discr(place.as_ref()) else {
585-
return Some(());
586-
};
579+
let Some(discr_target) = self.map.find_discr(place.as_ref()) else { return };
587580
let enum_ty = place.ty(self.body, self.tcx).ty;
588581
// `SetDiscriminant` guarantees that the discriminant is now `variant_index`.
589582
// Even if the discriminant write does nothing due to niches, it is UB to set the
590583
// discriminant when the data does not encode the desired discriminant.
591-
let discr =
592-
self.ecx.discriminant_for_variant(enum_ty, *variant_index).discard_err()?;
593-
self.process_immediate(bb, discr_target, discr, state);
584+
let Some(discr) =
585+
self.ecx.discriminant_for_variant(enum_ty, *variant_index).discard_err()
586+
else {
587+
return;
588+
};
589+
self.process_immediate(bb, discr_target, discr, state)
594590
}
595591
// If we expect `lhs ?= true`, we have an opportunity if we assume `lhs == true`.
596592
StatementKind::Intrinsic(box NonDivergingIntrinsic::Assume(
597593
Operand::Copy(place) | Operand::Move(place),
598594
)) => {
599-
let Some(conditions) = state.try_get(place.as_ref(), &self.map) else {
600-
return Some(());
601-
};
602-
conditions.iter_matches(ScalarInt::TRUE).for_each(register_opportunity);
595+
let Some(conditions) = state.try_get(place.as_ref(), &self.map) else { return };
596+
conditions.iter_matches(ScalarInt::TRUE).for_each(register_opportunity)
603597
}
604598
StatementKind::Assign(box (lhs_place, rhs)) => {
605-
self.process_assign(bb, lhs_place, rhs, state)?;
599+
self.process_assign(bb, lhs_place, rhs, state)
606600
}
607601
_ => {}
608602
}
609-
Some(())
610603
}
611604

612605
#[instrument(level = "trace", skip(self, state, cost))]
@@ -617,7 +610,7 @@ impl<'a, 'tcx> TOFinder<'a, 'tcx> {
617610
state: impl FnOnce() -> State<ConditionSet<'a>>,
618611
cost: &CostChecker<'_, 'tcx>,
619612
depth: usize,
620-
) -> Option<()> {
613+
) {
621614
let term = self.body.basic_blocks[bb].terminator();
622615
let place_to_flood = match term.kind {
623616
// We come from a target, so those are not possible.
@@ -632,9 +625,9 @@ impl<'a, 'tcx> TOFinder<'a, 'tcx> {
632625
| TerminatorKind::FalseUnwind { .. }
633626
| TerminatorKind::Yield { .. } => bug!("{term:?} invalid"),
634627
// Cannot reason about inline asm.
635-
TerminatorKind::InlineAsm { .. } => return Some(()),
628+
TerminatorKind::InlineAsm { .. } => return,
636629
// `SwitchInt` is handled specially.
637-
TerminatorKind::SwitchInt { .. } => return Some(()),
630+
TerminatorKind::SwitchInt { .. } => return,
638631
// We can recurse, no thing particular to do.
639632
TerminatorKind::Goto { .. } => None,
640633
// Flood the overwritten place, and progress through.

0 commit comments

Comments
 (0)