Rewrite the translation layer
This commit is contained in:
parent
5e9aa58261
commit
18b5c57d4c
@ -29,11 +29,17 @@ do
|
|||||||
end
|
end
|
||||||
|
|
||||||
do
|
do
|
||||||
|
local eqz = {}
|
||||||
|
local eq = {}
|
||||||
|
local ne = {}
|
||||||
local le = {}
|
local le = {}
|
||||||
local lt = {}
|
local lt = {}
|
||||||
local ge = {}
|
local ge = {}
|
||||||
local gt = {}
|
local gt = {}
|
||||||
|
|
||||||
|
module.eqz = eqz
|
||||||
|
module.eq = eq
|
||||||
|
module.ne = ne
|
||||||
module.le = le
|
module.le = le
|
||||||
module.lt = lt
|
module.lt = lt
|
||||||
module.ge = ge
|
module.ge = ge
|
||||||
@ -47,6 +53,10 @@ do
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
function eqz.i32(lhs) return to_boolean(lhs == 0) end
|
||||||
|
function eqz.i64(lhs) return to_boolean(lhs == 0) end
|
||||||
|
function eq.i32(lhs, rhs) return to_boolean(lhs == rhs) end
|
||||||
|
function eq.i64(lhs, rhs) return to_boolean(lhs == rhs) end
|
||||||
function ge.u32(lhs, rhs) return to_boolean(u32(lhs) >= u32(rhs)) end
|
function ge.u32(lhs, rhs) return to_boolean(u32(lhs) >= u32(rhs)) end
|
||||||
function ge.u64(lhs, rhs) return to_boolean(u64(lhs) >= u64(rhs)) end
|
function ge.u64(lhs, rhs) return to_boolean(u64(lhs) >= u64(rhs)) end
|
||||||
function gt.u32(lhs, rhs) return to_boolean(u32(lhs) > u32(rhs)) end
|
function gt.u32(lhs, rhs) return to_boolean(u32(lhs) > u32(rhs)) end
|
||||||
@ -55,6 +65,8 @@ do
|
|||||||
function le.u64(lhs, rhs) return to_boolean(u64(lhs) <= u64(rhs)) end
|
function le.u64(lhs, rhs) return to_boolean(u64(lhs) <= u64(rhs)) end
|
||||||
function lt.u32(lhs, rhs) return to_boolean(u32(lhs) < u32(rhs)) end
|
function lt.u32(lhs, rhs) return to_boolean(u32(lhs) < u32(rhs)) end
|
||||||
function lt.u64(lhs, rhs) return to_boolean(u64(lhs) < u64(rhs)) end
|
function lt.u64(lhs, rhs) return to_boolean(u64(lhs) < u64(rhs)) end
|
||||||
|
function ne.i32(lhs, rhs) return to_boolean(lhs ~= rhs) end
|
||||||
|
function ne.i64(lhs, rhs) return to_boolean(lhs ~= rhs) end
|
||||||
end
|
end
|
||||||
|
|
||||||
do
|
do
|
||||||
|
@ -15,11 +15,17 @@ do
|
|||||||
end
|
end
|
||||||
|
|
||||||
do
|
do
|
||||||
|
local eqz = {}
|
||||||
|
local eq = {}
|
||||||
|
local ne = {}
|
||||||
local le = {}
|
local le = {}
|
||||||
local lt = {}
|
local lt = {}
|
||||||
local ge = {}
|
local ge = {}
|
||||||
local gt = {}
|
local gt = {}
|
||||||
|
|
||||||
|
module.eqz = eqz
|
||||||
|
module.eq = eq
|
||||||
|
module.ne = ne
|
||||||
module.le = le
|
module.le = le
|
||||||
module.lt = lt
|
module.lt = lt
|
||||||
module.ge = ge
|
module.ge = ge
|
||||||
@ -37,6 +43,10 @@ do
|
|||||||
return x
|
return x
|
||||||
end
|
end
|
||||||
|
|
||||||
|
function eqz.i32(lhs) return lhs == 0 and 1 or 0 end
|
||||||
|
function eqz.i64(lhs) return lhs == 0 and 1 or 0 end
|
||||||
|
function eq.i32(lhs, rhs) return lhs == rhs and 1 or 0 end
|
||||||
|
function eq.i64(lhs, rhs) return lhs == rhs and 1 or 0 end
|
||||||
function ge.u32(lhs, rhs) return unsign_i32(lhs) >= unsign_i32(rhs) and 1 or 0 end
|
function ge.u32(lhs, rhs) return unsign_i32(lhs) >= unsign_i32(rhs) and 1 or 0 end
|
||||||
function ge.u64(lhs, rhs) return unsign_i64(lhs) >= unsign_i64(rhs) and 1 or 0 end
|
function ge.u64(lhs, rhs) return unsign_i64(lhs) >= unsign_i64(rhs) and 1 or 0 end
|
||||||
function gt.u32(lhs, rhs) return unsign_i32(lhs) > unsign_i32(rhs) and 1 or 0 end
|
function gt.u32(lhs, rhs) return unsign_i32(lhs) > unsign_i32(rhs) and 1 or 0 end
|
||||||
@ -45,6 +55,8 @@ do
|
|||||||
function le.u64(lhs, rhs) return unsign_i64(lhs) <= unsign_i64(rhs) and 1 or 0 end
|
function le.u64(lhs, rhs) return unsign_i64(lhs) <= unsign_i64(rhs) and 1 or 0 end
|
||||||
function lt.u32(lhs, rhs) return unsign_i32(lhs) < unsign_i32(rhs) and 1 or 0 end
|
function lt.u32(lhs, rhs) return unsign_i32(lhs) < unsign_i32(rhs) and 1 or 0 end
|
||||||
function lt.u64(lhs, rhs) return unsign_i64(lhs) < unsign_i64(rhs) and 1 or 0 end
|
function lt.u64(lhs, rhs) return unsign_i64(lhs) < unsign_i64(rhs) and 1 or 0 end
|
||||||
|
function ne.i32(lhs, rhs) return lhs ~= rhs and 1 or 0 end
|
||||||
|
function ne.i64(lhs, rhs) return lhs ~= rhs and 1 or 0 end
|
||||||
end
|
end
|
||||||
|
|
||||||
do
|
do
|
||||||
|
415
src/backend/ast/data.rs
Normal file
415
src/backend/ast/data.rs
Normal file
@ -0,0 +1,415 @@
|
|||||||
|
use std::ops::Range;
|
||||||
|
|
||||||
|
use parity_wasm::elements::BrTableData;
|
||||||
|
|
||||||
|
use crate::backend::visitor::data::Visitor;
|
||||||
|
|
||||||
|
use super::operation::{BinOp, Load, Store, UnOp};
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct Select {
|
||||||
|
pub cond: Box<Expression>,
|
||||||
|
pub a: Box<Expression>,
|
||||||
|
pub b: Box<Expression>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Select {
|
||||||
|
fn accept<V: Visitor>(&self, visitor: &mut V) {
|
||||||
|
visitor.visit_select(self);
|
||||||
|
|
||||||
|
self.cond.accept(visitor);
|
||||||
|
self.a.accept(visitor);
|
||||||
|
self.b.accept(visitor);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct GetLocal {
|
||||||
|
pub var: u32,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl GetLocal {
|
||||||
|
fn accept<V: Visitor>(&self, visitor: &mut V) {
|
||||||
|
visitor.visit_get_local(self);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct GetGlobal {
|
||||||
|
pub var: u32,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl GetGlobal {
|
||||||
|
fn accept<V: Visitor>(&self, visitor: &mut V) {
|
||||||
|
visitor.visit_get_global(self);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct AnyLoad {
|
||||||
|
pub op: Load,
|
||||||
|
pub offset: u32,
|
||||||
|
pub pointer: Box<Expression>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl AnyLoad {
|
||||||
|
fn accept<V: Visitor>(&self, visitor: &mut V) {
|
||||||
|
visitor.visit_any_load(self);
|
||||||
|
|
||||||
|
self.pointer.accept(visitor);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct MemorySize {
|
||||||
|
pub memory: u8,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl MemorySize {
|
||||||
|
fn accept<V: Visitor>(&self, visitor: &mut V) {
|
||||||
|
visitor.visit_memory_size(self);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct MemoryGrow {
|
||||||
|
pub memory: u8,
|
||||||
|
pub value: Box<Expression>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl MemoryGrow {
|
||||||
|
fn accept<V: Visitor>(&self, visitor: &mut V) {
|
||||||
|
visitor.visit_memory_grow(self);
|
||||||
|
|
||||||
|
self.value.accept(visitor);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy)]
|
||||||
|
pub enum Value {
|
||||||
|
I32(i32),
|
||||||
|
I64(i64),
|
||||||
|
F32(f32),
|
||||||
|
F64(f64),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Value {
|
||||||
|
fn accept<V: Visitor>(&self, visitor: &mut V) {
|
||||||
|
visitor.visit_value(self);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct AnyUnOp {
|
||||||
|
pub op: UnOp,
|
||||||
|
pub rhs: Box<Expression>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl AnyUnOp {
|
||||||
|
fn accept<V: Visitor>(&self, visitor: &mut V) {
|
||||||
|
visitor.visit_any_unop(self);
|
||||||
|
|
||||||
|
self.rhs.accept(visitor);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct AnyBinOp {
|
||||||
|
pub op: BinOp,
|
||||||
|
pub lhs: Box<Expression>,
|
||||||
|
pub rhs: Box<Expression>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl AnyBinOp {
|
||||||
|
fn accept<V: Visitor>(&self, visitor: &mut V) {
|
||||||
|
visitor.visit_any_binop(self);
|
||||||
|
|
||||||
|
self.lhs.accept(visitor);
|
||||||
|
self.rhs.accept(visitor);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub enum Expression {
|
||||||
|
Recall(usize),
|
||||||
|
Select(Select),
|
||||||
|
GetLocal(GetLocal),
|
||||||
|
GetGlobal(GetGlobal),
|
||||||
|
AnyLoad(AnyLoad),
|
||||||
|
MemorySize(MemorySize),
|
||||||
|
MemoryGrow(MemoryGrow),
|
||||||
|
Value(Value),
|
||||||
|
AnyUnOp(AnyUnOp),
|
||||||
|
AnyBinOp(AnyBinOp),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Expression {
|
||||||
|
fn accept<V: Visitor>(&self, visitor: &mut V) {
|
||||||
|
visitor.visit_expression(self);
|
||||||
|
|
||||||
|
match self {
|
||||||
|
Expression::Recall(v) => visitor.visit_recall(*v),
|
||||||
|
Expression::Select(v) => v.accept(visitor),
|
||||||
|
Expression::GetLocal(v) => v.accept(visitor),
|
||||||
|
Expression::GetGlobal(v) => v.accept(visitor),
|
||||||
|
Expression::AnyLoad(v) => v.accept(visitor),
|
||||||
|
Expression::MemorySize(v) => v.accept(visitor),
|
||||||
|
Expression::MemoryGrow(v) => v.accept(visitor),
|
||||||
|
Expression::Value(v) => v.accept(visitor),
|
||||||
|
Expression::AnyUnOp(v) => v.accept(visitor),
|
||||||
|
Expression::AnyBinOp(v) => v.accept(visitor),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn is_recalling(&self, wanted: usize) -> bool {
|
||||||
|
match *self {
|
||||||
|
Expression::Recall(v) => v == wanted,
|
||||||
|
_ => false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Memorize {
|
||||||
|
pub var: usize,
|
||||||
|
pub value: Expression,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Memorize {
|
||||||
|
fn accept<V: Visitor>(&self, visitor: &mut V) {
|
||||||
|
visitor.visit_memorize(self);
|
||||||
|
|
||||||
|
self.value.accept(visitor);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Forward {
|
||||||
|
pub body: Vec<Statement>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Forward {
|
||||||
|
fn accept<V: Visitor>(&self, visitor: &mut V) {
|
||||||
|
visitor.visit_forward(self);
|
||||||
|
|
||||||
|
for v in &self.body {
|
||||||
|
v.accept(visitor);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Backward {
|
||||||
|
pub body: Vec<Statement>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Backward {
|
||||||
|
fn accept<V: Visitor>(&self, visitor: &mut V) {
|
||||||
|
visitor.visit_backward(self);
|
||||||
|
|
||||||
|
for v in &self.body {
|
||||||
|
v.accept(visitor);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct If {
|
||||||
|
pub cond: Expression,
|
||||||
|
pub body: Vec<Statement>,
|
||||||
|
pub other: Option<Vec<Statement>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl If {
|
||||||
|
fn accept<V: Visitor>(&self, visitor: &mut V) {
|
||||||
|
visitor.visit_if(self);
|
||||||
|
|
||||||
|
self.cond.accept(visitor);
|
||||||
|
|
||||||
|
for v in &self.body {
|
||||||
|
v.accept(visitor);
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(v) = &self.other {
|
||||||
|
for v in v {
|
||||||
|
v.accept(visitor);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Br {
|
||||||
|
pub target: u32,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Br {
|
||||||
|
fn accept<V: Visitor>(&self, visitor: &mut V) {
|
||||||
|
visitor.visit_br(self);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct BrIf {
|
||||||
|
pub cond: Expression,
|
||||||
|
pub target: u32,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl BrIf {
|
||||||
|
fn accept<V: Visitor>(&self, visitor: &mut V) {
|
||||||
|
visitor.visit_br_if(self);
|
||||||
|
|
||||||
|
self.cond.accept(visitor);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct BrTable {
|
||||||
|
pub cond: Expression,
|
||||||
|
pub data: BrTableData,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl BrTable {
|
||||||
|
fn accept<V: Visitor>(&self, visitor: &mut V) {
|
||||||
|
visitor.visit_br_table(self);
|
||||||
|
|
||||||
|
self.cond.accept(visitor);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Return {
|
||||||
|
pub list: Vec<Expression>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Return {
|
||||||
|
fn accept<V: Visitor>(&self, visitor: &mut V) {
|
||||||
|
visitor.visit_return(self);
|
||||||
|
|
||||||
|
for v in &self.list {
|
||||||
|
v.accept(visitor);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Call {
|
||||||
|
pub func: u32,
|
||||||
|
pub result: Range<u32>,
|
||||||
|
pub param_list: Vec<Expression>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Call {
|
||||||
|
fn accept<V: Visitor>(&self, visitor: &mut V) {
|
||||||
|
visitor.visit_call(self);
|
||||||
|
|
||||||
|
for v in &self.param_list {
|
||||||
|
v.accept(visitor);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct CallIndirect {
|
||||||
|
pub table: u8,
|
||||||
|
pub index: Expression,
|
||||||
|
pub result: Range<u32>,
|
||||||
|
pub param_list: Vec<Expression>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl CallIndirect {
|
||||||
|
fn accept<V: Visitor>(&self, visitor: &mut V) {
|
||||||
|
visitor.visit_call_indirect(self);
|
||||||
|
|
||||||
|
self.index.accept(visitor);
|
||||||
|
|
||||||
|
for v in &self.param_list {
|
||||||
|
v.accept(visitor);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct SetLocal {
|
||||||
|
pub var: u32,
|
||||||
|
pub value: Expression,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SetLocal {
|
||||||
|
fn accept<V: Visitor>(&self, visitor: &mut V) {
|
||||||
|
visitor.visit_set_local(self);
|
||||||
|
|
||||||
|
self.value.accept(visitor);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct SetGlobal {
|
||||||
|
pub var: u32,
|
||||||
|
pub value: Expression,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SetGlobal {
|
||||||
|
fn accept<V: Visitor>(&self, visitor: &mut V) {
|
||||||
|
visitor.visit_set_global(self);
|
||||||
|
|
||||||
|
self.value.accept(visitor);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct AnyStore {
|
||||||
|
pub op: Store,
|
||||||
|
pub offset: u32,
|
||||||
|
pub pointer: Expression,
|
||||||
|
pub value: Expression,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl AnyStore {
|
||||||
|
fn accept<V: Visitor>(&self, visitor: &mut V) {
|
||||||
|
visitor.visit_any_store(self);
|
||||||
|
|
||||||
|
self.pointer.accept(visitor);
|
||||||
|
self.value.accept(visitor);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub enum Statement {
|
||||||
|
Unreachable,
|
||||||
|
Memorize(Memorize),
|
||||||
|
Forward(Forward),
|
||||||
|
Backward(Backward),
|
||||||
|
If(If),
|
||||||
|
Br(Br),
|
||||||
|
BrIf(BrIf),
|
||||||
|
BrTable(BrTable),
|
||||||
|
Return(Return),
|
||||||
|
Call(Call),
|
||||||
|
CallIndirect(CallIndirect),
|
||||||
|
SetLocal(SetLocal),
|
||||||
|
SetGlobal(SetGlobal),
|
||||||
|
AnyStore(AnyStore),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Statement {
|
||||||
|
fn accept<V: Visitor>(&self, visitor: &mut V) {
|
||||||
|
match self {
|
||||||
|
Statement::Unreachable => visitor.visit_unreachable(),
|
||||||
|
Statement::Memorize(v) => v.accept(visitor),
|
||||||
|
Statement::Forward(v) => v.accept(visitor),
|
||||||
|
Statement::Backward(v) => v.accept(visitor),
|
||||||
|
Statement::If(v) => v.accept(visitor),
|
||||||
|
Statement::Br(v) => v.accept(visitor),
|
||||||
|
Statement::BrIf(v) => v.accept(visitor),
|
||||||
|
Statement::BrTable(v) => v.accept(visitor),
|
||||||
|
Statement::Return(v) => v.accept(visitor),
|
||||||
|
Statement::Call(v) => v.accept(visitor),
|
||||||
|
Statement::CallIndirect(v) => v.accept(visitor),
|
||||||
|
Statement::SetLocal(v) => v.accept(visitor),
|
||||||
|
Statement::SetGlobal(v) => v.accept(visitor),
|
||||||
|
Statement::AnyStore(v) => v.accept(visitor),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Function {
|
||||||
|
pub num_param: u32,
|
||||||
|
pub num_local: u32,
|
||||||
|
pub num_stack: u32,
|
||||||
|
pub body: Vec<Statement>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Function {
|
||||||
|
pub fn accept<V: Visitor>(&self, visitor: &mut V) {
|
||||||
|
for v in &self.body {
|
||||||
|
v.accept(visitor);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
3
src/backend/ast/mod.rs
Normal file
3
src/backend/ast/mod.rs
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
pub mod data;
|
||||||
|
mod operation;
|
||||||
|
pub mod transformer;
|
@ -2,13 +2,8 @@ use std::convert::TryFrom;
|
|||||||
|
|
||||||
use parity_wasm::elements::Instruction;
|
use parity_wasm::elements::Instruction;
|
||||||
|
|
||||||
type Name = (&'static str, &'static str);
|
|
||||||
|
|
||||||
pub trait Named {
|
|
||||||
fn as_name(&self) -> Name;
|
|
||||||
}
|
|
||||||
|
|
||||||
#[allow(non_camel_case_types)]
|
#[allow(non_camel_case_types)]
|
||||||
|
#[derive(Clone, Copy)]
|
||||||
pub enum Load {
|
pub enum Load {
|
||||||
I32,
|
I32,
|
||||||
I64,
|
I64,
|
||||||
@ -26,23 +21,23 @@ pub enum Load {
|
|||||||
I64_U32,
|
I64_U32,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Named for Load {
|
impl Load {
|
||||||
fn as_name(&self) -> Name {
|
pub fn as_name(self) -> &'static str {
|
||||||
match self {
|
match self {
|
||||||
Self::I32 => ("load", "i32"),
|
Self::I32 => "i32",
|
||||||
Self::I64 => ("load", "i64"),
|
Self::I64 => "i64",
|
||||||
Self::F32 => ("load", "f32"),
|
Self::F32 => "f32",
|
||||||
Self::F64 => ("load", "f64"),
|
Self::F64 => "f64",
|
||||||
Self::I32_I8 => ("load", "i32_i8"),
|
Self::I32_I8 => "i32_i8",
|
||||||
Self::I32_U8 => ("load", "i32_u8"),
|
Self::I32_U8 => "i32_u8",
|
||||||
Self::I32_I16 => ("load", "i32_i16"),
|
Self::I32_I16 => "i32_i16",
|
||||||
Self::I32_U16 => ("load", "i32_u16"),
|
Self::I32_U16 => "i32_u16",
|
||||||
Self::I64_I8 => ("load", "i64_i8"),
|
Self::I64_I8 => "i64_i8",
|
||||||
Self::I64_U8 => ("load", "i64_u8"),
|
Self::I64_U8 => "i64_u8",
|
||||||
Self::I64_I16 => ("load", "i64_i16"),
|
Self::I64_I16 => "i64_i16",
|
||||||
Self::I64_U16 => ("load", "i64_u16"),
|
Self::I64_U16 => "i64_u16",
|
||||||
Self::I64_I32 => ("load", "i64_i32"),
|
Self::I64_I32 => "i64_i32",
|
||||||
Self::I64_U32 => ("load", "i64_u32"),
|
Self::I64_U32 => "i64_u32",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -74,6 +69,7 @@ impl TryFrom<&Instruction> for Load {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[allow(non_camel_case_types)]
|
#[allow(non_camel_case_types)]
|
||||||
|
#[derive(Clone, Copy)]
|
||||||
pub enum Store {
|
pub enum Store {
|
||||||
I32,
|
I32,
|
||||||
I64,
|
I64,
|
||||||
@ -86,18 +82,18 @@ pub enum Store {
|
|||||||
I64_N32,
|
I64_N32,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Named for Store {
|
impl Store {
|
||||||
fn as_name(&self) -> Name {
|
pub fn as_name(self) -> &'static str {
|
||||||
match self {
|
match self {
|
||||||
Self::I32 => ("store", "i32"),
|
Self::I32 => "i32",
|
||||||
Self::I64 => ("store", "i64"),
|
Self::I64 => "i64",
|
||||||
Self::F32 => ("store", "f32"),
|
Self::F32 => "f32",
|
||||||
Self::F64 => ("store", "f64"),
|
Self::F64 => "f64",
|
||||||
Self::I32_N8 => ("store", "i32_n8"),
|
Self::I32_N8 => "i32_n8",
|
||||||
Self::I32_N16 => ("store", "i32_n16"),
|
Self::I32_N16 => "i32_n16",
|
||||||
Self::I64_N8 => ("store", "i64_n8"),
|
Self::I64_N8 => "i64_n8",
|
||||||
Self::I64_N16 => ("store", "i64_n16"),
|
Self::I64_N16 => "i64_n16",
|
||||||
Self::I64_N32 => ("store", "i64_n32"),
|
Self::I64_N32 => "i64_n32",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -124,7 +120,10 @@ impl TryFrom<&Instruction> for Store {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[allow(non_camel_case_types)]
|
#[allow(non_camel_case_types)]
|
||||||
|
#[derive(Clone, Copy)]
|
||||||
pub enum UnOp {
|
pub enum UnOp {
|
||||||
|
Eqz_I32,
|
||||||
|
Eqz_I64,
|
||||||
Clz_I32,
|
Clz_I32,
|
||||||
Ctz_I32,
|
Ctz_I32,
|
||||||
Popcnt_I32,
|
Popcnt_I32,
|
||||||
@ -132,6 +131,7 @@ pub enum UnOp {
|
|||||||
Ctz_I64,
|
Ctz_I64,
|
||||||
Popcnt_I64,
|
Popcnt_I64,
|
||||||
Abs_FN,
|
Abs_FN,
|
||||||
|
Neg_FN,
|
||||||
Ceil_FN,
|
Ceil_FN,
|
||||||
Floor_FN,
|
Floor_FN,
|
||||||
Trunc_FN,
|
Trunc_FN,
|
||||||
@ -165,9 +165,20 @@ pub enum UnOp {
|
|||||||
Reinterpret_F64_I64,
|
Reinterpret_F64_I64,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Named for UnOp {
|
impl UnOp {
|
||||||
fn as_name(&self) -> Name {
|
pub fn as_operator(self) -> Option<&'static str> {
|
||||||
|
let op = match self {
|
||||||
|
Self::Neg_FN => "-",
|
||||||
|
_ => return None,
|
||||||
|
};
|
||||||
|
|
||||||
|
Some(op)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn as_name(self) -> (&'static str, &'static str) {
|
||||||
match self {
|
match self {
|
||||||
|
Self::Eqz_I32 => ("eqz", "i32"),
|
||||||
|
Self::Eqz_I64 => ("eqz", "i64"),
|
||||||
Self::Clz_I32 => ("clz", "i32"),
|
Self::Clz_I32 => ("clz", "i32"),
|
||||||
Self::Ctz_I32 => ("ctz", "i32"),
|
Self::Ctz_I32 => ("ctz", "i32"),
|
||||||
Self::Popcnt_I32 => ("popcnt", "i32"),
|
Self::Popcnt_I32 => ("popcnt", "i32"),
|
||||||
@ -175,10 +186,11 @@ impl Named for UnOp {
|
|||||||
Self::Ctz_I64 => ("ctz", "i64"),
|
Self::Ctz_I64 => ("ctz", "i64"),
|
||||||
Self::Popcnt_I64 => ("popcnt", "i64"),
|
Self::Popcnt_I64 => ("popcnt", "i64"),
|
||||||
Self::Abs_FN => ("math", "abs"),
|
Self::Abs_FN => ("math", "abs"),
|
||||||
|
Self::Neg_FN => ("neg", "num"),
|
||||||
Self::Ceil_FN => ("math", "ceil"),
|
Self::Ceil_FN => ("math", "ceil"),
|
||||||
Self::Floor_FN => ("math", "floor"),
|
Self::Floor_FN => ("math", "floor"),
|
||||||
Self::Trunc_FN => ("trunc", "f"),
|
Self::Trunc_FN => ("trunc", "num"),
|
||||||
Self::Nearest_FN => ("nearest", "f"),
|
Self::Nearest_FN => ("nearest", "num"),
|
||||||
Self::Sqrt_FN => ("math", "sqrt"),
|
Self::Sqrt_FN => ("math", "sqrt"),
|
||||||
Self::Copysign_FN => ("math", "sign"),
|
Self::Copysign_FN => ("math", "sign"),
|
||||||
Self::Wrap_I32_I64 => ("wrap", "i64_i32"),
|
Self::Wrap_I32_I64 => ("wrap", "i64_i32"),
|
||||||
@ -215,6 +227,8 @@ impl TryFrom<&Instruction> for UnOp {
|
|||||||
|
|
||||||
fn try_from(inst: &Instruction) -> Result<Self, Self::Error> {
|
fn try_from(inst: &Instruction) -> Result<Self, Self::Error> {
|
||||||
let result = match inst {
|
let result = match inst {
|
||||||
|
Instruction::I32Eqz => Self::Eqz_I32,
|
||||||
|
Instruction::I64Eqz => Self::Eqz_I64,
|
||||||
Instruction::I32Clz => Self::Clz_I32,
|
Instruction::I32Clz => Self::Clz_I32,
|
||||||
Instruction::I32Ctz => Self::Ctz_I32,
|
Instruction::I32Ctz => Self::Ctz_I32,
|
||||||
Instruction::I32Popcnt => Self::Popcnt_I32,
|
Instruction::I32Popcnt => Self::Popcnt_I32,
|
||||||
@ -222,6 +236,7 @@ impl TryFrom<&Instruction> for UnOp {
|
|||||||
Instruction::I64Ctz => Self::Ctz_I64,
|
Instruction::I64Ctz => Self::Ctz_I64,
|
||||||
Instruction::I64Popcnt => Self::Popcnt_I64,
|
Instruction::I64Popcnt => Self::Popcnt_I64,
|
||||||
Instruction::F32Abs | Instruction::F64Abs => Self::Abs_FN,
|
Instruction::F32Abs | Instruction::F64Abs => Self::Abs_FN,
|
||||||
|
Instruction::F32Neg | Instruction::F64Neg => Self::Neg_FN,
|
||||||
Instruction::F32Ceil | Instruction::F64Ceil => Self::Ceil_FN,
|
Instruction::F32Ceil | Instruction::F64Ceil => Self::Ceil_FN,
|
||||||
Instruction::F32Floor | Instruction::F64Floor => Self::Floor_FN,
|
Instruction::F32Floor | Instruction::F64Floor => Self::Floor_FN,
|
||||||
Instruction::F32Trunc | Instruction::F64Trunc => Self::Trunc_FN,
|
Instruction::F32Trunc | Instruction::F64Trunc => Self::Trunc_FN,
|
||||||
@ -261,15 +276,31 @@ impl TryFrom<&Instruction> for UnOp {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[allow(non_camel_case_types)]
|
#[allow(non_camel_case_types)]
|
||||||
|
#[derive(Clone, Copy)]
|
||||||
pub enum BinOp {
|
pub enum BinOp {
|
||||||
|
Eq_I32,
|
||||||
|
Ne_I32,
|
||||||
|
LtS_I32,
|
||||||
LtU_I32,
|
LtU_I32,
|
||||||
|
GtS_I32,
|
||||||
GtU_I32,
|
GtU_I32,
|
||||||
|
LeS_I32,
|
||||||
LeU_I32,
|
LeU_I32,
|
||||||
|
GeS_I32,
|
||||||
GeU_I32,
|
GeU_I32,
|
||||||
|
Eq_I64,
|
||||||
|
Ne_I64,
|
||||||
|
LtS_I64,
|
||||||
LtU_I64,
|
LtU_I64,
|
||||||
|
GtS_I64,
|
||||||
GtU_I64,
|
GtU_I64,
|
||||||
|
LeS_I64,
|
||||||
LeU_I64,
|
LeU_I64,
|
||||||
|
GeS_I64,
|
||||||
GeU_I64,
|
GeU_I64,
|
||||||
|
Add_I32,
|
||||||
|
Sub_I32,
|
||||||
|
Mul_I32,
|
||||||
DivS_I32,
|
DivS_I32,
|
||||||
DivU_I32,
|
DivU_I32,
|
||||||
RemS_I32,
|
RemS_I32,
|
||||||
@ -282,6 +313,9 @@ pub enum BinOp {
|
|||||||
ShrU_I32,
|
ShrU_I32,
|
||||||
Rotl_I32,
|
Rotl_I32,
|
||||||
Rotr_I32,
|
Rotr_I32,
|
||||||
|
Add_I64,
|
||||||
|
Sub_I64,
|
||||||
|
Mul_I64,
|
||||||
DivS_I64,
|
DivS_I64,
|
||||||
DivU_I64,
|
DivU_I64,
|
||||||
RemS_I64,
|
RemS_I64,
|
||||||
@ -294,21 +328,59 @@ pub enum BinOp {
|
|||||||
ShrU_I64,
|
ShrU_I64,
|
||||||
Rotl_I64,
|
Rotl_I64,
|
||||||
Rotr_I64,
|
Rotr_I64,
|
||||||
|
Eq_FN,
|
||||||
|
Ne_FN,
|
||||||
|
Lt_FN,
|
||||||
|
Gt_FN,
|
||||||
|
Le_FN,
|
||||||
|
Ge_FN,
|
||||||
|
Add_FN,
|
||||||
|
Sub_FN,
|
||||||
|
Mul_FN,
|
||||||
|
Div_FN,
|
||||||
Min_FN,
|
Min_FN,
|
||||||
Max_FN,
|
Max_FN,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Named for BinOp {
|
impl BinOp {
|
||||||
fn as_name(&self) -> Name {
|
pub fn as_operator(self) -> Option<&'static str> {
|
||||||
|
let op = match self {
|
||||||
|
Self::Add_I32 | Self::Add_I64 | Self::Add_FN => "+",
|
||||||
|
Self::Sub_I32 | Self::Sub_I64 | Self::Sub_FN => "-",
|
||||||
|
Self::Mul_I32 | Self::Mul_I64 | Self::Mul_FN => "*",
|
||||||
|
Self::Div_FN => "/",
|
||||||
|
Self::RemS_I32 | Self::RemU_I32 | Self::RemS_I64 | Self::RemU_I64 => "%",
|
||||||
|
_ => return None,
|
||||||
|
};
|
||||||
|
|
||||||
|
Some(op)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn as_name(self) -> (&'static str, &'static str) {
|
||||||
match self {
|
match self {
|
||||||
|
Self::Eq_I32 => ("eq", "i32"),
|
||||||
|
Self::Ne_I32 => ("ne", "i32"),
|
||||||
|
Self::LtS_I32 => ("lt", "i32"),
|
||||||
Self::LtU_I32 => ("lt", "u32"),
|
Self::LtU_I32 => ("lt", "u32"),
|
||||||
|
Self::GtS_I32 => ("gt", "i32"),
|
||||||
Self::GtU_I32 => ("gt", "u32"),
|
Self::GtU_I32 => ("gt", "u32"),
|
||||||
|
Self::LeS_I32 => ("le", "i32"),
|
||||||
Self::LeU_I32 => ("le", "u32"),
|
Self::LeU_I32 => ("le", "u32"),
|
||||||
|
Self::GeS_I32 => ("ge", "i32"),
|
||||||
Self::GeU_I32 => ("ge", "u32"),
|
Self::GeU_I32 => ("ge", "u32"),
|
||||||
|
Self::Eq_I64 => ("eq", "i64"),
|
||||||
|
Self::Ne_I64 => ("ne", "i64"),
|
||||||
|
Self::LtS_I64 => ("lt", "i64"),
|
||||||
Self::LtU_I64 => ("lt", "u64"),
|
Self::LtU_I64 => ("lt", "u64"),
|
||||||
|
Self::GtS_I64 => ("gt", "i64"),
|
||||||
Self::GtU_I64 => ("gt", "u64"),
|
Self::GtU_I64 => ("gt", "u64"),
|
||||||
|
Self::LeS_I64 => ("le", "i64"),
|
||||||
Self::LeU_I64 => ("le", "u64"),
|
Self::LeU_I64 => ("le", "u64"),
|
||||||
|
Self::GeS_I64 => ("ge", "i64"),
|
||||||
Self::GeU_I64 => ("ge", "u64"),
|
Self::GeU_I64 => ("ge", "u64"),
|
||||||
|
Self::Add_I32 => ("add", "i32"),
|
||||||
|
Self::Sub_I32 => ("sub", "i32"),
|
||||||
|
Self::Mul_I32 => ("mul", "i32"),
|
||||||
Self::DivS_I32 => ("div", "i32"),
|
Self::DivS_I32 => ("div", "i32"),
|
||||||
Self::DivU_I32 => ("div", "u32"),
|
Self::DivU_I32 => ("div", "u32"),
|
||||||
Self::RemS_I32 => ("rem", "i32"),
|
Self::RemS_I32 => ("rem", "i32"),
|
||||||
@ -321,6 +393,9 @@ impl Named for BinOp {
|
|||||||
Self::ShrU_I32 => ("shr", "u32"),
|
Self::ShrU_I32 => ("shr", "u32"),
|
||||||
Self::Rotl_I32 => ("rotl", "i32"),
|
Self::Rotl_I32 => ("rotl", "i32"),
|
||||||
Self::Rotr_I32 => ("rotr", "i32"),
|
Self::Rotr_I32 => ("rotr", "i32"),
|
||||||
|
Self::Add_I64 => ("add", "i64"),
|
||||||
|
Self::Sub_I64 => ("sub", "i64"),
|
||||||
|
Self::Mul_I64 => ("mul", "i64"),
|
||||||
Self::DivS_I64 => ("div", "i64"),
|
Self::DivS_I64 => ("div", "i64"),
|
||||||
Self::DivU_I64 => ("div", "u64"),
|
Self::DivU_I64 => ("div", "u64"),
|
||||||
Self::RemS_I64 => ("rem", "i64"),
|
Self::RemS_I64 => ("rem", "i64"),
|
||||||
@ -333,6 +408,16 @@ impl Named for BinOp {
|
|||||||
Self::ShrU_I64 => ("shr", "u64"),
|
Self::ShrU_I64 => ("shr", "u64"),
|
||||||
Self::Rotl_I64 => ("rotl", "i64"),
|
Self::Rotl_I64 => ("rotl", "i64"),
|
||||||
Self::Rotr_I64 => ("rotr", "i64"),
|
Self::Rotr_I64 => ("rotr", "i64"),
|
||||||
|
Self::Eq_FN => ("eq", "num"),
|
||||||
|
Self::Ne_FN => ("ne", "num"),
|
||||||
|
Self::Lt_FN => ("lt", "num"),
|
||||||
|
Self::Gt_FN => ("gt", "num"),
|
||||||
|
Self::Le_FN => ("le", "num"),
|
||||||
|
Self::Ge_FN => ("ge", "num"),
|
||||||
|
Self::Add_FN => ("add", "num"),
|
||||||
|
Self::Sub_FN => ("sub", "num"),
|
||||||
|
Self::Mul_FN => ("mul", "num"),
|
||||||
|
Self::Div_FN => ("div", "num"),
|
||||||
Self::Min_FN => ("math", "min"),
|
Self::Min_FN => ("math", "min"),
|
||||||
Self::Max_FN => ("math", "max"),
|
Self::Max_FN => ("math", "max"),
|
||||||
}
|
}
|
||||||
@ -344,14 +429,29 @@ impl TryFrom<&Instruction> for BinOp {
|
|||||||
|
|
||||||
fn try_from(inst: &Instruction) -> Result<Self, Self::Error> {
|
fn try_from(inst: &Instruction) -> Result<Self, Self::Error> {
|
||||||
let result = match inst {
|
let result = match inst {
|
||||||
|
Instruction::I32Eq => Self::Eq_I32,
|
||||||
|
Instruction::I32Ne => Self::Ne_I32,
|
||||||
|
Instruction::I32LtS => Self::LtS_I32,
|
||||||
Instruction::I32LtU => Self::LtU_I32,
|
Instruction::I32LtU => Self::LtU_I32,
|
||||||
|
Instruction::I32GtS => Self::GtS_I32,
|
||||||
Instruction::I32GtU => Self::GtU_I32,
|
Instruction::I32GtU => Self::GtU_I32,
|
||||||
|
Instruction::I32LeS => Self::LeS_I32,
|
||||||
Instruction::I32LeU => Self::LeU_I32,
|
Instruction::I32LeU => Self::LeU_I32,
|
||||||
|
Instruction::I32GeS => Self::GeS_I32,
|
||||||
Instruction::I32GeU => Self::GeU_I32,
|
Instruction::I32GeU => Self::GeU_I32,
|
||||||
|
Instruction::I64Eq => Self::Eq_I64,
|
||||||
|
Instruction::I64Ne => Self::Ne_I64,
|
||||||
|
Instruction::I64LtS => Self::LtS_I64,
|
||||||
Instruction::I64LtU => Self::LtU_I64,
|
Instruction::I64LtU => Self::LtU_I64,
|
||||||
|
Instruction::I64GtS => Self::GtS_I64,
|
||||||
Instruction::I64GtU => Self::GtU_I64,
|
Instruction::I64GtU => Self::GtU_I64,
|
||||||
|
Instruction::I64LeS => Self::LeS_I64,
|
||||||
Instruction::I64LeU => Self::LeU_I64,
|
Instruction::I64LeU => Self::LeU_I64,
|
||||||
|
Instruction::I64GeS => Self::GeS_I64,
|
||||||
Instruction::I64GeU => Self::GeU_I64,
|
Instruction::I64GeU => Self::GeU_I64,
|
||||||
|
Instruction::I32Add => Self::Add_I32,
|
||||||
|
Instruction::I32Sub => Self::Sub_I32,
|
||||||
|
Instruction::I32Mul => Self::Mul_I32,
|
||||||
Instruction::I32DivS => Self::DivS_I32,
|
Instruction::I32DivS => Self::DivS_I32,
|
||||||
Instruction::I32DivU => Self::DivU_I32,
|
Instruction::I32DivU => Self::DivU_I32,
|
||||||
Instruction::I32RemS => Self::RemS_I32,
|
Instruction::I32RemS => Self::RemS_I32,
|
||||||
@ -364,6 +464,9 @@ impl TryFrom<&Instruction> for BinOp {
|
|||||||
Instruction::I32ShrU => Self::ShrU_I32,
|
Instruction::I32ShrU => Self::ShrU_I32,
|
||||||
Instruction::I32Rotl => Self::Rotl_I32,
|
Instruction::I32Rotl => Self::Rotl_I32,
|
||||||
Instruction::I32Rotr => Self::Rotr_I32,
|
Instruction::I32Rotr => Self::Rotr_I32,
|
||||||
|
Instruction::I64Add => Self::Add_I64,
|
||||||
|
Instruction::I64Sub => Self::Sub_I64,
|
||||||
|
Instruction::I64Mul => Self::Mul_I64,
|
||||||
Instruction::I64DivS => Self::DivS_I64,
|
Instruction::I64DivS => Self::DivS_I64,
|
||||||
Instruction::I64DivU => Self::DivU_I64,
|
Instruction::I64DivU => Self::DivU_I64,
|
||||||
Instruction::I64RemS => Self::RemS_I64,
|
Instruction::I64RemS => Self::RemS_I64,
|
||||||
@ -376,6 +479,16 @@ impl TryFrom<&Instruction> for BinOp {
|
|||||||
Instruction::I64ShrU => Self::ShrU_I64,
|
Instruction::I64ShrU => Self::ShrU_I64,
|
||||||
Instruction::I64Rotl => Self::Rotl_I64,
|
Instruction::I64Rotl => Self::Rotl_I64,
|
||||||
Instruction::I64Rotr => Self::Rotr_I64,
|
Instruction::I64Rotr => Self::Rotr_I64,
|
||||||
|
Instruction::F32Eq | Instruction::F64Eq => Self::Eq_FN,
|
||||||
|
Instruction::F32Ne | Instruction::F64Ne => Self::Ne_FN,
|
||||||
|
Instruction::F32Lt | Instruction::F64Lt => Self::Lt_FN,
|
||||||
|
Instruction::F32Gt | Instruction::F64Gt => Self::Gt_FN,
|
||||||
|
Instruction::F32Le | Instruction::F64Le => Self::Le_FN,
|
||||||
|
Instruction::F32Ge | Instruction::F64Ge => Self::Ge_FN,
|
||||||
|
Instruction::F32Add | Instruction::F64Add => Self::Add_FN,
|
||||||
|
Instruction::F32Sub | Instruction::F64Sub => Self::Sub_FN,
|
||||||
|
Instruction::F32Mul | Instruction::F64Mul => Self::Mul_FN,
|
||||||
|
Instruction::F32Div | Instruction::F64Div => Self::Div_FN,
|
||||||
Instruction::F32Min | Instruction::F64Min => Self::Min_FN,
|
Instruction::F32Min | Instruction::F64Min => Self::Min_FN,
|
||||||
Instruction::F32Max | Instruction::F64Max => Self::Max_FN,
|
Instruction::F32Max | Instruction::F64Max => Self::Max_FN,
|
||||||
_ => {
|
_ => {
|
405
src/backend/ast/transformer.rs
Normal file
405
src/backend/ast/transformer.rs
Normal file
@ -0,0 +1,405 @@
|
|||||||
|
use parity_wasm::elements::{Instruction, Local, Module};
|
||||||
|
|
||||||
|
use crate::backend::translator::arity::{Arity, List as ArityList};
|
||||||
|
|
||||||
|
use super::{
|
||||||
|
data::Memorize,
|
||||||
|
operation::{BinOp, UnOp},
|
||||||
|
{
|
||||||
|
data::{
|
||||||
|
AnyBinOp, AnyLoad, AnyStore, AnyUnOp, Backward, Br, BrIf, BrTable, Call, CallIndirect,
|
||||||
|
Expression, Forward, Function, GetGlobal, GetLocal, If, MemoryGrow, MemorySize, Return,
|
||||||
|
Select, SetGlobal, SetLocal, Statement, Value,
|
||||||
|
},
|
||||||
|
operation::{Load, Store},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
pub struct Transformer<'a> {
|
||||||
|
// target state
|
||||||
|
wasm: &'a Module,
|
||||||
|
arity: &'a ArityList,
|
||||||
|
name: usize,
|
||||||
|
|
||||||
|
// translation state
|
||||||
|
sleeping: Vec<Vec<Expression>>,
|
||||||
|
living: Vec<Expression>,
|
||||||
|
last_stack: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
fn is_now_else(inst: &[Instruction]) -> bool {
|
||||||
|
inst.get(0) == Some(&Instruction::Else)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn local_sum(list: &[Local]) -> u32 {
|
||||||
|
list.iter().map(Local::count).sum()
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> Transformer<'a> {
|
||||||
|
pub fn new(wasm: &'a Module, arity: &'a ArityList, name: usize) -> Transformer<'a> {
|
||||||
|
Transformer {
|
||||||
|
wasm,
|
||||||
|
arity,
|
||||||
|
name,
|
||||||
|
sleeping: Vec::new(),
|
||||||
|
living: Vec::new(),
|
||||||
|
last_stack: 0,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn consume(mut self) -> Function {
|
||||||
|
debug_assert!(self.name != usize::MAX, "Not an indexed value");
|
||||||
|
|
||||||
|
let func = &self.wasm.code_section().unwrap().bodies()[self.name];
|
||||||
|
let body = self.new_stored_body(&mut func.code().elements());
|
||||||
|
|
||||||
|
Function {
|
||||||
|
num_param: self.arity.in_arity[self.name].num_param,
|
||||||
|
num_local: local_sum(func.locals()),
|
||||||
|
num_stack: u32::try_from(self.last_stack).unwrap(),
|
||||||
|
body,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn gen_push_recall(&mut self, num: u32) {
|
||||||
|
let len = self.living.len();
|
||||||
|
|
||||||
|
(len..len + num as usize)
|
||||||
|
.map(Expression::Recall)
|
||||||
|
.for_each(|v| self.living.push(v));
|
||||||
|
}
|
||||||
|
|
||||||
|
// If any expressions are still pending at the start of
|
||||||
|
// statement, we leak them into variables.
|
||||||
|
// Since expressions do not have set ordering rules, this is
|
||||||
|
// safe and condenses code.
|
||||||
|
fn gen_leak_pending(&mut self, stat: &mut Vec<Statement>) {
|
||||||
|
self.last_stack = self.last_stack.max(self.living.len());
|
||||||
|
|
||||||
|
for (i, v) in self
|
||||||
|
.living
|
||||||
|
.iter_mut()
|
||||||
|
.enumerate()
|
||||||
|
.filter(|v| !v.1.is_recalling(v.0))
|
||||||
|
{
|
||||||
|
let new = Expression::Recall(i);
|
||||||
|
let mem = Memorize {
|
||||||
|
var: i,
|
||||||
|
value: std::mem::replace(v, new),
|
||||||
|
};
|
||||||
|
|
||||||
|
stat.push(Statement::Memorize(mem));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Pending expressions are put to sleep before entering
|
||||||
|
// a control structure so that they are not lost.
|
||||||
|
fn save_pending(&mut self) {
|
||||||
|
self.sleeping.push(self.living.clone());
|
||||||
|
}
|
||||||
|
|
||||||
|
fn load_pending(&mut self) {
|
||||||
|
let mut old = 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>) {
|
||||||
|
let num = self.arity.in_arity[self.name].num_result as usize;
|
||||||
|
let list = self.living.split_off(self.living.len() - num);
|
||||||
|
|
||||||
|
self.gen_leak_pending(stat);
|
||||||
|
stat.push(Statement::Return(Return { list }));
|
||||||
|
}
|
||||||
|
|
||||||
|
fn gen_call(&mut self, func: u32, stat: &mut Vec<Statement>) {
|
||||||
|
let arity = self.arity.arity_of(func as usize);
|
||||||
|
|
||||||
|
let param_list = self
|
||||||
|
.living
|
||||||
|
.split_off(self.living.len() - arity.num_param as usize);
|
||||||
|
|
||||||
|
let len = u32::try_from(self.living.len()).unwrap();
|
||||||
|
let result = len..len + arity.num_result;
|
||||||
|
|
||||||
|
self.gen_push_recall(arity.num_result);
|
||||||
|
self.gen_leak_pending(stat);
|
||||||
|
stat.push(Statement::Call(Call {
|
||||||
|
func,
|
||||||
|
result,
|
||||||
|
param_list,
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
fn gen_call_indirect(&mut self, typ: u32, table: u8, stat: &mut Vec<Statement>) {
|
||||||
|
let types = self.wasm.type_section().unwrap().types();
|
||||||
|
let arity = Arity::from_index(types, typ);
|
||||||
|
|
||||||
|
let index = self.living.pop().unwrap();
|
||||||
|
let param_list = self
|
||||||
|
.living
|
||||||
|
.split_off(self.living.len() - arity.num_param as usize);
|
||||||
|
|
||||||
|
let len = u32::try_from(self.living.len()).unwrap();
|
||||||
|
let result = len..len + arity.num_result;
|
||||||
|
|
||||||
|
self.gen_push_recall(arity.num_result);
|
||||||
|
self.gen_leak_pending(stat);
|
||||||
|
stat.push(Statement::CallIndirect(CallIndirect {
|
||||||
|
table,
|
||||||
|
index,
|
||||||
|
result,
|
||||||
|
param_list,
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
fn push_load(&mut self, op: Load, offset: u32) {
|
||||||
|
let pointer = Box::new(self.living.pop().unwrap());
|
||||||
|
|
||||||
|
self.living.push(Expression::AnyLoad(AnyLoad {
|
||||||
|
op,
|
||||||
|
offset,
|
||||||
|
pointer,
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
fn gen_store(&mut self, op: Store, offset: u32, stat: &mut Vec<Statement>) {
|
||||||
|
let value = self.living.pop().unwrap();
|
||||||
|
let pointer = self.living.pop().unwrap();
|
||||||
|
|
||||||
|
self.gen_leak_pending(stat);
|
||||||
|
stat.push(Statement::AnyStore(AnyStore {
|
||||||
|
op,
|
||||||
|
offset,
|
||||||
|
pointer,
|
||||||
|
value,
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
fn push_constant(&mut self, value: Value) {
|
||||||
|
self.living.push(Expression::Value(value));
|
||||||
|
}
|
||||||
|
|
||||||
|
fn push_un_op(&mut self, op: UnOp) {
|
||||||
|
let rhs = Box::new(self.living.pop().unwrap());
|
||||||
|
|
||||||
|
self.living.push(Expression::AnyUnOp(AnyUnOp { op, rhs }));
|
||||||
|
}
|
||||||
|
|
||||||
|
fn push_bin_op(&mut self, op: BinOp) {
|
||||||
|
let rhs = Box::new(self.living.pop().unwrap());
|
||||||
|
let lhs = Box::new(self.living.pop().unwrap());
|
||||||
|
|
||||||
|
self.living
|
||||||
|
.push(Expression::AnyBinOp(AnyBinOp { op, lhs, rhs }));
|
||||||
|
}
|
||||||
|
|
||||||
|
fn new_body(&mut self, list: &mut &[Instruction]) -> Vec<Statement> {
|
||||||
|
use Instruction as Inst;
|
||||||
|
|
||||||
|
let mut stat = Vec::new();
|
||||||
|
|
||||||
|
while let Some(inst) = list.get(0) {
|
||||||
|
*list = &list[1..];
|
||||||
|
|
||||||
|
if let Ok(op) = UnOp::try_from(inst) {
|
||||||
|
self.push_un_op(op);
|
||||||
|
|
||||||
|
continue;
|
||||||
|
} else if let Ok(op) = BinOp::try_from(inst) {
|
||||||
|
self.push_bin_op(op);
|
||||||
|
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
match inst {
|
||||||
|
Inst::Nop => {}
|
||||||
|
Inst::Unreachable => {
|
||||||
|
self.gen_leak_pending(&mut stat);
|
||||||
|
stat.push(Statement::Unreachable);
|
||||||
|
}
|
||||||
|
Inst::Block(_) => {
|
||||||
|
self.gen_leak_pending(&mut stat);
|
||||||
|
|
||||||
|
let data = self.new_forward(list);
|
||||||
|
|
||||||
|
stat.push(Statement::Forward(data));
|
||||||
|
}
|
||||||
|
Inst::Loop(_) => {
|
||||||
|
self.gen_leak_pending(&mut stat);
|
||||||
|
|
||||||
|
let data = self.new_backward(list);
|
||||||
|
|
||||||
|
stat.push(Statement::Backward(data));
|
||||||
|
}
|
||||||
|
Inst::If(_) => {
|
||||||
|
let cond = self.living.pop().unwrap();
|
||||||
|
|
||||||
|
self.gen_leak_pending(&mut stat);
|
||||||
|
|
||||||
|
let data = self.new_if(cond, list);
|
||||||
|
|
||||||
|
stat.push(Statement::If(data));
|
||||||
|
}
|
||||||
|
Inst::Else => {
|
||||||
|
self.gen_leak_pending(&mut stat);
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
Inst::End => {
|
||||||
|
if list.is_empty() && !self.living.is_empty() {
|
||||||
|
self.gen_return(&mut stat);
|
||||||
|
} else {
|
||||||
|
self.gen_leak_pending(&mut stat);
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
Inst::Br(i) => {
|
||||||
|
self.gen_leak_pending(&mut stat);
|
||||||
|
|
||||||
|
stat.push(Statement::Br(Br { target: *i }));
|
||||||
|
}
|
||||||
|
Inst::BrIf(i) => {
|
||||||
|
let cond = self.living.pop().unwrap();
|
||||||
|
|
||||||
|
self.gen_leak_pending(&mut stat);
|
||||||
|
stat.push(Statement::BrIf(BrIf { cond, target: *i }));
|
||||||
|
}
|
||||||
|
Inst::BrTable(t) => {
|
||||||
|
let cond = self.living.pop().unwrap();
|
||||||
|
|
||||||
|
self.gen_leak_pending(&mut stat);
|
||||||
|
stat.push(Statement::BrTable(BrTable {
|
||||||
|
cond,
|
||||||
|
data: *t.clone(),
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
Inst::Return => {
|
||||||
|
self.gen_return(&mut stat);
|
||||||
|
}
|
||||||
|
Inst::Call(i) => {
|
||||||
|
self.gen_call(*i, &mut stat);
|
||||||
|
}
|
||||||
|
Inst::CallIndirect(i, t) => {
|
||||||
|
self.gen_call_indirect(*i, *t, &mut stat);
|
||||||
|
}
|
||||||
|
Inst::Drop => {
|
||||||
|
self.living.pop().unwrap();
|
||||||
|
}
|
||||||
|
Inst::Select => {
|
||||||
|
let cond = Box::new(self.living.pop().unwrap());
|
||||||
|
let b = Box::new(self.living.pop().unwrap());
|
||||||
|
let a = Box::new(self.living.pop().unwrap());
|
||||||
|
|
||||||
|
self.living.push(Expression::Select(Select { cond, a, b }));
|
||||||
|
}
|
||||||
|
Inst::GetLocal(i) => {
|
||||||
|
self.living.push(Expression::GetLocal(GetLocal { var: *i }));
|
||||||
|
}
|
||||||
|
Inst::SetLocal(i) => {
|
||||||
|
let value = self.living.pop().unwrap();
|
||||||
|
|
||||||
|
self.gen_leak_pending(&mut stat);
|
||||||
|
stat.push(Statement::SetLocal(SetLocal { var: *i, value }));
|
||||||
|
}
|
||||||
|
Inst::TeeLocal(i) => {
|
||||||
|
self.gen_leak_pending(&mut stat);
|
||||||
|
|
||||||
|
let value = self.living.last().unwrap().clone();
|
||||||
|
|
||||||
|
stat.push(Statement::SetLocal(SetLocal { var: *i, value }));
|
||||||
|
}
|
||||||
|
Inst::GetGlobal(i) => {
|
||||||
|
self.living
|
||||||
|
.push(Expression::GetGlobal(GetGlobal { var: *i }));
|
||||||
|
}
|
||||||
|
Inst::SetGlobal(i) => {
|
||||||
|
let value = self.living.pop().unwrap();
|
||||||
|
|
||||||
|
stat.push(Statement::SetGlobal(SetGlobal { var: *i, value }));
|
||||||
|
}
|
||||||
|
Inst::I32Load(_, o) => self.push_load(Load::I32, *o),
|
||||||
|
Inst::I64Load(_, o) => self.push_load(Load::I64, *o),
|
||||||
|
Inst::F32Load(_, o) => self.push_load(Load::F32, *o),
|
||||||
|
Inst::F64Load(_, o) => self.push_load(Load::F64, *o),
|
||||||
|
Inst::I32Load8S(_, o) => self.push_load(Load::I32_I8, *o),
|
||||||
|
Inst::I32Load8U(_, o) => self.push_load(Load::I32_U8, *o),
|
||||||
|
Inst::I32Load16S(_, o) => self.push_load(Load::I32_I16, *o),
|
||||||
|
Inst::I32Load16U(_, o) => self.push_load(Load::I32_U16, *o),
|
||||||
|
Inst::I64Load8S(_, o) => self.push_load(Load::I64_I8, *o),
|
||||||
|
Inst::I64Load8U(_, o) => self.push_load(Load::I64_U8, *o),
|
||||||
|
Inst::I64Load16S(_, o) => self.push_load(Load::I64_I16, *o),
|
||||||
|
Inst::I64Load16U(_, o) => self.push_load(Load::I64_U16, *o),
|
||||||
|
Inst::I64Load32S(_, o) => self.push_load(Load::I64_I32, *o),
|
||||||
|
Inst::I64Load32U(_, o) => self.push_load(Load::I64_U32, *o),
|
||||||
|
Inst::I32Store(_, o) => self.gen_store(Store::I32, *o, &mut stat),
|
||||||
|
Inst::I64Store(_, o) => self.gen_store(Store::I64, *o, &mut stat),
|
||||||
|
Inst::F32Store(_, o) => self.gen_store(Store::F32, *o, &mut stat),
|
||||||
|
Inst::F64Store(_, o) => self.gen_store(Store::F64, *o, &mut stat),
|
||||||
|
Inst::I32Store8(_, o) => self.gen_store(Store::I32_N8, *o, &mut stat),
|
||||||
|
Inst::I32Store16(_, o) => self.gen_store(Store::I32_N16, *o, &mut stat),
|
||||||
|
Inst::I64Store8(_, o) => self.gen_store(Store::I64_N8, *o, &mut stat),
|
||||||
|
Inst::I64Store16(_, o) => self.gen_store(Store::I64_N16, *o, &mut stat),
|
||||||
|
Inst::I64Store32(_, o) => self.gen_store(Store::I64_N32, *o, &mut stat),
|
||||||
|
Inst::CurrentMemory(i) => {
|
||||||
|
self.living
|
||||||
|
.push(Expression::MemorySize(MemorySize { memory: *i }));
|
||||||
|
}
|
||||||
|
Inst::GrowMemory(i) => {
|
||||||
|
let value = Box::new(self.living.pop().unwrap());
|
||||||
|
|
||||||
|
// `MemoryGrow` is an expression *but* it has side effects
|
||||||
|
self.gen_leak_pending(&mut stat);
|
||||||
|
self.living
|
||||||
|
.push(Expression::MemoryGrow(MemoryGrow { memory: *i, value }));
|
||||||
|
}
|
||||||
|
Inst::I32Const(v) => self.push_constant(Value::I32(*v)),
|
||||||
|
Inst::I64Const(v) => self.push_constant(Value::I64(*v)),
|
||||||
|
Inst::F32Const(v) => self.push_constant(Value::F32(f32::from_bits(*v))),
|
||||||
|
Inst::F64Const(v) => self.push_constant(Value::F64(f64::from_bits(*v))),
|
||||||
|
_ => unreachable!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
stat
|
||||||
|
}
|
||||||
|
|
||||||
|
fn new_stored_body(&mut self, list: &mut &[Instruction]) -> Vec<Statement> {
|
||||||
|
self.save_pending();
|
||||||
|
|
||||||
|
let body = self.new_body(list);
|
||||||
|
|
||||||
|
self.load_pending();
|
||||||
|
|
||||||
|
body
|
||||||
|
}
|
||||||
|
|
||||||
|
fn new_if(&mut self, cond: Expression, list: &mut &[Instruction]) -> If {
|
||||||
|
let body = self.new_stored_body(list);
|
||||||
|
let other = is_now_else(list).then(|| {
|
||||||
|
*list = &list[1..];
|
||||||
|
self.new_stored_body(list)
|
||||||
|
});
|
||||||
|
|
||||||
|
If { cond, body, other }
|
||||||
|
}
|
||||||
|
|
||||||
|
fn new_backward(&mut self, list: &mut &[Instruction]) -> Backward {
|
||||||
|
Backward {
|
||||||
|
body: self.new_stored_body(list),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn new_forward(&mut self, list: &mut &[Instruction]) -> Forward {
|
||||||
|
Forward {
|
||||||
|
body: self.new_stored_body(list),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,6 +1,7 @@
|
|||||||
use std::{fmt::Display, io::Result};
|
use std::{
|
||||||
|
fmt::Display,
|
||||||
use crate::backend::helper::writer::Writer;
|
io::{Result, Write},
|
||||||
|
};
|
||||||
|
|
||||||
use super::{luajit::LuaJIT, luau::Luau};
|
use super::{luajit::LuaJIT, luau::Luau};
|
||||||
|
|
||||||
@ -28,15 +29,15 @@ where
|
|||||||
pub trait Edition {
|
pub trait Edition {
|
||||||
fn runtime(&self) -> &'static str;
|
fn runtime(&self) -> &'static str;
|
||||||
|
|
||||||
fn start_block(&self, w: Writer) -> Result<()>;
|
fn start_block(&self, w: &mut dyn Write) -> Result<()>;
|
||||||
fn start_loop(&self, level: usize, w: Writer) -> Result<()>;
|
fn start_loop(&self, level: usize, w: &mut dyn Write) -> Result<()>;
|
||||||
fn start_if(&self, cond: &str, w: Writer) -> Result<()>;
|
fn start_if(&self, cond: &str, w: &mut dyn Write) -> Result<()>;
|
||||||
fn end_block(&self, level: usize, w: Writer) -> Result<()>;
|
fn end_block(&self, level: usize, w: &mut dyn Write) -> Result<()>;
|
||||||
fn end_loop(&self, w: Writer) -> Result<()>;
|
fn end_loop(&self, w: &mut dyn Write) -> Result<()>;
|
||||||
fn end_if(&self, level: usize, w: Writer) -> Result<()>;
|
fn end_if(&self, level: usize, w: &mut dyn Write) -> Result<()>;
|
||||||
|
|
||||||
fn br_target(&self, level: usize, in_loop: bool, w: Writer) -> Result<()>;
|
fn br_target(&self, level: usize, in_loop: bool, w: &mut dyn Write) -> Result<()>;
|
||||||
fn br_to_level(&self, level: usize, up: usize, is_loop: bool, w: Writer) -> Result<()>;
|
fn br_to_level(&self, level: usize, up: usize, is_loop: bool, w: &mut dyn Write) -> Result<()>;
|
||||||
|
|
||||||
fn i64(&self, i: i64) -> Infix<i64>;
|
fn i64(&self, i: i64) -> Infix<i64>;
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,4 @@
|
|||||||
use std::io::Result;
|
use std::io::{Result, Write};
|
||||||
|
|
||||||
use crate::backend::helper::writer::Writer;
|
|
||||||
|
|
||||||
use super::data::{Edition, Infix};
|
use super::data::{Edition, Infix};
|
||||||
|
|
||||||
@ -11,38 +9,44 @@ impl Edition for LuaJIT {
|
|||||||
"'luajit'"
|
"'luajit'"
|
||||||
}
|
}
|
||||||
|
|
||||||
fn start_block(&self, w: Writer) -> Result<()> {
|
fn start_block(&self, w: &mut dyn Write) -> Result<()> {
|
||||||
write!(w, "do ")
|
write!(w, "do ")
|
||||||
}
|
}
|
||||||
|
|
||||||
fn start_loop(&self, level: usize, w: Writer) -> Result<()> {
|
fn start_loop(&self, level: usize, w: &mut dyn Write) -> Result<()> {
|
||||||
write!(w, "do ")?;
|
write!(w, "do ")?;
|
||||||
write!(w, "::continue_at_{}::", level)
|
write!(w, "::continue_at_{}::", level)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn start_if(&self, cond: &str, w: Writer) -> Result<()> {
|
fn start_if(&self, cond: &str, w: &mut dyn Write) -> Result<()> {
|
||||||
write!(w, "if {} ~= 0 then ", cond)
|
write!(w, "if {} ~= 0 then ", cond)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn end_block(&self, level: usize, w: Writer) -> Result<()> {
|
fn end_block(&self, level: usize, w: &mut dyn Write) -> Result<()> {
|
||||||
write!(w, "::continue_at_{}::", level)?;
|
write!(w, "::continue_at_{}::", level)?;
|
||||||
write!(w, "end ")
|
write!(w, "end ")
|
||||||
}
|
}
|
||||||
|
|
||||||
fn end_loop(&self, w: Writer) -> Result<()> {
|
fn end_loop(&self, w: &mut dyn Write) -> Result<()> {
|
||||||
write!(w, "end ")
|
write!(w, "end ")
|
||||||
}
|
}
|
||||||
|
|
||||||
fn end_if(&self, level: usize, w: Writer) -> Result<()> {
|
fn end_if(&self, level: usize, w: &mut dyn Write) -> Result<()> {
|
||||||
write!(w, "::continue_at_{}::", level)?;
|
write!(w, "::continue_at_{}::", level)?;
|
||||||
write!(w, "end ")
|
write!(w, "end ")
|
||||||
}
|
}
|
||||||
|
|
||||||
fn br_target(&self, _level: usize, _in_loop: bool, _w: Writer) -> Result<()> {
|
fn br_target(&self, _level: usize, _in_loop: bool, _w: &mut dyn Write) -> Result<()> {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn br_to_level(&self, level: usize, up: usize, _is_loop: bool, w: Writer) -> Result<()> {
|
fn br_to_level(
|
||||||
|
&self,
|
||||||
|
level: usize,
|
||||||
|
up: usize,
|
||||||
|
_is_loop: bool,
|
||||||
|
w: &mut dyn Write,
|
||||||
|
) -> Result<()> {
|
||||||
write!(w, "goto continue_at_{} ", level - up)
|
write!(w, "goto continue_at_{} ", level - up)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,6 +1,4 @@
|
|||||||
use std::io::Result;
|
use std::io::{Result, Write};
|
||||||
|
|
||||||
use crate::backend::helper::writer::Writer;
|
|
||||||
|
|
||||||
use super::data::{Edition, Infix};
|
use super::data::{Edition, Infix};
|
||||||
|
|
||||||
@ -11,36 +9,36 @@ impl Edition for Luau {
|
|||||||
"script.Runtime"
|
"script.Runtime"
|
||||||
}
|
}
|
||||||
|
|
||||||
fn start_block(&self, w: Writer) -> Result<()> {
|
fn start_block(&self, w: &mut dyn Write) -> Result<()> {
|
||||||
write!(w, "while true do ")
|
write!(w, "while true do ")
|
||||||
}
|
}
|
||||||
|
|
||||||
fn start_loop(&self, _level: usize, w: Writer) -> Result<()> {
|
fn start_loop(&self, _level: usize, w: &mut dyn Write) -> Result<()> {
|
||||||
write!(w, "while true do ")
|
write!(w, "while true do ")
|
||||||
}
|
}
|
||||||
|
|
||||||
fn start_if(&self, cond: &str, w: Writer) -> Result<()> {
|
fn start_if(&self, cond: &str, w: &mut dyn Write) -> Result<()> {
|
||||||
write!(w, "while true do ")?;
|
write!(w, "while true do ")?;
|
||||||
write!(w, "if {} ~= 0 then ", cond)
|
write!(w, "if {} ~= 0 then ", cond)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn end_block(&self, _level: usize, w: Writer) -> Result<()> {
|
fn end_block(&self, _level: usize, w: &mut dyn Write) -> Result<()> {
|
||||||
write!(w, "break ")?;
|
write!(w, "break ")?;
|
||||||
write!(w, "end ")
|
write!(w, "end ")
|
||||||
}
|
}
|
||||||
|
|
||||||
fn end_loop(&self, w: Writer) -> Result<()> {
|
fn end_loop(&self, w: &mut dyn Write) -> Result<()> {
|
||||||
write!(w, "break ")?;
|
write!(w, "break ")?;
|
||||||
write!(w, "end ")
|
write!(w, "end ")
|
||||||
}
|
}
|
||||||
|
|
||||||
fn end_if(&self, _level: usize, w: Writer) -> Result<()> {
|
fn end_if(&self, _level: usize, w: &mut dyn Write) -> Result<()> {
|
||||||
write!(w, "end ")?;
|
write!(w, "end ")?;
|
||||||
write!(w, "break ")?;
|
write!(w, "break ")?;
|
||||||
write!(w, "end ")
|
write!(w, "end ")
|
||||||
}
|
}
|
||||||
|
|
||||||
fn br_target(&self, level: usize, in_loop: bool, w: Writer) -> Result<()> {
|
fn br_target(&self, level: usize, in_loop: bool, w: &mut dyn Write) -> Result<()> {
|
||||||
write!(w, "if desired then ")?;
|
write!(w, "if desired then ")?;
|
||||||
write!(w, "if desired == {} then ", level)?;
|
write!(w, "if desired == {} then ", level)?;
|
||||||
write!(w, "desired = nil ")?;
|
write!(w, "desired = nil ")?;
|
||||||
@ -54,7 +52,7 @@ impl Edition for Luau {
|
|||||||
write!(w, "end ")
|
write!(w, "end ")
|
||||||
}
|
}
|
||||||
|
|
||||||
fn br_to_level(&self, level: usize, up: usize, is_loop: bool, w: Writer) -> Result<()> {
|
fn br_to_level(&self, level: usize, up: usize, is_loop: bool, w: &mut dyn Write) -> Result<()> {
|
||||||
write!(w, "do ")?;
|
write!(w, "do ")?;
|
||||||
|
|
||||||
if up == 0 {
|
if up == 0 {
|
||||||
|
@ -1,3 +0,0 @@
|
|||||||
pub mod operation;
|
|
||||||
pub mod register;
|
|
||||||
pub mod writer;
|
|
@ -1,41 +0,0 @@
|
|||||||
pub struct Register {
|
|
||||||
pub last: u32,
|
|
||||||
pub inner: u32,
|
|
||||||
saved: Vec<u32>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Register {
|
|
||||||
pub fn new() -> Self {
|
|
||||||
Self {
|
|
||||||
last: 0,
|
|
||||||
inner: 0,
|
|
||||||
saved: vec![0],
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn extend(&mut self) {
|
|
||||||
self.last = self.last.max(self.inner);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn save(&mut self) {
|
|
||||||
self.saved.push(self.inner);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn load(&mut self) {
|
|
||||||
self.inner = self.saved.pop().unwrap();
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn push(&mut self, n: u32) -> u32 {
|
|
||||||
let prev = self.inner;
|
|
||||||
|
|
||||||
self.inner = self.inner.checked_add(n).unwrap();
|
|
||||||
self.extend();
|
|
||||||
|
|
||||||
prev
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn pop(&mut self, n: u32) -> u32 {
|
|
||||||
self.inner = self.inner.checked_sub(n).unwrap();
|
|
||||||
self.inner
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,17 +0,0 @@
|
|||||||
use std::io::{Result, Write};
|
|
||||||
|
|
||||||
pub type Writer<'a> = &'a mut dyn Write;
|
|
||||||
|
|
||||||
pub fn ordered_iter(prefix: &'static str, end: u32) -> impl Iterator<Item = String> {
|
|
||||||
(1..=end).map(move |i| format!("{}_{}", prefix, i))
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn write_ordered(prefix: &'static str, end: u32, w: Writer) -> Result<()> {
|
|
||||||
let mut iter = ordered_iter(prefix, end);
|
|
||||||
|
|
||||||
if let Some(s) = iter.next() {
|
|
||||||
write!(w, "{}", s)?;
|
|
||||||
}
|
|
||||||
|
|
||||||
iter.try_for_each(|s| write!(w, ", {}", s))
|
|
||||||
}
|
|
@ -1,4 +1,4 @@
|
|||||||
|
mod ast;
|
||||||
pub mod edition;
|
pub mod edition;
|
||||||
pub mod helper;
|
|
||||||
pub mod translator;
|
pub mod translator;
|
||||||
pub mod visitor;
|
mod visitor;
|
||||||
|
81
src/backend/translator/arity.rs
Executable file
81
src/backend/translator/arity.rs
Executable file
@ -0,0 +1,81 @@
|
|||||||
|
use std::convert::TryInto;
|
||||||
|
|
||||||
|
use parity_wasm::elements::{External, FunctionType, ImportEntry, Module, Type};
|
||||||
|
|
||||||
|
pub struct Arity {
|
||||||
|
pub num_param: u32,
|
||||||
|
pub num_result: u32,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Arity {
|
||||||
|
fn from_type(typ: &FunctionType) -> Self {
|
||||||
|
let num_param = typ.params().len().try_into().unwrap();
|
||||||
|
let num_result = typ.results().len().try_into().unwrap();
|
||||||
|
|
||||||
|
Self {
|
||||||
|
num_param,
|
||||||
|
num_result,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn from_index(types: &[Type], index: u32) -> Self {
|
||||||
|
let Type::Function(typ) = &types[index as usize];
|
||||||
|
|
||||||
|
Self::from_type(typ)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct List {
|
||||||
|
pub ex_arity: Vec<Arity>,
|
||||||
|
pub in_arity: Vec<Arity>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl List {
|
||||||
|
pub fn new(parent: &Module) -> Self {
|
||||||
|
Self {
|
||||||
|
ex_arity: Self::new_arity_ex_list(parent),
|
||||||
|
in_arity: Self::new_arity_in_list(parent),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn arity_of(&self, index: usize) -> &Arity {
|
||||||
|
let offset = self.ex_arity.len();
|
||||||
|
|
||||||
|
self.ex_arity
|
||||||
|
.get(index)
|
||||||
|
.or_else(|| self.in_arity.get(index - offset))
|
||||||
|
.unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn new_arity_ext(types: &[Type], import: &ImportEntry) -> Option<Arity> {
|
||||||
|
if let External::Function(i) = import.external() {
|
||||||
|
Some(Arity::from_index(types, *i))
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn new_arity_in_list(wasm: &Module) -> Vec<Arity> {
|
||||||
|
let (types, funcs) = match (wasm.type_section(), wasm.function_section()) {
|
||||||
|
(Some(t), Some(f)) => (t.types(), f.entries()),
|
||||||
|
_ => return Vec::new(),
|
||||||
|
};
|
||||||
|
|
||||||
|
funcs
|
||||||
|
.iter()
|
||||||
|
.map(|i| Arity::from_index(types, i.type_ref()))
|
||||||
|
.collect()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn new_arity_ex_list(wasm: &Module) -> Vec<Arity> {
|
||||||
|
let (types, imports) = match (wasm.type_section(), wasm.import_section()) {
|
||||||
|
(Some(t), Some(i)) => (t.types(), i.entries()),
|
||||||
|
_ => return Vec::new(),
|
||||||
|
};
|
||||||
|
|
||||||
|
imports
|
||||||
|
.iter()
|
||||||
|
.filter_map(|i| Self::new_arity_ext(types, i))
|
||||||
|
.collect()
|
||||||
|
}
|
||||||
|
}
|
279
src/backend/translator/data.rs
Normal file
279
src/backend/translator/data.rs
Normal file
@ -0,0 +1,279 @@
|
|||||||
|
use std::io::{Result, Write};
|
||||||
|
|
||||||
|
use parity_wasm::elements::{
|
||||||
|
External, ImportCountType, Instruction, Internal, Module as WasmModule, ResizableLimits,
|
||||||
|
};
|
||||||
|
|
||||||
|
use crate::backend::{ast::transformer::Transformer, edition::data::Edition};
|
||||||
|
|
||||||
|
use super::{arity::List as ArityList, writer::Data};
|
||||||
|
|
||||||
|
fn aux_internal_index(internal: Internal) -> u32 {
|
||||||
|
match internal {
|
||||||
|
Internal::Function(v) | Internal::Table(v) | Internal::Memory(v) | Internal::Global(v) => v,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn gen_table_init(limit: &ResizableLimits, w: &mut dyn Write) -> Result<()> {
|
||||||
|
write!(w, "{{ min = {}", limit.initial())?;
|
||||||
|
|
||||||
|
if let Some(max) = limit.maximum() {
|
||||||
|
write!(w, ", max = {}", max)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
write!(w, ", data = {{}} }}")
|
||||||
|
}
|
||||||
|
|
||||||
|
fn gen_memory_init(limit: &ResizableLimits, w: &mut dyn Write) -> Result<()> {
|
||||||
|
write!(w, "rt.memory.new({}, ", limit.initial())?;
|
||||||
|
|
||||||
|
if let Some(max) = limit.maximum() {
|
||||||
|
write!(w, "{}", max)?;
|
||||||
|
} else {
|
||||||
|
write!(w, "nil")?;
|
||||||
|
}
|
||||||
|
|
||||||
|
write!(w, ")")
|
||||||
|
}
|
||||||
|
|
||||||
|
fn gen_nil_array(name: &str, len: usize, w: &mut dyn Write) -> Result<()> {
|
||||||
|
if len == 0 {
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
|
||||||
|
write!(w, "local {} = {{[0] = {}}}", name, "nil, ".repeat(len))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn gen_expression(code: &[Instruction], w: &mut dyn Write) -> Result<()> {
|
||||||
|
assert!(code.len() == 2);
|
||||||
|
|
||||||
|
let inst = code.first().unwrap();
|
||||||
|
|
||||||
|
match *inst {
|
||||||
|
Instruction::I32Const(v) => write!(w, "{} ", v),
|
||||||
|
Instruction::I64Const(v) => write!(w, "{} ", v),
|
||||||
|
Instruction::F32Const(v) => write!(w, "{} ", f32::from_bits(v)),
|
||||||
|
Instruction::F64Const(v) => write!(w, "{} ", f64::from_bits(v)),
|
||||||
|
Instruction::GetGlobal(i) => write!(w, "GLOBAL_LIST[{}].value ", i),
|
||||||
|
_ => unreachable!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Module<'a> {
|
||||||
|
wasm: &'a WasmModule,
|
||||||
|
arity: ArityList,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> Module<'a> {
|
||||||
|
pub fn new(wasm: &'a WasmModule) -> Self {
|
||||||
|
let arity = ArityList::new(wasm);
|
||||||
|
|
||||||
|
Self { wasm, arity }
|
||||||
|
}
|
||||||
|
|
||||||
|
fn gen_import_of<T>(&self, w: &mut dyn Write, lower: &str, cond: T) -> Result<()>
|
||||||
|
where
|
||||||
|
T: Fn(&External) -> bool,
|
||||||
|
{
|
||||||
|
let import = match self.wasm.import_section() {
|
||||||
|
Some(v) => v.entries(),
|
||||||
|
None => return Ok(()),
|
||||||
|
};
|
||||||
|
let upper = lower.to_uppercase();
|
||||||
|
|
||||||
|
for (i, v) in import.iter().filter(|v| cond(v.external())).enumerate() {
|
||||||
|
let field = v.field();
|
||||||
|
let module = v.module();
|
||||||
|
|
||||||
|
write!(w, "{}[{}] = wasm.{}.{}.{} ", upper, i, module, lower, field)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn gen_export_of<T>(&self, w: &mut dyn Write, lower: &str, cond: T) -> Result<()>
|
||||||
|
where
|
||||||
|
T: Fn(&Internal) -> bool,
|
||||||
|
{
|
||||||
|
let export = match self.wasm.export_section() {
|
||||||
|
Some(v) => v.entries(),
|
||||||
|
None => return Ok(()),
|
||||||
|
};
|
||||||
|
let upper = lower.to_uppercase();
|
||||||
|
|
||||||
|
write!(w, "{} = {{", lower)?;
|
||||||
|
|
||||||
|
for v in export.iter().filter(|v| cond(v.internal())) {
|
||||||
|
let field = v.field();
|
||||||
|
let index = aux_internal_index(*v.internal());
|
||||||
|
|
||||||
|
write!(w, "{} = {}[{}],", field, upper, index)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
write!(w, "}},")
|
||||||
|
}
|
||||||
|
|
||||||
|
fn gen_import_list(&self, w: &mut dyn Write) -> Result<()> {
|
||||||
|
self.gen_import_of(w, "func_list", |v| matches!(v, External::Function(_)))?;
|
||||||
|
self.gen_import_of(w, "table_list", |v| matches!(v, External::Table(_)))?;
|
||||||
|
self.gen_import_of(w, "memory_list", |v| matches!(v, External::Memory(_)))?;
|
||||||
|
self.gen_import_of(w, "global_list", |v| matches!(v, External::Global(_)))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn gen_export_list(&self, w: &mut dyn Write) -> Result<()> {
|
||||||
|
self.gen_export_of(w, "func_list", |v| matches!(v, Internal::Function(_)))?;
|
||||||
|
self.gen_export_of(w, "table_list", |v| matches!(v, Internal::Table(_)))?;
|
||||||
|
self.gen_export_of(w, "memory_list", |v| matches!(v, Internal::Memory(_)))?;
|
||||||
|
self.gen_export_of(w, "global_list", |v| matches!(v, Internal::Global(_)))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn gen_table_list(&self, w: &mut dyn Write) -> Result<()> {
|
||||||
|
let table = match self.wasm.table_section() {
|
||||||
|
Some(v) => v.entries(),
|
||||||
|
None => return Ok(()),
|
||||||
|
};
|
||||||
|
let offset = self.wasm.import_count(ImportCountType::Table);
|
||||||
|
|
||||||
|
for (i, v) in table.iter().enumerate() {
|
||||||
|
let index = i + offset;
|
||||||
|
|
||||||
|
write!(w, "TABLE_LIST[{}] =", index)?;
|
||||||
|
gen_table_init(v.limits(), w)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn gen_memory_list(&self, w: &mut dyn Write) -> Result<()> {
|
||||||
|
let memory = match self.wasm.memory_section() {
|
||||||
|
Some(v) => v.entries(),
|
||||||
|
None => return Ok(()),
|
||||||
|
};
|
||||||
|
let offset = self.wasm.import_count(ImportCountType::Memory);
|
||||||
|
|
||||||
|
for (i, v) in memory.iter().enumerate() {
|
||||||
|
let index = i + offset;
|
||||||
|
|
||||||
|
write!(w, "MEMORY_LIST[{}] =", index)?;
|
||||||
|
gen_memory_init(v.limits(), w)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn gen_global_list(&self, w: &mut dyn Write) -> Result<()> {
|
||||||
|
let global = match self.wasm.global_section() {
|
||||||
|
Some(v) => v,
|
||||||
|
None => return Ok(()),
|
||||||
|
};
|
||||||
|
let offset = self.wasm.import_count(ImportCountType::Global);
|
||||||
|
|
||||||
|
for (i, v) in global.entries().iter().enumerate() {
|
||||||
|
let index = i + offset;
|
||||||
|
|
||||||
|
write!(w, "GLOBAL_LIST[{}] = {{ value =", index)?;
|
||||||
|
|
||||||
|
gen_expression(v.init_expr().code(), w)?;
|
||||||
|
|
||||||
|
write!(w, "}}")?;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn gen_element_list(&self, w: &mut dyn Write) -> Result<()> {
|
||||||
|
let element = match self.wasm.elements_section() {
|
||||||
|
Some(v) => v.entries(),
|
||||||
|
None => return Ok(()),
|
||||||
|
};
|
||||||
|
|
||||||
|
for v in element {
|
||||||
|
write!(w, "do ")?;
|
||||||
|
write!(w, "local target = TABLE_LIST[{}].data ", v.index())?;
|
||||||
|
write!(w, "local offset =")?;
|
||||||
|
|
||||||
|
gen_expression(v.offset().as_ref().unwrap().code(), w)?;
|
||||||
|
|
||||||
|
for (i, f) in v.members().iter().enumerate() {
|
||||||
|
write!(w, "target[offset + {}] = FUNC_LIST[{}]", i, f)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
write!(w, "end ")?;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn gen_data_list(&self, w: &mut dyn Write) -> Result<()> {
|
||||||
|
let data = match self.wasm.data_section() {
|
||||||
|
Some(v) => v.entries(),
|
||||||
|
None => return Ok(()),
|
||||||
|
};
|
||||||
|
|
||||||
|
for v in data {
|
||||||
|
write!(w, "do ")?;
|
||||||
|
write!(w, "local target = MEMORY_LIST[{}]", v.index())?;
|
||||||
|
write!(w, "local offset =")?;
|
||||||
|
|
||||||
|
gen_expression(v.offset().as_ref().unwrap().code(), w)?;
|
||||||
|
|
||||||
|
write!(w, "local data = \"")?;
|
||||||
|
|
||||||
|
v.value()
|
||||||
|
.iter()
|
||||||
|
.try_for_each(|v| write!(w, "\\x{:02X}", v))?;
|
||||||
|
|
||||||
|
write!(w, "\"")?;
|
||||||
|
|
||||||
|
write!(w, "rt.memory.init(target, offset, data)")?;
|
||||||
|
|
||||||
|
write!(w, "end ")?;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn gen_start_point(&self, w: &mut dyn Write) -> Result<()> {
|
||||||
|
write!(w, "local function run_init_code()")?;
|
||||||
|
self.gen_table_list(w)?;
|
||||||
|
self.gen_memory_list(w)?;
|
||||||
|
self.gen_global_list(w)?;
|
||||||
|
self.gen_element_list(w)?;
|
||||||
|
self.gen_data_list(w)?;
|
||||||
|
write!(w, "end ")?;
|
||||||
|
|
||||||
|
write!(w, "return function(wasm)")?;
|
||||||
|
self.gen_import_list(w)?;
|
||||||
|
write!(w, "run_init_code()")?;
|
||||||
|
|
||||||
|
if let Some(start) = self.wasm.start_section() {
|
||||||
|
write!(w, "FUNC_LIST[{}]()", start)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
write!(w, "return {{")?;
|
||||||
|
self.gen_export_list(w)?;
|
||||||
|
write!(w, "}} end ")
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn translate(&self, ed: &dyn Edition, w: &mut dyn Write) -> Result<()> {
|
||||||
|
write!(w, "local rt = require({})", ed.runtime())?;
|
||||||
|
|
||||||
|
gen_nil_array("FUNC_LIST", self.wasm.functions_space(), w)?;
|
||||||
|
gen_nil_array("TABLE_LIST", self.wasm.table_space(), w)?;
|
||||||
|
gen_nil_array("MEMORY_LIST", self.wasm.memory_space(), w)?;
|
||||||
|
gen_nil_array("GLOBAL_LIST", self.wasm.globals_space(), w)?;
|
||||||
|
|
||||||
|
let offset = self.arity.ex_arity.len();
|
||||||
|
|
||||||
|
for i in 0..self.arity.in_arity.len() {
|
||||||
|
let func = Transformer::new(self.wasm, &self.arity, i).consume();
|
||||||
|
let data = &mut Data::new(func.num_param, ed);
|
||||||
|
|
||||||
|
write!(w, "FUNC_LIST[{}] =", i + offset)?;
|
||||||
|
|
||||||
|
func.output(data, w)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
self.gen_start_point(w)
|
||||||
|
}
|
||||||
|
}
|
@ -1,483 +0,0 @@
|
|||||||
use std::{fmt::Display, io::Result, ops::Range};
|
|
||||||
|
|
||||||
use parity_wasm::elements::{BrTableData, Instruction};
|
|
||||||
|
|
||||||
use crate::{
|
|
||||||
backend::{
|
|
||||||
edition::data::Edition,
|
|
||||||
helper::{register::Register, writer::Writer},
|
|
||||||
},
|
|
||||||
data::{Arity, Code, Module},
|
|
||||||
};
|
|
||||||
|
|
||||||
pub fn list_to_range(list: &[u32]) -> Vec<(Range<usize>, u32)> {
|
|
||||||
let mut result = Vec::new();
|
|
||||||
let mut index = 0;
|
|
||||||
|
|
||||||
while index < list.len() {
|
|
||||||
let start = index;
|
|
||||||
|
|
||||||
loop {
|
|
||||||
index += 1;
|
|
||||||
|
|
||||||
// if end of list or next value is not equal, break
|
|
||||||
if index == list.len() || list[index - 1] != list[index] {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
result.push((start..index, list[start]));
|
|
||||||
}
|
|
||||||
|
|
||||||
result
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(PartialEq)]
|
|
||||||
pub enum Label {
|
|
||||||
Block,
|
|
||||||
If,
|
|
||||||
Loop,
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct Body<'a> {
|
|
||||||
spec: &'a dyn Edition,
|
|
||||||
label_list: Vec<Label>,
|
|
||||||
pub reg: Register,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> Body<'a> {
|
|
||||||
pub fn new(spec: &'a dyn Edition, base: u32) -> Self {
|
|
||||||
let mut reg = Register::new();
|
|
||||||
|
|
||||||
reg.push(base);
|
|
||||||
|
|
||||||
Self {
|
|
||||||
spec,
|
|
||||||
reg,
|
|
||||||
label_list: vec![],
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn generate(&mut self, index: usize, m: &Module, w: Writer) -> Result<()> {
|
|
||||||
m.code[index]
|
|
||||||
.inst_list
|
|
||||||
.iter()
|
|
||||||
.try_for_each(|v| self.gen_inst(index, v, m, w))
|
|
||||||
}
|
|
||||||
|
|
||||||
fn gen_jump(&mut self, up: u32, w: Writer) -> Result<()> {
|
|
||||||
let up = up as usize;
|
|
||||||
let level = self.label_list.len() - 1;
|
|
||||||
let is_loop = self.label_list[level - up] == Label::Loop;
|
|
||||||
|
|
||||||
self.spec.br_to_level(level, up, is_loop, w)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn gen_br_if(&mut self, i: u32, f: &Code, w: Writer) -> Result<()> {
|
|
||||||
let cond = f.var_name_of(self.reg.pop(1));
|
|
||||||
|
|
||||||
write!(w, "if {} ~= 0 then ", cond)?;
|
|
||||||
self.gen_jump(i, w)?;
|
|
||||||
write!(w, "end ")
|
|
||||||
}
|
|
||||||
|
|
||||||
fn gen_br_table(&mut self, data: &BrTableData, f: &Code, w: Writer) -> Result<()> {
|
|
||||||
let reg = f.var_name_of(self.reg.pop(1));
|
|
||||||
|
|
||||||
for (r, t) in list_to_range(&data.table) {
|
|
||||||
if r.len() == 1 {
|
|
||||||
write!(w, "if {} == {} then ", reg, r.start)?;
|
|
||||||
} else {
|
|
||||||
write!(w, "if {0} >= {1} and {0} <= {2} then ", reg, r.start, r.end)?;
|
|
||||||
}
|
|
||||||
|
|
||||||
self.gen_jump(t, w)?;
|
|
||||||
write!(w, "else")?;
|
|
||||||
}
|
|
||||||
|
|
||||||
write!(w, " ")?;
|
|
||||||
self.gen_jump(data.default, w)?;
|
|
||||||
write!(w, "end ")
|
|
||||||
}
|
|
||||||
|
|
||||||
fn gen_load(&mut self, t: &str, o: u32, f: &Code, w: Writer) -> Result<()> {
|
|
||||||
let reg = f.var_name_of(self.reg.pop(1));
|
|
||||||
|
|
||||||
self.reg.push(1);
|
|
||||||
|
|
||||||
write!(w, "{0} = load_{1}(memory_at_0, {0} + {2}) ", reg, t, o)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn gen_store(&mut self, t: &str, o: u32, f: &Code, w: Writer) -> Result<()> {
|
|
||||||
let val = f.var_name_of(self.reg.pop(1));
|
|
||||||
let reg = f.var_name_of(self.reg.pop(1));
|
|
||||||
|
|
||||||
write!(w, "store_{}(memory_at_0, {} + {}, {}) ", t, reg, o, val)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn gen_const<T: Display>(&mut self, val: T, f: &Code, w: Writer) -> Result<()> {
|
|
||||||
let reg = f.var_name_of(self.reg.push(1));
|
|
||||||
|
|
||||||
write!(w, "{} = {} ", reg, val)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn gen_compare(&mut self, op: &str, f: &Code, w: Writer) -> Result<()> {
|
|
||||||
let rhs = f.var_name_of(self.reg.pop(1));
|
|
||||||
let lhs = f.var_name_of(self.reg.pop(1));
|
|
||||||
|
|
||||||
self.reg.push(1);
|
|
||||||
|
|
||||||
write!(w, "{1} = {1} {0} {2} and 1 or 0 ", op, lhs, rhs)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn gen_unop_ex(&mut self, op: &str, f: &Code, w: Writer) -> Result<()> {
|
|
||||||
let reg = f.var_name_of(self.reg.pop(1));
|
|
||||||
|
|
||||||
self.reg.push(1);
|
|
||||||
|
|
||||||
write!(w, "{1} = {0}({1}) ", op, reg)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn gen_binop(&mut self, op: &str, f: &Code, w: Writer) -> Result<()> {
|
|
||||||
let rhs = f.var_name_of(self.reg.pop(1));
|
|
||||||
let lhs = f.var_name_of(self.reg.pop(1));
|
|
||||||
|
|
||||||
self.reg.push(1);
|
|
||||||
|
|
||||||
write!(w, "{1} = {1} {0} {2} ", op, lhs, rhs)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn gen_binop_ex(&mut self, op: &str, f: &Code, w: Writer) -> Result<()> {
|
|
||||||
let rhs = f.var_name_of(self.reg.pop(1));
|
|
||||||
let lhs = f.var_name_of(self.reg.pop(1));
|
|
||||||
|
|
||||||
self.reg.push(1);
|
|
||||||
|
|
||||||
write!(w, "{1} = {0}({1}, {2}) ", op, lhs, rhs)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn gen_call(&mut self, name: &str, f: &Code, a: &Arity, w: Writer) -> Result<()> {
|
|
||||||
let bottom = self.reg.pop(a.num_param);
|
|
||||||
|
|
||||||
self.reg.push(a.num_result);
|
|
||||||
|
|
||||||
if a.num_result != 0 {
|
|
||||||
let result = f.var_range_of(bottom, a.num_result).join(", ");
|
|
||||||
|
|
||||||
write!(w, "{} =", result)?;
|
|
||||||
}
|
|
||||||
|
|
||||||
if a.num_param == 0 {
|
|
||||||
write!(w, "{}()", name)
|
|
||||||
} else {
|
|
||||||
let param = f.var_range_of(bottom, a.num_param).join(", ");
|
|
||||||
|
|
||||||
write!(w, "{}({})", name, param)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn gen_return(&mut self, num: u32, f: &Code, w: Writer) -> Result<()> {
|
|
||||||
let top = self.reg.inner;
|
|
||||||
let list = f.var_range_of(top - num, num).join(", ");
|
|
||||||
|
|
||||||
self.reg.pop(num); // technically a no-op
|
|
||||||
|
|
||||||
write!(w, "do return {} end ", list)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn gen_inst(&mut self, index: usize, i: &Instruction, m: &Module, w: Writer) -> Result<()> {
|
|
||||||
let func = &m.code[index];
|
|
||||||
|
|
||||||
match i {
|
|
||||||
Instruction::Unreachable => write!(w, "error('unreachable code entered')"),
|
|
||||||
Instruction::Nop => {
|
|
||||||
// no code
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
Instruction::Block(_) => {
|
|
||||||
self.reg.save();
|
|
||||||
self.label_list.push(Label::Block);
|
|
||||||
|
|
||||||
self.spec.start_block(w)
|
|
||||||
}
|
|
||||||
Instruction::Loop(_) => {
|
|
||||||
self.reg.save();
|
|
||||||
self.label_list.push(Label::Loop);
|
|
||||||
|
|
||||||
self.spec.start_loop(self.label_list.len() - 1, w)
|
|
||||||
}
|
|
||||||
Instruction::If(_) => {
|
|
||||||
let cond = func.var_name_of(self.reg.pop(1));
|
|
||||||
|
|
||||||
self.reg.save();
|
|
||||||
self.label_list.push(Label::If);
|
|
||||||
|
|
||||||
self.spec.start_if(&cond, w)
|
|
||||||
}
|
|
||||||
Instruction::Else => {
|
|
||||||
self.reg.load();
|
|
||||||
self.reg.save();
|
|
||||||
|
|
||||||
write!(w, "else ")
|
|
||||||
}
|
|
||||||
Instruction::End => {
|
|
||||||
let rem = self.label_list.len().saturating_sub(1);
|
|
||||||
|
|
||||||
match self.label_list.pop() {
|
|
||||||
Some(Label::Block) => self.spec.end_block(rem, w)?,
|
|
||||||
Some(Label::If) => self.spec.end_if(rem, w)?,
|
|
||||||
Some(Label::Loop) => self.spec.end_loop(w)?,
|
|
||||||
None => {
|
|
||||||
let num = m.in_arity[index].num_result;
|
|
||||||
|
|
||||||
if num != 0 {
|
|
||||||
self.gen_return(num, func, w)?;
|
|
||||||
}
|
|
||||||
|
|
||||||
write!(w, "end ")?;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
self.reg.load();
|
|
||||||
|
|
||||||
match self.label_list.last() {
|
|
||||||
Some(Label::Block | Label::If) => self.spec.br_target(rem, false, w),
|
|
||||||
Some(Label::Loop) => self.spec.br_target(rem, true, w),
|
|
||||||
None => Ok(()),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Instruction::Br(i) => self.gen_jump(*i, w),
|
|
||||||
Instruction::BrIf(i) => self.gen_br_if(*i, func, w),
|
|
||||||
Instruction::BrTable(data) => self.gen_br_table(data, func, w),
|
|
||||||
Instruction::Return => {
|
|
||||||
let num = m.in_arity[index].num_result;
|
|
||||||
|
|
||||||
self.gen_return(num, func, w)
|
|
||||||
}
|
|
||||||
Instruction::Call(i) => {
|
|
||||||
let name = format!("FUNC_LIST[{}]", i);
|
|
||||||
let arity = m.arity_of(*i as usize);
|
|
||||||
|
|
||||||
self.gen_call(&name, func, arity, w)
|
|
||||||
}
|
|
||||||
Instruction::CallIndirect(i, t) => {
|
|
||||||
let index = func.var_name_of(self.reg.pop(1));
|
|
||||||
let name = format!("TABLE_LIST[{}].data[{}]", t, index);
|
|
||||||
let types = m.parent.type_section().unwrap().types();
|
|
||||||
let arity = Arity::from_index(types, *i);
|
|
||||||
|
|
||||||
self.gen_call(&name, func, &arity, w)
|
|
||||||
}
|
|
||||||
Instruction::Drop => {
|
|
||||||
self.reg.pop(1);
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
Instruction::Select => {
|
|
||||||
let cond = func.var_name_of(self.reg.pop(1));
|
|
||||||
let v2 = func.var_name_of(self.reg.pop(1));
|
|
||||||
let v1 = func.var_name_of(self.reg.pop(1));
|
|
||||||
|
|
||||||
self.reg.push(1);
|
|
||||||
|
|
||||||
write!(w, "if {} == 0 then ", cond)?;
|
|
||||||
write!(w, "{} = {} ", v1, v2)?;
|
|
||||||
write!(w, "end ")
|
|
||||||
}
|
|
||||||
Instruction::GetLocal(i) => {
|
|
||||||
let reg = func.var_name_of(self.reg.push(1));
|
|
||||||
let var = func.var_name_of(*i);
|
|
||||||
|
|
||||||
write!(w, "{} = {} ", reg, var)
|
|
||||||
}
|
|
||||||
Instruction::SetLocal(i) => {
|
|
||||||
let var = func.var_name_of(*i);
|
|
||||||
let reg = func.var_name_of(self.reg.pop(1));
|
|
||||||
|
|
||||||
write!(w, "{} = {} ", var, reg)
|
|
||||||
}
|
|
||||||
Instruction::TeeLocal(i) => {
|
|
||||||
let var = func.var_name_of(*i);
|
|
||||||
let reg = func.var_name_of(self.reg.pop(1));
|
|
||||||
|
|
||||||
self.reg.push(1);
|
|
||||||
|
|
||||||
write!(w, "{} = {} ", var, reg)
|
|
||||||
}
|
|
||||||
Instruction::GetGlobal(i) => {
|
|
||||||
let reg = func.var_name_of(self.reg.push(1));
|
|
||||||
|
|
||||||
write!(w, "{} = GLOBAL_LIST[{}].value ", reg, i)
|
|
||||||
}
|
|
||||||
Instruction::SetGlobal(i) => {
|
|
||||||
let reg = func.var_name_of(self.reg.pop(1));
|
|
||||||
|
|
||||||
write!(w, "GLOBAL_LIST[{}].value = {} ", i, reg)
|
|
||||||
}
|
|
||||||
Instruction::I32Load(_, o) => self.gen_load("i32", *o, func, w),
|
|
||||||
Instruction::I64Load(_, o) => self.gen_load("i64", *o, func, w),
|
|
||||||
Instruction::F32Load(_, o) => self.gen_load("f32", *o, func, w),
|
|
||||||
Instruction::F64Load(_, o) => self.gen_load("f64", *o, func, w),
|
|
||||||
Instruction::I32Load8S(_, o) => self.gen_load("i32_i8", *o, func, w),
|
|
||||||
Instruction::I32Load8U(_, o) => self.gen_load("i32_u8", *o, func, w),
|
|
||||||
Instruction::I32Load16S(_, o) => self.gen_load("i32_i16", *o, func, w),
|
|
||||||
Instruction::I32Load16U(_, o) => self.gen_load("i32_u16", *o, func, w),
|
|
||||||
Instruction::I64Load8S(_, o) => self.gen_load("i64_i8", *o, func, w),
|
|
||||||
Instruction::I64Load8U(_, o) => self.gen_load("i64_u8", *o, func, w),
|
|
||||||
Instruction::I64Load16S(_, o) => self.gen_load("i64_i16", *o, func, w),
|
|
||||||
Instruction::I64Load16U(_, o) => self.gen_load("i64_u16", *o, func, w),
|
|
||||||
Instruction::I64Load32S(_, o) => self.gen_load("i64_i32", *o, func, w),
|
|
||||||
Instruction::I64Load32U(_, o) => self.gen_load("i64_u32", *o, func, w),
|
|
||||||
Instruction::I32Store(_, o) => self.gen_store("i32", *o, func, w),
|
|
||||||
Instruction::I64Store(_, o) => self.gen_store("i64", *o, func, w),
|
|
||||||
Instruction::F32Store(_, o) => self.gen_store("f32", *o, func, w),
|
|
||||||
Instruction::F64Store(_, o) => self.gen_store("f64", *o, func, w),
|
|
||||||
Instruction::I32Store8(_, o) => self.gen_store("i32_n8", *o, func, w),
|
|
||||||
Instruction::I32Store16(_, o) => self.gen_store("i32_n16", *o, func, w),
|
|
||||||
Instruction::I64Store8(_, o) => self.gen_store("i64_n8", *o, func, w),
|
|
||||||
Instruction::I64Store16(_, o) => self.gen_store("i64_n16", *o, func, w),
|
|
||||||
Instruction::I64Store32(_, o) => self.gen_store("i64_n32", *o, func, w),
|
|
||||||
Instruction::CurrentMemory(index) => {
|
|
||||||
let reg = func.var_name_of(self.reg.push(1));
|
|
||||||
|
|
||||||
write!(w, "{} = rt.memory.size(memory_at_{})", reg, index)
|
|
||||||
}
|
|
||||||
Instruction::GrowMemory(index) => {
|
|
||||||
let reg = func.var_name_of(self.reg.pop(1));
|
|
||||||
|
|
||||||
self.reg.push(1);
|
|
||||||
|
|
||||||
write!(w, "{0} = rt.memory.grow(memory_at_{1}, {0})", reg, index)
|
|
||||||
}
|
|
||||||
Instruction::I32Const(v) => self.gen_const(v, func, w),
|
|
||||||
Instruction::I64Const(v) => self.gen_const(self.spec.i64(*v), func, w),
|
|
||||||
Instruction::F32Const(v) => self.gen_const(f32::from_bits(*v), func, w),
|
|
||||||
Instruction::F64Const(v) => self.gen_const(f64::from_bits(*v), func, w),
|
|
||||||
Instruction::I32Eqz | Instruction::I64Eqz => {
|
|
||||||
let reg = func.var_name_of(self.reg.pop(1));
|
|
||||||
|
|
||||||
self.reg.push(1);
|
|
||||||
|
|
||||||
write!(w, "{} = {} == 0 and 1 or 0 ", reg, reg)
|
|
||||||
}
|
|
||||||
Instruction::I32Eq | Instruction::I64Eq | Instruction::F32Eq | Instruction::F64Eq => {
|
|
||||||
self.gen_compare("==", func, w)
|
|
||||||
}
|
|
||||||
Instruction::I32Ne | Instruction::I64Ne | Instruction::F32Ne | Instruction::F64Ne => {
|
|
||||||
self.gen_compare("~=", func, w)
|
|
||||||
}
|
|
||||||
// note that signed comparisons of all types behave the same so
|
|
||||||
// they can be condensed using Lua's operators
|
|
||||||
Instruction::I32LtU => self.gen_binop_ex("lt_u32", func, w),
|
|
||||||
Instruction::I32LtS | Instruction::I64LtS | Instruction::F32Lt | Instruction::F64Lt => {
|
|
||||||
self.gen_compare("<", func, w)
|
|
||||||
}
|
|
||||||
Instruction::I32GtU => self.gen_binop_ex("gt_u32", func, w),
|
|
||||||
Instruction::I32GtS | Instruction::I64GtS | Instruction::F32Gt | Instruction::F64Gt => {
|
|
||||||
self.gen_compare(">", func, w)
|
|
||||||
}
|
|
||||||
Instruction::I32LeU => self.gen_binop_ex("le_u32", func, w),
|
|
||||||
Instruction::I32LeS | Instruction::I64LeS | Instruction::F32Le | Instruction::F64Le => {
|
|
||||||
self.gen_compare("<=", func, w)
|
|
||||||
}
|
|
||||||
Instruction::I32GeU => self.gen_binop_ex("ge_u32", func, w),
|
|
||||||
Instruction::I32GeS | Instruction::I64GeS | Instruction::F32Ge | Instruction::F64Ge => {
|
|
||||||
self.gen_compare(">=", func, w)
|
|
||||||
}
|
|
||||||
Instruction::I64LtU => self.gen_binop_ex("lt_u64", func, w),
|
|
||||||
Instruction::I64GtU => self.gen_binop_ex("gt_u64", func, w),
|
|
||||||
Instruction::I64LeU => self.gen_binop_ex("le_u64", func, w),
|
|
||||||
Instruction::I64GeU => self.gen_binop_ex("ge_u64", func, w),
|
|
||||||
Instruction::I32Clz => self.gen_unop_ex("clz_i32", func, w),
|
|
||||||
Instruction::I32Ctz => self.gen_unop_ex("ctz_i32", func, w),
|
|
||||||
Instruction::I32Popcnt => self.gen_unop_ex("popcnt_i32", func, w),
|
|
||||||
Instruction::I32DivS => self.gen_binop_ex("div_i32", func, w),
|
|
||||||
Instruction::I32DivU => self.gen_binop_ex("div_u32", func, w),
|
|
||||||
Instruction::I32RemS => self.gen_binop_ex("rem_i32", func, w),
|
|
||||||
Instruction::I32RemU => self.gen_binop_ex("rem_u32", func, w),
|
|
||||||
Instruction::I32And => self.gen_binop_ex("band_i32", func, w),
|
|
||||||
Instruction::I32Or => self.gen_binop_ex("bor_i32", func, w),
|
|
||||||
Instruction::I32Xor => self.gen_binop_ex("bxor_i32", func, w),
|
|
||||||
Instruction::I32Shl => self.gen_binop_ex("shl_i32", func, w),
|
|
||||||
Instruction::I32ShrS => self.gen_binop_ex("shr_i32", func, w),
|
|
||||||
Instruction::I32ShrU => self.gen_binop_ex("shr_u32", func, w),
|
|
||||||
Instruction::I32Rotl => self.gen_binop_ex("rotl_i32", func, w),
|
|
||||||
Instruction::I32Rotr => self.gen_binop_ex("rotr_i32", func, w),
|
|
||||||
Instruction::I64Clz => self.gen_unop_ex("clz_i64", func, w),
|
|
||||||
Instruction::I64Ctz => self.gen_unop_ex("ctz_i64", func, w),
|
|
||||||
Instruction::I64Popcnt => self.gen_unop_ex("popcnt_i64", func, w),
|
|
||||||
Instruction::I64DivS => self.gen_binop_ex("div_i64", func, w),
|
|
||||||
Instruction::I64DivU => self.gen_binop_ex("div_u64", func, w),
|
|
||||||
Instruction::I64RemS => self.gen_binop_ex("rem_i64", func, w),
|
|
||||||
Instruction::I64RemU => self.gen_binop_ex("rem_u64", func, w),
|
|
||||||
Instruction::I64And => self.gen_binop_ex("band_i64", func, w),
|
|
||||||
Instruction::I64Or => self.gen_binop_ex("bor_i64", func, w),
|
|
||||||
Instruction::I64Xor => self.gen_binop_ex("bxor_i64", func, w),
|
|
||||||
Instruction::I64Shl => self.gen_binop_ex("shl_i64", func, w),
|
|
||||||
Instruction::I64ShrS => self.gen_binop_ex("shr_i64", func, w),
|
|
||||||
Instruction::I64ShrU => self.gen_binop_ex("shr_u64", func, w),
|
|
||||||
Instruction::I64Rotl => self.gen_binop_ex("rotl_i64", func, w),
|
|
||||||
Instruction::I64Rotr => self.gen_binop_ex("rotr_i64", func, w),
|
|
||||||
Instruction::F32Abs | Instruction::F64Abs => self.gen_unop_ex("math_abs", func, w),
|
|
||||||
Instruction::F32Neg | Instruction::F64Neg => {
|
|
||||||
let reg = func.var_name_of(self.reg.pop(1));
|
|
||||||
|
|
||||||
self.reg.push(1);
|
|
||||||
|
|
||||||
write!(w, "{} = -{} ", reg, reg)
|
|
||||||
}
|
|
||||||
Instruction::F32Ceil | Instruction::F64Ceil => self.gen_unop_ex("math_ceil", func, w),
|
|
||||||
Instruction::F32Floor | Instruction::F64Floor => {
|
|
||||||
self.gen_unop_ex("math_floor", func, w)
|
|
||||||
}
|
|
||||||
Instruction::F32Trunc | Instruction::F64Trunc => self.gen_unop_ex("trunc_f", func, w),
|
|
||||||
Instruction::F32Nearest | Instruction::F64Nearest => {
|
|
||||||
self.gen_unop_ex("nearest_f", func, w)
|
|
||||||
}
|
|
||||||
Instruction::F32Sqrt | Instruction::F64Sqrt => self.gen_unop_ex("math_sqrt", func, w),
|
|
||||||
Instruction::I32Add
|
|
||||||
| Instruction::I64Add
|
|
||||||
| Instruction::F32Add
|
|
||||||
| Instruction::F64Add => self.gen_binop("+", func, w),
|
|
||||||
Instruction::I32Sub
|
|
||||||
| Instruction::I64Sub
|
|
||||||
| Instruction::F32Sub
|
|
||||||
| Instruction::F64Sub => self.gen_binop("-", func, w),
|
|
||||||
Instruction::I32Mul
|
|
||||||
| Instruction::I64Mul
|
|
||||||
| Instruction::F32Mul
|
|
||||||
| Instruction::F64Mul => self.gen_binop("*", func, w),
|
|
||||||
Instruction::F32Div | Instruction::F64Div => self.gen_binop("/", func, w),
|
|
||||||
Instruction::F32Min | Instruction::F64Min => self.gen_binop_ex("math_min", func, w),
|
|
||||||
Instruction::F32Max | Instruction::F64Max => self.gen_binop_ex("math_max", func, w),
|
|
||||||
Instruction::F32Copysign | Instruction::F64Copysign => {
|
|
||||||
self.gen_unop_ex("math_sign", func, w)
|
|
||||||
}
|
|
||||||
Instruction::I32WrapI64 => self.gen_unop_ex("wrap_i64_i32", func, w),
|
|
||||||
Instruction::I32TruncSF32 => self.gen_unop_ex("trunc_f32_i32", func, w),
|
|
||||||
Instruction::I32TruncUF32 => self.gen_unop_ex("trunc_f32_u32", func, w),
|
|
||||||
Instruction::I32TruncSF64 => self.gen_unop_ex("trunc_f64_i32", func, w),
|
|
||||||
Instruction::I32TruncUF64 => self.gen_unop_ex("trunc_f64_u32", func, w),
|
|
||||||
Instruction::I64ExtendSI32 => self.gen_unop_ex("extend_i32_i64", func, w),
|
|
||||||
Instruction::I64ExtendUI32 => self.gen_unop_ex("extend_i32_u64", func, w),
|
|
||||||
Instruction::I64TruncSF32 => self.gen_unop_ex("trunc_f32_i64", func, w),
|
|
||||||
Instruction::I64TruncUF32 => self.gen_unop_ex("trunc_f32_u64", func, w),
|
|
||||||
Instruction::I64TruncSF64 => self.gen_unop_ex("trunc_f64_i64", func, w),
|
|
||||||
Instruction::I64TruncUF64 => self.gen_unop_ex("trunc_f64_u64", func, w),
|
|
||||||
Instruction::F32ConvertSI32 => self.gen_unop_ex("convert_i32_f32", func, w),
|
|
||||||
Instruction::F32ConvertUI32 => self.gen_unop_ex("convert_u32_f32", func, w),
|
|
||||||
Instruction::F32ConvertSI64 => self.gen_unop_ex("convert_i64_f32", func, w),
|
|
||||||
Instruction::F32ConvertUI64 => self.gen_unop_ex("convert_u64_f32", func, w),
|
|
||||||
Instruction::F32DemoteF64 => self.gen_unop_ex("demote_f64_f32", func, w),
|
|
||||||
Instruction::F64ConvertSI32 => self.gen_unop_ex("convert_f64_i32", func, w),
|
|
||||||
Instruction::F64ConvertUI32 => self.gen_unop_ex("convert_f64_u32", func, w),
|
|
||||||
Instruction::F64ConvertSI64 => self.gen_unop_ex("convert_f64_i64", func, w),
|
|
||||||
Instruction::F64ConvertUI64 => self.gen_unop_ex("convert_f64_u64", func, w),
|
|
||||||
Instruction::F64PromoteF32 => self.gen_unop_ex("promote_f32_f64", func, w),
|
|
||||||
Instruction::I32ReinterpretF32 => self.gen_unop_ex("reinterpret_f32_i32", func, w),
|
|
||||||
Instruction::I64ReinterpretF64 => self.gen_unop_ex("reinterpret_f64_i64", func, w),
|
|
||||||
Instruction::F32ReinterpretI32 => self.gen_unop_ex("reinterpret_i32_f32", func, w),
|
|
||||||
Instruction::F64ReinterpretI64 => self.gen_unop_ex("reinterpret_i64_f64", func, w),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,86 +0,0 @@
|
|||||||
use std::{collections::BTreeSet, io::Result};
|
|
||||||
|
|
||||||
use parity_wasm::elements::Instruction;
|
|
||||||
|
|
||||||
use crate::{
|
|
||||||
backend::{
|
|
||||||
edition::data::Edition,
|
|
||||||
helper::writer::{write_ordered, Writer},
|
|
||||||
visitor::{localize, memory, register},
|
|
||||||
},
|
|
||||||
data::Module,
|
|
||||||
};
|
|
||||||
|
|
||||||
use super::level_1::Body;
|
|
||||||
|
|
||||||
pub fn gen_init_expression(code: &[Instruction], w: Writer) -> Result<()> {
|
|
||||||
assert!(code.len() == 2);
|
|
||||||
|
|
||||||
let inst = code.first().unwrap();
|
|
||||||
|
|
||||||
match *inst {
|
|
||||||
Instruction::I32Const(v) => write!(w, "{} ", v),
|
|
||||||
Instruction::I64Const(v) => write!(w, "{} ", v),
|
|
||||||
Instruction::F32Const(v) => write!(w, "{} ", f32::from_bits(v)),
|
|
||||||
Instruction::F64Const(v) => write!(w, "{} ", f64::from_bits(v)),
|
|
||||||
Instruction::GetGlobal(i) => write!(w, "GLOBAL_LIST[{}].value ", i),
|
|
||||||
_ => unreachable!(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn gen_prelude(num_stack: u32, num_param: u32, num_local: u32, w: Writer) -> Result<()> {
|
|
||||||
let num_reg = num_stack - num_param - num_local;
|
|
||||||
|
|
||||||
write!(w, "function(")?;
|
|
||||||
write_ordered("param", num_param, w)?;
|
|
||||||
write!(w, ")")?;
|
|
||||||
|
|
||||||
if num_local != 0 {
|
|
||||||
let zero = vec!["0"; num_local as usize].join(", ");
|
|
||||||
|
|
||||||
write!(w, "local ")?;
|
|
||||||
write_ordered("var", num_local, w)?;
|
|
||||||
write!(w, "= {} ", zero)?;
|
|
||||||
}
|
|
||||||
|
|
||||||
if num_reg != 0 {
|
|
||||||
write!(w, "local ")?;
|
|
||||||
write_ordered("reg", num_reg, w)?;
|
|
||||||
write!(w, " ")?;
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn gen_memory(set: BTreeSet<u8>, w: Writer) -> Result<()> {
|
|
||||||
set.into_iter()
|
|
||||||
.try_for_each(|i| write!(w, "local memory_at_{0} = MEMORY_LIST[{0}]", i))
|
|
||||||
}
|
|
||||||
|
|
||||||
fn gen_localize(set: BTreeSet<(&str, &str)>, w: Writer) -> Result<()> {
|
|
||||||
set.into_iter()
|
|
||||||
.try_for_each(|v| write!(w, "local {0}_{1} = {0}.{1} ", v.0, v.1))
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn gen_function(spec: &dyn Edition, index: usize, m: &Module, w: Writer) -> Result<()> {
|
|
||||||
let mem_set = memory::visit(m, index);
|
|
||||||
let loc_set = localize::visit(m, index);
|
|
||||||
let num_stack = register::visit(m, index);
|
|
||||||
|
|
||||||
let num_param = m.in_arity[index].num_param;
|
|
||||||
let num_local = m.code[index].num_local;
|
|
||||||
|
|
||||||
let mut inner = Body::new(spec, num_param + num_local);
|
|
||||||
|
|
||||||
gen_prelude(num_stack, num_param, num_local, w)?;
|
|
||||||
gen_memory(mem_set, w)?;
|
|
||||||
gen_localize(loc_set, w)?;
|
|
||||||
inner.generate(index, m, w)?;
|
|
||||||
|
|
||||||
assert!(
|
|
||||||
inner.reg.last == num_stack,
|
|
||||||
"Mismatched register allocation"
|
|
||||||
);
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
@ -1,276 +0,0 @@
|
|||||||
use std::io::Result;
|
|
||||||
|
|
||||||
use parity_wasm::elements::{External, ImportCountType, Internal, ResizableLimits};
|
|
||||||
|
|
||||||
use crate::{
|
|
||||||
backend::{edition::data::Edition, helper::writer::Writer},
|
|
||||||
data::Module,
|
|
||||||
};
|
|
||||||
|
|
||||||
use super::level_2::{gen_function, gen_init_expression};
|
|
||||||
|
|
||||||
const RUNTIME_DATA: &str = "
|
|
||||||
local add = rt.add
|
|
||||||
local sub = rt.sub
|
|
||||||
local mul = rt.mul
|
|
||||||
local div = rt.div
|
|
||||||
|
|
||||||
local le = rt.le
|
|
||||||
local lt = rt.lt
|
|
||||||
local ge = rt.ge
|
|
||||||
local gt = rt.gt
|
|
||||||
|
|
||||||
local band = rt.band
|
|
||||||
local bor = rt.bor
|
|
||||||
local bxor = rt.bxor
|
|
||||||
local bnot = rt.bnot
|
|
||||||
|
|
||||||
local shl = rt.shl
|
|
||||||
local shr = rt.shr
|
|
||||||
|
|
||||||
local extend = rt.extend
|
|
||||||
local wrap = rt.wrap
|
|
||||||
|
|
||||||
local load = rt.load
|
|
||||||
local store = rt.store
|
|
||||||
";
|
|
||||||
|
|
||||||
fn gen_import_of<T>(m: &Module, w: Writer, lower: &str, cond: T) -> Result<()>
|
|
||||||
where
|
|
||||||
T: Fn(&External) -> bool,
|
|
||||||
{
|
|
||||||
let import = match m.parent.import_section() {
|
|
||||||
Some(v) => v.entries(),
|
|
||||||
None => return Ok(()),
|
|
||||||
};
|
|
||||||
let upper = lower.to_uppercase();
|
|
||||||
|
|
||||||
for (i, v) in import.iter().filter(|v| cond(v.external())).enumerate() {
|
|
||||||
let field = v.field();
|
|
||||||
let module = v.module();
|
|
||||||
|
|
||||||
write!(w, "{}[{}] = wasm.{}.{}.{} ", upper, i, module, lower, field)?;
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn aux_internal_index(internal: Internal) -> u32 {
|
|
||||||
match internal {
|
|
||||||
Internal::Function(v) | Internal::Table(v) | Internal::Memory(v) | Internal::Global(v) => v,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn gen_export_of<T>(m: &Module, w: Writer, lower: &str, cond: T) -> Result<()>
|
|
||||||
where
|
|
||||||
T: Fn(&Internal) -> bool,
|
|
||||||
{
|
|
||||||
let export = match m.parent.export_section() {
|
|
||||||
Some(v) => v.entries(),
|
|
||||||
None => return Ok(()),
|
|
||||||
};
|
|
||||||
let upper = lower.to_uppercase();
|
|
||||||
|
|
||||||
write!(w, "{} = {{", lower)?;
|
|
||||||
|
|
||||||
for v in export.iter().filter(|v| cond(v.internal())) {
|
|
||||||
let field = v.field();
|
|
||||||
let index = aux_internal_index(*v.internal());
|
|
||||||
|
|
||||||
write!(w, "{} = {}[{}],", field, upper, index)?;
|
|
||||||
}
|
|
||||||
|
|
||||||
write!(w, "}},")
|
|
||||||
}
|
|
||||||
|
|
||||||
fn gen_import_list(m: &Module, w: Writer) -> Result<()> {
|
|
||||||
gen_import_of(m, w, "func_list", |v| matches!(v, External::Function(_)))?;
|
|
||||||
gen_import_of(m, w, "table_list", |v| matches!(v, External::Table(_)))?;
|
|
||||||
gen_import_of(m, w, "memory_list", |v| matches!(v, External::Memory(_)))?;
|
|
||||||
gen_import_of(m, w, "global_list", |v| matches!(v, External::Global(_)))
|
|
||||||
}
|
|
||||||
|
|
||||||
fn gen_export_list(m: &Module, w: Writer) -> Result<()> {
|
|
||||||
gen_export_of(m, w, "func_list", |v| matches!(v, Internal::Function(_)))?;
|
|
||||||
gen_export_of(m, w, "table_list", |v| matches!(v, Internal::Table(_)))?;
|
|
||||||
gen_export_of(m, w, "memory_list", |v| matches!(v, Internal::Memory(_)))?;
|
|
||||||
gen_export_of(m, w, "global_list", |v| matches!(v, Internal::Global(_)))
|
|
||||||
}
|
|
||||||
|
|
||||||
fn gen_table_init(limit: &ResizableLimits, w: Writer) -> Result<()> {
|
|
||||||
write!(w, "{{ min = {}", limit.initial())?;
|
|
||||||
|
|
||||||
if let Some(max) = limit.maximum() {
|
|
||||||
write!(w, ", max = {}", max)?;
|
|
||||||
}
|
|
||||||
|
|
||||||
write!(w, ", data = {{}} }}")
|
|
||||||
}
|
|
||||||
|
|
||||||
fn gen_memory_init(limit: &ResizableLimits, w: Writer) -> Result<()> {
|
|
||||||
write!(w, "rt.memory.new({}, ", limit.initial())?;
|
|
||||||
|
|
||||||
if let Some(max) = limit.maximum() {
|
|
||||||
write!(w, "{}", max)?;
|
|
||||||
} else {
|
|
||||||
write!(w, "nil")?;
|
|
||||||
}
|
|
||||||
|
|
||||||
write!(w, ")")
|
|
||||||
}
|
|
||||||
|
|
||||||
fn gen_table_list(m: &Module, w: Writer) -> Result<()> {
|
|
||||||
let table = match m.parent.table_section() {
|
|
||||||
Some(v) => v.entries(),
|
|
||||||
None => return Ok(()),
|
|
||||||
};
|
|
||||||
let offset = m.parent.import_count(ImportCountType::Table);
|
|
||||||
|
|
||||||
for (i, v) in table.iter().enumerate() {
|
|
||||||
let index = i + offset;
|
|
||||||
|
|
||||||
write!(w, "TABLE_LIST[{}] =", index)?;
|
|
||||||
gen_table_init(v.limits(), w)?;
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn gen_memory_list(m: &Module, w: Writer) -> Result<()> {
|
|
||||||
let memory = match m.parent.memory_section() {
|
|
||||||
Some(v) => v.entries(),
|
|
||||||
None => return Ok(()),
|
|
||||||
};
|
|
||||||
let offset = m.parent.import_count(ImportCountType::Memory);
|
|
||||||
|
|
||||||
for (i, v) in memory.iter().enumerate() {
|
|
||||||
let index = i + offset;
|
|
||||||
|
|
||||||
write!(w, "MEMORY_LIST[{}] =", index)?;
|
|
||||||
gen_memory_init(v.limits(), w)?;
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn gen_global_list(m: &Module, w: Writer) -> Result<()> {
|
|
||||||
let global = match m.parent.global_section() {
|
|
||||||
Some(v) => v,
|
|
||||||
None => return Ok(()),
|
|
||||||
};
|
|
||||||
let offset = m.parent.import_count(ImportCountType::Global);
|
|
||||||
|
|
||||||
for (i, v) in global.entries().iter().enumerate() {
|
|
||||||
let index = i + offset;
|
|
||||||
|
|
||||||
write!(w, "GLOBAL_LIST[{}] = {{ value =", index)?;
|
|
||||||
gen_init_expression(v.init_expr().code(), w)?;
|
|
||||||
write!(w, "}}")?;
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn gen_element_list(m: &Module, w: Writer) -> Result<()> {
|
|
||||||
let element = match m.parent.elements_section() {
|
|
||||||
Some(v) => v.entries(),
|
|
||||||
None => return Ok(()),
|
|
||||||
};
|
|
||||||
|
|
||||||
for v in element {
|
|
||||||
write!(w, "do ")?;
|
|
||||||
write!(w, "local target = TABLE_LIST[{}].data ", v.index())?;
|
|
||||||
write!(w, "local offset =")?;
|
|
||||||
|
|
||||||
gen_init_expression(v.offset().as_ref().unwrap().code(), w)?;
|
|
||||||
|
|
||||||
for (i, f) in v.members().iter().enumerate() {
|
|
||||||
write!(w, "target[offset + {}] = FUNC_LIST[{}]", i, f)?;
|
|
||||||
}
|
|
||||||
|
|
||||||
write!(w, "end ")?;
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn gen_data_list(m: &Module, w: Writer) -> Result<()> {
|
|
||||||
let data = match m.parent.data_section() {
|
|
||||||
Some(v) => v.entries(),
|
|
||||||
None => return Ok(()),
|
|
||||||
};
|
|
||||||
|
|
||||||
for v in data {
|
|
||||||
write!(w, "do ")?;
|
|
||||||
write!(w, "local target = MEMORY_LIST[{}]", v.index())?;
|
|
||||||
write!(w, "local offset =")?;
|
|
||||||
|
|
||||||
gen_init_expression(v.offset().as_ref().unwrap().code(), w)?;
|
|
||||||
|
|
||||||
write!(w, "local data = \"")?;
|
|
||||||
|
|
||||||
v.value()
|
|
||||||
.iter()
|
|
||||||
.try_for_each(|v| write!(w, "\\x{:02X}", v))?;
|
|
||||||
|
|
||||||
write!(w, "\"")?;
|
|
||||||
|
|
||||||
write!(w, "rt.memory.init(target, offset, data)")?;
|
|
||||||
|
|
||||||
write!(w, "end ")?;
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn gen_start_point(m: &Module, w: Writer) -> Result<()> {
|
|
||||||
write!(w, "local function run_init_code()")?;
|
|
||||||
gen_table_list(m, w)?;
|
|
||||||
gen_memory_list(m, w)?;
|
|
||||||
gen_global_list(m, w)?;
|
|
||||||
gen_element_list(m, w)?;
|
|
||||||
gen_data_list(m, w)?;
|
|
||||||
write!(w, "end ")?;
|
|
||||||
|
|
||||||
write!(w, "return function(wasm)")?;
|
|
||||||
gen_import_list(m, w)?;
|
|
||||||
write!(w, "run_init_code()")?;
|
|
||||||
|
|
||||||
if let Some(start) = m.parent.start_section() {
|
|
||||||
write!(w, "FUNC_LIST[{}]()", start)?;
|
|
||||||
}
|
|
||||||
|
|
||||||
write!(w, "return {{")?;
|
|
||||||
gen_export_list(m, w)?;
|
|
||||||
write!(w, "}} end ")
|
|
||||||
}
|
|
||||||
|
|
||||||
fn gen_nil_array(name: &str, len: usize, w: Writer) -> Result<()> {
|
|
||||||
if len == 0 {
|
|
||||||
return Ok(());
|
|
||||||
}
|
|
||||||
|
|
||||||
let list = vec!["nil"; len].join(", ");
|
|
||||||
|
|
||||||
write!(w, "local {} = {{[0] = {}}}", name, list)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn translate(spec: &dyn Edition, m: &Module, w: Writer) -> Result<()> {
|
|
||||||
write!(w, "local rt = require({})", spec.runtime())?;
|
|
||||||
write!(w, "{}", RUNTIME_DATA)?;
|
|
||||||
|
|
||||||
gen_nil_array("FUNC_LIST", m.in_arity.len(), w)?;
|
|
||||||
gen_nil_array("TABLE_LIST", m.parent.table_space(), w)?;
|
|
||||||
gen_nil_array("MEMORY_LIST", m.parent.memory_space(), w)?;
|
|
||||||
gen_nil_array("GLOBAL_LIST", m.parent.globals_space(), w)?;
|
|
||||||
|
|
||||||
let offset = m.ex_arity.len();
|
|
||||||
|
|
||||||
for i in 0..m.in_arity.len() {
|
|
||||||
write!(w, "FUNC_LIST[{}] =", i + offset)?;
|
|
||||||
|
|
||||||
gen_function(spec, i, m, w)?;
|
|
||||||
}
|
|
||||||
|
|
||||||
gen_start_point(m, w)
|
|
||||||
}
|
|
11
src/backend/translator/mod.rs
Executable file → Normal file
11
src/backend/translator/mod.rs
Executable file → Normal file
@ -1,8 +1,3 @@
|
|||||||
// Translation is done in levels.
|
pub mod arity;
|
||||||
// Level 1 handles user logic and WASM instructions.
|
pub mod data;
|
||||||
// Level 2 handles setup for functions.
|
mod writer;
|
||||||
// Level 3 handles initialization of the module.
|
|
||||||
|
|
||||||
mod level_1;
|
|
||||||
mod level_2;
|
|
||||||
pub mod level_3;
|
|
||||||
|
485
src/backend/translator/writer.rs
Normal file
485
src/backend/translator/writer.rs
Normal file
@ -0,0 +1,485 @@
|
|||||||
|
use std::{
|
||||||
|
io::{Result, Write},
|
||||||
|
ops::Range,
|
||||||
|
};
|
||||||
|
|
||||||
|
use crate::backend::{
|
||||||
|
ast::data::{
|
||||||
|
AnyBinOp, AnyLoad, AnyStore, AnyUnOp, Backward, Br, BrIf, BrTable, Call, CallIndirect,
|
||||||
|
Expression, Forward, Function, GetGlobal, GetLocal, If, Memorize, MemoryGrow, MemorySize,
|
||||||
|
Return, Select, SetGlobal, SetLocal, Statement, Value,
|
||||||
|
},
|
||||||
|
edition::data::Edition,
|
||||||
|
visitor::{localize, memory},
|
||||||
|
};
|
||||||
|
|
||||||
|
fn write_in_order(prefix: &'static str, len: u32, w: &mut dyn Write) -> Result<()> {
|
||||||
|
if len == 0 {
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
|
||||||
|
write!(w, "{}_{}", prefix, 0)?;
|
||||||
|
(1..len).try_for_each(|i| write!(w, ", {}_{}", prefix, i))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn write_br_gadget(rem: usize, d: &mut Data, w: &mut dyn Write) -> Result<()> {
|
||||||
|
match d.label_list.last() {
|
||||||
|
Some(Label::Forward | Label::If) => d.edition.br_target(rem, false, w),
|
||||||
|
Some(Label::Backward) => d.edition.br_target(rem, true, w),
|
||||||
|
None => Ok(()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn list_to_range(list: &[u32]) -> Vec<(Range<usize>, u32)> {
|
||||||
|
let mut result = Vec::new();
|
||||||
|
let mut index = 0;
|
||||||
|
|
||||||
|
while index < list.len() {
|
||||||
|
let start = index;
|
||||||
|
|
||||||
|
loop {
|
||||||
|
index += 1;
|
||||||
|
|
||||||
|
// if end of list or next value is not equal, break
|
||||||
|
if index == list.len() || list[index - 1] != list[index] {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
result.push((start..index, list[start]));
|
||||||
|
}
|
||||||
|
|
||||||
|
result
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(PartialEq, Eq)]
|
||||||
|
enum Label {
|
||||||
|
Forward,
|
||||||
|
Backward,
|
||||||
|
If,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Data<'a> {
|
||||||
|
label_list: Vec<Label>,
|
||||||
|
num_param: u32,
|
||||||
|
edition: &'a dyn Edition,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> Data<'a> {
|
||||||
|
pub fn new(num_param: u32, edition: &'a dyn Edition) -> Self {
|
||||||
|
Self {
|
||||||
|
label_list: Vec::new(),
|
||||||
|
num_param,
|
||||||
|
edition,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Select {
|
||||||
|
fn output(&self, d: &mut Data, w: &mut dyn Write) -> Result<()> {
|
||||||
|
write!(w, "(")?;
|
||||||
|
self.cond.output(d, w)?;
|
||||||
|
write!(w, " ~= 0 and ")?;
|
||||||
|
self.a.output(d, w)?;
|
||||||
|
write!(w, " or ")?;
|
||||||
|
self.b.output(d, w)?;
|
||||||
|
write!(w, ")")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl GetLocal {
|
||||||
|
fn write_variable(var: u32, d: &Data, w: &mut dyn Write) -> Result<()> {
|
||||||
|
if let Some(rem) = var.checked_sub(d.num_param) {
|
||||||
|
write!(w, "loc_{} ", rem)
|
||||||
|
} else {
|
||||||
|
write!(w, "param_{} ", var)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn output(&self, d: &Data, w: &mut dyn Write) -> Result<()> {
|
||||||
|
Self::write_variable(self.var, d, w)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl GetGlobal {
|
||||||
|
fn output(&self, w: &mut dyn Write) -> Result<()> {
|
||||||
|
write!(w, "GLOBAL_LIST[{}].value ", self.var)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl AnyLoad {
|
||||||
|
fn output(&self, d: &mut Data, w: &mut dyn Write) -> Result<()> {
|
||||||
|
write!(w, "load_{}(memory_at_0, ", self.op.as_name())?;
|
||||||
|
self.pointer.output(d, w)?;
|
||||||
|
write!(w, "+ {})", self.offset)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl MemorySize {
|
||||||
|
fn output(&self, w: &mut dyn Write) -> Result<()> {
|
||||||
|
write!(w, "rt.memory.size(memory_at_{})", self.memory)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl MemoryGrow {
|
||||||
|
fn output(&self, d: &mut Data, w: &mut dyn Write) -> Result<()> {
|
||||||
|
write!(w, "rt.memory.grow(memory_at_{}, ", self.memory)?;
|
||||||
|
self.value.output(d, w)?;
|
||||||
|
write!(w, ")")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Value {
|
||||||
|
fn output(&self, d: &Data, w: &mut dyn Write) -> Result<()> {
|
||||||
|
match self {
|
||||||
|
Self::I32(i) => write!(w, "{} ", i),
|
||||||
|
Self::I64(i) => write!(w, "{} ", d.edition.i64(*i)),
|
||||||
|
Self::F32(f) => write!(w, "{} ", f),
|
||||||
|
Self::F64(f) => write!(w, "{} ", f),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl AnyUnOp {
|
||||||
|
fn write_as_call(&self, d: &mut Data, w: &mut dyn Write) -> Result<()> {
|
||||||
|
let (a, b) = self.op.as_name();
|
||||||
|
|
||||||
|
write!(w, "{}_{}(", a, b)?;
|
||||||
|
self.rhs.output(d, w)?;
|
||||||
|
write!(w, ")")
|
||||||
|
}
|
||||||
|
|
||||||
|
fn output(&self, d: &mut Data, w: &mut dyn Write) -> Result<()> {
|
||||||
|
if let Some(op) = self.op.as_operator() {
|
||||||
|
write!(w, "{}", op)?;
|
||||||
|
self.rhs.output(d, w)
|
||||||
|
} else {
|
||||||
|
self.write_as_call(d, w)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl AnyBinOp {
|
||||||
|
fn write_as_op(&self, op: &'static str, d: &mut Data, w: &mut dyn Write) -> Result<()> {
|
||||||
|
write!(w, "(")?;
|
||||||
|
self.lhs.output(d, w)?;
|
||||||
|
write!(w, "{} ", op)?;
|
||||||
|
self.rhs.output(d, w)?;
|
||||||
|
write!(w, ")")
|
||||||
|
}
|
||||||
|
|
||||||
|
fn write_as_call(&self, d: &mut Data, w: &mut dyn Write) -> Result<()> {
|
||||||
|
let (a, b) = self.op.as_name();
|
||||||
|
|
||||||
|
write!(w, "{}_{}(", a, b)?;
|
||||||
|
self.lhs.output(d, w)?;
|
||||||
|
write!(w, ", ")?;
|
||||||
|
self.rhs.output(d, w)?;
|
||||||
|
write!(w, ")")
|
||||||
|
}
|
||||||
|
|
||||||
|
fn output(&self, d: &mut Data, w: &mut dyn Write) -> Result<()> {
|
||||||
|
if let Some(op) = self.op.as_operator() {
|
||||||
|
self.write_as_op(op, d, w)
|
||||||
|
} else {
|
||||||
|
self.write_as_call(d, w)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Expression {
|
||||||
|
fn write_list(list: &[Self], d: &mut Data, w: &mut dyn Write) -> Result<()> {
|
||||||
|
list.iter().enumerate().try_for_each(|(i, v)| {
|
||||||
|
if i != 0 {
|
||||||
|
write!(w, ", ")?;
|
||||||
|
}
|
||||||
|
|
||||||
|
v.output(d, w)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn output(&self, d: &mut Data, w: &mut dyn Write) -> Result<()> {
|
||||||
|
match self {
|
||||||
|
Self::Recall(i) => write!(w, "reg_{} ", i),
|
||||||
|
Self::Select(s) => s.output(d, w),
|
||||||
|
Self::GetLocal(g) => g.output(d, w),
|
||||||
|
Self::GetGlobal(g) => g.output(w),
|
||||||
|
Self::AnyLoad(a) => a.output(d, w),
|
||||||
|
Self::MemorySize(m) => m.output(w),
|
||||||
|
Self::MemoryGrow(m) => m.output(d, w),
|
||||||
|
Self::Value(v) => v.output(d, w),
|
||||||
|
Self::AnyUnOp(a) => a.output(d, w),
|
||||||
|
Self::AnyBinOp(a) => a.output(d, w),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn to_buffer(&self, d: &mut Data) -> Result<String> {
|
||||||
|
let mut buf = Vec::new();
|
||||||
|
|
||||||
|
self.output(d, &mut buf)?;
|
||||||
|
|
||||||
|
Ok(String::from_utf8(buf).unwrap())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Memorize {
|
||||||
|
fn output(&self, d: &mut Data, w: &mut dyn Write) -> Result<()> {
|
||||||
|
write!(w, "reg_{} = ", self.var)?;
|
||||||
|
self.value.output(d, w)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Forward {
|
||||||
|
fn output(&self, d: &mut Data, w: &mut dyn Write) -> Result<()> {
|
||||||
|
let rem = d.label_list.len();
|
||||||
|
|
||||||
|
d.label_list.push(Label::Forward);
|
||||||
|
d.edition.start_block(w)?;
|
||||||
|
|
||||||
|
self.body.iter().try_for_each(|s| s.output(d, w))?;
|
||||||
|
|
||||||
|
d.edition.end_block(rem, w)?;
|
||||||
|
d.label_list.pop().unwrap();
|
||||||
|
|
||||||
|
write_br_gadget(rem, d, w)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Backward {
|
||||||
|
fn output(&self, d: &mut Data, w: &mut dyn Write) -> Result<()> {
|
||||||
|
let rem = d.label_list.len();
|
||||||
|
|
||||||
|
d.label_list.push(Label::Backward);
|
||||||
|
d.edition.start_loop(rem, w)?;
|
||||||
|
|
||||||
|
self.body.iter().try_for_each(|s| s.output(d, w))?;
|
||||||
|
|
||||||
|
d.edition.end_loop(w)?;
|
||||||
|
d.label_list.pop().unwrap();
|
||||||
|
|
||||||
|
write_br_gadget(rem, d, w)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl If {
|
||||||
|
fn output(&self, d: &mut Data, w: &mut dyn Write) -> Result<()> {
|
||||||
|
let rem = d.label_list.len();
|
||||||
|
|
||||||
|
d.label_list.push(Label::If);
|
||||||
|
|
||||||
|
let var = self.cond.to_buffer(d)?;
|
||||||
|
|
||||||
|
d.edition.start_if(&var, w)?;
|
||||||
|
|
||||||
|
self.body.iter().try_for_each(|s| s.output(d, w))?;
|
||||||
|
|
||||||
|
d.edition.end_if(rem, w)?;
|
||||||
|
d.label_list.pop().unwrap();
|
||||||
|
|
||||||
|
write_br_gadget(rem, d, w)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Br {
|
||||||
|
fn write_at(up: u32, d: &Data, w: &mut dyn Write) -> Result<()> {
|
||||||
|
let up = up as usize;
|
||||||
|
let level = d.label_list.len() - 1;
|
||||||
|
let is_loop = d.label_list[level - up] == Label::Backward;
|
||||||
|
|
||||||
|
d.edition.br_to_level(level, up, is_loop, w)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn output(&self, d: &Data, w: &mut dyn Write) -> Result<()> {
|
||||||
|
Self::write_at(self.target, d, w)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl BrIf {
|
||||||
|
fn output(&self, d: &mut Data, w: &mut dyn Write) -> Result<()> {
|
||||||
|
write!(w, "if ")?;
|
||||||
|
self.cond.output(d, w)?;
|
||||||
|
write!(w, "~= 0 then ")?;
|
||||||
|
Br::write_at(self.target, d, w)?;
|
||||||
|
write!(w, "end ")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl BrTable {
|
||||||
|
fn output(&self, d: &mut Data, w: &mut dyn Write) -> Result<()> {
|
||||||
|
write!(w, "local temp = ")?;
|
||||||
|
self.cond.output(d, w)?;
|
||||||
|
write!(w, " ")?;
|
||||||
|
|
||||||
|
for (r, t) in list_to_range(&self.data.table) {
|
||||||
|
if r.len() == 1 {
|
||||||
|
write!(w, "if temp == {} then ", r.start)?;
|
||||||
|
} else {
|
||||||
|
write!(w, "if temp >= {} and temp <= {} then ", r.start, r.end)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
Br::write_at(t, d, w)?;
|
||||||
|
write!(w, "else")?;
|
||||||
|
}
|
||||||
|
|
||||||
|
write!(w, " ")?;
|
||||||
|
Br::write_at(self.data.default, d, w)?;
|
||||||
|
write!(w, "end ")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Return {
|
||||||
|
fn output(&self, d: &mut Data, w: &mut dyn Write) -> Result<()> {
|
||||||
|
write!(w, "do return ")?;
|
||||||
|
|
||||||
|
self.list.iter().enumerate().try_for_each(|(i, v)| {
|
||||||
|
if i > 0 {
|
||||||
|
write!(w, ", ")?;
|
||||||
|
}
|
||||||
|
|
||||||
|
v.output(d, w)
|
||||||
|
})?;
|
||||||
|
|
||||||
|
write!(w, "end ")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Call {
|
||||||
|
fn write_result_list(range: Range<u32>, w: &mut dyn Write) -> Result<()> {
|
||||||
|
if range.is_empty() {
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
|
||||||
|
range.clone().try_for_each(|i| {
|
||||||
|
if i != range.start {
|
||||||
|
write!(w, ", ")?;
|
||||||
|
}
|
||||||
|
|
||||||
|
write!(w, "reg_{}", i)
|
||||||
|
})?;
|
||||||
|
|
||||||
|
write!(w, " = ")
|
||||||
|
}
|
||||||
|
|
||||||
|
fn output(&self, d: &mut Data, w: &mut dyn Write) -> Result<()> {
|
||||||
|
Self::write_result_list(self.result.clone(), w)?;
|
||||||
|
|
||||||
|
write!(w, "FUNC_LIST[{}](", self.func)?;
|
||||||
|
|
||||||
|
Expression::write_list(&self.param_list, d, w)?;
|
||||||
|
|
||||||
|
write!(w, ")")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl CallIndirect {
|
||||||
|
fn output(&self, d: &mut Data, w: &mut dyn Write) -> Result<()> {
|
||||||
|
Call::write_result_list(self.result.clone(), w)?;
|
||||||
|
|
||||||
|
write!(w, "TABLE_LIST[{}][", self.table)?;
|
||||||
|
|
||||||
|
self.index.output(d, w)?;
|
||||||
|
|
||||||
|
write!(w, "](")?;
|
||||||
|
|
||||||
|
Expression::write_list(&self.param_list, d, w)?;
|
||||||
|
|
||||||
|
write!(w, ")")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SetLocal {
|
||||||
|
fn output(&self, d: &mut Data, w: &mut dyn Write) -> Result<()> {
|
||||||
|
GetLocal::write_variable(self.var, d, w)?;
|
||||||
|
|
||||||
|
write!(w, "= ")?;
|
||||||
|
self.value.output(d, w)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SetGlobal {
|
||||||
|
fn output(&self, d: &mut Data, w: &mut dyn Write) -> Result<()> {
|
||||||
|
write!(w, "GLOBAL_LIST[{}].value = ", self.var)?;
|
||||||
|
self.value.output(d, w)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl AnyStore {
|
||||||
|
fn output(&self, d: &mut Data, w: &mut dyn Write) -> Result<()> {
|
||||||
|
write!(w, "store_{}(memory_at_0, ", self.op.as_name())?;
|
||||||
|
self.pointer.output(d, w)?;
|
||||||
|
write!(w, "+ {}, ", self.offset)?;
|
||||||
|
self.value.output(d, w)?;
|
||||||
|
write!(w, ")")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Statement {
|
||||||
|
fn output(&self, d: &mut Data, w: &mut dyn Write) -> Result<()> {
|
||||||
|
match self {
|
||||||
|
Statement::Unreachable => write!(w, "error(\"out of code bounds\")"),
|
||||||
|
Statement::Memorize(v) => v.output(d, w),
|
||||||
|
Statement::Forward(v) => v.output(d, w),
|
||||||
|
Statement::Backward(v) => v.output(d, w),
|
||||||
|
Statement::If(v) => v.output(d, w),
|
||||||
|
Statement::Br(v) => v.output(d, w),
|
||||||
|
Statement::BrIf(v) => v.output(d, w),
|
||||||
|
Statement::BrTable(v) => v.output(d, w),
|
||||||
|
Statement::Return(v) => v.output(d, w),
|
||||||
|
Statement::Call(v) => v.output(d, w),
|
||||||
|
Statement::CallIndirect(v) => v.output(d, w),
|
||||||
|
Statement::SetLocal(v) => v.output(d, w),
|
||||||
|
Statement::SetGlobal(v) => v.output(d, w),
|
||||||
|
Statement::AnyStore(v) => v.output(d, w),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Function {
|
||||||
|
fn write_variable_list(&self, w: &mut dyn Write) -> Result<()> {
|
||||||
|
if self.num_local != 0 {
|
||||||
|
let list = vec!["0"; self.num_local as usize].join(", ");
|
||||||
|
|
||||||
|
write!(w, "local ")?;
|
||||||
|
write_in_order("loc", self.num_local, w)?;
|
||||||
|
write!(w, " = {} ", list)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
if self.num_stack != 0 {
|
||||||
|
write!(w, "local ")?;
|
||||||
|
write_in_order("reg", self.num_stack, w)?;
|
||||||
|
write!(w, " ")?;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn write_visitor_list(&self, w: &mut dyn Write) -> Result<()> {
|
||||||
|
let memory = memory::visit(self);
|
||||||
|
let localize = localize::visit(self);
|
||||||
|
|
||||||
|
for v in memory {
|
||||||
|
write!(w, "local memory_at_{0} = MEMORY_LIST[{0}]", v)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (a, b) in localize {
|
||||||
|
write!(w, "local {0}_{1} = rt.{0}.{1} ", a, b)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn output(&self, d: &mut Data, w: &mut dyn Write) -> Result<()> {
|
||||||
|
write!(w, "function(")?;
|
||||||
|
|
||||||
|
write_in_order("param", self.num_param, w)?;
|
||||||
|
|
||||||
|
write!(w, ")")?;
|
||||||
|
|
||||||
|
self.write_visitor_list(w)?;
|
||||||
|
self.write_variable_list(w)?;
|
||||||
|
|
||||||
|
self.body.iter().try_for_each(|s| s.output(d, w))?;
|
||||||
|
|
||||||
|
write!(w, "end ")
|
||||||
|
}
|
||||||
|
}
|
59
src/backend/visitor/data.rs
Normal file
59
src/backend/visitor/data.rs
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
use crate::backend::ast::data::{
|
||||||
|
AnyBinOp, AnyLoad, AnyStore, AnyUnOp, Backward, Br, BrIf, BrTable, Call, CallIndirect,
|
||||||
|
Expression, Forward, GetGlobal, GetLocal, If, Memorize, MemoryGrow, MemorySize, Return, Select,
|
||||||
|
SetGlobal, SetLocal, Statement, Value,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub trait Visitor {
|
||||||
|
fn visit_recall(&mut self, _: usize) {}
|
||||||
|
|
||||||
|
fn visit_select(&mut self, _: &Select) {}
|
||||||
|
|
||||||
|
fn visit_get_local(&mut self, _: &GetLocal) {}
|
||||||
|
|
||||||
|
fn visit_get_global(&mut self, _: &GetGlobal) {}
|
||||||
|
|
||||||
|
fn visit_any_load(&mut self, _: &AnyLoad) {}
|
||||||
|
|
||||||
|
fn visit_memory_size(&mut self, _: &MemorySize) {}
|
||||||
|
|
||||||
|
fn visit_memory_grow(&mut self, _: &MemoryGrow) {}
|
||||||
|
|
||||||
|
fn visit_value(&mut self, _: &Value) {}
|
||||||
|
|
||||||
|
fn visit_any_unop(&mut self, _: &AnyUnOp) {}
|
||||||
|
|
||||||
|
fn visit_any_binop(&mut self, _: &AnyBinOp) {}
|
||||||
|
|
||||||
|
fn visit_expression(&mut self, _: &Expression) {}
|
||||||
|
|
||||||
|
fn visit_unreachable(&mut self) {}
|
||||||
|
|
||||||
|
fn visit_memorize(&mut self, _: &Memorize) {}
|
||||||
|
|
||||||
|
fn visit_forward(&mut self, _: &Forward) {}
|
||||||
|
|
||||||
|
fn visit_backward(&mut self, _: &Backward) {}
|
||||||
|
|
||||||
|
fn visit_if(&mut self, _: &If) {}
|
||||||
|
|
||||||
|
fn visit_br(&mut self, _: &Br) {}
|
||||||
|
|
||||||
|
fn visit_br_if(&mut self, _: &BrIf) {}
|
||||||
|
|
||||||
|
fn visit_br_table(&mut self, _: &BrTable) {}
|
||||||
|
|
||||||
|
fn visit_return(&mut self, _: &Return) {}
|
||||||
|
|
||||||
|
fn visit_call(&mut self, _: &Call) {}
|
||||||
|
|
||||||
|
fn visit_call_indirect(&mut self, _: &CallIndirect) {}
|
||||||
|
|
||||||
|
fn visit_set_local(&mut self, _: &SetLocal) {}
|
||||||
|
|
||||||
|
fn visit_set_global(&mut self, _: &SetGlobal) {}
|
||||||
|
|
||||||
|
fn visit_any_store(&mut self, _: &AnyStore) {}
|
||||||
|
|
||||||
|
fn visit_statement(&mut self, _: &Statement) {}
|
||||||
|
}
|
@ -1,24 +1,53 @@
|
|||||||
use std::{collections::BTreeSet, convert::TryFrom};
|
use std::collections::BTreeSet;
|
||||||
|
|
||||||
use crate::{
|
use crate::backend::ast::data::{AnyBinOp, AnyLoad, AnyStore, AnyUnOp, Function};
|
||||||
backend::helper::operation::{BinOp, Load, Named, Store, UnOp},
|
|
||||||
data::Module,
|
|
||||||
};
|
|
||||||
|
|
||||||
pub fn visit(m: &Module, index: usize) -> BTreeSet<(&'static str, &'static str)> {
|
use super::data::Visitor;
|
||||||
let mut result = BTreeSet::new();
|
|
||||||
|
|
||||||
for i in m.code[index].inst_list {
|
struct Visit {
|
||||||
if let Ok(used) = Load::try_from(i) {
|
result: BTreeSet<(&'static str, &'static str)>,
|
||||||
result.insert(used.as_name());
|
}
|
||||||
} else if let Ok(used) = Store::try_from(i) {
|
|
||||||
result.insert(used.as_name());
|
impl Visitor for Visit {
|
||||||
} else if let Ok(used) = UnOp::try_from(i) {
|
fn visit_any_load(&mut self, v: &AnyLoad) {
|
||||||
result.insert(used.as_name());
|
let name = v.op.as_name();
|
||||||
} else if let Ok(used) = BinOp::try_from(i) {
|
|
||||||
result.insert(used.as_name());
|
self.result.insert(("load", name));
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
result
|
fn visit_any_store(&mut self, v: &AnyStore) {
|
||||||
|
let name = v.op.as_name();
|
||||||
|
|
||||||
|
self.result.insert(("store", name));
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_any_unop(&mut self, v: &AnyUnOp) {
|
||||||
|
if v.op.as_operator().is_some() {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let name = v.op.as_name();
|
||||||
|
|
||||||
|
self.result.insert(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_any_binop(&mut self, v: &AnyBinOp) {
|
||||||
|
if v.op.as_operator().is_some() {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let name = v.op.as_name();
|
||||||
|
|
||||||
|
self.result.insert(name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn visit(func: &Function) -> BTreeSet<(&'static str, &'static str)> {
|
||||||
|
let mut visit = Visit {
|
||||||
|
result: BTreeSet::new(),
|
||||||
|
};
|
||||||
|
|
||||||
|
func.accept(&mut visit);
|
||||||
|
|
||||||
|
visit.result
|
||||||
}
|
}
|
||||||
|
@ -1,45 +1,37 @@
|
|||||||
use std::collections::BTreeSet;
|
use std::collections::BTreeSet;
|
||||||
|
|
||||||
use parity_wasm::elements::Instruction;
|
use crate::backend::ast::data::{AnyLoad, AnyStore, Function, MemoryGrow, MemorySize};
|
||||||
|
|
||||||
use crate::data::Module;
|
use super::data::Visitor;
|
||||||
|
|
||||||
pub fn visit(m: &Module, index: usize) -> BTreeSet<u8> {
|
struct Visit {
|
||||||
let mut result = BTreeSet::new();
|
result: BTreeSet<u8>,
|
||||||
|
}
|
||||||
|
|
||||||
for i in m.code[index].inst_list {
|
impl Visitor for Visit {
|
||||||
match i {
|
fn visit_any_store(&mut self, _: &AnyStore) {
|
||||||
Instruction::I32Store(_, _)
|
self.result.insert(0);
|
||||||
| Instruction::I64Store(_, _)
|
|
||||||
| Instruction::F32Store(_, _)
|
|
||||||
| Instruction::F64Store(_, _)
|
|
||||||
| Instruction::I32Store8(_, _)
|
|
||||||
| Instruction::I32Store16(_, _)
|
|
||||||
| Instruction::I64Store8(_, _)
|
|
||||||
| Instruction::I64Store16(_, _)
|
|
||||||
| Instruction::I64Store32(_, _)
|
|
||||||
| Instruction::I32Load(_, _)
|
|
||||||
| Instruction::I64Load(_, _)
|
|
||||||
| Instruction::F32Load(_, _)
|
|
||||||
| Instruction::F64Load(_, _)
|
|
||||||
| Instruction::I32Load8S(_, _)
|
|
||||||
| Instruction::I32Load8U(_, _)
|
|
||||||
| Instruction::I32Load16S(_, _)
|
|
||||||
| Instruction::I32Load16U(_, _)
|
|
||||||
| Instruction::I64Load8S(_, _)
|
|
||||||
| Instruction::I64Load8U(_, _)
|
|
||||||
| Instruction::I64Load16S(_, _)
|
|
||||||
| Instruction::I64Load16U(_, _)
|
|
||||||
| Instruction::I64Load32S(_, _)
|
|
||||||
| Instruction::I64Load32U(_, _) => {
|
|
||||||
result.insert(0);
|
|
||||||
}
|
|
||||||
Instruction::CurrentMemory(index) | Instruction::GrowMemory(index) => {
|
|
||||||
result.insert(*index);
|
|
||||||
}
|
|
||||||
_ => {}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
result
|
fn visit_any_load(&mut self, _: &AnyLoad) {
|
||||||
|
self.result.insert(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_memory_size(&mut self, m: &MemorySize) {
|
||||||
|
self.result.insert(m.memory);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_memory_grow(&mut self, m: &MemoryGrow) {
|
||||||
|
self.result.insert(m.memory);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn visit(func: &Function) -> BTreeSet<u8> {
|
||||||
|
let mut visit = Visit {
|
||||||
|
result: BTreeSet::new(),
|
||||||
|
};
|
||||||
|
|
||||||
|
func.accept(&mut visit);
|
||||||
|
|
||||||
|
visit.result
|
||||||
}
|
}
|
||||||
|
@ -1,3 +1,3 @@
|
|||||||
|
pub mod data;
|
||||||
pub mod localize;
|
pub mod localize;
|
||||||
pub mod memory;
|
pub mod memory;
|
||||||
pub mod register;
|
|
||||||
|
@ -1,225 +0,0 @@
|
|||||||
use parity_wasm::elements::Instruction;
|
|
||||||
|
|
||||||
use crate::{
|
|
||||||
backend::helper::register::Register,
|
|
||||||
data::{Arity, Module},
|
|
||||||
};
|
|
||||||
|
|
||||||
pub fn visit(m: &Module, index: usize) -> u32 {
|
|
||||||
let mut reg = Register::new();
|
|
||||||
let num_param = m.in_arity[index].num_param;
|
|
||||||
let num_local = m.code[index].num_local;
|
|
||||||
|
|
||||||
reg.push(num_param + num_local);
|
|
||||||
|
|
||||||
for i in m.code[index].inst_list {
|
|
||||||
match i {
|
|
||||||
Instruction::Block(_) | Instruction::Loop(_) => {
|
|
||||||
reg.save();
|
|
||||||
}
|
|
||||||
Instruction::If(_) => {
|
|
||||||
reg.pop(1);
|
|
||||||
reg.save();
|
|
||||||
}
|
|
||||||
Instruction::Else => {
|
|
||||||
reg.load();
|
|
||||||
reg.save();
|
|
||||||
}
|
|
||||||
Instruction::End => {
|
|
||||||
reg.load();
|
|
||||||
}
|
|
||||||
Instruction::BrIf(_)
|
|
||||||
| Instruction::BrTable(_)
|
|
||||||
| Instruction::Drop
|
|
||||||
| Instruction::SetLocal(_)
|
|
||||||
| Instruction::SetGlobal(_) => {
|
|
||||||
reg.pop(1);
|
|
||||||
}
|
|
||||||
Instruction::Call(i) => {
|
|
||||||
let arity = m.arity_of(*i as usize);
|
|
||||||
|
|
||||||
reg.pop(arity.num_param);
|
|
||||||
reg.push(arity.num_result);
|
|
||||||
}
|
|
||||||
Instruction::CallIndirect(i, _) => {
|
|
||||||
let types = m.parent.type_section().unwrap().types();
|
|
||||||
let arity = Arity::from_index(types, *i);
|
|
||||||
|
|
||||||
reg.pop(arity.num_param + 1);
|
|
||||||
reg.push(arity.num_result);
|
|
||||||
}
|
|
||||||
Instruction::Select => {
|
|
||||||
reg.pop(3);
|
|
||||||
reg.push(1);
|
|
||||||
}
|
|
||||||
Instruction::GetLocal(_)
|
|
||||||
| Instruction::GetGlobal(_)
|
|
||||||
| Instruction::CurrentMemory(_)
|
|
||||||
| Instruction::I32Const(_)
|
|
||||||
| Instruction::I64Const(_)
|
|
||||||
| Instruction::F32Const(_)
|
|
||||||
| Instruction::F64Const(_) => {
|
|
||||||
reg.push(1);
|
|
||||||
}
|
|
||||||
Instruction::TeeLocal(_)
|
|
||||||
| Instruction::I32Load(_, _)
|
|
||||||
| Instruction::I64Load(_, _)
|
|
||||||
| Instruction::F32Load(_, _)
|
|
||||||
| Instruction::F64Load(_, _)
|
|
||||||
| Instruction::I32Load8S(_, _)
|
|
||||||
| Instruction::I32Load8U(_, _)
|
|
||||||
| Instruction::I32Load16S(_, _)
|
|
||||||
| Instruction::I32Load16U(_, _)
|
|
||||||
| Instruction::I64Load8S(_, _)
|
|
||||||
| Instruction::I64Load8U(_, _)
|
|
||||||
| Instruction::I64Load16S(_, _)
|
|
||||||
| Instruction::I64Load16U(_, _)
|
|
||||||
| Instruction::I64Load32S(_, _)
|
|
||||||
| Instruction::I64Load32U(_, _)
|
|
||||||
| Instruction::GrowMemory(_)
|
|
||||||
| Instruction::I32Eqz
|
|
||||||
| Instruction::I64Eqz
|
|
||||||
| Instruction::I32Clz
|
|
||||||
| Instruction::I32Ctz
|
|
||||||
| Instruction::I32Popcnt
|
|
||||||
| Instruction::I64Clz
|
|
||||||
| Instruction::I64Ctz
|
|
||||||
| Instruction::I64Popcnt
|
|
||||||
| Instruction::F32Abs
|
|
||||||
| Instruction::F32Neg
|
|
||||||
| Instruction::F32Ceil
|
|
||||||
| Instruction::F32Floor
|
|
||||||
| Instruction::F32Trunc
|
|
||||||
| Instruction::F32Nearest
|
|
||||||
| Instruction::F32Sqrt
|
|
||||||
| Instruction::F32Copysign
|
|
||||||
| Instruction::F64Abs
|
|
||||||
| Instruction::F64Neg
|
|
||||||
| Instruction::F64Ceil
|
|
||||||
| Instruction::F64Floor
|
|
||||||
| Instruction::F64Trunc
|
|
||||||
| Instruction::F64Nearest
|
|
||||||
| Instruction::F64Sqrt
|
|
||||||
| Instruction::F64Copysign
|
|
||||||
| Instruction::I32WrapI64
|
|
||||||
| Instruction::I32TruncSF32
|
|
||||||
| Instruction::I32TruncUF32
|
|
||||||
| Instruction::I32TruncSF64
|
|
||||||
| Instruction::I32TruncUF64
|
|
||||||
| Instruction::I64ExtendSI32
|
|
||||||
| Instruction::I64ExtendUI32
|
|
||||||
| Instruction::I64TruncSF32
|
|
||||||
| Instruction::I64TruncUF32
|
|
||||||
| Instruction::I64TruncSF64
|
|
||||||
| Instruction::I64TruncUF64
|
|
||||||
| Instruction::F32ConvertSI32
|
|
||||||
| Instruction::F32ConvertUI32
|
|
||||||
| Instruction::F32ConvertSI64
|
|
||||||
| Instruction::F32ConvertUI64
|
|
||||||
| Instruction::F32DemoteF64
|
|
||||||
| Instruction::F64ConvertSI32
|
|
||||||
| Instruction::F64ConvertUI32
|
|
||||||
| Instruction::F64ConvertSI64
|
|
||||||
| Instruction::F64ConvertUI64
|
|
||||||
| Instruction::F64PromoteF32
|
|
||||||
| Instruction::I32ReinterpretF32
|
|
||||||
| Instruction::I64ReinterpretF64
|
|
||||||
| Instruction::F32ReinterpretI32
|
|
||||||
| Instruction::F64ReinterpretI64 => {
|
|
||||||
reg.pop(1);
|
|
||||||
reg.push(1);
|
|
||||||
}
|
|
||||||
Instruction::I32Store(_, _)
|
|
||||||
| Instruction::I64Store(_, _)
|
|
||||||
| Instruction::F32Store(_, _)
|
|
||||||
| Instruction::F64Store(_, _)
|
|
||||||
| Instruction::I32Store8(_, _)
|
|
||||||
| Instruction::I32Store16(_, _)
|
|
||||||
| Instruction::I64Store8(_, _)
|
|
||||||
| Instruction::I64Store16(_, _)
|
|
||||||
| Instruction::I64Store32(_, _) => {
|
|
||||||
reg.pop(2);
|
|
||||||
}
|
|
||||||
Instruction::I32Eq
|
|
||||||
| Instruction::I32Ne
|
|
||||||
| Instruction::I32LtS
|
|
||||||
| Instruction::I32LtU
|
|
||||||
| Instruction::I32GtS
|
|
||||||
| Instruction::I32GtU
|
|
||||||
| Instruction::I32LeS
|
|
||||||
| Instruction::I32LeU
|
|
||||||
| Instruction::I32GeS
|
|
||||||
| Instruction::I32GeU
|
|
||||||
| Instruction::I64Eq
|
|
||||||
| Instruction::I64Ne
|
|
||||||
| Instruction::I64LtS
|
|
||||||
| Instruction::I64LtU
|
|
||||||
| Instruction::I64GtS
|
|
||||||
| Instruction::I64GtU
|
|
||||||
| Instruction::I64LeS
|
|
||||||
| Instruction::I64LeU
|
|
||||||
| Instruction::I64GeS
|
|
||||||
| Instruction::I64GeU
|
|
||||||
| Instruction::F32Eq
|
|
||||||
| Instruction::F32Ne
|
|
||||||
| Instruction::F32Lt
|
|
||||||
| Instruction::F32Gt
|
|
||||||
| Instruction::F32Le
|
|
||||||
| Instruction::F32Ge
|
|
||||||
| Instruction::F64Eq
|
|
||||||
| Instruction::F64Ne
|
|
||||||
| Instruction::F64Lt
|
|
||||||
| Instruction::F64Gt
|
|
||||||
| Instruction::F64Le
|
|
||||||
| Instruction::F64Ge
|
|
||||||
| Instruction::I32Add
|
|
||||||
| Instruction::I32Sub
|
|
||||||
| Instruction::I32Mul
|
|
||||||
| Instruction::I32DivS
|
|
||||||
| Instruction::I32DivU
|
|
||||||
| Instruction::I32RemS
|
|
||||||
| Instruction::I32RemU
|
|
||||||
| Instruction::I32And
|
|
||||||
| Instruction::I32Or
|
|
||||||
| Instruction::I32Xor
|
|
||||||
| Instruction::I32Shl
|
|
||||||
| Instruction::I32ShrS
|
|
||||||
| Instruction::I32ShrU
|
|
||||||
| Instruction::I32Rotl
|
|
||||||
| Instruction::I32Rotr
|
|
||||||
| Instruction::I64Add
|
|
||||||
| Instruction::I64Sub
|
|
||||||
| Instruction::I64Mul
|
|
||||||
| Instruction::I64DivS
|
|
||||||
| Instruction::I64DivU
|
|
||||||
| Instruction::I64RemS
|
|
||||||
| Instruction::I64RemU
|
|
||||||
| Instruction::I64And
|
|
||||||
| Instruction::I64Or
|
|
||||||
| Instruction::I64Xor
|
|
||||||
| Instruction::I64Shl
|
|
||||||
| Instruction::I64ShrS
|
|
||||||
| Instruction::I64ShrU
|
|
||||||
| Instruction::I64Rotl
|
|
||||||
| Instruction::I64Rotr
|
|
||||||
| Instruction::F32Add
|
|
||||||
| Instruction::F32Sub
|
|
||||||
| Instruction::F32Mul
|
|
||||||
| Instruction::F32Div
|
|
||||||
| Instruction::F32Min
|
|
||||||
| Instruction::F32Max
|
|
||||||
| Instruction::F64Add
|
|
||||||
| Instruction::F64Sub
|
|
||||||
| Instruction::F64Mul
|
|
||||||
| Instruction::F64Div
|
|
||||||
| Instruction::F64Min
|
|
||||||
| Instruction::F64Max => {
|
|
||||||
reg.pop(2);
|
|
||||||
reg.push(1);
|
|
||||||
}
|
|
||||||
_ => {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
reg.last
|
|
||||||
}
|
|
149
src/data.rs
149
src/data.rs
@ -1,149 +0,0 @@
|
|||||||
use std::{borrow::Cow, convert::TryInto};
|
|
||||||
|
|
||||||
use parity_wasm::elements::{
|
|
||||||
External, FunctionType, ImportEntry, Instruction, Local, Module as WasmModule, Type,
|
|
||||||
};
|
|
||||||
|
|
||||||
use crate::backend::helper::writer::ordered_iter;
|
|
||||||
|
|
||||||
pub struct Code<'a> {
|
|
||||||
pub num_local: u32,
|
|
||||||
pub inst_list: &'a [Instruction],
|
|
||||||
var_list: Vec<String>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> Code<'a> {
|
|
||||||
pub fn new(inst_list: &'a [Instruction], num_local: u32) -> Self {
|
|
||||||
Self {
|
|
||||||
num_local,
|
|
||||||
inst_list,
|
|
||||||
var_list: Vec::new(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn local_sum(list: &[Local]) -> u32 {
|
|
||||||
list.iter().map(Local::count).sum()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn var_name_of(&self, index: u32) -> Cow<'_, str> {
|
|
||||||
let index: usize = index.try_into().unwrap();
|
|
||||||
let offset = self.var_list.len();
|
|
||||||
|
|
||||||
self.var_list
|
|
||||||
.get(index)
|
|
||||||
.map_or_else(|| format!("reg_{}", index - offset + 1).into(), Cow::from)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn var_range_of(&self, start: u32, len: u32) -> Vec<Cow<'_, str>> {
|
|
||||||
(start..start + len).map(|i| self.var_name_of(i)).collect()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct Arity {
|
|
||||||
pub num_param: u32,
|
|
||||||
pub num_result: u32,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Arity {
|
|
||||||
fn from_type(typ: &FunctionType) -> Self {
|
|
||||||
let num_param = typ.params().len().try_into().unwrap();
|
|
||||||
let num_result = typ.results().len().try_into().unwrap();
|
|
||||||
|
|
||||||
Self {
|
|
||||||
num_param,
|
|
||||||
num_result,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn from_index(types: &[Type], index: u32) -> Self {
|
|
||||||
let Type::Function(typ) = &types[index as usize];
|
|
||||||
|
|
||||||
Self::from_type(typ)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct Module<'a> {
|
|
||||||
pub ex_arity: Vec<Arity>,
|
|
||||||
pub in_arity: Vec<Arity>,
|
|
||||||
pub code: Vec<Code<'a>>,
|
|
||||||
pub parent: &'a WasmModule,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> Module<'a> {
|
|
||||||
pub fn new(parent: &'a WasmModule) -> Self {
|
|
||||||
let mut module = Module {
|
|
||||||
in_arity: Self::new_arity_in_list(parent),
|
|
||||||
ex_arity: Self::new_arity_ex_list(parent),
|
|
||||||
code: Self::new_function_list(parent),
|
|
||||||
parent,
|
|
||||||
};
|
|
||||||
|
|
||||||
module.fill_cache();
|
|
||||||
module
|
|
||||||
}
|
|
||||||
|
|
||||||
fn fill_cache(&mut self) {
|
|
||||||
for (a, c) in self.in_arity.iter().zip(self.code.iter_mut()) {
|
|
||||||
c.var_list = ordered_iter("param", a.num_param)
|
|
||||||
.chain(ordered_iter("var", c.num_local))
|
|
||||||
.collect();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn arity_of(&self, index: usize) -> &Arity {
|
|
||||||
let offset = self.ex_arity.len();
|
|
||||||
|
|
||||||
self.ex_arity
|
|
||||||
.get(index)
|
|
||||||
.or_else(|| self.in_arity.get(index - offset))
|
|
||||||
.unwrap()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn new_arity_ext(types: &[Type], import: &ImportEntry) -> Option<Arity> {
|
|
||||||
if let External::Function(i) = import.external() {
|
|
||||||
Some(Arity::from_index(types, *i))
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn new_arity_in_list(wasm: &WasmModule) -> Vec<Arity> {
|
|
||||||
let (types, funcs) = match (wasm.type_section(), wasm.function_section()) {
|
|
||||||
(Some(t), Some(f)) => (t.types(), f.entries()),
|
|
||||||
_ => return Vec::new(),
|
|
||||||
};
|
|
||||||
|
|
||||||
funcs
|
|
||||||
.iter()
|
|
||||||
.map(|i| Arity::from_index(types, i.type_ref()))
|
|
||||||
.collect()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn new_arity_ex_list(wasm: &WasmModule) -> Vec<Arity> {
|
|
||||||
let (types, imports) = match (wasm.type_section(), wasm.import_section()) {
|
|
||||||
(Some(t), Some(i)) => (t.types(), i.entries()),
|
|
||||||
_ => return Vec::new(),
|
|
||||||
};
|
|
||||||
|
|
||||||
imports
|
|
||||||
.iter()
|
|
||||||
.filter_map(|i| Self::new_arity_ext(types, i))
|
|
||||||
.collect()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn new_function_list(wasm: &WasmModule) -> Vec<Code> {
|
|
||||||
let bodies = match wasm.code_section() {
|
|
||||||
Some(b) => b.bodies(),
|
|
||||||
None => return Vec::new(),
|
|
||||||
};
|
|
||||||
|
|
||||||
bodies
|
|
||||||
.iter()
|
|
||||||
.map(|v| {
|
|
||||||
let num_local = Code::local_sum(v.locals());
|
|
||||||
|
|
||||||
Code::new(v.code().elements(), num_local)
|
|
||||||
})
|
|
||||||
.collect()
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,13 +1,11 @@
|
|||||||
use backend::{edition::data::from_string, translator::level_3};
|
use backend::{edition::data::from_string, translator::data::Module};
|
||||||
use data::Module;
|
|
||||||
use parity_wasm::deserialize_file;
|
use parity_wasm::deserialize_file;
|
||||||
|
|
||||||
mod backend;
|
mod backend;
|
||||||
mod data;
|
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let mut args = std::env::args().skip(1);
|
let mut args = std::env::args().skip(1);
|
||||||
let spec = args
|
let ed = args
|
||||||
.next()
|
.next()
|
||||||
.as_deref()
|
.as_deref()
|
||||||
.and_then(from_string)
|
.and_then(from_string)
|
||||||
@ -19,6 +17,6 @@ fn main() {
|
|||||||
let wasm = deserialize_file(v).unwrap();
|
let wasm = deserialize_file(v).unwrap();
|
||||||
let module = Module::new(&wasm);
|
let module = Module::new(&wasm);
|
||||||
|
|
||||||
level_3::translate(spec, &module, &mut output.lock()).unwrap();
|
module.translate(ed, &mut output.lock()).unwrap();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user