1use crate::analysis::dataflow::types::DataflowGraph;
9use crate::compat::FxHashSet;
10use crate::compat::Spanned;
11use rustc_middle::mir::{
12 Local, Operand, Place, ProjectionElem, Rvalue, Terminator, TerminatorKind,
13};
14
15#[derive(Clone, Debug, Default)]
17pub struct DefUse {
18 pub defs: RelevantPlaces,
20 pub uses: RelevantPlaces,
22}
23
24impl DefUse {
25 pub fn new() -> Self {
27 Self::default()
28 }
29}
30
31#[derive(Clone, Debug, Eq, PartialEq, Hash)]
33pub enum PlaceBaseKey {
34 Return,
36 Local(usize),
38 Arg(usize),
40}
41
42#[derive(Clone, Debug, Eq, PartialEq, Hash)]
44pub struct PlaceKey {
45 pub base: PlaceBaseKey,
47 pub fields: Vec<usize>,
49}
50
51impl PlaceKey {
52 pub fn from_mir_place(place: &Place<'_>) -> Self {
54 Self {
55 base: if place.local.as_usize() == 0 {
56 PlaceBaseKey::Return
57 } else {
58 PlaceBaseKey::Local(place.local.as_usize())
59 },
60 fields: place
61 .projection
62 .iter()
63 .filter_map(|projection| match projection {
64 ProjectionElem::Field(index, _) => Some(index.as_usize()),
65 _ => None,
66 })
67 .collect(),
68 }
69 }
70
71 pub fn local(&self) -> Option<Local> {
73 match self.base {
74 PlaceBaseKey::Return => Some(Local::from_usize(0)),
75 PlaceBaseKey::Local(local) => Some(Local::from_usize(local)),
76 PlaceBaseKey::Arg(_) => None,
77 }
78 }
79
80 pub fn from_origin(local: usize, fields: Vec<usize>) -> Self {
82 Self {
83 base: PlaceBaseKey::Local(local),
84 fields,
85 }
86 }
87
88 pub fn overlaps(&self, other: &PlaceKey) -> bool {
93 self.base == other.base && {
94 let min_len = self.fields.len().min(other.fields.len());
95 self.fields[..min_len] == other.fields[..min_len]
96 }
97 }
98}
99
100#[derive(Clone, Debug, Default)]
102pub struct RelevantPlaces {
103 pub places: FxHashSet<PlaceKey>,
104 pub locals: FxHashSet<Local>,
105 pub saturated: FxHashSet<PlaceKey>,
106 pub just_added: FxHashSet<PlaceKey>,
107 pub need_len: FxHashSet<PlaceKey>,
111}
112
113impl RelevantPlaces {
114 pub fn new() -> Self {
116 Self::default()
117 }
118
119 pub fn is_empty(&self) -> bool {
121 self.places.is_empty() && self.locals.is_empty()
122 }
123
124 pub fn insert_local(&mut self, local: Local) {
126 let pk = PlaceKey {
127 base: if local.as_usize() == 0 {
128 PlaceBaseKey::Return
129 } else {
130 PlaceBaseKey::Local(local.as_usize())
131 },
132 fields: Vec::new(),
133 };
134 if self.places.insert(pk.clone()) {
135 self.just_added.insert(pk);
136 }
137 self.locals.insert(local);
138 }
139
140 pub fn insert_mir_place(&mut self, place: &Place<'_>) {
142 self.insert_place_key(PlaceKey::from_mir_place(place));
143 }
144
145 pub fn insert_place_key(&mut self, place: PlaceKey) {
147 if let Some(local) = place.local() {
148 self.locals.insert(local);
149 }
150 if self.places.insert(place.clone()) {
151 self.just_added.insert(place);
152 }
153 }
154
155 pub fn extend(&mut self, other: RelevantPlaces) {
157 for place in other.places {
158 if self.places.insert(place.clone()) {
159 self.just_added.insert(place);
160 }
161 }
162 for local in other.locals {
163 self.locals.insert(local);
164 }
165 for place in other.need_len {
166 self.need_len.insert(place);
167 }
168 }
169
170 pub fn remove_place_keys(&mut self, places: &[PlaceKey]) {
172 for place in places {
173 self.places.remove(place);
174 }
175 self.rebuild_locals();
176 }
177
178 pub fn intersects(&self, other: &RelevantPlaces) -> bool {
180 self.places
181 .iter()
182 .any(|sp| other.places.iter().any(|op| sp.overlaps(op)))
183 }
184
185 pub fn remove_all(&mut self, other: &RelevantPlaces) {
188 for local in &other.locals {
189 self.saturated.insert(PlaceKey {
190 base: PlaceBaseKey::Local(local.as_usize()),
191 fields: vec![],
192 });
193 self.locals.remove(local);
194 self.places.retain(|place| place.local() != Some(*local));
195 }
196 for place in &other.places {
197 self.saturated.insert(place.clone());
198 self.places.remove(place);
199 if let Some(local) = place.local() {
200 self.locals.remove(&local);
201 }
202 }
203 }
204
205 fn rebuild_locals(&mut self) {
206 self.locals = self.places.iter().filter_map(PlaceKey::local).collect();
207 }
208}
209
210pub fn terminator_use_def<'tcx>(terminator: &Terminator<'tcx>) -> DefUse {
214 let mut use_def = DefUse::new();
215 match &terminator.kind {
216 TerminatorKind::Call {
217 func,
218 args,
219 destination,
220 ..
221 } => {
222 use_def.defs.insert_mir_place(destination);
223 use_def.uses.extend(operand_uses(func));
224 for arg in args {
225 use_def.uses.extend(operand_uses(&arg.node));
226 }
227 }
228 TerminatorKind::SwitchInt { discr, .. } => {
229 use_def.uses.extend(operand_uses(discr));
230 }
231 TerminatorKind::Assert { cond, .. } => {
232 use_def.uses.extend(operand_uses(cond));
233 }
234 TerminatorKind::Drop { place, .. } => {
235 use_def.uses.extend(place_uses(place));
236 }
237 _ => {}
238 }
239 use_def
240}
241
242pub fn call_args_uses_at<'tcx>(
244 args: &[Spanned<Operand<'tcx>>],
245 indices: &[usize],
246) -> RelevantPlaces {
247 let mut uses = RelevantPlaces::new();
248 for index in indices {
249 if let Some(arg) = args.get(*index) {
250 uses.extend(operand_uses(&arg.node));
251 }
252 }
253 uses
254}
255
256pub fn operand_uses<'tcx>(operand: &Operand<'tcx>) -> RelevantPlaces {
258 let mut uses = RelevantPlaces::new();
259 match operand {
260 Operand::Copy(place) | Operand::Move(place) => {
261 uses.extend(place_uses(place));
262 }
263 Operand::Constant(_) => {}
264 #[cfg(rapx_ge_99)]
265 Operand::RuntimeChecks(_) => {}
266 }
267 uses
268}
269
270fn place_uses(place: &Place<'_>) -> RelevantPlaces {
271 let mut uses = RelevantPlaces::new();
272 uses.insert_mir_place(place);
273 uses.extend(place_projection_uses(place));
274 uses
275}
276
277fn place_projection_uses(place: &Place<'_>) -> RelevantPlaces {
278 let mut uses = RelevantPlaces::new();
279 for projection in place.projection {
280 if let ProjectionElem::Index(local) = projection {
281 uses.insert_local(local);
282 }
283 }
284 uses
285}
286
287pub fn rvalue_operands<'tcx>(rvalue: &'tcx Rvalue<'tcx>) -> Vec<&'tcx Operand<'tcx>> {
289 let mut operands = Vec::new();
290 match rvalue {
291 Rvalue::Use(op, ..)
292 | Rvalue::Repeat(op, _)
293 | Rvalue::Cast(_, op, _)
294 | Rvalue::UnaryOp(_, op) => {
295 operands.push(op);
296 }
297 Rvalue::BinaryOp(_, pair) => {
298 let (lhs, rhs) = &**pair;
299 operands.push(lhs);
300 operands.push(rhs);
301 }
302 Rvalue::Ref(_, _, _) | Rvalue::RawPtr(_, _) => {}
303 #[cfg(not(rapx_ge_99))]
304 Rvalue::ShallowInitBox(_, _) => {}
305 Rvalue::Aggregate(_, aggregate_operands) => {
306 operands.extend(aggregate_operands.iter());
307 }
308 Rvalue::Discriminant(_) | Rvalue::CopyForDeref(_) | Rvalue::ThreadLocalRef(_) | _ => {}
309 }
310 operands
311}
312
313pub fn trace_place_origin(flow: &DataflowGraph, key: &PlaceKey) -> PlaceKey {
318 let Some(local) = key.local() else {
319 return key.clone();
320 };
321 PlaceKey {
322 base: PlaceBaseKey::Local(flow.trace_origin(local).as_usize()),
323 fields: key.fields.clone(),
324 }
325}