150ea93a2SStanislav Mekhanoshin //===-- AMDGPUUnifyMetadata.cpp - Unify OpenCL metadata -------------------===// 250ea93a2SStanislav Mekhanoshin // 350ea93a2SStanislav Mekhanoshin // The LLVM Compiler Infrastructure 450ea93a2SStanislav Mekhanoshin // 550ea93a2SStanislav Mekhanoshin // This file is distributed under the University of Illinois Open Source 650ea93a2SStanislav Mekhanoshin // License. See LICENSE.TXT for details. 750ea93a2SStanislav Mekhanoshin // 850ea93a2SStanislav Mekhanoshin //===----------------------------------------------------------------------===// 950ea93a2SStanislav Mekhanoshin // 1050ea93a2SStanislav Mekhanoshin // \file 1150ea93a2SStanislav Mekhanoshin // \brief This pass that unifies multiple OpenCL metadata due to linking. 1250ea93a2SStanislav Mekhanoshin // 1350ea93a2SStanislav Mekhanoshin //===----------------------------------------------------------------------===// 1450ea93a2SStanislav Mekhanoshin 1550ea93a2SStanislav Mekhanoshin #include "AMDGPU.h" 16*734bb7bbSEugene Zelenko #include "llvm/ADT/SmallVector.h" 17*734bb7bbSEugene Zelenko #include "llvm/ADT/StringRef.h" 1850ea93a2SStanislav Mekhanoshin #include "llvm/IR/Constants.h" 19*734bb7bbSEugene Zelenko #include "llvm/IR/Function.h" 2050ea93a2SStanislav Mekhanoshin #include "llvm/IR/Module.h" 2150ea93a2SStanislav Mekhanoshin #include "llvm/Pass.h" 22*734bb7bbSEugene Zelenko #include <algorithm> 23*734bb7bbSEugene Zelenko #include <cassert> 2450ea93a2SStanislav Mekhanoshin 2550ea93a2SStanislav Mekhanoshin using namespace llvm; 2650ea93a2SStanislav Mekhanoshin 2750ea93a2SStanislav Mekhanoshin namespace { 28*734bb7bbSEugene Zelenko 2950ea93a2SStanislav Mekhanoshin namespace kOCLMD { 30*734bb7bbSEugene Zelenko 3150ea93a2SStanislav Mekhanoshin const char SpirVer[] = "opencl.spir.version"; 3250ea93a2SStanislav Mekhanoshin const char OCLVer[] = "opencl.ocl.version"; 3350ea93a2SStanislav Mekhanoshin const char UsedExt[] = "opencl.used.extensions"; 3450ea93a2SStanislav Mekhanoshin const char UsedOptCoreFeat[] = "opencl.used.optional.core.features"; 3550ea93a2SStanislav Mekhanoshin const char CompilerOptions[] = "opencl.compiler.options"; 3650ea93a2SStanislav Mekhanoshin const char LLVMIdent[] = "llvm.ident"; 37*734bb7bbSEugene Zelenko 38*734bb7bbSEugene Zelenko } // end namespace kOCLMD 3950ea93a2SStanislav Mekhanoshin 4050ea93a2SStanislav Mekhanoshin /// \brief Unify multiple OpenCL metadata due to linking. 4150ea93a2SStanislav Mekhanoshin class AMDGPUUnifyMetadata : public FunctionPass { 4250ea93a2SStanislav Mekhanoshin public: 4350ea93a2SStanislav Mekhanoshin static char ID; 44*734bb7bbSEugene Zelenko 45*734bb7bbSEugene Zelenko explicit AMDGPUUnifyMetadata() : FunctionPass(ID) {} 4650ea93a2SStanislav Mekhanoshin 4750ea93a2SStanislav Mekhanoshin private: 4850ea93a2SStanislav Mekhanoshin // This should really be a module pass but we have to run it as early 4950ea93a2SStanislav Mekhanoshin // as possible, so given function passes are executed first and 5050ea93a2SStanislav Mekhanoshin // TargetMachine::addEarlyAsPossiblePasses() expects only function passes 5150ea93a2SStanislav Mekhanoshin // it has to be a function pass. 5250ea93a2SStanislav Mekhanoshin virtual bool runOnModule(Module &M); 5350ea93a2SStanislav Mekhanoshin 5450ea93a2SStanislav Mekhanoshin // \todo: Convert to a module pass. 55*734bb7bbSEugene Zelenko bool runOnFunction(Function &F) override; 5650ea93a2SStanislav Mekhanoshin 5750ea93a2SStanislav Mekhanoshin /// \brief Unify version metadata. 5850ea93a2SStanislav Mekhanoshin /// \return true if changes are made. 5950ea93a2SStanislav Mekhanoshin /// Assume the named metadata has operands each of which is a pair of 6050ea93a2SStanislav Mekhanoshin /// integer constant, e.g. 6150ea93a2SStanislav Mekhanoshin /// !Name = {!n1, !n2} 6250ea93a2SStanislav Mekhanoshin /// !n1 = {i32 1, i32 2} 6350ea93a2SStanislav Mekhanoshin /// !n2 = {i32 2, i32 0} 6450ea93a2SStanislav Mekhanoshin /// Keep the largest version as the sole operand if PickFirst is false. 6550ea93a2SStanislav Mekhanoshin /// Otherwise pick it from the first value, representing kernel module. 6650ea93a2SStanislav Mekhanoshin bool unifyVersionMD(Module &M, StringRef Name, bool PickFirst) { 6750ea93a2SStanislav Mekhanoshin auto NamedMD = M.getNamedMetadata(Name); 6850ea93a2SStanislav Mekhanoshin if (!NamedMD || NamedMD->getNumOperands() <= 1) 6950ea93a2SStanislav Mekhanoshin return false; 7050ea93a2SStanislav Mekhanoshin MDNode *MaxMD = nullptr; 7150ea93a2SStanislav Mekhanoshin auto MaxVer = 0U; 7250ea93a2SStanislav Mekhanoshin for (const auto &VersionMD : NamedMD->operands()) { 7350ea93a2SStanislav Mekhanoshin assert(VersionMD->getNumOperands() == 2); 7450ea93a2SStanislav Mekhanoshin auto CMajor = mdconst::extract<ConstantInt>(VersionMD->getOperand(0)); 7550ea93a2SStanislav Mekhanoshin auto VersionMajor = CMajor->getZExtValue(); 7650ea93a2SStanislav Mekhanoshin auto CMinor = mdconst::extract<ConstantInt>(VersionMD->getOperand(1)); 7750ea93a2SStanislav Mekhanoshin auto VersionMinor = CMinor->getZExtValue(); 7850ea93a2SStanislav Mekhanoshin auto Ver = (VersionMajor * 100) + (VersionMinor * 10); 7950ea93a2SStanislav Mekhanoshin if (Ver > MaxVer) { 8050ea93a2SStanislav Mekhanoshin MaxVer = Ver; 8150ea93a2SStanislav Mekhanoshin MaxMD = VersionMD; 8250ea93a2SStanislav Mekhanoshin } 8350ea93a2SStanislav Mekhanoshin if (PickFirst) 8450ea93a2SStanislav Mekhanoshin break; 8550ea93a2SStanislav Mekhanoshin } 8650ea93a2SStanislav Mekhanoshin NamedMD->eraseFromParent(); 8750ea93a2SStanislav Mekhanoshin NamedMD = M.getOrInsertNamedMetadata(Name); 8850ea93a2SStanislav Mekhanoshin NamedMD->addOperand(MaxMD); 8950ea93a2SStanislav Mekhanoshin return true; 9050ea93a2SStanislav Mekhanoshin } 9150ea93a2SStanislav Mekhanoshin 9250ea93a2SStanislav Mekhanoshin /// \brief Unify version metadata. 9350ea93a2SStanislav Mekhanoshin /// \return true if changes are made. 9450ea93a2SStanislav Mekhanoshin /// Assume the named metadata has operands each of which is a list e.g. 9550ea93a2SStanislav Mekhanoshin /// !Name = {!n1, !n2} 9650ea93a2SStanislav Mekhanoshin /// !n1 = !{!"cl_khr_fp16", {!"cl_khr_fp64"}} 9750ea93a2SStanislav Mekhanoshin /// !n2 = !{!"cl_khr_image"} 9850ea93a2SStanislav Mekhanoshin /// Combine it into a single list with unique operands. 9950ea93a2SStanislav Mekhanoshin bool unifyExtensionMD(Module &M, StringRef Name) { 10050ea93a2SStanislav Mekhanoshin auto NamedMD = M.getNamedMetadata(Name); 10150ea93a2SStanislav Mekhanoshin if (!NamedMD || NamedMD->getNumOperands() == 1) 10250ea93a2SStanislav Mekhanoshin return false; 10350ea93a2SStanislav Mekhanoshin 10450ea93a2SStanislav Mekhanoshin SmallVector<Metadata *, 4> All; 10550ea93a2SStanislav Mekhanoshin for (const auto &MD : NamedMD->operands()) 10650ea93a2SStanislav Mekhanoshin for (const auto &Op : MD->operands()) 10750ea93a2SStanislav Mekhanoshin if (std::find(All.begin(), All.end(), Op.get()) == All.end()) 10850ea93a2SStanislav Mekhanoshin All.push_back(Op.get()); 10950ea93a2SStanislav Mekhanoshin 11050ea93a2SStanislav Mekhanoshin NamedMD->eraseFromParent(); 11150ea93a2SStanislav Mekhanoshin NamedMD = M.getOrInsertNamedMetadata(Name); 112980688cdSKonstantin Zhuravlyov for (const auto &MD : All) 113980688cdSKonstantin Zhuravlyov NamedMD->addOperand(MDNode::get(M.getContext(), MD)); 114980688cdSKonstantin Zhuravlyov 11550ea93a2SStanislav Mekhanoshin return true; 11650ea93a2SStanislav Mekhanoshin } 11750ea93a2SStanislav Mekhanoshin }; 11850ea93a2SStanislav Mekhanoshin 11950ea93a2SStanislav Mekhanoshin } // end anonymous namespace 12050ea93a2SStanislav Mekhanoshin 12150ea93a2SStanislav Mekhanoshin char AMDGPUUnifyMetadata::ID = 0; 12250ea93a2SStanislav Mekhanoshin 12350ea93a2SStanislav Mekhanoshin char &llvm::AMDGPUUnifyMetadataID = AMDGPUUnifyMetadata::ID; 12450ea93a2SStanislav Mekhanoshin 12550ea93a2SStanislav Mekhanoshin INITIALIZE_PASS(AMDGPUUnifyMetadata, "amdgpu-unify-metadata", 12650ea93a2SStanislav Mekhanoshin "Unify multiple OpenCL metadata due to linking", 12750ea93a2SStanislav Mekhanoshin false, false) 12850ea93a2SStanislav Mekhanoshin 12950ea93a2SStanislav Mekhanoshin FunctionPass* llvm::createAMDGPUUnifyMetadataPass() { 13050ea93a2SStanislav Mekhanoshin return new AMDGPUUnifyMetadata(); 13150ea93a2SStanislav Mekhanoshin } 13250ea93a2SStanislav Mekhanoshin 13350ea93a2SStanislav Mekhanoshin bool AMDGPUUnifyMetadata::runOnModule(Module &M) { 13450ea93a2SStanislav Mekhanoshin const char* Vers[] = { 13550ea93a2SStanislav Mekhanoshin kOCLMD::SpirVer, 13650ea93a2SStanislav Mekhanoshin kOCLMD::OCLVer 13750ea93a2SStanislav Mekhanoshin }; 13850ea93a2SStanislav Mekhanoshin const char* Exts[] = { 13950ea93a2SStanislav Mekhanoshin kOCLMD::UsedExt, 14050ea93a2SStanislav Mekhanoshin kOCLMD::UsedOptCoreFeat, 14150ea93a2SStanislav Mekhanoshin kOCLMD::CompilerOptions, 14250ea93a2SStanislav Mekhanoshin kOCLMD::LLVMIdent 14350ea93a2SStanislav Mekhanoshin }; 14450ea93a2SStanislav Mekhanoshin 14550ea93a2SStanislav Mekhanoshin bool Changed = false; 14650ea93a2SStanislav Mekhanoshin 14750ea93a2SStanislav Mekhanoshin for (auto &I : Vers) 14850ea93a2SStanislav Mekhanoshin Changed |= unifyVersionMD(M, I, true); 14950ea93a2SStanislav Mekhanoshin 15050ea93a2SStanislav Mekhanoshin for (auto &I : Exts) 15150ea93a2SStanislav Mekhanoshin Changed |= unifyExtensionMD(M, I); 15250ea93a2SStanislav Mekhanoshin 15350ea93a2SStanislav Mekhanoshin return Changed; 15450ea93a2SStanislav Mekhanoshin } 15550ea93a2SStanislav Mekhanoshin 15650ea93a2SStanislav Mekhanoshin bool AMDGPUUnifyMetadata::runOnFunction(Function &F) { 15750ea93a2SStanislav Mekhanoshin return runOnModule(*F.getParent()); 15850ea93a2SStanislav Mekhanoshin } 159