Repository: bytecodealliance/wasmtime
Pull request #8194 (2024-03-20 17:58:00)

winch: Enable `memory64` in Winch
Closes: https://github.com/bytecodealliance/wasmtime/issues/8089

This commit  unlocks support for the `memory64` proposal in Winch. After all the fixes to heap handling, all the spec and misc tests are passing, which is a good indication regarding the support for this proposal.

I'll like to merge this change after: https://github.com/bytecodealliance/wasmtime/pull/8156.

<!--
Please make sure you include the following information:

- If this work has been discussed elsewhere, please include a link to that
  conversation. If it was discussed in an issue, just mention "issue #...".

- Explain why this change is needed. If the details are in an issue already,
  this can be brief.

Our development process is documented in the Wasmtime book:
https://docs.wasmtime.dev/contributing-development-process.html

Please ensure all communication follows the code of conduct:
https://github.com/bytecodealliance/wasmtime/blob/main/CODE_OF_CONDUCT.md
-->



Patch:
diff --git a/build.rs b/build.rs
index 262b40838..d0b42afe2 100644
--- a/build.rs
+++ b/build.rs
@@ -241,6 +241,10 @@ fn ignore(testsuite: &str, testname: &str, strategy: &str) -> bool {
             return denylist || ref_types || simd;
         }
 
+        if testsuite == "memory64" {
+            return testname.starts_with("simd") || testname.starts_with("threads");
+        }
+
         if testsuite != "winch" {
             return true;
         }
diff --git a/cranelift/codegen/src/isa/aarch64/abi.rs b/cranelift/codegen/src/isa/aarch64/abi.rs
index 440840c4d..31a5c25c3 100644
--- a/cranelift/codegen/src/isa/aarch64/abi.rs
+++ b/cranelift/codegen/src/isa/aarch64/abi.rs
@@ -99,17 +99,14 @@ impl ABIMachineSpec for AArch64MachineDeps {
         16
     }
 
-    fn compute_arg_locs<'a, I>(
+    fn compute_arg_locs(
         call_conv: isa::CallConv,
         _flags: &settings::Flags,
-        params: I,
+        params: &[ir::AbiParam],
         args_or_rets: ArgsOrRets,
         add_ret_area_ptr: bool,
-        mut args: ArgsAccumulator<'_>,
-    ) -> CodegenResult<(u32, Option<usize>)>
-    where
-        I: IntoIterator<Item = &'a ir::AbiParam>,
-    {
+        mut args: ArgsAccumulator,
+    ) -> CodegenResult<(u32, Option<usize>)> {
         if matches!(call_conv, isa::CallConv::Tail | isa::CallConv::Winch) {
             return compute_arg_locs_tail(params, add_ret_area_ptr, args);
         }
@@ -1291,14 +1288,11 @@ impl AArch64CallSite {
     }
 }
 
