From 1b2bb4b98e53e1da6582e8da9304976af9f17ba8 Mon Sep 17 00:00:00 2001 From: Jakub Szuppe Date: Tue, 20 Sep 2016 18:03:32 +0200 Subject: [PATCH 1/5] Add missing lambda wrappers for builtin funcs --- include/boost/compute/lambda/functional.hpp | 296 ++++++++++++++++++-- test/test_lambda.cpp | 31 +- 2 files changed, 299 insertions(+), 28 deletions(-) diff --git a/include/boost/compute/lambda/functional.hpp b/include/boost/compute/lambda/functional.hpp index dd7190e4d..abe0a8be1 100644 --- a/include/boost/compute/lambda/functional.hpp +++ b/include/boost/compute/lambda/functional.hpp @@ -22,6 +22,11 @@ #include #include +#include +#include +#include +#include + namespace boost { namespace compute { namespace lambda { @@ -29,7 +34,8 @@ namespace lambda { namespace mpl = boost::mpl; namespace proto = boost::proto; -// wraps a unary boolean function +// wraps a unary boolean function whose result type is an int_ when the argument +// type is a scalar, and intN_ if the argument type is a vector of size N #define BOOST_COMPUTE_LAMBDA_WRAP_BOOLEAN_UNARY_FUNCTION(name) \ namespace detail { \ struct BOOST_PP_CAT(name, _func) \ @@ -37,7 +43,12 @@ namespace proto = boost::proto; template \ struct lambda_result \ { \ - typedef int type; \ + typedef typename proto::result_of::child_c::type Arg; \ + typedef typename ::boost::compute::lambda::result_of::type result_type; \ + typedef typename ::boost::compute::make_vector_type< \ + ::boost::compute::int_, \ + ::boost::compute::vector_size::value \ + >::type type; \ }; \ \ template \ @@ -60,7 +71,7 @@ namespace proto = boost::proto; ); \ } -// wraps a unary function who's return type is the same as the argument type +// wraps a unary function whose return type is the same as the argument type #define BOOST_COMPUTE_LAMBDA_WRAP_UNARY_FUNCTION_T(name) \ namespace detail { \ struct BOOST_PP_CAT(name, _func) \ @@ -92,7 +103,79 @@ namespace proto = boost::proto; ); \ } -// wraps a binary function +// wraps a unary function whose result type is the scalar type of the first argument +#define BOOST_COMPUTE_LAMBDA_WRAP_UNARY_FUNCTION_ST(name) \ + namespace detail { \ + struct BOOST_PP_CAT(name, _func) \ + { \ + template \ + struct lambda_result \ + { \ + typedef typename proto::result_of::child_c::type Arg; \ + typedef typename ::boost::compute::lambda::result_of::type result_type; \ + typedef typename ::boost::compute::scalar_type::type type; \ + }; \ + \ + template \ + static void apply(Context &ctx, const Arg &arg) \ + { \ + ctx.stream << #name << "("; \ + proto::eval(arg, ctx); \ + ctx.stream << ")"; \ + } \ + }; \ + } \ + template \ + inline typename proto::result_of::make_expr< \ + proto::tag::function, BOOST_PP_CAT(detail::name, _func), const Arg& \ + >::type const \ + name(const Arg &arg) \ + { \ + return proto::make_expr( \ + BOOST_PP_CAT(detail::name, _func)(), ::boost::ref(arg) \ + ); \ + } + +// wraps a binary boolean function whose result type is an int_ when the first +// argument type is a scalar, and intN_ if the first argument type is a vector +// of size N +#define BOOST_COMPUTE_LAMBDA_WRAP_BOOLEAN_BINARY_FUNCTION(name) \ + namespace detail { \ + struct BOOST_PP_CAT(name, _func) \ + { \ + template \ + struct lambda_result \ + { \ + typedef typename proto::result_of::child_c::type Arg1; \ + typedef typename ::boost::compute::make_vector_type< \ + ::boost::compute::int_, \ + ::boost::compute::vector_size::value \ + >::type type; \ + }; \ + \ + template \ + static void apply(Context &ctx, const Arg1 &arg1, const Arg2 &arg2) \ + { \ + ctx.stream << #name << "("; \ + proto::eval(arg1, ctx); \ + ctx.stream << ", "; \ + proto::eval(arg2, ctx); \ + ctx.stream << ")"; \ + } \ + }; \ + } \ + template \ + inline typename proto::result_of::make_expr< \ + proto::tag::function, BOOST_PP_CAT(detail::name, _func), const Arg1&, const Arg2& \ + >::type const \ + name(const Arg1 &arg1, const Arg2 &arg2) \ + { \ + return proto::make_expr( \ + BOOST_PP_CAT(detail::name, _func)(), ::boost::ref(arg1), ::boost::ref(arg2) \ + ); \ + } + +// wraps a binary function whose result type is the type of the first argument #define BOOST_COMPUTE_LAMBDA_WRAP_BINARY_FUNCTION(name) \ namespace detail { \ struct BOOST_PP_CAT(name, _func) \ @@ -126,6 +209,40 @@ namespace proto = boost::proto; ); \ } +// wraps a binary function whose result type is the type of the second argument +#define BOOST_COMPUTE_LAMBDA_WRAP_BINARY_FUNCTION_2(name) \ + namespace detail { \ + struct BOOST_PP_CAT(name, _func) \ + { \ + template \ + struct lambda_result \ + { \ + typedef typename proto::result_of::child_c::type Arg2; \ + typedef typename ::boost::compute::lambda::result_of::type type; \ + }; \ + \ + template \ + static void apply(Context &ctx, const Arg1 &arg1, const Arg2 &arg2) \ + { \ + ctx.stream << #name << "("; \ + proto::eval(arg1, ctx); \ + ctx.stream << ", "; \ + proto::eval(arg2, ctx); \ + ctx.stream << ")"; \ + } \ + }; \ + } \ + template \ + inline typename proto::result_of::make_expr< \ + proto::tag::function, BOOST_PP_CAT(detail::name, _func), const Arg1&, const Arg2& \ + >::type const \ + name(const Arg1 &arg1, const Arg2 &arg2) \ + { \ + return proto::make_expr( \ + BOOST_PP_CAT(detail::name, _func)(), ::boost::ref(arg1), ::boost::ref(arg2) \ + ); \ + } + // wraps a binary function who's result type is the scalar type of the first argument #define BOOST_COMPUTE_LAMBDA_WRAP_BINARY_FUNCTION_ST(name) \ namespace detail { \ @@ -197,43 +314,172 @@ namespace proto = boost::proto; ); \ } +// wraps a ternary function whose result type is the type of the third argument +#define BOOST_COMPUTE_LAMBDA_WRAP_TERNARY_FUNCTION_3(name) \ + namespace detail { \ + struct BOOST_PP_CAT(name, _func) \ + { \ + template \ + struct lambda_result \ + { \ + typedef typename proto::result_of::child_c::type Arg3; \ + typedef typename ::boost::compute::lambda::result_of::type type; \ + }; \ + \ + template \ + static void apply(Context &ctx, const Arg1 &arg1, const Arg2 &arg2, const Arg3 &arg3) \ + { \ + ctx.stream << #name << "("; \ + proto::eval(arg1, ctx); \ + ctx.stream << ", "; \ + proto::eval(arg2, ctx); \ + ctx.stream << ", "; \ + proto::eval(arg3, ctx); \ + ctx.stream << ")"; \ + } \ + }; \ + } \ + template \ + inline typename proto::result_of::make_expr< \ + proto::tag::function, BOOST_PP_CAT(detail::name, _func), const Arg1&, const Arg2&, const Arg3& \ + >::type const \ + name(const Arg1 &arg1, const Arg2 &arg2, const Arg3 &arg3) \ + { \ + return proto::make_expr( \ + BOOST_PP_CAT(detail::name, _func)(), ::boost::ref(arg1), ::boost::ref(arg2), ::boost::ref(arg3) \ + ); \ + } + +// Common Built-In Functions +BOOST_COMPUTE_LAMBDA_WRAP_TERNARY_FUNCTION(clamp) +BOOST_COMPUTE_LAMBDA_WRAP_UNARY_FUNCTION_T(degrees) +BOOST_COMPUTE_LAMBDA_WRAP_BINARY_FUNCTION(min) +BOOST_COMPUTE_LAMBDA_WRAP_BINARY_FUNCTION(max) +BOOST_COMPUTE_LAMBDA_WRAP_TERNARY_FUNCTION(mix) +BOOST_COMPUTE_LAMBDA_WRAP_UNARY_FUNCTION_T(radians) +BOOST_COMPUTE_LAMBDA_WRAP_UNARY_FUNCTION_T(sign) +BOOST_COMPUTE_LAMBDA_WRAP_BINARY_FUNCTION_2(step) +BOOST_COMPUTE_LAMBDA_WRAP_TERNARY_FUNCTION_3(smoothstep) -BOOST_COMPUTE_LAMBDA_WRAP_BOOLEAN_UNARY_FUNCTION(all) -BOOST_COMPUTE_LAMBDA_WRAP_BOOLEAN_UNARY_FUNCTION(any) -BOOST_COMPUTE_LAMBDA_WRAP_BOOLEAN_UNARY_FUNCTION(isinf) -BOOST_COMPUTE_LAMBDA_WRAP_BOOLEAN_UNARY_FUNCTION(isnan) -BOOST_COMPUTE_LAMBDA_WRAP_BOOLEAN_UNARY_FUNCTION(isfinite) +// Geometric Built-In Functions +BOOST_COMPUTE_LAMBDA_WRAP_BINARY_FUNCTION(cross) +BOOST_COMPUTE_LAMBDA_WRAP_BINARY_FUNCTION_ST(dot) +BOOST_COMPUTE_LAMBDA_WRAP_BINARY_FUNCTION_ST(distance) +BOOST_COMPUTE_LAMBDA_WRAP_UNARY_FUNCTION_ST(length) +BOOST_COMPUTE_LAMBDA_WRAP_UNARY_FUNCTION_T(normalize) +BOOST_COMPUTE_LAMBDA_WRAP_BINARY_FUNCTION_ST(fast_distance) +BOOST_COMPUTE_LAMBDA_WRAP_UNARY_FUNCTION_ST(fast_length) +BOOST_COMPUTE_LAMBDA_WRAP_UNARY_FUNCTION_T(fast_normalize) +// Integer Built-In Functions BOOST_COMPUTE_LAMBDA_WRAP_UNARY_FUNCTION_T(abs) -BOOST_COMPUTE_LAMBDA_WRAP_UNARY_FUNCTION_T(cos) +BOOST_COMPUTE_LAMBDA_WRAP_BINARY_FUNCTION(abs_diff) +BOOST_COMPUTE_LAMBDA_WRAP_BINARY_FUNCTION(add_sat) +BOOST_COMPUTE_LAMBDA_WRAP_BINARY_FUNCTION(hadd) +BOOST_COMPUTE_LAMBDA_WRAP_BINARY_FUNCTION(rhadd) +BOOST_COMPUTE_LAMBDA_WRAP_UNARY_FUNCTION_T(clz) +#ifdef CL_VERSION_2_0 +BOOST_COMPUTE_LAMBDA_WRAP_UNARY_FUNCTION_T(ctz) +#endif +// clamp() (since 1.1) already defined in common +BOOST_COMPUTE_LAMBDA_WRAP_TERNARY_FUNCTION(mad_hi) +BOOST_COMPUTE_LAMBDA_WRAP_TERNARY_FUNCTION(mad24) +BOOST_COMPUTE_LAMBDA_WRAP_TERNARY_FUNCTION(mad_sat) +// max() and min() functions are defined in common +BOOST_COMPUTE_LAMBDA_WRAP_BINARY_FUNCTION(mul_hi) +BOOST_COMPUTE_LAMBDA_WRAP_BINARY_FUNCTION(mul24) +BOOST_COMPUTE_LAMBDA_WRAP_BINARY_FUNCTION(rotate) +BOOST_COMPUTE_LAMBDA_WRAP_BINARY_FUNCTION(sub_sat) +BOOST_COMPUTE_LAMBDA_WRAP_BINARY_FUNCTION(upsample) +#ifdef CL_VERSION_1_2 +BOOST_COMPUTE_LAMBDA_WRAP_UNARY_FUNCTION_T(popcount) +#endif + +// Math Built-In Functions BOOST_COMPUTE_LAMBDA_WRAP_UNARY_FUNCTION_T(acos) -BOOST_COMPUTE_LAMBDA_WRAP_UNARY_FUNCTION_T(sin) +BOOST_COMPUTE_LAMBDA_WRAP_UNARY_FUNCTION_T(acosh) +BOOST_COMPUTE_LAMBDA_WRAP_UNARY_FUNCTION_T(acospi) BOOST_COMPUTE_LAMBDA_WRAP_UNARY_FUNCTION_T(asin) -BOOST_COMPUTE_LAMBDA_WRAP_UNARY_FUNCTION_T(tan) +BOOST_COMPUTE_LAMBDA_WRAP_UNARY_FUNCTION_T(asinh) +BOOST_COMPUTE_LAMBDA_WRAP_UNARY_FUNCTION_T(asinpi) BOOST_COMPUTE_LAMBDA_WRAP_UNARY_FUNCTION_T(atan) -BOOST_COMPUTE_LAMBDA_WRAP_UNARY_FUNCTION_T(sqrt) -BOOST_COMPUTE_LAMBDA_WRAP_UNARY_FUNCTION_T(rsqrt) +BOOST_COMPUTE_LAMBDA_WRAP_BINARY_FUNCTION(atan2) +BOOST_COMPUTE_LAMBDA_WRAP_UNARY_FUNCTION_T(atanh) +BOOST_COMPUTE_LAMBDA_WRAP_UNARY_FUNCTION_T(atanpi) +BOOST_COMPUTE_LAMBDA_WRAP_BINARY_FUNCTION(atan2pi) +BOOST_COMPUTE_LAMBDA_WRAP_UNARY_FUNCTION_T(cbrt) +BOOST_COMPUTE_LAMBDA_WRAP_UNARY_FUNCTION_T(ceil) +BOOST_COMPUTE_LAMBDA_WRAP_BINARY_FUNCTION(copysign) +BOOST_COMPUTE_LAMBDA_WRAP_UNARY_FUNCTION_T(cos) +BOOST_COMPUTE_LAMBDA_WRAP_UNARY_FUNCTION_T(cosh) +BOOST_COMPUTE_LAMBDA_WRAP_UNARY_FUNCTION_T(cospi) +BOOST_COMPUTE_LAMBDA_WRAP_UNARY_FUNCTION_T(erfc) +BOOST_COMPUTE_LAMBDA_WRAP_UNARY_FUNCTION_T(erf) BOOST_COMPUTE_LAMBDA_WRAP_UNARY_FUNCTION_T(exp) BOOST_COMPUTE_LAMBDA_WRAP_UNARY_FUNCTION_T(exp2) BOOST_COMPUTE_LAMBDA_WRAP_UNARY_FUNCTION_T(exp10) +BOOST_COMPUTE_LAMBDA_WRAP_UNARY_FUNCTION_T(expm1) +BOOST_COMPUTE_LAMBDA_WRAP_UNARY_FUNCTION_T(fabs) +BOOST_COMPUTE_LAMBDA_WRAP_BINARY_FUNCTION(fdim) +BOOST_COMPUTE_LAMBDA_WRAP_UNARY_FUNCTION_T(floor) +BOOST_COMPUTE_LAMBDA_WRAP_TERNARY_FUNCTION(fma) +BOOST_COMPUTE_LAMBDA_WRAP_BINARY_FUNCTION(fmax) +BOOST_COMPUTE_LAMBDA_WRAP_BINARY_FUNCTION(fmin) +BOOST_COMPUTE_LAMBDA_WRAP_BINARY_FUNCTION(fmod) +BOOST_COMPUTE_LAMBDA_WRAP_BINARY_FUNCTION(hypot) +BOOST_COMPUTE_LAMBDA_WRAP_BOOLEAN_BINARY_FUNCTION(ilogb) // ilogb returns intN_ +BOOST_COMPUTE_LAMBDA_WRAP_BINARY_FUNCTION(ldexp) +BOOST_COMPUTE_LAMBDA_WRAP_UNARY_FUNCTION_T(lgamma) BOOST_COMPUTE_LAMBDA_WRAP_UNARY_FUNCTION_T(log) BOOST_COMPUTE_LAMBDA_WRAP_UNARY_FUNCTION_T(log2) BOOST_COMPUTE_LAMBDA_WRAP_UNARY_FUNCTION_T(log10) -BOOST_COMPUTE_LAMBDA_WRAP_UNARY_FUNCTION_T(round) -BOOST_COMPUTE_LAMBDA_WRAP_UNARY_FUNCTION_T(length) - -BOOST_COMPUTE_LAMBDA_WRAP_BINARY_FUNCTION(cross) +BOOST_COMPUTE_LAMBDA_WRAP_UNARY_FUNCTION_T(log1p) +BOOST_COMPUTE_LAMBDA_WRAP_UNARY_FUNCTION_T(logb) +BOOST_COMPUTE_LAMBDA_WRAP_TERNARY_FUNCTION(mad) +#ifdef CL_VERSION_1_1 +BOOST_COMPUTE_LAMBDA_WRAP_BINARY_FUNCTION(maxmag) +BOOST_COMPUTE_LAMBDA_WRAP_BINARY_FUNCTION(minmag) +#endif +BOOST_COMPUTE_LAMBDA_WRAP_UNARY_FUNCTION_T(nan) +BOOST_COMPUTE_LAMBDA_WRAP_BINARY_FUNCTION(nextafter) BOOST_COMPUTE_LAMBDA_WRAP_BINARY_FUNCTION(pow) BOOST_COMPUTE_LAMBDA_WRAP_BINARY_FUNCTION(pown) BOOST_COMPUTE_LAMBDA_WRAP_BINARY_FUNCTION(powr) +BOOST_COMPUTE_LAMBDA_WRAP_BINARY_FUNCTION(remainder) +BOOST_COMPUTE_LAMBDA_WRAP_UNARY_FUNCTION_T(rint) +BOOST_COMPUTE_LAMBDA_WRAP_UNARY_FUNCTION_T(rootn) +BOOST_COMPUTE_LAMBDA_WRAP_UNARY_FUNCTION_T(round) +BOOST_COMPUTE_LAMBDA_WRAP_UNARY_FUNCTION_T(rsqrt) +BOOST_COMPUTE_LAMBDA_WRAP_UNARY_FUNCTION_T(sin) +BOOST_COMPUTE_LAMBDA_WRAP_UNARY_FUNCTION_T(sincos) +BOOST_COMPUTE_LAMBDA_WRAP_UNARY_FUNCTION_T(sinh) +BOOST_COMPUTE_LAMBDA_WRAP_UNARY_FUNCTION_T(sinpi) +BOOST_COMPUTE_LAMBDA_WRAP_UNARY_FUNCTION_T(sqrt) +BOOST_COMPUTE_LAMBDA_WRAP_UNARY_FUNCTION_T(tan) +BOOST_COMPUTE_LAMBDA_WRAP_UNARY_FUNCTION_T(tanh) +BOOST_COMPUTE_LAMBDA_WRAP_UNARY_FUNCTION_T(tanpi) +BOOST_COMPUTE_LAMBDA_WRAP_UNARY_FUNCTION_T(tgamma) +BOOST_COMPUTE_LAMBDA_WRAP_UNARY_FUNCTION_T(trunc) -BOOST_COMPUTE_LAMBDA_WRAP_BINARY_FUNCTION_ST(dot) -BOOST_COMPUTE_LAMBDA_WRAP_BINARY_FUNCTION_ST(distance) - -BOOST_COMPUTE_LAMBDA_WRAP_TERNARY_FUNCTION(clamp) -BOOST_COMPUTE_LAMBDA_WRAP_TERNARY_FUNCTION(fma) -BOOST_COMPUTE_LAMBDA_WRAP_TERNARY_FUNCTION(mad) -BOOST_COMPUTE_LAMBDA_WRAP_TERNARY_FUNCTION(smoothstep) +// Relational Built-In Functions +BOOST_COMPUTE_LAMBDA_WRAP_BOOLEAN_BINARY_FUNCTION(isequal) +BOOST_COMPUTE_LAMBDA_WRAP_BOOLEAN_BINARY_FUNCTION(isnotequal) +BOOST_COMPUTE_LAMBDA_WRAP_BOOLEAN_BINARY_FUNCTION(isgreater) +BOOST_COMPUTE_LAMBDA_WRAP_BOOLEAN_BINARY_FUNCTION(isgreaterequal) +BOOST_COMPUTE_LAMBDA_WRAP_BOOLEAN_BINARY_FUNCTION(isless) +BOOST_COMPUTE_LAMBDA_WRAP_BOOLEAN_BINARY_FUNCTION(islessequal) +BOOST_COMPUTE_LAMBDA_WRAP_BOOLEAN_BINARY_FUNCTION(islessgreater) +BOOST_COMPUTE_LAMBDA_WRAP_BOOLEAN_UNARY_FUNCTION(isfinite) +BOOST_COMPUTE_LAMBDA_WRAP_BOOLEAN_UNARY_FUNCTION(isinf) +BOOST_COMPUTE_LAMBDA_WRAP_BOOLEAN_UNARY_FUNCTION(isnan) +BOOST_COMPUTE_LAMBDA_WRAP_BOOLEAN_UNARY_FUNCTION(isnormal) +BOOST_COMPUTE_LAMBDA_WRAP_BOOLEAN_BINARY_FUNCTION(isordered) +BOOST_COMPUTE_LAMBDA_WRAP_BOOLEAN_BINARY_FUNCTION(isunordered) +BOOST_COMPUTE_LAMBDA_WRAP_BOOLEAN_UNARY_FUNCTION(singbit) +BOOST_COMPUTE_LAMBDA_WRAP_BOOLEAN_UNARY_FUNCTION(all) +BOOST_COMPUTE_LAMBDA_WRAP_BOOLEAN_UNARY_FUNCTION(any) +BOOST_COMPUTE_LAMBDA_WRAP_TERNARY_FUNCTION(bitselect) +BOOST_COMPUTE_LAMBDA_WRAP_TERNARY_FUNCTION(select) } // end lambda namespace } // end compute namespace diff --git a/test/test_lambda.cpp b/test/test_lambda.cpp index 03ffff454..61ce36375 100644 --- a/test/test_lambda.cpp +++ b/test/test_lambda.cpp @@ -127,15 +127,18 @@ BOOST_AUTO_TEST_CASE(result_of) namespace proto = ::boost::proto; - check_lambda_result(proto::lit(1)); - check_lambda_result(proto::lit(1) + 2); + using boost::compute::int_; + + check_lambda_result(proto::lit(1)); + check_lambda_result(proto::lit(1) + 2); check_lambda_result(proto::lit(1.2f)); check_lambda_result(proto::lit(1) + 1.2f); check_lambda_result(proto::lit(1) / 2 + 1.2f); using boost::compute::float4_; + using boost::compute::int4_; - check_lambda_result(_1, int(1)); + check_lambda_result(_1, int_(1)); check_lambda_result(_1, float(1.2f)); check_lambda_result(_1, float4_(1, 2, 3, 4)); check_lambda_result(2.0f * _1, float4_(1, 2, 3, 4)); @@ -146,9 +149,31 @@ BOOST_AUTO_TEST_CASE(result_of) check_lambda_result(distance(_1, _2), float4_(0, 1, 2, 3), float4_(3, 2, 1, 0)); check_lambda_result(distance(_1, float4_(3, 2, 1, 0)), float4_(0, 1, 2, 3)); + check_lambda_result(length(_1), float4_(3, 2, 1, 0)); + check_lambda_result(cross(_1, _2), float4_(0, 1, 2, 3), float4_(3, 2, 1, 0)); check_lambda_result(cross(_1, float4_(3, 2, 1, 0)), float4_(0, 1, 2, 3)); + check_lambda_result(max(_1, _2), float4_(3, 2, 1, 0), float4_(0, 1, 2, 3)); + check_lambda_result(max(_1, float(1.0f)), float4_(0, 1, 2, 3)); + check_lambda_result(max(_1, int4_(3, 2, 1, 0)), int4_(0, 1, 2, 3)); + check_lambda_result(max(_1, int_(1)), int4_(0, 1, 2, 3)); + check_lambda_result(min(_1, float4_(3, 2, 1, 0)), float4_(0, 1, 2, 3)); + + check_lambda_result(step(_1, _2), float4_(3, 2, 1, 0), float4_(0, 1, 2, 3)); + check_lambda_result(step(_1, _2), float(3.0f), int4_(0, 1, 2, 3)); + + check_lambda_result( + smoothstep(_1, _2, _3), + float4_(3, 2, 1, 0), float4_(3, 2, 1, 0), float4_(0, 1, 2, 3) + ); + check_lambda_result( + smoothstep(_1, _2, _3), + float(2.0f), float(3.0f), int4_(0, 1, 2, 3) + ); + + check_lambda_result(isinf(_1), float4_(0, 1, 2, 3)); + check_lambda_result(_1 + 2, int(2)); check_lambda_result(_1 + 2, float(2.2f)); From 131953bf94eff5a5ed4f62ca4994fba4ba215b52 Mon Sep 17 00:00:00 2001 From: Jakub Szuppe Date: Sat, 24 Sep 2016 17:22:30 +0200 Subject: [PATCH 2/5] Add macro for checking collections of real numbers --- test/check_macros.hpp | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/test/check_macros.hpp b/test/check_macros.hpp index a115e6a93..f3e609eda 100644 --- a/test/check_macros.hpp +++ b/test/check_macros.hpp @@ -30,6 +30,38 @@ ); \ } +template +inline void +equal_close_impl(Left left_begin, + Left left_end, + Right right_begin, + Right right_end, + ToleranceBaseType tolerance) +{ + for(; left_begin != (left_end); ++left_begin, ++right_begin) { + BOOST_CHECK_CLOSE(*left_begin, *right_begin, tolerance); \ + } +} + +#define BOOST_COMPUTE_TEST_CHECK_CLOSE_COLLECTIONS(L_begin, L_end, R_begin, R_end, tolerance) \ + { \ + equal_close_impl(L_begin, L_end, R_begin, R_end, tolerance); \ + } + +#define CHECK_RANGE_CLOSE(type, size, actual, expected, tolerance) \ + { \ + type _actual[size]; \ + boost::compute::copy( \ + actual.begin(), actual.begin()+size, _actual, queue \ + ); \ + const type _expected[size] = { \ + BOOST_PP_REPEAT(size, LIST_ARRAY_VALUES, (size, expected)) \ + }; \ + BOOST_COMPUTE_TEST_CHECK_CLOSE_COLLECTIONS( \ + _actual, _actual + size, _expected, _expected + size, tolerance \ + ); \ + } + #define CHECK_HOST_RANGE_EQUAL(type, size, actual, expected) \ { \ const type _expected[size] = { \ From 6f704003f1b0792b2545535131b3625b6a6b3be8 Mon Sep 17 00:00:00 2001 From: Jakub Szuppe Date: Sat, 24 Sep 2016 17:23:00 +0200 Subject: [PATCH 3/5] Add wrappers for OpenCL builtin funs with ptrs --- include/boost/compute/lambda/functional.hpp | 77 +++++++++++++++++++++ test/test_lambda.cpp | 51 ++++++++++++++ 2 files changed, 128 insertions(+) diff --git a/include/boost/compute/lambda/functional.hpp b/include/boost/compute/lambda/functional.hpp index abe0a8be1..180df3428 100644 --- a/include/boost/compute/lambda/functional.hpp +++ b/include/boost/compute/lambda/functional.hpp @@ -278,6 +278,41 @@ namespace proto = boost::proto; ); \ } +// wraps a binary function whose result type is the type of the first argument +// and the second argument is a pointer +#define BOOST_COMPUTE_LAMBDA_WRAP_BINARY_FUNCTION_PTR(name) \ + namespace detail { \ + struct BOOST_PP_CAT(name, _func) \ + { \ + template \ + struct lambda_result \ + { \ + typedef typename proto::result_of::child_c::type Arg1; \ + typedef typename ::boost::compute::lambda::result_of::type type; \ + }; \ + \ + template \ + static void apply(Context &ctx, const Arg1 &arg1, const Arg2 &arg2) \ + { \ + ctx.stream << #name << "("; \ + proto::eval(arg1, ctx); \ + ctx.stream << ", &"; \ + proto::eval(arg2, ctx); \ + ctx.stream << ")"; \ + } \ + }; \ + } \ + template \ + inline typename proto::result_of::make_expr< \ + proto::tag::function, BOOST_PP_CAT(detail::name, _func), const Arg1&, const Arg2& \ + >::type const \ + name(const Arg1 &arg1, const Arg2 &arg2) \ + { \ + return proto::make_expr( \ + BOOST_PP_CAT(detail::name, _func)(), ::boost::ref(arg1), ::boost::ref(arg2) \ + ); \ + } + // wraps a ternary function #define BOOST_COMPUTE_LAMBDA_WRAP_TERNARY_FUNCTION(name) \ namespace detail { \ @@ -350,6 +385,43 @@ namespace proto = boost::proto; ); \ } +// wraps a ternary function whose result type is the type of the first argument +// and the third argument of the function is a pointer +#define BOOST_COMPUTE_LAMBDA_WRAP_TERNARY_FUNCTION_PTR(name) \ + namespace detail { \ + struct BOOST_PP_CAT(name, _func) \ + { \ + template \ + struct lambda_result \ + { \ + typedef typename proto::result_of::child_c::type Arg3; \ + typedef typename ::boost::compute::lambda::result_of::type type; \ + }; \ + \ + template \ + static void apply(Context &ctx, const Arg1 &arg1, const Arg2 &arg2, const Arg3 &arg3) \ + { \ + ctx.stream << #name << "("; \ + proto::eval(arg1, ctx); \ + ctx.stream << ", "; \ + proto::eval(arg2, ctx); \ + ctx.stream << ", &"; \ + proto::eval(arg3, ctx); \ + ctx.stream << ")"; \ + } \ + }; \ + } \ + template \ + inline typename proto::result_of::make_expr< \ + proto::tag::function, BOOST_PP_CAT(detail::name, _func), const Arg1&, const Arg2&, const Arg3& \ + >::type const \ + name(const Arg1 &arg1, const Arg2 &arg2, const Arg3 &arg3) \ + { \ + return proto::make_expr( \ + BOOST_PP_CAT(detail::name, _func)(), ::boost::ref(arg1), ::boost::ref(arg2), ::boost::ref(arg3) \ + ); \ + } + // Common Built-In Functions BOOST_COMPUTE_LAMBDA_WRAP_TERNARY_FUNCTION(clamp) BOOST_COMPUTE_LAMBDA_WRAP_UNARY_FUNCTION_T(degrees) @@ -426,10 +498,13 @@ BOOST_COMPUTE_LAMBDA_WRAP_TERNARY_FUNCTION(fma) BOOST_COMPUTE_LAMBDA_WRAP_BINARY_FUNCTION(fmax) BOOST_COMPUTE_LAMBDA_WRAP_BINARY_FUNCTION(fmin) BOOST_COMPUTE_LAMBDA_WRAP_BINARY_FUNCTION(fmod) +BOOST_COMPUTE_LAMBDA_WRAP_BINARY_FUNCTION_PTR(fract) +BOOST_COMPUTE_LAMBDA_WRAP_BINARY_FUNCTION_PTR(frexp) BOOST_COMPUTE_LAMBDA_WRAP_BINARY_FUNCTION(hypot) BOOST_COMPUTE_LAMBDA_WRAP_BOOLEAN_BINARY_FUNCTION(ilogb) // ilogb returns intN_ BOOST_COMPUTE_LAMBDA_WRAP_BINARY_FUNCTION(ldexp) BOOST_COMPUTE_LAMBDA_WRAP_UNARY_FUNCTION_T(lgamma) +BOOST_COMPUTE_LAMBDA_WRAP_BINARY_FUNCTION_PTR(lgamma_r) BOOST_COMPUTE_LAMBDA_WRAP_UNARY_FUNCTION_T(log) BOOST_COMPUTE_LAMBDA_WRAP_UNARY_FUNCTION_T(log2) BOOST_COMPUTE_LAMBDA_WRAP_UNARY_FUNCTION_T(log10) @@ -440,12 +515,14 @@ BOOST_COMPUTE_LAMBDA_WRAP_TERNARY_FUNCTION(mad) BOOST_COMPUTE_LAMBDA_WRAP_BINARY_FUNCTION(maxmag) BOOST_COMPUTE_LAMBDA_WRAP_BINARY_FUNCTION(minmag) #endif +BOOST_COMPUTE_LAMBDA_WRAP_BINARY_FUNCTION_PTR(modf) BOOST_COMPUTE_LAMBDA_WRAP_UNARY_FUNCTION_T(nan) BOOST_COMPUTE_LAMBDA_WRAP_BINARY_FUNCTION(nextafter) BOOST_COMPUTE_LAMBDA_WRAP_BINARY_FUNCTION(pow) BOOST_COMPUTE_LAMBDA_WRAP_BINARY_FUNCTION(pown) BOOST_COMPUTE_LAMBDA_WRAP_BINARY_FUNCTION(powr) BOOST_COMPUTE_LAMBDA_WRAP_BINARY_FUNCTION(remainder) +BOOST_COMPUTE_LAMBDA_WRAP_TERNARY_FUNCTION_PTR(remquo) BOOST_COMPUTE_LAMBDA_WRAP_UNARY_FUNCTION_T(rint) BOOST_COMPUTE_LAMBDA_WRAP_UNARY_FUNCTION_T(rootn) BOOST_COMPUTE_LAMBDA_WRAP_UNARY_FUNCTION_T(round) diff --git a/test/test_lambda.cpp b/test/test_lambda.cpp index 61ce36375..0e13a9b37 100644 --- a/test/test_lambda.cpp +++ b/test/test_lambda.cpp @@ -247,6 +247,57 @@ BOOST_AUTO_TEST_CASE(make_function_from_binary_lamdba) CHECK_RANGE_EQUAL(int, 5, result, (8, 4, 0, 4, 8)); } +BOOST_AUTO_TEST_CASE(lambda_binary_function_with_pointer_modf) +{ + using boost::compute::lambda::_1; + using boost::compute::lambda::_2; + using boost::compute::lambda::abs; + + bc::float_ data1[] = { 2.2f, 4.2f, 6.3f, 8.3f, 10.2f }; + compute::vector vec1(data1, data1 + 5, queue); + compute::vector vec2(size_t(5), context); + compute::vector result(5, context); + + compute::transform( + bc::make_transform_iterator(vec1.begin(), _1 + 0.01f), + bc::make_transform_iterator(vec1.end(), _1 + 0.01f), + vec2.begin(), + result.begin(), + bc::lambda::modf(_1, _2), + queue + ); + CHECK_RANGE_CLOSE(bc::float_, 5, result, (0.21f, 0.21f, 0.31f, 0.31f, 0.21f), 0.01f); + CHECK_RANGE_CLOSE(bc::float_, 5, vec2, (2, 4, 6, 8, 10), 0.01f); +} + +BOOST_AUTO_TEST_CASE(lambda_tenary_function_with_pointer_remquo) +{ + using boost::compute::lambda::_1; + using boost::compute::lambda::_2; + using boost::compute::lambda::get; + + bc::float_ data1[] = { 2.2f, 4.2f, 6.3f, 8.3f, 10.2f }; + bc::float_ data2[] = { 4.4f, 4.2f, 6.3f, 16.6f, 10.2f }; + compute::vector vec1(data1, data1 + 5, queue); + compute::vector vec2(data2, data2 + 5, queue); + compute::vector vec3(size_t(5), context); + compute::vector result(5, context); + + compute::transform( + compute::make_zip_iterator( + boost::make_tuple(vec1.begin(), vec2.begin(), vec3.begin()) + ), + compute::make_zip_iterator( + boost::make_tuple(vec1.end(), vec2.end(), vec3.end()) + ), + result.begin(), + bc::lambda::remquo(get<0>(_1), get<1>(_1), get<2>(_1)), + queue + ); + CHECK_RANGE_CLOSE(bc::float_, 5, result, (2.2f, 0.0f, 0.0f, 8.3f, 0.0f), 0.01f); + CHECK_RANGE_EQUAL(bc::int_, 5, vec3, (0, 1, 1, 0, 1)); +} + BOOST_AUTO_TEST_CASE(lambda_get_vector) { using boost::compute::_1; From 8d9109e2f881c8233ec39d2fb84d6dc518b1713e Mon Sep 17 00:00:00 2001 From: Jakub Szuppe Date: Sat, 24 Sep 2016 21:33:47 +0200 Subject: [PATCH 4/5] Add lambda wrappers for native_|half_ funcs --- include/boost/compute/lambda/functional.hpp | 32 +++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/include/boost/compute/lambda/functional.hpp b/include/boost/compute/lambda/functional.hpp index 180df3428..6afb004df 100644 --- a/include/boost/compute/lambda/functional.hpp +++ b/include/boost/compute/lambda/functional.hpp @@ -538,6 +538,38 @@ BOOST_COMPUTE_LAMBDA_WRAP_UNARY_FUNCTION_T(tanpi) BOOST_COMPUTE_LAMBDA_WRAP_UNARY_FUNCTION_T(tgamma) BOOST_COMPUTE_LAMBDA_WRAP_UNARY_FUNCTION_T(trunc) +// Native Math Built-In Functions +BOOST_COMPUTE_LAMBDA_WRAP_UNARY_FUNCTION_T(native_cos) +BOOST_COMPUTE_LAMBDA_WRAP_BINARY_FUNCTION(native_divide) +BOOST_COMPUTE_LAMBDA_WRAP_UNARY_FUNCTION_T(native_exp) +BOOST_COMPUTE_LAMBDA_WRAP_UNARY_FUNCTION_T(native_exp2) +BOOST_COMPUTE_LAMBDA_WRAP_UNARY_FUNCTION_T(native_exp10) +BOOST_COMPUTE_LAMBDA_WRAP_UNARY_FUNCTION_T(native_log) +BOOST_COMPUTE_LAMBDA_WRAP_UNARY_FUNCTION_T(native_log2) +BOOST_COMPUTE_LAMBDA_WRAP_UNARY_FUNCTION_T(native_log10) +BOOST_COMPUTE_LAMBDA_WRAP_BINARY_FUNCTION(native_powr) +BOOST_COMPUTE_LAMBDA_WRAP_UNARY_FUNCTION_T(native_recip) +BOOST_COMPUTE_LAMBDA_WRAP_UNARY_FUNCTION_T(native_rsqrt) +BOOST_COMPUTE_LAMBDA_WRAP_UNARY_FUNCTION_T(native_sin) +BOOST_COMPUTE_LAMBDA_WRAP_UNARY_FUNCTION_T(native_sqrt) +BOOST_COMPUTE_LAMBDA_WRAP_UNARY_FUNCTION_T(native_tan) + +// Half Math Built-In Functions +BOOST_COMPUTE_LAMBDA_WRAP_UNARY_FUNCTION_T(half_cos) +BOOST_COMPUTE_LAMBDA_WRAP_BINARY_FUNCTION(half_divide) +BOOST_COMPUTE_LAMBDA_WRAP_UNARY_FUNCTION_T(half_exp) +BOOST_COMPUTE_LAMBDA_WRAP_UNARY_FUNCTION_T(half_exp2) +BOOST_COMPUTE_LAMBDA_WRAP_UNARY_FUNCTION_T(half_exp10) +BOOST_COMPUTE_LAMBDA_WRAP_UNARY_FUNCTION_T(half_log) +BOOST_COMPUTE_LAMBDA_WRAP_UNARY_FUNCTION_T(half_log2) +BOOST_COMPUTE_LAMBDA_WRAP_UNARY_FUNCTION_T(half_log10) +BOOST_COMPUTE_LAMBDA_WRAP_BINARY_FUNCTION(half_powr) +BOOST_COMPUTE_LAMBDA_WRAP_UNARY_FUNCTION_T(half_recip) +BOOST_COMPUTE_LAMBDA_WRAP_UNARY_FUNCTION_T(half_rsqrt) +BOOST_COMPUTE_LAMBDA_WRAP_UNARY_FUNCTION_T(half_sin) +BOOST_COMPUTE_LAMBDA_WRAP_UNARY_FUNCTION_T(half_sqrt) +BOOST_COMPUTE_LAMBDA_WRAP_UNARY_FUNCTION_T(half_tan) + // Relational Built-In Functions BOOST_COMPUTE_LAMBDA_WRAP_BOOLEAN_BINARY_FUNCTION(isequal) BOOST_COMPUTE_LAMBDA_WRAP_BOOLEAN_BINARY_FUNCTION(isnotequal) From e25bb7d99d00472c3f869937b0703adb48b16a8a Mon Sep 17 00:00:00 2001 From: Jakub Szuppe Date: Sat, 24 Sep 2016 22:30:20 +0200 Subject: [PATCH 5/5] POCL does not have remquo() OpenCL built-in func impl --- test/quirks.hpp | 10 ++++++++++ test/test_lambda.cpp | 6 ++++++ 2 files changed, 16 insertions(+) diff --git a/test/quirks.hpp b/test/quirks.hpp index 2c221c042..ff0a8c945 100644 --- a/test/quirks.hpp +++ b/test/quirks.hpp @@ -83,6 +83,16 @@ inline bool supports_image_samplers(const boost::compute::device &device) return true; } +// returns true if the device has remquo() built-in OpenCL function implementation +inline bool has_remquo_func(const boost::compute::device &device) +{ + // POCL does not have it + if(is_pocl_device(device)){ + return false; + } + return true; +} + // returns true if the device supports clSetMemObjectDestructorCallback inline bool supports_destructor_callback(const boost::compute::device &device) { diff --git a/test/test_lambda.cpp b/test/test_lambda.cpp index 0e13a9b37..d3d1973fe 100644 --- a/test/test_lambda.cpp +++ b/test/test_lambda.cpp @@ -26,6 +26,7 @@ #include #include "check_macros.hpp" +#include "quirks.hpp" #include "context_setup.hpp" namespace bc = boost::compute; @@ -272,6 +273,11 @@ BOOST_AUTO_TEST_CASE(lambda_binary_function_with_pointer_modf) BOOST_AUTO_TEST_CASE(lambda_tenary_function_with_pointer_remquo) { + if(!has_remquo_func(device)) + { + return; + } + using boost::compute::lambda::_1; using boost::compute::lambda::_2; using boost::compute::lambda::get;