Repository: bytecodealliance/wasmtime
Pull request #6938 (2023-08-31 09:50:54)

riscv64: Use `PCRelLo12I` relocation on Loads
👋 Hey,

This is a small follow up to #6933 that restores our ability to use a relocation for loads that point to a label / constant pool label.

It looks like the relocation that I needed to use was already implemented so this ended up being a lot easier than I expected.


Patch:
diff --git a/RELEASES.md b/RELEASES.md
index 1162d8765..8cc2cdb13 100644
--- a/RELEASES.md
+++ b/RELEASES.md
@@ -80,13 +80,6 @@ Unreleased.
   These methods do not affect the size of the pre-allocated pool.
   [#6835](https://github.com/bytecodealliance/wasmtime/pull/6835)
 
-* Options to the `wasmtime` CLI for Wasmtime itself must now come before the
-  WebAssembly module. For example `wasmtime run foo.wasm --disable-cache` now
-  must be specified as `wasmtime run --disable-cache foo.wasm`. Any
-  argument/option after the WebAssembly module is now interpreted as an argument
-  to the wasm module itself.
-  [#6737](https://github.com/bytecodealliance/wasmtime/pull/6737)
-
 * Builder methods for WASI contexts onw use `&mut self` instead of `self`.
   [#6770](https://github.com/bytecodealliance/wasmtime/pull/6770)
 
diff --git a/cranelift/codegen/src/isa/riscv64/inst/args.rs b/cranelift/codegen/src/isa/riscv64/inst/args.rs
index 40ebbc94f..18d8ae9b7 100644
--- a/cranelift/codegen/src/isa/riscv64/inst/args.rs
+++ b/cranelift/codegen/src/isa/riscv64/inst/args.rs
@@ -161,6 +161,18 @@ impl AMode {
         }
     }
 
+    /// Retrieve a MachLabel that corresponds to this addressing mode, if it exists.
+    pub(crate) fn get_label_with_sink(&self, sink: &mut MachBuffer<Inst>) -> Option<MachLabel> {
+        match self {
+            &AMode::Const(addr) => Some(sink.get_label_for_constant(addr)),
+            &AMode::Label(label) => Some(label),
+            &AMode::RegOffset(..)
+            | &AMode::SPOffset(..)
+            | &AMode::FPOffset(..)
+            | &AMode::NominalSPOffset(..) => None,
+        }
+    }
+
     pub(crate) fn to_string_with_alloc(&self, allocs: &mut AllocationConsumer<'_>) -> String {
         format!("{}", self.clone().with_allocs(allocs))
     }
diff --git a/cranelift/codegen/src/isa/riscv64/inst/emit.rs b/cranelift/codegen/src/isa/riscv64/inst/emit.rs
index 10ab56494..48b2c8ea3 100644
--- a/cranelift/codegen/src/isa/riscv64/inst/emit.rs
+++ b/cranelift/codegen/src/isa/riscv64/inst/emit.rs
@@ -620,18 +620,49 @@ impl MachInstEmit for Inst {
                 let base = from.get_base_register();
                 let offset = from.get_offset_with_state(state);
                 let offset_imm12 = Imm12::maybe_from_i64(offset);
+                let label = from.get_label_with_sink(sink);
 
-                // TODO: We shouldn't just fall back to `LoadAddr` immediately. For `MachLabel`s
-                // we should try to emit the `auipc` and add a relocation on this load.
-                let (addr, imm12) = match (base, offset_imm12) {
-                    // If the offset fits into an imm12 we can directly encode it.
-                    (Some(base), Some(imm12)) => (base, imm12),
-                    // Otherwise load the address it into a reg and load from it.
-                    _ => {
+                let (addr, imm12) = match (base, offset_imm12, label) {
+                    // When loading from a Reg+Offset, if the offset fits into an imm12 we can directly encode it.
+                    (Some(base), Some(imm12), None) => (base, imm12),
+
+                    // Otherwise, if the offset does not fit into a imm12, we need to materialize it into a
+                    // register and load from that.
+                    (Some(_), None, None) => {
                         let tmp = writable_spilltmp_reg();
                         Inst::LoadAddr { rd: tmp, mem: from }.emit(&[], sink, emit_info, state);
                         (tmp.to_reg(), Imm12::zero())
                     }
+
+                    // If the AMode contains a label we can emit an internal relocation that gets
+                    // resolved with the correct address later.
+                    (None, Some(imm), Some(label)) => {
+                        debug_assert_eq!(imm.as_i16(), 0);
+
+                        // Get the current PC.
+                        sink.use_label_at_offset(sink.cur_offset(), label, LabelUse::PCRelHi20);
+                        Inst::Auipc {
+                            rd,
+                            imm: Imm20::from_bits(0),
+                        }
+                        .emit(&[], sink, emit_info, state);
+
+                        // Emit a relocation for the load. This patches the offset into the instruction.
+                        sink.use_label_at_offset(sink.cur_offset(), label, LabelUse::PCRelLo12I);
+
+                        // Imm12 here is meaningless since it's going to get replaced.
+                        (rd.to_reg(), Imm12::zero())
+                    }
+
+                    // These cases are impossible with the current AModes that we have. We either
+                    // always have a register, or always have a label. Never both, and never neither.
+                    (None, None, None)
+                    | (None, Some(_), None)
+                    | (Some(_), None, Some(_))
+                    | (Some(_), Some(_), Some(_))
+                    | (None, None, Some(_)) => {
+                        unreachable!("Invalid load address")
+                    }
                 };
 
                 let srcloc = state.cur_srcloc();
@@ -650,8 +681,6 @@ impl MachInstEmit for Inst {
                 let offset = to.get_offset_with_state(state);
                 let offset_imm12 = Imm12::maybe_from_i64(offset);
 
-                // TODO: We shouldn't just fall back to `LoadAddr` immediately. For `MachLabel`s
-                // we should try to emit the `auipc` and add a relocation on this store.
                 let (addr, imm12) = match (base, offset_imm12) {
                     // If the offset fits into an imm12 we can directly encode it.
                     (Some(base), Some(imm12)) => (base, imm12),
diff --git a/cranelift/fuzzgen/src/function_generator.rs b/cranelift/fuzzgen/src/function_generator.rs
index 15e784433..216adce67 100644
--- a/cranelift/fuzzgen/src/function_generator.rs
+++ b/cranelift/fuzzgen/src/function_generator.rs
@@ -525,6 +525,8 @@ fn valid_for_target(triple: &Triple, op: Opcode, args: &[Type], rets: &[Type]) -
                 (Opcode::Cls, &[I32], &[I32]),
                 (Opcode::Cls, &[I64], &[I64]),
                 (Opcode::Cls, &[I128], &[I128]),
+                // TODO
+                (Opcode::Bitselect, &[_, _, _], &[F32 | F64]),
                 // https://github.com/bytecodealliance/wasmtime/issues/4897
                 // https://github.com/bytecodealliance/wasmtime/issues/4899
                 (
@@ -589,6 +591,15 @@ fn valid_for_target(triple: &Triple, op: Opcode, args: &[Type], rets: &[Type]) -
                     &[],
                     &[I8X16 | I16X8 | I32X4 | I64X2 | F32X4 | F64X2]
                 ),
+                // TODO
+                (
+                    Opcode::Sshr | Opcode::Ushr | Opcode::Ishl,
+                    &[I8X16 | I16X8 | I32X4 | I64X2, I128]
+                ),
+                (
+                    Opcode::Rotr | Opcode::Rotl,
+                    &[I8X16 | I16X8 | I32X4 | I64X2, _]
+                ),
             )
         }
 
@@ -647,6 +658,17 @@ fn valid_for_target(triple: &Triple, op: Opcode, args: &[Type], rets: &[Type]) -
                 // https://github.com/bytecodealliance/wasmtime/issues/6104
                 (Opcode::Bitcast, &[I128], &[_]),
                 (Opcode::Bitcast, &[_], &[I128]),
+                // TODO
+                (
+                    Opcode::Sshr | Opcode::Ushr | Opcode::Ishl,
+                    &[I8X16 | I16X8 | I32X4 | I64X2, I128]
+                ),
+                (
+                    Opcode::Rotr | Opcode::Rotl,
+                    &[I8X16 | I16X8 | I32X4 | I64X2, _]
+                ),
+                // TODO
+                (Opcode::Bitselect, &[_, _, _], &[F32 | F64]),
             )
         }
 
@@ -689,6 +711,8 @@ fn valid_for_target(triple: &Triple, op: Opcode, args: &[Type], rets: &[Type]) -
                 // https://github.com/bytecodealliance/wasmtime/issues/6104
                 (Opcode::Bitcast, &[I128], &[_]),
                 (Opcode::Bitcast, &[_], &[I128]),
+                // TODO
+                (Opcode::Bitselect, &[_, _, _], &[F32 | F64]),
             )
         }
 
@@ -737,8 +761,9 @@ fn valid_for_target(triple: &Triple, op: Opcode, args: &[Type], rets: &[Type]) -
                 (Opcode::Bitcast, &[I128], &[_]),
                 (Opcode::Bitcast, &[_], &[I128]),
                 // TODO
-                (Opcode::SelectSpectreGuard, &[_, _, _], &[F32]),
-                (Opcode::SelectSpectreGuard, &[_, _, _], &[F64]),
+                (Opcode::SelectSpectreGuard, &[_, _, _], &[F32 | F64]),
+                // TODO
+                (Opcode::Bitselect, &[_, _, _], &[F32 | F64]),
             )
         }
 
