From 745d9ae162df8eee3fe2fe047e0655eaf03625c5 Mon Sep 17 00:00:00 2001 From: Jef Date: Wed, 24 Apr 2019 12:32:17 +0200 Subject: [PATCH] Implement rem in backend - not every backend will act like x86 --- src/backend.rs | 102 ++++++++++++++++++++++++++++++++++++++--------- src/microwasm.rs | 77 ++--------------------------------- 2 files changed, 86 insertions(+), 93 deletions(-) diff --git a/src/backend.rs b/src/backend.rs index 49295be01c..016d96d384 100644 --- a/src/backend.rs +++ b/src/backend.rs @@ -371,6 +371,16 @@ pub enum CCLoc { Stack(i32), } +impl CCLoc { + fn try_from(other: ValueLocation) -> Option { + match other { + ValueLocation::Reg(reg) => Some(CCLoc::Reg(reg)), + ValueLocation::Stack(offset) => Some(CCLoc::Stack(offset)), + _ => None, + } + } +} + #[derive(Debug, Copy, Clone, PartialEq, Eq)] pub enum CondCode { CF0, @@ -670,27 +680,27 @@ impl StackDepth { } macro_rules! int_div { - ($full_div_s:ident, $full_div_u:ident, $div_u:ident, $div_s:ident, $rem_u:ident, $rem_s:ident, $imm_fn:ident, $signed_ty:ty, $unsigned_ty:ty) => { + ($full_div_s:ident, $full_div_u:ident, $div_u:ident, $div_s:ident, $rem_u:ident, $rem_s:ident, $imm_fn:ident, $signed_ty:ty, $unsigned_ty:ty, $reg_ty:tt, $pointer_ty:tt) => { // TODO: Fast div using mul for constant divisor? It looks like LLVM doesn't do that for us when // emitting Wasm. pub fn $div_u(&mut self) { let divisor = self.pop(); - let quotient = self.pop(); + let dividend = self.pop(); - if let (Some(quotient), Some(divisor)) = (quotient.$imm_fn(), divisor.$imm_fn()) { + if let (Some(dividend), Some(divisor)) = (dividend.$imm_fn(), divisor.$imm_fn()) { if divisor == 0 { self.trap(); self.push(ValueLocation::Immediate((0 as $unsigned_ty).into())); } else { self.push(ValueLocation::Immediate( - <$unsigned_ty>::wrapping_div(quotient as _, divisor as _).into(), + <$unsigned_ty>::wrapping_div(dividend as _, divisor as _).into(), )); } return; } - let (div, rem, mut saved) = self.$full_div_u(divisor, quotient); + let (div, rem, mut saved) = self.$full_div_u(divisor, dividend); self.free_value(rem); @@ -719,22 +729,22 @@ macro_rules! int_div { // emitting Wasm. pub fn $div_s(&mut self) { let divisor = self.pop(); - let quotient = self.pop(); + let dividend = self.pop(); - if let (Some(quotient), Some(divisor)) = (quotient.$imm_fn(), divisor.$imm_fn()) { + if let (Some(dividend), Some(divisor)) = (dividend.$imm_fn(), divisor.$imm_fn()) { if divisor == 0 { self.trap(); self.push(ValueLocation::Immediate((0 as $signed_ty).into())); } else { self.push(ValueLocation::Immediate( - <$signed_ty>::wrapping_div(quotient, divisor).into(), + <$signed_ty>::wrapping_div(dividend, divisor).into(), )); } return; } - let (div, rem, mut saved) = self.$full_div_s(divisor, quotient); + let (div, rem, mut saved) = self.$full_div_s(divisor, dividend); self.free_value(rem); @@ -761,21 +771,21 @@ macro_rules! int_div { pub fn $rem_u(&mut self) { let divisor = self.pop(); - let quotient = self.pop(); + let dividend = self.pop(); - if let (Some(quotient), Some(divisor)) = (quotient.$imm_fn(), divisor.$imm_fn()) { + if let (Some(dividend), Some(divisor)) = (dividend.$imm_fn(), divisor.$imm_fn()) { if divisor == 0 { self.trap(); self.push(ValueLocation::Immediate((0 as $unsigned_ty).into())); } else { self.push(ValueLocation::Immediate( - (quotient as $unsigned_ty % divisor as $unsigned_ty).into(), + (dividend as $unsigned_ty % divisor as $unsigned_ty).into(), )); } return; } - let (div, rem, mut saved) = self.$full_div_u(divisor, quotient); + let (div, rem, mut saved) = self.$full_div_u(divisor, dividend); self.free_value(div); @@ -802,19 +812,54 @@ macro_rules! int_div { pub fn $rem_s(&mut self) { let divisor = self.pop(); - let quotient = self.pop(); + let dividend = self.pop(); - if let (Some(quotient), Some(divisor)) = (quotient.$imm_fn(), divisor.$imm_fn()) { + if let (Some(dividend), Some(divisor)) = (dividend.$imm_fn(), divisor.$imm_fn()) { if divisor == 0 { self.trap(); self.push(ValueLocation::Immediate((0 as $signed_ty).into())); } else { - self.push(ValueLocation::Immediate((quotient % divisor).into())); + self.push(ValueLocation::Immediate((dividend % divisor).into())); } return; } - let (div, rem, mut saved) = self.$full_div_s(divisor, quotient); + let is_neg1 = self.create_label(); + + let gen_neg1_case = match divisor { + ValueLocation::Immediate(_) => { + if divisor.$imm_fn().unwrap() == -1 { + self.push(ValueLocation::Immediate((-1 as $signed_ty).into())); + return; + } + + false + } + ValueLocation::Reg(_) => { + let reg = self.into_reg(GPRType::Rq, divisor).unwrap(); + dynasm!(self.asm + ; cmp $reg_ty(reg.rq().unwrap()), -1 + ; je =>is_neg1.0 + ); + + true + } + ValueLocation::Stack(offset) => { + let offset = self.adjusted_offset(offset); + dynasm!(self.asm + ; cmp $pointer_ty [rsp + offset], -1 + ; je =>is_neg1.0 + ); + + true + } + ValueLocation::Cond(_) => { + // `cc` can never be `-1`, only `0` and `1` + false + } + }; + + let (div, rem, mut saved) = self.$full_div_s(divisor, dividend); self.free_value(div); @@ -836,6 +881,21 @@ macro_rules! int_div { self.cleanup_gprs(saved); + if gen_neg1_case { + let ret = self.create_label(); + dynasm!(self.asm + ; jmp =>ret.0 + ); + self.define_label(is_neg1); + + self.copy_value( + ValueLocation::Immediate((0 as $signed_ty).into()), + CCLoc::try_from(rem).expect("Programmer error") + ); + + self.define_label(ret); + } + self.push(rem); } } @@ -4033,7 +4093,9 @@ impl<'this, M: ModuleContext> Context<'this, M> { i32_rem_s, imm_i32, i32, - u32 + u32, + Rd, + DWORD ); int_div!( i64_full_div_s, @@ -4044,7 +4106,9 @@ impl<'this, M: ModuleContext> Context<'this, M> { i64_rem_s, imm_i64, i64, - u64 + u64, + Rq, + QWORD ); /// Returned divisor is guaranteed not to be `RAX` diff --git a/src/microwasm.rs b/src/microwasm.rs index 7d077c8b52..550f853f7a 100644 --- a/src/microwasm.rs +++ b/src/microwasm.rs @@ -1946,44 +1946,8 @@ where // Unlike Wasm, our `rem_s` instruction _does_ trap on `-1`. Instead // of handling this complexity in the backend, we handle it here // (where it's way easier to debug). - WasmOperator::I32RemS => { - let id = self.next_id(); + WasmOperator::I32RemS => smallvec![Operator::Rem(sint::I32),], - let then = (id, NameTag::Header); - let else_ = (id, NameTag::Else); - let end = (id, NameTag::End); - - let mut end_params = self.block_params(); - - end_params.pop(); - end_params.pop(); - end_params.push(I32); - - smallvec![ - Operator::block(self.block_params(), then), - Operator::block(self.block_params(), else_), - Operator::end(end_params, end), - Operator::Pick(0), - Operator::Const((-1i32).into()), - Operator::Ne(I32), - Operator::BrIf { - then: BrTarget::Label(then).into(), - else_: BrTarget::Label(else_).into() - }, - Operator::Label(then), - Operator::Rem(sint::I32), - Operator::Br { - target: BrTarget::Label(end).into() - }, - Operator::Label(else_), - Operator::Drop(0..=1), - Operator::Const(0i32.into()), - Operator::Br { - target: BrTarget::Label(end).into() - }, - Operator::Label(end), - ] - } WasmOperator::I32RemU => smallvec![Operator::Rem(sint::U32),], WasmOperator::I32And => smallvec![Operator::And(Size::_32)], WasmOperator::I32Or => smallvec![Operator::Or(Size::_32)], @@ -2001,44 +1965,8 @@ where WasmOperator::I64Mul => smallvec![Operator::Mul(I64)], WasmOperator::I64DivS => smallvec![Operator::Div(SI64)], WasmOperator::I64DivU => smallvec![Operator::Div(SU64)], - WasmOperator::I64RemS => { - let id = self.next_id(); + WasmOperator::I64RemS => smallvec![Operator::Rem(sint::I64),], - let then = (id, NameTag::Header); - let else_ = (id, NameTag::Else); - let end = (id, NameTag::End); - - let mut end_params = self.block_params(); - - end_params.pop(); - end_params.pop(); - end_params.push(I64); - - smallvec![ - Operator::block(self.block_params(), then), - Operator::block(self.block_params(), else_), - Operator::end(end_params, end), - Operator::Pick(0), - Operator::Const((-1i64).into()), - Operator::Ne(I64), - Operator::BrIf { - then: BrTarget::Label(then).into(), - else_: BrTarget::Label(else_).into() - }, - Operator::Label(then), - Operator::Rem(sint::I64), - Operator::Br { - target: BrTarget::Label(end).into() - }, - Operator::Label(else_), - Operator::Drop(0..=1), - Operator::Const(0i64.into()), - Operator::Br { - target: BrTarget::Label(end).into() - }, - Operator::Label(end), - ] - } WasmOperator::I64RemU => smallvec![Operator::Rem(sint::U64)], WasmOperator::I64And => smallvec![Operator::And(Size::_64)], WasmOperator::I64Or => smallvec![Operator::Or(Size::_64)], @@ -2174,3 +2102,4 @@ where })) } } +