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