[llvm] PHIElimination: add target hook to control reuse. (PR #163604)
Junjie Gu via llvm-commits
llvm-commits at lists.llvm.org
Sat Nov 8 11:10:02 PST 2025
https://github.com/jgu222 updated https://github.com/llvm/llvm-project/pull/163604
>From 9190ad134078fb612b163b25e71323449aaab0b0 Mon Sep 17 00:00:00 2001
From: "Gu, Junjie" <junjie.gu at intel.com>
Date: Wed, 15 Oct 2025 10:42:31 -0700
Subject: [PATCH 1/2] PHIElimination: add target hook to control reuse.
Add PHI reuse hook so that a target can decide if temporary register
during PHI node elimination can be reused. By default, two phis are
allowed to use the same temporary register if their right-hand-sides
are the same.
However, the left-hand sides of phis need to be checked as well
for some targets, such as a GPU target. If the register banks of
phis's left-hand sides are diffrerent, reuse is not allowed.
Thus, this change adds a target hook for this kind of checking
as it is target-dependent.
This change has no functional change.
This is to resolve the issue:
https://github.com/llvm/llvm-project/issues/163500
---
llvm/include/llvm/CodeGen/TargetInstrInfo.h | 15 +++++++++++++--
llvm/lib/CodeGen/PHIElimination.cpp | 2 +-
2 files changed, 14 insertions(+), 3 deletions(-)
diff --git a/llvm/include/llvm/CodeGen/TargetInstrInfo.h b/llvm/include/llvm/CodeGen/TargetInstrInfo.h
index 2dcedfb40f3e6..da944d0bd05ca 100644
--- a/llvm/include/llvm/CodeGen/TargetInstrInfo.h
+++ b/llvm/include/llvm/CodeGen/TargetInstrInfo.h
@@ -2169,7 +2169,7 @@ class LLVM_ABI TargetInstrInfo : public MCInstrInfo {
return TargetOpcode::COPY;
}
- /// During PHI eleimination lets target to make necessary checks and
+ /// During PHI elimination lets target to make necessary checks and
/// insert the copy to the PHI destination register in a target specific
/// manner.
virtual MachineInstr *createPHIDestinationCopy(
@@ -2179,7 +2179,7 @@ class LLVM_ABI TargetInstrInfo : public MCInstrInfo {
.addReg(Src);
}
- /// During PHI eleimination lets target to make necessary checks and
+ /// During PHI elimination lets target to make necessary checks and
/// insert the copy to the PHI destination register in a target specific
/// manner.
virtual MachineInstr *createPHISourceCopy(MachineBasicBlock &MBB,
@@ -2191,6 +2191,17 @@ class LLVM_ABI TargetInstrInfo : public MCInstrInfo {
.addReg(Src, 0, SrcSubReg);
}
+ /// During PHI elimination lets target to decide if two phis can use the
+ /// same register \p Reg when they have the same rhs. Register \p Reg has
+ /// been used for the first phi and \p PHIReg is the DestReg of the second
+ /// Phi. This function is to check if the second phi can reuse \p Reg as
+ /// its temporary register.
+ /// The default is to allow reuse.
+ virtual bool allowPHIReuse(Register Reg, Register PHIReg,
+ const MachineFunction &MF) const {
+ return true;
+ }
+
/// Returns a \p outliner::OutlinedFunction struct containing target-specific
/// information for a set of outlining candidates. Returns std::nullopt if the
/// candidates are not suitable for outlining. \p MinRepeats is the minimum
diff --git a/llvm/lib/CodeGen/PHIElimination.cpp b/llvm/lib/CodeGen/PHIElimination.cpp
index 34a9d5d0e401f..fc2ecb9317bc4 100644
--- a/llvm/lib/CodeGen/PHIElimination.cpp
+++ b/llvm/lib/CodeGen/PHIElimination.cpp
@@ -380,7 +380,7 @@ void PHIEliminationImpl::LowerPHINode(MachineBasicBlock &MBB,
Register *Entry = nullptr;
if (AllEdgesCritical)
Entry = &LoweredPHIs[MPhi];
- if (Entry && *Entry) {
+ if (Entry && *Entry && TII->allowPHIReuse(*Entry, DestReg, MF)) {
// An identical PHI node was already lowered. Reuse the incoming register.
IncomingReg = *Entry;
reusedIncoming = true;
>From 1e9ba4c9f6b99c35710e9a1299cba8480d277575 Mon Sep 17 00:00:00 2001
From: "Gu, Junjie" <junjie.gu at intel.com>
Date: Sun, 26 Oct 2025 12:50:34 -0700
Subject: [PATCH 2/2] Use common register class
Remove target hook. Instead, use common register class to
check if two phis are allowed to reuse the same temp.
---
llvm/include/llvm/CodeGen/TargetInstrInfo.h | 15 +------
llvm/lib/CodeGen/PHIElimination.cpp | 13 +++++-
.../AMDGPU/phi-elimination-reuse-pr163604.mir | 42 +++++++++++++++++++
3 files changed, 56 insertions(+), 14 deletions(-)
create mode 100644 llvm/test/CodeGen/AMDGPU/phi-elimination-reuse-pr163604.mir
diff --git a/llvm/include/llvm/CodeGen/TargetInstrInfo.h b/llvm/include/llvm/CodeGen/TargetInstrInfo.h
index da944d0bd05ca..2dcedfb40f3e6 100644
--- a/llvm/include/llvm/CodeGen/TargetInstrInfo.h
+++ b/llvm/include/llvm/CodeGen/TargetInstrInfo.h
@@ -2169,7 +2169,7 @@ class LLVM_ABI TargetInstrInfo : public MCInstrInfo {
return TargetOpcode::COPY;
}
- /// During PHI elimination lets target to make necessary checks and
+ /// During PHI eleimination lets target to make necessary checks and
/// insert the copy to the PHI destination register in a target specific
/// manner.
virtual MachineInstr *createPHIDestinationCopy(
@@ -2179,7 +2179,7 @@ class LLVM_ABI TargetInstrInfo : public MCInstrInfo {
.addReg(Src);
}
- /// During PHI elimination lets target to make necessary checks and
+ /// During PHI eleimination lets target to make necessary checks and
/// insert the copy to the PHI destination register in a target specific
/// manner.
virtual MachineInstr *createPHISourceCopy(MachineBasicBlock &MBB,
@@ -2191,17 +2191,6 @@ class LLVM_ABI TargetInstrInfo : public MCInstrInfo {
.addReg(Src, 0, SrcSubReg);
}
- /// During PHI elimination lets target to decide if two phis can use the
- /// same register \p Reg when they have the same rhs. Register \p Reg has
- /// been used for the first phi and \p PHIReg is the DestReg of the second
- /// Phi. This function is to check if the second phi can reuse \p Reg as
- /// its temporary register.
- /// The default is to allow reuse.
- virtual bool allowPHIReuse(Register Reg, Register PHIReg,
- const MachineFunction &MF) const {
- return true;
- }
-
/// Returns a \p outliner::OutlinedFunction struct containing target-specific
/// information for a set of outlining candidates. Returns std::nullopt if the
/// candidates are not suitable for outlining. \p MinRepeats is the minimum
diff --git a/llvm/lib/CodeGen/PHIElimination.cpp b/llvm/lib/CodeGen/PHIElimination.cpp
index fc2ecb9317bc4..41c2a576dc76a 100644
--- a/llvm/lib/CodeGen/PHIElimination.cpp
+++ b/llvm/lib/CodeGen/PHIElimination.cpp
@@ -377,10 +377,21 @@ void PHIEliminationImpl::LowerPHINode(MachineBasicBlock &MBB,
// typically those created by tail duplication. Typically, an identical PHI
// node can't occur, so avoid hashing/storing such PHIs, which is somewhat
// expensive.
+
+ // canReuse() checks if two phis of the same rhs have the common sub class
+ // for their lhs's and allow reuse if so. (useful for some GPU targets)
+ auto canReuse = [](Register Reg0, Register Reg1, MachineFunction &MF) {
+ auto &MRI = MF.getRegInfo();
+ auto *RC0 = MRI.getRegClass(Reg0);
+ auto *RC1 = MRI.getRegClass(Reg1);
+ return MF.getSubtarget().getRegisterInfo()->getCommonSubClass(RC0, RC1) !=
+ nullptr;
+ };
+
Register *Entry = nullptr;
if (AllEdgesCritical)
Entry = &LoweredPHIs[MPhi];
- if (Entry && *Entry && TII->allowPHIReuse(*Entry, DestReg, MF)) {
+ if (Entry && *Entry && canReuse(*Entry, DestReg, MF)) {
// An identical PHI node was already lowered. Reuse the incoming register.
IncomingReg = *Entry;
reusedIncoming = true;
diff --git a/llvm/test/CodeGen/AMDGPU/phi-elimination-reuse-pr163604.mir b/llvm/test/CodeGen/AMDGPU/phi-elimination-reuse-pr163604.mir
new file mode 100644
index 0000000000000..9cb5032eaac7c
--- /dev/null
+++ b/llvm/test/CodeGen/AMDGPU/phi-elimination-reuse-pr163604.mir
@@ -0,0 +1,42 @@
+# RUN: llc -mtriple amdgcn -run-pass phi-node-elimination -o - %s | FileCheck %s
+
+---
+# The test is to make sure that two phis, with the same right-hand-site but different
+# register classes for their left-hand-sites, are not doing phi reuse optimization.
+# Not sure whether this test makes any sense for the AMDGPU target, but it is a valid
+# case for aother GPU target that is not in LLVM trunk yet. Thus, this test uses the
+# ADMGPU target as a proof of concept.
+
+# Because of no reuse for the two phis, there are two temps: CP0 and CP1
+# They are translated to:
+# phi1 (%1:sreg_32) = CP0
+# phi2 (%4:vgpr_32) = CP1
+#
+# CHECK-LABEL: check-phi-reuse
+# CHECK-LABEL: bb.1:
+# CHECK: %1:sreg_32 = COPY %[[#CP0:]]
+# CHECK: %[[#CP0]]:sreg_32 = COPY {{.+}}
+# CHECK: %[[#CP1:]]:vgpr_32 = COPY {{.+}}
+# CHECK-LABEL: bb.2:
+# CHECK: %4:vgpr_32 = COPY %[[#CP1]]
+
+
+
+name: check-phi-reuse
+tracksRegLiveness: true
+body: |
+ bb.0:
+ %1:sreg_32 = S_MOV_B32 255
+ S_CBRANCH_SCC0 %bb.2, implicit undef $scc
+
+ bb.1:
+ %3:sreg_32 = PHI %4, %bb.1, %1, %bb.0
+ %2:sreg_32 = S_ADD_I32 %3, 1, implicit-def $scc
+ %4:vgpr_32 = COPY %2
+ S_CBRANCH_SCC0 %bb.1, implicit killed $scc
+ S_BRANCH %bb.2
+
+ bb.2:
+ %5:vgpr_32 = PHI %4, %bb.1, %1, %bb.0
+...
+
More information about the llvm-commits
mailing list