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