Implement block returns

This commit is contained in:
Rerumu 2021-11-22 15:16:14 -05:00
parent 30a0589fbe
commit 57b3c7f22a

View File

@ -1,4 +1,4 @@
use parity_wasm::elements::{Instruction, Local, Module}; use parity_wasm::elements::{BlockType, Instruction, Local, Module};
use crate::backend::translator::arity::{Arity, List as ArityList}; use crate::backend::translator::arity::{Arity, List as ArityList};
@ -27,14 +27,14 @@ pub struct Transformer<'a> {
last_stack: usize, last_stack: usize,
} }
fn is_now_else(inst: &[Instruction]) -> bool {
inst.get(0) == Some(&Instruction::Else)
}
fn local_sum(list: &[Local]) -> u32 { fn local_sum(list: &[Local]) -> u32 {
list.iter().map(Local::count).sum() list.iter().map(Local::count).sum()
} }
fn is_else_stat(list: &[Instruction]) -> bool {
list.get(0) == Some(&Instruction::Else)
}
impl<'a> Transformer<'a> { impl<'a> Transformer<'a> {
pub fn new(wasm: &'a Module, arity: &'a ArityList, name: usize) -> Transformer<'a> { pub fn new(wasm: &'a Module, arity: &'a ArityList, name: usize) -> Transformer<'a> {
Transformer { Transformer {
@ -61,7 +61,7 @@ impl<'a> Transformer<'a> {
} }
} }
fn gen_push_recall(&mut self, num: u32) { fn push_recall(&mut self, num: u32) {
let len = self.living.len(); let len = self.living.len();
(len..len + num as usize) (len..len + num as usize)
@ -69,6 +69,14 @@ impl<'a> Transformer<'a> {
.for_each(|v| self.living.push(v)); .for_each(|v| self.living.push(v));
} }
fn push_block_result(&mut self, typ: BlockType) {
if matches!(typ, BlockType::NoResult) {
return;
}
self.push_recall(1);
}
// If any expressions are still pending at the start of // If any expressions are still pending at the start of
// statement, we leak them into variables. // statement, we leak them into variables.
// Since expressions do not have set ordering rules, this is // Since expressions do not have set ordering rules, this is
@ -99,15 +107,7 @@ impl<'a> Transformer<'a> {
} }
fn load_pending(&mut self) { fn load_pending(&mut self) {
let mut old = self.sleeping.pop().unwrap(); self.living = self.sleeping.pop().unwrap();
if self.living.len() > old.len() {
let rem = self.living.drain(old.len()..);
old.extend(rem);
}
self.living = old;
} }
fn gen_return(&mut self, stat: &mut Vec<Statement>) { fn gen_return(&mut self, stat: &mut Vec<Statement>) {
@ -128,7 +128,7 @@ impl<'a> Transformer<'a> {
let len = u32::try_from(self.living.len()).unwrap(); let len = u32::try_from(self.living.len()).unwrap();
let result = len..len + arity.num_result; let result = len..len + arity.num_result;
self.gen_push_recall(arity.num_result); self.push_recall(arity.num_result);
self.gen_leak_pending(stat); self.gen_leak_pending(stat);
stat.push(Statement::Call(Call { stat.push(Statement::Call(Call {
func, func,
@ -149,7 +149,7 @@ impl<'a> Transformer<'a> {
let len = u32::try_from(self.living.len()).unwrap(); let len = u32::try_from(self.living.len()).unwrap();
let result = len..len + arity.num_result; let result = len..len + arity.num_result;
self.gen_push_recall(arity.num_result); self.push_recall(arity.num_result);
self.gen_leak_pending(stat); self.gen_leak_pending(stat);
stat.push(Statement::CallIndirect(CallIndirect { stat.push(Statement::CallIndirect(CallIndirect {
table, table,
@ -224,27 +224,30 @@ impl<'a> Transformer<'a> {
self.gen_leak_pending(&mut stat); self.gen_leak_pending(&mut stat);
stat.push(Statement::Unreachable); stat.push(Statement::Unreachable);
} }
Inst::Block(_) => { Inst::Block(t) => {
self.gen_leak_pending(&mut stat); self.gen_leak_pending(&mut stat);
let data = self.new_forward(list); let data = self.new_forward(list);
self.push_block_result(*t);
stat.push(Statement::Forward(data)); stat.push(Statement::Forward(data));
} }
Inst::Loop(_) => { Inst::Loop(t) => {
self.gen_leak_pending(&mut stat); self.gen_leak_pending(&mut stat);
let data = self.new_backward(list); let data = self.new_backward(list);
self.push_block_result(*t);
stat.push(Statement::Backward(data)); stat.push(Statement::Backward(data));
} }
Inst::If(_) => { Inst::If(t) => {
let cond = self.living.pop().unwrap(); let cond = self.living.pop().unwrap();
self.gen_leak_pending(&mut stat); self.gen_leak_pending(&mut stat);
let data = self.new_if(cond, list); let data = self.new_if(cond, list);
self.push_block_result(*t);
stat.push(Statement::If(data)); stat.push(Statement::If(data));
} }
Inst::Else => { Inst::Else => {
@ -263,7 +266,6 @@ impl<'a> Transformer<'a> {
} }
Inst::Br(i) => { Inst::Br(i) => {
self.gen_leak_pending(&mut stat); self.gen_leak_pending(&mut stat);
stat.push(Statement::Br(Br { target: *i })); stat.push(Statement::Br(Br { target: *i }));
} }
Inst::BrIf(i) => { Inst::BrIf(i) => {
@ -383,7 +385,7 @@ impl<'a> Transformer<'a> {
fn new_if(&mut self, cond: Expression, list: &mut &[Instruction]) -> If { fn new_if(&mut self, cond: Expression, list: &mut &[Instruction]) -> If {
let body = self.new_stored_body(list); let body = self.new_stored_body(list);
let other = is_now_else(list).then(|| { let other = is_else_stat(list).then(|| {
*list = &list[1..]; *list = &list[1..];
self.new_stored_body(list) self.new_stored_body(list)
}); });