rapx/analysis/core/alias_analysis/default/
mop.rs1use super::{graph::*, *};
2use rustc_data_structures::fx::FxHashSet;
3use rustc_hir::def_id::DefId;
4use rustc_middle::{
5 mir::{
6 Operand::{Constant, Copy, Move},
7 TerminatorKind,
8 },
9 ty::TypingEnv,
10};
11
12use std::{
13 collections::{HashMap, HashSet},
14 env,
15};
16
17impl<'tcx> MopGraph<'tcx> {
18 pub fn split_check(
19 &mut self,
20 bb_index: usize,
21 fn_map: &mut MopAAResultMap,
22 recursion_set: &mut HashSet<DefId>,
23 ) {
24 let backup_values = self.values.clone(); let backup_constant = self.constant.clone();
27 let backup_alias_set = self.alias_set.clone();
28 self.check(bb_index, fn_map, recursion_set);
29 self.alias_set = backup_alias_set;
31 self.values = backup_values;
32 self.constant = backup_constant;
33 }
34 pub fn split_check_with_cond(
35 &mut self,
36 bb_index: usize,
37 path_discr_id: usize,
38 path_discr_val: usize,
39 fn_map: &mut MopAAResultMap,
40 recursion_set: &mut HashSet<DefId>,
41 ) {
42 let backup_values = self.values.clone(); let backup_constant = self.constant.clone();
45 let backup_alias_set = self.alias_set.clone();
46 self.constant.insert(path_discr_id, path_discr_val);
48 self.check(bb_index, fn_map, recursion_set);
49 self.alias_set = backup_alias_set;
51 self.values = backup_values;
52 self.constant = backup_constant;
53 }
54
55 pub fn check(
57 &mut self,
58 bb_index: usize,
59 fn_map: &mut MopAAResultMap,
60 recursion_set: &mut HashSet<DefId>,
61 ) {
62 self.visit_times += 1;
63 if self.visit_times > VISIT_LIMIT {
64 return;
65 }
66 let cur_block = self.blocks[self.scc_indices[bb_index]].clone();
67 self.alias_bb(self.scc_indices[bb_index]);
68 self.alias_bbcall(self.scc_indices[bb_index], fn_map, recursion_set);
69
70 if self.child_scc.get(&self.scc_indices[bb_index]).is_some() {
71 let init_index = self.scc_indices[bb_index];
72 let (init_block, cur_targets, scc_block_set) =
73 self.child_scc.get(&init_index).unwrap().clone();
74
75 for enum_index in cur_targets.all_targets() {
76 let backup_values = self.values.clone();
77 let backup_constant = self.constant.clone();
78
79 let mut block_node = if bb_index == init_index {
80 init_block.clone()
81 } else {
82 self.blocks[bb_index].clone()
83 };
84
85 if !block_node.switch_stmts.is_empty() {
86 let TerminatorKind::SwitchInt { discr: _, targets } =
87 block_node.switch_stmts[0].kind.clone()
88 else {
89 unreachable!();
90 };
91 if cur_targets == targets {
92 block_node.next = FxHashSet::default();
93 block_node.next.insert(enum_index.index());
94 }
95 }
96
97 let mut work_list = Vec::new();
98 let mut work_set = FxHashSet::<usize>::default();
99 work_list.push(bb_index);
100 work_set.insert(bb_index);
101 while !work_list.is_empty() {
102 let current_node = work_list.pop().unwrap();
103 block_node.scc_sub_blocks.push(current_node);
104 let real_node = if current_node != init_index {
105 self.blocks[current_node].clone()
106 } else {
107 init_block.clone()
108 };
109
110 if real_node.switch_stmts.is_empty() {
111 for next in &real_node.next {
112 block_node.next.insert(*next);
113 }
114 } else {
115 let TerminatorKind::SwitchInt {
116 discr: _,
117 ref targets,
118 } = real_node.switch_stmts[0].kind
119 else {
120 unreachable!();
121 };
122
123 if cur_targets == *targets {
124 block_node.next.insert(enum_index.index());
125 } else {
126 for next in &real_node.next {
127 block_node.next.insert(*next);
128 }
129 }
130 }
131
132 if real_node.switch_stmts.is_empty() {
133 for next in &real_node.next {
134 if scc_block_set.contains(next) && !work_set.contains(next) {
135 work_set.insert(*next);
136 work_list.push(*next);
137 }
138 }
139 } else {
140 let TerminatorKind::SwitchInt {
141 discr: _,
142 ref targets,
143 } = real_node.switch_stmts[0].kind
144 else {
145 unreachable!();
146 };
147
148 if cur_targets == *targets {
149 let next_index = enum_index.index();
150 if scc_block_set.contains(&next_index)
151 && !work_set.contains(&next_index)
152 {
153 work_set.insert(next_index);
154 work_list.push(next_index);
155 }
156 } else {
157 for next in &real_node.next {
158 if scc_block_set.contains(next) && !work_set.contains(next) {
159 work_set.insert(*next);
160 work_list.push(*next);
161 }
162 }
163 }
164 }
165 }
166
167 let mut to_remove = Vec::new();
169 for i in block_node.next.iter() {
170 if self.scc_indices[*i] == init_index {
171 to_remove.push(*i);
172 }
173 }
174 for i in to_remove {
175 block_node.next.remove(&i);
176 }
177
178 for i in block_node.scc_sub_blocks.clone() {
179 self.alias_bb(i);
180 self.alias_bbcall(i, fn_map, recursion_set);
181 }
182 match block_node.next.len() {
184 0 => {}
185 _ => {
186 for next in block_node.next {
191 self.check(next, fn_map, recursion_set);
192 }
193 }
194 }
195
196 self.values = backup_values;
197 self.constant = backup_constant;
198 }
199
200 return;
201 }
202
203 let mut order = vec![];
204 order.push(vec![]);
205
206 if !cur_block.scc_sub_blocks.is_empty() {
208 match env::var_os("MOP") {
209 Some(val) if val == "0" => {
210 order.push(cur_block.scc_sub_blocks.clone());
211 }
212 _ => {
213 self.calculate_scc_order(
214 &mut cur_block.scc_sub_blocks.clone(),
215 &mut vec![],
216 &mut order,
217 &mut HashMap::new(),
218 bb_index,
219 bb_index,
220 &mut HashSet::new(),
221 );
222 }
223 }
224 }
225
226 let backup_values = self.values.clone(); let backup_constant = self.constant.clone();
228 let backup_alias_set = self.alias_set.clone();
229 let backup_fn_map = fn_map.clone();
230 let backup_recursion_set = recursion_set.clone();
231 for scc_each in order {
232 self.alias_set = backup_alias_set.clone();
233 self.values = backup_values.clone();
234 self.constant = backup_constant.clone();
235 *fn_map = backup_fn_map.clone();
236 *recursion_set = backup_recursion_set.clone();
237
238 if !scc_each.is_empty() {
239 for idx in scc_each {
240 self.alias_bb(idx);
241 self.alias_bbcall(idx, fn_map, recursion_set);
242 }
243 }
244
245 let cur_block = cur_block.clone();
246 match cur_block.next.len() {
248 0 => {
249 let results_nodes = self.values.clone();
250 self.merge_results(results_nodes);
251 return;
252 }
253 1 => {
254 for next in cur_block.next {
259 self.check(next, fn_map, recursion_set);
260 }
261 return;
262 }
263 _ => { }
265 }
266
267 let mut single_target = false;
269 let mut sw_val = 0;
270 let mut sw_target = 0; let mut path_discr_id = 0; let mut sw_targets = None; if !cur_block.switch_stmts.is_empty() && cur_block.scc_sub_blocks.is_empty() {
274 if let TerminatorKind::SwitchInt {
275 ref discr,
276 ref targets,
277 } = cur_block.switch_stmts[0].clone().kind
278 {
279 match discr {
280 Copy(p) | Move(p) => {
281 let place = self.projection(false, *p);
282 if let Some(father) = self.disc_map.get(&self.values[place].local) {
283 if let Some(constant) = self.constant.get(father) {
284 if *constant != usize::MAX {
285 single_target = true;
286 sw_val = *constant;
287 }
288 }
289 if self.values[place].local == place {
290 path_discr_id = *father;
291 sw_targets = Some(targets.clone());
292 }
293 }
294 }
295 Constant(c) => {
296 single_target = true;
297 let ty_env = TypingEnv::post_analysis(self.tcx, self.def_id);
298 if let Some(val) = c.const_.try_eval_target_usize(self.tcx, ty_env) {
299 sw_val = val as usize;
300 }
301 }
302 }
303 if single_target {
304 for iter in targets.iter() {
309 if iter.0 as usize == sw_val {
310 sw_target = iter.1.as_usize();
311 break;
312 }
313 }
314 if sw_target == 0 {
319 let all_target = targets.all_targets();
320 sw_target = all_target[all_target.len() - 1].as_usize();
321 }
322 }
323 }
324 }
325 if single_target {
328 self.check(sw_target, fn_map, recursion_set);
329 } else {
330 if let Some(targets) = sw_targets {
332 for iter in targets.iter() {
333 if self.visit_times > VISIT_LIMIT {
334 continue;
335 }
336 let next_index = iter.1.as_usize();
337 let path_discr_val = iter.0 as usize;
338 self.split_check_with_cond(
339 next_index,
340 path_discr_id,
341 path_discr_val,
342 fn_map,
343 recursion_set,
344 );
345 }
346 let all_targets = targets.all_targets();
347 let next_index = all_targets[all_targets.len() - 1].as_usize();
348 let path_discr_val = usize::MAX; self.split_check_with_cond(
350 next_index,
351 path_discr_id,
352 path_discr_val,
353 fn_map,
354 recursion_set,
355 );
356 } else {
357 for i in cur_block.next {
358 if self.visit_times > VISIT_LIMIT {
359 continue;
360 }
361 let next_index = i;
362 self.split_check(next_index, fn_map, recursion_set);
363 }
364 }
365 }
366 }
367 }
368
369 pub fn calculate_scc_order(
370 &mut self,
371 scc: &Vec<usize>,
372 path: &mut Vec<usize>,
373 ans: &mut Vec<Vec<usize>>,
374 disc_map: &mut HashMap<usize, usize>,
375 idx: usize,
376 root: usize,
377 visit: &mut HashSet<usize>,
378 ) {
379 if idx == root && !path.is_empty() {
380 ans.push(path.clone());
381 return;
382 }
383 visit.insert(idx);
384 let term = &self.terms[idx].clone();
385
386 match term {
387 TerminatorKind::SwitchInt {
388 ref discr,
389 ref targets,
390 } => match discr {
391 Copy(p) | Move(p) => {
392 let place = self.projection(false, *p);
393 if let Some(father) = self.disc_map.get(&self.values[place].local) {
394 let father = *father;
395 if let Some(constant) = disc_map.get(&father) {
396 let constant = *constant;
397 for t in targets.iter() {
398 if t.0 as usize == constant {
399 let target = t.1.as_usize();
400 if path.contains(&target) {
401 continue;
402 }
403 path.push(target);
404 self.calculate_scc_order(
405 scc, path, ans, disc_map, target, root, visit,
406 );
407 path.pop();
408 }
409 }
410 } else {
411 for t in targets.iter() {
412 let constant = t.0 as usize;
413 let target = t.1.as_usize();
414 if path.contains(&target) {
415 continue;
416 }
417 path.push(target);
418 disc_map.insert(father, constant);
419 self.calculate_scc_order(
420 scc, path, ans, disc_map, target, root, visit,
421 );
422 disc_map.remove(&father);
423 path.pop();
424 }
425 }
426 } else {
427 if let Some(constant) = disc_map.get(&place) {
428 let constant = *constant;
429 for t in targets.iter() {
430 if t.0 as usize == constant {
431 let target = t.1.as_usize();
432 if path.contains(&target) {
433 continue;
434 }
435 path.push(target);
436 self.calculate_scc_order(
437 scc, path, ans, disc_map, target, root, visit,
438 );
439 path.pop();
440 }
441 }
442 } else {
443 for t in targets.iter() {
444 let constant = t.0 as usize;
445 let target = t.1.as_usize();
446 if path.contains(&target) {
447 continue;
448 }
449 path.push(target);
450 disc_map.insert(place, constant);
451 self.calculate_scc_order(
452 scc, path, ans, disc_map, target, root, visit,
453 );
454 disc_map.remove(&place);
455 path.pop();
456 }
457
458 let constant = targets.iter().len();
459 let target = targets.otherwise().as_usize();
460 if !path.contains(&target) {
461 path.push(target);
462 disc_map.insert(place, constant);
463 self.calculate_scc_order(
464 scc, path, ans, disc_map, target, root, visit,
465 );
466 disc_map.remove(&place);
467 path.pop();
468 }
469 }
470 }
471 }
472 _ => {}
473 },
474 _ => {
475 for bidx in self.blocks[idx].next.clone() {
476 if !scc.contains(&bidx) && bidx != root {
477 continue;
478 }
479 if bidx != root {
480 path.push(bidx);
481 self.calculate_scc_order(scc, path, ans, disc_map, bidx, root, visit);
482 path.pop();
483 } else {
484 self.calculate_scc_order(scc, path, ans, disc_map, bidx, root, visit);
485 }
486 }
487 }
488 }
489
490 visit.remove(&idx);
491 }
492}