Skip to content

Commit e303a5f

Browse files
MrSidimsAlexeySotkin
authored andcommitted
Implement SPV_INTEL_fpga_invocation_pipelining_attributes extension
Some FPGA devices and toolchains can support customizable levels or implementation of pipeline parallelism when mapping a SPIR-V module to hardware. Through pipeline parallelism, multiple invocations of a kernel or function can execute concurrently. This extension adds decorations to request that a kernel or function support invocations at a specified initiation interval, that multiple invocations are forbidden from executing concurrently, or that the kernel or function is limited to a maximum number of concurrent invocations. Spec: https://github.com/KhronosGroup/SPIRV-Registry/blob/38a7e56b9b7feab7fa8b3bea08770f7232b76ed2/extensions/INTEL/SPV_INTEL_fpga_invocation_pipelining_attributes.asciidoc Signed-off-by: Dmitry Sidorov <dmitry.sidorov@intel.com>
1 parent b768773 commit e303a5f

File tree

9 files changed

+146
-18
lines changed

9 files changed

+146
-18
lines changed

include/LLVMSPIRVExtensions.inc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,3 +37,4 @@ EXT(SPV_INTEL_loop_fuse)
3737
EXT(SPV_INTEL_long_constant_composite)
3838
EXT(SPV_INTEL_optnone)
3939
EXT(SPV_INTEL_memory_access_aliasing)
40+
EXT(SPV_INTEL_fpga_invocation_pipelining_attributes)

lib/SPIRV/SPIRVInternal.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -406,6 +406,9 @@ const static char NumSIMD[] = "num_simd_work_items";
406406
const static char StallEnable[] = "stall_enable";
407407
const static char FmaxMhz[] = "scheduler_target_fmax_mhz";
408408
const static char LoopFuse[] = "loop_fuse";
409+
const static char InitiationInterval[] = "initiation_interval";
410+
const static char MaxConcurrency[] = "max_concurrency";
411+
const static char DisableLoopPipelining[] = "disable_loop_pipelining";
409412
} // namespace kSPIR2MD
410413

411414
enum Spir2SamplerKind {

lib/SPIRV/SPIRVReader.cpp

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4272,6 +4272,32 @@ bool SPIRVToLLVM::transFPGAFunctionMetadata(SPIRVFunction *BF, Function *F) {
42724272
MetadataVec.push_back(ConstantAsMetadata::get(getUInt32(M, Literals[1])));
42734273
F->setMetadata(kSPIR2MD::LoopFuse, MDNode::get(*Context, MetadataVec));
42744274
}
4275+
if (BF->hasDecorate(internal::DecorationInitiationIntervalINTEL)) {
4276+
std::vector<Metadata *> MetadataVec;
4277+
auto Literals =
4278+
BF->getDecorationLiterals(internal::DecorationInitiationIntervalINTEL);
4279+
MetadataVec.push_back(ConstantAsMetadata::get(getUInt32(M, Literals[0])));
4280+
F->setMetadata(kSPIR2MD::InitiationInterval,
4281+
MDNode::get(*Context, MetadataVec));
4282+
}
4283+
if (BF->hasDecorate(internal::DecorationMaxConcurrencyINTEL)) {
4284+
std::vector<Metadata *> MetadataVec;
4285+
auto Literals =
4286+
BF->getDecorationLiterals(internal::DecorationMaxConcurrencyINTEL);
4287+
MetadataVec.push_back(ConstantAsMetadata::get(getUInt32(M, Literals[0])));
4288+
F->setMetadata(kSPIR2MD::MaxConcurrency,
4289+
MDNode::get(*Context, MetadataVec));
4290+
}
4291+
if (BF->hasDecorate(internal::DecorationPipelineEnableINTEL)) {
4292+
auto Literals =
4293+
BF->getDecorationLiterals(internal::DecorationPipelineEnableINTEL);
4294+
if (!Literals[0]) {
4295+
std::vector<Metadata *> MetadataVec;
4296+
MetadataVec.push_back(ConstantAsMetadata::get(getInt32(M, 1)));
4297+
F->setMetadata(kSPIR2MD::DisableLoopPipelining,
4298+
MDNode::get(*Context, MetadataVec));
4299+
}
4300+
}
42754301
return true;
42764302
}
42774303

