Repository: bytecodealliance/wasmtime
Pull request #8476 (2024-04-25 19:42:19)

Switch from `bincode` to `postcard` for serializing
Wasmtime and Cranelift have a few miscellaenous use cases for "just take this Rust type and make it bytes", for example Wasmtime's serialization of internal metadata into a compiled module. Previously Wasmtime used the `bincode` crate for performing these tasks as the format was generally optimized to be small and fast, not general purpose (e.g. JSON). The `bincode` crate on crates.io doesn't work on `no_std`, however, and with the work in #8341 that's an issue now for Wasmtime.

This crate switches instead to the `postcard` crate. This crate is listed in Serde's documentation as:

> Postcard, a no_std and embedded-systems friendly compact binary
> format.

While I've not personally used it before it checks all the boxes we relied on `bincode` for and additionally works with `no_std`. After auditing the crate this commit then switches out Wasmtime's usage of `bincode` for `postcard` throughout the repository.

<!--
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/Cargo.lock b/Cargo.lock
index 47abbadae..6dc61cec6 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -161,15 +161,6 @@ version = "0.21.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "a4a4ddaa51a5bc52a6948f74c06d20aaaddb71924eab79b8c97a8c556e942d6a"
 
-[[package]]
-name = "bincode"
-version = "1.3.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b1f45e9417d87227c7a56d22e471c6206462cba514c7590c09aff4cf6d1ddcad"
-dependencies = [
- "serde",
-]
-
 [[package]]
 name = "bit-set"
 version = "0.5.2"
@@ -473,6 +464,12 @@ version = "0.5.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "2da6da31387c7e4ef160ffab6d5e7f00c42626fe39aea70a7b0f1773f7dd6c1b"
 
+[[package]]
+name = "cobs"
+version = "0.2.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "67ba02a97a2bd10f4b59b25c7973101c79642302776489e030cd13cdab09ed15"
+
 [[package]]
 name = "codespan-reporting"
 version = "0.11.1"
@@ -599,7 +596,6 @@ name = "cranelift-codegen"
 version = "0.108.0"
 dependencies = [
  "anyhow",
- "bincode",
  "bumpalo",
  "capstone",
  "cranelift-bforest",
@@ -612,6 +608,7 @@ dependencies = [
  "gimli",
  "hashbrown 0.14.0",
  "log",
+ "postcard",
  "regalloc2",
  "serde",
  "serde_derive",
@@ -1045,6 +1042,12 @@ version = "1.6.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "e78d4f1cc4ae33bbfc157ed5d5a5ef3bc29227303d595861deb238fcec4e9457"
 
+[[package]]
+name = "embedded-io"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ef1a6892d9eef45c8fa6b9e0086428a2cca8491aca8f787c534a3d6d0bcb3ced"
+
 [[package]]
 name = "embedding"
 version = "21.0.0"
@@ -2090,6 +2093,17 @@ dependencies = [
  "plotters-backend",
 ]
 
+[[package]]
+name = "postcard"
+version = "1.0.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a55c51ee6c0db07e68448e336cf8ea4131a620edefebf9893e759b2d793420f8"
+dependencies = [
+ "cobs",
+ "embedded-io",
+ "serde",
+]
+
 [[package]]
 name = "ppv-lite86"
 version = "0.2.16"
@@ -3408,7 +3422,6 @@ dependencies = [
  "addr2line",
  "anyhow",
  "async-trait",
- "bincode",
  "bumpalo",
  "cfg-if",
  "encoding_rs",
@@ -3421,6 +3434,7 @@ dependencies = [
  "object 0.33.0",
  "once_cell",
  "paste",
+ "postcard",
  "rayon",
  "rustix",
  "semver",
@@ -3509,11 +3523,11 @@ version = "21.0.0"
 dependencies = [
  "anyhow",
  "base64",
- "bincode",
  "directories-next",
  "filetime",
  "log",
  "once_cell",
+ "postcard",
  "pretty_env_logger",
  "rustix",
  "serde",
@@ -3653,7 +3667,6 @@ name = "wasmtime-environ"
 version = "21.0.0"
 dependencies = [
  "anyhow",
- "bincode",
  "clap",
  "cpp_demangle",
  "cranelift-entity",
@@ -3662,6 +3675,7 @@ dependencies = [
  "indexmap 2.0.0",
  "log",
  "object 0.33.0",
+ "postcard",
  "rustc-demangle",
  "serde",
  "serde_derive",
diff --git a/Cargo.toml b/Cargo.toml
index f137a2e26..0c876b37f 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -290,7 +290,7 @@ test-log = { version = "0.2", default-features = false, features = ["trace"] }
 tracing-subscriber = { version = "0.3.1", default-features = false, features = ['fmt', 'env-filter', 'ansi', 'tracing-log'] }
 url = "2.3.1"
 humantime = "2.0.0"
-bincode = "1.2.1"
+postcard = { version = "1.0.8", default-features = false, features = ['alloc'] }
 
 # =============================================================================
 #
diff --git a/cranelift/codegen/Cargo.toml b/cranelift/codegen/Cargo.toml
index 2dfde787e..02d4bb46f 100644
--- a/cranelift/codegen/Cargo.toml
+++ b/cranelift/codegen/Cargo.toml
@@ -28,7 +28,7 @@ target-lexicon = { workspace = true }
 log = { workspace = true }
 serde = { workspace = true, optional = true }
 serde_derive = { workspace = true, optional = true }
-bincode = { workspace = true, optional = true }
+postcard = { workspace = true, optional = true }
 gimli = { workspace = true, features = ["write"], optional = true }
 smallvec = { workspace = true }
 regalloc2 = { workspace = true, features = ["checker", "trace-log"] }
@@ -100,7 +100,7 @@ enable-serde = [
 # Enable the incremental compilation cache for hot-reload use cases.
 incremental-cache = [
     "enable-serde",
-    "bincode",
+    "postcard",
     "sha2"
 ]
 
diff --git a/cranelift/codegen/src/incremental_cache.rs b/cranelift/codegen/src/incremental_cache.rs
index 6290e55f8..bf5f6215e 100644
--- a/cranelift/codegen/src/incremental_cache.rs
+++ b/cranelift/codegen/src/incremental_cache.rs
@@ -208,12 +208,12 @@ pub fn compute_cache_key(isa: &dyn TargetIsa, func: &Function) -> CacheKeyHash {
 /// of the function call. The value is left untouched.
 pub fn serialize_compiled(
     result: CompiledCodeStencil,
-) -> (CompiledCodeStencil, Result<Vec<u8>, bincode::Error>) {
+) -> (CompiledCodeStencil, Result<Vec<u8>, postcard::Error>) {
     let cached = CachedFunc {
         version_marker: VersionMarker,
         stencil: result,
     };
-    let result = bincode::serialize(&cached);
+    let result = postcard::to_allocvec(&cached);
     (cached.stencil, result)
 }
 
@@ -223,7 +223,7 @@ pub enum RecompileError {
     /// The version embedded in the cache entry isn't the same as cranelift's current version.
     VersionMismatch,
     /// An error occurred while deserializing the cache entry.
-    Deserialize(bincode::Error),
+    Deserialize(postcard::Error),
 }
 
 impl fmt::Display for RecompileError {
@@ -231,7 +231,7 @@ impl fmt::Display for RecompileError {
         match self {
             RecompileError::VersionMismatch => write!(f, "cranelift version mismatch",),
             RecompileError::Deserialize(err) => {
-                write!(f, "bincode failed during deserialization: {err}")
+                write!(f, "postcard failed during deserialization: {err}")
             }
         }
     }
@@ -243,7 +243,7 @@ impl fmt::Display for RecompileError {
 /// Precondition: the bytes must have retrieved from a cache store entry which hash value
 /// is strictly the same as the `Function`'s computed hash retrieved from `compute_cache_key`.
 pub fn try_finish_recompile(func: &Function, bytes: &[u8]) -> Result<CompiledCode, RecompileError> {
-    match bincode::deserialize::<CachedFunc>(bytes) {
+    match postcard::from_bytes::<CachedFunc>(bytes) {
         Ok(result) => {
             if result.version_marker != func.stencil.version_marker {
                 Err(RecompileError::VersionMismatch)
diff --git a/cranelift/codegen/src/machinst/abi.rs b/cranelift/codegen/src/machinst/abi.rs
index a413ae98e..a5de3824d 100644
--- a/cranelift/codegen/src/machinst/abi.rs
+++ b/cranelift/codegen/src/machinst/abi.rs
@@ -1097,9 +1097,7 @@ pub struct Callee<M: ABIMachineSpec> {
     /// Finalized frame layout for this function.
     frame_layout: Option<FrameLayout>,
     /// The register holding the return-area pointer, if needed.
-    ret_area_ptr: Option<Writable<Reg>>,
-    /// Temp registers required for argument setup, if needed.
-    arg_temp_reg: Vec<Option<Writable<Reg>>>,
+    ret_area_ptr: Option<Reg>,
     /// Calling convention this function expects.
     call_conv: isa::CallConv,
     /// The settings controlling this function's compilation.
@@ -1241,7 +1239,6 @@ impl<M: ABIMachineSpec> Callee<M> {
             reg_args: vec![],
             frame_layout: None,
             ret_area_ptr: None,
-            arg_temp_reg: vec![],
             call_conv,
             flags,
             isa_flags: isa_flags.clone(),
@@ -1406,45 +1403,19 @@ impl<M: ABIMachineSpec> Callee<M> {
         &self.ir_sig
     }
 
-    /// Does the ABI-body code need temp registers (and if so, of what type)?
-    /// They will be provided to `init()` as the `temps` arg if so.
-    pub fn temps_needed(&self, sigs: &SigSet) -> Vec<Type> {
-        let mut temp_tys = vec![];
-        for arg in sigs.args(self.sig) {
-            match arg {
-                &ABIArg::ImplicitPtrArg { pointer, .. } => match &pointer {
-                    &ABIArgSlot::Reg { .. } => {}
-                    &ABIArgSlot::Stack { ty, .. } => {
-                        temp_tys.push(ty);
-                    }
-                },
-                _ => {}
-            }
-        }
-        if sigs[self.sig].stack_ret_arg.is_some() {
-            temp_tys.push(M::word_type());
-        }
-        temp_tys
-    }
-
     /// Initialize. This is called after the Callee is constructed because it
-    /// may be provided with a vector of temp vregs, which can only be allocated
-    /// once the lowering context exists.
-    pub fn init(&mut self, sigs: &SigSet, temps: Vec<Writable<Reg>>) {
-        let mut temps_iter = temps.into_iter();
-        for arg in sigs.args(self.sig) {
-            let temp = match arg {
-                &ABIArg::ImplicitPtrArg { pointer, .. } => match &pointer {
-                    &ABIArgSlot::Reg { .. } => None,
-                    &ABIArgSlot::Stack { .. } => Some(temps_iter.next().unwrap()),
-                },
-                _ => None,
-            };
-            self.arg_temp_reg.push(temp);
-        }
+    /// may allocate a temp vreg, which can only be allocated once the lowering
+    /// context exists.
+    pub fn init_retval_area(
+        &mut self,
+        sigs: &SigSet,
+        vregs: &mut VRegAllocator<M::I>,
+    ) -> CodegenResult<()> {
         if sigs[self.sig].stack_ret_arg.is_some() {
-            self.ret_area_ptr = Some(temps_iter.next().unwrap());
+            let ret_area_ptr = vregs.alloc(M::word_type())?;
+            self.ret_area_ptr = Some(ret_area_ptr.only_reg().unwrap());
         }
+        Ok(())
     }
 
     /// Accumulate outgoing arguments.
@@ -1574,9 +1545,9 @@ impl<M: ABIMachineSpec> Callee<M> {
                         tmp
                     }
                     &ABIArgSlot::Stack { offset, ty, .. } => {
-                        // In this case we need a temp register to hold the address.
-                        // This was allocated in the `init` routine.
-                        let addr_reg = self.arg_temp_reg[idx].unwrap();
+                        let addr_reg = writable_value_regs(vregs.alloc_with_deferred_error(ty))
+                            .only_reg()
+                            .unwrap();
                         insts.push(M::gen_load_stack(
                             StackAMode::IncomingArg(offset, sigs[self.sig].sized_stack_arg_space),
                             addr_reg,
@@ -1676,7 +1647,7 @@ impl<M: ABIMachineSpec> Callee<M> {
                                 _ => {}
                             };
                             ret.push(M::gen_store_base_offset(
-                                self.ret_area_ptr.unwrap().to_reg(),
+                                self.ret_area_ptr.unwrap(),
                                 off,
                                 from_reg,
                                 ty,
@@ -1706,17 +1677,14 @@ impl<M: ABIMachineSpec> Callee<M> {
         vregs: &mut VRegAllocator<M::I>,
     ) -> Option<M::I> {
         if let Some(i) = sigs[self.sig].stack_ret_arg {
-            let insts = self.gen_copy_arg_to_regs(
-                sigs,
-                i.into(),
-                ValueRegs::one(self.ret_area_ptr.unwrap()),
-                vregs,
-            );
+            let ret_area_ptr = Writable::from_reg(self.ret_area_ptr.unwrap());
+            let insts =
+                self.gen_copy_arg_to_regs(sigs, i.into(), ValueRegs::one(ret_area_ptr), vregs);
             insts.into_iter().next().map(|inst| {
                 trace!(
                     "gen_retval_area_setup: inst {:?}; ptr reg is {:?}",
                     inst,
-                    self.ret_area_ptr.unwrap().to_reg()
+                    ret_area_ptr.to_reg()
                 );
                 inst
             })
@@ -2390,7 +2358,7 @@ impl<M: ABIMachineSpec> CallSite<M> {
                 "if the tail callee has a return pointer, then the tail caller \
                  must as well",
             );
-            self.gen_arg(ctx, i.into(), ValueRegs::one(ret_area_ptr.to_reg()));
+            self.gen_arg(ctx, i.into(), ValueRegs::one(ret_area_ptr));
         }
     }
 
diff --git a/cranelift/codegen/src/machinst/lower.rs b/cranelift/codegen/src/machinst/lower.rs
index a6b3bc501..cbd0491fc 100644
--- a/cranelift/codegen/src/machinst/lower.rs
+++ b/cranelift/codegen/src/machinst/lower.rs
@@ -1019,15 +1019,7 @@ impl<'func, I: VCodeInst> Lower<'func, I> {
     ) -> CodegenResult<VCode<I>> {
         trace!("about to lower function: {:?}", self.f);
 
-        // Initialize the ABI object, giving it temps if requested.
-        let temps = self
-            .vcode
-            .abi()
-            .temps_needed(self.sigs())
-            .into_iter()
-            .map(|temp_ty| self.alloc_tmp(temp_ty).only_reg().unwrap())
-            .collect::<Vec<_>>();
-        self.vcode.init_abi(temps);
+        self.vcode.init_retval_area(&mut self.vregs)?;
 
         // Get the pinned reg here (we only parameterize this function on `B`,
         // not the whole `Lower` impl).
diff --git a/cranelift/codegen/src/machinst/vcode.rs b/cranelift/codegen/src/machinst/vcode.rs
index 05f95d6f5..39010b9da 100644
--- a/cranelift/codegen/src/machinst/vcode.rs
+++ b/cranelift/codegen/src/machinst/vcode.rs
@@ -291,8 +291,8 @@ impl<I: VCodeInst> VCodeBuilder<I> {
         }
     }
 
-    pub fn init_abi(&mut self, temps: Vec<Writable<Reg>>) {
-        self.vcode.abi.init(&self.vcode.sigs, temps);
+    pub fn init_retval_area(&mut self, vregs: &mut VRegAllocator<I>) -> CodegenResult<()> {
+        self.vcode.abi.init_retval_area(&self.vcode.sigs, vregs)
     }
 
     /// Access the ABI object.
diff --git a/crates/cache/Cargo.toml b/crates/cache/Cargo.toml
index 475f3828e..481f54641 100644
--- a/crates/cache/Cargo.toml
+++ b/crates/cache/Cargo.toml
@@ -14,7 +14,7 @@ workspace = true
 [dependencies]
 anyhow = { workspace = true }
 base64 = "0.21.0"
-bincode = { workspace = true }
+postcard = { workspace = true }
 directories-next = "2.0"
 log = { workspace = true }
 serde = { workspace = true }
diff --git a/crates/cache/src/lib.rs b/crates/cache/src/lib.rs
index 279831259..aabaded44 100644
--- a/crates/cache/src/lib.rs
+++ b/crates/cache/src/lib.rs
@@ -54,8 +54,8 @@ impl<'config> ModuleCacheEntry<'config> {
         self.get_data_raw(
             &state,
             compute,
-            |_state, data| bincode::serialize(data).ok(),
-            |_state, data| bincode::deserialize(&data).ok(),
+            |_state, data| postcard::to_allocvec(data).ok(),
+            |_state, data| postcard::from_bytes(&data).ok(),
         )
     }
 
diff --git a/crates/environ/Cargo.toml b/crates/environ/Cargo.toml
index bcf072581..2a6e1abf6 100644
--- a/crates/environ/Cargo.toml
+++ b/crates/environ/Cargo.toml
@@ -15,7 +15,7 @@ workspace = true
 
 [dependencies]
 anyhow = { workspace = true }
-bincode = { workspace = true }
+postcard = { workspace = true }
 cpp_demangle = { version = "0.4.3", optional = true }
 cranelift-entity = { workspace = true }
 wasmtime-types = { workspace = true }
diff --git a/crates/environ/src/compile/module_artifacts.rs b/crates/environ/src/compile/module_artifacts.rs
index 68f19e377..79b6f4c77 100644
--- a/crates/environ/src/compile/module_artifacts.rs
+++ b/crates/environ/src/compile/module_artifacts.rs
@@ -1,5 +1,5 @@
 //! Definitions of runtime structures and metadata which are serialized into ELF
-//! with `bincode` as part of a module's compilation process.
+//! with `postcard` as part of a module's compilation process.
 
 use crate::{
     obj, CompiledFunctionInfo, CompiledModuleInfo, DebugInfoData, DefinedFuncIndex, FunctionLoc,
@@ -261,7 +261,7 @@ impl<'a> ObjectBuilder<'a> {
             obj::ELF_WASMTIME_INFO.as_bytes().to_vec(),
             SectionKind::ReadOnlyData,
         );
-        let data = bincode::serialize(info).unwrap();
+        let data = postcard::to_allocvec(info).unwrap();
         self.obj.set_section_data(section, data, 1);
     }
 
diff --git a/crates/wasmtime/Cargo.toml b/crates/wasmtime/Cargo.toml
index 07e72b0fa..fccd5ba11 100644
--- a/crates/wasmtime/Cargo.toml
+++ b/crates/wasmtime/Cargo.toml
@@ -44,7 +44,7 @@ wat = { workspace = true, optional = true }
 serde = { workspace = true }
 serde_derive = { workspace = true }
 serde_json = { workspace = true }
-bincode = { workspace = true }
+postcard = { workspace = true }
 indexmap = { workspace = true }
 paste = "1.0.3"
 once_cell = { workspace = true }
diff --git a/crates/wasmtime/src/engine/serialization.rs b/crates/wasmtime/src/engine/serialization.rs
index d6254cdff..4aca40bc1 100644
--- a/crates/wasmtime/src/engine/serialization.rs
+++ b/crates/wasmtime/src/engine/serialization.rs
@@ -15,7 +15,7 @@
 //! 1. A version byte, currently `VERSION`.
 //! 2. A byte indicating how long the next field is.
 //! 3. A version string of the length of the previous byte value.
-//! 4. A `bincode`-encoded `Metadata` structure.
+//! 4. A `postcard`-encoded `Metadata` structure.
 //!
 //! This is hoped to help distinguish easily Wasmtime-based ELF files from
 //! other random ELF files, as well as provide better error messages for
@@ -110,7 +110,7 @@ pub fn check_compatible(engine: &Engine, mmap: &[u8], expected: ObjectKind) -> R
         }
         ModuleVersionStrategy::None => { /* ignore the version info, accept all */ }
     }
-    bincode::deserialize::<Metadata<'_>>(data)?.check_compatible(engine)
+    postcard::from_bytes::<Metadata<'_>>(data)?.check_compatible(engine)
 }
 
 #[cfg(any(feature = "cranelift", feature = "winch"))]
@@ -134,7 +134,7 @@ pub fn append_compiler_info(engine: &Engine, obj: &mut Object<'_>, metadata: &Me
     );
     data.push(version.len() as u8);
     data.extend_from_slice(version.as_bytes());
-    bincode::serialize_into(&mut data, metadata).unwrap();
+    data.extend(postcard::to_allocvec(metadata).unwrap());
     obj.set_section_data(section, data, 1);
 }
 
diff --git a/crates/wasmtime/src/runtime/component/component.rs b/crates/wasmtime/src/runtime/component/component.rs
index 4e263ba3f..09908b6b4 100644
--- a/crates/wasmtime/src/runtime/component/component.rs
+++ b/crates/wasmtime/src/runtime/component/component.rs
@@ -375,7 +375,7 @@ impl Component {
             static_modules,
         } = match artifacts {
             Some(artifacts) => artifacts,
-            None => bincode::deserialize(code_memory.wasmtime_info())?,
+            None => postcard::from_bytes(code_memory.wasmtime_info())?,
         };
 
         // Validate that the component can be used with the current instance
diff --git a/crates/wasmtime/src/runtime/module.rs b/crates/wasmtime/src/runtime/module.rs
index 04ecc47f1..42906a361 100644
--- a/crates/wasmtime/src/runtime/module.rs
+++ b/crates/wasmtime/src/runtime/module.rs
@@ -445,7 +445,7 @@ impl Module {
         // already.
         let (info, types) = match info_and_types {
             Some((info, types)) => (info, types),
-            None => bincode::deserialize(code_memory.wasmtime_info())?,
+            None => postcard::from_bytes(code_memory.wasmtime_info())?,
         };
 
         // Register function type signatures into the engine for the lifetime
diff --git a/supply-chain/audits.toml b/supply-chain/audits.toml
index 0c5195ca7..21ffd2869 100644
--- a/supply-chain/audits.toml
+++ b/supply-chain/audits.toml
@@ -1062,6 +1062,12 @@ who = "Pat Hickey <phickey@fastly.com>"
 criteria = "safe-to-deploy"
 version = "0.2.0"
 
+[[audits.cobs]]
+who = "Alex Crichton <alex@alexcrichton.com>"
+criteria = "safe-to-deploy"
+version = "0.2.3"
+notes = "No `unsafe` code in the crate and no usage of `std`"
+
 [[audits.codespan-reporting]]
 who = "Jamey Sharp <jsharp@fastly.com>"
 criteria = "safe-to-deploy"
@@ -1197,6 +1203,12 @@ This diff brings in a number of minor updates of which none are related to
 `unsafe` code or anything system-related like filesystems.
 """
 
+[[audits.embedded-io]]
+who = "Alex Crichton <alex@alexcrichton.com>"
+criteria = "safe-to-deploy"
+version = "0.4.0"
+notes = "No `unsafe` code and only uses `std` in ways one would expect the crate to do so."
+
 [[audits.errno]]
 who = "Dan Gohman <dev@sunfishcode.online>"
 criteria = "safe-to-deploy"
@@ -2007,6 +2019,15 @@ No `unsafe` additions or anything outside of the purview of the crate in this
 change.
 """
 
+[[audits.postcard]]
+who = "Alex Crichton <alex@alexcrichton.com>"
+criteria = "safe-to-deploy"
+version = "1.0.8"
+notes = """
+I've audited the unsafe code to do what it looks like it's doing. Otherwise the
+crate is a standard serializer/deserializer crate.
+"""
+
 [[audits.pretty_env_logger]]
 who = "Alex Crichton <alex@alexcrichton.com>"
 criteria = "safe-to-deploy"


Test patch:
diff --git a/cranelift/filetests/filetests/isa/s390x/call.clif b/cranelift/filetests/filetests/isa/s390x/call.clif
index 1d72253b1..41bf58ea7 100644
--- a/cranelift/filetests/filetests/isa/s390x/call.clif
+++ b/cranelift/filetests/filetests/isa/s390x/call.clif
@@ -332,14 +332,14 @@ block0(v0: i128, v1: i128, v2: i128, v3: i128, v4: i128, v5: i128, v6: i128, v7:
 ;   vl %v24, 0(%r5)
 ;   lg %r4, 184(%r15)
 ;   vl %v27, 0(%r4)
-;   vaq %v16, %v1, %v3
-;   vaq %v17, %v5, %v7
-;   vaq %v18, %v18, %v21
-;   vaq %v19, %v24, %v27
-;   vaq %v16, %v16, %v17
-;   vaq %v17, %v18, %v19
-;   vaq %v16, %v16, %v17
-;   vst %v16, 0(%r2)
+;   vaq %v4, %v1, %v3
+;   vaq %v5, %v5, %v7
+;   vaq %v6, %v18, %v21
+;   vaq %v7, %v24, %v27
+;   vaq %v4, %v4, %v5
+;   vaq %v5, %v6, %v7
+;   vaq %v4, %v4, %v5
+;   vst %v4, 0(%r2)
 ;   br %r14
 ;
 ; Disassembled:
@@ -356,14 +356,14 @@ block0(v0: i128, v1: i128, v2: i128, v3: i128, v4: i128, v5: i128, v6: i128, v7:
 ;   vl %v24, 0(%r5)
 ;   lg %r4, 0xb8(%r15)
 ;   vl %v27, 0(%r4)
-;   vaq %v16, %v1, %v3
-;   vaq %v17, %v5, %v7
-;   vaq %v18, %v18, %v21
-;   vaq %v19, %v24, %v27
-;   vaq %v16, %v16, %v17
-;   vaq %v17, %v18, %v19
-;   vaq %v16, %v16, %v17
-;   vst %v16, 0(%r2)
+;   vaq %v4, %v1, %v3
+;   vaq %v5, %v5, %v7
+;   vaq %v6, %v18, %v21
+;   vaq %v7, %v24, %v27
+;   vaq %v4, %v4, %v5
+;   vaq %v5, %v6, %v7
+;   vaq %v4, %v4, %v5
+;   vst %v4, 0(%r2)
 ;   br %r14
 
 function %call_sret() -> i64 {