Walk blocks in CFG order
This commit is contained in:
+21
-6
@@ -109,10 +109,18 @@ impl RegFn {
|
|||||||
let pcs = flat_fn.code.iter().map(|i| i.pc).collect::<Vec<usize>>();
|
let pcs = flat_fn.code.iter().map(|i| i.pc).collect::<Vec<usize>>();
|
||||||
let (starts, mut blocks) = find_basic_blocks(&flat_fn.code, &pcs);
|
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
|
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
|
// A block starts with the stack it is ENTERED with, not with
|
||||||
// whatever the block above it in the listing left behind. This one
|
// whatever the block above it in the listing left behind. This one
|
||||||
// line is what stops the walk running off a `return` into a
|
// 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);
|
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.
|
// Every edge out of here arrives at its target with this stack.
|
||||||
// One pass in listing order reaches every block, because a block is
|
// Walking a block only after something has arrived at it is what
|
||||||
// always entered from earlier in the listing before any back edge
|
// makes the entry stack right, and it is why the order is the CFG's
|
||||||
// returns to it.
|
// and not the listing's.
|
||||||
for i in 0..blocks[b].succ.len() {
|
for i in 0..blocks[b].succ.len() {
|
||||||
let to = blocks[b].succ[i];
|
let to = blocks[b].succ[i];
|
||||||
blocks[to].arrive(&stack);
|
blocks[to].arrive(&stack);
|
||||||
|
|
||||||
|
if !seen[to] {
|
||||||
|
seen[to] = true;
|
||||||
|
todo.push(to);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let output = emitted.into_iter().flatten().collect::<Vec<RegInstr>>();
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
name: flat_fn.name,
|
name: flat_fn.name,
|
||||||
arg_count: flat_fn.arg_count,
|
arg_count: flat_fn.arg_count,
|
||||||
|
|||||||
Reference in New Issue
Block a user