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