[llvm] GlobalISel: Use MIPatternMatch to look up defs in the artifact combiner (PR #216358)

Matt Arsenault via llvm-commits llvm-commits at lists.llvm.org
Fri Aug 14 09:59:55 PDT 2026


https://github.com/arsenm created https://github.com/llvm/llvm-project/pull/216358

Replace direct getVRegDef uses in the legalization artifact combiner with
the mi_match/m_MInstr idiom. To avoid awkwardly split handling of G_IMPLICIT_DEF,
add a similar matcher for G_CONSTANT.

Co-authored-by: Claude (Opus 4.8) <noreply at anthropic.com>

>From 989823351491be88d3b35000292b85006db6a10f Mon Sep 17 00:00:00 2001
From: Matt Arsenault <Matthew.Arsenault at amd.com>
Date: Fri, 14 Aug 2026 17:51:58 +0200
Subject: [PATCH] GlobalISel: Use MIPatternMatch to look up defs in the
 artifact combiner

Replace direct getVRegDef uses in the legalization artifact combiner with
the mi_match/m_MInstr idiom. To avoid awkwardly split handling of G_IMPLICIT_DEF,
add a similar matcher for G_CONSTANT.

Co-authored-by: Claude (Opus 4.8) <noreply at anthropic.com>
---
 .../CodeGen/GlobalISel/GenericMachineInstrs.h | 11 ++++
 .../GlobalISel/LegalizationArtifactCombiner.h | 57 +++++++++----------
 .../llvm/CodeGen/GlobalISel/MIPatternMatch.h  | 24 ++++++++
 3 files changed, 62 insertions(+), 30 deletions(-)

diff --git a/llvm/include/llvm/CodeGen/GlobalISel/GenericMachineInstrs.h b/llvm/include/llvm/CodeGen/GlobalISel/GenericMachineInstrs.h
index 3be9d31bc57c9..6daa7f3808f43 100644
--- a/llvm/include/llvm/CodeGen/GlobalISel/GenericMachineInstrs.h
+++ b/llvm/include/llvm/CodeGen/GlobalISel/GenericMachineInstrs.h
@@ -978,6 +978,17 @@ class GStepVector : public GenericMachineInstr {
   };
 };
 
