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