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 // \brief 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/Function.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 /// \brief Unify multiple OpenCL metadata due to linking. 41 class AMDGPUUnifyMetadata : public ModulePass { 42 public: 43 static char ID; 44 explicit AMDGPUUnifyMetadata() : ModulePass(ID) {}; 45 46 private: 47 virtual bool runOnModule(Module &M); 48 49 /// \brief Unify version metadata. 50 /// \return true if changes are made. 51 /// Assume the named metadata has operands each of which is a pair of 52 /// integer constant, e.g. 53 /// !Name = {!n1, !n2} 54 /// !n1 = {i32 1, i32 2} 55 /// !n2 = {i32 2, i32 0} 56 /// Keep the largest version as the sole operand if PickFirst is false. 57 /// Otherwise pick it from the first value, representing kernel module. 58 bool unifyVersionMD(Module &M, StringRef Name, bool PickFirst) { 59 auto NamedMD = M.getNamedMetadata(Name); 60 if (!NamedMD || NamedMD->getNumOperands() <= 1) 61 return false; 62 MDNode *MaxMD = nullptr; 63 auto MaxVer = 0U; 64 for (const auto &VersionMD : NamedMD->operands()) { 65 assert(VersionMD->getNumOperands() == 2); 66 auto CMajor = mdconst::extract<ConstantInt>(VersionMD->getOperand(0)); 67 auto VersionMajor = CMajor->getZExtValue(); 68 auto CMinor = mdconst::extract<ConstantInt>(VersionMD->getOperand(1)); 69 auto VersionMinor = CMinor->getZExtValue(); 70 auto Ver = (VersionMajor * 100) + (VersionMinor * 10); 71 if (Ver > MaxVer) { 72 MaxVer = Ver; 73 MaxMD = VersionMD; 74 } 75 if (PickFirst) 76 break; 77 } 78 NamedMD->eraseFromParent(); 79 NamedMD = M.getOrInsertNamedMetadata(Name); 80 NamedMD->addOperand(MaxMD); 81 return true; 82 } 83 84 /// \brief Unify version metadata. 85 /// \return true if changes are made. 86 /// Assume the named metadata has operands each of which is a list e.g. 87 /// !Name = {!n1, !n2} 88 /// !n1 = !{!"cl_khr_fp16", {!"cl_khr_fp64"}} 89 /// !n2 = !{!"cl_khr_image"} 90 /// Combine it into a single list with unique operands. 91 bool unifyExtensionMD(Module &M, StringRef Name) { 92 auto NamedMD = M.getNamedMetadata(Name); 93 if (!NamedMD || NamedMD->getNumOperands() == 1) 94 return false; 95 96 SmallVector<Metadata *, 4> All; 97 for (const auto &MD : NamedMD->operands()) 98 for (const auto &Op : MD->operands()) 99 if (std::find(All.begin(), All.end(), Op.get()) == All.end()) 100 All.push_back(Op.get()); 101 102 NamedMD->eraseFromParent(); 103 NamedMD = M.getOrInsertNamedMetadata(Name); 104 for (const auto &MD : All) 105 NamedMD->addOperand(MDNode::get(M.getContext(), MD)); 106 107 return true; 108 } 109 }; 110 111 } // end anonymous namespace 112 113 char AMDGPUUnifyMetadata::ID = 0; 114 115 char &llvm::AMDGPUUnifyMetadataID = AMDGPUUnifyMetadata::ID; 116 117 INITIALIZE_PASS(AMDGPUUnifyMetadata, "amdgpu-unify-metadata", 118 "Unify multiple OpenCL metadata due to linking", 119 false, false) 120 121 ModulePass* llvm::createAMDGPUUnifyMetadataPass() { 122 return new AMDGPUUnifyMetadata(); 123 } 124 125 bool AMDGPUUnifyMetadata::runOnModule(Module &M) { 126 const char* Vers[] = { 127 kOCLMD::SpirVer, 128 kOCLMD::OCLVer 129 }; 130 const char* Exts[] = { 131 kOCLMD::UsedExt, 132 kOCLMD::UsedOptCoreFeat, 133 kOCLMD::CompilerOptions, 134 kOCLMD::LLVMIdent 135 }; 136 137 bool Changed = false; 138 139 for (auto &I : Vers) 140 Changed |= unifyVersionMD(M, I, true); 141 142 for (auto &I : Exts) 143 Changed |= unifyExtensionMD(M, I); 144 145 return Changed; 146 } 147