Skip to content

Commit be9b4da

Browse files
[SPIR-V] Introduce support for 'spirv.Decorations' metadata node in SPIR-V Backend (#91736)
This PR is to introduce support for 'spirv.Decorations' metadata node in SPIR-V Backend. See also https://github.com/KhronosGroup/SPIRV-LLVM-Translator/blob/main/docs/SPIRVRepresentationInLLVM.rst that describes `spirv.Decorations` as an important part of SPIRV-friendly LLVM IR.
1 parent 429ce59 commit be9b4da

File tree

8 files changed

+103
-0
lines changed

8 files changed

+103
-0
lines changed

llvm/docs/SPIRVUsage.rst

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -253,6 +253,10 @@ SPIR-V backend, along with their descriptions and argument details.
253253
- None
254254
- `[Type, Vararg]`
255255
- Assigns names to types or values, enhancing readability and debuggability of SPIR-V code. Not emitted directly but used for metadata enrichment.
256+
* - `int_spv_assign_decoration`
257+
- None
258+
- `[Type, Metadata]`
259+
- Assigns decoration to values by associating them with metadatas. Not emitted directly but used to support SPIR-V representation in LLVM IR.
256260
* - `int_spv_track_constant`
257261
- Type
258262
- `[Type, Metadata]`

llvm/include/llvm/IR/IntrinsicsSPIRV.td

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ let TargetPrefix = "spv" in {
1414
def int_spv_assign_type : Intrinsic<[], [llvm_any_ty, llvm_metadata_ty]>;
1515
def int_spv_assign_ptr_type : Intrinsic<[], [llvm_any_ty, llvm_metadata_ty, llvm_i32_ty], [ImmArg<ArgIndex<2>>]>;
1616
def int_spv_assign_name : Intrinsic<[], [llvm_any_ty, llvm_vararg_ty]>;
17+
def int_spv_assign_decoration : Intrinsic<[], [llvm_any_ty, llvm_metadata_ty]>;
1718

1819
def int_spv_track_constant : Intrinsic<[llvm_any_ty], [llvm_any_ty, llvm_metadata_ty]>;
1920
def int_spv_init_global : Intrinsic<[], [llvm_any_ty, llvm_any_ty]>;

llvm/lib/Target/SPIRV/SPIRVEmitIntrinsics.cpp

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,7 @@ class SPIRVEmitIntrinsics
111111
unsigned OperandToReplace,
112112
IRBuilder<> &B);
113113
void insertPtrCastOrAssignTypeInstr(Instruction *I, IRBuilder<> &B);
114+
void insertSpirvDecorations(Instruction *I, IRBuilder<> &B);
114115
void processGlobalValue(GlobalVariable &GV, IRBuilder<> &B);
115116
void processParamTypes(Function *F, IRBuilder<> &B);
116117
void processParamTypesByFunHeader(Function *F, IRBuilder<> &B);
@@ -1116,6 +1117,15 @@ void SPIRVEmitIntrinsics::insertAssignTypeIntrs(Instruction *I,
11161117
}
11171118
}
11181119

1120+
void SPIRVEmitIntrinsics::insertSpirvDecorations(Instruction *I,
1121+
IRBuilder<> &B) {
1122+
if (MDNode *MD = I->getMetadata("spirv.Decorations")) {
1123+
B.SetInsertPoint(I->getNextNode());
1124+
B.CreateIntrinsic(Intrinsic::spv_assign_decoration, {I->getType()},
1125+
{I, MetadataAsValue::get(I->getContext(), MD)});
1126+
}
1127+
}
1128+
11191129
void SPIRVEmitIntrinsics::processInstrAfterVisit(Instruction *I,
11201130
IRBuilder<> &B) {
11211131
auto *II = dyn_cast<IntrinsicInst>(I);
@@ -1287,6 +1297,7 @@ bool SPIRVEmitIntrinsics::runOnFunction(Function &Func) {
12871297
insertAssignPtrTypeIntrs(I, B);
12881298
insertAssignTypeIntrs(I, B);
12891299
insertPtrCastOrAssignTypeInstr(I, B);
1300+
insertSpirvDecorations(I, B);
12901301
}
12911302

12921303
for (auto &I : instructions(Func))

llvm/lib/Target/SPIRV/SPIRVGlobalRegistry.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -691,6 +691,13 @@ Register SPIRVGlobalRegistry::buildGlobalVariable(
691691
buildOpDecorate(Reg, MIRBuilder, SPIRV::Decoration::BuiltIn,
692692
{static_cast<uint32_t>(BuiltInId)});
693693

694+
// If it's a global variable with "spirv.Decorations" metadata node
695+
// recognize it as a SPIR-V friendly LLVM IR and parse "spirv.Decorations"
696+
// arguments.
697+
MDNode *GVarMD = nullptr;
698+
if (GVar && (GVarMD = GVar->getMetadata("spirv.Decorations")) != nullptr)
699+
buildOpSpirvDecorations(Reg, MIRBuilder, GVarMD);
700+
694701
return Reg;
695702
}
696703

llvm/lib/Target/SPIRV/SPIRVPreLegalizer.cpp

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -519,6 +519,22 @@ static void processInstrsWithTypeFolding(MachineFunction &MF,
519519
}
520520
}
521521