+/// Represents a G_CONSTANT.
+class GConstant : public GenericMachineInstr {
+public:
+  const ConstantInt *getConstantInt() const { return getOperand(1).getCImm(); }
+  const APInt &getValue() const { return getConstantInt()->getValue(); }
+
+  static bool classof(const MachineInstr *MI) {
+    return MI->getOpcode() == TargetOpcode::G_CONSTANT;
+  };
+};
+
 /// Represents an integer subtraction.
 class GSub : public GIntBinOp {
 public:
diff --git a/llvm/include/llvm/CodeGen/GlobalISel/LegalizationArtifactCombiner.h b/llvm/include/llvm/CodeGen/GlobalISel/LegalizationArtifactCombiner.h
index 08e567f2e640a..dca2babbe112b 100644
--- a/llvm/include/llvm/CodeGen/GlobalISel/LegalizationArtifactCombiner.h
+++ b/llvm/include/llvm/CodeGen/GlobalISel/LegalizationArtifactCombiner.h
@@ -95,20 +95,19 @@ class LegalizationArtifactCombiner {
     }
 
     // Try to fold aext(g_constant) when the larger constant type is legal.
-    auto *SrcMI = MRI.getVRegDef(SrcReg);
-    if (SrcMI->getOpcode() == TargetOpcode::G_CONSTANT) {
+    GConstant *SrcCst;
+    if (mi_match(SrcReg, MRI, m_GConstant(SrcCst))) {
       const LLT DstTy = MRI.getType(DstReg);
       if (isInstLegal({TargetOpcode::G_CONSTANT, {DstTy}})) {
-        auto &CstVal = SrcMI->getOperand(1);
-        auto MergedLocation =
-            DebugLoc::getMergedLocation(MI.getDebugLoc(), SrcMI->getDebugLoc());
-        // Set the debug location to the merged location of the SrcMI and the MI
-        // if the aext fold is successful.
+        auto MergedLocation = DebugLoc::getMergedLocation(
+            MI.getDebugLoc(), SrcCst->getDebugLoc());
+        // Set the debug location to the merged location of the SrcCst and the
+        // MI if the aext fold is successful.
         Builder.setDebugLoc(MergedLocation);
-        Builder.buildConstant(
-            DstReg, CstVal.getCImm()->getValue().sext(DstTy.getSizeInBits()));
+        Builder.buildConstant(DstReg,
+                              SrcCst->getValue().sext(DstTy.getSizeInBits()));
         UpdatedDefs.push_back(DstReg);
-        markInstAndDefDead(MI, *SrcMI, DeadInsts);
+        markInstAndDefDead(MI, *SrcCst, DeadInsts);
         return true;
       }
     }
@@ -175,15 +174,14 @@ class LegalizationArtifactCombiner {
     }
 
     // Try to fold zext(g_constant) when the larger constant type is legal.
-    auto *SrcMI = MRI.getVRegDef(SrcReg);
-    if (SrcMI->getOpcode() == TargetOpcode::G_CONSTANT) {
+    GConstant *SrcCst;
+    if (mi_match(SrcReg, MRI, m_GConstant(SrcCst))) {
       const LLT DstTy = MRI.getType(DstReg);
       if (isInstLegal({TargetOpcode::G_CONSTANT, {DstTy}})) {
-        auto &CstVal = SrcMI->getOperand(1);
-        Builder.buildConstant(
-            DstReg, CstVal.getCImm()->getValue().zext(DstTy.getSizeInBits()));
+        Builder.buildConstant(DstReg,
+                              SrcCst->getValue().zext(DstTy.getSizeInBits()));
         UpdatedDefs.push_back(DstReg);
-        markInstAndDefDead(MI, *SrcMI, DeadInsts);
+        markInstAndDefDead(MI, *SrcCst, DeadInsts);
         return true;
       }
     }
@@ -242,15 +240,14 @@ class LegalizationArtifactCombiner {
     }
 
     // Try to fold sext(g_constant) when the larger constant type is legal.
-    auto *SrcMI = MRI.getVRegDef(SrcReg);
-    if (SrcMI->getOpcode() == TargetOpcode::G_CONSTANT) {
+    GConstant *SrcCst;
+    if (mi_match(SrcReg, MRI, m_GConstant(SrcCst))) {
       const LLT DstTy = MRI.getType(DstReg);
       if (isInstLegal({TargetOpcode::G_CONSTANT, {DstTy}})) {
-        auto &CstVal = SrcMI->getOperand(1);
-        Builder.buildConstant(
-            DstReg, CstVal.getCImm()->getValue().sext(DstTy.getSizeInBits()));
+        Builder.buildConstant(DstReg,
+                              SrcCst->getValue().sext(DstTy.getSizeInBits()));
         UpdatedDefs.push_back(DstReg);
-        markInstAndDefDead(MI, *SrcMI, DeadInsts);
+        markInstAndDefDead(MI, *SrcCst, DeadInsts);
         return true;
       }
     }
@@ -271,20 +268,20 @@ class LegalizationArtifactCombiner {
     Register SrcReg = lookThroughCopyInstrs(MI.getOperand(1).getReg());
 
     // Try to fold trunc(g_constant) when the smaller constant type is legal.
-    auto *SrcMI = MRI.getVRegDef(SrcReg);
-    if (SrcMI->getOpcode() == TargetOpcode::G_CONSTANT) {
+    GConstant *SrcCst;
+    if (mi_match(SrcReg, MRI, m_GConstant(SrcCst))) {
       if (isInstLegal({TargetOpcode::G_CONSTANT, {DstTy}})) {
-        auto &CstVal = SrcMI->getOperand(1);
-        Builder.buildConstant(
-            DstReg, CstVal.getCImm()->getValue().trunc(DstTy.getSizeInBits()));
+        Builder.buildConstant(DstReg,
+                              SrcCst->getValue().trunc(DstTy.getSizeInBits()));
         UpdatedDefs.push_back(DstReg);
-        markInstAndDefDead(MI, *SrcMI, DeadInsts);
+        markInstAndDefDead(MI, *SrcCst, DeadInsts);
         return true;
       }
     }
 
     // Try to fold trunc(merge) to directly use the source of the merge.
     // This gets rid of large, difficult to legalize, merges
+    MachineInstr *SrcMI = MRI.getVRegDef(SrcReg);
     if (auto *SrcMerge = dyn_cast<GMerge>(SrcMI)) {
       const Register MergeSrcReg = SrcMerge->getSourceReg(0);
       const LLT MergeSrcTy = MRI.getType(MergeSrcReg);
@@ -964,6 +961,7 @@ class LegalizationArtifactCombiner {
                                GUnmerge *Unmerge, unsigned UnmergeIdxStart,
                                unsigned NumElts, unsigned EltSize,
                                bool AllowUndef) {
+      using namespace llvm::MIPatternMatch;
       assert(MergeStartIdx + NumElts <= MI.getNumSources());
       for (unsigned i = MergeStartIdx; i < MergeStartIdx + NumElts; ++i) {
         unsigned EltUnmergeIdx;
@@ -975,8 +973,7 @@ class LegalizationArtifactCombiner {
           if (i - MergeStartIdx != EltUnmergeIdx - UnmergeIdxStart)
             return false;
         } else if (!AllowUndef ||
-                   MRI.getVRegDef(MI.getSourceReg(i))->getOpcode() !=
-                       TargetOpcode::G_IMPLICIT_DEF)
+                   !mi_match(MI.getSourceReg(i), MRI, m_GImplicitDef()))
           return false;
       }
       return true;
diff --git a/llvm/include/llvm/CodeGen/GlobalISel/MIPatternMatch.h b/llvm/include/llvm/CodeGen/GlobalISel/MIPatternMatch.h
index db1f4a89d3469..5353d8dbb7bcd 100644
--- a/llvm/include/llvm/CodeGen/GlobalISel/MIPatternMatch.h
+++ b/llvm/include/llvm/CodeGen/GlobalISel/MIPatternMatch.h
@@ -471,6 +471,30 @@ struct ImplicitDefMatch {
 
 inline ImplicitDefMatch m_GImplicitDef() { return ImplicitDefMatch(); }
 
+/// Matches a G_CONSTANT and binds the defining instruction. Unlike m_ICst, this
+/// returns the instruction (not the value) and does not look through vector
+/// splats.
+template <typename Class> struct GConstantMatch {
+  Class *&Inst;
+
+  GConstantMatch(Class *&Inst) : Inst(Inst) {}
+  bool match(const MachineRegisterInfo &MRI, Register Reg) {
+    MachineInstr *TmpMI;
+    if (mi_match(Reg, MRI, m_MInstr(TmpMI))) {
+      if (auto *Cst = dyn_cast<Class>(TmpMI)) {
+        Inst = Cst;
+        return true;
+      }
+    }
+    return false;
+  }
+};
+
+inline GConstantMatch<GConstant> m_GConstant(GConstant *&Inst) { return Inst; }
+inline GConstantMatch<const GConstant> m_GConstant(const GConstant *&Inst) {
+  return Inst;
+}
+
 // Helper for matching G_FCONSTANT
 inline bind_ty<const ConstantFP *> m_GFCst(const ConstantFP *&C) { return C; }
 



More information about the llvm-commits mailing list