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