rapx/analysis/ssa_transform/
Replacer.rs

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