Skip to content

Commit 9ccf154

Browse files
author
Brox Chen
authored
Decorate the pointer argument of OpLoad and Opstore with BufferLocationINTEL (#1801)
This PR is regarding spec KhronosGroup/SPIRV-Registry#185 This patch parse the string in a "ptr.annotation" call, extracting buffer location information and create a SPIRV decoration on the pointer using the buffer location information. This applies only on the pointer argument of OpLoad/Opstore
1 parent a7a1d2f commit 9ccf154

File tree

3 files changed

+118
-11
lines changed

3 files changed

+118
-11
lines changed

lib/SPIRV/SPIRVReader.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3377,6 +3377,8 @@ void generateIntelFPGAAnnotation(
33773377
}
33783378
if (E->hasDecorate(DecorationForcePow2DepthINTEL, 0, &Result))
33793379
Out << "{force_pow2_depth:" << Result << '}';
3380+
if (E->hasDecorate(DecorationBufferLocationINTEL, 0, &Result))
3381+
Out << "{sycl-buffer-location:" << Result << '}';
33803382

33813383
unsigned LSUParamsBitmask = 0;
33823384
llvm::SmallString<32> AdditionalParamsStr;

lib/SPIRV/SPIRVWriter.cpp

Lines changed: 59 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2824,6 +2824,12 @@ using DecorationsInfoVec =
28242824
struct AnnotationDecorations {
28252825
DecorationsInfoVec MemoryAttributesVec;
28262826
DecorationsInfoVec MemoryAccessesVec;
2827+
DecorationsInfoVec BufferLocationVec;
2828+
2829+
bool empty() {
2830+
return (MemoryAttributesVec.empty() && MemoryAccessesVec.empty() &&
2831+
BufferLocationVec.empty());
2832+
}
28272833
};
28282834

28292835
struct IntelLSUControlsInfo {
@@ -3014,6 +3020,8 @@ AnnotationDecorations tryParseAnnotationString(SPIRVModule *BM,
30143020
BM->isAllowedToUseExtension(ExtensionID::SPV_INTEL_fpga_memory_accesses);
30153021
const bool AllowFPGAMemAttr = BM->isAllowedToUseExtension(
30163022
ExtensionID::SPV_INTEL_fpga_memory_attributes);
3023+
const bool AllowFPGABufLoc =
3024+
BM->isAllowedToUseExtension(ExtensionID::SPV_INTEL_fpga_buffer_location);
30173025

30183026
bool ValidDecorationFound = false;
30193027
DecorationsInfoVec DecorationsVec;
@@ -3032,8 +3040,15 @@ AnnotationDecorations tryParseAnnotationString(SPIRVModule *BM,
30323040
std::vector<std::string> DecValues;
30333041
if (tryParseAnnotationDecoValues(ValueStr, DecValues)) {
30343042
ValidDecorationFound = true;
3035-
DecorationsVec.emplace_back(static_cast<Decoration>(DecorationKind),
3036-
std::move(DecValues));
3043+
3044+
if (AllowFPGABufLoc &&
3045+
DecorationKind == DecorationBufferLocationINTEL) {
3046+
Decorates.BufferLocationVec.emplace_back(
3047+
static_cast<Decoration>(DecorationKind), std::move(DecValues));
3048+
} else {
3049+
DecorationsVec.emplace_back(static_cast<Decoration>(DecorationKind),
3050+
std::move(DecValues));
3051+
}
30373052
}
30383053
continue;
30393054
}
@@ -3104,6 +3119,7 @@ AnnotationDecorations tryParseAnnotationString(SPIRVModule *BM,
31043119
DecorationsVec.emplace_back(Dec, std::move(DecValues));
31053120
}
31063121
}
3122+
31073123
// Even if there is an annotation string that is split in blocks like Intel
31083124
// FPGA annotation, it's not necessarily an FPGA annotation. Translate the
31093125
// whole string as UserSemantic decoration in this case.
@@ -3220,6 +3236,18 @@ void addAnnotationDecorations(SPIRVEntry *E, DecorationsInfoVec &Decorations) {
32203236
E->addDecorate(I.first, Result);
32213237
}
32223238
} break;
3239+
case DecorationBufferLocationINTEL: {
3240+
if (M->isAllowedToUseExtension(
3241+
ExtensionID::SPV_INTEL_fpga_buffer_location)) {
3242+
M->getErrorLog().checkError(I.second.size() == 1,
3243+
SPIRVEC_InvalidLlvmModule,
3244+
"Decoration requires a single argument.");
3245+
SPIRVWord Result = 0;
3246+
StringRef(I.second[0]).getAsInteger(10, Result);
3247+
E->addDecorate(I.first, Result);
3248+
}
3249+
} break;
3250+
32233251
default:
32243252
// Other decorations are either not supported by the translator or
32253253
// handled in other places.
@@ -3485,6 +3513,26 @@ static bool allowsApproxFunction(IntrinsicInst *II) {
34853513
cast<VectorType>(Ty)->getElementType()->isFloatTy()));
34863514
}
34873515

3516+
bool allowDecorateWithBufferLocationINTEL(IntrinsicInst *II) {
3517+
SmallVector<Value *, 8> UserList;
3518+
3519+
for (auto *Inst : II->users()) {
3520+
// if castInst, push Successors
3521+
if (auto *Cast = dyn_cast<CastInst>(Inst)) {
3522+
for (auto *Successor : Cast->users())
3523+
UserList.push_back(Successor);
3524+
} else {
3525+
UserList.push_back(Inst);
3526+
}
3527+
}
3528+
3529+
for (auto &Inst : UserList)
3530+
if (isa<LoadInst>(Inst) || isa<StoreInst>(Inst))
3531+
return true;
3532+
3533+
return false;
3534+
}
3535+
34883536
SPIRVValue *LLVMToSPIRVBase::transIntrinsicInst(IntrinsicInst *II,
34893537
SPIRVBasicBlock *BB) {
34903538
auto GetMemoryAccess = [](MemIntrinsic *MI) -> std::vector<SPIRVWord> {
@@ -3953,8 +4001,7 @@ SPIRVValue *LLVMToSPIRVBase::transIntrinsicInst(IntrinsicInst *II,
39534001

39544002
// If we didn't find any IntelFPGA-specific decorations, let's add the
39554003
// whole annotation string as UserSemantic Decoration
3956-
if (Decorations.MemoryAttributesVec.empty() &&
3957-
Decorations.MemoryAccessesVec.empty()) {
4004+
if (Decorations.empty()) {
39584005
// TODO: Is there a way to detect that the annotation belongs solely
39594006
// to struct member memory atributes or struct member memory access
39604007
// controls? This would allow emitting just the necessary decoration.
@@ -3971,20 +4018,26 @@ SPIRVValue *LLVMToSPIRVBase::transIntrinsicInst(IntrinsicInst *II,
39714018
// because multiple accesses to the struct-held memory can require
39724019
// different LSU parameters.
39734020
addAnnotationDecorations(ResPtr, Decorations.MemoryAccessesVec);
4021+
if (allowDecorateWithBufferLocationINTEL(II))
4022+
addAnnotationDecorations(ResPtr, Decorations.BufferLocationVec);
39744023
}
39754024
II->replaceAllUsesWith(II->getOperand(0));
39764025
} else {
39774026
// Memory accesses to a standalone pointer variable
39784027
auto *DecSubj = transValue(II->getArgOperand(0), BB);
3979-
if (Decorations.MemoryAccessesVec.empty())
4028+
if (Decorations.MemoryAccessesVec.empty() &&
4029+
Decorations.BufferLocationVec.empty())
39804030
DecSubj->addDecorate(new SPIRVDecorateUserSemanticAttr(
39814031
DecSubj, AnnotationString.c_str()));
3982-
else
4032+
else {
39834033
// Apply the LSU parameter decoration to the pointer result of an
39844034
// instruction. Note it's the address to the accessed memory that's
39854035
// loaded from the original pointer variable, and not the value
39864036
// accessed by the latter.
39874037
addAnnotationDecorations(DecSubj, Decorations.MemoryAccessesVec);
4038+
if (allowDecorateWithBufferLocationINTEL(II))
4039+
addAnnotationDecorations(DecSubj, Decorations.BufferLocationVec);
4040+
}
39884041
II->replaceAllUsesWith(II->getOperand(0));
39894042
}
39904043
return nullptr;

test/extensions/INTEL/SPV_INTEL_fpga_buffer_location/FPGABufferLocation.ll

Lines changed: 57 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
; CHECK-SPIRV: 4 Decorate [[ARGB]] BufferLocationINTEL 2
2323
; CHECK-SPIRV-NOT: 4 Decorate [[ARGD]] BufferLocationINTEL -1
2424
; CHECK-SPIRV-NOT: 4 Decorate [[ARGE]] BufferLocationINTEL 3
25+
; CHECK-SPIRV-DAG: 4 Decorate {{[0-9]+}} BufferLocationINTEL 123456789
2526

2627
; CHECK-SPIRV: 5 Function
2728
; CHECK-SPIRV: 3 FunctionParameter {{[0-9]+}} [[ARGA]]
@@ -30,20 +31,68 @@
3031
; CHECK-SPIRV: 3 FunctionParameter {{[0-9]+}} [[ARGD]]
3132
; CHECK-SPIRV: 3 FunctionParameter {{[0-9]+}} [[ARGE]]
3233

33-
; CHECK-LLVM: define spir_kernel void @test{{.*}} !kernel_arg_buffer_location ![[BUFLOC_MD:[0-9]+]] {{.*}}
34-
; CHECK-LLVM: ![[BUFLOC_MD]] = !{i32 1, i32 2, i32 -1, i32 -1, i32 -1}
35-
3634
; ModuleID = 'buffer_location.cl'
37-
source_filename = "buffer_location.cl"
3835
target datalayout = "e-i64:64-v16:16-v24:32-v32:32-v48:64-v96:128-v192:256-v256:256-v512:512-v1024:1024"
3936
target triple = "spir64-unknown-unknown"
4037

38+
%struct.MyIP = type { ptr addrspace(4) }
39+
40+
@.str.4 = internal unnamed_addr constant [19 x i8] c"{5921:\22123456789\22}\00"
41+
@.str.1 = internal unnamed_addr constant [9 x i8] c"main.cpp\00"
42+
; CHECK-LLVM: @[[ANN_STR:[0-9]+]] = private unnamed_addr constant [33 x i8] c"{sycl-buffer-location:123456789}\00"
43+
44+
; Function Attrs: nounwind
45+
define spir_kernel void @test(ptr addrspace(1) %a, ptr addrspace(1) %b, ptr addrspace(1) %c, i32 %d, i32 %e) local_unnamed_addr !kernel_arg_addr_space !3 !kernel_arg_access_qual !4 !kernel_arg_type !5 !kernel_arg_base_type !5 !kernel_arg_buffer_location !6
46+
; CHECK-LLVM: !kernel_arg_buffer_location ![[BUFLOC_MD:[0-9]+]]
47+
{
48+
entry:
49+
ret void
50+
}
51+
52+
; test1 : direct on kernel argument
4153
; Function Attrs: norecurse nounwind readnone
42-
define spir_kernel void @test(i32 addrspace(1)* %a, float addrspace(1)* %b, i32 addrspace(1)* %c, i32 %d, i32 %e) local_unnamed_addr !kernel_arg_addr_space !3 !kernel_arg_access_qual !4 !kernel_arg_type !5 !kernel_arg_base_type !5 !kernel_arg_buffer_location !6 {
54+
define spir_kernel void @test.1(ptr addrspace(4) %a) #0
55+
; CHECK-LLVM: !kernel_arg_buffer_location ![[BUFLOC_MD_TEST1:[0-9]+]]
56+
{
4357
entry:
58+
%0 = call ptr addrspace(4) @llvm.ptr.annotation.p4.p0(ptr addrspace(4) %a, ptr getelementptr inbounds ([19 x i8], ptr @.str.4, i32 0, i32 0), ptr getelementptr inbounds ([9 x i8], ptr @.str.1, i32 0, i32 0), i32 7, ptr null)
59+
store i8 0, ptr addrspace(4) %0, align 8
4460
ret void
4561
}
4662

63+
$test.2 = comdat any
64+
; test2 : general
65+
; Function Attrs: convergent mustprogress norecurse
66+
define weak_odr dso_local spir_kernel void @test.2(ptr addrspace(1) align 4 %arg_a) #0 comdat !kernel_arg_buffer_location !7 {
67+
entry:
68+
%this.addr.i = alloca ptr addrspace(4), align 8
69+
%arg_a.addr = alloca ptr addrspace(1), align 8
70+
%MyIP = alloca %struct.MyIP, align 8
71+
%arg_a.addr.ascast = addrspacecast ptr %arg_a.addr to ptr addrspace(4)
72+
%MyIP.ascast = addrspacecast ptr %MyIP to ptr addrspace(4)
73+
store ptr addrspace(1) %arg_a, ptr addrspace(4) %arg_a.addr.ascast, align 8
74+
%a = getelementptr inbounds %struct.MyIP, ptr addrspace(4) %MyIP.ascast, i32 0, i32 0
75+
%0 = call ptr addrspace(4) @llvm.ptr.annotation.p4.p0(ptr addrspace(4) %a, ptr getelementptr inbounds ([33 x i8], ptr @.str.4, i32 0, i32 0), ptr getelementptr inbounds ([9 x i8], ptr @.str.1, i32 0, i32 0), i32 7, ptr null)
76+
; CHECK-LLVM: call ptr addrspace(4) @llvm.ptr.annotation.p4.p0(ptr addrspace(4) %a, ptr @[[ANN_STR]], ptr undef, i32 undef, ptr undef)
77+
%b = load ptr addrspace(1), ptr addrspace(4) %arg_a.addr.ascast, align 8
78+
%1 = addrspacecast ptr addrspace(1) %b to ptr addrspace(4)
79+
store ptr addrspace(4) %1, ptr addrspace(4) %0, align 8
80+
%this.addr.ascast.i = addrspacecast ptr %this.addr.i to ptr addrspace(4)
81+
store ptr addrspace(4) %MyIP.ascast, ptr addrspace(4) %this.addr.ascast.i, align 8
82+
%this1.i = load ptr addrspace(4), ptr addrspace(4) %this.addr.ascast.i, align 8
83+
%a.i = getelementptr inbounds %struct.MyIP, ptr addrspace(4) %this1.i, i32 0, i32 0
84+
%2 = call ptr addrspace(4) @llvm.ptr.annotation.p4.p0(ptr addrspace(4) %a.i, ptr getelementptr inbounds ([19 x i8], ptr @.str.4, i32 0, i32 0), ptr getelementptr inbounds ([9 x i8], ptr @.str.1, i32 0, i32 0), i32 7, ptr null)
85+
; CHECK-LLVM: call ptr addrspace(4) @llvm.ptr.annotation.p4.p0(ptr addrspace(4) %a.i, ptr @[[ANN_STR]], ptr undef, i32 undef, ptr undef)
86+
%3 = load ptr addrspace(4), ptr addrspace(4) %2, align 8
87+
%4 = load i32, ptr addrspace(4) %3, align 4
88+
%inc.i = add nsw i32 %4, 1
89+
store i32 %inc.i, ptr addrspace(4) %3, align 4
90+
ret void
91+
}
92+
93+
; Function Attrs: nocallback nofree nosync nounwind willreturn memory(inaccessiblemem: readwrite)
94+
declare ptr addrspace(4) @llvm.ptr.annotation.p4.p0(ptr addrspace(4), ptr, ptr, i32, ptr) #1
95+
4796
!opencl.enable.FP_CONTRACT = !{}
4897
!opencl.ocl.version = !{!0}
4998
!opencl.spir.version = !{!0}
@@ -52,10 +101,13 @@ entry:
52101
!opencl.compiler.options = !{!1}
53102
!llvm.ident = !{!2}
54103

104+
; CHECK-LLVM: ![[BUFLOC_MD]] = !{i32 1, i32 2, i32 -1, i32 -1, i32 -1}
105+
; CHECK-LLVM: ![[BUFLOC_MD_TEST1]] = !{i32 123456789}
55106
!0 = !{i32 2, i32 0}
56107
!1 = !{}
57108
!2 = !{!""}
58109
!3 = !{i32 1, i32 1, i32 1}
59110
!4 = !{!"none", !"none", !"none"}
60111
!5 = !{!"int*", !"float*", !"int*"}
61112
!6 = !{i32 1, i32 2, i32 -1, i32 -1, i32 3}
113+
!7 = !{i32 -1}

0 commit comments

Comments
 (0)