Repository: bytecodealliance/wasmtime
Pull request #8177 (2024-03-18 23:27:00)

PCC: x64: 32- and 64-bit XMM loads/stores are 32 and 64 bits, respectively.
These are definitely not 128 bits wide; let's make the PCC model aware of that!

Fixes https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=67427.

cfallin: Stacked on top of #8176, #8174, #8173; only last commit is new.

Patch:
diff --git a/cranelift/codegen/src/context.rs b/cranelift/codegen/src/context.rs
index cc9719e5f..c5efafaee 100644
--- a/cranelift/codegen/src/context.rs
+++ b/cranelift/codegen/src/context.rs
@@ -365,6 +365,7 @@ impl Context {
             "About to optimize with egraph phase:\n{}",
             self.func.display()
         );
+        let fisa = fisa.into();
         self.compute_loop_analysis();
         let mut alias_analysis = AliasAnalysis::new(&self.func, &self.domtree);
         let mut pass = EgraphPass::new(
@@ -372,6 +373,7 @@ impl Context {
             &self.domtree,
             &self.loop_analysis,
             &mut alias_analysis,
+            &fisa.flags,
             ctrl_plane,
         );
         pass.run();
diff --git a/cranelift/codegen/src/egraph.rs b/cranelift/codegen/src/egraph.rs
index 8fa09e522..b1be475ac 100644
--- a/cranelift/codegen/src/egraph.rs
+++ b/cranelift/codegen/src/egraph.rs
@@ -7,12 +7,15 @@ use crate::dominator_tree::{DominatorTree, DominatorTreePreorder};
 use crate::egraph::elaborate::Elaborator;
 use crate::fx::FxHashSet;
 use crate::inst_predicates::{is_mergeable_for_egraph, is_pure_for_egraph};
+use crate::ir::pcc::Fact;
 use crate::ir::{
-    Block, DataFlowGraph, Function, Inst, InstructionData, Type, Value, ValueDef, ValueListPool,
+    Block, DataFlowGraph, Function, Inst, InstructionData, Opcode, Type, Value, ValueDef,
+    ValueListPool,
 };
 use crate::loop_analysis::LoopAnalysis;
 use crate::opts::IsleContext;
 use crate::scoped_hash_map::{Entry as ScopedEntry, ScopedHashMap};
+use crate::settings::Flags;
 use crate::trace;
 use crate::unionfind::UnionFind;
 use core::cmp::Ordering;
@@ -55,6 +58,8 @@ pub struct EgraphPass<'a> {
     /// Loop analysis results, used for built-in LICM during
     /// elaboration.
     loop_analysis: &'a LoopAnalysis,
+    /// Compiler flags.
+    flags: &'a Flags,
     /// Chaos-mode control-plane so we can test that we still get
     /// correct results when our heuristics make bad decisions.
     ctrl_plane: &'a mut ControlPlane,
@@ -91,6 +96,7 @@ where
     domtree: &'opt DominatorTreePreorder,
     pub(crate) alias_analysis: &'opt mut AliasAnalysis<'analysis>,
     pub(crate) alias_analysis_state: &'opt mut LastStores,
+    flags: &'opt Flags,
     ctrl_plane: &'opt mut ControlPlane,
     // Held locally during optimization of one node (recursively):
     pub(crate) rewrite_depth: usize,
@@ -203,6 +209,8 @@ where
                 }
             };
 
+            self.attach_constant_fact(inst, result);
+
             self.available_block[result] = self.get_available_block(inst);
             let opt_value = self.optimize_pure_enode(inst);
 
@@ -473,6 +481,22 @@ where
             false
         }
     }
+
+    /// Helper to propagate facts on constant values: if PCC is
+    /// enabled, then unconditionally add a fact attesting to the
+    /// Value's concrete value.
+    fn attach_constant_fact(&mut self, inst: Inst, value: Value) {
+        if self.flags.enable_pcc() {
+            if let InstructionData::UnaryImm {
+                opcode: Opcode::Iconst,
+                imm,
+            } = self.func.dfg.insts[inst]
+            {
+                let imm: i64 = imm.into();
+                self.func.dfg.facts[value] = Some(Fact::constant(64, imm as u64));
+            }
+        }
+    }
 }
 
 impl<'a> EgraphPass<'a> {
@@ -482,6 +506,7 @@ impl<'a> EgraphPass<'a> {
         raw_domtree: &'a DominatorTree,
         loop_analysis: &'a LoopAnalysis,
         alias_analysis: &'a mut AliasAnalysis<'a>,
+        flags: &'a Flags,
         ctrl_plane: &'a mut ControlPlane,
     ) -> Self {
         let num_values = func.dfg.num_values();
@@ -492,6 +517,7 @@ impl<'a> EgraphPass<'a> {
             domtree,
             loop_analysis,
             alias_analysis,
+            flags,
             ctrl_plane,
             stats: Stats::default(),
             eclasses: UnionFind::with_capacity(num_values),
@@ -662,6 +688,7 @@ impl<'a> EgraphPass<'a> {
                             domtree: &self.domtree,
                             alias_analysis: self.alias_analysis,
                             alias_analysis_state: &mut alias_analysis_state,
+                            flags: self.flags,
                             ctrl_plane: self.ctrl_plane,
                             optimized_values: Default::default(),
                         };
diff --git a/cranelift/codegen/src/isa/x64/pcc.rs b/cranelift/codegen/src/isa/x64/pcc.rs
index bc826c0d8..64a8acb7d 100644
--- a/cranelift/codegen/src/isa/x64/pcc.rs
+++ b/cranelift/codegen/src/isa/x64/pcc.rs
@@ -4,7 +4,7 @@ use crate::ir::pcc::*;
 use crate::ir::types::*;
 use crate::isa::x64::args::AvxOpcode;
 use crate::isa::x64::inst::args::{
-    AluRmiROpcode, Amode, Gpr, Imm8Reg, RegMem, RegMemImm, ShiftKind, SyntheticAmode,
+    AluRmiROpcode, Amode, Gpr, Imm8Reg, RegMem, RegMemImm, ShiftKind, SseOpcode, SyntheticAmode,
     ToWritableReg, CC,
 };
 use crate::isa::x64::inst::Inst;
@@ -259,8 +259,8 @@ pub(crate) fn check(
                 }
                 RegMem::Reg { .. } => {}
             }
-            undefined_result(ctx, vcode, dst_lo, 64, 64)?;
-            undefined_result(ctx, vcode, dst_hi, 64, 64)?;
+            undefined_result(ctx, vcode, dst_lo, 64, size.to_bits().into())?;
+            undefined_result(ctx, vcode, dst_hi, 64, size.to_bits().into())?;
             Ok(())
         }
         Inst::Mul8 { dst, ref src2, .. } => {
@@ -270,7 +270,7 @@ pub(crate) fn check(
                 }
                 RegMem::Reg { .. } => {}
             }
-            undefined_result(ctx, vcode, dst, 64, 64)?;
+            undefined_result(ctx, vcode, dst, 64, 16)?;
             Ok(())
         }
         Inst::IMul {
@@ -285,7 +285,7 @@ pub(crate) fn check(
                 }
                 RegMem::Reg { .. } => {}
             }
-            undefined_result(ctx, vcode, dst, 64, 64)?;
+            undefined_result(ctx, vcode, dst, 64, size.to_bits().into())?;
             Ok(())
         }
         Inst::IMulImm {
@@ -300,7 +300,7 @@ pub(crate) fn check(
                 }
                 RegMem::Reg { .. } => {}
             }
