[llvm] [SPIR-V] Introduce support for 'spirv.Decorations' metadata node in SPIR-V Backend (PR #91736)
Vyacheslav Levytskyy via llvm-commits
llvm-commits at lists.llvm.org
Tue May 14 00:29:05 PDT 2024
https://github.com/VyacheslavLevytskyy updated https://github.com/llvm/llvm-project/pull/91736
>From 8eed011f6a36d071d9afb68b8aa0a73892c5e260 Mon Sep 17 00:00:00 2001
From: "Levytskyy, Vyacheslav" <vyacheslav.levytskyy at intel.com>
Date: Fri, 10 May 2024 06:04:36 -0700
Subject: [PATCH 1/4] introduce support for 'spirv.Decorations' metadata node
---
llvm/lib/Target/SPIRV/SPIRVGlobalRegistry.cpp | 7 +++++
llvm/lib/Target/SPIRV/SPIRVUtils.cpp | 28 +++++++++++++++++++
llvm/lib/Target/SPIRV/SPIRVUtils.h | 4 +++
llvm/test/CodeGen/SPIRV/spirv-decoration.ll | 19 +++++++++++++
4 files changed, 58 insertions(+)
create mode 100644 llvm/test/CodeGen/SPIRV/spirv-decoration.ll
diff --git a/llvm/lib/Target/SPIRV/SPIRVGlobalRegistry.cpp b/llvm/lib/Target/SPIRV/SPIRVGlobalRegistry.cpp
index cebe230d3e8ce..0a4e44e2dac70 100644
--- a/llvm/lib/Target/SPIRV/SPIRVGlobalRegistry.cpp
+++ b/llvm/lib/Target/SPIRV/SPIRVGlobalRegistry.cpp
@@ -691,6 +691,13 @@ Register SPIRVGlobalRegistry::buildGlobalVariable(
buildOpDecorate(Reg, MIRBuilder, SPIRV::Decoration::BuiltIn,
{static_cast<uint32_t>(BuiltInId)});
+ // If it's a global variable with "spirv.Decorations" metadata node
+ // recognize it as a SPIR-V friendly LLVM IR and parse "spirv.Decorations"
+ // arguments.
+ MDNode *GVarMD = nullptr;
+ if (GVar && (GVarMD = GVar->getMetadata("spirv.Decorations")) != nullptr)
+ buildOpSpirvDecorations(Reg, MIRBuilder, GVarMD);
+
return Reg;
}
diff --git a/llvm/lib/Target/SPIRV/SPIRVUtils.cpp b/llvm/lib/Target/SPIRV/SPIRVUtils.cpp
index 871b95a28068e..3f8613d2707b8 100644
--- a/llvm/lib/Target/SPIRV/SPIRVUtils.cpp
+++ b/llvm/lib/Target/SPIRV/SPIRVUtils.cpp
@@ -133,6 +133,34 @@ void buildOpDecorate(Register Reg, MachineInstr &I, const SPIRVInstrInfo &TII,
finishBuildOpDecorate(MIB, DecArgs, StrImm);
}
+void buildOpSpirvDecorations(Register Reg, MachineIRBuilder &MIRBuilder,
+ MDNode *GVarMD) {
+ for (unsigned I = 0, E = GVarMD->getNumOperands(); I != E; ++I) {
+ auto *OpMD = dyn_cast<MDNode>(GVarMD->getOperand(I));
+ if (!OpMD)
+ report_fatal_error("Invalid decoration");
+ if (OpMD->getNumOperands() == 0)
+ report_fatal_error("Expect operand(s) of the decoration");
+ ConstantInt *DecorationId =
+ mdconst::dyn_extract<ConstantInt>(OpMD->getOperand(0));
+ if (!DecorationId)
+ report_fatal_error("Expect SPIR-V <Decoration> operand to be the first "
+ "element of the decoration");
+ auto MIB = MIRBuilder.buildInstr(SPIRV::OpDecorate)
+ .addUse(Reg)
+ .addImm(static_cast<uint32_t>(DecorationId->getZExtValue()));
+ for (unsigned OpI = 1, OpE = OpMD->getNumOperands(); OpI != OpE; ++OpI) {
+ if (ConstantInt *OpV =
+ mdconst::dyn_extract<ConstantInt>(OpMD->getOperand(OpI)))
+ MIB.addImm(static_cast<uint32_t>(OpV->getZExtValue()));
+ else if (MDString *OpV = dyn_cast<MDString>(OpMD->getOperand(OpI)))
+ addStringImm(OpV->getString(), MIB);
+ else
+ report_fatal_error("Unexpected operand of the decoration");
+ }
+ }
+}
+
// TODO: maybe the following two functions should be handled in the subtarget
// to allow for different OpenCL vs Vulkan handling.
unsigned storageClassToAddressSpace(SPIRV::StorageClass::StorageClass SC) {
diff --git a/llvm/lib/Target/SPIRV/SPIRVUtils.h b/llvm/lib/Target/SPIRV/SPIRVUtils.h
index 6a91b6e576f9c..fbdc9bf75dbe1 100644
--- a/llvm/lib/Target/SPIRV/SPIRVUtils.h
+++ b/llvm/lib/Target/SPIRV/SPIRVUtils.h
@@ -59,6 +59,10 @@ void buildOpDecorate(Register Reg, MachineInstr &I, const SPIRVInstrInfo &TII,
const std::vector<uint32_t> &DecArgs,
StringRef StrImm = "");
+// Add an OpDecorate instruction by "spirv.Decorations" metadata node
+void buildOpSpirvDecorations(Register Reg, MachineIRBuilder &MIRBuilder,
+ MDNode *GVarMD);
+
// Convert a SPIR-V storage class to the corresponding LLVM IR address space.
unsigned storageClassToAddressSpace(SPIRV::StorageClass::StorageClass SC);
diff --git a/llvm/test/CodeGen/SPIRV/spirv-decoration.ll b/llvm/test/CodeGen/SPIRV/spirv-decoration.ll
new file mode 100644
index 0000000000000..618646de93183
--- /dev/null
+++ b/llvm/test/CodeGen/SPIRV/spirv-decoration.ll
@@ -0,0 +1,19 @@
+; RUN: llc -O0 -mtriple=spirv64-unknown-unknown %s -o - | FileCheck %s
+; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv64-unknown-unknown %s -o - -filetype=obj | spirv-val %}
+
+; CHECK: OpName %[[#GV:]] "v"
+; CHECK-DAG: OpDecorate %[[#GV]] LinkageAttributes "v" Export
+; CHECK-DAG: OpDecorate %[[#GV]] Constant
+
+ at v = addrspace(1) global i32 0, !spirv.Decorations !0
+
+define spir_kernel void @foo() {
+entry:
+ %pv = load ptr addrspace(1), ptr addrspace(1) @v
+ store i32 3, ptr addrspace(1) %pv
+ ret void
+}
+
+!0 = !{!1, !2}
+!1 = !{i32 22}
+!2 = !{i32 41, !"v", i32 0}
>From ceb26e5ba84f0085cfed25d03689bd6f87c18d7e Mon Sep 17 00:00:00 2001
From: "Levytskyy, Vyacheslav" <vyacheslav.levytskyy at intel.com>
Date: Mon, 13 May 2024 06:41:34 -0700
Subject: [PATCH 2/4] support decoration of instructions
---
llvm/include/llvm/IR/IntrinsicsSPIRV.td | 1 +
llvm/lib/Target/SPIRV/SPIRVEmitIntrinsics.cpp | 12 +++++++++++-
llvm/lib/Target/SPIRV/SPIRVPreLegalizer.cpp | 17 +++++++++++++++++
llvm/lib/Target/SPIRV/SPIRVUtils.cpp | 2 +-
llvm/lib/Target/SPIRV/SPIRVUtils.h | 2 +-
llvm/test/CodeGen/SPIRV/spirv-decoration.ll | 18 +++++++++++++++---
6 files changed, 46 insertions(+), 6 deletions(-)
diff --git a/llvm/include/llvm/IR/IntrinsicsSPIRV.td b/llvm/include/llvm/IR/IntrinsicsSPIRV.td
index 8660782d71d95..931786ab96479 100644
--- a/llvm/include/llvm/IR/IntrinsicsSPIRV.td
+++ b/llvm/include/llvm/IR/IntrinsicsSPIRV.td
@@ -14,6 +14,7 @@ let TargetPrefix = "spv" in {
def int_spv_assign_type : Intrinsic<[], [llvm_any_ty, llvm_metadata_ty]>;
def int_spv_assign_ptr_type : Intrinsic<[], [llvm_any_ty, llvm_metadata_ty, llvm_i32_ty], [ImmArg<ArgIndex<2>>]>;
def int_spv_assign_name : Intrinsic<[], [llvm_any_ty, llvm_vararg_ty]>;
+ def int_spv_assign_decoration : Intrinsic<[], [llvm_any_ty, llvm_metadata_ty]>;
def int_spv_track_constant : Intrinsic<[llvm_any_ty], [llvm_any_ty, llvm_metadata_ty]>;
def int_spv_init_global : Intrinsic<[], [llvm_any_ty, llvm_any_ty]>;
diff --git a/llvm/lib/Target/SPIRV/SPIRVEmitIntrinsics.cpp b/llvm/lib/Target/SPIRV/SPIRVEmitIntrinsics.cpp
index 0d539b1ed9a88..90404686e4c6a 100644
--- a/llvm/lib/Target/SPIRV/SPIRVEmitIntrinsics.cpp
+++ b/llvm/lib/Target/SPIRV/SPIRVEmitIntrinsics.cpp
@@ -97,7 +97,6 @@ class SPIRVEmitIntrinsics
Args.push_back(Imm);
return B.CreateIntrinsic(IntrID, {Types}, Args);
}
-
void buildAssignPtr(IRBuilder<> &B, Type *ElemTy, Value *Arg);
void replaceMemInstrUses(Instruction *Old, Instruction *New, IRBuilder<> &B);
@@ -111,6 +110,7 @@ class SPIRVEmitIntrinsics
unsigned OperandToReplace,
IRBuilder<> &B);
void insertPtrCastOrAssignTypeInstr(Instruction *I, IRBuilder<> &B);
+ void insertSpirvDecorations(Instruction *I, IRBuilder<> &B);
void processGlobalValue(GlobalVariable &GV, IRBuilder<> &B);
void processParamTypes(Function *F, IRBuilder<> &B);
void processParamTypesByFunHeader(Function *F, IRBuilder<> &B);
@@ -1116,6 +1116,15 @@ void SPIRVEmitIntrinsics::insertAssignTypeIntrs(Instruction *I,
}
}
+void SPIRVEmitIntrinsics::insertSpirvDecorations(Instruction *I,
+ IRBuilder<> &B) {
+ if (MDNode *MD = I->getMetadata("spirv.Decorations")) {
+ B.SetInsertPoint(I->getNextNode());
+ B.CreateIntrinsic(Intrinsic::spv_assign_decoration, {I->getType()},
+ {I, MetadataAsValue::get(I->getContext(), MD)});
+ }
+}
+
void SPIRVEmitIntrinsics::processInstrAfterVisit(Instruction *I,
IRBuilder<> &B) {
auto *II = dyn_cast<IntrinsicInst>(I);
@@ -1287,6 +1296,7 @@ bool SPIRVEmitIntrinsics::runOnFunction(Function &Func) {
insertAssignPtrTypeIntrs(I, B);
insertAssignTypeIntrs(I, B);
insertPtrCastOrAssignTypeInstr(I, B);
+ insertSpirvDecorations(I, B);
}
for (auto &I : instructions(Func))
diff --git a/llvm/lib/Target/SPIRV/SPIRVPreLegalizer.cpp b/llvm/lib/Target/SPIRV/SPIRVPreLegalizer.cpp
index 84508fb5fe09e..6ee5d90d9afe1 100644
--- a/llvm/lib/Target/SPIRV/SPIRVPreLegalizer.cpp
+++ b/llvm/lib/Target/SPIRV/SPIRVPreLegalizer.cpp
@@ -519,6 +519,22 @@ static void processInstrsWithTypeFolding(MachineFunction &MF,
}
}
+static void insertSpirvDecorations(MachineFunction &MF, MachineIRBuilder MIB) {
+ SmallVector<MachineInstr *, 10> ToErase;
+ for (MachineBasicBlock &MBB : MF) {
+ for (MachineInstr &MI : MBB) {
+ if (!isSpvIntrinsic(MI, Intrinsic::spv_assign_decoration))
+ continue;
+ MIB.setInsertPt(*MI.getParent(), MI);
+ buildOpSpirvDecorations(MI.getOperand(1).getReg(), MIB,
+ MI.getOperand(2).getMetadata());
+ ToErase.push_back(&MI);
+ }
+ }
+ for (MachineInstr *MI : ToErase)
+ MI->eraseFromParent();
+}
+
// Find basic blocks of the switch and replace registers in spv_switch() by its
// MBB equivalent.
static void processSwitches(MachineFunction &MF, SPIRVGlobalRegistry *GR,
@@ -639,6 +655,7 @@ bool SPIRVPreLegalizer::runOnMachineFunction(MachineFunction &MF) {
processSwitches(MF, GR, MIB);
processInstrsWithTypeFolding(MF, GR, MIB);
removeImplicitFallthroughs(MF, MIB);
+ insertSpirvDecorations(MF, MIB);
return true;
}
diff --git a/llvm/lib/Target/SPIRV/SPIRVUtils.cpp b/llvm/lib/Target/SPIRV/SPIRVUtils.cpp
index 3f8613d2707b8..c20f3546a3e55 100644
--- a/llvm/lib/Target/SPIRV/SPIRVUtils.cpp
+++ b/llvm/lib/Target/SPIRV/SPIRVUtils.cpp
@@ -134,7 +134,7 @@ void buildOpDecorate(Register Reg, MachineInstr &I, const SPIRVInstrInfo &TII,
}
void buildOpSpirvDecorations(Register Reg, MachineIRBuilder &MIRBuilder,
- MDNode *GVarMD) {
+ const MDNode *GVarMD) {
for (unsigned I = 0, E = GVarMD->getNumOperands(); I != E; ++I) {
auto *OpMD = dyn_cast<MDNode>(GVarMD->getOperand(I));
if (!OpMD)
diff --git a/llvm/lib/Target/SPIRV/SPIRVUtils.h b/llvm/lib/Target/SPIRV/SPIRVUtils.h
index fbdc9bf75dbe1..711c3f7f09fb9 100644
--- a/llvm/lib/Target/SPIRV/SPIRVUtils.h
+++ b/llvm/lib/Target/SPIRV/SPIRVUtils.h
@@ -61,7 +61,7 @@ void buildOpDecorate(Register Reg, MachineInstr &I, const SPIRVInstrInfo &TII,
// Add an OpDecorate instruction by "spirv.Decorations" metadata node
void buildOpSpirvDecorations(Register Reg, MachineIRBuilder &MIRBuilder,
- MDNode *GVarMD);
+ const MDNode *GVarMD);
// Convert a SPIR-V storage class to the corresponding LLVM IR address space.
unsigned storageClassToAddressSpace(SPIRV::StorageClass::StorageClass SC);
diff --git a/llvm/test/CodeGen/SPIRV/spirv-decoration.ll b/llvm/test/CodeGen/SPIRV/spirv-decoration.ll
index 618646de93183..872c480bfe754 100644
--- a/llvm/test/CodeGen/SPIRV/spirv-decoration.ll
+++ b/llvm/test/CodeGen/SPIRV/spirv-decoration.ll
@@ -1,9 +1,13 @@
-; RUN: llc -O0 -mtriple=spirv64-unknown-unknown %s -o - | FileCheck %s
-; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv64-unknown-unknown %s -o - -filetype=obj | spirv-val %}
+; RUN: llc -O0 -mtriple=spirv64v1.4-unknown-unknown %s -o - | FileCheck %s
+; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv64v1.4-unknown-unknown %s -o - -filetype=obj | spirv-val %}
-; CHECK: OpName %[[#GV:]] "v"
+; CHECK-DAG: OpName %[[#GV:]] "v"
+; CHECK-DAG: OpName %[[#FunBar:]] "bar"
; CHECK-DAG: OpDecorate %[[#GV]] LinkageAttributes "v" Export
; CHECK-DAG: OpDecorate %[[#GV]] Constant
+; CHECK-DAG: OpDecorate %[[#Idx:]] UserSemantic "SemanticValue"
+; CHECK: %[[#FunBar]] = OpFunction
+; CHECK: %[[#Idx]] = OpInBoundsPtrAccessChain
@v = addrspace(1) global i32 0, !spirv.Decorations !0
@@ -14,6 +18,14 @@ entry:
ret void
}
+define spir_kernel void @bar(ptr addrspace(1) %arg) {
+entry:
+ %idx = getelementptr inbounds i32, ptr addrspace(1) %arg, i64 1, !spirv.Decorations !3
+ ret void
+}
+
!0 = !{!1, !2}
!1 = !{i32 22}
!2 = !{i32 41, !"v", i32 0}
+!3 = !{!4}
+!4 = !{i32 5635, !"SemanticValue"}
>From 0716e20b5b30e5ec8be843c3a0278990d40bbd1c Mon Sep 17 00:00:00 2001
From: "Levytskyy, Vyacheslav" <vyacheslav.levytskyy at intel.com>
Date: Mon, 13 May 2024 06:45:42 -0700
Subject: [PATCH 3/4] add comments
---
llvm/lib/Target/SPIRV/SPIRVEmitIntrinsics.cpp | 1 +
llvm/test/CodeGen/SPIRV/spirv-decoration.ll | 6 +++---
2 files changed, 4 insertions(+), 3 deletions(-)
diff --git a/llvm/lib/Target/SPIRV/SPIRVEmitIntrinsics.cpp b/llvm/lib/Target/SPIRV/SPIRVEmitIntrinsics.cpp
index 90404686e4c6a..c00066f5dca62 100644
--- a/llvm/lib/Target/SPIRV/SPIRVEmitIntrinsics.cpp
+++ b/llvm/lib/Target/SPIRV/SPIRVEmitIntrinsics.cpp
@@ -97,6 +97,7 @@ class SPIRVEmitIntrinsics
Args.push_back(Imm);
return B.CreateIntrinsic(IntrID, {Types}, Args);
}
+
void buildAssignPtr(IRBuilder<> &B, Type *ElemTy, Value *Arg);
void replaceMemInstrUses(Instruction *Old, Instruction *New, IRBuilder<> &B);
diff --git a/llvm/test/CodeGen/SPIRV/spirv-decoration.ll b/llvm/test/CodeGen/SPIRV/spirv-decoration.ll
index 872c480bfe754..783a2e916c22a 100644
--- a/llvm/test/CodeGen/SPIRV/spirv-decoration.ll
+++ b/llvm/test/CodeGen/SPIRV/spirv-decoration.ll
@@ -25,7 +25,7 @@ entry:
}
!0 = !{!1, !2}
-!1 = !{i32 22}
-!2 = !{i32 41, !"v", i32 0}
+!1 = !{i32 22} ; 22 is Constant decoration
+!2 = !{i32 41, !"v", i32 0} ; 41 is LinkageAttributes decoration with 2 extra operands
!3 = !{!4}
-!4 = !{i32 5635, !"SemanticValue"}
+!4 = !{i32 5635, !"SemanticValue"} ; 5635 is UserSemantic decoration
>From 004b8e4cd8dcc4d6aab1872e7f0d35d51565555c Mon Sep 17 00:00:00 2001
From: "Levytskyy, Vyacheslav" <vyacheslav.levytskyy at intel.com>
Date: Tue, 14 May 2024 00:28:53 -0700
Subject: [PATCH 4/4] tweak in a comment, docs are updated with description of
the newly introduced intrinsics
---
llvm/docs/SPIRVUsage.rst | 4 ++++
llvm/lib/Target/SPIRV/SPIRVUtils.h | 2 +-
2 files changed, 5 insertions(+), 1 deletion(-)
diff --git a/llvm/docs/SPIRVUsage.rst b/llvm/docs/SPIRVUsage.rst
index a183877c48cb2..589ee7646ce17 100644
--- a/llvm/docs/SPIRVUsage.rst
+++ b/llvm/docs/SPIRVUsage.rst
@@ -253,6 +253,10 @@ SPIR-V backend, along with their descriptions and argument details.
- None
- `[Type, Vararg]`
- Assigns names to types or values, enhancing readability and debuggability of SPIR-V code. Not emitted directly but used for metadata enrichment.
+ * - `int_spv_assign_decoration`
+ - None
+ - `[Type, Metadata]`
+ - Assigns decoration to values by associating them with metadatas. Not emitted directly but used to support SPIR-V representation in LLVM IR.
* - `int_spv_track_constant`
- Type
- `[Type, Metadata]`
diff --git a/llvm/lib/Target/SPIRV/SPIRVUtils.h b/llvm/lib/Target/SPIRV/SPIRVUtils.h
index 711c3f7f09fb9..33cb509dc4a59 100644
--- a/llvm/lib/Target/SPIRV/SPIRVUtils.h
+++ b/llvm/lib/Target/SPIRV/SPIRVUtils.h
@@ -59,7 +59,7 @@ void buildOpDecorate(Register Reg, MachineInstr &I, const SPIRVInstrInfo &TII,
const std::vector<uint32_t> &DecArgs,
StringRef StrImm = "");
-// Add an OpDecorate instruction by "spirv.Decorations" metadata node
+// Add an OpDecorate instruction by "spirv.Decorations" metadata node.
void buildOpSpirvDecorations(Register Reg, MachineIRBuilder &MIRBuilder,
const MDNode *GVarMD);
More information about the llvm-commits
mailing list