Home | History | Annotate | Download | only in AMDGPU
      1 //===- AMDGPUUnifyMetadata.cpp - Unify OpenCL metadata --------------------===//
      2 //
      3 //                     The LLVM Compiler Infrastructure
      4 //
      5 // This file is distributed under the University of Illinois Open Source
      6 // License. See LICENSE.TXT for details.
      7 //
      8 //===----------------------------------------------------------------------===//
      9 //
     10 // \file
     11 // This pass that unifies multiple OpenCL metadata due to linking.
     12 //
     13 //===----------------------------------------------------------------------===//
     14 
     15 #include "AMDGPU.h"
     16 #include "llvm/ADT/SmallVector.h"
     17 #include "llvm/ADT/StringRef.h"
     18 #include "llvm/IR/Constants.h"
     19 #include "llvm/IR/Metadata.h"
     20 #include "llvm/IR/Module.h"
     21 #include "llvm/Pass.h"
     22 #include <algorithm>
     23 #include <cassert>
     24 
     25 using namespace llvm;
     26 
     27 namespace {
     28 
     29   namespace kOCLMD {
     30 
     31     const char SpirVer[]            = "opencl.spir.version";
     32     const char OCLVer[]             = "opencl.ocl.version";
     33     const char UsedExt[]            = "opencl.used.extensions";
     34     const char UsedOptCoreFeat[]    = "opencl.used.optional.core.features";
     35     const char CompilerOptions[]    = "opencl.compiler.options";
     36     const char LLVMIdent[]          = "llvm.ident";
     37 
     38   } // end namespace kOCLMD
     39 
     40   /// Unify multiple OpenCL metadata due to linking.
     41   class AMDGPUUnifyMetadata : public ModulePass {
     42   public:
     43     static char ID;
     44 
     45     explicit AMDGPUUnifyMetadata() : ModulePass(ID) {}
     46 
     47   private:
     48     bool runOnModule(Module &M) override;
     49 
     50     /// Unify version metadata.
     51     /// \return true if changes are made.
     52     /// Assume the named metadata has operands each of which is a pair of
     53     /// integer constant, e.g.
     54     /// !Name = {!n1, !n2}
     55     /// !n1 = {i32 1, i32 2}
     56     /// !n2 = {i32 2, i32 0}
     57     /// Keep the largest version as the sole operand if PickFirst is false.
     58     /// Otherwise pick it from the first value, representing kernel module.
     59     bool unifyVersionMD(Module &M, StringRef Name, bool PickFirst) {
     60       auto NamedMD = M.getNamedMetadata(Name);
     61       if (!NamedMD || NamedMD->getNumOperands() <= 1)
     62         return false;
     63       MDNode *MaxMD = nullptr;
     64       auto MaxVer = 0U;
     65       for (const auto &VersionMD : NamedMD->operands()) {
     66         assert(VersionMD->getNumOperands() == 2);
     67         auto CMajor = mdconst::extract<ConstantInt>(VersionMD->getOperand(0));
     68         auto VersionMajor = CMajor->getZExtValue();
     69         auto CMinor = mdconst::extract<ConstantInt>(VersionMD->getOperand(1));
     70         auto VersionMinor = CMinor->getZExtValue();
     71         auto Ver = (VersionMajor * 100) + (VersionMinor * 10);
     72         if (Ver > MaxVer) {
     73           MaxVer = Ver;
     74           MaxMD = VersionMD;
     75         }
     76         if (PickFirst)
     77           break;
     78       }
     79       NamedMD->eraseFromParent();
     80       NamedMD = M.getOrInsertNamedMetadata(Name);
     81       NamedMD->addOperand(MaxMD);
     82       return true;
     83     }
     84 
     85   /// Unify version metadata.
     86   /// \return true if changes are made.
     87   /// Assume the named metadata has operands each of which is a list e.g.
     88   /// !Name = {!n1, !n2}
     89   /// !n1 = !{!"cl_khr_fp16", {!"cl_khr_fp64"}}
     90   /// !n2 = !{!"cl_khr_image"}
     91   /// Combine it into a single list with unique operands.
     92   bool unifyExtensionMD(Module &M, StringRef Name) {
     93     auto NamedMD = M.getNamedMetadata(Name);
     94     if (!NamedMD || NamedMD->getNumOperands() == 1)
     95       return false;
     96 
     97     SmallVector<Metadata *, 4> All;
     98     for (const auto &MD : NamedMD->operands())
     99       for (const auto &Op : MD->operands())
    100         if (std::find(All.begin(), All.end(), Op.get()) == All.end())
    101           All.push_back(Op.get());
    102 
    103     NamedMD->eraseFromParent();
    104     NamedMD = M.getOrInsertNamedMetadata(Name);
    105     for (const auto &MD : All)
    106       NamedMD->addOperand(MDNode::get(M.getContext(), MD));
    107 
    108     return true;
    109   }
    110 };
    111 
    112 } // end anonymous namespace
    113 
    114 char AMDGPUUnifyMetadata::ID = 0;
    115 
    116 char &llvm::AMDGPUUnifyMetadataID = AMDGPUUnifyMetadata::ID;
    117 
    118 INITIALIZE_PASS(AMDGPUUnifyMetadata, "amdgpu-unify-metadata",
    119                 "Unify multiple OpenCL metadata due to linking",
    120                 false, false)
    121 
    122 ModulePass* llvm::createAMDGPUUnifyMetadataPass() {
    123   return new AMDGPUUnifyMetadata();
    124 }
    125 
    126 bool AMDGPUUnifyMetadata::runOnModule(Module &M) {
    127   const char* Vers[] = {
    128       kOCLMD::SpirVer,
    129       kOCLMD::OCLVer
    130   };
    131   const char* Exts[] = {
    132       kOCLMD::UsedExt,
    133       kOCLMD::UsedOptCoreFeat,
    134       kOCLMD::CompilerOptions,
    135       kOCLMD::LLVMIdent
    136   };
    137 
    138   bool Changed = false;
    139 
    140   for (auto &I : Vers)
    141     Changed |= unifyVersionMD(M, I, true);
    142 
    143   for (auto &I : Exts)
    144     Changed |= unifyExtensionMD(M, I);
    145 
    146   return Changed;
    147 }
    148