]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - lib/Target/AMDGPU/AMDGPUUnifyMetadata.cpp
Vendor import of llvm trunk r291274:
[FreeBSD/FreeBSD.git] / lib / Target / AMDGPU / AMDGPUUnifyMetadata.cpp
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     for (const auto &MD : All)
104       NamedMD->addOperand(MDNode::get(M.getContext(), MD));
105
106     return true;
107   }
108 };
109
110 } // end anonymous namespace
111
112 char AMDGPUUnifyMetadata::ID = 0;
113
114 char &llvm::AMDGPUUnifyMetadataID = AMDGPUUnifyMetadata::ID;
115
116 INITIALIZE_PASS(AMDGPUUnifyMetadata, "amdgpu-unify-metadata",
117                 "Unify multiple OpenCL metadata due to linking",
118                 false, false)
119
120 FunctionPass* llvm::createAMDGPUUnifyMetadataPass() {
121   return new AMDGPUUnifyMetadata();
122 }
123
124 bool 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
138   for (auto &I : Vers)
139     Changed |= unifyVersionMD(M, I, true);
140
141   for (auto &I : Exts)
142     Changed |= unifyExtensionMD(M, I);
143
144   return Changed;
145 }
146
147 bool AMDGPUUnifyMetadata::runOnFunction(Function &F) {
148   return runOnModule(*F.getParent());
149 }