1use crate::ir::*;
8
9#[derive(Clone, Debug, PartialEq, Eq, Default)]
11pub struct SlotSet {
12 words: Vec<u64>,
13}
14
15impl SlotSet {
16 pub fn with_capacity(n: usize) -> SlotSet {
17 SlotSet {
18 words: vec![0; n.div_ceil(64)],
19 }
20 }
21
22 pub fn insert(&mut self, slot: SlotId) {
23 let (w, b) = (slot as usize / 64, slot as usize % 64);
24 if w >= self.words.len() {
25 self.words.resize(w + 1, 0);
26 }
27 self.words[w] |= 1 << b;
28 }
29
30 pub fn remove(&mut self, slot: SlotId) {
31 let (w, b) = (slot as usize / 64, slot as usize % 64);
32 if w < self.words.len() {
33 self.words[w] &= !(1 << b);
34 }
35 }
36
37 pub fn contains(&self, slot: SlotId) -> bool {
38 let (w, b) = (slot as usize / 64, slot as usize % 64);
39 w < self.words.len() && self.words[w] & (1 << b) != 0
40 }
41
42 pub fn union_with(&mut self, other: &SlotSet) {
43 if other.words.len() > self.words.len() {
44 self.words.resize(other.words.len(), 0);
45 }
46 for (a, b) in self.words.iter_mut().zip(&other.words) {
47 *a |= b;
48 }
49 }
50
51 pub fn iter(&self) -> impl Iterator<Item = SlotId> + '_ {
52 self.words
53 .iter()
54 .enumerate()
55 .flat_map(|(w, &bits)| Bits(bits).map(move |b| (w * 64) as SlotId + b))
56 }
57
58 pub fn iter_missing(&self, n: usize) -> impl Iterator<Item = SlotId> + '_ {
60 (0..n.div_ceil(64)).flat_map(move |w| {
61 let present = self.words.get(w).copied().unwrap_or(0);
62 let below = if n - w * 64 >= 64 {
63 u64::MAX
64 } else {
65 (1 << (n - w * 64)) - 1
66 };
67 Bits(!present & below).map(move |b| (w * 64) as SlotId + b)
68 })
69 }
70
71 fn same(&self, other: &SlotSet) -> bool {
72 let n = self.words.len().max(other.words.len());
73 (0..n).all(|i| self.words.get(i).copied().unwrap_or(0) == other.words.get(i).copied().unwrap_or(0))
74 }
75}
76
77struct Bits(u64);
79
80impl Iterator for Bits {
81 type Item = SlotId;
82
83 fn next(&mut self) -> Option<SlotId> {
84 if self.0 == 0 {
85 return None;
86 }
87 let b = self.0.trailing_zeros();
88 self.0 &= self.0 - 1;
89 Some(b)
90 }
91}
92
93#[derive(Debug)]
95pub struct Liveness {
96 pub after: Vec<SlotSet>,
98 pub loop_head: Vec<SlotSet>,
100 pub dies: Vec<Vec<SlotId>>,
105 pub narrows: Vec<bool>,
113}
114
115pub fn analyze(program: &Program) -> Liveness {
116 let n = program.stmt_count as usize;
117 let mut liveness = Liveness {
118 after: vec![SlotSet::default(); n],
119 loop_head: vec![SlotSet::default(); n],
120 dies: vec![Vec::new(); n],
121 narrows: vec![false; n],
122 };
123 for func in &program.functions {
124 let size = func.n_slots();
125 let exit = SlotSet::with_capacity(size);
126 let mut pass = Pass {
127 live: &mut liveness,
128 size,
129 caught: SlotSet::with_capacity(size),
130 };
131 let no_loop = LoopCtx {
132 after: exit.clone(),
133 head: exit.clone(),
134 };
135 pass.block(&func.body, exit, &no_loop);
136 }
137 liveness
138}
139
140struct LoopCtx {
141 after: SlotSet,
143 head: SlotSet,
145}
146
147struct Pass<'a> {
148 live: &'a mut Liveness,
149 size: usize,
150 caught: SlotSet,
153}
154
155impl Pass<'_> {
156 fn block(&mut self, block: &Block, mut live: SlotSet, lc: &LoopCtx) -> SlotSet {
157 live.union_with(&self.caught);
158 for (i, stmt) in block.stmts.iter().enumerate().rev() {
159 let mut before = self.stmt(stmt, live.clone(), lc);
160 before.union_with(&self.caught);
161 let mut touched = before.clone();
162 if let Some(slot) = written(stmt) {
163 touched.insert(slot);
164 }
165 let id = stmt.id as usize;
166 self.live.dies[id] = touched.iter().filter(|&s| !live.contains(s)).collect();
167 let last = i + 1 == block.stmts.len();
171 if let (StmtKind::Set { place, .. }, false) = (&stmt.kind, last) {
172 let overwritten = before.contains(place.slot) && live.contains(place.slot);
173 let lost = before.iter().filter(|&s| !live.contains(s)).count() + usize::from(overwritten);
174 self.live.narrows[id] = lost > usize::from(live.contains(place.slot));
175 }
176 self.live.after[id] = live;
177 live = before;
178 }
179 live
180 }
181
182 fn stmt(&mut self, stmt: &Stmt, out: SlotSet, lc: &LoopCtx) -> SlotSet {
183 match &stmt.kind {
184 StmtKind::Set { place, value } => {
185 let mut live = out;
186 define(place, &mut live);
187 uses(value, &mut live);
188 live
189 }
190 StmtKind::Draw { place, dist } => {
191 let mut live = out;
192 define(place, &mut live);
193 uses(dist, &mut live);
194 live
195 }
196 StmtKind::Take { place, bag } => {
197 let mut live = out;
198 define(place, &mut live);
199 live.insert(bag.slot);
200 place_uses(bag, &mut live);
201 live
202 }
203 StmtKind::Call { dest, callee, args } => {
204 let mut live = out;
205 define(dest, &mut live);
206 match callee {
207 Callee::Fn { capture_args, .. } => capture_args.iter().for_each(|&s| live.insert(s)),
208 Callee::Value(e, _) => uses(e, &mut live),
209 }
210 args.iter().for_each(|a| uses(a, &mut live));
211 live
212 }
213 StmtKind::If { cond, then, otherwise } => {
214 let mut live = self.block(then, out.clone(), lc);
215 live.union_with(&self.block(otherwise, out, lc));
216 uses(cond, &mut live);
217 live
218 }
219 StmtKind::Chance {
220 arms,
221 otherwise,
222 exhaustive,
223 } => {
224 let mut live = match otherwise {
225 Some(b) => self.block(b, out.clone(), lc),
226 None if !exhaustive => out.clone(),
227 None => SlotSet::with_capacity(self.size),
228 };
229 for (weight, body) in arms {
230 live.union_with(&self.block(body, out.clone(), lc));
231 uses(weight, &mut live);
232 }
233 live
234 }
235 StmtKind::Loop { body, .. } => {
236 let mut head = std::mem::take(&mut self.live.loop_head[stmt.id as usize]);
243 loop {
244 let inner = LoopCtx {
245 after: out.clone(),
246 head: head.clone(),
247 };
248 let mut entry = self.block(body, head.clone(), &inner);
249 entry.union_with(&head);
250 if entry.same(&head) {
251 break;
252 }
253 head = entry;
254 }
255 self.live.loop_head[stmt.id as usize] = head.clone();
256 head
257 }
258 StmtKind::Break => lc.after.clone(),
259 StmtKind::Continue => lc.head.clone(),
260 StmtKind::Return(value) => {
261 let mut live = SlotSet::with_capacity(self.size);
262 uses(value, &mut live);
263 live
264 }
265 StmtKind::Observe { value, from } => {
266 let mut live = out;
267 uses(value, &mut live);
268 if let Some(d) = from {
269 uses(d, &mut live);
270 }
271 live
272 }
273 StmtKind::Report { value, key, .. } => {
274 let mut live = out;
275 uses(value, &mut live);
276 if let Some(k) = key {
277 uses(k, &mut live);
278 }
279 live
280 }
281 StmtKind::Fail { .. } => SlotSet::with_capacity(self.size),
282 StmtKind::Check { slot, .. } => {
283 let mut live = out;
284 live.insert(*slot);
285 live
286 }
287 StmtKind::Try { body, catches } => {
288 let mut caught = SlotSet::with_capacity(self.size);
289 for c in catches {
290 caught.union_with(&self.block(&c.body, out.clone(), lc));
291 }
292 let outer = std::mem::replace(&mut self.caught, caught.clone());
293 self.caught.union_with(&outer);
294 let mut live = self.block(body, out, lc);
295 self.caught = outer;
296 live.union_with(&caught);
297 live
298 }
299 }
300 }
301}
302
303fn written(stmt: &Stmt) -> Option<SlotId> {
305 match &stmt.kind {
306 StmtKind::Set { place, .. } | StmtKind::Draw { place, .. } | StmtKind::Take { place, .. } => Some(place.slot),
307 StmtKind::Call { dest, .. } => Some(dest.slot),
308 _ => None,
309 }
310}
311
312fn define(place: &Place, live: &mut SlotSet) {
314 if place.path.is_empty() {
315 live.remove(place.slot);
316 } else {
317 live.insert(place.slot);
318 place_uses(place, live);
319 }
320}
321
322fn place_uses(place: &Place, live: &mut SlotSet) {
323 for elem in &place.path {
324 if let PathElem::Index(e) = elem {
325 uses(e, live);
326 }
327 }
328}
329
330fn uses(expr: &Expr, live: &mut SlotSet) {
331 match &expr.kind {
332 ExprKind::Lit(_) | ExprKind::Input(_) => {}
333 ExprKind::Slot(s) => live.insert(*s),
334 ExprKind::Unary(_, e) | ExprKind::Field(e, _) => uses(e, live),
335 ExprKind::Binary(_, a, b) | ExprKind::Index(a, b) => {
336 uses(a, live);
337 uses(b, live);
338 }
339 ExprKind::List(items) => items.iter().for_each(|e| uses(e, live)),
340 ExprKind::Map(entries) => entries.iter().for_each(|(k, v)| {
341 uses(k, live);
342 uses(v, live);
343 }),
344 ExprKind::Record { fields, .. } => fields.iter().for_each(|(_, e)| uses(e, live)),
345 ExprKind::With(base, fields) => {
346 uses(base, live);
347 fields.iter().for_each(|(_, e)| uses(e, live));
348 }
349 ExprKind::Builtin { args, named, .. } => {
350 args.iter().for_each(|e| uses(e, live));
351 named.iter().for_each(|(_, e)| uses(e, live));
352 }
353 ExprKind::Closure { capture_args, .. } | ExprKind::Simulate { capture_args, .. } => {
354 capture_args.iter().for_each(|&s| live.insert(s))
355 }
356 ExprKind::Interp(parts) => parts.iter().for_each(|p| {
357 if let InterpPart::Expr(e) = p {
358 uses(e, live)
359 }
360 }),
361 }
362}
363
364#[cfg(test)]
365mod tests {
366 use super::*;
367
368 #[test]
369 fn sets_list_their_members_and_the_rest() {
370 let mut set = SlotSet::with_capacity(130);
371 for s in [0, 3, 63, 64, 129] {
372 set.insert(s);
373 }
374 assert_eq!(set.iter().collect::<Vec<_>>(), [0, 3, 63, 64, 129]);
375 let missing: Vec<SlotId> = set.iter_missing(131).collect();
376 assert_eq!(missing.len(), 131 - 5);
377 assert!(missing.iter().all(|&s| !set.contains(s)));
378 assert_eq!(missing.last(), Some(&130));
379 assert_eq!(set.iter_missing(3).collect::<Vec<_>>(), [1, 2]);
380 assert_eq!(SlotSet::default().iter_missing(2).collect::<Vec<_>>(), [0, 1]);
381 assert_eq!(set.iter_missing(0).count(), 0);
382 }
383}