/Users/buildslave/jenkins/sharedspace/clang-stage2-coverage-R@2/llvm/lib/Target/AMDGPU/AMDGPUUnifyMetadata.cpp
Line | Count | Source |
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" |
16 | | #include "llvm/ADT/SmallVector.h" |
17 | | #include "llvm/ADT/StringRef.h" |
18 | | #include "llvm/IR/Constants.h" |
19 | | #include "llvm/IR/Metadata.h" |
20 | | #include "llvm/IR/Module.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 | | /// \brief Unify multiple OpenCL metadata due to linking. |
41 | | class AMDGPUUnifyMetadata : public ModulePass { |
42 | | public: |
43 | | static char ID; |
44 | | |
45 | 56 | explicit AMDGPUUnifyMetadata() : ModulePass(ID) {} |
46 | | |
47 | | private: |
48 | | bool runOnModule(Module &M) override; |
49 | | |
50 | | /// \brief Unify version metadata. |
51 | | /// \return true if changes are made. |
52 | | /// Assume the named metadata has operands each of which is a pair of |
53 | | /// integer constant, e.g. |
54 | | /// !Name = {!n1, !n2} |
55 | | /// !n1 = {i32 1, i32 2} |
56 | | /// !n2 = {i32 2, i32 0} |
57 | | /// Keep the largest version as the sole operand if PickFirst is false. |
58 | | /// Otherwise pick it from the first value, representing kernel module. |
59 | 112 | bool unifyVersionMD(Module &M, StringRef Name, bool PickFirst) { |
60 | 112 | auto NamedMD = M.getNamedMetadata(Name); |
61 | 112 | if (!NamedMD || 112 NamedMD->getNumOperands() <= 143 ) |
62 | 111 | return false; |
63 | 1 | MDNode *MaxMD = nullptr; |
64 | 1 | auto MaxVer = 0U; |
65 | 1 | for (const auto &VersionMD : NamedMD->operands()) { |
66 | 1 | assert(VersionMD->getNumOperands() == 2); |
67 | 1 | auto CMajor = mdconst::extract<ConstantInt>(VersionMD->getOperand(0)); |
68 | 1 | auto VersionMajor = CMajor->getZExtValue(); |
69 | 1 | auto CMinor = mdconst::extract<ConstantInt>(VersionMD->getOperand(1)); |
70 | 1 | auto VersionMinor = CMinor->getZExtValue(); |
71 | 1 | auto Ver = (VersionMajor * 100) + (VersionMinor * 10); |
72 | 1 | if (Ver > MaxVer1 ) { |
73 | 1 | MaxVer = Ver; |
74 | 1 | MaxMD = VersionMD; |
75 | 1 | } |
76 | 1 | if (PickFirst) |
77 | 1 | break; |
78 | 1 | } |
79 | 1 | NamedMD->eraseFromParent(); |
80 | 112 | NamedMD = M.getOrInsertNamedMetadata(Name); |
81 | 112 | NamedMD->addOperand(MaxMD); |
82 | 112 | return true; |
83 | 112 | } |
84 | | |
85 | | /// \brief Unify version metadata. |
86 | | /// \return true if changes are made. |
87 | | /// Assume the named metadata has operands each of which is a list e.g. |
88 | | /// !Name = {!n1, !n2} |
89 | | /// !n1 = !{!"cl_khr_fp16", {!"cl_khr_fp64"}} |
90 | | /// !n2 = !{!"cl_khr_image"} |
91 | | /// Combine it into a single list with unique operands. |
92 | 224 | bool unifyExtensionMD(Module &M, StringRef Name) { |
93 | 224 | auto NamedMD = M.getNamedMetadata(Name); |
94 | 224 | if (!NamedMD || 224 NamedMD->getNumOperands() == 144 ) |
95 | 222 | return false; |
96 | 2 | |
97 | 2 | SmallVector<Metadata *, 4> All; |
98 | 2 | for (const auto &MD : NamedMD->operands()) |
99 | 9 | for (const auto &Op : MD->operands()) |
100 | 11 | if (11 std::find(All.begin(), All.end(), Op.get()) == All.end()11 ) |
101 | 5 | All.push_back(Op.get()); |
102 | 2 | |
103 | 2 | NamedMD->eraseFromParent(); |
104 | 2 | NamedMD = M.getOrInsertNamedMetadata(Name); |
105 | 2 | for (const auto &MD : All) |
106 | 5 | NamedMD->addOperand(MDNode::get(M.getContext(), MD)); |
107 | 224 | |
108 | 224 | return true; |
109 | 224 | } |
110 | | }; |
111 | | |
112 | | } // end anonymous namespace |
113 | | |
114 | | char AMDGPUUnifyMetadata::ID = 0; |
115 | | |
116 | | char &llvm::AMDGPUUnifyMetadataID = AMDGPUUnifyMetadata::ID; |
117 | | |
118 | | INITIALIZE_PASS(AMDGPUUnifyMetadata, "amdgpu-unify-metadata", |
119 | | "Unify multiple OpenCL metadata due to linking", |
120 | | false, false) |
121 | | |
122 | 55 | ModulePass* llvm::createAMDGPUUnifyMetadataPass() { |
123 | 55 | return new AMDGPUUnifyMetadata(); |
124 | 55 | } |
125 | | |
126 | 56 | bool AMDGPUUnifyMetadata::runOnModule(Module &M) { |
127 | 56 | const char* Vers[] = { |
128 | 56 | kOCLMD::SpirVer, |
129 | 56 | kOCLMD::OCLVer |
130 | 56 | }; |
131 | 56 | const char* Exts[] = { |
132 | 56 | kOCLMD::UsedExt, |
133 | 56 | kOCLMD::UsedOptCoreFeat, |
134 | 56 | kOCLMD::CompilerOptions, |
135 | 56 | kOCLMD::LLVMIdent |
136 | 56 | }; |
137 | 56 | |
138 | 56 | bool Changed = false; |
139 | 56 | |
140 | 56 | for (auto &I : Vers) |
141 | 112 | Changed |= unifyVersionMD(M, I, true); |
142 | 56 | |
143 | 56 | for (auto &I : Exts) |
144 | 224 | Changed |= unifyExtensionMD(M, I); |
145 | 56 | |
146 | 56 | return Changed; |
147 | 56 | } |