lib/SPIRV/SPIRVWriter.cpp

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -728,6 +728,29 @@ void LLVMToSPIRVBase::transFPGAFunctionMetadata(SPIRVFunction *BF,
728728
new SPIRVDecorateFuseLoopsInFunctionINTEL(BF, Depth, Independent));
729729
}
730730
}
731+
if (MDNode *InitiationInterval =
732+
F->getMetadata(kSPIR2MD::InitiationInterval)) {
733+
if (BM->isAllowedToUseExtension(
734+
ExtensionID::SPV_INTEL_fpga_invocation_pipelining_attributes)) {
735+
if (size_t Cycles = getMDOperandAsInt(InitiationInterval, 0))
736+
BF->addDecorate(new SPIRVDecorateInitiationIntervalINTEL(BF, Cycles));
737+
}
738+
}
739+
if (MDNode *MaxConcurrency = F->getMetadata(kSPIR2MD::MaxConcurrency)) {
740+
if (BM->isAllowedToUseExtension(
741+
ExtensionID::SPV_INTEL_fpga_invocation_pipelining_attributes)) {
742+
size_t Invocations = getMDOperandAsInt(MaxConcurrency, 0);
743+
BF->addDecorate(new SPIRVDecorateMaxConcurrencyINTEL(BF, Invocations));
744+
}
745+
}
746+
if (MDNode *DisableLoopPipelining =
747+
F->getMetadata(kSPIR2MD::DisableLoopPipelining)) {
748+
if (BM->isAllowedToUseExtension(
749+
ExtensionID::SPV_INTEL_fpga_invocation_pipelining_attributes)) {
750+
if (size_t Disable = getMDOperandAsInt(DisableLoopPipelining, 0))
751+
BF->addDecorate(new SPIRVDecoratePipelineEnableINTEL(BF, !Disable));
752+
}
753+
}
731754
}
732755

