Initial open source release of OpenCL 2.2 CTS.

This commit is contained in:
Kedar Patil
2017-05-16 18:25:37 +05:30
parent 6911ba5116
commit 2821bf1323
1035 changed files with 343518 additions and 0 deletions

View File

@@ -0,0 +1,12 @@
set(MODULE_NAME CPP_MATH_FUNCS)
set(${MODULE_NAME}_SOURCES
main.cpp
../../../test_common/harness/errorHelpers.c
../../../test_common/harness/testHarness.c
../../../test_common/harness/kernelHelpers.c
../../../test_common/harness/msvc9.c
../../../test_common/harness/parseParameters.cpp
)
include(../../CMakeCommon.txt)

View File

@@ -0,0 +1,347 @@
//
// 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_MATH_FUNCS_COMMON_FUNCS_HPP
#define TEST_CONFORMANCE_CLCPP_MATH_FUNCS_COMMON_FUNCS_HPP
#include <cmath>
#include <limits>
#include "../common.hpp"
#include "../funcs_test_utils.hpp"
#include "reference.hpp"
#ifndef MATH_FUNCS_CLASS_NAME
#define MATH_FUNCS_CLASS_NAME(x, y) x ## _func_ ## y
#endif
#define MATH_FUNCS_DEFINE_UNARY_FUNC1(GROUP_NAME, NAME, OCL_FUNC, HOST_FUNC, USE_ULP, ULP, ULP_EMBEDDED, DELTA, MIN1, MAX1) \
struct MATH_FUNCS_CLASS_NAME(GROUP_NAME, NAME) : public unary_func<cl_float, cl_float> \
{ \
MATH_FUNCS_CLASS_NAME(GROUP_NAME, NAME)(bool is_embedded) : m_is_embedded(is_embedded) \
{ \
\
} \
\
std::string str() \
{ \
return #OCL_FUNC; \
} \
\
std::string headers() \
{ \
return "#include <opencl_math>\n"; \
} \
/* Reference value type is cl_double */ \
cl_double operator()(const cl_float& x) \
{ \
return (HOST_FUNC)(static_cast<cl_double>(x)); \
} \
\
cl_float min1() \
{ \
return MIN1; \
} \
\
cl_float max1() \
{ \
return MAX1; \
} \
\
std::vector<cl_float> in1_special_cases() \
{ \
return { \
cl_float(0.0f), \
cl_float(-0.0f), \
cl_float(1.0f), \
cl_float(-1.0f), \
cl_float(2.0f), \
cl_float(-2.0f), \
std::numeric_limits<cl_float>::infinity(), \
-std::numeric_limits<cl_float>::infinity(), \
std::numeric_limits<cl_float>::quiet_NaN() \
}; \
} \
\
bool use_ulp() \
{ \
return USE_ULP; \
} \
\
template<class T> \
typename make_vector_type<cl_double, vector_size<T>::value>::type \
delta(const cl_float& in1, const T& expected) \
{ \
typedef \
typename make_vector_type<cl_double, vector_size<T>::value>::type \
delta_vector_type; \
(void) in1; \
auto e = detail::make_value<delta_vector_type>(DELTA); \
return detail::multiply<delta_vector_type>(e, expected); \
} \
\
float ulp() \
{ \
if(m_is_embedded) \
{ \
return ULP_EMBEDDED; \
} \
return ULP; \
} \
private: \
bool m_is_embedded; \
};
#define MATH_FUNCS_DEFINE_BINARY_FUNC1(GROUP_NAME, NAME, OCL_NAME, HOST_FUNC, USE_ULP, ULP, ULP_EMBEDDED, DELTA, MIN1, MAX1, MIN2, MAX2) \
struct MATH_FUNCS_CLASS_NAME(GROUP_NAME, NAME) : public binary_func<cl_float, cl_float, cl_float> \
{ \
MATH_FUNCS_CLASS_NAME(GROUP_NAME, NAME)(bool is_embedded) : m_is_embedded(is_embedded) \
{ \
\
} \
\
std::string str() \
{ \
return #OCL_NAME; \
} \
\
std::string headers() \
{ \
return "#include <opencl_math>\n"; \
} \
\
cl_float operator()(const cl_float& x, const cl_float& y) \
{ \
return (HOST_FUNC)(x, y); \
} \
\
cl_float min1() \
{ \
return MIN1; \
} \
\
cl_float max1() \
{ \
return MAX1; \
} \
\
cl_float min2() \
{ \
return MIN2; \
} \
\
cl_float max2() \
{ \
return MAX2; \
} \
\
std::vector<cl_float> in1_special_cases() \
{ \
return { \
cl_float(0.0f), \
cl_float(-0.0f), \
cl_float(1.0f), \
cl_float(-1.0f), \
cl_float(2.0f), \
cl_float(-2.0f), \
std::numeric_limits<cl_float>::infinity(), \
-std::numeric_limits<cl_float>::infinity(), \
std::numeric_limits<cl_float>::quiet_NaN() \
}; \
} \
\
std::vector<cl_float> in2_special_cases() \
{ \
return { \
cl_float(0.0f), \
cl_float(-0.0f), \
cl_float(1.0f), \
cl_float(-1.0f), \
cl_float(2.0f), \
cl_float(-2.0f), \
std::numeric_limits<cl_float>::infinity(), \
-std::numeric_limits<cl_float>::infinity(), \
std::numeric_limits<cl_float>::quiet_NaN() \
}; \
} \
\
template<class T> \
typename make_vector_type<cl_double, vector_size<T>::value>::type \
delta(const cl_float& in1, const cl_float& in2, const T& expected) \
{ \
typedef \
typename make_vector_type<cl_double, vector_size<T>::value>::type \
delta_vector_type; \
(void) in1; \
(void) in2; \
auto e = detail::make_value<delta_vector_type>(DELTA); \
return detail::multiply<delta_vector_type>(e, expected); \
} \
\
bool use_ulp() \
{ \
return USE_ULP; \
} \
\
float ulp() \
{ \
if(m_is_embedded) \
{ \
return ULP_EMBEDDED; \
} \
return ULP; \
} \
private: \
bool m_is_embedded; \
};
#define MATH_FUNCS_DEFINE_TERNARY_FUNC1(GROUP_NAME, NAME, OCL_NAME, HOST_FUNC, USE_ULP, ULP, ULP_EMBEDDED, DELTA, MIN1, MAX1, MIN2, MAX2, MIN3, MAX3) \
struct MATH_FUNCS_CLASS_NAME(GROUP_NAME, NAME) : public ternary_func<cl_float, cl_float, cl_float, cl_float> \
{ \
MATH_FUNCS_CLASS_NAME(GROUP_NAME, NAME)(bool is_embedded) : m_is_embedded(is_embedded) \
{ \
\
} \
\
std::string str() \
{ \
return #OCL_NAME; \
} \
\
std::string headers() \
{ \
return "#include <opencl_math>\n"; \
} \
\
cl_double operator()(const cl_float& x, const cl_float& y, const cl_float& z) \
{ \
return (HOST_FUNC)(static_cast<cl_double>(x), static_cast<cl_double>(y), static_cast<cl_double>(z)); \
} \
\
cl_float min1() \
{ \
return MIN1; \
} \
\
cl_float max1() \
{ \
return MAX1; \
} \
\
cl_float min2() \
{ \
return MIN2; \
} \
\
cl_float max2() \
{ \
return MAX2; \
} \
\
cl_float min3() \
{ \
return MIN3; \
} \
\
cl_float max3() \
{ \
return MAX3; \
} \
\
std::vector<cl_float> in1_special_cases() \
{ \
return { \
cl_float(0.0f), \
cl_float(-0.0f), \
cl_float(1.0f), \
cl_float(-1.0f), \
cl_float(2.0f), \
cl_float(-2.0f), \
std::numeric_limits<cl_float>::infinity(), \
-std::numeric_limits<cl_float>::infinity(), \
std::numeric_limits<cl_float>::quiet_NaN() \
}; \
} \
\
std::vector<cl_float> in2_special_cases() \
{ \
return { \
cl_float(0.0f), \
cl_float(-0.0f), \
cl_float(1.0f), \
cl_float(-1.0f), \
cl_float(2.0f), \
cl_float(-2.0f), \
std::numeric_limits<cl_float>::infinity(), \
-std::numeric_limits<cl_float>::infinity(), \
std::numeric_limits<cl_float>::quiet_NaN() \
}; \
} \
\
std::vector<cl_float> in3_special_cases() \
{ \
return { \
cl_float(0.0f), \
cl_float(-0.0f), \
cl_float(1.0f), \
cl_float(-1.0f), \
cl_float(2.0f), \
cl_float(-2.0f), \
std::numeric_limits<cl_float>::infinity(), \
-std::numeric_limits<cl_float>::infinity(), \
std::numeric_limits<cl_float>::quiet_NaN() \
}; \
} \
\
template<class T> \
typename make_vector_type<cl_double, vector_size<T>::value>::type \
delta(const cl_float& in1, const cl_float& in2, const cl_float& in3, const T& expected) \
{ \
typedef \
typename make_vector_type<cl_double, vector_size<T>::value>::type \
delta_vector_type; \
(void) in1; \
(void) in2; \
(void) in3; \
auto e = detail::make_value<delta_vector_type>(DELTA); \
return detail::multiply<delta_vector_type>(e, expected); \
} \
\
bool use_ulp() \
{ \
return USE_ULP; \
} \
\
float ulp() \
{ \
if(m_is_embedded) \
{ \
return ULP_EMBEDDED; \
} \
return ULP; \
} \
private: \
bool m_is_embedded; \
};
#define MATH_FUNCS_DEFINE_UNARY_FUNC(GROUP_NAME, NAME, HOST_FUNC, USE_ULP, ULP, ULP_EMBEDDED, DELTA, MIN1, MAX1) \
MATH_FUNCS_DEFINE_UNARY_FUNC1(GROUP_NAME, NAME, NAME, HOST_FUNC, USE_ULP, ULP, ULP_EMBEDDED, DELTA, MIN1, MAX1)
#define MATH_FUNCS_DEFINE_BINARY_FUNC(GROUP_NAME, NAME, HOST_FUNC, USE_ULP, ULP, ULP_EMBEDDED, DELTA, MIN1, MAX1, MIN2, MAX2) \
MATH_FUNCS_DEFINE_BINARY_FUNC1(GROUP_NAME, NAME, NAME, HOST_FUNC, USE_ULP, ULP, ULP_EMBEDDED, DELTA, MIN1, MAX1, MIN2, MAX2)
#define MATH_FUNCS_DEFINE_TERNARY_FUNC(GROUP_NAME, NAME, HOST_FUNC, USE_ULP, ULP, ULP_EMBEDDED, DELTA, MIN1, MAX1, MIN2, MAX2, MIN3, MAX3) \
MATH_FUNCS_DEFINE_TERNARY_FUNC1(GROUP_NAME, NAME, NAME, HOST_FUNC, USE_ULP, ULP, ULP_EMBEDDED, DELTA, MIN1, MAX1, MIN2, MAX2, MIN3, MAX3)
#endif // TEST_CONFORMANCE_CLCPP_MATH_FUNCS_COMMON_FUNCS_HPP

