1c8fbf6ffSEugene Zelenko //===- AMDGPUUnifyMetadata.cpp - Unify OpenCL metadata --------------------===// 250ea93a2SStanislav Mekhanoshin // 32946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 42946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information. 52946cd70SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 650ea93a2SStanislav Mekhanoshin // 750ea93a2SStanislav Mekhanoshin //===----------------------------------------------------------------------===// 850ea93a2SStanislav Mekhanoshin // 950ea93a2SStanislav Mekhanoshin // \file 105f8f34e4SAdrian Prantl // This pass that unifies multiple OpenCL metadata due to linking. 1150ea93a2SStanislav Mekhanoshin // 1250ea93a2SStanislav Mekhanoshin //===----------------------------------------------------------------------===// 1350ea93a2SStanislav Mekhanoshin 1450ea93a2SStanislav Mekhanoshin #include "AMDGPU.h" 1550ea93a2SStanislav Mekhanoshin #include "llvm/IR/Constants.h" 1650ea93a2SStanislav Mekhanoshin #include "llvm/IR/Module.h" 17*e1833e74SArthur Eubanks #include "llvm/IR/PassManager.h" 1850ea93a2SStanislav Mekhanoshin #include "llvm/Pass.h" 1950ea93a2SStanislav Mekhanoshin 2050ea93a2SStanislav Mekhanoshin using namespace llvm; 2150ea93a2SStanislav Mekhanoshin 2250ea93a2SStanislav Mekhanoshin namespace { 23734bb7bbSEugene Zelenko 2450ea93a2SStanislav Mekhanoshin namespace kOCLMD { 25734bb7bbSEugene Zelenko 2650ea93a2SStanislav Mekhanoshin const char SpirVer[] = "opencl.spir.version"; 2750ea93a2SStanislav Mekhanoshin const char OCLVer[] = "opencl.ocl.version"; 2850ea93a2SStanislav Mekhanoshin const char UsedExt[] = "opencl.used.extensions"; 2950ea93a2SStanislav Mekhanoshin const char UsedOptCoreFeat[] = "opencl.used.optional.core.features"; 3050ea93a2SStanislav Mekhanoshin const char CompilerOptions[] = "opencl.compiler.options"; 3150ea93a2SStanislav Mekhanoshin const char LLVMIdent[] = "llvm.ident"; 32734bb7bbSEugene Zelenko 33734bb7bbSEugene Zelenko } // end namespace kOCLMD 3450ea93a2SStanislav Mekhanoshin 355f8f34e4SAdrian Prantl /// Unify multiple OpenCL metadata due to linking. 36f6c1feb8SStanislav Mekhanoshin class AMDGPUUnifyMetadata : public ModulePass { 3750ea93a2SStanislav Mekhanoshin public: 3850ea93a2SStanislav Mekhanoshin static char ID; 39c8fbf6ffSEugene Zelenko AMDGPUUnifyMetadata()40c8fbf6ffSEugene Zelenko explicit AMDGPUUnifyMetadata() : ModulePass(ID) {} 4150ea93a2SStanislav Mekhanoshin 4250ea93a2SStanislav Mekhanoshin private: 43c8fbf6ffSEugene Zelenko bool runOnModule(Module &M) override; 44*e1833e74SArthur Eubanks }; 4550ea93a2SStanislav Mekhanoshin 465f8f34e4SAdrian Prantl /// Unify version metadata. 4750ea93a2SStanislav Mekhanoshin /// \return true if changes are made. 4850ea93a2SStanislav Mekhanoshin /// Assume the named metadata has operands each of which is a pair of 4950ea93a2SStanislav Mekhanoshin /// integer constant, e.g. 5050ea93a2SStanislav Mekhanoshin /// !Name = {!n1, !n2} 5150ea93a2SStanislav Mekhanoshin /// !n1 = {i32 1, i32 2} 5250ea93a2SStanislav Mekhanoshin /// !n2 = {i32 2, i32 0} 5350ea93a2SStanislav Mekhanoshin /// Keep the largest version as the sole operand if PickFirst is false. 5450ea93a2SStanislav Mekhanoshin /// Otherwise pick it from the first value, representing kernel module. unifyVersionMD(Module & M,StringRef Name,bool PickFirst)5550ea93a2SStanislav Mekhanoshin bool unifyVersionMD(Module &M, StringRef Name, bool PickFirst) { 5650ea93a2SStanislav Mekhanoshin auto NamedMD = M.getNamedMetadata(Name); 5750ea93a2SStanislav Mekhanoshin if (!NamedMD || NamedMD->getNumOperands() <= 1) 5850ea93a2SStanislav Mekhanoshin return false; 5950ea93a2SStanislav Mekhanoshin MDNode *MaxMD = nullptr; 6050ea93a2SStanislav Mekhanoshin auto MaxVer = 0U; 612d903cc9SMark de Wever for (auto VersionMD : NamedMD->operands()) { 6250ea93a2SStanislav Mekhanoshin assert(VersionMD->getNumOperands() == 2); 6350ea93a2SStanislav Mekhanoshin auto CMajor = mdconst::extract<ConstantInt>(VersionMD->getOperand(0)); 6450ea93a2SStanislav Mekhanoshin auto VersionMajor = CMajor->getZExtValue(); 6550ea93a2SStanislav Mekhanoshin auto CMinor = mdconst::extract<ConstantInt>(VersionMD->getOperand(1)); 6650ea93a2SStanislav Mekhanoshin auto VersionMinor = CMinor->getZExtValue(); 6750ea93a2SStanislav Mekhanoshin auto Ver = (VersionMajor * 100) + (VersionMinor * 10); 6850ea93a2SStanislav Mekhanoshin if (Ver > MaxVer) { 6950ea93a2SStanislav Mekhanoshin MaxVer = Ver; 7050ea93a2SStanislav Mekhanoshin MaxMD = VersionMD; 7150ea93a2SStanislav Mekhanoshin } 7250ea93a2SStanislav Mekhanoshin if (PickFirst) 7350ea93a2SStanislav Mekhanoshin break; 7450ea93a2SStanislav Mekhanoshin } 7550ea93a2SStanislav Mekhanoshin NamedMD->eraseFromParent(); 7650ea93a2SStanislav Mekhanoshin NamedMD = M.getOrInsertNamedMetadata(Name); 7750ea93a2SStanislav Mekhanoshin NamedMD->addOperand(MaxMD); 7850ea93a2SStanislav Mekhanoshin return true; 7950ea93a2SStanislav Mekhanoshin } 8050ea93a2SStanislav Mekhanoshin 815f8f34e4SAdrian Prantl /// Unify version metadata. 8250ea93a2SStanislav Mekhanoshin /// \return true if changes are made. 8350ea93a2SStanislav Mekhanoshin /// Assume the named metadata has operands each of which is a list e.g. 8450ea93a2SStanislav Mekhanoshin /// !Name = {!n1, !n2} 8550ea93a2SStanislav Mekhanoshin /// !n1 = !{!"cl_khr_fp16", {!"cl_khr_fp64"}} 8650ea93a2SStanislav Mekhanoshin /// !n2 = !{!"cl_khr_image"} 8750ea93a2SStanislav Mekhanoshin /// Combine it into a single list with unique operands. unifyExtensionMD(Module & M,StringRef Name)8850ea93a2SStanislav Mekhanoshin bool unifyExtensionMD(Module &M, StringRef Name) { 8950ea93a2SStanislav Mekhanoshin auto NamedMD = M.getNamedMetadata(Name); 9050ea93a2SStanislav Mekhanoshin if (!NamedMD || NamedMD->getNumOperands() == 1) 9150ea93a2SStanislav Mekhanoshin return false; 9250ea93a2SStanislav Mekhanoshin 9350ea93a2SStanislav Mekhanoshin SmallVector<Metadata *, 4> All; 942d903cc9SMark de Wever for (auto MD : NamedMD->operands()) 9550ea93a2SStanislav Mekhanoshin for (const auto &Op : MD->operands()) 96902cbcd5SKazu Hirata if (!llvm::is_contained(All, Op.get())) 9750ea93a2SStanislav Mekhanoshin All.push_back(Op.get()); 9850ea93a2SStanislav Mekhanoshin 9950ea93a2SStanislav Mekhanoshin NamedMD->eraseFromParent(); 10050ea93a2SStanislav Mekhanoshin NamedMD = M.getOrInsertNamedMetadata(Name); 101980688cdSKonstantin Zhuravlyov for (const auto &MD : All) 102980688cdSKonstantin Zhuravlyov NamedMD->addOperand(MDNode::get(M.getContext(), MD)); 103980688cdSKonstantin Zhuravlyov 10450ea93a2SStanislav Mekhanoshin return true; 10550ea93a2SStanislav Mekhanoshin } 10650ea93a2SStanislav Mekhanoshin unifyMetadataImpl(Module & M)107*e1833e74SArthur Eubanks bool unifyMetadataImpl(Module &M) { 108*e1833e74SArthur Eubanks const char *Vers[] = {kOCLMD::SpirVer, kOCLMD::OCLVer}; 109*e1833e74SArthur Eubanks const char *Exts[] = {kOCLMD::UsedExt, kOCLMD::UsedOptCoreFeat, 110*e1833e74SArthur Eubanks kOCLMD::CompilerOptions, kOCLMD::LLVMIdent}; 11150ea93a2SStanislav Mekhanoshin 11250ea93a2SStanislav Mekhanoshin bool Changed = false; 11350ea93a2SStanislav Mekhanoshin 11450ea93a2SStanislav Mekhanoshin for (auto &I : Vers) 11550ea93a2SStanislav Mekhanoshin Changed |= unifyVersionMD(M, I, true); 11650ea93a2SStanislav Mekhanoshin 11750ea93a2SStanislav Mekhanoshin for (auto &I : Exts) 11850ea93a2SStanislav Mekhanoshin Changed |= unifyExtensionMD(M, I); 11950ea93a2SStanislav Mekhanoshin 12050ea93a2SStanislav Mekhanoshin return Changed; 12150ea93a2SStanislav Mekhanoshin } 122*e1833e74SArthur Eubanks 123*e1833e74SArthur Eubanks } // end anonymous namespace 124*e1833e74SArthur Eubanks 125*e1833e74SArthur Eubanks char AMDGPUUnifyMetadata::ID = 0; 126*e1833e74SArthur Eubanks 127*e1833e74SArthur Eubanks char &llvm::AMDGPUUnifyMetadataID = AMDGPUUnifyMetadata::ID; 128*e1833e74SArthur Eubanks 129*e1833e74SArthur Eubanks INITIALIZE_PASS(AMDGPUUnifyMetadata, "amdgpu-unify-metadata", 130*e1833e74SArthur Eubanks "Unify multiple OpenCL metadata due to linking", false, false) 131*e1833e74SArthur Eubanks createAMDGPUUnifyMetadataPass()132*e1833e74SArthur Eubanks ModulePass *llvm::createAMDGPUUnifyMetadataPass() { 133*e1833e74SArthur Eubanks return new AMDGPUUnifyMetadata(); 134*e1833e74SArthur Eubanks } 135*e1833e74SArthur Eubanks runOnModule(Module & M)136*e1833e74SArthur Eubanks bool AMDGPUUnifyMetadata::runOnModule(Module &M) { 137*e1833e74SArthur Eubanks return unifyMetadataImpl(M); 138*e1833e74SArthur Eubanks } 139*e1833e74SArthur Eubanks run(Module & M,ModuleAnalysisManager & AM)140*e1833e74SArthur Eubanks PreservedAnalyses AMDGPUUnifyMetadataPass::run(Module &M, 141*e1833e74SArthur Eubanks ModuleAnalysisManager &AM) { 142*e1833e74SArthur Eubanks return unifyMetadataImpl(M) ? PreservedAnalyses::none() 143*e1833e74SArthur Eubanks : PreservedAnalyses::all(); 144*e1833e74SArthur Eubanks } 145