return calls, more reordering

This commit is contained in:
Graham Kelly 2024-01-13 09:17:33 -05:00
parent c3705d8186
commit 6a90d5fdb5
7 changed files with 200 additions and 0 deletions

View file

@ -171,6 +171,18 @@ impl<'a> WasmFuncBackend<'a> {
} }
func.instruction(&wasm_encoder::Instruction::Return); func.instruction(&wasm_encoder::Instruction::Return);
} }
WasmBlock::ReturnCall { func: f,values } => {
for &value in &values[..] {
self.lower_value(value, func);
}
func.instruction(&wasm_encoder::Instruction::ReturnCall(f.index() as u32));
}
WasmBlock::ReturnCallIndirect { sig, table, values } => {
for &value in &values[..] {
self.lower_value(value, func);
}
func.instruction(&wasm_encoder::Instruction::ReturnCallIndirect { ty: sig.index() as u32, table: table.index() as u32 });
}
WasmBlock::Unreachable => { WasmBlock::Unreachable => {
func.instruction(&wasm_encoder::Instruction::Unreachable); func.instruction(&wasm_encoder::Instruction::Unreachable);
} }

View file

@ -9,6 +9,7 @@
//! //!
//! for more details on how this algorithm works. //! for more details on how this algorithm works.
use crate::{Func, Signature, Table};
use crate::cfg::CFGInfo; use crate::cfg::CFGInfo;
use crate::entity::EntityRef; use crate::entity::EntityRef;
use crate::ir::{Block, BlockTarget, FunctionBody, Terminator, Type, Value}; use crate::ir::{Block, BlockTarget, FunctionBody, Terminator, Type, Value};
@ -52,6 +53,8 @@ pub enum WasmBlock<'a> {
}, },
/// A function return instruction. /// A function return instruction.
Return { values: &'a [Value] }, Return { values: &'a [Value] },
ReturnCall { func: Func,values: &'a [Value] },
ReturnCallIndirect { sig: Signature,table: Table,values: &'a [Value] },
/// An unreachable instruction. /// An unreachable instruction.
Unreachable, Unreachable,
} }
@ -441,6 +444,12 @@ impl<'a, 'b> Context<'a, 'b> {
&Terminator::Unreachable | &Terminator::None => { &Terminator::Unreachable | &Terminator::None => {
into.push(WasmBlock::Unreachable); into.push(WasmBlock::Unreachable);
} }
&Terminator::ReturnCall { func, ref args } => {
into.push(WasmBlock::ReturnCall { func: func, values: args });
}
&Terminator::ReturnCallIndirect { sig, table, ref args } => {
into.push(WasmBlock::ReturnCallIndirect { sig, table, values: args })
}
} }
} }
} }

View file

