1#![allow(unused_imports)]
2#![allow(unused_variables)]
3#![allow(dead_code)]
4#![allow(unused_assignments)]
5#![allow(unused_parens)]
6#![allow(non_snake_case)]
7#![allow(unused)]
8
9use super::domain::*;
10use crate::analysis::core::range_analysis::{Range, RangeType};
11
12use crate::analysis::core::range_analysis::domain::SymbolicExpr::*;
13use crate::rap_debug;
14use crate::rap_info;
15use crate::rap_trace;
16use num_traits::Bounded;
17use once_cell::sync::{Lazy, OnceCell};
18use rustc_abi::FieldIdx;
20use rustc_data_structures::fx::FxHashMap;
21use rustc_hir::def_id::LOCAL_CRATE;
22use rustc_hir::{def, def_id::DefId};
23use rustc_index::IndexVec;
24use rustc_middle::mir::visit::{PlaceContext, Visitor};
25use rustc_middle::{
26 mir::*,
27 ty::{self, ScalarInt, TyCtxt, print},
28};
29use rustc_span::source_map::Spanned;
30use rustc_span::sym::var;
31
32use core::borrow;
33use std::cell::RefCell;
34use std::fmt::Write;
35use std::rc::Rc;
36use std::{
37 collections::{HashMap, HashSet, VecDeque},
38 default,
39 fmt::Debug,
40};
41
42#[derive(Clone)]
43
44pub struct ConstraintGraph<'tcx, T: IntervalArithmetic + ConstConvert + Debug> {
45 pub tcx: TyCtxt<'tcx>,
46 pub body: &'tcx Body<'tcx>,
47 pub self_def_id: DefId, pub vars: VarNodes<'tcx, T>, pub local_inserted: HashSet<Local>,
51
52 pub array_vars: VarNodes<'tcx, T>, pub oprs: Vec<BasicOpKind<'tcx, T>>, pub defmap: DefMap<'tcx>, pub usemap: UseMap<'tcx>, pub symbmap: SymbMap<'tcx>, pub values_branchmap: HashMap<&'tcx Place<'tcx>, ValueBranchMap<'tcx, T>>, constant_vector: Vec<T>, pub inst_rand_place_set: Vec<Place<'tcx>>,
63 pub essa: DefId,
64 pub ssa: DefId,
65 pub index: i32,
67 pub dfs: HashMap<&'tcx Place<'tcx>, i32>,
68 pub root: HashMap<&'tcx Place<'tcx>, &'tcx Place<'tcx>>,
69 pub in_component: HashSet<&'tcx Place<'tcx>>,
70 pub components: HashMap<&'tcx Place<'tcx>, HashSet<&'tcx Place<'tcx>>>,
71 pub worklist: VecDeque<&'tcx Place<'tcx>>,
72 pub numAloneSCCs: usize,
73 pub numSCCs: usize, pub final_vars: VarNodes<'tcx, T>,
75 pub arg_count: usize,
76 pub rerurn_places: HashSet<&'tcx Place<'tcx>>,
77 pub switchbbs: HashMap<BasicBlock, (Place<'tcx>, Place<'tcx>)>,
78 pub const_func_place: HashMap<&'tcx Place<'tcx>, usize>,
79 pub func_without_mir: HashMap<DefId, String>,
80 pub unique_adt_path: HashMap<String, usize>,
81}
82
83impl<'tcx, T> ConstraintGraph<'tcx, T>
84where
85 T: IntervalArithmetic + ConstConvert + Debug,
86{
87 pub fn convert_const(c: &Const) -> Option<T> {
88 T::from_const(c)
89 }
90 pub fn new(
91 body: &'tcx Body<'tcx>,
92 tcx: TyCtxt<'tcx>,
93 self_def_id: DefId,
94 essa: DefId,
95 ssa: DefId,
96 ) -> Self {
97 let mut unique_adt_path: HashMap<String, usize> = HashMap::new();
98 unique_adt_path.insert("std::ops::Range".to_string(), 1);
99
100 Self {
101 tcx,
102 body,
103 self_def_id,
104 vars: VarNodes::new(),
105 local_inserted: HashSet::new(),
106 array_vars: VarNodes::new(),
107 oprs: GenOprs::new(),
108 defmap: DefMap::new(),
110 usemap: UseMap::new(),
111 symbmap: SymbMap::new(),
112 values_branchmap: ValuesBranchMap::new(),
113 constant_vector: Vec::new(),
115 inst_rand_place_set: Vec::new(),
116 essa,
117 ssa,
118 index: 0,
119 dfs: HashMap::new(),
120 root: HashMap::new(),
121 in_component: HashSet::new(),
122 components: HashMap::new(),
123 worklist: VecDeque::new(),
124 numAloneSCCs: 0,
125 numSCCs: 0,
126 final_vars: VarNodes::new(),
127 arg_count: 0,
128 rerurn_places: HashSet::new(),
129 switchbbs: HashMap::new(),
130 const_func_place: HashMap::new(),
131 func_without_mir: HashMap::new(),
132 unique_adt_path: unique_adt_path,
133 }
134 }
135 pub fn new_without_ssa(body: &'tcx Body<'tcx>, tcx: TyCtxt<'tcx>, self_def_id: DefId) -> Self {
136 let mut unique_adt_path: HashMap<String, usize> = HashMap::new();
137 unique_adt_path.insert("std::ops::Range".to_string(), 1);
138 Self {
139 tcx,
140 body,
141 self_def_id,
142 vars: VarNodes::new(),
143 local_inserted: HashSet::new(),
144
145 array_vars: VarNodes::new(),
146 oprs: GenOprs::new(),
147 defmap: DefMap::new(),
149 usemap: UseMap::new(),
150 symbmap: SymbMap::new(),
151 values_branchmap: ValuesBranchMap::new(),
152 constant_vector: Vec::new(),
154 inst_rand_place_set: Vec::new(),
155 essa: self_def_id, ssa: self_def_id, index: 0,
158 dfs: HashMap::new(),
159 root: HashMap::new(),
160 in_component: HashSet::new(),
161 components: HashMap::new(),
162 worklist: VecDeque::new(),
163 numAloneSCCs: 0,
164 numSCCs: 0,
165 final_vars: VarNodes::new(),
166 arg_count: 0,
167 rerurn_places: HashSet::new(),
168 switchbbs: HashMap::new(),
169 const_func_place: HashMap::new(),
170 func_without_mir: HashMap::new(),
171 unique_adt_path: unique_adt_path,
172 }
173 }
174 pub fn to_dot(&self) -> String {
175 let mut dot = String::new();
176 writeln!(&mut dot, "digraph ConstraintGraph {{").unwrap();
177
178 writeln!(&mut dot, " layout=neato;").unwrap();
179 writeln!(&mut dot, " overlap=false;").unwrap();
180 writeln!(&mut dot, " splines=true;").unwrap();
181 writeln!(&mut dot, " sep=\"+1.0\";").unwrap();
182 writeln!(&mut dot, " rankdir=TB;").unwrap();
183 writeln!(&mut dot, " ranksep=1.8;").unwrap();
184 writeln!(&mut dot, " nodesep=0.8;").unwrap();
185 writeln!(&mut dot, " edge [len=2.0];").unwrap();
186 writeln!(&mut dot, " node [fontname=\"Fira Code\"];").unwrap();
187 writeln!(&mut dot, "\n // Variable Nodes").unwrap();
188 writeln!(&mut dot, " subgraph cluster_vars {{").unwrap();
189 writeln!(&mut dot, " rank=same;").unwrap();
190 for (place, var_node) in &self.vars {
191 let place_id = format!("{:?}", place);
192 let label = format!("{:?}", place);
193 writeln!(
194 &mut dot,
195 " \"{}\" [label=\"{}\", shape=ellipse, style=filled, fillcolor=lightblue, width=1.2, fixedsize=false];",
196 place_id, label
197 ).unwrap();
198 }
199 writeln!(&mut dot, " }}").unwrap();
200
201 writeln!(&mut dot, "\n // Operation Nodes").unwrap();
202 writeln!(&mut dot, " subgraph cluster_ops {{").unwrap();
203 writeln!(&mut dot, " rank=same;").unwrap();
204 for (op_idx, op) in self.oprs.iter().enumerate() {
205 let op_id = format!("op_{}", op_idx);
206 let label = match op {
207 BasicOpKind::Unary(o) => format!("Unary({:?})", o.op),
208 BasicOpKind::Binary(o) => format!("Binary({:?})", o.op),
209 BasicOpKind::Essa(_) => "Essa".to_string(),
210 BasicOpKind::ControlDep(_) => "ControlDep".to_string(),
211 BasicOpKind::Phi(_) => "Φ (Phi)".to_string(),
212 BasicOpKind::Use(_) => "Use".to_string(),
213 BasicOpKind::Call(c) => format!("Call({:?})", c.def_id),
214 BasicOpKind::Ref(r) => format!("Ref({:?})", r.borrowkind),
215 BasicOpKind::Aggregate(r) => format!("AggregateOp({:?})", r.unique_adt),
216 };
217 writeln!(
218 &mut dot,
219 " \"{}\" [label=\"{}\", shape=box, style=filled, fillcolor=lightgrey, width=1.5, fixedsize=false];",
220 op_id, label
221 ).unwrap();
222 }
223 writeln!(&mut dot, " }}").unwrap();
224
225 writeln!(&mut dot, "\n // Definition Edges (op -> var)").unwrap();
227 for (place, op_idx) in &self.defmap {
228 writeln!(&mut dot, " \"op_{}\" -> \"{:?}\";", op_idx, place).unwrap();
229 }
230
231 writeln!(&mut dot, "\n // Use Edges (var -> op)").unwrap();
232 for (place, op_indices) in &self.usemap {
233 for op_idx in op_indices {
234 writeln!(&mut dot, " \"{:?}\" -> \"op_{}\";", place, op_idx).unwrap();
235 }
236 }
237
238 writeln!(&mut dot, "\n // Symbolic Bound Edges (var -> op)").unwrap();
239 for (place, op_indices) in &self.symbmap {
240 for op_idx in op_indices {
241 writeln!(
242 &mut dot,
243 " \"{:?}\" -> \"op_{}\" [color=blue, style=dashed];",
244 place, op_idx
245 )
246 .unwrap();
247 }
248 }
249
250 writeln!(&mut dot, "}}").unwrap();
251 dot
252 }
253
254 pub fn build_final_vars(
255 &mut self,
256 places_map: &HashMap<Place<'tcx>, HashSet<Place<'tcx>>>,
257 ) -> (VarNodes<'tcx, T>, Vec<Place<'tcx>>) {
258 let mut final_vars: VarNodes<'tcx, T> = HashMap::new();
259 let mut not_found: Vec<Place<'tcx>> = Vec::new();
260
261 for (&_key_place, place_set) in places_map {
262 for &place in place_set {
263 let found = self.vars.iter().find(|&(&p, _)| *p == place);
264
265 if let Some((&found_place, var_node)) = found {
266 final_vars.insert(found_place, var_node.clone());
267 } else {
268 not_found.push(place);
269 }
270 }
271 }
272 self.final_vars = final_vars.clone();
273 (final_vars, not_found)
274 }
275 pub fn filter_final_vars(
276 vars: &VarNodes<'tcx, T>,
277 places_map: &HashMap<Place<'tcx>, HashSet<Place<'tcx>>>,
278 ) -> HashMap<Place<'tcx>, Range<T>> {
279 let mut final_vars = HashMap::new();
280
281 for (&_key_place, place_set) in places_map {
282 for &place in place_set {
283 if let Some(var_node) = vars.get(&place) {
284 final_vars.insert(place, var_node.get_range().clone());
285 }
286 }
287 }
288 final_vars
289 }
290 pub fn test_and_print_all_symbolic_expressions(&self) {
291 rap_info!("\n==== Testing and Printing All Symbolic Expressions ====");
292
293 let mut places: Vec<&'tcx Place<'tcx>> = self.vars.keys().copied().collect();
294 places.sort_by_key(|p| p.local.as_usize());
295
296 for place in places {
297 rap_info!("--- Place: {:?}", place);
298 }
307 rap_info!("==== End of Symbolic Expression Test ====\n");
308 }
309 pub fn rap_print_final_vars(&self) {
310 for (&key, value) in &self.final_vars {
311 rap_debug!("Var: {:?}, {:?} ", key, value.get_range());
312 }
313 }
314 pub fn rap_print_vars(&self) {
315 for (&key, value) in &self.vars {
316 rap_trace!("Var: {:?}. {:?} ", key, value.get_range());
317 }
318 }
319 pub fn print_vars(&self) {
320 for (&key, value) in &self.vars {
321 rap_trace!("Var: {:?}. {:?} ", key, value.get_range());
322 }
323 }
324 pub fn print_conponent_vars(&self) {
325 rap_trace!("====print_conponent_vars====");
326 for (key, value) in &self.components {
327 if value.len() > 1 {
328 rap_trace!("component: {:?} ", key);
329 for v in value {
330 if let Some(var_node) = self.vars.get(v) {
331 rap_trace!("Var: {:?}. {:?} ", v, var_node.get_range());
332 } else {
333 rap_trace!("Var: {:?} not found", v);
334 }
335 }
336 }
337 }
338 }
339 fn print_values_branchmap(&self) {
340 for (&key, value) in &self.values_branchmap {
341 rap_info!("vbm place: {:?}. {:?}\n ", key, value);
342 }
343 }
344 fn print_symbmap(&self) {
345 for (&key, value) in &self.symbmap {
346 for op in value.iter() {
347 if let Some(op) = self.oprs.get(*op) {
348 rap_trace!("symbmap op: {:?}. {:?}\n ", key, op);
349 } else {
350 rap_trace!("symbmap op: {:?} not found\n ", op);
351 }
352 }
353 }
354 }
355 fn print_defmap(&self) {
356 for (key, value) in self.defmap.clone() {
357 rap_trace!(
358 "place: {:?} def in stmt:{:?} {:?}",
359 key,
360 self.oprs[value].get_type_name(),
361 self.oprs[value].get_instruction()
362 );
363 }
364 }
365 fn print_compusemap(
366 &self,
367 component: &HashSet<&'tcx Place<'tcx>>,
368 comp_use_map: &HashMap<&'tcx Place<'tcx>, HashSet<usize>>,
369 ) {
370 for (key, value) in comp_use_map.clone() {
371 if component.contains(key) {
372 for v in value {
373 rap_trace!(
374 "compusemap place: {:?} use in stmt:{:?} {:?}",
375 key,
376 self.oprs[v].get_type_name(),
377 self.oprs[v].get_instruction()
378 );
379 }
380 }
381 }
382 }
383 fn print_usemap(&self) {
384 for (key, value) in self.usemap.clone() {
385 for v in value {
386 rap_trace!(
387 "place: {:?} use in stmt:{:?} {:?}",
388 key,
389 self.oprs[v].get_type_name(),
390 self.oprs[v].get_instruction()
391 );
392 }
393 }
394 }
395 fn print_symbexpr(&self) {
396 for (&key, value) in &self.vars {
397 rap_info!(
398 "Var: {:?}. [ {:?} , {:?} ]",
399 key,
400 value.interval.get_lower_expr(),
401 value.interval.get_upper_expr()
402 );
403 }
404 }
405 pub fn get_vars(&self) -> &VarNodes<'tcx, T> {
416 &self.vars
417 }
418 pub fn get_field_place(&self, adt_place: Place<'tcx>, field_index: FieldIdx) -> Place<'tcx> {
419 let adt_ty = adt_place.ty(&self.body.local_decls, self.tcx).ty;
420 let field_ty = match adt_ty.kind() {
421 ty::TyKind::Adt(adt_def, substs) => {
422 let variant_def = adt_def.variants().iter().next().unwrap();
424
425 let field_def = &variant_def.fields[field_index];
427
428 field_def.ty(self.tcx, substs)
431 }
432 _ => {
433 panic!("get_field_place expected an ADT, but found {:?}", adt_ty);
434 }
435 };
436
437 let mut new_projection = adt_place.projection.to_vec();
438 new_projection.push(ProjectionElem::Field(field_index, field_ty));
439
440 let new_place = Place {
441 local: adt_place.local,
442 projection: self.tcx.mk_place_elems(&new_projection),
443 };
444 new_place
445 }
446 pub fn add_varnode(&mut self, v: &'tcx Place<'tcx>) -> &mut VarNode<'tcx, T> {
447 let local_decls = &self.body.local_decls;
448
449 let node = VarNode::new(v);
450 let node_ref: &mut VarNode<'tcx, T> = self
451 .vars
452 .entry(v)
453 .or_insert(node);
455 self.usemap.entry(v).or_insert(HashSet::new());
456
457 let ty = local_decls[v.local].ty;
458 let place_ty = v.ty(local_decls, self.tcx);
459
460 if v.projection.is_empty() || self.defmap.contains_key(v) {
461 return node_ref;
462 }
463
464 if !v.projection.is_empty() {
465 let matches: Vec<(_, _)> = self
503 .defmap
504 .iter()
505 .filter(|(p, _)| p.local == v.local && p.projection.is_empty())
506 .map(|(p, def_op)| (*p, *def_op))
507 .collect();
508
509 for (base_place, def_op) in matches {
510 let mut v_op = self.oprs[def_op].clone();
511 v_op.set_sink(v);
512
513 for source in v_op.get_sources() {
514 self.usemap
515 .entry(source)
516 .or_insert(HashSet::new())
517 .insert(self.oprs.len());
518 }
519
520 self.oprs.push(v_op);
521 self.defmap.insert(v, self.oprs.len() - 1);
522 }
523 }
524
525 node_ref
526 }
527 pub fn add_varnode_sym(
528 &mut self,
529 v: &'tcx Place<'tcx>,
530 rvalue: &'tcx Rvalue<'tcx>,
531 ) -> &mut VarNode<'tcx, T> {
532 let local_decls = &self.body.local_decls;
533 let node = VarNode::new_symb(v, SymbExpr::from_rvalue(rvalue));
534 rap_debug!("add_varnode_sym node:{:?}", node);
535 let node_ref: &mut VarNode<'tcx, T> = self
536 .vars
537 .entry(v)
538 .or_insert(node);
540 self.usemap.entry(v).or_insert(HashSet::new());
541
542 let ty = local_decls[v.local].ty;
543 let place_ty = v.ty(local_decls, self.tcx);
544
545 if v.projection.is_empty() || self.defmap.contains_key(v) {
546 return node_ref;
547 }
548
549 if !v.projection.is_empty() {
550 let matches: Vec<(_, _)> = self
551 .defmap
552 .iter()
553 .filter(|(p, _)| p.local == v.local && p.projection.is_empty())
554 .map(|(p, &def_op)| (*p, def_op))
555 .collect();
556
557 for (base_place, def_op) in matches {
558 let mut v_op = self.oprs[def_op].clone();
559 v_op.set_sink(v);
560
561 for source in v_op.get_sources() {
562 self.usemap
563 .entry(source)
564 .or_insert(HashSet::new())
565 .insert(self.oprs.len());
566 }
567
568 self.oprs.push(v_op);
569 self.defmap.insert(v, self.oprs.len() - 1);
570 }
571 }
572
573 node_ref
574 }
575
576 pub fn postprocess_defmap(&mut self) {
577 for place in self.vars.keys() {
578 if !place.projection.is_empty() {
579 if let Some((&base_place, &base_value)) = self
580 .defmap
581 .iter()
582 .find(|(p, _)| p.local == place.local && p.projection.is_empty())
583 {
584 self.defmap.insert(place, base_value);
585 } else {
586 rap_trace!("postprocess_defmap: No base place found for {:?}", place);
587 }
588 }
589 }
590 }
591 pub fn build_graph(&mut self, body: &'tcx Body<'tcx>) {
612 self.arg_count = body.arg_count;
613 self.build_value_maps(body);
614 for block in body.basic_blocks.indices() {
615 let block_data = &body[block];
616 for statement in block_data.statements.iter() {
619 self.build_operations(statement, block, body);
620 }
621 self.build_terminator(block, block_data.terminator.as_ref().unwrap());
622 }
623 self.print_vars();
625 self.print_defmap();
626 self.print_usemap();
627 self.print_symbexpr();
628 }
630
631 pub fn build_value_maps(&mut self, body: &'tcx Body<'tcx>) {
632 for bb in body.basic_blocks.indices() {
633 let block_data = &body[bb];
634 if let Some(terminator) = &block_data.terminator {
635 match &terminator.kind {
636 TerminatorKind::SwitchInt { discr, targets } => {
637 self.build_value_branch_map(body, discr, targets, bb, block_data);
638 }
639 TerminatorKind::Goto { target } => {
640 }
642 _ => {
643 }
648 }
649 }
650 }
651 }
654
655 pub fn build_value_branch_map(
656 &mut self,
657 body: &Body<'tcx>,
658 discr: &'tcx Operand<'tcx>,
659 targets: &'tcx SwitchTargets,
660 block: BasicBlock,
661 block_data: &'tcx BasicBlockData<'tcx>,
662 ) {
663 if let Operand::Copy(place) | Operand::Move(place) = discr {
665 if let Some((op1, op2, cmp_op)) = self.extract_condition(place, block_data) {
666 let const_op1 = op1.constant();
667 let const_op2 = op2.constant();
668 match (const_op1, const_op2) {
669 (Some(c1), Some(c2)) => {}
670 (Some(c), None) | (None, Some(c)) => {
671 let const_in_left: bool;
672 let variable;
673 if const_op1.is_some() {
674 const_in_left = true;
675 variable = match op2 {
676 Operand::Copy(p) | Operand::Move(p) => p,
677 _ => panic!("Expected a place"),
678 };
679 } else {
680 const_in_left = false;
681 variable = match op1 {
682 Operand::Copy(p) | Operand::Move(p) => p,
683 _ => panic!("Expected a place"),
684 };
685 }
686 self.add_varnode(variable);
687 rap_trace!("add_vbm_varnode{:?}\n", variable.clone());
688
689 let value = Self::convert_const(&c.const_).unwrap();
691 let const_range =
692 Range::new(value.clone(), value.clone(), RangeType::Unknown);
693 rap_trace!("cmp_op{:?}\n", cmp_op);
694 rap_trace!("const_in_left{:?}\n", const_in_left);
695 let mut true_range =
696 self.apply_comparison(value.clone(), cmp_op, true, const_in_left);
697 let mut false_range =
698 self.apply_comparison(value.clone(), cmp_op, false, const_in_left);
699 true_range.set_regular();
700 false_range.set_regular();
701 let target_vec = targets.all_targets();
704
705 let vbm = ValueBranchMap::new(
706 variable,
707 &target_vec[0],
708 &target_vec[1],
709 IntervalType::Basic(BasicInterval::new(false_range)),
710 IntervalType::Basic(BasicInterval::new(true_range)),
711 );
712 self.values_branchmap.insert(variable, vbm);
713 }
715 (None, None) => {
716 let CR = Range::new(T::min_value(), T::max_value(), RangeType::Unknown);
717
718 let p1 = match op1 {
719 Operand::Copy(p) | Operand::Move(p) => p,
720 _ => panic!("Expected a place"),
721 };
722 let p2 = match op2 {
723 Operand::Copy(p) | Operand::Move(p) => p,
724 _ => panic!("Expected a place"),
725 };
726 let target_vec = targets.all_targets();
727 self.add_varnode(&p1);
728 rap_trace!("add_vbm_varnode{:?}\n", p1.clone());
729
730 self.add_varnode(&p2);
731 rap_trace!("add_vbm_varnode{:?}\n", p2.clone());
732 let flipped_cmp_op = Self::flipped_binop(cmp_op).unwrap();
733 let reversed_cmp_op = Self::reverse_binop(cmp_op).unwrap();
734 let reversed_flippedd_cmp_op =
735 Self::flipped_binop(reversed_cmp_op).unwrap();
736 let STOp1 = IntervalType::Symb(SymbInterval::new(CR.clone(), p2, cmp_op));
737 let SFOp1 =
738 IntervalType::Symb(SymbInterval::new(CR.clone(), p2, flipped_cmp_op));
739 let STOp2 =
740 IntervalType::Symb(SymbInterval::new(CR.clone(), p1, reversed_cmp_op));
741 let SFOp2 = IntervalType::Symb(SymbInterval::new(
742 CR.clone(),
743 p1,
744 reversed_flippedd_cmp_op,
745 ));
746 rap_trace!("SFOp1{:?}\n", SFOp1);
747 rap_trace!("SFOp2{:?}\n", SFOp2);
748 rap_trace!("STOp1{:?}\n", STOp1);
749 rap_trace!("STOp2{:?}\n", STOp2);
750 let vbm_1 =
751 ValueBranchMap::new(p1, &target_vec[0], &target_vec[1], SFOp1, STOp1);
752 let vbm_2 =
753 ValueBranchMap::new(p2, &target_vec[0], &target_vec[1], SFOp2, STOp2);
754 self.values_branchmap.insert(&p1, vbm_1);
755 self.values_branchmap.insert(&p2, vbm_2);
756 self.switchbbs.insert(block, (*p1, *p2));
757 }
758 }
759 };
760 }
761 }
762 pub fn flipped_binop(op: BinOp) -> Option<BinOp> {
763 use BinOp::*;
764 Some(match op {
765 Eq => Eq,
766 Ne => Ne,
767 Lt => Ge,
768 Le => Gt,
769 Gt => Le,
770 Ge => Lt,
771 Add => Add,
772 Mul => Mul,
773 BitXor => BitXor,
774 BitAnd => BitAnd,
775 BitOr => BitOr,
776 _ => {
777 return None;
778 }
779 })
780 }
781 fn reverse_binop(op: BinOp) -> Option<BinOp> {
782 use BinOp::*;
783 Some(match op {
784 Eq => Eq,
785 Ne => Ne,
786 Lt => Gt,
787 Le => Ge,
788 Gt => Lt,
789 Ge => Le,
790 Add => Add,
791 Mul => Mul,
792 BitXor => BitXor,
793 BitAnd => BitAnd,
794 BitOr => BitOr,
795 _ => {
796 return None;
797 }
798 })
799 }
800 fn extract_condition(
801 &mut self,
802 place: &'tcx Place<'tcx>,
803 switch_block: &'tcx BasicBlockData<'tcx>,
804 ) -> Option<(&'tcx Operand<'tcx>, &'tcx Operand<'tcx>, BinOp)> {
805 for stmt in &switch_block.statements {
806 if let StatementKind::Assign(box (lhs, Rvalue::BinaryOp(bin_op, box (op1, op2)))) =
807 &stmt.kind
808 {
809 if lhs == place {
810 let mut return_op1: &Operand<'tcx> = &op1;
811 let mut return_op2: &Operand<'tcx> = &op2;
812 for stmt_original in &switch_block.statements {
813 if let StatementKind::Assign(box (lhs, Rvalue::Use(OP1))) =
814 &stmt_original.kind
815 {
816 if lhs.clone() == op1.place().unwrap() {
817 return_op1 = OP1;
818 }
819 }
820 }
821 if op2.constant().is_none() {
822 for stmt_original in &switch_block.statements {
823 if let StatementKind::Assign(box (lhs, Rvalue::Use(OP2))) =
824 &stmt_original.kind
825 {
826 if lhs.clone() == op2.place().unwrap() {
827 return_op2 = OP2;
828 }
829 }
830 }
831 }
832
833 return Some((return_op1, return_op2, *bin_op));
834 }
835 }
836 }
837 None
838 }
839
840 fn apply_comparison<U: IntervalArithmetic>(
841 &self,
842 constant: U,
843 cmp_op: BinOp,
844 is_true_branch: bool,
845 const_in_left: bool,
846 ) -> Range<U> {
847 match cmp_op {
848 BinOp::Lt => {
849 if is_true_branch ^ const_in_left {
850 Range::new(U::min_value(), constant.sub(U::one()), RangeType::Unknown)
851 } else {
852 Range::new(constant, U::max_value(), RangeType::Unknown)
853 }
854 }
855
856 BinOp::Le => {
857 if is_true_branch ^ const_in_left {
858 Range::new(U::min_value(), constant, RangeType::Unknown)
859 } else {
860 Range::new(constant.add(U::one()), U::max_value(), RangeType::Unknown)
861 }
862 }
863
864 BinOp::Gt => {
865 if is_true_branch ^ const_in_left {
866 Range::new(U::min_value(), constant, RangeType::Unknown)
867 } else {
868 Range::new(constant.add(U::one()), U::max_value(), RangeType::Unknown)
869 }
870 }
871
872 BinOp::Ge => {
873 if is_true_branch ^ const_in_left {
874 Range::new(U::min_value(), constant, RangeType::Unknown)
875 } else {
876 Range::new(constant, U::max_value().sub(U::one()), RangeType::Unknown)
877 }
878 }
879
880 BinOp::Eq => {
881 if is_true_branch ^ const_in_left {
882 Range::new(U::min_value(), constant, RangeType::Unknown)
883 } else {
884 Range::new(constant, U::max_value(), RangeType::Unknown)
885 }
886 }
887
888 _ => Range::new(constant.clone(), constant.clone(), RangeType::Empty),
889 }
890 }
891
892 fn build_value_goto_map(&self, block_index: BasicBlock, target: BasicBlock) {
893 rap_trace!(
894 "Building value map for Goto in block {:?} targeting block {:?}",
895 block_index,
896 target
897 );
898 }
899 pub fn build_varnodes(&mut self) {
900 for (name, node) in self.vars.iter_mut() {
902 let is_undefined = !self.defmap.contains_key(name);
903 node.init(is_undefined);
904 }
905 }
906 pub fn build_symbolic_intersect_map(&mut self) {
907 for i in 0..self.oprs.len() {
908 if let BasicOpKind::Essa(essaop) = &self.oprs[i] {
909 if let IntervalType::Symb(symbi) = essaop.get_intersect() {
910 let v = symbi.get_bound();
911 self.symbmap.entry(v).or_insert_with(HashSet::new).insert(i);
912 rap_trace!("symbmap insert {:?} {:?}\n", v, essaop);
913 }
914 }
915 }
916 }
918 pub fn build_use_map(
919 &mut self,
920 component: &HashSet<&'tcx Place<'tcx>>,
921 ) -> HashMap<&'tcx Place<'tcx>, HashSet<usize>> {
922 let mut comp_use_map = HashMap::new();
924 for &place in component {
925 if let Some(uses) = self.usemap.get(place) {
926 for op in uses.iter() {
927 let sink = self.oprs[*op].get_sink();
928 if component.contains(&sink) {
929 comp_use_map
930 .entry(place)
931 .or_insert_with(HashSet::new)
932 .insert(*op);
933 }
934 }
935 }
936 }
937
938 self.print_compusemap(component, &comp_use_map);
939 comp_use_map
940 }
941 pub fn build_terminator(&mut self, block: BasicBlock, terminator: &'tcx Terminator<'tcx>) {
942 match &terminator.kind {
943 TerminatorKind::Call {
944 func,
945 args,
946 destination,
947 target: _,
948 unwind: _,
949 fn_span: _,
950 call_source,
951 } => {
952 rap_trace!(
953 "TerminatorKind::Call in block {:?} with function {:?} destination {:?} args {:?}\n",
954 block,
955 func,
956 destination,
957 args
958 );
959 self.add_call_op(destination, args, terminator, func, block);
961 }
962 TerminatorKind::Return => {}
963 TerminatorKind::Goto { target } => {
964 rap_trace!(
965 "TerminatorKind::Goto in block {:?} targeting block {:?}\n",
966 block,
967 target
968 );
969 }
970 TerminatorKind::SwitchInt { discr, targets } => {
971 rap_trace!(
972 "TerminatorKind::SwitchInt in block {:?} with discr {:?} and targets {:?}\n",
973 block,
974 discr,
975 targets
976 );
977 }
978 _ => {
979 rap_trace!(
980 "Unsupported terminator kind in block {:?}: {:?}",
981 block,
982 terminator.kind
983 );
984 }
985 }
986 }
987 pub fn build_operations(
988 &mut self,
989 inst: &'tcx Statement<'tcx>,
990 block: BasicBlock,
991 body: &'tcx Body<'tcx>,
992 ) {
993 match &inst.kind {
994 StatementKind::Assign(box (sink, rvalue)) => match rvalue {
995 Rvalue::BinaryOp(op, box (op1, op2)) => match op {
996 BinOp::Add
997 | BinOp::Sub
998 | BinOp::Mul
999 | BinOp::Div
1000 | BinOp::Rem
1001 | BinOp::AddUnchecked => {
1002 self.add_binary_op(sink, inst, rvalue, op1, op2, *op);
1003 }
1004 BinOp::AddWithOverflow => {
1005 self.add_binary_op(sink, inst, rvalue, op1, op2, *op);
1006 }
1007 BinOp::SubUnchecked => {
1008 self.add_binary_op(sink, inst, rvalue, op1, op2, *op);
1009 }
1010 BinOp::SubWithOverflow => {
1011 self.add_binary_op(sink, inst, rvalue, op1, op2, *op);
1012 }
1013 BinOp::MulUnchecked => {
1014 self.add_binary_op(sink, inst, rvalue, op1, op2, *op);
1015 }
1016 BinOp::MulWithOverflow => {
1017 self.add_binary_op(sink, inst, rvalue, op1, op2, *op);
1018 }
1019
1020 _ => {}
1021 },
1022 Rvalue::UnaryOp(unop, operand) => {
1023 self.add_unary_op(sink, inst, rvalue, operand, *unop);
1024 }
1025 Rvalue::Aggregate(kind, operends) => match **kind {
1026 AggregateKind::Adt(def_id, _, _, _, _) => match def_id {
1027 _ if def_id == self.essa => self.add_essa_op(sink, inst, operends, block),
1028 _ if def_id == self.ssa => self.add_ssa_op(sink, inst, operends),
1029 _ => match self.unique_adt_handler(def_id) {
1030 1 => {
1031 self.add_aggregate_op(sink, inst, rvalue, operends, 1);
1032 }
1033 _ => {
1034 rap_trace!(
1035 "AggregateKind::Adt with def_id {:?} in statement {:?} is not handled specially.\n",
1036 def_id,
1037 inst
1038 );
1039 }
1040 },
1041 },
1042 _ => {}
1043 },
1044 Rvalue::Use(operend) => {
1045 self.add_use_op(sink, inst, rvalue, operend);
1046 }
1047 Rvalue::Ref(_, borrowkind, place) => {
1048 self.add_ref_op(sink, inst, rvalue, place, *borrowkind);
1049 }
1050 _ => {}
1051 },
1052 _ => {}
1053 }
1054 }
1055 fn unique_adt_handler(&mut self, def_id: DefId) -> usize {
1057 let adt_path = self.tcx.def_path_str(def_id);
1058 rap_trace!("adt_path: {:?}\n", adt_path);
1059 if self.unique_adt_path.contains_key(&adt_path) {
1060 rap_trace!(
1061 "unique_adt_handler for def_id: {:?} -> {}\n",
1062 def_id,
1063 adt_path
1064 );
1065 return *self.unique_adt_path.get(&adt_path).unwrap();
1066 }
1067 0
1068 }
1069 fn add_call_op(
1071 &mut self,
1072 sink: &'tcx Place<'tcx>,
1073 args: &'tcx Box<[Spanned<Operand<'tcx>>]>,
1074 terminator: &'tcx Terminator<'tcx>,
1075 func: &'tcx Operand<'tcx>,
1076 block: BasicBlock,
1077 ) {
1078 rap_trace!("add_call_op for sink: {:?} {:?}\n", sink, terminator);
1079 let sink_node = self.add_varnode(&sink);
1080
1081 let mut path = String::new();
1085 let mut func_def_id = None;
1086 if let Operand::Constant(box const_operand) = func {
1087 let fn_ty = const_operand.ty();
1088 if let ty::TyKind::FnDef(def_id, _substs) = fn_ty.kind() {
1089 rap_debug!("fn_ty: {:?}\n", fn_ty);
1091 if def_id.krate != LOCAL_CRATE {
1092 path = self.tcx.def_path_str(*def_id);
1093
1094 self.func_without_mir.insert(*def_id, path.clone());
1095 rap_debug!("called external/no-MIR fn: {:?} -> {}", def_id, path);
1096 }
1097 func_def_id = Some(def_id);
1104 }
1105 }
1106
1107 if let Some(def_id) = func_def_id {
1108 rap_trace!(
1109 "TerminatorKind::Call in block {:?} with DefId {:?}\n",
1110 block,
1111 def_id
1112 );
1113 } else {
1115 rap_trace!(
1116 "TerminatorKind::Call in block {:?} is an indirect call (e.g., function pointer)\n",
1117 block
1118 );
1119 }
1122 let mut constant_count = 0 as usize;
1123 let arg_count = args.len();
1124 let mut arg_operands: Vec<Operand<'tcx>> = Vec::new();
1125 let mut places = Vec::new();
1126 for op in args.iter() {
1127 match &op.node {
1128 Operand::Copy(place) | Operand::Move(place) => {
1129 arg_operands.push(op.node.clone());
1130 places.push(place);
1131 self.add_varnode(place);
1132 self.usemap
1133 .entry(place)
1134 .or_default()
1135 .insert(self.oprs.len());
1136 }
1137
1138 Operand::Constant(_) => {
1139 arg_operands.push(op.node.clone());
1142 constant_count += 1;
1143 }
1144 }
1145 }
1146 {
1147 let bi = BasicInterval::new(Range::default(T::min_value()));
1148
1149 let call_op = CallOp::new(
1150 IntervalType::Basic(bi),
1151 &sink,
1152 terminator, arg_operands,
1154 *func_def_id.unwrap(), path,
1156 places,
1157 );
1158 rap_debug!("call_op: {:?}\n", call_op);
1159 let bop_index = self.oprs.len();
1160
1161 self.oprs.push(BasicOpKind::Call(call_op));
1163
1164 self.defmap.insert(&sink, bop_index);
1166 if constant_count == arg_count {
1167 rap_trace!("all args are constants\n");
1168 self.const_func_place.insert(&sink, bop_index);
1169 }
1170 }
1171 }
1172 fn add_ssa_op(
1173 &mut self,
1174 sink: &'tcx Place<'tcx>,
1175 inst: &'tcx Statement<'tcx>,
1176 operands: &'tcx IndexVec<FieldIdx, Operand<'tcx>>,
1177 ) {
1178 rap_trace!("ssa_op{:?}\n", inst);
1179
1180 let sink_node = self.add_varnode(sink);
1181 rap_trace!("addsink_in_ssa_op{:?}\n", sink_node);
1182
1183 let BI: BasicInterval<T> = BasicInterval::new(Range::default(T::min_value()));
1184 let mut phiop = PhiOp::new(IntervalType::Basic(BI), sink, inst, 0);
1185 let bop_index = self.oprs.len();
1186 for i in 0..operands.len() {
1187 let source = match &operands[FieldIdx::from_usize(i)] {
1188 Operand::Copy(place) | Operand::Move(place) => {
1189 self.add_varnode(place);
1190 Some(place)
1191 }
1192 _ => None,
1193 };
1194 if let Some(source) = source {
1195 self.add_varnode(source);
1196 phiop.add_source(source);
1197 rap_trace!("addvar_in_ssa_op{:?}\n", source);
1198 self.usemap.entry(source).or_default().insert(bop_index);
1199 }
1200 }
1201 self.oprs.push(BasicOpKind::Phi(phiop));
1204
1205 self.defmap.insert(sink, bop_index);
1208 }
1209 fn add_use_op(
1210 &mut self,
1211 sink: &'tcx Place<'tcx>,
1212 inst: &'tcx Statement<'tcx>,
1213 rvalue: &'tcx Rvalue<'tcx>,
1214 op: &'tcx Operand<'tcx>,
1215 ) {
1216 rap_trace!("use_op{:?}\n", inst);
1217
1218 let BI: BasicInterval<T> = BasicInterval::new(Range::default(T::min_value()));
1219 let mut source: Option<&'tcx Place<'tcx>> = None;
1220
1221 match op {
1222 Operand::Copy(place) | Operand::Move(place) => {
1223 if sink.local == RETURN_PLACE && sink.projection.is_empty() {
1224 self.rerurn_places.insert(place);
1225 let sink_node = self.add_varnode_sym(sink, rvalue);
1226
1227 rap_debug!("add_return_place{:?}\n", place);
1228 } else {
1229 self.add_varnode_sym(place, rvalue);
1230 source = Some(place);
1231 if let Some(source) = source {
1232 rap_trace!("addvar_in_use_op{:?}\n", source);
1233 let sink_node = self.add_varnode_sym(sink, rvalue);
1234 let useop =
1235 UseOp::new(IntervalType::Basic(BI), sink, inst, Some(source), None);
1236 let bop_index = self.oprs.len();
1238
1239 self.oprs.push(BasicOpKind::Use(useop));
1240 self.usemap.entry(source).or_default().insert(bop_index);
1242
1243 self.defmap.insert(sink, bop_index);
1244 }
1245 }
1246 }
1247 Operand::Constant(constant) => {
1248 rap_trace!("add_constant_op{:?}\n", inst);
1249 let Some(c) = op.constant() else {
1250 rap_trace!("add_constant_op: constant is None\n");
1251 return;
1252 };
1253 let useop = UseOp::new(IntervalType::Basic(BI), sink, inst, None, Some(c.const_));
1254 let bop_index = self.oprs.len();
1256
1257 self.oprs.push(BasicOpKind::Use(useop));
1258 self.defmap.insert(sink, bop_index);
1261 let sink_node = self.add_varnode_sym(sink, rvalue);
1262
1263 if let Some(value) = Self::convert_const(&c.const_) {
1264 sink_node.set_range(Range::new(
1265 value.clone(),
1266 value.clone(),
1267 RangeType::Regular,
1268 ));
1269 rap_trace!("set_const {:?} value: {:?}\n", sink_node, value);
1270 } else {
1272 sink_node.set_range(Range::default(T::min_value()));
1273 };
1274 }
1275 }
1276 }
1277 fn add_essa_op(
1278 &mut self,
1279 sink: &'tcx Place<'tcx>,
1280
1281 inst: &'tcx Statement<'tcx>,
1282 operands: &'tcx IndexVec<FieldIdx, Operand<'tcx>>,
1283 block: BasicBlock,
1284 ) {
1285 let sink_node = self.add_varnode(sink);
1287 let loc_1: usize = 0;
1291 let loc_2: usize = 1;
1292 let source1 = match &operands[FieldIdx::from_usize(loc_1)] {
1293 Operand::Copy(place) | Operand::Move(place) => {
1294 self.add_varnode(place);
1295 Some(place)
1296 }
1297 _ => None,
1298 };
1299 let op = &operands[FieldIdx::from_usize(loc_2)];
1300 let bop_index = self.oprs.len();
1301
1302 let BI: IntervalType<'_, T>;
1303 if let Operand::Constant(c) = op {
1304 let vbm = self.values_branchmap.get(source1.unwrap()).unwrap();
1305 if block == *vbm.get_bb_true() {
1306 rap_trace!("essa_op true branch{:?}\n", block);
1307 BI = vbm.get_itv_t();
1308 } else {
1309 rap_trace!("essa_op false branch{:?}\n", block);
1310 BI = vbm.get_itv_f();
1311 }
1312 self.usemap
1313 .entry(source1.unwrap())
1314 .or_default()
1315 .insert(bop_index);
1316
1317 let essaop = EssaOp::new(BI, sink, inst, source1.unwrap(), 0, false);
1318 rap_trace!(
1319 "addvar_in_essa_op {:?} from const {:?}\n",
1320 essaop,
1321 source1.unwrap()
1322 );
1323
1324 self.oprs.push(BasicOpKind::Essa(essaop));
1327 self.defmap.insert(sink, bop_index);
1334 } else {
1335 let vbm = self.values_branchmap.get(source1.unwrap()).unwrap();
1336 if block == *vbm.get_bb_true() {
1337 rap_trace!("essa_op true branch{:?}\n", block);
1338 BI = vbm.get_itv_t();
1339 } else {
1340 rap_trace!("essa_op false branch{:?}\n", block);
1341 BI = vbm.get_itv_f();
1342 }
1343 let source2 = match op {
1344 Operand::Copy(place) | Operand::Move(place) => {
1345 self.add_varnode(place);
1346 Some(place)
1347 }
1348 _ => None,
1349 };
1350 self.usemap
1351 .entry(source1.unwrap())
1352 .or_default()
1353 .insert(bop_index);
1354 let essaop = EssaOp::new(BI, sink, inst, source1.unwrap(), 0, true);
1359 rap_trace!(
1361 "addvar_in_essa_op {:?} from {:?}\n",
1362 essaop,
1363 source1.unwrap()
1364 );
1365
1366 self.oprs.push(BasicOpKind::Essa(essaop));
1367 self.defmap.insert(sink, bop_index);
1374 }
1375 }
1376 pub fn add_aggregate_op(
1377 &mut self,
1378 sink: &'tcx Place<'tcx>,
1379 inst: &'tcx Statement<'tcx>,
1380 rvalue: &'tcx Rvalue<'tcx>,
1381 operands: &'tcx IndexVec<FieldIdx, Operand<'tcx>>,
1382 unique_adt: usize,
1383 ) {
1384 rap_trace!("aggregate_op {:?}\n", inst);
1385
1386 let BI: BasicInterval<T> = BasicInterval::new(Range::default(T::min_value()));
1387 let mut agg_operands: Vec<AggregateOperand<'tcx>> = Vec::with_capacity(operands.len());
1388
1389 for operand in operands {
1390 match operand {
1391 Operand::Copy(place) | Operand::Move(place) => {
1392 if sink.local == RETURN_PLACE && sink.projection.is_empty() {
1393 self.rerurn_places.insert(place);
1394 self.add_varnode(sink);
1395 rap_debug!("add_return_place {:?}\n", place);
1396 } else {
1397 self.add_varnode(place);
1398 rap_trace!("addvar_in_aggregate_op {:?}\n", place);
1399 agg_operands.push(AggregateOperand::Place(place));
1400 }
1401 }
1402 Operand::Constant(c) => {
1403 rap_trace!("add_constant_aggregate_op {:?}\n", c);
1404 agg_operands.push(AggregateOperand::Const(c.const_));
1405
1406 let sink_node = self.add_varnode(sink);
1407 if let Some(value) = Self::convert_const(&c.const_) {
1408 sink_node.set_range(Range::new(
1409 value.clone(),
1410 value.clone(),
1411 RangeType::Regular,
1412 ));
1413 rap_trace!("set_const {:?} value: {:?}\n", sink_node, value);
1414 } else {
1415 sink_node.set_range(Range::default(T::min_value()));
1416 }
1417 }
1418 }
1419 }
1420
1421 if agg_operands.is_empty() {
1422 rap_trace!("aggregate_op has no operands, skipping\n");
1423 return;
1424 }
1425
1426 let agg_op = AggregateOp::new(
1427 IntervalType::Basic(BI),
1428 sink,
1429 inst,
1430 agg_operands,
1431 unique_adt,
1432 );
1433 let bop_index = self.oprs.len();
1434 self.oprs.push(BasicOpKind::Aggregate(agg_op));
1435
1436 for operand in operands {
1437 if let Operand::Copy(place) | Operand::Move(place) = operand {
1438 self.usemap.entry(place).or_default().insert(bop_index);
1439 }
1440 }
1441
1442 self.defmap.insert(sink, bop_index);
1443
1444 self.add_varnode(sink);
1445 }
1446
1447 fn add_unary_op(
1448 &mut self,
1449 sink: &'tcx Place<'tcx>,
1450 inst: &'tcx Statement<'tcx>,
1451 rvalue: &'tcx Rvalue<'tcx>,
1452 operand: &'tcx Operand<'tcx>,
1453 op: UnOp,
1454 ) {
1455 rap_trace!("unary_op{:?}\n", inst);
1456
1457 let sink_node = self.add_varnode_sym(sink, rvalue);
1458 rap_trace!("addsink_in_unary_op{:?}\n", sink_node);
1459
1460 let BI: BasicInterval<T> = BasicInterval::new(Range::default(T::min_value()));
1461 let loc_1: usize = 0;
1462
1463 let source = match operand {
1464 Operand::Copy(place) | Operand::Move(place) => {
1465 self.add_varnode(place);
1466 Some(place)
1467 }
1468 _ => None,
1469 };
1470
1471 rap_trace!("addvar_in_unary_op{:?}\n", source.unwrap());
1472 self.add_varnode(&source.unwrap());
1473
1474 let unaryop = UnaryOp::new(IntervalType::Basic(BI), sink, inst, source.unwrap(), op);
1475 let bop_index = self.oprs.len();
1477
1478 self.oprs.push(BasicOpKind::Unary(unaryop));
1479 self.defmap.insert(sink, bop_index);
1482 }
1483
1484 fn add_binary_op(
1485 &mut self,
1486 sink: &'tcx Place<'tcx>,
1487 inst: &'tcx Statement<'tcx>,
1488 rvalue: &'tcx Rvalue<'tcx>,
1489 op1: &'tcx Operand<'tcx>,
1490 op2: &'tcx Operand<'tcx>,
1491 bin_op: BinOp,
1492 ) {
1493 rap_trace!("binary_op{:?}\n", inst);
1494 let sink_node = self.add_varnode_sym(sink, rvalue);
1495 rap_trace!("addsink_in_binary_op{:?}\n", sink_node);
1496 let bop_index = self.oprs.len();
1497 let BI: BasicInterval<T> = BasicInterval::new(Range::default(T::min_value()));
1498
1499 let source1_place = match op1 {
1500 Operand::Copy(place) | Operand::Move(place) => {
1501 self.add_varnode(place);
1502 rap_trace!("addvar_in_binary_op{:?}\n", place);
1503
1504 Some(place)
1505 }
1506 Operand::Constant(_) => None,
1507 };
1508
1509 match op2 {
1510 Operand::Copy(place) | Operand::Move(place) => {
1511 self.add_varnode(place);
1512 rap_trace!("addvar_in_binary_op{:?}\n", place);
1513
1514 let source2_place = Some(place);
1515 let BOP = BinaryOp::new(
1516 IntervalType::Basic(BI),
1517 sink,
1518 inst,
1519 source1_place,
1520 source2_place,
1521 None,
1522 bin_op.clone(),
1523 );
1524 self.oprs.push(BasicOpKind::Binary(BOP));
1525 self.defmap.insert(sink, bop_index);
1527 if let Some(place) = source1_place {
1528 self.usemap.entry(place).or_default().insert(bop_index);
1529 }
1530
1531 if let Some(place) = source2_place {
1532 self.usemap.entry(place).or_default().insert(bop_index);
1533 }
1534 }
1535 Operand::Constant(c) => {
1536 let BOP = BinaryOp::new(
1538 IntervalType::Basic(BI),
1539 sink,
1540 inst,
1541 source1_place,
1542 None,
1543 Some(c.const_),
1544 bin_op.clone(),
1545 );
1546 self.oprs.push(BasicOpKind::Binary(BOP));
1547 self.defmap.insert(sink, bop_index);
1549 if let Some(place) = source1_place {
1550 self.usemap.entry(place).or_default().insert(bop_index);
1551 }
1552 }
1553 };
1554
1555 }
1561 fn add_ref_op(
1562 &mut self,
1563 sink: &'tcx Place<'tcx>,
1564 inst: &'tcx Statement<'tcx>,
1565 rvalue: &'tcx Rvalue<'tcx>,
1566 place: &'tcx Place<'tcx>,
1567 borrowkind: BorrowKind,
1568 ) {
1569 rap_trace!("ref_op {:?}\n", inst);
1570
1571 let BI: BasicInterval<T> = BasicInterval::new(Range::default(T::min_value()));
1572
1573 let source_node = self.add_varnode(place);
1574
1575 let sink_node = self.add_varnode_sym(sink, rvalue);
1576
1577 let refop = RefOp::new(IntervalType::Basic(BI), sink, inst, place, borrowkind);
1578 let bop_index = self.oprs.len();
1579 self.oprs.push(BasicOpKind::Ref(refop));
1580
1581 self.usemap.entry(place).or_default().insert(bop_index);
1582
1583 self.defmap.insert(sink, bop_index);
1584
1585 rap_trace!(
1586 "add_ref_op: created RefOp from {:?} to {:?} at {:?}\n",
1587 place,
1588 sink,
1589 inst
1590 );
1591 }
1592
1593 fn fix_intersects(&mut self, component: &HashSet<&'tcx Place<'tcx>>) {
1594 for &place in component.iter() {
1595 if let Some(sit) = self.symbmap.get_mut(place) {
1597 let node = self.vars.get(place).unwrap();
1598
1599 for &op in sit.iter() {
1600 let op = &mut self.oprs[op];
1601 let sinknode = self.vars.get(op.get_sink()).unwrap();
1602
1603 op.op_fix_intersects(node, sinknode);
1604 }
1605 }
1606 }
1607 }
1608 pub fn widen(
1609 &mut self,
1610 op: usize,
1611 cg_map: &FxHashMap<DefId, Rc<RefCell<ConstraintGraph<'tcx, T>>>>,
1612 vars_map: &mut FxHashMap<DefId, Vec<RefCell<VarNodes<'tcx, T>>>>,
1613 ) -> bool {
1614 let op_kind = &self.oprs[op];
1617 let sink = op_kind.get_sink();
1618 let old_interval = self.vars.get(sink).unwrap().get_range().clone();
1619
1620 let estimated_interval = match op_kind {
1623 BasicOpKind::Call(call_op) => {
1624 call_op.eval_call(&self.vars, cg_map, vars_map)
1626 }
1627 _ => {
1628 op_kind.eval(&self.vars)
1630 }
1631 };
1632 let old_lower = old_interval.get_lower();
1633 let old_upper = old_interval.get_upper();
1634 let new_lower = estimated_interval.get_lower();
1635 let new_upper = estimated_interval.get_upper();
1636 let updated = if old_interval.is_unknown() {
1652 estimated_interval.clone()
1653 } else if new_lower < old_lower && new_upper > old_upper {
1654 Range::new(T::min_value(), T::max_value(), RangeType::Regular)
1655 } else if new_lower < old_lower {
1656 Range::new(T::min_value(), old_upper.clone(), RangeType::Regular)
1657 } else if new_upper > old_upper {
1658 Range::new(old_lower.clone(), T::max_value(), RangeType::Regular)
1659 } else {
1660 old_interval.clone()
1661 };
1662
1663 self.vars.get_mut(sink).unwrap().set_range(updated.clone());
1664 rap_trace!(
1665 "WIDEN in {} set {:?}: E {:?} U {:?} {:?} -> {:?}",
1666 op,
1667 sink,
1668 estimated_interval,
1669 updated,
1670 old_interval,
1671 updated
1672 );
1673
1674 old_interval != updated
1675 }
1676 pub fn narrow(
1677 &mut self,
1678 op: usize,
1679 cg_map: &FxHashMap<DefId, Rc<RefCell<ConstraintGraph<'tcx, T>>>>,
1680 vars_map: &mut FxHashMap<DefId, Vec<RefCell<VarNodes<'tcx, T>>>>,
1681 ) -> bool {
1682 let op_kind = &self.oprs[op];
1683 let sink = op_kind.get_sink();
1684 let old_interval = self.vars.get(sink).unwrap().get_range().clone();
1685
1686 let estimated_interval = match op_kind {
1688 BasicOpKind::Call(call_op) => {
1689 call_op.eval_call(&self.vars, cg_map, vars_map)
1691 }
1692 _ => {
1693 op_kind.eval(&self.vars)
1695 }
1696 };
1697 let old_lower = old_interval.get_lower();
1698 let old_upper = old_interval.get_upper();
1699 let new_lower = estimated_interval.get_lower();
1700 let new_upper = estimated_interval.get_upper();
1701 let mut final_lower = old_lower.clone();
1704 let mut final_upper = old_upper.clone();
1705 if old_lower.clone() == T::min_value() && new_lower.clone() > T::min_value() {
1706 final_lower = new_lower.clone();
1707 } else if old_lower.clone() <= new_lower.clone() {
1710 final_lower = new_lower.clone();
1711
1712 };
1715 if old_upper.clone() == T::max_value() && new_upper.clone() < T::max_value() {
1716 final_upper = new_upper.clone();
1717 } else if old_upper.clone() >= new_upper.clone() {
1720 final_upper = new_upper.clone();
1721 }
1724 let tightened = Range::new(final_lower, final_upper, RangeType::Regular);
1725
1726 self.vars
1727 .get_mut(sink)
1728 .unwrap()
1729 .set_range(tightened.clone());
1730 rap_trace!(
1731 "NARROW in {} set {:?}: E {:?} U {:?} {:?} -> {:?}",
1732 op,
1733 sink,
1734 estimated_interval,
1735 tightened,
1736 old_interval,
1737 tightened
1738 );
1739 let hasChanged = old_interval != tightened;
1740
1741 hasChanged
1742 }
1743
1744 fn pre_update(
1745 &mut self,
1746 comp_use_map: &HashMap<&'tcx Place<'tcx>, HashSet<usize>>,
1747 entry_points: &HashSet<&'tcx Place<'tcx>>,
1748 cg_map: &FxHashMap<DefId, Rc<RefCell<ConstraintGraph<'tcx, T>>>>,
1749 vars_map: &mut FxHashMap<DefId, Vec<RefCell<VarNodes<'tcx, T>>>>,
1750 ) {
1751 let mut worklist: Vec<&'tcx Place<'tcx>> = entry_points.iter().cloned().collect();
1752
1753 while let Some(place) = worklist.pop() {
1754 if let Some(op_set) = comp_use_map.get(place) {
1755 for &op in op_set {
1756 if self.widen(op, cg_map, vars_map) {
1757 let sink = self.oprs[op].get_sink();
1758 rap_trace!("W {:?}\n", sink);
1759 worklist.push(sink);
1761 }
1762 }
1763 }
1764 }
1765 }
1766
1767 fn pos_update(
1768 &mut self,
1769 comp_use_map: &HashMap<&'tcx Place<'tcx>, HashSet<usize>>,
1770 entry_points: &HashSet<&'tcx Place<'tcx>>,
1771 cg_map: &FxHashMap<DefId, Rc<RefCell<ConstraintGraph<'tcx, T>>>>,
1772 vars_map: &mut FxHashMap<DefId, Vec<RefCell<VarNodes<'tcx, T>>>>,
1773 ) {
1774 let mut worklist: Vec<&'tcx Place<'tcx>> = entry_points.iter().cloned().collect();
1775 let mut iteration = 0;
1776 while let Some(place) = worklist.pop() {
1777 iteration += 1;
1778 if (iteration > 1000) {
1779 rap_trace!("Iteration limit reached, breaking out of pos_update\n");
1780 break;
1781 }
1782
1783 if let Some(op_set) = comp_use_map.get(place) {
1784 for &op in op_set {
1785 if self.narrow(op, cg_map, vars_map) {
1786 let sink = self.oprs[op].get_sink();
1787 rap_trace!("N {:?}\n", sink);
1788
1789 worklist.push(sink);
1791 }
1792 }
1793 }
1794 }
1795 rap_trace!("pos_update finished after {} iterations\n", iteration);
1796 }
1797 fn generate_active_vars(
1798 &mut self,
1799 component: &HashSet<&'tcx Place<'tcx>>,
1800 active_vars: &mut HashSet<&'tcx Place<'tcx>>,
1801 cg_map: &FxHashMap<DefId, Rc<RefCell<ConstraintGraph<'tcx, T>>>>,
1802 vars_map: &mut FxHashMap<DefId, Vec<RefCell<VarNodes<'tcx, T>>>>,
1803 ) {
1804 for place in component {
1805 let node = self.vars.get(place).unwrap();
1806 }
1807 }
1808 fn generate_entry_points(
1809 &mut self,
1810 component: &HashSet<&'tcx Place<'tcx>>,
1811 entry_points: &mut HashSet<&'tcx Place<'tcx>>,
1812 cg_map: &FxHashMap<DefId, Rc<RefCell<ConstraintGraph<'tcx, T>>>>,
1813 vars_map: &mut FxHashMap<DefId, Vec<RefCell<VarNodes<'tcx, T>>>>,
1814 ) {
1815 for &place in component {
1816 let op = self.defmap.get(place).unwrap();
1817 if let BasicOpKind::Essa(essaop) = &mut self.oprs[*op] {
1818 if essaop.is_unresolved() {
1819 let source = essaop.get_source();
1820 let new_range = essaop.eval(&self.vars);
1821 let sink_node = self.vars.get_mut(source).unwrap();
1822 sink_node.set_range(new_range);
1823 }
1824 essaop.mark_resolved();
1825 }
1826 if (!self.vars[place].get_range().is_unknown()) {
1827 entry_points.insert(place);
1828 }
1829 }
1830 }
1831 fn propagate_to_next_scc(
1832 &mut self,
1833 component: &HashSet<&'tcx Place<'tcx>>,
1834 cg_map: &FxHashMap<DefId, Rc<RefCell<ConstraintGraph<'tcx, T>>>>,
1835 vars_map: &mut FxHashMap<DefId, Vec<RefCell<VarNodes<'tcx, T>>>>,
1836 ) {
1837 for &place in component.iter() {
1838 let node = self.vars.get_mut(place).unwrap();
1839 for &op in self.usemap.get(place).unwrap().iter() {
1840 let op_kind = &mut self.oprs[op];
1841 let sink = op_kind.get_sink();
1842 if !component.contains(sink) {
1843 let new_range = op_kind.eval(&self.vars);
1844 let new_range = match op_kind {
1845 BasicOpKind::Call(call_op) => {
1846 call_op.eval_call(&self.vars, cg_map, vars_map)
1847 }
1848 _ => {
1849 op_kind.eval(&self.vars)
1851 }
1852 };
1853 let sink_node = self.vars.get_mut(sink).unwrap();
1854 rap_trace!(
1855 "prop component {:?} set {:?} to {:?} through {:?}\n",
1856 component,
1857 new_range,
1858 sink,
1859 op_kind.get_instruction()
1860 );
1861 sink_node.set_range(new_range);
1862 if let BasicOpKind::Essa(essaop) = op_kind {
1867 if essaop.get_intersect().get_range().is_unknown() {
1868 essaop.mark_unresolved();
1869 }
1870 }
1871 }
1872 }
1873 }
1874 }
1875 pub fn solve_const_func_call(
1876 &mut self,
1877 cg_map: &FxHashMap<DefId, Rc<RefCell<ConstraintGraph<'tcx, T>>>>,
1878 vars_map: &mut FxHashMap<DefId, Vec<RefCell<VarNodes<'tcx, T>>>>,
1879 ) {
1880 for (&sink, op) in &self.const_func_place {
1881 rap_trace!(
1882 "solve_const_func_call for sink {:?} with opset {:?}\n",
1883 sink,
1884 op
1885 );
1886 if let BasicOpKind::Call(call_op) = &self.oprs[*op] {
1887 let new_range = call_op.eval_call(&self.vars, cg_map, vars_map);
1888 rap_trace!("Setting range for {:?} to {:?}\n", sink, new_range);
1889 self.vars.get_mut(sink).unwrap().set_range(new_range);
1890 }
1891 }
1892 }
1893 pub fn store_vars(&mut self, varnodes_vec: &mut Vec<RefCell<VarNodes<'tcx, T>>>) {
1894 rap_trace!("Storing vars\n");
1895 let old_vars = self.vars.clone();
1896 varnodes_vec.push(RefCell::new(old_vars));
1897 }
1898 pub fn reset_vars(&mut self, varnodes_vec: &mut Vec<RefCell<VarNodes<'tcx, T>>>) {
1899 rap_trace!("Resetting vars\n");
1900 self.vars = varnodes_vec[0].borrow_mut().clone();
1901 }
1902 pub fn find_intervals(
1903 &mut self,
1904 cg_map: &FxHashMap<DefId, Rc<RefCell<ConstraintGraph<'tcx, T>>>>,
1905 vars_map: &mut FxHashMap<DefId, Vec<RefCell<VarNodes<'tcx, T>>>>,
1906 ) {
1907 self.solve_const_func_call(cg_map, vars_map);
1911 self.numSCCs = self.worklist.len();
1912 let mut seen = HashSet::new();
1913 let mut components = Vec::new();
1914
1915 for &place in self.worklist.iter().rev() {
1916 if seen.contains(place) {
1917 continue;
1918 }
1919
1920 if let Some(component) = self.components.get(place) {
1921 for &p in component {
1922 seen.insert(p);
1923 }
1924
1925 components.push(component.clone());
1926 }
1927 }
1928 rap_trace!("TOLO:{:?}\n", components);
1929
1930 for component in components {
1931 rap_trace!("===start component {:?}===\n", component);
1932 if component.len() == 1 {
1933 self.numAloneSCCs += 1;
1934
1935 self.fix_intersects(&component);
1936
1937 let variable: &Place<'tcx> = *component.iter().next().unwrap();
1938 let varnode = self.vars.get_mut(variable).unwrap();
1939 if varnode.get_range().is_unknown() {
1940 varnode.set_default();
1941 }
1942 } else {
1943 let comp_use_map = self.build_use_map(&component);
1945 let mut entry_points = HashSet::new();
1947 self.generate_entry_points(&component, &mut entry_points, cg_map, vars_map);
1950 rap_trace!("entry_points {:?} \n", entry_points);
1951 self.pre_update(&comp_use_map, &entry_points, cg_map, vars_map);
1953 self.fix_intersects(&component);
1954
1955 let mut active_vars = HashSet::new();
1963 self.generate_active_vars(&component, &mut active_vars, cg_map, vars_map);
1964 self.pos_update(&comp_use_map, &entry_points, cg_map, vars_map);
1965 }
1966 self.propagate_to_next_scc(&component, cg_map, vars_map);
1967 }
1968 self.merge_return_places();
1969 let Some(varnodes_vec) = vars_map.get_mut(&self.self_def_id) else {
1970 rap_trace!(
1971 "No variable map entry for this function {:?}, skipping Nuutila\n",
1972 self.self_def_id
1973 );
1974 return;
1975 };
1976 self.store_vars(varnodes_vec);
1977 }
1978 pub fn merge_return_places(&mut self) {
1979 rap_trace!("====Merging return places====\n");
1980 for &place in self.rerurn_places.iter() {
1981 rap_debug!("merging return place {:?}\n", place);
1982 let mut merged_range = Range::default(T::min_value());
1983 if let Some(opset) = self.vars.get(place) {
1984 merged_range = merged_range.unionwith(opset.get_range());
1985 }
1986 if let Some(return_node) = self.vars.get_mut(&Place::return_place()) {
1987 rap_debug!("Assigning final merged range {:?} to _0", merged_range);
1988 return_node.set_range(merged_range);
1989 } else {
1990 rap_trace!(
1994 "Warning: RETURN_PLACE (_0) not found in self.vars. Cannot assign merged return range."
1995 );
1996 }
1997 }
1998 }
1999
2000 pub fn add_control_dependence_edges(&mut self) {
2001 rap_trace!("====Add control dependence edges====\n");
2002 self.print_symbmap();
2003 for (&place, opset) in self.symbmap.iter() {
2004 for &op in opset.iter() {
2005 let bop_index = self.oprs.len();
2006 let opkind = &self.oprs[op];
2007 let control_edge = ControlDep::new(
2008 IntervalType::Basic(BasicInterval::default()),
2009 opkind.get_sink(),
2010 opkind.get_instruction().unwrap(),
2011 place,
2012 );
2013 rap_trace!(
2014 "Adding control_edge {:?} for place {:?} at index {}\n",
2015 control_edge,
2016 place,
2017 bop_index
2018 );
2019 self.oprs.push(BasicOpKind::ControlDep(control_edge));
2020 self.usemap.entry(place).or_default().insert(bop_index);
2021 }
2022 }
2023 }
2024 pub fn del_control_dependence_edges(&mut self) {
2025 rap_trace!("====Delete control dependence edges====\n");
2026
2027 let mut remove_from = self.oprs.len();
2028 while remove_from > 0 {
2029 match &self.oprs[remove_from - 1] {
2030 BasicOpKind::ControlDep(dep) => {
2031 let place = dep.source;
2032 rap_trace!(
2033 "removing control_edge at idx {}: {:?}\n",
2034 remove_from - 1,
2035 dep
2036 );
2037 if let Some(set) = self.usemap.get_mut(&place) {
2038 set.remove(&(remove_from - 1));
2039 if set.is_empty() {
2040 self.usemap.remove(&place);
2041 }
2042 }
2043 remove_from -= 1;
2044 }
2045 _ => break,
2046 }
2047 }
2048
2049 self.oprs.truncate(remove_from);
2050 }
2051
2052 pub fn build_nuutila(&mut self, single: bool) {
2053 rap_trace!("====Building Nuutila====\n");
2054 self.build_symbolic_intersect_map();
2055
2056 if single {
2057 } else {
2058 for place in self.vars.keys().copied() {
2059 self.dfs.insert(place, -1);
2060 }
2061
2062 self.add_control_dependence_edges();
2063
2064 let places: Vec<_> = self.vars.keys().copied().collect();
2065 rap_trace!("places{:?}\n", places);
2066 for place in places {
2067 if self.dfs[&place] < 0 {
2068 rap_trace!("start place{:?}\n", place);
2069 let mut stack = Vec::new();
2070 self.visit(place, &mut stack);
2071 }
2072 }
2073
2074 self.del_control_dependence_edges();
2075 }
2076 rap_trace!("components{:?}\n", self.components);
2077 rap_trace!("worklist{:?}\n", self.worklist);
2078 rap_trace!("dfs{:?}\n", self.dfs);
2079 }
2080 pub fn visit(&mut self, place: &'tcx Place<'tcx>, stack: &mut Vec<&'tcx Place<'tcx>>) {
2081 self.dfs.entry(place).and_modify(|v| *v = self.index);
2082 self.index += 1;
2083 self.root.insert(place, place);
2084 let uses = self.usemap.get(place).unwrap().clone();
2085 for op in uses {
2086 let name = self.oprs[op].get_sink();
2087 rap_trace!("place {:?} get name{:?}\n", place, name);
2088 if self.dfs.get(name).copied().unwrap_or(-1) < 0 {
2089 self.visit(name, stack);
2090 }
2091
2092 if (!self.in_component.contains(name)
2093 && self.dfs[self.root[place]] >= self.dfs[self.root[name]])
2094 {
2095 *self.root.get_mut(place).unwrap() = self.root.get(name).copied().unwrap();
2096
2097 }
2099 }
2100
2101 if self.root.get(place).copied().unwrap() == place {
2102 self.worklist.push_back(place);
2103
2104 let mut scc = HashSet::new();
2105 scc.insert(place);
2106
2107 self.in_component.insert(place);
2108
2109 while let Some(top) = stack.last() {
2110 if self.dfs.get(top).copied().unwrap_or(-1) > self.dfs.get(place).copied().unwrap()
2111 {
2112 let node = stack.pop().unwrap();
2113 self.in_component.insert(node);
2114
2115 scc.insert(node);
2116 } else {
2117 break;
2118 }
2119 }
2120
2121 self.components.insert(place, scc);
2122 } else {
2123 stack.push(place);
2124 }
2125 }
2126
2127 pub fn start_analyze_path_constraints(
2128 &mut self,
2129 body: &'tcx Body<'tcx>,
2130 all_paths_indices: &[Vec<usize>],
2131 ) -> HashMap<Vec<usize>, Vec<(Place<'tcx>, Place<'tcx>, BinOp)>> {
2132 self.build_value_maps(body);
2133 let result = self.analyze_path_constraints(body, all_paths_indices);
2134 result
2135 }
2136
2137 pub fn analyze_path_constraints(
2138 &self,
2139 body: &'tcx Body<'tcx>,
2140 all_paths_indices: &[Vec<usize>],
2141 ) -> HashMap<Vec<usize>, Vec<(Place<'tcx>, Place<'tcx>, BinOp)>> {
2142 let mut all_path_results: HashMap<Vec<usize>, Vec<(Place<'tcx>, Place<'tcx>, BinOp)>> =
2143 HashMap::with_capacity(all_paths_indices.len());
2144
2145 for path_indices in all_paths_indices {
2146 let mut current_path_constraints: Vec<(Place<'tcx>, Place<'tcx>, BinOp)> = Vec::new();
2147
2148 let path_bbs: Vec<BasicBlock> = path_indices
2149 .iter()
2150 .map(|&idx| BasicBlock::from_usize(idx))
2151 .collect();
2152
2153 for window in path_bbs.windows(2) {
2154 let current_bb = window[0];
2155
2156 if self.switchbbs.contains_key(¤t_bb) {
2157 let next_bb = window[1];
2158 let current_bb_data = &body[current_bb];
2159
2160 if let Some(Terminator {
2161 kind: TerminatorKind::SwitchInt { discr, .. },
2162 ..
2163 }) = ¤t_bb_data.terminator
2164 {
2165 let (constraint_place_1, constraint_place_2) =
2166 self.switchbbs.get(¤t_bb).unwrap();
2167 if let Some(vbm) = self.values_branchmap.get(constraint_place_1) {
2168 let relevant_interval_opt = if next_bb == *vbm.get_bb_true() {
2169 Some(vbm.get_itv_t())
2170 } else if next_bb == *vbm.get_bb_false() {
2171 Some(vbm.get_itv_f())
2172 } else {
2173 None
2174 };
2175
2176 if let Some(relevant_interval) = relevant_interval_opt {
2177 match relevant_interval {
2178 IntervalType::Basic(basic_interval) => {}
2179 IntervalType::Symb(symb_interval) => {
2180 current_path_constraints.push((
2181 constraint_place_1.clone(),
2182 constraint_place_2.clone(),
2183 symb_interval.get_operation().clone(),
2184 ));
2185 }
2186 }
2187 }
2188 }
2189 }
2190 }
2191 }
2192
2193 all_path_results.insert(path_indices.clone(), (current_path_constraints));
2194 }
2195
2196 all_path_results
2197 }
2198}
2199#[derive(Debug)]
2200pub struct Nuutila<'tcx, T: IntervalArithmetic + ConstConvert + Debug> {
2201 pub variables: &'tcx VarNodes<'tcx, T>,
2202 pub index: i32,
2203 pub dfs: HashMap<&'tcx Place<'tcx>, i32>,
2204 pub root: HashMap<&'tcx Place<'tcx>, &'tcx Place<'tcx>>,
2205 pub in_component: HashSet<&'tcx Place<'tcx>>,
2206 pub components: HashMap<&'tcx Place<'tcx>, HashSet<&'tcx Place<'tcx>>>,
2207 pub worklist: VecDeque<&'tcx Place<'tcx>>,
2208 }
2210
2211impl<'tcx, T> Nuutila<'tcx, T>
2212where
2213 T: IntervalArithmetic + ConstConvert + Debug,
2214{
2215 pub fn new(
2216 varNodes: &'tcx VarNodes<'tcx, T>,
2217 use_map: &'tcx UseMap<'tcx>,
2218 symb_map: &'tcx SymbMap<'tcx>,
2219 single: bool,
2220 oprs: &'tcx Vec<BasicOpKind<'tcx, T>>,
2221 ) -> Self {
2222 let mut n: Nuutila<'_, T> = Nuutila {
2223 variables: varNodes,
2224 index: 0,
2225 dfs: HashMap::new(),
2226 root: HashMap::new(),
2227 in_component: HashSet::new(),
2228 components: HashMap::new(),
2229 worklist: std::collections::VecDeque::new(),
2230 };
2232
2233 if single {
2234 } else {
2247 for place in n.variables.keys().copied() {
2248 n.dfs.insert(place, -1);
2249 }
2250
2251 n.add_control_dependence_edges(symb_map, use_map, varNodes);
2252
2253 for place in n.variables.keys() {
2254 if n.dfs[place] < 0 {
2255 let mut stack = Vec::new();
2256 n.visit(place, &mut stack, use_map, oprs);
2257 }
2258 }
2259
2260 }
2262
2263 n
2264 }
2265
2266 pub fn visit(
2267 &mut self,
2268 place: &'tcx Place<'tcx>,
2269 stack: &mut Vec<&'tcx Place<'tcx>>,
2270 use_map: &'tcx UseMap<'tcx>,
2271 oprs: &'tcx Vec<BasicOpKind<'tcx, T>>,
2272 ) {
2273 self.dfs.entry(place).and_modify(|v| *v = self.index);
2274 self.index += 1;
2275 self.root.insert(place, place);
2276
2277 if let Some(uses) = use_map.get(place) {
2278 for op in uses {
2279 let name = oprs[*op].get_sink();
2280
2281 if self.dfs.get(name).copied().unwrap_or(-1) < 0 {
2282 self.visit(name, stack, use_map, oprs);
2283 }
2284
2285 if (!self.in_component.contains(name)
2286 && self.dfs[self.root[place]] >= self.dfs[self.root[name]])
2287 {
2288 *self.root.get_mut(place).unwrap() = self.root.get(name).copied().unwrap();
2289
2290 }
2292 }
2293 }
2294
2295 if self.root.get(place).copied().unwrap() == place {
2296 self.worklist.push_back(place);
2297
2298 let mut scc = HashSet::new();
2299 scc.insert(place);
2300
2301 self.in_component.insert(place);
2302
2303 while let Some(&top) = stack.last() {
2304 if self.dfs.get(top).copied().unwrap_or(-1) > self.dfs.get(place).copied().unwrap()
2305 {
2306 let node = stack.pop().unwrap();
2307 self.in_component.insert(node);
2308
2309 scc.insert(node);
2310 } else {
2311 break;
2312 }
2313 }
2314
2315 self.components.insert(place, scc);
2316 } else {
2317 stack.push(place);
2318 }
2319 }
2320
2321 pub fn add_control_dependence_edges(
2322 &mut self,
2323 _symb_map: &'tcx SymbMap<'tcx>,
2324 _use_map: &'tcx UseMap<'tcx>,
2325 _vars: &'tcx VarNodes<'tcx, T>,
2326 ) {
2327 todo!()
2328 }
2329
2330 pub fn del_control_dependence_edges(&mut self, _use_map: &'tcx mut UseMap<'tcx>) {
2331 todo!()
2332 }
2333}