fuzzbug fix and more robust undef handling
This commit is contained in:
parent
63aa7e4cb6
commit
f33aab4216
|
@ -170,10 +170,5 @@ pub fn produce_func_wasm<FT: FuncTypeSink>(
|
||||||
ctx.translate(operator, locations);
|
ctx.translate(operator, locations);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fixup: add unreachable just before last `end`; there must be an explicit return.
|
|
||||||
// assert!(matches!(wasm.operators.pop(), Some(wasm_encoder::Instruction::End)));
|
|
||||||
// wasm.operators.push(wasm_encoder::Instruction::Unreachable);
|
|
||||||
// wasm.operators.push(wasm_encoder::Instruction::End);
|
|
||||||
|
|
||||||
wasm
|
wasm
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,7 +21,7 @@ pub struct Allocator<'a> {
|
||||||
freelist: FxHashMap<wasmparser::Type, Vec<LocalId>>,
|
freelist: FxHashMap<wasmparser::Type, Vec<LocalId>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug, Default)]
|
#[derive(Clone, Copy, Debug)]
|
||||||
pub struct ValueSpan {
|
pub struct ValueSpan {
|
||||||
value: Value,
|
value: Value,
|
||||||
multi_value_index: usize,
|
multi_value_index: usize,
|
||||||
|
|
|
@ -82,10 +82,6 @@ impl Schedule {
|
||||||
}
|
}
|
||||||
match value_def {
|
match value_def {
|
||||||
&ValueDef::Operator(op, ref operands) => {
|
&ValueDef::Operator(op, ref operands) => {
|
||||||
if operands.iter().any(|&value| value == Value::undef()) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if operands.len() == 0 {
|
if operands.len() == 0 {
|
||||||
if !op_rematerialize(&op) {
|
if !op_rematerialize(&op) {
|
||||||
log::trace!("immediately ready: v{}", value.index());
|
log::trace!("immediately ready: v{}", value.index());
|
||||||
|
|
|
@ -23,7 +23,6 @@ impl UseCountAnalysis {
|
||||||
let mut workqueue_set = FxHashSet::default();
|
let mut workqueue_set = FxHashSet::default();
|
||||||
for block in 0..f.blocks.len() {
|
for block in 0..f.blocks.len() {
|
||||||
for &value in &f.blocks[block].insts {
|
for &value in &f.blocks[block].insts {
|
||||||
if value != Value::undef() {
|
|
||||||
let value = f.resolve_alias(value);
|
let value = f.resolve_alias(value);
|
||||||
counts.add(value);
|
counts.add(value);
|
||||||
if workqueue_set.insert(value) {
|
if workqueue_set.insert(value) {
|
||||||
|
@ -31,15 +30,12 @@ impl UseCountAnalysis {
|
||||||
}
|
}
|
||||||
counts.toplevel.insert(value);
|
counts.toplevel.insert(value);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
f.blocks[block].terminator.visit_uses(|value| {
|
f.blocks[block].terminator.visit_uses(|value| {
|
||||||
if value != Value::undef() {
|
|
||||||
let value = f.resolve_alias(value);
|
let value = f.resolve_alias(value);
|
||||||
counts.add(value);
|
counts.add(value);
|
||||||
if workqueue_set.insert(value) {
|
if workqueue_set.insert(value) {
|
||||||
workqueue.push_back(value);
|
workqueue.push_back(value);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
while let Some(value) = workqueue.pop_front() {
|
while let Some(value) = workqueue.pop_front() {
|
||||||
|
@ -48,9 +44,6 @@ impl UseCountAnalysis {
|
||||||
&ValueDef::Alias(..) | &ValueDef::Arg(..) | &ValueDef::BlockParam(..) => {}
|
&ValueDef::Alias(..) | &ValueDef::Arg(..) | &ValueDef::BlockParam(..) => {}
|
||||||
&ValueDef::Operator(_op, ref args) => {
|
&ValueDef::Operator(_op, ref args) => {
|
||||||
for &arg in args {
|
for &arg in args {
|
||||||
if arg == Value::undef() {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
let arg = f.resolve_alias(arg);
|
let arg = f.resolve_alias(arg);
|
||||||
counts.add(arg);
|
counts.add(arg);
|
||||||
if counts.use_count[arg.index()] == 1 {
|
if counts.use_count[arg.index()] == 1 {
|
||||||
|
@ -61,9 +54,6 @@ impl UseCountAnalysis {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
&ValueDef::PickOutput(value, _) => {
|
&ValueDef::PickOutput(value, _) => {
|
||||||
if value == Value::undef() {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
let value = f.resolve_alias(value);
|
let value = f.resolve_alias(value);
|
||||||
counts.add(value);
|
counts.add(value);
|
||||||
if counts.use_count[value.index()] == 1 {
|
if counts.use_count[value.index()] == 1 {
|
||||||
|
|
|
@ -290,7 +290,8 @@ impl LocalTracker {
|
||||||
assert!((local as usize) < body.locals.len());
|
assert!((local as usize) < body.locals.len());
|
||||||
self.get_in_block(body, block, local)
|
self.get_in_block(body, block, local)
|
||||||
} else {
|
} else {
|
||||||
Value::undef()
|
let ty = body.locals[local as usize];
|
||||||
|
self.create_default_value(body, ty)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -541,11 +542,13 @@ impl<'a, 'b> FunctionBodyBuilder<'a, 'b> {
|
||||||
self.op_stack.pop().unwrap().1
|
self.op_stack.pop().unwrap().1
|
||||||
}
|
}
|
||||||
|
|
||||||
fn block_results(&mut self, n: usize, start_depth: usize) -> Vec<Value> {
|
fn block_results(&mut self, tys: &[Type], start_depth: usize) -> Vec<Value> {
|
||||||
if self.op_stack.len() < start_depth + n {
|
if self.op_stack.len() < start_depth + tys.len() {
|
||||||
vec![Value::undef(); n]
|
tys.iter()
|
||||||
|
.map(|&ty| self.locals.create_default_value(&mut self.body, ty))
|
||||||
|
.collect()
|
||||||
} else {
|
} else {
|
||||||
self.pop_n(n)
|
self.pop_n(tys.len())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -571,17 +574,13 @@ impl<'a, 'b> FunctionBodyBuilder<'a, 'b> {
|
||||||
|
|
||||||
wasmparser::Operator::LocalSet { local_index } => {
|
wasmparser::Operator::LocalSet { local_index } => {
|
||||||
let (_, value) = self.op_stack.pop().unwrap();
|
let (_, value) = self.op_stack.pop().unwrap();
|
||||||
if value != Value::undef() {
|
|
||||||
self.locals.set(*local_index, value);
|
self.locals.set(*local_index, value);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
wasmparser::Operator::LocalTee { local_index } => {
|
wasmparser::Operator::LocalTee { local_index } => {
|
||||||
let (_ty, value) = *self.op_stack.last().unwrap();
|
let (_ty, value) = *self.op_stack.last().unwrap();
|
||||||
if value != Value::undef() {
|
|
||||||
self.locals.set(*local_index, value);
|
self.locals.set(*local_index, value);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
wasmparser::Operator::Call { .. }
|
wasmparser::Operator::Call { .. }
|
||||||
| wasmparser::Operator::CallIndirect { .. }
|
| wasmparser::Operator::CallIndirect { .. }
|
||||||
|
@ -787,7 +786,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.block_results(results.len(), *start_depth);
|
let result_values = self.block_results(&results[..], *start_depth);
|
||||||
self.emit_branch(*out, &result_values[..]);
|
self.emit_branch(*out, &result_values[..]);
|
||||||
self.op_stack.truncate(*start_depth);
|
self.op_stack.truncate(*start_depth);
|
||||||
// Seal the out-block: no more edges will be
|
// Seal the out-block: no more edges will be
|
||||||
|
@ -812,7 +811,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.block_results(results.len(), *start_depth);
|
let result_values = self.block_results(&results[..], *start_depth);
|
||||||
self.emit_branch(*out, &result_values[..]);
|
self.emit_branch(*out, &result_values[..]);
|
||||||
self.op_stack.truncate(*start_depth);
|
self.op_stack.truncate(*start_depth);
|
||||||
// No `else`, so we need to generate a trivial
|
// No `else`, so we need to generate a trivial
|
||||||
|
@ -841,7 +840,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.block_results(results.len(), *start_depth);
|
let result_values = self.block_results(&results[..], *start_depth);
|
||||||
self.emit_branch(*out, &result_values[..]);
|
self.emit_branch(*out, &result_values[..]);
|
||||||
self.op_stack.truncate(*start_depth);
|
self.op_stack.truncate(*start_depth);
|
||||||
self.cur_block = Some(*out);
|
self.cur_block = Some(*out);
|
||||||
|
@ -920,7 +919,7 @@ impl<'a, 'b> FunctionBodyBuilder<'a, 'b> {
|
||||||
results,
|
results,
|
||||||
} = self.ctrl_stack.pop().unwrap()
|
} = self.ctrl_stack.pop().unwrap()
|
||||||
{
|
{
|
||||||
let if_results = self.block_results(results.len(), start_depth);
|
let if_results = self.block_results(&results[..], start_depth);
|
||||||
self.emit_branch(out, &if_results[..]);
|
self.emit_branch(out, &if_results[..]);
|
||||||
self.op_stack.truncate(start_depth);
|
self.op_stack.truncate(start_depth);
|
||||||
self.op_stack.extend(param_values);
|
self.op_stack.extend(param_values);
|
||||||
|
|
12
src/ir.rs
12
src/ir.rs
|
@ -100,7 +100,6 @@ impl FunctionBody {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_alias(&mut self, value: Value, to: Value) {
|
pub fn set_alias(&mut self, value: Value, to: Value) {
|
||||||
assert_ne!(to, Value::undef());
|
|
||||||
log::trace!("set_alias: value {:?} to {:?}", value, to);
|
log::trace!("set_alias: value {:?} to {:?}", value, to);
|
||||||
// Resolve the `to` value through all existing aliases.
|
// Resolve the `to` value through all existing aliases.
|
||||||
let to = self.resolve_and_update_alias(to);
|
let to = self.resolve_and_update_alias(to);
|
||||||
|
@ -112,7 +111,6 @@ impl FunctionBody {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn resolve_alias(&self, value: Value) -> Value {
|
pub fn resolve_alias(&self, value: Value) -> Value {
|
||||||
assert_ne!(value, Value::undef());
|
|
||||||
let mut result = value;
|
let mut result = value;
|
||||||
loop {
|
loop {
|
||||||
if let &ValueDef::Alias(to) = &self.values[result.index()] {
|
if let &ValueDef::Alias(to) = &self.values[result.index()] {
|
||||||
|
@ -238,10 +236,6 @@ impl std::fmt::Display for Value {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Value {
|
impl Value {
|
||||||
pub fn undef() -> Self {
|
|
||||||
Value(u32::MAX)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn index(self) -> usize {
|
pub fn index(self) -> usize {
|
||||||
self.0 as usize
|
self.0 as usize
|
||||||
}
|
}
|
||||||
|
@ -251,12 +245,6 @@ impl Value {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl std::default::Default for Value {
|
|
||||||
fn default() -> Self {
|
|
||||||
Value::undef()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
|
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
|
||||||
pub enum ValueDef {
|
pub enum ValueDef {
|
||||||
Arg(usize),
|
Arg(usize),
|
||||||
|
|
Loading…
Reference in a new issue