Add test for operation localization

This commit is contained in:
Rerumu 2021-11-18 12:51:21 -05:00
parent 1905b40f1b
commit f449fffe55
6 changed files with 496 additions and 75 deletions

View File

@ -1,2 +1,3 @@
pub mod operation;
pub mod register; pub mod register;
pub mod writer; pub mod writer;

View File

@ -0,0 +1,388 @@
use std::convert::TryFrom;
use parity_wasm::elements::Instruction;
type Name = (&'static str, &'static str);
pub trait Named {
fn as_name(&self) -> Name;
}
#[allow(non_camel_case_types)]
pub enum Load {
I32,
I64,
F32,
F64,
I32_I8,
I32_U8,
I32_I16,
I32_U16,
I64_I8,
I64_U8,
I64_I16,
I64_U16,
I64_I32,
I64_U32,
}
impl Named for Load {
fn as_name(&self) -> Name {
match self {
Self::I32 => ("load", "i32"),
Self::I64 => ("load", "i64"),
Self::F32 => ("load", "f32"),
Self::F64 => ("load", "f64"),
Self::I32_I8 => ("load", "i32_i8"),
Self::I32_U8 => ("load", "i32_u8"),
Self::I32_I16 => ("load", "i32_i16"),
Self::I32_U16 => ("load", "i32_u16"),
Self::I64_I8 => ("load", "i64_i8"),
Self::I64_U8 => ("load", "i64_u8"),
Self::I64_I16 => ("load", "i64_i16"),
Self::I64_U16 => ("load", "i64_u16"),
Self::I64_I32 => ("load", "i64_i32"),
Self::I64_U32 => ("load", "i64_u32"),
}
}
}
impl TryFrom<&Instruction> for Load {
type Error = ();
fn try_from(inst: &Instruction) -> Result<Self, Self::Error> {
let result = match inst {
Instruction::I32Load(_, _) => Self::I32,
Instruction::I64Load(_, _) => Self::I64,
Instruction::F32Load(_, _) => Self::F32,
Instruction::F64Load(_, _) => Self::F64,
Instruction::I32Load8S(_, _) => Self::I32_I8,
Instruction::I32Load8U(_, _) => Self::I32_U8,
Instruction::I32Load16S(_, _) => Self::I32_I16,
Instruction::I32Load16U(_, _) => Self::I32_U16,
Instruction::I64Load8S(_, _) => Self::I64_I8,
Instruction::I64Load8U(_, _) => Self::I64_U8,
Instruction::I64Load16S(_, _) => Self::I64_I16,
Instruction::I64Load16U(_, _) => Self::I64_U16,
Instruction::I64Load32S(_, _) => Self::I64_I32,
Instruction::I64Load32U(_, _) => Self::I64_U32,
_ => return Err(()),
};
Ok(result)
}
}
#[allow(non_camel_case_types)]
pub enum Store {
I32,
I64,
F32,
F64,
I32_N8,
I32_N16,
I64_N8,
I64_N16,
I64_N32,
}
impl Named for Store {
fn as_name(&self) -> Name {
match self {
Self::I32 => ("store", "i32"),
Self::I64 => ("store", "i64"),
Self::F32 => ("store", "f32"),
Self::F64 => ("store", "f64"),
Self::I32_N8 => ("store", "i32_n8"),
Self::I32_N16 => ("store", "i32_n16"),
Self::I64_N8 => ("store", "i64_n8"),
Self::I64_N16 => ("store", "i64_n16"),
Self::I64_N32 => ("store", "i64_n32"),
}
}
}
impl TryFrom<&Instruction> for Store {
type Error = ();
fn try_from(inst: &Instruction) -> Result<Self, Self::Error> {
let result = match inst {
Instruction::I32Store(_, _) => Self::I32,
Instruction::I64Store(_, _) => Self::I64,
Instruction::F32Store(_, _) => Self::F32,
Instruction::F64Store(_, _) => Self::F64,
Instruction::I32Store8(_, _) => Self::I32_N8,
Instruction::I32Store16(_, _) => Self::I32_N16,
Instruction::I64Store8(_, _) => Self::I64_N8,
Instruction::I64Store16(_, _) => Self::I64_N16,
Instruction::I64Store32(_, _) => Self::I64_N32,
_ => return Err(()),
};
Ok(result)
}
}
#[allow(non_camel_case_types)]
pub enum UnOp {
Clz_I32,
Ctz_I32,
Popcnt_I32,
Clz_I64,
Ctz_I64,
Popcnt_I64,
Abs_FN,
Ceil_FN,
Floor_FN,
Trunc_FN,
Nearest_FN,
Sqrt_FN,
Copysign_FN,
Wrap_I32_I64,
Trunc_I32_F32,
Trunc_U32_F32,
Trunc_I32_F64,
Trunc_U32_F64,
Extend_I64_I32,
Extend_U64_I32,
Trunc_I64_F32,
Trunc_U64_F32,
Trunc_I64_F64,
Trunc_U64_F64,
Convert_F32_I32,
Convert_F32_U32,
Convert_F32_I64,
Convert_F32_U64,
Demote_F32_F64,
Convert_F64_I32,
Convert_F64_U32,
Convert_F64_I64,
Convert_F64_U64,
Promote_F64_F32,
Reinterpret_I32_F32,
Reinterpret_I64_F64,
Reinterpret_F32_I32,
Reinterpret_F64_I64,
}
impl Named for UnOp {
fn as_name(&self) -> Name {
match self {
Self::Clz_I32 => ("clz", "i32"),
Self::Ctz_I32 => ("ctz", "i32"),
Self::Popcnt_I32 => ("popcnt", "i32"),
Self::Clz_I64 => ("clz", "i64"),
Self::Ctz_I64 => ("ctz", "i64"),
Self::Popcnt_I64 => ("popcnt", "i64"),
Self::Abs_FN => ("math", "abs"),
Self::Ceil_FN => ("math", "ceil"),
Self::Floor_FN => ("math", "floor"),
Self::Trunc_FN => ("trunc", "f"),
Self::Nearest_FN => ("nearest", "f"),
Self::Sqrt_FN => ("math", "sqrt"),
Self::Copysign_FN => ("math", "sign"),
Self::Wrap_I32_I64 => ("wrap", "i64_i32"),
Self::Trunc_I32_F32 => ("trunc", "f32_i32"),
Self::Trunc_U32_F32 => ("trunc", "f32_u32"),
Self::Trunc_I32_F64 => ("trunc", "f64_i32"),
Self::Trunc_U32_F64 => ("trunc", "f64_u32"),
Self::Extend_I64_I32 => ("extend", "i32_i64"),
Self::Extend_U64_I32 => ("extend", "i32_u64"),
Self::Trunc_I64_F32 => ("trunc", "f32_i64"),
Self::Trunc_U64_F32 => ("trunc", "f32_u64"),
Self::Trunc_I64_F64 => ("trunc", "f64_i64"),
Self::Trunc_U64_F64 => ("trunc", "f64_u64"),
Self::Convert_F32_I32 => ("convert", "i32_f32"),
Self::Convert_F32_U32 => ("convert", "u32_f32"),
Self::Convert_F32_I64 => ("convert", "i64_f32"),
Self::Convert_F32_U64 => ("convert", "u64_f32"),
Self::Demote_F32_F64 => ("demote", "f64_f32"),
Self::Convert_F64_I32 => ("convert", "f64_i32"),
Self::Convert_F64_U32 => ("convert", "f64_u32"),
Self::Convert_F64_I64 => ("convert", "f64_i64"),
Self::Convert_F64_U64 => ("convert", "f64_u64"),
Self::Promote_F64_F32 => ("promote", "f32_f64"),
Self::Reinterpret_I32_F32 => ("reinterpret", "f32_i32"),
Self::Reinterpret_I64_F64 => ("reinterpret", "f64_i64"),
Self::Reinterpret_F32_I32 => ("reinterpret", "i32_f32"),
Self::Reinterpret_F64_I64 => ("reinterpret", "i64_f64"),
}
}
}
impl TryFrom<&Instruction> for UnOp {
type Error = ();
fn try_from(inst: &Instruction) -> Result<Self, Self::Error> {
let result = match inst {
Instruction::I32Clz => Self::Clz_I32,
Instruction::I32Ctz => Self::Ctz_I32,
Instruction::I32Popcnt => Self::Popcnt_I32,
Instruction::I64Clz => Self::Clz_I64,
Instruction::I64Ctz => Self::Ctz_I64,
Instruction::I64Popcnt => Self::Popcnt_I64,
Instruction::F32Abs | Instruction::F64Abs => Self::Abs_FN,
Instruction::F32Ceil | Instruction::F64Ceil => Self::Ceil_FN,
Instruction::F32Floor | Instruction::F64Floor => Self::Floor_FN,
Instruction::F32Trunc | Instruction::F64Trunc => Self::Trunc_FN,
Instruction::F32Nearest | Instruction::F64Nearest => Self::Nearest_FN,
Instruction::F32Sqrt | Instruction::F64Sqrt => Self::Sqrt_FN,
Instruction::F32Copysign | Instruction::F64Copysign => Self::Copysign_FN,
Instruction::I32WrapI64 => Self::Wrap_I32_I64,
Instruction::I32TruncSF32 => Self::Trunc_I32_F32,
Instruction::I32TruncUF32 => Self::Trunc_U32_F32,
Instruction::I32TruncSF64 => Self::Trunc_I32_F64,
Instruction::I32TruncUF64 => Self::Trunc_U32_F64,
Instruction::I64ExtendSI32 => Self::Extend_I64_I32,
Instruction::I64ExtendUI32 => Self::Extend_U64_I32,
Instruction::I64TruncSF32 => Self::Trunc_I64_F32,
Instruction::I64TruncUF32 => Self::Trunc_U64_F32,
Instruction::I64TruncSF64 => Self::Trunc_I64_F64,
Instruction::I64TruncUF64 => Self::Trunc_U64_F64,
Instruction::F32ConvertSI32 => Self::Convert_F32_I32,
Instruction::F32ConvertUI32 => Self::Convert_F32_U32,
Instruction::F32ConvertSI64 => Self::Convert_F32_I64,
Instruction::F32ConvertUI64 => Self::Convert_F32_U64,
Instruction::F32DemoteF64 => Self::Demote_F32_F64,
Instruction::F64ConvertSI32 => Self::Convert_F64_I32,
Instruction::F64ConvertUI32 => Self::Convert_F64_U32,
Instruction::F64ConvertSI64 => Self::Convert_F64_I64,
Instruction::F64ConvertUI64 => Self::Convert_F64_U64,
Instruction::F64PromoteF32 => Self::Promote_F64_F32,
Instruction::I32ReinterpretF32 => Self::Reinterpret_I32_F32,
Instruction::I64ReinterpretF64 => Self::Reinterpret_I64_F64,
Instruction::F32ReinterpretI32 => Self::Reinterpret_F32_I32,
Instruction::F64ReinterpretI64 => Self::Reinterpret_F64_I64,
_ => return Err(()),
};
Ok(result)
}
}
#[allow(non_camel_case_types)]
pub enum BinOp {
LtU_I32,
GtU_I32,
LeU_I32,
GeU_I32,
LtU_I64,
GtU_I64,
LeU_I64,
GeU_I64,
DivS_I32,
DivU_I32,
RemS_I32,
RemU_I32,
And_I32,
Or_I32,
Xor_I32,
Shl_I32,
ShrS_I32,
ShrU_I32,
Rotl_I32,
Rotr_I32,
DivS_I64,
DivU_I64,
RemS_I64,
RemU_I64,
And_I64,
Or_I64,
Xor_I64,
Shl_I64,
ShrS_I64,
ShrU_I64,
Rotl_I64,
Rotr_I64,
Min_FN,
Max_FN,
}
impl Named for BinOp {
fn as_name(&self) -> Name {
match self {
Self::LtU_I32 => ("lt", "u32"),
Self::GtU_I32 => ("gt", "u32"),
Self::LeU_I32 => ("le", "u32"),
Self::GeU_I32 => ("ge", "u32"),
Self::LtU_I64 => ("lt", "u64"),
Self::GtU_I64 => ("gt", "u64"),
Self::LeU_I64 => ("le", "u64"),
Self::GeU_I64 => ("ge", "u64"),
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::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::Min_FN => ("math", "min"),
Self::Max_FN => ("math", "max"),
}
}
}
impl TryFrom<&Instruction> for BinOp {
type Error = ();
fn try_from(inst: &Instruction) -> Result<Self, Self::Error> {
let result = match inst {
Instruction::I32LtU => Self::LtU_I32,
Instruction::I32GtU => Self::GtU_I32,
Instruction::I32LeU => Self::LeU_I32,
Instruction::I32GeU => Self::GeU_I32,
Instruction::I64LtU => Self::LtU_I64,
Instruction::I64GtU => Self::GtU_I64,
Instruction::I64LeU => Self::LeU_I64,
Instruction::I64GeU => Self::GeU_I64,
Instruction::I32DivS => Self::DivS_I32,
Instruction::I32DivU => Self::DivU_I32,
Instruction::I32RemS => Self::RemS_I32,
Instruction::I32RemU => Self::RemU_I32,
Instruction::I32And => Self::And_I32,
Instruction::I32Or => Self::Or_I32,
Instruction::I32Xor => Self::Xor_I32,
Instruction::I32Shl => Self::Shl_I32,
Instruction::I32ShrS => Self::ShrS_I32,
Instruction::I32ShrU => Self::ShrU_I32,
Instruction::I32Rotl => Self::Rotl_I32,
Instruction::I32Rotr => Self::Rotr_I32,
Instruction::I64DivS => Self::DivS_I64,
Instruction::I64DivU => Self::DivU_I64,
Instruction::I64RemS => Self::RemS_I64,
Instruction::I64RemU => Self::RemU_I64,
Instruction::I64And => Self::And_I64,
Instruction::I64Or => Self::Or_I64,
Instruction::I64Xor => Self::Xor_I64,
Instruction::I64Shl => Self::Shl_I64,
Instruction::I64ShrS => Self::ShrS_I64,
Instruction::I64ShrU => Self::ShrU_I64,
Instruction::I64Rotl => Self::Rotl_I64,
Instruction::I64Rotr => Self::Rotr_I64,
Instruction::F32Min | Instruction::F64Min => Self::Min_FN,
Instruction::F32Max | Instruction::F64Max => Self::Max_FN,
_ => {
return Err(());
}
};
Ok(result)
}
}

