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