Skip to content

Commit 4d66fe7

Browse files
authored
Implement StreamingInterfaceINTEL execution mode (#1218)
In an FPGA design, one may want to control the interface that a kernel exposes to the rest of the design. This extension adds a new Execution Mode to indicate that the kernel has a streaming interface, in which invocation and return is synchronized by a handshaking protocol. The decision whether to add StreamingInterfaceINTEL execution mode with 0/1 literal is based on the kernel metadata, in case of: !ip_interface !N !N = !{!"streaming"} the translator emits StreamingInterfaceINTEL 0 and !ip_interface !N !N = !{!"streaming", !"stall_free_return"} the translator emits StreamingInterfaceINTEL 1 Spec update: KhronosGroup/SPIRV-Registry#130 Signed-off-by: Dmitry Sidorov <[email protected]>
1 parent 08884df commit 4d66fe7

10 files changed

+112
-4
lines changed

lib/SPIRV/PreprocessMetadata.cpp

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -256,6 +256,34 @@ void PreprocessMetadataBase::visit(Module *M) {
256256
.add(getMDOperandAsInt(SchedulerTargetFmaxMhzINTEL, 0))
257257
.done();
258258
}
259+
260+
// !{void (i32 addrspace(1)*)* @kernel, i32 ip_interface, i32 interface}
261+
if (MDNode *Interface =
262+
Kernel.getMetadata(kSPIR2MD::IntelFPGAIPInterface)) {
263+
std::set<std::string> InterfaceStrSet;
264+
// Default mode is 'csr' aka !ip_interface !N
265+
// !N = !{!”csr”}
266+
// don't emit any particular SPIR-V for it
267+
// Streaming mode metadata be like:
268+
// Not 'stall free' mode (to be mapped on '0' literal)
269+
// !ip_interface !N
270+
// !N = !{!"streaming"}
271+
// 'stall free' mode (to be mapped on '1' literal)
272+
// !ip_interface !N
273+
// !N = !{!"streaming", !"stall_free_return"}
274+
for (size_t I = 0; I != Interface->getNumOperands(); ++I)
275+
InterfaceStrSet.insert(getMDOperandAsString(Interface, I));
276+
if (InterfaceStrSet.find("streaming") != InterfaceStrSet.end()) {
277+
int32_t InterfaceMode = 0;
278+
if (InterfaceStrSet.find("stall_free_return") != InterfaceStrSet.end())
279+
InterfaceMode = 1;
280+
EM.addOp()
281+
.add(&Kernel)
282+
.add(spv::internal::ExecutionModeStreamingInterfaceINTEL)
283+
.add(InterfaceMode)
284+
.done();
285+
}
286+
}
259287
}
260288
}
261289

lib/SPIRV/SPIRVInternal.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -428,6 +428,7 @@ const static char PropDSPPref[] = "propagate_dsp_preference";
428428
const static char InitiationInterval[] = "initiation_interval";
429429
const static char MaxConcurrency[] = "max_concurrency";
430430
const static char DisableLoopPipelining[] = "disable_loop_pipelining";
431+
const static char IntelFPGAIPInterface[] = "ip_interface";
431432
} // namespace kSPIR2MD
432433

433434
enum Spir2SamplerKind {

lib/SPIRV/SPIRVReader.cpp

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3785,6 +3785,27 @@ bool SPIRVToLLVM::transMetadata() {
37853785
F->setMetadata(kSPIR2MD::FmaxMhz,
37863786
getMDNodeStringIntVec(Context, EM->getLiterals()));
37873787
}
3788+
// Generate metadata for Intel FPGA streaming interface
3789+
if (auto *EM = BF->getExecutionMode(
3790+
internal::ExecutionModeStreamingInterfaceINTEL)) {
3791+
std::vector<uint32_t> InterfaceVec = EM->getLiterals();
3792+
assert(InterfaceVec.size() == 1 &&
3793+
"Expected StreamingInterfaceINTEL to have exactly 1 literal");
3794+
std::vector<Metadata *> InterfaceMDVec =
3795+
[&]() -> std::vector<Metadata *> {
3796+
switch (InterfaceVec[0]) {
3797+
case 0:
3798+
return {MDString::get(*Context, "streaming")};
3799+
case 1:
3800+
return {MDString::get(*Context, "streaming"),
3801+
MDString::get(*Context, "stall_free_return")};
3802+
default:
3803+
llvm_unreachable("Invalid streaming interface mode");
3804+
}
3805+
}();
3806+
F->setMetadata(kSPIR2MD::IntelFPGAIPInterface,
3807+
MDNode::get(*Context, InterfaceMDVec));
3808+
}
37883809
}
37893810
NamedMDNode *MemoryModelMD =
37903811
M->getOrInsertNamedMetadata(kSPIRVMD::MemoryModel);

