Repository: bytecodealliance/wasmtime
Pull request #5823 (2023-02-17 20:37:53)

winch: Add support for <i32|i64>.rem_* WebAssembly instructions 
This commit adds support for i32 and i64 remainder instructions for
x64.

This builds on top of: https://github.com/bytecodealliance/wasmtime/pull/5807; I'm marking it as draft until the base PR lands. 

<!--

Please ensure that the following steps are all taken care of before submitting
the PR.

- [ ] This has been discussed in issue #..., or if not, please tell us why
  here.
- [ ] A short description of what this does, why it is needed; if the
  description becomes long, the matter should probably be discussed in an issue
  first.
- [ ] This PR contains test cases, if meaningful.
- [ ] A reviewer from the core maintainer team has been assigned for this PR.
  If you don't know who could review this, please indicate so. The list of
  suggested reviewers on the right can help you.

Please ensure all communication adheres to the [code of
conduct](https://github.com/bytecodealliance/wasmtime/blob/master/CODE_OF_CONDUCT.md).
-->


github-actions[bot]: #### Subscribe to Label Action

cc @saulecabrera

<details>
This issue or pull request has been labeled: "winch"

Thus the following users have been cc'd because of the following labels:

* saulecabrera: winch

To subscribe or unsubscribe from this label, edit the <code>.github/subscribe-to-label.json</code> configuration file.

[Learn more.](https://github.com/bytecodealliance/subscribe-to-label-action)
</details>

Patch:
diff --git a/winch/codegen/src/isa/aarch64/masm.rs b/winch/codegen/src/isa/aarch64/masm.rs
index 89efe72cc..e44c6c471 100644
--- a/winch/codegen/src/isa/aarch64/masm.rs
+++ b/winch/codegen/src/isa/aarch64/masm.rs
@@ -7,7 +7,7 @@ use crate::{
     abi::local::LocalSlot,
     codegen::CodeGenContext,
     isa::reg::Reg,
-    masm::{DivKind, MacroAssembler as Masm, OperandSize, RegImm},
+    masm::{DivKind, MacroAssembler as Masm, OperandSize, RegImm, RemKind},
 };
 use cranelift_codegen::{settings, Final, MachBufferFinalized};
 
@@ -156,6 +156,10 @@ impl Masm for MacroAssembler {
         todo!()
     }
 
+    fn rem(&mut self, _context: &mut CodeGenContext, _kind: RemKind, _size: OperandSize) {
+        todo!()
+    }
+
     fn zero(&mut self, reg: Reg) {
         self.asm.load_constant(0, reg);
     }
diff --git a/winch/codegen/src/isa/x64/asm.rs b/winch/codegen/src/isa/x64/asm.rs
index 5b2286404..03bddaac6 100644
--- a/winch/codegen/src/isa/x64/asm.rs
+++ b/winch/codegen/src/isa/x64/asm.rs
@@ -2,7 +2,7 @@
 
 use crate::{
     isa::reg::Reg,
-    masm::{DivKind, OperandSize},
+    masm::{DivKind, OperandSize, RemKind},
 };
 use cranelift_codegen::{
     isa::x64::{
@@ -73,6 +73,15 @@ impl From<DivKind> for DivOrRemKind {
     }
 }
 
+impl From<RemKind> for DivOrRemKind {
+    fn from(kind: RemKind) -> Self {
+        match kind {
+            RemKind::Signed => DivOrRemKind::SignedRem,
+            RemKind::Unsigned => DivOrRemKind::UnsignedRem,
+        }
+    }
+}
+
 /// Low level assembler implementation for x64.
 pub(crate) struct Assembler {
     /// The machine instruction buffer.
@@ -299,6 +308,26 @@ impl Assembler {
         });
     }
 
+    /// Signed/unsigned remainder.
+    ///
+    /// Emits a sequence of instructions to ensure the correctness of the
+    /// division invariants and ultimately calculate the remainder.
+    /// This function assumes that the
+    /// caller has correctly allocated the dividend as `(rdx:rax)` and
+    /// accounted for the remainder to be stored in `rdx`.
+    pub fn rem(&mut self, divisor: Reg, dst: (Reg, Reg), kind: RemKind, size: OperandSize) {
+        self.emit(Inst::CheckedDivOrRemSeq {
+            kind: kind.into(),
+            size: size.into(),
+            divisor: divisor.into(),
+            dividend_lo: dst.0.into(),
+            dividend_hi: dst.1.into(),
+            dst_quotient: dst.0.into(),
+            dst_remainder: dst.1.into(),
+            tmp: None,
+        });
+    }
+
     /// Multiply immediate and register.
     pub fn mul_ir(&mut self, imm: i32, dst: Reg, size: OperandSize) {
         let imm = RegMemImm::imm(imm as u32);
diff --git a/winch/codegen/src/isa/x64/masm.rs b/winch/codegen/src/isa/x64/masm.rs
index 758e72fa5..e4bc0db62 100644
--- a/winch/codegen/src/isa/x64/masm.rs
+++ b/winch/codegen/src/isa/x64/masm.rs
@@ -4,7 +4,7 @@ use super::{
     regs::{self, rbp, rsp},
 };
 use crate::isa::reg::Reg;
-use crate::masm::{DivKind, MacroAssembler as Masm, OperandSize, RegImm};
+use crate::masm::{DivKind, MacroAssembler as Masm, OperandSize, RegImm, RemKind};
 use crate::{abi::LocalSlot, codegen::CodeGenContext, stack::Val};
 use cranelift_codegen::{isa::x64::settings as x64_settings, settings, Final, MachBufferFinalized};
 
@@ -174,6 +174,28 @@ impl Masm for MacroAssembler {
         context.stack.push(Val::reg(rax));
     }
 
+    fn rem(&mut self, context: &mut CodeGenContext, kind: RemKind, size: OperandSize) {
+        // Allocate rdx:rax.
+        let rdx = context.gpr(regs::rdx(), self);
+        let rax = context.gpr(regs::rax(), self);
+
+        // Allocate the divisor, which can be any gpr.
+        let divisor = context.pop_to_reg(self, size);
+
+        // Mark rax as allocatable.
+        context.regalloc.free_gpr(rax);
+        // Move the top value to rax.
+        let rax = context.pop_to_named_reg(self, rax, size);
+        self.asm.rem(divisor, (rax, rdx), kind, size);
+
+        // Free the divisor and rax.
+        context.free_gpr(divisor);
+        context.free_gpr(rax);
+
+        // Push the remainder.
+        context.stack.push(Val::reg(rdx));
+    }
+
     fn epilogue(&mut self, locals_size: u32) {
         assert!(self.sp_offset == locals_size);
 
diff --git a/winch/codegen/src/masm.rs b/winch/codegen/src/masm.rs
index 1f4507be5..f23e31917 100644
--- a/winch/codegen/src/masm.rs
+++ b/winch/codegen/src/masm.rs
@@ -13,6 +13,14 @@ pub(crate) enum DivKind {
     Unsigned,
 }
 
+/// Remainder kind.
+pub(crate) enum RemKind {
+    /// Signed remainder.
+    Signed,
+    /// Unsigned remainder.
+    Unsigned,
+}
+
 /// Operand size, in bits.
 #[derive(Copy, Clone, Eq, PartialEq)]
 pub(crate) enum OperandSize {
@@ -116,6 +124,9 @@ pub(crate) trait MacroAssembler {
     /// functions.
     fn div(&mut self, context: &mut CodeGenContext, kind: DivKind, size: OperandSize);
 
+    /// Calculate remainder.
+    fn rem(&mut self, context: &mut CodeGenContext, kind: RemKind, size: OperandSize);
+
     /// Push the register to the stack, returning the offset.
     fn push(&mut self, src: Reg) -> u32;
 
diff --git a/winch/codegen/src/visitor.rs b/winch/codegen/src/visitor.rs
index 072c70404..331d0b76d 100644
--- a/winch/codegen/src/visitor.rs
+++ b/winch/codegen/src/visitor.rs
@@ -5,7 +5,7 @@
 //! machine code emitter.
 
 use crate::codegen::CodeGen;
-use crate::masm::{DivKind, MacroAssembler, OperandSize, RegImm};
+use crate::masm::{DivKind, MacroAssembler, OperandSize, RegImm, RemKind};
 use crate::stack::Val;
 use wasmparser::ValType;
 use wasmparser::VisitOperator;
@@ -41,6 +41,10 @@ macro_rules! def_unsupported {
     (emit I32DivU $($rest:tt)*) => {};
     (emit I64DivS $($rest:tt)*) => {};
     (emit I64DivU $($rest:tt)*) => {};
+    (emit I64RemU $($rest:tt)*) => {};
+    (emit I64RemS $($rest:tt)*) => {};
+    (emit I32RemU $($rest:tt)*) => {};
+    (emit I32RemS $($rest:tt)*) => {};
     (emit I64Mul $($rest:tt)*) => {};
     (emit I64Sub $($rest:tt)*) => {};
     (emit LocalGet $($rest:tt)*) => {};
@@ -134,6 +138,34 @@ where
         self.masm.div(&mut self.context, Unsigned, S64);
     }
 
+    fn visit_i32_rem_s(&mut self) {
+        use OperandSize::*;
+        use RemKind::*;
+
+        self.masm.rem(&mut self.context, Signed, S32);
+    }
+
+    fn visit_i32_rem_u(&mut self) {
+        use OperandSize::*;
+        use RemKind::*;
+
+        self.masm.rem(&mut self.context, Unsigned, S32);
+    }
+
+    fn visit_i64_rem_s(&mut self) {
+        use OperandSize::*;
+        use RemKind::*;
+
+        self.masm.rem(&mut self.context, Signed, S64);
+    }
+
+    fn visit_i64_rem_u(&mut self) {
+        use OperandSize::*;
+        use RemKind::*;
+
+        self.masm.rem(&mut self.context, Unsigned, S64);
+    }
+
     fn visit_end(&mut self) {}
 
     fn visit_local_get(&mut self, index: u32) {


Test patch:
diff --git a/winch/filetests/filetests/x64/i32_rems/const.wat b/winch/filetests/filetests/x64/i32_rems/const.wat
new file mode 100644
index 000000000..1dc8224b7
--- /dev/null
+++ b/winch/filetests/filetests/x64/i32_rems/const.wat
@@ -0,0 +1,25 @@
+;;! target = "x86_64"
+
+(module
+    (func (result i32)
+	(i32.const 7)
+	(i32.const 5)
+	(i32.rem_s)
+    )
+)
+;;    0:	 55                   	push	rbp
+;;    1:	 4889e5               	mov	rbp, rsp
+;;    4:	 b905000000           	mov	ecx, 5
+;;    9:	 b807000000           	mov	eax, 7
+;;    e:	 83f900               	cmp	ecx, 0
+;;   11:	 0f8502000000         	jne	0x19
+;;   17:	 0f0b                 	ud2	
+;;   19:	 83f9ff               	cmp	ecx, -1
+;;   1c:	 0f850a000000         	jne	0x2c
+;;   22:	 b800000000           	mov	eax, 0
+;;   27:	 e903000000           	jmp	0x2f
+;;   2c:	 99                   	cdq	
+;;   2d:	 f7f9                 	idiv	ecx
+;;   2f:	 4889d0               	mov	rax, rdx
+;;   32:	 5d                   	pop	rbp
+;;   33:	 c3                   	ret	
diff --git a/winch/filetests/filetests/x64/i32_rems/one_zero.wat b/winch/filetests/filetests/x64/i32_rems/one_zero.wat
new file mode 100644
index 000000000..bc7804ede
--- /dev/null
+++ b/winch/filetests/filetests/x64/i32_rems/one_zero.wat
@@ -0,0 +1,25 @@
+;;! target = "x86_64"
+
+(module
+    (func (result i32)
+	(i32.const 1)
+	(i32.const 0)
+	(i32.rem_s)
+    )
+)
+;;    0:	 55                   	push	rbp
+;;    1:	 4889e5               	mov	rbp, rsp
+;;    4:	 b900000000           	mov	ecx, 0
+;;    9:	 b801000000           	mov	eax, 1
+;;    e:	 83f900               	cmp	ecx, 0
+;;   11:	 0f8502000000         	jne	0x19
+;;   17:	 0f0b                 	ud2	
+;;   19:	 83f9ff               	cmp	ecx, -1
+;;   1c:	 0f850a000000         	jne	0x2c
+;;   22:	 b800000000           	mov	eax, 0
+;;   27:	 e903000000           	jmp	0x2f
+;;   2c:	 99                   	cdq	
+;;   2d:	 f7f9                 	idiv	ecx
+;;   2f:	 4889d0               	mov	rax, rdx
+;;   32:	 5d                   	pop	rbp
+;;   33:	 c3                   	ret	
diff --git a/winch/filetests/filetests/x64/i32_rems/overflow.wat b/winch/filetests/filetests/x64/i32_rems/overflow.wat
new file mode 100644
index 000000000..7211182b2
--- /dev/null
+++ b/winch/filetests/filetests/x64/i32_rems/overflow.wat
@@ -0,0 +1,25 @@
+;;! target = "x86_64"
+
+(module
+    (func (result i32)
+	(i32.const 0x80000000)
+	(i32.const -1)
+	(i32.rem_s)
+    )
+)
+;;    0:	 55                   	push	rbp
+;;    1:	 4889e5               	mov	rbp, rsp
+;;    4:	 b9ffffffff           	mov	ecx, 0xffffffff
+;;    9:	 b800000080           	mov	eax, 0x80000000
+;;    e:	 83f900               	cmp	ecx, 0
+;;   11:	 0f8502000000         	jne	0x19
+;;   17:	 0f0b                 	ud2	
+;;   19:	 83f9ff               	cmp	ecx, -1
+;;   1c:	 0f850a000000         	jne	0x2c
+;;   22:	 b800000000           	mov	eax, 0
+;;   27:	 e903000000           	jmp	0x2f
+;;   2c:	 99                   	cdq	
+;;   2d:	 f7f9                 	idiv	ecx
+;;   2f:	 4889d0               	mov	rax, rdx
+;;   32:	 5d                   	pop	rbp
+;;   33:	 c3                   	ret	
diff --git a/winch/filetests/filetests/x64/i32_rems/params.wat b/winch/filetests/filetests/x64/i32_rems/params.wat
new file mode 100644
index 000000000..d91d3937e
--- /dev/null
+++ b/winch/filetests/filetests/x64/i32_rems/params.wat
@@ -0,0 +1,29 @@
+;;! target = "x86_64"
+
+(module
+    (func (param i32) (param i32) (result i32)
+	(local.get 0)
+	(local.get 1)
+	(i32.rem_s)
+    )
+)
+;;    0:	 55                   	push	rbp
+;;    1:	 4889e5               	mov	rbp, rsp
+;;    4:	 4883ec08             	sub	rsp, 8
+;;    8:	 897c2404             	mov	dword ptr [rsp + 4], edi
+;;    c:	 893424               	mov	dword ptr [rsp], esi
+;;    f:	 8b0c24               	mov	ecx, dword ptr [rsp]
+;;   12:	 8b442404             	mov	eax, dword ptr [rsp + 4]
+;;   16:	 83f900               	cmp	ecx, 0
+;;   19:	 0f8502000000         	jne	0x21
+;;   1f:	 0f0b                 	ud2	
+;;   21:	 83f9ff               	cmp	ecx, -1
+;;   24:	 0f850a000000         	jne	0x34
+;;   2a:	 b800000000           	mov	eax, 0
+;;   2f:	 e903000000           	jmp	0x37
+;;   34:	 99                   	cdq	
+;;   35:	 f7f9                 	idiv	ecx
+;;   37:	 4889d0               	mov	rax, rdx
+;;   3a:	 4883c408             	add	rsp, 8
+;;   3e:	 5d                   	pop	rbp
+;;   3f:	 c3                   	ret	
diff --git a/winch/filetests/filetests/x64/i32_rems/zero_zero.wat b/winch/filetests/filetests/x64/i32_rems/zero_zero.wat
new file mode 100644
index 000000000..dd56aff9b
--- /dev/null
+++ b/winch/filetests/filetests/x64/i32_rems/zero_zero.wat
@@ -0,0 +1,25 @@
+;;! target = "x86_64"
+
+(module
+    (func (result i32)
+	(i32.const 0)
+	(i32.const 0)
+	(i32.rem_s)
+    )
+)
+;;    0:	 55                   	push	rbp
+;;    1:	 4889e5               	mov	rbp, rsp
+;;    4:	 b900000000           	mov	ecx, 0
+;;    9:	 b800000000           	mov	eax, 0
+;;    e:	 83f900               	cmp	ecx, 0
+;;   11:	 0f8502000000         	jne	0x19
+;;   17:	 0f0b                 	ud2	
+;;   19:	 83f9ff               	cmp	ecx, -1
+;;   1c:	 0f850a000000         	jne	0x2c
+;;   22:	 b800000000           	mov	eax, 0
+;;   27:	 e903000000           	jmp	0x2f
+;;   2c:	 99                   	cdq	
+;;   2d:	 f7f9                 	idiv	ecx
+;;   2f:	 4889d0               	mov	rax, rdx
+;;   32:	 5d                   	pop	rbp
+;;   33:	 c3                   	ret	
diff --git a/winch/filetests/filetests/x64/i32_remu/const.wat b/winch/filetests/filetests/x64/i32_remu/const.wat
new file mode 100644
index 000000000..65dc05cef
--- /dev/null
+++ b/winch/filetests/filetests/x64/i32_remu/const.wat
@@ -0,0 +1,21 @@
+;;! target = "x86_64"
+
+(module
+    (func (result i32)
+	(i32.const 7)
+	(i32.const 5)
+	(i32.rem_u)
+    )
+)
+;;    0:	 55                   	push	rbp
+;;    1:	 4889e5               	mov	rbp, rsp
+;;    4:	 b905000000           	mov	ecx, 5
+;;    9:	 b807000000           	mov	eax, 7
+;;    e:	 83f900               	cmp	ecx, 0
+;;   11:	 0f8502000000         	jne	0x19
+;;   17:	 0f0b                 	ud2	
+;;   19:	 ba00000000           	mov	edx, 0
+;;   1e:	 f7f1                 	div	ecx
+;;   20:	 4889d0               	mov	rax, rdx
+;;   23:	 5d                   	pop	rbp
+;;   24:	 c3                   	ret	
diff --git a/winch/filetests/filetests/x64/i32_remu/one_zero.wat b/winch/filetests/filetests/x64/i32_remu/one_zero.wat
new file mode 100644
index 000000000..9a482a68f
--- /dev/null
+++ b/winch/filetests/filetests/x64/i32_remu/one_zero.wat
@@ -0,0 +1,21 @@
+;;! target = "x86_64"
+
+(module
+    (func (result i32)
+	(i32.const 1)
+	(i32.const 0)
+	(i32.rem_u)
+    )
+)
+;;    0:	 55                   	push	rbp
+;;    1:	 4889e5               	mov	rbp, rsp
+;;    4:	 b900000000           	mov	ecx, 0
+;;    9:	 b801000000           	mov	eax, 1
+;;    e:	 83f900               	cmp	ecx, 0
+;;   11:	 0f8502000000         	jne	0x19
+;;   17:	 0f0b                 	ud2	
+;;   19:	 ba00000000           	mov	edx, 0
+;;   1e:	 f7f1                 	div	ecx
+;;   20:	 4889d0               	mov	rax, rdx
+;;   23:	 5d                   	pop	rbp
+;;   24:	 c3                   	ret	
diff --git a/winch/filetests/filetests/x64/i32_remu/params.wat b/winch/filetests/filetests/x64/i32_remu/params.wat
new file mode 100644
index 000000000..743ce4446
--- /dev/null
+++ b/winch/filetests/filetests/x64/i32_remu/params.wat
@@ -0,0 +1,25 @@
+;;! target = "x86_64"
+
+(module
+    (func (param i32) (param i32) (result i32)
+	(local.get 0)
+	(local.get 1)
+	(i32.rem_u)
+    )
+)
+;;    0:	 55                   	push	rbp
+;;    1:	 4889e5               	mov	rbp, rsp
+;;    4:	 4883ec08             	sub	rsp, 8
+;;    8:	 897c2404             	mov	dword ptr [rsp + 4], edi
+;;    c:	 893424               	mov	dword ptr [rsp], esi
+;;    f:	 8b0c24               	mov	ecx, dword ptr [rsp]
+;;   12:	 8b442404             	mov	eax, dword ptr [rsp + 4]
+;;   16:	 83f900               	cmp	ecx, 0
+;;   19:	 0f8502000000         	jne	0x21
+;;   1f:	 0f0b                 	ud2	
+;;   21:	 ba00000000           	mov	edx, 0
+;;   26:	 f7f1                 	div	ecx
+;;   28:	 4889d0               	mov	rax, rdx
+;;   2b:	 4883c408             	add	rsp, 8
+;;   2f:	 5d                   	pop	rbp
+;;   30:	 c3                   	ret	
diff --git a/winch/filetests/filetests/x64/i32_remu/signed.wat b/winch/filetests/filetests/x64/i32_remu/signed.wat
new file mode 100644
index 000000000..c29c66e5c
--- /dev/null
+++ b/winch/filetests/filetests/x64/i32_remu/signed.wat
@@ -0,0 +1,21 @@
+;;! target = "x86_64"
+
+(module
+    (func (result i32)
+	(i32.const -1)
+	(i32.const -1)
+	(i32.rem_u)
+    )
+)
+;;    0:	 55                   	push	rbp
+;;    1:	 4889e5               	mov	rbp, rsp
+;;    4:	 b9ffffffff           	mov	ecx, 0xffffffff
+;;    9:	 b8ffffffff           	mov	eax, 0xffffffff
+;;    e:	 83f900               	cmp	ecx, 0
+;;   11:	 0f8502000000         	jne	0x19
+;;   17:	 0f0b                 	ud2	
+;;   19:	 ba00000000           	mov	edx, 0
+;;   1e:	 f7f1                 	div	ecx
+;;   20:	 4889d0               	mov	rax, rdx
+;;   23:	 5d                   	pop	rbp
+;;   24:	 c3                   	ret	
diff --git a/winch/filetests/filetests/x64/i32_remu/zero_zero.wat b/winch/filetests/filetests/x64/i32_remu/zero_zero.wat
new file mode 100644
index 000000000..671840c32
--- /dev/null
+++ b/winch/filetests/filetests/x64/i32_remu/zero_zero.wat
@@ -0,0 +1,21 @@
+;;! target = "x86_64"
+
+(module
+    (func (result i32)
+	(i32.const 0)
+	(i32.const 0)
+	(i32.rem_u)
+    )
+)
+;;    0:	 55                   	push	rbp
+;;    1:	 4889e5               	mov	rbp, rsp
+;;    4:	 b900000000           	mov	ecx, 0
+;;    9:	 b800000000           	mov	eax, 0
+;;    e:	 83f900               	cmp	ecx, 0
+;;   11:	 0f8502000000         	jne	0x19
+;;   17:	 0f0b                 	ud2	
+;;   19:	 ba00000000           	mov	edx, 0
+;;   1e:	 f7f1                 	div	ecx
+;;   20:	 4889d0               	mov	rax, rdx
+;;   23:	 5d                   	pop	rbp
+;;   24:	 c3                   	ret	
diff --git a/winch/filetests/filetests/x64/i64_rems/const.wat b/winch/filetests/filetests/x64/i64_rems/const.wat
new file mode 100644
index 000000000..4eb4e8352
--- /dev/null
+++ b/winch/filetests/filetests/x64/i64_rems/const.wat
@@ -0,0 +1,25 @@
+;;! target = "x86_64"
+
+(module
+    (func (result i64)
+	(i64.const 7)
+	(i64.const 5)
+	(i64.rem_s)
+    )
+)
+;;    0:	 55                   	push	rbp
+;;    1:	 4889e5               	mov	rbp, rsp
+;;    4:	 48c7c105000000       	mov	rcx, 5
+;;    b:	 48c7c007000000       	mov	rax, 7
+;;   12:	 4883f900             	cmp	rcx, 0
+;;   16:	 0f8502000000         	jne	0x1e
+;;   1c:	 0f0b                 	ud2	
+;;   1e:	 4883f9ff             	cmp	rcx, -1
+;;   22:	 0f850a000000         	jne	0x32
+;;   28:	 b800000000           	mov	eax, 0
+;;   2d:	 e905000000           	jmp	0x37
+;;   32:	 4899                 	cqo	
+;;   34:	 48f7f9               	idiv	rcx
+;;   37:	 4889d0               	mov	rax, rdx
+;;   3a:	 5d                   	pop	rbp
+;;   3b:	 c3                   	ret	
diff --git a/winch/filetests/filetests/x64/i64_rems/one_zero.wat b/winch/filetests/filetests/x64/i64_rems/one_zero.wat
new file mode 100644
index 000000000..dc748d622
--- /dev/null
+++ b/winch/filetests/filetests/x64/i64_rems/one_zero.wat
@@ -0,0 +1,25 @@
+;;! target = "x86_64"
+
+(module
+    (func (result i64)
+	(i64.const 1)
+	(i64.const 0)
+	(i64.rem_s)
+    )
+)
+;;    0:	 55                   	push	rbp
+;;    1:	 4889e5               	mov	rbp, rsp
+;;    4:	 48c7c100000000       	mov	rcx, 0
+;;    b:	 48c7c001000000       	mov	rax, 1
+;;   12:	 4883f900             	cmp	rcx, 0
+;;   16:	 0f8502000000         	jne	0x1e
+;;   1c:	 0f0b                 	ud2	
+;;   1e:	 4883f9ff             	cmp	rcx, -1
+;;   22:	 0f850a000000         	jne	0x32
+;;   28:	 b800000000           	mov	eax, 0
+;;   2d:	 e905000000           	jmp	0x37
+;;   32:	 4899                 	cqo	
+;;   34:	 48f7f9               	idiv	rcx
+;;   37:	 4889d0               	mov	rax, rdx
+;;   3a:	 5d                   	pop	rbp
+;;   3b:	 c3                   	ret	
diff --git a/winch/filetests/filetests/x64/i64_rems/overflow.wat b/winch/filetests/filetests/x64/i64_rems/overflow.wat
new file mode 100644
index 000000000..33bd76cdd
--- /dev/null
+++ b/winch/filetests/filetests/x64/i64_rems/overflow.wat
@@ -0,0 +1,26 @@
+;;! target = "x86_64"
+
+(module
+    (func (result i64)
+	(i64.const 0x8000000000000000)
+	(i64.const -1)
+	(i64.rem_s)
+    )
+)
+;;    0:	 55                   	push	rbp
+;;    1:	 4889e5               	mov	rbp, rsp
+;;    4:	 48c7c1ffffffff       	mov	rcx, 0xffffffffffffffff
+;;    b:	 48b80000000000000080 	
+;; 				movabs	rax, 0x8000000000000000
+;;   15:	 4883f900             	cmp	rcx, 0
+;;   19:	 0f8502000000         	jne	0x21
+;;   1f:	 0f0b                 	ud2	
+;;   21:	 4883f9ff             	cmp	rcx, -1
+;;   25:	 0f850a000000         	jne	0x35
+;;   2b:	 b800000000           	mov	eax, 0
+;;   30:	 e905000000           	jmp	0x3a
+;;   35:	 4899                 	cqo	
+;;   37:	 48f7f9               	idiv	rcx
+;;   3a:	 4889d0               	mov	rax, rdx
+;;   3d:	 5d                   	pop	rbp
+;;   3e:	 c3                   	ret	
diff --git a/winch/filetests/filetests/x64/i64_rems/params.wat b/winch/filetests/filetests/x64/i64_rems/params.wat
new file mode 100644
index 000000000..5fc16387e
--- /dev/null
+++ b/winch/filetests/filetests/x64/i64_rems/params.wat
@@ -0,0 +1,29 @@
+;;! target = "x86_64"
+
+(module
+    (func (param i64) (param i64) (result i64)
+	(local.get 0)
+	(local.get 1)
+	(i64.rem_s)
+    )
+)
+;;    0:	 55                   	push	rbp
+;;    1:	 4889e5               	mov	rbp, rsp
+;;    4:	 4883ec10             	sub	rsp, 0x10
+;;    8:	 48897c2408           	mov	qword ptr [rsp + 8], rdi
+;;    d:	 48893424             	mov	qword ptr [rsp], rsi
+;;   11:	 488b0c24             	mov	rcx, qword ptr [rsp]
+;;   15:	 488b442408           	mov	rax, qword ptr [rsp + 8]
+;;   1a:	 4883f900             	cmp	rcx, 0
+;;   1e:	 0f8502000000         	jne	0x26
+;;   24:	 0f0b                 	ud2	
+;;   26:	 4883f9ff             	cmp	rcx, -1
+;;   2a:	 0f850a000000         	jne	0x3a
+;;   30:	 b800000000           	mov	eax, 0
+;;   35:	 e905000000           	jmp	0x3f
+;;   3a:	 4899                 	cqo	
+;;   3c:	 48f7f9               	idiv	rcx
+;;   3f:	 4889d0               	mov	rax, rdx
+;;   42:	 4883c410             	add	rsp, 0x10
+;;   46:	 5d                   	pop	rbp
+;;   47:	 c3                   	ret	
diff --git a/winch/filetests/filetests/x64/i64_rems/zero_zero.wat b/winch/filetests/filetests/x64/i64_rems/zero_zero.wat
new file mode 100644
index 000000000..ad5a74bdc
--- /dev/null
+++ b/winch/filetests/filetests/x64/i64_rems/zero_zero.wat
@@ -0,0 +1,25 @@
+;;! target = "x86_64"
+
+(module
+    (func (result i64)
+	(i64.const 0)
+	(i64.const 0)
+	(i64.rem_s)
+    )
+)
+;;    0:	 55                   	push	rbp
+;;    1:	 4889e5               	mov	rbp, rsp
+;;    4:	 48c7c100000000       	mov	rcx, 0
+;;    b:	 48c7c000000000       	mov	rax, 0
+;;   12:	 4883f900             	cmp	rcx, 0
+;;   16:	 0f8502000000         	jne	0x1e
+;;   1c:	 0f0b                 	ud2	
+;;   1e:	 4883f9ff             	cmp	rcx, -1
+;;   22:	 0f850a000000         	jne	0x32
+;;   28:	 b800000000           	mov	eax, 0
+;;   2d:	 e905000000           	jmp	0x37
+;;   32:	 4899                 	cqo	
+;;   34:	 48f7f9               	idiv	rcx
+;;   37:	 4889d0               	mov	rax, rdx
+;;   3a:	 5d                   	pop	rbp
+;;   3b:	 c3                   	ret	
diff --git a/winch/filetests/filetests/x64/i64_remu/const.wat b/winch/filetests/filetests/x64/i64_remu/const.wat
new file mode 100644
index 000000000..c139c6d72
--- /dev/null
+++ b/winch/filetests/filetests/x64/i64_remu/const.wat
@@ -0,0 +1,21 @@
+;;! target = "x86_64"
+
+(module
+    (func (result i64)
+	(i64.const 7)
+	(i64.const 5)
+	(i64.rem_u)
+    )
+)
+;;    0:	 55                   	push	rbp
+;;    1:	 4889e5               	mov	rbp, rsp
+;;    4:	 48c7c105000000       	mov	rcx, 5
+;;    b:	 48c7c007000000       	mov	rax, 7
+;;   12:	 4883f900             	cmp	rcx, 0
+;;   16:	 0f8502000000         	jne	0x1e
+;;   1c:	 0f0b                 	ud2	
+;;   1e:	 ba00000000           	mov	edx, 0
+;;   23:	 48f7f1               	div	rcx
+;;   26:	 4889d0               	mov	rax, rdx
+;;   29:	 5d                   	pop	rbp
+;;   2a:	 c3                   	ret	
diff --git a/winch/filetests/filetests/x64/i64_remu/one_zero.wat b/winch/filetests/filetests/x64/i64_remu/one_zero.wat
new file mode 100644
index 000000000..2c79349fa
--- /dev/null
+++ b/winch/filetests/filetests/x64/i64_remu/one_zero.wat
@@ -0,0 +1,21 @@
+;;! target = "x86_64"
+
+(module
+    (func (result i64)
+	(i64.const 1)
+	(i64.const 0)
+	(i64.rem_u)
+    )
+)
+;;    0:	 55                   	push	rbp
+;;    1:	 4889e5               	mov	rbp, rsp
+;;    4:	 48c7c100000000       	mov	rcx, 0
+;;    b:	 48c7c001000000       	mov	rax, 1
+;;   12:	 4883f900             	cmp	rcx, 0
+;;   16:	 0f8502000000         	jne	0x1e
+;;   1c:	 0f0b                 	ud2	
+;;   1e:	 ba00000000           	mov	edx, 0
+;;   23:	 48f7f1               	div	rcx
+;;   26:	 4889d0               	mov	rax, rdx
+;;   29:	 5d                   	pop	rbp
+;;   2a:	 c3                   	ret	
diff --git a/winch/filetests/filetests/x64/i64_remu/params.wat b/winch/filetests/filetests/x64/i64_remu/params.wat
new file mode 100644
index 000000000..e37f95534
--- /dev/null
+++ b/winch/filetests/filetests/x64/i64_remu/params.wat
@@ -0,0 +1,25 @@
+;;! target = "x86_64"
+
+(module
+    (func (param i64) (param i64) (result i64)
+	(local.get 0)
+	(local.get 1)
+	(i64.rem_u)
+    )
+)
+;;    0:	 55                   	push	rbp
+;;    1:	 4889e5               	mov	rbp, rsp
+;;    4:	 4883ec10             	sub	rsp, 0x10
+;;    8:	 48897c2408           	mov	qword ptr [rsp + 8], rdi
+;;    d:	 48893424             	mov	qword ptr [rsp], rsi
+;;   11:	 488b0c24             	mov	rcx, qword ptr [rsp]
+;;   15:	 488b442408           	mov	rax, qword ptr [rsp + 8]
+;;   1a:	 4883f900             	cmp	rcx, 0
+;;   1e:	 0f8502000000         	jne	0x26
+;;   24:	 0f0b                 	ud2	
+;;   26:	 ba00000000           	mov	edx, 0
+;;   2b:	 48f7f1               	div	rcx
+;;   2e:	 4889d0               	mov	rax, rdx
+;;   31:	 4883c410             	add	rsp, 0x10
+;;   35:	 5d                   	pop	rbp
+;;   36:	 c3                   	ret	
diff --git a/winch/filetests/filetests/x64/i64_remu/signed.wat b/winch/filetests/filetests/x64/i64_remu/signed.wat
new file mode 100644
index 000000000..b0b4cdce9
--- /dev/null
+++ b/winch/filetests/filetests/x64/i64_remu/signed.wat
@@ -0,0 +1,21 @@
+;;! target = "x86_64"
+
+(module
+    (func (result i64)
+	(i64.const -1)
+	(i64.const -1)
+	(i64.rem_u)
+    )
+)
+;;    0:	 55                   	push	rbp
+;;    1:	 4889e5               	mov	rbp, rsp
+;;    4:	 48c7c1ffffffff       	mov	rcx, 0xffffffffffffffff
+;;    b:	 48c7c0ffffffff       	mov	rax, 0xffffffffffffffff
+;;   12:	 4883f900             	cmp	rcx, 0
+;;   16:	 0f8502000000         	jne	0x1e
+;;   1c:	 0f0b                 	ud2	
+;;   1e:	 ba00000000           	mov	edx, 0
+;;   23:	 48f7f1               	div	rcx
+;;   26:	 4889d0               	mov	rax, rdx
+;;   29:	 5d                   	pop	rbp
+;;   2a:	 c3                   	ret	
diff --git a/winch/filetests/filetests/x64/i64_remu/zero_zero.wat b/winch/filetests/filetests/x64/i64_remu/zero_zero.wat
new file mode 100644
index 000000000..7fbf7a9ae
--- /dev/null
+++ b/winch/filetests/filetests/x64/i64_remu/zero_zero.wat
@@ -0,0 +1,21 @@
+;;! target = "x86_64"
+
+(module
+    (func (result i64)
+	(i64.const 0)
+	(i64.const 0)
+	(i64.rem_u)
+    )
+)
+;;    0:	 55                   	push	rbp
+;;    1:	 4889e5               	mov	rbp, rsp
+;;    4:	 48c7c100000000       	mov	rcx, 0
+;;    b:	 48c7c000000000       	mov	rax, 0
+;;   12:	 4883f900             	cmp	rcx, 0
+;;   16:	 0f8502000000         	jne	0x1e
+;;   1c:	 0f0b                 	ud2	
+;;   1e:	 ba00000000           	mov	edx, 0
+;;   23:	 48f7f1               	div	rcx
+;;   26:	 4889d0               	mov	rax, rdx
+;;   29:	 5d                   	pop	rbp
+;;   2a:	 c3                   	ret