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