lib/SPIRV/SPIRVWriter.cpp

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3844,6 +3844,7 @@ bool LLVMToSPIRVBase::transExecutionMode() {
38443844
N.get(X).get(Y).get(Z);
38453845
BF->addExecutionMode(BM->add(new SPIRVExecutionMode(
38463846
BF, static_cast<ExecutionMode>(EMode), X, Y, Z)));
3847+
BM->addExtension(ExtensionID::SPV_INTEL_kernel_attributes);
38473848
BM->addCapability(CapabilityKernelAttributesINTEL);
38483849
}
38493850
} break;
@@ -3853,6 +3854,7 @@ bool LLVMToSPIRVBase::transExecutionMode() {
38533854
break;
38543855
BF->addExecutionMode(BM->add(
38553856
new SPIRVExecutionMode(BF, static_cast<ExecutionMode>(EMode))));
3857+
BM->addExtension(ExtensionID::SPV_INTEL_kernel_attributes);
38563858
BM->addCapability(CapabilityKernelAttributesINTEL);
38573859
} break;
38583860
case spv::ExecutionModeVecTypeHint:
@@ -3862,11 +3864,13 @@ bool LLVMToSPIRVBase::transExecutionMode() {
38623864
break;
38633865
case spv::ExecutionModeNumSIMDWorkitemsINTEL:
38643866
case spv::ExecutionModeSchedulerTargetFmaxMhzINTEL:
3865-
case spv::ExecutionModeMaxWorkDimINTEL: {
3867+
case spv::ExecutionModeMaxWorkDimINTEL:
3868+
case spv::internal::ExecutionModeStreamingInterfaceINTEL: {
38663869
if (!BM->isAllowedToUseExtension(
38673870
ExtensionID::SPV_INTEL_kernel_attributes))
38683871
break;
38693872
AddSingleArgExecutionMode(static_cast<ExecutionMode>(EMode));
3873+
BM->addExtension(ExtensionID::SPV_INTEL_kernel_attributes);
38703874
BM->addCapability(CapabilityFPGAKernelAttributesINTEL);
38713875
} break;
38723876
case spv::ExecutionModeSharedLocalMemorySizeINTEL: {

lib/SPIRV/libSPIRV/SPIRVEntry.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -552,7 +552,7 @@ void SPIRVExecutionMode::encode(spv_ostream &O) const {
552552

553553
void SPIRVExecutionMode::decode(std::istream &I) {
554554
getDecoder(I) >> Target >> ExecMode;
555-
switch (ExecMode) {
555+
switch (static_cast<uint32_t>(ExecMode)) {
556556
case ExecutionModeLocalSize:
557557
case ExecutionModeLocalSizeHint:
558558
case ExecutionModeMaxWorkgroupSizeINTEL:
@@ -575,6 +575,7 @@ void SPIRVExecutionMode::decode(std::istream &I) {
575575
case ExecutionModeMaxWorkDimINTEL:
576576
case ExecutionModeNumSIMDWorkitemsINTEL:
577577
case ExecutionModeSchedulerTargetFmaxMhzINTEL:
578+
case internal::ExecutionModeStreamingInterfaceINTEL:
578579
WordLiterals.resize(1);
579580
break;
580581
default:

lib/SPIRV/libSPIRV/SPIRVEnum.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -261,6 +261,8 @@ template <> inline void SPIRVMap<SPIRVExecutionModeKind, SPIRVCapVec>::init() {
261261
{CapabilityVectorComputeINTEL});
262262
ADD_VEC_INIT(internal::ExecutionModeFastCompositeKernelINTEL,
263263
{internal::CapabilityFastCompositeINTEL});
264+
ADD_VEC_INIT(internal::ExecutionModeStreamingInterfaceINTEL,
265+
{CapabilityFPGAKernelAttributesINTEL});
264266
}
265267

266268
template <> inline void SPIRVMap<SPIRVMemoryModelKind, SPIRVCapVec>::init() {

lib/SPIRV/libSPIRV/SPIRVIsValidEnum.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ using namespace spv;
5555
namespace SPIRV {
5656

5757
inline bool isValid(spv::ExecutionModel V) {
58-
switch (V) {
58+
switch (static_cast<uint32_t>(V)) {
5959
case ExecutionModelVertex:
6060
case ExecutionModelTessellationControl:
6161
case ExecutionModelTessellationEvaluation:
@@ -71,6 +71,7 @@ inline bool isValid(spv::ExecutionModel V) {
7171
case ExecutionModelClosestHitKHR:
7272
case ExecutionModelMissKHR:
7373
case ExecutionModelCallableKHR:
74+
case internal::ExecutionModeStreamingInterfaceINTEL:
7475
return true;
7576
default:
7677
return false;

lib/SPIRV/libSPIRV/spirv_internal.hpp

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,10 @@ enum InternalMemoryAccessMask {
8181
IMemAccessNoAliasINTELMask = 0x20000
8282
};
8383

84-
enum InternalExecutionMode { IExecModeFastCompositeKernelINTEL = 6088 };
84+
enum InternalExecutionMode {
85+
IExecModeFastCompositeKernelINTEL = 6088,
86+
IExecModeStreamingInterfaceINTEL = 6154
87+
};
8588

8689
enum InternalLoopControlMask { ILoopControlLoopCountINTELMask = 0x1000000 };
8790

@@ -155,6 +158,8 @@ constexpr MemoryAccessMask MemoryAccessNoAliasINTELMask =
155158

156159
constexpr ExecutionMode ExecutionModeFastCompositeKernelINTEL =
157160
static_cast<ExecutionMode>(IExecModeFastCompositeKernelINTEL);
161+
constexpr ExecutionMode ExecutionModeStreamingInterfaceINTEL =
162+
static_cast<ExecutionMode>(IExecModeStreamingInterfaceINTEL);
158163

159164
constexpr LoopControlMask LoopControlLoopCountINTELMask =
160165
static_cast<LoopControlMask>(ILoopControlLoopCountINTELMask);
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
; RUN: llvm-as %s -o %t.bc
2+
; RUN: llvm-spirv %t.bc --spirv-ext=+SPV_INTEL_kernel_attributes -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 %t.spv -o %t.rev.bc
7+
; RUN: llvm-dis < %t.rev.bc | FileCheck %s --check-prefix=CHECK-LLVM
8+
9+
; CHECK-SPIRV: Capability FPGAKernelAttributesINTEL
10+
; CHECK-SPIRV: Extension "SPV_INTEL_kernel_attributes"
11+
; CHECK-SPIRV: EntryPoint [[#]] [[#KERNEL1:]] "test_1"
12+
; CHECK-SPIRV: EntryPoint [[#]] [[#KERNEL2:]] "test_2"
13+
; CHECK-SPIRV: ExecutionMode [[#KERNEL1]] 6154 0
14+
; CHECK-SPIRV: ExecutionMode [[#KERNEL2]] 6154 1
15+
; CHECK-SPIRV: Function [[#]] [[#KERNEL1]]
16+
; CHECK-SPIRV: Function [[#]] [[#KERNEL2]]
17+
18+
19+
; CHECK-LLVM: define spir_kernel void @test_1{{.*}} !ip_interface ![[#NOSTALLFREE:]]
20+
; CHECK-LLVM: define spir_kernel void @test_2{{.*}} !ip_interface ![[#STALLFREE:]]
21+
; CHECK-LLVM: ![[#NOSTALLFREE:]] = !{!"streaming"}
22+
; CHECK-LLVM: ![[#STALLFREE:]] = !{!"streaming", !"stall_free_return"}
23+
24+
; ModuleID = 'test.bc'
25+
target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v16:16:16-v24:32:32-v32:32:32-v48:64:64-v64:64:64-v96:128:128-v128:128:128-v192:256:256-v256:256:256-v512:512:512-v1024:1024:1024"
26+
target triple = "spir64-unknown-unknown"
27+
28+
; Function Attrs: nounwind
29+
define spir_kernel void @test_1() #0 !ip_interface !0
30+
{
31+
entry:
32+
ret void
33+
}
34+
35+
; Function Attrs: nounwind
36+
define spir_kernel void @test_2() #0 !ip_interface !1
37+
{
38+
entry:
39+
ret void
40+
}
41+
42+
attributes #0 = { nounwind }
43+
44+
!0 = !{!"streaming"}
45+
!1 = !{!"streaming", !"stall_free_return"}

0 commit comments

Comments
 (0)