Skip to content

Commit 534968e

Browse files
committedFeb 1, 2018
rustc_mir: add a local path access analysis.
1 parent b1ee6e8 commit 534968e

File tree

3 files changed

+196
-9
lines changed

3 files changed

+196
-9
lines changed
 

‎src/librustc_mir/analysis/dataflow/mod.rs

+9-9
Original file line numberDiff line numberDiff line change
@@ -120,14 +120,14 @@ pub struct MoveDataParamEnv<'gcx, 'tcx> {
120120
pub(crate) param_env: ty::ParamEnv<'gcx>,
121121
}
122122

123-
pub(crate) fn do_dataflow<'a, 'gcx, 'tcx, BD, P>(tcx: TyCtxt<'a, 'gcx, 'tcx>,
124-
mir: &'a Mir<'tcx>,
125-
node_id: ast::NodeId,
126-
attributes: &[ast::Attribute],
127-
dead_unwinds: &IdxSet<BasicBlock>,
128-
bd: BD,
129-
p: P)
130-
-> DataflowResults<BD>
123+
pub(crate) fn do_dataflow<BD, P>(tcx: TyCtxt,
124+
mir: &Mir,
125+
node_id: ast::NodeId,
126+
attributes: &[ast::Attribute],
127+
dead_unwinds: &IdxSet<BasicBlock>,
128+
bd: BD,
129+
p: P)
130+
-> DataflowResults<BD>
131131
where BD: BitDenotation + InitialFlow,
132132
P: Fn(&BD, BD::Idx) -> DebugFormatted
133133
{
@@ -138,7 +138,7 @@ pub(crate) fn do_dataflow<'a, 'gcx, 'tcx, BD, P>(tcx: TyCtxt<'a, 'gcx, 'tcx>,
138138
impl<'a, 'gcx: 'tcx, 'tcx: 'a, BD> DataflowAnalysis<'a, 'tcx, BD> where BD: BitDenotation
139139
{
140140
pub(crate) fn run<P>(self,
141-
tcx: TyCtxt<'a, 'gcx, 'tcx>,
141+
tcx: TyCtxt,
142142
node_id: ast::NodeId,
143143
attributes: &[ast::Attribute],
144144
p: P) -> DataflowResults<BD>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,186 @@
1+
// Copyright 2018 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+
use rustc_data_structures::indexed_set::IdxSetBuf;
12+
use rustc_data_structures::indexed_vec::Idx;
13+
use rustc::mir::*;
14+
use rustc::mir::visit::{PlaceContext, Visitor};
15+
use rustc::ty;
16+
use std::iter;
17+
use syntax::ast;
18+
use analysis::dataflow::{do_dataflow, BitDenotation, BlockSets, DebugFormatted};
19+
use analysis::eventflow::{Backward, Events, EventFlowResults, Forward, PastAndFuture};
20+
use analysis::local_paths::{LocalPaths, PathId};
21+
use analysis::local_paths::borrows::MaybeBorrowed;
22+
use analysis::locations::FlatLocations;
23+
24+
pub struct Accesses<'a> {
25+
pub results: PastAndFuture<EventFlowResults<'a, Forward, PathId>,
26+
EventFlowResults<'a, Backward, PathId>>
27+
}
28+
29+
impl<'a> Accesses<'a> {
30+
pub fn collect(mir: &Mir,
31+
local_paths: &LocalPaths,
32+
flat_locations: &'a FlatLocations)
33+
-> Self {
34+
let borrows = ty::tls::with(|tcx| {
35+
do_dataflow(tcx, mir, ast::DUMMY_NODE_ID, &[],
36+
&IdxSetBuf::new_empty(mir.basic_blocks().len()),
37+
MaybeBorrowed::new(mir, local_paths),
38+
|_, path| DebugFormatted::new(&path))
39+
});
40+
41+
let mut collector = AccessPathCollector {
42+
local_paths,
43+
location: Location {
44+
block: START_BLOCK,
45+
statement_index: !0
46+
},
47+
accesses: Events::new(mir, flat_locations, local_paths.total_count()),
48+
maybe_borrowed: IdxSetBuf::new_empty(0)
49+
};
50+
51+
// FIXME(eddyb) introduce a seeker for this (like in eventflow),
52+
// maybe reusing `dataflow::at_location(::FlowAtLocation)`.
53+
// That would remove the need for asserting the location.
54+
55+
for (block, data) in mir.basic_blocks().iter_enumerated() {
56+
collector.location.block = block;
57+
collector.maybe_borrowed = borrows.sets().on_entry_set_for(block.index()).to_owned();
58+
59+
let on_entry = &mut collector.maybe_borrowed.clone();
60+
let kill_set = &mut collector.maybe_borrowed.clone();
61+
for (i, statement) in data.statements.iter().enumerate() {
62+
collector.location.statement_index = i;
63+
borrows.operator().before_statement_effect(&mut BlockSets {
64+
on_entry,
65+
kill_set,
66+
gen_set: &mut collector.maybe_borrowed,
67+
}, collector.location);
68+
// FIXME(eddyb) get rid of temporary with NLL/2phi.
69+
let location = collector.location;
70+
collector.visit_statement(block, statement, location);
71+
borrows.operator().statement_effect(&mut BlockSets {
72+
on_entry,
73+
kill_set,
74+
gen_set: &mut collector.maybe_borrowed,
75+
}, collector.location);
76+
}
77+
78+
if let Some(ref terminator) = data.terminator {
79+
collector.location.statement_index = data.statements.len();
80+
borrows.operator().before_terminator_effect(&mut BlockSets {
81+
on_entry,
82+
kill_set,
83+
gen_set: &mut collector.maybe_borrowed,
84+
}, collector.location);
85+
// FIXME(eddyb) get rid of temporary with NLL/2phi.
86+
let location = collector.location;
87+
collector.visit_terminator(block, terminator, location);
88+
}
89+
}
90+
let results = collector.accesses.flow(mir.args_iter().flat_map(|arg| {
91+
// All arguments have been accessed prior to the call to this function.
92+
// FIXME(eddyb) use ranges here for performance.
93+
let arg = local_paths.locals[arg];
94+
iter::once(arg).chain(local_paths.descendants(arg))
95+
}));
96+
Accesses { results }
97+
}
98+
}
99+
100+
struct AccessPathCollector<'a, 'b, 'tcx: 'a> {
101+
local_paths: &'a LocalPaths<'tcx>,
102+
accesses: Events<'a, 'b, 'tcx, PathId>,
103+
location: Location,
104+
maybe_borrowed: IdxSetBuf<PathId>
105+
}
106+
107+
impl<'a, 'b, 'tcx> AccessPathCollector<'a, 'b, 'tcx> {
108+
fn access_anything_borrowed(&mut self, location: Location) {
109+
// FIXME(eddyb) OR `maybe_borrowed` into the accesses for performance.
110+
for path in self.maybe_borrowed.iter() {
111+
self.accesses.insert_at(path, location);
112+
}
113+
}
114+
}
115+
116+
impl<'a, 'b, 'tcx> Visitor<'tcx> for AccessPathCollector<'a, 'b, 'tcx> {
117+
fn visit_place(&mut self,
118+
place: &Place<'tcx>,
119+
context: PlaceContext<'tcx>,
120+
location: Location) {
121+
assert_eq!(self.location, location);
122+
123+
if context.is_use() {
124+
match self.local_paths.place_path(place) {
125+
Ok(path) | Err(Some(path)) => {
126+
self.accesses.insert_at(path, location);
127+
}
128+
Err(None) => {}
129+
}
130+
}
131+
132+
// Traverse the projections in `place`.
133+
let context = if context.is_mutating_use() {
134+
PlaceContext::Projection(Mutability::Mut)
135+
} else {
136+
PlaceContext::Projection(Mutability::Not)
137+
};
138+
let mut place = place;
139+
while let Place::Projection(ref proj) = *place {
140+
self.visit_projection_elem(&proj.elem, context, location);
141+
place = &proj.base;
142+
}
143+
}
144+
145+
// Handle the locals used in indexing projections.
146+
fn visit_local(&mut self,
147+
&local: &Local,
148+
context: PlaceContext,
149+
location: Location) {
150+
assert_eq!(self.location, location);
151+
152+
if context.is_use() {
153+
self.accesses.insert_at(self.local_paths.locals[local], location);
154+
}
155+
}
156+
157+
fn visit_projection_elem(&mut self,
158+
elem: &PlaceElem<'tcx>,
159+
context: PlaceContext<'tcx>,
160+
location: Location) {
161+
assert_eq!(self.location, location);
162+
163+
if let ProjectionElem::Deref = *elem {
164+
self.access_anything_borrowed(location);
165+
}
166+
self.super_projection_elem(elem, context, location);
167+
}
168+
169+
fn visit_terminator_kind(&mut self,
170+
block: BasicBlock,
171+
kind: &TerminatorKind<'tcx>,
172+
location: Location) {
173+
assert_eq!(self.location, location);
174+
175+
match *kind {
176+
TerminatorKind::Call { .. } => {
177+
self.access_anything_borrowed(location);
178+
}
179+
TerminatorKind::Return => {
180+
self.visit_local(&RETURN_PLACE, PlaceContext::Move, location);
181+
}
182+
_ => {}
183+
}
184+
self.super_terminator_kind(block, kind, location);
185+
}
186+
}

‎src/librustc_mir/analysis/local_paths/mod.rs

+1
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ use rustc::ty::Ty;
1515
use std::iter::Step;
1616
use std::ops::Range;
1717

18+
pub mod accesses;
1819
pub mod borrows;
1920
pub mod collect;
2021

0 commit comments

Comments
 (0)
Please sign in to comment.