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