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