Repository: bytecodealliance/wasmtime
Pull request #7269 (2023-10-17 15:48:52)

Refactor x64 asm methods to extract xmm logic in Winch
<!--
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
-->
Refactor x86 microassembler methods such that separate methods are used to operate on XMM registers as opposed to operating on general purpose registers. Also rename methods that operate on multiple XMM registers to use the format `xmm_operation_rr` to be consistent with the naming convention in the rest of the struct.


Patch:
diff --git a/Cargo.lock b/Cargo.lock
index f3956ba07..7b45f8915 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -650,7 +650,7 @@ dependencies = [
  "target-lexicon",
  "thiserror",
  "toml",
- "wasmparser",
+ "wasmparser 0.115.0",
  "wat",
 ]
 
@@ -829,7 +829,7 @@ dependencies = [
  "serde_derive",
  "smallvec",
  "target-lexicon",
- "wasmparser",
+ "wasmparser 0.115.0",
  "wasmtime-types",
  "wat",
 ]
@@ -2680,7 +2680,7 @@ version = "0.0.0"
 dependencies = [
  "cargo_metadata",
  "heck",
- "wit-component",
+ "wit-component 0.15.0",
 ]
 
 [[package]]
@@ -2977,7 +2977,7 @@ name = "verify-component-adapter"
 version = "15.0.0"
 dependencies = [
  "anyhow",
- "wasmparser",
+ "wasmparser 0.115.0",
  "wat",
 ]
 
@@ -3075,7 +3075,7 @@ dependencies = [
  "byte-array-literals",
  "object",
  "wasi",
- "wasm-encoder",
+ "wasm-encoder 0.35.0",
  "wit-bindgen",
 ]
 
@@ -3159,47 +3159,57 @@ dependencies = [
  "leb128",
 ]
 
+[[package]]
+name = "wasm-encoder"
+version = "0.35.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9ca90ba1b5b0a70d3d49473c5579951f3bddc78d47b59256d2f9d4922b150aca"
+dependencies = [
+ "leb128",
+]
+
 [[package]]
 name = "wasm-metadata"
-version = "0.10.6"
+version = "0.10.9"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "577508d8a45bc54ad97efe77c95ba57bb10e7e5c5bac9c31295ce88b8045cd7d"
+checksum = "14abc161bfda5b519aa229758b68f2a52b45a12b993808665c857d1a9a00223c"
 dependencies = [
  "anyhow",
  "indexmap 2.0.0",
  "serde",
+ "serde_derive",
  "serde_json",
  "spdx",
- "wasm-encoder",
- "wasmparser",
+ "wasm-encoder 0.35.0",
+ "wasmparser 0.115.0",
 ]
 
 [[package]]
 name = "wasm-mutate"
-version = "0.2.35"
+version = "0.2.38"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f22ff62504d0e55a4e4c32cdf4e65f9c925ba0bc9904e141394eb2ad2b8f319d"
+checksum = "7b1e04b0c049b0a0c42dd108a56c5c92500076747363d3bf1e83e7f0f8b4dfe4"
 dependencies = [
  "egg",
  "log",
  "rand",
  "thiserror",
- "wasm-encoder",
- "wasmparser",
+ "wasm-encoder 0.35.0",
+ "wasmparser 0.115.0",
 ]
 
 [[package]]
 name = "wasm-smith"
-version = "0.12.18"
+version = "0.12.21"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7499466e905b4e8d0cc1720c1bfddf1e5040f6fa42efd4f43edd1b88dbe9ce9b"
+checksum = "fef779c243bbf04d9f03333c2cb50b98047c6dcc2a1db0cc7d0691e4135064b4"
 dependencies = [
  "arbitrary",
  "flagset",
  "indexmap 2.0.0",
  "leb128",
- "wasm-encoder",
- "wasmparser",
+ "wasm-encoder 0.35.0",
+ "wasmparser 0.115.0",
 ]
 
 [[package]]
@@ -3250,6 +3260,16 @@ dependencies = [
  "semver",
 ]
 
+[[package]]
+name = "wasmparser"
+version = "0.115.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e06c0641a4add879ba71ccb3a1e4278fd546f76f1eafb21d8f7b07733b547cd5"
+dependencies = [
+ "indexmap 2.0.0",
+ "semver",
+]
+
 [[package]]
 name = "wasmparser-nostd"
 version = "0.91.0"
