Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions llvm/docs/SPIRVUsage.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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_cluster_attributes``
- Adds decorations to indicate the cluster attributes of a function.

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:

Expand Down
4 changes: 3 additions & 1 deletion llvm/lib/Target/SPIRV/SPIRVCommandLine.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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_fpga_cluster_attributes",
SPIRV::Extension::Extension::SPV_INTEL_fpga_cluster_attributes}};

bool SPIRVExtensionsParser::parse(cl::Option &O, StringRef ArgName,
StringRef ArgValue,
Expand Down
46 changes: 44 additions & 2 deletions llvm/lib/Target/SPIRV/SPIRVModuleAnalysis.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -920,6 +920,12 @@ static void addOpDecorateReqs(const MachineInstr &MI, unsigned DecIndex,
} else if (Dec == SPIRV::Decoration::FPMaxErrorDecorationINTEL) {
Reqs.addRequirements(SPIRV::Capability::FPMaxErrorINTEL);
Reqs.addExtension(SPIRV::Extension::SPV_INTEL_fp_max_error);
} else if (Dec == SPIRV::Decoration::StallEnableINTEL) {
Reqs.addRequirements(SPIRV::Capability::FPGAClusterAttributesINTEL);
Reqs.addExtension(SPIRV::Extension::SPV_INTEL_fpga_cluster_attributes);
} else if (Dec == SPIRV::Decoration::StallFreeINTEL) {
Reqs.addRequirements(SPIRV::Capability::FPGAClusterAttributesV2INTEL);
Reqs.addExtension(SPIRV::Extension::SPV_INTEL_fpga_cluster_attributes);
}
}

Expand Down Expand Up @@ -1976,6 +1982,38 @@ static void handleMIFlagDecoration(MachineInstr &I, const SPIRVSubtarget &ST,
buildOpDecorate(DstReg, I, TII, SPIRV::Decoration::FPFastMathMode, {FMFlags});
}

