// // Copyright (c) 2017 The Khronos Group Inc. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // #ifndef TEST_CONFORMANCE_CLCPP_INTEGER_FUNCS_NUMERIC_HPP #define TEST_CONFORMANCE_CLCPP_INTEGER_FUNCS_NUMERIC_HPP #include "common.hpp" #include template struct int_func_abs : public unary_func { std::string str() { return "abs"; } std::string headers() { return "#include \n"; } OUT1 operator()(const IN1& x) { static_assert( std::is_unsigned::value, "OUT1 type must be unsigned" ); if(x < IN1(0)) return static_cast(-x); return static_cast(x); } }; template struct int_func_abs_diff : public binary_func { std::string str() { return "abs_diff"; } std::string headers() { return "#include \n"; } OUT1 operator()(const IN1& x, const IN2& y) { static_assert( std::is_same::value, "IN1 must be IN2" ); static_assert( std::is_unsigned::value, "OUT1 type must be unsigned" ); if(x < y) return static_cast(y-x); return static_cast(x-y); } }; template struct int_func_add_sat : public binary_func { std::string str() { return "add_sat"; } std::string headers() { return "#include \n"; } OUT1 operator()(const IN1& x, const IN2& y) { static_assert( std::is_same::value, "IN1 must be IN2" ); static_assert( std::is_same::value, "OUT1 must be IN2" ); // sat unsigned integers if(std::is_unsigned::value) { OUT1 z = x + y; if(z < x || z < y) return (std::numeric_limits::max)(); return z; } // sat signed integers OUT1 z = x + y; if(y > 0) { if(z < x) return (std::numeric_limits::max)(); } else { if(z > x) return (std::numeric_limits::min)(); } return z; } }; template struct int_func_hadd : public binary_func { std::string str() { return "hadd"; } std::string headers() { return "#include \n"; } OUT1 operator()(const IN1& x, const IN2& y) { static_assert( std::is_same::value, "IN1 must be IN2" ); static_assert( std::is_same::value, "OUT1 must be IN2" ); return (x >> OUT1(1)) + (y >> OUT1(1)) + (x & y & OUT1(1)); } }; template struct int_func_rhadd : public binary_func { std::string str() { return "rhadd"; } std::string headers() { return "#include \n"; } OUT1 operator()(const IN1& x, const IN2& y) { static_assert( std::is_same::value, "IN1 must be IN2" ); static_assert( std::is_same::value, "OUT1 must be IN2" ); return (x >> OUT1(1)) + (y >> OUT1(1)) + ((x | y) & OUT1(1)); } }; // clamp for scalars template struct int_func_clamp : public ternary_func { std::string str() { return "clamp"; } std::string headers() { return "#include \n"; } OUT1 operator()(const IN1& x, const IN2& minval, const IN3& maxval) { static_assert( std::is_same::value, "IN3 must be IN2" ); static_assert( std::is_same::value, "OUT1 must be IN1" ); return (std::min)((std::max)(x, minval), maxval); } IN2 min2() { return (std::numeric_limits::min)(); } IN2 max2() { return (std::numeric_limits::max)() / IN2(2); } IN3 min3() { return IN3(1) + ((std::numeric_limits::max)() / IN3(2)); } IN3 max3() { return (std::numeric_limits::max)(); } }; // gentype clamp(gentype x, scalar minval, scalar maxval); template struct int_func_clamp::value>::type> : public ternary_func { std::string str() { return "clamp"; } std::string headers() { return "#include \n"; } OUT1 operator()(const IN1& x, const IN2& minval, const IN3& maxval) { static_assert( std::is_same::value, "IN3 must be IN2" ); static_assert( !is_vector_type::value && !is_vector_type::value, "IN3 and IN2 must be scalar" ); static_assert( std::is_same::value, "OUT1 must be IN1" ); OUT1 result; for(size_t i = 0; i < vector_size::value; i++) { result.s[i] = (std::min)((std::max)(x.s[i], minval), maxval); } return result; } IN1 min1() { typedef typename scalar_type::type SCALAR1; IN1 min1; for(size_t i = 0; i < vector_size::value; i++) { min1.s[i] = (std::numeric_limits::min)(); } return min1; } IN1 max1() { typedef typename scalar_type::type SCALAR1; IN1 max1; for(size_t i = 0; i < vector_size::value; i++) { max1.s[i] = (std::numeric_limits::max)(); } return max1; } IN2 min2() { return (std::numeric_limits::min)(); } IN2 max2() { return (std::numeric_limits::max)() / IN2(2); } IN3 min3() { return IN3(1) + ((std::numeric_limits::max)() / IN3(2)); } IN3 max3() { return (std::numeric_limits::max)(); } }; template struct int_func_mul_hi : public binary_func { std::string str() { return "mul_hi"; } std::string headers() { return "#include \n"; } OUT1 operator()(const IN1& x, const IN2& y) { static_assert( std::is_same::value && std::is_same::value, "Types must be the same" ); static_assert( !std::is_same::value && !std::is_same::value, "Operation unimplemented for 64-bit scalars" ); cl_long xl = static_cast(x); cl_long yl = static_cast(y); return static_cast((xl * yl) >> (8 * sizeof(OUT1))); } }; template struct int_func_mad_hi : public ternary_func { std::string str() { return "mad_hi"; } std::string headers() { return "#include \n"; } OUT1 operator()(const IN1& x, const IN2& y, const IN3& z) { static_assert( std::is_same::value && std::is_same::value && std::is_same::value, "Types must be the same" ); return int_func_mul_hi()(x, y) + z; } }; // This test is implemented only for unsigned integers template struct int_func_mad_sat : public ternary_func { std::string str() { return "mad_sat"; } std::string headers() { return "#include \n"; } OUT1 operator()(const IN1& x, const IN2& y, const IN3& z) { static_assert( std::is_same::value && std::is_same::value && std::is_same::value, "Types must be the same" ); static_assert( std::is_unsigned::value, "Test operation is not implemented for signed integers" ); // mad_sat unsigned integers OUT1 w1 = (x * y); if (x != 0 && w1 / x != y) return (std::numeric_limits::max)(); OUT1 w2 = w1 + z; if(w2 < w1) return (std::numeric_limits::max)(); return w2; } }; template struct int_func_sub_sat : public binary_func { std::string str() { return "sub_sat"; } std::string headers() { return "#include \n"; } OUT1 operator()(const IN1& x, const IN2& y) { static_assert( std::is_same::value && std::is_same::value, "IN1, IN2 and OUT1 must be the same types" ); // sat unsigned integers if(std::is_unsigned::value) { OUT1 z = x - y; if(x < y) return (std::numeric_limits::min)(); return z; } // sat signed integers OUT1 z = x - y; if(y < 0) { if(z < x) return (std::numeric_limits::max)(); } else { if(z > x) return (std::numeric_limits::min)(); } return z; } }; template struct int_func_max : public binary_func { std::string str() { return "max"; } std::string headers() { return "#include \n"; } OUT1 operator()(const IN1& x, const IN2& y) { static_assert( std::is_same::value && std::is_same::value, "IN1, IN2 and OUT1 must be the same types" ); return (std::max)(x, y); } }; template struct int_func_max::value>::type> : public binary_func { std::string str() { return "max"; } std::string headers() { return "#include \n"; } IN1 min1() { typedef typename scalar_type::type SCALAR1; IN1 min1; for(size_t i = 0; i < vector_size::value; i++) { min1.s[i] = (std::numeric_limits::min)(); } return min1; } IN1 max1() { typedef typename scalar_type::type SCALAR1; IN1 max1; for(size_t i = 0; i < vector_size::value; i++) { max1.s[i] = (std::numeric_limits::max)(); } return max1; } OUT1 operator()(const IN1& x, const IN2& y) { static_assert( std::is_same::value, "IN1 and OUT1 must be the same types" ); static_assert( !is_vector_type::value, "IN2 must be scalar" ); static_assert( std::is_same::type, IN2>::value, "IN2 must match with OUT1 and IN1" ); IN1 result = x; for(size_t i = 0; i < vector_size::value; i++) { result.s[i] = (std::max)(x.s[i], y); } return result; } }; template struct int_func_min : public binary_func { std::string str() { return "min"; } std::string headers() { return "#include \n"; } OUT1 operator()(const IN1& x, const IN2& y) { static_assert( std::is_same::value && std::is_same::value, "IN1, IN2 and OUT1 must be the same types" ); return (std::min)(x, y); } }; template struct int_func_min::value>::type> : public binary_func { std::string str() { return "min"; } std::string headers() { return "#include \n"; } IN1 min1() { typedef typename scalar_type::type SCALAR1; IN1 min1; for(size_t i = 0; i < vector_size::value; i++) { min1.s[i] = (std::numeric_limits::min)(); } return min1; } IN1 max1() { typedef typename scalar_type::type SCALAR1; IN1 max1; for(size_t i = 0; i < vector_size::value; i++) { max1.s[i] = (std::numeric_limits::max)(); } return max1; } OUT1 operator()(const IN1& x, const IN2& y) { static_assert( std::is_same::value, "IN1 and OUT1 must be the same types" ); static_assert( !is_vector_type::value, "IN2 must be scalar" ); static_assert( std::is_same::type, IN2>::value, "IN2 must match with OUT1 and IN1" ); IN1 result = x; for(size_t i = 0; i < vector_size::value; i++) { result.s[i] = (std::min)(x.s[i], y); } return result; } }; AUTO_TEST_CASE(test_int_numeric_funcs) (cl_device_id device, cl_context context, cl_command_queue queue, int n_elems) { int error = CL_SUCCESS; int last_error = CL_SUCCESS; // ugentype abs(gentype x); TEST_UNARY_FUNC_MACRO((int_func_abs())) TEST_UNARY_FUNC_MACRO((int_func_abs())) TEST_UNARY_FUNC_MACRO((int_func_abs())) TEST_UNARY_FUNC_MACRO((int_func_abs())) // ugentype abs_diff(gentype x, gentype y); TEST_BINARY_FUNC_MACRO((int_func_abs_diff())) TEST_BINARY_FUNC_MACRO((int_func_abs_diff())) TEST_BINARY_FUNC_MACRO((int_func_abs_diff())) TEST_BINARY_FUNC_MACRO((int_func_abs_diff())) // gentype add_sat(gentype x, gentype y); TEST_BINARY_FUNC_MACRO((int_func_add_sat())) TEST_BINARY_FUNC_MACRO((int_func_add_sat())) TEST_BINARY_FUNC_MACRO((int_func_add_sat())) TEST_BINARY_FUNC_MACRO((int_func_add_sat())) // gentype hadd(gentype x, gentype y); TEST_BINARY_FUNC_MACRO((int_func_hadd())) TEST_BINARY_FUNC_MACRO((int_func_hadd())) TEST_BINARY_FUNC_MACRO((int_func_hadd())) TEST_BINARY_FUNC_MACRO((int_func_hadd())) // gentype rhadd(gentype x, gentype y); TEST_BINARY_FUNC_MACRO((int_func_rhadd())) TEST_BINARY_FUNC_MACRO((int_func_rhadd())) TEST_BINARY_FUNC_MACRO((int_func_rhadd())) TEST_BINARY_FUNC_MACRO((int_func_rhadd())) // gentype clamp(gentype x, gentype minval, gentype maxval); TEST_TERNARY_FUNC_MACRO((int_func_clamp())) TEST_TERNARY_FUNC_MACRO((int_func_clamp())) TEST_TERNARY_FUNC_MACRO((int_func_clamp())) TEST_TERNARY_FUNC_MACRO((int_func_clamp())) // gentype clamp(gentype x, scalar minval, scalar maxval); TEST_TERNARY_FUNC_MACRO((int_func_clamp())) TEST_TERNARY_FUNC_MACRO((int_func_clamp())) TEST_TERNARY_FUNC_MACRO((int_func_clamp())) TEST_TERNARY_FUNC_MACRO((int_func_clamp())) // gentype mad_hi(gentype a, gentype b, gentype c); TEST_TERNARY_FUNC_MACRO((int_func_mad_hi())) TEST_TERNARY_FUNC_MACRO((int_func_mad_hi())) TEST_TERNARY_FUNC_MACRO((int_func_mad_hi())) TEST_TERNARY_FUNC_MACRO((int_func_mad_hi())) // gentype mad_sat(gentype a, gentype b, gentype c); TEST_TERNARY_FUNC_MACRO((int_func_mad_sat())) TEST_TERNARY_FUNC_MACRO((int_func_mad_sat())) TEST_TERNARY_FUNC_MACRO((int_func_mad_sat())) // gentype max(gentype x, gentype y); TEST_BINARY_FUNC_MACRO((int_func_max())) TEST_BINARY_FUNC_MACRO((int_func_max())) TEST_BINARY_FUNC_MACRO((int_func_max())) TEST_BINARY_FUNC_MACRO((int_func_max())) // gentype max(gentype x, scalar y); TEST_BINARY_FUNC_MACRO((int_func_max())) TEST_BINARY_FUNC_MACRO((int_func_max())) TEST_BINARY_FUNC_MACRO((int_func_max())) TEST_BINARY_FUNC_MACRO((int_func_max())) // gentype min(gentype x, gentype y); TEST_BINARY_FUNC_MACRO((int_func_min())) TEST_BINARY_FUNC_MACRO((int_func_min())) TEST_BINARY_FUNC_MACRO((int_func_min())) TEST_BINARY_FUNC_MACRO((int_func_min())) // gentype min(gentype x, scalar y); TEST_BINARY_FUNC_MACRO((int_func_min())) TEST_BINARY_FUNC_MACRO((int_func_min())) TEST_BINARY_FUNC_MACRO((int_func_min())) TEST_BINARY_FUNC_MACRO((int_func_min())) // gentype mul_hi(gentype x, gentype y); TEST_BINARY_FUNC_MACRO((int_func_mul_hi())) TEST_BINARY_FUNC_MACRO((int_func_mul_hi())) TEST_BINARY_FUNC_MACRO((int_func_mul_hi())) TEST_BINARY_FUNC_MACRO((int_func_mul_hi())) // gentype sub_sat(gentype x, gentype y); TEST_BINARY_FUNC_MACRO((int_func_sub_sat())) TEST_BINARY_FUNC_MACRO((int_func_sub_sat())) TEST_BINARY_FUNC_MACRO((int_func_sub_sat())) TEST_BINARY_FUNC_MACRO((int_func_sub_sat())) if(error != CL_SUCCESS) { return -1; } return error; } #endif // TEST_CONFORMANCE_CLCPP_INTEGER_FUNCS_NUMERIC_HPP