@@ -3261,12 +3281,12 @@ dependencies = [
 
 [[package]]
 name = "wasmprinter"
-version = "0.2.67"
+version = "0.2.70"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f6615a5587149e753bf4b93f90fa3c3f41c88597a7a2da72879afcabeda9648f"
+checksum = "e74458a9bc5cc9c7108abfa0fe4dc88d5abf1f3baf194df3264985f17d559b5e"
 dependencies = [
  "anyhow",
- "wasmparser",
+ "wasmparser 0.115.0",
 ]
 
 [[package]]
@@ -3294,8 +3314,8 @@ dependencies = [
  "target-lexicon",
  "tempfile",
  "wasi-cap-std-sync",
- "wasm-encoder",
- "wasmparser",
+ "wasm-encoder 0.35.0",
+ "wasmparser 0.115.0",
  "wasmtime-cache",
  "wasmtime-component-macro",
  "wasmtime-component-util",
@@ -3413,8 +3433,8 @@ dependencies = [
  "test-programs-artifacts",
  "tokio",
  "walkdir",
- "wasm-encoder",
- "wasmparser",
+ "wasm-encoder 0.35.0",
+ "wasmparser 0.115.0",
  "wasmtime",
  "wasmtime-cache",
  "wasmtime-cli-flags",
@@ -3428,7 +3448,7 @@ dependencies = [
  "wasmtime-wasi-nn",
  "wasmtime-wasi-threads",
  "wasmtime-wast",
- "wast 65.0.2",
+ "wast 66.0.2",
  "wat",
  "windows-sys",
 ]
@@ -3459,7 +3479,7 @@ dependencies = [
  "wasmtime",
  "wasmtime-component-util",
  "wasmtime-wit-bindgen",
- "wit-parser",
+ "wit-parser 0.12.0",
 ]
 
 [[package]]
@@ -3483,7 +3503,7 @@ dependencies = [
  "object",
  "target-lexicon",
  "thiserror",
- "wasmparser",
+ "wasmparser 0.115.0",
  "wasmtime-cranelift-shared",
  "wasmtime-environ",
  "wasmtime-versioned-export-macros",
@@ -3519,8 +3539,8 @@ dependencies = [
  "serde_derive",
  "target-lexicon",
  "thiserror",
- "wasm-encoder",
- "wasmparser",
+ "wasm-encoder 0.35.0",
+ "wasmparser 0.115.0",
  "wasmprinter",
  "wasmtime-component-util",
  "wasmtime-types",
@@ -3535,7 +3555,7 @@ dependencies = [
  "component-fuzz-util",
  "env_logger 0.10.0",
  "libfuzzer-sys",
- "wasmparser",
+ "wasmparser 0.115.0",
  "wasmprinter",
  "wasmtime-environ",
  "wat",
@@ -3592,7 +3612,7 @@ dependencies = [
  "rand",
  "smallvec",
  "target-lexicon",
- "wasmparser",
+ "wasmparser 0.115.0",
  "wasmtime",
  "wasmtime-fuzzing",
 ]
@@ -3612,12 +3632,12 @@ dependencies = [
  "target-lexicon",
  "tempfile",
  "v8",
- "wasm-encoder",
+ "wasm-encoder 0.35.0",
  "wasm-mutate",
  "wasm-smith",
  "wasm-spec-interpreter",
  "wasmi",
- "wasmparser",
+ "wasmparser 0.115.0",
  "wasmprinter",
  "wasmtime",
  "wasmtime-wast",
@@ -3688,7 +3708,7 @@ dependencies = [
  "rand",
  "rustix 0.38.8",
  "sptr",
- "wasm-encoder",
+ "wasm-encoder 0.35.0",
  "wasmtime-asm-macros",
  "wasmtime-environ",
  "wasmtime-fiber",
@@ -3706,7 +3726,7 @@ dependencies = [
  "serde",
  "serde_derive",
  "thiserror",
- "wasmparser",
+ "wasmparser 0.115.0",
 ]
 
 [[package]]
@@ -3812,7 +3832,7 @@ dependencies = [
  "anyhow",
  "log",
  "wasmtime",
- "wast 65.0.2",
+ "wast 66.0.2",
 ]
 
 [[package]]
@@ -3824,7 +3844,7 @@ dependencies = [
  "gimli",
  "object",
  "target-lexicon",
- "wasmparser",
+ "wasmparser 0.115.0",
  "wasmtime-cranelift-shared",
  "wasmtime-environ",
  "winch-codegen",
@@ -3837,7 +3857,7 @@ dependencies = [
  "anyhow",
  "heck",
  "indexmap 2.0.0",
- "wit-parser",
+ "wit-parser 0.12.0",
 ]
 
 [[package]]
@@ -3855,23 +3875,23 @@ dependencies = [
 
 [[package]]
 name = "wast"
-version = "65.0.2"
+version = "66.0.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a55a88724cf8c2c0ebbf32c8e8f4ac0d6aa7ba6d73a1cfd94b254aa8f894317e"
+checksum = "93cb43b0ac6dd156f2c375735ccfd72b012a7c0a6e6d09503499b8d3cb6e6072"
 dependencies = [
  "leb128",
  "memchr",
  "unicode-width",
- "wasm-encoder",
+ "wasm-encoder 0.35.0",
 ]
 
 [[package]]
 name = "wat"
-version = "1.0.74"
+version = "1.0.77"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d83e1a8d86d008adc7bafa5cf4332d448699a08fcf2a715a71fbb75e2c5ca188"
+checksum = "e367582095d2903caeeea9acbb140e1db9c7677001efa4347c3687fd34fe7072"
 dependencies = [
- "wast 65.0.2",
+ "wast 66.0.2",
 ]
 
 [[package]]
@@ -3996,7 +4016,7 @@ dependencies = [
  "regalloc2",
  "smallvec",
  "target-lexicon",
- "wasmparser",
+ "wasmparser 0.115.0",
  "wasmtime-environ",
 ]
 
@@ -4041,7 +4061,7 @@ dependencies = [
  "similar",
  "target-lexicon",
  "toml",
- "wasmparser",
+ "wasmparser 0.115.0",
  "wasmtime-environ",
  "wat",
  "winch-codegen",
@@ -4142,8 +4162,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "7f0371c47784e7559efb422f74473e395b49f7101725584e2673657e0b4fc104"
 dependencies = [
  "anyhow",
- "wit-component",
- "wit-parser",
+ "wit-component 0.14.4",
+ "wit-parser 0.11.3",
 ]
 
 [[package]]
@@ -4157,7 +4177,7 @@ dependencies = [
  "wasm-metadata",
  "wit-bindgen-core",
  "wit-bindgen-rust-lib",
- "wit-component",
+ "wit-component 0.14.4",
 ]
 
 [[package]]
@@ -4182,7 +4202,7 @@ dependencies = [
  "wit-bindgen-core",
  "wit-bindgen-rust",
  "wit-bindgen-rust-lib",
- "wit-component",
+ "wit-component 0.14.4",
 ]
 
 [[package]]
@@ -4197,10 +4217,29 @@ dependencies = [
  "log",
  "serde",
  "serde_json",
- "wasm-encoder",
+ "wasm-encoder 0.33.2",
  "wasm-metadata",
- "wasmparser",
- "wit-parser",
+ "wasmparser 0.113.2",
+ "wit-parser 0.11.3",
+]
+
+[[package]]
+name = "wit-component"
+version = "0.15.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c1bc644bb4205a2ee74035e5d35958777575fa4c6dd38ce7226c7680be2861c1"
+dependencies = [
+ "anyhow",
+ "bitflags 2.3.3",
+ "indexmap 2.0.0",
+ "log",
+ "serde",
+ "serde_derive",
+ "serde_json",
+ "wasm-encoder 0.35.0",
+ "wasm-metadata",
+ "wasmparser 0.115.0",
+ "wit-parser 0.12.0",
 ]
 
 [[package]]
@@ -4221,6 +4260,23 @@ dependencies = [
  "url",
 ]
 
+[[package]]
+name = "wit-parser"
+version = "0.12.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d08c9557c65c428ac18a3cce80bf2527dbec24ab06639642c7db73f2c7613f93"
+dependencies = [
+ "anyhow",
+ "id-arena",
+ "indexmap 2.0.0",
+ "log",
+ "semver",
+ "serde",
+ "serde_derive",
+ "serde_json",
+ "unicode-xid",
+]
+
 [[package]]
 name = "witx"
 version = "0.9.1"
diff --git a/Cargo.toml b/Cargo.toml
index 7c5aa7d9b..f759a4ed4 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -210,15 +210,15 @@ is-terminal = "0.4.0"
 wit-bindgen = { version = "0.12.0", default-features = false }
 
 # wasm-tools family:
-wasmparser = "0.113.2"
-wat = "1.0.74"
-wast = "65.0.2"
-wasmprinter = "0.2.67"
-wasm-encoder = "0.33.2"
-wasm-smith = "0.12.18"
-wasm-mutate = "0.2.35"
-wit-parser = "0.11.3"
-wit-component = "0.14.4"
+wasmparser = "0.115.0"
+wat = "1.0.77"
+wast = "66.0.2"
+wasmprinter = "0.2.70"
+wasm-encoder = "0.35.0"
+wasm-smith = "0.12.21"
+wasm-mutate = "0.2.38"
+wit-parser = "0.12.0"
+wit-component = "0.15.0"
 
 # Non-Bytecode Alliance maintained dependencies:
 # --------------------------
diff --git a/cranelift/codegen/src/isa/riscv64/inst.isle b/cranelift/codegen/src/isa/riscv64/inst.isle
index afcdad717..6da824e62 100644
--- a/cranelift/codegen/src/isa/riscv64/inst.isle
+++ b/cranelift/codegen/src/isa/riscv64/inst.isle
@@ -1666,12 +1666,41 @@
 (rule (rv_brev8 rs1)
   (alu_rr_funct12 (AluOPRRI.Brev8) rs1))
 
+;; `Zbs` Extension Instructions
+
+(decl rv_bclr (XReg XReg) XReg)
+(rule (rv_bclr rs1 rs2)
+  (alu_rrr (AluOPRRR.Bclr) rs1 rs2))
+
+(decl rv_bclri (XReg Imm12) XReg)
+(rule (rv_bclri rs1 imm)
+  (alu_rr_imm12 (AluOPRRI.Bclri) rs1 imm))
+
+(decl rv_bext (XReg XReg) XReg)
+(rule (rv_bext rs1 rs2)
+  (alu_rrr (AluOPRRR.Bext) rs1 rs2))
+
+(decl rv_bexti (XReg Imm12) XReg)
+(rule (rv_bexti rs1 imm)
+  (alu_rr_imm12 (AluOPRRI.Bexti) rs1 imm))
+
+(decl rv_binv (XReg XReg) XReg)
+(rule (rv_binv rs1 rs2)
+  (alu_rrr (AluOPRRR.Binv) rs1 rs2))
+
+(decl rv_binvi (XReg Imm12) XReg)
+(rule (rv_binvi rs1 imm)
+  (alu_rr_imm12 (AluOPRRI.Binvi) rs1 imm))
+
+(decl rv_bset (XReg XReg) XReg)
+(rule (rv_bset rs1 rs2)
+  (alu_rrr (AluOPRRR.Bset) rs1 rs2))
+
 ;; Helper for emitting the `bseti` ("Single-Bit Set Immediate") instruction.
 (decl rv_bseti (XReg Imm12) XReg)
 (rule (rv_bseti rs1 imm)
   (alu_rr_imm12 (AluOPRRI.Bseti) rs1 imm))
 
-
 ;; `Zbkb` Extension Instructions
 
 ;; Helper for emitting the `pack` ("Pack low halves of registers") instruction.
diff --git a/cranelift/codegen/src/isa/riscv64/lower.isle b/cranelift/codegen/src/isa/riscv64/lower.isle
index 2fbeeed37..021a3503d 100644
--- a/cranelift/codegen/src/isa/riscv64/lower.isle
+++ b/cranelift/codegen/src/isa/riscv64/lower.isle
@@ -556,7 +556,7 @@
 (rule 1 (lower (has_type (fits_in_16 ty) (sdiv x y @ (iconst imm))))
   (if-let $true (has_m))
   (if (safe_divisor_from_imm64 ty imm))
-  (rv_divw (sext x) y))
+  (rv_divw (sext x) (sext y)))
 
 (rule 2 (lower (has_type $I32 (sdiv x y)))
   (if-let $true (has_m))
@@ -604,7 +604,7 @@
 (rule 1 (lower (has_type (fits_in_16 ty) (urem x y @ (iconst imm))))
   (if-let $true (has_m))
   (if (safe_divisor_from_imm64 ty imm))
-  (rv_remuw (zext x) y))
+  (rv_remuw (zext x) (zext y)))
 
 (rule 2 (lower (has_type $I32 (urem x y)))
   (if-let $true (has_m))
@@ -633,7 +633,7 @@
 (rule 1 (lower (has_type (fits_in_16 ty) (srem x y @ (iconst imm))))
   (if-let $true (has_m))
   (if (safe_divisor_from_imm64 ty imm))
-  (rv_remw (sext x) y))
+  (rv_remw (sext x) (sext y)))
 
 (rule 2 (lower (has_type $I32 (srem x y)))
   (if-let $true (has_m))
@@ -715,6 +715,74 @@
   (if-let x_imm (replicated_imm5 x))
   (rv_vand_vi y x_imm (unmasked) ty))
 
+;; `bclr{,i}` specializations from `zbs`
+
+(rule 13 (lower (has_type (fits_in_32 ty) (band x (bnot (ishl (i64_from_iconst 1) y)))))
+  (if-let $true (has_zbs))
+  (rv_bclr x (rv_andi y (imm12_const (u8_sub (ty_bits ty) 1)))))
+(rule 14 (lower (has_type (fits_in_32 ty) (band (bnot (ishl (i64_from_iconst 1) y)) x)))
+  (if-let $true (has_zbs))
+  (rv_bclr x (rv_andi y (imm12_const (u8_sub (ty_bits ty) 1)))))
+
+(rule 15 (lower (has_type $I64 (band x (bnot (ishl (i64_from_iconst 1) y)))))
+  (if-let $true (has_zbs))
+  (rv_bclr x y))
+(rule 16 (lower (has_type $I64 (band (bnot (ishl (i64_from_iconst 1) y)) x)))
+  (if-let $true (has_zbs))
+  (rv_bclr x y))
+
+(rule 17 (lower (has_type (fits_in_64 ty) (band x (u64_from_iconst n))))
+  (if-let $true (has_zbs))
+  (if-let imm (bclr_imm ty n))
+  (rv_bclri x imm))
+(rule 18 (lower (has_type (fits_in_64 ty) (band (u64_from_iconst n) x)))
+  (if-let $true (has_zbs))
+  (if-let imm (bclr_imm ty n))
+  (rv_bclri x imm))
+
+(decl pure partial bclr_imm (Type u64) Imm12)
+(extern constructor bclr_imm bclr_imm)
+
+;; `bext{,i}` specializations from `zbs`
+
+(rule 19 (lower (has_type $I32 (band (ushr x y) (u64_from_iconst 1))))
+  (if-let $true (has_zbs))
+  (rv_bext x (rv_andi y (imm12_const 31))))
+(rule 19 (lower (has_type $I32 (band (sshr x y) (u64_from_iconst 1))))
+  (if-let $true (has_zbs))
+  (rv_bext x (rv_andi y (imm12_const 31))))
+(rule 19 (lower (has_type $I32 (band (u64_from_iconst 1) (ushr x y))))
+  (if-let $true (has_zbs))
+  (rv_bext x (rv_andi y (imm12_const 31))))
+(rule 19 (lower (has_type $I32 (band (u64_from_iconst 1) (sshr x y))))
+  (if-let $true (has_zbs))
+  (rv_bext x (rv_andi y (imm12_const 31))))
+
+(rule 19 (lower (has_type $I64 (band (ushr x y) (u64_from_iconst 1))))
+  (if-let $true (has_zbs))
+  (rv_bext x y))
+(rule 19 (lower (has_type $I64 (band (sshr x y) (u64_from_iconst 1))))
+  (if-let $true (has_zbs))
+  (rv_bext x y))
+(rule 19 (lower (has_type $I64 (band (u64_from_iconst 1) (ushr x y))))
+  (if-let $true (has_zbs))
+  (rv_bext x y))
+(rule 19 (lower (has_type $I64 (band (u64_from_iconst 1) (sshr x y))))
+  (if-let $true (has_zbs))
+  (rv_bext x y))
+
+(rule 20 (lower (has_type $I32 (band (ushr x (imm12_from_value y)) (u64_from_iconst 1))))
+  (if-let $true (has_zbs))
+  (rv_bexti x (imm12_and y 31)))
+(rule 20 (lower (has_type $I32 (band (sshr x (imm12_from_value y)) (u64_from_iconst 1))))
+  (if-let $true (has_zbs))
+  (rv_bexti x (imm12_and y 31)))
+(rule 20 (lower (has_type $I64 (band (ushr x (imm12_from_value y)) (u64_from_iconst 1))))
+  (if-let $true (has_zbs))
+  (rv_bexti x (imm12_and y 63)))
+(rule 20 (lower (has_type $I64 (band (sshr x (imm12_from_value y)) (u64_from_iconst 1))))
+  (if-let $true (has_zbs))
+  (rv_bexti x (imm12_and y 63)))
 
 ;;;; Rules for `or` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 (rule 0 (lower (has_type (ty_int ty) (bor x y)))
@@ -773,6 +841,33 @@
   (if-let x_imm (replicated_imm5 x))
   (rv_vor_vi y x_imm (unmasked) ty))
 
+;; `bset{,i}` specializations from `zbs`
+
+(rule 13 (lower (has_type $I32 (bor x (ishl (i64_from_iconst 1) y))))
+  (if-let $true (has_zbs))
+  (rv_bset x (rv_andi y (imm12_const 31))))
+(rule 14 (lower (has_type $I32 (bor (ishl (i64_from_iconst 1) y) x)))
+  (if-let $true (has_zbs))
+  (rv_bset x (rv_andi y (imm12_const 31))))
+
+(rule 13 (lower (has_type $I64 (bor x (ishl (i64_from_iconst 1) y))))
+  (if-let $true (has_zbs))
+  (rv_bset x y))
+(rule 14 (lower (has_type $I64 (bor (ishl (i64_from_iconst 1) y) x)))
+  (if-let $true (has_zbs))
+  (rv_bset x y))
+
+(rule 15 (lower (has_type (fits_in_64 _) (bor x (u64_from_iconst n))))
+  (if-let $true (has_zbs))
+  (if-let imm (bseti_imm n))
+  (rv_bseti x imm))
+(rule 16 (lower (has_type (fits_in_64 _) (bor (u64_from_iconst n) x)))
+  (if-let $true (has_zbs))
+  (if-let imm (bseti_imm n))
+  (rv_bseti x imm))
+
+(decl pure partial bseti_imm (u64) Imm12)
+(extern constructor bseti_imm bseti_imm)
 
 ;;;; Rules for `xor` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 (rule 0 (lower (has_type (fits_in_64 (ty_int ty)) (bxor x y)))
@@ -810,6 +905,33 @@
   (if-let x_imm (replicated_imm5 x))
   (rv_vxor_vi y x_imm (unmasked) ty))
 
+;; `binv{,i}` specializations from `zbs`
+
+(rule 13 (lower (has_type $I32 (bxor x (ishl (i64_from_iconst 1) y))))
+  (if-let $true (has_zbs))
+  (rv_binv x (rv_andi y (imm12_const 31))))
+(rule 14 (lower (has_type $I32 (bxor (ishl (i64_from_iconst 1) y) x)))
+  (if-let $true (has_zbs))
+  (rv_binv x (rv_andi y (imm12_const 31))))
+
+(rule 13 (lower (has_type $I64 (bxor x (ishl (i64_from_iconst 1) y))))
+  (if-let $true (has_zbs))
+  (rv_binv x y))
+(rule 14 (lower (has_type $I64 (bxor (ishl (i64_from_iconst 1) y) x)))
+  (if-let $true (has_zbs))
+  (rv_binv x y))
+
+(rule 15 (lower (has_type (fits_in_64 _) (bxor x (u64_from_iconst n))))
+  (if-let $true (has_zbs))
+  (if-let imm (binvi_imm n))
+  (rv_binvi x imm))
+(rule 16 (lower (has_type (fits_in_64 _) (bxor (u64_from_iconst n) x)))
+  (if-let $true (has_zbs))
+  (if-let imm (binvi_imm n))
+  (rv_binvi x imm))
+
+(decl pure partial binvi_imm (u64) Imm12)
+(extern constructor binvi_imm binvi_imm)
 
 ;;;; Rules for `bnot` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 (rule 0 (lower (has_type (ty_scalar ty) (bnot x)))
diff --git a/cranelift/codegen/src/isa/riscv64/lower/isle.rs b/cranelift/codegen/src/isa/riscv64/lower/isle.rs
index d4d449d0e..232e35e08 100644
--- a/cranelift/codegen/src/isa/riscv64/lower/isle.rs
+++ b/cranelift/codegen/src/isa/riscv64/lower/isle.rs
@@ -521,6 +521,26 @@ impl generated_code::Context for RV64IsleContext<'_, '_, MInst, Riscv64Backend>
     fn vec_alu_rr_dst_type(&mut self, op: &VecAluOpRR) -> Type {
         MInst::canonical_type_for_rc(op.dst_regclass())
     }
+
+    fn bclr_imm(&mut self, ty: Type, i: u64) -> Option<Imm12> {
+        // Only consider those bits in the immediate which are up to the width
+        // of `ty`.
+        let neg = !i & (u64::MAX >> (64 - ty.bits()));
+        if neg.count_ones() != 1 {
+            return None;
+        }
+        Imm12::maybe_from_u64(neg.trailing_zeros().into())
+    }
+
+    fn binvi_imm(&mut self, i: u64) -> Option<Imm12> {
+        if i.count_ones() != 1 {
+            return None;
+        }
+        Imm12::maybe_from_u64(i.trailing_zeros().into())
+    }
+    fn bseti_imm(&mut self, i: u64) -> Option<Imm12> {
+        self.binvi_imm(i)
+    }
 }
 
 /// The main entry point for lowering with ISLE.
diff --git a/crates/wasmtime/src/config.rs b/crates/wasmtime/src/config.rs
index 3b9aa6cad..c3b88e5e6 100644
--- a/crates/wasmtime/src/config.rs
+++ b/crates/wasmtime/src/config.rs
@@ -230,6 +230,10 @@ impl Config {
         ret.wasm_simd(true);
         ret.wasm_backtrace_details(WasmBacktraceDetails::Environment);
 
+        ret.wasm_relaxed_simd(false);
+        ret.wasm_threads(false);
+        ret.wasm_multi_memory(false);
+
         // This is on-by-default in `wasmparser` since it's a stage 4+ proposal
         // but it's not implemented in Wasmtime yet so disable it.
         ret.features.tail_call = false;
diff --git a/crates/wast/src/wast.rs b/crates/wast/src/wast.rs
index 32d4cc2d0..defb6dd08 100644
--- a/crates/wast/src/wast.rs
+++ b/crates/wast/src/wast.rs
@@ -465,6 +465,10 @@ impl<T> WastContext<T> {
                 }
             }
             AssertException { .. } => bail!("unimplemented assert_exception"),
+
+            Thread(_) => bail!("unimplemented `thread`"),
+
+            Wait { .. } => bail!("unimplemented `wait`"),
         }
 
         Ok(())
diff --git a/supply-chain/audits.toml b/supply-chain/audits.toml
index 70303719b..8b74c5ad6 100644
--- a/supply-chain/audits.toml
+++ b/supply-chain/audits.toml
@@ -3386,3 +3386,9 @@ criteria = "safe-to-deploy"
 user-id = 6825 # Dan Gohman (sunfishcode)
 start = "2019-08-20"
 end = "2024-07-14"
+
+[[trusted.wit-parser]]
+criteria = "safe-to-deploy"
+user-id = 696 # Nick Fitzgerald (fitzgen)
+start = "2023-10-12"
+end = "2024-10-17"
diff --git a/supply-chain/imports.lock b/supply-chain/imports.lock
index 27558affd..727934b53 100644
--- a/supply-chain/imports.lock
+++ b/supply-chain/imports.lock
@@ -831,6 +831,13 @@ user-id = 1
 user-login = "alexcrichton"
 user-name = "Alex Crichton"
 
+[[publisher.wasm-encoder]]
+version = "0.35.0"
+when = "2023-10-14"
+user-id = 1
+user-login = "alexcrichton"
+user-name = "Alex Crichton"
+
 [[publisher.wasm-metadata]]
 version = "0.10.6"
 when = "2023-09-26"
@@ -838,6 +845,13 @@ user-id = 1
 user-login = "alexcrichton"
 user-name = "Alex Crichton"
 
+[[publisher.wasm-metadata]]
+version = "0.10.9"
+when = "2023-10-14"
+user-id = 1
+user-login = "alexcrichton"
+user-name = "Alex Crichton"
+
 [[publisher.wasm-mutate]]
 version = "0.2.35"
 when = "2023-09-26"
@@ -845,6 +859,13 @@ user-id = 1
 user-login = "alexcrichton"
 user-name = "Alex Crichton"
 
+[[publisher.wasm-mutate]]
+version = "0.2.38"
+when = "2023-10-14"
+user-id = 1
+user-login = "alexcrichton"
+user-name = "Alex Crichton"
+
 [[publisher.wasm-smith]]
 version = "0.12.18"
 when = "2023-09-26"
@@ -852,6 +873,13 @@ user-id = 1
 user-login = "alexcrichton"
 user-name = "Alex Crichton"
 
+[[publisher.wasm-smith]]
+version = "0.12.21"
+when = "2023-10-14"
+user-id = 1
+user-login = "alexcrichton"
+user-name = "Alex Crichton"
+
 [[publisher.wasmparser]]
 version = "0.113.2"
 when = "2023-09-26"
@@ -859,6 +887,13 @@ user-id = 1
 user-login = "alexcrichton"
 user-name = "Alex Crichton"
 
+[[publisher.wasmparser]]
+version = "0.115.0"
+when = "2023-10-14"
+user-id = 1
+user-login = "alexcrichton"
+user-name = "Alex Crichton"
+
 [[publisher.wasmprinter]]
 version = "0.2.67"
 when = "2023-09-26"
@@ -866,6 +901,13 @@ user-id = 1
 user-login = "alexcrichton"
 user-name = "Alex Crichton"
 
+[[publisher.wasmprinter]]
+version = "0.2.70"
+when = "2023-10-14"
+user-id = 1
+user-login = "alexcrichton"
+user-name = "Alex Crichton"
+
 [[publisher.wasmtime]]
 version = "13.0.0"
 when = "2023-09-20"
@@ -1017,6 +1059,13 @@ user-id = 1
 user-login = "alexcrichton"
 user-name = "Alex Crichton"
 
+[[publisher.wast]]
+version = "66.0.2"
+when = "2023-10-14"
+user-id = 1
+user-login = "alexcrichton"
+user-name = "Alex Crichton"
+
 [[publisher.wat]]
 version = "1.0.74"
 when = "2023-09-26"
@@ -1024,6 +1073,13 @@ user-id = 1
 user-login = "alexcrichton"
 user-name = "Alex Crichton"
 
+[[publisher.wat]]
+version = "1.0.77"
+when = "2023-10-14"
+user-id = 1
+user-login = "alexcrichton"
+user-name = "Alex Crichton"
+
 [[publisher.wiggle]]
 version = "13.0.0"
 when = "2023-09-20"
@@ -1174,6 +1230,13 @@ user-id = 1
 user-login = "alexcrichton"
 user-name = "Alex Crichton"
 
+[[publisher.wit-component]]
+version = "0.15.0"
+when = "2023-10-14"
+user-id = 1
+user-login = "alexcrichton"
+user-name = "Alex Crichton"
+
 [[publisher.wit-parser]]
 version = "0.11.3"
 when = "2023-09-27"
@@ -1181,6 +1244,13 @@ user-id = 1
 user-login = "alexcrichton"
 user-name = "Alex Crichton"
 
+[[publisher.wit-parser]]
+version = "0.12.0"
+when = "2023-10-12"
+user-id = 696
+user-login = "fitzgen"
+user-name = "Nick Fitzgerald"
+
 [[audits.embark-studios.wildcard-audits.spdx]]
 who = "Jake Shadle <opensource@embark-studios.com>"
 criteria = "safe-to-deploy"
diff --git a/winch/codegen/src/isa/x64/asm.rs b/winch/codegen/src/isa/x64/asm.rs
index ddee15bcf..adddda012 100644
--- a/winch/codegen/src/isa/x64/asm.rs
+++ b/winch/codegen/src/isa/x64/asm.rs
@@ -1,7 +1,7 @@
 //! Assembler library implementation for x64.
 
 use crate::{
-    isa::reg::{Reg, RegClass},
+    isa::reg::Reg,
     masm::{CmpKind, DivKind, OperandSize, RemKind, RoundingMode, ShiftKind},
 };
 use cranelift_codegen::{
@@ -409,32 +409,13 @@ impl Assembler {
 
     /// "and" two registers.
     pub fn and_rr(&mut self, src: Reg, dst: Reg, size: OperandSize) {
-        match dst.class() {
-            RegClass::Int => {
-                self.emit(Inst::AluRmiR {
-                    size: size.into(),
-                    op: AluRmiROpcode::And,
-                    src1: dst.into(),
-                    src2: src.into(),
-                    dst: dst.into(),
-                });
-            }
-            RegClass::Float => {
-                let op = match size {
-                    OperandSize::S32 => SseOpcode::Andps,
-                    OperandSize::S64 => SseOpcode::Andpd,
-                    OperandSize::S128 => unreachable!(),
-                };
-
-                self.emit(Inst::XmmRmR {
-                    op,
-                    src1: dst.into(),
-                    src2: XmmMemAligned::from(Xmm::from(src)),
-                    dst: dst.into(),
-                });
-            }
-            RegClass::Vector => unreachable!(),
-        }
+        self.emit(Inst::AluRmiR {
+            size: size.into(),
+            op: AluRmiROpcode::And,
+            src1: dst.into(),
+            src2: src.into(),
+            dst: dst.into(),
+        });
     }
 
     pub fn and_ir(&mut self, imm: i32, dst: Reg, size: OperandSize) {
@@ -448,6 +429,22 @@ impl Assembler {
         });
     }
 
+    /// "and" two float registers.
+    pub fn xmm_and_rr(&mut self, src: Reg, dst: Reg, size: OperandSize) {
+        let op = match size {
+            OperandSize::S32 => SseOpcode::Andps,
+            OperandSize::S64 => SseOpcode::Andpd,
+            OperandSize::S128 => unreachable!(),
+        };
+
+        self.emit(Inst::XmmRmR {
+            op,
+            src1: dst.into(),
+            src2: XmmMemAligned::from(Xmm::from(src)),
+            dst: dst.into(),
+        });
+    }
+
     pub fn gpr_to_xmm(&mut self, src: Reg, dst: Reg, size: OperandSize) {
         let op = match size {
             OperandSize::S32 => SseOpcode::Movd,
@@ -487,32 +484,13 @@ impl Assembler {
 
     /// Logical exclusive or with registers.
     pub fn xor_rr(&mut self, src: Reg, dst: Reg, size: OperandSize) {
-        match dst.class() {
-            RegClass::Int => {
-                self.emit(Inst::AluRmiR {
-                    size: size.into(),
-                    op: AluRmiROpcode::Xor,
-                    src1: dst.into(),
-                    src2: src.into(),
-                    dst: dst.into(),
-                });
-            }
-            RegClass::Float => {
-                let op = match size {
-                    OperandSize::S32 => SseOpcode::Xorps,
-                    OperandSize::S64 => SseOpcode::Xorpd,
-                    OperandSize::S128 => unreachable!(),
-                };
-
-                self.emit(Inst::XmmRmR {
-                    op,
-                    src1: dst.into(),
-                    src2: XmmMemAligned::from(Xmm::from(src)),
-                    dst: dst.into(),
-                });
-            }
-            RegClass::Vector => todo!(),
-        }
+        self.emit(Inst::AluRmiR {
+            size: size.into(),
+            op: AluRmiROpcode::Xor,
+            src1: dst.into(),
+            src2: src.into(),
+            dst: dst.into(),
+        });
     }
 
     pub fn xor_ir(&mut self, imm: i32, dst: Reg, size: OperandSize) {
@@ -527,6 +505,22 @@ impl Assembler {
         });
     }
 
+    /// Logical exclusive or with float registers.
+    pub fn xmm_xor_rr(&mut self, src: Reg, dst: Reg, size: OperandSize) {
+        let op = match size {
+            OperandSize::S32 => SseOpcode::Xorps,
+            OperandSize::S64 => SseOpcode::Xorpd,
+            OperandSize::S128 => unreachable!(),
+        };
+
+        self.emit(Inst::XmmRmR {
+            op,
+            src1: dst.into(),
+            src2: XmmMemAligned::from(Xmm::from(src)),
+            dst: dst.into(),
+        });
+    }
+
     /// Shift with register and register.
     pub fn shift_rr(&mut self, src: Reg, dst: Reg, kind: ShiftKind, size: OperandSize) {
         self.emit(Inst::ShiftR {
@@ -823,7 +817,9 @@ impl Assembler {
         });
     }
 
-    pub fn rounds(&mut self, src: Reg, dst: Reg, mode: RoundingMode, size: OperandSize) {
+    /// Perform rounding operation on float register src and place results in
+    /// float register dst.
+    pub fn xmm_rounds_rr(&mut self, src: Reg, dst: Reg, mode: RoundingMode, size: OperandSize) {
         let op = match size {
             OperandSize::S32 => SseOpcode::Roundss,
             OperandSize::S64 => SseOpcode::Roundsd,
diff --git a/winch/codegen/src/isa/x64/masm.rs b/winch/codegen/src/isa/x64/masm.rs
index e580253fd..8b1ddcad8 100644
--- a/winch/codegen/src/isa/x64/masm.rs
+++ b/winch/codegen/src/isa/x64/masm.rs
@@ -380,7 +380,7 @@ impl Masm for MacroAssembler {
         self.load_constant(&mask, scratch_gpr, size);
         let scratch_xmm = regs::scratch_xmm();
         self.asm.gpr_to_xmm(scratch_gpr, scratch_xmm, size);
-        self.asm.xor_rr(scratch_xmm, dst, size);
+        self.asm.xmm_xor_rr(scratch_xmm, dst, size);
     }
 
     fn float_abs(&mut self, dst: Reg, size: OperandSize) {
@@ -394,13 +394,13 @@ impl Masm for MacroAssembler {
         self.load_constant(&mask, scratch_gpr, size);
         let scratch_xmm = regs::scratch_xmm();
         self.asm.gpr_to_xmm(scratch_gpr, scratch_xmm, size);
-        self.asm.and_rr(scratch_xmm, dst, size);
+        self.asm.xmm_and_rr(scratch_xmm, dst, size);
     }
 
     fn float_round(&mut self, mode: RoundingMode, context: &mut CodeGenContext, size: OperandSize) {
         if self.flags.has_sse41() {
             let src = context.pop_to_reg(self, None);
-            self.asm.rounds(src.into(), src.into(), mode, size);
+            self.asm.xmm_rounds_rr(src.into(), src.into(), mode, size);
             context.stack.push(src.into());
         } else {
             FnCall::emit::<Self, Self::Ptr, _>(self, context, |context| {


Test patch:
diff --git a/cranelift/filetests/filetests/isa/riscv64/wasm/zbs.wat b/cranelift/filetests/filetests/isa/riscv64/wasm/zbs.wat
new file mode 100644
index 000000000..3d14406d5
--- /dev/null
+++ b/cranelift/filetests/filetests/isa/riscv64/wasm/zbs.wat
@@ -0,0 +1,398 @@
+;;! target = "riscv64"
+;;! compile = true
+;;! settings = ["has_zbs", "opt_level=speed"]
+
+(module
+  (func (export "bclr32") (param i32 i32) (result i32)
+    (i32.and (local.get 0) (i32.xor (i32.shl (i32.const 1) (local.get 1)) (i32.const -1)))
+  )
+  (func (export "bclr64") (param i64 i64) (result i64)
+    (i64.and (i64.xor (i64.shl (i64.const 1) (local.get 1)) (i64.const -1)) (local.get 0))
+  )
+  (func (export "bclri32_4") (param i32) (result i32)
+    (i32.and (local.get 0) (i32.xor (i32.shl (i32.const 1) (i32.const 4)) (i32.const -1)))
+  )
+  (func (export "bclri32_20") (param i32) (result i32)
+    (i32.and (i32.xor (i32.shl (i32.const 1) (i32.const 20)) (i32.const -1)) (local.get 0))
+  )
+  (func (export "bclri64_4") (param i64) (result i64)
+    (i64.and (local.get 0) (i64.xor (i64.shl (i64.const 1) (i64.const 4)) (i64.const -1)))
+  )
+  (func (export "bclri64_52") (param i64) (result i64)
+    (i64.and (local.get 0) (i64.xor (i64.shl (i64.const 1) (i64.const 52)) (i64.const -1)))
+  )
+
+  (func (export "bext32_1") (param i32 i32) (result i32)
+    (i32.and (i32.shr_u (local.get 0) (local.get 1)) (i32.const 1))
+  )
+  (func (export "bext32_2") (param i32 i32) (result i32)
+    (i32.and (i32.shr_s (local.get 0) (local.get 1)) (i32.const 1))
+  )
+  (func (export "bext32_3") (param i32 i32) (result i32)
+    (i32.and (i32.const 1) (i32.shr_u (local.get 0) (local.get 1)))
+  )
+  (func (export "bext32_4") (param i32 i32) (result i32)
+    (i32.and (i32.const 1) (i32.shr_s (local.get 0) (local.get 1)))
+  )
+  (func (export "bext64_1") (param i64 i64) (result i64)
+    (i64.and (i64.shr_u (local.get 0) (local.get 1)) (i64.const 1))
+  )
+  (func (export "bext64_2") (param i64 i64) (result i64)
+    (i64.and (i64.shr_s (local.get 0) (local.get 1)) (i64.const 1))
+  )
+  (func (export "bext64_3") (param i64 i64) (result i64)
+    (i64.and (i64.const 1) (i64.shr_u (local.get 0) (local.get 1)))
+  )
+  (func (export "bext64_4") (param i64 i64) (result i64)
+    (i64.and (i64.const 1) (i64.shr_s (local.get 0) (local.get 1)))
+  )
+
+  (func (export "bexti32_1") (param i32) (result i32)
+    (i32.and (i32.shr_u (local.get 0) (i32.const 10)) (i32.const 1))
+  )
+  (func (export "bexti32_2") (param i32) (result i32)
+    (i32.and (i32.shr_s (local.get 0) (i32.const 20)) (i32.const 1))
+  )
+  (func (export "bexti32_3") (param i32) (result i32)
+    (i32.and (i32.shr_u (i32.const 1) (local.get 0) (i32.const 30)))
+  )
+  (func (export "bexti32_4") (param i32) (result i32)
+    (i32.and (i32.shr_s (i32.const 1) (local.get 0) (i32.const 40)))
+  )
+  (func (export "bexti64_1") (param i64) (result i64)
+    (i64.and (i64.shr_u (local.get 0) (i64.const 10)) (i64.const 1))
+  )
+  (func (export "bexti64_2") (param i64) (result i64)
+    (i64.and (i64.shr_s (local.get 0) (i64.const 20)) (i64.const 1))
+  )
+  (func (export "bexti64_3") (param i64) (result i64)
+    (i64.and (i64.shr_u (i64.const 1) (local.get 0) (i64.const 30)))
+  )
+  (func (export "bexti64_4") (param i64) (result i64)
+    (i64.and (i64.shr_s (i64.const 1) (local.get 0) (i64.const 40)))
+  )
+
+  (func (export "binv32_1") (param i32 i32) (result i32)
+    (i32.xor (local.get 0) (i32.shl (i32.const 1) (local.get 1)))
+  )
+  (func (export "binv32_2") (param i32 i32) (result i32)
+    (i32.xor (i32.shl (i32.const 1) (local.get 1)) (local.get 0))
+  )
+  (func (export "binv64_1") (param i64 i64) (result i64)
+    (i64.xor (local.get 0) (i64.shl (i64.const 1) (local.get 1)))
+  )
+  (func (export "binv64_2") (param i64 i64) (result i64)
+    (i64.xor (i64.shl (i64.const 1) (local.get 1)) (local.get 0))
+  )
+  (func (export "binvi32_1") (param i32) (result i32)
+    (i32.xor (local.get 0) (i32.shl (i32.const 1) (i32.const 10)))
+  )
+  (func (export "binvi32_2") (param i32) (result i32)
+    (i32.xor (i32.shl (i32.const 1) (i32.const 20)) (local.get 0))
+  )
+  (func (export "binvi64_1") (param i64) (result i64)
+    (i64.xor (local.get 0) (i64.shl (i64.const 1) (i64.const 30)))
+  )
+  (func (export "binvi64_2") (param i64) (result i64)
+    (i64.xor (i64.shl (i64.const 1) (i64.const 40)) (local.get 0))
+  )
+
+  (func (export "bset32_1") (param i32 i32) (result i32)
+    (i32.or (local.get 0) (i32.shl (i32.const 1) (local.get 1)))
+  )
+  (func (export "bset32_2") (param i32 i32) (result i32)
+    (i32.or (i32.shl (i32.const 1) (local.get 1)) (local.get 0))
+  )
+  (func (export "bset64_1") (param i64 i64) (result i64)
+    (i64.or (local.get 0) (i64.shl (i64.const 1) (local.get 1)))
+  )
+  (func (export "bset64_2") (param i64 i64) (result i64)
+    (i64.or (i64.shl (i64.const 1) (local.get 1)) (local.get 0))
+  )
+  (func (export "bseti32_1") (param i32) (result i32)
+    (i32.or (local.get 0) (i32.shl (i32.const 1) (i32.const 10)))
+  )
+  (func (export "bseti32_2") (param i32) (result i32)
+    (i32.or (i32.shl (i32.const 1) (i32.const 20)) (local.get 0))
+  )
+  (func (export "bseti64_1") (param i64) (result i64)
+    (i64.or (local.get 0) (i64.shl (i64.const 1) (i64.const 30)))
+  )
+  (func (export "bseti64_2") (param i64) (result i64)
+    (i64.or (i64.shl (i64.const 1) (i64.const 40)) (local.get 0))
+  )
+)
+;; function u0:0:
+;; block0:
+;;   j label1
+;; block1:
+;;   andi a5,a1,31
+;;   bclr a0,a0,a5
+;;   ret
+;;
+;; function u0:1:
+;; block0:
+;;   j label1
+;; block1:
+;;   bclr a0,a0,a1
+;;   ret
+;;
+;; function u0:2:
+;; block0:
+;;   j label1
+;; block1:
+;;   bclri a0,a0,4
+;;   ret
+;;
+;; function u0:3:
+;; block0:
+;;   j label1
+;; block1:
+;;   bclri a0,a0,20
+;;   ret
+;;
+;; function u0:4:
+;; block0:
+;;   j label1
+;; block1:
+;;   bclri a0,a0,4
+;;   ret
+;;
+;; function u0:5:
+;; block0:
+;;   j label1
+;; block1:
+;;   bclri a0,a0,52
+;;   ret
+;;
+;; function u0:6:
+;; block0:
+;;   j label1
+;; block1:
+;;   andi a5,a1,31
+;;   bext a0,a0,a5
+;;   ret
+;;
+;; function u0:7:
+;; block0:
+;;   j label1
+;; block1:
+;;   andi a5,a1,31
+;;   bext a0,a0,a5
+;;   ret
+;;
+;; function u0:8:
+;; block0:
+;;   j label1
+;; block1:
+;;   andi a5,a1,31
+;;   bext a0,a0,a5
+;;   ret
+;;
+;; function u0:9:
+;; block0:
+;;   j label1
+;; block1:
+;;   andi a5,a1,31
+;;   bext a0,a0,a5
+;;   ret
+;;
+;; function u0:10:
+;; block0:
+;;   j label1
+;; block1:
+;;   bext a0,a0,a1
+;;   ret
+;;
+;; function u0:11:
+;; block0:
+;;   j label1
+;; block1:
+;;   bext a0,a0,a1
+;;   ret
+;;
+;; function u0:12:
+;; block0:
+;;   j label1
+;; block1:
+;;   bext a0,a0,a1
+;;   ret
+;;
+;; function u0:13:
+;; block0:
+;;   j label1
+;; block1:
+;;   bext a0,a0,a1
+;;   ret
+;;
+;; function u0:14:
+;; block0:
+;;   j label1
+;; block1:
+;;   bexti a0,a0,10
+;;   ret
+;;
+;; function u0:15:
+;; block0:
+;;   j label1
+;; block1:
+;;   bexti a0,a0,20
+;;   ret
+;;
+;; function u0:16:
+;; block0:
+;;   j label1
+;; block1:
+;;   bexti a0,a0,30
+;;   ret
+;;
+;; function u0:17:
+;; block0:
+;;   j label1
+;; block1:
+;;   bexti a0,a0,8
+;;   ret
+;;
+;; function u0:18:
+;; block0:
+;;   j label1
+;; block1:
+;;   bexti a0,a0,10
+;;   ret
+;;
+;; function u0:19:
+;; block0:
+;;   j label1
+;; block1:
+;;   bexti a0,a0,20
+;;   ret
+;;
+;; function u0:20:
+;; block0:
+;;   j label1
+;; block1:
+;;   bexti a0,a0,30
+;;   ret
+;;
+;; function u0:21:
+;; block0:
+;;   j label1
+;; block1:
+;;   bexti a0,a0,40
+;;   ret
+;;
+;; function u0:22:
+;; block0:
+;;   j label1
+;; block1:
+;;   andi a5,a1,31
+;;   binv a0,a0,a5
+;;   ret
+;;
+;; function u0:23:
+;; block0:
+;;   j label1
+;; block1:
+;;   andi a5,a1,31
+;;   binv a0,a0,a5
+;;   ret
+;;
+;; function u0:24:
+;; block0:
+;;   j label1
+;; block1:
+;;   binv a0,a0,a1
+;;   ret
+;;
+;; function u0:25:
+;; block0:
+;;   j label1
+;; block1:
+;;   binv a0,a0,a1
+;;   ret
+;;
+;; function u0:26:
+;; block0:
+;;   j label1
+;; block1:
+;;   binvi a0,a0,10
+;;   ret
+;;
+;; function u0:27:
+;; block0:
+;;   j label1
+;; block1:
+;;   binvi a0,a0,20
+;;   ret
+;;
+;; function u0:28:
+;; block0:
+;;   j label1
+;; block1:
+;;   binvi a0,a0,30
+;;   ret
+;;
+;; function u0:29:
+;; block0:
+;;   j label1
+;; block1:
+;;   binvi a0,a0,40
+;;   ret
+;;
+;; function u0:30:
+;; block0:
+;;   j label1
+;; block1:
+;;   andi a5,a1,31
+;;   bset a0,a0,a5
+;;   ret
+;;
+;; function u0:31:
+;; block0:
+;;   j label1
+;; block1:
+;;   andi a5,a1,31
+;;   bset a0,a0,a5
+;;   ret
+;;
+;; function u0:32:
+;; block0:
+;;   j label1
+;; block1:
+;;   bset a0,a0,a1
+;;   ret
+;;
+;; function u0:33:
+;; block0:
+;;   j label1
+;; block1:
+;;   bset a0,a0,a1
+;;   ret
+;;
+;; function u0:34:
+;; block0:
+;;   j label1
+;; block1:
+;;   bseti a0,a0,10
+;;   ret
+;;
+;; function u0:35:
+;; block0:
+;;   j label1
+;; block1:
+;;   bseti a0,a0,20
+;;   ret
+;;
+;; function u0:36:
+;; block0:
+;;   j label1
+;; block1:
+;;   bseti a0,a0,30
+;;   ret
+;;
+;; function u0:37:
+;; block0:
+;;   j label1
+;; block1:
+;;   bseti a0,a0,40
+;;   ret
diff --git a/cranelift/filetests/filetests/runtests/urem.clif b/cranelift/filetests/filetests/runtests/urem.clif
index 42297ad37..3fa202424 100644
--- a/cranelift/filetests/filetests/runtests/urem.clif
+++ b/cranelift/filetests/filetests/runtests/urem.clif
@@ -135,3 +135,13 @@ block0(v0: i8):
 ; run: %urem_imm_i8(-19) == 0
 ; run: %urem_imm_i8(0xC0) == 0
 ; run: %urem_imm_i8(0x80) == 2
+
+
+function %constant_inputs() -> i8  {
+block0:
+    v3 = iconst.i8 208
+    v11 = urem v3, v3  ; v3 = 208, v3 = 208
+    return v11
+}
+
+; run: %constant_inputs() == 0