Bitcasting at control flow exits (#1272)

* Bitcast vectors immediately before a return

* Bitcast vectors immediately before a block end

* Use helper function for bitcasting arguments

* Add FuncTranslationState::peekn_mut; allows mutating of peeked values

* Bitcast values in place, avoiding an allocation

Also, retrieves the correct EBB header types for bitcasting on Operator::End.

* Bitcast values of a function with no explicit Wasm return instruction

* Add Signature::return_types method

This eliminates some duplicate code and avoids extra `use`s of `Vec`.

* Add Signature::param_types method; only collect normal parameters in both this and Signature::return_types

* Move normal_args to Signature::num_normal_params method

This matches the organization of the other Signature::num_*_params methods.

* Bitcast values of Operator::Call and Operator::CallIndirect

* Add DataFlowGraph::ebb_param_types

* Bitcast values of Operator::Br and Operator::BrIf

* Bitcast values of Operator::BrTable
This commit is contained in:
Andrew Brown
2020-01-06 15:33:22 -08:00
committed by Dan Gohman
parent 9bbe378d41
commit 46e58fbaaa
7 changed files with 171 additions and 44 deletions

View File

@@ -306,31 +306,40 @@ impl FuncTranslationState {
(v1, v2, v3)
}
/// Helper to ensure the the stack size is at least as big as `n`; note that due to
/// `debug_assert` this will not execute in non-optimized builds.
#[inline]
fn ensure_length_is_at_least(&self, n: usize) {
debug_assert!(
n <= self.stack.len(),
"attempted to access {} values but stack only has {} values",
n,
self.stack.len()
)
}
/// Pop the top `n` values on the stack.
///
/// The popped values are not returned. Use `peekn` to look at them before popping.
pub(crate) fn popn(&mut self, n: usize) {
debug_assert!(
n <= self.stack.len(),
"popn({}) but stack only has {} values",
n,
self.stack.len()
);
self.ensure_length_is_at_least(n);
let new_len = self.stack.len() - n;
self.stack.truncate(new_len);
}
/// Peek at the top `n` values on the stack in the order they were pushed.
pub(crate) fn peekn(&self, n: usize) -> &[Value] {
debug_assert!(
n <= self.stack.len(),
"peekn({}) but stack only has {} values",
n,
self.stack.len()
);
self.ensure_length_is_at_least(n);
&self.stack[self.stack.len() - n..]
}
/// Peek at the top `n` values on the stack in the order they were pushed.
pub(crate) fn peekn_mut(&mut self, n: usize) -> &mut [Value] {
self.ensure_length_is_at_least(n);
let len = self.stack.len();
&mut self.stack[len - n..]
}
/// Push a block on the control stack.
pub(crate) fn push_block(
&mut self,
@@ -465,7 +474,7 @@ impl FuncTranslationState {
Occupied(entry) => Ok(*entry.get()),
Vacant(entry) => {
let sig = environ.make_indirect_sig(func, index)?;
Ok(*entry.insert((sig, normal_args(&func.dfg.signatures[sig]))))
Ok(*entry.insert((sig, func.dfg.signatures[sig].num_normal_params())))
}
}
}
@@ -486,17 +495,8 @@ impl FuncTranslationState {
Vacant(entry) => {
let fref = environ.make_direct_func(func, index)?;
let sig = func.dfg.ext_funcs[fref].signature;
Ok(*entry.insert((fref, normal_args(&func.dfg.signatures[sig]))))
Ok(*entry.insert((fref, func.dfg.signatures[sig].num_normal_params())))
}
}
}
}
/// Count the number of normal parameters in a signature.
/// Exclude special-purpose parameters that represent runtime stuff and not WebAssembly arguments.
fn normal_args(sig: &ir::Signature) -> usize {
sig.params
.iter()
.filter(|arg| arg.purpose == ir::ArgumentPurpose::Normal)
.count()
}