diff --git a/README.md b/README.md index 54d788c46a..f10ea8c018 100644 --- a/README.md +++ b/README.md @@ -169,84 +169,84 @@ It's hard to judge, since each test in the spec testsuite covers a wide range of ``` running 76 tests -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::block ... FAILED -test spec_testsuite::br_if ... FAILED -test spec_testsuite::break_drop ... ok -test spec_testsuite::call ... FAILED -test spec_testsuite::call_indirect ... FAILED -test spec_testsuite::comments ... ok -test spec_testsuite::address ... FAILED -test spec_testsuite::const_ ... ok -test spec_testsuite::custom ... ok -test spec_testsuite::custom_section ... ok -test spec_testsuite::data ... ok -test spec_testsuite::elem ... FAILED -test spec_testsuite::conversions ... FAILED -test spec_testsuite::endianness ... FAILED -test spec_testsuite::br ... 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::float_literals ... FAILED -test spec_testsuite::f64 ... FAILED -test spec_testsuite::float_misc ... FAILED -test spec_testsuite::forward ... ok -test spec_testsuite::f64_cmp ... FAILED -test spec_testsuite::func_ptrs ... FAILED -test spec_testsuite::get_local ... FAILED -test spec_testsuite::float_memory ... ok -test spec_testsuite::globals ... FAILED -test spec_testsuite::float_exprs ... FAILED -test spec_testsuite::i64 ... FAILED -test spec_testsuite::i32 ... FAILED -test spec_testsuite::imports ... FAILED -test spec_testsuite::inline_module ... ok -test spec_testsuite::if_ ... FAILED -test spec_testsuite::int_exprs ... FAILED -test spec_testsuite::labels ... ok -test spec_testsuite::left_to_right ... FAILED -test spec_testsuite::int_literals ... ok -test spec_testsuite::linking ... FAILED -test spec_testsuite::func ... FAILED -test spec_testsuite::memory_grow ... FAILED -test spec_testsuite::loop_ ... FAILED -test spec_testsuite::memory_redundancy ... ok -test spec_testsuite::memory ... FAILED -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::set_local ... FAILED -test spec_testsuite::select ... FAILED -test spec_testsuite::stack ... FAILED -test spec_testsuite::start ... FAILED -test spec_testsuite::store_retval ... ok -test spec_testsuite::skip_stack_guard_page ... FAILED -test spec_testsuite::switch ... ok -test spec_testsuite::token ... ok -test spec_testsuite::tee_local ... FAILED -test spec_testsuite::type_ ... ok -test spec_testsuite::traps ... FAILED -test spec_testsuite::typecheck ... ok -test spec_testsuite::unreached_invalid ... ok -test spec_testsuite::unwind ... FAILED +test misc_testsuite::stack_overflow ... ok +test spec_testsuite::binary ... ok +test misc_testsuite::misc_traps ... ok +test spec_testsuite::block ... FAILED +test spec_testsuite::align ... FAILED +test spec_testsuite::br_if ... FAILED +test spec_testsuite::break_drop ... ok +test spec_testsuite::call ... FAILED +test spec_testsuite::call_indirect ... FAILED +test spec_testsuite::comments ... ok +test spec_testsuite::address ... FAILED +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::elem ... FAILED +test spec_testsuite::endianness ... FAILED +test spec_testsuite::exports ... ok +test spec_testsuite::br ... 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::fac ... ok +test spec_testsuite::f32_cmp ... FAILED +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::globals ... FAILED +test spec_testsuite::float_exprs ... FAILED +test spec_testsuite::i64 ... FAILED +test spec_testsuite::if_ ... FAILED +test spec_testsuite::imports ... FAILED +test spec_testsuite::inline_module ... ok +test spec_testsuite::float_literals ... ok +test spec_testsuite::func ... FAILED +test spec_testsuite::int_exprs ... FAILED +test spec_testsuite::i32 ... ok +test spec_testsuite::linking ... FAILED +test spec_testsuite::left_to_right ... FAILED +test spec_testsuite::loop_ ... FAILED +test spec_testsuite::int_literals ... ok +test spec_testsuite::memory_grow ... FAILED +test spec_testsuite::memory_redundancy ... ok +test spec_testsuite::memory ... FAILED +test spec_testsuite::memory_trap ... FAILED +test spec_testsuite::labels ... ok +test spec_testsuite::resizing ... FAILED +test spec_testsuite::return_minimal ... ok +test spec_testsuite::nop ... FAILED +test spec_testsuite::set_local ... FAILED +test spec_testsuite::select ... FAILED +test spec_testsuite::stack ... FAILED +test spec_testsuite::start ... FAILED +test spec_testsuite::store_retval ... ok +test spec_testsuite::skip_stack_guard_page ... FAILED +test spec_testsuite::switch ... ok +test spec_testsuite::token ... ok +test spec_testsuite::tee_local ... FAILED +test spec_testsuite::type_ ... ok +test spec_testsuite::traps ... FAILED +test spec_testsuite::typecheck ... 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::return_ ... ok -test spec_testsuite::unreachable ... ok -test spec_testsuite::names ... FAILED +test spec_testsuite::utf8_import_field ... ok +test spec_testsuite::return_ ... 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. 31 passed; 45 failed; 0 ignored; 0 measured; 0 filtered out +test result: FAILED. 33 passed; 43 failed; 0 ignored; 0 measured; 0 filtered out ``` All the failed tests apart from `address` and `unwind` (whose failure hasn't been investigated yet) are due to features that have yet to be implemented. diff --git a/src/backend.rs b/src/backend.rs index a26d738fd9..3481a7d780 100644 --- a/src/backend.rs +++ b/src/backend.rs @@ -690,6 +690,55 @@ macro_rules! unop { } }; + self.free_value(val); + self.push(out_val); + } + } +} + +macro_rules! conversion { + ( + $name:ident, + $instr:ident, + $in_reg_ty:ident, + $in_reg_fn:ident, + $out_reg_ty:ident, + $out_reg_fn:ident, + $in_typ:ty, + $out_typ:ty, + $const_ty_fn:ident, + $const_fallback:expr + ) => { + pub fn $name(&mut self) { + let mut val = self.pop(); + + let out_val = match val { + ValueLocation::Immediate(imm) => + ValueLocation::Immediate( + ($const_fallback(imm.$const_ty_fn().unwrap()) as $out_typ).into() + ), + ValueLocation::Stack(offset) => { + let offset = self.adjusted_offset(offset); + let temp = self.block_state.regs.take(Type::for_::<$out_typ>()); + dynasm!(self.asm + ; $instr $out_reg_ty(temp.rq().unwrap()), [rsp + offset] + ); + ValueLocation::Reg(temp) + } + ValueLocation::Reg(_) => { + let reg = self.into_reg(Type::for_::<$in_typ>(), val); + let temp = self.block_state.regs.take(Type::for_::<$out_typ>()); + val = ValueLocation::Reg(reg); + + dynasm!(self.asm + ; $instr $out_reg_ty(temp.$out_reg_fn().unwrap()), $in_reg_ty(reg.$in_reg_fn().unwrap()) + ); + ValueLocation::Reg(temp) + } + }; + + self.free_value(val); + self.push(out_val); } } @@ -1624,9 +1673,17 @@ impl<'module, M: ModuleContext> Context<'module, M> { /// Pops i32 predicate and branches to the specified label /// if the predicate is equal to zero. - pub fn br_if_false(&mut self, target: impl Into>, pass_args: impl FnOnce(&mut Self)) { + pub fn br_if_false( + &mut self, + target: impl Into>, + pass_args: impl FnOnce(&mut Self), + ) { let val = self.pop(); - let label = target.into().label().map(|c| *c).unwrap_or_else(|| self.ret_label()); + let label = target + .into() + .label() + .map(|c| *c) + .unwrap_or_else(|| self.ret_label()); pass_args(self); @@ -1642,9 +1699,17 @@ impl<'module, M: ModuleContext> Context<'module, M> { /// Pops i32 predicate and branches to the specified label /// if the predicate is not equal to zero. - pub fn br_if_true(&mut self, target: impl Into>, pass_args: impl FnOnce(&mut Self)) { + pub fn br_if_true( + &mut self, + target: impl Into>, + pass_args: impl FnOnce(&mut Self), + ) { let val = self.pop(); - let label = target.into().label().map(|c| *c).unwrap_or_else(|| self.ret_label()); + let label = target + .into() + .label() + .map(|c| *c) + .unwrap_or_else(|| self.ret_label()); pass_args(self); @@ -1685,18 +1750,7 @@ impl<'module, M: ModuleContext> Context<'module, M> { pass_args(self); - if count == 0 { - if let Some(default) = default { - match default { - BrTarget::Label(label) => self.br(label), - BrTarget::Return => { - dynasm!(self.asm - ; ret - ); - } - } - } - } else if let Some(imm) = selector.imm_i32() { + if let Some(imm) = selector.imm_i32() { if let Some(target) = targets.nth(imm as _).or(default) { match target { BrTarget::Label(label) => self.br(label), @@ -1708,16 +1762,33 @@ impl<'module, M: ModuleContext> Context<'module, M> { } } } else { - let selector_reg = self.into_reg(GPRType::Rq, selector); - selector = ValueLocation::Reg(selector_reg); + if count > 0 { + let selector_reg = self.into_reg(GPRType::Rq, selector); + selector = ValueLocation::Reg(selector_reg); - // TODO: Jump table (wrestling with dynasm to implement it is too much work) - for (i, target) in targets.enumerate() { - let label = self.target_to_label(target); + let tmp = self.block_state.regs.take(I64); + + self.immediate_to_reg(tmp, (count as u32).into()); dynasm!(self.asm - ; cmp Rq(selector_reg.rq().unwrap()), i as i32 - ; je =>label.0 + ; cmp Rq(selector_reg.rq().unwrap()), Rq(tmp.rq().unwrap()) + ; cmova Rq(selector_reg.rq().unwrap()), Rq(tmp.rq().unwrap()) + ; lea Rq(tmp.rq().unwrap()), [>start_label] + ; lea Rq(selector_reg.rq().unwrap()), [ + Rq(selector_reg.rq().unwrap()) * 5 + ] + ; add Rq(selector_reg.rq().unwrap()), Rq(tmp.rq().unwrap()) + ; jmp Rq(selector_reg.rq().unwrap()) + ; start_label: ); + + self.block_state.regs.release(tmp); + + for (i, target) in targets.enumerate() { + let label = self.target_to_label(target); + dynasm!(self.asm + ; jmp =>label.0 + ); + } } if let Some(def) = default { @@ -2251,6 +2322,18 @@ impl<'module, M: ModuleContext> Context<'module, M> { } unop!(i32_popcnt, popcnt, Rd, u32, u32::count_ones); + conversion!( + i32_truncate_f32, + cvttss2si, + Rx, + rx, + Rd, + rq, + f32, + i32, + as_f32, + |a: wasmparser::Ieee32| a.bits() + ); unop!(i64_popcnt, popcnt, Rq, u64, |a: u64| a.count_ones() as u64); // TODO: Use `lea` when the LHS operand isn't a temporary but both of the operands @@ -2270,10 +2353,12 @@ impl<'module, M: ModuleContext> Context<'module, M> { commutative_binop_f32!(f32_add, addss, |a, b| a + b); commutative_binop_f32!(f32_mul, mulss, |a, b| a * b); binop_f32!(f32_sub, subss, |a, b| a - b); + binop_f32!(f32_div, divss, |a, b| a / b); commutative_binop_f64!(f64_add, addsd, |a, b| a + b); commutative_binop_f64!(f64_mul, mulsd, |a, b| a * b); binop_f64!(f64_sub, subsd, |a, b| a - b); + binop_f64!(f64_div, divsd, |a, b| a / b); shift!( i32_shl, @@ -2358,27 +2443,30 @@ impl<'module, M: ModuleContext> Context<'module, M> { ) -> ( ValueLocation, ValueLocation, - impl Iterator + Clone + 'module, + impl Iterator + Clone, ) { - let divisor = if ValueLocation::Reg(RAX) == divisor { + self.block_state.regs.mark_used(RAX); + self.block_state.regs.mark_used(RDX); + let divisor = if divisor == ValueLocation::Reg(RAX) || divisor == ValueLocation::Reg(RDX) { let new_reg = self.block_state.regs.take(I32); self.copy_value(&divisor, &mut ValueLocation::Reg(new_reg)); - self.block_state.regs.release(RAX); + self.free_value(divisor); ValueLocation::Reg(new_reg) } else if let ValueLocation::Stack(_) = divisor { divisor } else { - ValueLocation::Reg(self.into_temp_reg(I32, divisor)) + ValueLocation::Reg(self.into_reg(I32, divisor)) }; - - self.free_value(quotient); - let should_save_rax = !self.block_state.regs.is_free(RAX); - let should_save_rdx = !self.block_state.regs.is_free(RDX); + self.block_state.regs.release(RDX); + self.block_state.regs.release(RAX); if let ValueLocation::Reg(r) = quotient { self.block_state.regs.mark_used(r); } + let should_save_rax = + quotient != ValueLocation::Reg(RAX) && !self.block_state.regs.is_free(RAX); + let saved_rax = if should_save_rax { let new_reg = self.block_state.regs.take(I32); dynasm!(self.asm @@ -2389,6 +2477,12 @@ impl<'module, M: ModuleContext> Context<'module, M> { None }; + self.block_state.regs.mark_used(RAX); + self.copy_value("ient, &mut ValueLocation::Reg(RAX)); + self.free_value(quotient); + + let should_save_rdx = !self.block_state.regs.is_free(RDX); + let saved_rdx = if should_save_rdx { let new_reg = self.block_state.regs.take(I32); dynasm!(self.asm @@ -2399,16 +2493,14 @@ impl<'module, M: ModuleContext> Context<'module, M> { None }; - dynasm!(self.asm - ; cdq - ); - do_div(self, divisor); - self.block_state.regs.mark_used(RAX); + + self.free_value(divisor); + self.block_state.regs.mark_used(RDX); ( - divisor, ValueLocation::Reg(RAX), + ValueLocation::Reg(RDX), saved_rax .map(|s| (s, RAX)) .into_iter() @@ -2429,12 +2521,14 @@ impl<'module, M: ModuleContext> Context<'module, M> { ValueLocation::Stack(offset) => { let offset = this.adjusted_offset(offset); dynasm!(this.asm + ; xor edx, edx ; div [rsp + offset] ); } ValueLocation::Reg(r) => { dynasm!(this.asm - ; div Rq(r.rq().unwrap()) + ; xor edx, edx + ; div Rd(r.rq().unwrap()) ); } ValueLocation::Immediate(_) => unreachable!(), @@ -2454,12 +2548,14 @@ impl<'module, M: ModuleContext> Context<'module, M> { ValueLocation::Stack(offset) => { let offset = this.adjusted_offset(offset); dynasm!(this.asm + ; cdq ; idiv [rsp + offset] ); } ValueLocation::Reg(r) => { dynasm!(this.asm - ; idiv Rq(r.rq().unwrap()) + ; cdq + ; idiv Rd(r.rq().unwrap()) ); } ValueLocation::Immediate(_) => unreachable!(), @@ -2496,6 +2592,59 @@ impl<'module, M: ModuleContext> Context<'module, M> { let (div, rem, saved) = self.i32_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.block_state.regs.take(I32); + dynasm!(self.asm + ; mov Rq(new.rq().unwrap()), Rq(div.rq().unwrap()) + ); + self.block_state.regs.release(div); + ValueLocation::Reg(new) + } + _ => div, + }; + + self.cleanup_gprs(saved); + + self.push(div); + } + + // TODO: Fast div using mul for constant divisor? It looks like LLVM doesn't do that for us when + // emitting Wasm. + pub fn i32_div_s(&mut self) { + let divisor = self.pop(); + let quotient = self.pop(); + + if let (Some(quotient), Some(divisor)) = (quotient.imm_i32(), divisor.imm_i32()) { + if divisor == 0 { + self.trap(); + self.push(ValueLocation::Immediate(0u32.into())); + } else { + self.push(ValueLocation::Immediate( + i32::wrapping_div(quotient, divisor).into(), + )); + } + + return; + } + + let (div, rem, saved) = self.i32_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.block_state.regs.take(I32); + dynasm!(self.asm + ; mov Rq(new.rq().unwrap()), Rq(div.rq().unwrap()) + ); + self.block_state.regs.release(div); + ValueLocation::Reg(new) + } + _ => div, + }; + self.cleanup_gprs(saved); self.push(div); @@ -2521,19 +2670,21 @@ impl<'module, M: ModuleContext> Context<'module, M> { self.free_value(div); - let rem = if saved.clone().any(|(_, dst)| dst == RAX) { - let new = self.block_state.regs.take(I32); - dynasm!(self.asm - ; mov Rq(new.rq().unwrap()), rax - ); - new - } else { - RAX + let rem = match rem { + ValueLocation::Reg(rem) if saved.clone().any(|(_, dst)| dst == rem) => { + let new = self.block_state.regs.take(I32); + dynasm!(self.asm + ; mov Rq(new.rq().unwrap()), Rq(rem.rq().unwrap()) + ); + self.block_state.regs.release(rem); + ValueLocation::Reg(new) + } + _ => rem, }; self.cleanup_gprs(saved); - self.push(ValueLocation::Reg(rem)); + self.push(rem); } pub fn i32_rem_s(&mut self) { @@ -2554,46 +2705,21 @@ impl<'module, M: ModuleContext> Context<'module, M> { self.free_value(div); - let rem = if saved.clone().any(|(_, dst)| dst == RAX) { - let new = self.block_state.regs.take(I32); - dynasm!(self.asm - ; mov Rq(new.rq().unwrap()), rax - ); - new - } else { - RAX + let rem = match rem { + ValueLocation::Reg(rem) if saved.clone().any(|(_, dst)| dst == rem) => { + let new = self.block_state.regs.take(I32); + dynasm!(self.asm + ; mov Rq(new.rq().unwrap()), Rq(rem.rq().unwrap()) + ); + self.block_state.regs.release(rem); + ValueLocation::Reg(new) + } + _ => rem, }; self.cleanup_gprs(saved); - self.push(ValueLocation::Reg(rem)); - } - - // TODO: Fast div using mul for constant divisor? It looks like LLVM doesn't do that for us when - // emitting Wasm. - pub fn i32_div_s(&mut self) { - let divisor = self.pop(); - let quotient = self.pop(); - - if let (Some(quotient), Some(divisor)) = (quotient.imm_i32(), divisor.imm_i32()) { - if divisor == 0 { - self.trap(); - self.push(ValueLocation::Immediate(0u32.into())); - } else { - self.push(ValueLocation::Immediate( - i32::wrapping_div(quotient, divisor).into(), - )); - } - - return; - } - - let (div, rem, saved) = self.i32_full_div_s(divisor, quotient); - self.free_value(rem); - - self.cleanup_gprs(saved); - - self.push(div); + self.push(rem); } // `i32_mul` needs to be separate because the immediate form of the instruction @@ -3141,3 +3267,4 @@ impl<'module, M: ModuleContext> Context<'module, M> { label } } + diff --git a/src/function_body.rs b/src/function_body.rs index 6ae0efff42..da079aac69 100644 --- a/src/function_body.rs +++ b/src/function_body.rs @@ -288,7 +288,8 @@ where **then_cc = { let mut cc = cc.clone(); - if let (Some(cc), Some(to_drop)) = (cc.as_mut(), then.to_drop.clone()) + if let (Some(cc), Some(to_drop)) = + (cc.as_mut(), then.to_drop.clone()) { match cc { Left(cc) => drop_elements(&mut cc.arguments, to_drop), @@ -299,7 +300,8 @@ where }; **else_cc = { let mut cc = cc; - if let (Some(cc), Some(to_drop)) = (cc.as_mut(), else_.to_drop.clone()) + if let (Some(cc), Some(to_drop)) = + (cc.as_mut(), else_.to_drop.clone()) { match cc { Left(cc) => drop_elements(&mut cc.arguments, to_drop), @@ -357,8 +359,6 @@ where if let Some(max) = max_num_callers { max_num_callers = block.num_callers.map(|n| max.max(n)); - } else { - max_num_callers = block.num_callers; } } @@ -387,8 +387,8 @@ where } }); } - Operator::Swap { depth } => ctx.swap(depth), - Operator::Pick { depth } => ctx.pick(depth), + Operator::Swap(depth) => ctx.swap(depth), + Operator::Pick(depth) => ctx.pick(depth), Operator::Eq(I32) => ctx.i32_eq(), Operator::Eqz(Size::_32) => ctx.i32_eqz(), Operator::Ne(I32) => ctx.i32_neq(), @@ -408,8 +408,8 @@ where Operator::Mul(I32) => ctx.i32_mul(), Operator::Div(SU32) => ctx.i32_div_u(), Operator::Div(SI32) => ctx.i32_div_s(), - Operator::Rem(sint::I32) => ctx.i32_rem_u(), - Operator::Rem(sint::U32) => ctx.i32_rem_s(), + Operator::Rem(sint::I32) => ctx.i32_rem_s(), + Operator::Rem(sint::U32) => ctx.i32_rem_u(), Operator::Shl(Size::_32) => ctx.i32_shl(), Operator::Shr(sint::I32) => ctx.i32_shr_s(), Operator::Shr(sint::U32) => ctx.i32_shr_u(), @@ -446,6 +446,7 @@ where Operator::Add(F32) => ctx.f32_add(), Operator::Mul(F32) => ctx.f32_mul(), Operator::Sub(F32) => ctx.f32_sub(), + Operator::Div(SF32) => ctx.f32_div(), Operator::Neg(Size::_32) => ctx.f32_neg(), Operator::Gt(SF32) => ctx.f32_gt(), Operator::Ge(SF32) => ctx.f32_ge(), @@ -454,6 +455,7 @@ where Operator::Add(F64) => ctx.f64_add(), Operator::Mul(F64) => ctx.f64_mul(), Operator::Sub(F64) => ctx.f64_sub(), + Operator::Div(SF64) => ctx.f64_div(), Operator::Neg(Size::_64) => ctx.f64_neg(), Operator::Gt(SF64) => ctx.f64_gt(), Operator::Ge(SF64) => ctx.f64_ge(), @@ -462,6 +464,17 @@ where Operator::Drop(range) => ctx.drop(range), Operator::Const(val) => ctx.const_(val), Operator::I32WrapFromI64 => {} + // All reinterpret operators are no-ops - we do the conversion at the point of usage. + Operator::I32ReinterpretFromF32 => {} + Operator::I64ReinterpretFromF64 => {} + Operator::F32ReinterpretFromI32 => {} + Operator::F64ReinterpretFromI64 => {} + Operator::ITruncFromF { + input_ty: Size::_32, + output_ty: SignfulInt(_, Size::_32), + } => { + ctx.i32_truncate_f32(); + } Operator::Extend { sign: Signedness::Unsigned, } => ctx.i32_extend_u(), diff --git a/src/lib.rs b/src/lib.rs index 42bbd88424..5aa05e30fe 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -5,7 +5,8 @@ never_type, alloc_layout_extra, try_from, - try_trait + try_trait, + bind_by_move_pattern_guards )] #![plugin(dynasm)] diff --git a/src/microwasm.rs b/src/microwasm.rs index af31a2c791..24e198af49 100644 --- a/src/microwasm.rs +++ b/src/microwasm.rs @@ -174,7 +174,7 @@ type Int = Size; type Float = Size; #[derive(Debug, Copy, Clone, PartialEq, Eq)] -pub struct SignfulInt(Signedness, Size); +pub struct SignfulInt(pub Signedness, pub Size); #[derive(Debug, Copy, Clone, PartialEq, Eq)] pub enum Type { @@ -461,16 +461,12 @@ pub enum Operator