From d7df9fb5b44a645cb786304ff88bbe4c9bb30d9d Mon Sep 17 00:00:00 2001 From: Rerumu Date: Tue, 14 Dec 2021 04:03:03 -0500 Subject: [PATCH] Refactored and decoupled `BinOp` and `CmpOp` --- wasm/runtime/luajit.lua | 5 - wasm/src/analyzer/localize.rs | 10 +- wasm/src/analyzer/visit.rs | 66 ++++---- wasm/src/ast/builder.rs | 62 ++++++-- wasm/src/ast/node.rs | 9 +- wasm/src/ast/tag.rs | 277 +++++++++++++++++----------------- wasm/src/writer/luajit.rs | 102 ++++++------- wasm/src/writer/luau.rs | 38 ++--- 8 files changed, 312 insertions(+), 257 deletions(-) diff --git a/wasm/runtime/luajit.lua b/wasm/runtime/luajit.lua index 6621c2f..492d0d5 100644 --- a/wasm/runtime/luajit.lua +++ b/wasm/runtime/luajit.lua @@ -105,15 +105,11 @@ do end do - local eqz = {} local le = {} local lt = {} local ge = {} 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.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.u64(lhs, rhs) return u64(lhs) < u64(rhs) end - module.eqz = eqz module.le = le module.lt = lt module.ge = ge diff --git a/wasm/src/analyzer/localize.rs b/wasm/src/analyzer/localize.rs index ecf8c0c..22ebe76 100644 --- a/wasm/src/analyzer/localize.rs +++ b/wasm/src/analyzer/localize.rs @@ -1,6 +1,6 @@ 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}; @@ -22,6 +22,12 @@ impl Visitor for Visit { } 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() { return; } @@ -31,7 +37,7 @@ impl Visitor for Visit { 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() { return; } diff --git a/wasm/src/analyzer/visit.rs b/wasm/src/analyzer/visit.rs index ca00a0f..948d280 100644 --- a/wasm/src/analyzer/visit.rs +++ b/wasm/src/analyzer/visit.rs @@ -1,7 +1,7 @@ use crate::ast::node::{ - AnyBinOp, AnyLoad, AnyStore, AnyUnOp, Backward, Br, BrIf, BrTable, Call, CallIndirect, Else, - Expression, Forward, Function, GetGlobal, GetLocal, If, Memorize, MemoryGrow, MemorySize, - Recall, Return, Select, SetGlobal, SetLocal, Statement, Value, + AnyBinOp, AnyCmpOp, AnyLoad, AnyStore, AnyUnOp, Backward, Br, BrIf, BrTable, Call, + CallIndirect, Else, Expression, Forward, Function, GetGlobal, GetLocal, If, Memorize, + MemoryGrow, MemorySize, Recall, Return, Select, SetGlobal, SetLocal, Statement, Value, }; pub trait Visitor { @@ -25,6 +25,8 @@ pub trait Visitor { fn visit_any_binop(&mut self, _: &AnyBinOp) {} + fn visit_any_cmpop(&mut self, _: &AnyCmpOp) {} + fn visit_expression(&mut self, _: &Expression) {} fn visit_unreachable(&mut self) {} @@ -137,19 +139,29 @@ impl Driver for AnyBinOp { } } +impl Driver for AnyCmpOp { + fn accept(&self, visitor: &mut T) { + self.lhs.accept(visitor); + self.rhs.accept(visitor); + + visitor.visit_any_cmpop(self); + } +} + impl Driver for Expression { fn accept(&self, visitor: &mut T) { match self { - Expression::Recall(v) => v.accept(visitor), - 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), + Self::Recall(v) => v.accept(visitor), + Self::Select(v) => v.accept(visitor), + Self::GetLocal(v) => v.accept(visitor), + Self::GetGlobal(v) => v.accept(visitor), + Self::AnyLoad(v) => v.accept(visitor), + Self::MemorySize(v) => v.accept(visitor), + Self::MemoryGrow(v) => v.accept(visitor), + Self::Value(v) => v.accept(visitor), + Self::AnyUnOp(v) => v.accept(visitor), + Self::AnyBinOp(v) => v.accept(visitor), + Self::AnyCmpOp(v) => v.accept(visitor), } visitor.visit_expression(self); @@ -292,20 +304,20 @@ impl Driver for AnyStore { impl Driver for Statement { fn accept(&self, visitor: &mut T) { 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), + Self::Unreachable => visitor.visit_unreachable(), + Self::Memorize(v) => v.accept(visitor), + Self::Forward(v) => v.accept(visitor), + Self::Backward(v) => v.accept(visitor), + Self::If(v) => v.accept(visitor), + Self::Br(v) => v.accept(visitor), + Self::BrIf(v) => v.accept(visitor), + Self::BrTable(v) => v.accept(visitor), + Self::Return(v) => v.accept(visitor), + Self::Call(v) => v.accept(visitor), + Self::CallIndirect(v) => v.accept(visitor), + Self::SetLocal(v) => v.accept(visitor), + Self::SetGlobal(v) => v.accept(visitor), + Self::AnyStore(v) => v.accept(visitor), } } } diff --git a/wasm/src/ast/builder.rs b/wasm/src/ast/builder.rs index 7e29e44..95d229e 100644 --- a/wasm/src/ast/builder.rs +++ b/wasm/src/ast/builder.rs @@ -4,11 +4,11 @@ use parity_wasm::elements::{ use super::{ node::{ - AnyBinOp, AnyLoad, AnyStore, AnyUnOp, Backward, Br, BrIf, BrTable, Call, CallIndirect, - Else, Expression, Forward, Function, GetGlobal, GetLocal, If, Memorize, MemoryGrow, - MemorySize, Recall, Return, Select, SetGlobal, SetLocal, Statement, Value, + AnyBinOp, AnyCmpOp, AnyLoad, AnyStore, AnyUnOp, Backward, Br, BrIf, BrTable, Call, + CallIndirect, Else, Expression, Forward, Function, GetGlobal, GetLocal, If, Memorize, + MemoryGrow, MemorySize, Recall, Return, Select, SetGlobal, SetLocal, Statement, Value, }, - tag::{BinOp, Load, Store, UnOp}, + tag::{BinOp, CmpOp, Load, Store, UnOp}, }; struct Arity { @@ -310,6 +310,52 @@ impl<'a> Builder<'a> { .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]) { use Instruction as Inst; @@ -353,13 +399,7 @@ impl<'a> Builder<'a> { *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); - + if self.from_operation(inst) { continue; } diff --git a/wasm/src/ast/node.rs b/wasm/src/ast/node.rs index 57cdeb6..4771630 100644 --- a/wasm/src/ast/node.rs +++ b/wasm/src/ast/node.rs @@ -2,7 +2,7 @@ use std::ops::Range; use parity_wasm::elements::BrTableData; -use super::tag::{BinOp, Load, Store, UnOp}; +use super::tag::{BinOp, CmpOp, Load, Store, UnOp}; #[derive(Clone)] pub struct Recall { @@ -57,6 +57,12 @@ pub struct AnyBinOp { pub rhs: Box, } +pub struct AnyCmpOp { + pub op: CmpOp, + pub lhs: Box, + pub rhs: Box, +} + pub enum Expression { Recall(Recall), Select(Select), @@ -68,6 +74,7 @@ pub enum Expression { Value(Value), AnyUnOp(AnyUnOp), AnyBinOp(AnyBinOp), + AnyCmpOp(AnyCmpOp), } impl Expression { diff --git a/wasm/src/ast/tag.rs b/wasm/src/ast/tag.rs index 5d50713..0471977 100644 --- a/wasm/src/ast/tag.rs +++ b/wasm/src/ast/tag.rs @@ -128,8 +128,6 @@ impl TryFrom<&Instruction> for Store { #[allow(non_camel_case_types)] #[derive(Clone, Copy)] pub enum UnOp { - Eqz_I32, - Eqz_I64, Clz_I32, Ctz_I32, Popcnt_I32, @@ -175,23 +173,8 @@ pub enum 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) { match self { - Self::Eqz_I32 => ("eqz", "i32"), - Self::Eqz_I64 => ("eqz", "i64"), Self::Clz_I32 => ("clz", "i32"), Self::Ctz_I32 => ("ctz", "i32"), Self::Popcnt_I32 => ("popcnt", "i32"), @@ -252,8 +235,6 @@ impl TryFrom<&Instruction> for UnOp { SignExtInstruction::I64Extend16S => Self::Extend_I64_I16, SignExtInstruction::I64Extend32S => Self::Extend_I64_I32, }, - Inst::I32Eqz => Self::Eqz_I32, - Inst::I64Eqz => Self::Eqz_I64, Inst::I32Clz => Self::Clz_I32, Inst::I32Ctz => Self::Ctz_I32, Inst::I32Popcnt => Self::Popcnt_I32, @@ -302,26 +283,6 @@ impl TryFrom<&Instruction> for UnOp { #[allow(non_camel_case_types)] #[derive(Clone, Copy)] 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, Sub_I32, Mul_I32, @@ -352,12 +313,6 @@ pub enum BinOp { ShrU_I64, Rotl_I64, Rotr_I64, - Eq_FN, - Ne_FN, - Lt_FN, - Gt_FN, - Le_FN, - Ge_FN, Add_FN, Sub_FN, Mul_FN, @@ -368,26 +323,6 @@ pub enum 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> { let op = match self { Self::Add_FN => "+", @@ -395,6 +330,142 @@ impl BinOp { 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 { + 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 { + 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::Ne_I32 | Self::Ne_I64 | Self::Ne_FN => "~=", Self::LtS_I32 | Self::LtS_I64 | Self::Lt_FN => "<", @@ -429,54 +500,17 @@ impl BinOp { Self::LeU_I64 => ("le", "u64"), Self::GeS_I64 => ("ge", "i64"), 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::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::Max_FN => ("math", "max"), - Self::Copysign_FN => ("copysign", "num"), } } } -impl TryFrom<&Instruction> for BinOp { +impl TryFrom<&Instruction> for CmpOp { type Error = (); fn try_from(inst: &Instruction) -> Result { @@ -503,49 +537,12 @@ impl TryFrom<&Instruction> for BinOp { Inst::I64LeU => Self::LeU_I64, Inst::I64GeS => Self::GeS_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::F32Ne | Inst::F64Ne => Self::Ne_FN, Inst::F32Lt | Inst::F64Lt => Self::Lt_FN, Inst::F32Gt | Inst::F64Gt => Self::Gt_FN, Inst::F32Le | Inst::F64Le => Self::Le_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(()); } diff --git a/wasm/src/writer/luajit.rs b/wasm/src/writer/luajit.rs index 87438d8..9ab6992 100644 --- a/wasm/src/writer/luajit.rs +++ b/wasm/src/writer/luajit.rs @@ -7,9 +7,9 @@ use crate::{ ast::{ builder::{Arities, Builder}, node::{ - AnyBinOp, AnyLoad, AnyStore, AnyUnOp, Backward, Br, BrIf, BrTable, Call, CallIndirect, - Else, Expression, Forward, Function, GetGlobal, GetLocal, If, Memorize, MemoryGrow, - MemorySize, Recall, Return, Select, SetGlobal, SetLocal, Statement, Value, + AnyBinOp, AnyCmpOp, AnyLoad, AnyStore, AnyUnOp, Backward, Br, BrIf, BrTable, Call, + CallIndirect, Else, Expression, Forward, Function, GetGlobal, GetLocal, If, Memorize, + 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 { fn visit(&self, v: &mut Visitor, w: Writer) -> Result<()> { - if self.op.is_compare() { - write!(w, "(")?; - } + let (a, b) = self.op.as_name(); - write_un_op(self, v, w)?; - - if self.op.is_compare() { - write!(w, "and 1 or 0)")?; - } - - Ok(()) + write!(w, "{}_{}(", a, b)?; + self.rhs.visit(v, w)?; + write!(w, ")") } } -fn write_bin_op(bin_op: &AnyBinOp, v: &mut Visitor, w: Writer) -> Result<()> { - if let Some(op) = bin_op.op.as_operator() { - bin_op.lhs.visit(v, w)?; - write!(w, "{} ", op)?; - bin_op.rhs.visit(v, w) - } else { - let (a, b) = bin_op.op.as_name(); - - write!(w, "{}_{}(", a, b)?; - bin_op.lhs.visit(v, w)?; - write!(w, ", ")?; - bin_op.rhs.visit(v, w)?; - write!(w, ")") - } +fn write_bin_call( + op: (&str, &str), + lhs: &Expression, + rhs: &Expression, + v: &mut Visitor, + w: Writer, +) -> Result<()> { + write!(w, "{}_{}(", op.0, op.1)?; + lhs.visit(v, w)?; + write!(w, ", ")?; + rhs.visit(v, w)?; + write!(w, ")") } impl Driver for AnyBinOp { fn visit(&self, v: &mut Visitor, w: Writer) -> Result<()> { - if self.op.is_compare() { + if let Some(op) = self.op.as_operator() { 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() { - write!(w, "and 1 or 0)")?; - } - - Ok(()) +impl Driver for AnyCmpOp { + fn visit(&self, v: &mut Visitor, w: Writer) -> Result<()> { + write!(w, "(")?; + write_any_cmp(self, v, w)?; + write!(w, "and 1 or 0)") } } // Removes the boolean to integer conversion fn write_as_condition(data: &Expression, v: &mut Visitor, w: Writer) -> Result<()> { - match data { - Expression::AnyUnOp(o) if o.op.is_compare() => write_un_op(o, v, w), - Expression::AnyBinOp(o) if o.op.is_compare() => write_bin_op(o, v, w), - _ => { - data.visit(v, w)?; - write!(w, "~= 0 ") - } + if let Expression::AnyCmpOp(o) = data { + write_any_cmp(o, v, w) + } else { + data.visit(v, w)?; + write!(w, "~= 0 ") } } @@ -261,6 +254,7 @@ impl Driver for Expression { Self::Value(e) => e.visit(v, w), Self::AnyUnOp(e) => e.visit(v, w), Self::AnyBinOp(e) => e.visit(v, w), + Self::AnyCmpOp(e) => e.visit(v, w), } } } diff --git a/wasm/src/writer/luau.rs b/wasm/src/writer/luau.rs index 2b9fbab..279b476 100644 --- a/wasm/src/writer/luau.rs +++ b/wasm/src/writer/luau.rs @@ -7,9 +7,9 @@ use crate::{ ast::{ builder::{Arities, Builder}, node::{ - AnyBinOp, AnyLoad, AnyStore, AnyUnOp, Backward, Br, BrIf, BrTable, Call, CallIndirect, - Else, Expression, Forward, Function, GetGlobal, GetLocal, If, Memorize, MemoryGrow, - MemorySize, Recall, Return, Select, SetGlobal, SetLocal, Statement, Value, + AnyBinOp, AnyCmpOp, AnyLoad, AnyStore, AnyUnOp, Backward, Br, BrIf, BrTable, Call, + CallIndirect, Else, Expression, Forward, Function, GetGlobal, GetLocal, If, Memorize, + 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 { fn visit(&self, v: &mut Visitor, w: Writer) -> Result<()> { - if let Some(op) = self.op.as_operator() { - write!(w, "{}", op)?; - self.rhs.visit(v, w) - } else { - write_un_op_call(self, v, w) - } + let (a, b) = self.op.as_name(); + + write!(w, "{}_{}(", a, b)?; + self.rhs.visit(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<()> { list.iter().enumerate().try_for_each(|(i, e)| { if i != 0 { @@ -226,6 +229,7 @@ impl Driver for Expression { Self::Value(e) => e.visit(v, w), Self::AnyUnOp(e) => e.visit(v, w), Self::AnyBinOp(e) => e.visit(v, w), + Self::AnyCmpOp(e) => e.visit(v, w), } } }