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