Skip to content

Commit a9f4f25

Browse files
authored
Implement RegisterMapInterfaceINTEL execution mode (#1774)
This PR adds the new execution mode RegisterMapInterfaceINTEL, see the Khronos SPIRV spec here: KhronosGroup/SPIRV-Registry#176 This execution mode allows specifying a 'register' based interface for FPGA kernels. The RegisterMapInterfaceINTEL execution mode is added with a 0/1 literal based on the kernel metadata. When the metadata is: !ip_interface !N !N = !{!"csr"} The translator emits RegisterMapInterfaceINTEL 0, and when the metadata is: !ip_interface !N !N = !{!"csr", !"accept_downstream_stall"} The translator emits RegisterMapInterfaceINTEL 1 NOTE The new mode is under capability FPGAKernelAttributesv2INTEL which implicitly defines the capability FPGAKernelAttributesv2INTEL. This PR is very similar to Implement StreamingInterfaceINTEL execution mode #1218
1 parent b7c5218 commit a9f4f25

File tree

9 files changed

+126
-22
lines changed

9 files changed

+126
-22
lines changed

lib/SPIRV/PreprocessMetadata.cpp

Lines changed: 35 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -229,18 +229,38 @@ void PreprocessMetadataBase::visit(Module *M) {
229229
if (MDNode *Interface =
230230
Kernel.getMetadata(kSPIR2MD::IntelFPGAIPInterface)) {
231231
std::set<std::string> InterfaceStrSet;
232-
// Default mode is 'csr' aka !ip_interface !N
233-
// !N = !{!”csr”}
234-
// don't emit any particular SPIR-V for it
232+
for (size_t I = 0; I != Interface->getNumOperands(); ++I)
233+
InterfaceStrSet.insert(getMDOperandAsString(Interface, I).str());
234+
235+
// ip_interface metadata will either have Register Map metadata or
236+
// Streaming metadata.
237+
//
238+
// Register Map mode metadata:
239+
// Not 'WaitForDoneWrite' mode (to be mapped on '0' literal)
240+
// !ip_interface !N
241+
// !N = !{!"csr"}
242+
// 'WaitForDoneWrite' mode (to be mapped on '1' literal)
243+
// !ip_interface !N
244+
// !N = !{!"csr", !"wait_for_done_write"}
245+
if (InterfaceStrSet.find("csr") != InterfaceStrSet.end()) {
246+
int32_t InterfaceMode = 0;
247+
if (InterfaceStrSet.find("wait_for_done_write") !=
248+
InterfaceStrSet.end())
249+
InterfaceMode = 1;
250+
EM.addOp()
251+
.add(&Kernel)
252+
.add(spv::ExecutionModeRegisterMapInterfaceINTEL)
253+
.add(InterfaceMode)
254+
.done();
255+
}
256+
235257
// Streaming mode metadata be like:
236258
// Not 'stall free' mode (to be mapped on '0' literal)
237259
// !ip_interface !N
238260
// !N = !{!"streaming"}
239261
// 'stall free' mode (to be mapped on '1' literal)
240262
// !ip_interface !N
241263
// !N = !{!"streaming", !"stall_free_return"}
242-
for (size_t I = 0; I != Interface->getNumOperands(); ++I)
243-
InterfaceStrSet.insert(getMDOperandAsString(Interface, I).str());
244264
if (InterfaceStrSet.find("streaming") != InterfaceStrSet.end()) {
245265
int32_t InterfaceMode = 0;
246266
if (InterfaceStrSet.find("stall_free_return") != InterfaceStrSet.end())
@@ -324,17 +344,16 @@ void PreprocessMetadataBase::preprocessVectorComputeMetadata(Module *M,
324344
FPRoundingModeExecModeMap::map(getFPRoundingMode(Mode));
325345
spv::ExecutionMode ExecFloatMode =
326346
FPOperationModeExecModeMap::map(getFPOperationMode(Mode));
327-
VCFloatTypeSizeMap::foreach (
328-
[&](VCFloatType FloatType, unsigned TargetWidth) {
329-
EM.addOp().add(&F).add(ExecRoundMode).add(TargetWidth).done();
330-
EM.addOp().add(&F).add(ExecFloatMode).add(TargetWidth).done();
331-
EM.addOp()
332-
.add(&F)
333-
.add(FPDenormModeExecModeMap::map(
334-
getFPDenormMode(Mode, FloatType)))
335-
.add(TargetWidth)
336-
.done();
337-
});
347+
VCFloatTypeSizeMap::foreach ([&](VCFloatType FloatType,
348+
unsigned TargetWidth) {
349+
EM.addOp().add(&F).add(ExecRoundMode).add(TargetWidth).done();
350+
EM.addOp().add(&F).add(ExecFloatMode).add(TargetWidth).done();
351+
EM.addOp()
352+
.add(&F)
353+
.add(FPDenormModeExecModeMap::map(getFPDenormMode(Mode, FloatType)))
354+
.add(TargetWidth)
355+
.done();
356+
});
338357
}
339358
if (Attrs.hasFnAttr(kVCMetadata::VCSLMSize)) {
340359
SPIRVWord SLMSize = 0;

lib/SPIRV/SPIRVReader.cpp

Lines changed: 26 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1257,7 +1257,7 @@ static void replaceOperandWithAnnotationIntrinsicCallResult(Value *&V) {
12571257
template <typename SPIRVInstType>
12581258
void SPIRVToLLVM::transAliasingMemAccess(SPIRVInstType *BI, Instruction *I) {
12591259
static_assert(std::is_same<SPIRVInstType, SPIRVStore>::value ||
1260-
std::is_same<SPIRVInstType, SPIRVLoad>::value,
1260+
std::is_same<SPIRVInstType, SPIRVLoad>::value,
12611261
"Only stores and loads can be aliased by memory access mask");
12621262
if (BI->SPIRVMemoryAccess::isNoAlias())
12631263
addMemAliasMetadata(I, BI->SPIRVMemoryAccess::getNoAliasInstID(),
@@ -2051,10 +2051,10 @@ Value *SPIRVToLLVM::transValueWithoutDecoration(SPIRVValue *BV, Function *F,
20512051

20522052
case 4: {
20532053
for (int Idx = 0; Idx < 4; ++Idx) {
2054-
Value *V1 = Builder.CreateShuffleVector(
2055-
MCache[0], MCache[1], ArrayRef<int>{Idx, Idx + 4});
2056-
Value *V2 = Builder.CreateShuffleVector(
2057-
MCache[2], MCache[3], ArrayRef<int>{Idx, Idx + 4});
2054+
Value *V1 = Builder.CreateShuffleVector(MCache[0], MCache[1],
2055+
ArrayRef<int>{Idx, Idx + 4});
2056+
Value *V2 = Builder.CreateShuffleVector(MCache[2], MCache[3],
2057+
ArrayRef<int>{Idx, Idx + 4});
20582058
Value *V3 =
20592059
Builder.CreateShuffleVector(V1, V2, ArrayRef<int>{0, 1, 2, 3});
20602060
V = Builder.CreateInsertValue(V, V3, Idx);
@@ -4028,6 +4028,27 @@ bool SPIRVToLLVM::transMetadata() {
40284028
F->setMetadata(kSPIR2MD::FmaxMhz,
40294029
getMDNodeStringIntVec(Context, EM->getLiterals()));
40304030
}
4031+
// Generate metadata for Intel FPGA register map interface
4032+
if (auto *EM =
4033+
BF->getExecutionMode(ExecutionModeRegisterMapInterfaceINTEL)) {
4034+
std::vector<uint32_t> InterfaceVec = EM->getLiterals();
4035+
assert(InterfaceVec.size() == 1 &&
4036+
"Expected RegisterMapInterfaceINTEL to have exactly 1 literal");
4037+
std::vector<Metadata *> InterfaceMDVec =
4038+
[&]() -> std::vector<Metadata *> {
4039+
switch (InterfaceVec[0]) {
4040+
case 0:
4041+
return {MDString::get(*Context, "csr")};
4042+
case 1:
4043+
return {MDString::get(*Context, "csr"),
4044+
MDString::get(*Context, "wait_for_done_write")};
4045+
default:
4046+
llvm_unreachable("Invalid register map interface mode");
4047+
}
4048+
}();
4049+
F->setMetadata(kSPIR2MD::IntelFPGAIPInterface,
4050+
MDNode::get(*Context, InterfaceMDVec));
4051+
}
40314052
// Generate metadata for Intel FPGA streaming interface
40324053
if (auto *EM = BF->getExecutionMode(ExecutionModeStreamingInterfaceINTEL)) {
40334054
std::vector<uint32_t> InterfaceVec = EM->getLiterals();

lib/SPIRV/SPIRVWriter.cpp

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4974,6 +4974,19 @@ bool LLVMToSPIRVBase::transExecutionMode() {
49744974
case spv::ExecutionModeNumSIMDWorkitemsINTEL:
49754975
case spv::ExecutionModeSchedulerTargetFmaxMhzINTEL:
49764976
case spv::ExecutionModeMaxWorkDimINTEL:
4977+
case spv::ExecutionModeRegisterMapInterfaceINTEL: {
4978+
if (!BM->isAllowedToUseExtension(
4979+
ExtensionID::SPV_INTEL_kernel_attributes))
4980+
break;
4981+
AddSingleArgExecutionMode(static_cast<ExecutionMode>(EMode));
4982+
BM->addExtension(ExtensionID::SPV_INTEL_kernel_attributes);
4983+
BM->addCapability(CapabilityFPGAKernelAttributesINTEL);
4984+
// RegisterMapInterfaceINTEL mode is defined by the
4985+
// CapabilityFPGAKernelAttributesv2INTEL capability and that
4986+
// capability implicitly defines CapabilityFPGAKernelAttributesINTEL
4987+
if (EMode == spv::ExecutionModeRegisterMapInterfaceINTEL)
4988+
BM->addCapability(CapabilityFPGAKernelAttributesv2INTEL);
4989+
} break;
49774990
case spv::ExecutionModeStreamingInterfaceINTEL: {
49784991
if (!BM->isAllowedToUseExtension(
49794992
ExtensionID::SPV_INTEL_kernel_attributes))

lib/SPIRV/libSPIRV/SPIRVEntry.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -614,6 +614,7 @@ void SPIRVExecutionMode::decode(std::istream &I) {
614614
case ExecutionModeMaxWorkDimINTEL:
615615
case ExecutionModeNumSIMDWorkitemsINTEL:
616616
case ExecutionModeSchedulerTargetFmaxMhzINTEL:
617+
case ExecutionModeRegisterMapInterfaceINTEL:
617618
case ExecutionModeStreamingInterfaceINTEL:
618619
WordLiterals.resize(1);
619620
break;

lib/SPIRV/libSPIRV/SPIRVEnum.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -277,6 +277,8 @@ template <> inline void SPIRVMap<SPIRVExecutionModeKind, SPIRVCapVec>::init() {
277277
{CapabilityVectorComputeINTEL});
278278
ADD_VEC_INIT(internal::ExecutionModeFastCompositeKernelINTEL,
279279
{internal::CapabilityFastCompositeINTEL});
280+
ADD_VEC_INIT(ExecutionModeRegisterMapInterfaceINTEL,
281+
{CapabilityFPGAKernelAttributesv2INTEL});
280282
ADD_VEC_INIT(ExecutionModeStreamingInterfaceINTEL,
281283
{CapabilityFPGAKernelAttributesINTEL});
282284
ADD_VEC_INIT(ExecutionModeNamedBarrierCountINTEL,

lib/SPIRV/libSPIRV/SPIRVIsValidEnum.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,7 @@ inline bool isValid(spv::ExecutionModel V) {
7171
case ExecutionModelClosestHitKHR:
7272
case ExecutionModelMissKHR:
7373
case ExecutionModelCallableKHR:
74+
case ExecutionModeRegisterMapInterfaceINTEL:
7475
case ExecutionModeStreamingInterfaceINTEL:
7576
return true;
7677
default:

lib/SPIRV/libSPIRV/SPIRVNameMapEnum.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -579,6 +579,7 @@ template <> inline void SPIRVMap<Capability, std::string>::init() {
579579
add(CapabilityFPGALoopControlsINTEL, "FPGALoopControlsINTEL");
580580
add(CapabilityKernelAttributesINTEL, "KernelAttributesINTEL");
581581
add(CapabilityFPGAKernelAttributesINTEL, "FPGAKernelAttributesINTEL");
582+
add(CapabilityFPGAKernelAttributesv2INTEL, "FPGAKernelAttributesv2INTEL");
582583
add(CapabilityFPGAMemoryAccessesINTEL, "FPGAMemoryAccessesINTEL");
583584
add(CapabilityFPGAClusterAttributesINTEL, "FPGAClusterAttributesINTEL");
584585
add(CapabilityLoopFuseINTEL, "LoopFuseINTEL");

spirv-headers-tag.conf

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
36c7694279dfb3ea7e6e086e368bb8bee076792a
1+
295cf5fb3bfe2454360e82b26bae7fc0de699abe
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
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 -emit-opaque-pointers %t.spv -o %t.rev.bc
7+
; RUN: llvm-dis < %t.rev.bc | FileCheck %s --check-prefix=CHECK-LLVM
8+
9+
; FPGAKernelAttributesv2INTEL implicitly defines FPGAKernelAttributesINTEL
10+
; CHECK-SPIRV: Capability FPGAKernelAttributesINTEL
11+
; CHECK-SPIRV: Capability FPGAKernelAttributesv2INTEL
12+
; CHECK-SPIRV: Extension "SPV_INTEL_kernel_attributes"
13+
; CHECK-SPIRV: EntryPoint [[#]] [[#KERNEL1:]] "test_1"
14+
; CHECK-SPIRV: EntryPoint [[#]] [[#KERNEL2:]] "test_2"
15+
; CHECK-SPIRV: ExecutionMode [[#KERNEL1]] 6160 0
16+
; CHECK-SPIRV: ExecutionMode [[#KERNEL2]] 6160 1
17+
; CHECK-SPIRV: Function [[#]] [[#KERNEL1]]
18+
; CHECK-SPIRV: Function [[#]] [[#KERNEL2]]
19+
20+
; CHECK-LLVM: define spir_kernel void @test_1{{.*}} !ip_interface ![[#NOWAITFORDONEWRITE:]]
21+
; CHECK-LLVM: define spir_kernel void @test_2{{.*}} !ip_interface ![[#WAITFORDONEWRITE:]]
22+
; CHECK-LLVM: ![[#NOWAITFORDONEWRITE:]] = !{!"csr"}
23+
; CHECK-LLVM: ![[#WAITFORDONEWRITE:]] = !{!"csr", !"wait_for_done_write"}
24+
25+
; ModuleID = 'test.bc'
26+
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"
27+
target triple = "spir64-unknown-unknown"
28+
29+
; Function Attrs: nounwind
30+
define spir_kernel void @test_1() #0 !ip_interface !0
31+
{
32+
entry:
33+
ret void
34+
}
35+
36+
; Function Attrs: nounwind
37+
define spir_kernel void @test_2() #0 !ip_interface !1
38+
{
39+
entry:
40+
ret void
41+
}
42+
43+
attributes #0 = { nounwind }
44+
45+
!0 = !{!"csr"}
46+
!1 = !{!"csr", !"wait_for_done_write"}

0 commit comments

Comments
 (0)