Wasm control stack entries only need the number of return types.
This eliminates heap-allocated vectors which stored the actual types.
This commit is contained in:
@@ -129,12 +129,10 @@ impl<'short, 'long, Variable> InstBuilderBase<'short> for FuncInstBuilder<'short
|
|||||||
// If the user has supplied jump arguments we must adapt the arguments of
|
// If the user has supplied jump arguments we must adapt the arguments of
|
||||||
// the destination ebb
|
// the destination ebb
|
||||||
// TODO: find a way not to allocate a vector
|
// TODO: find a way not to allocate a vector
|
||||||
let args_types: Vec<Type> =
|
let args_types: Vec<Value> =
|
||||||
match data.analyze_branch(&self.builder.func.dfg.value_lists) {
|
match data.analyze_branch(&self.builder.func.dfg.value_lists) {
|
||||||
BranchInfo::SingleDest(_, args) => {
|
BranchInfo::SingleDest(_, args) => {
|
||||||
args.iter()
|
args.to_vec()
|
||||||
.map(|arg| self.builder.func.dfg.value_type(*arg))
|
|
||||||
.collect()
|
|
||||||
}
|
}
|
||||||
_ => panic!("should not happen"),
|
_ => panic!("should not happen"),
|
||||||
};
|
};
|
||||||
@@ -255,7 +253,7 @@ where
|
|||||||
/// When inserting the terminator instruction (which doesn't have a falltrough to its immediate
|
/// When inserting the terminator instruction (which doesn't have a falltrough to its immediate
|
||||||
/// successor), the block will be declared filled and it will not be possible to append
|
/// successor), the block will be declared filled and it will not be possible to append
|
||||||
/// instructions to it.
|
/// instructions to it.
|
||||||
pub fn switch_to_block(&mut self, ebb: Ebb, jump_args: &[Type]) -> &[Value] {
|
pub fn switch_to_block(&mut self, ebb: Ebb, jump_args: &[Value]) -> &[Value] {
|
||||||
if self.pristine {
|
if self.pristine {
|
||||||
self.fill_function_args_values(ebb);
|
self.fill_function_args_values(ebb);
|
||||||
}
|
}
|
||||||
@@ -556,7 +554,7 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
fn ebb_args_adjustment(&mut self, dest_ebb: Ebb, jump_args: &[Type]) {
|
fn ebb_args_adjustment(&mut self, dest_ebb: Ebb, jump_args: &[Value]) {
|
||||||
if self.builder.ssa.predecessors(dest_ebb).is_empty() ||
|
if self.builder.ssa.predecessors(dest_ebb).is_empty() ||
|
||||||
self.builder.ebbs[dest_ebb].pristine
|
self.builder.ebbs[dest_ebb].pristine
|
||||||
{
|
{
|
||||||
@@ -571,7 +569,8 @@ where
|
|||||||
.iter()
|
.iter()
|
||||||
.zip(jump_args.iter().take(dest_ebb_args.len()))
|
.zip(jump_args.iter().take(dest_ebb_args.len()))
|
||||||
.all(|(dest_arg, jump_arg)| {
|
.all(|(dest_arg, jump_arg)| {
|
||||||
*jump_arg == self.func.dfg.value_type(*dest_arg)
|
self.func.dfg.value_type(*jump_arg) ==
|
||||||
|
self.func.dfg.value_type(*dest_arg)
|
||||||
}),
|
}),
|
||||||
"the jump argument supplied has not the \
|
"the jump argument supplied has not the \
|
||||||
same type as the corresponding dest ebb argument"
|
same type as the corresponding dest ebb argument"
|
||||||
@@ -579,8 +578,9 @@ where
|
|||||||
dest_ebb_args.len()
|
dest_ebb_args.len()
|
||||||
};
|
};
|
||||||
self.builder.ebbs[dest_ebb].user_arg_count = jump_args.len();
|
self.builder.ebbs[dest_ebb].user_arg_count = jump_args.len();
|
||||||
for ty in jump_args.iter().skip(dest_ebb_args_len) {
|
for val in jump_args.iter().skip(dest_ebb_args_len) {
|
||||||
self.func.dfg.append_ebb_arg(dest_ebb, *ty);
|
let ty = self.func.dfg.value_type(*val);
|
||||||
|
self.func.dfg.append_ebb_arg(dest_ebb, ty);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// The Ebb already has predecessors
|
// The Ebb already has predecessors
|
||||||
@@ -599,7 +599,7 @@ where
|
|||||||
self.builder.ebbs[dest_ebb].user_arg_count,
|
self.builder.ebbs[dest_ebb].user_arg_count,
|
||||||
))
|
))
|
||||||
.all(|(jump_arg, dest_arg)| {
|
.all(|(jump_arg, dest_arg)| {
|
||||||
*jump_arg == self.func.dfg.value_type(*dest_arg)
|
self.func.dfg.value_type(*jump_arg) == self.func.dfg.value_type(*dest_arg)
|
||||||
}),
|
}),
|
||||||
"the jump argument supplied has not the \
|
"the jump argument supplied has not the \
|
||||||
same type as the corresponding dest ebb argument"
|
same type as the corresponding dest ebb argument"
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ use cretonne::ir::types::*;
|
|||||||
use cretonne::ir::condcodes::{IntCC, FloatCC};
|
use cretonne::ir::condcodes::{IntCC, FloatCC};
|
||||||
use cton_frontend::FunctionBuilder;
|
use cton_frontend::FunctionBuilder;
|
||||||
use wasmparser::{Operator, MemoryImmediate};
|
use wasmparser::{Operator, MemoryImmediate};
|
||||||
use translation_utils::{f32_translation, f64_translation, type_to_type, translate_type, Local};
|
use translation_utils::{f32_translation, f64_translation, type_to_type, num_return_values, Local};
|
||||||
use translation_utils::{TableIndex, SignatureIndex, FunctionIndex, MemoryIndex};
|
use translation_utils::{TableIndex, SignatureIndex, FunctionIndex, MemoryIndex};
|
||||||
use state::{TranslationState, ControlStackFrame};
|
use state::{TranslationState, ControlStackFrame};
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
@@ -122,7 +122,7 @@ pub fn translate_operator<FE: FuncEnvironment + ?Sized>(
|
|||||||
if let Ok(ty_cre) = type_to_type(&ty) {
|
if let Ok(ty_cre) = type_to_type(&ty) {
|
||||||
builder.append_ebb_arg(next, ty_cre);
|
builder.append_ebb_arg(next, ty_cre);
|
||||||
}
|
}
|
||||||
state.push_block(next, translate_type(ty));
|
state.push_block(next, num_return_values(ty));
|
||||||
}
|
}
|
||||||
Operator::Loop { ty } => {
|
Operator::Loop { ty } => {
|
||||||
let loop_body = builder.create_ebb();
|
let loop_body = builder.create_ebb();
|
||||||
@@ -131,7 +131,7 @@ pub fn translate_operator<FE: FuncEnvironment + ?Sized>(
|
|||||||
builder.append_ebb_arg(next, ty_cre);
|
builder.append_ebb_arg(next, ty_cre);
|
||||||
}
|
}
|
||||||
builder.ins().jump(loop_body, &[]);
|
builder.ins().jump(loop_body, &[]);
|
||||||
state.push_loop(loop_body, next, translate_type(ty));
|
state.push_loop(loop_body, next, num_return_values(ty));
|
||||||
builder.switch_to_block(loop_body, &[]);
|
builder.switch_to_block(loop_body, &[]);
|
||||||
}
|
}
|
||||||
Operator::If { ty } => {
|
Operator::If { ty } => {
|
||||||
@@ -147,7 +147,7 @@ pub fn translate_operator<FE: FuncEnvironment + ?Sized>(
|
|||||||
if let Ok(ty_cre) = type_to_type(&ty) {
|
if let Ok(ty_cre) = type_to_type(&ty) {
|
||||||
builder.append_ebb_arg(if_not, ty_cre);
|
builder.append_ebb_arg(if_not, ty_cre);
|
||||||
}
|
}
|
||||||
state.push_if(jump_inst, if_not, translate_type(ty));
|
state.push_if(jump_inst, if_not, num_return_values(ty));
|
||||||
}
|
}
|
||||||
Operator::Else => {
|
Operator::Else => {
|
||||||
// We take the control frame pushed by the if, use its ebb as the else body
|
// We take the control frame pushed by the if, use its ebb as the else body
|
||||||
@@ -157,10 +157,10 @@ pub fn translate_operator<FE: FuncEnvironment + ?Sized>(
|
|||||||
let (destination, return_count, branch_inst) = match state.control_stack[i] {
|
let (destination, return_count, branch_inst) = match state.control_stack[i] {
|
||||||
ControlStackFrame::If {
|
ControlStackFrame::If {
|
||||||
destination,
|
destination,
|
||||||
ref return_values,
|
num_return_values,
|
||||||
branch_inst,
|
branch_inst,
|
||||||
..
|
..
|
||||||
} => (destination, return_values.len(), branch_inst),
|
} => (destination, num_return_values, branch_inst),
|
||||||
_ => panic!("should not happen"),
|
_ => panic!("should not happen"),
|
||||||
};
|
};
|
||||||
builder.ins().jump(destination, state.peekn(return_count));
|
builder.ins().jump(destination, state.peekn(return_count));
|
||||||
@@ -173,15 +173,14 @@ pub fn translate_operator<FE: FuncEnvironment + ?Sized>(
|
|||||||
}
|
}
|
||||||
Operator::End => {
|
Operator::End => {
|
||||||
let frame = state.control_stack.pop().unwrap();
|
let frame = state.control_stack.pop().unwrap();
|
||||||
|
let return_count = frame.num_return_values();
|
||||||
if !builder.is_unreachable() || !builder.is_pristine() {
|
if !builder.is_unreachable() || !builder.is_pristine() {
|
||||||
let return_count = frame.return_values().len();
|
|
||||||
builder.ins().jump(
|
builder.ins().jump(
|
||||||
frame.following_code(),
|
frame.following_code(),
|
||||||
state.peekn(return_count),
|
state.peekn(return_count),
|
||||||
);
|
);
|
||||||
state.popn(return_count);
|
|
||||||
}
|
}
|
||||||
builder.switch_to_block(frame.following_code(), frame.return_values());
|
builder.switch_to_block(frame.following_code(), state.peekn(return_count));
|
||||||
builder.seal_block(frame.following_code());
|
builder.seal_block(frame.following_code());
|
||||||
// If it is a loop we also have to seal the body loop block
|
// If it is a loop we also have to seal the body loop block
|
||||||
match frame {
|
match frame {
|
||||||
@@ -223,7 +222,7 @@ pub fn translate_operator<FE: FuncEnvironment + ?Sized>(
|
|||||||
let return_count = if frame.is_loop() {
|
let return_count = if frame.is_loop() {
|
||||||
0
|
0
|
||||||
} else {
|
} else {
|
||||||
frame.return_values().len()
|
frame.num_return_values()
|
||||||
};
|
};
|
||||||
(return_count, frame.br_destination())
|
(return_count, frame.br_destination())
|
||||||
};
|
};
|
||||||
@@ -245,7 +244,7 @@ pub fn translate_operator<FE: FuncEnvironment + ?Sized>(
|
|||||||
let return_count = if frame.is_loop() {
|
let return_count = if frame.is_loop() {
|
||||||
0
|
0
|
||||||
} else {
|
} else {
|
||||||
frame.return_values().len()
|
frame.num_return_values()
|
||||||
};
|
};
|
||||||
(return_count, frame.br_destination())
|
(return_count, frame.br_destination())
|
||||||
};
|
};
|
||||||
@@ -269,7 +268,7 @@ pub fn translate_operator<FE: FuncEnvironment + ?Sized>(
|
|||||||
if min_depth_frame.is_loop() {
|
if min_depth_frame.is_loop() {
|
||||||
0
|
0
|
||||||
} else {
|
} else {
|
||||||
min_depth_frame.return_values().len()
|
min_depth_frame.num_return_values()
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
if jump_args_count == 0 {
|
if jump_args_count == 0 {
|
||||||
@@ -334,7 +333,7 @@ pub fn translate_operator<FE: FuncEnvironment + ?Sized>(
|
|||||||
let (return_count, br_destination) = {
|
let (return_count, br_destination) = {
|
||||||
let frame = &mut state.control_stack[0];
|
let frame = &mut state.control_stack[0];
|
||||||
frame.set_reachable();
|
frame.set_reachable();
|
||||||
let return_count = frame.return_values().len();
|
let return_count = frame.num_return_values();
|
||||||
(return_count, frame.br_destination())
|
(return_count, frame.br_destination())
|
||||||
};
|
};
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
//! The `TranslationState` struct defined in this module is used to keep track of the WebAssembly
|
//! The `TranslationState` struct defined in this module is used to keep track of the WebAssembly
|
||||||
//! value and control stacks during the translation of a single function.
|
//! value and control stacks during the translation of a single function.
|
||||||
|
|
||||||
use cretonne::ir::{self, Ebb, Inst, Type, Value};
|
use cretonne::ir::{self, Ebb, Inst, Value};
|
||||||
use runtime::{FuncEnvironment, GlobalValue};
|
use runtime::{FuncEnvironment, GlobalValue};
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use translation_utils::{GlobalIndex, MemoryIndex, SignatureIndex, FunctionIndex};
|
use translation_utils::{GlobalIndex, MemoryIndex, SignatureIndex, FunctionIndex};
|
||||||
@@ -12,7 +12,7 @@ use translation_utils::{GlobalIndex, MemoryIndex, SignatureIndex, FunctionIndex}
|
|||||||
/// fields:
|
/// fields:
|
||||||
///
|
///
|
||||||
/// - `destination`: reference to the `Ebb` that will hold the code after the control block;
|
/// - `destination`: reference to the `Ebb` that will hold the code after the control block;
|
||||||
/// - `return_values`: types of the values returned by the control block;
|
/// - `num_return_values`: number of values returned by the control block;
|
||||||
/// - `original_stack_size`: size of the value stack at the beginning of the control block.
|
/// - `original_stack_size`: size of the value stack at the beginning of the control block.
|
||||||
///
|
///
|
||||||
/// Moreover, the `if` frame has the `branch_inst` field that points to the `brz` instruction
|
/// Moreover, the `if` frame has the `branch_inst` field that points to the `brz` instruction
|
||||||
@@ -23,20 +23,20 @@ pub enum ControlStackFrame {
|
|||||||
If {
|
If {
|
||||||
destination: Ebb,
|
destination: Ebb,
|
||||||
branch_inst: Inst,
|
branch_inst: Inst,
|
||||||
return_values: Vec<Type>,
|
num_return_values: usize,
|
||||||
original_stack_size: usize,
|
original_stack_size: usize,
|
||||||
reachable: bool,
|
reachable: bool,
|
||||||
},
|
},
|
||||||
Block {
|
Block {
|
||||||
destination: Ebb,
|
destination: Ebb,
|
||||||
return_values: Vec<Type>,
|
num_return_values: usize,
|
||||||
original_stack_size: usize,
|
original_stack_size: usize,
|
||||||
reachable: bool,
|
reachable: bool,
|
||||||
},
|
},
|
||||||
Loop {
|
Loop {
|
||||||
destination: Ebb,
|
destination: Ebb,
|
||||||
header: Ebb,
|
header: Ebb,
|
||||||
return_values: Vec<Type>,
|
num_return_values: usize,
|
||||||
original_stack_size: usize,
|
original_stack_size: usize,
|
||||||
reachable: bool,
|
reachable: bool,
|
||||||
},
|
},
|
||||||
@@ -44,11 +44,11 @@ pub enum ControlStackFrame {
|
|||||||
|
|
||||||
/// Helper methods for the control stack objects.
|
/// Helper methods for the control stack objects.
|
||||||
impl ControlStackFrame {
|
impl ControlStackFrame {
|
||||||
pub fn return_values(&self) -> &[Type] {
|
pub fn num_return_values(&self) -> usize {
|
||||||
match *self {
|
match *self {
|
||||||
ControlStackFrame::If { ref return_values, .. } |
|
ControlStackFrame::If { num_return_values, .. } |
|
||||||
ControlStackFrame::Block { ref return_values, .. } |
|
ControlStackFrame::Block { num_return_values, .. } |
|
||||||
ControlStackFrame::Loop { ref return_values, .. } => &return_values,
|
ControlStackFrame::Loop { num_return_values, .. } => num_return_values,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pub fn following_code(&self) -> Ebb {
|
pub fn following_code(&self) -> Ebb {
|
||||||
@@ -161,8 +161,7 @@ impl TranslationState {
|
|||||||
sig.return_types
|
sig.return_types
|
||||||
.iter()
|
.iter()
|
||||||
.filter(|arg| arg.purpose == ir::ArgumentPurpose::Normal)
|
.filter(|arg| arg.purpose == ir::ArgumentPurpose::Normal)
|
||||||
.map(|argty| argty.value_type)
|
.count(),
|
||||||
.collect(),
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -215,33 +214,33 @@ impl TranslationState {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Push a block on the control stack.
|
// Push a block on the control stack.
|
||||||
pub fn push_block(&mut self, following_code: Ebb, result_types: Vec<Type>) {
|
pub fn push_block(&mut self, following_code: Ebb, num_result_types: usize) {
|
||||||
self.control_stack.push(ControlStackFrame::Block {
|
self.control_stack.push(ControlStackFrame::Block {
|
||||||
destination: following_code,
|
destination: following_code,
|
||||||
original_stack_size: self.stack.len(),
|
original_stack_size: self.stack.len(),
|
||||||
return_values: result_types,
|
num_return_values: num_result_types,
|
||||||
reachable: false,
|
reachable: false,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// Push a loop on the control stack.
|
// Push a loop on the control stack.
|
||||||
pub fn push_loop(&mut self, header: Ebb, following_code: Ebb, result_types: Vec<Type>) {
|
pub fn push_loop(&mut self, header: Ebb, following_code: Ebb, num_result_types: usize) {
|
||||||
self.control_stack.push(ControlStackFrame::Loop {
|
self.control_stack.push(ControlStackFrame::Loop {
|
||||||
header,
|
header,
|
||||||
destination: following_code,
|
destination: following_code,
|
||||||
original_stack_size: self.stack.len(),
|
original_stack_size: self.stack.len(),
|
||||||
return_values: result_types,
|
num_return_values: num_result_types,
|
||||||
reachable: false,
|
reachable: false,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// Push an if on the control stack.
|
// Push an if on the control stack.
|
||||||
pub fn push_if(&mut self, branch_inst: Inst, following_code: Ebb, result_types: Vec<Type>) {
|
pub fn push_if(&mut self, branch_inst: Inst, following_code: Ebb, num_result_types: usize) {
|
||||||
self.control_stack.push(ControlStackFrame::If {
|
self.control_stack.push(ControlStackFrame::If {
|
||||||
branch_inst,
|
branch_inst,
|
||||||
destination: following_code,
|
destination: following_code,
|
||||||
original_stack_size: self.stack.len(),
|
original_stack_size: self.stack.len(),
|
||||||
return_values: result_types,
|
num_return_values: num_result_types,
|
||||||
reachable: false,
|
reachable: false,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -119,13 +119,13 @@ pub fn f64_translation(x: wasmparser::Ieee64) -> cretonne::ir::immediates::Ieee6
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Translate a `wasmparser` type into its `Cretonne` equivalent, when possible
|
/// Translate a `wasmparser` type into its `Cretonne` equivalent, when possible
|
||||||
pub fn translate_type(ty: wasmparser::Type) -> Vec<cretonne::ir::Type> {
|
pub fn num_return_values(ty: wasmparser::Type) -> usize {
|
||||||
match ty {
|
match ty {
|
||||||
wasmparser::Type::EmptyBlockType => Vec::new(),
|
wasmparser::Type::EmptyBlockType => 0,
|
||||||
wasmparser::Type::I32 => vec![cretonne::ir::types::I32],
|
wasmparser::Type::I32 |
|
||||||
wasmparser::Type::F32 => vec![cretonne::ir::types::F32],
|
wasmparser::Type::F32 |
|
||||||
wasmparser::Type::I64 => vec![cretonne::ir::types::I64],
|
wasmparser::Type::I64 |
|
||||||
wasmparser::Type::F64 => vec![cretonne::ir::types::F64],
|
wasmparser::Type::F64 => 1,
|
||||||
_ => panic!("unsupported return value type"),
|
_ => panic!("unsupported return value type"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user