static void handleFunctionDecoration(MachineInstr &MI, const SPIRVSubtarget &ST,
const SPIRVInstrInfo &TII,
SPIRV::ModuleAnalysisInfo &MAI,
llvm::Module::const_iterator F) {
Register FuncReg = MI.getOperand(0).getReg();
llvm::SmallVector<std::pair<unsigned int, llvm::MDNode *>> MetaDataList;

// Add function-level decorations based on metadata
F->getAllMetadata(MetaDataList);
for (auto &MetaData : MetaDataList) {
if (MetaData.second == F->getMetadata("stall_enable") ||
MetaData.second == F->getMetadata("stall_free")) {
Comment on lines +1995 to +1996
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Lets not use internal to https://github.com/intel/llvm metadata. Instead lets use spirv.Decorations metadata defined here: https://github.com/KhronosGroup/SPIRV-LLVM-Translator/blob/main/docs/SPIRVRepresentationInLLVM.rst (note, SPIR-V friendly LLVM IR is used not only in the translator, but also in SPIR-V backend).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Lets not use internal to https://github.com/intel/llvm metadata. Instead lets use spirv.Decorations metadata defined here: https://github.com/KhronosGroup/SPIRV-LLVM-Translator/blob/main/docs/SPIRVRepresentationInLLVM.rst (note, SPIR-V friendly LLVM IR is used not only in the translator, but also in SPIR-V backend).

Thanks for the reply. I understand that the use of Intel-specific metadata like stall_enable is discouraged, and the recommendation is to use the !spirv.Decorations metadata.

But I had a few questions:

Should the !spirv.Decorations metadata be expected to already exist in the LLVM IR (i.e., injected by the frontend or via an earlier pass), or am I expected to modify the frontend to emit this?

Alternatively, is it acceptable for me to assume that !spirv.Decorations will be present in the .ll file (e.g., from manually written tests or generated via a pass), and implement the behavior based on its presence?

Copy link
Contributor

@MrSidims MrSidims May 16, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should the !spirv.Decorations metadata be expected to already exist in the LLVM IR (i.e., injected by the frontend or via an earlier pass), or am I expected to modify the frontend to emit this?

As I have previously stated in #134352 (comment) - I don't really understand the end goal to give a precise and educated suggestion. So this question should be readdressed to your internship curator, what are you going to do with these extensions (I'm judging that there is one from your reply: "Actually I was implementing this extension as part of an internship project."). My point is: that it's better not to use internal to intel/llvm metadata. If the goal is just to modify SPIR-V backend that way, that it can emit SPV_INTEL_cluster_attributes - spirv.Decorations metadata is the way to go. Otherwise - if there are further plans to use these extensions, then it's still better to expect spirv.Decorations in the backend (and target it by the frontend) unless proven otherwise.

Also, I can't tell for sure as I haven't tested it, but my expectation is that nowadays llvm-spirv translator supports SPV_INTEL_cluster_attributes via spirv.Decorations metadata implicitly.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should the !spirv.Decorations metadata be expected to already exist in the LLVM IR (i.e., injected by the frontend or via an earlier pass), or am I expected to modify the frontend to emit this?

As I have previously stated in #134352 (comment) - I don't really understand the end goal to give a precise and educated suggestion. So this question should be readdressed to your internship curator, what are you going to do with these extensions (I'm judging that there is one from your reply: "Actually I was implementing this extension as part of an internship project."). My point is: that it's better not to use internal to intel/llvm metadata. If the goal is just to modify SPIR-V backend that way, that it can emit SPV_INTEL_cluster_attributes - spirv.Decorations metadata is the way to go. Otherwise - if there are further plans to use these extensions, then it's still better to expect spirv.Decorations in the backend (and target it by the frontend) unless proven otherwise.

Also, I can't tell for sure as I haven't tested it, but my expectation is that nowadays llvm-spirv translator supports SPV_INTEL_cluster_attributes via spirv.Decorations metadata implicitly.

Actually there is no particular use for this extension for us as of now. This was part of being familiar with llvm-project repo. So I tried to implement the missing extensions the same way they are handled in the translator. (Also the translator is using "stall_enable" and "stall_free" metadata to handle the extension)
So should I proceed with implementing the extension by modifying the frontend?

if (ST.canUseExtension(
SPIRV::Extension::SPV_INTEL_fpga_cluster_attributes)) {
llvm::SmallVector<llvm::MDNode *> MetaDataVector;
MetaDataVector.push_back(MetaData.second);
llvm::SmallVector<uint32_t> params =
getConstantFromMetadata(MetaDataVector);

if (params[0] == 1) {
if (MetaData.second == F->getMetadata("stall_enable"))
buildOpDecorate(FuncReg, MI, TII,
SPIRV::Decoration::StallEnableINTEL, {});
else
buildOpDecorate(FuncReg, MI, TII, SPIRV::Decoration::StallFreeINTEL,
{});
}
}
}
}
}

// Walk all functions and add decorations related to MI flags.
static void addDecorations(const Module &M, const SPIRVInstrInfo &TII,
MachineModuleInfo *MMI, const SPIRVSubtarget &ST,
Expand All @@ -1984,9 +2022,13 @@ static void addDecorations(const Module &M, const SPIRVInstrInfo &TII,
MachineFunction *MF = MMI->getMachineFunction(*F);
if (!MF)
continue;
for (auto &MBB : *MF)
for (auto &MI : MBB)
for (auto &MBB : *MF) {
for (auto &MI : MBB) {
handleMIFlagDecoration(MI, ST, TII, MAI.Reqs);
if (MI.getOpcode() == SPIRV::OpFunction)
handleFunctionDecoration(MI, ST, TII, MAI, F);
}
}
}
}

Expand Down
4 changes: 4 additions & 0 deletions llvm/lib/Target/SPIRV/SPIRVSymbolicOperands.td
Original file line number Diff line number Diff line change
Expand Up @@ -517,6 +517,8 @@ 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 FPGAClusterAttributesINTEL : CapabilityOperand<5904, 0, 0, [SPV_INTEL_fpga_cluster_attributes], []>;
defm FPGAClusterAttributesV2INTEL : CapabilityOperand<6150, 0, 0, [SPV_INTEL_fpga_cluster_attributes], []>;

