[llvm] [AMDGPU] Pack instruction format and modifier TSFlags bits into enums, NFC. (PR #223783)
via llvm-commits
llvm-commits at lists.llvm.org
Tue Sep 15 11:55:40 PDT 2026
llvmorg-github-actions[bot] wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-backend-amdgpu
Author: Valery Pykhtin (vpykhtin)
<details>
<summary>Changes</summary>
The instruction-format bits in TSFlags are mutually exclusive, so
collapse them into a single 5-bit Format enum and likewise FormatModifier
enum for DPP/SDWA. This frees 18 TSFlags bits.
For now Format is derived from individual TableGen bitfields to minimize
the patch, but next commit will remove those.
All raw format-bit tests already go through the SIInstrFlags predicates,
so no call sites change.
Co-Authored-By: Claude <noreply@<!-- -->anthropic.com>
---
Full diff: https://github.com/llvm/llvm-project/pull/223783.diff
2 Files Affected:
- (modified) llvm/lib/Target/AMDGPU/SIDefines.h (+114-75)
- (modified) llvm/lib/Target/AMDGPU/SIInstrFormats.td (+86-39)
``````````diff
diff --git a/llvm/lib/Target/AMDGPU/SIDefines.h b/llvm/lib/Target/AMDGPU/SIDefines.h
index 864a84cc8daf4..65388e237a3b3 100644
--- a/llvm/lib/Target/AMDGPU/SIDefines.h
+++ b/llvm/lib/Target/AMDGPU/SIDefines.h
@@ -14,6 +14,7 @@
#include "llvm/MC/MCInstrDesc.h"
#include "llvm/MC/MCInstrInfo.h"
#include "llvm/Support/AMDGPUAddrSpace.h"
+#include <cassert>
namespace llvm {
@@ -62,53 +63,26 @@ namespace SIInstrFlags {
namespace DontUseRawTSFlags {
// This needs to be kept in sync with the field bits in InstSI.
enum : uint64_t {
- // Low bits - basic encoding information.
- SALU = 1 << 0,
- VALU = 1 << 1,
-
- // SALU instruction formats.
- SOP1 = 1 << 2,
- SOP2 = 1 << 3,
- SOPC = 1 << 4,
- SOPK = 1 << 5,
- SOPP = 1 << 6,
-
- // VALU instruction formats.
- VOP1 = 1 << 7,
- VOP2 = 1 << 8,
- VOPC = 1 << 9,
-
- // TODO: Should this be spilt into VOP3 a and b?
- VOP3 = 1 << 10,
- VOP3P = 1 << 12,
-
- VINTRP = 1 << 13,
- SDWA = 1 << 14,
- DPP = 1 << 15,
- TRANS = 1 << 16,
-
- // Memory instruction formats.
- MUBUF = 1 << 17,
- MTBUF = 1 << 18,
- SMRD = 1 << 19,
- MIMG = 1 << 20,
- VIMAGE = 1 << 21,
- VSAMPLE = 1 << 22,
- EXP = 1 << 23,
- FLAT = 1 << 24,
- DS = 1 << 25,
-
- // Combined SGPR/VGPR Spill bit
- // Logic to separate them out is done in isSGPRSpill and isVGPRSpill
- Spill = 1 << 26,
-
- // LDSDIR instruction format.
- LDSDIR = 1 << 28,
-
- // VINTERP instruction format.
- VINTERP = 1 << 29,
-
- VOPD3 = 1 << 30,
+ // Bits 4-0: instruction format enum, see the InstFormat enum below.
+ Format_Bits = 5,
+ Format_Mask = (UINT64_C(1) << Format_Bits) - 1,
+
+ // Bits 6-5: operand-encoding modifier, see the FormatModifier enum below.
+ FormatModifier_Shift = 5,
+ FormatModifier_Bits = 2,
+ FormatModifier_Mask = ((UINT64_C(1) << FormatModifier_Bits) - 1)
+ << FormatModifier_Shift,
+
+ // Basic encoding class.
+ 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.
// High bits - other information.
VM_CNT = UINT64_C(1) << 32,
@@ -203,6 +177,56 @@ inline uint64_t getTSFlags(const MCInstrInfo &MII, const MCInst &Inst) {
return MII.get(Inst.getOpcode()).TSFlags;
}
+// Instruction format, keep in sync with AMDGPUInstrFormat in SIInstrFormats.td.
+enum class InstFormat : uint64_t {
+ NONE = 0,
+ SOP1,
+ SOP2,
+ SOPC,
+ SOPK,
+ SOPP,
+ VOP1,
+ VOP2,
+ VOPC,
+ VOP3,
+ VINTRP,
+ VOPD3,
+ LDSDIR,
+ MUBUF,
+ MTBUF,
+ SMRD,
+ MIMG,
+ VIMAGE,
+ VSAMPLE,
+ EXP,
+ FLAT,
+ DS,
+ Spill,
+};
+
+template <typename... T> constexpr InstFormat getFormat(const T &...O) {
+ return static_cast<InstFormat>(getTSFlags(O...) &
+ DontUseRawTSFlags::Format_Mask);
+}
+template <typename... T> constexpr bool isFormat(InstFormat F, const T &...O) {
+ return getFormat(O...) == F;
+}
+
+// Operand-encoding modifier, keep in sync with AMDGPUFormatModifier in
+// SIInstrFormats.td. Packed into TSFlags{6-5}.
+enum class FormatModifier : uint64_t {
+ None = 0,
+ DPP,
+ SDWA,
+};
+
+template <typename... T>
+constexpr FormatModifier getFormatModifier(const T &...O) {
+ return static_cast<FormatModifier>(
+ (getTSFlags(O...) & DontUseRawTSFlags::FormatModifier_Mask) >>
+ DontUseRawTSFlags::FormatModifier_Shift);
+}
+
template <typename... T> constexpr bool isSALU(const T &...O) {
return getTSFlags(O...) & DontUseRawTSFlags::SALU;
}
@@ -210,87 +234,102 @@ template <typename... T> constexpr bool isVALU(const T &...O) {
return getTSFlags(O...) & DontUseRawTSFlags::VALU;
}
template <typename... T> constexpr bool isSOP1(const T &...O) {
- return getTSFlags(O...) & DontUseRawTSFlags::SOP1;
+ return getFormat(O...) == InstFormat::SOP1;
}
template <typename... T> constexpr bool isSOP2(const T &...O) {
- return getTSFlags(O...) & DontUseRawTSFlags::SOP2;
+ return getFormat(O...) == InstFormat::SOP2;
}
template <typename... T> constexpr bool isSOPC(const T &...O) {
- return getTSFlags(O...) & DontUseRawTSFlags::SOPC;
+ return getFormat(O...) == InstFormat::SOPC;
}
template <typename... T> constexpr bool isSOPK(const T &...O) {
- return getTSFlags(O...) & DontUseRawTSFlags::SOPK;
+ return getFormat(O...) == InstFormat::SOPK;
}
template <typename... T> constexpr bool isSOPP(const T &...O) {
- return getTSFlags(O...) & DontUseRawTSFlags::SOPP;
+ return getFormat(O...) == InstFormat::SOPP;
}
template <typename... T> constexpr bool isVOP1(const T &...O) {
- return getTSFlags(O...) & DontUseRawTSFlags::VOP1;
+ return getFormat(O...) == InstFormat::VOP1;
}
template <typename... T> constexpr bool isVOP2(const T &...O) {
- return getTSFlags(O...) & DontUseRawTSFlags::VOP2;
+ return getFormat(O...) == InstFormat::VOP2;
}
template <typename... T> constexpr bool isVOPC(const T &...O) {
- return getTSFlags(O...) & DontUseRawTSFlags::VOPC;
+ return getFormat(O...) == InstFormat::VOPC;
}
template <typename... T> constexpr bool isVOP3(const T &...O) {
- return getTSFlags(O...) & DontUseRawTSFlags::VOP3;
+ return getFormat(O...) == InstFormat::VOP3;
}
template <typename... T> constexpr bool isVOP3P(const T &...O) {
return getTSFlags(O...) & DontUseRawTSFlags::VOP3P;
}
template <typename... T> constexpr bool isVOP3Like(const T &...O) {
- return getTSFlags(O...) &
- (DontUseRawTSFlags::VOP3 | DontUseRawTSFlags::VOP3P);
+ return isVOP3(O...) || isVOP3P(O...);
}
template <typename... T> constexpr bool isVINTRP(const T &...O) {
- return getTSFlags(O...) & DontUseRawTSFlags::VINTRP;
+ return getFormat(O...) == InstFormat::VINTRP;
}
template <typename... T> constexpr bool isSDWA(const T &...O) {
- return getTSFlags(O...) & DontUseRawTSFlags::SDWA;
+ bool R = getFormatModifier(O...) == FormatModifier::SDWA;
+ // SDWA layers on a base VOP format. The VOP1/VOP2 e32 sdwa forms currently
+ // carry Format::NONE instead of their base format.
+ // TODO: tag VOP1/VOP2 sdwa forms with VOP1/VOP2 (see VOP_SDWA_Pseudo) so this
+ // can assert getFormat() is VOP1/VOP2 rather than NONE.
+ assert((!R || getFormat(O...) == InstFormat::NONE) &&
+ "unexpected base format for SDWA");
+ return R;
}
template <typename... T> constexpr bool isDPP(const T &...O) {
- return getTSFlags(O...) & DontUseRawTSFlags::DPP;
+ 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.
+ // TODO: tag VOP1/VOP2 e32 dpp forms with VOP1/VOP2 (see VOP_DPP_Pseudo) so
+ // NONE can be dropped from this assert.
+ assert((!R || getFormat(O...) == InstFormat::VOP3 ||
+ getFormat(O...) == InstFormat::VOPC ||
+ getFormat(O...) == InstFormat::NONE) &&
+ "unexpected base format for DPP");
+ return R;
}
template <typename... T> constexpr bool isTRANS(const T &...O) {
return getTSFlags(O...) & DontUseRawTSFlags::TRANS;
}
template <typename... T> constexpr bool isMUBUF(const T &...O) {
- return getTSFlags(O...) & DontUseRawTSFlags::MUBUF;
+ return getFormat(O...) == InstFormat::MUBUF;
}
template <typename... T> constexpr bool isMTBUF(const T &...O) {
- return getTSFlags(O...) & DontUseRawTSFlags::MTBUF;
+ return getFormat(O...) == InstFormat::MTBUF;
}
template <typename... T> constexpr bool isBuffer(const T &...O) {
- return getTSFlags(O...) &
- (DontUseRawTSFlags::MUBUF | DontUseRawTSFlags::MTBUF);
+ return isMUBUF(O...) || isMTBUF(O...);
}
template <typename... T> constexpr bool isSMRD(const T &...O) {
- return getTSFlags(O...) & DontUseRawTSFlags::SMRD;
+ return getFormat(O...) == InstFormat::SMRD;
}
template <typename... T> constexpr bool isMIMG(const T &...O) {
- return getTSFlags(O...) & DontUseRawTSFlags::MIMG;
+ return getFormat(O...) == InstFormat::MIMG;
}
template <typename... T> constexpr bool isVIMAGE(const T &...O) {
- return getTSFlags(O...) & DontUseRawTSFlags::VIMAGE;
+ return getFormat(O...) == InstFormat::VIMAGE;
}
template <typename... T> constexpr bool isVSAMPLE(const T &...O) {
- return getTSFlags(O...) & DontUseRawTSFlags::VSAMPLE;
+ return getFormat(O...) == InstFormat::VSAMPLE;
}
template <typename... T> constexpr bool isEXP(const T &...O) {
- return getTSFlags(O...) & DontUseRawTSFlags::EXP;
+ return getFormat(O...) == InstFormat::EXP;
}
template <typename... T> constexpr bool isFLAT(const T &...O) {
- return getTSFlags(O...) & DontUseRawTSFlags::FLAT;
+ return getFormat(O...) == InstFormat::FLAT;
}
template <typename... T> constexpr bool isDS(const T &...O) {
- return getTSFlags(O...) & DontUseRawTSFlags::DS;
+ return getFormat(O...) == InstFormat::DS;
}
template <typename... T> constexpr bool isSpill(const T &...O) {
- return getTSFlags(O...) & DontUseRawTSFlags::Spill;
+ return getFormat(O...) == InstFormat::Spill;
}
template <typename... T> constexpr bool isLDSDIR(const T &...O) {
- return getTSFlags(O...) & DontUseRawTSFlags::LDSDIR;
+ return getFormat(O...) == InstFormat::LDSDIR;
}
template <typename... T> constexpr bool isVINTERP(const T &...O) {
return getTSFlags(O...) & DontUseRawTSFlags::VINTERP;
@@ -377,7 +416,7 @@ template <typename... T> constexpr bool isSWMMAC(const T &...O) {
return getTSFlags(O...) & DontUseRawTSFlags::IsSWMMAC;
}
template <typename... T> constexpr bool isVOPD3(const T &...O) {
- return getTSFlags(O...) & DontUseRawTSFlags::VOPD3;
+ return getFormat(O...) == InstFormat::VOPD3;
}
template <typename... T> constexpr bool usesVM_CNT(const T &...O) {
return getTSFlags(O...) & DontUseRawTSFlags::VM_CNT;
diff --git a/llvm/lib/Target/AMDGPU/SIInstrFormats.td b/llvm/lib/Target/AMDGPU/SIInstrFormats.td
index a476dc61f019a..22da81e387d60 100644
--- a/llvm/lib/Target/AMDGPU/SIInstrFormats.td
+++ b/llvm/lib/Target/AMDGPU/SIInstrFormats.td
@@ -10,6 +10,49 @@
//
//===----------------------------------------------------------------------===//
+// Instruction format, keep in sync with SIInstrFlags::InstFormat in SIDefines.h
+def AMDGPUInstrFormat {
+ int NONE = 0;
+
+ // SALU instruction formats.
+ int SOP1 = 1;
+ int SOP2 = 2;
+ int SOPC = 3;
+ int SOPK = 4;
+ int SOPP = 5;
+
+ // VALU instruction formats.
+ int VOP1 = 6;
+ int VOP2 = 7;
+ int VOPC = 8;
+ int VOP3 = 9;
+ int VINTRP = 10;
+ int VOPD3 = 11;
+ int LDSDIR = 12;
+
+ // 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;
+
+ // Combined SGPR/VGPR spill pseudo.
+ int Spill = 22;
+}
+
+// Operand-encoding modifier, keep in sync with SIInstrFlags::FormatModifier in
+// SIDefines.h.
+def AMDGPUFormatModifier {
+ int None = 0;
+ int DPP = 1;
+ int SDWA = 2;
+}
+
class InstSI <dag outs, dag ins, string asm = "",
list<dag> pattern = []> :
AMDGPUInst<outs, ins, asm, pattern>, PredicateControl {
@@ -156,45 +199,49 @@ class InstSI <dag outs, dag ins, string asm = "",
// This bit indicates that this is one of SWMMAC instructions.
field bit IsSWMMAC = 0;
- // These need to be kept in sync with the enum in SIInstrFlags.
- let TSFlags{0} = SALU;
- let TSFlags{1} = VALU;
-
- let TSFlags{2} = SOP1;
- let TSFlags{3} = SOP2;
- let TSFlags{4} = SOPC;
- let TSFlags{5} = SOPK;
- let TSFlags{6} = SOPP;
-
- let TSFlags{7} = VOP1;
- let TSFlags{8} = VOP2;
- let TSFlags{9} = VOPC;
- let TSFlags{10} = VOP3;
- let TSFlags{12} = VOP3P;
-
- let TSFlags{13} = VINTRP;
- let TSFlags{14} = SDWA;
- let TSFlags{15} = DPP;
- let TSFlags{16} = TRANS;
-
- let TSFlags{17} = MUBUF;
- let TSFlags{18} = MTBUF;
- let TSFlags{19} = SMRD;
- let TSFlags{20} = MIMG;
- let TSFlags{21} = VIMAGE;
- let TSFlags{22} = VSAMPLE;
- let TSFlags{23} = EXP;
- let TSFlags{24} = FLAT;
- let TSFlags{25} = DS;
-
- let TSFlags{26} = Spill;
-
- // Reserved, must be 0
- let TSFlags{27} = 0;
-
- let TSFlags{28} = LDSDIR;
- let TSFlags{29} = VINTERP;
- let TSFlags{30} = VOPD3;
+ // Mutually-exclusive instruction format, derived from the format bits above.
+ // The base format bits are all exclusive, so they collapse into one enum
+ // field.
+ bits<5> Format = !cond(SOP1 : AMDGPUInstrFormat.SOP1,
+ SOP2 : AMDGPUInstrFormat.SOP2,
+ SOPC : AMDGPUInstrFormat.SOPC,
+ SOPK : AMDGPUInstrFormat.SOPK,
+ SOPP : AMDGPUInstrFormat.SOPP,
+ VOP1 : AMDGPUInstrFormat.VOP1,
+ VOP2 : AMDGPUInstrFormat.VOP2,
+ VOPC : AMDGPUInstrFormat.VOPC,
+ VOP3 : AMDGPUInstrFormat.VOP3,
+ VINTRP : AMDGPUInstrFormat.VINTRP,
+ VOPD3 : AMDGPUInstrFormat.VOPD3,
+ LDSDIR : AMDGPUInstrFormat.LDSDIR,
+ MUBUF : AMDGPUInstrFormat.MUBUF,
+ MTBUF : AMDGPUInstrFormat.MTBUF,
+ SMRD : AMDGPUInstrFormat.SMRD,
+ MIMG : AMDGPUInstrFormat.MIMG,
+ VIMAGE : AMDGPUInstrFormat.VIMAGE,
+ VSAMPLE : AMDGPUInstrFormat.VSAMPLE,
+ EXP : AMDGPUInstrFormat.EXP,
+ FLAT : AMDGPUInstrFormat.FLAT,
+ DS : AMDGPUInstrFormat.DS,
+ Spill : AMDGPUInstrFormat.Spill,
+ true : AMDGPUInstrFormat.NONE);
+
+ // Mutually-exclusive operand-encoding modifier (DPP and SDWA never co-occur).
+ bits<2> FormatModifier = !cond(DPP : AMDGPUFormatModifier.DPP,
+ SDWA : AMDGPUFormatModifier.SDWA,
+ true : AMDGPUFormatModifier.None);
+
+ let TSFlags{4-0} = Format;
+ let TSFlags{6-5} = FormatModifier;
+
+ let TSFlags{7} = SALU;
+ let TSFlags{8} = VALU;
+
+ let TSFlags{9} = TRANS;
+ let TSFlags{10} = VOP3P;
+ let TSFlags{11} = VINTERP;
+
+ // Bits 30-12 are free.
let TSFlags{32} = VM_CNT;
let TSFlags{33} = EXP_CNT;
``````````
</details>
https://github.com/llvm/llvm-project/pull/223783
More information about the llvm-commits
mailing list