[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