View File

@@ -0,0 +1,59 @@
//
// 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_MATH_FUNCS_COMPARISON_FUNCS_HPP
#define TEST_CONFORMANCE_CLCPP_MATH_FUNCS_COMPARISON_FUNCS_HPP
#include <type_traits>
#include <cmath>
#include "common.hpp"
// group_name, func_name, reference_func, use_ulp, ulp, ulp_for_embedded, max_delta, min1, max1
MATH_FUNCS_DEFINE_BINARY_FUNC(comparison, fdim, std::fdim, true, 0.0f, 0.0f, 0.001f, -1000.0f, 1000.0f, -1000.0f, 1000.0f)
MATH_FUNCS_DEFINE_BINARY_FUNC(comparison, fmax, std::fmax, true, 0.0f, 0.0f, 0.001f, -1000.0f, 1000.0f, -1000.0f, 1000.0f)
MATH_FUNCS_DEFINE_BINARY_FUNC(comparison, fmin, std::fmin, true, 0.0f, 0.0f, 0.001f, -1000.0f, 1000.0f, -1000.0f, 1000.0f)
MATH_FUNCS_DEFINE_BINARY_FUNC(comparison, maxmag, reference::maxmag, true, 0.0f, 0.0f, 0.001f, -1000.0f, 1000.0f, -1000.0f, 1000.0f)
MATH_FUNCS_DEFINE_BINARY_FUNC(comparison, minmag, reference::minmag, true, 0.0f, 0.0f, 0.001f, -1000.0f, 1000.0f, -1000.0f, 1000.0f)
// comparison functions
AUTO_TEST_CASE(test_comparison_funcs)
(cl_device_id device, cl_context context, cl_command_queue queue, int n_elems)
{
int error = CL_SUCCESS;
int last_error = CL_SUCCESS;
// Check for EMBEDDED_PROFILE
bool is_embedded_profile = false;
char profile[128];
last_error = clGetDeviceInfo(device, CL_DEVICE_PROFILE, sizeof(profile), (void *)&profile, NULL);
RETURN_ON_CL_ERROR(last_error, "clGetDeviceInfo")
if (std::strcmp(profile, "EMBEDDED_PROFILE") == 0)
is_embedded_profile = true;
TEST_BINARY_FUNC_MACRO((comparison_func_fdim(is_embedded_profile)))
TEST_BINARY_FUNC_MACRO((comparison_func_fmax(is_embedded_profile)))
TEST_BINARY_FUNC_MACRO((comparison_func_fmin(is_embedded_profile)))
TEST_BINARY_FUNC_MACRO((comparison_func_maxmag(is_embedded_profile)))
TEST_BINARY_FUNC_MACRO((comparison_func_minmag(is_embedded_profile)))
if(error != CL_SUCCESS)
{
return -1;
}
return error;
}
#endif // TEST_CONFORMANCE_CLCPP_MATH_FUNCS_COMPARISON_FUNCS_HPP

View File

@@ -0,0 +1,139 @@
//
// 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_MATH_FUNCS_EXP_FUNCS_HPP
#define TEST_CONFORMANCE_CLCPP_MATH_FUNCS_EXP_FUNCS_HPP
#include <type_traits>
#include <cmath>
#include "common.hpp"
// group_name, func_name, reference_func, use_ulp, ulp, ulp_for_embedded, max_delta, min1, max1
MATH_FUNCS_DEFINE_UNARY_FUNC(exponential, exp, std::exp, true, 3.0f, 4.0f, 0.001f, -1000.0f, 1000.0f)
MATH_FUNCS_DEFINE_UNARY_FUNC(exponential, expm1, std::expm1, true, 3.0f, 4.0f, 0.001f, -1000.0f, 1000.0f)
MATH_FUNCS_DEFINE_UNARY_FUNC(exponential, exp2, std::exp2, true, 3.0f, 4.0f, 0.001f, -1000.0f, 1000.0f)
MATH_FUNCS_DEFINE_UNARY_FUNC(exponential, exp10, reference::exp10, true, 3.0f, 4.0f, 0.001f, -1000.0f, 1000.0f)
struct exponential_func_ldexp : public binary_func<cl_float, cl_int, cl_float>
{
exponential_func_ldexp(bool is_embedded) : m_is_embedded(is_embedded)
{
}
std::string str()
{
return "ldexp";
}
std::string headers()
{
return "#include <opencl_math>\n";
}
/* Reference value type is cl_double */
cl_double operator()(const cl_float& x, const cl_int& y)
{
return (std::ldexp)(static_cast<cl_double>(x), y);
}
cl_float min1()
{
return -1000.0f;
}
cl_float max1()
{
return 1000.0f;
}
cl_int min2()
{
return -8;
}
cl_int max2()
{
return 8;
}
std::vector<cl_float> in1_special_cases()
{
return {
cl_float(0.0f),
cl_float(-0.0f),
cl_float(1.0f),
cl_float(-1.0f),
cl_float(2.0f),
cl_float(-2.0f),
std::numeric_limits<cl_float>::infinity(),
-std::numeric_limits<cl_float>::infinity(),
std::numeric_limits<cl_float>::quiet_NaN()
};
}
bool use_ulp()
{
return true;
}
float ulp()
{
if(m_is_embedded)
{
return 0.0f;
}
return 0.0f;
}
private:
bool m_is_embedded;
};
// exponential functions
AUTO_TEST_CASE(test_exponential_funcs)
(cl_device_id device, cl_context context, cl_command_queue queue, int n_elems)
{
int error = CL_SUCCESS;
int last_error = CL_SUCCESS;
// Check for EMBEDDED_PROFILE
bool is_embedded_profile = false;
char profile[128];
last_error = clGetDeviceInfo(device, CL_DEVICE_PROFILE, sizeof(profile), (void *)&profile, NULL);
RETURN_ON_CL_ERROR(last_error, "clGetDeviceInfo")
if (std::strcmp(profile, "EMBEDDED_PROFILE") == 0)
is_embedded_profile = true;
// auto exp(gentype x);
// auto expm1(gentype x);
// auto exp2(gentype x);
// auto exp10(gentype x);
TEST_UNARY_FUNC_MACRO((exponential_func_exp(is_embedded_profile)))
TEST_UNARY_FUNC_MACRO((exponential_func_expm1(is_embedded_profile)))
TEST_UNARY_FUNC_MACRO((exponential_func_exp2(is_embedded_profile)))
TEST_UNARY_FUNC_MACRO((exponential_func_exp10(is_embedded_profile)))
// auto ldexp(gentype x, intn k);
TEST_BINARY_FUNC_MACRO((exponential_func_ldexp(is_embedded_profile)))
if(error != CL_SUCCESS)
{
return -1;
}
return error;
}
#endif // TEST_CONFORMANCE_CLCPP_MATH_FUNCS_EXP_FUNCS_HPP

View File