733756
SPIRVValue *LLVMToSPIRVBase::transConstant(Value *V) {

lib/SPIRV/libSPIRV/SPIRVDecorate.h

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -154,7 +154,7 @@ class SPIRVDecorate : public SPIRVDecorateGeneric {
154154
SPIRVDecorate() : SPIRVDecorateGeneric(OC) {}
155155

156156
llvm::Optional<ExtensionID> getRequiredExtension() const override {
157-
switch (Dec) {
157+
switch (static_cast<size_t>(Dec)) {
158158
case DecorationNoSignedWrap:
159159
case DecorationNoUnsignedWrap:
160160
return ExtensionID::SPV_KHR_no_integer_wrap_decoration;
@@ -192,6 +192,12 @@ class SPIRVDecorate : public SPIRVDecorateGeneric {
192192
return ExtensionID::SPV_INTEL_loop_fuse;
193193
case DecorationCallableFunctionINTEL:
194194
return ExtensionID::SPV_INTEL_fast_composite;
195+
case internal::DecorationInitiationIntervalINTEL:
196+
return ExtensionID::SPV_INTEL_fpga_invocation_pipelining_attributes;
197+
case internal::DecorationMaxConcurrencyINTEL:
198+
return ExtensionID::SPV_INTEL_fpga_invocation_pipelining_attributes;
199+
case internal::DecorationPipelineEnableINTEL:
200+
return ExtensionID::SPV_INTEL_fpga_invocation_pipelining_attributes;
195201
default:
196202
return {};
197203
}
@@ -682,6 +688,30 @@ class SPIRVDecorateNoAliasINTEL : public SPIRVDecorateId {
682688
AliasList){};
683689
};
684690

691+
class SPIRVDecorateInitiationIntervalINTEL : public SPIRVDecorate {
692+
public:
693+
// Complete constructor for SPIRVDecorateInitiationIntervalINTEL
694+
SPIRVDecorateInitiationIntervalINTEL(SPIRVEntry *TheTarget, SPIRVWord Cycles)
695+
: SPIRVDecorate(spv::internal::DecorationInitiationIntervalINTEL,
696+
TheTarget, Cycles){};
697+
};
698+
699+
class SPIRVDecorateMaxConcurrencyINTEL : public SPIRVDecorate {
700+
public:
701+
// Complete constructor for SPIRVDecorateMaxConcurrencyINTEL
702+
SPIRVDecorateMaxConcurrencyINTEL(SPIRVEntry *TheTarget, SPIRVWord Invocations)
703+
: SPIRVDecorate(spv::internal::DecorationMaxConcurrencyINTEL, TheTarget,
704+
Invocations){};
705+
};
706+
707+
class SPIRVDecoratePipelineEnableINTEL : public SPIRVDecorate {
708+
public:
709+
// Complete constructor for SPIRVDecoratePipelineEnableINTEL
710+
SPIRVDecoratePipelineEnableINTEL(SPIRVEntry *TheTarget, SPIRVWord Enable)
711+
: SPIRVDecorate(spv::internal::DecorationPipelineEnableINTEL, TheTarget,
712+
Enable){};
713+
};
714+
685715
} // namespace SPIRV
686716

687717
#endif // SPIRV_LIBSPIRV_SPIRVDECORATE_H

lib/SPIRV/libSPIRV/SPIRVEnum.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -429,6 +429,12 @@ template <> inline void SPIRVMap<Decoration, SPIRVCapVec>::init() {
429429
{internal::CapabilityMemoryAccessAliasingINTEL});
430430
ADD_VEC_INIT(internal::DecorationNoAliasINTEL,
431431
{internal::CapabilityMemoryAccessAliasingINTEL});
432+
ADD_VEC_INIT(internal::DecorationInitiationIntervalINTEL,
433+
{internal::CapabilityFPGAInvocationPipeliningAttributesINTEL});
434+
ADD_VEC_INIT(internal::DecorationMaxConcurrencyINTEL,
435+
{internal::CapabilityFPGAInvocationPipeliningAttributesINTEL});
436+
ADD_VEC_INIT(internal::DecorationPipelineEnableINTEL,
437+
{internal::CapabilityFPGAInvocationPipeliningAttributesINTEL});
432438
}
433439

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

lib/SPIRV/libSPIRV/SPIRVNameMapEnum.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -169,6 +169,9 @@ template <> inline void SPIRVMap<Decoration, std::string>::init() {
169169
add(DecorationFuseLoopsInFunctionINTEL, "FuseLoopsInFunctionINTEL");
170170
add(internal::DecorationAliasScopeINTEL, "AliasScopeINTEL");
171171
add(internal::DecorationNoAliasINTEL, "NoAliasINTEL");
172+
add(internal::DecorationInitiationIntervalINTEL, "InitiationIntervalINTEL");
173+
add(internal::DecorationMaxConcurrencyINTEL, "MaxConcurrencyINTEL");
174+
add(internal::DecorationPipelineEnableINTEL, "PipelineEnableINTEL");
172175
add(DecorationMax, "Max");
173176
}
174177
SPIRV_DEF_NAMEMAP(Decoration, SPIRVDecorationNameMap)
@@ -520,6 +523,8 @@ template <> inline void SPIRVMap<Capability, std::string>::init() {
520523
add(internal::CapabilityOptNoneINTEL, "OptNoneINTEL");
521524
add(internal::CapabilityMemoryAccessAliasingINTEL,
522525
"MemoryAccessAliasingINTEL");
526+
add(internal::CapabilityFPGAInvocationPipeliningAttributesINTEL,
527+
"FPGAInvocationPipeliningAttributesINTEL");
523528
}
524529
SPIRV_DEF_NAMEMAP(Capability, SPIRVCapabilityNameMap)
525530

lib/SPIRV/libSPIRV/spirv_internal.hpp

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,11 +44,15 @@ enum InternalOp {
4444

4545
enum InternalDecoration {
4646
IDecAliasScopeINTEL = 5914,
47-
IDecNoAliasINTEL = 5915
47+
IDecNoAliasINTEL = 5915,
48+
IDecInitiationIntervalINTEL = 5917,
49+
IDecMaxConcurrencyINTEL = 5918,
50+
IDecPipelineEnableINTEL = 5919
4851
};
4952

5053
enum InternalCapability {
5154
ICapMemoryAccessAliasingINTEL = 5910,
55+
ICapFPGAInvocationPipeliningAttributesINTEL = 5916,
5256
ICapOptNoneINTEL = 6094
5357
};
5458

@@ -72,11 +76,19 @@ constexpr Decoration DecorationAliasScopeINTEL =
7276
static_cast<Decoration>(IDecAliasScopeINTEL );
7377
constexpr Decoration DecorationNoAliasINTEL =
7478
static_cast<Decoration>(IDecNoAliasINTEL);
79+
constexpr Decoration DecorationInitiationIntervalINTEL =
80+
static_cast<Decoration>(IDecInitiationIntervalINTEL);
81+
constexpr Decoration DecorationMaxConcurrencyINTEL =
82+
static_cast<Decoration>(IDecMaxConcurrencyINTEL);
83+
constexpr Decoration DecorationPipelineEnableINTEL =
84+
static_cast<Decoration>(IDecPipelineEnableINTEL);
7585

7686
constexpr Capability CapabilityOptNoneINTEL =
7787
static_cast<Capability>(ICapOptNoneINTEL);
7888
constexpr Capability CapabilityMemoryAccessAliasingINTEL =
7989
static_cast<Capability>(ICapMemoryAccessAliasingINTEL);
90+
constexpr Capability CapabilityFPGAInvocationPipeliningAttributesINTEL =
91+
static_cast<Capability>(ICapFPGAInvocationPipeliningAttributesINTEL);
8092

8193
constexpr FunctionControlMask FunctionControlOptNoneINTELMask =
8294
static_cast<FunctionControlMask>(IFunctionControlOptNoneINTELMask);

test/transcoding/IntelFPGAFunctionAttributes.ll

Lines changed: 38 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,10 @@
77
;; intel::num_simd_work_items(8),
88
;; intel::stall_enable,
99
;; intel::scheduler_target_fmax_mhz(1000),
10-
;; intel::loop_fuse_independent(3)]] void operator()() {}
10+
;; intel::loop_fuse_independent(3),
11+
;; intel::initiation_interval(10),
12+
;; intel::max_concurrency(12),
13+
;; intel::disable_loop_pipelining]] void operator()() {}
1114
;; };
1215
;;
1316
;; template <typename name, typename Func>
@@ -22,7 +25,7 @@
2225
;; }
2326