522+
static void insertSpirvDecorations(MachineFunction &MF, MachineIRBuilder MIB) {
523+
SmallVector<MachineInstr *, 10> ToErase;
524+
for (MachineBasicBlock &MBB : MF) {
525+
for (MachineInstr &MI : MBB) {
526+
if (!isSpvIntrinsic(MI, Intrinsic::spv_assign_decoration))
527+
continue;
528+
MIB.setInsertPt(*MI.getParent(), MI);
529+
buildOpSpirvDecorations(MI.getOperand(1).getReg(), MIB,
530+
MI.getOperand(2).getMetadata());
531+
ToErase.push_back(&MI);
532+
}
533+
}
534+
for (MachineInstr *MI : ToErase)
535+
MI->eraseFromParent();
536+
}
537+
522538
// Find basic blocks of the switch and replace registers in spv_switch() by its
523539
// MBB equivalent.
524540
static void processSwitches(MachineFunction &MF, SPIRVGlobalRegistry *GR,
@@ -639,6 +655,7 @@ bool SPIRVPreLegalizer::runOnMachineFunction(MachineFunction &MF) {
639655
processSwitches(MF, GR, MIB);
640656
processInstrsWithTypeFolding(MF, GR, MIB);
641657
removeImplicitFallthroughs(MF, MIB);
658+
insertSpirvDecorations(MF, MIB);
642659

643660
return true;
644661
}

llvm/lib/Target/SPIRV/SPIRVUtils.cpp

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,34 @@ void buildOpDecorate(Register Reg, MachineInstr &I, const SPIRVInstrInfo &TII,
133133
finishBuildOpDecorate(MIB, DecArgs, StrImm);
134134
}
135135

136+
void buildOpSpirvDecorations(Register Reg, MachineIRBuilder &MIRBuilder,
137+
const MDNode *GVarMD) {
138+
for (unsigned I = 0, E = GVarMD->getNumOperands(); I != E; ++I) {
139+
auto *OpMD = dyn_cast<MDNode>(GVarMD->getOperand(I));
140+
if (!OpMD)
141+
report_fatal_error("Invalid decoration");
142+
if (OpMD->getNumOperands() == 0)
143+
report_fatal_error("Expect operand(s) of the decoration");
144+
ConstantInt *DecorationId =
145+
mdconst::dyn_extract<ConstantInt>(OpMD->getOperand(0));
146+
if (!DecorationId)
147+
report_fatal_error("Expect SPIR-V <Decoration> operand to be the first "
148+
"element of the decoration");
149+
auto MIB = MIRBuilder.buildInstr(SPIRV::OpDecorate)
150+
.addUse(Reg)
151+
.addImm(static_cast<uint32_t>(DecorationId->getZExtValue()));
152+
for (unsigned OpI = 1, OpE = OpMD->getNumOperands(); OpI != OpE; ++OpI) {
153+
if (ConstantInt *OpV =
154+
mdconst::dyn_extract<ConstantInt>(OpMD->getOperand(OpI)))
155+
MIB.addImm(static_cast<uint32_t>(OpV->getZExtValue()));
156+
else if (MDString *OpV = dyn_cast<MDString>(OpMD->getOperand(OpI)))
157+
addStringImm(OpV->getString(), MIB);
158+
else
159+
report_fatal_error("Unexpected operand of the decoration");
160+
}
161+
}
162+
}
163+
136164
// TODO: maybe the following two functions should be handled in the subtarget
137165
// to allow for different OpenCL vs Vulkan handling.
138166
unsigned storageClassToAddressSpace(SPIRV::StorageClass::StorageClass SC) {

llvm/lib/Target/SPIRV/SPIRVUtils.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,10 @@ void buildOpDecorate(Register Reg, MachineInstr &I, const SPIRVInstrInfo &TII,
5959
const std::vector<uint32_t> &DecArgs,
6060
StringRef StrImm = "");
6161

62+
// Add an OpDecorate instruction by "spirv.Decorations" metadata node.
63+
void buildOpSpirvDecorations(Register Reg, MachineIRBuilder &MIRBuilder,
64+
const MDNode *GVarMD);
65+
6266
// Convert a SPIR-V storage class to the corresponding LLVM IR address space.
6367
unsigned storageClassToAddressSpace(SPIRV::StorageClass::StorageClass SC);
6468

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
; RUN: llc -O0 -mtriple=spirv64v1.4-unknown-unknown %s -o - | FileCheck %s
2+
; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv64v1.4-unknown-unknown %s -o - -filetype=obj | spirv-val %}
3+
4+
; CHECK-DAG: OpName %[[#GV:]] "v"
5+
; CHECK-DAG: OpName %[[#FunBar:]] "bar"
6+
; CHECK-DAG: OpDecorate %[[#GV]] LinkageAttributes "v" Export
7+
; CHECK-DAG: OpDecorate %[[#GV]] Constant
8+
; CHECK-DAG: OpDecorate %[[#Idx:]] UserSemantic "SemanticValue"
9+
; CHECK: %[[#FunBar]] = OpFunction
10+
; CHECK: %[[#Idx]] = OpInBoundsPtrAccessChain
11+
12+
@v = addrspace(1) global i32 0, !spirv.Decorations !0
13+
14+
define spir_kernel void @foo() {
15+
entry:
16+
%pv = load ptr addrspace(1), ptr addrspace(1) @v
17+
store i32 3, ptr addrspace(1) %pv
18+
ret void
19+
}
20+
21+
define spir_kernel void @bar(ptr addrspace(1) %arg) {
22+
entry:
23+
%idx = getelementptr inbounds i32, ptr addrspace(1) %arg, i64 1, !spirv.Decorations !3
24+
ret void
25+
}
26+
27+
!0 = !{!1, !2}
28+
!1 = !{i32 22} ; 22 is Constant decoration
29+
!2 = !{i32 41, !"v", i32 0} ; 41 is LinkageAttributes decoration with 2 extra operands
30+
!3 = !{!4}
31+
!4 = !{i32 5635, !"SemanticValue"} ; 5635 is UserSemantic decoration

0 commit comments

Comments
 (0)