@@ -0,0 +1,733 @@
//
// 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_MATH_FUNCS_FP_FUNCS_HPP
#define TEST_CONFORMANCE_CLCPP_MATH_FUNCS_FP_FUNCS_HPP
#include <type_traits>
#include <cmath>
#include "common.hpp"
// -------------- UNARY FUNCTIONS
// gentype ceil(gentype x);
// gentype floor(gentype x);
// gentype rint(gentype x);
// gentype round(gentype x);
// gentype trunc(gentype x);
// group_name, func_name, reference_func, use_ulp, ulp, ulp_for_embedded, max_delta, min1, max1
MATH_FUNCS_DEFINE_UNARY_FUNC(fp, ceil, std::ceil, true, 0.0f, 0.0f, 0.001f, -1000.0f, 1000.0f)
MATH_FUNCS_DEFINE_UNARY_FUNC(fp, floor, std::floor, true, 0.0f, 0.0f, 0.001f, -1000.0f, 1000.0f)
MATH_FUNCS_DEFINE_UNARY_FUNC(fp, rint, std::rint, true, 0.0f, 0.0f, 0.001f, -1000.0f, 1000.0f)
MATH_FUNCS_DEFINE_UNARY_FUNC(fp, round, std::round, true, 0.0f, 0.0f, 0.001f, -1000.0f, 1000.0f)
MATH_FUNCS_DEFINE_UNARY_FUNC(fp, trunc, std::trunc, true, 0.0f, 0.0f, 0.001f, -1000.0f, 1000.0f)
// floatn nan(uintn nancode);
struct fp_func_nan : public unary_func<cl_uint, cl_float>
{
std::string str()
{
return "nan";
}
std::string headers()
{
return "#include <opencl_math>\n";
}
cl_float operator()(const cl_uint& x)
{
cl_uint r = x | 0x7fc00000U;
// cl_float and cl_int have the same size so that's correct
cl_float rf = *reinterpret_cast<cl_float*>(&r);
return rf;
}
cl_uint min1()
{
return 0;
}
cl_uint max1()
{
return 100;
}
std::vector<cl_uint> in1_special_cases()
{
return {
0, 1
};
}
};
// -------------- UNARY FUNCTIONS, 2ND ARG IS POINTER
// gentype fract(gentype x, gentype* iptr);
//
// Fuction fract() returns additional value via pointer (2nd argument). In order to test
// if it's correct output buffer type is cl_float2. In first compontent we store what
// fract() function returns, and in the 2nd component we store what is returned via its
// 2nd argument (gentype* iptr).
struct fp_func_fract : public unary_func<cl_float, cl_float2>
{
fp_func_fract(bool is_embedded) : m_is_embedded(is_embedded)
{
}
std::string str()
{
return "fract";
}
std::string headers()
{
return "#include <opencl_math>\n";
}
cl_double2 operator()(const cl_float& x)
{
return reference::fract(static_cast<cl_double>(x));
}
cl_float min1()
{
return -1000.0f;
}
cl_float max1()
{
return 1000.0f;
}
std::vector<cl_float> in1_special_cases()
{
return {
cl_float(0.0f),
cl_float(-0.0f),
cl_float(1.0f),
cl_float(-1.0f),
cl_float(2.0f),
cl_float(-2.0f),
std::numeric_limits<cl_float>::infinity(),
-std::numeric_limits<cl_float>::infinity(),
std::numeric_limits<cl_float>::quiet_NaN()
};
}
bool use_ulp()
{
return true;
}
float ulp()
{
if(m_is_embedded)
{
return 0.0f;
}
return 0.0f;
}
private:
bool m_is_embedded;
};
// We need to specialize generate_kernel_unary<>() function template for fp_func_fract.
// -----------------------------------------------------------------------------------
// ------------- ONLY FOR OPENCL 22 CONFORMANCE TEST 22 DEVELOPMENT ------------------
// -----------------------------------------------------------------------------------
#if defined(DEVELOPMENT) && defined(USE_OPENCLC_KERNELS)
template <>
std::string generate_kernel_unary<fp_func_fract, cl_float, cl_float2>(fp_func_fract func)
{
return
"__kernel void test_fract(global float *input, global float2 *output)\n"
"{\n"
" size_t gid = get_global_id(0);\n"
" float2 result;\n"
" float itpr = 0;\n"
" result.x = fract(input[gid], &itpr);\n"
" result.y = itpr;\n"
" output[gid] = result;\n"
"}\n";
}
#else
template <>
std::string generate_kernel_unary<fp_func_fract, cl_float, cl_float2>(fp_func_fract func)
{
return
"" + func.defs() +
"" + func.headers() +
"#include <opencl_memory>\n"
"#include <opencl_work_item>\n"
"using namespace cl;\n"
"__kernel void test_fract(global_ptr<float[]> input, global_ptr<float2[]> output)\n"
"{\n"
" size_t gid = get_global_id(0);\n"
" float2 result;\n"
" float itpr = 0;\n"
" result.x = fract(input[gid], &itpr);\n"
" result.y = itpr;\n"
" output[gid] = result;\n"
"}\n";
}
#endif
// gentype modf(gentype x, gentype* iptr);
//
// Fuction modf() returns additional value via pointer (2nd argument). In order to test
// if it's correct output buffer type is cl_float2. In first compontent we store what
// modf() function returns, and in the 2nd component we store what is returned via its
// 2nd argument (gentype* iptr).
struct fp_func_modf : public unary_func<cl_float, cl_float2>
{
fp_func_modf(bool is_embedded) : m_is_embedded(is_embedded)
{
}
std::string str()
{
return "modf";
}
std::string headers()
{
return "#include <opencl_math>\n";
}
cl_double2 operator()(const cl_float& x)
{
cl_double2 r;
r.s[0] = (std::modf)(static_cast<cl_double>(x), &(r.s[1]));
return r;
}
cl_float min1()
{
return -1000.0f;
}
cl_float max1()
{
return 1000.0f;
}
std::vector<cl_float> in1_special_cases()
{
return {
cl_float(0.0f),
cl_float(-0.0f),
cl_float(1.0f),
cl_float(-1.0f),
cl_float(2.0f),
cl_float(-2.0f),
std::numeric_limits<cl_float>::infinity(),
-std::numeric_limits<cl_float>::infinity(),
std::numeric_limits<cl_float>::quiet_NaN()
};
}
bool use_ulp()
{
return true;
}
float ulp()
{
if(m_is_embedded)
{
return 0.0f;
}
return 0.0f;
}
private:
bool m_is_embedded;
};
// We need to specialize generate_kernel_unary<>() function template for fp_func_modf.
// -----------------------------------------------------------------------------------
// ------------- ONLY FOR OPENCL 22 CONFORMANCE TEST 22 DEVELOPMENT ------------------
// -----------------------------------------------------------------------------------
#if defined(DEVELOPMENT) && defined(USE_OPENCLC_KERNELS)
template <>
std::string generate_kernel_unary<fp_func_modf, cl_float, cl_float2>(fp_func_modf func)
{
return
"__kernel void test_modf(global float *input, global float2 *output)\n"
"{\n"
" size_t gid = get_global_id(0);\n"
" float2 result;\n"
" float itpr = 0;\n"
" result.x = modf(input[gid], &itpr);\n"
" result.y = itpr;\n"
" output[gid] = result;\n"
"}\n";
}
#else
template <>
std::string generate_kernel_unary<fp_func_modf, cl_float, cl_float2>(fp_func_modf func)
{
return
"" + func.defs() +
"" + func.headers() +
"#include <opencl_memory>\n"
"#include <opencl_work_item>\n"
"using namespace cl;\n"
"__kernel void test_modf(global_ptr<float[]> input, global_ptr<float2[]> output)\n"
"{\n"
" size_t gid = get_global_id(0);\n"
" float2 result;\n"
" float itpr = 0;\n"
" result.x = modf(input[gid], &itpr);\n"
" result.y = itpr;\n"
" output[gid] = result;\n"
"}\n";
}
#endif
// gentype frexp(gentype x, intn* exp);
//
// Fuction frexp() returns additional value via pointer (2nd argument). In order to test
// if it's correct output buffer type is cl_float2. In first compontent we store what
// modf() function returns, and in the 2nd component we store what is returned via its
// 2nd argument (intn* exp).
struct fp_func_frexp : public unary_func<cl_float, cl_float2>
{
fp_func_frexp(bool is_embedded) : m_is_embedded(is_embedded)
{
}
std::string str()
{
return "frexp";
}
std::string headers()
{
return "#include <opencl_math>\n";
}
cl_double2 operator()(const cl_float& x)
{
cl_double2 r;
cl_int e;
r.s[0] = (std::frexp)(static_cast<cl_double>(x), &e);
r.s[1] = static_cast<cl_float>(e);
return r;
}
cl_float min1()
{
return -1000.0f;
}
cl_float max1()
{
return 1000.0f;
}
std::vector<cl_float> in1_special_cases()
{
return {
cl_float(0.0f),
cl_float(-0.0f),
cl_float(1.0f),
cl_float(-1.0f),
cl_float(2.0f),
cl_float(-2.0f),
std::numeric_limits<cl_float>::infinity(),
-std::numeric_limits<cl_float>::infinity(),
std::numeric_limits<cl_float>::quiet_NaN()
};
}
bool use_ulp()
{
return true;
}
float ulp()
{
if(m_is_embedded)
{
return 0.0f;
}
return 0.0f;
}
private:
bool m_is_embedded;
};
// We need to specialize generate_kernel_unary<>() function template for fp_func_frexp.
// -----------------------------------------------------------------------------------
// ------------- ONLY FOR OPENCL 22 CONFORMANCE TEST 22 DEVELOPMENT ------------------
// -----------------------------------------------------------------------------------
#if defined(DEVELOPMENT) && defined(USE_OPENCLC_KERNELS)
template <>
std::string generate_kernel_unary<fp_func_frexp, cl_float, cl_float2>(fp_func_frexp func)
{
return
"__kernel void test_frexp(global float *input, global float2 *output)\n"
"{\n"
" size_t gid = get_global_id(0);\n"
" float2 result;\n"
" int itpr = 0;\n"
" result.x = frexp(input[gid], &itpr);\n"
" result.y = itpr;\n"
" output[gid] = result;\n"
"}\n";
}
#else
template <>
std::string generate_kernel_unary<fp_func_frexp, cl_float, cl_float2>(fp_func_frexp func)
{
return
"" + func.defs() +
"" + func.headers() +
"#include <opencl_memory>\n"
"#include <opencl_work_item>\n"
"using namespace cl;\n"
"__kernel void test_frexp(global_ptr<float[]> input, global_ptr<float2[]> output)\n"
"{\n"
" size_t gid = get_global_id(0);\n"
" float2 result;\n"
" int itpr = 0;\n"
" result.x = frexp(input[gid], &itpr);\n"
" result.y = itpr;\n"
" output[gid] = result;\n"
"}\n";
}
#endif
// -------------- BINARY FUNCTIONS
// gentype copysign(gentype x, gentype y);
// gentype fmod(gentype x, gentype y);
// gentype remainder(gentype x, gentype y);
// group_name, func_name, reference_func, use_ulp, ulp, ulp_for_embedded, max_delta, min1, max1, min2, max2
MATH_FUNCS_DEFINE_BINARY_FUNC(fp, copysign, std::copysign, true, 0.0f, 0.0f, 0.001f, -100.0f, 100.0f, -10.0f, 10.0f)
MATH_FUNCS_DEFINE_BINARY_FUNC(fp, fmod, std::fmod, true, 0.0f, 0.0f, 0.001f, -100.0f, 100.0f, -10.0f, 10.0f)
MATH_FUNCS_DEFINE_BINARY_FUNC(fp, remainder, std::remainder, true, 0.0f, 0.001f, 0.0f, -100.0f, 100.0f, -10.0f, 10.0f)
// In case of function float nextafter(float, float) reference function must
// operate on floats and return float.
struct fp_func_nextafter : public binary_func<cl_float, cl_float, cl_float>
{
fp_func_nextafter(bool is_embedded) : m_is_embedded(is_embedded)
{
}
std::string str()
{
return "nextafter";
}
std::string headers()
{
return "#include <opencl_math>\n";
}
/* In this case reference value type MUST BE cl_float */
cl_float operator()(const cl_float& x, const cl_float& y)
{
return (std::nextafter)(x, y);
}
cl_float min1()
{
return -1000.0f;
}
cl_float max1()
{
return 500.0f;
}
cl_float min2()
{
return 501.0f;
}
cl_float max2()
{
return 1000.0f;
}
std::vector<cl_float> in1_special_cases()
{
return {
cl_float(0.0f),
cl_float(-0.0f),
cl_float(1.0f),
cl_float(-1.0f),
cl_float(2.0f),
cl_float(-2.0f),
std::numeric_limits<cl_float>::infinity(),
-std::numeric_limits<cl_float>::infinity(),
std::numeric_limits<cl_float>::quiet_NaN()
};
}
std::vector<cl_float> in2_special_cases()
{
return {
cl_float(0.0f),
cl_float(-0.0f),
cl_float(1.0f),
cl_float(-1.0f),
cl_float(2.0f),
cl_float(-2.0f),
std::numeric_limits<cl_float>::infinity(),
-std::numeric_limits<cl_float>::infinity(),
std::numeric_limits<cl_float>::quiet_NaN()
};
}
bool use_ulp()
{
return true;
}
float ulp()
{
if(m_is_embedded)
{
return 0.0f;
}
return 0.0f;
}
private:
bool m_is_embedded;
};
// gentype remquo(gentype x, gentype y, intn* quo);
struct fp_func_remquo : public binary_func<cl_float, cl_float, cl_float2>
{
fp_func_remquo(bool is_embedded) : m_is_embedded(is_embedded)
{
}
std::string str()
{
return "remquo";
}
std::string headers()
{
return "#include <opencl_math>\n";
}
cl_double2 operator()(const cl_float& x, const cl_float& y)
{
return reference::remquo(static_cast<cl_double>(x), static_cast<cl_double>(y));
}
cl_float min1()
{
return -1000.0f;
}
cl_float max1()
{
return 1000.0f;
}
cl_float min2()
{
return -1000.0f;
}
cl_float max2()
{
return 1000.0f;
}
std::vector<cl_float> in1_special_cases()
{
return {
cl_float(0.0f),
cl_float(-0.0f),
cl_float(1.0f),
cl_float(-1.0f),
std::numeric_limits<cl_float>::infinity(),
-std::numeric_limits<cl_float>::infinity(),
std::numeric_limits<cl_float>::quiet_NaN()
};
}
std::vector<cl_float> in2_special_cases()
{
return {
cl_float(0.0f),
cl_float(-0.0f),
cl_float(1.0f),
cl_float(-1.0f),
std::numeric_limits<cl_float>::infinity(),
-std::numeric_limits<cl_float>::infinity(),
std::numeric_limits<cl_float>::quiet_NaN()
};
}
bool use_ulp()
{
return true;
}
float ulp()
{
if(m_is_embedded)
{
return 0.0f;
}
return 0.0f;
}
private:
bool m_is_embedded;
};
// We need to specialize generate_kernel_binary<>() function template for fp_func_remquo.
// -----------------------------------------------------------------------------------
// ------------- ONLY FOR OPENCL 22 CONFORMANCE TEST 22 DEVELOPMENT ------------------
// -----------------------------------------------------------------------------------
#if defined(DEVELOPMENT) && defined(USE_OPENCLC_KERNELS)
template <>
std::string generate_kernel_binary<fp_func_remquo, cl_float, cl_float, cl_float2>(fp_func_remquo func)
{
return
"__kernel void test_remquo(global float *input1, global float *input2, global float2 *output)\n"
"{\n"
" size_t gid = get_global_id(0);\n"
" float2 result;\n"
" int quo = 0;\n"
" int sign = 0;\n"
" result.x = remquo(input1[gid], input2[gid], &quo);\n"
// Specification say:
// "remquo also calculates the lower seven bits of the integral quotient x/y,
// and gives that value the same sign as x/y. It stores this signed value in
// the object pointed to by quo."
// Implemenation may save into quo more than seven bits. We need to take
// care of that here.
" sign = (quo < 0) ? -1 : 1;\n"
" quo = (quo < 0) ? -quo : quo;\n"
" quo &= 0x0000007f;\n"
" result.y = (sign < 0) ? -quo : quo;\n"
" output[gid] = result;\n"
"}\n";
}
#else
template <>
std::string generate_kernel_binary<fp_func_remquo, cl_float, cl_float, cl_float2>(fp_func_remquo func)
{
return
"" + func.defs() +
"" + func.headers() +
"#include <opencl_memory>\n"
"#include <opencl_work_item>\n"
"using namespace cl;\n"
"__kernel void test_remquo(global_ptr<float[]> input1, global_ptr<float[]> input2, global_ptr<float2[]> output)\n"
"{\n"
" size_t gid = get_global_id(0);\n"
" float2 result;\n"
" int quo = 0;\n"
" int sign = 0;\n"
" result.x = remquo(input1[gid], input2[gid], &quo);\n"
// Specification say:
// "remquo also calculates the lower seven bits of the integral quotient x/y,
// and gives that value the same sign as x/y. It stores this signed value in
// the object pointed to by quo."
// Implemenation may save into quo more than seven bits. We need to take
// care of that here.
" sign = (quo < 0) ? -1 : 1;\n"
" quo = (quo < 0) ? -quo : quo;\n"
" quo &= 0x0000007f;\n"
" result.y = (sign < 0) ? -quo : quo;\n"
" output[gid] = result;\n"
"}\n";
}
#endif
// -------------- TERNARY FUNCTIONS
// gentype fma(gentype a, gentype b, gentype c);
// group_name, func_name, reference_func, use_ulp, ulp, ulp_for_embedded, max_delta, min1, max1, min2, max2, min3, max3
MATH_FUNCS_DEFINE_TERNARY_FUNC(fp, fma, std::fma, true, 0.0f, 0.0f, 0.001f, -1000.0f, 1000.0f, -1000.0f, 1000.0f, -1000.0f, 1000.0f)
// floating point functions
AUTO_TEST_CASE(test_fp_funcs)
(cl_device_id device, cl_context context, cl_command_queue queue, int n_elems)
{
int error = CL_SUCCESS;
int last_error = CL_SUCCESS;
// Check for EMBEDDED_PROFILE
bool is_embedded_profile = false;
char profile[128];
last_error = clGetDeviceInfo(device, CL_DEVICE_PROFILE, sizeof(profile), (void *)&profile, NULL);
RETURN_ON_CL_ERROR(last_error, "clGetDeviceInfo")
if (std::strcmp(profile, "EMBEDDED_PROFILE") == 0)
is_embedded_profile = true;
// gentype ceil(gentype x);
TEST_UNARY_FUNC_MACRO((fp_func_ceil(is_embedded_profile)))
// gentype floor(gentype x);
TEST_UNARY_FUNC_MACRO((fp_func_floor(is_embedded_profile)))
// gentype rint(gentype x);
TEST_UNARY_FUNC_MACRO((fp_func_rint(is_embedded_profile)))
// gentype round(gentype x);
TEST_UNARY_FUNC_MACRO((fp_func_round(is_embedded_profile)))
// gentype trunc(gentype x);
TEST_UNARY_FUNC_MACRO((fp_func_trunc(is_embedded_profile)))
// floatn nan(uintn nancode);
TEST_UNARY_FUNC_MACRO((fp_func_nan()))
// gentype fract(gentype x, gentype* iptr);
TEST_UNARY_FUNC_MACRO((fp_func_fract(is_embedded_profile)))
// gentype modf(gentype x, gentype* iptr);
TEST_UNARY_FUNC_MACRO((fp_func_modf(is_embedded_profile)))
// gentype frexp(gentype x, intn* exp);
TEST_UNARY_FUNC_MACRO((fp_func_frexp(is_embedded_profile)))
// gentype remainder(gentype x, gentype y);
TEST_BINARY_FUNC_MACRO((fp_func_remainder(is_embedded_profile)))
// gentype copysign(gentype x, gentype y);
TEST_BINARY_FUNC_MACRO((fp_func_copysign(is_embedded_profile)))
// gentype fmod(gentype x, gentype y);
TEST_BINARY_FUNC_MACRO((fp_func_fmod(is_embedded_profile)))
// gentype nextafter(gentype x, gentype y);
TEST_BINARY_FUNC_MACRO((fp_func_nextafter(is_embedded_profile)))
// gentype remquo(gentype x, gentype y, intn* quo);
TEST_BINARY_FUNC_MACRO((fp_func_remquo(is_embedded_profile)))
// gentype fma(gentype a, gentype b, gentype c);
TEST_TERNARY_FUNC_MACRO((fp_func_fma(is_embedded_profile)))
if(error != CL_SUCCESS)
{
return -1;
}
return error;
}
#endif // TEST_CONFORMANCE_CLCPP_MATH_FUNCS_FP_FUNCS_HPP

