Stanislav Mekhanoshin | 50ea93a | 2016-12-08 19:46:04 +0000 | [diff] [blame] | 1 | //===-- AMDGPUUnifyMetadata.cpp - Unify OpenCL metadata -------------------===// |
| 2 | // |
| 3 | // The LLVM Compiler Infrastructure |
| 4 | // |
| 5 | // This file is distributed under the University of Illinois Open Source |
| 6 | // License. See LICENSE.TXT for details. |
| 7 | // |
| 8 | //===----------------------------------------------------------------------===// |
| 9 | // |
| 10 | // \file |
| 11 | // \brief This pass that unifies multiple OpenCL metadata due to linking. |
| 12 | // |
| 13 | //===----------------------------------------------------------------------===// |
| 14 | |
| 15 | #include "AMDGPU.h" |
Eugene Zelenko | 734bb7b | 2017-01-20 17:52:16 +0000 | [diff] [blame^] | 16 | #include "llvm/ADT/SmallVector.h" |
| 17 | #include "llvm/ADT/StringRef.h" |
Stanislav Mekhanoshin | 50ea93a | 2016-12-08 19:46:04 +0000 | [diff] [blame] | 18 | #include "llvm/IR/Constants.h" |
Eugene Zelenko | 734bb7b | 2017-01-20 17:52:16 +0000 | [diff] [blame^] | 19 | #include "llvm/IR/Function.h" |
Stanislav Mekhanoshin | 50ea93a | 2016-12-08 19:46:04 +0000 | [diff] [blame] | 20 | #include "llvm/IR/Module.h" |
| 21 | #include "llvm/Pass.h" |
Eugene Zelenko | 734bb7b | 2017-01-20 17:52:16 +0000 | [diff] [blame^] | 22 | #include <algorithm> |
| 23 | #include <cassert> |
Stanislav Mekhanoshin | 50ea93a | 2016-12-08 19:46:04 +0000 | [diff] [blame] | 24 | |
| 25 | using namespace llvm; |
| 26 | |
| 27 | namespace { |
Eugene Zelenko | 734bb7b | 2017-01-20 17:52:16 +0000 | [diff] [blame^] | 28 | |
Stanislav Mekhanoshin | 50ea93a | 2016-12-08 19:46:04 +0000 | [diff] [blame] | 29 | namespace kOCLMD { |
Eugene Zelenko | 734bb7b | 2017-01-20 17:52:16 +0000 | [diff] [blame^] | 30 | |
Stanislav Mekhanoshin | 50ea93a | 2016-12-08 19:46:04 +0000 | [diff] [blame] | 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"; |
Eugene Zelenko | 734bb7b | 2017-01-20 17:52:16 +0000 | [diff] [blame^] | 37 | |
| 38 | } // end namespace kOCLMD |
Stanislav Mekhanoshin | 50ea93a | 2016-12-08 19:46:04 +0000 | [diff] [blame] | 39 | |
| 40 | /// \brief Unify multiple OpenCL metadata due to linking. |
| 41 | class AMDGPUUnifyMetadata : public FunctionPass { |
| 42 | public: |
| 43 | static char ID; |
Eugene Zelenko | 734bb7b | 2017-01-20 17:52:16 +0000 | [diff] [blame^] | 44 | |
| 45 | explicit AMDGPUUnifyMetadata() : FunctionPass(ID) {} |
Stanislav Mekhanoshin | 50ea93a | 2016-12-08 19:46:04 +0000 | [diff] [blame] | 46 | |
| 47 | private: |
| 48 | // This should really be a module pass but we have to run it as early |
| 49 | // as possible, so given function passes are executed first and |
| 50 | // TargetMachine::addEarlyAsPossiblePasses() expects only function passes |
| 51 | // it has to be a function pass. |
| 52 | virtual bool runOnModule(Module &M); |
| 53 | |
| 54 | // \todo: Convert to a module pass. |
Eugene Zelenko | 734bb7b | 2017-01-20 17:52:16 +0000 | [diff] [blame^] | 55 | bool runOnFunction(Function &F) override; |
Stanislav Mekhanoshin | 50ea93a | 2016-12-08 19:46:04 +0000 | [diff] [blame] | 56 | |
| 57 | /// \brief Unify version metadata. |
| 58 | /// \return true if changes are made. |
| 59 | /// Assume the named metadata has operands each of which is a pair of |
| 60 | /// integer constant, e.g. |
| 61 | /// !Name = {!n1, !n2} |
| 62 | /// !n1 = {i32 1, i32 2} |
| 63 | /// !n2 = {i32 2, i32 0} |
| 64 | /// Keep the largest version as the sole operand if PickFirst is false. |
| 65 | /// Otherwise pick it from the first value, representing kernel module. |
| 66 | bool unifyVersionMD(Module &M, StringRef Name, bool PickFirst) { |
| 67 | auto NamedMD = M.getNamedMetadata(Name); |
| 68 | if (!NamedMD || NamedMD->getNumOperands() <= 1) |
| 69 | return false; |
| 70 | MDNode *MaxMD = nullptr; |
| 71 | auto MaxVer = 0U; |
| 72 | for (const auto &VersionMD : NamedMD->operands()) { |
| 73 | assert(VersionMD->getNumOperands() == 2); |
| 74 | auto CMajor = mdconst::extract<ConstantInt>(VersionMD->getOperand(0)); |
| 75 | auto VersionMajor = CMajor->getZExtValue(); |
| 76 | auto CMinor = mdconst::extract<ConstantInt>(VersionMD->getOperand(1)); |
| 77 | auto VersionMinor = CMinor->getZExtValue(); |
| 78 | auto Ver = (VersionMajor * 100) + (VersionMinor * 10); |
| 79 | if (Ver > MaxVer) { |
| 80 | MaxVer = Ver; |
| 81 | MaxMD = VersionMD; |
| 82 | } |
| 83 | if (PickFirst) |
| 84 | break; |
| 85 | } |
| 86 | NamedMD->eraseFromParent(); |
| 87 | NamedMD = M.getOrInsertNamedMetadata(Name); |
| 88 | NamedMD->addOperand(MaxMD); |
| 89 | return true; |
| 90 | } |
| 91 | |
| 92 | /// \brief Unify version metadata. |
| 93 | /// \return true if changes are made. |
| 94 | /// Assume the named metadata has operands each of which is a list e.g. |
| 95 | /// !Name = {!n1, !n2} |
| 96 | /// !n1 = !{!"cl_khr_fp16", {!"cl_khr_fp64"}} |
| 97 | /// !n2 = !{!"cl_khr_image"} |
| 98 | /// Combine it into a single list with unique operands. |
| 99 | bool unifyExtensionMD(Module &M, StringRef Name) { |
| 100 | auto NamedMD = M.getNamedMetadata(Name); |
| 101 | if (!NamedMD || NamedMD->getNumOperands() == 1) |
| 102 | return false; |
| 103 | |
| 104 | SmallVector<Metadata *, 4> All; |
| 105 | for (const auto &MD : NamedMD->operands()) |
| 106 | for (const auto &Op : MD->operands()) |
| 107 | if (std::find(All.begin(), All.end(), Op.get()) == All.end()) |
| 108 | All.push_back(Op.get()); |
| 109 | |
| 110 | NamedMD->eraseFromParent(); |
| 111 | NamedMD = M.getOrInsertNamedMetadata(Name); |
Konstantin Zhuravlyov | 980688c | 2016-12-19 16:54:24 +0000 | [diff] [blame] | 112 | for (const auto &MD : All) |
| 113 | NamedMD->addOperand(MDNode::get(M.getContext(), MD)); |
| 114 | |
Stanislav Mekhanoshin | 50ea93a | 2016-12-08 19:46:04 +0000 | [diff] [blame] | 115 | return true; |
| 116 | } |
| 117 | }; |
| 118 | |
| 119 | } // end anonymous namespace |
| 120 | |
| 121 | char AMDGPUUnifyMetadata::ID = 0; |
| 122 | |
| 123 | char &llvm::AMDGPUUnifyMetadataID = AMDGPUUnifyMetadata::ID; |
| 124 | |
| 125 | INITIALIZE_PASS(AMDGPUUnifyMetadata, "amdgpu-unify-metadata", |
| 126 | "Unify multiple OpenCL metadata due to linking", |
| 127 | false, false) |
| 128 | |
| 129 | FunctionPass* llvm::createAMDGPUUnifyMetadataPass() { |
| 130 | return new AMDGPUUnifyMetadata(); |
| 131 | } |
| 132 | |
| 133 | bool AMDGPUUnifyMetadata::runOnModule(Module &M) { |
| 134 | const char* Vers[] = { |
| 135 | kOCLMD::SpirVer, |
| 136 | kOCLMD::OCLVer |
| 137 | }; |
| 138 | const char* Exts[] = { |
| 139 | kOCLMD::UsedExt, |
| 140 | kOCLMD::UsedOptCoreFeat, |
| 141 | kOCLMD::CompilerOptions, |
| 142 | kOCLMD::LLVMIdent |
| 143 | }; |
| 144 | |
| 145 | bool Changed = false; |
| 146 | |
Konstantin Zhuravlyov | 980688c | 2016-12-19 16:54:24 +0000 | [diff] [blame] | 147 | for (auto &I : Vers) |
Stanislav Mekhanoshin | 50ea93a | 2016-12-08 19:46:04 +0000 | [diff] [blame] | 148 | Changed |= unifyVersionMD(M, I, true); |
| 149 | |
Konstantin Zhuravlyov | 980688c | 2016-12-19 16:54:24 +0000 | [diff] [blame] | 150 | for (auto &I : Exts) |
Stanislav Mekhanoshin | 50ea93a | 2016-12-08 19:46:04 +0000 | [diff] [blame] | 151 | Changed |= unifyExtensionMD(M, I); |
| 152 | |
| 153 | return Changed; |
| 154 | } |
| 155 | |
| 156 | bool AMDGPUUnifyMetadata::runOnFunction(Function &F) { |
| 157 | return runOnModule(*F.getParent()); |
| 158 | } |