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:
@@ -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()
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user