From 75bd52d8ec191249ae088a5ecb5214e4c3111385 Mon Sep 17 00:00:00 2001 From: uditdey Date: Wed, 9 Sep 2026 14:04:57 +0000 Subject: [PATCH] Walk blocks in CFG order --- compiler/src/regify.rs | 27 +++++++++++++++++++++------ 1 file changed, 21 insertions(+), 6 deletions(-) diff --git a/compiler/src/regify.rs b/compiler/src/regify.rs index 2dc76d2..c6b04b2 100644 --- a/compiler/src/regify.rs +++ b/compiler/src/regify.rs @@ -109,10 +109,18 @@ impl RegFn { let pcs = flat_fn.code.iter().map(|i| i.pc).collect::>(); let (starts, mut blocks) = find_basic_blocks(&flat_fn.code, &pcs); - let mut output = Vec::with_capacity(flat_fn.code.len()); let mut next_val = flat_fn.var_count; // Reserve values for locals - for b in 0..blocks.len() { + // Emit per block, so blocks can be WALKED in the order control reaches + // them and still be READ in listing order. Listing order alone is not + // enough: a for-of puts its body before the test, and the body is + // reached only by the back edge, so walking it first finds no stack. + let mut emitted = vec![Vec::new(); blocks.len()]; + let mut seen = vec![false; blocks.len()]; + let mut todo = vec![0]; + seen[0] = true; + + while let Some(b) = todo.pop() { // A block starts with the stack it is ENTERED with, not with // whatever the block above it in the listing left behind. This one // line is what stops the walk running off a `return` into a @@ -212,19 +220,26 @@ impl RegFn { } reg_instr.block_start = std::mem::take(&mut first); - output.push(reg_instr); + emitted[b].push(reg_instr); } // Every edge out of here arrives at its target with this stack. - // One pass in listing order reaches every block, because a block is - // always entered from earlier in the listing before any back edge - // returns to it. + // Walking a block only after something has arrived at it is what + // makes the entry stack right, and it is why the order is the CFG's + // and not the listing's. for i in 0..blocks[b].succ.len() { let to = blocks[b].succ[i]; blocks[to].arrive(&stack); + + if !seen[to] { + seen[to] = true; + todo.push(to); + } } } + let output = emitted.into_iter().flatten().collect::>(); + Self { name: flat_fn.name, arg_count: flat_fn.arg_count,