| //===- 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 | |
| // 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/Metadata.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 | |
| /// Unify multiple OpenCL metadata due to linking. | |
| class AMDGPUUnifyMetadata : public ModulePass { | |
| public: | |
| static char ID; | |
| explicit AMDGPUUnifyMetadata() : ModulePass(ID) {} | |
| private: | |
| bool runOnModule(Module &M) override; | |
| /// 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; | |
| } | |
| /// 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; | |
| } |