@@ -896,10 +921,6 @@ static OPCODE_SIGNATURES: Lazy<Vec<OpcodeSignature>> = Lazy::new(|| {
                 (Opcode::ScalarToVector),
                 (Opcode::X86Pmaddubsw),
                 (Opcode::X86Cvtt2dq),
-                (Opcode::Bitselect, &[F32, F32, F32], &[F32]),
-                (Opcode::Bitselect, &[F64, F64, F64], &[F64]),
-                (Opcode::Bitselect, &[F32X4, F32X4, F32X4], &[F32X4]),
-                (Opcode::Bitselect, &[F64X2, F64X2, F64X2], &[F64X2]),
                 (Opcode::VanyTrue, &[F32X4], &[I8]),
                 (Opcode::VanyTrue, &[F64X2], &[I8]),
                 (Opcode::VhighBits, &[F32X4], &[I8]),
@@ -952,10 +973,6 @@ static OPCODE_SIGNATURES: Lazy<Vec<OpcodeSignature>> = Lazy::new(|| {
                 (Opcode::VhighBits, &[I64X2], &[I64X2]),
                 (Opcode::VhighBits, &[F32X4], &[I64X2]),
                 (Opcode::VhighBits, &[F64X2], &[I64X2]),
-                (Opcode::Ineg, &[I8X16], &[I8X16]),
-                (Opcode::Ineg, &[I16X8], &[I16X8]),
-                (Opcode::Ineg, &[I32X4], &[I32X4]),
-                (Opcode::Ineg, &[I64X2], &[I64X2]),
                 (Opcode::Umulhi, &[I128, I128], &[I128]),
                 (Opcode::Smulhi, &[I128, I128], &[I128]),
                 // https://github.com/bytecodealliance/wasmtime/issues/6073
@@ -966,106 +983,6 @@ static OPCODE_SIGNATURES: Lazy<Vec<OpcodeSignature>> = Lazy::new(|| {
                 (Opcode::Isplit, &[I64], &[I32, I32]),
                 (Opcode::Isplit, &[I32], &[I16, I16]),
                 (Opcode::Isplit, &[I16], &[I8, I8]),
-                (Opcode::Rotl, &[I8X16, I8], &[I8X16]),
-                (Opcode::Rotl, &[I8X16, I16], &[I8X16]),
-                (Opcode::Rotl, &[I8X16, I32], &[I8X16]),
-                (Opcode::Rotl, &[I8X16, I64], &[I8X16]),
-                (Opcode::Rotl, &[I8X16, I128], &[I8X16]),
-                (Opcode::Rotl, &[I16X8, I8], &[I16X8]),
-                (Opcode::Rotl, &[I16X8, I16], &[I16X8]),
-                (Opcode::Rotl, &[I16X8, I32], &[I16X8]),
-                (Opcode::Rotl, &[I16X8, I64], &[I16X8]),
-                (Opcode::Rotl, &[I16X8, I128], &[I16X8]),
-                (Opcode::Rotl, &[I32X4, I8], &[I32X4]),
-                (Opcode::Rotl, &[I32X4, I16], &[I32X4]),
-                (Opcode::Rotl, &[I32X4, I32], &[I32X4]),
-                (Opcode::Rotl, &[I32X4, I64], &[I32X4]),
-                (Opcode::Rotl, &[I32X4, I128], &[I32X4]),
-                (Opcode::Rotl, &[I64X2, I8], &[I64X2]),
-                (Opcode::Rotl, &[I64X2, I16], &[I64X2]),
-                (Opcode::Rotl, &[I64X2, I32], &[I64X2]),
-                (Opcode::Rotl, &[I64X2, I64], &[I64X2]),
-                (Opcode::Rotl, &[I64X2, I128], &[I64X2]),
-                (Opcode::Rotr, &[I8X16, I8], &[I8X16]),
-                (Opcode::Rotr, &[I8X16, I16], &[I8X16]),
-                (Opcode::Rotr, &[I8X16, I32], &[I8X16]),
-                (Opcode::Rotr, &[I8X16, I64], &[I8X16]),
-                (Opcode::Rotr, &[I8X16, I128], &[I8X16]),
-                (Opcode::Rotr, &[I16X8, I8], &[I16X8]),
-                (Opcode::Rotr, &[I16X8, I16], &[I16X8]),
-                (Opcode::Rotr, &[I16X8, I32], &[I16X8]),
-                (Opcode::Rotr, &[I16X8, I64], &[I16X8]),
-                (Opcode::Rotr, &[I16X8, I128], &[I16X8]),
-                (Opcode::Rotr, &[I32X4, I8], &[I32X4]),
-                (Opcode::Rotr, &[I32X4, I16], &[I32X4]),
-                (Opcode::Rotr, &[I32X4, I32], &[I32X4]),
-                (Opcode::Rotr, &[I32X4, I64], &[I32X4]),
-                (Opcode::Rotr, &[I32X4, I128], &[I32X4]),
-                (Opcode::Rotr, &[I64X2, I8], &[I64X2]),
-                (Opcode::Rotr, &[I64X2, I16], &[I64X2]),
-                (Opcode::Rotr, &[I64X2, I32], &[I64X2]),
-                (Opcode::Rotr, &[I64X2, I64], &[I64X2]),
-                (Opcode::Rotr, &[I64X2, I128], &[I64X2]),
-                (Opcode::Ishl, &[I8X16, I8], &[I8X16]),
-                (Opcode::Ishl, &[I8X16, I16], &[I8X16]),
-                (Opcode::Ishl, &[I8X16, I32], &[I8X16]),
-                (Opcode::Ishl, &[I8X16, I64], &[I8X16]),
-                (Opcode::Ishl, &[I8X16, I128], &[I8X16]),
-                (Opcode::Ishl, &[I16X8, I8], &[I16X8]),
-                (Opcode::Ishl, &[I16X8, I16], &[I16X8]),
-                (Opcode::Ishl, &[I16X8, I32], &[I16X8]),
-                (Opcode::Ishl, &[I16X8, I64], &[I16X8]),
-                (Opcode::Ishl, &[I16X8, I128], &[I16X8]),
-                (Opcode::Ishl, &[I32X4, I8], &[I32X4]),
-                (Opcode::Ishl, &[I32X4, I16], &[I32X4]),
-                (Opcode::Ishl, &[I32X4, I32], &[I32X4]),
-                (Opcode::Ishl, &[I32X4, I64], &[I32X4]),
-                (Opcode::Ishl, &[I32X4, I128], &[I32X4]),
-                (Opcode::Ishl, &[I64X2, I8], &[I64X2]),
-                (Opcode::Ishl, &[I64X2, I16], &[I64X2]),
-                (Opcode::Ishl, &[I64X2, I32], &[I64X2]),
-                (Opcode::Ishl, &[I64X2, I64], &[I64X2]),
-                (Opcode::Ishl, &[I64X2, I128], &[I64X2]),
-                (Opcode::Ushr, &[I8X16, I8], &[I8X16]),
-                (Opcode::Ushr, &[I8X16, I16], &[I8X16]),
-                (Opcode::Ushr, &[I8X16, I32], &[I8X16]),
-                (Opcode::Ushr, &[I8X16, I64], &[I8X16]),
-                (Opcode::Ushr, &[I8X16, I128], &[I8X16]),
-                (Opcode::Ushr, &[I16X8, I8], &[I16X8]),
-                (Opcode::Ushr, &[I16X8, I16], &[I16X8]),
-                (Opcode::Ushr, &[I16X8, I32], &[I16X8]),
-                (Opcode::Ushr, &[I16X8, I64], &[I16X8]),
-                (Opcode::Ushr, &[I16X8, I128], &[I16X8]),
-                (Opcode::Ushr, &[I32X4, I8], &[I32X4]),
-                (Opcode::Ushr, &[I32X4, I16], &[I32X4]),
-                (Opcode::Ushr, &[I32X4, I32], &[I32X4]),
-                (Opcode::Ushr, &[I32X4, I64], &[I32X4]),
-                (Opcode::Ushr, &[I32X4, I128], &[I32X4]),
-                (Opcode::Ushr, &[I64X2, I8], &[I64X2]),
-                (Opcode::Ushr, &[I64X2, I16], &[I64X2]),
-                (Opcode::Ushr, &[I64X2, I32], &[I64X2]),
-                (Opcode::Ushr, &[I64X2, I64], &[I64X2]),
-                (Opcode::Ushr, &[I64X2, I128], &[I64X2]),
-                (Opcode::Sshr, &[I8X16, I8], &[I8X16]),
-                (Opcode::Sshr, &[I8X16, I16], &[I8X16]),
-                (Opcode::Sshr, &[I8X16, I32], &[I8X16]),
-                (Opcode::Sshr, &[I8X16, I64], &[I8X16]),
-                (Opcode::Sshr, &[I8X16, I128], &[I8X16]),
-                (Opcode::Sshr, &[I16X8, I8], &[I16X8]),
-                (Opcode::Sshr, &[I16X8, I16], &[I16X8]),
-                (Opcode::Sshr, &[I16X8, I32], &[I16X8]),
-                (Opcode::Sshr, &[I16X8, I64], &[I16X8]),
-                (Opcode::Sshr, &[I16X8, I128], &[I16X8]),
-                (Opcode::Sshr, &[I32X4, I8], &[I32X4]),
-                (Opcode::Sshr, &[I32X4, I16], &[I32X4]),
-                (Opcode::Sshr, &[I32X4, I32], &[I32X4]),
-                (Opcode::Sshr, &[I32X4, I64], &[I32X4]),
-                (Opcode::Sshr, &[I32X4, I128], &[I32X4]),
-                (Opcode::Sshr, &[I64X2, I8], &[I64X2]),
-                (Opcode::Sshr, &[I64X2, I16], &[I64X2]),
-                (Opcode::Sshr, &[I64X2, I32], &[I64X2]),
-                (Opcode::Sshr, &[I64X2, I64], &[I64X2]),
-                (Opcode::Sshr, &[I64X2, I128], &[I64X2]),
                 (Opcode::Fmin, &[F32X4, F32X4], &[F32X4]),
                 (Opcode::Fmin, &[F64X2, F64X2], &[F64X2]),
                 (Opcode::Fmax, &[F32X4, F32X4], &[F32X4]),
diff --git a/cranelift/interpreter/src/step.rs b/cranelift/interpreter/src/step.rs
index f13d2c918..a8ae06f90 100644
--- a/cranelift/interpreter/src/step.rs
+++ b/cranelift/interpreter/src/step.rs
@@ -795,16 +795,16 @@ where
         Opcode::BandImm => binary(DataValueExt::and, arg(0), imm_as_ctrl_ty()?)?,
         Opcode::BorImm => binary(DataValueExt::or, arg(0), imm_as_ctrl_ty()?)?,
         Opcode::BxorImm => binary(DataValueExt::xor, arg(0), imm_as_ctrl_ty()?)?,
-        Opcode::Rotl => binary(DataValueExt::rotl, arg(0), arg(1))?,
-        Opcode::Rotr => binary(DataValueExt::rotr, arg(0), arg(1))?,
-        Opcode::RotlImm => binary(DataValueExt::rotl, arg(0), imm_as_ctrl_ty()?)?,
-        Opcode::RotrImm => binary(DataValueExt::rotr, arg(0), imm_as_ctrl_ty()?)?,
-        Opcode::Ishl => binary(DataValueExt::shl, arg(0), arg(1))?,
-        Opcode::Ushr => binary(DataValueExt::ushr, arg(0), arg(1))?,
-        Opcode::Sshr => binary(DataValueExt::sshr, arg(0), arg(1))?,
-        Opcode::IshlImm => binary(DataValueExt::shl, arg(0), imm_as_ctrl_ty()?)?,
-        Opcode::UshrImm => binary(DataValueExt::ushr, arg(0), imm_as_ctrl_ty()?)?,
-        Opcode::SshrImm => binary(DataValueExt::sshr, arg(0), imm_as_ctrl_ty()?)?,
+        Opcode::Rotl => binary(DataValueExt::rotl, arg(0), shift_amt(ctrl_ty, arg(1))?)?,
+        Opcode::Rotr => binary(DataValueExt::rotr, arg(0), shift_amt(ctrl_ty, arg(1))?)?,
+        Opcode::RotlImm => binary(DataValueExt::rotl, arg(0), shift_amt(ctrl_ty, imm())?)?,
+        Opcode::RotrImm => binary(DataValueExt::rotr, arg(0), shift_amt(ctrl_ty, imm())?)?,
+        Opcode::Ishl => binary(DataValueExt::shl, arg(0), shift_amt(ctrl_ty, arg(1))?)?,
+        Opcode::Ushr => binary(DataValueExt::ushr, arg(0), shift_amt(ctrl_ty, arg(1))?)?,
+        Opcode::Sshr => binary(DataValueExt::sshr, arg(0), shift_amt(ctrl_ty, arg(1))?)?,
+        Opcode::IshlImm => binary(DataValueExt::shl, arg(0), shift_amt(ctrl_ty, imm())?)?,
+        Opcode::UshrImm => binary(DataValueExt::ushr, arg(0), shift_amt(ctrl_ty, imm())?)?,
+        Opcode::SshrImm => binary(DataValueExt::sshr, arg(0), shift_amt(ctrl_ty, imm())?)?,
         Opcode::Bitrev => unary(DataValueExt::reverse_bits, arg(0))?,
         Opcode::Bswap => unary(DataValueExt::swap_bytes, arg(0))?,
         Opcode::Clz => unary(DataValueExt::leading_zeros, arg(0))?,
@@ -994,13 +994,7 @@ where
             }
             assign(DataValueExt::vector(new, types::I8X16)?)
         }
-        Opcode::Splat => {
-            let mut new_vector = SimdVec::new();
-            for _ in 0..ctrl_ty.lane_count() {
-                new_vector.push(arg(0));
-            }
-            assign(vectorizelanes(&new_vector, ctrl_ty)?)
-        }
+        Opcode::Splat => assign(splat(ctrl_ty, arg(0))?),
         Opcode::Insertlane => {
             let idx = imm().into_int_unsigned()? as usize;
             let mut vector = extractlanes(&arg(0), ctrl_ty)?;
@@ -1575,3 +1569,17 @@ fn bitselect(c: DataValue, x: DataValue, y: DataValue) -> ValueResult<DataValue>
     let mask_y = DataValueExt::and(DataValueExt::not(c)?, y)?;
     DataValueExt::or(mask_x, mask_y)
 }
+
+fn splat(ty: Type, val: DataValue) -> ValueResult<DataValue> {
+    let mut new_vector = SimdVec::new();
+    for _ in 0..ty.lane_count() {
+        new_vector.push(val.clone());
+    }
+    vectorizelanes(&new_vector, ty)
+}
+
+// Prepares the shift amount for a shift/rotate operation.
+// The shift amount must be the same type and have the same number of lanes as the vector.
+fn shift_amt(ty: Type, val: DataValue) -> ValueResult<DataValue> {
+    splat(ty, val.convert(ValueConversionKind::Exact(ty.lane_type()))?)
+}
diff --git a/crates/component-macro/src/bindgen.rs b/crates/component-macro/src/bindgen.rs
index 3dfd7f846..a87616e55 100644
--- a/crates/component-macro/src/bindgen.rs
+++ b/crates/component-macro/src/bindgen.rs
@@ -1,10 +1,11 @@
 use proc_macro2::{Span, TokenStream};
 use std::collections::HashMap;
+use std::collections::HashSet;
 use std::path::{Path, PathBuf};
 use syn::parse::{Error, Parse, ParseStream, Result};
 use syn::punctuated::Punctuated;
 use syn::{braced, token, Ident, Token};
-use wasmtime_wit_bindgen::{Opts, Ownership, TrappableError};
+use wasmtime_wit_bindgen::{AsyncConfig, Opts, Ownership, TrappableError};
 use wit_parser::{PackageId, Resolve, UnresolvedPackage, WorldId};
 
 pub struct Config {
@@ -15,7 +16,7 @@ pub struct Config {
 }
 
 pub fn expand(input: &Config) -> Result<TokenStream> {
-    if !cfg!(feature = "async") && input.opts.async_ {
+    if !cfg!(feature = "async") && input.opts.async_.maybe_async() {
         return Err(Error::new(
             Span::call_site(),
             "cannot enable async bindings unless `async` crate feature is active",
@@ -45,6 +46,7 @@ impl Parse for Config {
         let mut world = None;
         let mut inline = None;
         let mut path = None;
+        let mut async_configured = false;
 
         if input.peek(token::Brace) {
             let content;
@@ -71,7 +73,13 @@ impl Parse for Config {
                         inline = Some(s.value());
                     }
                     Opt::Tracing(val) => opts.tracing = val,
-                    Opt::Async(val) => opts.async_ = val,
+                    Opt::Async(val, span) => {
+                        if async_configured {
+                            return Err(Error::new(span, "cannot specify second async config"));
+                        }
+                        async_configured = true;
+                        opts.async_ = val;
+                    }
                     Opt::TrappableErrorType(val) => opts.trappable_error_type = val,
                     Opt::Ownership(val) => opts.ownership = val,
                     Opt::Interfaces(s) => {
@@ -171,6 +179,8 @@ mod kw {
     syn::custom_keyword!(ownership);
     syn::custom_keyword!(interfaces);
     syn::custom_keyword!(with);
+    syn::custom_keyword!(except_imports);
+    syn::custom_keyword!(only_imports);
 }
 
 enum Opt {
@@ -178,7 +188,7 @@ enum Opt {
     Path(syn::LitStr),
     Inline(syn::LitStr),
     Tracing(bool),
-    Async(bool),
+    Async(AsyncConfig, Span),
     TrappableErrorType(Vec<TrappableError>),
     Ownership(Ownership),
     Interfaces(syn::LitStr),
@@ -205,9 +215,43 @@ impl Parse for Opt {
             input.parse::<Token![:]>()?;
             Ok(Opt::Tracing(input.parse::<syn::LitBool>()?.value))
         } else if l.peek(Token![async]) {
-            input.parse::<Token![async]>()?;
+            let span = input.parse::<Token![async]>()?.span;
             input.parse::<Token![:]>()?;
-            Ok(Opt::Async(input.parse::<syn::LitBool>()?.value))
+            if input.peek(syn::LitBool) {
+                match input.parse::<syn::LitBool>()?.value {
+                    true => Ok(Opt::Async(AsyncConfig::All, span)),
+                    false => Ok(Opt::Async(AsyncConfig::None, span)),
+                }
+            } else {
+                let contents;
+                syn::braced!(contents in input);
+
+                let l = contents.lookahead1();
+                let ctor: fn(HashSet<String>) -> AsyncConfig = if l.peek(kw::except_imports) {
+                    contents.parse::<kw::except_imports>()?;
+                    contents.parse::<Token![:]>()?;
+                    AsyncConfig::AllExceptImports
+                } else if l.peek(kw::only_imports) {
+                    contents.parse::<kw::only_imports>()?;
+                    contents.parse::<Token![:]>()?;
+                    AsyncConfig::OnlyImports
+                } else {
+                    return Err(l.error());
+                };
+
+                let list;
+                syn::bracketed!(list in contents);
+                let fields: Punctuated<syn::LitStr, Token![,]> =
+                    list.parse_terminated(Parse::parse, Token![,])?;
+
+                if contents.peek(Token![,]) {
+                    contents.parse::<Token![,]>()?;
+                }
+                Ok(Opt::Async(
+                    ctor(fields.iter().map(|s| s.value()).collect()),
+                    span,
+                ))
+            }
         } else if l.peek(kw::ownership) {
             input.parse::<kw::ownership>()?;
             input.parse::<Token![:]>()?;
diff --git a/crates/wasmtime/src/component/mod.rs b/crates/wasmtime/src/component/mod.rs
index b8e79df1f..618f829b2 100644
--- a/crates/wasmtime/src/component/mod.rs
+++ b/crates/wasmtime/src/component/mod.rs
@@ -281,6 +281,22 @@ pub(crate) use self::store::ComponentStoreData;
 ///     // This option defaults to `false`.
 ///     async: true,
 ///
+///     // Alternative mode of async configuration where this still implies
+///     // async instantiation happens, for example, but more control is
+///     // provided over which imports are async and which aren't.
+///     //
+///     // Note that in this mode all exports are still async.
+///     async: {
+///         // All imports are async except for functions with these names
+///         except_imports: ["foo", "bar"],
+///
+///         // All imports are synchronous except for functions with these names
+///         //
+///         // Note that this key cannot be specified with `except_imports`,
+///         // only one or the other is accepted.
+///         only_imports: ["foo", "bar"],
+///     },
+///
 ///     // This can be used to translate WIT return values of the form
 ///     // `result<T, error-type>` into `Result<T, RustErrorType>` in Rust.
 ///     // The `RustErrorType` structure will have an automatically generated
diff --git a/crates/wit-bindgen/src/lib.rs b/crates/wit-bindgen/src/lib.rs
index 44431ba2e..21ae6367b 100644
--- a/crates/wit-bindgen/src/lib.rs
+++ b/crates/wit-bindgen/src/lib.rs
@@ -3,7 +3,7 @@ use crate::types::{TypeInfo, Types};
 use anyhow::{anyhow, bail, Context};
 use heck::*;
 use indexmap::IndexMap;
-use std::collections::{BTreeMap, HashMap};
+use std::collections::{BTreeMap, HashMap, HashSet};
 use std::fmt::Write as _;
 use std::io::{Read, Write};
 use std::mem;
@@ -94,7 +94,7 @@ pub struct Opts {
     pub tracing: bool,
 
     /// Whether or not to use async rust functions and traits.
-    pub async_: bool,
+    pub async_: AsyncConfig,
 
     /// A list of "trappable errors" which are used to replace the `E` in
     /// `result<T, E>` found in WIT.
@@ -123,6 +123,42 @@ pub struct TrappableError {
     pub rust_type_name: String,
 }
 
+#[derive(Default, Debug, Clone)]
+pub enum AsyncConfig {
+    /// No functions are `async`.
+    #[default]
+    None,
+    /// All generated functions should be `async`.
+    All,
+    /// These imported functions should not be async, but everything else is.
+    AllExceptImports(HashSet<String>),
+    /// These functions are the only imports that are async, all other imports
+    /// are sync.
+    ///
+    /// Note that all exports are still async in this situation.
+    OnlyImports(HashSet<String>),
+}
+
+impl AsyncConfig {
+    pub fn is_import_async(&self, f: &str) -> bool {
+        match self {
+            AsyncConfig::None => false,
+            AsyncConfig::All => true,
+            AsyncConfig::AllExceptImports(set) => !set.contains(f),
+            AsyncConfig::OnlyImports(set) => set.contains(f),
+        }
+    }
+
+    pub fn maybe_async(&self) -> bool {
+        match self {
+            AsyncConfig::None => false,
+            AsyncConfig::All | AsyncConfig::AllExceptImports(_) | AsyncConfig::OnlyImports(_) => {
+                true
+            }
+        }
+    }
+}
+
 impl Opts {
     pub fn generate(&self, resolve: &Resolve, world: WorldId) -> String {
         let mut r = Wasmtime::default();
@@ -412,7 +448,7 @@ impl Wasmtime {
         }
         self.src.push_str("}\n");
 
-        let (async_, async__, send, await_) = if self.opts.async_ {
+        let (async_, async__, send, await_) = if self.opts.async_.maybe_async() {
             ("async", "_async", ":Send", ".await")
         } else {
             ("", "", "", "")
@@ -577,7 +613,7 @@ impl Wasmtime {
         }
 
         let world_camel = to_rust_upper_camel_case(&resolve.worlds[world].name);
-        if self.opts.async_ {
+        if self.opts.async_.maybe_async() {
             uwriteln!(self.src, "#[wasmtime::component::__internal::async_trait]")
         }
         uwrite!(self.src, "pub trait {world_camel}Imports");
@@ -646,7 +682,7 @@ impl Wasmtime {
             self.src.push_str(&name);
         }
 
-        let maybe_send = if self.opts.async_ {
+        let maybe_send = if self.opts.async_.maybe_async() {
             " + Send, T: Send"
         } else {
             ""
@@ -854,7 +890,7 @@ impl<'a> InterfaceGenerator<'a> {
         self.rustdoc(docs);
         uwriteln!(self.src, "pub enum {camel} {{}}");
 
-        if self.gen.opts.async_ {
+        if self.gen.opts.async_.maybe_async() {
             uwriteln!(self.src, "#[wasmtime::component::__internal::async_trait]")
         }
 
@@ -1375,7 +1411,7 @@ impl<'a> InterfaceGenerator<'a> {
         let iface = &self.resolve.interfaces[id];
         let owner = TypeOwner::Interface(id);
 
-        if self.gen.opts.async_ {
+        if self.gen.opts.async_.maybe_async() {
             uwriteln!(self.src, "#[wasmtime::component::__internal::async_trait]")
         }
         // Generate the `pub trait` which represents the host functionality for
@@ -1400,7 +1436,7 @@ impl<'a> InterfaceGenerator<'a> {
         }
         uwriteln!(self.src, "}}");
 
-        let where_clause = if self.gen.opts.async_ {
+        let where_clause = if self.gen.opts.async_.maybe_async() {
             "T: Send, U: Host + Send".to_string()
         } else {
             "U: Host".to_string()
@@ -1443,7 +1479,7 @@ impl<'a> InterfaceGenerator<'a> {
         uwrite!(
             self.src,
             "{linker}.{}(\"{}\", ",
-            if self.gen.opts.async_ {
+            if self.gen.opts.async_.is_import_async(&func.name) {
                 "func_wrap_async"
             } else {
                 "func_wrap"
@@ -1472,7 +1508,7 @@ impl<'a> InterfaceGenerator<'a> {
             self.src.push_str(", ");
         }
         self.src.push_str(") |");
-        if self.gen.opts.async_ {
+        if self.gen.opts.async_.is_import_async(&func.name) {
             self.src.push_str(" Box::new(async move { \n");
         } else {
             self.src.push_str(" { \n");
@@ -1541,7 +1577,7 @@ impl<'a> InterfaceGenerator<'a> {
         for (i, _) in func.params.iter().enumerate() {
             uwrite!(self.src, "arg{},", i);
         }
-        if self.gen.opts.async_ {
+        if self.gen.opts.async_.is_import_async(&func.name) {
             uwrite!(self.src, ").await;\n");
         } else {
             uwrite!(self.src, ");\n");
@@ -1571,7 +1607,7 @@ impl<'a> InterfaceGenerator<'a> {
             uwrite!(self.src, "r\n");
         }
 
-        if self.gen.opts.async_ {
+        if self.gen.opts.async_.is_import_async(&func.name) {
             // Need to close Box::new and async block
             self.src.push_str("})");
         } else {
@@ -1582,7 +1618,7 @@ impl<'a> InterfaceGenerator<'a> {
     fn generate_function_trait_sig(&mut self, func: &Function) {
         self.rustdoc(&func.docs);
 
-        if self.gen.opts.async_ {
+        if self.gen.opts.async_.is_import_async(&func.name) {
             self.push_str("async ");
         }
         self.push_str("fn ");
@@ -1658,7 +1694,11 @@ impl<'a> InterfaceGenerator<'a> {
         ns: Option<&WorldKey>,
         func: &Function,
     ) {
-        let (async_, async__, await_) = if self.gen.opts.async_ {
+        // Exports must be async if anything could be async, it's just imports
+        // that get to be optionally async/sync.
+        let is_async = self.gen.opts.async_.maybe_async();
+
+        let (async_, async__, await_) = if is_async {
             ("async", "_async", ".await")
         } else {
             ("", "", "")
@@ -1681,7 +1721,7 @@ impl<'a> InterfaceGenerator<'a> {
         self.src.push_str(") -> wasmtime::Result<");
         self.print_result_ty(&func.results, TypeMode::Owned);
 
-        if self.gen.opts.async_ {
+        if is_async {
             self.src
                 .push_str("> where <S as wasmtime::AsContext>::Data: Send {\n");
         } else {
diff --git a/src/bin/wasmtime.rs b/src/bin/wasmtime.rs
index d32a0b63f..6d425625d 100644
--- a/src/bin/wasmtime.rs
+++ b/src/bin/wasmtime.rs
@@ -4,7 +4,7 @@
 //! See `wasmtime --help` for usage.
 
 use anyhow::Result;
-use clap::Parser;
+use clap::{error::ErrorKind, Parser};
 use wasmtime_cli::commands::{
     CompileCommand, ConfigCommand, ExploreCommand, RunCommand, SettingsCommand, WastCommand,
 };
@@ -27,24 +27,10 @@ use wasmtime_cli::commands::{
                   \n\
                   Invoking a specific function (e.g. `add`) in a WebAssembly module:\n\
                   \n  \
-                  wasmtime example.wasm --invoke add 1 2\n",
-
-    // This option enables the pattern below where we ask clap to parse twice
-    // sorta: once where it's trying to find a subcommand and once assuming
-    // a subcommand doesn't get passed. Clap should then, apparently,
-    // fill in the `subcommand` if found and otherwise fill in the
-    // `RunCommand`.
-    args_conflicts_with_subcommands = true
+                  wasmtime example.wasm --invoke add 1 2\n"
 )]
-struct Wasmtime {
-    #[clap(subcommand)]
-    subcommand: Option<Subcommand>,
-    #[clap(flatten)]
-    run: RunCommand,
-}
-
-#[derive(Parser)]
-enum Subcommand {
+enum Wasmtime {
+    // !!! IMPORTANT: if subcommands are added or removed, update `parse_module` in `src/commands/run.rs`. !!!
     /// Controls Wasmtime configuration settings
     Config(ConfigCommand),
     /// Compiles a WebAssembly module.
@@ -62,20 +48,26 @@ enum Subcommand {
 impl Wasmtime {
     /// Executes the command.
     pub fn execute(self) -> Result<()> {
-        let subcommand = self.subcommand.unwrap_or(Subcommand::Run(self.run));
-        match subcommand {
-            Subcommand::Config(c) => c.execute(),
-            Subcommand::Compile(c) => c.execute(),
-            Subcommand::Explore(c) => c.execute(),
-            Subcommand::Run(c) => c.execute(),
-            Subcommand::Settings(c) => c.execute(),
-            Subcommand::Wast(c) => c.execute(),
+        match self {
+            Self::Config(c) => c.execute(),
+            Self::Compile(c) => c.execute(),
+            Self::Explore(c) => c.execute(),
+            Self::Run(c) => c.execute(),
+            Self::Settings(c) => c.execute(),
+            Self::Wast(c) => c.execute(),
         }
     }
 }
 
 fn main() -> Result<()> {
-    Wasmtime::parse().execute()
+    Wasmtime::try_parse()
+        .unwrap_or_else(|e| match e.kind() {
+            ErrorKind::InvalidSubcommand | ErrorKind::UnknownArgument => {
+                Wasmtime::Run(RunCommand::parse())
+            }
+            _ => e.exit(),
+        })
+        .execute()
 }
 
 #[test]
diff --git a/src/commands/run.rs b/src/commands/run.rs
index 3a3f080c9..398b9bf68 100644
--- a/src/commands/run.rs
+++ b/src/commands/run.rs
@@ -6,8 +6,11 @@
 )]
 
 use anyhow::{anyhow, bail, Context as _, Error, Result};
+use clap::builder::{OsStringValueParser, TypedValueParser};
 use clap::Parser;
 use once_cell::sync::Lazy;
+use std::ffi::OsStr;
+use std::ffi::OsString;
 use std::fs::File;
 use std::io::Write;
 use std::path::{Path, PathBuf};
@@ -35,6 +38,18 @@ use wasmtime_wasi_threads::WasiThreadsCtx;
 // #[cfg(feature = "wasi-http")]
 // use wasmtime_wasi_http::WasiHttpCtx;
 
+fn parse_module(s: OsString) -> anyhow::Result<PathBuf> {
+    // Do not accept wasmtime subcommand names as the module name
+    match s.to_str() {
+        Some("help") | Some("config") | Some("run") | Some("wast") | Some("compile") => {
+            bail!("module name cannot be the same as a subcommand")
+        }
+        #[cfg(unix)]
+        Some("-") => Ok(PathBuf::from("/dev/stdin")),
+        _ => Ok(s.into()),
+    }
+}
+
 fn parse_env_var(s: &str) -> Result<(String, Option<String>)> {
     let mut parts = s.splitn(2, '=');
     Ok((
@@ -103,7 +118,7 @@ static AFTER_HELP: Lazy<String> = Lazy::new(|| crate::FLAG_EXPLANATIONS.to_strin
 
 /// Runs a WebAssembly module
 #[derive(Parser)]
-#[structopt(name = "run", after_help = AFTER_HELP.as_str())]
+#[structopt(name = "run", trailing_var_arg = true, after_help = AFTER_HELP.as_str())]
 pub struct RunCommand {
     #[clap(flatten)]
     common: CommonOptions,
@@ -177,6 +192,14 @@ pub struct RunCommand {
     #[clap(long = "wasi-nn-graph", value_name = "FORMAT::HOST_DIR", value_parser = parse_graphs)]
     graphs: Vec<(String, String)>,
 
+    /// The path of the WebAssembly module to run
+    #[clap(
+        required = true,
+        value_name = "MODULE",
+        value_parser = OsStringValueParser::new().try_map(parse_module),
+    )]
+    module: PathBuf,
+
     /// Load the given WebAssembly module before the main module
     #[clap(
         long = "preload",
@@ -220,6 +243,11 @@ pub struct RunCommand {
     #[clap(long = "coredump-on-trap", value_name = "PATH")]
     coredump_on_trap: Option<String>,
 
+    // NOTE: this must come last for trailing varargs
+    /// The arguments to pass to the module
+    #[clap(value_name = "ARGS")]
+    module_args: Vec<String>,
+
     /// Maximum size, in bytes, that a linear memory is allowed to reach.
     ///
     /// Growth beyond this limit will cause `memory.grow` instructions in
@@ -258,14 +286,6 @@ pub struct RunCommand {
     #[clap(long)]
     wmemcheck: bool,
 
-    /// The WebAssembly module to run and arguments to pass to it.
-    ///
-    /// Arguments passed to the wasm module will be configured as WASI CLI
-    /// arguments unless the `--invoke` CLI argument is passed in which case
-    /// arguments will be interpreted as arguments to the function specified.
-    #[clap(value_name = "WASM", trailing_var_arg = true, required = true)]
-    module_and_args: Vec<PathBuf>,
-
     /// Indicates that the implementation of WASI preview1 should be backed by
     /// the preview2 implementation for components.
     ///
@@ -337,7 +357,7 @@ impl RunCommand {
         let engine = Engine::new(&config)?;
 
         // Read the wasm module binary either as `*.wat` or a raw binary.
-        let main = self.load_module(&engine, &self.module_and_args[0])?;
+        let main = self.load_module(&engine, &self.module)?;
 
         // Validate coredump-on-trap argument
         if let Some(coredump_path) = self.coredump_on_trap.as_ref() {
@@ -429,12 +449,8 @@ impl RunCommand {
         // Load the main wasm module.
         match self
             .load_main_module(&mut store, &mut linker, &main, modules)
-            .with_context(|| {
-                format!(
-                    "failed to run main module `{}`",
-                    self.module_and_args[0].display()
-                )
-            }) {
+            .with_context(|| format!("failed to run main module `{}`", self.module.display()))
+        {
             Ok(()) => (),
             Err(e) => {
                 // Exit the process if Wasmtime understands the error;
@@ -483,25 +499,27 @@ impl RunCommand {
         Ok(listeners)
     }
 
-    fn compute_argv(&self) -> Result<Vec<String>> {
+    fn compute_argv(&self) -> Vec<String> {
         let mut result = Vec::new();
 
-        for (i, arg) in self.module_and_args.iter().enumerate() {
-            // For argv[0], which is the program name. Only include the base
-            // name of the main wasm module, to avoid leaking path information.
-            let arg = if i == 0 {
-                arg.components().next_back().unwrap().as_os_str()
-            } else {
-                arg.as_ref()
-            };
-            result.push(
-                arg.to_str()
-                    .ok_or_else(|| anyhow!("failed to convert {arg:?} to utf-8"))?
-                    .to_string(),
-            );
+        // Add argv[0], which is the program name. Only include the base name of the
+        // main wasm module, to avoid leaking path information.
+        result.push(
+            self.module
+                .components()
+                .next_back()
+                .map(|c| c.as_os_str())
+                .and_then(OsStr::to_str)
+                .unwrap_or("")
+                .to_owned(),
+        );
+
+        // Add the remaining arguments.
+        for arg in self.module_args.iter() {
+            result.push(arg.clone());
         }
 
-        Ok(result)
+        result
     }
 
     fn setup_epoch_handler(
@@ -510,7 +528,7 @@ impl RunCommand {
         modules: Vec<(String, Module)>,
     ) -> Box<dyn FnOnce(&mut Store<Host>)> {
         if let Some(Profile::Guest { path, interval }) = &self.profile {
-            let module_name = self.module_and_args[0].to_str().unwrap_or("<main module>");
+            let module_name = self.module.to_str().unwrap_or("<main module>");
             let interval = *interval;
             store.data_mut().guest_profiler =
                 Some(Arc::new(GuestProfiler::new(module_name, interval, modules)));
@@ -616,10 +634,9 @@ impl RunCommand {
             CliLinker::Core(linker) => {
                 // Use "" as a default module name.
                 let module = module.unwrap_core();
-                linker.module(&mut *store, "", &module).context(format!(
-                    "failed to instantiate {:?}",
-                    self.module_and_args[0]
-                ))?;
+                linker
+                    .module(&mut *store, "", &module)
+                    .context(format!("failed to instantiate {:?}", self.module))?;
 
                 // If a function to invoke was given, invoke it.
                 let func = if let Some(name) = &self.invoke {
@@ -678,7 +695,7 @@ impl RunCommand {
                  is experimental and may break in the future"
             );
         }
-        let mut args = self.module_and_args.iter().skip(1);
+        let mut args = self.module_args.iter();
         let mut values = Vec::new();
         for ty in ty.params() {
             let val = match args.next() {
@@ -691,9 +708,6 @@ impl RunCommand {
                     }
                 }
             };
-            let val = val
-                .to_str()
-                .ok_or_else(|| anyhow!("argument is not valid utf-8: {val:?}"))?;
             values.push(match ty {
                 // TODO: integer parsing here should handle hexadecimal notation
                 // like `0x0...`, but the Rust standard library currently only
@@ -751,9 +765,7 @@ impl RunCommand {
         if !err.is::<wasmtime::Trap>() {
             return err;
         }
-        let source_name = self.module_and_args[0]
-            .to_str()
-            .unwrap_or_else(|| "unknown");
+        let source_name = self.module.to_str().unwrap_or_else(|| "unknown");
 
         if let Err(coredump_err) = generate_coredump(&err, &source_name, coredump_path) {
             eprintln!("warning: coredump failed to generate: {}", coredump_err);
@@ -990,7 +1002,7 @@ impl RunCommand {
 
     fn set_preview1_ctx(&self, store: &mut Store<Host>) -> Result<()> {
         let mut builder = WasiCtxBuilder::new();
-        builder.inherit_stdio().args(&self.compute_argv()?)?;
+        builder.inherit_stdio().args(&self.compute_argv())?;
 
         for (key, value) in self.vars.iter() {
             let value = match value {
@@ -1022,7 +1034,7 @@ impl RunCommand {
 
     fn set_preview2_ctx(&self, store: &mut Store<Host>) -> Result<()> {
         let mut builder = preview2::WasiCtxBuilder::new();
-        builder.inherit_stdio().args(&self.compute_argv()?);
+        builder.inherit_stdio().args(&self.compute_argv());
 
         for (key, value) in self.vars.iter() {
             let value = match value {


Test patch:
diff --git a/cranelift/filetests/filetests/isa/riscv64/constants.clif b/cranelift/filetests/filetests/isa/riscv64/constants.clif
index 9a1afa3b2..ed8ef4192 100644
--- a/cranelift/filetests/filetests/isa/riscv64/constants.clif
+++ b/cranelift/filetests/filetests/isa/riscv64/constants.clif
@@ -81,10 +81,10 @@ block0:
 ;
 ; Disassembled:
 ; block0: ; offset 0x0
-;   auipc t6, 0
-;   addi t6, t6, 0x10
-;   ld a0, 0(t6)
+;   auipc a0, 0
+;   ld a0, 0x10(a0)
 ;   ret
+;   .byte 0x00, 0x00, 0x00, 0x00
 ;   .byte 0x00, 0x00, 0xff, 0xff
 ;   .byte 0x00, 0x00, 0x00, 0x00
 
@@ -101,11 +101,11 @@ block0:
 ;
 ; Disassembled:
 ; block0: ; offset 0x0
-;   auipc t6, 0
-;   addi t6, t6, 0x10
-;   ld a0, 0(t6)
+;   auipc a0, 0
+;   ld a0, 0x10(a0)
 ;   ret
 ;   .byte 0x00, 0x00, 0x00, 0x00
+;   .byte 0x00, 0x00, 0x00, 0x00
 ;   .byte 0xff, 0xff, 0x00, 0x00
 
 function %f() -> i64 {
@@ -121,11 +121,11 @@ block0:
 ;
 ; Disassembled:
 ; block0: ; offset 0x0
-;   auipc t6, 0
-;   addi t6, t6, 0x10
-;   ld a0, 0(t6)
+;   auipc a0, 0
+;   ld a0, 0x10(a0)
 ;   ret
 ;   .byte 0x00, 0x00, 0x00, 0x00
+;   .byte 0x00, 0x00, 0x00, 0x00
 ;   .byte 0x00, 0x00, 0xff, 0xff
 
 function %f() -> i64 {
@@ -173,10 +173,10 @@ block0:
 ;
 ; Disassembled:
 ; block0: ; offset 0x0
-;   auipc t6, 0
-;   addi t6, t6, 0x10
-;   ld a0, 0(t6)
+;   auipc a0, 0
+;   ld a0, 0x10(a0)
 ;   ret
+;   .byte 0x00, 0x00, 0x00, 0x00
 ;   .byte 0xff, 0xff, 0x00, 0x00
 ;   .byte 0xff, 0xff, 0xff, 0xff
 
@@ -193,10 +193,10 @@ block0:
 ;
 ; Disassembled:
 ; block0: ; offset 0x0
-;   auipc t6, 0
-;   addi t6, t6, 0x10
-;   ld a0, 0(t6)
+;   auipc a0, 0
+;   ld a0, 0x10(a0)
 ;   ret
+;   .byte 0x00, 0x00, 0x00, 0x00
 ;   .byte 0xff, 0xff, 0xff, 0xff
 ;   .byte 0x00, 0x00, 0xff, 0xff
 
@@ -213,10 +213,10 @@ block0:
 ;
 ; Disassembled:
 ; block0: ; offset 0x0
-;   auipc t6, 0
-;   addi t6, t6, 0x10
-;   ld a0, 0(t6)
+;   auipc a0, 0
+;   ld a0, 0x10(a0)
 ;   ret
+;   .byte 0x00, 0x00, 0x00, 0x00
 ;   .byte 0xff, 0xff, 0xff, 0xff
 ;   .byte 0xff, 0xff, 0x00, 0x00
 
@@ -233,10 +233,10 @@ block0:
 ;
 ; Disassembled:
 ; block0: ; offset 0x0
-;   auipc t6, 0
-;   addi t6, t6, 0x10
-;   ld a0, 0(t6)
+;   auipc a0, 0
+;   ld a0, 0x10(a0)
 ;   ret
+;   .byte 0x00, 0x00, 0x00, 0x00
 ;   .byte 0x3a, 0x00, 0x12, 0x12
 ;   .byte 0xa3, 0xf0, 0x4b, 0xf3
 
@@ -253,10 +253,10 @@ block0:
 ;
 ; Disassembled:
 ; block0: ; offset 0x0
-;   auipc t6, 0
-;   addi t6, t6, 0x10
-;   ld a0, 0(t6)
+;   auipc a0, 0
+;   ld a0, 0x10(a0)
 ;   ret
+;   .byte 0x00, 0x00, 0x00, 0x00
 ;   .byte 0x00, 0x00, 0xf4, 0x1e
 ;   .byte 0x00, 0x00, 0xe9, 0x12
 
@@ -273,10 +273,10 @@ block0:
 ;
 ; Disassembled:
 ; block0: ; offset 0x0
-;   auipc t6, 0
-;   addi t6, t6, 0x10
-;   ld a0, 0(t6)
+;   auipc a0, 0
+;   ld a0, 0x10(a0)
 ;   ret
+;   .byte 0x00, 0x00, 0x00, 0x00
 ;   .byte 0xff, 0xff, 0xf4, 0x1e
 ;   .byte 0xff, 0xff, 0xe9, 0x12
 
@@ -325,10 +325,10 @@ block0:
 ;
 ; Disassembled:
 ; block0: ; offset 0x0
-;   auipc t6, 0
-;   addi t6, t6, 0x10
-;   ld a0, 0(t6)
+;   auipc a0, 0
+;   ld a0, 0x10(a0)
 ;   ret
+;   .byte 0x00, 0x00, 0x00, 0x00
 ;   .byte 0xf7, 0xff, 0xff, 0xff
 ;   .byte 0x00, 0x00, 0x00, 0x00
 
@@ -362,13 +362,11 @@ block0:
 ;
 ; Disassembled:
 ; block0: ; offset 0x0
-;   auipc t6, 0
-;   addi t6, t6, 0x18
-;   ld t0, 0(t6)
+;   auipc t0, 0
+;   ld t0, 0x10(t0)
 ;   fmv.d.x fa0, t0
 ;   ret
 ;   .byte 0x00, 0x00, 0x00, 0x00
-;   .byte 0x00, 0x00, 0x00, 0x00
 ;   .byte 0x00, 0x00, 0xf0, 0x3f
 
 function %f() -> f32 {
@@ -403,13 +401,11 @@ block0:
 ;
 ; Disassembled:
 ; block0: ; offset 0x0
-;   auipc t6, 0
-;   addi t6, t6, 0x18
-;   ld t0, 0(t6)
+;   auipc t0, 0
+;   ld t0, 0x10(t0)
 ;   fmv.d.x fa0, t0
 ;   ret
 ;   .byte 0x00, 0x00, 0x00, 0x00
-;   .byte 0x00, 0x00, 0x00, 0x00
 ;   .byte 0x00, 0x00, 0x49, 0x40
 
 function %f() -> f32 {
@@ -480,13 +476,11 @@ block0:
 ;
 ; Disassembled:
 ; block0: ; offset 0x0
-;   auipc t6, 0
-;   addi t6, t6, 0x18
-;   ld t0, 0(t6)
+;   auipc t0, 0
+;   ld t0, 0x10(t0)
 ;   fmv.d.x fa0, t0
 ;   ret
 ;   .byte 0x00, 0x00, 0x00, 0x00
-;   .byte 0x00, 0x00, 0x00, 0x00
 ;   .byte 0x00, 0x00, 0x30, 0xc0
 
 function %f() -> f32 {
diff --git a/cranelift/filetests/filetests/isa/riscv64/fcvt-small.clif b/cranelift/filetests/filetests/isa/riscv64/fcvt-small.clif
index feb8e7c7d..d85137c8e 100644
--- a/cranelift/filetests/filetests/isa/riscv64/fcvt-small.clif
+++ b/cranelift/filetests/filetests/isa/riscv64/fcvt-small.clif
@@ -92,10 +92,9 @@ block0(v0: f32):
 ; Disassembled:
 ; block0: ; offset 0x0
 ;   feq.s a0, fa0, fa0
-;   beqz a0, 0x44
+;   beqz a0, 0x40
 ;   auipc t6, 0
-;   addi t6, t6, 0x10
-;   lw t6, 0(t6)
+;   lw t6, 0xc(t6)
 ;   j 8
 ;   .byte 0x00, 0x00, 0x80, 0xbf
 ;   fmv.w.x ft3, t6
@@ -126,10 +125,9 @@ block0(v0: f64):
 ; Disassembled:
 ; block0: ; offset 0x0
 ;   feq.d a0, fa0, fa0
-;   beqz a0, 0x5c
+;   beqz a0, 0x54
 ;   auipc t6, 0
-;   addi t6, t6, 0x10
-;   ld t6, 0(t6)
+;   ld t6, 0xc(t6)
 ;   j 0xc
 ;   .byte 0x00, 0x00, 0x00, 0x00
 ;   .byte 0x00, 0x00, 0xf0, 0xbf
@@ -138,8 +136,7 @@ block0(v0: f64):
 ;   beqz a0, 8
 ;   .byte 0x00, 0x00, 0x00, 0x00 ; trap: int_ovf
 ;   auipc t6, 0
-;   addi t6, t6, 0x10
-;   ld t6, 0(t6)
+;   ld t6, 0xc(t6)
 ;   j 0xc
 ;   .byte 0x00, 0x00, 0x00, 0x00
 ;   .byte 0x00, 0x00, 0x70, 0x40
@@ -166,10 +163,9 @@ block0(v0: f32):
 ; Disassembled:
 ; block0: ; offset 0x0
 ;   feq.s a0, fa0, fa0
-;   beqz a0, 0x44
+;   beqz a0, 0x40
 ;   auipc t6, 0
-;   addi t6, t6, 0x10
-;   lw t6, 0(t6)
+;   lw t6, 0xc(t6)
 ;   j 8
 ;   .byte 0x00, 0x00, 0x80, 0xbf
 ;   fmv.w.x ft3, t6
@@ -200,10 +196,9 @@ block0(v0: f64):
 ; Disassembled:
 ; block0: ; offset 0x0
 ;   feq.d a0, fa0, fa0
-;   beqz a0, 0x5c
+;   beqz a0, 0x54
 ;   auipc t6, 0
-;   addi t6, t6, 0x10
-;   ld t6, 0(t6)
+;   ld t6, 0xc(t6)
 ;   j 0xc
 ;   .byte 0x00, 0x00, 0x00, 0x00
 ;   .byte 0x00, 0x00, 0xf0, 0xbf
@@ -212,8 +207,7 @@ block0(v0: f64):
 ;   beqz a0, 8
 ;   .byte 0x00, 0x00, 0x00, 0x00 ; trap: int_ovf
 ;   auipc t6, 0
-;   addi t6, t6, 0x10
-;   ld t6, 0(t6)
+;   ld t6, 0xc(t6)
 ;   j 0xc
 ;   .byte 0x00, 0x00, 0x00, 0x00
 ;   .byte 0x00, 0x00, 0xf0, 0x40
diff --git a/cranelift/filetests/filetests/isa/riscv64/float.clif b/cranelift/filetests/filetests/isa/riscv64/float.clif
index bf33bab5c..7b839f037 100644
--- a/cranelift/filetests/filetests/isa/riscv64/float.clif
+++ b/cranelift/filetests/filetests/isa/riscv64/float.clif
@@ -453,10 +453,9 @@ block0(v0: f64):
 ; block0: ; offset 0x0
 ;   fmv.d ft5, fa0
 ;   feq.d a0, ft5, ft5
-;   beqz a0, 0x3c
+;   beqz a0, 0x38
 ;   auipc t6, 0
-;   addi t6, t6, 0x10
-;   ld t6, 0(t6)
+;   ld t6, 0xc(t6)
 ;   j 0xc
 ;   .byte 0x00, 0x00, 0x00, 0x00
 ;   .byte 0x00, 0x00, 0x40, 0x43
@@ -520,10 +519,9 @@ block0(v0: f64):
 ; block0: ; offset 0x0
 ;   fmv.d ft5, fa0
 ;   feq.d a0, ft5, ft5
-;   beqz a0, 0x3c
+;   beqz a0, 0x38
 ;   auipc t6, 0
-;   addi t6, t6, 0x10
-;   ld t6, 0(t6)
+;   ld t6, 0xc(t6)
 ;   j 0xc
 ;   .byte 0x00, 0x00, 0x00, 0x00
 ;   .byte 0x00, 0x00, 0x40, 0x43
@@ -587,10 +585,9 @@ block0(v0: f64):
 ; block0: ; offset 0x0
 ;   fmv.d ft5, fa0
 ;   feq.d a0, ft5, ft5
-;   beqz a0, 0x3c
+;   beqz a0, 0x38
 ;   auipc t6, 0
-;   addi t6, t6, 0x10
-;   ld t6, 0(t6)
+;   ld t6, 0xc(t6)
 ;   j 0xc
 ;   .byte 0x00, 0x00, 0x00, 0x00
 ;   .byte 0x00, 0x00, 0x40, 0x43
@@ -654,10 +651,9 @@ block0(v0: f64):
 ; block0: ; offset 0x0
 ;   fmv.d ft5, fa0
 ;   feq.d a0, ft5, ft5
-;   beqz a0, 0x3c
+;   beqz a0, 0x38
 ;   auipc t6, 0
-;   addi t6, t6, 0x10
-;   ld t6, 0(t6)
+;   ld t6, 0xc(t6)
 ;   j 0xc
 ;   .byte 0x00, 0x00, 0x00, 0x00
 ;   .byte 0x00, 0x00, 0x40, 0x43
@@ -752,10 +748,9 @@ block0(v0: f32):
 ; Disassembled:
 ; block0: ; offset 0x0
 ;   feq.s a0, fa0, fa0
-;   beqz a0, 0x44
+;   beqz a0, 0x40
 ;   auipc t6, 0
-;   addi t6, t6, 0x10
-;   lw t6, 0(t6)
+;   lw t6, 0xc(t6)
 ;   j 8
 ;   .byte 0x00, 0x00, 0x80, 0xbf
 ;   fmv.w.x ft3, t6
@@ -786,10 +781,9 @@ block0(v0: f32):
 ; Disassembled:
 ; block0: ; offset 0x0
 ;   feq.s a0, fa0, fa0
-;   beqz a0, 0x44
+;   beqz a0, 0x40
 ;   auipc t6, 0
-;   addi t6, t6, 0x10
-;   lw t6, 0(t6)
+;   lw t6, 0xc(t6)
 ;   j 8
 ;   .byte 0x01, 0x00, 0x00, 0xcf
 ;   fmv.w.x ft3, t6
@@ -820,10 +814,9 @@ block0(v0: f32):
 ; Disassembled:
 ; block0: ; offset 0x0
 ;   feq.s a0, fa0, fa0
-;   beqz a0, 0x44
+;   beqz a0, 0x40
 ;   auipc t6, 0
-;   addi t6, t6, 0x10
-;   lw t6, 0(t6)
+;   lw t6, 0xc(t6)
 ;   j 8
 ;   .byte 0x00, 0x00, 0x80, 0xbf
 ;   fmv.w.x ft3, t6
@@ -854,10 +847,9 @@ block0(v0: f32):
 ; Disassembled:
 ; block0: ; offset 0x0
 ;   feq.s a0, fa0, fa0
-;   beqz a0, 0x44
+;   beqz a0, 0x40
 ;   auipc t6, 0
-;   addi t6, t6, 0x10
-;   lw t6, 0(t6)
+;   lw t6, 0xc(t6)
 ;   j 8
 ;   .byte 0x01, 0x00, 0x00, 0xdf
 ;   fmv.w.x ft3, t6
@@ -888,10 +880,9 @@ block0(v0: f64):
 ; Disassembled:
 ; block0: ; offset 0x0
 ;   feq.d a0, fa0, fa0
-;   beqz a0, 0x5c
+;   beqz a0, 0x54
 ;   auipc t6, 0
-;   addi t6, t6, 0x10
-;   ld t6, 0(t6)
+;   ld t6, 0xc(t6)
 ;   j 0xc
 ;   .byte 0x00, 0x00, 0x00, 0x00
 ;   .byte 0x00, 0x00, 0xf0, 0xbf
@@ -900,8 +891,7 @@ block0(v0: f64):
 ;   beqz a0, 8
 ;   .byte 0x00, 0x00, 0x00, 0x00 ; trap: int_ovf
 ;   auipc t6, 0
-;   addi t6, t6, 0x10
-;   ld t6, 0(t6)
+;   ld t6, 0xc(t6)
 ;   j 0xc
 ;   .byte 0x00, 0x00, 0x00, 0x00
 ;   .byte 0x00, 0x00, 0xf0, 0x41
@@ -928,10 +918,9 @@ block0(v0: f64):
 ; Disassembled:
 ; block0: ; offset 0x0
 ;   feq.d a0, fa0, fa0
-;   beqz a0, 0x5c
+;   beqz a0, 0x54
 ;   auipc t6, 0
-;   addi t6, t6, 0x10
-;   ld t6, 0(t6)
+;   ld t6, 0xc(t6)
 ;   j 0xc
 ;   .byte 0x00, 0x00, 0x20, 0x00
 ;   .byte 0x00, 0x00, 0xe0, 0xc1
@@ -940,8 +929,7 @@ block0(v0: f64):
 ;   beqz a0, 8
 ;   .byte 0x00, 0x00, 0x00, 0x00 ; trap: int_ovf
 ;   auipc t6, 0
-;   addi t6, t6, 0x10
-;   ld t6, 0(t6)
+;   ld t6, 0xc(t6)
 ;   j 0xc
 ;   .byte 0x00, 0x00, 0x00, 0x00
 ;   .byte 0x00, 0x00, 0xe0, 0x41
@@ -968,10 +956,9 @@ block0(v0: f64):
 ; Disassembled:
 ; block0: ; offset 0x0
 ;   feq.d a0, fa0, fa0
-;   beqz a0, 0x5c
+;   beqz a0, 0x54
 ;   auipc t6, 0
-;   addi t6, t6, 0x10
-;   ld t6, 0(t6)
+;   ld t6, 0xc(t6)
 ;   j 0xc
 ;   .byte 0x00, 0x00, 0x00, 0x00
 ;   .byte 0x00, 0x00, 0xf0, 0xbf
@@ -980,8 +967,7 @@ block0(v0: f64):
 ;   beqz a0, 8
 ;   .byte 0x00, 0x00, 0x00, 0x00 ; trap: int_ovf
 ;   auipc t6, 0
-;   addi t6, t6, 0x10
-;   ld t6, 0(t6)
+;   ld t6, 0xc(t6)
 ;   j 0xc
 ;   .byte 0x00, 0x00, 0x00, 0x00
 ;   .byte 0x00, 0x00, 0xf0, 0x43
@@ -1008,10 +994,9 @@ block0(v0: f64):
 ; Disassembled:
 ; block0: ; offset 0x0
 ;   feq.d a0, fa0, fa0
-;   beqz a0, 0x5c
+;   beqz a0, 0x54
 ;   auipc t6, 0
-;   addi t6, t6, 0x10
-;   ld t6, 0(t6)
+;   ld t6, 0xc(t6)
 ;   j 0xc
 ;   .byte 0x01, 0x00, 0x00, 0x00
 ;   .byte 0x00, 0x00, 0xe0, 0xc3
@@ -1020,8 +1005,7 @@ block0(v0: f64):
 ;   beqz a0, 8
 ;   .byte 0x00, 0x00, 0x00, 0x00 ; trap: int_ovf
 ;   auipc t6, 0
-;   addi t6, t6, 0x10
-;   ld t6, 0(t6)
+;   ld t6, 0xc(t6)
 ;   j 0xc
 ;   .byte 0x00, 0x00, 0x00, 0x00
 ;   .byte 0x00, 0x00, 0xe0, 0x43
diff --git a/cranelift/filetests/filetests/isa/riscv64/return-call.clif b/cranelift/filetests/filetests/isa/riscv64/return-call.clif
index f09e9bf61..335e3cb75 100644
--- a/cranelift/filetests/filetests/isa/riscv64/return-call.clif
+++ b/cranelift/filetests/filetests/isa/riscv64/return-call.clif
@@ -103,13 +103,13 @@ block0(v0: f64):
 ;
 ; Disassembled:
 ; block0: ; offset 0x0
-;   auipc t6, 0
-;   addi t6, t6, 0x18
-;   ld a0, 0(t6)
+;   auipc a0, 0
+;   ld a0, 0x18(a0)
 ;   fmv.d.x ft5, a0
 ;   fadd.d ft0, ft0, ft5
 ;   ret
 ;   .byte 0x00, 0x00, 0x00, 0x00
+;   .byte 0x00, 0x00, 0x00, 0x00
 ;   .byte 0x00, 0x00, 0x30, 0x40
 
 function %call_f64(f64) -> f64 tail {
diff --git a/cranelift/filetests/filetests/isa/riscv64/simd-ceil.clif b/cranelift/filetests/filetests/isa/riscv64/simd-ceil.clif
index 3cc3b9b21..d9fd8fe4c 100644
--- a/cranelift/filetests/filetests/isa/riscv64/simd-ceil.clif
+++ b/cranelift/filetests/filetests/isa/riscv64/simd-ceil.clif
@@ -107,9 +107,8 @@ block0(v0: f64x2):
 ;   .byte 0x87, 0x80, 0x0f, 0x02
 ;   .byte 0x57, 0x70, 0x81, 0xcd
 ;   .byte 0x57, 0x92, 0x10, 0x2a
-;   auipc t6, 0
-;   addi t6, t6, 0x4c
-;   ld a3, 0(t6)
+;   auipc a3, 0
+;   ld a3, 0x4c(a3)
 ;   fmv.d.x fa0, a3
 ;   .byte 0x57, 0x50, 0x45, 0x6e
 ;   fsrmi t4, 3
@@ -127,5 +126,6 @@ block0(v0: f64x2):
 ;   addi sp, sp, 0x10
 ;   ret
 ;   .byte 0x00, 0x00, 0x00, 0x00
+;   .byte 0x00, 0x00, 0x00, 0x00
 ;   .byte 0x00, 0x00, 0x30, 0x43
 
diff --git a/cranelift/filetests/filetests/isa/riscv64/simd-floor.clif b/cranelift/filetests/filetests/isa/riscv64/simd-floor.clif
index 6ecdcc7c8..3c045f8f9 100644
--- a/cranelift/filetests/filetests/isa/riscv64/simd-floor.clif
+++ b/cranelift/filetests/filetests/isa/riscv64/simd-floor.clif
@@ -107,9 +107,8 @@ block0(v0: f64x2):
 ;   .byte 0x87, 0x80, 0x0f, 0x02
 ;   .byte 0x57, 0x70, 0x81, 0xcd
 ;   .byte 0x57, 0x92, 0x10, 0x2a
-;   auipc t6, 0
-;   addi t6, t6, 0x4c
-;   ld a3, 0(t6)
+;   auipc a3, 0
+;   ld a3, 0x4c(a3)
 ;   fmv.d.x fa0, a3
 ;   .byte 0x57, 0x50, 0x45, 0x6e
 ;   fsrmi t4, 2
@@ -127,5 +126,6 @@ block0(v0: f64x2):
 ;   addi sp, sp, 0x10
 ;   ret
 ;   .byte 0x00, 0x00, 0x00, 0x00
+;   .byte 0x00, 0x00, 0x00, 0x00
 ;   .byte 0x00, 0x00, 0x30, 0x43
 
diff --git a/cranelift/filetests/filetests/isa/riscv64/simd-fmax.clif b/cranelift/filetests/filetests/isa/riscv64/simd-fmax.clif
index d3805bfb9..d576a7dcd 100644
--- a/cranelift/filetests/filetests/isa/riscv64/simd-fmax.clif
+++ b/cranelift/filetests/filetests/isa/riscv64/simd-fmax.clif
@@ -45,9 +45,8 @@ block0(v0: f64x2, v1: f64x2):
 ;   .byte 0x57, 0x93, 0x10, 0x62
 ;   .byte 0x57, 0x94, 0x31, 0x62
 ;   .byte 0x57, 0x20, 0x64, 0x66
-;   auipc t6, 0
-;   addi t6, t6, 0x34
-;   ld t4, 0(t6)
+;   auipc t4, 0
+;   ld t4, 0x2c(t4)
 ;   .byte 0x57, 0xc7, 0x0e, 0x5e
 ;   .byte 0x57, 0x98, 0x11, 0x1a
 ;   .byte 0x57, 0x09, 0xe8, 0x5c
@@ -58,7 +57,6 @@ block0(v0: f64x2, v1: f64x2):
 ;   addi sp, sp, 0x10
 ;   ret
 ;   .byte 0x00, 0x00, 0x00, 0x00
-;   .byte 0x00, 0x00, 0x00, 0x00
 ;   .byte 0x00, 0x00, 0xf8, 0x7f
 
 function %fmax_f32x4(f32x4, f32x4) -> f32x4 {
diff --git a/cranelift/filetests/filetests/isa/riscv64/simd-fmin.clif b/cranelift/filetests/filetests/isa/riscv64/simd-fmin.clif
index 80fe5210d..d653dae0a 100644
--- a/cranelift/filetests/filetests/isa/riscv64/simd-fmin.clif
+++ b/cranelift/filetests/filetests/isa/riscv64/simd-fmin.clif
@@ -45,9 +45,8 @@ block0(v0: f64x2, v1: f64x2):
 ;   .byte 0x57, 0x93, 0x10, 0x62
 ;   .byte 0x57, 0x94, 0x31, 0x62
 ;   .byte 0x57, 0x20, 0x64, 0x66
-;   auipc t6, 0
-;   addi t6, t6, 0x34
-;   ld t4, 0(t6)
+;   auipc t4, 0
+;   ld t4, 0x2c(t4)
 ;   .byte 0x57, 0xc7, 0x0e, 0x5e
 ;   .byte 0x57, 0x98, 0x11, 0x12
 ;   .byte 0x57, 0x09, 0xe8, 0x5c
@@ -58,7 +57,6 @@ block0(v0: f64x2, v1: f64x2):
 ;   addi sp, sp, 0x10
 ;   ret
 ;   .byte 0x00, 0x00, 0x00, 0x00
-;   .byte 0x00, 0x00, 0x00, 0x00
 ;   .byte 0x00, 0x00, 0xf8, 0x7f
 
 function %fmin_f32x4(f32x4, f32x4) -> f32x4 {
diff --git a/cranelift/filetests/filetests/isa/riscv64/simd-iadd_pairwise.clif b/cranelift/filetests/filetests/isa/riscv64/simd-iadd_pairwise.clif
index 02ea0cb57..c99beb5fa 100644
--- a/cranelift/filetests/filetests/isa/riscv64/simd-iadd_pairwise.clif
+++ b/cranelift/filetests/filetests/isa/riscv64/simd-iadd_pairwise.clif
@@ -45,18 +45,16 @@ block0(v0: i8x16, v1: i8x16):
 ;   .byte 0x87, 0x80, 0x0f, 0x02
 ;   addi t6, s0, 0x20
 ;   .byte 0x87, 0x81, 0x0f, 0x02
-;   auipc t6, 0
-;   addi t6, t6, 0x64
-;   ld a3, 0(t6)
+;   auipc a3, 0
+;   ld a3, 0x5c(a3)
 ;   .byte 0x57, 0x70, 0x81, 0xcd
 ;   .byte 0x57, 0xe4, 0x06, 0x42
 ;   .byte 0x57, 0x70, 0x08, 0xcc
 ;   .byte 0x57, 0x26, 0x14, 0x5e
 ;   .byte 0xd7, 0x26, 0x34, 0x5e
 ;   .byte 0x57, 0x36, 0xd4, 0x3a
-;   auipc t6, 0
-;   addi t6, t6, 0x48
-;   ld a1, 0(t6)
+;   auipc a1, 0
+;   ld a1, 0x44(a1)
 ;   .byte 0x57, 0x70, 0x81, 0xcd
 ;   .byte 0x57, 0xe9, 0x05, 0x42
 ;   .byte 0x57, 0x70, 0x08, 0xcc
@@ -118,18 +116,16 @@ block0(v0: i16x8, v1: i16x8):
 ;   .byte 0x87, 0x80, 0x0f, 0x02
 ;   addi t6, s0, 0x20
 ;   .byte 0x87, 0x81, 0x0f, 0x02
-;   auipc t6, 0
-;   addi t6, t6, 0x64
-;   ld a3, 0(t6)
+;   auipc a3, 0
+;   ld a3, 0x5c(a3)
 ;   .byte 0x57, 0x70, 0x81, 0xcd
 ;   .byte 0x57, 0xe4, 0x06, 0x42
 ;   .byte 0x57, 0x70, 0x84, 0xcc
 ;   .byte 0x57, 0x26, 0x14, 0x5e
 ;   .byte 0xd7, 0x26, 0x34, 0x5e
 ;   .byte 0x57, 0x36, 0xd2, 0x3a
-;   auipc t6, 0
-;   addi t6, t6, 0x48
-;   ld a1, 0(t6)
+;   auipc a1, 0
+;   ld a1, 0x44(a1)
 ;   .byte 0x57, 0x70, 0x81, 0xcd
 ;   .byte 0x57, 0xe9, 0x05, 0x42
 ;   .byte 0x57, 0x70, 0x84, 0xcc
@@ -191,18 +187,16 @@ block0(v0: i32x4, v1: i32x4):
 ;   .byte 0x87, 0x80, 0x0f, 0x02
 ;   addi t6, s0, 0x20
 ;   .byte 0x87, 0x81, 0x0f, 0x02
-;   auipc t6, 0
-;   addi t6, t6, 0x64
-;   ld a3, 0(t6)
+;   auipc a3, 0
+;   ld a3, 0x5c(a3)
 ;   .byte 0x57, 0x70, 0x81, 0xcd
 ;   .byte 0x57, 0xe4, 0x06, 0x42
 ;   .byte 0x57, 0x70, 0x02, 0xcd
 ;   .byte 0x57, 0x26, 0x14, 0x5e
 ;   .byte 0xd7, 0x26, 0x34, 0x5e
 ;   .byte 0x57, 0x36, 0xd1, 0x3a
-;   auipc t6, 0
-;   addi t6, t6, 0x48
-;   ld a1, 0(t6)
+;   auipc a1, 0
+;   ld a1, 0x44(a1)
 ;   .byte 0x57, 0x70, 0x81, 0xcd
 ;   .byte 0x57, 0xe9, 0x05, 0x42
 ;   .byte 0x57, 0x70, 0x02, 0xcd
diff --git a/cranelift/filetests/filetests/isa/riscv64/simd-nearest.clif b/cranelift/filetests/filetests/isa/riscv64/simd-nearest.clif
index 359fdf6a1..cf2e1892d 100644
--- a/cranelift/filetests/filetests/isa/riscv64/simd-nearest.clif
+++ b/cranelift/filetests/filetests/isa/riscv64/simd-nearest.clif
@@ -107,9 +107,8 @@ block0(v0: f64x2):
 ;   .byte 0x87, 0x80, 0x0f, 0x02
 ;   .byte 0x57, 0x70, 0x81, 0xcd
 ;   .byte 0x57, 0x92, 0x10, 0x2a
-;   auipc t6, 0
-;   addi t6, t6, 0x4c
-;   ld a3, 0(t6)
+;   auipc a3, 0
+;   ld a3, 0x4c(a3)
 ;   fmv.d.x fa0, a3
 ;   .byte 0x57, 0x50, 0x45, 0x6e
 ;   fsrmi t4, 0
@@ -127,5 +126,6 @@ block0(v0: f64x2):
 ;   addi sp, sp, 0x10
 ;   ret
 ;   .byte 0x00, 0x00, 0x00, 0x00
+;   .byte 0x00, 0x00, 0x00, 0x00
 ;   .byte 0x00, 0x00, 0x30, 0x43
 
diff --git a/cranelift/filetests/filetests/isa/riscv64/simd-popcnt.clif b/cranelift/filetests/filetests/isa/riscv64/simd-popcnt.clif
index 40246e80e..e81fe132e 100644
--- a/cranelift/filetests/filetests/isa/riscv64/simd-popcnt.clif
+++ b/cranelift/filetests/filetests/isa/riscv64/simd-popcnt.clif
@@ -273,29 +273,25 @@ block0(v0: i64x2):
 ;   .byte 0x57, 0x70, 0x08, 0xcc
 ;   addi t6, s0, 0x10
 ;   .byte 0x87, 0x80, 0x0f, 0x02
-;   auipc t6, 0
-;   addi t6, t6, 0x84
-;   ld a1, 0(t6)
+;   auipc a1, 0
+;   ld a1, 0x74(a1)
 ;   .byte 0x57, 0x70, 0x81, 0xcd
 ;   .byte 0x57, 0xb3, 0x10, 0xa2
 ;   .byte 0x57, 0xc4, 0x65, 0x26
 ;   .byte 0x57, 0x05, 0x14, 0x0a
-;   auipc t6, 0
-;   addi t6, t6, 0x70
-;   ld t4, 0(t6)
+;   auipc t4, 0
+;   ld t4, 0x64(t4)
 ;   .byte 0x57, 0x37, 0xa1, 0xa2
 ;   .byte 0x57, 0xc8, 0xee, 0x26
 ;   .byte 0x57, 0xc9, 0xae, 0x26
 ;   .byte 0x57, 0x0a, 0x28, 0x03
-;   auipc t6, 0
-;   addi t6, t6, 0x5c
-;   ld a6, 0(t6)
+;   auipc a6, 0
+;   ld a6, 0x54(a6)
 ;   .byte 0x57, 0x3c, 0x42, 0xa3
 ;   .byte 0x57, 0x0d, 0x4c, 0x03
 ;   .byte 0x57, 0x4e, 0xa8, 0x27
-;   auipc t6, 0
-;   addi t6, t6, 0x4c
-;   ld a1, 0(t6)
+;   auipc a1, 0
+;   ld a1, 0x48(a1)
 ;   .byte 0x57, 0xe0, 0xc5, 0x97
 ;   addi a5, zero, 0x38
 ;   .byte 0x57, 0xc2, 0x07, 0xa2
diff --git a/cranelift/filetests/filetests/isa/riscv64/simd-trunc.clif b/cranelift/filetests/filetests/isa/riscv64/simd-trunc.clif
index 515643924..2a9346870 100644
--- a/cranelift/filetests/filetests/isa/riscv64/simd-trunc.clif
+++ b/cranelift/filetests/filetests/isa/riscv64/simd-trunc.clif
@@ -101,9 +101,8 @@ block0(v0: f64x2):
 ;   .byte 0x87, 0x80, 0x0f, 0x02
 ;   .byte 0x57, 0x70, 0x81, 0xcd
 ;   .byte 0x57, 0x92, 0x10, 0x2a
-;   auipc t6, 0
-;   addi t6, t6, 0x44
-;   ld a3, 0(t6)
+;   auipc a3, 0
+;   ld a3, 0x44(a3)
 ;   fmv.d.x fa0, a3
 ;   .byte 0x57, 0x50, 0x45, 0x6e
 ;   .byte 0x57, 0x96, 0x13, 0x4a
@@ -119,5 +118,6 @@ block0(v0: f64x2):
 ;   addi sp, sp, 0x10
 ;   ret
 ;   .byte 0x00, 0x00, 0x00, 0x00
+;   .byte 0x00, 0x00, 0x00, 0x00
 ;   .byte 0x00, 0x00, 0x30, 0x43
 
diff --git a/cranelift/filetests/filetests/runtests/simd-ishl.clif b/cranelift/filetests/filetests/runtests/simd-ishl.clif
index 524bc2745..648d8f9fe 100644
--- a/cranelift/filetests/filetests/runtests/simd-ishl.clif
+++ b/cranelift/filetests/filetests/runtests/simd-ishl.clif
@@ -1,3 +1,4 @@
+test interpret
 test run
 target aarch64
 target s390x
diff --git a/cranelift/filetests/filetests/runtests/simd-sshr.clif b/cranelift/filetests/filetests/runtests/simd-sshr.clif
index a5fc47821..2df402270 100644
--- a/cranelift/filetests/filetests/runtests/simd-sshr.clif
+++ b/cranelift/filetests/filetests/runtests/simd-sshr.clif
@@ -1,3 +1,4 @@
+test interpret
 test run
 target aarch64
 target s390x
@@ -70,7 +71,7 @@ block0(v0: i8x16):
     v2 = sshr v0, v1
     return v2
 }
-; run: %i8x16_shl_const([0x01 0x02 0x04 0x08 0x10 0x20 0x40 0x80 0 0 0 0 0 0 0 0]) == [0 0 0x01 0x02 0x04 0x08 0x10 0xe0 0 0 0 0 0 0 0 0]
+; run: %i8x16_sshr_const([0x01 0x02 0x04 0x08 0x10 0x20 0x40 0x80 0 0 0 0 0 0 0 0]) == [0 0 0x01 0x02 0x04 0x08 0x10 0xe0 0 0 0 0 0 0 0 0]
 
 function %i16x8_sshr_const(i16x8) -> i16x8 {
 block0(v0: i16x8):
diff --git a/cranelift/filetests/filetests/runtests/simd-ushr.clif b/cranelift/filetests/filetests/runtests/simd-ushr.clif
index 5b188523e..5d8cf88be 100644
--- a/cranelift/filetests/filetests/runtests/simd-ushr.clif
+++ b/cranelift/filetests/filetests/runtests/simd-ushr.clif
@@ -1,3 +1,4 @@
+test interpret
 test run
 target aarch64
 target s390x
@@ -54,7 +55,7 @@ block0(v0: i8x16):
     v2 = ushr v0, v1
     return v2
 }
-; run: %i8x16_shl_const([0x01 0x02 0x04 0x08 0x10 0x20 0x40 0x80 0 0 0 0 0 0 0 0]) == [0 0 0x01 0x02 0x04 0x08 0x10 0x20 0 0 0 0 0 0 0 0]
+; run: %i8x16_ushr_const([0x01 0x02 0x04 0x08 0x10 0x20 0x40 0x80 0 0 0 0 0 0 0 0]) == [0 0 0x01 0x02 0x04 0x08 0x10 0x20 0 0 0 0 0 0 0 0]
 
 function %i16x8_ushr_const(i16x8) -> i16x8 {
 block0(v0: i16x8):
diff --git a/tests/all/cli_tests.rs b/tests/all/cli_tests.rs
index 29561129c..f144dd933 100644
--- a/tests/all/cli_tests.rs
+++ b/tests/all/cli_tests.rs
@@ -604,6 +604,7 @@ fn wasm_flags() -> Result<()> {
     let stdout = run_wasmtime(&[
         "run",
         "tests/all/cli_tests/print-arguments.wat",
+        "--",
         "--argument",
         "-for",
         "the",
@@ -619,7 +620,7 @@ fn wasm_flags() -> Result<()> {
             command\n\
         "
     );
-    let stdout = run_wasmtime(&["run", "tests/all/cli_tests/print-arguments.wat", "-"])?;
+    let stdout = run_wasmtime(&["run", "tests/all/cli_tests/print-arguments.wat", "--", "-"])?;
     assert_eq!(
         stdout,
         "\
@@ -627,7 +628,7 @@ fn wasm_flags() -> Result<()> {
             -\n\
         "
     );
-    let stdout = run_wasmtime(&["run", "tests/all/cli_tests/print-arguments.wat", "--"])?;
+    let stdout = run_wasmtime(&["run", "tests/all/cli_tests/print-arguments.wat", "--", "--"])?;
     assert_eq!(
         stdout,
         "\
@@ -648,7 +649,6 @@ fn wasm_flags() -> Result<()> {
         "\
             print-arguments.wat\n\
             --\n\
-            --\n\
             -a\n\
             b\n\
         "
@@ -658,30 +658,37 @@ fn wasm_flags() -> Result<()> {
 
 #[test]
 fn name_same_as_builtin_command() -> Result<()> {
-    // a bare subcommand shouldn't run successfully
+    // A bare subcommand shouldn't run successfully.
+    //
+    // This is ambiguous between a missing module argument and a module named
+    // `run` with no other options.
     let output = get_wasmtime_command()?
         .current_dir("tests/all/cli_tests")
         .arg("run")
         .output()?;
     assert!(!output.status.success());
 
-    // a `--` prefix should let everything else get interpreted as a wasm
-    // module and arguments, even if the module has a name like `run`
+    // Currently even `--` isn't enough to disambiguate, so this still is an
+    // error.
+    //
+    // NB: this will change in Wasmtime 14 when #6737 is relanded.
     let output = get_wasmtime_command()?
         .current_dir("tests/all/cli_tests")
         .arg("--")
         .arg("run")
         .output()?;
-    assert!(output.status.success(), "expected success got {output:#?}");
+    assert!(!output.status.success(), "expected failure got {output:#?}");
 
-    // Passing options before the subcommand should work and doesn't require
-    // `--` to disambiguate
+    // Passing `--foo` options before the module is also not enough to
+    // disambiguate for now.
+    //
+    // NB: this will change in Wasmtime 14 when #6737 is relanded.
     let output = get_wasmtime_command()?
         .current_dir("tests/all/cli_tests")
         .arg("--disable-cache")
         .arg("run")
         .output()?;
-    assert!(output.status.success(), "expected success got {output:#?}");
+    assert!(!output.status.success(), "expected failure got {output:#?}");
     Ok(())
 }
 
@@ -701,6 +708,7 @@ fn wasm_flags_without_subcommand() -> Result<()> {
     let output = get_wasmtime_command()?
         .current_dir("tests/all/cli_tests/")
         .arg("print-arguments.wat")
+        .arg("--")
         .arg("-foo")
         .arg("bar")
         .output()?;
diff --git a/tests/all/component_model/bindgen.rs b/tests/all/component_model/bindgen.rs
index dbe65a3dd..f0160dc92 100644
--- a/tests/all/component_model/bindgen.rs
+++ b/tests/all/component_model/bindgen.rs
@@ -316,3 +316,97 @@ mod resources_at_interface_level {
         Ok(())
     }
 }
+
+mod async_config {
+    use super::*;
+
+    wasmtime::component::bindgen!({
+        inline: "
+            package foo:foo
+
+            world t1 {
+                import x: func()
+                import y: func()
+                export z: func()
+            }
+        ",
+        async: true,
+    });
+
+    struct T;
+
+    #[async_trait::async_trait]
+    impl T1Imports for T {
+        async fn x(&mut self) -> Result<()> {
+            Ok(())
+        }
+
+        async fn y(&mut self) -> Result<()> {
+            Ok(())
+        }
+    }
+
+    async fn _test_t1(t1: &T1, store: &mut Store<()>) {
+        let _ = t1.call_z(&mut *store).await;
+    }
+
+    wasmtime::component::bindgen!({
+        inline: "
+            package foo:foo
+
+            world t2 {
+                import x: func()
+                import y: func()
+                export z: func()
+            }
+        ",
+        async: {
+            except_imports: ["x"],
+        },
+    });
+
+    #[async_trait::async_trait]
+    impl T2Imports for T {
+        fn x(&mut self) -> Result<()> {
+            Ok(())
+        }
+
+        async fn y(&mut self) -> Result<()> {
+            Ok(())
+        }
+    }
+
+    async fn _test_t2(t2: &T2, store: &mut Store<()>) {
+        let _ = t2.call_z(&mut *store).await;
+    }
+
+    wasmtime::component::bindgen!({
+        inline: "
+            package foo:foo
+
+            world t3 {
+                import x: func()
+                import y: func()
+                export z: func()
+            }
+        ",
+        async: {
+            only_imports: ["x"],
+        },
+    });
+
+    #[async_trait::async_trait]
+    impl T3Imports for T {
+        async fn x(&mut self) -> Result<()> {
+            Ok(())
+        }
+
+        fn y(&mut self) -> Result<()> {
+            Ok(())
+        }
+    }
+
+    async fn _test_t3(t3: &T3, store: &mut Store<()>) {
+        let _ = t3.call_z(&mut *store).await;
+    }
+}