| //===- AMDGPUExportKernelRuntimeHandles.cpp - Lower enqueued block --------===// | |
| // | |
| // 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 | |
| // | |
| //===----------------------------------------------------------------------===// | |
| // | |
| // \file | |
| // | |
| // Give any globals used for OpenCL block enqueue runtime handles external | |
| // linkage so the runtime may access them. These should behave like internal | |
| // functions for purposes of linking, but need to have an external symbol in the | |
| // final object for the runtime to access them. | |
| // | |
| // TODO: This could be replaced with a new linkage type or global object | |
| // metadata that produces an external symbol in the final object, but allows | |
| // rename on IR linking. Alternatively if we can rely on | |
| // GlobalValue::getGlobalIdentifier we can just make these external symbols to | |
| // begin with. | |
| // | |
| //===----------------------------------------------------------------------===// | |
| #include "AMDGPUExportKernelRuntimeHandles.h" | |
| #include "AMDGPU.h" | |
| #include "llvm/IR/Module.h" | |
| #include "llvm/Pass.h" | |
| #define DEBUG_TYPE "amdgpu-export-kernel-runtime-handles" | |
| using namespace llvm; | |
| namespace { | |
| /// Lower enqueued blocks. | |
| class AMDGPUExportKernelRuntimeHandlesLegacy : public ModulePass { | |
| public: | |
| static char ID; | |
| explicit AMDGPUExportKernelRuntimeHandlesLegacy() : ModulePass(ID) {} | |
| private: | |
| bool runOnModule(Module &M) override; | |
| }; | |
| } // end anonymous namespace | |
| char AMDGPUExportKernelRuntimeHandlesLegacy::ID = 0; | |
| char &llvm::AMDGPUExportKernelRuntimeHandlesLegacyID = | |
| AMDGPUExportKernelRuntimeHandlesLegacy::ID; | |
| INITIALIZE_PASS(AMDGPUExportKernelRuntimeHandlesLegacy, DEBUG_TYPE, | |
| "Externalize enqueued block runtime handles", false, false) | |
| ModulePass *llvm::createAMDGPUExportKernelRuntimeHandlesLegacyPass() { | |
| return new AMDGPUExportKernelRuntimeHandlesLegacy(); | |
| } | |
| static bool exportKernelRuntimeHandles(Module &M) { | |
| bool Changed = false; | |
| const StringLiteral HandleSectionName(".amdgpu.kernel.runtime.handle"); | |
| for (GlobalVariable &GV : M.globals()) { | |
| if (GV.getSection() == HandleSectionName) { | |
| GV.setLinkage(GlobalValue::ExternalLinkage); | |
| GV.setDSOLocal(false); | |
| Changed = true; | |
| } | |
| } | |
| if (!Changed) | |
| return false; | |
| // FIXME: We shouldn't really need to export the kernel address. We can | |
| // initialize the runtime handle with the kernel descriptor. | |
| for (Function &F : M) { | |
| if (F.getCallingConv() != CallingConv::AMDGPU_KERNEL) | |
| continue; | |
| const MDNode *Associated = F.getMetadata(LLVMContext::MD_associated); | |
| if (!Associated) | |
| continue; | |
| auto *VM = cast<ValueAsMetadata>(Associated->getOperand(0)); | |
| auto *Handle = dyn_cast<GlobalObject>(VM->getValue()); | |
| if (Handle && Handle->getSection() == HandleSectionName) { | |
| F.setLinkage(GlobalValue::ExternalLinkage); | |
| F.setVisibility(GlobalValue::ProtectedVisibility); | |
| } | |
| } | |
| return Changed; | |
| } | |
| bool AMDGPUExportKernelRuntimeHandlesLegacy::runOnModule(Module &M) { | |
| return exportKernelRuntimeHandles(M); | |
| } | |
| PreservedAnalyses | |
| AMDGPUExportKernelRuntimeHandlesPass::run(Module &M, | |
| ModuleAnalysisManager &MAM) { | |
| if (!exportKernelRuntimeHandles(M)) | |
| return PreservedAnalyses::all(); | |
| PreservedAnalyses PA; | |
| PA.preserveSet<AllAnalysesOn<Function>>(); | |
| return PA; | |
| } |