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                        if targets.iter().count() == 1 {
702                            self.build_value_branch_map(body, discr, targets, bb, block_data);
703                        }
704                    }
705                    TerminatorKind::Goto { target } => {
706                        // self.build_value_goto_map(block_index, *target);
707                    }
708                    _ => {
709                        // rap_trace!(
710                        //     "BasicBlock {:?} has an unsupported terminator: {:?}",
711                        //     block_index, terminator.kind
712                        // );
713                    }
714                }
715            }
716        }
717        // rap_trace!("value_branchmap{:?}\n", self.values_branchmap);
718        // rap_trace!("varnodes{:?}\n,", self.vars);
719    }
720    fn trace_operand_source(
721        &self,
722        body: &'tcx Body<'tcx>,
723        mut current_block: BasicBlock,
724        target_place: Place<'tcx>,
725    ) -> Option<&'tcx Operand<'tcx>> {
726        let mut visited = HashSet::new();
727        let target_local = target_place.local;
728
729        while visited.insert(current_block) {
730            let data = &body.basic_blocks[current_block];
731
732            // 逆序扫描当前块
733            for stmt in data.statements.iter().rev() {
734                if let StatementKind::Assign(box (lhs, rvalue)) = &stmt.kind {
735                    // 只要找到了对目标变量的赋值语句
736                    if lhs.local == target_local {
737                        rap_debug!(
738                            "Tracing source for {:?} in block {:?} {:?}\n",
739                            target_place,
740                            current_block,
741                            rvalue
742                        );
743                        return match rvalue {
744                            // 如果右值是 Operand (例如 _2 = _1 或 _2 = const 5)
745                            // 直接返回这个 Operand 的引用,不再往上追 _1 的来源
746                            Rvalue::Use(op) => Some(op),
747
748                            // 如果右值是计算结果 (例如 _2 = Add(_3, _4))
749                            // 说明 _2 的来源就在这里,但它不是一个独立的 Operand 对象,返回 None
750                            _ => None,
751                        };
752                    }
753                }
754            }
755
756            // 当前块没找到,尝试回溯唯一的前驱块
757            let preds = &body.basic_blocks.predecessors()[current_block];
758            if preds.len() == 1 {
759                current_block = preds[0];
760            } else {
761                break;
762            }
763        }
764
765        None
766    }
767    pub fn build_value_branch_map(
768        &mut self,
769        body: &'tcx Body<'tcx>,
770        discr: &'tcx Operand<'tcx>,
771        targets: &'tcx SwitchTargets,
772        switch_block: BasicBlock,
773        block_data: &'tcx BasicBlockData<'tcx>,
774    ) {
775        // let place1: &Place<'tcx>;
776        let first_target = targets.all_targets()[0];
777        let target_data = &body.basic_blocks[first_target];
778
779        if let Operand::Copy(place) | Operand::Move(place) = discr {
780            if let Some((op1, op2, cmp_op)) = self.extract_condition(place, block_data) {
781                rap_debug!(
782                    "extract_condition op1:{:?} op2:{:?} cmp_op:{:?}\n",
783                    op1,
784                    op2,
785                    cmp_op
786                );
787                let op1 = if let Some(p1) = op1.place() {
788                    self.trace_operand_source(body, switch_block, p1)
789                        .unwrap_or(op1)
790                } else {
791                    op1
792                };
793
794                let op2 = if let Some(p2) = op2.place() {
795                    self.trace_operand_source(body, switch_block, p2)
796                        .unwrap_or(op2)
797                } else {
798                    op2
799                };
800                rap_debug!(
801                    "build_value_branch_map op1:{:?} op2:{:?} cmp_op:{:?}\n",
802                    op1,
803                    op2,
804                    cmp_op
805                );
806                let const_op1 = op1.constant();
807                let const_op2 = op2.constant();
808                match (const_op1, const_op2) {
809                    (Some(c1), Some(c2)) => {}
810                    (Some(c), None) | (None, Some(c)) => {
811                        let const_in_left: bool;
812                        let variable;
813                        if const_op1.is_some() {
814                            const_in_left = true;
815                            variable = match op2 {
816                                Operand::Copy(p) | Operand::Move(p) => p,
817                                _ => panic!("Expected a place"),
818                            };
819                        } else {
820                            const_in_left = false;
821                            variable = match op1 {
822                                Operand::Copy(p) | Operand::Move(p) => p,
823                                _ => panic!("Expected a place"),
824                            };
825                        }
826                        self.add_varnode(variable);
827                        rap_trace!("add_vbm_varnode{:?}\n", variable.clone());
828
829                        // let value = c.const_.try_to_scalar_int().unwrap();
830                        let value = Self::convert_const(&c.const_).unwrap();
831                        let const_range =
832                            Range::new(value.clone(), value.clone(), RangeType::Unknown);
833                        rap_trace!("cmp_op {:?}\n", cmp_op);
834                        rap_trace!("const_in_left {:?}\n", const_in_left);
835                        let mut true_range =
836                            self.apply_comparison(value.clone(), cmp_op, true, const_in_left);
837                        let mut false_range =
838                            self.apply_comparison(value.clone(), cmp_op, false, const_in_left);
839                        true_range.set_regular();
840                        false_range.set_regular();
841                        // rap_trace!("true_range{:?}\n", true_range);
842                        // rap_trace!("false_range{:?}\n", false_range);
843                        let target_vec = targets.all_targets();
844
845                        let vbm = ValueBranchMap::new(
846                            variable,
847                            &target_vec[0],
848                            &target_vec[1],
849                            IntervalType::Basic(BasicInterval::new(false_range)),
850                            IntervalType::Basic(BasicInterval::new(true_range)),
851                        );
852                        self.values_branchmap.insert(variable, vbm);
853                        // self.switchbbs.insert(block, (place, variable));
854                    }
855                    (None, None) => {
856                        let CR = Range::new(T::min_value(), T::max_value(), RangeType::Unknown);
857
858                        let p1 = match op1 {
859                            Operand::Copy(p) | Operand::Move(p) => p,
860                            _ => panic!("Expected a place"),
861                        };
862                        let p2 = match op2 {
863                            Operand::Copy(p) | Operand::Move(p) => p,
864                            _ => panic!("Expected a place"),
865                        };
866                        let target_vec = targets.all_targets();
867                        self.add_varnode(&p1);
868                        rap_trace!("add_vbm_varnode{:?}\n", p1.clone());
869
870                        self.add_varnode(&p2);
871                        rap_trace!("add_vbm_varnode{:?}\n", p2.clone());
872                        let flipped_cmp_op = Self::flipped_binop(cmp_op).unwrap();
873                        let reversed_cmp_op = Self::reverse_binop(cmp_op).unwrap();
874                        let reversed_flippedd_cmp_op =
875                            Self::flipped_binop(reversed_cmp_op).unwrap();
876                        let STOp1 = IntervalType::Symb(SymbInterval::new(CR.clone(), p2, cmp_op));
877                        let SFOp1 =
878                            IntervalType::Symb(SymbInterval::new(CR.clone(), p2, flipped_cmp_op));
879                        let STOp2 =
880                            IntervalType::Symb(SymbInterval::new(CR.clone(), p1, reversed_cmp_op));
881                        let SFOp2 = IntervalType::Symb(SymbInterval::new(
882                            CR.clone(),
883                            p1,
884                            reversed_flippedd_cmp_op,
885                        ));
886                        rap_trace!("SFOp1{:?}\n", SFOp1);
887                        rap_trace!("SFOp2{:?}\n", SFOp2);
888                        rap_trace!("STOp1{:?}\n", STOp1);
889                        rap_trace!("STOp2{:?}\n", STOp2);
890                        let vbm_1 =
891                            ValueBranchMap::new(p1, &target_vec[0], &target_vec[1], SFOp1, STOp1);
892                        let vbm_2 =
893                            ValueBranchMap::new(p2, &target_vec[0], &target_vec[1], SFOp2, STOp2);
894                        self.values_branchmap.insert(&p1, vbm_1);
895                        self.values_branchmap.insert(&p2, vbm_2);
896                        self.switchbbs.insert(switch_block, (*p1, *p2));
897                    }
898                }
899            };
900        }
901    }
902    pub fn flipped_binop(op: BinOp) -> Option<BinOp> {
903        use BinOp::*;
904        Some(match op {
905            Eq => Eq,
906            Ne => Ne,
907            Lt => Ge,
908            Le => Gt,
909            Gt => Le,
910            Ge => Lt,
911            Add => Add,
912            Mul => Mul,
913            BitXor => BitXor,
914            BitAnd => BitAnd,
915            BitOr => BitOr,
916            _ => {
917                return None;
918            }
919        })
920    }
921    fn reverse_binop(op: BinOp) -> Option<BinOp> {
922        use BinOp::*;
923        Some(match op {
924            Eq => Eq,
925            Ne => Ne,
926            Lt => Gt,
927            Le => Ge,
928            Gt => Lt,
929            Ge => Le,
930            Add => Add,
931            Mul => Mul,
932            BitXor => BitXor,
933            BitAnd => BitAnd,
934            BitOr => BitOr,
935            _ => {
936                return None;
937            }
938        })
939    }
940    fn extract_condition(
941        &mut self,
942        place: &'tcx Place<'tcx>,
943        switch_block: &'tcx BasicBlockData<'tcx>,
944    ) -> Option<(&'tcx Operand<'tcx>, &'tcx Operand<'tcx>, BinOp)> {
945        for stmt in &switch_block.statements {
946            if let StatementKind::Assign(box (lhs, Rvalue::BinaryOp(bin_op, box (op1, op2)))) =
947                &stmt.kind
948            {
949                if lhs == place {
950                    let mut return_op1: &Operand<'tcx> = &op1;
951                    let mut return_op2: &Operand<'tcx> = &op2;
952                    // for stmt_original in &switch_block.statements {
953                    //     if op1.constant().is_none() {
954                    //         if let StatementKind::Assign(box (lhs, Rvalue::Use(OP1))) =
955                    //             &stmt_original.kind
956                    //         {
957                    //             if lhs.clone() == op1.place().unwrap() {
958                    //                 return_op1 = OP1;
959                    //             }
960                    //         }
961                    //     }
962                    // }
963                    // if op2.constant().is_none() {
964                    //     for stmt_original in &switch_block.statements {
965                    //         if let StatementKind::Assign(box (lhs, Rvalue::Use(OP2))) =
966                    //             &stmt_original.kind
967                    //         {
968                    //             if lhs.clone() == op2.place().unwrap() {
969                    //                 return_op2 = OP2;
970                    //             }
971                    //         }
972                    //     }
973                    // }
974
975                    return Some((return_op1, return_op2, *bin_op));
976                }
977            }
978        }
979        None
980    }
981
982    fn apply_comparison<U: IntervalArithmetic>(
983        &self,
984        constant: U,
985        cmp_op: BinOp,
986        is_true_branch: bool,
987        const_in_left: bool,
988    ) -> Range<U> {
989        match cmp_op {
990            BinOp::Lt => {
991                if is_true_branch ^ const_in_left {
992                    Range::new(U::min_value(), constant.sub(U::one()), RangeType::Unknown)
993                } else {
994                    Range::new(constant, U::max_value(), RangeType::Unknown)
995                }
996            }
997
998            BinOp::Le => {
999                if is_true_branch ^ const_in_left {
1000                    Range::new(U::min_value(), constant, RangeType::Unknown)
1001                } else {
1002                    Range::new(constant.add(U::one()), U::max_value(), RangeType::Unknown)
1003                }
1004            }
1005
1006            BinOp::Gt => {
1007                if is_true_branch ^ const_in_left {
1008                    Range::new(U::min_value(), constant, RangeType::Unknown)
1009                } else {
1010                    Range::new(constant.add(U::one()), U::max_value(), RangeType::Unknown)
1011                }
1012            }
1013
1014            BinOp::Ge => {
1015                if is_true_branch ^ const_in_left {
1016                    Range::new(U::min_value(), constant, RangeType::Unknown)
1017                } else {
1018                    Range::new(constant, U::max_value().sub(U::one()), RangeType::Unknown)
1019                }
1020            }
1021
1022            BinOp::Eq => {
1023                if is_true_branch ^ const_in_left {
1024                    Range::new(U::min_value(), constant, RangeType::Unknown)
1025                } else {
1026                    Range::new(constant, U::max_value(), RangeType::Unknown)
1027                }
1028            }
1029
1030            _ => Range::new(constant.clone(), constant.clone(), RangeType::Empty),
1031        }
1032    }
1033
1034    fn build_value_goto_map(&self, block_index: BasicBlock, target: BasicBlock) {
1035        rap_trace!(
1036            "Building value map for Goto in block {:?} targeting block {:?}",
1037            block_index,
1038            target
1039        );
1040    }
1041    pub fn build_varnodes(&mut self) {
1042        // Builds VarNodes
1043        for (name, node) in self.vars.iter_mut() {
1044            let is_undefined = !self.defmap.contains_key(name);
1045            node.init(is_undefined);
1046        }
1047    }
1048
1049    pub fn build_symbolic_intersect_map(&mut self) {
1050        for i in 0..self.oprs.len() {
1051            if let BasicOpKind::Essa(essaop) = &self.oprs[i] {
1052                if let IntervalType::Symb(symbi) = essaop.get_intersect() {
1053                    let v = symbi.get_bound();
1054                    self.symbmap.entry(v).or_insert_with(HashSet::new).insert(i);
1055                    rap_trace!("symbmap insert {:?} {:?}\n", v, essaop);
1056                }
1057            }
1058        }
1059        // rap_trace!("symbmap: {:?}", self.symbmap);
1060    }
1061    pub fn build_use_map(
1062        &mut self,
1063        component: &HashSet<&'tcx Place<'tcx>>,
1064    ) -> HashMap<&'tcx Place<'tcx>, HashSet<usize>> {
1065        // Builds use map
1066        let mut comp_use_map = HashMap::new();
1067        for &place in component {
1068            if let Some(uses) = self.usemap.get(place) {
1069                for op in uses.iter() {
1070                    let sink = self.oprs[*op].get_sink();
1071                    if component.contains(&sink) {
1072                        comp_use_map
1073                            .entry(place)
1074                            .or_insert_with(HashSet::new)
1075                            .insert(*op);
1076                    }
1077                }
1078            }
1079        }
1080
1081        self.print_compusemap(component, &comp_use_map);
1082        comp_use_map
1083    }
1084    pub fn build_terminator(&mut self, block: BasicBlock, terminator: &'tcx Terminator<'tcx>) {
1085        match &terminator.kind {
1086            TerminatorKind::Call {
1087                func,
1088                args,
1089                destination,
1090                target: _,
1091                unwind: _,
1092                fn_span: _,
1093                call_source,
1094            } => {
1095                rap_trace!(
1096                    "TerminatorKind::Call in block {:?} with function {:?} destination {:?} args {:?}\n",
1097                    block,
1098                    func,
1099                    destination,
1100                    args
1101                );
1102                // Handle the call operation
1103                self.add_call_op(destination, args, terminator, func, block);
1104            }
1105            TerminatorKind::Return => {}
1106            TerminatorKind::Goto { target } => {
1107                rap_trace!(
1108                    "TerminatorKind::Goto in block {:?} targeting block {:?}\n",
1109                    block,
1110                    target
1111                );
1112            }
1113            TerminatorKind::SwitchInt { discr, targets } => {
1114                rap_trace!(
1115                    "TerminatorKind::SwitchInt in block {:?} with discr {:?} and targets {:?}\n",
1116                    block,
1117                    discr,
1118                    targets
1119                );
1120            }
1121            _ => {
1122                rap_trace!(
1123                    "Unsupported terminator kind in block {:?}: {:?}",
1124                    block,
1125                    terminator.kind
1126                );
1127            }
1128        }
1129    }
1130    pub fn build_operations(
1131        &mut self,
1132        inst: &'tcx Statement<'tcx>,
1133        block: BasicBlock,
1134        body: &'tcx Body<'tcx>,
1135    ) {
1136        match &inst.kind {
1137            StatementKind::Assign(box (sink, rvalue)) => match rvalue {
1138                Rvalue::BinaryOp(op, box (op1, op2)) => match op {
1139                    BinOp::Add
1140                    | BinOp::Sub
1141                    | BinOp::Mul
1142                    | BinOp::Div
1143                    | BinOp::Rem
1144                    | BinOp::AddUnchecked => {
1145                        self.add_binary_op(sink, inst, rvalue, op1, op2, *op);
1146                    }
1147                    BinOp::AddWithOverflow => {
1148                        self.add_binary_op(sink, inst, rvalue, op1, op2, *op);
1149                    }
1150                    BinOp::SubUnchecked => {
1151                        self.add_binary_op(sink, inst, rvalue, op1, op2, *op);
1152                    }
1153                    BinOp::SubWithOverflow => {
1154                        self.add_binary_op(sink, inst, rvalue, op1, op2, *op);
1155                    }
1156                    BinOp::MulUnchecked => {
1157                        self.add_binary_op(sink, inst, rvalue, op1, op2, *op);
1158                    }
1159                    BinOp::MulWithOverflow => {
1160                        self.add_binary_op(sink, inst, rvalue, op1, op2, *op);
1161                    }
1162
1163                    _ => {}
1164                },
1165                Rvalue::UnaryOp(unop, operand) => {
1166                    self.add_unary_op(sink, inst, rvalue, operand, *unop);
1167                }
1168                Rvalue::Aggregate(kind, operends) => match **kind {
1169                    AggregateKind::Adt(def_id, _, _, _, _) => match def_id {
1170                        _ if def_id == self.essa => {
1171                            self.add_essa_op(sink, inst, rvalue, operends, block)
1172                        }
1173                        _ if def_id == self.ssa => self.add_ssa_op(sink, inst, rvalue, operends),
1174                        _ => match self.unique_adt_handler(def_id) {
1175                            1 => {
1176                                self.add_aggregate_op(sink, inst, rvalue, operends, 1);
1177                            }
1178                            _ => {
1179                                rap_trace!(
1180                                    "AggregateKind::Adt with def_id {:?} in statement {:?} is not handled specially.\n",
1181                                    def_id,
1182                                    inst
1183                                );
1184                            }
1185                        },
1186                    },
1187                    _ => {}
1188                },
1189                Rvalue::Use(operend) => {
1190                    self.add_use_op(sink, inst, rvalue, operend);
1191                }
1192                Rvalue::Ref(_, borrowkind, place) => {
1193                    self.add_ref_op(sink, inst, rvalue, place, *borrowkind);
1194                }
1195                _ => {}
1196            },
1197            _ => {}
1198        }
1199    }
1200    // ... inside your struct impl ...
1201    fn unique_adt_handler(&mut self, def_id: DefId) -> usize {
1202        let adt_path = self.tcx.def_path_str(def_id);
1203        rap_trace!("adt_path: {:?}\n", adt_path);
1204        if self.unique_adt_path.contains_key(&adt_path) {
1205            rap_trace!(
1206                "unique_adt_handler for def_id: {:?} -> {}\n",
1207                def_id,
1208                adt_path
1209            );
1210            return *self.unique_adt_path.get(&adt_path).unwrap();
1211        }
1212        0
1213    }
1214    /// Adds a function call operation to the graph.
1215    fn add_call_op(
1216        &mut self,
1217        sink: &'tcx Place<'tcx>,
1218        args: &'tcx Box<[Spanned<Operand<'tcx>>]>,
1219        terminator: &'tcx Terminator<'tcx>,
1220        func: &'tcx Operand<'tcx>,
1221        block: BasicBlock,
1222    ) {
1223        rap_trace!("add_call_op for sink: {:?} {:?}\n", sink, terminator);
1224        let sink_node = self.add_varnode(&sink);
1225
1226        // Convert Operand arguments to Place arguments.
1227        // An Operand can be a Constant or a moved/copied Place.
1228        // We only care about Places for our analysis.
1229        let mut path = String::new();
1230        let mut func_def_id = None;
1231        if let Operand::Constant(box const_operand) = func {
1232            let fn_ty = const_operand.ty();
1233            if let ty::TyKind::FnDef(def_id, _substs) = fn_ty.kind() {
1234                // Found the DefId for a direct function call!
1235                rap_debug!("fn_ty: {:?}\n", fn_ty);
1236                if def_id.krate != LOCAL_CRATE {
1237                    path = self.tcx.def_path_str(*def_id);
1238
1239                    self.func_without_mir.insert(*def_id, path.clone());
1240                    rap_debug!("called external/no-MIR fn: {:?} -> {}", def_id, path);
1241                }
1242                // if !self.tcx.is_mir_available(*def_id) {
1243                //     path = self.tcx.def_path_str(*def_id);
1244
1245                //     self.func_without_mir.insert(*def_id, path.clone());
1246                //     rap_debug!("called external/no-MIR fn: {:?} -> {}", def_id, path);
1247                // }
1248                func_def_id = Some(def_id);
1249            }
1250        }
1251
1252        if let Some(def_id) = func_def_id {
1253            rap_trace!(
1254                "TerminatorKind::Call in block {:?} with DefId {:?}\n",
1255                block,
1256                def_id
1257            );
1258            // You can now use the def_id
1259        } else {
1260            rap_trace!(
1261                "TerminatorKind::Call in block {:?} is an indirect call (e.g., function pointer)\n",
1262                block
1263            );
1264            // This handles cases where the call is not a direct one,
1265            // such as calling a function pointer stored in a variable.
1266        }
1267        let mut constant_count = 0 as usize;
1268        let arg_count = args.len();
1269        let mut arg_operands: Vec<Operand<'tcx>> = Vec::new();
1270        let mut places = Vec::new();
1271        for op in args.iter() {
1272            match &op.node {
1273                Operand::Copy(place) | Operand::Move(place) => {
1274                    arg_operands.push(op.node.clone());
1275                    places.push(place);
1276                    self.add_varnode(place);
1277                    self.usemap
1278                        .entry(place)
1279                        .or_default()
1280                        .insert(self.oprs.len());
1281                }
1282
1283                Operand::Constant(_) => {
1284                    // If it's not a Place, we can still add it as an operand.
1285                    // This is useful for constants or other non-place operands.
1286                    arg_operands.push(op.node.clone());
1287                    constant_count += 1;
1288                }
1289            }
1290        }
1291        {
1292            let bi = BasicInterval::new(Range::default(T::min_value()));
1293
1294            let call_op = CallOp::new(
1295                IntervalType::Basic(bi),
1296                &sink,
1297                terminator, // Pass the allocated dummy statement
1298                arg_operands,
1299                *func_def_id.unwrap(), // Use the DefId if available
1300                path,
1301                places,
1302            );
1303            rap_debug!("call_op: {:?}\n", call_op);
1304            let bop_index = self.oprs.len();
1305
1306            // Insert the operation into the graph.
1307            self.oprs.push(BasicOpKind::Call(call_op));
1308
1309            // Insert this definition in defmap
1310            self.defmap.insert(&sink, bop_index);
1311            if constant_count == arg_count {
1312                rap_trace!("all args are constants\n");
1313                self.const_func_place.insert(&sink, bop_index);
1314            }
1315        }
1316    }
1317    fn add_ssa_op(
1318        &mut self,
1319        sink: &'tcx Place<'tcx>,
1320        inst: &'tcx Statement<'tcx>,
1321        rvalue: &'tcx Rvalue<'tcx>,
1322
1323        operands: &'tcx IndexVec<FieldIdx, Operand<'tcx>>,
1324    ) {
1325        rap_trace!("ssa_op{:?}\n", inst);
1326
1327        let sink_node: &mut VarNode<'_, T> = self.def_add_varnode_sym(sink, rvalue);
1328        rap_trace!("addsink_in_ssa_op{:?}\n", sink_node);
1329
1330        let BI: BasicInterval<T> = BasicInterval::new(Range::default(T::min_value()));
1331        let mut phiop = PhiOp::new(IntervalType::Basic(BI), sink, inst, 0);
1332        let bop_index = self.oprs.len();
1333        for i in 0..operands.len() {
1334            let source = match &operands[FieldIdx::from_usize(i)] {
1335                Operand::Copy(place) | Operand::Move(place) => {
1336                    self.use_add_varnode_sym(place, rvalue);
1337                    Some(place)
1338                }
1339                _ => None,
1340            };
1341            if let Some(source) = source {
1342                self.use_add_varnode_sym(source, rvalue);
1343                phiop.add_source(source);
1344                rap_trace!("addvar_in_ssa_op{:?}\n", source);
1345                self.usemap.entry(source).or_default().insert(bop_index);
1346            }
1347        }
1348        // Insert the operation in the graph.
1349
1350        self.oprs.push(BasicOpKind::Phi(phiop));
1351
1352        // Insert this definition in defmap
1353
1354        self.defmap.insert(sink, bop_index);
1355    }
1356    fn add_use_op(
1357        &mut self,
1358        sink: &'tcx Place<'tcx>,
1359        inst: &'tcx Statement<'tcx>,
1360        rvalue: &'tcx Rvalue<'tcx>,
1361        op: &'tcx Operand<'tcx>,
1362    ) {
1363        rap_trace!("use_op{:?}\n", inst);
1364
1365        let BI: BasicInterval<T> = BasicInterval::new(Range::default(T::min_value()));
1366        let mut source: Option<&'tcx Place<'tcx>> = None;
1367
1368        match op {
1369            Operand::Copy(place) | Operand::Move(place) => {
1370                if sink.local == RETURN_PLACE && sink.projection.is_empty() {
1371                    self.rerurn_places.insert(place);
1372                    // self.add_varnode_sym(place, rvalue);
1373
1374                    let sink_node = self.def_add_varnode_sym(sink, rvalue);
1375
1376                    rap_debug!("add_return_place{:?}\n", place);
1377                } else {
1378                    self.use_add_varnode_sym(place, rvalue);
1379                    rap_trace!("addvar_in_use_op{:?}\n", place);
1380                    let sink_node = self.def_add_varnode_sym(sink, rvalue);
1381                    let useop = UseOp::new(IntervalType::Basic(BI), sink, inst, Some(place), None);
1382                    // Insert the operation in the graph.
1383                    let bop_index = self.oprs.len();
1384
1385                    self.oprs.push(BasicOpKind::Use(useop));
1386                    // Insert this definition in defmap
1387                    self.usemap.entry(place).or_default().insert(bop_index);
1388
1389                    self.defmap.insert(sink, bop_index);
1390                }
1391            }
1392            Operand::Constant(constant) => {
1393                rap_trace!("add_constant_op{:?}\n", inst);
1394                let Some(c) = op.constant() else {
1395                    rap_trace!("add_constant_op: constant is None\n");
1396                    return;
1397                };
1398                let useop = UseOp::new(IntervalType::Basic(BI), sink, inst, None, Some(c.const_));
1399                // Insert the operation in the graph.
1400                let bop_index = self.oprs.len();
1401
1402                self.oprs.push(BasicOpKind::Use(useop));
1403                // Insert this definition in defmap
1404
1405                self.defmap.insert(sink, bop_index);
1406                let sink_node = self.def_add_varnode_sym(sink, rvalue);
1407
1408                if let Some(value) = Self::convert_const(&c.const_) {
1409                    sink_node.set_range(Range::new(
1410                        value.clone(),
1411                        value.clone(),
1412                        RangeType::Regular,
1413                    ));
1414                    rap_trace!("set_const {:?} value: {:?}\n", sink_node, value);
1415                    // rap_trace!("sinknoderange: {:?}\n", sink_node.get_range());
1416                } else {
1417                    sink_node.set_range(Range::default(T::min_value()));
1418                };
1419            }
1420        }
1421    }
1422    fn add_essa_op(
1423        &mut self,
1424        sink: &'tcx Place<'tcx>,
1425        inst: &'tcx Statement<'tcx>,
1426        rvalue: &'tcx Rvalue<'tcx>,
1427        operands: &'tcx IndexVec<FieldIdx, Operand<'tcx>>,
1428        block: BasicBlock,
1429    ) {
1430        // rap_trace!("essa_op{:?}\n", inst);
1431        let sink_node = self.def_add_varnode_sym(sink, rvalue);
1432        // rap_trace!("addsink_in_essa_op {:?}\n", sink_node);
1433
1434        // let BI: BasicInterval<T> = BasicInterval::new(Range::default(T::min_value()));
1435        let loc_1: usize = 0;
1436        let loc_2: usize = 1;
1437        let source1 = match &operands[FieldIdx::from_usize(loc_1)] {
1438            Operand::Copy(place) | Operand::Move(place) => {
1439                self.use_add_varnode_sym(place, rvalue);
1440                Some(place)
1441            }
1442            _ => None,
1443        };
1444        let op = &operands[FieldIdx::from_usize(loc_2)];
1445        let bop_index = self.oprs.len();
1446        let BI: IntervalType<'_, T>;
1447        rap_trace!("essa_op operand1 {:?}\n", source1.unwrap());
1448        if let Operand::Constant(c) = op {
1449            let vbm = self.values_branchmap.get(source1.unwrap()).unwrap();
1450            if block == *vbm.get_bb_true() {
1451                rap_trace!("essa_op true branch{:?}\n", block);
1452                BI = vbm.get_itv_t();
1453            } else {
1454                rap_trace!("essa_op false branch{:?}\n", block);
1455                BI = vbm.get_itv_f();
1456            }
1457            self.usemap
1458                .entry(source1.unwrap())
1459                .or_default()
1460                .insert(bop_index);
1461
1462            let essaop = EssaOp::new(BI, sink, inst, source1.unwrap(), 0, false);
1463            rap_trace!(
1464                "addvar_in_essa_op {:?} from const {:?}\n",
1465                essaop,
1466                source1.unwrap()
1467            );
1468
1469            // Insert the operation in the graph.
1470
1471            self.oprs.push(BasicOpKind::Essa(essaop));
1472            // Insert this definition in defmap
1473            // self.usemap
1474            //     .entry(source1.unwrap())
1475            //     .or_default()
1476            //     .insert(bop_index);
1477
1478            self.defmap.insert(sink, bop_index);
1479        } else {
1480            let vbm = self.values_branchmap.get(source1.unwrap()).unwrap();
1481            if block == *vbm.get_bb_true() {
1482                rap_trace!("essa_op true branch{:?}\n", block);
1483                BI = vbm.get_itv_t();
1484            } else {
1485                rap_trace!("essa_op false branch{:?}\n", block);
1486                BI = vbm.get_itv_f();
1487            }
1488            let source2 = match op {
1489                Operand::Copy(place) | Operand::Move(place) => {
1490                    self.use_add_varnode_sym(place, rvalue);
1491                    Some(place)
1492                }
1493                _ => None,
1494            };
1495            self.usemap
1496                .entry(source1.unwrap())
1497                .or_default()
1498                .insert(bop_index);
1499            // self.usemap
1500            // .entry(source2.unwrap())
1501            // .or_default()
1502            // .insert(bop_index);
1503            let essaop = EssaOp::new(BI, sink, inst, source1.unwrap(), 0, true);
1504            // Insert the operation in the graph.
1505            rap_trace!(
1506                "addvar_in_essa_op {:?} from {:?}\n",
1507                essaop,
1508                source1.unwrap()
1509            );
1510
1511            self.oprs.push(BasicOpKind::Essa(essaop));
1512            // Insert this definition in defmap
1513            // self.usemap
1514            //     .entry(source1.unwrap())
1515            //     .or_default()
1516            //     .insert(bop_index);
1517
1518            self.defmap.insert(sink, bop_index);
1519        }
1520    }
1521    pub fn add_aggregate_op(
1522        &mut self,
1523        sink: &'tcx Place<'tcx>,
1524        inst: &'tcx Statement<'tcx>,
1525        rvalue: &'tcx Rvalue<'tcx>,
1526        operands: &'tcx IndexVec<FieldIdx, Operand<'tcx>>,
1527        unique_adt: usize,
1528    ) {
1529        rap_trace!("aggregate_op {:?}\n", inst);
1530
1531        let BI: BasicInterval<T> = BasicInterval::new(Range::default(T::min_value()));
1532        let mut agg_operands: Vec<AggregateOperand<'tcx>> = Vec::with_capacity(operands.len());
1533
1534        for operand in operands {
1535            match operand {
1536                Operand::Copy(place) | Operand::Move(place) => {
1537                    if sink.local == RETURN_PLACE && sink.projection.is_empty() {
1538                        self.rerurn_places.insert(place);
1539                        self.def_add_varnode_sym(sink, rvalue);
1540                        rap_debug!("add_return_place {:?}\n", place);
1541                    } else {
1542                        self.use_add_varnode_sym(place, rvalue);
1543                        rap_trace!("addvar_in_aggregate_op {:?}\n", place);
1544                        agg_operands.push(AggregateOperand::Place(place));
1545                    }
1546                }
1547                Operand::Constant(c) => {
1548                    rap_trace!("add_constant_aggregate_op {:?}\n", c);
1549                    agg_operands.push(AggregateOperand::Const(c.const_));
1550
1551                    let sink_node = self.def_add_varnode_sym(sink, rvalue);
1552                    if let Some(value) = Self::convert_const(&c.const_) {
1553                        sink_node.set_range(Range::new(
1554                            value.clone(),
1555                            value.clone(),
1556                            RangeType::Regular,
1557                        ));
1558                        rap_trace!("set_const {:?} value: {:?}\n", sink_node, value);
1559                    } else {
1560                        sink_node.set_range(Range::default(T::min_value()));
1561                    }
1562                }
1563            }
1564        }
1565
1566        if agg_operands.is_empty() {
1567            rap_trace!("aggregate_op has no operands, skipping\n");
1568            return;
1569        }
1570
1571        let agg_op = AggregateOp::new(
1572            IntervalType::Basic(BI),
1573            sink,
1574            inst,
1575            agg_operands,
1576            unique_adt,
1577        );
1578        let bop_index = self.oprs.len();
1579        self.oprs.push(BasicOpKind::Aggregate(agg_op));
1580
1581        for operand in operands {
1582            if let Operand::Copy(place) | Operand::Move(place) = operand {
1583                self.usemap.entry(place).or_default().insert(bop_index);
1584            }
1585        }
1586
1587        self.defmap.insert(sink, bop_index);
1588
1589        self.def_add_varnode_sym(sink, rvalue);
1590    }
1591
1592    fn add_unary_op(
1593        &mut self,
1594        sink: &'tcx Place<'tcx>,
1595        inst: &'tcx Statement<'tcx>,
1596        rvalue: &'tcx Rvalue<'tcx>,
1597        operand: &'tcx Operand<'tcx>,
1598        op: UnOp,
1599    ) {
1600        rap_trace!("unary_op{:?}\n", inst);
1601
1602        let sink_node = self.def_add_varnode_sym(sink, rvalue);
1603        rap_trace!("addsink_in_unary_op{:?}\n", sink_node);
1604
1605        let BI: BasicInterval<T> = BasicInterval::new(Range::default(T::min_value()));
1606        let loc_1: usize = 0;
1607
1608        let source = match operand {
1609            Operand::Copy(place) | Operand::Move(place) => {
1610                self.add_varnode(place);
1611                Some(place)
1612            }
1613            _ => None,
1614        };
1615
1616        rap_trace!("addvar_in_unary_op{:?}\n", source.unwrap());
1617        self.use_add_varnode_sym(&source.unwrap(), rvalue);
1618
1619        let unaryop = UnaryOp::new(IntervalType::Basic(BI), sink, inst, source.unwrap(), op);
1620        // Insert the operation in the graph.
1621        let bop_index = self.oprs.len();
1622
1623        self.oprs.push(BasicOpKind::Unary(unaryop));
1624        // Insert this definition in defmap
1625
1626        self.defmap.insert(sink, bop_index);
1627    }
1628    fn add_binary_op(
1629        &mut self,
1630        sink: &'tcx Place<'tcx>,
1631        inst: &'tcx Statement<'tcx>,
1632        rvalue: &'tcx Rvalue<'tcx>,
1633        op1: &'tcx Operand<'tcx>,
1634        op2: &'tcx Operand<'tcx>,
1635        bin_op: BinOp,
1636    ) {
1637        rap_trace!("binary_op{:?}\n", inst);
1638
1639        // Define the sink node (Def)
1640        let sink_node = self.def_add_varnode_sym(sink, rvalue);
1641        rap_trace!("addsink_in_binary_op{:?}\n", sink_node);
1642
1643        let bop_index = self.oprs.len();
1644        let bi: BasicInterval<T> = BasicInterval::new(Range::default(T::min_value()));
1645
1646        // Match both operands simultaneously to handle all combinations.
1647        // Goal: Ensure source1 is always a Place if at least one Place exists.
1648        let (source1_place, source2_place, const_val) = match (op1, op2) {
1649            // Case 1: Place + Place
1650            (Operand::Copy(p1) | Operand::Move(p1), Operand::Copy(p2) | Operand::Move(p2)) => {
1651                self.use_add_varnode_sym(p1, rvalue);
1652                self.use_add_varnode_sym(p2, rvalue);
1653                rap_trace!("addvar_in_binary_op p1:{:?}, p2:{:?}\n", p1, p2);
1654
1655                (Some(p1), Some(p2), None)
1656            }
1657
1658            // Case 2: Place + Constant
1659            (Operand::Copy(p1) | Operand::Move(p1), Operand::Constant(c2)) => {
1660                self.use_add_varnode_sym(p1, rvalue);
1661                rap_trace!("addvar_in_binary_op p1:{:?}\n", p1);
1662
1663                (Some(p1), None, Some(c2.const_))
1664            }
1665
1666            // Case 3: Constant + Place
1667            // Here we normalize: Treat the Place (op2) as source1, and the Constant (op1) as the const value.
1668            // NOTE: Be careful with non-commutative operations (Sub, Div) in your interval logic later,
1669            // as the physical order is swapped here.
1670            (Operand::Constant(c1), Operand::Copy(p2) | Operand::Move(p2)) => {
1671                self.use_add_varnode_sym(p2, rvalue);
1672                rap_trace!("addvar_in_binary_op p2(as source1):{:?}\n", p2);
1673
1674                // Assign p2 to the first return position to make it source1
1675                (Some(p2), None, Some(c1.const_))
1676            }
1677
1678            // Case 4: Constant + Constant
1679            (Operand::Constant(c1), Operand::Constant(_)) => {
1680                // Logic depends on how you want to handle two constants.
1681                // Usually keeping one is sufficient for the struct signature.
1682                (None, None, Some(c1.const_))
1683            }
1684        };
1685
1686        // Construct the BinaryOp
1687        let bop = BinaryOp::new(
1688            IntervalType::Basic(bi),
1689            sink,
1690            inst,
1691            source1_place, // This is guaranteed to be the Place (if one exists)
1692            source2_place,
1693            const_val,
1694            bin_op.clone(),
1695        );
1696
1697        self.oprs.push(BasicOpKind::Binary(bop));
1698
1699        // Update DefMap
1700        self.defmap.insert(sink, bop_index);
1701
1702        // Update UseMap
1703        if let Some(place) = source1_place {
1704            self.usemap.entry(place).or_default().insert(bop_index);
1705        }
1706
1707        if let Some(place) = source2_place {
1708            self.usemap.entry(place).or_default().insert(bop_index);
1709        }
1710    }
1711    fn add_ref_op(
1712        &mut self,
1713        sink: &'tcx Place<'tcx>,
1714        inst: &'tcx Statement<'tcx>,
1715        rvalue: &'tcx Rvalue<'tcx>,
1716        place: &'tcx Place<'tcx>,
1717        borrowkind: BorrowKind,
1718    ) {
1719        rap_trace!("ref_op {:?}\n", inst);
1720
1721        let BI: BasicInterval<T> = BasicInterval::new(Range::default(T::min_value()));
1722
1723        let source_node = self.use_add_varnode_sym(place, rvalue);
1724
1725        let sink_node = self.def_add_varnode_sym(sink, rvalue);
1726
1727        let refop = RefOp::new(IntervalType::Basic(BI), sink, inst, place, borrowkind);
1728        let bop_index = self.oprs.len();
1729        self.oprs.push(BasicOpKind::Ref(refop));
1730
1731        self.usemap.entry(place).or_default().insert(bop_index);
1732
1733        self.defmap.insert(sink, bop_index);
1734
1735        rap_trace!(
1736            "add_ref_op: created RefOp from {:?} to {:?} at {:?}\n",
1737            place,
1738            sink,
1739            inst
1740        );
1741    }
1742
1743    fn fix_intersects(&mut self, component: &HashSet<&'tcx Place<'tcx>>) {
1744        for &place in component.iter() {
1745            // node.fix_intersects();
1746            if let Some(sit) = self.symbmap.get_mut(place) {
1747                let node = self.vars.get(place).unwrap();
1748
1749                for &op in sit.iter() {
1750                    let op = &mut self.oprs[op];
1751                    let sinknode = self.vars.get(op.get_sink()).unwrap();
1752
1753                    op.op_fix_intersects(node, sinknode);
1754                }
1755            }
1756        }
1757    }
1758    pub fn widen(
1759        &mut self,
1760        op: usize,
1761        cg_map: &FxHashMap<DefId, Rc<RefCell<ConstraintGraph<'tcx, T>>>>,
1762        vars_map: &mut FxHashMap<DefId, Vec<RefCell<VarNodes<'tcx, T>>>>,
1763    ) -> bool {
1764        // use crate::range_util::{get_first_less_from_vector, get_first_greater_from_vector};
1765        // assert!(!constant_vector.is_empty(), "Invalid constant vector");
1766        let op_kind = &self.oprs[op];
1767        let sink = op_kind.get_sink();
1768        let old_interval = self.vars.get(sink).unwrap().get_range().clone();
1769
1770        // HERE IS THE SPECIALIZATION:
1771        // We check the operation type and call the appropriate eval function.
1772        let estimated_interval = match op_kind {
1773            BasicOpKind::Call(call_op) => {
1774                // For a call, use the special inter-procedural eval.
1775                call_op.eval_call(&self.vars, cg_map, vars_map)
1776            }
1777            _ => {
1778                // For all other operations, use the simple, generic eval.
1779                op_kind.eval(&self.vars)
1780            }
1781        };
1782        let old_lower = old_interval.get_lower();
1783        let old_upper = old_interval.get_upper();
1784        let new_lower = estimated_interval.get_lower();
1785        let new_upper = estimated_interval.get_upper();
1786        // op.set_intersect(estimated_interval.clone());
1787
1788        // let nlconstant = get_first_less_from_vector(constant_vector, new_lower);
1789        // let nuconstant = get_first_greater_from_vector(constant_vector, new_upper);
1790        // let nlconstant = constant_vector
1791        //     .iter()
1792        //     .find(|&&c| c <= new_lower)
1793        //     .cloned()
1794        //     .unwrap_or(T::min_value());
1795        // let nuconstant = constant_vector
1796        //     .iter()
1797        //     .find(|&&c| c >= new_upper)
1798        //     .cloned()
1799        //     .unwrap_or(T::max_value());
1800
1801        let updated = if old_interval.is_unknown() {
1802            estimated_interval.clone()
1803        } else if new_lower < old_lower && new_upper > old_upper {
1804            Range::new(T::min_value(), T::max_value(), RangeType::Regular)
1805        } else if new_lower < old_lower {
1806            Range::new(T::min_value(), old_upper.clone(), RangeType::Regular)
1807        } else if new_upper > old_upper {
1808            Range::new(old_lower.clone(), T::max_value(), RangeType::Regular)
1809        } else {
1810            old_interval.clone()
1811        };
1812
1813        self.vars.get_mut(sink).unwrap().set_range(updated.clone());
1814        rap_trace!(
1815            "WIDEN in {} set {:?}: E {:?} U {:?} {:?} -> {:?}",
1816            op,
1817            sink,
1818            estimated_interval,
1819            updated,
1820            old_interval,
1821            updated
1822        );
1823
1824        old_interval != updated
1825    }
1826    pub fn narrow(
1827        &mut self,
1828        op: usize,
1829        cg_map: &FxHashMap<DefId, Rc<RefCell<ConstraintGraph<'tcx, T>>>>,
1830        vars_map: &mut FxHashMap<DefId, Vec<RefCell<VarNodes<'tcx, T>>>>,
1831    ) -> bool {
1832        let op_kind = &self.oprs[op];
1833        let sink = op_kind.get_sink();
1834        let old_interval = self.vars.get(sink).unwrap().get_range().clone();
1835
1836        // SPECIALIZATION for narrow:
1837        let estimated_interval = match op_kind {
1838            BasicOpKind::Call(call_op) => {
1839                // For a call, use the special inter-procedural eval.
1840                call_op.eval_call(&self.vars, cg_map, vars_map)
1841            }
1842            _ => {
1843                // For all other operations, use the simple, generic eval.
1844                op_kind.eval(&self.vars)
1845            }
1846        };
1847        let old_lower = old_interval.get_lower();
1848        let old_upper = old_interval.get_upper();
1849        let new_lower = estimated_interval.get_lower();
1850        let new_upper = estimated_interval.get_upper();
1851        // op.set_intersect(estimated_interval.clone());
1852        // let mut hasChanged = false;
1853        let mut final_lower = old_lower.clone();
1854        let mut final_upper = old_upper.clone();
1855        if old_lower.clone() == T::min_value() && new_lower.clone() > T::min_value() {
1856            final_lower = new_lower.clone();
1857            // tightened = Range::new(new_lower.clone(), old_upper.clone(), RangeType::Regular);
1858            // hasChanged = true;
1859        } else if old_lower.clone() <= new_lower.clone() {
1860            final_lower = new_lower.clone();
1861
1862            // tightened = Range::new(new_lower.clone(), old_upper.clone(), RangeType::Regular);
1863            // hasChanged = true;
1864        };
1865        if old_upper.clone() == T::max_value() && new_upper.clone() < T::max_value() {
1866            final_upper = new_upper.clone();
1867            // tightened = Range::new(old_lower.clone(), new_upper.clone(), RangeType::Regular);
1868            // hasChanged = true;
1869        } else if old_upper.clone() >= new_upper.clone() {
1870            final_upper = new_upper.clone();
1871            // tightened = Range::new(old_lower.clone(), new_upper.clone(), RangeType::Regular);
1872            // hasChanged = true;
1873        }
1874        let tightened = Range::new(final_lower, final_upper, RangeType::Regular);
1875
1876        self.vars
1877            .get_mut(sink)
1878            .unwrap()
1879            .set_range(tightened.clone());
1880        rap_trace!(
1881            "NARROW in {} set {:?}: E {:?} U {:?} {:?} -> {:?}",
1882            op,
1883            sink,
1884            estimated_interval,
1885            tightened,
1886            old_interval,
1887            tightened
1888        );
1889        let hasChanged = old_interval != tightened;
1890
1891        hasChanged
1892    }
1893
1894    fn pre_update(
1895        &mut self,
1896        comp_use_map: &HashMap<&'tcx Place<'tcx>, HashSet<usize>>,
1897        entry_points: &HashSet<&'tcx Place<'tcx>>,
1898        cg_map: &FxHashMap<DefId, Rc<RefCell<ConstraintGraph<'tcx, T>>>>,
1899        vars_map: &mut FxHashMap<DefId, Vec<RefCell<VarNodes<'tcx, T>>>>,
1900    ) {
1901        let mut worklist: Vec<&'tcx Place<'tcx>> = entry_points.iter().cloned().collect();
1902
1903        while let Some(place) = worklist.pop() {
1904            if let Some(op_set) = comp_use_map.get(place) {
1905                for &op in op_set {
1906                    if self.widen(op, cg_map, vars_map) {
1907                        let sink = self.oprs[op].get_sink();
1908                        rap_trace!("W {:?}\n", sink);
1909                        // let sink_node = self.vars.get_mut(sink).unwrap();
1910                        worklist.push(sink);
1911                    }
1912                }
1913            }
1914        }
1915    }
1916
1917    fn pos_update(
1918        &mut self,
1919        comp_use_map: &HashMap<&'tcx Place<'tcx>, HashSet<usize>>,
1920        entry_points: &HashSet<&'tcx Place<'tcx>>,
1921        cg_map: &FxHashMap<DefId, Rc<RefCell<ConstraintGraph<'tcx, T>>>>,
1922        vars_map: &mut FxHashMap<DefId, Vec<RefCell<VarNodes<'tcx, T>>>>,
1923    ) {
1924        let mut worklist: Vec<&'tcx Place<'tcx>> = entry_points.iter().cloned().collect();
1925        let mut iteration = 0;
1926        while let Some(place) = worklist.pop() {
1927            iteration += 1;
1928            if (iteration > 1000) {
1929                rap_trace!("Iteration limit reached, breaking out of pos_update\n");
1930                break;
1931            }
1932
1933            if let Some(op_set) = comp_use_map.get(place) {
1934                for &op in op_set {
1935                    if self.narrow(op, cg_map, vars_map) {
1936                        let sink = self.oprs[op].get_sink();
1937                        rap_trace!("N {:?}\n", sink);
1938
1939                        // let sink_node = self.vars.get_mut(sink).unwrap();
1940                        worklist.push(sink);
1941                    }
1942                }
1943            }
1944        }
1945        rap_trace!("pos_update finished after {} iterations\n", iteration);
1946    }
1947    fn generate_active_vars(
1948        &mut self,
1949        component: &HashSet<&'tcx Place<'tcx>>,
1950        active_vars: &mut HashSet<&'tcx Place<'tcx>>,
1951        cg_map: &FxHashMap<DefId, Rc<RefCell<ConstraintGraph<'tcx, T>>>>,
1952        vars_map: &mut FxHashMap<DefId, Vec<RefCell<VarNodes<'tcx, T>>>>,
1953    ) {
1954        for place in component {
1955            let node = self.vars.get(place).unwrap();
1956        }
1957    }
1958    fn generate_entry_points(
1959        &mut self,
1960        component: &HashSet<&'tcx Place<'tcx>>,
1961        entry_points: &mut HashSet<&'tcx Place<'tcx>>,
1962        cg_map: &FxHashMap<DefId, Rc<RefCell<ConstraintGraph<'tcx, T>>>>,
1963        vars_map: &mut FxHashMap<DefId, Vec<RefCell<VarNodes<'tcx, T>>>>,
1964    ) {
1965        for &place in component {
1966            let op = self.defmap.get(place).unwrap();
1967            if let BasicOpKind::Essa(essaop) = &mut self.oprs[*op] {
1968                if essaop.is_unresolved() {
1969                    let source = essaop.get_source();
1970                    let new_range = essaop.eval(&self.vars);
1971                    let sink_node = self.vars.get_mut(source).unwrap();
1972                    sink_node.set_range(new_range);
1973                }
1974                essaop.mark_resolved();
1975            }
1976            if (!self.vars[place].get_range().is_unknown()) {
1977                entry_points.insert(place);
1978            }
1979        }
1980    }
1981    fn propagate_to_next_scc(
1982        &mut self,
1983        component: &HashSet<&'tcx Place<'tcx>>,
1984        cg_map: &FxHashMap<DefId, Rc<RefCell<ConstraintGraph<'tcx, T>>>>,
1985        vars_map: &mut FxHashMap<DefId, Vec<RefCell<VarNodes<'tcx, T>>>>,
1986    ) {
1987        for &place in component.iter() {
1988            let node = self.vars.get_mut(place).unwrap();
1989            for &op in self.usemap.get(place).unwrap().iter() {
1990                let op_kind = &mut self.oprs[op];
1991                let sink = op_kind.get_sink();
1992                if !component.contains(sink) {
1993                    let new_range = op_kind.eval(&self.vars);
1994                    let new_range = match op_kind {
1995                        BasicOpKind::Call(call_op) => {
1996                            call_op.eval_call(&self.vars, cg_map, vars_map)
1997                        }
1998                        _ => {
1999                            // For all other operations, use the simple, generic eval.
2000                            op_kind.eval(&self.vars)
2001                        }
2002                    };
2003                    let sink_node = self.vars.get_mut(sink).unwrap();
2004                    rap_trace!(
2005                        "prop component {:?} set {:?} to {:?} through {:?}\n",
2006                        component,
2007                        new_range,
2008                        sink,
2009                        op_kind.get_instruction()
2010                    );
2011                    sink_node.set_range(new_range);
2012                    // if self.symbmap.contains_key(sink) {
2013                    //     let symb_set = self.symbmap.get_mut(sink).unwrap();
2014                    //     symb_set.insert(op.get_index());
2015                    // }
2016                    if let BasicOpKind::Essa(essaop) = op_kind {
2017                        if essaop.get_intersect().get_range().is_unknown() {
2018                            essaop.mark_unresolved();
2019                        }
2020                    }
2021                }
2022            }
2023        }
2024    }
2025    pub fn solve_const_func_call(
2026        &mut self,
2027        cg_map: &FxHashMap<DefId, Rc<RefCell<ConstraintGraph<'tcx, T>>>>,
2028        vars_map: &mut FxHashMap<DefId, Vec<RefCell<VarNodes<'tcx, T>>>>,
2029    ) {
2030        for (&sink, op) in &self.const_func_place {
2031            rap_trace!(
2032                "solve_const_func_call for sink {:?} with opset {:?}\n",
2033                sink,
2034                op
2035            );
2036            if let BasicOpKind::Call(call_op) = &self.oprs[*op] {
2037                let new_range = call_op.eval_call(&self.vars, cg_map, vars_map);
2038                rap_trace!("Setting range for {:?} to {:?}\n", sink, new_range);
2039                self.vars.get_mut(sink).unwrap().set_range(new_range);
2040            }
2041        }
2042    }
2043    pub fn store_vars(&mut self, varnodes_vec: &mut Vec<RefCell<VarNodes<'tcx, T>>>) {
2044        rap_trace!("Storing vars\n");
2045        let old_vars = self.vars.clone();
2046        varnodes_vec.push(RefCell::new(old_vars));
2047    }
2048    pub fn reset_vars(&mut self, varnodes_vec: &mut Vec<RefCell<VarNodes<'tcx, T>>>) {
2049        rap_trace!("Resetting vars\n");
2050        self.vars = varnodes_vec[0].borrow_mut().clone();
2051    }
2052    pub fn find_intervals(
2053        &mut self,
2054        cg_map: &FxHashMap<DefId, Rc<RefCell<ConstraintGraph<'tcx, T>>>>,
2055        vars_map: &mut FxHashMap<DefId, Vec<RefCell<VarNodes<'tcx, T>>>>,
2056    ) {
2057        // let scc_list = Nuutila::new(&self.vars, &self.usemap, &self.symbmap,false,&self.oprs);
2058        // self.print_vars();
2059
2060        self.solve_const_func_call(cg_map, vars_map);
2061        self.numSCCs = self.worklist.len();
2062        let mut seen = HashSet::new();
2063        let mut components = Vec::new();
2064
2065        for &place in self.worklist.iter().rev() {
2066            if seen.contains(place) {
2067                continue;
2068            }
2069
2070            if let Some(component) = self.components.get(place) {
2071                for &p in component {
2072                    seen.insert(p);
2073                }
2074
2075                components.push(component.clone());
2076            }
2077        }
2078        rap_trace!("TOLO:{:?}\n", components);
2079
2080        for component in components {
2081            rap_trace!("===start component {:?}===\n", component);
2082            if component.len() == 1 {
2083                self.numAloneSCCs += 1;
2084
2085                self.fix_intersects(&component);
2086
2087                let variable: &Place<'tcx> = *component.iter().next().unwrap();
2088                let varnode = self.vars.get_mut(variable).unwrap();
2089                if varnode.get_range().is_unknown() {
2090                    varnode.set_default();
2091                }
2092            } else {
2093                // self.pre_update(&comp_use_map, &entry_points);
2094                let comp_use_map = self.build_use_map(&component);
2095                // build_constant_vec(&component, &self.oprs, &mut self.constant_vec);
2096                let mut entry_points = HashSet::new();
2097                // self.print_vars();
2098
2099                self.generate_entry_points(&component, &mut entry_points, cg_map, vars_map);
2100                rap_trace!("entry_points {:?}  \n", entry_points);
2101                // rap_trace!("comp_use_map {:?}  \n ", comp_use_map);
2102                self.pre_update(&comp_use_map, &entry_points, cg_map, vars_map);
2103                self.fix_intersects(&component);
2104
2105                // for &variable in &component {
2106                //     let varnode = self.vars.get_mut(variable).unwrap();
2107                //     if varnode.get_range().is_unknown() {
2108                //         varnode.set_default();
2109                //     }
2110                // }
2111
2112                let mut active_vars = HashSet::new();
2113                self.generate_active_vars(&component, &mut active_vars, cg_map, vars_map);
2114                self.pos_update(&comp_use_map, &entry_points, cg_map, vars_map);
2115            }
2116            self.propagate_to_next_scc(&component, cg_map, vars_map);
2117        }
2118        self.merge_return_places();
2119        let Some(varnodes_vec) = vars_map.get_mut(&self.self_def_id) else {
2120            rap_trace!(
2121                "No variable map entry for this function {:?}, skipping Nuutila\n",
2122                self.self_def_id
2123            );
2124            return;
2125        };
2126        self.store_vars(varnodes_vec);
2127    }
2128    pub fn merge_return_places(&mut self) {
2129        rap_trace!("====Merging return places====\n");
2130        for &place in self.rerurn_places.iter() {
2131            rap_debug!("merging return place {:?}\n", place);
2132            let mut merged_range = Range::default(T::min_value());
2133            if let Some(opset) = self.vars.get(place) {
2134                merged_range = merged_range.unionwith(opset.get_range());
2135            }
2136            if let Some(return_node) = self.vars.get_mut(&Place::return_place()) {
2137                rap_debug!("Assigning final merged range {:?} to _0", merged_range);
2138                return_node.set_range(merged_range);
2139            } else {
2140                // This case is unlikely for functions that return a value, as `_0`
2141                // should have been created during the initial graph build.
2142                // We add a trace message for robustness.
2143                rap_trace!(
2144                    "Warning: RETURN_PLACE (_0) not found in self.vars. Cannot assign merged return range."
2145                );
2146            }
2147        }
2148    }
2149
2150    pub fn add_control_dependence_edges(&mut self) {
2151        rap_trace!("====Add control dependence edges====\n");
2152        self.print_symbmap();
2153        for (&place, opset) in self.symbmap.iter() {
2154            for &op in opset.iter() {
2155                let bop_index = self.oprs.len();
2156                let opkind = &self.oprs[op];
2157                let control_edge = ControlDep::new(
2158                    IntervalType::Basic(BasicInterval::default()),
2159                    opkind.get_sink(),
2160                    opkind.get_instruction().unwrap(),
2161                    place,
2162                );
2163                rap_trace!(
2164                    "Adding control_edge {:?} for place {:?} at index {}\n",
2165                    control_edge,
2166                    place,
2167                    bop_index
2168                );
2169                self.oprs.push(BasicOpKind::ControlDep(control_edge));
2170                self.usemap.entry(place).or_default().insert(bop_index);
2171            }
2172        }
2173    }
2174    pub fn del_control_dependence_edges(&mut self) {
2175        rap_trace!("====Delete control dependence edges====\n");
2176
2177        let mut remove_from = self.oprs.len();
2178        while remove_from > 0 {
2179            match &self.oprs[remove_from - 1] {
2180                BasicOpKind::ControlDep(dep) => {
2181                    let place = dep.source;
2182                    rap_trace!(
2183                        "removing control_edge at idx {}: {:?}\n",
2184                        remove_from - 1,
2185                        dep
2186                    );
2187                    if let Some(set) = self.usemap.get_mut(&place) {
2188                        set.remove(&(remove_from - 1));
2189                        if set.is_empty() {
2190                            self.usemap.remove(&place);
2191                        }
2192                    }
2193                    remove_from -= 1;
2194                }
2195                _ => break,
2196            }
2197        }
2198
2199        self.oprs.truncate(remove_from);
2200    }
2201
2202    pub fn build_nuutila(&mut self, single: bool) {
2203        rap_trace!("====Building Nuutila====\n");
2204        self.build_symbolic_intersect_map();
2205
2206        if single {
2207        } else {
2208            for place in self.vars.keys().copied() {
2209                self.dfs.insert(place, -1);
2210            }
2211
2212            self.add_control_dependence_edges();
2213
2214            let places: Vec<_> = self.vars.keys().copied().collect();
2215            rap_trace!("places{:?}\n", places);
2216            for place in places {
2217                if self.dfs[&place] < 0 {
2218                    rap_trace!("start place{:?}\n", place);
2219                    let mut stack = Vec::new();
2220                    self.visit(place, &mut stack);
2221                }
2222            }
2223
2224            self.del_control_dependence_edges();
2225        }
2226        rap_trace!("components{:?}\n", self.components);
2227        rap_trace!("worklist{:?}\n", self.worklist);
2228        rap_trace!("dfs{:?}\n", self.dfs);
2229    }
2230    pub fn visit(&mut self, place: &'tcx Place<'tcx>, stack: &mut Vec<&'tcx Place<'tcx>>) {
2231        self.dfs.entry(place).and_modify(|v| *v = self.index);
2232        self.index += 1;
2233        self.root.insert(place, place);
2234        let uses = self.usemap.get(place).unwrap().clone();
2235        for op in uses {
2236            let name = self.oprs[op].get_sink();
2237            rap_trace!("place {:?} get name{:?}\n", place, name);
2238            if self.dfs.get(name).copied().unwrap_or(-1) < 0 {
2239                self.visit(name, stack);
2240            }
2241
2242            if (!self.in_component.contains(name)
2243                && self.dfs[self.root[place]] >= self.dfs[self.root[name]])
2244            {
2245                *self.root.get_mut(place).unwrap() = self.root.get(name).copied().unwrap();
2246
2247                // let weq = self.root.get(place)
2248            }
2249        }
2250
2251        if self.root.get(place).copied().unwrap() == place {
2252            self.worklist.push_back(place);
2253
2254            let mut scc = HashSet::new();
2255            scc.insert(place);
2256
2257            self.in_component.insert(place);
2258
2259            while let Some(top) = stack.last() {
2260                if self.dfs.get(top).copied().unwrap_or(-1) > self.dfs.get(place).copied().unwrap()
2261                {
2262                    let node = stack.pop().unwrap();
2263                    self.in_component.insert(node);
2264
2265                    scc.insert(node);
2266                } else {
2267                    break;
2268                }
2269            }
2270
2271            self.components.insert(place, scc);
2272        } else {
2273            stack.push(place);
2274        }
2275    }
2276
2277    pub fn start_analyze_path_constraints(
2278        &mut self,
2279        body: &'tcx Body<'tcx>,
2280        all_paths_indices: &[Vec<usize>],
2281    ) -> HashMap<Vec<usize>, Vec<(Place<'tcx>, Place<'tcx>, BinOp)>> {
2282        self.build_value_maps(body);
2283        let result = self.analyze_path_constraints(body, all_paths_indices);
2284        result
2285    }
2286
2287    pub fn analyze_path_constraints(
2288        &self,
2289        body: &'tcx Body<'tcx>,
2290        all_paths_indices: &[Vec<usize>],
2291    ) -> HashMap<Vec<usize>, Vec<(Place<'tcx>, Place<'tcx>, BinOp)>> {
2292        let mut all_path_results: HashMap<Vec<usize>, Vec<(Place<'tcx>, Place<'tcx>, BinOp)>> =
2293            HashMap::with_capacity(all_paths_indices.len());
2294
2295        for path_indices in all_paths_indices {
2296            let mut current_path_constraints: Vec<(Place<'tcx>, Place<'tcx>, BinOp)> = Vec::new();
2297
2298            let path_bbs: Vec<BasicBlock> = path_indices
2299                .iter()
2300                .map(|&idx| BasicBlock::from_usize(idx))
2301                .collect();
2302
2303            for window in path_bbs.windows(2) {
2304                let current_bb = window[0];
2305
2306                if self.switchbbs.contains_key(&current_bb) {
2307                    let next_bb = window[1];
2308                    let current_bb_data = &body[current_bb];
2309
2310                    if let Some(Terminator {
2311                        kind: TerminatorKind::SwitchInt { discr, .. },
2312                        ..
2313                    }) = &current_bb_data.terminator
2314                    {
2315                        let (constraint_place_1, constraint_place_2) =
2316                            self.switchbbs.get(&current_bb).unwrap();
2317                        if let Some(vbm) = self.values_branchmap.get(constraint_place_1) {
2318                            let relevant_interval_opt = if next_bb == *vbm.get_bb_true() {
2319                                Some(vbm.get_itv_t())
2320                            } else if next_bb == *vbm.get_bb_false() {
2321                                Some(vbm.get_itv_f())
2322                            } else {
2323                                None
2324                            };
2325
2326                            if let Some(relevant_interval) = relevant_interval_opt {
2327                                match relevant_interval {
2328                                    IntervalType::Basic(basic_interval) => {}
2329                                    IntervalType::Symb(symb_interval) => {
2330                                        current_path_constraints.push((
2331                                            constraint_place_1.clone(),
2332                                            constraint_place_2.clone(),
2333                                            symb_interval.get_operation().clone(),
2334                                        ));
2335                                    }
2336                                }
2337                            }
2338                        }
2339                    }
2340                }
2341            }
2342
2343            all_path_results.insert(path_indices.clone(), (current_path_constraints));
2344        }
2345
2346        all_path_results
2347    }
2348}
2349#[derive(Debug)]
2350pub struct Nuutila<'tcx, T: IntervalArithmetic + ConstConvert + Debug> {
2351    pub variables: &'tcx VarNodes<'tcx, T>,
2352    pub index: i32,
2353    pub dfs: HashMap<&'tcx Place<'tcx>, i32>,
2354    pub root: HashMap<&'tcx Place<'tcx>, &'tcx Place<'tcx>>,
2355    pub in_component: HashSet<&'tcx Place<'tcx>>,
2356    pub components: HashMap<&'tcx Place<'tcx>, HashSet<&'tcx Place<'tcx>>>,
2357    pub worklist: VecDeque<&'tcx Place<'tcx>>,
2358    // pub oprs: &Vec<BasicOpKind<'tcx, T>>,
2359}
2360
2361impl<'tcx, T> Nuutila<'tcx, T>
2362where
2363    T: IntervalArithmetic + ConstConvert + Debug,
2364{
2365    pub fn new(
2366        varNodes: &'tcx VarNodes<'tcx, T>,
2367        use_map: &'tcx UseMap<'tcx>,
2368        symb_map: &'tcx SymbMap<'tcx>,
2369        single: bool,
2370        oprs: &'tcx Vec<BasicOpKind<'tcx, T>>,
2371    ) -> Self {
2372        let mut n: Nuutila<'_, T> = Nuutila {
2373            variables: varNodes,
2374            index: 0,
2375            dfs: HashMap::new(),
2376            root: HashMap::new(),
2377            in_component: HashSet::new(),
2378            components: HashMap::new(),
2379            worklist: std::collections::VecDeque::new(),
2380            // oprs:oprs
2381        };
2382
2383        if single {
2384            // let mut scc = HashSet::new();
2385            // for var_node in variables.values() {
2386            //     scc.insert(var_node.clone());
2387            // }
2388
2389            // for (place, _) in variables.iter() {
2390            //     n.components.insert(place.clone(), scc.clone());
2391            // }
2392
2393            // if let Some((first_place, _)) = variables.iter().next() {
2394            //     n.worklist.push_back(first_place.clone());
2395            // }
2396        } else {
2397            for place in n.variables.keys().copied() {
2398                n.dfs.insert(place, -1);
2399            }
2400
2401            n.add_control_dependence_edges(symb_map, use_map, varNodes);
2402
2403            for place in n.variables.keys() {
2404                if n.dfs[place] < 0 {
2405                    let mut stack = Vec::new();
2406                    n.visit(place, &mut stack, use_map, oprs);
2407                }
2408            }
2409
2410            // n.del_control_dependence_edges(use_map);
2411        }
2412
2413        n
2414    }
2415
2416    pub fn visit(
2417        &mut self,
2418        place: &'tcx Place<'tcx>,
2419        stack: &mut Vec<&'tcx Place<'tcx>>,
2420        use_map: &'tcx UseMap<'tcx>,
2421        oprs: &'tcx Vec<BasicOpKind<'tcx, T>>,
2422    ) {
2423        self.dfs.entry(place).and_modify(|v| *v = self.index);
2424        self.index += 1;
2425        self.root.insert(place, place);
2426
2427        if let Some(uses) = use_map.get(place) {
2428            for op in uses {
2429                let name = oprs[*op].get_sink();
2430
2431                if self.dfs.get(name).copied().unwrap_or(-1) < 0 {
2432                    self.visit(name, stack, use_map, oprs);
2433                }
2434
2435                if (!self.in_component.contains(name)
2436                    && self.dfs[self.root[place]] >= self.dfs[self.root[name]])
2437                {
2438                    *self.root.get_mut(place).unwrap() = self.root.get(name).copied().unwrap();
2439
2440                    // let weq = self.root.get(place)
2441                }
2442            }
2443        }
2444
2445        if self.root.get(place).copied().unwrap() == place {
2446            self.worklist.push_back(place);
2447
2448            let mut scc = HashSet::new();
2449            scc.insert(place);
2450
2451            self.in_component.insert(place);
2452
2453            while let Some(&top) = stack.last() {
2454                if self.dfs.get(top).copied().unwrap_or(-1) > self.dfs.get(place).copied().unwrap()
2455                {
2456                    let node = stack.pop().unwrap();
2457                    self.in_component.insert(node);
2458
2459                    scc.insert(node);
2460                } else {
2461                    break;
2462                }
2463            }
2464
2465            self.components.insert(place, scc);
2466        } else {
2467            stack.push(place);
2468        }
2469    }
2470
2471    pub fn add_control_dependence_edges(
2472        &mut self,
2473        _symb_map: &'tcx SymbMap<'tcx>,
2474        _use_map: &'tcx UseMap<'tcx>,
2475        _vars: &'tcx VarNodes<'tcx, T>,
2476    ) {
2477        todo!()
2478    }
2479
2480    pub fn del_control_dependence_edges(&mut self, _use_map: &'tcx mut UseMap<'tcx>) {
2481        todo!()
2482    }
2483}