[llvm] [SPIRV] support for extension SPV_INTEL_maximum_registers (PR #137229)

VISHAKH PRAKASH via llvm-commits llvm-commits at lists.llvm.org
Tue Apr 29 12:12:05 PDT 2025


https://github.com/VishMCW updated https://github.com/llvm/llvm-project/pull/137229

>From 0d2015b7bba384581395d22ccac43191ee362363 Mon Sep 17 00:00:00 2001
From: VishMCW <vishakh.prakash at multicorewareinc.com>
Date: Fri, 18 Apr 2025 18:09:39 +0530
Subject: [PATCH 1/2] FEAT: - Add support for the extension
 SPV_INTEL_maximum_registers

---
 llvm/include/llvm/IR/IntrinsicsSPIRV.td       |  4 +
 .../Target/SPIRV/MCTargetDesc/SPIRVBaseInfo.h |  5 ++
 .../SPIRV/MCTargetDesc/SPIRVInstPrinter.cpp   | 20 ++++-
 llvm/lib/Target/SPIRV/SPIRVAsmPrinter.cpp     | 46 +++++++++++
 llvm/lib/Target/SPIRV/SPIRVCommandLine.cpp    |  4 +-
 llvm/lib/Target/SPIRV/SPIRVEmitIntrinsics.cpp | 27 ++++++-
 llvm/lib/Target/SPIRV/SPIRVGlobalRegistry.h   | 13 ++++
 .../Target/SPIRV/SPIRVInstructionSelector.cpp |  7 ++
 llvm/lib/Target/SPIRV/SPIRVModuleAnalysis.cpp | 50 +++++++++++-
 .../lib/Target/SPIRV/SPIRVSymbolicOperands.td | 32 ++++++++
 .../registerallocmode_maxreg_extension.ll     | 77 +++++++++++++++++++
 11 files changed, 280 insertions(+), 5 deletions(-)
 create mode 100644 llvm/test/CodeGen/SPIRV/extensions/SPV_INTEL_maximum_registers/registerallocmode_maxreg_extension.ll

diff --git a/llvm/include/llvm/IR/IntrinsicsSPIRV.td b/llvm/include/llvm/IR/IntrinsicsSPIRV.td
index 4389b86745d7f..1ff17b4345679 100644
--- a/llvm/include/llvm/IR/IntrinsicsSPIRV.td
+++ b/llvm/include/llvm/IR/IntrinsicsSPIRV.td
@@ -145,4 +145,8 @@ let TargetPrefix = "spv" in {
 
   // FPMaxErrorDecorationINTEL
   def int_spv_assign_fpmaxerror_decoration: Intrinsic<[], [llvm_any_ty, llvm_metadata_ty]>;
+  
+  // ExecutionModeMaxRedId
+  def int_spv_max_reg_constant : Intrinsic<[], [llvm_i32_ty], [ImmArg<ArgIndex<0>>]>;
+
 }
diff --git a/llvm/lib/Target/SPIRV/MCTargetDesc/SPIRVBaseInfo.h b/llvm/lib/Target/SPIRV/MCTargetDesc/SPIRVBaseInfo.h
index d009244a92259..3ea39506c38c6 100644
--- a/llvm/lib/Target/SPIRV/MCTargetDesc/SPIRVBaseInfo.h
+++ b/llvm/lib/Target/SPIRV/MCTargetDesc/SPIRVBaseInfo.h
@@ -217,6 +217,11 @@ namespace CooperativeMatrixOperands {
 #include "SPIRVGenTables.inc"
 } // namespace CooperativeMatrixOperands
 
+namespace NamedMaximumNumberOfRegisters {
+#define GET_NamedMaximumNumberOfRegisters_DECL
+#include "SPIRVGenTables.inc"
+} // namespace NamedMaximumNumberOfRegisters
+
 struct ExtendedBuiltin {
   StringRef Name;
   InstructionSet::InstructionSet Set;
diff --git a/llvm/lib/Target/SPIRV/MCTargetDesc/SPIRVInstPrinter.cpp b/llvm/lib/Target/SPIRV/MCTargetDesc/SPIRVInstPrinter.cpp
index b486132077e3b..bee11a56b10cf 100644
--- a/llvm/lib/Target/SPIRV/MCTargetDesc/SPIRVInstPrinter.cpp
+++ b/llvm/lib/Target/SPIRV/MCTargetDesc/SPIRVInstPrinter.cpp
@@ -22,6 +22,7 @@
 #include "llvm/Support/Casting.h"
 #include "llvm/Support/ErrorHandling.h"
 #include "llvm/Support/FormattedStream.h"
+#include "llvm/Support/raw_ostream.h"
 
 using namespace llvm;
 using namespace llvm::SPIRV;
@@ -147,7 +148,24 @@ void SPIRVInstPrinter::printInst(const MCInst *MI, uint64_t Address,
         case SPIRV::OpMemberDecorate:
           printRemainingVariableOps(MI, NumFixedOps, OS);
           break;
-        case SPIRV::OpExecutionMode:
+        case SPIRV::OpExecutionMode: {
+          unsigned NumOperands = MI->getNumOperands();
+          if (NumOperands != NumFixedOps) {
+            const unsigned MaxRegVal =
+                MI->getOperand(FirstVariableIndex).getImm();
+            if (MaxRegVal == 0) {
+
+              OS << ' ';
+              printSymbolicOperand<
+                  OperandCategory::NamedMaximumNumberOfRegistersOperand>(
+                  MI, FirstVariableIndex, OS);
+              break;
+            }
+          }
+          printRemainingVariableOps(MI, NumFixedOps, OS);
+
+
+        } break;
         case SPIRV::OpExecutionModeId:
         case SPIRV::OpLoopMerge: {
           // Print any literals after the OPERAND_UNKNOWN argument normally.
diff --git a/llvm/lib/Target/SPIRV/SPIRVAsmPrinter.cpp b/llvm/lib/Target/SPIRV/SPIRVAsmPrinter.cpp
index f17c8a8fac14b..365e5ed3c197a 100644
--- a/llvm/lib/Target/SPIRV/SPIRVAsmPrinter.cpp
+++ b/llvm/lib/Target/SPIRV/SPIRVAsmPrinter.cpp
@@ -76,6 +76,9 @@ class SPIRVAsmPrinter : public AsmPrinter {
   void outputExecutionModeFromNumthreadsAttribute(
       const MCRegister &Reg, const Attribute &Attr,
       SPIRV::ExecutionMode::ExecutionMode EM);
+  void outputExecutionModeFromRegisterAllocMode(const MCRegister &Reg,
+                                                const MDNode *Node,
+                                                MachineFunction *MF);
   void outputExecutionMode(const Module &M);
   void outputAnnotations(const Module &M);
   void outputModuleSections();
@@ -492,6 +495,45 @@ void SPIRVAsmPrinter::outputExecutionModeFromNumthreadsAttribute(
   outputMCInst(Inst);
 }
 
+// outputs the execution mode for the extension SPV_INTEL_maximum_registers
+void SPIRVAsmPrinter::outputExecutionModeFromRegisterAllocMode(
+    const MCRegister &Reg, const MDNode *Node, MachineFunction *MF) {
+  MCInst Inst;
+  auto *RegisterAllocMode = Node->getOperand(0).get();
+  Inst.setOpcode(SPIRV::OpExecutionMode);
+  Inst.addOperand(MCOperand::createReg(Reg));
+
+  if (auto *MDS = dyn_cast<MDString>(RegisterAllocMode)) {
+    StringRef Str = MDS->getString();
+    if (Str.equals_insensitive("AutoINTEL")) {
+      Inst.addOperand(MCOperand::createImm(static_cast<unsigned>(
+          SPIRV::ExecutionMode::NamedMaximumRegistersINTEL)));
+      Inst.addOperand(MCOperand::createImm(static_cast<unsigned>(
+          SPIRV::NamedMaximumNumberOfRegisters::AutoINTEL)));
+    }
+  } else if (MDNode *NestedNode = dyn_cast<MDNode>(RegisterAllocMode)) {
+    if (auto *CMD = dyn_cast<ConstantAsMetadata>(NestedNode->getOperand(0))) {
+      if (ConstantInt *CI = dyn_cast<ConstantInt>(CMD->getValue())) {
+        Inst.setOpcode(SPIRV::OpExecutionModeId);
+        Inst.addOperand(MCOperand::createImm(
+            SPIRV::ExecutionMode::MaximumRegistersIdINTEL));
+        auto *GR = ST ->getSPIRVGlobalRegistry();
+        Register MaxOpConstantReg = GR ->getMaxRegConstantExtMap(MF);
+        MCRegister MaxRegister = MAI->getRegisterAlias(MF, MaxOpConstantReg);
+        Inst.addOperand(MCOperand::createReg(MaxRegister));
+      }
+    }
+  } else {
+
+    int64_t RegisterAllocVal =
+        mdconst::dyn_extract<ConstantInt>(RegisterAllocMode)->getZExtValue();
+    Inst.addOperand(
+        MCOperand::createImm(SPIRV::ExecutionMode::MaximumRegistersINTEL));
+    Inst.addOperand(MCOperand::createImm(RegisterAllocVal));
+  }
+  outputMCInst(Inst);
+}
+
 void SPIRVAsmPrinter::outputExecutionMode(const Module &M) {
   NamedMDNode *Node = M.getNamedMetadata("spirv.ExecutionMode");
   if (Node) {
@@ -532,6 +574,10 @@ void SPIRVAsmPrinter::outputExecutionMode(const Module &M) {
       Inst.addOperand(MCOperand::createImm(TypeCode));
       outputMCInst(Inst);
     }
+    if (MDNode *Node = F.getMetadata("RegisterAllocMode")) {
+      MachineFunction *MF = MMI->getMachineFunction(F);
+      outputExecutionModeFromRegisterAllocMode(FReg, Node, MF);
+    }
     if (ST->isOpenCLEnv() && !M.getNamedMetadata("spirv.ExecutionMode") &&
         !M.getNamedMetadata("opencl.enable.FP_CONTRACT")) {
       MCInst Inst;
diff --git a/llvm/lib/Target/SPIRV/SPIRVCommandLine.cpp b/llvm/lib/Target/SPIRV/SPIRVCommandLine.cpp
index 56cbd9414c9ee..bf9058886aa98 100644
--- a/llvm/lib/Target/SPIRV/SPIRVCommandLine.cpp
+++ b/llvm/lib/Target/SPIRV/SPIRVCommandLine.cpp
@@ -97,7 +97,9 @@ static const std::map<std::string, SPIRV::Extension::Extension, std::less<>>
          SPIRV::Extension::Extension::
              SPV_INTEL_subgroup_matrix_multiply_accumulate},
         {"SPV_INTEL_ternary_bitwise_function",
-         SPIRV::Extension::Extension::SPV_INTEL_ternary_bitwise_function}};
+         SPIRV::Extension::Extension::SPV_INTEL_ternary_bitwise_function},
+        {"SPV_INTEL_maximum_registers",
+         SPIRV::Extension::SPV_INTEL_maximum_registers}};
 
 bool SPIRVExtensionsParser::parse(cl::Option &O, StringRef ArgName,
                                   StringRef ArgValue,
diff --git a/llvm/lib/Target/SPIRV/SPIRVEmitIntrinsics.cpp b/llvm/lib/Target/SPIRV/SPIRVEmitIntrinsics.cpp
index 6205dfedb79fb..4777dbb586b08 100644
--- a/llvm/lib/Target/SPIRV/SPIRVEmitIntrinsics.cpp
+++ b/llvm/lib/Target/SPIRV/SPIRVEmitIntrinsics.cpp
@@ -149,6 +149,7 @@ class SPIRVEmitIntrinsics
                                         unsigned OperandToReplace,
                                         IRBuilder<> &B);
   void insertPtrCastOrAssignTypeInstr(Instruction *I, IRBuilder<> &B);
+  void insertMaxRegIdExecModeIntrs(Function *F, IRBuilder<> &B);
   bool shouldTryToAddMemAliasingDecoration(Instruction *Inst);
   void insertSpirvDecorations(Instruction *I, IRBuilder<> &B);
   void processGlobalValue(GlobalVariable &GV, IRBuilder<> &B);
@@ -2206,6 +2207,30 @@ void SPIRVEmitIntrinsics::processParamTypesByFunHeader(Function *F,
   }
 }
 
+void SPIRVEmitIntrinsics::insertMaxRegIdExecModeIntrs(Function *F,
+                                                      IRBuilder<> &B) {
+  MDNode *Node = F->getMetadata("RegisterAllocMode");
+
+  if (Node) {
+    Metadata *RegisterAllocMode = Node->getOperand(0).get();
+    // spv_max_reg_constant is added to add the OpConstant instruction which
+    // will be then used as operand for OpExecutionMode MaximumRegistersIdINTEL
+    if (MDNode *NestedNode = dyn_cast<MDNode>(RegisterAllocMode)) {
+      if (auto *CMD = dyn_cast<ConstantAsMetadata>(NestedNode->getOperand(0))) {
+        auto *CI = dyn_cast<ConstantInt>(CMD->getValue());
+        if (!CI)
+          return;
+        int32_t MaxRegNumExt = CI->getSExtValue();
+        B.SetInsertPointPastAllocas(F);
+        Value *MaxRegNumExtVal =
+            ConstantInt::get(Type::getInt32Ty(B.getContext()), MaxRegNumExt);
+        B.CreateIntrinsic(Intrinsic::spv_max_reg_constant, {},
+                          {MaxRegNumExtVal});
+      }
+    }
+  }
+}
+
 void SPIRVEmitIntrinsics::processParamTypes(Function *F, IRBuilder<> &B) {
   B.SetInsertPointPastAllocas(F);
   for (unsigned OpIdx = 0; OpIdx < F->arg_size(); ++OpIdx) {
@@ -2381,7 +2406,6 @@ bool SPIRVEmitIntrinsics::runOnFunction(Function &Func) {
   }
 
   processParamTypesByFunHeader(CurrF, B);
-
   // StoreInst's operand type can be changed during the next transformations,
   // so we need to store it in the set. Also store already transformed types.
   for (auto &I : instructions(Func)) {
@@ -2415,6 +2439,7 @@ bool SPIRVEmitIntrinsics::runOnFunction(Function &Func) {
     insertAssignTypeIntrs(I, B);
     insertPtrCastOrAssignTypeInstr(I, B);
     insertSpirvDecorations(I, B);
+    insertMaxRegIdExecModeIntrs(CurrF, B);
     // if instruction requires a pointee type set, let's check if we know it
     // already, and force it to be i8 if not
     if (Postpone && !GR->findAssignPtrTypeInstr(I))
diff --git a/llvm/lib/Target/SPIRV/SPIRVGlobalRegistry.h b/llvm/lib/Target/SPIRV/SPIRVGlobalRegistry.h
index b05896fb7174c..f3691ff2f0f46 100644
--- a/llvm/lib/Target/SPIRV/SPIRVGlobalRegistry.h
+++ b/llvm/lib/Target/SPIRV/SPIRVGlobalRegistry.h
@@ -68,6 +68,10 @@ class SPIRVGlobalRegistry : public SPIRVIRMapping {
   // Number of bits pointers and size_t integers require.
   const unsigned PointerSize;
 
+  // Maps each MachineFunction to its associated OpConstant register for the
+  // // SPV_INTEL_maximum_registers extension with ExecutionModeId MaximumRegistersIdINTEL.
+  DenseMap<const MachineFunction *, Register> MaxRegConstantExtMap;
+
   // Holds the maximum ID we have in the module.
   unsigned Bound;
 
@@ -114,6 +118,15 @@ class SPIRVGlobalRegistry : public SPIRVIRMapping {
   void setBound(unsigned V) { Bound = V; }
   unsigned getBound() { return Bound; }
 
+  void addMaxRegConstantRegisterExt(const MachineFunction *MF, Register Reg) {
+    MaxRegConstantExtMap[MF] = Reg;
+  }
+
+  Register getMaxRegConstantExtMap(const MachineFunction *MF) {
+    assert(MaxRegConstantExtMap.count(MF) &&
+           "MachineFunction not found in MaxRegConstantExtMap");
+    return MaxRegConstantExtMap[MF];
+  }
   void addGlobalObject(const Value *V, const MachineFunction *MF, Register R) {
     Reg2GO[std::make_pair(MF, R)] = V;
   }
diff --git a/llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp b/llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp
index 79f6b43f3aded..6d8602a158ae1 100644
--- a/llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp
+++ b/llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp
@@ -3185,6 +3185,13 @@ bool SPIRVInstructionSelector::selectIntrinsic(Register ResVReg,
   case Intrinsic::spv_discard: {
     return selectDiscard(ResVReg, ResType, I);
   }
+  case Intrinsic::spv_max_reg_constant: {
+    int32_t MaxRegNum = I.getOperand(1).getImm();
+    auto ConstMaxRegId = buildI32Constant(MaxRegNum, I);
+    Register MaxIdRegister = ConstMaxRegId.first;
+    GR.addMaxRegConstantRegisterExt(MF, MaxIdRegister);
+    return ConstMaxRegId.second;
+  } break;
   default: {
     std::string DiagMsg;
     raw_string_ostream OS(DiagMsg);
diff --git a/llvm/lib/Target/SPIRV/SPIRVModuleAnalysis.cpp b/llvm/lib/Target/SPIRV/SPIRVModuleAnalysis.cpp
index a6482d9df2ccb..740e88e41e9b3 100644
--- a/llvm/lib/Target/SPIRV/SPIRVModuleAnalysis.cpp
+++ b/llvm/lib/Target/SPIRV/SPIRVModuleAnalysis.cpp
@@ -1176,6 +1176,50 @@ static bool isImageTypeWithUnknownFormat(SPIRVType *TypeInst) {
   return TypeInst->getOperand(7).getImm() == 0;
 }
 
+static void setExtMaxRegId(const MachineFunction *MF,
+                           SPIRV::ModuleAnalysisInfo &MAI,
+                           SPIRVGlobalRegistry *GR) {
+  Register VirtualReg = GR->getMaxRegConstantExtMap(MF);
+  MCRegister MaxOpConstantReg = MAI.getNextIDRegister();
+  MAI.setRegisterAlias(MF, VirtualReg, MaxOpConstantReg);
+}
+
+static void transFunctionMetadataAsExecutionMode(const Function &F,
+                                                 const SPIRVSubtarget &ST,
+                                                 SPIRV::ModuleAnalysisInfo &MAI,
+                                                 MachineFunction *MF) {
+  SmallVector<MDNode *, 1> RegisterAllocModeMDs;
+  F.getMetadata("RegisterAllocMode", RegisterAllocModeMDs);
+  if (!RegisterAllocModeMDs.empty()) {
+    MAI.Reqs.addExtension(SPIRV::Extension::SPV_INTEL_maximum_registers);
+    MAI.Reqs.addCapability(SPIRV::Capability::RegisterLimitsINTEL);
+  }
+  for (unsigned I = 0; I < RegisterAllocModeMDs.size(); I++) {
+
+    auto *RegisterAllocMode = RegisterAllocModeMDs[I]->getOperand(0).get();
+    if (auto *MDS = dyn_cast<MDString>(RegisterAllocMode)) {
+      MAI.Reqs.getAndAddRequirements(
+          SPIRV::OperandCategory::ExecutionModeOperand,
+          SPIRV::ExecutionMode::NamedMaximumRegistersINTEL, ST);
+    } else if (isa<MDNode>(RegisterAllocMode)) {
+      MDNode *NestedNode = dyn_cast<MDNode>(RegisterAllocMode);
+      if (auto *CMD = dyn_cast<ConstantAsMetadata>(NestedNode->getOperand(0))) {
+        auto *CI = dyn_cast<ConstantInt>(CMD->getValue());
+        if (!CI)
+          break;
+        MAI.Reqs.getAndAddRequirements(
+            SPIRV::OperandCategory::ExecutionModeOperand,
+            SPIRV::ExecutionMode::MaximumRegistersIdINTEL, ST);
+        setExtMaxRegId(MF, MAI, ST.getSPIRVGlobalRegistry());
+      }
+    } else {
+      MAI.Reqs.getAndAddRequirements(
+          SPIRV::OperandCategory::ExecutionModeOperand,
+          SPIRV::ExecutionMode::MaximumRegistersINTEL, ST);
+    }
+  }
+}
+
 static void AddDotProductRequirements(const MachineInstr &MI,
                                       SPIRV::RequirementHandler &Reqs,
                                       const SPIRVSubtarget &ST) {
@@ -1921,7 +1965,10 @@ static void collectReqs(const Module &M, SPIRV::ModuleAnalysisInfo &MAI,
       MAI.Reqs.getAndAddRequirements(
           SPIRV::OperandCategory::ExecutionModeOperand,
           SPIRV::ExecutionMode::VecTypeHint, ST);
-
+    if (F.getMetadata("RegisterAllocMode")) {
+      MachineFunction *MF = MMI->getMachineFunction(F);
+      transFunctionMetadataAsExecutionMode(F, ST, MAI, MF);
+    }
     if (F.hasOptNone()) {
       if (ST.canUseExtension(SPIRV::Extension::SPV_INTEL_optnone)) {
         MAI.Reqs.addExtension(SPIRV::Extension::SPV_INTEL_optnone);
@@ -2061,7 +2108,6 @@ bool SPIRVModuleAnalysis::runOnModule(Module &M) {
 
   // Process type/const/global var/func decl instructions, number their
   // destination registers from 0 to N, collect Extensions and Capabilities.
-  collectReqs(M, MAI, MMI, *ST);
   collectDeclarations(M);
 
   // Number rest of registers from N+1 onwards.
diff --git a/llvm/lib/Target/SPIRV/SPIRVSymbolicOperands.td b/llvm/lib/Target/SPIRV/SPIRVSymbolicOperands.td
index afd3a5206926c..1f10a0fa94a9c 100644
--- a/llvm/lib/Target/SPIRV/SPIRVSymbolicOperands.td
+++ b/llvm/lib/Target/SPIRV/SPIRVSymbolicOperands.td
@@ -172,6 +172,8 @@ def KernelProfilingInfoOperand : OperandCategory;
 def OpcodeOperand : OperandCategory;
 def CooperativeMatrixLayoutOperand : OperandCategory;
 def CooperativeMatrixOperandsOperand : OperandCategory;
+def NamedMaximumNumberOfRegistersOperand: OperandCategory;
+
 
 //===----------------------------------------------------------------------===//
 // Multiclass used to define Extesions enum values and at the same time
@@ -315,6 +317,7 @@ defm SPV_INTEL_memory_access_aliasing : ExtensionOperand<118>;
 defm SPV_INTEL_fp_max_error : ExtensionOperand<119>;
 defm SPV_INTEL_ternary_bitwise_function : ExtensionOperand<120>;
 defm SPV_INTEL_subgroup_matrix_multiply_accumulate : ExtensionOperand<121>;
+defm SPV_INTEL_maximum_registers : ExtensionOperand<122>;
 
 //===----------------------------------------------------------------------===//
 // Multiclass used to define Capabilities enum values and at the same time
@@ -517,6 +520,7 @@ defm MemoryAccessAliasingINTEL : CapabilityOperand<5910, 0, 0, [SPV_INTEL_memory
 defm FPMaxErrorINTEL : CapabilityOperand<6169, 0, 0, [SPV_INTEL_fp_max_error], []>;
 defm TernaryBitwiseFunctionINTEL : CapabilityOperand<6241, 0, 0, [SPV_INTEL_ternary_bitwise_function], []>;
 defm SubgroupMatrixMultiplyAccumulateINTEL : CapabilityOperand<6236, 0, 0, [SPV_INTEL_subgroup_matrix_multiply_accumulate], []>;
+defm RegisterLimitsINTEL : CapabilityOperand<6460 , 0, 0, [SPV_INTEL_maximum_registers], []>;
 
 //===----------------------------------------------------------------------===//
 // Multiclass used to define SourceLanguage enum values and at the same time
@@ -714,6 +718,9 @@ defm RoundingModeRTPINTEL : ExecutionModeOperand<5620, [RoundToInfinityINTEL]>;
 defm RoundingModeRTNINTEL : ExecutionModeOperand<5621, [RoundToInfinityINTEL]>;
 defm FloatingPointModeALTINTEL : ExecutionModeOperand<5622, [FloatingPointModeINTEL]>;
 defm FloatingPointModeIEEEINTEL : ExecutionModeOperand<5623, [FloatingPointModeINTEL]>;
+defm MaximumRegistersINTEL : ExecutionModeOperand<6461, [RegisterLimitsINTEL]>;
+defm MaximumRegistersIdINTEL : ExecutionModeOperand<6462, [RegisterLimitsINTEL]>;
+defm NamedMaximumRegistersINTEL : ExecutionModeOperand<6463, [RegisterLimitsINTEL]>;
 
 //===----------------------------------------------------------------------===//
 // Multiclass used to define StorageClass enum values and at the same time
@@ -1745,3 +1752,28 @@ defm MatrixAAndBTF32ComponentsINTEL : CooperativeMatrixOperandsOperand<0x20, [SP
 defm MatrixAAndBBFloat16ComponentsINTEL : CooperativeMatrixOperandsOperand<0x40, [SPV_INTEL_joint_matrix], [CooperativeMatrixBFloat16ComponentTypeINTEL]>;
 defm MatrixCBFloat16ComponentsINTEL : CooperativeMatrixOperandsOperand<0x80, [SPV_INTEL_joint_matrix], [CooperativeMatrixBFloat16ComponentTypeINTEL]>;
 defm MatrixResultBFloat16ComponentsINTEL : CooperativeMatrixOperandsOperand<0x100, [SPV_INTEL_joint_matrix], [CooperativeMatrixBFloat16ComponentTypeINTEL]>;
+
+//===----------------------------------------------------------------------===//
+// Multiclass used to define Named Max Number of Reg Operands enum values and at the
+// same time SymbolicOperand entries with string mnemonics, extensions and
+// capabilities.
+//===----------------------------------------------------------------------===//
+
+def NamedMaximumNumberOfRegisters : GenericEnum, Operand<i32> {
+  let FilterClass = "NamedMaximumNumberOfRegisters";
+  let NameField = "Name";
+  let ValueField = "Value";
+  let PrintMethod = !strconcat("printSymbolicOperand<OperandCategory::", FilterClass, "Operand>");
+}
+
+class NamedMaximumNumberOfRegisters<string name, bits<32> value> {
+  string Name = name;
+  bits<32> Value = value;
+}
+
+multiclass NamedMaximumNumberOfRegistersOperand<bits<32> value, list<Extension> reqExtensions, list<Capability> reqCapabilities> {
+  def : NamedMaximumNumberOfRegisters<NAME, value>;
+  defm : SymbolicOperandWithRequirements<NamedMaximumNumberOfRegistersOperand, value, NAME, 0, 0, reqExtensions, reqCapabilities>;
+}
+
+defm AutoINTEL : NamedMaximumNumberOfRegistersOperand<0x0, [SPV_INTEL_maximum_registers], [RegisterLimitsINTEL]>;
diff --git a/llvm/test/CodeGen/SPIRV/extensions/SPV_INTEL_maximum_registers/registerallocmode_maxreg_extension.ll b/llvm/test/CodeGen/SPIRV/extensions/SPV_INTEL_maximum_registers/registerallocmode_maxreg_extension.ll
new file mode 100644
index 0000000000000..b30abf65aaaa1
--- /dev/null
+++ b/llvm/test/CodeGen/SPIRV/extensions/SPV_INTEL_maximum_registers/registerallocmode_maxreg_extension.ll
@@ -0,0 +1,77 @@
+; RUN: llc -verify-machineinstrs -O0 -mtriple=spirv64-unknown-unknown %s --spirv-ext=+SPV_INTEL_maximum_registers -o - | FileCheck %s
+; TODO: %if spirv-tools %{ llc -O0 -mtriple=spirv64-unknown-unknown %s --spirv-ext=+SPV_INTEL_maximum_registers -o - -filetype=obj | spirv-val %}
+
+; CHECK: OpCapability RegisterLimitsINTEL
+; CHECK: OpExtension "SPV_INTEL_maximum_registers"
+
+; CHECK: OpMemoryModel Physical64 OpenCL
+; CHECK: OpExecutionMode %[[#f1:]] MaximumRegistersINTEL 2
+; CHECK: OpExecutionMode %[[#f2:]] MaximumRegistersINTEL 1
+; CHECK: OpExecutionMode %[[#f3:]] NamedMaximumRegistersINTEL AutoINTEL
+; CHECK: OpExecutionModeId %[[#f4:]] MaximumRegistersIdINTEL %[[#const_3:]]
+
+; CHECK: %[[#void_type:]] = OpTypeVoid
+; CHECK: %[[#func_type:]] = OpTypeFunction %[[#void_type]]
+
+; CHECK: %[[#int_type:]] = OpTypeInt 32 0
+; CHECK: %[[#const_3]] = OpConstant %[[#int_type]] 3
+
+; CHECK: %[[#f1]] = OpFunction %[[#void_type]] DontInline %[[#]]
+; Function Attrs: noinline nounwind optnone
+define weak dso_local spir_kernel void @main_l3() #0 !RegisterAllocMode !10 {
+newFuncRoot:
+  ret void
+}
+
+; CHECK: %[[#f2]] = OpFunction %[[#void_type]] DontInline %[[#]]
+; Function Attrs: noinline nounwind optnone
+define weak dso_local spir_kernel void @main_l6() #0 !RegisterAllocMode !11 {
+newFuncRoot:
+  ret void
+}
+
+; CHECK: %[[#f3]] = OpFunction %[[#void_type]] DontInline %[[#]]
+; Function Attrs: noinline nounwind optnone
+define weak dso_local spir_kernel void @main_l9() #0 !RegisterAllocMode !12 {
+newFuncRoot:
+  ret void
+}
+
+; CHECK: %[[#f4]] = OpFunction %[[#void_type]] DontInline %[[#]]
+; Function Attrs: noinline nounwind optnone
+define weak dso_local spir_kernel void @main_l13() #0 !RegisterAllocMode !13 {
+newFuncRoot:
+  ret void
+}
+
+; CHECK: %[[#f5:]] = OpFunction %[[#void_type]] DontInline %[[#]]
+; Function Attrs: noinline nounwind optnone
+define weak dso_local spir_kernel void @main_l19() #0 {
+newFuncRoot:
+  ret void
+}
+
+attributes #0 = { noinline nounwind optnone }
+
+
+!opencl.compiler.options = !{!0, !0, !0, !0, !0, !0, !0, !0, !0, !0, !0, !0, !0, !0, !0, !0, !0, !0, !0, !0, !0, !0}
+!spirv.Source = !{!2, !3, !3, !3, !3, !3, !2, !3, !2, !2, !2, !2, !2, !2, !2, !2, !2, !2, !2, !2, !2, !2}
+!llvm.module.flags = !{!4, !5, !6, !7, !8}
+!spirv.MemoryModel = !{!9, !9, !9, !9, !9, !9}
+!spirv.ExecutionMode = !{}
+
+!0 = !{}
+!2 = !{i32 4, i32 200000}
+!3 = !{i32 3, i32 200000}
+!4 = !{i32 1, !"wchar_size", i32 4}
+!5 = !{i32 7, !"openmp", i32 50}
+!6 = !{i32 7, !"openmp-device", i32 50}
+!7 = !{i32 8, !"PIC Level", i32 2}
+!8 = !{i32 7, !"frame-pointer", i32 2}
+!9 = !{i32 2, i32 2}
+!10 = !{i32 2}
+!11 = !{i32 1}
+!12 = !{!"AutoINTEL"}
+!13 = !{!14}
+!14 = !{i32 3}
+

>From 187a8d9ac6fc93ba6513cb83eb74d2e7df95e9e9 Mon Sep 17 00:00:00 2001
From: VishMCW <vishakh.prakash at multicorewareinc.com>
Date: Tue, 29 Apr 2025 22:37:28 +0530
Subject: [PATCH 2/2] formatting and documentation

---
 llvm/docs/SPIRVUsage.rst                                | 7 +++++++
 llvm/lib/Target/SPIRV/MCTargetDesc/SPIRVInstPrinter.cpp | 2 --
 llvm/lib/Target/SPIRV/SPIRVAsmPrinter.cpp               | 4 ++--
 llvm/lib/Target/SPIRV/SPIRVGlobalRegistry.h             | 3 ++-
 4 files changed, 11 insertions(+), 5 deletions(-)

diff --git a/llvm/docs/SPIRVUsage.rst b/llvm/docs/SPIRVUsage.rst
index 6ff8034cac00c..8e8966e0fb63f 100644
--- a/llvm/docs/SPIRVUsage.rst
+++ b/llvm/docs/SPIRVUsage.rst
@@ -213,6 +213,8 @@ list of supported SPIR-V extensions, sorted alphabetically by their extension na
      - Adds a bitwise instruction on three operands and a look-up table index for specifying the bitwise operation to perform. 
    * - ``SPV_INTEL_subgroup_matrix_multiply_accumulate``
      - Adds an instruction to compute the matrix product of an M x K matrix with a K x N matrix and then add an M x N matrix. 
+   * - ``SPV_INTEL_maximum_registers``
+     - This extension adds an execution mode to specify the maximum number of registers a SPIR-V consumer should use when compiling an entry point.  
 
 To enable multiple extensions, list them separated by comma. For example, to enable support for atomic operations on floating-point numbers and arbitrary precision integers, use:
 
@@ -489,6 +491,11 @@ SPIR-V backend, along with their descriptions and argument details.
      - `[spirv.Image Image, 32-bit Integer coordinate, vec4 data]`
      - Stores the data to the image buffer at the given coordinate. The \
        data must be a 4-element vector.
+   * - `int_spv_max_reg_constant`
+     - void
+     - `[32-bit Integer Maximum registers allowed]`
+     - 32-bit integer indicating the maximum number of registers allowed. \
+       Used as an operand to the OpExecutionModeId MaximumRegistersIdINTEL.
 
 .. _spirv-builtin-functions:
 
diff --git a/llvm/lib/Target/SPIRV/MCTargetDesc/SPIRVInstPrinter.cpp b/llvm/lib/Target/SPIRV/MCTargetDesc/SPIRVInstPrinter.cpp
index bee11a56b10cf..c51ae48b3310a 100644
--- a/llvm/lib/Target/SPIRV/MCTargetDesc/SPIRVInstPrinter.cpp
+++ b/llvm/lib/Target/SPIRV/MCTargetDesc/SPIRVInstPrinter.cpp
@@ -163,8 +163,6 @@ void SPIRVInstPrinter::printInst(const MCInst *MI, uint64_t Address,
             }
           }
           printRemainingVariableOps(MI, NumFixedOps, OS);
-
-
         } break;
         case SPIRV::OpExecutionModeId:
         case SPIRV::OpLoopMerge: {
diff --git a/llvm/lib/Target/SPIRV/SPIRVAsmPrinter.cpp b/llvm/lib/Target/SPIRV/SPIRVAsmPrinter.cpp
index 365e5ed3c197a..eff41bd1f0c7e 100644
--- a/llvm/lib/Target/SPIRV/SPIRVAsmPrinter.cpp
+++ b/llvm/lib/Target/SPIRV/SPIRVAsmPrinter.cpp
@@ -517,8 +517,8 @@ void SPIRVAsmPrinter::outputExecutionModeFromRegisterAllocMode(
         Inst.setOpcode(SPIRV::OpExecutionModeId);
         Inst.addOperand(MCOperand::createImm(
             SPIRV::ExecutionMode::MaximumRegistersIdINTEL));
-        auto *GR = ST ->getSPIRVGlobalRegistry();
-        Register MaxOpConstantReg = GR ->getMaxRegConstantExtMap(MF);
+        auto *GR = ST->getSPIRVGlobalRegistry();
+        Register MaxOpConstantReg = GR->getMaxRegConstantExtMap(MF);
         MCRegister MaxRegister = MAI->getRegisterAlias(MF, MaxOpConstantReg);
         Inst.addOperand(MCOperand::createReg(MaxRegister));
       }
diff --git a/llvm/lib/Target/SPIRV/SPIRVGlobalRegistry.h b/llvm/lib/Target/SPIRV/SPIRVGlobalRegistry.h
index f3691ff2f0f46..5e811edcdef0c 100644
--- a/llvm/lib/Target/SPIRV/SPIRVGlobalRegistry.h
+++ b/llvm/lib/Target/SPIRV/SPIRVGlobalRegistry.h
@@ -69,7 +69,8 @@ class SPIRVGlobalRegistry : public SPIRVIRMapping {
   const unsigned PointerSize;
 
   // Maps each MachineFunction to its associated OpConstant register for the
-  // // SPV_INTEL_maximum_registers extension with ExecutionModeId MaximumRegistersIdINTEL.
+  // SPV_INTEL_maximum_registers extension with ExecutionModeId
+  // MaximumRegistersIdINTEL.
   DenseMap<const MachineFunction *, Register> MaxRegConstantExtMap;
 
   // Holds the maximum ID we have in the module.



More information about the llvm-commits mailing list