From f71cec58d14be2360a8be60f9fcfec1a4a10ea06 Mon Sep 17 00:00:00 2001 From: Dmitry Sidorov Date: Fri, 10 Jul 2020 12:38:47 +0300 Subject: [PATCH] Add support for SPV_INTEL_fpga_buffer_location extension This extension adds a function parameter decoration that is useful for FPGA targets. This decoration indicates that a particular global memory pointer can only access a particular physical memory location. Knowing this information at compile time can allow FPGA compilers to generate load store units of lower area for accesses done through such a pointer. Specification: https://github.com/intel/llvm/pull/2084 Signed-off-by: Dmitry Sidorov --- llvm-spirv/include/LLVMSPIRVExtensions.inc | 1 + llvm-spirv/lib/SPIRV/SPIRVReader.cpp | 30 +++++++++ llvm-spirv/lib/SPIRV/SPIRVWriter.cpp | 16 +++++ llvm-spirv/lib/SPIRV/libSPIRV/SPIRVDecorate.h | 4 ++ llvm-spirv/lib/SPIRV/libSPIRV/SPIRVEnum.h | 2 + .../lib/SPIRV/libSPIRV/SPIRVNameMapEnum.h | 2 + llvm-spirv/lib/SPIRV/libSPIRV/spirv.hpp | 2 + .../test/transcoding/FPGABufferLocation.ll | 61 +++++++++++++++++++ 8 files changed, 118 insertions(+) create mode 100644 llvm-spirv/test/transcoding/FPGABufferLocation.ll diff --git a/llvm-spirv/include/LLVMSPIRVExtensions.inc b/llvm-spirv/include/LLVMSPIRVExtensions.inc index 4a037aeddab25..adaa48efadc20 100644 --- a/llvm-spirv/include/LLVMSPIRVExtensions.inc +++ b/llvm-spirv/include/LLVMSPIRVExtensions.inc @@ -23,3 +23,4 @@ EXT(SPV_INTEL_optimization_hints) EXT(SPV_INTEL_float_controls2) EXT(SPV_INTEL_vector_compute) EXT(SPV_INTEL_usm_storage_classes) +EXT(SPV_INTEL_fpga_buffer_location) diff --git a/llvm-spirv/lib/SPIRV/SPIRVReader.cpp b/llvm-spirv/lib/SPIRV/SPIRVReader.cpp index b2518ffdbe620..864395ff42aa7 100644 --- a/llvm-spirv/lib/SPIRV/SPIRVReader.cpp +++ b/llvm-spirv/lib/SPIRV/SPIRVReader.cpp @@ -168,6 +168,27 @@ static void addOCLKernelArgumentMetadata( Fn->setMetadata(MDName, MDNode::get(*Context, ValueVec)); } +static void addBufferLocationMetadata( + LLVMContext *Context, SPIRVFunction *BF, llvm::Function *Fn, + std::function Func) { + std::vector ValueVec; + bool DecorationFound = false; + BF->foreachArgument([&](SPIRVFunctionParameter *Arg) { + if (Arg->getType()->isTypePointer() && + Arg->hasDecorate(DecorationBufferLocationINTEL)) { + DecorationFound = true; + ValueVec.push_back(Func(Arg)); + } else { + llvm::Metadata *DefaultNode = ConstantAsMetadata::get( + ConstantInt::get(Type::getInt32Ty(*Context), -1)); + ValueVec.push_back(DefaultNode); + } + }); + if (DecorationFound) + Fn->setMetadata("kernel_arg_buffer_location", + MDNode::get(*Context, ValueVec)); +} + Value *SPIRVToLLVM::getTranslatedValue(SPIRVValue *BV) { auto Loc = ValueMap.find(BV); if (Loc != ValueMap.end()) @@ -3479,6 +3500,15 @@ bool SPIRVToLLVM::transOCLMetadata(SPIRVFunction *BF) { Arg->getName()); }); } + // Generate metadata for kernel_arg_buffer_location + addBufferLocationMetadata(Context, BF, F, [=](SPIRVFunctionParameter *Arg) { + auto Literals = Arg->getDecorationLiterals(DecorationBufferLocationINTEL); + assert(Literals.size() == 1 && + "BufferLocationINTEL decoration shall have 1 ID literal"); + + return ConstantAsMetadata::get( + ConstantInt::get(Type::getInt32Ty(*Context), Literals[0])); + }); return true; } diff --git a/llvm-spirv/lib/SPIRV/SPIRVWriter.cpp b/llvm-spirv/lib/SPIRV/SPIRVWriter.cpp index 08599d5d2630a..bbe5ff9618a73 100644 --- a/llvm-spirv/lib/SPIRV/SPIRVWriter.cpp +++ b/llvm-spirv/lib/SPIRV/SPIRVWriter.cpp @@ -527,6 +527,13 @@ SPIRVFunction *LLVMToSPIRV::transFunctionDecl(Function *F) { BM->addEntryPoint(ExecutionModelKernel, BF->getId()); else if (F->getLinkage() != GlobalValue::InternalLinkage) BF->setLinkageType(transLinkageType(F)); + + // Translate OpenCL/SYCL buffer_location metadata if it's attached to the + // translated function declaration + MDNode *BufferLocation = nullptr; + if (BM->isAllowedToUseExtension(ExtensionID::SPV_INTEL_fpga_buffer_location)) + BufferLocation = ((*F).getMetadata("kernel_arg_buffer_location")); + auto Attrs = F->getAttributes(); for (Function::arg_iterator I = F->arg_begin(), E = F->arg_end(); I != E; @@ -552,6 +559,15 @@ SPIRVFunction *LLVMToSPIRV::transFunctionDecl(Function *F) { BA->addDecorate(DecorationMaxByteOffset, Attrs.getAttribute(ArgNo + 1, Attribute::Dereferenceable) .getDereferenceableBytes()); + if (BufferLocation && I->getType()->isPointerTy()) { + // Order of integer numbers in MD node follows the order of function + // parameters on which we shall attach the appropriate decoration. Add + // decoration only if MD value is not negative. + BM->addCapability(CapabilityFPGABufferLocationINTEL); + int LocID = getMDOperandAsInt(BufferLocation, ArgNo); + if (LocID >= 0) + BA->addDecorate(DecorationBufferLocationINTEL, LocID); + } } if (Attrs.hasAttribute(AttributeList::ReturnIndex, Attribute::ZExt)) BF->addDecorate(DecorationFuncParamAttr, FunctionParameterAttributeZext); diff --git a/llvm-spirv/lib/SPIRV/libSPIRV/SPIRVDecorate.h b/llvm-spirv/lib/SPIRV/libSPIRV/SPIRVDecorate.h index 31c60f0f2e243..ba03b181cf3ca 100644 --- a/llvm-spirv/lib/SPIRV/libSPIRV/SPIRVDecorate.h +++ b/llvm-spirv/lib/SPIRV/libSPIRV/SPIRVDecorate.h @@ -164,6 +164,8 @@ class SPIRVDecorate : public SPIRVDecorateGeneric { return getSet(ExtensionID::SPV_INTEL_function_pointers); case DecorationIOPipeStorageINTEL: return getSet(ExtensionID::SPV_INTEL_io_pipes); + case DecorationBufferLocationINTEL: + return getSet(ExtensionID::SPV_INTEL_fpga_buffer_location); default: return SPIRVExtSet(); } @@ -267,6 +269,8 @@ class SPIRVMemberDecorate : public SPIRVDecorateGeneric { return getSet(ExtensionID::SPV_INTEL_fpga_memory_accesses); case DecorationIOPipeStorageINTEL: return getSet(ExtensionID::SPV_INTEL_io_pipes); + case DecorationBufferLocationINTEL: + return getSet(ExtensionID::SPV_INTEL_fpga_buffer_location); default: return SPIRVExtSet(); } diff --git a/llvm-spirv/lib/SPIRV/libSPIRV/SPIRVEnum.h b/llvm-spirv/lib/SPIRV/libSPIRV/SPIRVEnum.h index 0ced7ce27f408..c35b4f01f1730 100644 --- a/llvm-spirv/lib/SPIRV/libSPIRV/SPIRVEnum.h +++ b/llvm-spirv/lib/SPIRV/libSPIRV/SPIRVEnum.h @@ -402,6 +402,8 @@ template <> inline void SPIRVMap::init() { ADD_VEC_INIT(DecorationDontStaticallyCoalesceINTEL, {CapabilityFPGAMemoryAccessesINTEL}); ADD_VEC_INIT(DecorationPrefetchINTEL, {CapabilityFPGAMemoryAccessesINTEL}); + ADD_VEC_INIT(DecorationBufferLocationINTEL, + {CapabilityFPGABufferLocationINTEL}); } template <> inline void SPIRVMap::init() { diff --git a/llvm-spirv/lib/SPIRV/libSPIRV/SPIRVNameMapEnum.h b/llvm-spirv/lib/SPIRV/libSPIRV/SPIRVNameMapEnum.h index e096040ed0727..c9915382e4fcc 100644 --- a/llvm-spirv/lib/SPIRV/libSPIRV/SPIRVNameMapEnum.h +++ b/llvm-spirv/lib/SPIRV/libSPIRV/SPIRVNameMapEnum.h @@ -376,6 +376,7 @@ template <> inline void SPIRVMap::init() { add(DecorationGlobalVariableOffsetINTEL, "GlobalVariableOffsetINTEL"); add(DecorationFuncParamIOKind, "FuncParamIOKind"); add(DecorationSIMTCallINTEL, "SIMTCallINTEL"); + add(DecorationBufferLocationINTEL, "BufferLocationINTEL"); } SPIRV_DEF_NAMEMAP(Decoration, SPIRVDecorationNameMap) @@ -560,6 +561,7 @@ template <> inline void SPIRVMap::init() { "GroupNonUniformShuffleRelative"); add(CapabilityGroupNonUniformClustered, "GroupNonUniformClustered"); add(CapabilityUSMStorageClassesINTEL, "USMStorageClassesINTEL"); + add(CapabilityFPGABufferLocationINTEL, "FPGABufferLocationINTEL"); } SPIRV_DEF_NAMEMAP(Capability, SPIRVCapabilityNameMap) diff --git a/llvm-spirv/lib/SPIRV/libSPIRV/spirv.hpp b/llvm-spirv/lib/SPIRV/libSPIRV/spirv.hpp index 22ccb3f8b17cb..53492791c7e7b 100644 --- a/llvm-spirv/lib/SPIRV/libSPIRV/spirv.hpp +++ b/llvm-spirv/lib/SPIRV/libSPIRV/spirv.hpp @@ -508,6 +508,7 @@ enum Decoration { DecorationCacheSizeINTEL = 5900, DecorationDontStaticallyCoalesceINTEL = 5901, DecorationPrefetchINTEL = 5902, + DecorationBufferLocationINTEL = 5921, DecorationIOPipeStorageINTEL = 5944, DecorationMax = 0x7fffffff, }; @@ -962,6 +963,7 @@ enum Capability { CapabilityFPGARegINTEL = 5948, CapabilityKernelAttributesINTEL = 5892, CapabilityFPGAKernelAttributesINTEL = 5897, + CapabilityFPGABufferLocationINTEL = 5920, CapabilityUSMStorageClassesINTEL = 5935, CapabilityFPGAMemoryAccessesINTEL = 5898, CapabilityIOPipeINTEL = 5943, diff --git a/llvm-spirv/test/transcoding/FPGABufferLocation.ll b/llvm-spirv/test/transcoding/FPGABufferLocation.ll new file mode 100644 index 0000000000000..e649a89625d5e --- /dev/null +++ b/llvm-spirv/test/transcoding/FPGABufferLocation.ll @@ -0,0 +1,61 @@ +; RUN: llvm-as %s -o %t.bc +; RUN: llvm-spirv %t.bc --spirv-ext=+SPV_INTEL_fpga_buffer_location -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 %t.spv -o %t.rev.bc +; RUN: llvm-dis < %t.rev.bc | FileCheck %s --check-prefix=CHECK-LLVM + +; RUN: llvm-spirv -spirv-text -r %t.spt -o %t.rev.bc +; RUN: llvm-dis < %t.rev.bc | FileCheck %s --check-prefix=CHECK-LLVM + +; CHECK-SPIRV: 2 Capability FPGABufferLocationINTEL +; CHECK-SPIRV: 9 Extension "SPV_INTEL_fpga_buffer_location" +; CHECK-SPIRV: 3 Name [[ARGA:[0-9]+]] "a" +; CHECK-SPIRV: 3 Name [[ARGB:[0-9]+]] "b" +; CHECK-SPIRV: 3 Name [[ARGC:[0-9]+]] "c" +; CHECK-SPIRV: 3 Name [[ARGD:[0-9]+]] "d" +; CHECK-SPIRV: 3 Name [[ARGE:[0-9]+]] "e" +; CHECK-SPIRV-NOT: 4 Decorate [[ARGC]] BufferLocationINTEL -1 +; CHECK-SPIRV-NOT: 4 Decorate [[ARGC]] BufferLocationINTEL -1 +; CHECK-SPIRV: 4 Decorate [[ARGA]] BufferLocationINTEL 1 +; CHECK-SPIRV: 4 Decorate [[ARGB]] BufferLocationINTEL 2 +; CHECK-SPIRV-NOT: 4 Decorate [[ARGD]] BufferLocationINTEL -1 +; CHECK-SPIRV-NOT: 4 Decorate [[ARGE]] BufferLocationINTEL 3 + +; CHECK-SPIRV: 5 Function +; CHECK-SPIRV: 3 FunctionParameter {{[0-9]+}} [[ARGA]] +; CHECK-SPIRV: 3 FunctionParameter {{[0-9]+}} [[ARGB]] +; CHECK-SPIRV: 3 FunctionParameter {{[0-9]+}} [[ARGC]] +; CHECK-SPIRV: 3 FunctionParameter {{[0-9]+}} [[ARGD]] +; CHECK-SPIRV: 3 FunctionParameter {{[0-9]+}} [[ARGE]] + +; CHECK-LLVM: define spir_kernel void @test{{.*}} !kernel_arg_buffer_location ![[BUFLOC_MD:[0-9]+]] {{.*}} +; CHECK-LLVM: ![[BUFLOC_MD]] = !{i32 1, i32 2, i32 -1, i32 -1, i32 -1} + +; ModuleID = 'buffer_location.cl' +source_filename = "buffer_location.cl" +target datalayout = "e-i64:64-v16:16-v24:32-v32:32-v48:64-v96:128-v192:256-v256:256-v512:512-v1024:1024" +target triple = "spir64-unknown-unknown" + +; Function Attrs: norecurse nounwind readnone +define spir_kernel void @test(i32 addrspace(1)* %a, float addrspace(1)* %b, i32 addrspace(1)* %c, i32 %d, i32 %e) local_unnamed_addr !kernel_arg_addr_space !3 !kernel_arg_access_qual !4 !kernel_arg_type !5 !kernel_arg_base_type !5 !kernel_arg_buffer_location !6 { +entry: + ret void +} + +!opencl.enable.FP_CONTRACT = !{} +!opencl.ocl.version = !{!0} +!opencl.spir.version = !{!0} +!opencl.used.extensions = !{!1} +!opencl.used.optional.core.features = !{!1} +!opencl.compiler.options = !{!1} +!llvm.ident = !{!2} + +!0 = !{i32 2, i32 0} +!1 = !{} +!2 = !{!""} +!3 = !{i32 1, i32 1, i32 1} +!4 = !{!"none", !"none", !"none"} +!5 = !{!"int*", !"float*", !"int*"} +!6 = !{i32 1, i32 2, i32 -1, i32 -1, i32 3}