View File

@@ -0,0 +1,106 @@
//
// 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_MATH_FUNCS_HALF_MATH_FUNCS_HPP
#define TEST_CONFORMANCE_CLCPP_MATH_FUNCS_HALF_MATH_FUNCS_HPP
#include <type_traits>
#include <cmath>
#include "common.hpp"
#if defined(DEVELOPMENT) && defined(USE_OPENCLC_KERNELS)
// group_name, func_name, reference_func, use_ulp, ulp, ulp_for_embedded, max_delta, min1, max1
MATH_FUNCS_DEFINE_UNARY_FUNC1(half_math, cos, half_cos, std::cos, true, 8192.0f, 8192.0f, 0.1f, -CL_M_PI_F, CL_M_PI_F)
MATH_FUNCS_DEFINE_UNARY_FUNC1(half_math, sin, half_sin, std::sin, true, 8192.0f, 8192.0f, 0.1f, -CL_M_PI_F, CL_M_PI_F)
MATH_FUNCS_DEFINE_UNARY_FUNC1(half_math, tan, half_tan, std::tan, true, 8192.0f, 8192.0f, 0.1f, -CL_M_PI_F, CL_M_PI_F)
MATH_FUNCS_DEFINE_UNARY_FUNC1(half_math, exp, half_exp, std::exp, true, 8192.0f, 8192.0f, 0.1f, -1000.0f, 1000.0f)
MATH_FUNCS_DEFINE_UNARY_FUNC1(half_math, exp2, half_exp2, std::exp2, true, 8192.0f, 8192.0f, 0.1f, -1000.0f, 1000.0f)
MATH_FUNCS_DEFINE_UNARY_FUNC1(half_math, exp10, half_exp10, reference::exp10, true, 8192.0f, 8192.0f, 0.1f, -1000.0f, 1000.0f)
MATH_FUNCS_DEFINE_UNARY_FUNC1(half_math, log, half_log, std::log, true, 8192.0f, 8192.0f, 0.1f, -1000.0f, 1000.0f)
MATH_FUNCS_DEFINE_UNARY_FUNC1(half_math, log2, half_log2, std::log2, true, 8192.0f, 8192.0f, 0.1f, -1000.0f, 1000.0f)
MATH_FUNCS_DEFINE_UNARY_FUNC1(half_math, log10, half_log10, std::log10, true, 8192.0f, 8192.0f, 0.1f, -1000.0f, 1000.0f)
MATH_FUNCS_DEFINE_UNARY_FUNC1(half_math, rsqrt, half_rsqrt, reference::rsqrt, true, 8192.0f, 8192.0f, 0.1f, -1000.0f, 1000.0f)
MATH_FUNCS_DEFINE_UNARY_FUNC1(half_math, sqrt, half_sqrt, std::sqrt, true, 8192.0f, 8192.0f, 0.1f, -1000.0f, 1000.0f)
MATH_FUNCS_DEFINE_UNARY_FUNC1(half_math, recip, half_recip, reference::recip, true, 8192.0f, 8192.0f, 0.1f, -1000.0f, 1000.0f)
// group_name, func_name, reference_func, use_ulp, ulp, ulp_for_embedded, max_delta, min1, max1, min2, max2
MATH_FUNCS_DEFINE_BINARY_FUNC1(half_math, divide, half_divide, reference::divide, true, 8192.0f, 8192.0f, 0.1f, -1024.0f, 1024.0f, -1024.0f, 1024.0f)
MATH_FUNCS_DEFINE_BINARY_FUNC1(half_math, powr, half_powr, reference::powr, true, 8192.0f, 8192.0f, 0.1f, -1024.0f, 1024.0f, -1024.0f, 1024.0f)
#else
// group_name, func_name, reference_func, use_ulp, ulp, ulp_for_embedded, max_delta, min1, max1
MATH_FUNCS_DEFINE_UNARY_FUNC1(half_math, cos, half_math::cos, std::cos, true, 8192.0f, 8192.0f, 0.1f, -CL_M_PI_F, CL_M_PI_F)
MATH_FUNCS_DEFINE_UNARY_FUNC1(half_math, sin, half_math::sin, std::sin, true, 8192.0f, 8192.0f, 0.1f, -CL_M_PI_F, CL_M_PI_F)
MATH_FUNCS_DEFINE_UNARY_FUNC1(half_math, tan, half_math::tan, std::tan, true, 8192.0f, 8192.0f, 0.1f, -CL_M_PI_F, CL_M_PI_F)
MATH_FUNCS_DEFINE_UNARY_FUNC1(half_math, exp, half_math::exp, std::exp, true, 8192.0f, 8192.0f, 0.1f, -1000.0f, 1000.0f)
MATH_FUNCS_DEFINE_UNARY_FUNC1(half_math, exp2, half_math::exp2, std::exp2, true, 8192.0f, 8192.0f, 0.1f, -1000.0f, 1000.0f)
MATH_FUNCS_DEFINE_UNARY_FUNC1(half_math, exp10, half_math::exp10, reference::exp10, true, 8192.0f, 8192.0f, 0.1f, -1000.0f, 1000.0f)
MATH_FUNCS_DEFINE_UNARY_FUNC1(half_math, log, half_math::log, std::log, true, 8192.0f, 8192.0f, 0.1f, -1000.0f, 1000.0f)
MATH_FUNCS_DEFINE_UNARY_FUNC1(half_math, log2, half_math::log2, std::log2, true, 8192.0f, 8192.0f, 0.1f, -1000.0f, 1000.0f)
MATH_FUNCS_DEFINE_UNARY_FUNC1(half_math, log10, half_math::log10, std::log10, true, 8192.0f, 8192.0f, 0.1f, -1000.0f, 1000.0f)
MATH_FUNCS_DEFINE_UNARY_FUNC1(half_math, rsqrt, half_math::rsqrt, reference::rsqrt, true, 8192.0f, 8192.0f, 0.1f, -1000.0f, 1000.0f)
MATH_FUNCS_DEFINE_UNARY_FUNC1(half_math, sqrt, half_math::sqrt, std::sqrt, true, 8192.0f, 8192.0f, 0.1f, -1000.0f, 1000.0f)
MATH_FUNCS_DEFINE_UNARY_FUNC1(half_math, recip, half_math::recip, reference::recip, true, 8192.0f, 8192.0f, 0.1f, -1000.0f, 1000.0f)
// group_name, func_name, reference_func, use_ulp, ulp, ulp_for_embedded, max_delta, min1, max1, min2, max2
MATH_FUNCS_DEFINE_BINARY_FUNC1(half_math, divide, half_math::divide, reference::divide, true, 8192.0f, 8192.0f, 0.1f, -1024.0f, 1024.0f, -1024.0f, 1024.0f)
MATH_FUNCS_DEFINE_BINARY_FUNC1(half_math, powr, half_math::powr, reference::powr, true, 8192.0f, 8192.0f, 0.1f, -1024.0f, 1024.0f, -1024.0f, 1024.0f)
#endif
// comparison functions
AUTO_TEST_CASE(test_half_math_funcs)
(cl_device_id device, cl_context context, cl_command_queue queue, int n_elems)
{
int error = CL_SUCCESS;
int last_error = CL_SUCCESS;
// Check for EMBEDDED_PROFILE
bool is_embedded_profile = false;
char profile[128];
last_error = clGetDeviceInfo(device, CL_DEVICE_PROFILE, sizeof(profile), (void *)&profile, NULL);
RETURN_ON_CL_ERROR(last_error, "clGetDeviceInfo")
if (std::strcmp(profile, "EMBEDDED_PROFILE") == 0)
is_embedded_profile = true;
TEST_UNARY_FUNC_MACRO((half_math_func_cos(is_embedded_profile)))
TEST_UNARY_FUNC_MACRO((half_math_func_sin(is_embedded_profile)))
TEST_UNARY_FUNC_MACRO((half_math_func_tan(is_embedded_profile)))
TEST_UNARY_FUNC_MACRO((half_math_func_exp(is_embedded_profile)))
TEST_UNARY_FUNC_MACRO((half_math_func_exp2(is_embedded_profile)))
TEST_UNARY_FUNC_MACRO((half_math_func_exp10(is_embedded_profile)))
TEST_UNARY_FUNC_MACRO((half_math_func_log(is_embedded_profile)))
TEST_UNARY_FUNC_MACRO((half_math_func_log2(is_embedded_profile)))
TEST_UNARY_FUNC_MACRO((half_math_func_log10(is_embedded_profile)))
TEST_BINARY_FUNC_MACRO((half_math_func_divide(is_embedded_profile)))
if(error != CL_SUCCESS)
{
return -1;
}
return error;
}
#endif // TEST_CONFORMANCE_CLCPP_MATH_FUNCS_HALF_MATH_FUNCS_HPP

