Repository: bytecodealliance/wasmtime
Pull request #7823 (2024-01-25 20:42:12)

Update to actions/cache@v4
Resolves some warnings on CI about using Node 16 instead of Node 20

<!--
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/.github/actions/install-cargo-vet/action.yml b/.github/actions/install-cargo-vet/action.yml
index ddbf87e9b..a964f79cb 100644
--- a/.github/actions/install-cargo-vet/action.yml
+++ b/.github/actions/install-cargo-vet/action.yml
@@ -10,7 +10,7 @@ inputs:
 runs:
   using: composite
   steps:
-    - uses: actions/cache@v3
+    - uses: actions/cache@v4
       with:
         path: ${{ runner.tool_cache }}/cargo-vet
         key: cargo-vet-bin-${{ inputs.version }}
diff --git a/.github/actions/install-rust/action.yml b/.github/actions/install-rust/action.yml
index b15c33c0a..41d528608 100644
--- a/.github/actions/install-rust/action.yml
+++ b/.github/actions/install-rust/action.yml
@@ -81,7 +81,7 @@ runs:
       run: echo CARGO_REGISTRY_CACHE_KEY=$(date +%Y%m%d) >> $GITHUB_ENV
 
     - name: Cache Cargo registry index
-      uses: actions/cache@v3
+      uses: actions/cache@v4
       with:
         path: ~/.cargo/registry/index/
         key: cargo-registry-${{ env.CARGO_REGISTRY_CACHE_KEY }}
@@ -90,7 +90,7 @@ runs:
         restore-keys: cargo-registry-
 
     - name: Cache crate sources for dependencies
-      uses: actions/cache@v3
+      uses: actions/cache@v4
       with:
         path: |
           ~/.cargo/registry/cache/
diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml
index 55dcc0c51..b18fbcf0a 100644
--- a/.github/workflows/main.yml
+++ b/.github/workflows/main.yml
@@ -215,7 +215,7 @@ jobs:
     - run: cd crates/c-api && doxygen doxygen.conf
 
     # install mdbook, build the docs, and test the docs
-    - uses: actions/cache@v3
+    - uses: actions/cache@v4
       with:
         path: ${{ runner.tool_cache }}/mdbook
         key: cargo-mdbook-bin-${{ env.CARGO_MDBOOK_VERSION }}
@@ -324,7 +324,7 @@ jobs:
     - run: rustup target add aarch64-linux-android
     - name: Setup Android SDK
       uses: android-actions/setup-android@v2
-    - uses: actions/cache@v3
+    - uses: actions/cache@v4
       with:
         path: ${{ runner.tool_cache }}/cargo-ndk
         key: cargo-ndk-bin-${{ env.CARGO_NDK_VERSION }}
@@ -439,7 +439,7 @@ jobs:
 
     - run: cargo fetch --locked
 
-    - uses: actions/cache@v3
+    - uses: actions/cache@v4
       with:
         path: ${{ runner.tool_cache }}/qemu
         key: qemu-${{ matrix.target }}-${{ env.QEMU_BUILD_VERSION }}-patchcpuinfo
@@ -659,7 +659,7 @@ jobs:
       with:
         toolchain: nightly-2023-10-10
     - run: rustup component add rust-src miri
-    - uses: actions/cache@v3
+    - uses: actions/cache@v4
       with:
         path: ${{ runner.tool_cache }}/cargo-nextest
         key: cargo-nextest-bin-${{ env.CARGO_NEXTEST_VERSION }}
diff --git a/Cargo.lock b/Cargo.lock
index e7893096a..a5f1d0e3e 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -664,7 +664,7 @@ dependencies = [
  "target-lexicon",
  "thiserror",
  "toml",
- "wasmparser 0.119.0",
+ "wasmparser 0.120.0",
  "wat",
 ]
 
@@ -843,7 +843,7 @@ dependencies = [
  "serde_derive",
  "smallvec",
  "target-lexicon",
- "wasmparser 0.119.0",
+ "wasmparser 0.120.0",
  "wasmtime-types",
  "wat",
 ]
@@ -2607,7 +2607,7 @@ version = "0.0.0"
 dependencies = [
  "cargo_metadata",
  "heck",
- "wit-component 0.19.1",
+ "wit-component 0.20.0",
 ]
 
 [[package]]
@@ -2895,7 +2895,7 @@ name = "verify-component-adapter"
 version = "18.0.0"
 dependencies = [
  "anyhow",
- "wasmparser 0.119.0",
+ "wasmparser 0.120.0",
  "wat",
 ]
 
@@ -3002,7 +3002,7 @@ dependencies = [
  "byte-array-literals",
  "object",
  "wasi",
- "wasm-encoder 0.39.0",
+ "wasm-encoder 0.40.0",
  "wit-bindgen",
 ]
 
