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