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