-fn compute_arg_locs_tail<'a, I>(
-    params: I,
+fn compute_arg_locs_tail(
+    params: &[ir::AbiParam],
     add_ret_area_ptr: bool,
-    mut args: ArgsAccumulator<'_>,
-) -> CodegenResult<(u32, Option<usize>)>
-where
-    I: IntoIterator<Item = &'a ir::AbiParam>,
-{
+    mut args: ArgsAccumulator,
+) -> CodegenResult<(u32, Option<usize>)> {
     let mut xregs = ALL_CLOBBERS
         .into_iter()
         .filter(|r| r.class() == RegClass::Int)
diff --git a/cranelift/codegen/src/isa/riscv64/abi.rs b/cranelift/codegen/src/isa/riscv64/abi.rs
index 0f0d32e8f..c119fe312 100644
--- a/cranelift/codegen/src/isa/riscv64/abi.rs
+++ b/cranelift/codegen/src/isa/riscv64/abi.rs
@@ -87,17 +87,14 @@ impl ABIMachineSpec for Riscv64MachineDeps {
         16
     }
 
-    fn compute_arg_locs<'a, I>(
+    fn compute_arg_locs(
         call_conv: isa::CallConv,
         _flags: &settings::Flags,
-        params: I,
+        params: &[ir::AbiParam],
         args_or_rets: ArgsOrRets,
         add_ret_area_ptr: bool,
-        mut args: ArgsAccumulator<'_>,
-    ) -> CodegenResult<(u32, Option<usize>)>
-    where
-        I: IntoIterator<Item = &'a ir::AbiParam>,
-    {
+        mut args: ArgsAccumulator,
+    ) -> CodegenResult<(u32, Option<usize>)> {
         assert_ne!(
             call_conv,
             isa::CallConv::Winch,
diff --git a/cranelift/codegen/src/isa/s390x/abi.rs b/cranelift/codegen/src/isa/s390x/abi.rs
index af34bb5a4..7c48578a8 100644
--- a/cranelift/codegen/src/isa/s390x/abi.rs
+++ b/cranelift/codegen/src/isa/s390x/abi.rs
@@ -220,17 +220,14 @@ impl ABIMachineSpec for S390xMachineDeps {
         8
     }
 
-    fn compute_arg_locs<'a, I>(
+    fn compute_arg_locs(
         call_conv: isa::CallConv,
         _flags: &settings::Flags,
-        params: I,
+        params: &[ir::AbiParam],
         args_or_rets: ArgsOrRets,
         add_ret_area_ptr: bool,
-        mut args: ArgsAccumulator<'_>,
-    ) -> CodegenResult<(u32, Option<usize>)>
-    where
-        I: IntoIterator<Item = &'a ir::AbiParam>,
-    {
+        mut args: ArgsAccumulator,
+    ) -> CodegenResult<(u32, Option<usize>)> {
         assert_ne!(
             call_conv,
             isa::CallConv::Tail,
diff --git a/cranelift/codegen/src/isa/x64/abi.rs b/cranelift/codegen/src/isa/x64/abi.rs
index eeda5b6cd..9b8eb0764 100644
--- a/cranelift/codegen/src/isa/x64/abi.rs
+++ b/cranelift/codegen/src/isa/x64/abi.rs
@@ -101,17 +101,14 @@ impl ABIMachineSpec for X64ABIMachineSpec {
         16
     }
 
-    fn compute_arg_locs<'a, I>(
+    fn compute_arg_locs(
         call_conv: isa::CallConv,
         flags: &settings::Flags,
-        params: I,
+        params: &[ir::AbiParam],
         args_or_rets: ArgsOrRets,
         add_ret_area_ptr: bool,
-        mut args: ArgsAccumulator<'_>,
-    ) -> CodegenResult<(u32, Option<usize>)>
-    where
-        I: IntoIterator<Item = &'a ir::AbiParam>,
-    {
+        mut args: ArgsAccumulator,
+    ) -> CodegenResult<(u32, Option<usize>)> {
         let is_fastcall = call_conv.extends_windows_fastcall();
 
         let mut next_gpr = 0;
diff --git a/cranelift/codegen/src/machinst/abi.rs b/cranelift/codegen/src/machinst/abi.rs
index 8e16fdae8..4af7bc343 100644
--- a/cranelift/codegen/src/machinst/abi.rs
+++ b/cranelift/codegen/src/machinst/abi.rs
@@ -408,16 +408,14 @@ pub trait ABIMachineSpec {
     /// Returns the stack-space used (rounded up to as alignment requires), and
     /// if `add_ret_area_ptr` was passed, the index of the extra synthetic arg
     /// that was added.
-    fn compute_arg_locs<'a, I>(
+    fn compute_arg_locs(
         call_conv: isa::CallConv,
         flags: &settings::Flags,
-        params: I,
+        params: &[ir::AbiParam],
         args_or_rets: ArgsOrRets,
         add_ret_area_ptr: bool,
-        args: ArgsAccumulator<'_>,
-    ) -> CodegenResult<(u32, Option<usize>)>
-    where
-        I: IntoIterator<Item = &'a ir::AbiParam>;
+        args: ArgsAccumulator,
+    ) -> CodegenResult<(u32, Option<usize>)>;
 
     /// Returns the offset from FP to the argument area, i.e., jumping over the saved FP, return
     /// address, and maybe other standard elements depending on ABI (e.g. Wasm TLS reg).
@@ -827,8 +825,13 @@ impl SigSet {
         sig: &ir::Signature,
         flags: &settings::Flags,
     ) -> CodegenResult<SigData> {
-        let sret = missing_struct_return(sig);
-        let returns = sret.as_ref().into_iter().chain(&sig.returns);
+        use std::borrow::Cow;
+
+        let returns = if let Some(sret) = missing_struct_return(sig) {
+            Cow::from_iter(std::iter::once(&sret).chain(&sig.returns).copied())
+        } else {
+            Cow::from(sig.returns.as_slice())
+        };
 
         // Compute args and retvals from signature. Handle retvals first,
         // because we may need to add a return-area arg to the args.
@@ -839,7 +842,7 @@ impl SigSet {
         let (sized_stack_ret_space, _) = M::compute_arg_locs(
             sig.call_conv,
             flags,
-            returns,
+            &returns,
             ArgsOrRets::Rets,
             /* extra ret-area ptr = */ false,
             ArgsAccumulator::new(&mut self.abi_args),
diff --git a/crates/fuzzing/src/generators/config.rs b/crates/fuzzing/src/generators/config.rs
index c974af2d7..d54202112 100644
--- a/crates/fuzzing/src/generators/config.rs
+++ b/crates/fuzzing/src/generators/config.rs
@@ -342,7 +342,6 @@ impl Config {
     pub fn disable_unimplemented_winch_proposals(&mut self) {
         self.module_config.config.simd_enabled = false;
         self.module_config.config.relaxed_simd_enabled = false;
-        self.module_config.config.memory64_enabled = false;
         self.module_config.config.gc_enabled = false;
         self.module_config.config.threads_enabled = false;
         self.module_config.config.tail_call_enabled = false;
diff --git a/winch/codegen/src/codegen/env.rs b/winch/codegen/src/codegen/env.rs
index 978d16561..53e82fa46 100644
--- a/winch/codegen/src/codegen/env.rs
+++ b/winch/codegen/src/codegen/env.rs
@@ -328,8 +328,7 @@ impl<'a, 'translation, 'data, P: PtrSize> FuncEnv<'a, 'translation, 'data, P> {
                     current_length_offset,
                     style,
                     ty: if plan.memory.memory64 {
-                        // TODO: Add support for 64-bit memories.
-                        unimplemented!("memory64")
+                        WasmValType::I64
                     } else {
                         WasmValType::I32
                     },
diff --git a/winch/codegen/src/visitor.rs b/winch/codegen/src/visitor.rs
index 3ad1ec585..da9051302 100644
--- a/winch/codegen/src/visitor.rs
+++ b/winch/codegen/src/visitor.rs
@@ -10,6 +10,7 @@ use crate::masm::{
     DivKind, ExtendKind, FloatCmpKind, IntCmpKind, MacroAssembler, MemMoveDirection, OperandSize,
     RegImm, RemKind, RoundingMode, SPOffset, ShiftKind, TruncKind,
 };
+use crate::reg::Reg;
 use crate::stack::{TypedReg, Val};
 use cranelift_codegen::ir::TrapCode;
 use regalloc2::RegClass;
@@ -1593,8 +1594,24 @@ where
         //   [ vmctx, delta, index ]
         self.context.stack.extend([mem.try_into().unwrap()]);
 
+        let heap = self.env.resolve_heap(MemoryIndex::from_u32(mem));
         let builtin = self.env.builtins.memory32_grow::<M::ABI, M::Ptr>();
-        FnCall::emit::<M, M::Ptr>(self.masm, &mut self.context, Callee::Builtin(builtin))
+        FnCall::emit::<M, M::Ptr>(self.masm, &mut self.context, Callee::Builtin(builtin));
+
+        // The memory32_grow builtin returns a pointer type, therefore we must
+        // ensure that the return type is representative of the address space of
+        // the heap type.
+        match (self.env.ptr_type(), heap.ty) {
+            (WasmValType::I64, WasmValType::I64) => {}
+            // When the heap type is smaller than the pointer type, we adjust
+            // the result of the memory32_grow builtin.
+            (WasmValType::I64, WasmValType::I32) => {
+                let top: Reg = self.context.pop_to_reg(self.masm, None).into();
+                self.masm.wrap(top.into(), top.into());
+                self.context.stack.push(TypedReg::i32(top).into());
+            }
+            _ => unimplemented!("Support for 32-bit platforms"),
+        }
     }
 
     fn visit_data_drop(&mut self, data_index: u32) {


Test patch:
diff --git a/winch/filetests/filetests/x64/load/grow_load.wat b/winch/filetests/filetests/x64/load/grow_load.wat
new file mode 100644
index 000000000..1e1bf5e51
--- /dev/null
+++ b/winch/filetests/filetests/x64/load/grow_load.wat
@@ -0,0 +1,103 @@
+;;! target = "x86_64"
+(module
+  (type (;0;) (func (param f32 f64 i64 i64 f64 f64 f32) (result f32 f64 f32)))
+  (func (;0;) (type 0) (param f32 f64 i64 i64 f64 f64 f32) (result f32 f64 f32)
+    global.get 1
+    i32.eqz
+    if ;; label = @1
+      unreachable
+    end
+    global.get 1
+    i32.const 1
+    i32.sub
+    global.set 1
+    memory.size
+    memory.grow
+    i64.load8_s offset=143396
+    (drop)
+    (f32.const 0)
+    (f64.const 0)
+    (f32.const 0)
+  )
+  (memory (;1;) 10 10)
+  (global (;0;) f32 f32.const 0x1.d6a0d6p+87 (;=284477330000000000000000000;))
+  (global (;1;) (mut i32) i32.const 1000)
+  (export "main" (func 0))
+  (export "0" (memory 0))
+  (export "1" (global 0))
+)
+;;      	 55                   	push	rbp
+;;      	 4889e5               	mov	rbp, rsp
+;;      	 4c8b5f08             	mov	r11, qword ptr [rdi + 8]
+;;      	 4d8b1b               	mov	r11, qword ptr [r11]
+;;      	 4981c360000000       	add	r11, 0x60
+;;      	 4939e3               	cmp	r11, rsp
+;;      	 0f87f1000000         	ja	0x10c
+;;   1b:	 4989fe               	mov	r14, rdi
+;;      	 4883ec50             	sub	rsp, 0x50
+;;      	 48897c2448           	mov	qword ptr [rsp + 0x48], rdi
+;;      	 4889742440           	mov	qword ptr [rsp + 0x40], rsi
+;;      	 f30f1144243c         	movss	dword ptr [rsp + 0x3c], xmm0
+;;      	 f20f114c2430         	movsd	qword ptr [rsp + 0x30], xmm1
+;;      	 4889542428           	mov	qword ptr [rsp + 0x28], rdx
+;;      	 48894c2420           	mov	qword ptr [rsp + 0x20], rcx
+;;      	 f20f11542418         	movsd	qword ptr [rsp + 0x18], xmm2
+;;      	 f20f115c2410         	movsd	qword ptr [rsp + 0x10], xmm3
+;;      	 f30f1164240c         	movss	dword ptr [rsp + 0xc], xmm4
+;;      	 4c890424             	mov	qword ptr [rsp], r8
+;;      	 418b4670             	mov	eax, dword ptr [r14 + 0x70]
+;;      	 83f800               	cmp	eax, 0
+;;      	 b800000000           	mov	eax, 0
+;;      	 400f94c0             	sete	al
+;;      	 85c0                 	test	eax, eax
+;;      	 0f8402000000         	je	0x72
+;;   70:	 0f0b                 	ud2	
+;;      	 418b4670             	mov	eax, dword ptr [r14 + 0x70]
+;;      	 83e801               	sub	eax, 1
+;;      	 41894670             	mov	dword ptr [r14 + 0x70], eax
+;;      	 498b4658             	mov	rax, qword ptr [r14 + 0x58]
+;;      	 c1e810               	shr	eax, 0x10
+;;      	 4883ec04             	sub	rsp, 4
+;;      	 890424               	mov	dword ptr [rsp], eax
+;;      	 4d8b5e38             	mov	r11, qword ptr [r14 + 0x38]
+;;      	 498b0b               	mov	rcx, qword ptr [r11]
+;;      	 4883ec0c             	sub	rsp, 0xc
+;;      	 4c89f7               	mov	rdi, r14
+;;      	 8b74240c             	mov	esi, dword ptr [rsp + 0xc]
+;;      	 ba00000000           	mov	edx, 0
+;;      	 ffd1                 	call	rcx
+;;      	 4883c40c             	add	rsp, 0xc
+;;      	 4883c404             	add	rsp, 4
+;;      	 4c8b742448           	mov	r14, qword ptr [rsp + 0x48]
+;;      	 89c0                 	mov	eax, eax
+;;      	 498b4e50             	mov	rcx, qword ptr [r14 + 0x50]
+;;      	 4801c1               	add	rcx, rax
+;;      	 4881c124300200       	add	rcx, 0x23024
+;;      	 480fbe01             	movsx	rax, byte ptr [rcx]
+;;      	 f30f100543000000     	movss	xmm0, dword ptr [rip + 0x43]
+;;      	 4883ec0c             	sub	rsp, 0xc
+;;      	 f2440f103d3e000000   	
+;; 				movsd	xmm15, qword ptr [rip + 0x3e]
+;;      	 f2440f113c24         	movsd	qword ptr [rsp], xmm15
+;;      	 f3440f103d27000000   	
+;; 				movss	xmm15, dword ptr [rip + 0x27]
+;;      	 f3440f117c2408       	movss	dword ptr [rsp + 8], xmm15
+;;      	 488b44240c           	mov	rax, qword ptr [rsp + 0xc]
+;;      	 415b                 	pop	r11
+;;      	 4c8918               	mov	qword ptr [rax], r11
+;;      	 448b1c24             	mov	r11d, dword ptr [rsp]
+;;      	 4883c404             	add	rsp, 4
+;;      	 44895808             	mov	dword ptr [rax + 8], r11d
+;;      	 4883c450             	add	rsp, 0x50
+;;      	 5d                   	pop	rbp
+;;      	 c3                   	ret	
+;;  10c:	 0f0b                 	ud2	
+;;  10e:	 0000                 	add	byte ptr [rax], al
+;;  110:	 0000                 	add	byte ptr [rax], al
+;;  112:	 0000                 	add	byte ptr [rax], al
+;;  114:	 0000                 	add	byte ptr [rax], al
+;;  116:	 0000                 	add	byte ptr [rax], al
+;;  118:	 0000                 	add	byte ptr [rax], al
+;;  11a:	 0000                 	add	byte ptr [rax], al
+;;  11c:	 0000                 	add	byte ptr [rax], al
+;;  11e:	 0000                 	add	byte ptr [rax], al