Improve regify/infer
This commit is contained in:
+117
-66
@@ -50,7 +50,7 @@ pub struct RegFn {
|
||||
|
||||
impl RegFn {
|
||||
fn from_flat(flat_fn: FlatFn) -> Self {
|
||||
let blocks = find_basic_blocks(&flat_fn.code);
|
||||
let mut blocks = find_basic_blocks(&flat_fn.code);
|
||||
let mut out = vec![RegInstr::nop(); flat_fn.code.len()];
|
||||
|
||||
let mut next_val = flat_fn.var_count; // Reserve values for locals
|
||||
@@ -62,20 +62,20 @@ impl RegFn {
|
||||
worklist.push(0);
|
||||
|
||||
while let Some(block_idx) = worklist.pop() {
|
||||
let block = &mut blocks[block_idx];
|
||||
let mut stack: Vec<usize> = entry_stacks[block_idx].clone().unwrap_or_default();
|
||||
|
||||
walk_block(
|
||||
&blocks[block_idx],
|
||||
&flat_fn.code,
|
||||
&mut stack,
|
||||
&mut next_val,
|
||||
&mut out,
|
||||
);
|
||||
walk_block(block, &flat_fn.code, &mut stack, &mut next_val, &mut out);
|
||||
|
||||
for &succ_idx in &blocks[block_idx].succ {
|
||||
if entry_stacks[succ_idx].is_none() {
|
||||
entry_stacks[succ_idx] = Some(stack.clone());
|
||||
worklist.push(succ_idx);
|
||||
for succ_idx in block.succ.clone() {
|
||||
let succ_stack = &mut entry_stacks[succ_idx];
|
||||
|
||||
match succ_stack {
|
||||
Some(succ_stack) => add_block_postfix(block, &stack, succ_stack),
|
||||
None => {
|
||||
*succ_stack = Some(stack.clone());
|
||||
worklist.push(succ_idx);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -115,21 +115,8 @@ fn walk_block(
|
||||
args: vec![],
|
||||
};
|
||||
|
||||
// Some instrs have extra pops not reflected in info.n_pop
|
||||
let extra_pop = match instr.op {
|
||||
OpCode::Call0 => 0,
|
||||
OpCode::Call1 => 1,
|
||||
OpCode::Call2 => 2,
|
||||
OpCode::Call3 => 3,
|
||||
_ => match instr.imm_operands {
|
||||
ImmOperand::Npop(npop) => npop as usize,
|
||||
ImmOperand::NpopU16 { npop, .. } => npop as usize,
|
||||
_ => 0,
|
||||
},
|
||||
};
|
||||
|
||||
let info = instr.op.info();
|
||||
let n_pop = info.n_pop as usize + extra_pop;
|
||||
let n_pop = info.n_pop as usize + extra_pops(instr);
|
||||
let n_push = info.n_push as usize;
|
||||
|
||||
// Handle this instr's pops
|
||||
@@ -138,61 +125,125 @@ fn walk_block(
|
||||
out_instr.args.push(v);
|
||||
}
|
||||
|
||||
// Locals are not renamed, needs special handling
|
||||
let local_access = match instr.op {
|
||||
OpCode::GetLoc0 | OpCode::PutLoc0 | OpCode::SetLoc0 => Some(0),
|
||||
OpCode::GetLoc1 | OpCode::PutLoc1 | OpCode::SetLoc1 => Some(1),
|
||||
OpCode::GetLoc2 | OpCode::PutLoc2 | OpCode::SetLoc2 => Some(2),
|
||||
OpCode::GetLoc3 | OpCode::PutLoc3 | OpCode::SetLoc3 => Some(3),
|
||||
|
||||
OpCode::GetLoc
|
||||
| OpCode::GetLoc8
|
||||
| OpCode::GetLocCheck
|
||||
| OpCode::PutLoc
|
||||
| OpCode::PutLoc8
|
||||
| OpCode::PutLocCheck
|
||||
| OpCode::PutLocCheckInit
|
||||
| OpCode::SetLoc
|
||||
| OpCode::SetLoc8
|
||||
| OpCode::SetLocUninitialized => match instr.imm_operands {
|
||||
ImmOperand::Loc(k) => Some(k as usize),
|
||||
_ => None,
|
||||
},
|
||||
|
||||
_ => None,
|
||||
};
|
||||
|
||||
// Handle this instr's pushes, handling local accesses separately
|
||||
match local_access {
|
||||
// Locals are not renamed, local read/writes need special handling
|
||||
// Handle read of a local value
|
||||
match is_local_read(instr) {
|
||||
Some(loc) => {
|
||||
stack.push(loc);
|
||||
out_instr.op = OpCode::Nop;
|
||||
out_instr.imm = ImmOperand::None;
|
||||
out[instr_idx] = out_instr;
|
||||
continue;
|
||||
}
|
||||
None if instr.op == OpCode::GetLoc0Loc1 => {
|
||||
stack.push(0);
|
||||
stack.push(1);
|
||||
out_instr.op = OpCode::Nop;
|
||||
out_instr.imm = ImmOperand::None;
|
||||
out[instr_idx] = out_instr;
|
||||
continue;
|
||||
}
|
||||
None => (),
|
||||
}
|
||||
|
||||
// Handle write of a local value
|
||||
match is_local_write(instr) {
|
||||
Some(loc) => {
|
||||
out_instr.op = OpCode::SetLoc;
|
||||
out_instr.imm = ImmOperand::None;
|
||||
out_instr.dsts.push(loc);
|
||||
out[instr_idx] = out_instr;
|
||||
|
||||
if n_push == 1 {
|
||||
stack.push(loc);
|
||||
}
|
||||
}
|
||||
|
||||
// The one op that reads two locals at once
|
||||
None if instr.op == OpCode::GetLoc0Loc1 => {
|
||||
for k in [0, 1] {
|
||||
stack.push(k);
|
||||
out_instr.dsts.push(k);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
None if instr.op == OpCode::SetLocUninitialized => {
|
||||
out_instr.op = OpCode::Nop;
|
||||
out_instr.imm = ImmOperand::None;
|
||||
out[instr_idx] = out_instr;
|
||||
continue;
|
||||
}
|
||||
None => (),
|
||||
}
|
||||
|
||||
None => {
|
||||
for _ in 0..n_push {
|
||||
let v = fresh_val();
|
||||
stack.push(v);
|
||||
out_instr.dsts.push(v);
|
||||
}
|
||||
}
|
||||
// Handle this instr's pushes
|
||||
for _ in 0..n_push {
|
||||
let v = fresh_val();
|
||||
stack.push(v);
|
||||
out_instr.dsts.push(v);
|
||||
}
|
||||
|
||||
out[instr_idx] = out_instr;
|
||||
}
|
||||
}
|
||||
|
||||
fn extra_pops(instr: &Instr) -> usize {
|
||||
match instr.op {
|
||||
OpCode::Call0 => 0,
|
||||
OpCode::Call1 => 1,
|
||||
OpCode::Call2 => 2,
|
||||
OpCode::Call3 => 3,
|
||||
_ => match instr.imm_operands {
|
||||
ImmOperand::Npop(npop) => npop as usize,
|
||||
ImmOperand::NpopU16 { npop, .. } => npop as usize,
|
||||
_ => 0,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
fn is_local_read(instr: &Instr) -> Option<usize> {
|
||||
match instr.op {
|
||||
OpCode::GetLoc0 => Some(0),
|
||||
OpCode::GetLoc1 => Some(1),
|
||||
OpCode::GetLoc2 => Some(2),
|
||||
OpCode::GetLoc3 => Some(3),
|
||||
|
||||
OpCode::GetLoc | OpCode::GetLoc8 | OpCode::GetLocCheck => match instr.imm_operands {
|
||||
ImmOperand::Loc(k) => Some(k as usize),
|
||||
_ => unreachable!(),
|
||||
},
|
||||
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
fn is_local_write(instr: &Instr) -> Option<usize> {
|
||||
match instr.op {
|
||||
OpCode::PutLoc0 | OpCode::SetLoc0 => Some(0),
|
||||
OpCode::PutLoc1 | OpCode::SetLoc1 => Some(1),
|
||||
OpCode::PutLoc2 | OpCode::SetLoc2 => Some(2),
|
||||
OpCode::PutLoc3 | OpCode::SetLoc3 => Some(3),
|
||||
|
||||
OpCode::PutLoc
|
||||
| OpCode::PutLoc8
|
||||
| OpCode::PutLocCheck
|
||||
| OpCode::PutLocCheckInit
|
||||
| OpCode::SetLoc
|
||||
| OpCode::SetLoc8 => match instr.imm_operands {
|
||||
ImmOperand::Loc(k) => Some(k as usize),
|
||||
_ => unreachable!(),
|
||||
},
|
||||
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
fn add_block_postfix(block: &mut BasicBlock, stack: &[usize], succ_stack: &[usize]) {
|
||||
let overlap = stack.iter().rev().zip(succ_stack.iter().rev());
|
||||
|
||||
for (val, succ_val) in overlap {
|
||||
block.postfix.push(RegInstr {
|
||||
dsts: vec![*succ_val],
|
||||
op: OpCode::SetLoc,
|
||||
imm: ImmOperand::None,
|
||||
args: vec![*val],
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
pub fn regify(flat_fns: Vec<FlatFn>) -> Vec<RegFn> {
|
||||
flat_fns.into_iter().map(RegFn::from_flat).collect()
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user