• 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/Config/llvm-config.h>
36 #include <llvm/IR/Constants.h>
37 #include <llvm/IR/Module.h>
38 #include <llvm/IR/Metadata.h>
39 
40 namespace clover {
41    namespace llvm {
42       namespace detail {
43          inline bool
is_kernel(const::llvm::Function & f)44          is_kernel(const ::llvm::Function &f) {
45             return f.getMetadata("kernel_arg_type");
46          }
47 
48          inline iterator_range< ::llvm::MDNode::op_iterator>
get_kernel_metadata_operands(const::llvm::Function & f,const std::string & name)49          get_kernel_metadata_operands(const ::llvm::Function &f,
50                                       const std::string &name) {
51             const auto data_node = f.getMetadata(name);
52             if (data_node)
53                return range(data_node->op_begin(), data_node->op_end());
54             else
55                return iterator_range< ::llvm::MDNode::op_iterator>();
56          }
57       }
58 
59       ///
60       /// Extract the string metadata node \p name.
61       ///
62       inline std::string
get_str_kernel_metadata(const::llvm::Function & f,const std::string & name)63       get_str_kernel_metadata(const ::llvm::Function &f,
64                           const std::string &name) {
65          auto operands = detail::get_kernel_metadata_operands(f, name);
66          if (operands.size()) {
67             return ::llvm::cast< ::llvm::MDString>(
68                detail::get_kernel_metadata_operands(f, name)[0])
69                ->getString().str();
70          } else {
71             return "";
72          }
73       }
74 
75       ///
76       /// Extract the string metadata node \p name.
77       ///
78       inline std::vector<size_t>
get_uint_vector_kernel_metadata(const::llvm::Function & f,const std::string & name)79       get_uint_vector_kernel_metadata(const ::llvm::Function &f,
80                           const std::string &name) {
81          auto operands = detail::get_kernel_metadata_operands(f, name);
82          if (operands.size()) {
83             return map([=](const ::llvm::MDOperand& o) {
84                auto value = ::llvm::cast< ::llvm::ConstantAsMetadata>(o)
85                                                                ->getValue();
86                return ::llvm::cast< ::llvm::ConstantInt>(value)
87                                                 ->getLimitedValue(UINT_MAX);
88             }, operands);
89          } else {
90             return {};
91          }
92       }
93 
94       ///
95       /// Extract the string metadata node \p name.
96       ///
97       inline std::string
get_type_kernel_metadata(const::llvm::Function & f,const std::string & name)98       get_type_kernel_metadata(const ::llvm::Function &f,
99                           const std::string &name) {
100          auto operands = detail::get_kernel_metadata_operands(f, name);
101          if (operands.size()) {
102             auto value = ::llvm::cast< ::llvm::ConstantAsMetadata>(operands[0])
103                                                                ->getValue();
104             auto type = ::llvm::cast< ::llvm::UndefValue>(value)
105                                                                ->getType();
106 
107             value = ::llvm::cast< ::llvm::ConstantAsMetadata>(operands[1])
108                                                                ->getValue();
109             bool is_signed = ::llvm::cast< ::llvm::ConstantInt>(value)
110                                                 ->getLimitedValue(UINT_MAX);
111 
112             std::string data;
113             if (type->isIntOrIntVectorTy()) {
114                if (!is_signed)
115                   data = "unsigned ";
116 
117                const auto size = type->getScalarSizeInBits();
118                switch(size) {
119                   case 8:
120                      data += "char";
121                      break;
122                   case 16:
123                      data += "short";
124                      break;
125                   case 32:
126                      data += "int";
127                      break;
128                   case 64:
129                      data += "long";
130                      break;
131                }
132                if (compat::is_scalable_vector(type))
133                   throw build_error("hit unexpected scalable vector");
134                if (compat::is_fixed_vector(type))
135                   data += std::to_string(compat::get_fixed_vector_elements(type));
136 
137             } else {
138                ::llvm::raw_string_ostream os { data };
139                type->print(os);
140                os.flush();
141             }
142 
143             return data;
144          } else {
145             return "";
146          }
147       }
148 
149       ///
150       /// Extract the string metadata node \p name corresponding to the kernel
151       /// argument given by \p arg.
152       ///
153       inline std::string
get_str_argument_metadata(const::llvm::Function & f,const::llvm::Argument & arg,const std::string & name)154       get_str_argument_metadata(const ::llvm::Function &f,
155                             const ::llvm::Argument &arg,
156                             const std::string &name) {
157          auto operands = detail::get_kernel_metadata_operands(f, name);
158          if (operands.size() > arg.getArgNo()) {
159             return ::llvm::cast< ::llvm::MDString>(operands[arg.getArgNo()])
160                ->getString().str();
161          } else {
162             return "";
163          }
164       }
165 
166       ///
167       /// Extract the int metadata node \p name corresponding to the kernel
168       /// argument given by \p arg.
169       ///
170       inline uint64_t
get_uint_argument_metadata(const::llvm::Function & f,const::llvm::Argument & arg,const std::string & name)171       get_uint_argument_metadata(const ::llvm::Function &f,
172                             const ::llvm::Argument &arg,
173                             const std::string &name) {
174          auto operands = detail::get_kernel_metadata_operands(f, name);
175          if (operands.size() >= arg.getArgNo()) {
176             auto meta_arg_value = ::llvm::cast< ::llvm::ConstantAsMetadata>(
177                operands[arg.getArgNo()])->getValue();
178             return ::llvm::cast< ::llvm::ConstantInt>(meta_arg_value)
179                ->getLimitedValue(UINT_MAX);
180          } else {
181             return 0;
182          }
183       }
184 
185       ///
186       /// Return a vector with all CL kernel functions found in the LLVM
187       /// module \p mod.
188       ///
189       inline std::vector<const ::llvm::Function *>
get_kernels(const::llvm::Module & mod)190       get_kernels(const ::llvm::Module &mod) {
191          std::vector<const ::llvm::Function *> fs;
192 
193          for (auto &f : mod.getFunctionList()) {
194             if (detail::is_kernel(f))
195                fs.push_back(&f);
196          }
197 
198          return fs;
199       }
200    }
201 }
202 
203 #endif
204