WIP.
This commit is contained in:
parent
d0ecd1238a
commit
8744965705
|
@ -1,8 +1,10 @@
|
||||||
//! Backend: IR to Wasm.
|
//! Backend: IR to Wasm.
|
||||||
|
|
||||||
use crate::cfg::CFGInfo;
|
use crate::cfg::CFGInfo;
|
||||||
use crate::ir::{FunctionBody, Value};
|
use crate::entity::EntityRef;
|
||||||
|
use crate::ir::{FunctionBody, Value, ValueDef};
|
||||||
use crate::passes::rpo::RPO;
|
use crate::passes::rpo::RPO;
|
||||||
|
use crate::Operator;
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
use std::borrow::Cow;
|
use std::borrow::Cow;
|
||||||
|
|
||||||
|
@ -21,6 +23,12 @@ pub struct WasmBackend<'a> {
|
||||||
locals: Localifier,
|
locals: Localifier,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
macro_rules! op {
|
||||||
|
($name:tt) => {
|
||||||
|
Some(wasm_encoder::Instruction::$name)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
impl<'a> WasmBackend<'a> {
|
impl<'a> WasmBackend<'a> {
|
||||||
pub fn new(body: &'a FunctionBody) -> Result<WasmBackend<'a>> {
|
pub fn new(body: &'a FunctionBody) -> Result<WasmBackend<'a>> {
|
||||||
log::debug!("Backend compiling:\n{}\n", body.display_verbose("| "));
|
log::debug!("Backend compiling:\n{}\n", body.display_verbose("| "));
|
||||||
|
@ -66,6 +74,8 @@ impl<'a> WasmBackend<'a> {
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
log::debug!("Compiled to:\n{:?}\n", func);
|
||||||
|
|
||||||
Ok(func)
|
Ok(func)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -130,15 +140,26 @@ impl<'a> WasmBackend<'a> {
|
||||||
}
|
}
|
||||||
WasmBlock::Leaf { block } => {
|
WasmBlock::Leaf { block } => {
|
||||||
for &inst in &self.body.blocks[*block].insts {
|
for &inst in &self.body.blocks[*block].insts {
|
||||||
self.lower_inst(inst, func);
|
// If this value is "owned", do nothing: it will be lowered in
|
||||||
|
// the one place it's used.
|
||||||
|
if self.trees.owner.contains_key(&inst) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
self.lower_inst(inst, /* root = */ true, func);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
WasmBlock::BlockParams { from, to } => {
|
WasmBlock::BlockParams { from, to } => {
|
||||||
debug_assert_eq!(from.len(), to.len());
|
debug_assert_eq!(from.len(), to.len());
|
||||||
for &from in from.iter() {
|
for (&from, &(_, to)) in from.iter().zip(to.iter()) {
|
||||||
|
if self.locals.values[to].is_empty() {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
self.lower_value(from, func);
|
self.lower_value(from, func);
|
||||||
}
|
}
|
||||||
for &(_, to) in to.iter().rev() {
|
for &(_, to) in to.iter().rev() {
|
||||||
|
if self.locals.values[to].is_empty() {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
self.lower_set_value(to, func);
|
self.lower_set_value(to, func);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -155,14 +176,330 @@ impl<'a> WasmBackend<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn lower_value(&self, value: Value, func: &mut wasm_encoder::Function) {
|
fn lower_value(&self, value: Value, func: &mut wasm_encoder::Function) {
|
||||||
todo!()
|
let value = self.body.resolve_alias(value);
|
||||||
|
let local = match &self.body.values[value] {
|
||||||
|
&ValueDef::BlockParam(..) | &ValueDef::Operator(..) => self.locals.values[value][0],
|
||||||
|
&ValueDef::PickOutput(orig_value, idx, _) => self.locals.values[orig_value][idx],
|
||||||
|
_ => unreachable!(),
|
||||||
|
};
|
||||||
|
func.instruction(&wasm_encoder::Instruction::LocalGet(local.index() as u32));
|
||||||
}
|
}
|
||||||
|
|
||||||
fn lower_set_value(&self, value: Value, func: &mut wasm_encoder::Function) {
|
fn lower_set_value(&self, value: Value, func: &mut wasm_encoder::Function) {
|
||||||
todo!()
|
debug_assert_eq!(
|
||||||
|
self.locals.values[value].len(),
|
||||||
|
1,
|
||||||
|
"Value {} has no local",
|
||||||
|
value
|
||||||
|
);
|
||||||
|
let local = self.locals.values[value][0];
|
||||||
|
func.instruction(&wasm_encoder::Instruction::LocalSet(local.index() as u32));
|
||||||
}
|
}
|
||||||
|
|
||||||
fn lower_inst(&self, value: Value, func: &mut wasm_encoder::Function) {
|
fn lower_inst(&self, value: Value, root: bool, func: &mut wasm_encoder::Function) {
|
||||||
todo!()
|
match &self.body.values[value] {
|
||||||
|
&ValueDef::Operator(ref op, ref args, _) => {
|
||||||
|
for &arg in &args[..] {
|
||||||
|
if self.trees.owner.contains_key(&arg) {
|
||||||
|
self.lower_inst(arg, /* root = */ false, func);
|
||||||
|
} else {
|
||||||
|
self.lower_value(arg, func);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
self.lower_op(op, func);
|
||||||
|
if root {
|
||||||
|
for &local in &self.locals.values[value] {
|
||||||
|
func.instruction(
|
||||||
|
&wasm_encoder::Instruction::LocalSet(local.index() as u32),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => unreachable!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn lower_op(&self, op: &Operator, func: &mut wasm_encoder::Function) {
|
||||||
|
let inst = match op {
|
||||||
|
Operator::Unreachable => Some(wasm_encoder::Instruction::Unreachable),
|
||||||
|
Operator::Nop => None,
|
||||||
|
Operator::Call { function_index } => Some(wasm_encoder::Instruction::Call(
|
||||||
|
function_index.index() as u32,
|
||||||
|
)),
|
||||||
|
Operator::CallIndirect {
|
||||||
|
sig_index,
|
||||||
|
table_index,
|
||||||
|
} => Some(wasm_encoder::Instruction::CallIndirect {
|
||||||
|
ty: sig_index.index() as u32,
|
||||||
|
table: table_index.index() as u32,
|
||||||
|
}),
|
||||||
|
Operator::Return => Some(wasm_encoder::Instruction::Return),
|
||||||
|
Operator::Select => Some(wasm_encoder::Instruction::Select),
|
||||||
|
Operator::TypedSelect { ty } => Some(wasm_encoder::Instruction::TypedSelect(
|
||||||
|
wasm_encoder::ValType::from(*ty),
|
||||||
|
)),
|
||||||
|
Operator::GlobalGet { global_index } => Some(wasm_encoder::Instruction::GlobalGet(
|
||||||
|
global_index.index() as u32,
|
||||||
|
)),
|
||||||
|
Operator::GlobalSet { global_index } => Some(wasm_encoder::Instruction::GlobalSet(
|
||||||
|
global_index.index() as u32,
|
||||||
|
)),
|
||||||
|
Operator::I32Load { memory } => Some(wasm_encoder::Instruction::I32Load(
|
||||||
|
wasm_encoder::MemArg::from(*memory),
|
||||||
|
)),
|
||||||
|
Operator::I64Load { memory } => Some(wasm_encoder::Instruction::I64Load(
|
||||||
|
wasm_encoder::MemArg::from(*memory),
|
||||||
|
)),
|
||||||
|
Operator::F32Load { memory } => Some(wasm_encoder::Instruction::F32Load(
|
||||||
|
wasm_encoder::MemArg::from(*memory),
|
||||||
|
)),
|
||||||
|
Operator::F64Load { memory } => Some(wasm_encoder::Instruction::F64Load(
|
||||||
|
wasm_encoder::MemArg::from(*memory),
|
||||||
|
)),
|
||||||
|
Operator::I32Load8S { memory } => Some(wasm_encoder::Instruction::I32Load8S(
|
||||||
|
wasm_encoder::MemArg::from(*memory),
|
||||||
|
)),
|
||||||
|
Operator::I32Load8U { memory } => Some(wasm_encoder::Instruction::I32Load8U(
|
||||||
|
wasm_encoder::MemArg::from(*memory),
|
||||||
|
)),
|
||||||
|
Operator::I32Load16S { memory } => Some(wasm_encoder::Instruction::I32Load16S(
|
||||||
|
wasm_encoder::MemArg::from(*memory),
|
||||||
|
)),
|
||||||
|
Operator::I32Load16U { memory } => Some(wasm_encoder::Instruction::I32Load16U(
|
||||||
|
wasm_encoder::MemArg::from(*memory),
|
||||||
|
)),
|
||||||
|
Operator::I64Load8S { memory } => Some(wasm_encoder::Instruction::I64Load8S(
|
||||||
|
wasm_encoder::MemArg::from(*memory),
|
||||||
|
)),
|
||||||
|
Operator::I64Load8U { memory } => Some(wasm_encoder::Instruction::I64Load8U(
|
||||||
|
wasm_encoder::MemArg::from(*memory),
|
||||||
|
)),
|
||||||
|
Operator::I64Load16S { memory } => Some(wasm_encoder::Instruction::I64Load16S(
|
||||||
|
wasm_encoder::MemArg::from(*memory),
|
||||||
|
)),
|
||||||
|
Operator::I64Load16U { memory } => Some(wasm_encoder::Instruction::I64Load16U(
|
||||||
|
wasm_encoder::MemArg::from(*memory),
|
||||||
|
)),
|
||||||
|
Operator::I64Load32S { memory } => Some(wasm_encoder::Instruction::I64Load32S(
|
||||||
|
wasm_encoder::MemArg::from(*memory),
|
||||||
|
)),
|
||||||
|
Operator::I64Load32U { memory } => Some(wasm_encoder::Instruction::I64Load32U(
|
||||||
|
wasm_encoder::MemArg::from(*memory),
|
||||||
|
)),
|
||||||
|
|
||||||
|
Operator::I32Store { memory } => Some(wasm_encoder::Instruction::I32Store(
|
||||||
|
wasm_encoder::MemArg::from(*memory),
|
||||||
|
)),
|
||||||
|
Operator::I64Store { memory } => Some(wasm_encoder::Instruction::I64Store(
|
||||||
|
wasm_encoder::MemArg::from(*memory),
|
||||||
|
)),
|
||||||
|
Operator::F32Store { memory } => Some(wasm_encoder::Instruction::F32Store(
|
||||||
|
wasm_encoder::MemArg::from(*memory),
|
||||||
|
)),
|
||||||
|
Operator::F64Store { memory } => Some(wasm_encoder::Instruction::F64Store(
|
||||||
|
wasm_encoder::MemArg::from(*memory),
|
||||||
|
)),
|
||||||
|
Operator::I32Store8 { memory } => Some(wasm_encoder::Instruction::I32Store8(
|
||||||
|
wasm_encoder::MemArg::from(*memory),
|
||||||
|
)),
|
||||||
|
Operator::I32Store16 { memory } => Some(wasm_encoder::Instruction::I32Store16(
|
||||||
|
wasm_encoder::MemArg::from(*memory),
|
||||||
|
)),
|
||||||
|
Operator::I64Store8 { memory } => Some(wasm_encoder::Instruction::I64Store8(
|
||||||
|
wasm_encoder::MemArg::from(*memory),
|
||||||
|
)),
|
||||||
|
Operator::I64Store16 { memory } => Some(wasm_encoder::Instruction::I64Store16(
|
||||||
|
wasm_encoder::MemArg::from(*memory),
|
||||||
|
)),
|
||||||
|
Operator::I64Store32 { memory } => Some(wasm_encoder::Instruction::I64Store32(
|
||||||
|
wasm_encoder::MemArg::from(*memory),
|
||||||
|
)),
|
||||||
|
|
||||||
|
Operator::I32Const { value } => {
|
||||||
|
Some(wasm_encoder::Instruction::I32Const(*value as i32))
|
||||||
|
}
|
||||||
|
Operator::I64Const { value } => {
|
||||||
|
Some(wasm_encoder::Instruction::I64Const(*value as i64))
|
||||||
|
}
|
||||||
|
Operator::F32Const { value } => {
|
||||||
|
Some(wasm_encoder::Instruction::F32Const(f32::from_bits(*value)))
|
||||||
|
}
|
||||||
|
Operator::F64Const { value } => {
|
||||||
|
Some(wasm_encoder::Instruction::F64Const(f64::from_bits(*value)))
|
||||||
|
}
|
||||||
|
|
||||||
|
Operator::I32Eqz => op!(I32Eqz),
|
||||||
|
Operator::I32Eq => op!(I32Eq),
|
||||||
|
Operator::I32Ne => op!(I32Ne),
|
||||||
|
Operator::I32LtS => op!(I32LtS),
|
||||||
|
Operator::I32LtU => op!(I32LtU),
|
||||||
|
Operator::I32GtS => op!(I32GtS),
|
||||||
|
Operator::I32GtU => op!(I32GtU),
|
||||||
|
Operator::I32LeS => op!(I32LeS),
|
||||||
|
Operator::I32LeU => op!(I32LeU),
|
||||||
|
Operator::I32GeS => op!(I32GeS),
|
||||||
|
Operator::I32GeU => op!(I32GeU),
|
||||||
|
|
||||||
|
Operator::I64Eqz => op!(I64Eqz),
|
||||||
|
|
||||||
|
Operator::I64Eq => op!(I64Eq),
|
||||||
|
Operator::I64Ne => op!(I64Ne),
|
||||||
|
Operator::I64LtS => op!(I64LtS),
|
||||||
|
Operator::I64LtU => op!(I64LtU),
|
||||||
|
Operator::I64GtU => op!(I64GtU),
|
||||||
|
Operator::I64GtS => op!(I64GtS),
|
||||||
|
Operator::I64LeS => op!(I64LeS),
|
||||||
|
Operator::I64LeU => op!(I64LeU),
|
||||||
|
Operator::I64GeS => op!(I64GeS),
|
||||||
|
Operator::I64GeU => op!(I64GeU),
|
||||||
|
|
||||||
|
Operator::F32Eq => op!(F32Eq),
|
||||||
|
Operator::F32Ne => op!(F32Ne),
|
||||||
|
Operator::F32Lt => op!(F32Lt),
|
||||||
|
Operator::F32Gt => op!(F32Gt),
|
||||||
|
Operator::F32Le => op!(F32Le),
|
||||||
|
Operator::F32Ge => op!(F32Ge),
|
||||||
|
|
||||||
|
Operator::F64Eq => op!(F64Eq),
|
||||||
|
Operator::F64Ne => op!(F64Ne),
|
||||||
|
Operator::F64Lt => op!(F64Lt),
|
||||||
|
Operator::F64Gt => op!(F64Gt),
|
||||||
|
Operator::F64Le => op!(F64Le),
|
||||||
|
Operator::F64Ge => op!(F64Ge),
|
||||||
|
|
||||||
|
Operator::I32Clz => op!(I32Clz),
|
||||||
|
Operator::I32Ctz => op!(I32Ctz),
|
||||||
|
Operator::I32Popcnt => op!(I32Popcnt),
|
||||||
|
|
||||||
|
Operator::I32Add => op!(I32Add),
|
||||||
|
Operator::I32Sub => op!(I32Sub),
|
||||||
|
Operator::I32Mul => op!(I32Mul),
|
||||||
|
Operator::I32DivS => op!(I32DivS),
|
||||||
|
Operator::I32DivU => op!(I32DivU),
|
||||||
|
Operator::I32RemS => op!(I32RemS),
|
||||||
|
Operator::I32RemU => op!(I32RemU),
|
||||||
|
Operator::I32And => op!(I32And),
|
||||||
|
Operator::I32Or => op!(I32Or),
|
||||||
|
Operator::I32Xor => op!(I32Xor),
|
||||||
|
Operator::I32Shl => op!(I32Shl),
|
||||||
|
Operator::I32ShrS => op!(I32ShrS),
|
||||||
|
Operator::I32ShrU => op!(I32ShrU),
|
||||||
|
Operator::I32Rotl => op!(I32Rotl),
|
||||||
|
Operator::I32Rotr => op!(I32Rotr),
|
||||||
|
|
||||||
|
Operator::I64Clz => op!(I64Clz),
|
||||||
|
Operator::I64Ctz => op!(I64Ctz),
|
||||||
|
Operator::I64Popcnt => op!(I64Popcnt),
|
||||||
|
|
||||||
|
Operator::I64Add => op!(I64Add),
|
||||||
|
Operator::I64Sub => op!(I64Sub),
|
||||||
|
Operator::I64Mul => op!(I64Mul),
|
||||||
|
Operator::I64DivS => op!(I64DivS),
|
||||||
|
Operator::I64DivU => op!(I64DivU),
|
||||||
|
Operator::I64RemS => op!(I64RemS),
|
||||||
|
Operator::I64RemU => op!(I64RemU),
|
||||||
|
Operator::I64And => op!(I64And),
|
||||||
|
Operator::I64Or => op!(I64Or),
|
||||||
|
Operator::I64Xor => op!(I64Xor),
|
||||||
|
Operator::I64Shl => op!(I64Shl),
|
||||||
|
Operator::I64ShrS => op!(I64ShrS),
|
||||||
|
Operator::I64ShrU => op!(I64ShrU),
|
||||||
|
Operator::I64Rotl => op!(I64Rotl),
|
||||||
|
Operator::I64Rotr => op!(I64Rotr),
|
||||||
|
|
||||||
|
Operator::F32Abs => op!(F32Abs),
|
||||||
|
Operator::F32Neg => op!(F32Neg),
|
||||||
|
Operator::F32Ceil => op!(F32Ceil),
|
||||||
|
Operator::F32Floor => op!(F32Floor),
|
||||||
|
Operator::F32Trunc => op!(F32Trunc),
|
||||||
|
Operator::F32Nearest => op!(F32Nearest),
|
||||||
|
Operator::F32Sqrt => op!(F32Sqrt),
|
||||||
|
|
||||||
|
Operator::F32Add => op!(F32Add),
|
||||||
|
Operator::F32Sub => op!(F32Sub),
|
||||||
|
Operator::F32Mul => op!(F32Mul),
|
||||||
|
Operator::F32Div => op!(F32Div),
|
||||||
|
Operator::F32Min => op!(F32Min),
|
||||||
|
Operator::F32Max => op!(F32Max),
|
||||||
|
Operator::F32Copysign => op!(F32Copysign),
|
||||||
|
|
||||||
|
Operator::F64Abs => op!(F64Abs),
|
||||||
|
Operator::F64Neg => op!(F64Neg),
|
||||||
|
Operator::F64Ceil => op!(F64Ceil),
|
||||||
|
Operator::F64Floor => op!(F64Floor),
|
||||||
|
Operator::F64Trunc => op!(F64Trunc),
|
||||||
|
Operator::F64Nearest => op!(F64Nearest),
|
||||||
|
Operator::F64Sqrt => op!(F64Sqrt),
|
||||||
|
|
||||||
|
Operator::F64Add => op!(F64Add),
|
||||||
|
Operator::F64Sub => op!(F64Sub),
|
||||||
|
Operator::F64Mul => op!(F64Mul),
|
||||||
|
Operator::F64Div => op!(F64Div),
|
||||||
|
Operator::F64Min => op!(F64Min),
|
||||||
|
Operator::F64Max => op!(F64Max),
|
||||||
|
Operator::F64Copysign => op!(F64Copysign),
|
||||||
|
|
||||||
|
Operator::I32WrapI64 => op!(I32WrapI64),
|
||||||
|
Operator::I32TruncF32S => op!(I32TruncF32S),
|
||||||
|
Operator::I32TruncF32U => op!(I32TruncF32U),
|
||||||
|
Operator::I32TruncF64S => op!(I32TruncF64S),
|
||||||
|
Operator::I32TruncF64U => op!(I32TruncF64U),
|
||||||
|
Operator::I64ExtendI32S => op!(I64ExtendI32S),
|
||||||
|
Operator::I64ExtendI32U => op!(I64ExtendI32U),
|
||||||
|
Operator::I64TruncF32S => op!(I64TruncF32S),
|
||||||
|
Operator::I64TruncF32U => op!(I64TruncF32U),
|
||||||
|
Operator::I64TruncF64S => op!(I64TruncF64S),
|
||||||
|
Operator::I64TruncF64U => op!(I64TruncF64U),
|
||||||
|
Operator::F32ConvertI32S => op!(F32ConvertI32S),
|
||||||
|
Operator::F32ConvertI32U => op!(F32ConvertI32U),
|
||||||
|
Operator::F32ConvertI64S => op!(F32ConvertI64S),
|
||||||
|
Operator::F32ConvertI64U => op!(F32ConvertI64U),
|
||||||
|
Operator::F32DemoteF64 => op!(F32DemoteF64),
|
||||||
|
Operator::F64ConvertI32S => op!(F64ConvertI32S),
|
||||||
|
Operator::F64ConvertI32U => op!(F64ConvertI32U),
|
||||||
|
Operator::F64ConvertI64S => op!(F64ConvertI64S),
|
||||||
|
Operator::F64ConvertI64U => op!(F64ConvertI64U),
|
||||||
|
Operator::F64PromoteF32 => op!(F64PromoteF32),
|
||||||
|
Operator::I32Extend8S => op!(I32Extend8S),
|
||||||
|
Operator::I32Extend16S => op!(I32Extend16S),
|
||||||
|
Operator::I64Extend8S => op!(I64Extend8S),
|
||||||
|
Operator::I64Extend16S => op!(I64Extend16S),
|
||||||
|
Operator::I64Extend32S => op!(I64Extend32S),
|
||||||
|
Operator::I32TruncSatF32S => op!(I32TruncSatF32S),
|
||||||
|
Operator::I32TruncSatF32U => op!(I32TruncSatF32U),
|
||||||
|
Operator::I32TruncSatF64S => op!(I32TruncSatF64S),
|
||||||
|
Operator::I32TruncSatF64U => op!(I32TruncSatF64U),
|
||||||
|
Operator::I64TruncSatF32S => op!(I64TruncSatF32S),
|
||||||
|
Operator::I64TruncSatF32U => op!(I64TruncSatF32U),
|
||||||
|
Operator::I64TruncSatF64S => op!(I64TruncSatF64S),
|
||||||
|
Operator::I64TruncSatF64U => op!(I64TruncSatF64U),
|
||||||
|
Operator::F32ReinterpretI32 => op!(F32ReinterpretI32),
|
||||||
|
Operator::F64ReinterpretI64 => op!(F64ReinterpretI64),
|
||||||
|
Operator::I32ReinterpretF32 => op!(I32ReinterpretF32),
|
||||||
|
Operator::I64ReinterpretF64 => op!(I64ReinterpretF64),
|
||||||
|
|
||||||
|
Operator::TableGet { table_index } => Some(wasm_encoder::Instruction::TableGet(
|
||||||
|
table_index.index() as u32,
|
||||||
|
)),
|
||||||
|
Operator::TableSet { table_index } => Some(wasm_encoder::Instruction::TableSet(
|
||||||
|
table_index.index() as u32,
|
||||||
|
)),
|
||||||
|
Operator::TableGrow { table_index } => Some(wasm_encoder::Instruction::TableGrow(
|
||||||
|
table_index.index() as u32,
|
||||||
|
)),
|
||||||
|
Operator::TableSize { table_index } => Some(wasm_encoder::Instruction::TableSize(
|
||||||
|
table_index.index() as u32,
|
||||||
|
)),
|
||||||
|
Operator::MemorySize { mem } => {
|
||||||
|
Some(wasm_encoder::Instruction::MemorySize(mem.index() as u32))
|
||||||
|
}
|
||||||
|
Operator::MemoryGrow { mem } => {
|
||||||
|
Some(wasm_encoder::Instruction::MemoryGrow(mem.index() as u32))
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
if let Some(inst) = inst {
|
||||||
|
func.instruction(&inst);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1316,14 +1316,8 @@ impl<'a, 'b> FunctionBodyBuilder<'a, 'b> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn emit(&mut self, op: Operator) -> Result<()> {
|
fn emit(&mut self, op: Operator) -> Result<()> {
|
||||||
let inputs = op_inputs(
|
let inputs = op_inputs(self.module, self.my_sig, &self.op_stack[..], &op)?;
|
||||||
self.module,
|
let outputs = op_outputs(self.module, &self.op_stack[..], &op)?;
|
||||||
self.my_sig,
|
|
||||||
&self.body.locals,
|
|
||||||
&self.op_stack[..],
|
|
||||||
&op,
|
|
||||||
)?;
|
|
||||||
let outputs = op_outputs(self.module, &self.body.locals, &self.op_stack[..], &op)?;
|
|
||||||
|
|
||||||
log::trace!(
|
log::trace!(
|
||||||
"emit into block {:?}: op {:?} inputs {:?}",
|
"emit into block {:?}: op {:?} inputs {:?}",
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
//! Metadata on operators.
|
//! Metadata on operators.
|
||||||
|
|
||||||
use crate::entity::EntityVec;
|
use crate::ir::{Module, Signature, Type, Value};
|
||||||
use crate::ir::{Local, Module, Signature, Type, Value};
|
|
||||||
use crate::Operator;
|
use crate::Operator;
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
use std::borrow::Cow;
|
use std::borrow::Cow;
|
||||||
|
@ -9,7 +8,6 @@ use std::borrow::Cow;
|
||||||
pub fn op_inputs(
|
pub fn op_inputs(
|
||||||
module: &Module,
|
module: &Module,
|
||||||
my_sig: Signature,
|
my_sig: Signature,
|
||||||
my_locals: &EntityVec<Local, Type>,
|
|
||||||
op_stack: &[(Type, Value)],
|
op_stack: &[(Type, Value)],
|
||||||
op: &Operator,
|
op: &Operator,
|
||||||
) -> Result<Cow<'static, [Type]>> {
|
) -> Result<Cow<'static, [Type]>> {
|
||||||
|
@ -27,11 +25,6 @@ pub fn op_inputs(
|
||||||
}
|
}
|
||||||
&Operator::Return => Ok(Vec::from(module.signature(my_sig).returns.clone()).into()),
|
&Operator::Return => Ok(Vec::from(module.signature(my_sig).returns.clone()).into()),
|
||||||
|
|
||||||
&Operator::LocalSet { local_index } | &Operator::LocalTee { local_index } => {
|
|
||||||
Ok(vec![my_locals[local_index]].into())
|
|
||||||
}
|
|
||||||
&Operator::LocalGet { .. } => Ok(Cow::Borrowed(&[])),
|
|
||||||
|
|
||||||
&Operator::Select => {
|
&Operator::Select => {
|
||||||
let val_ty = op_stack[op_stack.len() - 2].0;
|
let val_ty = op_stack[op_stack.len() - 2].0;
|
||||||
Ok(vec![val_ty, val_ty, Type::I32].into())
|
Ok(vec![val_ty, val_ty, Type::I32].into())
|
||||||
|
@ -235,7 +228,6 @@ pub fn op_inputs(
|
||||||
|
|
||||||
pub fn op_outputs(
|
pub fn op_outputs(
|
||||||
module: &Module,
|
module: &Module,
|
||||||
my_locals: &EntityVec<Local, Type>,
|
|
||||||
op_stack: &[(Type, Value)],
|
op_stack: &[(Type, Value)],
|
||||||
op: &Operator,
|
op: &Operator,
|
||||||
) -> Result<Cow<'static, [Type]>> {
|
) -> Result<Cow<'static, [Type]>> {
|
||||||
|
@ -250,10 +242,6 @@ pub fn op_outputs(
|
||||||
Ok(Vec::from(module.signature(sig_index).returns.clone()).into())
|
Ok(Vec::from(module.signature(sig_index).returns.clone()).into())
|
||||||
}
|
}
|
||||||
&Operator::Return => Ok(Cow::Borrowed(&[])),
|
&Operator::Return => Ok(Cow::Borrowed(&[])),
|
||||||
&Operator::LocalSet { .. } => Ok(Cow::Borrowed(&[])),
|
|
||||||
&Operator::LocalGet { local_index } | &Operator::LocalTee { local_index } => {
|
|
||||||
Ok(vec![my_locals[local_index]].into())
|
|
||||||
}
|
|
||||||
|
|
||||||
&Operator::Select => {
|
&Operator::Select => {
|
||||||
let val_ty = op_stack[op_stack.len() - 2].0;
|
let val_ty = op_stack[op_stack.len() - 2].0;
|
||||||
|
@ -469,9 +457,6 @@ impl Operator {
|
||||||
&Operator::Call { .. } => &[All],
|
&Operator::Call { .. } => &[All],
|
||||||
&Operator::CallIndirect { .. } => &[All],
|
&Operator::CallIndirect { .. } => &[All],
|
||||||
&Operator::Return => &[Return],
|
&Operator::Return => &[Return],
|
||||||
&Operator::LocalSet { .. } => &[WriteLocal],
|
|
||||||
&Operator::LocalGet { .. } => &[ReadLocal],
|
|
||||||
&Operator::LocalTee { .. } => &[ReadLocal, WriteLocal],
|
|
||||||
|
|
||||||
&Operator::Select => &[],
|
&Operator::Select => &[],
|
||||||
&Operator::TypedSelect { .. } => &[],
|
&Operator::TypedSelect { .. } => &[],
|
||||||
|
@ -675,9 +660,6 @@ impl std::fmt::Display for Operator {
|
||||||
table_index,
|
table_index,
|
||||||
} => write!(f, "call_indirect<{}, {}>", sig_index, table_index)?,
|
} => write!(f, "call_indirect<{}, {}>", sig_index, table_index)?,
|
||||||
&Operator::Return => write!(f, "return")?,
|
&Operator::Return => write!(f, "return")?,
|
||||||
&Operator::LocalSet { local_index, .. } => write!(f, "local_set<{}>", local_index)?,
|
|
||||||
&Operator::LocalGet { local_index, .. } => write!(f, "local_get<{}>", local_index)?,
|
|
||||||
&Operator::LocalTee { local_index, .. } => write!(f, "local_tee<{}>", local_index)?,
|
|
||||||
|
|
||||||
&Operator::Select => write!(f, "select")?,
|
&Operator::Select => write!(f, "select")?,
|
||||||
&Operator::TypedSelect { ty } => write!(f, "typed_select<{}>", ty)?,
|
&Operator::TypedSelect { ty } => write!(f, "typed_select<{}>", ty)?,
|
||||||
|
|
33
src/ops.rs
33
src/ops.rs
|
@ -1,6 +1,6 @@
|
||||||
//! Operators.
|
//! Operators.
|
||||||
|
|
||||||
use crate::{Func, Global, Local, Memory, Signature, Table, Type};
|
use crate::{entity::EntityRef, Func, Global, Memory, Signature, Table, Type};
|
||||||
use std::convert::TryFrom;
|
use std::convert::TryFrom;
|
||||||
pub use wasmparser::{Ieee32, Ieee64};
|
pub use wasmparser::{Ieee32, Ieee64};
|
||||||
|
|
||||||
|
@ -34,15 +34,6 @@ pub enum Operator {
|
||||||
table_index: Table,
|
table_index: Table,
|
||||||
},
|
},
|
||||||
Return,
|
Return,
|
||||||
LocalSet {
|
|
||||||
local_index: Local,
|
|
||||||
},
|
|
||||||
LocalTee {
|
|
||||||
local_index: Local,
|
|
||||||
},
|
|
||||||
LocalGet {
|
|
||||||
local_index: Local,
|
|
||||||
},
|
|
||||||
Select,
|
Select,
|
||||||
TypedSelect {
|
TypedSelect {
|
||||||
ty: Type,
|
ty: Type,
|
||||||
|
@ -326,15 +317,9 @@ impl<'a, 'b> std::convert::TryFrom<&'b wasmparser::Operator<'a>> for Operator {
|
||||||
table_index: Table::from(table_index),
|
table_index: Table::from(table_index),
|
||||||
}),
|
}),
|
||||||
&wasmparser::Operator::Return => Ok(Operator::Return),
|
&wasmparser::Operator::Return => Ok(Operator::Return),
|
||||||
&wasmparser::Operator::LocalSet { local_index } => Ok(Operator::LocalSet {
|
&wasmparser::Operator::LocalSet { .. } => Err(()),
|
||||||
local_index: Local::from(local_index),
|
&wasmparser::Operator::LocalTee { .. } => Err(()),
|
||||||
}),
|
&wasmparser::Operator::LocalGet { .. } => Err(()),
|
||||||
&wasmparser::Operator::LocalTee { local_index } => Ok(Operator::LocalTee {
|
|
||||||
local_index: Local::from(local_index),
|
|
||||||
}),
|
|
||||||
&wasmparser::Operator::LocalGet { local_index } => Ok(Operator::LocalGet {
|
|
||||||
local_index: Local::from(local_index),
|
|
||||||
}),
|
|
||||||
&wasmparser::Operator::Select => Ok(Operator::Select),
|
&wasmparser::Operator::Select => Ok(Operator::Select),
|
||||||
&wasmparser::Operator::TypedSelect { ty } => {
|
&wasmparser::Operator::TypedSelect { ty } => {
|
||||||
Ok(Operator::TypedSelect { ty: ty.into() })
|
Ok(Operator::TypedSelect { ty: ty.into() })
|
||||||
|
@ -594,3 +579,13 @@ impl std::convert::From<wasmparser::MemArg> for MemoryArg {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl std::convert::From<MemoryArg> for wasm_encoder::MemArg {
|
||||||
|
fn from(value: MemoryArg) -> wasm_encoder::MemArg {
|
||||||
|
wasm_encoder::MemArg {
|
||||||
|
offset: value.offset as u64,
|
||||||
|
align: value.align,
|
||||||
|
memory_index: value.memory.index() as u32,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue