Skip to content

Commit 50ea93a

Browse files
committedDec 8, 2016
[AMDGPU] Add amdgpu-unify-metadata pass
Multiple metadata values for records such as opencl.ocl.version, llvm.ident and similar are created after linking several modules. For some of them, notably opencl.ocl.version, this creates semantic problem because we cannot tell which version of OpenCL the composite module conforms. Moreover, such repetitions of identical values often create a huge list of unneeded metadata, which grows bitcode size both in memory and stored on disk. It can go up to several Mb when linked against our OpenCL library. Lastly, such long lists obscure reading of dumped IR. The pass unifies metadata after linking. Differential Revision: https://reviews.llvm.org/D25381 llvm-svn: 289092
1 parent 64135c3 commit 50ea93a

File tree

6 files changed

+185
-0
lines changed

6 files changed

+185
-0
lines changed
 

‎llvm/lib/Target/AMDGPU/AMDGPU.h

+4
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,10 @@ ModulePass *createAMDGPUAlwaysInlinePass();
9090
ModulePass *createAMDGPUOpenCLImageTypeLoweringPass();
9191
FunctionPass *createAMDGPUAnnotateUniformValues();
9292

93+
FunctionPass* createAMDGPUUnifyMetadataPass();
94+
void initializeAMDGPUUnifyMetadataPass(PassRegistry&);
95+
extern char &AMDGPUUnifyMetadataID;
96+
9397
void initializeSIFixControlFlowLiveIntervalsPass(PassRegistry&);
9498
extern char &SIFixControlFlowLiveIntervalsID;
9599

‎llvm/lib/Target/AMDGPU/AMDGPUTargetMachine.cpp

+6
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
#include "llvm/Transforms/Scalar.h"
3535
#include "llvm/Transforms/Scalar/GVN.h"
3636
#include "llvm/Transforms/Vectorize.h"
37+
#include "llvm/IR/LegacyPassManager.h"
3738

3839
using namespace llvm;
3940

@@ -85,6 +86,7 @@ extern "C" void LLVMInitializeAMDGPUTarget() {
8586
initializeAMDGPUAnnotateUniformValuesPass(*PR);
8687
initializeAMDGPUPromoteAllocaPass(*PR);
8788
initializeAMDGPUCodeGenPreparePass(*PR);
89+
initializeAMDGPUUnifyMetadataPass(*PR);
8890
initializeSIAnnotateControlFlowPass(*PR);
8991
initializeSIInsertWaitsPass(*PR);
9092
initializeSIWholeQuadModePass(*PR);
@@ -189,6 +191,10 @@ StringRef AMDGPUTargetMachine::getFeatureString(const Function &F) const {
189191
FSAttr.getValueAsString();
190192
}
191193

194+
void AMDGPUTargetMachine::addEarlyAsPossiblePasses(PassManagerBase &PM) {
195+
PM.add(llvm::createAMDGPUUnifyMetadataPass());
196+
}
197+
192198
//===----------------------------------------------------------------------===//
193199
// R600 Target Machine (R600 -> Cayman)
194200
//===----------------------------------------------------------------------===//

‎llvm/lib/Target/AMDGPU/AMDGPUTargetMachine.h

+1
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ class AMDGPUTargetMachine : public LLVMTargetMachine {
5050
TargetLoweringObjectFile *getObjFileLowering() const override {
5151
return TLOF.get();
5252
}
53+
void addEarlyAsPossiblePasses(PassManagerBase &PM) override;
5354
};
5455

5556
//===----------------------------------------------------------------------===//
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,147 @@
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/IR/Constants.h"
17+
#include "llvm/IR/Module.h"
18+
#include "llvm/Pass.h"
19+
20+
using namespace llvm;
21+
22+
namespace {
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);
103+
NamedMD->addOperand(MDNode::get(M.getContext(), All));
104+
return true;
105+
}
106+
};
107+
108+
} // end anonymous namespace
109+
110+
char AMDGPUUnifyMetadata::ID = 0;
111+
112+
char &llvm::AMDGPUUnifyMetadataID = AMDGPUUnifyMetadata::ID;
113+
114+
INITIALIZE_PASS(AMDGPUUnifyMetadata, "amdgpu-unify-metadata",
115+
"Unify multiple OpenCL metadata due to linking",
116+
false, false)
117+
118+
FunctionPass* llvm::createAMDGPUUnifyMetadataPass() {
119+
return new AMDGPUUnifyMetadata();
120+
}
121+
122+
bool AMDGPUUnifyMetadata::runOnModule(Module &M) {
123+
const char* Vers[] = {
124+
kOCLMD::SpirVer,
125+
kOCLMD::OCLVer
126+
};
127+
const char* Exts[] = {
128+
kOCLMD::UsedExt,
129+
kOCLMD::UsedOptCoreFeat,
130+
kOCLMD::CompilerOptions,
131+
kOCLMD::LLVMIdent
132+
};
133+
134+
bool Changed = false;
135+
136+
for (auto &I:Vers)
137+
Changed |= unifyVersionMD(M, I, true);
138+
139+
for (auto &I:Exts)
140+
Changed |= unifyExtensionMD(M, I);
141+
142+
return Changed;
143+
}
144+
145+
bool AMDGPUUnifyMetadata::runOnFunction(Function &F) {
146+
return runOnModule(*F.getParent());
147+
}

‎llvm/lib/Target/AMDGPU/CMakeLists.txt

+1
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ add_llvm_target(AMDGPUCodeGen
4141
AMDGPUISelDAGToDAG.cpp
4242
AMDGPUMCInstLower.cpp
4343
AMDGPUMachineFunction.cpp
44+
AMDGPUUnifyMetadata.cpp
4445
AMDGPUOpenCLImageTypeLoweringPass.cpp
4546
AMDGPUSubtarget.cpp
4647
AMDGPUTargetMachine.cpp
+26
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
; RUN: opt -mtriple=amdgcn--amdhsa -amdgpu-unify-metadata -S < %s | FileCheck -check-prefix=ALL %s
2+
3+
; This test check that we have a singe metadata value after linking several
4+
; modules for records such as opencl.ocl.version, llvm.ident and similar.
5+
6+
; ALL-DAG: !opencl.ocl.version = !{![[OCL_VER:[0-9]+]]}
7+
; ALL-DAG: !llvm.ident = !{![[LLVM_IDENT:[0-9]+]]}
8+
; ALL-DAG: !opencl.used.extensions = !{![[USED_EXT:[0-9]+]]}
9+
; ALL-DAG: ![[OCL_VER]] = !{i32 1, i32 2}
10+
; ALL-DAG: ![[LLVM_IDENT]] = !{!"clang version 4.0 "}
11+
; ALL-DAG: ![[USED_EXT]] = !{!"cl_images", !"cl_khr_fp16", !"cl_doubles"}
12+
13+
define void @test() {
14+
ret void
15+
}
16+
17+
!opencl.ocl.version = !{!1, !0, !0, !0}
18+
!llvm.ident = !{!2, !2, !2, !2}
19+
!opencl.used.extensions = !{!3, !3, !4, !5}
20+
21+
!0 = !{i32 2, i32 0}
22+
!1 = !{i32 1, i32 2}
23+
!2 = !{!"clang version 4.0 "}
24+
!3 = !{!"cl_images", !"cl_khr_fp16"}
25+
!4 = !{!"cl_images", !"cl_doubles"}
26+
!5 = !{}

0 commit comments

Comments
 (0)
Please sign in to comment.