New direction
This commit is contained in:
+71
-121
@@ -14,6 +14,17 @@ pub struct RegInstr {
|
||||
pub args: Vec<usize>,
|
||||
}
|
||||
|
||||
impl RegInstr {
|
||||
pub fn new(op: OpCode, imm: ImmOperand, dsts: Vec<usize>, args: Vec<usize>) -> Self {
|
||||
Self {
|
||||
dsts,
|
||||
op,
|
||||
imm,
|
||||
args,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Debug for RegInstr {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
write!(
|
||||
@@ -24,148 +35,87 @@ impl Debug for RegInstr {
|
||||
}
|
||||
}
|
||||
|
||||
/// A `FlatFn` with its stack bytecode lowered to register code.
|
||||
#[derive(Debug)]
|
||||
pub struct RegFn {
|
||||
pub name: String,
|
||||
pub arg_count: usize,
|
||||
pub var_count: usize,
|
||||
pub value_names: Vec<AtomRef>,
|
||||
pub captures: Vec<Capture>,
|
||||
pub cpool: Vec<JsValue>,
|
||||
pub code: Vec<RegInstr>,
|
||||
/// Set by `declass` when this function is a class constructor.
|
||||
pub is_ctor: bool,
|
||||
next_val: usize,
|
||||
}
|
||||
|
||||
fn regify_walk(code: &[Instr], var_count: usize) -> Vec<RegInstr> {
|
||||
let mut stack = vec![];
|
||||
let mut output = vec![];
|
||||
let mut next_val = var_count;
|
||||
impl RegFn {
|
||||
fn from_flat(flat_fn: FlatFn) -> Self {
|
||||
let mut stack = vec![];
|
||||
let mut output = Vec::with_capacity(flat_fn.code.len());
|
||||
let mut next_val = flat_fn.var_count;
|
||||
|
||||
let mut fresh_val = || {
|
||||
let v = next_val;
|
||||
next_val += 1;
|
||||
v
|
||||
};
|
||||
|
||||
for instr in code {
|
||||
let mut reg_instr = RegInstr {
|
||||
dsts: vec![],
|
||||
op: instr.op,
|
||||
imm: instr.imm_operands,
|
||||
args: vec![],
|
||||
let mut fresh_val = || {
|
||||
let v = next_val;
|
||||
next_val += 1;
|
||||
v
|
||||
};
|
||||
|
||||
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,
|
||||
},
|
||||
};
|
||||
for instr in flat_fn.code {
|
||||
let mut reg_instr = RegInstr {
|
||||
dsts: vec![],
|
||||
op: instr.op,
|
||||
imm: instr.imm_operands,
|
||||
args: vec![],
|
||||
};
|
||||
|
||||
let info = instr.op.info();
|
||||
let n_pop = info.n_pop as usize + extra_pop;
|
||||
let n_push = info.n_push as usize;
|
||||
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,
|
||||
},
|
||||
};
|
||||
|
||||
for _ in 0..n_pop {
|
||||
let v = stack.pop().unwrap();
|
||||
reg_instr.args.push(v);
|
||||
let info = instr.op.info();
|
||||
let n_pop = info.n_pop as usize + extra_pop;
|
||||
let n_push = info.n_push as usize;
|
||||
|
||||
for _ in 0..n_pop {
|
||||
let v = stack.pop().unwrap();
|
||||
reg_instr.args.push(v);
|
||||
}
|
||||
|
||||
for _ in 0..n_push {
|
||||
let v = fresh_val();
|
||||
stack.push(v);
|
||||
reg_instr.dsts.push(v);
|
||||
}
|
||||
|
||||
output.push(reg_instr);
|
||||
}
|
||||
|
||||
for _ in 0..n_push {
|
||||
let v = fresh_val();
|
||||
stack.push(v);
|
||||
reg_instr.dsts.push(v);
|
||||
Self {
|
||||
name: flat_fn.name,
|
||||
arg_count: flat_fn.arg_count,
|
||||
var_count: flat_fn.var_count,
|
||||
value_names: flat_fn.value_names,
|
||||
captures: flat_fn.captures,
|
||||
cpool: flat_fn.cpool,
|
||||
code: output,
|
||||
next_val,
|
||||
}
|
||||
|
||||
output.push(reg_instr);
|
||||
}
|
||||
|
||||
output
|
||||
pub fn fresh_val(&mut self) -> usize {
|
||||
let v = self.next_val;
|
||||
self.next_val += 1;
|
||||
v
|
||||
}
|
||||
}
|
||||
|
||||
/// Lower every function's stack code to register code, keeping the rest.
|
||||
pub fn regify(flat_fns: Vec<FlatFn>) -> Vec<RegFn> {
|
||||
flat_fns
|
||||
.into_iter()
|
||||
.map(|f| RegFn {
|
||||
code: regify_walk(&f.code, f.var_count),
|
||||
name: f.name,
|
||||
arg_count: f.arg_count,
|
||||
var_count: f.var_count,
|
||||
captures: f.captures,
|
||||
cpool: f.cpool,
|
||||
is_ctor: false,
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
|
||||
// ─── shared by the de* passes ──────────────────────────────────────────────
|
||||
|
||||
impl RegInstr {
|
||||
pub fn new(op: OpCode, imm: ImmOperand, dsts: Vec<usize>, args: Vec<usize>) -> Self {
|
||||
RegInstr {
|
||||
dsts,
|
||||
op,
|
||||
imm,
|
||||
args,
|
||||
}
|
||||
}
|
||||
|
||||
/// Whether this instruction reads or writes `value`.
|
||||
pub fn mentions(&self, value: usize) -> bool {
|
||||
self.args.contains(&value) || self.dsts.contains(&value)
|
||||
}
|
||||
}
|
||||
|
||||
/// Hands out value numbers that nothing in the function uses yet.
|
||||
pub struct Fresh(usize);
|
||||
|
||||
impl Fresh {
|
||||
/// Start just past the highest value the function already uses.
|
||||
pub fn for_fn(f: &RegFn) -> Fresh {
|
||||
let highest = f
|
||||
.code
|
||||
.iter()
|
||||
.flat_map(|i| i.dsts.iter().chain(i.args.iter()))
|
||||
.copied()
|
||||
.max()
|
||||
.unwrap_or(0);
|
||||
Fresh(highest + 1)
|
||||
}
|
||||
|
||||
pub fn new_value(&mut self) -> usize {
|
||||
let v = self.0;
|
||||
self.0 += 1;
|
||||
v
|
||||
}
|
||||
}
|
||||
|
||||
/// A call with no receiver. `call_method` and `call_constructor` carry one and
|
||||
/// are handled by the class passes instead.
|
||||
pub fn is_plain_call(op: OpCode) -> bool {
|
||||
use OpCode::*;
|
||||
matches!(op, Call | Call0 | Call1 | Call2 | Call3 | TailCall)
|
||||
}
|
||||
|
||||
/// The generic form of a call opcode: any tail variant becomes `tail_call`,
|
||||
/// everything else `call`.
|
||||
pub fn as_plain_call(op: OpCode) -> OpCode {
|
||||
use OpCode::*;
|
||||
if matches!(op, TailCall | TailCallMethod) {
|
||||
TailCall
|
||||
} else {
|
||||
Call
|
||||
}
|
||||
}
|
||||
|
||||
/// An integer-named field. The synthetic objects these passes build use
|
||||
/// integer names so no new atoms have to be minted.
|
||||
pub fn int_field(index: u32) -> ImmOperand {
|
||||
ImmOperand::Atom(AtomRef::TaggedInt(index))
|
||||
flat_fns.into_iter().map(RegFn::from_flat).collect()
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user