Skip to content

Commit

Permalink
Do less work in codegen now that the MIR is simplified
Browse files Browse the repository at this point in the history
  • Loading branch information
scottmcm committed Jul 5, 2024
1 parent 0d804b9 commit 03bb5e0
Show file tree
Hide file tree
Showing 2 changed files with 20 additions and 20 deletions.
19 changes: 14 additions & 5 deletions compiler/rustc_codegen_ssa/src/mir/block.rs
Original file line number Diff line number Diff line change
Expand Up @@ -363,15 +363,24 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
discr: &mir::Operand<'tcx>,
targets: &SwitchTargets,
) {
let discr = self.codegen_operand(bx, discr);
let discr_value = discr.immediate();
let switch_ty = discr.layout.ty;
// If our discriminant is a constant we can branch directly
if let Some(const_discr) = bx.const_to_opt_u128(discr_value, false) {
if let Some(const_op) = discr.constant() {
let const_value = self.eval_mir_constant(const_op);
let Some(const_discr) = const_value.try_to_bits_for_ty(
self.cx.tcx(),
ty::ParamEnv::reveal_all(),
const_op.ty(),
) else {
bug!("Failed to evaluate constant {discr:?} for SwitchInt terminator")
};
let target = targets.target_for_value(const_discr);
bx.br(helper.llbb_with_cleanup(self, target));
return;
};
}

let discr = self.codegen_operand(bx, discr);
let discr_value = discr.immediate();
let switch_ty = discr.layout.ty;

let mut target_iter = targets.iter();
if target_iter.len() == 1 {
Expand Down
21 changes: 6 additions & 15 deletions compiler/rustc_middle/src/mir/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -711,6 +711,7 @@ impl<'tcx> Body<'tcx> {
};

// If this is a SwitchInt(const _), then we can just evaluate the constant and return.
// (The `SwitchConst` transform pass tries to ensure this.)
let discr = match discr {
Operand::Constant(constant) => {
let bits = eval_mono_const(constant)?;
Expand All @@ -719,24 +720,18 @@ impl<'tcx> Body<'tcx> {
Operand::Move(place) | Operand::Copy(place) => place,
};

// MIR for `if false` actually looks like this:
// _1 = const _
// SwitchInt(_1)
//
// And MIR for if intrinsics::ub_checks() looks like this:
// _1 = UbChecks()
// SwitchInt(_1)
//
// So we're going to try to recognize this pattern.
//
// If we have a SwitchInt on a non-const place, we find the most recent statement that
// isn't a storage marker. If that statement is an assignment of a const to our
// discriminant place, we evaluate and return the const, as if we've const-propagated it
// into the SwitchInt.
// If we have a SwitchInt on a non-const place, we look at the last statement
// in the block. If that statement is an assignment of UbChecks to our
// discriminant place, we evaluate its value, as if we've
// const-propagated it into the SwitchInt.

let last_stmt = block.statements.iter().rev().find(|stmt| {
!matches!(stmt.kind, StatementKind::StorageDead(_) | StatementKind::StorageLive(_))
})?;
let last_stmt = block.statements.last()?;

let (place, rvalue) = last_stmt.kind.as_assign()?;

Expand All @@ -746,10 +741,6 @@ impl<'tcx> Body<'tcx> {

match rvalue {
Rvalue::NullaryOp(NullOp::UbChecks, _) => Some((tcx.sess.ub_checks() as u128, targets)),
Rvalue::Use(Operand::Constant(constant)) => {
let bits = eval_mono_const(constant)?;
Some((bits, targets))
}
_ => None,
}
}
Expand Down

0 comments on commit 03bb5e0

Please sign in to comment.