Inline and remove some functions.
These are all functions with a single callsite, where having a separate function does nothing to help with readability. These changes make the code a little shorter and easier to read.
This commit is contained in:
parent
8235af07d2
commit
48064d4498
10 changed files with 341 additions and 392 deletions
|
@ -32,12 +32,6 @@ pub(super) use self::AddCallGuards::*;
|
||||||
|
|
||||||
impl<'tcx> crate::MirPass<'tcx> for AddCallGuards {
|
impl<'tcx> crate::MirPass<'tcx> for AddCallGuards {
|
||||||
fn run_pass(&self, _tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
|
fn run_pass(&self, _tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
|
||||||
self.add_call_guards(body);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl AddCallGuards {
|
|
||||||
pub(super) fn add_call_guards(&self, body: &mut Body<'_>) {
|
|
||||||
let mut pred_count: IndexVec<_, _> =
|
let mut pred_count: IndexVec<_, _> =
|
||||||
body.basic_blocks.predecessors().iter().map(|ps| ps.len()).collect();
|
body.basic_blocks.predecessors().iter().map(|ps| ps.len()).collect();
|
||||||
pred_count[START_BLOCK] += 1;
|
pred_count[START_BLOCK] += 1;
|
||||||
|
|
|
@ -40,35 +40,34 @@ pub(super) struct AddMovesForPackedDrops;
|
||||||
impl<'tcx> crate::MirPass<'tcx> for AddMovesForPackedDrops {
|
impl<'tcx> crate::MirPass<'tcx> for AddMovesForPackedDrops {
|
||||||
fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
|
fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
|
||||||
debug!("add_moves_for_packed_drops({:?} @ {:?})", body.source, body.span);
|
debug!("add_moves_for_packed_drops({:?} @ {:?})", body.source, body.span);
|
||||||
add_moves_for_packed_drops(tcx, body);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn add_moves_for_packed_drops<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
|
let def_id = body.source.def_id();
|
||||||
let patch = add_moves_for_packed_drops_patch(tcx, body);
|
let mut patch = MirPatch::new(body);
|
||||||
patch.apply(body);
|
let param_env = tcx.param_env(def_id);
|
||||||
}
|
|
||||||
|
|
||||||
fn add_moves_for_packed_drops_patch<'tcx>(tcx: TyCtxt<'tcx>, body: &Body<'tcx>) -> MirPatch<'tcx> {
|
for (bb, data) in body.basic_blocks.iter_enumerated() {
|
||||||
let def_id = body.source.def_id();
|
let loc = Location { block: bb, statement_index: data.statements.len() };
|
||||||
let mut patch = MirPatch::new(body);
|
let terminator = data.terminator();
|
||||||
let param_env = tcx.param_env(def_id);
|
|
||||||
|
|
||||||
for (bb, data) in body.basic_blocks.iter_enumerated() {
|
match terminator.kind {
|
||||||
let loc = Location { block: bb, statement_index: data.statements.len() };
|
TerminatorKind::Drop { place, .. }
|
||||||
let terminator = data.terminator();
|
if util::is_disaligned(tcx, body, param_env, place) =>
|
||||||
|
{
|
||||||
match terminator.kind {
|
add_move_for_packed_drop(
|
||||||
TerminatorKind::Drop { place, .. }
|
tcx,
|
||||||
if util::is_disaligned(tcx, body, param_env, place) =>
|
body,
|
||||||
{
|
&mut patch,
|
||||||
add_move_for_packed_drop(tcx, body, &mut patch, terminator, loc, data.is_cleanup);
|
terminator,
|
||||||
|
loc,
|
||||||
|
data.is_cleanup,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
}
|
}
|
||||||
_ => {}
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
patch
|
patch.apply(body);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn add_move_for_packed_drop<'tcx>(
|
fn add_move_for_packed_drop<'tcx>(
|
||||||
|
|
|
@ -51,18 +51,14 @@ impl<'a, 'tcx> MutVisitor<'tcx> for SubTypeChecker<'a, 'tcx> {
|
||||||
// // gets transformed to
|
// // gets transformed to
|
||||||
// let temp: rval_ty = rval;
|
// let temp: rval_ty = rval;
|
||||||
// let place: place_ty = temp as place_ty;
|
// let place: place_ty = temp as place_ty;
|
||||||
fn subtype_finder<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
|
|
||||||
let patch = MirPatch::new(body);
|
|
||||||
let mut checker = SubTypeChecker { tcx, patcher: patch, local_decls: &body.local_decls };
|
|
||||||
|
|
||||||
for (bb, data) in body.basic_blocks.as_mut_preserves_cfg().iter_enumerated_mut() {
|
|
||||||
checker.visit_basic_block_data(bb, data);
|
|
||||||
}
|
|
||||||
checker.patcher.apply(body);
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'tcx> crate::MirPass<'tcx> for Subtyper {
|
impl<'tcx> crate::MirPass<'tcx> for Subtyper {
|
||||||
fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
|
fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
|
||||||
subtype_finder(tcx, body);
|
let patch = MirPatch::new(body);
|
||||||
|
let mut checker = SubTypeChecker { tcx, patcher: patch, local_decls: &body.local_decls };
|
||||||
|
|
||||||
|
for (bb, data) in body.basic_blocks.as_mut_preserves_cfg().iter_enumerated_mut() {
|
||||||
|
checker.visit_basic_block_data(bb, data);
|
||||||
|
}
|
||||||
|
checker.patcher.apply(body);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,37 +27,34 @@ impl<'tcx> crate::MirPass<'tcx> for CopyProp {
|
||||||
#[instrument(level = "trace", skip(self, tcx, body))]
|
#[instrument(level = "trace", skip(self, tcx, body))]
|
||||||
fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
|
fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
|
||||||
debug!(def_id = ?body.source.def_id());
|
debug!(def_id = ?body.source.def_id());
|
||||||
propagate_ssa(tcx, body);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn propagate_ssa<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
|
let param_env = tcx.param_env_reveal_all_normalized(body.source.def_id());
|
||||||
let param_env = tcx.param_env_reveal_all_normalized(body.source.def_id());
|
let ssa = SsaLocals::new(tcx, body, param_env);
|
||||||
let ssa = SsaLocals::new(tcx, body, param_env);
|
|
||||||
|
|
||||||
let fully_moved = fully_moved_locals(&ssa, body);
|
let fully_moved = fully_moved_locals(&ssa, body);
|
||||||
debug!(?fully_moved);
|
debug!(?fully_moved);
|
||||||
|
|
||||||
let mut storage_to_remove = BitSet::new_empty(fully_moved.domain_size());
|
let mut storage_to_remove = BitSet::new_empty(fully_moved.domain_size());
|
||||||
for (local, &head) in ssa.copy_classes().iter_enumerated() {
|
for (local, &head) in ssa.copy_classes().iter_enumerated() {
|
||||||
if local != head {
|
if local != head {
|
||||||
storage_to_remove.insert(head);
|
storage_to_remove.insert(head);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
let any_replacement = ssa.copy_classes().iter_enumerated().any(|(l, &h)| l != h);
|
let any_replacement = ssa.copy_classes().iter_enumerated().any(|(l, &h)| l != h);
|
||||||
|
|
||||||
Replacer {
|
Replacer {
|
||||||
tcx,
|
tcx,
|
||||||
copy_classes: ssa.copy_classes(),
|
copy_classes: ssa.copy_classes(),
|
||||||
fully_moved,
|
fully_moved,
|
||||||
borrowed_locals: ssa.borrowed_locals(),
|
borrowed_locals: ssa.borrowed_locals(),
|
||||||
storage_to_remove,
|
storage_to_remove,
|
||||||
}
|
}
|
||||||
.visit_body_preserves_cfg(body);
|
.visit_body_preserves_cfg(body);
|
||||||
|
|
||||||
if any_replacement {
|
if any_replacement {
|
||||||
crate::simplify::remove_unused_definitions(body);
|
crate::simplify::remove_unused_definitions(body);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -119,53 +119,50 @@ impl<'tcx> crate::MirPass<'tcx> for GVN {
|
||||||
#[instrument(level = "trace", skip(self, tcx, body))]
|
#[instrument(level = "trace", skip(self, tcx, body))]
|
||||||
fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
|
fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
|
||||||
debug!(def_id = ?body.source.def_id());
|
debug!(def_id = ?body.source.def_id());
|
||||||
propagate_ssa(tcx, body);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn propagate_ssa<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
|
let param_env = tcx.param_env_reveal_all_normalized(body.source.def_id());
|
||||||
let param_env = tcx.param_env_reveal_all_normalized(body.source.def_id());
|
let ssa = SsaLocals::new(tcx, body, param_env);
|
||||||
let ssa = SsaLocals::new(tcx, body, param_env);
|
// Clone dominators as we need them while mutating the body.
|
||||||
// Clone dominators as we need them while mutating the body.
|
let dominators = body.basic_blocks.dominators().clone();
|
||||||
let dominators = body.basic_blocks.dominators().clone();
|
|
||||||
|
|
||||||
let mut state = VnState::new(tcx, body, param_env, &ssa, &dominators, &body.local_decls);
|
let mut state = VnState::new(tcx, body, param_env, &ssa, &dominators, &body.local_decls);
|
||||||
ssa.for_each_assignment_mut(
|
ssa.for_each_assignment_mut(
|
||||||
body.basic_blocks.as_mut_preserves_cfg(),
|
body.basic_blocks.as_mut_preserves_cfg(),
|
||||||
|local, value, location| {
|
|local, value, location| {
|
||||||
let value = match value {
|
let value = match value {
|
||||||
// We do not know anything of this assigned value.
|
// We do not know anything of this assigned value.
|
||||||
AssignedValue::Arg | AssignedValue::Terminator => None,
|
AssignedValue::Arg | AssignedValue::Terminator => None,
|
||||||
// Try to get some insight.
|
// Try to get some insight.
|
||||||
AssignedValue::Rvalue(rvalue) => {
|
AssignedValue::Rvalue(rvalue) => {
|
||||||
let value = state.simplify_rvalue(rvalue, location);
|
let value = state.simplify_rvalue(rvalue, location);
|
||||||
// FIXME(#112651) `rvalue` may have a subtype to `local`. We can only mark
|
// FIXME(#112651) `rvalue` may have a subtype to `local`. We can only mark
|
||||||
// `local` as reusable if we have an exact type match.
|
// `local` as reusable if we have an exact type match.
|
||||||
if state.local_decls[local].ty != rvalue.ty(state.local_decls, tcx) {
|
if state.local_decls[local].ty != rvalue.ty(state.local_decls, tcx) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
value
|
||||||
}
|
}
|
||||||
value
|
};
|
||||||
}
|
// `next_opaque` is `Some`, so `new_opaque` must return `Some`.
|
||||||
};
|
let value = value.or_else(|| state.new_opaque()).unwrap();
|
||||||
// `next_opaque` is `Some`, so `new_opaque` must return `Some`.
|
state.assign(local, value);
|
||||||
let value = value.or_else(|| state.new_opaque()).unwrap();
|
},
|
||||||
state.assign(local, value);
|
);
|
||||||
},
|
|
||||||
);
|
|
||||||
|
|
||||||
// Stop creating opaques during replacement as it is useless.
|
// Stop creating opaques during replacement as it is useless.
|
||||||
state.next_opaque = None;
|
state.next_opaque = None;
|
||||||
|
|
||||||
let reverse_postorder = body.basic_blocks.reverse_postorder().to_vec();
|
let reverse_postorder = body.basic_blocks.reverse_postorder().to_vec();
|
||||||
for bb in reverse_postorder {
|
for bb in reverse_postorder {
|
||||||
let data = &mut body.basic_blocks.as_mut_preserves_cfg()[bb];
|
let data = &mut body.basic_blocks.as_mut_preserves_cfg()[bb];
|
||||||
state.visit_basic_block_data(bb, data);
|
state.visit_basic_block_data(bb, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
// For each local that is reused (`y` above), we remove its storage statements do avoid any
|
||||||
|
// difficulty. Those locals are SSA, so should be easy to optimize by LLVM without storage
|
||||||
|
// statements.
|
||||||
|
StorageRemover { tcx, reused_locals: state.reused_locals }.visit_body_preserves_cfg(body);
|
||||||
}
|
}
|
||||||
|
|
||||||
// For each local that is reused (`y` above), we remove its storage statements do avoid any
|
|
||||||
// difficulty. Those locals are SSA, so should be easy to optimize by LLVM without storage
|
|
||||||
// statements.
|
|
||||||
StorageRemover { tcx, reused_locals: state.reused_locals }.visit_body_preserves_cfg(body);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
newtype_index! {
|
newtype_index! {
|
||||||
|
|
|
@ -18,19 +18,13 @@ pub(super) enum InstSimplify {
|
||||||
AfterSimplifyCfg,
|
AfterSimplifyCfg,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl InstSimplify {
|
impl<'tcx> crate::MirPass<'tcx> for InstSimplify {
|
||||||
fn name(&self) -> &'static str {
|
fn name(&self) -> &'static str {
|
||||||
match self {
|
match self {
|
||||||
InstSimplify::BeforeInline => "InstSimplify-before-inline",
|
InstSimplify::BeforeInline => "InstSimplify-before-inline",
|
||||||
InstSimplify::AfterSimplifyCfg => "InstSimplify-after-simplifycfg",
|
InstSimplify::AfterSimplifyCfg => "InstSimplify-after-simplifycfg",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
impl<'tcx> crate::MirPass<'tcx> for InstSimplify {
|
|
||||||
fn name(&self) -> &'static str {
|
|
||||||
self.name()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn is_enabled(&self, sess: &rustc_session::Session) -> bool {
|
fn is_enabled(&self, sess: &rustc_session::Session) -> bool {
|
||||||
sess.mir_opt_level() > 0
|
sess.mir_opt_level() > 0
|
||||||
|
|
|
@ -37,7 +37,169 @@ impl<'tcx> crate::MirPass<'tcx> for EnumSizeOpt {
|
||||||
fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
|
fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
|
||||||
// NOTE: This pass may produce different MIR based on the alignment of the target
|
// NOTE: This pass may produce different MIR based on the alignment of the target
|
||||||
// platform, but it will still be valid.
|
// platform, but it will still be valid.
|
||||||
self.optim(tcx, body);
|
|
||||||
|
let mut alloc_cache = FxHashMap::default();
|
||||||
|
let body_did = body.source.def_id();
|
||||||
|
let param_env = tcx.param_env_reveal_all_normalized(body_did);
|
||||||
|
|
||||||
|
let blocks = body.basic_blocks.as_mut();
|
||||||
|
let local_decls = &mut body.local_decls;
|
||||||
|
|
||||||
|
for bb in blocks {
|
||||||
|
bb.expand_statements(|st| {
|
||||||
|
let StatementKind::Assign(box (
|
||||||
|
lhs,
|
||||||
|
Rvalue::Use(Operand::Copy(rhs) | Operand::Move(rhs)),
|
||||||
|
)) = &st.kind
|
||||||
|
else {
|
||||||
|
return None;
|
||||||
|
};
|
||||||
|
|
||||||
|
let ty = lhs.ty(local_decls, tcx).ty;
|
||||||
|
|
||||||
|
let (adt_def, num_variants, alloc_id) =
|
||||||
|
self.candidate(tcx, param_env, ty, &mut alloc_cache)?;
|
||||||
|
|
||||||
|
let source_info = st.source_info;
|
||||||
|
let span = source_info.span;
|
||||||
|
|
||||||
|
let tmp_ty = Ty::new_array(tcx, tcx.types.usize, num_variants as u64);
|
||||||
|
let size_array_local = local_decls.push(LocalDecl::new(tmp_ty, span));
|
||||||
|
let store_live =
|
||||||
|
Statement { source_info, kind: StatementKind::StorageLive(size_array_local) };
|
||||||
|
|
||||||
|
let place = Place::from(size_array_local);
|
||||||
|
let constant_vals = ConstOperand {
|
||||||
|
span,
|
||||||
|
user_ty: None,
|
||||||
|
const_: Const::Val(
|
||||||
|
ConstValue::Indirect { alloc_id, offset: Size::ZERO },
|
||||||
|
tmp_ty,
|
||||||
|
),
|
||||||
|
};
|
||||||
|
let rval = Rvalue::Use(Operand::Constant(Box::new(constant_vals)));
|
||||||
|
let const_assign =
|
||||||
|
Statement { source_info, kind: StatementKind::Assign(Box::new((place, rval))) };
|
||||||
|
|
||||||
|
let discr_place = Place::from(
|
||||||
|
local_decls.push(LocalDecl::new(adt_def.repr().discr_type().to_ty(tcx), span)),
|
||||||
|
);
|
||||||
|
let store_discr = Statement {
|
||||||
|
source_info,
|
||||||
|
kind: StatementKind::Assign(Box::new((
|
||||||
|
discr_place,
|
||||||
|
Rvalue::Discriminant(*rhs),
|
||||||
|
))),
|
||||||
|
};
|
||||||
|
|
||||||
|
let discr_cast_place =
|
||||||
|
Place::from(local_decls.push(LocalDecl::new(tcx.types.usize, span)));
|
||||||
|
let cast_discr = Statement {
|
||||||
|
source_info,
|
||||||
|
kind: StatementKind::Assign(Box::new((
|
||||||
|
discr_cast_place,
|
||||||
|
Rvalue::Cast(
|
||||||
|
CastKind::IntToInt,
|
||||||
|
Operand::Copy(discr_place),
|
||||||
|
tcx.types.usize,
|
||||||
|
),
|
||||||
|
))),
|
||||||
|
};
|
||||||
|
|
||||||
|
let size_place =
|
||||||
|
Place::from(local_decls.push(LocalDecl::new(tcx.types.usize, span)));
|
||||||
|
let store_size = Statement {
|
||||||
|
source_info,
|
||||||
|
kind: StatementKind::Assign(Box::new((
|
||||||
|
size_place,
|
||||||
|
Rvalue::Use(Operand::Copy(Place {
|
||||||
|
local: size_array_local,
|
||||||
|
projection: tcx
|
||||||
|
.mk_place_elems(&[PlaceElem::Index(discr_cast_place.local)]),
|
||||||
|
})),
|
||||||
|
))),
|
||||||
|
};
|
||||||
|
|
||||||
|
let dst =
|
||||||
|
Place::from(local_decls.push(LocalDecl::new(Ty::new_mut_ptr(tcx, ty), span)));
|
||||||
|
let dst_ptr = Statement {
|
||||||
|
source_info,
|
||||||
|
kind: StatementKind::Assign(Box::new((
|
||||||
|
dst,
|
||||||
|
Rvalue::RawPtr(Mutability::Mut, *lhs),
|
||||||
|
))),
|
||||||
|
};
|
||||||
|
|
||||||
|
let dst_cast_ty = Ty::new_mut_ptr(tcx, tcx.types.u8);
|
||||||
|
let dst_cast_place =
|
||||||
|
Place::from(local_decls.push(LocalDecl::new(dst_cast_ty, span)));
|
||||||
|
let dst_cast = Statement {
|
||||||
|
source_info,
|
||||||
|
kind: StatementKind::Assign(Box::new((
|
||||||
|
dst_cast_place,
|
||||||
|
Rvalue::Cast(CastKind::PtrToPtr, Operand::Copy(dst), dst_cast_ty),
|
||||||
|
))),
|
||||||
|
};
|
||||||
|
|
||||||
|
let src =
|
||||||
|
Place::from(local_decls.push(LocalDecl::new(Ty::new_imm_ptr(tcx, ty), span)));
|
||||||
|
let src_ptr = Statement {
|
||||||
|
source_info,
|
||||||
|
kind: StatementKind::Assign(Box::new((
|
||||||
|
src,
|
||||||
|
Rvalue::RawPtr(Mutability::Not, *rhs),
|
||||||
|
))),
|
||||||
|
};
|
||||||
|
|
||||||
|
let src_cast_ty = Ty::new_imm_ptr(tcx, tcx.types.u8);
|
||||||
|
let src_cast_place =
|
||||||
|
Place::from(local_decls.push(LocalDecl::new(src_cast_ty, span)));
|
||||||
|
let src_cast = Statement {
|
||||||
|
source_info,
|
||||||
|
kind: StatementKind::Assign(Box::new((
|
||||||
|
src_cast_place,
|
||||||
|
Rvalue::Cast(CastKind::PtrToPtr, Operand::Copy(src), src_cast_ty),
|
||||||
|
))),
|
||||||
|
};
|
||||||
|
|
||||||
|
let deinit_old =
|
||||||
|
Statement { source_info, kind: StatementKind::Deinit(Box::new(dst)) };
|
||||||
|
|
||||||
|
let copy_bytes = Statement {
|
||||||
|
source_info,
|
||||||
|
kind: StatementKind::Intrinsic(Box::new(
|
||||||
|
NonDivergingIntrinsic::CopyNonOverlapping(CopyNonOverlapping {
|
||||||
|
src: Operand::Copy(src_cast_place),
|
||||||
|
dst: Operand::Copy(dst_cast_place),
|
||||||
|
count: Operand::Copy(size_place),
|
||||||
|
}),
|
||||||
|
)),
|
||||||
|
};
|
||||||
|
|
||||||
|
let store_dead =
|
||||||
|
Statement { source_info, kind: StatementKind::StorageDead(size_array_local) };
|
||||||
|
|
||||||
|
let iter = [
|
||||||
|
store_live,
|
||||||
|
const_assign,
|
||||||
|
store_discr,
|
||||||
|
cast_discr,
|
||||||
|
store_size,
|
||||||
|
dst_ptr,
|
||||||
|
dst_cast,
|
||||||
|
src_ptr,
|
||||||
|
src_cast,
|
||||||
|
deinit_old,
|
||||||
|
copy_bytes,
|
||||||
|
store_dead,
|
||||||
|
]
|
||||||
|
.into_iter();
|
||||||
|
|
||||||
|
st.make_nop();
|
||||||
|
|
||||||
|
Some(iter)
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -116,185 +278,4 @@ impl EnumSizeOpt {
|
||||||
let alloc = tcx.reserve_and_set_memory_alloc(tcx.mk_const_alloc(alloc));
|
let alloc = tcx.reserve_and_set_memory_alloc(tcx.mk_const_alloc(alloc));
|
||||||
Some((*adt_def, num_discrs, *alloc_cache.entry(ty).or_insert(alloc)))
|
Some((*adt_def, num_discrs, *alloc_cache.entry(ty).or_insert(alloc)))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn optim<'tcx>(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
|
|
||||||
let mut alloc_cache = FxHashMap::default();
|
|
||||||
let body_did = body.source.def_id();
|
|
||||||
let param_env = tcx.param_env_reveal_all_normalized(body_did);
|
|
||||||
|
|
||||||
let blocks = body.basic_blocks.as_mut();
|
|
||||||
let local_decls = &mut body.local_decls;
|
|
||||||
|
|
||||||
for bb in blocks {
|
|
||||||
bb.expand_statements(|st| {
|
|
||||||
if let StatementKind::Assign(box (
|
|
||||||
lhs,
|
|
||||||
Rvalue::Use(Operand::Copy(rhs) | Operand::Move(rhs)),
|
|
||||||
)) = &st.kind
|
|
||||||
{
|
|
||||||
let ty = lhs.ty(local_decls, tcx).ty;
|
|
||||||
|
|
||||||
let source_info = st.source_info;
|
|
||||||
let span = source_info.span;
|
|
||||||
|
|
||||||
let (adt_def, num_variants, alloc_id) =
|
|
||||||
self.candidate(tcx, param_env, ty, &mut alloc_cache)?;
|
|
||||||
|
|
||||||
let tmp_ty = Ty::new_array(tcx, tcx.types.usize, num_variants as u64);
|
|
||||||
|
|
||||||
let size_array_local = local_decls.push(LocalDecl::new(tmp_ty, span));
|
|
||||||
let store_live = Statement {
|
|
||||||
source_info,
|
|
||||||
kind: StatementKind::StorageLive(size_array_local),
|
|
||||||
};
|
|
||||||
|
|
||||||
let place = Place::from(size_array_local);
|
|
||||||
let constant_vals = ConstOperand {
|
|
||||||
span,
|
|
||||||
user_ty: None,
|
|
||||||
const_: Const::Val(
|
|
||||||
ConstValue::Indirect { alloc_id, offset: Size::ZERO },
|
|
||||||
tmp_ty,
|
|
||||||
),
|
|
||||||
};
|
|
||||||
let rval = Rvalue::Use(Operand::Constant(Box::new(constant_vals)));
|
|
||||||
|
|
||||||
let const_assign = Statement {
|
|
||||||
source_info,
|
|
||||||
kind: StatementKind::Assign(Box::new((place, rval))),
|
|
||||||
};
|
|
||||||
|
|
||||||
let discr_place = Place::from(
|
|
||||||
local_decls
|
|
||||||
.push(LocalDecl::new(adt_def.repr().discr_type().to_ty(tcx), span)),
|
|
||||||
);
|
|
||||||
|
|
||||||
let store_discr = Statement {
|
|
||||||
source_info,
|
|
||||||
kind: StatementKind::Assign(Box::new((
|
|
||||||
discr_place,
|
|
||||||
Rvalue::Discriminant(*rhs),
|
|
||||||
))),
|
|
||||||
};
|
|
||||||
|
|
||||||
let discr_cast_place =
|
|
||||||
Place::from(local_decls.push(LocalDecl::new(tcx.types.usize, span)));
|
|
||||||
|
|
||||||
let cast_discr = Statement {
|
|
||||||
source_info,
|
|
||||||
kind: StatementKind::Assign(Box::new((
|
|
||||||
discr_cast_place,
|
|
||||||
Rvalue::Cast(
|
|
||||||
CastKind::IntToInt,
|
|
||||||
Operand::Copy(discr_place),
|
|
||||||
tcx.types.usize,
|
|
||||||
),
|
|
||||||
))),
|
|
||||||
};
|
|
||||||
|
|
||||||
let size_place =
|
|
||||||
Place::from(local_decls.push(LocalDecl::new(tcx.types.usize, span)));
|
|
||||||
|
|
||||||
let store_size = Statement {
|
|
||||||
source_info,
|
|
||||||
kind: StatementKind::Assign(Box::new((
|
|
||||||
size_place,
|
|
||||||
Rvalue::Use(Operand::Copy(Place {
|
|
||||||
local: size_array_local,
|
|
||||||
projection: tcx
|
|
||||||
.mk_place_elems(&[PlaceElem::Index(discr_cast_place.local)]),
|
|
||||||
})),
|
|
||||||
))),
|
|
||||||
};
|
|
||||||
|
|
||||||
let dst = Place::from(
|
|
||||||
local_decls.push(LocalDecl::new(Ty::new_mut_ptr(tcx, ty), span)),
|
|
||||||
);
|
|
||||||
|
|
||||||
let dst_ptr = Statement {
|
|
||||||
source_info,
|
|
||||||
kind: StatementKind::Assign(Box::new((
|
|
||||||
dst,
|
|
||||||
Rvalue::RawPtr(Mutability::Mut, *lhs),
|
|
||||||
))),
|
|
||||||
};
|
|
||||||
|
|
||||||
let dst_cast_ty = Ty::new_mut_ptr(tcx, tcx.types.u8);
|
|
||||||
let dst_cast_place =
|
|
||||||
Place::from(local_decls.push(LocalDecl::new(dst_cast_ty, span)));
|
|
||||||
|
|
||||||
let dst_cast = Statement {
|
|
||||||
source_info,
|
|
||||||
kind: StatementKind::Assign(Box::new((
|
|
||||||
dst_cast_place,
|
|
||||||
Rvalue::Cast(CastKind::PtrToPtr, Operand::Copy(dst), dst_cast_ty),
|
|
||||||
))),
|
|
||||||
};
|
|
||||||
|
|
||||||
let src = Place::from(
|
|
||||||
local_decls.push(LocalDecl::new(Ty::new_imm_ptr(tcx, ty), span)),
|
|
||||||
);
|
|
||||||
|
|
||||||
let src_ptr = Statement {
|
|
||||||
source_info,
|
|
||||||
kind: StatementKind::Assign(Box::new((
|
|
||||||
src,
|
|
||||||
Rvalue::RawPtr(Mutability::Not, *rhs),
|
|
||||||
))),
|
|
||||||
};
|
|
||||||
|
|
||||||
let src_cast_ty = Ty::new_imm_ptr(tcx, tcx.types.u8);
|
|
||||||
let src_cast_place =
|
|
||||||
Place::from(local_decls.push(LocalDecl::new(src_cast_ty, span)));
|
|
||||||
|
|
||||||
let src_cast = Statement {
|
|
||||||
source_info,
|
|
||||||
kind: StatementKind::Assign(Box::new((
|
|
||||||
src_cast_place,
|
|
||||||
Rvalue::Cast(CastKind::PtrToPtr, Operand::Copy(src), src_cast_ty),
|
|
||||||
))),
|
|
||||||
};
|
|
||||||
|
|
||||||
let deinit_old =
|
|
||||||
Statement { source_info, kind: StatementKind::Deinit(Box::new(dst)) };
|
|
||||||
|
|
||||||
let copy_bytes = Statement {
|
|
||||||
source_info,
|
|
||||||
kind: StatementKind::Intrinsic(Box::new(
|
|
||||||
NonDivergingIntrinsic::CopyNonOverlapping(CopyNonOverlapping {
|
|
||||||
src: Operand::Copy(src_cast_place),
|
|
||||||
dst: Operand::Copy(dst_cast_place),
|
|
||||||
count: Operand::Copy(size_place),
|
|
||||||
}),
|
|
||||||
)),
|
|
||||||
};
|
|
||||||
|
|
||||||
let store_dead = Statement {
|
|
||||||
source_info,
|
|
||||||
kind: StatementKind::StorageDead(size_array_local),
|
|
||||||
};
|
|
||||||
let iter = [
|
|
||||||
store_live,
|
|
||||||
const_assign,
|
|
||||||
store_discr,
|
|
||||||
cast_discr,
|
|
||||||
store_size,
|
|
||||||
dst_ptr,
|
|
||||||
dst_cast,
|
|
||||||
src_ptr,
|
|
||||||
src_cast,
|
|
||||||
deinit_old,
|
|
||||||
copy_bytes,
|
|
||||||
store_dead,
|
|
||||||
]
|
|
||||||
.into_iter();
|
|
||||||
|
|
||||||
st.make_nop();
|
|
||||||
Some(iter)
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,22 +13,18 @@ impl<'tcx> crate::MirPass<'tcx> for LowerSliceLenCalls {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
|
fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
|
||||||
lower_slice_len_calls(tcx, body)
|
let language_items = tcx.lang_items();
|
||||||
}
|
let Some(slice_len_fn_item_def_id) = language_items.slice_len_fn() else {
|
||||||
}
|
// there is no lang item to compare to :)
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
|
||||||
fn lower_slice_len_calls<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
|
// The one successor remains unchanged, so no need to invalidate
|
||||||
let language_items = tcx.lang_items();
|
let basic_blocks = body.basic_blocks.as_mut_preserves_cfg();
|
||||||
let Some(slice_len_fn_item_def_id) = language_items.slice_len_fn() else {
|
for block in basic_blocks {
|
||||||
// there is no lang item to compare to :)
|
// lower `<[_]>::len` calls
|
||||||
return;
|
lower_slice_len_call(block, slice_len_fn_item_def_id);
|
||||||
};
|
}
|
||||||
|
|
||||||
// The one successor remains unchanged, so no need to invalidate
|
|
||||||
let basic_blocks = body.basic_blocks.as_mut_preserves_cfg();
|
|
||||||
for block in basic_blocks {
|
|
||||||
// lower `<[_]>::len` calls
|
|
||||||
lower_slice_len_call(block, slice_len_fn_item_def_id);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -18,7 +18,61 @@ impl<'tcx> crate::MirPass<'tcx> for RemoveNoopLandingPads {
|
||||||
fn run_pass(&self, _tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
|
fn run_pass(&self, _tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
|
||||||
let def_id = body.source.def_id();
|
let def_id = body.source.def_id();
|
||||||
debug!(?def_id);
|
debug!(?def_id);
|
||||||
self.remove_nop_landing_pads(body)
|
|
||||||
|
// Skip the pass if there are no blocks with a resume terminator.
|
||||||
|
let has_resume = body
|
||||||
|
.basic_blocks
|
||||||
|
.iter_enumerated()
|
||||||
|
.any(|(_bb, block)| matches!(block.terminator().kind, TerminatorKind::UnwindResume));
|
||||||
|
if !has_resume {
|
||||||
|
debug!("remove_noop_landing_pads: no resume block in MIR");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// make sure there's a resume block without any statements
|
||||||
|
let resume_block = {
|
||||||
|
let mut patch = MirPatch::new(body);
|
||||||
|
let resume_block = patch.resume_block();
|
||||||
|
patch.apply(body);
|
||||||
|
resume_block
|
||||||
|
};
|
||||||
|
debug!("remove_noop_landing_pads: resume block is {:?}", resume_block);
|
||||||
|
|
||||||
|
let mut jumps_folded = 0;
|
||||||
|
let mut landing_pads_removed = 0;
|
||||||
|
let mut nop_landing_pads = BitSet::new_empty(body.basic_blocks.len());
|
||||||
|
|
||||||
|
// This is a post-order traversal, so that if A post-dominates B
|
||||||
|
// then A will be visited before B.
|
||||||
|
let postorder: Vec<_> = traversal::postorder(body).map(|(bb, _)| bb).collect();
|
||||||
|
for bb in postorder {
|
||||||
|
debug!(" processing {:?}", bb);
|
||||||
|
if let Some(unwind) = body[bb].terminator_mut().unwind_mut() {
|
||||||
|
if let UnwindAction::Cleanup(unwind_bb) = *unwind {
|
||||||
|
if nop_landing_pads.contains(unwind_bb) {
|
||||||
|
debug!(" removing noop landing pad");
|
||||||
|
landing_pads_removed += 1;
|
||||||
|
*unwind = UnwindAction::Continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for target in body[bb].terminator_mut().successors_mut() {
|
||||||
|
if *target != resume_block && nop_landing_pads.contains(*target) {
|
||||||
|
debug!(" folding noop jump to {:?} to resume block", target);
|
||||||
|
*target = resume_block;
|
||||||
|
jumps_folded += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let is_nop_landing_pad = self.is_nop_landing_pad(bb, body, &nop_landing_pads);
|
||||||
|
if is_nop_landing_pad {
|
||||||
|
nop_landing_pads.insert(bb);
|
||||||
|
}
|
||||||
|
debug!(" is_nop_landing_pad({:?}) = {}", bb, is_nop_landing_pad);
|
||||||
|
}
|
||||||
|
|
||||||
|
debug!("removed {:?} jumps and {:?} landing pads", jumps_folded, landing_pads_removed);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -82,61 +136,4 @@ impl RemoveNoopLandingPads {
|
||||||
| TerminatorKind::InlineAsm { .. } => false,
|
| TerminatorKind::InlineAsm { .. } => false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn remove_nop_landing_pads(&self, body: &mut Body<'_>) {
|
|
||||||
// Skip the pass if there are no blocks with a resume terminator.
|
|
||||||
let has_resume = body
|
|
||||||
.basic_blocks
|
|
||||||
.iter_enumerated()
|
|
||||||
.any(|(_bb, block)| matches!(block.terminator().kind, TerminatorKind::UnwindResume));
|
|
||||||
if !has_resume {
|
|
||||||
debug!("remove_noop_landing_pads: no resume block in MIR");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// make sure there's a resume block without any statements
|
|
||||||
let resume_block = {
|
|
||||||
let mut patch = MirPatch::new(body);
|
|
||||||
let resume_block = patch.resume_block();
|
|
||||||
patch.apply(body);
|
|
||||||
resume_block
|
|
||||||
};
|
|
||||||
debug!("remove_noop_landing_pads: resume block is {:?}", resume_block);
|
|
||||||
|
|
||||||
let mut jumps_folded = 0;
|
|
||||||
let mut landing_pads_removed = 0;
|
|
||||||
let mut nop_landing_pads = BitSet::new_empty(body.basic_blocks.len());
|
|
||||||
|
|
||||||
// This is a post-order traversal, so that if A post-dominates B
|
|
||||||
// then A will be visited before B.
|
|
||||||
let postorder: Vec<_> = traversal::postorder(body).map(|(bb, _)| bb).collect();
|
|
||||||
for bb in postorder {
|
|
||||||
debug!(" processing {:?}", bb);
|
|
||||||
if let Some(unwind) = body[bb].terminator_mut().unwind_mut() {
|
|
||||||
if let UnwindAction::Cleanup(unwind_bb) = *unwind {
|
|
||||||
if nop_landing_pads.contains(unwind_bb) {
|
|
||||||
debug!(" removing noop landing pad");
|
|
||||||
landing_pads_removed += 1;
|
|
||||||
*unwind = UnwindAction::Continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for target in body[bb].terminator_mut().successors_mut() {
|
|
||||||
if *target != resume_block && nop_landing_pads.contains(*target) {
|
|
||||||
debug!(" folding noop jump to {:?} to resume block", target);
|
|
||||||
*target = resume_block;
|
|
||||||
jumps_folded += 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let is_nop_landing_pad = self.is_nop_landing_pad(bb, body, &nop_landing_pads);
|
|
||||||
if is_nop_landing_pad {
|
|
||||||
nop_landing_pads.insert(bb);
|
|
||||||
}
|
|
||||||
debug!(" is_nop_landing_pad({:?}) = {}", bb, is_nop_landing_pad);
|
|
||||||
}
|
|
||||||
|
|
||||||
debug!("removed {:?} jumps and {:?} landing pads", jumps_folded, landing_pads_removed);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -381,7 +381,29 @@ impl<'tcx> crate::MirPass<'tcx> for SimplifyLocals {
|
||||||
|
|
||||||
fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
|
fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
|
||||||
trace!("running SimplifyLocals on {:?}", body.source);
|
trace!("running SimplifyLocals on {:?}", body.source);
|
||||||
simplify_locals(body, tcx);
|
|
||||||
|
// First, we're going to get a count of *actual* uses for every `Local`.
|
||||||
|
let mut used_locals = UsedLocals::new(body);
|
||||||
|
|
||||||
|
// Next, we're going to remove any `Local` with zero actual uses. When we remove those
|
||||||
|
// `Locals`, we're also going to subtract any uses of other `Locals` from the `used_locals`
|
||||||
|
// count. For example, if we removed `_2 = discriminant(_1)`, then we'll subtract one from
|
||||||
|
// `use_counts[_1]`. That in turn might make `_1` unused, so we loop until we hit a
|
||||||
|
// fixedpoint where there are no more unused locals.
|
||||||
|
remove_unused_definitions_helper(&mut used_locals, body);
|
||||||
|
|
||||||
|
// Finally, we'll actually do the work of shrinking `body.local_decls` and remapping the
|
||||||
|
// `Local`s.
|
||||||
|
let map = make_local_map(&mut body.local_decls, &used_locals);
|
||||||
|
|
||||||
|
// Only bother running the `LocalUpdater` if we actually found locals to remove.
|
||||||
|
if map.iter().any(Option::is_none) {
|
||||||
|
// Update references to all vars and tmps now
|
||||||
|
let mut updater = LocalUpdater { map, tcx };
|
||||||
|
updater.visit_body_preserves_cfg(body);
|
||||||
|
|
||||||
|
body.local_decls.shrink_to_fit();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -397,30 +419,6 @@ pub(super) fn remove_unused_definitions<'tcx>(body: &mut Body<'tcx>) {
|
||||||
remove_unused_definitions_helper(&mut used_locals, body);
|
remove_unused_definitions_helper(&mut used_locals, body);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn simplify_locals<'tcx>(body: &mut Body<'tcx>, tcx: TyCtxt<'tcx>) {
|
|
||||||
// First, we're going to get a count of *actual* uses for every `Local`.
|
|
||||||
let mut used_locals = UsedLocals::new(body);
|
|
||||||
|
|
||||||
// Next, we're going to remove any `Local` with zero actual uses. When we remove those
|
|
||||||
// `Locals`, we're also going to subtract any uses of other `Locals` from the `used_locals`
|
|
||||||
// count. For example, if we removed `_2 = discriminant(_1)`, then we'll subtract one from
|
|
||||||
// `use_counts[_1]`. That in turn might make `_1` unused, so we loop until we hit a
|
|
||||||
// fixedpoint where there are no more unused locals.
|
|
||||||
remove_unused_definitions_helper(&mut used_locals, body);
|
|
||||||
|
|
||||||
// Finally, we'll actually do the work of shrinking `body.local_decls` and remapping the `Local`s.
|
|
||||||
let map = make_local_map(&mut body.local_decls, &used_locals);
|
|
||||||
|
|
||||||
// Only bother running the `LocalUpdater` if we actually found locals to remove.
|
|
||||||
if map.iter().any(Option::is_none) {
|
|
||||||
// Update references to all vars and tmps now
|
|
||||||
let mut updater = LocalUpdater { map, tcx };
|
|
||||||
updater.visit_body_preserves_cfg(body);
|
|
||||||
|
|
||||||
body.local_decls.shrink_to_fit();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Construct the mapping while swapping out unused stuff out from the `vec`.
|
/// Construct the mapping while swapping out unused stuff out from the `vec`.
|
||||||
fn make_local_map<V>(
|
fn make_local_map<V>(
|
||||||
local_decls: &mut IndexVec<Local, V>,
|
local_decls: &mut IndexVec<Local, V>,
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue