From 3ed31bbf057660909b6a9a20ac240ffad7dd34f0 Mon Sep 17 00:00:00 2001 From: Francisco Jerez Date: Tue, 17 May 2016 16:02:53 +0200 Subject: [PATCH] clover/llvm: Add simplified utility functions for metadata introspection. v2: Fix for latest LLVM from SVN. Reviewed-by: Serge Martin (v1) Tested-by: Jan Vesely --- src/gallium/state_trackers/clover/Makefile.sources | 1 + .../state_trackers/clover/llvm/metadata.hpp | 132 +++++++++++++++++++++ 2 files changed, 133 insertions(+) create mode 100644 src/gallium/state_trackers/clover/llvm/metadata.hpp diff --git a/src/gallium/state_trackers/clover/Makefile.sources b/src/gallium/state_trackers/clover/Makefile.sources index 4b30941..ae9d92c 100644 --- a/src/gallium/state_trackers/clover/Makefile.sources +++ b/src/gallium/state_trackers/clover/Makefile.sources @@ -56,6 +56,7 @@ CPP_SOURCES := \ LLVM_SOURCES := \ llvm/compat.hpp \ llvm/invocation.cpp \ + llvm/metadata.hpp \ llvm/util.hpp TGSI_SOURCES := \ diff --git a/src/gallium/state_trackers/clover/llvm/metadata.hpp b/src/gallium/state_trackers/clover/llvm/metadata.hpp new file mode 100644 index 0000000..814c830 --- /dev/null +++ b/src/gallium/state_trackers/clover/llvm/metadata.hpp @@ -0,0 +1,132 @@ +// +// Copyright 2016 Francisco Jerez +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the "Software"), +// to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, +// and/or sell copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR +// OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +// OTHER DEALINGS IN THE SOFTWARE. +// + +/// +/// \file +/// Utility functions for LLVM IR metadata introspection. +/// + +#ifndef CLOVER_LLVM_METADATA_HPP +#define CLOVER_LLVM_METADATA_HPP + +#include "llvm/compat.hpp" +#include "util/algorithm.hpp" + +#include +#include +#include + +namespace clover { + namespace llvm { + namespace detail { + inline std::vector + get_kernel_nodes(const ::llvm::Module &mod) { + if (const ::llvm::NamedMDNode *n = + mod.getNamedMetadata("opencl.kernels")) + return { n->op_begin(), n->op_end() }; + else + return {}; + } + + inline std::function + is_kernel_node_for(const ::llvm::Function &f) { + return [&](const ::llvm::MDNode *n) { + using ::llvm::mdconst::dyn_extract; + return &f == dyn_extract<::llvm::Function>(n->getOperand(0)); + }; + } + + inline bool + is_kernel(const ::llvm::Function &f) { +#if HAVE_LLVM >= 0x0309 + return f.getMetadata("kernel_arg_type"); +#else + return clover::any_of(is_kernel_node_for(f), + get_kernel_nodes(*f.getParent())); +#endif + } + + inline iterator_range<::llvm::MDNode::op_iterator> + get_kernel_metadata_operands(const ::llvm::Function &f, + const std::string &name) { +#if HAVE_LLVM >= 0x0309 + // On LLVM v3.9+ kernel argument attributes are stored as + // function metadata. + const auto data_node = f.getMetadata(name); + return range(data_node->op_begin(), data_node->op_end()); +#else + using ::llvm::cast; + using ::llvm::dyn_cast; + const auto kernel_node = find(is_kernel_node_for(f), + get_kernel_nodes(*f.getParent())); + + const auto data_node = cast<::llvm::MDNode>( + find([&](const ::llvm::MDOperand &op) { + if (auto m = dyn_cast<::llvm::MDNode>(op)) + if (m->getNumOperands()) + if (auto m_name = dyn_cast<::llvm::MDString>( + m->getOperand(0).get())) + return m_name->getString() == name; + + return false; + }, + kernel_node->operands())); + + // Skip the first operand node which is just the metadata + // attribute name. + return range(data_node->op_begin() + 1, data_node->op_end()); +#endif + } + } + + /// + /// Extract the string metadata node \p name corresponding to the kernel + /// argument given by \p arg. + /// + inline std::string + get_argument_metadata(const ::llvm::Function &f, + const ::llvm::Argument &arg, + const std::string &name) { + return ::llvm::cast<::llvm::MDString>( + detail::get_kernel_metadata_operands(f, name)[arg.getArgNo()]) + ->getString(); + } + + /// + /// Return a vector with all CL kernel functions found in the LLVM + /// module \p mod. + /// + inline std::vector + get_kernels(const ::llvm::Module &mod) { + std::vector fs; + + for (auto &f : mod.getFunctionList()) { + if (detail::is_kernel(f)) + fs.push_back(&f); + } + + return fs; + } + } +} + +#endif -- 2.7.4