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