summaryrefslogtreecommitdiff
path: root/boost/compute/detail/meta_kernel.hpp
diff options
context:
space:
mode:
Diffstat (limited to 'boost/compute/detail/meta_kernel.hpp')
-rw-r--r--boost/compute/detail/meta_kernel.hpp1054
1 files changed, 1054 insertions, 0 deletions
diff --git a/boost/compute/detail/meta_kernel.hpp b/boost/compute/detail/meta_kernel.hpp
new file mode 100644
index 0000000000..7be778b025
--- /dev/null
+++ b/boost/compute/detail/meta_kernel.hpp
@@ -0,0 +1,1054 @@
+//---------------------------------------------------------------------------//
+// Copyright (c) 2013 Kyle Lutz <kyle.r.lutz@gmail.com>
+//
+// Distributed under the Boost Software License, Version 1.0
+// See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt
+//
+// See http://boostorg.github.com/compute for more information.
+//---------------------------------------------------------------------------//
+
+#ifndef BOOST_COMPUTE_DETAIL_META_KERNEL_HPP
+#define BOOST_COMPUTE_DETAIL_META_KERNEL_HPP
+
+#include <set>
+#include <string>
+#include <vector>
+#include <iomanip>
+#include <sstream>
+#include <utility>
+
+#include <boost/tuple/tuple.hpp>
+#include <boost/type_traits.hpp>
+#include <boost/lexical_cast.hpp>
+#include <boost/static_assert.hpp>
+#include <boost/algorithm/string/find.hpp>
+#include <boost/preprocessor/repetition.hpp>
+
+#include <boost/compute/kernel.hpp>
+#include <boost/compute/closure.hpp>
+#include <boost/compute/function.hpp>
+#include <boost/compute/functional.hpp>
+#include <boost/compute/type_traits.hpp>
+#include <boost/compute/command_queue.hpp>
+#include <boost/compute/image/image2d.hpp>
+#include <boost/compute/image/image_sampler.hpp>
+#include <boost/compute/memory_object.hpp>
+#include <boost/compute/detail/device_ptr.hpp>
+#include <boost/compute/detail/sha1.hpp>
+#include <boost/compute/utility/program_cache.hpp>
+
+namespace boost {
+namespace compute {
+namespace detail {
+
+template<class T>
+class meta_kernel_variable
+{
+public:
+ typedef T result_type;
+
+ meta_kernel_variable(const std::string &name)
+ : m_name(name)
+ {
+ }
+
+ meta_kernel_variable(const meta_kernel_variable &other)
+ : m_name(other.m_name)
+ {
+ }
+
+ meta_kernel_variable& operator=(const meta_kernel_variable &other)
+ {
+ if(this != &other){
+ m_name = other.m_name;
+ }
+
+ return *this;
+ }
+
+ ~meta_kernel_variable()
+ {
+ }
+
+ std::string name() const
+ {
+ return m_name;
+ }
+
+private:
+ std::string m_name;
+};
+
+template<class T>
+class meta_kernel_literal
+{
+public:
+ typedef T result_type;
+
+ meta_kernel_literal(const T &value)
+ : m_value(value)
+ {
+ }
+
+ meta_kernel_literal(const meta_kernel_literal &other)
+ : m_value(other.m_value)
+ {
+ }
+
+ meta_kernel_literal& operator=(const meta_kernel_literal &other)
+ {
+ if(this != &other){
+ m_value = other.m_value;
+ }
+
+ return *this;
+ }
+
+ ~meta_kernel_literal()
+ {
+ }
+
+ const T& value() const
+ {
+ return m_value;
+ }
+
+private:
+ T m_value;
+};
+
+struct meta_kernel_stored_arg
+{
+ meta_kernel_stored_arg()
+ : m_size(0),
+ m_value(0)
+ {
+ }
+
+ meta_kernel_stored_arg(const meta_kernel_stored_arg &other)
+ : m_size(0),
+ m_value(0)
+ {
+ set_value(other.m_size, other.m_value);
+ }
+
+ meta_kernel_stored_arg& operator=(const meta_kernel_stored_arg &other)
+ {
+ if(this != &other){
+ set_value(other.m_size, other.m_value);
+ }
+
+ return *this;
+ }
+
+ template<class T>
+ meta_kernel_stored_arg(const T &value)
+ : m_size(0),
+ m_value(0)
+ {
+ set_value(value);
+ }
+
+ ~meta_kernel_stored_arg()
+ {
+ if(m_value){
+ std::free(m_value);
+ }
+ }
+
+ void set_value(size_t size, const void *value)
+ {
+ if(m_value){
+ std::free(m_value);
+ }
+
+ m_size = size;
+
+ if(value){
+ m_value = std::malloc(size);
+ std::memcpy(m_value, value, size);
+ }
+ else {
+ m_value = 0;
+ }
+ }
+
+ template<class T>
+ void set_value(const T &value)
+ {
+ set_value(sizeof(T), boost::addressof(value));
+ }
+
+ size_t m_size;
+ void *m_value;
+};
+
+struct meta_kernel_buffer_info
+{
+ meta_kernel_buffer_info(const buffer &buffer,
+ const std::string &id,
+ memory_object::address_space addr_space,
+ size_t i)
+ : m_mem(buffer.get()),
+ identifier(id),
+ address_space(addr_space),
+ index(i)
+ {
+ }
+
+ cl_mem m_mem;
+ std::string identifier;
+ memory_object::address_space address_space;
+ size_t index;
+};
+
+class meta_kernel;
+
+template<class Type>
+struct inject_type_impl
+{
+ void operator()(meta_kernel &)
+ {
+ // default implementation does nothing
+ }
+};
+
+#define BOOST_COMPUTE_META_KERNEL_DECLARE_SCALAR_TYPE_STREAM_OPERATOR(type) \
+ meta_kernel& operator<<(const type &x) \
+ { \
+ m_source << x; \
+ return *this; \
+ }
+
+#define BOOST_COMPUTE_META_KERNEL_DECLARE_VECTOR_TYPE_STREAM_OPERATOR(type) \
+ meta_kernel& operator<<(const type &x) \
+ { \
+ m_source << "(" << type_name<type>() << ")"; \
+ m_source << "("; \
+ for(size_t i = 0; i < vector_size<type>::value; i++){ \
+ *this << lit(x[i]); \
+ \
+ if(i != vector_size<type>::value - 1){ \
+ m_source << ","; \
+ } \
+ } \
+ m_source << ")"; \
+ return *this; \
+ }
+
+#define BOOST_COMPUTE_META_KERNEL_DECLARE_TYPE_STREAM_OPERATORS(type) \
+ BOOST_COMPUTE_META_KERNEL_DECLARE_SCALAR_TYPE_STREAM_OPERATOR(BOOST_PP_CAT(type, _)) \
+ BOOST_COMPUTE_META_KERNEL_DECLARE_VECTOR_TYPE_STREAM_OPERATOR(BOOST_PP_CAT(BOOST_PP_CAT(type, 2), _)) \
+ BOOST_COMPUTE_META_KERNEL_DECLARE_VECTOR_TYPE_STREAM_OPERATOR(BOOST_PP_CAT(BOOST_PP_CAT(type, 4), _)) \
+ BOOST_COMPUTE_META_KERNEL_DECLARE_VECTOR_TYPE_STREAM_OPERATOR(BOOST_PP_CAT(BOOST_PP_CAT(type, 8), _)) \
+ BOOST_COMPUTE_META_KERNEL_DECLARE_VECTOR_TYPE_STREAM_OPERATOR(BOOST_PP_CAT(BOOST_PP_CAT(type, 16), _))
+
+class meta_kernel
+{
+public:
+ template<class T>
+ class argument
+ {
+ public:
+ argument(const std::string &name, size_t index)
+ : m_name(name),
+ m_index(index)
+ {
+ }
+
+ const std::string &name() const
+ {
+ return m_name;
+ }
+
+ size_t index() const
+ {
+ return m_index;
+ }
+
+ private:
+ std::string m_name;
+ size_t m_index;
+ };
+
+ explicit meta_kernel(const std::string &name)
+ : m_name(name)
+ {
+ }
+
+ meta_kernel(const meta_kernel &other)
+ {
+ m_source.str(other.m_source.str());
+ }
+
+ meta_kernel& operator=(const meta_kernel &other)
+ {
+ if(this != &other){
+ m_source.str(other.m_source.str());
+ }
+
+ return *this;
+ }
+
+ ~meta_kernel()
+ {
+ }
+
+ std::string name() const
+ {
+ return m_name;
+ }
+
+ std::string source() const
+ {
+ std::stringstream stream;
+
+ // add pragmas
+ if(!m_pragmas.empty()){
+ stream << m_pragmas << "\n";
+ }
+
+ // add macros
+ stream << "#define boost_pair_type(t1, t2) _pair_ ## t1 ## _ ## t2 ## _t\n";
+ stream << "#define boost_pair_get(x, n) (n == 0 ? x.first ## x.second)\n";
+ stream << "#define boost_make_pair(t1, x, t2, y) (boost_pair_type(t1, t2)) { x, y }\n";
+ stream << "#define boost_tuple_get(x, n) (x.v ## n)\n";
+
+ // add type declaration source
+ stream << m_type_declaration_source.str() << "\n";
+
+ // add external function source
+ stream << m_external_function_source.str() << "\n";
+
+ // add kernel source
+ stream << "__kernel void " << m_name
+ << "(" << boost::join(m_args, ", ") << ")\n"
+ << "{\n" << m_source.str() << "\n}\n";
+
+ return stream.str();
+ }
+
+ kernel compile(const context &context, const std::string &options = std::string())
+ {
+ // generate the program source
+ std::string source = this->source();
+
+ // generate cache key
+ std::string cache_key = "__boost_meta_kernel_" +
+ static_cast<std::string>(detail::sha1(source));
+
+ // load program cache
+ boost::shared_ptr<program_cache> cache =
+ program_cache::get_global_cache(context);
+
+ // load (or build) program from cache
+ ::boost::compute::program program =
+ cache->get_or_build(cache_key, options, source, context);
+
+ // create kernel
+ ::boost::compute::kernel kernel = program.create_kernel(name());
+
+ // bind stored args
+ for(size_t i = 0; i < m_stored_args.size(); i++){
+ const detail::meta_kernel_stored_arg &arg = m_stored_args[i];
+
+ if(arg.m_size != 0){
+ kernel.set_arg(i, arg.m_size, arg.m_value);
+ }
+ }
+
+ // bind buffer args
+ for(size_t i = 0; i < m_stored_buffers.size(); i++){
+ const detail::meta_kernel_buffer_info &bi = m_stored_buffers[i];
+
+ kernel.set_arg(bi.index, bi.m_mem);
+ }
+
+ return kernel;
+ }
+
+ template<class T>
+ size_t add_arg(const std::string &name)
+ {
+ std::stringstream stream;
+ stream << type<T>() << " " << name;
+
+ // add argument to list
+ m_args.push_back(stream.str());
+
+ // return index
+ return m_args.size() - 1;
+ }
+
+ template<class T>
+ size_t add_arg(memory_object::address_space address_space,
+ const std::string &name)
+ {
+ return add_arg_with_qualifiers<T>(address_space_prefix(address_space), name);
+ }
+
+ template<class T>
+ void set_arg(size_t index, const T &value)
+ {
+ if(index >= m_stored_args.size()){
+ m_stored_args.resize(index + 1);
+ }
+
+ m_stored_args[index] = detail::meta_kernel_stored_arg(value);
+ }
+
+ void set_arg(size_t index, const memory_object &mem)
+ {
+ set_arg<cl_mem>(index, mem.get());
+ }
+
+ void set_arg(size_t index, const image_sampler &sampler)
+ {
+ set_arg<cl_sampler>(index, cl_sampler(sampler));
+ }
+
+ template<class T>
+ size_t add_set_arg(const std::string &name, const T &value)
+ {
+ size_t index = add_arg<T>(name);
+ set_arg<T>(index, value);
+ return index;
+ }
+
+ void add_extension_pragma(const std::string &extension,
+ const std::string &value = "enable")
+ {
+ m_pragmas += "#pragma OPENCL EXTENSION " + extension + " : " + value + "\n";
+ }
+
+ void add_extension_pragma(const std::string &extension,
+ const std::string &value) const
+ {
+ return const_cast<meta_kernel *>(this)->add_extension_pragma(extension, value);
+ }
+
+ template<class T>
+ std::string type() const
+ {
+ std::stringstream stream;
+
+ // const qualifier
+ if(boost::is_const<T>::value){
+ stream << "const ";
+ }
+
+ // volatile qualifier
+ if(boost::is_volatile<T>::value){
+ stream << "volatile ";
+ }
+
+ // type
+ typedef
+ typename boost::remove_cv<
+ typename boost::remove_pointer<T>::type
+ >::type Type;
+ stream << type_name<Type>();
+
+ // pointer
+ if(boost::is_pointer<T>::value){
+ stream << "*";
+ }
+
+ // inject type pragmas and/or definitions
+ inject_type<Type>();
+
+ return stream.str();
+ }
+
+ template<class T>
+ std::string decl(const std::string &name) const
+ {
+ return type<T>() + " " + name;
+ }
+
+ template<class T, class Expr>
+ std::string decl(const std::string &name, const Expr &init) const
+ {
+ meta_kernel tmp((std::string()));
+ tmp << tmp.decl<T>(name) << " = " << init;
+ return tmp.m_source.str();
+ }
+
+ template<class T>
+ detail::meta_kernel_variable<T> var(const std::string &name) const
+ {
+ type<T>();
+
+ return make_var<T>(name);
+ }
+
+ template<class T>
+ detail::meta_kernel_literal<T> lit(const T &value) const
+ {
+ type<T>();
+
+ return detail::meta_kernel_literal<T>(value);
+ }
+
+ template<class T>
+ detail::meta_kernel_variable<T> expr(const std::string &expr) const
+ {
+ type<T>();
+
+ return detail::meta_kernel_variable<T>(expr);
+ }
+
+ // define stream operators for scalar and vector types
+ BOOST_COMPUTE_META_KERNEL_DECLARE_TYPE_STREAM_OPERATORS(char)
+ BOOST_COMPUTE_META_KERNEL_DECLARE_TYPE_STREAM_OPERATORS(uchar)
+ BOOST_COMPUTE_META_KERNEL_DECLARE_TYPE_STREAM_OPERATORS(short)
+ BOOST_COMPUTE_META_KERNEL_DECLARE_TYPE_STREAM_OPERATORS(ushort)
+ BOOST_COMPUTE_META_KERNEL_DECLARE_TYPE_STREAM_OPERATORS(int)
+ BOOST_COMPUTE_META_KERNEL_DECLARE_TYPE_STREAM_OPERATORS(uint)
+ BOOST_COMPUTE_META_KERNEL_DECLARE_TYPE_STREAM_OPERATORS(long)
+ BOOST_COMPUTE_META_KERNEL_DECLARE_TYPE_STREAM_OPERATORS(ulong)
+ BOOST_COMPUTE_META_KERNEL_DECLARE_TYPE_STREAM_OPERATORS(double)
+
+ // define stream operators for float scalar and vector types
+ meta_kernel& operator<<(const float &x)
+ {
+ m_source << std::showpoint << x << 'f';
+ return *this;
+ }
+
+ BOOST_COMPUTE_META_KERNEL_DECLARE_VECTOR_TYPE_STREAM_OPERATOR(float2_)
+ BOOST_COMPUTE_META_KERNEL_DECLARE_VECTOR_TYPE_STREAM_OPERATOR(float4_)
+ BOOST_COMPUTE_META_KERNEL_DECLARE_VECTOR_TYPE_STREAM_OPERATOR(float8_)
+ BOOST_COMPUTE_META_KERNEL_DECLARE_VECTOR_TYPE_STREAM_OPERATOR(float16_)
+
+ // define stream operators for variable types
+ template<class T>
+ meta_kernel& operator<<(const meta_kernel_variable<T> &variable)
+ {
+ return *this << variable.name();
+ }
+
+ // define stream operators for literal types
+ template<class T>
+ meta_kernel& operator<<(const meta_kernel_literal<T> &literal)
+ {
+ return *this << literal.value();
+ }
+
+ meta_kernel& operator<<(const meta_kernel_literal<bool> &literal)
+ {
+ return *this << (literal.value() ? "true" : "false");
+ }
+
+ meta_kernel& operator<<(const meta_kernel_literal<char> &literal)
+ {
+ const char c = literal.value();
+
+ switch(c){
+ // control characters
+ case '\0':
+ return *this << "'\\0'";
+ case '\a':
+ return *this << "'\\a'";
+ case '\b':
+ return *this << "'\\b'";
+ case '\t':
+ return *this << "'\\t'";
+ case '\n':
+ return *this << "'\\n'";
+ case '\v':
+ return *this << "'\\v'";
+ case '\f':
+ return *this << "'\\f'";
+ case '\r':
+ return *this << "'\\r'";
+
+ // characters which need escaping
+ case '\"':
+ case '\'':
+ case '\?':
+ case '\\':
+ return *this << "'\\" << c << "'";
+
+ // all other characters
+ default:
+ return *this << "'" << c << "'";
+ }
+ }
+
+ meta_kernel& operator<<(const meta_kernel_literal<signed char> &literal)
+ {
+ return *this << lit<char>(literal.value());
+ }
+
+ meta_kernel& operator<<(const meta_kernel_literal<unsigned char> &literal)
+ {
+ return *this << uint_(literal.value());
+ }
+
+ // define stream operators for strings
+ meta_kernel& operator<<(char ch)
+ {
+ m_source << ch;
+ return *this;
+ }
+
+ meta_kernel& operator<<(const char *string)
+ {
+ m_source << string;
+ return *this;
+ }
+
+ meta_kernel& operator<<(const std::string &string)
+ {
+ m_source << string;
+ return *this;
+ }
+
+ template<class T>
+ static detail::meta_kernel_variable<T> make_var(const std::string &name)
+ {
+ return detail::meta_kernel_variable<T>(name);
+ }
+
+ template<class T>
+ static detail::meta_kernel_literal<T> make_lit(const T &value)
+ {
+ return detail::meta_kernel_literal<T>(value);
+ }
+
+ template<class T>
+ static detail::meta_kernel_variable<T> make_expr(const std::string &expr)
+ {
+ return detail::meta_kernel_variable<T>(expr);
+ }
+
+ event exec(command_queue &queue)
+ {
+ return exec_1d(queue, 0, 1);
+ }
+
+ event exec_1d(command_queue &queue,
+ size_t global_work_offset,
+ size_t global_work_size)
+ {
+ const context &context = queue.get_context();
+
+ ::boost::compute::kernel kernel = compile(context);
+
+ return queue.enqueue_1d_range_kernel(
+ kernel,
+ global_work_offset,
+ global_work_size,
+ 0
+ );
+ }
+
+ event exec_1d(command_queue &queue,
+ size_t global_work_offset,
+ size_t global_work_size,
+ size_t local_work_size)
+ {
+ const context &context = queue.get_context();
+
+ ::boost::compute::kernel kernel = compile(context);
+
+ return queue.enqueue_1d_range_kernel(
+ kernel,
+ global_work_offset,
+ global_work_size,
+ local_work_size
+ );
+ }
+
+ template<class T>
+ std::string get_buffer_identifier(const buffer &buffer,
+ const memory_object::address_space address_space =
+ memory_object::global_memory)
+ {
+ // check if we've already seen buffer
+ for(size_t i = 0; i < m_stored_buffers.size(); i++){
+ const detail::meta_kernel_buffer_info &bi = m_stored_buffers[i];
+
+ if(bi.m_mem == buffer.get() &&
+ bi.address_space == address_space){
+ return bi.identifier;
+ }
+ }
+
+ // create a new binding
+ std::string identifier =
+ "_buf" + lexical_cast<std::string>(m_stored_buffers.size());
+ size_t index = add_arg<T *>(address_space, identifier);
+
+ // store new buffer info
+ m_stored_buffers.push_back(
+ detail::meta_kernel_buffer_info(buffer, identifier, address_space, index));
+
+ return identifier;
+ }
+
+ std::string get_image_identifier(const char *qualifiers, const image2d &image)
+ {
+ size_t index = add_arg_with_qualifiers<image2d>(qualifiers, "image");
+
+ set_arg(index, image);
+
+ return "image";
+ }
+
+ std::string get_sampler_identifier(bool normalized_coords,
+ cl_addressing_mode addressing_mode,
+ cl_filter_mode filter_mode)
+ {
+ (void) normalized_coords;
+ (void) addressing_mode;
+ (void) filter_mode;
+
+ m_pragmas += "const sampler_t sampler = CLK_NORMALIZED_COORDS_FALSE |\n"
+ " CLK_ADDRESS_NONE |\n"
+ " CLK_FILTER_NEAREST;\n";
+
+ return "sampler";
+ }
+
+ template<class Expr>
+ static std::string expr_to_string(const Expr &expr)
+ {
+ meta_kernel tmp((std::string()));
+ tmp << expr;
+ return tmp.m_source.str();
+ }
+
+ template<class Predicate>
+ detail::invoked_function<bool, boost::tuple<Predicate> > if_(Predicate pred) const
+ {
+ return detail::invoked_function<bool, boost::tuple<Predicate> >(
+ "if", std::string(), boost::make_tuple(pred)
+ );
+ }
+
+ template<class Predicate>
+ detail::invoked_function<bool, boost::tuple<Predicate> > else_if_(Predicate pred) const
+ {
+ return detail::invoked_function<bool, boost::tuple<Predicate> >(
+ "else if", std::string(), boost::make_tuple(pred)
+ );
+ }
+
+ detail::meta_kernel_variable<cl_uint> get_global_id(size_t dim) const
+ {
+ return expr<cl_uint>("get_global_id(" + lexical_cast<std::string>(dim) + ")");
+ }
+
+ void add_function(const std::string &name, const std::string &source)
+ {
+ if(m_external_function_names.count(name)){
+ return;
+ }
+
+ m_external_function_names.insert(name);
+ m_external_function_source << source << "\n";
+ }
+
+ void add_function(const std::string &name,
+ const std::string &source,
+ const std::map<std::string, std::string> &definitions)
+ {
+ typedef std::map<std::string, std::string>::const_iterator iter;
+
+ std::stringstream s;
+
+ // add #define's
+ for(iter i = definitions.begin(); i != definitions.end(); i++){
+ s << "#define " << i->first;
+ if(!i->second.empty()){
+ s << " " << i->second;
+ }
+ s << "\n";
+ }
+
+ s << source << "\n";
+
+ // add #undef's
+ for(iter i = definitions.begin(); i != definitions.end(); i++){
+ s << "#undef " << i->first << "\n";
+ }
+
+ add_function(name, s.str());
+ }
+
+ template<class Type>
+ void add_type_declaration(const std::string &declaration)
+ {
+ const char *name = type_name<Type>();
+
+ // check if the type has already been declared
+ std::string source = m_type_declaration_source.str();
+ if(source.find(name) != std::string::npos){
+ return;
+ }
+
+ m_type_declaration_source << declaration;
+ }
+
+ template<class Type>
+ void inject_type() const
+ {
+ inject_type_impl<Type>()(const_cast<meta_kernel &>(*this));
+ }
+
+ // the insert_function_call() method inserts a call to a function with
+ // the given name tuple of argument values.
+ template<class ArgTuple>
+ void insert_function_call(const std::string &name, const ArgTuple &args)
+ {
+ *this << name << '(';
+ insert_function_call_args(args);
+ *this << ')';
+ }
+
+ // the insert_function_call_args() method takes a tuple of argument values
+ // and inserts them into the source string with a comma in-between each.
+ // this is useful for creating function calls given a tuple of values.
+ void insert_function_call_args(const boost::tuple<>&)
+ {
+ }
+
+ #define BOOST_COMPUTE_META_KERNEL_INSERT_FUNCTION_ARG_TYPE(z, n, unused) \
+ inject_type<BOOST_PP_CAT(T, n)>();
+
+ #define BOOST_COMPUTE_META_KERNEL_STREAM_FUNCTION_ARG(z, n, unused) \
+ << boost::get<BOOST_PP_DEC(n)>(args) << ", "
+
+ #define BOOST_COMPUTE_META_KERNEL_INSERT_FUNCTION_ARGS(z, n, unused) \
+ template<BOOST_PP_ENUM_PARAMS(n, class T)> \
+ void insert_function_call_args( \
+ const boost::tuple<BOOST_PP_ENUM_PARAMS(n, T)> &args \
+ ) \
+ { \
+ BOOST_PP_REPEAT_FROM_TO( \
+ 0, n, BOOST_COMPUTE_META_KERNEL_INSERT_FUNCTION_ARG_TYPE, ~ \
+ ) \
+ *this \
+ BOOST_PP_REPEAT_FROM_TO( \
+ 1, n, BOOST_COMPUTE_META_KERNEL_STREAM_FUNCTION_ARG, ~ \
+ ) \
+ << boost::get<BOOST_PP_DEC(n)>(args); \
+ }
+
+ BOOST_PP_REPEAT_FROM_TO(
+ 1, BOOST_COMPUTE_MAX_ARITY, BOOST_COMPUTE_META_KERNEL_INSERT_FUNCTION_ARGS, ~
+ )
+
+ #undef BOOST_COMPUTE_META_KERNEL_INSERT_FUNCTION_ARG_TYPE
+ #undef BOOST_COMPUTE_META_KERNEL_STREAM_FUNCTION_ARG
+ #undef BOOST_COMPUTE_META_KERNEL_INSERT_FUNCTION_ARGS
+
+ static const char* address_space_prefix(const memory_object::address_space value)
+ {
+ switch(value){
+ case memory_object::global_memory: return "__global";
+ case memory_object::local_memory: return "__local";
+ case memory_object::private_memory: return "__private";
+ case memory_object::constant_memory: return "__constant";
+ };
+
+ return 0; // unreachable
+ }
+
+private:
+ template<class T>
+ size_t add_arg_with_qualifiers(const char *qualifiers, const std::string &name)
+ {
+ size_t index = add_arg<T>(name);
+
+ // update argument type declaration with qualifiers
+ std::stringstream s;
+ s << qualifiers << " " << m_args[index];
+ m_args[index] = s.str();
+
+ return index;
+ }
+
+private:
+ std::string m_name;
+ std::stringstream m_source;
+ std::stringstream m_external_function_source;
+ std::stringstream m_type_declaration_source;
+ std::set<std::string> m_external_function_names;
+ std::vector<std::string> m_args;
+ std::string m_pragmas;
+ std::vector<detail::meta_kernel_stored_arg> m_stored_args;
+ std::vector<detail::meta_kernel_buffer_info> m_stored_buffers;
+};
+
+template<class ResultType, class ArgTuple>
+inline meta_kernel&
+operator<<(meta_kernel &kernel, const invoked_function<ResultType, ArgTuple> &expr)
+{
+ if(!expr.source().empty()){
+ kernel.add_function(expr.name(), expr.source(), expr.definitions());
+ }
+
+ kernel.insert_function_call(expr.name(), expr.args());
+
+ return kernel;
+}
+
+template<class ResultType, class ArgTuple, class CaptureTuple>
+inline meta_kernel&
+operator<<(meta_kernel &kernel,
+ const invoked_closure<ResultType, ArgTuple, CaptureTuple> &expr)
+{
+ if(!expr.source().empty()){
+ kernel.add_function(expr.name(), expr.source(), expr.definitions());
+ }
+
+ kernel << expr.name() << '(';
+ kernel.insert_function_call_args(expr.args());
+ kernel << ", ";
+ kernel.insert_function_call_args(expr.capture());
+ kernel << ')';
+
+ return kernel;
+}
+
+template<class Arg1, class Arg2, class Result>
+inline meta_kernel& operator<<(meta_kernel &kernel,
+ const invoked_binary_operator<Arg1,
+ Arg2,
+ Result> &expr)
+{
+ return kernel << "((" << expr.arg1() << ")"
+ << expr.op()
+ << "(" << expr.arg2() << "))";
+}
+
+template<class T, class IndexExpr>
+inline meta_kernel& operator<<(meta_kernel &kernel,
+ const detail::device_ptr_index_expr<T, IndexExpr> &expr)
+{
+ if(expr.m_index == 0){
+ return kernel <<
+ kernel.get_buffer_identifier<T>(expr.m_buffer) <<
+ '[' << expr.m_expr << ']';
+ }
+ else {
+ return kernel <<
+ kernel.get_buffer_identifier<T>(expr.m_buffer) <<
+ '[' << expr.m_index << "+(" << expr.m_expr << ")]";
+ }
+}
+
+template<class T1, class T2, class IndexExpr>
+inline meta_kernel& operator<<(meta_kernel &kernel,
+ const detail::device_ptr_index_expr<std::pair<T1, T2>, IndexExpr> &expr)
+{
+ typedef std::pair<T1, T2> T;
+
+ if(expr.m_index == 0){
+ return kernel <<
+ kernel.get_buffer_identifier<T>(expr.m_buffer) <<
+ '[' << expr.m_expr << ']';
+ }
+ else {
+ return kernel <<
+ kernel.get_buffer_identifier<T>(expr.m_buffer) <<
+ '[' << expr.m_index << "+(" << expr.m_expr << ")]";
+ }
+}
+
+template<class Predicate, class Arg>
+inline meta_kernel& operator<<(meta_kernel &kernel,
+ const invoked_unary_negate_function<Predicate,
+ Arg> &expr)
+{
+ return kernel << "!(" << expr.pred()(expr.expr()) << ')';
+}
+
+template<class Predicate, class Arg1, class Arg2>
+inline meta_kernel& operator<<(meta_kernel &kernel,
+ const invoked_binary_negate_function<Predicate,
+ Arg1,
+ Arg2> &expr)
+{
+ return kernel << "!(" << expr.pred()(expr.expr1(), expr.expr2()) << ')';
+}
+
+// get<N>() for vector types
+template<size_t N, class Arg, class T>
+inline meta_kernel& operator<<(meta_kernel &kernel,
+ const invoked_get<N, Arg, T> &expr)
+{
+ BOOST_STATIC_ASSERT(N < 16);
+
+ if(N < 10){
+ return kernel << expr.m_arg << ".s" << uint_(N);
+ }
+ else if(N < 16){
+#ifdef _MSC_VER
+# pragma warning(push)
+# pragma warning(disable: 4307)
+#endif
+ return kernel << expr.m_arg << ".s" << char('a' + (N - 10));
+#ifdef _MSC_VER
+# pragma warning(pop)
+#endif
+ }
+
+ return kernel;
+}
+
+template<class T, class Arg>
+inline meta_kernel& operator<<(meta_kernel &kernel,
+ const invoked_field<T, Arg> &expr)
+{
+ return kernel << expr.m_arg << "." << expr.m_field;
+}
+
+template<class T, class Arg>
+inline meta_kernel& operator<<(meta_kernel &k,
+ const invoked_as<T, Arg> &expr)
+{
+ return k << "as_" << type_name<T>() << "(" << expr.m_arg << ")";
+}
+
+template<class T, class Arg>
+inline meta_kernel& operator<<(meta_kernel &k,
+ const invoked_convert<T, Arg> &expr)
+{
+ return k << "convert_" << type_name<T>() << "(" << expr.m_arg << ")";
+}
+
+template<class T, class Arg>
+inline meta_kernel& operator<<(meta_kernel &k,
+ const invoked_identity<T, Arg> &expr)
+{
+ return k << expr.m_arg;
+}
+
+template<>
+struct inject_type_impl<double_>
+{
+ void operator()(meta_kernel &kernel)
+ {
+ kernel.add_extension_pragma("cl_khr_fp64", "enable");
+ }
+};
+
+template<class Scalar, size_t N>
+struct inject_type_impl<vector_type<Scalar, N> >
+{
+ void operator()(meta_kernel &kernel)
+ {
+ kernel.inject_type<Scalar>();
+ }
+};
+
+} // end detail namespace
+} // end compute namespace
+} // end boost namespace
+
+#endif // BOOST_COMPUTE_DETAIL_META_KERNEL_HPP