[llvm] PHIElimination: add target hook to control reuse. (PR #163604)

Junjie Gu via llvm-commits llvm-commits at lists.llvm.org
Tue Oct 28 16:23:18 PDT 2025


https://github.com/jgu222 updated https://github.com/llvm/llvm-project/pull/163604

>From a4bb8a115fb461eee6f4de9167daf39b7ef718ad 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 175f205328361..041958b7a3649 100644
--- a/llvm/include/llvm/CodeGen/TargetInstrInfo.h
+++ b/llvm/include/llvm/CodeGen/TargetInstrInfo.h
@@ -2158,7 +2158,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(
@@ -2168,7 +2168,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,
@@ -2180,6 +2180,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 9ead58d5685f398c56c51e24c89e16dd1efe046a 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 ++++++++++++-
 2 files changed, 14 insertions(+), 14 deletions(-)

diff --git a/llvm/include/llvm/CodeGen/TargetInstrInfo.h b/llvm/include/llvm/CodeGen/TargetInstrInfo.h
index 041958b7a3649..175f205328361 100644
--- a/llvm/include/llvm/CodeGen/TargetInstrInfo.h
+++ b/llvm/include/llvm/CodeGen/TargetInstrInfo.h
@@ -2158,7 +2158,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(
@@ -2168,7 +2168,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,
@@ -2180,17 +2180,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;



More information about the llvm-commits mailing list