View File

@@ -0,0 +1,260 @@
//
// 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_MATH_FUNCS_LOG_FUNCS_HPP
#define TEST_CONFORMANCE_CLCPP_MATH_FUNCS_LOG_FUNCS_HPP
#include <type_traits>
#include <cmath>
#include "common.hpp"
namespace detail
{
// This function reads values of FP_ILOGB0 and FP_ILOGBNAN macros defined on the device.
// OpenCL C++ Spec:
// The value of FP_ILOGB0 shall be either {INT_MIN} or {INT_MAX}. The value of FP_ILOGBNAN
// shall be either {INT_MAX} or {INT_MIN}.
int get_ilogb_nan_zero(cl_device_id device, cl_context context, cl_command_queue queue, cl_int& ilogb_nan, cl_int& ilogb_zero)
{
cl_mem buffers[1];
cl_program program;
cl_kernel kernel;
size_t work_size[1];
int err;
std::string code_str =
"__kernel void get_ilogb_nan_zero(__global int *out)\n"
"{\n"
" out[0] = FP_ILOGB0;\n"
" out[1] = FP_ILOGBNAN;\n"
"}\n";
std::string kernel_name("get_ilogb_nan_zero");
err = create_opencl_kernel(context, &program, &kernel, code_str, kernel_name, "-cl-std=CL2.0", false);
RETURN_ON_ERROR(err)
std::vector<cl_int> output = generate_output<cl_int>(2);
buffers[0] = clCreateBuffer(context, (cl_mem_flags)(CL_MEM_READ_WRITE), sizeof(cl_int) * output.size(), NULL, &err);
RETURN_ON_CL_ERROR(err, "clCreateBuffer")
err = clSetKernelArg(kernel, 0, sizeof(buffers[0]), &buffers[0]);
RETURN_ON_CL_ERROR(err, "clSetKernelArg");
work_size[0] = 1;
err = clEnqueueNDRangeKernel(queue, kernel, 1, NULL, work_size, NULL, 0, NULL, NULL);
RETURN_ON_CL_ERROR(err, "clEnqueueNDRangeKernel");
err = clEnqueueReadBuffer(
queue, buffers[0], CL_TRUE, 0, sizeof(cl_int) * output.size(),
static_cast<void *>(output.data()), 0, NULL, NULL
);
RETURN_ON_CL_ERROR(err, "clEnqueueReadBuffer");
// Save
ilogb_zero = output[0];
ilogb_nan = output[1];
clReleaseMemObject(buffers[0]);
clReleaseKernel(kernel);
clReleaseProgram(program);
return err;
}
} // namespace detail
struct logarithmic_func_ilogb : public unary_func<cl_float, cl_int>
{
logarithmic_func_ilogb(cl_int ilogb_nan, cl_int ilogb_zero)
: m_ilogb_nan(ilogb_nan), m_ilogb_zero(ilogb_zero)
{
}
std::string str()
{
return "ilogb";
}
std::string headers()
{
return "#include <opencl_math>\n";
}
cl_int operator()(const cl_float& x)
{
if((std::isnan)(x))
{
return m_ilogb_nan;
}
else if(x == 0.0 || x == -0.0)
{
return m_ilogb_zero;
}
static_assert(
sizeof(cl_int) == sizeof(int),
"Tests assumes that sizeof(cl_int) == sizeof(int)"
);
return (std::ilogb)(x);
}
cl_float min1()
{
return -100.0f;
}
cl_float max1()
{
return 1000.0f;
}
std::vector<cl_float> in1_special_cases()
{
return {
cl_float(0.0f),
cl_float(-0.0f),
cl_float(1.0f),
cl_float(-1.0f),
cl_float(2.0f),
cl_float(-2.0f),
std::numeric_limits<cl_float>::infinity(),
-std::numeric_limits<cl_float>::infinity(),
std::numeric_limits<cl_float>::quiet_NaN()
};
}
private:
cl_int m_ilogb_nan;
cl_int m_ilogb_zero;
};
// gentype log(gentype x);
// gentype logb(gentype x);
// gentype log2(gentype x);
// gentype log10(gentype x);
// gentype log1p(gentype x);
// group_name, func_name, reference_func, use_ulp, ulp, ulp_for_embedded, max_delta, min1, max1
MATH_FUNCS_DEFINE_UNARY_FUNC(logarithmic, log, std::log, true, 3.0f, 4.0f, 0.001f, -10.0f, 1000.0f)
MATH_FUNCS_DEFINE_UNARY_FUNC(logarithmic, logb, std::logb, true, 0.0f, 0.0f, 0.001f, -10.0f, 1000.0f)
MATH_FUNCS_DEFINE_UNARY_FUNC(logarithmic, log2, std::log2, true, 3.0f, 4.0f, 0.001f, -10.0f, 1000.0f)
MATH_FUNCS_DEFINE_UNARY_FUNC(logarithmic, log10, std::log10, true, 3.0f, 4.0f, 0.001f, -10.0f, 1000.0f)
MATH_FUNCS_DEFINE_UNARY_FUNC(logarithmic, log1p, std::log1p, true, 2.0f, 4.0f, 0.001f, -10.0f, 1000.0f)
// gentype lgamma(gentype x);
// OpenCL C++ Spec.:
// The ULP values for built-in math functions lgamma and lgamma_r is currently undefined.
// Because of that we don't check ULP and set acceptable delta to 0.2f (20%).
MATH_FUNCS_DEFINE_UNARY_FUNC(logarithmic, lgamma, std::lgamma, false, 0.0f, 0.0f, 0.2f, -10.0f, 1000.0f)
// gentype lgamma_r(gentype x, intn* signp);
// OpenCL C++ Spec.:
// The ULP values for built-in math functions lgamma and lgamma_r is currently undefined.
// Because of that we don't check ULP and set acceptable delta to 0.2f (20%).
//
// Note:
// We DO NOT test if sign of the gamma function return by lgamma_r is correct.
MATH_FUNCS_DEFINE_UNARY_FUNC(logarithmic, lgamma_r, std::lgamma, false, 0.0f, 0.0f, 0.2f, -10.0f, 1000.0f)
// We need to specialize generate_kernel_unary<>() function template for logarithmic_func_lgamma_r
// because it takes two arguments, but only one of it is input, the 2nd one is used to return
// the sign of the gamma function.
// -----------------------------------------------------------------------------------
// ------------- ONLY FOR OPENCL 22 CONFORMANCE TEST 22 DEVELOPMENT ------------------
// -----------------------------------------------------------------------------------
#if defined(DEVELOPMENT) && defined(USE_OPENCLC_KERNELS)
template <>
std::string generate_kernel_unary<logarithmic_func_lgamma_r, cl_float, cl_float>(logarithmic_func_lgamma_r func)
{
return
"__kernel void test_lgamma_r(global float *input, global float *output)\n"
"{\n"
" size_t gid = get_global_id(0);\n"
" int sign;\n"
" output[gid] = lgamma_r(input[gid], &sign);\n"
"}\n";
}
#else
template <>
std::string generate_kernel_unary<logarithmic_func_lgamma_r, cl_float, cl_float>(logarithmic_func_lgamma_r func)
{
return
"" + func.defs() +
"" + func.headers() +
"#include <opencl_memory>\n"
"#include <opencl_work_item>\n"
"using namespace cl;\n"
"__kernel void test_lgamma_r(global_ptr<float[]> input, global_ptr<float[]> output)\n"
"{\n"
" size_t gid = get_global_id(0);\n"
" int sign;\n"
" output[gid] = lgamma_r(input[gid], &sign);\n"
"}\n";
}
#endif
// logarithmic functions
AUTO_TEST_CASE(test_logarithmic_funcs)
(cl_device_id device, cl_context context, cl_command_queue queue, int n_elems)
{
int error = CL_SUCCESS;
int last_error = CL_SUCCESS;
// Check for EMBEDDED_PROFILE
bool is_embedded_profile = false;
char profile[128];
error = clGetDeviceInfo(device, CL_DEVICE_PROFILE, sizeof(profile), (void *)&profile, NULL);
RETURN_ON_CL_ERROR(error, "clGetDeviceInfo")
if (std::strcmp(profile, "EMBEDDED_PROFILE") == 0)
is_embedded_profile = true;
// Write values of FP_ILOGB0 and FP_ILOGBNAN, which are macros defined on the device, to
// ilogb_zero and ilogb_nan.
cl_int ilogb_nan = 0;
cl_int ilogb_zero = 0;
error = detail::get_ilogb_nan_zero(device, context, queue, ilogb_nan, ilogb_zero);
RETURN_ON_ERROR_MSG(error, "detail::get_ilogb_nan_zero function failed");
// intn ilogb(gentype x);
TEST_UNARY_FUNC_MACRO((logarithmic_func_ilogb(ilogb_nan, ilogb_zero)))
// gentype log(gentype x);
// gentype logb(gentype x);
// gentype log2(gentype x);
// gentype log10(gentype x);
// gentype log1p(gentype x);
TEST_UNARY_FUNC_MACRO((logarithmic_func_log(is_embedded_profile)))
TEST_UNARY_FUNC_MACRO((logarithmic_func_logb(is_embedded_profile)))
TEST_UNARY_FUNC_MACRO((logarithmic_func_log2(is_embedded_profile)))
TEST_UNARY_FUNC_MACRO((logarithmic_func_log10(is_embedded_profile)))
TEST_UNARY_FUNC_MACRO((logarithmic_func_log1p(is_embedded_profile)))
// gentype lgamma(gentype x);
TEST_UNARY_FUNC_MACRO((logarithmic_func_lgamma(is_embedded_profile)))
// gentype lgamma(gentype x);
//
// Note:
// We DO NOT test if sign of the gamma function return by lgamma_r is correct
TEST_UNARY_FUNC_MACRO((logarithmic_func_lgamma_r(is_embedded_profile)))
if(error != CL_SUCCESS)
{
return -1;
}
return error;
}
#endif // TEST_CONFORMANCE_CLCPP_MATH_FUNCS_LOG_FUNCS_HPP