//===----------------------------------------------------------------------===//
// Multiclass used to define SourceLanguage enum values and at the same time
Expand Down Expand Up @@ -1268,6 +1270,8 @@ defm FunctionFloatingPointModeINTEL : DecorationOperand<6080, 0, 0, [], [Functio
defm AliasScopeINTEL : DecorationOperand<5914, 0, 0, [], [MemoryAccessAliasingINTEL]>;
defm NoAliasINTEL : DecorationOperand<5915, 0, 0, [], [MemoryAccessAliasingINTEL]>;
defm FPMaxErrorDecorationINTEL : DecorationOperand<6170, 0, 0, [], [FPMaxErrorINTEL]>;
defm StallEnableINTEL : DecorationOperand<5905, 0, 0, [SPV_INTEL_fpga_cluster_attributes], [FPGAClusterAttributesINTEL]>;
defm StallFreeINTEL : DecorationOperand<6151, 0, 0, [SPV_INTEL_fpga_cluster_attributes], [FPGAClusterAttributesV2INTEL]>;

//===----------------------------------------------------------------------===//
// Multiclass used to define BuiltIn enum values and at the same time
Expand Down
18 changes: 18 additions & 0 deletions llvm/lib/Target/SPIRV/SPIRVUtils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -370,6 +370,24 @@ Type *getMDOperandAsType(const MDNode *N, unsigned I) {
return toTypedPointer(ElementTy);
}

llvm::SmallVector<uint32_t>
getConstantFromMetadata(llvm::SmallVector<llvm::MDNode *> &MetaDataList) {
llvm::SmallVector<uint32_t> res;
for (auto metaDataNode : MetaDataList) {
if (metaDataNode->getNumOperands() > 0) {
if (auto *CMD = llvm::dyn_cast<llvm::ConstantAsMetadata>(
metaDataNode->getOperand(0))) {
if (auto *CI = llvm::dyn_cast<llvm::ConstantInt>(CMD->getValue())) {
APInt val = CI->getValue();
int64_t decVal = val.getZExtValue();
res.push_back(decVal);
}
}
}
}
return res;
}

// The set of names is borrowed from the SPIR-V translator.
// TODO: may be implemented in SPIRVBuiltins.td.
static bool isPipeOrAddressSpaceCastBI(const StringRef MangledName) {
Expand Down
4 changes: 4 additions & 0 deletions llvm/lib/Target/SPIRV/SPIRVUtils.h
Original file line number Diff line number Diff line change
Expand Up @@ -243,6 +243,10 @@ bool isSpvIntrinsic(const Value *Arg);
// Get type of i-th operand of the metadata node.
Type *getMDOperandAsType(const MDNode *N, unsigned I);

// Extract the constant value from the metadata node.
llvm::SmallVector<uint32_t>
getConstantFromMetadata(llvm::SmallVector<llvm::MDNode *> &MetaDataList);

// If OpenCL or SPIR-V builtin function name is recognized, return a demangled
// name, otherwise return an empty string.
std::string getOclOrSpirvBuiltinDemangledName(StringRef Name);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
; RUN: llc -verify-machineinstrs -O0 -mtriple=spirv64-unknown-unknown --spirv-ext=+SPV_INTEL_fpga_cluster_attributes %s -o - | FileCheck %s

; CHECK-DAG: OpCapability FPGAClusterAttributesINTEL
; CHECK-DAG: OpCapability FPGAClusterAttributesV2INTEL
; CHECK-DAG: OpExtension "SPV_INTEL_fpga_cluster_attributes"
; CHECK-DAG: OpDecorate %[[#STALLENABLE_DEC:]] StallEnableINTEL
; CHECK-DAG: OpDecorate %[[#STALLFREE_DEC:]] StallFreeINTEL
; CHECK: %[[#STALLENABLE_DEC]] = OpFunction %[[#]] None %[[#]]
; CHECK: %[[#STALLFREE_DEC]] = OpFunction %[[#]] None %[[#]]

define spir_func void @test_fpga_stallenable_attr() !stall_enable !0 {
entry:
ret void
}

define spir_func void @test_fpga_stallfree_attr() !stall_free !1 {
entry:
ret void
}

!0 = !{ i32 1 }
!1 = !{ i32 1 }