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/IR/Module.h> 36 #include <llvm/IR/Metadata.h> 37 38 namespace clover { 39 namespace llvm { 40 namespace detail { 41 inline std::vector<const ::llvm::MDNode *> get_kernel_nodes(const::llvm::Module & mod)42 get_kernel_nodes(const ::llvm::Module &mod) { 43 if (const ::llvm::NamedMDNode *n = 44 mod.getNamedMetadata("opencl.kernels")) 45 return { n->op_begin(), n->op_end() }; 46 else 47 return {}; 48 } 49 50 inline std::function<bool (const ::llvm::MDNode *n)> is_kernel_node_for(const::llvm::Function & f)51 is_kernel_node_for(const ::llvm::Function &f) { 52 return [&](const ::llvm::MDNode *n) { 53 using ::llvm::mdconst::dyn_extract; 54 return &f == dyn_extract< ::llvm::Function>(n->getOperand(0)); 55 }; 56 } 57 58 inline bool is_kernel(const::llvm::Function & f)59 is_kernel(const ::llvm::Function &f) { 60 #if HAVE_LLVM >= 0x0309 61 return f.getMetadata("kernel_arg_type"); 62 #else 63 return clover::any_of(is_kernel_node_for(f), 64 get_kernel_nodes(*f.getParent())); 65 #endif 66 } 67 68 inline iterator_range< ::llvm::MDNode::op_iterator> get_kernel_metadata_operands(const::llvm::Function & f,const std::string & name)69 get_kernel_metadata_operands(const ::llvm::Function &f, 70 const std::string &name) { 71 #if HAVE_LLVM >= 0x0309 72 // On LLVM v3.9+ kernel argument attributes are stored as 73 // function metadata. 74 const auto data_node = f.getMetadata(name); 75 return range(data_node->op_begin(), data_node->op_end()); 76 #else 77 using ::llvm::cast; 78 using ::llvm::dyn_cast; 79 const auto kernel_node = find(is_kernel_node_for(f), 80 get_kernel_nodes(*f.getParent())); 81 82 const auto data_node = cast< ::llvm::MDNode>( 83 find([&](const ::llvm::MDOperand &op) { 84 if (auto m = dyn_cast< ::llvm::MDNode>(op)) 85 if (m->getNumOperands()) 86 if (auto m_name = dyn_cast< ::llvm::MDString>( 87 m->getOperand(0).get())) 88 return m_name->getString() == name; 89 90 return false; 91 }, 92 kernel_node->operands())); 93 94 // Skip the first operand node which is just the metadata 95 // attribute name. 96 return range(data_node->op_begin() + 1, data_node->op_end()); 97 #endif 98 } 99 } 100 101 /// 102 /// Extract the string metadata node \p name corresponding to the kernel 103 /// argument given by \p arg. 104 /// 105 inline std::string get_argument_metadata(const::llvm::Function & f,const::llvm::Argument & arg,const std::string & name)106 get_argument_metadata(const ::llvm::Function &f, 107 const ::llvm::Argument &arg, 108 const std::string &name) { 109 return ::llvm::cast< ::llvm::MDString>( 110 detail::get_kernel_metadata_operands(f, name)[arg.getArgNo()]) 111 ->getString(); 112 } 113 114 /// 115 /// Return a vector with all CL kernel functions found in the LLVM 116 /// module \p mod. 117 /// 118 inline std::vector<const ::llvm::Function *> get_kernels(const::llvm::Module & mod)119 get_kernels(const ::llvm::Module &mod) { 120 std::vector<const ::llvm::Function *> fs; 121 122 for (auto &f : mod.getFunctionList()) { 123 if (detail::is_kernel(f)) 124 fs.push_back(&f); 125 } 126 127 return fs; 128 } 129 } 130 } 131 132 #endif 133