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) => {
|
||||
for _ in 0..reader.get_count() {
|
||||
if let ImportSectionEntryType::Function(sig_idx) = reader.read()?.ty {
|
||||
module.funcs.push(FuncDecl::Import(sig_idx as SignatureId));
|
||||
*next_func += 1;
|
||||
match reader.read()?.ty {
|
||||
ImportSectionEntryType::Function(sig_idx) => {
|
||||
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) => {
|
||||
for _ in 0..reader.get_count() {
|
||||
let sig_idx = reader.read()? as SignatureId;
|
||||
|
@ -104,7 +125,7 @@ struct FunctionBodyBuilder<'a, 'b> {
|
|||
body: &'b mut FunctionBody<'a>,
|
||||
cur_block: Option<BlockId>,
|
||||
ctrl_stack: Vec<Frame>,
|
||||
op_stack: Vec<ValueId>,
|
||||
op_stack: Vec<(Type, ValueId)>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
|
@ -126,7 +147,7 @@ enum Frame {
|
|||
start_depth: usize,
|
||||
out: BlockId,
|
||||
el: BlockId,
|
||||
param_values: Vec<ValueId>,
|
||||
param_values: Vec<(Type, ValueId)>,
|
||||
params: Vec<Type>,
|
||||
results: Vec<Type>,
|
||||
},
|
||||
|
@ -183,6 +204,18 @@ impl<'a, 'b> FunctionBodyBuilder<'a, 'b> {
|
|||
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<()> {
|
||||
match &op {
|
||||
Operator::Unreachable
|
||||
|
@ -364,7 +397,7 @@ impl<'a, 'b> FunctionBodyBuilder<'a, 'b> {
|
|||
Operator::Nop => {}
|
||||
|
||||
Operator::Drop => {
|
||||
self.op_stack.pop().unwrap();
|
||||
let _ = self.pop_1();
|
||||
}
|
||||
|
||||
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
|
||||
// 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[..]);
|
||||
assert_eq!(self.op_stack.len(), start_depth);
|
||||
self.cur_block = Some(out);
|
||||
|
@ -401,13 +434,17 @@ impl<'a, 'b> FunctionBodyBuilder<'a, 'b> {
|
|||
}) => {
|
||||
// Generate a branch to the out-block with
|
||||
// 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[..]);
|
||||
// No `else`, so we need to generate a trivial
|
||||
// branch in the else-block. If the if-block-type
|
||||
// has results, they must be exactly the params.
|
||||
let else_result_values = param_values;
|
||||
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[..]);
|
||||
assert_eq!(self.op_stack.len(), start_depth);
|
||||
self.cur_block = Some(out);
|
||||
|
@ -421,7 +458,7 @@ impl<'a, 'b> FunctionBodyBuilder<'a, 'b> {
|
|||
}) => {
|
||||
// Generate a branch to the out-block with
|
||||
// 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);
|
||||
self.emit_branch(out, &result_values[..]);
|
||||
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 header = self.create_block();
|
||||
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();
|
||||
self.emit_branch(header, &initial_args[..]);
|
||||
self.cur_block = Some(header);
|
||||
|
@ -467,7 +504,7 @@ impl<'a, 'b> FunctionBodyBuilder<'a, 'b> {
|
|||
let if_false = self.create_block();
|
||||
let join = self.create_block();
|
||||
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 start_depth = self.op_stack.len();
|
||||
self.ctrl_stack.push(Frame::If {
|
||||
|
@ -492,7 +529,7 @@ impl<'a, 'b> FunctionBodyBuilder<'a, 'b> {
|
|||
results,
|
||||
} = 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.op_stack.extend(param_values);
|
||||
self.ctrl_stack.push(Frame::Else {
|
||||
|
@ -510,13 +547,13 @@ impl<'a, 'b> FunctionBodyBuilder<'a, 'b> {
|
|||
Operator::Br { relative_depth } | Operator::BrIf { relative_depth } => {
|
||||
let cond = match &op {
|
||||
Operator::Br { .. } => None,
|
||||
Operator::BrIf { .. } => Some(self.op_stack.pop().unwrap()),
|
||||
Operator::BrIf { .. } => Some(self.pop_1()),
|
||||
_ => unreachable!(),
|
||||
};
|
||||
// Get the frame we're branching to.
|
||||
let frame = self.relative_frame(*relative_depth).clone();
|
||||
// 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.
|
||||
match cond {
|
||||
None => {
|
||||
|
@ -533,14 +570,14 @@ impl<'a, 'b> FunctionBodyBuilder<'a, 'b> {
|
|||
|
||||
Operator::BrTable { table } => {
|
||||
// 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
|
||||
// us the signature of all frames (since wasmparser
|
||||
// validates the input for us). Pop that many args.
|
||||
let default_frame = self.relative_frame(table.default());
|
||||
let default_term_target = default_frame.br_target();
|
||||
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
|
||||
// every branch target.
|
||||
let mut term_targets = vec![];
|
||||
|
@ -556,9 +593,7 @@ impl<'a, 'b> FunctionBodyBuilder<'a, 'b> {
|
|||
}
|
||||
|
||||
Operator::Return => {
|
||||
let retvals = self
|
||||
.op_stack
|
||||
.split_off(self.module.signatures[self.my_sig].returns.len());
|
||||
let retvals = self.pop_n(self.module.signatures[self.my_sig].returns.len());
|
||||
self.emit_ret(&retvals[..]);
|
||||
self.cur_block = None;
|
||||
}
|
||||
|
@ -677,7 +712,7 @@ impl<'a, 'b> FunctionBodyBuilder<'a, 'b> {
|
|||
kind: ValueKind::BlockParam(self.cur_block.unwrap(), i),
|
||||
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 mut inputs = vec![];
|
||||
for input in op_inputs(self.module, self.my_sig, &self.body.locals[..], &op)?
|
||||
.into_iter()
|
||||
.rev()
|
||||
for input in op_inputs(
|
||||
self.module,
|
||||
self.my_sig,
|
||||
&self.body.locals[..],
|
||||
&self.op_stack[..],
|
||||
&op,
|
||||
)?
|
||||
.into_iter()
|
||||
.rev()
|
||||
{
|
||||
let stack_top = self.op_stack.pop().unwrap();
|
||||
assert_eq!(self.body.values[stack_top].ty, input);
|
||||
let (stack_top_ty, stack_top) = self.op_stack.pop().unwrap();
|
||||
assert_eq!(stack_top_ty, input);
|
||||
inputs.push(Operand::value(stack_top));
|
||||
}
|
||||
inputs.reverse();
|
||||
|
||||
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;
|
||||
outputs.push(val);
|
||||
self.body.values.push(ValueDef {
|
||||
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 {
|
||||
|
@ -713,11 +756,18 @@ impl<'a, 'b> FunctionBodyBuilder<'a, 'b> {
|
|||
inputs,
|
||||
});
|
||||
} else {
|
||||
let _ = self
|
||||
.op_stack
|
||||
.split_off(op_inputs(self.module, self.my_sig, &self.body.locals[..], &op)?.len());
|
||||
for _ in 0..op_outputs(self.module, &self.body.locals[..], &op)?.len() {
|
||||
self.op_stack.push(NO_VALUE);
|
||||
let _ = self.pop_n(
|
||||
op_inputs(
|
||||
self.module,
|
||||
self.my_sig,
|
||||
&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 funcs: Vec<FuncDecl<'a>>,
|
||||
pub signatures: Vec<FuncType>,
|
||||
pub globals: Vec<Type>,
|
||||
pub tables: Vec<Type>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
|
|
376
src/op_traits.rs
376
src/op_traits.rs
|
@ -1,6 +1,6 @@
|
|||
//! Metadata on operators.
|
||||
|
||||
use crate::ir::{Module, SignatureId};
|
||||
use crate::ir::{Module, SignatureId, ValueId};
|
||||
use anyhow::{bail, Result};
|
||||
use wasmparser::{Operator, Type};
|
||||
|
||||
|
@ -8,6 +8,7 @@ pub fn op_inputs(
|
|||
module: &Module,
|
||||
my_sig: SignatureId,
|
||||
my_locals: &[Type],
|
||||
op_stack: &[(Type, ValueId)],
|
||||
op: &Operator<'_>,
|
||||
) -> Result<Vec<Type>> {
|
||||
match op {
|
||||
|
@ -29,14 +30,201 @@ pub fn op_inputs(
|
|||
}
|
||||
&Operator::LocalGet { .. } => Ok(vec![]),
|
||||
|
||||
&Operator::I32Eqz => Ok(vec![Type::I32]),
|
||||
&Operator::I32Eq => Ok(vec![Type::I32, Type::I32]),
|
||||
&Operator::Select => {
|
||||
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),
|
||||
}
|
||||
}
|
||||
|
||||
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 {
|
||||
&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::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),
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue