Repository: bytecodealliance/wasmtime
Pull request #8701 (2024-05-28 19:56:05)

riscv64: Special-case `f32const 0` and `f64const 0`
This commit is inspired by discussion on #8695 which made me remember the discussion around #7162 historically. In lieu of a deeper fix for the issue of "why can't `iconst 0` use `(zero_reg)`" it's still possible to add special-cases to rules throughout the backend so this commit does that for generating zero-value floats.

<!--
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
-->


alexcrichton: > Received request to deprovision: The request was cancelled by the remote provider.

After 4 times in a row I'm going to deprovision myself for tonight.

Patch:
diff --git a/Cargo.lock b/Cargo.lock
index 77bb402f2..9d23f7c15 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -853,7 +853,7 @@ dependencies = [
  "serde_derive",
  "smallvec",
  "target-lexicon",
- "wasmparser",
+ "wasmparser 0.209.1",
  "wasmtime-types",
  "wat",
 ]
@@ -2763,7 +2763,7 @@ dependencies = [
  "cargo_metadata",
  "heck 0.4.0",
  "wasmtime",
- "wit-component",
+ "wit-component 0.209.1",
 ]
 
 [[package]]
@@ -3093,7 +3093,7 @@ name = "verify-component-adapter"
 version = "22.0.0"
 dependencies = [
  "anyhow",
- "wasmparser",
+ "wasmparser 0.209.1",
  "wat",
 ]
 
@@ -3186,7 +3186,7 @@ dependencies = [
  "byte-array-literals",
  "object 0.33.0",
  "wasi",
- "wasm-encoder",
+ "wasm-encoder 0.209.1",
  "wit-bindgen-rust-macro",
 ]
 
@@ -3253,6 +3253,15 @@ dependencies = [
  "leb128",
 ]
 
+[[package]]
+name = "wasm-encoder"
+version = "0.209.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7b4a05336882dae732ce6bd48b7e11fe597293cb72c13da4f35d7d5f8d53b2a7"
+dependencies = [
+ "leb128",
+]
+
 [[package]]
 name = "wasm-metadata"
 version = "0.208.1"
@@ -3265,36 +3274,52 @@ dependencies = [
  "serde_derive",
  "serde_json",
  "spdx",
- "wasm-encoder",
- "wasmparser",
+ "wasm-encoder 0.208.1",
+ "wasmparser 0.208.1",
+]
+
+[[package]]
+name = "wasm-metadata"
+version = "0.209.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4d32029ce424f6d3c2b39b4419fb45a0e2d84fb0751e0c0a32b7ce8bd5d97f46"
+dependencies = [
+ "anyhow",
+ "indexmap 2.2.6",
+ "serde",
+ "serde_derive",
+ "serde_json",
+ "spdx",
+ "wasm-encoder 0.209.1",
+ "wasmparser 0.209.1",
 ]
 
 [[package]]
 name = "wasm-mutate"
-version = "0.208.1"
+version = "0.209.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d279475f0f5e68af5ad6eebf0377f777cadcd0c15208f64121522e44dbe45ec9"
+checksum = "f58dddabebff47e1a4f22fbe7fbb769ab699cd9efe7552f50ce5d0881f006884"
 dependencies = [
  "egg",
  "log",
  "rand",
  "thiserror",
- "wasm-encoder",
- "wasmparser",
+ "wasm-encoder 0.209.1",
+ "wasmparser 0.209.1",
 ]
 
 [[package]]
 name = "wasm-smith"
-version = "0.208.1"
+version = "0.209.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8c94a8e7d3a1c3b34ad60d41421c857105aac67e00ae9854247a4a668694f6e9"
+checksum = "38482bb6ce309f7b5b8a168209d0e5c1df8643f1026fc21aaa196058f16d42e8"
 dependencies = [
  "anyhow",
  "arbitrary",
  "flagset",
  "indexmap 2.2.6",
  "leb128",
- "wasm-encoder",
+ "wasm-encoder 0.209.1",
 ]
 
 [[package]]
@@ -3342,6 +3367,19 @@ name = "wasmparser"
 version = "0.208.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "dd921789c9dcc495f589cb37d200155dee65b4a4beeb853323b5e24e0a5f9c58"
