• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //
2 // Copyright 2016 Francisco Jerez
3 //
4 // Permission is hereby granted, free of charge, to any person obtaining a
5 // copy of this software and associated documentation files (the "Software"),
6 // to deal in the Software without restriction, including without limitation
7 // the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 // and/or sell copies of the Software, and to permit persons to whom the
9 // Software is furnished to do so, subject to the following conditions:
10 //
11 // The above copyright notice and this permission notice shall be included in
12 // all copies or substantial portions of the Software.
13 //
14 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
17 // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
18 // OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
19 // ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20 // OTHER DEALINGS IN THE SOFTWARE.
21 //
22 
23 ///
24 /// \file
25 /// Utility functions for LLVM IR metadata introspection.
26 ///
27 
28 #ifndef CLOVER_LLVM_METADATA_HPP
29 #define CLOVER_LLVM_METADATA_HPP
30 
31 #include "llvm/compat.hpp"
32 #include "util/algorithm.hpp"
33 
34 #include <vector>
35 #include <llvm/IR/Module.h>
36 #include <llvm/IR/Metadata.h>
37 
38 namespace clover {
39    namespace llvm {
40       namespace detail {
41          inline std::vector<const ::llvm::MDNode *>
get_kernel_nodes(const::llvm::Module & mod)42          get_kernel_nodes(const ::llvm::Module &mod) {
43             if (const ::llvm::NamedMDNode *n =
44                    mod.getNamedMetadata("opencl.kernels"))
45                return { n->op_begin(), n->op_end() };
46             else
47                return {};
48          }
49 
50          inline std::function<bool (const ::llvm::MDNode *n)>
is_kernel_node_for(const::llvm::Function & f)51          is_kernel_node_for(const ::llvm::Function &f) {
52             return [&](const ::llvm::MDNode *n) {
53                using ::llvm::mdconst::dyn_extract;
54                return &f == dyn_extract< ::llvm::Function>(n->getOperand(0));
55             };
56          }
57 
58          inline bool
is_kernel(const::llvm::Function & f)59          is_kernel(const ::llvm::Function &f) {
60 #if HAVE_LLVM >= 0x0309
61             return f.getMetadata("kernel_arg_type");
62 #else
63             return clover::any_of(is_kernel_node_for(f),
64                                   get_kernel_nodes(*f.getParent()));
65 #endif
66          }
67 
68          inline iterator_range< ::llvm::MDNode::op_iterator>
get_kernel_metadata_operands(const::llvm::Function & f,const std::string & name)69          get_kernel_metadata_operands(const ::llvm::Function &f,
70                                       const std::string &name) {
71 #if HAVE_LLVM >= 0x0309
72             // On LLVM v3.9+ kernel argument attributes are stored as
73             // function metadata.
74             const auto data_node = f.getMetadata(name);
75             return range(data_node->op_begin(), data_node->op_end());
76 #else
77             using ::llvm::cast;
78             using ::llvm::dyn_cast;
79             const auto kernel_node = find(is_kernel_node_for(f),
80                                           get_kernel_nodes(*f.getParent()));
81 
82             const auto data_node = cast< ::llvm::MDNode>(
83                find([&](const ::llvm::MDOperand &op) {
84                      if (auto m = dyn_cast< ::llvm::MDNode>(op))
85                         if (m->getNumOperands())
86                            if (auto m_name = dyn_cast< ::llvm::MDString>(
87                                   m->getOperand(0).get()))
88                               return m_name->getString() == name;
89 
90                      return false;
91                   },
92                   kernel_node->operands()));
93 
94             // Skip the first operand node which is just the metadata
95             // attribute name.
96             return range(data_node->op_begin() + 1, data_node->op_end());
97 #endif
98          }
99       }
100 
101       ///
102       /// Extract the string metadata node \p name corresponding to the kernel
103       /// argument given by \p arg.
104       ///
105       inline std::string
get_argument_metadata(const::llvm::Function & f,const::llvm::Argument & arg,const std::string & name)106       get_argument_metadata(const ::llvm::Function &f,
107                             const ::llvm::Argument &arg,
108                             const std::string &name) {
109          return ::llvm::cast< ::llvm::MDString>(
110                detail::get_kernel_metadata_operands(f, name)[arg.getArgNo()])
111             ->getString();
112       }
113 
114       ///
115       /// Return a vector with all CL kernel functions found in the LLVM
116       /// module \p mod.
117       ///
118       inline std::vector<const ::llvm::Function *>
get_kernels(const::llvm::Module & mod)119       get_kernels(const ::llvm::Module &mod) {
120          std::vector<const ::llvm::Function *> fs;
121 
122          for (auto &f : mod.getFunctionList()) {
123             if (detail::is_kernel(f))
124                fs.push_back(&f);
125          }
126 
127          return fs;
128       }
129    }
130 }
131 
132 #endif
133