Skip to content

Commit 480287e

Browse files
committed
librustc: Implement def-use chains and trivial copy propagation on MIR.
This only supports trivial cases in which there is exactly one def and one use.
1 parent 2e6a918 commit 480287e

File tree

14 files changed

+560
-32
lines changed

14 files changed

+560
-32
lines changed

src/librustc/mir/repr.rs

+46
Original file line numberDiff line numberDiff line change
@@ -188,6 +188,24 @@ impl<'tcx> Mir<'tcx> {
188188
self.temp_decls.len() + 1
189189
}
190190

191+
pub fn format_local(&self, local: Local) -> String {
192+
let mut index = local.index();
193+
index = match index.checked_sub(self.arg_decls.len()) {
194+
None => return format!("{:?}", Arg::new(index)),
195+
Some(index) => index,
196+
};
197+
index = match index.checked_sub(self.var_decls.len()) {
198+
None => return format!("{:?}", Var::new(index)),
199+
Some(index) => index,
200+
};
201+
index = match index.checked_sub(self.temp_decls.len()) {
202+
None => return format!("{:?}", Temp::new(index)),
203+
Some(index) => index,
204+
};
205+
debug_assert!(index == 0);
206+
return "ReturnPointer".to_string()
207+
}
208+
191209
/// Changes a statement to a nop. This is both faster than deleting instructions and avoids
192210
/// invalidating statement indices in `Location`s.
193211
pub fn make_statement_nop(&mut self, location: Location) {
@@ -844,6 +862,24 @@ impl<'tcx> Lvalue<'tcx> {
844862
elem: elem,
845863
}))
846864
}
865+
866+
pub fn from_local(mir: &Mir<'tcx>, local: Local) -> Lvalue<'tcx> {
867+
let mut index = local.index();
868+
index = match index.checked_sub(mir.arg_decls.len()) {
869+
None => return Lvalue::Arg(Arg(index as u32)),
870+
Some(index) => index,
871+
};
872+
index = match index.checked_sub(mir.var_decls.len()) {
873+
None => return Lvalue::Var(Var(index as u32)),
874+
Some(index) => index,
875+
};
876+
index = match index.checked_sub(mir.temp_decls.len()) {
877+
None => return Lvalue::Temp(Temp(index as u32)),
878+
Some(index) => index,
879+
};
880+
debug_assert!(index == 0);
881+
Lvalue::ReturnPointer
882+
}
847883
}
848884

849885
impl<'tcx> Debug for Lvalue<'tcx> {
@@ -1278,3 +1314,13 @@ impl fmt::Debug for Location {
12781314
write!(fmt, "{:?}[{}]", self.block, self.statement_index)
12791315
}
12801316
}
1317+
1318+
impl Location {
1319+
pub fn dominates(&self, other: &Location, dominators: &Dominators<BasicBlock>) -> bool {
1320+
if self.block == other.block {
1321+
self.statement_index <= other.statement_index
1322+
} else {
1323+
dominators.is_dominated_by(other.block, self.block)
1324+
}
1325+
}
1326+
}

src/librustc/mir/visit.rs

+103-5
Original file line numberDiff line numberDiff line change
@@ -150,7 +150,7 @@ macro_rules! make_mir_visitor {
150150

151151
fn visit_lvalue(&mut self,
152152
lvalue: & $($mutability)* Lvalue<'tcx>,
153-
context: LvalueContext,
153+
context: LvalueContext<'tcx>,
154154
location: Location) {
155155
self.super_lvalue(lvalue, context, location);
156156
}
@@ -581,7 +581,7 @@ macro_rules! make_mir_visitor {
581581

582582
fn super_lvalue(&mut self,
583583
lvalue: & $($mutability)* Lvalue<'tcx>,
584-
context: LvalueContext,
584+
context: LvalueContext<'tcx>,
585585
location: Location) {
586586
match *lvalue {
587587
Lvalue::Var(_) |
@@ -606,7 +606,12 @@ macro_rules! make_mir_visitor {
606606
ref $($mutability)* base,
607607
ref $($mutability)* elem,
608608
} = *proj;
609-
self.visit_lvalue(base, LvalueContext::Projection, location);
609+
let context = if context.is_mutating_use() {
610+
LvalueContext::Projection(Mutability::Mut)
611+
} else {
612+
LvalueContext::Projection(Mutability::Not)
613+
};
614+
self.visit_lvalue(base, context, location);
610615
self.visit_projection_elem(elem, context, location);
611616
}
612617

@@ -751,6 +756,21 @@ macro_rules! make_mir_visitor {
751756

752757
fn super_const_usize(&mut self, _substs: & $($mutability)* ConstUsize) {
753758
}
759+
760+
// Convenience methods
761+
762+
fn visit_location(&mut self, mir: & $($mutability)* Mir<'tcx>, location: Location) {
763+
let basic_block = & $($mutability)* mir[location.block];
764+
if basic_block.statements.len() == location.statement_index {
765+
if let Some(ref $($mutability)* terminator) = basic_block.terminator {
766+
self.visit_terminator(location.block, terminator, location)
767+
}
768+
} else {
769+
let statement = & $($mutability)*
770+
basic_block.statements[location.statement_index];
771+
self.visit_statement(location.block, statement, location)
772+
}
773+
}
754774
}
755775
}
756776
}
@@ -775,8 +795,20 @@ pub enum LvalueContext<'tcx> {
775795
// Being borrowed
776796
Borrow { region: &'tcx Region, kind: BorrowKind },
777797

778-
// Used as base for another lvalue, e.g. `x` in `x.y`
779-
Projection,
798+
// Used as base for another lvalue, e.g. `x` in `x.y`.
799+
//
800+
// The `Mutability` argument specifies whether the projection is being performed in order to
801+
// (potentially) mutate the lvalue. For example, the projection `x.y` is marked as a mutation
802+
// in these cases:
803+
//
804+
// x.y = ...;
805+
// f(&mut x.y);
806+
//
807+
// But not in these cases:
808+
//
809+
// z = x.y;
810+
// f(&x.y);
811+
Projection(Mutability),
780812

781813
// Consumed as part of an operand
782814
Consume,
@@ -785,3 +817,69 @@ pub enum LvalueContext<'tcx> {
785817
StorageLive,
786818
StorageDead,
787819
}
820+
821+
impl<'tcx> LvalueContext<'tcx> {
822+
/// Returns true if this lvalue context represents a drop.
823+
pub fn is_drop(&self) -> bool {
824+
match *self {
825+
LvalueContext::Drop => true,
826+
_ => false,
827+
}
828+
}
829+
830+
/// Returns true if this lvalue context represents a storage live or storage dead marker.
831+
pub fn is_storage_marker(&self) -> bool {
832+
match *self {
833+
LvalueContext::StorageLive | LvalueContext::StorageDead => true,
834+
_ => false,
835+
}
836+
}
837+
838+
/// Returns true if this lvalue context represents a storage live marker.
839+
pub fn is_storage_live_marker(&self) -> bool {
840+
match *self {
841+
LvalueContext::StorageLive => true,
842+
_ => false,
843+
}
844+
}
845+
846+
/// Returns true if this lvalue context represents a storage dead marker.
847+
pub fn is_storage_dead_marker(&self) -> bool {
848+
match *self {
849+
LvalueContext::StorageDead => true,
850+
_ => false,
851+
}
852+
}
853+
854+
/// Returns true if this lvalue context represents a use that potentially changes the value.
855+
pub fn is_mutating_use(&self) -> bool {
856+
match *self {
857+
LvalueContext::Store | LvalueContext::Call |
858+
LvalueContext::Borrow { kind: BorrowKind::Mut, .. } |
859+
LvalueContext::Projection(Mutability::Mut) |
860+
LvalueContext::Drop => true,
861+
LvalueContext::Inspect |
862+
LvalueContext::Borrow { kind: BorrowKind::Shared, .. } |
863+
LvalueContext::Borrow { kind: BorrowKind::Unique, .. } |
864+
LvalueContext::Projection(Mutability::Not) | LvalueContext::Consume |
865+
LvalueContext::StorageLive | LvalueContext::StorageDead => false,
866+
}
867+
}
868+
869+
/// Returns true if this lvalue context represents a use that does not change the value.
870+
pub fn is_nonmutating_use(&self) -> bool {
871+
match *self {
872+
LvalueContext::Inspect | LvalueContext::Borrow { kind: BorrowKind::Shared, .. } |
873+
LvalueContext::Borrow { kind: BorrowKind::Unique, .. } |
874+
LvalueContext::Projection(Mutability::Not) | LvalueContext::Consume => true,
875+
LvalueContext::Borrow { kind: BorrowKind::Mut, .. } | LvalueContext::Store |
876+
LvalueContext::Call | LvalueContext::Projection(Mutability::Mut) |
877+
LvalueContext::Drop | LvalueContext::StorageLive | LvalueContext::StorageDead => false,
878+
}
879+
}
880+
881+
pub fn is_use(&self) -> bool {
882+
self.is_mutating_use() || self.is_nonmutating_use()
883+
}
884+
}
885+

src/librustc_borrowck/borrowck/mir/gather_moves.rs

+1
Original file line numberDiff line numberDiff line change
@@ -438,6 +438,7 @@ impl<'a, 'tcx> MoveDataBuilder<'a, 'tcx> {
438438
span_bug!(stmt.source_info.span,
439439
"SetDiscriminant should not exist during borrowck");
440440
}
441+
StatementKind::Nop => {}
441442
}
442443
}
443444

src/librustc_driver/driver.rs

+1
Original file line numberDiff line numberDiff line change
@@ -1028,6 +1028,7 @@ pub fn phase_4_translate_to_llvm<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
10281028
// No lifetime analysis based on borrowing can be done from here on out.
10291029
passes.push_pass(box mir::transform::instcombine::InstCombine::new());
10301030
passes.push_pass(box mir::transform::deaggregator::Deaggregator);
1031+
passes.push_pass(box mir::transform::copy_prop::CopyPropagation);
10311032

10321033
passes.push_pass(box mir::transform::add_call_guards::AddCallGuards);
10331034
passes.push_pass(box mir::transform::dump_mir::Marker("PreTrans"));

0 commit comments

Comments
 (0)