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

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