diff --git a/lib/SPIRV/PreprocessMetadata.cpp b/lib/SPIRV/PreprocessMetadata.cpp index 10e0d78675..32beea3b24 100644 --- a/lib/SPIRV/PreprocessMetadata.cpp +++ b/lib/SPIRV/PreprocessMetadata.cpp @@ -224,9 +224,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 @@ -234,8 +256,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()) @@ -319,17 +339,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 d40a3ccafb..a67b7af3d5 100644 --- a/lib/SPIRV/SPIRVReader.cpp +++ b/lib/SPIRV/SPIRVReader.cpp @@ -932,6 +932,14 @@ void SPIRVToLLVM::setLLVMLoopMetadata(const LoopInstType *LM, "llvm.loop.intel.loopcount_avg", static_cast(LoopCountAvg))); } } + if (LC & spv::internal::LoopControlMaxReinvocationDelayINTELMask) { + Metadata.push_back(llvm::MDNode::get( + *Context, getMetadataFromNameAndParameter( + "llvm.loop.intel.max_reinvocation_delay.count", + LoopControlParameters[NumParam++]))); + assert(NumParam <= LoopControlParameters.size() && + "Missing loop control parameter!"); + } llvm::MDNode *Node = llvm::MDNode::get(*Context, Metadata); // Set the first operand to refer itself @@ -4091,6 +4099,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( internal::ExecutionModeStreamingInterfaceINTEL)) { diff --git a/lib/SPIRV/SPIRVWriter.cpp b/lib/SPIRV/SPIRVWriter.cpp index e8f7848e07..23d156b722 100644 --- a/lib/SPIRV/SPIRVWriter.cpp +++ b/lib/SPIRV/SPIRVWriter.cpp @@ -973,6 +973,8 @@ void LLVMToSPIRVBase::transVectorComputeMetadata(Function *F) { } } +static void transMetadataDecorations(Metadata *MD, SPIRVEntry *Target); + void LLVMToSPIRVBase::transFPGAFunctionMetadata(SPIRVFunction *BF, Function *F) { if (MDNode *StallEnable = F->getMetadata(kSPIR2MD::StallEnable)) { @@ -1021,6 +1023,10 @@ void LLVMToSPIRVBase::transFPGAFunctionMetadata(SPIRVFunction *BF, BF->addDecorate(new SPIRVDecoratePipelineEnableINTEL(BF, !Disable)); } } + + // In addition, process the decorations on the function + if (auto *FDecoMD = F->getMetadata(SPIRV_MD_DECORATIONS)) + transMetadataDecorations(FDecoMD, BF); } void LLVMToSPIRVBase::transAuxDataInst(SPIRVFunction *BF, Function *F) { @@ -1563,6 +1569,14 @@ LLVMToSPIRVBase::getLoopControl(const BranchInst *Branch, BM->addCapability(CapabilityFPGALoopControlsINTEL); LoopCount.Avg = getMDOperandAsInt(Node, 1); LoopControl |= spv::internal::LoopControlLoopCountINTELMask; + } else if (S == "llvm.loop.intel.max_reinvocation_delay.count") { + BM->addExtension(ExtensionID::SPV_INTEL_fpga_loop_controls); + BM->addCapability(CapabilityFPGALoopControlsINTEL); + size_t I = getMDOperandAsInt(Node, 1); + ParametersToSort.emplace_back( + spv::internal::LoopControlMaxReinvocationDelayINTELMask, I); + LoopControl |= + spv::internal::LoopControlMaxReinvocationDelayINTELMask; } } } @@ -2820,6 +2834,12 @@ using DecorationsInfoVec = struct AnnotationDecorations { DecorationsInfoVec MemoryAttributesVec; DecorationsInfoVec MemoryAccessesVec; + DecorationsInfoVec CacheControlVec; + + bool empty() { + return (MemoryAttributesVec.empty() && MemoryAccessesVec.empty() && + CacheControlVec.empty()); + } }; struct IntelLSUControlsInfo { @@ -2996,6 +3016,8 @@ AnnotationDecorations tryParseAnnotationString(SPIRVModule *BM, BM->isAllowedToUseExtension(ExtensionID::SPV_INTEL_fpga_memory_accesses); const bool AllowFPGAMemAttr = BM->isAllowedToUseExtension( ExtensionID::SPV_INTEL_fpga_memory_attributes); + const bool AllowCacheControls = + BM->isAllowedToUseExtension(ExtensionID::SPV_INTEL_cache_controls); bool ValidDecorationFound = false; DecorationsInfoVec DecorationsVec; @@ -3014,8 +3036,15 @@ AnnotationDecorations tryParseAnnotationString(SPIRVModule *BM, std::vector DecValues; if (tryParseAnnotationDecoValues(ValueStr, DecValues)) { ValidDecorationFound = true; - DecorationsVec.emplace_back(static_cast(DecorationKind), - std::move(DecValues)); + + if (AllowCacheControls && + DecorationKind == internal::DecorationCacheControlLoadINTEL) { + Decorates.CacheControlVec.emplace_back( + static_cast(DecorationKind), std::move(DecValues)); + } else { + DecorationsVec.emplace_back(static_cast(DecorationKind), + std::move(DecValues)); + } } continue; } @@ -3117,7 +3146,7 @@ void addAnnotationDecorations(SPIRVEntry *E, DecorationsInfoVec &Decorations) { continue; } - switch (I.first) { + switch (static_cast(I.first)) { case DecorationUserSemantic: M->getErrorLog().checkError(I.second.size() == 1, SPIRVEC_InvalidLlvmModule, @@ -3201,6 +3230,21 @@ void addAnnotationDecorations(SPIRVEntry *E, DecorationsInfoVec &Decorations) { E->addDecorate(I.first, Result); } } break; + case spv::internal::DecorationCacheControlLoadINTEL: { + if (M->isAllowedToUseExtension(ExtensionID::SPV_INTEL_cache_controls)) { + M->getErrorLog().checkError( + I.second.size() == 2, SPIRVEC_InvalidLlvmModule, + "CacheControlLoadINTEL requires exactly 2 extra operands"); + SPIRVWord CacheLevel = 0; + SPIRVWord CacheControl = 0; + StringRef(I.second[0]).getAsInteger(10, CacheLevel); + StringRef(I.second[1]).getAsInteger(10, CacheControl); + E->addDecorate(new SPIRVDecorateCacheControlLoadINTEL( + E, CacheLevel, + static_cast(CacheControl))); + } + } + default: // Other decorations are either not supported by the translator or // handled in other places. @@ -3931,15 +3975,17 @@ SPIRVValue *LLVMToSPIRVBase::transIntrinsicInst(IntrinsicInst *II, } else { // Memory accesses to a standalone pointer variable auto *DecSubj = transValue(II->getArgOperand(0), BB); - if (Decorations.MemoryAccessesVec.empty()) + if (Decorations.empty()) DecSubj->addDecorate(new SPIRVDecorateUserSemanticAttr( DecSubj, AnnotationString.c_str())); - else + else { // Apply the LSU parameter decoration to the pointer result of an // instruction. Note it's the address to the accessed memory that's // loaded from the original pointer variable, and not the value // accessed by the latter. addAnnotationDecorations(DecSubj, Decorations.MemoryAccessesVec); + addAnnotationDecorations(DecSubj, Decorations.CacheControlVec); + } II->replaceAllUsesWith(II->getOperand(0)); } } @@ -4762,6 +4808,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::internal::ExecutionModeStreamingInterfaceINTEL: { if (!BM->isAllowedToUseExtension( ExtensionID::SPV_INTEL_kernel_attributes)) diff --git a/lib/SPIRV/libSPIRV/SPIRVEntry.cpp b/lib/SPIRV/libSPIRV/SPIRVEntry.cpp index a72b658266..a949d40b8e 100644 --- a/lib/SPIRV/libSPIRV/SPIRVEntry.cpp +++ b/lib/SPIRV/libSPIRV/SPIRVEntry.cpp @@ -626,6 +626,7 @@ void SPIRVExecutionMode::decode(std::istream &I) { case ExecutionModeMaxWorkDimINTEL: case ExecutionModeNumSIMDWorkitemsINTEL: case ExecutionModeSchedulerTargetFmaxMhzINTEL: + case ExecutionModeRegisterMapInterfaceINTEL: case internal::ExecutionModeStreamingInterfaceINTEL: WordLiterals.resize(1); break; diff --git a/lib/SPIRV/libSPIRV/SPIRVEnum.h b/lib/SPIRV/libSPIRV/SPIRVEnum.h index 4874e3ab0d..0761e16606 100644 --- a/lib/SPIRV/libSPIRV/SPIRVEnum.h +++ b/lib/SPIRV/libSPIRV/SPIRVEnum.h @@ -273,6 +273,8 @@ template <> inline void SPIRVMap::init() { {CapabilityVectorComputeINTEL}); ADD_VEC_INIT(internal::ExecutionModeFastCompositeKernelINTEL, {internal::CapabilityFastCompositeINTEL}); + ADD_VEC_INIT(ExecutionModeRegisterMapInterfaceINTEL, + {CapabilityFPGAKernelAttributesv2INTEL}); ADD_VEC_INIT(internal::ExecutionModeStreamingInterfaceINTEL, {CapabilityFPGAKernelAttributesINTEL}); ADD_VEC_INIT(ExecutionModeNamedBarrierCountINTEL, diff --git a/lib/SPIRV/libSPIRV/SPIRVIsValidEnum.h b/lib/SPIRV/libSPIRV/SPIRVIsValidEnum.h index a10e624486..2cb3452e1b 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 internal::ExecutionModeStreamingInterfaceINTEL: return true; default: diff --git a/lib/SPIRV/libSPIRV/SPIRVNameMapEnum.h b/lib/SPIRV/libSPIRV/SPIRVNameMapEnum.h index a2289bab57..94b9a2682e 100644 --- a/lib/SPIRV/libSPIRV/SPIRVNameMapEnum.h +++ b/lib/SPIRV/libSPIRV/SPIRVNameMapEnum.h @@ -568,6 +568,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/lib/SPIRV/libSPIRV/spirv_internal.hpp b/lib/SPIRV/libSPIRV/spirv_internal.hpp index c09a38f5c7..63fd50c5f0 100644 --- a/lib/SPIRV/libSPIRV/spirv_internal.hpp +++ b/lib/SPIRV/libSPIRV/spirv_internal.hpp @@ -123,7 +123,10 @@ enum InternalExecutionMode { IExecModeStreamingInterfaceINTEL = 6154 }; -enum InternalLoopControlMask { ILoopControlLoopCountINTELMask = 0x1000000 }; +enum InternalLoopControlMask { + ILoopControlLoopCountINTELMask = 0x1000000, + ILoopControlMaxReinvocationDelayINTELMask = 0x2000000 +}; constexpr LinkageType LinkageTypeInternal = static_cast(ILTInternal); @@ -293,6 +296,8 @@ constexpr ExecutionMode ExecutionModeStreamingInterfaceINTEL = constexpr LoopControlMask LoopControlLoopCountINTELMask = static_cast(ILoopControlLoopCountINTELMask); +static const LoopControlMask LoopControlMaxReinvocationDelayINTELMask = + static_cast(ILoopControlMaxReinvocationDelayINTELMask); } // namespace internal } // namespace spv diff --git a/test/extensions/INTEL/SPV_INTEL_cache_controls/decorate-prefetch-w-cache-controls.ll b/test/extensions/INTEL/SPV_INTEL_cache_controls/decorate-prefetch-w-cache-controls.ll new file mode 100644 index 0000000000..0687e5685f --- /dev/null +++ b/test/extensions/INTEL/SPV_INTEL_cache_controls/decorate-prefetch-w-cache-controls.ll @@ -0,0 +1,96 @@ +; RUN: llvm-as %s -o %t.bc +; RUN: llvm-spirv --spirv-ext=+SPV_INTEL_cache_controls -spirv-text %t.bc -o - | FileCheck %s --check-prefix=CHECK-SPIRV + +; RUN: llvm-spirv --spirv-ext=+SPV_INTEL_cache_controls %t.bc -o %t.spv +; RUN: llvm-spirv -r %t.spv --spirv-target-env=SPV-IR -o - | llvm-dis -o - | FileCheck %s --check-prefix=CHECK-LLVM + +target datalayout = "e-i64:64-v16:16-v24:32-v32:32-v48:64-v96:128-v192:256-v256:256-v512:512-v1024:1024-n8:16:32:64" +target triple = "spir64-unknown-unknown" + +$_ZTSZ4mainEUlvE_ = comdat any + +; https://github.com/KhronosGroup/SPIRV-Registry/blob/main/extensions/INTEL/SPV_INTEL_cache_controls.asciidoc +; These strings are: +; {CacheControlLoadINTEL_Token:\22CacheLevel,CacheControl\22} +@.str.1 = private unnamed_addr addrspace(1) constant [16 x i8] c"../prefetch.hpp\00", section "llvm.metadata" +@.str.9 = private unnamed_addr addrspace(1) constant [13 x i8] c"{6442:\220,1\22}\00", section "llvm.metadata" +@.str.10 = private unnamed_addr addrspace(1) constant [13 x i8] c"{6442:\221,1\22}\00", section "llvm.metadata" +@.str.11 = private unnamed_addr addrspace(1) constant [13 x i8] c"{6442:\222,3\22}\00", section "llvm.metadata" + +; these CHECK-SPIRV check that prefetch's arg is decorated with the appropriate +; CacheLevel and CacheControl values. + +; CHECK-SPIRV: ExtInst [[#]] [[#]] [[#]] prefetch [[#]] [[#]] +; CHECK-SPIRV: ExtInst [[#]] [[#]] [[#]] prefetch [[#]] [[#]] +; CHECK-SPIRV: ExtInst [[#]] [[#]] [[#]] prefetch [[#]] [[#]] + +; Check that the appropriate !spirv.Decorations are preserved after reverse +; translation + +; CHECK-LLVM: %[[CALL1:.*]] = call spir_func i8 addrspace(1)* @_Z41__spirv_GenericCastToPtrExplicit_ToGlobal{{.*}} +; CHECK-LLVM: %[[CALL1P4:.*]] = addrspacecast i8 addrspace(1)* %[[CALL1]] to i8 addrspace(4)* +; CHECK-LLVM: call spir_func void @_Z20__spirv_ocl_prefetch{{.*}}(i8 addrspace(4)* %[[CALL1P4]], i64 1) +; CHECK-LLVM: %[[CALL2:.*]] = call spir_func i8 addrspace(1)* @_Z41__spirv_GenericCastToPtrExplicit_ToGlobal{{.*}} +; CHECK-LLVM: %[[CALL2P4:.*]] = addrspacecast i8 addrspace(1)* %[[CALL2]] to i8 addrspace(4)* +; CHECK-LLVM: call spir_func void @_Z20__spirv_ocl_prefetch{{.*}}(i8 addrspace(4)* %[[CALL2P4]], i64 1) +; CHECK-LLVM: %[[CALL3:.*]] = call spir_func i8 addrspace(1)* @_Z41__spirv_GenericCastToPtrExplicit_ToGlobal{{.*}} +; CHECK-LLVM: %[[CALL3P4:.*]] = addrspacecast i8 addrspace(1)* %[[CALL3]] to i8 addrspace(4)* +; CHECK-LLVM: call spir_func void @_Z20__spirv_ocl_prefetch{{.*}}(i8 addrspace(4)* %[[CALL3P4]], i64 2) + + +; Function Attrs: convergent norecurse nounwind +define weak_odr dso_local spir_kernel void @_ZTSZ4mainEUlvE_(i8 addrspace(1)* noundef align 1 %_arg_dataPtr) local_unnamed_addr comdat !srcloc !5 !kernel_arg_buffer_location !6 !sycl_fixed_targets !7 !sycl_kernel_omit_args !8 { +entry: + %0 = addrspacecast i8 addrspace(1)* %_arg_dataPtr to i8 addrspace(4)* + %call.i.i.i.i = tail call spir_func noundef i8 addrspace(1)* @_Z41__spirv_GenericCastToPtrExplicit_ToGlobalPvi(i8 addrspace(4)* noundef %0, i32 noundef 5) + %call.i.i.i.i.p4 = addrspacecast i8 addrspace(1)* %call.i.i.i.i to i8 addrspace(4)* + %ptr1 = getelementptr inbounds [13 x i8], [13 x i8] addrspace(1)* @.str.9, i64 0, i64 0 + %ptr2 = getelementptr inbounds [16 x i8], [16 x i8] addrspace(1)* @.str.1, i64 0, i64 0 + %ptr1.p4 = addrspacecast i8 addrspace(1)* %ptr1 to i8 addrspace(4)* + %ptr1.p0 = addrspacecast i8 addrspace(4)* %ptr1.p4 to i8* + %ptr2.p4 = addrspacecast i8 addrspace(1)* %ptr2 to i8 addrspace(4)* + %ptr2.p0 = addrspacecast i8 addrspace(4)* %ptr2.p4 to i8* + %1 = tail call i8 addrspace(4)* @llvm.ptr.annotation.p4.p1(i8 addrspace(4)* %call.i.i.i.i.p4, i8* %ptr1.p0, i8* %ptr2.p0, i32 76) + tail call spir_func void @_Z20__spirv_ocl_prefetchPU3AS1Kcm(i8 addrspace(4)* noundef %1, i64 noundef 1) + %arrayidx3.i = getelementptr inbounds i8, i8 addrspace(4)* %0, i64 1 + %call.i.i.i13.i = tail call spir_func noundef i8 addrspace(1)* @_Z41__spirv_GenericCastToPtrExplicit_ToGlobalPvi(i8 addrspace(4)* noundef %arrayidx3.i, i32 noundef 5) + %call.i.i.i13.i.p4 = addrspacecast i8 addrspace(1)* %call.i.i.i13.i to i8 addrspace(4)* + %ptr3 = getelementptr inbounds [13 x i8], [13 x i8] addrspace(1)* @.str.10, i64 0, i64 0 + %ptr3.p4 = addrspacecast i8 addrspace(1)* %ptr3 to i8 addrspace(4)* + %ptr3.p0 = addrspacecast i8 addrspace(4)* %ptr3.p4 to i8* + %2 = tail call i8 addrspace(4)* @llvm.ptr.annotation.p4.p1(i8 addrspace(4)* %call.i.i.i13.i.p4, i8* %ptr3.p0, i8* %ptr2.p0, i32 80) + tail call spir_func void @_Z20__spirv_ocl_prefetchPU3AS1Kcm(i8 addrspace(4)* noundef %2, i64 noundef 1) + %arrayidx7.i = getelementptr inbounds i8, i8 addrspace(4)* %0, i64 2 + %call.i.i.i16.i = tail call spir_func noundef i8 addrspace(1)* @_Z41__spirv_GenericCastToPtrExplicit_ToGlobalPvi(i8 addrspace(4)* noundef %arrayidx7.i, i32 noundef 5) + %call.i.i.i16.i.p4 = addrspacecast i8 addrspace(1)* %call.i.i.i16.i to i8 addrspace(4)* + %ptr4 = getelementptr inbounds [13 x i8], [13 x i8] addrspace(1)* @.str.11, i64 0, i64 0 + %ptr4.p4 = addrspacecast i8 addrspace(1)* %ptr4 to i8 addrspace(4)* + %ptr4.p0 = addrspacecast i8 addrspace(4)* %ptr4.p4 to i8* + %3 = tail call i8 addrspace(4)* @llvm.ptr.annotation.p4.p1(i8 addrspace(4)* %call.i.i.i16.i.p4, i8* %ptr4.p0, i8* %ptr2.p0, i32 80) + tail call spir_func void @_Z20__spirv_ocl_prefetchPU3AS1Kcm(i8 addrspace(4)* noundef %3, i64 noundef 2) + ret void +} + +; Function Attrs: mustprogress nocallback nofree nosync nounwind willreturn memory(inaccessiblemem: readwrite) +declare i8 addrspace(4)* @llvm.ptr.annotation.p4.p1(i8 addrspace(4)*, i8*, i8*, i32) + +; Function Attrs: convergent nounwind +declare dso_local spir_func void @_Z20__spirv_ocl_prefetchPU3AS1Kcm(i8 addrspace(4)* noundef, i64 noundef) local_unnamed_addr + +; Function Attrs: convergent mustprogress nofree nounwind willreturn memory(none) +declare dso_local spir_func noundef i8 addrspace(1)* @_Z41__spirv_GenericCastToPtrExplicit_ToGlobalPvi(i8 addrspace(4)* noundef, i32 noundef) local_unnamed_addr + +!llvm.module.flags = !{!0, !1} +!opencl.spir.version = !{!2} +!spirv.Source = !{!3} +!llvm.ident = !{!4} + +!0 = !{i32 1, !"wchar_size", i32 4} +!1 = !{i32 7, !"frame-pointer", i32 2} +!2 = !{i32 1, i32 2} +!3 = !{i32 4, i32 100000} +!4 = !{!"clang version 18.0.0"} +!5 = !{i32 1522} +!6 = !{i32 -1} +!7 = !{} +!8 = !{i1 false} diff --git a/test/transcoding/SPV_INTEL_fpga_loop_controls/FPGALoopMergeInst.ll b/test/transcoding/SPV_INTEL_fpga_loop_controls/FPGALoopMergeInst.ll index 8926e76f18..8c96351745 100644 --- a/test/transcoding/SPV_INTEL_fpga_loop_controls/FPGALoopMergeInst.ll +++ b/test/transcoding/SPV_INTEL_fpga_loop_controls/FPGALoopMergeInst.ll @@ -90,6 +90,14 @@ ; for (int i = 0; i != 10; ++i) ; a[i] = 0; ; } +; +; void max_reinvocation_delay() { +; int a[10]; +; [[intel::max_reinvocation_delay(2)]] +; for (int i = 0; i != 10; ++i) +; a[i] = 0; +; } + ; TODO: This source code will result in different LLVM IR after ; rev [a47242e4b2c1c9] of https://github.com/intel/llvm (the @@ -478,6 +486,40 @@ for.end: ; preds = %for.cond ret void } +; Function Attrs: noinline nounwind optnone +define spir_func void @max_reinvocation_delay() #3 { +entry: + %a = alloca [10 x i32], align 4 + %i = alloca i32, align 4 + store i32 0, i32* %i, align 4 + br label %for.cond + +; Per SPIR-V spec, LoopControlMaxReinvocationDelayINTELMask = 0x2000000 (33554432) +; CHECK-SPIRV: 5 LoopMerge {{[0-9]+}} {{[0-9]+}} 33554432 2 +; CHECK-SPIRV-NEXT: 4 BranchConditional {{[0-9]+}} {{[0-9]+}} {{[0-9]+}} +; CHECK-SPIRV-NEGATIVE-NOT: 5 LoopMerge {{[0-9]+}} {{[0-9]+}} 33554432 2 +for.cond: ; preds = %for.inc, %entry + %0 = load i32, i32* %i, align 4 + %cmp = icmp ne i32 %0, 10 + br i1 %cmp, label %for.body, label %for.end + +for.body: ; preds = %for.cond + %1 = load i32, i32* %i, align 4 + %idxprom = sext i32 %1 to i64 + %arrayidx = getelementptr inbounds [10 x i32], [10 x i32]* %a, i64 0, i64 %idxprom + store i32 0, i32* %arrayidx, align 4 + br label %for.inc + +for.inc: ; preds = %for.body + %2 = load i32, i32* %i, align 4 + %inc = add nsw i32 %2, 1 + store i32 %inc, i32* %i, align 4 + br label %for.cond, !llvm.loop !31 + +for.end: ; preds = %for.cond + ret void +} + attributes #0 = { "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "frame-pointer"="all" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "sycl-module-id"="FPGALoopMergeInst.cpp" "uniform-work-group-size"="true" "unsafe-fp-math"="false" "use-soft-float"="false" } attributes #1 = { argmemonly nounwind willreturn } attributes #2 = { inlinehint nounwind "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "frame-pointer"="all" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" } @@ -520,6 +562,8 @@ attributes #4 = { nounwind } !28 = !{!"llvm.loop.intel.speculated.iterations.count", i32 4} !29 = distinct !{!29, !30} !30 = !{!"llvm.loop.fusion.disable"} +!31 = distinct !{!31, !32} +!32 = !{!"llvm.loop.intel.max_reinvocation_delay.count", i32 2} ; CHECK-LLVM: br label %while.cond, !llvm.loop ![[MD_A:[0-9]+]] ; CHECK-LLVM: br label %while.cond{{[0-9]+}}, !llvm.loop ![[MD_B:[0-9]+]] @@ -531,6 +575,7 @@ attributes #4 = { nounwind } ; CHECK-LLVM: br label %for.cond{{[0-9]*}}, !llvm.loop ![[MD_H:[0-9]+]] ; CHECK-LLVM: br label %for.cond{{[0-9]*}}, !llvm.loop ![[MD_I:[0-9]+]] ; CHECK-LLVM: br label %for.cond{{[0-9]*}}, !llvm.loop ![[MD_NF:[0-9]+]] +; CHECK-LLVM: br label %for.cond{{[0-9]*}}, !llvm.loop ![[MD_MRD:[0-9]+]] ; CHECK-LLVM: ![[MD_A]] = distinct !{![[MD_A]], ![[MD_ivdep_enable:[0-9]+]]} ; CHECK-LLVM: ![[MD_ivdep_enable]] = !{!"llvm.loop.ivdep.enable"} @@ -553,3 +598,5 @@ attributes #4 = { nounwind } ; CHECK-LLVM: ![[MD_spec_iterations]] = !{!"llvm.loop.intel.speculated.iterations.count", i32 4} ; CHECK-LLVM: ![[MD_NF]] = distinct !{![[MD_NF]], ![[MD_nofusion:[0-9]+]]} ; CHECK-LLVM: ![[MD_nofusion]] = !{!"llvm.loop.fusion.disable"} +; CHECK-LLVM: ![[MD_MRD]] = distinct !{![[MD_MRD]], ![[MD_max_reinvocation_delay:[0-9]+]]} +; CHECK-LLVM: ![[MD_max_reinvocation_delay]] = !{!"llvm.loop.intel.max_reinvocation_delay.count", i32 2} diff --git a/test/transcoding/SPV_INTEL_kernel_attributes/register_map_interface_attribute.ll b/test/transcoding/SPV_INTEL_kernel_attributes/register_map_interface_attribute.ll new file mode 100644 index 0000000000..1878e24399 --- /dev/null +++ b/test/transcoding/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 %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"} diff --git a/test/transcoding/SPV_INTEL_kernel_attributes/spirv_fpga_function_decorations.ll b/test/transcoding/SPV_INTEL_kernel_attributes/spirv_fpga_function_decorations.ll new file mode 100644 index 0000000000..e741a52b77 --- /dev/null +++ b/test/transcoding/SPV_INTEL_kernel_attributes/spirv_fpga_function_decorations.ll @@ -0,0 +1,45 @@ +; Check that !spirv.Decorations are handled on FPGA functions as well as global variables +; RUN: llvm-as %s -o %t.bc +; RUN: llvm-spirv %t.bc --spirv-ext=+SPV_INTEL_fpga_invocation_pipelining_attributes -spirv-text -o - | FileCheck %s --check-prefix=CHECK-SPIRV +; RUN: llvm-spirv --spirv-ext=+SPV_INTEL_fpga_invocation_pipelining_attributes %t.bc -o %t.spv +; RUN: llvm-spirv --spirv-ext=+SPV_INTEL_fpga_invocation_pipelining_attributes -r %t.spv --spirv-target-env=SPV-IR -o %t.rev.bc +; RUN: llvm-dis < %t.rev.bc | FileCheck %s --check-prefix=CHECK-SPV-IR +; RUN: llvm-spirv -r --spirv-ext=+SPV_INTEL_fpga_invocation_pipelining_attributes %t.spv --spirv-target-env=SPV-IR -o %t.rev.bc +; RUN: llvm-dis < %t.rev.bc | FileCheck %s --check-prefix=CHECK-LLVM + +target datalayout = "e-p:32:32-i64:64-v16:16-v24:32-v32:32-v48:64-v96:128-v192:256-v256:256-v512:512-v1024:1024" +target triple = "spir" + +; Function Attrs: convergent nounwind +define spir_kernel void @k(float %a, float %b, float %c) #0 !kernel_arg_addr_space !4 !kernel_arg_access_qual !5 !kernel_arg_type !6 !kernel_arg_type_qual !7 !kernel_arg_base_type !6 !spirv.Decorations !9 { +entry: + ret void +} + +; CHECK-SPIRV: Decorate [[PId1:[0-9]+]] PipelineEnableINTEL 1 +; CHECK-SPIRV: Decorate [[PId1]] InitiationIntervalINTEL 2 + +!llvm.module.flags = !{!0} +!opencl.ocl.version = !{!1} +!opencl.spir.version = !{!2} +!llvm.ident = !{!3} + +!0 = !{i32 1, !"wchar_size", i32 4} +!1 = !{i32 1, i32 0} +!2 = !{i32 1, i32 2} +!3 = !{!"clang version 14.0.0"} +!4 = !{i32 0, i32 0, i32 0} +!5 = !{!"none", !"none", !"none"} +!6 = !{!"float", !"float", !"float"} +!7 = !{!"", !"", !""} +!8 = !{i32 19} +!9 = !{!10, !11} +!10 = !{i32 5919, i32 1} +!11 = !{i32 5917, i32 2} + +; CHECK-SPV-IR: define spir_kernel void @k(float %a, float %b, float %c) {{.*}} !initiation_interval ![[II:[0-9]+]] !disable_loop_pipelining ![[DISABLE_LOOP_PIPELINING:[0-9]+]] { +; CHECK-SPV-IR-DAG: ![[II]] = !{i32 2} +; CHECK-SPV-IR-DAG: ![[DISABLE_LOOP_PIPELINING]] = !{i32 0} + +; CHECK-LLVM-NOT: define spir_kernel void @k(float %a, float %b, float %c) {{.*}} !spirv.Decorations ![[DecoListId:[0-9]+]] { +; CHECK-LLVM: define spir_kernel void @k(float %a, float %b, float %c) {{.*}} {