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 (type->isVectorTy()) 132 data += std::to_string(((::llvm::VectorType*)type)->getNumElements()); 133 134 } else { 135 ::llvm::raw_string_ostream os { data }; 136 type->print(os); 137 os.flush(); 138 } 139 140 return data; 141 } else { 142 return ""; 143 } 144 } 145 146 /// 147 /// Extract the string metadata node \p name corresponding to the kernel 148 /// argument given by \p arg. 149 /// 150 inline std::string get_str_argument_metadata(const::llvm::Function & f,const::llvm::Argument & arg,const std::string & name)151 get_str_argument_metadata(const ::llvm::Function &f, 152 const ::llvm::Argument &arg, 153 const std::string &name) { 154 auto operands = detail::get_kernel_metadata_operands(f, name); 155 if (operands.size() > arg.getArgNo()) { 156 return ::llvm::cast< ::llvm::MDString>(operands[arg.getArgNo()]) 157 ->getString().str(); 158 } else { 159 return ""; 160 } 161 } 162 163 /// 164 /// Extract the int metadata node \p name corresponding to the kernel 165 /// argument given by \p arg. 166 /// 167 inline uint get_uint_argument_metadata(const::llvm::Function & f,const::llvm::Argument & arg,const std::string & name)168 get_uint_argument_metadata(const ::llvm::Function &f, 169 const ::llvm::Argument &arg, 170 const std::string &name) { 171 auto operands = detail::get_kernel_metadata_operands(f, name); 172 if (operands.size() >= arg.getArgNo()) { 173 auto meta_arg_value = ::llvm::cast< ::llvm::ConstantAsMetadata>( 174 operands[arg.getArgNo()])->getValue(); 175 return ::llvm::cast< ::llvm::ConstantInt>(meta_arg_value) 176 ->getLimitedValue(UINT_MAX); 177 } else { 178 return 0; 179 } 180 } 181 182 /// 183 /// Return a vector with all CL kernel functions found in the LLVM 184 /// module \p mod. 185 /// 186 inline std::vector<const ::llvm::Function *> get_kernels(const::llvm::Module & mod)187 get_kernels(const ::llvm::Module &mod) { 188 std::vector<const ::llvm::Function *> fs; 189 190 for (auto &f : mod.getFunctionList()) { 191 if (detail::is_kernel(f)) 192 fs.push_back(&f); 193 } 194 195 return fs; 196 } 197 } 198 } 199 200 #endif 201