• Home
  • History
  • Annotate
  • 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