1#![allow(non_snake_case)]
2#![allow(unused_variables)]
3#![allow(dead_code)]
4use super::SSATransformer::SSATransformer;
5use rustc_abi::FieldIdx;
6use rustc_index::IndexVec;
7use rustc_middle::ty::TyCtxt;
8use rustc_middle::{mir::*, ty::GenericArgs};
9use std::collections::{HashMap, HashSet, VecDeque};
10pub struct Replacer<'tcx> {
16 pub(crate) tcx: TyCtxt<'tcx>,
17 pub(crate) ssatransformer: super::SSATransformer::SSATransformer<'tcx>,
18 pub(crate) new_local_collection: HashSet<Local>,
19}
20impl<'tcx> Replacer<'tcx> {
21 pub fn insert_phi_statment(&mut self, body: &mut Body<'tcx>) {
22 for (block_index, blockdata) in body.basic_blocks.iter_enumerated() {}
23 let mut phi_functions: HashMap<BasicBlock, HashSet<Local>> = HashMap::new();
24 for bb in body.basic_blocks.indices() {
25 phi_functions.insert(bb, HashSet::new());
26 }
27 let variables: Vec<Local> = self
28 .ssatransformer
29 .local_assign_blocks
30 .iter()
31 .filter(|(_, blocks)| blocks.len() >= 2)
32 .map(|(&local, _)| local)
33 .collect();
34 for var in &variables {
35 if let Some(def_blocks) = self.ssatransformer.local_assign_blocks.get(var) {
36 let mut worklist: VecDeque<BasicBlock> = def_blocks.iter().cloned().collect();
37 let mut processed: HashSet<BasicBlock> = HashSet::new();
38
39 while let Some(block) = worklist.pop_front() {
40 if let Some(df_blocks) = self.ssatransformer.df.get(&block) {
41 for &df_block in df_blocks {
42 if !processed.contains(&df_block) {
43 phi_functions.get_mut(&df_block).unwrap().insert(*var);
44 processed.insert(df_block);
45 if self.ssatransformer.local_assign_blocks[var].contains(&df_block)
46 {
47 worklist.push_back(df_block);
48 }
49 }
50 }
51 }
52 }
53 }
54 }
55
56 for (block, vars) in phi_functions {
57 for var in vars.clone() {
58 let decl = body.local_decls[var].clone();
59 let predecessors = body.basic_blocks.predecessors()[block].clone();
63
64 let mut operands = IndexVec::with_capacity(predecessors.len());
65 for _ in 0..predecessors.len() {
66 operands.push(Operand::Copy(Place::from(var)));
67 }
68 let phi_stmt: Statement<'_> = Statement {
69 source_info: SourceInfo::outermost(body.span),
70 kind: StatementKind::Assign(Box::new((
71 Place::from(var),
72 Rvalue::Aggregate(
73 Box::new(AggregateKind::Adt(
74 self.ssatransformer.phi_def_id.clone(),
75 rustc_abi::VariantIdx::from_u32(0),
76 GenericArgs::empty(),
77 None,
78 None,
79 )),
80 operands,
81 ),
82 ))),
83 };
84 body.basic_blocks_mut()[block]
92 .statements
93 .insert(0, phi_stmt);
94 }
95
96 for i in 0..vars.len() {
97 let phi_in_body = body.basic_blocks.as_mut()[block]
98 .statements
99 .get_mut(i)
100 .unwrap();
101 let phi_ptr = phi_in_body as *const _;
102 self.ssatransformer.phi_statements.insert(phi_ptr, true);
103 }
104 }
105 }
106 pub fn insert_essa_statement(&mut self, body: &mut Body<'tcx>) {
107 let order = SSATransformer::depth_first_search_preorder(
108 &self.ssatransformer.dom_tree,
109 body.basic_blocks.indices().next().unwrap(),
110 );
111
112 for &bb in &order {
113 self.essa_process_basic_block(bb, body);
114 }
115 }
116
117 fn essa_process_basic_block(&mut self, bb: BasicBlock, body: &mut Body<'tcx>) {
118 let switch_block_data = body.basic_blocks[bb].clone();
119
120 if let Some(terminator) = &switch_block_data.terminator {
121 if let TerminatorKind::SwitchInt { discr, targets, .. } = &terminator.kind {
122 {
123 for (value, target) in targets.iter() {
124 self.essa_assign_statement(&target, &bb, value, discr, body);
125 }
126 let otherwise = targets.otherwise();
127
128 self.essa_assign_statement(&otherwise, &bb, 1, discr, body);
129 }
130 }
131 }
132 }
133 fn extract_condition(
134 &self,
135 place: &Place<'tcx>,
136 switch_block: &BasicBlockData<'tcx>,
137 ) -> Option<(Operand<'tcx>, Operand<'tcx>, BinOp)> {
138 for stmt in &switch_block.statements {
139 if let StatementKind::Assign(box (lhs, Rvalue::BinaryOp(bin_op, box (op1, op2)))) =
140 &stmt.kind
141 {
142 if lhs == place {
143 let mut return_op1: &Operand<'tcx> = &op1;
144 let mut return_op2: &Operand<'tcx> = &op2;
145 for stmt_original in &switch_block.statements {
146 if let StatementKind::Assign(box (lhs, Rvalue::Use(OP1))) =
147 &stmt_original.kind
148 {
149 if lhs.clone() == op1.place().unwrap() {
150 return_op1 = OP1;
151 }
152 }
153 }
154 if op2.constant().is_none() {
155 for stmt_original in &switch_block.statements {
156 if let StatementKind::Assign(box (lhs, Rvalue::Use(OP2))) =
157 &stmt_original.kind
158 {
159 if lhs.clone() == op2.place().unwrap() {
160 return_op2 = OP2;
161 }
162 }
163 }
164 }
165 return Some((return_op1.clone(), return_op2.clone(), *bin_op));
166 }
167 }
168 }
169 None
170 }
171 fn essa_assign_statement(
173 &mut self,
174 bb: &BasicBlock,
175 switch_block: &BasicBlock,
176 value: u128,
177 discr: &Operand<'tcx>,
178 body: &mut Body<'tcx>,
179 ) {
180 let switch_block_data = &body.basic_blocks[*switch_block];
181
182 let magic_number = 213134123 as u64;
184 let magic_number_operand = Operand::Constant(Box::new(ConstOperand {
185 span: rustc_span::DUMMY_SP,
186 user_ty: None,
187 const_: Const::from_usize(self.tcx, magic_number),
188 }));
189 let Lt_operand = Operand::Constant(Box::new(ConstOperand {
190 span: rustc_span::DUMMY_SP,
191 user_ty: None,
192 const_: Const::from_usize(self.tcx, 1),
193 }));
194 let Le_operand = Operand::Constant(Box::new(ConstOperand {
195 span: rustc_span::DUMMY_SP,
196 user_ty: None,
197 const_: Const::from_usize(self.tcx, 2),
198 }));
199 let Ge_operand = Operand::Constant(Box::new(ConstOperand {
200 span: rustc_span::DUMMY_SP,
201 user_ty: None,
202 const_: Const::from_usize(self.tcx, 3),
203 }));
204 let Gt_operand = Operand::Constant(Box::new(ConstOperand {
205 span: rustc_span::DUMMY_SP,
206 user_ty: None,
207 const_: Const::from_usize(self.tcx, 4),
208 }));
209 if let Operand::Copy(switch_place) | Operand::Move(switch_place) = discr {
210 if let Some((op1, op2, cmp_op)) =
211 self.extract_condition(switch_place, switch_block_data)
212 {
213 let block_data: &mut BasicBlockData<'tcx> = &mut body.basic_blocks.as_mut()[*bb];
214
215 let const_op1: Option<&ConstOperand<'_>> = op1.constant();
216 let const_op2: Option<&ConstOperand<'_>> = op2.constant();
217 let cmp_operand: Operand<'_> = match cmp_op.clone() {
218 BinOp::Lt => Lt_operand.clone(),
219 BinOp::Le => Le_operand.clone(),
220 BinOp::Gt => Gt_operand.clone(),
221 BinOp::Ge => Ge_operand.clone(),
222 _ => panic!("not a comparison operator"),
223 };
224 let flip_cmp_operand: Operand<'_> = match Self::flip(cmp_op) {
225 BinOp::Lt => Gt_operand.clone(),
226 BinOp::Le => Ge_operand.clone(),
227 BinOp::Gt => Lt_operand.clone(),
228 BinOp::Ge => Le_operand.clone(),
229 _ => panic!("not a comparison operator"),
230 };
231
232 match (const_op1, const_op2) {
233 (None, None) => {
234 match (op1, op2) {
235 (
236 Operand::Copy(p1) | Operand::Move(p1),
237 Operand::Copy(p2) | Operand::Move(p2),
238 ) => {
239 let ADT = AggregateKind::Adt(
240 self.ssatransformer.essa_def_id.clone(),
241 rustc_abi::VariantIdx::from_u32(0),
242 GenericArgs::empty(),
243 None,
244 None,
245 );
246 let place1 = Place::from(p1);
247 let place2 = Place::from(p2);
248 let rvalue1;
249 let rvalue2;
250 let mut operand1: IndexVec<_, _> = IndexVec::with_capacity(4);
251 let mut operand2: IndexVec<_, _> = IndexVec::with_capacity(4);
252
253 if value == 0 {
254 operand1.push(Operand::Copy(Place::from(p1)));
255 operand1.push(Operand::Copy(Place::from(p2)));
256 operand1.push(flip_cmp_operand.clone());
257 operand1.push(magic_number_operand.clone());
258
259 operand2.push(Operand::Copy(Place::from(p2)));
260 operand2.push(Operand::Copy(Place::from(p1)));
261 operand2.push(cmp_operand.clone());
262 operand2.push(magic_number_operand.clone());
263 rvalue1 = Rvalue::Aggregate(Box::new(ADT.clone()), operand1);
268 rvalue2 = Rvalue::Aggregate(Box::new(ADT.clone()), operand2);
269 } else {
270 operand1.push(Operand::Copy(Place::from(p1)));
271 operand1.push(Operand::Copy(Place::from(p2)));
272 operand1.push(cmp_operand.clone());
273 operand1.push(magic_number_operand.clone());
274
275 operand2.push(Operand::Copy(Place::from(p2)));
276 operand2.push(Operand::Copy(Place::from(p1)));
277 operand2.push(flip_cmp_operand.clone());
278 operand2.push(magic_number_operand.clone());
279 rvalue1 = Rvalue::Aggregate(Box::new(ADT.clone()), operand1);
284 rvalue2 = Rvalue::Aggregate(Box::new(ADT.clone()), operand2);
285 }
286
287 let assign_stmt1 = Statement {
288 source_info: SourceInfo::outermost(body.span),
289 kind: StatementKind::Assign(Box::new((place1, rvalue1))),
290 };
291 let assign_stmt2 = Statement {
292 source_info: SourceInfo::outermost(body.span),
293 kind: StatementKind::Assign(Box::new((place2, rvalue2))),
294 };
295 block_data.statements.insert(0, assign_stmt2);
296 block_data.statements.insert(0, assign_stmt1);
297
298 for i in 0..2 {
299 let essa_in_body = block_data.statements.get_mut(i).unwrap();
300 let essa_ptr = essa_in_body as *const _;
301 self.ssatransformer.essa_statements.insert(essa_ptr, true);
302 }
303 }
304 _ => panic!("Expected a place"),
305 };
306 }
307 (None, Some(_)) | (Some(_), None) => {
308 let mut operand: IndexVec<_, _> = IndexVec::with_capacity(3);
309
310 let place = match op1 {
311 Operand::Copy(p) | Operand::Move(p) => Place::from(p),
312 _ => panic!("Expected a place"),
313 };
314 operand.push(op1.clone());
315 operand.push(op2.clone());
316 let rvalue;
317 if value == 0 {
318 operand.push(flip_cmp_operand.clone());
319 } else {
320 operand.push(cmp_operand.clone());
321 }
322 let ADT = AggregateKind::Adt(
323 self.ssatransformer.essa_def_id.clone(),
324 rustc_abi::VariantIdx::from_u32(0),
325 GenericArgs::empty(),
326 None,
327 None,
328 );
329 rvalue = Rvalue::Aggregate(Box::new(ADT.clone()), operand);
330 let assign_stmt = Statement {
331 source_info: SourceInfo::outermost(body.span),
332 kind: StatementKind::Assign(Box::new((place, rvalue))),
333 };
334 block_data.statements.insert(0, assign_stmt);
335
336 for i in 0..1 {
337 let essa_in_body = block_data.statements.get_mut(i).unwrap();
338 let essa_ptr = essa_in_body as *const _;
339 self.ssatransformer.essa_statements.insert(essa_ptr, true);
340 }
341 }
342
343 (Some(_), Some(_)) => {}
344 }
345 };
346 }
347
348 }
350 pub fn flip(binOp: BinOp) -> BinOp {
351 match binOp {
352 BinOp::Lt => BinOp::Ge,
353 BinOp::Le => BinOp::Gt,
354 BinOp::Gt => BinOp::Le,
355 BinOp::Ge => BinOp::Lt,
356 _ => panic!("flip() called on non-comparison operator"),
357 }
358 }
359 pub fn rename_variables(&mut self, body: &mut Body<'tcx>) {
360 for local in body.local_decls.indices() {
361 self.ssatransformer.reaching_def.insert(local, None);
362 }
363 let order = SSATransformer::depth_first_search_preorder(
366 &self.ssatransformer.dom_tree,
367 body.basic_blocks.indices().next().unwrap().clone(),
368 );
369 for bb in order {
370 self.process_basic_block(bb, body);
371 }
372 }
373
374 fn process_basic_block(&mut self, bb: BasicBlock, body: &mut Body<'tcx>) {
375 self.rename_statement(bb, body);
376 self.rename_terminator(bb, body);
377 let terminator = body.basic_blocks[bb].terminator();
378 let successors: Vec<_> = terminator.successors().collect();
379 if let TerminatorKind::SwitchInt { .. } = &terminator.kind {
380 for succ_bb in successors.clone() {
381 self.process_essa_statments(succ_bb, body, bb);
382 }
383 }
384
385 for succ_bb in successors {
386 self.process_phi_functions(succ_bb, body, bb);
387 }
388 }
389 pub fn process_essa_statments(
390 &mut self,
391 succ_bb: BasicBlock,
392 body: &mut Body<'tcx>,
393 switch_bb: BasicBlock,
394 ) {
395 let switch_block_data = &body.basic_blocks[switch_bb];
396 if let Some(terminator) = &switch_block_data.terminator {
397 if let TerminatorKind::SwitchInt { discr, .. } = &terminator.kind {
398 if let Operand::Copy(switch_place) | Operand::Move(switch_place) = discr {
399 if let Some((op1, op2, cmp_op)) =
400 self.extract_condition(switch_place, switch_block_data)
401 {
402 if op2.constant().is_none() {
403 let essa_statement = body.basic_blocks.as_mut()[succ_bb]
404 .statements
405 .get_mut(0)
406 .unwrap();
407 match &mut essa_statement.kind {
408 StatementKind::Assign(box (place, rvalue)) => {
409 if let Rvalue::Aggregate(_, operands) = rvalue {
410 let loc_1: usize = 0;
411 let loc_2: usize = 1;
412
413 operands[FieldIdx::from_usize(loc_1)] = op1.clone();
414 operands[FieldIdx::from_usize(loc_2)] = op2.clone();
415 }
416 }
417 _ => {}
418 }
419 let essa_statement = body.basic_blocks.as_mut()[succ_bb]
420 .statements
421 .get_mut(1)
422 .unwrap();
423 match &mut essa_statement.kind {
424 StatementKind::Assign(box (place, rvalue)) => {
425 if let Rvalue::Aggregate(_, operands) = rvalue {
426 let loc_1: usize = 0;
427 let loc_2: usize = 1;
428 operands[FieldIdx::from_usize(loc_1)] = op2.clone();
429 operands[FieldIdx::from_usize(loc_2)] = op1.clone();
430 }
431 }
432 _ => {}
433 }
434 } else {
435 let essa_statement = body.basic_blocks.as_mut()[succ_bb]
436 .statements
437 .get_mut(0)
438 .unwrap();
439 match &mut essa_statement.kind {
440 StatementKind::Assign(box (place, rvalue)) => {
441 if let Rvalue::Aggregate(_, operands) = rvalue {
442 let loc: usize = 0;
443 operands[FieldIdx::from_usize(loc)] = op1.clone();
444 }
445 }
446 _ => {}
447 }
448 }
449 }
450 }
451 }
452 }
453 }
454
455 fn process_phi_functions(
456 &mut self,
457 succ_bb: BasicBlock,
458 body: &mut Body<'tcx>,
459 do_bb: BasicBlock,
460 ) {
461 for statement in body.basic_blocks.as_mut()[succ_bb].statements.iter_mut() {
462 let phi_stmt = statement as *const _;
463
464 if SSATransformer::is_phi_statement(&self.ssatransformer, statement) {
465 if let StatementKind::Assign(box (_, rvalue)) = &mut statement.kind {
466 if let Rvalue::Aggregate(_, operands) = rvalue {
467 let operand_count = operands.len();
468 let index = self
469 .ssatransformer
470 .phi_index
471 .entry(phi_stmt)
472 .or_insert(0)
473 .clone();
474
475 if index < operand_count {
476 match &mut operands[FieldIdx::from_usize(index)] {
478 Operand::Copy(place) | Operand::Move(place) => {
479 self.replace_place(place, &do_bb);
480 }
481 _ => {}
482 }
483 *self.ssatransformer.phi_index.entry(phi_stmt).or_insert(0) += 1;
484 }
488 }
489 }
490 }
491 }
492 }
493
494 pub fn rename_statement(&mut self, bb: BasicBlock, body: &mut Body<'tcx>) {
495 for statement in body.basic_blocks.as_mut()[bb].statements.iter_mut() {
496 let is_phi = SSATransformer::is_phi_statement(&self.ssatransformer, statement);
498 let is_essa = SSATransformer::is_essa_statement(&self.ssatransformer, statement);
499 match &mut statement.kind {
500 StatementKind::Assign(box (place, rvalue)) => {
501 if !is_phi {
502 if !is_essa {
503 self.replace_rvalue(rvalue, &bb);
504 self.rename_local_def(place, &bb, true);
505 } else {
506 self.ssa_rename_local_def(place, &bb, true);
507 }
508 } else {
509 self.ssa_rename_local_def(place, &bb, false);
510 }
511 }
512 StatementKind::Deinit(place) | StatementKind::SetDiscriminant { place, .. } => {
514 }
518 StatementKind::StorageLive(local) => {
519 }
521 StatementKind::StorageDead(local) => {
522 }
524 _ => {}
525 }
526 }
527 }
528
529 fn rename_terminator(&mut self, bb: BasicBlock, body: &mut Body<'tcx>) {
530 let terminator: &mut Terminator<'tcx> = body.basic_blocks.as_mut()[bb].terminator_mut();
531 match &mut terminator.kind {
532 TerminatorKind::Call {
533 args, destination, ..
534 } => {
535 }
542 TerminatorKind::Assert { cond, .. } => {
543 self.replace_operand(cond, &bb);
544 }
545 TerminatorKind::Drop { place, .. } => {
546 self.replace_place(place, &bb);
547 }
548 TerminatorKind::SwitchInt { discr, .. } => {
549 self.replace_operand(discr, &bb);
550 }
551 _ => {}
552 }
553 }
554
555 fn replace_rvalue(&mut self, rvalue: &mut Rvalue<'tcx>, bb: &BasicBlock) {
556 match rvalue {
557 Rvalue::Use(operand)
558 | Rvalue::Repeat(operand, _)
559 | Rvalue::UnaryOp(_, operand)
560 | Rvalue::Cast(_, operand, _)
561 | Rvalue::ShallowInitBox(operand, _) => {
562 self.replace_operand(operand, &bb);
563 }
564 Rvalue::BinaryOp(_, box (lhs, rhs)) => {
565 self.replace_operand(lhs, &bb);
566 self.replace_operand(rhs, &bb);
567 }
568 Rvalue::Aggregate(_, operands) => {
569 for operand in operands {
570 self.replace_operand(operand, &bb);
571 }
572 }
573 _ => {}
574 }
575 }
576
577 fn replace_operand(&mut self, operand: &mut Operand<'tcx>, bb: &BasicBlock) {
578 match operand {
579 Operand::Copy(place) | Operand::Move(place) => {
580 self.replace_place(place, bb);
581 }
583 _ => {}
584 }
585 }
586
587 fn replace_place(&mut self, place: &mut Place<'tcx>, bb: &BasicBlock) {
588 self.update_reachinf_def(&place.local, &bb);
590
591 if let Some(Some(reaching_local)) = self.ssatransformer.reaching_def.get(&place.local) {
592 let local = reaching_local.clone();
593 *place = Place::from(local);
594 } else {
595 }
596 }
597
598 fn ssa_rename_local_def(&mut self, place: &mut Place<'tcx>, bb: &BasicBlock, not_phi: bool) {
599 self.update_reachinf_def(&place.local, &bb);
601 let Place {
602 local: old_local,
603 projection: _,
604 } = place;
605
606 let new_local = Local::from_u32(self.ssatransformer.local_index);
607 self.ssatransformer.local_index += 1;
608
609 let _old_local = old_local.clone();
610 self.ssatransformer
611 .ssa_locals_map
612 .entry(*old_local)
613 .or_insert_with(HashSet::new)
614 .insert(new_local.clone());
615
616 *place = Place::from(new_local);
617 self.ssatransformer
618 .local_defination_block
619 .insert(new_local.clone(), bb.clone());
620 let old_local_reaching = self
621 .ssatransformer
622 .reaching_def
623 .get(&_old_local.clone())
624 .unwrap();
625
626 self.ssatransformer
627 .reaching_def
628 .insert(new_local.clone(), *old_local_reaching);
629 self.ssatransformer
630 .reaching_def
631 .insert(_old_local.clone(), Some(new_local.clone()));
632
633 }
638 fn rename_local_def(&mut self, place: &mut Place<'tcx>, bb: &BasicBlock, not_phi: bool) {
639 self.update_reachinf_def(&place.local, &bb);
641 let Place {
642 local: old_local,
643 projection: _,
644 } = place;
645 if self.ssatransformer.skipped.contains(&old_local.as_u32()) && not_phi {
647 self.ssatransformer.skipped.remove(&old_local.as_u32());
648 self.ssatransformer
649 .reaching_def
650 .insert(*old_local, Some(*old_local));
651 self.ssatransformer
652 .locals_map
653 .entry(*old_local)
654 .or_insert_with(HashSet::new)
655 .insert(*old_local);
656 return;
657 }
658 let new_local = Local::from_u32(self.ssatransformer.local_index);
659 self.ssatransformer.local_index += 1;
660 self.ssatransformer
661 .locals_map
662 .entry(*old_local)
663 .or_insert_with(HashSet::new)
664 .insert(new_local);
665
666 let _old_local = old_local.clone();
667 *place = Place::from(new_local);
668 self.ssatransformer
669 .local_defination_block
670 .insert(new_local.clone(), bb.clone());
671 let old_local_reaching = self
672 .ssatransformer
673 .reaching_def
674 .get(&_old_local.clone())
675 .unwrap();
676
677 self.ssatransformer
678 .reaching_def
679 .insert(new_local.clone(), *old_local_reaching);
680 self.ssatransformer
681 .reaching_def
682 .insert(_old_local.clone(), Some(new_local.clone()));
683
684 }
689
690 pub fn dominates_(&self, def_bb: &BasicBlock, bb: &BasicBlock) -> bool {
691 let mut visited = HashSet::new();
692
693 let mut stack = self.ssatransformer.dom_tree.get(def_bb).unwrap().clone();
694 while let Some(block) = stack.pop() {
695 if !visited.insert(block) {
696 continue;
697 }
698
699 if block == *bb {
700 return true;
701 }
702
703 if let Some(children) = self.ssatransformer.dom_tree.get(&block) {
704 stack.extend(children);
705 }
706 }
707
708 false
709 }
710 fn update_reachinf_def(&mut self, local: &Local, bb: &BasicBlock) {
711 let mut r = self.ssatransformer.reaching_def[local];
715 let mut dominate_bool = true;
716 if r != None {
717 let def_bb = self.ssatransformer.local_defination_block[&r.unwrap()];
718 }
719
720 while !(r == None || dominate_bool) {
721 r = self.ssatransformer.reaching_def[&r.unwrap()];
722 if r != None {
723 let def_bb = self.ssatransformer.local_defination_block[&r.unwrap()];
724
725 dominate_bool = self.dominates_(&def_bb, bb);
726 }
727 }
728
729 if let Some(entry) = self.ssatransformer.reaching_def.get_mut(local) {
730 *entry = r.clone();
731 }
732 }
733}
734
735