diff --git a/README.md b/README.md index a393542e62..ed244f075b 100644 --- a/README.md +++ b/README.md @@ -180,71 +180,71 @@ test spec_testsuite::comments ... ok test spec_testsuite::const_ ... ok test spec_testsuite::call ... ok test spec_testsuite::custom ... ok -test spec_testsuite::conversions ... FAILED test spec_testsuite::custom_section ... ok test spec_testsuite::data ... ok -test spec_testsuite::br_table ... FAILED test spec_testsuite::elem ... ok +test spec_testsuite::br_table ... FAILED +test spec_testsuite::conversions ... ok test spec_testsuite::call_indirect ... ok test spec_testsuite::exports ... ok test spec_testsuite::endianness ... ok test spec_testsuite::f32_bitwise ... ok test spec_testsuite::f64_bitwise ... ok +test spec_testsuite::f32 ... ok test spec_testsuite::f32_cmp ... ok test spec_testsuite::fac ... ok test spec_testsuite::f64 ... ok -test spec_testsuite::f32 ... ok -test spec_testsuite::float_memory ... ok test spec_testsuite::f64_cmp ... ok +test spec_testsuite::float_memory ... ok test spec_testsuite::forward ... ok +test spec_testsuite::float_literals ... ok test spec_testsuite::float_misc ... ok test spec_testsuite::func_ptrs ... ok -test spec_testsuite::float_literals ... ok -test spec_testsuite::get_local ... FAILED +test spec_testsuite::get_local ... ok test spec_testsuite::func ... ok -test spec_testsuite::float_exprs ... FAILED test spec_testsuite::globals ... ok test spec_testsuite::i32 ... ok -test spec_testsuite::inline_module ... ok -test spec_testsuite::if_ ... ok test spec_testsuite::i64 ... ok +test spec_testsuite::inline_module ... ok test spec_testsuite::imports ... ok -test spec_testsuite::labels ... ok +test spec_testsuite::if_ ... ok test spec_testsuite::int_literals ... ok +test spec_testsuite::labels ... ok test spec_testsuite::linking ... ok test spec_testsuite::int_exprs ... ok test spec_testsuite::loop_ ... ok -test spec_testsuite::memory_redundancy ... ok test spec_testsuite::left_to_right ... ok +test spec_testsuite::memory_redundancy ... ok test spec_testsuite::memory ... ok +test spec_testsuite::memory_grow ... ok test spec_testsuite::memory_trap ... ok test spec_testsuite::resizing ... ok -test spec_testsuite::memory_grow ... ok +test spec_testsuite::float_exprs ... ok test spec_testsuite::return_minimal ... ok -test spec_testsuite::select ... ok test spec_testsuite::return_ ... ok -test spec_testsuite::set_local ... FAILED -test spec_testsuite::skip_stack_guard_page ... FAILED +test spec_testsuite::select ... ok +test spec_testsuite::set_local ... ok test spec_testsuite::nop ... ok -test spec_testsuite::start ... ok +test spec_testsuite::skip_stack_guard_page ... FAILED test spec_testsuite::store_retval ... ok test spec_testsuite::stack ... ok +test spec_testsuite::start ... ok test spec_testsuite::token ... ok test spec_testsuite::switch ... ok test spec_testsuite::type_ ... ok -test spec_testsuite::traps ... FAILED test spec_testsuite::typecheck ... ok +test spec_testsuite::traps ... 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::tee_local ... ok test spec_testsuite::utf8_invalid_encoding ... ok -test spec_testsuite::tee_local ... FAILED test spec_testsuite::unreachable ... ok test spec_testsuite::names ... ok -test result: FAILED. 65 passed; 9 failed; 0 ignored; 0 measured; 0 filtered out +test result: FAILED. 71 passed; 3 failed; 0 ignored; 0 measured; 3 filtered out ``` ## Getting involved diff --git a/src/backend.rs b/src/backend.rs index 46dc8d7ed4..b1a2b53f9a 100644 --- a/src/backend.rs +++ b/src/backend.rs @@ -2162,12 +2162,15 @@ impl<'this, M: ModuleContext> Context<'this, M> { .map(|c| *c) .unwrap_or_else(|| self.ret_label()); - pass_args(self); - let predicate = self.into_reg(I32, val); dynasm!(self.asm ; test Rd(predicate.rq().unwrap()), Rd(predicate.rq().unwrap()) + ); + + pass_args(self); + + dynasm!(self.asm ; jz =>label.0 ); @@ -2188,12 +2191,15 @@ impl<'this, M: ModuleContext> Context<'this, M> { .map(|c| *c) .unwrap_or_else(|| self.ret_label()); - pass_args(self); - let predicate = self.into_reg(I32, val); dynasm!(self.asm ; test Rd(predicate.rq().unwrap()), Rd(predicate.rq().unwrap()) + ); + + pass_args(self); + + dynasm!(self.asm ; jnz =>label.0 ); @@ -2344,7 +2350,7 @@ impl<'this, M: ModuleContext> Context<'this, M> { self.pop_into(dst.into()); } - self.set_stack_depth(cc.stack_depth); + self.set_stack_depth_preserve_flags(cc.stack_depth); } /// Puts all stack values into "real" locations so that they can i.e. be set to different @@ -2452,31 +2458,27 @@ impl<'this, M: ModuleContext> Context<'this, M> { } fn immediate_to_reg(&mut self, reg: GPR, val: Value) { - if val.as_bytes() == 0 { - self.zero_reg(reg); - } else { - match reg { - GPR::Rq(r) => { - let val = val.as_bytes(); - if (val as u64) <= u32::max_value() as u64 { - dynasm!(self.asm - ; mov Rd(r), val as i32 - ); - } else { - dynasm!(self.asm - ; mov Rq(r), QWORD val - ); - } - } - GPR::Rx(r) => { - let temp = self.block_state.regs.take(I64); - self.immediate_to_reg(temp, val); + match reg { + GPR::Rq(r) => { + let val = val.as_bytes(); + if (val as u64) <= u32::max_value() as u64 { dynasm!(self.asm - ; movq Rx(r), Rq(temp.rq().unwrap()) + ; mov Rd(r), val as i32 + ); + } else { + dynasm!(self.asm + ; mov Rq(r), QWORD val ); - self.block_state.regs.release(temp); } } + GPR::Rx(r) => { + let temp = self.block_state.regs.take(I64); + self.immediate_to_reg(temp, val); + dynasm!(self.asm + ; movq Rx(r), Rq(temp.rq().unwrap()) + ); + self.block_state.regs.release(temp); + } } } @@ -3068,18 +3070,18 @@ impl<'this, M: ModuleContext> Context<'this, M> { let sign_mask = self.aligned_label(4, LabelValue::I32(SIGN_MASK_F32 as i32)); let float_cmp_mask = self.aligned_label(16, LabelValue::I32(0xcf000000u32 as i32)); let zero = self.aligned_label(16, LabelValue::I32(0)); - let trap_mask = self.trap_label(); + let trap_label = self.trap_label(); dynasm!(self.asm ; cvttss2si Rd(temp.rq().unwrap()), Rx(reg.rx().unwrap()) ; cmp Rd(temp.rq().unwrap()), [=>sign_mask.0] ; jne >ret ; ucomiss Rx(reg.rx().unwrap()), Rx(reg.rx().unwrap()) - ; jp =>trap_mask.0 + ; jp =>trap_label.0 ; ucomiss Rx(reg.rx().unwrap()), [=>float_cmp_mask.0] - ; jnae =>trap_mask.0 + ; jnae =>trap_label.0 ; ucomiss Rx(reg.rx().unwrap()), [=>zero.0] - ; jnb =>trap_mask.0 + ; jnb =>trap_label.0 ; ret: ); @@ -3106,21 +3108,21 @@ impl<'this, M: ModuleContext> Context<'this, M> { let sign_mask = self.aligned_label(4, LabelValue::I32(SIGN_MASK_F32 as i32)); let float_cmp_mask = self.aligned_label(16, LabelValue::I32(0x4f000000u32 as i32)); let zero = self.aligned_label(16, LabelValue::I32(0)); - let trap_mask = self.trap_label(); + let trap_label = self.trap_label(); dynasm!(self.asm ; ucomiss Rx(reg.rx().unwrap()), [=>float_cmp_mask.0] ; jae >else_ - ; jp =>trap_mask.0 + ; jp =>trap_label.0 ; cvttss2si Rd(temp.rq().unwrap()), Rx(reg.rx().unwrap()) - ; cmp Rd(temp.rq().unwrap()), 0 - ; jnge =>trap_mask.0 + ; test Rd(temp.rq().unwrap()), Rd(temp.rq().unwrap()) + ; js =>trap_label.0 ; jmp >ret ; else_: ; subss Rx(reg.rx().unwrap()), [=>float_cmp_mask.0] ; cvttss2si Rd(temp.rq().unwrap()), Rx(reg.rx().unwrap()) - ; cmp Rd(temp.rq().unwrap()), 0 - ; jnge =>trap_mask.0 + ; test Rd(temp.rq().unwrap()), Rd(temp.rq().unwrap()) + ; js =>trap_label.0 ; add Rq(temp.rq().unwrap()), [=>sign_mask.0] ; ret: ); @@ -3147,20 +3149,21 @@ impl<'this, M: ModuleContext> Context<'this, M> { val = ValueLocation::Reg(reg); let sign_mask = self.aligned_label(4, LabelValue::I32(SIGN_MASK_F32 as i32)); - let float_cmp_mask = self.aligned_label(16, LabelValue::I64(0xc1e0000000200000u64 as i64)); + let float_cmp_mask = + self.aligned_label(16, LabelValue::I64(0xc1e0000000200000u64 as i64)); let zero = self.aligned_label(16, LabelValue::I64(0)); - let trap_mask = self.trap_label(); + let trap_label = self.trap_label(); dynasm!(self.asm ; cvttsd2si Rd(temp.rq().unwrap()), Rx(reg.rx().unwrap()) ; cmp Rd(temp.rq().unwrap()), [=>sign_mask.0] ; jne >ret ; ucomisd Rx(reg.rx().unwrap()), Rx(reg.rx().unwrap()) - ; jp =>trap_mask.0 + ; jp =>trap_label.0 ; ucomisd Rx(reg.rx().unwrap()), [=>float_cmp_mask.0] - ; jna =>trap_mask.0 + ; jna =>trap_label.0 ; ucomisd Rx(reg.rx().unwrap()), [=>zero.0] - ; jnb =>trap_mask.0 + ; jnb =>trap_label.0 ; ret: ); @@ -3186,23 +3189,24 @@ impl<'this, M: ModuleContext> Context<'this, M> { let temp = self.block_state.regs.take(I32); let sign_mask = self.aligned_label(4, LabelValue::I32(SIGN_MASK_F32 as i32)); - let float_cmp_mask = self.aligned_label(16, LabelValue::I64(0x41e0000000000000u64 as i64)); + let float_cmp_mask = + self.aligned_label(16, LabelValue::I64(0x41e0000000000000u64 as i64)); let zero = self.aligned_label(16, LabelValue::I64(0)); - let trap_mask = self.trap_label(); + let trap_label = self.trap_label(); dynasm!(self.asm ; ucomisd Rx(reg.rx().unwrap()), [=>float_cmp_mask.0] ; jae >else_ - ; jp =>trap_mask.0 + ; jp =>trap_label.0 ; cvttsd2si Rd(temp.rq().unwrap()), Rx(reg.rx().unwrap()) - ; cmp Rd(temp.rq().unwrap()), 0 - ; jnge =>trap_mask.0 + ; test Rd(temp.rq().unwrap()), Rd(temp.rq().unwrap()) + ; js =>trap_label.0 ; jmp >ret ; else_: ; subsd Rx(reg.rx().unwrap()), [=>float_cmp_mask.0] ; cvttsd2si Rd(temp.rq().unwrap()), Rx(reg.rx().unwrap()) - ; cmp Rd(temp.rq().unwrap()), 0 - ; jnge =>trap_mask.0 + ; test Rd(temp.rq().unwrap()), Rd(temp.rq().unwrap()) + ; js =>trap_label.0 ; add Rq(temp.rq().unwrap()), [=>sign_mask.0] ; ret: ); @@ -3265,30 +3269,84 @@ impl<'this, M: ModuleContext> Context<'this, M> { |a| wasmparser::Ieee64((a as f64).to_bits()) ); - conversion!( - i64_truncate_f32_s, - cvttss2si, - Rx, - rx, - Rq, - rq, - f32, - i64, - as_f32, - |a: wasmparser::Ieee32| f32::from_bits(a.bits()) as i64 - ); - conversion!( - i64_truncate_f64_s, - cvttsd2si, - Rx, - rx, - Rq, - rq, - f64, - i64, - as_f64, - |a: wasmparser::Ieee64| f64::from_bits(a.bits()) as i64 - ); + pub fn i64_truncate_f32_s(&mut self) { + let mut val = self.pop(); + + let out_val = match val { + ValueLocation::Immediate(imm) => ValueLocation::Immediate( + (f32::from_bits(imm.as_f32().unwrap().bits()) as i32).into(), + ), + other => { + let reg = self.into_temp_reg(F32, other); + val = ValueLocation::Reg(reg); + let temp = self.block_state.regs.take(I32); + + let sign_mask = self.aligned_label(16, LabelValue::I64(SIGN_MASK_F64 as i64)); + let float_cmp_mask = self.aligned_label(16, LabelValue::I32(0xdf000000u32 as i32)); + let zero = self.aligned_label(16, LabelValue::I64(0)); + let trap_label = self.trap_label(); + + dynasm!(self.asm + ; cvttss2si Rq(temp.rq().unwrap()), Rx(reg.rx().unwrap()) + ; cmp Rq(temp.rq().unwrap()), [=>sign_mask.0] + ; jne >ret + ; ucomiss Rx(reg.rx().unwrap()), Rx(reg.rx().unwrap()) + ; jp =>trap_label.0 + ; ucomiss Rx(reg.rx().unwrap()), [=>float_cmp_mask.0] + ; jnae =>trap_label.0 + ; ucomiss Rx(reg.rx().unwrap()), [=>zero.0] + ; jnb =>trap_label.0 + ; ret: + ); + + ValueLocation::Reg(temp) + } + }; + + self.free_value(val); + + self.push(out_val); + } + + pub fn i64_truncate_f64_s(&mut self) { + let mut val = self.pop(); + + let out_val = match val { + ValueLocation::Immediate(imm) => ValueLocation::Immediate( + (f64::from_bits(imm.as_f64().unwrap().bits()) as i32).into(), + ), + other => { + let reg = self.into_reg(F32, other); + let temp = self.block_state.regs.take(I32); + val = ValueLocation::Reg(reg); + + let sign_mask = self.aligned_label(8, LabelValue::I64(SIGN_MASK_F64 as i64)); + let float_cmp_mask = + self.aligned_label(16, LabelValue::I64(0xc3e0000000000000u64 as i64)); + let zero = self.aligned_label(16, LabelValue::I64(0)); + let trap_label = self.trap_label(); + + dynasm!(self.asm + ; cvttsd2si Rq(temp.rq().unwrap()), Rx(reg.rx().unwrap()) + ; cmp Rq(temp.rq().unwrap()), [=>sign_mask.0] + ; jne >ret + ; ucomisd Rx(reg.rx().unwrap()), Rx(reg.rx().unwrap()) + ; jp =>trap_label.0 + ; ucomisd Rx(reg.rx().unwrap()), [=>float_cmp_mask.0] + ; jnae =>trap_label.0 + ; ucomisd Rx(reg.rx().unwrap()), [=>zero.0] + ; jnb =>trap_label.0 + ; ret: + ); + + ValueLocation::Reg(temp) + } + }; + + self.free_value(val); + + self.push(out_val); + } pub fn i64_truncate_f32_u(&mut self) { struct Trunc; @@ -3304,17 +3362,24 @@ impl<'this, M: ModuleContext> Context<'this, M> { val = ValueLocation::Reg(reg); let temp = self.block_state.regs.take(I64); + let sign_mask = self.aligned_label(16, LabelValue::I64(SIGN_MASK_F64 as i64)); let u64_trunc_f32_const = self.aligned_label(16, LabelValue::I32(0x5F000000)); + let trap_label = self.trap_label(); dynasm!(self.asm ; comiss Rx(reg.rx().unwrap()), [=>u64_trunc_f32_const.0] - ; jnb >large + ; jae >large + ; jp =>trap_label.0 ; cvttss2si Rq(temp.rq().unwrap()), Rx(reg.rx().unwrap()) + ; test Rq(temp.rq().unwrap()), Rq(temp.rq().unwrap()) + ; js =>trap_label.0 ; jmp >cont ; large: ; subss Rx(reg.rx().unwrap()), [=>u64_trunc_f32_const.0] ; cvttss2si Rq(temp.rq().unwrap()), Rx(reg.rx().unwrap()) - ; btc Rq(temp.rq().unwrap()), 0b00111111 + ; test Rq(temp.rq().unwrap()), Rq(temp.rq().unwrap()) + ; js =>trap_label.0 + ; add Rq(temp.rq().unwrap()), [=>sign_mask.0] ; cont: ); @@ -3339,18 +3404,25 @@ impl<'this, M: ModuleContext> Context<'this, M> { val = ValueLocation::Reg(reg); let temp = self.block_state.regs.take(I64); + let sign_mask = self.aligned_label(16, LabelValue::I64(SIGN_MASK_F64 as i64)); let u64_trunc_f64_const = - self.aligned_label(16, LabelValue::I64(0x43E0000000000000)); + self.aligned_label(16, LabelValue::I64(0x43e0000000000000)); + let trap_label = self.trap_label(); dynasm!(self.asm ; comisd Rx(reg.rx().unwrap()), [=>u64_trunc_f64_const.0] ; jnb >large + ; jp =>trap_label.0 ; cvttsd2si Rq(temp.rq().unwrap()), Rx(reg.rx().unwrap()) - ; jmp >cont + ; cmp Rq(temp.rq().unwrap()), 0 + ; jge >cont + ; jmp =>trap_label.0 ; large: ; subsd Rx(reg.rx().unwrap()), [=>u64_trunc_f64_const.0] ; cvttsd2si Rq(temp.rq().unwrap()), Rx(reg.rx().unwrap()) - ; btc Rq(temp.rq().unwrap()), 0b00111111 + ; cmp Rq(temp.rq().unwrap()), 0 + ; jnge =>trap_label.0 + ; add Rq(temp.rq().unwrap()), [=>sign_mask.0] ; cont: ); @@ -3435,6 +3507,7 @@ impl<'this, M: ModuleContext> Context<'this, M> { ; test Rq(reg.rq().unwrap()), Rq(reg.rq().unwrap()) ; js >negative ; cvtsi2ss Rx(out.rx().unwrap()), Rq(reg.rq().unwrap()) + ; jmp >ret ; negative: ; mov Rq(temp.rq().unwrap()), Rq(reg.rq().unwrap()) ; shr Rq(temp.rq().unwrap()), 1 @@ -3442,6 +3515,7 @@ impl<'this, M: ModuleContext> Context<'this, M> { ; or Rq(reg.rq().unwrap()), Rq(temp.rq().unwrap()) ; cvtsi2ss Rx(out.rx().unwrap()), Rq(reg.rq().unwrap()) ; addss Rx(out.rx().unwrap()), Rx(out.rx().unwrap()) + ; ret: ); self.free_value(ValueLocation::Reg(temp)); @@ -3466,27 +3540,22 @@ impl<'this, M: ModuleContext> Context<'this, M> { let reg = self.into_reg(I64, val); val = ValueLocation::Reg(reg); - let out = self.block_state.regs.take(F64); - let temp = self.block_state.regs.take(F64); - - let conv_const_0 = self.aligned_label( - 16, - (LabelValue::I32(0x43300000), LabelValue::I32(0x43300000)), - ); - let conv_const_1 = self.aligned_label( - 16, - ( - LabelValue::I64(0x4330000000000000), - LabelValue::I64(0x4530000000000000), - ), - ); + let out = self.block_state.regs.take(F32); + let temp = self.block_state.regs.take(I64); dynasm!(self.asm - ; movq Rx(temp.rx().unwrap()), rdi - ; punpckldq Rx(temp.rx().unwrap()), [=>conv_const_0.0] - ; subpd Rx(temp.rx().unwrap()), [=>conv_const_1.0] - ; pshufd Rx(out.rx().unwrap()), Rx(temp.rx().unwrap()), 78 - ; addpd Rx(out.rx().unwrap()), Rx(temp.rx().unwrap()) + ; test Rq(reg.rq().unwrap()), Rq(reg.rq().unwrap()) + ; js >negative + ; cvtsi2sd Rx(out.rx().unwrap()), Rq(reg.rq().unwrap()) + ; jmp >ret + ; negative: + ; mov Rq(temp.rq().unwrap()), Rq(reg.rq().unwrap()) + ; shr Rq(temp.rq().unwrap()), 1 + ; and Rq(reg.rq().unwrap()), 1 + ; or Rq(reg.rq().unwrap()), Rq(temp.rq().unwrap()) + ; cvtsi2sd Rx(out.rx().unwrap()), Rq(reg.rq().unwrap()) + ; addsd Rx(out.rx().unwrap()), Rx(out.rx().unwrap()) + ; ret: ); self.free_value(ValueLocation::Reg(temp));