Seems to be fuzz-clean in wasm-to-IR step now; complete for Wasm-MVP
This commit is contained in:
parent
d8a4340743
commit
0eb41cb0a3
271
src/frontend.rs
271
src/frontend.rs
|
@ -100,6 +100,11 @@ fn parse_body<'a, 'b>(
|
|||
body: wasmparser::FunctionBody<'a>,
|
||||
) -> Result<FunctionBody<'a>> {
|
||||
let mut ret: FunctionBody<'a> = FunctionBody::default();
|
||||
|
||||
for ¶m in &module.signatures[my_sig].params[..] {
|
||||
ret.locals.push(param);
|
||||
}
|
||||
|
||||
let mut locals = body.get_locals_reader()?;
|
||||
for _ in 0..locals.get_count() {
|
||||
let (count, ty) = locals.read()?;
|
||||
|
@ -197,6 +202,15 @@ impl Frame {
|
|||
Frame::If { out, .. } | Frame::Else { out, .. } => *out,
|
||||
}
|
||||
}
|
||||
|
||||
fn out(&self) -> BlockId {
|
||||
match self {
|
||||
Frame::Block { out, .. }
|
||||
| Frame::Loop { out, .. }
|
||||
| Frame::If { out, .. }
|
||||
| Frame::Else { out, .. } => *out,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 'b> FunctionBodyBuilder<'a, 'b> {
|
||||
|
@ -212,13 +226,13 @@ impl<'a, 'b> FunctionBodyBuilder<'a, 'b> {
|
|||
};
|
||||
|
||||
// Push initial implicit Block.
|
||||
let params = module.signatures[my_sig].params.to_vec();
|
||||
let results = module.signatures[my_sig].params.to_vec();
|
||||
let results = module.signatures[my_sig].returns.to_vec();
|
||||
let out = ret.create_block();
|
||||
ret.add_block_params(out, &results[..]);
|
||||
ret.ctrl_stack.push(Frame::Block {
|
||||
start_depth: 0,
|
||||
out,
|
||||
params,
|
||||
params: vec![],
|
||||
results,
|
||||
});
|
||||
ret
|
||||
|
@ -229,11 +243,13 @@ impl<'a, 'b> FunctionBodyBuilder<'a, 'b> {
|
|||
}
|
||||
|
||||
fn pop_n(&mut self, n: usize) -> Vec<ValueId> {
|
||||
self.op_stack
|
||||
.split_off(n)
|
||||
.into_iter()
|
||||
.map(|(_ty, value)| value)
|
||||
.collect()
|
||||
let new_top = self.op_stack.len() - n;
|
||||
let ret = self.op_stack[new_top..]
|
||||
.iter()
|
||||
.map(|(_ty, value)| *value)
|
||||
.collect::<Vec<_>>();
|
||||
self.op_stack.truncate(new_top);
|
||||
ret
|
||||
}
|
||||
|
||||
fn pop_1(&mut self) -> ValueId {
|
||||
|
@ -242,9 +258,17 @@ impl<'a, 'b> FunctionBodyBuilder<'a, 'b> {
|
|||
|
||||
fn handle_op(&mut self, op: Operator<'a>) -> Result<()> {
|
||||
trace!("handle_op: {:?}", op);
|
||||
trace!("op_stack = {:?}", self.op_stack);
|
||||
trace!("ctrl_stack = {:?}", self.ctrl_stack);
|
||||
match &op {
|
||||
Operator::Unreachable
|
||||
| Operator::LocalGet { .. }
|
||||
Operator::Unreachable => {
|
||||
if let Some(block) = self.cur_block {
|
||||
self.body.blocks[block].terminator = Terminator::None;
|
||||
}
|
||||
self.cur_block = None;
|
||||
}
|
||||
|
||||
Operator::LocalGet { .. }
|
||||
| Operator::LocalSet { .. }
|
||||
| Operator::LocalTee { .. }
|
||||
| Operator::Call { .. }
|
||||
|
@ -414,6 +438,10 @@ impl<'a, 'b> FunctionBodyBuilder<'a, 'b> {
|
|||
| Operator::I64TruncSatF32U
|
||||
| Operator::I64TruncSatF64S
|
||||
| Operator::I64TruncSatF64U
|
||||
| Operator::F32ReinterpretI32
|
||||
| Operator::F64ReinterpretI64
|
||||
| Operator::I32ReinterpretF32
|
||||
| Operator::I64ReinterpretF64
|
||||
| Operator::TableGet { .. }
|
||||
| Operator::TableSet { .. }
|
||||
| Operator::TableGrow { .. }
|
||||
|
@ -425,71 +453,88 @@ impl<'a, 'b> FunctionBodyBuilder<'a, 'b> {
|
|||
let _ = self.pop_1();
|
||||
}
|
||||
|
||||
Operator::End => match self.ctrl_stack.pop() {
|
||||
None => {
|
||||
self.emit(Operator::Return)?;
|
||||
Operator::End if self.cur_block.is_none() => {
|
||||
let frame = self.ctrl_stack.pop().unwrap();
|
||||
self.op_stack.truncate(frame.start_depth());
|
||||
self.cur_block = Some(frame.out());
|
||||
self.push_block_params();
|
||||
}
|
||||
|
||||
Operator::End => {
|
||||
let frame = self.ctrl_stack.pop();
|
||||
match frame {
|
||||
None => {
|
||||
self.emit(Operator::Return)?;
|
||||
}
|
||||
Some(Frame::Block {
|
||||
start_depth,
|
||||
out,
|
||||
results,
|
||||
..
|
||||
})
|
||||
| Some(Frame::Loop {
|
||||
start_depth,
|
||||
out,
|
||||
results,
|
||||
..
|
||||
}) => {
|
||||
// Generate a branch to the out-block with
|
||||
// blockparams for the results.
|
||||
if self.cur_block.is_some() {
|
||||
let result_values = self.pop_n(results.len());
|
||||
self.emit_branch(out, &result_values[..]);
|
||||
}
|
||||
self.op_stack.truncate(start_depth);
|
||||
self.cur_block = Some(out);
|
||||
self.push_block_params();
|
||||
}
|
||||
Some(Frame::If {
|
||||
start_depth,
|
||||
out,
|
||||
el,
|
||||
param_values,
|
||||
results,
|
||||
..
|
||||
}) => {
|
||||
// Generate a branch to the out-block with
|
||||
// blockparams for the results.
|
||||
if self.cur_block.is_some() {
|
||||
let result_values = self.pop_n(results.len());
|
||||
self.emit_branch(out, &result_values[..]);
|
||||
}
|
||||
self.op_stack.truncate(start_depth);
|
||||
// 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);
|
||||
self.push_block_params();
|
||||
}
|
||||
Some(Frame::Else {
|
||||
out,
|
||||
results,
|
||||
start_depth,
|
||||
..
|
||||
}) => {
|
||||
// Generate a branch to the out-block with
|
||||
// blockparams for the results.
|
||||
if self.cur_block.is_some() {
|
||||
let result_values = self.pop_n(results.len());
|
||||
self.emit_branch(out, &result_values[..]);
|
||||
}
|
||||
self.op_stack.truncate(start_depth);
|
||||
self.cur_block = Some(out);
|
||||
self.push_block_params();
|
||||
}
|
||||
}
|
||||
Some(Frame::Block {
|
||||
start_depth,
|
||||
out,
|
||||
results,
|
||||
..
|
||||
})
|
||||
| Some(Frame::Loop {
|
||||
start_depth,
|
||||
out,
|
||||
results,
|
||||
..
|
||||
}) => {
|
||||
// Generate a branch to the out-block with
|
||||
// blockparams for the results.
|
||||
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);
|
||||
self.push_block_params(&results[..]);
|
||||
}
|
||||
Some(Frame::If {
|
||||
start_depth,
|
||||
out,
|
||||
el,
|
||||
param_values,
|
||||
results,
|
||||
..
|
||||
}) => {
|
||||
// Generate a branch to the out-block with
|
||||
// blockparams for the results.
|
||||
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);
|
||||
self.push_block_params(&results[..]);
|
||||
}
|
||||
Some(Frame::Else {
|
||||
out,
|
||||
results,
|
||||
start_depth,
|
||||
..
|
||||
}) => {
|
||||
// Generate a branch to the out-block with
|
||||
// blockparams for the results.
|
||||
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);
|
||||
self.push_block_params(&results[..]);
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
Operator::Block { ty } => {
|
||||
let (params, results) = self.block_params_and_results(*ty);
|
||||
|
@ -512,8 +557,9 @@ impl<'a, 'b> FunctionBodyBuilder<'a, 'b> {
|
|||
let start_depth = self.op_stack.len();
|
||||
self.emit_branch(header, &initial_args[..]);
|
||||
self.cur_block = Some(header);
|
||||
self.push_block_params(¶ms[..]);
|
||||
self.push_block_params();
|
||||
let out = self.create_block();
|
||||
self.add_block_params(out, &results[..]);
|
||||
self.ctrl_stack.push(Frame::Loop {
|
||||
start_depth,
|
||||
header,
|
||||
|
@ -531,7 +577,7 @@ impl<'a, 'b> FunctionBodyBuilder<'a, 'b> {
|
|||
self.add_block_params(join, &results[..]);
|
||||
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();
|
||||
let start_depth = self.op_stack.len() - params.len();
|
||||
self.ctrl_stack.push(Frame::If {
|
||||
start_depth,
|
||||
out: join,
|
||||
|
@ -554,8 +600,11 @@ impl<'a, 'b> FunctionBodyBuilder<'a, 'b> {
|
|||
results,
|
||||
} = self.ctrl_stack.pop().unwrap()
|
||||
{
|
||||
let if_results = self.pop_n(results.len());
|
||||
self.emit_branch(out, &if_results[..]);
|
||||
if self.cur_block.is_some() {
|
||||
let if_results = self.pop_n(results.len());
|
||||
self.emit_branch(out, &if_results[..]);
|
||||
}
|
||||
self.op_stack.truncate(start_depth);
|
||||
self.op_stack.extend(param_values);
|
||||
self.ctrl_stack.push(Frame::Else {
|
||||
start_depth,
|
||||
|
@ -577,16 +626,21 @@ impl<'a, 'b> FunctionBodyBuilder<'a, 'b> {
|
|||
};
|
||||
// Get the frame we're branching to.
|
||||
let frame = self.relative_frame(*relative_depth).clone();
|
||||
// Get the args off the stack.
|
||||
let args = self.pop_n(frame.br_args().len());
|
||||
// Finally, generate the branch itself.
|
||||
match cond {
|
||||
None => {
|
||||
// Get the args off the stack unconditionally.
|
||||
let args = self.pop_n(frame.br_args().len());
|
||||
self.emit_branch(frame.br_target(), &args[..]);
|
||||
self.cur_block = None;
|
||||
}
|
||||
Some(cond) => {
|
||||
let cont = self.create_block();
|
||||
// Get the args off the stack but leave for the fallthrough.
|
||||
let args = self.op_stack[self.op_stack.len() - frame.br_args().len()..]
|
||||
.iter()
|
||||
.map(|(_ty, value)| *value)
|
||||
.collect::<Vec<_>>();
|
||||
self.emit_cond_branch(cond, frame.br_target(), &args[..], cont, &[]);
|
||||
self.cur_block = Some(cont);
|
||||
}
|
||||
|
@ -637,6 +691,7 @@ impl<'a, 'b> FunctionBodyBuilder<'a, 'b> {
|
|||
|
||||
fn block_params_and_results(&self, ty: TypeOrFuncType) -> (Vec<Type>, Vec<Type>) {
|
||||
match ty {
|
||||
TypeOrFuncType::Type(Type::EmptyBlockType) => (vec![], vec![]),
|
||||
TypeOrFuncType::Type(ret_ty) => (vec![], vec![ret_ty]),
|
||||
TypeOrFuncType::FuncType(sig_idx) => {
|
||||
let sig = &self.module.signatures[sig_idx as SignatureId];
|
||||
|
@ -729,8 +784,9 @@ impl<'a, 'b> FunctionBodyBuilder<'a, 'b> {
|
|||
}
|
||||
}
|
||||
|
||||
fn push_block_params(&mut self, tys: &[Type]) {
|
||||
assert_eq!(tys, self.body.blocks[self.cur_block.unwrap()].params);
|
||||
fn push_block_params(&mut self) {
|
||||
let tys = &self.body.blocks[self.cur_block.unwrap()].params[..];
|
||||
|
||||
for (i, &ty) in tys.iter().enumerate() {
|
||||
let value_id = self.body.values.len() as ValueId;
|
||||
self.body.values.push(ValueDef {
|
||||
|
@ -742,32 +798,30 @@ impl<'a, 'b> FunctionBodyBuilder<'a, 'b> {
|
|||
}
|
||||
|
||||
fn emit(&mut self, op: Operator<'a>) -> Result<()> {
|
||||
let inputs = op_inputs(
|
||||
self.module,
|
||||
self.my_sig,
|
||||
&self.body.locals[..],
|
||||
&self.op_stack[..],
|
||||
&op,
|
||||
)?;
|
||||
let outputs = op_outputs(self.module, &self.body.locals[..], &self.op_stack[..], &op)?;
|
||||
|
||||
if let Some(block) = self.cur_block {
|
||||
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[..],
|
||||
&self.op_stack[..],
|
||||
&op,
|
||||
)?
|
||||
.into_iter()
|
||||
.rev()
|
||||
{
|
||||
let mut input_operands = vec![];
|
||||
for input in inputs.into_iter().rev() {
|
||||
let (stack_top_ty, stack_top) = self.op_stack.pop().unwrap();
|
||||
assert_eq!(stack_top_ty, input);
|
||||
inputs.push(Operand::value(stack_top));
|
||||
input_operands.push(Operand::value(stack_top));
|
||||
}
|
||||
inputs.reverse();
|
||||
input_operands.reverse();
|
||||
|
||||
let mut outputs = vec![];
|
||||
for output_ty in
|
||||
op_outputs(self.module, &self.body.locals[..], &self.op_stack[..], &op)?.into_iter()
|
||||
{
|
||||
let mut output_operands = vec![];
|
||||
for output_ty in outputs.into_iter() {
|
||||
let val = self.body.values.len() as ValueId;
|
||||
outputs.push(val);
|
||||
output_operands.push(val);
|
||||
self.body.values.push(ValueDef {
|
||||
kind: ValueKind::Inst(block, inst),
|
||||
ty: output_ty,
|
||||
|
@ -777,21 +831,12 @@ impl<'a, 'b> FunctionBodyBuilder<'a, 'b> {
|
|||
|
||||
self.body.blocks[block].insts.push(Inst {
|
||||
operator: op,
|
||||
outputs,
|
||||
inputs,
|
||||
outputs: output_operands,
|
||||
inputs: input_operands,
|
||||
});
|
||||
} else {
|
||||
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)? {
|
||||
let _ = self.pop_n(inputs.len());
|
||||
for ty in outputs {
|
||||
self.op_stack.push((ty, NO_VALUE));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,8 +19,8 @@ pub fn op_inputs(
|
|||
Ok(Vec::from(module.signatures[sig].params.clone()))
|
||||
}
|
||||
&Operator::CallIndirect { index, .. } => {
|
||||
let mut params = vec![Type::I32];
|
||||
params.extend_from_slice(&module.signatures[index as usize].params[..]);
|
||||
let mut params = module.signatures[index as usize].params.to_vec();
|
||||
params.push(Type::I32);
|
||||
Ok(params)
|
||||
}
|
||||
&Operator::Return => Ok(Vec::from(module.signatures[my_sig].returns.clone())),
|
||||
|
@ -210,10 +210,16 @@ pub fn op_inputs(
|
|||
Operator::I64TruncSatF32U => Ok(vec![Type::F32]),
|
||||
Operator::I64TruncSatF64S => Ok(vec![Type::F64]),
|
||||
Operator::I64TruncSatF64U => Ok(vec![Type::F64]),
|
||||
Operator::F32ReinterpretI32 => Ok(vec![Type::I32]),
|
||||
Operator::F64ReinterpretI64 => Ok(vec![Type::I64]),
|
||||
Operator::I32ReinterpretF32 => Ok(vec![Type::F32]),
|
||||
Operator::I64ReinterpretF64 => 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![]),
|
||||
Operator::MemorySize { .. } => Ok(vec![]),
|
||||
Operator::MemoryGrow { .. } => Ok(vec![Type::I32]),
|
||||
|
||||
_ => bail!("Unknown operator in op_inputs(): {:?}", op),
|
||||
}
|
||||
|
@ -236,8 +242,10 @@ pub fn op_outputs(
|
|||
Ok(Vec::from(module.signatures[index as usize].returns.clone()))
|
||||
}
|
||||
&Operator::Return => Ok(vec![]),
|
||||
&Operator::LocalSet { .. } | &Operator::LocalTee { .. } => Ok(vec![]),
|
||||
&Operator::LocalGet { local_index } => Ok(vec![my_locals[local_index as usize]]),
|
||||
&Operator::LocalSet { .. } => Ok(vec![]),
|
||||
&Operator::LocalGet { local_index } | &Operator::LocalTee { local_index } => {
|
||||
Ok(vec![my_locals[local_index as usize]])
|
||||
}
|
||||
|
||||
&Operator::Select => {
|
||||
let val_ty = op_stack[op_stack.len() - 2].0;
|
||||
|
@ -248,19 +256,19 @@ pub fn op_outputs(
|
|||
&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::I64Load { .. }
|
||||
| Operator::I64Load8S { .. }
|
||||
| Operator::I64Load8U { .. }
|
||||
| Operator::I64Load16S { .. }
|
||||
| Operator::I64Load16U { .. }
|
||||
| Operator::I64Load32S { .. }
|
||||
| Operator::I64Load32U { .. } => Ok(vec![Type::I64]),
|
||||
Operator::F32Load { .. } => Ok(vec![Type::F32]),
|
||||
Operator::F64Load { .. } => Ok(vec![Type::F64]),
|
||||
|
||||
Operator::I32Store { .. } => Ok(vec![]),
|
||||
Operator::I64Store { .. } => Ok(vec![]),
|
||||
|
@ -414,10 +422,16 @@ pub fn op_outputs(
|
|||
Operator::I64TruncSatF32U => Ok(vec![Type::I64]),
|
||||
Operator::I64TruncSatF64S => Ok(vec![Type::I64]),
|
||||
Operator::I64TruncSatF64U => Ok(vec![Type::I64]),
|
||||
Operator::F32ReinterpretI32 => Ok(vec![Type::F32]),
|
||||
Operator::F64ReinterpretI64 => Ok(vec![Type::F64]),
|
||||
Operator::I32ReinterpretF32 => Ok(vec![Type::I32]),
|
||||
Operator::I64ReinterpretF64 => 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]),
|
||||
Operator::MemorySize { .. } => Ok(vec![Type::I32]),
|
||||
Operator::MemoryGrow { .. } => Ok(vec![Type::I32]),
|
||||
|
||||
_ => bail!("Unknown operator in op_outputs(): {:?}", op),
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue