Refactored and decoupled BinOp and CmpOp

This commit is contained in:
Rerumu 2021-12-14 04:03:03 -05:00
parent e568baee1d
commit d7df9fb5b4
8 changed files with 312 additions and 257 deletions

View File

@ -105,15 +105,11 @@ do
end end
do do
local eqz = {}
local le = {} local le = {}
local lt = {} local lt = {}
local ge = {} local ge = {}
local gt = {} local gt = {}
function eqz.i32(lhs) return lhs == 0 end
function eqz.i64(lhs) return lhs == 0 end
function ge.u32(lhs, rhs) return u32(lhs) >= u32(rhs) end function ge.u32(lhs, rhs) return u32(lhs) >= u32(rhs) end
function ge.u64(lhs, rhs) return u64(lhs) >= u64(rhs) end function ge.u64(lhs, rhs) return u64(lhs) >= u64(rhs) end
@ -126,7 +122,6 @@ do
function lt.u32(lhs, rhs) return u32(lhs) < u32(rhs) end function lt.u32(lhs, rhs) return u32(lhs) < u32(rhs) end
function lt.u64(lhs, rhs) return u64(lhs) < u64(rhs) end function lt.u64(lhs, rhs) return u64(lhs) < u64(rhs) end
module.eqz = eqz
module.le = le module.le = le
module.lt = lt module.lt = lt
module.ge = ge module.ge = ge

View File

@ -1,6 +1,6 @@
use std::collections::BTreeSet; use std::collections::BTreeSet;
use crate::ast::node::{AnyBinOp, AnyLoad, AnyStore, AnyUnOp, Function}; use crate::ast::node::{AnyBinOp, AnyCmpOp, AnyLoad, AnyStore, AnyUnOp, Function};
use super::visit::{Driver, Visitor}; use super::visit::{Driver, Visitor};
@ -22,6 +22,12 @@ impl Visitor for Visit {
} }
fn visit_any_unop(&mut self, v: &AnyUnOp) { fn visit_any_unop(&mut self, v: &AnyUnOp) {
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() { if v.op.as_operator().is_some() {
return; return;
} }
@ -31,7 +37,7 @@ impl Visitor for Visit {
self.result.insert(name); self.result.insert(name);
} }
fn visit_any_binop(&mut self, v: &AnyBinOp) { fn visit_any_cmpop(&mut self, v: &AnyCmpOp) {
if v.op.as_operator().is_some() { if v.op.as_operator().is_some() {
return; return;
} }

View File

@ -1,7 +1,7 @@
use crate::ast::node::{ use crate::ast::node::{
AnyBinOp, AnyLoad, AnyStore, AnyUnOp, Backward, Br, BrIf, BrTable, Call, CallIndirect, Else, AnyBinOp, AnyCmpOp, AnyLoad, AnyStore, AnyUnOp, Backward, Br, BrIf, BrTable, Call,
Expression, Forward, Function, GetGlobal, GetLocal, If, Memorize, MemoryGrow, MemorySize, CallIndirect, Else, Expression, Forward, Function, GetGlobal, GetLocal, If, Memorize,
Recall, Return, Select, SetGlobal, SetLocal, Statement, Value, MemoryGrow, MemorySize, Recall, Return, Select, SetGlobal, SetLocal, Statement, Value,
}; };
pub trait Visitor { pub trait Visitor {
@ -25,6 +25,8 @@ pub trait Visitor {
fn visit_any_binop(&mut self, _: &AnyBinOp) {} fn visit_any_binop(&mut self, _: &AnyBinOp) {}
fn visit_any_cmpop(&mut self, _: &AnyCmpOp) {}
fn visit_expression(&mut self, _: &Expression) {} fn visit_expression(&mut self, _: &Expression) {}
fn visit_unreachable(&mut self) {} fn visit_unreachable(&mut self) {}
@ -137,19 +139,29 @@ impl<T: Visitor> Driver<T> for AnyBinOp {
} }
} }
impl<T: Visitor> Driver<T> for AnyCmpOp {
fn accept(&self, visitor: &mut T) {
self.lhs.accept(visitor);
self.rhs.accept(visitor);
visitor.visit_any_cmpop(self);
}
}
impl<T: Visitor> Driver<T> for Expression { impl<T: Visitor> Driver<T> for Expression {
fn accept(&self, visitor: &mut T) { fn accept(&self, visitor: &mut T) {
match self { match self {
Expression::Recall(v) => v.accept(visitor), Self::Recall(v) => v.accept(visitor),
Expression::Select(v) => v.accept(visitor), Self::Select(v) => v.accept(visitor),
Expression::GetLocal(v) => v.accept(visitor), Self::GetLocal(v) => v.accept(visitor),
Expression::GetGlobal(v) => v.accept(visitor), Self::GetGlobal(v) => v.accept(visitor),
Expression::AnyLoad(v) => v.accept(visitor), Self::AnyLoad(v) => v.accept(visitor),
Expression::MemorySize(v) => v.accept(visitor), Self::MemorySize(v) => v.accept(visitor),
Expression::MemoryGrow(v) => v.accept(visitor), Self::MemoryGrow(v) => v.accept(visitor),
Expression::Value(v) => v.accept(visitor), Self::Value(v) => v.accept(visitor),
Expression::AnyUnOp(v) => v.accept(visitor), Self::AnyUnOp(v) => v.accept(visitor),
Expression::AnyBinOp(v) => v.accept(visitor), Self::AnyBinOp(v) => v.accept(visitor),
Self::AnyCmpOp(v) => v.accept(visitor),
} }
visitor.visit_expression(self); visitor.visit_expression(self);
@ -292,20 +304,20 @@ impl<T: Visitor> Driver<T> for AnyStore {
impl<T: Visitor> Driver<T> for Statement { impl<T: Visitor> Driver<T> for Statement {
fn accept(&self, visitor: &mut T) { fn accept(&self, visitor: &mut T) {
match self { match self {
Statement::Unreachable => visitor.visit_unreachable(), Self::Unreachable => visitor.visit_unreachable(),
Statement::Memorize(v) => v.accept(visitor), Self::Memorize(v) => v.accept(visitor),
Statement::Forward(v) => v.accept(visitor), Self::Forward(v) => v.accept(visitor),
Statement::Backward(v) => v.accept(visitor), Self::Backward(v) => v.accept(visitor),
Statement::If(v) => v.accept(visitor), Self::If(v) => v.accept(visitor),
Statement::Br(v) => v.accept(visitor), Self::Br(v) => v.accept(visitor),
Statement::BrIf(v) => v.accept(visitor), Self::BrIf(v) => v.accept(visitor),
Statement::BrTable(v) => v.accept(visitor), Self::BrTable(v) => v.accept(visitor),
Statement::Return(v) => v.accept(visitor), Self::Return(v) => v.accept(visitor),
Statement::Call(v) => v.accept(visitor), Self::Call(v) => v.accept(visitor),
Statement::CallIndirect(v) => v.accept(visitor), Self::CallIndirect(v) => v.accept(visitor),
Statement::SetLocal(v) => v.accept(visitor), Self::SetLocal(v) => v.accept(visitor),
Statement::SetGlobal(v) => v.accept(visitor), Self::SetGlobal(v) => v.accept(visitor),
Statement::AnyStore(v) => v.accept(visitor), Self::AnyStore(v) => v.accept(visitor),
} }
} }
} }

View File

@ -4,11 +4,11 @@ use parity_wasm::elements::{
use super::{ use super::{
node::{ node::{
AnyBinOp, AnyLoad, AnyStore, AnyUnOp, Backward, Br, BrIf, BrTable, Call, CallIndirect, AnyBinOp, AnyCmpOp, AnyLoad, AnyStore, AnyUnOp, Backward, Br, BrIf, BrTable, Call,
Else, Expression, Forward, Function, GetGlobal, GetLocal, If, Memorize, MemoryGrow, CallIndirect, Else, Expression, Forward, Function, GetGlobal, GetLocal, If, Memorize,
MemorySize, Recall, Return, Select, SetGlobal, SetLocal, Statement, Value, MemoryGrow, MemorySize, Recall, Return, Select, SetGlobal, SetLocal, Statement, Value,
}, },
tag::{BinOp, Load, Store, UnOp}, tag::{BinOp, CmpOp, Load, Store, UnOp},
}; };
struct Arity { struct Arity {
@ -310,6 +310,52 @@ impl<'a> Builder<'a> {
.push(Expression::AnyBinOp(AnyBinOp { op, lhs, rhs })); .push(Expression::AnyBinOp(AnyBinOp { op, lhs, rhs }));
} }
fn push_cmp_op(&mut self, op: CmpOp) {
let rhs = Box::new(self.stack.pop().unwrap());
let lhs = Box::new(self.stack.pop().unwrap());
self.stack
.push(Expression::AnyCmpOp(AnyCmpOp { op, lhs, rhs }));
}
// Since Eqz is the only unary comparison it's cleaner to
// generate a simple CmpOp
fn from_equal_zero(&mut self, inst: &Instruction) -> bool {
match inst {
Instruction::I32Eqz => {
self.push_constant(Value::I32(0));
self.push_cmp_op(CmpOp::Eq_I32);
true
}
Instruction::I64Eqz => {
self.push_constant(Value::I64(0));
self.push_cmp_op(CmpOp::Eq_I64);
true
}
_ => false,
}
}
fn from_operation(&mut self, inst: &Instruction) -> bool {
if let Ok(op) = UnOp::try_from(inst) {
self.push_un_op(op);
true
} else if let Ok(op) = BinOp::try_from(inst) {
self.push_bin_op(op);
true
} else if let Ok(op) = CmpOp::try_from(inst) {
self.push_cmp_op(op);
true
} else {
self.from_equal_zero(inst)
}
}
fn drop_unreachable(list: &mut &[Instruction]) { fn drop_unreachable(list: &mut &[Instruction]) {
use Instruction as Inst; use Instruction as Inst;
@ -353,13 +399,7 @@ impl<'a> Builder<'a> {
*list = &list[1..]; *list = &list[1..];
if let Ok(op) = UnOp::try_from(inst) { if self.from_operation(inst) {
self.push_un_op(op);
continue;
} else if let Ok(op) = BinOp::try_from(inst) {
self.push_bin_op(op);
continue; continue;
} }

View File

@ -2,7 +2,7 @@ use std::ops::Range;
use parity_wasm::elements::BrTableData; use parity_wasm::elements::BrTableData;
use super::tag::{BinOp, Load, Store, UnOp}; use super::tag::{BinOp, CmpOp, Load, Store, UnOp};
#[derive(Clone)] #[derive(Clone)]
pub struct Recall { pub struct Recall {
@ -57,6 +57,12 @@ pub struct AnyBinOp {
pub rhs: Box<Expression>, pub rhs: Box<Expression>,
} }
pub struct AnyCmpOp {
pub op: CmpOp,
pub lhs: Box<Expression>,
pub rhs: Box<Expression>,
}
pub enum Expression { pub enum Expression {
Recall(Recall), Recall(Recall),
Select(Select), Select(Select),
@ -68,6 +74,7 @@ pub enum Expression {
Value(Value), Value(Value),
AnyUnOp(AnyUnOp), AnyUnOp(AnyUnOp),
AnyBinOp(AnyBinOp), AnyBinOp(AnyBinOp),
AnyCmpOp(AnyCmpOp),
} }
impl Expression { impl Expression {

View File

@ -128,8 +128,6 @@ impl TryFrom<&Instruction> for Store {
#[allow(non_camel_case_types)] #[allow(non_camel_case_types)]
#[derive(Clone, Copy)] #[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,
@ -175,23 +173,8 @@ pub enum UnOp {
} }
impl UnOp { impl UnOp {
pub fn is_compare(self) -> bool {
matches!(self, Self::Eqz_I32 | Self::Eqz_I64)
}
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) { 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"),
@ -252,8 +235,6 @@ impl TryFrom<&Instruction> for UnOp {
SignExtInstruction::I64Extend16S => Self::Extend_I64_I16, SignExtInstruction::I64Extend16S => Self::Extend_I64_I16,
SignExtInstruction::I64Extend32S => Self::Extend_I64_I32, SignExtInstruction::I64Extend32S => Self::Extend_I64_I32,
}, },
Inst::I32Eqz => Self::Eqz_I32,
Inst::I64Eqz => Self::Eqz_I64,
Inst::I32Clz => Self::Clz_I32, Inst::I32Clz => Self::Clz_I32,
Inst::I32Ctz => Self::Ctz_I32, Inst::I32Ctz => Self::Ctz_I32,
Inst::I32Popcnt => Self::Popcnt_I32, Inst::I32Popcnt => Self::Popcnt_I32,
@ -302,26 +283,6 @@ impl TryFrom<&Instruction> for UnOp {
#[allow(non_camel_case_types)] #[allow(non_camel_case_types)]
#[derive(Clone, Copy)] #[derive(Clone, Copy)]
pub enum BinOp { pub enum BinOp {
Eq_I32,
Ne_I32,
LtS_I32,
LtU_I32,
GtS_I32,
GtU_I32,
LeS_I32,
LeU_I32,
GeS_I32,
GeU_I32,
Eq_I64,
Ne_I64,
LtS_I64,
LtU_I64,
GtS_I64,
GtU_I64,
LeS_I64,
LeU_I64,
GeS_I64,
GeU_I64,
Add_I32, Add_I32,
Sub_I32, Sub_I32,
Mul_I32, Mul_I32,
@ -352,12 +313,6 @@ 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, Add_FN,
Sub_FN, Sub_FN,
Mul_FN, Mul_FN,
@ -368,26 +323,6 @@ pub enum BinOp {
} }
impl BinOp { impl BinOp {
pub fn is_compare(self) -> bool {
matches!(
self,
Self::Eq_I32
| Self::Ne_I32 | Self::LtS_I32
| Self::LtU_I32 | Self::GtS_I32
| Self::GtU_I32 | Self::LeS_I32
| Self::LeU_I32 | Self::GeS_I32
| Self::GeU_I32 | Self::Eq_I64
| Self::Ne_I64 | Self::LtS_I64
| Self::LtU_I64 | Self::GtS_I64
| Self::GtU_I64 | Self::LeS_I64
| Self::LeU_I64 | Self::GeS_I64
| Self::GeU_I64 | Self::Eq_FN
| Self::Ne_FN | Self::Lt_FN
| Self::Gt_FN | Self::Le_FN
| Self::Ge_FN
)
}
pub fn as_operator(self) -> Option<&'static str> { pub fn as_operator(self) -> Option<&'static str> {
let op = match self { let op = match self {
Self::Add_FN => "+", Self::Add_FN => "+",
@ -395,6 +330,142 @@ impl BinOp {
Self::Mul_FN => "*", Self::Mul_FN => "*",
Self::Div_FN => "/", Self::Div_FN => "/",
Self::RemS_I32 | Self::RemU_I32 | Self::RemS_I64 | Self::RemU_I64 => "%", 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 {
Self::Add_I32 => ("add", "i32"),
Self::Sub_I32 => ("sub", "i32"),
Self::Mul_I32 => ("mul", "i32"),
Self::DivS_I32 => ("div", "i32"),
Self::DivU_I32 => ("div", "u32"),
Self::RemS_I32 => ("rem", "i32"),
Self::RemU_I32 => ("rem", "u32"),
Self::And_I32 => ("band", "i32"),
Self::Or_I32 => ("bor", "i32"),
Self::Xor_I32 => ("bxor", "i32"),
Self::Shl_I32 => ("shl", "i32"),
Self::ShrS_I32 => ("shr", "i32"),
Self::ShrU_I32 => ("shr", "u32"),
Self::Rotl_I32 => ("rotl", "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::DivU_I64 => ("div", "u64"),
Self::RemS_I64 => ("rem", "i64"),
Self::RemU_I64 => ("rem", "u64"),
Self::And_I64 => ("band", "i64"),
Self::Or_I64 => ("bor", "i64"),
Self::Xor_I64 => ("bxor", "i64"),
Self::Shl_I64 => ("shl", "i64"),
Self::ShrS_I64 => ("shr", "i64"),
Self::ShrU_I64 => ("shr", "u64"),
Self::Rotl_I64 => ("rotl", "i64"),
Self::Rotr_I64 => ("rotr", "i64"),
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::Max_FN => ("math", "max"),
Self::Copysign_FN => ("copysign", "num"),
}
}
}
impl TryFrom<&Instruction> for BinOp {
type Error = ();
fn try_from(inst: &Instruction) -> Result<Self, Self::Error> {
use Instruction as Inst;
let result = match inst {
Inst::I32Add => Self::Add_I32,
Inst::I32Sub => Self::Sub_I32,
Inst::I32Mul => Self::Mul_I32,
Inst::I32DivS => Self::DivS_I32,
Inst::I32DivU => Self::DivU_I32,
Inst::I32RemS => Self::RemS_I32,
Inst::I32RemU => Self::RemU_I32,
Inst::I32And => Self::And_I32,
Inst::I32Or => Self::Or_I32,
Inst::I32Xor => Self::Xor_I32,
Inst::I32Shl => Self::Shl_I32,
Inst::I32ShrS => Self::ShrS_I32,
Inst::I32ShrU => Self::ShrU_I32,
Inst::I32Rotl => Self::Rotl_I32,
Inst::I32Rotr => Self::Rotr_I32,
Inst::I64Add => Self::Add_I64,
Inst::I64Sub => Self::Sub_I64,
Inst::I64Mul => Self::Mul_I64,
Inst::I64DivS => Self::DivS_I64,
Inst::I64DivU => Self::DivU_I64,
Inst::I64RemS => Self::RemS_I64,
Inst::I64RemU => Self::RemU_I64,
Inst::I64And => Self::And_I64,
Inst::I64Or => Self::Or_I64,
Inst::I64Xor => Self::Xor_I64,
Inst::I64Shl => Self::Shl_I64,
Inst::I64ShrS => Self::ShrS_I64,
Inst::I64ShrU => Self::ShrU_I64,
Inst::I64Rotl => Self::Rotl_I64,
Inst::I64Rotr => Self::Rotr_I64,
Inst::F32Add | Inst::F64Add => Self::Add_FN,
Inst::F32Sub | Inst::F64Sub => Self::Sub_FN,
Inst::F32Mul | Inst::F64Mul => Self::Mul_FN,
Inst::F32Div | Inst::F64Div => Self::Div_FN,
Inst::F32Min | Inst::F64Min => Self::Min_FN,
Inst::F32Max | Inst::F64Max => Self::Max_FN,
Inst::F32Copysign | Inst::F64Copysign => Self::Copysign_FN,
_ => {
return Err(());
}
};
Ok(result)
}
}
#[allow(non_camel_case_types)]
#[derive(Clone, Copy)]
pub enum CmpOp {
Eq_I32,
Ne_I32,
LtS_I32,
LtU_I32,
GtS_I32,
GtU_I32,
LeS_I32,
LeU_I32,
GeS_I32,
GeU_I32,
Eq_I64,
Ne_I64,
LtS_I64,
LtU_I64,
GtS_I64,
GtU_I64,
LeS_I64,
LeU_I64,
GeS_I64,
GeU_I64,
Eq_FN,
Ne_FN,
Lt_FN,
Gt_FN,
Le_FN,
Ge_FN,
}
impl CmpOp {
pub fn as_operator(self) -> Option<&'static str> {
let op = match self {
Self::Eq_I32 | Self::Eq_I64 | Self::Eq_FN => "==", Self::Eq_I32 | Self::Eq_I64 | Self::Eq_FN => "==",
Self::Ne_I32 | Self::Ne_I64 | Self::Ne_FN => "~=", Self::Ne_I32 | Self::Ne_I64 | Self::Ne_FN => "~=",
Self::LtS_I32 | Self::LtS_I64 | Self::Lt_FN => "<", Self::LtS_I32 | Self::LtS_I64 | Self::Lt_FN => "<",
@ -429,54 +500,17 @@ impl BinOp {
Self::LeU_I64 => ("le", "u64"), Self::LeU_I64 => ("le", "u64"),
Self::GeS_I64 => ("ge", "i64"), 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::DivU_I32 => ("div", "u32"),
Self::RemS_I32 => ("rem", "i32"),
Self::RemU_I32 => ("rem", "u32"),
Self::And_I32 => ("band", "i32"),
Self::Or_I32 => ("bor", "i32"),
Self::Xor_I32 => ("bxor", "i32"),
Self::Shl_I32 => ("shl", "i32"),
Self::ShrS_I32 => ("shr", "i32"),
Self::ShrU_I32 => ("shr", "u32"),
Self::Rotl_I32 => ("rotl", "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::DivU_I64 => ("div", "u64"),
Self::RemS_I64 => ("rem", "i64"),
Self::RemU_I64 => ("rem", "u64"),
Self::And_I64 => ("band", "i64"),
Self::Or_I64 => ("bor", "i64"),
Self::Xor_I64 => ("bxor", "i64"),
Self::Shl_I64 => ("shl", "i64"),
Self::ShrS_I64 => ("shr", "i64"),
Self::ShrU_I64 => ("shr", "u64"),
Self::Rotl_I64 => ("rotl", "i64"),
Self::Rotr_I64 => ("rotr", "i64"),
Self::Eq_FN => ("eq", "num"), Self::Eq_FN => ("eq", "num"),
Self::Ne_FN => ("ne", "num"), Self::Ne_FN => ("ne", "num"),
Self::Lt_FN => ("lt", "num"), Self::Lt_FN => ("lt", "num"),
Self::Gt_FN => ("gt", "num"), Self::Gt_FN => ("gt", "num"),
Self::Le_FN => ("le", "num"), Self::Le_FN => ("le", "num"),
Self::Ge_FN => ("ge", "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::Max_FN => ("math", "max"),
Self::Copysign_FN => ("copysign", "num"),
} }
} }
} }
impl TryFrom<&Instruction> for BinOp { impl TryFrom<&Instruction> for CmpOp {
type Error = (); type Error = ();
fn try_from(inst: &Instruction) -> Result<Self, Self::Error> { fn try_from(inst: &Instruction) -> Result<Self, Self::Error> {
@ -503,49 +537,12 @@ impl TryFrom<&Instruction> for BinOp {
Inst::I64LeU => Self::LeU_I64, Inst::I64LeU => Self::LeU_I64,
Inst::I64GeS => Self::GeS_I64, Inst::I64GeS => Self::GeS_I64,
Inst::I64GeU => Self::GeU_I64, Inst::I64GeU => Self::GeU_I64,
Inst::I32Add => Self::Add_I32,
Inst::I32Sub => Self::Sub_I32,
Inst::I32Mul => Self::Mul_I32,
Inst::I32DivS => Self::DivS_I32,
Inst::I32DivU => Self::DivU_I32,
Inst::I32RemS => Self::RemS_I32,
Inst::I32RemU => Self::RemU_I32,
Inst::I32And => Self::And_I32,
Inst::I32Or => Self::Or_I32,
Inst::I32Xor => Self::Xor_I32,
Inst::I32Shl => Self::Shl_I32,
Inst::I32ShrS => Self::ShrS_I32,
Inst::I32ShrU => Self::ShrU_I32,
Inst::I32Rotl => Self::Rotl_I32,
Inst::I32Rotr => Self::Rotr_I32,
Inst::I64Add => Self::Add_I64,
Inst::I64Sub => Self::Sub_I64,
Inst::I64Mul => Self::Mul_I64,
Inst::I64DivS => Self::DivS_I64,
Inst::I64DivU => Self::DivU_I64,
Inst::I64RemS => Self::RemS_I64,
Inst::I64RemU => Self::RemU_I64,
Inst::I64And => Self::And_I64,
Inst::I64Or => Self::Or_I64,
Inst::I64Xor => Self::Xor_I64,
Inst::I64Shl => Self::Shl_I64,
Inst::I64ShrS => Self::ShrS_I64,
Inst::I64ShrU => Self::ShrU_I64,
Inst::I64Rotl => Self::Rotl_I64,
Inst::I64Rotr => Self::Rotr_I64,
Inst::F32Eq | Inst::F64Eq => Self::Eq_FN, Inst::F32Eq | Inst::F64Eq => Self::Eq_FN,
Inst::F32Ne | Inst::F64Ne => Self::Ne_FN, Inst::F32Ne | Inst::F64Ne => Self::Ne_FN,
Inst::F32Lt | Inst::F64Lt => Self::Lt_FN, Inst::F32Lt | Inst::F64Lt => Self::Lt_FN,
Inst::F32Gt | Inst::F64Gt => Self::Gt_FN, Inst::F32Gt | Inst::F64Gt => Self::Gt_FN,
Inst::F32Le | Inst::F64Le => Self::Le_FN, Inst::F32Le | Inst::F64Le => Self::Le_FN,
Inst::F32Ge | Inst::F64Ge => Self::Ge_FN, Inst::F32Ge | Inst::F64Ge => Self::Ge_FN,
Inst::F32Add | Inst::F64Add => Self::Add_FN,
Inst::F32Sub | Inst::F64Sub => Self::Sub_FN,
Inst::F32Mul | Inst::F64Mul => Self::Mul_FN,
Inst::F32Div | Inst::F64Div => Self::Div_FN,
Inst::F32Min | Inst::F64Min => Self::Min_FN,
Inst::F32Max | Inst::F64Max => Self::Max_FN,
Inst::F32Copysign | Inst::F64Copysign => Self::Copysign_FN,
_ => { _ => {
return Err(()); return Err(());
} }

View File

@ -7,9 +7,9 @@ use crate::{
ast::{ ast::{
builder::{Arities, Builder}, builder::{Arities, Builder},
node::{ node::{
AnyBinOp, AnyLoad, AnyStore, AnyUnOp, Backward, Br, BrIf, BrTable, Call, CallIndirect, AnyBinOp, AnyCmpOp, AnyLoad, AnyStore, AnyUnOp, Backward, Br, BrIf, BrTable, Call,
Else, Expression, Forward, Function, GetGlobal, GetLocal, If, Memorize, MemoryGrow, CallIndirect, Else, Expression, Forward, Function, GetGlobal, GetLocal, If, Memorize,
MemorySize, Recall, Return, Select, SetGlobal, SetLocal, Statement, Value, MemoryGrow, MemorySize, Recall, Return, Select, SetGlobal, SetLocal, Statement, Value,
}, },
}, },
}; };
@ -165,76 +165,69 @@ impl Driver for Value {
} }
} }
fn write_un_op(un_op: &AnyUnOp, v: &mut Visitor, w: Writer) -> Result<()> {
if let Some(op) = un_op.op.as_operator() {
write!(w, "{} ", op)?;
un_op.rhs.visit(v, w)
} else {
let (a, b) = un_op.op.as_name();
write!(w, "{}_{}(", a, b)?;
un_op.rhs.visit(v, w)?;
write!(w, ")")
}
}
impl Driver for AnyUnOp { impl Driver for AnyUnOp {
fn visit(&self, v: &mut Visitor, w: Writer) -> Result<()> { fn visit(&self, v: &mut Visitor, w: Writer) -> Result<()> {
if self.op.is_compare() { let (a, b) = self.op.as_name();
write!(w, "(")?;
}
write_un_op(self, v, w)?; write!(w, "{}_{}(", a, b)?;
self.rhs.visit(v, w)?;
if self.op.is_compare() { write!(w, ")")
write!(w, "and 1 or 0)")?;
}
Ok(())
} }
} }
fn write_bin_op(bin_op: &AnyBinOp, v: &mut Visitor, w: Writer) -> Result<()> { fn write_bin_call(
if let Some(op) = bin_op.op.as_operator() { op: (&str, &str),
bin_op.lhs.visit(v, w)?; lhs: &Expression,
write!(w, "{} ", op)?; rhs: &Expression,
bin_op.rhs.visit(v, w) v: &mut Visitor,
} else { w: Writer,
let (a, b) = bin_op.op.as_name(); ) -> Result<()> {
write!(w, "{}_{}(", op.0, op.1)?;
write!(w, "{}_{}(", a, b)?; lhs.visit(v, w)?;
bin_op.lhs.visit(v, w)?; write!(w, ", ")?;
write!(w, ", ")?; rhs.visit(v, w)?;
bin_op.rhs.visit(v, w)?; write!(w, ")")
write!(w, ")")
}
} }
impl Driver for AnyBinOp { impl Driver for AnyBinOp {
fn visit(&self, v: &mut Visitor, w: Writer) -> Result<()> { fn visit(&self, v: &mut Visitor, w: Writer) -> Result<()> {
if self.op.is_compare() { if let Some(op) = self.op.as_operator() {
write!(w, "(")?; write!(w, "(")?;
self.lhs.visit(v, w)?;
write!(w, "{} ", op)?;
self.rhs.visit(v, w)?;
write!(w, ")")
} else {
write_bin_call(self.op.as_name(), &self.lhs, &self.rhs, v, w)
} }
}
}
write_bin_op(self, v, w)?; fn write_any_cmp(cmp: &AnyCmpOp, v: &mut Visitor, w: Writer) -> Result<()> {
if let Some(op) = cmp.op.as_operator() {
cmp.lhs.visit(v, w)?;
write!(w, "{} ", op)?;
cmp.rhs.visit(v, w)
} else {
write_bin_call(cmp.op.as_name(), &cmp.lhs, &cmp.rhs, v, w)
}
}
if self.op.is_compare() { impl Driver for AnyCmpOp {
write!(w, "and 1 or 0)")?; fn visit(&self, v: &mut Visitor, w: Writer) -> Result<()> {
} write!(w, "(")?;
write_any_cmp(self, v, w)?;
Ok(()) write!(w, "and 1 or 0)")
} }
} }
// Removes the boolean to integer conversion // Removes the boolean to integer conversion
fn write_as_condition(data: &Expression, v: &mut Visitor, w: Writer) -> Result<()> { fn write_as_condition(data: &Expression, v: &mut Visitor, w: Writer) -> Result<()> {
match data { if let Expression::AnyCmpOp(o) = data {
Expression::AnyUnOp(o) if o.op.is_compare() => write_un_op(o, v, w), write_any_cmp(o, v, w)
Expression::AnyBinOp(o) if o.op.is_compare() => write_bin_op(o, v, w), } else {
_ => { data.visit(v, w)?;
data.visit(v, w)?; write!(w, "~= 0 ")
write!(w, "~= 0 ")
}
} }
} }
@ -261,6 +254,7 @@ impl Driver for Expression {
Self::Value(e) => e.visit(v, w), Self::Value(e) => e.visit(v, w),
Self::AnyUnOp(e) => e.visit(v, w), Self::AnyUnOp(e) => e.visit(v, w),
Self::AnyBinOp(e) => e.visit(v, w), Self::AnyBinOp(e) => e.visit(v, w),
Self::AnyCmpOp(e) => e.visit(v, w),
} }
} }
} }

View File

@ -7,9 +7,9 @@ use crate::{
ast::{ ast::{
builder::{Arities, Builder}, builder::{Arities, Builder},
node::{ node::{
AnyBinOp, AnyLoad, AnyStore, AnyUnOp, Backward, Br, BrIf, BrTable, Call, CallIndirect, AnyBinOp, AnyCmpOp, AnyLoad, AnyStore, AnyUnOp, Backward, Br, BrIf, BrTable, Call,
Else, Expression, Forward, Function, GetGlobal, GetLocal, If, Memorize, MemoryGrow, CallIndirect, Else, Expression, Forward, Function, GetGlobal, GetLocal, If, Memorize,
MemorySize, Recall, Return, Select, SetGlobal, SetLocal, Statement, Value, MemoryGrow, MemorySize, Recall, Return, Select, SetGlobal, SetLocal, Statement, Value,
}, },
}, },
}; };
@ -154,22 +154,13 @@ impl Driver for Value {
} }
} }
fn write_un_op_call(un_op: &AnyUnOp, v: &mut Visitor, w: Writer) -> Result<()> {
let (a, b) = un_op.op.as_name();
write!(w, "{}_{}(", a, b)?;
un_op.rhs.visit(v, w)?;
write!(w, ")")
}
impl Driver for AnyUnOp { impl Driver for AnyUnOp {
fn visit(&self, v: &mut Visitor, w: Writer) -> Result<()> { fn visit(&self, v: &mut Visitor, w: Writer) -> Result<()> {
if let Some(op) = self.op.as_operator() { let (a, b) = self.op.as_name();
write!(w, "{}", op)?;
self.rhs.visit(v, w) write!(w, "{}_{}(", a, b)?;
} else { self.rhs.visit(v, w)?;
write_un_op_call(self, v, w) write!(w, ")")
}
} }
} }
@ -203,6 +194,18 @@ impl Driver for AnyBinOp {
} }
} }
impl Driver for AnyCmpOp {
fn visit(&self, v: &mut Visitor, w: Writer) -> Result<()> {
let (a, b) = self.op.as_name();
write!(w, "{}_{}(", a, b)?;
self.lhs.visit(v, w)?;
write!(w, ", ")?;
self.rhs.visit(v, w)?;
write!(w, ")")
}
}
fn write_expr_list(list: &[Expression], v: &mut Visitor, w: Writer) -> Result<()> { fn write_expr_list(list: &[Expression], v: &mut Visitor, w: Writer) -> Result<()> {
list.iter().enumerate().try_for_each(|(i, e)| { list.iter().enumerate().try_for_each(|(i, e)| {
if i != 0 { if i != 0 {
@ -226,6 +229,7 @@ impl Driver for Expression {
Self::Value(e) => e.visit(v, w), Self::Value(e) => e.visit(v, w),
Self::AnyUnOp(e) => e.visit(v, w), Self::AnyUnOp(e) => e.visit(v, w),
Self::AnyBinOp(e) => e.visit(v, w), Self::AnyBinOp(e) => e.visit(v, w),
Self::AnyCmpOp(e) => e.visit(v, w),
} }
} }
} }