]> git.proxmox.com Git - rustc.git/blame - 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
CommitLineData
9e0c209e
SL
1//! Def-use analysis.
2
e74abb32 3use rustc_index::vec::IndexVec;
ba9703b0 4use rustc_middle::mir::visit::{MutVisitor, PlaceContext, Visitor};
f9f354fc 5use rustc_middle::mir::{Body, Local, Location, VarDebugInfo};
ba9703b0 6use rustc_middle::ty::TyCtxt;
9e0c209e
SL
7use std::mem;
8
48663c56
XL
9pub struct DefUseAnalysis {
10 info: IndexVec<Local, Info>,
9e0c209e
SL
11}
12
13#[derive(Clone)]
48663c56 14pub struct Info {
60c5eb7d 15 // FIXME(eddyb) use smallvec where possible.
48663c56 16 pub defs_and_uses: Vec<Use>,
60c5eb7d 17 var_debug_info_indices: Vec<usize>,
9e0c209e
SL
18}
19
20#[derive(Clone)]
48663c56
XL
21pub struct Use {
22 pub context: PlaceContext,
9e0c209e
SL
23 pub location: Location,
24}
25
48663c56 26impl DefUseAnalysis {
dc9dc135 27 pub fn new(body: &Body<'_>) -> DefUseAnalysis {
dfeec247 28 DefUseAnalysis { info: IndexVec::from_elem_n(Info::new(), body.local_decls.len()) }
9e0c209e
SL
29 }
30
f9f354fc 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),
60c5eb7d
XL
36 var_debug_info_index: 0,
37 in_var_debug_info: false,
9e0c209e 38 };
ba9703b0 39 finder.visit_body(&body);
9e0c209e
SL
40 self.info = finder.info
41 }
42
abe05a73
XL
43 fn clear(&mut self) {
44 for info in &mut self.info {
45 info.clear();
46 }
47 }
48
48663c56 49 pub fn local_info(&self, local: Local) -> &Info {
9e0c209e
SL
50 &self.info[local]
51 }
52
e74abb32
XL
53 fn mutate_defs_and_uses(
54 &self,
55 local: Local,
f9f354fc 56 body: &mut Body<'tcx>,
e74abb32
XL
57 new_local: Local,
58 tcx: TyCtxt<'tcx>,
59 ) {
60c5eb7d
XL
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]);
9e0c209e
SL
68 }
69 }
70
9fa01778 71 // FIXME(pcwalton): this should update the def-use chains.
dfeec247
XL
72 pub fn replace_all_defs_and_uses_with(
73 &self,
74 local: Local,
f9f354fc 75 body: &mut Body<'tcx>,
dfeec247
XL
76 new_local: Local,
77 tcx: TyCtxt<'tcx>,
78 ) {
e74abb32 79 self.mutate_defs_and_uses(local, body, new_local, tcx)
9e0c209e
SL
80 }
81}
82
48663c56
XL
83struct DefUseFinder {
84 info: IndexVec<Local, Info>,
60c5eb7d
XL
85 var_debug_info_index: usize,
86 in_var_debug_info: bool,
9e0c209e
SL
87}
88
48663c56 89impl Visitor<'_> for DefUseFinder {
dfeec247 90 fn visit_local(&mut self, &local: &Local, context: PlaceContext, location: Location) {
60c5eb7d
XL
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 {
dfeec247 95 info.defs_and_uses.push(Use { context, location });
60c5eb7d
XL
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;
9e0c209e
SL
104 }
105}
106
48663c56
XL
107impl Info {
108 fn new() -> Info {
dfeec247 109 Info { defs_and_uses: vec![], var_debug_info_indices: vec![] }
9e0c209e
SL
110 }
111
abe05a73
XL
112 fn clear(&mut self) {
113 self.defs_and_uses.clear();
60c5eb7d 114 self.var_debug_info_indices.clear();
abe05a73
XL
115 }
116
9e0c209e 117 pub fn def_count(&self) -> usize {
ff7c6d11 118 self.defs_and_uses.iter().filter(|place_use| place_use.context.is_mutating_use()).count()
9e0c209e
SL
119 }
120
121 pub fn def_count_not_including_drop(&self) -> usize {
abe05a73
XL
122 self.defs_not_including_drop().count()
123 }
124
dfeec247
XL
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())
9e0c209e
SL
129 }
130
131 pub fn use_count(&self) -> usize {
dfeec247 132 self.defs_and_uses.iter().filter(|place_use| place_use.context.is_nonmutating_use()).count()
9e0c209e
SL
133 }
134}
135
e74abb32 136struct MutateUseVisitor<'tcx> {
9e0c209e 137 query: Local,
e74abb32
XL
138 new_local: Local,
139 tcx: TyCtxt<'tcx>,
9e0c209e
SL
140}
141
e74abb32 142impl MutateUseVisitor<'tcx> {
dfeec247 143 fn new(query: Local, new_local: Local, tcx: TyCtxt<'tcx>) -> MutateUseVisitor<'tcx> {
e74abb32 144 MutateUseVisitor { query, new_local, tcx }
9e0c209e
SL
145 }
146}
147
e74abb32
XL
148impl MutVisitor<'tcx> for MutateUseVisitor<'tcx> {
149 fn tcx(&self) -> TyCtxt<'tcx> {
150 self.tcx
151 }
152
dfeec247 153 fn visit_local(&mut self, local: &mut Local, _context: PlaceContext, _location: Location) {
ea8adc8c 154 if *local == self.query {
e74abb32
XL
155 *local = self.new_local;
156 }
157 }
9e0c209e 158}