[llvm] [WebAssembly][FastISel] Call materializeLoadStoreOperands in load fold (PR #184203)

via llvm-commits llvm-commits at lists.llvm.org
Mon Mar 2 10:54:45 PST 2026


llvmbot wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-backend-webassembly

Author: hanbeom (ParkHanbum)

<details>
<summary>Changes</summary>

The `tryToFoldLoadIntoMI` function omitted materializing base registers for addresses before folding sign-extend instructions into loads. This left `$noreg` as the base register, crashing subsequent passes.

WebAssembly memory instructions structurally require a valid base register. Calling the existing `materializeLoadStoreOperands` function ensures that a `CONST 0` virtual register is generated when addressing global variables directly without a pre-existing base register.

(before) %1:i32 = LOAD8_S_I32_A32 0, @<!-- -->ch, $noreg ... -> CRASH (after)  %3:i32 = CONST_I32 0
         %1:i32 = LOAD8_S_I32_A32 0, @<!-- -->ch, %3:i32 ... -> Folded safely

---
Full diff: https://github.com/llvm/llvm-project/pull/184203.diff


2 Files Affected:

- (modified) llvm/lib/Target/WebAssembly/WebAssemblyFastISel.cpp (+1) 
- (modified) llvm/test/CodeGen/WebAssembly/load-ext.ll (+291) 


``````````diff
diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyFastISel.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyFastISel.cpp
index 02c3eb2469ea0..faec1acef68f9 100644
--- a/llvm/lib/Target/WebAssembly/WebAssemblyFastISel.cpp
+++ b/llvm/lib/Target/WebAssembly/WebAssemblyFastISel.cpp
@@ -1306,6 +1306,7 @@ bool WebAssemblyFastISel::tryToFoldLoadIntoMI(MachineInstr *MI, unsigned OpNo,
   if (!computeAddress(LI->getPointerOperand(), Addr))
     return false;
 
+  materializeLoadStoreOperands(Addr);
   Register ResultReg = MI->getOperand(0).getReg();
   MachineInstrBuilder MIB = BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD,
                                     TII.get(NewOpc), ResultReg);
diff --git a/llvm/test/CodeGen/WebAssembly/load-ext.ll b/llvm/test/CodeGen/WebAssembly/load-ext.ll
index d15b69fc7c76e..23664a8691d48 100644
--- a/llvm/test/CodeGen/WebAssembly/load-ext.ll
+++ b/llvm/test/CodeGen/WebAssembly/load-ext.ll
@@ -10,6 +10,297 @@
 
 ; Test that extending loads are assembled properly.
 
+ at gv8 = hidden global i8 0, align 1
+ at gv16 = hidden global i16 0, align 1
+
+define i32 @global_sext_i8_i32() {
+; WASM32-DAG-LABEL: global_sext_i8_i32:
+; WASM32-DAG:         .functype global_sext_i8_i32 () -> (i32)
+; WASM32-DAG-NEXT:  # %bb.0:
+; WASM32-DAG-NEXT:    i32.const $push0=, 0
+; WASM32-DAG-NEXT:    i32.load8_s $push1=, gv8($pop0)
+; WASM32-DAG-NEXT:    return $pop1
+;
+; WASM32-DAG-MVP-LABEL: global_sext_i8_i32:
+; WASM32-DAG-MVP:         .functype global_sext_i8_i32 () -> (i32)
+; WASM32-DAG-MVP-NEXT:  # %bb.0:
+; WASM32-DAG-MVP-NEXT:    i32.const $push0=, 0
+; WASM32-DAG-MVP-NEXT:    i32.load8_s $push1=, gv8($pop0)
+; WASM32-DAG-MVP-NEXT:    return $pop1
+;
+; WASM32-FAST-LABEL: global_sext_i8_i32:
+; WASM32-FAST:         .functype global_sext_i8_i32 () -> (i32)
+; WASM32-FAST-NEXT:  # %bb.0:
+; WASM32-FAST-NEXT:    i32.const $push1=, 0
+; WASM32-FAST-NEXT:    i32.load8_s $push0=, gv8($pop1)
+; WASM32-FAST-NEXT:    return $pop0
+;
+; WASM32-FAST-MVP-LABEL: global_sext_i8_i32:
+; WASM32-FAST-MVP:         .functype global_sext_i8_i32 () -> (i32)
+; WASM32-FAST-MVP-NEXT:  # %bb.0:
+; WASM32-FAST-MVP-NEXT:    i32.const $push3=, 0
+; WASM32-FAST-MVP-NEXT:    i32.load8_u $push4=, gv8($pop3)
+; WASM32-FAST-MVP-NEXT:    i32.const $push0=, 24
+; WASM32-FAST-MVP-NEXT:    i32.shl $push1=, $pop4, $pop0
+; WASM32-FAST-MVP-NEXT:    i32.const $push5=, 24
+; WASM32-FAST-MVP-NEXT:    i32.shr_s $push2=, $pop1, $pop5
+; WASM32-FAST-MVP-NEXT:    return $pop2
+;
+; WASM64-DAG-LABEL: global_sext_i8_i32:
+; WASM64-DAG:         .functype global_sext_i8_i32 () -> (i32)
+; WASM64-DAG-NEXT:  # %bb.0:
+; WASM64-DAG-NEXT:    i64.const $push0=, 0
+; WASM64-DAG-NEXT:    i32.load8_s $push1=, gv8($pop0)
+; WASM64-DAG-NEXT:    return $pop1
+;
+; WASM64-DAG-MVP-LABEL: global_sext_i8_i32:
+; WASM64-DAG-MVP:         .functype global_sext_i8_i32 () -> (i32)
+; WASM64-DAG-MVP-NEXT:  # %bb.0:
+; WASM64-DAG-MVP-NEXT:    i64.const $push0=, 0
+; WASM64-DAG-MVP-NEXT:    i32.load8_s $push1=, gv8($pop0)
+; WASM64-DAG-MVP-NEXT:    return $pop1
+;
+; WASM64-FAST-LABEL: global_sext_i8_i32:
+; WASM64-FAST:         .functype global_sext_i8_i32 () -> (i32)
+; WASM64-FAST-NEXT:  # %bb.0:
+; WASM64-FAST-NEXT:    i64.const $push1=, 0
+; WASM64-FAST-NEXT:    i32.load8_s $push0=, gv8($pop1)
+; WASM64-FAST-NEXT:    return $pop0
+;
+; WASM64-FAST-MVP-LABEL: global_sext_i8_i32:
+; WASM64-FAST-MVP:         .functype global_sext_i8_i32 () -> (i32)
+; WASM64-FAST-MVP-NEXT:  # %bb.0:
+; WASM64-FAST-MVP-NEXT:    i64.const $push3=, 0
+; WASM64-FAST-MVP-NEXT:    i32.load8_u $push4=, gv8($pop3)
+; WASM64-FAST-MVP-NEXT:    i32.const $push0=, 24
+; WASM64-FAST-MVP-NEXT:    i32.shl $push1=, $pop4, $pop0
+; WASM64-FAST-MVP-NEXT:    i32.const $push5=, 24
+; WASM64-FAST-MVP-NEXT:    i32.shr_s $push2=, $pop1, $pop5
+; WASM64-FAST-MVP-NEXT:    return $pop2
+  %ld = load i8, ptr @gv8, align 1
+  %conv = sext i8 %ld to i32
+  ret i32 %conv
+}
+
+define i32 @global_sext_i16_i32() {
+; WASM32-DAG-LABEL: global_sext_i16_i32:
+; WASM32-DAG:         .functype global_sext_i16_i32 () -> (i32)
+; WASM32-DAG-NEXT:  # %bb.0:
+; WASM32-DAG-NEXT:    i32.const $push0=, 0
+; WASM32-DAG-NEXT:    i32.load16_s $push1=, gv16($pop0):p2align=0
+; WASM32-DAG-NEXT:    return $pop1
+;
+; WASM32-DAG-MVP-LABEL: global_sext_i16_i32:
+; WASM32-DAG-MVP:         .functype global_sext_i16_i32 () -> (i32)
+; WASM32-DAG-MVP-NEXT:  # %bb.0:
+; WASM32-DAG-MVP-NEXT:    i32.const $push0=, 0
+; WASM32-DAG-MVP-NEXT:    i32.load16_s $push1=, gv16($pop0):p2align=0
+; WASM32-DAG-MVP-NEXT:    return $pop1
+;
+; WASM32-FAST-LABEL: global_sext_i16_i32:
+; WASM32-FAST:         .functype global_sext_i16_i32 () -> (i32)
+; WASM32-FAST-NEXT:  # %bb.0:
+; WASM32-FAST-NEXT:    i32.const $push1=, 0
+; WASM32-FAST-NEXT:    i32.load16_s $push0=, gv16($pop1):p2align=0
+; WASM32-FAST-NEXT:    return $pop0
+;
+; WASM32-FAST-MVP-LABEL: global_sext_i16_i32:
+; WASM32-FAST-MVP:         .functype global_sext_i16_i32 () -> (i32)
+; WASM32-FAST-MVP-NEXT:  # %bb.0:
+; WASM32-FAST-MVP-NEXT:    i32.const $push3=, 0
+; WASM32-FAST-MVP-NEXT:    i32.load16_u $push4=, gv16($pop3):p2align=0
+; WASM32-FAST-MVP-NEXT:    i32.const $push0=, 16
+; WASM32-FAST-MVP-NEXT:    i32.shl $push1=, $pop4, $pop0
+; WASM32-FAST-MVP-NEXT:    i32.const $push5=, 16
+; WASM32-FAST-MVP-NEXT:    i32.shr_s $push2=, $pop1, $pop5
+; WASM32-FAST-MVP-NEXT:    return $pop2
+;
+; WASM64-DAG-LABEL: global_sext_i16_i32:
+; WASM64-DAG:         .functype global_sext_i16_i32 () -> (i32)
+; WASM64-DAG-NEXT:  # %bb.0:
+; WASM64-DAG-NEXT:    i64.const $push0=, 0
+; WASM64-DAG-NEXT:    i32.load16_s $push1=, gv16($pop0):p2align=0
+; WASM64-DAG-NEXT:    return $pop1
+;
+; WASM64-DAG-MVP-LABEL: global_sext_i16_i32:
+; WASM64-DAG-MVP:         .functype global_sext_i16_i32 () -> (i32)
+; WASM64-DAG-MVP-NEXT:  # %bb.0:
+; WASM64-DAG-MVP-NEXT:    i64.const $push0=, 0
+; WASM64-DAG-MVP-NEXT:    i32.load16_s $push1=, gv16($pop0):p2align=0
+; WASM64-DAG-MVP-NEXT:    return $pop1
+;
+; WASM64-FAST-LABEL: global_sext_i16_i32:
+; WASM64-FAST:         .functype global_sext_i16_i32 () -> (i32)
+; WASM64-FAST-NEXT:  # %bb.0:
+; WASM64-FAST-NEXT:    i64.const $push1=, 0
+; WASM64-FAST-NEXT:    i32.load16_s $push0=, gv16($pop1):p2align=0
+; WASM64-FAST-NEXT:    return $pop0
+;
+; WASM64-FAST-MVP-LABEL: global_sext_i16_i32:
+; WASM64-FAST-MVP:         .functype global_sext_i16_i32 () -> (i32)
+; WASM64-FAST-MVP-NEXT:  # %bb.0:
+; WASM64-FAST-MVP-NEXT:    i64.const $push3=, 0
+; WASM64-FAST-MVP-NEXT:    i32.load16_u $push4=, gv16($pop3):p2align=0
+; WASM64-FAST-MVP-NEXT:    i32.const $push0=, 16
+; WASM64-FAST-MVP-NEXT:    i32.shl $push1=, $pop4, $pop0
+; WASM64-FAST-MVP-NEXT:    i32.const $push5=, 16
+; WASM64-FAST-MVP-NEXT:    i32.shr_s $push2=, $pop1, $pop5
+; WASM64-FAST-MVP-NEXT:    return $pop2
+  %ld = load i16, ptr @gv16, align 1
+  %conv = sext i16 %ld to i32
+  ret i32 %conv
+}
+
+define i64 @global_sext_i8_i64() {
+; WASM32-DAG-LABEL: global_sext_i8_i64:
+; WASM32-DAG:         .functype global_sext_i8_i64 () -> (i64)
+; WASM32-DAG-NEXT:  # %bb.0:
+; WASM32-DAG-NEXT:    i32.const $push0=, 0
+; WASM32-DAG-NEXT:    i64.load8_s $push1=, gv8($pop0)
+; WASM32-DAG-NEXT:    return $pop1
+;
+; WASM32-DAG-MVP-LABEL: global_sext_i8_i64:
+; WASM32-DAG-MVP:         .functype global_sext_i8_i64 () -> (i64)
+; WASM32-DAG-MVP-NEXT:  # %bb.0:
+; WASM32-DAG-MVP-NEXT:    i32.const $push0=, 0
+; WASM32-DAG-MVP-NEXT:    i64.load8_s $push1=, gv8($pop0)
+; WASM32-DAG-MVP-NEXT:    return $pop1
+;
+; WASM32-FAST-LABEL: global_sext_i8_i64:
+; WASM32-FAST:         .functype global_sext_i8_i64 () -> (i64)
+; WASM32-FAST-NEXT:  # %bb.0:
+; WASM32-FAST-NEXT:    i32.const $push2=, 0
+; WASM32-FAST-NEXT:    i32.load8_u $push3=, gv8($pop2)
+; WASM32-FAST-NEXT:    i64.extend_i32_u $push0=, $pop3
+; WASM32-FAST-NEXT:    i64.extend8_s $push1=, $pop0
+; WASM32-FAST-NEXT:    return $pop1
+;
+; WASM32-FAST-MVP-LABEL: global_sext_i8_i64:
+; WASM32-FAST-MVP:         .functype global_sext_i8_i64 () -> (i64)
+; WASM32-FAST-MVP-NEXT:  # %bb.0:
+; WASM32-FAST-MVP-NEXT:    i32.const $push4=, 0
+; WASM32-FAST-MVP-NEXT:    i32.load8_u $push5=, gv8($pop4)
+; WASM32-FAST-MVP-NEXT:    i32.const $push1=, 24
+; WASM32-FAST-MVP-NEXT:    i32.shl $push2=, $pop5, $pop1
+; WASM32-FAST-MVP-NEXT:    i32.const $push6=, 24
+; WASM32-FAST-MVP-NEXT:    i32.shr_s $push3=, $pop2, $pop6
+; WASM32-FAST-MVP-NEXT:    i64.extend_i32_s $push0=, $pop3
+; WASM32-FAST-MVP-NEXT:    return $pop0
+;
+; WASM64-DAG-LABEL: global_sext_i8_i64:
+; WASM64-DAG:         .functype global_sext_i8_i64 () -> (i64)
+; WASM64-DAG-NEXT:  # %bb.0:
+; WASM64-DAG-NEXT:    i64.const $push0=, 0
+; WASM64-DAG-NEXT:    i64.load8_s $push1=, gv8($pop0)
+; WASM64-DAG-NEXT:    return $pop1
+;
+; WASM64-DAG-MVP-LABEL: global_sext_i8_i64:
+; WASM64-DAG-MVP:         .functype global_sext_i8_i64 () -> (i64)
+; WASM64-DAG-MVP-NEXT:  # %bb.0:
+; WASM64-DAG-MVP-NEXT:    i64.const $push0=, 0
+; WASM64-DAG-MVP-NEXT:    i64.load8_s $push1=, gv8($pop0)
+; WASM64-DAG-MVP-NEXT:    return $pop1
+;
+; WASM64-FAST-LABEL: global_sext_i8_i64:
+; WASM64-FAST:         .functype global_sext_i8_i64 () -> (i64)
+; WASM64-FAST-NEXT:  # %bb.0:
+; WASM64-FAST-NEXT:    i64.const $push2=, 0
+; WASM64-FAST-NEXT:    i32.load8_u $push3=, gv8($pop2)
+; WASM64-FAST-NEXT:    i64.extend_i32_u $push0=, $pop3
+; WASM64-FAST-NEXT:    i64.extend8_s $push1=, $pop0
+; WASM64-FAST-NEXT:    return $pop1
+;
+; WASM64-FAST-MVP-LABEL: global_sext_i8_i64:
+; WASM64-FAST-MVP:         .functype global_sext_i8_i64 () -> (i64)
+; WASM64-FAST-MVP-NEXT:  # %bb.0:
+; WASM64-FAST-MVP-NEXT:    i64.const $push4=, 0
+; WASM64-FAST-MVP-NEXT:    i32.load8_u $push5=, gv8($pop4)
+; WASM64-FAST-MVP-NEXT:    i32.const $push1=, 24
+; WASM64-FAST-MVP-NEXT:    i32.shl $push2=, $pop5, $pop1
+; WASM64-FAST-MVP-NEXT:    i32.const $push6=, 24
+; WASM64-FAST-MVP-NEXT:    i32.shr_s $push3=, $pop2, $pop6
+; WASM64-FAST-MVP-NEXT:    i64.extend_i32_s $push0=, $pop3
+; WASM64-FAST-MVP-NEXT:    return $pop0
+  %ld = load i8, ptr @gv8, align 1
+  %conv = sext i8 %ld to i64
+  ret i64 %conv
+}
+
+define i64 @global_sext_i16_i64() {
+; WASM32-DAG-LABEL: global_sext_i16_i64:
+; WASM32-DAG:         .functype global_sext_i16_i64 () -> (i64)
+; WASM32-DAG-NEXT:  # %bb.0:
+; WASM32-DAG-NEXT:    i32.const $push0=, 0
+; WASM32-DAG-NEXT:    i64.load16_s $push1=, gv16($pop0):p2align=0
+; WASM32-DAG-NEXT:    return $pop1
+;
+; WASM32-DAG-MVP-LABEL: global_sext_i16_i64:
+; WASM32-DAG-MVP:         .functype global_sext_i16_i64 () -> (i64)
+; WASM32-DAG-MVP-NEXT:  # %bb.0:
+; WASM32-DAG-MVP-NEXT:    i32.const $push0=, 0
+; WASM32-DAG-MVP-NEXT:    i64.load16_s $push1=, gv16($pop0):p2align=0
+; WASM32-DAG-MVP-NEXT:    return $pop1
+;
+; WASM32-FAST-LABEL: global_sext_i16_i64:
+; WASM32-FAST:         .functype global_sext_i16_i64 () -> (i64)
+; WASM32-FAST-NEXT:  # %bb.0:
+; WASM32-FAST-NEXT:    i32.const $push2=, 0
+; WASM32-FAST-NEXT:    i32.load16_u $push3=, gv16($pop2):p2align=0
+; WASM32-FAST-NEXT:    i64.extend_i32_u $push0=, $pop3
+; WASM32-FAST-NEXT:    i64.extend16_s $push1=, $pop0
+; WASM32-FAST-NEXT:    return $pop1
+;
+; WASM32-FAST-MVP-LABEL: global_sext_i16_i64:
+; WASM32-FAST-MVP:         .functype global_sext_i16_i64 () -> (i64)
+; WASM32-FAST-MVP-NEXT:  # %bb.0:
+; WASM32-FAST-MVP-NEXT:    i32.const $push4=, 0
+; WASM32-FAST-MVP-NEXT:    i32.load16_u $push5=, gv16($pop4):p2align=0
+; WASM32-FAST-MVP-NEXT:    i32.const $push1=, 16
+; WASM32-FAST-MVP-NEXT:    i32.shl $push2=, $pop5, $pop1
+; WASM32-FAST-MVP-NEXT:    i32.const $push6=, 16
+; WASM32-FAST-MVP-NEXT:    i32.shr_s $push3=, $pop2, $pop6
+; WASM32-FAST-MVP-NEXT:    i64.extend_i32_s $push0=, $pop3
+; WASM32-FAST-MVP-NEXT:    return $pop0
+;
+; WASM64-DAG-LABEL: global_sext_i16_i64:
+; WASM64-DAG:         .functype global_sext_i16_i64 () -> (i64)
+; WASM64-DAG-NEXT:  # %bb.0:
+; WASM64-DAG-NEXT:    i64.const $push0=, 0
+; WASM64-DAG-NEXT:    i64.load16_s $push1=, gv16($pop0):p2align=0
+; WASM64-DAG-NEXT:    return $pop1
+;
+; WASM64-DAG-MVP-LABEL: global_sext_i16_i64:
+; WASM64-DAG-MVP:         .functype global_sext_i16_i64 () -> (i64)
+; WASM64-DAG-MVP-NEXT:  # %bb.0:
+; WASM64-DAG-MVP-NEXT:    i64.const $push0=, 0
+; WASM64-DAG-MVP-NEXT:    i64.load16_s $push1=, gv16($pop0):p2align=0
+; WASM64-DAG-MVP-NEXT:    return $pop1
+;
+; WASM64-FAST-LABEL: global_sext_i16_i64:
+; WASM64-FAST:         .functype global_sext_i16_i64 () -> (i64)
+; WASM64-FAST-NEXT:  # %bb.0:
+; WASM64-FAST-NEXT:    i64.const $push2=, 0
+; WASM64-FAST-NEXT:    i32.load16_u $push3=, gv16($pop2):p2align=0
+; WASM64-FAST-NEXT:    i64.extend_i32_u $push0=, $pop3
+; WASM64-FAST-NEXT:    i64.extend16_s $push1=, $pop0
+; WASM64-FAST-NEXT:    return $pop1
+;
+; WASM64-FAST-MVP-LABEL: global_sext_i16_i64:
+; WASM64-FAST-MVP:         .functype global_sext_i16_i64 () -> (i64)
+; WASM64-FAST-MVP-NEXT:  # %bb.0:
+; WASM64-FAST-MVP-NEXT:    i64.const $push4=, 0
+; WASM64-FAST-MVP-NEXT:    i32.load16_u $push5=, gv16($pop4):p2align=0
+; WASM64-FAST-MVP-NEXT:    i32.const $push1=, 16
+; WASM64-FAST-MVP-NEXT:    i32.shl $push2=, $pop5, $pop1
+; WASM64-FAST-MVP-NEXT:    i32.const $push6=, 16
+; WASM64-FAST-MVP-NEXT:    i32.shr_s $push3=, $pop2, $pop6
+; WASM64-FAST-MVP-NEXT:    i64.extend_i32_s $push0=, $pop3
+; WASM64-FAST-MVP-NEXT:    return $pop0
+  %ld= load i16, ptr @gv16, align 1
+  %conv = sext i16 %ld to i64
+  ret i64 %conv
+}
+
 define i32 @sext_i8_i32(ptr %p) {
 ; WASM32-DAG-LABEL: sext_i8_i32:
 ; WASM32-DAG:         .functype sext_i8_i32 (i32) -> (i32)

``````````

</details>


https://github.com/llvm/llvm-project/pull/184203


More information about the llvm-commits mailing list