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 writeln!(&mut dot, " layout=neato;").unwrap();
178 writeln!(&mut dot, " overlap=false;").unwrap();
179 writeln!(&mut dot, " splines=true;").unwrap();
180 writeln!(&mut dot, " sep=\"+1.0\";").unwrap();
181 writeln!(&mut dot, " rankdir=TB;").unwrap();
182 writeln!(&mut dot, " ranksep=1.8;").unwrap();
183 writeln!(&mut dot, " nodesep=0.8;").unwrap();
184 writeln!(&mut dot, " edge [len=2.0];").unwrap();
185 writeln!(&mut dot, " node [fontname=\"Fira Code\"];").unwrap();
186 writeln!(&mut dot, "\n // Variable Nodes").unwrap();
187 writeln!(&mut dot, " subgraph cluster_vars {{").unwrap();
188 writeln!(&mut dot, " rank=same;").unwrap();
189 for (place, var_node) in &self.vars {
190 let place_id = format!("{:?}", place);
191 let label = format!("{:?}", place);
192 writeln!(
193 &mut dot,
194 " \"{}\" [label=\"{}\", shape=ellipse, style=filled, fillcolor=lightblue, width=1.2, fixedsize=false];",
195 place_id, label
196 ).unwrap();
197 }
198 writeln!(&mut dot, " }}").unwrap();
199
200 writeln!(&mut dot, "\n // Operation Nodes").unwrap();
201 writeln!(&mut dot, " subgraph cluster_ops {{").unwrap();
202 writeln!(&mut dot, " rank=same;").unwrap();
203 for (op_idx, op) in self.oprs.iter().enumerate() {
204 let op_id = format!("op_{}", op_idx);
205 let label = match op {
206 BasicOpKind::Unary(o) => format!("Unary({:?})", o.op),
207 BasicOpKind::Binary(o) => format!("Binary({:?})", o.op),
208 BasicOpKind::Essa(_) => "Essa".to_string(),
209 BasicOpKind::ControlDep(_) => "ControlDep".to_string(),
210 BasicOpKind::Phi(_) => "Φ (Phi)".to_string(),
211 BasicOpKind::Use(_) => "Use".to_string(),
212 BasicOpKind::Call(c) => format!("Call({:?})", c.def_id),
213 BasicOpKind::Ref(r) => format!("Ref({:?})", r.borrowkind),
214 BasicOpKind::Aggregate(r) => format!("AggregateOp({:?})", r.unique_adt),
215 };
216 writeln!(
217 &mut dot,
218 " \"{}\" [label=\"{}\", shape=box, style=filled, fillcolor=lightgrey, width=1.5, fixedsize=false];",
219 op_id, label
220 ).unwrap();
221 }
222 writeln!(&mut dot, " }}").unwrap();
223
224 writeln!(&mut dot, "\n // Definition Edges (op -> var)").unwrap();
226 for (place, op_idx) in &self.defmap {
227 writeln!(&mut dot, " \"op_{}\" -> \"{:?}\";", op_idx, place).unwrap();
228 }
229
230 writeln!(&mut dot, "\n // Use Edges (var -> op)").unwrap();
231 for (place, op_indices) in &self.usemap {
232 for op_idx in op_indices {
233 writeln!(&mut dot, " \"{:?}\" -> \"op_{}\";", place, op_idx).unwrap();
234 }
235 }
236
237 writeln!(&mut dot, "\n // Symbolic Bound Edges (var -> op)").unwrap();
238 for (place, op_indices) in &self.symbmap {
239 for op_idx in op_indices {
240 writeln!(
241 &mut dot,
242 " \"{:?}\" -> \"op_{}\" [color=blue, style=dashed];",
243 place, op_idx
244 )
245 .unwrap();
246 }
247 }
248
249 writeln!(&mut dot, "}}").unwrap();
250 dot
251 }
252
253 pub fn build_final_vars(
254 &mut self,
255 places_map: &HashMap<Place<'tcx>, HashSet<Place<'tcx>>>,
256 ) -> (VarNodes<'tcx, T>, Vec<Place<'tcx>>) {
257 let mut final_vars: VarNodes<'tcx, T> = HashMap::new();
258 let mut not_found: Vec<Place<'tcx>> = Vec::new();
259
260 for (&_key_place, place_set) in places_map {
261 for &place in place_set {
262 let found = self.vars.iter().find(|&(&p, _)| *p == place);
263
264 if let Some((&found_place, var_node)) = found {
265 final_vars.insert(found_place, var_node.clone());
266 } else {
267 not_found.push(place);
268 }
269 }
270 }
271 self.final_vars = final_vars.clone();
272 (final_vars, not_found)
273 }
274 pub fn filter_final_vars(
275 vars: &VarNodes<'tcx, T>,
276 places_map: &HashMap<Place<'tcx>, HashSet<Place<'tcx>>>,
277 ) -> HashMap<Place<'tcx>, Range<T>> {
278 let mut final_vars = HashMap::new();
279
280 for (&_key_place, place_set) in places_map {
281 for &place in place_set {
282 if let Some(var_node) = vars.get(&place) {
283 final_vars.insert(place, var_node.get_range().clone());
284 }
285 }
286 }
287 final_vars
288 }
289 pub fn test_and_print_all_symbolic_expressions(&self) {
290 rap_info!("\n==== Testing and Printing All Symbolic Expressions ====");
291
292 let mut places: Vec<&'tcx Place<'tcx>> = self.vars.keys().copied().collect();
293 places.sort_by_key(|p| p.local.as_usize());
294
295 for place in places {
296 rap_info!("--- Place: {:?}", place);
297 }
306 rap_info!("==== End of Symbolic Expression Test ====\n");
307 }
308 pub fn rap_print_final_vars(&self) {
309 for (&key, value) in &self.final_vars {
310 rap_debug!("Var: {:?}, {:?} ", key, value.get_range());
311 }
312 }
313 pub fn rap_print_vars(&self) {
314 for (&key, value) in &self.vars {
315 rap_trace!("Var: {:?}. {:?} ", key, value.get_range());
316 }
317 }
318 pub fn print_vars(&self) {
319 for (&key, value) in &self.vars {
320 rap_trace!("Var: {:?}. {:?} ", key, value.get_range());
321 }
322 }
323 pub fn print_conponent_vars(&self) {
324 rap_trace!("====print_conponent_vars====");
325 for (key, value) in &self.components {
326 if value.len() > 1 {
327 rap_trace!("component: {:?} ", key);
328 for v in value {
329 if let Some(var_node) = self.vars.get(v) {
330 rap_trace!("Var: {:?}. {:?} ", v, var_node.get_range());
331 } else {
332 rap_trace!("Var: {:?} not found", v);
333 }
334 }
335 }
336 }
337 }
338 fn print_values_branchmap(&self) {
339 for (&key, value) in &self.values_branchmap {
340 rap_info!("vbm place: {:?}. {:?}\n ", key, value);
341 }
342 }
343 fn print_symbmap(&self) {
344 for (&key, value) in &self.symbmap {
345 for op in value.iter() {
346 if let Some(op) = self.oprs.get(*op) {
347 rap_trace!("symbmap op: {:?}. {:?}\n ", key, op);
348 } else {
349 rap_trace!("symbmap op: {:?} not found\n ", op);
350 }
351 }
352 }
353 }
354 fn print_defmap(&self) {
355 for (key, value) in self.defmap.clone() {
356 rap_trace!(
357 "place: {:?} def in stmt:{:?} {:?}",
358 key,
359 self.oprs[value].get_type_name(),
360 self.oprs[value].get_instruction()
361 );
362 }
363 }
364 fn print_compusemap(
365 &self,
366 component: &HashSet<&'tcx Place<'tcx>>,
367 comp_use_map: &HashMap<&'tcx Place<'tcx>, HashSet<usize>>,
368 ) {
369 for (key, value) in comp_use_map.clone() {
370 if component.contains(key) {
371 for v in value {
372 rap_trace!(
373 "compusemap place: {:?} use in stmt:{:?} {:?}",
374 key,
375 self.oprs[v].get_type_name(),
376 self.oprs[v].get_instruction()
377 );
378 }
379 }
380 }
381 }
382 fn print_usemap(&self) {
383 for (key, value) in self.usemap.clone() {
384 for v in value {
385 rap_trace!(
386 "place: {:?} use in stmt:{:?} {:?}",
387 key,
388 self.oprs[v].get_type_name(),
389 self.oprs[v].get_instruction()
390 );
391 }
392 }
393 }
394 fn print_symbexpr(&self) {
395 let mut vars: Vec<_> = self.vars.iter().collect();
396
397 vars.sort_by_key(|(local, _)| local.local.index());
398
399 for (&local, value) in vars {
400 rap_info!(
401 "Var: {:?}. [ {:?} , {:?} ]",
402 local,
403 value.interval.get_lower_expr(),
404 value.interval.get_upper_expr()
405 );
406 }
407 }
408 pub fn get_vars(&self) -> &VarNodes<'tcx, T> {
419 &self.vars
420 }
421 pub fn get_field_place(&self, adt_place: Place<'tcx>, field_index: FieldIdx) -> Place<'tcx> {
422 let adt_ty = adt_place.ty(&self.body.local_decls, self.tcx).ty;
423 let field_ty = match adt_ty.kind() {
424 ty::TyKind::Adt(adt_def, substs) => {
425 let variant_def = adt_def.variants().iter().next().unwrap();
427
428 let field_def = &variant_def.fields[field_index];
430
431 field_def.ty(self.tcx, substs)
434 }
435 _ => {
436 panic!("get_field_place expected an ADT, but found {:?}", adt_ty);
437 }
438 };
439
440 let mut new_projection = adt_place.projection.to_vec();
441 new_projection.push(ProjectionElem::Field(field_index, field_ty));
442
443 let new_place = Place {
444 local: adt_place.local,
445 projection: self.tcx.mk_place_elems(&new_projection),
446 };
447 new_place
448 }
449 pub fn add_varnode(&mut self, v: &'tcx Place<'tcx>) -> &mut VarNode<'tcx, T> {
450 let local_decls = &self.body.local_decls;
451
452 let node = VarNode::new(v);
453 let node_ref: &mut VarNode<'tcx, T> = self
454 .vars
455 .entry(v)
456 .or_insert(node);
458 self.usemap.entry(v).or_insert(HashSet::new());
459
460 let ty = local_decls[v.local].ty;
461 let place_ty = v.ty(local_decls, self.tcx);
462
463 if v.projection.is_empty() || self.defmap.contains_key(v) {
464 return node_ref;
465 }
466
467 if !v.projection.is_empty() {
468 let matches: Vec<(_, _)> = self
506 .defmap
507 .iter()
508 .filter(|(p, _)| p.local == v.local && p.projection.is_empty())
509 .map(|(p, def_op)| (*p, *def_op))
510 .collect();
511
512 for (base_place, def_op) in matches {
513 let mut v_op = self.oprs[def_op].clone();
514 v_op.set_sink(v);
515
516 for source in v_op.get_sources() {
517 self.usemap
518 .entry(source)
519 .or_insert(HashSet::new())
520 .insert(self.oprs.len());
521 }
522
523 self.oprs.push(v_op);
524 self.defmap.insert(v, self.oprs.len() - 1);
525 }
526 }
527
528 node_ref
529 }
530 pub fn use_add_varnode_sym(
531 &mut self,
532 v: &'tcx Place<'tcx>,
533 rvalue: &'tcx Rvalue<'tcx>,
534 ) -> &mut VarNode<'tcx, T> {
535 if !self.vars.contains_key(v) {
536 let mut place_ctx: Vec<&Place<'tcx>> = self.vars.keys().map(|p| *p).collect();
537 let node = VarNode::new_symb(v, SymbExpr::from_rvalue(rvalue, place_ctx.clone()));
538 rap_debug!("use node:{:?}", node);
539
540 self.vars.insert(v, node);
541 self.usemap.entry(v).or_insert(HashSet::new());
542
543 if !(v.projection.is_empty() || self.defmap.contains_key(v)) {
544 let matches: Vec<_> = self
545 .defmap
546 .iter()
547 .filter(|(p, _)| p.local == v.local && p.projection.is_empty())
548 .map(|(p, &def_op)| (*p, def_op))
549 .collect();
550
551 for (base_place, def_op) in matches {
552 let mut v_op = self.oprs[def_op].clone();
553 v_op.set_sink(v);
554
555 for source in v_op.get_sources() {
556 self.usemap
557 .entry(source)
558 .or_insert(HashSet::new())
559 .insert(self.oprs.len());
560 }
561
562 self.oprs.push(v_op);
563 self.defmap.insert(v, self.oprs.len() - 1);
564 }
565 }
566 }
567
568 self.vars.get_mut(v).unwrap()
569 }
570
571 pub fn def_add_varnode_sym(
572 &mut self,
573 v: &'tcx Place<'tcx>,
574 rvalue: &'tcx Rvalue<'tcx>,
575 ) -> &mut VarNode<'tcx, T> {
576 let mut place_ctx: Vec<&Place<'tcx>> = self.vars.keys().map(|p| *p).collect();
577
578 let local_decls = &self.body.local_decls;
579 let node = VarNode::new_symb(v, SymbExpr::from_rvalue(rvalue, place_ctx.clone()));
580 rap_debug!("def node:{:?}", node);
581 let node_ref: &mut VarNode<'tcx, T> = self
582 .vars
583 .entry(v)
584 .and_modify(|old| *old = node.clone())
585 .or_insert(node);
586 self.usemap.entry(v).or_insert(HashSet::new());
587
588 let ty = local_decls[v.local].ty;
589 let place_ty = v.ty(local_decls, self.tcx);
590
591 if v.projection.is_empty() || self.defmap.contains_key(v) {
592 return node_ref;
593 }
594
595 if !v.projection.is_empty() {
596 let matches: Vec<(_, _)> = self
597 .defmap
598 .iter()
599 .filter(|(p, _)| p.local == v.local && p.projection.is_empty())
600 .map(|(p, &def_op)| (*p, def_op))
601 .collect();
602
603 for (base_place, def_op) in matches {
604 let mut v_op = self.oprs[def_op].clone();
605 v_op.set_sink(v);
606
607 for source in v_op.get_sources() {
608 self.usemap
609 .entry(source)
610 .or_insert(HashSet::new())
611 .insert(self.oprs.len());
612 }
613
614 self.oprs.push(v_op);
615 self.defmap.insert(v, self.oprs.len() - 1);
616 }
617 }
618 node_ref
619 }
620 pub fn resolve_all_symexpr(&mut self) {
621 let lookup_context = self.vars.clone();
622 let mut nodes: Vec<&mut VarNode<'tcx, T>> = self.vars.values_mut().collect();
623 nodes.sort_by(|a, b| a.v.local.as_usize().cmp(&b.v.local.as_usize()));
624 for node in nodes {
625 if let IntervalType::Basic(basic) = &mut node.interval {
626 rap_debug!("======{}=====", node.v.local.as_usize());
627 rap_debug!("Before resolve: lower_expr: {}\n", basic.lower);
628 basic.lower.resolve_lower_bound(&lookup_context);
629 basic.lower.simplify();
630 rap_debug!("After resolve: lower_expr: {}\n", basic.lower);
631 rap_debug!("Before resolve: upper_expr: {}\n", basic.upper);
632 basic.upper.resolve_upper_bound(&lookup_context);
633 basic.upper.simplify();
634
635 rap_debug!("After resolve: upper_expr: {}\n", basic.upper);
636 }
637 }
638 }
639 pub fn postprocess_defmap(&mut self) {
640 for place in self.vars.keys() {
641 if !place.projection.is_empty() {
642 if let Some((&base_place, &base_value)) = self
643 .defmap
644 .iter()
645 .find(|(p, _)| p.local == place.local && p.projection.is_empty())
646 {
647 self.defmap.insert(place, base_value);
648 } else {
649 rap_trace!("postprocess_defmap: No base place found for {:?}", place);
650 }
651 }
652 }
653 }
654 pub fn build_graph(&mut self, body: &'tcx Body<'tcx>) {
675 self.arg_count = body.arg_count;
676 self.build_value_maps(body);
677 for block in body.basic_blocks.indices() {
678 let block_data: &BasicBlockData<'tcx> = &body[block];
679 for statement in block_data.statements.iter() {
682 self.build_operations(statement, block, body);
683 }
684 self.build_terminator(block, block_data.terminator.as_ref().unwrap());
685 }
686 self.resolve_all_symexpr();
688 self.print_vars();
689 self.print_defmap();
690 self.print_usemap();
691 self.print_symbexpr();
692 }
694
695 pub fn build_value_maps(&mut self, body: &'tcx Body<'tcx>) {
696 for bb in body.basic_blocks.indices() {
697 let block_data = &body[bb];
698 if let Some(terminator) = &block_data.terminator {
699 match &terminator.kind {
700 TerminatorKind::SwitchInt { discr, targets } => {
701 if targets.iter().count() == 1 {
702 self.build_value_branch_map(body, discr, targets, bb, block_data);
703 }
704 }
705 TerminatorKind::Goto { target } => {
706 }
708 _ => {
709 }
714 }
715 }
716 }
717 }
720 fn trace_operand_source(
721 &self,
722 body: &'tcx Body<'tcx>,
723 mut current_block: BasicBlock,
724 target_place: Place<'tcx>,
725 ) -> Option<&'tcx Operand<'tcx>> {
726 let mut visited = HashSet::new();
727 let target_local = target_place.local;
728
729 while visited.insert(current_block) {
730 let data = &body.basic_blocks[current_block];
731
732 for stmt in data.statements.iter().rev() {
734 if let StatementKind::Assign(box (lhs, rvalue)) = &stmt.kind {
735 if lhs.local == target_local {
737 rap_debug!(
738 "Tracing source for {:?} in block {:?} {:?}\n",
739 target_place,
740 current_block,
741 rvalue
742 );
743 return match rvalue {
744 Rvalue::Use(op) => Some(op),
747
748 _ => None,
751 };
752 }
753 }
754 }
755
756 let preds = &body.basic_blocks.predecessors()[current_block];
758 if preds.len() == 1 {
759 current_block = preds[0];
760 } else {
761 break;
762 }
763 }
764
765 None
766 }
767 pub fn build_value_branch_map(
768 &mut self,
769 body: &'tcx Body<'tcx>,
770 discr: &'tcx Operand<'tcx>,
771 targets: &'tcx SwitchTargets,
772 switch_block: BasicBlock,
773 block_data: &'tcx BasicBlockData<'tcx>,
774 ) {
775 let first_target = targets.all_targets()[0];
777 let target_data = &body.basic_blocks[first_target];
778
779 if let Operand::Copy(place) | Operand::Move(place) = discr {
780 if let Some((op1, op2, cmp_op)) = self.extract_condition(place, block_data) {
781 rap_debug!(
782 "extract_condition op1:{:?} op2:{:?} cmp_op:{:?}\n",
783 op1,
784 op2,
785 cmp_op
786 );
787 let op1 = if let Some(p1) = op1.place() {
788 self.trace_operand_source(body, switch_block, p1)
789 .unwrap_or(op1)
790 } else {
791 op1
792 };
793
794 let op2 = if let Some(p2) = op2.place() {
795 self.trace_operand_source(body, switch_block, p2)
796 .unwrap_or(op2)
797 } else {
798 op2
799 };
800 rap_debug!(
801 "build_value_branch_map op1:{:?} op2:{:?} cmp_op:{:?}\n",
802 op1,
803 op2,
804 cmp_op
805 );
806 let const_op1 = op1.constant();
807 let const_op2 = op2.constant();
808 match (const_op1, const_op2) {
809 (Some(c1), Some(c2)) => {}
810 (Some(c), None) | (None, Some(c)) => {
811 let const_in_left: bool;
812 let variable;
813 if const_op1.is_some() {
814 const_in_left = true;
815 variable = match op2 {
816 Operand::Copy(p) | Operand::Move(p) => p,
817 _ => panic!("Expected a place"),
818 };
819 } else {
820 const_in_left = false;
821 variable = match op1 {
822 Operand::Copy(p) | Operand::Move(p) => p,
823 _ => panic!("Expected a place"),
824 };
825 }
826 self.add_varnode(variable);
827 rap_trace!("add_vbm_varnode{:?}\n", variable.clone());
828
829 let value = Self::convert_const(&c.const_).unwrap();
831 let const_range =
832 Range::new(value.clone(), value.clone(), RangeType::Unknown);
833 rap_trace!("cmp_op {:?}\n", cmp_op);
834 rap_trace!("const_in_left {:?}\n", const_in_left);
835 let mut true_range =
836 self.apply_comparison(value.clone(), cmp_op, true, const_in_left);
837 let mut false_range =
838 self.apply_comparison(value.clone(), cmp_op, false, const_in_left);
839 true_range.set_regular();
840 false_range.set_regular();
841 let target_vec = targets.all_targets();
844
845 let vbm = ValueBranchMap::new(
846 variable,
847 &target_vec[0],
848 &target_vec[1],
849 IntervalType::Basic(BasicInterval::new(false_range)),
850 IntervalType::Basic(BasicInterval::new(true_range)),
851 );
852 self.values_branchmap.insert(variable, vbm);
853 }
855 (None, None) => {
856 let CR = Range::new(T::min_value(), T::max_value(), RangeType::Unknown);
857
858 let p1 = match op1 {
859 Operand::Copy(p) | Operand::Move(p) => p,
860 _ => panic!("Expected a place"),
861 };
862 let p2 = match op2 {
863 Operand::Copy(p) | Operand::Move(p) => p,
864 _ => panic!("Expected a place"),
865 };
866 let target_vec = targets.all_targets();
867 self.add_varnode(&p1);
868 rap_trace!("add_vbm_varnode{:?}\n", p1.clone());
869
870 self.add_varnode(&p2);
871 rap_trace!("add_vbm_varnode{:?}\n", p2.clone());
872 let flipped_cmp_op = Self::flipped_binop(cmp_op).unwrap();
873 let reversed_cmp_op = Self::reverse_binop(cmp_op).unwrap();
874 let reversed_flippedd_cmp_op =
875 Self::flipped_binop(reversed_cmp_op).unwrap();
876 let STOp1 = IntervalType::Symb(SymbInterval::new(CR.clone(), p2, cmp_op));
877 let SFOp1 =
878 IntervalType::Symb(SymbInterval::new(CR.clone(), p2, flipped_cmp_op));
879 let STOp2 =
880 IntervalType::Symb(SymbInterval::new(CR.clone(), p1, reversed_cmp_op));
881 let SFOp2 = IntervalType::Symb(SymbInterval::new(
882 CR.clone(),
883 p1,
884 reversed_flippedd_cmp_op,
885 ));
886 rap_trace!("SFOp1{:?}\n", SFOp1);
887 rap_trace!("SFOp2{:?}\n", SFOp2);
888 rap_trace!("STOp1{:?}\n", STOp1);
889 rap_trace!("STOp2{:?}\n", STOp2);
890 let vbm_1 =
891 ValueBranchMap::new(p1, &target_vec[0], &target_vec[1], SFOp1, STOp1);
892 let vbm_2 =
893 ValueBranchMap::new(p2, &target_vec[0], &target_vec[1], SFOp2, STOp2);
894 self.values_branchmap.insert(&p1, vbm_1);
895 self.values_branchmap.insert(&p2, vbm_2);
896 self.switchbbs.insert(switch_block, (*p1, *p2));
897 }
898 }
899 };
900 }
901 }
902 pub fn flipped_binop(op: BinOp) -> Option<BinOp> {
903 use BinOp::*;
904 Some(match op {
905 Eq => Eq,
906 Ne => Ne,
907 Lt => Ge,
908 Le => Gt,
909 Gt => Le,
910 Ge => Lt,
911 Add => Add,
912 Mul => Mul,
913 BitXor => BitXor,
914 BitAnd => BitAnd,
915 BitOr => BitOr,
916 _ => {
917 return None;
918 }
919 })
920 }
921 fn reverse_binop(op: BinOp) -> Option<BinOp> {
922 use BinOp::*;
923 Some(match op {
924 Eq => Eq,
925 Ne => Ne,
926 Lt => Gt,
927 Le => Ge,
928 Gt => Lt,
929 Ge => Le,
930 Add => Add,
931 Mul => Mul,
932 BitXor => BitXor,
933 BitAnd => BitAnd,
934 BitOr => BitOr,
935 _ => {
936 return None;
937 }
938 })
939 }
940 fn extract_condition(
941 &mut self,
942 place: &'tcx Place<'tcx>,
943 switch_block: &'tcx BasicBlockData<'tcx>,
944 ) -> Option<(&'tcx Operand<'tcx>, &'tcx Operand<'tcx>, BinOp)> {
945 for stmt in &switch_block.statements {
946 if let StatementKind::Assign(box (lhs, Rvalue::BinaryOp(bin_op, box (op1, op2)))) =
947 &stmt.kind
948 {
949 if lhs == place {
950 let mut return_op1: &Operand<'tcx> = &op1;
951 let mut return_op2: &Operand<'tcx> = &op2;
952 return Some((return_op1, return_op2, *bin_op));
976 }
977 }
978 }
979 None
980 }
981
982 fn apply_comparison<U: IntervalArithmetic>(
983 &self,
984 constant: U,
985 cmp_op: BinOp,
986 is_true_branch: bool,
987 const_in_left: bool,
988 ) -> Range<U> {
989 match cmp_op {
990 BinOp::Lt => {
991 if is_true_branch ^ const_in_left {
992 Range::new(U::min_value(), constant.sub(U::one()), RangeType::Unknown)
993 } else {
994 Range::new(constant, U::max_value(), RangeType::Unknown)
995 }
996 }
997
998 BinOp::Le => {
999 if is_true_branch ^ const_in_left {
1000 Range::new(U::min_value(), constant, RangeType::Unknown)
1001 } else {
1002 Range::new(constant.add(U::one()), U::max_value(), RangeType::Unknown)
1003 }
1004 }
1005
1006 BinOp::Gt => {
1007 if is_true_branch ^ const_in_left {
1008 Range::new(U::min_value(), constant, RangeType::Unknown)
1009 } else {
1010 Range::new(constant.add(U::one()), U::max_value(), RangeType::Unknown)
1011 }
1012 }
1013
1014 BinOp::Ge => {
1015 if is_true_branch ^ const_in_left {
1016 Range::new(U::min_value(), constant, RangeType::Unknown)
1017 } else {
1018 Range::new(constant, U::max_value().sub(U::one()), RangeType::Unknown)
1019 }
1020 }
1021
1022 BinOp::Eq => {
1023 if is_true_branch ^ const_in_left {
1024 Range::new(U::min_value(), constant, RangeType::Unknown)
1025 } else {
1026 Range::new(constant, U::max_value(), RangeType::Unknown)
1027 }
1028 }
1029
1030 _ => Range::new(constant.clone(), constant.clone(), RangeType::Empty),
1031 }
1032 }
1033
1034 fn build_value_goto_map(&self, block_index: BasicBlock, target: BasicBlock) {
1035 rap_trace!(
1036 "Building value map for Goto in block {:?} targeting block {:?}",
1037 block_index,
1038 target
1039 );
1040 }
1041 pub fn build_varnodes(&mut self) {
1042 for (name, node) in self.vars.iter_mut() {
1044 let is_undefined = !self.defmap.contains_key(name);
1045 node.init(is_undefined);
1046 }
1047 }
1048
1049 pub fn build_symbolic_intersect_map(&mut self) {
1050 for i in 0..self.oprs.len() {
1051 if let BasicOpKind::Essa(essaop) = &self.oprs[i] {
1052 if let IntervalType::Symb(symbi) = essaop.get_intersect() {
1053 let v = symbi.get_bound();
1054 self.symbmap.entry(v).or_insert_with(HashSet::new).insert(i);
1055 rap_trace!("symbmap insert {:?} {:?}\n", v, essaop);
1056 }
1057 }
1058 }
1059 }
1061 pub fn build_use_map(
1062 &mut self,
1063 component: &HashSet<&'tcx Place<'tcx>>,
1064 ) -> HashMap<&'tcx Place<'tcx>, HashSet<usize>> {
1065 let mut comp_use_map = HashMap::new();
1067 for &place in component {
1068 if let Some(uses) = self.usemap.get(place) {
1069 for op in uses.iter() {
1070 let sink = self.oprs[*op].get_sink();
1071 if component.contains(&sink) {
1072 comp_use_map
1073 .entry(place)
1074 .or_insert_with(HashSet::new)
1075 .insert(*op);
1076 }
1077 }
1078 }
1079 }
1080
1081 self.print_compusemap(component, &comp_use_map);
1082 comp_use_map
1083 }
1084 pub fn build_terminator(&mut self, block: BasicBlock, terminator: &'tcx Terminator<'tcx>) {
1085 match &terminator.kind {
1086 TerminatorKind::Call {
1087 func,
1088 args,
1089 destination,
1090 target: _,
1091 unwind: _,
1092 fn_span: _,
1093 call_source,
1094 } => {
1095 rap_trace!(
1096 "TerminatorKind::Call in block {:?} with function {:?} destination {:?} args {:?}\n",
1097 block,
1098 func,
1099 destination,
1100 args
1101 );
1102 self.add_call_op(destination, args, terminator, func, block);
1104 }
1105 TerminatorKind::Return => {}
1106 TerminatorKind::Goto { target } => {
1107 rap_trace!(
1108 "TerminatorKind::Goto in block {:?} targeting block {:?}\n",
1109 block,
1110 target
1111 );
1112 }
1113 TerminatorKind::SwitchInt { discr, targets } => {
1114 rap_trace!(
1115 "TerminatorKind::SwitchInt in block {:?} with discr {:?} and targets {:?}\n",
1116 block,
1117 discr,
1118 targets
1119 );
1120 }
1121 _ => {
1122 rap_trace!(
1123 "Unsupported terminator kind in block {:?}: {:?}",
1124 block,
1125 terminator.kind
1126 );
1127 }
1128 }
1129 }
1130 pub fn build_operations(
1131 &mut self,
1132 inst: &'tcx Statement<'tcx>,
1133 block: BasicBlock,
1134 body: &'tcx Body<'tcx>,
1135 ) {
1136 match &inst.kind {
1137 StatementKind::Assign(box (sink, rvalue)) => match rvalue {
1138 Rvalue::BinaryOp(op, box (op1, op2)) => match op {
1139 BinOp::Add
1140 | BinOp::Sub
1141 | BinOp::Mul
1142 | BinOp::Div
1143 | BinOp::Rem
1144 | BinOp::AddUnchecked => {
1145 self.add_binary_op(sink, inst, rvalue, op1, op2, *op);
1146 }
1147 BinOp::AddWithOverflow => {
1148 self.add_binary_op(sink, inst, rvalue, op1, op2, *op);
1149 }
1150 BinOp::SubUnchecked => {
1151 self.add_binary_op(sink, inst, rvalue, op1, op2, *op);
1152 }
1153 BinOp::SubWithOverflow => {
1154 self.add_binary_op(sink, inst, rvalue, op1, op2, *op);
1155 }
1156 BinOp::MulUnchecked => {
1157 self.add_binary_op(sink, inst, rvalue, op1, op2, *op);
1158 }
1159 BinOp::MulWithOverflow => {
1160 self.add_binary_op(sink, inst, rvalue, op1, op2, *op);
1161 }
1162
1163 _ => {}
1164 },
1165 Rvalue::UnaryOp(unop, operand) => {
1166 self.add_unary_op(sink, inst, rvalue, operand, *unop);
1167 }
1168 Rvalue::Aggregate(kind, operends) => match **kind {
1169 AggregateKind::Adt(def_id, _, _, _, _) => match def_id {
1170 _ if def_id == self.essa => {
1171 self.add_essa_op(sink, inst, rvalue, operends, block)
1172 }
1173 _ if def_id == self.ssa => self.add_ssa_op(sink, inst, rvalue, operends),
1174 _ => match self.unique_adt_handler(def_id) {
1175 1 => {
1176 self.add_aggregate_op(sink, inst, rvalue, operends, 1);
1177 }
1178 _ => {
1179 rap_trace!(
1180 "AggregateKind::Adt with def_id {:?} in statement {:?} is not handled specially.\n",
1181 def_id,
1182 inst
1183 );
1184 }
1185 },
1186 },
1187 _ => {}
1188 },
1189 Rvalue::Use(operend) => {
1190 self.add_use_op(sink, inst, rvalue, operend);
1191 }
1192 Rvalue::Ref(_, borrowkind, place) => {
1193 self.add_ref_op(sink, inst, rvalue, place, *borrowkind);
1194 }
1195 _ => {}
1196 },
1197 _ => {}
1198 }
1199 }
1200 fn unique_adt_handler(&mut self, def_id: DefId) -> usize {
1202 let adt_path = self.tcx.def_path_str(def_id);
1203 rap_trace!("adt_path: {:?}\n", adt_path);
1204 if self.unique_adt_path.contains_key(&adt_path) {
1205 rap_trace!(
1206 "unique_adt_handler for def_id: {:?} -> {}\n",
1207 def_id,
1208 adt_path
1209 );
1210 return *self.unique_adt_path.get(&adt_path).unwrap();
1211 }
1212 0
1213 }
1214 fn add_call_op(
1216 &mut self,
1217 sink: &'tcx Place<'tcx>,
1218 args: &'tcx Box<[Spanned<Operand<'tcx>>]>,
1219 terminator: &'tcx Terminator<'tcx>,
1220 func: &'tcx Operand<'tcx>,
1221 block: BasicBlock,
1222 ) {
1223 rap_trace!("add_call_op for sink: {:?} {:?}\n", sink, terminator);
1224 let sink_node = self.add_varnode(&sink);
1225
1226 let mut path = String::new();
1230 let mut func_def_id = None;
1231 if let Operand::Constant(box const_operand) = func {
1232 let fn_ty = const_operand.ty();
1233 if let ty::TyKind::FnDef(def_id, _substs) = fn_ty.kind() {
1234 rap_debug!("fn_ty: {:?}\n", fn_ty);
1236 if def_id.krate != LOCAL_CRATE {
1237 path = self.tcx.def_path_str(*def_id);
1238
1239 self.func_without_mir.insert(*def_id, path.clone());
1240 rap_debug!("called external/no-MIR fn: {:?} -> {}", def_id, path);
1241 }
1242 func_def_id = Some(def_id);
1249 }
1250 }
1251
1252 if let Some(def_id) = func_def_id {
1253 rap_trace!(
1254 "TerminatorKind::Call in block {:?} with DefId {:?}\n",
1255 block,
1256 def_id
1257 );
1258 } else {
1260 rap_trace!(
1261 "TerminatorKind::Call in block {:?} is an indirect call (e.g., function pointer)\n",
1262 block
1263 );
1264 }
1267 let mut constant_count = 0 as usize;
1268 let arg_count = args.len();
1269 let mut arg_operands: Vec<Operand<'tcx>> = Vec::new();
1270 let mut places = Vec::new();
1271 for op in args.iter() {
1272 match &op.node {
1273 Operand::Copy(place) | Operand::Move(place) => {
1274 arg_operands.push(op.node.clone());
1275 places.push(place);
1276 self.add_varnode(place);
1277 self.usemap
1278 .entry(place)
1279 .or_default()
1280 .insert(self.oprs.len());
1281 }
1282
1283 Operand::Constant(_) => {
1284 arg_operands.push(op.node.clone());
1287 constant_count += 1;
1288 }
1289 }
1290 }
1291 {
1292 let bi = BasicInterval::new(Range::default(T::min_value()));
1293
1294 let call_op = CallOp::new(
1295 IntervalType::Basic(bi),
1296 &sink,
1297 terminator, arg_operands,
1299 *func_def_id.unwrap(), path,
1301 places,
1302 );
1303 rap_debug!("call_op: {:?}\n", call_op);
1304 let bop_index = self.oprs.len();
1305
1306 self.oprs.push(BasicOpKind::Call(call_op));
1308
1309 self.defmap.insert(&sink, bop_index);
1311 if constant_count == arg_count {
1312 rap_trace!("all args are constants\n");
1313 self.const_func_place.insert(&sink, bop_index);
1314 }
1315 }
1316 }
1317 fn add_ssa_op(
1318 &mut self,
1319 sink: &'tcx Place<'tcx>,
1320 inst: &'tcx Statement<'tcx>,
1321 rvalue: &'tcx Rvalue<'tcx>,
1322
1323 operands: &'tcx IndexVec<FieldIdx, Operand<'tcx>>,
1324 ) {
1325 rap_trace!("ssa_op{:?}\n", inst);
1326
1327 let sink_node: &mut VarNode<'_, T> = self.def_add_varnode_sym(sink, rvalue);
1328 rap_trace!("addsink_in_ssa_op{:?}\n", sink_node);
1329
1330 let BI: BasicInterval<T> = BasicInterval::new(Range::default(T::min_value()));
1331 let mut phiop = PhiOp::new(IntervalType::Basic(BI), sink, inst, 0);
1332 let bop_index = self.oprs.len();
1333 for i in 0..operands.len() {
1334 let source = match &operands[FieldIdx::from_usize(i)] {
1335 Operand::Copy(place) | Operand::Move(place) => {
1336 self.use_add_varnode_sym(place, rvalue);
1337 Some(place)
1338 }
1339 _ => None,
1340 };
1341 if let Some(source) = source {
1342 self.use_add_varnode_sym(source, rvalue);
1343 phiop.add_source(source);
1344 rap_trace!("addvar_in_ssa_op{:?}\n", source);
1345 self.usemap.entry(source).or_default().insert(bop_index);
1346 }
1347 }
1348 self.oprs.push(BasicOpKind::Phi(phiop));
1351
1352 self.defmap.insert(sink, bop_index);
1355 }
1356 fn add_use_op(
1357 &mut self,
1358 sink: &'tcx Place<'tcx>,
1359 inst: &'tcx Statement<'tcx>,
1360 rvalue: &'tcx Rvalue<'tcx>,
1361 op: &'tcx Operand<'tcx>,
1362 ) {
1363 rap_trace!("use_op{:?}\n", inst);
1364
1365 let BI: BasicInterval<T> = BasicInterval::new(Range::default(T::min_value()));
1366 let mut source: Option<&'tcx Place<'tcx>> = None;
1367
1368 match op {
1369 Operand::Copy(place) | Operand::Move(place) => {
1370 if sink.local == RETURN_PLACE && sink.projection.is_empty() {
1371 self.rerurn_places.insert(place);
1372 let sink_node = self.def_add_varnode_sym(sink, rvalue);
1375
1376 rap_debug!("add_return_place{:?}\n", place);
1377 } else {
1378 self.use_add_varnode_sym(place, rvalue);
1379 rap_trace!("addvar_in_use_op{:?}\n", place);
1380 let sink_node = self.def_add_varnode_sym(sink, rvalue);
1381 let useop = UseOp::new(IntervalType::Basic(BI), sink, inst, Some(place), None);
1382 let bop_index = self.oprs.len();
1384
1385 self.oprs.push(BasicOpKind::Use(useop));
1386 self.usemap.entry(place).or_default().insert(bop_index);
1388
1389 self.defmap.insert(sink, bop_index);
1390 }
1391 }
1392 Operand::Constant(constant) => {
1393 rap_trace!("add_constant_op{:?}\n", inst);
1394 let Some(c) = op.constant() else {
1395 rap_trace!("add_constant_op: constant is None\n");
1396 return;
1397 };
1398 let useop = UseOp::new(IntervalType::Basic(BI), sink, inst, None, Some(c.const_));
1399 let bop_index = self.oprs.len();
1401
1402 self.oprs.push(BasicOpKind::Use(useop));
1403 self.defmap.insert(sink, bop_index);
1406 let sink_node = self.def_add_varnode_sym(sink, rvalue);
1407
1408 if let Some(value) = Self::convert_const(&c.const_) {
1409 sink_node.set_range(Range::new(
1410 value.clone(),
1411 value.clone(),
1412 RangeType::Regular,
1413 ));
1414 rap_trace!("set_const {:?} value: {:?}\n", sink_node, value);
1415 } else {
1417 sink_node.set_range(Range::default(T::min_value()));
1418 };
1419 }
1420 }
1421 }
1422 fn add_essa_op(
1423 &mut self,
1424 sink: &'tcx Place<'tcx>,
1425 inst: &'tcx Statement<'tcx>,
1426 rvalue: &'tcx Rvalue<'tcx>,
1427 operands: &'tcx IndexVec<FieldIdx, Operand<'tcx>>,
1428 block: BasicBlock,
1429 ) {
1430 let sink_node = self.def_add_varnode_sym(sink, rvalue);
1432 let loc_1: usize = 0;
1436 let loc_2: usize = 1;
1437 let source1 = match &operands[FieldIdx::from_usize(loc_1)] {
1438 Operand::Copy(place) | Operand::Move(place) => {
1439 self.use_add_varnode_sym(place, rvalue);
1440 Some(place)
1441 }
1442 _ => None,
1443 };
1444 let op = &operands[FieldIdx::from_usize(loc_2)];
1445 let bop_index = self.oprs.len();
1446 let BI: IntervalType<'_, T>;
1447 rap_trace!("essa_op operand1 {:?}\n", source1.unwrap());
1448 if let Operand::Constant(c) = op {
1449 let vbm = self.values_branchmap.get(source1.unwrap()).unwrap();
1450 if block == *vbm.get_bb_true() {
1451 rap_trace!("essa_op true branch{:?}\n", block);
1452 BI = vbm.get_itv_t();
1453 } else {
1454 rap_trace!("essa_op false branch{:?}\n", block);
1455 BI = vbm.get_itv_f();
1456 }
1457 self.usemap
1458 .entry(source1.unwrap())
1459 .or_default()
1460 .insert(bop_index);
1461
1462 let essaop = EssaOp::new(BI, sink, inst, source1.unwrap(), 0, false);
1463 rap_trace!(
1464 "addvar_in_essa_op {:?} from const {:?}\n",
1465 essaop,
1466 source1.unwrap()
1467 );
1468
1469 self.oprs.push(BasicOpKind::Essa(essaop));
1472 self.defmap.insert(sink, bop_index);
1479 } else {
1480 let vbm = self.values_branchmap.get(source1.unwrap()).unwrap();
1481 if block == *vbm.get_bb_true() {
1482 rap_trace!("essa_op true branch{:?}\n", block);
1483 BI = vbm.get_itv_t();
1484 } else {
1485 rap_trace!("essa_op false branch{:?}\n", block);
1486 BI = vbm.get_itv_f();
1487 }
1488 let source2 = match op {
1489 Operand::Copy(place) | Operand::Move(place) => {
1490 self.use_add_varnode_sym(place, rvalue);
1491 Some(place)
1492 }
1493 _ => None,
1494 };
1495 self.usemap
1496 .entry(source1.unwrap())
1497 .or_default()
1498 .insert(bop_index);
1499 let essaop = EssaOp::new(BI, sink, inst, source1.unwrap(), 0, true);
1504 rap_trace!(
1506 "addvar_in_essa_op {:?} from {:?}\n",
1507 essaop,
1508 source1.unwrap()
1509 );
1510
1511 self.oprs.push(BasicOpKind::Essa(essaop));
1512 self.defmap.insert(sink, bop_index);
1519 }
1520 }
1521 pub fn add_aggregate_op(
1522 &mut self,
1523 sink: &'tcx Place<'tcx>,
1524 inst: &'tcx Statement<'tcx>,
1525 rvalue: &'tcx Rvalue<'tcx>,
1526 operands: &'tcx IndexVec<FieldIdx, Operand<'tcx>>,
1527 unique_adt: usize,
1528 ) {
1529 rap_trace!("aggregate_op {:?}\n", inst);
1530
1531 let BI: BasicInterval<T> = BasicInterval::new(Range::default(T::min_value()));
1532 let mut agg_operands: Vec<AggregateOperand<'tcx>> = Vec::with_capacity(operands.len());
1533
1534 for operand in operands {
1535 match operand {
1536 Operand::Copy(place) | Operand::Move(place) => {
1537 if sink.local == RETURN_PLACE && sink.projection.is_empty() {
1538 self.rerurn_places.insert(place);
1539 self.def_add_varnode_sym(sink, rvalue);
1540 rap_debug!("add_return_place {:?}\n", place);
1541 } else {
1542 self.use_add_varnode_sym(place, rvalue);
1543 rap_trace!("addvar_in_aggregate_op {:?}\n", place);
1544 agg_operands.push(AggregateOperand::Place(place));
1545 }
1546 }
1547 Operand::Constant(c) => {
1548 rap_trace!("add_constant_aggregate_op {:?}\n", c);
1549 agg_operands.push(AggregateOperand::Const(c.const_));
1550
1551 let sink_node = self.def_add_varnode_sym(sink, rvalue);
1552 if let Some(value) = Self::convert_const(&c.const_) {
1553 sink_node.set_range(Range::new(
1554 value.clone(),
1555 value.clone(),
1556 RangeType::Regular,
1557 ));
1558 rap_trace!("set_const {:?} value: {:?}\n", sink_node, value);
1559 } else {
1560 sink_node.set_range(Range::default(T::min_value()));
1561 }
1562 }
1563 }
1564 }
1565
1566 if agg_operands.is_empty() {
1567 rap_trace!("aggregate_op has no operands, skipping\n");
1568 return;
1569 }
1570
1571 let agg_op = AggregateOp::new(
1572 IntervalType::Basic(BI),
1573 sink,
1574 inst,
1575 agg_operands,
1576 unique_adt,
1577 );
1578 let bop_index = self.oprs.len();
1579 self.oprs.push(BasicOpKind::Aggregate(agg_op));
1580
1581 for operand in operands {
1582 if let Operand::Copy(place) | Operand::Move(place) = operand {
1583 self.usemap.entry(place).or_default().insert(bop_index);
1584 }
1585 }
1586
1587 self.defmap.insert(sink, bop_index);
1588
1589 self.def_add_varnode_sym(sink, rvalue);
1590 }
1591
1592 fn add_unary_op(
1593 &mut self,
1594 sink: &'tcx Place<'tcx>,
1595 inst: &'tcx Statement<'tcx>,
1596 rvalue: &'tcx Rvalue<'tcx>,
1597 operand: &'tcx Operand<'tcx>,
1598 op: UnOp,
1599 ) {
1600 rap_trace!("unary_op{:?}\n", inst);
1601
1602 let sink_node = self.def_add_varnode_sym(sink, rvalue);
1603 rap_trace!("addsink_in_unary_op{:?}\n", sink_node);
1604
1605 let BI: BasicInterval<T> = BasicInterval::new(Range::default(T::min_value()));
1606 let loc_1: usize = 0;
1607
1608 let source = match operand {
1609 Operand::Copy(place) | Operand::Move(place) => {
1610 self.add_varnode(place);
1611 Some(place)
1612 }
1613 _ => None,
1614 };
1615
1616 rap_trace!("addvar_in_unary_op{:?}\n", source.unwrap());
1617 self.use_add_varnode_sym(&source.unwrap(), rvalue);
1618
1619 let unaryop = UnaryOp::new(IntervalType::Basic(BI), sink, inst, source.unwrap(), op);
1620 let bop_index = self.oprs.len();
1622
1623 self.oprs.push(BasicOpKind::Unary(unaryop));
1624 self.defmap.insert(sink, bop_index);
1627 }
1628 fn add_binary_op(
1629 &mut self,
1630 sink: &'tcx Place<'tcx>,
1631 inst: &'tcx Statement<'tcx>,
1632 rvalue: &'tcx Rvalue<'tcx>,
1633 op1: &'tcx Operand<'tcx>,
1634 op2: &'tcx Operand<'tcx>,
1635 bin_op: BinOp,
1636 ) {
1637 rap_trace!("binary_op{:?}\n", inst);
1638
1639 let sink_node = self.def_add_varnode_sym(sink, rvalue);
1641 rap_trace!("addsink_in_binary_op{:?}\n", sink_node);
1642
1643 let bop_index = self.oprs.len();
1644 let bi: BasicInterval<T> = BasicInterval::new(Range::default(T::min_value()));
1645
1646 let (source1_place, source2_place, const_val) = match (op1, op2) {
1649 (Operand::Copy(p1) | Operand::Move(p1), Operand::Copy(p2) | Operand::Move(p2)) => {
1651 self.use_add_varnode_sym(p1, rvalue);
1652 self.use_add_varnode_sym(p2, rvalue);
1653 rap_trace!("addvar_in_binary_op p1:{:?}, p2:{:?}\n", p1, p2);
1654
1655 (Some(p1), Some(p2), None)
1656 }
1657
1658 (Operand::Copy(p1) | Operand::Move(p1), Operand::Constant(c2)) => {
1660 self.use_add_varnode_sym(p1, rvalue);
1661 rap_trace!("addvar_in_binary_op p1:{:?}\n", p1);
1662
1663 (Some(p1), None, Some(c2.const_))
1664 }
1665
1666 (Operand::Constant(c1), Operand::Copy(p2) | Operand::Move(p2)) => {
1671 self.use_add_varnode_sym(p2, rvalue);
1672 rap_trace!("addvar_in_binary_op p2(as source1):{:?}\n", p2);
1673
1674 (Some(p2), None, Some(c1.const_))
1676 }
1677
1678 (Operand::Constant(c1), Operand::Constant(_)) => {
1680 (None, None, Some(c1.const_))
1683 }
1684 };
1685
1686 let bop = BinaryOp::new(
1688 IntervalType::Basic(bi),
1689 sink,
1690 inst,
1691 source1_place, source2_place,
1693 const_val,
1694 bin_op.clone(),
1695 );
1696
1697 self.oprs.push(BasicOpKind::Binary(bop));
1698
1699 self.defmap.insert(sink, bop_index);
1701
1702 if let Some(place) = source1_place {
1704 self.usemap.entry(place).or_default().insert(bop_index);
1705 }
1706
1707 if let Some(place) = source2_place {
1708 self.usemap.entry(place).or_default().insert(bop_index);
1709 }
1710 }
1711 fn add_ref_op(
1712 &mut self,
1713 sink: &'tcx Place<'tcx>,
1714 inst: &'tcx Statement<'tcx>,
1715 rvalue: &'tcx Rvalue<'tcx>,
1716 place: &'tcx Place<'tcx>,
1717 borrowkind: BorrowKind,
1718 ) {
1719 rap_trace!("ref_op {:?}\n", inst);
1720
1721 let BI: BasicInterval<T> = BasicInterval::new(Range::default(T::min_value()));
1722
1723 let source_node = self.use_add_varnode_sym(place, rvalue);
1724
1725 let sink_node = self.def_add_varnode_sym(sink, rvalue);
1726
1727 let refop = RefOp::new(IntervalType::Basic(BI), sink, inst, place, borrowkind);
1728 let bop_index = self.oprs.len();
1729 self.oprs.push(BasicOpKind::Ref(refop));
1730
1731 self.usemap.entry(place).or_default().insert(bop_index);
1732
1733 self.defmap.insert(sink, bop_index);
1734
1735 rap_trace!(
1736 "add_ref_op: created RefOp from {:?} to {:?} at {:?}\n",
1737 place,
1738 sink,
1739 inst
1740 );
1741 }
1742
1743 fn fix_intersects(&mut self, component: &HashSet<&'tcx Place<'tcx>>) {
1744 for &place in component.iter() {
1745 if let Some(sit) = self.symbmap.get_mut(place) {
1747 let node = self.vars.get(place).unwrap();
1748
1749 for &op in sit.iter() {
1750 let op = &mut self.oprs[op];
1751 let sinknode = self.vars.get(op.get_sink()).unwrap();
1752
1753 op.op_fix_intersects(node, sinknode);
1754 }
1755 }
1756 }
1757 }
1758 pub fn widen(
1759 &mut self,
1760 op: usize,
1761 cg_map: &FxHashMap<DefId, Rc<RefCell<ConstraintGraph<'tcx, T>>>>,
1762 vars_map: &mut FxHashMap<DefId, Vec<RefCell<VarNodes<'tcx, T>>>>,
1763 ) -> bool {
1764 let op_kind = &self.oprs[op];
1767 let sink = op_kind.get_sink();
1768 let old_interval = self.vars.get(sink).unwrap().get_range().clone();
1769
1770 let estimated_interval = match op_kind {
1773 BasicOpKind::Call(call_op) => {
1774 call_op.eval_call(&self.vars, cg_map, vars_map)
1776 }
1777 _ => {
1778 op_kind.eval(&self.vars)
1780 }
1781 };
1782 let old_lower = old_interval.get_lower();
1783 let old_upper = old_interval.get_upper();
1784 let new_lower = estimated_interval.get_lower();
1785 let new_upper = estimated_interval.get_upper();
1786 let updated = if old_interval.is_unknown() {
1802 estimated_interval.clone()
1803 } else if new_lower < old_lower && new_upper > old_upper {
1804 Range::new(T::min_value(), T::max_value(), RangeType::Regular)
1805 } else if new_lower < old_lower {
1806 Range::new(T::min_value(), old_upper.clone(), RangeType::Regular)
1807 } else if new_upper > old_upper {
1808 Range::new(old_lower.clone(), T::max_value(), RangeType::Regular)
1809 } else {
1810 old_interval.clone()
1811 };
1812
1813 self.vars.get_mut(sink).unwrap().set_range(updated.clone());
1814 rap_trace!(
1815 "WIDEN in {} set {:?}: E {:?} U {:?} {:?} -> {:?}",
1816 op,
1817 sink,
1818 estimated_interval,
1819 updated,
1820 old_interval,
1821 updated
1822 );
1823
1824 old_interval != updated
1825 }
1826 pub fn narrow(
1827 &mut self,
1828 op: usize,
1829 cg_map: &FxHashMap<DefId, Rc<RefCell<ConstraintGraph<'tcx, T>>>>,
1830 vars_map: &mut FxHashMap<DefId, Vec<RefCell<VarNodes<'tcx, T>>>>,
1831 ) -> bool {
1832 let op_kind = &self.oprs[op];
1833 let sink = op_kind.get_sink();
1834 let old_interval = self.vars.get(sink).unwrap().get_range().clone();
1835
1836 let estimated_interval = match op_kind {
1838 BasicOpKind::Call(call_op) => {
1839 call_op.eval_call(&self.vars, cg_map, vars_map)
1841 }
1842 _ => {
1843 op_kind.eval(&self.vars)
1845 }
1846 };
1847 let old_lower = old_interval.get_lower();
1848 let old_upper = old_interval.get_upper();
1849 let new_lower = estimated_interval.get_lower();
1850 let new_upper = estimated_interval.get_upper();
1851 let mut final_lower = old_lower.clone();
1854 let mut final_upper = old_upper.clone();
1855 if old_lower.clone() == T::min_value() && new_lower.clone() > T::min_value() {
1856 final_lower = new_lower.clone();
1857 } else if old_lower.clone() <= new_lower.clone() {
1860 final_lower = new_lower.clone();
1861
1862 };
1865 if old_upper.clone() == T::max_value() && new_upper.clone() < T::max_value() {
1866 final_upper = new_upper.clone();
1867 } else if old_upper.clone() >= new_upper.clone() {
1870 final_upper = new_upper.clone();
1871 }
1874 let tightened = Range::new(final_lower, final_upper, RangeType::Regular);
1875
1876 self.vars
1877 .get_mut(sink)
1878 .unwrap()
1879 .set_range(tightened.clone());
1880 rap_trace!(
1881 "NARROW in {} set {:?}: E {:?} U {:?} {:?} -> {:?}",
1882 op,
1883 sink,
1884 estimated_interval,
1885 tightened,
1886 old_interval,
1887 tightened
1888 );
1889 let hasChanged = old_interval != tightened;
1890
1891 hasChanged
1892 }
1893
1894 fn pre_update(
1895 &mut self,
1896 comp_use_map: &HashMap<&'tcx Place<'tcx>, HashSet<usize>>,
1897 entry_points: &HashSet<&'tcx Place<'tcx>>,
1898 cg_map: &FxHashMap<DefId, Rc<RefCell<ConstraintGraph<'tcx, T>>>>,
1899 vars_map: &mut FxHashMap<DefId, Vec<RefCell<VarNodes<'tcx, T>>>>,
1900 ) {
1901 let mut worklist: Vec<&'tcx Place<'tcx>> = entry_points.iter().cloned().collect();
1902
1903 while let Some(place) = worklist.pop() {
1904 if let Some(op_set) = comp_use_map.get(place) {
1905 for &op in op_set {
1906 if self.widen(op, cg_map, vars_map) {
1907 let sink = self.oprs[op].get_sink();
1908 rap_trace!("W {:?}\n", sink);
1909 worklist.push(sink);
1911 }
1912 }
1913 }
1914 }
1915 }
1916
1917 fn pos_update(
1918 &mut self,
1919 comp_use_map: &HashMap<&'tcx Place<'tcx>, HashSet<usize>>,
1920 entry_points: &HashSet<&'tcx Place<'tcx>>,
1921 cg_map: &FxHashMap<DefId, Rc<RefCell<ConstraintGraph<'tcx, T>>>>,
1922 vars_map: &mut FxHashMap<DefId, Vec<RefCell<VarNodes<'tcx, T>>>>,
1923 ) {
1924 let mut worklist: Vec<&'tcx Place<'tcx>> = entry_points.iter().cloned().collect();
1925 let mut iteration = 0;
1926 while let Some(place) = worklist.pop() {
1927 iteration += 1;
1928 if (iteration > 1000) {
1929 rap_trace!("Iteration limit reached, breaking out of pos_update\n");
1930 break;
1931 }
1932
1933 if let Some(op_set) = comp_use_map.get(place) {
1934 for &op in op_set {
1935 if self.narrow(op, cg_map, vars_map) {
1936 let sink = self.oprs[op].get_sink();
1937 rap_trace!("N {:?}\n", sink);
1938
1939 worklist.push(sink);
1941 }
1942 }
1943 }
1944 }
1945 rap_trace!("pos_update finished after {} iterations\n", iteration);
1946 }
1947 fn generate_active_vars(
1948 &mut self,
1949 component: &HashSet<&'tcx Place<'tcx>>,
1950 active_vars: &mut HashSet<&'tcx Place<'tcx>>,
1951 cg_map: &FxHashMap<DefId, Rc<RefCell<ConstraintGraph<'tcx, T>>>>,
1952 vars_map: &mut FxHashMap<DefId, Vec<RefCell<VarNodes<'tcx, T>>>>,
1953 ) {
1954 for place in component {
1955 let node = self.vars.get(place).unwrap();
1956 }
1957 }
1958 fn generate_entry_points(
1959 &mut self,
1960 component: &HashSet<&'tcx Place<'tcx>>,
1961 entry_points: &mut HashSet<&'tcx Place<'tcx>>,
1962 cg_map: &FxHashMap<DefId, Rc<RefCell<ConstraintGraph<'tcx, T>>>>,
1963 vars_map: &mut FxHashMap<DefId, Vec<RefCell<VarNodes<'tcx, T>>>>,
1964 ) {
1965 for &place in component {
1966 let op = self.defmap.get(place).unwrap();
1967 if let BasicOpKind::Essa(essaop) = &mut self.oprs[*op] {
1968 if essaop.is_unresolved() {
1969 let source = essaop.get_source();
1970 let new_range = essaop.eval(&self.vars);
1971 let sink_node = self.vars.get_mut(source).unwrap();
1972 sink_node.set_range(new_range);
1973 }
1974 essaop.mark_resolved();
1975 }
1976 if (!self.vars[place].get_range().is_unknown()) {
1977 entry_points.insert(place);
1978 }
1979 }
1980 }
1981 fn propagate_to_next_scc(
1982 &mut self,
1983 component: &HashSet<&'tcx Place<'tcx>>,
1984 cg_map: &FxHashMap<DefId, Rc<RefCell<ConstraintGraph<'tcx, T>>>>,
1985 vars_map: &mut FxHashMap<DefId, Vec<RefCell<VarNodes<'tcx, T>>>>,
1986 ) {
1987 for &place in component.iter() {
1988 let node = self.vars.get_mut(place).unwrap();
1989 for &op in self.usemap.get(place).unwrap().iter() {
1990 let op_kind = &mut self.oprs[op];
1991 let sink = op_kind.get_sink();
1992 if !component.contains(sink) {
1993 let new_range = op_kind.eval(&self.vars);
1994 let new_range = match op_kind {
1995 BasicOpKind::Call(call_op) => {
1996 call_op.eval_call(&self.vars, cg_map, vars_map)
1997 }
1998 _ => {
1999 op_kind.eval(&self.vars)
2001 }
2002 };
2003 let sink_node = self.vars.get_mut(sink).unwrap();
2004 rap_trace!(
2005 "prop component {:?} set {:?} to {:?} through {:?}\n",
2006 component,
2007 new_range,
2008 sink,
2009 op_kind.get_instruction()
2010 );
2011 sink_node.set_range(new_range);
2012 if let BasicOpKind::Essa(essaop) = op_kind {
2017 if essaop.get_intersect().get_range().is_unknown() {
2018 essaop.mark_unresolved();
2019 }
2020 }
2021 }
2022 }
2023 }
2024 }
2025 pub fn solve_const_func_call(
2026 &mut self,
2027 cg_map: &FxHashMap<DefId, Rc<RefCell<ConstraintGraph<'tcx, T>>>>,
2028 vars_map: &mut FxHashMap<DefId, Vec<RefCell<VarNodes<'tcx, T>>>>,
2029 ) {
2030 for (&sink, op) in &self.const_func_place {
2031 rap_trace!(
2032 "solve_const_func_call for sink {:?} with opset {:?}\n",
2033 sink,
2034 op
2035 );
2036 if let BasicOpKind::Call(call_op) = &self.oprs[*op] {
2037 let new_range = call_op.eval_call(&self.vars, cg_map, vars_map);
2038 rap_trace!("Setting range for {:?} to {:?}\n", sink, new_range);
2039 self.vars.get_mut(sink).unwrap().set_range(new_range);
2040 }
2041 }
2042 }
2043 pub fn store_vars(&mut self, varnodes_vec: &mut Vec<RefCell<VarNodes<'tcx, T>>>) {
2044 rap_trace!("Storing vars\n");
2045 let old_vars = self.vars.clone();
2046 varnodes_vec.push(RefCell::new(old_vars));
2047 }
2048 pub fn reset_vars(&mut self, varnodes_vec: &mut Vec<RefCell<VarNodes<'tcx, T>>>) {
2049 rap_trace!("Resetting vars\n");
2050 self.vars = varnodes_vec[0].borrow_mut().clone();
2051 }
2052 pub fn find_intervals(
2053 &mut self,
2054 cg_map: &FxHashMap<DefId, Rc<RefCell<ConstraintGraph<'tcx, T>>>>,
2055 vars_map: &mut FxHashMap<DefId, Vec<RefCell<VarNodes<'tcx, T>>>>,
2056 ) {
2057 self.solve_const_func_call(cg_map, vars_map);
2061 self.numSCCs = self.worklist.len();
2062 let mut seen = HashSet::new();
2063 let mut components = Vec::new();
2064
2065 for &place in self.worklist.iter().rev() {
2066 if seen.contains(place) {
2067 continue;
2068 }
2069
2070 if let Some(component) = self.components.get(place) {
2071 for &p in component {
2072 seen.insert(p);
2073 }
2074
2075 components.push(component.clone());
2076 }
2077 }
2078 rap_trace!("TOLO:{:?}\n", components);
2079
2080 for component in components {
2081 rap_trace!("===start component {:?}===\n", component);
2082 if component.len() == 1 {
2083 self.numAloneSCCs += 1;
2084
2085 self.fix_intersects(&component);
2086
2087 let variable: &Place<'tcx> = *component.iter().next().unwrap();
2088 let varnode = self.vars.get_mut(variable).unwrap();
2089 if varnode.get_range().is_unknown() {
2090 varnode.set_default();
2091 }
2092 } else {
2093 let comp_use_map = self.build_use_map(&component);
2095 let mut entry_points = HashSet::new();
2097 self.generate_entry_points(&component, &mut entry_points, cg_map, vars_map);
2100 rap_trace!("entry_points {:?} \n", entry_points);
2101 self.pre_update(&comp_use_map, &entry_points, cg_map, vars_map);
2103 self.fix_intersects(&component);
2104
2105 let mut active_vars = HashSet::new();
2113 self.generate_active_vars(&component, &mut active_vars, cg_map, vars_map);
2114 self.pos_update(&comp_use_map, &entry_points, cg_map, vars_map);
2115 }
2116 self.propagate_to_next_scc(&component, cg_map, vars_map);
2117 }
2118 self.merge_return_places();
2119 let Some(varnodes_vec) = vars_map.get_mut(&self.self_def_id) else {
2120 rap_trace!(
2121 "No variable map entry for this function {:?}, skipping Nuutila\n",
2122 self.self_def_id
2123 );
2124 return;
2125 };
2126 self.store_vars(varnodes_vec);
2127 }
2128 pub fn merge_return_places(&mut self) {
2129 rap_trace!("====Merging return places====\n");
2130 for &place in self.rerurn_places.iter() {
2131 rap_debug!("merging return place {:?}\n", place);
2132 let mut merged_range = Range::default(T::min_value());
2133 if let Some(opset) = self.vars.get(place) {
2134 merged_range = merged_range.unionwith(opset.get_range());
2135 }
2136 if let Some(return_node) = self.vars.get_mut(&Place::return_place()) {
2137 rap_debug!("Assigning final merged range {:?} to _0", merged_range);
2138 return_node.set_range(merged_range);
2139 } else {
2140 rap_trace!(
2144 "Warning: RETURN_PLACE (_0) not found in self.vars. Cannot assign merged return range."
2145 );
2146 }
2147 }
2148 }
2149
2150 pub fn add_control_dependence_edges(&mut self) {
2151 rap_trace!("====Add control dependence edges====\n");
2152 self.print_symbmap();
2153 for (&place, opset) in self.symbmap.iter() {
2154 for &op in opset.iter() {
2155 let bop_index = self.oprs.len();
2156 let opkind = &self.oprs[op];
2157 let control_edge = ControlDep::new(
2158 IntervalType::Basic(BasicInterval::default()),
2159 opkind.get_sink(),
2160 opkind.get_instruction().unwrap(),
2161 place,
2162 );
2163 rap_trace!(
2164 "Adding control_edge {:?} for place {:?} at index {}\n",
2165 control_edge,
2166 place,
2167 bop_index
2168 );
2169 self.oprs.push(BasicOpKind::ControlDep(control_edge));
2170 self.usemap.entry(place).or_default().insert(bop_index);
2171 }
2172 }
2173 }
2174 pub fn del_control_dependence_edges(&mut self) {
2175 rap_trace!("====Delete control dependence edges====\n");
2176
2177 let mut remove_from = self.oprs.len();
2178 while remove_from > 0 {
2179 match &self.oprs[remove_from - 1] {
2180 BasicOpKind::ControlDep(dep) => {
2181 let place = dep.source;
2182 rap_trace!(
2183 "removing control_edge at idx {}: {:?}\n",
2184 remove_from - 1,
2185 dep
2186 );
2187 if let Some(set) = self.usemap.get_mut(&place) {
2188 set.remove(&(remove_from - 1));
2189 if set.is_empty() {
2190 self.usemap.remove(&place);
2191 }
2192 }
2193 remove_from -= 1;
2194 }
2195 _ => break,
2196 }
2197 }
2198
2199 self.oprs.truncate(remove_from);
2200 }
2201
2202 pub fn build_nuutila(&mut self, single: bool) {
2203 rap_trace!("====Building Nuutila====\n");
2204 self.build_symbolic_intersect_map();
2205
2206 if single {
2207 } else {
2208 for place in self.vars.keys().copied() {
2209 self.dfs.insert(place, -1);
2210 }
2211
2212 self.add_control_dependence_edges();
2213
2214 let places: Vec<_> = self.vars.keys().copied().collect();
2215 rap_trace!("places{:?}\n", places);
2216 for place in places {
2217 if self.dfs[&place] < 0 {
2218 rap_trace!("start place{:?}\n", place);
2219 let mut stack = Vec::new();
2220 self.visit(place, &mut stack);
2221 }
2222 }
2223
2224 self.del_control_dependence_edges();
2225 }
2226 rap_trace!("components{:?}\n", self.components);
2227 rap_trace!("worklist{:?}\n", self.worklist);
2228 rap_trace!("dfs{:?}\n", self.dfs);
2229 }
2230 pub fn visit(&mut self, place: &'tcx Place<'tcx>, stack: &mut Vec<&'tcx Place<'tcx>>) {
2231 self.dfs.entry(place).and_modify(|v| *v = self.index);
2232 self.index += 1;
2233 self.root.insert(place, place);
2234 let uses = self.usemap.get(place).unwrap().clone();
2235 for op in uses {
2236 let name = self.oprs[op].get_sink();
2237 rap_trace!("place {:?} get name{:?}\n", place, name);
2238 if self.dfs.get(name).copied().unwrap_or(-1) < 0 {
2239 self.visit(name, stack);
2240 }
2241
2242 if (!self.in_component.contains(name)
2243 && self.dfs[self.root[place]] >= self.dfs[self.root[name]])
2244 {
2245 *self.root.get_mut(place).unwrap() = self.root.get(name).copied().unwrap();
2246
2247 }
2249 }
2250
2251 if self.root.get(place).copied().unwrap() == place {
2252 self.worklist.push_back(place);
2253
2254 let mut scc = HashSet::new();
2255 scc.insert(place);
2256
2257 self.in_component.insert(place);
2258
2259 while let Some(top) = stack.last() {
2260 if self.dfs.get(top).copied().unwrap_or(-1) > self.dfs.get(place).copied().unwrap()
2261 {
2262 let node = stack.pop().unwrap();
2263 self.in_component.insert(node);
2264
2265 scc.insert(node);
2266 } else {
2267 break;
2268 }
2269 }
2270
2271 self.components.insert(place, scc);
2272 } else {
2273 stack.push(place);
2274 }
2275 }
2276
2277 pub fn start_analyze_path_constraints(
2278 &mut self,
2279 body: &'tcx Body<'tcx>,
2280 all_paths_indices: &[Vec<usize>],
2281 ) -> HashMap<Vec<usize>, Vec<(Place<'tcx>, Place<'tcx>, BinOp)>> {
2282 self.build_value_maps(body);
2283 let result = self.analyze_path_constraints(body, all_paths_indices);
2284 result
2285 }
2286
2287 pub fn analyze_path_constraints(
2288 &self,
2289 body: &'tcx Body<'tcx>,
2290 all_paths_indices: &[Vec<usize>],
2291 ) -> HashMap<Vec<usize>, Vec<(Place<'tcx>, Place<'tcx>, BinOp)>> {
2292 let mut all_path_results: HashMap<Vec<usize>, Vec<(Place<'tcx>, Place<'tcx>, BinOp)>> =
2293 HashMap::with_capacity(all_paths_indices.len());
2294
2295 for path_indices in all_paths_indices {
2296 let mut current_path_constraints: Vec<(Place<'tcx>, Place<'tcx>, BinOp)> = Vec::new();
2297
2298 let path_bbs: Vec<BasicBlock> = path_indices
2299 .iter()
2300 .map(|&idx| BasicBlock::from_usize(idx))
2301 .collect();
2302
2303 for window in path_bbs.windows(2) {
2304 let current_bb = window[0];
2305
2306 if self.switchbbs.contains_key(¤t_bb) {
2307 let next_bb = window[1];
2308 let current_bb_data = &body[current_bb];
2309
2310 if let Some(Terminator {
2311 kind: TerminatorKind::SwitchInt { discr, .. },
2312 ..
2313 }) = ¤t_bb_data.terminator
2314 {
2315 let (constraint_place_1, constraint_place_2) =
2316 self.switchbbs.get(¤t_bb).unwrap();
2317 if let Some(vbm) = self.values_branchmap.get(constraint_place_1) {
2318 let relevant_interval_opt = if next_bb == *vbm.get_bb_true() {
2319 Some(vbm.get_itv_t())
2320 } else if next_bb == *vbm.get_bb_false() {
2321 Some(vbm.get_itv_f())
2322 } else {
2323 None
2324 };
2325
2326 if let Some(relevant_interval) = relevant_interval_opt {
2327 match relevant_interval {
2328 IntervalType::Basic(basic_interval) => {}
2329 IntervalType::Symb(symb_interval) => {
2330 current_path_constraints.push((
2331 constraint_place_1.clone(),
2332 constraint_place_2.clone(),
2333 symb_interval.get_operation().clone(),
2334 ));
2335 }
2336 }
2337 }
2338 }
2339 }
2340 }
2341 }
2342
2343 all_path_results.insert(path_indices.clone(), (current_path_constraints));
2344 }
2345
2346 all_path_results
2347 }
2348}
2349#[derive(Debug)]
2350pub struct Nuutila<'tcx, T: IntervalArithmetic + ConstConvert + Debug> {
2351 pub variables: &'tcx VarNodes<'tcx, T>,
2352 pub index: i32,
2353 pub dfs: HashMap<&'tcx Place<'tcx>, i32>,
2354 pub root: HashMap<&'tcx Place<'tcx>, &'tcx Place<'tcx>>,
2355 pub in_component: HashSet<&'tcx Place<'tcx>>,
2356 pub components: HashMap<&'tcx Place<'tcx>, HashSet<&'tcx Place<'tcx>>>,
2357 pub worklist: VecDeque<&'tcx Place<'tcx>>,
2358 }
2360
2361impl<'tcx, T> Nuutila<'tcx, T>
2362where
2363 T: IntervalArithmetic + ConstConvert + Debug,
2364{
2365 pub fn new(
2366 varNodes: &'tcx VarNodes<'tcx, T>,
2367 use_map: &'tcx UseMap<'tcx>,
2368 symb_map: &'tcx SymbMap<'tcx>,
2369 single: bool,
2370 oprs: &'tcx Vec<BasicOpKind<'tcx, T>>,
2371 ) -> Self {
2372 let mut n: Nuutila<'_, T> = Nuutila {
2373 variables: varNodes,
2374 index: 0,
2375 dfs: HashMap::new(),
2376 root: HashMap::new(),
2377 in_component: HashSet::new(),
2378 components: HashMap::new(),
2379 worklist: std::collections::VecDeque::new(),
2380 };
2382
2383 if single {
2384 } else {
2397 for place in n.variables.keys().copied() {
2398 n.dfs.insert(place, -1);
2399 }
2400
2401 n.add_control_dependence_edges(symb_map, use_map, varNodes);
2402
2403 for place in n.variables.keys() {
2404 if n.dfs[place] < 0 {
2405 let mut stack = Vec::new();
2406 n.visit(place, &mut stack, use_map, oprs);
2407 }
2408 }
2409
2410 }
2412
2413 n
2414 }
2415
2416 pub fn visit(
2417 &mut self,
2418 place: &'tcx Place<'tcx>,
2419 stack: &mut Vec<&'tcx Place<'tcx>>,
2420 use_map: &'tcx UseMap<'tcx>,
2421 oprs: &'tcx Vec<BasicOpKind<'tcx, T>>,
2422 ) {
2423 self.dfs.entry(place).and_modify(|v| *v = self.index);
2424 self.index += 1;
2425 self.root.insert(place, place);
2426
2427 if let Some(uses) = use_map.get(place) {
2428 for op in uses {
2429 let name = oprs[*op].get_sink();
2430
2431 if self.dfs.get(name).copied().unwrap_or(-1) < 0 {
2432 self.visit(name, stack, use_map, oprs);
2433 }
2434
2435 if (!self.in_component.contains(name)
2436 && self.dfs[self.root[place]] >= self.dfs[self.root[name]])
2437 {
2438 *self.root.get_mut(place).unwrap() = self.root.get(name).copied().unwrap();
2439
2440 }
2442 }
2443 }
2444
2445 if self.root.get(place).copied().unwrap() == place {
2446 self.worklist.push_back(place);
2447
2448 let mut scc = HashSet::new();
2449 scc.insert(place);
2450
2451 self.in_component.insert(place);
2452
2453 while let Some(&top) = stack.last() {
2454 if self.dfs.get(top).copied().unwrap_or(-1) > self.dfs.get(place).copied().unwrap()
2455 {
2456 let node = stack.pop().unwrap();
2457 self.in_component.insert(node);
2458
2459 scc.insert(node);
2460 } else {
2461 break;
2462 }
2463 }
2464
2465 self.components.insert(place, scc);
2466 } else {
2467 stack.push(place);
2468 }
2469 }
2470
2471 pub fn add_control_dependence_edges(
2472 &mut self,
2473 _symb_map: &'tcx SymbMap<'tcx>,
2474 _use_map: &'tcx UseMap<'tcx>,
2475 _vars: &'tcx VarNodes<'tcx, T>,
2476 ) {
2477 todo!()
2478 }
2479
2480 pub fn del_control_dependence_edges(&mut self, _use_map: &'tcx mut UseMap<'tcx>) {
2481 todo!()
2482 }
2483}