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