View File

@@ -0,0 +1,55 @@
//
// 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.
//
#include <limits>
#include "../common.hpp"
#include "comparison_funcs.hpp"
#include "exponential_funcs.hpp"
#include "floating_point_funcs.hpp"
#include "half_math_funcs.hpp"
#include "logarithmic_funcs.hpp"
#include "other_funcs.hpp"
#include "power_funcs.hpp"
#include "trigonometric_funcs.hpp"
int main(int argc, const char *argv[])
{
// Check if cl_float (float) and cl_double (double) fulfill the requirements of
// IEC 559 (IEEE 754) standard. This is required for the tests to run correctly.
if(!std::numeric_limits<cl_float>::is_iec559)
{
RETURN_ON_ERROR_MSG(-1,
"cl_float (float) does not fulfill the requirements of IEC 559 (IEEE 754) standard. "
"Tests won't run correctly."
);
}
if(!std::numeric_limits<cl_double>::is_iec559)
{
RETURN_ON_ERROR_MSG(-1,
"cl_double (double) does not fulfill the requirements of IEC 559 (IEEE 754) standard. "
"Tests won't run correctly."
);
}
// Get list to all test functions
std::vector<basefn> testfn_list = autotest::test_suite::get_test_functions();
// Get names of all test functions
std::vector<std::string> testfn_names = autotest::test_suite::get_test_names();
// Create a vector of pointers to the names test functions
std::vector<const char *> testfn_names_c_str = autotest::get_strings_ptrs(testfn_names);
return runTestHarness(argc, argv, testfn_list.size(), testfn_list.data(), testfn_names_c_str.data(), false, false, 0);
}

View File

@@ -0,0 +1,75 @@
//
// 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_MATH_FUNCS_OTHER_FUNCS_HPP
#define TEST_CONFORMANCE_CLCPP_MATH_FUNCS_OTHER_FUNCS_HPP
#include <type_traits>
#include <cmath>
#include "common.hpp"
// group_name, func_name, reference_func, use_ulp, ulp, ulp_for_embedded, max_delta, min1, max1
MATH_FUNCS_DEFINE_UNARY_FUNC(other, erfc, std::erfc, true, 16.0f, 16.0f, 0.001f, -1000.0f, 1000.0f)
MATH_FUNCS_DEFINE_UNARY_FUNC(other, erf, std::erf, true, 16.0f, 16.0f, 0.001f, -1000.0f, 1000.0f)
MATH_FUNCS_DEFINE_UNARY_FUNC(other, fabs, std::fabs, true, 0.0f, 0.0f, 0.001f, -1000.0f, 1000.0f)
MATH_FUNCS_DEFINE_UNARY_FUNC(other, tgamma, std::tgamma, true, 16.0f, 16.0f, 0.001f, -1000.0f, 1000.0f)
// group_name, func_name, reference_func, use_ulp, ulp, ulp_for_embedded, max_delta, min1, max1, min2, max2
MATH_FUNCS_DEFINE_BINARY_FUNC(other, hypot, std::hypot, true, 4.0f, 4.0f, 0.001f, -1000.0f, 1000.0f, -1000.0f, 1000.0f)
// group_name, func_name, reference_func, use_ulp, ulp, ulp_for_embedded, max_delta, min1, max1, min2, max2, min3, max3
MATH_FUNCS_DEFINE_TERNARY_FUNC(other, mad, reference::mad, false, 0.0f, 0.0f, 0.1f, -10.0f, 10.0f, -10.0f, 10.0f, -10.0f, 10.0f)
// other functions
AUTO_TEST_CASE(test_other_funcs)
(cl_device_id device, cl_context context, cl_command_queue queue, int n_elems)
{
int error = CL_SUCCESS;
int last_error = CL_SUCCESS;
// Check for EMBEDDED_PROFILE
bool is_embedded_profile = false;
char profile[128];
last_error = clGetDeviceInfo(device, CL_DEVICE_PROFILE, sizeof(profile), (void *)&profile, NULL);
RETURN_ON_CL_ERROR(last_error, "clGetDeviceInfo")
if (std::strcmp(profile, "EMBEDDED_PROFILE") == 0)
is_embedded_profile = true;
// gentype erf(gentype x);
// gentype erfc(gentype x);
TEST_UNARY_FUNC_MACRO((other_func_erfc(is_embedded_profile)))
TEST_UNARY_FUNC_MACRO((other_func_erf(is_embedded_profile)))
// gentype fabs(gentype x);
TEST_UNARY_FUNC_MACRO((other_func_fabs(is_embedded_profile)))
// gentype tgamma(gentype x);
TEST_UNARY_FUNC_MACRO((other_func_tgamma(is_embedded_profile)))
// gentype hypot(gentype x, gentype y);
TEST_BINARY_FUNC_MACRO((other_func_hypot(is_embedded_profile)))
// gentype mad(gentype a, gentype b, gentype c);
TEST_TERNARY_FUNC_MACRO((other_func_mad(is_embedded_profile)))
if(error != CL_SUCCESS)
{
return -1;
}
return error;
}
#endif // TEST_CONFORMANCE_CLCPP_MATH_FUNCS_OTHER_FUNCS_HPP

View File

@@ -0,0 +1,153 @@
//
// 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_MATH_FUNCS_POWER_FUNCS_HPP
#define TEST_CONFORMANCE_CLCPP_MATH_FUNCS_POWER_FUNCS_HPP
#include <limits>
#include <type_traits>
#include <cmath>
#include "common.hpp"
#define DEFINE_BINARY_POWER_FUNC_INT(NAME, HOST_FUNC, USE_ULP, ULP, ULP_EMBEDDED, MIN1, MAX1, MIN2, MAX2) \
struct power_func_ ## NAME : public binary_func<cl_float, cl_int, cl_float> \
{ \
power_func_ ## NAME(bool is_embedded) : m_is_embedded(is_embedded) \
{ \
\
} \
\
std::string str() \
{ \
return #NAME; \
} \
\
std::string headers() \
{ \
return "#include <opencl_math>\n"; \
} \
/* Reference value type is cl_double */ \
cl_double operator()(const cl_float& x, const cl_int& y) \
{ \
return (HOST_FUNC)(static_cast<cl_double>(x), y); \
} \
\
cl_float min1() \
{ \
return MIN1; \
} \
\
cl_float max1() \
{ \
return MAX1; \
} \
\
cl_int min2() \
{ \
return MIN2; \
} \
\
cl_int max2() \
{ \
return MAX2; \
} \
\
std::vector<cl_float> in1_special_cases() \
{ \
return { \
cl_float(-1.0f), \
cl_float(0.0f), \
cl_float(-0.0f), \
}; \
} \
\
std::vector<cl_int> in2_special_cases() \
{ \
return { \
2, 3, -1, 1, -2, 2 \
}; \
} \
\
bool use_ulp() \
{ \
return USE_ULP; \
} \
\
float ulp() \
{ \
if(m_is_embedded) \
{ \
return ULP_EMBEDDED; \
} \
return ULP; \
} \
private: \
bool m_is_embedded; \
};
// group_name, func_name, reference_func, use_ulp, ulp, ulp_for_embedded, max_delta, min1, max1
MATH_FUNCS_DEFINE_UNARY_FUNC(power, cbrt, std::cbrt, true, 2.0f, 4.0f, 0.001f, -1000.0f, -9.0f)
MATH_FUNCS_DEFINE_UNARY_FUNC(power, rsqrt, reference::rsqrt, true, 2.0f, 4.0f, 0.001f, 1.0f, 100.0f)
MATH_FUNCS_DEFINE_UNARY_FUNC(power, sqrt, std::sqrt, true, 3.0f, 4.0f, 0.001f, 1.0f, 100.0f)
// group_name, func_name, reference_func, use_ulp, ulp, ulp_for_embedded, max_delta, min1, max1, min2, max2
MATH_FUNCS_DEFINE_BINARY_FUNC(power, pow, std::pow, true, 16.0f, 16.0f, 0.001f, 1.0f, 100.0f, 1.0f, 10.0f)
MATH_FUNCS_DEFINE_BINARY_FUNC(power, powr, reference::powr, true, 16.0f, 16.0f, 0.001f, 1.0f, 100.0f, 1.0f, 10.0f)
// func_name, reference_func, use_ulp, ulp, ulp_for_embedded, min1, max1, min2, max2
DEFINE_BINARY_POWER_FUNC_INT(pown, std::pow, true, 16.0f, 16.0f, 1.0f, 100.0f, 1, 10)
DEFINE_BINARY_POWER_FUNC_INT(rootn, reference::rootn, true, 16.0f, 16.0f, -100.0f, 100.0f, -10, 10)
// power functions
AUTO_TEST_CASE(test_power_funcs)
(cl_device_id device, cl_context context, cl_command_queue queue, int n_elems)
{
int error = CL_SUCCESS;
int last_error = CL_SUCCESS;
// Check for EMBEDDED_PROFILE
bool is_embedded_profile = false;
char profile[128];
last_error = clGetDeviceInfo(device, CL_DEVICE_PROFILE, sizeof(profile), (void *)&profile, NULL);
RETURN_ON_CL_ERROR(last_error, "clGetDeviceInfo")
if (std::strcmp(profile, "EMBEDDED_PROFILE") == 0)
is_embedded_profile = true;
// gentype cbrt(gentype x);
// gentype rsqrt(gentype x);
// gentype sqrt(gentype x);
TEST_UNARY_FUNC_MACRO((power_func_cbrt(is_embedded_profile)))
TEST_UNARY_FUNC_MACRO((power_func_sqrt(is_embedded_profile)))
TEST_UNARY_FUNC_MACRO((power_func_rsqrt(is_embedded_profile)))
// gentype pow(gentype x, gentype y);
// gentype powr(gentype x, gentype y);
TEST_BINARY_FUNC_MACRO((power_func_pow(is_embedded_profile)))
TEST_BINARY_FUNC_MACRO((power_func_powr(is_embedded_profile)))
// gentype pown(gentype x, intn y);
// gentype rootn(gentype x, intn y);
TEST_BINARY_FUNC_MACRO((power_func_pown(is_embedded_profile)))
TEST_BINARY_FUNC_MACRO((power_func_rootn(is_embedded_profile)))
if(error != CL_SUCCESS)
{
return -1;
}
return error;
}
#endif // TEST_CONFORMANCE_CLCPP_MATH_FUNCS_POWER_FUNCS_HPP