-            undefined_result(ctx, vcode, dst, 64, 64)?;
+            undefined_result(ctx, vcode, dst, 64, size.to_bits().into())?;
             Ok(())
         }
         Inst::CheckedSRemSeq {
@@ -545,6 +545,35 @@ pub(crate) fn check(
             ensure_no_fact(vcode, dst.to_writable_reg().to_reg())
         }
 
+        Inst::XmmUnaryRmRUnaligned {
+            dst,
+            ref src,
+            op: SseOpcode::Movss,
+            ..
+        } => {
+            match <&RegMem>::from(src) {
+                RegMem::Mem { ref addr } => {
+                    check_load(ctx, None, addr, vcode, F32, 32)?;
+                }
+                RegMem::Reg { .. } => {}
+            }
+            ensure_no_fact(vcode, dst.to_writable_reg().to_reg())
+        }
+        Inst::XmmUnaryRmRUnaligned {
+            dst,
+            ref src,
+            op: SseOpcode::Movsd,
+            ..
+        } => {
+            match <&RegMem>::from(src) {
+                RegMem::Mem { ref addr } => {
+                    check_load(ctx, None, addr, vcode, F64, 64)?;
+                }
+                RegMem::Reg { .. } => {}
+            }
+            ensure_no_fact(vcode, dst.to_writable_reg().to_reg())
+        }
+
         // NOTE: it's assumed that all of these cases perform 128-bit loads, but this hasn't been
         // verified. The effect of this will be spurious PCC failures when these instructions are
         // involved.
@@ -597,17 +626,17 @@ pub(crate) fn check(
             src: ref src2,
             ..
         } => {
-            let size = match op {
-                AvxOpcode::Vmovss => 32,
-                AvxOpcode::Vmovsd => 64,
+            let (ty, size) = match op {
+                AvxOpcode::Vmovss => (F32, 32),
+                AvxOpcode::Vmovsd => (F64, 64),
 
                 // We assume all other operations happen on 128-bit values.
-                _ => 128,
+                _ => (I8X16, 128),
             };
 
             match <&RegMem>::from(src2) {
                 RegMem::Mem { ref addr } => {
-                    check_load(ctx, None, addr, vcode, I8X16, size)?;
+                    check_load(ctx, None, addr, vcode, ty, size)?;
                 }
                 RegMem::Reg { .. } => {}
             }
@@ -652,6 +681,24 @@ pub(crate) fn check(
 
         Inst::XmmToGprVex { dst, .. } => undefined_result(ctx, vcode, dst, 64, 64),
 
+        Inst::XmmMovRM {
+            ref dst,
+            op: SseOpcode::Movss,
+            ..
+        } => {
+            check_store(ctx, None, dst, vcode, F32)?;
+            Ok(())
+        }
+
+        Inst::XmmMovRM {
+            ref dst,
+            op: SseOpcode::Movsd,
+            ..
+        } => {
+            check_store(ctx, None, dst, vcode, F64)?;
+            Ok(())
+        }
+
         Inst::XmmMovRM { ref dst, .. } | Inst::XmmMovRMImm { ref dst, .. } => {
             check_store(ctx, None, dst, vcode, I8X16)?;
             Ok(())
diff --git a/cranelift/wasm/src/environ/dummy.rs b/cranelift/wasm/src/environ/dummy.rs
index 78ee7faf4..eeecefc71 100644
--- a/cranelift/wasm/src/environ/dummy.rs
+++ b/cranelift/wasm/src/environ/dummy.rs
@@ -530,8 +530,8 @@ impl<'dummy_environment> FuncEnvironment for DummyFuncEnvironment<'dummy_environ
         let pointer_type = self.pointer_type();
         self.ensure_table_exists(builder.func, table_index);
         let table = self.tables[table_index].as_ref().unwrap();
-        let table_entry_addr = table.prepare_table_addr(builder, index, pointer_type, true);
-        let flags = ir::MemFlags::trusted().with_alias_region(Some(ir::AliasRegion::Table));
+        let (table_entry_addr, flags) =
+            table.prepare_table_addr(builder, index, pointer_type, true);
         let value = builder
             .ins()
             .load(self.reference_type(), flags, table_entry_addr, 0);
@@ -548,8 +548,8 @@ impl<'dummy_environment> FuncEnvironment for DummyFuncEnvironment<'dummy_environ
         let pointer_type = self.pointer_type();
         self.ensure_table_exists(builder.func, table_index);
         let table = self.tables[table_index].as_ref().unwrap();
-        let table_entry_addr = table.prepare_table_addr(builder, index, pointer_type, true);
-        let flags = ir::MemFlags::trusted().with_alias_region(Some(ir::AliasRegion::Table));
+        let (table_entry_addr, flags) =
+            table.prepare_table_addr(builder, index, pointer_type, true);
         builder.ins().store(flags, value, table_entry_addr, 0);
         Ok(())
     }
diff --git a/cranelift/wasm/src/table.rs b/cranelift/wasm/src/table.rs
index ed00221a9..bb5466670 100644
--- a/cranelift/wasm/src/table.rs
+++ b/cranelift/wasm/src/table.rs
@@ -50,7 +50,7 @@ impl TableData {
         mut index: ir::Value,
         addr_ty: ir::Type,
         enable_table_access_spectre_mitigation: bool,
-    ) -> ir::Value {
+    ) -> (ir::Value, ir::MemFlags) {
         let index_ty = pos.func.dfg.value_type(index);
 
         // Start with the bounds check. Trap if `index + 1 > bound`.
@@ -60,16 +60,10 @@ impl TableData {
         let oob = pos
             .ins()
             .icmp(IntCC::UnsignedGreaterThanOrEqual, index, bound);
-        pos.ins().trapnz(oob, ir::TrapCode::TableOutOfBounds);
 
-        // If Spectre mitigations are enabled, we will use a comparison to
-        // short-circuit the computed table element address to the start
-        // of the table on the misspeculation path when out-of-bounds.
-        let spectre_oob_cmp = if enable_table_access_spectre_mitigation {
-            Some((index, bound))
-        } else {
-            None
-        };
+        if !enable_table_access_spectre_mitigation {
+            pos.ins().trapnz(oob, ir::TrapCode::TableOutOfBounds);
+        }
 
         // Convert `index` to `addr_ty`.
         if index_ty != addr_ty {
@@ -91,14 +85,20 @@ impl TableData {
 
         let element_addr = pos.ins().iadd(base, offset);
 
-        if let Some((index, bound)) = spectre_oob_cmp {
-            let cond = pos
-                .ins()
-                .icmp(IntCC::UnsignedGreaterThanOrEqual, index, bound);
-            // If out-of-bounds, choose the table base on the misspeculation path.
-            pos.ins().select_spectre_guard(cond, base, element_addr)
+        let base_flags = ir::MemFlags::new()
+            .with_aligned()
+            .with_alias_region(Some(ir::AliasRegion::Table));
+        if enable_table_access_spectre_mitigation {
+            // Short-circuit the computed table element address to a null pointer
+            // when out-of-bounds. The consumer of this address will trap when
+            // trying to access it.
+            let zero = pos.ins().iconst(addr_ty, 0);
+            (
+                pos.ins().select_spectre_guard(oob, zero, element_addr),
+                base_flags.with_trap_code(Some(ir::TrapCode::TableOutOfBounds)),
+            )
         } else {
-            element_addr
+            (element_addr, base_flags.with_trap_code(None))
         }
     }
 }
diff --git a/crates/cranelift/src/func_environ.rs b/crates/cranelift/src/func_environ.rs
index d46b70cd6..6104a9411 100644
--- a/crates/cranelift/src/func_environ.rs
+++ b/crates/cranelift/src/func_environ.rs
@@ -955,13 +955,12 @@ impl<'module_environment> FuncEnvironment<'module_environment> {
         // contents, we check for a null entry here, and
         // if null, we take a slow-path that invokes a
         // libcall.
-        let table_entry_addr = table_data.prepare_table_addr(
+        let (table_entry_addr, flags) = table_data.prepare_table_addr(
             builder,
             index,
             pointer_type,
             self.isa.flags().enable_table_access_spectre_mitigation(),
         );
-        let flags = ir::MemFlags::trusted().with_alias_region(Some(ir::AliasRegion::Table));
         let value = builder.ins().load(pointer_type, flags, table_entry_addr, 0);
         // Mask off the "initialized bit". See documentation on
         // FUNCREF_INIT_BIT in crates/environ/src/ref_bits.rs for more
@@ -1548,13 +1547,12 @@ impl<'module_environment> cranelift_wasm::FuncEnvironment for FuncEnvironment<'m
                 // Load the table element.
                 self.ensure_table_exists(builder.func, table_index);
                 let table_data = self.tables[table_index].as_ref().unwrap();
-                let elem_addr = table_data.prepare_table_addr(
+                let (elem_addr, flags) = table_data.prepare_table_addr(
                     builder,
                     index,
                     pointer_type,
                     self.isa.flags().enable_table_access_spectre_mitigation(),
                 );
-                let flags = ir::MemFlags::trusted().with_alias_region(Some(ir::AliasRegion::Table));
                 let elem = builder.ins().load(reference_type, flags, elem_addr, 0);
 
                 let elem_is_null = builder.ins().is_null(elem);
@@ -1659,7 +1657,7 @@ impl<'module_environment> cranelift_wasm::FuncEnvironment for FuncEnvironment<'m
             WasmHeapType::Func | WasmHeapType::Concrete(_) | WasmHeapType::NoFunc => {
                 match plan.style {
                     TableStyle::CallerChecksSignature => {
-                        let table_entry_addr = table_data.prepare_table_addr(
+                        let (table_entry_addr, flags) = table_data.prepare_table_addr(
                             builder,
                             index,
                             pointer_type,
@@ -1671,8 +1669,6 @@ impl<'module_environment> cranelift_wasm::FuncEnvironment for FuncEnvironment<'m
                         let value_with_init_bit = builder
                             .ins()
                             .bor_imm(value, Imm64::from(FUNCREF_INIT_BIT as i64));
-                        let flags =
-                            ir::MemFlags::trusted().with_alias_region(Some(ir::AliasRegion::Table));
                         builder
                             .ins()
                             .store(flags, value_with_init_bit, table_entry_addr, 0);
@@ -1736,14 +1732,16 @@ impl<'module_environment> cranelift_wasm::FuncEnvironment for FuncEnvironment<'m
                 // not recorded in the stack map (which would lead to the GC
                 // saving a reference to a deallocated object, and then using it
                 // after its been freed).
-                let table_entry_addr = table_data.prepare_table_addr(
+                let (table_entry_addr, flags) = table_data.prepare_table_addr(
                     builder,
                     index,
                     pointer_type,
                     self.isa.flags().enable_table_access_spectre_mitigation(),
                 );
-                let flags = ir::MemFlags::trusted().with_alias_region(Some(ir::AliasRegion::Table));
                 let current_elem = builder.ins().load(pointer_type, flags, table_entry_addr, 0);
+
+                // After the load, a store to the same address can't trap.
+                let flags = ir::MemFlags::trusted().with_alias_region(Some(ir::AliasRegion::Table));
                 builder.ins().store(flags, value, table_entry_addr, 0);
 
                 // If value is not null, increment `value`'s ref count.


Test patch:
diff --git a/cranelift/filetests/filetests/pcc/succeed/fuzz-float-loads.clif b/cranelift/filetests/filetests/pcc/succeed/fuzz-float-loads.clif
new file mode 100644
index 000000000..af5aa34c8
--- /dev/null
+++ b/cranelift/filetests/filetests/pcc/succeed/fuzz-float-loads.clif
@@ -0,0 +1,86 @@
+test compile
+set enable_pcc=true
+set opt_level=speed
+target x86_64
+
+function u0:0(i64 vmctx, i64) fast {
+    gv0 = vmctx
+    gv1 = load.i64 notrap aligned readonly gv0+8
+    gv2 = load.i64 notrap aligned gv1
+    gv3 ! mem(mt0, 0x0, 0x0) = vmctx
+    gv4 ! mem(mt1, 0x0, 0x0) = load.i64 notrap aligned readonly checked gv3+80
+    mt0 = struct 88 { 80: i64 readonly ! mem(mt1, 0x0, 0x0) }
+    mt1 = memory 0x180000000
+    sig0 = (i64 vmctx) system_v
+    sig1 = (i64 vmctx, i32 uext) system_v
+    sig2 = (i64 vmctx, i32 uext, i32 uext, i32 uext) -> i32 uext system_v
+    const0 = 0x02030077ff00ff04030077ff6cff5503
+    stack_limit = gv2
+
+block0(v0: i64, v1: i64):
+    v2 = iconst.i32 0
+    v25 -> v2
+    v45 -> v2
+    v24 -> v25
+    v3 = null.r64
+    v4 = global_value.i64 gv3
+    v5 = load.i64 notrap aligned v4+8
+    v17 -> v5
+    v44 -> v5
+    v42 -> v17
+    v6 = load.i64 notrap aligned v5+8
+    v7 = iadd_imm v6, 1
+    v8 = iconst.i64 0
+    v9 = icmp sge v7, v8  ; v8 = 0
+    brif v9, block2, block3(v7)
+
+block2:
+    store.i64 notrap aligned v7, v5+8
+    v10 = global_value.i64 gv3
+    v11 = load.i64 notrap aligned readonly v10+56
+    v12 = load.i64 notrap aligned readonly v11+120
+    call_indirect sig0, v12(v10)
+    v13 = load.i64 notrap aligned v5+8
+    jump block3(v13)
+
+block3(v43: i64):
+    v15 -> v43
+    jump block4
+
+block4:
+    v14 = iconst.i64 0
+    v16 = icmp.i64 sge v15, v14  ; v14 = 0
+    brif v16, block6, block7(v15)
+
+block6:
+    store.i64 notrap aligned v15, v17+8
+    v18 = global_value.i64 gv3
+    v19 = load.i64 notrap aligned readonly v18+56
+    v20 = load.i64 notrap aligned readonly v19+120
+    call_indirect sig0, v20(v18)
+    v21 = load.i64 notrap aligned v17+8
+    jump block7(v21)
+
+block7(v40: i64):
+    v22 = vconst.i8x16 const0
+    v23 = uwiden_high v22  ; v22 = const0
+    v26 = bitcast.i8x16 little v23
+    v27 = sshr v26, v25  ; v25 = 0
+    v28 = bitcast.i64x2 little v27
+    v29 = extractlane v28, 1
+    v30 = iconst.i32 1
+    v31 = global_value.i64 gv3
+    v32 = load.i64 notrap aligned readonly v31+56
+    v33 = load.i64 notrap aligned readonly v32+24
+    call_indirect sig1, v33(v31, v30)  ; v30 = 1
+    v34 = ireduce.i32 v29
+    v35 ! range(64, 0x0, 0xffffffff) = uextend.i64 v34
+    v36 ! mem(mt1, 0x0, 0x0) = global_value.i64 gv4
+    v37 ! mem(mt1, 0x0, 0xffffffff) = iadd v36, v35
+    v38 = load.f64 little checked heap v37
+    v39 = f64const 0x0.0000000005b28p-1022
+    v41 = iadd_imm v40, 9
+    store notrap aligned v41, v17+8
+    trap unreachable
+}
+
diff --git a/cranelift/filetests/filetests/pcc/succeed/imul-fuzzbug.clif b/cranelift/filetests/filetests/pcc/succeed/imul-fuzzbug.clif
new file mode 100644
index 000000000..8ce327402
--- /dev/null
+++ b/cranelift/filetests/filetests/pcc/succeed/imul-fuzzbug.clif
@@ -0,0 +1,282 @@
+test compile
+set enable_pcc=true
+set opt_level=speed
+target x86_64
+
+function u0:3(i64 vmctx, i64) fast {
+        gv0 = vmctx
+        gv1 = load.i64 notrap aligned readonly gv0+8
+        gv2 = load.i64 notrap aligned gv1
+        gv3 ! mem(mt0, 0x0, 0x0) = vmctx
+        mt0 = struct 0 { }
+        sig0 = (i64 vmctx, i32 uext) system_v
+        sig1 = (i64 vmctx, i32 uext, i32 uext) -> i32 uext system_v
+        sig2 = (i64 vmctx, i32 uext) -> i32 uext system_v
+        stack_limit = gv2
+    
+block0(v0 ! mem(mt0, 0x0, 0x0): i64, v1: i64):
+    v13 -> v0
+    v17 -> v0
+    v21 -> v0
+    v22 -> v0
+    v43 -> v0
+    v51 -> v0
+    v155 -> v0
+    v160 -> v0
+    v163 -> v0
+    v164 -> v0
+    v167 -> v0
+    v168 -> v0
+    v171 -> v0
+    v173 -> v0
+    v176 -> v0
+    v177 -> v0
+    v180 -> v0
+    v182 -> v0
+    v185 -> v0
+    v2 = f64const 0.0
+    v3 = iconst.i64 0
+    v4 = iconst.i64 0
+    v5 = iconst.i64 0
+    v6 = iconst.i64 0
+    v7 = iconst.i64 0
+    v8 = iconst.i64 0
+    v9 = iconst.i64 0
+    v10 = iconst.i64 0
+    v11 = iconst.i64 0
+    v12 = iconst.i64 0
+    v14 = load.i32 notrap aligned table v13+192
+    v186 = iconst.i32 0
+    v15 = icmp eq v14, v186  ; v186 = 0
+    v16 = uextend.i32 v15
+    brif v16, block2, block3
+
+block2:
+    trap unreachable
+
+block3:
+    v18 = load.i32 notrap aligned table v17+192
+    v19 = iconst.i32 1
+    v20 = isub v18, v19  ; v19 = 1
+    store notrap aligned table v20, v21+192
+    v23 = load.i32 notrap aligned table v22+128
+    v24 = f64const -0x1.3090455030609p194
+    v25 = fneg v24  ; v24 = -0x1.3090455030609p194
+    v26 = fneg v25
+    v27 = fneg v26
+    v28 = fneg v27
+    v29 = fneg v28
+    v30 = fneg v29
+    v31 = fneg v30
+    v32 = fneg v31
+    v33 = fneg v32
+    v34 = fneg v33
+    v35 = fneg v34
+    v36 = fneg v35
+    v37 = floor v36
+    v38 = f64const +NaN
+    v39 = fcmp eq v37, v37
+    v40 = uextend.i32 v39
+    v41 = select v40, v37, v38  ; v38 = +NaN
+    v42 = iconst.i32 0x1309_0455
+    v44 = load.i32 notrap aligned table v43+128
+    v45 = rotl v42, v44  ; v42 = 0x1309_0455
+    v46 = fcvt_from_sint.f32 v45
+    v47 = iconst.i64 0x2001_8113_0904_5503
+    v48 = iconst.i64 0x2001_8113_0904_5503
+    v187 = iconst.i64 0
+    v49 = icmp eq v48, v187  ; v48 = 0x2001_8113_0904_5503, v187 = 0
+    v50 = uextend.i32 v49
+    store notrap aligned table v50, v51+128
+    v52 = iconst.i32 0x2001_8113
+    v53 = iconst.i32 0x0904_5503
+    v54 = rotl v52, v53  ; v52 = 0x2001_8113, v53 = 0x0904_5503
+    v55 = fcvt_from_sint.f32 v54
+    v56 = iconst.i64 -1
+    v70 -> v56
+    v71 -> v56
+    v57 = iconst.i32 0xffff_ffff
+    v58 = uextend.i64 v57  ; v57 = 0xffff_ffff
+    v59 = iconst.i64 1
+    v188 = iconst.i64 0
+    v60 = icmp eq v58, v188  ; v188 = 0
+    v61 = uextend.i32 v60
+    v62 = select v61, v59, v58  ; v59 = 1
+    v73 -> v62
+    v63 = iconst.i64 0x8000_0000_0000_0000
+    v64 = icmp ne v56, v63  ; v56 = -1, v63 = 0x8000_0000_0000_0000
+    v65 = uextend.i32 v64
+    brif v65, block5, block6
+
+block6:
+    v66 = iconst.i64 -1
+    v67 = icmp.i64 ne v62, v66  ; v66 = -1
+    v68 = uextend.i32 v67
+    brif v68, block5, block7
+
+block7:
+    v69 = iconst.i64 1
+    jump block4(v69)  ; v69 = 1
+
+block5:
+    jump block4(v62)
+
+block4(v72: i64):
+    v74 = srem.i64 v56, v72  ; v56 = -1
+    v88 -> v74
+    v89 -> v74
+    v75 = iconst.i32 0xffff_ffff
+    v76 = uextend.i64 v75  ; v75 = 0xffff_ffff
+    v77 = iconst.i64 1
+    v189 = iconst.i64 0
+    v78 = icmp eq v76, v189  ; v189 = 0
+    v79 = uextend.i32 v78
+    v80 = select v79, v77, v76  ; v77 = 1
+    v91 -> v80
+    v81 = iconst.i64 0x8000_0000_0000_0000
+    v82 = icmp ne v74, v81  ; v81 = 0x8000_0000_0000_0000
+    v83 = uextend.i32 v82
+    brif v83, block9, block10
+
+block10:
+    v84 = iconst.i64 -1
+    v85 = icmp.i64 ne v80, v84  ; v84 = -1
+    v86 = uextend.i32 v85
+    brif v86, block9, block11
+
+block11:
+    v87 = iconst.i64 1
+    jump block8(v87)  ; v87 = 1
+
+block9:
+    jump block8(v80)
+
+block8(v90: i64):
+    v92 = srem.i64 v74, v90
+    v106 -> v92
+    v107 -> v92
+    v93 = iconst.i32 0xffff_ffff
+    v94 = uextend.i64 v93  ; v93 = 0xffff_ffff
+    v95 = iconst.i64 1
+    v190 = iconst.i64 0
+    v96 = icmp eq v94, v190  ; v190 = 0
+    v97 = uextend.i32 v96
+    v98 = select v97, v95, v94  ; v95 = 1
+    v109 -> v98
+    v99 = iconst.i64 0x8000_0000_0000_0000
+    v100 = icmp ne v92, v99  ; v99 = 0x8000_0000_0000_0000
+    v101 = uextend.i32 v100
+    brif v101, block13, block14
+
+block14:
+    v102 = iconst.i64 -1
+    v103 = icmp.i64 ne v98, v102  ; v102 = -1
+    v104 = uextend.i32 v103
+    brif v104, block13, block15
+
+block15:
+    v105 = iconst.i64 1
+    jump block12(v105)  ; v105 = 1
+
+block13:
+    jump block12(v98)
+
+block12(v108: i64):
+    v110 = srem.i64 v92, v108
+    v124 -> v110
+    v125 -> v110
+    v111 = iconst.i32 0xffff_ffff
+    v112 = uextend.i64 v111  ; v111 = 0xffff_ffff
+    v113 = iconst.i64 1
+    v191 = iconst.i64 0
+    v114 = icmp eq v112, v191  ; v191 = 0
+    v115 = uextend.i32 v114
+    v116 = select v115, v113, v112  ; v113 = 1
+    v127 -> v116
+    v117 = iconst.i64 0x8000_0000_0000_0000
+    v118 = icmp ne v110, v117  ; v117 = 0x8000_0000_0000_0000
+    v119 = uextend.i32 v118
+    brif v119, block17, block18
+
+block18:
+    v120 = iconst.i64 -1
+    v121 = icmp.i64 ne v116, v120  ; v120 = -1
+    v122 = uextend.i32 v121
+    brif v122, block17, block19
+
+block19:
+    v123 = iconst.i64 1
+    jump block16(v123)  ; v123 = 1
+
+block17:
+    jump block16(v116)
+
+block16(v126: i64):
+    v128 = srem.i64 v110, v126
+    v145 -> v128
+    v146 -> v128
+    v129 = iconst.i32 0x0944_0909
+    v130 = popcnt v129  ; v129 = 0x0944_0909
+    v131 = iconst.i32 0x3482_3582
+    v132 = imul v130, v131  ; v131 = 0x3482_3582
+    v133 = uextend.i64 v132
+    v134 = iconst.i64 1
+    v192 = iconst.i64 0
+    v135 = icmp eq v133, v192  ; v192 = 0
+    v136 = uextend.i32 v135
+    v137 = select v136, v134, v133  ; v134 = 1
+    v148 -> v137
+    v138 = iconst.i64 0x8000_0000_0000_0000
+    v139 = icmp ne v128, v138  ; v138 = 0x8000_0000_0000_0000
+    v140 = uextend.i32 v139
+    brif v140, block21, block22
+
+block22:
+    v141 = iconst.i64 -1
+    v142 = icmp.i64 ne v137, v141  ; v141 = -1
+    v143 = uextend.i32 v142
+    brif v143, block21, block23
+
+block23:
+    v144 = iconst.i64 1
+    jump block20(v144)  ; v144 = 1
+
+block21:
+    jump block20(v137)
+
+block20(v147: i64):
+    v149 = srem.i64 v128, v147
+    v150 = iconst.i32 0xb7b7_746e
+    v151 = fcvt_from_uint.f32 v150  ; v150 = 0xb7b7_746e
+    v152 = fcvt_to_sint_sat.i64 v151
+    v153 = icmp eq v149, v152
+    v154 = uextend.i32 v153
+    v156 = load.i32 notrap aligned table v155+128
+    v157 = ctz v156
+    v158 = f32const 0x1.bc0402p-124
+    v159 = bitcast.i32 v158  ; v158 = 0x1.bc0402p-124
+    v161 = load.i32 notrap aligned table v160+144
+    v162 = bxor v159, v161
+    store notrap aligned table v162, v163+144
+    v165 = load.i32 notrap aligned table v164+160
+    v166 = bxor v157, v165
+    store notrap aligned table v166, v167+160
+    v169 = load.i32 notrap aligned table v168+160
+    v170 = bxor v154, v169
+    store notrap aligned table v170, v171+160
+    v172 = bitcast.i32 v55
+    v174 = load.i32 notrap aligned table v173+144
+    v175 = bxor v172, v174
+    store notrap aligned table v175, v176+144
+    v178 = load.i64 notrap aligned table v177+176
+    v179 = bxor.i64 v47, v178  ; v47 = 0x2001_8113_0904_5503
+    store notrap aligned table v179, v180+176
+    v181 = bitcast.i32 v46
+    v183 = load.i32 notrap aligned table v182+144
+    v184 = bxor v181, v183
+    store notrap aligned table v184, v185+144
+    jump block1
+
+block1:
+    return
+}
diff --git a/cranelift/filetests/filetests/pcc/succeed/uextend-add-iconst.clif b/cranelift/filetests/filetests/pcc/succeed/uextend-add-iconst.clif
new file mode 100644
index 000000000..9448298c8
--- /dev/null
+++ b/cranelift/filetests/filetests/pcc/succeed/uextend-add-iconst.clif
@@ -0,0 +1,119 @@
+test compile
+set enable_pcc=true
+set opt_level=speed
+target x86_64
+
+;; v110 is a uextend'd iconst; v111 is a memtype base; v112 is that
+;; base plus that fixed offset, and should be able to verify that its
+;; offset is in 0..4GiB. In the fuzzbug that inspired this test, we
+;; had a bare `iconst` with no range fact on it after optimization.
+
+function u0:2(i64 vmctx, i64, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32) -> i32, i32, i32, i32, i32, i32 fast {
+    gv0 = vmctx
+    gv1 = load.i64 notrap aligned readonly gv0+8
+    gv2 = load.i64 notrap aligned gv1
+    gv3 ! mem(mt0, 0x0, 0x0) = vmctx
+    gv4 ! mem(mt1, 0x0, 0x0) = load.i64 notrap aligned readonly checked gv3+96
+    mt0 = struct 104 { 96: i64 readonly ! mem(mt1, 0x0, 0x0) }
+    mt1 = memory 0x180000000
+    sig0 = (i64 vmctx, i32 uext) system_v
+    sig1 = (i64 vmctx, i32 uext, i32 uext, i32 uext) -> i32 uext system_v
+    sig2 = (i64 vmctx, i32 uext, i32 uext) -> i32 uext system_v
+    sig3 = (i64 vmctx, i32 uext) -> i32 uext system_v
+    stack_limit = gv2
+
+block0(v0 ! mem(mt0, 0x0, 0x0): i64, v1: i64, v2: i32, v3: i32, v4: i32, v5: i32, v6: i32, v7: i32, v8: i32, v9: i32, v10: i32, v11: i32, v12: i32, v13: i32, v14: i32, v15: i32, v16: i32, v17: i32, v18: i32, v19: i32, v20: i32, v21: i32):
+    v77 -> v0
+    v81 -> v0
+    v85 -> v0
+    v87 -> v0
+    v91 -> v0
+    v95 -> v0
+    v97 -> v0
+    v130 -> v0
+    v78 = load.i32 notrap aligned table v77+176
+    v127 = iconst.i32 0
+    v79 = icmp eq v78, v127  ; v127 = 0
+    v80 = uextend.i32 v79
+    brif v80, block2, block3
+
+block2:
+    trap unreachable
+
+block3:
+    v82 = load.i32 notrap aligned table v81+176
+    v83 = iconst.i32 1
+    v84 = isub v82, v83  ; v83 = 1
+    store notrap aligned table v84, v85+176
+    jump block4
+
+block4:
+    v88 = load.i32 notrap aligned table v87+176
+    v128 = iconst.i32 0
+    v89 = icmp eq v88, v128  ; v128 = 0
+    v90 = uextend.i32 v89
+    brif v90, block6, block7
+
+block6:
+    trap unreachable
+
+block7:
+    v92 = load.i32 notrap aligned table v91+176
+    v93 = iconst.i32 1
+    v94 = isub v92, v93  ; v93 = 1
+    store notrap aligned table v94, v95+176
+    v96 = iconst.i32 0xffff_3234
+    v98 = load.i64 notrap aligned v97+104
+    v129 = iconst.i64 0x0001_0000
+    v99 = udiv v98, v129  ; v129 = 0x0001_0000
+    v100 = ireduce.i32 v99
+    v101 = iconst.i32 0x0001_0000
+    v102 = imul v100, v101  ; v101 = 0x0001_0000
+    v103 = iconst.i32 0x0005_ffee
+    v104 = iadd v103, v96  ; v103 = 0x0005_ffee, v96 = 0xffff_3234
+    v105 = icmp ule v102, v104
+    v106 = uextend.i32 v105
+    brif v106, block9, block10
+
+block10:
+    v107 = iconst.i32 0
+    v108 = icmp.i32 sle v96, v107  ; v96 = 0xffff_3234, v107 = 0
+    v109 = uextend.i32 v108
+    brif v109, block9, block11
+
+block11:
+    v110 ! range(64, 0x0, 0xffffffff) = uextend.i64 v96  ; v96 = 0xffff_3234
+    v111 ! mem(mt1, 0x0, 0x0) = load.i64 notrap aligned readonly checked v130+96
+    v112 ! mem(mt1, 0x0, 0xffffffff) = iadd v111, v110
+    v113 ! range(64, 0x5ffe6, 0x5ffe6) = iconst.i64 0x0005_ffe6
+    v114 ! mem(mt1, 0x5ffe6, 0x10005ffe5) = iadd v112, v113  ; v113 = 0x0005_ffe6
+    v115 = uload8.i64 little checked heap v114
+    jump block8(v115)
+
+block9:
+    v116 = iconst.i64 0
+    jump block8(v116)  ; v116 = 0
+
+block8(v117: i64):
+    v118 = fcvt_from_uint.f32 v117
+    v86 -> v118
+    jump block5
+
+block5:
+    v121 = iconst.i32 0
+    v22 -> v121
+    v122 = iconst.i32 0
+    v23 -> v122
+    v123 = iconst.i32 0
+    v24 -> v123
+    v124 = iconst.i32 0
+    v25 -> v124
+    v125 = iconst.i32 0
+    v26 -> v125
+    v126 = iconst.i32 0
+    v27 -> v126
+    jump block1
+
+block1:
+    return v22, v23, v24, v25, v26, v27  ; v22 = 0, v23 = 0, v24 = 0, v25 = 0, v26 = 0, v27 = 0
+}
diff --git a/tests/disas/icall-simd.wat b/tests/disas/icall-simd.wat
index e6f33895d..12253e10c 100644
--- a/tests/disas/icall-simd.wat
+++ b/tests/disas/icall-simd.wat
@@ -23,14 +23,13 @@
 ;;                                 block0(v0: i64, v1: i64, v2: i32, v3: i8x16):
 ;; @0033                               v5 = iconst.i32 23
 ;; @0033                               v6 = icmp uge v2, v5  ; v5 = 23
-;; @0033                               trapnz v6, table_oob
 ;; @0033                               v7 = uextend.i64 v2
 ;; @0033                               v8 = global_value.i64 gv4
 ;; @0033                               v9 = ishl_imm v7, 3
 ;; @0033                               v10 = iadd v8, v9
-;; @0033                               v11 = icmp uge v2, v5  ; v5 = 23
-;; @0033                               v12 = select_spectre_guard v11, v8, v10
-;; @0033                               v13 = load.i64 notrap aligned table v12
+;; @0033                               v11 = iconst.i64 0
+;; @0033                               v12 = select_spectre_guard v6, v11, v10  ; v11 = 0
+;; @0033                               v13 = load.i64 table_oob aligned table v12
 ;; @0033                               v14 = band_imm v13, -2
 ;; @0033                               brif v13, block3(v14), block2
 ;;
diff --git a/tests/disas/icall.wat b/tests/disas/icall.wat
index ec6f668c1..e810b78ee 100644
--- a/tests/disas/icall.wat
+++ b/tests/disas/icall.wat
@@ -23,14 +23,13 @@
 ;;                                 block0(v0: i64, v1: i64, v2: i32, v3: f32):
 ;; @0033                               v5 = iconst.i32 23
 ;; @0033                               v6 = icmp uge v2, v5  ; v5 = 23
-;; @0033                               trapnz v6, table_oob
 ;; @0033                               v7 = uextend.i64 v2
 ;; @0033                               v8 = global_value.i64 gv4
 ;; @0033                               v9 = ishl_imm v7, 3
 ;; @0033                               v10 = iadd v8, v9
-;; @0033                               v11 = icmp uge v2, v5  ; v5 = 23
-;; @0033                               v12 = select_spectre_guard v11, v8, v10
-;; @0033                               v13 = load.i64 notrap aligned table v12
+;; @0033                               v11 = iconst.i64 0
+;; @0033                               v12 = select_spectre_guard v6, v11, v10  ; v11 = 0
+;; @0033                               v13 = load.i64 table_oob aligned table v12
 ;; @0033                               v14 = band_imm v13, -2
 ;; @0033                               brif v13, block3(v14), block2
 ;;
diff --git a/tests/disas/pcc-loads-x64-avx.wat b/tests/disas/pcc-loads-x64-avx.wat
new file mode 100644
index 000000000..45f9ec872
--- /dev/null
+++ b/tests/disas/pcc-loads-x64-avx.wat
@@ -0,0 +1,95 @@
+;;! target = "x86_64"
+;;! test = "compile"
+;;! flags = [ "-Oopt-level=2", "-Cpcc=y", "-Ccranelift-has-avx=true" ]
+
+(module
+  (memory 1 1)
+  (func (export "load_f32") (param i32) (result f32)
+    local.get 0
+    f32.load)
+  (func (export "load_f64") (param i32) (result f64)
+    local.get 0
+    f64.load)
+  (func (export "store_f32") (param i32 f32)
+    local.get 0
+    local.get 1
+    f32.store)
+  (func (export "store_f64") (param i32 f64)
+    local.get 0
+    local.get 1
+    f64.store))
+;; function u0:0:
+;;   pushq   %rbp
+;;   unwind PushFrameRegs { offset_upward_to_caller_sp: 16 }
+;;   movq    %rsp, %rbp
+;;   movq    8(%rdi), %r10
+;;   movq    0(%r10), %r10
+;;   cmpq    %rsp, %r10
+;;   jnbe #trap=stk_ovf
+;;   unwind DefineNewFrame { offset_upward_to_caller_sp: 16, offset_downward_to_clobbers: 0 }
+;; block0:
+;;   movq    80(%rdi), %r9
+;;   movl    %edx, %r10d
+;;   vmovss  0(%r9,%r10,1), %xmm0
+;;   jmp     label1
+;; block1:
+;;   movq    %rbp, %rsp
+;;   popq    %rbp
+;;   ret
+;;
+;; function u0:1:
+;;   pushq   %rbp
+;;   unwind PushFrameRegs { offset_upward_to_caller_sp: 16 }
+;;   movq    %rsp, %rbp
+;;   movq    8(%rdi), %r10
+;;   movq    0(%r10), %r10
+;;   cmpq    %rsp, %r10
+;;   jnbe #trap=stk_ovf
+;;   unwind DefineNewFrame { offset_upward_to_caller_sp: 16, offset_downward_to_clobbers: 0 }
+;; block0:
+;;   movq    80(%rdi), %r9
+;;   movl    %edx, %r10d
+;;   vmovsd  0(%r9,%r10,1), %xmm0
+;;   jmp     label1
+;; block1:
+;;   movq    %rbp, %rsp
+;;   popq    %rbp
+;;   ret
+;;
+;; function u0:2:
+;;   pushq   %rbp
+;;   unwind PushFrameRegs { offset_upward_to_caller_sp: 16 }
+;;   movq    %rsp, %rbp
+;;   movq    8(%rdi), %r10
+;;   movq    0(%r10), %r10
+;;   cmpq    %rsp, %r10
+;;   jnbe #trap=stk_ovf
+;;   unwind DefineNewFrame { offset_upward_to_caller_sp: 16, offset_downward_to_clobbers: 0 }
+;; block0:
+;;   movq    80(%rdi), %r9
+;;   movl    %edx, %r10d
+;;   vmovss  %xmm0, 0(%r9,%r10,1)
+;;   jmp     label1
+;; block1:
+;;   movq    %rbp, %rsp
+;;   popq    %rbp
+;;   ret
+;;
+;; function u0:3:
+;;   pushq   %rbp
+;;   unwind PushFrameRegs { offset_upward_to_caller_sp: 16 }
+;;   movq    %rsp, %rbp
+;;   movq    8(%rdi), %r10
+;;   movq    0(%r10), %r10
+;;   cmpq    %rsp, %r10
+;;   jnbe #trap=stk_ovf
+;;   unwind DefineNewFrame { offset_upward_to_caller_sp: 16, offset_downward_to_clobbers: 0 }
+;; block0:
+;;   movq    80(%rdi), %r9
+;;   movl    %edx, %r10d
+;;   vmovsd  %xmm0, 0(%r9,%r10,1)
+;;   jmp     label1
+;; block1:
+;;   movq    %rbp, %rsp
+;;   popq    %rbp
+;;   ret
diff --git a/tests/disas/pcc-loads-x64.wat b/tests/disas/pcc-loads-x64.wat
new file mode 100644
index 000000000..b31030eef
--- /dev/null
+++ b/tests/disas/pcc-loads-x64.wat
@@ -0,0 +1,95 @@
+;;! target = "x86_64"
+;;! test = "compile"
+;;! flags = [ "-Oopt-level=2", "-Cpcc=y", "-Ccranelift-has-avx=false" ]
+
+(module
+  (memory 1 1)
+  (func (export "load_f32") (param i32) (result f32)
+    local.get 0
+    f32.load)
+  (func (export "load_f64") (param i32) (result f64)
+    local.get 0
+    f64.load)
+  (func (export "store_f32") (param i32 f32)
+    local.get 0
+    local.get 1
+    f32.store)
+  (func (export "store_f64") (param i32 f64)
+    local.get 0
+    local.get 1
+    f64.store))
+;; function u0:0:
+;;   pushq   %rbp
+;;   unwind PushFrameRegs { offset_upward_to_caller_sp: 16 }
+;;   movq    %rsp, %rbp
+;;   movq    8(%rdi), %r10
+;;   movq    0(%r10), %r10
+;;   cmpq    %rsp, %r10
+;;   jnbe #trap=stk_ovf
+;;   unwind DefineNewFrame { offset_upward_to_caller_sp: 16, offset_downward_to_clobbers: 0 }
+;; block0:
+;;   movq    80(%rdi), %r9
+;;   movl    %edx, %r10d
+;;   movss   0(%r9,%r10,1), %xmm0
+;;   jmp     label1
+;; block1:
+;;   movq    %rbp, %rsp
+;;   popq    %rbp
+;;   ret
+;;
+;; function u0:1:
+;;   pushq   %rbp
+;;   unwind PushFrameRegs { offset_upward_to_caller_sp: 16 }
+;;   movq    %rsp, %rbp
+;;   movq    8(%rdi), %r10
+;;   movq    0(%r10), %r10
+;;   cmpq    %rsp, %r10
+;;   jnbe #trap=stk_ovf
+;;   unwind DefineNewFrame { offset_upward_to_caller_sp: 16, offset_downward_to_clobbers: 0 }
+;; block0:
+;;   movq    80(%rdi), %r9
+;;   movl    %edx, %r10d
+;;   movsd   0(%r9,%r10,1), %xmm0
+;;   jmp     label1
+;; block1:
+;;   movq    %rbp, %rsp
+;;   popq    %rbp
+;;   ret
+;;
+;; function u0:2:
+;;   pushq   %rbp
+;;   unwind PushFrameRegs { offset_upward_to_caller_sp: 16 }
+;;   movq    %rsp, %rbp
+;;   movq    8(%rdi), %r10
+;;   movq    0(%r10), %r10
+;;   cmpq    %rsp, %r10
+;;   jnbe #trap=stk_ovf
+;;   unwind DefineNewFrame { offset_upward_to_caller_sp: 16, offset_downward_to_clobbers: 0 }
+;; block0:
+;;   movq    80(%rdi), %r9
+;;   movl    %edx, %r10d
+;;   movss   %xmm0, 0(%r9,%r10,1)
+;;   jmp     label1
+;; block1:
+;;   movq    %rbp, %rsp
+;;   popq    %rbp
+;;   ret
+;;
+;; function u0:3:
+;;   pushq   %rbp
+;;   unwind PushFrameRegs { offset_upward_to_caller_sp: 16 }
+;;   movq    %rsp, %rbp
+;;   movq    8(%rdi), %r10
+;;   movq    0(%r10), %r10
+;;   cmpq    %rsp, %r10
+;;   jnbe #trap=stk_ovf
+;;   unwind DefineNewFrame { offset_upward_to_caller_sp: 16, offset_downward_to_clobbers: 0 }
+;; block0:
+;;   movq    80(%rdi), %r9
+;;   movl    %edx, %r10d
+;;   movsd   %xmm0, 0(%r9,%r10,1)
+;;   jmp     label1
+;; block1:
+;;   movq    %rbp, %rsp
+;;   popq    %rbp
+;;   ret
diff --git a/tests/disas/table-get-fixed-size.wat b/tests/disas/table-get-fixed-size.wat
index b0e7dd4c2..fbdaf794d 100644
--- a/tests/disas/table-get-fixed-size.wat
+++ b/tests/disas/table-get-fixed-size.wat
@@ -33,20 +33,14 @@
 ;; @0052                               v3 = iconst.i32 0
 ;; @0054                               v4 = iconst.i32 7
 ;; @0054                               v5 = icmp uge v3, v4  ; v3 = 0, v4 = 7
-;; @0054                               brif v5, block6, block7
-;;
-;;                                 block6 cold:
-;; @0054                               trap table_oob
-;;
-;;                                 block7:
 ;; @0054                               v6 = uextend.i64 v3  ; v3 = 0
 ;; @0054                               v7 = load.i64 notrap aligned v25+72
 ;;                                     v26 = iconst.i64 3
 ;; @0054                               v8 = ishl v6, v26  ; v26 = 3
 ;; @0054                               v9 = iadd v7, v8
-;; @0054                               v10 = icmp.i32 uge v3, v4  ; v3 = 0, v4 = 7
-;; @0054                               v11 = select_spectre_guard v10, v7, v9
-;; @0054                               v12 = load.r64 notrap aligned table v11
+;; @0054                               v10 = iconst.i64 0
+;; @0054                               v11 = select_spectre_guard v5, v10, v9  ; v10 = 0
+;; @0054                               v12 = load.r64 table_oob aligned table v11
 ;;                                     v2 -> v12
 ;; @0054                               v13 = is_null v12
 ;; @0054                               brif v13, block2, block3
@@ -99,20 +93,14 @@
 ;;                                     v25 -> v0
 ;; @005b                               v4 = iconst.i32 7
 ;; @005b                               v5 = icmp uge v2, v4  ; v4 = 7
-;; @005b                               brif v5, block6, block7
-;;
-;;                                 block6 cold:
-;; @005b                               trap table_oob
-;;
-;;                                 block7:
 ;; @005b                               v6 = uextend.i64 v2
 ;; @005b                               v7 = load.i64 notrap aligned v25+72
 ;;                                     v26 = iconst.i64 3
 ;; @005b                               v8 = ishl v6, v26  ; v26 = 3
 ;; @005b                               v9 = iadd v7, v8
-;; @005b                               v10 = icmp.i32 uge v2, v4  ; v4 = 7
-;; @005b                               v11 = select_spectre_guard v10, v7, v9
-;; @005b                               v12 = load.r64 notrap aligned table v11
+;; @005b                               v10 = iconst.i64 0
+;; @005b                               v11 = select_spectre_guard v5, v10, v9  ; v10 = 0
+;; @005b                               v12 = load.r64 table_oob aligned table v11
 ;;                                     v3 -> v12
 ;; @005b                               v13 = is_null v12
 ;; @005b                               brif v13, block2, block3
diff --git a/tests/disas/table-get.wat b/tests/disas/table-get.wat
index 992d62451..0cbee62e2 100644
--- a/tests/disas/table-get.wat
+++ b/tests/disas/table-get.wat
@@ -34,20 +34,14 @@
 ;; @0051                               v3 = iconst.i32 0
 ;; @0053                               v4 = load.i32 notrap aligned v25+80
 ;; @0053                               v5 = icmp uge v3, v4  ; v3 = 0
-;; @0053                               brif v5, block6, block7
-;;
-;;                                 block6 cold:
-;; @0053                               trap table_oob
-;;
-;;                                 block7:
 ;; @0053                               v6 = uextend.i64 v3  ; v3 = 0
 ;; @0053                               v7 = load.i64 notrap aligned v26+72
 ;;                                     v27 = iconst.i64 3
 ;; @0053                               v8 = ishl v6, v27  ; v27 = 3
 ;; @0053                               v9 = iadd v7, v8
-;; @0053                               v10 = icmp.i32 uge v3, v4  ; v3 = 0
-;; @0053                               v11 = select_spectre_guard v10, v7, v9
-;; @0053                               v12 = load.r64 notrap aligned table v11
+;; @0053                               v10 = iconst.i64 0
+;; @0053                               v11 = select_spectre_guard v5, v10, v9  ; v10 = 0
+;; @0053                               v12 = load.r64 table_oob aligned table v11
 ;;                                     v2 -> v12
 ;; @0053                               v13 = is_null v12
 ;; @0053                               brif v13, block2, block3
@@ -102,20 +96,14 @@
 ;;                                     v26 -> v0
 ;; @005a                               v4 = load.i32 notrap aligned v25+80
 ;; @005a                               v5 = icmp uge v2, v4
-;; @005a                               brif v5, block6, block7
-;;
-;;                                 block6 cold:
-;; @005a                               trap table_oob
-;;
-;;                                 block7:
 ;; @005a                               v6 = uextend.i64 v2
 ;; @005a                               v7 = load.i64 notrap aligned v26+72
 ;;                                     v27 = iconst.i64 3
 ;; @005a                               v8 = ishl v6, v27  ; v27 = 3
 ;; @005a                               v9 = iadd v7, v8
-;; @005a                               v10 = icmp.i32 uge v2, v4
-;; @005a                               v11 = select_spectre_guard v10, v7, v9
-;; @005a                               v12 = load.r64 notrap aligned table v11
+;; @005a                               v10 = iconst.i64 0
+;; @005a                               v11 = select_spectre_guard v5, v10, v9  ; v10 = 0
+;; @005a                               v12 = load.r64 table_oob aligned table v11
 ;;                                     v3 -> v12
 ;; @005a                               v13 = is_null v12
 ;; @005a                               brif v13, block2, block3
diff --git a/tests/disas/table-set-fixed-size.wat b/tests/disas/table-set-fixed-size.wat
index ceb2da584..f501bf1b7 100644
--- a/tests/disas/table-set-fixed-size.wat
+++ b/tests/disas/table-set-fixed-size.wat
@@ -34,22 +34,16 @@
 ;; @0052                               v3 = iconst.i32 0
 ;; @0056                               v4 = iconst.i32 7
 ;; @0056                               v5 = icmp uge v3, v4  ; v3 = 0, v4 = 7
-;; @0056                               brif v5, block7, block8
-;;
-;;                                 block7 cold:
-;; @0056                               trap table_oob
-;;
-;;                                 block8:
 ;; @0056                               v6 = uextend.i64 v3  ; v3 = 0
 ;; @0056                               v7 = load.i64 notrap aligned v23+72
 ;;                                     v24 = iconst.i64 3
 ;; @0056                               v8 = ishl v6, v24  ; v24 = 3
 ;; @0056                               v9 = iadd v7, v8
-;; @0056                               v10 = icmp.i32 uge v3, v4  ; v3 = 0, v4 = 7
-;; @0056                               v11 = select_spectre_guard v10, v7, v9
-;; @0056                               v12 = load.i64 notrap aligned table v11
-;; @0056                               store.r64 notrap aligned table v2, v11
-;; @0056                               v13 = is_null.r64 v2
+;; @0056                               v10 = iconst.i64 0
+;; @0056                               v11 = select_spectre_guard v5, v10, v9  ; v10 = 0
+;; @0056                               v12 = load.i64 table_oob aligned table v11
+;; @0056                               store notrap aligned table v2, v11
+;; @0056                               v13 = is_null v2
 ;; @0056                               brif v13, block3, block2
 ;;
 ;;                                 block2:
@@ -102,22 +96,16 @@
 ;;                                     v23 -> v0
 ;; @005f                               v4 = iconst.i32 7
 ;; @005f                               v5 = icmp uge v2, v4  ; v4 = 7
-;; @005f                               brif v5, block7, block8
-;;
-;;                                 block7 cold:
-;; @005f                               trap table_oob
-;;
-;;                                 block8:
 ;; @005f                               v6 = uextend.i64 v2
 ;; @005f                               v7 = load.i64 notrap aligned v23+72
 ;;                                     v24 = iconst.i64 3
 ;; @005f                               v8 = ishl v6, v24  ; v24 = 3
 ;; @005f                               v9 = iadd v7, v8
-;; @005f                               v10 = icmp.i32 uge v2, v4  ; v4 = 7
-;; @005f                               v11 = select_spectre_guard v10, v7, v9
-;; @005f                               v12 = load.i64 notrap aligned table v11
-;; @005f                               store.r64 notrap aligned table v3, v11
-;; @005f                               v13 = is_null.r64 v3
+;; @005f                               v10 = iconst.i64 0
+;; @005f                               v11 = select_spectre_guard v5, v10, v9  ; v10 = 0
+;; @005f                               v12 = load.i64 table_oob aligned table v11
+;; @005f                               store notrap aligned table v3, v11
+;; @005f                               v13 = is_null v3
 ;; @005f                               brif v13, block3, block2
 ;;
 ;;                                 block2:
diff --git a/tests/disas/table-set.wat b/tests/disas/table-set.wat
index 93b71d52a..f792fb23a 100644
--- a/tests/disas/table-set.wat
+++ b/tests/disas/table-set.wat
@@ -35,22 +35,16 @@
 ;; @0051                               v3 = iconst.i32 0
 ;; @0055                               v4 = load.i32 notrap aligned v23+80
 ;; @0055                               v5 = icmp uge v3, v4  ; v3 = 0
-;; @0055                               brif v5, block7, block8
-;;
-;;                                 block7 cold:
-;; @0055                               trap table_oob
-;;
-;;                                 block8:
 ;; @0055                               v6 = uextend.i64 v3  ; v3 = 0
 ;; @0055                               v7 = load.i64 notrap aligned v24+72
 ;;                                     v25 = iconst.i64 3
 ;; @0055                               v8 = ishl v6, v25  ; v25 = 3
 ;; @0055                               v9 = iadd v7, v8
-;; @0055                               v10 = icmp.i32 uge v3, v4  ; v3 = 0
-;; @0055                               v11 = select_spectre_guard v10, v7, v9
-;; @0055                               v12 = load.i64 notrap aligned table v11
-;; @0055                               store.r64 notrap aligned table v2, v11
-;; @0055                               v13 = is_null.r64 v2
+;; @0055                               v10 = iconst.i64 0
+;; @0055                               v11 = select_spectre_guard v5, v10, v9  ; v10 = 0
+;; @0055                               v12 = load.i64 table_oob aligned table v11
+;; @0055                               store notrap aligned table v2, v11
+;; @0055                               v13 = is_null v2
 ;; @0055                               brif v13, block3, block2
 ;;
 ;;                                 block2:
@@ -105,22 +99,16 @@
 ;;                                     v24 -> v0
 ;; @005e                               v4 = load.i32 notrap aligned v23+80
 ;; @005e                               v5 = icmp uge v2, v4
-;; @005e                               brif v5, block7, block8
-;;
-;;                                 block7 cold:
-;; @005e                               trap table_oob
-;;
-;;                                 block8:
 ;; @005e                               v6 = uextend.i64 v2
 ;; @005e                               v7 = load.i64 notrap aligned v24+72
 ;;                                     v25 = iconst.i64 3
 ;; @005e                               v8 = ishl v6, v25  ; v25 = 3
 ;; @005e                               v9 = iadd v7, v8
-;; @005e                               v10 = icmp.i32 uge v2, v4
-;; @005e                               v11 = select_spectre_guard v10, v7, v9
-;; @005e                               v12 = load.i64 notrap aligned table v11
-;; @005e                               store.r64 notrap aligned table v3, v11
-;; @005e                               v13 = is_null.r64 v3
+;; @005e                               v10 = iconst.i64 0
+;; @005e                               v11 = select_spectre_guard v5, v10, v9  ; v10 = 0
+;; @005e                               v12 = load.i64 table_oob aligned table v11
+;; @005e                               store notrap aligned table v3, v11
+;; @005e                               v13 = is_null v3
 ;; @005e                               brif v13, block3, block2
 ;;
 ;;                                 block2:
diff --git a/tests/disas/typed-funcrefs.wat b/tests/disas/typed-funcrefs.wat
index 07f52e6aa..10ba6a955 100644
--- a/tests/disas/typed-funcrefs.wat
+++ b/tests/disas/typed-funcrefs.wat
@@ -112,6 +112,7 @@
 
         local.get $sum)
 )
+
 ;; function u0:0(i64 vmctx, i64, i32, i32, i32, i32) -> i32 fast {
 ;;     gv0 = vmctx
 ;;     gv1 = load.i64 notrap aligned readonly gv0+8
@@ -149,19 +150,13 @@
 ;;                                     v31 -> v3
 ;;                                     v32 -> v4
 ;;                                     v33 -> v5
-;;                                     v62 = iconst.i8 0
-;; @0048                               brif v62, block6, block7  ; v62 = 0
-;;
-;;                                 block6 cold:
-;; @0048                               trap table_oob
-;;
-;;                                 block7:
 ;; @0048                               v12 = load.i64 notrap aligned v0+72
-;;                                     v79 = iconst.i8 0
+;;                                     v62 = iconst.i8 0
+;; @0048                               v15 = iconst.i64 0
 ;;                                     v70 = iconst.i64 8
 ;; @0048                               v14 = iadd v12, v70  ; v70 = 8
-;; @0048                               v16 = select_spectre_guard v79, v12, v14  ; v79 = 0
-;; @0048                               v17 = load.i64 notrap aligned table v16
+;; @0048                               v16 = select_spectre_guard v62, v15, v14  ; v62 = 0, v15 = 0
+;; @0048                               v17 = load.i64 table_oob aligned table v16
 ;;                                     v58 = iconst.i64 -2
 ;; @0048                               v18 = band v17, v58  ; v58 = -2
 ;; @0048                               brif v17, block3(v18), block2
@@ -179,29 +174,23 @@
 ;; @004a                               v25 = load.i64 null_reference aligned readonly v19+16
 ;; @004a                               v26 = load.i64 notrap aligned readonly v19+32
 ;; @004a                               v27 = call_indirect sig1, v25(v26, v0, v2, v3, v4, v5)
-;;                                     v80 = iconst.i8 0
-;; @005b                               brif v80, block8, block9  ; v80 = 0
-;;
-;;                                 block8 cold:
-;; @005b                               trap table_oob
-;;
-;;                                 block9:
 ;; @005b                               v38 = load.i64 notrap aligned v0+72
-;;                                     v81 = iconst.i8 0
+;;                                     v79 = iconst.i8 0
+;;                                     v80 = iconst.i64 0
 ;;                                     v78 = iconst.i64 16
 ;; @005b                               v40 = iadd v38, v78  ; v78 = 16
-;; @005b                               v42 = select_spectre_guard v81, v38, v40  ; v81 = 0
-;; @005b                               v43 = load.i64 notrap aligned table v42
-;;                                     v82 = iconst.i64 -2
-;;                                     v83 = band v43, v82  ; v82 = -2
-;; @005b                               brif v43, block5(v83), block4
+;; @005b                               v42 = select_spectre_guard v79, v80, v40  ; v79 = 0, v80 = 0
+;; @005b                               v43 = load.i64 table_oob aligned table v42
+;;                                     v81 = iconst.i64 -2
+;;                                     v82 = band v43, v81  ; v81 = -2
+;; @005b                               brif v43, block5(v82), block4
 ;;
 ;;                                 block4 cold:
-;;                                     v84 = load.i64 notrap aligned readonly v0+56
-;;                                     v85 = load.i64 notrap aligned readonly v84+72
-;;                                     v86 = iconst.i32 0
+;;                                     v83 = load.i64 notrap aligned readonly v0+56
+;;                                     v84 = load.i64 notrap aligned readonly v83+72
+;;                                     v85 = iconst.i32 0
 ;; @0059                               v34 = iconst.i32 2
-;; @005b                               v50 = call_indirect sig0, v85(v0, v86, v34)  ; v86 = 0, v34 = 2
+;; @005b                               v50 = call_indirect sig0, v84(v0, v85, v34)  ; v85 = 0, v34 = 2
 ;; @005b                               jump block5(v50)
 ;;
 ;;                                 block5(v45: i64):
@@ -237,19 +226,13 @@
 ;;                                     v31 -> v3
 ;;                                     v32 -> v4
 ;;                                     v33 -> v5
-;;                                     v62 = iconst.i8 0
-;; @0075                               brif v62, block6, block7  ; v62 = 0
-;;
-;;                                 block6 cold:
-;; @0075                               trap table_oob
-;;
-;;                                 block7:
 ;; @0075                               v12 = load.i64 notrap aligned v0+72
-;;                                     v79 = iconst.i8 0
+;;                                     v62 = iconst.i8 0
+;; @0075                               v15 = iconst.i64 0
 ;;                                     v70 = iconst.i64 8
 ;; @0075                               v14 = iadd v12, v70  ; v70 = 8
-;; @0075                               v16 = select_spectre_guard v79, v12, v14  ; v79 = 0
-;; @0075                               v17 = load.i64 notrap aligned table v16
+;; @0075                               v16 = select_spectre_guard v62, v15, v14  ; v62 = 0, v15 = 0
+;; @0075                               v17 = load.i64 table_oob aligned table v16
 ;;                                     v58 = iconst.i64 -2
 ;; @0075                               v18 = band v17, v58  ; v58 = -2
 ;; @0075                               brif v17, block3(v18), block2
@@ -267,29 +250,23 @@
 ;; @0075                               v25 = load.i64 icall_null aligned readonly v19+16
 ;; @0075                               v26 = load.i64 notrap aligned readonly v19+32
 ;; @0075                               v27 = call_indirect sig0, v25(v26, v0, v2, v3, v4, v5)
-;;                                     v80 = iconst.i8 0
-;; @0087                               brif v80, block8, block9  ; v80 = 0
-;;
-;;                                 block8 cold:
-;; @0087                               trap table_oob
-;;
-;;                                 block9:
 ;; @0087                               v38 = load.i64 notrap aligned v0+72
-;;                                     v81 = iconst.i8 0
+;;                                     v79 = iconst.i8 0
+;;                                     v80 = iconst.i64 0
 ;;                                     v78 = iconst.i64 16
 ;; @0087                               v40 = iadd v38, v78  ; v78 = 16
-;; @0087                               v42 = select_spectre_guard v81, v38, v40  ; v81 = 0
-;; @0087                               v43 = load.i64 notrap aligned table v42
-;;                                     v82 = iconst.i64 -2
-;;                                     v83 = band v43, v82  ; v82 = -2
-;; @0087                               brif v43, block5(v83), block4
+;; @0087                               v42 = select_spectre_guard v79, v80, v40  ; v79 = 0, v80 = 0
+;; @0087                               v43 = load.i64 table_oob aligned table v42
+;;                                     v81 = iconst.i64 -2
+;;                                     v82 = band v43, v81  ; v81 = -2
+;; @0087                               brif v43, block5(v82), block4
 ;;
 ;;                                 block4 cold:
-;;                                     v84 = load.i64 notrap aligned readonly v0+56
-;;                                     v85 = load.i64 notrap aligned readonly v84+72
-;;                                     v86 = iconst.i32 0
+;;                                     v83 = load.i64 notrap aligned readonly v0+56
+;;                                     v84 = load.i64 notrap aligned readonly v83+72
+;;                                     v85 = iconst.i32 0
 ;; @0085                               v34 = iconst.i32 2
-;; @0087                               v50 = call_indirect sig1, v85(v0, v86, v34)  ; v86 = 0, v34 = 2
+;; @0087                               v50 = call_indirect sig1, v84(v0, v85, v34)  ; v85 = 0, v34 = 2
 ;; @0087                               jump block5(v50)
 ;;
 ;;                                 block5(v45: i64):