[llvm] [WebAssembly][GlobalISel] Implement control flow ops. (PR #218857)

Demetrius Kanios via llvm-commits llvm-commits at lists.llvm.org
Wed Aug 26 10:56:37 PDT 2026


https://github.com/QuantumSegfault updated https://github.com/llvm/llvm-project/pull/218857

>From dea72e88cdc09e57db22e19ca515f485a81f0dba Mon Sep 17 00:00:00 2001
From: Demetrius Kanios <demetrius at kanios.net>
Date: Wed, 26 Aug 2026 01:17:26 -0700
Subject: [PATCH 1/2] Implement control flow ops.

---
 .../GISel/WebAssemblyInstructionSelector.cpp  |  44 +++
 .../GISel/WebAssemblyLegalizerInfo.cpp        |  13 +
 .../GISel/WebAssemblyRegisterBankInfo.cpp     |   2 +-
 .../WebAssembly/GlobalISel/instructions/br.ll |  24 ++
 .../GlobalISel/instructions/brcond.ll         |  36 +++
 .../GlobalISel/instructions/brjt.ll           | 116 ++++++++
 .../GlobalISel/instructions/phi.ll            | 280 ++++++++++++++++++
 7 files changed, 514 insertions(+), 1 deletion(-)
 create mode 100644 llvm/test/CodeGen/WebAssembly/GlobalISel/instructions/br.ll
 create mode 100644 llvm/test/CodeGen/WebAssembly/GlobalISel/instructions/brcond.ll
 create mode 100644 llvm/test/CodeGen/WebAssembly/GlobalISel/instructions/brjt.ll
 create mode 100644 llvm/test/CodeGen/WebAssembly/GlobalISel/instructions/phi.ll

diff --git a/llvm/lib/Target/WebAssembly/GISel/WebAssemblyInstructionSelector.cpp b/llvm/lib/Target/WebAssembly/GISel/WebAssemblyInstructionSelector.cpp
index 2331b8b636603..2f40034cb7309 100644
--- a/llvm/lib/Target/WebAssembly/GISel/WebAssemblyInstructionSelector.cpp
+++ b/llvm/lib/Target/WebAssembly/GISel/WebAssemblyInstructionSelector.cpp
@@ -20,6 +20,7 @@
 #include "llvm/CodeGen/GlobalISel/InstructionSelector.h"
 #include "llvm/CodeGen/GlobalISel/MachineIRBuilder.h"
 #include "llvm/CodeGen/GlobalISel/Utils.h"
+#include "llvm/CodeGen/MachineJumpTableInfo.h"
 #include "llvm/CodeGen/MachineOperand.h"
 #include "llvm/CodeGen/TargetLowering.h"
 #include "llvm/IR/IntrinsicsWebAssembly.h"
@@ -141,6 +142,19 @@ bool WebAssemblyInstructionSelector::select(MachineInstr &I) {
   MachineFunction &MF = *MBB.getParent();
   MachineRegisterInfo &MRI = MF.getRegInfo();
 
+  if (I.isPHI()) {
+    const Register DefReg = I.getOperand(0).getReg();
+
+    const TargetRegisterClass *DefRC =
+        TRI.getConstrainedRegClassForOperand(I.getOperand(0), MRI);
+
+    if (!DefRC)
+      return false;
+
+    I.setDesc(TII.get(TargetOpcode::PHI));
+    return RBI.constrainGenericRegister(DefReg, *DefRC, MRI) != nullptr;
+  }
+
   if (!I.isPreISelOpcode()) {
     if (I.isCopy())
       return selectCopy(I, MRI);
@@ -165,6 +179,36 @@ bool WebAssemblyInstructionSelector::select(MachineInstr &I) {
     I.setDesc(TII.get(TargetOpcode::IMPLICIT_DEF));
     return RBI.constrainGenericRegister(DefReg, *DefRC, MRI) != nullptr;
   }
+  case G_BRJT: {
+    auto JT = I.getOperand(1);
+    auto Index = I.getOperand(2);
+
+    assert(JT.getTargetFlags() == 0 && "WebAssembly doesn't set target flags");
+
+    MachineIRBuilder B(I);
+
+    MachineJumpTableInfo *MJTI = MF.getJumpTableInfo();
+    const auto &MBBs = MJTI->getJumpTables()[JT.getIndex()].MBBs;
+
+    LLT IndexTy = MRI.getType(Index.getReg());
+    bool IndexIsI64 = IndexTy.getSizeInBits() == 64;
+    auto MIB = B.buildInstr(IndexIsI64 ? WebAssembly::BR_TABLE_I64
+                                       : WebAssembly::BR_TABLE_I32)
+                   .add(Index);
+
+    for (auto *MBB : MBBs)
+      MIB.addMBB(MBB);
+
+    // Add the first MBB as a dummy default target for now. This will be
+    // replaced with the proper default target (and the preceding range check
+    // eliminated) if possible by WebAssemblyFixBrTableDefaults.
+    MIB.addMBB(*MBBs.begin());
+
+    constrainSelectedInstRegOperands(*MIB, TII, TRI, RBI);
+    I.eraseFromParent();
+
+    return true;
+  }
   default:
     break;
   }
diff --git a/llvm/lib/Target/WebAssembly/GISel/WebAssemblyLegalizerInfo.cpp b/llvm/lib/Target/WebAssembly/GISel/WebAssemblyLegalizerInfo.cpp
index 1fe8298b8e555..999e4efeb4e9b 100644
--- a/llvm/lib/Target/WebAssembly/GISel/WebAssemblyLegalizerInfo.cpp
+++ b/llvm/lib/Target/WebAssembly/GISel/WebAssemblyLegalizerInfo.cpp
@@ -35,6 +35,9 @@ WebAssemblyLegalizerInfo::WebAssemblyLegalizerInfo(
   const LLT s32 = LLT::scalar(32);
   const LLT s64 = LLT::scalar(64);
 
+  const LLT p0 = LLT::pointer(0, ST.hasAddr64() ? 64 : 32);
+  const LLT p0i = LLT::integer(ST.hasAddr64() ? 64 : 32);
+
   getActionDefinitionsBuilder(G_IMPLICIT_DEF)
       .legalFor({i32, i64, f32, f64})
       .widenScalarToNextPow2(0)
@@ -154,6 +157,16 @@ WebAssemblyLegalizerInfo::WebAssemblyLegalizerInfo(
       .widenScalarToNextPow2(0)
       .clampScalar(0, s32, s64)
       .clampScalar(1, s32, s32);
+
+  getActionDefinitionsBuilder(G_PHI)
+      .legalFor({i32, i64, f32, f64, p0})
+      .widenScalarToNextPow2(0)
+      .clampScalar(0, s32, s64);
+  getActionDefinitionsBuilder(G_BR).alwaysLegal();
+  getActionDefinitionsBuilder(G_BRCOND).legalFor({i32}).clampScalar(0, s32,
+                                                                    s32);
+  getActionDefinitionsBuilder(G_BRJT).legalFor({{p0, p0i}});
+  getActionDefinitionsBuilder(G_JUMP_TABLE).legalFor({p0});
 }
 
 bool WebAssemblyLegalizerInfo::legalizeCustom(
diff --git a/llvm/lib/Target/WebAssembly/GISel/WebAssemblyRegisterBankInfo.cpp b/llvm/lib/Target/WebAssembly/GISel/WebAssemblyRegisterBankInfo.cpp
index 7e50ca6ab22fe..78f2f3d3fae03 100644
--- a/llvm/lib/Target/WebAssembly/GISel/WebAssemblyRegisterBankInfo.cpp
+++ b/llvm/lib/Target/WebAssembly/GISel/WebAssemblyRegisterBankInfo.cpp
@@ -77,7 +77,7 @@ WebAssemblyRegisterBankInfo::getInstrMapping(const MachineInstr &MI) const {
 
     OpSize[Idx] = Ty.getSizeInBits().getKnownMinValue();
 
-    if (Ty.isInteger()) {
+    if (Ty.isInteger() || (Ty.isPointer() && Ty.getAddressSpace() == 0)) {
       if (OpSize[Idx] == 32) {
         OpRegBankIdx[Idx] = WebAssembly::PMI_I32;
       } else if (OpSize[Idx] == 64) {
diff --git a/llvm/test/CodeGen/WebAssembly/GlobalISel/instructions/br.ll b/llvm/test/CodeGen/WebAssembly/GlobalISel/instructions/br.ll
new file mode 100644
index 0000000000000..2c0fcadb9eb1a
--- /dev/null
+++ b/llvm/test/CodeGen/WebAssembly/GlobalISel/instructions/br.ll
@@ -0,0 +1,24 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 6
+; RUN: llc < %s -O0 --global-isel -disable-wasm-fallthrough-return-opt -wasm-keep-registers | FileCheck %s
+
+target triple = "wasm32-unknown-unknown"
+
+define i1 @br() {
+; CHECK-LABEL: br:
+; CHECK:         .functype br () -> (i32)
+; CHECK-NEXT:    .local i32
+; CHECK-NEXT:  # %bb.0: # %entry
+; CHECK-NEXT:    i32.const $push0=, 1
+; CHECK-NEXT:    local.set 0, $pop0
+; CHECK-NEXT:  # %bb.1: # %actualRet
+; CHECK-NEXT:    local.get $push1=, 0
+; CHECK-NEXT:    return $pop1
+entry:
+  br label %actualRet
+
+unusedRet:
+  ret i1 false
+
+actualRet:
+  ret i1 true
+}
diff --git a/llvm/test/CodeGen/WebAssembly/GlobalISel/instructions/brcond.ll b/llvm/test/CodeGen/WebAssembly/GlobalISel/instructions/brcond.ll
new file mode 100644
index 0000000000000..e52a013601bdd
--- /dev/null
+++ b/llvm/test/CodeGen/WebAssembly/GlobalISel/instructions/brcond.ll
@@ -0,0 +1,36 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 6
+; RUN: llc < %s -O0 --global-isel -disable-wasm-fallthrough-return-opt -wasm-keep-registers | FileCheck %s
+
+target triple = "wasm32-unknown-unknown"
+
+define i8 @brcond(i1 %cond) {
+; CHECK-LABEL: brcond:
+; CHECK:         .functype brcond (i32) -> (i32)
+; CHECK-NEXT:    .local i32, i32
+; CHECK-NEXT:  # %bb.0: # %entry
+; CHECK-NEXT:    i32.const $push2=, 0
+; CHECK-NEXT:    local.set 1, $pop2
+; CHECK-NEXT:    i32.const $push3=, -1
+; CHECK-NEXT:    local.set 2, $pop3
+; CHECK-NEXT:    block
+; CHECK-NEXT:    local.get $push4=, 0
+; CHECK-NEXT:    i32.const $push1=, 1
+; CHECK-NEXT:    i32.and $push0=, $pop4, $pop1
+; CHECK-NEXT:    i32.eqz $push7=, $pop0
+; CHECK-NEXT:    br_if 0, $pop7 # 0: down to label0
+; CHECK-NEXT:  # %bb.1: # %truePath
+; CHECK-NEXT:    local.get $push5=, 2
+; CHECK-NEXT:    return $pop5
+; CHECK-NEXT:  .LBB0_2: # %falsePath
+; CHECK-NEXT:    end_block # label0:
+; CHECK-NEXT:    local.get $push6=, 1
+; CHECK-NEXT:    return $pop6
+entry:
+  br i1 %cond, label %truePath, label %falsePath
+
+truePath:
+  ret i8 255
+
+falsePath:
+  ret i8 0
+}
diff --git a/llvm/test/CodeGen/WebAssembly/GlobalISel/instructions/brjt.ll b/llvm/test/CodeGen/WebAssembly/GlobalISel/instructions/brjt.ll
new file mode 100644
index 0000000000000..671948ece1b80
--- /dev/null
+++ b/llvm/test/CodeGen/WebAssembly/GlobalISel/instructions/brjt.ll
@@ -0,0 +1,116 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 6
+; RUN: llc < %s -O0 -mtriple=wasm32-unknown-unknown --global-isel -disable-wasm-fallthrough-return-opt | FileCheck %s --check-prefix=WASM32
+; RUN: llc < %s -O0 -mtriple=wasm64-unknown-unknown --global-isel -disable-wasm-fallthrough-return-opt | FileCheck %s --check-prefix=WASM64
+
+define i8 @brjt(i32 %val) {
+; WASM32-LABEL: brjt:
+; WASM32:         .functype brjt (i32) -> (i32)
+; WASM32-NEXT:    .local i32, i32, i32, i32, i32, i32
+; WASM32-NEXT:  # %bb.0: # %entry
+; WASM32-NEXT:    i32.const 2
+; WASM32-NEXT:    local.set 1
+; WASM32-NEXT:    i32.const -1
+; WASM32-NEXT:    local.set 2
+; WASM32-NEXT:    i32.const 42
+; WASM32-NEXT:    local.set 3
+; WASM32-NEXT:    i32.const 0
+; WASM32-NEXT:    local.set 4
+; WASM32-NEXT:    i32.const 127
+; WASM32-NEXT:    local.set 5
+; WASM32-NEXT:    local.get 0
+; WASM32-NEXT:    i32.const 0
+; WASM32-NEXT:    i32.sub
+; WASM32-NEXT:    local.set 6
+; WASM32-NEXT:    local.get 6
+; WASM32-NEXT:    local.get 1
+; WASM32-NEXT:    i32.gt_u
+; WASM32-NEXT:    drop
+; WASM32-NEXT:    block
+; WASM32-NEXT:    block
+; WASM32-NEXT:    block
+; WASM32-NEXT:    block
+; WASM32-NEXT:    local.get 6
+; WASM32-NEXT:    br_table {0, 1, 2, 3} # 1: down to label2
+; WASM32-NEXT:    # 2: down to label1
+; WASM32-NEXT:    # 3: down to label0
+; WASM32-NEXT:  .LBB0_1: # %onzero
+; WASM32-NEXT:    end_block # label3:
+; WASM32-NEXT:    local.get 4
+; WASM32-NEXT:    return
+; WASM32-NEXT:  .LBB0_2: # %onone
+; WASM32-NEXT:    end_block # label2:
+; WASM32-NEXT:    local.get 3
+; WASM32-NEXT:    return
+; WASM32-NEXT:  .LBB0_3: # %ontwo
+; WASM32-NEXT:    end_block # label1:
+; WASM32-NEXT:    local.get 2
+; WASM32-NEXT:    return
+; WASM32-NEXT:  .LBB0_4: # %otherwise
+; WASM32-NEXT:    end_block # label0:
+; WASM32-NEXT:    local.get 5
+; WASM32-NEXT:    return
+;
+; WASM64-LABEL: brjt:
+; WASM64:         .functype brjt (i32) -> (i32)
+; WASM64-NEXT:    .local i32, i32, i32, i32, i32
+; WASM64-NEXT:  # %bb.0: # %entry
+; WASM64-NEXT:    i32.const -1
+; WASM64-NEXT:    local.set 1
+; WASM64-NEXT:    i32.const 42
+; WASM64-NEXT:    local.set 2
+; WASM64-NEXT:    i32.const 0
+; WASM64-NEXT:    local.set 3
+; WASM64-NEXT:    i32.const 127
+; WASM64-NEXT:    local.set 4
+; WASM64-NEXT:    local.get 0
+; WASM64-NEXT:    i32.const 0
+; WASM64-NEXT:    i32.sub
+; WASM64-NEXT:    local.set 5
+; WASM64-NEXT:    block
+; WASM64-NEXT:    local.get 5
+; WASM64-NEXT:    i64.extend_i32_u
+; WASM64-NEXT:    i64.const 2
+; WASM64-NEXT:    i64.gt_u
+; WASM64-NEXT:    br_if 0 # 0: down to label0
+; WASM64-NEXT:  # %bb.1: # %entry
+; WASM64-NEXT:    block
+; WASM64-NEXT:    block
+; WASM64-NEXT:    block
+; WASM64-NEXT:    local.get 5
+; WASM64-NEXT:    br_table {0, 1, 2, 0} # 1: down to label2
+; WASM64-NEXT:    # 2: down to label1
+; WASM64-NEXT:    # 0: down to label3
+; WASM64-NEXT:  .LBB0_2: # %onzero
+; WASM64-NEXT:    end_block # label3:
+; WASM64-NEXT:    local.get 3
+; WASM64-NEXT:    return
+; WASM64-NEXT:  .LBB0_3: # %onone
+; WASM64-NEXT:    end_block # label2:
+; WASM64-NEXT:    local.get 2
+; WASM64-NEXT:    return
+; WASM64-NEXT:  .LBB0_4: # %ontwo
+; WASM64-NEXT:    end_block # label1:
+; WASM64-NEXT:    local.get 1
+; WASM64-NEXT:    return
+; WASM64-NEXT:  .LBB0_5: # %otherwise
+; WASM64-NEXT:    end_block # label0:
+; WASM64-NEXT:    local.get 4
+; WASM64-NEXT:    return
+
+entry:
+  switch i32 %val, label %otherwise [ i32 0, label %onzero
+                                      i32 1, label %onone
+                                      i32 2, label %ontwo ]
+
+onzero:
+  ret i8 0
+
+onone:
+  ret i8 42
+
+ontwo:
+  ret i8 -1
+
+otherwise:
+  ret i8 127
+}
diff --git a/llvm/test/CodeGen/WebAssembly/GlobalISel/instructions/phi.ll b/llvm/test/CodeGen/WebAssembly/GlobalISel/instructions/phi.ll
new file mode 100644
index 0000000000000..ebc8c00ed390a
--- /dev/null
+++ b/llvm/test/CodeGen/WebAssembly/GlobalISel/instructions/phi.ll
@@ -0,0 +1,280 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 6
+; RUN: llc < %s -O0 -mtriple=wasm32-unknown-unknown --global-isel -disable-wasm-fallthrough-return-opt -wasm-keep-registers | FileCheck %s --check-prefixes=CHECK,WASM32
+; RUN: llc < %s -O0 -mtriple=wasm64-unknown-unknown --global-isel -disable-wasm-fallthrough-return-opt -wasm-keep-registers | FileCheck %s --check-prefixes=CHECK,WASM64
+
+define i8 @phi_i8(i1 %cond) {
+; CHECK-LABEL: phi_i8:
+; CHECK:         .functype phi_i8 (i32) -> (i32)
+; CHECK-NEXT:    .local i32, i32, i32, i32
+; CHECK-NEXT:  # %bb.0: # %entry
+; CHECK-NEXT:    i32.const $push2=, 0
+; CHECK-NEXT:    local.set 1, $pop2
+; CHECK-NEXT:    i32.const $push3=, -1
+; CHECK-NEXT:    local.set 2, $pop3
+; CHECK-NEXT:    local.get $push5=, 0
+; CHECK-NEXT:    i32.const $push1=, 1
+; CHECK-NEXT:    i32.and $push4=, $pop5, $pop1
+; CHECK-NEXT:    local.set 3, $pop4
+; CHECK-NEXT:    local.get $push6=, 1
+; CHECK-NEXT:    local.set 4, $pop6
+; CHECK-NEXT:    block
+; CHECK-NEXT:    local.get $push7=, 3
+; CHECK-NEXT:    i32.eqz $push9=, $pop7
+; CHECK-NEXT:    br_if 0, $pop9 # 0: down to label0
+; CHECK-NEXT:  # %bb.1: # %hop
+; CHECK-NEXT:    local.get $push8=, 2
+; CHECK-NEXT:    local.set 4, $pop8
+; CHECK-NEXT:  .LBB0_2: # %end
+; CHECK-NEXT:    end_block # label0:
+; CHECK-NEXT:    local.get $push0=, 4
+; CHECK-NEXT:    return $pop0
+entry:
+  br i1 %cond, label %hop, label %end
+
+hop:
+  br label %end
+
+end:
+  %rval = phi i8 [0, %entry], [255, %hop]
+  ret i8 %rval
+}
+
+define i16 @phi_i16(i1 %cond) {
+; CHECK-LABEL: phi_i16:
+; CHECK:         .functype phi_i16 (i32) -> (i32)
+; CHECK-NEXT:    .local i32, i32, i32, i32
+; CHECK-NEXT:  # %bb.0: # %entry
+; CHECK-NEXT:    i32.const $push2=, 0
+; CHECK-NEXT:    local.set 1, $pop2
+; CHECK-NEXT:    i32.const $push3=, -1
+; CHECK-NEXT:    local.set 2, $pop3
+; CHECK-NEXT:    local.get $push5=, 0
+; CHECK-NEXT:    i32.const $push1=, 1
+; CHECK-NEXT:    i32.and $push4=, $pop5, $pop1
+; CHECK-NEXT:    local.set 3, $pop4
+; CHECK-NEXT:    local.get $push6=, 1
+; CHECK-NEXT:    local.set 4, $pop6
+; CHECK-NEXT:    block
+; CHECK-NEXT:    local.get $push7=, 3
+; CHECK-NEXT:    i32.eqz $push9=, $pop7
+; CHECK-NEXT:    br_if 0, $pop9 # 0: down to label1
+; CHECK-NEXT:  # %bb.1: # %hop
+; CHECK-NEXT:    local.get $push8=, 2
+; CHECK-NEXT:    local.set 4, $pop8
+; CHECK-NEXT:  .LBB1_2: # %end
+; CHECK-NEXT:    end_block # label1:
+; CHECK-NEXT:    local.get $push0=, 4
+; CHECK-NEXT:    return $pop0
+entry:
+  br i1 %cond, label %hop, label %end
+
+hop:
+  br label %end
+
+end:
+  %rval = phi i16 [0, %entry], [65535, %hop]
+  ret i16 %rval
+}
+
+define i32 @phi_i32(i1 %cond) {
+; CHECK-LABEL: phi_i32:
+; CHECK:         .functype phi_i32 (i32) -> (i32)
+; CHECK-NEXT:    .local i32, i32, i32, i32
+; CHECK-NEXT:  # %bb.0: # %entry
+; CHECK-NEXT:    i32.const $push2=, 0
+; CHECK-NEXT:    local.set 1, $pop2
+; CHECK-NEXT:    i32.const $push3=, -1
+; CHECK-NEXT:    local.set 2, $pop3
+; CHECK-NEXT:    local.get $push5=, 0
+; CHECK-NEXT:    i32.const $push1=, 1
+; CHECK-NEXT:    i32.and $push4=, $pop5, $pop1
+; CHECK-NEXT:    local.set 3, $pop4
+; CHECK-NEXT:    local.get $push6=, 1
+; CHECK-NEXT:    local.set 4, $pop6
+; CHECK-NEXT:    block
+; CHECK-NEXT:    local.get $push7=, 3
+; CHECK-NEXT:    i32.eqz $push9=, $pop7
+; CHECK-NEXT:    br_if 0, $pop9 # 0: down to label2
+; CHECK-NEXT:  # %bb.1: # %hop
+; CHECK-NEXT:    local.get $push8=, 2
+; CHECK-NEXT:    local.set 4, $pop8
+; CHECK-NEXT:  .LBB2_2: # %end
+; CHECK-NEXT:    end_block # label2:
+; CHECK-NEXT:    local.get $push0=, 4
+; CHECK-NEXT:    return $pop0
+entry:
+  br i1 %cond, label %hop, label %end
+
+hop:
+  br label %end
+
+end:
+  %rval = phi i32 [0, %entry], [4294967295, %hop]
+  ret i32 %rval
+}
+
+define i64 @phi_i64(i1 %cond) {
+; CHECK-LABEL: phi_i64:
+; CHECK:         .functype phi_i64 (i32) -> (i64)
+; CHECK-NEXT:    .local i64, i64, i32, i64
+; CHECK-NEXT:  # %bb.0: # %entry
+; CHECK-NEXT:    i64.const $push2=, 0
+; CHECK-NEXT:    local.set 1, $pop2
+; CHECK-NEXT:    i64.const $push3=, -1
+; CHECK-NEXT:    local.set 2, $pop3
+; CHECK-NEXT:    local.get $push5=, 0
+; CHECK-NEXT:    i32.const $push1=, 1
+; CHECK-NEXT:    i32.and $push4=, $pop5, $pop1
+; CHECK-NEXT:    local.set 3, $pop4
+; CHECK-NEXT:    local.get $push6=, 1
+; CHECK-NEXT:    local.set 4, $pop6
+; CHECK-NEXT:    block
+; CHECK-NEXT:    local.get $push7=, 3
+; CHECK-NEXT:    i32.eqz $push9=, $pop7
+; CHECK-NEXT:    br_if 0, $pop9 # 0: down to label3
+; CHECK-NEXT:  # %bb.1: # %hop
+; CHECK-NEXT:    local.get $push8=, 2
+; CHECK-NEXT:    local.set 4, $pop8
+; CHECK-NEXT:  .LBB3_2: # %end
+; CHECK-NEXT:    end_block # label3:
+; CHECK-NEXT:    local.get $push0=, 4
+; CHECK-NEXT:    return $pop0
+entry:
+  br i1 %cond, label %hop, label %end
+
+hop:
+  br label %end
+
+end:
+  %rval = phi i64 [0, %entry], [18446744073709551615, %hop]
+  ret i64 %rval
+}
+
+define float @phi_float(i1 %cond) {
+; CHECK-LABEL: phi_float:
+; CHECK:         .functype phi_float (i32) -> (f32)
+; CHECK-NEXT:    .local f32, f32, i32, f32
+; CHECK-NEXT:  # %bb.0: # %entry
+; CHECK-NEXT:    f32.const $push2=, 0x0p0
+; CHECK-NEXT:    local.set 1, $pop2
+; CHECK-NEXT:    f32.const $push3=, 0x1p0
+; CHECK-NEXT:    local.set 2, $pop3
+; CHECK-NEXT:    local.get $push5=, 0
+; CHECK-NEXT:    i32.const $push1=, 1
+; CHECK-NEXT:    i32.and $push4=, $pop5, $pop1
+; CHECK-NEXT:    local.set 3, $pop4
+; CHECK-NEXT:    local.get $push6=, 1
+; CHECK-NEXT:    local.set 4, $pop6
+; CHECK-NEXT:    block
+; CHECK-NEXT:    local.get $push7=, 3
+; CHECK-NEXT:    i32.eqz $push9=, $pop7
+; CHECK-NEXT:    br_if 0, $pop9 # 0: down to label4
+; CHECK-NEXT:  # %bb.1: # %hop
+; CHECK-NEXT:    local.get $push8=, 2
+; CHECK-NEXT:    local.set 4, $pop8
+; CHECK-NEXT:  .LBB4_2: # %end
+; CHECK-NEXT:    end_block # label4:
+; CHECK-NEXT:    local.get $push0=, 4
+; CHECK-NEXT:    return $pop0
+entry:
+  br i1 %cond, label %hop, label %end
+
+hop:
+  br label %end
+
+end:
+  %rval = phi float [0.0, %entry], [1.0, %hop]
+  ret float %rval
+}
+
+define double @phi_double(i1 %cond) {
+; CHECK-LABEL: phi_double:
+; CHECK:         .functype phi_double (i32) -> (f64)
+; CHECK-NEXT:    .local f64, f64, i32, f64
+; CHECK-NEXT:  # %bb.0: # %entry
+; CHECK-NEXT:    f64.const $push2=, 0x0p0
+; CHECK-NEXT:    local.set 1, $pop2
+; CHECK-NEXT:    f64.const $push3=, 0x1p0
+; CHECK-NEXT:    local.set 2, $pop3
+; CHECK-NEXT:    local.get $push5=, 0
+; CHECK-NEXT:    i32.const $push1=, 1
+; CHECK-NEXT:    i32.and $push4=, $pop5, $pop1
+; CHECK-NEXT:    local.set 3, $pop4
+; CHECK-NEXT:    local.get $push6=, 1
+; CHECK-NEXT:    local.set 4, $pop6
+; CHECK-NEXT:    block
+; CHECK-NEXT:    local.get $push7=, 3
+; CHECK-NEXT:    i32.eqz $push9=, $pop7
+; CHECK-NEXT:    br_if 0, $pop9 # 0: down to label5
+; CHECK-NEXT:  # %bb.1: # %hop
+; CHECK-NEXT:    local.get $push8=, 2
+; CHECK-NEXT:    local.set 4, $pop8
+; CHECK-NEXT:  .LBB5_2: # %end
+; CHECK-NEXT:    end_block # label5:
+; CHECK-NEXT:    local.get $push0=, 4
+; CHECK-NEXT:    return $pop0
+entry:
+  br i1 %cond, label %hop, label %end
+
+hop:
+  br label %end
+
+end:
+  %rval = phi double [0.0, %entry], [1.0, %hop]
+  ret double %rval
+}
+
+define ptr @phi_ptr(i1 %cond, ptr %p1, ptr %p2) {
+; WASM32-LABEL: phi_ptr:
+; WASM32:         .functype phi_ptr (i32, i32, i32) -> (i32)
+; WASM32-NEXT:    .local i32, i32
+; WASM32-NEXT:  # %bb.0: # %entry
+; WASM32-NEXT:    local.get $push3=, 0
+; WASM32-NEXT:    i32.const $push1=, 1
+; WASM32-NEXT:    i32.and $push2=, $pop3, $pop1
+; WASM32-NEXT:    local.set 3, $pop2
+; WASM32-NEXT:    local.get $push4=, 1
+; WASM32-NEXT:    local.set 4, $pop4
+; WASM32-NEXT:    block
+; WASM32-NEXT:    local.get $push5=, 3
+; WASM32-NEXT:    i32.eqz $push7=, $pop5
+; WASM32-NEXT:    br_if 0, $pop7 # 0: down to label6
+; WASM32-NEXT:  # %bb.1: # %hop
+; WASM32-NEXT:    local.get $push6=, 2
+; WASM32-NEXT:    local.set 4, $pop6
+; WASM32-NEXT:  .LBB6_2: # %end
+; WASM32-NEXT:    end_block # label6:
+; WASM32-NEXT:    local.get $push0=, 4
+; WASM32-NEXT:    return $pop0
+;
+; WASM64-LABEL: phi_ptr:
+; WASM64:         .functype phi_ptr (i32, i64, i64) -> (i64)
+; WASM64-NEXT:    .local i32, i64
+; WASM64-NEXT:  # %bb.0: # %entry
+; WASM64-NEXT:    local.get $push3=, 0
+; WASM64-NEXT:    i32.const $push1=, 1
+; WASM64-NEXT:    i32.and $push2=, $pop3, $pop1
+; WASM64-NEXT:    local.set 3, $pop2
+; WASM64-NEXT:    local.get $push4=, 1
+; WASM64-NEXT:    local.set 4, $pop4
+; WASM64-NEXT:    block
+; WASM64-NEXT:    local.get $push5=, 3
+; WASM64-NEXT:    i32.eqz $push7=, $pop5
+; WASM64-NEXT:    br_if 0, $pop7 # 0: down to label6
+; WASM64-NEXT:  # %bb.1: # %hop
+; WASM64-NEXT:    local.get $push6=, 2
+; WASM64-NEXT:    local.set 4, $pop6
+; WASM64-NEXT:  .LBB6_2: # %end
+; WASM64-NEXT:    end_block # label6:
+; WASM64-NEXT:    local.get $push0=, 4
+; WASM64-NEXT:    return $pop0
+entry:
+  br i1 %cond, label %hop, label %end
+
+hop:
+  br label %end
+
+end:
+  %rval = phi ptr [%p1, %entry], [%p2, %hop]
+  ret ptr %rval
+}

>From c53dfea3f341df04ec924b656e6383d4422a2385 Mon Sep 17 00:00:00 2001
From: Demetrius Kanios <demetrius at kanios.net>
Date: Wed, 26 Aug 2026 10:56:27 -0700
Subject: [PATCH 2/2] Remove extra newline from merge

---
 .../Target/WebAssembly/GISel/WebAssemblyInstructionSelector.cpp  | 1 -
 1 file changed, 1 deletion(-)

diff --git a/llvm/lib/Target/WebAssembly/GISel/WebAssemblyInstructionSelector.cpp b/llvm/lib/Target/WebAssembly/GISel/WebAssemblyInstructionSelector.cpp
index 03447031afce5..5f2f9498b1d77 100644
--- a/llvm/lib/Target/WebAssembly/GISel/WebAssemblyInstructionSelector.cpp
+++ b/llvm/lib/Target/WebAssembly/GISel/WebAssemblyInstructionSelector.cpp
@@ -329,7 +329,6 @@ bool WebAssemblyInstructionSelector::select(MachineInstr &I) {
   }
   default:
     break;
-
   }
 
   return false;



More information about the llvm-commits mailing list