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