Repository: bytecodealliance/wasmtime
Pull request #8850 (2024-06-20 19:05:46)

riscv64: Update `Inst::worst_case_size`
👋 Hey,

This PR updates the `Inst::worst_case_size` size for the RISC-V backend. The panic that happens in #8847 is entirely due to the `return_call_indirect` generating too many bytes.

I found it difficult to add an automatic calculation of the worst possible size for that instruction to the test that we have, so I attempted to manually calculate the worst case size and used that.

The two test cases here are the original test case, and a minimized version without zicond. I'm not entirely sure why it bisects to the ZiCond PR (https://github.com/bytecodealliance/wasmtime/pull/8695), but having both test cases is not too much of a burden, so might as well.

The increased worst case size now causes an island to be emitted in the `return-call.clif` test, which are the changes for that test in this PR.


Patch:
diff --git a/cranelift/codegen/src/isa/riscv64/abi.rs b/cranelift/codegen/src/isa/riscv64/abi.rs
index 05f3f3a45..d13949c1d 100644
--- a/cranelift/codegen/src/isa/riscv64/abi.rs
+++ b/cranelift/codegen/src/isa/riscv64/abi.rs
@@ -855,7 +855,7 @@ fn compute_clobber_size(clobbers: &[Writable<RealReg>]) -> u32 {
     align_to(clobbered_size, 16)
 }
 
-const DEFAULT_CLOBBERS: PRegSet = PRegSet::empty()
+pub(crate) const DEFAULT_CLOBBERS: PRegSet = PRegSet::empty()
     .with(px_reg(1))
     .with(px_reg(5))
     .with(px_reg(6))