+dependencies = [
+ "ahash",
+ "bitflags 2.4.1",
+ "hashbrown 0.14.3",
+ "indexmap 2.2.6",
+ "semver",
+]
+
+[[package]]
+name = "wasmparser"
+version = "0.209.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "07035cc9a9b41e62d3bb3a3815a66ab87c993c06fe1cf6b2a3f2a18499d937db"
 dependencies = [
  "ahash",
  "bitflags 2.4.1",
@@ -3362,12 +3400,12 @@ dependencies = [
 
 [[package]]
 name = "wasmprinter"
-version = "0.208.1"
+version = "0.209.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0700bdace4821e6c694617938500ae9999946df464bb13219c16570f8b6f202f"
+checksum = "ceca8ae6eaa8c7c87b33c25c53bdf299f8c2a764aee1179402ff7652ef3a6859"
 dependencies = [
  "anyhow",
- "wasmparser",
+ "wasmparser 0.209.1",
 ]
 
 [[package]]
@@ -3410,8 +3448,8 @@ dependencies = [
  "target-lexicon",
  "tempfile",
  "wasi-common",
- "wasm-encoder",
- "wasmparser",
+ "wasm-encoder 0.209.1",
+ "wasmparser 0.209.1",
  "wasmtime-asm-macros",
  "wasmtime-cache",
  "wasmtime-component-macro",
@@ -3553,7 +3591,7 @@ dependencies = [
  "tracing",
  "walkdir",
  "wasi-common",
- "wasmparser",
+ "wasmparser 0.209.1",
  "wasmtime",
  "wasmtime-cache",
  "wasmtime-cli-flags",
@@ -3567,10 +3605,10 @@ dependencies = [
  "wasmtime-wasi-nn",
  "wasmtime-wasi-threads",
  "wasmtime-wast",
- "wast 208.0.1",
+ "wast 209.0.1",
  "wat",
  "windows-sys 0.52.0",
- "wit-component",
+ "wit-component 0.209.1",
 ]
 
 [[package]]
@@ -3603,7 +3641,7 @@ dependencies = [
  "wasmtime",
  "wasmtime-component-util",
  "wasmtime-wit-bindgen",
- "wit-parser",
+ "wit-parser 0.209.1",
 ]
 
 [[package]]
@@ -3627,7 +3665,7 @@ dependencies = [
  "object 0.33.0",
  "target-lexicon",
  "thiserror",
- "wasmparser",
+ "wasmparser 0.209.1",
  "wasmtime-environ",
  "wasmtime-versioned-export-macros",
 ]
@@ -3650,8 +3688,8 @@ dependencies = [
  "serde",
  "serde_derive",
  "target-lexicon",
- "wasm-encoder",
- "wasmparser",
+ "wasm-encoder 0.209.1",
+ "wasmparser 0.209.1",
  "wasmprinter",
  "wasmtime-component-util",
  "wasmtime-types",
@@ -3666,7 +3704,7 @@ dependencies = [
  "component-fuzz-util",
  "env_logger",
  "libfuzzer-sys",
- "wasmparser",
+ "wasmparser 0.209.1",
  "wasmprinter",
  "wasmtime-environ",
  "wat",
@@ -3724,7 +3762,7 @@ dependencies = [
  "rand",
  "smallvec",
  "target-lexicon",
- "wasmparser",
+ "wasmparser 0.209.1",
  "wasmtime",
  "wasmtime-fuzzing",
 ]
@@ -3745,12 +3783,12 @@ dependencies = [
  "target-lexicon",
  "tempfile",
  "v8",
- "wasm-encoder",
+ "wasm-encoder 0.209.1",
  "wasm-mutate",
  "wasm-smith",
  "wasm-spec-interpreter",
  "wasmi",
- "wasmparser",
+ "wasmparser 0.209.1",
  "wasmprinter",
  "wasmtime",
  "wasmtime-wast",
@@ -3799,7 +3837,7 @@ dependencies = [
  "serde",
  "serde_derive",
  "smallvec",
- "wasmparser",
+ "wasmparser 0.209.1",
 ]
 
 [[package]]
@@ -3906,7 +3944,7 @@ dependencies = [
  "anyhow",
  "log",
  "wasmtime",
- "wast 208.0.1",
+ "wast 209.0.1",
 ]
 
 [[package]]
@@ -3918,7 +3956,7 @@ dependencies = [
  "gimli",
  "object 0.33.0",
  "target-lexicon",
- "wasmparser",
+ "wasmparser 0.209.1",
  "wasmtime-cranelift",
  "wasmtime-environ",
  "winch-codegen",
@@ -3931,7 +3969,7 @@ dependencies = [
  "anyhow",
  "heck 0.4.0",
  "indexmap 2.2.6",
- "wit-parser",
+ "wit-parser 0.209.1",
 ]
 
 [[package]]
@@ -3949,24 +3987,24 @@ dependencies = [
 
 [[package]]
 name = "wast"
-version = "208.0.1"
+version = "209.0.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bc00b3f023b4e2ccd2e054e240294263db52ae962892e6523e550783c83a67f1"
+checksum = "8fffef2ff6147e4d12e972765fd75332c6a11c722571d4ab7a780d81ffc8f0a4"
 dependencies = [
  "bumpalo",
  "leb128",
  "memchr",
  "unicode-width",
- "wasm-encoder",
+ "wasm-encoder 0.209.1",
 ]
 
 [[package]]
 name = "wat"
-version = "1.208.1"
+version = "1.209.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "58ed38e59176550214c025ea2bd0eeefd8e86b92d0af6698d5ba95020ec2e07b"
+checksum = "42203ec0271d113f8eb1f77ebc624886530cecb35915a7f63a497131f16e4d24"
 dependencies = [
- "wast 208.0.1",
+ "wast 209.0.1",
 ]
 
 [[package]]
@@ -4086,7 +4124,7 @@ dependencies = [
  "regalloc2",
  "smallvec",
  "target-lexicon",
- "wasmparser",
+ "wasmparser 0.209.1",
  "wasmtime-cranelift",
  "wasmtime-environ",
 ]
@@ -4279,7 +4317,7 @@ checksum = "7076a12e69af6e1f6093bd16657d7ae61c30cfd3c5f62321046eb863b17ab1e2"
 dependencies = [
  "anyhow",
  "heck 0.5.0",
- "wit-parser",
+ "wit-parser 0.208.1",
 ]
 
 [[package]]
@@ -4300,9 +4338,9 @@ dependencies = [
  "anyhow",
  "heck 0.5.0",
  "indexmap 2.2.6",
- "wasm-metadata",
+ "wasm-metadata 0.208.1",
  "wit-bindgen-core",
- "wit-component",
+ "wit-component 0.208.1",
 ]
 
 [[package]]
@@ -4332,10 +4370,29 @@ dependencies = [
  "serde",
  "serde_derive",
  "serde_json",
- "wasm-encoder",
- "wasm-metadata",
- "wasmparser",
- "wit-parser",
+ "wasm-encoder 0.208.1",
+ "wasm-metadata 0.208.1",
+ "wasmparser 0.208.1",
+ "wit-parser 0.208.1",
+]
+
+[[package]]
+name = "wit-component"
+version = "0.209.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "25a2bb5b039f9cb03425e1d5a6e54b441ca4ca1b1d4fa6a0924db67a55168f99"
+dependencies = [
+ "anyhow",
+ "bitflags 2.4.1",
+ "indexmap 2.2.6",
+ "log",
+ "serde",
+ "serde_derive",
+ "serde_json",
+ "wasm-encoder 0.209.1",
+ "wasm-metadata 0.209.1",
+ "wasmparser 0.209.1",
+ "wit-parser 0.209.1",
 ]
 
 [[package]]
@@ -4353,7 +4410,25 @@ dependencies = [
  "serde_derive",
  "serde_json",
  "unicode-xid",
- "wasmparser",
+ "wasmparser 0.208.1",
+]
+
+[[package]]
+name = "wit-parser"
+version = "0.209.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3e79b9e3c0b6bb589dec46317e645851e0db2734c44e2be5e251b03ff4a51269"
+dependencies = [
+ "anyhow",
+ "id-arena",
+ "indexmap 2.2.6",
+ "log",
+ "semver",
+ "serde",
+ "serde_derive",
+ "serde_json",
+ "unicode-xid",
+ "wasmparser 0.209.1",
 ]
 
 [[package]]
diff --git a/Cargo.toml b/Cargo.toml
index 4457503d8..ef48f5fc0 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -166,6 +166,7 @@ unused_extern_crates = 'warn'
 trivial_numeric_casts = 'warn'
 unstable_features = 'warn'
 unused_import_braces = 'warn'
+unused-lifetimes = 'warn'
 
 [workspace.lints.clippy]
 # The default set of lints in Clippy is viewed as "too noisy" right now so
@@ -251,15 +252,15 @@ wit-bindgen = { version = "0.25.0", default-features = false }
 wit-bindgen-rust-macro = { version = "0.25.0", default-features = false }
 
 # wasm-tools family:
-wasmparser = { version = "0.208.1", default-features = false }
-wat = "1.208.1"
-wast = "208.0.1"
-wasmprinter = "0.208.1"
-wasm-encoder = "0.208.1"
-wasm-smith = "0.208.1"
-wasm-mutate = "0.208.1"
-wit-parser = "0.208.1"
-wit-component = "0.208.1"
+wasmparser = { version = "0.209.1", default-features = false }
+wat = "1.209.1"
+wast = "209.0.1"
+wasmprinter = "0.209.1"
+wasm-encoder = "0.209.1"
+wasm-smith = "0.209.1"
+wasm-mutate = "0.209.1"
+wit-parser = "0.209.1"
+wit-component = "0.209.1"
 
 # Non-Bytecode Alliance maintained dependencies:
 # --------------------------
diff --git a/benches/instantiation.rs b/benches/instantiation.rs
index b1d5e9c91..938159985 100644
--- a/benches/instantiation.rs
+++ b/benches/instantiation.rs
@@ -20,7 +20,7 @@ fn instantiate(pre: &InstancePre<WasiCtx>, engine: &Engine) -> Result<()> {
     Ok(())
 }
 
-fn benchmark_name<'a>(strategy: &InstanceAllocationStrategy) -> &'static str {
+fn benchmark_name(strategy: &InstanceAllocationStrategy) -> &'static str {
     match strategy {
         InstanceAllocationStrategy::OnDemand => "default",
         InstanceAllocationStrategy::Pooling { .. } => "pooling",
diff --git a/cranelift/codegen/meta/src/isa/riscv64.rs b/cranelift/codegen/meta/src/isa/riscv64.rs
index 7c1caff9b..d11fbf951 100644
--- a/cranelift/codegen/meta/src/isa/riscv64.rs
+++ b/cranelift/codegen/meta/src/isa/riscv64.rs
@@ -126,6 +126,12 @@ pub(crate) fn define() -> TargetIsa {
         "Zbs: Single-bit instructions",
         false,
     );
+    let _has_zicond = setting.add_bool(
+        "has_zicond",
+        "has extension zicond?",
+        "ZiCond: Integer Conditional Operations",
+        false,
+    );
 
     let has_zicsr = setting.add_bool(
         "has_zicsr",
diff --git a/cranelift/codegen/src/isa/riscv64/inst.isle b/cranelift/codegen/src/isa/riscv64/inst.isle
index 4866ed774..2fed117c9 100644
--- a/cranelift/codegen/src/isa/riscv64/inst.isle
+++ b/cranelift/codegen/src/isa/riscv64/inst.isle
@@ -553,6 +553,10 @@
   (Pack)
   (Packw)
   (Packh)
+
+  ;; ZiCond: Integer Conditional Operations
+  (CzeroEqz)
+  (CzeroNez)
 ))
 
 
@@ -1047,6 +1051,9 @@
 (decl pure has_zbs () bool)
 (extern constructor has_zbs has_zbs)
 
+(decl pure has_zicond () bool)
+(extern constructor has_zicond has_zicond)
+
 
 ;;;; Instruction Helpers ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 
@@ -1783,6 +1790,26 @@
 (rule (rv_packw rs1 rs2)
   (alu_rrr (AluOPRRR.Packw) rs1 rs2))
 
+;; `ZiCond` Extension Instructions
+
+;; Helper for emitting the `czero.eqz` ("Conditional zero, if condition is equal to zero") instruction.
+;; RS1 is the data source
+;; RS2 is the condition
+;;
+;; rd = (rs2 == 0) ? 0 : rs1
+(decl rv_czero_eqz (XReg XReg) XReg)
+(rule (rv_czero_eqz rs1 rs2)
+  (alu_rrr (AluOPRRR.CzeroEqz) rs1 rs2))
+
+;; Helper for emitting the `czero.nez` ("Conditional zero, if condition is nonzero") instruction.
+;; RS1 is the data source
+;; RS2 is the condition
+;;
+;; rd = (rs2 != 0) ? 0 : rs1
+(decl rv_czero_nez (XReg XReg) XReg)
+(rule (rv_czero_nez rs1 rs2)
+  (alu_rrr (AluOPRRR.CzeroNez) rs1 rs2))
+
 
 ;; `Zicsr` Extension Instructions
 
@@ -1836,6 +1863,11 @@
 ;; TODO: Load floats using `fld` instead of `ld`
 (decl imm (Type u64) Reg)
 
+;; Special-case 0.0 for floats to use the `(zero_reg)` directly.
+;; See #7162 for why this doesn't fall out of the rules below.
+(rule 8 (imm $F32 0) (gen_bitcast (zero_reg) $I32 $F32))
+(rule 8 (imm $F64 0) (gen_bitcast (zero_reg) $I64 $F64))
+
 ;; If Zfa is enabled, we can load certain constants with the `fli` instruction.
 (rule 7 (imm (ty_scalar_float ty) imm)
   (if-let $true (has_zfa))
@@ -2560,26 +2592,68 @@
 
 (decl gen_select_xreg (IntegerCompare XReg XReg) XReg)
 
-(rule 1 (gen_select_xreg (int_compare_decompose cc x y) x y)
+(rule 6 (gen_select_xreg (int_compare_decompose cc x y) x y)
   (if-let (IntCC.UnsignedLessThan) (intcc_without_eq cc))
   (if-let $true (has_zbb))
   (rv_minu x y))
 
-(rule 1 (gen_select_xreg (int_compare_decompose cc x y) x y)
+(rule 6 (gen_select_xreg (int_compare_decompose cc x y) x y)
   (if-let (IntCC.SignedLessThan) (intcc_without_eq cc))
   (if-let $true (has_zbb))
   (rv_min x y))
 
-(rule 1 (gen_select_xreg (int_compare_decompose cc x y) x y)
+(rule 6 (gen_select_xreg (int_compare_decompose cc x y) x y)
   (if-let (IntCC.UnsignedGreaterThan) (intcc_without_eq cc))
   (if-let $true (has_zbb))
   (rv_maxu x y))
 
-(rule 1 (gen_select_xreg (int_compare_decompose cc x y) x y)
+(rule 6 (gen_select_xreg (int_compare_decompose cc x y) x y)
   (if-let (IntCC.SignedGreaterThan) (intcc_without_eq cc))
   (if-let $true (has_zbb))
   (rv_max x y))
 
+;; Rotate Zero Reg to the right. This allows us to write fewer rules
+;; below when matching the zero register
+;;
+;; Additionally prevent this rule from recursing infinitely by only
+;; matching when one of the inputs is the zero register, but not both.
+
+(rule 5 (gen_select_xreg (int_compare_decompose cc a @ (zero_reg) b @ (non_zero_reg)) x y)
+  (if-let $true (has_zicond))
+  (gen_select_xreg (int_compare (intcc_swap_args cc) b a) x y))
+
+(rule 4 (gen_select_xreg c @ (int_compare_decompose cc a b) x @ (zero_reg) y @ (non_zero_reg))
+  (if-let $true (has_zicond))
+  (gen_select_xreg (int_compare (intcc_complement cc) a b) y x))
+
+(rule 3 (gen_select_xreg (int_compare_decompose (IntCC.Equal) c (zero_reg)) x (zero_reg))
+  (if-let $true (has_zicond))
+  (rv_czero_nez x c))
+
+(rule 3 (gen_select_xreg (int_compare_decompose (IntCC.NotEqual) c (zero_reg)) x (zero_reg))
+  (if-let $true (has_zicond))
+  (rv_czero_eqz x c))
+
+(rule 2 (gen_select_xreg (int_compare_decompose (IntCC.Equal) c (zero_reg)) x y)
+  (if-let $true (has_zicond))
+  (rv_or
+    (rv_czero_nez x c)
+    (rv_czero_eqz y c)))
+
+(rule 2 (gen_select_xreg (int_compare_decompose (IntCC.NotEqual) c (zero_reg)) x y)
+  (if-let $true (has_zicond))
+  (rv_or
+    (rv_czero_eqz x c)
+    (rv_czero_nez y c)))
+
+;; It is still beneficial to emit the full compare instruction, and then the 3 instruction
+;; select using zicond, so do that here as a last resort.
+(rule 1 (gen_select_xreg compare x y)
+  (if-let $true (has_zicond))
+  (gen_select_xreg (cmp_nez (lower_int_compare compare)) x y))
+
+;; In the base case we emit a conditional branch and a few moves.
+
 (rule 0 (gen_select_xreg c x y)
   (let
     ((dst WritableReg (temp_writable_xreg))
@@ -2956,6 +3030,10 @@
 (decl sp_reg () PReg)
 (extern constructor sp_reg sp_reg)
 
+;; Extractor that matches all registers, except the zero register
+(decl non_zero_reg () XReg)
+(extern extractor non_zero_reg is_non_zero_reg)
+
 ;; Helper for creating the zero register.
 (decl zero_reg () XReg)
 (extern constructor zero_reg zero_reg)
diff --git a/cranelift/codegen/src/isa/riscv64/inst/args.rs b/cranelift/codegen/src/isa/riscv64/inst/args.rs
index 2f6ed9fb0..51e3c69f9 100644
--- a/cranelift/codegen/src/isa/riscv64/inst/args.rs
+++ b/cranelift/codegen/src/isa/riscv64/inst/args.rs
@@ -804,6 +804,8 @@ impl AluOPRRR {
             Self::Pack => "pack",
             Self::Packw => "packw",
             Self::Packh => "packh",
+            Self::CzeroEqz => "czero.eqz",
+            Self::CzeroNez => "czero.nez",
         }
     }
 
@@ -874,6 +876,10 @@ impl AluOPRRR {
             AluOPRRR::Pack => 0b100,
             AluOPRRR::Packw => 0b100,
             AluOPRRR::Packh => 0b111,
+
+            // ZiCond
+            AluOPRRR::CzeroEqz => 0b101,
+            AluOPRRR::CzeroNez => 0b111,
         }
     }
 
@@ -935,7 +941,9 @@ impl AluOPRRR {
             | AluOPRRR::Sh1add
             | AluOPRRR::Sh2add
             | AluOPRRR::Sh3add
-            | AluOPRRR::Xnor => 0b0110011,
+            | AluOPRRR::Xnor
+            | AluOPRRR::CzeroEqz
+            | AluOPRRR::CzeroNez => 0b0110011,
 
             AluOPRRR::Rolw
             | AluOPRRR::Rorw
@@ -1011,6 +1019,10 @@ impl AluOPRRR {
             AluOPRRR::Pack => 0b0000100,
             AluOPRRR::Packw => 0b0000100,
             AluOPRRR::Packh => 0b0000100,
+
+            // ZiCond
+            AluOPRRR::CzeroEqz => 0b0000111,
+            AluOPRRR::CzeroNez => 0b0000111,
         }
     }
 
diff --git a/cranelift/codegen/src/isa/riscv64/lower.isle b/cranelift/codegen/src/isa/riscv64/lower.isle
index bd09e1c69..6dc99e3c8 100644
--- a/cranelift/codegen/src/isa/riscv64/lower.isle
+++ b/cranelift/codegen/src/isa/riscv64/lower.isle
@@ -1826,16 +1826,27 @@
   (rv_seqz (rv_addi v (imm12_const 1))))
 
 ;;;;;  Rules for `select`;;;;;;;;;
-(rule 0 (lower (has_type (ty_int_ref_scalar_64 _) (select c x y)))
+
+;; Manually matching (iconst 0) here is a bit of a hack. We can't do that as part
+;; of the iconst rule because that runs into regalloc issues. gen_select_xreg
+;; has some optimizations based on the use of the zero register so we have to
+;; manually match it here.
+(rule 5 (lower (has_type (ty_int_ref_scalar_64 _) (select c (i64_from_iconst 0) y)))
+  (gen_select_xreg (is_nonzero_cmp c) (zero_reg) y))
+
+(rule 4 (lower (has_type (ty_int_ref_scalar_64 _) (select c x (i64_from_iconst 0))))
+  (gen_select_xreg (is_nonzero_cmp c) x (zero_reg)))
+
+(rule 3 (lower (has_type (ty_int_ref_scalar_64 _) (select c x y)))
   (gen_select_xreg (is_nonzero_cmp c) x y))
 
-(rule 1 (lower (has_type $I128 (select c x y)))
+(rule 2 (lower (has_type $I128 (select c x y)))
   (gen_select_regs (is_nonzero_cmp c) x y))
 
-(rule 2 (lower (has_type (ty_vec_fits_in_register _) (select c x y)))
+(rule 1 (lower (has_type (ty_vec_fits_in_register _) (select c x y)))
   (gen_select_vreg (is_nonzero_cmp c) x y))
 
-(rule 3 (lower (has_type (ty_scalar_float _) (select c x y)))
+(rule 0 (lower (has_type (ty_scalar_float _) (select c x y)))
   (gen_select_freg (is_nonzero_cmp c) x y))
 
 ;;;;;  Rules for `bitselect`;;;;;;;;;
diff --git a/cranelift/codegen/src/isa/riscv64/lower/isle.rs b/cranelift/codegen/src/isa/riscv64/lower/isle.rs
index 87f15ba4f..743220d0d 100644
--- a/cranelift/codegen/src/isa/riscv64/lower/isle.rs
+++ b/cranelift/codegen/src/isa/riscv64/lower/isle.rs
@@ -300,6 +300,13 @@ impl generated_code::Context for RV64IsleContext<'_, '_, MInst, Riscv64Backend>
     fn zero_reg(&mut self) -> XReg {
         XReg::new(zero_reg()).unwrap()
     }
+    fn is_non_zero_reg(&mut self, reg: XReg) -> Option<()> {
+        if reg != self.zero_reg() {
+            Some(())
+        } else {
+            None
+        }
+    }
     fn is_zero_reg(&mut self, reg: XReg) -> Option<()> {
         if reg == self.zero_reg() {
             Some(())
@@ -399,6 +406,10 @@ impl generated_code::Context for RV64IsleContext<'_, '_, MInst, Riscv64Backend>
         self.backend.isa_flags.has_zbs()
     }
 
+    fn has_zicond(&mut self) -> bool {
+        self.backend.isa_flags.has_zicond()
+    }
+
     fn gen_reg_offset_amode(&mut self, base: Reg, offset: i64) -> AMode {
         AMode::RegOffset(base, offset)
     }
diff --git a/cranelift/codegen/src/machinst/abi.rs b/cranelift/codegen/src/machinst/abi.rs
index ade1298a0..713fcec25 100644
--- a/cranelift/codegen/src/machinst/abi.rs
+++ b/cranelift/codegen/src/machinst/abi.rs
@@ -1087,7 +1087,7 @@ fn checked_round_up(val: u32, mask: u32) -> Option<u32> {
 
 impl<M: ABIMachineSpec> Callee<M> {
     /// Create a new body ABI instance.
-    pub fn new<'a>(
+    pub fn new(
         f: &ir::Function,
         isa: &dyn TargetIsa,
         isa_flags: &M::F,
diff --git a/cranelift/codegen/src/prelude_opt.isle b/cranelift/codegen/src/prelude_opt.isle
index 8bd6370eb..e0cd14860 100644
--- a/cranelift/codegen/src/prelude_opt.isle
+++ b/cranelift/codegen/src/prelude_opt.isle
@@ -74,7 +74,7 @@
 ;; When constructing, the rule will fail if the value cannot be represented in
 ;; the target type.  If it fits, it'll be masked accordingly in the constant.
 (decl iconst_s (Type i64) Value)
-(extractor (iconst_s ty c) (sextend_maybe ty (inst_data_tupled (iconst_sextend_etor _inner_ty c))))
+(extractor (iconst_s ty c) (inst_data_tupled (iconst_sextend_etor ty c)))
 (rule 0 (iconst_s ty c)
 	(if-let c_masked (u64_and (i64_as_u64 c) (ty_umax ty)))
 	(if-let c_reextended (i64_sextend_u64 ty c_masked))
@@ -89,7 +89,7 @@
 ;; When constructing, the rule will fail if the value cannot be represented in
 ;; the target type.
 (decl iconst_u (Type u64) Value)
-(extractor (iconst_u ty c) (uextend_maybe ty (iconst _inner_ty (u64_from_imm64 c))))
+(extractor (iconst_u ty c) (iconst ty (u64_from_imm64 c)))
 (rule 0 (iconst_u ty c)
 	(if-let $true (u64_le c (ty_umax ty)))
     (iconst ty (imm64 c)))
diff --git a/cranelift/reader/src/parser.rs b/cranelift/reader/src/parser.rs
index 23ce76526..1ad9809bc 100644
--- a/cranelift/reader/src/parser.rs
+++ b/cranelift/reader/src/parser.rs
@@ -179,7 +179,7 @@ pub fn parse_test<'a>(text: &'a str, options: ParseOptions<'a>) -> ParseResult<T
 ///    or `print`
 ///  - `Ok(Some(command))` if the comment is intended as a `RunCommand` and can be parsed to one
 ///  - `Err` otherwise.
-pub fn parse_run_command<'a>(text: &str, signature: &Signature) -> ParseResult<Option<RunCommand>> {
+pub fn parse_run_command(text: &str, signature: &Signature) -> ParseResult<Option<RunCommand>> {
     let _tt = timing::parse_text();
     // We remove leading spaces and semi-colons for convenience here instead of at the call sites
     // since this function will be attempting to parse a RunCommand from a CLIF comment.
diff --git a/crates/c-api/CMakeLists.txt b/crates/c-api/CMakeLists.txt
index a8b5098ec..1235c61a0 100644
--- a/crates/c-api/CMakeLists.txt
+++ b/crates/c-api/CMakeLists.txt
@@ -1,4 +1,4 @@
-cmake_minimum_required(VERSION 3.10)
+cmake_minimum_required(VERSION 3.12)
 project(wasmtime C)
 
 set(WASMTIME_USER_CARGO_BUILD_OPTIONS "" CACHE STRING "Additional cargo flags (such as --features) to apply to the build command")
diff --git a/crates/cache/src/lib.rs b/crates/cache/src/lib.rs
index aabaded44..7b146fc9c 100644
--- a/crates/cache/src/lib.rs
+++ b/crates/cache/src/lib.rs
@@ -27,7 +27,7 @@ struct Sha256Hasher(Sha256);
 
 impl<'config> ModuleCacheEntry<'config> {
     /// Create the cache entry.
-    pub fn new<'data>(compiler_name: &str, cache_config: &'config CacheConfig) -> Self {
+    pub fn new(compiler_name: &str, cache_config: &'config CacheConfig) -> Self {
         if cache_config.enabled() {
             Self(Some(ModuleCacheEntryInner::new(
                 compiler_name,
@@ -108,7 +108,7 @@ impl<'config> ModuleCacheEntry<'config> {
 }
 
 impl<'config> ModuleCacheEntryInner<'config> {
-    fn new<'data>(compiler_name: &str, cache_config: &'config CacheConfig) -> Self {
+    fn new(compiler_name: &str, cache_config: &'config CacheConfig) -> Self {
         // If debug assertions are enabled then assume that we're some sort of
         // local build. We don't want local builds to stomp over caches between
         // builds, so just use a separate cache directory based on the mtime of
diff --git a/crates/cranelift/src/debug/transform/mod.rs b/crates/cranelift/src/debug/transform/mod.rs
index 788550d0e..0695c3f3a 100644
--- a/crates/cranelift/src/debug/transform/mod.rs
+++ b/crates/cranelift/src/debug/transform/mod.rs
@@ -132,7 +132,7 @@ fn read_dwarf_package_from_bytes<'data>(
     }
 }
 
-pub fn transform_dwarf<'data>(
+pub fn transform_dwarf(
     isa: &dyn TargetIsa,
     di: &DebugInfoData,
     funcs: &CompiledFunctionsMetadata,
diff --git a/crates/cranelift/src/debug/write_debuginfo.rs b/crates/cranelift/src/debug/write_debuginfo.rs
index 35b9fed72..e5099a704 100644
--- a/crates/cranelift/src/debug/write_debuginfo.rs
+++ b/crates/cranelift/src/debug/write_debuginfo.rs
@@ -140,7 +140,7 @@ impl Writer for WriterRelocate {
     }
 }
 
-fn create_frame_table<'a>(
+fn create_frame_table(
     isa: &dyn TargetIsa,
     funcs: &CompiledFunctionsMetadata,
 ) -> Option<FrameTable> {
@@ -174,7 +174,7 @@ fn create_frame_table<'a>(
     Some(table)
 }
 
-pub fn emit_dwarf<'a>(
+pub fn emit_dwarf(
     isa: &dyn TargetIsa,
     debuginfo_data: &DebugInfoData,
     funcs: &CompiledFunctionsMetadata,
diff --git a/crates/environ/Cargo.toml b/crates/environ/Cargo.toml
index 8ca3e98d6..5cef16b18 100644
--- a/crates/environ/Cargo.toml
+++ b/crates/environ/Cargo.toml
@@ -13,6 +13,9 @@ edition.workspace = true
 [lints]
 workspace = true
 
+[package.metadata.docs.rs]
+all-features = true
+
 [dependencies]
 anyhow = { workspace = true }
 postcard = { workspace = true }
diff --git a/crates/fuzzing/src/oracles/dummy.rs b/crates/fuzzing/src/oracles/dummy.rs
index d88cd2c3a..75152c399 100644
--- a/crates/fuzzing/src/oracles/dummy.rs
+++ b/crates/fuzzing/src/oracles/dummy.rs
@@ -4,7 +4,7 @@ use anyhow::ensure;
 use wasmtime::*;
 
 /// Create a set of dummy functions/globals/etc for the given imports.
-pub fn dummy_linker<'module, T>(store: &mut Store<T>, module: &Module) -> Result<Linker<T>> {
+pub fn dummy_linker<T>(store: &mut Store<T>, module: &Module) -> Result<Linker<T>> {
     let mut linker = Linker::new(store.engine());
     linker.allow_shadowing(true);
     for import in module.imports() {
diff --git a/crates/wasi-nn/src/witx.rs b/crates/wasi-nn/src/witx.rs
index d2f85d25f..ffcaccac4 100644
--- a/crates/wasi-nn/src/witx.rs
+++ b/crates/wasi-nn/src/witx.rs
@@ -35,7 +35,7 @@ mod gen {
     }
 
     /// Convert the host errors to their WITX-generated type.
-    impl<'a> types::UserErrorConversion for WasiNnCtx {
+    impl types::UserErrorConversion for WasiNnCtx {
         fn nn_errno_from_wasi_nn_error(
             &mut self,
             e: WasiNnError,
@@ -51,8 +51,8 @@ mod gen {
 }
 
 /// Wire up the WITX-generated trait to the `wasi-nn` host state.
-impl<'a> gen::wasi_ephemeral_nn::WasiEphemeralNn for WasiNnCtx {
-    fn load<'b>(
+impl gen::wasi_ephemeral_nn::WasiEphemeralNn for WasiNnCtx {
+    fn load(
         &mut self,
         builders: &gen::types::GraphBuilderArray<'_>,
         encoding: gen::types::GraphEncoding,
@@ -128,7 +128,7 @@ impl<'a> gen::wasi_ephemeral_nn::WasiEphemeralNn for WasiNnCtx {
         }
     }
 
-    fn get_output<'b>(
+    fn get_output(
         &mut self,
         exec_context_id: gen::types::GraphExecutionContext,
         index: u32,
diff --git a/crates/wasmtime/Cargo.toml b/crates/wasmtime/Cargo.toml
index 8aad132e5..5e00f9a63 100644
--- a/crates/wasmtime/Cargo.toml
+++ b/crates/wasmtime/Cargo.toml
@@ -14,10 +14,7 @@ rust-version.workspace = true
 workspace = true
 
 [package.metadata.docs.rs]
-# Docs.rs will use the `component-model` feature for documentation;
-# so this feature also passed in to the `cargo doc` invocation in CI.
-# See .github/workflows/main.yml
-features = ["component-model"]
+all-features = true
 
 [dependencies]
 wasmtime-asm-macros = { workspace = true, optional = true }
diff --git a/crates/wasmtime/src/compile.rs b/crates/wasmtime/src/compile.rs
index 0436a7e76..e352ac6ad 100644
--- a/crates/wasmtime/src/compile.rs
+++ b/crates/wasmtime/src/compile.rs
@@ -122,7 +122,7 @@ pub(crate) fn build_artifacts<T: FinishedObject>(
 /// The output artifact here is the serialized object file contained within
 /// an owned mmap along with metadata about the compilation itself.
 #[cfg(feature = "component-model")]
-pub(crate) fn build_component_artifacts<'a, T: FinishedObject>(
+pub(crate) fn build_component_artifacts<T: FinishedObject>(
     engine: &Engine,
     binary: &[u8],
     _dwarf_package: Option<&[u8]>,
diff --git a/crates/wasmtime/src/runtime/func/typed.rs b/crates/wasmtime/src/runtime/func/typed.rs
index a802d941e..c72e5414b 100644
--- a/crates/wasmtime/src/runtime/func/typed.rs
+++ b/crates/wasmtime/src/runtime/func/typed.rs
@@ -533,7 +533,7 @@ unsafe impl WasmTy for Func {
     }
 
     #[inline]
-    fn compatible_with_store<'a>(&self, store: &StoreOpaque) -> bool {
+    fn compatible_with_store(&self, store: &StoreOpaque) -> bool {
         store.store_data().contains(self.0)
     }
 
@@ -571,7 +571,7 @@ unsafe impl WasmTy for Option<Func> {
     }
 
     #[inline]
-    fn compatible_with_store<'a>(&self, store: &StoreOpaque) -> bool {
+    fn compatible_with_store(&self, store: &StoreOpaque) -> bool {
         if let Some(f) = self {
             store.store_data().contains(f.0)
         } else {
diff --git a/crates/wasmtime/src/runtime/vm/traphandlers.rs b/crates/wasmtime/src/runtime/vm/traphandlers.rs
index 25e48560c..e68ff075f 100644
--- a/crates/wasmtime/src/runtime/vm/traphandlers.rs
+++ b/crates/wasmtime/src/runtime/vm/traphandlers.rs
@@ -227,7 +227,7 @@ pub(crate) enum TrapTest {
 /// returning them as a `Result`.
 ///
 /// Highly unsafe since `closure` won't have any dtors run.
-pub unsafe fn catch_traps<'a, F>(
+pub unsafe fn catch_traps<F>(
     signal_handler: Option<*const SignalHandler<'static>>,
     capture_backtrace: bool,
     capture_coredump: bool,
diff --git a/crates/wit-bindgen/src/lib.rs b/crates/wit-bindgen/src/lib.rs
index 1a570e107..23b9e8c4b 100644
--- a/crates/wit-bindgen/src/lib.rs
+++ b/crates/wit-bindgen/src/lib.rs
@@ -315,13 +315,13 @@ impl Wasmtime {
 
         let world = &resolve.worlds[id];
         for (name, import) in world.imports.iter() {
-            if !self.opts.only_interfaces || matches!(import, WorldItem::Interface(_)) {
+            if !self.opts.only_interfaces || matches!(import, WorldItem::Interface { .. }) {
                 self.import(resolve, id, name, import);
             }
         }
 
         for (name, export) in world.exports.iter() {
-            if !self.opts.only_interfaces || matches!(export, WorldItem::Interface(_)) {
+            if !self.opts.only_interfaces || matches!(export, WorldItem::Interface { .. }) {
                 self.export(resolve, name, export);
             }
         }
@@ -349,7 +349,7 @@ impl Wasmtime {
                     add_to_linker,
                 });
             }
-            WorldItem::Interface(id) => {
+            WorldItem::Interface { id, .. } => {
                 gen.gen.interface_last_seen_as_import.insert(*id, true);
                 if gen.gen.name_interface(resolve, *id, name, false) {
                     return;
@@ -412,7 +412,7 @@ impl Wasmtime {
                 )
             }
             WorldItem::Type(_) => unreachable!(),
-            WorldItem::Interface(id) => {
+            WorldItem::Interface { id, .. } => {
                 gen.gen.interface_last_seen_as_import.insert(*id, false);
                 gen.gen.name_interface(resolve, *id, name, true);
                 gen.current_interface = Some((*id, name, true));
diff --git a/crates/wit-bindgen/src/types.rs b/crates/wit-bindgen/src/types.rs
index b41360495..c45d3d80f 100644
--- a/crates/wit-bindgen/src/types.rs
+++ b/crates/wit-bindgen/src/types.rs
@@ -57,7 +57,7 @@ impl Types {
         {
             match item {
                 WorldItem::Function(f) => self.type_info_func(resolve, f, import),
-                WorldItem::Interface(id) => {
+                WorldItem::Interface { id, .. } => {
                     let iface = &resolve.interfaces[*id];
 
                     for (_, t) in iface.types.iter() {
diff --git a/supply-chain/imports.lock b/supply-chain/imports.lock
index 736a1f7d7..15c1483f4 100644
--- a/supply-chain/imports.lock
+++ b/supply-chain/imports.lock
@@ -1537,6 +1537,12 @@ when = "2024-05-20"
 user-id = 73222
 user-login = "wasmtime-publish"
 
+[[publisher.wasm-encoder]]
+version = "0.209.1"
+when = "2024-05-29"
+user-id = 73222
+user-login = "wasmtime-publish"
+
 [[publisher.wasm-metadata]]
 version = "0.201.0"
 when = "2024-02-27"
@@ -1585,6 +1591,12 @@ when = "2024-05-20"
 user-id = 73222
 user-login = "wasmtime-publish"
 
+[[publisher.wasm-metadata]]
+version = "0.209.1"
+when = "2024-05-29"
+user-id = 73222
+user-login = "wasmtime-publish"
+
 [[publisher.wasm-mutate]]
 version = "0.201.0"
 when = "2024-02-27"
@@ -1705,6 +1717,12 @@ when = "2024-05-20"
 user-id = 73222
 user-login = "wasmtime-publish"
 
+[[publisher.wasmparser]]
+version = "0.209.1"
+when = "2024-05-29"
+user-id = 73222
+user-login = "wasmtime-publish"
+
 [[publisher.wasmprinter]]
 version = "0.201.0"
 when = "2024-02-27"
@@ -1753,6 +1771,12 @@ when = "2024-05-20"
 user-id = 73222
 user-login = "wasmtime-publish"
 
+[[publisher.wasmprinter]]
+version = "0.209.1"
+when = "2024-05-29"
+user-id = 73222
+user-login = "wasmtime-publish"
+
 [[publisher.wasmtime]]
 version = "18.0.2"
 when = "2024-02-28"
@@ -2215,6 +2239,12 @@ when = "2024-05-20"
 user-id = 73222
 user-login = "wasmtime-publish"
 
+[[publisher.wast]]
+version = "209.0.1"
+when = "2024-05-29"
+user-id = 73222
+user-login = "wasmtime-publish"
+
 [[publisher.wat]]
 version = "1.201.0"
 when = "2024-02-27"
@@ -2263,6 +2293,12 @@ when = "2024-05-20"
 user-id = 73222
 user-login = "wasmtime-publish"
 
+[[publisher.wat]]
+version = "1.209.1"
+when = "2024-05-29"
+user-id = 73222
+user-login = "wasmtime-publish"
+
 [[publisher.wiggle]]
 version = "18.0.2"
 when = "2024-02-28"
@@ -2635,6 +2671,12 @@ when = "2024-05-20"
 user-id = 73222
 user-login = "wasmtime-publish"
 
+[[publisher.wit-component]]
+version = "0.209.1"
+when = "2024-05-29"
+user-id = 73222
+user-login = "wasmtime-publish"
+
 [[publisher.wit-parser]]
 version = "0.201.0"
 when = "2024-02-27"
@@ -2683,6 +2725,12 @@ when = "2024-05-20"
 user-id = 73222
 user-login = "wasmtime-publish"
 
+[[publisher.wit-parser]]
+version = "0.209.1"
+when = "2024-05-29"
+user-id = 73222
+user-login = "wasmtime-publish"
+
 [[publisher.witx]]
 version = "0.9.1"
 when = "2021-06-22"


Test patch:
diff --git a/ci/build-test-matrix.js b/ci/build-test-matrix.js
index 9bc77f219..18692260e 100644
--- a/ci/build-test-matrix.js
+++ b/ci/build-test-matrix.js
@@ -116,7 +116,7 @@ const FULL_MATRIX = [
     "target": "riscv64gc-unknown-linux-gnu",
     "gcc_package": "gcc-riscv64-linux-gnu",
     "gcc": "riscv64-linux-gnu-gcc",
-    "qemu": "qemu-riscv64 -cpu rv64,v=true,vlen=256,vext_spec=v1.0,Zfa=true,zba=true,zbb=true,zbc=true,zbs=true,zbkb=true,zcb=true -L /usr/riscv64-linux-gnu",
+    "qemu": "qemu-riscv64 -cpu rv64,v=true,vlen=256,vext_spec=v1.0,Zfa=true,zba=true,zbb=true,zbc=true,zbs=true,zbkb=true,zcb=true,x-zicond=true -L /usr/riscv64-linux-gnu",
     "qemu_target": "riscv64-linux-user",
     "name": "Test Linux riscv64",
     "filter": "linux-riscv64",
diff --git a/cranelift/filetests/filetests/egraph/i128-opts.clif b/cranelift/filetests/filetests/egraph/i128-opts.clif
index c84fc23bb..86a04b164 100644
--- a/cranelift/filetests/filetests/egraph/i128-opts.clif
+++ b/cranelift/filetests/filetests/egraph/i128-opts.clif
@@ -136,22 +136,22 @@ block0:
     ; check: return v4
 }
 
-function %mul_2u_i128(i128) -> i128 {
-block0(v0: i128):
-    v1 = iconst.i16 2
-    v2 = uextend.i128 v1
-    v3 = imul v0, v2
-    return v3
-    ; check: v4 = iadd v0, v0
-    ; check: return v4
+function %slt() -> i8 {
+block0:
+    v0 = iconst.i64 0
+    v1 = uextend.i128 v0
+    v2 = icmp slt v1, v1
+    return v2
+    ; check: v3 = iconst.i8 0
+    ; check: return
 }
 
-function %mul_neg1_i128(i128) -> i128 {
-block0(v0: i128):
-    v1 = iconst.i16 -1
-    v2 = sextend.i128 v1
-    v3 = imul v0, v2
-    return v3
-    ; check: v4 = ineg v0
-    ; check: return v4
+function %ult() -> i8 {
+block0:
+    v0 = iconst.i64 0
+    v1 = uextend.i128 v0
+    v2 = icmp ult v1, v1
+    return v2
+    ; check: v3 = iconst.i8 0
+    ; check: return
 }
diff --git a/cranelift/filetests/filetests/isa/riscv64/bitops-float.clif b/cranelift/filetests/filetests/isa/riscv64/bitops-float.clif
index c4b228d76..a302407c6 100644
--- a/cranelift/filetests/filetests/isa/riscv64/bitops-float.clif
+++ b/cranelift/filetests/filetests/isa/riscv64/bitops-float.clif
@@ -22,20 +22,19 @@ block1(v4: f32):
 ; VCode:
 ; block0:
 ;   li a0,0
-;   li a1,0
+;   fmv.w.x fa1,zero
+;   fmv.x.w a5,fa1
+;   not a1,a5
 ;   fmv.w.x fa3,a1
+;   fmv.x.w a4,fa3
 ;   fmv.x.w a1,fa3
-;   not a2,a1
-;   fmv.w.x fa4,a2
-;   fmv.x.w a5,fa4
-;   fmv.x.w a1,fa4
-;   or a3,a5,a1
-;   fmv.w.x fa4,a3
-;   br_table a0,[MachLabel(1),MachLabel(2)]##tmp1=a1,tmp2=a2
+;   or a2,a4,a1
+;   fmv.w.x fa2,a2
+;   br_table a0,[MachLabel(1),MachLabel(2)]##tmp1=a2,tmp2=a1
 ; block1:
 ;   j label3
 ; block2:
-;   fmv.d fa4,fa3
+;   fmv.d fa2,fa1
 ;   j label3
 ; block3:
 ;   ret
@@ -43,31 +42,30 @@ block1(v4: f32):
 ; Disassembled:
 ; block0: ; offset 0x0
 ;   mv a0, zero
-;   mv a1, zero
+;   fmv.w.x fa1, zero
+;   fmv.x.w a5, fa1
+;   not a1, a5
 ;   fmv.w.x fa3, a1
+;   fmv.x.w a4, fa3
 ;   fmv.x.w a1, fa3
-;   not a2, a1
-;   fmv.w.x fa4, a2
-;   fmv.x.w a5, fa4
-;   fmv.x.w a1, fa4
-;   or a3, a5, a1
-;   fmv.w.x fa4, a3
+;   or a2, a4, a1
+;   fmv.w.x fa2, a2
 ;   slli t6, a0, 0x20
 ;   srli t6, t6, 0x20
-;   addi a2, zero, 1
-;   bltu t6, a2, 0xc
-;   auipc a2, 0
-;   jalr zero, a2, 0x28
+;   addi a1, zero, 1
+;   bltu t6, a1, 0xc
 ;   auipc a1, 0
-;   slli a2, t6, 3
-;   add a1, a1, a2
-;   jalr zero, a1, 0x10
+;   jalr zero, a1, 0x28
 ;   auipc a2, 0
-;   jalr zero, a2, 0xc
-; block1: ; offset 0x58
+;   slli a1, t6, 3
+;   add a2, a2, a1
+;   jalr zero, a2, 0x10
+;   auipc a1, 0
+;   jalr zero, a1, 0xc
+; block1: ; offset 0x54
 ;   j 8
-; block2: ; offset 0x5c
-;   fmv.d fa4, fa3
-; block3: ; offset 0x60
+; block2: ; offset 0x58
+;   fmv.d fa2, fa1
+; block3: ; offset 0x5c
 ;   ret
 
diff --git a/cranelift/filetests/filetests/isa/riscv64/constants.clif b/cranelift/filetests/filetests/isa/riscv64/constants.clif
index 3a159071e..9e81223ee 100644
--- a/cranelift/filetests/filetests/isa/riscv64/constants.clif
+++ b/cranelift/filetests/filetests/isa/riscv64/constants.clif
@@ -426,14 +426,12 @@ block0:
 
 ; VCode:
 ; block0:
-;   li a0,0
-;   fmv.d.x fa0,a0
+;   fmv.d.x fa0,zero
 ;   ret
 ;
 ; Disassembled:
 ; block0: ; offset 0x0
-;   mv a0, zero
-;   fmv.d.x fa0, a0
+;   fmv.d.x fa0, zero
 ;   ret
 
 function %f() -> f32 {
@@ -444,14 +442,12 @@ block0:
 
 ; VCode:
 ; block0:
-;   li a0,0
-;   fmv.w.x fa0,a0
+;   fmv.w.x fa0,zero
 ;   ret
 ;
 ; Disassembled:
 ; block0: ; offset 0x0
-;   mv a0, zero
-;   fmv.w.x fa0, a0
+;   fmv.w.x fa0, zero
 ;   ret
 
 function %f() -> f64 {
diff --git a/cranelift/filetests/filetests/isa/riscv64/fcmp.clif b/cranelift/filetests/filetests/isa/riscv64/fcmp.clif
index 01b569b0f..8e2ee2f91 100644
--- a/cranelift/filetests/filetests/isa/riscv64/fcmp.clif
+++ b/cranelift/filetests/filetests/isa/riscv64/fcmp.clif
@@ -14,10 +14,9 @@ block1:
 
 ; VCode:
 ; block0:
-;   li a1,0
-;   fmv.d.x fa3,a1
-;   fle.d a2,fa3,fa3
-;   beq a2,zero,taken(label1),not_taken(label2)
+;   fmv.d.x fa1,zero
+;   fle.d a1,fa1,fa1
+;   beq a1,zero,taken(label1),not_taken(label2)
 ; block1:
 ;   j label3
 ; block2:
@@ -27,10 +26,9 @@ block1:
 ;
 ; Disassembled:
 ; block0: ; offset 0x0
-;   mv a1, zero
-;   fmv.d.x fa3, a1
-;   fle.d a2, fa3, fa3
-; block1: ; offset 0xc
+;   fmv.d.x fa1, zero
+;   fle.d a1, fa1, fa1
+; block1: ; offset 0x8
 ;   ret
 
 function %f1() {
@@ -45,10 +43,9 @@ block1:
 
 ; VCode:
 ; block0:
-;   li a1,0
-;   fmv.d.x fa3,a1
-;   fle.d a2,fa3,fa3
-;   beq a2,zero,taken(label1),not_taken(label2)
+;   fmv.d.x fa1,zero
+;   fle.d a1,fa1,fa1
+;   beq a1,zero,taken(label1),not_taken(label2)
 ; block1:
 ;   j label3
 ; block2:
@@ -58,10 +55,9 @@ block1:
 ;
 ; Disassembled:
 ; block0: ; offset 0x0
-;   mv a1, zero
-;   fmv.d.x fa3, a1
-;   fle.d a2, fa3, fa3
-; block1: ; offset 0xc
+;   fmv.d.x fa1, zero
+;   fle.d a1, fa1, fa1
+; block1: ; offset 0x8
 ;   ret
 
 function %ord(f32, f32) -> i8 {
diff --git a/cranelift/filetests/filetests/isa/riscv64/zicond.clif b/cranelift/filetests/filetests/isa/riscv64/zicond.clif
new file mode 100644
index 000000000..00b0c37dd
--- /dev/null
+++ b/cranelift/filetests/filetests/isa/riscv64/zicond.clif
@@ -0,0 +1,185 @@
+test compile precise-output
+set unwind_info=false
+target riscv64 has_zicond
+
+
+function %select_zero(i64, i64) -> i64 {
+block0(v0: i64, v1: i64):
+  v2 = iconst.i64 0
+  v3 = select.i64 v0, v1, v2
+  return v3
+}
+
+; VCode:
+; block0:
+;   czero.eqz a0,a1,a0
+;   ret
+;
+; Disassembled:
+; block0: ; offset 0x0
+;   .byte 0x33, 0xd5, 0xa5, 0x0e
+;   ret
+
+function %select_zero_icmp_neq(i64, i64) -> i64 {
+block0(v0: i64, v1: i64):
+  v2 = iconst.i64 0
+  v3 = icmp.i64 ne v0, v2
+  v4 = select.i64 v3, v1, v2
+  return v4
+}
+
+; VCode:
+; block0:
+;   czero.eqz a0,a1,a0
+;   ret
+;
+; Disassembled:
+; block0: ; offset 0x0
+;   .byte 0x33, 0xd5, 0xa5, 0x0e
+;   ret
+
+function %select_zero_icmp_neq_reverse(i64, i64) -> i64 {
+block0(v0: i64, v1: i64):
+  v2 = iconst.i64 0
+  v3 = icmp.i64 ne v2, v0
+  v4 = select.i64 v3, v2, v1
+  return v4
+}
+
+; VCode:
+; block0:
+;   czero.nez a0,a1,a0
+;   ret
+;
+; Disassembled:
+; block0: ; offset 0x0
+;   .byte 0x33, 0xf5, 0xa5, 0x0e
+;   ret
+
+function %select_zero_icmp_eqz(i64, i64) -> i64 {
+block0(v0: i64, v1: i64):
+  v2 = iconst.i64 0
+  v3 = icmp.i64 eq v0, v2
+  v4 = select.i64 v3, v1, v2
+  return v4
+}
+
+; VCode:
+; block0:
+;   czero.nez a0,a1,a0
+;   ret
+;
+; Disassembled:
+; block0: ; offset 0x0
+;   .byte 0x33, 0xf5, 0xa5, 0x0e
+;   ret
+
+
+function %select_zero_icmp_eqz_reverse(i64, i64) -> i64 {
+block0(v0: i64, v1: i64):
+  v2 = iconst.i64 0
+  v3 = icmp.i64 eq v2, v0
+  v4 = select.i64 v3, v2, v1
+  return v4
+}
+
+; VCode:
+; block0:
+;   czero.eqz a0,a1,a0
+;   ret
+;
+; Disassembled:
+; block0: ; offset 0x0
+;   .byte 0x33, 0xd5, 0xa5, 0x0e
+;   ret
+
+
+function %select_icmp_eq_zero(i64, i64, i64) -> i64 {
+block0(v0: i64, v1: i64, v2: i64):
+  v3 = iconst.i64 0
+  v4 = icmp.i64 eq v0, v3
+  v5 = select.i64 v4, v1, v2
+  return v5
+}
+
+; VCode:
+; block0:
+;   czero.nez a4,a1,a0
+;   czero.eqz a0,a2,a0
+;   or a0,a4,a0
+;   ret
+;
+; Disassembled:
+; block0: ; offset 0x0
+;   .byte 0x33, 0xf7, 0xa5, 0x0e
+;   .byte 0x33, 0x55, 0xa6, 0x0e
+;   or a0, a4, a0
+;   ret
+
+function %select_icmp_ne_zero(i64, i64, i64) -> i64 {
+block0(v0: i64, v1: i64, v2: i64):
+  v3 = iconst.i64 0
+  v4 = icmp.i64 ne v0, v3
+  v5 = select.i64 v4, v1, v2
+  return v5
+}
+
+; VCode:
+; block0:
+;   czero.eqz a4,a1,a0
+;   czero.nez a0,a2,a0
+;   or a0,a4,a0
+;   ret
+;
+; Disassembled:
+; block0: ; offset 0x0
+;   .byte 0x33, 0xd7, 0xa5, 0x0e
+;   .byte 0x33, 0x75, 0xa6, 0x0e
+;   or a0, a4, a0
+;   ret
+
+
+function %select_icmp_sle(i64, i64, i64, i64) -> i64 {
+block0(v0: i64, v1: i64, v2: i64, v3: i64):
+  v4 = icmp.i64 slt v0, v1
+  v5 = select.i64 v4, v2, v3
+  return v5
+}
+
+; VCode:
+; block0:
+;   slt a5,a0,a1
+;   czero.eqz a1,a2,a5
+;   czero.nez a3,a3,a5
+;   or a0,a1,a3
+;   ret
+;
+; Disassembled:
+; block0: ; offset 0x0
+;   slt a5, a0, a1
+;   .byte 0xb3, 0x55, 0xf6, 0x0e
+;   .byte 0xb3, 0xf6, 0xf6, 0x0e
+;   or a0, a1, a3
+;   ret
+
+;; This can trigger a stack overflow with if the rules don't prevent
+;; this situation.
+function %check_rule_stack_overflow(i64, i64, i64) -> i64 {
+block0(v0: i64, v1: i64, v2: i64):
+  v3 = iconst.i64 0
+  v4 = icmp.i64 ne v3, v3
+  v5 = select.i64 v4, v3, v3
+  return v5
+}
+
+; VCode:
+; block0:
+;   li a1,0
+;   czero.nez a0,a1,zero
+;   ret
+;
+; Disassembled:
+; block0: ; offset 0x0
+;   mv a1, zero
+;   .byte 0x33, 0xf5, 0x05, 0x0e
+;   ret
diff --git a/cranelift/filetests/filetests/runtests/select.clif b/cranelift/filetests/filetests/runtests/select.clif
index 7740093e2..e53e240e2 100644
--- a/cranelift/filetests/filetests/runtests/select.clif
+++ b/cranelift/filetests/filetests/runtests/select.clif
@@ -4,6 +4,7 @@ target aarch64
 target s390x
 target x86_64
 target riscv64
+target riscv64 has_zicond
 target riscv64 has_c has_zcb
 
 function %select_eq_f32(f32, f32) -> i32 {
@@ -139,3 +140,43 @@ block0(v0: i32):
 ; run: %select_overflow_i32(2) == 1
 ; run: %select_overflow_i32(1) == 0
 ; run: %select_overflow_i32(98) == 1
+
+function %select_zero(i64, i64) -> i64 {
+block0(v0: i64, v1: i64):
+  v2 = iconst.i64 0
+  v3 = select.i64 v0, v1, v2
+  return v3
+}
+; run: %select_zero(0, 42) == 0
+; run: %select_zero(42, 42) == 42
+
+function %select_zero_icmp_neq_zero(i64, i64) -> i64 {
+block0(v0: i64, v1: i64):
+  v2 = iconst.i64 0
+  v3 = icmp.i64 ne v0, v2
+  v4 = select.i64 v3, v1, v2
+  return v4
+}
+; run: %select_zero_icmp_neq_zero(0, 42) == 0
+; run: %select_zero_icmp_neq_zero(42, 42) == 42
+
+function %select_icmp_eq_zero(i64, i64, i64) -> i64 {
+block0(v0: i64, v1: i64, v2: i64):
+  v3 = iconst.i64 0
+  v4 = icmp.i64 eq v0, v3
+  v5 = select.i64 v4, v1, v2
+  return v5
+}
+; run: %select_icmp_eq_zero(0, 42, 35) == 42
+; run: %select_icmp_eq_zero(42, 42, 35) == 35
+
+function %select_icmp_ne_zero(i64, i64, i64) -> i64 {
+block0(v0: i64, v1: i64, v2: i64):
+  v3 = iconst.i64 0
+  v4 = icmp.i64 ne v0, v3
+  v5 = select.i64 v4, v1, v2
+  return v5
+}
+; run: %select_icmp_ne_zero(0, 42, 35) == 35
+; run: %select_icmp_ne_zero(42, 42, 35) == 42
+