Repository: bytecodealliance/wasmtime
Pull request #8365 (2024-04-14 15:01:51)

winch(arm64): fpu arithmetics (add, sub, mul, div, min, max) and regalloc
- Add some of the instructions in #8321
- Introduces preliminary support to FPU registers to regalloc
- Introduces tests for the instructions above (ported over from x64)
- Fixes a few typos.

This is a draft ~with a handful of tests for `float_add{32,64}` (LGTM but another pair of eyes would help), I will add the remaining later~. Added the remaining tests.

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/.github/actions/install-cargo-vet/action.yml b/.github/actions/install-cargo-vet/action.yml
index a964f79cb..7757f7895 100644
--- a/.github/actions/install-cargo-vet/action.yml
+++ b/.github/actions/install-cargo-vet/action.yml
@@ -16,5 +16,5 @@ runs:
         key: cargo-vet-bin-${{ inputs.version }}
     - run: echo "${{ runner.tool_cache }}/cargo-vet/bin" >> $GITHUB_PATH
       shell: bash
-    - run: cargo install --root ${{ runner.tool_cache }}/cargo-vet --version ${{ inputs.version }} cargo-vet
+    - run: cargo install --root ${{ runner.tool_cache }}/cargo-vet --version ${{ inputs.version }} cargo-vet --locked
       shell: bash
diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml
index 6fe81d06f..48417841f 100644
--- a/.github/workflows/main.yml
+++ b/.github/workflows/main.yml
@@ -263,10 +263,9 @@ jobs:
         key: cargo-mdbook-bin-${{ env.CARGO_MDBOOK_VERSION }}
     - run: |
         echo "${{ runner.tool_cache }}/mdbook/bin" >> $GITHUB_PATH
-        cargo install --root ${{ runner.tool_cache }}/mdbook --version ${{ env.CARGO_MDBOOK_VERSION }} mdbook
+        cargo install --root ${{ runner.tool_cache }}/mdbook --version ${{ env.CARGO_MDBOOK_VERSION }} mdbook --locked
     - run: (cd docs && mdbook build)
     - run: cargo build -p wasi-common --features wasmtime/wat,wasmtime/cranelift
-    - run: (cd docs/rust_wasi_markdown_parser && cargo build)
     - run: (cd docs && mdbook test -L ../target/debug/deps)
 
     # Build Rust API documentation.
@@ -393,7 +392,7 @@ jobs:
         path: ${{ runner.tool_cache }}/cargo-ndk
         key: cargo-ndk-bin-${{ env.CARGO_NDK_VERSION }}
     - run: echo "${{ runner.tool_cache }}/cargo-ndk/bin" >> $GITHUB_PATH
-    - run: cargo install --root ${{ runner.tool_cache }}/cargo-ndk --version ${{ env.CARGO_NDK_VERSION }} cargo-ndk
+    - run: cargo install --root ${{ runner.tool_cache }}/cargo-ndk --version ${{ env.CARGO_NDK_VERSION }} cargo-ndk --locked
     - run: cargo ndk -t arm64-v8a check -p wasmtime
 
     # Run clippy configuration
@@ -459,7 +458,7 @@ jobs:
     #
     # Install the OCaml packages necessary for fuzz targets that use the
     # `wasm-spec-interpreter`.
-    - run: cargo install cargo-fuzz --vers "^0.11"
+    - run: cargo install cargo-fuzz --vers "^0.11" --locked
     - run: sudo apt-get update && sudo apt install -y ocaml-nox ocamlbuild ocaml-findlib libzarith-ocaml-dev
     - run: cargo fetch
       working-directory: ./fuzz
@@ -470,7 +469,7 @@ jobs:
     #
     # Afterwards make sure the generated header file is up to date by ensuring
     # that the regeneration process didn't change anything in-tree.
-    - run: cargo install cbindgen --vers "^0.26"
+    - run: cargo install cbindgen --vers "^0.26" --locked
     - run: rustup component add rust-src
     - run: ./build.sh ./embedding/x86_64-unknown-unknown.json
       working-directory: ./examples/min-platform
@@ -796,7 +795,7 @@ jobs:
         path: ${{ runner.tool_cache }}/cargo-nextest
         key: cargo-nextest-bin-${{ env.CARGO_NEXTEST_VERSION }}
     - run: echo "${{ runner.tool_cache }}/cargo-nextest/bin" >> $GITHUB_PATH
-    - run: cargo install --root ${{ runner.tool_cache }}/cargo-nextest --version ${{ env.CARGO_NEXTEST_VERSION }} cargo-nextest
+    - run: cargo install --root ${{ runner.tool_cache }}/cargo-nextest --version ${{ env.CARGO_NEXTEST_VERSION }} cargo-nextest --locked
     - run: |
         cargo miri nextest run -j4 --no-fail-fast \
           -p wasmtime \
diff --git a/crates/c-api/include/wasi.h b/crates/c-api/include/wasi.h
index 1f520cb26..869f99ff6 100644
--- a/crates/c-api/include/wasi.h
+++ b/crates/c-api/include/wasi.h
@@ -168,21 +168,6 @@ WASI_API_EXTERN bool wasi_config_preopen_dir(wasi_config_t *config,
                                              const char *path,
                                              const char *guest_path);
 
-/**
- * \brief Configures a "preopened" listen socket to be available to WASI APIs.
- *
- * By default WASI programs do not have access to open up network sockets on
- * the host. This API can be used to grant WASI programs access to a network
- * socket file descriptor on the host.
- *
- * The fd_num argument is the number of the file descriptor by which it will be
- * known in WASM and the host_port is the IP address and port (e.g.
- * "127.0.0.1:8080") requested to listen on.
- */
-WASI_API_EXTERN bool wasi_config_preopen_socket(wasi_config_t *config,
-                                                uint32_t fd_num,
-                                                const char *host_port);
-
 #undef own
 
 #ifdef __cplusplus
diff --git a/crates/c-api/include/wasmtime/extern.h b/crates/c-api/include/wasmtime/extern.h
index 7cb058b7d..f94815d72 100644
--- a/crates/c-api/include/wasmtime/extern.h
+++ b/crates/c-api/include/wasmtime/extern.h
@@ -8,6 +8,7 @@
 #define WASMTIME_EXTERN_H
 
 #include <wasmtime/module.h>
+#include <wasmtime/sharedmemory.h>
 #include <wasmtime/store.h>
 
 #ifdef __cplusplus
@@ -89,8 +90,6 @@ typedef uint8_t wasmtime_extern_kind_t;
 /// shared memory
 #define WASMTIME_EXTERN_SHAREDMEMORY 4
 
-struct wasmtime_sharedmemory;
-
 /**
  * \typedef wasmtime_extern_union_t
  * \brief Convenience alias for #wasmtime_extern_union
diff --git a/crates/c-api/include/wasmtime/sharedmemory.h b/crates/c-api/include/wasmtime/sharedmemory.h
index 0c68d7403..fdea7f252 100644
--- a/crates/c-api/include/wasmtime/sharedmemory.h
+++ b/crates/c-api/include/wasmtime/sharedmemory.h
@@ -56,18 +56,6 @@ wasmtime_sharedmemory_delete(wasmtime_sharedmemory_t *memory);
 WASM_API_EXTERN wasmtime_sharedmemory_t *
 wasmtime_sharedmemory_clone(const wasmtime_sharedmemory_t *memory);
 
-/**
- * \brief Moves shared linear memory into wasmtime_extern_t object
- *
- * \param memory memory to be moved
- * \param out where to store resulting `wasmtime_extern_t`
- *
- * This function moves ownership of `memory` into resulting `wasmtime_extern_t`.
- */
-WASM_API_EXTERN void
-wasmtime_sharedmemory_into_extern(wasmtime_sharedmemory_t *memory,
-                                  wasmtime_extern_t *out);
-
 /**
  * \brief Returns the type of the shared memory specified
  */
diff --git a/crates/c-api/include/wasmtime/val.h b/crates/c-api/include/wasmtime/val.h
index 3721f6513..f923b5113 100644
--- a/crates/c-api/include/wasmtime/val.h
+++ b/crates/c-api/include/wasmtime/val.h
@@ -7,6 +7,7 @@
 #ifndef WASMTIME_VAL_H
 #define WASMTIME_VAL_H
 
+#include <stdalign.h>
 #include <wasm.h>
 #include <wasmtime/extern.h>
 
@@ -306,6 +307,16 @@ typedef union wasmtime_val_raw {
   void *funcref;
 } wasmtime_val_raw_t;
 