View File

@@ -0,0 +1,315 @@
//
// 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_MATH_FUNCS_REFERENCE_HPP
#define TEST_CONFORMANCE_CLCPP_MATH_FUNCS_REFERENCE_HPP
#include <type_traits>
#include <cmath>
#include <limits>
#include "../common.hpp"
namespace reference
{
// Reference functions for OpenCL comparison functions that
// are not already defined in STL.
cl_float maxmag(const cl_float& x, const cl_float& y)
{
if((std::abs)(x) > (std::abs)(y))
{
return x;
}
else if((std::abs)(y) > (std::abs)(x))
{
return y;
}
return (std::fmax)(x, y);
}
cl_float minmag(const cl_float& x, const cl_float& y)
{
if((std::abs)(x) < (std::abs)(y))
{
return x;
}
else if((std::abs)(y) < (std::abs)(x))
{
return y;
}
return (std::fmin)(x, y);
}
// Reference functions for OpenCL exp functions that
// are not already defined in STL.
cl_double exp10(const cl_double& x)
{
// 10^x = exp2( x * log2(10) )
auto log2_10 = (std::log2)(static_cast<long double>(10.0));
cl_double x_log2_10 = static_cast<cl_double>(x * log2_10);
return (std::exp2)(x_log2_10);
}
// Reference functions for OpenCL floating point functions that
// are not already defined in STL.
cl_double2 fract(cl_double x)
{
// Copied from math_brute_force/reference_math.c
cl_double2 r;
if((std::isnan)(x))
{
r.s[0] = std::numeric_limits<cl_double>::quiet_NaN();
r.s[1] = std::numeric_limits<cl_double>::quiet_NaN();
return r;
}
r.s[0] = (std::modf)(x, &(r.s[1]));
if(r.s[0] < 0.0 )
{
r.s[0] = 1.0f + r.s[0];
r.s[1] -= 1.0f;
if( r.s[0] == 1.0f )
r.s[0] = HEX_FLT(+, 1, fffffe, -, 1);
}
return r;
}
cl_double2 remquo(cl_double x, cl_double y)
{
cl_double2 r;
// remquo return the same value that is returned by the
// remainder function
r.s[0] = (std::remainder)(x,y);
// calulcate quo
cl_double x_y = (x - r.s[0]) / y;
cl_uint quo = (std::abs)(x_y);
r.s[1] = quo & 0x0000007fU;
if(x_y < 0.0)
r.s[1] = -r.s[1];
// fix edge cases
if(!(std::isnan)(x) && y == 0.0)
{
r.s[1] = 0;
}
else if((std::isnan)(x) && (std::isnan)(y))
{
r.s[1] = 0;
}
return r;
}
// Reference functions for OpenCL half_math:: functions that
// are not already defined in STL.
cl_double divide(cl_double x, cl_double y)
{
return x / y;
}
cl_double recip(cl_double x)
{
return 1.0 / x;
}
// Reference functions for OpenCL other functions that
// are not already defined in STL.
cl_double mad(cl_double x, cl_double y, cl_double z)
{
return (x * y) + z;
}
// Reference functions for OpenCL power functions that
// are not already defined in STL.
cl_double rsqrt(const cl_double& x)
{
return cl_double(1.0) / ((std::sqrt)(x));
}
cl_double powr(const cl_double& x, const cl_double& y)
{
//powr(x, y) returns NaN for x < 0.
if( x < 0.0 )
return std::numeric_limits<cl_double>::quiet_NaN();
//powr ( x, NaN ) returns the NaN for x >= 0.
//powr ( NaN, y ) returns the NaN.
if((std::isnan)(x) || (std::isnan)(y) )
return std::numeric_limits<cl_double>::quiet_NaN();
if( x == 1.0 )
{
//powr ( +1, +-inf ) returns NaN.
if((std::abs)(y) == INFINITY )
return std::numeric_limits<cl_double>::quiet_NaN();
//powr ( +1, y ) is 1 for finite y. (NaN handled above)
return 1.0;
}
if( y == 0.0 )
{
//powr ( +inf, +-0 ) returns NaN.
//powr ( +-0, +-0 ) returns NaN.
if( x == 0.0 || x == std::numeric_limits<cl_double>::infinity())
return std::numeric_limits<cl_double>::quiet_NaN();
//powr ( x, +-0 ) is 1 for finite x > 0. (x <= 0, NaN, INF already handled above)
return 1.0;
}
if( x == 0.0 )
{
//powr ( +-0, -inf) is +inf.
//powr ( +-0, y ) is +inf for finite y < 0.
if( y < 0.0 )
return std::numeric_limits<cl_double>::infinity();
//powr ( +-0, y ) is +0 for y > 0. (NaN, y==0 handled above)
return 0.0;
}
// x = +inf
if( (std::isinf)(x) )
{
if( y < 0 )
return 0;
return std::numeric_limits<cl_double>::infinity();
}
double fabsx = (std::abs)(x);
double fabsy = (std::abs)(y);
//y = +-inf cases
if( (std::isinf)(fabsy) )
{
if( y < 0.0 )
{
if( fabsx < 1.0 )
return std::numeric_limits<cl_double>::infinity();
return 0;
}
if( fabsx < 1.0 )
return 0.0;
return std::numeric_limits<cl_double>::infinity();
}
return (std::pow)(x, y);
}
cl_double rootn(const cl_double& x, const cl_int n)
{
//rootn (x, 0) returns a NaN.
if(n == 0)
return std::numeric_limits<cl_double>::quiet_NaN();
//rootn ( x, n ) returns a NaN for x < 0 and n is even.
if(x < 0 && 0 == (n & 1))
return std::numeric_limits<cl_double>::quiet_NaN();
if(x == 0.0)
{
if(n > 0)
{
//rootn ( +-0, n ) is +0 for even n > 0.
if(0 == (n & 1))
{
return cl_double(0.0);
}
//rootn ( +-0, n ) is +-0 for odd n > 0.
else
{
return x;
}
}
else
{
//rootn ( +-0, n ) is +inf for even n < 0.
if(0 == ((-n) & 1))
{
return std::numeric_limits<cl_double>::infinity();
}
//rootn ( +-0, n ) is +-inf for odd n < 0.
else
{
return (std::copysign)(
std::numeric_limits<cl_double>::infinity(), x
);
}
}
}
cl_double r = (std::abs)(x);
r = (std::exp2)((std::log2)(r) / static_cast<cl_double>(n));
return (std::copysign)(r, x);
}
// Reference functions for OpenCL trigonometric functions that
// are not already defined in STL.
cl_double acospi(cl_double x)
{
return (std::acos)(x) / CL_M_PI;
}
cl_double asinpi(cl_double x)
{
return (std::asin)(x) / CL_M_PI;
}
cl_double atanpi(cl_double x)
{
return (std::atan)(x) / CL_M_PI;
}
cl_double cospi(cl_double x)
{
return (std::cos)(x * CL_M_PI);
}
cl_double sinpi(cl_double x)
{
return (std::sin)(x * CL_M_PI);
}
cl_double tanpi(cl_double x)
{
return (std::tan)(x * CL_M_PI);
}
cl_double atan2(cl_double x, cl_double y)
{
#if defined(WIN32) || defined(_WIN32)
// Fix edge cases for Windows
if ((std::isinf)(x) && (std::isinf)(y)) {
cl_double retval = (y > 0) ? CL_M_PI_4 : 3.f * CL_M_PI_4;
return (x > 0) ? retval : -retval;
}
#endif // defined(WIN32) || defined(_WIN32)
return (std::atan2)(x, y);
}
cl_double atan2pi(cl_double x, cl_double y)
{
return ::reference::atan2(x, y) / CL_M_PI;
}
cl_double2 sincos(cl_double x)
{
cl_double2 r;
r.s[0] = (std::sin)(x);
r.s[1] = (std::cos)(x);
return r;
}
}
#endif // TEST_CONFORMANCE_CLCPP_MATH_FUNCS_REFERENCE_HPP

View File

