Line data Source code
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 : // 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 : /// Unify multiple OpenCL metadata due to linking.
41 : class AMDGPUUnifyMetadata : public ModulePass {
42 : public:
43 : static char ID;
44 :
45 74 : explicit AMDGPUUnifyMetadata() : ModulePass(ID) {}
46 :
47 : private:
48 : bool runOnModule(Module &M) override;
49 :
50 : /// 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 148 : bool unifyVersionMD(Module &M, StringRef Name, bool PickFirst) {
60 148 : auto NamedMD = M.getNamedMetadata(Name);
61 148 : if (!NamedMD || NamedMD->getNumOperands() <= 1)
62 147 : return false;
63 : MDNode *MaxMD = nullptr;
64 : auto MaxVer = 0U;
65 1 : for (const auto &VersionMD : NamedMD->operands()) {
66 : assert(VersionMD->getNumOperands() == 2);
67 : auto CMajor = mdconst::extract<ConstantInt>(VersionMD->getOperand(0));
68 : auto VersionMajor = CMajor->getZExtValue();
69 : auto CMinor = mdconst::extract<ConstantInt>(VersionMD->getOperand(1));
70 : auto VersionMinor = CMinor->getZExtValue();
71 1 : auto Ver = (VersionMajor * 100) + (VersionMinor * 10);
72 1 : if (Ver > MaxVer) {
73 1 : MaxVer = Ver;
74 : MaxMD = VersionMD;
75 : }
76 1 : if (PickFirst)
77 : break;
78 : }
79 1 : NamedMD->eraseFromParent();
80 1 : NamedMD = M.getOrInsertNamedMetadata(Name);
81 1 : NamedMD->addOperand(MaxMD);
82 1 : return true;
83 : }
84 :
85 : /// 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 0 : bool unifyExtensionMD(Module &M, StringRef Name) {
93 0 : auto NamedMD = M.getNamedMetadata(Name);
94 0 : if (!NamedMD || NamedMD->getNumOperands() == 1)
95 0 : return false;
96 :
97 : SmallVector<Metadata *, 4> All;
98 0 : for (const auto &MD : NamedMD->operands())
99 0 : for (const auto &Op : MD->operands())
100 0 : if (std::find(All.begin(), All.end(), Op.get()) == All.end())
101 0 : All.push_back(Op.get());
102 :
103 0 : NamedMD->eraseFromParent();
104 0 : NamedMD = M.getOrInsertNamedMetadata(Name);
105 0 : for (const auto &MD : All)
106 0 : NamedMD->addOperand(MDNode::get(M.getContext(), MD));
107 :
108 : return true;
109 : }
110 : };
111 :
112 : } // end anonymous namespace
113 :
114 : char AMDGPUUnifyMetadata::ID = 0;
115 :
116 : char &llvm::AMDGPUUnifyMetadataID = AMDGPUUnifyMetadata::ID;
117 :
118 199024 : INITIALIZE_PASS(AMDGPUUnifyMetadata, "amdgpu-unify-metadata",
119 : "Unify multiple OpenCL metadata due to linking",
120 : false, false)
121 :
122 73 : ModulePass* llvm::createAMDGPUUnifyMetadataPass() {
123 73 : return new AMDGPUUnifyMetadata();
124 : }
125 :
126 74 : bool AMDGPUUnifyMetadata::runOnModule(Module &M) {
127 74 : const char* Vers[] = {
128 : kOCLMD::SpirVer,
129 : kOCLMD::OCLVer
130 : };
131 74 : const char* Exts[] = {
132 : kOCLMD::UsedExt,
133 : kOCLMD::UsedOptCoreFeat,
134 : kOCLMD::CompilerOptions,
135 : kOCLMD::LLVMIdent
136 : };
137 :
138 : bool Changed = false;
139 :
140 222 : for (auto &I : Vers)
141 296 : Changed |= unifyVersionMD(M, I, true);
142 :
143 370 : for (auto &I : Exts)
144 592 : Changed |= unifyExtensionMD(M, I);
145 :
146 74 : return Changed;
147 : }
|