Skip to content

Commit 0933ebb

Browse files
authored
Add support for fpga latency control extension (#1893)
This change adds SPIRV-LLVM-Translator changes for SPV_INTEL_fpga_latency_control extension. The extension can be found here: KhronosGroup/SPIRV-Registry#179 The SPIR-V headers changes are here: KhronosGroup/SPIRV-Headers#321 Annotated pipes are not supported yet. Thanks Signed-off-by: Arvind Sudarsanam <[email protected]>
1 parent 4355f70 commit 0933ebb

File tree

9 files changed

+169
-17
lines changed

9 files changed

+169
-17
lines changed

include/LLVMSPIRVExtensions.inc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,3 +58,4 @@ EXT(SPV_INTEL_masked_gather_scatter)
5858
EXT(SPV_INTEL_tensor_float32_conversion)
5959
EXT(SPV_EXT_relaxed_printf_string_address_space)
6060
EXT(SPV_INTEL_fpga_argument_interfaces)
61+
EXT(SPV_INTEL_fpga_latency_control)

lib/SPIRV/SPIRVReader.cpp

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3399,6 +3399,16 @@ void generateIntelFPGAAnnotation(
33993399
Out << "{force_pow2_depth:" << Result << '}';
34003400
if (E->hasDecorate(DecorationBufferLocationINTEL, 0, &Result))
34013401
Out << "{sycl-buffer-location:" << Result << '}';
3402+
if (E->hasDecorate(DecorationLatencyControlLabelINTEL, 0, &Result))
3403+
Out << "{sycl-latency-anchor-id:" << Result << '}';
3404+
if (E->hasDecorate(DecorationLatencyControlConstraintINTEL)) {
3405+
auto Literals =
3406+
E->getDecorationLiterals(DecorationLatencyControlConstraintINTEL);
3407+
assert(Literals.size() == 3 &&
3408+
"Latency Control Constraint decoration shall have 3 extra operands");
3409+
Out << "{sycl-latency-constraint:" << Literals[0] << "," << Literals[1]
3410+
<< "," << Literals[2] << '}';
3411+
}
34023412

34033413
unsigned LSUParamsBitmask = 0;
34043414
llvm::SmallString<32> AdditionalParamsStr;

lib/SPIRV/SPIRVWriter.cpp

Lines changed: 53 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -2891,10 +2891,11 @@ struct AnnotationDecorations {
28912891
DecorationsInfoVec MemoryAttributesVec;
28922892
DecorationsInfoVec MemoryAccessesVec;
28932893
DecorationsInfoVec BufferLocationVec;
2894+
DecorationsInfoVec LatencyControlVec;
28942895

28952896
bool empty() {
28962897
return (MemoryAttributesVec.empty() && MemoryAccessesVec.empty() &&
2897-
BufferLocationVec.empty());
2898+
BufferLocationVec.empty() && LatencyControlVec.empty());
28982899
}
28992900
};
29002901

@@ -3028,8 +3029,8 @@ static bool tryParseAnnotationDecoValues(StringRef ValueStr,
30283029
return false;
30293030
// Skip the , delimiter and go directly to the start of next value.
30303031
ValueStart = (++I) + 1;
3032+
continue;
30313033
}
3032-
continue;
30333034
}
30343035
if (CurrentC == ',') {
30353036
// Since we are not currently in a string literal, comma denotes a
@@ -3064,7 +3065,6 @@ static bool tryParseAnnotationDecoValues(StringRef ValueStr,
30643065
AnnotationDecorations tryParseAnnotationString(SPIRVModule *BM,
30653066
StringRef AnnotatedCode) {
30663067
AnnotationDecorations Decorates;
3067-
30683068
// Annotation string decorations are separated into {word} OR
30693069
// {word:value,value,...} blocks, where value is either a word (including
30703070
// numbers) or a quotation mark enclosed string.
@@ -3088,6 +3088,8 @@ AnnotationDecorations tryParseAnnotationString(SPIRVModule *BM,
30883088
ExtensionID::SPV_INTEL_fpga_memory_attributes);
30893089
const bool AllowFPGABufLoc =
30903090
BM->isAllowedToUseExtension(ExtensionID::SPV_INTEL_fpga_buffer_location);
3091+
const bool AllowFPGALatencyControl =
3092+
BM->isAllowedToUseExtension(ExtensionID::SPV_INTEL_fpga_latency_control);
30913093

30923094
bool ValidDecorationFound = false;
30933095
DecorationsInfoVec DecorationsVec;
@@ -3111,6 +3113,12 @@ AnnotationDecorations tryParseAnnotationString(SPIRVModule *BM,
31113113
DecorationKind == DecorationBufferLocationINTEL) {
31123114
Decorates.BufferLocationVec.emplace_back(
31133115
static_cast<Decoration>(DecorationKind), std::move(DecValues));
3116+
} else if (AllowFPGALatencyControl &&
3117+
(DecorationKind == DecorationLatencyControlLabelINTEL ||
3118+
DecorationKind ==
3119+
DecorationLatencyControlConstraintINTEL)) {
3120+
Decorates.LatencyControlVec.emplace_back(
3121+
static_cast<Decoration>(DecorationKind), std::move(DecValues));
31143122
} else {
31153123
DecorationsVec.emplace_back(static_cast<Decoration>(DecorationKind),
31163124
std::move(DecValues));
@@ -3203,12 +3211,12 @@ AnnotationDecorations tryParseAnnotationString(SPIRVModule *BM,
32033211
}
32043212

32053213
std::vector<SPIRVWord>
3206-
getBankBitsFromStrings(const std::vector<std::string> &BitsStrings) {
3207-
std::vector<SPIRVWord> Bits(BitsStrings.size());
3208-
for (size_t J = 0; J < BitsStrings.size(); ++J)
3209-
if (StringRef(BitsStrings[J]).getAsInteger(10, Bits[J]))
3214+
getLiteralsFromStrings(const std::vector<std::string> &Strings) {
3215+
std::vector<SPIRVWord> Literals(Strings.size());
3216+
for (size_t J = 0; J < Strings.size(); ++J)
3217+
if (StringRef(Strings[J]).getAsInteger(10, Literals[J]))
32103218
return {};
3211-
return Bits;
3219+
return Literals;
32123220
}
32133221

32143222
void addAnnotationDecorations(SPIRVEntry *E, DecorationsInfoVec &Decorations) {
@@ -3254,7 +3262,7 @@ void addAnnotationDecorations(SPIRVEntry *E, DecorationsInfoVec &Decorations) {
32543262
I.second.size() > 0, SPIRVEC_InvalidLlvmModule,
32553263
"BankBitsINTEL requires at least one argument.");
32563264
E->addDecorate(new SPIRVDecorateBankBitsINTELAttr(
3257-
E, getBankBitsFromStrings(I.second)));
3265+
E, getLiteralsFromStrings(I.second)));
32583266
}
32593267
} break;
32603268
case DecorationRegisterINTEL:
@@ -3315,7 +3323,32 @@ void addAnnotationDecorations(SPIRVEntry *E, DecorationsInfoVec &Decorations) {
33153323
E->addDecorate(I.first, Result);
33163324
}
33173325
} break;
3318-
3326+
case DecorationLatencyControlLabelINTEL: {
3327+
if (M->isAllowedToUseExtension(
3328+
ExtensionID::SPV_INTEL_fpga_latency_control)) {
3329+
M->getErrorLog().checkError(
3330+
I.second.size() == 1, SPIRVEC_InvalidLlvmModule,
3331+
"LatencyControlLabelINTEL requires exactly 1 extra operand");
3332+
SPIRVWord Label = 0;
3333+
StringRef(I.second[0]).getAsInteger(10, Label);
3334+
E->addDecorate(
3335+
new SPIRVDecorate(DecorationLatencyControlLabelINTEL, E, Label));
3336+
}
3337+
break;
3338+
}
3339+
case DecorationLatencyControlConstraintINTEL: {
3340+
if (M->isAllowedToUseExtension(
3341+
ExtensionID::SPV_INTEL_fpga_latency_control)) {
3342+
M->getErrorLog().checkError(
3343+
I.second.size() == 3, SPIRVEC_InvalidLlvmModule,
3344+
"LatencyControlConstraintINTEL requires exactly 3 extra operands");
3345+
auto Literals = getLiteralsFromStrings(I.second);
3346+
E->addDecorate(
3347+
new SPIRVDecorate(DecorationLatencyControlConstraintINTEL, E,
3348+
Literals[0], Literals[1], Literals[2]));
3349+
}
3350+
break;
3351+
}
33193352
default:
33203353
// Other decorations are either not supported by the translator or
33213354
// handled in other places.
@@ -3364,7 +3397,7 @@ void addAnnotationDecorationsForStructMember(SPIRVEntry *E,
33643397
I.second.size() > 0, SPIRVEC_InvalidLlvmModule,
33653398
"BankBitsINTEL requires at least one argument.");
33663399
E->addMemberDecorate(new SPIRVMemberDecorateBankBitsINTELAttr(
3367-
E, MemberNumber, getBankBitsFromStrings(I.second)));
3400+
E, MemberNumber, getLiteralsFromStrings(I.second)));
33683401
break;
33693402
case DecorationRegisterINTEL:
33703403
case DecorationSinglepumpINTEL:
@@ -3581,7 +3614,7 @@ static bool allowsApproxFunction(IntrinsicInst *II) {
35813614
cast<VectorType>(Ty)->getElementType()->isFloatTy()));
35823615
}
35833616

3584-
bool allowDecorateWithBufferLocationINTEL(IntrinsicInst *II) {
3617+
bool allowDecorateWithBufferLocationOrLatencyControlINTEL(IntrinsicInst *II) {
35853618
SmallVector<Value *, 8> UserList;
35863619

35873620
for (auto *Inst : II->users()) {
@@ -4086,15 +4119,18 @@ SPIRVValue *LLVMToSPIRVBase::transIntrinsicInst(IntrinsicInst *II,
40864119
// because multiple accesses to the struct-held memory can require
40874120
// different LSU parameters.
40884121
addAnnotationDecorations(ResPtr, Decorations.MemoryAccessesVec);
4089-
if (allowDecorateWithBufferLocationINTEL(II))
4122+
if (allowDecorateWithBufferLocationOrLatencyControlINTEL(II)) {
40904123
addAnnotationDecorations(ResPtr, Decorations.BufferLocationVec);
4124+
addAnnotationDecorations(ResPtr, Decorations.LatencyControlVec);
4125+
}
40914126
}
40924127
II->replaceAllUsesWith(II->getOperand(0));
40934128
} else {
40944129
// Memory accesses to a standalone pointer variable
40954130
auto *DecSubj = transValue(II->getArgOperand(0), BB);
40964131
if (Decorations.MemoryAccessesVec.empty() &&
4097-
Decorations.BufferLocationVec.empty())
4132+
Decorations.BufferLocationVec.empty() &&
4133+
Decorations.LatencyControlVec.empty())
40984134
DecSubj->addDecorate(new SPIRVDecorateUserSemanticAttr(
40994135
DecSubj, AnnotationString.c_str()));
41004136
else {
@@ -4103,8 +4139,10 @@ SPIRVValue *LLVMToSPIRVBase::transIntrinsicInst(IntrinsicInst *II,
41034139
// loaded from the original pointer variable, and not the value
41044140
// accessed by the latter.
41054141
addAnnotationDecorations(DecSubj, Decorations.MemoryAccessesVec);
4106-
if (allowDecorateWithBufferLocationINTEL(II))
4142+
if (allowDecorateWithBufferLocationOrLatencyControlINTEL(II)) {
41074143
addAnnotationDecorations(DecSubj, Decorations.BufferLocationVec);
4144+
addAnnotationDecorations(DecSubj, Decorations.LatencyControlVec);
4145+
}
41084146
}
41094147
II->replaceAllUsesWith(II->getOperand(0));
41104148
}

lib/SPIRV/libSPIRV/SPIRVDecorate.cpp

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,16 @@ SPIRVDecorateGeneric::SPIRVDecorateGeneric(Op OC, SPIRVWord WC,
8181
updateModuleVersion();
8282
}
8383

84+
SPIRVDecorateGeneric::SPIRVDecorateGeneric(Op OC, SPIRVWord WC,
85+
Decoration TheDec,
86+
SPIRVEntry *TheTarget, SPIRVWord V1,
87+
SPIRVWord V2, SPIRVWord V3)
88+
: SPIRVDecorateGeneric(OC, WC, TheDec, TheTarget, V1, V2) {
89+
Literals.push_back(V3);
90+
validate();
91+
updateModuleVersion();
92+
}
93+
8494
SPIRVDecorateGeneric::SPIRVDecorateGeneric(Op OC)
8595
: SPIRVAnnotationGeneric(OC), Dec(DecorationRelaxedPrecision),
8696
Owner(nullptr) {}

lib/SPIRV/libSPIRV/SPIRVDecorate.h

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,11 @@ class SPIRVDecorateGeneric : public SPIRVAnnotationGeneric {
6060
// Complete constructor for decorations with two word literals
6161
SPIRVDecorateGeneric(Op OC, SPIRVWord WC, Decoration TheDec,
6262
SPIRVEntry *TheTarget, SPIRVWord V1, SPIRVWord V2);
63+
// Complete constructor for decorations with three word literals
64+
SPIRVDecorateGeneric(Op OC, SPIRVWord WC, Decoration TheDec,
65+
SPIRVEntry *TheTarget, SPIRVWord V1, SPIRVWord V2,
66+
SPIRVWord V3);
67+
6368
// Incomplete constructor
6469
SPIRVDecorateGeneric(Op OC);
6570

@@ -124,6 +129,11 @@ class SPIRVDecorate : public SPIRVDecorateGeneric {
124129
SPIRVDecorate(Decoration TheDec, SPIRVEntry *TheTarget, SPIRVWord V1,
125130
SPIRVWord V2)
126131
: SPIRVDecorateGeneric(OC, 5, TheDec, TheTarget, V1, V2) {}
132+
// Complete constructor for decorations with three word literals
133+
SPIRVDecorate(Decoration TheDec, SPIRVEntry *TheTarget, SPIRVWord V1,
134+
SPIRVWord V2, SPIRVWord V3)
135+
: SPIRVDecorateGeneric(OC, 6, TheDec, TheTarget, V1, V2, V3) {}
136+
127137
// Incomplete constructor
128138
SPIRVDecorate() : SPIRVDecorateGeneric(OC) {}
129139

@@ -188,6 +198,9 @@ class SPIRVDecorate : public SPIRVDecorateGeneric {
188198
case DecorationMMHostInterfaceMaxBurstINTEL:
189199
case DecorationMMHostInterfaceWaitRequestINTEL:
190200
return ExtensionID::SPV_INTEL_fpga_argument_interfaces;
201+
case DecorationLatencyControlLabelINTEL:
202+
case DecorationLatencyControlConstraintINTEL:
203+
return ExtensionID::SPV_INTEL_fpga_latency_control;
191204
default:
192205
return {};
193206
}

lib/SPIRV/libSPIRV/SPIRVEnum.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -487,6 +487,10 @@ template <> inline void SPIRVMap<Decoration, SPIRVCapVec>::init() {
487487
{CapabilityFPGAArgumentInterfacesINTEL});
488488
ADD_VEC_INIT(DecorationStableKernelArgumentINTEL,
489489
{CapabilityFPGAArgumentInterfacesINTEL});
490+
ADD_VEC_INIT(DecorationLatencyControlLabelINTEL,
491+
{CapabilityFPGALatencyControlINTEL});
492+
ADD_VEC_INIT(DecorationLatencyControlConstraintINTEL,
493+
{CapabilityFPGALatencyControlINTEL});
490494
}
491495

492496
template <> inline void SPIRVMap<BuiltIn, SPIRVCapVec>::init() {

lib/SPIRV/libSPIRV/SPIRVNameMapEnum.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -196,6 +196,8 @@ template <> inline void SPIRVMap<Decoration, std::string>::init() {
196196
add(DecorationMMHostInterfaceWaitRequestINTEL,
197197
"MMHostInterfaceWaitRequestINTEL");
198198
add(DecorationStableKernelArgumentINTEL, "StableKernelArgumentINTEL");
199+
add(DecorationLatencyControlLabelINTEL, "LatencyControlLabelINTEL");
200+
add(DecorationLatencyControlConstraintINTEL, "LatencyControlConstraintINTEL");
199201

200202
// From spirv_internal.hpp
201203
add(internal::DecorationCallableFunctionINTEL, "CallableFunctionINTEL");
@@ -617,7 +619,7 @@ template <> inline void SPIRVMap<Capability, std::string>::init() {
617619
add(CapabilityRuntimeAlignedAttributeINTEL, "RuntimeAlignedAttributeINTEL");
618620
add(CapabilityMax, "Max");
619621
add(CapabilityFPGAArgumentInterfacesINTEL, "FPGAArgumentInterfacesINTEL");
620-
622+
add(CapabilityFPGALatencyControlINTEL, "FPGALatencyControlINTEL");
621623
// From spirv_internal.hpp
622624
add(internal::CapabilityFastCompositeINTEL, "FastCompositeINTEL");
623625
add(internal::CapabilityOptNoneINTEL, "OptNoneINTEL");

spirv-headers-tag.conf

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
295cf5fb3bfe2454360e82b26bae7fc0de699abe
1+
1feaf4414eb2b353764d01d88f8aa4bcc67b60db
Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
; RUN: llvm-as %s -o %t.bc
2+
; RUN: llvm-spirv %t.bc --spirv-ext=+SPV_INTEL_fpga_latency_control -o %t.spv
3+
; RUN: llvm-spirv %t.spv -to-text -o %t.spt
4+
; RUN: FileCheck < %t.spt %s --check-prefix=CHECK-SPIRV
5+
6+
; RUN: llvm-spirv -r -emit-opaque-pointers %t.spv -o %t.rev.bc
7+
; RUN: llvm-dis < %t.rev.bc | FileCheck %s --check-prefix=CHECK-LLVM
8+
9+
; CHECK-SPIRV: Capability FPGALatencyControlINTEL
10+
; CHECK-SPIRV: Extension "SPV_INTEL_fpga_latency_control"
11+
; CHECK-SPIRV: Decorate [[#ARGA:]] LatencyControlLabelINTEL 0
12+
; CHECK-SPIRV: Decorate [[#ARGB:]] LatencyControlLabelINTEL 1
13+
; CHECK-SPIRV: Decorate [[#ARGB]] LatencyControlConstraintINTEL 0 1 5
14+
; CHECK-SPIRV: Bitcast [[#]] [[#OUT1:]] [[#ARGA]]
15+
; CHECK-SPIRV-DAG: Bitcast [[#]] [[#OUT2:]] [[#OUT1]]
16+
; CHECK-SPIRV-DAG: Load [[#]] [[#]] [[#OUT2]] [[#]] [[#]]
17+
; CHECK-SPIRV: Bitcast [[#]] [[#OUT3:]] [[#ARGB]]
18+
; CHECK-SPIRV-DAG: Bitcast [[#]] [[#OUT4:]] [[#OUT3]]
19+
; CHECK-SPIRV-DAG: Load [[#]] [[#]] [[#OUT4]] [[#]] [[#]]
20+
21+
target datalayout = "e-i64:64-v16:16-v24:32-v32:32-v48:64-v96:128-v192:256-v256:256-v512:512-v1024:1024-n8:16:32:64"
22+
target triple = "spir64-unknown-unknown"
23+
24+
%struct.__spirv_Something = type { i32, i32 }
25+
26+
$_ZTSZ4fooEUlvE_ = comdat any
27+
28+
@.str = private unnamed_addr constant [16 x i8] c"sycl-properties\00", section "llvm.metadata"
29+
@.str.1 = private unnamed_addr constant [19 x i8] c"inc/fpga_utils.hpp\00", section "llvm.metadata"
30+
@.str.9 = private unnamed_addr constant [11 x i8] c"{6172:\220\22}\00", section "llvm.metadata"
31+
@.str.10 = private unnamed_addr constant [25 x i8] c"{6172:\221\22}{6173:\220,1,5\22}\00", section "llvm.metadata"
32+
33+
; CHECK-LLVM: @[[#ANN_STR1:]] = private unnamed_addr constant [27 x i8] c"{sycl-latency-anchor-id:0}\00"
34+
; CHECK-LLVM: @[[#ANN_STR2:]] = private unnamed_addr constant [58 x i8] c"{sycl-latency-anchor-id:1}{sycl-latency-constraint:0,1,5}\00"
35+
36+
; Function Attrs: mustprogress norecurse
37+
define weak_odr dso_local spir_kernel void @_ZTSZ4fooEUlvE_(ptr %0) local_unnamed_addr #0 comdat !kernel_arg_buffer_location !5 !sycl_kernel_omit_args !5 {
38+
entry:
39+
%1 = alloca ptr, align 8
40+
store ptr %0, ptr %1, align 8
41+
%2 = load ptr, ptr %1, align 8
42+
%3 = getelementptr inbounds %struct.__spirv_Something, ptr %2, i32 0, i32 0
43+
%4 = bitcast ptr %3 to ptr
44+
; CHECK-LLVM: %[[#ANN_PTR1:]] = getelementptr inbounds %struct.__spirv_Something, ptr %[[#]], i32 0, i32 0
45+
%5 = call ptr @llvm.ptr.annotation.p0.p0(ptr %4, ptr @.str.9, ptr @.str.1, i32 5, ptr null)
46+
; CHECK-LLVM: call ptr @llvm.ptr.annotation.p0.p0(ptr %[[#ANN_PTR1]], ptr @[[#ANN_STR1]], ptr undef, i32 undef, ptr undef)
47+
%6 = load i32, ptr %5, align 8
48+
%7 = load ptr, ptr %1, align 8
49+
%8 = getelementptr inbounds %struct.__spirv_Something, ptr %7, i32 0, i32 1
50+
%9 = bitcast ptr %8 to ptr
51+
; CHECK-LLVM: %[[#ANN_PTR2:]] = getelementptr inbounds %struct.__spirv_Something, ptr %[[#]], i32 0, i32 1
52+
%10 = call ptr @llvm.ptr.annotation.p0.p0(ptr %9, ptr @.str.10, ptr @.str.1, i32 5, ptr null)
53+
; CHECK-LLVM: call ptr @llvm.ptr.annotation.p0.p0(ptr %[[#ANN_PTR2]], ptr @[[#ANN_STR2]], ptr undef, i32 undef, ptr undef)
54+
%11 = load i32, ptr %10, align 8
55+
ret void
56+
}
57+
58+
; Function Attrs: nocallback nofree nosync nounwind willreturn memory(inaccessiblemem: readwrite)
59+
declare ptr @llvm.ptr.annotation.p0.p0(ptr, ptr, ptr, i32, ptr) #1
60+
61+
attributes #0 = { mustprogress norecurse "frame-pointer"="all" "min-legal-vector-width"="0" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "sycl-module-id"="sycl-properties-ptr-annotations.cpp" "uniform-work-group-size"="true" }
62+
attributes #1 = { nocallback nofree nosync nounwind willreturn memory(inaccessiblemem: readwrite) }
63+
64+
!opencl.spir.version = !{!0, !0, !0, !0, !0, !0}
65+
!spirv.Source = !{!1, !1, !1, !1, !1, !1}
66+
!llvm.ident = !{!2, !2, !2, !2, !2, !2}
67+
!llvm.module.flags = !{!3, !4}
68+
69+
!0 = !{i32 1, i32 2}
70+
!1 = !{i32 4, i32 100000}
71+
!2 = !{!"clang version 15.0.0"}
72+
!3 = !{i32 1, !"wchar_size", i32 4}
73+
!4 = !{i32 7, !"frame-pointer", i32 2}
74+
!5 = !{}

0 commit comments

Comments
 (0)