Repository: bytecodealliance/wasmtime
Pull request #4367 (2022-07-01 22:48:12)

Implement `fma`/`fabs`/`fneg`/`fcopysign` on the interpreter
👋  Hey, This implements a few more scalar floating point operations on the interpreter.

It also fixes some issues that `fneg` had and adds tests for that operation.



Patch:
diff --git a/Cargo.lock b/Cargo.lock
index 61be15734..4717e16e9 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -450,6 +450,15 @@ dependencies = [
  "cc",
 ]
 
+[[package]]
+name = "component-macro-test"
+version = "0.1.0"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
 [[package]]
 name = "console"
 version = "0.15.0"
@@ -491,7 +500,7 @@ dependencies = [
 
 [[package]]
 name = "cranelift"
-version = "0.86.0"
+version = "0.87.0"
 dependencies = [
  "cranelift-codegen",
  "cranelift-frontend",
@@ -499,14 +508,14 @@ dependencies = [
 
 [[package]]
 name = "cranelift-bforest"
-version = "0.86.0"
+version = "0.87.0"
 dependencies = [
  "cranelift-entity",
 ]
 
 [[package]]
 name = "cranelift-codegen"
-version = "0.86.0"
+version = "0.87.0"
 dependencies = [
  "bincode",
  "cranelift-bforest",
@@ -528,18 +537,18 @@ dependencies = [
 
 [[package]]
 name = "cranelift-codegen-meta"
-version = "0.86.0"
+version = "0.87.0"
 dependencies = [
  "cranelift-codegen-shared",
 ]
 
 [[package]]
 name = "cranelift-codegen-shared"
-version = "0.86.0"
+version = "0.87.0"
 
 [[package]]
 name = "cranelift-entity"
-version = "0.86.0"
+version = "0.87.0"
 dependencies = [
  "serde",
 ]
@@ -568,7 +577,7 @@ dependencies = [
 
 [[package]]
 name = "cranelift-frontend"
-version = "0.86.0"
+version = "0.87.0"
 dependencies = [
  "cranelift-codegen",
  "hashbrown",
@@ -588,7 +597,7 @@ dependencies = [
 
 [[package]]
 name = "cranelift-interpreter"
-version = "0.86.0"
+version = "0.87.0"
 dependencies = [
  "cranelift-codegen",
  "cranelift-entity",
@@ -601,7 +610,7 @@ dependencies = [
 
 [[package]]
 name = "cranelift-isle"
-version = "0.86.0"
+version = "0.87.0"
 dependencies = [
  "log",
  "miette",
@@ -610,7 +619,7 @@ dependencies = [
 
 [[package]]
 name = "cranelift-jit"
-version = "0.86.0"
+version = "0.87.0"
 dependencies = [
  "anyhow",
  "cranelift",
@@ -629,7 +638,7 @@ dependencies = [
 
 [[package]]
 name = "cranelift-module"
-version = "0.86.0"
+version = "0.87.0"
 dependencies = [
  "anyhow",
  "cranelift-codegen",
@@ -638,7 +647,7 @@ dependencies = [
 
 [[package]]
 name = "cranelift-native"
-version = "0.86.0"
+version = "0.87.0"
 dependencies = [
  "cranelift-codegen",
  "libc",
@@ -647,7 +656,7 @@ dependencies = [
 
 [[package]]
 name = "cranelift-object"
-version = "0.86.0"
+version = "0.87.0"
 dependencies = [
  "anyhow",
  "cranelift-codegen",
@@ -661,14 +670,14 @@ dependencies = [
 
 [[package]]
 name = "cranelift-preopt"
-version = "0.86.0"
+version = "0.87.0"
 dependencies = [
  "cranelift-codegen",
 ]
 
 [[package]]
 name = "cranelift-reader"
-version = "0.86.0"
+version = "0.87.0"
 dependencies = [
  "cranelift-codegen",
  "smallvec",
@@ -677,7 +686,7 @@ dependencies = [
 
 [[package]]
 name = "cranelift-serde"
-version = "0.86.0"
+version = "0.87.0"
 dependencies = [
  "clap 3.1.15",
  "cranelift-codegen",
@@ -721,7 +730,7 @@ dependencies = [
 
 [[package]]
 name = "cranelift-wasm"
-version = "0.86.0"
+version = "0.87.0"
 dependencies = [
  "cranelift-codegen",
  "cranelift-entity",
@@ -1631,11 +1640,11 @@ checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d"
 
 [[package]]
 name = "memfd"
-version = "0.4.1"
+version = "0.6.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f6627dc657574b49d6ad27105ed671822be56e0d2547d413bfbf3e8d8fa92e7a"
+checksum = "480b5a5de855d11ff13195950bdc8b98b5e942ef47afc447f6615cdcc4e15d80"
 dependencies = [
- "libc",
+ "rustix",
 ]
 
 [[package]]
@@ -3080,7 +3089,7 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
 
 [[package]]
 name = "wasi-cap-std-sync"
-version = "0.39.0"
+version = "0.40.0"
 dependencies = [
  "anyhow",
  "async-trait",
@@ -3103,7 +3112,7 @@ dependencies = [
 
 [[package]]
 name = "wasi-common"
-version = "0.39.0"
+version = "0.40.0"
 dependencies = [
  "anyhow",
  "bitflags",
@@ -3148,7 +3157,7 @@ dependencies = [
 
 [[package]]
 name = "wasi-tokio"
-version = "0.39.0"
+version = "0.40.0"
 dependencies = [
  "anyhow",
  "cap-std",
@@ -3309,7 +3318,7 @@ dependencies = [
 
 [[package]]
 name = "wasmtime"
-version = "0.39.0"
+version = "0.40.0"
 dependencies = [
  "anyhow",
  "async-trait",
@@ -3385,7 +3394,7 @@ dependencies = [
 
 [[package]]
 name = "wasmtime-cache"
-version = "0.39.0"
+version = "0.40.0"
 dependencies = [
  "anyhow",
  "base64",
@@ -3408,11 +3417,12 @@ dependencies = [
 
 [[package]]
 name = "wasmtime-cli"
-version = "0.39.0"
+version = "0.40.0"
 dependencies = [
  "anyhow",
  "async-trait",
  "clap 3.1.15",
+ "component-macro-test",
  "criterion",
  "env_logger 0.9.0",
  "filecheck",
@@ -3448,7 +3458,7 @@ dependencies = [
 
 [[package]]
 name = "wasmtime-cli-flags"
-version = "0.39.0"
+version = "0.40.0"
 dependencies = [
  "anyhow",
  "clap 3.1.15",
@@ -3460,7 +3470,7 @@ dependencies = [
 
 [[package]]
 name = "wasmtime-component-macro"
-version = "0.39.0"
+version = "0.40.0"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -3469,7 +3479,7 @@ dependencies = [
 
 [[package]]
 name = "wasmtime-cranelift"
-version = "0.39.0"
+version = "0.40.0"
 dependencies = [
  "anyhow",
  "cranelift-codegen",
@@ -3489,7 +3499,7 @@ dependencies = [
 
 [[package]]
 name = "wasmtime-environ"
-version = "0.39.0"
+version = "0.40.0"
 dependencies = [
  "anyhow",
  "cranelift-entity",
@@ -3507,7 +3517,7 @@ dependencies = [
 
 [[package]]
 name = "wasmtime-fiber"
-version = "0.39.0"
+version = "0.40.0"
 dependencies = [
  "backtrace",
  "cc",
@@ -3559,7 +3569,7 @@ dependencies = [
 
 [[package]]
 name = "wasmtime-jit"
-version = "0.39.0"
+version = "0.40.0"
 dependencies = [
  "addr2line",
  "anyhow",
@@ -3584,7 +3594,7 @@ dependencies = [
 
 [[package]]
 name = "wasmtime-jit-debug"
-version = "0.39.0"
+version = "0.40.0"
 dependencies = [
  "lazy_static",
  "object",
@@ -3593,7 +3603,7 @@ dependencies = [
 
 [[package]]
 name = "wasmtime-runtime"
-version = "0.39.0"
+version = "0.40.0"
 dependencies = [
  "anyhow",
  "backtrace",
@@ -3618,7 +3628,7 @@ dependencies = [
 
 [[package]]
 name = "wasmtime-types"
-version = "0.39.0"
+version = "0.40.0"
 dependencies = [
  "cranelift-entity",
  "serde",
@@ -3628,7 +3638,7 @@ dependencies = [
 
 [[package]]
 name = "wasmtime-wasi"
-version = "0.39.0"
+version = "0.40.0"
 dependencies = [
  "anyhow",
  "wasi-cap-std-sync",
@@ -3640,7 +3650,7 @@ dependencies = [
 
 [[package]]
 name = "wasmtime-wasi-crypto"
-version = "0.39.0"
+version = "0.40.0"
 dependencies = [
  "anyhow",
  "wasi-crypto",
@@ -3650,7 +3660,7 @@ dependencies = [
 
 [[package]]
 name = "wasmtime-wasi-nn"
-version = "0.39.0"
+version = "0.40.0"
 dependencies = [
  "anyhow",
  "openvino",
@@ -3661,7 +3671,7 @@ dependencies = [
 
 [[package]]
 name = "wasmtime-wast"
-version = "0.39.0"
+version = "0.40.0"
 dependencies = [
  "anyhow",
  "wasmtime",
@@ -3721,7 +3731,7 @@ dependencies = [
 
 [[package]]
 name = "wiggle"
-version = "0.39.0"
+version = "0.40.0"
 dependencies = [
  "anyhow",
  "async-trait",
@@ -3738,7 +3748,7 @@ dependencies = [
 
 [[package]]
 name = "wiggle-generate"
-version = "0.39.0"
+version = "0.40.0"
 dependencies = [
  "anyhow",
  "heck",
@@ -3751,7 +3761,7 @@ dependencies = [
 
 [[package]]
 name = "wiggle-macro"
-version = "0.39.0"
+version = "0.40.0"
 dependencies = [
  "proc-macro2",
  "quote",
diff --git a/Cargo.toml b/Cargo.toml
index 706b3aeb9..74e73f195 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -1,6 +1,6 @@
 [package]
 name = "wasmtime-cli"
-version = "0.39.0"
+version = "0.40.0"
 authors = ["The Wasmtime Project Developers"]
 description = "Command-line interface for Wasmtime"
 license = "Apache-2.0 WITH LLVM-exception"
@@ -21,15 +21,15 @@ path = "src/bin/wasmtime.rs"
 doc = false
 
 [dependencies]
-wasmtime = { path = "crates/wasmtime", version = "0.39.0", default-features = false, features = ['cache', 'cranelift'] }
-wasmtime-cache = { path = "crates/cache", version = "=0.39.0" }
-wasmtime-cli-flags = { path = "crates/cli-flags", version = "=0.39.0" }
-wasmtime-cranelift = { path = "crates/cranelift", version = "=0.39.0" }
-wasmtime-environ = { path = "crates/environ", version = "=0.39.0" }
-wasmtime-wast = { path = "crates/wast", version = "=0.39.0" }
-wasmtime-wasi = { path = "crates/wasi", version = "0.39.0" }
-wasmtime-wasi-crypto = { path = "crates/wasi-crypto", version = "0.39.0", optional = true }
-wasmtime-wasi-nn = { path = "crates/wasi-nn", version = "0.39.0", optional = true }
+wasmtime = { path = "crates/wasmtime", version = "0.40.0", default-features = false, features = ['cache', 'cranelift'] }
+wasmtime-cache = { path = "crates/cache", version = "=0.40.0" }
+wasmtime-cli-flags = { path = "crates/cli-flags", version = "=0.40.0" }
+wasmtime-cranelift = { path = "crates/cranelift", version = "=0.40.0" }
+wasmtime-environ = { path = "crates/environ", version = "=0.40.0" }
+wasmtime-wast = { path = "crates/wast", version = "=0.40.0" }
+wasmtime-wasi = { path = "crates/wasi", version = "0.40.0" }
+wasmtime-wasi-crypto = { path = "crates/wasi-crypto", version = "0.40.0", optional = true }
+wasmtime-wasi-nn = { path = "crates/wasi-nn", version = "0.40.0", optional = true }
 clap = { version = "3.1.12", features = ["color", "suggestions", "derive"] }
 anyhow = "1.0.19"
 target-lexicon = { version = "0.12.0", default-features = false }
@@ -43,7 +43,7 @@ rustix = { version = "0.35.6", features = ["mm", "param"] }
 
 [dev-dependencies]
 # depend again on wasmtime to activate its default features for tests
-wasmtime = { path = "crates/wasmtime", version = "0.39.0" }
+wasmtime = { path = "crates/wasmtime", version = "0.40.0" }
 env_logger = "0.9.0"
 filecheck = "0.5.0"
 more-asserts = "0.2.1"
@@ -60,6 +60,7 @@ async-trait = "0.1"
 wat = "1.0.43"
 once_cell = "1.9.0"
 rayon = "1.5.0"
+component-macro-test = { path = "crates/misc/component-macro-test" }
 
 [target.'cfg(windows)'.dev-dependencies]
 windows-sys = { version = "0.36.0", features = ["Win32_System_Memory"] }
diff --git a/RELEASES.md b/RELEASES.md
index d2620d21a..7349857e6 100644
--- a/RELEASES.md
+++ b/RELEASES.md
@@ -1,5 +1,15 @@
 --------------------------------------------------------------------------------
 
+## 0.40.0
+
+Unreleased.
+
+### Added
+
+### Changed
+
+--------------------------------------------------------------------------------
+
 ## 0.39.0
 
 Unreleased.
@@ -37,6 +47,10 @@ Unreleased.
   It's recommended to only used the set of named `[features]` for Wasmtime.
   [#4293](https://github.com/bytecodealliance/wasmtime/pull/4293)
 
+* Register allocation has fixed a few issues related to excessive memory usage
+  at compile time.
+  [#4324](https://github.com/bytecodealliance/wasmtime/pull/4324)
+
 ### Fixed
 
 * A refactor of `Config` was made to fix an issue that the order of calls to `Config`
@@ -48,6 +62,10 @@ Unreleased.
   `simd` feature is disabled in `Config`.
   [#4231](https://github.com/bytecodealliance/wasmtime/pull/4231)
 
+* Generation of platform-specific unwinding information is disabled if
+  `wasm_backtrace` and `wasm_reference_types` are both disabled.
+  [#4351](https://github.com/bytecodealliance/wasmtime/pull/4351)
+
 --------------------------------------------------------------------------------
 
 ## 0.38.1
diff --git a/cranelift/Cargo.toml b/cranelift/Cargo.toml
index 04999a53a..9f15c8796 100644
--- a/cranelift/Cargo.toml
+++ b/cranelift/Cargo.toml
@@ -15,19 +15,19 @@ path = "src/clif-util.rs"
 
 [dependencies]
 cfg-if = "1.0"
-cranelift-codegen = { path = "codegen", version = "0.86.0" }
-cranelift-entity = { path = "entity", version = "0.86.0" }
-cranelift-interpreter = { path = "interpreter", version = "0.86.0" }
-cranelift-reader = { path = "reader", version = "0.86.0" }
-cranelift-frontend = { path = "frontend", version = "0.86.0" }
-cranelift-wasm = { path = "wasm", version = "0.86.0", optional = true }
-cranelift-native = { path = "native", version = "0.86.0" }
+cranelift-codegen = { path = "codegen", version = "0.87.0" }
+cranelift-entity = { path = "entity", version = "0.87.0" }
+cranelift-interpreter = { path = "interpreter", version = "0.87.0" }
+cranelift-reader = { path = "reader", version = "0.87.0" }
+cranelift-frontend = { path = "frontend", version = "0.87.0" }
+cranelift-wasm = { path = "wasm", version = "0.87.0", optional = true }
+cranelift-native = { path = "native", version = "0.87.0" }
 cranelift-filetests = { path = "filetests", version = "0.73.0" }
-cranelift-module = { path = "module", version = "0.86.0" }
-cranelift-object = { path = "object", version = "0.86.0" }
-cranelift-jit = { path = "jit", version = "0.86.0" }
-cranelift-preopt = { path = "preopt", version = "0.86.0" }
-cranelift = { path = "umbrella", version = "0.86.0" }
+cranelift-module = { path = "module", version = "0.87.0" }
+cranelift-object = { path = "object", version = "0.87.0" }
+cranelift-jit = { path = "jit", version = "0.87.0" }
+cranelift-preopt = { path = "preopt", version = "0.87.0" }
+cranelift = { path = "umbrella", version = "0.87.0" }
 filecheck = "0.5.0"
 log = "0.4.8"
 termcolor = "1.1.2"
diff --git a/cranelift/bforest/Cargo.toml b/cranelift/bforest/Cargo.toml
index 006d87bae..870607a86 100644
--- a/cranelift/bforest/Cargo.toml
+++ b/cranelift/bforest/Cargo.toml
@@ -1,7 +1,7 @@
 [package]
 authors = ["The Cranelift Project Developers"]
 name = "cranelift-bforest"
-version = "0.86.0"
+version = "0.87.0"
 description = "A forest of B+-trees"
 license = "Apache-2.0 WITH LLVM-exception"
 documentation = "https://docs.rs/cranelift-bforest"
@@ -12,7 +12,7 @@ keywords = ["btree", "forest", "set", "map"]
 edition = "2021"
 
 [dependencies]
-cranelift-entity = { path = "../entity", version = "0.86.0", default-features = false }
+cranelift-entity = { path = "../entity", version = "0.87.0", default-features = false }
 
 [badges]
 maintenance = { status = "experimental" }
diff --git a/cranelift/codegen/Cargo.toml b/cranelift/codegen/Cargo.toml
index 5cfdb07e8..23e631cc7 100644
--- a/cranelift/codegen/Cargo.toml
+++ b/cranelift/codegen/Cargo.toml
@@ -1,7 +1,7 @@
 [package]
 authors = ["The Cranelift Project Developers"]
 name = "cranelift-codegen"
-version = "0.86.0"
+version = "0.87.0"
 description = "Low-level code generator library"
 license = "Apache-2.0 WITH LLVM-exception"
 documentation = "https://docs.rs/cranelift-codegen"
@@ -13,9 +13,9 @@ build = "build.rs"
 edition = "2021"
 
 [dependencies]
-cranelift-codegen-shared = { path = "./shared", version = "0.86.0" }
-cranelift-entity = { path = "../entity", version = "0.86.0" }
-cranelift-bforest = { path = "../bforest", version = "0.86.0" }
+cranelift-codegen-shared = { path = "./shared", version = "0.87.0" }
+cranelift-entity = { path = "../entity", version = "0.87.0" }
+cranelift-bforest = { path = "../bforest", version = "0.87.0" }
 hashbrown = { version = "0.11", optional = true }
 target-lexicon = "0.12"
 log = { version = "0.4.6", default-features = false }
@@ -34,8 +34,8 @@ souper-ir = { version = "2.1.0", optional = true }
 criterion = "0.3"
 
 [build-dependencies]
-cranelift-codegen-meta = { path = "meta", version = "0.86.0" }
-cranelift-isle = { path = "../isle/isle", version = "=0.86.0" }
+cranelift-codegen-meta = { path = "meta", version = "0.87.0" }
+cranelift-isle = { path = "../isle/isle", version = "=0.87.0" }
 miette = { version = "4.7.0", features = ["fancy"], optional = true }
 
 [features]
diff --git a/cranelift/codegen/meta/Cargo.toml b/cranelift/codegen/meta/Cargo.toml
index af0268f91..5716637b7 100644
--- a/cranelift/codegen/meta/Cargo.toml
+++ b/cranelift/codegen/meta/Cargo.toml
@@ -1,7 +1,7 @@
 [package]
 name = "cranelift-codegen-meta"
 authors = ["The Cranelift Project Developers"]
-version = "0.86.0"
+version = "0.87.0"
 description = "Metaprogram for cranelift-codegen code generator library"
 license = "Apache-2.0 WITH LLVM-exception"
 repository = "https://github.com/bytecodealliance/wasmtime"
@@ -13,7 +13,7 @@ edition = "2021"
 # rustdoc-args = [ "--document-private-items" ]
 
 [dependencies]
-cranelift-codegen-shared = { path = "../shared", version = "0.86.0" }
+cranelift-codegen-shared = { path = "../shared", version = "0.87.0" }
 
 [badges]
 maintenance = { status = "experimental" }
diff --git a/cranelift/codegen/shared/Cargo.toml b/cranelift/codegen/shared/Cargo.toml
index 0626daa85..40cb546f9 100644
--- a/cranelift/codegen/shared/Cargo.toml
+++ b/cranelift/codegen/shared/Cargo.toml
@@ -1,7 +1,7 @@
 [package]
 authors = ["The Cranelift Project Developers"]
 name = "cranelift-codegen-shared"
-version = "0.86.0"
+version = "0.87.0"
 description = "For code shared between cranelift-codegen-meta and cranelift-codegen"
 license = "Apache-2.0 WITH LLVM-exception"
 repository = "https://github.com/bytecodealliance/wasmtime"
diff --git a/cranelift/codegen/src/ir/immediates.rs b/cranelift/codegen/src/ir/immediates.rs
index 704a6a78e..59e32be9d 100644
--- a/cranelift/codegen/src/ir/immediates.rs
+++ b/cranelift/codegen/src/ir/immediates.rs
@@ -12,6 +12,7 @@ use core::str::FromStr;
 use core::{i32, u32};
 #[cfg(feature = "enable-serde")]
 use serde::{Deserialize, Serialize};
+use std::ops::Neg;
 
 /// Convert a type into a vector of bytes; all implementors in this file must use little-endian
 /// orderings of bytes to match WebAssembly's little-endianness.
@@ -761,18 +762,39 @@ impl Ieee32 {
 
     /// Check if the value is a NaN.
     pub fn is_nan(&self) -> bool {
-        f32::from_bits(self.0).is_nan()
+        self.as_f32().is_nan()
+    }
+
+    /// Converts Self to a rust f32
+    pub fn as_f32(self) -> f32 {
+        f32::from_bits(self.0)
+    }
+
+    /// Fused multiply-add. Computes (self * a) + b with only one rounding error, yielding a
+    /// more accurate result than an unfused multiply-add.
+    pub fn mul_add(&self, a: Self, b: Self) -> Self {
+        Self::with_float(self.as_f32().mul_add(a.as_f32(), b.as_f32()))
     }
 
     /// Returns the square root of self.
     pub fn sqrt(self) -> Self {
-        Self::with_float(f32::from_bits(self.0).sqrt())
+        Self::with_float(self.as_f32().sqrt())
+    }
+
+    /// Computes the absolute value of self.
+    pub fn abs(self) -> Self {
+        Self::with_float(self.as_f32().abs())
+    }
+
+    /// Returns a number composed of the magnitude of self and the sign of sign.
+    pub fn copysign(self, sign: Self) -> Self {
+        Self::with_float(self.as_f32().copysign(sign.as_f32()))
     }
 }
 
 impl PartialOrd for Ieee32 {
     fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
-        f32::from_bits(self.0).partial_cmp(&f32::from_bits(other.0))
+        self.as_f32().partial_cmp(&other.as_f32())
     }
 }
 
@@ -806,6 +828,14 @@ impl IntoBytes for Ieee32 {
     }
 }
 
+impl Neg for Ieee32 {
+    type Output = Ieee32;
+
+    fn neg(self) -> Self::Output {
+        Self::with_float(self.as_f32().neg())
+    }
+}
+
 impl Ieee64 {
     /// Create a new `Ieee64` containing the bits of `x`.
     pub fn with_bits(x: u64) -> Self {
@@ -851,18 +881,39 @@ impl Ieee64 {
     /// Check if the value is a NaN. For [Ieee64], this means checking that the 11 exponent bits are
     /// all set.
     pub fn is_nan(&self) -> bool {
-        f64::from_bits(self.0).is_nan()
+        self.as_f64().is_nan()
+    }
+
+    /// Converts Self to a rust f64
+    pub fn as_f64(self) -> f64 {
+        f64::from_bits(self.0)
+    }
+
+    /// Fused multiply-add. Computes (self * a) + b with only one rounding error, yielding a
+    /// more accurate result than an unfused multiply-add.
+    pub fn mul_add(&self, a: Self, b: Self) -> Self {
+        Self::with_float(self.as_f64().mul_add(a.as_f64(), b.as_f64()))
     }
 
     /// Returns the square root of self.
     pub fn sqrt(self) -> Self {
-        Self::with_float(f64::from_bits(self.0).sqrt())
+        Self::with_float(self.as_f64().sqrt())
+    }
+
+    /// Computes the absolute value of self.
+    pub fn abs(self) -> Self {
+        Self::with_float(self.as_f64().abs())
+    }
+
+    /// Returns a number composed of the magnitude of self and the sign of sign.
+    pub fn copysign(self, sign: Self) -> Self {
+        Self::with_float(self.as_f64().copysign(sign.as_f64()))
     }
 }
 
 impl PartialOrd for Ieee64 {
     fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
-        f64::from_bits(self.0).partial_cmp(&f64::from_bits(other.0))
+        self.as_f64().partial_cmp(&other.as_f64())
     }
 }
 
@@ -902,6 +953,14 @@ impl IntoBytes for Ieee64 {
     }
 }
 
+impl Neg for Ieee64 {
+    type Output = Ieee64;
+
+    fn neg(self) -> Self::Output {
+        Self::with_float(self.as_f64().neg())
+    }
+}
+
 #[cfg(test)]
 mod tests {
     use super::*;
diff --git a/cranelift/entity/Cargo.toml b/cranelift/entity/Cargo.toml
index c931136c8..10c88dd7a 100644
--- a/cranelift/entity/Cargo.toml
+++ b/cranelift/entity/Cargo.toml
@@ -1,7 +1,7 @@
 [package]
 authors = ["The Cranelift Project Developers"]
 name = "cranelift-entity"
-version = "0.86.0"
+version = "0.87.0"
 description = "Data structures using entity references as mapping keys"
 license = "Apache-2.0 WITH LLVM-exception"
 documentation = "https://docs.rs/cranelift-entity"
diff --git a/cranelift/frontend/Cargo.toml b/cranelift/frontend/Cargo.toml
index 82e04fc9d..20bd91e5d 100644
--- a/cranelift/frontend/Cargo.toml
+++ b/cranelift/frontend/Cargo.toml
@@ -1,7 +1,7 @@
 [package]
 authors = ["The Cranelift Project Developers"]
 name = "cranelift-frontend"
-version = "0.86.0"
+version = "0.87.0"
 description = "Cranelift IR builder helper"
 license = "Apache-2.0 WITH LLVM-exception"
 documentation = "https://docs.rs/cranelift-frontend"
@@ -11,7 +11,7 @@ readme = "README.md"
 edition = "2021"
 
 [dependencies]
-cranelift-codegen = { path = "../codegen", version = "0.86.0", default-features = false }
+cranelift-codegen = { path = "../codegen", version = "0.87.0", default-features = false }
 target-lexicon = "0.12"
 log = { version = "0.4.6", default-features = false }
 hashbrown = { version = "0.11", optional = true }
diff --git a/cranelift/fuzzgen/Cargo.toml b/cranelift/fuzzgen/Cargo.toml
index c39ad48fd..139fed1b3 100644
--- a/cranelift/fuzzgen/Cargo.toml
+++ b/cranelift/fuzzgen/Cargo.toml
@@ -11,7 +11,7 @@ publish = false
 
 
 [dependencies]
-cranelift = { path = "../umbrella", version = "0.86.0" }
+cranelift = { path = "../umbrella", version = "0.87.0" }
 
 anyhow = "1.0.19"
 arbitrary = "1.0.0"
diff --git a/cranelift/interpreter/Cargo.toml b/cranelift/interpreter/Cargo.toml
index b97f9c9ed..4003495cb 100644
--- a/cranelift/interpreter/Cargo.toml
+++ b/cranelift/interpreter/Cargo.toml
@@ -1,6 +1,6 @@
 [package]
 name = "cranelift-interpreter"
-version = "0.86.0"
+version = "0.87.0"
 authors = ["The Cranelift Project Developers"]
 description = "Interpret Cranelift IR"
 repository = "https://github.com/bytecodealliance/wasmtime"
@@ -11,15 +11,15 @@ readme = "README.md"
 edition = "2021"
 
 [dependencies]
-cranelift-codegen = { path = "../codegen", version = "0.86.0" }
-cranelift-entity = { path = "../entity", version = "0.86.0" }
+cranelift-codegen = { path = "../codegen", version = "0.87.0" }
+cranelift-entity = { path = "../entity", version = "0.87.0" }
 log = { version = "0.4.8", default-features = false }
 smallvec = "1.6.1"
 thiserror = "1.0.15"
 
 [dev-dependencies]
-cranelift-frontend = { path = "../frontend", version = "0.86.0" }
-cranelift-reader = { path = "../reader", version = "0.86.0" }
+cranelift-frontend = { path = "../frontend", version = "0.87.0" }
+cranelift-reader = { path = "../reader", version = "0.87.0" }
 
 [badges]
 maintenance = { status = "experimental" }
diff --git a/cranelift/interpreter/src/step.rs b/cranelift/interpreter/src/step.rs
index 91bbcf46d..5ef0f0d54 100644
--- a/cranelift/interpreter/src/step.rs
+++ b/cranelift/interpreter/src/step.rs
@@ -679,10 +679,10 @@ where
         Opcode::Fmul => binary(Value::mul, arg(0)?, arg(1)?)?,
         Opcode::Fdiv => binary(Value::div, arg(0)?, arg(1)?)?,
         Opcode::Sqrt => assign(Value::sqrt(arg(0)?)?),
-        Opcode::Fma => unimplemented!("Fma"),
-        Opcode::Fneg => binary(Value::sub, Value::float(0, ctrl_ty)?, arg(0)?)?,
-        Opcode::Fabs => unimplemented!("Fabs"),
-        Opcode::Fcopysign => unimplemented!("Fcopysign"),
+        Opcode::Fma => assign(Value::fma(arg(0)?, arg(1)?, arg(2)?)?),
+        Opcode::Fneg => assign(Value::neg(arg(0)?)?),
+        Opcode::Fabs => assign(Value::abs(arg(0)?)?),
+        Opcode::Fcopysign => binary(Value::copysign, arg(0)?, arg(1)?)?,
         Opcode::Fmin => choose(
             Value::is_nan(&arg(0)?)? || Value::lt(&arg(0)?, &arg(1)?)?,
             arg(0)?,
diff --git a/cranelift/interpreter/src/value.rs b/cranelift/interpreter/src/value.rs
index a38d2aca4..9fe7baf53 100644
--- a/cranelift/interpreter/src/value.rs
+++ b/cranelift/interpreter/src/value.rs
@@ -51,6 +51,12 @@ pub trait Value: Clone + From<DataValue> {
     fn div(self, other: Self) -> ValueResult<Self>;
     fn rem(self, other: Self) -> ValueResult<Self>;
     fn sqrt(self) -> ValueResult<Self>;
+    fn fma(self, a: Self, b: Self) -> ValueResult<Self>;
+    fn abs(self) -> ValueResult<Self>;
+
+    // Float operations
+    fn neg(self) -> ValueResult<Self>;
+    fn copysign(self, sign: Self) -> ValueResult<Self>;
 
     // Saturating arithmetic.
     fn add_sat(self, other: Self) -> ValueResult<Self>;
@@ -468,6 +474,30 @@ impl Value for DataValue {
         unary_match!(sqrt(&self); [F32, F64]; [Ieee32, Ieee64])
     }
 
+    fn fma(self, b: Self, c: Self) -> ValueResult<Self> {
+        match (self, b, c) {
+            (DataValue::F32(a), DataValue::F32(b), DataValue::F32(c)) => {
+                Ok(DataValue::F32(a.mul_add(b, c)))
+            }
+            (DataValue::F64(a), DataValue::F64(b), DataValue::F64(c)) => {
+                Ok(DataValue::F64(a.mul_add(b, c)))
+            }
+            (a, _b, _c) => Err(ValueError::InvalidType(ValueTypeClass::Float, a.ty())),
+        }
+    }
+
+    fn abs(self) -> ValueResult<Self> {
+        unary_match!(abs(&self); [F32, F64])
+    }
+
+    fn neg(self) -> ValueResult<Self> {
+        unary_match!(neg(&self); [F32, F64])
+    }
+
+    fn copysign(self, sign: Self) -> ValueResult<Self> {
+        binary_match!(copysign(&self, &sign); [F32, F64])
+    }
+
     fn add_sat(self, other: Self) -> ValueResult<Self> {
         binary_match!(saturating_add(self, &other); [I8, I16, I32, I64, I128, U8, U16, U32, U64, U128])
     }
diff --git a/cranelift/isle/isle/Cargo.toml b/cranelift/isle/isle/Cargo.toml
index e6c5b192c..91ee21908 100644
--- a/cranelift/isle/isle/Cargo.toml
+++ b/cranelift/isle/isle/Cargo.toml
@@ -6,7 +6,7 @@ license = "Apache-2.0 WITH LLVM-exception"
 name = "cranelift-isle"
 readme = "../README.md"
 repository = "https://github.com/bytecodealliance/wasmtime/tree/main/cranelift/isle"
-version = "0.86.0"
+version = "0.87.0"
 
 [dependencies]
 log = { version = "0.4", optional = true }
diff --git a/cranelift/jit/Cargo.toml b/cranelift/jit/Cargo.toml
index 8936cf926..594bd784a 100644
--- a/cranelift/jit/Cargo.toml
+++ b/cranelift/jit/Cargo.toml
@@ -1,6 +1,6 @@
 [package]
 name = "cranelift-jit"
-version = "0.86.0"
+version = "0.87.0"
 authors = ["The Cranelift Project Developers"]
 description = "A JIT library backed by Cranelift"
 repository = "https://github.com/bytecodealliance/wasmtime"
@@ -10,10 +10,10 @@ readme = "README.md"
 edition = "2021"
 
 [dependencies]
-cranelift-module = { path = "../module", version = "0.86.0" }
-cranelift-native = { path = "../native", version = "0.86.0" }
-cranelift-codegen = { path = "../codegen", version = "0.86.0", default-features = false, features = ["std"] }
-cranelift-entity = { path = "../entity", version = "0.86.0" }
+cranelift-module = { path = "../module", version = "0.87.0" }
+cranelift-native = { path = "../native", version = "0.87.0" }
+cranelift-codegen = { path = "../codegen", version = "0.87.0", default-features = false, features = ["std"] }
+cranelift-entity = { path = "../entity", version = "0.87.0" }
 anyhow = "1.0"
 region = "2.2.0"
 libc = { version = "0.2.42" }
@@ -34,9 +34,9 @@ selinux-fix = ['memmap2']
 default = []
 
 [dev-dependencies]
-cranelift = { path = "../umbrella", version = "0.86.0" }
-cranelift-frontend = { path = "../frontend", version = "0.86.0" }
-cranelift-entity = { path = "../entity", version = "0.86.0" }
+cranelift = { path = "../umbrella", version = "0.87.0" }
+cranelift-frontend = { path = "../frontend", version = "0.87.0" }
+cranelift-entity = { path = "../entity", version = "0.87.0" }
 
 [badges]
 maintenance = { status = "experimental" }
diff --git a/cranelift/module/Cargo.toml b/cranelift/module/Cargo.toml
index 2b560eec4..20f150e47 100644
--- a/cranelift/module/Cargo.toml
+++ b/cranelift/module/Cargo.toml
@@ -1,6 +1,6 @@
 [package]
 name = "cranelift-module"
-version = "0.86.0"
+version = "0.87.0"
 authors = ["The Cranelift Project Developers"]
 description = "Support for linking functions and data with Cranelift"
 repository = "https://github.com/bytecodealliance/wasmtime"
@@ -11,7 +11,7 @@ readme = "README.md"
 edition = "2021"
 
 [dependencies]
-cranelift-codegen = { path = "../codegen", version = "0.86.0", default-features = false }
+cranelift-codegen = { path = "../codegen", version = "0.87.0", default-features = false }
 hashbrown = { version = "0.11", optional = true }
 anyhow = "1.0"
 
diff --git a/cranelift/native/Cargo.toml b/cranelift/native/Cargo.toml
index 0c613a895..d0038fc9c 100644
--- a/cranelift/native/Cargo.toml
+++ b/cranelift/native/Cargo.toml
@@ -1,6 +1,6 @@
 [package]
 name = "cranelift-native"
-version = "0.86.0"
+version = "0.87.0"
 authors = ["The Cranelift Project Developers"]
 description = "Support for targeting the host with Cranelift"
 documentation = "https://docs.rs/cranelift-native"
@@ -11,7 +11,7 @@ readme = "README.md"
 edition = "2021"
 
 [dependencies]
-cranelift-codegen = { path = "../codegen", version = "0.86.0", default-features = false }
+cranelift-codegen = { path = "../codegen", version = "0.87.0", default-features = false }
 target-lexicon = "0.12"
 
 [target.'cfg(target_arch = "s390x")'.dependencies]
diff --git a/cranelift/object/Cargo.toml b/cranelift/object/Cargo.toml
index 8a492563d..7d0951acf 100644
--- a/cranelift/object/Cargo.toml
+++ b/cranelift/object/Cargo.toml
@@ -1,6 +1,6 @@
 [package]
 name = "cranelift-object"
-version = "0.86.0"
+version = "0.87.0"
 authors = ["The Cranelift Project Developers"]
 description = "Emit Cranelift output to native object files with `object`"
 repository = "https://github.com/bytecodealliance/wasmtime"
@@ -10,16 +10,16 @@ readme = "README.md"
 edition = "2021"
 
 [dependencies]
-cranelift-module = { path = "../module", version = "0.86.0" }
-cranelift-codegen = { path = "../codegen", version = "0.86.0", default-features = false, features = ["std"] }
+cranelift-module = { path = "../module", version = "0.87.0" }
+cranelift-codegen = { path = "../codegen", version = "0.87.0", default-features = false, features = ["std"] }
 object = { version = "0.28.0", default-features = false, features = ["write"] }
 target-lexicon = "0.12"
 anyhow = "1.0"
 log = { version = "0.4.6", default-features = false }
 
 [dev-dependencies]
-cranelift-frontend = { path = "../frontend", version = "0.86.0" }
-cranelift-entity = { path = "../entity", version = "0.86.0" }
+cranelift-frontend = { path = "../frontend", version = "0.87.0" }
+cranelift-entity = { path = "../entity", version = "0.87.0" }
 
 [badges]
 maintenance = { status = "experimental" }
diff --git a/cranelift/preopt/Cargo.toml b/cranelift/preopt/Cargo.toml
index e2d9658e8..ea05b775d 100644
--- a/cranelift/preopt/Cargo.toml
+++ b/cranelift/preopt/Cargo.toml
@@ -1,7 +1,7 @@
 [package]
 authors = ["The Cranelift Project Developers"]
 name = "cranelift-preopt"
-version = "0.86.0"
+version = "0.87.0"
 description = "Support for optimizations in Cranelift"
 license = "Apache-2.0 WITH LLVM-exception"
 documentation = "https://docs.rs/cranelift-preopt"
@@ -12,7 +12,7 @@ keywords = ["optimize", "compile", "compiler", "jit"]
 edition = "2021"
 
 [dependencies]
-cranelift-codegen = { path = "../codegen", version = "0.86.0", default-features = false }
+cranelift-codegen = { path = "../codegen", version = "0.87.0", default-features = false }
 # This is commented out because it doesn't build on Rust 1.25.0, which
 # cranelift currently supports.
 # rustc_apfloat = { version = "0.1.2", default-features = false }
diff --git a/cranelift/reader/Cargo.toml b/cranelift/reader/Cargo.toml
index 8a205363d..be876aa66 100644
--- a/cranelift/reader/Cargo.toml
+++ b/cranelift/reader/Cargo.toml
@@ -1,7 +1,7 @@
 [package]
 authors = ["The Cranelift Project Developers"]
 name = "cranelift-reader"
-version = "0.86.0"
+version = "0.87.0"
 description = "Cranelift textual IR reader"
 license = "Apache-2.0 WITH LLVM-exception"
 documentation = "https://docs.rs/cranelift-reader"
@@ -10,7 +10,7 @@ readme = "README.md"
 edition = "2021"
 
 [dependencies]
-cranelift-codegen = { path = "../codegen", version = "0.86.0" }
+cranelift-codegen = { path = "../codegen", version = "0.87.0" }
 smallvec = "1.6.1"
 target-lexicon = "0.12"
 
diff --git a/cranelift/serde/Cargo.toml b/cranelift/serde/Cargo.toml
index 7994ca028..f51d42174 100644
--- a/cranelift/serde/Cargo.toml
+++ b/cranelift/serde/Cargo.toml
@@ -1,6 +1,6 @@
 [package]
 name = "cranelift-serde"
-version = "0.86.0"
+version = "0.87.0"
 authors = ["The Cranelift Project Developers"]
 description = "Serializer/Deserializer for Cranelift IR"
 repository = "https://github.com/bytecodealliance/wasmtime"
@@ -16,8 +16,8 @@ path = "src/clif-json.rs"
 [dependencies]
 clap = { version = "3.1.12", features = ["derive"] }
 serde_json = "1.0.26"
-cranelift-codegen = { path = "../codegen", version = "0.86.0", features = ["enable-serde"] }
-cranelift-reader = { path = "../reader", version = "0.86.0" }
+cranelift-codegen = { path = "../codegen", version = "0.87.0", features = ["enable-serde"] }
+cranelift-reader = { path = "../reader", version = "0.87.0" }
 
 [badges]
 maintenance = { status = "experimental" }
diff --git a/cranelift/umbrella/Cargo.toml b/cranelift/umbrella/Cargo.toml
index 7f3152139..a7b8f0106 100644
--- a/cranelift/umbrella/Cargo.toml
+++ b/cranelift/umbrella/Cargo.toml
@@ -1,7 +1,7 @@
 [package]
 authors = ["The Cranelift Project Developers"]
 name = "cranelift"
-version = "0.86.0"
+version = "0.87.0"
 description = "Umbrella for commonly-used cranelift crates"
 license = "Apache-2.0 WITH LLVM-exception"
 documentation = "https://docs.rs/cranelift"
@@ -12,8 +12,8 @@ keywords = ["compile", "compiler", "jit"]
 edition = "2021"
 
 [dependencies]
-cranelift-codegen = { path = "../codegen", version = "0.86.0", default-features = false }
-cranelift-frontend = { path = "../frontend", version = "0.86.0", default-features = false }
+cranelift-codegen = { path = "../codegen", version = "0.87.0", default-features = false }
+cranelift-frontend = { path = "../frontend", version = "0.87.0", default-features = false }
 
 [features]
 default = ["std"]
diff --git a/cranelift/wasm/Cargo.toml b/cranelift/wasm/Cargo.toml
index 59d15a311..443de0a9a 100644
--- a/cranelift/wasm/Cargo.toml
+++ b/cranelift/wasm/Cargo.toml
@@ -1,6 +1,6 @@
 [package]
 name = "cranelift-wasm"
-version = "0.86.0"
+version = "0.87.0"
 authors = ["The Cranelift Project Developers"]
 description = "Translator from WebAssembly to Cranelift IR"
 documentation = "https://docs.rs/cranelift-wasm"
@@ -13,10 +13,10 @@ edition = "2021"
 
 [dependencies]
 wasmparser = { version = "0.86.0", default-features = false }
-cranelift-codegen = { path = "../codegen", version = "0.86.0", default-features = false }
-cranelift-entity = { path = "../entity", version = "0.86.0" }
-cranelift-frontend = { path = "../frontend", version = "0.86.0", default-features = false }
-wasmtime-types = { path = "../../crates/types", version = "0.39.0" }
+cranelift-codegen = { path = "../codegen", version = "0.87.0", default-features = false }
+cranelift-entity = { path = "../entity", version = "0.87.0" }
+cranelift-frontend = { path = "../frontend", version = "0.87.0", default-features = false }
+wasmtime-types = { path = "../../crates/types", version = "0.40.0" }
 hashbrown = { version = "0.11", optional = true }
 itertools = "0.10.0"
 log = { version = "0.4.6", default-features = false }
@@ -26,7 +26,7 @@ smallvec = "1.6.1"
 [dev-dependencies]
 wat = "1.0.37"
 target-lexicon = "0.12"
-cranelift-codegen = { path = "../codegen", version = "0.86.0", default-features = false }
+cranelift-codegen = { path = "../codegen", version = "0.87.0", default-features = false }
 
 [features]
 default = ["std"]
diff --git a/crates/cache/Cargo.toml b/crates/cache/Cargo.toml
index fc129f6b1..efcb4ac27 100644
--- a/crates/cache/Cargo.toml
+++ b/crates/cache/Cargo.toml
@@ -1,6 +1,6 @@
 [package]
 name = "wasmtime-cache"
-version = "0.39.0"
+version = "0.40.0"
 authors = ["The Wasmtime Project Developers"]
 description = "Support for automatic module caching with Wasmtime"
 license = "Apache-2.0 WITH LLVM-exception"
diff --git a/crates/cli-flags/Cargo.toml b/crates/cli-flags/Cargo.toml
index 2c0be98ff..dbfbe4a8a 100644
--- a/crates/cli-flags/Cargo.toml
+++ b/crates/cli-flags/Cargo.toml
@@ -1,6 +1,6 @@
 [package]
 name = "wasmtime-cli-flags"
-version = "0.39.0"
+version = "0.40.0"
 authors = ["The Wasmtime Project Developers"]
 description = "Exposes common CLI flags used for running Wasmtime"
 license = "Apache-2.0 WITH LLVM-exception"
@@ -14,7 +14,7 @@ clap = { version = "3.1.12", features = ["color", "suggestions", "derive"] }
 file-per-thread-logger = "0.1.1"
 pretty_env_logger = "0.4.0"
 rayon = "1.5.0"
-wasmtime = { path = "../wasmtime", version = "0.39.0", default-features = false }
+wasmtime = { path = "../wasmtime", version = "0.40.0", default-features = false }
 
 [features]
 default = [
diff --git a/crates/component-macro/Cargo.toml b/crates/component-macro/Cargo.toml
index 4e924ec97..6fadf5e65 100644
--- a/crates/component-macro/Cargo.toml
+++ b/crates/component-macro/Cargo.toml
@@ -1,6 +1,6 @@
 [package]
 name = "wasmtime-component-macro"
-version = "0.39.0"
+version = "0.40.0"
 authors = ["The Wasmtime Project Developers"]
 description = "Macros for deriving component interface types from Rust types"
 license = "Apache-2.0 WITH LLVM-exception"
diff --git a/crates/component-macro/src/lib.rs b/crates/component-macro/src/lib.rs
index b956c9e31..878c53f68 100644
--- a/crates/component-macro/src/lib.rs
+++ b/crates/component-macro/src/lib.rs
@@ -145,6 +145,54 @@ fn add_trait_bounds(generics: &syn::Generics, bound: syn::TypeParamBound) -> syn
     generics
 }
 
+#[derive(Debug, Copy, Clone)]
+enum DiscriminantSize {
+    Size1,
+    Size2,
+    Size4,
+}
+
+impl DiscriminantSize {
+    fn quote(self, discriminant: usize) -> TokenStream {
+        match self {
+            Self::Size1 => {
+                let discriminant = u8::try_from(discriminant).unwrap();
+                quote!(#discriminant)
+            }
+            Self::Size2 => {
+                let discriminant = u16::try_from(discriminant).unwrap();
+                quote!(#discriminant)
+            }
+            Self::Size4 => {
+                let discriminant = u32::try_from(discriminant).unwrap();
+                quote!(#discriminant)
+            }
+        }
+    }
+}
+
+impl From<DiscriminantSize> for u32 {
+    fn from(size: DiscriminantSize) -> u32 {
+        match size {
+            DiscriminantSize::Size1 => 1,
+            DiscriminantSize::Size2 => 2,
+            DiscriminantSize::Size4 => 4,
+        }
+    }
+}
+
+fn discriminant_size(case_count: usize) -> Option<DiscriminantSize> {
+    if case_count <= 0xFF {
+        Some(DiscriminantSize::Size1)
+    } else if case_count <= 0xFFFF {
+        Some(DiscriminantSize::Size2)
+    } else if case_count <= 0xFFFF_FFFF {
+        Some(DiscriminantSize::Size4)
+    } else {
+        None
+    }
+}
+
 struct VariantCase<'a> {
     attrs: &'a [syn::Attribute],
     ident: &'a syn::Ident,
@@ -157,6 +205,7 @@ trait Expander {
     fn expand_variant(
         &self,
         input: &DeriveInput,
+        discriminant_size: DiscriminantSize,
         cases: &[VariantCase],
         style: VariantStyle,
     ) -> Result<TokenStream>;
@@ -217,6 +266,13 @@ fn expand_variant(
         ));
     }
 
+    let discriminant_size = discriminant_size(body.variants.len()).ok_or_else(|| {
+        Error::new(
+            input.ident.span(),
+            "`enum`s with more than 2^32 variants are not supported",
+        )
+    })?;
+
     let cases = body
         .variants
         .iter()
@@ -240,8 +296,13 @@ fn expand_variant(
                                 name.span(),
                                 format!(
                                     "`{}` component types can only be derived for Rust `enum`s \
-                                     containing variants with at most one unnamed field each",
-                                    style
+                                     containing variants with {}",
+                                    style,
+                                    match style {
+                                        VariantStyle::Variant => "at most one unnamed field each",
+                                        VariantStyle::Enum => "no fields",
+                                        VariantStyle::Union => "exactly one unnamed field each",
+                                    }
                                 ),
                             ))
                         }
@@ -251,7 +312,7 @@ fn expand_variant(
         )
         .collect::<Result<Vec<_>>>()?;
 
-    expander.expand_variant(input, &cases, style)
+    expander.expand_variant(input, discriminant_size, &cases, style)
 }
 
 #[proc_macro_derive(Lift, attributes(component))]
@@ -321,6 +382,7 @@ impl Expander for LiftExpander {
     fn expand_variant(
         &self,
         input: &DeriveInput,
+        discriminant_size: DiscriminantSize,
         cases: &[VariantCase],
         _style: VariantStyle,
     ) -> Result<TokenStream> {
@@ -330,31 +392,26 @@ impl Expander for LiftExpander {
         let mut loads = TokenStream::new();
 
         for (index, VariantCase { ident, ty, .. }) in cases.iter().enumerate() {
-            let index_u8 = u8::try_from(index).map_err(|_| {
-                Error::new(
-                    input.ident.span(),
-                    "`enum`s with more than 256 variants not yet supported",
-                )
-            })?;
+            let index_u32 = u32::try_from(index).unwrap();
 
-            let index_i32 = index_u8 as i32;
+            let index_quoted = discriminant_size.quote(index);
 
             if let Some(ty) = ty {
                 lifts.extend(
-                    quote!(#index_i32 => Self::#ident(<#ty as wasmtime::component::Lift>::lift(
+                    quote!(#index_u32 => Self::#ident(<#ty as wasmtime::component::Lift>::lift(
                         store, options, unsafe { &src.payload.#ident }
                     )?),),
                 );
 
                 loads.extend(
-                    quote!(#index_u8 => Self::#ident(<#ty as wasmtime::component::Lift>::load(
+                    quote!(#index_quoted => Self::#ident(<#ty as wasmtime::component::Lift>::load(
                         memory, &payload[..<#ty as wasmtime::component::ComponentType>::SIZE32]
                     )?),),
                 );
             } else {
-                lifts.extend(quote!(#index_i32 => Self::#ident,));
+                lifts.extend(quote!(#index_u32 => Self::#ident,));
 
-                loads.extend(quote!(#index_u8 => Self::#ident,));
+                loads.extend(quote!(#index_quoted => Self::#ident,));
             }
         }
 
@@ -362,6 +419,14 @@ impl Expander for LiftExpander {
         let generics = add_trait_bounds(&input.generics, parse_quote!(wasmtime::component::Lift));
         let (impl_generics, ty_generics, where_clause) = generics.split_for_impl();
 
+        let from_bytes = match discriminant_size {
+            DiscriminantSize::Size1 => quote!(bytes[0]),
+            DiscriminantSize::Size2 => quote!(u16::from_le_bytes(bytes[0..2].try_into()?)),
+            DiscriminantSize::Size4 => quote!(u32::from_le_bytes(bytes[0..4].try_into()?)),
+        };
+
+        let payload_offset = u32::from(discriminant_size) as usize;
+
         let expanded = quote! {
             unsafe impl #impl_generics wasmtime::component::Lift for #name #ty_generics #where_clause {
                 #[inline]
@@ -370,7 +435,7 @@ impl Expander for LiftExpander {
                     options: &#internal::Options,
                     src: &Self::Lower,
                 ) -> #internal::anyhow::Result<Self> {
-                    Ok(match src.tag.get_i32() {
+                    Ok(match src.tag.get_u32() {
                         #lifts
                         discrim => #internal::anyhow::bail!("unexpected discriminant: {}", discrim),
                     })
@@ -380,8 +445,8 @@ impl Expander for LiftExpander {
                 fn load(memory: &#internal::Memory, bytes: &[u8]) -> #internal::anyhow::Result<Self> {
                     let align = <Self as wasmtime::component::ComponentType>::ALIGN32;
                     debug_assert!((bytes.as_ptr() as usize) % (align as usize) == 0);
-                    let discrim = bytes[0];
-                    let payload = &bytes[#internal::align_to(1, align)..];
+                    let discrim = #from_bytes;
+                    let payload = &bytes[#internal::align_to(#payload_offset, align)..];
                     Ok(match discrim {
                         #loads
                         discrim => #internal::anyhow::bail!("unexpected discriminant: {}", discrim),
@@ -456,6 +521,7 @@ impl Expander for LowerExpander {
     fn expand_variant(
         &self,
         input: &DeriveInput,
+        discriminant_size: DiscriminantSize,
         cases: &[VariantCase],
         _style: VariantStyle,
     ) -> Result<TokenStream> {
@@ -465,14 +531,9 @@ impl Expander for LowerExpander {
         let mut stores = TokenStream::new();
 
         for (index, VariantCase { ident, ty, .. }) in cases.iter().enumerate() {
-            let index_u8 = u8::try_from(index).map_err(|_| {
-                Error::new(
-                    input.ident.span(),
-                    "`enum`s with more than 256 variants not yet supported",
-                )
-            })?;
+            let index_u32 = u32::try_from(index).unwrap();
 
-            let index_i32 = index_u8 as i32;
+            let index_quoted = discriminant_size.quote(index);
 
             let pattern;
             let lower;
@@ -492,12 +553,14 @@ impl Expander for LowerExpander {
             }
 
             lowers.extend(quote!(#pattern => {
-                #internal::map_maybe_uninit!(dst.tag).write(wasmtime::ValRaw::i32(#index_i32));
+                #internal::map_maybe_uninit!(dst.tag).write(wasmtime::ValRaw::i32(#index_u32 as i32));
                 #lower
             }));
 
+            let discriminant_size = u32::from(discriminant_size) as usize;
+
             stores.extend(quote!(#pattern => {
-                memory.get::<1>(offset)[0] = #index_u8;
+                *memory.get::<#discriminant_size>(offset) = #index_quoted.to_le_bytes();
                 #store
             }));
         }
@@ -668,6 +731,7 @@ impl Expander for ComponentTypeExpander {
     fn expand_variant(
         &self,
         input: &DeriveInput,
+        discriminant_size: DiscriminantSize,
         cases: &[VariantCase],
         style: VariantStyle,
     ) -> Result<TokenStream> {
@@ -766,6 +830,7 @@ impl Expander for ComponentTypeExpander {
         let (impl_generics, ty_generics, where_clause) = generics.split_for_impl();
         let lower = format_ident!("Lower{}", name);
         let lower_payload = format_ident!("LowerPayload{}", name);
+        let discriminant_size = u32::from(discriminant_size);
 
         // You may wonder why we make the types of all the fields of the #lower struct and #lower_payload union
         // generic.  This is to work around a [normalization bug in
@@ -806,11 +871,11 @@ impl Expander for ComponentTypeExpander {
                 const SIZE32: usize = {
                     let mut size = 0;
                     #sizes
-                    #internal::align_to(1, Self::ALIGN32) + size
+                    #internal::align_to(#discriminant_size as usize, Self::ALIGN32) + size
                 };
 
                 const ALIGN32: u32 = {
-                    let mut align = 1;
+                    let mut align = #discriminant_size;
                     #alignments
                     align
                 };
diff --git a/crates/cranelift/Cargo.toml b/crates/cranelift/Cargo.toml
index e8ec94f37..fe167d8a4 100644
--- a/crates/cranelift/Cargo.toml
+++ b/crates/cranelift/Cargo.toml
@@ -1,6 +1,6 @@
 [package]
 name = "wasmtime-cranelift"
-version = "0.39.0"
+version = "0.40.0"
 authors = ["The Wasmtime Project Developers"]
 description = "Integration between Cranelift and Wasmtime"
 license = "Apache-2.0 WITH LLVM-exception"
@@ -13,12 +13,12 @@ edition = "2021"
 [dependencies]
 anyhow = "1.0"
 log = "0.4"
-wasmtime-environ = { path = "../environ", version = "=0.39.0" }
-cranelift-wasm = { path = "../../cranelift/wasm", version = "0.86.0" }
-cranelift-codegen = { path = "../../cranelift/codegen", version = "0.86.0" }
-cranelift-frontend = { path = "../../cranelift/frontend", version = "0.86.0" }
-cranelift-entity = { path = "../../cranelift/entity", version = "0.86.0" }
-cranelift-native = { path = "../../cranelift/native", version = "0.86.0" }
+wasmtime-environ = { path = "../environ", version = "=0.40.0" }
+cranelift-wasm = { path = "../../cranelift/wasm", version = "0.87.0" }
+cranelift-codegen = { path = "../../cranelift/codegen", version = "0.87.0" }
+cranelift-frontend = { path = "../../cranelift/frontend", version = "0.87.0" }
+cranelift-entity = { path = "../../cranelift/entity", version = "0.87.0" }
+cranelift-native = { path = "../../cranelift/native", version = "0.87.0" }
 wasmparser = "0.86.0"
 target-lexicon = "0.12"
 gimli = { version = "0.26.0", default-features = false, features = ['read', 'std'] }
diff --git a/crates/environ/Cargo.toml b/crates/environ/Cargo.toml
index dac7e4c0a..7572476a9 100644
--- a/crates/environ/Cargo.toml
+++ b/crates/environ/Cargo.toml
@@ -1,6 +1,6 @@
 [package]
 name = "wasmtime-environ"
-version = "0.39.0"
+version = "0.40.0"
 authors = ["The Wasmtime Project Developers"]
 description = "Standalone environment support for WebAsssembly code in Cranelift"
 license = "Apache-2.0 WITH LLVM-exception"
@@ -12,8 +12,8 @@ edition = "2021"
 
 [dependencies]
 anyhow = "1.0"
-cranelift-entity = { path = "../../cranelift/entity", version = "0.86.0" }
-wasmtime-types = { path = "../types", version = "0.39.0" }
+cranelift-entity = { path = "../../cranelift/entity", version = "0.87.0" }
+wasmtime-types = { path = "../types", version = "0.40.0" }
 wasmparser = "0.86.0"
 indexmap = { version = "1.0.2", features = ["serde-1"] }
 thiserror = "1.0.4"
diff --git a/crates/fiber/Cargo.toml b/crates/fiber/Cargo.toml
index 77a750ed9..f224489cf 100644
--- a/crates/fiber/Cargo.toml
+++ b/crates/fiber/Cargo.toml
@@ -1,6 +1,6 @@
 [package]
 name = "wasmtime-fiber"
-version = "0.39.0"
+version = "0.40.0"
 authors = ["The Wasmtime Project Developers"]
 description = "Fiber support for Wasmtime"
 license = "Apache-2.0 WITH LLVM-exception"
diff --git a/crates/fiber/build.rs b/crates/fiber/build.rs
index 9e7b8b5a3..6bfc5c4b9 100644
--- a/crates/fiber/build.rs
+++ b/crates/fiber/build.rs
@@ -5,13 +5,16 @@ fn main() {
     let arch = env::var("CARGO_CFG_TARGET_ARCH").unwrap();
     let os = env::var("CARGO_CFG_TARGET_OS").unwrap();
     if os == "windows" {
+        println!("cargo:rerun-if-changed=src/windows.c");
         build.file("src/windows.c");
     } else if arch == "s390x" {
+        println!("cargo:rerun-if-changed=src/unix/s390x.S");
         build.file("src/unix/s390x.S");
     } else {
         // assume that this is included via inline assembly in the crate itself,
         // and the crate will otherwise have a `compile_error!` for unsupported
         // platforms.
+        println!("cargo:rerun-if-changed=build.rs");
         return;
     }
     build.define(&format!("CFG_TARGET_OS_{}", os), None);
diff --git a/crates/jit-debug/Cargo.toml b/crates/jit-debug/Cargo.toml
index 0af9aa5c2..a28d108a5 100644
--- a/crates/jit-debug/Cargo.toml
+++ b/crates/jit-debug/Cargo.toml
@@ -1,6 +1,6 @@
 [package]
 name = "wasmtime-jit-debug"
-version = "0.39.0"
+version = "0.40.0"
 authors = ["The Wasmtime Project Developers"]
 description = "JIT debug interfaces support for Wasmtime"
 license = "Apache-2.0 WITH LLVM-exception"
diff --git a/crates/jit/Cargo.toml b/crates/jit/Cargo.toml
index 11372ae2d..c35896e53 100644
--- a/crates/jit/Cargo.toml
+++ b/crates/jit/Cargo.toml
@@ -1,6 +1,6 @@
 [package]
 name = "wasmtime-jit"
-version = "0.39.0"
+version = "0.40.0"
 authors = ["The Wasmtime Project Developers"]
 description = "JIT-style execution for WebAsssembly code in Cranelift"
 documentation = "https://docs.rs/wasmtime-jit"
@@ -11,9 +11,9 @@ repository = "https://github.com/bytecodealliance/wasmtime"
 edition = "2021"
 
 [dependencies]
-wasmtime-environ = { path = "../environ", version = "=0.39.0" }
-wasmtime-jit-debug = { path = "../jit-debug", version = "=0.39.0", features = ["perf_jitdump"], optional = true }
-wasmtime-runtime = { path = "../runtime", version = "=0.39.0" }
+wasmtime-environ = { path = "../environ", version = "=0.40.0" }
+wasmtime-jit-debug = { path = "../jit-debug", version = "=0.40.0", features = ["perf_jitdump"], optional = true }
+wasmtime-runtime = { path = "../runtime", version = "=0.40.0" }
 region = "2.2.0"
 thiserror = "1.0.4"
 target-lexicon = { version = "0.12.0", default-features = false }
diff --git a/crates/runtime/Cargo.toml b/crates/runtime/Cargo.toml
index d1973ec31..fc5886eef 100644
--- a/crates/runtime/Cargo.toml
+++ b/crates/runtime/Cargo.toml
@@ -1,6 +1,6 @@
 [package]
 name = "wasmtime-runtime"
-version = "0.39.0"
+version = "0.40.0"
 authors = ["The Wasmtime Project Developers"]
 description = "Runtime library support for Wasmtime"
 documentation = "https://docs.rs/wasmtime-runtime"
@@ -11,9 +11,9 @@ repository = "https://github.com/bytecodealliance/wasmtime"
 edition = "2021"
 
 [dependencies]
-wasmtime-environ = { path = "../environ", version = "=0.39.0" }
-wasmtime-fiber = { path = "../fiber", version = "=0.39.0", optional = true }
-wasmtime-jit-debug = { path = "../jit-debug", version = "=0.39.0", features = ["gdb_jit_int"] }
+wasmtime-environ = { path = "../environ", version = "=0.40.0" }
+wasmtime-fiber = { path = "../fiber", version = "=0.40.0", optional = true }
+wasmtime-jit-debug = { path = "../jit-debug", version = "=0.40.0", features = ["gdb_jit_int"] }
 region = "2.1.0"
 libc = { version = "0.2.112", default-features = false }
 log = "0.4.8"
@@ -25,7 +25,7 @@ cfg-if = "1.0"
 backtrace = { version = "0.3.61" }
 rand = "0.8.3"
 anyhow = "1.0.38"
-memfd = { version = "0.4.1", optional = true }
+memfd = { version = "0.6.1", optional = true }
 
 [target.'cfg(target_os = "macos")'.dependencies]
 mach = "0.3.2"
diff --git a/crates/runtime/src/cow.rs b/crates/runtime/src/cow.rs
index ab4a062bf..6c3767861 100644
--- a/crates/runtime/src/cow.rs
+++ b/crates/runtime/src/cow.rs
@@ -162,10 +162,12 @@ impl MemoryImage {
                 // extra-super-sure that it never changes, and because
                 // this costs very little, we use the kernel's "seal" API
                 // to make the memfd image permanently read-only.
-                memfd.add_seal(memfd::FileSeal::SealGrow)?;
-                memfd.add_seal(memfd::FileSeal::SealShrink)?;
-                memfd.add_seal(memfd::FileSeal::SealWrite)?;
-                memfd.add_seal(memfd::FileSeal::SealSeal)?;
+                memfd.add_seals(&[
+                    memfd::FileSeal::SealGrow,
+                    memfd::FileSeal::SealShrink,
+                    memfd::FileSeal::SealWrite,
+                    memfd::FileSeal::SealSeal,
+                ])?;
 
                 Ok(Some(MemoryImage {
                     fd: FdSource::Memfd(memfd),
diff --git a/crates/types/Cargo.toml b/crates/types/Cargo.toml
index 94569eb74..bd6369520 100644
--- a/crates/types/Cargo.toml
+++ b/crates/types/Cargo.toml
@@ -1,6 +1,6 @@
 [package]
 name = "wasmtime-types"
-version = "0.39.0"
+version = "0.40.0"
 authors = ["The Wasmtime Project Developers"]
 description = "WebAssembly type definitions for Cranelift"
 license = "Apache-2.0 WITH LLVM-exception"
@@ -9,7 +9,7 @@ documentation = "https://docs.rs/wasmtime-types"
 edition = "2021"
 
 [dependencies]
-cranelift-entity = { path = "../../cranelift/entity", version = "0.86.0", features = ['enable-serde'] }
+cranelift-entity = { path = "../../cranelift/entity", version = "0.87.0", features = ['enable-serde'] }
 serde = { version = "1.0.94", features = ["derive"] }
 thiserror = "1.0.4"
 wasmparser = { version = "0.86.0", default-features = false }
diff --git a/crates/wasi-common/Cargo.toml b/crates/wasi-common/Cargo.toml
index 280456f7e..28a428c1e 100644
--- a/crates/wasi-common/Cargo.toml
+++ b/crates/wasi-common/Cargo.toml
@@ -1,6 +1,6 @@
 [package]
 name = "wasi-common"
-version = "0.39.0"
+version = "0.40.0"
 authors = ["The Wasmtime Project Developers"]
 description = "WASI implementation in Rust"
 license = "Apache-2.0 WITH LLVM-exception"
@@ -20,7 +20,7 @@ links = "wasi-common-19"
 [dependencies]
 anyhow = "1.0"
 thiserror = "1.0"
-wiggle = { path = "../wiggle", default-features = false, version = "=0.39.0" }
+wiggle = { path = "../wiggle", default-features = false, version = "=0.40.0" }
 tracing = "0.1.19"
 cap-std = "0.25.0"
 cap-rand = "0.25.0"
diff --git a/crates/wasi-common/cap-std-sync/Cargo.toml b/crates/wasi-common/cap-std-sync/Cargo.toml
index 1fd5efd55..1f667b556 100644
--- a/crates/wasi-common/cap-std-sync/Cargo.toml
+++ b/crates/wasi-common/cap-std-sync/Cargo.toml
@@ -1,6 +1,6 @@
 [package]
 name = "wasi-cap-std-sync"
-version = "0.39.0"
+version = "0.40.0"
 authors = ["The Wasmtime Project Developers"]
 description = "WASI implementation in Rust"
 license = "Apache-2.0 WITH LLVM-exception"
@@ -12,7 +12,7 @@ edition = "2021"
 include = ["src/**/*", "README.md", "LICENSE" ]
 
 [dependencies]
-wasi-common = { path = "../", version = "=0.39.0" }
+wasi-common = { path = "../", version = "=0.40.0" }
 async-trait = "0.1"
 anyhow = "1.0"
 cap-std = "0.25.0"
diff --git a/crates/wasi-common/tokio/Cargo.toml b/crates/wasi-common/tokio/Cargo.toml
index fb9012c1e..14224a4ec 100644
--- a/crates/wasi-common/tokio/Cargo.toml
+++ b/crates/wasi-common/tokio/Cargo.toml
@@ -1,6 +1,6 @@
 [package]
 name = "wasi-tokio"
-version = "0.39.0"
+version = "0.40.0"
 authors = ["The Wasmtime Project Developers"]
 description = "WASI implementation in Rust"
 license = "Apache-2.0 WITH LLVM-exception"
@@ -11,9 +11,9 @@ edition = "2021"
 include = ["src/**/*", "LICENSE" ]
 
 [dependencies]
-wasi-common = { path = "../", version = "=0.39.0" }
-wasi-cap-std-sync = { path = "../cap-std-sync", version = "=0.39.0" }
-wiggle = { path = "../../wiggle", version = "=0.39.0" }
+wasi-common = { path = "../", version = "=0.40.0" }
+wasi-cap-std-sync = { path = "../cap-std-sync", version = "=0.40.0" }
+wiggle = { path = "../../wiggle", version = "=0.40.0" }
 tokio = { version = "1.8.0", features = [ "rt", "fs", "time", "io-util", "net", "io-std", "rt-multi-thread"] }
 cap-std = "0.25.0"
 anyhow = "1"
diff --git a/crates/wasi-crypto/Cargo.toml b/crates/wasi-crypto/Cargo.toml
index 6d6be3179..e392ea410 100644
--- a/crates/wasi-crypto/Cargo.toml
+++ b/crates/wasi-crypto/Cargo.toml
@@ -1,6 +1,6 @@
 [package]
 name = "wasmtime-wasi-crypto"
-version = "0.39.0"
+version = "0.40.0"
 authors = ["The Wasmtime Project Developers"]
 description = "Wasmtime implementation of the wasi-crypto API"
 documentation = "https://docs.rs/wasmtime-wasi-crypto"
@@ -14,8 +14,8 @@ edition = "2021"
 [dependencies]
 anyhow = "1.0"
 wasi-crypto = { path = "spec/implementations/hostcalls/rust", version = "0.1.5" }
-wasmtime = { path = "../wasmtime", version = "0.39.0", default-features = false }
-wiggle = { path = "../wiggle", version = "=0.39.0" }
+wasmtime = { path = "../wasmtime", version = "0.40.0", default-features = false }
+wiggle = { path = "../wiggle", version = "=0.40.0" }
 
 [badges]
 maintenance = { status = "experimental" }
diff --git a/crates/wasi-nn/Cargo.toml b/crates/wasi-nn/Cargo.toml
index 613494bca..f922d49bb 100644
--- a/crates/wasi-nn/Cargo.toml
+++ b/crates/wasi-nn/Cargo.toml
@@ -1,6 +1,6 @@
 [package]
 name = "wasmtime-wasi-nn"
-version = "0.39.0"
+version = "0.40.0"
 authors = ["The Wasmtime Project Developers"]
 description = "Wasmtime implementation of the wasi-nn API"
 documentation = "https://docs.rs/wasmtime-wasi-nn"
@@ -14,7 +14,7 @@ edition = "2021"
 [dependencies]
 # These dependencies are necessary for the witx-generation macros to work:
 anyhow = "1.0"
-wiggle = { path = "../wiggle", version = "=0.39.0" }
+wiggle = { path = "../wiggle", version = "=0.40.0" }
 
 # These dependencies are necessary for the wasi-nn implementation:
 openvino = { version = "0.3.3", features = ["runtime-linking"] }
diff --git a/crates/wasi/Cargo.toml b/crates/wasi/Cargo.toml
index d0bafdd39..ba3a298e8 100644
--- a/crates/wasi/Cargo.toml
+++ b/crates/wasi/Cargo.toml
@@ -1,6 +1,6 @@
 [package]
 name = "wasmtime-wasi"
-version = "0.39.0"
+version = "0.40.0"
 authors = ["The Wasmtime Project Developers"]
 description = "WASI implementation in Rust"
 license = "Apache-2.0 WITH LLVM-exception"
@@ -13,11 +13,11 @@ include = ["src/**/*", "README.md", "LICENSE", "build.rs"]
 build = "build.rs"
 
 [dependencies]
-wasi-common = { path = "../wasi-common", version = "=0.39.0" }
-wasi-cap-std-sync = { path = "../wasi-common/cap-std-sync", version = "=0.39.0", optional = true }
-wasi-tokio = { path = "../wasi-common/tokio", version = "=0.39.0", optional = true }
-wiggle = { path = "../wiggle", default-features = false, version = "=0.39.0", features = ["wasmtime_integration"] }
-wasmtime = { path = "../wasmtime", default-features = false, version = "0.39.0" }
+wasi-common = { path = "../wasi-common", version = "=0.40.0" }
+wasi-cap-std-sync = { path = "../wasi-common/cap-std-sync", version = "=0.40.0", optional = true }
+wasi-tokio = { path = "../wasi-common/tokio", version = "=0.40.0", optional = true }
+wiggle = { path = "../wiggle", default-features = false, version = "=0.40.0", features = ["wasmtime_integration"] }
+wasmtime = { path = "../wasmtime", default-features = false, version = "0.40.0" }
 anyhow = "1.0"
 
 [features]
diff --git a/crates/wasmtime/Cargo.toml b/crates/wasmtime/Cargo.toml
index 21329348f..733878d5a 100644
--- a/crates/wasmtime/Cargo.toml
+++ b/crates/wasmtime/Cargo.toml
@@ -1,6 +1,6 @@
 [package]
 name = "wasmtime"
-version = "0.39.0"
+version = "0.40.0"
 authors = ["The Wasmtime Project Developers"]
 description = "High-level API to expose the Wasmtime runtime"
 documentation = "https://docs.rs/wasmtime"
@@ -13,13 +13,13 @@ edition = "2021"
 rustdoc-args = ["--cfg", "nightlydoc"]
 
 [dependencies]
-wasmtime-runtime = { path = "../runtime", version = "=0.39.0" }
-wasmtime-environ = { path = "../environ", version = "=0.39.0" }
-wasmtime-jit = { path = "../jit", version = "=0.39.0" }
-wasmtime-cache = { path = "../cache", version = "=0.39.0", optional = true }
-wasmtime-fiber = { path = "../fiber", version = "=0.39.0", optional = true }
-wasmtime-cranelift = { path = "../cranelift", version = "=0.39.0", optional = true }
-wasmtime-component-macro = { path = "../component-macro", version = "=0.39.0", optional = true }
+wasmtime-runtime = { path = "../runtime", version = "=0.40.0" }
+wasmtime-environ = { path = "../environ", version = "=0.40.0" }
+wasmtime-jit = { path = "../jit", version = "=0.40.0" }
+wasmtime-cache = { path = "../cache", version = "=0.40.0", optional = true }
+wasmtime-fiber = { path = "../fiber", version = "=0.40.0", optional = true }
+wasmtime-cranelift = { path = "../cranelift", version = "=0.40.0", optional = true }
+wasmtime-component-macro = { path = "../component-macro", version = "=0.40.0", optional = true }
 target-lexicon = { version = "0.12.0", default-features = false }
 wasmparser = "0.86.0"
 anyhow = "1.0.19"
diff --git a/crates/wast/Cargo.toml b/crates/wast/Cargo.toml
index 85e473992..24c475142 100644
--- a/crates/wast/Cargo.toml
+++ b/crates/wast/Cargo.toml
@@ -1,6 +1,6 @@
 [package]
 name = "wasmtime-wast"
-version = "0.39.0"
+version = "0.40.0"
 authors = ["The Wasmtime Project Developers"]
 description = "wast testing support for wasmtime"
 license = "Apache-2.0 WITH LLVM-exception"
@@ -11,7 +11,7 @@ edition = "2021"
 
 [dependencies]
 anyhow = "1.0.19"
-wasmtime = { path = "../wasmtime", version = "0.39.0", default-features = false, features = ['cranelift'] }
+wasmtime = { path = "../wasmtime", version = "0.40.0", default-features = false, features = ['cranelift'] }
 wast = "42.0.0"
 
 [badges]
diff --git a/crates/wiggle/Cargo.toml b/crates/wiggle/Cargo.toml
index 492f74f64..c7e2d9056 100644
--- a/crates/wiggle/Cargo.toml
+++ b/crates/wiggle/Cargo.toml
@@ -1,6 +1,6 @@
 [package]
 name = "wiggle"
-version = "0.39.0"
+version = "0.40.0"
 authors = ["Pat Hickey <phickey@fastly.com>", "Jakub Konka <kubkonk@jakubkonka.com>", "Alex Crichton <alex@alexcrichton.com>"]
 edition = "2021"
 license = "Apache-2.0 WITH LLVM-exception"
@@ -13,11 +13,11 @@ include = ["src/**/*", "README.md", "LICENSE"]
 [dependencies]
 thiserror = "1"
 witx = { path = "../wasi-common/WASI/tools/witx", version = "0.9.1", optional = true }
-wiggle-macro = { path = "macro", version = "=0.39.0" }
+wiggle-macro = { path = "macro", version = "=0.40.0" }
 tracing = "0.1.26"
 bitflags = "1.2"
 async-trait = "0.1.42"
-wasmtime = { path = "../wasmtime", version = "0.39.0", optional = true, default-features = false }
+wasmtime = { path = "../wasmtime", version = "0.40.0", optional = true, default-features = false }
 anyhow = "1.0"
 
 [badges]
diff --git a/crates/wiggle/generate/Cargo.toml b/crates/wiggle/generate/Cargo.toml
index 3e1eb6285..af3ac56af 100644
--- a/crates/wiggle/generate/Cargo.toml
+++ b/crates/wiggle/generate/Cargo.toml
@@ -1,6 +1,6 @@
 [package]
 name = "wiggle-generate"
-version = "0.39.0"
+version = "0.40.0"
 authors = ["Pat Hickey <phickey@fastly.com>", "Jakub Konka <kubkon@jakubkonka.com>", "Alex Crichton <alex@alexcrichton.com>"]
 license = "Apache-2.0 WITH LLVM-exception"
 edition = "2021"
diff --git a/crates/wiggle/macro/Cargo.toml b/crates/wiggle/macro/Cargo.toml
index 81f3bfee3..f2b6df1d6 100644
--- a/crates/wiggle/macro/Cargo.toml
+++ b/crates/wiggle/macro/Cargo.toml
@@ -1,6 +1,6 @@
 [package]
 name = "wiggle-macro"
-version = "0.39.0"
+version = "0.40.0"
 authors = ["Pat Hickey <phickey@fastly.com>", "Jakub Konka <kubkon@jakubkonka.com>", "Alex Crichton <alex@alexcrichton.com>"]
 edition = "2021"
 license = "Apache-2.0 WITH LLVM-exception"
@@ -21,7 +21,7 @@ test = false
 doctest = false
 
 [dependencies]
-wiggle-generate = { path = "../generate", version = "=0.39.0" }
+wiggle-generate = { path = "../generate", version = "=0.40.0" }
 quote = "1.0"
 syn = { version = "1.0", features = ["full"] }
 proc-macro2 = "1.0"


Test patch:
diff --git a/cranelift/filetests/Cargo.toml b/cranelift/filetests/Cargo.toml
index cf659222c..7f87f195e 100644
--- a/cranelift/filetests/Cargo.toml
+++ b/cranelift/filetests/Cargo.toml
@@ -10,12 +10,12 @@ publish = false
 edition = "2021"
 
 [dependencies]
-cranelift-codegen = { path = "../codegen", version = "0.86.0", features = ["testing_hooks"] }
-cranelift-frontend = { path = "../frontend", version = "0.86.0" }
-cranelift-interpreter = { path = "../interpreter", version = "0.86.0" }
-cranelift-native = { path = "../native", version = "0.86.0" }
-cranelift-reader = { path = "../reader", version = "0.86.0" }
-cranelift-preopt = { path = "../preopt", version = "0.86.0" }
+cranelift-codegen = { path = "../codegen", version = "0.87.0", features = ["testing_hooks"] }
+cranelift-frontend = { path = "../frontend", version = "0.87.0" }
+cranelift-interpreter = { path = "../interpreter", version = "0.87.0" }
+cranelift-native = { path = "../native", version = "0.87.0" }
+cranelift-reader = { path = "../reader", version = "0.87.0" }
+cranelift-preopt = { path = "../preopt", version = "0.87.0" }
 file-per-thread-logger = "0.1.2"
 filecheck = "0.5.0"
 gimli = { version = "0.26.0", default-features = false, features = ["read"] }
diff --git a/cranelift/filetests/filetests/runtests/fabs.clif b/cranelift/filetests/filetests/runtests/fabs.clif
new file mode 100644
index 000000000..4d63273ef
--- /dev/null
+++ b/cranelift/filetests/filetests/runtests/fabs.clif
@@ -0,0 +1,93 @@
+test interpret
+test run
+target aarch64
+target x86_64
+target s390x
+
+function %fabs_f32(f32) -> f32 {
+block0(v0: f32):
+    v1 = fabs v0
+    return v1
+}
+; run: %fabs_f32(0x9.0) == 0x9.0
+; run: %fabs_f32(-0x9.0) == 0x9.0
+; run: %fabs_f32(0x0.0) == 0x0.0
+; run: %fabs_f32(-0x0.0) == 0x0.0
+
+; F32 Inf
+; run: %fabs_f32(Inf) == Inf
+; run: %fabs_f32(-Inf) == +Inf
+
+; F32 Epsilon  / Max / Min Positive
+; run: %fabs_f32(0x1.000000p-23) == 0x1.000000p-23
+; run: %fabs_f32(-0x1.000000p-23) == 0x1.000000p-23
+; run: %fabs_f32(0x1.fffffep127) == 0x1.fffffep127
+; run: %fabs_f32(-0x1.fffffep127) == 0x1.fffffep127
+; run: %fabs_f32(0x1.000000p-126) == 0x1.000000p-126
+; run: %fabs_f32(-0x1.000000p-126) == 0x1.000000p-126
+
+; F32 Subnormals
+; run: %fabs_f32(0x0.800000p-126) == 0x0.800000p-126
+; run: %fabs_f32(-0x0.800000p-126) == 0x0.800000p-126
+; run: %fabs_f32(0x0.000002p-126) == 0x0.000002p-126
+; run: %fabs_f32(-0x0.000002p-126) == 0x0.000002p-126
+
+; F32 NaN's
+; Unlike with other operations fabs is guaranteed to only affect the sign bit
+; run: %fabs_f32(+NaN) == +NaN
+; run: %fabs_f32(-NaN) == +NaN
+; run: %fabs_f32(+NaN:0x0) == +NaN:0x0
+; run: %fabs_f32(+NaN:0x1) == +NaN:0x1
+; run: %fabs_f32(+NaN:0x300001) == +NaN:0x300001
+; run: %fabs_f32(-NaN:0x0) == +NaN:0x0
+; run: %fabs_f32(-NaN:0x1) == +NaN:0x1
+; run: %fabs_f32(-NaN:0x300001) == +NaN:0x300001
+; run: %fabs_f32(+sNaN:0x1) == +sNaN:0x1
+; run: %fabs_f32(-sNaN:0x1) == +sNaN:0x1
+; run: %fabs_f32(+sNaN:0x200001) == +sNaN:0x200001
+; run: %fabs_f32(-sNaN:0x200001) == +sNaN:0x200001
+
+
+
+function %fabs_f64(f64) -> f64 {
+block0(v0: f64):
+    v1 = fabs v0
+    return v1
+}
+; run: %fabs_f64(0x9.0) == 0x9.0
+; run: %fabs_f64(-0x9.0) == 0x9.0
+; run: %fabs_f64(0x0.0) == 0x0.0
+; run: %fabs_f64(-0x0.0) == 0x0.0
+
+; F64 Inf
+; run: %fabs_f64(Inf) == Inf
+; run: %fabs_f64(-Inf) == +Inf
+
+; F64 Epsilon / Max / Min Positive
+; run: %fabs_f64(0x1.0000000000000p-52) == 0x1.0000000000000p-52
+; run: %fabs_f64(-0x1.0000000000000p-52) == 0x1.0000000000000p-52
+; run: %fabs_f64(0x1.fffffffffffffp1023) == 0x1.fffffffffffffp1023
+; run: %fabs_f64(-0x1.fffffffffffffp1023) == 0x1.fffffffffffffp1023
+; run: %fabs_f64(0x1.0000000000000p-1022) == 0x1.0000000000000p-1022
+; run: %fabs_f64(-0x1.0000000000000p-1022) == 0x1.0000000000000p-1022
+
+; F64 Subnormals
+; run: %fabs_f64(0x0.8000000000000p-1022) == 0x0.8000000000000p-1022
+; run: %fabs_f64(-0x0.8000000000000p-1022) == 0x0.8000000000000p-1022
+; run: %fabs_f64(0x0.0000000000001p-1022) == 0x0.0000000000001p-1022
+; run: %fabs_f64(-0x0.0000000000001p-1022) == 0x0.0000000000001p-1022
+
+; F64 NaN's
+; Unlike with other operations fabs is guaranteed to only affect the sign bit
+; run: %fabs_f64(+NaN) == +NaN
+; run: %fabs_f64(-NaN) == +NaN
+; run: %fabs_f64(+NaN:0x0) == +NaN:0x0
+; run: %fabs_f64(+NaN:0x1) == +NaN:0x1
+; run: %fabs_f64(+NaN:0x4000000000001) == +NaN:0x4000000000001
+; run: %fabs_f64(-NaN:0x0) == +NaN:0x0
+; run: %fabs_f64(-NaN:0x1) == +NaN:0x1
+; run: %fabs_f64(-NaN:0x4000000000001) == +NaN:0x4000000000001
+; run: %fabs_f64(+sNaN:0x1) == +sNaN:0x1
+; run: %fabs_f64(-sNaN:0x1) == +sNaN:0x1
+; run: %fabs_f64(+sNaN:0x4000000000001) == +sNaN:0x4000000000001
+; run: %fabs_f64(-sNaN:0x4000000000001) == +sNaN:0x4000000000001
diff --git a/cranelift/filetests/filetests/runtests/fcopysign.clif b/cranelift/filetests/filetests/runtests/fcopysign.clif
new file mode 100644
index 000000000..281143783
--- /dev/null
+++ b/cranelift/filetests/filetests/runtests/fcopysign.clif
@@ -0,0 +1,107 @@
+test interpret
+test run
+target aarch64
+target x86_64
+target s390x
+
+function %fcopysign_f32(f32, f32) -> f32 {
+block0(v0: f32, v1: f32):
+    v2 = fcopysign v0, v1
+    return v2
+}
+; run: %fcopysign_f32(0x9.0, 0x9.0) == 0x9.0
+; run: %fcopysign_f32(-0x9.0, 0x9.0) == 0x9.0
+; run: %fcopysign_f32(0x9.0, -0x9.0) == -0x9.0
+; run: %fcopysign_f32(-0x9.0, -0x9.0) == -0x9.0
+; run: %fcopysign_f32(0x0.0, -0x0.0) == -0x0.0
+; run: %fcopysign_f32(-0x0.0, 0x0.0) == 0x0.0
+
+; F32 Inf
+; run: %fcopysign_f32(Inf, Inf) == Inf
+; run: %fcopysign_f32(-Inf, Inf) == Inf
+; run: %fcopysign_f32(Inf, -Inf) == -Inf
+; run: %fcopysign_f32(-Inf, -Inf) == -Inf
+
+; F32 Epsilon  / Max / Min Positive
+; run: %fcopysign_f32(0x1.000000p-23, -0x0.0) == -0x1.000000p-23
+; run: %fcopysign_f32(-0x1.000000p-23, 0x0.0) == 0x1.000000p-23
+; run: %fcopysign_f32(0x1.fffffep127, -0x0.0) == -0x1.fffffep127
+; run: %fcopysign_f32(-0x1.fffffep127, 0x0.0) == 0x1.fffffep127
+; run: %fcopysign_f32(0x1.000000p-126, -0x0.0) == -0x1.000000p-126
+; run: %fcopysign_f32(-0x1.000000p-126, 0x0.0) == 0x1.000000p-126
+
+; F32 Subnormals
+; run: %fcopysign_f32(0x0.800000p-126, -0x0.0) == -0x0.800000p-126
+; run: %fcopysign_f32(-0x0.800000p-126, 0x0.0) == 0x0.800000p-126
+; run: %fcopysign_f32(0x0.000002p-126, -0x0.0) == -0x0.000002p-126
+; run: %fcopysign_f32(-0x0.000002p-126, 0x0.0) == 0x0.000002p-126
+
+; F32 NaN's
+; Unlike with other operations fcopysign is guaranteed to only affect the sign bit
+; run: %fcopysign_f32(0x0.0, -NaN) == -0x0.0
+; run: %fcopysign_f32(0x3.0, +sNaN:0x1) == 0x3.0
+; run: %fcopysign_f32(Inf, -NaN) == -Inf
+; run: %fcopysign_f32(+NaN, -NaN) == -NaN
+; run: %fcopysign_f32(-NaN, +NaN) == +NaN
+; run: %fcopysign_f32(+NaN:0x0, -NaN) == -NaN:0x0
+; run: %fcopysign_f32(+NaN:0x1, -NaN) == -NaN:0x1
+; run: %fcopysign_f32(+NaN:0x300001, -NaN) == -NaN:0x300001
+; run: %fcopysign_f32(-NaN:0x0, +NaN) == +NaN:0x0
+; run: %fcopysign_f32(-NaN:0x1, +NaN) == +NaN:0x1
+; run: %fcopysign_f32(-NaN:0x300001, +NaN) == +NaN:0x300001
+; run: %fcopysign_f32(+sNaN:0x1, -NaN) == -sNaN:0x1
+; run: %fcopysign_f32(-sNaN:0x1, +NaN) == +sNaN:0x1
+; run: %fcopysign_f32(+sNaN:0x200001, -NaN) == -sNaN:0x200001
+; run: %fcopysign_f32(-sNaN:0x200001, +NaN) == +sNaN:0x200001
+
+
+
+function %fcopysign_f64(f64, f64) -> f64 {
+block0(v0: f64, v1: f64):
+    v2 = fcopysign v0, v1
+    return v2
+}
+; run: %fcopysign_f64(0x9.0, 0x9.0) == 0x9.0
+; run: %fcopysign_f64(-0x9.0, 0x9.0) == 0x9.0
+; run: %fcopysign_f64(0x9.0, -0x9.0) == -0x9.0
+; run: %fcopysign_f64(-0x9.0, -0x9.0) == -0x9.0
+; run: %fcopysign_f64(0x0.0, -0x0.0) == -0x0.0
+; run: %fcopysign_f64(-0x0.0, 0x0.0) == 0x0.0
+
+; F64 Inf
+; run: %fcopysign_f64(Inf, Inf) == Inf
+; run: %fcopysign_f64(-Inf, Inf) == Inf
+; run: %fcopysign_f64(Inf, -Inf) == -Inf
+; run: %fcopysign_f64(-Inf, -Inf) == -Inf
+
+; F64 Epsilon / Max / Min Positive
+; run: %fcopysign_f64(0x1.0000000000000p-52, -0x0.0) == -0x1.0000000000000p-52
+; run: %fcopysign_f64(-0x1.0000000000000p-52, 0x0.0) == 0x1.0000000000000p-52
+; run: %fcopysign_f64(0x1.fffffffffffffp1023, -0x0.0) == -0x1.fffffffffffffp1023
+; run: %fcopysign_f64(-0x1.fffffffffffffp1023, 0x0.0) == 0x1.fffffffffffffp1023
+; run: %fcopysign_f64(0x1.0000000000000p-1022, -0x0.0) == -0x1.0000000000000p-1022
+; run: %fcopysign_f64(-0x1.0000000000000p-1022, 0x0.0) == 0x1.0000000000000p-1022
+
+; F64 Subnormals
+; run: %fcopysign_f64(0x0.8000000000000p-1022, -0x0.0) == -0x0.8000000000000p-1022
+; run: %fcopysign_f64(-0x0.8000000000000p-1022, 0x0.0) == 0x0.8000000000000p-1022
+; run: %fcopysign_f64(0x0.0000000000001p-1022, -0x0.0) == -0x0.0000000000001p-1022
+; run: %fcopysign_f64(-0x0.0000000000001p-1022, 0x0.0) == 0x0.0000000000001p-1022
+
+; F64 NaN's
+; Unlike with other operations fcopysign is guaranteed to only affect the sign bit
+; run: %fcopysign_f64(0x0.0, -NaN) == -0x0.0
+; run: %fcopysign_f64(0x3.0, +sNaN:0x1) == 0x3.0
+; run: %fcopysign_f64(Inf, -NaN) == -Inf
+; run: %fcopysign_f64(+NaN, -NaN) == -NaN
+; run: %fcopysign_f64(-NaN, +NaN) == +NaN
+; run: %fcopysign_f64(+NaN:0x0, -NaN) == -NaN:0x0
+; run: %fcopysign_f64(+NaN:0x1, -NaN) == -NaN:0x1
+; run: %fcopysign_f64(+NaN:0x4000000000001, -NaN) == -NaN:0x4000000000001
+; run: %fcopysign_f64(-NaN:0x0, +NaN) == +NaN:0x0
+; run: %fcopysign_f64(-NaN:0x1, +NaN) == +NaN:0x1
+; run: %fcopysign_f64(-NaN:0x4000000000001, +NaN) == +NaN:0x4000000000001
+; run: %fcopysign_f64(+sNaN:0x1, -NaN) == -sNaN:0x1
+; run: %fcopysign_f64(-sNaN:0x1, +NaN) == +sNaN:0x1
+; run: %fcopysign_f64(+sNaN:0x4000000000001, -NaN) == -sNaN:0x4000000000001
+; run: %fcopysign_f64(-sNaN:0x4000000000001, +NaN) == +sNaN:0x4000000000001
diff --git a/cranelift/filetests/filetests/runtests/fma.clif b/cranelift/filetests/filetests/runtests/fma.clif
new file mode 100644
index 000000000..e9429f4b5
--- /dev/null
+++ b/cranelift/filetests/filetests/runtests/fma.clif
@@ -0,0 +1,119 @@
+test interpret
+test run
+target aarch64
+target s390x
+
+function %fma_f32(f32, f32, f32) -> f32 {
+block0(v0: f32, v1: f32, v2: f32):
+    v3 = fma v0, v1, v2
+    return v3
+}
+; run: %fma_f32(0x9.0, 0x9.0, 0x9.0) == 0x1.680000p6
+; run: %fma_f32(0x83.0, 0x2.68091p6, 0x9.88721p1) == 0x1.3b88e6p14
+
+; run: %fma_f32(0x0.0, 0x0.0, 0x0.0) == 0x0.0
+; run: %fma_f32(0x0.0, 0x0.0, -0x0.0) == 0x0.0
+; run: %fma_f32(0x0.0, -0x0.0, 0x0.0) == 0x0.0
+; run: %fma_f32(-0x0.0, 0x0.0, 0x0.0) == 0x0.0
+
+; run: %fma_f32(-Inf, -Inf, 0x0.0) == +Inf
+; run: %fma_f32(Inf, -Inf, 0x0.0) == -Inf
+; run: %fma_f32(-Inf, Inf, 0x0.0) == -Inf
+; run: %fma_f32(Inf, -Inf, -Inf) == -Inf
+; run: %fma_f32(-Inf, Inf, -Inf) == -Inf
+
+; F32 Epsilon / Max / Min Positive
+; run: %fma_f32(0x1.000000p-23, 0x1.000000p-23, 0x1.000000p-23) == 0x1.000002p-23
+; run: %fma_f32(0x0.0, 0x0.0, 0x1.000000p-23) == 0x1.000000p-23
+; run: %fma_f32(0x1.fffffep127, 0x1.fffffep127, 0x1.fffffep127) == +Inf
+; run: %fma_f32(0x0.0, 0x0.0, 0x1.fffffep127) == 0x1.fffffep127
+; run: %fma_f32(0x1.000000p-126, 0x1.000000p-126, 0x1.000000p-126) == 0x1.000000p-126
+; run: %fma_f32(0x0.0, 0x0.0, 0x1.000000p-126) == 0x1.000000p-126
+
+; F32 Subnormals
+; run: %fma_f32(0x0.800000p-126, 0x0.800000p-126, 0x0.800000p-126) == 0x0.800000p-126
+; run: %fma_f32(0x0.800000p-126, 0x0.800000p-126, 0x0.0) == 0x0.0
+; run: %fma_f32(0x0.0, 0x0.0, 0x0.800000p-126) == 0x0.800000p-126
+; run: %fma_f32(0x0.000002p-126, 0x0.000002p-126, 0x0.000002p-126) == 0x0.000002p-126
+; run: %fma_f32(0x0.000002p-126, 0x0.000002p-126, 0x0.0) == 0x0.0
+; run: %fma_f32(0x0.0, 0x0.0, 0x0.000002p-126) == 0x0.000002p-126
+
+
+
+;; The IEEE754 Standard does not make a lot of guarantees about what
+;; comes out of NaN producing operations, we just check if its a NaN
+function %fma_is_nan_f32(f32, f32, f32) -> i32 {
+block0(v0: f32, v1: f32, v2: f32):
+    v3 = fma v0, v1, v2
+    v4 = fcmp ne v3, v3
+    v5 = bint.i32 v4
+    return v5
+}
+; run: %fma_is_nan_f32(Inf, -Inf, Inf) == 1
+; run: %fma_is_nan_f32(-Inf, Inf, Inf) == 1
+; run: %fma_is_nan_f32(-Inf, -Inf, -Inf) == 1
+
+; run: %fma_is_nan_f32(+NaN, 0x0.0, 0x0.0) == 1
+; run: %fma_is_nan_f32(0x0.0, +NaN, 0x0.0) == 1
+; run: %fma_is_nan_f32(0x0.0, 0x0.0, +NaN) == 1
+; run: %fma_is_nan_f32(-NaN, 0x0.0, 0x0.0) == 1
+; run: %fma_is_nan_f32(0x0.0, -NaN, 0x0.0) == 1
+; run: %fma_is_nan_f32(0x0.0, 0x0.0, -NaN) == 1
+
+
+
+function %fma_f64(f64, f64, f64) -> f64 {
+block0(v0: f64, v1: f64, v2: f64):
+    v3 = fma v0, v1, v2
+    return v3
+}
+; run: %fma_f64(0x9.0, 0x9.0, 0x9.0) == 0x1.680000p6
+; run: %fma_f64(0x1.3b88ea148dd4ap14, 0x2.680916809121p6, 0x9.887218721837p1) == 0x1.7ba6ebee17417p21
+
+; run: %fma_f64(0x0.0, 0x0.0, 0x0.0) == 0x0.0
+; run: %fma_f64(0x0.0, 0x0.0, -0x0.0) == 0x0.0
+; run: %fma_f64(0x0.0, -0x0.0, 0x0.0) == 0x0.0
+; run: %fma_f64(-0x0.0, 0x0.0, 0x0.0) == 0x0.0
+
+; run: %fma_f64(-Inf, -Inf, 0x0.0) == +Inf
+; run: %fma_f64(Inf, -Inf, 0x0.0) == -Inf
+; run: %fma_f64(-Inf, Inf, 0x0.0) == -Inf
+; run: %fma_f64(Inf, -Inf, -Inf) == -Inf
+; run: %fma_f64(-Inf, Inf, -Inf) == -Inf
+
+; F64 Epsilon / Max / Min Positive
+; run: %fma_f64(0x1.0000000000000p-52, 0x1.0000000000000p-52, 0x1.0000000000000p-52) == 0x1.0000000000001p-52
+; run: %fma_f64(0x0.0, 0x0.0, 0x1.0000000000000p-52) == 0x1.0000000000000p-52
+; run: %fma_f64(0x1.fffffffffffffp1023, 0x1.fffffffffffffp1023, 0x1.fffffffffffffp1023) == +Inf
+; run: %fma_f64(0x0.0, 0x0.0, 0x1.fffffffffffffp1023) == 0x1.fffffffffffffp1023
+; run: %fma_f64(0x1.0000000000000p-1022, 0x1.0000000000000p-1022, 0x1.0000000000000p-1022) == 0x1.0000000000000p-1022
+; run: %fma_f64(0x0.0, 0x0.0, 0x1.0000000000000p-1022) == 0x1.0000000000000p-1022
+
+; F64 Subnormals
+; run: %fma_f64(0x0.8000000000000p-1022, 0x0.8000000000000p-1022, 0x0.8000000000000p-1022) == 0x0.8000000000000p-1022
+; run: %fma_f64(0x0.8000000000000p-1022, 0x0.8000000000000p-1022, 0x0.0) == 0x0.0
+; run: %fma_f64(0x0.0, 0x0.0, 0x0.8000000000000p-1022) == 0x0.8000000000000p-1022
+; run: %fma_f64(0x0.0000000000001p-1022, 0x0.0000000000001p-1022, 0x0.0000000000001p-1022) == 0x0.0000000000001p-1022
+; run: %fma_f64(0x0.0000000000001p-1022, 0x0.0000000000001p-1022, 0x0.0) == 0x0.0
+; run: %fma_f64(0x0.0, 0x0.0, 0x0.0000000000001p-1022) == 0x0.0000000000001p-1022
+
+
+;; The IEEE754 Standard does not make a lot of guarantees about what
+;; comes out of NaN producing operations, we just check if its a NaN
+function %fma_is_nan_f64(f64, f64, f64) -> i32 {
+block0(v0: f64, v1: f64, v2: f64):
+    v3 = fma v0, v1, v2
+    v4 = fcmp ne v3, v3
+    v5 = bint.i32 v4
+    return v5
+}
+; run: %fma_is_nan_f64(Inf, -Inf, Inf) == 1
+; run: %fma_is_nan_f64(-Inf, Inf, Inf) == 1
+; run: %fma_is_nan_f64(-Inf, -Inf, -Inf) == 1
+
+; run: %fma_is_nan_f64(+NaN, 0x0.0, 0x0.0) == 1
+; run: %fma_is_nan_f64(0x0.0, +NaN, 0x0.0) == 1
+; run: %fma_is_nan_f64(0x0.0, 0x0.0, +NaN) == 1
+; run: %fma_is_nan_f64(-NaN, 0x0.0, 0x0.0) == 1
+; run: %fma_is_nan_f64(0x0.0, -NaN, 0x0.0) == 1
+; run: %fma_is_nan_f64(0x0.0, 0x0.0, -NaN) == 1
diff --git a/cranelift/filetests/filetests/runtests/fneg.clif b/cranelift/filetests/filetests/runtests/fneg.clif
new file mode 100644
index 000000000..bfe63f924
--- /dev/null
+++ b/cranelift/filetests/filetests/runtests/fneg.clif
@@ -0,0 +1,93 @@
+test interpret
+test run
+target aarch64
+target x86_64
+target s390x
+
+function %fneg_f32(f32) -> f32 {
+block0(v0: f32):
+    v1 = fneg v0
+    return v1
+}
+; run: %fneg_f32(0x9.0) == -0x9.0
+; run: %fneg_f32(-0x9.0) == 0x9.0
+; run: %fneg_f32(0x0.0) == -0x0.0
+; run: %fneg_f32(-0x0.0) == 0x0.0
+
+; F32 Inf
+; run: %fneg_f32(Inf) == -Inf
+; run: %fneg_f32(-Inf) == +Inf
+
+; F32 Epsilon  / Max / Min Positive
+; run: %fneg_f32(0x1.000000p-23) == -0x1.000000p-23
+; run: %fneg_f32(-0x1.000000p-23) == 0x1.000000p-23
+; run: %fneg_f32(0x1.fffffep127) == -0x1.fffffep127
+; run: %fneg_f32(-0x1.fffffep127) == 0x1.fffffep127
+; run: %fneg_f32(0x1.000000p-126) == -0x1.000000p-126
+; run: %fneg_f32(-0x1.000000p-126) == 0x1.000000p-126
+
+; F32 Subnormals
+; run: %fneg_f32(0x0.800000p-126) == -0x0.800000p-126
+; run: %fneg_f32(-0x0.800000p-126) == 0x0.800000p-126
+; run: %fneg_f32(0x0.000002p-126) == -0x0.000002p-126
+; run: %fneg_f32(-0x0.000002p-126) == 0x0.000002p-126
+
+; F32 NaN's
+; Unlike with other operations fneg is guaranteed to only affect the sign bit
+; run: %fneg_f32(+NaN) == -NaN
+; run: %fneg_f32(-NaN) == +NaN
+; run: %fneg_f32(+NaN:0x0) == -NaN:0x0
+; run: %fneg_f32(+NaN:0x1) == -NaN:0x1
+; run: %fneg_f32(+NaN:0x300001) == -NaN:0x300001
+; run: %fneg_f32(-NaN:0x0) == +NaN:0x0
+; run: %fneg_f32(-NaN:0x1) == +NaN:0x1
+; run: %fneg_f32(-NaN:0x300001) == +NaN:0x300001
+; run: %fneg_f32(+sNaN:0x1) == -sNaN:0x1
+; run: %fneg_f32(-sNaN:0x1) == +sNaN:0x1
+; run: %fneg_f32(+sNaN:0x200001) == -sNaN:0x200001
+; run: %fneg_f32(-sNaN:0x200001) == +sNaN:0x200001
+
+
+
+function %fneg_f64(f64) -> f64 {
+block0(v0: f64):
+    v1 = fneg v0
+    return v1
+}
+; run: %fneg_f64(0x9.0) == -0x9.0
+; run: %fneg_f64(-0x9.0) == 0x9.0
+; run: %fneg_f64(0x0.0) == -0x0.0
+; run: %fneg_f64(-0x0.0) == 0x0.0
+
+; F64 Inf
+; run: %fneg_f64(+Inf) == -Inf
+; run: %fneg_f64(-Inf) == +Inf
+
+; F64 Epsilon / Max / Min Positive
+; run: %fneg_f64(0x1.0000000000000p-52) == -0x1.0000000000000p-52
+; run: %fneg_f64(-0x1.0000000000000p-52) == 0x1.0000000000000p-52
+; run: %fneg_f64(0x1.fffffffffffffp1023) == -0x1.fffffffffffffp1023
+; run: %fneg_f64(-0x1.fffffffffffffp1023) == 0x1.fffffffffffffp1023
+; run: %fneg_f64(0x1.0000000000000p-1022) == -0x1.0000000000000p-1022
+; run: %fneg_f64(-0x1.0000000000000p-1022) == 0x1.0000000000000p-1022
+
+; F64 Subnormals
+; run: %fneg_f64(0x0.8000000000000p-1022) == -0x0.8000000000000p-1022
+; run: %fneg_f64(-0x0.8000000000000p-1022) == 0x0.8000000000000p-1022
+; run: %fneg_f64(0x0.0000000000001p-1022) == -0x0.0000000000001p-1022
+; run: %fneg_f64(-0x0.0000000000001p-1022) == 0x0.0000000000001p-1022
+
+; F64 NaN's
+; Unlike with other operations fneg is guaranteed to only affect the sign bit
+; run: %fneg_f64(+NaN) == -NaN
+; run: %fneg_f64(-NaN) == +NaN
+; run: %fneg_f64(+NaN:0x0) == -NaN:0x0
+; run: %fneg_f64(+NaN:0x1) == -NaN:0x1
+; run: %fneg_f64(+NaN:0x4000000000001) == -NaN:0x4000000000001
+; run: %fneg_f64(-NaN:0x0) == +NaN:0x0
+; run: %fneg_f64(-NaN:0x1) == +NaN:0x1
+; run: %fneg_f64(-NaN:0x4000000000001) == +NaN:0x4000000000001
+; run: %fneg_f64(+sNaN:0x1) == -sNaN:0x1
+; run: %fneg_f64(-sNaN:0x1) == +sNaN:0x1
+; run: %fneg_f64(+sNaN:0x4000000000001) == -sNaN:0x4000000000001
+; run: %fneg_f64(-sNaN:0x4000000000001) == +sNaN:0x4000000000001
diff --git a/crates/misc/component-macro-test/Cargo.toml b/crates/misc/component-macro-test/Cargo.toml
new file mode 100644
index 000000000..f613aaeb2
--- /dev/null
+++ b/crates/misc/component-macro-test/Cargo.toml
@@ -0,0 +1,15 @@
+[package]
+name = "component-macro-test"
+authors = ["The Wasmtime Project Developers"]
+license = "Apache-2.0 WITH LLVM-exception"
+version = "0.1.0"
+edition = "2021"
+publish = false
+
+[lib]
+proc-macro = true
+
+[dependencies]
+proc-macro2 = "1.0"
+quote = "1.0"
+syn = { version = "1.0", features = ["full"] }
diff --git a/crates/misc/component-macro-test/src/lib.rs b/crates/misc/component-macro-test/src/lib.rs
new file mode 100644
index 000000000..59a62de38
--- /dev/null
+++ b/crates/misc/component-macro-test/src/lib.rs
@@ -0,0 +1,34 @@
+use proc_macro2::{Span, TokenStream};
+use quote::quote;
+use syn::parse_macro_input;
+
+#[proc_macro_attribute]
+pub fn add_variants(
+    attr: proc_macro::TokenStream,
+    item: proc_macro::TokenStream,
+) -> proc_macro::TokenStream {
+    expand_variants(
+        &parse_macro_input!(attr as syn::LitInt),
+        parse_macro_input!(item as syn::ItemEnum),
+    )
+    .unwrap_or_else(syn::Error::into_compile_error)
+    .into()
+}
+
+fn expand_variants(count: &syn::LitInt, mut ty: syn::ItemEnum) -> syn::Result<TokenStream> {
+    let count = count
+        .base10_digits()
+        .parse::<usize>()
+        .map_err(|_| syn::Error::new(count.span(), "expected unsigned integer"))?;
+
+    ty.variants = (0..count)
+        .map(|index| syn::Variant {
+            attrs: Vec::new(),
+            ident: syn::Ident::new(&format!("V{}", index), Span::call_site()),
+            fields: syn::Fields::Unit,
+            discriminant: None,
+        })
+        .collect();
+
+    Ok(quote!(#ty))
+}
diff --git a/crates/test-programs/Cargo.toml b/crates/test-programs/Cargo.toml
index 694eeb71b..a4781940c 100644
--- a/crates/test-programs/Cargo.toml
+++ b/crates/test-programs/Cargo.toml
@@ -11,10 +11,10 @@ license = "Apache-2.0 WITH LLVM-exception"
 cfg-if = "1.0"
 
 [dev-dependencies]
-wasi-common = { path = "../wasi-common", version = "0.39.0" }
-wasi-cap-std-sync = { path = "../wasi-common/cap-std-sync", version = "0.39.0" }
-wasmtime = { path = "../wasmtime", version = "0.39.0" }
-wasmtime-wasi = { path = "../wasi", version = "0.39.0", features = ["tokio"] }
+wasi-common = { path = "../wasi-common", version = "0.40.0" }
+wasi-cap-std-sync = { path = "../wasi-common/cap-std-sync", version = "0.40.0" }
+wasmtime = { path = "../wasmtime", version = "0.40.0" }
+wasmtime-wasi = { path = "../wasi", version = "0.40.0", features = ["tokio"] }
 target-lexicon = "0.12.0"
 pretty_env_logger = "0.4.0"
 tempfile = "3.1.0"
diff --git a/tests/all/component_model/macros.rs b/tests/all/component_model/macros.rs
index 71a1385b1..ca519d2f4 100644
--- a/tests/all/component_model/macros.rs
+++ b/tests/all/component_model/macros.rs
@@ -1,5 +1,6 @@
 use super::TypedFuncExt;
 use anyhow::Result;
+use component_macro_test::add_variants;
 use std::fmt::Write;
 use wasmtime::component::{Component, ComponentType, Lift, Linker, Lower};
 use wasmtime::Store;
@@ -475,5 +476,41 @@ fn enum_derive() -> Result<()> {
         .get_typed_func::<(Foo,), Foo, _>(&mut store, "echo")
         .is_err());
 
+    #[add_variants(257)]
+    #[derive(ComponentType, Lift, Lower, PartialEq, Eq, Debug, Copy, Clone)]
+    #[component(enum)]
+    enum Many {}
+
+    let component = Component::new(
+        &engine,
+        make_echo_component(
+            &format!(
+                r#"(type $Foo (enum {}))"#,
+                (0..257)
+                    .map(|index| format!(r#""V{}""#, index))
+                    .collect::<Vec<_>>()
+                    .join(" ")
+            ),
+            4,
+        ),
+    )?;
+    let instance = Linker::new(&engine).instantiate(&mut store, &component)?;
+    let func = instance.get_typed_func::<(Many,), Many, _>(&mut store, "echo")?;
+
+    for &input in &[Many::V0, Many::V1, Many::V254, Many::V255, Many::V256] {
+        let output = func.call_and_post_return(&mut store, (input,))?;
+
+        assert_eq!(input, output);
+    }
+
+    // TODO: The following case takes forever (i.e. I gave up after 30 minutes) to compile; we'll need to profile
+    // the compiler to find out why, which may point the way to a more efficient option.  On the other hand, this
+    // may not be worth spending time on.  Enums with over 2^16 variants are rare enough.
+
+    // #[add_variants(65537)]
+    // #[derive(ComponentType, Lift, Lower, PartialEq, Eq, Debug, Copy, Clone)]
+    // #[component(enum)]
+    // enum ManyMore {}
+
     Ok(())
 }