Remove duplicated implementations of borrowed locals analysis
This commit is contained in:
parent
37a42258ff
commit
915f091819
4 changed files with 29 additions and 133 deletions
|
@ -145,3 +145,23 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The set of locals that are borrowed at some point in the MIR body.
|
||||||
|
pub fn borrowed_locals(body: &Body<'_>) -> BitSet<Local> {
|
||||||
|
struct Borrowed(BitSet<Local>);
|
||||||
|
|
||||||
|
impl GenKill<Local> for Borrowed {
|
||||||
|
#[inline]
|
||||||
|
fn gen(&mut self, elem: Local) {
|
||||||
|
self.0.gen(elem)
|
||||||
|
}
|
||||||
|
#[inline]
|
||||||
|
fn kill(&mut self, _: Local) {
|
||||||
|
// Ignore borrow invalidation.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut borrowed = Borrowed(BitSet::new_empty(body.local_decls.len()));
|
||||||
|
TransferFunction { trans: &mut borrowed }.visit_body(body);
|
||||||
|
borrowed.0
|
||||||
|
}
|
||||||
|
|
|
@ -23,6 +23,7 @@ mod init_locals;
|
||||||
mod liveness;
|
mod liveness;
|
||||||
mod storage_liveness;
|
mod storage_liveness;
|
||||||
|
|
||||||
|
pub use self::borrowed_locals::borrowed_locals;
|
||||||
pub use self::borrowed_locals::MaybeBorrowedLocals;
|
pub use self::borrowed_locals::MaybeBorrowedLocals;
|
||||||
pub use self::init_locals::MaybeInitializedLocals;
|
pub use self::init_locals::MaybeInitializedLocals;
|
||||||
pub use self::liveness::MaybeLiveLocals;
|
pub use self::liveness::MaybeLiveLocals;
|
||||||
|
|
|
@ -13,16 +13,15 @@
|
||||||
//!
|
//!
|
||||||
|
|
||||||
use rustc_index::bit_set::BitSet;
|
use rustc_index::bit_set::BitSet;
|
||||||
use rustc_middle::{
|
use rustc_middle::mir::*;
|
||||||
mir::{visit::Visitor, *},
|
use rustc_middle::ty::TyCtxt;
|
||||||
ty::TyCtxt,
|
use rustc_mir_dataflow::impls::{borrowed_locals, MaybeTransitiveLiveLocals};
|
||||||
};
|
use rustc_mir_dataflow::Analysis;
|
||||||
use rustc_mir_dataflow::{impls::MaybeTransitiveLiveLocals, Analysis};
|
|
||||||
|
|
||||||
/// Performs the optimization on the body
|
/// Performs the optimization on the body
|
||||||
///
|
///
|
||||||
/// The `borrowed` set must be a `BitSet` of all the locals that are ever borrowed in this body. It
|
/// The `borrowed` set must be a `BitSet` of all the locals that are ever borrowed in this body. It
|
||||||
/// can be generated via the [`get_borrowed_locals`] function.
|
/// can be generated via the [`borrowed_locals`] function.
|
||||||
pub fn eliminate<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>, borrowed: &BitSet<Local>) {
|
pub fn eliminate<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>, borrowed: &BitSet<Local>) {
|
||||||
let mut live = MaybeTransitiveLiveLocals::new(borrowed)
|
let mut live = MaybeTransitiveLiveLocals::new(borrowed)
|
||||||
.into_engine(tcx, body)
|
.into_engine(tcx, body)
|
||||||
|
@ -73,67 +72,6 @@ pub fn eliminate<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>, borrowed: &BitS
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_borrowed_locals(body: &Body<'_>) -> BitSet<Local> {
|
|
||||||
let mut b = BorrowedLocals(BitSet::new_empty(body.local_decls.len()));
|
|
||||||
b.visit_body(body);
|
|
||||||
b.0
|
|
||||||
}
|
|
||||||
|
|
||||||
struct BorrowedLocals(BitSet<Local>);
|
|
||||||
|
|
||||||
impl<'tcx> Visitor<'tcx> for BorrowedLocals {
|
|
||||||
fn visit_rvalue(&mut self, rvalue: &Rvalue<'tcx>, loc: Location) {
|
|
||||||
self.super_rvalue(rvalue, loc);
|
|
||||||
match rvalue {
|
|
||||||
Rvalue::AddressOf(_, borrowed_place) | Rvalue::Ref(_, _, borrowed_place) => {
|
|
||||||
if !borrowed_place.is_indirect() {
|
|
||||||
self.0.insert(borrowed_place.local);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Rvalue::Cast(..)
|
|
||||||
| Rvalue::ShallowInitBox(..)
|
|
||||||
| Rvalue::Use(..)
|
|
||||||
| Rvalue::Repeat(..)
|
|
||||||
| Rvalue::Len(..)
|
|
||||||
| Rvalue::BinaryOp(..)
|
|
||||||
| Rvalue::CheckedBinaryOp(..)
|
|
||||||
| Rvalue::NullaryOp(..)
|
|
||||||
| Rvalue::UnaryOp(..)
|
|
||||||
| Rvalue::Discriminant(..)
|
|
||||||
| Rvalue::Aggregate(..)
|
|
||||||
| Rvalue::ThreadLocalRef(..) => {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn visit_terminator(&mut self, terminator: &Terminator<'tcx>, location: Location) {
|
|
||||||
self.super_terminator(terminator, location);
|
|
||||||
|
|
||||||
match terminator.kind {
|
|
||||||
TerminatorKind::Drop { place: dropped_place, .. } => {
|
|
||||||
if !dropped_place.is_indirect() {
|
|
||||||
self.0.insert(dropped_place.local);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
TerminatorKind::Abort
|
|
||||||
| TerminatorKind::DropAndReplace { .. }
|
|
||||||
| TerminatorKind::Assert { .. }
|
|
||||||
| TerminatorKind::Call { .. }
|
|
||||||
| TerminatorKind::FalseEdge { .. }
|
|
||||||
| TerminatorKind::FalseUnwind { .. }
|
|
||||||
| TerminatorKind::GeneratorDrop
|
|
||||||
| TerminatorKind::Goto { .. }
|
|
||||||
| TerminatorKind::Resume
|
|
||||||
| TerminatorKind::Return
|
|
||||||
| TerminatorKind::SwitchInt { .. }
|
|
||||||
| TerminatorKind::Unreachable
|
|
||||||
| TerminatorKind::Yield { .. }
|
|
||||||
| TerminatorKind::InlineAsm { .. } => {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct DeadStoreElimination;
|
pub struct DeadStoreElimination;
|
||||||
|
|
||||||
impl<'tcx> MirPass<'tcx> for DeadStoreElimination {
|
impl<'tcx> MirPass<'tcx> for DeadStoreElimination {
|
||||||
|
@ -142,7 +80,7 @@ impl<'tcx> MirPass<'tcx> for DeadStoreElimination {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
|
fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
|
||||||
let borrowed = get_borrowed_locals(body);
|
let borrowed = borrowed_locals(body);
|
||||||
eliminate(tcx, body, &borrowed);
|
eliminate(tcx, body, &borrowed);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -104,7 +104,7 @@ use rustc_middle::mir::{
|
||||||
Rvalue, Statement, StatementKind, Terminator, TerminatorKind,
|
Rvalue, Statement, StatementKind, Terminator, TerminatorKind,
|
||||||
};
|
};
|
||||||
use rustc_middle::ty::TyCtxt;
|
use rustc_middle::ty::TyCtxt;
|
||||||
use rustc_mir_dataflow::impls::{MaybeInitializedLocals, MaybeLiveLocals};
|
use rustc_mir_dataflow::impls::{borrowed_locals, MaybeInitializedLocals, MaybeLiveLocals};
|
||||||
use rustc_mir_dataflow::Analysis;
|
use rustc_mir_dataflow::Analysis;
|
||||||
|
|
||||||
// Empirical measurements have resulted in some observations:
|
// Empirical measurements have resulted in some observations:
|
||||||
|
@ -805,7 +805,7 @@ fn find_candidates<'tcx>(body: &Body<'tcx>) -> Vec<CandidateAssignment<'tcx>> {
|
||||||
let mut visitor = FindAssignments {
|
let mut visitor = FindAssignments {
|
||||||
body,
|
body,
|
||||||
candidates: Vec::new(),
|
candidates: Vec::new(),
|
||||||
ever_borrowed_locals: ever_borrowed_locals(body),
|
ever_borrowed_locals: borrowed_locals(body),
|
||||||
locals_used_as_array_index: locals_used_as_array_index(body),
|
locals_used_as_array_index: locals_used_as_array_index(body),
|
||||||
};
|
};
|
||||||
visitor.visit_body(body);
|
visitor.visit_body(body);
|
||||||
|
@ -886,69 +886,6 @@ fn is_local_required(local: Local, body: &Body<'_>) -> bool {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Walks MIR to find all locals that have their address taken anywhere.
|
|
||||||
fn ever_borrowed_locals(body: &Body<'_>) -> BitSet<Local> {
|
|
||||||
let mut visitor = BorrowCollector { locals: BitSet::new_empty(body.local_decls.len()) };
|
|
||||||
visitor.visit_body(body);
|
|
||||||
visitor.locals
|
|
||||||
}
|
|
||||||
|
|
||||||
struct BorrowCollector {
|
|
||||||
locals: BitSet<Local>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'tcx> Visitor<'tcx> for BorrowCollector {
|
|
||||||
fn visit_rvalue(&mut self, rvalue: &Rvalue<'tcx>, location: Location) {
|
|
||||||
self.super_rvalue(rvalue, location);
|
|
||||||
|
|
||||||
match rvalue {
|
|
||||||
Rvalue::AddressOf(_, borrowed_place) | Rvalue::Ref(_, _, borrowed_place) => {
|
|
||||||
if !borrowed_place.is_indirect() {
|
|
||||||
self.locals.insert(borrowed_place.local);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Rvalue::Cast(..)
|
|
||||||
| Rvalue::ShallowInitBox(..)
|
|
||||||
| Rvalue::Use(..)
|
|
||||||
| Rvalue::Repeat(..)
|
|
||||||
| Rvalue::Len(..)
|
|
||||||
| Rvalue::BinaryOp(..)
|
|
||||||
| Rvalue::CheckedBinaryOp(..)
|
|
||||||
| Rvalue::NullaryOp(..)
|
|
||||||
| Rvalue::UnaryOp(..)
|
|
||||||
| Rvalue::Discriminant(..)
|
|
||||||
| Rvalue::Aggregate(..)
|
|
||||||
| Rvalue::ThreadLocalRef(..) => {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn visit_terminator(&mut self, terminator: &Terminator<'tcx>, location: Location) {
|
|
||||||
self.super_terminator(terminator, location);
|
|
||||||
|
|
||||||
match terminator.kind {
|
|
||||||
TerminatorKind::Drop { place: dropped_place, .. }
|
|
||||||
| TerminatorKind::DropAndReplace { place: dropped_place, .. } => {
|
|
||||||
self.locals.insert(dropped_place.local);
|
|
||||||
}
|
|
||||||
|
|
||||||
TerminatorKind::Abort
|
|
||||||
| TerminatorKind::Assert { .. }
|
|
||||||
| TerminatorKind::Call { .. }
|
|
||||||
| TerminatorKind::FalseEdge { .. }
|
|
||||||
| TerminatorKind::FalseUnwind { .. }
|
|
||||||
| TerminatorKind::GeneratorDrop
|
|
||||||
| TerminatorKind::Goto { .. }
|
|
||||||
| TerminatorKind::Resume
|
|
||||||
| TerminatorKind::Return
|
|
||||||
| TerminatorKind::SwitchInt { .. }
|
|
||||||
| TerminatorKind::Unreachable
|
|
||||||
| TerminatorKind::Yield { .. }
|
|
||||||
| TerminatorKind::InlineAsm { .. } => {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// `PlaceElem::Index` only stores a `Local`, so we can't replace that with a full `Place`.
|
/// `PlaceElem::Index` only stores a `Local`, so we can't replace that with a full `Place`.
|
||||||
///
|
///
|
||||||
/// Collect locals used as indices so we don't generate candidates that are impossible to apply
|
/// Collect locals used as indices so we don't generate candidates that are impossible to apply
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue