Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit 480287e

Browse files
committedSep 20, 2016
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‎

Lines changed: 46 additions & 0 deletions
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‎

Lines changed: 103 additions & 5 deletions
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‎

Lines changed: 1 addition & 0 deletions
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‎

Lines changed: 1 addition & 0 deletions
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"));

‎src/librustc_mir/def_use.rs‎

Lines changed: 197 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,197 @@
1+
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
//! Def-use analysis.
12+
13+
use rustc::mir::repr::{Local, Location, Lvalue, Mir};
14+
use rustc::mir::visit::{LvalueContext, MutVisitor, Visitor};
15+
use rustc_data_structures::indexed_vec::{Idx, IndexVec};
16+
use std::marker::PhantomData;
17+
use std::mem;
18+
19+
pub struct DefUseAnalysis<'tcx> {
20+
info: IndexVec<Local, Info<'tcx>>,
21+
mir_summary: MirSummary,
22+
}
23+
24+
#[derive(Clone)]
25+
pub struct Info<'tcx> {
26+
pub defs_and_uses: Vec<Use<'tcx>>,
27+
}
28+
29+
#[derive(Clone)]
30+
pub struct Use<'tcx> {
31+
pub context: LvalueContext<'tcx>,
32+
pub location: Location,
33+
}
34+
35+
impl<'tcx> DefUseAnalysis<'tcx> {
36+
pub fn new(mir: &Mir<'tcx>) -> DefUseAnalysis<'tcx> {
37+
DefUseAnalysis {
38+
info: IndexVec::from_elem_n(Info::new(), mir.count_locals()),
39+
mir_summary: MirSummary::new(mir),
40+
}
41+
}
42+
43+
pub fn analyze(&mut self, mir: &Mir<'tcx>) {
44+
let mut finder = DefUseFinder {
45+
info: mem::replace(&mut self.info, IndexVec::new()),
46+
mir_summary: self.mir_summary,
47+
};
48+
finder.visit_mir(mir);
49+
self.info = finder.info
50+
}
51+
52+
pub fn local_info(&self, local: Local) -> &Info<'tcx> {
53+
&self.info[local]
54+
}
55+
56+
pub fn local_info_mut(&mut self, local: Local) -> &mut Info<'tcx> {
57+
&mut self.info[local]
58+
}
59+
60+
fn mutate_defs_and_uses<F>(&self, local: Local, mir: &mut Mir<'tcx>, mut callback: F)
61+
where F: for<'a> FnMut(&'a mut Lvalue<'tcx>,
62+
LvalueContext<'tcx>,
63+
Location) {
64+
for lvalue_use in &self.info[local].defs_and_uses {
65+
MutateUseVisitor::new(local,
66+
&mut callback,
67+
self.mir_summary,
68+
mir).visit_location(mir, lvalue_use.location)
69+
}
70+
}
71+
72+
/// FIXME(pcwalton): This should update the def-use chains.
73+
pub fn replace_all_defs_and_uses_with(&self,
74+
local: Local,
75+
mir: &mut Mir<'tcx>,
76+
new_lvalue: Lvalue<'tcx>) {
77+
self.mutate_defs_and_uses(local, mir, |lvalue, _, _| *lvalue = new_lvalue.clone())
78+
}
79+
}
80+
81+
struct DefUseFinder<'tcx> {
82+
info: IndexVec<Local, Info<'tcx>>,
83+
mir_summary: MirSummary,
84+
}
85+
86+
impl<'tcx> DefUseFinder<'tcx> {
87+
fn lvalue_mut_info(&mut self, lvalue: &Lvalue<'tcx>) -> Option<&mut Info<'tcx>> {
88+
let info = &mut self.info;
89+
self.mir_summary.local_index(lvalue).map(move |local| &mut info[local])
90+
}
91+
}
92+
93+
impl<'tcx> Visitor<'tcx> for DefUseFinder<'tcx> {
94+
fn visit_lvalue(&mut self,
95+
lvalue: &Lvalue<'tcx>,
96+
context: LvalueContext<'tcx>,
97+
location: Location) {
98+
if let Some(ref mut info) = self.lvalue_mut_info(lvalue) {
99+
info.defs_and_uses.push(Use {
100+
context: context,
101+
location: location,
102+
})
103+
}
104+
self.super_lvalue(lvalue, context, location)
105+
}
106+
}
107+
108+
impl<'tcx> Info<'tcx> {
109+
fn new() -> Info<'tcx> {
110+
Info {
111+
defs_and_uses: vec![],
112+
}
113+
}
114+
115+
pub fn def_count(&self) -> usize {
116+
self.defs_and_uses.iter().filter(|lvalue_use| lvalue_use.context.is_mutating_use()).count()
117+
}
118+
119+
pub fn def_count_not_including_drop(&self) -> usize {
120+
self.defs_and_uses.iter().filter(|lvalue_use| {
121+
lvalue_use.context.is_mutating_use() && !lvalue_use.context.is_drop()
122+
}).count()
123+
}
124+
125+
pub fn use_count(&self) -> usize {
126+
self.defs_and_uses.iter().filter(|lvalue_use| {
127+
lvalue_use.context.is_nonmutating_use()
128+
}).count()
129+
}
130+
}
131+
132+
struct MutateUseVisitor<'tcx, F> {
133+
query: Local,
134+
callback: F,
135+
mir_summary: MirSummary,
136+
phantom: PhantomData<&'tcx ()>,
137+
}
138+
139+
impl<'tcx, F> MutateUseVisitor<'tcx, F> {
140+
fn new(query: Local, callback: F, mir_summary: MirSummary, _: &Mir<'tcx>)
141+
-> MutateUseVisitor<'tcx, F>
142+
where F: for<'a> FnMut(&'a mut Lvalue<'tcx>, LvalueContext<'tcx>, Location) {
143+
MutateUseVisitor {
144+
query: query,
145+
callback: callback,
146+
mir_summary: mir_summary,
147+
phantom: PhantomData,
148+
}
149+
}
150+
}
151+
152+
impl<'tcx, F> MutVisitor<'tcx> for MutateUseVisitor<'tcx, F>
153+
where F: for<'a> FnMut(&'a mut Lvalue<'tcx>, LvalueContext<'tcx>, Location) {
154+
fn visit_lvalue(&mut self,
155+
lvalue: &mut Lvalue<'tcx>,
156+
context: LvalueContext<'tcx>,
157+
location: Location) {
158+
if self.mir_summary.local_index(lvalue) == Some(self.query) {
159+
(self.callback)(lvalue, context, location)
160+
}
161+
self.super_lvalue(lvalue, context, location)
162+
}
163+
}
164+
165+
/// A small structure that enables various metadata of the MIR to be queried
166+
/// without a reference to the MIR itself.
167+
#[derive(Clone, Copy)]
168+
struct MirSummary {
169+
arg_count: usize,
170+
var_count: usize,
171+
temp_count: usize,
172+
}
173+
174+
impl MirSummary {
175+
fn new(mir: &Mir) -> MirSummary {
176+
MirSummary {
177+
arg_count: mir.arg_decls.len(),
178+
var_count: mir.var_decls.len(),
179+
temp_count: mir.temp_decls.len(),
180+
}
181+
}
182+
183+
fn local_index<'tcx>(&self, lvalue: &Lvalue<'tcx>) -> Option<Local> {
184+
match *lvalue {
185+
Lvalue::Arg(arg) => Some(Local::new(arg.index())),
186+
Lvalue::Var(var) => Some(Local::new(var.index() + self.arg_count)),
187+
Lvalue::Temp(temp) => {
188+
Some(Local::new(temp.index() + self.arg_count + self.var_count))
189+
}
190+
Lvalue::ReturnPointer => {
191+
Some(Local::new(self.arg_count + self.var_count + self.temp_count))
192+
}
193+
_ => None,
194+
}
195+
}
196+
}
197+

