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