Skip to main content

rapx/analysis/ssa_transform/
replacer.rs

1#![allow(non_snake_case)]
2#![allow(unused_variables)]
3#![allow(dead_code)]
4use super::ssa_transformer::SSATransformer;
5use rustc_abi::FieldIdx;
6use rustc_hir::def_id::DefIdMap;
7use rustc_index::IndexVec;
8use rustc_middle::ty::TyCtxt;
9use rustc_middle::{mir::*, ty::GenericArgs};
10use rustc_span::sym::new;
11use std::collections::{HashMap, HashSet, VecDeque};
12
13pub struct Replacer<'tcx> {
14    pub(crate) tcx: TyCtxt<'tcx>,
15    pub(crate) ssatransformer: super::ssa_transformer::SSATransformer<'tcx>,
16    pub(crate) new_local_collection: HashSet<Local>,
17    pub(crate) new_locals_to_declare: HashMap<Local, Local>,
18}
19impl<'tcx> Replacer<'tcx> {
20    pub fn insert_phi_statment(&mut self, body: &mut Body<'tcx>) {
21        for (block_index, blockdata) in body.basic_blocks.iter_enumerated() {}
22        let mut phi_functions: HashMap<BasicBlock, HashSet<Local>> = HashMap::new();
23        for bb in body.basic_blocks.indices() {
24            phi_functions.insert(bb, HashSet::new());
25        }
26        let variables: Vec<Local> = self
27            .ssatransformer
28            .local_assign_blocks
29            .iter()
30            .filter(|(_, blocks)| blocks.len() >= 2)
31            .map(|(&local, _)| local)
32            .collect();
33        for var in &variables {
34            if let Some(def_blocks) = self.ssatransformer.local_assign_blocks.get(var) {
35                let mut worklist: VecDeque<BasicBlock> = def_blocks.iter().cloned().collect();
36                let mut processed: HashSet<BasicBlock> = HashSet::new();
37                while let Some(block) = worklist.pop_front() {
38                    if let Some(df_blocks) = self.ssatransformer.df.get(&block) {
39                        for &df_block in df_blocks {
40                            if !processed.contains(&df_block) {
41                                phi_functions.get_mut(&df_block).unwrap().insert(*var);
42                                processed.insert(df_block);
43
44                                worklist.push_back(df_block);
45                            }
46                        }
47                    }
48                }
49                //     }
50                // }
51            }
52        }
53
54        for (block, vars) in phi_functions {
55            for var in vars.clone() {
56                let decl = body.local_decls[var].clone();
57                // let new_var = body.local_decls.push(decl);
58
59                // print!("body.local_decls.len():{:?}\n", body.local_decls.len());
60                let predecessors = body.basic_blocks.predecessors()[block].clone();
61
62                let mut operands = IndexVec::with_capacity(predecessors.len());
63                for _ in 0..predecessors.len() {
64                    operands.push(Operand::Copy(Place::from(var)));
65                }
66                let phi_stmt: Statement<'_> = Statement::new(
67                    SourceInfo::outermost(body.span),
68                    StatementKind::Assign(Box::new((
69                        Place::from(var),
70                        Rvalue::Aggregate(
71                            Box::new(AggregateKind::Adt(
72                                self.ssatransformer.phi_def_id.clone(),
73                                rustc_abi::VariantIdx::from_u32(0),
74                                GenericArgs::empty(),
75                                None,
76                                None,
77                            )),
78                            operands,
79                        ),
80                    ))),
81                );
82
83                body.basic_blocks_mut()[block]
84                    .statements
85                    .insert(0, phi_stmt);
86            }
87        }
88    }
89    pub fn insert_essa_statement(&mut self, body: &mut Body<'tcx>) {
90        let order = SSATransformer::depth_first_search_preorder(
91            &self.ssatransformer.dom_tree,
92            body.basic_blocks.indices().next().unwrap(),
93        );
94
95        for &bb in &order {
96            self.essa_process_basic_block(bb, body);
97        }
98    }
99
100    fn essa_process_basic_block(&mut self, bb: BasicBlock, body: &mut Body<'tcx>) {
101        let switch_block_data = body.basic_blocks[bb].clone();
102
103        if let Some(terminator) = &switch_block_data.terminator {
104            if let TerminatorKind::SwitchInt { discr, targets, .. } = &terminator.kind {
105                if targets.iter().count() == 1 {
106                    let (value, target) = targets.iter().next().unwrap();
107                    self.essa_assign_statement(&target, &bb, value, discr, body);
108
109                    let otherwise = targets.otherwise();
110                    self.essa_assign_statement(&otherwise, &bb, 1, discr, body);
111                }
112            }
113        }
114    }
115
116    fn extract_condition(
117        &self,
118        place: &Place<'tcx>,
119        switch_block: &BasicBlockData<'tcx>,
120    ) -> Option<(Operand<'tcx>, Operand<'tcx>, BinOp)> {
121        for stmt in &switch_block.statements {
122            if let StatementKind::Assign(assign) = &stmt.kind {
123                let (lhs, rvalue) = &**assign;
124                if let Rvalue::BinaryOp(bin_op, pair) = rvalue {
125                    let (op1, op2) = &**pair;
126                    if lhs == place {
127                        let return_op1: &Operand<'tcx> = &op1;
128                        let return_op2: &Operand<'tcx> = &op2;
129
130                        return Some((return_op1.clone(), return_op2.clone(), *bin_op));
131                    }
132                }
133            }
134        }
135        None
136    }
137    fn make_const_operand(&self, val: u64) -> Operand<'tcx> {
138        Operand::Constant(Box::new(ConstOperand {
139            span: rustc_span::DUMMY_SP,
140            user_ty: None,
141            const_: Const::from_usize(self.tcx, val),
142        }))
143    }
144
145    fn op_to_code(op: BinOp) -> u64 {
146        match op {
147            BinOp::Lt => 1,
148            BinOp::Le => 2,
149            BinOp::Ge => 3,
150            BinOp::Gt => 4,
151            BinOp::Eq => 5,
152            BinOp::Ne => 6,
153            _ => 7,
154        }
155    }
156    fn trace_operand_source(
157        &self,
158        body: &Body<'tcx>,
159        mut current_block: BasicBlock,
160        target_place: Place<'tcx>,
161    ) -> Operand<'tcx> {
162        let mut visited = HashSet::new();
163        let current_place = target_place;
164
165        while visited.insert(current_block) {
166            let data = &body.basic_blocks[current_block];
167            for stmt in data.statements.iter().rev() {
168                if let StatementKind::Assign(assign) = &stmt.kind {
169                    let (lhs, rvalue) = &**assign;
170                    if *lhs == current_place {
171                        match rvalue {
172                            Rvalue::Use(op, ..) => return op.clone(),
173                            _ => return Operand::Copy(current_place),
174                        }
175                    }
176                }
177            }
178
179            let preds = &body.basic_blocks.predecessors()[current_block];
180            if preds.len() == 1 {
181                current_block = preds[0];
182            } else {
183                break;
184            }
185        }
186
187        Operand::Copy(current_place)
188    }
189    // This function inserts eSSA (extended SSA) assignment statements into the basic block.
190    // These statements capture control flow information by asserting conditions on variables
191    // based on the outcome of a switch (branching) instruction.
192    fn essa_assign_statement(
193        &mut self,
194        bb: &BasicBlock,
195        switch_block: &BasicBlock,
196        value: u128,
197        discr: &Operand<'tcx>,
198        body: &mut Body<'tcx>,
199    ) {
200        let switch_block_data = &body.basic_blocks[*switch_block];
201
202        let magic_number_operand = self.make_const_operand(switch_block.as_usize() as u64);
203
204        // Helper: verify if the discriminant is a Place (variable).
205        if let Operand::Copy(switch_place) | Operand::Move(switch_place) = discr {
206            // Attempt to extract the binary condition that led to this switch.
207            if let Some((op1, op2, cmp_op)) =
208                self.extract_condition(switch_place, switch_block_data)
209            {
210                let op1 = if let Some(p1) = op1.place() {
211                    self.trace_operand_source(body, *switch_block, p1)
212                } else {
213                    op1
214                };
215
216                let op2 = if let Some(p2) = op2.place() {
217                    self.trace_operand_source(body, *switch_block, p2)
218                } else {
219                    op2
220                };
221                rap_debug!(
222                    "essa trace_operand_source op1:{:?} op2:{:?} cmp_op:{:?} value:{:?}\n",
223                    op1,
224                    op2,
225                    cmp_op,
226                    value
227                );
228                let block_data: &mut BasicBlockData<'tcx> = &mut body.basic_blocks.as_mut()[*bb];
229
230                let const_op1: Option<&ConstOperand<'_>> = op1.constant();
231                let const_op2: Option<&ConstOperand<'_>> = op2.constant();
232
233                // Generate operands for the comparison operators.
234                let cmp_operand = self.make_const_operand(Self::op_to_code(cmp_op));
235                let flip_cmp_operand =
236                    self.make_const_operand(Self::op_to_code(Self::flip(cmp_op)));
237                let reverse_cmp_operand =
238                    self.make_const_operand(Self::op_to_code(Self::reverse(cmp_op)));
239                let flip_reverse_cmp_operand =
240                    self.make_const_operand(Self::op_to_code(Self::flip(Self::reverse(cmp_op))));
241
242                match (const_op1, const_op2) {
243                    // Case 1: Both operands are places (variables).
244                    (None, None) => {
245                        match (op1, op2) {
246                            (
247                                Operand::Copy(p1) | Operand::Move(p1),
248                                Operand::Copy(p2) | Operand::Move(p2),
249                            ) => {
250                                let adt_kind = AggregateKind::Adt(
251                                    self.ssatransformer.essa_def_id.clone(),
252                                    rustc_abi::VariantIdx::from_u32(0),
253                                    GenericArgs::empty(),
254                                    None,
255                                    None,
256                                );
257                                let place1 = Place::from(p1);
258                                let place2 = Place::from(p2);
259                                let rvalue1;
260                                let rvalue2;
261                                let mut operand1: IndexVec<_, _> = IndexVec::with_capacity(4);
262                                let mut operand2: IndexVec<_, _> = IndexVec::with_capacity(4);
263
264                                // Determine constraints based on whether the condition was true (value != 0) or false (value == 0).
265                                if value == 0 {
266                                    // False branch: Use flipped operators.
267                                    // For p1: p1 (negated_op) p2
268                                    operand1.push(Operand::Copy(Place::from(p1)));
269                                    operand1.push(Operand::Copy(Place::from(p2)));
270                                    operand1.push(flip_cmp_operand.clone());
271                                    operand1.push(magic_number_operand.clone());
272
273                                    // For p2: p2 (negated_reversed_op) p1
274                                    operand2.push(Operand::Copy(Place::from(p2)));
275                                    operand2.push(Operand::Copy(Place::from(p1)));
276                                    operand2.push(flip_reverse_cmp_operand.clone());
277                                    operand2.push(magic_number_operand.clone());
278
279                                    rvalue1 =
280                                        Rvalue::Aggregate(Box::new(adt_kind.clone()), operand1);
281                                    rvalue2 =
282                                        Rvalue::Aggregate(Box::new(adt_kind.clone()), operand2);
283                                } else {
284                                    // True branch: Use original operators.
285                                    // For p1: p1 (op) p2
286                                    operand1.push(Operand::Copy(Place::from(p1)));
287                                    operand1.push(Operand::Copy(Place::from(p2)));
288                                    operand1.push(cmp_operand.clone());
289                                    operand1.push(magic_number_operand.clone());
290
291                                    // For p2: p2 (reversed_op) p1
292                                    operand2.push(Operand::Copy(Place::from(p2)));
293                                    operand2.push(Operand::Copy(Place::from(p1)));
294                                    operand2.push(reverse_cmp_operand.clone());
295                                    operand2.push(magic_number_operand.clone());
296
297                                    rvalue1 =
298                                        Rvalue::Aggregate(Box::new(adt_kind.clone()), operand1);
299                                    rvalue2 =
300                                        Rvalue::Aggregate(Box::new(adt_kind.clone()), operand2);
301                                }
302
303                                let assign_stmt1 = Statement::new(
304                                    SourceInfo::outermost(body.span),
305                                    StatementKind::Assign(Box::new((place1, rvalue1))),
306                                );
307                                let assign_stmt2 = Statement::new(
308                                    SourceInfo::outermost(body.span),
309                                    StatementKind::Assign(Box::new((place2, rvalue2))),
310                                );
311
312                                let mut insert_index = 0;
313                                for (i, stmt) in block_data.statements.iter().enumerate() {
314                                    if !SSATransformer::is_essa_statement(
315                                        &self.ssatransformer,
316                                        stmt,
317                                    ) {
318                                        break;
319                                    }
320                                    insert_index = i + 1;
321                                }
322
323                                block_data.statements.insert(insert_index, assign_stmt1);
324                                block_data.statements.insert(insert_index + 1, assign_stmt2);
325
326                                for i in insert_index..insert_index + 2 {
327                                    let essa_in_body = block_data.statements.get_mut(i).unwrap();
328                                    rap_trace!(
329                                        "Inserted eSSA statement {:?}  in block {:?}",
330                                        essa_in_body,
331                                        magic_number_operand
332                                    );
333                                }
334                            }
335                            _ => panic!("Expected a place"),
336                        };
337                    }
338
339                    // Case 2: One operand is a constant.
340                    (None, Some(_)) | (Some(_), None) => {
341                        let mut operand: IndexVec<_, _> = IndexVec::with_capacity(3);
342                        let place;
343
344                        // normalize operands: place always extracted as 'place', and stored first in operand list?
345                        // Actually logic keeps place as the key, but operand order in Aggregate is [Place, Other] or [Other, Place]?
346                        // Looking at logic below:
347                        // If op1 is place: operand.push(op1), operand.push(op2) -> [Place, Const]
348                        // If op2 is place: operand.push(op2), operand.push(op1) -> [Place, Const]
349                        // So the first element in Aggregate is always the Place (variable).
350
351                        if op1.constant().is_none() {
352                            place = match op1 {
353                                Operand::Copy(p) | Operand::Move(p) => Place::from(p),
354                                _ => panic!("Expected a place"),
355                            };
356                            operand.push(op1.clone());
357                            operand.push(op2.clone());
358                        } else {
359                            place = match op2 {
360                                Operand::Copy(p) | Operand::Move(p) => Place::from(p),
361                                _ => panic!("Expected a place"),
362                            };
363                            operand.push(op2.clone());
364                            operand.push(op1.clone());
365                        }
366
367                        let rvalue;
368                        if value == 0 {
369                            operand.push(flip_cmp_operand.clone());
370                        } else {
371                            operand.push(cmp_operand.clone());
372                        }
373                        operand.push(magic_number_operand.clone());
374                        let adt_kind = AggregateKind::Adt(
375                            self.ssatransformer.essa_def_id.clone(),
376                            rustc_abi::VariantIdx::from_u32(0),
377                            GenericArgs::empty(),
378                            None,
379                            None,
380                        );
381                        rvalue = Rvalue::Aggregate(Box::new(adt_kind.clone()), operand);
382
383                        let assign_stmt = Statement::new(
384                            SourceInfo::outermost(body.span),
385                            StatementKind::Assign(Box::new((place, rvalue))),
386                        );
387                        let mut insert_index = 0;
388                        for (i, stmt) in block_data.statements.iter().enumerate() {
389                            if !SSATransformer::is_essa_statement(&self.ssatransformer, stmt) {
390                                break;
391                            }
392                            insert_index = i + 1;
393                        }
394
395                        block_data.statements.insert(insert_index, assign_stmt);
396
397                        let essa_in_body = block_data.statements.get_mut(insert_index).unwrap();
398                        let essa_ptr = essa_in_body as *const _;
399
400                        rap_trace!(
401                            "Inserted eSSA statement {:?}  in block {:?}",
402                            essa_in_body,
403                            magic_number_operand
404                        );
405                    }
406
407                    (Some(_), Some(_)) => {}
408                }
409            };
410        }
411
412        // block_data.statements.insert(0, assign_stmt);
413    }
414    pub fn flip(binOp: BinOp) -> BinOp {
415        match binOp {
416            BinOp::Lt => BinOp::Ge,
417            BinOp::Le => BinOp::Gt,
418            BinOp::Gt => BinOp::Le,
419            BinOp::Ge => BinOp::Lt,
420            BinOp::Eq => BinOp::Ne,
421            BinOp::Ne => BinOp::Eq,
422            _ => panic!("flip() called on non-comparison operator"),
423        }
424    }
425    pub fn reverse(binOp: BinOp) -> BinOp {
426        match binOp {
427            BinOp::Lt => BinOp::Gt,
428            BinOp::Le => BinOp::Ge,
429            BinOp::Gt => BinOp::Lt,
430            BinOp::Ge => BinOp::Le,
431            BinOp::Eq => BinOp::Ne,
432            BinOp::Ne => BinOp::Eq,
433            _ => panic!("flip() called on non-comparison operator"),
434        }
435    }
436    pub fn rename_variables(&mut self, body: &mut Body<'tcx>) {
437        for local in body.local_decls.indices() {
438            self.ssatransformer.reaching_def.insert(local, None);
439        }
440        // self.ssatransformer.local_defination_block = Self::map_locals_to_definition_block(&self.body.borrow());
441
442        let order = SSATransformer::depth_first_search_preorder(
443            &self.ssatransformer.dom_tree,
444            body.basic_blocks.indices().next().unwrap().clone(),
445        );
446        for bb in order {
447            self.process_basic_block(bb, body);
448        }
449
450        rap_debug!("new_locals_to_declare {:?}", self.new_locals_to_declare);
451
452        let mut locals_to_add: Vec<_> = self.new_locals_to_declare.iter().collect();
453        locals_to_add.sort_by_key(|(new_local, _)| new_local.index());
454        rap_debug!("locals_to_add {:?}", locals_to_add);
455        for (new_local, original_local) in locals_to_add {
456            let original_decl = &body.local_decls[*original_local];
457
458            let new_decl = original_decl.clone();
459
460            let pushed_index = body.local_decls.push(new_decl);
461            rap_debug!("Ok with {:?} {:?}", pushed_index, *new_local);
462            assert_eq!(pushed_index, *new_local);
463        }
464    }
465
466    fn process_basic_block(&mut self, bb: BasicBlock, body: &mut Body<'tcx>) {
467        self.rename_statement(bb, body);
468        self.rename_terminator(bb, body);
469        let terminator = body.basic_blocks[bb].terminator();
470        let successors: Vec<_> = terminator.successors().collect();
471        if let TerminatorKind::SwitchInt { targets, .. } = &terminator.kind {
472            if targets.iter().count() == 1 {
473                for succ_bb in successors.clone() {
474                    self.rename_essa_statments(succ_bb, body, bb);
475                }
476            }
477        }
478
479        for succ_bb in successors {
480            self.rename_phi_functions(succ_bb, body, bb);
481        }
482    }
483    fn rename_essa_statments(
484        &mut self,
485        succ_bb: BasicBlock,
486        body: &mut Body<'tcx>,
487        do_bb: BasicBlock,
488    ) {
489        // Iterate through all statements in the successor basic block to find and update ESSA nodes.
490        for statement in body.basic_blocks.as_mut()[succ_bb].statements.iter_mut() {
491            // Check if the current statement is an ESSA statement (identified by specific DefId).
492            if self.ssatransformer.is_essa_statement(statement) {
493                // Retrieve the source basic block ID encoded in the statement's operands.
494                // This replaces the unstable pointer-based lookup map.
495                if let Some(pred_block) = self.ssatransformer.get_essa_source_block(statement) {
496                    // Check if this ESSA statement corresponds to the predecessor block (`do_bb`)
497                    // we are currently processing. If not, skip it.
498                    if pred_block != do_bb {
499                        continue;
500                    }
501
502                    // Proceed to rename the variable in the ESSA statement.
503                    if let StatementKind::Assign(assign) = &mut statement.kind {
504                        let (_, rvalue) = &mut **assign;
505                        if let Rvalue::Aggregate(_, operands) = rvalue {
506                            // The first operand (index 0) is the variable that needs to be renamed/replaced.
507                            let index = 0;
508                            if index < operands.len() {
509                                // Replace the operand with the correct SSA version for the current path.
510                                self.replace_operand(
511                                    &mut operands[FieldIdx::from_usize(index)],
512                                    &do_bb,
513                                );
514                            }
515                        }
516                    }
517                }
518            }
519        }
520    }
521
522    fn rename_phi_functions(
523        &mut self,
524        succ_bb: BasicBlock,
525        body: &mut Body<'tcx>,
526        do_bb: BasicBlock,
527    ) {
528        for (stmt_idx, statement) in body.basic_blocks.as_mut()[succ_bb]
529            .statements
530            .iter_mut()
531            .enumerate()
532        {
533            let location = Location {
534                block: succ_bb,
535                statement_index: stmt_idx,
536            };
537
538            if SSATransformer::is_phi_statement(&self.ssatransformer, statement) {
539                if let StatementKind::Assign(assign) = &mut statement.kind {
540                    let (_, rvalue) = &mut **assign;
541                    if let Rvalue::Aggregate(_, operands) = rvalue {
542                        let operand_count = operands.len();
543                        let index = *self.ssatransformer.phi_index.entry(location).or_insert(0);
544
545                        if index < operand_count {
546                            match &mut operands[FieldIdx::from_usize(index)] {
547                                Operand::Copy(place) | Operand::Move(place) => {
548                                    self.replace_place(place, &do_bb);
549                                }
550                                _ => {}
551                            }
552                            *self.ssatransformer.phi_index.entry(location).or_insert(0) += 1;
553                        }
554                    }
555                }
556            }
557        }
558    }
559    pub fn rename_statement(&mut self, bb: BasicBlock, body: &mut Body<'tcx>) {
560        for statement in body.basic_blocks.as_mut()[bb].statements.iter_mut() {
561            // let rc_stat = Rc::new(RefCell::new(statement));
562            let is_phi = SSATransformer::is_phi_statement(&self.ssatransformer, statement);
563            let is_essa = SSATransformer::is_essa_statement(&self.ssatransformer, statement);
564            rap_trace!(
565                "IS in statement at block {:?}: {:?}, is_phi: {}, is_essa: {}",
566                bb,
567                statement.clone(),
568                is_phi,
569                is_essa
570            );
571            match &mut statement.kind {
572                StatementKind::Assign(assign) => {
573                    let (place, rvalue) = &mut **assign;
574                    if !is_phi {
575                        if !is_essa {
576                            rap_trace!(
577                                "Renaming in statement at block {:?}: {:?}",
578                                bb,
579                                rvalue.clone()
580                            );
581                            self.replace_rvalue(rvalue, &bb);
582                            self.rename_local_def(place, &bb, true);
583                        } else {
584                            self.ssa_rename_local_def(place, &bb, true);
585                        }
586                    } else {
587                        self.ssa_rename_local_def(place, &bb, false);
588                    }
589                }
590                // StatementKind::FakeRead(_, place)
591                StatementKind::StorageLive(local) => {
592                    // self.rename_local_def(*local);
593                }
594                StatementKind::StorageDead(local) => {
595                    // self.replace_local(local);
596                }
597                _ => {}
598            }
599        }
600    }
601
602    fn rename_terminator(&mut self, bb: BasicBlock, body: &mut Body<'tcx>) {
603        let terminator: &mut Terminator<'tcx> = body.basic_blocks.as_mut()[bb].terminator_mut();
604        match &mut terminator.kind {
605            TerminatorKind::Call {
606                args, destination, ..
607            } => {
608                for op in args.iter_mut() {
609                    match &mut op.node {
610                        Operand::Copy(place) | Operand::Move(place) => {
611                            self.replace_place(place, &bb);
612                        }
613                        Operand::Constant(const_operand) => {}
614                        #[cfg(rapx_ge_99)]
615                        Operand::RuntimeChecks(_) => {}
616                    }
617                }
618                self.rename_local_def(destination, &bb, true);
619            }
620            TerminatorKind::Assert { cond, .. } => {
621                self.replace_operand(cond, &bb);
622            }
623            TerminatorKind::Drop { place, .. } => {
624                self.replace_place(place, &bb);
625            }
626            TerminatorKind::SwitchInt { discr, .. } => {
627                self.replace_operand(discr, &bb);
628            }
629            _ => {}
630        }
631    }
632
633    fn replace_rvalue(&mut self, rvalue: &mut Rvalue<'tcx>, bb: &BasicBlock) {
634        match rvalue {
635            Rvalue::Use(operand, ..)
636            | Rvalue::Repeat(operand, _)
637            | Rvalue::UnaryOp(_, operand)
638            | Rvalue::Cast(_, operand, _) => {
639                self.replace_operand(operand, &bb);
640            }
641            #[cfg(not(rapx_ge_99))]
642            Rvalue::ShallowInitBox(operand, _) => {
643                self.replace_operand(operand, &bb);
644            }
645            Rvalue::BinaryOp(_, pair) => {
646                let (lhs, rhs) = &mut **pair;
647                self.replace_operand(lhs, &bb);
648                self.replace_operand(rhs, &bb);
649            }
650            Rvalue::Aggregate(_, operands) => {
651                for operand in operands {
652                    self.replace_operand(operand, &bb);
653                }
654            }
655            _ => {}
656        }
657    }
658
659    fn replace_operand(&mut self, operand: &mut Operand<'tcx>, bb: &BasicBlock) {
660        match operand {
661            Operand::Copy(place) | Operand::Move(place) => {
662                self.replace_place(place, bb);
663                // print!("replace_operand: {:?} -> {:?}\n", place.local, place.local);
664            }
665            _ => {}
666        }
667    }
668
669    fn replace_place(&mut self, place: &mut Place<'tcx>, bb: &BasicBlock) {
670        // let old_local = place.local;
671        self.update_reachinf_def(&place.local, &bb);
672
673        if let Some(Some(reaching_local)) = self.ssatransformer.reaching_def.get(&place.local) {
674            let local = reaching_local.clone();
675            let mut new_place: Place<'_> = Place::from(local);
676            new_place.projection = place.projection;
677
678            *place = new_place;
679        } else {
680        }
681    }
682
683    fn ssa_rename_local_def(&mut self, place: &mut Place<'tcx>, bb: &BasicBlock, not_phi: bool) {
684        // let old_local = place.as_local().as_mut().unwrap();
685        self.update_reachinf_def(&place.local, &bb);
686        let Place {
687            local: old_local,
688            projection: _,
689        } = place.clone();
690        let old_place = place.clone();
691        if old_local.as_u32() == 0 {
692            return;
693        }
694        let new_local = Local::from_usize(self.ssatransformer.local_index);
695        self.ssatransformer.local_index += 1;
696        let new_place: Place<'_> = Place::from(new_local);
697        *place = new_place.clone();
698        self.new_locals_to_declare.insert(new_local, old_local);
699
700        let _old_local = old_local.clone();
701        self.ssatransformer
702            .ssa_locals_map
703            .entry(old_place)
704            .or_insert_with(HashSet::new)
705            .insert(new_place);
706
707        self.ssatransformer
708            .local_defination_block
709            .insert(new_local.clone(), bb.clone());
710        let old_local_reaching = self
711            .ssatransformer
712            .reaching_def
713            .get(&_old_local.clone())
714            .unwrap();
715
716        self.ssatransformer
717            .reaching_def
718            .insert(new_local.clone(), *old_local_reaching);
719        self.ssatransformer
720            .reaching_def
721            .insert(_old_local.clone(), Some(new_local.clone()));
722
723        // self.reaching_def
724        //     .entry(old_local)
725        //     .or_default()
726        //     .replace(Some(old_local));
727    }
728    fn rename_local_def(&mut self, place: &mut Place<'tcx>, bb: &BasicBlock, not_phi: bool) {
729        // let old_local = place.as_local().as_mut().unwrap();
730        self.update_reachinf_def(&place.local, &bb);
731        let Place {
732            local: old_local,
733            projection: _,
734        } = place.clone();
735        let old_place = place.clone();
736        if old_local.as_u32() == 0 {
737            return;
738        }
739
740        if self.ssatransformer.skipped.contains(&old_local.as_usize()) && not_phi {
741            self.ssatransformer.skipped.remove(&old_local.as_usize());
742            self.ssatransformer
743                .reaching_def
744                .insert(old_local, Some(old_local));
745            self.ssatransformer
746                .places_map
747                .entry(old_place)
748                .or_insert_with(HashSet::new)
749                .insert(old_place);
750            return;
751        }
752        let new_local = Local::from_usize(self.ssatransformer.local_index);
753        let mut new_place: Place<'_> = Place::from(new_local);
754        self.new_locals_to_declare.insert(new_local, old_local);
755
756        new_place.projection = place.projection;
757        *place = new_place.clone();
758
759        //find the original local defination assign statement
760        if old_local.as_u32() == 0 {
761            return;
762        }
763
764        self.ssatransformer.local_index += 1;
765        self.ssatransformer
766            .places_map
767            .entry(old_place)
768            .or_insert_with(HashSet::new)
769            .insert(new_place);
770
771        let _old_local = old_local.clone();
772        self.ssatransformer
773            .local_defination_block
774            .insert(new_local.clone(), bb.clone());
775        let old_local_reaching = self
776            .ssatransformer
777            .reaching_def
778            .get(&_old_local.clone())
779            .unwrap();
780
781        self.ssatransformer
782            .reaching_def
783            .insert(new_local.clone(), *old_local_reaching);
784        self.ssatransformer
785            .reaching_def
786            .insert(_old_local.clone(), Some(new_local.clone()));
787
788        // self.reaching_def
789        //     .entry(old_local)
790        //     .or_default()
791        //     .replace(Some(old_local));
792    }
793
794    pub fn dominates_(&self, def_bb: &BasicBlock, bb: &BasicBlock) -> bool {
795        let mut visited = HashSet::new();
796
797        let mut stack = self.ssatransformer.dom_tree.get(def_bb).unwrap().clone();
798        while let Some(block) = stack.pop() {
799            if !visited.insert(block) {
800                continue;
801            }
802
803            if block == *bb {
804                return true;
805            }
806
807            if let Some(children) = self.ssatransformer.dom_tree.get(&block) {
808                stack.extend(children);
809            }
810        }
811
812        false
813    }
814    fn update_reachinf_def(&mut self, local: &Local, bb: &BasicBlock) {
815        // if self.ssatransformer.reaching_def[local]!= None {
816        //     return;
817        // }
818        let mut r = self.ssatransformer.reaching_def[local];
819        let mut dominate_bool = true;
820        if r != None {
821            let def_bb = self.ssatransformer.local_defination_block[&r.unwrap()];
822        }
823
824        while !(r == None || dominate_bool) {
825            r = self.ssatransformer.reaching_def[&r.unwrap()];
826            if r != None {
827                let def_bb = self.ssatransformer.local_defination_block[&r.unwrap()];
828
829                dominate_bool = self.dominates_(&def_bb, bb);
830            }
831        }
832
833        if let Some(entry) = self.ssatransformer.reaching_def.get_mut(local) {
834            *entry = r.clone();
835        }
836    }
837}