diff --git a/llvm/include/llvm/SYCLLowerIR/ESIMD/ESIMDUtils.h b/llvm/include/llvm/SYCLLowerIR/ESIMD/ESIMDUtils.h index 109753fb3b3a1..8a2df48e780a8 100644 --- a/llvm/include/llvm/SYCLLowerIR/ESIMD/ESIMDUtils.h +++ b/llvm/include/llvm/SYCLLowerIR/ESIMD/ESIMDUtils.h @@ -16,6 +16,7 @@ namespace llvm { namespace esimd { constexpr char ATTR_DOUBLE_GRF[] = "esimd-double-grf"; +constexpr char ESIMD_MARKER_MD[] = "sycl_explicit_simd"; using CallGraphNodeAction = std::function; void traverseCallgraphUp(llvm::Function *F, CallGraphNodeAction NodeF, @@ -34,6 +35,8 @@ void traverseCallgraphUp(Function *F, CallGraphNodeActionF ActionF, // Tells whether given function is a ESIMD kernel. bool isESIMDKernel(const Function &F); +// Tells whether given function is a ESIMD function. +bool isESIMD(const Function &F); /// Reports and error with the message \p Msg concatenated with the optional /// \p OptMsg if \p Condition is false. diff --git a/llvm/include/llvm/SYCLLowerIR/ESIMD/LowerESIMD.h b/llvm/include/llvm/SYCLLowerIR/ESIMD/LowerESIMD.h index a40667d07b6fa..fb59621add194 100644 --- a/llvm/include/llvm/SYCLLowerIR/ESIMD/LowerESIMD.h +++ b/llvm/include/llvm/SYCLLowerIR/ESIMD/LowerESIMD.h @@ -76,6 +76,12 @@ class SYCLLowerESIMDKernelPropsPass PreservedAnalyses run(Module &M, ModuleAnalysisManager &); }; +// Fixes ESIMD Kernel attributes for wrapper functions for ESIMD kernels +class SYCLFixupESIMDKernelWrapperMDPass + : public PassInfoMixin { +public: + PreservedAnalyses run(Module &M, ModuleAnalysisManager &); +}; } // namespace llvm #endif // LLVM_SYCLLOWERIR_LOWERESIMD_H diff --git a/llvm/lib/Passes/PassRegistry.def b/llvm/lib/Passes/PassRegistry.def index 07be606d3a292..0202b23c6aa92 100644 --- a/llvm/lib/Passes/PassRegistry.def +++ b/llvm/lib/Passes/PassRegistry.def @@ -135,6 +135,7 @@ MODULE_PASS("SYCLMutatePrintfAddrspace", SYCLMutatePrintfAddrspacePass()) MODULE_PASS("SPIRITTAnnotations", SPIRITTAnnotationsPass()) MODULE_PASS("deadargelim-sycl", DeadArgumentEliminationSYCLPass()) MODULE_PASS("sycllowerwglocalmemory", SYCLLowerWGLocalMemoryPass()) +MODULE_PASS("lower-esimd-kernel-attrs", SYCLFixupESIMDKernelWrapperMDPass()) #undef MODULE_PASS #ifndef MODULE_PASS_WITH_PARAMS diff --git a/llvm/lib/SYCLLowerIR/CMakeLists.txt b/llvm/lib/SYCLLowerIR/CMakeLists.txt index 57aa236f53083..21a5786bde3d7 100644 --- a/llvm/lib/SYCLLowerIR/CMakeLists.txt +++ b/llvm/lib/SYCLLowerIR/CMakeLists.txt @@ -53,6 +53,7 @@ add_llvm_component_library(LLVMSYCLLowerIR ESIMD/LowerESIMDVecArg.cpp ESIMD/ESIMDUtils.cpp ESIMD/ESIMDVerifier.cpp + ESIMD/LowerESIMDKernelAttrs.cpp LowerInvokeSimd.cpp LowerWGScope.cpp LowerWGLocalMemory.cpp diff --git a/llvm/lib/SYCLLowerIR/ESIMD/ESIMDUtils.cpp b/llvm/lib/SYCLLowerIR/ESIMD/ESIMDUtils.cpp index a2ddc06d1fa06..2f45a8407197b 100644 --- a/llvm/lib/SYCLLowerIR/ESIMD/ESIMDUtils.cpp +++ b/llvm/lib/SYCLLowerIR/ESIMD/ESIMDUtils.cpp @@ -54,9 +54,10 @@ void traverseCallgraphUp(llvm::Function *F, CallGraphNodeAction ActionF, } else { auto *CI = cast(FCall); - if ((CI->getCalledFunction() != CurF) && ErrorOnNonCallUse) { + if ((CI->getCalledFunction() != CurF)) { // CurF is used in a call, but not as the callee. - llvm::report_fatal_error(ErrMsg); + if (ErrorOnNonCallUse) + llvm::report_fatal_error(ErrMsg); } else { auto FCaller = CI->getFunction(); @@ -69,9 +70,12 @@ void traverseCallgraphUp(llvm::Function *F, CallGraphNodeAction ActionF, } } +bool isESIMD(const Function &F) { + return F.getMetadata(ESIMD_MARKER_MD) != nullptr; +} + bool isESIMDKernel(const Function &F) { - return (F.getCallingConv() == CallingConv::SPIR_KERNEL) && - (F.getMetadata("sycl_explicit_simd") != nullptr); + return (F.getCallingConv() == CallingConv::SPIR_KERNEL) && isESIMD(F); } } // namespace esimd diff --git a/llvm/lib/SYCLLowerIR/ESIMD/LowerESIMD.cpp b/llvm/lib/SYCLLowerIR/ESIMD/LowerESIMD.cpp index 8ac058f90416f..44dd23788460b 100644 --- a/llvm/lib/SYCLLowerIR/ESIMD/LowerESIMD.cpp +++ b/llvm/lib/SYCLLowerIR/ESIMD/LowerESIMD.cpp @@ -1215,6 +1215,7 @@ translateSpirvGlobalUses(LoadInst *LI, StringRef SpirvGlobalName, // TODO: Implement support for the following intrinsics: // uint32_t __spirv_BuiltIn NumSubgroups; // uint32_t __spirv_BuiltIn SubgroupId; + // uint32_t __spirv_BuiltIn GlobalLinearId // Translate those loads from _scalar_ SPIRV globals that can be replaced with // a const value here. @@ -1227,6 +1228,8 @@ translateSpirvGlobalUses(LoadInst *LI, StringRef SpirvGlobalName, SpirvGlobalName == "SubgroupMaxSize") { NewInst = llvm::Constant::getIntegerValue(LI->getType(), llvm::APInt(32, 1, true)); + } else if (SpirvGlobalName == "GlobalLinearId") { + NewInst = llvm::Constant::getNullValue(LI->getType()); } if (NewInst) { LI->replaceAllUsesWith(NewInst); diff --git a/llvm/lib/SYCLLowerIR/ESIMD/LowerESIMDKernelAttrs.cpp b/llvm/lib/SYCLLowerIR/ESIMD/LowerESIMDKernelAttrs.cpp new file mode 100644 index 0000000000000..91b969fcd106f --- /dev/null +++ b/llvm/lib/SYCLLowerIR/ESIMD/LowerESIMDKernelAttrs.cpp @@ -0,0 +1,42 @@ +//===---- LowerESIMDKernelAttrs - lower __esimd_set_kernel_attributes ---===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// Finds and adds sycl_explicit_simd attributes to wrapper functions that wrap +// ESIMD kernel functions + +#include "llvm/SYCLLowerIR/ESIMD/ESIMDUtils.h" +#include "llvm/SYCLLowerIR/ESIMD/LowerESIMD.h" + +#include "llvm/IR/Module.h" +#include "llvm/Pass.h" + +#define DEBUG_TYPE "LowerESIMDKernelAttrs" + +using namespace llvm; + +namespace llvm { +PreservedAnalyses +SYCLFixupESIMDKernelWrapperMDPass::run(Module &M, ModuleAnalysisManager &MAM) { + bool Modified = false; + for (Function &F : M) { + if (llvm::esimd::isESIMD(F)) { + llvm::esimd::traverseCallgraphUp( + &F, + [&](Function *GraphNode) { + if (!llvm::esimd::isESIMD(*GraphNode)) { + GraphNode->setMetadata( + llvm::esimd::ESIMD_MARKER_MD, + llvm::MDNode::get(GraphNode->getContext(), {})); + Modified = true; + } + }, + false); + } + } + return Modified ? PreservedAnalyses::none() : PreservedAnalyses::all(); +} +} // namespace llvm diff --git a/llvm/tools/sycl-post-link/sycl-post-link.cpp b/llvm/tools/sycl-post-link/sycl-post-link.cpp index 24cfc42b0bdcc..caf97a94bd5ab 100644 --- a/llvm/tools/sycl-post-link/sycl-post-link.cpp +++ b/llvm/tools/sycl-post-link/sycl-post-link.cpp @@ -665,6 +665,10 @@ processInputModule(std::unique_ptr M) { // if none were made. bool Modified = false; + // Propagate ESIMD attribute to wrapper functions to prevent + // spurious splits and kernel link errors. + Modified |= runModulePass(*M); + // After linking device bitcode "llvm.used" holds references to the kernels // that are defined in the device image. But after splitting device image into // separate kernels we may end up with having references to kernel declaration