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