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