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