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 AMDGPUUnifyMetadata()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. unifyVersionMD(Module & M,StringRef Name,bool PickFirst)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. unifyExtensionMD(Module & M,StringRef Name)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 createAMDGPUUnifyMetadataPass()122 ModulePass* llvm::createAMDGPUUnifyMetadataPass() { 123 return new AMDGPUUnifyMetadata(); 124 } 125 runOnModule(Module & M)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