rapx/analysis/core/range_analysis/domain/
ConstraintGraph.rs

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