2427
; RUN: llvm-as %s -o %t.bc
25-
; RUN: llvm-spirv %t.bc --spirv-ext=+SPV_INTEL_kernel_attributes --spirv-ext=+SPV_INTEL_fpga_cluster_attributes,+SPV_INTEL_loop_fuse -o %t.spv
28+
; RUN: llvm-spirv %t.bc --spirv-ext=+SPV_INTEL_kernel_attributes,+SPV_INTEL_fpga_cluster_attributes,+SPV_INTEL_loop_fuse,+SPV_INTEL_fpga_invocation_pipelining_attributes -o %t.spv
2629
; RUN: llvm-spirv %t.spv -to-text -o %t.spt
2730
; RUN: FileCheck < %t.spt %s --check-prefix=CHECK-SPIRV
2831

@@ -32,24 +35,41 @@
3235
; RUN: llvm-spirv -spirv-text -r %t.spt -o %t.rev.bc
3336
; RUN: llvm-dis < %t.rev.bc | FileCheck %s --check-prefix=CHECK-LLVM
3437

35-
; CHECK-SPIRV: 2 Capability KernelAttributesINTEL
36-
; CHECK-SPIRV: 2 Capability FPGAKernelAttributesINTEL
37-
; CHECK-SPIRV: 2 Capability FPGAClusterAttributesINTEL
38-
; CHECK-SPIRV: 2 Capability LoopFuseINTEL
39-
; CHECK-SPIRV: 6 ExecutionMode [[FUNCENTRY:[0-9]+]] 5893 1 1 1
40-
; CHECK-SPIRV: 4 ExecutionMode [[FUNCENTRY]] 5894 1
41-
; CHECK-SPIRV: 3 ExecutionMode [[FUNCENTRY]] 5895
42-
; CHECK-SPIRV: 4 ExecutionMode [[FUNCENTRY]] 5896 8
43-
; CHECK-SPIRV: 4 ExecutionMode [[FUNCENTRY]] 5903 1000
44-
; CHECK-SPIRV: 3 Decorate [[FUNCENTRY]] StallEnableINTEL
45-
; CHECK-SPIRV: 5 Decorate [[FUNCENTRY]] FuseLoopsInFunctionINTEL 3 1
46-
; CHECK-SPIRV: 5 Function {{.*}} [[FUNCENTRY]] {{.*}}
38+
; CHECK-SPIRV: Capability KernelAttributesINTEL
39+
; CHECK-SPIRV: Capability FPGAKernelAttributesINTEL
40+
; CHECK-SPIRV: Capability FPGAClusterAttributesINTEL
41+
; CHECK-SPIRV: Capability LoopFuseINTEL
42+
; CHECK-SPIRV: Capability FPGAInvocationPipeliningAttributesINTEL
43+
; CHECK-SPIRV: Extension "SPV_INTEL_fpga_cluster_attributes"
44+
; CHECK-SPIRV: Extension "SPV_INTEL_fpga_invocation_pipelining_attributes"
45+
; CHECK-SPIRV: Extension "SPV_INTEL_loop_fuse"
46+
; CHECK-SPIRV: ExecutionMode [[FUNCENTRY:[0-9]+]] 5893 1 1 1
47+
; CHECK-SPIRV: ExecutionMode [[FUNCENTRY]] 5894 1
48+
; CHECK-SPIRV: ExecutionMode [[FUNCENTRY]] 5895
49+
; CHECK-SPIRV: ExecutionMode [[FUNCENTRY]] 5896 8
50+
; CHECK-SPIRV: ExecutionMode [[FUNCENTRY]] 5903 1000
51+
; CHECK-SPIRV: Decorate [[FUNCENTRY]] StallEnableINTEL
52+
; CHECK-SPIRV: Decorate [[FUNCENTRY]] FuseLoopsInFunctionINTEL 3 1
53+
; CHECK-SPIRV: Decorate [[FUNCENTRY]] InitiationIntervalINTEL 10
54+
; CHECK-SPIRV: Decorate [[FUNCENTRY]] MaxConcurrencyINTEL 12
55+
; CHECK-SPIRV: Decorate [[FUNCENTRY]] PipelineEnableINTEL 0
56+
; CHECK-SPIRV: Function {{.*}} [[FUNCENTRY]] {{.*}}
4757

48-
; CHECK-LLVM: define spir_kernel void {{.*}}kernel_name() {{.*}} !stall_enable ![[ONEMD:[0-9]+]] !loop_fuse ![[FUSE:[0-9]+]] !max_work_group_size ![[MAXWG:[0-9]+]] !no_global_work_offset ![[OFFSET:[0-9]+]] !max_global_work_dim ![[ONEMD:[0-9]+]] !num_simd_work_items ![[NUMSIMD:[0-9]+]] !scheduler_target_fmax_mhz ![[MAXMHZ:[0-9]+]]
58+
; CHECK-LLVM: define spir_kernel void {{.*}}kernel_name()
59+
; CHECK-LLVM-SAME: !stall_enable ![[ONEMD:[0-9]+]] !loop_fuse ![[FUSE:[0-9]+]]
60+
; CHECK-LLVM-SAME: !initiation_interval ![[II:[0-9]+]]
61+
; CHECK-LLVM-SAME: !max_concurrency ![[MAXCON:[0-9]+]]
62+
; CHECK-LLVM-SAME: !disable_loop_pipelining ![[ONEMD]]
63+
; CHECK-LLVM-SAME: !max_work_group_size ![[MAXWG:[0-9]+]]
64+
; CHECK-LLVM-SAME: !no_global_work_offset ![[OFFSET:[0-9]+]]
65+
; CHECK-LLVM-SAME: !max_global_work_dim ![[ONEMD]] !num_simd_work_items ![[NUMSIMD:[0-9]+]]
66+
; CHECK-LLVM-SAME: !scheduler_target_fmax_mhz ![[MAXMHZ:[0-9]+]]
4967
; CHECK-LLVM-NOT: define spir_kernel void {{.*}}kernel_name2 {{.*}} !no_global_work_offset {{.*}}
5068
; CHECK-LLVM: ![[OFFSET]] = !{}
5169
; CHECK-LLVM: ![[ONEMD]] = !{i32 1}
5270
; CHECK-LLVM: ![[FUSE]] = !{i32 3, i32 1}
71+
; CHECK-LLVM: ![[II]] = !{i32 10}
72+
; CHECK-LLVM: ![[MAXCON]] = !{i32 12}
5373
; CHECK-LLVM: ![[MAXWG]] = !{i32 1, i32 1, i32 1}
5474
; CHECK-LLVM: ![[NUMSIMD]] = !{i32 8}
5575
; CHECK-LLVM: ![[MAXMHZ]] = !{i32 1000}
@@ -65,7 +85,7 @@ target triple = "spir64-unknown-linux-sycldevice"
6585
$_ZN3FooclEv = comdat any
6686