@@ -3088,19 +3088,18 @@ dependencies = [
 
 [[package]]
 name = "wasm-encoder"
-version = "0.39.0"
+version = "0.40.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "111495d6204760238512f57a9af162f45086504da332af210f2f75dd80b34f1d"
+checksum = "d162eb64168969ae90e8668ca0593b0e47667e315aa08e717a9c9574d700d826"
 dependencies = [
  "leb128",
- "wasmparser 0.119.0",
 ]
 
 [[package]]
 name = "wasm-metadata"
-version = "0.10.15"
+version = "0.10.16"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "818931c85b1d197909699d36c509fa89550ccfa0d66932ba3c1726faddb4d0c7"
+checksum = "0b313e616ef69d1b4c64155451439db26d1923e8bbc13d451ec24cf14579632e"
 dependencies = [
  "anyhow",
  "indexmap 2.0.0",
@@ -3108,35 +3107,35 @@ dependencies = [
  "serde_derive",
  "serde_json",
  "spdx",
- "wasm-encoder 0.39.0",
- "wasmparser 0.119.0",
+ "wasm-encoder 0.40.0",
+ "wasmparser 0.120.0",
 ]
 
 [[package]]
 name = "wasm-mutate"
-version = "0.2.44"
+version = "0.2.45"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6f95378917a3e9c61e79d41ca4629eb3e0a3ca1714d745c1c2a186439472578c"
+checksum = "31c97c7c401830ef659b9df5778647aef0c493ad6dde06296dc8c9b52b9495f9"
 dependencies = [
  "egg",
  "log",
  "rand",
  "thiserror",
- "wasm-encoder 0.39.0",
- "wasmparser 0.119.0",
+ "wasm-encoder 0.40.0",
+ "wasmparser 0.120.0",
 ]
 
 [[package]]
 name = "wasm-smith"
-version = "0.14.0"
+version = "0.15.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a419bbbab75f5ad71744256b74fdaeeb9215ea9e9bfc59c477e96c462ee0ef59"
+checksum = "51803e2c31e82f93ec1796f781f9855844ff1203f993409eb74d1d17130928a7"
 dependencies = [
  "arbitrary",
  "flagset",
  "indexmap 2.0.0",
  "leb128",
- "wasm-encoder 0.39.0",
+ "wasm-encoder 0.40.0",
 ]
 
 [[package]]
@@ -3191,9 +3190,9 @@ dependencies = [
 
 [[package]]
 name = "wasmparser"
-version = "0.119.0"
+version = "0.120.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8c35daf77afb4f9b14016625144a391085ec2ca99ca9cc53ed291bb53ab5278d"
+checksum = "e9148127f39cbffe43efee8d5442b16ecdba21567785268daa1ec9e134389705"
 dependencies = [
  "bitflags 2.4.1",
  "indexmap 2.0.0",
@@ -3211,12 +3210,12 @@ dependencies = [
 
 [[package]]
 name = "wasmprinter"
-version = "0.2.76"
+version = "0.2.77"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "cac2a7745372074e5573e365e17100f5a26058740576313784ef03fb900ea8d2"
+checksum = "d8389a95eb0b3165fea0537a6988960cc23a33d9be650e63fc3d63065fe20dcb"
 dependencies = [
  "anyhow",
- "wasmparser 0.119.0",
+ "wasmparser 0.120.0",
 ]
 
 [[package]]
@@ -3247,8 +3246,8 @@ dependencies = [
  "target-lexicon",
  "tempfile",
  "wasi-cap-std-sync",
- "wasm-encoder 0.39.0",
- "wasmparser 0.119.0",
+ "wasm-encoder 0.40.0",
+ "wasmparser 0.120.0",
  "wasmtime-cache",
  "wasmtime-component-macro",
  "wasmtime-component-util",
@@ -3380,7 +3379,7 @@ dependencies = [
  "tokio",
  "tracing",
  "walkdir",
- "wasmparser 0.119.0",
+ "wasmparser 0.120.0",
  "wasmtime",
  "wasmtime-cache",
  "wasmtime-cli-flags",
@@ -3394,10 +3393,10 @@ dependencies = [
  "wasmtime-wasi-nn",
  "wasmtime-wasi-threads",
  "wasmtime-wast",
- "wast 70.0.0",
+ "wast 70.0.1",
  "wat",
  "windows-sys 0.52.0",
- "wit-component 0.19.1",
+ "wit-component 0.20.0",
 ]
 
 [[package]]
@@ -3450,7 +3449,7 @@ dependencies = [
  "object",
  "target-lexicon",
  "thiserror",
- "wasmparser 0.119.0",
+ "wasmparser 0.120.0",
  "wasmtime-cranelift-shared",
  "wasmtime-environ",
  "wasmtime-versioned-export-macros",
@@ -3489,8 +3488,8 @@ dependencies = [
  "serde_derive",
  "target-lexicon",
  "thiserror",
- "wasm-encoder 0.39.0",
- "wasmparser 0.119.0",
+ "wasm-encoder 0.40.0",
+ "wasmparser 0.120.0",
  "wasmprinter",
  "wasmtime-component-util",
  "wasmtime-types",
@@ -3505,7 +3504,7 @@ dependencies = [
  "component-fuzz-util",
  "env_logger",
  "libfuzzer-sys",
- "wasmparser 0.119.0",
+ "wasmparser 0.120.0",
  "wasmprinter",
  "wasmtime-environ",
  "wat",
@@ -3562,7 +3561,7 @@ dependencies = [
  "rand",
  "smallvec",
  "target-lexicon",
- "wasmparser 0.119.0",
+ "wasmparser 0.120.0",
  "wasmtime",
  "wasmtime-fuzzing",
 ]
@@ -3582,12 +3581,12 @@ dependencies = [
  "target-lexicon",
  "tempfile",
  "v8",
- "wasm-encoder 0.39.0",
+ "wasm-encoder 0.40.0",
  "wasm-mutate",
  "wasm-smith",
  "wasm-spec-interpreter",
  "wasmi",
- "wasmparser 0.119.0",
+ "wasmparser 0.120.0",
  "wasmprinter",
  "wasmtime",
  "wasmtime-wast",
@@ -3634,7 +3633,7 @@ dependencies = [
  "rand",
  "rustix",
  "sptr",
- "wasm-encoder 0.39.0",
+ "wasm-encoder 0.40.0",
  "wasmtime-asm-macros",
  "wasmtime-environ",
  "wasmtime-fiber",
@@ -3652,7 +3651,7 @@ dependencies = [
  "serde",
  "serde_derive",
  "thiserror",
- "wasmparser 0.119.0",
+ "wasmparser 0.120.0",
 ]
 
 [[package]]
@@ -3763,7 +3762,7 @@ dependencies = [
  "anyhow",
  "log",
  "wasmtime",
- "wast 70.0.0",
+ "wast 70.0.1",
 ]
 
 [[package]]
@@ -3775,7 +3774,7 @@ dependencies = [
  "gimli",
  "object",
  "target-lexicon",
- "wasmparser 0.119.0",
+ "wasmparser 0.120.0",
  "wasmtime-cranelift-shared",
  "wasmtime-environ",
  "winch-codegen",
@@ -3806,23 +3805,23 @@ dependencies = [
 
 [[package]]
 name = "wast"
-version = "70.0.0"
+version = "70.0.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2ee4bc54bbe1c6924160b9f75e374a1d07532e7580eb632c0ee6cdd109bb217e"
+checksum = "f5d415036fe747a32b30c76c8bd6c73f69b7705fb7ebca5f16e852eef0c95802"
 dependencies = [
  "leb128",
  "memchr",
  "unicode-width",
- "wasm-encoder 0.39.0",
+ "wasm-encoder 0.40.0",
 ]
 
 [[package]]
 name = "wat"
-version = "1.0.83"
+version = "1.0.84"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9f0dce8cdc288c717cf01e461a1e451a7b8445d53451123536ba576e423a101a"
+checksum = "8241f34599d413d2243a21015ab43aef68bfb32a0e447c54eef8d423525ca15e"
 dependencies = [
- "wast 70.0.0",
+ "wast 70.0.1",
 ]
 
 [[package]]
@@ -3947,7 +3946,7 @@ dependencies = [
  "regalloc2",
  "smallvec",
  "target-lexicon",
- "wasmparser 0.119.0",
+ "wasmparser 0.120.0",
  "wasmtime-environ",
 ]
 
@@ -3963,7 +3962,7 @@ dependencies = [
  "similar",
  "target-lexicon",
  "toml",
- "wasmparser 0.119.0",
+ "wasmparser 0.120.0",
  "wasmtime-environ",
  "wat",
  "winch-codegen",
@@ -3993,7 +3992,7 @@ dependencies = [
  "similar",
  "target-lexicon",
  "toml",
- "wasmparser 0.119.0",
+ "wasmparser 0.120.0",
  "wasmtime-environ",
  "wat",
  "winch-codegen",
@@ -4222,9 +4221,9 @@ dependencies = [
 
 [[package]]
 name = "wit-component"
-version = "0.19.1"
+version = "0.20.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "429e3c06fba3a7566aab724ae3ffff3152ede5399d44789e7dd11f5421292859"
+checksum = "8fa6229817f3a3e4a7fafe02e063b5dc64b73b286fb0e0c14addbc0d47809c9b"
 dependencies = [
  "anyhow",
  "bitflags 2.4.1",
@@ -4233,9 +4232,9 @@ dependencies = [
  "serde",
  "serde_derive",
  "serde_json",
- "wasm-encoder 0.39.0",
+ "wasm-encoder 0.40.0",
  "wasm-metadata",
- "wasmparser 0.119.0",
+ "wasmparser 0.120.0",
  "wit-parser",
 ]
 
diff --git a/Cargo.toml b/Cargo.toml
index c66ed0db4..2bffa7bcd 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -232,15 +232,15 @@ is-terminal = "0.4.0"
 wit-bindgen = { version = "0.15.0", default-features = false }
 
 # wasm-tools family:
-wasmparser = "0.119.0"
-wat = "1.0.83"
-wast = "70.0.0"
-wasmprinter = "0.2.76"
-wasm-encoder = "0.39.0"
-wasm-smith = "0.14.0"
-wasm-mutate = "0.2.44"
+wasmparser = "0.120.0"
+wat = "1.0.84"
+wast = "70.0.1"
+wasmprinter = "0.2.77"
+wasm-encoder = "0.40.0"
+wasm-smith = "0.15.0"
+wasm-mutate = "0.2.45"
 wit-parser = "0.13.1"
-wit-component = "0.19.1"
+wit-component = "0.20.0"
 
 # Non-Bytecode Alliance maintained dependencies:
 # --------------------------
diff --git a/build.rs b/build.rs
index 0826f0a86..0421313e7 100644
--- a/build.rs
+++ b/build.rs
@@ -204,30 +204,7 @@ fn ignore(testsuite: &str, testname: &str, strategy: &str) -> bool {
     assert!(strategy == "Cranelift" || strategy == "Winch");
 
     // Ignore everything except the winch misc test suite.
-    // We ignore tests that assert for traps on windows, given
-    // that Winch doesn't encode unwind information for Windows, yet.
     if strategy == "Winch" {
-        let assert_trap = [
-            "i32",
-            "i64",
-            "call",
-            "call_indirect",
-            "conversions",
-            "table_fill",
-            "table_init",
-            "table_copy",
-            "table_set",
-            "table_get",
-            "memory_grow",
-            "memory_init",
-            "memory_fill",
-        ]
-        .contains(&testname);
-
-        if assert_trap && env::var("CARGO_CFG_TARGET_OS").unwrap().as_str() == "windows" {
-            return true;
-        }
-
         if testsuite == "misc_testsuite" {
             // The misc/call_indirect is fully supported by Winch.
             if testname != "call_indirect" {
diff --git a/cranelift/codegen/src/isa/x64/inst.isle b/cranelift/codegen/src/isa/x64/inst.isle
index e55867ab4..82fbcd052 100644
--- a/cranelift/codegen/src/isa/x64/inst.isle
+++ b/cranelift/codegen/src/isa/x64/inst.isle
@@ -4281,18 +4281,27 @@
 (rule (x64_vfnmadd132 $F64X2 a b c) (xmm_rmr_vex3 (AvxOpcode.Vfnmadd132pd) a b c))
 
 ;; Helper for creating `sqrtss` instructions.
-(decl x64_sqrtss (XmmMem) Xmm)
-(rule (x64_sqrtss x) (xmm_unary_rm_r_unaligned (SseOpcode.Sqrtss) x))
-(rule 1 (x64_sqrtss x)
+;;
+;; NB: the square-root operation technically only has one operand but this
+;; instruction has two. This is to reflect how the square root operation copies
+;; the upper bits of the first register and only performs the square root
+;; operation on the low bits of the second register. This introduces
+;; a data-dependency on the contents of the first register which is modeled
+;; here.
+(decl x64_sqrtss (Xmm XmmMem) Xmm)
+(rule (x64_sqrtss x y) (xmm_rm_r_unaligned (SseOpcode.Sqrtss) x y))
+(rule 1 (x64_sqrtss x y)
         (if-let $true (use_avx))
-        (xmm_unary_rm_r_vex (AvxOpcode.Vsqrtss) x))
+        (xmm_rmir_vex (AvxOpcode.Vsqrtss) x y))
 
 ;; Helper for creating `sqrtsd` instructions.
-(decl x64_sqrtsd (XmmMem) Xmm)
-(rule (x64_sqrtsd x) (xmm_unary_rm_r_unaligned (SseOpcode.Sqrtsd) x))
-(rule 1 (x64_sqrtsd x)
+;;
+;; NB: see `x64_sqrtss` for explanation of why this has two args.
+(decl x64_sqrtsd (Xmm XmmMem) Xmm)
+(rule (x64_sqrtsd x y) (xmm_rm_r_unaligned (SseOpcode.Sqrtsd) x y))
+(rule 1 (x64_sqrtsd x y)
         (if-let $true (use_avx))
-        (xmm_unary_rm_r_vex (AvxOpcode.Vsqrtsd) x))
+        (xmm_rmir_vex (AvxOpcode.Vsqrtsd) x y))
 
 ;; Helper for creating `sqrtps` instructions.
 (decl x64_sqrtps (XmmMem) Xmm)
@@ -4309,18 +4318,22 @@
         (xmm_unary_rm_r_vex (AvxOpcode.Vsqrtpd) x))
 
 ;; Helper for creating `cvtss2sd` instructions.
-(decl x64_cvtss2sd (XmmMem) Xmm)
-(rule (x64_cvtss2sd x) (xmm_unary_rm_r_unaligned (SseOpcode.Cvtss2sd) x))
-(rule 1 (x64_cvtss2sd x)
+;;
+;; NB: see `x64_sqrtss` for why this has two args (same reasoning, different op)
+(decl x64_cvtss2sd (Xmm XmmMem) Xmm)
+(rule (x64_cvtss2sd x y) (xmm_rm_r_unaligned (SseOpcode.Cvtss2sd) x y))
+(rule 1 (x64_cvtss2sd x y)
         (if-let $true (use_avx))
-        (xmm_unary_rm_r_vex (AvxOpcode.Vcvtss2sd) x))
+        (xmm_rmir_vex (AvxOpcode.Vcvtss2sd) x y))
 
 ;; Helper for creating `cvtsd2ss` instructions.
-(decl x64_cvtsd2ss (XmmMem) Xmm)
-(rule (x64_cvtsd2ss x) (xmm_unary_rm_r_unaligned (SseOpcode.Cvtsd2ss) x))
-(rule 1 (x64_cvtsd2ss x)
+;;
+;; NB: see `x64_sqrtss` for why this has two args (same reasoning, different op)
+(decl x64_cvtsd2ss (Xmm XmmMem) Xmm)
+(rule (x64_cvtsd2ss x y) (xmm_rm_r_unaligned (SseOpcode.Cvtsd2ss) x y))
+(rule 1 (x64_cvtsd2ss x y)
         (if-let $true (use_avx))
-        (xmm_unary_rm_r_vex (AvxOpcode.Vcvtsd2ss) x))
+        (xmm_rmir_vex (AvxOpcode.Vcvtsd2ss) x y))
 
 ;; Helper for creating `cvtdq2ps` instructions.
 (decl x64_cvtdq2ps (XmmMem) Xmm)
diff --git a/cranelift/codegen/src/isa/x64/inst/emit.rs b/cranelift/codegen/src/isa/x64/inst/emit.rs
index 6bd65154e..1312a1578 100644
--- a/cranelift/codegen/src/isa/x64/inst/emit.rs
+++ b/cranelift/codegen/src/isa/x64/inst/emit.rs
@@ -1969,8 +1969,6 @@ pub(crate) fn emit(
                 SseOpcode::Cvtpd2ps => (LegacyPrefixes::_66, 0x0F5A, 2),
                 SseOpcode::Cvtps2pd => (LegacyPrefixes::None, 0x0F5A, 2),
                 SseOpcode::Cvtdq2ps => (LegacyPrefixes::None, 0x0F5B, 2),
-                SseOpcode::Cvtss2sd => (LegacyPrefixes::_F3, 0x0F5A, 2),
-                SseOpcode::Cvtsd2ss => (LegacyPrefixes::_F2, 0x0F5A, 2),
                 SseOpcode::Cvttpd2dq => (LegacyPrefixes::_66, 0x0FE6, 2),
                 SseOpcode::Cvttps2dq => (LegacyPrefixes::_F3, 0x0F5B, 2),
                 SseOpcode::Movaps => (LegacyPrefixes::None, 0x0F28, 2),
@@ -1998,8 +1996,6 @@ pub(crate) fn emit(
                 SseOpcode::Pmovzxdq => (LegacyPrefixes::_66, 0x0F3835, 3),
                 SseOpcode::Sqrtps => (LegacyPrefixes::None, 0x0F51, 2),
                 SseOpcode::Sqrtpd => (LegacyPrefixes::_66, 0x0F51, 2),
-                SseOpcode::Sqrtss => (LegacyPrefixes::_F3, 0x0F51, 2),
-                SseOpcode::Sqrtsd => (LegacyPrefixes::_F2, 0x0F51, 2),
                 SseOpcode::Movddup => (LegacyPrefixes::_F2, 0x0F12, 2),
                 _ => unimplemented!("Opcode {:?} not implemented", op),
             };
@@ -2231,6 +2227,10 @@ pub(crate) fn emit(
                 SseOpcode::Phaddw => (LegacyPrefixes::_66, 0x0F3801, 3),
                 SseOpcode::Phaddd => (LegacyPrefixes::_66, 0x0F3802, 3),
                 SseOpcode::Movss => (LegacyPrefixes::_F3, 0x0F10, 2),
+                SseOpcode::Cvtss2sd => (LegacyPrefixes::_F3, 0x0F5A, 2),
+                SseOpcode::Cvtsd2ss => (LegacyPrefixes::_F2, 0x0F5A, 2),
+                SseOpcode::Sqrtss => (LegacyPrefixes::_F3, 0x0F51, 2),
+                SseOpcode::Sqrtsd => (LegacyPrefixes::_F2, 0x0F51, 2),
                 _ => unimplemented!("Opcode {:?} not implemented", op),
             };
 
@@ -2452,6 +2452,10 @@ pub(crate) fn emit(
                 AvxOpcode::Vpunpckhqdq => (LP::_66, OM::_0F, 0x6D),
                 AvxOpcode::Vmovsd => (LP::_F2, OM::_0F, 0x10),
                 AvxOpcode::Vmovss => (LP::_F3, OM::_0F, 0x10),
+                AvxOpcode::Vcvtss2sd => (LP::_F3, OM::_0F, 0x5A),
+                AvxOpcode::Vcvtsd2ss => (LP::_F2, OM::_0F, 0x5A),
+                AvxOpcode::Vsqrtss => (LP::_F3, OM::_0F, 0x51),
+                AvxOpcode::Vsqrtsd => (LP::_F2, OM::_0F, 0x51),
                 _ => panic!("unexpected rmir vex opcode {op:?}"),
             };
             VexInstruction::new()
@@ -2681,36 +2685,17 @@ pub(crate) fn emit(
                 AvxOpcode::Vbroadcastss => (LegacyPrefixes::_66, OpcodeMap::_0F38, 0x18),
                 AvxOpcode::Vmovddup => (LegacyPrefixes::_F2, OpcodeMap::_0F, 0x12),
 
-                AvxOpcode::Vcvtss2sd => (LegacyPrefixes::_F3, OpcodeMap::_0F, 0x5A),
-                AvxOpcode::Vcvtsd2ss => (LegacyPrefixes::_F2, OpcodeMap::_0F, 0x5A),
-                AvxOpcode::Vsqrtss => (LegacyPrefixes::_F3, OpcodeMap::_0F, 0x51),
-                AvxOpcode::Vsqrtsd => (LegacyPrefixes::_F2, OpcodeMap::_0F, 0x51),
-
                 _ => panic!("unexpected rmr_imm_vex opcode {op:?}"),
             };
 
-            let vex = VexInstruction::new()
+            VexInstruction::new()
                 .length(VexVectorLength::V128)
                 .prefix(prefix)
                 .map(map)
                 .opcode(opcode)
                 .reg(dst.to_real_reg().unwrap().hw_enc())
-                .rm(src);
-
-            // These opcodes take a second operand through `vvvv` which copies
-            // the upper bits into the destination register. That's not
-            // reflected in the CLIF instruction, however, since the SSE version
-            // doesn't have this functionality. Instead just copy whatever
-            // happens to already be in the destination, which at least is what
-            // LLVM seems to do.
-            let vex = match op {
-                AvxOpcode::Vcvtss2sd
-                | AvxOpcode::Vcvtsd2ss
-                | AvxOpcode::Vsqrtss
-                | AvxOpcode::Vsqrtsd => vex.vvvv(dst.to_real_reg().unwrap().hw_enc()),
-                _ => vex,
-            };
-            vex.encode(sink);
+                .rm(src)
+                .encode(sink);
         }
 
         Inst::XmmUnaryRmRImmVex { op, src, dst, imm } => {
diff --git a/cranelift/codegen/src/isa/x64/lower.isle b/cranelift/codegen/src/isa/x64/lower.isle
index e0d17fe62..2452966a1 100644
--- a/cranelift/codegen/src/isa/x64/lower.isle
+++ b/cranelift/codegen/src/isa/x64/lower.isle
@@ -2577,9 +2577,9 @@
 
 ;; Rules for `sqrt` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 (rule (lower (has_type $F32 (sqrt x)))
-      (x64_sqrtss x))
+      (x64_sqrtss (xmm_zero $F32X4) x))
 (rule (lower (has_type $F64 (sqrt x)))
-      (x64_sqrtsd x))
+      (x64_sqrtsd (xmm_zero $F64X2) x))
 (rule (lower (has_type $F32X4 (sqrt x)))
       (x64_sqrtps x))
 (rule (lower (has_type $F64X2 (sqrt x)))
@@ -2587,7 +2587,7 @@
 
 ;; Rules for `fpromote` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 (rule (lower (has_type $F64 (fpromote x)))
-      (x64_cvtss2sd x))
+      (x64_cvtss2sd (xmm_zero $F64X2) x))
 
 ;; Rules for `fvpromote` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 (rule (lower (has_type $F64X2 (fvpromote_low x)))
@@ -2595,7 +2595,7 @@
 
 ;; Rules for `fdemote` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 (rule (lower (has_type $F32 (fdemote x)))
-      (x64_cvtsd2ss x))
+      (x64_cvtsd2ss (xmm_zero $F32X4) x))
 
 ;; Rules for `fvdemote` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 (rule (lower (has_type $F32X4 (fvdemote x)))
diff --git a/cranelift/codegen/src/isa/x64/mod.rs b/cranelift/codegen/src/isa/x64/mod.rs
index 38a9c668c..5aaa664fc 100644
--- a/cranelift/codegen/src/isa/x64/mod.rs
+++ b/cranelift/codegen/src/isa/x64/mod.rs
@@ -15,6 +15,7 @@ use crate::machinst::{
 };
 use crate::result::CodegenResult;
 use crate::settings::{self as shared_settings, Flags};
+use crate::{Final, MachBufferFinalized};
 use alloc::{boxed::Box, vec::Vec};
 use core::fmt;
 use cranelift_control::ControlPlane;
@@ -27,6 +28,8 @@ mod lower;
 mod pcc;
 pub mod settings;
 
+pub use inst::unwind::systemv::create_cie;
+
 /// An X64 backend.
 pub(crate) struct X64Backend {
     triple: Triple,
@@ -118,26 +121,7 @@ impl TargetIsa for X64Backend {
         result: &CompiledCode,
         kind: crate::isa::unwind::UnwindInfoKind,
     ) -> CodegenResult<Option<crate::isa::unwind::UnwindInfo>> {
-        use crate::isa::unwind::UnwindInfo;
-        use crate::isa::unwind::UnwindInfoKind;
-        Ok(match kind {
-            UnwindInfoKind::SystemV => {
-                let mapper = self::inst::unwind::systemv::RegisterMapper;
-                Some(UnwindInfo::SystemV(
-                    crate::isa::unwind::systemv::create_unwind_info_from_insts(
-                        &result.buffer.unwind_info[..],
-                        result.buffer.data().len(),
-                        &mapper,
-                    )?,
-                ))
-            }
-            UnwindInfoKind::Windows => Some(UnwindInfo::WindowsX64(
-                crate::isa::unwind::winx64::create_unwind_info_from_insts::<
-                    self::inst::unwind::winx64::RegisterMapper,
-                >(&result.buffer.unwind_info[..])?,
-            )),
-            _ => None,
-        })
+        emit_unwind_info(&result.buffer, kind)
     }
 
     #[cfg(feature = "unwind")]
@@ -193,6 +177,32 @@ impl TargetIsa for X64Backend {
     }
 }
 
+/// Emit unwind info for an x86 target.
+pub fn emit_unwind_info(
+    buffer: &MachBufferFinalized<Final>,
+    kind: crate::isa::unwind::UnwindInfoKind,
+) -> CodegenResult<Option<crate::isa::unwind::UnwindInfo>> {
+    use crate::isa::unwind::{UnwindInfo, UnwindInfoKind};
+    Ok(match kind {
+        UnwindInfoKind::SystemV => {
+            let mapper = self::inst::unwind::systemv::RegisterMapper;
+            Some(UnwindInfo::SystemV(
+                crate::isa::unwind::systemv::create_unwind_info_from_insts(
+                    &buffer.unwind_info[..],
+                    buffer.data().len(),
+                    &mapper,
+                )?,
+            ))
+        }
+        UnwindInfoKind::Windows => Some(UnwindInfo::WindowsX64(
+            crate::isa::unwind::winx64::create_unwind_info_from_insts::<
+                self::inst::unwind::winx64::RegisterMapper,
+            >(&buffer.unwind_info[..])?,
+        )),
+        _ => None,
+    })
+}
+
 impl fmt::Display for X64Backend {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
         f.debug_struct("MachBackend")
diff --git a/cranelift/codegen/src/lib.rs b/cranelift/codegen/src/lib.rs
index 5d9922bf7..1908bdd3d 100644
--- a/cranelift/codegen/src/lib.rs
+++ b/cranelift/codegen/src/lib.rs
@@ -59,8 +59,8 @@ pub use crate::machinst::buffer::{
 };
 pub use crate::machinst::{
     CompiledCode, Final, MachBuffer, MachBufferFinalized, MachInst, MachInstEmit,
-    MachInstEmitState, MachLabel, Reg, TextSectionBuilder, VCodeConstantData, VCodeConstants,
-    Writable,
+    MachInstEmitState, MachLabel, RealReg, Reg, TextSectionBuilder, VCodeConstantData,
+    VCodeConstants, Writable,
 };
 
 mod alias_analysis;
diff --git a/cranelift/codegen/src/machinst/reg.rs b/cranelift/codegen/src/machinst/reg.rs
index 8aadc11b5..4e21377d2 100644
--- a/cranelift/codegen/src/machinst/reg.rs
+++ b/cranelift/codegen/src/machinst/reg.rs
@@ -112,6 +112,7 @@ impl RealReg {
         self.0.class()
     }
 
+    /// The physical register number.
     pub fn hw_enc(self) -> u8 {
         PReg::from(self).hw_enc() as u8
     }
diff --git a/crates/runtime/src/vmcontext.rs b/crates/runtime/src/vmcontext.rs
index f79f063e3..b6e17c139 100644
--- a/crates/runtime/src/vmcontext.rs
+++ b/crates/runtime/src/vmcontext.rs
@@ -584,6 +584,11 @@ impl VMSharedSignatureIndex {
     /// Create a new `VMSharedSignatureIndex`.
     #[inline]
     pub fn new(value: u32) -> Self {
+        assert_ne!(
+            value,
+            u32::MAX,
+            "u32::MAX is reserved for the default value"
+        );
         Self(value)
     }
 
@@ -597,7 +602,7 @@ impl VMSharedSignatureIndex {
 impl Default for VMSharedSignatureIndex {
     #[inline]
     fn default() -> Self {
-        Self::new(u32::MAX)
+        Self(u32::MAX)
     }
 }
 
diff --git a/crates/wasmtime/src/signatures.rs b/crates/wasmtime/src/signatures.rs
index 6ce6b0150..b2327ef85 100644
--- a/crates/wasmtime/src/signatures.rs
+++ b/crates/wasmtime/src/signatures.rs
@@ -72,8 +72,20 @@ struct RegistryEntry {
 
 #[derive(Debug, Default)]
 struct SignatureRegistryInner {
+    // A map from the Wasm function type to a `VMSharedSignatureIndex`, for all
+    // the Wasm function types we have already registered.
     map: HashMap<WasmFuncType, VMSharedSignatureIndex>,
+
+    // A map from `VMSharedSignatureIndex::bits()` to the signature index's
+    // associated data, such as the underlying Wasm type.
     entries: Vec<Option<RegistryEntry>>,
+
+    // A free list of the `VMSharedSignatureIndex`es that are no longer being
+    // used by anything, and can therefore be reused.
+    //
+    // This is a size optimization, and not strictly necessary for correctness:
+    // we reuse entries rather than leak them and have logical holes in our
+    // `self.entries` list.
     free: Vec<VMSharedSignatureIndex>,
 }
 
@@ -99,8 +111,9 @@ impl SignatureRegistryInner {
                 let (index, entry) = match self.free.pop() {
                     Some(index) => (index, &mut self.entries[index.bits() as usize]),
                     None => {
-                        // Keep `index_map` len under 2**32 -- VMSharedSignatureIndex::new(std::u32::MAX)
-                        // is reserved for VMSharedSignatureIndex::default().
+                        // Keep `index_map`'s length under `u32::MAX` because
+                        // `u32::MAX` is reserved for `VMSharedSignatureIndex`'s
+                        // default value.
                         assert!(
                             len < std::u32::MAX as usize,
                             "Invariant check: index_map.len() < std::u32::MAX"
@@ -169,8 +182,13 @@ impl SignatureRegistryInner {
 impl Drop for SignatureRegistryInner {
     fn drop(&mut self) {
         assert!(
-            self.map.is_empty() && self.free.len() == self.entries.len(),
-            "signature registry not empty"
+            self.map.is_empty(),
+            "signature registry not empty: still have registered types in self.map"
+        );
+        assert_eq!(
+            self.free.len(),
+            self.entries.len(),
+            "signature registery not empty: not all entries in free list"
         );
     }
 }
diff --git a/crates/winch/src/compiler.rs b/crates/winch/src/compiler.rs
index bc1191887..c58318eb8 100644
--- a/crates/winch/src/compiler.rs
+++ b/crates/winch/src/compiler.rs
@@ -1,4 +1,5 @@
 use anyhow::Result;
+use cranelift_codegen::isa::unwind::UnwindInfoKind;
 use object::write::{Object, SymbolId};
 use std::any::Any;
 use std::mem;
@@ -63,6 +64,27 @@ impl Compiler {
         context.allocations = allocs;
         self.contexts.lock().unwrap().push(context);
     }
+
+    /// Emit unwind info into the [`CompiledFunction`].
+    fn emit_unwind_info(
+        &self,
+        compiled_function: &mut CompiledFunction<CompiledFuncEnv>,
+    ) -> Result<(), CompileError> {
+        let kind = match self.isa.triple().operating_system {
+            target_lexicon::OperatingSystem::Windows => UnwindInfoKind::Windows,
+            _ => UnwindInfoKind::SystemV,
+        };
+
+        if let Some(info) = self
+            .isa
+            .emit_unwind_info(&compiled_function.buffer, kind)
+            .map_err(|e| CompileError::Codegen(format!("{e:?}")))?
+        {
+            compiled_function.set_unwind_info(info);
+        }
+
+        Ok(())
+    }
 }
 
 impl wasmtime_environ::Compiler for Compiler {
@@ -98,9 +120,14 @@ impl wasmtime_environ::Compiler for Compiler {
             .map_err(|e| CompileError::Codegen(format!("{e:?}")));
         self.save_context(context, validator.into_allocations());
         let buffer = buffer?;
-        let compiled_function =
+
+        let mut compiled_function =
             CompiledFunction::new(buffer, CompiledFuncEnv {}, self.isa.function_alignment());
 
+        if self.isa.flags().unwind_info() {
+            self.emit_unwind_info(&mut compiled_function)?;
+        }
+
         Ok((
             WasmFunctionInfo {
                 start_srcloc,
@@ -123,9 +150,14 @@ impl wasmtime_environ::Compiler for Compiler {
             .isa
             .compile_trampoline(&ty, TrampolineKind::ArrayToWasm(func_index))
             .map_err(|e| CompileError::Codegen(format!("{:?}", e)))?;
-        let compiled_function =
+
+        let mut compiled_function =
             CompiledFunction::new(buffer, CompiledFuncEnv {}, self.isa.function_alignment());
 
+        if self.isa.flags().unwind_info() {
+            self.emit_unwind_info(&mut compiled_function)?;
+        }
+
         Ok(Box::new(compiled_function))
     }
 
@@ -144,9 +176,13 @@ impl wasmtime_environ::Compiler for Compiler {
             .compile_trampoline(ty, TrampolineKind::NativeToWasm(func_index))
             .map_err(|e| CompileError::Codegen(format!("{:?}", e)))?;
 
-        let compiled_function =
+        let mut compiled_function =
             CompiledFunction::new(buffer, CompiledFuncEnv {}, self.isa.function_alignment());
 
+        if self.isa.flags().unwind_info() {
+            self.emit_unwind_info(&mut compiled_function)?;
+        }
+
         Ok(Box::new(compiled_function))
     }
 
@@ -159,9 +195,13 @@ impl wasmtime_environ::Compiler for Compiler {
             .compile_trampoline(wasm_func_ty, TrampolineKind::WasmToNative)
             .map_err(|e| CompileError::Codegen(format!("{:?}", e)))?;
 
-        let compiled_function =
+        let mut compiled_function =
             CompiledFunction::new(buffer, CompiledFuncEnv {}, self.isa.function_alignment());
 
+        if self.isa.flags().unwind_info() {
+            self.emit_unwind_info(&mut compiled_function)?;
+        }
+
         Ok(Box::new(compiled_function))
     }
 
diff --git a/supply-chain/imports.lock b/supply-chain/imports.lock
index 1ffc14475..2ab2a8a11 100644
--- a/supply-chain/imports.lock
+++ b/supply-chain/imports.lock
@@ -1954,6 +1954,13 @@ user-id = 1
 user-login = "alexcrichton"
 user-name = "Alex Crichton"
 
+[[publisher.wasm-encoder]]
+version = "0.40.0"
+when = "2024-01-24"
+user-id = 1
+user-login = "alexcrichton"
+user-name = "Alex Crichton"
+
 [[publisher.wasm-metadata]]
 version = "0.10.9"
 when = "2023-10-14"
@@ -1996,6 +2003,13 @@ user-id = 1
 user-login = "alexcrichton"
 user-name = "Alex Crichton"
 
+[[publisher.wasm-metadata]]
+version = "0.10.16"
+when = "2024-01-24"
+user-id = 1
+user-login = "alexcrichton"
+user-name = "Alex Crichton"
+
 [[publisher.wasm-mutate]]
 version = "0.2.38"
 when = "2023-10-14"
@@ -2031,6 +2045,13 @@ user-id = 1
 user-login = "alexcrichton"
 user-name = "Alex Crichton"
 
+[[publisher.wasm-mutate]]
+version = "0.2.45"
+when = "2024-01-24"
+user-id = 1
+user-login = "alexcrichton"
+user-name = "Alex Crichton"
+
 [[publisher.wasm-smith]]
 version = "0.12.21"
 when = "2023-10-14"
@@ -2073,6 +2094,13 @@ user-id = 1
 user-login = "alexcrichton"
 user-name = "Alex Crichton"
 
+[[publisher.wasm-smith]]
+version = "0.15.0"
+when = "2024-01-24"
+user-id = 1
+user-login = "alexcrichton"
+user-name = "Alex Crichton"
+
 [[publisher.wasmparser]]
 version = "0.115.0"
 when = "2023-10-14"
@@ -2115,6 +2143,13 @@ user-id = 1
 user-login = "alexcrichton"
 user-name = "Alex Crichton"
 
+[[publisher.wasmparser]]
+version = "0.120.0"
+when = "2024-01-24"
+user-id = 1
+user-login = "alexcrichton"
+user-name = "Alex Crichton"
+
 [[publisher.wasmprinter]]
 version = "0.2.70"
 when = "2023-10-14"
@@ -2157,6 +2192,13 @@ user-id = 1
 user-login = "alexcrichton"
 user-name = "Alex Crichton"
 
+[[publisher.wasmprinter]]
+version = "0.2.77"
+when = "2024-01-24"
+user-id = 1
+user-login = "alexcrichton"
+user-name = "Alex Crichton"
+
 [[publisher.wasmtime]]
 version = "14.0.2"
 when = "2023-10-26"
@@ -2775,6 +2817,13 @@ user-id = 1
 user-login = "alexcrichton"
 user-name = "Alex Crichton"
 
+[[publisher.wast]]
+version = "70.0.1"
+when = "2024-01-24"
+user-id = 1
+user-login = "alexcrichton"
+user-name = "Alex Crichton"
+
 [[publisher.wat]]
 version = "1.0.77"
 when = "2023-10-14"
@@ -2817,6 +2866,13 @@ user-id = 1
 user-login = "alexcrichton"
 user-name = "Alex Crichton"
 
+[[publisher.wat]]
+version = "1.0.84"
+when = "2024-01-24"
+user-id = 1
+user-login = "alexcrichton"
+user-name = "Alex Crichton"
+
 [[publisher.wiggle]]
 version = "14.0.2"
 when = "2023-10-26"
@@ -3200,6 +3256,13 @@ user-id = 1
 user-login = "alexcrichton"
 user-name = "Alex Crichton"
 
+[[publisher.wit-component]]
+version = "0.20.0"
+when = "2024-01-24"
+user-id = 1
+user-login = "alexcrichton"
+user-name = "Alex Crichton"
+
 [[publisher.wit-parser]]
 version = "0.12.1"
 when = "2023-10-18"
diff --git a/winch/codegen/Cargo.toml b/winch/codegen/Cargo.toml
index cc2b942ff..90c52fa5c 100644
--- a/winch/codegen/Cargo.toml
+++ b/winch/codegen/Cargo.toml
@@ -19,7 +19,7 @@ target-lexicon = { workspace = true, features = ["std"] }
 # mostly to have access to `PReg`s and the calling convention.
 # In the next iteration we'll factor out the common bits so that they can be consumed
 # by Cranelift and Winch.
-cranelift-codegen = { workspace = true }
+cranelift-codegen = { workspace = true, features = ["unwind"] }
 regalloc2 = { workspace = true }
 gimli = { workspace = true }
 wasmtime-environ = { workspace = true }
diff --git a/winch/codegen/src/isa/aarch64/mod.rs b/winch/codegen/src/isa/aarch64/mod.rs
index 15d6b2188..a17e8fbdd 100644
--- a/winch/codegen/src/isa/aarch64/mod.rs
+++ b/winch/codegen/src/isa/aarch64/mod.rs
@@ -134,4 +134,12 @@ impl TargetIsa for Aarch64 {
     ) -> Result<MachBufferFinalized<Final>> {
         todo!()
     }
+
+    fn emit_unwind_info(
+        &self,
+        _result: &MachBufferFinalized<Final>,
+        _kind: cranelift_codegen::isa::unwind::UnwindInfoKind,
+    ) -> Result<Option<cranelift_codegen::isa::unwind::UnwindInfo>> {
+        todo!()
+    }
 }
diff --git a/winch/codegen/src/isa/mod.rs b/winch/codegen/src/isa/mod.rs
index 7ccf621f5..2579840d9 100644
--- a/winch/codegen/src/isa/mod.rs
+++ b/winch/codegen/src/isa/mod.rs
@@ -1,6 +1,7 @@
 use crate::{BuiltinFunctions, TrampolineKind};
 use anyhow::{anyhow, Result};
 use core::fmt::Formatter;
+use cranelift_codegen::isa::unwind::{UnwindInfo, UnwindInfoKind};
 use cranelift_codegen::isa::{CallConv, IsaBuilder};
 use cranelift_codegen::settings;
 use cranelift_codegen::{Final, MachBufferFinalized, TextSectionBuilder};
@@ -184,6 +185,12 @@ pub trait TargetIsa: Send + Sync {
         self.triple().endianness().unwrap()
     }
 
+    fn emit_unwind_info(
+        &self,
+        _result: &MachBufferFinalized<Final>,
+        _kind: UnwindInfoKind,
+    ) -> Result<Option<UnwindInfo>>;
+
     /// See `cranelift_codegen::isa::TargetIsa::create_systemv_cie`.
     fn create_systemv_cie(&self) -> Option<gimli::write::CommonInformationEntry> {
         // By default, an ISA cannot create a System V CIE.
diff --git a/winch/codegen/src/isa/reg.rs b/winch/codegen/src/isa/reg.rs
index 0a96df329..bfdcdb8fc 100644
--- a/winch/codegen/src/isa/reg.rs
+++ b/winch/codegen/src/isa/reg.rs
@@ -1,5 +1,6 @@
-use regalloc2::PReg;
+use cranelift_codegen::RealReg;
 pub use regalloc2::RegClass;
+use regalloc2::{PReg, VReg};
 
 /// A newtype abstraction on top of a physical register.
 //
@@ -71,3 +72,15 @@ impl std::fmt::Debug for Reg {
         write!(f, "{}", self.0)
     }
 }
+
+impl Into<VReg> for Reg {
+    fn into(self) -> VReg {
+        VReg::new(self.inner().index(), self.class())
+    }
+}
+
+impl Into<RealReg> for Reg {
+    fn into(self) -> RealReg {
+        Into::<VReg>::into(self).into()
+    }
+}
diff --git a/winch/codegen/src/isa/x64/asm.rs b/winch/codegen/src/isa/x64/asm.rs
index 256d4fb9f..27acea761 100644
--- a/winch/codegen/src/isa/x64/asm.rs
+++ b/winch/codegen/src/isa/x64/asm.rs
@@ -8,6 +8,7 @@ use cranelift_codegen::{
     entity::EntityRef,
     ir::{types, ConstantPool, ExternalName, LibCall, Opcode, TrapCode, UserExternalNameRef},
     isa::{
+        unwind::UnwindInst,
         x64::{
             args::{
                 self, AluRmiROpcode, Amode, CmpOpcode, DivSignedness, ExtMode, FromWritableReg,
@@ -229,6 +230,11 @@ impl Assembler {
         }
     }
 
+    /// Emit an unwind instruction.
+    pub fn emit_unwind_inst(&mut self, inst: UnwindInst) {
+        self.emit(Inst::Unwind { inst })
+    }
+
     /// Push register.
     pub fn push_r(&mut self, reg: Reg) {
         self.emit(Inst::Push64 { src: reg.into() });
@@ -627,9 +633,10 @@ impl Assembler {
             _ => unimplemented!(),
         };
 
-        self.emit(Inst::XmmUnaryRmRUnaligned {
+        self.emit(Inst::XmmRmRUnaligned {
             op,
-            src: Xmm::new(src.into()).expect("valid xmm unaligned").into(),
+            src2: Xmm::new(src.into()).expect("valid xmm unaligned").into(),
+            src1: dst.into(),
             dst: dst.into(),
         });
     }
@@ -1158,9 +1165,10 @@ impl Assembler {
             OperandSize::S128 => unreachable!(),
         };
 
-        self.emit(Inst::XmmUnaryRmR {
+        self.emit(Inst::XmmRmR {
             op,
-            src: Xmm::from(src).into(),
+            src2: Xmm::from(src).into(),
+            src1: dst.into(),
             dst: dst.into(),
         })
     }
diff --git a/winch/codegen/src/isa/x64/masm.rs b/winch/codegen/src/isa/x64/masm.rs
index 7000dacdd..680adb481 100644
--- a/winch/codegen/src/isa/x64/masm.rs
+++ b/winch/codegen/src/isa/x64/masm.rs
@@ -24,7 +24,8 @@ use crate::{
     masm::CalleeKind,
 };
 use cranelift_codegen::{
-    isa::x64::settings as x64_settings, settings, Final, MachBufferFinalized, MachLabel,
+    isa::unwind::UnwindInst, isa::x64::settings as x64_settings, settings, Final,
+    MachBufferFinalized, MachLabel,
 };
 
 use wasmtime_environ::{PtrSize, WasmType, WASM_PAGE_SIZE};
@@ -53,8 +54,25 @@ impl Masm for MacroAssembler {
         let stack_pointer = rsp();
 
         self.asm.push_r(frame_pointer);
+
+        if self.shared_flags.unwind_info() {
+            self.asm.emit_unwind_inst(UnwindInst::PushFrameRegs {
+                offset_upward_to_caller_sp: Self::ABI::arg_base_offset().try_into().unwrap(),
+            })
+        }
+
         self.asm
             .mov_rr(stack_pointer, frame_pointer, OperandSize::S64);
+
+        if self.shared_flags.unwind_info() {
+            self.asm.emit_unwind_inst(UnwindInst::DefineNewFrame {
+                offset_upward_to_caller_sp: Self::ABI::arg_base_offset().try_into().unwrap(),
+
+                // Clobbers appear directly after the RET and FP if they're present. As we just
+                // pushed the frame pointer, the offset to the clobbers will be `0`.
+                offset_downward_to_clobbers: 0,
+            })
+        }
     }
 
     fn check_stack(&mut self) {
@@ -107,6 +125,19 @@ impl Masm for MacroAssembler {
         }
     }
 
+    fn save(&mut self, clobber_offset: u32, reg: Reg, size: OperandSize) -> StackSlot {
+        let slot = self.push(reg, size);
+
+        if self.shared_flags.unwind_info() {
+            self.asm.emit_unwind_inst(UnwindInst::SaveReg {
+                clobber_offset,
+                reg: reg.into(),
+            });
+        }
+
+        slot
+    }
+
     fn reserve_stack(&mut self, bytes: u32) {
         if bytes == 0 {
             return;
diff --git a/winch/codegen/src/isa/x64/mod.rs b/winch/codegen/src/isa/x64/mod.rs
index 7e56d933f..e14baae00 100644
--- a/winch/codegen/src/isa/x64/mod.rs
+++ b/winch/codegen/src/isa/x64/mod.rs
@@ -169,4 +169,16 @@ impl TargetIsa for X64 {
 
         Ok(masm.finalize())
     }
+
+    fn emit_unwind_info(
+        &self,
+        buffer: &MachBufferFinalized<Final>,
+        kind: cranelift_codegen::isa::unwind::UnwindInfoKind,
+    ) -> Result<Option<cranelift_codegen::isa::unwind::UnwindInfo>> {
+        Ok(cranelift_codegen::isa::x64::emit_unwind_info(buffer, kind)?)
+    }
+
+    fn create_systemv_cie(&self) -> Option<gimli::write::CommonInformationEntry> {
+        Some(cranelift_codegen::isa::x64::create_cie())
+    }
 }
diff --git a/winch/codegen/src/masm.rs b/winch/codegen/src/masm.rs
index f12d284ec..3ea75a40e 100644
--- a/winch/codegen/src/masm.rs
+++ b/winch/codegen/src/masm.rs
@@ -766,4 +766,11 @@ pub(crate) trait MacroAssembler {
             self.free_stack(bytes);
         }
     }
+
+    /// Save the value of this register to the stack. By default this is the same as pushing the
+    /// register, however it's present in the [`MacroAssembler`] trait to ensure that it's possible
+    /// to add unwind info for register saves in backends.
+    fn save(&mut self, _off: u32, src: Reg, size: OperandSize) -> StackSlot {
+        self.push(src, size)
+    }
 }
diff --git a/winch/codegen/src/trampoline.rs b/winch/codegen/src/trampoline.rs
index 6d3e4bcfd..bd651ad63 100644
--- a/winch/codegen/src/trampoline.rs
+++ b/winch/codegen/src/trampoline.rs
@@ -705,8 +705,10 @@ where
     fn prologue_with_callee_saved(&mut self) {
         self.masm.prologue();
         // Save any callee-saved registers.
+        let mut off = 0;
         for (r, s) in &self.callee_saved_regs {
-            self.masm.push(*r, *s);
+            let slot = self.masm.save(off, *r, *s);
+            off += slot.size;
         }
     }
 


Test patch:
diff --git a/cranelift/codegen/src/isa/x64/inst/emit_tests.rs b/cranelift/codegen/src/isa/x64/inst/emit_tests.rs
index 147f61deb..b340f6e2a 100644
--- a/cranelift/codegen/src/isa/x64/inst/emit_tests.rs
+++ b/cranelift/codegen/src/isa/x64/inst/emit_tests.rs
@@ -4889,25 +4889,25 @@ fn test_x64_emit() {
     ));
 
     insns.push((
-        Inst::xmm_unary_rm_r(SseOpcode::Sqrtss, RegMem::reg(xmm7), w_xmm8),
+        Inst::xmm_rm_r(SseOpcode::Sqrtss, RegMem::reg(xmm7), w_xmm8),
         "F3440F51C7",
-        "sqrtss  %xmm7, %xmm8",
+        "sqrtss  %xmm8, %xmm7, %xmm8",
     ));
     insns.push((
-        Inst::xmm_unary_rm_r(SseOpcode::Sqrtsd, RegMem::reg(xmm1), w_xmm2),
+        Inst::xmm_rm_r(SseOpcode::Sqrtsd, RegMem::reg(xmm1), w_xmm2),
         "F20F51D1",
-        "sqrtsd  %xmm1, %xmm2",
+        "sqrtsd  %xmm2, %xmm1, %xmm2",
     ));
 
     insns.push((
-        Inst::xmm_unary_rm_r(SseOpcode::Cvtss2sd, RegMem::reg(xmm0), w_xmm1),
+        Inst::xmm_rm_r(SseOpcode::Cvtss2sd, RegMem::reg(xmm0), w_xmm1),
         "F30F5AC8",
-        "cvtss2sd %xmm0, %xmm1",
+        "cvtss2sd %xmm1, %xmm0, %xmm1",
     ));
     insns.push((
-        Inst::xmm_unary_rm_r(SseOpcode::Cvtsd2ss, RegMem::reg(xmm1), w_xmm0),
+        Inst::xmm_rm_r(SseOpcode::Cvtsd2ss, RegMem::reg(xmm1), w_xmm0),
         "F20F5AC1",
-        "cvtsd2ss %xmm1, %xmm0",
+        "cvtsd2ss %xmm0, %xmm1, %xmm0",
     ));
 
     insns.push((
diff --git a/cranelift/filetests/filetests/isa/x64/fpromote-demote-avx.clif b/cranelift/filetests/filetests/isa/x64/fpromote-demote-avx.clif
index 4b07ebfa4..3feb3e07e 100644
--- a/cranelift/filetests/filetests/isa/x64/fpromote-demote-avx.clif
+++ b/cranelift/filetests/filetests/isa/x64/fpromote-demote-avx.clif
@@ -11,7 +11,9 @@ block0(v0: f32):
 ;   pushq   %rbp
 ;   movq    %rsp, %rbp
 ; block0:
-;   vcvtss2sd %xmm0, %xmm0
+;   uninit  %xmm2
+;   vxorpd  %xmm2, %xmm2, %xmm4
+;   vcvtss2sd %xmm4, %xmm0, %xmm0
 ;   movq    %rbp, %rsp
 ;   popq    %rbp
 ;   ret
@@ -21,7 +23,8 @@ block0(v0: f32):
 ;   pushq %rbp
 ;   movq %rsp, %rbp
 ; block1: ; offset 0x4
-;   vcvtss2sd %xmm0, %xmm0, %xmm0
+;   vxorpd %xmm2, %xmm2, %xmm4
+;   vcvtss2sd %xmm0, %xmm4, %xmm0
 ;   movq %rbp, %rsp
 ;   popq %rbp
 ;   retq
@@ -42,9 +45,11 @@ block0(v1: i64, v2: f32):
 ;   movq    %rsp, %rbp
 ;   subq    %rsp, $16, %rsp
 ; block0:
-;   lea     rsp(0 + virtual offset), %rdx
-;   vmovss  %xmm0, 0(%rdx)
-;   vcvtss2sd 0(%rdx), %xmm0
+;   lea     rsp(0 + virtual offset), %r9
+;   vmovss  %xmm0, 0(%r9)
+;   uninit  %xmm5
+;   vxorpd  %xmm5, %xmm5, %xmm7
+;   vcvtss2sd %xmm7, 0(%r9), %xmm0
 ;   addq    %rsp, $16, %rsp
 ;   movq    %rbp, %rsp
 ;   popq    %rbp
@@ -56,9 +61,10 @@ block0(v1: i64, v2: f32):
 ;   movq %rsp, %rbp
 ;   subq $0x10, %rsp
 ; block1: ; offset 0x8
-;   leaq (%rsp), %rdx
-;   vmovss %xmm0, (%rdx) ; trap: heap_oob
-;   vcvtss2sd (%rdx), %xmm0, %xmm0 ; trap: heap_oob
+;   leaq (%rsp), %r9
+;   vmovss %xmm0, (%r9) ; trap: heap_oob
+;   vxorpd %xmm5, %xmm5, %xmm7
+;   vcvtss2sd (%r9), %xmm7, %xmm0 ; trap: heap_oob
 ;   addq $0x10, %rsp
 ;   movq %rbp, %rsp
 ;   popq %rbp
@@ -74,7 +80,9 @@ block0(v0: f64):
 ;   pushq   %rbp
 ;   movq    %rsp, %rbp
 ; block0:
-;   vcvtsd2ss %xmm0, %xmm0
+;   uninit  %xmm2
+;   vxorps  %xmm2, %xmm2, %xmm4
+;   vcvtsd2ss %xmm4, %xmm0, %xmm0
 ;   movq    %rbp, %rsp
 ;   popq    %rbp
 ;   ret
@@ -84,7 +92,8 @@ block0(v0: f64):
 ;   pushq %rbp
 ;   movq %rsp, %rbp
 ; block1: ; offset 0x4
-;   vcvtsd2ss %xmm0, %xmm0, %xmm0
+;   vxorps %xmm2, %xmm2, %xmm4
+;   vcvtsd2ss %xmm0, %xmm4, %xmm0
 ;   movq %rbp, %rsp
 ;   popq %rbp
 ;   retq
@@ -105,9 +114,11 @@ block0(v1: i64, v2: f64):
 ;   movq    %rsp, %rbp
 ;   subq    %rsp, $16, %rsp
 ; block0:
-;   lea     rsp(0 + virtual offset), %rdx
-;   vmovsd  %xmm0, 0(%rdx)
-;   vcvtsd2ss 0(%rdx), %xmm0
+;   lea     rsp(0 + virtual offset), %r9
+;   vmovsd  %xmm0, 0(%r9)
+;   uninit  %xmm5
+;   vxorps  %xmm5, %xmm5, %xmm7
+;   vcvtsd2ss %xmm7, 0(%r9), %xmm0
 ;   addq    %rsp, $16, %rsp
 ;   movq    %rbp, %rsp
 ;   popq    %rbp
@@ -119,9 +130,10 @@ block0(v1: i64, v2: f64):
 ;   movq %rsp, %rbp
 ;   subq $0x10, %rsp
 ; block1: ; offset 0x8
-;   leaq (%rsp), %rdx
-;   vmovsd %xmm0, (%rdx) ; trap: heap_oob
-;   vcvtsd2ss (%rdx), %xmm0, %xmm0 ; trap: heap_oob
+;   leaq (%rsp), %r9
+;   vmovsd %xmm0, (%r9) ; trap: heap_oob
+;   vxorps %xmm5, %xmm5, %xmm7
+;   vcvtsd2ss (%r9), %xmm7, %xmm0 ; trap: heap_oob
 ;   addq $0x10, %rsp
 ;   movq %rbp, %rsp
 ;   popq %rbp
diff --git a/cranelift/filetests/filetests/isa/x64/fpromote-demote.clif b/cranelift/filetests/filetests/isa/x64/fpromote-demote.clif
index 465460962..c7dc0db58 100644
--- a/cranelift/filetests/filetests/isa/x64/fpromote-demote.clif
+++ b/cranelift/filetests/filetests/isa/x64/fpromote-demote.clif
@@ -11,7 +11,11 @@ block0(v0: f32):
 ;   pushq   %rbp
 ;   movq    %rsp, %rbp
 ; block0:
-;   cvtss2sd %xmm0, %xmm0
+;   movdqa  %xmm0, %xmm5
+;   uninit  %xmm0
+;   xorpd   %xmm0, %xmm0, %xmm0
+;   movdqa  %xmm5, %xmm7
+;   cvtss2sd %xmm0, %xmm7, %xmm0
 ;   movq    %rbp, %rsp
 ;   popq    %rbp
 ;   ret
@@ -21,7 +25,10 @@ block0(v0: f32):
 ;   pushq %rbp
 ;   movq %rsp, %rbp
 ; block1: ; offset 0x4
-;   cvtss2sd %xmm0, %xmm0
+;   movdqa %xmm0, %xmm5
+;   xorpd %xmm0, %xmm0
+;   movdqa %xmm5, %xmm7
+;   cvtss2sd %xmm7, %xmm0
 ;   movq %rbp, %rsp
 ;   popq %rbp
 ;   retq
@@ -42,9 +49,11 @@ block0(v1: i64, v2: f32):
 ;   movq    %rsp, %rbp
 ;   subq    %rsp, $16, %rsp
 ; block0:
-;   lea     rsp(0 + virtual offset), %rdx
-;   movss   %xmm0, 0(%rdx)
-;   cvtss2sd 0(%rdx), %xmm0
+;   lea     rsp(0 + virtual offset), %r9
+;   movss   %xmm0, 0(%r9)
+;   uninit  %xmm0
+;   xorpd   %xmm0, %xmm0, %xmm0
+;   cvtss2sd %xmm0, 0(%r9), %xmm0
 ;   addq    %rsp, $16, %rsp
 ;   movq    %rbp, %rsp
 ;   popq    %rbp
@@ -56,9 +65,10 @@ block0(v1: i64, v2: f32):
 ;   movq %rsp, %rbp
 ;   subq $0x10, %rsp
 ; block1: ; offset 0x8
-;   leaq (%rsp), %rdx
-;   movss %xmm0, (%rdx) ; trap: heap_oob
-;   cvtss2sd (%rdx), %xmm0 ; trap: heap_oob
+;   leaq (%rsp), %r9
+;   movss %xmm0, (%r9) ; trap: heap_oob
+;   xorpd %xmm0, %xmm0
+;   cvtss2sd (%r9), %xmm0 ; trap: heap_oob
 ;   addq $0x10, %rsp
 ;   movq %rbp, %rsp
 ;   popq %rbp
@@ -74,7 +84,11 @@ block0(v0: f64):
 ;   pushq   %rbp
 ;   movq    %rsp, %rbp
 ; block0:
-;   cvtsd2ss %xmm0, %xmm0
+;   movdqa  %xmm0, %xmm5
+;   uninit  %xmm0
+;   xorps   %xmm0, %xmm0, %xmm0
+;   movdqa  %xmm5, %xmm7
+;   cvtsd2ss %xmm0, %xmm7, %xmm0
 ;   movq    %rbp, %rsp
 ;   popq    %rbp
 ;   ret
@@ -84,7 +98,10 @@ block0(v0: f64):
 ;   pushq %rbp
 ;   movq %rsp, %rbp
 ; block1: ; offset 0x4
-;   cvtsd2ss %xmm0, %xmm0
+;   movdqa %xmm0, %xmm5
+;   xorps %xmm0, %xmm0
+;   movdqa %xmm5, %xmm7
+;   cvtsd2ss %xmm7, %xmm0
 ;   movq %rbp, %rsp
 ;   popq %rbp
 ;   retq
@@ -105,9 +122,11 @@ block0(v1: i64, v2: f64):
 ;   movq    %rsp, %rbp
 ;   subq    %rsp, $16, %rsp
 ; block0:
-;   lea     rsp(0 + virtual offset), %rdx
-;   movsd   %xmm0, 0(%rdx)
-;   cvtsd2ss 0(%rdx), %xmm0
+;   lea     rsp(0 + virtual offset), %r9
+;   movsd   %xmm0, 0(%r9)
+;   uninit  %xmm0
+;   xorps   %xmm0, %xmm0, %xmm0
+;   cvtsd2ss %xmm0, 0(%r9), %xmm0
 ;   addq    %rsp, $16, %rsp
 ;   movq    %rbp, %rsp
 ;   popq    %rbp
@@ -119,9 +138,10 @@ block0(v1: i64, v2: f64):
 ;   movq %rsp, %rbp
 ;   subq $0x10, %rsp
 ; block1: ; offset 0x8
-;   leaq (%rsp), %rdx
-;   movsd %xmm0, (%rdx) ; trap: heap_oob
-;   cvtsd2ss (%rdx), %xmm0 ; trap: heap_oob
+;   leaq (%rsp), %r9
+;   movsd %xmm0, (%r9) ; trap: heap_oob
+;   xorps %xmm0, %xmm0
+;   cvtsd2ss (%r9), %xmm0 ; trap: heap_oob
 ;   addq $0x10, %rsp
 ;   movq %rbp, %rsp
 ;   popq %rbp
diff --git a/cranelift/filetests/filetests/isa/x64/fsqrt-avx.clif b/cranelift/filetests/filetests/isa/x64/fsqrt-avx.clif
index 1e87a00a2..7740c538c 100644
--- a/cranelift/filetests/filetests/isa/x64/fsqrt-avx.clif
+++ b/cranelift/filetests/filetests/isa/x64/fsqrt-avx.clif
@@ -11,7 +11,9 @@ block0(v0: f32):
 ;   pushq   %rbp
 ;   movq    %rsp, %rbp
 ; block0:
-;   vsqrtss %xmm0, %xmm0
+;   uninit  %xmm2
+;   vxorps  %xmm2, %xmm2, %xmm4
+;   vsqrtss %xmm4, %xmm0, %xmm0
 ;   movq    %rbp, %rsp
 ;   popq    %rbp
 ;   ret
@@ -21,7 +23,8 @@ block0(v0: f32):
 ;   pushq %rbp
 ;   movq %rsp, %rbp
 ; block1: ; offset 0x4
-;   vsqrtss %xmm0, %xmm0, %xmm0
+;   vxorps %xmm2, %xmm2, %xmm4
+;   vsqrtss %xmm0, %xmm4, %xmm0
 ;   movq %rbp, %rsp
 ;   popq %rbp
 ;   retq
@@ -36,7 +39,9 @@ block0(v0: f64):
 ;   pushq   %rbp
 ;   movq    %rsp, %rbp
 ; block0:
-;   vsqrtsd %xmm0, %xmm0
+;   uninit  %xmm2
+;   vxorpd  %xmm2, %xmm2, %xmm4
+;   vsqrtsd %xmm4, %xmm0, %xmm0
 ;   movq    %rbp, %rsp
 ;   popq    %rbp
 ;   ret
@@ -46,7 +51,8 @@ block0(v0: f64):
 ;   pushq %rbp
 ;   movq %rsp, %rbp
 ; block1: ; offset 0x4
-;   vsqrtsd %xmm0, %xmm0, %xmm0
+;   vxorpd %xmm2, %xmm2, %xmm4
+;   vsqrtsd %xmm0, %xmm4, %xmm0
 ;   movq %rbp, %rsp
 ;   popq %rbp
 ;   retq
diff --git a/cranelift/filetests/filetests/isa/x64/fsqrt.clif b/cranelift/filetests/filetests/isa/x64/fsqrt.clif
index ec4c3f742..be10b19ac 100644
--- a/cranelift/filetests/filetests/isa/x64/fsqrt.clif
+++ b/cranelift/filetests/filetests/isa/x64/fsqrt.clif
@@ -11,7 +11,11 @@ block0(v0: f32):
 ;   pushq   %rbp
 ;   movq    %rsp, %rbp
 ; block0:
-;   sqrtss  %xmm0, %xmm0
+;   movdqa  %xmm0, %xmm5
+;   uninit  %xmm0
+;   xorps   %xmm0, %xmm0, %xmm0
+;   movdqa  %xmm5, %xmm7
+;   sqrtss  %xmm0, %xmm7, %xmm0
 ;   movq    %rbp, %rsp
 ;   popq    %rbp
 ;   ret
@@ -21,7 +25,10 @@ block0(v0: f32):
 ;   pushq %rbp
 ;   movq %rsp, %rbp
 ; block1: ; offset 0x4
-;   sqrtss %xmm0, %xmm0
+;   movdqa %xmm0, %xmm5
+;   xorps %xmm0, %xmm0
+;   movdqa %xmm5, %xmm7
+;   sqrtss %xmm7, %xmm0
 ;   movq %rbp, %rsp
 ;   popq %rbp
 ;   retq
@@ -36,7 +43,11 @@ block0(v0: f64):
 ;   pushq   %rbp
 ;   movq    %rsp, %rbp
 ; block0:
-;   sqrtsd  %xmm0, %xmm0
+;   movdqa  %xmm0, %xmm5
+;   uninit  %xmm0
+;   xorpd   %xmm0, %xmm0, %xmm0
+;   movdqa  %xmm5, %xmm7
+;   sqrtsd  %xmm0, %xmm7, %xmm0
 ;   movq    %rbp, %rsp
 ;   popq    %rbp
 ;   ret
@@ -46,7 +57,10 @@ block0(v0: f64):
 ;   pushq %rbp
 ;   movq %rsp, %rbp
 ; block1: ; offset 0x4
-;   sqrtsd %xmm0, %xmm0
+;   movdqa %xmm0, %xmm5
+;   xorpd %xmm0, %xmm0
+;   movdqa %xmm5, %xmm7
+;   sqrtsd %xmm7, %xmm0
 ;   movq %rbp, %rsp
 ;   popq %rbp
 ;   retq