]> git.proxmox.com Git - rustc.git/blame - src/librustc_mir/util/def_use.rs
New upstream version 1.40.0+dfsg1
[rustc.git] / src / librustc_mir / util / def_use.rs
CommitLineData
9e0c209e
SL
1//! Def-use analysis.
2
e74abb32 3use rustc::mir::{Body, Local, Location, PlaceElem};
ff7c6d11 4use rustc::mir::visit::{PlaceContext, MutVisitor, Visitor};
e74abb32
XL
5use rustc::ty::TyCtxt;
6use rustc_index::vec::IndexVec;
9e0c209e
SL
7use std::mem;
8
48663c56
XL
9pub struct DefUseAnalysis {
10 info: IndexVec<Local, Info>,
9e0c209e
SL
11}
12
13#[derive(Clone)]
48663c56
XL
14pub struct Info {
15 pub defs_and_uses: Vec<Use>,
9e0c209e
SL
16}
17
18#[derive(Clone)]
48663c56
XL
19pub struct Use {
20 pub context: PlaceContext,
9e0c209e
SL
21 pub location: Location,
22}
23
48663c56 24impl DefUseAnalysis {
dc9dc135 25 pub fn new(body: &Body<'_>) -> DefUseAnalysis {
9e0c209e 26 DefUseAnalysis {
dc9dc135 27 info: IndexVec::from_elem_n(Info::new(), body.local_decls.len()),
9e0c209e
SL
28 }
29 }
30
dc9dc135 31 pub fn analyze(&mut self, body: &Body<'_>) {
abe05a73
XL
32 self.clear();
33
9e0c209e 34 let mut finder = DefUseFinder {
416331ca 35 info: mem::take(&mut self.info),
9e0c209e 36 };
dc9dc135 37 finder.visit_body(body);
9e0c209e
SL
38 self.info = finder.info
39 }
40
abe05a73
XL
41 fn clear(&mut self) {
42 for info in &mut self.info {
43 info.clear();
44 }
45 }
46
48663c56 47 pub fn local_info(&self, local: Local) -> &Info {
9e0c209e
SL
48 &self.info[local]
49 }
50
e74abb32
XL
51 fn mutate_defs_and_uses(
52 &self,
53 local: Local,
54 body: &mut Body<'tcx>,
55 new_local: Local,
56 tcx: TyCtxt<'tcx>,
57 ) {
ff7c6d11 58 for place_use in &self.info[local].defs_and_uses {
e74abb32
XL
59 MutateUseVisitor::new(local, new_local, body, tcx)
60 .visit_location(body, place_use.location)
9e0c209e
SL
61 }
62 }
63
9fa01778 64 // FIXME(pcwalton): this should update the def-use chains.
9e0c209e
SL
65 pub fn replace_all_defs_and_uses_with(&self,
66 local: Local,
e74abb32
XL
67 body: &mut Body<'tcx>,
68 new_local: Local,
69 tcx: TyCtxt<'tcx>) {
70 self.mutate_defs_and_uses(local, body, new_local, tcx)
9e0c209e
SL
71 }
72}
73
48663c56
XL
74struct DefUseFinder {
75 info: IndexVec<Local, Info>,
9e0c209e
SL
76}
77
48663c56 78impl Visitor<'_> for DefUseFinder {
ea8adc8c
XL
79 fn visit_local(&mut self,
80 &local: &Local,
48663c56 81 context: PlaceContext,
ea8adc8c
XL
82 location: Location) {
83 self.info[local].defs_and_uses.push(Use {
84 context,
85 location,
86 });
9e0c209e
SL
87 }
88}
89
48663c56
XL
90impl Info {
91 fn new() -> Info {
9e0c209e
SL
92 Info {
93 defs_and_uses: vec![],
94 }
95 }
96
abe05a73
XL
97 fn clear(&mut self) {
98 self.defs_and_uses.clear();
99 }
100
9e0c209e 101 pub fn def_count(&self) -> usize {
ff7c6d11 102 self.defs_and_uses.iter().filter(|place_use| place_use.context.is_mutating_use()).count()
9e0c209e
SL
103 }
104
105 pub fn def_count_not_including_drop(&self) -> usize {
abe05a73
XL
106 self.defs_not_including_drop().count()
107 }
108
109 pub fn defs_not_including_drop(
110 &self,
48663c56 111 ) -> impl Iterator<Item=&Use> {
ff7c6d11
XL
112 self.defs_and_uses.iter().filter(|place_use| {
113 place_use.context.is_mutating_use() && !place_use.context.is_drop()
abe05a73 114 })
9e0c209e
SL
115 }
116
117 pub fn use_count(&self) -> usize {
ff7c6d11
XL
118 self.defs_and_uses.iter().filter(|place_use| {
119 place_use.context.is_nonmutating_use()
9e0c209e
SL
120 }).count()
121 }
122}
123
e74abb32 124struct MutateUseVisitor<'tcx> {
9e0c209e 125 query: Local,
e74abb32
XL
126 new_local: Local,
127 tcx: TyCtxt<'tcx>,
9e0c209e
SL
128}
129
e74abb32
XL
130impl MutateUseVisitor<'tcx> {
131 fn new(
132 query: Local,
133 new_local: Local,
134 _: &Body<'tcx>,
135 tcx: TyCtxt<'tcx>,
136 ) -> MutateUseVisitor<'tcx> {
137 MutateUseVisitor { query, new_local, tcx }
9e0c209e
SL
138 }
139}
140
e74abb32
XL
141impl MutVisitor<'tcx> for MutateUseVisitor<'tcx> {
142 fn tcx(&self) -> TyCtxt<'tcx> {
143 self.tcx
144 }
145
ea8adc8c
XL
146 fn visit_local(&mut self,
147 local: &mut Local,
e74abb32
XL
148 _context: PlaceContext,
149 _location: Location) {
ea8adc8c 150 if *local == self.query {
e74abb32
XL
151 *local = self.new_local;
152 }
153 }
154
155 fn process_projection_elem(
156 &mut self,
157 elem: &PlaceElem<'tcx>,
158 ) -> Option<PlaceElem<'tcx>> {
159 match elem {
160 PlaceElem::Index(local) if *local == self.query => {
161 Some(PlaceElem::Index(self.new_local))
162 }
163 _ => None,
9e0c209e
SL
164 }
165 }
166}