diff options
Diffstat (limited to 'contrib/llvm/lib/Target/AMDGPU/AMDGPUUnifyMetadata.cpp')
-rw-r--r-- | contrib/llvm/lib/Target/AMDGPU/AMDGPUUnifyMetadata.cpp | 146 |
1 files changed, 146 insertions, 0 deletions
diff --git a/contrib/llvm/lib/Target/AMDGPU/AMDGPUUnifyMetadata.cpp b/contrib/llvm/lib/Target/AMDGPU/AMDGPUUnifyMetadata.cpp new file mode 100644 index 000000000000..3a0c3ede08f4 --- /dev/null +++ b/contrib/llvm/lib/Target/AMDGPU/AMDGPUUnifyMetadata.cpp @@ -0,0 +1,146 @@ +//===-- 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; +} |