[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