Repository: bytecodealliance/wasmtime
Pull request #6092 (2023-03-23 14:54:27)

x64: Add AVX support for some more float-related instructions
This PR adds AVX support for `vsqrts{s,d}`, `vrounds{s,d}`, and `vcvt{ss2sd,sd2ss}`. After this I think that `XmmCmpRmR` is the only remaining non-VEX instruction, which I hope to tackle next.


Patch:
diff --git a/.github/actions/github-release/main.js b/.github/actions/github-release/main.js
index b2d75d3fa..d61b24ed5 100644
--- a/.github/actions/github-release/main.js
+++ b/.github/actions/github-release/main.js
@@ -57,13 +57,11 @@ async function runOnce() {
         console.log("ERROR: ", JSON.stringify(e.data, null, 2));
         core.info(`creating dev tag`);
         try {
-          await octokit.git.createTag({
+          await octokit.rest.git.createRef({
             owner,
             repo,
-            tag: 'dev',
-            message: 'dev release',
-            object: sha,
-            type: 'commit',
+            ref: 'refs/tags/dev',
+            sha,
           });
         } catch (e) {
           // we might race with others, so assume someone else has created the
diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml
index 1ceb2e2b0..1b1e60ca5 100644
--- a/.github/workflows/main.yml
+++ b/.github/workflows/main.yml
@@ -82,7 +82,7 @@ jobs:
     if: needs.determine.outputs.audit
     runs-on: ubuntu-latest
     env:
-      CARGO_VET_VERSION: 0.5.0
+      CARGO_VET_VERSION: 0.6.1
     steps:
     - uses: actions/checkout@v3
       with:
@@ -363,7 +363,7 @@ jobs:
     name: ${{ matrix.name }}
     runs-on: ${{ matrix.os }}
     env:
-      QEMU_BUILD_VERSION: 6.1.0
+      QEMU_BUILD_VERSION: 7.2.0
     strategy:
       matrix: ${{ fromJson(needs.determine.outputs.test-matrix) }}
     steps:
@@ -387,7 +387,7 @@ jobs:
     - uses: actions/cache@v3
       with:
         path: ${{ runner.tool_cache }}/qemu
-        key: qemu-${{ matrix.target }}-${{ env.QEMU_BUILD_VERSION }}-patchmadvise2
+        key: qemu-${{ matrix.target }}-${{ env.QEMU_BUILD_VERSION }}
       if: matrix.target != '' && matrix.os == 'ubuntu-latest'
     - name: Install cross-compilation tools
       run: |
@@ -420,7 +420,6 @@ jobs:
         # quickly.
         curl https://download.qemu.org/qemu-$QEMU_BUILD_VERSION.tar.xz | tar xJf -
         cd qemu-$QEMU_BUILD_VERSION
-        patch -p1 < $GITHUB_WORKSPACE/ci/qemu-madvise.patch
         ./configure --target-list=${{ matrix.qemu_target }} --prefix=${{ runner.tool_cache}}/qemu --disable-tools --disable-slirp --disable-fdt --disable-capstone --disable-docs
         ninja -C build install
         touch ${{ runner.tool_cache }}/qemu/built
diff --git a/CODEOWNERS b/CODEOWNERS
new file mode 100644
index 000000000..61d8a372d
--- /dev/null
+++ b/CODEOWNERS
@@ -0,0 +1,42 @@
+# In this project, we use CODEOWNERS to identify people who are likely to know
+# who should review a pull request.
+#
+# People listed in this file are committing to respond in a timely fashion to
+# PRs in the selected areas. However, that response doesn't have to be a full
+# code review; it could also take any of these forms:
+#
+# - "I intend to review this but I can't yet. Please leave me a message if I
+#   haven't responded by (a specific date in the near future)."
+#
+# - "I think (a specific other contributor) should review this." (Note that the
+#   best reviewer for a PR may not necessarily be listed in this file.)
+#
+# People must only be added to this file if they've agreed to provide one of
+# the above responses in a reasonable amount of time for every PR to which
+# they're assigned.
+#
+# We only ask for this commitment from people who are employed full-time to
+# work on this project. We gratefully welcome reviews from other contributors,
+# but we don't believe it's fair to ask volunteers to respond quickly.
+
+# If none of the later patterns match, assign to anyone. This team is the
+# parent of all the other teams and automatically includes everyone on those
+# teams.
+* @bytecodealliance/wasmtime-default-reviewers
+
+# Some parts of the project require more specialized knowledge. In those areas
+# we designate smaller groups who are more likely to be aware of who's working
+# in specific areas.
+
+# Wasmtime
+/crates/   @bytecodealliance/wasmtime-core-reviewers
+/examples/ @bytecodealliance/wasmtime-core-reviewers
+/src/      @bytecodealliance/wasmtime-core-reviewers
+/tests/    @bytecodealliance/wasmtime-core-reviewers
+
+# Cranelift/Winch compilers
+/cranelift/ @bytecodealliance/wasmtime-compiler-reviewers
+/winch/     @bytecodealliance/wasmtime-compiler-reviewers
+
+# Fuzz testing
+/fuzz/ @bytecodealliance/wasmtime-fuzz-reviewers
diff --git a/ci/qemu-madvise.patch b/ci/qemu-madvise.patch
deleted file mode 100644
index d2eb9fcd3..000000000
--- a/ci/qemu-madvise.patch
+++ /dev/null
@@ -1,61 +0,0 @@
-From 1ec3de1634195a4d4410cc33fdc66c68057e16a3 Mon Sep 17 00:00:00 2001
-From: Chris Fallin <chris@cfallin.org>
-Date: Sat, 5 Feb 2022 22:45:58 -0800
-Subject: [PATCH] Emulate Linux madvise() properly when possible.
-
-Curently madvise() is not emulated for Linux targets because it is not
-trivial to emulate when the guest and host page sizes differ -- in this
-case, mmap()s are not passed straight through, so the semantics of
-various MADV_* flags are not trivial to replicate.
-
-However, if the guest and host are both Linux, and the page sizes are
-the same on both ends (which is often the case, e.g. 4KiB for x86-64,
-aarch64, s390x, and possibly others), then the mmap()s are in fact
-passed straight through. Furthermore, the MADV_* flags are defined in
-target-independent headers, so we can pass the base, length, and
-`advice` arugments to `madvise()` straight through.
-
-This patch alters the Linux-userspace syscall emulation to do just that,
-passing through the `madvise()` calls when possible and returning
-`EINVAL` otherwise so the guest is properly informed that the desired
-semantics (e.g., MADV_DONTNEED to clear memory) are not available.
----
- linux-user/syscall.c | 22 ++++++++++++++++------
- 1 file changed, 16 insertions(+), 6 deletions(-)
-
-diff --git a/linux-user/syscall.c b/linux-user/syscall.c
-index 5950222a77..836e39df5f 100644
---- a/linux-user/syscall.c
-+++ b/linux-user/syscall.c
-@@ -11853,12 +11853,22 @@ static abi_long do_syscall1(void *cpu_env, int num, abi_long arg1,
- 
- #ifdef TARGET_NR_madvise
-     case TARGET_NR_madvise:
--        /* A straight passthrough may not be safe because qemu sometimes
--           turns private file-backed mappings into anonymous mappings.
--           This will break MADV_DONTNEED.
--           This is a hint, so ignoring and returning success is ok.  */
--        return 0;
--#endif
-+#ifdef __linux__
-+        /* If the host is Linux, and the guest and host page sizes are the
-+         * same, then mmaps will have been passed through one-to-one, so we can
-+         * rely on the madvise semantics of the host. Note that the advice
-+         * argument (arg3) is fully architecture-independent. */
-+        if (TARGET_PAGE_SIZE == sysconf(_SC_PAGESIZE)) {
-+            return get_errno(madvise(g2h_untagged(arg1), (size_t)arg2, (int)arg3));
-+        } else {
-+            return -TARGET_EINVAL;
-+        }
-+#else   // __linux__
-+        /* We will not be able to emulate the Linux-specific semantics, so we
-+         * raise an error. */
-+        return -TARGET_EINVAL;
-+#endif  // !__linux__
-+#endif  // TARGET_NR_madvise
- #ifdef TARGET_NR_fcntl64
-     case TARGET_NR_fcntl64:
-     {
--- 
-2.34.1
-
diff --git a/cranelift/codegen/src/binemit/mod.rs b/cranelift/codegen/src/binemit/mod.rs
index 33bc8f641..2b1f57e0f 100644
--- a/cranelift/codegen/src/binemit/mod.rs
+++ b/cranelift/codegen/src/binemit/mod.rs
@@ -56,12 +56,20 @@ pub enum Reloc {
     /// Mach-O x86_64 32 bit signed PC relative offset to a `__thread_vars` entry.
     MachOX86_64Tlv,
 
-    /// AArch64 TLS GD
+    /// Mach-O Aarch64 TLS
+    /// PC-relative distance to the page of the TLVP slot.
+    MachOAarch64TlsAdrPage21,
+
+    /// Mach-O Aarch64 TLS
+    /// Offset within page of TLVP slot.
+    MachOAarch64TlsAdrPageOff12,
+
+    /// Aarch64 TLS GD
     /// Set an ADRP immediate field to the top 21 bits of the final address. Checks for overflow.
     /// This is equivalent to `R_AARCH64_TLSGD_ADR_PAGE21` in the [aaelf64](https://github.com/ARM-software/abi-aa/blob/2bcab1e3b22d55170c563c3c7940134089176746/aaelf64/aaelf64.rst#relocations-for-thread-local-storage)
     Aarch64TlsGdAdrPage21,
 
-    /// AArch64 TLS GD
+    /// Aarch64 TLS GD
     /// Set the add immediate field to the low 12 bits of the final address. Does not check for overflow.
     /// This is equivalent to `R_AARCH64_TLSGD_ADD_LO12_NC` in the [aaelf64](https://github.com/ARM-software/abi-aa/blob/2bcab1e3b22d55170c563c3c7940134089176746/aaelf64/aaelf64.rst#relocations-for-thread-local-storage)
     Aarch64TlsGdAddLo12Nc,
@@ -109,6 +117,8 @@ impl fmt::Display for Reloc {
 
             Self::ElfX86_64TlsGd => write!(f, "ElfX86_64TlsGd"),
             Self::MachOX86_64Tlv => write!(f, "MachOX86_64Tlv"),
+            Self::MachOAarch64TlsAdrPage21 => write!(f, "MachOAarch64TlsAdrPage21"),
+            Self::MachOAarch64TlsAdrPageOff12 => write!(f, "MachOAarch64TlsAdrPageOff12"),
             Self::Aarch64TlsGdAdrPage21 => write!(f, "Aarch64TlsGdAdrPage21"),
             Self::Aarch64TlsGdAddLo12Nc => write!(f, "Aarch64TlsGdAddLo12Nc"),
             Self::Aarch64AdrGotPage21 => write!(f, "Aarch64AdrGotPage21"),
diff --git a/cranelift/codegen/src/isa/aarch64/inst.isle b/cranelift/codegen/src/isa/aarch64/inst.isle
index f7239a2ad..389fac99b 100644
--- a/cranelift/codegen/src/isa/aarch64/inst.isle
+++ b/cranelift/codegen/src/isa/aarch64/inst.isle
@@ -927,6 +927,10 @@
         (symbol ExternalName)
         (rd WritableReg))
 
+       (MachOTlsGetAddr
+        (symbol ExternalName)
+        (rd WritableReg))
+
        ;; An unwind pseudo-instruction.
        (Unwind
         (inst UnwindInst))
@@ -3591,6 +3595,12 @@
             (_ Unit (emit (MInst.ElfTlsGetAddr name dst))))
         dst))
 
+(decl macho_tls_get_addr (ExternalName) Reg)
+(rule (macho_tls_get_addr name)
+      (let ((dst WritableReg (temp_writable_reg $I64))
+            (_ Unit (emit (MInst.MachOTlsGetAddr name dst))))
+        dst))
+
 ;; A tuple of `ProducesFlags` and `IntCC`.
 (type FlagsAndCC (enum (FlagsAndCC (flags ProducesFlags)
                                    (cc IntCC))))
diff --git a/cranelift/codegen/src/isa/aarch64/inst/emit.rs b/cranelift/codegen/src/isa/aarch64/inst/emit.rs
index 04b9ba705..2e576fc89 100644
--- a/cranelift/codegen/src/isa/aarch64/inst/emit.rs
+++ b/cranelift/codegen/src/isa/aarch64/inst/emit.rs
@@ -3458,6 +3458,54 @@ impl MachInstEmit for Inst {
                 sink.put4(0xd503201f);
             }
 
+            &Inst::MachOTlsGetAddr { ref symbol, rd } => {
+                // Each thread local variable gets a descriptor, where the first xword of the descriptor is a pointer
+                // to a function that takes the descriptor address in x0, and after the function returns x0
+                // contains the address for the thread local variable
+                //
+                // what we want to emit is basically:
+                //
+                // adrp x0, <label>@TLVPPAGE  ; Load the address of the page of the thread local variable pointer (TLVP)
+                // ldr x0, [x0, <label>@TLVPPAGEOFF] ; Load the descriptor's address into x0
+                // ldr x1, [x0] ; Load the function pointer (the first part of the descriptor)
+                // blr x1 ; Call the function pointer with the descriptor address in x0
+                // ; x0 now contains the TLV address
+
+                let rd = allocs.next_writable(rd);
+                assert_eq!(xreg(0), rd.to_reg());
+                let rtmp = writable_xreg(1);
+
+                // adrp x0, <label>@TLVPPAGE
+                sink.add_reloc(Reloc::MachOAarch64TlsAdrPage21, symbol, 0);
+                sink.put4(0x90000000);
+
+                // ldr x0, [x0, <label>@TLVPPAGEOFF]
+                sink.add_reloc(Reloc::MachOAarch64TlsAdrPageOff12, symbol, 0);
+                sink.put4(0xf9400000);
+
+                // load [x0] into temp register
+                Inst::ULoad64 {
+                    rd: rtmp,
+                    mem: AMode::reg(rd.to_reg()),
+                    flags: MemFlags::trusted(),
+                }
+                .emit(&[], sink, emit_info, state);
+
+                // call function pointer in temp register
+                Inst::CallInd {
+                    info: crate::isa::Box::new(CallIndInfo {
+                        rn: rtmp.to_reg(),
+                        uses: smallvec![],
+                        defs: smallvec![],
+                        clobbers: PRegSet::empty(),
+                        opcode: Opcode::CallIndirect,
+                        caller_callconv: CallConv::AppleAarch64,
+                        callee_callconv: CallConv::AppleAarch64,
+                    }),
+                }
+                .emit(&[], sink, emit_info, state);
+            }
+
             &Inst::Unwind { ref inst } => {
                 sink.add_unwind(inst.clone());
             }
diff --git a/cranelift/codegen/src/isa/aarch64/inst/mod.rs b/cranelift/codegen/src/isa/aarch64/inst/mod.rs
index 09f64c764..b7debcda6 100644
--- a/cranelift/codegen/src/isa/aarch64/inst/mod.rs
+++ b/cranelift/codegen/src/isa/aarch64/inst/mod.rs
@@ -907,6 +907,13 @@ fn aarch64_get_operands<F: Fn(VReg) -> VReg>(inst: &Inst, collector: &mut Operan
             clobbers.remove(regs::xreg_preg(0));
             collector.reg_clobbers(clobbers);
         }
+        &Inst::MachOTlsGetAddr { rd, .. } => {
+            collector.reg_fixed_def(rd, regs::xreg(0));
+            let mut clobbers =
+                AArch64MachineDeps::get_regs_clobbered_by_call(CallConv::AppleAarch64);
+            clobbers.remove(regs::xreg_preg(0));
+            collector.reg_clobbers(clobbers);
+        }
         &Inst::Unwind { .. } => {}
         &Inst::EmitIsland { .. } => {}
         &Inst::DummyUse { reg } => {
@@ -2701,6 +2708,10 @@ impl Inst {
                 let rd = pretty_print_reg(rd.to_reg(), allocs);
                 format!("elf_tls_get_addr {}, {}", rd, symbol.display(None))
             }
+            &Inst::MachOTlsGetAddr { ref symbol, rd } => {
+                let rd = pretty_print_reg(rd.to_reg(), allocs);
+                format!("macho_tls_get_addr {}, {}", rd, symbol.display(None))
+            }
             &Inst::Unwind { ref inst } => {
                 format!("unwind {:?}", inst)
             }
diff --git a/cranelift/codegen/src/isa/aarch64/lower.isle b/cranelift/codegen/src/isa/aarch64/lower.isle
index bafd73330..a08dcd553 100644
--- a/cranelift/codegen/src/isa/aarch64/lower.isle
+++ b/cranelift/codegen/src/isa/aarch64/lower.isle
@@ -2574,10 +2574,12 @@
 
 ;;; Rules for `tls_value` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 
-(rule (lower (tls_value (symbol_value_data name _ _)))
-      (if (tls_model_is_elf_gd))
+(rule (lower (has_type (tls_model (TlsModel.ElfGd)) (tls_value (symbol_value_data name _ _))))
       (elf_tls_get_addr name))
 
+(rule (lower (has_type (tls_model (TlsModel.Macho)) (tls_value (symbol_value_data name _ _))))
+      (macho_tls_get_addr name))
+
 ;;; Rules for `fcvt_low_from_sint` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 
 (rule (lower (has_type $F64X2 (fcvt_low_from_sint val)))
diff --git a/cranelift/codegen/src/isa/riscv64/inst.isle b/cranelift/codegen/src/isa/riscv64/inst.isle
index d4eed1f98..ef6195fe7 100644
--- a/cranelift/codegen/src/isa/riscv64/inst.isle
+++ b/cranelift/codegen/src/isa/riscv64/inst.isle
@@ -761,6 +761,510 @@
       (_ Unit (emit (MInst.FloatSelect op rd tmp x y ty))))
     (writable_reg_to_reg rd)))
 
+
+;;;; Instruction Helpers ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+;; RV32I Base Integer Instruction Set
+
+;; Helper for emitting the `add` instruction.
+;; rd ← rs1 + rs2
+(decl rv_add (Reg Reg) Reg)
+(rule (rv_add rs1 rs2)
+  (alu_rrr (AluOPRRR.Add) rs1 rs2))
+
+;; Helper for emitting the `addi` ("Add Immediate") instruction.
+;; rd ← rs1 + sext(imm)
+(decl rv_addi (Reg Imm12) Reg)
+(rule (rv_addi rs1 imm)
+  (alu_rr_imm12 (AluOPRRI.Addi) rs1 imm))
+
+;; Helper for emitting the `sub` instruction.
+;; rd ← rs1 - rs2
+(decl rv_sub (Reg Reg) Reg)
+(rule (rv_sub rs1 rs2)
+  (alu_rrr (AluOPRRR.Sub) rs1 rs2))
+
+;; Helper for emitting the `neg` instruction.
+;; This instruction is a mnemonic for `sub rd, zero, rs1`.
+(decl rv_neg (Reg) Reg)
+(rule (rv_neg rs1)
+  (alu_rrr (AluOPRRR.Sub) (zero_reg) rs1))
+
+;; Helper for emitting the `sll` ("Shift Left Logical") instruction.
+;; rd ← rs1 << rs2
+(decl rv_sll (Reg Reg) Reg)
+(rule (rv_sll rs1 rs2)
+  (alu_rrr (AluOPRRR.Sll) rs1 rs2))
+
+;; Helper for emitting the `slli` ("Shift Left Logical Immediate") instruction.
+;; rd ← rs1 << uext(imm)
+(decl rv_slli (Reg Imm12) Reg)
+(rule (rv_slli rs1 imm)
+  (alu_rr_imm12 (AluOPRRI.Slli) rs1 imm))
+
+;; Helper for emitting the `srl` ("Shift Right Logical") instruction.
+;; rd ← rs1 >> rs2
+(decl rv_srl (Reg Reg) Reg)
+(rule (rv_srl rs1 rs2)
+  (alu_rrr (AluOPRRR.Srl) rs1 rs2))
+
+;; Helper for emitting the `srli` ("Shift Right Logical Immediate") instruction.
+;; rd ← rs1 >> uext(imm)
+(decl rv_srli (Reg Imm12) Reg)
+(rule (rv_srli rs1 imm)
+  (alu_rr_imm12 (AluOPRRI.Srli) rs1 imm))
+
+;; Helper for emitting the `sra` ("Shift Right Arithmetic") instruction.
+;; rd ← rs1 >> rs2
+(decl rv_sra (Reg Reg) Reg)
+(rule (rv_sra rs1 rs2)
+  (alu_rrr (AluOPRRR.Sra) rs1 rs2))
+
+;; Helper for emitting the `srai` ("Shift Right Arithmetic Immediate") instruction.
+;; rd ← rs1 >> uext(imm)
+(decl rv_srai (Reg Imm12) Reg)
+(rule (rv_srai rs1 imm)
+  (alu_rr_imm12 (AluOPRRI.Srai) rs1 imm))
+
+;; Helper for emitting the `or` instruction.
+;; rd ← rs1 ∨ rs2
+(decl rv_or (Reg Reg) Reg)
+(rule (rv_or rs1 rs2)
+  (alu_rrr (AluOPRRR.Or) rs1 rs2))
+
+;; Helper for emitting the `ori` ("Or Immediate") instruction.
+;; rd ← rs1 ∨ uext(imm)
+(decl rv_ori (Reg Imm12) Reg)
+(rule (rv_ori rs1 imm)
+  (alu_rr_imm12 (AluOPRRI.Ori) rs1 imm))
+
+;; Helper for emitting the `xor` instruction.
+;; rd ← rs1 ⊕ rs2
+(decl rv_xor (Reg Reg) Reg)
+(rule (rv_xor rs1 rs2)
+  (alu_rrr (AluOPRRR.Xor) rs1 rs2))
+
+;; Helper for emitting the `xori` ("Exlusive Or Immediate") instruction.
+;; rd ← rs1 ⊕ uext(imm)
+(decl rv_xori (Reg Imm12) Reg)
+(rule (rv_xori rs1 imm)
+  (alu_rr_imm12 (AluOPRRI.Xori) rs1 imm))
+
+;; Helper for emitting the `not` instruction.
+;; This instruction is a mnemonic for `xori rd, rs1, -1`.
+(decl rv_not (Reg) Reg)
+(rule (rv_not rs1)
+  (rv_xori rs1 (imm12_const -1)))
+
+;; Helper for emitting the `and` instruction.
+;; rd ← rs1 ∧ rs2
+(decl rv_and (Reg Reg) Reg)
+(rule (rv_and rs1 rs2)
+  (alu_rrr (AluOPRRR.And) rs1 rs2))
+
+;; Helper for emitting the `andi` ("And Immediate") instruction.
+;; rd ← rs1 ∧ uext(imm)
+(decl rv_andi (Reg Imm12) Reg)
+(rule (rv_andi rs1 imm)
+  (alu_rr_imm12 (AluOPRRI.Andi) rs1 imm))
+
+;; Helper for emitting the `sltu` ("Set Less Than Unsigned") instruction.
+;; rd ← rs1 < rs2
+(decl rv_sltu (Reg Reg) Reg)
+(rule (rv_sltu rs1 rs2)
+  (alu_rrr (AluOPRRR.SltU) rs1 rs2))
+
+;; Helper for emiting the `sltiu` ("Set Less Than Immediate Unsigned") instruction.
+;; rd ← rs1 < imm
+(decl rv_sltiu (Reg Imm12) Reg)
+(rule (rv_sltiu rs1 imm)
+  (alu_rr_imm12 (AluOPRRI.SltiU) rs1 imm))
+
+;; Helper for emitting the `seqz` instruction.
+;; This instruction is a mnemonic for `sltiu rd, rs, 1`.
+(decl rv_seqz (Reg) Reg)
+(rule (rv_seqz rs1)
+  (rv_sltiu rs1 (imm12_const 1)))
+
+
+;; RV64I Base Integer Instruction Set
+;; Unlike RV32I instructions these are only present in the 64bit ISA
+
+;; Helper for emitting the `addw` ("Add Word") instruction.
+;; rd ← sext32(rs1) + sext32(rs2)
+(decl rv_addw (Reg Reg) Reg)
+(rule (rv_addw rs1 rs2)
+  (alu_rrr (AluOPRRR.Addw) rs1 rs2))
+
+;; Helper for emitting the `addiw` ("Add Word Immediate") instruction.
+;; rd ← sext32(rs1) + imm
+(decl rv_addiw (Reg Imm12) Reg)
+(rule (rv_addiw rs1 imm)
+  (alu_rr_imm12 (AluOPRRI.Addiw) rs1 imm))
+
+;; Helper for emitting the `sext.w` ("Sign Extend Word") instruction.
+;; This instruction is a mnemonic for `addiw rd, rs, zero`.
+(decl rv_sextw (Reg) Reg)
+(rule (rv_sextw rs1)
+  (rv_addiw rs1 (imm12_const 0)))
+
+;; Helper for emitting the `subw` ("Subtract Word") instruction.
+;; rd ← sext32(rs1) - sext32(rs2)
+(decl rv_subw (Reg Reg) Reg)
+(rule (rv_subw rs1 rs2)
+  (alu_rrr (AluOPRRR.Subw) rs1 rs2))
+
+;; Helper for emitting the `sllw` ("Shift Left Logical Word") instruction.
+;; rd ← sext32(uext32(rs1) << rs2)
+(decl rv_sllw (Reg Reg) Reg)
+(rule (rv_sllw rs1 rs2)
+  (alu_rrr (AluOPRRR.Sllw) rs1 rs2))
+
+;; Helper for emitting the `slliw` ("Shift Left Logical Immediate Word") instruction.
+;; rd ← sext32(uext32(rs1) << imm)
+(decl rv_slliw (Reg Imm12) Reg)
+(rule (rv_slliw rs1 imm)
+  (alu_rr_imm12 (AluOPRRI.Slliw) rs1 imm))
+
+;; Helper for emitting the `srlw` ("Shift Right Logical Word") instruction.
+;; rd ← sext32(uext32(rs1) >> rs2)
+(decl rv_srlw (Reg Reg) Reg)
+(rule (rv_srlw rs1 rs2)
+  (alu_rrr (AluOPRRR.Srlw) rs1 rs2))
+
+;; Helper for emitting the `srliw` ("Shift Right Logical Immediate Word") instruction.
+;; rd ← sext32(uext32(rs1) >> imm)
+(decl rv_srliw (Reg Imm12) Reg)
+(rule (rv_srliw rs1 imm)
+  (alu_rr_imm12 (AluOPRRI.SrliW) rs1 imm))
+
+;; Helper for emitting the `sraw` ("Shift Right Arithmetic Word") instruction.
+;; rd ← sext32(rs1 >> rs2)
+(decl rv_sraw (Reg Reg) Reg)
+(rule (rv_sraw rs1 rs2)
+  (alu_rrr (AluOPRRR.Sraw) rs1 rs2))
+
+;; Helper for emitting the `sraiw` ("Shift Right Arithmetic Immediate Word") instruction.
+;; rd ← sext32(rs1 >> imm)
+(decl rv_sraiw (Reg Imm12) Reg)
+(rule (rv_sraiw rs1 imm)
+  (alu_rr_imm12 (AluOPRRI.Sraiw) rs1 imm))
+
+
+;; RV32M Extension
+;; TODO: Enable these instructions only when we have the M extension
+
+;; Helper for emitting the `mul` instruction.
+;; rd ← rs1 × rs2
+(decl rv_mul (Reg Reg) Reg)
+(rule (rv_mul rs1 rs2)
+  (alu_rrr (AluOPRRR.Mul) rs1 rs2))
+
+;; Helper for emitting the `mulh` ("Multiply High Signed Signed") instruction.
+;; rd ← (sext(rs1) × sext(rs2)) » xlen
+(decl rv_mulh (Reg Reg) Reg)
+(rule (rv_mulh rs1 rs2)
+  (alu_rrr (AluOPRRR.Mulh) rs1 rs2))
+
+;; Helper for emitting the `mulhu` ("Multiply High Unsigned Unsigned") instruction.
+;; rd ← (uext(rs1) × uext(rs2)) » xlen
+(decl rv_mulhu (Reg Reg) Reg)
+(rule (rv_mulhu rs1 rs2)
+  (alu_rrr (AluOPRRR.Mulhu) rs1 rs2))
+
+;; Helper for emitting the `div` instruction.
+;; rd ← rs1 ÷ rs2
+(decl rv_div (Reg Reg) Reg)
+(rule (rv_div rs1 rs2)
+  (alu_rrr (AluOPRRR.Div) rs1 rs2))
+
+;; Helper for emitting the `divu` ("Divide Unsigned") instruction.
+;; rd ← rs1 ÷ rs2
+(decl rv_divu (Reg Reg) Reg)
+(rule (rv_divu rs1 rs2)
+  (alu_rrr (AluOPRRR.DivU) rs1 rs2))
+
+;; Helper for emitting the `rem` instruction.
+;; rd ← rs1 mod rs2
+(decl rv_rem (Reg Reg) Reg)
+(rule (rv_rem rs1 rs2)
+  (alu_rrr (AluOPRRR.Rem) rs1 rs2))
+
+;; Helper for emitting the `remu` ("Remainder Unsigned") instruction.
+;; rd ← rs1 mod rs2
+(decl rv_remu (Reg Reg) Reg)
+(rule (rv_remu rs1 rs2)
+  (alu_rrr (AluOPRRR.RemU) rs1 rs2))
+
+
+
+;; RV64M Extension
+;; TODO: Enable these instructions only when we have the M extension
+
+;; Helper for emitting the `mulw` ("Multiply Word") instruction.
+;; rd ← uext32(rs1) × uext32(rs2)
+(decl rv_mulw (Reg Reg) Reg)
+(rule (rv_mulw rs1 rs2)
+  (alu_rrr (AluOPRRR.Mulw) rs1 rs2))
+
+;; Helper for emitting the `divw` ("Divide Word") instruction.
+;; rd ← sext32(rs1) ÷ sext32(rs2)
+(decl rv_divw (Reg Reg) Reg)
+(rule (rv_divw rs1 rs2)
+  (alu_rrr (AluOPRRR.Divw) rs1 rs2))
+
+;; Helper for emitting the `divuw` ("Divide Unsigned Word") instruction.
+;; rd ← uext32(rs1) ÷ uext32(rs2)
+(decl rv_divuw (Reg Reg) Reg)
+(rule (rv_divuw rs1 rs2)
+  (alu_rrr (AluOPRRR.Divuw) rs1 rs2))
+
+;; Helper for emitting the `remw` ("Remainder Word") instruction.
+;; rd ← sext32(rs1) mod sext32(rs2)
+(decl rv_remw (Reg Reg) Reg)
+(rule (rv_remw rs1 rs2)
+  (alu_rrr (AluOPRRR.Remw) rs1 rs2))
+
+;; Helper for emitting the `remuw` ("Remainder Unsigned Word") instruction.
+;; rd ← uext32(rs1) mod uext32(rs2)
+(decl rv_remuw (Reg Reg) Reg)
+(rule (rv_remuw rs1 rs2)
+  (alu_rrr (AluOPRRR.Remuw) rs1 rs2))
+
+
+;; F and D Extensions
+;; TODO: Enable these instructions only when we have the F or D extensions
+
+;; Helper for emitting the `fadd` instruction.
+(decl rv_fadd (Type Reg Reg) Reg)
+(rule (rv_fadd $F32 rs1 rs2) (fpu_rrr (FpuOPRRR.FaddS) $F32 rs1 rs2))
+(rule (rv_fadd $F64 rs1 rs2) (fpu_rrr (FpuOPRRR.FaddD) $F64 rs1 rs2))
+
+;; Helper for emitting the `fsub` instruction.
+(decl rv_fsub (Type Reg Reg) Reg)
+(rule (rv_fsub $F32 rs1 rs2) (fpu_rrr (FpuOPRRR.FsubS) $F32 rs1 rs2))
+(rule (rv_fsub $F64 rs1 rs2) (fpu_rrr (FpuOPRRR.FsubD) $F64 rs1 rs2))
+
+;; Helper for emitting the `fmul` instruction.
+(decl rv_fmul (Type Reg Reg) Reg)
+(rule (rv_fmul $F32 rs1 rs2) (fpu_rrr (FpuOPRRR.FmulS) $F32 rs1 rs2))
+(rule (rv_fmul $F64 rs1 rs2) (fpu_rrr (FpuOPRRR.FmulD) $F64 rs1 rs2))
+
+;; Helper for emitting the `fdiv` instruction.
+(decl rv_fdiv (Type Reg Reg) Reg)
+(rule (rv_fdiv $F32 rs1 rs2) (fpu_rrr (FpuOPRRR.FdivS) $F32 rs1 rs2))
+(rule (rv_fdiv $F64 rs1 rs2) (fpu_rrr (FpuOPRRR.FdivD) $F64 rs1 rs2))
+
+;; Helper for emitting the `fsqrt` instruction.
+(decl rv_fsqrt (Type Reg) Reg)
+(rule (rv_fsqrt $F32 rs1) (fpu_rr (FpuOPRR.FsqrtS) $F32 rs1))
+(rule (rv_fsqrt $F64 rs1) (fpu_rr (FpuOPRR.FsqrtD) $F64 rs1))
+
+;; Helper for emitting the `fmadd` instruction.
+(decl rv_fmadd (Type Reg Reg Reg) Reg)
+(rule (rv_fmadd $F32 rs1 rs2 rs3) (fpu_rrrr (FpuOPRRRR.FmaddS) $F32 rs1 rs2 rs3))
+(rule (rv_fmadd $F64 rs1 rs2 rs3) (fpu_rrrr (FpuOPRRRR.FmaddD) $F64 rs1 rs2 rs3))
+
+;; Helper for emitting the `fcvt.d.s` ("Float Convert Double to Single") instruction.
+(decl rv_fcvtds (Reg) Reg)
+(rule (rv_fcvtds rs1) (fpu_rr (FpuOPRR.FcvtDS) $F32 rs1))
+
+;; Helper for emitting the `fcvt.s.d` ("Float Convert Single to Double") instruction.
+(decl rv_fcvtsd (Reg) Reg)
+(rule (rv_fcvtsd rs1) (fpu_rr (FpuOPRR.FcvtSD) $F64 rs1))
+
+;; Helper for emitting the `fsgnj` ("Floating Point Sign Injection") instruction.
+;; The output of this instruction is `rs1` with the sign bit from `rs2`
+;; This implements the `copysign` operation
+(decl rv_fsgnj (Type Reg Reg) Reg)
+(rule (rv_fsgnj $F32 rs1 rs2) (fpu_rrr (FpuOPRRR.FsgnjS) $F32 rs1 rs2))
+(rule (rv_fsgnj $F64 rs1 rs2) (fpu_rrr (FpuOPRRR.FsgnjD) $F64 rs1 rs2))
+
+;; Helper for emitting the `fsgnjn` ("Floating Point Sign Injection Negated") instruction.
+;; The output of this instruction is `rs1` with the negated sign bit from `rs2`
+;; When `rs1 == rs2` this implements the `neg` operation
+(decl rv_fsgnjn (Type Reg Reg) Reg)
+(rule (rv_fsgnjn $F32 rs1 rs2) (fpu_rrr (FpuOPRRR.FsgnjnS) $F32 rs1 rs2))
+(rule (rv_fsgnjn $F64 rs1 rs2) (fpu_rrr (FpuOPRRR.FsgnjnD) $F64 rs1 rs2))
+
+;; Helper for emitting the `fneg` ("Floating Point Negate") instruction.
+;; This instruction is a mnemonic for `fsgnjn rd, rs1, rs1`
+(decl rv_fneg (Type Reg) Reg)
+(rule (rv_fneg ty rs1) (rv_fsgnjn ty rs1 rs1))
+
+;; Helper for emitting the `fsgnjx` ("Floating Point Sign Injection Exclusive") instruction.
+;; The output of this instruction is `rs1` with the XOR of the sign bits from `rs1` and `rs2`.
+;; When `rs1 == rs2` this implements `fabs`
+(decl rv_fsgnjx (Type Reg Reg) Reg)
+(rule (rv_fsgnjx $F32 rs1 rs2) (fpu_rrr (FpuOPRRR.FsgnjxS) $F32 rs1 rs2))
+(rule (rv_fsgnjx $F64 rs1 rs2) (fpu_rrr (FpuOPRRR.FsgnjxD) $F64 rs1 rs2))
+
+;; Helper for emitting the `fabs` ("Floating Point Absolute") instruction.
+;; This instruction is a mnemonic for `fsgnjx rd, rs1, rs1`
+(decl rv_fabs (Type Reg) Reg)
+(rule (rv_fabs ty rs1) (rv_fsgnjx ty rs1 rs1))
+
+;; Helper for emitting the `feq` ("Float Equal") instruction.
+(decl rv_feq (Type Reg Reg) Reg)
+(rule (rv_feq $F32 rs1 rs2) (fpu_rrr (FpuOPRRR.FeqS) $I64 rs1 rs2))
+(rule (rv_feq $F64 rs1 rs2) (fpu_rrr (FpuOPRRR.FeqD) $I64 rs1 rs2))
+
+;; Helper for emitting the `flt` ("Float Less Than") instruction.
+(decl rv_flt (Type Reg Reg) Reg)
+(rule (rv_flt $F32 rs1 rs2) (fpu_rrr (FpuOPRRR.FltS) $I64 rs1 rs2))
+(rule (rv_flt $F64 rs1 rs2) (fpu_rrr (FpuOPRRR.FltD) $I64 rs1 rs2))
+
+;; Helper for emitting the `fle` ("Float Less Than or Equal") instruction.
+(decl rv_fle (Type Reg Reg) Reg)
+(rule (rv_fle $F32 rs1 rs2) (fpu_rrr (FpuOPRRR.FleS) $I64 rs1 rs2))
+(rule (rv_fle $F64 rs1 rs2) (fpu_rrr (FpuOPRRR.FleD) $I64 rs1 rs2))
+
+;; Helper for emitting the `fgt` ("Float Greater Than") instruction.
+;; Note: The arguments are reversed
+(decl rv_fgt (Type Reg Reg) Reg)
+(rule (rv_fgt ty rs1 rs2) (rv_flt ty rs2 rs1))
+
+;; Helper for emitting the `fge` ("Float Greater Than or Equal") instruction.
+;; Note: The arguments are reversed
+(decl rv_fge (Type Reg Reg) Reg)
+(rule (rv_fge ty rs1 rs2) (rv_fle ty rs2 rs1))
+
+
+;; `Zba` Extension Instructions
+
+;; Helper for emitting the `adduw` ("Add Unsigned Word") instruction.
+;; rd ← uext32(rs1) + uext32(rs2)
+(decl rv_adduw (Reg Reg) Reg)
+(rule (rv_adduw rs1 rs2)
+  (alu_rrr (AluOPRRR.Adduw) rs1 rs2))
+
+;; Helper for emitting the `zext.w` ("Zero Extend Word") instruction.
+;; This instruction is a mnemonic for `adduw rd, rs1, zero`.
+;; rd ← uext32(rs1)
+(decl rv_zextw (Reg) Reg)
+(rule (rv_zextw rs1)
+  (rv_adduw rs1 (zero_reg)))
+
+;; Helper for emitting the `slli.uw` ("Shift Left Logical Immediate Unsigned Word") instruction.
+;; rd ← uext32(rs1) << imm
+(decl rv_slliuw (Reg Imm12) Reg)
+(rule (rv_slliuw rs1 imm)
+  (alu_rr_imm12 (AluOPRRI.SlliUw) rs1 imm))
+
+
+;; `Zbb` Extension Instructions
+
+;; Helper for emitting the `andn` ("And Negated") instruction.
+;; rd ← rs1 ∧ ~(rs2)
+(decl rv_andn (Reg Reg) Reg)
+(rule (rv_andn rs1 rs2)
+  (alu_rrr (AluOPRRR.Andn) rs1 rs2))
+
+;; Helper for emitting the `orn` ("Or Negated") instruction.
+;; rd ← rs1 ∨ ~(rs2)
+(decl rv_orn (Reg Reg) Reg)
+(rule (rv_orn rs1 rs2)
+  (alu_rrr (AluOPRRR.Orn) rs1 rs2))
+
+;; Helper for emitting the `clz` ("Count Leading Zero Bits") instruction.
+(decl rv_clz (Reg) Reg)
+(rule (rv_clz rs1)
+  (alu_rr_funct12 (AluOPRRI.Clz) rs1))
+
+;; Helper for emitting the `clzw` ("Count Leading Zero Bits in Word") instruction.
+(decl rv_clzw (Reg) Reg)
+(rule (rv_clzw rs1)
+  (alu_rr_funct12 (AluOPRRI.Clzw) rs1))
+
+;; Helper for emitting the `ctz` ("Count Trailing Zero Bits") instruction.
+(decl rv_ctz (Reg) Reg)
+(rule (rv_ctz rs1)
+  (alu_rr_funct12 (AluOPRRI.Ctz) rs1))
+
+;; Helper for emitting the `ctzw` ("Count Trailing Zero Bits in Word") instruction.
+(decl rv_ctzw (Reg) Reg)
+(rule (rv_ctzw rs1)
+  (alu_rr_funct12 (AluOPRRI.Ctzw) rs1))
+
+;; Helper for emitting the `cpop` ("Count Population") instruction.
+(decl rv_cpop (Reg) Reg)
+(rule (rv_cpop rs1)
+  (alu_rr_funct12 (AluOPRRI.Cpop) rs1))
+
+;; Helper for emitting the `max` instruction.
+(decl rv_max (Reg Reg) Reg)
+(rule (rv_max rs1 rs2)
+  (alu_rrr (AluOPRRR.Max) rs1 rs2))
+
+;; Helper for emitting the `sext.b` instruction.
+(decl rv_sextb (Reg) Reg)
+(rule (rv_sextb rs1)
+  (alu_rr_imm12 (AluOPRRI.Sextb) rs1 (imm12_const 0)))
+
+;; Helper for emitting the `sext.h` instruction.
+(decl rv_sexth (Reg) Reg)
+(rule (rv_sexth rs1)
+  (alu_rr_imm12 (AluOPRRI.Sexth) rs1 (imm12_const 0)))
+
+;; Helper for emitting the `zext.h` instruction.
+(decl rv_zexth (Reg) Reg)
+(rule (rv_zexth rs1)
+  (alu_rr_imm12 (AluOPRRI.Zexth) rs1 (imm12_const 0)))
+
+;; Helper for emitting the `rol` ("Rotate Left") instruction.
+(decl rv_rol (Reg Reg) Reg)
+(rule (rv_rol rs1 rs2)
+  (alu_rrr (AluOPRRR.Rol) rs1 rs2))
+
+;; Helper for emitting the `rolw` ("Rotate Left Word") instruction.
+(decl rv_rolw (Reg Reg) Reg)
+(rule (rv_rolw rs1 rs2)
+  (alu_rrr (AluOPRRR.Rolw) rs1 rs2))
+
+;; Helper for emitting the `ror` ("Rotate Right") instruction.
+(decl rv_ror (Reg Reg) Reg)
+(rule (rv_ror rs1 rs2)
+  (alu_rrr (AluOPRRR.Ror) rs1 rs2))
+
+;; Helper for emitting the `rorw` ("Rotate Right Word") instruction.
+(decl rv_rorw (Reg Reg) Reg)
+(rule (rv_rorw rs1 rs2)
+  (alu_rrr (AluOPRRR.Rorw) rs1 rs2))
+
+;; Helper for emitting the `rev8` ("Byte Reverse") instruction.
+(decl rv_rev8 (Reg) Reg)
+(rule (rv_rev8 rs1)
+  (alu_rr_funct12 (AluOPRRI.Rev8) rs1))
+
+;; Helper for emitting the `brev8` ("Bit Reverse Inside Bytes") instruction.
+;; TODO: This instruction is mentioned in some older versions of the
+;; spec, but has since disappeared, we should follow up on this.
+;; It probably was renamed to `rev.b` which seems to be the closest match.
+(decl rv_brev8 (Reg) Reg)
+(rule (rv_brev8 rs1)
+  (alu_rr_funct12 (AluOPRRI.Brev8) rs1))
+
+;; Helper for emitting the `bseti` ("Single-Bit Set Immediate") instruction.
+(decl rv_bseti (Reg Imm12) Reg)
+(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.
+(decl rv_pack (Reg Reg) Reg)
+(rule (rv_pack rs1 rs2)
+  (alu_rrr (AluOPRRR.Pack) rs1 rs2))
+
+;; Helper for emitting the `packw` ("Pack low 16-bits of registers") instruction.
+(decl rv_packw (Reg Reg) Reg)
+(rule (rv_packw rs1 rs2)
+  (alu_rrr (AluOPRRR.Packw) rs1 rs2))
+
+
+
+
 ;; for load immediate
 (decl imm (Type u64) Reg)
 (extern constructor imm imm)
@@ -778,7 +1282,7 @@
 (decl load_imm12 (i32) Reg)
 (rule
   (load_imm12 x)
-  (alu_rr_imm12 (AluOPRRI.Addi) (zero_reg) (imm12_const x)))
+  (rv_addi (zero_reg) (imm12_const x)))
   
 ;; for load immediate
 (decl imm_from_bits (u64) Imm12)
@@ -809,26 +1313,6 @@
 (extern extractor imm12_from_u64 imm12_from_u64)
 
 
-;;;; Instruction Helpers ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-
-
-;; bseti: Set a single bit in a register, indexed by a constant.
-(decl bseti (Reg u64) Reg)
-(rule (bseti val bit)
-  (if-let $false (has_zbs))
-  (if-let $false (u64_le bit 12))
-  (let ((const Reg (load_u64_constant (u64_shl 1 bit))))
-    (alu_rrr (AluOPRRR.Or) val const)))
-
-(rule (bseti val bit)
-  (if-let $false (has_zbs))
-  (if-let $true (u64_le bit 12))
-  (alu_rr_imm12 (AluOPRRI.Ori) val (imm12_const (u64_as_i32 (u64_shl 1 bit)))))
-
-(rule (bseti val bit)
-  (if-let $true (has_zbs))
-  (alu_rr_imm12 (AluOPRRI.Bseti) val (imm12_const (u64_as_i32 bit))))
-
 
 ;; Float Helpers
 
@@ -849,23 +1333,6 @@
             (_ Unit (emit (MInst.AluRRR op dst src1 src2))))
         dst))
 
-;; Helper for emit rd = rs1 + rs2 for Interger.
-(decl alu_add (Reg Reg) Reg)
-(rule
-  (alu_add rs1 rs2)
-  (alu_rrr (AluOPRRR.Add) rs1 rs2))
-
-(decl alu_and (Reg Reg) Reg)
-(rule
-  (alu_and rs1 rs2)
-  (alu_rrr (AluOPRRR.And) rs1 rs2))
-
-
-;; Helper for emit rd = rs1 - rs2 for Interger.
-(decl alu_sub (Reg Reg) Reg)
-(rule
-  (alu_sub rs1 rs2)
-  (alu_rrr (AluOPRRR.Sub) rs1 rs2))
 
 (decl pack_float_rounding_mode (FRM) OptionFloatRoundingMode)
 (extern constructor pack_float_rounding_mode pack_float_rounding_mode)
@@ -893,18 +1360,6 @@
             (_ Unit (emit (MInst.AluRRImm12 op dst src imm))))
         dst))
 
-(decl alu_andi (Reg i32) Reg)
-(rule (alu_andi r i)
-  (alu_rr_imm12 (AluOPRRI.Andi) r (imm12_const i)))
-
-
-(decl alu_slli (Reg i32) Reg)
-(rule (alu_slli r i)
-  (alu_rr_imm12 (AluOPRRI.Slli) r (imm12_const i)))
-(decl alu_srli (Reg i32) Reg)
-(rule (alu_srli r i)
-  (alu_rr_imm12 (AluOPRRI.Srli) r (imm12_const i)))
-
 ;; some instruction use imm12 as funct12.
 ;; so we don't need the imm12 paramter.
 (decl alu_rr_funct12 (AluOPRRI Reg) Reg)
@@ -913,31 +1368,19 @@
             (_ Unit (emit (MInst.AluRRImm12 op dst src (imm12_zero)))))
         dst))
 
-
 (decl select_addi (Type) AluOPRRI)
 (rule 1 (select_addi (fits_in_32 ty)) (AluOPRRI.Addiw))
 (rule (select_addi (fits_in_64 ty)) (AluOPRRI.Addi))
 
 
-;; Helper for emiting the `sltiu` instruction
-(decl sltiu (Reg Imm12) Reg)
-(rule (sltiu r imm)
-  (alu_rr_imm12 (AluOPRRI.SltiU) r imm))
-
-;; Helper for emiting the `seqz` mnemonic
-(decl seqz (Reg) Reg)
-(rule (seqz r)
-  (sltiu r (imm12_const 1)))
-
-
 (decl bnot_128 (ValueRegs) ValueRegs)
 (rule
   (bnot_128 val)
   (let
     (;; low part.
-      (low Reg (gen_bit_not (value_regs_get val 0)))
+      (low Reg (rv_not (value_regs_get val 0)))
       ;; high part.
-      (high Reg (gen_bit_not (value_regs_get val 1))))
+      (high Reg (rv_not (value_regs_get val 1))))
     (value_regs low high)))
 
 (decl lower_bit_reverse (Reg Type) Reg)
@@ -951,7 +1394,7 @@
   (let
     ((tmp Reg (gen_brev8 r $I16))
       (tmp2 Reg (gen_rev8 tmp))
-      (result Reg (alu_rr_imm12 (AluOPRRI.Srli) tmp2 (imm12_const 48))))
+      (result Reg (rv_srli tmp2 (imm12_const 48))))
     result))
 
 (rule
@@ -959,7 +1402,7 @@
   (let
     ((tmp Reg (gen_brev8 r $I32))
       (tmp2 Reg (gen_rev8 tmp))
-      (result Reg (alu_rr_imm12 (AluOPRRI.Srli) tmp2 (imm12_const 32))))
+      (result Reg (rv_srli tmp2 (imm12_const 32))))
     result))
 
 (rule
@@ -975,16 +1418,16 @@
 
 (rule 1 (lower_ctz (fits_in_16 ty) x)
   (if-let $true (has_zbb))
-  (let ((tmp Reg (bseti x (ty_bits ty))))
-    (alu_rr_funct12 (AluOPRRI.Ctzw) tmp)))
+  (let ((tmp Reg (gen_bseti x (ty_bits ty))))
+    (rv_ctzw tmp)))
 
 (rule 2 (lower_ctz $I32 x)
   (if-let $true (has_zbb))
-  (alu_rr_funct12 (AluOPRRI.Ctzw) x))
+  (rv_ctzw x))
 
 (rule 2 (lower_ctz $I64 x)
   (if-let $true (has_zbb))
-  (alu_rr_funct12 (AluOPRRI.Ctz) x))
+  (rv_ctz x))
 
 ;; Count trailing zeros from a i128 bit value.
 ;; We count both halves separately and conditionally add them if it makes sense.
@@ -997,11 +1440,9 @@
         (low Reg (lower_ctz $I64 x_lo))
         ;; Only add the top half if the bottom is zero
         (high Reg (gen_select_reg (IntCC.Equal) x_lo (zero_reg) high (zero_reg)))
-        (result Reg (alu_add low high)))
+        (result Reg (rv_add low high)))
     (zext result $I64 $I128)))
 
-
-
 (decl lower_clz (Type Reg) Reg)
 (rule (lower_clz ty rs)
   (gen_cltz $true rs ty))
@@ -1009,18 +1450,19 @@
 (rule 1 (lower_clz (fits_in_16 ty) r)
   (if-let $true (has_zbb))
   (let ((tmp Reg (zext r ty $I64))
-        (count Reg (alu_rr_funct12 (AluOPRRI.Clz) tmp))
+        (count Reg (rv_clz tmp))
         ;; We always do the operation on the full 64-bit register, so subtract 64 from the result.
-        (result Reg (alu_rr_imm12 (AluOPRRI.Addi) count (imm12_const_add (ty_bits ty) -64))))
+        (result Reg (rv_addi count (imm12_const_add (ty_bits ty) -64))))
     result))
 
 (rule 2 (lower_clz $I32 r)
   (if-let $true (has_zbb))
-  (alu_rr_funct12 (AluOPRRI.Clzw) r))
+  (rv_clzw r))
 
 (rule 2 (lower_clz $I64 r)
   (if-let $true (has_zbb))
-  (alu_rr_funct12 (AluOPRRI.Clz) r))
+  (rv_clz r))
+
 
 ;; Count leading zeros from a i128 bit value.
 ;; We count both halves separately and conditionally add them if it makes sense.
@@ -1033,16 +1475,16 @@
         (low Reg (lower_clz $I64 x_lo))
         ;; Only add the bottom zeros if the top half is zero
         (low Reg (gen_select_reg (IntCC.Equal) x_hi (zero_reg) low (zero_reg)))
-        (result Reg (alu_add high low)))
+        (result Reg (rv_add high low)))
     (zext result $I64 $I128)))
 
 
 (decl lower_cls (Type Reg) Reg)
 (rule (lower_cls ty r)
   (let ((tmp Reg (ext_int_if_need $true r ty))
-        (tmp2 Reg (gen_select_reg (IntCC.SignedLessThan) tmp (zero_reg) (gen_bit_not tmp) tmp))
+        (tmp2 Reg (gen_select_reg (IntCC.SignedLessThan) tmp (zero_reg) (rv_not tmp) tmp))
         (tmp3 Reg (lower_clz ty tmp2)))
-    (alu_rr_imm12 (AluOPRRI.Addi) tmp3 (imm12_const -1))))
+    (rv_addi tmp3 (imm12_const -1))))
 
 ;; If the sign bit is set, we count the leading zeros of the inverted value.
 ;; Otherwise we can just count the leading zeros of the original value.
@@ -1051,11 +1493,11 @@
 (rule (lower_cls_i128 x)
   (let ((low Reg (value_regs_get x 0))
         (high Reg (value_regs_get x 1))
-        (low Reg (gen_select_reg (IntCC.SignedLessThan) high (zero_reg) (gen_bit_not low) low))
-        (high Reg (gen_select_reg (IntCC.SignedLessThan) high (zero_reg) (gen_bit_not high) high))
+        (low Reg (gen_select_reg (IntCC.SignedLessThan) high (zero_reg) (rv_not low) low))
+        (high Reg (gen_select_reg (IntCC.SignedLessThan) high (zero_reg) (rv_not high) high))
         (tmp ValueRegs (lower_clz_i128 (value_regs low high)))
         (count Reg (value_regs_get tmp 0))
-        (result Reg (alu_rr_imm12 (AluOPRRI.Addi) count (imm12_const -1))))
+        (result Reg (rv_addi count (imm12_const -1))))
     (zext result $I64 $I128)))
 
 
@@ -1106,7 +1548,7 @@
 (rule 0 (extend val extend_op (fits_in_32 from_ty) (fits_in_64 to_ty))
   (let ((val Reg (value_regs_get val 0))
         (shift Imm12 (imm_from_bits (u64_sub 64 (ty_bits from_ty))))
-        (left Reg (alu_rr_imm12 (AluOPRRI.Slli) val shift))
+        (left Reg (rv_slli val shift))
         (shift_op AluOPRRI (extend_shift_op extend_op))
         (right Reg (alu_rr_imm12 shift_op left shift)))
     right))
@@ -1114,13 +1556,13 @@
 ;; If we are zero extending a U8 we can use a `andi` instruction.
 (rule 1 (extend val (ExtendOp.Zero) $I8 (fits_in_64 to_ty))
   (let ((val Reg (value_regs_get val 0)))
-    (alu_rr_imm12 (AluOPRRI.Andi) val (imm12_const 255))))
+    (rv_andi val (imm12_const 255))))
 
 ;; When signed extending from 32 to 64 bits we can use a
 ;; `addiw val 0`. Also known as a `sext.w`
 (rule 1 (extend val (ExtendOp.Signed) $I32 $I64)
   (let ((val Reg (value_regs_get val 0)))
-    (alu_rr_imm12 (AluOPRRI.Addiw) val (imm12_const 0))))
+    (rv_sextw val)))
 
 
 ;; No point in trying to use `packh` here to zero extend 8 bit values
@@ -1130,39 +1572,45 @@
 (rule 1 (extend val (ExtendOp.Zero) $I16 (fits_in_64 _))
   (if-let $true (has_zbkb))
   (let ((val Reg (value_regs_get val 0)))
-    (alu_rrr (AluOPRRR.Packw) val (zero_reg))))
+    (rv_packw val (zero_reg))))
 
 ;; If we have the `zbkb` extension `pack` can be used to zero extend 32 bit registers
 (rule 1 (extend val (ExtendOp.Zero) $I32 $I64)
   (if-let $true (has_zbkb))
   (let ((val Reg (value_regs_get val 0)))
-    (alu_rrr (AluOPRRR.Pack) val (zero_reg))))
+    (rv_pack val (zero_reg))))
 
 
 ;; If we have the `zbb` extension we can use the dedicated `sext.b` instruction.
 (rule 1 (extend val (ExtendOp.Signed) $I8 (fits_in_64 _))
   (if-let $true (has_zbb))
   (let ((val Reg (value_regs_get val 0)))
-    (alu_rr_imm12 (AluOPRRI.Sextb) val (imm12_const 0))))
+    (rv_sextb val)))
 
 ;; If we have the `zbb` extension we can use the dedicated `sext.h` instruction.
 (rule 1 (extend val (ExtendOp.Signed) $I16 (fits_in_64 _))
   (if-let $true (has_zbb))
   (let ((val Reg (value_regs_get val 0)))
-    (alu_rr_imm12 (AluOPRRI.Sexth) val (imm12_const 0))))
+    (rv_sexth val)))
 
 ;; If we have the `zbb` extension we can use the dedicated `zext.h` instruction.
 (rule 2 (extend val (ExtendOp.Zero) $I16 (fits_in_64 _))
   (if-let $true (has_zbb))
   (let ((val Reg (value_regs_get val 0)))
-    (alu_rr_imm12 (AluOPRRI.Zexth) val (imm12_const 0))))
+    (rv_zexth val)))
+
+;; With `zba` we have a `zext.w` instruction
+(rule 2 (extend val (ExtendOp.Zero) $I32 $I64)
+  (if-let $true (has_zba))
+  (let ((val Reg (value_regs_get val 0)))
+    (rv_zextw val)))
 
 ;;; Signed rules extending to I128
 ;; Extend the bottom part, and extract the sign bit from the bottom as the top
-(rule 2 (extend val (ExtendOp.Signed) (fits_in_64 from_ty) $I128)
+(rule 3 (extend val (ExtendOp.Signed) (fits_in_64 from_ty) $I128)
   (let ((val Reg (value_regs_get val 0))
         (low Reg (extend val (ExtendOp.Signed) from_ty $I64))
-        (high Reg (alu_rr_imm12 (AluOPRRI.Srai) low (imm12_const 63))))
+        (high Reg (rv_srai low (imm12_const 63))))
     (value_regs low high)))
 
 ;;; Unsigned rules extending to I128
@@ -1191,24 +1639,24 @@
 (decl lower_umlhi (Type Reg Reg) Reg)
 (rule 1
   (lower_umlhi $I64 rs1 rs2)
-  (alu_rrr (AluOPRRR.Mulhu) rs1 rs2))
+  (rv_mulhu rs1 rs2))
 
 (rule
   (lower_umlhi ty rs1 rs2)
   (let
-    ((tmp Reg (alu_rrr (AluOPRRR.Mul) (ext_int_if_need $false rs1 ty) (ext_int_if_need $false rs2 ty))))
-    (alu_rr_imm12 (AluOPRRI.Srli) tmp (imm12_const (ty_bits ty)))))
+    ((tmp Reg (rv_mul (ext_int_if_need $false rs1 ty) (ext_int_if_need $false rs2 ty))))
+    (rv_srli tmp (imm12_const (ty_bits ty)))))
 
 (decl lower_smlhi (Type Reg Reg) Reg)
 (rule 1
   (lower_smlhi $I64 rs1 rs2)
-  (alu_rrr (AluOPRRR.Mulh) rs1 rs2))
+  (rv_mulh rs1 rs2))
 
 (rule
   (lower_smlhi ty rs1 rs2)
   (let
-    ((tmp Reg (alu_rrr (AluOPRRR.Mul) rs1 rs2)))
-    (alu_rr_imm12 (AluOPRRI.Srli) tmp (imm12_const (ty_bits ty)))))
+    ((tmp Reg (rv_mul rs1 rs2)))
+    (rv_srli tmp (imm12_const (ty_bits ty)))))
 
 
 (decl lower_rotl (Type Reg Reg) Reg)
@@ -1216,7 +1664,7 @@
 (rule 1
   (lower_rotl $I64 rs amount)
   (if-let $true (has_zbb))
-  (alu_rrr (AluOPRRR.Rol) rs amount))
+  (rv_rol rs amount))
 
 (rule
   (lower_rotl $I64 rs amount)
@@ -1226,7 +1674,7 @@
 (rule 1
   (lower_rotl $I32 rs amount)
   (if-let $true (has_zbb))
-  (alu_rrr (AluOPRRR.Rolw) rs amount))
+  (rv_rolw rs amount))
 
 (rule
   (lower_rotl $I32 rs amount)
@@ -1248,11 +1696,11 @@
       (shamt Reg (value_regs_get x 0))
       (len_sub_shamt Reg (value_regs_get x 1))
       ;;
-      (part1 Reg (alu_rrr (AluOPRRR.Sll) rs shamt))
+      (part1 Reg (rv_sll rs shamt))
       ;;
-      (part2 Reg (alu_rrr (AluOPRRR.Srl) rs len_sub_shamt))
+      (part2 Reg (rv_srl rs len_sub_shamt))
       (part3 Reg (gen_select_reg (IntCC.Equal) shamt (zero_reg) (zero_reg) part2)))
-    (alu_rrr (AluOPRRR.Or) part1 part3)))
+    (rv_or part1 part3)))
 
 
 ;;;; construct shift amount.rotl on i128 will use shift to implement. So can call this function.
@@ -1266,7 +1714,7 @@
 (rule 1
   (lower_rotr $I64 rs amount)
   (if-let $true (has_zbb))
-  (alu_rrr (AluOPRRR.Ror) rs amount))
+  (rv_ror rs amount))
 (rule
   (lower_rotr $I64 rs amount)
   (if-let $false (has_zbb))
@@ -1275,7 +1723,7 @@
 (rule 1
   (lower_rotr $I32 rs amount)
   (if-let $true (has_zbb))
-  (alu_rrr (AluOPRRR.Rorw) rs amount))
+  (rv_rorw rs amount))
 
 (rule
   (lower_rotr $I32 rs amount)
@@ -1296,12 +1744,31 @@
       (shamt Reg (value_regs_get x 0))
       (len_sub_shamt Reg (value_regs_get x 1))
       ;;
-      (part1 Reg (alu_rrr (AluOPRRR.Srl) rs shamt))
+      (part1 Reg (rv_srl rs shamt))
       ;;
-      (part2 Reg (alu_rrr (AluOPRRR.Sll) rs len_sub_shamt))
+      (part2 Reg (rv_sll rs len_sub_shamt))
       ;;
       (part3 Reg (gen_select_reg (IntCC.Equal) shamt (zero_reg) (zero_reg) part2)))
-    (alu_rrr (AluOPRRR.Or) part1 part3)))
+    (rv_or part1 part3)))
+
+
+
+;; bseti: Set a single bit in a register, indexed by a constant.
+(decl gen_bseti (Reg u64) Reg)
+(rule (gen_bseti val bit)
+  (if-let $false (has_zbs))
+  (if-let $false (u64_le bit 12))
+  (let ((const Reg (load_u64_constant (u64_shl 1 bit))))
+    (rv_or val const)))
+
+(rule (gen_bseti val bit)
+  (if-let $false (has_zbs))
+  (if-let $true (u64_le bit 12))
+  (rv_ori val (imm12_const (u64_as_i32 (u64_shl 1 bit)))))
+
+(rule (gen_bseti val bit)
+  (if-let $true (has_zbs))
+  (rv_bseti val (imm12_const (u64_as_i32 bit))))
 
 
 (decl gen_popcnt (Reg Type) Reg)
@@ -1315,9 +1782,9 @@
     (writable_reg_to_reg sum)))
 
 (decl lower_popcnt (Reg Type) Reg)
-(rule 1 (lower_popcnt rs ty )
+(rule 1 (lower_popcnt rs ty)
   (if-let $true (has_zbb))
-  (alu_rr_funct12 (AluOPRRI.Cpop) (ext_int_if_need $false rs ty)))
+  (rv_cpop (ext_int_if_need $false rs ty)))
 (rule (lower_popcnt rs ty)
   (if-let $false (has_zbb))
   (gen_popcnt rs ty))
@@ -1331,7 +1798,7 @@
       ;; high part.
       (high Reg (lower_popcnt (value_regs_get a 1) $I64))
       ;; add toghter.
-      (result Reg (alu_add low high)))
+      (result Reg (rv_add low high)))
     (value_regs result (load_u64_constant 0))))
 
 (decl lower_i128_rotl (ValueRegs ValueRegs) ValueRegs)
@@ -1342,19 +1809,19 @@
       (shamt Reg (value_regs_get tmp 0))
       (len_sub_shamt Reg (value_regs_get tmp 1))
       ;;
-      (low_part1 Reg (alu_rrr (AluOPRRR.Sll) (value_regs_get x 0) shamt))
-      (low_part2 Reg (alu_rrr (AluOPRRR.Srl) (value_regs_get x 1) len_sub_shamt))
+      (low_part1 Reg (rv_sll (value_regs_get x 0) shamt))
+      (low_part2 Reg (rv_srl (value_regs_get x 1) len_sub_shamt))
       ;;; if shamt == 0 low_part2 will overflow we should zero instead.
       (low_part3 Reg (gen_select_reg (IntCC.Equal) shamt (zero_reg) (zero_reg) low_part2))
-      (low Reg (alu_rrr (AluOPRRR.Or) low_part1 low_part3))
+      (low Reg (rv_or low_part1 low_part3))
       ;;
-      (high_part1 Reg (alu_rrr (AluOPRRR.Sll) (value_regs_get x 1) shamt))
-      (high_part2 Reg (alu_rrr (AluOPRRR.Srl) (value_regs_get x 0) len_sub_shamt))
+      (high_part1 Reg (rv_sll (value_regs_get x 1) shamt))
+      (high_part2 Reg (rv_srl (value_regs_get x 0) len_sub_shamt))
       (high_part3 Reg (gen_select_reg (IntCC.Equal) shamt (zero_reg) (zero_reg) high_part2))
-      (high Reg (alu_rrr (AluOPRRR.Or) high_part1 high_part3))
+      (high Reg (rv_or high_part1 high_part3))
       ;;
       (const64 Reg (load_u64_constant 64))
-      (shamt_128 Reg (alu_andi (value_regs_get y 0) 127)))
+      (shamt_128 Reg (rv_andi (value_regs_get y 0) (imm12_const 127))))
     ;; right now we only rotate less than 64 bits.
     ;; if shamt is greater than or equal 64 , we should switch low and high.
     (value_regs
@@ -1371,20 +1838,20 @@
       (shamt Reg (value_regs_get tmp 0))
       (len_sub_shamt Reg (value_regs_get tmp 1))
       ;;
-      (low_part1 Reg (alu_rrr (AluOPRRR.Srl) (value_regs_get x 0) shamt))
-      (low_part2 Reg (alu_rrr (AluOPRRR.Sll) (value_regs_get x 1) len_sub_shamt))
+      (low_part1 Reg (rv_srl (value_regs_get x 0) shamt))
+      (low_part2 Reg (rv_sll (value_regs_get x 1) len_sub_shamt))
       ;;; if shamt == 0 low_part2 will overflow we should zero instead.
       (low_part3 Reg (gen_select_reg (IntCC.Equal) shamt (zero_reg) (zero_reg) low_part2))
-      (low Reg (alu_rrr (AluOPRRR.Or) low_part1 low_part3))
+      (low Reg (rv_or low_part1 low_part3))
       ;;
-      (high_part1 Reg (alu_rrr (AluOPRRR.Srl) (value_regs_get x 1) shamt))
-      (high_part2 Reg (alu_rrr (AluOPRRR.Sll) (value_regs_get x 0) len_sub_shamt))
+      (high_part1 Reg (rv_srl (value_regs_get x 1) shamt))
+      (high_part2 Reg (rv_sll (value_regs_get x 0) len_sub_shamt))
       (high_part3 Reg (gen_select_reg (IntCC.Equal) shamt (zero_reg) (zero_reg) high_part2))
-      (high Reg (alu_rrr (AluOPRRR.Or) high_part1 high_part3))
+      (high Reg (rv_or high_part1 high_part3))
 
       ;;
       (const64 Reg (load_u64_constant 64))
-      (shamt_128 Reg (alu_andi (value_regs_get y 0) 127)))
+      (shamt_128 Reg (rv_andi (value_regs_get y 0) (imm12_const 127))))
     ;; right now we only rotate less than 64 bits.
     ;; if shamt is greater than or equal 64 , we should switch low and high.
     (value_regs
@@ -1401,16 +1868,16 @@
       (shamt Reg (value_regs_get tmp 0))
       (len_sub_shamt Reg (value_regs_get tmp 1))
       ;;
-      (low Reg (alu_rrr (AluOPRRR.Sll) (value_regs_get x 0) shamt))
+      (low Reg (rv_sll (value_regs_get x 0) shamt))
       ;; high part.
-      (high_part1 Reg (alu_rrr (AluOPRRR.Srl) (value_regs_get x 0) len_sub_shamt))
+      (high_part1 Reg (rv_srl (value_regs_get x 0) len_sub_shamt))
       (high_part2 Reg (gen_select_reg (IntCC.Equal) shamt (zero_reg) (zero_reg) high_part1))
       ;;
-      (high_part3 Reg (alu_rrr (AluOPRRR.Sll) (value_regs_get x 1) shamt))
-      (high Reg (alu_rrr (AluOPRRR.Or) high_part2 high_part3 ))
+      (high_part3 Reg (rv_sll (value_regs_get x 1) shamt))
+      (high Reg (rv_or high_part2 high_part3 ))
       ;;
       (const64 Reg (load_u64_constant 64))
-      (shamt_128 Reg (alu_andi (value_regs_get y 0) 127)))
+      (shamt_128 Reg (rv_andi (value_regs_get y 0) (imm12_const 127))))
     (value_regs
       (gen_select_reg (IntCC.UnsignedGreaterThanOrEqual) shamt_128 const64 (zero_reg) low)
       (gen_select_reg (IntCC.UnsignedGreaterThanOrEqual) shamt_128 const64 low high))))
@@ -1424,17 +1891,17 @@
       (len_sub_shamt Reg (value_regs_get tmp 1))
 
       ;; low part.
-      (low_part1 Reg (alu_rrr (AluOPRRR.Sll) (value_regs_get x 1) len_sub_shamt))
+      (low_part1 Reg (rv_sll (value_regs_get x 1) len_sub_shamt))
       (low_part2 Reg (gen_select_reg (IntCC.Equal) shamt (zero_reg) (zero_reg) low_part1))
       ;;
-      (low_part3 Reg (alu_rrr (AluOPRRR.Srl) (value_regs_get x 0) shamt))
-      (low Reg (alu_rrr (AluOPRRR.Or) low_part2 low_part3 ))
+      (low_part3 Reg (rv_srl (value_regs_get x 0) shamt))
+      (low Reg (rv_or low_part2 low_part3 ))
       ;;
       (const64 Reg (load_u64_constant 64))
 
       ;;
-      (high Reg (alu_rrr (AluOPRRR.Srl) (value_regs_get x 1) shamt))
-      (shamt_128 Reg (alu_andi (value_regs_get y 0) 127)))
+      (high Reg (rv_srl (value_regs_get x 1) shamt))
+      (shamt_128 Reg (rv_andi (value_regs_get y 0) (imm12_const 127))))
     (value_regs
       (gen_select_reg (IntCC.UnsignedGreaterThanOrEqual) shamt_128 const64 high low)
       (gen_select_reg (IntCC.UnsignedGreaterThanOrEqual) shamt_128 const64 (zero_reg) high))))
@@ -1449,21 +1916,21 @@
       (len_sub_shamt Reg (value_regs_get tmp 1))
 
       ;; low part.
-      (low_part1 Reg (alu_rrr (AluOPRRR.Sll) (value_regs_get x 1) len_sub_shamt))
+      (low_part1 Reg (rv_sll (value_regs_get x 1) len_sub_shamt))
       (low_part2 Reg (gen_select_reg (IntCC.Equal) shamt (zero_reg) (zero_reg) low_part1))
       ;;
-      (low_part3 Reg (alu_rrr (AluOPRRR.Srl) (value_regs_get x 0) shamt))
-      (low Reg (alu_rrr (AluOPRRR.Or) low_part2 low_part3 ))
+      (low_part3 Reg (rv_srl (value_regs_get x 0) shamt))
+      (low Reg (rv_or low_part2 low_part3 ))
       ;;
       (const64 Reg (load_u64_constant 64))
       ;;
-      (high Reg (alu_rrr (AluOPRRR.Sra) (value_regs_get x 1) shamt))
+      (high Reg (rv_sra (value_regs_get x 1) shamt))
       ;;
       (const_neg_1 Reg (load_imm12 -1))
       ;;
       (high_replacement Reg (gen_select_reg (IntCC.SignedLessThan) (value_regs_get x 1) (zero_reg) const_neg_1 (zero_reg)))
       (const64 Reg (load_u64_constant 64))
-      (shamt_128 Reg (alu_andi (value_regs_get y 0) 127)))
+      (shamt_128 Reg (rv_andi (value_regs_get y 0) (imm12_const 127))))
     (value_regs
       (gen_select_reg (IntCC.UnsignedGreaterThanOrEqual) shamt_128 const64 high low)
       (gen_select_reg (IntCC.UnsignedGreaterThanOrEqual) shamt_128 const64 high_replacement high))))
@@ -1619,45 +2086,6 @@
   (side_effect (SideEffectNoResult.Inst (MInst.AtomicStore src ty p)))
 )
 
-;; helper function to inverse all bits.
-(decl gen_bit_not (Reg) Reg)
-(rule (gen_bit_not r)
-  (alu_rr_imm12 (AluOPRRI.Xori) r (imm12_const -1)))
-
-
-;; float arithmatic op
-(decl f_arithmatic_op (Type Opcode) FpuOPRRR)
-(rule
-  (f_arithmatic_op $F32 (Opcode.Fadd))
-  (FpuOPRRR.FaddS))
-
-(rule
-  (f_arithmatic_op $F64 (Opcode.Fadd))
-  (FpuOPRRR.FaddD))
-
-(rule
-  (f_arithmatic_op $F32 (Opcode.Fsub))
-  (FpuOPRRR.FsubS))
-(rule
-  (f_arithmatic_op $F64 (Opcode.Fsub))
-  (FpuOPRRR.FsubD))
-
-(rule
-  (f_arithmatic_op $F32 (Opcode.Fmul))
-  (FpuOPRRR.FmulS))
-
-(rule
-  (f_arithmatic_op $F64 (Opcode.Fmul))
-  (FpuOPRRR.FmulD))
-
-(rule
-  (f_arithmatic_op $F32 (Opcode.Fdiv))
-  (FpuOPRRR.FdivS))
-
-(rule
-  (f_arithmatic_op $F64 (Opcode.Fdiv))
-  (FpuOPRRR.FdivD))
-
 
 (decl move_f_to_x (Reg Type) Reg)
 (extern constructor move_f_to_x move_f_to_x)
@@ -1665,21 +2093,6 @@
 (decl move_x_to_f (Reg Type) Reg)
 (extern constructor move_x_to_f move_x_to_f)
 
-
-;;float copy sign bit op.
-(decl f_copysign_op (Type) FpuOPRRR)
-(rule (f_copysign_op $F32) (FpuOPRRR.FsgnjS))
-(rule (f_copysign_op $F64) (FpuOPRRR.FsgnjD))
-
-;;float copy neg sign bit op.
-(decl f_copy_neg_sign_op (Type) FpuOPRRR)
-(rule (f_copy_neg_sign_op $F32) (FpuOPRRR.FsgnjnS))
-(rule (f_copy_neg_sign_op $F64) (FpuOPRRR.FsgnjnD))
-
-(decl fabs_copy_sign (Type) FpuOPRRR)
-(rule (fabs_copy_sign $F32) (FpuOPRRR.FsgnjxS))
-(rule (fabs_copy_sign $F64) (FpuOPRRR.FsgnjxD))
-
 (decl gen_stack_addr (StackSlot Offset32) Reg )
 (extern constructor gen_stack_addr gen_stack_addr)
 
@@ -1728,13 +2141,13 @@
 (rule
   (gen_bitselect ty c x y)
   (let
-    ((tmp_x Reg (alu_rrr (AluOPRRR.And) c x))
+    ((tmp_x Reg (rv_and c x))
       ;;;inverse condition
-      (c_inverse Reg (gen_bit_not c))
+      (c_inverse Reg (rv_not c))
       ;;;get all y part.
-      (tmp_y Reg (alu_rrr (AluOPRRR.And) c_inverse y))
+      (tmp_y Reg (rv_and c_inverse y))
       ;;;get reuslt.
-      (result Reg (alu_rrr (AluOPRRR.Or) tmp_x tmp_y)))
+      (result Reg (rv_or tmp_x tmp_y)))
     result))
 
 (decl gen_int_select (Type IntSelectOP ValueRegs ValueRegs) ValueRegs)
@@ -1825,7 +2238,7 @@
     (;; move to x register.
       (tmp Reg (move_f_to_x x ty))
       ;; inverse all bits.
-      (tmp2 Reg (gen_bit_not tmp)))
+      (tmp2 Reg (rv_not tmp)))
     ;; move back to float register.
     (move_x_to_f tmp2 ty)))
 
@@ -1844,27 +2257,22 @@
   (i128_sub x y )
   (let
     (;; low part.
-      (low Reg (alu_rrr (AluOPRRR.Sub) (value_regs_get x 0) (value_regs_get y 0)))
+      (low Reg (rv_sub (value_regs_get x 0) (value_regs_get y 0)))
       ;; compute borrow.
-      (borrow Reg (alu_rrr (AluOPRRR.SltU) (value_regs_get x 0) low))
+      (borrow Reg (rv_sltu (value_regs_get x 0) low))
       ;;
-      (high_tmp Reg (alu_rrr (AluOPRRR.Sub) (value_regs_get x 1) (value_regs_get y 1)))
+      (high_tmp Reg (rv_sub (value_regs_get x 1) (value_regs_get y 1)))
       ;;
-      (high Reg (alu_rrr (AluOPRRR.Sub) high_tmp borrow)))
+      (high Reg (rv_sub high_tmp borrow)))
     (value_regs low high)))
 
 
-(decl gen_fabs (Reg Type) Reg)
-(rule
-  (gen_fabs x ty)
-  (fpu_rrr (fabs_copy_sign ty) ty x x))
-
 ;;; Returns the sum in the first register, and the overflow test in the second.
 (decl lower_uadd_overflow (Reg Reg Type) ValueRegs)
 
 (rule 1
   (lower_uadd_overflow x y $I64)
-  (let ((tmp Reg (alu_add x y))
+  (let ((tmp Reg (rv_add x y))
         (test Reg (gen_icmp (IntCC.UnsignedLessThan) tmp x $I64)))
     (value_regs tmp test)))
 
@@ -1872,8 +2280,8 @@
   (lower_uadd_overflow x y (fits_in_32 ty))
   (let ((tmp_x Reg (ext_int_if_need $false x ty))
         (tmp_y Reg (ext_int_if_need $false y ty))
-        (sum Reg (alu_add tmp_x tmp_y))
-        (test Reg (alu_srli sum (ty_bits ty))))
+        (sum Reg (rv_add tmp_x tmp_y))
+        (test Reg (rv_srli sum (imm12_const (ty_bits ty)))))
     (value_regs sum test)))
 
 (decl inst_output_get (InstOutput u8) ValueRegs)
@@ -1935,7 +2343,7 @@
 (rule 0 (truthy_to_reg $I128 regs)
       (let ((lo Reg (value_regs_get regs 0))
             (hi Reg (value_regs_get regs 1)))
-        (alu_rrr (AluOPRRR.Or) lo hi)))
+        (rv_or lo hi)))
 
 ;; Default behavior for branching based on an input value.
 (rule
@@ -1980,21 +2388,11 @@
 (decl load_ra () Reg)
 (extern constructor load_ra load_ra)
 
-;;;
-(decl gen_andn (Reg Reg) Reg)
-(rule 1 (gen_andn rs1 rs2)
-  (alu_rrr (AluOPRRR.Andn) rs1 rs2))
-
-;;;
-(decl gen_orn (Reg Reg) Reg)
-(rule 1 (gen_orn rs1 rs2)
-  (alu_rrr (AluOPRRR.Orn) rs1 rs2))
-
 (decl gen_rev8 (Reg) Reg)
 (rule 1
   (gen_rev8 rs)
   (if-let $true (has_zbb))
-  (alu_rr_funct12 (AluOPRRI.Rev8) rs))
+  (rv_rev8 rs))
 
 (rule
   (gen_rev8 rs)
@@ -2011,7 +2409,7 @@
 (rule 1
   (gen_brev8 rs _)
   (if-let $true (has_zbkb))
-  (alu_rr_funct12 (AluOPRRI.Brev8) rs))
+  (rv_brev8 rs))
 (rule
   (gen_brev8 rs ty)
   (if-let $false (has_zbkb))
@@ -2028,7 +2426,7 @@
 (decl neg (Type ValueRegs) ValueRegs)
 (rule 1 (neg (fits_in_64 (ty_int ty)) val)
   (value_reg
-    (alu_rrr (AluOPRRR.Sub) (zero_reg) (value_regs_get val 0))))
+    (rv_neg (value_regs_get val 0))))
 
 (rule 2 (neg $I128 val)
   (i128_sub (value_regs_zero) val))
@@ -2038,7 +2436,7 @@
 (decl max (Type Reg Reg) Reg)
 (rule (max (fits_in_64 (ty_int ty)) x y)
   (if-let $true (has_zbb))
-  (alu_rrr (AluOPRRR.Max) x y))
+  (rv_max x y))
 
 (rule (max (fits_in_64 (ty_int ty)) x y)
   (if-let $false (has_zbb))
@@ -2076,11 +2474,11 @@
   (gen_div_overflow rs1 rs2 ty)
   (let
     ((r_const_neg_1 Reg (load_imm12 -1))
-      (r_const_min Reg (alu_slli (load_imm12 1) 63))
+      (r_const_min Reg (rv_slli (load_imm12 1) (imm12_const 63)))
       (tmp_rs1 Reg (shift_int_to_most_significant rs1 ty))
       (t1 Reg (gen_icmp (IntCC.Equal) r_const_neg_1 rs2 ty))
       (t2 Reg (gen_icmp (IntCC.Equal) r_const_min tmp_rs1 ty))
-      (test Reg (alu_and t1 t2)))
+      (test Reg (rv_and t1 t2)))
     (gen_trapif test (TrapCode.IntegerOverflow))))
 
 (decl gen_div_by_zero (Reg) InstOutput)
@@ -2101,12 +2499,8 @@
 (rule
   (madd n m a)
   (let
-    ((t Reg (alu_rrr (AluOPRRR.Mul) n m)))
-    (alu_add t a)))
-
-(decl umulh (Reg Reg) Reg)
-(rule (umulh a b)
-  (alu_rrr (AluOPRRR.Mulhu) a b))
+    ((t Reg (rv_mul n m)))
+    (rv_add t a)))
 
 ;;;; Helpers for bmask ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 
@@ -2130,7 +2524,7 @@
   (lower_bmask (fits_in_64 ty) $I128 val)
   (let ((lo Reg (value_regs_get val 0))
         (hi Reg (value_regs_get val 1))
-        (combined Reg (alu_rrr (AluOPRRR.Or) lo hi)))
+        (combined Reg (rv_or lo hi)))
     (lower_bmask ty $I64 (value_reg combined))))
 
 ;; Conversion of one 64-bit value to a 128-bit one. Duplicate the result of the
@@ -2182,37 +2576,13 @@
 ;;;; Helpers for floating point comparisons ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 
 (decl not (Reg) Reg)
-(rule (not x) (alu_rr_imm12 (AluOPRRI.Xori) x (imm_from_bits 1)))
-
-(decl emit_or (Reg Reg) Reg)
-(rule (emit_or x y) (alu_rrr (AluOPRRR.Or) x y))
-
-(decl emit_and (Reg Reg) Reg)
-(rule (emit_and x y) (alu_rrr (AluOPRRR.And) x y))
+(rule (not x) (rv_xori x (imm_from_bits 1)))
 
 (decl is_not_nan (Type Reg) Reg)
-(rule (is_not_nan ty a) (feq ty a a))
-
-(decl feq (Type Reg Reg) Reg)
-(rule (feq $F32 a b) (fpu_rrr (FpuOPRRR.FeqS) $I64 a b))
-(rule (feq $F64 a b) (fpu_rrr (FpuOPRRR.FeqD) $I64 a b))
-
-(decl flt (Type Reg Reg) Reg)
-(rule (flt $F32 a b) (fpu_rrr (FpuOPRRR.FltS) $I64 a b))
-(rule (flt $F64 a b) (fpu_rrr (FpuOPRRR.FltD) $I64 a b))
-
-(decl fle (Type Reg Reg) Reg)
-(rule (fle $F32 a b) (fpu_rrr (FpuOPRRR.FleS) $I64 a b))
-(rule (fle $F64 a b) (fpu_rrr (FpuOPRRR.FleD) $I64 a b))
-
-(decl fgt (Type Reg Reg) Reg)
-(rule (fgt ty a b) (flt ty b a))
-
-(decl fge (Type Reg Reg) Reg)
-(rule (fge ty a b) (fle ty b a))
+(rule (is_not_nan ty a) (rv_feq ty a a))
 
 (decl ordered (Type Reg Reg) Reg)
-(rule (ordered ty a b) (emit_and (is_not_nan ty a) (is_not_nan ty b)))
+(rule (ordered ty a b) (rv_and (is_not_nan ty a) (is_not_nan ty b)))
 
 (type CmpResult (enum
                   (Result
@@ -2272,64 +2642,64 @@
 ;; a == b
 (rule
   (emit_fcmp (FloatCC.Equal) ty a b)
-  (cmp_result (feq ty a b)))
+  (cmp_result (rv_feq ty a b)))
 
 ;; a != b
 ;; == !(a == b)
 (rule
   (emit_fcmp (FloatCC.NotEqual) ty a b)
-  (cmp_result_invert (feq ty a b)))
+  (cmp_result_invert (rv_feq ty a b)))
 
 ;; a < b || a > b
 (rule
   (emit_fcmp (FloatCC.OrderedNotEqual) ty a b)
-  (cmp_result (emit_or (flt ty a b) (fgt ty a b))))
+  (cmp_result (rv_or (rv_flt ty a b) (rv_fgt ty a b))))
 
 ;; !(ordered a b) || a == b
 (rule
   (emit_fcmp (FloatCC.UnorderedOrEqual) ty a b)
-  (cmp_result (emit_or (not (ordered ty a b)) (feq ty a b))))
+  (cmp_result (rv_or (not (ordered ty a b)) (rv_feq ty a b))))
 
 ;; a < b
 (rule
   (emit_fcmp (FloatCC.LessThan) ty a b)
-  (cmp_result (flt ty a b)))
+  (cmp_result (rv_flt ty a b)))
 
 ;; a <= b
 (rule
   (emit_fcmp (FloatCC.LessThanOrEqual) ty a b)
-  (cmp_result (fle ty a b)))
+  (cmp_result (rv_fle ty a b)))
 
 ;; a > b
 (rule
   (emit_fcmp (FloatCC.GreaterThan) ty a b)
-  (cmp_result (fgt ty a b)))
+  (cmp_result (rv_fgt ty a b)))
 
 ;; a >= b
 (rule
   (emit_fcmp (FloatCC.GreaterThanOrEqual) ty a b)
-  (cmp_result (fge ty a b)))
+  (cmp_result (rv_fge ty a b)))
 
 ;; !(ordered a b) || a < b
 ;; == !(ordered a b && a >= b)
 (rule
   (emit_fcmp (FloatCC.UnorderedOrLessThan) ty a b)
-  (cmp_result_invert (emit_and (ordered ty a b) (fge ty a b))))
+  (cmp_result_invert (rv_and (ordered ty a b) (rv_fge ty a b))))
 
 ;; !(ordered a b) || a <= b
 ;; == !(ordered a b && a > b)
 (rule
   (emit_fcmp (FloatCC.UnorderedOrLessThanOrEqual) ty a b)
-  (cmp_result_invert (emit_and (ordered ty a b) (fgt ty a b))))
+  (cmp_result_invert (rv_and (ordered ty a b) (rv_fgt ty a b))))
 
 ;; !(ordered a b) || a > b
 ;; == !(ordered a b && a <= b)
 (rule
   (emit_fcmp (FloatCC.UnorderedOrGreaterThan) ty a b)
-  (cmp_result_invert (emit_and (ordered ty a b) (fle ty a b))))
+  (cmp_result_invert (rv_and (ordered ty a b) (rv_fle ty a b))))
 
 ;; !(ordered a b) || a >= b
 ;; == !(ordered a b && a < b)
 (rule
   (emit_fcmp (FloatCC.UnorderedOrGreaterThanOrEqual) ty a b)
-  (cmp_result_invert (emit_and (ordered ty a b) (flt ty a b))))
+  (cmp_result_invert (rv_and (ordered ty a b) (rv_flt ty a b))))
diff --git a/cranelift/codegen/src/isa/riscv64/inst/emit.rs b/cranelift/codegen/src/isa/riscv64/inst/emit.rs
index d44d2d306..3d2585930 100644
--- a/cranelift/codegen/src/isa/riscv64/inst/emit.rs
+++ b/cranelift/codegen/src/isa/riscv64/inst/emit.rs
@@ -370,68 +370,6 @@ impl Inst {
         }
         insts
     }
-
-    /// check if float is unordered.
-    pub(crate) fn lower_float_unordered(
-        tmp: Writable<Reg>,
-        ty: Type,
-        x: Reg,
-        y: Reg,
-        taken: BranchTarget,
-        not_taken: BranchTarget,
-    ) -> SmallInstVec<Inst> {
-        let mut insts = SmallInstVec::new();
-        let class_op = if ty == F32 {
-            FpuOPRR::FclassS
-        } else {
-            FpuOPRR::FclassD
-        };
-        // if x is nan
-        insts.push(Inst::FpuRR {
-            frm: None,
-            alu_op: class_op,
-            rd: tmp,
-            rs: x,
-        });
-        insts.push(Inst::AluRRImm12 {
-            alu_op: AluOPRRI::Andi,
-            rd: tmp,
-            rs: tmp.to_reg(),
-            imm12: Imm12::from_bits(FClassResult::is_nan_bits() as i16),
-        });
-        insts.push(Inst::CondBr {
-            taken,
-            not_taken: BranchTarget::zero(),
-            kind: IntegerCompare {
-                kind: IntCC::NotEqual,
-                rs1: tmp.to_reg(),
-                rs2: zero_reg(),
-            },
-        });
-        // if y is nan.
-        insts.push(Inst::FpuRR {
-            frm: None,
-            alu_op: class_op,
-            rd: tmp,
-            rs: y,
-        });
-        insts.push(Inst::AluRRImm12 {
-            alu_op: AluOPRRI::Andi,
-            rd: tmp,
-            rs: tmp.to_reg(),
-            imm12: Imm12::from_bits(FClassResult::is_nan_bits() as i16),
-        });
-        insts.push(Inst::CondBr {
-            taken,
-            not_taken,
-            kind: IntegerCompare {
-                kind: IntCC::NotEqual,
-                rs1: tmp.to_reg(),
-                rs2: zero_reg(),
-            },
-        });
-        insts
-    }
 }
 
 impl MachInstEmit for Inst {
diff --git a/cranelift/codegen/src/isa/riscv64/inst/mod.rs b/cranelift/codegen/src/isa/riscv64/inst/mod.rs
index 8ad8a4f13..e62be595f 100644
--- a/cranelift/codegen/src/isa/riscv64/inst/mod.rs
+++ b/cranelift/codegen/src/isa/riscv64/inst/mod.rs
@@ -1220,10 +1220,17 @@ impl Inst {
                 rs1,
                 rs2,
             } => {
-                let rs1 = format_reg(rs1, allocs);
-                let rs2 = format_reg(rs2, allocs);
-                let rd = format_reg(rd.to_reg(), allocs);
-                format!("{} {},{},{}", alu_op.op_name(), rd, rs1, rs2,)
+                let rs1_s = format_reg(rs1, allocs);
+                let rs2_s = format_reg(rs2, allocs);
+                let rd_s = format_reg(rd.to_reg(), allocs);
+                match alu_op {
+                    AluOPRRR::Adduw if rs2 == zero_reg() => {
+                        format!("zext.w {},{}", rd_s, rs1_s)
+                    }
+                    _ => {
+                        format!("{} {},{},{}", alu_op.op_name(), rd_s, rs1_s, rs2_s)
+                    }
+                }
             }
             &Inst::FpuRR {
                 frm,
diff --git a/cranelift/codegen/src/isa/riscv64/lower.isle b/cranelift/codegen/src/isa/riscv64/lower.isle
index 458b59847..3bc08aa70 100644
--- a/cranelift/codegen/src/isa/riscv64/lower.isle
+++ b/cranelift/codegen/src/isa/riscv64/lower.isle
@@ -26,12 +26,10 @@
 
 
 ;;;; Rules for `iadd` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-(rule -1 (lower (has_type (fits_in_32 ty) (iadd x y)))
-  (alu_rrr (AluOPRRR.Addw) x y))
 
 ;; Base case, simply adding things in registers.
-(rule -2 (lower (has_type (fits_in_64 ty) (iadd x y)))
-  (alu_add x y))
+(rule 0 (lower (has_type (fits_in_64 ty) (iadd x y)))
+  (rv_add x y))
 
 ;; Special cases for when one operand is an immediate that fits in 12 bits.
 (rule 1 (lower (has_type (fits_in_64 ty) (iadd x (imm12_from_value y))))
@@ -40,17 +38,63 @@
 (rule 2 (lower (has_type (fits_in_64 ty) (iadd (imm12_from_value x) y)))
   (alu_rr_imm12 (select_addi ty) y x))
 
-(rule
-  (lower (has_type $I128 (iadd x y)))
-  (let
-    ( ;; low part.
-      (low Reg (alu_add (value_regs_get x 0) (value_regs_get y 0)))
-      ;; compute carry.
-      (carry Reg (alu_rrr (AluOPRRR.SltU) low (value_regs_get y 0)))
-      ;;
-      (high_tmp Reg (alu_add (value_regs_get x 1) (value_regs_get y 1)))
-      ;; add carry.
-      (high Reg (alu_add high_tmp carry)))
+;; Special case when one of the operands is uextended
+;; Needs `Zba`
+(rule 3 (lower (has_type $I64 (iadd x (uextend y @ (value_type $I32)))))
+  (if-let $true (has_zba))
+  (rv_adduw y x))
+
+(rule 4 (lower (has_type $I64 (iadd (uextend x @ (value_type $I32)) y)))
+  (if-let $true (has_zba))
+  (rv_adduw x y))
+
+;; Add with const shift. We have a few of these instructions with `Zba`.
+(decl pure partial match_shnadd (Imm64) AluOPRRR)
+(rule (match_shnadd (u64_from_imm64 1)) (AluOPRRR.Sh1add))
+(rule (match_shnadd (u64_from_imm64 2)) (AluOPRRR.Sh2add))
+(rule (match_shnadd (u64_from_imm64 3)) (AluOPRRR.Sh3add))
+  
+(rule 3 (lower (has_type $I64 (iadd x (ishl y (maybe_uextend (iconst n))))))
+  (if-let $true (has_zba))
+  (if-let shnadd (match_shnadd n))
+  (alu_rrr shnadd y x))
+
+(rule 4 (lower (has_type $I64 (iadd (ishl x (maybe_uextend (iconst n))) y)))
+  (if-let $true (has_zba))
+  (if-let shnadd (match_shnadd n))
+  (alu_rrr shnadd x y))
+
+
+;; Add with uextended const shift. We have a few of these instructions with `Zba`.
+;;
+;; !!! Important !!!
+;; These rules only work for (ishl (uextend _) _) and not for (uextend (ishl _ _))!
+;; Getting this wrong means a potential misscalculation of the shift amount.
+;; Additionaly we can only ensure that this is correct if the uextend is 32 to 64 bits.
+(decl pure partial match_shnadd_uw (Imm64) AluOPRRR)
+(rule (match_shnadd_uw (u64_from_imm64 1)) (AluOPRRR.Sh1adduw))
+(rule (match_shnadd_uw (u64_from_imm64 2)) (AluOPRRR.Sh2adduw))
+(rule (match_shnadd_uw (u64_from_imm64 3)) (AluOPRRR.Sh3adduw))
+  
+(rule 5 (lower (has_type $I64 (iadd x (ishl (uextend y @ (value_type $I32)) (maybe_uextend (iconst n))))))
+  (if-let $true (has_zba))
+  (if-let shnadd_uw (match_shnadd_uw n))
+  (alu_rrr shnadd_uw y x))
+
+(rule 6 (lower (has_type $I64 (iadd (ishl (uextend x @ (value_type $I32)) (maybe_uextend (iconst n))) y)))
+  (if-let $true (has_zba))
+  (if-let shnadd_uw (match_shnadd_uw n))
+  (alu_rrr shnadd_uw x y))
+
+;; I128 cases
+(rule 7 (lower (has_type $I128 (iadd x y)))
+  (let ((low Reg (rv_add (value_regs_get x 0) (value_regs_get y 0)))
+        ;; compute carry.
+        (carry Reg (rv_sltu low (value_regs_get y 0)))
+        ;;
+        (high_tmp Reg (rv_add (value_regs_get x 1) (value_regs_get y 1)))
+        ;; add carry.
+        (high Reg (rv_add high_tmp carry)))
     (value_regs low high)))
 
 ;;; Rules for `uadd_overflow_trap` ;;;;;;;;;;;;;
@@ -65,10 +109,10 @@
 ;; Base case, simply subtracting things in registers.
 
 (rule -2 (lower (has_type (fits_in_64 ty) (isub x y)))
-  (alu_rrr (AluOPRRR.Sub) x y))
+  (rv_sub x y))
 
 (rule -1 (lower (has_type (fits_in_32 ty) (isub x y)))
-  (alu_rrr (AluOPRRR.Subw) x y))
+  (rv_subw x y))
 
 (rule (lower (has_type $I128 (isub x y)))
   (i128_sub x y))
@@ -82,9 +126,9 @@
 ;;;; Rules for `imul` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 
 (rule -2 (lower (has_type (fits_in_64 ty) (imul x y)))
-  (alu_rrr (AluOPRRR.Mul) x y))
+  (rv_mul x y))
 (rule -1 (lower (has_type (fits_in_32 ty) (imul x y)))
-  (alu_rrr (AluOPRRR.Mulw) x y))
+  (rv_mulw x y))
 
 ;;;; Rules for `smulhi` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 (rule (lower (has_type (fits_in_64 ty) (smulhi x y)))
@@ -108,14 +152,14 @@
 
       ;; 128bit mul formula:
       ;;   dst_lo = x_lo * y_lo
-      ;;   dst_hi = umulhi(x_lo, y_lo) + (x_lo * y_hi) + (x_hi * y_lo)
+      ;;   dst_hi = mulhu(x_lo, y_lo) + (x_lo * y_hi) + (x_hi * y_lo)
       ;;
       ;; We can convert the above formula into the following
-      ;; umulh   dst_hi, x_lo, y_lo
+      ;; mulhu   dst_hi, x_lo, y_lo
       ;; madd    dst_hi, x_lo, y_hi, dst_hi
       ;; madd    dst_hi, x_hi, y_lo, dst_hi
       ;; madd    dst_lo, x_lo, y_lo, zero
-      (dst_hi1 Reg (umulh x_lo y_lo))
+      (dst_hi1 Reg (rv_mulhu x_lo y_lo))
       (dst_hi2 Reg (madd x_lo y_hi dst_hi1))
       (dst_hi Reg (madd x_hi y_lo dst_hi2))
       (dst_lo Reg (madd x_lo y_lo (zero_reg))))
@@ -128,7 +172,7 @@
   (let
     ((y2 Reg (ext_int_if_need $false y ty))
       (_ InstOutput (gen_div_by_zero y2)))
-    (alu_rrr (AluOPRRR.Divuw) (ext_int_if_need $false x ty) y2)))
+    (rv_divuw (ext_int_if_need $false x ty) y2)))
 
 (rule -1 (lower (has_type (fits_in_32 ty) (sdiv x y)))
   (let
@@ -136,18 +180,18 @@
       (b Reg (ext_int_if_need $true y ty))
       (_ InstOutput (gen_div_overflow a b ty))
       (_ InstOutput (gen_div_by_zero b)))
-    (alu_rrr (AluOPRRR.Divw) a b)))
+    (rv_divw a b)))
 
 (rule (lower (has_type $I64 (sdiv x y)))
   (let
     ((_ InstOutput (gen_div_overflow x y $I64))
       (_ InstOutput (gen_div_by_zero y))    )
-    (alu_rrr (AluOPRRR.Div) x y)))
+    (rv_div x y)))
 
 (rule (lower (has_type $I64 (udiv x y)))
   (let
     ((_ InstOutput (gen_div_by_zero y)))
-    (alu_rrr (AluOPRRR.DivU) x y)))
+    (rv_divu x y)))
 
 ;;;; Rules for `rem` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 
@@ -155,46 +199,46 @@
   (let
     ((y2 Reg (ext_int_if_need $false y ty))
       (_ InstOutput (gen_div_by_zero y2)))
-    (alu_rrr (AluOPRRR.Remuw) (ext_int_if_need $false x ty) y2)))
+    (rv_remuw (ext_int_if_need $false x ty) y2)))
 
 (rule -1 (lower (has_type (fits_in_16 ty) (srem x y)))
   (let
     ((y2 Reg (ext_int_if_need $true y ty))
       (_ InstOutput (gen_div_by_zero y2)))
-    (alu_rrr (AluOPRRR.Remw) (ext_int_if_need $true x ty) y2)))
+    (rv_remw (ext_int_if_need $true x ty) y2)))
 
 (rule (lower (has_type $I32 (srem x y)))
   (let
     ((y2 Reg (ext_int_if_need $true y $I32))
       (_ InstOutput (gen_div_by_zero y2)))
-   (alu_rrr (AluOPRRR.Remw) x y2)))
+   (rv_remw x y2)))
 
 (rule (lower (has_type $I32 (urem x y)))
   (let
     ((y2 Reg (ext_int_if_need $false y $I32))
         (_ InstOutput (gen_div_by_zero y2)))
-    (alu_rrr (AluOPRRR.Remuw) x y2)))
+    (rv_remuw x y2)))
 
 (rule (lower (has_type $I64 (srem x y)))
   (let
     ((_ InstOutput (gen_div_by_zero y)))
-    (alu_rrr (AluOPRRR.Rem) x y)))
+    (rv_rem x y)))
 
 (rule (lower (has_type $I64 (urem x y)))
   (let
     ((_ InstOutput (gen_div_by_zero y)))
-    (alu_rrr (AluOPRRR.RemU) x y)))
+    (rv_remu x y)))
 
 ;;;; Rules for `and` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 (rule -1 (lower (has_type (fits_in_64 (ty_int ty)) (band x y)))
-  (alu_rrr (AluOPRRR.And) x y))
+  (rv_and x y))
 
 ;; Special cases for when one operand is an immediate that fits in 12 bits.
 (rule 2 (lower (has_type (fits_in_64 (ty_int ty)) (band x (imm12_from_value y))))
-  (alu_rr_imm12 (AluOPRRI.Andi) x y))
+  (rv_andi x y))
 
 (rule 1 (lower (has_type (fits_in_64 (ty_int ty)) (band (imm12_from_value x) y)))
-  (alu_rr_imm12 (AluOPRRI.Andi) y x))
+  (rv_andi y x))
 
 (rule (lower (has_type $I128 (band x y)))
   (lower_b128_binary (AluOPRRR.And) x y))
@@ -211,37 +255,37 @@
 
 (rule 3 (lower (has_type (fits_in_64 (ty_int ty)) (band x (bnot y))))
   (if-let $true (has_zbb))
-  (gen_andn x y))
+  (rv_andn x y))
 
 (rule 4 (lower (has_type (fits_in_64 (ty_int ty)) (band (bnot y) x)))
   (if-let $true (has_zbb))
-  (gen_andn x y))
+  (rv_andn x y))
 
 (rule 5 (lower (has_type $I128 (band x (bnot y))))
   (if-let $true (has_zbb))
   (let
-    ((low Reg (gen_andn (value_regs_get x 0) (value_regs_get y 0)))
-      (high Reg (gen_andn (value_regs_get x 1) (value_regs_get y 1))))
+    ((low Reg (rv_andn (value_regs_get x 0) (value_regs_get y 0)))
+      (high Reg (rv_andn (value_regs_get x 1) (value_regs_get y 1))))
     (value_regs low high)))
 
 (rule 6 (lower (has_type $I128 (band (bnot y) x)))
   (if-let $true (has_zbb))
   (let
-    ((low Reg (gen_andn (value_regs_get x 0) (value_regs_get y 0)))
-      (high Reg (gen_andn (value_regs_get x 1) (value_regs_get y 1))))
+    ((low Reg (rv_andn (value_regs_get x 0) (value_regs_get y 0)))
+      (high Reg (rv_andn (value_regs_get x 1) (value_regs_get y 1))))
     (value_regs low high)))
 
 
 ;;;; Rules for `or` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 (rule -1 (lower (has_type (fits_in_64 (ty_int ty)) (bor x y)))
-  (alu_rrr (AluOPRRR.Or) x y))
+  (rv_or x y))
 
 ;; Special cases for when one operand is an immediate that fits in 12 bits.
 (rule 2 (lower (has_type (fits_in_64 (ty_int ty)) (bor x (imm12_from_value y))))
-  (alu_rr_imm12 (AluOPRRI.Ori) x y))
+  (rv_ori x y))
 
 (rule 1 (lower (has_type (fits_in_64 (ty_int ty)) (bor (imm12_from_value x) y)))
-  (alu_rr_imm12 (AluOPRRI.Ori) y x))
+  (rv_ori y x))
 
 (rule (lower (has_type $I128 (bor x y)))
   (lower_b128_binary (AluOPRRR.Or) x y))
@@ -258,37 +302,37 @@
 
 (rule 3 (lower (has_type (fits_in_64 (ty_int ty)) (bor x (bnot y))))
   (if-let $true (has_zbb))
-  (gen_orn x y))
+  (rv_orn x y))
 
 (rule 4 (lower (has_type (fits_in_64 (ty_int ty)) (bor (bnot y) x)))
   (if-let $true (has_zbb))
-  (gen_orn x y))
+  (rv_orn x y))
 
 (rule 5 (lower (has_type $I128 (bor x (bnot y))))
   (if-let $true (has_zbb))
   (let
-    ((low Reg (gen_orn (value_regs_get x 0) (value_regs_get y 0)))
-      (high Reg (gen_orn (value_regs_get x 1) (value_regs_get y 1))))
+    ((low Reg (rv_orn (value_regs_get x 0) (value_regs_get y 0)))
+      (high Reg (rv_orn (value_regs_get x 1) (value_regs_get y 1))))
     (value_regs low high)))
 
 (rule 6 (lower (has_type $I128 (bor (bnot y) x)))
   (if-let $true (has_zbb))
   (let
-    ((low Reg (gen_orn (value_regs_get x 0) (value_regs_get y 0)))
-      (high Reg (gen_orn (value_regs_get x 1) (value_regs_get y 1))))
+    ((low Reg (rv_orn (value_regs_get x 0) (value_regs_get y 0)))
+      (high Reg (rv_orn (value_regs_get x 1) (value_regs_get y 1))))
     (value_regs low high)))
 
 
 ;;;; Rules for `xor` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 (rule -1 (lower (has_type (fits_in_64 (ty_int ty)) (bxor x y)))
-  (alu_rrr (AluOPRRR.Xor) x y))
+  (rv_xor x y))
 
 ;; Special cases for when one operand is an immediate that fits in 12 bits.
 (rule 2 (lower (has_type (fits_in_64 (ty_int ty)) (bxor x (imm12_from_value y))))
-  (alu_rr_imm12 (AluOPRRI.Xori) x y))
+  (rv_xori x y))
 
 (rule 1 (lower (has_type (fits_in_64 (ty_int ty)) (bxor (imm12_from_value x) y)))
-  (alu_rr_imm12 (AluOPRRI.Xori) y x))
+  (rv_xori y x))
 
 (rule (lower (has_type $I128 (bxor x y)))
   (lower_b128_binary (AluOPRRR.Xor) x y))
@@ -302,7 +346,7 @@
 
 ;;;; Rules for `bnot` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 (rule -1 (lower (has_type (fits_in_64 (ty_int ty)) (bnot x)))
-  (alu_rr_imm12 (AluOPRRI.Xori) x (imm_from_neg_bits -1)))
+  (rv_xori x (imm_from_neg_bits -1)))
 
 (rule (lower (has_type $I128 (bnot x)))
   (bnot_128 x))
@@ -355,6 +399,38 @@
 (rule (lower (has_type out_ty (sextend val @ (value_type in_ty))))
   (sext val in_ty out_ty))
 
+;; The instructions below are present in RV64I and sign-extend the result to 64 bits.
+
+(rule 1 (lower (has_type $I64 (sextend (has_type $I32 (iadd x y)))))
+  (rv_addw x y))
+
+(rule 1 (lower (has_type $I64 (sextend (has_type $I32 (isub x y)))))
+  (rv_subw x y))
+
+(rule 1 (lower (has_type $I64 (sextend (has_type $I32 (ishl x y)))))
+  (rv_sllw x (value_regs_get y 0)))
+
+(rule 1 (lower (has_type $I64 (sextend (has_type $I32 (ushr x y)))))
+  (rv_srlw x (value_regs_get y 0)))
+
+(rule 1 (lower (has_type $I64 (sextend (has_type $I32 (sshr x y)))))
+  (rv_sraw x (value_regs_get y 0)))
+
+
+(rule 2 (lower (has_type $I64 (sextend (has_type $I32 (iadd x (imm12_from_value y))))))
+  (rv_addiw x y))
+
+(rule 3 (lower (has_type $I64 (sextend (has_type $I32 (iadd (imm12_from_value x) y)))))
+  (rv_addiw y x))
+
+(rule 2 (lower (has_type $I64 (sextend (has_type $I32 (ishl x (imm12_from_value y))))))
+  (rv_slliw x y))
+
+(rule 2 (lower (has_type $I64 (sextend (has_type $I32 (ushr x (imm12_from_value y))))))
+  (rv_srliw x y))
+
+(rule 2 (lower (has_type $I64 (sextend (has_type $I32 (sshr x (imm12_from_value y))))))
+  (rv_sraiw x y))
 
 ;;;; Rules for `popcnt` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 (rule (lower (has_type (fits_in_64 ty) (popcnt x)))
@@ -364,52 +440,58 @@
 
 ;;;; Rules for `ishl` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 (rule 1 (lower (has_type $I8 (ishl x y)))
-  (alu_rrr (AluOPRRR.Sllw) x (alu_andi (value_regs_get y 0) 7))
-)
+  (rv_sllw x (rv_andi (value_regs_get y 0) (imm12_const 7))))
+
 (rule 2 (lower (has_type $I8 (ishl x (imm12_from_value y))))
-  (alu_rr_imm12 (AluOPRRI.Slliw) x (imm12_and y 7)))
+  (rv_slliw x (imm12_and y 7)))
 
 (rule 1 (lower (has_type $I16 (ishl x y)))
-  (alu_rrr (AluOPRRR.Sllw) x (alu_andi (value_regs_get y 0) 15))
-)
+  (rv_sllw x (rv_andi (value_regs_get y 0) (imm12_const 15))))
+
 (rule 2 (lower (has_type $I16 (ishl x (imm12_from_value y))))
-  (alu_rr_imm12 (AluOPRRI.Slliw) x (imm12_and y 15)))
+  (rv_slliw x (imm12_and y 15)))
 
 (rule 1 (lower (has_type $I32 (ishl x y)))
-  (alu_rrr (AluOPRRR.Sllw) x (value_regs_get y 0)))
+  (rv_sllw x (value_regs_get y 0)))
 (rule 2 (lower (has_type $I32 (ishl x (imm12_from_value y))))
-  (alu_rr_imm12 (AluOPRRI.Slliw) x y))
+  (rv_slliw x y))
 
 (rule 2 (lower (has_type $I64 (ishl x (imm12_from_value y))))
-  (alu_rr_imm12 (AluOPRRI.Slli) x y))
+  (rv_slli x y))
 (rule 1 (lower (has_type $I64 (ishl x y)))
-  (alu_rrr (AluOPRRR.Sll) x (value_regs_get y 0)))
+  (rv_sll x (value_regs_get y 0)))
+
+;; With `Zba` we have a shift that zero extends the LHS argument.
+(rule 3 (lower (has_type $I64 (ishl (uextend x @ (value_type $I32)) (maybe_uextend (imm12_from_value y)))))
+  (if-let $true (has_zba))
+  (rv_slliuw x y))
 
+;; I128 cases
 (rule 0 (lower (has_type $I128 (ishl x y)))
   (lower_i128_ishl x y))
 
 ;;;; Rules for `ushr` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 (rule 1 (lower (has_type $I8 (ushr x y)))
-  (alu_rrr (AluOPRRR.Srlw) (ext_int_if_need $false x $I8) (alu_andi (value_regs_get y 0) 7))
-)
+  (rv_srlw (ext_int_if_need $false x $I8) (rv_andi (value_regs_get y 0) (imm12_const 7))))
+
 (rule 2 (lower (has_type $I8 (ushr x (imm12_from_value y))))
-  (alu_rr_imm12 (AluOPRRI.SrliW) (ext_int_if_need $false x $I8) (imm12_and y 7)))
+  (rv_srliw (ext_int_if_need $false x $I8) (imm12_and y 7)))
 
 (rule 1 (lower (has_type $I16 (ushr x y)))
-  (alu_rrr (AluOPRRR.Srlw) (ext_int_if_need $false x $I16) (alu_andi (value_regs_get y 0) 15))
-)
+  (rv_srlw (ext_int_if_need $false x $I16) (rv_andi (value_regs_get y 0) (imm12_const 15))))
+
 (rule 2 (lower (has_type $I16 (ushr x (imm12_from_value y))))
-  (alu_rr_imm12 (AluOPRRI.SrliW) (ext_int_if_need $false x $I16) (imm12_and y 15)))
+  (rv_srliw (ext_int_if_need $false x $I16) (imm12_and y 15)))
 
 (rule 1 (lower (has_type $I32 (ushr x y)))
-  (alu_rrr (AluOPRRR.Srlw) x (value_regs_get y 0)))
+  (rv_srlw x (value_regs_get y 0)))
 (rule 2 (lower (has_type $I32 (ushr x (imm12_from_value y))))
-  (alu_rr_imm12 (AluOPRRI.SrliW) x y))
+  (rv_srliw x y))
 
 (rule 2 (lower (has_type $I64 (ushr x (imm12_from_value y))))
-  (alu_rr_imm12 (AluOPRRI.Srli) x y))
+  (rv_srli x y))
 (rule 1 (lower (has_type $I64 (ushr x y)))
-  (alu_rrr (AluOPRRR.Srl) x (value_regs_get y 0)))
+  (rv_srl x (value_regs_get y 0)))
 
 (rule 0 (lower (has_type $I128 (ushr x y)))
   (lower_i128_ushr x y))
@@ -417,25 +499,25 @@
 
 ;;;; Rules for `sshr` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 (rule 1 (lower (has_type $I8 (sshr x y)))
-  (alu_rrr (AluOPRRR.Sra) (ext_int_if_need $true x $I8) (alu_andi (value_regs_get y 0) 7))
-)
+  (rv_sra (ext_int_if_need $true x $I8) (rv_andi (value_regs_get y 0) (imm12_const 7))))
+
 (rule 2 (lower (has_type $I8 (sshr x (imm12_from_value y))))
-  (alu_rr_imm12 (AluOPRRI.Srai) (ext_int_if_need $true x $I8) (imm12_and y 7)))
+  (rv_srai (ext_int_if_need $true x $I8) (imm12_and y 7)))
 
 (rule 1 (lower (has_type $I16 (sshr x y)))
-  (alu_rrr (AluOPRRR.Sra) (ext_int_if_need $true x $I16) (alu_andi (value_regs_get y 0) 15))
-)
+  (rv_sra (ext_int_if_need $true x $I16) (rv_andi (value_regs_get y 0) (imm12_const 15))))
+
 (rule 2 (lower (has_type $I16 (sshr x (imm12_from_value y))))
-  (alu_rr_imm12 (AluOPRRI.Srai) (ext_int_if_need $true x $I16) (imm12_and y 15)))
+  (rv_srai (ext_int_if_need $true x $I16) (imm12_and y 15)))
 
 (rule 1 (lower (has_type $I32 (sshr x y)))
-  (alu_rrr (AluOPRRR.Sraw) x (value_regs_get y 0)))
+  (rv_sraw x (value_regs_get y 0)))
 (rule 2 (lower (has_type $I32 (sshr x (imm12_from_value y))))
-  (alu_rr_imm12 (AluOPRRI.Sraiw) x y))
+  (rv_sraiw x y))
 (rule 1 (lower (has_type $I64 (sshr x y)))
-  (alu_rrr (AluOPRRR.Sra) x (value_regs_get y 0)))
+  (rv_sra x (value_regs_get y 0)))
 (rule 2 (lower (has_type $I64 (sshr x (imm12_from_value y))))
-  (alu_rr_imm12 (AluOPRRI.Srai) x y))
+  (rv_srai x y))
 (rule 0 (lower (has_type $I128 (sshr x y)))
   (lower_i128_sshr x (value_regs_get y 0)))
 
@@ -456,32 +538,25 @@
 
 
 ;;;; Rules for `fabs` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-(rule
-  (lower (has_type ty (fabs x)))
-  (gen_fabs x ty))
+(rule (lower (has_type ty (fabs x)))
+  (rv_fabs ty x))
 
 ;;;; Rules for `fneg` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-(rule
-  (lower (has_type ty (fneg x)))
-  (fpu_rrr (f_copy_neg_sign_op ty) ty x x))
+(rule (lower (has_type ty (fneg x)))
+  (rv_fneg ty x))
 
 ;;;; Rules for `fcopysign` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 (rule (lower (has_type ty (fcopysign x y)))
-  (fpu_rrr (f_copysign_op ty) ty x y))
+  (rv_fsgnj ty x y))
 
 ;;;; Rules for `fma` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-(rule (lower (has_type $F32 (fma x y z)))
-  (fpu_rrrr (FpuOPRRRR.FmaddS) $F64 x y z))
-(rule (lower (has_type $F64 (fma x y z)))
-  (fpu_rrrr (FpuOPRRRR.FmaddD) $F64 x y z))
+(rule (lower (has_type ty (fma x y z)))
+  (rv_fmadd ty x y z))
 
 
 ;;;; Rules for `sqrt` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-(rule (lower (has_type $F32 (sqrt x)))
-  (fpu_rr (FpuOPRR.FsqrtS) $F64 x))
-
-(rule (lower (has_type $F64 (sqrt x)))
-  (fpu_rr (FpuOPRR.FsqrtD) $F64 x))
+(rule (lower (has_type ty (sqrt x)))
+  (rv_fsqrt ty x))
 
 
 ;;;; Rules for `AtomicRMW` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
@@ -518,7 +593,7 @@
     (has_type (valid_atomic_transaction ty) (atomic_rmw flags (AtomicRmwOp.Sub) addr x)))
   (let
     ((tmp WritableReg (temp_writable_reg ty))
-      (x2 Reg (alu_rrr (AluOPRRR.Sub) (zero_reg) x)))
+     (x2 Reg (rv_neg x)))
     (gen_atomic (get_atomic_rmw_op ty (AtomicRmwOp.Add)) addr x2 (atomic_amo))))
 
 (decl gen_atomic_rmw_loop (AtomicRmwOp Type Reg Reg) Reg)
@@ -552,14 +627,14 @@
 
 (decl gen_atomic_offset (Reg Type) Reg)
 (rule 1 (gen_atomic_offset p (fits_in_16 ty))
-  (alu_slli (alu_andi p 3) 3))
+  (rv_slli (rv_andi p (imm12_const 3)) (imm12_const 3)))
 
 (rule (gen_atomic_offset p _)
   (zero_reg))
 
 (decl gen_atomic_p (Reg Type) Reg)
 (rule 1 (gen_atomic_p p (fits_in_16 ty))
-  (alu_andi p -4))
+  (rv_andi p (imm12_const -4)))
 
 (rule (gen_atomic_p p _)
   p)
@@ -580,28 +655,26 @@
   (gen_move2 (value_regs_get x 0) ty ty))
 
 ;;;;;  Rules for `fpromote`;;;;;;;;;;;;;;;;;
-(rule
-  (lower (has_type ty (fpromote x)))
-  (fpu_rr (FpuOPRR.FcvtDS) ty x))
+(rule (lower (fpromote x))
+  (rv_fcvtds x))
 
-(rule
-  (lower (has_type ty (fdemote x)))
-  (fpu_rr (FpuOPRR.FcvtSD) ty x))
+;;;;;  Rules for `fdemote`;;;;;;;;;;;;;;;;;;
+(rule (lower (fdemote x))
+  (rv_fcvtsd x))
 
 
-;;;;;  Rules for `for float arithmatic`
-(rule
-  (lower (has_type ty (fadd x y)))
-  (fpu_rrr (f_arithmatic_op ty (Opcode.Fadd)) ty x y))
-(rule
-  (lower (has_type ty (fsub x y)))
-  (fpu_rrr (f_arithmatic_op ty (Opcode.Fsub)) ty x y))
-(rule
-  (lower (has_type ty (fmul x y)))
-  (fpu_rrr (f_arithmatic_op ty (Opcode.Fmul)) ty x y))
-(rule
-  (lower (has_type ty (fdiv x y)))
-  (fpu_rrr (f_arithmatic_op ty (Opcode.Fdiv)) ty x y))
+;;;;;  Rules for for float arithmetic
+(rule (lower (has_type ty (fadd x y)))
+  (rv_fadd ty x y))
+
+(rule (lower (has_type ty (fsub x y)))
+  (rv_fsub ty x y))
+
+(rule (lower (has_type ty (fmul x y)))
+  (rv_fmul ty x y))
+
+(rule (lower (has_type ty (fdiv x y)))
+  (rv_fdiv ty x y))
 
 (rule
   (lower (has_type ty (fmin x y)))
@@ -628,13 +701,13 @@
 
 ;; Null references are represented by the constant value `0`.
 (rule (lower (is_null v))
-  (seqz v))
+  (rv_seqz v))
 
 ;;;;;  Rules for `is_invalid`;;;;;;;;;
 
 ;; Invalid references are represented by the constant value `-1`.
 (rule (lower (is_invalid v))
-  (seqz (alu_rr_imm12 (AluOPRRI.Addi) v (imm12_const 1))))
+  (rv_seqz (rv_addi v (imm12_const 1))))
 
 ;;;;;  Rules for `select`;;;;;;;;;
 (rule
diff --git a/cranelift/codegen/src/isa/s390x/inst/emit.rs b/cranelift/codegen/src/isa/s390x/inst/emit.rs
index 5a811e7a3..4ac01db59 100644
--- a/cranelift/codegen/src/isa/s390x/inst/emit.rs
+++ b/cranelift/codegen/src/isa/s390x/inst/emit.rs
@@ -682,6 +682,7 @@ fn enc_ril_b(opcode: u16, r1: Reg, ri2: u32) -> [u8; 6] {
     let opcode1 = ((opcode >> 4) & 0xff) as u8;
     let opcode2 = (opcode & 0xf) as u8;
     let r1 = machreg_to_gpr(r1) & 0x0f;
+    let ri2 = ri2 >> 1;
 
     enc[0] = opcode1;
     enc[1] = r1 << 4 | opcode2;
@@ -700,6 +701,7 @@ fn enc_ril_c(opcode: u16, m1: u8, ri2: u32) -> [u8; 6] {
     let opcode1 = ((opcode >> 4) & 0xff) as u8;
     let opcode2 = (opcode & 0xf) as u8;
     let m1 = m1 & 0x0f;
+    let ri2 = ri2 >> 1;
 
     enc[0] = opcode1;
     enc[1] = m1 << 4 | opcode2;
@@ -3590,14 +3592,19 @@ impl Inst {
                 put_with_trap(sink, &enc_e(0x0000), trap_code);
             }
             &Inst::TrapIf { cond, trap_code } => {
-                // Branch over trap if condition is false.
-                let opcode = 0xa74; // BCR
-                put(sink, &enc_ri_c(opcode, cond.invert().bits(), 4 + 2));
-                // Now emit the actual trap.
                 if let Some(s) = state.take_stack_map() {
-                    sink.add_stack_map(StackMapExtent::UpcomingBytes(2), s);
+                    sink.add_stack_map(StackMapExtent::UpcomingBytes(6), s);
                 }
-                put_with_trap(sink, &enc_e(0x0000), trap_code);
+                // We implement a TrapIf as a conditional branch into the middle
+                // of the branch (BRCL) instruction itself - those middle two bytes
+                // are zero, which matches the trap instruction itself.
+                let opcode = 0xc04; // BCRL
+                let enc = &enc_ril_c(opcode, cond.bits(), 2);
+                debug_assert!(enc.len() == 6 && enc[2] == 0 && enc[3] == 0);
+                // The trap must be placed on the last byte of the embedded trap
+                // instruction, so we need to emit the encoding in two parts.
+                put_with_trap(sink, &enc[0..4], trap_code);
+                put(sink, &enc[4..6]);
             }
             &Inst::JTSequence { ridx, ref targets } => {
                 let ridx = allocs.next(ridx);
diff --git a/cranelift/codegen/src/isa/s390x/inst/mod.rs b/cranelift/codegen/src/isa/s390x/inst/mod.rs
index f6b22aa46..08ea1ffe9 100644
--- a/cranelift/codegen/src/isa/s390x/inst/mod.rs
+++ b/cranelift/codegen/src/isa/s390x/inst/mod.rs
@@ -3185,11 +3185,13 @@ impl Inst {
                 let cond = cond.pretty_print_default();
                 format!("jg{} {}", cond, target)
             }
-            &Inst::Debugtrap => "debugtrap".to_string(),
-            &Inst::Trap { .. } => "trap".to_string(),
-            &Inst::TrapIf { cond, .. } => {
-                let cond = cond.invert().pretty_print_default();
-                format!("j{} 6 ; trap", cond)
+            &Inst::Debugtrap => ".word 0x0001 # debugtrap".to_string(),
+            &Inst::Trap { trap_code } => {
+                format!(".word 0x0000 # trap={}", trap_code)
+            }
+            &Inst::TrapIf { cond, trap_code } => {
+                let cond = cond.pretty_print_default();
+                format!("jg{} .+2 # trap={}", cond, trap_code)
             }
             &Inst::JTSequence { ridx, ref targets } => {
                 let ridx = pretty_print_reg(ridx, allocs);
diff --git a/cranelift/codegen/src/isa/x64/inst.isle b/cranelift/codegen/src/isa/x64/inst.isle
index 1fdc6b25c..b11efad40 100644
--- a/cranelift/codegen/src/isa/x64/inst.isle
+++ b/cranelift/codegen/src/isa/x64/inst.isle
@@ -1299,6 +1299,12 @@
             Vpmovmskb
             Vcvtsi2ss
             Vcvtsi2sd
+            Vcvtss2sd
+            Vcvtsd2ss
+            Vsqrtss
+            Vsqrtsd
+            Vroundss
+            Vroundsd
           ))
 
 (type Avx512Opcode extern
@@ -3348,11 +3354,17 @@
 (decl x64_roundss (XmmMem RoundImm) Xmm)
 (rule (x64_roundss src1 round)
       (xmm_unary_rm_r_imm (SseOpcode.Roundss) src1 (encode_round_imm round)))
+(rule 1 (x64_roundss src1 round)
+        (if-let $true (use_avx_simd))
+        (xmm_unary_rm_r_imm_vex (AvxOpcode.Vroundss) src1 (encode_round_imm round)))
 
 ;; Helper for creating `roundsd` instructions.
 (decl x64_roundsd (XmmMem RoundImm) Xmm)
 (rule (x64_roundsd src1 round)
       (xmm_unary_rm_r_imm (SseOpcode.Roundsd) src1 (encode_round_imm round)))
+(rule 1 (x64_roundsd src1 round)
+        (if-let $true (use_avx_simd))
+        (xmm_unary_rm_r_imm_vex (AvxOpcode.Vroundsd) src1 (encode_round_imm round)))
 
 ;; Helper for creating `roundps` instructions.
 (decl x64_roundps (XmmMem RoundImm) Xmm)
@@ -3985,10 +3997,16 @@
 ;; Helper for creating `sqrtss` instructions.
 (decl x64_sqrtss (XmmMem) Xmm)
 (rule (x64_sqrtss x) (xmm_unary_rm_r_unaligned (SseOpcode.Sqrtss) x))
+(rule 1 (x64_sqrtss x)
+        (if-let $true (use_avx_simd))
+        (xmm_unary_rm_r_vex (AvxOpcode.Vsqrtss) x))
 
 ;; Helper for creating `sqrtsd` instructions.
 (decl x64_sqrtsd (XmmMem) Xmm)
 (rule (x64_sqrtsd x) (xmm_unary_rm_r_unaligned (SseOpcode.Sqrtsd) x))
+(rule 1 (x64_sqrtsd x)
+        (if-let $true (use_avx_simd))
+        (xmm_unary_rm_r_vex (AvxOpcode.Vsqrtsd) x))
 
 ;; Helper for creating `sqrtps` instructions.
 (decl x64_sqrtps (XmmMem) Xmm)
@@ -4005,12 +4023,18 @@
         (xmm_unary_rm_r_vex (AvxOpcode.Vsqrtpd) x))
 
 ;; Helper for creating `cvtss2sd` instructions.
-(decl x64_cvtss2sd (Xmm) Xmm)
-(rule (x64_cvtss2sd x) (xmm_unary_rm_r (SseOpcode.Cvtss2sd) x))
+(decl x64_cvtss2sd (XmmMem) Xmm)
+(rule (x64_cvtss2sd x) (xmm_unary_rm_r_unaligned (SseOpcode.Cvtss2sd) x))
+(rule 1 (x64_cvtss2sd x)
+        (if-let $true (use_avx_simd))
+        (xmm_unary_rm_r_vex (AvxOpcode.Vcvtss2sd) x))
 
 ;; Helper for creating `cvtsd2ss` instructions.
-(decl x64_cvtsd2ss (Xmm) Xmm)
-(rule (x64_cvtsd2ss x) (xmm_unary_rm_r (SseOpcode.Cvtsd2ss) x))
+(decl x64_cvtsd2ss (XmmMem) Xmm)
+(rule (x64_cvtsd2ss x) (xmm_unary_rm_r_unaligned (SseOpcode.Cvtsd2ss) x))
+(rule 1 (x64_cvtsd2ss x)
+        (if-let $true (use_avx_simd))
+        (xmm_unary_rm_r_vex (AvxOpcode.Vcvtsd2ss) x))
 
 ;; Helper for creating `cvtdq2ps` instructions.
 (decl x64_cvtdq2ps (XmmMem) Xmm)
@@ -4375,9 +4399,20 @@
       (let ((size OperandSize (raw_operand_size_of_type ty)))
         (icmp_cond_result (x64_cmp size a b) (intcc_reverse cc))))
 
+;; Special case: use the test instruction for comparisons with 0.
+(rule 2 (emit_cmp cc a @ (value_type ty) (u64_from_iconst 0))
+      (let ((size OperandSize (raw_operand_size_of_type ty))
+            (a Gpr (put_in_reg a)))
+        (icmp_cond_result (x64_test size a a) cc)))
+
+(rule 3 (emit_cmp cc (u64_from_iconst 0) b @ (value_type ty))
+      (let ((size OperandSize (raw_operand_size_of_type ty))
+            (b Gpr (put_in_reg b)))
+        (icmp_cond_result (x64_test size b b) (intcc_reverse cc))))
+
 ;; For I128 values (held in two GPRs), the instruction sequences depend on what
 ;; kind of condition is tested.
-(rule 3 (emit_cmp (IntCC.Equal) a @ (value_type $I128) b)
+(rule 5 (emit_cmp (IntCC.Equal) a @ (value_type $I128) b)
       (let ((a_lo Gpr (value_regs_get_gpr a 0))
             (a_hi Gpr (value_regs_get_gpr a 1))
             (b_lo Gpr (value_regs_get_gpr b 0))
@@ -4398,7 +4433,7 @@
           (x64_test (OperandSize.Size64) (RegMemImm.Imm 1) cmp)
           (CC.NZ))))
 
-(rule 3 (emit_cmp (IntCC.NotEqual) a @ (value_type $I128) b)
+(rule 5 (emit_cmp (IntCC.NotEqual) a @ (value_type $I128) b)
       (let ((a_lo Gpr (value_regs_get_gpr a 0))
             (a_hi Gpr (value_regs_get_gpr a 1))
             (b_lo Gpr (value_regs_get_gpr b 0))
@@ -4413,7 +4448,7 @@
 
 ;; Result = (a_hi <> b_hi) ||
 ;;          (a_hi == b_hi && a_lo <> b_lo)
-(rule 2 (emit_cmp cc a @ (value_type $I128) b)
+(rule 4 (emit_cmp cc a @ (value_type $I128) b)
       (let ((a_lo Gpr (value_regs_get_gpr a 0))
             (a_hi Gpr (value_regs_get_gpr a 1))
             (b_lo Gpr (value_regs_get_gpr b 0))
diff --git a/cranelift/codegen/src/isa/x64/inst/args.rs b/cranelift/codegen/src/isa/x64/inst/args.rs
index a135fc5af..b2301f729 100644
--- a/cranelift/codegen/src/isa/x64/inst/args.rs
+++ b/cranelift/codegen/src/isa/x64/inst/args.rs
@@ -1722,7 +1722,13 @@ impl AvxOpcode {
             | AvxOpcode::Vmovmskpd
             | AvxOpcode::Vpmovmskb
             | AvxOpcode::Vcvtsi2ss
-            | AvxOpcode::Vcvtsi2sd => {
+            | AvxOpcode::Vcvtsi2sd
+            | AvxOpcode::Vcvtss2sd
+            | AvxOpcode::Vcvtsd2ss
+            | AvxOpcode::Vsqrtss
+            | AvxOpcode::Vsqrtsd
+            | AvxOpcode::Vroundss
+            | AvxOpcode::Vroundsd => {
                 smallvec![InstructionSet::AVX]
             }
 
diff --git a/cranelift/codegen/src/isa/x64/inst/emit.rs b/cranelift/codegen/src/isa/x64/inst/emit.rs
index 2b0f3af08..e2ca40cfe 100644
--- a/cranelift/codegen/src/isa/x64/inst/emit.rs
+++ b/cranelift/codegen/src/isa/x64/inst/emit.rs
@@ -2405,17 +2405,36 @@ pub(crate) fn emit(
                 AvxOpcode::Vbroadcastss => (LegacyPrefixes::_66, OpcodeMap::_0F38, 0x18),
                 AvxOpcode::Vmovddup => (LegacyPrefixes::_F2, OpcodeMap::_0F, 0x12),
 
+                AvxOpcode::Vcvtss2sd => (LegacyPrefixes::_F3, OpcodeMap::_0F, 0x5A),
+                AvxOpcode::Vcvtsd2ss => (LegacyPrefixes::_F2, OpcodeMap::_0F, 0x5A),
+                AvxOpcode::Vsqrtss => (LegacyPrefixes::_F3, OpcodeMap::_0F, 0x51),
+                AvxOpcode::Vsqrtsd => (LegacyPrefixes::_F2, OpcodeMap::_0F, 0x51),
+
                 _ => panic!("unexpected rmr_imm_vex opcode {op:?}"),
             };
 
-            VexInstruction::new()
+            let vex = VexInstruction::new()
                 .length(VexVectorLength::V128)
                 .prefix(prefix)
                 .map(map)
                 .opcode(opcode)
                 .reg(dst.to_real_reg().unwrap().hw_enc())
-                .rm(src)
-                .encode(sink);
+                .rm(src);
+
+            // These opcodes take a second operand through `vvvv` which copies
+            // the upper bits into the destination register. That's not
+            // reflected in the CLIF instruction, however, since the SSE version
+            // doesn't have this functionality. Instead just copy whatever
+            // happens to already be in the destination, which at least is what
+            // LLVM seems to do.
+            let vex = match op {
+                AvxOpcode::Vcvtss2sd
+                | AvxOpcode::Vcvtsd2ss
+                | AvxOpcode::Vsqrtss
+                | AvxOpcode::Vsqrtsd => vex.vvvv(dst.to_real_reg().unwrap().hw_enc()),
+                _ => vex,
+            };
+            vex.encode(sink);
         }
 
         Inst::XmmUnaryRmRImmVex { op, src, dst, imm } => {
@@ -2433,18 +2452,29 @@ pub(crate) fn emit(
                 AvxOpcode::Vpshuflw => (LegacyPrefixes::_F2, OpcodeMap::_0F, 0x70),
                 AvxOpcode::Vpshufhw => (LegacyPrefixes::_F3, OpcodeMap::_0F, 0x70),
                 AvxOpcode::Vpshufd => (LegacyPrefixes::_66, OpcodeMap::_0F, 0x70),
+                AvxOpcode::Vroundss => (LegacyPrefixes::_66, OpcodeMap::_0F3A, 0x0A),
+                AvxOpcode::Vroundsd => (LegacyPrefixes::_66, OpcodeMap::_0F3A, 0x0B),
                 _ => panic!("unexpected rmr_imm_vex opcode {op:?}"),
             };
 
-            VexInstruction::new()
+            let vex = VexInstruction::new()
                 .length(VexVectorLength::V128)
                 .prefix(prefix)
                 .map(map)
                 .opcode(opcode)
                 .reg(dst.to_real_reg().unwrap().hw_enc())
                 .rm(src)
-                .imm(*imm)
-                .encode(sink);
+                .imm(*imm);
+
+            // See comments in similar block above in `XmmUnaryRmRVex` for what
+            // this is doing.
+            let vex = match op {
+                AvxOpcode::Vroundss | AvxOpcode::Vroundsd => {
+                    vex.vvvv(dst.to_real_reg().unwrap().hw_enc())
+                }
+                _ => vex,
+            };
+            vex.encode(sink);
         }
 
         Inst::XmmMovRMVex { op, src, dst } => {
diff --git a/cranelift/codegen/src/isa/x64/inst/mod.rs b/cranelift/codegen/src/isa/x64/inst/mod.rs
index f9dd071dc..723cffb10 100644
--- a/cranelift/codegen/src/isa/x64/inst/mod.rs
+++ b/cranelift/codegen/src/isa/x64/inst/mod.rs
@@ -1589,20 +1589,19 @@ impl PrettyPrint for Inst {
                 let alternative = pretty_print_reg(alternative.to_reg(), size, allocs);
                 let dst = pretty_print_reg(dst.to_reg().to_reg(), size, allocs);
                 let consequent = consequent.pretty_print(size, allocs);
+                let suffix = match *ty {
+                    types::F64 => "sd",
+                    types::F32 => "ss",
+                    types::F32X4 => "aps",
+                    types::F64X2 => "apd",
+                    _ => "dqa",
+                };
                 format!(
-                    "mov {}, {}; j{} $next; mov{} {}, {}; $next: ",
+                    "mov{suffix} {alternative}, {dst}; \
+                    j{} $next; \
+                    mov{suffix} {consequent}, {dst}; \
+                    $next:",
                     cc.invert().to_string(),
-                    match *ty {
-                        types::F64 => "sd",
-                        types::F32 => "ss",
-                        types::F32X4 => "aps",
-                        types::F64X2 => "apd",
-                        _ => "dqa",
-                    },
-                    consequent,
-                    dst,
-                    alternative,
-                    dst,
                 )
             }
 
diff --git a/cranelift/codegen/src/isa/x64/lower.isle b/cranelift/codegen/src/isa/x64/lower.isle
index ee7ca827b..3e50417d0 100644
--- a/cranelift/codegen/src/isa/x64/lower.isle
+++ b/cranelift/codegen/src/isa/x64/lower.isle
@@ -1570,90 +1570,25 @@
 
 ;;;; Rules for `select` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 
-;; CLIF `select` instructions receive a testable argument (i.e. boolean or
-;; integer) that determines which of the other two arguments is selected as
-;; output. Since Cranelift booleans are typically generated by a comparison, the
-;; lowerings in this section "look upwards in the tree" to emit the proper
-;; sequence of "selection" instructions.
+;; When a `select` has an `fcmp` as a condition then rely on `emit_fcmp` to
+;; figure out how to perform the comparison.
 ;;
-;; The following rules--for selecting on a floating-point comparison--emit a
-;; `UCOMIS*` instruction and then a conditional move, `cmove`. Note that for
-;; values contained in XMM registers, `cmove` and `cmove_or` may in fact emit a
-;; jump sequence, not `CMOV`. The `cmove` instruction operates on the flags set
-;; by `UCOMIS*`; the key to understanding these is the UCOMIS* documentation
-;; (see Intel's Software Developer's Manual, volume 2, chapter 4):
-;;  - unordered assigns    Z = 1, P = 1, C = 1
-;;  - greater than assigns Z = 0, P = 0, C = 0
-;;  - less than assigns    Z = 0, P = 0, C = 1
-;;  - equal assigns        Z = 1, P = 0, C = 0
-;;
-;; Note that prefixing the flag with `N` means "not," so that `CC.P -> P = 1`
-;; and `CC.NP -> P = 0`. Also, x86 uses mnemonics for certain combinations of
-;; flags; e.g.:
-;;  - `CC.B -> C = 1` (below)
-;;  - `CC.NB -> C = 0` (not below)
-;;  - `CC.BE -> C = 1 OR Z = 1` (below or equal)
-;;  - `CC.NBE -> C = 0 AND Z = 0` (not below or equal)
-
-(rule (lower (has_type ty (select (maybe_uextend (fcmp (FloatCC.Ordered) a b)) x y)))
-      (with_flags (x64_ucomis b a) (cmove_from_values ty (CC.NP) x y)))
-
-(rule (lower (has_type ty (select (maybe_uextend (fcmp (FloatCC.Unordered) a b)) x y)))
-      (with_flags (x64_ucomis b a) (cmove_from_values ty (CC.P) x y)))
-
-(rule (lower (has_type ty (select (maybe_uextend (fcmp (FloatCC.GreaterThan) a b)) x y)))
-      (with_flags (x64_ucomis b a) (cmove_from_values ty (CC.NBE) x y)))
-
-(rule (lower (has_type ty (select (maybe_uextend (fcmp (FloatCC.GreaterThanOrEqual) a b)) x y)))
-      (with_flags (x64_ucomis b a) (cmove_from_values ty (CC.NB) x y)))
-
-(rule (lower (has_type ty (select (maybe_uextend (fcmp (FloatCC.UnorderedOrLessThan) a b)) x y)))
-      (with_flags (x64_ucomis b a) (cmove_from_values ty (CC.B) x y)))
-
-(rule (lower (has_type ty (select (maybe_uextend (fcmp (FloatCC.UnorderedOrLessThanOrEqual) a b)) x y)))
-      (with_flags (x64_ucomis b a) (cmove_from_values ty (CC.BE) x y)))
-
-;; Certain FloatCC variants are implemented by flipping the operands of the
-;; comparison (e.g., "greater than" is lowered the same as "less than" but the
-;; comparison is reversed). This allows us to use a single flag for the `cmove`,
-;; which involves fewer instructions than `cmove_or`.
-;;
-;; But why flip at all, you may ask? Can't we just use `CC.B` (i.e., below) for
-;; `FloatCC.LessThan`? Recall that in these floating-point lowerings, values may
-;; be unordered and we must we want to express that `FloatCC.LessThan` is `LT`,
-;; not `LT | UNO`. By flipping the operands AND inverting the comparison (e.g.,
-;; to `CC.NBE`), we also avoid these unordered cases.
-
-(rule (lower (has_type ty (select (maybe_uextend (fcmp (FloatCC.LessThan) a b)) x y)))
-      (with_flags (x64_ucomis a b) (cmove_from_values ty (CC.NBE) x y)))
-
-(rule (lower (has_type ty (select (maybe_uextend (fcmp (FloatCC.LessThanOrEqual) a b)) x y)))
-      (with_flags (x64_ucomis a b) (cmove_from_values ty (CC.NB) x y)))
-
-(rule (lower (has_type ty (select (maybe_uextend (fcmp (FloatCC.UnorderedOrGreaterThan) a b)) x y)))
-      (with_flags (x64_ucomis a b) (cmove_from_values ty (CC.B) x y)))
-
-(rule (lower (has_type ty (select (maybe_uextend (fcmp (FloatCC.UnorderedOrGreaterThanOrEqual) a b)) x y)))
-      (with_flags (x64_ucomis a b) (cmove_from_values ty (CC.BE) x y)))
-
-;; `FloatCC.Equal` and `FloatCC.NotEqual` can only be implemented with multiple
-;; flag checks. Recall from the flag assignment chart above that equality, e.g.,
-;; will assign `Z = 1`. But so does an unordered comparison: `Z = 1, P = 1, C =
-;; 1`. In order to avoid semantics like `EQ | UNO` for equality, we must ensure
-;; that the values are actually ordered, checking that `P = 0` (note that the
-;; `C` flag is irrelevant here). Since we cannot find a single instruction that
-;; implements a `Z = 1 AND P = 0` check, we invert the flag checks (i.e., `Z = 1
-;; AND P = 0` becomes `Z = 0 OR P = 1`) and also flip the select operands, `x`
-;; and `y`. The same argument applies to `FloatCC.NotEqual`.
-;;
-;; More details about the CLIF semantics for `fcmp` are available at
-;; https://docs.rs/cranelift-codegen/latest/cranelift_codegen/ir/trait.InstBuilder.html#method.fcmp.
-
-(rule (lower (has_type ty (select (maybe_uextend (fcmp (FloatCC.Equal) a b)) x y)))
-      (with_flags (x64_ucomis a b) (cmove_or_from_values ty (CC.NZ) (CC.P) y x)))
-
-(rule (lower (has_type ty (select (maybe_uextend (fcmp (FloatCC.NotEqual) a b)) x y)))
-      (with_flags (x64_ucomis a b) (cmove_or_from_values ty (CC.NZ) (CC.P) x y)))
+;; Note, though, that the `FloatCC.Equal` requires an "and" to happen for two
+;; condition codes which isn't the easiest thing to lower to a `cmove`
+;; instruction. For this reason a `select (fcmp eq ..) ..` is instead
+;; flipped around to be `select (fcmp ne ..) ..` with all operands reversed.
+;; This will produce a `FcmpCondResult.OrCondition` which is easier to codegen
+;; for.
+(rule (lower (has_type ty (select (maybe_uextend (fcmp cc a b)) x y)))
+      (lower_select_fcmp ty (emit_fcmp cc a b) x y))
+(rule 1 (lower (has_type ty (select (maybe_uextend (fcmp (FloatCC.Equal) a b)) x y)))
+        (lower_select_fcmp ty (emit_fcmp (FloatCC.NotEqual) a b) y x))
+
+(decl lower_select_fcmp (Type FcmpCondResult Value Value) InstOutput)
+(rule (lower_select_fcmp ty (FcmpCondResult.Condition flags cc) x y)
+      (with_flags flags (cmove_from_values ty cc x y)))
+(rule (lower_select_fcmp ty (FcmpCondResult.OrCondition flags cc1 cc2) x y)
+      (with_flags flags (cmove_or_from_values ty cc1 cc2 x y)))
 
 ;; We also can lower `select`s that depend on an `icmp` test, but more simply
 ;; than the `fcmp` variants above. In these cases, we lower to a `CMP`
diff --git a/cranelift/codegen/src/opts/algebraic.isle b/cranelift/codegen/src/opts/algebraic.isle
index 8cab77bd4..db3d8d4b4 100644
--- a/cranelift/codegen/src/opts/algebraic.isle
+++ b/cranelift/codegen/src/opts/algebraic.isle
@@ -479,6 +479,56 @@
              (iconst _ (u64_from_imm64 0))))
       (iconst ty (imm64 1)))
 
+(decl pure decompose_intcc (IntCC) u64)
+(rule (decompose_intcc (IntCC.Equal)) 1)
+(rule (decompose_intcc (IntCC.UnsignedLessThan)) 2)
+(rule (decompose_intcc (IntCC.SignedLessThan)) 2)
+(rule (decompose_intcc (IntCC.UnsignedLessThanOrEqual)) 3)
+(rule (decompose_intcc (IntCC.SignedLessThanOrEqual)) 3)
+(rule (decompose_intcc (IntCC.UnsignedGreaterThan)) 4)
+(rule (decompose_intcc (IntCC.SignedGreaterThan)) 4)
+(rule (decompose_intcc (IntCC.UnsignedGreaterThanOrEqual)) 5)
+(rule (decompose_intcc (IntCC.SignedGreaterThanOrEqual)) 5)
+(rule (decompose_intcc (IntCC.NotEqual)) 6)
+
+(decl compose_icmp (Type u64 bool Value Value) Value)
+(rule (compose_icmp ty 0 _ _ _) (subsume (iconst ty (imm64 0))))
+(rule (compose_icmp ty 1 _ x y) (icmp ty (IntCC.Equal) x y))
+(rule (compose_icmp ty 2 $false x y) (icmp ty (IntCC.UnsignedLessThan) x y))
+(rule (compose_icmp ty 2 $true x y) (icmp ty (IntCC.SignedLessThan) x y))
+(rule (compose_icmp ty 3 $false x y) (icmp ty (IntCC.UnsignedLessThanOrEqual) x y))
+(rule (compose_icmp ty 3 $true x y) (icmp ty (IntCC.SignedLessThanOrEqual) x y))
+(rule (compose_icmp ty 4 $false x y) (icmp ty (IntCC.UnsignedGreaterThan) x y))
+(rule (compose_icmp ty 4 $true x y) (icmp ty (IntCC.SignedGreaterThan) x y))
+(rule (compose_icmp ty 5 $false x y) (icmp ty (IntCC.UnsignedGreaterThanOrEqual) x y))
+(rule (compose_icmp ty 5 $true x y) (icmp ty (IntCC.SignedGreaterThanOrEqual) x y))
+(rule (compose_icmp ty 6 _ x y) (icmp ty (IntCC.NotEqual) x y))
+(rule (compose_icmp ty 7 _ _ _) (subsume (iconst ty (imm64 1))))
+
+(decl pure intcc_class (IntCC) u64)
+(rule (intcc_class (IntCC.UnsignedLessThan)) 1)
+(rule (intcc_class (IntCC.UnsignedLessThanOrEqual)) 1)
+(rule (intcc_class (IntCC.UnsignedGreaterThan)) 1)
+(rule (intcc_class (IntCC.UnsignedGreaterThanOrEqual)) 1)
+(rule (intcc_class (IntCC.SignedLessThan)) 2)
+(rule (intcc_class (IntCC.SignedLessThanOrEqual)) 2)
+(rule (intcc_class (IntCC.SignedGreaterThan)) 2)
+(rule (intcc_class (IntCC.SignedGreaterThanOrEqual)) 2)
+(rule (intcc_class (IntCC.Equal)) 3)
+(rule (intcc_class (IntCC.NotEqual)) 3)
+
+(decl pure partial intcc_comparable (IntCC IntCC) bool)
+(rule (intcc_comparable x y)
+  (if-let (u64_nonzero class) (u64_and (intcc_class x) (intcc_class y)))
+  (u64_eq 2 class))
+
+(rule (simplify (band ty (icmp ty cc1 x y) (icmp ty cc2 x y)))
+  (if-let signed (intcc_comparable cc1 cc2))
+  (compose_icmp ty (u64_and (decompose_intcc cc1) (decompose_intcc cc2)) signed x y))
+
+(rule (simplify (bor ty (icmp ty cc1 x y) (icmp ty cc2 x y)))
+  (if-let signed (intcc_comparable cc1 cc2))
+  (compose_icmp ty (u64_or (decompose_intcc cc1) (decompose_intcc cc2)) signed x y))
 
 ;; Transform select-of-icmp into {u,s}{min,max} instructions where possible.
 (rule (simplify (select ty (sgt _ x y) x y)) (smax ty x y))
diff --git a/cranelift/object/src/backend.rs b/cranelift/object/src/backend.rs
index b0f12198e..24bd04d13 100644
--- a/cranelift/object/src/backend.rs
+++ b/cranelift/object/src/backend.rs
@@ -654,6 +654,36 @@ impl ObjectModule {
                     32,
                 )
             }
+            Reloc::MachOAarch64TlsAdrPage21 => {
+                assert_eq!(
+                    self.object.format(),
+                    object::BinaryFormat::MachO,
+                    "MachOAarch64TlsAdrPage21 is not supported for this file format"
+                );
+                (
+                    RelocationKind::MachO {
+                        value: object::macho::ARM64_RELOC_TLVP_LOAD_PAGE21,
+                        relative: true,
+                    },
+                    RelocationEncoding::Generic,
+                    21,
+                )
+            }
+            Reloc::MachOAarch64TlsAdrPageOff12 => {
+                assert_eq!(
+                    self.object.format(),
+                    object::BinaryFormat::MachO,
+                    "MachOAarch64TlsAdrPageOff12 is not supported for this file format"
+                );
+                (
+                    RelocationKind::MachO {
+                        value: object::macho::ARM64_RELOC_TLVP_LOAD_PAGEOFF12,
+                        relative: false,
+                    },
+                    RelocationEncoding::Generic,
+                    12,
+                )
+            }
             Reloc::Aarch64TlsGdAdrPage21 => {
                 assert_eq!(
                     self.object.format(),
diff --git a/crates/environ/src/component/translate.rs b/crates/environ/src/component/translate.rs
index d7fbb173b..387bd48bb 100644
--- a/crates/environ/src/component/translate.rs
+++ b/crates/environ/src/component/translate.rs
@@ -622,8 +622,31 @@ impl<'a, 'data> Translator<'a, 'data> {
                     self.result
                         .initializers
                         .push(LocalInitializer::Export(item));
-                    if let ComponentItem::Type(ty) = item {
-                        self.types.push_component_typedef(ty);
+
+                    // Exports create a new index, so push the item onto the
+                    // appropriate list.
+                    match item {
+                        ComponentItem::Func(idx) => {
+                            self.result
+                                .component_funcs
+                                .push(self.result.component_funcs[idx]);
+                        }
+                        ComponentItem::Module(_idx) => {
+                            // We don't need to do anything here for modules as
+                            // the type information isn't tracked in the initial
+                            // translation pass.
+                        }
+                        ComponentItem::Component(idx) => {
+                            self.result.components.push(self.result.components[idx]);
+                        }
+                        ComponentItem::ComponentInstance(idx) => {
+                            self.result
+                                .component_instances
+                                .push(self.result.component_instances[idx]);
+                        }
+                        ComponentItem::Type(ty) => {
+                            self.types.push_component_typedef(ty);
+                        }
                     }
                 }
             }
diff --git a/crates/wasmtime/src/store.rs b/crates/wasmtime/src/store.rs
index 9a322fd6a..8b7f5f3e6 100644
--- a/crates/wasmtime/src/store.rs
+++ b/crates/wasmtime/src/store.rs
@@ -425,11 +425,13 @@ enum OutOfGas {
 
 /// What to do when the engine epoch reaches the deadline for a Store
 /// during execution of a function using that store.
+#[derive(Default)]
 enum EpochDeadline<T> {
     /// Return early with a trap.
+    #[default]
     Trap,
     /// Call a custom deadline handler.
-    Callback(Box<dyn FnMut(&mut T) -> Result<u64> + Send + Sync>),
+    Callback(Box<dyn FnMut(StoreContextMut<T>) -> Result<u64> + Send + Sync>),
     /// Extend the deadline by the specified number of ticks after
     /// yielding to the async executor loop.
     #[cfg(feature = "async")]
@@ -932,7 +934,7 @@ impl<T> Store<T> {
     /// for an introduction to epoch-based interruption.
     pub fn epoch_deadline_callback(
         &mut self,
-        callback: impl FnMut(&mut T) -> Result<u64> + Send + Sync + 'static,
+        callback: impl FnMut(StoreContextMut<T>) -> Result<u64> + Send + Sync + 'static,
     ) {
         self.inner.epoch_deadline_callback(Box::new(callback));
     }
@@ -1975,10 +1977,13 @@ unsafe impl<T> wasmtime_runtime::Store for StoreInner<T> {
     }
 
     fn new_epoch(&mut self) -> Result<u64, anyhow::Error> {
-        return match &mut self.epoch_deadline_behavior {
+        // Temporarily take the configured behavior to avoid mutably borrowing
+        // multiple times.
+        let mut behavior = std::mem::take(&mut self.epoch_deadline_behavior);
+        let delta_result = match &mut behavior {
             EpochDeadline::Trap => Err(Trap::Interrupt.into()),
             EpochDeadline::Callback(callback) => {
-                let delta = callback(&mut self.data)?;
+                let delta = callback((&mut *self).as_context_mut())?;
                 // Set a new deadline and return the new epoch deadline so
                 // the Wasm code doesn't have to reload it.
                 self.set_epoch_deadline(delta);
@@ -1998,6 +2003,10 @@ unsafe impl<T> wasmtime_runtime::Store for StoreInner<T> {
                 Ok(self.get_epoch_deadline())
             }
         };
+
+        // Put back the original behavior which was replaced by `take`.
+        self.epoch_deadline_behavior = behavior;
+        delta_result
     }
 }
 
@@ -2022,7 +2031,7 @@ impl<T> StoreInner<T> {
 
     fn epoch_deadline_callback(
         &mut self,
-        callback: Box<dyn FnMut(&mut T) -> Result<u64> + Send + Sync>,
+        callback: Box<dyn FnMut(StoreContextMut<T>) -> Result<u64> + Send + Sync>,
     ) {
         self.epoch_deadline_behavior = EpochDeadline::Callback(callback);
     }
diff --git a/supply-chain/config.toml b/supply-chain/config.toml
index 6d2b34dc6..d9c5ea126 100644
--- a/supply-chain/config.toml
+++ b/supply-chain/config.toml
@@ -2,14 +2,17 @@
 # cargo-vet config file
 
 [cargo-vet]
-version = "0.5"
-
-[imports.chromeos]
-url = "https://chromium.googlesource.com/chromiumos/third_party/rust_crates/+/main/cargo-vet/audits.toml?format=TEXT"
+version = "0.6"
 
 [imports.embark-studios]
 url = "https://raw.githubusercontent.com/EmbarkStudios/rust-ecosystem/main/audits.toml"
 
+[imports.google]
+url = [
+    "https://chromium.googlesource.com/chromiumos/third_party/rust_crates/+/main/cargo-vet/audits.toml?format=TEXT",
+    "https://fuchsia.googlesource.com/fuchsia/+/refs/heads/main/third_party/rust_crates/supply-chain/audits.toml?format=TEXT",
+]
+
 [imports.isrg]
 url = "https://raw.githubusercontent.com/divviup/libprio-rs/main/supply-chain/audits.toml"
 
@@ -858,10 +861,6 @@ criteria = "safe-to-run"
 version = "0.1.0"
 criteria = "safe-to-deploy"
 
-[[exemptions.version_check]]
-version = "0.9.4"
-criteria = "safe-to-deploy"
-
 [[exemptions.wait-timeout]]
 version = "0.2.0"
 criteria = "safe-to-deploy"
diff --git a/supply-chain/imports.lock b/supply-chain/imports.lock
index e2e66717c..814fabfbf 100644
--- a/supply-chain/imports.lock
+++ b/supply-chain/imports.lock
@@ -15,21 +15,6 @@ user-id = 696
 user-login = "fitzgen"
 user-name = "Nick Fitzgerald"
 
-[[audits.chromeos.audits.libfuzzer-sys]]
-who = "ChromeOS"
-criteria = "safe-to-run"
-version = "0.4.4"
-
-[[audits.chromeos.audits.miniz_oxide]]
-who = "George Burgess IV <gbiv@google.com>"
-criteria = "safe-to-run"
-version = "0.6.2"
-
-[[audits.chromeos.audits.static_assertions]]
-who = "ChromeOS"
-criteria = "safe-to-run"
-version = "1.1.0"
-
 [[audits.embark-studios.audits.anyhow]]
 who = "Johan Andersson <opensource@embark-studios.com>"
 criteria = "safe-to-deploy"
@@ -47,6 +32,30 @@ criteria = "safe-to-deploy"
 version = "0.2.2"
 notes = "Inspected it and is a tiny crate with just type definitions"
 
+[[audits.google.audits.libfuzzer-sys]]
+who = "ChromeOS"
+criteria = "safe-to-run"
+version = "0.4.4"
+aggregated-from = "https://chromium.googlesource.com/chromiumos/third_party/rust_crates/+/main/cargo-vet/audits.toml?format=TEXT"
+
+[[audits.google.audits.miniz_oxide]]
+who = "George Burgess IV <gbiv@google.com>"
+criteria = "safe-to-run"
+version = "0.6.2"
+aggregated-from = "https://chromium.googlesource.com/chromiumos/third_party/rust_crates/+/main/cargo-vet/audits.toml?format=TEXT"
+
+[[audits.google.audits.static_assertions]]
+who = "ChromeOS"
+criteria = "safe-to-run"
+version = "1.1.0"
+aggregated-from = "https://chromium.googlesource.com/chromiumos/third_party/rust_crates/+/main/cargo-vet/audits.toml?format=TEXT"
+
+[[audits.google.audits.version_check]]
+who = "George Burgess IV <gbiv@google.com>"
+criteria = "safe-to-deploy"
+version = "0.9.4"
+aggregated-from = "https://chromium.googlesource.com/chromiumos/third_party/rust_crates/+/main/cargo-vet/audits.toml?format=TEXT"
+
 [[audits.isrg.audits.block-buffer]]
 who = "David Cook <dcook@divviup.org>"
 criteria = "safe-to-deploy"
diff --git a/winch/codegen/src/abi/local.rs b/winch/codegen/src/abi/local.rs
index 6f4f72748..a951dac44 100644
--- a/winch/codegen/src/abi/local.rs
+++ b/winch/codegen/src/abi/local.rs
@@ -1,7 +1,7 @@
 use wasmparser::ValType;
 /// Base register used to address the local slot.
 ///
-/// Slots for stack arguments are addressed from the frame pointer
+/// Slots for stack arguments are addressed from the frame pointer.
 /// Slots for function-defined locals and for registers are addressed
 /// from the stack pointer.
 #[derive(Eq, PartialEq)]
diff --git a/winch/codegen/src/abi/mod.rs b/winch/codegen/src/abi/mod.rs
index 087770391..83a39cf6d 100644
--- a/winch/codegen/src/abi/mod.rs
+++ b/winch/codegen/src/abi/mod.rs
@@ -1,3 +1,47 @@
+//! This module provides all the necessary building blocks for
+//! implementing ISA specific ABIs.
+//!
+//! # Default ABI
+//!
+//! Winch uses a default internal ABI, for all internal functions.
+//! This allows us to push the complexity of system ABI compliance to
+//! the trampolines (not yet implemented).  The default ABI treats all
+//! allocatable registers as caller saved, which means that (i) all
+//! register values in the Wasm value stack (which are normally
+//! referred to as "live"), must be saved onto the machine stack (ii)
+//! function prologues and epilogues don't store/restore other
+//! registers more than the non-allocatable ones (e.g. rsp/rbp in
+//! x86_64).
+//!
+//! The calling convention in the default ABI, uses registers to a
+//! certain fixed count for arguments and return values, and then the
+//! stack is used for all additional arguments.
+//!
+//! Generally the stack layout looks like:
+//! +-------------------------------+
+//! |                               |
+//! |                               |
+//! |         Stack Args            |
+//! |                               |
+//! |                               |
+//! +-------------------------------+----> SP @ function entry
+//! |         Ret addr              |
+//! +-------------------------------+
+//! |            SP                 |
+//! +-------------------------------+----> SP @ Function prologue
+//! |                               |
+//! |                               |
+//! |                               |
+//! |        Stack slots            |
+//! |        + dynamic space        |
+//! |                               |
+//! |                               |
+//! |                               |
+//! +-------------------------------+----> SP @ callsite (after)
+//! |        alignment              |
+//! |        + arguments            |
+//! |                               | ----> Space allocated for calls
+//! |                               |
 use crate::isa::reg::Reg;
 use smallvec::SmallVec;
 use std::ops::{Add, BitAnd, Not, Sub};
@@ -13,6 +57,9 @@ pub(crate) trait ABI {
     /// The required stack alignment.
     fn stack_align(&self) -> u8;
 
+    /// The required stack alignment for calls.
+    fn call_stack_align(&self) -> u8;
+
     /// The offset to the argument base, relative to the frame pointer.
     fn arg_base_offset(&self) -> u8;
 
@@ -117,11 +164,27 @@ impl ABIResult {
     }
 }
 
+pub(crate) type ABIParams = SmallVec<[ABIArg; 6]>;
+
 /// An ABI-specific representation of a function signature.
 pub(crate) struct ABISig {
     /// Function parameters.
-    pub params: SmallVec<[ABIArg; 6]>,
+    pub params: ABIParams,
+    /// Function result.
     pub result: ABIResult,
+    /// Stack space needed for stack arguments.
+    pub stack_bytes: u32,
+}
+
+impl ABISig {
+    /// Create a new ABI signature.
+    pub fn new(params: ABIParams, result: ABIResult, stack_bytes: u32) -> Self {
+        Self {
+            params,
+            result,
+            stack_bytes,
+        }
+    }
 }
 
 /// Returns the size in bytes of a given WebAssembly type.
diff --git a/winch/codegen/src/codegen/call.rs b/winch/codegen/src/codegen/call.rs
new file mode 100644
index 000000000..c2907ab24
--- /dev/null
+++ b/winch/codegen/src/codegen/call.rs
@@ -0,0 +1,222 @@
+//! Function call emission.  For more details around the ABI and
+//! calling convention, see [ABI].
+use super::CodeGenContext;
+use crate::{
+    abi::{align_to, ABIArg, ABIResult, ABISig, ABI},
+    masm::{MacroAssembler, OperandSize},
+    reg::Reg,
+    stack::Val,
+};
+
+/// All the information needed to emit a function call.
+pub(crate) struct FnCall<'a> {
+    /// The total stack space in bytes used by the function call.
+    /// This amount includes the sum of:
+    ///
+    /// 1. The amount of stack space that needs to be explicitly
+    ///    allocated at the callsite for callee arguments that
+    ///    go in the stack, plus any alignment.
+    /// 2. The amount of stack space created by saving any live
+    ///    registers at the callsite.
+    /// 3. The amount of space used by any memory entries in the value
+    ///    stack present at the callsite, that will be used as
+    ///    arguments for the function call. Any memory values in the
+    ///    value stack that are needed as part of the function
+    ///    arguments, will be consumed by the function call (either by
+    ///    assigning those values to a register or by storing those
+    ///    values to a memory location if the callee argument is on
+    ///    the stack), so we track that stack space to reclaim it once
+    ///    the function call has ended. This could also be done in
+    ///    `assign_args` everytime a memory entry needs to be assigned
+    ///    to a particular location, but doing so, will incur in more
+    ///    instructions (e.g. a pop per argument that needs to be
+    ///    assigned); it's more efficient to track the space needed by
+    ///    those memory values and reclaim it at once.
+    ///
+    ///   The machine stack state that this amount is capturing, is the following:
+    /// ┌──────────────────────────────────────────────────┐
+    /// │                                                  │
+    /// │                                                  │
+    /// │  Stack space created by any previous spills      │
+    /// │  from the value stack; and which memory values   │
+    /// │  are used as function arguments.                 │        
+    /// │                                                  │
+    /// ├──────────────────────────────────────────────────┤ ---> The Wasm value stack at this point in time would look like:
+    /// │                                                  │      [ Reg | Reg | Mem(offset) | Mem(offset) ]
+    /// │                                                  │
+    /// │   Stack space created by saving                  │
+    /// │   any live registers at the callsite.            │
+    /// │                                                  │
+    /// │                                                  │
+    /// ├─────────────────────────────────────────────────┬┤ ---> The Wasm value stack at this point in time would look like:
+    /// │                                                  │      [ Mem(offset) | Mem(offset) | Mem(offset) | Mem(offset) ]
+    /// │                                                  │      Assuming that the callee takes 4 arguments, we calculate
+    /// │                                                  │      2 spilled registers + 2 memory values; all of which will be used  
+    /// │   Stack space allocated for                      │      as arguments to the call via `assign_args`, thus the memory they represent is
+    /// │   the callee function arguments in the stack;    │      is considered to be consumed by the call.
+    /// │   represented by `arg_stack_space`               │
+    /// │                                                  │
+    /// │                                                  │
+    /// │                                                  │
+    /// └──────────────────────────────────────────────────┘ ------> Stack pointer when emitting the call
+    ///    
+    total_stack_space: u32,
+    /// The total stack space needed for the callee arguments on the
+    /// stack, including any adjustments to the function's frame and
+    /// aligned to to the required ABI alignment.
+    arg_stack_space: u32,
+    /// The ABI-specific signature of the callee.
+    abi_sig: &'a ABISig,
+    /// The stack pointer offset prior to preparing and emitting the
+    /// call. This is tracked to assert the position of the stack
+    /// pointer after the call has finished.
+    sp_offset_at_callsite: u32,
+}
+
+impl<'a> FnCall<'a> {
+    /// Allocate and setup a new function call.
+    ///
+    /// The setup process, will first save all the live registers in
+    /// the value stack, tracking down those spilled for the function
+    /// arguments(see comment below for more details) it will also
+    /// track all the memory entries consumed by the function
+    /// call. Then, it will calculate any adjustments needed to ensure
+    /// the alignment of the caller's frame.  It's important to note
+    /// that the order of operations in the setup is important, as we
+    /// want to calculate any adjustments to the caller's frame, after
+    /// having saved any live registers, so that we can account for
+    /// any pushes generated by register spilling.
+    pub fn new<A: ABI, M: MacroAssembler>(
+        abi: &A,
+        callee_sig: &'a ABISig,
+        context: &mut CodeGenContext,
+        masm: &mut M,
+    ) -> Self {
+        let stack = &context.stack;
+        let arg_stack_space = callee_sig.stack_bytes;
+        let callee_params = &callee_sig.params;
+        let sp_offset_at_callsite = masm.sp_offset();
+
+        let (spilled_regs, memory_values) = match callee_params.len() {
+            0 => {
+                let _ = context.spill_regs_and_count_memory_in(masm, ..);
+                (0, 0)
+            }
+            _ => {
+                // Here we perform a "spill" of the register entries
+                // in the Wasm value stack, we also count any memory
+                // values that will be used used as part of the callee
+                // arguments.  Saving the live registers is done by
+                // emitting push operations for every `Reg` entry in
+                // the Wasm value stack. We do this to be compliant
+                // with Winch's internal ABI, in which all registers
+                // are treated as caller-saved. For more details, see
+                // [ABI].
+                //
+                // The next few lines, partition the value stack into
+                // two sections:
+                // +------------------+--+--- (Stack top)
+                // |                  |  |
+                // |                  |  | 1. The top `n` elements, which are used for
+                // |                  |  |    function arguments; for which we save any
+                // |                  |  |    live registers, keeping track of the amount of registers
+                // +------------------+  |    saved plus the amount of memory values consumed by the function call;
+                // |                  |  |    with this information we can later reclaim the space used by the function call.
+                // |                  |  |
+                // +------------------+--+---
+                // |                  |  | 2. The rest of the items in the stack, for which
+                // |                  |  |    we only save any live registers.
+                // |                  |  |
+                // +------------------+  |
+                assert!(stack.len() >= callee_params.len());
+                let partition = stack.len() - callee_params.len();
+                let _ = context.spill_regs_and_count_memory_in(masm, 0..partition);
+                context.spill_regs_and_count_memory_in(masm, partition..)
+            }
+        };
+
+        let delta = calculate_frame_adjustment(
+            masm.sp_offset(),
+            abi.arg_base_offset() as u32,
+            abi.call_stack_align() as u32,
+        );
+
+        let arg_stack_space = align_to(arg_stack_space + delta, abi.call_stack_align() as u32);
+        Self {
+            abi_sig: &callee_sig,
+            arg_stack_space,
+            total_stack_space: (spilled_regs * <A as ABI>::word_bytes())
+                + (memory_values * <A as ABI>::word_bytes())
+                + arg_stack_space,
+            sp_offset_at_callsite,
+        }
+    }
+
+    /// Emit the function call.
+    pub fn emit<M: MacroAssembler, A: ABI>(
+        &self,
+        masm: &mut M,
+        context: &mut CodeGenContext,
+        callee: u32,
+    ) {
+        masm.reserve_stack(self.arg_stack_space);
+        self.assign_args(context, masm, <A as ABI>::scratch_reg());
+        masm.call(callee);
+        masm.free_stack(self.total_stack_space);
+        context.drop_last(self.abi_sig.params.len());
+        // The stack pointer at the end of the function call
+        // cannot be less than what it was when starting the
+        // function call.
+        assert!(self.sp_offset_at_callsite >= masm.sp_offset());
+        self.handle_result(context, masm);
+    }
+
+    fn assign_args<M: MacroAssembler>(
+        &self,
+        context: &mut CodeGenContext,
+        masm: &mut M,
+        scratch: Reg,
+    ) {
+        let arg_count = self.abi_sig.params.len();
+        let stack = &context.stack;
+        let mut stack_values = stack.peekn(arg_count);
+        for arg in &self.abi_sig.params {
+            let val = stack_values
+                .next()
+                .unwrap_or_else(|| panic!("expected stack value for function argument"));
+            match &arg {
+                &ABIArg::Reg { ty, reg } => {
+                    context.move_val_to_reg(&val, *reg, masm, (*ty).into());
+                }
+                &ABIArg::Stack { ty, offset } => {
+                    let addr = masm.address_at_sp(*offset);
+                    let size: OperandSize = (*ty).into();
+                    context.move_val_to_reg(val, scratch, masm, size);
+                    masm.store(scratch.into(), addr, size);
+                }
+            }
+        }
+    }
+
+    fn handle_result<M: MacroAssembler>(&self, context: &mut CodeGenContext, masm: &mut M) {
+        let result = &self.abi_sig.result;
+        if result.is_void() {
+            return;
+        }
+
+        match result {
+            &ABIResult::Reg { ty: _, reg } => {
+                assert!(context.regalloc.gpr_available(reg));
+                let result_reg = Val::reg(context.gpr(reg, masm));
+                context.stack.push(result_reg);
+            }
+        }
+    }
+}
+
+/// Calculates the delta needed to adjust a function's frame plus some
+/// addend to a given alignment.
+fn calculate_frame_adjustment(frame_size: u32, addend: u32, alignment: u32) -> u32 {
+    let total = frame_size + addend;
+    (alignment - (total % alignment)) % alignment
+}
diff --git a/winch/codegen/src/codegen/context.rs b/winch/codegen/src/codegen/context.rs
index 94b3da496..12d3f8de4 100644
--- a/winch/codegen/src/codegen/context.rs
+++ b/winch/codegen/src/codegen/context.rs
@@ -5,6 +5,7 @@ use crate::{
     regalloc::RegAlloc,
     stack::{Stack, Val},
 };
+use std::ops::RangeBounds;
 
 /// The code generation context.
 /// The code generation context is made up of three
@@ -60,58 +61,66 @@ impl<'a> CodeGenContext<'a> {
         self.regalloc.free_gpr(reg);
     }
 
-    /// Loads the stack top value into a register, if it isn't already one;
-    /// spilling if there are no registers available.
-    pub fn pop_to_reg<M: MacroAssembler>(&mut self, masm: &mut M, size: OperandSize) -> Reg {
-        if let Some(reg) = self.stack.pop_reg() {
-            return reg;
-        }
-
-        let dst = self.any_gpr(masm);
-        let val = self.stack.pop().expect("a value at stack top");
-        Self::move_val_to_reg(val, dst, masm, self.frame, size);
-        dst
-    }
-
-    /// Checks if the stack top contains the given register. The register
-    /// gets allocated otherwise, potentially causing a spill.
-    /// Once the requested register is allocated, the value at the top of the stack
-    /// gets loaded into the register.
-    pub fn pop_to_named_reg<M: MacroAssembler>(
+    /// Loads the stack top value into the next available register, if
+    /// it isn't already one; spilling if there are no registers
+    /// available.  Optionally the caller may specify a specific
+    /// destination register.
+    pub fn pop_to_reg<M: MacroAssembler>(
         &mut self,
         masm: &mut M,
-        named: Reg,
+        named: Option<Reg>,
         size: OperandSize,
     ) -> Reg {
-        if let Some(reg) = self.stack.pop_named_reg(named) {
-            return reg;
+        let (in_stack, dst) = if let Some(dst) = named {
+            self.stack
+                .pop_named_reg(dst)
+                .map(|reg| (true, reg))
+                .unwrap_or_else(|| (false, self.gpr(dst, masm)))
+        } else {
+            self.stack
+                .pop_reg()
+                .map(|reg| (true, reg))
+                .unwrap_or_else(|| (false, self.any_gpr(masm)))
+        };
+
+        if in_stack {
+            return dst;
         }
 
-        let dst = self.gpr(named, masm);
         let val = self.stack.pop().expect("a value at stack top");
-        Self::move_val_to_reg(val, dst, masm, self.frame, size);
+        if val.is_mem() {
+            masm.pop(dst);
+        } else {
+            self.move_val_to_reg(&val, dst, masm, size);
+        }
+
         dst
     }
 
-    fn move_val_to_reg<M: MacroAssembler>(
-        src: Val,
+    /// Move a stack value to the given register.
+    pub fn move_val_to_reg<M: MacroAssembler>(
+        &self,
+        src: &Val,
         dst: Reg,
         masm: &mut M,
-        frame: &Frame,
         size: OperandSize,
     ) {
         match src {
-            Val::Reg(src) => masm.mov(RegImm::reg(src), RegImm::reg(dst), size),
-            Val::I32(imm) => masm.mov(RegImm::imm(imm.into()), RegImm::reg(dst), size),
-            Val::I64(imm) => masm.mov(RegImm::imm(imm), RegImm::reg(dst), size),
+            Val::Reg(src) => masm.mov(RegImm::reg(*src), RegImm::reg(dst), size),
+            Val::I32(imm) => masm.mov(RegImm::imm((*imm).into()), RegImm::reg(dst), size),
+            Val::I64(imm) => masm.mov(RegImm::imm(*imm), RegImm::reg(dst), size),
             Val::Local(index) => {
-                let slot = frame
-                    .get_local(index)
-                    .expect(&format!("valid locat at index = {}", index));
+                let slot = self
+                    .frame
+                    .get_local(*index)
+                    .unwrap_or_else(|| panic!("valid local at index = {}", index));
                 let addr = masm.local_address(&slot);
                 masm.load(addr, dst, slot.ty.into());
             }
-            v => panic!("Unsupported value {:?}", v),
+            Val::Memory(offset) => {
+                let addr = masm.address_from_sp(*offset);
+                masm.load(addr, dst, size);
+            }
         };
     }
 
@@ -128,7 +137,7 @@ impl<'a> CodeGenContext<'a> {
                 .stack
                 .pop_i32_const()
                 .expect("i32 const value at stack top");
-            let reg = self.pop_to_reg(masm, OperandSize::S32);
+            let reg = self.pop_to_reg(masm, None, OperandSize::S32);
             emit(
                 masm,
                 RegImm::reg(reg),
@@ -137,8 +146,8 @@ impl<'a> CodeGenContext<'a> {
             );
             self.stack.push(Val::reg(reg));
         } else {
-            let src = self.pop_to_reg(masm, OperandSize::S32);
-            let dst = self.pop_to_reg(masm, OperandSize::S32);
+            let src = self.pop_to_reg(masm, None, OperandSize::S32);
+            let dst = self.pop_to_reg(masm, None, OperandSize::S32);
             emit(masm, dst.into(), src.into(), OperandSize::S32);
             self.regalloc.free_gpr(src);
             self.stack.push(Val::reg(dst));
@@ -157,18 +166,64 @@ impl<'a> CodeGenContext<'a> {
                 .stack
                 .pop_i64_const()
                 .expect("i64 const value at stack top");
-            let reg = self.pop_to_reg(masm, OperandSize::S64);
+            let reg = self.pop_to_reg(masm, None, OperandSize::S64);
             emit(masm, RegImm::reg(reg), RegImm::imm(val), OperandSize::S64);
             self.stack.push(Val::reg(reg));
         } else {
-            let src = self.pop_to_reg(masm, OperandSize::S64);
-            let dst = self.pop_to_reg(masm, OperandSize::S64);
+            let src = self.pop_to_reg(masm, None, OperandSize::S64);
+            let dst = self.pop_to_reg(masm, None, OperandSize::S64);
             emit(masm, dst.into(), src.into(), OperandSize::S64);
             self.regalloc.free_gpr(src);
             self.stack.push(Val::reg(dst));
         }
     }
 
+    /// Saves any live registers in the value stack in a particular
+    /// range defined by the caller.  This is a specialization of the
+    /// spill function; made available for cases in which spilling
+    /// locals is not required, like for example for function calls in
+    /// which locals are not reachable by the callee.  It also tracks
+    /// down the number of memory values in the given range.
+    ///
+    /// Returns the number of spilled registers and the number of
+    /// memory values in the given range of the value stack.
+    pub fn spill_regs_and_count_memory_in<M, R>(&mut self, masm: &mut M, range: R) -> (u32, u32)
+    where
+        R: RangeBounds<usize>,
+        M: MacroAssembler,
+    {
+        let mut spilled: u32 = 0;
+        let mut memory_values = 0;
+        for i in self.stack.inner_mut().range_mut(range) {
+            if i.is_reg() {
+                let reg = i.get_reg();
+                let offset = masm.push(reg);
+                self.regalloc.free_gpr(reg);
+                *i = Val::Memory(offset);
+                spilled += 1;
+            } else if i.is_mem() {
+                memory_values += 1;
+            }
+        }
+
+        (spilled, memory_values)
+    }
+
+    /// Drops the last `n` elements of the stack, freeing any
+    /// registers located in that region.
+    pub fn drop_last(&mut self, last: usize) {
+        let len = self.stack.len();
+        assert!(last <= len);
+        let truncate = self.stack.len() - last;
+
+        self.stack.inner_mut().range(truncate..).for_each(|v| {
+            if v.is_reg() {
+                self.regalloc.free_gpr(v.get_reg());
+            }
+        });
+        self.stack.inner_mut().truncate(truncate);
+    }
+
     /// Spill locals and registers to memory.
     // TODO optimize the spill range;
     //
diff --git a/winch/codegen/src/codegen/mod.rs b/winch/codegen/src/codegen/mod.rs
index 807912218..7ffbaf5e9 100644
--- a/winch/codegen/src/codegen/mod.rs
+++ b/winch/codegen/src/codegen/mod.rs
@@ -3,21 +3,21 @@ use crate::{
     masm::{MacroAssembler, OperandSize},
 };
 use anyhow::Result;
+use call::FnCall;
 use wasmparser::{BinaryReader, FuncValidator, ValType, ValidatorResources, VisitOperator};
 
 mod context;
 pub(crate) use context::*;
 mod env;
 pub use env::*;
+mod call;
 
 /// The code generation abstraction.
-pub(crate) struct CodeGen<'a, M>
+pub(crate) struct CodeGen<'a, A, M>
 where
     M: MacroAssembler,
+    A: ABI,
 {
-    /// The word size in bytes, extracted from the current ABI.
-    word_size: u32,
-
     /// The ABI-specific representation of the function signature, excluding results.
     sig: ABISig,
 
@@ -26,18 +26,32 @@ where
 
     /// The MacroAssembler.
     pub masm: &'a mut M,
+
+    /// A reference to the function compilation environment.
+    pub env: &'a dyn env::FuncEnv,
+
+    /// A reference to the current ABI.
+    pub abi: &'a A,
 }
 
-impl<'a, M> CodeGen<'a, M>
+impl<'a, A, M> CodeGen<'a, A, M>
 where
     M: MacroAssembler,
+    A: ABI,
 {
-    pub fn new<A: ABI>(masm: &'a mut M, context: CodeGenContext<'a>, sig: ABISig) -> Self {
+    pub fn new(
+        masm: &'a mut M,
+        abi: &'a A,
+        context: CodeGenContext<'a>,
+        env: &'a dyn FuncEnv,
+        sig: ABISig,
+    ) -> Self {
         Self {
-            word_size: <A as ABI>::word_bytes(),
             sig,
             context,
             masm,
+            abi,
+            env,
         }
     }
 
@@ -70,7 +84,7 @@ where
         let defined_locals_range = &self.context.frame.defined_locals_range;
         self.masm.zero_mem_range(
             defined_locals_range.as_range(),
-            self.word_size,
+            <A as ABI>::word_bytes(),
             &mut self.context.regalloc,
         );
 
@@ -105,8 +119,21 @@ where
         }
     }
 
-    // Emit the usual function end instruction sequence.
-    pub fn emit_end(&mut self) -> Result<()> {
+    /// Emit a direct function call.
+    pub fn emit_call(&mut self, index: u32) {
+        let callee = self.env.callee_from_index(index);
+        if callee.import {
+            // TODO: Only locally defined functions for now.
+            unreachable!()
+        }
+
+        let sig = self.abi.sig(&callee.ty);
+        let fncall = FnCall::new(self.abi, &sig, &mut self.context, self.masm);
+        fncall.emit::<M, A>(self.masm, &mut self.context, index);
+    }
+
+    /// Emit the usual function end instruction sequence.
+    fn emit_end(&mut self) -> Result<()> {
         self.handle_abi_result();
         self.masm.epilogue(self.context.frame.locals_size);
         Ok(())
@@ -149,7 +176,7 @@ where
         let named_reg = self.sig.result.result_reg();
         let reg = self
             .context
-            .pop_to_named_reg(self.masm, named_reg, OperandSize::S64);
+            .pop_to_reg(self.masm, Some(named_reg), OperandSize::S64);
         self.context.regalloc.free_gpr(reg);
     }
 }
diff --git a/winch/codegen/src/isa/aarch64/abi.rs b/winch/codegen/src/isa/aarch64/abi.rs
index 14afcc235..f348412e4 100644
--- a/winch/codegen/src/isa/aarch64/abi.rs
+++ b/winch/codegen/src/isa/aarch64/abi.rs
@@ -47,6 +47,10 @@ impl ABI for Aarch64ABI {
         8
     }
 
+    fn call_stack_align(&self) -> u8 {
+        16
+    }
+
     fn arg_base_offset(&self) -> u8 {
         16
     }
@@ -74,7 +78,7 @@ impl ABI for Aarch64ABI {
         let reg = regs::xreg(0);
         let result = ABIResult::reg(ty, reg);
 
-        ABISig { params, result }
+        ABISig::new(params, result, stack_offset)
     }
 
     fn scratch_reg() -> Reg {
diff --git a/winch/codegen/src/isa/aarch64/masm.rs b/winch/codegen/src/isa/aarch64/masm.rs
index e44c6c471..92b30218f 100644
--- a/winch/codegen/src/isa/aarch64/masm.rs
+++ b/winch/codegen/src/isa/aarch64/masm.rs
@@ -96,6 +96,10 @@ impl Masm for MacroAssembler {
         self.increment_sp(bytes);
     }
 
+    fn free_stack(&mut self, _bytes: u32) {
+        todo!()
+    }
+
     fn local_address(&mut self, local: &LocalSlot) -> Address {
         let (reg, offset) = local
             .addressed_from_sp()
@@ -111,6 +115,14 @@ impl Masm for MacroAssembler {
         Address::offset(reg, offset as i64)
     }
 
+    fn address_from_sp(&self, _offset: u32) -> Self::Address {
+        todo!()
+    }
+
+    fn address_at_sp(&self, _offset: u32) -> Self::Address {
+        todo!()
+    }
+
     fn store(&mut self, src: RegImm, dst: Address, size: OperandSize) {
         let src = match src {
             RegImm::Imm(imm) => {
@@ -124,10 +136,18 @@ impl Masm for MacroAssembler {
         self.asm.str(src, dst, size);
     }
 
+    fn call(&mut self, _callee: u32) {
+        todo!()
+    }
+
     fn load(&mut self, src: Address, dst: Reg, size: OperandSize) {
         self.asm.ldr(src, dst, size);
     }
 
+    fn pop(&mut self, _dst: Reg) {
+        todo!()
+    }
+
     fn sp_offset(&mut self) -> u32 {
         self.sp_offset
     }
diff --git a/winch/codegen/src/isa/aarch64/mod.rs b/winch/codegen/src/isa/aarch64/mod.rs
index ff56cdb99..6934d0492 100644
--- a/winch/codegen/src/isa/aarch64/mod.rs
+++ b/winch/codegen/src/isa/aarch64/mod.rs
@@ -8,6 +8,7 @@ use crate::{
     regalloc::RegAlloc,
     regset::RegSet,
     stack::Stack,
+    FuncEnv,
 };
 use anyhow::Result;
 use cranelift_codegen::settings::{self, Flags};
@@ -84,6 +85,7 @@ impl TargetIsa for Aarch64 {
         &self,
         sig: &FuncType,
         body: &FunctionBody,
+        env: &dyn FuncEnv,
         mut validator: FuncValidator<ValidatorResources>,
     ) -> Result<MachBufferFinalized<Final>> {
         let mut body = body.get_binary_reader();
@@ -95,7 +97,7 @@ impl TargetIsa for Aarch64 {
         // TODO: Add floating point bitmask
         let regalloc = RegAlloc::new(RegSet::new(ALL_GPR, 0), scratch());
         let codegen_context = CodeGenContext::new(regalloc, stack, &frame);
-        let mut codegen = CodeGen::new::<abi::Aarch64ABI>(&mut masm, codegen_context, abi_sig);
+        let mut codegen = CodeGen::new(&mut masm, &abi, codegen_context, env, abi_sig);
 
         codegen.emit(&mut body, validator)?;
         Ok(masm.finalize())
diff --git a/winch/codegen/src/isa/mod.rs b/winch/codegen/src/isa/mod.rs
index 37fcb76f0..058c9c70e 100644
--- a/winch/codegen/src/isa/mod.rs
+++ b/winch/codegen/src/isa/mod.rs
@@ -10,6 +10,8 @@ use std::{
 use target_lexicon::{Architecture, Triple};
 use wasmparser::{FuncType, FuncValidator, FunctionBody, ValidatorResources};
 
+use crate::FuncEnv;
+
 #[cfg(feature = "x64")]
 pub(crate) mod x64;
 
@@ -92,6 +94,7 @@ pub trait TargetIsa: Send + Sync {
         &self,
         sig: &FuncType,
         body: &FunctionBody,
+        env: &dyn FuncEnv,
         validator: FuncValidator<ValidatorResources>,
     ) -> Result<MachBufferFinalized<Final>>;
 
diff --git a/winch/codegen/src/isa/x64/abi.rs b/winch/codegen/src/isa/x64/abi.rs
index cf7dc2eb5..0bd30e713 100644
--- a/winch/codegen/src/isa/x64/abi.rs
+++ b/winch/codegen/src/isa/x64/abi.rs
@@ -39,6 +39,10 @@ impl ABI for X64ABI {
         8
     }
 
+    fn call_stack_align(&self) -> u8 {
+        16
+    }
+
     fn arg_base_offset(&self) -> u8 {
         // Two 8-byte slots, one for the return address and another
         // one for the frame pointer.
@@ -75,7 +79,7 @@ impl ABI for X64ABI {
         let reg = regs::rax();
         let result = ABIResult::reg(ty, reg);
 
-        ABISig { params, result }
+        ABISig::new(params, result, stack_offset)
     }
 
     fn scratch_reg() -> Reg {
diff --git a/winch/codegen/src/isa/x64/asm.rs b/winch/codegen/src/isa/x64/asm.rs
index c6a2548c8..8f03489e2 100644
--- a/winch/codegen/src/isa/x64/asm.rs
+++ b/winch/codegen/src/isa/x64/asm.rs
@@ -5,18 +5,21 @@ use crate::{
     masm::{DivKind, OperandSize, RemKind},
 };
 use cranelift_codegen::{
+    entity::EntityRef,
     ir::TrapCode,
+    ir::{ExternalName, Opcode, UserExternalNameRef},
     isa::x64::{
         args::{
             self, AluRmiROpcode, Amode, CmpOpcode, DivSignedness, ExtMode, FromWritableReg, Gpr,
             GprMem, GprMemImm, RegMem, RegMemImm, SyntheticAmode, WritableGpr, CC,
         },
-        settings as x64_settings, EmitInfo, EmitState, Inst,
+        settings as x64_settings, CallInfo, EmitInfo, EmitState, Inst,
     },
     settings, Final, MachBuffer, MachBufferFinalized, MachInstEmit, Writable,
 };
 
 use super::{address::Address, regs};
+use smallvec::smallvec;
 
 /// A x64 instruction operand.
 #[derive(Debug, Copy, Clone)]
@@ -465,4 +468,18 @@ impl Assembler {
             dst: dst.into(),
         });
     }
+
+    /// Direct function call to a user defined function.
+    pub fn call(&mut self, callee: u32) {
+        let dest = ExternalName::user(UserExternalNameRef::new(callee as usize));
+        self.emit(Inst::CallKnown {
+            dest,
+            info: Box::new(CallInfo {
+                uses: smallvec![],
+                defs: smallvec![],
+                clobbers: Default::default(),
+                opcode: Opcode::Call,
+            }),
+        });
+    }
 }
diff --git a/winch/codegen/src/isa/x64/masm.rs b/winch/codegen/src/isa/x64/masm.rs
index e4bc0db62..cc973b24a 100644
--- a/winch/codegen/src/isa/x64/masm.rs
+++ b/winch/codegen/src/isa/x64/masm.rs
@@ -70,6 +70,14 @@ impl Masm for MacroAssembler {
         self.increment_sp(bytes);
     }
 
+    fn free_stack(&mut self, bytes: u32) {
+        if bytes == 0 {
+            return;
+        }
+        self.asm.add_ir(bytes as i32, rsp(), OperandSize::S64);
+        self.decrement_sp(bytes);
+    }
+
     fn local_address(&mut self, local: &LocalSlot) -> Address {
         let (reg, offset) = local
             .addressed_from_sp()
@@ -85,6 +93,14 @@ impl Masm for MacroAssembler {
         Address::offset(reg, offset)
     }
 
+    fn address_from_sp(&self, offset: u32) -> Self::Address {
+        Address::offset(regs::rsp(), self.sp_offset - offset)
+    }
+
+    fn address_at_sp(&self, offset: u32) -> Self::Address {
+        Address::offset(regs::rsp(), offset)
+    }
+
     fn store(&mut self, src: RegImm, dst: Address, size: OperandSize) {
         let src: Operand = src.into();
         let dst: Operand = dst.into();
@@ -92,6 +108,16 @@ impl Masm for MacroAssembler {
         self.asm.mov(src, dst, size);
     }
 
+    fn pop(&mut self, dst: Reg) {
+        self.asm.pop_r(dst);
+        // Similar to the comment in `push`, we assume 8 bytes per pop.
+        self.decrement_sp(8);
+    }
+
+    fn call(&mut self, callee: u32) {
+        self.asm.call(callee);
+    }
+
     fn load(&mut self, src: Address, dst: Reg, size: OperandSize) {
         let src = src.into();
         let dst = dst.into();
@@ -158,12 +184,12 @@ impl Masm for MacroAssembler {
         let rax = context.gpr(regs::rax(), self);
 
         // Allocate the divisor, which can be any gpr.
-        let divisor = context.pop_to_reg(self, size);
+        let divisor = context.pop_to_reg(self, None, size);
 
         // Mark rax as allocatable.
         context.regalloc.free_gpr(rax);
         // Move the top value to rax.
-        let rax = context.pop_to_named_reg(self, rax, size);
+        let rax = context.pop_to_reg(self, Some(rax), size);
         self.asm.div(divisor, (rax, rdx), kind, size);
 
         // Free the divisor and rdx.
@@ -180,12 +206,12 @@ impl Masm for MacroAssembler {
         let rax = context.gpr(regs::rax(), self);
 
         // Allocate the divisor, which can be any gpr.
-        let divisor = context.pop_to_reg(self, size);
+        let divisor = context.pop_to_reg(self, None, size);
 
         // Mark rax as allocatable.
         context.regalloc.free_gpr(rax);
         // Move the top value to rax.
-        let rax = context.pop_to_named_reg(self, rax, size);
+        let rax = context.pop_to_reg(self, Some(rax), size);
         self.asm.rem(divisor, (rax, rdx), kind, size);
 
         // Free the divisor and rax.
@@ -225,7 +251,6 @@ impl MacroAssembler {
         self.sp_offset += bytes;
     }
 
-    #[allow(dead_code)]
     fn decrement_sp(&mut self, bytes: u32) {
         assert!(
             self.sp_offset >= bytes,
diff --git a/winch/codegen/src/isa/x64/mod.rs b/winch/codegen/src/isa/x64/mod.rs
index dc3105540..78d85a38c 100644
--- a/winch/codegen/src/isa/x64/mod.rs
+++ b/winch/codegen/src/isa/x64/mod.rs
@@ -5,6 +5,7 @@ use crate::isa::x64::masm::MacroAssembler as X64Masm;
 use crate::masm::MacroAssembler;
 use crate::regalloc::RegAlloc;
 use crate::stack::Stack;
+use crate::FuncEnv;
 use crate::{
     isa::{Builder, TargetIsa},
     regset::RegSet,
@@ -85,6 +86,7 @@ impl TargetIsa for X64 {
         &self,
         sig: &FuncType,
         body: &FunctionBody,
+        env: &dyn FuncEnv,
         mut validator: FuncValidator<ValidatorResources>,
     ) -> Result<MachBufferFinalized<Final>> {
         let mut body = body.get_binary_reader();
@@ -96,7 +98,7 @@ impl TargetIsa for X64 {
         // TODO Add in floating point bitmask
         let regalloc = RegAlloc::new(RegSet::new(ALL_GPR, 0), regs::scratch());
         let codegen_context = CodeGenContext::new(regalloc, stack, &frame);
-        let mut codegen = CodeGen::new::<abi::X64ABI>(&mut masm, codegen_context, abi_sig);
+        let mut codegen = CodeGen::new(&mut masm, &abi, codegen_context, env, abi_sig);
 
         codegen.emit(&mut body, validator)?;
 
diff --git a/winch/codegen/src/masm.rs b/winch/codegen/src/masm.rs
index f23e31917..38ce40655 100644
--- a/winch/codegen/src/masm.rs
+++ b/winch/codegen/src/masm.rs
@@ -22,7 +22,7 @@ pub(crate) enum RemKind {
 }
 
 /// Operand size, in bits.
-#[derive(Copy, Clone, Eq, PartialEq)]
+#[derive(Copy, Debug, Clone, Eq, PartialEq)]
 pub(crate) enum OperandSize {
     /// 32 bits.
     S32,
@@ -87,9 +87,24 @@ pub(crate) trait MacroAssembler {
     /// Reserve stack space.
     fn reserve_stack(&mut self, bytes: u32);
 
+    /// Free stack space.
+    fn free_stack(&mut self, bytes: u32);
+
     /// Get the address of a local slot.
     fn local_address(&mut self, local: &LocalSlot) -> Self::Address;
 
+    /// Constructs an address with an offset that is relative to the
+    /// current position of the stack pointer (e.g. [sp + (sp_offset -
+    /// offset)].
+    fn address_from_sp(&self, offset: u32) -> Self::Address;
+
+    /// Constructs an address with an offset that is absolute to the
+    /// current position of the stack pointer (e.g. [sp + offset].
+    fn address_at_sp(&self, offset: u32) -> Self::Address;
+
+    /// Emit a function call to a locally defined function.
+    fn call(&mut self, callee: u32);
+
     /// Get stack pointer offset.
     fn sp_offset(&mut self) -> u32;
 
@@ -99,6 +114,9 @@ pub(crate) trait MacroAssembler {
     /// Perform a stack load.
     fn load(&mut self, src: Self::Address, dst: Reg, size: OperandSize);
 
+    /// Pop a value from the machine stack into the given register.
+    fn pop(&mut self, dst: Reg);
+
     /// Perform a move.
     fn mov(&mut self, src: RegImm, dst: RegImm, size: OperandSize);
 
diff --git a/winch/codegen/src/regalloc.rs b/winch/codegen/src/regalloc.rs
index 9cd95213a..7640561d7 100644
--- a/winch/codegen/src/regalloc.rs
+++ b/winch/codegen/src/regalloc.rs
@@ -35,6 +35,11 @@ impl RegAlloc {
         })
     }
 
+    /// Checks if a general purpose register is avaiable.
+    pub fn gpr_available(&self, reg: Reg) -> bool {
+        self.regset.named_gpr_available(reg.hw_enc() as u32)
+    }
+
     /// Request a specific general purpose register,
     /// spilling if not available.
     pub fn gpr<F>(&mut self, named: Reg, spill: &mut F) -> Reg
diff --git a/winch/codegen/src/regset.rs b/winch/codegen/src/regset.rs
index 676a25992..8b0ab0c73 100644
--- a/winch/codegen/src/regset.rs
+++ b/winch/codegen/src/regset.rs
@@ -38,7 +38,9 @@ impl RegSet {
         self.gpr |= 1 << index;
     }
 
-    fn named_gpr_available(&self, index: u32) -> bool {
+    /// Returns true if the given general purpose register
+    /// is available.
+    pub fn named_gpr_available(&self, index: u32) -> bool {
         let index = 1 << index;
         (!self.gpr & index) == 0
     }
diff --git a/winch/codegen/src/stack.rs b/winch/codegen/src/stack.rs
index 72308006f..d563d91e8 100644
--- a/winch/codegen/src/stack.rs
+++ b/winch/codegen/src/stack.rs
@@ -45,6 +45,14 @@ impl Val {
         }
     }
 
+    /// Check wheter the value is a memory offset.
+    pub fn is_mem(&self) -> bool {
+        match *self {
+            Self::Memory(_) => true,
+            _ => false,
+        }
+    }
+
     /// Get the register representation of the value.
     ///
     /// # Panics
@@ -109,6 +117,11 @@ impl Stack {
         }
     }
 
+    /// Get the length of the stack.
+    pub fn len(&self) -> usize {
+        self.inner.len()
+    }
+
     /// Push a value to the stack.
     pub fn push(&mut self, val: Val) {
         self.inner.push_back(val);
@@ -119,6 +132,16 @@ impl Stack {
         self.inner.back()
     }
 
+    /// Returns an iterator referencing the last n items of the stack,
+    /// in bottom-most to top-most order.
+    pub fn peekn(&self, n: usize) -> impl Iterator<Item = &Val> + '_ {
+        let len = self.len();
+        assert!(n <= len);
+
+        let partition = len - n;
+        self.inner.range(partition..)
+    }
+
     /// Pops the top element of the stack, if any.
     pub fn pop(&mut self) -> Option<Val> {
         self.inner.pop_back()
diff --git a/winch/codegen/src/visitor.rs b/winch/codegen/src/visitor.rs
index 331d0b76d..ac872e460 100644
--- a/winch/codegen/src/visitor.rs
+++ b/winch/codegen/src/visitor.rs
@@ -4,6 +4,7 @@
 //! which validates and dispatches to the corresponding
 //! machine code emitter.
 
+use crate::abi::ABI;
 use crate::codegen::CodeGen;
 use crate::masm::{DivKind, MacroAssembler, OperandSize, RegImm, RemKind};
 use crate::stack::Val;
@@ -49,14 +50,16 @@ macro_rules! def_unsupported {
     (emit I64Sub $($rest:tt)*) => {};
     (emit LocalGet $($rest:tt)*) => {};
     (emit LocalSet $($rest:tt)*) => {};
+    (emit Call $($rest:tt)*) => {};
     (emit End $($rest:tt)*) => {};
 
     (emit $unsupported:tt $($rest:tt)*) => {$($rest)*};
 }
 
-impl<'a, M> VisitOperator<'a> for CodeGen<'a, M>
+impl<'a, A, M> VisitOperator<'a> for CodeGen<'a, A, M>
 where
     M: MacroAssembler,
+    A: ABI,
 {
     type Output = ();
 
@@ -188,12 +191,16 @@ where
             .get_local(index)
             .expect(&format!("vald local at slot = {}", index));
         let size: OperandSize = slot.ty.into();
-        let src = self.context.pop_to_reg(self.masm, size);
+        let src = self.context.pop_to_reg(self.masm, None, size);
         let addr = self.masm.local_address(&slot);
         self.masm.store(RegImm::reg(src), addr, size);
         self.context.regalloc.free_gpr(src);
     }
 
+    fn visit_call(&mut self, index: u32) {
+        self.emit_call(index);
+    }
+
     wasmparser::for_each_operator!(def_unsupported);
 }
 
diff --git a/winch/src/compile.rs b/winch/src/compile.rs
index 1e05a6aaf..c08fa800b 100644
--- a/winch/src/compile.rs
+++ b/winch/src/compile.rs
@@ -60,7 +60,7 @@ fn compile(env: &FuncEnv, f: (DefinedFuncIndex, FunctionBodyData<'_>)) -> Result
     let validator = validator.into_validator(Default::default());
     let buffer = env
         .isa
-        .compile_function(&sig, &body, validator)
+        .compile_function(&sig, &body, env, validator)
         .expect("Couldn't compile function");
 
     println!("Disassembly for function: {}", index.as_u32());


Test patch:
diff --git a/cranelift/codegen/src/isa/riscv64/inst/emit_tests.rs b/cranelift/codegen/src/isa/riscv64/inst/emit_tests.rs
index f919990d8..261f9c2b5 100644
--- a/cranelift/codegen/src/isa/riscv64/inst/emit_tests.rs
+++ b/cranelift/codegen/src/isa/riscv64/inst/emit_tests.rs
@@ -248,7 +248,6 @@ fn test_riscv64_binemit() {
         0x28755593,
     ));
 
-    //
     insns.push(TestUnit::new(
         Inst::AluRRR {
             alu_op: AluOPRRR::Adduw,
@@ -256,10 +255,21 @@ fn test_riscv64_binemit() {
             rs1: a0(),
             rs2: zero_reg(),
         },
-        "add.uw a1,a0,zero",
+        "zext.w a1,a0",
         0x80505bb,
     ));
 
+    insns.push(TestUnit::new(
+        Inst::AluRRR {
+            alu_op: AluOPRRR::Adduw,
+            rd: writable_a1(),
+            rs1: a0(),
+            rs2: a1(),
+        },
+        "add.uw a1,a0,a1",
+        0x08b505bb,
+    ));
+
     insns.push(TestUnit::new(
         Inst::AluRRR {
             alu_op: AluOPRRR::Andn,
diff --git a/cranelift/codegen/src/isa/s390x/inst/emit_tests.rs b/cranelift/codegen/src/isa/s390x/inst/emit_tests.rs
index 003365cc0..c33f48964 100644
--- a/cranelift/codegen/src/isa/s390x/inst/emit_tests.rs
+++ b/cranelift/codegen/src/isa/s390x/inst/emit_tests.rs
@@ -7027,22 +7027,22 @@ fn test_s390x_binemit() {
         "br %r14",
     ));
 
-    insns.push((Inst::Debugtrap, "0001", "debugtrap"));
+    insns.push((Inst::Debugtrap, "0001", ".word 0x0001 # debugtrap"));
 
     insns.push((
         Inst::Trap {
             trap_code: TrapCode::StackOverflow,
         },
         "0000",
-        "trap",
+        ".word 0x0000 # trap=stk_ovf",
     ));
     insns.push((
         Inst::TrapIf {
             cond: Cond::from_mask(1),
             trap_code: TrapCode::StackOverflow,
         },
-        "A7E400030000",
-        "jno 6 ; trap",
+        "C01400000001",
+        "jgo .+2 # trap=stk_ovf",
     ));
 
     insns.push((
diff --git a/cranelift/filetests/filetests/egraph/icmp.clif b/cranelift/filetests/filetests/egraph/icmp.clif
new file mode 100644
index 000000000..0f10e4062
--- /dev/null
+++ b/cranelift/filetests/filetests/egraph/icmp.clif
@@ -0,0 +1,3010 @@
+test optimize precise-output
+set opt_level=speed
+set use_egraphs=true
+target x86_64
+
+;; !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+;; !!! GENERATED BY 'make-icmp-tests.sh' DO NOT EDIT !!!
+;; !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+;; run with the 'CRANELIFT_TEST_BLESS=1' env var set to update this file
+
+function %icmp_and_eq_eq(i32, i32) -> i8 {
+block0(v0: i32, v1: i32):
+    v2 = icmp eq v0, v1
+    v3 = icmp eq v0, v1
+    v4 = band v2, v3
+    return v4
+}
+
+; function %icmp_and_eq_eq(i32, i32) -> i8 fast {
+; block0(v0: i32, v1: i32):
+;     v2 = icmp eq v0, v1
+;     return v2
+; }
+
+function %icmp_and_eq_ne(i32, i32) -> i8 {
+block0(v0: i32, v1: i32):
+    v2 = icmp eq v0, v1
+    v3 = icmp ne v0, v1
+    v4 = band v2, v3
+    return v4
+}
+
+; function %icmp_and_eq_ne(i32, i32) -> i8 fast {
+; block0(v0: i32, v1: i32):
+;     v5 = iconst.i8 0
+;     return v5  ; v5 = 0
+; }
+
+function %icmp_and_eq_ult(i32, i32) -> i8 {
+block0(v0: i32, v1: i32):
+    v2 = icmp eq v0, v1
+    v3 = icmp ult v0, v1
+    v4 = band v2, v3
+    return v4
+}
+
+; function %icmp_and_eq_ult(i32, i32) -> i8 fast {
+; block0(v0: i32, v1: i32):
+;     v5 = iconst.i8 0
+;     return v5  ; v5 = 0
+; }
+
+function %icmp_and_eq_ule(i32, i32) -> i8 {
+block0(v0: i32, v1: i32):
+    v2 = icmp eq v0, v1
+    v3 = icmp ule v0, v1
+    v4 = band v2, v3
+    return v4
+}
+
+; function %icmp_and_eq_ule(i32, i32) -> i8 fast {
+; block0(v0: i32, v1: i32):
+;     v5 = icmp eq v0, v1
+;     v6 -> v5
+;     return v5
+; }
+
+function %icmp_and_eq_ugt(i32, i32) -> i8 {
+block0(v0: i32, v1: i32):
+    v2 = icmp eq v0, v1
+    v3 = icmp ugt v0, v1
+    v4 = band v2, v3
+    return v4
+}
+
+; function %icmp_and_eq_ugt(i32, i32) -> i8 fast {
+; block0(v0: i32, v1: i32):
+;     v5 = iconst.i8 0
+;     return v5  ; v5 = 0
+; }
+
+function %icmp_and_eq_uge(i32, i32) -> i8 {
+block0(v0: i32, v1: i32):
+    v2 = icmp eq v0, v1
+    v3 = icmp uge v0, v1
+    v4 = band v2, v3
+    return v4
+}
+
+; function %icmp_and_eq_uge(i32, i32) -> i8 fast {
+; block0(v0: i32, v1: i32):
+;     v5 = icmp eq v0, v1
+;     v6 -> v5
+;     return v5
+; }
+
+function %icmp_and_eq_slt(i32, i32) -> i8 {
+block0(v0: i32, v1: i32):
+    v2 = icmp eq v0, v1
+    v3 = icmp slt v0, v1
+    v4 = band v2, v3
+    return v4
+}
+
+; function %icmp_and_eq_slt(i32, i32) -> i8 fast {
+; block0(v0: i32, v1: i32):
+;     v5 = iconst.i8 0
+;     return v5  ; v5 = 0
+; }
+
+function %icmp_and_eq_sle(i32, i32) -> i8 {
+block0(v0: i32, v1: i32):
+    v2 = icmp eq v0, v1
+    v3 = icmp sle v0, v1
+    v4 = band v2, v3
+    return v4
+}
+
+; function %icmp_and_eq_sle(i32, i32) -> i8 fast {
+; block0(v0: i32, v1: i32):
+;     v5 = icmp eq v0, v1
+;     v6 -> v5
+;     return v5
+; }
+
+function %icmp_and_eq_sgt(i32, i32) -> i8 {
+block0(v0: i32, v1: i32):
+    v2 = icmp eq v0, v1
+    v3 = icmp sgt v0, v1
+    v4 = band v2, v3
+    return v4
+}
+
+; function %icmp_and_eq_sgt(i32, i32) -> i8 fast {
+; block0(v0: i32, v1: i32):
+;     v5 = iconst.i8 0
+;     return v5  ; v5 = 0
+; }
+
+function %icmp_and_eq_sge(i32, i32) -> i8 {
+block0(v0: i32, v1: i32):
+    v2 = icmp eq v0, v1
+    v3 = icmp sge v0, v1
+    v4 = band v2, v3
+    return v4
+}
+
+; function %icmp_and_eq_sge(i32, i32) -> i8 fast {
+; block0(v0: i32, v1: i32):
+;     v5 = icmp eq v0, v1
+;     v6 -> v5
+;     return v5
+; }
+
+function %icmp_and_ne_eq(i32, i32) -> i8 {
+block0(v0: i32, v1: i32):
+    v2 = icmp ne v0, v1
+    v3 = icmp eq v0, v1
+    v4 = band v2, v3
+    return v4
+}
+
+; function %icmp_and_ne_eq(i32, i32) -> i8 fast {
+; block0(v0: i32, v1: i32):
+;     v5 = iconst.i8 0
+;     return v5  ; v5 = 0
+; }
+
+function %icmp_and_ne_ne(i32, i32) -> i8 {
+block0(v0: i32, v1: i32):
+    v2 = icmp ne v0, v1
+    v3 = icmp ne v0, v1
+    v4 = band v2, v3
+    return v4
+}
+
+; function %icmp_and_ne_ne(i32, i32) -> i8 fast {
+; block0(v0: i32, v1: i32):
+;     v2 = icmp ne v0, v1
+;     return v2
+; }
+
+function %icmp_and_ne_ult(i32, i32) -> i8 {
+block0(v0: i32, v1: i32):
+    v2 = icmp ne v0, v1
+    v3 = icmp ult v0, v1
+    v4 = band v2, v3
+    return v4
+}
+
+; function %icmp_and_ne_ult(i32, i32) -> i8 fast {
+; block0(v0: i32, v1: i32):
+;     v5 = icmp ult v0, v1
+;     v6 -> v5
+;     return v5
+; }
+
+function %icmp_and_ne_ule(i32, i32) -> i8 {
+block0(v0: i32, v1: i32):
+    v2 = icmp ne v0, v1
+    v3 = icmp ule v0, v1
+    v4 = band v2, v3
+    return v4
+}
+
+; function %icmp_and_ne_ule(i32, i32) -> i8 fast {
+; block0(v0: i32, v1: i32):
+;     v5 = icmp ult v0, v1
+;     v6 -> v5
+;     return v5
+; }
+
+function %icmp_and_ne_ugt(i32, i32) -> i8 {
+block0(v0: i32, v1: i32):
+    v2 = icmp ne v0, v1
+    v3 = icmp ugt v0, v1
+    v4 = band v2, v3
+    return v4
+}
+
+; function %icmp_and_ne_ugt(i32, i32) -> i8 fast {
+; block0(v0: i32, v1: i32):
+;     v5 = icmp ugt v0, v1
+;     v6 -> v5
+;     return v5
+; }
+
+function %icmp_and_ne_uge(i32, i32) -> i8 {
+block0(v0: i32, v1: i32):
+    v2 = icmp ne v0, v1
+    v3 = icmp uge v0, v1
+    v4 = band v2, v3
+    return v4
+}
+
+; function %icmp_and_ne_uge(i32, i32) -> i8 fast {
+; block0(v0: i32, v1: i32):
+;     v5 = icmp ugt v0, v1
+;     v6 -> v5
+;     return v5
+; }
+
+function %icmp_and_ne_slt(i32, i32) -> i8 {
+block0(v0: i32, v1: i32):
+    v2 = icmp ne v0, v1
+    v3 = icmp slt v0, v1
+    v4 = band v2, v3
+    return v4
+}
+
+; function %icmp_and_ne_slt(i32, i32) -> i8 fast {
+; block0(v0: i32, v1: i32):
+;     v5 = icmp slt v0, v1
+;     v6 -> v5
+;     return v5
+; }
+
+function %icmp_and_ne_sle(i32, i32) -> i8 {
+block0(v0: i32, v1: i32):
+    v2 = icmp ne v0, v1
+    v3 = icmp sle v0, v1
+    v4 = band v2, v3
+    return v4
+}
+
+; function %icmp_and_ne_sle(i32, i32) -> i8 fast {
+; block0(v0: i32, v1: i32):
+;     v5 = icmp slt v0, v1
+;     v6 -> v5
+;     return v5
+; }
+
+function %icmp_and_ne_sgt(i32, i32) -> i8 {
+block0(v0: i32, v1: i32):
+    v2 = icmp ne v0, v1
+    v3 = icmp sgt v0, v1
+    v4 = band v2, v3
+    return v4
+}
+
+; function %icmp_and_ne_sgt(i32, i32) -> i8 fast {
+; block0(v0: i32, v1: i32):
+;     v5 = icmp sgt v0, v1
+;     v6 -> v5
+;     return v5
+; }
+
+function %icmp_and_ne_sge(i32, i32) -> i8 {
+block0(v0: i32, v1: i32):
+    v2 = icmp ne v0, v1
+    v3 = icmp sge v0, v1
+    v4 = band v2, v3
+    return v4
+}
+
+; function %icmp_and_ne_sge(i32, i32) -> i8 fast {
+; block0(v0: i32, v1: i32):
+;     v5 = icmp sgt v0, v1
+;     v6 -> v5
+;     return v5
+; }
+
+function %icmp_and_ult_eq(i32, i32) -> i8 {
+block0(v0: i32, v1: i32):
+    v2 = icmp ult v0, v1
+    v3 = icmp eq v0, v1
+    v4 = band v2, v3
+    return v4
+}
+
+; function %icmp_and_ult_eq(i32, i32) -> i8 fast {
+; block0(v0: i32, v1: i32):
+;     v5 = iconst.i8 0
+;     return v5  ; v5 = 0
+; }
+
+function %icmp_and_ult_ne(i32, i32) -> i8 {
+block0(v0: i32, v1: i32):
+    v2 = icmp ult v0, v1
+    v3 = icmp ne v0, v1
+    v4 = band v2, v3
+    return v4
+}
+
+; function %icmp_and_ult_ne(i32, i32) -> i8 fast {
+; block0(v0: i32, v1: i32):
+;     v5 = icmp ult v0, v1
+;     v6 -> v5
+;     return v5
+; }
+
+function %icmp_and_ult_ult(i32, i32) -> i8 {
+block0(v0: i32, v1: i32):
+    v2 = icmp ult v0, v1
+    v3 = icmp ult v0, v1
+    v4 = band v2, v3
+    return v4
+}
+
+; function %icmp_and_ult_ult(i32, i32) -> i8 fast {
+; block0(v0: i32, v1: i32):
+;     v2 = icmp ult v0, v1
+;     return v2
+; }
+
+function %icmp_and_ult_ule(i32, i32) -> i8 {
+block0(v0: i32, v1: i32):
+    v2 = icmp ult v0, v1
+    v3 = icmp ule v0, v1
+    v4 = band v2, v3
+    return v4
+}
+
+; function %icmp_and_ult_ule(i32, i32) -> i8 fast {
+; block0(v0: i32, v1: i32):
+;     v5 = icmp ult v0, v1
+;     v6 -> v5
+;     return v5
+; }
+
+function %icmp_and_ult_ugt(i32, i32) -> i8 {
+block0(v0: i32, v1: i32):
+    v2 = icmp ult v0, v1
+    v3 = icmp ugt v0, v1
+    v4 = band v2, v3
+    return v4
+}
+
+; function %icmp_and_ult_ugt(i32, i32) -> i8 fast {
+; block0(v0: i32, v1: i32):
+;     v5 = iconst.i8 0
+;     return v5  ; v5 = 0
+; }
+
+function %icmp_and_ult_uge(i32, i32) -> i8 {
+block0(v0: i32, v1: i32):
+    v2 = icmp ult v0, v1
+    v3 = icmp uge v0, v1
+    v4 = band v2, v3
+    return v4
+}
+
+; function %icmp_and_ult_uge(i32, i32) -> i8 fast {
+; block0(v0: i32, v1: i32):
+;     v5 = iconst.i8 0
+;     return v5  ; v5 = 0
+; }
+
+function %icmp_and_ult_slt(i32, i32) -> i8 {
+block0(v0: i32, v1: i32):
+    v2 = icmp ult v0, v1
+    v3 = icmp slt v0, v1
+    v4 = band v2, v3
+    return v4
+}
+
+; function %icmp_and_ult_slt(i32, i32) -> i8 fast {
+; block0(v0: i32, v1: i32):
+;     v2 = icmp ult v0, v1
+;     v3 = icmp slt v0, v1
+;     v4 = band v2, v3
+;     return v4
+; }
+
+function %icmp_and_ult_sle(i32, i32) -> i8 {
+block0(v0: i32, v1: i32):
+    v2 = icmp ult v0, v1
+    v3 = icmp sle v0, v1
+    v4 = band v2, v3
+    return v4
+}
+
+; function %icmp_and_ult_sle(i32, i32) -> i8 fast {
+; block0(v0: i32, v1: i32):
+;     v2 = icmp ult v0, v1
+;     v3 = icmp sle v0, v1
+;     v4 = band v2, v3
+;     return v4
+; }
+
+function %icmp_and_ult_sgt(i32, i32) -> i8 {
+block0(v0: i32, v1: i32):
+    v2 = icmp ult v0, v1
+    v3 = icmp sgt v0, v1
+    v4 = band v2, v3
+    return v4
+}
+
+; function %icmp_and_ult_sgt(i32, i32) -> i8 fast {
+; block0(v0: i32, v1: i32):
+;     v2 = icmp ult v0, v1
+;     v3 = icmp sgt v0, v1
+;     v4 = band v2, v3
+;     return v4
+; }
+
+function %icmp_and_ult_sge(i32, i32) -> i8 {
+block0(v0: i32, v1: i32):
+    v2 = icmp ult v0, v1
+    v3 = icmp sge v0, v1
+    v4 = band v2, v3
+    return v4
+}
+
+; function %icmp_and_ult_sge(i32, i32) -> i8 fast {
+; block0(v0: i32, v1: i32):
+;     v2 = icmp ult v0, v1
+;     v3 = icmp sge v0, v1
+;     v4 = band v2, v3
+;     return v4
+; }
+
+function %icmp_and_ule_eq(i32, i32) -> i8 {
+block0(v0: i32, v1: i32):
+    v2 = icmp ule v0, v1
+    v3 = icmp eq v0, v1
+    v4 = band v2, v3
+    return v4
+}
+
+; function %icmp_and_ule_eq(i32, i32) -> i8 fast {
+; block0(v0: i32, v1: i32):
+;     v5 = icmp eq v0, v1
+;     v6 -> v5
+;     return v5
+; }
+
+function %icmp_and_ule_ne(i32, i32) -> i8 {
+block0(v0: i32, v1: i32):
+    v2 = icmp ule v0, v1
+    v3 = icmp ne v0, v1
+    v4 = band v2, v3
+    return v4
+}
+
+; function %icmp_and_ule_ne(i32, i32) -> i8 fast {
+; block0(v0: i32, v1: i32):
+;     v5 = icmp ult v0, v1
+;     v6 -> v5
+;     return v5
+; }
+
+function %icmp_and_ule_ult(i32, i32) -> i8 {
+block0(v0: i32, v1: i32):
+    v2 = icmp ule v0, v1
+    v3 = icmp ult v0, v1
+    v4 = band v2, v3
+    return v4
+}
+
+; function %icmp_and_ule_ult(i32, i32) -> i8 fast {
+; block0(v0: i32, v1: i32):
+;     v5 = icmp ult v0, v1
+;     v6 -> v5
+;     return v5
+; }
+
+function %icmp_and_ule_ule(i32, i32) -> i8 {
+block0(v0: i32, v1: i32):
+    v2 = icmp ule v0, v1
+    v3 = icmp ule v0, v1
+    v4 = band v2, v3
+    return v4
+}
+
+; function %icmp_and_ule_ule(i32, i32) -> i8 fast {
+; block0(v0: i32, v1: i32):
+;     v2 = icmp ule v0, v1
+;     return v2
+; }
+
+function %icmp_and_ule_ugt(i32, i32) -> i8 {
+block0(v0: i32, v1: i32):
+    v2 = icmp ule v0, v1
+    v3 = icmp ugt v0, v1
+    v4 = band v2, v3
+    return v4
+}
+
+; function %icmp_and_ule_ugt(i32, i32) -> i8 fast {
+; block0(v0: i32, v1: i32):
+;     v5 = iconst.i8 0
+;     return v5  ; v5 = 0
+; }
+
+function %icmp_and_ule_uge(i32, i32) -> i8 {
+block0(v0: i32, v1: i32):
+    v2 = icmp ule v0, v1
+    v3 = icmp uge v0, v1
+    v4 = band v2, v3
+    return v4
+}
+
+; function %icmp_and_ule_uge(i32, i32) -> i8 fast {
+; block0(v0: i32, v1: i32):
+;     v5 = icmp eq v0, v1
+;     v6 -> v5
+;     return v5
+; }
+
+function %icmp_and_ule_slt(i32, i32) -> i8 {
+block0(v0: i32, v1: i32):
+    v2 = icmp ule v0, v1
+    v3 = icmp slt v0, v1
+    v4 = band v2, v3
+    return v4
+}
+
+; function %icmp_and_ule_slt(i32, i32) -> i8 fast {
+; block0(v0: i32, v1: i32):
+;     v2 = icmp ule v0, v1
+;     v3 = icmp slt v0, v1
+;     v4 = band v2, v3
+;     return v4
+; }
+
+function %icmp_and_ule_sle(i32, i32) -> i8 {
+block0(v0: i32, v1: i32):
+    v2 = icmp ule v0, v1
+    v3 = icmp sle v0, v1
+    v4 = band v2, v3
+    return v4
+}
+
+; function %icmp_and_ule_sle(i32, i32) -> i8 fast {
+; block0(v0: i32, v1: i32):
+;     v2 = icmp ule v0, v1
+;     v3 = icmp sle v0, v1
+;     v4 = band v2, v3
+;     return v4
+; }
+
+function %icmp_and_ule_sgt(i32, i32) -> i8 {
+block0(v0: i32, v1: i32):
+    v2 = icmp ule v0, v1
+    v3 = icmp sgt v0, v1
+    v4 = band v2, v3
+    return v4
+}
+
+; function %icmp_and_ule_sgt(i32, i32) -> i8 fast {
+; block0(v0: i32, v1: i32):
+;     v2 = icmp ule v0, v1
+;     v3 = icmp sgt v0, v1
+;     v4 = band v2, v3
+;     return v4
+; }
+
+function %icmp_and_ule_sge(i32, i32) -> i8 {
+block0(v0: i32, v1: i32):
+    v2 = icmp ule v0, v1
+    v3 = icmp sge v0, v1
+    v4 = band v2, v3
+    return v4
+}
+
+; function %icmp_and_ule_sge(i32, i32) -> i8 fast {
+; block0(v0: i32, v1: i32):
+;     v2 = icmp ule v0, v1
+;     v3 = icmp sge v0, v1
+;     v4 = band v2, v3
+;     return v4
+; }
+
+function %icmp_and_ugt_eq(i32, i32) -> i8 {
+block0(v0: i32, v1: i32):
+    v2 = icmp ugt v0, v1
+    v3 = icmp eq v0, v1
+    v4 = band v2, v3
+    return v4
+}
+
+; function %icmp_and_ugt_eq(i32, i32) -> i8 fast {
+; block0(v0: i32, v1: i32):
+;     v5 = iconst.i8 0
+;     return v5  ; v5 = 0
+; }
+
+function %icmp_and_ugt_ne(i32, i32) -> i8 {
+block0(v0: i32, v1: i32):
+    v2 = icmp ugt v0, v1
+    v3 = icmp ne v0, v1
+    v4 = band v2, v3
+    return v4
+}
+
+; function %icmp_and_ugt_ne(i32, i32) -> i8 fast {
+; block0(v0: i32, v1: i32):
+;     v5 = icmp ugt v0, v1
+;     v6 -> v5
+;     return v5
+; }
+
+function %icmp_and_ugt_ult(i32, i32) -> i8 {
+block0(v0: i32, v1: i32):
+    v2 = icmp ugt v0, v1
+    v3 = icmp ult v0, v1
+    v4 = band v2, v3
+    return v4
+}
+
+; function %icmp_and_ugt_ult(i32, i32) -> i8 fast {
+; block0(v0: i32, v1: i32):
+;     v5 = iconst.i8 0
+;     return v5  ; v5 = 0
+; }
+
+function %icmp_and_ugt_ule(i32, i32) -> i8 {
+block0(v0: i32, v1: i32):
+    v2 = icmp ugt v0, v1
+    v3 = icmp ule v0, v1
+    v4 = band v2, v3
+    return v4
+}
+
+; function %icmp_and_ugt_ule(i32, i32) -> i8 fast {
+; block0(v0: i32, v1: i32):
+;     v5 = iconst.i8 0
+;     return v5  ; v5 = 0
+; }
+
+function %icmp_and_ugt_ugt(i32, i32) -> i8 {
+block0(v0: i32, v1: i32):
+    v2 = icmp ugt v0, v1
+    v3 = icmp ugt v0, v1
+    v4 = band v2, v3
+    return v4
+}
+
+; function %icmp_and_ugt_ugt(i32, i32) -> i8 fast {
+; block0(v0: i32, v1: i32):
+;     v2 = icmp ugt v0, v1
+;     return v2
+; }
+
+function %icmp_and_ugt_uge(i32, i32) -> i8 {
+block0(v0: i32, v1: i32):
+    v2 = icmp ugt v0, v1
+    v3 = icmp uge v0, v1
+    v4 = band v2, v3
+    return v4
+}
+
+; function %icmp_and_ugt_uge(i32, i32) -> i8 fast {
+; block0(v0: i32, v1: i32):
+;     v5 = icmp ugt v0, v1
+;     v6 -> v5
+;     return v5
+; }
+
+function %icmp_and_ugt_slt(i32, i32) -> i8 {
+block0(v0: i32, v1: i32):
+    v2 = icmp ugt v0, v1
+    v3 = icmp slt v0, v1
+    v4 = band v2, v3
+    return v4
+}
+
+; function %icmp_and_ugt_slt(i32, i32) -> i8 fast {
+; block0(v0: i32, v1: i32):
+;     v2 = icmp ugt v0, v1
+;     v3 = icmp slt v0, v1
+;     v4 = band v2, v3
+;     return v4
+; }
+
+function %icmp_and_ugt_sle(i32, i32) -> i8 {
+block0(v0: i32, v1: i32):
+    v2 = icmp ugt v0, v1
+    v3 = icmp sle v0, v1
+    v4 = band v2, v3
+    return v4
+}
+
+; function %icmp_and_ugt_sle(i32, i32) -> i8 fast {
+; block0(v0: i32, v1: i32):
+;     v2 = icmp ugt v0, v1
+;     v3 = icmp sle v0, v1
+;     v4 = band v2, v3
+;     return v4
+; }
+
+function %icmp_and_ugt_sgt(i32, i32) -> i8 {
+block0(v0: i32, v1: i32):
+    v2 = icmp ugt v0, v1
+    v3 = icmp sgt v0, v1
+    v4 = band v2, v3
+    return v4
+}
+
+; function %icmp_and_ugt_sgt(i32, i32) -> i8 fast {
+; block0(v0: i32, v1: i32):
+;     v2 = icmp ugt v0, v1
+;     v3 = icmp sgt v0, v1
+;     v4 = band v2, v3
+;     return v4
+; }
+
+function %icmp_and_ugt_sge(i32, i32) -> i8 {
+block0(v0: i32, v1: i32):
+    v2 = icmp ugt v0, v1
+    v3 = icmp sge v0, v1
+    v4 = band v2, v3
+    return v4
+}
+
+; function %icmp_and_ugt_sge(i32, i32) -> i8 fast {
+; block0(v0: i32, v1: i32):
+;     v2 = icmp ugt v0, v1
+;     v3 = icmp sge v0, v1
+;     v4 = band v2, v3
+;     return v4
+; }
+
+function %icmp_and_uge_eq(i32, i32) -> i8 {
+block0(v0: i32, v1: i32):
+    v2 = icmp uge v0, v1
+    v3 = icmp eq v0, v1
+    v4 = band v2, v3
+    return v4
+}
+
+; function %icmp_and_uge_eq(i32, i32) -> i8 fast {
+; block0(v0: i32, v1: i32):
+;     v5 = icmp eq v0, v1
+;     v6 -> v5
+;     return v5
+; }
+
+function %icmp_and_uge_ne(i32, i32) -> i8 {
+block0(v0: i32, v1: i32):
+    v2 = icmp uge v0, v1
+    v3 = icmp ne v0, v1
+    v4 = band v2, v3
+    return v4
+}
+
+; function %icmp_and_uge_ne(i32, i32) -> i8 fast {
+; block0(v0: i32, v1: i32):
+;     v5 = icmp ugt v0, v1
+;     v6 -> v5
+;     return v5
+; }
+
+function %icmp_and_uge_ult(i32, i32) -> i8 {
+block0(v0: i32, v1: i32):
+    v2 = icmp uge v0, v1
+    v3 = icmp ult v0, v1
+    v4 = band v2, v3
+    return v4
+}
+
+; function %icmp_and_uge_ult(i32, i32) -> i8 fast {
+; block0(v0: i32, v1: i32):
+;     v5 = iconst.i8 0
+;     return v5  ; v5 = 0
+; }
+
+function %icmp_and_uge_ule(i32, i32) -> i8 {
+block0(v0: i32, v1: i32):
+    v2 = icmp uge v0, v1
+    v3 = icmp ule v0, v1
+    v4 = band v2, v3
+    return v4
+}
+
+; function %icmp_and_uge_ule(i32, i32) -> i8 fast {
+; block0(v0: i32, v1: i32):
+;     v5 = icmp eq v0, v1
+;     v6 -> v5
+;     return v5
+; }
+
+function %icmp_and_uge_ugt(i32, i32) -> i8 {
+block0(v0: i32, v1: i32):
+    v2 = icmp uge v0, v1
+    v3 = icmp ugt v0, v1
+    v4 = band v2, v3
+    return v4
+}
+
+; function %icmp_and_uge_ugt(i32, i32) -> i8 fast {
+; block0(v0: i32, v1: i32):
+;     v5 = icmp ugt v0, v1
+;     v6 -> v5
+;     return v5
+; }
+
+function %icmp_and_uge_uge(i32, i32) -> i8 {
+block0(v0: i32, v1: i32):
+    v2 = icmp uge v0, v1
+    v3 = icmp uge v0, v1
+    v4 = band v2, v3
+    return v4
+}
+
+; function %icmp_and_uge_uge(i32, i32) -> i8 fast {
+; block0(v0: i32, v1: i32):
+;     v2 = icmp uge v0, v1
+;     return v2
+; }
+
+function %icmp_and_uge_slt(i32, i32) -> i8 {
+block0(v0: i32, v1: i32):
+    v2 = icmp uge v0, v1
+    v3 = icmp slt v0, v1
+    v4 = band v2, v3
+    return v4
+}
+
+; function %icmp_and_uge_slt(i32, i32) -> i8 fast {
+; block0(v0: i32, v1: i32):
+;     v2 = icmp uge v0, v1
+;     v3 = icmp slt v0, v1
+;     v4 = band v2, v3
+;     return v4
+; }
+
+function %icmp_and_uge_sle(i32, i32) -> i8 {
+block0(v0: i32, v1: i32):
+    v2 = icmp uge v0, v1
+    v3 = icmp sle v0, v1
+    v4 = band v2, v3
+    return v4
+}
+
+; function %icmp_and_uge_sle(i32, i32) -> i8 fast {
+; block0(v0: i32, v1: i32):
+;     v2 = icmp uge v0, v1
+;     v3 = icmp sle v0, v1
+;     v4 = band v2, v3
+;     return v4
+; }
+
+function %icmp_and_uge_sgt(i32, i32) -> i8 {
+block0(v0: i32, v1: i32):
+    v2 = icmp uge v0, v1
+    v3 = icmp sgt v0, v1
+    v4 = band v2, v3
+    return v4
+}
+
+; function %icmp_and_uge_sgt(i32, i32) -> i8 fast {
+; block0(v0: i32, v1: i32):
+;     v2 = icmp uge v0, v1
+;     v3 = icmp sgt v0, v1
+;     v4 = band v2, v3
+;     return v4
+; }
+
+function %icmp_and_uge_sge(i32, i32) -> i8 {
+block0(v0: i32, v1: i32):
+    v2 = icmp uge v0, v1
+    v3 = icmp sge v0, v1
+    v4 = band v2, v3
+    return v4
+}
+
+; function %icmp_and_uge_sge(i32, i32) -> i8 fast {
+; block0(v0: i32, v1: i32):
+;     v2 = icmp uge v0, v1
+;     v3 = icmp sge v0, v1
+;     v4 = band v2, v3
+;     return v4
+; }
+
+function %icmp_and_slt_eq(i32, i32) -> i8 {
+block0(v0: i32, v1: i32):
+    v2 = icmp slt v0, v1
+    v3 = icmp eq v0, v1
+    v4 = band v2, v3
+    return v4
+}
+
+; function %icmp_and_slt_eq(i32, i32) -> i8 fast {
+; block0(v0: i32, v1: i32):
+;     v5 = iconst.i8 0
+;     return v5  ; v5 = 0
+; }
+
+function %icmp_and_slt_ne(i32, i32) -> i8 {
+block0(v0: i32, v1: i32):
+    v2 = icmp slt v0, v1
+    v3 = icmp ne v0, v1
+    v4 = band v2, v3
+    return v4
+}
+
+; function %icmp_and_slt_ne(i32, i32) -> i8 fast {
+; block0(v0: i32, v1: i32):
+;     v5 = icmp slt v0, v1
+;     v6 -> v5
+;     return v5
+; }
+
+function %icmp_and_slt_ult(i32, i32) -> i8 {
+block0(v0: i32, v1: i32):
+    v2 = icmp slt v0, v1
+    v3 = icmp ult v0, v1
+    v4 = band v2, v3
+    return v4
+}
+
+; function %icmp_and_slt_ult(i32, i32) -> i8 fast {
+; block0(v0: i32, v1: i32):
+;     v2 = icmp slt v0, v1
+;     v3 = icmp ult v0, v1
+;     v4 = band v2, v3
+;     return v4
+; }
+
+function %icmp_and_slt_ule(i32, i32) -> i8 {
+block0(v0: i32, v1: i32):
+    v2 = icmp slt v0, v1
+    v3 = icmp ule v0, v1
+    v4 = band v2, v3
+    return v4
+}
+
+; function %icmp_and_slt_ule(i32, i32) -> i8 fast {
+; block0(v0: i32, v1: i32):
+;     v2 = icmp slt v0, v1
+;     v3 = icmp ule v0, v1
+;     v4 = band v2, v3
+;     return v4
+; }
+
+function %icmp_and_slt_ugt(i32, i32) -> i8 {
+block0(v0: i32, v1: i32):
+    v2 = icmp slt v0, v1
+    v3 = icmp ugt v0, v1
+    v4 = band v2, v3
+    return v4
+}
+
+; function %icmp_and_slt_ugt(i32, i32) -> i8 fast {
+; block0(v0: i32, v1: i32):
+;     v2 = icmp slt v0, v1
+;     v3 = icmp ugt v0, v1
+;     v4 = band v2, v3
+;     return v4
+; }
+
+function %icmp_and_slt_uge(i32, i32) -> i8 {
+block0(v0: i32, v1: i32):
+    v2 = icmp slt v0, v1
+    v3 = icmp uge v0, v1
+    v4 = band v2, v3
+    return v4
+}
+
+; function %icmp_and_slt_uge(i32, i32) -> i8 fast {
+; block0(v0: i32, v1: i32):
+;     v2 = icmp slt v0, v1
+;     v3 = icmp uge v0, v1
+;     v4 = band v2, v3
+;     return v4
+; }
+
+function %icmp_and_slt_slt(i32, i32) -> i8 {
+block0(v0: i32, v1: i32):
+    v2 = icmp slt v0, v1
+    v3 = icmp slt v0, v1
+    v4 = band v2, v3
+    return v4
+}
+
+; function %icmp_and_slt_slt(i32, i32) -> i8 fast {
+; block0(v0: i32, v1: i32):
+;     v2 = icmp slt v0, v1
+;     return v2
+; }
+
+function %icmp_and_slt_sle(i32, i32) -> i8 {
+block0(v0: i32, v1: i32):
+    v2 = icmp slt v0, v1
+    v3 = icmp sle v0, v1
+    v4 = band v2, v3
+    return v4
+}
+
+; function %icmp_and_slt_sle(i32, i32) -> i8 fast {
+; block0(v0: i32, v1: i32):
+;     v5 = icmp slt v0, v1
+;     v6 -> v5
+;     return v5
+; }
+
+function %icmp_and_slt_sgt(i32, i32) -> i8 {
+block0(v0: i32, v1: i32):
+    v2 = icmp slt v0, v1
+    v3 = icmp sgt v0, v1
+    v4 = band v2, v3
+    return v4
+}
+
+; function %icmp_and_slt_sgt(i32, i32) -> i8 fast {
+; block0(v0: i32, v1: i32):
+;     v5 = iconst.i8 0
+;     return v5  ; v5 = 0
+; }
+
+function %icmp_and_slt_sge(i32, i32) -> i8 {
+block0(v0: i32, v1: i32):
+    v2 = icmp slt v0, v1
+    v3 = icmp sge v0, v1
+    v4 = band v2, v3
+    return v4
+}
+
+; function %icmp_and_slt_sge(i32, i32) -> i8 fast {
+; block0(v0: i32, v1: i32):
+;     v5 = iconst.i8 0
+;     return v5  ; v5 = 0
+; }
+
+function %icmp_and_sle_eq(i32, i32) -> i8 {
+block0(v0: i32, v1: i32):
+    v2 = icmp sle v0, v1
+    v3 = icmp eq v0, v1
+    v4 = band v2, v3
+    return v4
+}
+
+; function %icmp_and_sle_eq(i32, i32) -> i8 fast {
+; block0(v0: i32, v1: i32):
+;     v5 = icmp eq v0, v1
+;     v6 -> v5
+;     return v5
+; }
+
+function %icmp_and_sle_ne(i32, i32) -> i8 {
+block0(v0: i32, v1: i32):
+    v2 = icmp sle v0, v1
+    v3 = icmp ne v0, v1
+    v4 = band v2, v3
+    return v4
+}
+
+; function %icmp_and_sle_ne(i32, i32) -> i8 fast {
+; block0(v0: i32, v1: i32):
+;     v5 = icmp slt v0, v1
+;     v6 -> v5
+;     return v5
+; }
+
+function %icmp_and_sle_ult(i32, i32) -> i8 {
+block0(v0: i32, v1: i32):
+    v2 = icmp sle v0, v1
+    v3 = icmp ult v0, v1
+    v4 = band v2, v3
+    return v4
+}
+
+; function %icmp_and_sle_ult(i32, i32) -> i8 fast {
+; block0(v0: i32, v1: i32):
+;     v2 = icmp sle v0, v1
+;     v3 = icmp ult v0, v1
+;     v4 = band v2, v3
+;     return v4
+; }
+
+function %icmp_and_sle_ule(i32, i32) -> i8 {
+block0(v0: i32, v1: i32):
+    v2 = icmp sle v0, v1
+    v3 = icmp ule v0, v1
+    v4 = band v2, v3
+    return v4
+}
+
+; function %icmp_and_sle_ule(i32, i32) -> i8 fast {
+; block0(v0: i32, v1: i32):
+;     v2 = icmp sle v0, v1
+;     v3 = icmp ule v0, v1
+;     v4 = band v2, v3
+;     return v4
+; }
+
+function %icmp_and_sle_ugt(i32, i32) -> i8 {
+block0(v0: i32, v1: i32):
+    v2 = icmp sle v0, v1
+    v3 = icmp ugt v0, v1
+    v4 = band v2, v3
+    return v4
+}
+
+; function %icmp_and_sle_ugt(i32, i32) -> i8 fast {
+; block0(v0: i32, v1: i32):
+;     v2 = icmp sle v0, v1
+;     v3 = icmp ugt v0, v1
+;     v4 = band v2, v3
+;     return v4
+; }
+
+function %icmp_and_sle_uge(i32, i32) -> i8 {
+block0(v0: i32, v1: i32):
+    v2 = icmp sle v0, v1
+    v3 = icmp uge v0, v1
+    v4 = band v2, v3
+    return v4
+}
+
+; function %icmp_and_sle_uge(i32, i32) -> i8 fast {
+; block0(v0: i32, v1: i32):
+;     v2 = icmp sle v0, v1
+;     v3 = icmp uge v0, v1
+;     v4 = band v2, v3
+;     return v4
+; }
+
+function %icmp_and_sle_slt(i32, i32) -> i8 {
+block0(v0: i32, v1: i32):
+    v2 = icmp sle v0, v1
+    v3 = icmp slt v0, v1
+    v4 = band v2, v3
+    return v4
+}
+
+; function %icmp_and_sle_slt(i32, i32) -> i8 fast {
+; block0(v0: i32, v1: i32):
+;     v5 = icmp slt v0, v1
+;     v6 -> v5
+;     return v5
+; }
+
+function %icmp_and_sle_sle(i32, i32) -> i8 {
+block0(v0: i32, v1: i32):
+    v2 = icmp sle v0, v1
+    v3 = icmp sle v0, v1
+    v4 = band v2, v3
+    return v4
+}
+
+; function %icmp_and_sle_sle(i32, i32) -> i8 fast {
+; block0(v0: i32, v1: i32):
+;     v2 = icmp sle v0, v1
+;     return v2
+; }
+
+function %icmp_and_sle_sgt(i32, i32) -> i8 {
+block0(v0: i32, v1: i32):
+    v2 = icmp sle v0, v1
+    v3 = icmp sgt v0, v1
+    v4 = band v2, v3
+    return v4
+}
+
+; function %icmp_and_sle_sgt(i32, i32) -> i8 fast {
+; block0(v0: i32, v1: i32):
+;     v5 = iconst.i8 0
+;     return v5  ; v5 = 0
+; }
+
+function %icmp_and_sle_sge(i32, i32) -> i8 {
+block0(v0: i32, v1: i32):
+    v2 = icmp sle v0, v1
+    v3 = icmp sge v0, v1
+    v4 = band v2, v3
+    return v4
+}
+
+; function %icmp_and_sle_sge(i32, i32) -> i8 fast {
+; block0(v0: i32, v1: i32):
+;     v5 = icmp eq v0, v1
+;     v6 -> v5
+;     return v5
+; }
+
+function %icmp_and_sgt_eq(i32, i32) -> i8 {
+block0(v0: i32, v1: i32):
+    v2 = icmp sgt v0, v1
+    v3 = icmp eq v0, v1
+    v4 = band v2, v3
+    return v4
+}
+
+; function %icmp_and_sgt_eq(i32, i32) -> i8 fast {
+; block0(v0: i32, v1: i32):
+;     v5 = iconst.i8 0
+;     return v5  ; v5 = 0
+; }
+
+function %icmp_and_sgt_ne(i32, i32) -> i8 {
+block0(v0: i32, v1: i32):
+    v2 = icmp sgt v0, v1
+    v3 = icmp ne v0, v1
+    v4 = band v2, v3
+    return v4
+}
+
+; function %icmp_and_sgt_ne(i32, i32) -> i8 fast {
+; block0(v0: i32, v1: i32):
+;     v5 = icmp sgt v0, v1
+;     v6 -> v5
+;     return v5
+; }
+
+function %icmp_and_sgt_ult(i32, i32) -> i8 {
+block0(v0: i32, v1: i32):
+    v2 = icmp sgt v0, v1
+    v3 = icmp ult v0, v1
+    v4 = band v2, v3
+    return v4
+}
+
+; function %icmp_and_sgt_ult(i32, i32) -> i8 fast {
+; block0(v0: i32, v1: i32):
+;     v2 = icmp sgt v0, v1
+;     v3 = icmp ult v0, v1
+;     v4 = band v2, v3
+;     return v4
+; }
+
+function %icmp_and_sgt_ule(i32, i32) -> i8 {
+block0(v0: i32, v1: i32):
+    v2 = icmp sgt v0, v1
+    v3 = icmp ule v0, v1
+    v4 = band v2, v3
+    return v4
+}
+
+; function %icmp_and_sgt_ule(i32, i32) -> i8 fast {
+; block0(v0: i32, v1: i32):
+;     v2 = icmp sgt v0, v1
+;     v3 = icmp ule v0, v1
+;     v4 = band v2, v3
+;     return v4
+; }
+
+function %icmp_and_sgt_ugt(i32, i32) -> i8 {
+block0(v0: i32, v1: i32):
+    v2 = icmp sgt v0, v1
+    v3 = icmp ugt v0, v1
+    v4 = band v2, v3
+    return v4
+}
+
+; function %icmp_and_sgt_ugt(i32, i32) -> i8 fast {
+; block0(v0: i32, v1: i32):
+;     v2 = icmp sgt v0, v1
+;     v3 = icmp ugt v0, v1
+;     v4 = band v2, v3
+;     return v4
+; }
+
+function %icmp_and_sgt_uge(i32, i32) -> i8 {
+block0(v0: i32, v1: i32):
+    v2 = icmp sgt v0, v1
+    v3 = icmp uge v0, v1
+    v4 = band v2, v3
+    return v4
+}
+
+; function %icmp_and_sgt_uge(i32, i32) -> i8 fast {
+; block0(v0: i32, v1: i32):
+;     v2 = icmp sgt v0, v1
+;     v3 = icmp uge v0, v1
+;     v4 = band v2, v3
+;     return v4
+; }
+
+function %icmp_and_sgt_slt(i32, i32) -> i8 {
+block0(v0: i32, v1: i32):
+    v2 = icmp sgt v0, v1
+    v3 = icmp slt v0, v1
+    v4 = band v2, v3
+    return v4
+}
+
+; function %icmp_and_sgt_slt(i32, i32) -> i8 fast {
+; block0(v0: i32, v1: i32):
+;     v5 = iconst.i8 0
+;     return v5  ; v5 = 0
+; }
+
+function %icmp_and_sgt_sle(i32, i32) -> i8 {
+block0(v0: i32, v1: i32):
+    v2 = icmp sgt v0, v1
+    v3 = icmp sle v0, v1
+    v4 = band v2, v3
+    return v4
+}
+
+; function %icmp_and_sgt_sle(i32, i32) -> i8 fast {
+; block0(v0: i32, v1: i32):
+;     v5 = iconst.i8 0
+;     return v5  ; v5 = 0
+; }
+
+function %icmp_and_sgt_sgt(i32, i32) -> i8 {
+block0(v0: i32, v1: i32):
+    v2 = icmp sgt v0, v1
+    v3 = icmp sgt v0, v1
+    v4 = band v2, v3
+    return v4
+}
+
+; function %icmp_and_sgt_sgt(i32, i32) -> i8 fast {
+; block0(v0: i32, v1: i32):
+;     v2 = icmp sgt v0, v1
+;     return v2
+; }
+
+function %icmp_and_sgt_sge(i32, i32) -> i8 {
+block0(v0: i32, v1: i32):
+    v2 = icmp sgt v0, v1
+    v3 = icmp sge v0, v1
+    v4 = band v2, v3
+    return v4
+}
+
+; function %icmp_and_sgt_sge(i32, i32) -> i8 fast {
+; block0(v0: i32, v1: i32):
+;     v5 = icmp sgt v0, v1
+;     v6 -> v5
+;     return v5
+; }
+
+function %icmp_and_sge_eq(i32, i32) -> i8 {
+block0(v0: i32, v1: i32):
+    v2 = icmp sge v0, v1
+    v3 = icmp eq v0, v1
+    v4 = band v2, v3
+    return v4
+}
+
+; function %icmp_and_sge_eq(i32, i32) -> i8 fast {
+; block0(v0: i32, v1: i32):
+;     v5 = icmp eq v0, v1
+;     v6 -> v5
+;     return v5
+; }
+
+function %icmp_and_sge_ne(i32, i32) -> i8 {
+block0(v0: i32, v1: i32):
+    v2 = icmp sge v0, v1
+    v3 = icmp ne v0, v1
+    v4 = band v2, v3
+    return v4
+}
+
+; function %icmp_and_sge_ne(i32, i32) -> i8 fast {
+; block0(v0: i32, v1: i32):
+;     v5 = icmp sgt v0, v1
+;     v6 -> v5
+;     return v5
+; }
+
+function %icmp_and_sge_ult(i32, i32) -> i8 {
+block0(v0: i32, v1: i32):
+    v2 = icmp sge v0, v1
+    v3 = icmp ult v0, v1
+    v4 = band v2, v3
+    return v4
+}
+
+; function %icmp_and_sge_ult(i32, i32) -> i8 fast {
+; block0(v0: i32, v1: i32):
+;     v2 = icmp sge v0, v1
+;     v3 = icmp ult v0, v1
+;     v4 = band v2, v3
+;     return v4
+; }
+
+function %icmp_and_sge_ule(i32, i32) -> i8 {
+block0(v0: i32, v1: i32):
+    v2 = icmp sge v0, v1
+    v3 = icmp ule v0, v1
+    v4 = band v2, v3
+    return v4
+}
+
+; function %icmp_and_sge_ule(i32, i32) -> i8 fast {
+; block0(v0: i32, v1: i32):
+;     v2 = icmp sge v0, v1
+;     v3 = icmp ule v0, v1
+;     v4 = band v2, v3
+;     return v4
+; }
+
+function %icmp_and_sge_ugt(i32, i32) -> i8 {
+block0(v0: i32, v1: i32):
+    v2 = icmp sge v0, v1
+    v3 = icmp ugt v0, v1
+    v4 = band v2, v3
+    return v4
+}
+
+; function %icmp_and_sge_ugt(i32, i32) -> i8 fast {
+; block0(v0: i32, v1: i32):
+;     v2 = icmp sge v0, v1
+;     v3 = icmp ugt v0, v1
+;     v4 = band v2, v3
+;     return v4
+; }
+
+function %icmp_and_sge_uge(i32, i32) -> i8 {
+block0(v0: i32, v1: i32):
+    v2 = icmp sge v0, v1
+    v3 = icmp uge v0, v1
+    v4 = band v2, v3
+    return v4
+}
+
+; function %icmp_and_sge_uge(i32, i32) -> i8 fast {
+; block0(v0: i32, v1: i32):
+;     v2 = icmp sge v0, v1
+;     v3 = icmp uge v0, v1
+;     v4 = band v2, v3
+;     return v4
+; }
+
+function %icmp_and_sge_slt(i32, i32) -> i8 {
+block0(v0: i32, v1: i32):
+    v2 = icmp sge v0, v1
+    v3 = icmp slt v0, v1
+    v4 = band v2, v3
+    return v4
+}
+
+; function %icmp_and_sge_slt(i32, i32) -> i8 fast {
+; block0(v0: i32, v1: i32):
+;     v5 = iconst.i8 0
+;     return v5  ; v5 = 0
+; }
+
+function %icmp_and_sge_sle(i32, i32) -> i8 {
+block0(v0: i32, v1: i32):
+    v2 = icmp sge v0, v1
+    v3 = icmp sle v0, v1
+    v4 = band v2, v3
+    return v4
+}
+
+; function %icmp_and_sge_sle(i32, i32) -> i8 fast {
+; block0(v0: i32, v1: i32):
+;     v5 = icmp eq v0, v1
+;     v6 -> v5
+;     return v5
+; }
+
+function %icmp_and_sge_sgt(i32, i32) -> i8 {
+block0(v0: i32, v1: i32):
+    v2 = icmp sge v0, v1
+    v3 = icmp sgt v0, v1
+    v4 = band v2, v3
+    return v4
+}
+
+; function %icmp_and_sge_sgt(i32, i32) -> i8 fast {
+; block0(v0: i32, v1: i32):
+;     v5 = icmp sgt v0, v1
+;     v6 -> v5
+;     return v5
+; }
+
+function %icmp_and_sge_sge(i32, i32) -> i8 {
+block0(v0: i32, v1: i32):
+    v2 = icmp sge v0, v1
+    v3 = icmp sge v0, v1
+    v4 = band v2, v3
+    return v4
+}
+
+; function %icmp_and_sge_sge(i32, i32) -> i8 fast {
+; block0(v0: i32, v1: i32):
+;     v2 = icmp sge v0, v1
+;     return v2
+; }
+
+function %icmp_or_eq_eq(i32, i32) -> i8 {
+block0(v0: i32, v1: i32):
+    v2 = icmp eq v0, v1
+    v3 = icmp eq v0, v1
+    v4 = bor v2, v3
+    return v4
+}
+
+; function %icmp_or_eq_eq(i32, i32) -> i8 fast {
+; block0(v0: i32, v1: i32):
+;     v2 = icmp eq v0, v1
+;     return v2
+; }
+
+function %icmp_or_eq_ne(i32, i32) -> i8 {
+block0(v0: i32, v1: i32):
+    v2 = icmp eq v0, v1
+    v3 = icmp ne v0, v1
+    v4 = bor v2, v3
+    return v4
+}
+
+; function %icmp_or_eq_ne(i32, i32) -> i8 fast {
+; block0(v0: i32, v1: i32):
+;     v5 = iconst.i8 1
+;     return v5  ; v5 = 1
+; }
+
+function %icmp_or_eq_ult(i32, i32) -> i8 {
+block0(v0: i32, v1: i32):
+    v2 = icmp eq v0, v1
+    v3 = icmp ult v0, v1
+    v4 = bor v2, v3
+    return v4
+}
+
+; function %icmp_or_eq_ult(i32, i32) -> i8 fast {
+; block0(v0: i32, v1: i32):
+;     v5 = icmp ule v0, v1
+;     v6 -> v5
+;     return v5
+; }
+
+function %icmp_or_eq_ule(i32, i32) -> i8 {
+block0(v0: i32, v1: i32):
+    v2 = icmp eq v0, v1
+    v3 = icmp ule v0, v1
+    v4 = bor v2, v3
+    return v4
+}
+
+; function %icmp_or_eq_ule(i32, i32) -> i8 fast {
+; block0(v0: i32, v1: i32):
+;     v5 = icmp ule v0, v1
+;     v6 -> v5
+;     return v5
+; }
+
+function %icmp_or_eq_ugt(i32, i32) -> i8 {
+block0(v0: i32, v1: i32):
+    v2 = icmp eq v0, v1
+    v3 = icmp ugt v0, v1
+    v4 = bor v2, v3
+    return v4
+}
+
+; function %icmp_or_eq_ugt(i32, i32) -> i8 fast {
+; block0(v0: i32, v1: i32):
+;     v5 = icmp uge v0, v1
+;     v6 -> v5
+;     return v5
+; }
+
+function %icmp_or_eq_uge(i32, i32) -> i8 {
+block0(v0: i32, v1: i32):
+    v2 = icmp eq v0, v1
+    v3 = icmp uge v0, v1
+    v4 = bor v2, v3
+    return v4
+}
+
+; function %icmp_or_eq_uge(i32, i32) -> i8 fast {
+; block0(v0: i32, v1: i32):
+;     v5 = icmp uge v0, v1
+;     v6 -> v5
+;     return v5
+; }
+
+function %icmp_or_eq_slt(i32, i32) -> i8 {
+block0(v0: i32, v1: i32):
+    v2 = icmp eq v0, v1
+    v3 = icmp slt v0, v1
+    v4 = bor v2, v3
+    return v4
+}
+
+; function %icmp_or_eq_slt(i32, i32) -> i8 fast {
+; block0(v0: i32, v1: i32):
+;     v5 = icmp sle v0, v1
+;     v6 -> v5
+;     return v5
+; }
+
+function %icmp_or_eq_sle(i32, i32) -> i8 {
+block0(v0: i32, v1: i32):
+    v2 = icmp eq v0, v1
+    v3 = icmp sle v0, v1
+    v4 = bor v2, v3
+    return v4
+}
+
+; function %icmp_or_eq_sle(i32, i32) -> i8 fast {
+; block0(v0: i32, v1: i32):
+;     v5 = icmp sle v0, v1
+;     v6 -> v5
+;     return v5
+; }
+
+function %icmp_or_eq_sgt(i32, i32) -> i8 {
+block0(v0: i32, v1: i32):
+    v2 = icmp eq v0, v1
+    v3 = icmp sgt v0, v1
+    v4 = bor v2, v3
+    return v4
+}
+
+; function %icmp_or_eq_sgt(i32, i32) -> i8 fast {
+; block0(v0: i32, v1: i32):
+;     v5 = icmp sge v0, v1
+;     v6 -> v5
+;     return v5
+; }
+
+function %icmp_or_eq_sge(i32, i32) -> i8 {
+block0(v0: i32, v1: i32):
+    v2 = icmp eq v0, v1
+    v3 = icmp sge v0, v1
+    v4 = bor v2, v3
+    return v4
+}
+
+; function %icmp_or_eq_sge(i32, i32) -> i8 fast {
+; block0(v0: i32, v1: i32):
+;     v5 = icmp sge v0, v1
+;     v6 -> v5
+;     return v5
+; }
+
+function %icmp_or_ne_eq(i32, i32) -> i8 {
+block0(v0: i32, v1: i32):
+    v2 = icmp ne v0, v1
+    v3 = icmp eq v0, v1
+    v4 = bor v2, v3
+    return v4
+}
+
+; function %icmp_or_ne_eq(i32, i32) -> i8 fast {
+; block0(v0: i32, v1: i32):
+;     v5 = iconst.i8 1
+;     return v5  ; v5 = 1
+; }
+
+function %icmp_or_ne_ne(i32, i32) -> i8 {
+block0(v0: i32, v1: i32):
+    v2 = icmp ne v0, v1
+    v3 = icmp ne v0, v1
+    v4 = bor v2, v3
+    return v4
+}
+
+; function %icmp_or_ne_ne(i32, i32) -> i8 fast {
+; block0(v0: i32, v1: i32):
+;     v2 = icmp ne v0, v1
+;     return v2
+; }
+
+function %icmp_or_ne_ult(i32, i32) -> i8 {
+block0(v0: i32, v1: i32):
+    v2 = icmp ne v0, v1
+    v3 = icmp ult v0, v1
+    v4 = bor v2, v3
+    return v4
+}
+
+; function %icmp_or_ne_ult(i32, i32) -> i8 fast {
+; block0(v0: i32, v1: i32):
+;     v5 = icmp ne v0, v1
+;     v6 -> v5
+;     return v5
+; }
+
+function %icmp_or_ne_ule(i32, i32) -> i8 {
+block0(v0: i32, v1: i32):
+    v2 = icmp ne v0, v1
+    v3 = icmp ule v0, v1
+    v4 = bor v2, v3
+    return v4
+}
+
+; function %icmp_or_ne_ule(i32, i32) -> i8 fast {
+; block0(v0: i32, v1: i32):
+;     v5 = iconst.i8 1
+;     return v5  ; v5 = 1
+; }
+
+function %icmp_or_ne_ugt(i32, i32) -> i8 {
+block0(v0: i32, v1: i32):
+    v2 = icmp ne v0, v1
+    v3 = icmp ugt v0, v1
+    v4 = bor v2, v3
+    return v4
+}
+
+; function %icmp_or_ne_ugt(i32, i32) -> i8 fast {
+; block0(v0: i32, v1: i32):
+;     v5 = icmp ne v0, v1
+;     v6 -> v5
+;     return v5
+; }
+
+function %icmp_or_ne_uge(i32, i32) -> i8 {
+block0(v0: i32, v1: i32):
+    v2 = icmp ne v0, v1
+    v3 = icmp uge v0, v1
+    v4 = bor v2, v3
+    return v4
+}
+
+; function %icmp_or_ne_uge(i32, i32) -> i8 fast {
+; block0(v0: i32, v1: i32):
+;     v5 = iconst.i8 1
+;     return v5  ; v5 = 1
+; }
+
+function %icmp_or_ne_slt(i32, i32) -> i8 {
+block0(v0: i32, v1: i32):
+    v2 = icmp ne v0, v1
+    v3 = icmp slt v0, v1
+    v4 = bor v2, v3
+    return v4
+}
+
+; function %icmp_or_ne_slt(i32, i32) -> i8 fast {
+; block0(v0: i32, v1: i32):
+;     v5 = icmp ne v0, v1
+;     v6 -> v5
+;     return v5
+; }
+
+function %icmp_or_ne_sle(i32, i32) -> i8 {
+block0(v0: i32, v1: i32):
+    v2 = icmp ne v0, v1
+    v3 = icmp sle v0, v1
+    v4 = bor v2, v3
+    return v4
+}
+
+; function %icmp_or_ne_sle(i32, i32) -> i8 fast {
+; block0(v0: i32, v1: i32):
+;     v5 = iconst.i8 1
+;     return v5  ; v5 = 1
+; }
+
+function %icmp_or_ne_sgt(i32, i32) -> i8 {
+block0(v0: i32, v1: i32):
+    v2 = icmp ne v0, v1
+    v3 = icmp sgt v0, v1
+    v4 = bor v2, v3
+    return v4
+}
+
+; function %icmp_or_ne_sgt(i32, i32) -> i8 fast {
+; block0(v0: i32, v1: i32):
+;     v5 = icmp ne v0, v1
+;     v6 -> v5
+;     return v5
+; }
+
+function %icmp_or_ne_sge(i32, i32) -> i8 {
+block0(v0: i32, v1: i32):
+    v2 = icmp ne v0, v1
+    v3 = icmp sge v0, v1
+    v4 = bor v2, v3
+    return v4
+}
+
+; function %icmp_or_ne_sge(i32, i32) -> i8 fast {
+; block0(v0: i32, v1: i32):
+;     v5 = iconst.i8 1
+;     return v5  ; v5 = 1
+; }
+
+function %icmp_or_ult_eq(i32, i32) -> i8 {
+block0(v0: i32, v1: i32):
+    v2 = icmp ult v0, v1
+    v3 = icmp eq v0, v1
+    v4 = bor v2, v3
+    return v4
+}
+
+; function %icmp_or_ult_eq(i32, i32) -> i8 fast {
+; block0(v0: i32, v1: i32):
+;     v5 = icmp ule v0, v1
+;     v6 -> v5
+;     return v5
+; }
+
+function %icmp_or_ult_ne(i32, i32) -> i8 {
+block0(v0: i32, v1: i32):
+    v2 = icmp ult v0, v1
+    v3 = icmp ne v0, v1
+    v4 = bor v2, v3
+    return v4
+}
+
+; function %icmp_or_ult_ne(i32, i32) -> i8 fast {
+; block0(v0: i32, v1: i32):
+;     v5 = icmp ne v0, v1
+;     v6 -> v5
+;     return v5
+; }
+
+function %icmp_or_ult_ult(i32, i32) -> i8 {
+block0(v0: i32, v1: i32):
+    v2 = icmp ult v0, v1
+    v3 = icmp ult v0, v1
+    v4 = bor v2, v3
+    return v4
+}
+
+; function %icmp_or_ult_ult(i32, i32) -> i8 fast {
+; block0(v0: i32, v1: i32):
+;     v2 = icmp ult v0, v1
+;     return v2
+; }
+
+function %icmp_or_ult_ule(i32, i32) -> i8 {
+block0(v0: i32, v1: i32):
+    v2 = icmp ult v0, v1
+    v3 = icmp ule v0, v1
+    v4 = bor v2, v3
+    return v4
+}
+
+; function %icmp_or_ult_ule(i32, i32) -> i8 fast {
+; block0(v0: i32, v1: i32):
+;     v5 = icmp ule v0, v1
+;     v6 -> v5
+;     return v5
+; }
+
+function %icmp_or_ult_ugt(i32, i32) -> i8 {
+block0(v0: i32, v1: i32):
+    v2 = icmp ult v0, v1
+    v3 = icmp ugt v0, v1
+    v4 = bor v2, v3
+    return v4
+}
+
+; function %icmp_or_ult_ugt(i32, i32) -> i8 fast {
+; block0(v0: i32, v1: i32):
+;     v5 = icmp ne v0, v1
+;     v6 -> v5
+;     return v5
+; }
+
+function %icmp_or_ult_uge(i32, i32) -> i8 {
+block0(v0: i32, v1: i32):
+    v2 = icmp ult v0, v1
+    v3 = icmp uge v0, v1
+    v4 = bor v2, v3
+    return v4
+}
+
+; function %icmp_or_ult_uge(i32, i32) -> i8 fast {
+; block0(v0: i32, v1: i32):
+;     v5 = iconst.i8 1
+;     return v5  ; v5 = 1
+; }
+
+function %icmp_or_ult_slt(i32, i32) -> i8 {
+block0(v0: i32, v1: i32):
+    v2 = icmp ult v0, v1
+    v3 = icmp slt v0, v1
+    v4 = bor v2, v3
+    return v4
+}
+
+; function %icmp_or_ult_slt(i32, i32) -> i8 fast {
+; block0(v0: i32, v1: i32):
+;     v2 = icmp ult v0, v1
+;     v3 = icmp slt v0, v1
+;     v4 = bor v2, v3
+;     return v4
+; }
+
+function %icmp_or_ult_sle(i32, i32) -> i8 {
+block0(v0: i32, v1: i32):
+    v2 = icmp ult v0, v1
+    v3 = icmp sle v0, v1
+    v4 = bor v2, v3
+    return v4
+}
+
+; function %icmp_or_ult_sle(i32, i32) -> i8 fast {
+; block0(v0: i32, v1: i32):
+;     v2 = icmp ult v0, v1
+;     v3 = icmp sle v0, v1
+;     v4 = bor v2, v3
+;     return v4
+; }
+
+function %icmp_or_ult_sgt(i32, i32) -> i8 {
+block0(v0: i32, v1: i32):
+    v2 = icmp ult v0, v1
+    v3 = icmp sgt v0, v1
+    v4 = bor v2, v3
+    return v4
+}
+
+; function %icmp_or_ult_sgt(i32, i32) -> i8 fast {
+; block0(v0: i32, v1: i32):
+;     v2 = icmp ult v0, v1
+;     v3 = icmp sgt v0, v1
+;     v4 = bor v2, v3
+;     return v4
+; }
+
+function %icmp_or_ult_sge(i32, i32) -> i8 {
+block0(v0: i32, v1: i32):
+    v2 = icmp ult v0, v1
+    v3 = icmp sge v0, v1
+    v4 = bor v2, v3
+    return v4
+}
+
+; function %icmp_or_ult_sge(i32, i32) -> i8 fast {
+; block0(v0: i32, v1: i32):
+;     v2 = icmp ult v0, v1
+;     v3 = icmp sge v0, v1
+;     v4 = bor v2, v3
+;     return v4
+; }
+
+function %icmp_or_ule_eq(i32, i32) -> i8 {
+block0(v0: i32, v1: i32):
+    v2 = icmp ule v0, v1
+    v3 = icmp eq v0, v1
+    v4 = bor v2, v3
+    return v4
+}
+
+; function %icmp_or_ule_eq(i32, i32) -> i8 fast {
+; block0(v0: i32, v1: i32):
+;     v5 = icmp ule v0, v1
+;     v6 -> v5
+;     return v5
+; }
+
+function %icmp_or_ule_ne(i32, i32) -> i8 {
+block0(v0: i32, v1: i32):
+    v2 = icmp ule v0, v1
+    v3 = icmp ne v0, v1
+    v4 = bor v2, v3
+    return v4
+}
+
+; function %icmp_or_ule_ne(i32, i32) -> i8 fast {
+; block0(v0: i32, v1: i32):
+;     v5 = iconst.i8 1
+;     return v5  ; v5 = 1
+; }
+
+function %icmp_or_ule_ult(i32, i32) -> i8 {
+block0(v0: i32, v1: i32):
+    v2 = icmp ule v0, v1
+    v3 = icmp ult v0, v1
+    v4 = bor v2, v3
+    return v4
+}
+
+; function %icmp_or_ule_ult(i32, i32) -> i8 fast {
+; block0(v0: i32, v1: i32):
+;     v5 = icmp ule v0, v1
+;     v6 -> v5
+;     return v5
+; }
+
+function %icmp_or_ule_ule(i32, i32) -> i8 {
+block0(v0: i32, v1: i32):
+    v2 = icmp ule v0, v1
+    v3 = icmp ule v0, v1
+    v4 = bor v2, v3
+    return v4
+}
+
+; function %icmp_or_ule_ule(i32, i32) -> i8 fast {
+; block0(v0: i32, v1: i32):
+;     v2 = icmp ule v0, v1
+;     return v2
+; }
+
+function %icmp_or_ule_ugt(i32, i32) -> i8 {
+block0(v0: i32, v1: i32):
+    v2 = icmp ule v0, v1
+    v3 = icmp ugt v0, v1
+    v4 = bor v2, v3
+    return v4
+}
+
+; function %icmp_or_ule_ugt(i32, i32) -> i8 fast {
+; block0(v0: i32, v1: i32):
+;     v5 = iconst.i8 1
+;     return v5  ; v5 = 1
+; }
+
+function %icmp_or_ule_uge(i32, i32) -> i8 {
+block0(v0: i32, v1: i32):
+    v2 = icmp ule v0, v1
+    v3 = icmp uge v0, v1
+    v4 = bor v2, v3
+    return v4
+}
+
+; function %icmp_or_ule_uge(i32, i32) -> i8 fast {
+; block0(v0: i32, v1: i32):
+;     v5 = iconst.i8 1
+;     return v5  ; v5 = 1
+; }
+
+function %icmp_or_ule_slt(i32, i32) -> i8 {
+block0(v0: i32, v1: i32):
+    v2 = icmp ule v0, v1
+    v3 = icmp slt v0, v1
+    v4 = bor v2, v3
+    return v4
+}
+
+; function %icmp_or_ule_slt(i32, i32) -> i8 fast {
+; block0(v0: i32, v1: i32):
+;     v2 = icmp ule v0, v1
+;     v3 = icmp slt v0, v1
+;     v4 = bor v2, v3
+;     return v4
+; }
+
+function %icmp_or_ule_sle(i32, i32) -> i8 {
+block0(v0: i32, v1: i32):
+    v2 = icmp ule v0, v1
+    v3 = icmp sle v0, v1
+    v4 = bor v2, v3
+    return v4
+}
+
+; function %icmp_or_ule_sle(i32, i32) -> i8 fast {
+; block0(v0: i32, v1: i32):
+;     v2 = icmp ule v0, v1
+;     v3 = icmp sle v0, v1
+;     v4 = bor v2, v3
+;     return v4
+; }
+
+function %icmp_or_ule_sgt(i32, i32) -> i8 {
+block0(v0: i32, v1: i32):
+    v2 = icmp ule v0, v1
+    v3 = icmp sgt v0, v1
+    v4 = bor v2, v3
+    return v4
+}
+
+; function %icmp_or_ule_sgt(i32, i32) -> i8 fast {
+; block0(v0: i32, v1: i32):
+;     v2 = icmp ule v0, v1
+;     v3 = icmp sgt v0, v1
+;     v4 = bor v2, v3
+;     return v4
+; }
+
+function %icmp_or_ule_sge(i32, i32) -> i8 {
+block0(v0: i32, v1: i32):
+    v2 = icmp ule v0, v1
+    v3 = icmp sge v0, v1
+    v4 = bor v2, v3
+    return v4
+}
+
+; function %icmp_or_ule_sge(i32, i32) -> i8 fast {
+; block0(v0: i32, v1: i32):
+;     v2 = icmp ule v0, v1
+;     v3 = icmp sge v0, v1
+;     v4 = bor v2, v3
+;     return v4
+; }
+
+function %icmp_or_ugt_eq(i32, i32) -> i8 {
+block0(v0: i32, v1: i32):
+    v2 = icmp ugt v0, v1
+    v3 = icmp eq v0, v1
+    v4 = bor v2, v3
+    return v4
+}
+
+; function %icmp_or_ugt_eq(i32, i32) -> i8 fast {
+; block0(v0: i32, v1: i32):
+;     v5 = icmp uge v0, v1
+;     v6 -> v5
+;     return v5
+; }
+
+function %icmp_or_ugt_ne(i32, i32) -> i8 {
+block0(v0: i32, v1: i32):
+    v2 = icmp ugt v0, v1
+    v3 = icmp ne v0, v1
+    v4 = bor v2, v3
+    return v4
+}
+
+; function %icmp_or_ugt_ne(i32, i32) -> i8 fast {
+; block0(v0: i32, v1: i32):
+;     v5 = icmp ne v0, v1
+;     v6 -> v5
+;     return v5
+; }
+
+function %icmp_or_ugt_ult(i32, i32) -> i8 {
+block0(v0: i32, v1: i32):
+    v2 = icmp ugt v0, v1
+    v3 = icmp ult v0, v1
+    v4 = bor v2, v3
+    return v4
+}
+
+; function %icmp_or_ugt_ult(i32, i32) -> i8 fast {
+; block0(v0: i32, v1: i32):
+;     v5 = icmp ne v0, v1
+;     v6 -> v5
+;     return v5
+; }
+
+function %icmp_or_ugt_ule(i32, i32) -> i8 {
+block0(v0: i32, v1: i32):
+    v2 = icmp ugt v0, v1
+    v3 = icmp ule v0, v1
+    v4 = bor v2, v3
+    return v4
+}
+
+; function %icmp_or_ugt_ule(i32, i32) -> i8 fast {
+; block0(v0: i32, v1: i32):
+;     v5 = iconst.i8 1
+;     return v5  ; v5 = 1
+; }
+
+function %icmp_or_ugt_ugt(i32, i32) -> i8 {
+block0(v0: i32, v1: i32):
+    v2 = icmp ugt v0, v1
+    v3 = icmp ugt v0, v1
+    v4 = bor v2, v3
+    return v4
+}
+
+; function %icmp_or_ugt_ugt(i32, i32) -> i8 fast {
+; block0(v0: i32, v1: i32):
+;     v2 = icmp ugt v0, v1
+;     return v2
+; }
+
+function %icmp_or_ugt_uge(i32, i32) -> i8 {
+block0(v0: i32, v1: i32):
+    v2 = icmp ugt v0, v1
+    v3 = icmp uge v0, v1
+    v4 = bor v2, v3
+    return v4
+}
+
+; function %icmp_or_ugt_uge(i32, i32) -> i8 fast {
+; block0(v0: i32, v1: i32):
+;     v5 = icmp uge v0, v1
+;     v6 -> v5
+;     return v5
+; }
+
+function %icmp_or_ugt_slt(i32, i32) -> i8 {
+block0(v0: i32, v1: i32):
+    v2 = icmp ugt v0, v1
+    v3 = icmp slt v0, v1
+    v4 = bor v2, v3
+    return v4
+}
+
+; function %icmp_or_ugt_slt(i32, i32) -> i8 fast {
+; block0(v0: i32, v1: i32):
+;     v2 = icmp ugt v0, v1
+;     v3 = icmp slt v0, v1
+;     v4 = bor v2, v3
+;     return v4
+; }
+
+function %icmp_or_ugt_sle(i32, i32) -> i8 {
+block0(v0: i32, v1: i32):
+    v2 = icmp ugt v0, v1
+    v3 = icmp sle v0, v1
+    v4 = bor v2, v3
+    return v4
+}
+
+; function %icmp_or_ugt_sle(i32, i32) -> i8 fast {
+; block0(v0: i32, v1: i32):
+;     v2 = icmp ugt v0, v1
+;     v3 = icmp sle v0, v1
+;     v4 = bor v2, v3
+;     return v4
+; }
+
+function %icmp_or_ugt_sgt(i32, i32) -> i8 {
+block0(v0: i32, v1: i32):
+    v2 = icmp ugt v0, v1
+    v3 = icmp sgt v0, v1
+    v4 = bor v2, v3
+    return v4
+}
+
+; function %icmp_or_ugt_sgt(i32, i32) -> i8 fast {
+; block0(v0: i32, v1: i32):
+;     v2 = icmp ugt v0, v1
+;     v3 = icmp sgt v0, v1
+;     v4 = bor v2, v3
+;     return v4
+; }
+
+function %icmp_or_ugt_sge(i32, i32) -> i8 {
+block0(v0: i32, v1: i32):
+    v2 = icmp ugt v0, v1
+    v3 = icmp sge v0, v1
+    v4 = bor v2, v3
+    return v4
+}
+
+; function %icmp_or_ugt_sge(i32, i32) -> i8 fast {
+; block0(v0: i32, v1: i32):
+;     v2 = icmp ugt v0, v1
+;     v3 = icmp sge v0, v1
+;     v4 = bor v2, v3
+;     return v4
+; }
+
+function %icmp_or_uge_eq(i32, i32) -> i8 {
+block0(v0: i32, v1: i32):
+    v2 = icmp uge v0, v1
+    v3 = icmp eq v0, v1
+    v4 = bor v2, v3
+    return v4
+}
+
+; function %icmp_or_uge_eq(i32, i32) -> i8 fast {
+; block0(v0: i32, v1: i32):
+;     v5 = icmp uge v0, v1
+;     v6 -> v5
+;     return v5
+; }
+
+function %icmp_or_uge_ne(i32, i32) -> i8 {
+block0(v0: i32, v1: i32):
+    v2 = icmp uge v0, v1
+    v3 = icmp ne v0, v1
+    v4 = bor v2, v3
+    return v4
+}
+
+; function %icmp_or_uge_ne(i32, i32) -> i8 fast {
+; block0(v0: i32, v1: i32):
+;     v5 = iconst.i8 1
+;     return v5  ; v5 = 1
+; }
+
+function %icmp_or_uge_ult(i32, i32) -> i8 {
+block0(v0: i32, v1: i32):
+    v2 = icmp uge v0, v1
+    v3 = icmp ult v0, v1
+    v4 = bor v2, v3
+    return v4
+}
+
+; function %icmp_or_uge_ult(i32, i32) -> i8 fast {
+; block0(v0: i32, v1: i32):
+;     v5 = iconst.i8 1
+;     return v5  ; v5 = 1
+; }
+
+function %icmp_or_uge_ule(i32, i32) -> i8 {
+block0(v0: i32, v1: i32):
+    v2 = icmp uge v0, v1
+    v3 = icmp ule v0, v1
+    v4 = bor v2, v3
+    return v4
+}
+
+; function %icmp_or_uge_ule(i32, i32) -> i8 fast {
+; block0(v0: i32, v1: i32):
+;     v5 = iconst.i8 1
+;     return v5  ; v5 = 1
+; }
+
+function %icmp_or_uge_ugt(i32, i32) -> i8 {
+block0(v0: i32, v1: i32):
+    v2 = icmp uge v0, v1
+    v3 = icmp ugt v0, v1
+    v4 = bor v2, v3
+    return v4
+}
+
+; function %icmp_or_uge_ugt(i32, i32) -> i8 fast {
+; block0(v0: i32, v1: i32):
+;     v5 = icmp uge v0, v1
+;     v6 -> v5
+;     return v5
+; }
+
+function %icmp_or_uge_uge(i32, i32) -> i8 {
+block0(v0: i32, v1: i32):
+    v2 = icmp uge v0, v1
+    v3 = icmp uge v0, v1
+    v4 = bor v2, v3
+    return v4
+}
+
+; function %icmp_or_uge_uge(i32, i32) -> i8 fast {
+; block0(v0: i32, v1: i32):
+;     v2 = icmp uge v0, v1
+;     return v2
+; }
+
+function %icmp_or_uge_slt(i32, i32) -> i8 {
+block0(v0: i32, v1: i32):
+    v2 = icmp uge v0, v1
+    v3 = icmp slt v0, v1
+    v4 = bor v2, v3
+    return v4
+}
+
+; function %icmp_or_uge_slt(i32, i32) -> i8 fast {
+; block0(v0: i32, v1: i32):
+;     v2 = icmp uge v0, v1
+;     v3 = icmp slt v0, v1
+;     v4 = bor v2, v3
+;     return v4
+; }
+
+function %icmp_or_uge_sle(i32, i32) -> i8 {
+block0(v0: i32, v1: i32):
+    v2 = icmp uge v0, v1
+    v3 = icmp sle v0, v1
+    v4 = bor v2, v3
+    return v4
+}
+
+; function %icmp_or_uge_sle(i32, i32) -> i8 fast {
+; block0(v0: i32, v1: i32):
+;     v2 = icmp uge v0, v1
+;     v3 = icmp sle v0, v1
+;     v4 = bor v2, v3
+;     return v4
+; }
+
+function %icmp_or_uge_sgt(i32, i32) -> i8 {
+block0(v0: i32, v1: i32):
+    v2 = icmp uge v0, v1
+    v3 = icmp sgt v0, v1
+    v4 = bor v2, v3
+    return v4
+}
+
+; function %icmp_or_uge_sgt(i32, i32) -> i8 fast {
+; block0(v0: i32, v1: i32):
+;     v2 = icmp uge v0, v1
+;     v3 = icmp sgt v0, v1
+;     v4 = bor v2, v3
+;     return v4
+; }
+
+function %icmp_or_uge_sge(i32, i32) -> i8 {
+block0(v0: i32, v1: i32):
+    v2 = icmp uge v0, v1
+    v3 = icmp sge v0, v1
+    v4 = bor v2, v3
+    return v4
+}
+
+; function %icmp_or_uge_sge(i32, i32) -> i8 fast {
+; block0(v0: i32, v1: i32):
+;     v2 = icmp uge v0, v1
+;     v3 = icmp sge v0, v1
+;     v4 = bor v2, v3
+;     return v4
+; }
+
+function %icmp_or_slt_eq(i32, i32) -> i8 {
+block0(v0: i32, v1: i32):
+    v2 = icmp slt v0, v1
+    v3 = icmp eq v0, v1
+    v4 = bor v2, v3
+    return v4
+}
+
+; function %icmp_or_slt_eq(i32, i32) -> i8 fast {
+; block0(v0: i32, v1: i32):
+;     v5 = icmp sle v0, v1
+;     v6 -> v5
+;     return v5
+; }
+
+function %icmp_or_slt_ne(i32, i32) -> i8 {
+block0(v0: i32, v1: i32):
+    v2 = icmp slt v0, v1
+    v3 = icmp ne v0, v1
+    v4 = bor v2, v3
+    return v4
+}
+
+; function %icmp_or_slt_ne(i32, i32) -> i8 fast {
+; block0(v0: i32, v1: i32):
+;     v5 = icmp ne v0, v1
+;     v6 -> v5
+;     return v5
+; }
+
+function %icmp_or_slt_ult(i32, i32) -> i8 {
+block0(v0: i32, v1: i32):
+    v2 = icmp slt v0, v1
+    v3 = icmp ult v0, v1
+    v4 = bor v2, v3
+    return v4
+}
+
+; function %icmp_or_slt_ult(i32, i32) -> i8 fast {
+; block0(v0: i32, v1: i32):
+;     v2 = icmp slt v0, v1
+;     v3 = icmp ult v0, v1
+;     v4 = bor v2, v3
+;     return v4
+; }
+
+function %icmp_or_slt_ule(i32, i32) -> i8 {
+block0(v0: i32, v1: i32):
+    v2 = icmp slt v0, v1
+    v3 = icmp ule v0, v1
+    v4 = bor v2, v3
+    return v4
+}
+
+; function %icmp_or_slt_ule(i32, i32) -> i8 fast {
+; block0(v0: i32, v1: i32):
+;     v2 = icmp slt v0, v1
+;     v3 = icmp ule v0, v1
+;     v4 = bor v2, v3
+;     return v4
+; }
+
+function %icmp_or_slt_ugt(i32, i32) -> i8 {
+block0(v0: i32, v1: i32):
+    v2 = icmp slt v0, v1
+    v3 = icmp ugt v0, v1
+    v4 = bor v2, v3
+    return v4
+}
+
+; function %icmp_or_slt_ugt(i32, i32) -> i8 fast {
+; block0(v0: i32, v1: i32):
+;     v2 = icmp slt v0, v1
+;     v3 = icmp ugt v0, v1
+;     v4 = bor v2, v3
+;     return v4
+; }
+
+function %icmp_or_slt_uge(i32, i32) -> i8 {
+block0(v0: i32, v1: i32):
+    v2 = icmp slt v0, v1
+    v3 = icmp uge v0, v1
+    v4 = bor v2, v3
+    return v4
+}
+
+; function %icmp_or_slt_uge(i32, i32) -> i8 fast {
+; block0(v0: i32, v1: i32):
+;     v2 = icmp slt v0, v1
+;     v3 = icmp uge v0, v1
+;     v4 = bor v2, v3
+;     return v4
+; }
+
+function %icmp_or_slt_slt(i32, i32) -> i8 {
+block0(v0: i32, v1: i32):
+    v2 = icmp slt v0, v1
+    v3 = icmp slt v0, v1
+    v4 = bor v2, v3
+    return v4
+}
+
+; function %icmp_or_slt_slt(i32, i32) -> i8 fast {
+; block0(v0: i32, v1: i32):
+;     v2 = icmp slt v0, v1
+;     return v2
+; }
+
+function %icmp_or_slt_sle(i32, i32) -> i8 {
+block0(v0: i32, v1: i32):
+    v2 = icmp slt v0, v1
+    v3 = icmp sle v0, v1
+    v4 = bor v2, v3
+    return v4
+}
+
+; function %icmp_or_slt_sle(i32, i32) -> i8 fast {
+; block0(v0: i32, v1: i32):
+;     v5 = icmp sle v0, v1
+;     v6 -> v5
+;     return v5
+; }
+
+function %icmp_or_slt_sgt(i32, i32) -> i8 {
+block0(v0: i32, v1: i32):
+    v2 = icmp slt v0, v1
+    v3 = icmp sgt v0, v1
+    v4 = bor v2, v3
+    return v4
+}
+
+; function %icmp_or_slt_sgt(i32, i32) -> i8 fast {
+; block0(v0: i32, v1: i32):
+;     v5 = icmp ne v0, v1
+;     v6 -> v5
+;     return v5
+; }
+
+function %icmp_or_slt_sge(i32, i32) -> i8 {
+block0(v0: i32, v1: i32):
+    v2 = icmp slt v0, v1
+    v3 = icmp sge v0, v1
+    v4 = bor v2, v3
+    return v4
+}
+
+; function %icmp_or_slt_sge(i32, i32) -> i8 fast {
+; block0(v0: i32, v1: i32):
+;     v5 = iconst.i8 1
+;     return v5  ; v5 = 1
+; }
+
+function %icmp_or_sle_eq(i32, i32) -> i8 {
+block0(v0: i32, v1: i32):
+    v2 = icmp sle v0, v1
+    v3 = icmp eq v0, v1
+    v4 = bor v2, v3
+    return v4
+}
+
+; function %icmp_or_sle_eq(i32, i32) -> i8 fast {
+; block0(v0: i32, v1: i32):
+;     v5 = icmp sle v0, v1
+;     v6 -> v5
+;     return v5
+; }
+
+function %icmp_or_sle_ne(i32, i32) -> i8 {
+block0(v0: i32, v1: i32):
+    v2 = icmp sle v0, v1
+    v3 = icmp ne v0, v1
+    v4 = bor v2, v3
+    return v4
+}
+
+; function %icmp_or_sle_ne(i32, i32) -> i8 fast {
+; block0(v0: i32, v1: i32):
+;     v5 = iconst.i8 1
+;     return v5  ; v5 = 1
+; }
+
+function %icmp_or_sle_ult(i32, i32) -> i8 {
+block0(v0: i32, v1: i32):
+    v2 = icmp sle v0, v1
+    v3 = icmp ult v0, v1
+    v4 = bor v2, v3
+    return v4
+}
+
+; function %icmp_or_sle_ult(i32, i32) -> i8 fast {
+; block0(v0: i32, v1: i32):
+;     v2 = icmp sle v0, v1
+;     v3 = icmp ult v0, v1
+;     v4 = bor v2, v3
+;     return v4
+; }
+
+function %icmp_or_sle_ule(i32, i32) -> i8 {
+block0(v0: i32, v1: i32):
+    v2 = icmp sle v0, v1
+    v3 = icmp ule v0, v1
+    v4 = bor v2, v3
+    return v4
+}
+
+; function %icmp_or_sle_ule(i32, i32) -> i8 fast {
+; block0(v0: i32, v1: i32):
+;     v2 = icmp sle v0, v1
+;     v3 = icmp ule v0, v1
+;     v4 = bor v2, v3
+;     return v4
+; }
+
+function %icmp_or_sle_ugt(i32, i32) -> i8 {
+block0(v0: i32, v1: i32):
+    v2 = icmp sle v0, v1
+    v3 = icmp ugt v0, v1
+    v4 = bor v2, v3
+    return v4
+}
+
+; function %icmp_or_sle_ugt(i32, i32) -> i8 fast {
+; block0(v0: i32, v1: i32):
+;     v2 = icmp sle v0, v1
+;     v3 = icmp ugt v0, v1
+;     v4 = bor v2, v3
+;     return v4
+; }
+
+function %icmp_or_sle_uge(i32, i32) -> i8 {
+block0(v0: i32, v1: i32):
+    v2 = icmp sle v0, v1
+    v3 = icmp uge v0, v1
+    v4 = bor v2, v3
+    return v4
+}
+
+; function %icmp_or_sle_uge(i32, i32) -> i8 fast {
+; block0(v0: i32, v1: i32):
+;     v2 = icmp sle v0, v1
+;     v3 = icmp uge v0, v1
+;     v4 = bor v2, v3
+;     return v4
+; }
+
+function %icmp_or_sle_slt(i32, i32) -> i8 {
+block0(v0: i32, v1: i32):
+    v2 = icmp sle v0, v1
+    v3 = icmp slt v0, v1
+    v4 = bor v2, v3
+    return v4
+}
+
+; function %icmp_or_sle_slt(i32, i32) -> i8 fast {
+; block0(v0: i32, v1: i32):
+;     v5 = icmp sle v0, v1
+;     v6 -> v5
+;     return v5
+; }
+
+function %icmp_or_sle_sle(i32, i32) -> i8 {
+block0(v0: i32, v1: i32):
+    v2 = icmp sle v0, v1
+    v3 = icmp sle v0, v1
+    v4 = bor v2, v3
+    return v4
+}
+
+; function %icmp_or_sle_sle(i32, i32) -> i8 fast {
+; block0(v0: i32, v1: i32):
+;     v2 = icmp sle v0, v1
+;     return v2
+; }
+
+function %icmp_or_sle_sgt(i32, i32) -> i8 {
+block0(v0: i32, v1: i32):
+    v2 = icmp sle v0, v1
+    v3 = icmp sgt v0, v1
+    v4 = bor v2, v3
+    return v4
+}
+
+; function %icmp_or_sle_sgt(i32, i32) -> i8 fast {
+; block0(v0: i32, v1: i32):
+;     v5 = iconst.i8 1
+;     return v5  ; v5 = 1
+; }
+
+function %icmp_or_sle_sge(i32, i32) -> i8 {
+block0(v0: i32, v1: i32):
+    v2 = icmp sle v0, v1
+    v3 = icmp sge v0, v1
+    v4 = bor v2, v3
+    return v4
+}
+
+; function %icmp_or_sle_sge(i32, i32) -> i8 fast {
+; block0(v0: i32, v1: i32):
+;     v5 = iconst.i8 1
+;     return v5  ; v5 = 1
+; }
+
+function %icmp_or_sgt_eq(i32, i32) -> i8 {
+block0(v0: i32, v1: i32):
+    v2 = icmp sgt v0, v1
+    v3 = icmp eq v0, v1
+    v4 = bor v2, v3
+    return v4
+}
+
+; function %icmp_or_sgt_eq(i32, i32) -> i8 fast {
+; block0(v0: i32, v1: i32):
+;     v5 = icmp sge v0, v1
+;     v6 -> v5
+;     return v5
+; }
+
+function %icmp_or_sgt_ne(i32, i32) -> i8 {
+block0(v0: i32, v1: i32):
+    v2 = icmp sgt v0, v1
+    v3 = icmp ne v0, v1
+    v4 = bor v2, v3
+    return v4
+}
+
+; function %icmp_or_sgt_ne(i32, i32) -> i8 fast {
+; block0(v0: i32, v1: i32):
+;     v5 = icmp ne v0, v1
+;     v6 -> v5
+;     return v5
+; }
+
+function %icmp_or_sgt_ult(i32, i32) -> i8 {
+block0(v0: i32, v1: i32):
+    v2 = icmp sgt v0, v1
+    v3 = icmp ult v0, v1
+    v4 = bor v2, v3
+    return v4
+}
+
+; function %icmp_or_sgt_ult(i32, i32) -> i8 fast {
+; block0(v0: i32, v1: i32):
+;     v2 = icmp sgt v0, v1
+;     v3 = icmp ult v0, v1
+;     v4 = bor v2, v3
+;     return v4
+; }
+
+function %icmp_or_sgt_ule(i32, i32) -> i8 {
+block0(v0: i32, v1: i32):
+    v2 = icmp sgt v0, v1
+    v3 = icmp ule v0, v1
+    v4 = bor v2, v3
+    return v4
+}
+
+; function %icmp_or_sgt_ule(i32, i32) -> i8 fast {
+; block0(v0: i32, v1: i32):
+;     v2 = icmp sgt v0, v1
+;     v3 = icmp ule v0, v1
+;     v4 = bor v2, v3
+;     return v4
+; }
+
+function %icmp_or_sgt_ugt(i32, i32) -> i8 {
+block0(v0: i32, v1: i32):
+    v2 = icmp sgt v0, v1
+    v3 = icmp ugt v0, v1
+    v4 = bor v2, v3
+    return v4
+}
+
+; function %icmp_or_sgt_ugt(i32, i32) -> i8 fast {
+; block0(v0: i32, v1: i32):
+;     v2 = icmp sgt v0, v1
+;     v3 = icmp ugt v0, v1
+;     v4 = bor v2, v3
+;     return v4
+; }
+
+function %icmp_or_sgt_uge(i32, i32) -> i8 {
+block0(v0: i32, v1: i32):
+    v2 = icmp sgt v0, v1
+    v3 = icmp uge v0, v1
+    v4 = bor v2, v3
+    return v4
+}
+
+; function %icmp_or_sgt_uge(i32, i32) -> i8 fast {
+; block0(v0: i32, v1: i32):
+;     v2 = icmp sgt v0, v1
+;     v3 = icmp uge v0, v1
+;     v4 = bor v2, v3
+;     return v4
+; }
+
+function %icmp_or_sgt_slt(i32, i32) -> i8 {
+block0(v0: i32, v1: i32):
+    v2 = icmp sgt v0, v1
+    v3 = icmp slt v0, v1
+    v4 = bor v2, v3
+    return v4
+}
+
+; function %icmp_or_sgt_slt(i32, i32) -> i8 fast {
+; block0(v0: i32, v1: i32):
+;     v5 = icmp ne v0, v1
+;     v6 -> v5
+;     return v5
+; }
+
+function %icmp_or_sgt_sle(i32, i32) -> i8 {
+block0(v0: i32, v1: i32):
+    v2 = icmp sgt v0, v1
+    v3 = icmp sle v0, v1
+    v4 = bor v2, v3
+    return v4
+}
+
+; function %icmp_or_sgt_sle(i32, i32) -> i8 fast {
+; block0(v0: i32, v1: i32):
+;     v5 = iconst.i8 1
+;     return v5  ; v5 = 1
+; }
+
+function %icmp_or_sgt_sgt(i32, i32) -> i8 {
+block0(v0: i32, v1: i32):
+    v2 = icmp sgt v0, v1
+    v3 = icmp sgt v0, v1
+    v4 = bor v2, v3
+    return v4
+}
+
+; function %icmp_or_sgt_sgt(i32, i32) -> i8 fast {
+; block0(v0: i32, v1: i32):
+;     v2 = icmp sgt v0, v1
+;     return v2
+; }
+
+function %icmp_or_sgt_sge(i32, i32) -> i8 {
+block0(v0: i32, v1: i32):
+    v2 = icmp sgt v0, v1
+    v3 = icmp sge v0, v1
+    v4 = bor v2, v3
+    return v4
+}
+
+; function %icmp_or_sgt_sge(i32, i32) -> i8 fast {
+; block0(v0: i32, v1: i32):
+;     v5 = icmp sge v0, v1
+;     v6 -> v5
+;     return v5
+; }
+
+function %icmp_or_sge_eq(i32, i32) -> i8 {
+block0(v0: i32, v1: i32):
+    v2 = icmp sge v0, v1
+    v3 = icmp eq v0, v1
+    v4 = bor v2, v3
+    return v4
+}
+
+; function %icmp_or_sge_eq(i32, i32) -> i8 fast {
+; block0(v0: i32, v1: i32):
+;     v5 = icmp sge v0, v1
+;     v6 -> v5
+;     return v5
+; }
+
+function %icmp_or_sge_ne(i32, i32) -> i8 {
+block0(v0: i32, v1: i32):
+    v2 = icmp sge v0, v1
+    v3 = icmp ne v0, v1
+    v4 = bor v2, v3
+    return v4
+}
+
+; function %icmp_or_sge_ne(i32, i32) -> i8 fast {
+; block0(v0: i32, v1: i32):
+;     v5 = iconst.i8 1
+;     return v5  ; v5 = 1
+; }
+
+function %icmp_or_sge_ult(i32, i32) -> i8 {
+block0(v0: i32, v1: i32):
+    v2 = icmp sge v0, v1
+    v3 = icmp ult v0, v1
+    v4 = bor v2, v3
+    return v4
+}
+
+; function %icmp_or_sge_ult(i32, i32) -> i8 fast {
+; block0(v0: i32, v1: i32):
+;     v2 = icmp sge v0, v1
+;     v3 = icmp ult v0, v1
+;     v4 = bor v2, v3
+;     return v4
+; }
+
+function %icmp_or_sge_ule(i32, i32) -> i8 {
+block0(v0: i32, v1: i32):
+    v2 = icmp sge v0, v1
+    v3 = icmp ule v0, v1
+    v4 = bor v2, v3
+    return v4
+}
+
+; function %icmp_or_sge_ule(i32, i32) -> i8 fast {
+; block0(v0: i32, v1: i32):
+;     v2 = icmp sge v0, v1
+;     v3 = icmp ule v0, v1
+;     v4 = bor v2, v3
+;     return v4
+; }
+
+function %icmp_or_sge_ugt(i32, i32) -> i8 {
+block0(v0: i32, v1: i32):
+    v2 = icmp sge v0, v1
+    v3 = icmp ugt v0, v1
+    v4 = bor v2, v3
+    return v4
+}
+
+; function %icmp_or_sge_ugt(i32, i32) -> i8 fast {
+; block0(v0: i32, v1: i32):
+;     v2 = icmp sge v0, v1
+;     v3 = icmp ugt v0, v1
+;     v4 = bor v2, v3
+;     return v4
+; }
+
+function %icmp_or_sge_uge(i32, i32) -> i8 {
+block0(v0: i32, v1: i32):
+    v2 = icmp sge v0, v1
+    v3 = icmp uge v0, v1
+    v4 = bor v2, v3
+    return v4
+}
+
+; function %icmp_or_sge_uge(i32, i32) -> i8 fast {
+; block0(v0: i32, v1: i32):
+;     v2 = icmp sge v0, v1
+;     v3 = icmp uge v0, v1
+;     v4 = bor v2, v3
+;     return v4
+; }
+
+function %icmp_or_sge_slt(i32, i32) -> i8 {
+block0(v0: i32, v1: i32):
+    v2 = icmp sge v0, v1
+    v3 = icmp slt v0, v1
+    v4 = bor v2, v3
+    return v4
+}
+
+; function %icmp_or_sge_slt(i32, i32) -> i8 fast {
+; block0(v0: i32, v1: i32):
+;     v5 = iconst.i8 1
+;     return v5  ; v5 = 1
+; }
+
+function %icmp_or_sge_sle(i32, i32) -> i8 {
+block0(v0: i32, v1: i32):
+    v2 = icmp sge v0, v1
+    v3 = icmp sle v0, v1
+    v4 = bor v2, v3
+    return v4
+}
+
+; function %icmp_or_sge_sle(i32, i32) -> i8 fast {
+; block0(v0: i32, v1: i32):
+;     v5 = iconst.i8 1
+;     return v5  ; v5 = 1
+; }
+
+function %icmp_or_sge_sgt(i32, i32) -> i8 {
+block0(v0: i32, v1: i32):
+    v2 = icmp sge v0, v1
+    v3 = icmp sgt v0, v1
+    v4 = bor v2, v3
+    return v4
+}
+
+; function %icmp_or_sge_sgt(i32, i32) -> i8 fast {
+; block0(v0: i32, v1: i32):
+;     v5 = icmp sge v0, v1
+;     v6 -> v5
+;     return v5
+; }
+
+function %icmp_or_sge_sge(i32, i32) -> i8 {
+block0(v0: i32, v1: i32):
+    v2 = icmp sge v0, v1
+    v3 = icmp sge v0, v1
+    v4 = bor v2, v3
+    return v4
+}
+
+; function %icmp_or_sge_sge(i32, i32) -> i8 fast {
+; block0(v0: i32, v1: i32):
+;     v2 = icmp sge v0, v1
+;     return v2
+; }
+
diff --git a/cranelift/filetests/filetests/egraph/make-icmp-tests.sh b/cranelift/filetests/filetests/egraph/make-icmp-tests.sh
new file mode 100755
index 000000000..79b021781
--- /dev/null
+++ b/cranelift/filetests/filetests/egraph/make-icmp-tests.sh
@@ -0,0 +1,38 @@
+#!/usr/bin/env bash
+
+set -e
+cd $(dirname "$0")
+out=icmp.clif
+CCS="eq ne ult ule ugt uge slt sle sgt sge"
+
+function main {
+    cat << EOF > $out
+test optimize precise-output
+set opt_level=speed
+set use_egraphs=true
+target x86_64
+
+;; !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+;; !!! GENERATED BY 'make-icmp-tests.sh' DO NOT EDIT !!!
+;; !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+;; run with the 'CRANELIFT_TEST_BLESS=1' env var set to update this file
+
+EOF
+    for op in "and" "or"; do
+        for cc1 in $CCS; do
+            for cc2 in $CCS; do
+                cat << EOF >> $out
+function %icmp_${op}_${cc1}_${cc2}(i32, i32) -> i8 {
+block0(v0: i32, v1: i32):
+    v2 = icmp ${cc1} v0, v1
+    v3 = icmp ${cc2} v0, v1
+    v4 = b${op} v2, v3
+    return v4
+}
+EOF
+            done
+        done
+    done
+}
+
+main
diff --git a/cranelift/filetests/filetests/isa/aarch64/tls-macho.clif b/cranelift/filetests/filetests/isa/aarch64/tls-macho.clif
new file mode 100644
index 000000000..4158860d0
--- /dev/null
+++ b/cranelift/filetests/filetests/isa/aarch64/tls-macho.clif
@@ -0,0 +1,58 @@
+test compile precise-output
+set tls_model=macho
+target aarch64
+
+function u0:0(i32) -> i32, i64 {
+gv0 = symbol colocated tls u1:0
+
+block0(v0: i32):
+    v1 = global_value.i64 gv0
+    return v0, v1
+}
+
+; VCode:
+;   stp fp, lr, [sp, #-16]!
+;   mov fp, sp
+;   str x24, [sp, #-16]!
+;   stp d14, d15, [sp, #-16]!
+;   stp d12, d13, [sp, #-16]!
+;   stp d10, d11, [sp, #-16]!
+;   stp d8, d9, [sp, #-16]!
+; block0:
+;   mov x24, x0
+;   macho_tls_get_addr x0, userextname0
+;   mov x1, x0
+;   mov x0, x24
+;   ldp d8, d9, [sp], #16
+;   ldp d10, d11, [sp], #16
+;   ldp d12, d13, [sp], #16
+;   ldp d14, d15, [sp], #16
+;   ldr x24, [sp], #16
+;   ldp fp, lr, [sp], #16
+;   ret
+; 
+; Disassembled:
+; block0: ; offset 0x0
+;   stp x29, x30, [sp, #-0x10]!
+;   mov x29, sp
+;   str x24, [sp, #-0x10]!
+;   stp d14, d15, [sp, #-0x10]!
+;   stp d12, d13, [sp, #-0x10]!
+;   stp d10, d11, [sp, #-0x10]!
+;   stp d8, d9, [sp, #-0x10]!
+; block1: ; offset 0x1c
+;   mov x24, x0
+;   adrp x0, #0 ; reloc_external MachOAarch64TlsAdrPage21 u1:0 0
+;   ldr x0, [x0] ; reloc_external MachOAarch64TlsAdrPageOff12 u1:0 0
+;   ldr x1, [x0]
+;   blr x1
+;   mov x1, x0
+;   mov x0, x24
+;   ldp d8, d9, [sp], #0x10
+;   ldp d10, d11, [sp], #0x10
+;   ldp d12, d13, [sp], #0x10
+;   ldp d14, d15, [sp], #0x10
+;   ldr x24, [sp], #0x10
+;   ldp x29, x30, [sp], #0x10
+;   ret
+
diff --git a/cranelift/filetests/filetests/isa/riscv64/arithmetic-extends.clif b/cranelift/filetests/filetests/isa/riscv64/arithmetic-extends.clif
new file mode 100644
index 000000000..53466d9d0
--- /dev/null
+++ b/cranelift/filetests/filetests/isa/riscv64/arithmetic-extends.clif
@@ -0,0 +1,179 @@
+test compile precise-output
+set unwind_info=false
+target riscv64
+
+function %sext_add_i32(i32, i32) -> i64 {
+block0(v0: i32, v1: i32):
+    v2 = iadd.i32 v0, v1
+    v3 = sextend.i64 v2
+    return v3
+}
+
+; VCode:
+; block0:
+;   addw a0,a0,a1
+;   ret
+; 
+; Disassembled:
+; block0: ; offset 0x0
+;   addw a0, a0, a1
+;   ret
+
+function %sext_sub_i32(i32, i32) -> i64 {
+block0(v0: i32, v1: i32):
+    v2 = isub.i32 v0, v1
+    v3 = sextend.i64 v2
+    return v3
+}
+
+; VCode:
+; block0:
+;   subw a0,a0,a1
+;   ret
+; 
+; Disassembled:
+; block0: ; offset 0x0
+;   subw a0, a0, a1
+;   ret
+
+function %sext_ishl_i32(i32, i32) -> i64 {
+block0(v0: i32, v1: i32):
+    v2 = ishl.i32 v0, v1
+    v3 = sextend.i64 v2
+    return v3
+}
+
+; VCode:
+; block0:
+;   sllw a0,a0,a1
+;   ret
+; 
+; Disassembled:
+; block0: ; offset 0x0
+;   sllw a0, a0, a1
+;   ret
+
+function %sext_ushr_i32(i32, i32) -> i64 {
+block0(v0: i32, v1: i32):
+    v2 = ushr.i32 v0, v1
+    v3 = sextend.i64 v2
+    return v3
+}
+
+; VCode:
+; block0:
+;   srlw a0,a0,a1
+;   ret
+; 
+; Disassembled:
+; block0: ; offset 0x0
+;   srlw a0, a0, a1
+;   ret
+
+function %sext_sshr_i32(i32, i32) -> i64 {
+block0(v0: i32, v1: i32):
+    v2 = sshr.i32 v0, v1
+    v3 = sextend.i64 v2
+    return v3
+}
+
+; VCode:
+; block0:
+;   sraw a0,a0,a1
+;   ret
+; 
+; Disassembled:
+; block0: ; offset 0x0
+;   sraw a0, a0, a1
+;   ret
+
+function %sext_add_const_i32(i32) -> i64 {
+block0(v0: i32):
+    v1 = iconst.i32 -1
+    v2 = iadd.i32 v0, v1
+    v3 = sextend.i64 v2
+    return v3
+}
+
+; VCode:
+; block0:
+;   addiw a0,a0,-1
+;   ret
+; 
+; Disassembled:
+; block0: ; offset 0x0
+;   addiw a0, a0, -1
+;   ret
+
+function %sext_ishl_const_i32(i32) -> i64 {
+block0(v0: i32):
+    v1 = iconst.i32 31
+    v2 = ishl.i32 v0, v1
+    v3 = sextend.i64 v2
+    return v3
+}
+
+; VCode:
+; block0:
+;   slliw a0,a0,31
+;   ret
+; 
+; Disassembled:
+; block0: ; offset 0x0
+;   slliw a0, a0, 0x1f
+;   ret
+
+function %sext_ushr_const_i32(i32) -> i64 {
+block0(v0: i32):
+    v1 = iconst.i32 31
+    v2 = ushr.i32 v0, v1
+    v3 = sextend.i64 v2
+    return v3
+}
+
+; VCode:
+; block0:
+;   srliw a0,a0,31
+;   ret
+; 
+; Disassembled:
+; block0: ; offset 0x0
+;   srliw a0, a0, 0x1f
+;   ret
+
+function %sext_sshr_const_i32(i32) -> i64 {
+block0(v0: i32):
+    v1 = iconst.i32 31
+    v2 = sshr.i32 v0, v1
+    v3 = sextend.i64 v2
+    return v3
+}
+
+; VCode:
+; block0:
+;   sraiw a0,a0,31
+;   ret
+; 
+; Disassembled:
+; block0: ; offset 0x0
+;   sraiw a0, a0, 0x1f
+;   ret
+
+
+function %sext_sshr_i32_i128(i32, i128) -> i64 {
+block0(v0: i32, v1: i128):
+    v2 = sshr.i32 v0, v1
+    v3 = sextend.i64 v2
+    return v3
+}
+
+; VCode:
+; block0:
+;   sraw a0,a0,a1
+;   ret
+; 
+; Disassembled:
+; block0: ; offset 0x0
+;   sraw a0, a0, a1
+;   ret
+
diff --git a/cranelift/filetests/filetests/isa/riscv64/arithmetic-zba.clif b/cranelift/filetests/filetests/isa/riscv64/arithmetic-zba.clif
new file mode 100644
index 000000000..2354a9e54
--- /dev/null
+++ b/cranelift/filetests/filetests/isa/riscv64/arithmetic-zba.clif
@@ -0,0 +1,190 @@
+test compile precise-output
+set unwind_info=false
+target riscv64 has_zba
+
+
+function %add_uw_i32(i64, i32) -> i64 {
+block0(v0: i64, v1: i32):
+    v2 = uextend.i64 v1
+    v3 = iadd.i64 v0, v2
+    return v3
+}
+
+; VCode:
+; block0:
+;   add.uw a0,a1,a0
+;   ret
+; 
+; Disassembled:
+; block0: ; offset 0x0
+;   .byte 0x3b, 0x85, 0xa5, 0x08
+;   ret
+
+function %sh1add(i64, i64) -> i64 {
+block0(v0: i64, v1: i64):
+    v2 = iconst.i64 1
+    v3 = ishl v1, v2
+    v4 = iadd.i64 v0, v3
+    return v4
+}
+
+; VCode:
+; block0:
+;   sh1add a0,a1,a0
+;   ret
+; 
+; Disassembled:
+; block0: ; offset 0x0
+;   .byte 0x33, 0xa5, 0xa5, 0x20
+;   ret
+
+function %sh1add_uw(i64, i32) -> i64 {
+block0(v0: i64, v1: i32):
+    v2 = uextend.i64 v1
+    v3 = iconst.i64 1
+    v4 = ishl v2, v3
+    v5 = iadd.i64 v0, v4
+    return v5
+}
+
+; VCode:
+; block0:
+;   sh1add.uw a0,a1,a0
+;   ret
+; 
+; Disassembled:
+; block0: ; offset 0x0
+;   .byte 0x3b, 0xa5, 0xa5, 0x20
+;   ret
+
+function %sh2add(i64, i64) -> i64 {
+block0(v0: i64, v1: i64):
+    v2 = iconst.i64 2
+    v3 = ishl v1, v2
+    v4 = iadd.i64 v0, v3
+    return v4
+}
+
+; VCode:
+; block0:
+;   sh2add a0,a1,a0
+;   ret
+; 
+; Disassembled:
+; block0: ; offset 0x0
+;   .byte 0x33, 0xc5, 0xa5, 0x20
+;   ret
+
+function %sh2add_uw(i64, i32) -> i64 {
+block0(v0: i64, v1: i32):
+    v2 = uextend.i64 v1
+    v3 = iconst.i64 2
+    v4 = ishl v2, v3
+    v5 = iadd.i64 v0, v4
+    return v5
+}
+
+; VCode:
+; block0:
+;   sh2add.uw a0,a1,a0
+;   ret
+; 
+; Disassembled:
+; block0: ; offset 0x0
+;   .byte 0x3b, 0xc5, 0xa5, 0x20
+;   ret
+
+function %sh3add(i64, i64) -> i64 {
+block0(v0: i64, v1: i64):
+    v2 = iconst.i64 3
+    v3 = ishl v1, v2
+    v4 = iadd.i64 v0, v3
+    return v4
+}
+
+; VCode:
+; block0:
+;   sh3add a0,a1,a0
+;   ret
+; 
+; Disassembled:
+; block0: ; offset 0x0
+;   .byte 0x33, 0xe5, 0xa5, 0x20
+;   ret
+
+function %sh3add_uw(i64, i32) -> i64 {
+block0(v0: i64, v1: i32):
+    v2 = uextend.i64 v1
+    v3 = iconst.i64 3
+    v4 = ishl v2, v3
+    v5 = iadd.i64 v0, v4
+    return v5
+}
+
+; VCode:
+; block0:
+;   sh3add.uw a0,a1,a0
+;   ret
+; 
+; Disassembled:
+; block0: ; offset 0x0
+;   .byte 0x3b, 0xe5, 0xa5, 0x20
+;   ret
+
+;; Same as %sh1add but with the operands reversed
+function %sh1add_r(i64, i64) -> i64 {
+block0(v0: i64, v1: i64):
+    v2 = iconst.i64 1
+    v3 = ishl v1, v2
+    v4 = iadd.i64 v3, v0
+    return v4
+}
+
+; VCode:
+; block0:
+;   sh1add a0,a1,a0
+;   ret
+; 
+; Disassembled:
+; block0: ; offset 0x0
+;   .byte 0x33, 0xa5, 0xa5, 0x20
+;   ret
+
+;; Same as %sh1add but with an uextended const
+function %sh1add_uextend(i64, i64) -> i64 {
+block0(v0: i64, v1: i64):
+    v2 = iconst.i32 1
+    v3 = uextend.i64 v2
+    v4 = ishl v1, v3
+    v5 = iadd.i64 v0, v4
+    return v5
+}
+
+; VCode:
+; block0:
+;   sh1add a0,a1,a0
+;   ret
+; 
+; Disassembled:
+; block0: ; offset 0x0
+;   .byte 0x33, 0xa5, 0xa5, 0x20
+;   ret
+
+function %slli_uw(i32) -> i64 {
+block0(v0: i32):
+    v1 = uextend.i64 v0
+    v2 = iconst.i64 5
+    v3 = ishl v1, v2
+    return v3
+}
+
+; VCode:
+; block0:
+;   slli.uw a0,a0,5
+;   ret
+; 
+; Disassembled:
+; block0: ; offset 0x0
+;   .byte 0x1b, 0x15, 0x55, 0x08
+;   ret
+
diff --git a/cranelift/filetests/filetests/isa/riscv64/arithmetic.clif b/cranelift/filetests/filetests/isa/riscv64/arithmetic.clif
index aec33f722..791c51a8f 100644
--- a/cranelift/filetests/filetests/isa/riscv64/arithmetic.clif
+++ b/cranelift/filetests/filetests/isa/riscv64/arithmetic.clif
@@ -716,13 +716,13 @@ block0(v0: i32, v1: i32, v2: i32):
 ; VCode:
 ; block0:
 ;   mulw a2,a1,a2
-;   addw a0,a2,a0
+;   add a0,a2,a0
 ;   ret
 ; 
 ; Disassembled:
 ; block0: ; offset 0x0
 ;   mulw a2, a1, a2
-;   addw a0, a2, a0
+;   add a0, a2, a0
 ;   ret
 
 function %msub_i32(i32, i32, i32) -> i32 {
diff --git a/cranelift/filetests/filetests/isa/riscv64/br_table.clif b/cranelift/filetests/filetests/isa/riscv64/br_table.clif
index 027dc257b..9fa81fc24 100644
--- a/cranelift/filetests/filetests/isa/riscv64/br_table.clif
+++ b/cranelift/filetests/filetests/isa/riscv64/br_table.clif
@@ -47,7 +47,7 @@ block5(v5: i32):
 ;   li a2,4
 ;   j label7
 ; block7:
-;   addw a0,a0,a2
+;   add a0,a0,a2
 ;   ret
 ; 
 ; Disassembled:
@@ -84,6 +84,6 @@ block5(v5: i32):
 ; block5: ; offset 0x64
 ;   addi a2, zero, 4
 ; block6: ; offset 0x68
-;   addw a0, a0, a2
+;   add a0, a0, a2
 ;   ret
 
diff --git a/cranelift/filetests/filetests/isa/riscv64/extend-zba.clif b/cranelift/filetests/filetests/isa/riscv64/extend-zba.clif
new file mode 100644
index 000000000..4221043a6
--- /dev/null
+++ b/cranelift/filetests/filetests/isa/riscv64/extend-zba.clif
@@ -0,0 +1,20 @@
+test compile precise-output
+set unwind_info=false
+target riscv64 has_zba=true
+
+function %uextend32_64(i32) -> i64 {
+block0(v0: i32):
+    v1 = uextend.i64 v0
+    return v1
+}
+
+; VCode:
+; block0:
+;   zext.w a0,a0
+;   ret
+; 
+; Disassembled:
+; block0: ; offset 0x0
+;   .byte 0x3b, 0x05, 0x05, 0x08
+;   ret
+
diff --git a/cranelift/filetests/filetests/isa/riscv64/narrow-arithmetic.clif b/cranelift/filetests/filetests/isa/riscv64/narrow-arithmetic.clif
index eb7c8878a..3fec76273 100644
--- a/cranelift/filetests/filetests/isa/riscv64/narrow-arithmetic.clif
+++ b/cranelift/filetests/filetests/isa/riscv64/narrow-arithmetic.clif
@@ -10,12 +10,12 @@ block0(v0: i8, v1: i8):
 
 ; VCode:
 ; block0:
-;   addw a0,a0,a1
+;   add a0,a0,a1
 ;   ret
 ; 
 ; Disassembled:
 ; block0: ; offset 0x0
-;   addw a0, a0, a1
+;   add a0, a0, a1
 ;   ret
 
 function %add16(i16, i16) -> i16 {
@@ -26,12 +26,12 @@ block0(v0: i16, v1: i16):
 
 ; VCode:
 ; block0:
-;   addw a0,a0,a1
+;   add a0,a0,a1
 ;   ret
 ; 
 ; Disassembled:
 ; block0: ; offset 0x0
-;   addw a0, a0, a1
+;   add a0, a0, a1
 ;   ret
 
 function %add32(i32, i32) -> i32 {
@@ -42,12 +42,12 @@ block0(v0: i32, v1: i32):
 
 ; VCode:
 ; block0:
-;   addw a0,a0,a1
+;   add a0,a0,a1
 ;   ret
 ; 
 ; Disassembled:
 ; block0: ; offset 0x0
-;   addw a0, a0, a1
+;   add a0, a0, a1
 ;   ret
 
 function %add32_8(i32, i8) -> i32 {
@@ -61,14 +61,14 @@ block0(v0: i32, v1: i8):
 ; block0:
 ;   slli a1,a1,56
 ;   srai a3,a1,56
-;   addw a0,a0,a3
+;   add a0,a0,a3
 ;   ret
 ; 
 ; Disassembled:
 ; block0: ; offset 0x0
 ;   slli a1, a1, 0x38
 ;   srai a3, a1, 0x38
-;   addw a0, a0, a3
+;   add a0, a0, a3
 ;   ret
 
 function %add64_32(i64, i32) -> i64 {
diff --git a/cranelift/filetests/filetests/isa/s390x/call.clif b/cranelift/filetests/filetests/isa/s390x/call.clif
index 88044bd38..8db535d46 100644
--- a/cranelift/filetests/filetests/isa/s390x/call.clif
+++ b/cranelift/filetests/filetests/isa/s390x/call.clif
@@ -382,7 +382,7 @@ block0:
 ; block0:
 ;   lghi %r2, 0
 ;   brasl %r14, %g
-;   trap
+;   .word 0x0000 # trap=user0
 ; 
 ; Disassembled:
 ; block0: ; offset 0x0
diff --git a/cranelift/filetests/filetests/isa/s390x/floating-point-arch13.clif b/cranelift/filetests/filetests/isa/s390x/floating-point-arch13.clif
index b111bf062..29f7648fe 100644
--- a/cranelift/filetests/filetests/isa/s390x/floating-point-arch13.clif
+++ b/cranelift/filetests/filetests/isa/s390x/floating-point-arch13.clif
@@ -10,13 +10,13 @@ block0(v0: f32):
 ; VCode:
 ; block0:
 ;   cebr %f0, %f0
-;   jno 6 ; trap
+;   jgo .+2 # trap=bad_toint
 ;   bras %r1, 8 ; data.f32 256 ; le %f4, 0(%r1)
 ;   cebr %f0, %f4
-;   jnhe 6 ; trap
+;   jghe .+2 # trap=int_ovf
 ;   bras %r1, 8 ; data.f32 -1 ; vlef %v16, 0(%r1), 0
 ;   wfcsb %f0, %v16
-;   jnle 6 ; trap
+;   jgle .+2 # trap=int_ovf
 ;   wclfeb %v20, %f0, 0, 5
 ;   vlgvf %r2, %v20, 0
 ;   br %r14
@@ -24,20 +24,17 @@ block0(v0: f32):
 ; Disassembled:
 ; block0: ; offset 0x0
 ;   cebr %f0, %f0
-;   jno 0xa
-;   .byte 0x00, 0x00 ; trap: bad_toint
+;   jgo 6 ; trap: bad_toint
 ;   bras %r1, 0x12
 ;   ic %r8, 0
 ;   le %f4, 0(%r1)
 ;   cebr %f0, %f4
-;   jnhe 0x20
-;   .byte 0x00, 0x00 ; trap: int_ovf
+;   jghe 0x1c ; trap: int_ovf
 ;   bras %r1, 0x28
 ;   icm %r8, 0, 0
 ;   vlef %v16, 0(%r1), 0
 ;   wfcsb %f0, %v16
-;   jnle 0x3a
-;   .byte 0x00, 0x00 ; trap: int_ovf
+;   jgle 0x36 ; trap: int_ovf
 ;   vclgd %v20, %v0, 2, 8, 5
 ;   vlgvf %r2, %v20, 0
 ;   br %r14
@@ -51,13 +48,13 @@ block0(v0: f32):
 ; VCode:
 ; block0:
 ;   cebr %f0, %f0
-;   jno 6 ; trap
+;   jgo .+2 # trap=bad_toint
 ;   bras %r1, 8 ; data.f32 128 ; le %f4, 0(%r1)
 ;   cebr %f0, %f4
-;   jnhe 6 ; trap
+;   jghe .+2 # trap=int_ovf
 ;   bras %r1, 8 ; data.f32 -129 ; vlef %v16, 0(%r1), 0
 ;   wfcsb %f0, %v16
-;   jnle 6 ; trap
+;   jgle .+2 # trap=int_ovf
 ;   wcfeb %v20, %f0, 0, 5
 ;   vlgvf %r2, %v20, 0
 ;   br %r14
@@ -65,21 +62,18 @@ block0(v0: f32):
 ; Disassembled:
 ; block0: ; offset 0x0
 ;   cebr %f0, %f0
-;   jno 0xa
-;   .byte 0x00, 0x00 ; trap: bad_toint
+;   jgo 6 ; trap: bad_toint
 ;   bras %r1, 0x12
 ;   ic %r0, 0
 ;   le %f4, 0(%r1)
 ;   cebr %f0, %f4
-;   jnhe 0x20
-;   .byte 0x00, 0x00 ; trap: int_ovf
+;   jghe 0x1c ; trap: int_ovf
 ;   bras %r1, 0x28
 ;   .byte 0xc3, 0x01
 ;   .byte 0x00, 0x00
 ;   vlef %v16, 0(%r1), 0
 ;   wfcsb %f0, %v16
-;   jnle 0x3a
-;   .byte 0x00, 0x00 ; trap: int_ovf
+;   jgle 0x36 ; trap: int_ovf
 ;   vcgd %v20, %v0, 2, 8, 5
 ;   vlgvf %r2, %v20, 0
 ;   br %r14
@@ -93,13 +87,13 @@ block0(v0: f32):
 ; VCode:
 ; block0:
 ;   cebr %f0, %f0
-;   jno 6 ; trap
+;   jgo .+2 # trap=bad_toint
 ;   bras %r1, 8 ; data.f32 65536 ; le %f4, 0(%r1)
 ;   cebr %f0, %f4
-;   jnhe 6 ; trap
+;   jghe .+2 # trap=int_ovf
 ;   bras %r1, 8 ; data.f32 -1 ; vlef %v16, 0(%r1), 0
 ;   wfcsb %f0, %v16
-;   jnle 6 ; trap
+;   jgle .+2 # trap=int_ovf
 ;   wclfeb %v20, %f0, 0, 5
 ;   vlgvf %r2, %v20, 0
 ;   br %r14
@@ -107,20 +101,17 @@ block0(v0: f32):
 ; Disassembled:
 ; block0: ; offset 0x0
 ;   cebr %f0, %f0
-;   jno 0xa
-;   .byte 0x00, 0x00 ; trap: bad_toint
+;   jgo 6 ; trap: bad_toint
 ;   bras %r1, 0x12
 ;   be 0
 ;   le %f4, 0(%r1)
 ;   cebr %f0, %f4
-;   jnhe 0x20
-;   .byte 0x00, 0x00 ; trap: int_ovf
+;   jghe 0x1c ; trap: int_ovf
 ;   bras %r1, 0x28
 ;   icm %r8, 0, 0
 ;   vlef %v16, 0(%r1), 0
 ;   wfcsb %f0, %v16
-;   jnle 0x3a
-;   .byte 0x00, 0x00 ; trap: int_ovf
+;   jgle 0x36 ; trap: int_ovf
 ;   vclgd %v20, %v0, 2, 8, 5
 ;   vlgvf %r2, %v20, 0
 ;   br %r14
@@ -134,13 +125,13 @@ block0(v0: f32):
 ; VCode:
 ; block0:
 ;   cebr %f0, %f0
-;   jno 6 ; trap
+;   jgo .+2 # trap=bad_toint
 ;   bras %r1, 8 ; data.f32 32768 ; le %f4, 0(%r1)
 ;   cebr %f0, %f4
-;   jnhe 6 ; trap
+;   jghe .+2 # trap=int_ovf
 ;   bras %r1, 8 ; data.f32 -32769 ; vlef %v16, 0(%r1), 0
 ;   wfcsb %f0, %v16
-;   jnle 6 ; trap
+;   jgle .+2 # trap=int_ovf
 ;   wcfeb %v20, %f0, 0, 5
 ;   vlgvf %r2, %v20, 0
 ;   br %r14
@@ -148,21 +139,18 @@ block0(v0: f32):
 ; Disassembled:
 ; block0: ; offset 0x0
 ;   cebr %f0, %f0
-;   jno 0xa
-;   .byte 0x00, 0x00 ; trap: bad_toint
+;   jgo 6 ; trap: bad_toint
 ;   bras %r1, 0x12
 ;   bc 0, 0
 ;   le %f4, 0(%r1)
 ;   cebr %f0, %f4
-;   jnhe 0x20
-;   .byte 0x00, 0x00 ; trap: int_ovf
+;   jghe 0x1c ; trap: int_ovf
 ;   bras %r1, 0x28
 ;   bpp 0, -0x31dc, 0x100
 ;   lpr %r0, %r0
 ;   .byte 0x08, 0x03
 ;   wfcsb %f0, %v16
-;   jnle 0x3a
-;   .byte 0x00, 0x00 ; trap: int_ovf
+;   jgle 0x36 ; trap: int_ovf
 ;   vcgd %v20, %v0, 2, 8, 5
 ;   vlgvf %r2, %v20, 0
 ;   br %r14
@@ -176,13 +164,13 @@ block0(v0: f32):
 ; VCode:
 ; block0:
 ;   cebr %f0, %f0
-;   jno 6 ; trap
+;   jgo .+2 # trap=bad_toint
 ;   bras %r1, 8 ; data.f32 4294967300 ; le %f4, 0(%r1)
 ;   cebr %f0, %f4
-;   jnhe 6 ; trap
+;   jghe .+2 # trap=int_ovf
 ;   bras %r1, 8 ; data.f32 -1 ; vlef %v16, 0(%r1), 0
 ;   wfcsb %f0, %v16
-;   jnle 6 ; trap
+;   jgle .+2 # trap=int_ovf
 ;   wclfeb %v20, %f0, 0, 5
 ;   vlgvf %r2, %v20, 0
 ;   br %r14
@@ -190,20 +178,17 @@ block0(v0: f32):
 ; Disassembled:
 ; block0: ; offset 0x0
 ;   cebr %f0, %f0
-;   jno 0xa
-;   .byte 0x00, 0x00 ; trap: bad_toint
+;   jgo 6 ; trap: bad_toint
 ;   bras %r1, 0x12
 ;   cvb %r8, 0
 ;   le %f4, 0(%r1)
 ;   cebr %f0, %f4
-;   jnhe 0x20
-;   .byte 0x00, 0x00 ; trap: int_ovf
+;   jghe 0x1c ; trap: int_ovf
 ;   bras %r1, 0x28
 ;   icm %r8, 0, 0
 ;   vlef %v16, 0(%r1), 0
 ;   wfcsb %f0, %v16
-;   jnle 0x3a
-;   .byte 0x00, 0x00 ; trap: int_ovf
+;   jgle 0x36 ; trap: int_ovf
 ;   vclgd %v20, %v0, 2, 8, 5
 ;   vlgvf %r2, %v20, 0
 ;   br %r14
@@ -217,13 +202,13 @@ block0(v0: f32):
 ; VCode:
 ; block0:
 ;   cebr %f0, %f0
-;   jno 6 ; trap
+;   jgo .+2 # trap=bad_toint
 ;   bras %r1, 8 ; data.f32 2147483600 ; le %f4, 0(%r1)
 ;   cebr %f0, %f4
-;   jnhe 6 ; trap
+;   jghe .+2 # trap=int_ovf
 ;   bras %r1, 8 ; data.f32 -2147484000 ; vlef %v16, 0(%r1), 0
 ;   wfcsb %f0, %v16
-;   jnle 6 ; trap
+;   jgle .+2 # trap=int_ovf
 ;   wcfeb %v20, %f0, 0, 5
 ;   vlgvf %r2, %v20, 0
 ;   br %r14
@@ -231,21 +216,18 @@ block0(v0: f32):
 ; Disassembled:
 ; block0: ; offset 0x0
 ;   cebr %f0, %f0
-;   jno 0xa
-;   .byte 0x00, 0x00 ; trap: bad_toint
+;   jgo 6 ; trap: bad_toint
 ;   bras %r1, 0x12
 ;   cvb %r0, 0
 ;   le %f4, 0(%r1)
 ;   cebr %f0, %f4
-;   jnhe 0x20
-;   .byte 0x00, 0x00 ; trap: int_ovf
+;   jghe 0x1c ; trap: int_ovf
 ;   bras %r1, 0x28
 ;   .byte 0xcf, 0x00
 ;   .byte 0x00, 0x01
 ;   vlef %v16, 0(%r1), 0
 ;   wfcsb %f0, %v16
-;   jnle 0x3a
-;   .byte 0x00, 0x00 ; trap: int_ovf
+;   jgle 0x36 ; trap: int_ovf
 ;   vcgd %v20, %v0, 2, 8, 5
 ;   vlgvf %r2, %v20, 0
 ;   br %r14
@@ -259,13 +241,13 @@ block0(v0: f32):
 ; VCode:
 ; block0:
 ;   cebr %f0, %f0
-;   jno 6 ; trap
+;   jgo .+2 # trap=bad_toint
 ;   bras %r1, 8 ; data.f32 18446744000000000000 ; le %f4, 0(%r1)
 ;   cebr %f0, %f4
-;   jnhe 6 ; trap
+;   jghe .+2 # trap=int_ovf
 ;   bras %r1, 8 ; data.f32 -1 ; vlef %v16, 0(%r1), 0
 ;   wfcsb %f0, %v16
-;   jnle 6 ; trap
+;   jgle .+2 # trap=int_ovf
 ;   wldeb %v20, %f0
 ;   wclgdb %v22, %v20, 0, 5
 ;   vlgvg %r2, %v22, 0
@@ -274,20 +256,17 @@ block0(v0: f32):
 ; Disassembled:
 ; block0: ; offset 0x0
 ;   cebr %f0, %f0
-;   jno 0xa
-;   .byte 0x00, 0x00 ; trap: bad_toint
+;   jgo 6 ; trap: bad_toint
 ;   bras %r1, 0x12
 ;   sl %r8, 0
 ;   le %f4, 0(%r1)
 ;   cebr %f0, %f4
-;   jnhe 0x20
-;   .byte 0x00, 0x00 ; trap: int_ovf
+;   jghe 0x1c ; trap: int_ovf
 ;   bras %r1, 0x28
 ;   icm %r8, 0, 0
 ;   vlef %v16, 0(%r1), 0
 ;   wfcsb %f0, %v16
-;   jnle 0x3a
-;   .byte 0x00, 0x00 ; trap: int_ovf
+;   jgle 0x36 ; trap: int_ovf
 ;   wldeb %v20, %f0
 ;   wclgdb %v22, %v20, 0, 5
 ;   vlgvg %r2, %v22, 0
@@ -302,13 +281,13 @@ block0(v0: f32):
 ; VCode:
 ; block0:
 ;   cebr %f0, %f0
-;   jno 6 ; trap
+;   jgo .+2 # trap=bad_toint
 ;   bras %r1, 8 ; data.f32 9223372000000000000 ; le %f4, 0(%r1)
 ;   cebr %f0, %f4
-;   jnhe 6 ; trap
+;   jghe .+2 # trap=int_ovf
 ;   bras %r1, 8 ; data.f32 -9223373000000000000 ; vlef %v16, 0(%r1), 0
 ;   wfcsb %f0, %v16
-;   jnle 6 ; trap
+;   jgle .+2 # trap=int_ovf
 ;   wldeb %v20, %f0
 ;   wcgdb %v22, %v20, 0, 5
 ;   vlgvg %r2, %v22, 0
@@ -317,21 +296,18 @@ block0(v0: f32):
 ; Disassembled:
 ; block0: ; offset 0x0
 ;   cebr %f0, %f0
-;   jno 0xa
-;   .byte 0x00, 0x00 ; trap: bad_toint
+;   jgo 6 ; trap: bad_toint
 ;   bras %r1, 0x12
 ;   sl %r0, 0
 ;   le %f4, 0(%r1)
 ;   cebr %f0, %f4
-;   jnhe 0x20
-;   .byte 0x00, 0x00 ; trap: int_ovf
+;   jghe 0x1c ; trap: int_ovf
 ;   bras %r1, 0x28
 ;   edmk 1(1), 0x700(%r14)
 ;   lpr %r0, %r0
 ;   .byte 0x08, 0x03
 ;   wfcsb %f0, %v16
-;   jnle 0x3a
-;   .byte 0x00, 0x00 ; trap: int_ovf
+;   jgle 0x36 ; trap: int_ovf
 ;   wldeb %v20, %f0
 ;   wcgdb %v22, %v20, 0, 5
 ;   vlgvg %r2, %v22, 0
@@ -346,13 +322,13 @@ block0(v0: f64):
 ; VCode:
 ; block0:
 ;   cdbr %f0, %f0
-;   jno 6 ; trap
+;   jgo .+2 # trap=bad_toint
 ;   bras %r1, 12 ; data.f64 256 ; ld %f4, 0(%r1)
 ;   cdbr %f0, %f4
-;   jnhe 6 ; trap
+;   jghe .+2 # trap=int_ovf
 ;   bras %r1, 12 ; data.f64 -1 ; vleg %v16, 0(%r1), 0
 ;   wfcdb %f0, %v16
-;   jnle 6 ; trap
+;   jgle .+2 # trap=int_ovf
 ;   wclgdb %v20, %f0, 0, 5
 ;   vlgvg %r2, %v20, 0
 ;   br %r14
@@ -360,24 +336,21 @@ block0(v0: f64):
 ; Disassembled:
 ; block0: ; offset 0x0
 ;   cdbr %f0, %f0
-;   jno 0xa
-;   .byte 0x00, 0x00 ; trap: bad_toint
+;   jgo 6 ; trap: bad_toint
 ;   bras %r1, 0x16
 ;   sth %r7, 0
 ;   .byte 0x00, 0x00
 ;   .byte 0x00, 0x00
 ;   ld %f4, 0(%r1)
 ;   cdbr %f0, %f4
-;   jnhe 0x24
-;   .byte 0x00, 0x00 ; trap: int_ovf
+;   jghe 0x20 ; trap: int_ovf
 ;   bras %r1, 0x30
 ;   icm %r15, 0, 0
 ;   .byte 0x00, 0x00
 ;   .byte 0x00, 0x00
 ;   vleg %v16, 0(%r1), 0
 ;   wfcdb %f0, %v16
-;   jnle 0x42
-;   .byte 0x00, 0x00 ; trap: int_ovf
+;   jgle 0x3e ; trap: int_ovf
 ;   wclgdb %v20, %f0, 0, 5
 ;   vlgvg %r2, %v20, 0
 ;   br %r14
@@ -391,13 +364,13 @@ block0(v0: f64):
 ; VCode:
 ; block0:
 ;   cdbr %f0, %f0
-;   jno 6 ; trap
+;   jgo .+2 # trap=bad_toint
 ;   bras %r1, 12 ; data.f64 128 ; ld %f4, 0(%r1)
 ;   cdbr %f0, %f4
-;   jnhe 6 ; trap
+;   jghe .+2 # trap=int_ovf
 ;   bras %r1, 12 ; data.f64 -129 ; vleg %v16, 0(%r1), 0
 ;   wfcdb %f0, %v16
-;   jnle 6 ; trap
+;   jgle .+2 # trap=int_ovf
 ;   wcgdb %v20, %f0, 0, 5
 ;   vlgvg %r2, %v20, 0
 ;   br %r14
@@ -405,23 +378,20 @@ block0(v0: f64):
 ; Disassembled:
 ; block0: ; offset 0x0
 ;   cdbr %f0, %f0
-;   jno 0xa
-;   .byte 0x00, 0x00 ; trap: bad_toint
+;   jgo 6 ; trap: bad_toint
 ;   bras %r1, 0x16
 ;   sth %r6, 0
 ;   .byte 0x00, 0x00
 ;   .byte 0x00, 0x00
 ;   ld %f4, 0(%r1)
 ;   cdbr %f0, %f4
-;   jnhe 0x24
-;   .byte 0x00, 0x00 ; trap: int_ovf
+;   jghe 0x20 ; trap: int_ovf
 ;   bras %r1, 0x30
 ;   larl %r6, 0x40000028
 ;   .byte 0x00, 0x00
 ;   vleg %v16, 0(%r1), 0
 ;   wfcdb %f0, %v16
-;   jnle 0x42
-;   .byte 0x00, 0x00 ; trap: int_ovf
+;   jgle 0x3e ; trap: int_ovf
 ;   wcgdb %v20, %f0, 0, 5
 ;   vlgvg %r2, %v20, 0
 ;   br %r14
@@ -435,13 +405,13 @@ block0(v0: f64):
 ; VCode:
 ; block0:
 ;   cdbr %f0, %f0
-;   jno 6 ; trap
+;   jgo .+2 # trap=bad_toint
 ;   bras %r1, 12 ; data.f64 65536 ; ld %f4, 0(%r1)
 ;   cdbr %f0, %f4
-;   jnhe 6 ; trap
+;   jghe .+2 # trap=int_ovf
 ;   bras %r1, 12 ; data.f64 -1 ; vleg %v16, 0(%r1), 0
 ;   wfcdb %f0, %v16
-;   jnle 6 ; trap
+;   jgle .+2 # trap=int_ovf
 ;   wclgdb %v20, %f0, 0, 5
 ;   vlgvg %r2, %v20, 0
 ;   br %r14
@@ -449,24 +419,21 @@ block0(v0: f64):
 ; Disassembled:
 ; block0: ; offset 0x0
 ;   cdbr %f0, %f0
-;   jno 0xa
-;   .byte 0x00, 0x00 ; trap: bad_toint
+;   jgo 6 ; trap: bad_toint
 ;   bras %r1, 0x16
 ;   sth %r15, 0
 ;   .byte 0x00, 0x00
 ;   .byte 0x00, 0x00
 ;   ld %f4, 0(%r1)
 ;   cdbr %f0, %f4
-;   jnhe 0x24
-;   .byte 0x00, 0x00 ; trap: int_ovf
+;   jghe 0x20 ; trap: int_ovf
 ;   bras %r1, 0x30
 ;   icm %r15, 0, 0
 ;   .byte 0x00, 0x00
 ;   .byte 0x00, 0x00
 ;   vleg %v16, 0(%r1), 0
 ;   wfcdb %f0, %v16
-;   jnle 0x42
-;   .byte 0x00, 0x00 ; trap: int_ovf
+;   jgle 0x3e ; trap: int_ovf
 ;   wclgdb %v20, %f0, 0, 5
 ;   vlgvg %r2, %v20, 0
 ;   br %r14
@@ -480,13 +447,13 @@ block0(v0: f64):
 ; VCode:
 ; block0:
 ;   cdbr %f0, %f0
-;   jno 6 ; trap
+;   jgo .+2 # trap=bad_toint
 ;   bras %r1, 12 ; data.f64 32768 ; ld %f4, 0(%r1)
 ;   cdbr %f0, %f4
-;   jnhe 6 ; trap
+;   jghe .+2 # trap=int_ovf
 ;   bras %r1, 12 ; data.f64 -32769 ; vleg %v16, 0(%r1), 0
 ;   wfcdb %f0, %v16
-;   jnle 6 ; trap
+;   jgle .+2 # trap=int_ovf
 ;   wcgdb %v20, %f0, 0, 5
 ;   vlgvg %r2, %v20, 0
 ;   br %r14
@@ -494,23 +461,20 @@ block0(v0: f64):
 ; Disassembled:
 ; block0: ; offset 0x0
 ;   cdbr %f0, %f0
-;   jno 0xa
-;   .byte 0x00, 0x00 ; trap: bad_toint
+;   jgo 6 ; trap: bad_toint
 ;   bras %r1, 0x16
 ;   sth %r14, 0
 ;   .byte 0x00, 0x00
 ;   .byte 0x00, 0x00
 ;   ld %f4, 0(%r1)
 ;   cdbr %f0, %f4
-;   jnhe 0x24
-;   .byte 0x00, 0x00 ; trap: int_ovf
+;   jghe 0x20 ; trap: int_ovf
 ;   bras %r1, 0x30
 ;   larl %r14, 0x400028
 ;   .byte 0x00, 0x00
 ;   vleg %v16, 0(%r1), 0
 ;   wfcdb %f0, %v16
-;   jnle 0x42
-;   .byte 0x00, 0x00 ; trap: int_ovf
+;   jgle 0x3e ; trap: int_ovf
 ;   wcgdb %v20, %f0, 0, 5
 ;   vlgvg %r2, %v20, 0
 ;   br %r14
@@ -524,13 +488,13 @@ block0(v0: f64):
 ; VCode:
 ; block0:
 ;   cdbr %f0, %f0
-;   jno 6 ; trap
+;   jgo .+2 # trap=bad_toint
 ;   bras %r1, 12 ; data.f64 4294967296 ; ld %f4, 0(%r1)
 ;   cdbr %f0, %f4
-;   jnhe 6 ; trap
+;   jghe .+2 # trap=int_ovf
 ;   bras %r1, 12 ; data.f64 -1 ; vleg %v16, 0(%r1), 0
 ;   wfcdb %f0, %v16
-;   jnle 6 ; trap
+;   jgle .+2 # trap=int_ovf
 ;   wclgdb %v20, %f0, 0, 5
 ;   vlgvg %r2, %v20, 0
 ;   br %r14
@@ -538,24 +502,21 @@ block0(v0: f64):
 ; Disassembled:
 ; block0: ; offset 0x0
 ;   cdbr %f0, %f0
-;   jno 0xa
-;   .byte 0x00, 0x00 ; trap: bad_toint
+;   jgo 6 ; trap: bad_toint
 ;   bras %r1, 0x16
 ;   la %r15, 0
 ;   .byte 0x00, 0x00
 ;   .byte 0x00, 0x00
 ;   ld %f4, 0(%r1)
 ;   cdbr %f0, %f4
-;   jnhe 0x24
-;   .byte 0x00, 0x00 ; trap: int_ovf
+;   jghe 0x20 ; trap: int_ovf
 ;   bras %r1, 0x30
 ;   icm %r15, 0, 0
 ;   .byte 0x00, 0x00
 ;   .byte 0x00, 0x00
 ;   vleg %v16, 0(%r1), 0
 ;   wfcdb %f0, %v16
-;   jnle 0x42
-;   .byte 0x00, 0x00 ; trap: int_ovf
+;   jgle 0x3e ; trap: int_ovf
 ;   wclgdb %v20, %f0, 0, 5
 ;   vlgvg %r2, %v20, 0
 ;   br %r14
@@ -569,13 +530,13 @@ block0(v0: f64):
 ; VCode:
 ; block0:
 ;   cdbr %f0, %f0
-;   jno 6 ; trap
+;   jgo .+2 # trap=bad_toint
 ;   bras %r1, 12 ; data.f64 2147483648 ; ld %f4, 0(%r1)
 ;   cdbr %f0, %f4
-;   jnhe 6 ; trap
+;   jghe .+2 # trap=int_ovf
 ;   bras %r1, 12 ; data.f64 -2147483649 ; vleg %v16, 0(%r1), 0
 ;   wfcdb %f0, %v16
-;   jnle 6 ; trap
+;   jgle .+2 # trap=int_ovf
 ;   wcgdb %v20, %f0, 0, 5
 ;   vlgvg %r2, %v20, 0
 ;   br %r14
@@ -583,16 +544,14 @@ block0(v0: f64):
 ; Disassembled:
 ; block0: ; offset 0x0
 ;   cdbr %f0, %f0
-;   jno 0xa
-;   .byte 0x00, 0x00 ; trap: bad_toint
+;   jgo 6 ; trap: bad_toint
 ;   bras %r1, 0x16
 ;   la %r14, 0
 ;   .byte 0x00, 0x00
 ;   .byte 0x00, 0x00
 ;   ld %f4, 0(%r1)
 ;   cdbr %f0, %f4
-;   jnhe 0x24
-;   .byte 0x00, 0x00 ; trap: int_ovf
+;   jghe 0x20 ; trap: int_ovf
 ;   bras %r1, 0x30
 ;   .byte 0xc1, 0xe0
 ;   .byte 0x00, 0x00
@@ -600,8 +559,7 @@ block0(v0: f64):
 ;   .byte 0x00, 0x00
 ;   vleg %v16, 0(%r1), 0
 ;   wfcdb %f0, %v16
-;   jnle 0x42
-;   .byte 0x00, 0x00 ; trap: int_ovf
+;   jgle 0x3e ; trap: int_ovf
 ;   wcgdb %v20, %f0, 0, 5
 ;   vlgvg %r2, %v20, 0
 ;   br %r14
@@ -615,13 +573,13 @@ block0(v0: f64):
 ; VCode:
 ; block0:
 ;   cdbr %f0, %f0
-;   jno 6 ; trap
+;   jgo .+2 # trap=bad_toint
 ;   bras %r1, 12 ; data.f64 18446744073709552000 ; ld %f4, 0(%r1)
 ;   cdbr %f0, %f4
-;   jnhe 6 ; trap
+;   jghe .+2 # trap=int_ovf
 ;   bras %r1, 12 ; data.f64 -1 ; vleg %v16, 0(%r1), 0
 ;   wfcdb %f0, %v16
-;   jnle 6 ; trap
+;   jgle .+2 # trap=int_ovf
 ;   wclgdb %v20, %f0, 0, 5
 ;   vlgvg %r2, %v20, 0
 ;   br %r14
@@ -629,24 +587,21 @@ block0(v0: f64):
 ; Disassembled:
 ; block0: ; offset 0x0
 ;   cdbr %f0, %f0
-;   jno 0xa
-;   .byte 0x00, 0x00 ; trap: bad_toint
+;   jgo 6 ; trap: bad_toint
 ;   bras %r1, 0x16
 ;   ic %r15, 0
 ;   .byte 0x00, 0x00
 ;   .byte 0x00, 0x00
 ;   ld %f4, 0(%r1)
 ;   cdbr %f0, %f4
-;   jnhe 0x24
-;   .byte 0x00, 0x00 ; trap: int_ovf
+;   jghe 0x20 ; trap: int_ovf
 ;   bras %r1, 0x30
 ;   icm %r15, 0, 0
 ;   .byte 0x00, 0x00
 ;   .byte 0x00, 0x00
 ;   vleg %v16, 0(%r1), 0
 ;   wfcdb %f0, %v16
-;   jnle 0x42
-;   .byte 0x00, 0x00 ; trap: int_ovf
+;   jgle 0x3e ; trap: int_ovf
 ;   wclgdb %v20, %f0, 0, 5
 ;   vlgvg %r2, %v20, 0
 ;   br %r14
@@ -660,13 +615,13 @@ block0(v0: f64):
 ; VCode:
 ; block0:
 ;   cdbr %f0, %f0
-;   jno 6 ; trap
+;   jgo .+2 # trap=bad_toint
 ;   bras %r1, 12 ; data.f64 9223372036854776000 ; ld %f4, 0(%r1)
 ;   cdbr %f0, %f4
-;   jnhe 6 ; trap
+;   jghe .+2 # trap=int_ovf
 ;   bras %r1, 12 ; data.f64 -9223372036854778000 ; vleg %v16, 0(%r1), 0
 ;   wfcdb %f0, %v16
-;   jnle 6 ; trap
+;   jgle .+2 # trap=int_ovf
 ;   wcgdb %v20, %f0, 0, 5
 ;   vlgvg %r2, %v20, 0
 ;   br %r14
@@ -674,16 +629,14 @@ block0(v0: f64):
 ; Disassembled:
 ; block0: ; offset 0x0
 ;   cdbr %f0, %f0
-;   jno 0xa
-;   .byte 0x00, 0x00 ; trap: bad_toint
+;   jgo 6 ; trap: bad_toint
 ;   bras %r1, 0x16
 ;   ic %r14, 0
 ;   .byte 0x00, 0x00
 ;   .byte 0x00, 0x00
 ;   ld %f4, 0(%r1)
 ;   cdbr %f0, %f4
-;   jnhe 0x24
-;   .byte 0x00, 0x00 ; trap: int_ovf
+;   jghe 0x20 ; trap: int_ovf
 ;   bras %r1, 0x30
 ;   .byte 0xc3, 0xe0
 ;   .byte 0x00, 0x00
@@ -691,8 +644,7 @@ block0(v0: f64):
 ;   .byte 0x00, 0x01
 ;   vleg %v16, 0(%r1), 0
 ;   wfcdb %f0, %v16
-;   jnle 0x42
-;   .byte 0x00, 0x00 ; trap: int_ovf
+;   jgle 0x3e ; trap: int_ovf
 ;   wcgdb %v20, %f0, 0, 5
 ;   vlgvg %r2, %v20, 0
 ;   br %r14
diff --git a/cranelift/filetests/filetests/isa/s390x/floating-point.clif b/cranelift/filetests/filetests/isa/s390x/floating-point.clif
index 0181ffdd3..75b5474da 100644
--- a/cranelift/filetests/filetests/isa/s390x/floating-point.clif
+++ b/cranelift/filetests/filetests/isa/s390x/floating-point.clif
@@ -683,13 +683,13 @@ block0(v0: f32):
 ; VCode:
 ; block0:
 ;   cebr %f0, %f0
-;   jno 6 ; trap
+;   jgo .+2 # trap=bad_toint
 ;   bras %r1, 8 ; data.f32 256 ; le %f4, 0(%r1)
 ;   cebr %f0, %f4
-;   jnhe 6 ; trap
+;   jghe .+2 # trap=int_ovf
 ;   bras %r1, 8 ; data.f32 -1 ; vlef %v16, 0(%r1), 0
 ;   wfcsb %f0, %v16
-;   jnle 6 ; trap
+;   jgle .+2 # trap=int_ovf
 ;   wldeb %v20, %f0
 ;   wclgdb %v22, %v20, 0, 5
 ;   vlgvg %r2, %v22, 0
@@ -698,20 +698,17 @@ block0(v0: f32):
 ; Disassembled:
 ; block0: ; offset 0x0
 ;   cebr %f0, %f0
-;   jno 0xa
-;   .byte 0x00, 0x00 ; trap: bad_toint
+;   jgo 6 ; trap: bad_toint
 ;   bras %r1, 0x12
 ;   ic %r8, 0
 ;   le %f4, 0(%r1)
 ;   cebr %f0, %f4
-;   jnhe 0x20
-;   .byte 0x00, 0x00 ; trap: int_ovf
+;   jghe 0x1c ; trap: int_ovf
 ;   bras %r1, 0x28
 ;   icm %r8, 0, 0
 ;   vlef %v16, 0(%r1), 0
 ;   wfcsb %f0, %v16
-;   jnle 0x3a
-;   .byte 0x00, 0x00 ; trap: int_ovf
+;   jgle 0x36 ; trap: int_ovf
 ;   wldeb %v20, %f0
 ;   wclgdb %v22, %v20, 0, 5
 ;   vlgvg %r2, %v22, 0
@@ -726,13 +723,13 @@ block0(v0: f32):
 ; VCode:
 ; block0:
 ;   cebr %f0, %f0
-;   jno 6 ; trap
+;   jgo .+2 # trap=bad_toint
 ;   bras %r1, 8 ; data.f32 128 ; le %f4, 0(%r1)
 ;   cebr %f0, %f4
-;   jnhe 6 ; trap
+;   jghe .+2 # trap=int_ovf
 ;   bras %r1, 8 ; data.f32 -129 ; vlef %v16, 0(%r1), 0
 ;   wfcsb %f0, %v16
-;   jnle 6 ; trap
+;   jgle .+2 # trap=int_ovf
 ;   wldeb %v20, %f0
 ;   wcgdb %v22, %v20, 0, 5
 ;   vlgvg %r2, %v22, 0
@@ -741,21 +738,18 @@ block0(v0: f32):
 ; Disassembled:
 ; block0: ; offset 0x0
 ;   cebr %f0, %f0
-;   jno 0xa
-;   .byte 0x00, 0x00 ; trap: bad_toint
+;   jgo 6 ; trap: bad_toint
 ;   bras %r1, 0x12
 ;   ic %r0, 0
 ;   le %f4, 0(%r1)
 ;   cebr %f0, %f4
-;   jnhe 0x20
-;   .byte 0x00, 0x00 ; trap: int_ovf
+;   jghe 0x1c ; trap: int_ovf
 ;   bras %r1, 0x28
 ;   .byte 0xc3, 0x01
 ;   .byte 0x00, 0x00
 ;   vlef %v16, 0(%r1), 0
 ;   wfcsb %f0, %v16
-;   jnle 0x3a
-;   .byte 0x00, 0x00 ; trap: int_ovf
+;   jgle 0x36 ; trap: int_ovf
 ;   wldeb %v20, %f0
 ;   wcgdb %v22, %v20, 0, 5
 ;   vlgvg %r2, %v22, 0
@@ -770,13 +764,13 @@ block0(v0: f32):
 ; VCode:
 ; block0:
 ;   cebr %f0, %f0
-;   jno 6 ; trap
+;   jgo .+2 # trap=bad_toint
 ;   bras %r1, 8 ; data.f32 65536 ; le %f4, 0(%r1)
 ;   cebr %f0, %f4
-;   jnhe 6 ; trap
+;   jghe .+2 # trap=int_ovf
 ;   bras %r1, 8 ; data.f32 -1 ; vlef %v16, 0(%r1), 0
 ;   wfcsb %f0, %v16
-;   jnle 6 ; trap
+;   jgle .+2 # trap=int_ovf
 ;   wldeb %v20, %f0
 ;   wclgdb %v22, %v20, 0, 5
 ;   vlgvg %r2, %v22, 0
@@ -785,20 +779,17 @@ block0(v0: f32):
 ; Disassembled:
 ; block0: ; offset 0x0
 ;   cebr %f0, %f0
-;   jno 0xa
-;   .byte 0x00, 0x00 ; trap: bad_toint
+;   jgo 6 ; trap: bad_toint
 ;   bras %r1, 0x12
 ;   be 0
 ;   le %f4, 0(%r1)
 ;   cebr %f0, %f4
-;   jnhe 0x20
-;   .byte 0x00, 0x00 ; trap: int_ovf
+;   jghe 0x1c ; trap: int_ovf
 ;   bras %r1, 0x28
 ;   icm %r8, 0, 0
 ;   vlef %v16, 0(%r1), 0
 ;   wfcsb %f0, %v16
-;   jnle 0x3a
-;   .byte 0x00, 0x00 ; trap: int_ovf
+;   jgle 0x36 ; trap: int_ovf
 ;   wldeb %v20, %f0
 ;   wclgdb %v22, %v20, 0, 5
 ;   vlgvg %r2, %v22, 0
@@ -813,13 +804,13 @@ block0(v0: f32):
 ; VCode:
 ; block0:
 ;   cebr %f0, %f0
-;   jno 6 ; trap
+;   jgo .+2 # trap=bad_toint
 ;   bras %r1, 8 ; data.f32 32768 ; le %f4, 0(%r1)
 ;   cebr %f0, %f4
-;   jnhe 6 ; trap
+;   jghe .+2 # trap=int_ovf
 ;   bras %r1, 8 ; data.f32 -32769 ; vlef %v16, 0(%r1), 0
 ;   wfcsb %f0, %v16
-;   jnle 6 ; trap
+;   jgle .+2 # trap=int_ovf
 ;   wldeb %v20, %f0
 ;   wcgdb %v22, %v20, 0, 5
 ;   vlgvg %r2, %v22, 0
@@ -828,21 +819,18 @@ block0(v0: f32):
 ; Disassembled:
 ; block0: ; offset 0x0
 ;   cebr %f0, %f0
-;   jno 0xa
-;   .byte 0x00, 0x00 ; trap: bad_toint
+;   jgo 6 ; trap: bad_toint
 ;   bras %r1, 0x12
 ;   bc 0, 0
 ;   le %f4, 0(%r1)
 ;   cebr %f0, %f4
-;   jnhe 0x20
-;   .byte 0x00, 0x00 ; trap: int_ovf
+;   jghe 0x1c ; trap: int_ovf
 ;   bras %r1, 0x28
 ;   bpp 0, -0x31dc, 0x100
 ;   lpr %r0, %r0
 ;   .byte 0x08, 0x03
 ;   wfcsb %f0, %v16
-;   jnle 0x3a
-;   .byte 0x00, 0x00 ; trap: int_ovf
+;   jgle 0x36 ; trap: int_ovf
 ;   wldeb %v20, %f0
 ;   wcgdb %v22, %v20, 0, 5
 ;   vlgvg %r2, %v22, 0
@@ -857,13 +845,13 @@ block0(v0: f32):
 ; VCode:
 ; block0:
 ;   cebr %f0, %f0
-;   jno 6 ; trap
+;   jgo .+2 # trap=bad_toint
 ;   bras %r1, 8 ; data.f32 4294967300 ; le %f4, 0(%r1)
 ;   cebr %f0, %f4
-;   jnhe 6 ; trap
+;   jghe .+2 # trap=int_ovf
 ;   bras %r1, 8 ; data.f32 -1 ; vlef %v16, 0(%r1), 0
 ;   wfcsb %f0, %v16
-;   jnle 6 ; trap
+;   jgle .+2 # trap=int_ovf
 ;   wldeb %v20, %f0
 ;   wclgdb %v22, %v20, 0, 5
 ;   vlgvg %r2, %v22, 0
@@ -872,20 +860,17 @@ block0(v0: f32):
 ; Disassembled:
 ; block0: ; offset 0x0
 ;   cebr %f0, %f0
-;   jno 0xa
-;   .byte 0x00, 0x00 ; trap: bad_toint
+;   jgo 6 ; trap: bad_toint
 ;   bras %r1, 0x12
 ;   cvb %r8, 0
 ;   le %f4, 0(%r1)
 ;   cebr %f0, %f4
-;   jnhe 0x20
-;   .byte 0x00, 0x00 ; trap: int_ovf
+;   jghe 0x1c ; trap: int_ovf
 ;   bras %r1, 0x28
 ;   icm %r8, 0, 0
 ;   vlef %v16, 0(%r1), 0
 ;   wfcsb %f0, %v16
-;   jnle 0x3a
-;   .byte 0x00, 0x00 ; trap: int_ovf
+;   jgle 0x36 ; trap: int_ovf
 ;   wldeb %v20, %f0
 ;   wclgdb %v22, %v20, 0, 5
 ;   vlgvg %r2, %v22, 0
@@ -900,13 +885,13 @@ block0(v0: f32):
 ; VCode:
 ; block0:
 ;   cebr %f0, %f0
-;   jno 6 ; trap
+;   jgo .+2 # trap=bad_toint
 ;   bras %r1, 8 ; data.f32 2147483600 ; le %f4, 0(%r1)
 ;   cebr %f0, %f4
-;   jnhe 6 ; trap
+;   jghe .+2 # trap=int_ovf
 ;   bras %r1, 8 ; data.f32 -2147484000 ; vlef %v16, 0(%r1), 0
 ;   wfcsb %f0, %v16
-;   jnle 6 ; trap
+;   jgle .+2 # trap=int_ovf
 ;   wldeb %v20, %f0
 ;   wcgdb %v22, %v20, 0, 5
 ;   vlgvg %r2, %v22, 0
@@ -915,21 +900,18 @@ block0(v0: f32):
 ; Disassembled:
 ; block0: ; offset 0x0
 ;   cebr %f0, %f0
-;   jno 0xa
-;   .byte 0x00, 0x00 ; trap: bad_toint
+;   jgo 6 ; trap: bad_toint
 ;   bras %r1, 0x12
 ;   cvb %r0, 0
 ;   le %f4, 0(%r1)
 ;   cebr %f0, %f4
-;   jnhe 0x20
-;   .byte 0x00, 0x00 ; trap: int_ovf
+;   jghe 0x1c ; trap: int_ovf
 ;   bras %r1, 0x28
 ;   .byte 0xcf, 0x00
 ;   .byte 0x00, 0x01
 ;   vlef %v16, 0(%r1), 0
 ;   wfcsb %f0, %v16
-;   jnle 0x3a
-;   .byte 0x00, 0x00 ; trap: int_ovf
+;   jgle 0x36 ; trap: int_ovf
 ;   wldeb %v20, %f0
 ;   wcgdb %v22, %v20, 0, 5
 ;   vlgvg %r2, %v22, 0
@@ -944,13 +926,13 @@ block0(v0: f32):
 ; VCode:
 ; block0:
 ;   cebr %f0, %f0
-;   jno 6 ; trap
+;   jgo .+2 # trap=bad_toint
 ;   bras %r1, 8 ; data.f32 18446744000000000000 ; le %f4, 0(%r1)
 ;   cebr %f0, %f4
-;   jnhe 6 ; trap
+;   jghe .+2 # trap=int_ovf
 ;   bras %r1, 8 ; data.f32 -1 ; vlef %v16, 0(%r1), 0
 ;   wfcsb %f0, %v16
-;   jnle 6 ; trap
+;   jgle .+2 # trap=int_ovf
 ;   wldeb %v20, %f0
 ;   wclgdb %v22, %v20, 0, 5
 ;   vlgvg %r2, %v22, 0
@@ -959,20 +941,17 @@ block0(v0: f32):
 ; Disassembled:
 ; block0: ; offset 0x0
 ;   cebr %f0, %f0
-;   jno 0xa
-;   .byte 0x00, 0x00 ; trap: bad_toint
+;   jgo 6 ; trap: bad_toint
 ;   bras %r1, 0x12
 ;   sl %r8, 0
 ;   le %f4, 0(%r1)
 ;   cebr %f0, %f4
-;   jnhe 0x20
-;   .byte 0x00, 0x00 ; trap: int_ovf
+;   jghe 0x1c ; trap: int_ovf
 ;   bras %r1, 0x28
 ;   icm %r8, 0, 0
 ;   vlef %v16, 0(%r1), 0
 ;   wfcsb %f0, %v16
-;   jnle 0x3a
-;   .byte 0x00, 0x00 ; trap: int_ovf
+;   jgle 0x36 ; trap: int_ovf
 ;   wldeb %v20, %f0
 ;   wclgdb %v22, %v20, 0, 5
 ;   vlgvg %r2, %v22, 0
@@ -987,13 +966,13 @@ block0(v0: f32):
 ; VCode:
 ; block0:
 ;   cebr %f0, %f0
-;   jno 6 ; trap
+;   jgo .+2 # trap=bad_toint
 ;   bras %r1, 8 ; data.f32 9223372000000000000 ; le %f4, 0(%r1)
 ;   cebr %f0, %f4
-;   jnhe 6 ; trap
+;   jghe .+2 # trap=int_ovf
 ;   bras %r1, 8 ; data.f32 -9223373000000000000 ; vlef %v16, 0(%r1), 0
 ;   wfcsb %f0, %v16
-;   jnle 6 ; trap
+;   jgle .+2 # trap=int_ovf
 ;   wldeb %v20, %f0
 ;   wcgdb %v22, %v20, 0, 5
 ;   vlgvg %r2, %v22, 0
@@ -1002,21 +981,18 @@ block0(v0: f32):
 ; Disassembled:
 ; block0: ; offset 0x0
 ;   cebr %f0, %f0
-;   jno 0xa
-;   .byte 0x00, 0x00 ; trap: bad_toint
+;   jgo 6 ; trap: bad_toint
 ;   bras %r1, 0x12
 ;   sl %r0, 0
 ;   le %f4, 0(%r1)
 ;   cebr %f0, %f4
-;   jnhe 0x20
-;   .byte 0x00, 0x00 ; trap: int_ovf
+;   jghe 0x1c ; trap: int_ovf
 ;   bras %r1, 0x28
 ;   edmk 1(1), 0x700(%r14)
 ;   lpr %r0, %r0
 ;   .byte 0x08, 0x03
 ;   wfcsb %f0, %v16
-;   jnle 0x3a
-;   .byte 0x00, 0x00 ; trap: int_ovf
+;   jgle 0x36 ; trap: int_ovf
 ;   wldeb %v20, %f0
 ;   wcgdb %v22, %v20, 0, 5
 ;   vlgvg %r2, %v22, 0
@@ -1031,13 +1007,13 @@ block0(v0: f64):
 ; VCode:
 ; block0:
 ;   cdbr %f0, %f0
-;   jno 6 ; trap
+;   jgo .+2 # trap=bad_toint
 ;   bras %r1, 12 ; data.f64 256 ; ld %f4, 0(%r1)
 ;   cdbr %f0, %f4
-;   jnhe 6 ; trap
+;   jghe .+2 # trap=int_ovf
 ;   bras %r1, 12 ; data.f64 -1 ; vleg %v16, 0(%r1), 0
 ;   wfcdb %f0, %v16
-;   jnle 6 ; trap
+;   jgle .+2 # trap=int_ovf
 ;   wclgdb %v20, %f0, 0, 5
 ;   vlgvg %r2, %v20, 0
 ;   br %r14
@@ -1045,24 +1021,21 @@ block0(v0: f64):
 ; Disassembled:
 ; block0: ; offset 0x0
 ;   cdbr %f0, %f0
-;   jno 0xa
-;   .byte 0x00, 0x00 ; trap: bad_toint
+;   jgo 6 ; trap: bad_toint
 ;   bras %r1, 0x16
 ;   sth %r7, 0
 ;   .byte 0x00, 0x00
 ;   .byte 0x00, 0x00
 ;   ld %f4, 0(%r1)
 ;   cdbr %f0, %f4
-;   jnhe 0x24
-;   .byte 0x00, 0x00 ; trap: int_ovf
+;   jghe 0x20 ; trap: int_ovf
 ;   bras %r1, 0x30
 ;   icm %r15, 0, 0
 ;   .byte 0x00, 0x00
 ;   .byte 0x00, 0x00
 ;   vleg %v16, 0(%r1), 0
 ;   wfcdb %f0, %v16
-;   jnle 0x42
-;   .byte 0x00, 0x00 ; trap: int_ovf
+;   jgle 0x3e ; trap: int_ovf
 ;   wclgdb %v20, %f0, 0, 5
 ;   vlgvg %r2, %v20, 0
 ;   br %r14
@@ -1076,13 +1049,13 @@ block0(v0: f64):
 ; VCode:
 ; block0:
 ;   cdbr %f0, %f0
-;   jno 6 ; trap
+;   jgo .+2 # trap=bad_toint
 ;   bras %r1, 12 ; data.f64 128 ; ld %f4, 0(%r1)
 ;   cdbr %f0, %f4
-;   jnhe 6 ; trap
+;   jghe .+2 # trap=int_ovf
 ;   bras %r1, 12 ; data.f64 -129 ; vleg %v16, 0(%r1), 0
 ;   wfcdb %f0, %v16
-;   jnle 6 ; trap
+;   jgle .+2 # trap=int_ovf
 ;   wcgdb %v20, %f0, 0, 5
 ;   vlgvg %r2, %v20, 0
 ;   br %r14
@@ -1090,23 +1063,20 @@ block0(v0: f64):
 ; Disassembled:
 ; block0: ; offset 0x0
 ;   cdbr %f0, %f0
-;   jno 0xa
-;   .byte 0x00, 0x00 ; trap: bad_toint
+;   jgo 6 ; trap: bad_toint
 ;   bras %r1, 0x16
 ;   sth %r6, 0
 ;   .byte 0x00, 0x00
 ;   .byte 0x00, 0x00
 ;   ld %f4, 0(%r1)
 ;   cdbr %f0, %f4
-;   jnhe 0x24
-;   .byte 0x00, 0x00 ; trap: int_ovf
+;   jghe 0x20 ; trap: int_ovf
 ;   bras %r1, 0x30
 ;   larl %r6, 0x40000028
 ;   .byte 0x00, 0x00
 ;   vleg %v16, 0(%r1), 0
 ;   wfcdb %f0, %v16
-;   jnle 0x42
-;   .byte 0x00, 0x00 ; trap: int_ovf
+;   jgle 0x3e ; trap: int_ovf
 ;   wcgdb %v20, %f0, 0, 5
 ;   vlgvg %r2, %v20, 0
 ;   br %r14
@@ -1120,13 +1090,13 @@ block0(v0: f64):
 ; VCode:
 ; block0:
 ;   cdbr %f0, %f0
-;   jno 6 ; trap
+;   jgo .+2 # trap=bad_toint
 ;   bras %r1, 12 ; data.f64 65536 ; ld %f4, 0(%r1)
 ;   cdbr %f0, %f4
-;   jnhe 6 ; trap
+;   jghe .+2 # trap=int_ovf
 ;   bras %r1, 12 ; data.f64 -1 ; vleg %v16, 0(%r1), 0
 ;   wfcdb %f0, %v16
-;   jnle 6 ; trap
+;   jgle .+2 # trap=int_ovf
 ;   wclgdb %v20, %f0, 0, 5
 ;   vlgvg %r2, %v20, 0
 ;   br %r14
@@ -1134,24 +1104,21 @@ block0(v0: f64):
 ; Disassembled:
 ; block0: ; offset 0x0
 ;   cdbr %f0, %f0
-;   jno 0xa
-;   .byte 0x00, 0x00 ; trap: bad_toint
+;   jgo 6 ; trap: bad_toint
 ;   bras %r1, 0x16
 ;   sth %r15, 0
 ;   .byte 0x00, 0x00
 ;   .byte 0x00, 0x00
 ;   ld %f4, 0(%r1)
 ;   cdbr %f0, %f4
-;   jnhe 0x24
-;   .byte 0x00, 0x00 ; trap: int_ovf
+;   jghe 0x20 ; trap: int_ovf
 ;   bras %r1, 0x30
 ;   icm %r15, 0, 0
 ;   .byte 0x00, 0x00
 ;   .byte 0x00, 0x00
 ;   vleg %v16, 0(%r1), 0
 ;   wfcdb %f0, %v16
-;   jnle 0x42
-;   .byte 0x00, 0x00 ; trap: int_ovf
+;   jgle 0x3e ; trap: int_ovf
 ;   wclgdb %v20, %f0, 0, 5
 ;   vlgvg %r2, %v20, 0
 ;   br %r14
@@ -1165,13 +1132,13 @@ block0(v0: f64):
 ; VCode:
 ; block0:
 ;   cdbr %f0, %f0
-;   jno 6 ; trap
+;   jgo .+2 # trap=bad_toint
 ;   bras %r1, 12 ; data.f64 32768 ; ld %f4, 0(%r1)
 ;   cdbr %f0, %f4
-;   jnhe 6 ; trap
+;   jghe .+2 # trap=int_ovf
 ;   bras %r1, 12 ; data.f64 -32769 ; vleg %v16, 0(%r1), 0
 ;   wfcdb %f0, %v16
-;   jnle 6 ; trap
+;   jgle .+2 # trap=int_ovf
 ;   wcgdb %v20, %f0, 0, 5
 ;   vlgvg %r2, %v20, 0
 ;   br %r14
@@ -1179,23 +1146,20 @@ block0(v0: f64):
 ; Disassembled:
 ; block0: ; offset 0x0
 ;   cdbr %f0, %f0
-;   jno 0xa
-;   .byte 0x00, 0x00 ; trap: bad_toint
+;   jgo 6 ; trap: bad_toint
 ;   bras %r1, 0x16
 ;   sth %r14, 0
 ;   .byte 0x00, 0x00
 ;   .byte 0x00, 0x00
 ;   ld %f4, 0(%r1)
 ;   cdbr %f0, %f4
-;   jnhe 0x24
-;   .byte 0x00, 0x00 ; trap: int_ovf
+;   jghe 0x20 ; trap: int_ovf
 ;   bras %r1, 0x30
 ;   larl %r14, 0x400028
 ;   .byte 0x00, 0x00
 ;   vleg %v16, 0(%r1), 0
 ;   wfcdb %f0, %v16
-;   jnle 0x42
-;   .byte 0x00, 0x00 ; trap: int_ovf
+;   jgle 0x3e ; trap: int_ovf
 ;   wcgdb %v20, %f0, 0, 5
 ;   vlgvg %r2, %v20, 0
 ;   br %r14
@@ -1209,13 +1173,13 @@ block0(v0: f64):
 ; VCode:
 ; block0:
 ;   cdbr %f0, %f0
-;   jno 6 ; trap
+;   jgo .+2 # trap=bad_toint
 ;   bras %r1, 12 ; data.f64 4294967296 ; ld %f4, 0(%r1)
 ;   cdbr %f0, %f4
-;   jnhe 6 ; trap
+;   jghe .+2 # trap=int_ovf
 ;   bras %r1, 12 ; data.f64 -1 ; vleg %v16, 0(%r1), 0
 ;   wfcdb %f0, %v16
-;   jnle 6 ; trap
+;   jgle .+2 # trap=int_ovf
 ;   wclgdb %v20, %f0, 0, 5
 ;   vlgvg %r2, %v20, 0
 ;   br %r14
@@ -1223,24 +1187,21 @@ block0(v0: f64):
 ; Disassembled:
 ; block0: ; offset 0x0
 ;   cdbr %f0, %f0
-;   jno 0xa
-;   .byte 0x00, 0x00 ; trap: bad_toint
+;   jgo 6 ; trap: bad_toint
 ;   bras %r1, 0x16
 ;   la %r15, 0
 ;   .byte 0x00, 0x00
 ;   .byte 0x00, 0x00
 ;   ld %f4, 0(%r1)
 ;   cdbr %f0, %f4
-;   jnhe 0x24
-;   .byte 0x00, 0x00 ; trap: int_ovf
+;   jghe 0x20 ; trap: int_ovf
 ;   bras %r1, 0x30
 ;   icm %r15, 0, 0
 ;   .byte 0x00, 0x00
 ;   .byte 0x00, 0x00
 ;   vleg %v16, 0(%r1), 0
 ;   wfcdb %f0, %v16
-;   jnle 0x42
-;   .byte 0x00, 0x00 ; trap: int_ovf
+;   jgle 0x3e ; trap: int_ovf
 ;   wclgdb %v20, %f0, 0, 5
 ;   vlgvg %r2, %v20, 0
 ;   br %r14
@@ -1254,13 +1215,13 @@ block0(v0: f64):
 ; VCode:
 ; block0:
 ;   cdbr %f0, %f0
-;   jno 6 ; trap
+;   jgo .+2 # trap=bad_toint
 ;   bras %r1, 12 ; data.f64 2147483648 ; ld %f4, 0(%r1)
 ;   cdbr %f0, %f4
-;   jnhe 6 ; trap
+;   jghe .+2 # trap=int_ovf
 ;   bras %r1, 12 ; data.f64 -2147483649 ; vleg %v16, 0(%r1), 0
 ;   wfcdb %f0, %v16
-;   jnle 6 ; trap
+;   jgle .+2 # trap=int_ovf
 ;   wcgdb %v20, %f0, 0, 5
 ;   vlgvg %r2, %v20, 0
 ;   br %r14
@@ -1268,16 +1229,14 @@ block0(v0: f64):
 ; Disassembled:
 ; block0: ; offset 0x0
 ;   cdbr %f0, %f0
-;   jno 0xa
-;   .byte 0x00, 0x00 ; trap: bad_toint
+;   jgo 6 ; trap: bad_toint
 ;   bras %r1, 0x16
 ;   la %r14, 0
 ;   .byte 0x00, 0x00
 ;   .byte 0x00, 0x00
 ;   ld %f4, 0(%r1)
 ;   cdbr %f0, %f4
-;   jnhe 0x24
-;   .byte 0x00, 0x00 ; trap: int_ovf
+;   jghe 0x20 ; trap: int_ovf
 ;   bras %r1, 0x30
 ;   .byte 0xc1, 0xe0
 ;   .byte 0x00, 0x00
@@ -1285,8 +1244,7 @@ block0(v0: f64):
 ;   .byte 0x00, 0x00
 ;   vleg %v16, 0(%r1), 0
 ;   wfcdb %f0, %v16
-;   jnle 0x42
-;   .byte 0x00, 0x00 ; trap: int_ovf
+;   jgle 0x3e ; trap: int_ovf
 ;   wcgdb %v20, %f0, 0, 5
 ;   vlgvg %r2, %v20, 0
 ;   br %r14
@@ -1300,13 +1258,13 @@ block0(v0: f64):
 ; VCode:
 ; block0:
 ;   cdbr %f0, %f0
-;   jno 6 ; trap
+;   jgo .+2 # trap=bad_toint
 ;   bras %r1, 12 ; data.f64 18446744073709552000 ; ld %f4, 0(%r1)
 ;   cdbr %f0, %f4
-;   jnhe 6 ; trap
+;   jghe .+2 # trap=int_ovf
 ;   bras %r1, 12 ; data.f64 -1 ; vleg %v16, 0(%r1), 0
 ;   wfcdb %f0, %v16
-;   jnle 6 ; trap
+;   jgle .+2 # trap=int_ovf
 ;   wclgdb %v20, %f0, 0, 5
 ;   vlgvg %r2, %v20, 0
 ;   br %r14
@@ -1314,24 +1272,21 @@ block0(v0: f64):
 ; Disassembled:
 ; block0: ; offset 0x0
 ;   cdbr %f0, %f0
-;   jno 0xa
-;   .byte 0x00, 0x00 ; trap: bad_toint
+;   jgo 6 ; trap: bad_toint
 ;   bras %r1, 0x16
 ;   ic %r15, 0
 ;   .byte 0x00, 0x00
 ;   .byte 0x00, 0x00
 ;   ld %f4, 0(%r1)
 ;   cdbr %f0, %f4
-;   jnhe 0x24
-;   .byte 0x00, 0x00 ; trap: int_ovf
+;   jghe 0x20 ; trap: int_ovf
 ;   bras %r1, 0x30
 ;   icm %r15, 0, 0
 ;   .byte 0x00, 0x00
 ;   .byte 0x00, 0x00
 ;   vleg %v16, 0(%r1), 0
 ;   wfcdb %f0, %v16
-;   jnle 0x42
-;   .byte 0x00, 0x00 ; trap: int_ovf
+;   jgle 0x3e ; trap: int_ovf
 ;   wclgdb %v20, %f0, 0, 5
 ;   vlgvg %r2, %v20, 0
 ;   br %r14
@@ -1345,13 +1300,13 @@ block0(v0: f64):
 ; VCode:
 ; block0:
 ;   cdbr %f0, %f0
-;   jno 6 ; trap
+;   jgo .+2 # trap=bad_toint
 ;   bras %r1, 12 ; data.f64 9223372036854776000 ; ld %f4, 0(%r1)
 ;   cdbr %f0, %f4
-;   jnhe 6 ; trap
+;   jghe .+2 # trap=int_ovf
 ;   bras %r1, 12 ; data.f64 -9223372036854778000 ; vleg %v16, 0(%r1), 0
 ;   wfcdb %f0, %v16
-;   jnle 6 ; trap
+;   jgle .+2 # trap=int_ovf
 ;   wcgdb %v20, %f0, 0, 5
 ;   vlgvg %r2, %v20, 0
 ;   br %r14
@@ -1359,16 +1314,14 @@ block0(v0: f64):
 ; Disassembled:
 ; block0: ; offset 0x0
 ;   cdbr %f0, %f0
-;   jno 0xa
-;   .byte 0x00, 0x00 ; trap: bad_toint
+;   jgo 6 ; trap: bad_toint
 ;   bras %r1, 0x16
 ;   ic %r14, 0
 ;   .byte 0x00, 0x00
 ;   .byte 0x00, 0x00
 ;   ld %f4, 0(%r1)
 ;   cdbr %f0, %f4
-;   jnhe 0x24
-;   .byte 0x00, 0x00 ; trap: int_ovf
+;   jghe 0x20 ; trap: int_ovf
 ;   bras %r1, 0x30
 ;   .byte 0xc3, 0xe0
 ;   .byte 0x00, 0x00
@@ -1376,8 +1329,7 @@ block0(v0: f64):
 ;   .byte 0x00, 0x01
 ;   vleg %v16, 0(%r1), 0
 ;   wfcdb %f0, %v16
-;   jnle 0x42
-;   .byte 0x00, 0x00 ; trap: int_ovf
+;   jgle 0x3e ; trap: int_ovf
 ;   wcgdb %v20, %f0, 0, 5
 ;   vlgvg %r2, %v20, 0
 ;   br %r14
diff --git a/cranelift/filetests/filetests/isa/s390x/traps.clif b/cranelift/filetests/filetests/isa/s390x/traps.clif
index 101a17946..7759f6c8e 100644
--- a/cranelift/filetests/filetests/isa/s390x/traps.clif
+++ b/cranelift/filetests/filetests/isa/s390x/traps.clif
@@ -12,7 +12,7 @@ block0:
 
 ; VCode:
 ; block0:
-;   trap
+;   .word 0x0000 # trap=user0
 ; 
 ; Disassembled:
 ; block0: ; offset 0x0
@@ -25,7 +25,7 @@ block0:
 
 ; VCode:
 ; block0:
-;   trap
+;   .word 0x0000 # trap=user0
 ; 
 ; Disassembled:
 ; block0: ; offset 0x0
@@ -46,7 +46,7 @@ block0(v0: i64):
 ; block2:
 ;   br %r14
 ; block1:
-;   trap
+;   .word 0x0000 # trap=user0
 ; 
 ; Disassembled:
 ; block0: ; offset 0x0
@@ -72,7 +72,7 @@ block0(v0: i64):
 ; block1:
 ;   br %r14
 ; block2:
-;   trap
+;   .word 0x0000 # trap=user0
 ; 
 ; Disassembled:
 ; block0: ; offset 0x0
@@ -98,7 +98,7 @@ block0(v0: i64):
 ; block1:
 ;   br %r14
 ; block2:
-;   trap
+;   .word 0x0000 # trap=user0
 ; 
 ; Disassembled:
 ; block0: ; offset 0x0
@@ -117,7 +117,7 @@ block0:
 
 ; VCode:
 ; block0:
-;   debugtrap
+;   .word 0x0001 # debugtrap
 ;   br %r14
 ; 
 ; Disassembled:
diff --git a/cranelift/filetests/filetests/isa/s390x/uadd_overflow_trap.clif b/cranelift/filetests/filetests/isa/s390x/uadd_overflow_trap.clif
index f49a40590..dd5f8f798 100644
--- a/cranelift/filetests/filetests/isa/s390x/uadd_overflow_trap.clif
+++ b/cranelift/filetests/filetests/isa/s390x/uadd_overflow_trap.clif
@@ -11,14 +11,13 @@ block0(v0: i32):
 ; VCode:
 ; block0:
 ;   alfi %r2, 127
-;   jle 6 ; trap
+;   jgnle .+2 # trap=user0
 ;   br %r14
 ; 
 ; Disassembled:
 ; block0: ; offset 0x0
 ;   alfi %r2, 0x7f
-;   jle 0xc
-;   .byte 0x00, 0x00 ; trap: user0
+;   jgnle 8 ; trap: user0
 ;   br %r14
 
 function %f1(i32) -> i32 {
@@ -31,14 +30,13 @@ block0(v0: i32):
 ; VCode:
 ; block0:
 ;   alfi %r2, 127
-;   jle 6 ; trap
+;   jgnle .+2 # trap=user0
 ;   br %r14
 ; 
 ; Disassembled:
 ; block0: ; offset 0x0
 ;   alfi %r2, 0x7f
-;   jle 0xc
-;   .byte 0x00, 0x00 ; trap: user0
+;   jgnle 8 ; trap: user0
 ;   br %r14
 
 function %f2(i32, i32) -> i32 {
@@ -50,14 +48,13 @@ block0(v0: i32, v1: i32):
 ; VCode:
 ; block0:
 ;   alr %r2, %r3
-;   jle 6 ; trap
+;   jgnle .+2 # trap=user0
 ;   br %r14
 ; 
 ; Disassembled:
 ; block0: ; offset 0x0
 ;   alr %r2, %r3
-;   jle 8
-;   .byte 0x00, 0x00 ; trap: user0
+;   jgnle 4 ; trap: user0
 ;   br %r14
 
 function %f3(i64) -> i64 {
@@ -70,14 +67,13 @@ block0(v0: i64):
 ; VCode:
 ; block0:
 ;   algfi %r2, 127
-;   jle 6 ; trap
+;   jgnle .+2 # trap=user0
 ;   br %r14
 ; 
 ; Disassembled:
 ; block0: ; offset 0x0
 ;   algfi %r2, 0x7f
-;   jle 0xc
-;   .byte 0x00, 0x00 ; trap: user0
+;   jgnle 8 ; trap: user0
 ;   br %r14
 
 function %f3(i64) -> i64 {
@@ -90,14 +86,13 @@ block0(v0: i64):
 ; VCode:
 ; block0:
 ;   algfi %r2, 127
-;   jle 6 ; trap
+;   jgnle .+2 # trap=user0
 ;   br %r14
 ; 
 ; Disassembled:
 ; block0: ; offset 0x0
 ;   algfi %r2, 0x7f
-;   jle 0xc
-;   .byte 0x00, 0x00 ; trap: user0
+;   jgnle 8 ; trap: user0
 ;   br %r14
 
 function %f4(i64, i64) -> i64 {
@@ -109,14 +104,13 @@ block0(v0: i64, v1: i64):
 ; VCode:
 ; block0:
 ;   algr %r2, %r3
-;   jle 6 ; trap
+;   jgnle .+2 # trap=user0
 ;   br %r14
 ; 
 ; Disassembled:
 ; block0: ; offset 0x0
 ;   algr %r2, %r3
-;   jle 0xa
-;   .byte 0x00, 0x00 ; trap: user0
+;   jgnle 6 ; trap: user0
 ;   br %r14
 
 function %f5(i64, i32) -> i64 {
@@ -129,13 +123,12 @@ block0(v0: i64, v1: i32):
 ; VCode:
 ; block0:
 ;   algfr %r2, %r3
-;   jle 6 ; trap
+;   jgnle .+2 # trap=user0
 ;   br %r14
 ; 
 ; Disassembled:
 ; block0: ; offset 0x0
 ;   algfr %r2, %r3
-;   jle 0xa
-;   .byte 0x00, 0x00 ; trap: user0
+;   jgnle 6 ; trap: user0
 ;   br %r14
 
diff --git a/cranelift/filetests/filetests/isa/s390x/wasm/load_store_dynamic_kind_i32_index_0_guard_no_spectre_i32_access_0_offset.wat b/cranelift/filetests/filetests/isa/s390x/wasm/load_store_dynamic_kind_i32_index_0_guard_no_spectre_i32_access_0_offset.wat
index 44a3712ac..58e5f0894 100644
--- a/cranelift/filetests/filetests/isa/s390x/wasm/load_store_dynamic_kind_i32_index_0_guard_no_spectre_i32_access_0_offset.wat
+++ b/cranelift/filetests/filetests/isa/s390x/wasm/load_store_dynamic_kind_i32_index_0_guard_no_spectre_i32_access_0_offset.wat
@@ -55,7 +55,7 @@
 ;; block2:
 ;;   br %r14
 ;; block3:
-;;   trap
+;;   .word 0x0000 # trap=heap_oob
 ;;
 ;; function u0:1:
 ;;   unwind DefineNewFrame { offset_upward_to_caller_sp: 160, offset_downward_to_clobbers: 0 }
@@ -73,4 +73,4 @@
 ;; block2:
 ;;   br %r14
 ;; block3:
-;;   trap
+;;   .word 0x0000 # trap=heap_oob
diff --git a/cranelift/filetests/filetests/isa/s390x/wasm/load_store_dynamic_kind_i32_index_0_guard_no_spectre_i32_access_0x1000_offset.wat b/cranelift/filetests/filetests/isa/s390x/wasm/load_store_dynamic_kind_i32_index_0_guard_no_spectre_i32_access_0x1000_offset.wat
index b4f3e24f8..709818f96 100644
--- a/cranelift/filetests/filetests/isa/s390x/wasm/load_store_dynamic_kind_i32_index_0_guard_no_spectre_i32_access_0x1000_offset.wat
+++ b/cranelift/filetests/filetests/isa/s390x/wasm/load_store_dynamic_kind_i32_index_0_guard_no_spectre_i32_access_0x1000_offset.wat
@@ -57,7 +57,7 @@
 ;; block2:
 ;;   br %r14
 ;; block3:
-;;   trap
+;;   .word 0x0000 # trap=heap_oob
 ;;
 ;; function u0:1:
 ;;   unwind DefineNewFrame { offset_upward_to_caller_sp: 160, offset_downward_to_clobbers: 0 }
@@ -78,4 +78,4 @@
 ;; block2:
 ;;   br %r14
 ;; block3:
-;;   trap
+;;   .word 0x0000 # trap=heap_oob
diff --git a/cranelift/filetests/filetests/isa/s390x/wasm/load_store_dynamic_kind_i32_index_0_guard_no_spectre_i32_access_0xffff0000_offset.wat b/cranelift/filetests/filetests/isa/s390x/wasm/load_store_dynamic_kind_i32_index_0_guard_no_spectre_i32_access_0xffff0000_offset.wat
index 3b19386e2..36dc8ac55 100644
--- a/cranelift/filetests/filetests/isa/s390x/wasm/load_store_dynamic_kind_i32_index_0_guard_no_spectre_i32_access_0xffff0000_offset.wat
+++ b/cranelift/filetests/filetests/isa/s390x/wasm/load_store_dynamic_kind_i32_index_0_guard_no_spectre_i32_access_0xffff0000_offset.wat
@@ -58,7 +58,7 @@
 ;;   lgr %r5, %r2
 ;;   llilf %r2, 4294901764
 ;;   algfr %r2, %r5
-;;   jle 6 ; trap
+;;   jgnle .+2 # trap=heap_oob
 ;;   lgr %r5, %r7
 ;;   lg %r7, 8(%r5)
 ;;   clgr %r2, %r7
@@ -72,7 +72,7 @@
 ;;   lmg %r7, %r15, 56(%r15)
 ;;   br %r14
 ;; block3:
-;;   trap
+;;   .word 0x0000 # trap=heap_oob
 ;;
 ;; function u0:1:
 ;;   unwind DefineNewFrame { offset_upward_to_caller_sp: 160, offset_downward_to_clobbers: 0 }
@@ -82,7 +82,7 @@
 ;;   llgfr %r3, %r2
 ;;   llilf %r5, 4294901764
 ;;   algfr %r5, %r2
-;;   jle 6 ; trap
+;;   jgnle .+2 # trap=heap_oob
 ;;   lg %r2, 8(%r4)
 ;;   clgr %r5, %r2
 ;;   jgh label3 ; jg label1
@@ -94,4 +94,4 @@
 ;; block2:
 ;;   br %r14
 ;; block3:
-;;   trap
+;;   .word 0x0000 # trap=heap_oob
diff --git a/cranelift/filetests/filetests/isa/s390x/wasm/load_store_dynamic_kind_i32_index_0_guard_no_spectre_i8_access_0_offset.wat b/cranelift/filetests/filetests/isa/s390x/wasm/load_store_dynamic_kind_i32_index_0_guard_no_spectre_i8_access_0_offset.wat
index 5e29e4117..8d2f03cd7 100644
--- a/cranelift/filetests/filetests/isa/s390x/wasm/load_store_dynamic_kind_i32_index_0_guard_no_spectre_i8_access_0_offset.wat
+++ b/cranelift/filetests/filetests/isa/s390x/wasm/load_store_dynamic_kind_i32_index_0_guard_no_spectre_i8_access_0_offset.wat
@@ -56,7 +56,7 @@
 ;; block2:
 ;;   br %r14
 ;; block3:
-;;   trap
+;;   .word 0x0000 # trap=heap_oob
 ;;
 ;; function u0:1:
 ;;   unwind DefineNewFrame { offset_upward_to_caller_sp: 160, offset_downward_to_clobbers: 0 }
@@ -73,4 +73,4 @@
 ;; block2:
 ;;   br %r14
 ;; block3:
-;;   trap
+;;   .word 0x0000 # trap=heap_oob
diff --git a/cranelift/filetests/filetests/isa/s390x/wasm/load_store_dynamic_kind_i32_index_0_guard_no_spectre_i8_access_0x1000_offset.wat b/cranelift/filetests/filetests/isa/s390x/wasm/load_store_dynamic_kind_i32_index_0_guard_no_spectre_i8_access_0x1000_offset.wat
index 502af723d..2b7e0f548 100644
--- a/cranelift/filetests/filetests/isa/s390x/wasm/load_store_dynamic_kind_i32_index_0_guard_no_spectre_i8_access_0x1000_offset.wat
+++ b/cranelift/filetests/filetests/isa/s390x/wasm/load_store_dynamic_kind_i32_index_0_guard_no_spectre_i8_access_0x1000_offset.wat
@@ -57,7 +57,7 @@
 ;; block2:
 ;;   br %r14
 ;; block3:
-;;   trap
+;;   .word 0x0000 # trap=heap_oob
 ;;
 ;; function u0:1:
 ;;   unwind DefineNewFrame { offset_upward_to_caller_sp: 160, offset_downward_to_clobbers: 0 }
@@ -78,4 +78,4 @@
 ;; block2:
 ;;   br %r14
 ;; block3:
-;;   trap
+;;   .word 0x0000 # trap=heap_oob
diff --git a/cranelift/filetests/filetests/isa/s390x/wasm/load_store_dynamic_kind_i32_index_0_guard_no_spectre_i8_access_0xffff0000_offset.wat b/cranelift/filetests/filetests/isa/s390x/wasm/load_store_dynamic_kind_i32_index_0_guard_no_spectre_i8_access_0xffff0000_offset.wat
index 08084f5b1..2c17d1cc0 100644
--- a/cranelift/filetests/filetests/isa/s390x/wasm/load_store_dynamic_kind_i32_index_0_guard_no_spectre_i8_access_0xffff0000_offset.wat
+++ b/cranelift/filetests/filetests/isa/s390x/wasm/load_store_dynamic_kind_i32_index_0_guard_no_spectre_i8_access_0xffff0000_offset.wat
@@ -58,7 +58,7 @@
 ;;   lgr %r5, %r2
 ;;   llilf %r2, 4294901761
 ;;   algfr %r2, %r5
-;;   jle 6 ; trap
+;;   jgnle .+2 # trap=heap_oob
 ;;   lgr %r5, %r7
 ;;   lg %r7, 8(%r5)
 ;;   clgr %r2, %r7
@@ -72,7 +72,7 @@
 ;;   lmg %r7, %r15, 56(%r15)
 ;;   br %r14
 ;; block3:
-;;   trap
+;;   .word 0x0000 # trap=heap_oob
 ;;
 ;; function u0:1:
 ;;   unwind DefineNewFrame { offset_upward_to_caller_sp: 160, offset_downward_to_clobbers: 0 }
@@ -82,7 +82,7 @@
 ;;   llgfr %r3, %r2
 ;;   llilf %r5, 4294901761
 ;;   algfr %r5, %r2
-;;   jle 6 ; trap
+;;   jgnle .+2 # trap=heap_oob
 ;;   lg %r2, 8(%r4)
 ;;   clgr %r5, %r2
 ;;   jgh label3 ; jg label1
@@ -94,4 +94,4 @@
 ;; block2:
 ;;   br %r14
 ;; block3:
-;;   trap
+;;   .word 0x0000 # trap=heap_oob
diff --git a/cranelift/filetests/filetests/isa/s390x/wasm/load_store_dynamic_kind_i32_index_0_guard_yes_spectre_i32_access_0xffff0000_offset.wat b/cranelift/filetests/filetests/isa/s390x/wasm/load_store_dynamic_kind_i32_index_0_guard_yes_spectre_i32_access_0xffff0000_offset.wat
index 1c1a1189a..bd864d0c6 100644
--- a/cranelift/filetests/filetests/isa/s390x/wasm/load_store_dynamic_kind_i32_index_0_guard_yes_spectre_i32_access_0xffff0000_offset.wat
+++ b/cranelift/filetests/filetests/isa/s390x/wasm/load_store_dynamic_kind_i32_index_0_guard_yes_spectre_i32_access_0xffff0000_offset.wat
@@ -55,7 +55,7 @@
 ;;   llgfr %r4, %r2
 ;;   llilf %r9, 4294901764
 ;;   algfr %r9, %r2
-;;   jle 6 ; trap
+;;   jgnle .+2 # trap=heap_oob
 ;;   lgr %r2, %r5
 ;;   lg %r5, 8(%r2)
 ;;   ag %r4, 0(%r2)
@@ -78,7 +78,7 @@
 ;;   llgfr %r3, %r2
 ;;   llilf %r5, 4294901764
 ;;   algfr %r5, %r2
-;;   jle 6 ; trap
+;;   jgnle .+2 # trap=heap_oob
 ;;   lgr %r2, %r4
 ;;   lg %r4, 8(%r2)
 ;;   ag %r3, 0(%r2)
diff --git a/cranelift/filetests/filetests/isa/s390x/wasm/load_store_dynamic_kind_i32_index_0_guard_yes_spectre_i8_access_0xffff0000_offset.wat b/cranelift/filetests/filetests/isa/s390x/wasm/load_store_dynamic_kind_i32_index_0_guard_yes_spectre_i8_access_0xffff0000_offset.wat
index 9741ef2df..9f0e71fb6 100644
--- a/cranelift/filetests/filetests/isa/s390x/wasm/load_store_dynamic_kind_i32_index_0_guard_yes_spectre_i8_access_0xffff0000_offset.wat
+++ b/cranelift/filetests/filetests/isa/s390x/wasm/load_store_dynamic_kind_i32_index_0_guard_yes_spectre_i8_access_0xffff0000_offset.wat
@@ -55,7 +55,7 @@
 ;;   llgfr %r4, %r2
 ;;   llilf %r9, 4294901761
 ;;   algfr %r9, %r2
-;;   jle 6 ; trap
+;;   jgnle .+2 # trap=heap_oob
 ;;   lgr %r2, %r5
 ;;   lg %r5, 8(%r2)
 ;;   ag %r4, 0(%r2)
@@ -78,7 +78,7 @@
 ;;   llgfr %r3, %r2
 ;;   llilf %r5, 4294901761
 ;;   algfr %r5, %r2
-;;   jle 6 ; trap
+;;   jgnle .+2 # trap=heap_oob
 ;;   lgr %r2, %r4
 ;;   lg %r4, 8(%r2)
 ;;   ag %r3, 0(%r2)
diff --git a/cranelift/filetests/filetests/isa/s390x/wasm/load_store_dynamic_kind_i32_index_0xffffffff_guard_no_spectre_i32_access_0_offset.wat b/cranelift/filetests/filetests/isa/s390x/wasm/load_store_dynamic_kind_i32_index_0xffffffff_guard_no_spectre_i32_access_0_offset.wat
index 708e4bfe8..a746643e2 100644
--- a/cranelift/filetests/filetests/isa/s390x/wasm/load_store_dynamic_kind_i32_index_0xffffffff_guard_no_spectre_i32_access_0_offset.wat
+++ b/cranelift/filetests/filetests/isa/s390x/wasm/load_store_dynamic_kind_i32_index_0xffffffff_guard_no_spectre_i32_access_0_offset.wat
@@ -56,7 +56,7 @@
 ;; block2:
 ;;   br %r14
 ;; block3:
-;;   trap
+;;   .word 0x0000 # trap=heap_oob
 ;;
 ;; function u0:1:
 ;;   unwind DefineNewFrame { offset_upward_to_caller_sp: 160, offset_downward_to_clobbers: 0 }
@@ -73,4 +73,4 @@
 ;; block2:
 ;;   br %r14
 ;; block3:
-;;   trap
+;;   .word 0x0000 # trap=heap_oob
diff --git a/cranelift/filetests/filetests/isa/s390x/wasm/load_store_dynamic_kind_i32_index_0xffffffff_guard_no_spectre_i32_access_0x1000_offset.wat b/cranelift/filetests/filetests/isa/s390x/wasm/load_store_dynamic_kind_i32_index_0xffffffff_guard_no_spectre_i32_access_0x1000_offset.wat
index d7f0c5361..d9e076100 100644
--- a/cranelift/filetests/filetests/isa/s390x/wasm/load_store_dynamic_kind_i32_index_0xffffffff_guard_no_spectre_i32_access_0x1000_offset.wat
+++ b/cranelift/filetests/filetests/isa/s390x/wasm/load_store_dynamic_kind_i32_index_0xffffffff_guard_no_spectre_i32_access_0x1000_offset.wat
@@ -56,7 +56,7 @@
 ;; block2:
 ;;   br %r14
 ;; block3:
-;;   trap
+;;   .word 0x0000 # trap=heap_oob
 ;;
 ;; function u0:1:
 ;;   unwind DefineNewFrame { offset_upward_to_caller_sp: 160, offset_downward_to_clobbers: 0 }
@@ -75,4 +75,4 @@
 ;; block2:
 ;;   br %r14
 ;; block3:
-;;   trap
+;;   .word 0x0000 # trap=heap_oob
diff --git a/cranelift/filetests/filetests/isa/s390x/wasm/load_store_dynamic_kind_i32_index_0xffffffff_guard_no_spectre_i32_access_0xffff0000_offset.wat b/cranelift/filetests/filetests/isa/s390x/wasm/load_store_dynamic_kind_i32_index_0xffffffff_guard_no_spectre_i32_access_0xffff0000_offset.wat
index efe0b2cd1..4be98bd7a 100644
--- a/cranelift/filetests/filetests/isa/s390x/wasm/load_store_dynamic_kind_i32_index_0xffffffff_guard_no_spectre_i32_access_0xffff0000_offset.wat
+++ b/cranelift/filetests/filetests/isa/s390x/wasm/load_store_dynamic_kind_i32_index_0xffffffff_guard_no_spectre_i32_access_0xffff0000_offset.wat
@@ -56,7 +56,7 @@
 ;; block2:
 ;;   br %r14
 ;; block3:
-;;   trap
+;;   .word 0x0000 # trap=heap_oob
 ;;
 ;; function u0:1:
 ;;   unwind DefineNewFrame { offset_upward_to_caller_sp: 160, offset_downward_to_clobbers: 0 }
@@ -75,4 +75,4 @@
 ;; block2:
 ;;   br %r14
 ;; block3:
-;;   trap
+;;   .word 0x0000 # trap=heap_oob
diff --git a/cranelift/filetests/filetests/isa/s390x/wasm/load_store_dynamic_kind_i32_index_0xffffffff_guard_no_spectre_i8_access_0_offset.wat b/cranelift/filetests/filetests/isa/s390x/wasm/load_store_dynamic_kind_i32_index_0xffffffff_guard_no_spectre_i8_access_0_offset.wat
index 18bdd868a..306699d99 100644
--- a/cranelift/filetests/filetests/isa/s390x/wasm/load_store_dynamic_kind_i32_index_0xffffffff_guard_no_spectre_i8_access_0_offset.wat
+++ b/cranelift/filetests/filetests/isa/s390x/wasm/load_store_dynamic_kind_i32_index_0xffffffff_guard_no_spectre_i8_access_0_offset.wat
@@ -56,7 +56,7 @@
 ;; block2:
 ;;   br %r14
 ;; block3:
-;;   trap
+;;   .word 0x0000 # trap=heap_oob
 ;;
 ;; function u0:1:
 ;;   unwind DefineNewFrame { offset_upward_to_caller_sp: 160, offset_downward_to_clobbers: 0 }
@@ -73,4 +73,4 @@
 ;; block2:
 ;;   br %r14
 ;; block3:
-;;   trap
+;;   .word 0x0000 # trap=heap_oob
diff --git a/cranelift/filetests/filetests/isa/s390x/wasm/load_store_dynamic_kind_i32_index_0xffffffff_guard_no_spectre_i8_access_0x1000_offset.wat b/cranelift/filetests/filetests/isa/s390x/wasm/load_store_dynamic_kind_i32_index_0xffffffff_guard_no_spectre_i8_access_0x1000_offset.wat
index 4288c8491..fa1828b95 100644
--- a/cranelift/filetests/filetests/isa/s390x/wasm/load_store_dynamic_kind_i32_index_0xffffffff_guard_no_spectre_i8_access_0x1000_offset.wat
+++ b/cranelift/filetests/filetests/isa/s390x/wasm/load_store_dynamic_kind_i32_index_0xffffffff_guard_no_spectre_i8_access_0x1000_offset.wat
@@ -56,7 +56,7 @@
 ;; block2:
 ;;   br %r14
 ;; block3:
-;;   trap
+;;   .word 0x0000 # trap=heap_oob
 ;;
 ;; function u0:1:
 ;;   unwind DefineNewFrame { offset_upward_to_caller_sp: 160, offset_downward_to_clobbers: 0 }
@@ -75,4 +75,4 @@
 ;; block2:
 ;;   br %r14
 ;; block3:
-;;   trap
+;;   .word 0x0000 # trap=heap_oob
diff --git a/cranelift/filetests/filetests/isa/s390x/wasm/load_store_dynamic_kind_i32_index_0xffffffff_guard_no_spectre_i8_access_0xffff0000_offset.wat b/cranelift/filetests/filetests/isa/s390x/wasm/load_store_dynamic_kind_i32_index_0xffffffff_guard_no_spectre_i8_access_0xffff0000_offset.wat
index 2c0ddb02e..49d92de1a 100644
--- a/cranelift/filetests/filetests/isa/s390x/wasm/load_store_dynamic_kind_i32_index_0xffffffff_guard_no_spectre_i8_access_0xffff0000_offset.wat
+++ b/cranelift/filetests/filetests/isa/s390x/wasm/load_store_dynamic_kind_i32_index_0xffffffff_guard_no_spectre_i8_access_0xffff0000_offset.wat
@@ -56,7 +56,7 @@
 ;; block2:
 ;;   br %r14
 ;; block3:
-;;   trap
+;;   .word 0x0000 # trap=heap_oob
 ;;
 ;; function u0:1:
 ;;   unwind DefineNewFrame { offset_upward_to_caller_sp: 160, offset_downward_to_clobbers: 0 }
@@ -75,4 +75,4 @@
 ;; block2:
 ;;   br %r14
 ;; block3:
-;;   trap
+;;   .word 0x0000 # trap=heap_oob
diff --git a/cranelift/filetests/filetests/isa/s390x/wasm/load_store_dynamic_kind_i64_index_0_guard_no_spectre_i32_access_0_offset.wat b/cranelift/filetests/filetests/isa/s390x/wasm/load_store_dynamic_kind_i64_index_0_guard_no_spectre_i32_access_0_offset.wat
index 40b318783..7c7974d27 100644
--- a/cranelift/filetests/filetests/isa/s390x/wasm/load_store_dynamic_kind_i64_index_0_guard_no_spectre_i32_access_0_offset.wat
+++ b/cranelift/filetests/filetests/isa/s390x/wasm/load_store_dynamic_kind_i64_index_0_guard_no_spectre_i32_access_0_offset.wat
@@ -54,7 +54,7 @@
 ;; block2:
 ;;   br %r14
 ;; block3:
-;;   trap
+;;   .word 0x0000 # trap=heap_oob
 ;;
 ;; function u0:1:
 ;;   unwind DefineNewFrame { offset_upward_to_caller_sp: 160, offset_downward_to_clobbers: 0 }
@@ -71,4 +71,4 @@
 ;; block2:
 ;;   br %r14
 ;; block3:
-;;   trap
+;;   .word 0x0000 # trap=heap_oob
diff --git a/cranelift/filetests/filetests/isa/s390x/wasm/load_store_dynamic_kind_i64_index_0_guard_no_spectre_i32_access_0x1000_offset.wat b/cranelift/filetests/filetests/isa/s390x/wasm/load_store_dynamic_kind_i64_index_0_guard_no_spectre_i32_access_0x1000_offset.wat
index b40b27c87..536d2560c 100644
--- a/cranelift/filetests/filetests/isa/s390x/wasm/load_store_dynamic_kind_i64_index_0_guard_no_spectre_i32_access_0x1000_offset.wat
+++ b/cranelift/filetests/filetests/isa/s390x/wasm/load_store_dynamic_kind_i64_index_0_guard_no_spectre_i32_access_0x1000_offset.wat
@@ -56,7 +56,7 @@
 ;; block2:
 ;;   br %r14
 ;; block3:
-;;   trap
+;;   .word 0x0000 # trap=heap_oob
 ;;
 ;; function u0:1:
 ;;   unwind DefineNewFrame { offset_upward_to_caller_sp: 160, offset_downward_to_clobbers: 0 }
@@ -75,4 +75,4 @@
 ;; block2:
 ;;   br %r14
 ;; block3:
-;;   trap
+;;   .word 0x0000 # trap=heap_oob
diff --git a/cranelift/filetests/filetests/isa/s390x/wasm/load_store_dynamic_kind_i64_index_0_guard_no_spectre_i32_access_0xffff0000_offset.wat b/cranelift/filetests/filetests/isa/s390x/wasm/load_store_dynamic_kind_i64_index_0_guard_no_spectre_i32_access_0xffff0000_offset.wat
index 1a8a615d1..0abec009a 100644
--- a/cranelift/filetests/filetests/isa/s390x/wasm/load_store_dynamic_kind_i64_index_0_guard_no_spectre_i32_access_0xffff0000_offset.wat
+++ b/cranelift/filetests/filetests/isa/s390x/wasm/load_store_dynamic_kind_i64_index_0_guard_no_spectre_i32_access_0xffff0000_offset.wat
@@ -48,7 +48,7 @@
 ;; block0:
 ;;   lgr %r5, %r2
 ;;   algfi %r5, 4294901764
-;;   jle 6 ; trap
+;;   jgnle .+2 # trap=heap_oob
 ;;   lg %r14, 8(%r4)
 ;;   clgr %r5, %r14
 ;;   jgh label3 ; jg label1
@@ -62,7 +62,7 @@
 ;;   lmg %r14, %r15, 112(%r15)
 ;;   br %r14
 ;; block3:
-;;   trap
+;;   .word 0x0000 # trap=heap_oob
 ;;
 ;; function u0:1:
 ;;   unwind DefineNewFrame { offset_upward_to_caller_sp: 160, offset_downward_to_clobbers: 0 }
@@ -70,7 +70,7 @@
 ;; block0:
 ;;   lgr %r5, %r2
 ;;   algfi %r5, 4294901764
-;;   jle 6 ; trap
+;;   jgnle .+2 # trap=heap_oob
 ;;   lg %r4, 8(%r3)
 ;;   clgr %r5, %r4
 ;;   jgh label3 ; jg label1
@@ -83,4 +83,4 @@
 ;; block2:
 ;;   br %r14
 ;; block3:
-;;   trap
+;;   .word 0x0000 # trap=heap_oob
diff --git a/cranelift/filetests/filetests/isa/s390x/wasm/load_store_dynamic_kind_i64_index_0_guard_no_spectre_i8_access_0_offset.wat b/cranelift/filetests/filetests/isa/s390x/wasm/load_store_dynamic_kind_i64_index_0_guard_no_spectre_i8_access_0_offset.wat
index 71895085c..2a46594c5 100644
--- a/cranelift/filetests/filetests/isa/s390x/wasm/load_store_dynamic_kind_i64_index_0_guard_no_spectre_i8_access_0_offset.wat
+++ b/cranelift/filetests/filetests/isa/s390x/wasm/load_store_dynamic_kind_i64_index_0_guard_no_spectre_i8_access_0_offset.wat
@@ -53,7 +53,7 @@
 ;; block2:
 ;;   br %r14
 ;; block3:
-;;   trap
+;;   .word 0x0000 # trap=heap_oob
 ;;
 ;; function u0:1:
 ;;   unwind DefineNewFrame { offset_upward_to_caller_sp: 160, offset_downward_to_clobbers: 0 }
@@ -69,4 +69,4 @@
 ;; block2:
 ;;   br %r14
 ;; block3:
-;;   trap
+;;   .word 0x0000 # trap=heap_oob
diff --git a/cranelift/filetests/filetests/isa/s390x/wasm/load_store_dynamic_kind_i64_index_0_guard_no_spectre_i8_access_0x1000_offset.wat b/cranelift/filetests/filetests/isa/s390x/wasm/load_store_dynamic_kind_i64_index_0_guard_no_spectre_i8_access_0x1000_offset.wat
index b5829de08..65a74304e 100644
--- a/cranelift/filetests/filetests/isa/s390x/wasm/load_store_dynamic_kind_i64_index_0_guard_no_spectre_i8_access_0x1000_offset.wat
+++ b/cranelift/filetests/filetests/isa/s390x/wasm/load_store_dynamic_kind_i64_index_0_guard_no_spectre_i8_access_0x1000_offset.wat
@@ -56,7 +56,7 @@
 ;; block2:
 ;;   br %r14
 ;; block3:
-;;   trap
+;;   .word 0x0000 # trap=heap_oob
 ;;
 ;; function u0:1:
 ;;   unwind DefineNewFrame { offset_upward_to_caller_sp: 160, offset_downward_to_clobbers: 0 }
@@ -75,4 +75,4 @@
 ;; block2:
 ;;   br %r14
 ;; block3:
-;;   trap
+;;   .word 0x0000 # trap=heap_oob
diff --git a/cranelift/filetests/filetests/isa/s390x/wasm/load_store_dynamic_kind_i64_index_0_guard_no_spectre_i8_access_0xffff0000_offset.wat b/cranelift/filetests/filetests/isa/s390x/wasm/load_store_dynamic_kind_i64_index_0_guard_no_spectre_i8_access_0xffff0000_offset.wat
index 2c591ee9b..5cbdc6a00 100644
--- a/cranelift/filetests/filetests/isa/s390x/wasm/load_store_dynamic_kind_i64_index_0_guard_no_spectre_i8_access_0xffff0000_offset.wat
+++ b/cranelift/filetests/filetests/isa/s390x/wasm/load_store_dynamic_kind_i64_index_0_guard_no_spectre_i8_access_0xffff0000_offset.wat
@@ -48,7 +48,7 @@
 ;; block0:
 ;;   lgr %r5, %r2
 ;;   algfi %r5, 4294901761
-;;   jle 6 ; trap
+;;   jgnle .+2 # trap=heap_oob
 ;;   lg %r14, 8(%r4)
 ;;   clgr %r5, %r14
 ;;   jgh label3 ; jg label1
@@ -62,7 +62,7 @@
 ;;   lmg %r14, %r15, 112(%r15)
 ;;   br %r14
 ;; block3:
-;;   trap
+;;   .word 0x0000 # trap=heap_oob
 ;;
 ;; function u0:1:
 ;;   unwind DefineNewFrame { offset_upward_to_caller_sp: 160, offset_downward_to_clobbers: 0 }
@@ -70,7 +70,7 @@
 ;; block0:
 ;;   lgr %r5, %r2
 ;;   algfi %r5, 4294901761
-;;   jle 6 ; trap
+;;   jgnle .+2 # trap=heap_oob
 ;;   lg %r4, 8(%r3)
 ;;   clgr %r5, %r4
 ;;   jgh label3 ; jg label1
@@ -83,4 +83,4 @@
 ;; block2:
 ;;   br %r14
 ;; block3:
-;;   trap
+;;   .word 0x0000 # trap=heap_oob
diff --git a/cranelift/filetests/filetests/isa/s390x/wasm/load_store_dynamic_kind_i64_index_0_guard_yes_spectre_i32_access_0xffff0000_offset.wat b/cranelift/filetests/filetests/isa/s390x/wasm/load_store_dynamic_kind_i64_index_0_guard_yes_spectre_i32_access_0xffff0000_offset.wat
index 86cec29b9..a2df1b01c 100644
--- a/cranelift/filetests/filetests/isa/s390x/wasm/load_store_dynamic_kind_i64_index_0_guard_yes_spectre_i32_access_0xffff0000_offset.wat
+++ b/cranelift/filetests/filetests/isa/s390x/wasm/load_store_dynamic_kind_i64_index_0_guard_yes_spectre_i32_access_0xffff0000_offset.wat
@@ -55,7 +55,7 @@
 ;; block0:
 ;;   lgr %r7, %r2
 ;;   algfi %r7, 4294901764
-;;   jle 6 ; trap
+;;   jgnle .+2 # trap=heap_oob
 ;;   lg %r5, 8(%r4)
 ;;   ag %r2, 0(%r4)
 ;;   llilh %r4, 65535
@@ -75,7 +75,7 @@
 ;; block0:
 ;;   lgr %r4, %r2
 ;;   algfi %r4, 4294901764
-;;   jle 6 ; trap
+;;   jgnle .+2 # trap=heap_oob
 ;;   lg %r5, 8(%r3)
 ;;   ag %r2, 0(%r3)
 ;;   llilh %r3, 65535
diff --git a/cranelift/filetests/filetests/isa/s390x/wasm/load_store_dynamic_kind_i64_index_0_guard_yes_spectre_i8_access_0xffff0000_offset.wat b/cranelift/filetests/filetests/isa/s390x/wasm/load_store_dynamic_kind_i64_index_0_guard_yes_spectre_i8_access_0xffff0000_offset.wat
index be29d3526..ae1caf963 100644
--- a/cranelift/filetests/filetests/isa/s390x/wasm/load_store_dynamic_kind_i64_index_0_guard_yes_spectre_i8_access_0xffff0000_offset.wat
+++ b/cranelift/filetests/filetests/isa/s390x/wasm/load_store_dynamic_kind_i64_index_0_guard_yes_spectre_i8_access_0xffff0000_offset.wat
@@ -55,7 +55,7 @@
 ;; block0:
 ;;   lgr %r7, %r2
 ;;   algfi %r7, 4294901761
-;;   jle 6 ; trap
+;;   jgnle .+2 # trap=heap_oob
 ;;   lg %r5, 8(%r4)
 ;;   ag %r2, 0(%r4)
 ;;   llilh %r4, 65535
@@ -75,7 +75,7 @@
 ;; block0:
 ;;   lgr %r4, %r2
 ;;   algfi %r4, 4294901761
-;;   jle 6 ; trap
+;;   jgnle .+2 # trap=heap_oob
 ;;   lg %r5, 8(%r3)
 ;;   ag %r2, 0(%r3)
 ;;   llilh %r3, 65535
diff --git a/cranelift/filetests/filetests/isa/s390x/wasm/load_store_dynamic_kind_i64_index_0xffffffff_guard_no_spectre_i32_access_0_offset.wat b/cranelift/filetests/filetests/isa/s390x/wasm/load_store_dynamic_kind_i64_index_0xffffffff_guard_no_spectre_i32_access_0_offset.wat
index cf7df8397..b16a1ef87 100644
--- a/cranelift/filetests/filetests/isa/s390x/wasm/load_store_dynamic_kind_i64_index_0xffffffff_guard_no_spectre_i32_access_0_offset.wat
+++ b/cranelift/filetests/filetests/isa/s390x/wasm/load_store_dynamic_kind_i64_index_0xffffffff_guard_no_spectre_i32_access_0_offset.wat
@@ -53,7 +53,7 @@
 ;; block2:
 ;;   br %r14
 ;; block3:
-;;   trap
+;;   .word 0x0000 # trap=heap_oob
 ;;
 ;; function u0:1:
 ;;   unwind DefineNewFrame { offset_upward_to_caller_sp: 160, offset_downward_to_clobbers: 0 }
@@ -69,4 +69,4 @@
 ;; block2:
 ;;   br %r14
 ;; block3:
-;;   trap
+;;   .word 0x0000 # trap=heap_oob
diff --git a/cranelift/filetests/filetests/isa/s390x/wasm/load_store_dynamic_kind_i64_index_0xffffffff_guard_no_spectre_i32_access_0x1000_offset.wat b/cranelift/filetests/filetests/isa/s390x/wasm/load_store_dynamic_kind_i64_index_0xffffffff_guard_no_spectre_i32_access_0x1000_offset.wat
index 47d32bb98..57f3aeb37 100644
--- a/cranelift/filetests/filetests/isa/s390x/wasm/load_store_dynamic_kind_i64_index_0xffffffff_guard_no_spectre_i32_access_0x1000_offset.wat
+++ b/cranelift/filetests/filetests/isa/s390x/wasm/load_store_dynamic_kind_i64_index_0xffffffff_guard_no_spectre_i32_access_0x1000_offset.wat
@@ -54,7 +54,7 @@
 ;; block2:
 ;;   br %r14
 ;; block3:
-;;   trap
+;;   .word 0x0000 # trap=heap_oob
 ;;
 ;; function u0:1:
 ;;   unwind DefineNewFrame { offset_upward_to_caller_sp: 160, offset_downward_to_clobbers: 0 }
@@ -71,4 +71,4 @@
 ;; block2:
 ;;   br %r14
 ;; block3:
-;;   trap
+;;   .word 0x0000 # trap=heap_oob
diff --git a/cranelift/filetests/filetests/isa/s390x/wasm/load_store_dynamic_kind_i64_index_0xffffffff_guard_no_spectre_i32_access_0xffff0000_offset.wat b/cranelift/filetests/filetests/isa/s390x/wasm/load_store_dynamic_kind_i64_index_0xffffffff_guard_no_spectre_i32_access_0xffff0000_offset.wat
index 434de2925..217b1336a 100644
--- a/cranelift/filetests/filetests/isa/s390x/wasm/load_store_dynamic_kind_i64_index_0xffffffff_guard_no_spectre_i32_access_0xffff0000_offset.wat
+++ b/cranelift/filetests/filetests/isa/s390x/wasm/load_store_dynamic_kind_i64_index_0xffffffff_guard_no_spectre_i32_access_0xffff0000_offset.wat
@@ -54,7 +54,7 @@
 ;; block2:
 ;;   br %r14
 ;; block3:
-;;   trap
+;;   .word 0x0000 # trap=heap_oob
 ;;
 ;; function u0:1:
 ;;   unwind DefineNewFrame { offset_upward_to_caller_sp: 160, offset_downward_to_clobbers: 0 }
@@ -71,4 +71,4 @@
 ;; block2:
 ;;   br %r14
 ;; block3:
-;;   trap
+;;   .word 0x0000 # trap=heap_oob
diff --git a/cranelift/filetests/filetests/isa/s390x/wasm/load_store_dynamic_kind_i64_index_0xffffffff_guard_no_spectre_i8_access_0_offset.wat b/cranelift/filetests/filetests/isa/s390x/wasm/load_store_dynamic_kind_i64_index_0xffffffff_guard_no_spectre_i8_access_0_offset.wat
index 6678fe619..437423679 100644
--- a/cranelift/filetests/filetests/isa/s390x/wasm/load_store_dynamic_kind_i64_index_0xffffffff_guard_no_spectre_i8_access_0_offset.wat
+++ b/cranelift/filetests/filetests/isa/s390x/wasm/load_store_dynamic_kind_i64_index_0xffffffff_guard_no_spectre_i8_access_0_offset.wat
@@ -53,7 +53,7 @@
 ;; block2:
 ;;   br %r14
 ;; block3:
-;;   trap
+;;   .word 0x0000 # trap=heap_oob
 ;;
 ;; function u0:1:
 ;;   unwind DefineNewFrame { offset_upward_to_caller_sp: 160, offset_downward_to_clobbers: 0 }
@@ -69,4 +69,4 @@
 ;; block2:
 ;;   br %r14
 ;; block3:
-;;   trap
+;;   .word 0x0000 # trap=heap_oob
diff --git a/cranelift/filetests/filetests/isa/s390x/wasm/load_store_dynamic_kind_i64_index_0xffffffff_guard_no_spectre_i8_access_0x1000_offset.wat b/cranelift/filetests/filetests/isa/s390x/wasm/load_store_dynamic_kind_i64_index_0xffffffff_guard_no_spectre_i8_access_0x1000_offset.wat
index 9782d3a0d..afc2bcf33 100644
--- a/cranelift/filetests/filetests/isa/s390x/wasm/load_store_dynamic_kind_i64_index_0xffffffff_guard_no_spectre_i8_access_0x1000_offset.wat
+++ b/cranelift/filetests/filetests/isa/s390x/wasm/load_store_dynamic_kind_i64_index_0xffffffff_guard_no_spectre_i8_access_0x1000_offset.wat
@@ -54,7 +54,7 @@
 ;; block2:
 ;;   br %r14
 ;; block3:
-;;   trap
+;;   .word 0x0000 # trap=heap_oob
 ;;
 ;; function u0:1:
 ;;   unwind DefineNewFrame { offset_upward_to_caller_sp: 160, offset_downward_to_clobbers: 0 }
@@ -71,4 +71,4 @@
 ;; block2:
 ;;   br %r14
 ;; block3:
-;;   trap
+;;   .word 0x0000 # trap=heap_oob
diff --git a/cranelift/filetests/filetests/isa/s390x/wasm/load_store_dynamic_kind_i64_index_0xffffffff_guard_no_spectre_i8_access_0xffff0000_offset.wat b/cranelift/filetests/filetests/isa/s390x/wasm/load_store_dynamic_kind_i64_index_0xffffffff_guard_no_spectre_i8_access_0xffff0000_offset.wat
index 2e68c2e53..65808bc9c 100644
--- a/cranelift/filetests/filetests/isa/s390x/wasm/load_store_dynamic_kind_i64_index_0xffffffff_guard_no_spectre_i8_access_0xffff0000_offset.wat
+++ b/cranelift/filetests/filetests/isa/s390x/wasm/load_store_dynamic_kind_i64_index_0xffffffff_guard_no_spectre_i8_access_0xffff0000_offset.wat
@@ -54,7 +54,7 @@
 ;; block2:
 ;;   br %r14
 ;; block3:
-;;   trap
+;;   .word 0x0000 # trap=heap_oob
 ;;
 ;; function u0:1:
 ;;   unwind DefineNewFrame { offset_upward_to_caller_sp: 160, offset_downward_to_clobbers: 0 }
@@ -71,4 +71,4 @@
 ;; block2:
 ;;   br %r14
 ;; block3:
-;;   trap
+;;   .word 0x0000 # trap=heap_oob
diff --git a/cranelift/filetests/filetests/isa/s390x/wasm/load_store_static_kind_i32_index_0_guard_no_spectre_i32_access_0_offset.wat b/cranelift/filetests/filetests/isa/s390x/wasm/load_store_static_kind_i32_index_0_guard_no_spectre_i32_access_0_offset.wat
index 8a58d7550..8526bb67e 100644
--- a/cranelift/filetests/filetests/isa/s390x/wasm/load_store_static_kind_i32_index_0_guard_no_spectre_i32_access_0_offset.wat
+++ b/cranelift/filetests/filetests/isa/s390x/wasm/load_store_static_kind_i32_index_0_guard_no_spectre_i32_access_0_offset.wat
@@ -52,7 +52,7 @@
 ;; block2:
 ;;   br %r14
 ;; block3:
-;;   trap
+;;   .word 0x0000 # trap=heap_oob
 ;;
 ;; function u0:1:
 ;;   unwind DefineNewFrame { offset_upward_to_caller_sp: 160, offset_downward_to_clobbers: 0 }
@@ -69,4 +69,4 @@
 ;; block2:
 ;;   br %r14
 ;; block3:
-;;   trap
+;;   .word 0x0000 # trap=heap_oob
diff --git a/cranelift/filetests/filetests/isa/s390x/wasm/load_store_static_kind_i32_index_0_guard_no_spectre_i32_access_0x1000_offset.wat b/cranelift/filetests/filetests/isa/s390x/wasm/load_store_static_kind_i32_index_0_guard_no_spectre_i32_access_0x1000_offset.wat
index 9319fb85a..1d76ee44d 100644
--- a/cranelift/filetests/filetests/isa/s390x/wasm/load_store_static_kind_i32_index_0_guard_no_spectre_i32_access_0x1000_offset.wat
+++ b/cranelift/filetests/filetests/isa/s390x/wasm/load_store_static_kind_i32_index_0_guard_no_spectre_i32_access_0x1000_offset.wat
@@ -53,7 +53,7 @@
 ;; block2:
 ;;   br %r14
 ;; block3:
-;;   trap
+;;   .word 0x0000 # trap=heap_oob
 ;;
 ;; function u0:1:
 ;;   unwind DefineNewFrame { offset_upward_to_caller_sp: 160, offset_downward_to_clobbers: 0 }
@@ -72,4 +72,4 @@
 ;; block2:
 ;;   br %r14
 ;; block3:
-;;   trap
+;;   .word 0x0000 # trap=heap_oob
diff --git a/cranelift/filetests/filetests/isa/s390x/wasm/load_store_static_kind_i32_index_0_guard_no_spectre_i32_access_0xffff0000_offset.wat b/cranelift/filetests/filetests/isa/s390x/wasm/load_store_static_kind_i32_index_0_guard_no_spectre_i32_access_0xffff0000_offset.wat
index 08ecbb170..66463fee1 100644
--- a/cranelift/filetests/filetests/isa/s390x/wasm/load_store_static_kind_i32_index_0_guard_no_spectre_i32_access_0xffff0000_offset.wat
+++ b/cranelift/filetests/filetests/isa/s390x/wasm/load_store_static_kind_i32_index_0_guard_no_spectre_i32_access_0xffff0000_offset.wat
@@ -41,10 +41,10 @@
 ;;   unwind DefineNewFrame { offset_upward_to_caller_sp: 160, offset_downward_to_clobbers: 0 }
 ;;   unwind StackAlloc { size: 0 }
 ;; block0:
-;;   trap
+;;   .word 0x0000 # trap=heap_oob
 ;;
 ;; function u0:1:
 ;;   unwind DefineNewFrame { offset_upward_to_caller_sp: 160, offset_downward_to_clobbers: 0 }
 ;;   unwind StackAlloc { size: 0 }
 ;; block0:
-;;   trap
\ No newline at end of file
+;;   .word 0x0000 # trap=heap_oob
diff --git a/cranelift/filetests/filetests/isa/s390x/wasm/load_store_static_kind_i32_index_0_guard_no_spectre_i8_access_0_offset.wat b/cranelift/filetests/filetests/isa/s390x/wasm/load_store_static_kind_i32_index_0_guard_no_spectre_i8_access_0_offset.wat
index 02ea029a5..fd2169564 100644
--- a/cranelift/filetests/filetests/isa/s390x/wasm/load_store_static_kind_i32_index_0_guard_no_spectre_i8_access_0_offset.wat
+++ b/cranelift/filetests/filetests/isa/s390x/wasm/load_store_static_kind_i32_index_0_guard_no_spectre_i8_access_0_offset.wat
@@ -52,7 +52,7 @@
 ;; block2:
 ;;   br %r14
 ;; block3:
-;;   trap
+;;   .word 0x0000 # trap=heap_oob
 ;;
 ;; function u0:1:
 ;;   unwind DefineNewFrame { offset_upward_to_caller_sp: 160, offset_downward_to_clobbers: 0 }
@@ -69,4 +69,4 @@
 ;; block2:
 ;;   br %r14
 ;; block3:
-;;   trap
+;;   .word 0x0000 # trap=heap_oob
diff --git a/cranelift/filetests/filetests/isa/s390x/wasm/load_store_static_kind_i32_index_0_guard_no_spectre_i8_access_0x1000_offset.wat b/cranelift/filetests/filetests/isa/s390x/wasm/load_store_static_kind_i32_index_0_guard_no_spectre_i8_access_0x1000_offset.wat
index 9a2216619..1b1d767c7 100644
--- a/cranelift/filetests/filetests/isa/s390x/wasm/load_store_static_kind_i32_index_0_guard_no_spectre_i8_access_0x1000_offset.wat
+++ b/cranelift/filetests/filetests/isa/s390x/wasm/load_store_static_kind_i32_index_0_guard_no_spectre_i8_access_0x1000_offset.wat
@@ -53,7 +53,7 @@
 ;; block2:
 ;;   br %r14
 ;; block3:
-;;   trap
+;;   .word 0x0000 # trap=heap_oob
 ;;
 ;; function u0:1:
 ;;   unwind DefineNewFrame { offset_upward_to_caller_sp: 160, offset_downward_to_clobbers: 0 }
@@ -72,4 +72,4 @@
 ;; block2:
 ;;   br %r14
 ;; block3:
-;;   trap
+;;   .word 0x0000 # trap=heap_oob
diff --git a/cranelift/filetests/filetests/isa/s390x/wasm/load_store_static_kind_i32_index_0_guard_no_spectre_i8_access_0xffff0000_offset.wat b/cranelift/filetests/filetests/isa/s390x/wasm/load_store_static_kind_i32_index_0_guard_no_spectre_i8_access_0xffff0000_offset.wat
index b1906ca85..2f85b8cdf 100644
--- a/cranelift/filetests/filetests/isa/s390x/wasm/load_store_static_kind_i32_index_0_guard_no_spectre_i8_access_0xffff0000_offset.wat
+++ b/cranelift/filetests/filetests/isa/s390x/wasm/load_store_static_kind_i32_index_0_guard_no_spectre_i8_access_0xffff0000_offset.wat
@@ -41,10 +41,10 @@
 ;;   unwind DefineNewFrame { offset_upward_to_caller_sp: 160, offset_downward_to_clobbers: 0 }
 ;;   unwind StackAlloc { size: 0 }
 ;; block0:
-;;   trap
+;;   .word 0x0000 # trap=heap_oob
 ;;
 ;; function u0:1:
 ;;   unwind DefineNewFrame { offset_upward_to_caller_sp: 160, offset_downward_to_clobbers: 0 }
 ;;   unwind StackAlloc { size: 0 }
 ;; block0:
-;;   trap
\ No newline at end of file
+;;   .word 0x0000 # trap=heap_oob
diff --git a/cranelift/filetests/filetests/isa/s390x/wasm/load_store_static_kind_i32_index_0_guard_yes_spectre_i32_access_0xffff0000_offset.wat b/cranelift/filetests/filetests/isa/s390x/wasm/load_store_static_kind_i32_index_0_guard_yes_spectre_i32_access_0xffff0000_offset.wat
index d8f39931c..36579daec 100644
--- a/cranelift/filetests/filetests/isa/s390x/wasm/load_store_static_kind_i32_index_0_guard_yes_spectre_i32_access_0xffff0000_offset.wat
+++ b/cranelift/filetests/filetests/isa/s390x/wasm/load_store_static_kind_i32_index_0_guard_yes_spectre_i32_access_0xffff0000_offset.wat
@@ -41,10 +41,10 @@
 ;;   unwind DefineNewFrame { offset_upward_to_caller_sp: 160, offset_downward_to_clobbers: 0 }
 ;;   unwind StackAlloc { size: 0 }
 ;; block0:
-;;   trap
+;;   .word 0x0000 # trap=heap_oob
 ;;
 ;; function u0:1:
 ;;   unwind DefineNewFrame { offset_upward_to_caller_sp: 160, offset_downward_to_clobbers: 0 }
 ;;   unwind StackAlloc { size: 0 }
 ;; block0:
-;;   trap
\ No newline at end of file
+;;   .word 0x0000 # trap=heap_oob
diff --git a/cranelift/filetests/filetests/isa/s390x/wasm/load_store_static_kind_i32_index_0_guard_yes_spectre_i8_access_0xffff0000_offset.wat b/cranelift/filetests/filetests/isa/s390x/wasm/load_store_static_kind_i32_index_0_guard_yes_spectre_i8_access_0xffff0000_offset.wat
index 9291d34ee..648929ef8 100644
--- a/cranelift/filetests/filetests/isa/s390x/wasm/load_store_static_kind_i32_index_0_guard_yes_spectre_i8_access_0xffff0000_offset.wat
+++ b/cranelift/filetests/filetests/isa/s390x/wasm/load_store_static_kind_i32_index_0_guard_yes_spectre_i8_access_0xffff0000_offset.wat
@@ -41,10 +41,10 @@
 ;;   unwind DefineNewFrame { offset_upward_to_caller_sp: 160, offset_downward_to_clobbers: 0 }
 ;;   unwind StackAlloc { size: 0 }
 ;; block0:
-;;   trap
+;;   .word 0x0000 # trap=heap_oob
 ;;
 ;; function u0:1:
 ;;   unwind DefineNewFrame { offset_upward_to_caller_sp: 160, offset_downward_to_clobbers: 0 }
 ;;   unwind StackAlloc { size: 0 }
 ;; block0:
-;;   trap
\ No newline at end of file
+;;   .word 0x0000 # trap=heap_oob
diff --git a/cranelift/filetests/filetests/isa/s390x/wasm/load_store_static_kind_i32_index_0xffffffff_guard_no_spectre_i32_access_0xffff0000_offset.wat b/cranelift/filetests/filetests/isa/s390x/wasm/load_store_static_kind_i32_index_0xffffffff_guard_no_spectre_i32_access_0xffff0000_offset.wat
index ae231d776..4ba9e532a 100644
--- a/cranelift/filetests/filetests/isa/s390x/wasm/load_store_static_kind_i32_index_0xffffffff_guard_no_spectre_i32_access_0xffff0000_offset.wat
+++ b/cranelift/filetests/filetests/isa/s390x/wasm/load_store_static_kind_i32_index_0xffffffff_guard_no_spectre_i32_access_0xffff0000_offset.wat
@@ -41,10 +41,10 @@
 ;;   unwind DefineNewFrame { offset_upward_to_caller_sp: 160, offset_downward_to_clobbers: 0 }
 ;;   unwind StackAlloc { size: 0 }
 ;; block0:
-;;   trap
+;;   .word 0x0000 # trap=heap_oob
 ;;
 ;; function u0:1:
 ;;   unwind DefineNewFrame { offset_upward_to_caller_sp: 160, offset_downward_to_clobbers: 0 }
 ;;   unwind StackAlloc { size: 0 }
 ;; block0:
-;;   trap
\ No newline at end of file
+;;   .word 0x0000 # trap=heap_oob
diff --git a/cranelift/filetests/filetests/isa/s390x/wasm/load_store_static_kind_i32_index_0xffffffff_guard_no_spectre_i8_access_0xffff0000_offset.wat b/cranelift/filetests/filetests/isa/s390x/wasm/load_store_static_kind_i32_index_0xffffffff_guard_no_spectre_i8_access_0xffff0000_offset.wat
index e20bfe70d..6ffce7d78 100644
--- a/cranelift/filetests/filetests/isa/s390x/wasm/load_store_static_kind_i32_index_0xffffffff_guard_no_spectre_i8_access_0xffff0000_offset.wat
+++ b/cranelift/filetests/filetests/isa/s390x/wasm/load_store_static_kind_i32_index_0xffffffff_guard_no_spectre_i8_access_0xffff0000_offset.wat
@@ -41,10 +41,10 @@
 ;;   unwind DefineNewFrame { offset_upward_to_caller_sp: 160, offset_downward_to_clobbers: 0 }
 ;;   unwind StackAlloc { size: 0 }
 ;; block0:
-;;   trap
+;;   .word 0x0000 # trap=heap_oob
 ;;
 ;; function u0:1:
 ;;   unwind DefineNewFrame { offset_upward_to_caller_sp: 160, offset_downward_to_clobbers: 0 }
 ;;   unwind StackAlloc { size: 0 }
 ;; block0:
-;;   trap
\ No newline at end of file
+;;   .word 0x0000 # trap=heap_oob
diff --git a/cranelift/filetests/filetests/isa/s390x/wasm/load_store_static_kind_i32_index_0xffffffff_guard_yes_spectre_i32_access_0xffff0000_offset.wat b/cranelift/filetests/filetests/isa/s390x/wasm/load_store_static_kind_i32_index_0xffffffff_guard_yes_spectre_i32_access_0xffff0000_offset.wat
index bda2d224e..9c1d577ce 100644
--- a/cranelift/filetests/filetests/isa/s390x/wasm/load_store_static_kind_i32_index_0xffffffff_guard_yes_spectre_i32_access_0xffff0000_offset.wat
+++ b/cranelift/filetests/filetests/isa/s390x/wasm/load_store_static_kind_i32_index_0xffffffff_guard_yes_spectre_i32_access_0xffff0000_offset.wat
@@ -41,10 +41,10 @@
 ;;   unwind DefineNewFrame { offset_upward_to_caller_sp: 160, offset_downward_to_clobbers: 0 }
 ;;   unwind StackAlloc { size: 0 }
 ;; block0:
-;;   trap
+;;   .word 0x0000 # trap=heap_oob
 ;;
 ;; function u0:1:
 ;;   unwind DefineNewFrame { offset_upward_to_caller_sp: 160, offset_downward_to_clobbers: 0 }
 ;;   unwind StackAlloc { size: 0 }
 ;; block0:
-;;   trap
\ No newline at end of file
+;;   .word 0x0000 # trap=heap_oob
diff --git a/cranelift/filetests/filetests/isa/s390x/wasm/load_store_static_kind_i32_index_0xffffffff_guard_yes_spectre_i8_access_0xffff0000_offset.wat b/cranelift/filetests/filetests/isa/s390x/wasm/load_store_static_kind_i32_index_0xffffffff_guard_yes_spectre_i8_access_0xffff0000_offset.wat
index 99282dbdc..a66de6355 100644
--- a/cranelift/filetests/filetests/isa/s390x/wasm/load_store_static_kind_i32_index_0xffffffff_guard_yes_spectre_i8_access_0xffff0000_offset.wat
+++ b/cranelift/filetests/filetests/isa/s390x/wasm/load_store_static_kind_i32_index_0xffffffff_guard_yes_spectre_i8_access_0xffff0000_offset.wat
@@ -41,10 +41,10 @@
 ;;   unwind DefineNewFrame { offset_upward_to_caller_sp: 160, offset_downward_to_clobbers: 0 }
 ;;   unwind StackAlloc { size: 0 }
 ;; block0:
-;;   trap
+;;   .word 0x0000 # trap=heap_oob
 ;;
 ;; function u0:1:
 ;;   unwind DefineNewFrame { offset_upward_to_caller_sp: 160, offset_downward_to_clobbers: 0 }
 ;;   unwind StackAlloc { size: 0 }
 ;; block0:
-;;   trap
\ No newline at end of file
+;;   .word 0x0000 # trap=heap_oob
diff --git a/cranelift/filetests/filetests/isa/s390x/wasm/load_store_static_kind_i64_index_0_guard_no_spectre_i32_access_0_offset.wat b/cranelift/filetests/filetests/isa/s390x/wasm/load_store_static_kind_i64_index_0_guard_no_spectre_i32_access_0_offset.wat
index 75df18787..ac557b60a 100644
--- a/cranelift/filetests/filetests/isa/s390x/wasm/load_store_static_kind_i64_index_0_guard_no_spectre_i32_access_0_offset.wat
+++ b/cranelift/filetests/filetests/isa/s390x/wasm/load_store_static_kind_i64_index_0_guard_no_spectre_i32_access_0_offset.wat
@@ -50,7 +50,7 @@
 ;; block2:
 ;;   br %r14
 ;; block3:
-;;   trap
+;;   .word 0x0000 # trap=heap_oob
 ;;
 ;; function u0:1:
 ;;   unwind DefineNewFrame { offset_upward_to_caller_sp: 160, offset_downward_to_clobbers: 0 }
@@ -65,4 +65,4 @@
 ;; block2:
 ;;   br %r14
 ;; block3:
-;;   trap
+;;   .word 0x0000 # trap=heap_oob
diff --git a/cranelift/filetests/filetests/isa/s390x/wasm/load_store_static_kind_i64_index_0_guard_no_spectre_i32_access_0x1000_offset.wat b/cranelift/filetests/filetests/isa/s390x/wasm/load_store_static_kind_i64_index_0_guard_no_spectre_i32_access_0x1000_offset.wat
index 6a0cc56bb..23b2ddf63 100644
--- a/cranelift/filetests/filetests/isa/s390x/wasm/load_store_static_kind_i64_index_0_guard_no_spectre_i32_access_0x1000_offset.wat
+++ b/cranelift/filetests/filetests/isa/s390x/wasm/load_store_static_kind_i64_index_0_guard_no_spectre_i32_access_0x1000_offset.wat
@@ -52,7 +52,7 @@
 ;; block2:
 ;;   br %r14
 ;; block3:
-;;   trap
+;;   .word 0x0000 # trap=heap_oob
 ;;
 ;; function u0:1:
 ;;   unwind DefineNewFrame { offset_upward_to_caller_sp: 160, offset_downward_to_clobbers: 0 }
@@ -69,4 +69,4 @@
 ;; block2:
 ;;   br %r14
 ;; block3:
-;;   trap
+;;   .word 0x0000 # trap=heap_oob
diff --git a/cranelift/filetests/filetests/isa/s390x/wasm/load_store_static_kind_i64_index_0_guard_no_spectre_i32_access_0xffff0000_offset.wat b/cranelift/filetests/filetests/isa/s390x/wasm/load_store_static_kind_i64_index_0_guard_no_spectre_i32_access_0xffff0000_offset.wat
index 3e7443260..be3e0b57a 100644
--- a/cranelift/filetests/filetests/isa/s390x/wasm/load_store_static_kind_i64_index_0_guard_no_spectre_i32_access_0xffff0000_offset.wat
+++ b/cranelift/filetests/filetests/isa/s390x/wasm/load_store_static_kind_i64_index_0_guard_no_spectre_i32_access_0xffff0000_offset.wat
@@ -41,10 +41,10 @@
 ;;   unwind DefineNewFrame { offset_upward_to_caller_sp: 160, offset_downward_to_clobbers: 0 }
 ;;   unwind StackAlloc { size: 0 }
 ;; block0:
-;;   trap
+;;   .word 0x0000 # trap=heap_oob
 ;;
 ;; function u0:1:
 ;;   unwind DefineNewFrame { offset_upward_to_caller_sp: 160, offset_downward_to_clobbers: 0 }
 ;;   unwind StackAlloc { size: 0 }
 ;; block0:
-;;   trap
\ No newline at end of file
+;;   .word 0x0000 # trap=heap_oob
diff --git a/cranelift/filetests/filetests/isa/s390x/wasm/load_store_static_kind_i64_index_0_guard_no_spectre_i8_access_0_offset.wat b/cranelift/filetests/filetests/isa/s390x/wasm/load_store_static_kind_i64_index_0_guard_no_spectre_i8_access_0_offset.wat
index 939fa2008..66f1a626f 100644
--- a/cranelift/filetests/filetests/isa/s390x/wasm/load_store_static_kind_i64_index_0_guard_no_spectre_i8_access_0_offset.wat
+++ b/cranelift/filetests/filetests/isa/s390x/wasm/load_store_static_kind_i64_index_0_guard_no_spectre_i8_access_0_offset.wat
@@ -50,7 +50,7 @@
 ;; block2:
 ;;   br %r14
 ;; block3:
-;;   trap
+;;   .word 0x0000 # trap=heap_oob
 ;;
 ;; function u0:1:
 ;;   unwind DefineNewFrame { offset_upward_to_caller_sp: 160, offset_downward_to_clobbers: 0 }
@@ -65,4 +65,4 @@
 ;; block2:
 ;;   br %r14
 ;; block3:
-;;   trap
+;;   .word 0x0000 # trap=heap_oob
diff --git a/cranelift/filetests/filetests/isa/s390x/wasm/load_store_static_kind_i64_index_0_guard_no_spectre_i8_access_0x1000_offset.wat b/cranelift/filetests/filetests/isa/s390x/wasm/load_store_static_kind_i64_index_0_guard_no_spectre_i8_access_0x1000_offset.wat
index dac7fdc73..19cdeed46 100644
--- a/cranelift/filetests/filetests/isa/s390x/wasm/load_store_static_kind_i64_index_0_guard_no_spectre_i8_access_0x1000_offset.wat
+++ b/cranelift/filetests/filetests/isa/s390x/wasm/load_store_static_kind_i64_index_0_guard_no_spectre_i8_access_0x1000_offset.wat
@@ -52,7 +52,7 @@
 ;; block2:
 ;;   br %r14
 ;; block3:
-;;   trap
+;;   .word 0x0000 # trap=heap_oob
 ;;
 ;; function u0:1:
 ;;   unwind DefineNewFrame { offset_upward_to_caller_sp: 160, offset_downward_to_clobbers: 0 }
@@ -69,4 +69,4 @@
 ;; block2:
 ;;   br %r14
 ;; block3:
-;;   trap
+;;   .word 0x0000 # trap=heap_oob
diff --git a/cranelift/filetests/filetests/isa/s390x/wasm/load_store_static_kind_i64_index_0_guard_no_spectre_i8_access_0xffff0000_offset.wat b/cranelift/filetests/filetests/isa/s390x/wasm/load_store_static_kind_i64_index_0_guard_no_spectre_i8_access_0xffff0000_offset.wat
index f6265c4a6..2a0585aaa 100644
--- a/cranelift/filetests/filetests/isa/s390x/wasm/load_store_static_kind_i64_index_0_guard_no_spectre_i8_access_0xffff0000_offset.wat
+++ b/cranelift/filetests/filetests/isa/s390x/wasm/load_store_static_kind_i64_index_0_guard_no_spectre_i8_access_0xffff0000_offset.wat
@@ -41,10 +41,10 @@
 ;;   unwind DefineNewFrame { offset_upward_to_caller_sp: 160, offset_downward_to_clobbers: 0 }
 ;;   unwind StackAlloc { size: 0 }
 ;; block0:
-;;   trap
+;;   .word 0x0000 # trap=heap_oob
 ;;
 ;; function u0:1:
 ;;   unwind DefineNewFrame { offset_upward_to_caller_sp: 160, offset_downward_to_clobbers: 0 }
 ;;   unwind StackAlloc { size: 0 }
 ;; block0:
-;;   trap
\ No newline at end of file
+;;   .word 0x0000 # trap=heap_oob
diff --git a/cranelift/filetests/filetests/isa/s390x/wasm/load_store_static_kind_i64_index_0_guard_yes_spectre_i32_access_0xffff0000_offset.wat b/cranelift/filetests/filetests/isa/s390x/wasm/load_store_static_kind_i64_index_0_guard_yes_spectre_i32_access_0xffff0000_offset.wat
index ce99d89d1..99cd316b7 100644
--- a/cranelift/filetests/filetests/isa/s390x/wasm/load_store_static_kind_i64_index_0_guard_yes_spectre_i32_access_0xffff0000_offset.wat
+++ b/cranelift/filetests/filetests/isa/s390x/wasm/load_store_static_kind_i64_index_0_guard_yes_spectre_i32_access_0xffff0000_offset.wat
@@ -41,10 +41,10 @@
 ;;   unwind DefineNewFrame { offset_upward_to_caller_sp: 160, offset_downward_to_clobbers: 0 }
 ;;   unwind StackAlloc { size: 0 }
 ;; block0:
-;;   trap
+;;   .word 0x0000 # trap=heap_oob
 ;;
 ;; function u0:1:
 ;;   unwind DefineNewFrame { offset_upward_to_caller_sp: 160, offset_downward_to_clobbers: 0 }
 ;;   unwind StackAlloc { size: 0 }
 ;; block0:
-;;   trap
\ No newline at end of file
+;;   .word 0x0000 # trap=heap_oob
diff --git a/cranelift/filetests/filetests/isa/s390x/wasm/load_store_static_kind_i64_index_0_guard_yes_spectre_i8_access_0xffff0000_offset.wat b/cranelift/filetests/filetests/isa/s390x/wasm/load_store_static_kind_i64_index_0_guard_yes_spectre_i8_access_0xffff0000_offset.wat
index 12c007b40..aa942f5c2 100644
--- a/cranelift/filetests/filetests/isa/s390x/wasm/load_store_static_kind_i64_index_0_guard_yes_spectre_i8_access_0xffff0000_offset.wat
+++ b/cranelift/filetests/filetests/isa/s390x/wasm/load_store_static_kind_i64_index_0_guard_yes_spectre_i8_access_0xffff0000_offset.wat
@@ -41,10 +41,10 @@
 ;;   unwind DefineNewFrame { offset_upward_to_caller_sp: 160, offset_downward_to_clobbers: 0 }
 ;;   unwind StackAlloc { size: 0 }
 ;; block0:
-;;   trap
+;;   .word 0x0000 # trap=heap_oob
 ;;
 ;; function u0:1:
 ;;   unwind DefineNewFrame { offset_upward_to_caller_sp: 160, offset_downward_to_clobbers: 0 }
 ;;   unwind StackAlloc { size: 0 }
 ;; block0:
-;;   trap
\ No newline at end of file
+;;   .word 0x0000 # trap=heap_oob
diff --git a/cranelift/filetests/filetests/isa/s390x/wasm/load_store_static_kind_i64_index_0xffffffff_guard_no_spectre_i32_access_0_offset.wat b/cranelift/filetests/filetests/isa/s390x/wasm/load_store_static_kind_i64_index_0xffffffff_guard_no_spectre_i32_access_0_offset.wat
index 7a8607456..2e53bc16d 100644
--- a/cranelift/filetests/filetests/isa/s390x/wasm/load_store_static_kind_i64_index_0xffffffff_guard_no_spectre_i32_access_0_offset.wat
+++ b/cranelift/filetests/filetests/isa/s390x/wasm/load_store_static_kind_i64_index_0xffffffff_guard_no_spectre_i32_access_0_offset.wat
@@ -50,7 +50,7 @@
 ;; block2:
 ;;   br %r14
 ;; block3:
-;;   trap
+;;   .word 0x0000 # trap=heap_oob
 ;;
 ;; function u0:1:
 ;;   unwind DefineNewFrame { offset_upward_to_caller_sp: 160, offset_downward_to_clobbers: 0 }
@@ -65,4 +65,4 @@
 ;; block2:
 ;;   br %r14
 ;; block3:
-;;   trap
+;;   .word 0x0000 # trap=heap_oob
diff --git a/cranelift/filetests/filetests/isa/s390x/wasm/load_store_static_kind_i64_index_0xffffffff_guard_no_spectre_i32_access_0x1000_offset.wat b/cranelift/filetests/filetests/isa/s390x/wasm/load_store_static_kind_i64_index_0xffffffff_guard_no_spectre_i32_access_0x1000_offset.wat
index 99cfa8102..46fb88b46 100644
--- a/cranelift/filetests/filetests/isa/s390x/wasm/load_store_static_kind_i64_index_0xffffffff_guard_no_spectre_i32_access_0x1000_offset.wat
+++ b/cranelift/filetests/filetests/isa/s390x/wasm/load_store_static_kind_i64_index_0xffffffff_guard_no_spectre_i32_access_0x1000_offset.wat
@@ -52,7 +52,7 @@
 ;; block2:
 ;;   br %r14
 ;; block3:
-;;   trap
+;;   .word 0x0000 # trap=heap_oob
 ;;
 ;; function u0:1:
 ;;   unwind DefineNewFrame { offset_upward_to_caller_sp: 160, offset_downward_to_clobbers: 0 }
@@ -69,4 +69,4 @@
 ;; block2:
 ;;   br %r14
 ;; block3:
-;;   trap
+;;   .word 0x0000 # trap=heap_oob
diff --git a/cranelift/filetests/filetests/isa/s390x/wasm/load_store_static_kind_i64_index_0xffffffff_guard_no_spectre_i32_access_0xffff0000_offset.wat b/cranelift/filetests/filetests/isa/s390x/wasm/load_store_static_kind_i64_index_0xffffffff_guard_no_spectre_i32_access_0xffff0000_offset.wat
index ca723b335..79d407bf5 100644
--- a/cranelift/filetests/filetests/isa/s390x/wasm/load_store_static_kind_i64_index_0xffffffff_guard_no_spectre_i32_access_0xffff0000_offset.wat
+++ b/cranelift/filetests/filetests/isa/s390x/wasm/load_store_static_kind_i64_index_0xffffffff_guard_no_spectre_i32_access_0xffff0000_offset.wat
@@ -41,10 +41,10 @@
 ;;   unwind DefineNewFrame { offset_upward_to_caller_sp: 160, offset_downward_to_clobbers: 0 }
 ;;   unwind StackAlloc { size: 0 }
 ;; block0:
-;;   trap
+;;   .word 0x0000 # trap=heap_oob
 ;;
 ;; function u0:1:
 ;;   unwind DefineNewFrame { offset_upward_to_caller_sp: 160, offset_downward_to_clobbers: 0 }
 ;;   unwind StackAlloc { size: 0 }
 ;; block0:
-;;   trap
\ No newline at end of file
+;;   .word 0x0000 # trap=heap_oob
diff --git a/cranelift/filetests/filetests/isa/s390x/wasm/load_store_static_kind_i64_index_0xffffffff_guard_no_spectre_i8_access_0_offset.wat b/cranelift/filetests/filetests/isa/s390x/wasm/load_store_static_kind_i64_index_0xffffffff_guard_no_spectre_i8_access_0_offset.wat
index b0f253d5c..4c98b41e5 100644
--- a/cranelift/filetests/filetests/isa/s390x/wasm/load_store_static_kind_i64_index_0xffffffff_guard_no_spectre_i8_access_0_offset.wat
+++ b/cranelift/filetests/filetests/isa/s390x/wasm/load_store_static_kind_i64_index_0xffffffff_guard_no_spectre_i8_access_0_offset.wat
@@ -50,7 +50,7 @@
 ;; block2:
 ;;   br %r14
 ;; block3:
-;;   trap
+;;   .word 0x0000 # trap=heap_oob
 ;;
 ;; function u0:1:
 ;;   unwind DefineNewFrame { offset_upward_to_caller_sp: 160, offset_downward_to_clobbers: 0 }
@@ -65,4 +65,4 @@
 ;; block2:
 ;;   br %r14
 ;; block3:
-;;   trap
+;;   .word 0x0000 # trap=heap_oob
diff --git a/cranelift/filetests/filetests/isa/s390x/wasm/load_store_static_kind_i64_index_0xffffffff_guard_no_spectre_i8_access_0x1000_offset.wat b/cranelift/filetests/filetests/isa/s390x/wasm/load_store_static_kind_i64_index_0xffffffff_guard_no_spectre_i8_access_0x1000_offset.wat
index 367b7a519..db9cf08ae 100644
--- a/cranelift/filetests/filetests/isa/s390x/wasm/load_store_static_kind_i64_index_0xffffffff_guard_no_spectre_i8_access_0x1000_offset.wat
+++ b/cranelift/filetests/filetests/isa/s390x/wasm/load_store_static_kind_i64_index_0xffffffff_guard_no_spectre_i8_access_0x1000_offset.wat
@@ -52,7 +52,7 @@
 ;; block2:
 ;;   br %r14
 ;; block3:
-;;   trap
+;;   .word 0x0000 # trap=heap_oob
 ;;
 ;; function u0:1:
 ;;   unwind DefineNewFrame { offset_upward_to_caller_sp: 160, offset_downward_to_clobbers: 0 }
@@ -69,4 +69,4 @@
 ;; block2:
 ;;   br %r14
 ;; block3:
-;;   trap
+;;   .word 0x0000 # trap=heap_oob
diff --git a/cranelift/filetests/filetests/isa/s390x/wasm/load_store_static_kind_i64_index_0xffffffff_guard_no_spectre_i8_access_0xffff0000_offset.wat b/cranelift/filetests/filetests/isa/s390x/wasm/load_store_static_kind_i64_index_0xffffffff_guard_no_spectre_i8_access_0xffff0000_offset.wat
index 93a0dc186..c154ac31a 100644
--- a/cranelift/filetests/filetests/isa/s390x/wasm/load_store_static_kind_i64_index_0xffffffff_guard_no_spectre_i8_access_0xffff0000_offset.wat
+++ b/cranelift/filetests/filetests/isa/s390x/wasm/load_store_static_kind_i64_index_0xffffffff_guard_no_spectre_i8_access_0xffff0000_offset.wat
@@ -41,10 +41,10 @@
 ;;   unwind DefineNewFrame { offset_upward_to_caller_sp: 160, offset_downward_to_clobbers: 0 }
 ;;   unwind StackAlloc { size: 0 }
 ;; block0:
-;;   trap
+;;   .word 0x0000 # trap=heap_oob
 ;;
 ;; function u0:1:
 ;;   unwind DefineNewFrame { offset_upward_to_caller_sp: 160, offset_downward_to_clobbers: 0 }
 ;;   unwind StackAlloc { size: 0 }
 ;; block0:
-;;   trap
\ No newline at end of file
+;;   .word 0x0000 # trap=heap_oob
diff --git a/cranelift/filetests/filetests/isa/s390x/wasm/load_store_static_kind_i64_index_0xffffffff_guard_yes_spectre_i32_access_0xffff0000_offset.wat b/cranelift/filetests/filetests/isa/s390x/wasm/load_store_static_kind_i64_index_0xffffffff_guard_yes_spectre_i32_access_0xffff0000_offset.wat
index 59a805178..a346794bc 100644
--- a/cranelift/filetests/filetests/isa/s390x/wasm/load_store_static_kind_i64_index_0xffffffff_guard_yes_spectre_i32_access_0xffff0000_offset.wat
+++ b/cranelift/filetests/filetests/isa/s390x/wasm/load_store_static_kind_i64_index_0xffffffff_guard_yes_spectre_i32_access_0xffff0000_offset.wat
@@ -41,10 +41,10 @@
 ;;   unwind DefineNewFrame { offset_upward_to_caller_sp: 160, offset_downward_to_clobbers: 0 }
 ;;   unwind StackAlloc { size: 0 }
 ;; block0:
-;;   trap
+;;   .word 0x0000 # trap=heap_oob
 ;;
 ;; function u0:1:
 ;;   unwind DefineNewFrame { offset_upward_to_caller_sp: 160, offset_downward_to_clobbers: 0 }
 ;;   unwind StackAlloc { size: 0 }
 ;; block0:
-;;   trap
\ No newline at end of file
+;;   .word 0x0000 # trap=heap_oob
diff --git a/cranelift/filetests/filetests/isa/s390x/wasm/load_store_static_kind_i64_index_0xffffffff_guard_yes_spectre_i8_access_0xffff0000_offset.wat b/cranelift/filetests/filetests/isa/s390x/wasm/load_store_static_kind_i64_index_0xffffffff_guard_yes_spectre_i8_access_0xffff0000_offset.wat
index f9ef02672..f69fb1447 100644
--- a/cranelift/filetests/filetests/isa/s390x/wasm/load_store_static_kind_i64_index_0xffffffff_guard_yes_spectre_i8_access_0xffff0000_offset.wat
+++ b/cranelift/filetests/filetests/isa/s390x/wasm/load_store_static_kind_i64_index_0xffffffff_guard_yes_spectre_i8_access_0xffff0000_offset.wat
@@ -41,10 +41,10 @@
 ;;   unwind DefineNewFrame { offset_upward_to_caller_sp: 160, offset_downward_to_clobbers: 0 }
 ;;   unwind StackAlloc { size: 0 }
 ;; block0:
-;;   trap
+;;   .word 0x0000 # trap=heap_oob
 ;;
 ;; function u0:1:
 ;;   unwind DefineNewFrame { offset_upward_to_caller_sp: 160, offset_downward_to_clobbers: 0 }
 ;;   unwind StackAlloc { size: 0 }
 ;; block0:
-;;   trap
\ No newline at end of file
+;;   .word 0x0000 # trap=heap_oob
diff --git a/cranelift/filetests/filetests/isa/x64/branches.clif b/cranelift/filetests/filetests/isa/x64/branches.clif
index bdaf6b5b6..f5ef0c709 100644
--- a/cranelift/filetests/filetests/isa/x64/branches.clif
+++ b/cranelift/filetests/filetests/isa/x64/branches.clif
@@ -383,7 +383,7 @@ block2:
 ;   pushq   %rbp
 ;   movq    %rsp, %rbp
 ; block0:
-;   cmpq    $0, %rdi
+;   testq   %rdi, %rdi
 ;   jl      label2; j label1
 ; block1:
 ;   xorl    %eax, %eax, %eax
@@ -401,14 +401,14 @@ block2:
 ;   pushq %rbp
 ;   movq %rsp, %rbp
 ; block1: ; offset 0x4
-;   cmpq $0, %rdi
-;   jl 0x15
-; block2: ; offset 0xe
+;   testq %rdi, %rdi
+;   jl 0x14
+; block2: ; offset 0xd
 ;   xorl %eax, %eax
 ;   movq %rbp, %rsp
 ;   popq %rbp
 ;   retq
-; block3: ; offset 0x15
+; block3: ; offset 0x14
 ;   movl $1, %eax
 ;   movq %rbp, %rsp
 ;   popq %rbp
@@ -431,7 +431,7 @@ block2:
 ;   pushq   %rbp
 ;   movq    %rsp, %rbp
 ; block0:
-;   cmpl    $0, %edi
+;   testl   %edi, %edi
 ;   jl      label2; j label1
 ; block1:
 ;   xorl    %eax, %eax, %eax
@@ -449,8 +449,152 @@ block2:
 ;   pushq %rbp
 ;   movq %rsp, %rbp
 ; block1: ; offset 0x4
-;   cmpl $0, %edi
-;   jl 0x14
+;   testl %edi, %edi
+;   jl 0x13
+; block2: ; offset 0xc
+;   xorl %eax, %eax
+;   movq %rbp, %rsp
+;   popq %rbp
+;   retq
+; block3: ; offset 0x13
+;   movl $1, %eax
+;   movq %rbp, %rsp
+;   popq %rbp
+;   retq
+
+function %f8(i64) -> i8 {
+block0(v0: i64):
+  v1 = iconst.i64 0
+  v2 = icmp eq v0, v1
+  brif v2, block1, block2
+block1:
+  v3 = iconst.i8 1
+  return v3
+block2:
+  v4 = iconst.i8 0
+  return v4
+}
+
+; VCode:
+;   pushq   %rbp
+;   movq    %rsp, %rbp
+; block0:
+;   testq   %rdi, %rdi
+;   jz      label2; j label1
+; block1:
+;   xorl    %eax, %eax, %eax
+;   movq    %rbp, %rsp
+;   popq    %rbp
+;   ret
+; block2:
+;   movl    $1, %eax
+;   movq    %rbp, %rsp
+;   popq    %rbp
+;   ret
+; 
+; Disassembled:
+; block0: ; offset 0x0
+;   pushq %rbp
+;   movq %rsp, %rbp
+; block1: ; offset 0x4
+;   testq %rdi, %rdi
+;   je 0x14
+; block2: ; offset 0xd
+;   xorl %eax, %eax
+;   movq %rbp, %rsp
+;   popq %rbp
+;   retq
+; block3: ; offset 0x14
+;   movl $1, %eax
+;   movq %rbp, %rsp
+;   popq %rbp
+;   retq
+
+function %f9(i32) -> i8 {
+block0(v0: i32):
+  v1 = iconst.i32 0
+  v2 = icmp eq v0, v1
+  brif v2, block1, block2
+block1:
+  v3 = iconst.i8 1
+  return v3
+block2:
+  v4 = iconst.i8 0
+  return v4
+}
+
+; VCode:
+;   pushq   %rbp
+;   movq    %rsp, %rbp
+; block0:
+;   testl   %edi, %edi
+;   jz      label2; j label1
+; block1:
+;   xorl    %eax, %eax, %eax
+;   movq    %rbp, %rsp
+;   popq    %rbp
+;   ret
+; block2:
+;   movl    $1, %eax
+;   movq    %rbp, %rsp
+;   popq    %rbp
+;   ret
+; 
+; Disassembled:
+; block0: ; offset 0x0
+;   pushq %rbp
+;   movq %rsp, %rbp
+; block1: ; offset 0x4
+;   testl %edi, %edi
+;   je 0x13
+; block2: ; offset 0xc
+;   xorl %eax, %eax
+;   movq %rbp, %rsp
+;   popq %rbp
+;   retq
+; block3: ; offset 0x13
+;   movl $1, %eax
+;   movq %rbp, %rsp
+;   popq %rbp
+;   retq
+
+function %f10(i64) -> i8 {
+block0(v0: i64):
+  v1 = iconst.i64 0
+  v2 = icmp slt v1, v0
+  brif v2, block1, block2
+block1:
+  v3 = iconst.i8 1
+  return v3
+block2:
+  v4 = iconst.i8 0
+  return v4
+}
+
+; VCode:
+;   pushq   %rbp
+;   movq    %rsp, %rbp
+; block0:
+;   testq   %rdi, %rdi
+;   jnle    label2; j label1
+; block1:
+;   xorl    %eax, %eax, %eax
+;   movq    %rbp, %rsp
+;   popq    %rbp
+;   ret
+; block2:
+;   movl    $1, %eax
+;   movq    %rbp, %rsp
+;   popq    %rbp
+;   ret
+; 
+; Disassembled:
+; block0: ; offset 0x0
+;   pushq %rbp
+;   movq %rsp, %rbp
+; block1: ; offset 0x4
+;   testq %rdi, %rdi
+;   jg 0x14
 ; block2: ; offset 0xd
 ;   xorl %eax, %eax
 ;   movq %rbp, %rsp
diff --git a/cranelift/filetests/filetests/isa/x64/ceil-avx.clif b/cranelift/filetests/filetests/isa/x64/ceil-avx.clif
new file mode 100644
index 000000000..cee651622
--- /dev/null
+++ b/cranelift/filetests/filetests/isa/x64/ceil-avx.clif
@@ -0,0 +1,104 @@
+test compile precise-output
+set enable_simd
+target x86_64 has_avx
+
+function %f1(f32) -> f32 {
+block0(v0: f32):
+  v1 = ceil v0
+  return v1
+}
+
+; VCode:
+;   pushq   %rbp
+;   movq    %rsp, %rbp
+; block0:
+;   vroundss $2, %xmm0, %xmm0
+;   movq    %rbp, %rsp
+;   popq    %rbp
+;   ret
+; 
+; Disassembled:
+; block0: ; offset 0x0
+;   pushq %rbp
+;   movq %rsp, %rbp
+; block1: ; offset 0x4
+;   vroundss $2, %xmm0, %xmm0, %xmm0
+;   movq %rbp, %rsp
+;   popq %rbp
+;   retq
+
+function %f2(f64) -> f64 {
+block0(v0: f64):
+  v1 = ceil v0
+  return v1
+}
+
+; VCode:
+;   pushq   %rbp
+;   movq    %rsp, %rbp
+; block0:
+;   vroundsd $2, %xmm0, %xmm0
+;   movq    %rbp, %rsp
+;   popq    %rbp
+;   ret
+; 
+; Disassembled:
+; block0: ; offset 0x0
+;   pushq %rbp
+;   movq %rsp, %rbp
+; block1: ; offset 0x4
+;   vroundsd $2, %xmm0, %xmm0, %xmm0
+;   movq %rbp, %rsp
+;   popq %rbp
+;   retq
+
+function %f4(f32x4) -> f32x4 {
+block0(v0: f32x4):
+  v1 = ceil v0
+  return v1
+}
+
+; VCode:
+;   pushq   %rbp
+;   movq    %rsp, %rbp
+; block0:
+;   vroundps $2, %xmm0, %xmm0
+;   movq    %rbp, %rsp
+;   popq    %rbp
+;   ret
+; 
+; Disassembled:
+; block0: ; offset 0x0
+;   pushq %rbp
+;   movq %rsp, %rbp
+; block1: ; offset 0x4
+;   vroundps $2, %xmm0, %xmm0
+;   movq %rbp, %rsp
+;   popq %rbp
+;   retq
+
+function %f4(f64x2) -> f64x2 {
+block0(v0: f64x2):
+  v1 = ceil v0
+  return v1
+}
+
+; VCode:
+;   pushq   %rbp
+;   movq    %rsp, %rbp
+; block0:
+;   vroundpd $2, %xmm0, %xmm0
+;   movq    %rbp, %rsp
+;   popq    %rbp
+;   ret
+; 
+; Disassembled:
+; block0: ; offset 0x0
+;   pushq %rbp
+;   movq %rsp, %rbp
+; block1: ; offset 0x4
+;   vroundpd $2, %xmm0, %xmm0
+;   movq %rbp, %rsp
+;   popq %rbp
+;   retq
+
diff --git a/cranelift/filetests/filetests/isa/x64/cmp-mem-bug.clif b/cranelift/filetests/filetests/isa/x64/cmp-mem-bug.clif
index 459302beb..a7996bdab 100644
--- a/cranelift/filetests/filetests/isa/x64/cmp-mem-bug.clif
+++ b/cranelift/filetests/filetests/isa/x64/cmp-mem-bug.clif
@@ -60,10 +60,10 @@ block0(v0: f64, v1: i64):
 ;   setz    %al
 ;   andl    %edi, %eax, %edi
 ;   movzbq  %dil, %rax
-;   ucomisd %xmm0, %xmm9
+;   ucomisd %xmm9, %xmm0
 ;   movdqa  %xmm0, %xmm2
-;   mov z, sd; j%xmm2 $next; mov%xmm0 %xmm0, %xmm0; $next: 
-;   mov np, sd; j%xmm2 $next; mov%xmm0 %xmm0, %xmm0; $next: 
+;   movsd %xmm0, %xmm0; jnp $next; movsd %xmm2, %xmm0; $next:
+;   movsd %xmm0, %xmm0; jz $next; movsd %xmm2, %xmm0; $next:
 ;   movq    %rbp, %rsp
 ;   popq    %rbp
 ;   ret
@@ -79,11 +79,11 @@ block0(v0: f64, v1: i64):
 ;   sete %al
 ;   andl %eax, %edi
 ;   movzbq %dil, %rax
-;   ucomisd %xmm0, %xmm9
+;   ucomisd %xmm9, %xmm0
 ;   movdqa %xmm0, %xmm2
-;   je 0x2f
+;   jnp 0x2f
 ;   movsd %xmm2, %xmm0
-;   jnp 0x39
+;   je 0x39
 ;   movsd %xmm2, %xmm0
 ;   movq %rbp, %rsp
 ;   popq %rbp
diff --git a/cranelift/filetests/filetests/isa/x64/fpromote-demote-avx.clif b/cranelift/filetests/filetests/isa/x64/fpromote-demote-avx.clif
new file mode 100644
index 000000000..999d9d5ec
--- /dev/null
+++ b/cranelift/filetests/filetests/isa/x64/fpromote-demote-avx.clif
@@ -0,0 +1,130 @@
+test compile precise-output
+set enable_simd
+target x86_64 has_avx
+
+function %fpromote(f32) -> f64 {
+block0(v0: f32):
+    v1 = fpromote.f64 v0
+    return v1
+}
+
+; VCode:
+;   pushq   %rbp
+;   movq    %rsp, %rbp
+; block0:
+;   vcvtss2sd %xmm0, %xmm0
+;   movq    %rbp, %rsp
+;   popq    %rbp
+;   ret
+; 
+; Disassembled:
+; block0: ; offset 0x0
+;   pushq %rbp
+;   movq %rsp, %rbp
+; block1: ; offset 0x4
+;   vcvtss2sd %xmm0, %xmm0, %xmm0
+;   movq %rbp, %rsp
+;   popq %rbp
+;   retq
+
+function %fpromote_load(i64, f32) -> f64 {
+    ss0 = explicit_slot 16
+
+block0(v1: i64, v2: f32):
+    v3 = stack_addr.i64 ss0
+    store.f32 v2, v3
+    v4 = load.f32 v3
+    v5 = fpromote.f64 v4
+    return v5
+}
+
+; VCode:
+;   pushq   %rbp
+;   movq    %rsp, %rbp
+;   subq    %rsp, $16, %rsp
+; block0:
+;   lea     rsp(0 + virtual offset), %rdx
+;   vmovss  %xmm0, 0(%rdx)
+;   vcvtss2sd 0(%rdx), %xmm0
+;   addq    %rsp, $16, %rsp
+;   movq    %rbp, %rsp
+;   popq    %rbp
+;   ret
+; 
+; Disassembled:
+; block0: ; offset 0x0
+;   pushq %rbp
+;   movq %rsp, %rbp
+;   subq $0x10, %rsp
+; block1: ; offset 0x8
+;   leaq (%rsp), %rdx
+;   vmovss %xmm0, (%rdx) ; trap: heap_oob
+;   vcvtss2sd (%rdx), %xmm0, %xmm0 ; trap: heap_oob
+;   addq $0x10, %rsp
+;   movq %rbp, %rsp
+;   popq %rbp
+;   retq
+
+function %fdemote(f64) -> f32 {
+block0(v0: f64):
+    v1 = fdemote.f32 v0
+    return v1
+}
+
+; VCode:
+;   pushq   %rbp
+;   movq    %rsp, %rbp
+; block0:
+;   vcvtsd2ss %xmm0, %xmm0
+;   movq    %rbp, %rsp
+;   popq    %rbp
+;   ret
+; 
+; Disassembled:
+; block0: ; offset 0x0
+;   pushq %rbp
+;   movq %rsp, %rbp
+; block1: ; offset 0x4
+;   vcvtsd2ss %xmm0, %xmm0, %xmm0
+;   movq %rbp, %rsp
+;   popq %rbp
+;   retq
+
+function %fdemote_load(i64, f64) -> f32 {
+    ss0 = explicit_slot 16
+
+block0(v1: i64, v2: f64):
+    v3 = stack_addr.i64 ss0
+    store.f64 v2, v3
+    v4 = load.f64 v3
+    v5 = fdemote.f32 v4
+    return v5
+}
+
+; VCode:
+;   pushq   %rbp
+;   movq    %rsp, %rbp
+;   subq    %rsp, $16, %rsp
+; block0:
+;   lea     rsp(0 + virtual offset), %rdx
+;   vmovsd  %xmm0, 0(%rdx)
+;   vcvtsd2ss 0(%rdx), %xmm0
+;   addq    %rsp, $16, %rsp
+;   movq    %rbp, %rsp
+;   popq    %rbp
+;   ret
+; 
+; Disassembled:
+; block0: ; offset 0x0
+;   pushq %rbp
+;   movq %rsp, %rbp
+;   subq $0x10, %rsp
+; block1: ; offset 0x8
+;   leaq (%rsp), %rdx
+;   vmovsd %xmm0, (%rdx) ; trap: heap_oob
+;   vcvtsd2ss (%rdx), %xmm0, %xmm0 ; trap: heap_oob
+;   addq $0x10, %rsp
+;   movq %rbp, %rsp
+;   popq %rbp
+;   retq
+
diff --git a/cranelift/filetests/filetests/isa/x64/fpromote-demote.clif b/cranelift/filetests/filetests/isa/x64/fpromote-demote.clif
new file mode 100644
index 000000000..3f6cf72e3
--- /dev/null
+++ b/cranelift/filetests/filetests/isa/x64/fpromote-demote.clif
@@ -0,0 +1,130 @@
+test compile precise-output
+set enable_simd
+target x86_64
+
+function %fpromote(f32) -> f64 {
+block0(v0: f32):
+    v1 = fpromote.f64 v0
+    return v1
+}
+
+; VCode:
+;   pushq   %rbp
+;   movq    %rsp, %rbp
+; block0:
+;   cvtss2sd %xmm0, %xmm0
+;   movq    %rbp, %rsp
+;   popq    %rbp
+;   ret
+; 
+; Disassembled:
+; block0: ; offset 0x0
+;   pushq %rbp
+;   movq %rsp, %rbp
+; block1: ; offset 0x4
+;   cvtss2sd %xmm0, %xmm0
+;   movq %rbp, %rsp
+;   popq %rbp
+;   retq
+
+function %fpromote_load(i64, f32) -> f64 {
+    ss0 = explicit_slot 16
+
+block0(v1: i64, v2: f32):
+    v3 = stack_addr.i64 ss0
+    store.f32 v2, v3
+    v4 = load.f32 v3
+    v5 = fpromote.f64 v4
+    return v5
+}
+
+; VCode:
+;   pushq   %rbp
+;   movq    %rsp, %rbp
+;   subq    %rsp, $16, %rsp
+; block0:
+;   lea     rsp(0 + virtual offset), %rdx
+;   movss   %xmm0, 0(%rdx)
+;   cvtss2sd 0(%rdx), %xmm0
+;   addq    %rsp, $16, %rsp
+;   movq    %rbp, %rsp
+;   popq    %rbp
+;   ret
+; 
+; Disassembled:
+; block0: ; offset 0x0
+;   pushq %rbp
+;   movq %rsp, %rbp
+;   subq $0x10, %rsp
+; block1: ; offset 0x8
+;   leaq (%rsp), %rdx
+;   movss %xmm0, (%rdx) ; trap: heap_oob
+;   cvtss2sd (%rdx), %xmm0 ; trap: heap_oob
+;   addq $0x10, %rsp
+;   movq %rbp, %rsp
+;   popq %rbp
+;   retq
+
+function %fdemote(f64) -> f32 {
+block0(v0: f64):
+    v1 = fdemote.f32 v0
+    return v1
+}
+
+; VCode:
+;   pushq   %rbp
+;   movq    %rsp, %rbp
+; block0:
+;   cvtsd2ss %xmm0, %xmm0
+;   movq    %rbp, %rsp
+;   popq    %rbp
+;   ret
+; 
+; Disassembled:
+; block0: ; offset 0x0
+;   pushq %rbp
+;   movq %rsp, %rbp
+; block1: ; offset 0x4
+;   cvtsd2ss %xmm0, %xmm0
+;   movq %rbp, %rsp
+;   popq %rbp
+;   retq
+
+function %fdemote_load(i64, f64) -> f32 {
+    ss0 = explicit_slot 16
+
+block0(v1: i64, v2: f64):
+    v3 = stack_addr.i64 ss0
+    store.f64 v2, v3
+    v4 = load.f64 v3
+    v5 = fdemote.f32 v4
+    return v5
+}
+
+; VCode:
+;   pushq   %rbp
+;   movq    %rsp, %rbp
+;   subq    %rsp, $16, %rsp
+; block0:
+;   lea     rsp(0 + virtual offset), %rdx
+;   movsd   %xmm0, 0(%rdx)
+;   cvtsd2ss 0(%rdx), %xmm0
+;   addq    %rsp, $16, %rsp
+;   movq    %rbp, %rsp
+;   popq    %rbp
+;   ret
+; 
+; Disassembled:
+; block0: ; offset 0x0
+;   pushq %rbp
+;   movq %rsp, %rbp
+;   subq $0x10, %rsp
+; block1: ; offset 0x8
+;   leaq (%rsp), %rdx
+;   movsd %xmm0, (%rdx) ; trap: heap_oob
+;   cvtsd2ss (%rdx), %xmm0 ; trap: heap_oob
+;   addq $0x10, %rsp
+;   movq %rbp, %rsp
+;   popq %rbp
+;   retq
+
diff --git a/cranelift/filetests/filetests/isa/x64/fsqrt-avx.clif b/cranelift/filetests/filetests/isa/x64/fsqrt-avx.clif
new file mode 100644
index 000000000..35fb832a8
--- /dev/null
+++ b/cranelift/filetests/filetests/isa/x64/fsqrt-avx.clif
@@ -0,0 +1,54 @@
+test compile precise-output
+set enable_simd
+target x86_64 has_avx
+
+function %sqrt_f32(f32) -> f32 {
+block0(v0: f32):
+    v1 = sqrt v0
+    return v1
+}
+
+; VCode:
+;   pushq   %rbp
+;   movq    %rsp, %rbp
+; block0:
+;   vsqrtss %xmm0, %xmm0
+;   movq    %rbp, %rsp
+;   popq    %rbp
+;   ret
+; 
+; Disassembled:
+; block0: ; offset 0x0
+;   pushq %rbp
+;   movq %rsp, %rbp
+; block1: ; offset 0x4
+;   vsqrtss %xmm0, %xmm0, %xmm0
+;   movq %rbp, %rsp
+;   popq %rbp
+;   retq
+
+function %sqrt_f64(f64) -> f64 {
+block0(v0: f64):
+    v1 = sqrt v0
+    return v1
+}
+
+; VCode:
+;   pushq   %rbp
+;   movq    %rsp, %rbp
+; block0:
+;   vsqrtsd %xmm0, %xmm0
+;   movq    %rbp, %rsp
+;   popq    %rbp
+;   ret
+; 
+; Disassembled:
+; block0: ; offset 0x0
+;   pushq %rbp
+;   movq %rsp, %rbp
+; block1: ; offset 0x4
+;   vsqrtsd %xmm0, %xmm0, %xmm0
+;   movq %rbp, %rsp
+;   popq %rbp
+;   retq
+
diff --git a/cranelift/filetests/filetests/isa/x64/fsqrt.clif b/cranelift/filetests/filetests/isa/x64/fsqrt.clif
new file mode 100644
index 000000000..ffe971de1
--- /dev/null
+++ b/cranelift/filetests/filetests/isa/x64/fsqrt.clif
@@ -0,0 +1,54 @@
+test compile precise-output
+set enable_simd
+target x86_64
+
+function %sqrt_f32(f32) -> f32 {
+block0(v0: f32):
+    v1 = sqrt v0
+    return v1
+}
+
+; VCode:
+;   pushq   %rbp
+;   movq    %rsp, %rbp
+; block0:
+;   sqrtss  %xmm0, %xmm0
+;   movq    %rbp, %rsp
+;   popq    %rbp
+;   ret
+; 
+; Disassembled:
+; block0: ; offset 0x0
+;   pushq %rbp
+;   movq %rsp, %rbp
+; block1: ; offset 0x4
+;   sqrtss %xmm0, %xmm0
+;   movq %rbp, %rsp
+;   popq %rbp
+;   retq
+
+function %sqrt_f64(f64) -> f64 {
+block0(v0: f64):
+    v1 = sqrt v0
+    return v1
+}
+
+; VCode:
+;   pushq   %rbp
+;   movq    %rsp, %rbp
+; block0:
+;   sqrtsd  %xmm0, %xmm0
+;   movq    %rbp, %rsp
+;   popq    %rbp
+;   ret
+; 
+; Disassembled:
+; block0: ; offset 0x0
+;   pushq %rbp
+;   movq %rsp, %rbp
+; block1: ; offset 0x4
+;   sqrtsd %xmm0, %xmm0
+;   movq %rbp, %rsp
+;   popq %rbp
+;   retq
+
diff --git a/cranelift/filetests/filetests/isa/x64/load-op.clif b/cranelift/filetests/filetests/isa/x64/load-op.clif
index 3c4e5fde9..16931d55f 100644
--- a/cranelift/filetests/filetests/isa/x64/load-op.clif
+++ b/cranelift/filetests/filetests/isa/x64/load-op.clif
@@ -238,3 +238,33 @@ block0(v0: i64):
 ;   popq %rbp
 ;   retq
 
+function %cmp_mem_zero(i64) -> i8 {
+block0(v0: i64):
+  v1 = load.i64 v0
+  v2 = icmp_imm eq v1, 0
+  return v2
+}
+
+; VCode:
+;   pushq   %rbp
+;   movq    %rsp, %rbp
+; block0:
+;   movq    0(%rdi), %rcx
+;   testq   %rcx, %rcx
+;   setz    %al
+;   movq    %rbp, %rsp
+;   popq    %rbp
+;   ret
+; 
+; Disassembled:
+; block0: ; offset 0x0
+;   pushq %rbp
+;   movq %rsp, %rbp
+; block1: ; offset 0x4
+;   movq (%rdi), %rcx ; trap: heap_oob
+;   testq %rcx, %rcx
+;   sete %al
+;   movq %rbp, %rsp
+;   popq %rbp
+;   retq
+
diff --git a/cranelift/filetests/filetests/isa/x64/select-i128.clif b/cranelift/filetests/filetests/isa/x64/select-i128.clif
index 89576c873..035322813 100644
--- a/cranelift/filetests/filetests/isa/x64/select-i128.clif
+++ b/cranelift/filetests/filetests/isa/x64/select-i128.clif
@@ -52,11 +52,11 @@ block0(v0: f32, v1: i128, v2: i128):
 ; block0:
 ;   ucomiss %xmm0, %xmm0
 ;   movq    %rdi, %rax
-;   cmovnzq %rdx, %rax, %rax
 ;   cmovpq  %rdx, %rax, %rax
+;   cmovnzq %rdx, %rax, %rax
 ;   movq    %rsi, %rdx
-;   cmovnzq %rcx, %rdx, %rdx
 ;   cmovpq  %rcx, %rdx, %rdx
+;   cmovnzq %rcx, %rdx, %rdx
 ;   movq    %rbp, %rsp
 ;   popq    %rbp
 ;   ret
@@ -68,11 +68,11 @@ block0(v0: f32, v1: i128, v2: i128):
 ; block1: ; offset 0x4
 ;   ucomiss %xmm0, %xmm0
 ;   movq %rdi, %rax
-;   cmovneq %rdx, %rax
 ;   cmovpq %rdx, %rax
+;   cmovneq %rdx, %rax
 ;   movq %rsi, %rdx
-;   cmovneq %rcx, %rdx
 ;   cmovpq %rcx, %rdx
+;   cmovneq %rcx, %rdx
 ;   movq %rbp, %rsp
 ;   popq %rbp
 ;   retq
diff --git a/cranelift/filetests/filetests/isa/x64/select-issue-3744.clif b/cranelift/filetests/filetests/isa/x64/select-issue-3744.clif
index 2e50d6c0a..eff72d2b3 100644
--- a/cranelift/filetests/filetests/isa/x64/select-issue-3744.clif
+++ b/cranelift/filetests/filetests/isa/x64/select-issue-3744.clif
@@ -1,4 +1,4 @@
-test compile
+test compile precise-output
 target x86_64
 
 ; Check that no intervening moves are inserted when lowering `select` (see
@@ -9,8 +9,35 @@ block0(v0: f32, v1: f32):
     v3 = iconst.i32 1
     v4 = iconst.i32 0
     v5 = select v2, v3, v4
-    ; check: ucomiss
-    ; nextln: cmovnzl
-    ; nextln: cmovpl
     return v5
 }
+
+; VCode:
+;   pushq   %rbp
+;   movq    %rsp, %rbp
+; block0:
+;   movl    $1, %eax
+;   ucomiss %xmm1, %xmm0
+;   cmovpl  const(0), %eax, %eax
+;   cmovnzl const(0), %eax, %eax
+;   movq    %rbp, %rsp
+;   popq    %rbp
+;   ret
+; 
+; Disassembled:
+; block0: ; offset 0x0
+;   pushq %rbp
+;   movq %rsp, %rbp
+; block1: ; offset 0x4
+;   movl $1, %eax
+;   ucomiss %xmm1, %xmm0
+;   cmovpl 0xd(%rip), %eax
+;   cmovnel 6(%rip), %eax
+;   movq %rbp, %rsp
+;   popq %rbp
+;   retq
+;   addb %al, (%rax)
+;   addb %al, (%rax)
+;   addb %al, (%rax)
+;   addb %al, (%rax)
+
diff --git a/cranelift/filetests/filetests/isa/x64/select.clif b/cranelift/filetests/filetests/isa/x64/select.clif
index 674a01e5f..0b7445ace 100644
--- a/cranelift/filetests/filetests/isa/x64/select.clif
+++ b/cranelift/filetests/filetests/isa/x64/select.clif
@@ -44,10 +44,10 @@ block0(v0: f32, v1: f32, v2: i64, v3: i64):
 ;   pushq   %rbp
 ;   movq    %rsp, %rbp
 ; block0:
-;   ucomiss %xmm0, %xmm1
+;   ucomiss %xmm1, %xmm0
 ;   movq    %rdi, %rax
-;   cmovnzq %rsi, %rax, %rax
 ;   cmovpq  %rsi, %rax, %rax
+;   cmovnzq %rsi, %rax, %rax
 ;   movq    %rbp, %rsp
 ;   popq    %rbp
 ;   ret
@@ -57,10 +57,10 @@ block0(v0: f32, v1: f32, v2: i64, v3: i64):
 ;   pushq %rbp
 ;   movq %rsp, %rbp
 ; block1: ; offset 0x4
-;   ucomiss %xmm0, %xmm1
+;   ucomiss %xmm1, %xmm0
 ;   movq %rdi, %rax
-;   cmovneq %rsi, %rax
 ;   cmovpq %rsi, %rax
+;   cmovneq %rsi, %rax
 ;   movq %rbp, %rsp
 ;   popq %rbp
 ;   retq
diff --git a/cranelift/filetests/filetests/runtests/arithmetic-extends.clif b/cranelift/filetests/filetests/runtests/arithmetic-extends.clif
new file mode 100644
index 000000000..e8a8579b2
--- /dev/null
+++ b/cranelift/filetests/filetests/runtests/arithmetic-extends.clif
@@ -0,0 +1,235 @@
+test interpret
+test run
+target aarch64
+target s390x
+target x86_64
+target riscv64
+target riscv64 has_zba
+
+;; Various runtests intended to target the instructions encoded by the RISC-V `Zba` Extension
+;; Although other targets may also benefit from these tests and may implement similar optimizations
+
+
+function %add_uext_i32(i64, i32) -> i64 {
+block0(v0: i64, v1: i32):
+    v2 = uextend.i64 v1
+    v3 = iadd.i64 v0, v2
+    return v3
+}
+; run: %add_uext_i32(0, 0) == 0
+; run: %add_uext_i32(2, 1) == 3
+; run: %add_uext_i32(2, 0xFFFFFFFF) == 0x100000001
+
+
+function %sh1add(i64, i64) -> i64 {
+block0(v0: i64, v1: i64):
+    v2 = iconst.i64 1
+    v3 = ishl v1, v2
+    v4 = iadd.i64 v0, v3
+    return v4
+}
+; run: %sh1add(0, 0) == 0
+; run: %sh1add(2, 1) == 4
+; run: %sh1add(2, 0xFFFFFFFFFFFFFFFF) == 0
+
+
+function %sh1add_uext(i64, i32) -> i64 {
+block0(v0: i64, v1: i32):
+    v2 = uextend.i64 v1
+    v3 = iconst.i64 1
+    v4 = ishl v2, v3
+    v5 = iadd.i64 v0, v4
+    return v5
+}
+; run: %sh1add_uext(0, 0) == 0
+; run: %sh1add_uext(2, 1) == 4
+; run: %sh1add_uext(2, 0xFFFFFFFF) == 0x200000000
+; run: %sh1add_uext(0x100000000, 0x80000000) == 0x200000000
+
+
+function %sh2add(i64, i64) -> i64 {
+block0(v0: i64, v1: i64):
+    v2 = iconst.i64 2
+    v3 = ishl v1, v2
+    v4 = iadd.i64 v0, v3
+    return v4
+}
+; run: %sh2add(0, 0) == 0
+; run: %sh2add(2, 1) == 6
+; run: %sh2add(2, 0xFFFFFFFFFFFFFFFF) == 0xFFFFFFFFFFFFFFFE
+
+
+function %sh2add_uext(i64, i32) -> i64 {
+block0(v0: i64, v1: i32):
+    v2 = uextend.i64 v1
+    v3 = iconst.i64 2
+    v4 = ishl v2, v3
+    v5 = iadd.i64 v0, v4
+    return v5
+}
+; run: %sh2add_uext(0, 0) == 0
+; run: %sh2add_uext(2, 1) == 6
+; run: %sh2add_uext(4, 0xFFFFFFFF) == 0x400000000
+; run: %sh2add_uext(0x100000000, 0x80000000) == 0x300000000
+
+
+function %sh3add(i64, i64) -> i64 {
+block0(v0: i64, v1: i64):
+    v2 = iconst.i64 3
+    v3 = ishl v1, v2
+    v4 = iadd.i64 v0, v3
+    return v4
+}
+; run: %sh3add(0, 0) == 0
+; run: %sh3add(2, 1) == 10
+; run: %sh3add(2, 0xFFFFFFFFFFFFFFFF) == 0xFFFFFFFFFFFFFFFA
+
+
+function %sh3add_uext(i64, i32) -> i64 {
+block0(v0: i64, v1: i32):
+    v2 = uextend.i64 v1
+    v3 = iconst.i64 3
+    v4 = ishl v2, v3
+    v5 = iadd.i64 v0, v4
+    return v5
+}
+; run: %sh3add_uext(0, 0) == 0
+; run: %sh3add_uext(2, 1) == 10
+; run: %sh3add_uext(8, 0xFFFFFFFF) == 0x800000000
+; run: %sh3add_uext(0x100000000, 0x80000000) == 0x500000000
+
+
+function %ishl_uextend(i32) -> i64 {
+block0(v0: i32):
+    v1 = uextend.i64 v0
+    v2 = iconst.i64 5
+    v3 = ishl v1, v2
+    return v3
+}
+; run: %ishl_uextend(0) == 0
+; run: %ishl_uextend(1) == 0x20
+; run: %ishl_uextend(0xFFFFFFFF) == 0x1FFFFFFFE0
+
+
+;; These tests ensure that we don't merge the `uextend` and `ishl` instructions
+;; in a way that doesen't respect the `ishl` semantics of cutting off the high bits.
+
+function %add_uext_ishl_1(i64, i32) -> i64 {
+block0(v0: i64, v1: i32):
+    v2 = iconst.i32 1
+    v3 = ishl v1, v2
+    v4 = uextend.i64 v3
+    v5 = iadd.i64 v0, v4
+    return v5
+}
+; run: %add_uext_ishl_1(0x0123_4567, 0x8000_0000) == 0x0123_4567
+; run: %add_uext_ishl_1(0x0123_4567, 0xC000_0000) == 0x8123_4567
+; run: %add_uext_ishl_1(0x0123_4567, 0xE000_0000) == 0xC123_4567
+
+function %add_uext_ishl_2(i64, i32) -> i64 {
+block0(v0: i64, v1: i32):
+    v2 = iconst.i32 2
+    v3 = ishl v1, v2
+    v4 = uextend.i64 v3
+    v5 = iadd.i64 v0, v4
+    return v5
+}
+; run: %add_uext_ishl_2(0x0123_4567, 0x8000_0000) == 0x0123_4567
+; run: %add_uext_ishl_2(0x0123_4567, 0xC000_0000) == 0x0123_4567
+; run: %add_uext_ishl_2(0x0123_4567, 0xE000_0000) == 0x8123_4567
+
+function %add_uext_ishl_3(i64, i32) -> i64 {
+block0(v0: i64, v1: i32):
+    v2 = iconst.i32 3
+    v3 = ishl v1, v2
+    v4 = uextend.i64 v3
+    v5 = iadd.i64 v0, v4
+    return v5
+}
+; run: %add_uext_ishl_3(0x0123_4567, 0x8000_0000) == 0x0123_4567
+; run: %add_uext_ishl_3(0x0123_4567, 0xC000_0000) == 0x0123_4567
+; run: %add_uext_ishl_3(0x0123_4567, 0xE000_0000) == 0x0123_4567
+
+
+;; These tests perform the operations in 32bits but then sign extend the results to 64bits
+function %sext_add_i32(i32, i32) -> i64 {
+block0(v0: i32, v1: i32):
+    v2 = iadd.i32 v0, v1
+    v3 = sextend.i64 v2
+    return v3
+}
+; run: %sext_add_i32(1, 0) == 1
+; run: %sext_add_i32(0, -1) == -1
+
+
+function %sext_sub_i32(i32, i32) -> i64 {
+block0(v0: i32, v1: i32):
+    v2 = isub.i32 v0, v1
+    v3 = sextend.i64 v2
+    return v3
+}
+; run: %sext_sub_i32(1, 0) == 1
+; run: %sext_sub_i32(0, 1) == -1
+
+
+function %sext_ishl_i32(i32, i32) -> i64 {
+block0(v0: i32, v1: i32):
+    v2 = ishl.i32 v0, v1
+    v3 = sextend.i64 v2
+    return v3
+}
+; run: %sext_ishl_i32(1, 31) == 0xFFFFFFFF80000000
+
+function %sext_ushr_i32(i32, i32) -> i64 {
+block0(v0: i32, v1: i32):
+    v2 = ushr.i32 v0, v1
+    v3 = sextend.i64 v2
+    return v3
+}
+; run: %sext_ushr_i32(0x8000_0000, 0) == 0xFFFFFFFF80000000
+; run: %sext_ushr_i32(0x8000_0000, 32) == 0xFFFFFFFF80000000
+
+function %sext_sshr_i32(i32, i32) -> i64 {
+block0(v0: i32, v1: i32):
+    v2 = sshr.i32 v0, v1
+    v3 = sextend.i64 v2
+    return v3
+}
+; run: %sext_sshr_i32(0x8000_0000, 0) == 0xFFFFFFFF80000000
+; run: %sext_sshr_i32(0x8000_0000, 32) == 0xFFFFFFFF80000000
+
+function %sext_add_const_i32(i32) -> i64 {
+block0(v0: i32):
+    v1 = iconst.i32 -1
+    v2 = iadd.i32 v0, v1
+    v3 = sextend.i64 v2
+    return v3
+}
+; run: %sext_add_const_i32(0) == -1
+
+function %sext_ishl_const_i32(i32) -> i64 {
+block0(v0: i32):
+    v1 = iconst.i32 31
+    v2 = ishl.i32 v0, v1
+    v3 = sextend.i64 v2
+    return v3
+}
+; run: %sext_ishl_const_i32(1) == 0xFFFFFFFF80000000
+
+function %sext_ushr_const_i32(i32) -> i64 {
+block0(v0: i32):
+    v1 = iconst.i32 32
+    v2 = ushr.i32 v0, v1
+    v3 = sextend.i64 v2
+    return v3
+}
+; run: %sext_ushr_const_i32(0x8000_0000) == 0xFFFFFFFF80000000
+
+function %sext_sshr_const_i32(i32) -> i64 {
+block0(v0: i32):
+    v1 = iconst.i32 32
+    v2 = sshr.i32 v0, v1
+    v3 = sextend.i64 v2
+    return v3
+}
+; run: %sext_sshr_const_i32(0x8000_0000) == 0xFFFFFFFF80000000
diff --git a/cranelift/filetests/filetests/runtests/extend.clif b/cranelift/filetests/filetests/runtests/extend.clif
index 9c82cdcae..69a7551ee 100644
--- a/cranelift/filetests/filetests/runtests/extend.clif
+++ b/cranelift/filetests/filetests/runtests/extend.clif
@@ -4,6 +4,7 @@ target aarch64
 target s390x
 target x86_64
 target riscv64
+target riscv64 has_zba
 target riscv64 has_zbb
 target riscv64 has_zbkb
 
diff --git a/cranelift/filetests/filetests/runtests/i128-arithmetic-extends.clif b/cranelift/filetests/filetests/runtests/i128-arithmetic-extends.clif
new file mode 100644
index 000000000..406668f1c
--- /dev/null
+++ b/cranelift/filetests/filetests/runtests/i128-arithmetic-extends.clif
@@ -0,0 +1,18 @@
+test interpret
+test run
+set enable_llvm_abi_extensions=true
+target aarch64
+target s390x
+target x86_64
+target riscv64
+target riscv64 has_zba
+
+function %sext_sshr_i32_i128(i32, i128) -> i64 {
+block0(v0: i32, v1: i128):
+    v2 = sshr.i32 v0, v1
+    v3 = sextend.i64 v2
+    return v3
+}
+; run: %sext_sshr_i32_i128(0x8000_0000, 0) == 0xFFFFFFFF80000000
+; run: %sext_sshr_i32_i128(0x8000_0000, 32) == 0xFFFFFFFF80000000
+; run: %sext_sshr_i32_i128(0x8000_0000, 0xFFFFFFFF_FFFFFFFF_FFFFFFFF_FFFFFF20) == 0xFFFFFFFF80000000
diff --git a/cranelift/filetests/filetests/runtests/i128-extend.clif b/cranelift/filetests/filetests/runtests/i128-extend.clif
index 7e0b4251e..2e64d239a 100644
--- a/cranelift/filetests/filetests/runtests/i128-extend.clif
+++ b/cranelift/filetests/filetests/runtests/i128-extend.clif
@@ -5,6 +5,7 @@ target aarch64
 target s390x
 target x86_64
 target riscv64
+target riscv64 has_zba
 target riscv64 has_zbb
 target riscv64 has_zbkb
 
diff --git a/cranelift/filetests/src/subtest.rs b/cranelift/filetests/src/subtest.rs
index b34292917..5b4776700 100644
--- a/cranelift/filetests/src/subtest.rs
+++ b/cranelift/filetests/src/subtest.rs
@@ -2,13 +2,16 @@
 
 use crate::runone::FileUpdate;
 use anyhow::Context as _;
+use anyhow::{bail, Result};
 use cranelift_codegen::ir::Function;
 use cranelift_codegen::isa::TargetIsa;
 use cranelift_codegen::settings::{Flags, FlagsOrIsa};
 use cranelift_reader::{Comment, Details, TestFile};
 use filecheck::{Checker, CheckerBuilder, NO_VARIABLES};
 use log::info;
+use similar::TextDiff;
 use std::borrow::Cow;
+use std::env;
 
 /// Context for running a test on a single function.
 pub struct Context<'a> {
@@ -149,3 +152,74 @@ pub fn build_filechecker(context: &Context) -> anyhow::Result<Checker> {
     }
     Ok(builder.finish())
 }
+
+pub fn check_precise_output(actual: &[&str], context: &Context) -> Result<()> {
+    // Use the comments after the function to build the test expectation.
+    let expected = context
+        .details
+        .comments
+        .iter()
+        .filter(|c| !c.text.starts_with(";;"))
+        .map(|c| c.text.strip_prefix("; ").unwrap_or(c.text))
+        .collect::<Vec<_>>();
+
+    // If the expectation matches what we got, then there's nothing to do.
+    if actual == expected {
+        return Ok(());
+    }
+
+    // If we're supposed to automatically update the test, then do so here.
+    if env::var("CRANELIFT_TEST_BLESS").unwrap_or(String::new()) == "1" {
+        return update_test(&actual, context);
+    }
+
+    // Otherwise this test has failed, and we can print out as such.
+    bail!(
+        "compilation of function on line {} does not match\n\
+         the text expectation\n\
+         \n\
+         {}\n\
+         \n\
+         This test assertion can be automatically updated by setting the\n\
+         CRANELIFT_TEST_BLESS=1 environment variable when running this test.
+         ",
+        context.details.location.line_number,
+        TextDiff::from_slices(&expected, &actual)
+            .unified_diff()
+            .header("expected", "actual")
+    )
+}
+
+fn update_test(output: &[&str], context: &Context) -> Result<()> {
+    context
+        .file_update
+        .update_at(&context.details.location, |new_test, old_test| {
+            // blank newline after the function
+            new_test.push_str("\n");
+
+            // Splice in the test output
+            for output in output {
+                new_test.push_str("; ");
+                new_test.push_str(output);
+                new_test.push_str("\n");
+            }
+
+            // blank newline after test assertion
+            new_test.push_str("\n");
+
+            // Drop all remaining commented lines (presumably the old test expectation),
+            // but after we hit a real line then we push all remaining lines.
+            let mut in_next_function = false;
+            for line in old_test {
+                if !in_next_function
+                    && (line.trim().is_empty()
+                        || (line.starts_with(";") && !line.starts_with(";;")))
+                {
+                    continue;
+                }
+                in_next_function = true;
+                new_test.push_str(line);
+                new_test.push_str("\n");
+            }
+        })
+}
diff --git a/cranelift/filetests/src/test_compile.rs b/cranelift/filetests/src/test_compile.rs
index 94c975c14..934219086 100644
--- a/cranelift/filetests/src/test_compile.rs
+++ b/cranelift/filetests/src/test_compile.rs
@@ -2,17 +2,12 @@
 //!
 //! The `compile` test command runs each function through the full code generator pipeline
 
-use crate::subtest::{run_filecheck, Context, SubTest};
-use anyhow::{bail, Result};
+use crate::subtest::{check_precise_output, run_filecheck, Context, SubTest};
+use anyhow::Result;
 use cranelift_codegen::ir;
-use cranelift_codegen::ir::function::FunctionParameters;
-use cranelift_codegen::isa;
-use cranelift_codegen::CompiledCode;
 use cranelift_reader::{TestCommand, TestOption};
 use log::info;
-use similar::TextDiff;
 use std::borrow::Cow;
-use std::env;
 
 struct TestCompile {
     /// Flag indicating that the text expectation, comments after the function,
@@ -67,97 +62,20 @@ impl SubTest for TestCompile {
         info!("Generated {} bytes of code:\n{}", total_size, vcode);
 
         if self.precise_output {
-            check_precise_output(isa, &params, &compiled_code, context)
+            let cs = isa
+                .to_capstone()
+                .map_err(|e| anyhow::format_err!("{}", e))?;
+            let dis = compiled_code.disassemble(Some(&params), &cs)?;
+
+            let actual = Vec::from_iter(
+                std::iter::once("VCode:")
+                    .chain(compiled_code.vcode.as_ref().unwrap().lines())
+                    .chain(["", "Disassembled:"])
+                    .chain(dis.lines()),
+            );
+            check_precise_output(&actual, context)
         } else {
             run_filecheck(&vcode, context)
         }
     }
 }
-
-fn check_precise_output(
-    isa: &dyn isa::TargetIsa,
-    params: &FunctionParameters,
-    compiled_code: &CompiledCode,
-    context: &Context,
-) -> Result<()> {
-    let cs = isa
-        .to_capstone()
-        .map_err(|e| anyhow::format_err!("{}", e))?;
-    let dis = compiled_code.disassemble(Some(params), &cs)?;
-
-    let actual = Vec::from_iter(
-        std::iter::once("VCode:")
-            .chain(compiled_code.vcode.as_ref().unwrap().lines())
-            .chain(["", "Disassembled:"])
-            .chain(dis.lines()),
-    );
-
-    // Use the comments after the function to build the test expectation.
-    let expected = context
-        .details
-        .comments
-        .iter()
-        .filter(|c| !c.text.starts_with(";;"))
-        .map(|c| c.text.strip_prefix("; ").unwrap_or(c.text))
-        .collect::<Vec<_>>();
-
-    // If the expectation matches what we got, then there's nothing to do.
-    if actual == expected {
-        return Ok(());
-    }
-
-    // If we're supposed to automatically update the test, then do so here.
-    if env::var("CRANELIFT_TEST_BLESS").unwrap_or(String::new()) == "1" {
-        return update_test(&actual, context);
-    }
-
-    // Otherwise this test has failed, and we can print out as such.
-    bail!(
-        "compilation of function on line {} does not match\n\
-         the text expectation\n\
-         \n\
-         {}\n\
-         \n\
-         This test assertion can be automatically updated by setting the\n\
-         CRANELIFT_TEST_BLESS=1 environment variable when running this test.
-         ",
-        context.details.location.line_number,
-        TextDiff::from_slices(&expected, &actual)
-            .unified_diff()
-            .header("expected", "actual")
-    )
-}
-
-fn update_test(output: &[&str], context: &Context) -> Result<()> {
-    context
-        .file_update
-        .update_at(&context.details.location, |new_test, old_test| {
-            // blank newline after the function
-            new_test.push_str("\n");
-
-            // Splice in the test output
-            for output in output {
-                new_test.push_str("; ");
-                new_test.push_str(output);
-                new_test.push_str("\n");
-            }
-
-            // blank newline after test assertion
-            new_test.push_str("\n");
-
-            // Drop all remaining commented lines (presumably the old test expectation),
-            // but after we hit a real line then we push all remaining lines.
-            let mut in_next_function = false;
-            for line in old_test {
-                if !in_next_function
-                    && (line.trim().is_empty()
-                        || (line.starts_with(";") && !line.starts_with(";;")))
-                {
-                    continue;
-                }
-                in_next_function = true;
-                new_test.push_str(line);
-                new_test.push_str("\n");
-            }
-        })
-}
diff --git a/cranelift/filetests/src/test_optimize.rs b/cranelift/filetests/src/test_optimize.rs
index dfab6a1c4..fd76a8fe0 100644
--- a/cranelift/filetests/src/test_optimize.rs
+++ b/cranelift/filetests/src/test_optimize.rs
@@ -7,17 +7,32 @@
 //! Some legalization may be ISA-specific, so this requires an ISA
 //! (for now).
 
-use crate::subtest::{run_filecheck, Context, SubTest};
+use crate::subtest::{check_precise_output, run_filecheck, Context, SubTest};
 use anyhow::Result;
 use cranelift_codegen::ir;
-use cranelift_reader::TestCommand;
+use cranelift_reader::{TestCommand, TestOption};
 use std::borrow::Cow;
 
-struct TestOptimize;
+struct TestOptimize {
+    /// Flag indicating that the text expectation, comments after the function,
+    /// must be a precise 100% match on the compiled output of the function.
+    /// This test assertion is also automatically-update-able to allow tweaking
+    /// the code generator and easily updating all affected tests.
+    precise_output: bool,
+}
 
 pub fn subtest(parsed: &TestCommand) -> Result<Box<dyn SubTest>> {
     assert_eq!(parsed.command, "optimize");
-    Ok(Box::new(TestOptimize))
+    let mut test = TestOptimize {
+        precise_output: false,
+    };
+    for option in parsed.options.iter() {
+        match option {
+            TestOption::Flag("precise-output") => test.precise_output = true,
+            _ => anyhow::bail!("unknown option on {}", parsed),
+        }
+    }
+    Ok(Box::new(test))
 }
 
 impl SubTest for TestOptimize {
@@ -42,6 +57,12 @@ impl SubTest for TestOptimize {
             .map_err(|e| crate::pretty_anyhow_error(&comp_ctx.func, e))?;
 
         let clif = format!("{:?}", comp_ctx.func);
-        run_filecheck(&clif, context)
+
+        if self.precise_output {
+            let actual: Vec<_> = clif.lines().collect();
+            check_precise_output(&actual, context)
+        } else {
+            run_filecheck(&clif, context)
+        }
     }
 }
diff --git a/tests/all/epoch_interruption.rs b/tests/all/epoch_interruption.rs
index c34a8b7f7..a340ef658 100644
--- a/tests/all/epoch_interruption.rs
+++ b/tests/all/epoch_interruption.rs
@@ -32,7 +32,7 @@ fn make_env<T>(engine: &Engine) -> Linker<T> {
 
 enum InterruptMode {
     Trap,
-    Callback(fn(&mut usize) -> Result<u64>),
+    Callback(fn(StoreContextMut<usize>) -> Result<u64>),
     Yield(u64),
 }
 
@@ -334,7 +334,8 @@ async fn epoch_callback_continue() {
                 (func $subfunc))
             ",
             1,
-            InterruptMode::Callback(|s| {
+            InterruptMode::Callback(|mut cx| {
+                let s = cx.data_mut();
                 *s += 1;
                 Ok(1)
             }),
diff --git a/tests/misc_testsuite/component-model/aliasing.wast b/tests/misc_testsuite/component-model/aliasing.wast
new file mode 100644
index 000000000..ad18f9354
--- /dev/null
+++ b/tests/misc_testsuite/component-model/aliasing.wast
@@ -0,0 +1,29 @@
+(component
+  (component
+    (component
+      (component)
+      (instance (instantiate 0))
+      (export "a" (instance 0))
+    )
+    (instance (instantiate 0))
+    (export "a" (instance 0))
+  )
+
+  (instance (instantiate 0))       ;; instance 0
+  (alias export 0 "a" (instance))  ;; instance 1
+  (export "a" (instance 1))        ;; instance 2
+  (alias export 2 "a" (instance))  ;; instance 3
+  (export "inner-a" (instance 3))  ;; instance 4
+)
+
+(component
+  (component
+    (core module)
+    (export "a" (core module 0))
+  )
+
+  (instance (instantiate 0))
+  (alias export 0 "a" (core module))  ;; module 0
+  (export "a" (core module 0))        ;; module 1
+  (core instance (instantiate 1))
+)
diff --git a/winch/filetests/filetests/x64/call/params.wat b/winch/filetests/filetests/x64/call/params.wat
new file mode 100644
index 000000000..56ebb9dd4
--- /dev/null
+++ b/winch/filetests/filetests/x64/call/params.wat
@@ -0,0 +1,121 @@
+;;! target = "x86_64"
+
+(module
+  (func (export "main") (param i32) (param i32) (result i32)
+    (local.get 1)
+    (local.get 0)
+    (i32.div_u)
+
+    (call $add (i32.const 1) (i32.const 2) (i32.const 3) (i32.const 4) (i32.const 5) (i32.const 6) (i32.const 7) (i32.const 8))
+
+    (local.get 1)
+    (local.get 0)
+    (i32.div_u)
+
+    (call $add (i32.const 2) (i32.const 3) (i32.const 4) (i32.const 5) (i32.const 6) (i32.const 7) (i32.const 8))
+  )
+
+  (func $add (param i32 i32 i32 i32 i32 i32 i32 i32 i32) (result i32)
+    (local.get 0)
+    (local.get 1)
+    (i32.add)
+    (local.get 2)
+    (i32.add)
+    (local.get 3)
+    (i32.add)
+    (local.get 4)
+    (i32.add)
+    (local.get 5)
+    (i32.add)
+    (local.get 6)
+    (i32.add)
+    (local.get 7)
+    (i32.add)
+    (local.get 8)
+    (i32.add)
+  )
+)
+;;    0:	 55                   	push	rbp
+;;    1:	 4889e5               	mov	rbp, rsp
+;;    4:	 4883ec08             	sub	rsp, 8
+;;    8:	 897c2404             	mov	dword ptr [rsp + 4], edi
+;;    c:	 893424               	mov	dword ptr [rsp], esi
+;;    f:	 8b4c2404             	mov	ecx, dword ptr [rsp + 4]
+;;   13:	 8b0424               	mov	eax, dword ptr [rsp]
+;;   16:	 31d2                 	xor	edx, edx
+;;   18:	 f7f1                 	div	ecx
+;;   1a:	 50                   	push	rax
+;;   1b:	 4883ec20             	sub	rsp, 0x20
+;;   1f:	 8b7c2420             	mov	edi, dword ptr [rsp + 0x20]
+;;   23:	 be01000000           	mov	esi, 1
+;;   28:	 ba02000000           	mov	edx, 2
+;;   2d:	 b903000000           	mov	ecx, 3
+;;   32:	 41b804000000         	mov	r8d, 4
+;;   38:	 41b905000000         	mov	r9d, 5
+;;   3e:	 41bb06000000         	mov	r11d, 6
+;;   44:	 44891c24             	mov	dword ptr [rsp], r11d
+;;   48:	 41bb07000000         	mov	r11d, 7
+;;   4e:	 44895c2408           	mov	dword ptr [rsp + 8], r11d
+;;   53:	 41bb08000000         	mov	r11d, 8
+;;   59:	 44895c2410           	mov	dword ptr [rsp + 0x10], r11d
+;;   5e:	 e800000000           	call	0x63
+;;   63:	 4883c428             	add	rsp, 0x28
+;;   67:	 50                   	push	rax
+;;   68:	 448b5c2408           	mov	r11d, dword ptr [rsp + 8]
+;;   6d:	 4153                 	push	r11
+;;   6f:	 448b5c2414           	mov	r11d, dword ptr [rsp + 0x14]
+;;   74:	 4153                 	push	r11
+;;   76:	 59                   	pop	rcx
+;;   77:	 58                   	pop	rax
+;;   78:	 31d2                 	xor	edx, edx
+;;   7a:	 f7f1                 	div	ecx
+;;   7c:	 50                   	push	rax
+;;   7d:	 4883ec20             	sub	rsp, 0x20
+;;   81:	 8b7c2428             	mov	edi, dword ptr [rsp + 0x28]
+;;   85:	 8b742420             	mov	esi, dword ptr [rsp + 0x20]
+;;   89:	 ba02000000           	mov	edx, 2
+;;   8e:	 b903000000           	mov	ecx, 3
+;;   93:	 41b804000000         	mov	r8d, 4
+;;   99:	 41b905000000         	mov	r9d, 5
+;;   9f:	 41bb06000000         	mov	r11d, 6
+;;   a5:	 44891c24             	mov	dword ptr [rsp], r11d
+;;   a9:	 41bb07000000         	mov	r11d, 7
+;;   af:	 44895c2408           	mov	dword ptr [rsp + 8], r11d
+;;   b4:	 41bb08000000         	mov	r11d, 8
+;;   ba:	 44895c2410           	mov	dword ptr [rsp + 0x10], r11d
+;;   bf:	 e800000000           	call	0xc4
+;;   c4:	 4883c430             	add	rsp, 0x30
+;;   c8:	 4883c408             	add	rsp, 8
+;;   cc:	 5d                   	pop	rbp
+;;   cd:	 c3                   	ret	
+;;
+;;    0:	 55                   	push	rbp
+;;    1:	 4889e5               	mov	rbp, rsp
+;;    4:	 4883ec18             	sub	rsp, 0x18
+;;    8:	 897c2414             	mov	dword ptr [rsp + 0x14], edi
+;;    c:	 89742410             	mov	dword ptr [rsp + 0x10], esi
+;;   10:	 8954240c             	mov	dword ptr [rsp + 0xc], edx
+;;   14:	 894c2408             	mov	dword ptr [rsp + 8], ecx
+;;   18:	 4489442404           	mov	dword ptr [rsp + 4], r8d
+;;   1d:	 44890c24             	mov	dword ptr [rsp], r9d
+;;   21:	 8b442410             	mov	eax, dword ptr [rsp + 0x10]
+;;   25:	 8b4c2414             	mov	ecx, dword ptr [rsp + 0x14]
+;;   29:	 01c1                 	add	ecx, eax
+;;   2b:	 8b44240c             	mov	eax, dword ptr [rsp + 0xc]
+;;   2f:	 01c1                 	add	ecx, eax
+;;   31:	 8b442408             	mov	eax, dword ptr [rsp + 8]
+;;   35:	 01c1                 	add	ecx, eax
+;;   37:	 8b442404             	mov	eax, dword ptr [rsp + 4]
+;;   3b:	 01c1                 	add	ecx, eax
+;;   3d:	 8b0424               	mov	eax, dword ptr [rsp]
+;;   40:	 01c1                 	add	ecx, eax
+;;   42:	 8b4510               	mov	eax, dword ptr [rbp + 0x10]
+;;   45:	 01c1                 	add	ecx, eax
+;;   47:	 8b4518               	mov	eax, dword ptr [rbp + 0x18]
+;;   4a:	 01c1                 	add	ecx, eax
+;;   4c:	 8b4520               	mov	eax, dword ptr [rbp + 0x20]
+;;   4f:	 01c1                 	add	ecx, eax
+;;   51:	 4889c8               	mov	rax, rcx
+;;   54:	 4883c418             	add	rsp, 0x18
+;;   58:	 5d                   	pop	rbp
+;;   59:	 c3                   	ret	
diff --git a/winch/filetests/filetests/x64/call/simple.wat b/winch/filetests/filetests/x64/call/simple.wat
new file mode 100644
index 000000000..a2cb8d32a
--- /dev/null
+++ b/winch/filetests/filetests/x64/call/simple.wat
@@ -0,0 +1,49 @@
+;;! target = "x86_64"
+
+(module
+  (func $main (result i32)
+    (local $var i32)
+    (call $product (i32.const 20) (i32.const 80))
+    (local.set $var (i32.const 2))
+    (local.get $var)
+    (i32.div_u))
+
+  (func $product (param i32 i32) (result i32)
+    (local.get 0)
+    (local.get 1)
+    (i32.mul))
+)
+;;    0:	 55                   	push	rbp
+;;    1:	 4889e5               	mov	rbp, rsp
+;;    4:	 4883ec08             	sub	rsp, 8
+;;    8:	 48c7042400000000     	mov	qword ptr [rsp], 0
+;;   10:	 4883ec10             	sub	rsp, 0x10
+;;   14:	 bf14000000           	mov	edi, 0x14
+;;   19:	 be50000000           	mov	esi, 0x50
+;;   1e:	 e800000000           	call	0x23
+;;   23:	 4883c410             	add	rsp, 0x10
+;;   27:	 b902000000           	mov	ecx, 2
+;;   2c:	 894c2404             	mov	dword ptr [rsp + 4], ecx
+;;   30:	 50                   	push	rax
+;;   31:	 448b5c240c           	mov	r11d, dword ptr [rsp + 0xc]
+;;   36:	 4153                 	push	r11
+;;   38:	 59                   	pop	rcx
+;;   39:	 58                   	pop	rax
+;;   3a:	 31d2                 	xor	edx, edx
+;;   3c:	 f7f1                 	div	ecx
+;;   3e:	 4883c408             	add	rsp, 8
+;;   42:	 5d                   	pop	rbp
+;;   43:	 c3                   	ret	
+;;
+;;    0:	 55                   	push	rbp
+;;    1:	 4889e5               	mov	rbp, rsp
+;;    4:	 4883ec08             	sub	rsp, 8
+;;    8:	 897c2404             	mov	dword ptr [rsp + 4], edi
+;;    c:	 893424               	mov	dword ptr [rsp], esi
+;;    f:	 8b0424               	mov	eax, dword ptr [rsp]
+;;   12:	 8b4c2404             	mov	ecx, dword ptr [rsp + 4]
+;;   16:	 0fafc8               	imul	ecx, eax
+;;   19:	 4889c8               	mov	rax, rcx
+;;   1c:	 4883c408             	add	rsp, 8
+;;   20:	 5d                   	pop	rbp
+;;   21:	 c3                   	ret	
diff --git a/winch/filetests/src/lib.rs b/winch/filetests/src/lib.rs
index 0d4f8832d..a6d744717 100644
--- a/winch/filetests/src/lib.rs
+++ b/winch/filetests/src/lib.rs
@@ -155,7 +155,7 @@ mod test {
 
         let buffer = env
             .isa
-            .compile_function(&sig, &body, validator)
+            .compile_function(&sig, &body, env, validator)
             .expect("Couldn't compile function");
 
         disasm(buffer.data(), env.isa).unwrap()