Initial support for all Wasm MVP opcodes in frontend. Still have a few fuzz failures.
This commit is contained in:
parent
0966867317
commit
45a66fa3b8
116
src/frontend.rs
116
src/frontend.rs
|
@ -39,12 +39,33 @@ fn handle_payload<'a>(
|
||||||
}
|
}
|
||||||
Payload::ImportSection(mut reader) => {
|
Payload::ImportSection(mut reader) => {
|
||||||
for _ in 0..reader.get_count() {
|
for _ in 0..reader.get_count() {
|
||||||
if let ImportSectionEntryType::Function(sig_idx) = reader.read()?.ty {
|
match reader.read()?.ty {
|
||||||
module.funcs.push(FuncDecl::Import(sig_idx as SignatureId));
|
ImportSectionEntryType::Function(sig_idx) => {
|
||||||
*next_func += 1;
|
module.funcs.push(FuncDecl::Import(sig_idx as SignatureId));
|
||||||
|
*next_func += 1;
|
||||||
|
}
|
||||||
|
ImportSectionEntryType::Global(ty) => {
|
||||||
|
module.globals.push(ty.content_type);
|
||||||
|
}
|
||||||
|
ImportSectionEntryType::Table(ty) => {
|
||||||
|
module.tables.push(ty.element_type);
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Payload::GlobalSection(mut reader) => {
|
||||||
|
for _ in 0..reader.get_count() {
|
||||||
|
let global = reader.read()?;
|
||||||
|
module.globals.push(global.ty.content_type);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Payload::TableSection(mut reader) => {
|
||||||
|
for _ in 0..reader.get_count() {
|
||||||
|
let table = reader.read()?;
|
||||||
|
module.tables.push(table.element_type);
|
||||||
|
}
|
||||||
|
}
|
||||||
Payload::FunctionSection(mut reader) => {
|
Payload::FunctionSection(mut reader) => {
|
||||||
for _ in 0..reader.get_count() {
|
for _ in 0..reader.get_count() {
|
||||||
let sig_idx = reader.read()? as SignatureId;
|
let sig_idx = reader.read()? as SignatureId;
|
||||||
|
@ -104,7 +125,7 @@ struct FunctionBodyBuilder<'a, 'b> {
|
||||||
body: &'b mut FunctionBody<'a>,
|
body: &'b mut FunctionBody<'a>,
|
||||||
cur_block: Option<BlockId>,
|
cur_block: Option<BlockId>,
|
||||||
ctrl_stack: Vec<Frame>,
|
ctrl_stack: Vec<Frame>,
|
||||||
op_stack: Vec<ValueId>,
|
op_stack: Vec<(Type, ValueId)>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
|
@ -126,7 +147,7 @@ enum Frame {
|
||||||
start_depth: usize,
|
start_depth: usize,
|
||||||
out: BlockId,
|
out: BlockId,
|
||||||
el: BlockId,
|
el: BlockId,
|
||||||
param_values: Vec<ValueId>,
|
param_values: Vec<(Type, ValueId)>,
|
||||||
params: Vec<Type>,
|
params: Vec<Type>,
|
||||||
results: Vec<Type>,
|
results: Vec<Type>,
|
||||||
},
|
},
|
||||||
|
@ -183,6 +204,18 @@ impl<'a, 'b> FunctionBodyBuilder<'a, 'b> {
|
||||||
self.body.blocks[block].params.extend_from_slice(tys);
|
self.body.blocks[block].params.extend_from_slice(tys);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn pop_n(&mut self, n: usize) -> Vec<ValueId> {
|
||||||
|
self.op_stack
|
||||||
|
.split_off(n)
|
||||||
|
.into_iter()
|
||||||
|
.map(|(_ty, value)| value)
|
||||||
|
.collect()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn pop_1(&mut self) -> ValueId {
|
||||||
|
self.op_stack.pop().unwrap().1
|
||||||
|
}
|
||||||
|
|
||||||
fn handle_op(&mut self, op: Operator<'a>) -> Result<()> {
|
fn handle_op(&mut self, op: Operator<'a>) -> Result<()> {
|
||||||
match &op {
|
match &op {
|
||||||
Operator::Unreachable
|
Operator::Unreachable
|
||||||
|
@ -364,7 +397,7 @@ impl<'a, 'b> FunctionBodyBuilder<'a, 'b> {
|
||||||
Operator::Nop => {}
|
Operator::Nop => {}
|
||||||
|
|
||||||
Operator::Drop => {
|
Operator::Drop => {
|
||||||
self.op_stack.pop().unwrap();
|
let _ = self.pop_1();
|
||||||
}
|
}
|
||||||
|
|
||||||
Operator::End => match self.ctrl_stack.pop() {
|
Operator::End => match self.ctrl_stack.pop() {
|
||||||
|
@ -385,7 +418,7 @@ impl<'a, 'b> FunctionBodyBuilder<'a, 'b> {
|
||||||
}) => {
|
}) => {
|
||||||
// Generate a branch to the out-block with
|
// Generate a branch to the out-block with
|
||||||
// blockparams for the results.
|
// blockparams for the results.
|
||||||
let result_values = self.op_stack.split_off(results.len());
|
let result_values = self.pop_n(results.len());
|
||||||
self.emit_branch(out, &result_values[..]);
|
self.emit_branch(out, &result_values[..]);
|
||||||
assert_eq!(self.op_stack.len(), start_depth);
|
assert_eq!(self.op_stack.len(), start_depth);
|
||||||
self.cur_block = Some(out);
|
self.cur_block = Some(out);
|
||||||
|
@ -401,13 +434,17 @@ impl<'a, 'b> FunctionBodyBuilder<'a, 'b> {
|
||||||
}) => {
|
}) => {
|
||||||
// Generate a branch to the out-block with
|
// Generate a branch to the out-block with
|
||||||
// blockparams for the results.
|
// blockparams for the results.
|
||||||
let result_values = self.op_stack.split_off(results.len());
|
let result_values = self.pop_n(results.len());
|
||||||
self.emit_branch(out, &result_values[..]);
|
self.emit_branch(out, &result_values[..]);
|
||||||
// No `else`, so we need to generate a trivial
|
// No `else`, so we need to generate a trivial
|
||||||
// branch in the else-block. If the if-block-type
|
// branch in the else-block. If the if-block-type
|
||||||
// has results, they must be exactly the params.
|
// has results, they must be exactly the params.
|
||||||
let else_result_values = param_values;
|
let else_result_values = param_values;
|
||||||
assert_eq!(else_result_values.len(), results.len());
|
assert_eq!(else_result_values.len(), results.len());
|
||||||
|
let else_result_values = else_result_values
|
||||||
|
.iter()
|
||||||
|
.map(|(_ty, value)| *value)
|
||||||
|
.collect::<Vec<_>>();
|
||||||
self.emit_branch(el, &else_result_values[..]);
|
self.emit_branch(el, &else_result_values[..]);
|
||||||
assert_eq!(self.op_stack.len(), start_depth);
|
assert_eq!(self.op_stack.len(), start_depth);
|
||||||
self.cur_block = Some(out);
|
self.cur_block = Some(out);
|
||||||
|
@ -421,7 +458,7 @@ impl<'a, 'b> FunctionBodyBuilder<'a, 'b> {
|
||||||
}) => {
|
}) => {
|
||||||
// Generate a branch to the out-block with
|
// Generate a branch to the out-block with
|
||||||
// blockparams for the results.
|
// blockparams for the results.
|
||||||
let result_values = self.op_stack.split_off(results.len());
|
let result_values = self.pop_n(results.len());
|
||||||
assert_eq!(self.op_stack.len(), start_depth);
|
assert_eq!(self.op_stack.len(), start_depth);
|
||||||
self.emit_branch(out, &result_values[..]);
|
self.emit_branch(out, &result_values[..]);
|
||||||
self.cur_block = Some(out);
|
self.cur_block = Some(out);
|
||||||
|
@ -446,7 +483,7 @@ impl<'a, 'b> FunctionBodyBuilder<'a, 'b> {
|
||||||
let (params, results) = self.block_params_and_results(*ty);
|
let (params, results) = self.block_params_and_results(*ty);
|
||||||
let header = self.create_block();
|
let header = self.create_block();
|
||||||
self.add_block_params(header, ¶ms[..]);
|
self.add_block_params(header, ¶ms[..]);
|
||||||
let initial_args = self.op_stack.split_off(params.len());
|
let initial_args = self.pop_n(params.len());
|
||||||
let start_depth = self.op_stack.len();
|
let start_depth = self.op_stack.len();
|
||||||
self.emit_branch(header, &initial_args[..]);
|
self.emit_branch(header, &initial_args[..]);
|
||||||
self.cur_block = Some(header);
|
self.cur_block = Some(header);
|
||||||
|
@ -467,7 +504,7 @@ impl<'a, 'b> FunctionBodyBuilder<'a, 'b> {
|
||||||
let if_false = self.create_block();
|
let if_false = self.create_block();
|
||||||
let join = self.create_block();
|
let join = self.create_block();
|
||||||
self.add_block_params(join, &results[..]);
|
self.add_block_params(join, &results[..]);
|
||||||
let cond = self.op_stack.pop().unwrap();
|
let cond = self.pop_1();
|
||||||
let param_values = self.op_stack[self.op_stack.len() - params.len()..].to_vec();
|
let param_values = self.op_stack[self.op_stack.len() - params.len()..].to_vec();
|
||||||
let start_depth = self.op_stack.len();
|
let start_depth = self.op_stack.len();
|
||||||
self.ctrl_stack.push(Frame::If {
|
self.ctrl_stack.push(Frame::If {
|
||||||
|
@ -492,7 +529,7 @@ impl<'a, 'b> FunctionBodyBuilder<'a, 'b> {
|
||||||
results,
|
results,
|
||||||
} = self.ctrl_stack.pop().unwrap()
|
} = self.ctrl_stack.pop().unwrap()
|
||||||
{
|
{
|
||||||
let if_results = self.op_stack.split_off(results.len());
|
let if_results = self.pop_n(results.len());
|
||||||
self.emit_branch(out, &if_results[..]);
|
self.emit_branch(out, &if_results[..]);
|
||||||
self.op_stack.extend(param_values);
|
self.op_stack.extend(param_values);
|
||||||
self.ctrl_stack.push(Frame::Else {
|
self.ctrl_stack.push(Frame::Else {
|
||||||
|
@ -510,13 +547,13 @@ impl<'a, 'b> FunctionBodyBuilder<'a, 'b> {
|
||||||
Operator::Br { relative_depth } | Operator::BrIf { relative_depth } => {
|
Operator::Br { relative_depth } | Operator::BrIf { relative_depth } => {
|
||||||
let cond = match &op {
|
let cond = match &op {
|
||||||
Operator::Br { .. } => None,
|
Operator::Br { .. } => None,
|
||||||
Operator::BrIf { .. } => Some(self.op_stack.pop().unwrap()),
|
Operator::BrIf { .. } => Some(self.pop_1()),
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
};
|
};
|
||||||
// Get the frame we're branching to.
|
// Get the frame we're branching to.
|
||||||
let frame = self.relative_frame(*relative_depth).clone();
|
let frame = self.relative_frame(*relative_depth).clone();
|
||||||
// Get the args off the stack.
|
// Get the args off the stack.
|
||||||
let args = self.op_stack.split_off(frame.br_args().len());
|
let args = self.pop_n(frame.br_args().len());
|
||||||
// Finally, generate the branch itself.
|
// Finally, generate the branch itself.
|
||||||
match cond {
|
match cond {
|
||||||
None => {
|
None => {
|
||||||
|
@ -533,14 +570,14 @@ impl<'a, 'b> FunctionBodyBuilder<'a, 'b> {
|
||||||
|
|
||||||
Operator::BrTable { table } => {
|
Operator::BrTable { table } => {
|
||||||
// Get the selector index.
|
// Get the selector index.
|
||||||
let index = self.op_stack.pop().unwrap();
|
let index = self.pop_1();
|
||||||
// Get the signature of the default frame; this tells
|
// Get the signature of the default frame; this tells
|
||||||
// us the signature of all frames (since wasmparser
|
// us the signature of all frames (since wasmparser
|
||||||
// validates the input for us). Pop that many args.
|
// validates the input for us). Pop that many args.
|
||||||
let default_frame = self.relative_frame(table.default());
|
let default_frame = self.relative_frame(table.default());
|
||||||
let default_term_target = default_frame.br_target();
|
let default_term_target = default_frame.br_target();
|
||||||
let arg_len = default_frame.br_args().len();
|
let arg_len = default_frame.br_args().len();
|
||||||
let args = self.op_stack.split_off(arg_len);
|
let args = self.pop_n(arg_len);
|
||||||
// Generate a branch terminator with the same args for
|
// Generate a branch terminator with the same args for
|
||||||
// every branch target.
|
// every branch target.
|
||||||
let mut term_targets = vec![];
|
let mut term_targets = vec![];
|
||||||
|
@ -556,9 +593,7 @@ impl<'a, 'b> FunctionBodyBuilder<'a, 'b> {
|
||||||
}
|
}
|
||||||
|
|
||||||
Operator::Return => {
|
Operator::Return => {
|
||||||
let retvals = self
|
let retvals = self.pop_n(self.module.signatures[self.my_sig].returns.len());
|
||||||
.op_stack
|
|
||||||
.split_off(self.module.signatures[self.my_sig].returns.len());
|
|
||||||
self.emit_ret(&retvals[..]);
|
self.emit_ret(&retvals[..]);
|
||||||
self.cur_block = None;
|
self.cur_block = None;
|
||||||
}
|
}
|
||||||
|
@ -677,7 +712,7 @@ impl<'a, 'b> FunctionBodyBuilder<'a, 'b> {
|
||||||
kind: ValueKind::BlockParam(self.cur_block.unwrap(), i),
|
kind: ValueKind::BlockParam(self.cur_block.unwrap(), i),
|
||||||
ty,
|
ty,
|
||||||
});
|
});
|
||||||
self.op_stack.push(value_id);
|
self.op_stack.push((ty, value_id));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -686,25 +721,33 @@ impl<'a, 'b> FunctionBodyBuilder<'a, 'b> {
|
||||||
let inst = self.body.blocks[block].insts.len() as InstId;
|
let inst = self.body.blocks[block].insts.len() as InstId;
|
||||||
|
|
||||||
let mut inputs = vec![];
|
let mut inputs = vec![];
|
||||||
for input in op_inputs(self.module, self.my_sig, &self.body.locals[..], &op)?
|
for input in op_inputs(
|
||||||
.into_iter()
|
self.module,
|
||||||
.rev()
|
self.my_sig,
|
||||||
|
&self.body.locals[..],
|
||||||
|
&self.op_stack[..],
|
||||||
|
&op,
|
||||||
|
)?
|
||||||
|
.into_iter()
|
||||||
|
.rev()
|
||||||
{
|
{
|
||||||
let stack_top = self.op_stack.pop().unwrap();
|
let (stack_top_ty, stack_top) = self.op_stack.pop().unwrap();
|
||||||
assert_eq!(self.body.values[stack_top].ty, input);
|
assert_eq!(stack_top_ty, input);
|
||||||
inputs.push(Operand::value(stack_top));
|
inputs.push(Operand::value(stack_top));
|
||||||
}
|
}
|
||||||
inputs.reverse();
|
inputs.reverse();
|
||||||
|
|
||||||
let mut outputs = vec![];
|
let mut outputs = vec![];
|
||||||
for output in op_outputs(self.module, &self.body.locals[..], &op)?.into_iter() {
|
for output_ty in
|
||||||
|
op_outputs(self.module, &self.body.locals[..], &self.op_stack[..], &op)?.into_iter()
|
||||||
|
{
|
||||||
let val = self.body.values.len() as ValueId;
|
let val = self.body.values.len() as ValueId;
|
||||||
outputs.push(val);
|
outputs.push(val);
|
||||||
self.body.values.push(ValueDef {
|
self.body.values.push(ValueDef {
|
||||||
kind: ValueKind::Inst(block, inst),
|
kind: ValueKind::Inst(block, inst),
|
||||||
ty: output,
|
ty: output_ty,
|
||||||
});
|
});
|
||||||
self.op_stack.push(val);
|
self.op_stack.push((output_ty, val));
|
||||||
}
|
}
|
||||||
|
|
||||||
self.body.blocks[block].insts.push(Inst {
|
self.body.blocks[block].insts.push(Inst {
|
||||||
|
@ -713,11 +756,18 @@ impl<'a, 'b> FunctionBodyBuilder<'a, 'b> {
|
||||||
inputs,
|
inputs,
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
let _ = self
|
let _ = self.pop_n(
|
||||||
.op_stack
|
op_inputs(
|
||||||
.split_off(op_inputs(self.module, self.my_sig, &self.body.locals[..], &op)?.len());
|
self.module,
|
||||||
for _ in 0..op_outputs(self.module, &self.body.locals[..], &op)?.len() {
|
self.my_sig,
|
||||||
self.op_stack.push(NO_VALUE);
|
&self.body.locals[..],
|
||||||
|
&self.op_stack[..],
|
||||||
|
&op,
|
||||||
|
)?
|
||||||
|
.len(),
|
||||||
|
);
|
||||||
|
for ty in op_outputs(self.module, &self.body.locals[..], &self.op_stack[..], &op)? {
|
||||||
|
self.op_stack.push((ty, NO_VALUE));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -14,6 +14,8 @@ pub const NO_VALUE: ValueId = usize::MAX;
|
||||||
pub struct Module<'a> {
|
pub struct Module<'a> {
|
||||||
pub funcs: Vec<FuncDecl<'a>>,
|
pub funcs: Vec<FuncDecl<'a>>,
|
||||||
pub signatures: Vec<FuncType>,
|
pub signatures: Vec<FuncType>,
|
||||||
|
pub globals: Vec<Type>,
|
||||||
|
pub tables: Vec<Type>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
|
|
376
src/op_traits.rs
376
src/op_traits.rs
|
@ -1,6 +1,6 @@
|
||||||
//! Metadata on operators.
|
//! Metadata on operators.
|
||||||
|
|
||||||
use crate::ir::{Module, SignatureId};
|
use crate::ir::{Module, SignatureId, ValueId};
|
||||||
use anyhow::{bail, Result};
|
use anyhow::{bail, Result};
|
||||||
use wasmparser::{Operator, Type};
|
use wasmparser::{Operator, Type};
|
||||||
|
|
||||||
|
@ -8,6 +8,7 @@ pub fn op_inputs(
|
||||||
module: &Module,
|
module: &Module,
|
||||||
my_sig: SignatureId,
|
my_sig: SignatureId,
|
||||||
my_locals: &[Type],
|
my_locals: &[Type],
|
||||||
|
op_stack: &[(Type, ValueId)],
|
||||||
op: &Operator<'_>,
|
op: &Operator<'_>,
|
||||||
) -> Result<Vec<Type>> {
|
) -> Result<Vec<Type>> {
|
||||||
match op {
|
match op {
|
||||||
|
@ -29,14 +30,201 @@ pub fn op_inputs(
|
||||||
}
|
}
|
||||||
&Operator::LocalGet { .. } => Ok(vec![]),
|
&Operator::LocalGet { .. } => Ok(vec![]),
|
||||||
|
|
||||||
&Operator::I32Eqz => Ok(vec![Type::I32]),
|
&Operator::Select => {
|
||||||
&Operator::I32Eq => Ok(vec![Type::I32, Type::I32]),
|
let val_ty = op_stack[op_stack.len() - 2].0;
|
||||||
|
Ok(vec![val_ty, val_ty, Type::I32])
|
||||||
|
}
|
||||||
|
&Operator::TypedSelect { ty } => Ok(vec![ty, ty, Type::I32]),
|
||||||
|
|
||||||
|
&Operator::GlobalGet { .. } => Ok(vec![]),
|
||||||
|
&Operator::GlobalSet { global_index } => Ok(vec![module.globals[global_index as usize]]),
|
||||||
|
|
||||||
|
Operator::I32Load { .. }
|
||||||
|
| Operator::I64Load { .. }
|
||||||
|
| Operator::F32Load { .. }
|
||||||
|
| Operator::F64Load { .. }
|
||||||
|
| Operator::I32Load8S { .. }
|
||||||
|
| Operator::I32Load8U { .. }
|
||||||
|
| Operator::I32Load16S { .. }
|
||||||
|
| Operator::I32Load16U { .. }
|
||||||
|
| Operator::I64Load8S { .. }
|
||||||
|
| Operator::I64Load8U { .. }
|
||||||
|
| Operator::I64Load16S { .. }
|
||||||
|
| Operator::I64Load16U { .. }
|
||||||
|
| Operator::I64Load32S { .. }
|
||||||
|
| Operator::I64Load32U { .. } => Ok(vec![Type::I32]),
|
||||||
|
|
||||||
|
Operator::I32Store { .. } => Ok(vec![Type::I32, Type::I32]),
|
||||||
|
Operator::I64Store { .. } => Ok(vec![Type::I32, Type::I64]),
|
||||||
|
Operator::F32Store { .. } => Ok(vec![Type::I32, Type::F32]),
|
||||||
|
Operator::F64Store { .. } => Ok(vec![Type::I32, Type::F64]),
|
||||||
|
Operator::I32Store8 { .. } => Ok(vec![Type::I32, Type::I32]),
|
||||||
|
Operator::I32Store16 { .. } => Ok(vec![Type::I32, Type::I32]),
|
||||||
|
Operator::I64Store8 { .. } => Ok(vec![Type::I32, Type::I64]),
|
||||||
|
Operator::I64Store16 { .. } => Ok(vec![Type::I32, Type::I64]),
|
||||||
|
Operator::I64Store32 { .. } => Ok(vec![Type::I32, Type::I64]),
|
||||||
|
|
||||||
|
Operator::I32Const { .. }
|
||||||
|
| Operator::I64Const { .. }
|
||||||
|
| Operator::F32Const { .. }
|
||||||
|
| Operator::F64Const { .. } => Ok(vec![]),
|
||||||
|
|
||||||
|
Operator::I32Eqz => Ok(vec![Type::I32]),
|
||||||
|
Operator::I32Eq
|
||||||
|
| Operator::I32Ne
|
||||||
|
| Operator::I32LtS
|
||||||
|
| Operator::I32LtU
|
||||||
|
| Operator::I32GtS
|
||||||
|
| Operator::I32GtU
|
||||||
|
| Operator::I32LeS
|
||||||
|
| Operator::I32LeU
|
||||||
|
| Operator::I32GeS
|
||||||
|
| Operator::I32GeU => Ok(vec![Type::I32, Type::I32]),
|
||||||
|
|
||||||
|
Operator::I64Eqz => Ok(vec![Type::I64]),
|
||||||
|
|
||||||
|
Operator::I64Eq
|
||||||
|
| Operator::I64Ne
|
||||||
|
| Operator::I64LtS
|
||||||
|
| Operator::I64LtU
|
||||||
|
| Operator::I64GtU
|
||||||
|
| Operator::I64GtS
|
||||||
|
| Operator::I64LeS
|
||||||
|
| Operator::I64LeU
|
||||||
|
| Operator::I64GeS
|
||||||
|
| Operator::I64GeU => Ok(vec![Type::I64, Type::I64]),
|
||||||
|
|
||||||
|
Operator::F32Eq
|
||||||
|
| Operator::F32Ne
|
||||||
|
| Operator::F32Lt
|
||||||
|
| Operator::F32Gt
|
||||||
|
| Operator::F32Le
|
||||||
|
| Operator::F32Ge => Ok(vec![Type::F32, Type::F32]),
|
||||||
|
|
||||||
|
Operator::F64Eq
|
||||||
|
| Operator::F64Ne
|
||||||
|
| Operator::F64Lt
|
||||||
|
| Operator::F64Gt
|
||||||
|
| Operator::F64Le
|
||||||
|
| Operator::F64Ge => Ok(vec![Type::F64, Type::F64]),
|
||||||
|
|
||||||
|
Operator::I32Clz | Operator::I32Ctz | Operator::I32Popcnt => Ok(vec![Type::I32]),
|
||||||
|
|
||||||
|
Operator::I32Add
|
||||||
|
| Operator::I32Sub
|
||||||
|
| Operator::I32Mul
|
||||||
|
| Operator::I32DivS
|
||||||
|
| Operator::I32DivU
|
||||||
|
| Operator::I32RemS
|
||||||
|
| Operator::I32RemU
|
||||||
|
| Operator::I32And
|
||||||
|
| Operator::I32Or
|
||||||
|
| Operator::I32Xor
|
||||||
|
| Operator::I32Shl
|
||||||
|
| Operator::I32ShrS
|
||||||
|
| Operator::I32ShrU
|
||||||
|
| Operator::I32Rotl
|
||||||
|
| Operator::I32Rotr => Ok(vec![Type::I32, Type::I32]),
|
||||||
|
|
||||||
|
Operator::I64Clz | Operator::I64Ctz | Operator::I64Popcnt => Ok(vec![Type::I64]),
|
||||||
|
|
||||||
|
Operator::I64Add
|
||||||
|
| Operator::I64Sub
|
||||||
|
| Operator::I64Mul
|
||||||
|
| Operator::I64DivS
|
||||||
|
| Operator::I64DivU
|
||||||
|
| Operator::I64RemS
|
||||||
|
| Operator::I64RemU
|
||||||
|
| Operator::I64And
|
||||||
|
| Operator::I64Or
|
||||||
|
| Operator::I64Xor
|
||||||
|
| Operator::I64Shl
|
||||||
|
| Operator::I64ShrS
|
||||||
|
| Operator::I64ShrU
|
||||||
|
| Operator::I64Rotl
|
||||||
|
| Operator::I64Rotr => Ok(vec![Type::I64, Type::I64]),
|
||||||
|
|
||||||
|
Operator::F32Abs
|
||||||
|
| Operator::F32Neg
|
||||||
|
| Operator::F32Ceil
|
||||||
|
| Operator::F32Floor
|
||||||
|
| Operator::F32Trunc
|
||||||
|
| Operator::F32Nearest
|
||||||
|
| Operator::F32Sqrt => Ok(vec![Type::F32]),
|
||||||
|
|
||||||
|
Operator::F32Add
|
||||||
|
| Operator::F32Sub
|
||||||
|
| Operator::F32Mul
|
||||||
|
| Operator::F32Div
|
||||||
|
| Operator::F32Min
|
||||||
|
| Operator::F32Max
|
||||||
|
| Operator::F32Copysign => Ok(vec![Type::F32, Type::F32]),
|
||||||
|
|
||||||
|
Operator::F64Abs
|
||||||
|
| Operator::F64Neg
|
||||||
|
| Operator::F64Ceil
|
||||||
|
| Operator::F64Floor
|
||||||
|
| Operator::F64Trunc
|
||||||
|
| Operator::F64Nearest
|
||||||
|
| Operator::F64Sqrt => Ok(vec![Type::F64]),
|
||||||
|
|
||||||
|
Operator::F64Add
|
||||||
|
| Operator::F64Sub
|
||||||
|
| Operator::F64Mul
|
||||||
|
| Operator::F64Div
|
||||||
|
| Operator::F64Min
|
||||||
|
| Operator::F64Max
|
||||||
|
| Operator::F64Copysign => Ok(vec![Type::F64, Type::F64]),
|
||||||
|
|
||||||
|
Operator::I32WrapI64 => Ok(vec![Type::I64]),
|
||||||
|
Operator::I32TruncF32S => Ok(vec![Type::F32]),
|
||||||
|
Operator::I32TruncF32U => Ok(vec![Type::F32]),
|
||||||
|
Operator::I32TruncF64S => Ok(vec![Type::F64]),
|
||||||
|
Operator::I32TruncF64U => Ok(vec![Type::F64]),
|
||||||
|
Operator::I64ExtendI32S => Ok(vec![Type::I32]),
|
||||||
|
Operator::I64ExtendI32U => Ok(vec![Type::I32]),
|
||||||
|
Operator::I64TruncF32S => Ok(vec![Type::F32]),
|
||||||
|
Operator::I64TruncF32U => Ok(vec![Type::F32]),
|
||||||
|
Operator::I64TruncF64S => Ok(vec![Type::F64]),
|
||||||
|
Operator::I64TruncF64U => Ok(vec![Type::F64]),
|
||||||
|
Operator::F32ConvertI32S => Ok(vec![Type::I32]),
|
||||||
|
Operator::F32ConvertI32U => Ok(vec![Type::I32]),
|
||||||
|
Operator::F32ConvertI64S => Ok(vec![Type::I64]),
|
||||||
|
Operator::F32ConvertI64U => Ok(vec![Type::I64]),
|
||||||
|
Operator::F32DemoteF64 => Ok(vec![Type::F64]),
|
||||||
|
Operator::F64ConvertI32S => Ok(vec![Type::I32]),
|
||||||
|
Operator::F64ConvertI32U => Ok(vec![Type::I32]),
|
||||||
|
Operator::F64ConvertI64S => Ok(vec![Type::I64]),
|
||||||
|
Operator::F64ConvertI64U => Ok(vec![Type::I64]),
|
||||||
|
Operator::F64PromoteF32 => Ok(vec![Type::F32]),
|
||||||
|
Operator::I32Extend8S => Ok(vec![Type::I32]),
|
||||||
|
Operator::I32Extend16S => Ok(vec![Type::I32]),
|
||||||
|
Operator::I64Extend8S => Ok(vec![Type::I64]),
|
||||||
|
Operator::I64Extend16S => Ok(vec![Type::I64]),
|
||||||
|
Operator::I64Extend32S => Ok(vec![Type::I64]),
|
||||||
|
Operator::I32TruncSatF32S => Ok(vec![Type::F32]),
|
||||||
|
Operator::I32TruncSatF32U => Ok(vec![Type::F32]),
|
||||||
|
Operator::I32TruncSatF64S => Ok(vec![Type::F64]),
|
||||||
|
Operator::I32TruncSatF64U => Ok(vec![Type::F64]),
|
||||||
|
Operator::I64TruncSatF32S => Ok(vec![Type::F32]),
|
||||||
|
Operator::I64TruncSatF32U => Ok(vec![Type::F32]),
|
||||||
|
Operator::I64TruncSatF64S => Ok(vec![Type::F64]),
|
||||||
|
Operator::I64TruncSatF64U => Ok(vec![Type::F64]),
|
||||||
|
Operator::TableGet { .. } => Ok(vec![Type::I32]),
|
||||||
|
Operator::TableSet { table } => Ok(vec![Type::I32, module.tables[*table as usize]]),
|
||||||
|
Operator::TableGrow { .. } => Ok(vec![Type::I32]),
|
||||||
|
Operator::TableSize { .. } => Ok(vec![]),
|
||||||
|
|
||||||
_ => bail!("Unknown operator in op_inputs(): {:?}", op),
|
_ => bail!("Unknown operator in op_inputs(): {:?}", op),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn op_outputs(module: &Module, my_locals: &[Type], op: &Operator<'_>) -> Result<Vec<Type>> {
|
pub fn op_outputs(
|
||||||
|
module: &Module,
|
||||||
|
my_locals: &[Type],
|
||||||
|
op_stack: &[(Type, ValueId)],
|
||||||
|
op: &Operator<'_>,
|
||||||
|
) -> Result<Vec<Type>> {
|
||||||
match op {
|
match op {
|
||||||
&Operator::Unreachable | &Operator::Nop => Ok(vec![]),
|
&Operator::Unreachable | &Operator::Nop => Ok(vec![]),
|
||||||
|
|
||||||
|
@ -51,7 +239,185 @@ pub fn op_outputs(module: &Module, my_locals: &[Type], op: &Operator<'_>) -> Res
|
||||||
&Operator::LocalSet { .. } | &Operator::LocalTee { .. } => Ok(vec![]),
|
&Operator::LocalSet { .. } | &Operator::LocalTee { .. } => Ok(vec![]),
|
||||||
&Operator::LocalGet { local_index } => Ok(vec![my_locals[local_index as usize]]),
|
&Operator::LocalGet { local_index } => Ok(vec![my_locals[local_index as usize]]),
|
||||||
|
|
||||||
&Operator::I32Eqz | &Operator::I32Eq => Ok(vec![Type::I32]),
|
&Operator::Select => {
|
||||||
|
let val_ty = op_stack[op_stack.len() - 2].0;
|
||||||
|
Ok(vec![val_ty])
|
||||||
|
}
|
||||||
|
&Operator::TypedSelect { ty } => Ok(vec![ty]),
|
||||||
|
&Operator::GlobalGet { global_index } => Ok(vec![module.globals[global_index as usize]]),
|
||||||
|
&Operator::GlobalSet { .. } => Ok(vec![]),
|
||||||
|
|
||||||
|
Operator::I32Load { .. }
|
||||||
|
| Operator::I64Load { .. }
|
||||||
|
| Operator::F32Load { .. }
|
||||||
|
| Operator::F64Load { .. }
|
||||||
|
| Operator::I32Load8S { .. }
|
||||||
|
| Operator::I32Load8U { .. }
|
||||||
|
| Operator::I32Load16S { .. }
|
||||||
|
| Operator::I32Load16U { .. } => Ok(vec![Type::I32]),
|
||||||
|
Operator::I64Load8S { .. }
|
||||||
|
| Operator::I64Load8U { .. }
|
||||||
|
| Operator::I64Load16S { .. }
|
||||||
|
| Operator::I64Load16U { .. }
|
||||||
|
| Operator::I64Load32S { .. }
|
||||||
|
| Operator::I64Load32U { .. } => Ok(vec![Type::I64]),
|
||||||
|
|
||||||
|
Operator::I32Store { .. } => Ok(vec![]),
|
||||||
|
Operator::I64Store { .. } => Ok(vec![]),
|
||||||
|
Operator::F32Store { .. } => Ok(vec![]),
|
||||||
|
Operator::F64Store { .. } => Ok(vec![]),
|
||||||
|
Operator::I32Store8 { .. } => Ok(vec![]),
|
||||||
|
Operator::I32Store16 { .. } => Ok(vec![]),
|
||||||
|
Operator::I64Store8 { .. } => Ok(vec![]),
|
||||||
|
Operator::I64Store16 { .. } => Ok(vec![]),
|
||||||
|
Operator::I64Store32 { .. } => Ok(vec![]),
|
||||||
|
|
||||||
|
Operator::I32Const { .. } => Ok(vec![Type::I32]),
|
||||||
|
Operator::I64Const { .. } => Ok(vec![Type::I64]),
|
||||||
|
Operator::F32Const { .. } => Ok(vec![Type::F32]),
|
||||||
|
Operator::F64Const { .. } => Ok(vec![Type::F64]),
|
||||||
|
|
||||||
|
Operator::I32Eqz
|
||||||
|
| Operator::I32Eq
|
||||||
|
| Operator::I32Ne
|
||||||
|
| Operator::I32LtS
|
||||||
|
| Operator::I32LtU
|
||||||
|
| Operator::I32GtS
|
||||||
|
| Operator::I32GtU
|
||||||
|
| Operator::I32LeS
|
||||||
|
| Operator::I32LeU
|
||||||
|
| Operator::I32GeS
|
||||||
|
| Operator::I32GeU
|
||||||
|
| Operator::I64Eqz
|
||||||
|
| Operator::I64Eq
|
||||||
|
| Operator::I64Ne
|
||||||
|
| Operator::I64LtS
|
||||||
|
| Operator::I64LtU
|
||||||
|
| Operator::I64GtU
|
||||||
|
| Operator::I64GtS
|
||||||
|
| Operator::I64LeS
|
||||||
|
| Operator::I64LeU
|
||||||
|
| Operator::I64GeS
|
||||||
|
| Operator::I64GeU
|
||||||
|
| Operator::F32Eq
|
||||||
|
| Operator::F32Ne
|
||||||
|
| Operator::F32Lt
|
||||||
|
| Operator::F32Gt
|
||||||
|
| Operator::F32Le
|
||||||
|
| Operator::F32Ge
|
||||||
|
| Operator::F64Eq
|
||||||
|
| Operator::F64Ne
|
||||||
|
| Operator::F64Lt
|
||||||
|
| Operator::F64Gt
|
||||||
|
| Operator::F64Le
|
||||||
|
| Operator::F64Ge => Ok(vec![Type::I32]),
|
||||||
|
|
||||||
|
Operator::I32Clz
|
||||||
|
| Operator::I32Ctz
|
||||||
|
| Operator::I32Popcnt
|
||||||
|
| Operator::I32Add
|
||||||
|
| Operator::I32Sub
|
||||||
|
| Operator::I32Mul
|
||||||
|
| Operator::I32DivS
|
||||||
|
| Operator::I32DivU
|
||||||
|
| Operator::I32RemS
|
||||||
|
| Operator::I32RemU
|
||||||
|
| Operator::I32And
|
||||||
|
| Operator::I32Or
|
||||||
|
| Operator::I32Xor
|
||||||
|
| Operator::I32Shl
|
||||||
|
| Operator::I32ShrS
|
||||||
|
| Operator::I32ShrU
|
||||||
|
| Operator::I32Rotl
|
||||||
|
| Operator::I32Rotr => Ok(vec![Type::I32]),
|
||||||
|
|
||||||
|
Operator::I64Clz
|
||||||
|
| Operator::I64Ctz
|
||||||
|
| Operator::I64Popcnt
|
||||||
|
| Operator::I64Add
|
||||||
|
| Operator::I64Sub
|
||||||
|
| Operator::I64Mul
|
||||||
|
| Operator::I64DivS
|
||||||
|
| Operator::I64DivU
|
||||||
|
| Operator::I64RemS
|
||||||
|
| Operator::I64RemU
|
||||||
|
| Operator::I64And
|
||||||
|
| Operator::I64Or
|
||||||
|
| Operator::I64Xor
|
||||||
|
| Operator::I64Shl
|
||||||
|
| Operator::I64ShrS
|
||||||
|
| Operator::I64ShrU
|
||||||
|
| Operator::I64Rotl
|
||||||
|
| Operator::I64Rotr => Ok(vec![Type::I64]),
|
||||||
|
|
||||||
|
Operator::F32Abs
|
||||||
|
| Operator::F32Neg
|
||||||
|
| Operator::F32Ceil
|
||||||
|
| Operator::F32Floor
|
||||||
|
| Operator::F32Trunc
|
||||||
|
| Operator::F32Nearest
|
||||||
|
| Operator::F32Sqrt
|
||||||
|
| Operator::F32Add
|
||||||
|
| Operator::F32Sub
|
||||||
|
| Operator::F32Mul
|
||||||
|
| Operator::F32Div
|
||||||
|
| Operator::F32Min
|
||||||
|
| Operator::F32Max
|
||||||
|
| Operator::F32Copysign => Ok(vec![Type::F32]),
|
||||||
|
|
||||||
|
Operator::F64Abs
|
||||||
|
| Operator::F64Neg
|
||||||
|
| Operator::F64Ceil
|
||||||
|
| Operator::F64Floor
|
||||||
|
| Operator::F64Trunc
|
||||||
|
| Operator::F64Nearest
|
||||||
|
| Operator::F64Sqrt
|
||||||
|
| Operator::F64Add
|
||||||
|
| Operator::F64Sub
|
||||||
|
| Operator::F64Mul
|
||||||
|
| Operator::F64Div
|
||||||
|
| Operator::F64Min
|
||||||
|
| Operator::F64Max
|
||||||
|
| Operator::F64Copysign => Ok(vec![Type::F64]),
|
||||||
|
|
||||||
|
Operator::I32WrapI64 => Ok(vec![Type::I32]),
|
||||||
|
Operator::I32TruncF32S => Ok(vec![Type::I32]),
|
||||||
|
Operator::I32TruncF32U => Ok(vec![Type::I32]),
|
||||||
|
Operator::I32TruncF64S => Ok(vec![Type::I32]),
|
||||||
|
Operator::I32TruncF64U => Ok(vec![Type::I32]),
|
||||||
|
Operator::I64ExtendI32S => Ok(vec![Type::I64]),
|
||||||
|
Operator::I64ExtendI32U => Ok(vec![Type::I64]),
|
||||||
|
Operator::I64TruncF32S => Ok(vec![Type::I64]),
|
||||||
|
Operator::I64TruncF32U => Ok(vec![Type::I64]),
|
||||||
|
Operator::I64TruncF64S => Ok(vec![Type::I64]),
|
||||||
|
Operator::I64TruncF64U => Ok(vec![Type::I64]),
|
||||||
|
Operator::F32ConvertI32S => Ok(vec![Type::F32]),
|
||||||
|
Operator::F32ConvertI32U => Ok(vec![Type::F32]),
|
||||||
|
Operator::F32ConvertI64S => Ok(vec![Type::F32]),
|
||||||
|
Operator::F32ConvertI64U => Ok(vec![Type::F32]),
|
||||||
|
Operator::F32DemoteF64 => Ok(vec![Type::F32]),
|
||||||
|
Operator::F64ConvertI32S => Ok(vec![Type::F64]),
|
||||||
|
Operator::F64ConvertI32U => Ok(vec![Type::F64]),
|
||||||
|
Operator::F64ConvertI64S => Ok(vec![Type::F64]),
|
||||||
|
Operator::F64ConvertI64U => Ok(vec![Type::F64]),
|
||||||
|
Operator::F64PromoteF32 => Ok(vec![Type::F64]),
|
||||||
|
Operator::I32Extend8S => Ok(vec![Type::I32]),
|
||||||
|
Operator::I32Extend16S => Ok(vec![Type::I32]),
|
||||||
|
Operator::I64Extend8S => Ok(vec![Type::I64]),
|
||||||
|
Operator::I64Extend16S => Ok(vec![Type::I64]),
|
||||||
|
Operator::I64Extend32S => Ok(vec![Type::I64]),
|
||||||
|
Operator::I32TruncSatF32S => Ok(vec![Type::I32]),
|
||||||
|
Operator::I32TruncSatF32U => Ok(vec![Type::I32]),
|
||||||
|
Operator::I32TruncSatF64S => Ok(vec![Type::I32]),
|
||||||
|
Operator::I32TruncSatF64U => Ok(vec![Type::I32]),
|
||||||
|
Operator::I64TruncSatF32S => Ok(vec![Type::I64]),
|
||||||
|
Operator::I64TruncSatF32U => Ok(vec![Type::I64]),
|
||||||
|
Operator::I64TruncSatF64S => Ok(vec![Type::I64]),
|
||||||
|
Operator::I64TruncSatF64U => Ok(vec![Type::I64]),
|
||||||
|
Operator::TableGet { table } => Ok(vec![module.tables[*table as usize]]),
|
||||||
|
Operator::TableSet { .. } => Ok(vec![]),
|
||||||
|
Operator::TableGrow { .. } => Ok(vec![]),
|
||||||
|
Operator::TableSize { .. } => Ok(vec![Type::I32]),
|
||||||
|
|
||||||
_ => bail!("Unknown operator in op_outputs(): {:?}", op),
|
_ => bail!("Unknown operator in op_outputs(): {:?}", op),
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue