regalloc2/ion/
redundant_moves.rs1use crate::{Allocation, VReg};
4use fxhash::FxHashMap;
5use smallvec::{smallvec, SmallVec};
6
7#[derive(Copy, Clone, Debug, PartialEq, Eq)]
8pub enum RedundantMoveState {
9 Copy(Allocation, Option<VReg>),
10 Orig(VReg),
11 None,
12}
13#[derive(Clone, Debug, Default)]
14pub struct RedundantMoveEliminator {
15 allocs: FxHashMap<Allocation, RedundantMoveState>,
16 reverse_allocs: FxHashMap<Allocation, SmallVec<[Allocation; 4]>>,
17}
18#[derive(Copy, Clone, Debug)]
19pub struct RedundantMoveAction {
20 pub elide: bool,
21}
22
23impl RedundantMoveEliminator {
24 pub fn process_move(
25 &mut self,
26 from: Allocation,
27 to: Allocation,
28 to_vreg: Option<VReg>,
29 ) -> RedundantMoveAction {
30 let from_state = self
32 .allocs
33 .get(&from)
34 .map(|&p| p)
35 .unwrap_or(RedundantMoveState::None);
36 let to_state = self
37 .allocs
38 .get(&to)
39 .map(|&p| p)
40 .unwrap_or(RedundantMoveState::None);
41
42 trace!(
43 " -> redundant move tracker: from {} to {} to_vreg {:?}",
44 from,
45 to,
46 to_vreg
47 );
48 trace!(
49 " -> from_state {:?} to_state {:?}",
50 from_state,
51 to_state
52 );
53
54 if from == to && to_vreg.is_some() {
55 self.clear_alloc(to);
56 self.allocs
57 .insert(to, RedundantMoveState::Orig(to_vreg.unwrap()));
58 return RedundantMoveAction { elide: true };
59 }
60
61 let src_vreg = match from_state {
62 RedundantMoveState::Copy(_, opt_r) => opt_r,
63 RedundantMoveState::Orig(r) => Some(r),
64 _ => None,
65 };
66 trace!(" -> src_vreg {:?}", src_vreg);
67 let dst_vreg = to_vreg.or(src_vreg);
68 trace!(" -> dst_vreg {:?}", dst_vreg);
69 let existing_dst_vreg = match to_state {
70 RedundantMoveState::Copy(_, opt_r) => opt_r,
71 RedundantMoveState::Orig(r) => Some(r),
72 _ => None,
73 };
74 trace!(" -> existing_dst_vreg {:?}", existing_dst_vreg);
75
76 let elide = match (from_state, to_state) {
77 (_, RedundantMoveState::Copy(orig_alloc, _)) if orig_alloc == from => true,
78 (RedundantMoveState::Copy(new_alloc, _), _) if new_alloc == to => true,
79 _ => false,
80 };
81 trace!(" -> elide {}", elide);
82
83 if !elide {
85 self.clear_alloc(to);
86 }
87
88 if from.is_reg() || to.is_reg() {
90 self.allocs
91 .insert(to, RedundantMoveState::Copy(from, dst_vreg));
92 trace!(
93 " -> create mapping {} -> {:?}",
94 to,
95 RedundantMoveState::Copy(from, dst_vreg)
96 );
97 self.reverse_allocs
98 .entry(from)
99 .or_insert_with(|| smallvec![])
100 .push(to);
101 }
102
103 RedundantMoveAction { elide }
104 }
105
106 pub fn clear(&mut self) {
107 trace!(" redundant move eliminator cleared");
108 self.allocs.clear();
109 self.reverse_allocs.clear();
110 }
111
112 pub fn clear_alloc(&mut self, alloc: Allocation) {
113 trace!(" redundant move eliminator: clear {:?}", alloc);
114 if let Some(ref mut existing_copies) = self.reverse_allocs.get_mut(&alloc) {
115 for to_inval in existing_copies.iter() {
116 trace!(" -> clear existing copy: {:?}", to_inval);
117 if let Some(val) = self.allocs.get_mut(to_inval) {
118 match val {
119 RedundantMoveState::Copy(_, Some(vreg)) => {
120 *val = RedundantMoveState::Orig(*vreg);
121 }
122 _ => *val = RedundantMoveState::None,
123 }
124 }
125 self.allocs.remove(to_inval);
126 }
127 existing_copies.clear();
128 }
129 self.allocs.remove(&alloc);
130 }
131}