|  | //===-- AMDGPUUnifyMetadata.cpp - Unify OpenCL metadata -------------------===// | 
|  | // | 
|  | //                     The LLVM Compiler Infrastructure | 
|  | // | 
|  | // This file is distributed under the University of Illinois Open Source | 
|  | // License. See LICENSE.TXT for details. | 
|  | // | 
|  | //===----------------------------------------------------------------------===// | 
|  | // | 
|  | // \file | 
|  | // \brief This pass that unifies multiple OpenCL metadata due to linking. | 
|  | // | 
|  | //===----------------------------------------------------------------------===// | 
|  |  | 
|  | #include "AMDGPU.h" | 
|  | #include "llvm/ADT/SmallVector.h" | 
|  | #include "llvm/ADT/StringRef.h" | 
|  | #include "llvm/IR/Constants.h" | 
|  | #include "llvm/IR/Function.h" | 
|  | #include "llvm/IR/Module.h" | 
|  | #include "llvm/Pass.h" | 
|  | #include <algorithm> | 
|  | #include <cassert> | 
|  |  | 
|  | using namespace llvm; | 
|  |  | 
|  | namespace { | 
|  |  | 
|  | namespace kOCLMD { | 
|  |  | 
|  | const char SpirVer[]            = "opencl.spir.version"; | 
|  | const char OCLVer[]             = "opencl.ocl.version"; | 
|  | const char UsedExt[]            = "opencl.used.extensions"; | 
|  | const char UsedOptCoreFeat[]    = "opencl.used.optional.core.features"; | 
|  | const char CompilerOptions[]    = "opencl.compiler.options"; | 
|  | const char LLVMIdent[]          = "llvm.ident"; | 
|  |  | 
|  | } // end namespace kOCLMD | 
|  |  | 
|  | /// \brief Unify multiple OpenCL metadata due to linking. | 
|  | class AMDGPUUnifyMetadata : public ModulePass { | 
|  | public: | 
|  | static char ID; | 
|  | explicit AMDGPUUnifyMetadata() : ModulePass(ID) {}; | 
|  |  | 
|  | private: | 
|  | virtual bool runOnModule(Module &M); | 
|  |  | 
|  | /// \brief Unify version metadata. | 
|  | /// \return true if changes are made. | 
|  | /// Assume the named metadata has operands each of which is a pair of | 
|  | /// integer constant, e.g. | 
|  | /// !Name = {!n1, !n2} | 
|  | /// !n1 = {i32 1, i32 2} | 
|  | /// !n2 = {i32 2, i32 0} | 
|  | /// Keep the largest version as the sole operand if PickFirst is false. | 
|  | /// Otherwise pick it from the first value, representing kernel module. | 
|  | bool unifyVersionMD(Module &M, StringRef Name, bool PickFirst) { | 
|  | auto NamedMD = M.getNamedMetadata(Name); | 
|  | if (!NamedMD || NamedMD->getNumOperands() <= 1) | 
|  | return false; | 
|  | MDNode *MaxMD = nullptr; | 
|  | auto MaxVer = 0U; | 
|  | for (const auto &VersionMD : NamedMD->operands()) { | 
|  | assert(VersionMD->getNumOperands() == 2); | 
|  | auto CMajor = mdconst::extract<ConstantInt>(VersionMD->getOperand(0)); | 
|  | auto VersionMajor = CMajor->getZExtValue(); | 
|  | auto CMinor = mdconst::extract<ConstantInt>(VersionMD->getOperand(1)); | 
|  | auto VersionMinor = CMinor->getZExtValue(); | 
|  | auto Ver = (VersionMajor * 100) + (VersionMinor * 10); | 
|  | if (Ver > MaxVer) { | 
|  | MaxVer = Ver; | 
|  | MaxMD = VersionMD; | 
|  | } | 
|  | if (PickFirst) | 
|  | break; | 
|  | } | 
|  | NamedMD->eraseFromParent(); | 
|  | NamedMD = M.getOrInsertNamedMetadata(Name); | 
|  | NamedMD->addOperand(MaxMD); | 
|  | return true; | 
|  | } | 
|  |  | 
|  | /// \brief Unify version metadata. | 
|  | /// \return true if changes are made. | 
|  | /// Assume the named metadata has operands each of which is a list e.g. | 
|  | /// !Name = {!n1, !n2} | 
|  | /// !n1 = !{!"cl_khr_fp16", {!"cl_khr_fp64"}} | 
|  | /// !n2 = !{!"cl_khr_image"} | 
|  | /// Combine it into a single list with unique operands. | 
|  | bool unifyExtensionMD(Module &M, StringRef Name) { | 
|  | auto NamedMD = M.getNamedMetadata(Name); | 
|  | if (!NamedMD || NamedMD->getNumOperands() == 1) | 
|  | return false; | 
|  |  | 
|  | SmallVector<Metadata *, 4> All; | 
|  | for (const auto &MD : NamedMD->operands()) | 
|  | for (const auto &Op : MD->operands()) | 
|  | if (std::find(All.begin(), All.end(), Op.get()) == All.end()) | 
|  | All.push_back(Op.get()); | 
|  |  | 
|  | NamedMD->eraseFromParent(); | 
|  | NamedMD = M.getOrInsertNamedMetadata(Name); | 
|  | for (const auto &MD : All) | 
|  | NamedMD->addOperand(MDNode::get(M.getContext(), MD)); | 
|  |  | 
|  | return true; | 
|  | } | 
|  | }; | 
|  |  | 
|  | } // end anonymous namespace | 
|  |  | 
|  | char AMDGPUUnifyMetadata::ID = 0; | 
|  |  | 
|  | char &llvm::AMDGPUUnifyMetadataID = AMDGPUUnifyMetadata::ID; | 
|  |  | 
|  | INITIALIZE_PASS(AMDGPUUnifyMetadata, "amdgpu-unify-metadata", | 
|  | "Unify multiple OpenCL metadata due to linking", | 
|  | false, false) | 
|  |  | 
|  | ModulePass* llvm::createAMDGPUUnifyMetadataPass() { | 
|  | return new AMDGPUUnifyMetadata(); | 
|  | } | 
|  |  | 
|  | bool AMDGPUUnifyMetadata::runOnModule(Module &M) { | 
|  | const char* Vers[] = { | 
|  | kOCLMD::SpirVer, | 
|  | kOCLMD::OCLVer | 
|  | }; | 
|  | const char* Exts[] = { | 
|  | kOCLMD::UsedExt, | 
|  | kOCLMD::UsedOptCoreFeat, | 
|  | kOCLMD::CompilerOptions, | 
|  | kOCLMD::LLVMIdent | 
|  | }; | 
|  |  | 
|  | bool Changed = false; | 
|  |  | 
|  | for (auto &I : Vers) | 
|  | Changed |= unifyVersionMD(M, I, true); | 
|  |  | 
|  | for (auto &I : Exts) | 
|  | Changed |= unifyExtensionMD(M, I); | 
|  |  | 
|  | return Changed; | 
|  | } |