Seems to be fuzz-clean in wasm-to-IR step now; complete for Wasm-MVP

This commit is contained in:
Chris Fallin 2021-11-13 17:47:33 -08:00
parent d8a4340743
commit 0eb41cb0a3
2 changed files with 180 additions and 121 deletions

View file

@ -100,6 +100,11 @@ fn parse_body<'a, 'b>(
body: wasmparser::FunctionBody<'a>, body: wasmparser::FunctionBody<'a>,
) -> Result<FunctionBody<'a>> { ) -> Result<FunctionBody<'a>> {
let mut ret: FunctionBody<'a> = FunctionBody::default(); let mut ret: FunctionBody<'a> = FunctionBody::default();
for &param in &module.signatures[my_sig].params[..] {
ret.locals.push(param);
}
let mut locals = body.get_locals_reader()?; let mut locals = body.get_locals_reader()?;
for _ in 0..locals.get_count() { for _ in 0..locals.get_count() {
let (count, ty) = locals.read()?; let (count, ty) = locals.read()?;
@ -197,6 +202,15 @@ impl Frame {
Frame::If { out, .. } | Frame::Else { out, .. } => *out, 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> { impl<'a, 'b> FunctionBodyBuilder<'a, 'b> {
@ -212,13 +226,13 @@ impl<'a, 'b> FunctionBodyBuilder<'a, 'b> {
}; };
// Push initial implicit Block. // Push initial implicit Block.
let params = module.signatures[my_sig].params.to_vec(); let results = module.signatures[my_sig].returns.to_vec();
let results = module.signatures[my_sig].params.to_vec();
let out = ret.create_block(); let out = ret.create_block();
ret.add_block_params(out, &results[..]);
ret.ctrl_stack.push(Frame::Block { ret.ctrl_stack.push(Frame::Block {
start_depth: 0, start_depth: 0,
out, out,
params, params: vec![],
results, results,
}); });
ret ret
@ -229,11 +243,13 @@ impl<'a, 'b> FunctionBodyBuilder<'a, 'b> {
} }
fn pop_n(&mut self, n: usize) -> Vec<ValueId> { fn pop_n(&mut self, n: usize) -> Vec<ValueId> {
self.op_stack let new_top = self.op_stack.len() - n;
.split_off(n) let ret = self.op_stack[new_top..]
.into_iter() .iter()
.map(|(_ty, value)| value) .map(|(_ty, value)| *value)
.collect() .collect::<Vec<_>>();
self.op_stack.truncate(new_top);
ret
} }
fn pop_1(&mut self) -> ValueId { 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<()> { fn handle_op(&mut self, op: Operator<'a>) -> Result<()> {
trace!("handle_op: {:?}", op); trace!("handle_op: {:?}", op);
trace!("op_stack = {:?}", self.op_stack);
trace!("ctrl_stack = {:?}", self.ctrl_stack);
match &op { match &op {
Operator::Unreachable Operator::Unreachable => {
| Operator::LocalGet { .. } if let Some(block) = self.cur_block {
self.body.blocks[block].terminator = Terminator::None;
}
self.cur_block = None;
}
Operator::LocalGet { .. }
| Operator::LocalSet { .. } | Operator::LocalSet { .. }
| Operator::LocalTee { .. } | Operator::LocalTee { .. }
| Operator::Call { .. } | Operator::Call { .. }
@ -414,6 +438,10 @@ impl<'a, 'b> FunctionBodyBuilder<'a, 'b> {
| Operator::I64TruncSatF32U | Operator::I64TruncSatF32U
| Operator::I64TruncSatF64S | Operator::I64TruncSatF64S
| Operator::I64TruncSatF64U | Operator::I64TruncSatF64U
| Operator::F32ReinterpretI32
| Operator::F64ReinterpretI64
| Operator::I32ReinterpretF32
| Operator::I64ReinterpretF64
| Operator::TableGet { .. } | Operator::TableGet { .. }
| Operator::TableSet { .. } | Operator::TableSet { .. }
| Operator::TableGrow { .. } | Operator::TableGrow { .. }
@ -425,71 +453,88 @@ impl<'a, 'b> FunctionBodyBuilder<'a, 'b> {
let _ = self.pop_1(); let _ = self.pop_1();
} }
Operator::End => match self.ctrl_stack.pop() { Operator::End if self.cur_block.is_none() => {
None => { let frame = self.ctrl_stack.pop().unwrap();
self.emit(Operator::Return)?; 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 } => { Operator::Block { ty } => {
let (params, results) = self.block_params_and_results(*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(); 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);
self.push_block_params(&params[..]); self.push_block_params();
let out = self.create_block(); let out = self.create_block();
self.add_block_params(out, &results[..]);
self.ctrl_stack.push(Frame::Loop { self.ctrl_stack.push(Frame::Loop {
start_depth, start_depth,
header, header,
@ -531,7 +577,7 @@ impl<'a, 'b> FunctionBodyBuilder<'a, 'b> {
self.add_block_params(join, &results[..]); self.add_block_params(join, &results[..]);
let cond = self.pop_1(); 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() - params.len();
self.ctrl_stack.push(Frame::If { self.ctrl_stack.push(Frame::If {
start_depth, start_depth,
out: join, out: join,
@ -554,8 +600,11 @@ impl<'a, 'b> FunctionBodyBuilder<'a, 'b> {
results, results,
} = self.ctrl_stack.pop().unwrap() } = self.ctrl_stack.pop().unwrap()
{ {
let if_results = self.pop_n(results.len()); if self.cur_block.is_some() {
self.emit_branch(out, &if_results[..]); 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.op_stack.extend(param_values);
self.ctrl_stack.push(Frame::Else { self.ctrl_stack.push(Frame::Else {
start_depth, start_depth,
@ -577,16 +626,21 @@ impl<'a, 'b> FunctionBodyBuilder<'a, 'b> {
}; };
// 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.
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 => {
// Get the args off the stack unconditionally.
let args = self.pop_n(frame.br_args().len());
self.emit_branch(frame.br_target(), &args[..]); self.emit_branch(frame.br_target(), &args[..]);
self.cur_block = None; self.cur_block = None;
} }
Some(cond) => { Some(cond) => {
let cont = self.create_block(); 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.emit_cond_branch(cond, frame.br_target(), &args[..], cont, &[]);
self.cur_block = Some(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>) { fn block_params_and_results(&self, ty: TypeOrFuncType) -> (Vec<Type>, Vec<Type>) {
match ty { match ty {
TypeOrFuncType::Type(Type::EmptyBlockType) => (vec![], vec![]),
TypeOrFuncType::Type(ret_ty) => (vec![], vec![ret_ty]), TypeOrFuncType::Type(ret_ty) => (vec![], vec![ret_ty]),
TypeOrFuncType::FuncType(sig_idx) => { TypeOrFuncType::FuncType(sig_idx) => {
let sig = &self.module.signatures[sig_idx as SignatureId]; 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]) { fn push_block_params(&mut self) {
assert_eq!(tys, self.body.blocks[self.cur_block.unwrap()].params); let tys = &self.body.blocks[self.cur_block.unwrap()].params[..];
for (i, &ty) in tys.iter().enumerate() { for (i, &ty) in tys.iter().enumerate() {
let value_id = self.body.values.len() as ValueId; let value_id = self.body.values.len() as ValueId;
self.body.values.push(ValueDef { self.body.values.push(ValueDef {
@ -742,32 +798,30 @@ impl<'a, 'b> FunctionBodyBuilder<'a, 'b> {
} }
fn emit(&mut self, op: Operator<'a>) -> Result<()> { 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 { if let Some(block) = self.cur_block {
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 input_operands = vec![];
for input in op_inputs( for input in inputs.into_iter().rev() {
self.module,
self.my_sig,
&self.body.locals[..],
&self.op_stack[..],
&op,
)?
.into_iter()
.rev()
{
let (stack_top_ty, stack_top) = self.op_stack.pop().unwrap(); let (stack_top_ty, stack_top) = self.op_stack.pop().unwrap();
assert_eq!(stack_top_ty, input); 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![]; let mut output_operands = vec![];
for output_ty in for output_ty in outputs.into_iter() {
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); output_operands.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, ty: output_ty,
@ -777,21 +831,12 @@ impl<'a, 'b> FunctionBodyBuilder<'a, 'b> {
self.body.blocks[block].insts.push(Inst { self.body.blocks[block].insts.push(Inst {
operator: op, operator: op,
outputs, outputs: output_operands,
inputs, inputs: input_operands,
}); });
} else { } else {
let _ = self.pop_n( let _ = self.pop_n(inputs.len());
op_inputs( for ty in outputs {
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)); self.op_stack.push((ty, NO_VALUE));
} }
} }

View file

@ -19,8 +19,8 @@ pub fn op_inputs(
Ok(Vec::from(module.signatures[sig].params.clone())) Ok(Vec::from(module.signatures[sig].params.clone()))
} }
&Operator::CallIndirect { index, .. } => { &Operator::CallIndirect { index, .. } => {
let mut params = vec![Type::I32]; let mut params = module.signatures[index as usize].params.to_vec();
params.extend_from_slice(&module.signatures[index as usize].params[..]); params.push(Type::I32);
Ok(params) Ok(params)
} }
&Operator::Return => Ok(Vec::from(module.signatures[my_sig].returns.clone())), &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::I64TruncSatF32U => Ok(vec![Type::F32]),
Operator::I64TruncSatF64S => Ok(vec![Type::F64]), Operator::I64TruncSatF64S => Ok(vec![Type::F64]),
Operator::I64TruncSatF64U => 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::TableGet { .. } => Ok(vec![Type::I32]),
Operator::TableSet { table } => Ok(vec![Type::I32, module.tables[*table as usize]]), Operator::TableSet { table } => Ok(vec![Type::I32, module.tables[*table as usize]]),
Operator::TableGrow { .. } => Ok(vec![Type::I32]), Operator::TableGrow { .. } => Ok(vec![Type::I32]),
Operator::TableSize { .. } => Ok(vec![]), Operator::TableSize { .. } => Ok(vec![]),
Operator::MemorySize { .. } => Ok(vec![]),
Operator::MemoryGrow { .. } => Ok(vec![Type::I32]),
_ => bail!("Unknown operator in op_inputs(): {:?}", op), _ => 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())) Ok(Vec::from(module.signatures[index as usize].returns.clone()))
} }
&Operator::Return => Ok(vec![]), &Operator::Return => Ok(vec![]),
&Operator::LocalSet { .. } | &Operator::LocalTee { .. } => Ok(vec![]), &Operator::LocalSet { .. } => Ok(vec![]),
&Operator::LocalGet { local_index } => Ok(vec![my_locals[local_index as usize]]), &Operator::LocalGet { local_index } | &Operator::LocalTee { local_index } => {
Ok(vec![my_locals[local_index as usize]])
}
&Operator::Select => { &Operator::Select => {
let val_ty = op_stack[op_stack.len() - 2].0; let val_ty = op_stack[op_stack.len() - 2].0;
@ -248,19 +256,19 @@ pub fn op_outputs(
&Operator::GlobalSet { .. } => Ok(vec![]), &Operator::GlobalSet { .. } => Ok(vec![]),
Operator::I32Load { .. } Operator::I32Load { .. }
| Operator::I64Load { .. }
| Operator::F32Load { .. }
| Operator::F64Load { .. }
| Operator::I32Load8S { .. } | Operator::I32Load8S { .. }
| Operator::I32Load8U { .. } | Operator::I32Load8U { .. }
| Operator::I32Load16S { .. } | Operator::I32Load16S { .. }
| Operator::I32Load16U { .. } => Ok(vec![Type::I32]), | Operator::I32Load16U { .. } => Ok(vec![Type::I32]),
Operator::I64Load8S { .. } Operator::I64Load { .. }
| Operator::I64Load8S { .. }
| Operator::I64Load8U { .. } | Operator::I64Load8U { .. }
| Operator::I64Load16S { .. } | Operator::I64Load16S { .. }
| Operator::I64Load16U { .. } | Operator::I64Load16U { .. }
| Operator::I64Load32S { .. } | Operator::I64Load32S { .. }
| Operator::I64Load32U { .. } => Ok(vec![Type::I64]), | Operator::I64Load32U { .. } => Ok(vec![Type::I64]),
Operator::F32Load { .. } => Ok(vec![Type::F32]),
Operator::F64Load { .. } => Ok(vec![Type::F64]),
Operator::I32Store { .. } => Ok(vec![]), Operator::I32Store { .. } => Ok(vec![]),
Operator::I64Store { .. } => Ok(vec![]), Operator::I64Store { .. } => Ok(vec![]),
@ -414,10 +422,16 @@ pub fn op_outputs(
Operator::I64TruncSatF32U => Ok(vec![Type::I64]), Operator::I64TruncSatF32U => Ok(vec![Type::I64]),
Operator::I64TruncSatF64S => Ok(vec![Type::I64]), Operator::I64TruncSatF64S => Ok(vec![Type::I64]),
Operator::I64TruncSatF64U => 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::TableGet { table } => Ok(vec![module.tables[*table as usize]]),
Operator::TableSet { .. } => Ok(vec![]), Operator::TableSet { .. } => Ok(vec![]),
Operator::TableGrow { .. } => Ok(vec![]), Operator::TableGrow { .. } => Ok(vec![]),
Operator::TableSize { .. } => Ok(vec![Type::I32]), 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), _ => bail!("Unknown operator in op_outputs(): {:?}", op),
} }