yz_basic_block/arena/
optimize.rs1use super::Arena;
2use crate::bb::BasicBlockInner;
3use crate::jump::{self, ForeachTarget};
4use crate::BbId;
5use alloc::collections::{BTreeMap as Map, BTreeSet};
6use alloc::vec::Vec;
7use core::mem::{drop, take};
8
9#[derive(Clone)]
21struct TransInfo {
22 target: usize,
24
25 refs: BTreeSet<usize>,
30}
31
32impl TransInfo {
33 #[inline]
34 fn new(id: usize) -> Self {
35 Self {
36 target: id,
37 refs: BTreeSet::new(),
38 }
39 }
40}
41
42fn fetchk<C>(is_mergable: &mut bool, container: &C, exclude: <C as ForeachTarget>::JumpTarget)
45where
46 C: ForeachTarget,
47 C::JumpTarget: Copy + PartialEq,
48{
49 container.foreach_target(move |&t| {
50 if exclude == t {
51 *is_mergable = false;
52 }
53 });
54}
55
56impl<S, C> Arena<S, C>
57where
58 S: ForeachTarget<JumpTarget = BbId>,
59 C: ForeachTarget<JumpTarget = BbId>,
60{
61 pub fn optimize(&mut self) -> bool {
62 let mut new_in_use = Vec::with_capacity(self.bbs.len());
63 let mut trm: Map<BbId, Option<TransInfo>> = Map::new();
64
65 for (&from, i) in self.bbs.iter() {
66 if i.is_public {
67 new_in_use.push(from);
68 } else if let BasicBlockInner::Concrete {
69 statements,
70 condjmp,
71 next,
72 } = &i.inner
73 {
74 if statements.is_empty() && condjmp.is_none() {
75 if let jump::Unconditional::Jump(trg) = *next {
76 if from != trg {
77 trm.entry(from)
78 .or_insert_with(|| Some(TransInfo::new(from)))
79 .as_mut()
80 .unwrap()
81 .target = trg;
82 }
83 }
84 }
85 }
86 }
87
88 let mut in_use = BTreeSet::new();
90 while !new_in_use.is_empty() {
91 for i in take(&mut new_in_use) {
92 if let Some(ent) = self.bbs.get(&i) {
93 if in_use.insert(i) {
94 ent.foreach_target(|&trg| {
96 trm.entry(trg)
97 .or_insert_with(|| Some(TransInfo::new(trg)))
98 .as_mut()
99 .unwrap()
100 .refs
101 .insert(i);
102 new_in_use.push(trg);
103 });
104 }
105 }
106 }
107 }
108 drop(new_in_use);
109
110 for (n, ti) in trm
112 .iter()
113 .filter_map(|(&n, ti)| ti.as_ref().map(|ti2| (n, ti2)))
114 {
115 if ti.refs.len() != 1 {
116 continue;
117 }
118 let bbheadref = *ti.refs.iter().next().unwrap();
119 if bbheadref == n {
120 continue;
121 }
122 if trm
123 .get(&bbheadref)
124 .and_then(Option::as_ref)
125 .map(|hti| hti.target != bbheadref)
126 == Some(true)
127 {
128 continue;
130 }
131 let mut is_mergable = false;
132 if let Some(bbhead) = self.bbs.get_mut(&bbheadref) {
133 if let BasicBlockInner::Concrete {
134 statements,
135 condjmp,
136 next,
137 } = &mut bbhead.inner
138 {
139 is_mergable = condjmp.is_none() && *next == jump::Unconditional::Jump(n);
140
141 fetchk(&mut is_mergable, statements, n);
143 }
144 }
145 if !is_mergable {
146 continue;
147 }
148 let bbtail = if let Some(bbtail) = self.bbs.get_mut(&n) {
149 if bbtail.is_public || !bbtail.inner.is_concrete() {
150 continue;
151 }
152 fetchk(&mut is_mergable, bbtail, n);
153 if !is_mergable {
154 continue;
155 }
156 take(&mut bbtail.inner)
157 } else {
158 continue;
159 };
160
161 if let BasicBlockInner::Concrete {
163 mut statements,
164 condjmp,
165 next,
166 } = bbtail
167 {
168 if let BasicBlockInner::Concrete {
169 statements: ref mut h_statements,
170 condjmp: ref mut h_condjmp,
171 next: ref mut h_next,
172 } = &mut self.bbs.get_mut(&bbheadref).unwrap().inner
173 {
174 in_use.remove(&n);
175 if h_statements.is_empty() {
176 for ltrg in self.labels.values_mut() {
179 if *ltrg == n {
180 *ltrg = bbheadref;
181 }
182 }
183 }
184 h_statements.append(&mut statements);
185 *h_condjmp = condjmp;
186 *h_next = next;
187 } else {
188 unreachable!();
189 }
190 } else {
191 unreachable!();
192 }
193 }
194
195 let mut modified = false;
197 for i in self.bbs.keys() {
198 let e = trm.entry(*i);
199 if in_use.contains(i) {
200 if let alloc::collections::btree_map::Entry::Occupied(mut e) = e {
201 if let Some(ti) = e.get_mut() {
202 if *i != ti.target {
203 modified = true;
204 } else {
205 e.remove_entry();
206 }
207 }
208 }
209 } else {
210 *e.or_default() = None;
211 modified = true;
212 }
213 }
214 if !modified {
215 return false;
217 }
218
219 {
221 let mut it = trm.iter().filter(|x| x.1.is_none()).map(|x| x.0);
222 if let Some(&nfi) = it.next() {
223 if nfi < self.cache_ins_start {
224 self.cache_ins_start = nfi;
225 }
226 self.bbs.remove(&nfi);
227 for n in it {
228 self.bbs.remove(&n);
229 }
230 }
231 }
232
233 for i in self.bbs.values_mut() {
235 i.foreach_target_mut(|target| {
236 if let Some(Some(ti)) = trm.get(target) {
237 *target = ti.target;
238 }
239 });
240 }
241
242 self.labels = take(&mut self.labels)
243 .into_iter()
244 .filter_map(|(label, bbid)| {
245 match trm.get(&bbid) {
249 Some(None) => None,
250 Some(Some(ti)) => Some(ti.target),
251 None => Some(bbid),
252 }
253 .map(|nn| (label, nn))
254 })
255 .collect();
256
257 true
258 }
259}