blob: e6e10c7bc6063d91a037581718ef66934c88859d [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"
Eugene Zelenko734bb7b2017-01-20 17:52:16 +000016#include "llvm/ADT/SmallVector.h"
17#include "llvm/ADT/StringRef.h"
Stanislav Mekhanoshin50ea93a2016-12-08 19:46:04 +000018#include "llvm/IR/Constants.h"
Eugene Zelenko734bb7b2017-01-20 17:52:16 +000019#include "llvm/IR/Function.h"
Stanislav Mekhanoshin50ea93a2016-12-08 19:46:04 +000020#include "llvm/IR/Module.h"
21#include "llvm/Pass.h"
Eugene Zelenko734bb7b2017-01-20 17:52:16 +000022#include <algorithm>
23#include <cassert>
Stanislav Mekhanoshin50ea93a2016-12-08 19:46:04 +000024
25using namespace llvm;
26
27namespace {
Eugene Zelenko734bb7b2017-01-20 17:52:16 +000028
Stanislav Mekhanoshin50ea93a2016-12-08 19:46:04 +000029 namespace kOCLMD {
Eugene Zelenko734bb7b2017-01-20 17:52:16 +000030
Stanislav Mekhanoshin50ea93a2016-12-08 19:46:04 +000031 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 Zelenko734bb7b2017-01-20 17:52:16 +000037
38 } // end namespace kOCLMD
Stanislav Mekhanoshin50ea93a2016-12-08 19:46:04 +000039
40 /// \brief Unify multiple OpenCL metadata due to linking.
41 class AMDGPUUnifyMetadata : public FunctionPass {
42 public:
43 static char ID;
Eugene Zelenko734bb7b2017-01-20 17:52:16 +000044
45 explicit AMDGPUUnifyMetadata() : FunctionPass(ID) {}
Stanislav Mekhanoshin50ea93a2016-12-08 19:46:04 +000046
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 Zelenko734bb7b2017-01-20 17:52:16 +000055 bool runOnFunction(Function &F) override;
Stanislav Mekhanoshin50ea93a2016-12-08 19:46:04 +000056
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 Zhuravlyov980688c2016-12-19 16:54:24 +0000112 for (const auto &MD : All)
113 NamedMD->addOperand(MDNode::get(M.getContext(), MD));
114
Stanislav Mekhanoshin50ea93a2016-12-08 19:46:04 +0000115 return true;
116 }
117};
118
119} // end anonymous namespace
120
121char AMDGPUUnifyMetadata::ID = 0;
122
123char &llvm::AMDGPUUnifyMetadataID = AMDGPUUnifyMetadata::ID;
124
125INITIALIZE_PASS(AMDGPUUnifyMetadata, "amdgpu-unify-metadata",
126 "Unify multiple OpenCL metadata due to linking",
127 false, false)
128
129FunctionPass* llvm::createAMDGPUUnifyMetadataPass() {
130 return new AMDGPUUnifyMetadata();
131}
132
133bool 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 Zhuravlyov980688c2016-12-19 16:54:24 +0000147 for (auto &I : Vers)
Stanislav Mekhanoshin50ea93a2016-12-08 19:46:04 +0000148 Changed |= unifyVersionMD(M, I, true);
149
Konstantin Zhuravlyov980688c2016-12-19 16:54:24 +0000150 for (auto &I : Exts)
Stanislav Mekhanoshin50ea93a2016-12-08 19:46:04 +0000151 Changed |= unifyExtensionMD(M, I);
152
153 return Changed;
154}
155
156bool AMDGPUUnifyMetadata::runOnFunction(Function &F) {
157 return runOnModule(*F.getParent());
158}