+// Assert that the shape of this type is as expected since it needs to match
+// Rust.
+static inline void __wasmtime_val_assertions() {
+  static_assert(sizeof(wasmtime_valunion_t) == 16, "should be 16-bytes large");
+  static_assert(__alignof(wasmtime_valunion_t) == 8,
+                "should be 8-byte aligned");
+  static_assert(sizeof(wasmtime_val_raw_t) == 16, "should be 16 bytes large");
+  static_assert(__alignof(wasmtime_val_raw_t) == 8, "should be 8-byte aligned");
+}
+
 /**
  * \typedef wasmtime_val_t
  * \brief Convenience alias for #wasmtime_val_t
diff --git a/crates/c-api/src/sharedmemory.rs b/crates/c-api/src/sharedmemory.rs
index 80aaf58c1..43d5076a9 100644
--- a/crates/c-api/src/sharedmemory.rs
+++ b/crates/c-api/src/sharedmemory.rs
@@ -1,7 +1,6 @@
-use crate::{handle_result, wasm_memorytype_t, wasmtime_error_t, wasmtime_extern_t};
+use crate::{handle_result, wasm_memorytype_t, wasmtime_error_t};
 use std::cell::UnsafeCell;
-use std::mem::MaybeUninit;
-use wasmtime::{Extern, SharedMemory};
+use wasmtime::SharedMemory;
 
 type wasmtime_sharedmemory_t = SharedMemory;
 
@@ -27,14 +26,6 @@ pub extern "C" fn wasmtime_sharedmemory_clone(
     Box::new(mem.clone())
 }
 
-#[no_mangle]
-pub extern "C" fn wasmtime_sharedmemory_into_extern(
-    mem: Box<wasmtime_sharedmemory_t>,
-    ext: &mut MaybeUninit<wasmtime_extern_t>,
-) {
-    crate::initialize(ext, Extern::from(*mem).into());
-}
-
 #[no_mangle]
 pub extern "C" fn wasmtime_sharedmemory_type(
     mem: &wasmtime_sharedmemory_t,
diff --git a/crates/c-api/src/val.rs b/crates/c-api/src/val.rs
index b57c75f99..adfe61d65 100644
--- a/crates/c-api/src/val.rs
+++ b/crates/c-api/src/val.rs
@@ -150,6 +150,11 @@ pub union wasmtime_val_union {
     pub v128: [u8; 16],
 }
 
+const _: () = {
+    assert!(std::mem::size_of::<wasmtime_val_union>() == 16);
+    assert!(std::mem::align_of::<wasmtime_val_union>() == 8);
+};
+
 // The raw pointers are actually optional boxes.
 unsafe impl Send for wasmtime_val_union
 where
diff --git a/crates/component-macro/src/bindgen.rs b/crates/component-macro/src/bindgen.rs
index d0aee83a0..9972dde34 100644
--- a/crates/component-macro/src/bindgen.rs
+++ b/crates/component-macro/src/bindgen.rs
@@ -25,7 +25,10 @@ pub fn expand(input: &Config) -> Result<TokenStream> {
         ));
     }
 
-    let mut src = input.opts.generate(&input.resolve, input.world);
+    let mut src = match input.opts.generate(&input.resolve, input.world) {
+        Ok(s) => s,
+        Err(e) => return Err(Error::new(Span::call_site(), e.to_string())),
+    };
 
     // If a magical `WASMTIME_DEBUG_BINDGEN` environment variable is set then
     // place a formatted version of the expanded code into a file. This file
diff --git a/crates/cranelift/src/compiler.rs b/crates/cranelift/src/compiler.rs
index b291a2fae..dc247b4eb 100644
--- a/crates/cranelift/src/compiler.rs
+++ b/crates/cranelift/src/compiler.rs
@@ -963,7 +963,9 @@ impl Compiler {
         // despite this load/store being unrelated to execution in wasm itself.
         // For more details on this see the `ValRaw` type in the
         // `wasmtime-runtime` crate.
-        let flags = ir::MemFlags::trusted().with_endianness(ir::Endianness::Little);
+        let flags = ir::MemFlags::new()
+            .with_notrap()
+            .with_endianness(ir::Endianness::Little);
 
         let value_size = mem::size_of::<u128>();
         for (i, (val, ty)) in values.iter().copied().zip(types).enumerate() {
@@ -1000,7 +1002,9 @@ impl Compiler {
 
         // Note that this is little-endian like `store_values_to_array` above,
         // see notes there for more information.
-        let flags = MemFlags::trusted().with_endianness(ir::Endianness::Little);
+        let flags = MemFlags::new()
+            .with_notrap()
+            .with_endianness(ir::Endianness::Little);
 
         let mut results = Vec::new();
         for (i, ty) in types.iter().enumerate() {
diff --git a/crates/runtime/src/vmcontext.rs b/crates/runtime/src/vmcontext.rs
index fbe63b402..3ae3dab64 100644
--- a/crates/runtime/src/vmcontext.rs
+++ b/crates/runtime/src/vmcontext.rs
@@ -991,13 +991,14 @@ pub union ValRaw {
 
     /// A WebAssembly `v128` value.
     ///
-    /// The payload here is a Rust `u128` which has the same number of bits but
-    /// note that `v128` in WebAssembly is often considered a vector type such
-    /// as `i32x4` or `f64x2`. This means that the actual interpretation of the
-    /// underlying bits is left up to the instructions which consume this value.
+    /// The payload here is a Rust `[u8; 16]` which has the same number of bits
+    /// but note that `v128` in WebAssembly is often considered a vector type
+    /// such as `i32x4` or `f64x2`. This means that the actual interpretation
+    /// of the underlying bits is left up to the instructions which consume
+    /// this value.
     ///
     /// This value is always stored in a little-endian format.
-    v128: u128,
+    v128: [u8; 16],
 
     /// A WebAssembly `funcref` value (or one of its subtypes).
     ///
@@ -1032,6 +1033,14 @@ pub union ValRaw {
     anyref: u32,
 }
 
+// The `ValRaw` type is matched as `wasmtime_val_raw_t` in the C API so these
+// are some simple assertions about the shape of the type which are additionally
+// matched in C.
+const _: () = {
+    assert!(std::mem::size_of::<ValRaw>() == 16);
+    assert!(std::mem::align_of::<ValRaw>() == 8);
+};
+
 // This type is just a bag-of-bits so it's up to the caller to figure out how
 // to safely deal with threading concerns and safely access interior bits.
 unsafe impl Send for ValRaw {}
@@ -1055,7 +1064,7 @@ impl std::fmt::Debug for ValRaw {
                 .field("i64", &Hex(self.i64))
                 .field("f32", &Hex(self.f32))
                 .field("f64", &Hex(self.f64))
-                .field("v128", &Hex(self.v128))
+                .field("v128", &Hex(u128::from_le_bytes(self.v128)))
                 .field("funcref", &self.funcref)
                 .field("externref", &Hex(self.externref))
                 .field("anyref", &Hex(self.anyref))
@@ -1114,7 +1123,9 @@ impl ValRaw {
     /// Creates a WebAssembly `v128` value
     #[inline]
     pub fn v128(i: u128) -> ValRaw {
-        ValRaw { v128: i.to_le() }
+        ValRaw {
+            v128: i.to_le_bytes(),
+        }
     }
 
     /// Creates a WebAssembly `funcref` value
@@ -1180,7 +1191,7 @@ impl ValRaw {
     /// Gets the WebAssembly `v128` value
     #[inline]
     pub fn get_v128(&self) -> u128 {
-        unsafe { u128::from_le(self.v128) }
+        unsafe { u128::from_le_bytes(self.v128) }
     }
 
     /// Gets the WebAssembly `funcref` value
diff --git a/crates/wit-bindgen/src/lib.rs b/crates/wit-bindgen/src/lib.rs
index 5d51c583b..6007d945e 100644
--- a/crates/wit-bindgen/src/lib.rs
+++ b/crates/wit-bindgen/src/lib.rs
@@ -50,6 +50,9 @@ struct Wasmtime {
     interface_names: HashMap<InterfaceId, InterfaceName>,
     interface_last_seen_as_import: HashMap<InterfaceId, bool>,
     trappable_errors: IndexMap<TypeId, String>,
+    // Track the with options that were used. Remapped interfaces provided via `with`
+    // are required to be used.
+    used_with_opts: HashSet<String>,
 }
 
 struct ImportFunction {
@@ -179,7 +182,7 @@ impl TrappableImports {
 }
 
 impl Opts {
-    pub fn generate(&self, resolve: &Resolve, world: WorldId) -> String {
+    pub fn generate(&self, resolve: &Resolve, world: WorldId) -> anyhow::Result<String> {
         let mut r = Wasmtime::default();
         r.sizes.fill(resolve);
         r.opts = self.clone();
@@ -270,7 +273,7 @@ impl Wasmtime {
         format!("{base}{version}")
     }
 
-    fn generate(&mut self, resolve: &Resolve, id: WorldId) -> String {
+    fn generate(&mut self, resolve: &Resolve, id: WorldId) -> anyhow::Result<String> {
         self.types.analyze(resolve, id);
         for (i, te) in self.opts.trappable_error_type.iter().enumerate() {
             let id = resolve_type_in_package(resolve, &te.wit_path)
@@ -622,7 +625,20 @@ impl Wasmtime {
         uwriteln!(self.src, "}};"); // close `const _: () = ...
     }
 
-    fn finish(&mut self, resolve: &Resolve, world: WorldId) -> String {
+    fn finish(&mut self, resolve: &Resolve, world: WorldId) -> anyhow::Result<String> {
+        let remapping_keys = self.opts.with.keys().cloned().collect::<HashSet<String>>();
+
+        let mut unused_keys = remapping_keys
+            .difference(&self.used_with_opts)
+            .map(|s| s.as_str())
+            .collect::<Vec<&str>>();
+
+        unused_keys.sort();
+
+        if !unused_keys.is_empty() {
+            anyhow::bail!("interfaces were specified in the `with` config option but are not referenced in the target world: {unused_keys:?}");
+        }
+
         if !self.opts.only_interfaces {
             self.build_struct(resolve, world)
         }
@@ -658,7 +674,7 @@ impl Wasmtime {
             assert!(status.success());
         }
 
-        src.into()
+        Ok(src.into())
     }
 
     fn emit_modules(&mut self, modules: Vec<(String, InterfaceName)>) {
@@ -700,7 +716,7 @@ impl Wasmtime {
     /// Attempts to find the `key`, possibly with the resource projection
     /// `item`, within the `with` map provided to bindings configuration.
     fn lookup_replacement(
-        &self,
+        &mut self,
         resolve: &Resolve,
         key: &WorldKey,
         item: Option<&str>,
@@ -729,7 +745,11 @@ impl Wasmtime {
                     Some(item) => format!("{key}/{item}"),
                     None => key.to_string(),
                 };
-                return self.opts.with.get(&to_lookup).cloned();
+                let result = self.opts.with.get(&to_lookup).cloned();
+                if result.is_some() {
+                    self.used_with_opts.insert(to_lookup.clone());
+                }
+                return result;
             }
         };
 
@@ -749,6 +769,7 @@ impl Wasmtime {
             if let Some(renamed) = self.opts.with.get(&lookup) {
                 projection.push(renamed.clone());
                 projection.reverse();
+                self.used_with_opts.insert(lookup);
                 return Some(projection.join("::"));
             }
             if !name.pop(resolve, &mut projection) {
@@ -1102,7 +1123,10 @@ impl<'a> InterfaceGenerator<'a> {
 
             let replacement = match self.current_interface {
                 Some((_, key, _)) => self.gen.lookup_replacement(self.resolve, key, Some(name)),
-                None => self.gen.opts.with.get(name).cloned(),
+                None => {
+                    self.gen.used_with_opts.insert(name.into());
+                    self.gen.opts.with.get(name).cloned()
+                }
             };
             match replacement {
                 Some(path) => {
diff --git a/docs/rust_wasi_markdown_parser/Cargo.toml b/docs/rust_wasi_markdown_parser/Cargo.toml
deleted file mode 100644
index a9562ff1a..000000000
--- a/docs/rust_wasi_markdown_parser/Cargo.toml
+++ /dev/null
@@ -1,10 +0,0 @@
-[package]
-name = "rust_wasi_markdown_parser"
-version = "0.1.0"
-edition = "2021"
-
-# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
-
-[dependencies]
-pulldown-cmark = "0.1.2"
-structopt = "0.3.22"
diff --git a/docs/rust_wasi_markdown_parser/example_markdown.md b/docs/rust_wasi_markdown_parser/example_markdown.md
deleted file mode 100644
index c43cf286e..000000000
--- a/docs/rust_wasi_markdown_parser/example_markdown.md
+++ /dev/null
@@ -1,3 +0,0 @@
-# Hello!
-
-I am example markdown for this demo!
diff --git a/docs/rust_wasi_markdown_parser/src/main.rs b/docs/rust_wasi_markdown_parser/src/main.rs
deleted file mode 100644
index b588b6ad4..000000000
--- a/docs/rust_wasi_markdown_parser/src/main.rs
+++ /dev/null
@@ -1,46 +0,0 @@
-// Import our CLI parsing libraries (And PathBuf for reading paths)
-extern crate structopt;
-
-use structopt::StructOpt;
-use std::path::PathBuf;
-
-// Import our markdown parser library, crate
-extern crate pulldown_cmark;
-
-use pulldown_cmark::{html, Parser};
-
-// Import from the standard library, to allow reading from the file system
-use std::fs;
-
-// Define our CLI options using structopt
-#[derive(StructOpt)]
-#[structopt(name = "rust_wasi_markdown_parser", about = "Markdown to HTML renderer CLI, written with Rust & WASI")]
-pub struct Options {
-    /// The markdown file to render
-    #[structopt(parse(from_os_str))]
-    filename: PathBuf,
-}
-
-// Our entrypoint into our WASI module
-fn main() {
-
-    // Get the passed CLI options
-    let options = Options::from_args();
-
-    // Read the markdown file into a string
-    let contents = fs::read_to_string(options.filename)
-        .expect("Something went wrong reading the file");
-
-    // Run our parsing function to get back an HTML string
-    let result = render_markdown(contents);
-
-    // Print out the resulting HTML to standard out
-    println!("{}", result);
-}
-
-pub fn render_markdown(markdown: String) -> String {
-    let mut html_buf = String::new();
-    let parser = Parser::new(&markdown[..]);
-    html::push_html(&mut html_buf, parser);
-    html_buf
-}
diff --git a/winch/codegen/src/isa/aarch64/abi.rs b/winch/codegen/src/isa/aarch64/abi.rs
index 50a00f4ca..8dafe17a2 100644
--- a/winch/codegen/src/isa/aarch64/abi.rs
+++ b/winch/codegen/src/isa/aarch64/abi.rs
@@ -118,7 +118,7 @@ impl ABI for Aarch64ABI {
     }
 
     fn float_scratch_reg() -> Reg {
-        todo!()
+        regs::float_scratch()
     }
 
     fn vmctx_reg() -> Reg {
diff --git a/winch/codegen/src/isa/aarch64/asm.rs b/winch/codegen/src/isa/aarch64/asm.rs
index c6deb1778..a3c259368 100644
--- a/winch/codegen/src/isa/aarch64/asm.rs
+++ b/winch/codegen/src/isa/aarch64/asm.rs
@@ -2,6 +2,7 @@
 
 use super::{address::Address, regs};
 use crate::{masm::OperandSize, reg::Reg};
+use cranelift_codegen::isa::aarch64::inst::{FPUOp2, ScalarSize};
 use cranelift_codegen::{
     ir::{MemFlags, SourceLoc},
     isa::aarch64::inst::{
@@ -22,6 +23,17 @@ impl From<OperandSize> for inst::OperandSize {
         }
     }
 }
+impl Into<ScalarSize> for OperandSize {
+    fn into(self) -> ScalarSize {
+        match self {
+            OperandSize::S8 => ScalarSize::Size8,
+            OperandSize::S16 => ScalarSize::Size16,
+            OperandSize::S32 => ScalarSize::Size32,
+            OperandSize::S64 => ScalarSize::Size64,
+            OperandSize::S128 => ScalarSize::Size128,
+        }
+    }
+}
 
 /// Low level assembler implementation for Aarch64.
 pub(crate) struct Assembler {
@@ -149,6 +161,23 @@ impl Assembler {
         });
     }
 
+    pub fn fmov64_rr(&mut self, rm: Reg, rd: Reg) {
+        let writable_rd = Writable::from_reg(rd.into());
+        self.emit(Inst::FpuMove64 {
+            rd: writable_rd,
+            rn: rm.into(),
+        })
+    }
+
+    pub fn mov_to_fpu(&mut self, rn: Reg, rd: Reg, size: OperandSize) {
+        let writable_rd = Writable::from_reg(rd.into());
+        self.emit(Inst::MovToFpu {
+            size: size.into(),
+            rd: writable_rd,
+            rn: rn.into(),
+        });
+    }
+
     /// Add with three registers.
     pub fn add_rrr(&mut self, rm: Reg, rn: Reg, rd: Reg, size: OperandSize) {
         self.emit_alu_rrr_extend(ALUOp::Add, rm, rn, rd, size);
@@ -195,6 +224,36 @@ impl Assembler {
         self.emit_alu_rrrr(ALUOp3::MAdd, scratch, rn, rd, regs::zero(), size);
     }
 
+    /// Float add with three registers.
+    pub fn fadd_rrr(&mut self, rm: Reg, rn: Reg, rd: Reg, size: OperandSize) {
+        self.emit_fpu_rrr(FPUOp2::Add, rm, rn, rd, size);
+    }
+
+    /// Float sub with three registers.
+    pub fn fsub_rrr(&mut self, rm: Reg, rn: Reg, rd: Reg, size: OperandSize) {
+        self.emit_fpu_rrr(FPUOp2::Sub, rm, rn, rd, size);
+    }
+
+    /// Float multiply with three registers.
+    pub fn fmul_rrr(&mut self, rm: Reg, rn: Reg, rd: Reg, size: OperandSize) {
+        self.emit_fpu_rrr(FPUOp2::Mul, rm, rn, rd, size);
+    }
+
+    /// Float division with three registers.
+    pub fn fdiv_rrr(&mut self, rm: Reg, rn: Reg, rd: Reg, size: OperandSize) {
+        self.emit_fpu_rrr(FPUOp2::Div, rm, rn, rd, size);
+    }
+
+    /// Float max with three registers.
+    pub fn fmax_rrr(&mut self, rm: Reg, rn: Reg, rd: Reg, size: OperandSize) {
+        self.emit_fpu_rrr(FPUOp2::Max, rm, rn, rd, size);
+    }
+
+    /// Float min with three registers.
+    pub fn fmin_rrr(&mut self, rm: Reg, rn: Reg, rd: Reg, size: OperandSize) {
+        self.emit_fpu_rrr(FPUOp2::Min, rm, rn, rd, size);
+    }
+
     /// Return instruction.
     pub fn ret(&mut self) {
         self.emit(Inst::Ret {});
@@ -234,6 +293,16 @@ impl Assembler {
         });
     }
 
+    fn emit_fpu_rrr(&mut self, op: FPUOp2, rm: Reg, rn: Reg, rd: Reg, size: OperandSize) {
+        self.emit(Inst::FpuRRR {
+            fpu_op: op,
+            size: size.into(),
+            rd: Writable::from_reg(rd.into()),
+            rn: rn.into(),
+            rm: rm.into(),
+        });
+    }
+
     /// Get a label from the underlying machine code buffer.
     pub fn get_label(&mut self) -> MachLabel {
         self.buffer.get_label()
diff --git a/winch/codegen/src/isa/aarch64/masm.rs b/winch/codegen/src/isa/aarch64/masm.rs
index 0a106d582..6fab3ae89 100644
--- a/winch/codegen/src/isa/aarch64/masm.rs
+++ b/winch/codegen/src/isa/aarch64/masm.rs
@@ -14,6 +14,7 @@ use cranelift_codegen::{
     ir::{RelSourceLoc, SourceLoc},
     settings, Final, MachBufferFinalized, MachLabel,
 };
+use regalloc2::RegClass;
 use wasmtime_environ::PtrSize;
 
 /// Aarch64 MacroAssembler.
@@ -197,16 +198,25 @@ impl Masm for MacroAssembler {
                 let imm = match v {
                     I::I32(v) => v as u64,
                     I::I64(v) => v,
-                    _ => panic!(),
+                    I::F32(v) => v as u64,
+                    I::F64(v) => v,
                 };
 
                 let scratch = regs::scratch();
                 self.asm.load_constant(imm, scratch);
-                self.asm.mov_rr(scratch, rd, size);
-            }
-            (RegImm::Reg(rs), rd) => {
-                self.asm.mov_rr(rs, rd, size);
+                match rd.class() {
+                    RegClass::Int => self.asm.mov_rr(scratch, rd, size),
+                    RegClass::Float => self.asm.mov_to_fpu(scratch, rd, size),
+                    _ => todo!(),
+                }
             }
+            (RegImm::Reg(rs), rd) => match (rs.class(), rd.class()) {
+                (RegClass::Int, RegClass::Int) => self.asm.mov_rr(rs, rd, size),
+                // TODO: verify whether we should use `fmov sd, sn` for F32.
+                (RegClass::Float, RegClass::Float) => self.asm.fmov64_rr(rs, rd),
+                (RegClass::Int, RegClass::Float) => self.asm.mov_to_fpu(rs, rd, size),
+                _ => todo!(),
+            },
         }
     }
 
@@ -279,28 +289,28 @@ impl Masm for MacroAssembler {
         }
     }
 
-    fn float_add(&mut self, _dst: Reg, _lhs: Reg, _rhs: Reg, _size: OperandSize) {
-        todo!()
+    fn float_add(&mut self, dst: Reg, lhs: Reg, rhs: Reg, size: OperandSize) {
+        self.asm.fadd_rrr(rhs, lhs, dst, size);
     }
 
-    fn float_sub(&mut self, _dst: Reg, _lhs: Reg, _rhs: Reg, _size: OperandSize) {
-        todo!()
+    fn float_sub(&mut self, dst: Reg, lhs: Reg, rhs: Reg, size: OperandSize) {
+        self.asm.fsub_rrr(rhs, lhs, dst, size);
     }
 
-    fn float_mul(&mut self, _dst: Reg, _lhs: Reg, _rhs: Reg, _size: OperandSize) {
-        todo!()
+    fn float_mul(&mut self, dst: Reg, lhs: Reg, rhs: Reg, size: OperandSize) {
+        self.asm.fmul_rrr(rhs, lhs, dst, size);
     }
 
-    fn float_div(&mut self, _dst: Reg, _lhs: Reg, _rhs: Reg, _size: OperandSize) {
-        todo!()
+    fn float_div(&mut self, dst: Reg, lhs: Reg, rhs: Reg, size: OperandSize) {
+        self.asm.fdiv_rrr(rhs, lhs, dst, size);
     }
 
-    fn float_min(&mut self, _dst: Reg, _lhs: Reg, _rhs: Reg, _size: OperandSize) {
-        todo!()
+    fn float_min(&mut self, dst: Reg, lhs: Reg, rhs: Reg, size: OperandSize) {
+        self.asm.fmin_rrr(rhs, lhs, dst, size);
     }
 
-    fn float_max(&mut self, _dst: Reg, _lhs: Reg, _rhs: Reg, _size: OperandSize) {
-        todo!()
+    fn float_max(&mut self, dst: Reg, lhs: Reg, rhs: Reg, size: OperandSize) {
+        self.asm.fmax_rrr(rhs, lhs, dst, size);
     }
 
     fn float_copysign(&mut self, _dst: Reg, _lhs: Reg, _rhs: Reg, _size: OperandSize) {
diff --git a/winch/codegen/src/isa/aarch64/mod.rs b/winch/codegen/src/isa/aarch64/mod.rs
index 6dfa9a2a5..e955460ad 100644
--- a/winch/codegen/src/isa/aarch64/mod.rs
+++ b/winch/codegen/src/isa/aarch64/mod.rs
@@ -1,4 +1,5 @@
 use self::regs::{ALL_GPR, MAX_FPR, MAX_GPR, NON_ALLOCATABLE_GPR};
+use crate::isa::aarch64::regs::{ALL_FPR, NON_ALLOCATABLE_FPR};
 use crate::{
     abi::{wasm_sig, ABI},
     codegen::{CodeGen, CodeGenContext, FuncEnv, TypeConverter},
@@ -116,8 +117,11 @@ impl TargetIsa for Aarch64 {
             NON_ALLOCATABLE_GPR.into(),
             usize::try_from(MAX_GPR).unwrap(),
         );
-        // TODO: Add floating point bitmask
-        let fpr = RegBitSet::float(0, 0, usize::try_from(MAX_FPR).unwrap());
+        let fpr = RegBitSet::float(
+            ALL_FPR.into(),
+            NON_ALLOCATABLE_FPR.into(),
+            usize::try_from(MAX_FPR).unwrap(),
+        );
         let regalloc = RegAlloc::from(gpr, fpr);
         let codegen_context = CodeGenContext::new(regalloc, stack, frame, &vmoffsets);
         let mut codegen = CodeGen::new(&mut masm, codegen_context, env, abi_sig);
diff --git a/winch/codegen/src/isa/aarch64/regs.rs b/winch/codegen/src/isa/aarch64/regs.rs
index 1193af020..00f317fb0 100644
--- a/winch/codegen/src/isa/aarch64/regs.rs
+++ b/winch/codegen/src/isa/aarch64/regs.rs
@@ -31,6 +31,11 @@ pub(crate) const fn scratch() -> Reg {
     ip0()
 }
 
+// Alias to register v31.
+pub(crate) const fn float_scratch() -> Reg {
+    vreg(31)
+}
+
 /// Scratch register.
 /// Intra-procedure-call corruptible register.
 pub(crate) const fn ip1() -> Reg {
@@ -135,7 +140,7 @@ pub(crate) const fn shadow_sp() -> Reg {
     xreg(28)
 }
 
-/// Bitmask for non-allocatble GPR.
+/// Bitmask for non-allocatable GPR.
 pub(crate) const NON_ALLOCATABLE_GPR: u32 = (1 << ip0().hw_enc())
     | (1 << ip1().hw_enc())
     | (1 << platform().hw_enc())
@@ -147,3 +152,10 @@ pub(crate) const NON_ALLOCATABLE_GPR: u32 = (1 << ip0().hw_enc())
 
 /// Bitmask to represent the available general purpose registers.
 pub(crate) const ALL_GPR: u32 = u32::MAX & !NON_ALLOCATABLE_GPR;
+
+/// Bitmask for non-allocatable FPR.
+/// All FPRs are allocatable, v0..=v7 are generally used for params and results.
+pub(crate) const NON_ALLOCATABLE_FPR: u32 = 1 << float_scratch().hw_enc();
+
+/// Bitmask to represent the available floating point registers.
+pub(crate) const ALL_FPR: u32 = u32::MAX & !NON_ALLOCATABLE_FPR;
diff --git a/winch/codegen/src/regalloc.rs b/winch/codegen/src/regalloc.rs
index 578fea6b5..a95cf106e 100644
--- a/winch/codegen/src/regalloc.rs
+++ b/winch/codegen/src/regalloc.rs
@@ -35,7 +35,7 @@ impl RegAlloc {
         self.regset.reg_for_class(class).unwrap_or_else(|| {
             spill(self);
             self.regset.reg_for_class(class).unwrap_or_else(|| {
-                panic!("expected register for class {:?}, to be avilable", class)
+                panic!("expected register for class {:?}, to be available", class)
             })
         })
     }
diff --git a/winch/codegen/src/regset.rs b/winch/codegen/src/regset.rs
index 0f51dc2ba..0e39d010f 100644
--- a/winch/codegen/src/regset.rs
+++ b/winch/codegen/src/regset.rs
@@ -1,6 +1,6 @@
 use crate::isa::reg::{Reg, RegClass};
 
-/// A bit set to track regiter availability.
+/// A bit set to track register availability.
 pub(crate) struct RegSet {
     /// Bitset to track general purpose register availability.
     gpr: RegBitSet,


Test patch:
diff --git a/tests/disas/winch/aarch64/f32_add/const.wat b/tests/disas/winch/aarch64/f32_add/const.wat
new file mode 100644
index 000000000..9c1cfb1df
--- /dev/null
+++ b/tests/disas/winch/aarch64/f32_add/const.wat
@@ -0,0 +1,31 @@
+;;! target = "aarch64"
+;;! test = "winch"
+
+(module
+    (func (result f32)
+        (f32.const 1.1)
+        (f32.const 2.2)
+        (f32.add)
+    )
+)
+;; wasm[0]::function[0]:
+;;       stp     x29, x30, [sp, #-0x10]!
+;;       mov     x29, sp
+;;       mov     x28, sp
+;;       mov     x9, x0
+;;       sub     sp, sp, #0x10
+;;       mov     x28, sp
+;;       stur    x0, [x28, #8]
+;;       stur    x1, [x28]
+;;       mov     w16, #0xcccd
+;;       movk    w16, #0x400c, lsl #16
+;;       fmov    s0, w16
+;;       mov     w16, #0xcccd
+;;       movk    w16, #0x3f8c, lsl #16
+;;       fmov    s1, w16
+;;       fadd    s1, s1, s0
+;;       fmov    d0, d1
+;;       add     sp, sp, #0x10
+;;       mov     x28, sp
+;;       ldp     x29, x30, [sp], #0x10
+;;       ret
diff --git a/tests/disas/winch/aarch64/f32_add/locals.wat b/tests/disas/winch/aarch64/f32_add/locals.wat
new file mode 100644
index 000000000..046ab1158
--- /dev/null
+++ b/tests/disas/winch/aarch64/f32_add/locals.wat
@@ -0,0 +1,46 @@
+;;! target = "aarch64"
+;;! test = "winch"
+
+(module
+    (func (result f32)
+        (local $foo f32)  
+        (local $bar f32)
+
+        (f32.const 1.1)
+        (local.set $foo)
+
+        (f32.const 2.2)
+        (local.set $bar)
+
+        (local.get $foo)
+        (local.get $bar)
+        f32.add
+    )
+)
+;; wasm[0]::function[0]:
+;;       stp     x29, x30, [sp, #-0x10]!
+;;       mov     x29, sp
+;;       mov     x28, sp
+;;       mov     x9, x0
+;;       sub     sp, sp, #0x18
+;;       mov     x28, sp
+;;       stur    x0, [x28, #0x10]
+;;       stur    x1, [x28, #8]
+;;       mov     x16, #0
+;;       stur    x16, [x28]
+;;       mov     w16, #0xcccd
+;;       movk    w16, #0x3f8c, lsl #16
+;;       fmov    s0, w16
+;;       stur    w0, [x28, #4]
+;;       mov     w16, #0xcccd
+;;       movk    w16, #0x400c, lsl #16
+;;       fmov    s0, w16
+;;       stur    w0, [x28]
+;;       ldur    w0, [x28]
+;;       ldur    w1, [x28, #4]
+;;       fadd    s1, s1, s0
+;;       fmov    d0, d1
+;;       add     sp, sp, #0x18
+;;       mov     x28, sp
+;;       ldp     x29, x30, [sp], #0x10
+;;       ret
\ No newline at end of file
diff --git a/tests/disas/winch/aarch64/f32_add/params.wat b/tests/disas/winch/aarch64/f32_add/params.wat
new file mode 100644
index 000000000..49b401a1d
--- /dev/null
+++ b/tests/disas/winch/aarch64/f32_add/params.wat
@@ -0,0 +1,29 @@
+;;! target = "aarch64"
+;;! test = "winch"
+
+(module
+    (func (param f32) (param f32) (result f32)
+        (local.get 0)
+        (local.get 1)
+        (f32.add)
+    )
+)
+;; wasm[0]::function[0]:
+;;       stp     x29, x30, [sp, #-0x10]!
+;;       mov     x29, sp
+;;       mov     x28, sp
+;;       mov     x9, x0
+;;       sub     sp, sp, #0x18
+;;       mov     x28, sp
+;;       stur    x0, [x28, #0x10]
+;;       stur    x1, [x28, #8]
+;;       stur    w0, [x28, #4]
+;;       stur    w1, [x28]
+;;       ldur    w0, [x28]
+;;       ldur    w1, [x28, #4]
+;;       fadd    s1, s1, s0
+;;       fmov    d0, d1
+;;       add     sp, sp, #0x18
+;;       mov     x28, sp
+;;       ldp     x29, x30, [sp], #0x10
+;;       ret
\ No newline at end of file
diff --git a/tests/disas/winch/aarch64/f32_div/const.wat b/tests/disas/winch/aarch64/f32_div/const.wat
new file mode 100644
index 000000000..a2aa63a18
--- /dev/null
+++ b/tests/disas/winch/aarch64/f32_div/const.wat
@@ -0,0 +1,31 @@
+;;! target = "aarch64"
+;;! test = "winch"
+
+(module
+    (func (result f32)
+        (f32.const 1.1)
+        (f32.const 2.2)
+        (f32.div)
+    )
+)
+;; wasm[0]::function[0]:
+;;       stp     x29, x30, [sp, #-0x10]!
+;;       mov     x29, sp
+;;       mov     x28, sp
+;;       mov     x9, x0
+;;       sub     sp, sp, #0x10
+;;       mov     x28, sp
+;;       stur    x0, [x28, #8]
+;;       stur    x1, [x28]
+;;       mov     w16, #0xcccd
+;;       movk    w16, #0x400c, lsl #16
+;;       fmov    s0, w16
+;;       mov     w16, #0xcccd
+;;       movk    w16, #0x3f8c, lsl #16
+;;       fmov    s1, w16
+;;       fdiv    s1, s1, s0
+;;       fmov    d0, d1
+;;       add     sp, sp, #0x10
+;;       mov     x28, sp
+;;       ldp     x29, x30, [sp], #0x10
+;;       ret
diff --git a/tests/disas/winch/aarch64/f32_div/locals.wat b/tests/disas/winch/aarch64/f32_div/locals.wat
new file mode 100644
index 000000000..91aad5f7f
--- /dev/null
+++ b/tests/disas/winch/aarch64/f32_div/locals.wat
@@ -0,0 +1,46 @@
+;;! target = "aarch64"
+;;! test = "winch"
+
+(module
+    (func (result f32)
+        (local $foo f32)  
+        (local $bar f32)
+
+        (f32.const 1.1)
+        (local.set $foo)
+
+        (f32.const 2.2)
+        (local.set $bar)
+
+        (local.get $foo)
+        (local.get $bar)
+        f32.div
+    )
+)
+;; wasm[0]::function[0]:
+;;       stp     x29, x30, [sp, #-0x10]!
+;;       mov     x29, sp
+;;       mov     x28, sp
+;;       mov     x9, x0
+;;       sub     sp, sp, #0x18
+;;       mov     x28, sp
+;;       stur    x0, [x28, #0x10]
+;;       stur    x1, [x28, #8]
+;;       mov     x16, #0
+;;       stur    x16, [x28]
+;;       mov     w16, #0xcccd
+;;       movk    w16, #0x3f8c, lsl #16
+;;       fmov    s0, w16
+;;       stur    w0, [x28, #4]
+;;       mov     w16, #0xcccd
+;;       movk    w16, #0x400c, lsl #16
+;;       fmov    s0, w16
+;;       stur    w0, [x28]
+;;       ldur    w0, [x28]
+;;       ldur    w1, [x28, #4]
+;;       fdiv    s1, s1, s0
+;;       fmov    d0, d1
+;;       add     sp, sp, #0x18
+;;       mov     x28, sp
+;;       ldp     x29, x30, [sp], #0x10
+;;       ret
diff --git a/tests/disas/winch/aarch64/f32_div/params.wat b/tests/disas/winch/aarch64/f32_div/params.wat
new file mode 100644
index 000000000..3d84a0e04
--- /dev/null
+++ b/tests/disas/winch/aarch64/f32_div/params.wat
@@ -0,0 +1,29 @@
+;;! target = "aarch64"
+;;! test = "winch"
+
+(module
+    (func (param f32) (param f32) (result f32)
+        (local.get 0)
+        (local.get 1)
+        (f32.div)
+    )
+)
+;; wasm[0]::function[0]:
+;;       stp     x29, x30, [sp, #-0x10]!
+;;       mov     x29, sp
+;;       mov     x28, sp
+;;       mov     x9, x0
+;;       sub     sp, sp, #0x18
+;;       mov     x28, sp
+;;       stur    x0, [x28, #0x10]
+;;       stur    x1, [x28, #8]
+;;       stur    w0, [x28, #4]
+;;       stur    w1, [x28]
+;;       ldur    w0, [x28]
+;;       ldur    w1, [x28, #4]
+;;       fdiv    s1, s1, s0
+;;       fmov    d0, d1
+;;       add     sp, sp, #0x18
+;;       mov     x28, sp
+;;       ldp     x29, x30, [sp], #0x10
+;;       ret
\ No newline at end of file
diff --git a/tests/disas/winch/aarch64/f32_max/const.wat b/tests/disas/winch/aarch64/f32_max/const.wat
new file mode 100644
index 000000000..1437d66cd
--- /dev/null
+++ b/tests/disas/winch/aarch64/f32_max/const.wat
@@ -0,0 +1,31 @@
+;;! target = "aarch64"
+;;! test = "winch"
+
+(module
+    (func (result f32)
+        (f32.const 1.1)
+        (f32.const 2.2)
+        (f32.max)
+    )
+)
+;; wasm[0]::function[0]:
+;;       stp     x29, x30, [sp, #-0x10]!
+;;       mov     x29, sp
+;;       mov     x28, sp
+;;       mov     x9, x0
+;;       sub     sp, sp, #0x10
+;;       mov     x28, sp
+;;       stur    x0, [x28, #8]
+;;       stur    x1, [x28]
+;;       mov     w16, #0xcccd
+;;       movk    w16, #0x400c, lsl #16
+;;       fmov    s0, w16
+;;       mov     w16, #0xcccd
+;;       movk    w16, #0x3f8c, lsl #16
+;;       fmov    s1, w16
+;;       fmax    s1, s1, s0
+;;       fmov    d0, d1
+;;       add     sp, sp, #0x10
+;;       mov     x28, sp
+;;       ldp     x29, x30, [sp], #0x10
+;;       ret
diff --git a/tests/disas/winch/aarch64/f32_max/locals.wat b/tests/disas/winch/aarch64/f32_max/locals.wat
new file mode 100644
index 000000000..5ca81e7b0
--- /dev/null
+++ b/tests/disas/winch/aarch64/f32_max/locals.wat
@@ -0,0 +1,46 @@
+;;! target = "aarch64"
+;;! test = "winch"
+
+(module
+    (func (result f32)
+        (local $foo f32)  
+        (local $bar f32)
+
+        (f32.const 1.1)
+        (local.set $foo)
+
+        (f32.const 2.2)
+        (local.set $bar)
+
+        (local.get $foo)
+        (local.get $bar)
+        f32.max
+    )
+)
+;; wasm[0]::function[0]:
+;;       stp     x29, x30, [sp, #-0x10]!
+;;       mov     x29, sp
+;;       mov     x28, sp
+;;       mov     x9, x0
+;;       sub     sp, sp, #0x18
+;;       mov     x28, sp
+;;       stur    x0, [x28, #0x10]
+;;       stur    x1, [x28, #8]
+;;       mov     x16, #0
+;;       stur    x16, [x28]
+;;       mov     w16, #0xcccd
+;;       movk    w16, #0x3f8c, lsl #16
+;;       fmov    s0, w16
+;;       stur    w0, [x28, #4]
+;;       mov     w16, #0xcccd
+;;       movk    w16, #0x400c, lsl #16
+;;       fmov    s0, w16
+;;       stur    w0, [x28]
+;;       ldur    w0, [x28]
+;;       ldur    w1, [x28, #4]
+;;       fmax    s1, s1, s0
+;;       fmov    d0, d1
+;;       add     sp, sp, #0x18
+;;       mov     x28, sp
+;;       ldp     x29, x30, [sp], #0x10
+;;       ret
diff --git a/tests/disas/winch/aarch64/f32_max/params.wat b/tests/disas/winch/aarch64/f32_max/params.wat
new file mode 100644
index 000000000..47347971d
--- /dev/null
+++ b/tests/disas/winch/aarch64/f32_max/params.wat
@@ -0,0 +1,29 @@
+;;! target = "aarch64"
+;;! test = "winch"
+
+(module
+    (func (param f32) (param f32) (result f32)
+        (local.get 0)
+        (local.get 1)
+        (f32.max)
+    )
+)
+;; wasm[0]::function[0]:
+;;       stp     x29, x30, [sp, #-0x10]!
+;;       mov     x29, sp
+;;       mov     x28, sp
+;;       mov     x9, x0
+;;       sub     sp, sp, #0x18
+;;       mov     x28, sp
+;;       stur    x0, [x28, #0x10]
+;;       stur    x1, [x28, #8]
+;;       stur    w0, [x28, #4]
+;;       stur    w1, [x28]
+;;       ldur    w0, [x28]
+;;       ldur    w1, [x28, #4]
+;;       fmax    s1, s1, s0
+;;       fmov    d0, d1
+;;       add     sp, sp, #0x18
+;;       mov     x28, sp
+;;       ldp     x29, x30, [sp], #0x10
+;;       ret
diff --git a/tests/disas/winch/aarch64/f32_min/const.wat b/tests/disas/winch/aarch64/f32_min/const.wat
new file mode 100644
index 000000000..b8a3d3d6b
--- /dev/null
+++ b/tests/disas/winch/aarch64/f32_min/const.wat
@@ -0,0 +1,31 @@
+;;! target = "aarch64"
+;;! test = "winch"
+
+(module
+    (func (result f32)
+        (f32.const 1.1)
+        (f32.const 2.2)
+        (f32.min)
+    )
+)
+;; wasm[0]::function[0]:
+;;       stp     x29, x30, [sp, #-0x10]!
+;;       mov     x29, sp
+;;       mov     x28, sp
+;;       mov     x9, x0
+;;       sub     sp, sp, #0x10
+;;       mov     x28, sp
+;;       stur    x0, [x28, #8]
+;;       stur    x1, [x28]
+;;       mov     w16, #0xcccd
+;;       movk    w16, #0x400c, lsl #16
+;;       fmov    s0, w16
+;;       mov     w16, #0xcccd
+;;       movk    w16, #0x3f8c, lsl #16
+;;       fmov    s1, w16
+;;       fmin    s1, s1, s0
+;;       fmov    d0, d1
+;;       add     sp, sp, #0x10
+;;       mov     x28, sp
+;;       ldp     x29, x30, [sp], #0x10
+;;       ret
diff --git a/tests/disas/winch/aarch64/f32_min/locals.wat b/tests/disas/winch/aarch64/f32_min/locals.wat
new file mode 100644
index 000000000..aa7d41de1
--- /dev/null
+++ b/tests/disas/winch/aarch64/f32_min/locals.wat
@@ -0,0 +1,46 @@
+;;! target = "aarch64"
+;;! test = "winch"
+
+(module
+    (func (result f32)
+        (local $foo f32)  
+        (local $bar f32)
+
+        (f32.const 1.1)
+        (local.set $foo)
+
+        (f32.const 2.2)
+        (local.set $bar)
+
+        (local.get $foo)
+        (local.get $bar)
+        f32.min
+    )
+)
+;; wasm[0]::function[0]:
+;;       stp     x29, x30, [sp, #-0x10]!
+;;       mov     x29, sp
+;;       mov     x28, sp
+;;       mov     x9, x0
+;;       sub     sp, sp, #0x18
+;;       mov     x28, sp
+;;       stur    x0, [x28, #0x10]
+;;       stur    x1, [x28, #8]
+;;       mov     x16, #0
+;;       stur    x16, [x28]
+;;       mov     w16, #0xcccd
+;;       movk    w16, #0x3f8c, lsl #16
+;;       fmov    s0, w16
+;;       stur    w0, [x28, #4]
+;;       mov     w16, #0xcccd
+;;       movk    w16, #0x400c, lsl #16
+;;       fmov    s0, w16
+;;       stur    w0, [x28]
+;;       ldur    w0, [x28]
+;;       ldur    w1, [x28, #4]
+;;       fmin    s1, s1, s0
+;;       fmov    d0, d1
+;;       add     sp, sp, #0x18
+;;       mov     x28, sp
+;;       ldp     x29, x30, [sp], #0x10
+;;       ret
diff --git a/tests/disas/winch/aarch64/f32_min/params.wat b/tests/disas/winch/aarch64/f32_min/params.wat
new file mode 100644
index 000000000..c402f6a04
--- /dev/null
+++ b/tests/disas/winch/aarch64/f32_min/params.wat
@@ -0,0 +1,29 @@
+;;! target = "aarch64"
+;;! test = "winch"
+
+(module
+    (func (param f32) (param f32) (result f32)
+        (local.get 0)
+        (local.get 1)
+        (f32.min)
+    )
+)
+;; wasm[0]::function[0]:
+;;       stp     x29, x30, [sp, #-0x10]!
+;;       mov     x29, sp
+;;       mov     x28, sp
+;;       mov     x9, x0
+;;       sub     sp, sp, #0x18
+;;       mov     x28, sp
+;;       stur    x0, [x28, #0x10]
+;;       stur    x1, [x28, #8]
+;;       stur    w0, [x28, #4]
+;;       stur    w1, [x28]
+;;       ldur    w0, [x28]
+;;       ldur    w1, [x28, #4]
+;;       fmin    s1, s1, s0
+;;       fmov    d0, d1
+;;       add     sp, sp, #0x18
+;;       mov     x28, sp
+;;       ldp     x29, x30, [sp], #0x10
+;;       ret
diff --git a/tests/disas/winch/aarch64/f32_mul/const.wat b/tests/disas/winch/aarch64/f32_mul/const.wat
new file mode 100644
index 000000000..c73529ff1
--- /dev/null
+++ b/tests/disas/winch/aarch64/f32_mul/const.wat
@@ -0,0 +1,31 @@
+;;! target = "aarch64"
+;;! test = "winch"
+
+(module
+    (func (result f32)
+        (f32.const 1.1)
+        (f32.const 2.2)
+        (f32.mul)
+    )
+)
+;; wasm[0]::function[0]:
+;;       stp     x29, x30, [sp, #-0x10]!
+;;       mov     x29, sp
+;;       mov     x28, sp
+;;       mov     x9, x0
+;;       sub     sp, sp, #0x10
+;;       mov     x28, sp
+;;       stur    x0, [x28, #8]
+;;       stur    x1, [x28]
+;;       mov     w16, #0xcccd
+;;       movk    w16, #0x400c, lsl #16
+;;       fmov    s0, w16
+;;       mov     w16, #0xcccd
+;;       movk    w16, #0x3f8c, lsl #16
+;;       fmov    s1, w16
+;;       fmul    s1, s1, s0
+;;       fmov    d0, d1
+;;       add     sp, sp, #0x10
+;;       mov     x28, sp
+;;       ldp     x29, x30, [sp], #0x10
+;;       ret
diff --git a/tests/disas/winch/aarch64/f32_mul/locals.wat b/tests/disas/winch/aarch64/f32_mul/locals.wat
new file mode 100644
index 000000000..ff7bea88f
--- /dev/null
+++ b/tests/disas/winch/aarch64/f32_mul/locals.wat
@@ -0,0 +1,46 @@
+;;! target = "aarch64"
+;;! test = "winch"
+
+(module
+    (func (result f32)
+        (local $foo f32)  
+        (local $bar f32)
+
+        (f32.const 1.1)
+        (local.set $foo)
+
+        (f32.const 2.2)
+        (local.set $bar)
+
+        (local.get $foo)
+        (local.get $bar)
+        f32.mul
+    )
+)
+;; wasm[0]::function[0]:
+;;       stp     x29, x30, [sp, #-0x10]!
+;;       mov     x29, sp
+;;       mov     x28, sp
+;;       mov     x9, x0
+;;       sub     sp, sp, #0x18
+;;       mov     x28, sp
+;;       stur    x0, [x28, #0x10]
+;;       stur    x1, [x28, #8]
+;;       mov     x16, #0
+;;       stur    x16, [x28]
+;;       mov     w16, #0xcccd
+;;       movk    w16, #0x3f8c, lsl #16
+;;       fmov    s0, w16
+;;       stur    w0, [x28, #4]
+;;       mov     w16, #0xcccd
+;;       movk    w16, #0x400c, lsl #16
+;;       fmov    s0, w16
+;;       stur    w0, [x28]
+;;       ldur    w0, [x28]
+;;       ldur    w1, [x28, #4]
+;;       fmul    s1, s1, s0
+;;       fmov    d0, d1
+;;       add     sp, sp, #0x18
+;;       mov     x28, sp
+;;       ldp     x29, x30, [sp], #0x10
+;;       ret
diff --git a/tests/disas/winch/aarch64/f32_mul/params.wat b/tests/disas/winch/aarch64/f32_mul/params.wat
new file mode 100644
index 000000000..7b8a5571d
--- /dev/null
+++ b/tests/disas/winch/aarch64/f32_mul/params.wat
@@ -0,0 +1,29 @@
+;;! target = "aarch64"
+;;! test = "winch"
+
+(module
+    (func (param f32) (param f32) (result f32)
+        (local.get 0)
+        (local.get 1)
+        (f32.mul)
+    )
+)
+;; wasm[0]::function[0]:
+;;       stp     x29, x30, [sp, #-0x10]!
+;;       mov     x29, sp
+;;       mov     x28, sp
+;;       mov     x9, x0
+;;       sub     sp, sp, #0x18
+;;       mov     x28, sp
+;;       stur    x0, [x28, #0x10]
+;;       stur    x1, [x28, #8]
+;;       stur    w0, [x28, #4]
+;;       stur    w1, [x28]
+;;       ldur    w0, [x28]
+;;       ldur    w1, [x28, #4]
+;;       fmul    s1, s1, s0
+;;       fmov    d0, d1
+;;       add     sp, sp, #0x18
+;;       mov     x28, sp
+;;       ldp     x29, x30, [sp], #0x10
+;;       ret
diff --git a/tests/disas/winch/aarch64/f32_sub/const.wat b/tests/disas/winch/aarch64/f32_sub/const.wat
new file mode 100644
index 000000000..c16998758
--- /dev/null
+++ b/tests/disas/winch/aarch64/f32_sub/const.wat
@@ -0,0 +1,31 @@
+;;! target = "aarch64"
+;;! test = "winch"
+
+(module
+    (func (result f32)
+        (f32.const 1.1)
+        (f32.const 2.2)
+        (f32.sub)
+    )
+)
+;; wasm[0]::function[0]:
+;;       stp     x29, x30, [sp, #-0x10]!
+;;       mov     x29, sp
+;;       mov     x28, sp
+;;       mov     x9, x0
+;;       sub     sp, sp, #0x10
+;;       mov     x28, sp
+;;       stur    x0, [x28, #8]
+;;       stur    x1, [x28]
+;;       mov     w16, #0xcccd
+;;       movk    w16, #0x400c, lsl #16
+;;       fmov    s0, w16
+;;       mov     w16, #0xcccd
+;;       movk    w16, #0x3f8c, lsl #16
+;;       fmov    s1, w16
+;;       fsub    s1, s1, s0
+;;       fmov    d0, d1
+;;       add     sp, sp, #0x10
+;;       mov     x28, sp
+;;       ldp     x29, x30, [sp], #0x10
+;;       ret
diff --git a/tests/disas/winch/aarch64/f32_sub/locals.wat b/tests/disas/winch/aarch64/f32_sub/locals.wat
new file mode 100644
index 000000000..05806f4b6
--- /dev/null
+++ b/tests/disas/winch/aarch64/f32_sub/locals.wat
@@ -0,0 +1,46 @@
+;;! target = "aarch64"
+;;! test = "winch"
+
+(module
+    (func (result f32)
+        (local $foo f32)  
+        (local $bar f32)
+
+        (f32.const 1.1)
+        (local.set $foo)
+
+        (f32.const 2.2)
+        (local.set $bar)
+
+        (local.get $foo)
+        (local.get $bar)
+        f32.sub
+    )
+)
+;; wasm[0]::function[0]:
+;;       stp     x29, x30, [sp, #-0x10]!
+;;       mov     x29, sp
+;;       mov     x28, sp
+;;       mov     x9, x0
+;;       sub     sp, sp, #0x18
+;;       mov     x28, sp
+;;       stur    x0, [x28, #0x10]
+;;       stur    x1, [x28, #8]
+;;       mov     x16, #0
+;;       stur    x16, [x28]
+;;       mov     w16, #0xcccd
+;;       movk    w16, #0x3f8c, lsl #16
+;;       fmov    s0, w16
+;;       stur    w0, [x28, #4]
+;;       mov     w16, #0xcccd
+;;       movk    w16, #0x400c, lsl #16
+;;       fmov    s0, w16
+;;       stur    w0, [x28]
+;;       ldur    w0, [x28]
+;;       ldur    w1, [x28, #4]
+;;       fsub    s1, s1, s0
+;;       fmov    d0, d1
+;;       add     sp, sp, #0x18
+;;       mov     x28, sp
+;;       ldp     x29, x30, [sp], #0x10
+;;       ret
diff --git a/tests/disas/winch/aarch64/f32_sub/params.wat b/tests/disas/winch/aarch64/f32_sub/params.wat
new file mode 100644
index 000000000..d97ccb07e
--- /dev/null
+++ b/tests/disas/winch/aarch64/f32_sub/params.wat
@@ -0,0 +1,29 @@
+;;! target = "aarch64"
+;;! test = "winch"
+
+(module
+    (func (param f32) (param f32) (result f32)
+        (local.get 0)
+        (local.get 1)
+        (f32.sub)
+    )
+)
+;; wasm[0]::function[0]:
+;;       stp     x29, x30, [sp, #-0x10]!
+;;       mov     x29, sp
+;;       mov     x28, sp
+;;       mov     x9, x0
+;;       sub     sp, sp, #0x18
+;;       mov     x28, sp
+;;       stur    x0, [x28, #0x10]
+;;       stur    x1, [x28, #8]
+;;       stur    w0, [x28, #4]
+;;       stur    w1, [x28]
+;;       ldur    w0, [x28]
+;;       ldur    w1, [x28, #4]
+;;       fsub    s1, s1, s0
+;;       fmov    d0, d1
+;;       add     sp, sp, #0x18
+;;       mov     x28, sp
+;;       ldp     x29, x30, [sp], #0x10
+;;       ret
diff --git a/tests/disas/winch/aarch64/f64_add/const.wat b/tests/disas/winch/aarch64/f64_add/const.wat
new file mode 100644
index 000000000..c734942ad
--- /dev/null
+++ b/tests/disas/winch/aarch64/f64_add/const.wat
@@ -0,0 +1,35 @@
+;;! target = "aarch64"
+;;! test = "winch"
+
+(module
+    (func (result f64)
+        (f64.const 1.1)
+        (f64.const 2.2)
+        (f64.add)
+    )
+)
+;; wasm[0]::function[0]:
+;;       stp     x29, x30, [sp, #-0x10]!
+;;       mov     x29, sp
+;;       mov     x28, sp
+;;       mov     x9, x0
+;;       sub     sp, sp, #0x10
+;;       mov     x28, sp
+;;       stur    x0, [x28, #8]
+;;       stur    x1, [x28]
+;;       mov     x16, #0x999a
+;;       movk    x16, #0x9999, lsl #16
+;;       movk    x16, #0x9999, lsl #32
+;;       movk    x16, #0x4001, lsl #48
+;;       fmov    d0, x16
+;;       mov     x16, #0x999a
+;;       movk    x16, #0x9999, lsl #16
+;;       movk    x16, #0x9999, lsl #32
+;;       movk    x16, #0x3ff1, lsl #48
+;;       fmov    d1, x16
+;;       fadd    d1, d1, d0
+;;       fmov    d0, d1
+;;       add     sp, sp, #0x10
+;;       mov     x28, sp
+;;       ldp     x29, x30, [sp], #0x10
+;;       ret
diff --git a/tests/disas/winch/aarch64/f64_add/locals.wat b/tests/disas/winch/aarch64/f64_add/locals.wat
new file mode 100644
index 000000000..d3dde833e
--- /dev/null
+++ b/tests/disas/winch/aarch64/f64_add/locals.wat
@@ -0,0 +1,51 @@
+;;! target = "aarch64"
+;;! test = "winch"
+
+(module
+    (func (result f64)
+        (local $foo f64)  
+        (local $bar f64)
+
+        (f64.const 1.1)
+        (local.set $foo)
+
+        (f64.const 2.2)
+        (local.set $bar)
+
+        (local.get $foo)
+        (local.get $bar)
+        f64.add
+    )
+)
+;; wasm[0]::function[0]:
+;;       stp     x29, x30, [sp, #-0x10]!
+;;       mov     x29, sp
+;;       mov     x28, sp
+;;       mov     x9, x0
+;;       sub     sp, sp, #0x20
+;;       mov     x28, sp
+;;       stur    x0, [x28, #0x18]
+;;       stur    x1, [x28, #0x10]
+;;       mov     x16, #0
+;;       stur    x16, [x28, #8]
+;;       stur    x16, [x28]
+;;       mov     x16, #0x999a
+;;       movk    x16, #0x9999, lsl #16
+;;       movk    x16, #0x9999, lsl #32
+;;       movk    x16, #0x3ff1, lsl #48
+;;       fmov    d0, x16
+;;       stur    x0, [x28, #8]
+;;       mov     x16, #0x999a
+;;       movk    x16, #0x9999, lsl #16
+;;       movk    x16, #0x9999, lsl #32
+;;       movk    x16, #0x4001, lsl #48
+;;       fmov    d0, x16
+;;       stur    x0, [x28]
+;;       ldur    x0, [x28]
+;;       ldur    x1, [x28, #8]
+;;       fadd    d1, d1, d0
+;;       fmov    d0, d1
+;;       add     sp, sp, #0x20
+;;       mov     x28, sp
+;;       ldp     x29, x30, [sp], #0x10
+;;       ret
diff --git a/tests/disas/winch/aarch64/f64_add/params.wat b/tests/disas/winch/aarch64/f64_add/params.wat
new file mode 100644
index 000000000..005a6d463
--- /dev/null
+++ b/tests/disas/winch/aarch64/f64_add/params.wat
@@ -0,0 +1,29 @@
+;;! target = "aarch64"
+;;! test = "winch"
+
+(module
+    (func (param f64) (param f64) (result f64)
+        (local.get 0)
+        (local.get 1)
+        (f64.add)
+    )
+)
+;; wasm[0]::function[0]:
+;;       stp     x29, x30, [sp, #-0x10]!
+;;       mov     x29, sp
+;;       mov     x28, sp
+;;       mov     x9, x0
+;;       sub     sp, sp, #0x20
+;;       mov     x28, sp
+;;       stur    x0, [x28, #0x18]
+;;       stur    x1, [x28, #0x10]
+;;       stur    x0, [x28, #8]
+;;       stur    x1, [x28]
+;;       ldur    x0, [x28]
+;;       ldur    x1, [x28, #8]
+;;       fadd    d1, d1, d0
+;;       fmov    d0, d1
+;;       add     sp, sp, #0x20
+;;       mov     x28, sp
+;;       ldp     x29, x30, [sp], #0x10
+;;       ret
\ No newline at end of file
diff --git a/tests/disas/winch/aarch64/f64_div/const.wat b/tests/disas/winch/aarch64/f64_div/const.wat
new file mode 100644
index 000000000..26e1c9d58
--- /dev/null
+++ b/tests/disas/winch/aarch64/f64_div/const.wat
@@ -0,0 +1,35 @@
+;;! target = "aarch64"
+;;! test = "winch"
+
+(module
+    (func (result f64)
+        (f64.const 1.1)
+        (f64.const 2.2)
+        (f64.div)
+    )
+)
+;; wasm[0]::function[0]:
+;;       stp     x29, x30, [sp, #-0x10]!
+;;       mov     x29, sp
+;;       mov     x28, sp
+;;       mov     x9, x0
+;;       sub     sp, sp, #0x10
+;;       mov     x28, sp
+;;       stur    x0, [x28, #8]
+;;       stur    x1, [x28]
+;;       mov     x16, #0x999a
+;;       movk    x16, #0x9999, lsl #16
+;;       movk    x16, #0x9999, lsl #32
+;;       movk    x16, #0x4001, lsl #48
+;;       fmov    d0, x16
+;;       mov     x16, #0x999a
+;;       movk    x16, #0x9999, lsl #16
+;;       movk    x16, #0x9999, lsl #32
+;;       movk    x16, #0x3ff1, lsl #48
+;;       fmov    d1, x16
+;;       fdiv    d1, d1, d0
+;;       fmov    d0, d1
+;;       add     sp, sp, #0x10
+;;       mov     x28, sp
+;;       ldp     x29, x30, [sp], #0x10
+;;       ret
diff --git a/tests/disas/winch/aarch64/f64_div/locals.wat b/tests/disas/winch/aarch64/f64_div/locals.wat
new file mode 100644
index 000000000..0f3871692
--- /dev/null
+++ b/tests/disas/winch/aarch64/f64_div/locals.wat
@@ -0,0 +1,51 @@
+;;! target = "aarch64"
+;;! test = "winch"
+
+(module
+    (func (result f64)
+        (local $foo f64)  
+        (local $bar f64)
+
+        (f64.const 1.1)
+        (local.set $foo)
+
+        (f64.const 2.2)
+        (local.set $bar)
+
+        (local.get $foo)
+        (local.get $bar)
+        f64.div
+    )
+)
+;; wasm[0]::function[0]:
+;;       stp     x29, x30, [sp, #-0x10]!
+;;       mov     x29, sp
+;;       mov     x28, sp
+;;       mov     x9, x0
+;;       sub     sp, sp, #0x20
+;;       mov     x28, sp
+;;       stur    x0, [x28, #0x18]
+;;       stur    x1, [x28, #0x10]
+;;       mov     x16, #0
+;;       stur    x16, [x28, #8]
+;;       stur    x16, [x28]
+;;       mov     x16, #0x999a
+;;       movk    x16, #0x9999, lsl #16
+;;       movk    x16, #0x9999, lsl #32
+;;       movk    x16, #0x3ff1, lsl #48
+;;       fmov    d0, x16
+;;       stur    x0, [x28, #8]
+;;       mov     x16, #0x999a
+;;       movk    x16, #0x9999, lsl #16
+;;       movk    x16, #0x9999, lsl #32
+;;       movk    x16, #0x4001, lsl #48
+;;       fmov    d0, x16
+;;       stur    x0, [x28]
+;;       ldur    x0, [x28]
+;;       ldur    x1, [x28, #8]
+;;       fdiv    d1, d1, d0
+;;       fmov    d0, d1
+;;       add     sp, sp, #0x20
+;;       mov     x28, sp
+;;       ldp     x29, x30, [sp], #0x10
+;;       ret
diff --git a/tests/disas/winch/aarch64/f64_div/params.wat b/tests/disas/winch/aarch64/f64_div/params.wat
new file mode 100644
index 000000000..8abb587b4
--- /dev/null
+++ b/tests/disas/winch/aarch64/f64_div/params.wat
@@ -0,0 +1,29 @@
+;;! target = "aarch64"
+;;! test = "winch"
+
+(module
+    (func (param f64) (param f64) (result f64)
+        (local.get 0)
+        (local.get 1)
+        (f64.div)
+    )
+)
+;; wasm[0]::function[0]:
+;;       stp     x29, x30, [sp, #-0x10]!
+;;       mov     x29, sp
+;;       mov     x28, sp
+;;       mov     x9, x0
+;;       sub     sp, sp, #0x20
+;;       mov     x28, sp
+;;       stur    x0, [x28, #0x18]
+;;       stur    x1, [x28, #0x10]
+;;       stur    x0, [x28, #8]
+;;       stur    x1, [x28]
+;;       ldur    x0, [x28]
+;;       ldur    x1, [x28, #8]
+;;       fdiv    d1, d1, d0
+;;       fmov    d0, d1
+;;       add     sp, sp, #0x20
+;;       mov     x28, sp
+;;       ldp     x29, x30, [sp], #0x10
+;;       ret
diff --git a/tests/disas/winch/aarch64/f64_max/const.wat b/tests/disas/winch/aarch64/f64_max/const.wat
new file mode 100644
index 000000000..39b51913e
--- /dev/null
+++ b/tests/disas/winch/aarch64/f64_max/const.wat
@@ -0,0 +1,35 @@
+;;! target = "aarch64"
+;;! test = "winch"
+
+(module
+    (func (result f64)
+        (f64.const 1.1)
+        (f64.const 2.2)
+        (f64.max)
+    )
+)
+;; wasm[0]::function[0]:
+;;       stp     x29, x30, [sp, #-0x10]!
+;;       mov     x29, sp
+;;       mov     x28, sp
+;;       mov     x9, x0
+;;       sub     sp, sp, #0x10
+;;       mov     x28, sp
+;;       stur    x0, [x28, #8]
+;;       stur    x1, [x28]
+;;       mov     x16, #0x999a
+;;       movk    x16, #0x9999, lsl #16
+;;       movk    x16, #0x9999, lsl #32
+;;       movk    x16, #0x4001, lsl #48
+;;       fmov    d0, x16
+;;       mov     x16, #0x999a
+;;       movk    x16, #0x9999, lsl #16
+;;       movk    x16, #0x9999, lsl #32
+;;       movk    x16, #0x3ff1, lsl #48
+;;       fmov    d1, x16
+;;       fmax    d1, d1, d0
+;;       fmov    d0, d1
+;;       add     sp, sp, #0x10
+;;       mov     x28, sp
+;;       ldp     x29, x30, [sp], #0x10
+;;       ret
diff --git a/tests/disas/winch/aarch64/f64_max/locals.wat b/tests/disas/winch/aarch64/f64_max/locals.wat
new file mode 100644
index 000000000..b6f97551b
--- /dev/null
+++ b/tests/disas/winch/aarch64/f64_max/locals.wat
@@ -0,0 +1,51 @@
+;;! target = "aarch64"
+;;! test = "winch"
+
+(module
+    (func (result f64)
+        (local $foo f64)  
+        (local $bar f64)
+
+        (f64.const 1.1)
+        (local.set $foo)
+
+        (f64.const 2.2)
+        (local.set $bar)
+
+        (local.get $foo)
+        (local.get $bar)
+        f64.max
+    )
+)
+;; wasm[0]::function[0]:
+;;       stp     x29, x30, [sp, #-0x10]!
+;;       mov     x29, sp
+;;       mov     x28, sp
+;;       mov     x9, x0
+;;       sub     sp, sp, #0x20
+;;       mov     x28, sp
+;;       stur    x0, [x28, #0x18]
+;;       stur    x1, [x28, #0x10]
+;;       mov     x16, #0
+;;       stur    x16, [x28, #8]
+;;       stur    x16, [x28]
+;;       mov     x16, #0x999a
+;;       movk    x16, #0x9999, lsl #16
+;;       movk    x16, #0x9999, lsl #32
+;;       movk    x16, #0x3ff1, lsl #48
+;;       fmov    d0, x16
+;;       stur    x0, [x28, #8]
+;;       mov     x16, #0x999a
+;;       movk    x16, #0x9999, lsl #16
+;;       movk    x16, #0x9999, lsl #32
+;;       movk    x16, #0x4001, lsl #48
+;;       fmov    d0, x16
+;;       stur    x0, [x28]
+;;       ldur    x0, [x28]
+;;       ldur    x1, [x28, #8]
+;;       fmax    d1, d1, d0
+;;       fmov    d0, d1
+;;       add     sp, sp, #0x20
+;;       mov     x28, sp
+;;       ldp     x29, x30, [sp], #0x10
+;;       ret
diff --git a/tests/disas/winch/aarch64/f64_max/params.wat b/tests/disas/winch/aarch64/f64_max/params.wat
new file mode 100644
index 000000000..19e25cf32
--- /dev/null
+++ b/tests/disas/winch/aarch64/f64_max/params.wat
@@ -0,0 +1,29 @@
+;;! target = "aarch64"
+;;! test = "winch"
+
+(module
+    (func (param f64) (param f64) (result f64)
+        (local.get 0)
+        (local.get 1)
+        (f64.max)
+    )
+)
+;; wasm[0]::function[0]:
+;;       stp     x29, x30, [sp, #-0x10]!
+;;       mov     x29, sp
+;;       mov     x28, sp
+;;       mov     x9, x0
+;;       sub     sp, sp, #0x20
+;;       mov     x28, sp
+;;       stur    x0, [x28, #0x18]
+;;       stur    x1, [x28, #0x10]
+;;       stur    x0, [x28, #8]
+;;       stur    x1, [x28]
+;;       ldur    x0, [x28]
+;;       ldur    x1, [x28, #8]
+;;       fmax    d1, d1, d0
+;;       fmov    d0, d1
+;;       add     sp, sp, #0x20
+;;       mov     x28, sp
+;;       ldp     x29, x30, [sp], #0x10
+;;       ret
diff --git a/tests/disas/winch/aarch64/f64_min/const.wat b/tests/disas/winch/aarch64/f64_min/const.wat
new file mode 100644
index 000000000..4f95658fc
--- /dev/null
+++ b/tests/disas/winch/aarch64/f64_min/const.wat
@@ -0,0 +1,35 @@
+;;! target = "aarch64"
+;;! test = "winch"
+
+(module
+    (func (result f64)
+        (f64.const 1.1)
+        (f64.const 2.2)
+        (f64.min)
+    )
+)
+;; wasm[0]::function[0]:
+;;       stp     x29, x30, [sp, #-0x10]!
+;;       mov     x29, sp
+;;       mov     x28, sp
+;;       mov     x9, x0
+;;       sub     sp, sp, #0x10
+;;       mov     x28, sp
+;;       stur    x0, [x28, #8]
+;;       stur    x1, [x28]
+;;       mov     x16, #0x999a
+;;       movk    x16, #0x9999, lsl #16
+;;       movk    x16, #0x9999, lsl #32
+;;       movk    x16, #0x4001, lsl #48
+;;       fmov    d0, x16
+;;       mov     x16, #0x999a
+;;       movk    x16, #0x9999, lsl #16
+;;       movk    x16, #0x9999, lsl #32
+;;       movk    x16, #0x3ff1, lsl #48
+;;       fmov    d1, x16
+;;       fmin    d1, d1, d0
+;;       fmov    d0, d1
+;;       add     sp, sp, #0x10
+;;       mov     x28, sp
+;;       ldp     x29, x30, [sp], #0x10
+;;       ret
diff --git a/tests/disas/winch/aarch64/f64_min/locals.wat b/tests/disas/winch/aarch64/f64_min/locals.wat
new file mode 100644
index 000000000..15aa9ddeb
--- /dev/null
+++ b/tests/disas/winch/aarch64/f64_min/locals.wat
@@ -0,0 +1,51 @@
+;;! target = "aarch64"
+;;! test = "winch"
+
+(module
+    (func (result f64)
+        (local $foo f64)  
+        (local $bar f64)
+
+        (f64.const 1.1)
+        (local.set $foo)
+
+        (f64.const 2.2)
+        (local.set $bar)
+
+        (local.get $foo)
+        (local.get $bar)
+        f64.min
+    )
+)
+;; wasm[0]::function[0]:
+;;       stp     x29, x30, [sp, #-0x10]!
+;;       mov     x29, sp
+;;       mov     x28, sp
+;;       mov     x9, x0
+;;       sub     sp, sp, #0x20
+;;       mov     x28, sp
+;;       stur    x0, [x28, #0x18]
+;;       stur    x1, [x28, #0x10]
+;;       mov     x16, #0
+;;       stur    x16, [x28, #8]
+;;       stur    x16, [x28]
+;;       mov     x16, #0x999a
+;;       movk    x16, #0x9999, lsl #16
+;;       movk    x16, #0x9999, lsl #32
+;;       movk    x16, #0x3ff1, lsl #48
+;;       fmov    d0, x16
+;;       stur    x0, [x28, #8]
+;;       mov     x16, #0x999a
+;;       movk    x16, #0x9999, lsl #16
+;;       movk    x16, #0x9999, lsl #32
+;;       movk    x16, #0x4001, lsl #48
+;;       fmov    d0, x16
+;;       stur    x0, [x28]
+;;       ldur    x0, [x28]
+;;       ldur    x1, [x28, #8]
+;;       fmin    d1, d1, d0
+;;       fmov    d0, d1
+;;       add     sp, sp, #0x20
+;;       mov     x28, sp
+;;       ldp     x29, x30, [sp], #0x10
+;;       ret
diff --git a/tests/disas/winch/aarch64/f64_min/params.wat b/tests/disas/winch/aarch64/f64_min/params.wat
new file mode 100644
index 000000000..1738beed4
--- /dev/null
+++ b/tests/disas/winch/aarch64/f64_min/params.wat
@@ -0,0 +1,29 @@
+;;! target = "aarch64"
+;;! test = "winch"
+
+(module
+    (func (param f64) (param f64) (result f64)
+        (local.get 0)
+        (local.get 1)
+        (f64.min)
+    )
+)
+;; wasm[0]::function[0]:
+;;       stp     x29, x30, [sp, #-0x10]!
+;;       mov     x29, sp
+;;       mov     x28, sp
+;;       mov     x9, x0
+;;       sub     sp, sp, #0x20
+;;       mov     x28, sp
+;;       stur    x0, [x28, #0x18]
+;;       stur    x1, [x28, #0x10]
+;;       stur    x0, [x28, #8]
+;;       stur    x1, [x28]
+;;       ldur    x0, [x28]
+;;       ldur    x1, [x28, #8]
+;;       fmin    d1, d1, d0
+;;       fmov    d0, d1
+;;       add     sp, sp, #0x20
+;;       mov     x28, sp
+;;       ldp     x29, x30, [sp], #0x10
+;;       ret
diff --git a/tests/disas/winch/aarch64/f64_mul/const.wat b/tests/disas/winch/aarch64/f64_mul/const.wat
new file mode 100644
index 000000000..299d8a76d
--- /dev/null
+++ b/tests/disas/winch/aarch64/f64_mul/const.wat
@@ -0,0 +1,35 @@
+;;! target = "aarch64"
+;;! test = "winch"
+
+(module
+    (func (result f64)
+        (f64.const 1.1)
+        (f64.const 2.2)
+        (f64.mul)
+    )
+)
+;; wasm[0]::function[0]:
+;;       stp     x29, x30, [sp, #-0x10]!
+;;       mov     x29, sp
+;;       mov     x28, sp
+;;       mov     x9, x0
+;;       sub     sp, sp, #0x10
+;;       mov     x28, sp
+;;       stur    x0, [x28, #8]
+;;       stur    x1, [x28]
+;;       mov     x16, #0x999a
+;;       movk    x16, #0x9999, lsl #16
+;;       movk    x16, #0x9999, lsl #32
+;;       movk    x16, #0x4001, lsl #48
+;;       fmov    d0, x16
+;;       mov     x16, #0x999a
+;;       movk    x16, #0x9999, lsl #16
+;;       movk    x16, #0x9999, lsl #32
+;;       movk    x16, #0x3ff1, lsl #48
+;;       fmov    d1, x16
+;;       fmul    d1, d1, d0
+;;       fmov    d0, d1
+;;       add     sp, sp, #0x10
+;;       mov     x28, sp
+;;       ldp     x29, x30, [sp], #0x10
+;;       ret
diff --git a/tests/disas/winch/aarch64/f64_mul/locals.wat b/tests/disas/winch/aarch64/f64_mul/locals.wat
new file mode 100644
index 000000000..b7d5a5ebe
--- /dev/null
+++ b/tests/disas/winch/aarch64/f64_mul/locals.wat
@@ -0,0 +1,51 @@
+;;! target = "aarch64"
+;;! test = "winch"
+
+(module
+    (func (result f64)
+        (local $foo f64)  
+        (local $bar f64)
+
+        (f64.const 1.1)
+        (local.set $foo)
+
+        (f64.const 2.2)
+        (local.set $bar)
+
+        (local.get $foo)
+        (local.get $bar)
+        f64.mul
+    )
+)
+;; wasm[0]::function[0]:
+;;       stp     x29, x30, [sp, #-0x10]!
+;;       mov     x29, sp
+;;       mov     x28, sp
+;;       mov     x9, x0
+;;       sub     sp, sp, #0x20
+;;       mov     x28, sp
+;;       stur    x0, [x28, #0x18]
+;;       stur    x1, [x28, #0x10]
+;;       mov     x16, #0
+;;       stur    x16, [x28, #8]
+;;       stur    x16, [x28]
+;;       mov     x16, #0x999a
+;;       movk    x16, #0x9999, lsl #16
+;;       movk    x16, #0x9999, lsl #32
+;;       movk    x16, #0x3ff1, lsl #48
+;;       fmov    d0, x16
+;;       stur    x0, [x28, #8]
+;;       mov     x16, #0x999a
+;;       movk    x16, #0x9999, lsl #16
+;;       movk    x16, #0x9999, lsl #32
+;;       movk    x16, #0x4001, lsl #48
+;;       fmov    d0, x16
+;;       stur    x0, [x28]
+;;       ldur    x0, [x28]
+;;       ldur    x1, [x28, #8]
+;;       fmul    d1, d1, d0
+;;       fmov    d0, d1
+;;       add     sp, sp, #0x20
+;;       mov     x28, sp
+;;       ldp     x29, x30, [sp], #0x10
+;;       ret
diff --git a/tests/disas/winch/aarch64/f64_mul/params.wat b/tests/disas/winch/aarch64/f64_mul/params.wat
new file mode 100644
index 000000000..17e258ac9
--- /dev/null
+++ b/tests/disas/winch/aarch64/f64_mul/params.wat
@@ -0,0 +1,29 @@
+;;! target = "aarch64"
+;;! test = "winch"
+
+(module
+    (func (param f64) (param f64) (result f64)
+        (local.get 0)
+        (local.get 1)
+        (f64.mul)
+    )
+)
+;; wasm[0]::function[0]:
+;;       stp     x29, x30, [sp, #-0x10]!
+;;       mov     x29, sp
+;;       mov     x28, sp
+;;       mov     x9, x0
+;;       sub     sp, sp, #0x20
+;;       mov     x28, sp
+;;       stur    x0, [x28, #0x18]
+;;       stur    x1, [x28, #0x10]
+;;       stur    x0, [x28, #8]
+;;       stur    x1, [x28]
+;;       ldur    x0, [x28]
+;;       ldur    x1, [x28, #8]
+;;       fmul    d1, d1, d0
+;;       fmov    d0, d1
+;;       add     sp, sp, #0x20
+;;       mov     x28, sp
+;;       ldp     x29, x30, [sp], #0x10
+;;       ret
diff --git a/tests/disas/winch/aarch64/f64_sub/const.wat b/tests/disas/winch/aarch64/f64_sub/const.wat
new file mode 100644
index 000000000..0f59f1168
--- /dev/null
+++ b/tests/disas/winch/aarch64/f64_sub/const.wat
@@ -0,0 +1,35 @@
+;;! target = "aarch64"
+;;! test = "winch"
+
+(module
+    (func (result f64)
+        (f64.const 1.1)
+        (f64.const 2.2)
+        (f64.sub)
+    )
+)
+;; wasm[0]::function[0]:
+;;       stp     x29, x30, [sp, #-0x10]!
+;;       mov     x29, sp
+;;       mov     x28, sp
+;;       mov     x9, x0
+;;       sub     sp, sp, #0x10
+;;       mov     x28, sp
+;;       stur    x0, [x28, #8]
+;;       stur    x1, [x28]
+;;       mov     x16, #0x999a
+;;       movk    x16, #0x9999, lsl #16
+;;       movk    x16, #0x9999, lsl #32
+;;       movk    x16, #0x4001, lsl #48
+;;       fmov    d0, x16
+;;       mov     x16, #0x999a
+;;       movk    x16, #0x9999, lsl #16
+;;       movk    x16, #0x9999, lsl #32
+;;       movk    x16, #0x3ff1, lsl #48
+;;       fmov    d1, x16
+;;       fsub    d1, d1, d0
+;;       fmov    d0, d1
+;;       add     sp, sp, #0x10
+;;       mov     x28, sp
+;;       ldp     x29, x30, [sp], #0x10
+;;       ret
diff --git a/tests/disas/winch/aarch64/f64_sub/locals.wat b/tests/disas/winch/aarch64/f64_sub/locals.wat
new file mode 100644
index 000000000..dd21ce0a2
--- /dev/null
+++ b/tests/disas/winch/aarch64/f64_sub/locals.wat
@@ -0,0 +1,51 @@
+;;! target = "aarch64"
+;;! test = "winch"
+
+(module
+    (func (result f64)
+        (local $foo f64)  
+        (local $bar f64)
+
+        (f64.const 1.1)
+        (local.set $foo)
+
+        (f64.const 2.2)
+        (local.set $bar)
+
+        (local.get $foo)
+        (local.get $bar)
+        f64.sub
+    )
+)
+;; wasm[0]::function[0]:
+;;       stp     x29, x30, [sp, #-0x10]!
+;;       mov     x29, sp
+;;       mov     x28, sp
+;;       mov     x9, x0
+;;       sub     sp, sp, #0x20
+;;       mov     x28, sp
+;;       stur    x0, [x28, #0x18]
+;;       stur    x1, [x28, #0x10]
+;;       mov     x16, #0
+;;       stur    x16, [x28, #8]
+;;       stur    x16, [x28]
+;;       mov     x16, #0x999a
+;;       movk    x16, #0x9999, lsl #16
+;;       movk    x16, #0x9999, lsl #32
+;;       movk    x16, #0x3ff1, lsl #48
+;;       fmov    d0, x16
+;;       stur    x0, [x28, #8]
+;;       mov     x16, #0x999a
+;;       movk    x16, #0x9999, lsl #16
+;;       movk    x16, #0x9999, lsl #32
+;;       movk    x16, #0x4001, lsl #48
+;;       fmov    d0, x16
+;;       stur    x0, [x28]
+;;       ldur    x0, [x28]
+;;       ldur    x1, [x28, #8]
+;;       fsub    d1, d1, d0
+;;       fmov    d0, d1
+;;       add     sp, sp, #0x20
+;;       mov     x28, sp
+;;       ldp     x29, x30, [sp], #0x10
+;;       ret
diff --git a/tests/disas/winch/aarch64/f64_sub/params.wat b/tests/disas/winch/aarch64/f64_sub/params.wat
new file mode 100644
index 000000000..236655df0
--- /dev/null
+++ b/tests/disas/winch/aarch64/f64_sub/params.wat
@@ -0,0 +1,29 @@
+;;! target = "aarch64"
+;;! test = "winch"
+
+(module
+    (func (param f64) (param f64) (result f64)
+        (local.get 0)
+        (local.get 1)
+        (f64.sub)
+    )
+)
+;; wasm[0]::function[0]:
+;;       stp     x29, x30, [sp, #-0x10]!
+;;       mov     x29, sp
+;;       mov     x28, sp
+;;       mov     x9, x0
+;;       sub     sp, sp, #0x20
+;;       mov     x28, sp
+;;       stur    x0, [x28, #0x18]
+;;       stur    x1, [x28, #0x10]
+;;       stur    x0, [x28, #8]
+;;       stur    x1, [x28]
+;;       ldur    x0, [x28]
+;;       ldur    x1, [x28, #8]
+;;       fsub    d1, d1, d0
+;;       fmov    d0, d1
+;;       add     sp, sp, #0x20
+;;       mov     x28, sp
+;;       ldp     x29, x30, [sp], #0x10
+;;       ret