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 39namespace clover { 40 namespace llvm { 41 namespace detail { 42 inline bool 43 is_kernel(const ::llvm::Function &f) { 44 return f.getMetadata("kernel_arg_type"); 45 } 46 47 inline iterator_range< ::llvm::MDNode::op_iterator> 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 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> 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 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 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 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 *> 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