17ec681f3Smrg// 27ec681f3Smrg// Copyright 2016 Francisco Jerez 37ec681f3Smrg// 47ec681f3Smrg// Permission is hereby granted, free of charge, to any person obtaining a 57ec681f3Smrg// copy of this software and associated documentation files (the "Software"), 67ec681f3Smrg// to deal in the Software without restriction, including without limitation 77ec681f3Smrg// the rights to use, copy, modify, merge, publish, distribute, sublicense, 87ec681f3Smrg// and/or sell copies of the Software, and to permit persons to whom the 97ec681f3Smrg// Software is furnished to do so, subject to the following conditions: 107ec681f3Smrg// 117ec681f3Smrg// The above copyright notice and this permission notice shall be included in 127ec681f3Smrg// all copies or substantial portions of the Software. 137ec681f3Smrg// 147ec681f3Smrg// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 157ec681f3Smrg// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 167ec681f3Smrg// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 177ec681f3Smrg// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR 187ec681f3Smrg// OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 197ec681f3Smrg// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 207ec681f3Smrg// OTHER DEALINGS IN THE SOFTWARE. 217ec681f3Smrg// 227ec681f3Smrg 237ec681f3Smrg/// 247ec681f3Smrg/// \file 257ec681f3Smrg/// Utility functions for LLVM IR metadata introspection. 267ec681f3Smrg/// 277ec681f3Smrg 287ec681f3Smrg#ifndef CLOVER_LLVM_METADATA_HPP 297ec681f3Smrg#define CLOVER_LLVM_METADATA_HPP 307ec681f3Smrg 317ec681f3Smrg#include "llvm/compat.hpp" 327ec681f3Smrg#include "util/algorithm.hpp" 337ec681f3Smrg 347ec681f3Smrg#include <vector> 357ec681f3Smrg#include <llvm/Config/llvm-config.h> 367ec681f3Smrg#include <llvm/IR/Module.h> 377ec681f3Smrg#include <llvm/IR/Metadata.h> 387ec681f3Smrg 397ec681f3Smrgnamespace clover { 407ec681f3Smrg namespace llvm { 417ec681f3Smrg namespace detail { 427ec681f3Smrg inline bool 437ec681f3Smrg is_kernel(const ::llvm::Function &f) { 447ec681f3Smrg return f.getMetadata("kernel_arg_type"); 457ec681f3Smrg } 467ec681f3Smrg 477ec681f3Smrg inline iterator_range< ::llvm::MDNode::op_iterator> 487ec681f3Smrg get_kernel_metadata_operands(const ::llvm::Function &f, 497ec681f3Smrg const std::string &name) { 507ec681f3Smrg const auto data_node = f.getMetadata(name); 517ec681f3Smrg if (data_node) 527ec681f3Smrg return range(data_node->op_begin(), data_node->op_end()); 537ec681f3Smrg else 547ec681f3Smrg return iterator_range< ::llvm::MDNode::op_iterator>(); 557ec681f3Smrg } 567ec681f3Smrg } 577ec681f3Smrg 587ec681f3Smrg /// 597ec681f3Smrg /// Extract the string metadata node \p name. 607ec681f3Smrg /// 617ec681f3Smrg inline std::string 627ec681f3Smrg get_str_kernel_metadata(const ::llvm::Function &f, 637ec681f3Smrg const std::string &name) { 647ec681f3Smrg auto operands = detail::get_kernel_metadata_operands(f, name); 657ec681f3Smrg if (operands.size()) { 667ec681f3Smrg return ::llvm::cast< ::llvm::MDString>( 677ec681f3Smrg detail::get_kernel_metadata_operands(f, name)[0]) 687ec681f3Smrg ->getString().str(); 697ec681f3Smrg } else { 707ec681f3Smrg return ""; 717ec681f3Smrg } 727ec681f3Smrg } 737ec681f3Smrg 747ec681f3Smrg /// 757ec681f3Smrg /// Extract the string metadata node \p name. 767ec681f3Smrg /// 777ec681f3Smrg inline std::vector<size_t> 787ec681f3Smrg get_uint_vector_kernel_metadata(const ::llvm::Function &f, 797ec681f3Smrg const std::string &name) { 807ec681f3Smrg auto operands = detail::get_kernel_metadata_operands(f, name); 817ec681f3Smrg if (operands.size()) { 827ec681f3Smrg return map([=](const ::llvm::MDOperand& o) { 837ec681f3Smrg auto value = ::llvm::cast< ::llvm::ConstantAsMetadata>(o) 847ec681f3Smrg ->getValue(); 857ec681f3Smrg return ::llvm::cast< ::llvm::ConstantInt>(value) 867ec681f3Smrg ->getLimitedValue(UINT_MAX); 877ec681f3Smrg }, operands); 887ec681f3Smrg } else { 897ec681f3Smrg return {}; 907ec681f3Smrg } 917ec681f3Smrg } 927ec681f3Smrg 937ec681f3Smrg /// 947ec681f3Smrg /// Extract the string metadata node \p name. 957ec681f3Smrg /// 967ec681f3Smrg inline std::string 977ec681f3Smrg get_type_kernel_metadata(const ::llvm::Function &f, 987ec681f3Smrg const std::string &name) { 997ec681f3Smrg auto operands = detail::get_kernel_metadata_operands(f, name); 1007ec681f3Smrg if (operands.size()) { 1017ec681f3Smrg auto value = ::llvm::cast< ::llvm::ConstantAsMetadata>(operands[0]) 1027ec681f3Smrg ->getValue(); 1037ec681f3Smrg auto type = ::llvm::cast< ::llvm::UndefValue>(value) 1047ec681f3Smrg ->getType(); 1057ec681f3Smrg 1067ec681f3Smrg value = ::llvm::cast< ::llvm::ConstantAsMetadata>(operands[1]) 1077ec681f3Smrg ->getValue(); 1087ec681f3Smrg bool is_signed = ::llvm::cast< ::llvm::ConstantInt>(value) 1097ec681f3Smrg ->getLimitedValue(UINT_MAX); 1107ec681f3Smrg 1117ec681f3Smrg std::string data; 1127ec681f3Smrg if (type->isIntOrIntVectorTy()) { 1137ec681f3Smrg if (!is_signed) 1147ec681f3Smrg data = "unsigned "; 1157ec681f3Smrg 1167ec681f3Smrg const auto size = type->getScalarSizeInBits(); 1177ec681f3Smrg switch(size) { 1187ec681f3Smrg case 8: 1197ec681f3Smrg data += "char"; 1207ec681f3Smrg break; 1217ec681f3Smrg case 16: 1227ec681f3Smrg data += "short"; 1237ec681f3Smrg break; 1247ec681f3Smrg case 32: 1257ec681f3Smrg data += "int"; 1267ec681f3Smrg break; 1277ec681f3Smrg case 64: 1287ec681f3Smrg data += "long"; 1297ec681f3Smrg break; 1307ec681f3Smrg } 1317ec681f3Smrg if (compat::is_scalable_vector(type)) 1327ec681f3Smrg throw build_error("hit unexpected scalable vector"); 1337ec681f3Smrg if (compat::is_fixed_vector(type)) 1347ec681f3Smrg data += std::to_string(compat::get_fixed_vector_elements(type)); 1357ec681f3Smrg 1367ec681f3Smrg } else { 1377ec681f3Smrg ::llvm::raw_string_ostream os { data }; 1387ec681f3Smrg type->print(os); 1397ec681f3Smrg os.flush(); 1407ec681f3Smrg } 1417ec681f3Smrg 1427ec681f3Smrg return data; 1437ec681f3Smrg } else { 1447ec681f3Smrg return ""; 1457ec681f3Smrg } 1467ec681f3Smrg } 1477ec681f3Smrg 1487ec681f3Smrg /// 1497ec681f3Smrg /// Extract the string metadata node \p name corresponding to the kernel 1507ec681f3Smrg /// argument given by \p arg. 1517ec681f3Smrg /// 1527ec681f3Smrg inline std::string 1537ec681f3Smrg get_str_argument_metadata(const ::llvm::Function &f, 1547ec681f3Smrg const ::llvm::Argument &arg, 1557ec681f3Smrg const std::string &name) { 1567ec681f3Smrg auto operands = detail::get_kernel_metadata_operands(f, name); 1577ec681f3Smrg if (operands.size() > arg.getArgNo()) { 1587ec681f3Smrg return ::llvm::cast< ::llvm::MDString>(operands[arg.getArgNo()]) 1597ec681f3Smrg ->getString().str(); 1607ec681f3Smrg } else { 1617ec681f3Smrg return ""; 1627ec681f3Smrg } 1637ec681f3Smrg } 1647ec681f3Smrg 1657ec681f3Smrg /// 1667ec681f3Smrg /// Extract the int metadata node \p name corresponding to the kernel 1677ec681f3Smrg /// argument given by \p arg. 1687ec681f3Smrg /// 1697ec681f3Smrg inline uint64_t 1707ec681f3Smrg get_uint_argument_metadata(const ::llvm::Function &f, 1717ec681f3Smrg const ::llvm::Argument &arg, 1727ec681f3Smrg const std::string &name) { 1737ec681f3Smrg auto operands = detail::get_kernel_metadata_operands(f, name); 1747ec681f3Smrg if (operands.size() >= arg.getArgNo()) { 1757ec681f3Smrg auto meta_arg_value = ::llvm::cast< ::llvm::ConstantAsMetadata>( 1767ec681f3Smrg operands[arg.getArgNo()])->getValue(); 1777ec681f3Smrg return ::llvm::cast< ::llvm::ConstantInt>(meta_arg_value) 1787ec681f3Smrg ->getLimitedValue(UINT_MAX); 1797ec681f3Smrg } else { 1807ec681f3Smrg return 0; 1817ec681f3Smrg } 1827ec681f3Smrg } 1837ec681f3Smrg 1847ec681f3Smrg /// 1857ec681f3Smrg /// Return a vector with all CL kernel functions found in the LLVM 1867ec681f3Smrg /// module \p mod. 1877ec681f3Smrg /// 1887ec681f3Smrg inline std::vector<const ::llvm::Function *> 1897ec681f3Smrg get_kernels(const ::llvm::Module &mod) { 1907ec681f3Smrg std::vector<const ::llvm::Function *> fs; 1917ec681f3Smrg 1927ec681f3Smrg for (auto &f : mod.getFunctionList()) { 1937ec681f3Smrg if (detail::is_kernel(f)) 1947ec681f3Smrg fs.push_back(&f); 1957ec681f3Smrg } 1967ec681f3Smrg 1977ec681f3Smrg return fs; 1987ec681f3Smrg } 1997ec681f3Smrg } 2007ec681f3Smrg} 2017ec681f3Smrg 2027ec681f3Smrg#endif 203