‎src/librustc_mir/lib.rs‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,8 +46,10 @@ extern crate rustc_const_eval;
4646
pub mod diagnostics;
4747

4848
pub mod build;
49+
pub mod def_use;
4950
pub mod graphviz;
5051
mod hair;
5152
pub mod mir_map;
5253
pub mod pretty;
5354
pub mod transform;
55+
Lines changed: 180 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,180 @@
1+
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
//! Trivial copy propagation pass.
12+
//!
13+
//! This uses def-use analysis to remove values that have exactly one def and one use, which must
14+
//! be an assignment.
15+
//!
16+
//! To give an example, we look for patterns that look like:
17+
//!
18+
//! DEST = SRC
19+
//! ...
20+
//! USE(DEST)
21+
//!
22+
//! where `DEST` and `SRC` are both locals of some form. We replace that with:
23+
//!
24+
//! NOP
25+
//! ...
26+
//! USE(SRC)
27+
//!
28+
//! The assignment `DEST = SRC` must be (a) the only mutation of `DEST` and (b) the only
29+
//! (non-mutating) use of `SRC`. These restrictions are conservative and may be relaxed in the
30+
//! future.
31+
32+
use def_use::DefUseAnalysis;
33+
use rustc::mir::repr::{Local, Lvalue, Mir, Operand, Rvalue, StatementKind};
34+
use rustc::mir::transform::{MirPass, MirSource, Pass};
35+
use rustc::ty::TyCtxt;
36+
use rustc_data_structures::indexed_vec::Idx;
37+
38+
pub struct CopyPropagation;
39+
40+
impl Pass for CopyPropagation {}
41+
42+
impl<'tcx> MirPass<'tcx> for CopyPropagation {
43+
fn run_pass<'a>(&mut self, _: TyCtxt<'a, 'tcx, 'tcx>, _: MirSource, mir: &mut Mir<'tcx>) {
44+
loop {
45+
let mut def_use_analysis = DefUseAnalysis::new(mir);
46+
def_use_analysis.analyze(mir);
47+
48+
let mut changed = false;
49+
for dest_local_index in 0..mir.count_locals() {
50+
let dest_local = Local::new(dest_local_index);
51+
debug!("Considering destination local: {}", mir.format_local(dest_local));
52+
53+
let src_local;
54+
let location;
55+
{
56+
// The destination must have exactly one def.
57+
let dest_use_info = def_use_analysis.local_info(dest_local);
58+
let dest_def_count = dest_use_info.def_count_not_including_drop();
59+
if dest_def_count == 0 {
60+
debug!(" Can't copy-propagate local: dest {} undefined",
61+
mir.format_local(dest_local));
62+
continue
63+
}
64+
if dest_def_count > 1 {
65+
debug!(" Can't copy-propagate local: dest {} defined {} times",
66+
mir.format_local(dest_local),
67+
dest_use_info.def_count());
68+
continue
69+
}
70+
if dest_use_info.use_count() == 0 {
71+
debug!(" Can't copy-propagate local: dest {} unused",
72+
mir.format_local(dest_local));
73+
continue
74+
}
75+
let dest_lvalue_def = dest_use_info.defs_and_uses.iter().filter(|lvalue_def| {
76+
lvalue_def.context.is_mutating_use() && !lvalue_def.context.is_drop()
77+
}).next().unwrap();
78+
location = dest_lvalue_def.location;
79+
80+
let basic_block = &mir[location.block];
81+
let statement_index = location.statement_index;
82+
let statement = match basic_block.statements.get(statement_index) {
83+
Some(statement) => statement,
84+
None => {
85+
debug!(" Can't copy-propagate local: used in terminator");
86+
continue
87+
}
88+
};
89+
90+
// That use of the source must be an assignment.
91+
let src_lvalue = match statement.kind {
92+
StatementKind::Assign(
93+
ref dest_lvalue,
94+
Rvalue::Use(Operand::Consume(ref src_lvalue)))
95+
if Some(dest_local) == mir.local_index(dest_lvalue) => {
96+
src_lvalue
97+
}
98+
_ => {
99+
debug!(" Can't copy-propagate local: source use is not an \
100+
assignment");
101+
continue
102+
}
103+
};
104+
src_local = match mir.local_index(src_lvalue) {
105+
Some(src_local) => src_local,
106+
None => {
107+
debug!(" Can't copy-propagate local: source is not a local");
108+
continue
109+
}
110+
};
111+
112+
// There must be exactly one use of the source used in a statement (not in a
113+
// terminator).
114+
let src_use_info = def_use_analysis.local_info(src_local);
115+
let src_use_count = src_use_info.use_count();
116+
if src_use_count == 0 {
117+
debug!(" Can't copy-propagate local: no uses");
118+
continue
119+
}
120+
if src_use_count != 1 {
121+
debug!(" Can't copy-propagate local: {} uses", src_use_info.use_count());
122+
continue
123+
}
124+
125+
// Verify that the source doesn't change in between. This is done
126+
// conservatively for now, by ensuring that the source has exactly one
127+
// mutation. The goal is to prevent things like:
128+
//
129+
// DEST = SRC;
130+
// SRC = X;
131+
// USE(DEST);
132+
//
133+
// From being misoptimized into:
134+
//
135+
// SRC = X;
136+
// USE(SRC);
137+
let src_def_count = src_use_info.def_count_not_including_drop();
138+
if src_def_count != 1 {
139+
debug!(" Can't copy-propagate local: {} defs of src",
140+
src_use_info.def_count_not_including_drop());
141+
continue
142+
}
143+
}
144+
145+
// If all checks passed, then we can eliminate the destination and the assignment.
146+
//
147+
// First, remove all markers.
148+
//
149+
// FIXME(pcwalton): Don't do this. Merge live ranges instead.
150+
debug!(" Replacing all uses of {}", mir.format_local(dest_local));
151+
for lvalue_use in &def_use_analysis.local_info(dest_local).defs_and_uses {
152+
if lvalue_use.context.is_storage_marker() {
153+
mir.make_statement_nop(lvalue_use.location)
154+
}
155+
}
156+
for lvalue_use in &def_use_analysis.local_info(src_local).defs_and_uses {
157+
if lvalue_use.context.is_storage_marker() {
158+
mir.make_statement_nop(lvalue_use.location)
159+
}
160+
}
161+
162+
// Now replace all uses of the destination local with the source local.
163+
let src_lvalue = Lvalue::from_local(mir, src_local);
164+
def_use_analysis.replace_all_defs_and_uses_with(dest_local, mir, src_lvalue);
165+
166+
// Finally, zap the now-useless assignment instruction.
167+
mir.make_statement_nop(location);
168+
169+
changed = true;
170+
// FIXME(pcwalton): Update the use-def chains to delete the instructions instead of
171+
// regenerating the chains.
172+
break
173+
}
174+
if !changed {
175+
break
176+
}
177+
}
178+
}
179+
}
180+

