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
8use super::domain::*;
9use crate::analysis::core::range_analysis::{Range, RangeType};
10
11use crate::analysis::core::range_analysis::domain::SymbolicExpr::*;
12use crate::rap_debug;
13use crate::rap_info;
14use crate::rap_trace;
15use num_traits::Bounded;
16use once_cell::sync::{Lazy, OnceCell};
17use rustc_abi::FieldIdx;
19use rustc_data_structures::fx::FxHashMap;
20use rustc_hir::{def, def_id::DefId};
21use rustc_index::IndexVec;
22use rustc_middle::{
23 mir::*,
24 ty::{self, ScalarInt, TyCtxt, print},
25};
26use rustc_span::source_map::Spanned;
27use rustc_span::sym::var;
28
29use std::cell::RefCell;
30use std::rc::Rc;
31use std::{
32 collections::{HashMap, HashSet, VecDeque},
33 default,
34 fmt::Debug,
35};
36#[derive(Debug, Clone)]
37
38pub struct ConstraintGraph<'tcx, T: IntervalArithmetic + ConstConvert + Debug> {
39 pub self_def_id: DefId, pub 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>>,
52 pub essa: DefId,
53 pub ssa: DefId,
54 pub index: i32,
56 pub dfs: HashMap<&'tcx Place<'tcx>, i32>,
57 pub root: HashMap<&'tcx Place<'tcx>, &'tcx Place<'tcx>>,
58 pub in_component: HashSet<&'tcx Place<'tcx>>,
59 pub components: HashMap<&'tcx Place<'tcx>, HashSet<&'tcx Place<'tcx>>>,
60 pub worklist: VecDeque<&'tcx Place<'tcx>>,
61 pub numAloneSCCs: usize,
62 pub numSCCs: usize, pub final_vars: VarNodes<'tcx, T>,
64 pub arg_count: usize,
65 pub rerurn_places: HashSet<&'tcx Place<'tcx>>,
66 pub switchbbs: HashMap<BasicBlock, (Place<'tcx>, Place<'tcx>)>,
67 pub const_func_place: HashMap<&'tcx Place<'tcx>, usize>,
68}
69
70impl<'tcx, T> ConstraintGraph<'tcx, T>
71where
72 T: IntervalArithmetic + ConstConvert + Debug,
73{
74 pub fn convert_const(c: &Const) -> Option<T> {
75 T::from_const(c)
76 }
77 pub fn new(self_def_id: DefId, essa: DefId, ssa: DefId) -> Self {
78 Self {
79 self_def_id,
80 vars: VarNodes::new(),
81 oprs: GenOprs::new(),
82 defmap: DefMap::new(),
84 usemap: UseMap::new(),
85 symbmap: SymbMap::new(),
86 values_branchmap: ValuesBranchMap::new(),
87 constant_vector: Vec::new(),
89 inst_rand_place_set: Vec::new(),
90 essa,
91 ssa,
92 index: 0,
93 dfs: HashMap::new(),
94 root: HashMap::new(),
95 in_component: HashSet::new(),
96 components: HashMap::new(),
97 worklist: VecDeque::new(),
98 numAloneSCCs: 0,
99 numSCCs: 0,
100 final_vars: VarNodes::new(),
101 arg_count: 0,
102 rerurn_places: HashSet::new(),
103 switchbbs: HashMap::new(),
104 const_func_place: HashMap::new(),
105 }
106 }
107 pub fn new_without_ssa(self_def_id: DefId) -> Self {
108 Self {
109 self_def_id,
110 vars: VarNodes::new(),
111 oprs: GenOprs::new(),
112 defmap: DefMap::new(),
114 usemap: UseMap::new(),
115 symbmap: SymbMap::new(),
116 values_branchmap: ValuesBranchMap::new(),
117 constant_vector: Vec::new(),
119 inst_rand_place_set: Vec::new(),
120 essa: self_def_id, ssa: self_def_id, index: 0,
123 dfs: HashMap::new(),
124 root: HashMap::new(),
125 in_component: HashSet::new(),
126 components: HashMap::new(),
127 worklist: VecDeque::new(),
128 numAloneSCCs: 0,
129 numSCCs: 0,
130 final_vars: VarNodes::new(),
131 arg_count: 0,
132 rerurn_places: HashSet::new(),
133 switchbbs: HashMap::new(),
134 const_func_place: HashMap::new(),
135 }
136 }
137 pub fn build_final_vars(
138 &mut self,
139 places_map: &HashMap<Place<'tcx>, HashSet<Place<'tcx>>>,
140 ) -> (VarNodes<'tcx, T>, Vec<Place<'tcx>>) {
141 let mut final_vars: VarNodes<'tcx, T> = HashMap::new();
142 let mut not_found: Vec<Place<'tcx>> = Vec::new();
143
144 for (&_key_place, place_set) in places_map {
145 for &place in place_set {
146 let found = self.vars.iter().find(|&(&p, _)| *p == place);
147
148 if let Some((&found_place, var_node)) = found {
149 final_vars.insert(found_place, var_node.clone());
150 } else {
151 not_found.push(place);
152 }
153 }
154 }
155 self.final_vars = final_vars.clone();
156 (final_vars, not_found)
157 }
158 pub fn filter_final_vars(
159 vars: &VarNodes<'tcx, T>,
160 places_map: &HashMap<Place<'tcx>, HashSet<Place<'tcx>>>,
161 ) -> HashMap<Place<'tcx>, Range<T>> {
162 let mut final_vars = HashMap::new();
163
164 for (&_key_place, place_set) in places_map {
165 for &place in place_set {
166 if let Some(var_node) = vars.get(&place) {
167 final_vars.insert(place, var_node.get_range().clone());
168 }
169 }
170 }
171 final_vars
172 }
173 pub fn test_and_print_all_symbolic_expressions(&self) {
174 rap_info!("\n==== Testing and Printing All Symbolic Expressions ====");
175
176 let mut places: Vec<&'tcx Place<'tcx>> = self.vars.keys().copied().collect();
177 places.sort_by_key(|p| p.local.as_usize());
178
179 for place in places {
180 rap_info!("--- Place: {:?}", place);
181 match self.get_symbolicexpression(place) {
182 Some(sym_expr) => {
183 rap_info!(" Symbolic Expr: {}", sym_expr);
184 }
185 None => {
186 rap_info!(" Symbolic Expr: Could not be resolved (None returned).");
187 }
188 }
189 }
190 rap_info!("==== End of Symbolic Expression Test ====\n");
191 }
192 pub fn rap_print_final_vars(&self) {
193 for (&key, value) in &self.final_vars {
194 rap_debug!("Var: {:?}, {} ", key, value.get_range());
195 }
196 }
197 pub fn rap_print_vars(&self) {
198 for (&key, value) in &self.vars {
199 rap_trace!("Var: {:?}. {} ", key, value.get_range());
200 }
201 }
202 pub fn print_vars(&self) {
203 for (&key, value) in &self.vars {
204 rap_trace!("Var: {:?}. {} ", key, value.get_range());
205 }
206 }
207 pub fn print_conponent_vars(&self) {
208 rap_trace!("====print_conponent_vars====");
209 for (key, value) in &self.components {
210 if value.len() > 1 {
211 rap_trace!("component: {:?} ", key);
212 for v in value {
213 if let Some(var_node) = self.vars.get(v) {
214 rap_trace!("Var: {:?}. {} ", v, var_node.get_range());
215 } else {
216 rap_trace!("Var: {:?} not found", v);
217 }
218 }
219 }
220 }
221 }
222 fn print_values_branchmap(&self) {
223 for (&key, value) in &self.values_branchmap {
224 rap_info!("vbm place: {:?}. {:?}\n ", key, value);
225 }
226 }
227 fn print_symbmap(&self) {
228 for (&key, value) in &self.symbmap {
229 for op in value.iter() {
230 if let Some(op) = self.oprs.get(*op) {
231 rap_trace!("symbmap op: {:?}. {:?}\n ", key, op);
232 } else {
233 rap_trace!("symbmap op: {:?} not found\n ", op);
234 }
235 }
236 }
237 }
238 fn print_defmap(&self) {
239 for (key, value) in self.defmap.clone() {
240 rap_trace!(
241 "place: {:?} def in stmt:{:?} {:?}",
242 key,
243 self.oprs[value].get_type_name(),
244 self.oprs[value].get_instruction()
245 );
246 }
247 }
248 fn print_compusemap(
249 &self,
250 component: &HashSet<&'tcx Place<'tcx>>,
251 comp_use_map: &HashMap<&'tcx Place<'tcx>, HashSet<usize>>,
252 ) {
253 for (key, value) in comp_use_map.clone() {
254 if component.contains(key) {
255 for v in value {
256 rap_trace!(
257 "compusemap place: {:?} use in stmt:{:?} {:?}",
258 key,
259 self.oprs[v].get_type_name(),
260 self.oprs[v].get_instruction()
261 );
262 }
263 }
264 }
265 }
266 fn print_usemap(&self) {
267 for (key, value) in self.usemap.clone() {
268 for v in value {
269 rap_trace!(
270 "place: {:?} use in stmt:{:?} {:?}",
271 key,
272 self.oprs[v].get_type_name(),
273 self.oprs[v].get_instruction()
274 );
275 }
276 }
277 }
278 pub fn get_vars(&self) -> &VarNodes<'tcx, T> {
289 &self.vars
290 }
291 pub fn add_varnode(&mut self, v: &'tcx Place<'tcx>) -> &mut VarNode<'tcx, T> {
292 let node = VarNode::new(v);
293 let node_ref: &mut VarNode<'tcx, T> = self.vars.entry(v).or_insert(node);
294 self.usemap.entry(v).or_insert(HashSet::new());
295
296 node_ref
297 }
298
299 pub fn build_graph(&mut self, body: &'tcx Body<'tcx>) {
300 self.arg_count = body.arg_count;
301 self.build_value_maps(body);
302 for block in body.basic_blocks.indices() {
303 let block_data = &body[block];
304 for statement in block_data.statements.iter() {
307 self.build_operations(statement, block);
308 }
309 self.build_terminator(block, block_data.terminator.as_ref().unwrap());
310 }
311
312 }
317
318 pub fn build_value_maps(&mut self, body: &'tcx Body<'tcx>) {
319 for bb in body.basic_blocks.indices() {
320 let block_data = &body[bb];
321 if let Some(terminator) = &block_data.terminator {
322 match &terminator.kind {
323 TerminatorKind::SwitchInt { discr, targets } => {
324 self.build_value_branch_map(body, discr, targets, bb, block_data);
325 }
326 TerminatorKind::Goto { target } => {
327 }
329 _ => {
330 }
335 }
336 }
337 }
338 }
341
342 pub fn build_value_branch_map(
343 &mut self,
344 body: &Body<'tcx>,
345 discr: &'tcx Operand<'tcx>,
346 targets: &'tcx SwitchTargets,
347 block: BasicBlock,
348 block_data: &'tcx BasicBlockData<'tcx>,
349 ) {
350 if let Operand::Copy(place) | Operand::Move(place) = discr {
352 if let Some((op1, op2, cmp_op)) = self.extract_condition(place, block_data) {
353 let const_op1 = op1.constant();
354 let const_op2 = op2.constant();
355 match (const_op1, const_op2) {
356 (Some(c1), Some(c2)) => {}
357 (Some(c), None) | (None, Some(c)) => {
358 let const_in_left: bool;
359 let variable;
360 if const_op1.is_some() {
361 const_in_left = true;
362 variable = match op2 {
363 Operand::Copy(p) | Operand::Move(p) => p,
364 _ => panic!("Expected a place"),
365 };
366 } else {
367 const_in_left = false;
368 variable = match op1 {
369 Operand::Copy(p) | Operand::Move(p) => p,
370 _ => panic!("Expected a place"),
371 };
372 }
373 self.add_varnode(variable);
374 rap_trace!("add_vbm_varnode{:?}\n", variable.clone());
375
376 let value = Self::convert_const(&c.const_).unwrap();
378 let const_range =
379 Range::new(value.clone(), value.clone(), RangeType::Unknown);
380 rap_trace!("cmp_op{:?}\n", cmp_op);
381 rap_trace!("const_in_left{:?}\n", const_in_left);
382 let mut true_range =
383 self.apply_comparison(value.clone(), cmp_op, true, const_in_left);
384 let mut false_range =
385 self.apply_comparison(value.clone(), cmp_op, false, const_in_left);
386 true_range.set_regular();
387 false_range.set_regular();
388 let target_vec = targets.all_targets();
391
392 let vbm = ValueBranchMap::new(
393 variable,
394 &target_vec[0],
395 &target_vec[1],
396 IntervalType::Basic(BasicInterval::new(false_range)),
397 IntervalType::Basic(BasicInterval::new(true_range)),
398 );
399 self.values_branchmap.insert(variable, vbm);
400 }
402 (None, None) => {
403 let CR = Range::new(T::min_value(), T::max_value(), RangeType::Unknown);
404
405 let p1 = match op1 {
406 Operand::Copy(p) | Operand::Move(p) => p,
407 _ => panic!("Expected a place"),
408 };
409 let p2 = match op2 {
410 Operand::Copy(p) | Operand::Move(p) => p,
411 _ => panic!("Expected a place"),
412 };
413 let target_vec = targets.all_targets();
414 self.add_varnode(&p1);
415 rap_trace!("add_vbm_varnode{:?}\n", p1.clone());
416
417 self.add_varnode(&p2);
418 rap_trace!("add_vbm_varnode{:?}\n", p2.clone());
419 let flipped_cmp_op = Self::flipped_binop(cmp_op).unwrap();
420 let reversed_cmp_op = Self::reverse_binop(cmp_op).unwrap();
421 let reversed_flippedd_cmp_op =
422 Self::flipped_binop(reversed_cmp_op).unwrap();
423 let STOp1 = IntervalType::Symb(SymbInterval::new(CR.clone(), p2, cmp_op));
424 let SFOp1 =
425 IntervalType::Symb(SymbInterval::new(CR.clone(), p2, flipped_cmp_op));
426 let STOp2 =
427 IntervalType::Symb(SymbInterval::new(CR.clone(), p1, reversed_cmp_op));
428 let SFOp2 = IntervalType::Symb(SymbInterval::new(
429 CR.clone(),
430 p1,
431 reversed_flippedd_cmp_op,
432 ));
433 rap_trace!("SFOp1{:?}\n", SFOp1);
434 rap_trace!("SFOp2{:?}\n", SFOp2);
435 rap_trace!("STOp1{:?}\n", STOp1);
436 rap_trace!("STOp2{:?}\n", STOp2);
437 let vbm_1 =
438 ValueBranchMap::new(p1, &target_vec[0], &target_vec[1], SFOp1, STOp1);
439 let vbm_2 =
440 ValueBranchMap::new(p2, &target_vec[0], &target_vec[1], SFOp2, STOp2);
441 self.values_branchmap.insert(&p1, vbm_1);
442 self.values_branchmap.insert(&p2, vbm_2);
443 self.switchbbs.insert(block, (*p1, *p2));
444 }
445 }
446 };
447 }
448 }
449 pub fn flipped_binop(op: BinOp) -> Option<BinOp> {
450 use BinOp::*;
451 Some(match op {
452 Eq => Eq,
453 Ne => Ne,
454 Lt => Ge,
455 Le => Gt,
456 Gt => Le,
457 Ge => Lt,
458 Add => Add,
459 Mul => Mul,
460 BitXor => BitXor,
461 BitAnd => BitAnd,
462 BitOr => BitOr,
463 _ => {
464 return None;
465 }
466 })
467 }
468 fn reverse_binop(op: BinOp) -> Option<BinOp> {
469 use BinOp::*;
470 Some(match op {
471 Eq => Eq,
472 Ne => Ne,
473 Lt => Gt,
474 Le => Ge,
475 Gt => Lt,
476 Ge => Le,
477 Add => Add,
478 Mul => Mul,
479 BitXor => BitXor,
480 BitAnd => BitAnd,
481 BitOr => BitOr,
482 _ => {
483 return None;
484 }
485 })
486 }
487 fn extract_condition(
488 &mut self,
489 place: &'tcx Place<'tcx>,
490 switch_block: &'tcx BasicBlockData<'tcx>,
491 ) -> Option<(&'tcx Operand<'tcx>, &'tcx Operand<'tcx>, BinOp)> {
492 for stmt in &switch_block.statements {
493 if let StatementKind::Assign(box (lhs, Rvalue::BinaryOp(bin_op, box (op1, op2)))) =
494 &stmt.kind
495 {
496 if lhs == place {
497 let mut return_op1: &Operand<'tcx> = &op1;
498 let mut return_op2: &Operand<'tcx> = &op2;
499 for stmt_original in &switch_block.statements {
500 if let StatementKind::Assign(box (lhs, Rvalue::Use(OP1))) =
501 &stmt_original.kind
502 {
503 if lhs.clone() == op1.place().unwrap() {
504 return_op1 = OP1;
505 }
506 }
507 }
508 if op2.constant().is_none() {
509 for stmt_original in &switch_block.statements {
510 if let StatementKind::Assign(box (lhs, Rvalue::Use(OP2))) =
511 &stmt_original.kind
512 {
513 if lhs.clone() == op2.place().unwrap() {
514 return_op2 = OP2;
515 }
516 }
517 }
518 }
519
520 return Some((return_op1, return_op2, *bin_op));
521 }
522 }
523 }
524 None
525 }
526
527 fn apply_comparison<U: IntervalArithmetic>(
528 &self,
529 constant: U,
530 cmp_op: BinOp,
531 is_true_branch: bool,
532 const_in_left: bool,
533 ) -> Range<U> {
534 match cmp_op {
535 BinOp::Lt => {
536 if is_true_branch ^ const_in_left {
537 Range::new(U::min_value(), constant.sub(U::one()), RangeType::Unknown)
538 } else {
539 Range::new(constant, U::max_value(), RangeType::Unknown)
540 }
541 }
542
543 BinOp::Le => {
544 if is_true_branch ^ const_in_left {
545 Range::new(U::min_value(), constant, RangeType::Unknown)
546 } else {
547 Range::new(constant.add(U::one()), U::max_value(), RangeType::Unknown)
548 }
549 }
550
551 BinOp::Gt => {
552 if is_true_branch ^ const_in_left {
553 Range::new(U::min_value(), constant, RangeType::Unknown)
554 } else {
555 Range::new(constant.add(U::one()), U::max_value(), RangeType::Unknown)
556 }
557 }
558
559 BinOp::Ge => {
560 if is_true_branch ^ const_in_left {
561 Range::new(U::min_value(), constant, RangeType::Unknown)
562 } else {
563 Range::new(constant, U::max_value().sub(U::one()), RangeType::Unknown)
564 }
565 }
566
567 BinOp::Eq => {
568 if is_true_branch ^ const_in_left {
569 Range::new(U::min_value(), constant, RangeType::Unknown)
570 } else {
571 Range::new(constant, U::max_value(), RangeType::Unknown)
572 }
573 }
574
575 _ => Range::new(constant.clone(), constant.clone(), RangeType::Empty),
576 }
577 }
578
579 fn build_value_goto_map(&self, block_index: BasicBlock, target: BasicBlock) {
580 rap_trace!(
581 "Building value map for Goto in block {:?} targeting block {:?}",
582 block_index,
583 target
584 );
585 }
586 pub fn build_varnodes(&mut self) {
587 for (name, node) in self.vars.iter_mut() {
589 let is_undefined = !self.defmap.contains_key(name);
590 node.init(is_undefined);
591 }
592 }
593 pub fn build_symbolic_intersect_map(&mut self) {
594 for i in 0..self.oprs.len() {
595 if let BasicOpKind::Essa(essaop) = &self.oprs[i] {
596 if let IntervalType::Symb(symbi) = essaop.get_intersect() {
597 let v = symbi.get_bound();
598 self.symbmap.entry(v).or_insert_with(HashSet::new).insert(i);
599 rap_trace!("symbmap insert {:?} {:?}\n", v, essaop);
600 }
601 }
602 }
603 }
605 pub fn build_use_map(
606 &mut self,
607 component: &HashSet<&'tcx Place<'tcx>>,
608 ) -> HashMap<&'tcx Place<'tcx>, HashSet<usize>> {
609 let mut comp_use_map = HashMap::new();
611 for &place in component {
612 if let Some(uses) = self.usemap.get(place) {
613 for op in uses.iter() {
614 let sink = self.oprs[*op].get_sink();
615 if component.contains(&sink) {
616 comp_use_map
617 .entry(place)
618 .or_insert_with(HashSet::new)
619 .insert(*op);
620 }
621 }
622 }
623 }
624
625 self.print_compusemap(component, &comp_use_map);
626 comp_use_map
627 }
628 pub fn build_terminator(&mut self, block: BasicBlock, terminator: &'tcx Terminator<'tcx>) {
629 match &terminator.kind {
630 TerminatorKind::Call {
631 func,
632 args,
633 destination,
634 target: _,
635 unwind: _,
636 fn_span: _,
637 call_source,
638 } => {
639 rap_trace!(
640 "TerminatorKind::Call in block {:?} with function {:?} destination {:?} args {:?}\n",
641 block,
642 func,
643 destination,
644 args
645 );
646 self.add_call_op(destination, args, terminator, func, block);
648 }
649 TerminatorKind::Return => {}
650 TerminatorKind::Goto { target } => {
651 rap_trace!(
652 "TerminatorKind::Goto in block {:?} targeting block {:?}\n",
653 block,
654 target
655 );
656 }
657 TerminatorKind::SwitchInt { discr, targets } => {
658 rap_trace!(
659 "TerminatorKind::SwitchInt in block {:?} with discr {:?} and targets {:?}\n",
660 block,
661 discr,
662 targets
663 );
664 }
665 _ => {
666 rap_trace!(
667 "Unsupported terminator kind in block {:?}: {:?}",
668 block,
669 terminator.kind
670 );
671 }
672 }
673 }
674 pub fn build_operations(&mut self, inst: &'tcx Statement<'tcx>, block: BasicBlock) {
675 match &inst.kind {
676 StatementKind::Assign(box (sink, rvalue)) => {
677 match rvalue {
678 Rvalue::BinaryOp(op, box (op1, op2)) => match op {
679 BinOp::Add
680 | BinOp::Sub
681 | BinOp::Mul
682 | BinOp::Div
683 | BinOp::Rem
684 | BinOp::AddUnchecked => {
685 self.add_binary_op(sink, inst, op1, op2, *op);
686 }
687 BinOp::AddWithOverflow => {
688 self.add_binary_op(sink, inst, op1, op2, *op);
689 }
690 BinOp::SubUnchecked => {
691 self.add_binary_op(sink, inst, op1, op2, *op);
692 }
693 BinOp::SubWithOverflow => {
694 self.add_binary_op(sink, inst, op1, op2, *op);
695 }
696 BinOp::MulUnchecked => {
697 self.add_binary_op(sink, inst, op1, op2, *op);
698 }
699 BinOp::MulWithOverflow => {
700 self.add_binary_op(sink, inst, op1, op2, *op);
701 }
702
703 _ => {}
704 },
705 Rvalue::UnaryOp(unop, operand) => {
706 self.add_unary_op(sink, inst, operand, *unop);
707 }
708 Rvalue::Aggregate(kind, operends) => {
709 match **kind {
710 AggregateKind::Adt(def_id, _, _, _, _) => {
711 if def_id == self.essa {
712 self.add_essa_op(sink, inst, operends, block);
713 }
715 if def_id == self.ssa {
716 self.add_ssa_op(sink, inst, operends);
717 }
719 }
720 _ => {}
721 }
722 }
723 Rvalue::Use(operend) => {
724 self.add_use_op(sink, inst, operend);
725 }
726 _ => {}
727 }
728 }
729 _ => {}
730 }
731 }
732 fn add_call_op(
736 &mut self,
737 sink: &'tcx Place<'tcx>,
738 args: &'tcx Box<[Spanned<Operand<'tcx>>]>,
739 terminator: &'tcx Terminator<'tcx>,
740 func: &'tcx Operand<'tcx>,
741 block: BasicBlock,
742 ) {
743 rap_trace!("add_call_op for sink: {:?} {:?}\n", sink, terminator);
744 let sink_node = self.add_varnode(&sink);
745
746 let mut func_def_id = None;
750 if let Operand::Constant(box const_operand) = func {
751 let fn_ty = const_operand.ty();
752 if let ty::TyKind::FnDef(def_id, _substs) = fn_ty.kind() {
753 func_def_id = Some(def_id);
755 }
756 }
757
758 if let Some(def_id) = func_def_id {
759 rap_trace!(
760 "TerminatorKind::Call in block {:?} with DefId {:?}\n",
761 block,
762 def_id
763 );
764 } else {
766 rap_trace!(
767 "TerminatorKind::Call in block {:?} is an indirect call (e.g., function pointer)\n",
768 block
769 );
770 }
773 let mut constant_count = 0 as usize;
774 let arg_count = args.len();
775 let mut arg_operands: Vec<Operand<'tcx>> = Vec::new();
776 for op in args.iter() {
777 match &op.node {
778 Operand::Copy(place) | Operand::Move(place) => {
779 arg_operands.push(op.node.clone());
780
781 self.add_varnode(place);
782 self.usemap
783 .entry(place)
784 .or_default()
785 .insert(self.oprs.len());
786 }
787
788 Operand::Constant(_) => {
789 arg_operands.push(op.node.clone());
792 constant_count += 1;
793 }
794 }
795 }
796 {
797 let bi = BasicInterval::new(Range::default(T::min_value()));
798
799 let call_op = CallOp::new(
800 IntervalType::Basic(bi),
801 &sink,
802 terminator, arg_operands,
804 *func_def_id.unwrap(), );
806 rap_debug!("call_op: {:?}\n", call_op);
807 let bop_index = self.oprs.len();
808
809 self.oprs.push(BasicOpKind::Call(call_op));
811
812 self.defmap.insert(&sink, bop_index);
814 if constant_count == arg_count {
815 rap_trace!("all args are constants\n");
816 self.const_func_place.insert(&sink, bop_index);
817 }
818 }
819 }
820 fn add_ssa_op(
821 &mut self,
822 sink: &'tcx Place<'tcx>,
823 inst: &'tcx Statement<'tcx>,
824 operands: &'tcx IndexVec<FieldIdx, Operand<'tcx>>,
825 ) {
826 rap_trace!("ssa_op{:?}\n", inst);
827
828 let sink_node = self.add_varnode(sink);
829 rap_trace!("addsink_in_ssa_op{:?}\n", sink_node);
830
831 let BI: BasicInterval<T> = BasicInterval::new(Range::default(T::min_value()));
832 let mut phiop = PhiOp::new(IntervalType::Basic(BI), sink, inst, 0);
833 let bop_index = self.oprs.len();
834 for i in 0..operands.len() {
835 let source = match &operands[FieldIdx::from_usize(i)] {
836 Operand::Copy(place) | Operand::Move(place) => {
837 self.add_varnode(place);
838 Some(place)
839 }
840 _ => None,
841 };
842 if let Some(source) = source {
843 self.add_varnode(source);
844 phiop.add_source(source);
845 rap_trace!("addvar_in_ssa_op{:?}\n", source);
846 self.usemap.entry(source).or_default().insert(bop_index);
847 }
848 }
849 self.oprs.push(BasicOpKind::Phi(phiop));
852
853 self.defmap.insert(sink, bop_index);
856 }
857 fn add_use_op(
858 &mut self,
859 sink: &'tcx Place<'tcx>,
860 inst: &'tcx Statement<'tcx>,
861 op: &'tcx Operand<'tcx>,
862 ) {
863 rap_trace!("use_op{:?}\n", inst);
864
865 let BI: BasicInterval<T> = BasicInterval::new(Range::default(T::min_value()));
866 let mut source: Option<&'tcx Place<'tcx>> = None;
867
868 match op {
869 Operand::Copy(place) | Operand::Move(place) => {
870 if sink.local == RETURN_PLACE && sink.projection.is_empty() {
871 self.rerurn_places.insert(place);
872 let sink_node = self.add_varnode(sink);
873
874 rap_debug!("add_return_place{:?}\n", place);
875 } else {
876 self.add_varnode(place);
877 source = Some(place);
878 if let Some(source) = source {
879 rap_trace!("addvar_in_use_op{:?}\n", source);
880 let sink_node = self.add_varnode(sink);
881
882 let useop =
883 UseOp::new(IntervalType::Basic(BI), sink, inst, Some(source), None);
884 let bop_index = self.oprs.len();
886
887 self.oprs.push(BasicOpKind::Use(useop));
888 self.usemap.entry(source).or_default().insert(bop_index);
890
891 self.defmap.insert(sink, bop_index);
892 }
893 }
894 }
895 Operand::Constant(constant) => {
896 rap_trace!("add_constant_op{:?}\n", inst);
897 let Some(c) = op.constant() else {
898 rap_trace!("add_constant_op: constant is None\n");
899 return;
900 };
901 let useop = UseOp::new(IntervalType::Basic(BI), sink, inst, None, Some(c.const_));
902 let bop_index = self.oprs.len();
904
905 self.oprs.push(BasicOpKind::Use(useop));
906 self.defmap.insert(sink, bop_index);
909 let sink_node = self.add_varnode(sink);
910
911 if let Some(value) = Self::convert_const(&c.const_) {
912 sink_node.set_range(Range::new(
913 value.clone(),
914 value.clone(),
915 RangeType::Regular,
916 ));
917 rap_trace!("set_const {:?} value: {:?}\n", sink_node, value);
918 } else {
920 sink_node.set_range(Range::default(T::min_value()));
921 };
922 }
923 }
924 }
925 fn add_essa_op(
926 &mut self,
927 sink: &'tcx Place<'tcx>,
928
929 inst: &'tcx Statement<'tcx>,
930 operands: &'tcx IndexVec<FieldIdx, Operand<'tcx>>,
931 block: BasicBlock,
932 ) {
933 let sink_node = self.add_varnode(sink);
935 let loc_1: usize = 0;
939 let loc_2: usize = 1;
940 let source1 = match &operands[FieldIdx::from_usize(loc_1)] {
941 Operand::Copy(place) | Operand::Move(place) => {
942 self.add_varnode(place);
943 Some(place)
944 }
945 _ => None,
946 };
947 let op = &operands[FieldIdx::from_usize(loc_2)];
948 let bop_index = self.oprs.len();
949
950 let BI: IntervalType<'_, T>;
951 if let Operand::Constant(c) = op {
952 let vbm = self.values_branchmap.get(source1.unwrap()).unwrap();
953 if block == *vbm.get_bb_true() {
954 rap_trace!("essa_op true branch{:?}\n", block);
955 BI = vbm.get_itv_t();
956 } else {
957 rap_trace!("essa_op false branch{:?}\n", block);
958 BI = vbm.get_itv_f();
959 }
960 self.usemap
961 .entry(source1.unwrap())
962 .or_default()
963 .insert(bop_index);
964
965 let essaop = EssaOp::new(BI, sink, inst, source1.unwrap(), 0, false);
966 rap_trace!(
967 "addvar_in_essa_op {:?} from const {:?}\n",
968 essaop,
969 source1.unwrap()
970 );
971
972 self.oprs.push(BasicOpKind::Essa(essaop));
975 self.defmap.insert(sink, bop_index);
982 } else {
983 let vbm = self.values_branchmap.get(source1.unwrap()).unwrap();
984 if block == *vbm.get_bb_true() {
985 rap_trace!("essa_op true branch{:?}\n", block);
986 BI = vbm.get_itv_t();
987 } else {
988 rap_trace!("essa_op false branch{:?}\n", block);
989 BI = vbm.get_itv_f();
990 }
991 let source2 = match op {
992 Operand::Copy(place) | Operand::Move(place) => {
993 self.add_varnode(place);
994 Some(place)
995 }
996 _ => None,
997 };
998 self.usemap
999 .entry(source1.unwrap())
1000 .or_default()
1001 .insert(bop_index);
1002 let essaop = EssaOp::new(BI, sink, inst, source1.unwrap(), 0, true);
1007 rap_trace!(
1009 "addvar_in_essa_op {:?} from {:?}\n",
1010 essaop,
1011 source1.unwrap()
1012 );
1013
1014 self.oprs.push(BasicOpKind::Essa(essaop));
1015 self.defmap.insert(sink, bop_index);
1022 }
1023 }
1024 fn add_unary_op(
1025 &mut self,
1026 sink: &'tcx Place<'tcx>,
1027 inst: &'tcx Statement<'tcx>,
1028 operand: &'tcx Operand<'tcx>,
1029 op: UnOp,
1030 ) {
1031 rap_trace!("unary_op{:?}\n", inst);
1032
1033 let sink_node = self.add_varnode(sink);
1034 rap_trace!("addsink_in_unary_op{:?}\n", sink_node);
1035
1036 let BI: BasicInterval<T> = BasicInterval::new(Range::default(T::min_value()));
1037 let loc_1: usize = 0;
1038
1039 let source = match operand {
1040 Operand::Copy(place) | Operand::Move(place) => {
1041 self.add_varnode(place);
1042 Some(place)
1043 }
1044 _ => None,
1045 };
1046
1047 rap_trace!("addvar_in_unary_op{:?}\n", source.unwrap());
1048 self.add_varnode(&source.unwrap());
1049
1050 let unaryop = UnaryOp::new(IntervalType::Basic(BI), sink, inst, source.unwrap(), op);
1051 let bop_index = self.oprs.len();
1053
1054 self.oprs.push(BasicOpKind::Unary(unaryop));
1055 self.defmap.insert(sink, bop_index);
1058 }
1059
1060 fn add_binary_op(
1061 &mut self,
1062 sink: &'tcx Place<'tcx>,
1063 inst: &'tcx Statement<'tcx>,
1064 op1: &'tcx Operand<'tcx>,
1065 op2: &'tcx Operand<'tcx>,
1066 bin_op: BinOp,
1067 ) {
1068 rap_trace!("binary_op{:?}\n", inst);
1069 let sink_node = self.add_varnode(sink);
1070 rap_trace!("addsink_in_binary_op{:?}\n", sink_node);
1071 let bop_index = self.oprs.len();
1072 let BI: BasicInterval<T> = BasicInterval::new(Range::default(T::min_value()));
1073
1074 let source1_place = match op1 {
1075 Operand::Copy(place) | Operand::Move(place) => {
1076 self.add_varnode(place);
1077 rap_trace!("addvar_in_binary_op{:?}\n", place);
1078
1079 Some(place)
1080 }
1081 Operand::Constant(_) => None,
1082 };
1083
1084 match op2 {
1085 Operand::Copy(place) | Operand::Move(place) => {
1086 self.add_varnode(place);
1087 rap_trace!("addvar_in_binary_op{:?}\n", place);
1088
1089 let source2_place = Some(place);
1090 let BOP = BinaryOp::new(
1091 IntervalType::Basic(BI),
1092 sink,
1093 inst,
1094 source1_place,
1095 source2_place,
1096 None,
1097 bin_op.clone(),
1098 );
1099 self.oprs.push(BasicOpKind::Binary(BOP));
1100 self.defmap.insert(sink, bop_index);
1102 if let Some(place) = source1_place {
1103 self.usemap.entry(place).or_default().insert(bop_index);
1104 }
1105
1106 if let Some(place) = source2_place {
1107 self.usemap.entry(place).or_default().insert(bop_index);
1108 }
1109 }
1110 Operand::Constant(c) => {
1111 let BOP = BinaryOp::new(
1113 IntervalType::Basic(BI),
1114 sink,
1115 inst,
1116 source1_place,
1117 None,
1118 Some(c.const_),
1119 bin_op.clone(),
1120 );
1121 self.oprs.push(BasicOpKind::Binary(BOP));
1122 self.defmap.insert(sink, bop_index);
1124 if let Some(place) = source1_place {
1125 self.usemap.entry(place).or_default().insert(bop_index);
1126 }
1127 }
1128 };
1129
1130 }
1136 fn fix_intersects(&mut self, component: &HashSet<&'tcx Place<'tcx>>) {
1137 for &place in component.iter() {
1138 if let Some(sit) = self.symbmap.get_mut(place) {
1140 let node = self.vars.get(place).unwrap();
1141
1142 for &op in sit.iter() {
1143 let op = &mut self.oprs[op];
1144 let sinknode = self.vars.get(op.get_sink()).unwrap();
1145
1146 op.op_fix_intersects(node, sinknode);
1147 }
1148 }
1149 }
1150 }
1151 pub fn widen(
1152 &mut self,
1153 op: usize,
1154 cg_map: &FxHashMap<DefId, Rc<RefCell<ConstraintGraph<'tcx, T>>>>,
1155 vars_map: &mut FxHashMap<DefId, Vec<RefCell<VarNodes<'tcx, T>>>>,
1156 ) -> bool {
1157 let op_kind = &self.oprs[op];
1160 let sink = op_kind.get_sink();
1161 let old_interval = self.vars.get(sink).unwrap().get_range().clone();
1162
1163 let estimated_interval = match op_kind {
1166 BasicOpKind::Call(call_op) => {
1167 call_op.eval_call(&self.vars, cg_map, vars_map)
1169 }
1170 _ => {
1171 op_kind.eval(&self.vars)
1173 }
1174 };
1175 let old_lower = old_interval.get_lower();
1176 let old_upper = old_interval.get_upper();
1177 let new_lower = estimated_interval.get_lower();
1178 let new_upper = estimated_interval.get_upper();
1179 let updated = if old_interval.is_unknown() {
1195 estimated_interval.clone()
1196 } else if new_lower < old_lower && new_upper > old_upper {
1197 Range::new(T::min_value(), T::max_value(), RangeType::Regular)
1198 } else if new_lower < old_lower {
1199 Range::new(T::min_value(), old_upper.clone(), RangeType::Regular)
1200 } else if new_upper > old_upper {
1201 Range::new(old_lower.clone(), T::max_value(), RangeType::Regular)
1202 } else {
1203 old_interval.clone()
1204 };
1205
1206 self.vars.get_mut(sink).unwrap().set_range(updated.clone());
1207 rap_trace!(
1208 "WIDEN in {} set {:?}: E {} U {} {} -> {}",
1209 op,
1210 sink,
1211 estimated_interval,
1212 updated,
1213 old_interval,
1214 updated
1215 );
1216
1217 old_interval != updated
1218 }
1219 pub fn narrow(
1220 &mut self,
1221 op: usize,
1222 cg_map: &FxHashMap<DefId, Rc<RefCell<ConstraintGraph<'tcx, T>>>>,
1223 vars_map: &mut FxHashMap<DefId, Vec<RefCell<VarNodes<'tcx, T>>>>,
1224 ) -> bool {
1225 let op_kind = &self.oprs[op];
1226 let sink = op_kind.get_sink();
1227 let old_interval = self.vars.get(sink).unwrap().get_range().clone();
1228
1229 let estimated_interval = match op_kind {
1231 BasicOpKind::Call(call_op) => {
1232 call_op.eval_call(&self.vars, cg_map, vars_map)
1234 }
1235 _ => {
1236 op_kind.eval(&self.vars)
1238 }
1239 };
1240 let old_lower = old_interval.get_lower();
1241 let old_upper = old_interval.get_upper();
1242 let new_lower = estimated_interval.get_lower();
1243 let new_upper = estimated_interval.get_upper();
1244 let mut final_lower = old_lower.clone();
1247 let mut final_upper = old_upper.clone();
1248 if old_lower.clone() == T::min_value() && new_lower.clone() > T::min_value() {
1249 final_lower = new_lower.clone();
1250 } else if old_lower.clone() <= new_lower.clone() {
1253 final_lower = new_lower.clone();
1254
1255 };
1258 if old_upper.clone() == T::max_value() && new_upper.clone() < T::max_value() {
1259 final_upper = new_upper.clone();
1260 } else if old_upper.clone() >= new_upper.clone() {
1263 final_upper = new_upper.clone();
1264 }
1267 let tightened = Range::new(final_lower, final_upper, RangeType::Regular);
1268
1269 self.vars
1270 .get_mut(sink)
1271 .unwrap()
1272 .set_range(tightened.clone());
1273 rap_trace!(
1274 "NARROW in {} set {:?}: E {} U {} {} -> {}",
1275 op,
1276 sink,
1277 estimated_interval,
1278 tightened,
1279 old_interval,
1280 tightened
1281 );
1282 let hasChanged = old_interval != tightened;
1283
1284 hasChanged
1285 }
1286
1287 fn pre_update(
1288 &mut self,
1289 comp_use_map: &HashMap<&'tcx Place<'tcx>, HashSet<usize>>,
1290 entry_points: &HashSet<&'tcx Place<'tcx>>,
1291 cg_map: &FxHashMap<DefId, Rc<RefCell<ConstraintGraph<'tcx, T>>>>,
1292 vars_map: &mut FxHashMap<DefId, Vec<RefCell<VarNodes<'tcx, T>>>>,
1293 ) {
1294 let mut worklist: Vec<&'tcx Place<'tcx>> = entry_points.iter().cloned().collect();
1295
1296 while let Some(place) = worklist.pop() {
1297 if let Some(op_set) = comp_use_map.get(place) {
1298 for &op in op_set {
1299 if self.widen(op, cg_map, vars_map) {
1300 let sink = self.oprs[op].get_sink();
1301 rap_trace!("W {:?}\n", sink);
1302 worklist.push(sink);
1304 }
1305 }
1306 }
1307 }
1308 }
1309
1310 fn pos_update(
1311 &mut self,
1312 comp_use_map: &HashMap<&'tcx Place<'tcx>, HashSet<usize>>,
1313 entry_points: &HashSet<&'tcx Place<'tcx>>,
1314 cg_map: &FxHashMap<DefId, Rc<RefCell<ConstraintGraph<'tcx, T>>>>,
1315 vars_map: &mut FxHashMap<DefId, Vec<RefCell<VarNodes<'tcx, T>>>>,
1316 ) {
1317 let mut worklist: Vec<&'tcx Place<'tcx>> = entry_points.iter().cloned().collect();
1318 let mut iteration = 0;
1319 while let Some(place) = worklist.pop() {
1320 iteration += 1;
1321 if (iteration > 1000) {
1322 rap_trace!("Iteration limit reached, breaking out of pos_update\n");
1323 break;
1324 }
1325
1326 if let Some(op_set) = comp_use_map.get(place) {
1327 for &op in op_set {
1328 if self.narrow(op, cg_map, vars_map) {
1329 let sink = self.oprs[op].get_sink();
1330 rap_trace!("N {:?}\n", sink);
1331
1332 worklist.push(sink);
1334 }
1335 }
1336 }
1337 }
1338 rap_trace!("pos_update finished after {} iterations\n", iteration);
1339 }
1340 fn generate_active_vars(
1341 &mut self,
1342 component: &HashSet<&'tcx Place<'tcx>>,
1343 active_vars: &mut HashSet<&'tcx Place<'tcx>>,
1344 cg_map: &FxHashMap<DefId, Rc<RefCell<ConstraintGraph<'tcx, T>>>>,
1345 vars_map: &mut FxHashMap<DefId, Vec<RefCell<VarNodes<'tcx, T>>>>,
1346 ) {
1347 for place in component {
1348 let node = self.vars.get(place).unwrap();
1349 }
1350 }
1351 fn generate_entry_points(
1352 &mut self,
1353 component: &HashSet<&'tcx Place<'tcx>>,
1354 entry_points: &mut HashSet<&'tcx Place<'tcx>>,
1355 cg_map: &FxHashMap<DefId, Rc<RefCell<ConstraintGraph<'tcx, T>>>>,
1356 vars_map: &mut FxHashMap<DefId, Vec<RefCell<VarNodes<'tcx, T>>>>,
1357 ) {
1358 for &place in component {
1359 let op = self.defmap.get(place).unwrap();
1360 if let BasicOpKind::Essa(essaop) = &mut self.oprs[*op] {
1361 if essaop.is_unresolved() {
1362 let source = essaop.get_source();
1363 let new_range = essaop.eval(&self.vars);
1364 let sink_node = self.vars.get_mut(source).unwrap();
1365 sink_node.set_range(new_range);
1366 }
1367 essaop.mark_resolved();
1368 }
1369 if (!self.vars[place].get_range().is_unknown()) {
1370 entry_points.insert(place);
1371 }
1372 }
1373 }
1374 fn propagate_to_next_scc(
1375 &mut self,
1376 component: &HashSet<&'tcx Place<'tcx>>,
1377 cg_map: &FxHashMap<DefId, Rc<RefCell<ConstraintGraph<'tcx, T>>>>,
1378 vars_map: &mut FxHashMap<DefId, Vec<RefCell<VarNodes<'tcx, T>>>>,
1379 ) {
1380 for &place in component.iter() {
1381 let node = self.vars.get_mut(place).unwrap();
1382 for &op in self.usemap.get(place).unwrap().iter() {
1383 let op_kind = &mut self.oprs[op];
1384 let sink = op_kind.get_sink();
1385 if !component.contains(sink) {
1386 let new_range = op_kind.eval(&self.vars);
1387 let new_range = match op_kind {
1388 BasicOpKind::Call(call_op) => {
1389 call_op.eval_call(&self.vars, cg_map, vars_map)
1390 }
1391 _ => {
1392 op_kind.eval(&self.vars)
1394 }
1395 };
1396 let sink_node = self.vars.get_mut(sink).unwrap();
1397 rap_trace!(
1398 "prop component {:?} set {} to {:?} through {:?}\n",
1399 component,
1400 new_range,
1401 sink,
1402 op_kind.get_instruction()
1403 );
1404 sink_node.set_range(new_range);
1405 if let BasicOpKind::Essa(essaop) = op_kind {
1410 if essaop.get_intersect().get_range().is_unknown() {
1411 essaop.mark_unresolved();
1412 }
1413 }
1414 }
1415 }
1416 }
1417 }
1418 pub fn solve_const_func_call(
1419 &mut self,
1420 cg_map: &FxHashMap<DefId, Rc<RefCell<ConstraintGraph<'tcx, T>>>>,
1421 vars_map: &mut FxHashMap<DefId, Vec<RefCell<VarNodes<'tcx, T>>>>,
1422 ) {
1423 for (&sink, op) in &self.const_func_place {
1424 rap_trace!(
1425 "solve_const_func_call for sink {:?} with opset {:?}\n",
1426 sink,
1427 op
1428 );
1429 if let BasicOpKind::Call(call_op) = &self.oprs[*op] {
1430 let new_range = call_op.eval_call(&self.vars, cg_map, vars_map);
1431 rap_trace!("Setting range for {:?} to {:?}\n", sink, new_range);
1432 self.vars.get_mut(sink).unwrap().set_range(new_range);
1433 }
1434 }
1435 }
1436 pub fn store_vars(&mut self, varnodes_vec: &mut Vec<RefCell<VarNodes<'tcx, T>>>) {
1437 rap_trace!("Storing vars\n");
1438 let old_vars = self.vars.clone();
1439 varnodes_vec.push(RefCell::new(old_vars));
1440 }
1441 pub fn reset_vars(&mut self, varnodes_vec: &mut Vec<RefCell<VarNodes<'tcx, T>>>) {
1442 rap_trace!("Resetting vars\n");
1443 self.vars = varnodes_vec[0].borrow_mut().clone();
1444 }
1445 pub fn find_intervals(
1446 &mut self,
1447 cg_map: &FxHashMap<DefId, Rc<RefCell<ConstraintGraph<'tcx, T>>>>,
1448 vars_map: &mut FxHashMap<DefId, Vec<RefCell<VarNodes<'tcx, T>>>>,
1449 ) {
1450 self.solve_const_func_call(cg_map, vars_map);
1454 self.numSCCs = self.worklist.len();
1455 let mut seen = HashSet::new();
1456 let mut components = Vec::new();
1457
1458 for &place in self.worklist.iter().rev() {
1459 if seen.contains(place) {
1460 continue;
1461 }
1462
1463 if let Some(component) = self.components.get(place) {
1464 for &p in component {
1465 seen.insert(p);
1466 }
1467
1468 components.push(component.clone());
1469 }
1470 }
1471 rap_trace!("TOLO:{:?}\n", components);
1472
1473 for component in components {
1474 rap_trace!("===start component {:?}===\n", component);
1475 if component.len() == 1 {
1476 self.numAloneSCCs += 1;
1477
1478 self.fix_intersects(&component);
1479
1480 let variable: &Place<'tcx> = *component.iter().next().unwrap();
1481 let varnode = self.vars.get_mut(variable).unwrap();
1482 if varnode.get_range().is_unknown() {
1483 varnode.set_default();
1484 }
1485 } else {
1486 let comp_use_map = self.build_use_map(&component);
1488 let mut entry_points = HashSet::new();
1490 self.generate_entry_points(&component, &mut entry_points, cg_map, vars_map);
1493 rap_trace!("entry_points {:?} \n", entry_points);
1494 self.pre_update(&comp_use_map, &entry_points, cg_map, vars_map);
1496 self.fix_intersects(&component);
1497
1498 let mut active_vars = HashSet::new();
1506 self.generate_active_vars(&component, &mut active_vars, cg_map, vars_map);
1507 self.pos_update(&comp_use_map, &entry_points, cg_map, vars_map);
1508 }
1509 self.propagate_to_next_scc(&component, cg_map, vars_map);
1510 }
1511 self.merge_return_places();
1512 let Some(varnodes_vec) = vars_map.get_mut(&self.self_def_id) else {
1513 rap_trace!(
1514 "No variable map entry for this function {:?}, skipping Nuutila\n",
1515 self.self_def_id
1516 );
1517 return;
1518 };
1519 self.store_vars(varnodes_vec);
1520 }
1521 pub fn merge_return_places(&mut self) {
1522 rap_trace!("====Merging return places====\n");
1523 for &place in self.rerurn_places.iter() {
1524 rap_debug!("merging return place {:?}\n", place);
1525 let mut merged_range = Range::default(T::min_value());
1526 if let Some(opset) = self.vars.get(place) {
1527 merged_range = merged_range.unionwith(opset.get_range());
1528 }
1529 if let Some(return_node) = self.vars.get_mut(&Place::return_place()) {
1530 rap_debug!("Assigning final merged range {} to _0", merged_range);
1531 return_node.set_range(merged_range);
1532 } else {
1533 rap_trace!(
1537 "Warning: RETURN_PLACE (_0) not found in self.vars. Cannot assign merged return range."
1538 );
1539 }
1540 }
1541 }
1542
1543 pub fn add_control_dependence_edges(&mut self) {
1544 rap_trace!("====Add control dependence edges====\n");
1545 self.print_symbmap();
1546 for (&place, opset) in self.symbmap.iter() {
1547 for &op in opset.iter() {
1548 let bop_index = self.oprs.len();
1549 let opkind = &self.oprs[op];
1550 let control_edge = ControlDep::new(
1551 IntervalType::Basic(BasicInterval::default()),
1552 opkind.get_sink(),
1553 opkind.get_instruction().unwrap(),
1554 place,
1555 );
1556 rap_trace!(
1557 "Adding control_edge {:?} for place {:?} at index {}\n",
1558 control_edge,
1559 place,
1560 bop_index
1561 );
1562 self.oprs.push(BasicOpKind::ControlDep(control_edge));
1563 self.usemap.entry(place).or_default().insert(bop_index);
1564 }
1565 }
1566 }
1567 pub fn del_control_dependence_edges(&mut self) {
1568 rap_trace!("====Delete control dependence edges====\n");
1569
1570 let mut remove_from = self.oprs.len();
1571 while remove_from > 0 {
1572 match &self.oprs[remove_from - 1] {
1573 BasicOpKind::ControlDep(dep) => {
1574 let place = dep.source;
1575 rap_trace!(
1576 "removing control_edge at idx {}: {:?}\n",
1577 remove_from - 1,
1578 dep
1579 );
1580 if let Some(set) = self.usemap.get_mut(&place) {
1581 set.remove(&(remove_from - 1));
1582 if set.is_empty() {
1583 self.usemap.remove(&place);
1584 }
1585 }
1586 remove_from -= 1;
1587 }
1588 _ => break,
1589 }
1590 }
1591
1592 self.oprs.truncate(remove_from);
1593 }
1594
1595 pub fn build_nuutila(&mut self, single: bool) {
1596 rap_trace!("====Building graph====\n");
1597 self.print_usemap();
1598 self.build_symbolic_intersect_map();
1599
1600 if single {
1601 } else {
1602 for place in self.vars.keys().copied() {
1603 self.dfs.insert(place, -1);
1604 }
1605
1606 self.add_control_dependence_edges();
1607
1608 let places: Vec<_> = self.vars.keys().copied().collect();
1609 rap_trace!("places{:?}\n", places);
1610 for place in places {
1611 if self.dfs[&place] < 0 {
1612 rap_trace!("start place{:?}\n", place);
1613 let mut stack = Vec::new();
1614 self.visit(place, &mut stack);
1615 }
1616 }
1617
1618 self.del_control_dependence_edges();
1619 }
1620 rap_trace!("components{:?}\n", self.components);
1621 rap_trace!("worklist{:?}\n", self.worklist);
1622 rap_trace!("dfs{:?}\n", self.dfs);
1623 }
1624 pub fn visit(&mut self, place: &'tcx Place<'tcx>, stack: &mut Vec<&'tcx Place<'tcx>>) {
1625 self.dfs.entry(place).and_modify(|v| *v = self.index);
1626 self.index += 1;
1627 self.root.insert(place, place);
1628 let uses = self.usemap.get(place).unwrap().clone();
1629 for op in uses {
1630 let name = self.oprs[op].get_sink();
1631 rap_trace!("place {:?} get name{:?}\n", place, name);
1632 if self.dfs.get(name).copied().unwrap_or(-1) < 0 {
1633 self.visit(name, stack);
1634 }
1635
1636 if (!self.in_component.contains(name)
1637 && self.dfs[self.root[place]] >= self.dfs[self.root[name]])
1638 {
1639 *self.root.get_mut(place).unwrap() = self.root.get(name).copied().unwrap();
1640
1641 }
1643 }
1644
1645 if self.root.get(place).copied().unwrap() == place {
1646 self.worklist.push_back(place);
1647
1648 let mut scc = HashSet::new();
1649 scc.insert(place);
1650
1651 self.in_component.insert(place);
1652
1653 while let Some(top) = stack.last() {
1654 if self.dfs.get(top).copied().unwrap_or(-1) > self.dfs.get(place).copied().unwrap()
1655 {
1656 let node = stack.pop().unwrap();
1657 self.in_component.insert(node);
1658
1659 scc.insert(node);
1660 } else {
1661 break;
1662 }
1663 }
1664
1665 self.components.insert(place, scc);
1666 } else {
1667 stack.push(place);
1668 }
1669 }
1670 pub fn get_symbolicexpression(&self, place: &'tcx Place<'tcx>) -> Option<SymbolicExpr<'tcx>> {
1671 let mut memo: HashMap<&'tcx Place<'tcx>, Option<SymbolicExpr<'tcx>>> = HashMap::new();
1672 let mut in_progress: HashSet<&'tcx Place<'tcx>> = HashSet::new();
1673
1674 self.get_symbolic_expression_recursive(place, &mut memo, &mut in_progress)
1675 }
1676
1677 fn get_symbolic_expression_recursive(
1678 &self,
1679 place: &'tcx Place<'tcx>,
1680 memo: &mut HashMap<&'tcx Place<'tcx>, Option<SymbolicExpr<'tcx>>>,
1681 in_progress: &mut HashSet<&'tcx Place<'tcx>>,
1682 ) -> Option<SymbolicExpr<'tcx>> {
1683 if memo.contains_key(place) {
1684 return memo.get(place).cloned().unwrap();
1685 }
1686
1687 if !in_progress.insert(place) {
1688 rap_trace!("Cyclic dependency detected for place: {:?}", place);
1689 let expr = Some(SymbolicExpr::Unknown(UnknownReason::CyclicDependency));
1690 memo.insert(place, expr.clone());
1691 return expr;
1692 }
1693
1694 let result = if place.projection.is_empty() {
1695 if let Some(&op_idx) = self.defmap.get(place) {
1696 let op_kind = &self.oprs[op_idx];
1697 self.op_kind_to_symbolic_expr(op_kind, memo, in_progress)
1698 } else if place.local.as_usize() > 0 {
1699 rap_trace!(
1700 "Place {:?} not found in defmap, assuming it's an argument.",
1701 place
1702 );
1703 Some(SymbolicExpr::Argument(*place))
1704 } else {
1705 let op_idx = self.defmap.get(place);
1706 let op_kind = &self.oprs[*op_idx.unwrap()];
1707
1708 rap_trace!(
1709 "Local {:?} not defined by an operation and not considered an argument. Returning Unknown.",
1710 place
1711 );
1712 Some(SymbolicExpr::Unknown(UnknownReason::CyclicDependency))
1713 }
1714 } else {
1715 let mut current_expr =
1716 match self.get_symbolic_expression_recursive(place, memo, in_progress) {
1717 Some(e) => e,
1718 None => {
1719 in_progress.remove(place);
1720 memo.insert(place, None);
1721 return None;
1722 }
1723 };
1724
1725 for proj_elem in place.projection.iter() {
1726 match proj_elem {
1727 PlaceElem::Deref => {
1728 current_expr = SymbolicExpr::Deref(Box::new(current_expr));
1730 }
1731 PlaceElem::Field(field_idx, _ty) => {
1732 rap_trace!(
1733 "Unsupported PlaceElem::Field {:?} at {:?}. Returning Unknown for SymbolicExpr.",
1734 field_idx,
1735 place
1736 );
1737 in_progress.remove(place);
1738 memo.insert(
1739 place,
1740 Some(SymbolicExpr::Unknown(UnknownReason::CyclicDependency)),
1741 );
1742 return Some(SymbolicExpr::Unknown(UnknownReason::CyclicDependency));
1743 }
1744 PlaceElem::Index(index_place) => {
1745 return Some(SymbolicExpr::Unknown(UnknownReason::Unsupported));
1759 }
1760 PlaceElem::ConstantIndex {
1761 offset,
1762 min_length,
1763 from_end,
1764 } => {
1765 rap_trace!(
1766 "Unsupported PlaceElem::ConstantIndex at {:?}. Requires TyCtxt to create Const<'tcx>. Returning Unknown.",
1767 place
1768 );
1769 in_progress.remove(place);
1770 memo.insert(
1771 place,
1772 Some(SymbolicExpr::Unknown(UnknownReason::CyclicDependency)),
1773 );
1774 return Some(SymbolicExpr::Unknown(UnknownReason::CyclicDependency));
1775 }
1776
1777 _ => {
1778 rap_trace!(
1779 "Unsupported PlaceElem kind at {:?}. Cannot convert to SymbolicExpr. Returning Unknown.",
1780 place
1781 );
1782 in_progress.remove(place);
1783 memo.insert(
1784 place,
1785 Some(SymbolicExpr::Unknown(UnknownReason::CyclicDependency)),
1786 );
1787 return Some(SymbolicExpr::Unknown(UnknownReason::CyclicDependency));
1788 }
1789 }
1790 }
1791 Some(current_expr)
1792 };
1793
1794 in_progress.remove(place);
1795 memo.insert(place, result.clone());
1796 result
1797 }
1798
1799 fn op_kind_to_symbolic_expr(
1800 &self,
1801 op_kind: &BasicOpKind<'tcx, T>,
1802 memo: &mut HashMap<&'tcx Place<'tcx>, Option<SymbolicExpr<'tcx>>>,
1803 in_progress: &mut HashSet<&'tcx Place<'tcx>>,
1804 ) -> Option<SymbolicExpr<'tcx>> {
1805 match op_kind {
1806 BasicOpKind::Binary(bop) => {
1807 let (original_op1, original_op2) = {
1808 if let StatementKind::Assign(box (
1809 _lhs,
1810 Rvalue::BinaryOp(_op, box (op1_mir, op2_mir)),
1811 )) = &bop.inst.kind
1812 {
1813 (op1_mir, op2_mir)
1814 } else {
1815 rap_trace!(
1817 "Error: BinaryOp's instruction {:?} is not a BinaryOp statement. Returning Unknown.",
1818 bop.inst
1819 );
1820 return Some(SymbolicExpr::Unknown(UnknownReason::CannotParse));
1821 }
1822 };
1823
1824 let left_expr = if let Some(src_place) = bop.source1 {
1825 self.get_symbolic_expression_recursive(src_place, memo, in_progress)?
1826 } else if let Operand::Constant(c) = original_op1 {
1827 SymbolicExpr::Constant(c.const_)
1828 } else {
1829 rap_trace!(
1830 "Error: BinaryOp source1 is None, but original op1 is not a constant for inst {:?}. Returning Unknown.",
1831 bop.inst
1832 );
1833 return Some(SymbolicExpr::Unknown(UnknownReason::CannotParse));
1834 };
1835
1836 let right_expr = if let Some(src_place) = bop.source2 {
1837 self.get_symbolic_expression_recursive(src_place, memo, in_progress)?
1838 } else if let Operand::Constant(c) = original_op2 {
1839 SymbolicExpr::Constant(c.const_)
1840 } else {
1841 rap_trace!(
1842 "Error: BinaryOp source2 is None, but original op2 is not a constant for inst {:?}. Returning Unknown.",
1843 bop.inst
1844 );
1845 return Some(SymbolicExpr::Unknown(UnknownReason::CannotParse));
1846 };
1847
1848 Some(SymbolicExpr::BinaryOp {
1849 op: bop.op,
1850 left: Box::new(left_expr),
1851 right: Box::new(right_expr),
1852 })
1853 }
1854 BasicOpKind::Unary(uop) => {
1855 let original_operand_mir = {
1856 if let StatementKind::Assign(box (_lhs, Rvalue::UnaryOp(_op, operand_mir))) =
1857 &uop.inst.kind
1858 {
1859 operand_mir
1860 } else {
1861 rap_trace!(
1862 "Error: UnaryOp's instruction {:?} is not a UnaryOp statement. Returning Unknown.",
1863 uop.inst
1864 );
1865 return Some(SymbolicExpr::Unknown(UnknownReason::CannotParse));
1866 }
1867 };
1868
1869 let operand_expr = if let Operand::Constant(c) = original_operand_mir {
1870 SymbolicExpr::Constant(c.const_)
1871 } else if let Operand::Copy(place) | Operand::Move(place) = original_operand_mir {
1872 self.get_symbolic_expression_recursive(place, memo, in_progress)?
1873 } else {
1874 rap_trace!(
1875 "Error: UnaryOp's operand is neither Place nor Constant for inst {:?}. Returning Unknown.",
1876 uop.inst
1877 );
1878 return Some(SymbolicExpr::Unknown(UnknownReason::CannotParse));
1879 };
1880
1881 Some(SymbolicExpr::UnaryOp {
1882 op: uop.op,
1883 operand: Box::new(operand_expr),
1884 })
1885 }
1886 BasicOpKind::Use(use_op) => {
1887 if let Some(c) = use_op.const_value {
1888 Some(SymbolicExpr::Constant(c))
1889 } else if let Some(source_place) = use_op.source {
1890 self.get_symbolic_expression_recursive(source_place, memo, in_progress)
1891 } else {
1892 rap_trace!(
1893 "Error: UseOp has neither source nor const_value for inst {:?}. Returning Unknown.",
1894 use_op.inst
1895 );
1896 Some(SymbolicExpr::Unknown(UnknownReason::CannotParse))
1897 }
1898 }
1899 BasicOpKind::Phi(phi_op) => {
1900 let mut operands_exprs = Vec::new();
1901 for &source_place in phi_op.get_sources() {
1902 if let Some(expr) =
1906 self.get_symbolic_expression_recursive(source_place, memo, in_progress)
1907 {
1908 operands_exprs.push(expr);
1909 } else {
1910 rap_trace!(
1913 "Warning: One source of Phi {:?} cannot be resolved to a symbolic expression. Returning Unknown for the Phi.",
1914 phi_op.sink
1915 );
1916 return Some(SymbolicExpr::Unknown(UnknownReason::CannotParse));
1917 }
1918 }
1919 Some(SymbolicExpr::Ssa(operands_exprs))
1920 }
1921 BasicOpKind::Essa(essa_op) => {
1922 let operand_expr = self.get_symbolic_expression_recursive(
1923 essa_op.get_source(),
1924 memo,
1925 in_progress,
1926 )?;
1927
1928 let (constraint_op_operand, bin_op) = match essa_op.get_intersect() {
1931 super::domain::IntervalType::Symb(symb_interval) => {
1932 (
1934 VarorConst::Place(*symb_interval.get_bound()),
1935 symb_interval.get_operation(),
1936 )
1937 }
1938 super::domain::IntervalType::Basic(basic_interval) => {
1939 if let Some(vbm) = self.values_branchmap.get(essa_op.get_source()) {
1940 rap_trace!(
1941 "Warning: EssaOp with BasicInterval constraint. Cannot directly reconstruct original BinOp and constraint_operand from EssaOp's internal state. Returning Unknown for constraint part.",
1942 );
1943 return Some(SymbolicExpr::Unknown(UnknownReason::CannotParse));
1945 } else {
1946 rap_trace!(
1947 "Warning: EssaOp with BasicInterval constraint, but source not found in values_branchmap. Returning Unknown for constraint part.",
1948 );
1949 return Some(SymbolicExpr::Unknown(UnknownReason::CannotParse));
1950 }
1951 }
1952 };
1953
1954 Some(SymbolicExpr::Essa {
1955 operand: Box::new(operand_expr),
1956 constraint_operand: constraint_op_operand,
1957 bin_op: bin_op,
1958 })
1959 }
1960 BasicOpKind::ControlDep(_) => {
1961 rap_trace!(
1962 "Encountered unexpected ControlDep operation defining a place. Returning Unknown."
1963 );
1964 Some(SymbolicExpr::Unknown(UnknownReason::CannotParse))
1965 }
1966 BasicOpKind::Call(call_op) => todo!(),
1967 }
1968 }
1969 pub fn start_analyze_path_constraints(
1970 &mut self,
1971 body: &'tcx Body<'tcx>,
1972 all_paths_indices: &[Vec<usize>],
1973 ) -> HashMap<Vec<usize>, Vec<(Place<'tcx>, Place<'tcx>, BinOp)>> {
1974 self.build_value_maps(body);
1975 let result = self.analyze_path_constraints(body, all_paths_indices);
1976 result
1977 }
1978
1979 pub fn analyze_path_constraints(
1980 &self,
1981 body: &'tcx Body<'tcx>,
1982 all_paths_indices: &[Vec<usize>],
1983 ) -> HashMap<Vec<usize>, Vec<(Place<'tcx>, Place<'tcx>, BinOp)>> {
1984 let mut all_path_results: HashMap<Vec<usize>, Vec<(Place<'tcx>, Place<'tcx>, BinOp)>> =
1985 HashMap::with_capacity(all_paths_indices.len());
1986
1987 for path_indices in all_paths_indices {
1988 let mut current_path_constraints: Vec<(Place<'tcx>, Place<'tcx>, BinOp)> = Vec::new();
1989
1990 let path_bbs: Vec<BasicBlock> = path_indices
1991 .iter()
1992 .map(|&idx| BasicBlock::from_usize(idx))
1993 .collect();
1994
1995 for window in path_bbs.windows(2) {
1996 let current_bb = window[0];
1997
1998 if self.switchbbs.contains_key(¤t_bb) {
1999 let next_bb = window[1];
2000 let current_bb_data = &body[current_bb];
2001
2002 if let Some(Terminator {
2003 kind: TerminatorKind::SwitchInt { discr, .. },
2004 ..
2005 }) = ¤t_bb_data.terminator
2006 {
2007 let (constraint_place_1, constraint_place_2) =
2008 self.switchbbs.get(¤t_bb).unwrap();
2009 if let Some(vbm) = self.values_branchmap.get(constraint_place_1) {
2010 let relevant_interval_opt = if next_bb == *vbm.get_bb_true() {
2011 Some(vbm.get_itv_t())
2012 } else if next_bb == *vbm.get_bb_false() {
2013 Some(vbm.get_itv_f())
2014 } else {
2015 None
2016 };
2017
2018 if let Some(relevant_interval) = relevant_interval_opt {
2019 match relevant_interval {
2020 IntervalType::Basic(basic_interval) => {}
2021 IntervalType::Symb(symb_interval) => {
2022 current_path_constraints.push((
2023 constraint_place_1.clone(),
2024 constraint_place_2.clone(),
2025 symb_interval.get_operation().clone(),
2026 ));
2027 }
2028 }
2029 }
2030 }
2031 }
2032 }
2033 }
2034
2035 all_path_results.insert(path_indices.clone(), (current_path_constraints));
2036 }
2037
2038 all_path_results
2039 }
2040}
2041
2042#[derive(Debug)]
2043pub struct Nuutila<'tcx, T: IntervalArithmetic + ConstConvert + Debug> {
2044 pub variables: &'tcx VarNodes<'tcx, T>,
2045 pub index: i32,
2046 pub dfs: HashMap<&'tcx Place<'tcx>, i32>,
2047 pub root: HashMap<&'tcx Place<'tcx>, &'tcx Place<'tcx>>,
2048 pub in_component: HashSet<&'tcx Place<'tcx>>,
2049 pub components: HashMap<&'tcx Place<'tcx>, HashSet<&'tcx Place<'tcx>>>,
2050 pub worklist: VecDeque<&'tcx Place<'tcx>>,
2051 }
2053
2054impl<'tcx, T> Nuutila<'tcx, T>
2055where
2056 T: IntervalArithmetic + ConstConvert + Debug,
2057{
2058 pub fn new(
2059 varNodes: &'tcx VarNodes<'tcx, T>,
2060 use_map: &'tcx UseMap<'tcx>,
2061 symb_map: &'tcx SymbMap<'tcx>,
2062 single: bool,
2063 oprs: &'tcx Vec<BasicOpKind<'tcx, T>>,
2064 ) -> Self {
2065 let mut n: Nuutila<'_, T> = Nuutila {
2066 variables: varNodes,
2067 index: 0,
2068 dfs: HashMap::new(),
2069 root: HashMap::new(),
2070 in_component: HashSet::new(),
2071 components: HashMap::new(),
2072 worklist: std::collections::VecDeque::new(),
2073 };
2075
2076 if single {
2077 } else {
2090 for place in n.variables.keys().copied() {
2091 n.dfs.insert(place, -1);
2092 }
2093
2094 n.add_control_dependence_edges(symb_map, use_map, varNodes);
2095
2096 for place in n.variables.keys() {
2097 if n.dfs[place] < 0 {
2098 let mut stack = Vec::new();
2099 n.visit(place, &mut stack, use_map, oprs);
2100 }
2101 }
2102
2103 }
2105
2106 n
2107 }
2108
2109 pub fn visit(
2110 &mut self,
2111 place: &'tcx Place<'tcx>,
2112 stack: &mut Vec<&'tcx Place<'tcx>>,
2113 use_map: &'tcx UseMap<'tcx>,
2114 oprs: &'tcx Vec<BasicOpKind<'tcx, T>>,
2115 ) {
2116 self.dfs.entry(place).and_modify(|v| *v = self.index);
2117 self.index += 1;
2118 self.root.insert(place, place);
2119
2120 if let Some(uses) = use_map.get(place) {
2121 for op in uses {
2122 let name = oprs[*op].get_sink();
2123
2124 if self.dfs.get(name).copied().unwrap_or(-1) < 0 {
2125 self.visit(name, stack, use_map, oprs);
2126 }
2127
2128 if (!self.in_component.contains(name)
2129 && self.dfs[self.root[place]] >= self.dfs[self.root[name]])
2130 {
2131 *self.root.get_mut(place).unwrap() = self.root.get(name).copied().unwrap();
2132
2133 }
2135 }
2136 }
2137
2138 if self.root.get(place).copied().unwrap() == place {
2139 self.worklist.push_back(place);
2140
2141 let mut scc = HashSet::new();
2142 scc.insert(place);
2143
2144 self.in_component.insert(place);
2145
2146 while let Some(&top) = stack.last() {
2147 if self.dfs.get(top).copied().unwrap_or(-1) > self.dfs.get(place).copied().unwrap()
2148 {
2149 let node = stack.pop().unwrap();
2150 self.in_component.insert(node);
2151
2152 scc.insert(node);
2153 } else {
2154 break;
2155 }
2156 }
2157
2158 self.components.insert(place, scc);
2159 } else {
2160 stack.push(place);
2161 }
2162 }
2163
2164 pub fn add_control_dependence_edges(
2165 &mut self,
2166 _symb_map: &'tcx SymbMap<'tcx>,
2167 _use_map: &'tcx UseMap<'tcx>,
2168 _vars: &'tcx VarNodes<'tcx, T>,
2169 ) {
2170 todo!()
2171 }
2172
2173 pub fn del_control_dependence_edges(&mut self, _use_map: &'tcx mut UseMap<'tcx>) {
2174 todo!()
2175 }
2176}