diff --git a/Cargo.toml b/Cargo.toml index ffe60876e9..5f716ee0d3 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -11,8 +11,8 @@ edition = "2018" [dependencies] smallvec = "0.6" -dynasm = "0.2.3" -dynasmrt = "0.2.3" +dynasm = "0.3" +dynasmrt = "0.3" wasmparser = { path = "./wasmparser.rs" } memoffset = "0.2" itertools = "0.8" @@ -29,3 +29,6 @@ typemap = "0.3" [badges] maintenance = { status = "experimental" } + +[features] +bench = [] diff --git a/src/backend.rs b/src/backend.rs index b60a40cef2..3e217934b3 100644 --- a/src/backend.rs +++ b/src/backend.rs @@ -2,6 +2,7 @@ use crate::error::Error; use crate::microwasm::{BrTarget, SignlessType, Type, Value, F32, F64, I32, I64}; use crate::module::ModuleContext; use cranelift_codegen::{binemit, ir}; +use dynasm::dynasm; use dynasmrt::x64::Assembler; use dynasmrt::{AssemblyOffset, DynamicLabel, DynasmApi, DynasmLabelApi, ExecutableBuffer}; use either::Either; @@ -231,61 +232,6 @@ const REST_MASK_F64: u64 = !SIGN_MASK_F64; const SIGN_MASK_F32: u32 = 0b10000000000000000000000000000000; const REST_MASK_F32: u32 = !SIGN_MASK_F32; -extern "sysv64" fn println(len: u64, args: *const u8) { - println!("{}", unsafe { - std::str::from_utf8_unchecked(std::slice::from_raw_parts(args, len as usize)) - }); -} - -macro_rules! asm_println { - ($asm:expr) => {asm_println!($asm,)}; - ($asm:expr, $($args:tt)*) => {{ - use std::mem; - - let mut args = format!($($args)*).into_bytes(); - - let len = args.len(); - let ptr = args.as_mut_ptr(); - mem::forget(args); - - dynasm!($asm - ; push rdi - ; push rsi - ; push rdx - ; push rcx - ; push r8 - ; push r9 - ; push r10 - ; push r11 - - ; mov rax, QWORD println as *const u8 as i64 - ; mov rdi, QWORD len as i64 - ; mov rsi, QWORD ptr as i64 - - ; test rsp, 0b1111 - ; jnz >with_adjusted_stack_ptr - - ; call rax - ; jmp >pop_rest - - ; with_adjusted_stack_ptr: - ; push 1 - ; call rax - ; pop r11 - - ; pop_rest: - ; pop r11 - ; pop r10 - ; pop r9 - ; pop r8 - ; pop rcx - ; pop rdx - ; pop rsi - ; pop rdi - ); - }} -} - impl GPRs { fn take(&mut self) -> Option { let lz = self.bits.trailing_zeros(); @@ -675,18 +621,22 @@ macro_rules! int_div { return; } - let (div, rem, saved) = self.$full_div_u(divisor, quotient); + let (div, rem, mut saved) = self.$full_div_u(divisor, quotient); self.free_value(rem); let div = match div { - ValueLocation::Reg(div) if saved.clone().any(|(_, dst)| dst == div) => { - let new = self.take_reg(I32); - dynasm!(self.asm - ; mov Rq(new.rq().unwrap()), Rq(div.rq().unwrap()) - ); - self.block_state.regs.release(div); - ValueLocation::Reg(new) + ValueLocation::Reg(div) => { + if saved.any(|(_, dst)| dst == div) { + let new = self.take_reg(I32); + dynasm!(self.asm + ; mov Rq(new.rq().unwrap()), Rq(div.rq().unwrap()) + ); + self.block_state.regs.release(div); + ValueLocation::Reg(new) + } else { + ValueLocation::Reg(div) + } } _ => div, }; @@ -715,18 +665,22 @@ macro_rules! int_div { return; } - let (div, rem, saved) = self.$full_div_s(divisor, quotient); + let (div, rem, mut saved) = self.$full_div_s(divisor, quotient); self.free_value(rem); let div = match div { - ValueLocation::Reg(div) if saved.clone().any(|(_, dst)| dst == div) => { - let new = self.take_reg(I32); - dynasm!(self.asm - ; mov Rq(new.rq().unwrap()), Rq(div.rq().unwrap()) - ); - self.block_state.regs.release(div); - ValueLocation::Reg(new) + ValueLocation::Reg(div) => { + if saved.any(|(_, dst)| dst == div) { + let new = self.take_reg(I32); + dynasm!(self.asm + ; mov Rq(new.rq().unwrap()), Rq(div.rq().unwrap()) + ); + self.block_state.regs.release(div); + ValueLocation::Reg(new) + } else { + ValueLocation::Reg(div) + } } _ => div, }; @@ -752,18 +706,22 @@ macro_rules! int_div { return; } - let (div, rem, saved) = self.$full_div_u(divisor, quotient); + let (div, rem, mut saved) = self.$full_div_u(divisor, quotient); self.free_value(div); let rem = match rem { - ValueLocation::Reg(rem) if saved.clone().any(|(_, dst)| dst == rem) => { - let new = self.take_reg(I32); - dynasm!(self.asm - ; mov Rq(new.rq().unwrap()), Rq(rem.rq().unwrap()) - ); - self.block_state.regs.release(rem); - ValueLocation::Reg(new) + ValueLocation::Reg(rem) => { + if saved.any(|(_, dst)| dst == rem) { + let new = self.take_reg(I32); + dynasm!(self.asm + ; mov Rq(new.rq().unwrap()), Rq(rem.rq().unwrap()) + ); + self.block_state.regs.release(rem); + ValueLocation::Reg(new) + } else { + ValueLocation::Reg(rem) + } } _ => rem, }; @@ -787,18 +745,22 @@ macro_rules! int_div { return; } - let (div, rem, saved) = self.$full_div_s(divisor, quotient); + let (div, rem, mut saved) = self.$full_div_s(divisor, quotient); self.free_value(div); let rem = match rem { - ValueLocation::Reg(rem) if saved.clone().any(|(_, dst)| dst == rem) => { - let new = self.take_reg(I32); - dynasm!(self.asm - ; mov Rq(new.rq().unwrap()), Rq(rem.rq().unwrap()) - ); - self.block_state.regs.release(rem); - ValueLocation::Reg(new) + ValueLocation::Reg(rem) => { + if saved.any(|(_, dst)| dst == rem) { + let new = self.take_reg(I32); + dynasm!(self.asm + ; mov Rq(new.rq().unwrap()), Rq(rem.rq().unwrap()) + ); + self.block_state.regs.release(rem); + ValueLocation::Reg(new) + } else { + ValueLocation::Reg(rem) + } } _ => rem, }; @@ -811,7 +773,7 @@ macro_rules! int_div { } macro_rules! unop { - ($name:ident, $instr:ident, $reg_ty:ident, $typ:ty, $const_fallback:expr) => { + ($name:ident, $instr:ident, $reg_ty:tt, $typ:ty, $const_fallback:expr) => { pub fn $name(&mut self) { let val = self.pop(); @@ -847,9 +809,9 @@ macro_rules! conversion { ( $name:ident, $instr:ident, - $in_reg_ty:ident, + $in_reg_ty:tt, $in_reg_fn:ident, - $out_reg_ty:ident, + $out_reg_ty:tt, $out_reg_fn:ident, $in_typ:ty, $out_typ:ty, @@ -895,7 +857,7 @@ macro_rules! conversion { // TODO: Support immediate `count` parameters macro_rules! shift { - ($name:ident, $reg_ty:ident, $instr:ident, $const_fallback:expr, $ty:expr) => { + ($name:ident, $reg_ty:tt, $instr:ident, $const_fallback:expr, $ty:expr) => { pub fn $name(&mut self) { let mut count = self.pop(); let mut val = self.pop(); @@ -1481,7 +1443,7 @@ macro_rules! commutative_binop_f64 { }; } macro_rules! commutative_binop { - ($name:ident, $instr:ident, $const_fallback:expr, $reg_ty:ident, $reg_fn:ident, $ty:expr, $imm_fn:ident, $direct_imm:expr) => { + ($name:ident, $instr:ident, $const_fallback:expr, $reg_ty:tt, $reg_fn:ident, $ty:expr, $imm_fn:ident, $direct_imm:expr) => { binop!( $name, $instr, @@ -1506,10 +1468,10 @@ macro_rules! commutative_binop { } macro_rules! binop { - ($name:ident, $instr:ident, $const_fallback:expr, $reg_ty:ident, $reg_fn:ident, $ty:expr, $imm_fn:ident, $direct_imm:expr) => { + ($name:ident, $instr:ident, $const_fallback:expr, $reg_ty:tt, $reg_fn:ident, $ty:expr, $imm_fn:ident, $direct_imm:expr) => { binop!($name, $instr, $const_fallback, $reg_ty, $reg_fn, $ty, $imm_fn, $direct_imm, |a, b| (a, b)); }; - ($name:ident, $instr:ident, $const_fallback:expr, $reg_ty:ident, $reg_fn:ident, $ty:expr, $imm_fn:ident, $direct_imm:expr, $map_op:expr) => { + ($name:ident, $instr:ident, $const_fallback:expr, $reg_ty:tt, $reg_fn:ident, $ty:expr, $imm_fn:ident, $direct_imm:expr, $map_op:expr) => { pub fn $name(&mut self) { let right = self.pop(); let left = self.pop(); @@ -1541,7 +1503,7 @@ macro_rules! binop { } ValueLocation::Immediate(i) => { if let Some(i) = i.as_int().and_then(|i| i.try_into()) { - $direct_imm(self, left, i); + $direct_imm(&mut *self, left, i); } else { let scratch = self.take_reg($ty); self.immediate_to_reg(scratch, i); @@ -1562,7 +1524,7 @@ macro_rules! binop { } macro_rules! load { - (@inner $name:ident, $rtype:expr, $reg_ty:ident, $emit_fn:expr) => { + (@inner $name:ident, $rtype:expr, $reg_ty:tt, $emit_fn:expr) => { pub fn $name(&mut self, offset: u32) { fn load_to_reg<_M: ModuleContext>( ctx: &mut Context<_M>, @@ -1666,7 +1628,7 @@ macro_rules! load { self.push(ValueLocation::Reg(temp)); } }; - ($name:ident, $rtype:expr, $reg_ty:ident, NONE, $rq_instr:ident, $ty:ident) => { + ($name:ident, $rtype:expr, $reg_ty:tt, NONE, $rq_instr:ident, $ty:ident) => { load!(@inner $name, $rtype, @@ -1687,7 +1649,7 @@ macro_rules! load { } ); }; - ($name:ident, $rtype:expr, $reg_ty:ident, $xmm_instr:ident, $rq_instr:ident, $ty:ident) => { + ($name:ident, $rtype:expr, $reg_ty:tt, $xmm_instr:ident, $rq_instr:ident, $ty:ident) => { load!(@inner $name, $rtype, @@ -1721,7 +1683,7 @@ macro_rules! load { } macro_rules! store { - (@inner $name:ident, $int_reg_ty:ident, $match_offset:expr, $size:ident) => { + (@inner $name:ident, $int_reg_ty:tt, $match_offset:expr, $size:ident) => { pub fn $name(&mut self, offset: u32) { fn store_from_reg<_M: ModuleContext>( ctx: &mut Context<_M>, @@ -1827,7 +1789,7 @@ macro_rules! store { } } }; - ($name:ident, $int_reg_ty:ident, NONE, $size:ident) => { + ($name:ident, $int_reg_ty:tt, NONE, $size:ident) => { store!(@inner $name, $int_reg_ty, @@ -1852,7 +1814,7 @@ macro_rules! store { $size ); }; - ($name:ident, $int_reg_ty:ident, $xmm_instr:ident, $size:ident) => { + ($name:ident, $int_reg_ty:tt, $xmm_instr:ident, $size:ident) => { store!(@inner $name, $int_reg_ty, @@ -1948,10 +1910,6 @@ impl<'this, M: ModuleContext> Context<'this, M> { } } - pub fn debug(&mut self, d: std::fmt::Arguments) { - asm_println!(self.asm, "{}", d); - } - pub fn virtual_calling_convention(&self) -> VirtualCallingConvention { VirtualCallingConvention { stack: self.block_state.stack.clone(), diff --git a/src/error.rs b/src/error.rs index c7b1fe46e8..5f2ac6492e 100644 --- a/src/error.rs +++ b/src/error.rs @@ -20,12 +20,6 @@ impl From for Error { } } -impl From for Error { - fn from(other: !) -> Self { - other - } -} - impl From for Error { fn from(e: capstone::Error) -> Self { Error::Disassembler(e.to_string()) diff --git a/src/lib.rs b/src/lib.rs index b3cb08d16d..d76b0d786a 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,18 +1,6 @@ -#![feature( - plugin, - test, - const_slice_len, - never_type, - alloc_layout_extra, - try_from, - try_trait, - bind_by_move_pattern_guards, - fnbox, - copysign -)] -#![plugin(dynasm)] +#![cfg_attr(feature = "bench", feature(test))] +#![feature(proc_macro_hygiene)] -extern crate test; #[macro_use] extern crate smallvec; extern crate capstone; @@ -23,6 +11,7 @@ pub extern crate wasmparser; extern crate failure_derive; #[macro_use] extern crate memoffset; +extern crate dynasm; extern crate dynasmrt; extern crate itertools; #[cfg(test)] diff --git a/src/microwasm.rs b/src/microwasm.rs index 56f32521a3..80b8ea2c1f 100644 --- a/src/microwasm.rs +++ b/src/microwasm.rs @@ -1,11 +1,10 @@ use crate::module::{ModuleContext, SigType, Signature}; use smallvec::SmallVec; use std::{ - convert::{TryFrom, TryInto}, + convert::TryInto, fmt, iter::{self, FromIterator}, ops::RangeInclusive, - option::NoneError, }; use wasmparser::{ FunctionBody, Ieee32, Ieee64, MemoryImmediate, Operator as WasmOperator, OperatorsReader, @@ -290,14 +289,6 @@ impl SignlessType { } } -impl TryFrom for SignlessType { - type Error = NoneError; - - fn try_from(other: wasmparser::Type) -> Result { - Ok(SignlessType::from_wasm(other)?) - } -} - #[derive(Debug, Clone)] pub struct BrTable { pub targets: Vec>, @@ -1543,9 +1534,7 @@ where id, arguments: self.stack.len() as u32, returns: Vec::from_iter(Type::from_wasm(ty)), - kind: ControlFrameKind::If { - has_else: false, - }, + kind: ControlFrameKind::If { has_else: false }, }); let (then, else_, end) = ( (id, NameTag::Header), diff --git a/src/tests.rs b/src/tests.rs index e9023e0c48..0b0a2432a6 100644 --- a/src/tests.rs +++ b/src/tests.rs @@ -929,7 +929,10 @@ fn i64_rem() { let translated = translate_wat(CODE); translated.disassemble(); - assert_eq!(translated.execute_func::<_, u64>(0, (123121i64, -1i64)), Ok(0)); + assert_eq!( + translated.execute_func::<_, u64>(0, (123121i64, -1i64)), + Ok(0) + ); } #[test] @@ -1021,37 +1024,44 @@ macro_rules! test_select { test_select!(select32, i32); test_select!(select64, i64); -#[bench] -fn bench_fibonacci_compile(b: &mut test::Bencher) { - let wasm = wabt::wat2wasm(FIBONACCI).unwrap(); +#[cfg(feature = "bench")] +mod benches { + extern crate test; - b.iter(|| test::black_box(translate(&wasm).unwrap())); -} + use super::{translate, wabt, FIBONACCI, FIBONACCI_OPT}; -#[bench] -fn bench_fibonacci_run(b: &mut test::Bencher) { - let wasm = wabt::wat2wasm(FIBONACCI_OPT).unwrap(); - let module = translate(&wasm).unwrap(); + #[bench] + fn bench_fibonacci_compile(b: &mut test::Bencher) { + let wasm = wabt::wat2wasm(FIBONACCI).unwrap(); - b.iter(|| module.execute_func::<_, u32>(0, (20,))); -} - -#[bench] -fn bench_fibonacci_compile_run(b: &mut test::Bencher) { - let wasm = wabt::wat2wasm(FIBONACCI).unwrap(); - - b.iter(|| translate(&wasm).unwrap().execute_func::<_, u32>(0, (20,))); -} - -#[bench] -fn bench_fibonacci_baseline(b: &mut test::Bencher) { - fn fib(n: i32) -> i32 { - if n == 0 || n == 1 { - 1 - } else { - fib(n - 1) + fib(n - 2) - } + b.iter(|| test::black_box(translate(&wasm).unwrap())); } - b.iter(|| test::black_box(fib(test::black_box(20)))); + #[bench] + fn bench_fibonacci_run(b: &mut test::Bencher) { + let wasm = wabt::wat2wasm(FIBONACCI_OPT).unwrap(); + let module = translate(&wasm).unwrap(); + + b.iter(|| module.execute_func::<_, u32>(0, (20,))); + } + + #[bench] + fn bench_fibonacci_compile_run(b: &mut test::Bencher) { + let wasm = wabt::wat2wasm(FIBONACCI).unwrap(); + + b.iter(|| translate(&wasm).unwrap().execute_func::<_, u32>(0, (20,))); + } + + #[bench] + fn bench_fibonacci_baseline(b: &mut test::Bencher) { + fn fib(n: i32) -> i32 { + if n == 0 || n == 1 { + 1 + } else { + fib(n - 1) + fib(n - 2) + } + } + + b.iter(|| test::black_box(fib(test::black_box(20)))); + } }