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 version metadata. 36 /// \return true if changes are made. 37 /// Assume the named metadata has operands each of which is a pair of 38 /// integer constant, e.g. 39 /// !Name = {!n1, !n2} 40 /// !n1 = {i32 1, i32 2} 41 /// !n2 = {i32 2, i32 0} 42 /// Keep the largest version as the sole operand if PickFirst is false. 43 /// Otherwise pick it from the first value, representing kernel module. 44 bool unifyVersionMD(Module &M, StringRef Name, bool PickFirst) { 45 auto *NamedMD = M.getNamedMetadata(Name); 46 if (!NamedMD || NamedMD->getNumOperands() <= 1) 47 return false; 48 MDNode *MaxMD = nullptr; 49 auto MaxVer = 0U; 50 for (auto *VersionMD : NamedMD->operands()) { 51 assert(VersionMD->getNumOperands() == 2); 52 auto *CMajor = mdconst::extract<ConstantInt>(VersionMD->getOperand(0)); 53 auto VersionMajor = CMajor->getZExtValue(); 54 auto *CMinor = mdconst::extract<ConstantInt>(VersionMD->getOperand(1)); 55 auto VersionMinor = CMinor->getZExtValue(); 56 auto Ver = (VersionMajor * 100) + (VersionMinor * 10); 57 if (Ver > MaxVer) { 58 MaxVer = Ver; 59 MaxMD = VersionMD; 60 } 61 if (PickFirst) 62 break; 63 } 64 NamedMD->eraseFromParent(); 65 NamedMD = M.getOrInsertNamedMetadata(Name); 66 NamedMD->addOperand(MaxMD); 67 return true; 68 } 69 70 /// Unify version metadata. 71 /// \return true if changes are made. 72 /// Assume the named metadata has operands each of which is a list e.g. 73 /// !Name = {!n1, !n2} 74 /// !n1 = !{!"cl_khr_fp16", {!"cl_khr_fp64"}} 75 /// !n2 = !{!"cl_khr_image"} 76 /// Combine it into a single list with unique operands. 77 bool unifyExtensionMD(Module &M, StringRef Name) { 78 auto *NamedMD = M.getNamedMetadata(Name); 79 if (!NamedMD || NamedMD->getNumOperands() == 1) 80 return false; 81 82 SmallVector<Metadata *, 4> All; 83 for (auto *MD : NamedMD->operands()) 84 for (const auto &Op : MD->operands()) 85 if (!llvm::is_contained(All, Op.get())) 86 All.push_back(Op.get()); 87 88 NamedMD->eraseFromParent(); 89 NamedMD = M.getOrInsertNamedMetadata(Name); 90 for (const auto &MD : All) 91 NamedMD->addOperand(MDNode::get(M.getContext(), MD)); 92 93 return true; 94 } 95 96 /// Unify multiple OpenCL metadata due to linking. 97 bool unifyMetadataImpl(Module &M) { 98 const char *Vers[] = {kOCLMD::SpirVer, kOCLMD::OCLVer}; 99 const char *Exts[] = {kOCLMD::UsedExt, kOCLMD::UsedOptCoreFeat, 100 kOCLMD::CompilerOptions, kOCLMD::LLVMIdent}; 101 102 bool Changed = false; 103 104 for (auto &I : Vers) 105 Changed |= unifyVersionMD(M, I, true); 106 107 for (auto &I : Exts) 108 Changed |= unifyExtensionMD(M, I); 109 110 return Changed; 111 } 112 113 } // end anonymous namespace 114 115 PreservedAnalyses AMDGPUUnifyMetadataPass::run(Module &M, 116 ModuleAnalysisManager &AM) { 117 return unifyMetadataImpl(M) ? PreservedAnalyses::none() 118 : PreservedAnalyses::all(); 119 } 120