-
Notifications
You must be signed in to change notification settings - Fork 12.7k
Commit
- Loading branch information
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,5 +1,3 @@ | ||
use rustc_index::bit_set::BitSet; | ||
|
||
use super::*; | ||
|
||
/// Preorder traversal of a graph. | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,75 @@ | ||
//! A pass that simplifies branches when their condition is known. | ||
|
||
use rustc_middle::mir::*; | ||
use rustc_middle::ty::TyCtxt; | ||
|
||
/// The lowering for `if CONST` produces | ||
/// ``` | ||
/// _1 = Const(...); | ||
Check failure on line 8 in compiler/rustc_mir_transform/src/simplify_if_const.rs GitHub Actions / PR - x86_64-gnu-llvm-16
Check failure on line 8 in compiler/rustc_mir_transform/src/simplify_if_const.rs GitHub Actions / PR - x86_64-gnu-llvm-16
Check failure on line 8 in compiler/rustc_mir_transform/src/simplify_if_const.rs GitHub Actions / PR - x86_64-gnu-llvm-16
|
||
/// switchInt (move _1) | ||
/// ``` | ||
/// so this pass replaces that with | ||
/// ``` | ||
/// switchInt (Const(...)) | ||
Check failure on line 13 in compiler/rustc_mir_transform/src/simplify_if_const.rs GitHub Actions / PR - x86_64-gnu-llvm-16
Check failure on line 13 in compiler/rustc_mir_transform/src/simplify_if_const.rs GitHub Actions / PR - x86_64-gnu-llvm-16
Check failure on line 13 in compiler/rustc_mir_transform/src/simplify_if_const.rs GitHub Actions / PR - x86_64-gnu-llvm-16
|
||
/// ``` | ||
/// so that further MIR consumers can special-case it more easily. | ||
/// | ||
/// Unlike ConstProp, this supports generic constants too, not just concrete ones. | ||
pub struct SimplifyIfConst; | ||
|
||
impl<'tcx> MirPass<'tcx> for SimplifyIfConst { | ||
fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { | ||
for block in body.basic_blocks_mut() { | ||
simplify_assign_move_switch(tcx, block); | ||
} | ||
} | ||
} | ||
|
||
fn simplify_assign_move_switch(tcx: TyCtxt<'_>, block: &mut BasicBlockData<'_>) { | ||
let Some(Terminator { kind: TerminatorKind::SwitchInt { discr: switch_desc, .. }, .. }) = | ||
&mut block.terminator | ||
else { | ||
return; | ||
}; | ||
|
||
let &mut Operand::Move(switch_place) = &mut *switch_desc else { return }; | ||
|
||
let Some(switch_local) = switch_place.as_local() else { return }; | ||
|
||
let Some(last_statement) = block.statements.last_mut() else { return }; | ||
|
||
let StatementKind::Assign(boxed_place_rvalue) = &last_statement.kind else { return }; | ||
|
||
let Some(assigned_local) = boxed_place_rvalue.0.as_local() else { return }; | ||
|
||
if switch_local != assigned_local { | ||
return; | ||
} | ||
|
||
if !matches!(boxed_place_rvalue.1, Rvalue::Use(Operand::Constant(_))) { | ||
return; | ||
} | ||
|
||
let should_optimize = tcx.consider_optimizing(|| { | ||
format!( | ||
"SimplifyBranches - Assignment: {:?} SourceInfo: {:?}", | ||
boxed_place_rvalue, last_statement.source_info | ||
) | ||
}); | ||
|
||
if should_optimize { | ||
let Some(last_statement) = block.statements.pop() else { | ||
bug!("Somehow the statement disappeared?"); | ||
}; | ||
|
||
let StatementKind::Assign(boxed_place_rvalue) = last_statement.kind else { | ||
bug!("Somehow it's not an assignment any more?"); | ||
}; | ||
|
||
let Rvalue::Use(assigned_constant @ Operand::Constant(_)) = boxed_place_rvalue.1 else { | ||
bug!("Somehow it's not a use of a constant any more?"); | ||
}; | ||
|
||
*switch_desc = assigned_constant; | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
// compile-flags: -O -C no-prepopulate-passes | ||
|
||
#![crate_type = "lib"] | ||
|
||
#[no_mangle] | ||
pub fn demo_for_i32() { | ||
generic_impl::<i32>(); | ||
} | ||
|
||
// Two important things here: | ||
// - We replace the "then" block with `unreachable` to avoid linking problems | ||
// - We neither declare nor define the `big_impl` that said block "calls". | ||
|
||
// CHECK-LABEL: ; skip_mono_inside_if_false::generic_impl | ||
// CHECK: start: | ||
// CHECK-NEXT: br i1 false, label %[[THEN_BRANCH:bb[0-9]+]], label %[[ELSE_BRANCH:bb[0-9]+]] | ||
// CHECK: [[ELSE_BRANCH]]: | ||
// CHECK-NEXT: call skip_mono_inside_if_false::small_impl | ||
// CHECK: [[THEN_BRANCH]]: | ||
// CHECK-NEXT: unreachable | ||
|
||
fn generic_impl<T>() { | ||
trait MagicTrait { | ||
const IS_BIG: bool; | ||
} | ||
impl<T> MagicTrait for T { | ||
const IS_BIG: bool = std::mem::size_of::<T>() > 10; | ||
} | ||
if T::IS_BIG { | ||
big_impl::<T>(); | ||
} else { | ||
small_impl::<T>(); | ||
} | ||
} | ||
|
||
#[inline(never)] | ||
fn small_impl<T>() {} | ||
#[inline(never)] | ||
fn big_impl<T>() {} |