1c8fbf6ffSEugene Zelenko //===- AMDGPUUnifyMetadata.cpp - Unify OpenCL metadata --------------------===//
250ea93a2SStanislav Mekhanoshin //
32946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
42946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information.
52946cd70SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
650ea93a2SStanislav Mekhanoshin //
750ea93a2SStanislav Mekhanoshin //===----------------------------------------------------------------------===//
850ea93a2SStanislav Mekhanoshin //
950ea93a2SStanislav Mekhanoshin // \file
105f8f34e4SAdrian Prantl // This pass that unifies multiple OpenCL metadata due to linking.
1150ea93a2SStanislav Mekhanoshin //
1250ea93a2SStanislav Mekhanoshin //===----------------------------------------------------------------------===//
1350ea93a2SStanislav Mekhanoshin 
1450ea93a2SStanislav Mekhanoshin #include "AMDGPU.h"
1550ea93a2SStanislav Mekhanoshin #include "llvm/IR/Constants.h"
1650ea93a2SStanislav Mekhanoshin #include "llvm/IR/Module.h"
17*e1833e74SArthur Eubanks #include "llvm/IR/PassManager.h"
1850ea93a2SStanislav Mekhanoshin #include "llvm/Pass.h"
1950ea93a2SStanislav Mekhanoshin 
2050ea93a2SStanislav Mekhanoshin using namespace llvm;
2150ea93a2SStanislav Mekhanoshin 
2250ea93a2SStanislav Mekhanoshin namespace {
23734bb7bbSEugene Zelenko 
2450ea93a2SStanislav Mekhanoshin   namespace kOCLMD {
25734bb7bbSEugene Zelenko 
2650ea93a2SStanislav Mekhanoshin     const char SpirVer[]            = "opencl.spir.version";
2750ea93a2SStanislav Mekhanoshin     const char OCLVer[]             = "opencl.ocl.version";
2850ea93a2SStanislav Mekhanoshin     const char UsedExt[]            = "opencl.used.extensions";
2950ea93a2SStanislav Mekhanoshin     const char UsedOptCoreFeat[]    = "opencl.used.optional.core.features";
3050ea93a2SStanislav Mekhanoshin     const char CompilerOptions[]    = "opencl.compiler.options";
3150ea93a2SStanislav Mekhanoshin     const char LLVMIdent[]          = "llvm.ident";
32734bb7bbSEugene Zelenko 
33734bb7bbSEugene Zelenko   } // end namespace kOCLMD
3450ea93a2SStanislav Mekhanoshin 
355f8f34e4SAdrian Prantl   /// Unify multiple OpenCL metadata due to linking.
36f6c1feb8SStanislav Mekhanoshin   class AMDGPUUnifyMetadata : public ModulePass {
3750ea93a2SStanislav Mekhanoshin   public:
3850ea93a2SStanislav Mekhanoshin     static char ID;
39c8fbf6ffSEugene Zelenko 
AMDGPUUnifyMetadata()40c8fbf6ffSEugene Zelenko     explicit AMDGPUUnifyMetadata() : ModulePass(ID) {}
4150ea93a2SStanislav Mekhanoshin 
4250ea93a2SStanislav Mekhanoshin   private:
43c8fbf6ffSEugene Zelenko     bool runOnModule(Module &M) override;
44*e1833e74SArthur Eubanks   };
4550ea93a2SStanislav Mekhanoshin 
465f8f34e4SAdrian Prantl     /// Unify version metadata.
4750ea93a2SStanislav Mekhanoshin     /// \return true if changes are made.
4850ea93a2SStanislav Mekhanoshin     /// Assume the named metadata has operands each of which is a pair of
4950ea93a2SStanislav Mekhanoshin     /// integer constant, e.g.
5050ea93a2SStanislav Mekhanoshin     /// !Name = {!n1, !n2}
5150ea93a2SStanislav Mekhanoshin     /// !n1 = {i32 1, i32 2}
5250ea93a2SStanislav Mekhanoshin     /// !n2 = {i32 2, i32 0}
5350ea93a2SStanislav Mekhanoshin     /// Keep the largest version as the sole operand if PickFirst is false.
5450ea93a2SStanislav Mekhanoshin     /// Otherwise pick it from the first value, representing kernel module.
unifyVersionMD(Module & M,StringRef Name,bool PickFirst)5550ea93a2SStanislav Mekhanoshin     bool unifyVersionMD(Module &M, StringRef Name, bool PickFirst) {
5650ea93a2SStanislav Mekhanoshin       auto NamedMD = M.getNamedMetadata(Name);
5750ea93a2SStanislav Mekhanoshin       if (!NamedMD || NamedMD->getNumOperands() <= 1)
5850ea93a2SStanislav Mekhanoshin         return false;
5950ea93a2SStanislav Mekhanoshin       MDNode *MaxMD = nullptr;
6050ea93a2SStanislav Mekhanoshin       auto MaxVer = 0U;
612d903cc9SMark de Wever       for (auto VersionMD : NamedMD->operands()) {
6250ea93a2SStanislav Mekhanoshin         assert(VersionMD->getNumOperands() == 2);
6350ea93a2SStanislav Mekhanoshin         auto CMajor = mdconst::extract<ConstantInt>(VersionMD->getOperand(0));
6450ea93a2SStanislav Mekhanoshin         auto VersionMajor = CMajor->getZExtValue();
6550ea93a2SStanislav Mekhanoshin         auto CMinor = mdconst::extract<ConstantInt>(VersionMD->getOperand(1));
6650ea93a2SStanislav Mekhanoshin         auto VersionMinor = CMinor->getZExtValue();
6750ea93a2SStanislav Mekhanoshin         auto Ver = (VersionMajor * 100) + (VersionMinor * 10);
6850ea93a2SStanislav Mekhanoshin         if (Ver > MaxVer) {
6950ea93a2SStanislav Mekhanoshin           MaxVer = Ver;
7050ea93a2SStanislav Mekhanoshin           MaxMD = VersionMD;
7150ea93a2SStanislav Mekhanoshin         }
7250ea93a2SStanislav Mekhanoshin         if (PickFirst)
7350ea93a2SStanislav Mekhanoshin           break;
7450ea93a2SStanislav Mekhanoshin       }
7550ea93a2SStanislav Mekhanoshin       NamedMD->eraseFromParent();
7650ea93a2SStanislav Mekhanoshin       NamedMD = M.getOrInsertNamedMetadata(Name);
7750ea93a2SStanislav Mekhanoshin       NamedMD->addOperand(MaxMD);
7850ea93a2SStanislav Mekhanoshin       return true;
7950ea93a2SStanislav Mekhanoshin     }
8050ea93a2SStanislav Mekhanoshin 
815f8f34e4SAdrian Prantl   /// Unify version metadata.
8250ea93a2SStanislav Mekhanoshin   /// \return true if changes are made.
8350ea93a2SStanislav Mekhanoshin   /// Assume the named metadata has operands each of which is a list e.g.
8450ea93a2SStanislav Mekhanoshin   /// !Name = {!n1, !n2}
8550ea93a2SStanislav Mekhanoshin   /// !n1 = !{!"cl_khr_fp16", {!"cl_khr_fp64"}}
8650ea93a2SStanislav Mekhanoshin   /// !n2 = !{!"cl_khr_image"}
8750ea93a2SStanislav Mekhanoshin   /// Combine it into a single list with unique operands.
unifyExtensionMD(Module & M,StringRef Name)8850ea93a2SStanislav Mekhanoshin   bool unifyExtensionMD(Module &M, StringRef Name) {
8950ea93a2SStanislav Mekhanoshin     auto NamedMD = M.getNamedMetadata(Name);
9050ea93a2SStanislav Mekhanoshin     if (!NamedMD || NamedMD->getNumOperands() == 1)
9150ea93a2SStanislav Mekhanoshin       return false;
9250ea93a2SStanislav Mekhanoshin 
9350ea93a2SStanislav Mekhanoshin     SmallVector<Metadata *, 4> All;
942d903cc9SMark de Wever     for (auto MD : NamedMD->operands())
9550ea93a2SStanislav Mekhanoshin       for (const auto &Op : MD->operands())
96902cbcd5SKazu Hirata         if (!llvm::is_contained(All, Op.get()))
9750ea93a2SStanislav Mekhanoshin           All.push_back(Op.get());
9850ea93a2SStanislav Mekhanoshin 
9950ea93a2SStanislav Mekhanoshin     NamedMD->eraseFromParent();
10050ea93a2SStanislav Mekhanoshin     NamedMD = M.getOrInsertNamedMetadata(Name);
101980688cdSKonstantin Zhuravlyov     for (const auto &MD : All)
102980688cdSKonstantin Zhuravlyov       NamedMD->addOperand(MDNode::get(M.getContext(), MD));
103980688cdSKonstantin Zhuravlyov 
10450ea93a2SStanislav Mekhanoshin     return true;
10550ea93a2SStanislav Mekhanoshin   }
10650ea93a2SStanislav Mekhanoshin 
unifyMetadataImpl(Module & M)107*e1833e74SArthur Eubanks   bool unifyMetadataImpl(Module &M) {
108*e1833e74SArthur Eubanks     const char *Vers[] = {kOCLMD::SpirVer, kOCLMD::OCLVer};
109*e1833e74SArthur Eubanks     const char *Exts[] = {kOCLMD::UsedExt, kOCLMD::UsedOptCoreFeat,
110*e1833e74SArthur Eubanks                           kOCLMD::CompilerOptions, kOCLMD::LLVMIdent};
11150ea93a2SStanislav Mekhanoshin 
11250ea93a2SStanislav Mekhanoshin     bool Changed = false;
11350ea93a2SStanislav Mekhanoshin 
11450ea93a2SStanislav Mekhanoshin     for (auto &I : Vers)
11550ea93a2SStanislav Mekhanoshin       Changed |= unifyVersionMD(M, I, true);
11650ea93a2SStanislav Mekhanoshin 
11750ea93a2SStanislav Mekhanoshin     for (auto &I : Exts)
11850ea93a2SStanislav Mekhanoshin       Changed |= unifyExtensionMD(M, I);
11950ea93a2SStanislav Mekhanoshin 
12050ea93a2SStanislav Mekhanoshin     return Changed;
12150ea93a2SStanislav Mekhanoshin   }
122*e1833e74SArthur Eubanks 
123*e1833e74SArthur Eubanks   } // end anonymous namespace
124*e1833e74SArthur Eubanks 
125*e1833e74SArthur Eubanks   char AMDGPUUnifyMetadata::ID = 0;
126*e1833e74SArthur Eubanks 
127*e1833e74SArthur Eubanks   char &llvm::AMDGPUUnifyMetadataID = AMDGPUUnifyMetadata::ID;
128*e1833e74SArthur Eubanks 
129*e1833e74SArthur Eubanks   INITIALIZE_PASS(AMDGPUUnifyMetadata, "amdgpu-unify-metadata",
130*e1833e74SArthur Eubanks                   "Unify multiple OpenCL metadata due to linking", false, false)
131*e1833e74SArthur Eubanks 
createAMDGPUUnifyMetadataPass()132*e1833e74SArthur Eubanks   ModulePass *llvm::createAMDGPUUnifyMetadataPass() {
133*e1833e74SArthur Eubanks     return new AMDGPUUnifyMetadata();
134*e1833e74SArthur Eubanks   }
135*e1833e74SArthur Eubanks 
runOnModule(Module & M)136*e1833e74SArthur Eubanks   bool AMDGPUUnifyMetadata::runOnModule(Module &M) {
137*e1833e74SArthur Eubanks     return unifyMetadataImpl(M);
138*e1833e74SArthur Eubanks   }
139*e1833e74SArthur Eubanks 
run(Module & M,ModuleAnalysisManager & AM)140*e1833e74SArthur Eubanks   PreservedAnalyses AMDGPUUnifyMetadataPass::run(Module &M,
141*e1833e74SArthur Eubanks                                                  ModuleAnalysisManager &AM) {
142*e1833e74SArthur Eubanks     return unifyMetadataImpl(M) ? PreservedAnalyses::none()
143*e1833e74SArthur Eubanks                                 : PreservedAnalyses::all();
144*e1833e74SArthur Eubanks   }
145