[llvm-branch-commits] [llvm] [AMDGPU] Decouple isVOP3P/isVINTERP from isVOP3 (#223448) (PR #223784)

Valery Pykhtin via llvm-branch-commits llvm-branch-commits at lists.llvm.org
Thu Sep 17 02:05:51 PDT 2026


https://github.com/vpykhtin updated https://github.com/llvm/llvm-project/pull/223784

>From 7d61d88db6411af7a3592ab63e1508fd011e3d17 Mon Sep 17 00:00:00 2001
From: Valery Pykhtin <valery.pykhtin at amd.com>
Date: Tue, 15 Sep 2026 13:23:35 +0000
Subject: [PATCH] [AMDGPU] Decouple isVOP3P/isVINTERP from isVOP3 (#223448)

VOP3P and VINTERP instructions also set the VOP3 TSFlags bit, so isVOP3()
returned true for them. This overloaded isVOP3() to mean both "the VOP3
encoding" and "uses VOP3-style operand rules" (modifiers, constant bus,
literal legality).

Make VOP3P and VINTERP their own instruction-format enum values so
isVOP3() is strict (Format == VOP3). Callers that need "any VOP3-family
operand encoding" now use isVOP3Like() (VOP3 | VOP3P | VINTERP), added as
a SIInstrInfo wrapper. Redundant "isVOP3() && !isVOP3P()" tests are
simplified to isVOP3().

Resolves llvm/llvm-project#223448.

Co-Authored-By: Claude <noreply at anthropic.com>
---
 .../AMDGPU/AsmParser/AMDGPUAsmParser.cpp      | 11 +++---
 llvm/lib/Target/AMDGPU/GCNCreateVOPD.cpp      |  2 +-
 llvm/lib/Target/AMDGPU/GCNDPPCombine.cpp      |  2 +-
 llvm/lib/Target/AMDGPU/GCNVOPDUtils.cpp       |  4 +--
 .../AMDGPU/MCTargetDesc/AMDGPUInstPrinter.cpp |  4 +--
 llvm/lib/Target/AMDGPU/SIDefines.h            | 25 +++++++------
 llvm/lib/Target/AMDGPU/SIFoldOperands.cpp     |  2 +-
 llvm/lib/Target/AMDGPU/SIISelLowering.cpp     |  2 +-
 llvm/lib/Target/AMDGPU/SIInstrFormats.td      | 36 ++++++++++---------
 llvm/lib/Target/AMDGPU/SIInstrInfo.cpp        | 13 +++----
 .../Target/AMDGPU/Utils/AMDGPUBaseInfo.cpp    |  4 +--
 11 files changed, 53 insertions(+), 52 deletions(-)

diff --git a/llvm/lib/Target/AMDGPU/AsmParser/AMDGPUAsmParser.cpp b/llvm/lib/Target/AMDGPU/AsmParser/AMDGPUAsmParser.cpp
index 15560e0758a19..acc6b3d22231d 100644
--- a/llvm/lib/Target/AMDGPU/AsmParser/AMDGPUAsmParser.cpp
+++ b/llvm/lib/Target/AMDGPU/AsmParser/AMDGPUAsmParser.cpp
@@ -3686,8 +3686,8 @@ ParseStatus AMDGPUAsmParser::parseVReg32OrOff(OperandVector &Operands) {
 }
 
 unsigned AMDGPUAsmParser::checkTargetMatchPredicate(MCInst &Inst) {
-  if ((getForcedEncodingSize() == 32 && SIInstrFlags::isVOP3(MII, Inst)) ||
-      (getForcedEncodingSize() == 64 && !SIInstrFlags::isVOP3(MII, Inst)) ||
+  if ((getForcedEncodingSize() == 32 && SIInstrFlags::isVOP3Like(MII, Inst)) ||
+      (getForcedEncodingSize() == 64 && !SIInstrFlags::isVOP3Like(MII, Inst)) ||
       (isForcedDPP() && !SIInstrFlags::isDPP(MII, Inst)) ||
       (isForcedSDWA() && !SIInstrFlags::isSDWA(MII, Inst)))
     return Match_InvalidOperand;
@@ -4904,8 +4904,7 @@ bool AMDGPUAsmParser::validateBF16InlineConst(const MCInst &Inst,
 
   const unsigned Opc = Inst.getOpcode();
   const MCInstrDesc &Desc = MII.get(Opc);
-  const bool IsVOP3 =
-      SIInstrFlags::isVOP3(Desc) && !SIInstrFlags::isVOP3P(Desc);
+  const bool IsVOP3 = SIInstrFlags::isVOP3(Desc);
   if (!SIInstrFlags::isVOP1(Desc) && !IsVOP3)
     return true;
 
@@ -5025,7 +5024,7 @@ bool AMDGPUAsmParser::validateOpSel(const MCInst &Inst) {
 
   // op_sel[0:1] must be 0 for v_dot2_bf16_bf16 and v_dot2_f16_f16 (VOP3 Dot).
   if (isGFX11Plus() && SIInstrFlags::isDOT(MII, Inst) &&
-      SIInstrFlags::isVOP3(MII, Inst) && !SIInstrFlags::isVOP3P(MII, Inst)) {
+      SIInstrFlags::isVOP3(MII, Inst)) {
     int OpSelIdx = AMDGPU::getNamedOperandIdx(Opc, AMDGPU::OpName::op_sel);
     unsigned OpSel = Inst.getOperand(OpSelIdx).getImm();
     if (OpSel & 3)
@@ -10634,7 +10633,7 @@ void AMDGPUAsmParser::cvtVOP3DPP(MCInst &Inst, const OperandVector &Operands,
 
   if (SIInstrFlags::isVOP3P(Desc))
     cvtVOP3P(Inst, Operands, OptionalIdx);
-  else if (SIInstrFlags::isVOP3(Desc))
+  else if (SIInstrFlags::isVOP3Like(Desc))
     cvtVOP3OpSel(Inst, Operands, OptionalIdx);
   else if (AMDGPU::hasNamedOperand(Opc, AMDGPU::OpName::op_sel)) {
     addOptionalImmOperand(Inst, Operands, OptionalIdx,
diff --git a/llvm/lib/Target/AMDGPU/GCNCreateVOPD.cpp b/llvm/lib/Target/AMDGPU/GCNCreateVOPD.cpp
index 2ca4fa50f7f29..fce58f58ac35d 100644
--- a/llvm/lib/Target/AMDGPU/GCNCreateVOPD.cpp
+++ b/llvm/lib/Target/AMDGPU/GCNCreateVOPD.cpp
@@ -262,7 +262,7 @@ class GCNCreateVOPD {
 
     for (auto CompIdx : VOPD::COMPONENTS) {
       auto CompSrcOprNum = InstInfo[CompIdx].getCompSrcOperandsNum();
-      bool IsVOP3 = SII->isVOP3(*MI[CompIdx]);
+      bool IsVOP3 = SIInstrFlags::isVOP3Like(*MI[CompIdx]);
       for (unsigned CompSrcIdx = 0; CompSrcIdx < CompSrcOprNum; ++CompSrcIdx) {
         if (AMDGPU::hasNamedOperand(VOPDOpc, Mods[CompIdx][CompSrcIdx])) {
           const MachineOperand *Mod =
diff --git a/llvm/lib/Target/AMDGPU/GCNDPPCombine.cpp b/llvm/lib/Target/AMDGPU/GCNDPPCombine.cpp
index 4fb9abb707040..52917d198eb1a 100644
--- a/llvm/lib/Target/AMDGPU/GCNDPPCombine.cpp
+++ b/llvm/lib/Target/AMDGPU/GCNDPPCombine.cpp
@@ -363,7 +363,7 @@ MachineInstr *GCNDPPCombine::createDPPInst(MachineInstr &OrigMI,
         OpSel |= (Mod0 ? (!!(Mod0->getImm() & SISrcMods::OP_SEL_0) << 0) : 0);
         OpSel |= (Mod1 ? (!!(Mod1->getImm() & SISrcMods::OP_SEL_0) << 1) : 0);
         OpSel |= (Mod2 ? (!!(Mod2->getImm() & SISrcMods::OP_SEL_0) << 2) : 0);
-        if (Mod0 && TII->isVOP3(OrigMI) && !TII->isVOP3P(OrigMI))
+        if (Mod0 && TII->isVOP3(OrigMI))
           OpSel |= !!(Mod0->getImm() & SISrcMods::DST_OP_SEL) << 3;
 
         if (OpSel != 0) {
diff --git a/llvm/lib/Target/AMDGPU/GCNVOPDUtils.cpp b/llvm/lib/Target/AMDGPU/GCNVOPDUtils.cpp
index 63b28bf4ad645..3f1d3969672b2 100644
--- a/llvm/lib/Target/AMDGPU/GCNVOPDUtils.cpp
+++ b/llvm/lib/Target/AMDGPU/GCNVOPDUtils.cpp
@@ -124,8 +124,8 @@ checkVOPDRegConstraints(const SIInstrInfo &TII, const MachineInstr &MIX,
 
   if (IsVOPD3 && !ST.hasVOPD3())
     return false;
-  if (!IsVOPD3 && ((TII.isVOP3(MIX) && !canMapVOP3PToVOPD(MIX)) ||
-                   (TII.isVOP3(MIY) && !canMapVOP3PToVOPD(MIY))))
+  if (!IsVOPD3 && ((SIInstrFlags::isVOP3Like(MIX) && !canMapVOP3PToVOPD(MIX)) ||
+                   (SIInstrFlags::isVOP3Like(MIY) && !canMapVOP3PToVOPD(MIY))))
     return false;
   if (TII.isDPP(MIX) || TII.isDPP(MIY))
     return false;
diff --git a/llvm/lib/Target/AMDGPU/MCTargetDesc/AMDGPUInstPrinter.cpp b/llvm/lib/Target/AMDGPU/MCTargetDesc/AMDGPUInstPrinter.cpp
index 12880e6692918..aac7e1ad34d81 100644
--- a/llvm/lib/Target/AMDGPU/MCTargetDesc/AMDGPUInstPrinter.cpp
+++ b/llvm/lib/Target/AMDGPU/MCTargetDesc/AMDGPUInstPrinter.cpp
@@ -432,9 +432,9 @@ void AMDGPUInstPrinter::printVOPDst(const MCInst *MI, unsigned OpNo,
                                     const MCSubtargetInfo &STI, raw_ostream &O) {
   auto Opcode = MI->getOpcode();
   if (OpNo == 0) {
-    if (SIInstrFlags::isVOP3(MII, *MI) && SIInstrFlags::isDPP(MII, *MI))
+    if (SIInstrFlags::isVOP3Like(MII, *MI) && SIInstrFlags::isDPP(MII, *MI))
       O << "_e64_dpp";
-    else if (SIInstrFlags::isVOP3(MII, *MI)) {
+    else if (SIInstrFlags::isVOP3Like(MII, *MI)) {
       if (!getVOP3IsSingle(Opcode))
         O << "_e64";
     } else if (SIInstrFlags::isDPP(MII, *MI))
diff --git a/llvm/lib/Target/AMDGPU/SIDefines.h b/llvm/lib/Target/AMDGPU/SIDefines.h
index 65388e237a3b3..999754be8f356 100644
--- a/llvm/lib/Target/AMDGPU/SIDefines.h
+++ b/llvm/lib/Target/AMDGPU/SIDefines.h
@@ -77,12 +77,9 @@ enum : uint64_t {
   SALU = 1 << 7,
   VALU = 1 << 8,
 
-  // Remaining modifiers that layer on top of a base format.
   TRANS = 1 << 9,
-  VOP3P = 1 << 10,
-  VINTERP = 1 << 11,
 
-  // Bits 30-12 are free.
+  // Bits 30-10 are free.
 
   // High bits - other information.
   VM_CNT = UINT64_C(1) << 32,
@@ -189,6 +186,8 @@ enum class InstFormat : uint64_t {
   VOP2,
   VOPC,
   VOP3,
+  VOP3P,
+  VINTERP,
   VINTRP,
   VOPD3,
   LDSDIR,
@@ -261,10 +260,13 @@ template <typename... T> constexpr bool isVOP3(const T &...O) {
   return getFormat(O...) == InstFormat::VOP3;
 }
 template <typename... T> constexpr bool isVOP3P(const T &...O) {
-  return getTSFlags(O...) & DontUseRawTSFlags::VOP3P;
+  return getFormat(O...) == InstFormat::VOP3P;
+}
+template <typename... T> constexpr bool isVINTERP(const T &...O) {
+  return getFormat(O...) == InstFormat::VINTERP;
 }
 template <typename... T> constexpr bool isVOP3Like(const T &...O) {
-  return isVOP3(O...) || isVOP3P(O...);
+  return isVOP3(O...) || isVOP3P(O...) || isVINTERP(O...);
 }
 template <typename... T> constexpr bool isVINTRP(const T &...O) {
   return getFormat(O...) == InstFormat::VINTRP;
@@ -281,13 +283,13 @@ template <typename... T> constexpr bool isSDWA(const T &...O) {
 }
 template <typename... T> constexpr bool isDPP(const T &...O) {
   bool R = getFormatModifier(O...) == FormatModifier::DPP;
-  // DPP layers on VOP3 and VOPC (VOP3P instructions carry Format::VOP3 here).
-  // The VOP1/VOP2 e32 dpp forms currently carry Format::NONE instead of their
-  // base format.
+  // DPP layers on VOP3, VOPC and VOP3P. The VOP1/VOP2 e32 dpp forms currently
+  // carry Format::NONE instead of their base format.
   // TODO: tag VOP1/VOP2 e32 dpp forms with VOP1/VOP2 (see VOP_DPP_Pseudo) so
-  //       NONE can be dropped from this assert.
+  //       Format::NONE can be dropped from this assert.
   assert((!R || getFormat(O...) == InstFormat::VOP3 ||
           getFormat(O...) == InstFormat::VOPC ||
+          getFormat(O...) == InstFormat::VOP3P ||
           getFormat(O...) == InstFormat::NONE) &&
          "unexpected base format for DPP");
   return R;
@@ -331,9 +333,6 @@ template <typename... T> constexpr bool isSpill(const T &...O) {
 template <typename... T> constexpr bool isLDSDIR(const T &...O) {
   return getFormat(O...) == InstFormat::LDSDIR;
 }
-template <typename... T> constexpr bool isVINTERP(const T &...O) {
-  return getTSFlags(O...) & DontUseRawTSFlags::VINTERP;
-}
 template <typename... T> constexpr bool isWQM(const T &...O) {
   return getTSFlags(O...) & DontUseRawTSFlags::WQM;
 }
diff --git a/llvm/lib/Target/AMDGPU/SIFoldOperands.cpp b/llvm/lib/Target/AMDGPU/SIFoldOperands.cpp
index e5490b390db08..bf0dc60790a53 100644
--- a/llvm/lib/Target/AMDGPU/SIFoldOperands.cpp
+++ b/llvm/lib/Target/AMDGPU/SIFoldOperands.cpp
@@ -495,7 +495,7 @@ bool SIFoldOperandsImpl::canUseImmWithOpSel(const MachineInstr *MI,
   case AMDGPU::OPERAND_REG_INLINE_C_V2INT16:
     // VOP3 packed instructions ignore op_sel source modifiers, we cannot encode
     // two different constants.
-    if (SIInstrFlags::isVOP3(*MI) && !SIInstrFlags::isVOP3P(*MI) &&
+    if (SIInstrFlags::isVOP3(*MI) &&
         static_cast<uint16_t>(ImmVal) != static_cast<uint16_t>(ImmVal >> 16))
       return false;
     break;
diff --git a/llvm/lib/Target/AMDGPU/SIISelLowering.cpp b/llvm/lib/Target/AMDGPU/SIISelLowering.cpp
index b5fa732ea9418..f2fa3f1257c37 100644
--- a/llvm/lib/Target/AMDGPU/SIISelLowering.cpp
+++ b/llvm/lib/Target/AMDGPU/SIISelLowering.cpp
@@ -19807,7 +19807,7 @@ void SITargetLowering::AdjustInstrPostInstrSelection(MachineInstr &MI,
   MachineFunction *MF = MI.getMF();
   MachineRegisterInfo &MRI = MF->getRegInfo();
 
-  if (TII->isVOP3(MI.getOpcode())) {
+  if (SIInstrFlags::isVOP3Like(MI)) {
     // Make sure constant bus requirements are respected.
     TII->legalizeOperandsVOP3(MRI, MI);
 
diff --git a/llvm/lib/Target/AMDGPU/SIInstrFormats.td b/llvm/lib/Target/AMDGPU/SIInstrFormats.td
index 545baf749793c..a0c25cc99c018 100644
--- a/llvm/lib/Target/AMDGPU/SIInstrFormats.td
+++ b/llvm/lib/Target/AMDGPU/SIInstrFormats.td
@@ -26,23 +26,25 @@ def AMDGPUInstrFormat {
   int VOP2 = 7;
   int VOPC = 8;
   int VOP3 = 9;
-  int VINTRP = 10;
-  int VOPD3 = 11;
-  int LDSDIR = 12;
+  int VOP3P = 10;
+  int VINTERP = 11;
+  int VINTRP = 12;
+  int VOPD3 = 13;
+  int LDSDIR = 14;
 
   // Memory instruction formats.
-  int MUBUF = 13;
-  int MTBUF = 14;
-  int SMRD = 15;
-  int MIMG = 16;
-  int VIMAGE = 17;
-  int VSAMPLE = 18;
-  int EXP = 19;
-  int FLAT = 20;
-  int DS = 21;
+  int MUBUF = 15;
+  int MTBUF = 16;
+  int SMRD = 17;
+  int MIMG = 18;
+  int VIMAGE = 19;
+  int VSAMPLE = 20;
+  int EXP = 21;
+  int FLAT = 22;
+  int DS = 23;
 
   // Combined SGPR/VGPR spill pseudo.
-  int Spill = 22;
+  int Spill = 24;
 }
 
 // Operand-encoding modifier, keep in sync with SIInstrFlags::FormatModifier in
@@ -201,7 +203,7 @@ class InstSI <dag outs, dag ins, string asm = "",
 
   // Mutually-exclusive instruction format, derived from the format bits above.
   // The base format bits are all exclusive, so they collapse into one enum
-  // field.
+  // field. VOP3P/VINTERP also set the VOP3 bit, so match them before VOP3.
   bits<5> Format = !cond(SOP1    : AMDGPUInstrFormat.SOP1,
                          SOP2    : AMDGPUInstrFormat.SOP2,
                          SOPC    : AMDGPUInstrFormat.SOPC,
@@ -210,6 +212,8 @@ class InstSI <dag outs, dag ins, string asm = "",
                          VOP1    : AMDGPUInstrFormat.VOP1,
                          VOP2    : AMDGPUInstrFormat.VOP2,
                          VOPC    : AMDGPUInstrFormat.VOPC,
+                         VOP3P   : AMDGPUInstrFormat.VOP3P,
+                         VINTERP : AMDGPUInstrFormat.VINTERP,
                          VOP3    : AMDGPUInstrFormat.VOP3,
                          VINTRP  : AMDGPUInstrFormat.VINTRP,
                          VOPD3   : AMDGPUInstrFormat.VOPD3,
@@ -238,11 +242,9 @@ class InstSI <dag outs, dag ins, string asm = "",
   let TSFlags{8} = VALU;
 
   let TSFlags{9} = TRANS;
-  let TSFlags{10} = VOP3P;
-  let TSFlags{11} = VINTERP;
 
   // Reserved, must be 0.
-  let TSFlags{31-12} = 0;
+  let TSFlags{31-10} = 0;
 
   let TSFlags{32} = VM_CNT;
   let TSFlags{33} = EXP_CNT;
diff --git a/llvm/lib/Target/AMDGPU/SIInstrInfo.cpp b/llvm/lib/Target/AMDGPU/SIInstrInfo.cpp
index 2c014218914b0..68e19bcb8a555 100644
--- a/llvm/lib/Target/AMDGPU/SIInstrInfo.cpp
+++ b/llvm/lib/Target/AMDGPU/SIInstrInfo.cpp
@@ -112,7 +112,7 @@ static bool nodesHaveSameOperandValue(SDNode *N0, SDNode *N1,
 static bool canRemat(const MachineInstr &MI) {
 
   if (SIInstrInfo::isVOP1(MI) || SIInstrInfo::isVOP2(MI) ||
-      SIInstrInfo::isVOP3(MI) || SIInstrInfo::isSDWA(MI) ||
+      SIInstrFlags::isVOP3Like(MI) || SIInstrInfo::isSDWA(MI) ||
       SIInstrInfo::isSALU(MI))
     return true;
 
@@ -5063,7 +5063,7 @@ bool SIInstrInfo::isLiteralOperandLegal(const MCInstrDesc &InstDesc,
   if (!RI.opCanUseLiteralConstant(OpInfo.OperandType))
     return false;
 
-  if (!isVOP3(InstDesc) || !AMDGPU::isSISrcOperand(OpInfo))
+  if (!SIInstrFlags::isVOP3Like(InstDesc) || !AMDGPU::isSISrcOperand(OpInfo))
     return true;
 
   return ST.hasVOP3Literal();
@@ -5743,7 +5743,7 @@ bool SIInstrInfo::verifyInstruction(const MachineInstr &MI,
             UsesLiteral = true;
             LiteralVal = &MO;
           } else if (!MO.isIdenticalTo(*LiteralVal)) {
-            assert(isVOP2(MI) || isVOP3(MI));
+            assert(isVOP2(MI) || SIInstrFlags::isVOP3Like(MI));
             ErrInfo = "VOP2/VOP3 instruction uses more than one literal";
             return false;
           }
@@ -5770,7 +5770,7 @@ bool SIInstrInfo::verifyInstruction(const MachineInstr &MI,
       return false;
     }
 
-    if (isVOP3(MI) && UsesLiteral && !ST.hasVOP3Literal()) {
+    if (SIInstrFlags::isVOP3Like(MI) && UsesLiteral && !ST.hasVOP3Literal()) {
       ErrInfo = "VOP3 instruction uses literal";
       return false;
     }
@@ -6716,7 +6716,8 @@ bool SIInstrInfo::isOperandLegal(const MachineInstr &MI, unsigned OpIdx,
     const MachineOperand *UsedLiteral = nullptr;
 
     int ConstantBusLimit = ST.getConstantBusLimit(MI.getOpcode());
-    int LiteralLimit = !isVOP3(MI) || ST.hasVOP3Literal() ? 1 : 0;
+    int LiteralLimit =
+        !SIInstrFlags::isVOP3Like(MI) || ST.hasVOP3Literal() ? 1 : 0;
 
     // TODO: Be more permissive with frame indexes.
     if (!MO->isReg() && !isInlineConstant(*MO, OpInfo)) {
@@ -7716,7 +7717,7 @@ SIInstrInfo::legalizeOperands(MachineInstr &MI,
   }
 
   // Legalize VOP3
-  if (isVOP3(MI)) {
+  if (SIInstrFlags::isVOP3Like(MI)) {
     legalizeOperandsVOP3(MRI, MI);
     return CreatedBB;
   }
diff --git a/llvm/lib/Target/AMDGPU/Utils/AMDGPUBaseInfo.cpp b/llvm/lib/Target/AMDGPU/Utils/AMDGPUBaseInfo.cpp
index 3bc50b5017ecf..d6ffb69cb97a5 100644
--- a/llvm/lib/Target/AMDGPU/Utils/AMDGPUBaseInfo.cpp
+++ b/llvm/lib/Target/AMDGPU/Utils/AMDGPUBaseInfo.cpp
@@ -914,7 +914,7 @@ ComponentProps::ComponentProps(const MCInstrDesc &OpDesc, bool VOP3Layout) {
   HasSrc2Acc = TiedIdx != -1;
   Opcode = OpDesc.getOpcode();
 
-  IsVOP3 = VOP3Layout || SIInstrFlags::isVOP3(OpDesc);
+  IsVOP3 = VOP3Layout || SIInstrFlags::isVOP3Like(OpDesc);
   SrcOperandsNum = AMDGPU::hasNamedOperand(Opcode, AMDGPU::OpName::src2)   ? 3
                    : AMDGPU::hasNamedOperand(Opcode, AMDGPU::OpName::imm)  ? 3
                    : AMDGPU::hasNamedOperand(Opcode, AMDGPU::OpName::src1) ? 2
@@ -943,7 +943,7 @@ ComponentProps::ComponentProps(const MCInstrDesc &OpDesc, bool VOP3Layout) {
       --NumVOPD3Mods;
   }
 
-  if (SIInstrFlags::isVOP3(OpDesc))
+  if (SIInstrFlags::isVOP3Like(OpDesc))
     return;
 
   auto OperandsNum = OpDesc.getNumOperands();



More information about the llvm-branch-commits mailing list