logicaffeine_compile/analysis/
liveness.rs1use std::collections::{HashMap, HashSet};
2
3use logicaffeine_base::Symbol;
4use logicaffeine_language::ast::{Expr, Stmt};
5use logicaffeine_language::ast::stmt::{ClosureBody, Pattern};
6
7pub struct LivenessResult {
17 functions: HashMap<Symbol, FunctionLiveness>,
18}
19
20pub struct FunctionLiveness {
22 pub live_after: Vec<HashSet<Symbol>>,
24}
25
26impl LivenessResult {
27 pub fn analyze(stmts: &[Stmt<'_>]) -> Self {
34 let mut functions = HashMap::new();
35 for stmt in stmts {
36 if let Stmt::FunctionDef { name, body, .. } = stmt {
37 functions.insert(*name, analyze_function(body));
38 }
39 }
40 Self { functions }
41 }
42
43 pub fn is_live_after(&self, fn_sym: Symbol, stmt_idx: usize, var: Symbol) -> bool {
49 self.functions
50 .get(&fn_sym)
51 .and_then(|fl| fl.live_after.get(stmt_idx))
52 .map(|s| s.contains(&var))
53 .unwrap_or(false)
54 }
55
56 pub fn live_after(&self, fn_sym: Symbol, stmt_idx: usize) -> &HashSet<Symbol> {
61 static EMPTY: std::sync::OnceLock<HashSet<Symbol>> = std::sync::OnceLock::new();
62 self.functions
63 .get(&fn_sym)
64 .and_then(|fl| fl.live_after.get(stmt_idx))
65 .unwrap_or_else(|| EMPTY.get_or_init(HashSet::new))
66 }
67}
68
69fn analyze_function(body: &[Stmt<'_>]) -> FunctionLiveness {
74 let n = body.len();
75 let mut live_after = vec![HashSet::<Symbol>::new(); n];
76 let mut current: HashSet<Symbol> = HashSet::new();
77
78 for i in (0..n).rev() {
79 if is_terminator(&body[i]) {
80 live_after[i] = HashSet::new();
83 current = gen_stmt(&body[i]);
84 } else {
85 live_after[i] = current.clone();
86 current = live_before_stmt(&body[i], ¤t);
87 }
88 }
89
90 FunctionLiveness { live_after }
91}
92
93fn is_terminator(stmt: &Stmt<'_>) -> bool {
94 matches!(stmt, Stmt::Return { .. })
95}
96
97fn gen_stmt(stmt: &Stmt<'_>) -> HashSet<Symbol> {
104 let mut out = HashSet::new();
105 match stmt {
106 Stmt::Return { value: Some(v) } => gen_expr(v, &mut out),
107 _ => {}
108 }
109 out
110}
111
112fn live_before_stmt(stmt: &Stmt<'_>, live_out: &HashSet<Symbol>) -> HashSet<Symbol> {
114 match stmt {
115 Stmt::Return { .. } => gen_stmt(stmt),
116
117 Stmt::Let { var, value, .. } => {
118 let mut result = live_out.clone();
119 result.remove(var);
120 gen_expr(value, &mut result);
121 result
122 }
123
124 Stmt::Set { target, value } => {
125 let mut result = live_out.clone();
126 result.remove(target);
127 gen_expr(value, &mut result);
128 result
129 }
130
131 Stmt::Call { args, .. } => {
132 let mut result = live_out.clone();
133 for a in args.iter() {
134 gen_expr(a, &mut result);
135 }
136 result
137 }
138
139 Stmt::Push { value, collection } => {
140 let mut result = live_out.clone();
141 gen_expr(value, &mut result);
142 gen_expr(collection, &mut result);
143 result
144 }
145
146 Stmt::Pop { collection, into } => {
147 let mut result = live_out.clone();
148 if let Some(v) = into {
149 result.remove(v);
150 }
151 gen_expr(collection, &mut result);
152 result
153 }
154
155 Stmt::Add { value, collection } | Stmt::Remove { value, collection } => {
156 let mut result = live_out.clone();
157 gen_expr(value, &mut result);
158 gen_expr(collection, &mut result);
159 result
160 }
161
162 Stmt::SetIndex { collection, index, value } => {
163 let mut result = live_out.clone();
164 gen_expr(collection, &mut result);
165 gen_expr(index, &mut result);
166 gen_expr(value, &mut result);
167 result
168 }
169
170 Stmt::SetField { object, value, .. } => {
171 let mut result = live_out.clone();
172 gen_expr(object, &mut result);
173 gen_expr(value, &mut result);
174 result
175 }
176
177 Stmt::If { cond, then_block, else_block } => {
178 let then_lb = live_before_block(then_block, live_out);
179 let else_lb = match else_block {
180 Some(b) => live_before_block(b, live_out),
181 None => live_out.clone(),
182 };
183 let mut result = HashSet::new();
184 gen_expr(cond, &mut result);
185 result.extend(then_lb);
186 result.extend(else_lb);
187 result
188 }
189
190 Stmt::While { cond, body, .. } => {
191 let mut loop_live: HashSet<Symbol> = live_out.clone();
193 gen_expr(cond, &mut loop_live);
194 loop {
195 let body_before = live_before_block(body, &loop_live);
196 let mut new_live = live_out.clone();
197 gen_expr(cond, &mut new_live);
198 new_live.extend(body_before);
199 if new_live == loop_live {
200 break;
201 }
202 loop_live = new_live;
203 }
204 loop_live
205 }
206
207 Stmt::Repeat { pattern, iterable, body } => {
208 let body_before = live_before_block(body, live_out);
209 let pattern_syms: HashSet<Symbol> = match pattern {
210 Pattern::Identifier(s) => [*s].into_iter().collect(),
211 Pattern::Tuple(syms) => syms.iter().copied().collect(),
212 };
213 let mut result = live_out.clone();
214 gen_expr(iterable, &mut result);
215 for sym in body_before {
216 if !pattern_syms.contains(&sym) {
217 result.insert(sym);
218 }
219 }
220 result
221 }
222
223 Stmt::Inspect { target, arms, .. } => {
224 let mut result = HashSet::new();
225 for arm in arms.iter() {
226 let arm_lb = live_before_block(arm.body, live_out);
227 result.extend(arm_lb);
228 }
229 gen_expr(target, &mut result);
230 result
231 }
232
233 Stmt::Concurrent { tasks } | Stmt::Parallel { tasks } => {
234 live_before_block(tasks, live_out)
235 }
236
237 Stmt::Zone { body, .. } => live_before_block(body, live_out),
238
239 _ => live_out.clone(),
240 }
241}
242
243fn live_before_block(stmts: &[Stmt<'_>], live_out: &HashSet<Symbol>) -> HashSet<Symbol> {
245 let mut current = live_out.clone();
246 for stmt in stmts.iter().rev() {
247 if is_terminator(stmt) {
248 current = gen_stmt(stmt);
249 } else {
250 current = live_before_stmt(stmt, ¤t);
251 }
252 }
253 current
254}
255
256fn gen_expr(expr: &Expr<'_>, out: &mut HashSet<Symbol>) {
265 match expr {
266 Expr::Identifier(sym) => {
267 out.insert(*sym);
268 }
269 Expr::BinaryOp { left, right, .. } => {
270 gen_expr(left, out);
271 gen_expr(right, out);
272 }
273 Expr::Call { args, .. } => {
274 for a in args.iter() {
275 gen_expr(a, out);
276 }
277 }
278 Expr::CallExpr { callee, args } => {
279 gen_expr(callee, out);
280 for a in args.iter() {
281 gen_expr(a, out);
282 }
283 }
284 Expr::Length { collection } => gen_expr(collection, out),
285 Expr::Index { collection, index } => {
286 gen_expr(collection, out);
287 gen_expr(index, out);
288 }
289 Expr::Slice { collection, start, end } => {
290 gen_expr(collection, out);
291 gen_expr(start, out);
292 gen_expr(end, out);
293 }
294 Expr::Contains { collection, value } => {
295 gen_expr(collection, out);
296 gen_expr(value, out);
297 }
298 Expr::Union { left, right } | Expr::Intersection { left, right } => {
299 gen_expr(left, out);
300 gen_expr(right, out);
301 }
302 Expr::ManifestOf { zone } => gen_expr(zone, out),
303 Expr::ChunkAt { index, zone } => {
304 gen_expr(index, out);
305 gen_expr(zone, out);
306 }
307 Expr::FieldAccess { object, .. } => gen_expr(object, out),
308 Expr::List(items) | Expr::Tuple(items) => {
309 for i in items.iter() {
310 gen_expr(i, out);
311 }
312 }
313 Expr::Range { start, end } => {
314 gen_expr(start, out);
315 gen_expr(end, out);
316 }
317 Expr::Copy { expr } | Expr::Give { value: expr } | Expr::Not { operand: expr } => gen_expr(expr, out),
318 Expr::OptionSome { value } => gen_expr(value, out),
319 Expr::WithCapacity { value, capacity } => {
320 gen_expr(value, out);
321 gen_expr(capacity, out);
322 }
323 Expr::New { init_fields, .. } => {
324 for (_, v) in init_fields.iter() {
325 gen_expr(v, out);
326 }
327 }
328 Expr::NewVariant { fields, .. } => {
329 for (_, v) in fields.iter() {
330 gen_expr(v, out);
331 }
332 }
333 Expr::Closure { body, .. } => match body {
334 ClosureBody::Expression(e) => gen_expr(e, out),
335 ClosureBody::Block(stmts) => {
336 for s in stmts.iter() {
337 gen_stmt_exprs(s, out);
338 }
339 }
340 },
341 Expr::InterpolatedString(parts) => {
342 for part in parts.iter() {
343 if let logicaffeine_language::ast::stmt::StringPart::Expr { value, .. } = part {
344 gen_expr(value, out);
345 }
346 }
347 }
348 Expr::Literal(_) | Expr::OptionNone | Expr::Escape { .. } => {}
349 }
350}
351
352fn gen_stmt_exprs(stmt: &Stmt<'_>, out: &mut HashSet<Symbol>) {
355 match stmt {
356 Stmt::Let { value, .. } => gen_expr(value, out),
357 Stmt::Set { value, .. } => gen_expr(value, out),
358 Stmt::Return { value: Some(v) } => gen_expr(v, out),
359 Stmt::Call { args, .. } => {
360 for a in args.iter() { gen_expr(a, out); }
361 }
362 Stmt::Push { value, collection } => {
363 gen_expr(value, out);
364 gen_expr(collection, out);
365 }
366 Stmt::If { cond, then_block, else_block } => {
367 gen_expr(cond, out);
368 for s in then_block.iter() { gen_stmt_exprs(s, out); }
369 if let Some(b) = else_block {
370 for s in b.iter() { gen_stmt_exprs(s, out); }
371 }
372 }
373 Stmt::While { cond, body, .. } => {
374 gen_expr(cond, out);
375 for s in body.iter() { gen_stmt_exprs(s, out); }
376 }
377 _ => {}
378 }
379}