@@ -0,0 +1,222 @@
//
// 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_MATH_FUNCS_TRI_FUNCS_HPP
#define TEST_CONFORMANCE_CLCPP_MATH_FUNCS_TRI_FUNCS_HPP
#include <type_traits>
#include <cmath>
#include "common.hpp"
// group_name, func_name, reference_func, use_ulp, ulp, ulp_for_embedded, max_delta, min1, max1
MATH_FUNCS_DEFINE_UNARY_FUNC(trigonometric, acos, std::acos, true, 4.0f, 4.0f, 0.001f, -1.0f, 1.0f)
MATH_FUNCS_DEFINE_UNARY_FUNC(trigonometric, acosh, std::acosh, true, 4.0f, 4.0f, 0.001f, -1.0f, 1.0f)
MATH_FUNCS_DEFINE_UNARY_FUNC(trigonometric, acospi, reference::acospi, true, 5.0f, 5.0f, 0.001f, -1.0f, 1.0f)
MATH_FUNCS_DEFINE_UNARY_FUNC(trigonometric, asin, std::asin, true, 4.0f, 4.0f, 0.001f, -1.0f, 1.0f)
MATH_FUNCS_DEFINE_UNARY_FUNC(trigonometric, asinh, std::asinh, true, 4.0f, 4.0f, 0.001f, -1.0f, 1.0f)
MATH_FUNCS_DEFINE_UNARY_FUNC(trigonometric, asinpi, reference::asinpi, true, 5.0f, 5.0f, 0.001f, -1.0f, 1.0f)
MATH_FUNCS_DEFINE_UNARY_FUNC(trigonometric, atan, std::atan, true, 5.0f, 5.0f, 0.001f, -1.0f, 1.0f)
MATH_FUNCS_DEFINE_UNARY_FUNC(trigonometric, atanh, std::atanh, true, 5.0f, 5.0f, 0.001f, -1.0f, 1.0f)
MATH_FUNCS_DEFINE_UNARY_FUNC(trigonometric, atanpi, reference::atanpi, true, 5.0f, 5.0f, 0.001f, -1.0f, 1.0f)
// For (sin/cos/tan)pi functions min input value is -0.24 and max input value is 0.24,
// so (CL_M_PI * x) is never greater than CL_M_PI_F.
// group_name, func_name, reference_func, use_ulp, ulp, ulp_for_embedded, max_delta, min1, max1
MATH_FUNCS_DEFINE_UNARY_FUNC(trigonometric, cos, std::cos, true, 4.0f, 4.0f, 0.001f, -CL_M_PI_F, CL_M_PI_F)
MATH_FUNCS_DEFINE_UNARY_FUNC(trigonometric, cosh, std::cosh, true, 4.0f, 4.0f, 0.001f, -CL_M_PI_F, CL_M_PI_F)
MATH_FUNCS_DEFINE_UNARY_FUNC(trigonometric, cospi, reference::cospi, true, 4.0f, 4.0f, 0.001f, -0.24, -0.24f)
MATH_FUNCS_DEFINE_UNARY_FUNC(trigonometric, sin, std::sin, true, 4.0f, 4.0f, 0.001f, -CL_M_PI_F, CL_M_PI_F)
MATH_FUNCS_DEFINE_UNARY_FUNC(trigonometric, sinh, std::sinh, true, 4.0f, 4.0f, 0.001f, -CL_M_PI_F, CL_M_PI_F)
MATH_FUNCS_DEFINE_UNARY_FUNC(trigonometric, sinpi, reference::sinpi, true, 4.0f, 4.0f, 0.001f, -0.24, -0.24f)
MATH_FUNCS_DEFINE_UNARY_FUNC(trigonometric, tan, std::tan, true, 5.0f, 5.0f, 0.001f, -CL_M_PI_F, CL_M_PI_F)
MATH_FUNCS_DEFINE_UNARY_FUNC(trigonometric, tanh, std::tanh, true, 5.0f, 5.0f, 0.001f, -CL_M_PI_F, CL_M_PI_F)
MATH_FUNCS_DEFINE_UNARY_FUNC(trigonometric, tanpi, reference::tanpi, true, 6.0f, 6.0f, 0.001f, -0.24, -0.24f)
// group_name, func_name, reference_func, use_ulp, ulp, ulp_for_embedded, max_delta, min1, max1, min2, max2
MATH_FUNCS_DEFINE_BINARY_FUNC(trigonometric, atan2, reference::atan2, true, 6.0f, 6.0f, 0.001f, -1.0f, 1.0f, -1.0f, 1.0f)
MATH_FUNCS_DEFINE_BINARY_FUNC(trigonometric, atan2pi, reference::atan2pi, true, 6.0f, 6.0f, 0.001f, -1.0f, 1.0f, -1.0f, 1.0f)
// gentype sincos(gentype x, gentype * cosval);
//
// Fact that second argument is a pointer is inconvenient.
//
// We don't want to modify all helper functions defined in funcs_test_utils.hpp
// that run test kernels generated based on this class and check if results are
// correct, so instead of having two output cl_float buffers, one for sines and
// one for cosines values, we use one cl_float2 output buffer (first component is
// sine, second is cosine).
//
// Below we also define specialization of generate_kernel_unary function template
// for trigonometric_func_sincos.
struct trigonometric_func_sincos : public unary_func<cl_float, cl_float2>
{
trigonometric_func_sincos(bool is_embedded) : m_is_embedded(is_embedded)
{
}
std::string str()
{
return "sincos";
}
std::string headers()
{
return "#include <opencl_math>\n";
}
/* Reference value type is cl_double */
cl_double2 operator()(const cl_float& x)
{
return (reference::sincos)(static_cast<cl_double>(x));
}
cl_float min1()
{
return -CL_M_PI_F;
}
cl_float max1()
{
return CL_M_PI_F;
}
bool use_ulp()
{
return true;
}
float ulp()
{
if(m_is_embedded)
{
return 4.0f;
}
return 4.0f;
}
private:
bool m_is_embedded;
};
// -----------------------------------------------------------------------------------
// ------------- ONLY FOR OPENCL 22 CONFORMANCE TEST 22 DEVELOPMENT ------------------
// -----------------------------------------------------------------------------------
#if defined(DEVELOPMENT) && defined(USE_OPENCLC_KERNELS)
template <>
std::string generate_kernel_unary<trigonometric_func_sincos, cl_float, cl_float2>(trigonometric_func_sincos func)
{
return
"__kernel void test_sincos(global float *input, global float2 *output)\n"
"{\n"
" size_t gid = get_global_id(0);\n"
" float2 sine_cosine_of_x;\n"
" float cosine_of_x = 0;\n"
" sine_cosine_of_x.x = sincos(input[gid], &(cosine_of_x));\n"
" sine_cosine_of_x.y = cosine_of_x;\n"
" output[gid] = sine_cosine_of_x;\n"
"}\n";
}
#else
template <>
std::string generate_kernel_unary<trigonometric_func_sincos, cl_float, cl_float2>(trigonometric_func_sincos func)
{
return
"" + func.defs() +
"" + func.headers() +
"#include <opencl_memory>\n"
"#include <opencl_work_item>\n"
"using namespace cl;\n"
"__kernel void test_sincos(global_ptr<float[]> input, global_ptr<float2[]> output)\n"
"{\n"
" size_t gid = get_global_id(0);\n"
" float2 sine_cosine_of_x;\n"
" float cosine_of_x = 0;\n"
" sine_cosine_of_x.x = sincos(input[gid], &(cosine_of_x));\n"
" sine_cosine_of_x.y = cosine_of_x;\n"
" output[gid] = sine_cosine_of_x;\n"
"}\n";
}
#endif
// trigonometric functions
AUTO_TEST_CASE(test_trigonometric_funcs)
(cl_device_id device, cl_context context, cl_command_queue queue, int n_elems)
{
int error = CL_SUCCESS;
int last_error = CL_SUCCESS;
// Check for EMBEDDED_PROFILE
bool is_embedded_profile = false;
char profile[128];
last_error = clGetDeviceInfo(device, CL_DEVICE_PROFILE, sizeof(profile), (void *)&profile, NULL);
RETURN_ON_CL_ERROR(last_error, "clGetDeviceInfo")
if (std::strcmp(profile, "EMBEDDED_PROFILE") == 0)
is_embedded_profile = true;
// gentype acos(gentype x);
// gentype acosh(gentype x);
// gentype acospi(gentype x);
// gentype asin(gentype x);
// gentype asinh(gentype x);
// gentype asinpi(gentype x);
// gentype atan(gentype x);
// gentype atanh(gentype x);
// gentype atanpi(gentype x);
TEST_UNARY_FUNC_MACRO((trigonometric_func_acos(is_embedded_profile)))
TEST_UNARY_FUNC_MACRO((trigonometric_func_acosh(is_embedded_profile)))
TEST_UNARY_FUNC_MACRO((trigonometric_func_acospi(is_embedded_profile)))
TEST_UNARY_FUNC_MACRO((trigonometric_func_asin(is_embedded_profile)))
TEST_UNARY_FUNC_MACRO((trigonometric_func_asinh(is_embedded_profile)))
TEST_UNARY_FUNC_MACRO((trigonometric_func_asinpi(is_embedded_profile)))
TEST_UNARY_FUNC_MACRO((trigonometric_func_atan(is_embedded_profile)))
TEST_UNARY_FUNC_MACRO((trigonometric_func_atanh(is_embedded_profile)))
TEST_UNARY_FUNC_MACRO((trigonometric_func_atanpi(is_embedded_profile)))
// gentype cos(gentype x);
// gentype cosh(gentype x);
// gentype cospi(gentype x);
// gentype sin(gentype x);
// gentype sinh(gentype x);
// gentype sinpi(gentype x);
// gentype tan(gentype x);
// gentype tanh(gentype x);
// gentype tanpi(gentype x);
TEST_UNARY_FUNC_MACRO((trigonometric_func_cos(is_embedded_profile)))
TEST_UNARY_FUNC_MACRO((trigonometric_func_cosh(is_embedded_profile)))
TEST_UNARY_FUNC_MACRO((trigonometric_func_cospi(is_embedded_profile)))
TEST_UNARY_FUNC_MACRO((trigonometric_func_sin(is_embedded_profile)))
TEST_UNARY_FUNC_MACRO((trigonometric_func_sinh(is_embedded_profile)))
TEST_UNARY_FUNC_MACRO((trigonometric_func_sinpi(is_embedded_profile)))
TEST_UNARY_FUNC_MACRO((trigonometric_func_tan(is_embedded_profile)))
TEST_UNARY_FUNC_MACRO((trigonometric_func_tanh(is_embedded_profile)))
TEST_UNARY_FUNC_MACRO((trigonometric_func_tanpi(is_embedded_profile)))
// gentype atan2(gentype y, gentype x);
// gentype atan2pi(gentype y, gentype x);
TEST_BINARY_FUNC_MACRO((trigonometric_func_atan2(is_embedded_profile)))
TEST_BINARY_FUNC_MACRO((trigonometric_func_atan2pi(is_embedded_profile)))
// gentype sincos(gentype x, gentype * cosval);
TEST_UNARY_FUNC_MACRO((trigonometric_func_sincos(is_embedded_profile)))
if(error != CL_SUCCESS)
{
return -1;
}
return error;
}
#endif // TEST_CONFORMANCE_CLCPP_MATH_FUNCS_TRI_FUNCS_HPP