6787
; Function Attrs: nounwind
68-
define spir_kernel void @_ZTSZ3barvE11kernel_name() #0 !kernel_arg_addr_space !4 !kernel_arg_access_qual !4 !kernel_arg_type !4 !kernel_arg_base_type !4 !kernel_arg_type_qual !4 !num_simd_work_items !5 !max_work_group_size !6 !max_global_work_dim !7 !no_global_work_offset !4 !stall_enable !7 !scheduler_target_fmax_mhz !12 !loop_fuse !13 {
88+
define spir_kernel void @_ZTSZ3barvE11kernel_name() #0 !kernel_arg_addr_space !4 !kernel_arg_access_qual !4 !kernel_arg_type !4 !kernel_arg_base_type !4 !kernel_arg_type_qual !4 !num_simd_work_items !5 !max_work_group_size !6 !max_global_work_dim !7 !no_global_work_offset !4 !stall_enable !7 !scheduler_target_fmax_mhz !12 !loop_fuse !13 !initiation_interval !14 !max_concurrency !15 !disable_loop_pipelining !7 {
6989
entry:
7090
%Foo = alloca %class._ZTS3Foo.Foo, align 1
7191
%0 = bitcast %class._ZTS3Foo.Foo* %Foo to i8*
@@ -137,3 +157,5 @@ attributes #4 = { nounwind }
137157
!11 = !{!"Simple C++ TBAA"}
138158
!12 = !{i32 1000}
139159
!13 = !{i32 3, i32 1}
160+
!14 = !{i32 10}
161+
!15 = !{i32 12}

0 commit comments

Comments
 (0)