View File

@ -107,14 +107,14 @@ impl<'a> Body<'a> {
self.reg.push(1); self.reg.push(1);
write!(w, "{0} = load.{1}(memory_at_0, {0} + {2}) ", reg, t, o) 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<()> { 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 val = f.var_name_of(self.reg.pop(1));
let reg = 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) write!(w, "store_{}(memory_at_0, {} + {}, {}) ", t, reg, o, val)
} }
fn gen_const<T: Display>(&mut self, val: T, f: &Code, w: Writer) -> Result<()> { fn gen_const<T: Display>(&mut self, val: T, f: &Code, w: Writer) -> Result<()> {
@ -370,57 +370,57 @@ impl<'a> Body<'a> {
} }
// note that signed comparisons of all types behave the same so // note that signed comparisons of all types behave the same so
// they can be condensed using Lua's operators // they can be condensed using Lua's operators
Instruction::I32LtU => self.gen_binop_ex("lt.u32", func, w), Instruction::I32LtU => self.gen_binop_ex("lt_u32", func, w),
Instruction::I32LtS | Instruction::I64LtS | Instruction::F32Lt | Instruction::F64Lt => { Instruction::I32LtS | Instruction::I64LtS | Instruction::F32Lt | Instruction::F64Lt => {
self.gen_compare("<", func, w) self.gen_compare("<", func, w)
} }
Instruction::I32GtU => self.gen_binop_ex("gt.u32", func, w), Instruction::I32GtU => self.gen_binop_ex("gt_u32", func, w),
Instruction::I32GtS | Instruction::I64GtS | Instruction::F32Gt | Instruction::F64Gt => { Instruction::I32GtS | Instruction::I64GtS | Instruction::F32Gt | Instruction::F64Gt => {
self.gen_compare(">", func, w) self.gen_compare(">", func, w)
} }
Instruction::I32LeU => self.gen_binop_ex("le.u32", func, w), Instruction::I32LeU => self.gen_binop_ex("le_u32", func, w),
Instruction::I32LeS | Instruction::I64LeS | Instruction::F32Le | Instruction::F64Le => { Instruction::I32LeS | Instruction::I64LeS | Instruction::F32Le | Instruction::F64Le => {
self.gen_compare("<=", func, w) self.gen_compare("<=", func, w)
} }
Instruction::I32GeU => self.gen_binop_ex("ge.u32", func, w), Instruction::I32GeU => self.gen_binop_ex("ge_u32", func, w),
Instruction::I32GeS | Instruction::I64GeS | Instruction::F32Ge | Instruction::F64Ge => { Instruction::I32GeS | Instruction::I64GeS | Instruction::F32Ge | Instruction::F64Ge => {
self.gen_compare(">=", func, w) self.gen_compare(">=", func, w)
} }
Instruction::I64LtU => self.gen_binop_ex("lt.u64", func, w), Instruction::I64LtU => self.gen_binop_ex("lt_u64", func, w),
Instruction::I64GtU => self.gen_binop_ex("gt.u64", func, w), Instruction::I64GtU => self.gen_binop_ex("gt_u64", func, w),
Instruction::I64LeU => self.gen_binop_ex("le.u64", func, w), Instruction::I64LeU => self.gen_binop_ex("le_u64", func, w),
Instruction::I64GeU => self.gen_binop_ex("ge.u64", func, w), Instruction::I64GeU => self.gen_binop_ex("ge_u64", func, w),
Instruction::I32Clz => self.gen_unop_ex("clz.i32", func, w), Instruction::I32Clz => self.gen_unop_ex("clz_i32", func, w),
Instruction::I32Ctz => self.gen_unop_ex("ctz.i32", func, w), Instruction::I32Ctz => self.gen_unop_ex("ctz_i32", func, w),
Instruction::I32Popcnt => self.gen_unop_ex("popcnt.i32", func, w), Instruction::I32Popcnt => self.gen_unop_ex("popcnt_i32", func, w),
Instruction::I32DivS => self.gen_binop_ex("div.i32", func, w), Instruction::I32DivS => self.gen_binop_ex("div_i32", func, w),
Instruction::I32DivU => self.gen_binop_ex("div.u32", func, w), Instruction::I32DivU => self.gen_binop_ex("div_u32", func, w),
Instruction::I32RemS => self.gen_binop_ex("rem.i32", func, w), Instruction::I32RemS => self.gen_binop_ex("rem_i32", func, w),
Instruction::I32RemU => self.gen_binop_ex("rem.u32", func, w), Instruction::I32RemU => self.gen_binop_ex("rem_u32", func, w),
Instruction::I32And => self.gen_binop_ex("band.i32", func, w), Instruction::I32And => self.gen_binop_ex("band_i32", func, w),
Instruction::I32Or => self.gen_binop_ex("bor.i32", func, w), Instruction::I32Or => self.gen_binop_ex("bor_i32", func, w),
Instruction::I32Xor => self.gen_binop_ex("bxor.i32", func, w), Instruction::I32Xor => self.gen_binop_ex("bxor_i32", func, w),
Instruction::I32Shl => self.gen_binop_ex("shl.i32", func, w), Instruction::I32Shl => self.gen_binop_ex("shl_i32", func, w),
Instruction::I32ShrS => self.gen_binop_ex("shr.i32", func, w), Instruction::I32ShrS => self.gen_binop_ex("shr_i32", func, w),
Instruction::I32ShrU => self.gen_binop_ex("shr.u32", func, w), Instruction::I32ShrU => self.gen_binop_ex("shr_u32", func, w),
Instruction::I32Rotl => self.gen_binop_ex("rotl.i32", func, w), Instruction::I32Rotl => self.gen_binop_ex("rotl_i32", func, w),
Instruction::I32Rotr => self.gen_binop_ex("rotr.i32", func, w), Instruction::I32Rotr => self.gen_binop_ex("rotr_i32", func, w),
Instruction::I64Clz => self.gen_unop_ex("clz.i64", func, w), Instruction::I64Clz => self.gen_unop_ex("clz_i64", func, w),
Instruction::I64Ctz => self.gen_unop_ex("ctz.i64", func, w), Instruction::I64Ctz => self.gen_unop_ex("ctz_i64", func, w),
Instruction::I64Popcnt => self.gen_unop_ex("popcnt.i64", func, w), Instruction::I64Popcnt => self.gen_unop_ex("popcnt_i64", func, w),
Instruction::I64DivS => self.gen_binop_ex("div.i64", func, w), Instruction::I64DivS => self.gen_binop_ex("div_i64", func, w),
Instruction::I64DivU => self.gen_binop_ex("div.u64", func, w), Instruction::I64DivU => self.gen_binop_ex("div_u64", func, w),
Instruction::I64RemS => self.gen_binop_ex("rem.i64", func, w), Instruction::I64RemS => self.gen_binop_ex("rem_i64", func, w),
Instruction::I64RemU => self.gen_binop_ex("rem.u64", func, w), Instruction::I64RemU => self.gen_binop_ex("rem_u64", func, w),
Instruction::I64And => self.gen_binop_ex("band.i64", func, w), Instruction::I64And => self.gen_binop_ex("band_i64", func, w),
Instruction::I64Or => self.gen_binop_ex("bor.i64", func, w), Instruction::I64Or => self.gen_binop_ex("bor_i64", func, w),
Instruction::I64Xor => self.gen_binop_ex("bxor.i64", func, w), Instruction::I64Xor => self.gen_binop_ex("bxor_i64", func, w),
Instruction::I64Shl => self.gen_binop_ex("shl.i64", func, w), Instruction::I64Shl => self.gen_binop_ex("shl_i64", func, w),
Instruction::I64ShrS => self.gen_binop_ex("shr.i64", func, w), Instruction::I64ShrS => self.gen_binop_ex("shr_i64", func, w),
Instruction::I64ShrU => self.gen_binop_ex("shr.u64", func, w), Instruction::I64ShrU => self.gen_binop_ex("shr_u64", func, w),
Instruction::I64Rotl => self.gen_binop_ex("rotl.i64", func, w), Instruction::I64Rotl => self.gen_binop_ex("rotl_i64", func, w),
Instruction::I64Rotr => self.gen_binop_ex("rotr.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::F32Abs | Instruction::F64Abs => self.gen_unop_ex("math_abs", func, w),
Instruction::F32Neg | Instruction::F64Neg => { Instruction::F32Neg | Instruction::F64Neg => {
let reg = func.var_name_of(self.reg.pop(1)); let reg = func.var_name_of(self.reg.pop(1));
@ -428,15 +428,15 @@ impl<'a> Body<'a> {
write!(w, "{} = -{} ", reg, reg) write!(w, "{} = -{} ", reg, reg)
} }
Instruction::F32Ceil | Instruction::F64Ceil => self.gen_unop_ex("math.ceil", func, w), Instruction::F32Ceil | Instruction::F64Ceil => self.gen_unop_ex("math_ceil", func, w),
Instruction::F32Floor | Instruction::F64Floor => { Instruction::F32Floor | Instruction::F64Floor => {
self.gen_unop_ex("math.floor", func, w) self.gen_unop_ex("math_floor", func, w)
} }
Instruction::F32Trunc | Instruction::F64Trunc => self.gen_unop_ex("trunc.f", func, w), Instruction::F32Trunc | Instruction::F64Trunc => self.gen_unop_ex("trunc_f", func, w),
Instruction::F32Nearest | Instruction::F64Nearest => { Instruction::F32Nearest | Instruction::F64Nearest => {
self.gen_unop_ex("nearest.f", func, w) self.gen_unop_ex("nearest_f", func, w)
} }
Instruction::F32Sqrt | Instruction::F64Sqrt => self.gen_unop_ex("math.sqrt", func, w), Instruction::F32Sqrt | Instruction::F64Sqrt => self.gen_unop_ex("math_sqrt", func, w),
Instruction::I32Add Instruction::I32Add
| Instruction::I64Add | Instruction::I64Add
| Instruction::F32Add | Instruction::F32Add
@ -450,36 +450,36 @@ impl<'a> Body<'a> {
| Instruction::F32Mul | Instruction::F32Mul
| Instruction::F64Mul => self.gen_binop("*", func, w), | Instruction::F64Mul => self.gen_binop("*", func, w),
Instruction::F32Div | Instruction::F64Div => 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::F32Min | Instruction::F64Min => self.gen_binop_ex("math_min", func, w),
Instruction::F32Max | Instruction::F64Max => self.gen_binop_ex("math.max", func, w), Instruction::F32Max | Instruction::F64Max => self.gen_binop_ex("math_max", func, w),
Instruction::F32Copysign | Instruction::F64Copysign => { Instruction::F32Copysign | Instruction::F64Copysign => {
self.gen_unop_ex("math.sign", func, w) self.gen_unop_ex("math_sign", func, w)
} }
Instruction::I32WrapI64 => self.gen_unop_ex("wrap.i64_i32", 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::I32TruncSF32 => self.gen_unop_ex("trunc_f32_i32", func, w),
Instruction::I32TruncUF32 => self.gen_unop_ex("trunc.f32_u32", 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::I32TruncSF64 => self.gen_unop_ex("trunc_f64_i32", func, w),
Instruction::I32TruncUF64 => self.gen_unop_ex("trunc.f64_u32", 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::I64ExtendSI32 => self.gen_unop_ex("extend_i32_i64", func, w),
Instruction::I64ExtendUI32 => self.gen_unop_ex("extend.i32_u64", 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::I64TruncSF32 => self.gen_unop_ex("trunc_f32_i64", func, w),
Instruction::I64TruncUF32 => self.gen_unop_ex("trunc.f32_u64", 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::I64TruncSF64 => self.gen_unop_ex("trunc_f64_i64", func, w),
Instruction::I64TruncUF64 => self.gen_unop_ex("trunc.f64_u64", 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::F32ConvertSI32 => self.gen_unop_ex("convert_i32_f32", func, w),
Instruction::F32ConvertUI32 => self.gen_unop_ex("convert.u32_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::F32ConvertSI64 => self.gen_unop_ex("convert_i64_f32", func, w),
Instruction::F32ConvertUI64 => self.gen_unop_ex("convert.u64_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::F32DemoteF64 => self.gen_unop_ex("demote_f64_f32", func, w),
Instruction::F64ConvertSI32 => self.gen_unop_ex("convert.f64_i32", 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::F64ConvertUI32 => self.gen_unop_ex("convert_f64_u32", func, w),
Instruction::F64ConvertSI64 => self.gen_unop_ex("convert.f64_i64", 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::F64ConvertUI64 => self.gen_unop_ex("convert_f64_u64", func, w),
Instruction::F64PromoteF32 => self.gen_unop_ex("promote.f32_f64", 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::I32ReinterpretF32 => self.gen_unop_ex("reinterpret_f32_i32", func, w),
Instruction::I64ReinterpretF64 => self.gen_unop_ex("reinterpret.f64_i64", 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::F32ReinterpretI32 => self.gen_unop_ex("reinterpret_i32_f32", func, w),
Instruction::F64ReinterpretI64 => self.gen_unop_ex("reinterpret.i64_f64", func, w), Instruction::F64ReinterpretI64 => self.gen_unop_ex("reinterpret_i64_f64", func, w),
} }
} }
} }

View File

@ -6,7 +6,7 @@ use crate::{
backend::{ backend::{
edition::data::Edition, edition::data::Edition,
helper::writer::{write_ordered, Writer}, helper::writer::{write_ordered, Writer},
visitor::{memory, register}, visitor::{localize, memory, register},
}, },
data::Module, data::Module,
}; };
@ -57,8 +57,14 @@ fn gen_memory(set: BTreeSet<u8>, w: Writer) -> Result<()> {
.try_for_each(|i| write!(w, "local memory_at_{0} = MEMORY_LIST[{0}]", i)) .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<()> { pub fn gen_function(spec: &dyn Edition, index: usize, m: &Module, w: Writer) -> Result<()> {
let mem_set = memory::visit(m, index); let mem_set = memory::visit(m, index);
let loc_set = localize::visit(m, index);
let num_stack = register::visit(m, index); let num_stack = register::visit(m, index);
let num_param = m.in_arity[index].num_param; let num_param = m.in_arity[index].num_param;
@ -68,6 +74,7 @@ pub fn gen_function(spec: &dyn Edition, index: usize, m: &Module, w: Writer) ->
gen_prelude(num_stack, num_param, num_local, w)?; gen_prelude(num_stack, num_param, num_local, w)?;
gen_memory(mem_set, w)?; gen_memory(mem_set, w)?;
gen_localize(loc_set, w)?;
inner.generate(index, m, w)?; inner.generate(index, m, w)?;
assert!( assert!(

View File

@ -0,0 +1,24 @@
use std::{collections::BTreeSet, convert::TryFrom};
use crate::{
backend::helper::operation::{BinOp, Load, Named, Store, UnOp},
data::Module,
};
pub fn visit(m: &Module, index: usize) -> BTreeSet<(&'static str, &'static str)> {
let mut result = BTreeSet::new();
for i in m.code[index].inst_list {
if let Ok(used) = Load::try_from(i) {
result.insert(used.as_name());
} else if let Ok(used) = Store::try_from(i) {
result.insert(used.as_name());
} else if let Ok(used) = UnOp::try_from(i) {
result.insert(used.as_name());
} else if let Ok(used) = BinOp::try_from(i) {
result.insert(used.as_name());
}
}
result
}

View File

@ -1,2 +1,3 @@
pub mod localize;
pub mod memory; pub mod memory;
pub mod register; pub mod register;