diff --git a/cranelift/codegen/src/isa/riscv64/inst/emit.rs b/cranelift/codegen/src/isa/riscv64/inst/emit.rs
index db3b3c198..044368a5b 100644
--- a/cranelift/codegen/src/isa/riscv64/inst/emit.rs
+++ b/cranelift/codegen/src/isa/riscv64/inst/emit.rs
@@ -47,14 +47,14 @@ pub enum EmitVState {
 #[derive(Default, Clone, Debug)]
 pub struct EmitState {
     /// Safepoint stack map for upcoming instruction, as provided to `pre_safepoint()`.
-    stack_map: Option<StackMap>,
+    pub(crate) stack_map: Option<StackMap>,
     /// Only used during fuzz-testing. Otherwise, it is a zero-sized struct and
     /// optimized away at compiletime. See [cranelift_control].
-    ctrl_plane: ControlPlane,
+    pub(crate) ctrl_plane: ControlPlane,
     /// Vector State
     /// Controls the current state of the vector unit at the emission point.
-    vstate: EmitVState,
-    frame_layout: FrameLayout,
+    pub(crate) vstate: EmitVState,
+    pub(crate) frame_layout: FrameLayout,
 }
 
 impl EmitState {
diff --git a/cranelift/codegen/src/isa/riscv64/inst/mod.rs b/cranelift/codegen/src/isa/riscv64/inst/mod.rs
index a846c6024..b03f8e98e 100644
--- a/cranelift/codegen/src/isa/riscv64/inst/mod.rs
+++ b/cranelift/codegen/src/isa/riscv64/inst/mod.rs
@@ -844,8 +844,8 @@ impl MachInst for Inst {
     }
 
     fn worst_case_size() -> CodeOffset {
-        // calculate by test function riscv64_worst_case_instruction_size()
-        124
+        // Our worst case size is determined by the riscv64_worst_case_instruction_size test
+        168
     }
 
     fn ref_type_regclass(_settings: &settings::Flags) -> RegClass {
diff --git a/cranelift/codegen/src/isa/riscv64/lower.isle b/cranelift/codegen/src/isa/riscv64/lower.isle
index d287e0c7b..04de11d1f 100644
--- a/cranelift/codegen/src/isa/riscv64/lower.isle
+++ b/cranelift/codegen/src/isa/riscv64/lower.isle
@@ -2465,20 +2465,25 @@
 
 ;; These rules should probably be handled in `gen_bitcast`, but it's convenient to have that return
 ;; a single register, instead of a `ValueRegs`
-(rule 2 (lower (has_type $I128 (bitcast _ v @ (value_type (ty_vec_fits_in_register _)))))
+(rule 3 (lower (has_type $I128 (bitcast _ v @ (value_type (ty_vec_fits_in_register _)))))
     (value_regs
       (gen_extractlane $I64X2 v 0)
       (gen_extractlane $I64X2 v 1)))
 
 ;; Move the high half into a vector register, and then use vslide1up to move it up and
 ;; insert the lower half in one instruction.
-(rule 1 (lower (has_type (ty_vec_fits_in_register _) (bitcast _ v @ (value_type $I128))))
+(rule 2 (lower (has_type (ty_vec_fits_in_register _) (bitcast _ v @ (value_type $I128))))
     (let ((lo XReg (value_regs_get v 0))
           (hi XReg (value_regs_get v 1))
           (vstate VState (vstate_from_type $I64X2))
           (vec VReg (rv_vmv_sx hi vstate)))
       (rv_vslide1up_vx vec vec lo (unmasked) vstate)))
 
+;; `gen_bitcast` below only works with single register values, so handle I128
+;; specially here.
+(rule 1 (lower (has_type $I128 (bitcast _ v @ (value_type $I128))))
+   v)
+
 (rule 0 (lower (has_type out_ty (bitcast _ v @ (value_type in_ty))))
    (gen_bitcast v in_ty out_ty))
 


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 5a00e4f4d..ffa5f118f 100644
--- a/cranelift/codegen/src/isa/riscv64/inst/emit_tests.rs
+++ b/cranelift/codegen/src/isa/riscv64/inst/emit_tests.rs
@@ -1,6 +1,6 @@
 #[allow(unused)]
 use crate::ir::LibCall;
-use crate::isa::riscv64::inst::*;
+use crate::isa::riscv64::{abi::DEFAULT_CLOBBERS, inst::*};
 use std::borrow::Cow;
 
 fn fa7() -> Reg {
@@ -2135,7 +2135,7 @@ fn riscv64_worst_case_instruction_size() {
     let (flags, isa_flags) = make_test_flags();
     let emit_info = EmitInfo::new(flags, isa_flags);
 
-    //there are all candidates potential generate a lot of bytes.
+    // These are all candidate instructions with potential to generate a lot of bytes.
     let mut candidates: Vec<MInst> = vec![];
 
     candidates.push(Inst::Popcnt {
@@ -2198,10 +2198,40 @@ fn riscv64_worst_case_instruction_size() {
             }),
     );
 
+    candidates.push(Inst::ReturnCallInd {
+        callee: a0(),
+        info: Box::new(ReturnCallInfo {
+            opcode: Opcode::ReturnCallIndirect,
+            new_stack_arg_size: 64,
+            uses: DEFAULT_CLOBBERS
+                .into_iter()
+                .map(|reg| CallArgPair {
+                    vreg: reg.into(),
+                    preg: reg.into(),
+                })
+                .collect(),
+        }),
+    });
+
     let mut max: (u32, MInst) = (0, Inst::Nop0);
     for i in candidates {
         let mut buffer = MachBuffer::new();
-        i.emit(&mut buffer, &emit_info, &mut Default::default());
+        let mut emit_state = EmitState {
+            // This frame layout is important to ensure that the ReturnCallIndirect
+            // instruction in this test, becomes as large as practically possible.
+            frame_layout: FrameLayout {
+                tail_args_size: 64,
+                setup_area_size: 8192,
+                clobbered_callee_saves: DEFAULT_CLOBBERS
+                    .into_iter()
+                    .filter(|r| r.class() != RegClass::Vector)
+                    .map(|r| Writable::from_reg(r.into()))
+                    .collect(),
+                ..Default::default()
+            },
+            ..Default::default()
+        };
+        i.emit(&mut buffer, &emit_info, &mut emit_state);
         let buffer = buffer.finish(&Default::default(), &mut Default::default());
         let length = buffer.data().len() as u32;
         if length > max.0 {
diff --git a/cranelift/filetests/filetests/isa/riscv64/issue8847-1.clif b/cranelift/filetests/filetests/isa/riscv64/issue8847-1.clif
new file mode 100644
index 000000000..64dae40ca
--- /dev/null
+++ b/cranelift/filetests/filetests/isa/riscv64/issue8847-1.clif
@@ -0,0 +1,57 @@
+;; Compile test case
+
+test compile
+target riscv64
+
+function u1:0() tail {
+    ss0 = explicit_slot 50, align = 512
+    ss1 = explicit_slot 47, align = 4
+    ss2 = explicit_slot 34, align = 32
+    ss3 = explicit_slot 103, align = 1024
+    ss4 = explicit_slot 110, align = 512
+    ss5 = explicit_slot 126, align = 512
+    sig0 = (i64 sext, i64 sext, i64 sext, i64 sext, i64 sext, i64 sext, i64 sext, i8 uext, i16 uext, i16, i64 sext, i64 sext, i128 uext, i8 sext, f32) tail
+
+block0:
+    v0 = iconst.i64 0xef31_de2a_2352_79ff
+    v3 = iconst.i16 0xffef
+    v164 = iconst.i64 0
+    v7 = uextend.i128 v164  ; v164 = 0
+    v14 = iconst.i8 203
+    v15 = f32const -0x1.979796p24
+    v112 = iconst.i8 0
+    v134 = iconst.i8 0
+    v147 = iconst.i8 0
+    v154 = iconst.i8 0
+    v156 = iconst.i32 0
+    v157 = iconst.i32 0
+    v163 = iconst.i64 0
+    brif v112, block40, block39  ; v112 = 0
+
+block40:
+    trap user0
+
+block39:
+    brif.i8 v134, block58, block57  ; v134 = 0
+
+block58:
+    trap user0
+
+block57:
+    brif.i8 v147, block68, block67  ; v147 = 0
+
+block68:
+    trap user0
+
+block67:
+    brif.i8 v154, block73, block72  ; v154 = 0
+
+block73:
+    br_table v156, block1, [block1, block1]  ; v156 = 0
+
+block72:
+    br_table v157, block1, [block1, block1]  ; v157 = 0
+
+block1 cold:
+    return_call_indirect.i64 sig0, v163(v0, v0, v0, v0, v0, v0, v0, v14, v3, v3, v0, v0, v7, v14, v15)  ; v163 = 0, v0 = 0xef31_de2a_2352_79ff, v0 = 0xef31_de2a_2352_79ff, v0 = 0xef31_de2a_2352_79ff, v0 = 0xef31_de2a_2352_79ff, v0 = 0xef31_de2a_2352_79ff, v0 = 0xef31_de2a_2352_79ff, v0 = 0xef31_de2a_2352_79ff, v14 = 203, v3 = 0xffef, v3 = 0xffef, v0 = 0xef31_de2a_2352_79ff, v0 = 0xef31_de2a_2352_79ff, v14 = 203, v15 = -0x1.979796p24
+}
diff --git a/cranelift/filetests/filetests/isa/riscv64/issue8847.clif b/cranelift/filetests/filetests/isa/riscv64/issue8847.clif
new file mode 100644
index 000000000..c7c79d5b8
--- /dev/null
+++ b/cranelift/filetests/filetests/isa/riscv64/issue8847.clif
@@ -0,0 +1,480 @@
+;; Compile test case
+
+test compile
+set bb_padding_log2_minus_one=4
+set enable_alias_analysis=false
+set enable_llvm_abi_extensions=true
+set machine_code_cfg_info=true
+set enable_jump_tables=false
+set enable_heap_access_spectre_mitigation=false
+target riscv64 has_zcd has_zbkb has_zbc has_zbs has_zicond has_zvl32b has_zvl64b has_zvl128b has_zvl1024b has_zvl2048b has_zvl4096b has_zvl8192b has_zvl16384b has_zvl32768b
+
+function u1:0() tail {
+    ss0 = explicit_slot 50, align = 512
+    ss1 = explicit_slot 47, align = 4
+    ss2 = explicit_slot 34, align = 32
+    ss3 = explicit_slot 103, align = 1024
+    ss4 = explicit_slot 110, align = 512
+    ss5 = explicit_slot 126, align = 512
+    sig0 = (f32, f64, f64, f32, i8 uext, i128, i8 uext, i32, i16 sext, i64, i64 sext, i128, i8 sext, i8, i64, i64 sext) -> i16 sext, i64 sext, f64, i32 sext, f64, i8 sext, i64 sext, f32
+    sig1 = () system_v
+    sig2 = (i128, i16 sext, i128 sext, i32 sext, i16, i64 uext, f32, i8 sext, f32, i8, i64, i64, i64, i64 uext, f64) -> f64, i8 uext, f32, i128, i64 uext, i8, i16 sext, i64 sext tail
+    sig3 = () -> i8 sext, f32, i128, i32, f32, i128 uext, i8, i8 uext, f64, i8 sext, f32 system_v
+    sig4 = (i8, i16, i64 sext, i64 sext, i128 uext, i8, i32, f64, i32, f32, i128 uext, i8, i8 uext, f64, f64) -> i8 uext system_v
+    sig5 = (i8 sext, i64 uext, i16 sext, i64 sext, i128 uext, i128 sext, f32, i16 uext, i64 sext, i32 sext, i64, i64 uext, f64, f64, i16 sext) -> f32 tail
+    sig6 = (i64 sext, i64 sext, i64 sext, i64 sext, i64 sext, i64 sext, i64 sext, i8 uext, i16 uext, i16, i64 sext, i64 sext, i128 uext, i8 sext, f32) tail
+    sig7 = (f32) -> f32 system_v
+    sig8 = (f64) -> f64 system_v
+    sig9 = (f32) -> f32 system_v
+    sig10 = (f64) -> f64 system_v
+    sig11 = (f32) -> f32 system_v
+    sig12 = (f64) -> f64 system_v
+    sig13 = (f32) -> f32 system_v
+    sig14 = (f64) -> f64 system_v
+    sig15 = (f32, f32, f32) -> f32 system_v
+    sig16 = (f64, f64, f64) -> f64 system_v
+    fn0 = colocated u2:0 sig0
+    fn1 = colocated u2:1 sig1
+    fn2 = colocated u2:2 sig2
+    fn3 = colocated u2:3 sig3
+    fn4 = colocated u2:4 sig4
+    fn5 = colocated u2:5 sig5
+    fn6 = colocated u2:6 sig6
+    fn7 = %CeilF32 sig7
+    fn8 = %CeilF64 sig8
+    fn9 = %FloorF32 sig9
+    fn10 = %FloorF64 sig10
+    fn11 = colocated %TruncF32 sig11
+    fn12 = %TruncF64 sig12
+    fn13 = colocated %NearestF32 sig13
+    fn14 = %NearestF64 sig14
+    fn15 = %FmaF32 sig15
+    fn16 = %FmaF64 sig16
+
+block0:
+    v0 = iconst.i64 0xef31_de2a_2352_79ff
+    v158 -> v0
+    v1 = iconst.i64 0x2231_ffd1_ff29_ff26
+    v2 = f64const 0x1.8ff2320672823p-225
+    v3 = iconst.i16 0xffef
+    v160 -> v3
+    v4 = iconst.i64 0xddde_2a23_52f9_ffff
+    v5 = iconst.i64 0xc8c8_c8c8_c8c8_c8c8
+    v6 = iconst.i64 0xc8c8_c8c8_c8c8_c8c8
+    v7 = iconcat v6, v5  ; v6 = 0xc8c8_c8c8_c8c8_c8c8, v5 = 0xc8c8_c8c8_c8c8_c8c8
+    v161 -> v7
+    v8 = iconst.i64 0xc8c8_c8c8_c8c8_c8c8
+    v9 = iconst.i64 0xc8c8_c8c8_c8c8_c8c8
+    v10 = iconcat v9, v8  ; v9 = 0xc8c8_c8c8_c8c8_c8c8, v8 = 0xc8c8_c8c8_c8c8_c8c8
+    v11 = iconst.i64 0xcbcb_cbcb_cbc8_c8c8
+    v12 = iconst.i64 0xc8c8_c8c8_c8c8_c8c8
+    v13 = iconcat v12, v11  ; v12 = 0xc8c8_c8c8_c8c8_c8c8, v11 = 0xcbcb_cbcb_cbc8_c8c8
+    v14 = iconst.i8 203
+    v159 -> v14
+    v15 = f32const -0x1.979796p24
+    v162 -> v15
+    v16 = iconst.i64 0x0031_2222_2a2f
+    v17 = iconst.i64 0xcbcb_2adc_9e98_d7d4
+    v18 = iconcat v17, v16  ; v17 = 0xcbcb_2adc_9e98_d7d4, v16 = 0x0031_2222_2a2f
+    v19 = iconst.i8 0
+    v20 = iconst.i16 0
+    v21 = iconst.i32 0
+    v22 = iconst.i64 0
+    v23 = uextend.i128 v22  ; v22 = 0
+    v24 = stack_addr.i64 ss2
+    store notrap table v23, v24
+    v25 = stack_addr.i64 ss2+16
+    store notrap table v23, v25
+    v26 = stack_addr.i64 ss2+32
+    store notrap table v20, v26  ; v20 = 0
+    v27 = stack_addr.i64 ss1
+    store notrap table v23, v27
+    v28 = stack_addr.i64 ss1+16
+    store notrap table v23, v28
+    v29 = stack_addr.i64 ss1+32
+    store notrap table v22, v29  ; v22 = 0
+    v30 = stack_addr.i64 ss1+40
+    store notrap table v21, v30  ; v21 = 0
+    v31 = stack_addr.i64 ss1+44
+    store notrap table v20, v31  ; v20 = 0
+    v32 = stack_addr.i64 ss1+46
+    store notrap table v19, v32  ; v19 = 0
+    v33 = stack_addr.i64 ss0
+    store notrap table v23, v33
+    v34 = stack_addr.i64 ss0+16
+    store notrap table v23, v34
+    v35 = stack_addr.i64 ss0+32
+    store notrap table v23, v35
+    v36 = stack_addr.i64 ss0+48
+    store notrap table v20, v36  ; v20 = 0
+    v37 = stack_addr.i64 ss3
+    store notrap vmctx v23, v37
+    v38 = stack_addr.i64 ss3+16
+    store notrap vmctx v23, v38
+    v39 = stack_addr.i64 ss3+32
+    store notrap vmctx v23, v39
+    v40 = stack_addr.i64 ss3+48
+    store notrap vmctx v23, v40
+    v41 = stack_addr.i64 ss3+64
+    store notrap vmctx v23, v41
+    v42 = stack_addr.i64 ss3+80
+    store notrap vmctx v23, v42
+    v43 = stack_addr.i64 ss3+96
+    store notrap vmctx v21, v43  ; v21 = 0
+    v44 = stack_addr.i64 ss3+100
+    store notrap vmctx v20, v44  ; v20 = 0
+    v45 = stack_addr.i64 ss3+102
+    store notrap vmctx v19, v45  ; v19 = 0
+    v46 = stack_addr.i64 ss4
+    store notrap heap v23, v46
+    v47 = stack_addr.i64 ss4+16
+    store notrap heap v23, v47
+    v48 = stack_addr.i64 ss4+32
+    store notrap heap v23, v48
+    v49 = stack_addr.i64 ss4+48
+    store notrap heap v23, v49
+    v50 = stack_addr.i64 ss4+64
+    store notrap heap v23, v50
+    v51 = stack_addr.i64 ss4+80
+    store notrap heap v23, v51
+    v52 = stack_addr.i64 ss4+96
+    store notrap heap v22, v52  ; v22 = 0
+    v53 = stack_addr.i64 ss4+104
+    store notrap heap v21, v53  ; v21 = 0
+    v54 = stack_addr.i64 ss4+108
+    store notrap heap v20, v54  ; v20 = 0
+    v55 = stack_addr.i64 ss5
+    store notrap vmctx v23, v55
+    v56 = stack_addr.i64 ss5+16
+    store notrap vmctx v23, v56
+    v57 = stack_addr.i64 ss5+32
+    store notrap vmctx v23, v57
+    v58 = stack_addr.i64 ss5+48
+    store notrap vmctx v23, v58
+    v59 = stack_addr.i64 ss5+64
+    store notrap vmctx v23, v59
+    v60 = stack_addr.i64 ss5+80
+    store notrap vmctx v23, v60
+    v61 = stack_addr.i64 ss5+96
+    store notrap vmctx v23, v61
+    v62 = stack_addr.i64 ss5+112
+    store notrap vmctx v22, v62  ; v22 = 0
+    v63 = stack_addr.i64 ss5+120
+    store notrap vmctx v21, v63  ; v21 = 0
+    v64 = stack_addr.i64 ss5+124
+    store notrap vmctx v20, v64  ; v20 = 0
+    v65 = icmp_imm uge v3, 0x5123  ; v3 = 0xffef
+    brif v65, block3, block2
+
+block3:
+    v66 = icmp_imm.i16 uge v3, 0xd5d7  ; v3 = 0xffef
+    brif v66, block5, block4
+
+block5:
+    v67 = icmp_imm.i16 uge v3, 0xf6ff  ; v3 = 0xffef
+    brif v67, block7, block6
+
+block7:
+    v68 = icmp_imm.i16 uge v3, 0xff22  ; v3 = 0xffef
+    brif v68, block9, block8
+
+block9:
+    v69 = icmp_imm.i16 eq v3, 0xffdd  ; v3 = 0xffef
+    brif v69, block1, block10
+
+block10:
+    v70 = icmp_imm.i16 uge v3, 0xff79  ; v3 = 0xffef
+    brif v70, block12, block11
+
+block12:
+    v71 = iadd_imm.i16 v3, 0xffff_ffff_ffff_0087  ; v3 = 0xffef
+    v72 = uextend.i32 v71
+    br_table v72, block1, [block1, block1, block1, block1, block1, block1]
+
+block11:
+    v73 = icmp_imm.i16 uge v3, 0xff22  ; v3 = 0xffef
+    brif v73, block13, block1
+
+block13:
+    v74 = iadd_imm.i16 v3, 0xffff_ffff_ffff_00de  ; v3 = 0xffef
+    v75 = uextend.i32 v74
+    br_table v75, block1, [block1, block1, block1, block1, block1, block1, block1, block1, block1, block1, block1, block1, block1, block1, block1, block1, block1, block1, block1, block1, block1]
+
+block8:
+    v76 = icmp_imm.i16 eq v3, 0xf951  ; v3 = 0xffef
+    brif v76, block1, block14
+
+block14:
+    v77 = icmp_imm.i16 uge v3, 0xf6ff  ; v3 = 0xffef
+    brif v77, block15, block1
+
+block15:
+    v78 = iadd_imm.i16 v3, 0xffff_ffff_ffff_0901  ; v3 = 0xffef
+    v79 = uextend.i32 v78
+    br_table v79, block1, [block1, block1, block1, block1, block1, block1, block1]
+
+block6:
+    v80 = icmp_imm.i16 uge v3, 0xef2a  ; v3 = 0xffef
+    brif v80, block17, block16
+
+block17:
+    v81 = icmp_imm.i16 eq v3, 0xf426  ; v3 = 0xffef
+    brif v81, block1, block18
+
+block18:
+    v82 = icmp_imm.i16 uge v3, 0xefff  ; v3 = 0xffef
+    brif v82, block20, block19
+
+block20:
+    v83 = iadd_imm.i16 v3, 0xffff_ffff_ffff_1001  ; v3 = 0xffef
+    v84 = uextend.i32 v83
+    br_table v84, block1, [block1, block1, block1, block1, block1, block1, block1, block1, block1, block1, block1, block1, block1, block1, block1, block1, block1, block1, block1, block1, block1, block1, block1, block1, block1, block1, block1, block1, block1, block1]
+
+block19:
+    v85 = icmp_imm.i16 uge v3, 0xef2a  ; v3 = 0xffef
+    brif v85, block21, block1
+
+block21:
+    v86 = iadd_imm.i16 v3, 0xffff_ffff_ffff_10d6  ; v3 = 0xffef
+    v87 = uextend.i32 v86
+    br_table v87, block1, [block1, block1, block1, block1, block1, block1, block1, block1, block1]
+
+block16:
+    v88 = icmp_imm.i16 eq v3, 0xdc2a  ; v3 = 0xffef
+    brif v88, block1, block22
+
+block22:
+    v89 = icmp_imm.i16 uge v3, 0xd5d7  ; v3 = 0xffef
+    brif v89, block23, block1
+
+block23:
+    v90 = iadd_imm.i16 v3, 0xffff_ffff_ffff_2a29  ; v3 = 0xffef
+    v91 = uextend.i32 v90
+    br_table v91, block1, [block1, block1, block1, block1, block1, block1, block1, block1, block1, block1, block1, block1, block1, block1, block1, block1, block1, block1, block1, block1, block1, block1, block1, block1, block1, block1, block1, block1, block1, block1, block1, block1]
+
+block4:
+    v92 = icmp_imm.i16 uge v3, 0x7363  ; v3 = 0xffef
+    brif v92, block25, block24
+
+block25:
+    v93 = icmp_imm.i16 uge v3, 0x9f22  ; v3 = 0xffef
+    brif v93, block27, block26
+
+block27:
+    v94 = icmp_imm.i16 uge v3, 0xbf41  ; v3 = 0xffef
+    brif v94, block29, block28
+
+block29:
+    v95 = iadd_imm.i16 v3, 0xffff_ffff_ffff_40bf  ; v3 = 0xffef
+    v96 = uextend.i32 v95
+    br_table v96, block1, [block1, block1, block1, block1, block1, block1, block1, block1, block1]
+
+block28:
+    v97 = icmp_imm.i16 eq v3, 0xae73  ; v3 = 0xffef
+    brif v97, block1, block30
+
+block30:
+    v98 = icmp_imm.i16 eq v3, 0x9f22  ; v3 = 0xffef
+    brif v98, block1, block1
+
+block26:
+    v99 = icmp_imm.i16 uge v3, 0x9301  ; v3 = 0xffef
+    brif v99, block32, block31
+
+block32:
+    v100 = iadd_imm.i16 v3, 0xffff_ffff_ffff_6cff  ; v3 = 0xffef
+    v101 = uextend.i32 v100
+    br_table v101, block1, [block1, block1, block1, block1, block1, block1, block1]
+
+block31:
+    v102 = icmp_imm.i16 uge v3, 0x7363  ; v3 = 0xffef
+    brif v102, block33, block1
+
+block33:
+    v103 = iadd_imm.i16 v3, 0xffff_ffff_ffff_8c9d  ; v3 = 0xffef
+    v104 = uextend.i32 v103
+    br_table v104, block1, [block1, block1, block1, block1, block1, block1, block1, block1, block1, block1, block1, block1, block1, block1, block1, block1, block1, block1, block1, block1, block1, block1, block1, block1, block1]
+
+block24:
+    v105 = icmp_imm.i16 uge v3, 0x56cc  ; v3 = 0xffef
+    brif v105, block35, block34
+
+block35:
+    v106 = icmp_imm.i16 eq v3, 0x6720  ; v3 = 0xffef
+    brif v106, block1, block36
+
+block36:
+    v107 = icmp_imm.i16 eq v3, 0x56cc  ; v3 = 0xffef
+    brif v107, block1, block1
+
+block34:
+    v108 = icmp_imm.i16 eq v3, 0x5230  ; v3 = 0xffef
+    brif v108, block1, block37
+
+block37:
+    v109 = icmp_imm.i16 uge v3, 0x5123  ; v3 = 0xffef
+    brif v109, block38, block1
+
+block38:
+    v110 = iadd_imm.i16 v3, 0xffff_ffff_ffff_aedd  ; v3 = 0xffef
+    v111 = uextend.i32 v110
+    br_table v111, block1, [block1, block1, block1, block1, block1, block1, block1]
+
+block2:
+    v112 = icmp_imm.i16 uge v3, 0x2a20  ; v3 = 0xffef
+    brif v112, block40, block39
+
+block40:
+    v113 = icmp_imm.i16 uge v3, 0x2f22  ; v3 = 0xffef
+    brif v113, block42, block41
+
+block42:
+    v114 = icmp_imm.i16 uge v3, 0x3320  ; v3 = 0xffef
+    brif v114, block44, block43
+
+block44:
+    v115 = icmp_imm.i16 uge v3, 0x504d  ; v3 = 0xffef
+    brif v115, block46, block45
+
+block46:
+    v116 = iadd_imm.i16 v3, 0xffff_ffff_ffff_afb3  ; v3 = 0xffef
+    v117 = uextend.i32 v116
+    br_table v117, block1, [block1, block1, block1, block1, block1, block1, block1, block1, block1, block1, block1, block1, block1]
+
+block45:
+    v118 = icmp_imm.i16 eq v3, 0x4118  ; v3 = 0xffef
+    brif v118, block1, block47
+
+block47:
+    v119 = icmp_imm.i16 eq v3, 0x3320  ; v3 = 0xffef
+    brif v119, block1, block1
+
+block43:
+    v120 = icmp_imm.i16 uge v3, 0x2f2a  ; v3 = 0xffef
+    brif v120, block49, block48
+
+block49:
+    v121 = iadd_imm.i16 v3, 0xffff_ffff_ffff_d0d6  ; v3 = 0xffef
+    v122 = uextend.i32 v121
+    br_table v122, block1, [block1, block1, block1, block1, block1, block1, block1, block1, block1, block1, block1, block1, block1, block1, block1, block1, block1, block1, block1, block1, block1, block1, block1, block1, block1, block1, block1, block1]
+
+block48:
+    v123 = icmp_imm.i16 eq v3, 0x2f22  ; v3 = 0xffef
+    brif v123, block1, block1
+
+block41:
+    v124 = icmp_imm.i16 uge v3, 0x2a67  ; v3 = 0xffef
+    brif v124, block51, block50
+
+block51:
+    v125 = icmp_imm.i16 uge v3, 0x2ade  ; v3 = 0xffef
+    brif v125, block53, block52
+
+block53:
+    v126 = iadd_imm.i16 v3, 0xffff_ffff_ffff_d522  ; v3 = 0xffef
+    v127 = uextend.i32 v126
+    br_table v127, block1, [block1, block1, block1, block1, block1, block1, block1, block1, block1, block1, block1, block1, block1, block1, block1, block1, block1, block1, block1, block1, block1, block1, block1, block1, block1, block1, block1, block1, block1, block1, block1, block1, block1, block1]
+
+block52:
+    v128 = icmp_imm.i16 eq v3, 0x2ab2  ; v3 = 0xffef
+    brif v128, block1, block54
+
+block54:
+    v129 = icmp_imm.i16 uge v3, 0x2a67  ; v3 = 0xffef
+    brif v129, block55, block1
+
+block55:
+    v130 = iadd_imm.i16 v3, 0xffff_ffff_ffff_d599  ; v3 = 0xffef
+    v131 = uextend.i32 v130
+    br_table v131, block1, [block1, block1, block1, block1, block1, block1]
+
+block50:
+    v132 = icmp_imm.i16 eq v3, 0x2a38  ; v3 = 0xffef
+    brif v132, block1, block56
+
+block56:
+    v133 = icmp_imm.i16 eq v3, 0x2a20  ; v3 = 0xffef
+    brif v133, block1, block1
+
+block39:
+    v134 = icmp_imm.i16 uge v3, 512  ; v3 = 0xffef
+    brif v134, block58, block57
+
+block58:
+    v135 = icmp_imm.i16 uge v3, 8241  ; v3 = 0xffef
+    brif v135, block60, block59
+
+block60:
+    v136 = icmp_imm.i16 eq v3, 9983  ; v3 = 0xffef
+    brif v136, block1, block61
+
+block61:
+    v137 = icmp_imm.i16 uge v3, 8738  ; v3 = 0xffef
+    brif v137, block63, block62
+
+block63:
+    v138 = iadd_imm.i16 v3, -8738  ; v3 = 0xffef
+    v139 = uextend.i32 v138
+    br_table v139, block1, [block1, block1, block1, block1, block1, block1, block1, block1, block1, block1, block1]
+
+block62:
+    v140 = icmp_imm.i16 uge v3, 8241  ; v3 = 0xffef
+    brif v140, block64, block1
+
+block64:
+    v141 = iadd_imm.i16 v3, -8241  ; v3 = 0xffef
+    v142 = uextend.i32 v141
+    br_table v142, block1, [block1, block1, block1, block1, block1, block1, block1, block1, block1, block1, block1, block1, block1, block1, block1, block1, block1, block1, block1, block1, block1, block1, block1, block1, block1, block1, block1]
+
+block59:
+    v143 = icmp_imm.i16 eq v3, 6493  ; v3 = 0xffef
+    brif v143, block1, block65
+
+block65:
+    v144 = icmp_imm.i16 uge v3, 512  ; v3 = 0xffef
+    brif v144, block66, block1
+
+block66:
+    v145 = iadd_imm.i16 v3, -512  ; v3 = 0xffef
+    v146 = uextend.i32 v145
+    br_table v146, block1, [block1, block1, block1]
+
+block57:
+    v147 = icmp_imm.i16 uge v3, 212  ; v3 = 0xffef
+    brif v147, block68, block67
+
+block68:
+    v148 = icmp_imm.i16 uge v3, 341  ; v3 = 0xffef
+    brif v148, block70, block69
+
+block70:
+    v149 = iadd_imm.i16 v3, -341  ; v3 = 0xffef
+    v150 = uextend.i32 v149
+    br_table v150, block1, [block1, block1]
+
+block69:
+    v151 = icmp_imm.i16 uge v3, 212  ; v3 = 0xffef
+    brif v151, block71, block1
+
+block71:
+    v152 = iadd_imm.i16 v3, -212  ; v3 = 0xffef
+    v153 = uextend.i32 v152
+    br_table v153, block1, [block1, block1, block1, block1, block1, block1, block1, block1, block1, block1, block1, block1, block1, block1, block1, block1, block1, block1, block1, block1, block1, block1, block1, block1, block1, block1, block1, block1, block1, block1]
+
+block67:
+    v154 = icmp_imm.i16 uge v3, 128  ; v3 = 0xffef
+    brif v154, block73, block72
+
+block73:
+    v155 = iadd_imm.i16 v3, -128  ; v3 = 0xffef
+    v156 = uextend.i32 v155
+    br_table v156, block1, [block1, block1]
+
+block72:
+    v157 = uextend.i32 v3  ; v3 = 0xffef
+    br_table v157, block1, [block1, block1]
+
+block1 cold:
+    v163 = func_addr.i64 fn6
+    return_call_indirect sig6, v163(v158, v158, v158, v158, v158, v158, v158, v159, v160, v160, v158, v158, v161, v159, v162)  ; v158 = 0xef31_de2a_2352_79ff, v158 = 0xef31_de2a_2352_79ff, v158 = 0xef31_de2a_2352_79ff, v158 = 0xef31_de2a_2352_79ff, v158 = 0xef31_de2a_2352_79ff, v158 = 0xef31_de2a_2352_79ff, v158 = 0xef31_de2a_2352_79ff, v159 = 203, v160 = 0xffef, v160 = 0xffef, v158 = 0xef31_de2a_2352_79ff, v158 = 0xef31_de2a_2352_79ff, v159 = 203, v162 = -0x1.979796p24
+}
diff --git a/cranelift/filetests/filetests/isa/riscv64/return-call.clif b/cranelift/filetests/filetests/isa/riscv64/return-call.clif
index e119025b9..5a575cb1a 100644
--- a/cranelift/filetests/filetests/isa/riscv64/return-call.clif
+++ b/cranelift/filetests/filetests/isa/riscv64/return-call.clif
@@ -693,8 +693,11 @@ block2:
 ;   addi s8, zero, 0x7d
 ;   addi s7, zero, 0x82
 ;   addi s6, zero, 0x87
-;   bnez a0, 0xb0
-; block2: ; offset 0xcc
+;   bnez a0, 8
+;   j 0xc
+;   auipc t6, 0
+;   jalr zero, t6, 0xb4
+; block2: ; offset 0xd8
 ;   addi a0, zero, 0x8c
 ;   sd a2, 0x90(sp)
 ;   sd a1, 0x98(sp)
@@ -738,7 +741,7 @@ block2:
 ;   ld s0, 0x80(sp)
 ;   addi sp, sp, 0x90
 ;   jr t0
-; block3: ; offset 0x178
+; block3: ; offset 0x184
 ;   ld a0, 0x10(sp)
 ;   sd a2, 0xa0(sp)
 ;   sd a1, 0xa8(sp)
diff --git a/cranelift/filetests/filetests/runtests/i128-bitcast.clif b/cranelift/filetests/filetests/runtests/i128-bitcast.clif
new file mode 100644
index 000000000..2b4cf930c
--- /dev/null
+++ b/cranelift/filetests/filetests/runtests/i128-bitcast.clif
@@ -0,0 +1,15 @@
+test interpret
+test run
+set enable_llvm_abi_extensions=true
+target aarch64
+target x86_64
+target s390x
+target riscv64
+target riscv64 has_c has_zcb
+
+function %bitcast_i128_i128(i128) -> i128 {
+block0(v0: i128):
+  v1 = bitcast.i128 v0
+  return v1
+}
+; run: %bitcast_i128_i128(0) == 0