diff --git a/README.md b/README.md index a0c6d6aef2..a8837c0aff 100644 --- a/README.md +++ b/README.md @@ -165,88 +165,88 @@ Now obviously I'm not advocating for replacing FireFox's optimising compiler wit ## Specification compliance -It's hard to judge, since each test in the spec testsuite covers a wide range of features (to check their interactions), but currently 40 out of 76 of the spec suite tests pass when run in Wasmtime with Lightbeam as a backend. Here's the full test output: +It's hard to judge, since each test in the spec testsuite covers a wide range of features (to check their interactions), but currently 42 out of 76 of the spec suite tests pass when run in Wasmtime with Lightbeam as a backend. Here's the full test output: ``` running 76 tests -test misc_testsuite::stack_overflow ... ok -test spec_testsuite::binary ... ok -test misc_testsuite::misc_traps ... ok -test spec_testsuite::align ... FAILED -test spec_testsuite::address ... FAILED -test spec_testsuite::block ... ok -test spec_testsuite::break_drop ... ok -test spec_testsuite::call ... FAILED -test spec_testsuite::br ... ok -test spec_testsuite::call_indirect ... FAILED -test spec_testsuite::comments ... ok -test spec_testsuite::const_ ... ok -test spec_testsuite::custom ... ok -test spec_testsuite::custom_section ... ok -test spec_testsuite::data ... ok -test spec_testsuite::conversions ... FAILED -test spec_testsuite::endianness ... FAILED -test spec_testsuite::elem ... FAILED -test spec_testsuite::br_if ... ok -test spec_testsuite::exports ... ok -test spec_testsuite::f32_bitwise ... FAILED -test spec_testsuite::br_table ... FAILED -test spec_testsuite::f64_bitwise ... FAILED -test spec_testsuite::f32 ... FAILED -test spec_testsuite::f32_cmp ... FAILED -test spec_testsuite::fac ... ok -test spec_testsuite::f64 ... FAILED -test spec_testsuite::f64_cmp ... FAILED -test spec_testsuite::float_memory ... ok -test spec_testsuite::forward ... ok -test spec_testsuite::float_misc ... FAILED -test spec_testsuite::func_ptrs ... FAILED -test spec_testsuite::get_local ... FAILED -test spec_testsuite::float_exprs ... FAILED -test spec_testsuite::float_literals ... ok -test spec_testsuite::globals ... ok -test spec_testsuite::if_ ... FAILED -test spec_testsuite::func ... ok -test spec_testsuite::inline_module ... ok -test spec_testsuite::imports ... FAILED -test spec_testsuite::i32 ... ok -test spec_testsuite::i64 ... ok -test spec_testsuite::int_literals ... ok -test spec_testsuite::labels ... ok -test spec_testsuite::linking ... FAILED -test spec_testsuite::left_to_right ... FAILED -test spec_testsuite::loop_ ... FAILED -test spec_testsuite::memory ... FAILED -test spec_testsuite::memory_grow ... FAILED -test spec_testsuite::memory_redundancy ... ok -test spec_testsuite::memory_trap ... FAILED -test spec_testsuite::resizing ... FAILED -test spec_testsuite::nop ... FAILED -test spec_testsuite::return_minimal ... ok -test spec_testsuite::int_exprs ... ok -test spec_testsuite::set_local ... FAILED -test spec_testsuite::select ... FAILED -test spec_testsuite::skip_stack_guard_page ... FAILED -test spec_testsuite::stack ... ok -test spec_testsuite::store_retval ... ok -test spec_testsuite::start ... FAILED -test spec_testsuite::tee_local ... FAILED -test spec_testsuite::token ... ok -test spec_testsuite::switch ... ok -test spec_testsuite::type_ ... ok -test spec_testsuite::return_ ... ok -test spec_testsuite::typecheck ... ok -test spec_testsuite::traps ... FAILED -test spec_testsuite::unwind ... FAILED -test spec_testsuite::unreached_invalid ... ok +test misc_testsuite::stack_overflow ... ok +test misc_testsuite::misc_traps ... ok +test spec_testsuite::binary ... ok +test spec_testsuite::align ... FAILED +test spec_testsuite::address ... FAILED +test spec_testsuite::block ... ok +test spec_testsuite::break_drop ... ok +test spec_testsuite::br ... ok +test spec_testsuite::call ... FAILED +test spec_testsuite::comments ... ok +test spec_testsuite::call_indirect ... FAILED +test spec_testsuite::const_ ... ok +test spec_testsuite::custom ... ok +test spec_testsuite::custom_section ... ok +test spec_testsuite::br_if ... ok +test spec_testsuite::data ... ok +test spec_testsuite::conversions ... FAILED +test spec_testsuite::endianness ... FAILED +test spec_testsuite::exports ... ok +test spec_testsuite::elem ... FAILED +test spec_testsuite::f32_bitwise ... FAILED +test spec_testsuite::br_table ... FAILED +test spec_testsuite::f64_bitwise ... FAILED +test spec_testsuite::f32 ... FAILED +test spec_testsuite::fac ... ok +test spec_testsuite::f64 ... FAILED +test spec_testsuite::f32_cmp ... ok +test spec_testsuite::float_memory ... ok +test spec_testsuite::f64_cmp ... ok +test spec_testsuite::forward ... ok +test spec_testsuite::float_misc ... FAILED +test spec_testsuite::func_ptrs ... FAILED +test spec_testsuite::get_local ... FAILED +test spec_testsuite::float_literals ... ok +test spec_testsuite::float_exprs ... FAILED +test spec_testsuite::globals ... ok +test spec_testsuite::func ... ok +test spec_testsuite::if_ ... FAILED +test spec_testsuite::inline_module ... ok +test spec_testsuite::imports ... FAILED +test spec_testsuite::i32 ... ok +test spec_testsuite::int_literals ... ok +test spec_testsuite::labels ... ok +test spec_testsuite::linking ... FAILED +test spec_testsuite::i64 ... ok +test spec_testsuite::left_to_right ... FAILED +test spec_testsuite::loop_ ... FAILED +test spec_testsuite::memory ... FAILED +test spec_testsuite::memory_grow ... FAILED +test spec_testsuite::memory_redundancy ... ok +test spec_testsuite::memory_trap ... FAILED +test spec_testsuite::resizing ... FAILED +test spec_testsuite::nop ... FAILED +test spec_testsuite::return_minimal ... ok +test spec_testsuite::int_exprs ... ok +test spec_testsuite::set_local ... FAILED +test spec_testsuite::select ... FAILED +test spec_testsuite::skip_stack_guard_page ... FAILED +test spec_testsuite::stack ... ok +test spec_testsuite::store_retval ... ok +test spec_testsuite::start ... FAILED +test spec_testsuite::tee_local ... FAILED +test spec_testsuite::token ... ok +test spec_testsuite::switch ... ok +test spec_testsuite::type_ ... ok +test spec_testsuite::typecheck ... ok +test spec_testsuite::traps ... FAILED +test spec_testsuite::return_ ... ok +test spec_testsuite::unreached_invalid ... ok +test spec_testsuite::unwind ... FAILED test spec_testsuite::utf8_custom_section_id ... ok -test spec_testsuite::utf8_import_field ... ok -test spec_testsuite::utf8_import_module ... ok -test spec_testsuite::utf8_invalid_encoding ... ok -test spec_testsuite::unreachable ... ok -test spec_testsuite::names ... FAILED +test spec_testsuite::utf8_import_field ... ok +test spec_testsuite::utf8_import_module ... ok +test spec_testsuite::utf8_invalid_encoding ... ok +test spec_testsuite::unreachable ... ok +test spec_testsuite::names ... FAILED -test result: FAILED. 40 passed; 36 failed; 0 ignored; 0 measured; 0 filtered out +test result: FAILED. 42 passed; 34 failed; 0 ignored; 0 measured; 0 filtered out ``` ## Getting involved diff --git a/src/backend.rs b/src/backend.rs index 59c67dd354..7e725a35a2 100644 --- a/src/backend.rs +++ b/src/backend.rs @@ -1245,6 +1245,48 @@ macro_rules! cmp_f32 { }; } +macro_rules! eq_float { + ($name:ident, $instr:ident, $imm_fn:ident, $const_fallback:expr) => { + pub fn $name(&mut self) { + let right = self.pop(); + let left = self.pop(); + + if let Some(right) = right.immediate() { + if let Some(left) = left.immediate() { + self.push(ValueLocation::Immediate( + if $const_fallback(left.$imm_fn().unwrap(), right.$imm_fn().unwrap()) { + 1u32 + } else { + 0 + }.into() + )); + return; + } + } + + let (left, right) = match left { + ValueLocation::Reg(r) if self.block_state.regs.num_usages(r) <= 1 => (left, right), + _ => (right, left) + }; + + let left = self.into_temp_reg(GPRType::Rx, left); + let right = self.into_reg(GPRType::Rx, right); + let out = self.block_state.regs.take(I32); + + dynasm!(self.asm + ; $instr Rx(left.rx().unwrap()), Rx(right.rx().unwrap()) + ; movd Rd(out.rq().unwrap()), Rx(left.rx().unwrap()) + ; and Rd(out.rq().unwrap()), 1 + ); + + self.push(ValueLocation::Reg(out)); + self.free_value(ValueLocation::Reg(left)); + self.free_value(ValueLocation::Reg(right)); + } + + } +} + macro_rules! cmp_f64 { ($name:ident, $reverse_name:ident, $instr:ident, $const_fallback:expr) => { cmp_float!( @@ -1855,9 +1897,33 @@ impl<'module, M: ModuleContext> Context<'module, M> { cmp_f32!(f32_gt, f32_lt, seta, |a, b| a > b); cmp_f32!(f32_ge, f32_le, setnc, |a, b| a >= b); + eq_float!( + f32_eq, + cmpeqss, + as_f32, + |a: wasmparser::Ieee32, b: wasmparser::Ieee32| f32::from_bits(a.0) == f32::from_bits(b.0) + ); + eq_float!( + f32_ne, + cmpneqss, + as_f32, + |a: wasmparser::Ieee32, b: wasmparser::Ieee32| f32::from_bits(a.0) != f32::from_bits(b.0) + ); cmp_f64!(f64_gt, f64_lt, seta, |a, b| a > b); cmp_f64!(f64_ge, f64_le, setnc, |a, b| a >= b); + eq_float!( + f64_eq, + cmpeqsd, + as_f64, + |a: wasmparser::Ieee64, b: wasmparser::Ieee64| f64::from_bits(a.0) == f64::from_bits(b.0) + ); + eq_float!( + f64_ne, + cmpneqsd, + as_f64, + |a: wasmparser::Ieee64, b: wasmparser::Ieee64| f64::from_bits(a.0) != f64::from_bits(b.0) + ); // TODO: Should we do this logic in `eq` and just have this delegate to `eq`? // That would mean that `eqz` and `eq` with a const 0 argument don't diff --git a/src/function_body.rs b/src/function_body.rs index 78088c5692..4608fabbea 100644 --- a/src/function_body.rs +++ b/src/function_body.rs @@ -459,6 +459,8 @@ where Operator::Div(SF32) => ctx.f32_div(), Operator::Neg(Size::_32) => ctx.f32_neg(), Operator::Abs(Size::_32) => ctx.f32_abs(), + Operator::Eq(F32) => ctx.f32_eq(), + Operator::Ne(F32) => ctx.f32_ne(), Operator::Gt(SF32) => ctx.f32_gt(), Operator::Ge(SF32) => ctx.f32_ge(), Operator::Lt(SF32) => ctx.f32_lt(), @@ -469,6 +471,8 @@ where Operator::Div(SF64) => ctx.f64_div(), Operator::Neg(Size::_64) => ctx.f64_neg(), Operator::Abs(Size::_64) => ctx.f64_abs(), + Operator::Eq(F64) => ctx.f64_eq(), + Operator::Ne(F64) => ctx.f64_ne(), Operator::Gt(SF64) => ctx.f64_gt(), Operator::Ge(SF64) => ctx.f64_ge(), Operator::Lt(SF64) => ctx.f64_lt(),