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