Add naive local and temporary spills
This commit is contained in:
+15
-15
@@ -1,10 +1,10 @@
|
||||
use wasmparser::{BlockType, FunctionBody, MemArg, Operator, Result};
|
||||
|
||||
use crate::{
|
||||
module::{read_checked, TypeInfo},
|
||||
module::{read_checked, read_checked_locals, TypeInfo},
|
||||
node::{
|
||||
BinOp, BinOpType, Block, Br, BrIf, BrTable, Call, CallIndirect, CmpOp, CmpOpType,
|
||||
Expression, FuncData, GetGlobal, GetLocal, If, LabelType, LoadAt, LoadType, MemoryArgument,
|
||||
Expression, FuncData, GetGlobal, If, LabelType, LoadAt, LoadType, Local, MemoryArgument,
|
||||
MemoryCopy, MemoryFill, MemoryGrow, MemorySize, Select, SetGlobal, SetLocal, Statement,
|
||||
StoreAt, StoreType, Terminator, UnOp, UnOpType, Value,
|
||||
},
|
||||
@@ -253,13 +253,13 @@ impl<'a> Factory<'a> {
|
||||
/// Returns an error if the function is malformed.
|
||||
pub fn create_indexed(&mut self, index: usize, func: &FunctionBody) -> Result<FuncData> {
|
||||
let code = read_checked(func.get_operators_reader()?)?;
|
||||
let local = read_checked(func.get_locals_reader()?)?;
|
||||
let local_data = read_checked_locals(func.get_locals_reader()?)?;
|
||||
|
||||
let (num_param, num_result) = self.type_info.by_func_index(index);
|
||||
let data = self.build_stat_list(&code, num_result);
|
||||
|
||||
Ok(FuncData {
|
||||
local_data: local,
|
||||
local_data,
|
||||
num_result,
|
||||
num_param,
|
||||
num_stack: data.stack.capacity,
|
||||
@@ -279,7 +279,7 @@ impl<'a> Factory<'a> {
|
||||
BlockVariant::If => BlockData::If { num_result, ty },
|
||||
BlockVariant::Else => {
|
||||
old.stack.pop_len(num_result).for_each(drop);
|
||||
old.stack.push_temporary(num_param);
|
||||
old.stack.push_temporaries(num_param);
|
||||
|
||||
BlockData::Else { num_result }
|
||||
}
|
||||
@@ -287,7 +287,7 @@ impl<'a> Factory<'a> {
|
||||
|
||||
self.target.stack = old.stack.split_last(num_param, num_result);
|
||||
|
||||
old.stack.push_temporary(num_result);
|
||||
old.stack.push_temporaries(num_result);
|
||||
|
||||
self.pending.push(old);
|
||||
}
|
||||
@@ -358,12 +358,12 @@ impl<'a> Factory<'a> {
|
||||
|
||||
self.target.leak_pre_call();
|
||||
|
||||
let result = self.target.stack.push_temporary(num_result);
|
||||
let result_list = self.target.stack.push_temporaries(num_result);
|
||||
|
||||
let data = Statement::Call(Call {
|
||||
function,
|
||||
result,
|
||||
param_list,
|
||||
result_list,
|
||||
});
|
||||
|
||||
self.target.code.push(data);
|
||||
@@ -376,13 +376,13 @@ impl<'a> Factory<'a> {
|
||||
|
||||
self.target.leak_pre_call();
|
||||
|
||||
let result = self.target.stack.push_temporary(num_result);
|
||||
let result_list = self.target.stack.push_temporaries(num_result);
|
||||
|
||||
let data = Statement::CallIndirect(CallIndirect {
|
||||
table,
|
||||
index,
|
||||
result,
|
||||
param_list,
|
||||
result_list,
|
||||
});
|
||||
|
||||
self.target.code.push(data);
|
||||
@@ -521,14 +521,14 @@ impl<'a> Factory<'a> {
|
||||
}
|
||||
Operator::LocalGet { local_index } => {
|
||||
let var = local_index.try_into().unwrap();
|
||||
let data = Expression::GetLocal(GetLocal { var });
|
||||
let data = Expression::GetLocal(Local { var });
|
||||
|
||||
self.target.stack.push_with_single(data);
|
||||
}
|
||||
Operator::LocalSet { local_index } => {
|
||||
let var = local_index.try_into().unwrap();
|
||||
let data = Statement::SetLocal(SetLocal {
|
||||
var,
|
||||
var: Local { var },
|
||||
value: self.target.stack.pop().into(),
|
||||
});
|
||||
|
||||
@@ -537,9 +537,9 @@ impl<'a> Factory<'a> {
|
||||
}
|
||||
Operator::LocalTee { local_index } => {
|
||||
let var = local_index.try_into().unwrap();
|
||||
let get = Expression::GetLocal(GetLocal { var });
|
||||
let get = Expression::GetLocal(Local { var });
|
||||
let set = Statement::SetLocal(SetLocal {
|
||||
var,
|
||||
var: Local { var },
|
||||
value: self.target.stack.pop().into(),
|
||||
});
|
||||
|
||||
@@ -594,7 +594,7 @@ impl<'a> Factory<'a> {
|
||||
}
|
||||
Operator::MemoryGrow { mem, .. } => {
|
||||
let size = self.target.stack.pop().into();
|
||||
let result = self.target.stack.push_temporary(1).start;
|
||||
let result = self.target.stack.push_temporary();
|
||||
let memory = mem.try_into().unwrap();
|
||||
|
||||
let data = Statement::MemoryGrow(MemoryGrow {
|
||||
|
||||
+11
-2
@@ -1,8 +1,9 @@
|
||||
use std::collections::HashMap;
|
||||
|
||||
use wasmparser::{
|
||||
BlockType, Data, Element, Export, ExternalKind, FunctionBody, Global, Import, MemoryType, Name,
|
||||
NameSectionReader, Parser, Payload, Result, TableType, Type, TypeRef,
|
||||
BlockType, Data, Element, Export, ExternalKind, FunctionBody, Global, Import, LocalsReader,
|
||||
MemoryType, Name, NameSectionReader, Parser, Payload, Result, TableType, Type, TypeRef,
|
||||
ValType,
|
||||
};
|
||||
|
||||
#[derive(PartialEq, Eq, Clone, Copy)]
|
||||
@@ -45,6 +46,14 @@ where
|
||||
reader.into_iter().collect()
|
||||
}
|
||||
|
||||
pub(crate) fn read_checked_locals(reader: LocalsReader) -> Result<Vec<ValType>> {
|
||||
read_checked(reader).map(|locals| {
|
||||
let convert = |(a, b)| std::iter::repeat(b).take(usize::try_from(a).unwrap());
|
||||
|
||||
locals.into_iter().flat_map(convert).collect()
|
||||
})
|
||||
}
|
||||
|
||||
pub struct Module<'a> {
|
||||
type_section: Vec<Type>,
|
||||
import_section: Vec<Import<'a>>,
|
||||
|
||||
+53
-33
@@ -1,5 +1,3 @@
|
||||
use std::ops::Range;
|
||||
|
||||
use wasmparser::{Operator, ValType};
|
||||
|
||||
#[allow(non_camel_case_types)]
|
||||
@@ -627,22 +625,22 @@ impl Select {
|
||||
}
|
||||
}
|
||||
|
||||
pub struct GetTemporary {
|
||||
pub struct Temporary {
|
||||
pub(crate) var: usize,
|
||||
}
|
||||
|
||||
impl GetTemporary {
|
||||
impl Temporary {
|
||||
#[must_use]
|
||||
pub const fn var(&self) -> usize {
|
||||
self.var
|
||||
}
|
||||
}
|
||||
|
||||
pub struct GetLocal {
|
||||
pub struct Local {
|
||||
pub(crate) var: usize,
|
||||
}
|
||||
|
||||
impl GetLocal {
|
||||
impl Local {
|
||||
#[must_use]
|
||||
pub const fn var(&self) -> usize {
|
||||
self.var
|
||||
@@ -797,8 +795,8 @@ impl CmpOp {
|
||||
|
||||
pub enum Expression {
|
||||
Select(Select),
|
||||
GetTemporary(GetTemporary),
|
||||
GetLocal(GetLocal),
|
||||
GetTemporary(Temporary),
|
||||
GetLocal(Local),
|
||||
GetGlobal(GetGlobal),
|
||||
LoadAt(LoadAt),
|
||||
MemorySize(MemorySize),
|
||||
@@ -808,6 +806,28 @@ pub enum Expression {
|
||||
CmpOp(CmpOp),
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct ResultList {
|
||||
start: usize,
|
||||
end: usize,
|
||||
}
|
||||
|
||||
impl ResultList {
|
||||
#[must_use]
|
||||
pub const fn new(start: usize, end: usize) -> Self {
|
||||
Self { start, end }
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub const fn is_empty(self) -> bool {
|
||||
self.start == self.end
|
||||
}
|
||||
|
||||
pub fn iter(self) -> impl Iterator<Item = Temporary> {
|
||||
(self.start..self.end).map(|var| Temporary { var })
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Align {
|
||||
pub(crate) new: usize,
|
||||
pub(crate) old: usize,
|
||||
@@ -821,13 +841,13 @@ impl Align {
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub const fn new_range(&self) -> Range<usize> {
|
||||
self.new..self.new + self.length
|
||||
pub const fn new_range(&self) -> ResultList {
|
||||
ResultList::new(self.new, self.new + self.length)
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub const fn old_range(&self) -> Range<usize> {
|
||||
self.old..self.old + self.length
|
||||
pub const fn old_range(&self) -> ResultList {
|
||||
ResultList::new(self.old, self.old + self.length)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -949,8 +969,8 @@ impl If {
|
||||
|
||||
pub struct Call {
|
||||
pub(crate) function: usize,
|
||||
pub(crate) result: Range<usize>,
|
||||
pub(crate) param_list: Vec<Expression>,
|
||||
pub(crate) result_list: ResultList,
|
||||
}
|
||||
|
||||
impl Call {
|
||||
@@ -960,21 +980,21 @@ impl Call {
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn result(&self) -> Range<usize> {
|
||||
self.result.clone()
|
||||
pub fn param_list(&self) -> &[Expression] {
|
||||
&self.param_list
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn param_list(&self) -> &[Expression] {
|
||||
&self.param_list
|
||||
pub const fn result_list(&self) -> ResultList {
|
||||
self.result_list
|
||||
}
|
||||
}
|
||||
|
||||
pub struct CallIndirect {
|
||||
pub(crate) table: usize,
|
||||
pub(crate) index: Box<Expression>,
|
||||
pub(crate) result: Range<usize>,
|
||||
pub(crate) param_list: Vec<Expression>,
|
||||
pub(crate) result_list: ResultList,
|
||||
}
|
||||
|
||||
impl CallIndirect {
|
||||
@@ -989,25 +1009,25 @@ impl CallIndirect {
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn result(&self) -> Range<usize> {
|
||||
self.result.clone()
|
||||
pub fn param_list(&self) -> &[Expression] {
|
||||
&self.param_list
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn param_list(&self) -> &[Expression] {
|
||||
&self.param_list
|
||||
pub const fn result_list(&self) -> ResultList {
|
||||
self.result_list
|
||||
}
|
||||
}
|
||||
|
||||
pub struct SetTemporary {
|
||||
pub(crate) var: usize,
|
||||
pub(crate) var: Temporary,
|
||||
pub(crate) value: Box<Expression>,
|
||||
}
|
||||
|
||||
impl SetTemporary {
|
||||
#[must_use]
|
||||
pub const fn var(&self) -> usize {
|
||||
self.var
|
||||
pub const fn var(&self) -> &Temporary {
|
||||
&self.var
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
@@ -1017,14 +1037,14 @@ impl SetTemporary {
|
||||
}
|
||||
|
||||
pub struct SetLocal {
|
||||
pub(crate) var: usize,
|
||||
pub(crate) var: Local,
|
||||
pub(crate) value: Box<Expression>,
|
||||
}
|
||||
|
||||
impl SetLocal {
|
||||
#[must_use]
|
||||
pub const fn var(&self) -> usize {
|
||||
self.var
|
||||
pub const fn var(&self) -> &Local {
|
||||
&self.var
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
@@ -1087,7 +1107,7 @@ impl StoreAt {
|
||||
|
||||
pub struct MemoryGrow {
|
||||
pub(crate) memory: usize,
|
||||
pub(crate) result: usize,
|
||||
pub(crate) result: Temporary,
|
||||
pub(crate) size: Box<Expression>,
|
||||
}
|
||||
|
||||
@@ -1098,8 +1118,8 @@ impl MemoryGrow {
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub const fn result(&self) -> usize {
|
||||
self.result
|
||||
pub const fn result(&self) -> &Temporary {
|
||||
&self.result
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
@@ -1187,7 +1207,7 @@ pub enum Statement {
|
||||
}
|
||||
|
||||
pub struct FuncData {
|
||||
pub(crate) local_data: Vec<(u32, ValType)>,
|
||||
pub(crate) local_data: Vec<ValType>,
|
||||
pub(crate) num_result: usize,
|
||||
pub(crate) num_param: usize,
|
||||
pub(crate) num_stack: usize,
|
||||
@@ -1196,7 +1216,7 @@ pub struct FuncData {
|
||||
|
||||
impl FuncData {
|
||||
#[must_use]
|
||||
pub fn local_data(&self) -> &[(u32, ValType)] {
|
||||
pub fn local_data(&self) -> &[ValType] {
|
||||
&self.local_data
|
||||
}
|
||||
|
||||
|
||||
+12
-8
@@ -1,7 +1,7 @@
|
||||
use std::{collections::HashSet, ops::Range};
|
||||
use std::collections::HashSet;
|
||||
|
||||
use crate::node::{
|
||||
Align, Expression, GetGlobal, GetLocal, GetTemporary, LoadAt, SetTemporary, Statement,
|
||||
Align, Expression, GetGlobal, LoadAt, Local, ResultList, SetTemporary, Statement, Temporary,
|
||||
};
|
||||
|
||||
#[derive(Clone, Copy, PartialEq, Eq, Hash)]
|
||||
@@ -68,7 +68,7 @@ impl Stack {
|
||||
pub fn push_with_single(&mut self, data: Expression) {
|
||||
let mut read = HashSet::new();
|
||||
let elem = match data {
|
||||
Expression::GetLocal(GetLocal { var }) => ReadType::Local(var),
|
||||
Expression::GetLocal(Local { var }) => ReadType::Local(var),
|
||||
Expression::GetGlobal(GetGlobal { var }) => ReadType::Global(var),
|
||||
Expression::LoadAt(LoadAt { memory, .. }) => ReadType::Memory(memory),
|
||||
_ => unreachable!(),
|
||||
@@ -94,19 +94,23 @@ impl Stack {
|
||||
self.var_list.drain(desired..).map(|v| v.data)
|
||||
}
|
||||
|
||||
pub fn push_temporary(&mut self, num: usize) -> Range<usize> {
|
||||
pub fn push_temporaries(&mut self, num: usize) -> ResultList {
|
||||
let start = self.previous + self.len();
|
||||
let range = start..start + num;
|
||||
|
||||
self.capacity = self.capacity.max(range.end);
|
||||
|
||||
for var in range.clone() {
|
||||
let data = Expression::GetTemporary(GetTemporary { var });
|
||||
let data = Expression::GetTemporary(Temporary { var });
|
||||
|
||||
self.push(data);
|
||||
}
|
||||
|
||||
range
|
||||
ResultList::new(range.start, range.end)
|
||||
}
|
||||
|
||||
pub fn push_temporary(&mut self) -> Temporary {
|
||||
self.push_temporaries(1).iter().next().unwrap()
|
||||
}
|
||||
|
||||
// Return the alignment necessary for this block to branch out to a
|
||||
@@ -136,9 +140,9 @@ impl Stack {
|
||||
|
||||
old.read.clear();
|
||||
|
||||
let get = Expression::GetTemporary(GetTemporary { var });
|
||||
let get = Expression::GetTemporary(Temporary { var });
|
||||
let set = Statement::SetTemporary(SetTemporary {
|
||||
var,
|
||||
var: Temporary { var },
|
||||
value: std::mem::replace(&mut old.data, get).into(),
|
||||
});
|
||||
|
||||
|
||||
@@ -1,15 +1,15 @@
|
||||
use crate::node::{
|
||||
BinOp, Block, Br, BrIf, BrTable, Call, CallIndirect, CmpOp, Expression, FuncData, GetGlobal,
|
||||
GetLocal, GetTemporary, If, LoadAt, MemoryCopy, MemoryFill, MemoryGrow, MemorySize, Select,
|
||||
SetGlobal, SetLocal, SetTemporary, Statement, StoreAt, Terminator, UnOp, Value,
|
||||
If, LoadAt, Local, MemoryCopy, MemoryFill, MemoryGrow, MemorySize, Select, SetGlobal, SetLocal,
|
||||
SetTemporary, Statement, StoreAt, Temporary, Terminator, UnOp, Value,
|
||||
};
|
||||
|
||||
pub trait Visitor {
|
||||
fn visit_select(&mut self, _: &Select) {}
|
||||
|
||||
fn visit_get_temporary(&mut self, _: &GetTemporary) {}
|
||||
fn visit_get_temporary(&mut self, _: &Temporary) {}
|
||||
|
||||
fn visit_get_local(&mut self, _: &GetLocal) {}
|
||||
fn visit_get_local(&mut self, _: &Local) {}
|
||||
|
||||
fn visit_get_global(&mut self, _: &GetGlobal) {}
|
||||
|
||||
@@ -76,13 +76,13 @@ impl<T: Visitor> Driver<T> for Select {
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Visitor> Driver<T> for GetTemporary {
|
||||
impl<T: Visitor> Driver<T> for Temporary {
|
||||
fn accept(&self, visitor: &mut T) {
|
||||
visitor.visit_get_temporary(self);
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Visitor> Driver<T> for GetLocal {
|
||||
impl<T: Visitor> Driver<T> for Local {
|
||||
fn accept(&self, visitor: &mut T) {
|
||||
visitor.visit_get_local(self);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user