diff --git a/lib/SPIRV/PreprocessMetadata.cpp b/lib/SPIRV/PreprocessMetadata.cpp index c56222982..23b5e453d 100644 --- a/lib/SPIRV/PreprocessMetadata.cpp +++ b/lib/SPIRV/PreprocessMetadata.cpp @@ -229,9 +229,31 @@ void PreprocessMetadataBase::visit(Module *M) { if (MDNode *Interface = Kernel.getMetadata(kSPIR2MD::IntelFPGAIPInterface)) { std::set InterfaceStrSet; - // Default mode is 'csr' aka !ip_interface !N - // !N = !{!”csr”} - // don't emit any particular SPIR-V for it + for (size_t I = 0; I != Interface->getNumOperands(); ++I) + InterfaceStrSet.insert(getMDOperandAsString(Interface, I).str()); + + // ip_interface metadata will either have Register Map metadata or + // Streaming metadata. + // + // Register Map mode metadata: + // Not 'WaitForDoneWrite' mode (to be mapped on '0' literal) + // !ip_interface !N + // !N = !{!"csr"} + // 'WaitForDoneWrite' mode (to be mapped on '1' literal) + // !ip_interface !N + // !N = !{!"csr", !"wait_for_done_write"} + if (InterfaceStrSet.find("csr") != InterfaceStrSet.end()) { + int32_t InterfaceMode = 0; + if (InterfaceStrSet.find("wait_for_done_write") != + InterfaceStrSet.end()) + InterfaceMode = 1; + EM.addOp() + .add(&Kernel) + .add(spv::ExecutionModeRegisterMapInterfaceINTEL) + .add(InterfaceMode) + .done(); + } + // Streaming mode metadata be like: // Not 'stall free' mode (to be mapped on '0' literal) // !ip_interface !N @@ -239,8 +261,6 @@ void PreprocessMetadataBase::visit(Module *M) { // 'stall free' mode (to be mapped on '1' literal) // !ip_interface !N // !N = !{!"streaming", !"stall_free_return"} - for (size_t I = 0; I != Interface->getNumOperands(); ++I) - InterfaceStrSet.insert(getMDOperandAsString(Interface, I).str()); if (InterfaceStrSet.find("streaming") != InterfaceStrSet.end()) { int32_t InterfaceMode = 0; if (InterfaceStrSet.find("stall_free_return") != InterfaceStrSet.end()) @@ -324,17 +344,16 @@ void PreprocessMetadataBase::preprocessVectorComputeMetadata(Module *M, FPRoundingModeExecModeMap::map(getFPRoundingMode(Mode)); spv::ExecutionMode ExecFloatMode = FPOperationModeExecModeMap::map(getFPOperationMode(Mode)); - VCFloatTypeSizeMap::foreach ( - [&](VCFloatType FloatType, unsigned TargetWidth) { - EM.addOp().add(&F).add(ExecRoundMode).add(TargetWidth).done(); - EM.addOp().add(&F).add(ExecFloatMode).add(TargetWidth).done(); - EM.addOp() - .add(&F) - .add(FPDenormModeExecModeMap::map( - getFPDenormMode(Mode, FloatType))) - .add(TargetWidth) - .done(); - }); + VCFloatTypeSizeMap::foreach ([&](VCFloatType FloatType, + unsigned TargetWidth) { + EM.addOp().add(&F).add(ExecRoundMode).add(TargetWidth).done(); + EM.addOp().add(&F).add(ExecFloatMode).add(TargetWidth).done(); + EM.addOp() + .add(&F) + .add(FPDenormModeExecModeMap::map(getFPDenormMode(Mode, FloatType))) + .add(TargetWidth) + .done(); + }); } if (Attrs.hasFnAttr(kVCMetadata::VCSLMSize)) { SPIRVWord SLMSize = 0; diff --git a/lib/SPIRV/SPIRVReader.cpp b/lib/SPIRV/SPIRVReader.cpp index c74f468e8..5dd1a3d26 100644 --- a/lib/SPIRV/SPIRVReader.cpp +++ b/lib/SPIRV/SPIRVReader.cpp @@ -1238,7 +1238,7 @@ static void replaceOperandWithAnnotationIntrinsicCallResult(Value *&V) { template void SPIRVToLLVM::transAliasingMemAccess(SPIRVInstType *BI, Instruction *I) { static_assert(std::is_same::value || - std::is_same::value, + std::is_same::value, "Only stores and loads can be aliased by memory access mask"); if (BI->SPIRVMemoryAccess::isNoAlias()) addMemAliasMetadata(I, BI->SPIRVMemoryAccess::getNoAliasInstID(), @@ -2032,10 +2032,10 @@ Value *SPIRVToLLVM::transValueWithoutDecoration(SPIRVValue *BV, Function *F, case 4: { for (int Idx = 0; Idx < 4; ++Idx) { - Value *V1 = Builder.CreateShuffleVector( - MCache[0], MCache[1], ArrayRef{Idx, Idx + 4}); - Value *V2 = Builder.CreateShuffleVector( - MCache[2], MCache[3], ArrayRef{Idx, Idx + 4}); + Value *V1 = Builder.CreateShuffleVector(MCache[0], MCache[1], + ArrayRef{Idx, Idx + 4}); + Value *V2 = Builder.CreateShuffleVector(MCache[2], MCache[3], + ArrayRef{Idx, Idx + 4}); Value *V3 = Builder.CreateShuffleVector(V1, V2, ArrayRef{0, 1, 2, 3}); V = Builder.CreateInsertValue(V, V3, Idx); @@ -4009,6 +4009,27 @@ bool SPIRVToLLVM::transMetadata() { F->setMetadata(kSPIR2MD::FmaxMhz, getMDNodeStringIntVec(Context, EM->getLiterals())); } + // Generate metadata for Intel FPGA register map interface + if (auto *EM = + BF->getExecutionMode(ExecutionModeRegisterMapInterfaceINTEL)) { + std::vector InterfaceVec = EM->getLiterals(); + assert(InterfaceVec.size() == 1 && + "Expected RegisterMapInterfaceINTEL to have exactly 1 literal"); + std::vector InterfaceMDVec = + [&]() -> std::vector { + switch (InterfaceVec[0]) { + case 0: + return {MDString::get(*Context, "csr")}; + case 1: + return {MDString::get(*Context, "csr"), + MDString::get(*Context, "wait_for_done_write")}; + default: + llvm_unreachable("Invalid register map interface mode"); + } + }(); + F->setMetadata(kSPIR2MD::IntelFPGAIPInterface, + MDNode::get(*Context, InterfaceMDVec)); + } // Generate metadata for Intel FPGA streaming interface if (auto *EM = BF->getExecutionMode(ExecutionModeStreamingInterfaceINTEL)) { std::vector InterfaceVec = EM->getLiterals(); diff --git a/lib/SPIRV/SPIRVWriter.cpp b/lib/SPIRV/SPIRVWriter.cpp index 9464972f5..2aced2ade 100644 --- a/lib/SPIRV/SPIRVWriter.cpp +++ b/lib/SPIRV/SPIRVWriter.cpp @@ -4964,6 +4964,19 @@ bool LLVMToSPIRVBase::transExecutionMode() { case spv::ExecutionModeNumSIMDWorkitemsINTEL: case spv::ExecutionModeSchedulerTargetFmaxMhzINTEL: case spv::ExecutionModeMaxWorkDimINTEL: + case spv::ExecutionModeRegisterMapInterfaceINTEL: { + if (!BM->isAllowedToUseExtension( + ExtensionID::SPV_INTEL_kernel_attributes)) + break; + AddSingleArgExecutionMode(static_cast(EMode)); + BM->addExtension(ExtensionID::SPV_INTEL_kernel_attributes); + BM->addCapability(CapabilityFPGAKernelAttributesINTEL); + // RegisterMapInterfaceINTEL mode is defined by the + // CapabilityFPGAKernelAttributesv2INTEL capability and that + // capability implicitly defines CapabilityFPGAKernelAttributesINTEL + if (EMode == spv::ExecutionModeRegisterMapInterfaceINTEL) + BM->addCapability(CapabilityFPGAKernelAttributesv2INTEL); + } break; case spv::ExecutionModeStreamingInterfaceINTEL: { if (!BM->isAllowedToUseExtension( ExtensionID::SPV_INTEL_kernel_attributes)) diff --git a/lib/SPIRV/libSPIRV/SPIRVEntry.cpp b/lib/SPIRV/libSPIRV/SPIRVEntry.cpp index 54475a9d9..bb2df97da 100644 --- a/lib/SPIRV/libSPIRV/SPIRVEntry.cpp +++ b/lib/SPIRV/libSPIRV/SPIRVEntry.cpp @@ -614,6 +614,7 @@ void SPIRVExecutionMode::decode(std::istream &I) { case ExecutionModeMaxWorkDimINTEL: case ExecutionModeNumSIMDWorkitemsINTEL: case ExecutionModeSchedulerTargetFmaxMhzINTEL: + case ExecutionModeRegisterMapInterfaceINTEL: case ExecutionModeStreamingInterfaceINTEL: WordLiterals.resize(1); break; diff --git a/lib/SPIRV/libSPIRV/SPIRVEnum.h b/lib/SPIRV/libSPIRV/SPIRVEnum.h index 0f03e2508..59a5e6f68 100644 --- a/lib/SPIRV/libSPIRV/SPIRVEnum.h +++ b/lib/SPIRV/libSPIRV/SPIRVEnum.h @@ -269,6 +269,8 @@ template <> inline void SPIRVMap::init() { {CapabilityVectorComputeINTEL}); ADD_VEC_INIT(internal::ExecutionModeFastCompositeKernelINTEL, {internal::CapabilityFastCompositeINTEL}); + ADD_VEC_INIT(ExecutionModeRegisterMapInterfaceINTEL, + {CapabilityFPGAKernelAttributesv2INTEL}); ADD_VEC_INIT(ExecutionModeStreamingInterfaceINTEL, {CapabilityFPGAKernelAttributesINTEL}); ADD_VEC_INIT(ExecutionModeNamedBarrierCountINTEL, diff --git a/lib/SPIRV/libSPIRV/SPIRVIsValidEnum.h b/lib/SPIRV/libSPIRV/SPIRVIsValidEnum.h index 093141d10..080b8bcd8 100644 --- a/lib/SPIRV/libSPIRV/SPIRVIsValidEnum.h +++ b/lib/SPIRV/libSPIRV/SPIRVIsValidEnum.h @@ -71,6 +71,7 @@ inline bool isValid(spv::ExecutionModel V) { case ExecutionModelClosestHitKHR: case ExecutionModelMissKHR: case ExecutionModelCallableKHR: + case ExecutionModeRegisterMapInterfaceINTEL: case ExecutionModeStreamingInterfaceINTEL: return true; default: diff --git a/lib/SPIRV/libSPIRV/SPIRVNameMapEnum.h b/lib/SPIRV/libSPIRV/SPIRVNameMapEnum.h index a8cc9f924..1fdaa99f8 100644 --- a/lib/SPIRV/libSPIRV/SPIRVNameMapEnum.h +++ b/lib/SPIRV/libSPIRV/SPIRVNameMapEnum.h @@ -579,6 +579,7 @@ template <> inline void SPIRVMap::init() { add(CapabilityFPGALoopControlsINTEL, "FPGALoopControlsINTEL"); add(CapabilityKernelAttributesINTEL, "KernelAttributesINTEL"); add(CapabilityFPGAKernelAttributesINTEL, "FPGAKernelAttributesINTEL"); + add(CapabilityFPGAKernelAttributesv2INTEL, "FPGAKernelAttributesv2INTEL"); add(CapabilityFPGAMemoryAccessesINTEL, "FPGAMemoryAccessesINTEL"); add(CapabilityFPGAClusterAttributesINTEL, "FPGAClusterAttributesINTEL"); add(CapabilityLoopFuseINTEL, "LoopFuseINTEL"); diff --git a/spirv-headers-tag.conf b/spirv-headers-tag.conf index 49e09ea4c..2129a9107 100644 --- a/spirv-headers-tag.conf +++ b/spirv-headers-tag.conf @@ -1 +1 @@ -36c7694279dfb3ea7e6e086e368bb8bee076792a +295cf5fb3bfe2454360e82b26bae7fc0de699abe diff --git a/test/extensions/INTEL/SPV_INTEL_kernel_attributes/register_map_interface_attribute.ll b/test/extensions/INTEL/SPV_INTEL_kernel_attributes/register_map_interface_attribute.ll new file mode 100644 index 000000000..cec656bad --- /dev/null +++ b/test/extensions/INTEL/SPV_INTEL_kernel_attributes/register_map_interface_attribute.ll @@ -0,0 +1,46 @@ +; RUN: llvm-as %s -o %t.bc +; RUN: llvm-spirv %t.bc --spirv-ext=+SPV_INTEL_kernel_attributes -o %t.spv +; RUN: llvm-spirv %t.spv -to-text -o %t.spt +; RUN: FileCheck < %t.spt %s --check-prefix=CHECK-SPIRV + +; RUN: llvm-spirv -r -emit-opaque-pointers %t.spv -o %t.rev.bc +; RUN: llvm-dis < %t.rev.bc | FileCheck %s --check-prefix=CHECK-LLVM + +; FPGAKernelAttributesv2INTEL implicitly defines FPGAKernelAttributesINTEL +; CHECK-SPIRV: Capability FPGAKernelAttributesINTEL +; CHECK-SPIRV: Capability FPGAKernelAttributesv2INTEL +; CHECK-SPIRV: Extension "SPV_INTEL_kernel_attributes" +; CHECK-SPIRV: EntryPoint [[#]] [[#KERNEL1:]] "test_1" +; CHECK-SPIRV: EntryPoint [[#]] [[#KERNEL2:]] "test_2" +; CHECK-SPIRV: ExecutionMode [[#KERNEL1]] 6160 0 +; CHECK-SPIRV: ExecutionMode [[#KERNEL2]] 6160 1 +; CHECK-SPIRV: Function [[#]] [[#KERNEL1]] +; CHECK-SPIRV: Function [[#]] [[#KERNEL2]] + +; CHECK-LLVM: define spir_kernel void @test_1{{.*}} !ip_interface ![[#NOWAITFORDONEWRITE:]] +; CHECK-LLVM: define spir_kernel void @test_2{{.*}} !ip_interface ![[#WAITFORDONEWRITE:]] +; CHECK-LLVM: ![[#NOWAITFORDONEWRITE:]] = !{!"csr"} +; CHECK-LLVM: ![[#WAITFORDONEWRITE:]] = !{!"csr", !"wait_for_done_write"} + +; ModuleID = 'test.bc' +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" +target triple = "spir64-unknown-unknown" + +; Function Attrs: nounwind +define spir_kernel void @test_1() #0 !ip_interface !0 +{ +entry: + ret void +} + +; Function Attrs: nounwind +define spir_kernel void @test_2() #0 !ip_interface !1 +{ +entry: + ret void +} + +attributes #0 = { nounwind } + +!0 = !{!"csr"} +!1 = !{!"csr", !"wait_for_done_write"}