‎src/librustc_mir/transform/mod.rs‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,4 +19,4 @@ pub mod qualify_consts;
1919
pub mod dump_mir;
2020
pub mod deaggregator;
2121
pub mod instcombine;
22-
22+
pub mod copy_prop;

‎src/librustc_mir/transform/promote_consts.rs‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -328,7 +328,7 @@ impl<'a, 'tcx> Promoter<'a, 'tcx> {
328328
impl<'a, 'tcx> MutVisitor<'tcx> for Promoter<'a, 'tcx> {
329329
fn visit_lvalue(&mut self,
330330
lvalue: &mut Lvalue<'tcx>,
331-
context: LvalueContext,
331+
context: LvalueContext<'tcx>,
332332
location: Location) {
333333
if let Lvalue::Temp(ref mut temp) = *lvalue {
334334
*temp = self.promote_temp(*temp);

‎src/librustc_mir/transform/qualify_consts.rs‎

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -475,7 +475,10 @@ impl<'a, 'tcx> Qualifier<'a, 'tcx, 'tcx> {
475475
/// For functions (constant or not), it also records
476476
/// candidates for promotion in promotion_candidates.
477477
impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> {
478-
fn visit_lvalue(&mut self, lvalue: &Lvalue<'tcx>, context: LvalueContext, location: Location) {
478+
fn visit_lvalue(&mut self,
479+
lvalue: &Lvalue<'tcx>,
480+
context: LvalueContext<'tcx>,
481+
location: Location) {
479482
match *lvalue {
480483
Lvalue::Arg(_) => {
481484
self.add(Qualif::FN_ARGUMENT);

‎src/librustc_trans/collector.rs‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -523,7 +523,7 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirNeighborCollector<'a, 'tcx> {
523523

524524
fn visit_lvalue(&mut self,
525525
lvalue: &mir::Lvalue<'tcx>,
526-
context: mir_visit::LvalueContext,
526+
context: mir_visit::LvalueContext<'tcx>,
527527
location: Location) {
528528
debug!("visiting lvalue {:?}", *lvalue);
529529

‎src/librustc_trans/mir/analyze.rs‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -147,7 +147,7 @@ impl<'mir, 'bcx, 'tcx> Visitor<'tcx> for LocalAnalyzer<'mir, 'bcx, 'tcx> {
147147

148148
fn visit_lvalue(&mut self,
149149
lvalue: &mir::Lvalue<'tcx>,
150-
context: LvalueContext,
150+
context: LvalueContext<'tcx>,
151151
location: Location) {
152152
debug!("visit_lvalue(lvalue={:?}, context={:?})", lvalue, context);
153153

@@ -180,7 +180,7 @@ impl<'mir, 'bcx, 'tcx> Visitor<'tcx> for LocalAnalyzer<'mir, 'bcx, 'tcx> {
180180
LvalueContext::Store |
181181
LvalueContext::Inspect |
182182
LvalueContext::Borrow { .. } |
183-
LvalueContext::Projection => {
183+
LvalueContext::Projection(..) => {
184184
self.mark_as_lvalue(index);
185185
}
186186

‎src/test/codegen/refs.rs‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,9 +23,9 @@ fn helper(_: usize) {
2323
pub fn ref_dst(s: &[u8]) {
2424
// We used to generate an extra alloca and memcpy to ref the dst, so check that we copy
2525
// directly to the alloca for "x"
26-
// CHECK: [[X0:%[0-9]+]] = getelementptr {{.*}} { i8*, [[USIZE]] }* %x, i32 0, i32 0
26+
// CHECK: [[X0:%[0-9]+]] = getelementptr {{.*}} { i8*, [[USIZE]] }* %s, i32 0, i32 0
2727
// CHECK: store i8* %0, i8** [[X0]]
28-
// CHECK: [[X1:%[0-9]+]] = getelementptr {{.*}} { i8*, [[USIZE]] }* %x, i32 0, i32 1
28+
// CHECK: [[X1:%[0-9]+]] = getelementptr {{.*}} { i8*, [[USIZE]] }* %s, i32 0, i32 1
2929
// CHECK: store [[USIZE]] %1, [[USIZE]]* [[X1]]
3030

3131
let x = &*s;

‎src/test/mir-opt/storage_ranges.rs‎

Lines changed: 19 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -21,27 +21,27 @@ fn main() {
2121
// END RUST SOURCE
2222
// START rustc.node4.PreTrans.after.mir
2323
// bb0: {
24-
// StorageLive(var0); // scope 0 at storage_ranges.rs:12:9: 12:10
25-
// var0 = const 0i32; // scope 0 at storage_ranges.rs:12:13: 12:14
26-
// StorageLive(var1); // scope 1 at storage_ranges.rs:14:13: 14:14
27-
// StorageLive(tmp1); // scope 1 at storage_ranges.rs:14:18: 14:25
28-
// StorageLive(tmp2); // scope 1 at storage_ranges.rs:14:23: 14:24
29-
// tmp2 = var0; // scope 1 at storage_ranges.rs:14:23: 14:24
30-
// tmp1 = std::option::Option<i32>::Some(tmp2,); // scope 1 at storage_ranges.rs:14:18: 14:25
31-
// var1 = &tmp1; // scope 1 at storage_ranges.rs:14:17: 14:25
32-
// StorageDead(tmp2); // scope 1 at storage_ranges.rs:14:23: 14:24
33-
// tmp0 = (); // scope 2 at storage_ranges.rs:13:5: 15:6
34-
// StorageDead(tmp1); // scope 1 at storage_ranges.rs:14:18: 14:25
35-
// StorageDead(var1); // scope 1 at storage_ranges.rs:14:13: 14:14
36-
// StorageLive(var2); // scope 1 at storage_ranges.rs:16:9: 16:10
37-
// var2 = const 1i32; // scope 1 at storage_ranges.rs:16:13: 16:14
38-
// return = (); // scope 3 at storage_ranges.rs:11:11: 17:2
39-
// StorageDead(var2); // scope 1 at storage_ranges.rs:16:9: 16:10
40-
// StorageDead(var0); // scope 0 at storage_ranges.rs:12:9: 12:10
41-
// goto -> bb1; // scope 0 at storage_ranges.rs:11:1: 17:2
24+
// nop; // scope 0 at storage_ranges.rs:14:9: 14:10
25+
// var0 = const 0i32; // scope 0 at storage_ranges.rs:14:13: 14:14
26+
// StorageLive(var1); // scope 1 at storage_ranges.rs:16:13: 16:14
27+
// StorageLive(tmp1); // scope 1 at storage_ranges.rs:16:18: 16:25
28+
// nop; // scope 1 at storage_ranges.rs:16:23: 16:24
29+
// nop; // scope 1 at storage_ranges.rs:16:23: 16:24
30+
// tmp1 = std::option::Option<i32>::Some(var0,); // scope 1 at storage_ranges.rs:16:18: 16:25
31+
// var1 = &tmp1; // scope 1 at storage_ranges.rs:16:17: 16:25
32+
// nop; // scope 1 at storage_ranges.rs:16:23: 16:24
33+
// tmp0 = (); // scope 2 at storage_ranges.rs:15:5: 17:6
34+
// StorageDead(tmp1); // scope 1 at storage_ranges.rs:16:18: 16:25
35+
// StorageDead(var1); // scope 1 at storage_ranges.rs:16:13: 16:14
36+
// StorageLive(var2); // scope 1 at storage_ranges.rs:18:9: 18:10
37+
// var2 = const 1i32; // scope 1 at storage_ranges.rs:18:13: 18:14
38+
// return = (); // scope 3 at storage_ranges.rs:13:11: 19:2
39+
// StorageDead(var2); // scope 1 at storage_ranges.rs:18:9: 18:10
40+
// nop; // scope 0 at storage_ranges.rs:14:9: 14:10
41+
// goto -> bb1; // scope 0 at storage_ranges.rs:13:1: 19:2
4242
// }
4343
//
4444
// bb1: {
45-
// return; // scope 0 at storage_ranges.rs:11:1: 17:2
45+
// return; // scope 0 at storage_ranges.rs:13:1: 19:2
4646
// }
4747
// END rustc.node4.PreTrans.after.mir

0 commit comments

Comments
 (0)
Please sign in to comment.