xref: /freebsd/contrib/llvm-project/llvm/lib/Target/AMDGPU/AMDGPUUnifyMetadata.cpp (revision bdd1243df58e60e85101c09001d9812a789b6bc4)
10b57cec5SDimitry Andric //===- AMDGPUUnifyMetadata.cpp - Unify OpenCL metadata --------------------===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric //
90b57cec5SDimitry Andric // \file
100b57cec5SDimitry Andric // This pass that unifies multiple OpenCL metadata due to linking.
110b57cec5SDimitry Andric //
120b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
130b57cec5SDimitry Andric 
140b57cec5SDimitry Andric #include "AMDGPU.h"
150b57cec5SDimitry Andric #include "llvm/IR/Constants.h"
160b57cec5SDimitry Andric #include "llvm/IR/Module.h"
17e8d8bef9SDimitry Andric #include "llvm/IR/PassManager.h"
180b57cec5SDimitry Andric #include "llvm/Pass.h"
190b57cec5SDimitry Andric 
200b57cec5SDimitry Andric using namespace llvm;
210b57cec5SDimitry Andric 
220b57cec5SDimitry Andric namespace {
230b57cec5SDimitry Andric 
240b57cec5SDimitry Andric   namespace kOCLMD {
250b57cec5SDimitry Andric 
260b57cec5SDimitry Andric     const char SpirVer[]            = "opencl.spir.version";
270b57cec5SDimitry Andric     const char OCLVer[]             = "opencl.ocl.version";
280b57cec5SDimitry Andric     const char UsedExt[]            = "opencl.used.extensions";
290b57cec5SDimitry Andric     const char UsedOptCoreFeat[]    = "opencl.used.optional.core.features";
300b57cec5SDimitry Andric     const char CompilerOptions[]    = "opencl.compiler.options";
310b57cec5SDimitry Andric     const char LLVMIdent[]          = "llvm.ident";
320b57cec5SDimitry Andric 
330b57cec5SDimitry Andric   } // end namespace kOCLMD
340b57cec5SDimitry Andric 
350b57cec5SDimitry Andric   /// Unify multiple OpenCL metadata due to linking.
360b57cec5SDimitry Andric   class AMDGPUUnifyMetadata : public ModulePass {
370b57cec5SDimitry Andric   public:
380b57cec5SDimitry Andric     static char ID;
390b57cec5SDimitry Andric 
AMDGPUUnifyMetadata()400b57cec5SDimitry Andric     explicit AMDGPUUnifyMetadata() : ModulePass(ID) {}
410b57cec5SDimitry Andric 
420b57cec5SDimitry Andric   private:
430b57cec5SDimitry Andric     bool runOnModule(Module &M) override;
44e8d8bef9SDimitry Andric   };
450b57cec5SDimitry Andric 
460b57cec5SDimitry Andric     /// Unify version metadata.
470b57cec5SDimitry Andric     /// \return true if changes are made.
480b57cec5SDimitry Andric     /// Assume the named metadata has operands each of which is a pair of
490b57cec5SDimitry Andric     /// integer constant, e.g.
500b57cec5SDimitry Andric     /// !Name = {!n1, !n2}
510b57cec5SDimitry Andric     /// !n1 = {i32 1, i32 2}
520b57cec5SDimitry Andric     /// !n2 = {i32 2, i32 0}
530b57cec5SDimitry Andric     /// Keep the largest version as the sole operand if PickFirst is false.
540b57cec5SDimitry Andric     /// Otherwise pick it from the first value, representing kernel module.
unifyVersionMD(Module & M,StringRef Name,bool PickFirst)550b57cec5SDimitry Andric     bool unifyVersionMD(Module &M, StringRef Name, bool PickFirst) {
560b57cec5SDimitry Andric       auto NamedMD = M.getNamedMetadata(Name);
570b57cec5SDimitry Andric       if (!NamedMD || NamedMD->getNumOperands() <= 1)
580b57cec5SDimitry Andric         return false;
590b57cec5SDimitry Andric       MDNode *MaxMD = nullptr;
600b57cec5SDimitry Andric       auto MaxVer = 0U;
61*bdd1243dSDimitry Andric       for (auto *VersionMD : NamedMD->operands()) {
620b57cec5SDimitry Andric         assert(VersionMD->getNumOperands() == 2);
630b57cec5SDimitry Andric         auto CMajor = mdconst::extract<ConstantInt>(VersionMD->getOperand(0));
640b57cec5SDimitry Andric         auto VersionMajor = CMajor->getZExtValue();
650b57cec5SDimitry Andric         auto CMinor = mdconst::extract<ConstantInt>(VersionMD->getOperand(1));
660b57cec5SDimitry Andric         auto VersionMinor = CMinor->getZExtValue();
670b57cec5SDimitry Andric         auto Ver = (VersionMajor * 100) + (VersionMinor * 10);
680b57cec5SDimitry Andric         if (Ver > MaxVer) {
690b57cec5SDimitry Andric           MaxVer = Ver;
700b57cec5SDimitry Andric           MaxMD = VersionMD;
710b57cec5SDimitry Andric         }
720b57cec5SDimitry Andric         if (PickFirst)
730b57cec5SDimitry Andric           break;
740b57cec5SDimitry Andric       }
750b57cec5SDimitry Andric       NamedMD->eraseFromParent();
760b57cec5SDimitry Andric       NamedMD = M.getOrInsertNamedMetadata(Name);
770b57cec5SDimitry Andric       NamedMD->addOperand(MaxMD);
780b57cec5SDimitry Andric       return true;
790b57cec5SDimitry Andric     }
800b57cec5SDimitry Andric 
810b57cec5SDimitry Andric   /// Unify version metadata.
820b57cec5SDimitry Andric   /// \return true if changes are made.
830b57cec5SDimitry Andric   /// Assume the named metadata has operands each of which is a list e.g.
840b57cec5SDimitry Andric   /// !Name = {!n1, !n2}
850b57cec5SDimitry Andric   /// !n1 = !{!"cl_khr_fp16", {!"cl_khr_fp64"}}
860b57cec5SDimitry Andric   /// !n2 = !{!"cl_khr_image"}
870b57cec5SDimitry Andric   /// Combine it into a single list with unique operands.
unifyExtensionMD(Module & M,StringRef Name)880b57cec5SDimitry Andric   bool unifyExtensionMD(Module &M, StringRef Name) {
890b57cec5SDimitry Andric     auto NamedMD = M.getNamedMetadata(Name);
900b57cec5SDimitry Andric     if (!NamedMD || NamedMD->getNumOperands() == 1)
910b57cec5SDimitry Andric       return false;
920b57cec5SDimitry Andric 
930b57cec5SDimitry Andric     SmallVector<Metadata *, 4> All;
94*bdd1243dSDimitry Andric     for (auto *MD : NamedMD->operands())
950b57cec5SDimitry Andric       for (const auto &Op : MD->operands())
96e8d8bef9SDimitry Andric         if (!llvm::is_contained(All, Op.get()))
970b57cec5SDimitry Andric           All.push_back(Op.get());
980b57cec5SDimitry Andric 
990b57cec5SDimitry Andric     NamedMD->eraseFromParent();
1000b57cec5SDimitry Andric     NamedMD = M.getOrInsertNamedMetadata(Name);
1010b57cec5SDimitry Andric     for (const auto &MD : All)
1020b57cec5SDimitry Andric       NamedMD->addOperand(MDNode::get(M.getContext(), MD));
1030b57cec5SDimitry Andric 
1040b57cec5SDimitry Andric     return true;
1050b57cec5SDimitry Andric   }
1060b57cec5SDimitry Andric 
unifyMetadataImpl(Module & M)107e8d8bef9SDimitry Andric   bool unifyMetadataImpl(Module &M) {
108e8d8bef9SDimitry Andric     const char *Vers[] = {kOCLMD::SpirVer, kOCLMD::OCLVer};
109e8d8bef9SDimitry Andric     const char *Exts[] = {kOCLMD::UsedExt, kOCLMD::UsedOptCoreFeat,
110e8d8bef9SDimitry Andric                           kOCLMD::CompilerOptions, kOCLMD::LLVMIdent};
1110b57cec5SDimitry Andric 
1120b57cec5SDimitry Andric     bool Changed = false;
1130b57cec5SDimitry Andric 
1140b57cec5SDimitry Andric     for (auto &I : Vers)
1150b57cec5SDimitry Andric       Changed |= unifyVersionMD(M, I, true);
1160b57cec5SDimitry Andric 
1170b57cec5SDimitry Andric     for (auto &I : Exts)
1180b57cec5SDimitry Andric       Changed |= unifyExtensionMD(M, I);
1190b57cec5SDimitry Andric 
1200b57cec5SDimitry Andric     return Changed;
1210b57cec5SDimitry Andric   }
122e8d8bef9SDimitry Andric 
123e8d8bef9SDimitry Andric   } // end anonymous namespace
124e8d8bef9SDimitry Andric 
125e8d8bef9SDimitry Andric   char AMDGPUUnifyMetadata::ID = 0;
126e8d8bef9SDimitry Andric 
127e8d8bef9SDimitry Andric   char &llvm::AMDGPUUnifyMetadataID = AMDGPUUnifyMetadata::ID;
128e8d8bef9SDimitry Andric 
129e8d8bef9SDimitry Andric   INITIALIZE_PASS(AMDGPUUnifyMetadata, "amdgpu-unify-metadata",
130e8d8bef9SDimitry Andric                   "Unify multiple OpenCL metadata due to linking", false, false)
131e8d8bef9SDimitry Andric 
createAMDGPUUnifyMetadataPass()132e8d8bef9SDimitry Andric   ModulePass *llvm::createAMDGPUUnifyMetadataPass() {
133e8d8bef9SDimitry Andric     return new AMDGPUUnifyMetadata();
134e8d8bef9SDimitry Andric   }
135e8d8bef9SDimitry Andric 
runOnModule(Module & M)136e8d8bef9SDimitry Andric   bool AMDGPUUnifyMetadata::runOnModule(Module &M) {
137e8d8bef9SDimitry Andric     return unifyMetadataImpl(M);
138e8d8bef9SDimitry Andric   }
139e8d8bef9SDimitry Andric 
run(Module & M,ModuleAnalysisManager & AM)140e8d8bef9SDimitry Andric   PreservedAnalyses AMDGPUUnifyMetadataPass::run(Module &M,
141e8d8bef9SDimitry Andric                                                  ModuleAnalysisManager &AM) {
142e8d8bef9SDimitry Andric     return unifyMetadataImpl(M) ? PreservedAnalyses::none()
143e8d8bef9SDimitry Andric                                 : PreservedAnalyses::all();
144e8d8bef9SDimitry Andric   }
145