@ -1230,6 +1230,18 @@ impl<'a, 'b> FunctionBodyBuilder<'a, 'b> {
self.emit_ret(&retvals[..]); self.emit_ret(&retvals[..]);
self.reachable = false; self.reachable = false;
} }
wasmparser::Operator::ReturnCall { function_index } => {
let sig = self.module.funcs[Func::new(*function_index as usize)].sig();
let retvals = self.pop_n(self.module.signatures[sig].params.len());
self.emit_term(Terminator::ReturnCall { func: Func::new(*function_index as usize), args: retvals });
self.reachable = false;
}
wasmparser::Operator::ReturnCallIndirect { type_index, table_index } => {
// let sig = self.module.funcs[Func::new(*function_index as usize)].sig();
let retvals = self.pop_n(self.module.signatures[Signature::new(*type_index as usize)].params.len());
self.emit_term(Terminator::ReturnCallIndirect { sig: Signature::new(*type_index as usize), table: Table::new(*table_index as usize),args: retvals });
self.reachable = false;
}
_ => bail!(FrontendError::UnsupportedFeature(format!( _ => bail!(FrontendError::UnsupportedFeature(format!(
"Unsupported operator: {:?}", "Unsupported operator: {:?}",
@ -1647,6 +1659,21 @@ impl<'a, 'b> FunctionBodyBuilder<'a, 'b> {
} }
} }
fn emit_term(&mut self, t: Terminator){
log::trace!(
"emit_term: cur_block {} reachable {} terminator {:?}",
self.cur_block,
self.reachable,
t
);
if self.reachable {
// let values = values.to_vec();
self.body
.set_terminator(self.cur_block,t);
self.reachable = false;
}
}
fn emit_unreachable(&mut self) { fn emit_unreachable(&mut self) {
log::trace!( log::trace!(
"emit_unreachable: cur_block {} reachable {}", "emit_unreachable: cur_block {} reachable {}",

View file

@ -227,6 +227,34 @@ impl InterpContext {
} }
match &body.blocks[frame.cur_block].terminator { match &body.blocks[frame.cur_block].terminator {
&Terminator::ReturnCallIndirect { sig, table, ref args } => {
let args = args
.iter()
.map(|&arg| {
let arg = body.resolve_alias(arg);
let multivalue = frame.values.get(&arg).unwrap();
assert_eq!(multivalue.len(), 1);
multivalue[0]
})
.collect::<Vec<_>>();
let idx = args.last().unwrap().as_u32().unwrap() as usize;
let func = self.tables[table].elements[idx];
let result = self.call(module, func, &args[..args.len() - 1]);
return result;
}
&Terminator::ReturnCall { func, ref args } => {
let args = args
.iter()
.map(|&arg| {
let arg = body.resolve_alias(arg);
let multivalue = frame.values.get(&arg).unwrap();
assert_eq!(multivalue.len(), 1);
multivalue[0]
})
.collect::<Vec<_>>();
let result = self.call(module, func, &args[..]);
return result;
}
&Terminator::None => { &Terminator::None => {
return InterpResult::Trap(frame.func, frame.cur_block, u32::MAX) return InterpResult::Trap(frame.func, frame.cur_block, u32::MAX)
} }

View file

@ -1,4 +1,5 @@
use super::{Block, FunctionBodyDisplay, Local, Module, Signature, Type, Value, ValueDef}; use super::{Block, FunctionBodyDisplay, Local, Module, Signature, Type, Value, ValueDef};
use crate::{Func, Table};
use crate::backend::WasmFuncBackend; use crate::backend::WasmFuncBackend;
use crate::cfg::CFGInfo; use crate::cfg::CFGInfo;
use crate::entity::{EntityRef, EntityVec, PerEntity}; use crate::entity::{EntityRef, EntityVec, PerEntity};
@ -536,6 +537,15 @@ pub enum Terminator {
Return { Return {
values: Vec<Value>, values: Vec<Value>,
}, },
ReturnCall {
func: Func,
args: Vec<Value>,
},
ReturnCallIndirect {
sig: Signature,
table: Table,
args: Vec<Value>,
},
Unreachable, Unreachable,
None, None,
} }
@ -581,6 +591,26 @@ impl std::fmt::Display for Terminator {
.join(", ") .join(", ")
)?, )?,
Terminator::Unreachable => write!(f, "unreachable")?, Terminator::Unreachable => write!(f, "unreachable")?,
Terminator::ReturnCall { func, args } => write!(
f,
"return_call {}({})",
func,
args
.iter()
.map(|val| format!("{}", val))
.collect::<Vec<_>>()
.join(", ")
)?,
Terminator::ReturnCallIndirect { sig, table, args } => write!(
f,
"return_call_indirect ({};{})({})",
sig,table,
args
.iter()
.map(|val| format!("{}", val))
.collect::<Vec<_>>()
.join(", ")
)?,
} }
Ok(()) Ok(())
} }
@ -611,6 +641,8 @@ impl Terminator {
} }
Terminator::None => {} Terminator::None => {}
Terminator::Unreachable => {} Terminator::Unreachable => {}
Terminator::ReturnCall { func, args } =>{},
Terminator::ReturnCallIndirect { sig, table, args } => {},
} }
} }
@ -638,6 +670,8 @@ impl Terminator {
} }
Terminator::None => {} Terminator::None => {}
Terminator::Unreachable => {} Terminator::Unreachable => {}
Terminator::ReturnCall { func, args } =>{},
Terminator::ReturnCallIndirect { sig, table, args } => {},
} }
} }
@ -717,6 +751,16 @@ impl Terminator {
f(value); f(value);
} }
} }
&Terminator::ReturnCall { func, ref args } => {
for value in args{
f(*value);
}
}
&Terminator::ReturnCallIndirect { sig, table, ref args } => {
for value in args{
f(*value);
}
},
_ => {} _ => {}
} }
} }
@ -735,6 +779,16 @@ impl Terminator {
f(value); f(value);
} }
} }
&mut Terminator::ReturnCall { func, ref mut args } => {
for value in args{
f(value);
}
}
&mut Terminator::ReturnCallIndirect { sig, table, ref mut args } => {
for value in args{
f(value);
}
},
_ => {} _ => {}
} }
} }

View file

@ -8,3 +8,4 @@ pub mod remove_phis;
pub mod resolve_aliases; pub mod resolve_aliases;
pub mod ssa; pub mod ssa;
pub mod trace; pub mod trace;
pub mod reorder_funs;

View file

@ -0,0 +1,69 @@
use std::collections::BTreeMap;
use crate::{ExportKind, Func, FuncDecl, FunctionBody, ImportKind, Module, Operator, ValueDef, entity::EntityRef, Terminator};
pub fn reorder_funcs_in_body(b: &mut FunctionBody, f: &BTreeMap<Func, Func>) {
for v in b.values.values_mut() {
if let ValueDef::Operator(a, _, _) = v {
if let Operator::Call { function_index } = a {
*function_index = *f.get(&*function_index).unwrap();
}
}
}
for k in b.blocks.values_mut(){
if let Terminator::ReturnCall { func, args } = &mut k.terminator{
*func = *f.get(&*func).unwrap();
}
}
}
pub fn reorder_funcs(m: &mut Module, fs: &BTreeMap<Func, Func>) {
let mut n = m.funcs.clone();
for (f, b) in m.funcs.entries() {
let mut b = b.clone();
if let Some(b) = b.body_mut() {
reorder_funcs_in_body(b, fs);
}
n[*fs.get(&f).unwrap()] = b;
}
m.funcs = n;
for t in m.tables.values_mut() {
if let Some(e) = t.func_elements.as_mut() {
for e in e.iter_mut() {
*e = *fs.get(&*e).unwrap();
}
}
}
for i in m.imports.iter_mut() {
if let ImportKind::Func(f) = &mut i.kind {
*f = *fs.get(&*f).unwrap();
}
}
for i in m.exports.iter_mut() {
if let ExportKind::Func(f) = &mut i.kind {
*f = *fs.get(&*f).unwrap();
}
}
}
pub fn fixup_orders(m: &mut Module) {
let mut fs = BTreeMap::new();
let mut a = vec![];
let mut b = vec![];
for (f, d) in m.funcs.entries() {
if let FuncDecl::Import(_, _) = d {
a.push(f)
} else {
b.push(f)
}
}
let mut i = 0;
for v in a{
fs.insert(v, Func::new(i));
i += 1;
}
for v in b{
fs.insert(v, Func::new(i));
i += 1;
}
reorder_funcs(m, &fs);
return;
}