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