[llvm] AMDGPU: Refactor checkVOPDRegConstraints (PR #196514)

Petar Avramovic via llvm-commits llvm-commits at lists.llvm.org
Thu Jul 16 01:46:45 PDT 2026


https://github.com/petar-avramovic updated https://github.com/llvm/llvm-project/pull/196514

>From e83e07be75bd10877b5c05c8bd03c5e3eab50345 Mon Sep 17 00:00:00 2001
From: Petar Avramovic <Petar.Avramovic at amd.com>
Date: Fri, 8 May 2026 12:16:25 +0200
Subject: [PATCH] AMDGPU: Refactor checkVOPDRegConstraints

---
 llvm/lib/Target/AMDGPU/GCNVOPDUtils.cpp | 69 ++++++++++---------------
 1 file changed, 28 insertions(+), 41 deletions(-)

diff --git a/llvm/lib/Target/AMDGPU/GCNVOPDUtils.cpp b/llvm/lib/Target/AMDGPU/GCNVOPDUtils.cpp
index 93069e71dffe1..44e467b0ba721 100644
--- a/llvm/lib/Target/AMDGPU/GCNVOPDUtils.cpp
+++ b/llvm/lib/Target/AMDGPU/GCNVOPDUtils.cpp
@@ -63,14 +63,6 @@ bool llvm::checkVOPDRegConstraints(const SIInstrInfo &TII,
   };
   SmallSet<Register, 4> UniqueScalarRegs;
 
-  auto getVRegIdx = [&](unsigned OpcodeIdx, unsigned OperandIdx) {
-    const MachineInstr &MI = (OpcodeIdx == VOPD::X) ? MIX : MIY;
-    const MachineOperand &Operand = MI.getOperand(OperandIdx);
-    if (Operand.isReg() && TRI->isVectorRegister(MRI, Operand.getReg()))
-      return Operand.getReg();
-    return Register();
-  };
-
   auto InstInfo = AMDGPU::getVOPDInstInfo(MIX.getDesc(), MIY.getDesc());
 
   for (auto CompIdx : VOPD::COMPONENTS) {
@@ -87,33 +79,36 @@ bool llvm::checkVOPDRegConstraints(const SIInstrInfo &TII,
       addLiteral(Src0);
     }
 
+    // V_FMAMK_F32 (src1) and V_FMAAK_F32 (src2) have a mandatory literal.
+    // VOPD3 instructions don't set MandatoryLiteralIdx.
     if (InstInfo[CompIdx].hasMandatoryLiteral()) {
-      if (IsVOPD3)
-        return false;
-
       auto CompOprIdx = InstInfo[CompIdx].getMandatoryLiteralCompOperandIndex();
       addLiteral(MI.getOperand(CompOprIdx));
     }
+
+    // VOPD only. Affects V_CNDMASK_B32_e32.
     if (MI.getDesc().hasImplicitUseOfPhysReg(AMDGPU::VCC))
       UniqueScalarRegs.insert(AMDGPU::VCC_LO);
 
     if (IsVOPD3) {
-      for (auto OpName : {AMDGPU::OpName::src1, AMDGPU::OpName::src2}) {
-        const MachineOperand *Src = TII.getNamedOperand(MI, OpName);
-        if (!Src)
-          continue;
-        if (OpName == AMDGPU::OpName::src2) {
-          if (AMDGPU::hasNamedOperand(MI.getOpcode(), AMDGPU::OpName::bitop3))
-            continue;
-          if (MI.getOpcode() == AMDGPU::V_CNDMASK_B32_e64) {
-            UniqueScalarRegs.insert(Src->getReg());
-            continue;
-          }
-        }
-        if (!Src->isReg() || !TRI->isVGPR(MRI, Src->getReg()))
+      if (const MachineOperand *Src1 =
+              TII.getNamedOperand(MI, AMDGPU::OpName::src1)) {
+        if (!Src1->isReg() || !TRI->isVGPR(MRI, Src1->getReg()))
           return false;
       }
 
+      if (const MachineOperand *Src2 =
+              TII.getNamedOperand(MI, AMDGPU::OpName::src2)) {
+        if (AMDGPU::hasNamedOperand(MI.getOpcode(), AMDGPU::OpName::bitop3)) {
+          // BITOP3 can be converted to DUAL_BITOP2 when src2 is zero.
+          if (!Src2->isImm() || Src2->getImm())
+            return false;
+        } else if (MI.getOpcode() == AMDGPU::V_CNDMASK_B32_e64) {
+          UniqueScalarRegs.insert(Src2->getReg());
+        } else if (!Src2->isReg() || !TRI->isVGPR(MRI, Src2->getReg())) {
+          return false;
+        }
+      }
       for (auto OpName : {AMDGPU::OpName::clamp, AMDGPU::OpName::omod,
                           AMDGPU::OpName::op_sel}) {
         if (TII.hasModifiersSet(MI, OpName))
@@ -137,33 +132,25 @@ bool llvm::checkVOPDRegConstraints(const SIInstrInfo &TII,
   if ((UniqueLiterals.size() + UniqueScalarRegs.size()) > 2)
     return false;
 
+  auto getVRegIdx = [&](unsigned OpcodeIdx, unsigned OperandIdx) {
+    const MachineInstr &MI = (OpcodeIdx == VOPD::X) ? MIX : MIY;
+    const MachineOperand &Operand = MI.getOperand(OperandIdx);
+    if (Operand.isReg() && TRI->isVectorRegister(MRI, Operand.getReg()))
+      return Operand.getReg();
+    return Register();
+  };
+
   // On GFX1170+ if both OpX and OpY are V_MOV_B32 then OPY uses SRC2
   // source-cache.
   bool SkipSrc = (ST.hasGFX11_7Insts() || ST.hasGFX12Insts()) &&
                  MIX.getOpcode() == AMDGPU::V_MOV_B32_e32 &&
                  MIY.getOpcode() == AMDGPU::V_MOV_B32_e32;
 
+  // Check VGPR bank constraints for operand registers across both instructions.
   if (InstInfo.hasInvalidOperand(getVRegIdx, *TRI, SkipSrc, AllowSameVGPR,
                                  IsVOPD3))
     return false;
 
-  if (IsVOPD3) {
-    // BITOP3 can be converted to DUAL_BITOP2 only if src2 is zero.
-    // MIX check is only relevant to scheduling?
-    if (AMDGPU::hasNamedOperand(MIX.getOpcode(), AMDGPU::OpName::bitop3)) {
-      const MachineOperand &Src2 =
-          *TII.getNamedOperand(MIX, AMDGPU::OpName::src2);
-      if (!Src2.isImm() || Src2.getImm())
-        return false;
-    }
-    if (AMDGPU::hasNamedOperand(MIY.getOpcode(), AMDGPU::OpName::bitop3)) {
-      const MachineOperand &Src2 =
-          *TII.getNamedOperand(MIY, AMDGPU::OpName::src2);
-      if (!Src2.isImm() || Src2.getImm())
-        return false;
-    }
-  }
-
   LLVM_DEBUG(dbgs() << "VOPD Reg Constraints Passed\n\tX: " << MIX
                     << "\n\tY: " << MIY << "\n");
   return true;



More information about the llvm-commits mailing list