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