mirror of
https://github.com/KhronosGroup/OpenCL-CTS.git
synced 2026-03-23 15:39:03 +00:00
Initial open source release of OpenCL 2.2 CTS.
This commit is contained in:
12
test_conformance/clcpp/vload_vstore/CMakeLists.txt
Normal file
12
test_conformance/clcpp/vload_vstore/CMakeLists.txt
Normal file
@@ -0,0 +1,12 @@
|
||||
set(MODULE_NAME CPP_VLOAD_VSTORE_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)
|
||||
81
test_conformance/clcpp/vload_vstore/common.hpp
Normal file
81
test_conformance/clcpp/vload_vstore/common.hpp
Normal file
@@ -0,0 +1,81 @@
|
||||
//
|
||||
// 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_RELATIONAL_FUNCS_COMMON_HPP
|
||||
#define TEST_CONFORMANCE_CLCPP_RELATIONAL_FUNCS_COMMON_HPP
|
||||
|
||||
#include <type_traits>
|
||||
#include <cmath>
|
||||
|
||||
#include "../common.hpp"
|
||||
#include "../funcs_test_utils.hpp"
|
||||
|
||||
#include "half_utils.hpp"
|
||||
|
||||
// Generates cl_half input
|
||||
std::vector<cl_half> generate_half_input(size_t count,
|
||||
const cl_float& min,
|
||||
const cl_float& max,
|
||||
const std::vector<cl_half> special_cases)
|
||||
{
|
||||
std::vector<cl_half> input(count);
|
||||
std::random_device rd;
|
||||
std::mt19937 gen(rd());
|
||||
std::uniform_real_distribution<cl_float> dis(min, max);
|
||||
for(auto& i : input)
|
||||
{
|
||||
i = float2half_rte(dis(gen));
|
||||
}
|
||||
|
||||
input.insert(input.begin(), special_cases.begin(), special_cases.end());
|
||||
input.resize(count);
|
||||
return input;
|
||||
}
|
||||
|
||||
// Generates input for vload_vstore tests, we can't just simply use function
|
||||
// generate_input<type>(...), because cl_half is typedef of cl_short (but generating
|
||||
// cl_shorts and generating cl_halfs are different operations).
|
||||
template <class type>
|
||||
std::vector<type> vload_vstore_generate_input(size_t count,
|
||||
const type& min,
|
||||
const type& max,
|
||||
const std::vector<type> special_cases,
|
||||
const bool generate_half,
|
||||
typename std::enable_if<
|
||||
std::is_same<type, cl_half>::value
|
||||
>::type* = 0)
|
||||
{
|
||||
if(!generate_half)
|
||||
{
|
||||
return generate_input<type>(count, min, max, special_cases);
|
||||
}
|
||||
return generate_half_input(count, -(CL_HALF_MAX/4.f), (CL_HALF_MAX/4.f), special_cases);
|
||||
}
|
||||
|
||||
// If !std::is_same<type, cl_half>::value, we can just use generate_input<type>(...).
|
||||
template <class type>
|
||||
std::vector<type> vload_vstore_generate_input(size_t count,
|
||||
const type& min,
|
||||
const type& max,
|
||||
const std::vector<type> special_cases,
|
||||
const bool generate_half,
|
||||
typename std::enable_if<
|
||||
!std::is_same<type, cl_half>::value
|
||||
>::type* = 0)
|
||||
{
|
||||
return generate_input<type>(count, min, max, special_cases);
|
||||
}
|
||||
|
||||
#endif // TEST_CONFORMANCE_CLCPP_RELATIONAL_FUNCS_COMMON_HPP
|
||||
136
test_conformance/clcpp/vload_vstore/half_utils.hpp
Normal file
136
test_conformance/clcpp/vload_vstore/half_utils.hpp
Normal file
@@ -0,0 +1,136 @@
|
||||
//
|
||||
// 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_HALF_UTILS_HPP
|
||||
#define TEST_CONFORMANCE_CLCPP_HALF_UTILS_HPP
|
||||
|
||||
#include "../common.hpp"
|
||||
#include "../funcs_test_utils.hpp"
|
||||
|
||||
#include <cmath>
|
||||
|
||||
namespace detail
|
||||
{
|
||||
|
||||
template<class INT_TYPE>
|
||||
inline int clz(INT_TYPE x)
|
||||
{
|
||||
int count = 0;
|
||||
if(std::is_unsigned<INT_TYPE>::value)
|
||||
{
|
||||
cl_ulong value = x;
|
||||
value <<= 8 * sizeof(value) - (8 * sizeof(x));
|
||||
for(count = 0; 0 == (value & (CL_LONG_MIN)); count++)
|
||||
{
|
||||
value <<= 1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
cl_long value = x;
|
||||
value <<= 8 * sizeof(value) - (8 * sizeof(x));
|
||||
for(count = 0; 0 == (value & (CL_LONG_MIN)); count++)
|
||||
{
|
||||
value <<= 1;
|
||||
}
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
} // namespace detail
|
||||
|
||||
inline cl_float half2float(cl_half us)
|
||||
{
|
||||
uint32_t u = us;
|
||||
uint32_t sign = (u << 16) & 0x80000000;
|
||||
int32_t exponent = (u & 0x7c00) >> 10;
|
||||
uint32_t mantissa = (u & 0x03ff) << 13;
|
||||
union{ cl_uint u; cl_float f;}uu;
|
||||
|
||||
if( exponent == 0 )
|
||||
{
|
||||
if( mantissa == 0 )
|
||||
return sign ? -0.0f : 0.0f;
|
||||
|
||||
int shift = detail::clz( mantissa ) - 8;
|
||||
exponent -= shift-1;
|
||||
mantissa <<= shift;
|
||||
mantissa &= 0x007fffff;
|
||||
}
|
||||
else
|
||||
if( exponent == 31)
|
||||
{
|
||||
uu.u = mantissa | sign;
|
||||
if( mantissa )
|
||||
uu.u |= 0x7fc00000;
|
||||
else
|
||||
uu.u |= 0x7f800000;
|
||||
|
||||
return uu.f;
|
||||
}
|
||||
|
||||
exponent += 127 - 15;
|
||||
exponent <<= 23;
|
||||
|
||||
exponent |= mantissa;
|
||||
uu.u = exponent | sign;
|
||||
|
||||
return uu.f;
|
||||
}
|
||||
|
||||
inline cl_ushort float2half_rte(cl_float f)
|
||||
{
|
||||
union{ cl_float f; cl_uint u; } u = {f};
|
||||
cl_uint sign = (u.u >> 16) & 0x8000;
|
||||
cl_float x = fabsf(f);
|
||||
|
||||
//Nan
|
||||
if( x != x )
|
||||
{
|
||||
u.u >>= (24-11);
|
||||
u.u &= 0x7fff;
|
||||
u.u |= 0x0200; //silence the NaN
|
||||
return u.u | sign;
|
||||
}
|
||||
|
||||
// overflow
|
||||
if( x >= MAKE_HEX_FLOAT(0x1.ffep15f, 0x1ffeL, 3) )
|
||||
return 0x7c00 | sign;
|
||||
|
||||
// underflow
|
||||
if( x <= MAKE_HEX_FLOAT(0x1.0p-25f, 0x1L, -25) )
|
||||
return sign; // The halfway case can return 0x0001 or 0. 0 is even.
|
||||
|
||||
// very small
|
||||
if( x < MAKE_HEX_FLOAT(0x1.8p-24f, 0x18L, -28) )
|
||||
return sign | 1;
|
||||
|
||||
// half denormal
|
||||
if( x < MAKE_HEX_FLOAT(0x1.0p-14f, 0x1L, -14) )
|
||||
{
|
||||
u.f = x * MAKE_HEX_FLOAT(0x1.0p-125f, 0x1L, -125);
|
||||
return sign | u.u;
|
||||
}
|
||||
|
||||
u.f *= MAKE_HEX_FLOAT(0x1.0p13f, 0x1L, 13);
|
||||
u.u &= 0x7f800000;
|
||||
x += u.f;
|
||||
u.f = x - u.f;
|
||||
u.f *= MAKE_HEX_FLOAT(0x1.0p-112f, 0x1L, -112);
|
||||
|
||||
return (u.u >> (24-11)) | sign;
|
||||
}
|
||||
|
||||
#endif // TEST_CONFORMANCE_CLCPP_HALF_UTILS_HPP
|
||||
30
test_conformance/clcpp/vload_vstore/main.cpp
Normal file
30
test_conformance/clcpp/vload_vstore/main.cpp
Normal file
@@ -0,0 +1,30 @@
|
||||
//
|
||||
// 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 "../common.hpp"
|
||||
|
||||
#include "vload_funcs.hpp"
|
||||
#include "vstore_funcs.hpp"
|
||||
|
||||
int main(int argc, const char *argv[])
|
||||
{
|
||||
// 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);
|
||||
}
|
||||
363
test_conformance/clcpp/vload_vstore/vload_funcs.hpp
Normal file
363
test_conformance/clcpp/vload_vstore/vload_funcs.hpp
Normal file
@@ -0,0 +1,363 @@
|
||||
//
|
||||
// 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_VLOAD_VSTORE_FUNCS_VLOAD_FUNCS_HPP
|
||||
#define TEST_CONFORMANCE_CLCPP_VLOAD_VSTORE_FUNCS_VLOAD_FUNCS_HPP
|
||||
|
||||
#include <iterator>
|
||||
|
||||
#include "../common.hpp"
|
||||
#include "../funcs_test_utils.hpp"
|
||||
|
||||
#include "common.hpp"
|
||||
|
||||
// -----------------------------------------------------------------------------------
|
||||
// ------------- ONLY FOR OPENCL 22 CONFORMANCE TEST 22 DEVELOPMENT ------------------
|
||||
// -----------------------------------------------------------------------------------
|
||||
#if defined(DEVELOPMENT) && defined(USE_OPENCLC_KERNELS)
|
||||
template <class func_type, class in_type, class out_type, size_t N>
|
||||
std::string generate_kernel_vload(func_type func)
|
||||
{
|
||||
std::string input1_type_str = type_name<in_type>();
|
||||
if(func.is_in1_half())
|
||||
{
|
||||
input1_type_str = "half";
|
||||
}
|
||||
std::string output1_type_str = type_name<out_type>();
|
||||
if(N == 3)
|
||||
{
|
||||
output1_type_str[output1_type_str.size() - 1] = '3';
|
||||
}
|
||||
return
|
||||
"__kernel void test_" + func.str() + "(global " + input1_type_str + " *input, global " + output1_type_str + " *output)\n"
|
||||
"{\n"
|
||||
" size_t gid = get_global_id(0);\n"
|
||||
" output[gid] = " + func.str() + std::to_string(N) + "(gid, input);\n"
|
||||
"}\n";
|
||||
}
|
||||
#else
|
||||
template <class func_type, class in_type, class out_type, size_t N>
|
||||
std::string generate_kernel_vload(func_type func)
|
||||
{
|
||||
std::string input1_type_str = type_name<in_type>();
|
||||
if(func.is_in1_half())
|
||||
{
|
||||
input1_type_str = "half";
|
||||
}
|
||||
std::string output1_type_str = type_name<out_type>();
|
||||
if(N == 3)
|
||||
{
|
||||
output1_type_str[output1_type_str.size() - 1] = '3';
|
||||
}
|
||||
return
|
||||
"" + func.defs() +
|
||||
"" + func.headers() +
|
||||
"#include <opencl_memory>\n"
|
||||
"#include <opencl_work_item>\n"
|
||||
"using namespace cl;\n"
|
||||
"__kernel void test_" + func.str() + "(global_ptr<" + input1_type_str + "[]> input,"
|
||||
"global_ptr<" + output1_type_str + "[]> output)\n"
|
||||
"{\n"
|
||||
" size_t gid = get_global_id(0);\n"
|
||||
" output[gid] = " + func.str() + "<" + std::to_string(N) + ">(gid, input.get());\n"
|
||||
"}\n";
|
||||
}
|
||||
#endif
|
||||
|
||||
template<class INPUT, class OUTPUT, class vload_op>
|
||||
bool verify_vload(const std::vector<INPUT> &in, const std::vector<OUTPUT> &out, vload_op op)
|
||||
{
|
||||
for(size_t i = 0; i < out.size(); i++)
|
||||
{
|
||||
auto expected = op(i, in.begin());
|
||||
for(size_t j = 0; j < vload_op::vector_size; j++)
|
||||
{
|
||||
size_t idx = (i * vector_size<OUTPUT>::value) + j;
|
||||
if(!are_equal(expected.s[j], out[i].s[j], op.delta(in[idx], expected.s[j]), op))
|
||||
{
|
||||
print_error_msg(expected, out[i], i, op);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
template <class vload_op>
|
||||
int test_vload_func(cl_device_id device, cl_context context, cl_command_queue queue, size_t count, vload_op op)
|
||||
{
|
||||
cl_mem buffers[2];
|
||||
cl_program program;
|
||||
cl_kernel kernel;
|
||||
size_t work_size[1];
|
||||
int err;
|
||||
|
||||
typedef typename vload_op::in_type INPUT;
|
||||
typedef typename vload_op::out_type OUTPUT;
|
||||
|
||||
// Don't run test for unsupported types
|
||||
if(!(type_supported<INPUT>(device) && type_supported<OUTPUT>(device)))
|
||||
{
|
||||
return CL_SUCCESS;
|
||||
}
|
||||
|
||||
std::string code_str = generate_kernel_vload<vload_op, INPUT, OUTPUT, vload_op::vector_size>(op);
|
||||
std::string kernel_name("test_"); kernel_name += op.str();
|
||||
|
||||
// -----------------------------------------------------------------------------------
|
||||
// ------------- ONLY FOR OPENCL 22 CONFORMANCE TEST 22 DEVELOPMENT ------------------
|
||||
// -----------------------------------------------------------------------------------
|
||||
// Only OpenCL C++ to SPIR-V compilation
|
||||
#if defined(DEVELOPMENT) && defined(ONLY_SPIRV_COMPILATION)
|
||||
err = create_opencl_kernel(context, &program, &kernel, code_str, kernel_name);
|
||||
RETURN_ON_ERROR(err)
|
||||
return err;
|
||||
// Use OpenCL C kernels instead of OpenCL C++ kernels (test C++ host code)
|
||||
#elif defined(DEVELOPMENT) && defined(USE_OPENCLC_KERNELS)
|
||||
err = create_opencl_kernel(context, &program, &kernel, code_str, kernel_name, "-cl-std=CL2.0", false);
|
||||
RETURN_ON_ERROR(err)
|
||||
#else
|
||||
err = create_opencl_kernel(context, &program, &kernel, code_str, kernel_name);
|
||||
RETURN_ON_ERROR(err)
|
||||
#endif
|
||||
|
||||
std::vector<INPUT> input = vload_vstore_generate_input<INPUT>(
|
||||
count * vector_size<OUTPUT>::value, op.min1(), op.max1(), op.in_special_cases(), op.is_in1_half()
|
||||
);
|
||||
std::vector<OUTPUT> output = generate_output<OUTPUT>(count);
|
||||
|
||||
buffers[0] = clCreateBuffer(context, (cl_mem_flags)(CL_MEM_READ_WRITE), sizeof(INPUT) * input.size(), NULL, &err);
|
||||
RETURN_ON_CL_ERROR(err, "clCreateBuffer");
|
||||
|
||||
buffers[1] = clCreateBuffer(context, (cl_mem_flags)(CL_MEM_READ_WRITE), sizeof(OUTPUT) * output.size(), NULL, &err);
|
||||
RETURN_ON_CL_ERROR(err, "clCreateBuffer");
|
||||
|
||||
err = clEnqueueWriteBuffer(
|
||||
queue, buffers[0], CL_TRUE, 0, sizeof(INPUT) * input.size(),
|
||||
static_cast<void *>(input.data()), 0, NULL, NULL
|
||||
);
|
||||
RETURN_ON_CL_ERROR(err, "clEnqueueWriteBuffer");
|
||||
|
||||
err = clSetKernelArg(kernel, 0, sizeof(buffers[0]), &buffers[0]);
|
||||
err |= clSetKernelArg(kernel, 1, sizeof(buffers[1]), &buffers[1]);
|
||||
RETURN_ON_CL_ERROR(err, "clSetKernelArg");
|
||||
|
||||
work_size[0] = count;
|
||||
err = clEnqueueNDRangeKernel(queue, kernel, 1, NULL, work_size, NULL, 0, NULL, NULL);
|
||||
RETURN_ON_CL_ERROR(err, "clEnqueueNDRangeKernel");
|
||||
|
||||
err = clEnqueueReadBuffer(
|
||||
queue, buffers[1], CL_TRUE, 0, sizeof(OUTPUT) * output.size(),
|
||||
static_cast<void *>(output.data()), 0, NULL, NULL
|
||||
);
|
||||
RETURN_ON_CL_ERROR(err, "clEnqueueReadBuffer");
|
||||
|
||||
if (!verify_vload(input, output, op))
|
||||
{
|
||||
RETURN_ON_ERROR_MSG(-1, "test_%s %s(%s) failed",
|
||||
op.str().c_str(),
|
||||
type_name<OUTPUT>().c_str(),
|
||||
type_name<INPUT>().c_str()
|
||||
);
|
||||
}
|
||||
log_info("test_%s %s(%s) passed\n", op.str().c_str(), type_name<OUTPUT>().c_str(), type_name<INPUT>().c_str());
|
||||
|
||||
clReleaseMemObject(buffers[0]);
|
||||
clReleaseMemObject(buffers[1]);
|
||||
clReleaseKernel(kernel);
|
||||
clReleaseProgram(program);
|
||||
return err;
|
||||
}
|
||||
|
||||
template <class IN1, cl_int N /* Vector size */>
|
||||
struct vload_func : public unary_func<
|
||||
IN1,
|
||||
typename make_vector_type<IN1, N>::type /* create IN1N type */
|
||||
>
|
||||
{
|
||||
typedef typename make_vector_type<IN1, N>::type result_type;
|
||||
const static size_t vector_size = N;
|
||||
|
||||
std::string str()
|
||||
{
|
||||
return "vload";
|
||||
}
|
||||
|
||||
std::string headers()
|
||||
{
|
||||
return "#include <opencl_vector_load_store>\n";
|
||||
}
|
||||
|
||||
template<class Iterator>
|
||||
result_type operator()(const size_t offset, Iterator x)
|
||||
{
|
||||
static_assert(
|
||||
!is_vector_type<IN1>::value,
|
||||
"IN1 must be scalar type"
|
||||
);
|
||||
static_assert(
|
||||
std::is_same<typename std::iterator_traits<Iterator>::value_type, IN1>::value,
|
||||
"std::iterator_traits<Iterator>::value_type must be IN1"
|
||||
);
|
||||
|
||||
typedef typename std::iterator_traits<Iterator>::difference_type diff_type;
|
||||
|
||||
result_type r;
|
||||
Iterator temp = x + static_cast<diff_type>(offset * N);
|
||||
for(size_t i = 0; i < N; i++)
|
||||
{
|
||||
r.s[i] = *temp;
|
||||
temp++;
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
bool is_in1_half()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
template <cl_int N /* Vector size */>
|
||||
struct vload_half_func : public unary_func<
|
||||
cl_half,
|
||||
typename make_vector_type<cl_float, N>::type /* create IN1N type */
|
||||
>
|
||||
{
|
||||
typedef typename make_vector_type<cl_float, N>::type result_type;
|
||||
const static size_t vector_size = N;
|
||||
|
||||
std::string str()
|
||||
{
|
||||
return "vload_half";
|
||||
}
|
||||
|
||||
std::string headers()
|
||||
{
|
||||
return "#include <opencl_vector_load_store>\n";
|
||||
}
|
||||
|
||||
template<class Iterator>
|
||||
result_type operator()(const size_t offset, Iterator x)
|
||||
{
|
||||
static_assert(
|
||||
std::is_same<typename std::iterator_traits<Iterator>::value_type, cl_half>::value,
|
||||
"std::iterator_traits<Iterator>::value_type must be cl_half"
|
||||
);
|
||||
|
||||
typedef typename std::iterator_traits<Iterator>::difference_type diff_type;
|
||||
|
||||
result_type r;
|
||||
Iterator temp = x + static_cast<diff_type>(offset * N);
|
||||
for(size_t i = 0; i < N; i++)
|
||||
{
|
||||
r.s[i] = half2float(*temp);
|
||||
temp++;
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
bool is_in1_half()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
template <cl_int N /* Vector size */>
|
||||
struct vloada_half_func : public unary_func<
|
||||
cl_half,
|
||||
typename make_vector_type<cl_float, N>::type /* create IN1N type */
|
||||
>
|
||||
{
|
||||
typedef typename make_vector_type<cl_float, N>::type result_type;
|
||||
const static size_t vector_size = N;
|
||||
|
||||
std::string str()
|
||||
{
|
||||
return "vloada_half";
|
||||
}
|
||||
|
||||
std::string headers()
|
||||
{
|
||||
return "#include <opencl_vector_load_store>\n";
|
||||
}
|
||||
|
||||
template<class Iterator>
|
||||
result_type operator()(const size_t offset, Iterator x)
|
||||
{
|
||||
static_assert(
|
||||
std::is_same<typename std::iterator_traits<Iterator>::value_type, cl_half>::value,
|
||||
"std::iterator_traits<Iterator>::value_type must be cl_half"
|
||||
);
|
||||
|
||||
typedef typename std::iterator_traits<Iterator>::difference_type diff_type;
|
||||
|
||||
result_type r;
|
||||
size_t alignment = N == 3 ? 4 : N;
|
||||
Iterator temp = x + static_cast<diff_type>(offset * alignment);
|
||||
for(size_t i = 0; i < N; i++)
|
||||
{
|
||||
r.s[i] = half2float(*temp);
|
||||
temp++;
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
bool is_in1_half()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
AUTO_TEST_CASE(test_vload_funcs)
|
||||
(cl_device_id device, cl_context context, cl_command_queue queue, int n_elems)
|
||||
{
|
||||
int error = CL_SUCCESS;
|
||||
int last_error = CL_SUCCESS;
|
||||
|
||||
#define TEST_VLOAD_FUNC_MACRO(CLASS) \
|
||||
last_error = test_vload_func( \
|
||||
device, context, queue, n_elems, CLASS \
|
||||
); \
|
||||
CHECK_ERROR(last_error) \
|
||||
error |= last_error;
|
||||
|
||||
TEST_VLOAD_FUNC_MACRO((vload_func<cl_uint, 2>()))
|
||||
TEST_VLOAD_FUNC_MACRO((vload_func<cl_float, 4>()))
|
||||
TEST_VLOAD_FUNC_MACRO((vload_func<cl_short, 8>()))
|
||||
TEST_VLOAD_FUNC_MACRO((vload_func<cl_int, 16>()))
|
||||
|
||||
TEST_VLOAD_FUNC_MACRO((vload_half_func<2>()))
|
||||
TEST_VLOAD_FUNC_MACRO((vload_half_func<3>()))
|
||||
TEST_VLOAD_FUNC_MACRO((vload_half_func<4>()))
|
||||
TEST_VLOAD_FUNC_MACRO((vload_half_func<8>()))
|
||||
TEST_VLOAD_FUNC_MACRO((vload_half_func<16>()))
|
||||
|
||||
TEST_VLOAD_FUNC_MACRO((vloada_half_func<2>()))
|
||||
TEST_VLOAD_FUNC_MACRO((vloada_half_func<3>()))
|
||||
TEST_VLOAD_FUNC_MACRO((vloada_half_func<4>()))
|
||||
TEST_VLOAD_FUNC_MACRO((vloada_half_func<8>()))
|
||||
TEST_VLOAD_FUNC_MACRO((vloada_half_func<16>()))
|
||||
|
||||
#undef TEST_VLOAD_FUNC_MACRO
|
||||
|
||||
if(error != CL_SUCCESS)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
return error;
|
||||
}
|
||||
|
||||
#endif // TEST_CONFORMANCE_CLCPP_VLOAD_VSTORE_FUNCS_VLOAD_FUNCS_HPP
|
||||
348
test_conformance/clcpp/vload_vstore/vstore_funcs.hpp
Normal file
348
test_conformance/clcpp/vload_vstore/vstore_funcs.hpp
Normal file
@@ -0,0 +1,348 @@
|
||||
//
|
||||
// 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_VLOAD_VSTORE_FUNCS_VSTORE_FUNCS_HPP
|
||||
#define TEST_CONFORMANCE_CLCPP_VLOAD_VSTORE_FUNCS_VSTORE_FUNCS_HPP
|
||||
|
||||
#include "../common.hpp"
|
||||
#include "../funcs_test_utils.hpp"
|
||||
|
||||
#include <iterator>
|
||||
|
||||
#include "../common.hpp"
|
||||
#include "../funcs_test_utils.hpp"
|
||||
|
||||
#include "common.hpp"
|
||||
|
||||
// -----------------------------------------------------------------------------------
|
||||
// ------------- ONLY FOR OPENCL 22 CONFORMANCE TEST 22 DEVELOPMENT ------------------
|
||||
// -----------------------------------------------------------------------------------
|
||||
#if defined(DEVELOPMENT) && defined(USE_OPENCLC_KERNELS)
|
||||
template <class func_type, class in_type, class out_type, size_t N>
|
||||
std::string generate_kernel_vstore(func_type func)
|
||||
{
|
||||
std::string input1_type_str = type_name<in_type>();
|
||||
if(N == 3)
|
||||
{
|
||||
input1_type_str[input1_type_str.size() - 1] = '3';
|
||||
}
|
||||
std::string output1_type_str = type_name<out_type>();
|
||||
if(func.is_out_half())
|
||||
{
|
||||
output1_type_str = "half";
|
||||
}
|
||||
return
|
||||
"__kernel void test_" + func.str() + "(global " + input1_type_str + " *input, global " + output1_type_str + " *output)\n"
|
||||
"{\n"
|
||||
" size_t gid = get_global_id(0);\n"
|
||||
" " + func.str() + std::to_string(N) + "(input[gid], gid, output);\n"
|
||||
"}\n";
|
||||
}
|
||||
#else
|
||||
template <class func_type, class in_type, class out_type, size_t N>
|
||||
std::string generate_kernel_vstore(func_type func)
|
||||
{
|
||||
std::string input1_type_str = type_name<in_type>();
|
||||
if(N == 3)
|
||||
{
|
||||
input1_type_str[input1_type_str.size() - 1] = '3';
|
||||
}
|
||||
std::string output1_type_str = type_name<out_type>();
|
||||
if(func.is_out_half())
|
||||
{
|
||||
output1_type_str = "half";
|
||||
}
|
||||
return
|
||||
"" + func.defs() +
|
||||
"" + func.headers() +
|
||||
"#include <opencl_memory>\n"
|
||||
"#include <opencl_work_item>\n"
|
||||
"using namespace cl;\n"
|
||||
"__kernel void test_" + func.str() + "(global_ptr<" + input1_type_str + "[]> input,"
|
||||
"global_ptr<" + output1_type_str + "[]> output)\n"
|
||||
"{\n"
|
||||
" size_t gid = get_global_id(0);\n"
|
||||
" " + func.str() + "(input[gid], gid, output.get());\n"
|
||||
"}\n";
|
||||
}
|
||||
#endif
|
||||
|
||||
template<class INPUT, class OUTPUT, class vload_op>
|
||||
bool verify_vstore(const std::vector<INPUT> &in, const std::vector<OUTPUT> &out, vload_op op)
|
||||
{
|
||||
for(size_t i = 0; i < in.size(); i++)
|
||||
{
|
||||
auto expected = op(in[i]);
|
||||
for(size_t j = 0; j < vload_op::vector_size; j++)
|
||||
{
|
||||
size_t idx = (i * vload_op::vec_alignment) + j;
|
||||
if(!are_equal(expected.s[j], out[idx], op.delta(in[i], expected).s[j], op))
|
||||
{
|
||||
print_error_msg(expected.s[j], out[idx], idx, op);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
template <class vload_op>
|
||||
int test_vstore_func(cl_device_id device, cl_context context, cl_command_queue queue, size_t count, vload_op op)
|
||||
{
|
||||
cl_mem buffers[2];
|
||||
cl_program program;
|
||||
cl_kernel kernel;
|
||||
size_t work_size[1];
|
||||
int err;
|
||||
|
||||
typedef typename vload_op::in_type INPUT;
|
||||
typedef typename vload_op::out_type OUTPUT;
|
||||
|
||||
// Don't run test for unsupported types
|
||||
if(!(type_supported<INPUT>(device) && type_supported<OUTPUT>(device)))
|
||||
{
|
||||
return CL_SUCCESS;
|
||||
}
|
||||
|
||||
std::string code_str = generate_kernel_vstore<vload_op, INPUT, OUTPUT, vload_op::vector_size>(op);
|
||||
std::string kernel_name("test_"); kernel_name += op.str();
|
||||
|
||||
// -----------------------------------------------------------------------------------
|
||||
// ------------- ONLY FOR OPENCL 22 CONFORMANCE TEST 22 DEVELOPMENT ------------------
|
||||
// -----------------------------------------------------------------------------------
|
||||
// Only OpenCL C++ to SPIR-V compilation
|
||||
#if defined(DEVELOPMENT) && defined(ONLY_SPIRV_COMPILATION)
|
||||
err = create_opencl_kernel(context, &program, &kernel, code_str, kernel_name);
|
||||
RETURN_ON_ERROR(err)
|
||||
return err;
|
||||
// Use OpenCL C kernels instead of OpenCL C++ kernels (test C++ host code)
|
||||
#elif defined(DEVELOPMENT) && defined(USE_OPENCLC_KERNELS)
|
||||
err = create_opencl_kernel(context, &program, &kernel, code_str, kernel_name, "-cl-std=CL2.0", false);
|
||||
RETURN_ON_ERROR(err)
|
||||
#else
|
||||
err = create_opencl_kernel(context, &program, &kernel, code_str, kernel_name);
|
||||
RETURN_ON_ERROR(err)
|
||||
#endif
|
||||
|
||||
std::vector<INPUT> input = generate_input<INPUT>(count, op.min1(), op.max1(), op.in_special_cases());
|
||||
std::vector<OUTPUT> output = generate_output<OUTPUT>(count * vector_size<INPUT>::value);
|
||||
|
||||
buffers[0] = clCreateBuffer(context, (cl_mem_flags)(CL_MEM_READ_WRITE), sizeof(INPUT) * input.size(), NULL, &err);
|
||||
RETURN_ON_CL_ERROR(err, "clCreateBuffer");
|
||||
|
||||
buffers[1] = clCreateBuffer(context, (cl_mem_flags)(CL_MEM_READ_WRITE), sizeof(OUTPUT) * output.size(), NULL, &err);
|
||||
RETURN_ON_CL_ERROR(err, "clCreateBuffer");
|
||||
|
||||
err = clEnqueueWriteBuffer(
|
||||
queue, buffers[0], CL_TRUE, 0, sizeof(INPUT) * input.size(),
|
||||
static_cast<void *>(input.data()), 0, NULL, NULL
|
||||
);
|
||||
RETURN_ON_CL_ERROR(err, "clEnqueueWriteBuffer");
|
||||
|
||||
err = clSetKernelArg(kernel, 0, sizeof(buffers[0]), &buffers[0]);
|
||||
err |= clSetKernelArg(kernel, 1, sizeof(buffers[1]), &buffers[1]);
|
||||
RETURN_ON_CL_ERROR(err, "clSetKernelArg");
|
||||
|
||||
work_size[0] = count;
|
||||
err = clEnqueueNDRangeKernel(queue, kernel, 1, NULL, work_size, NULL, 0, NULL, NULL);
|
||||
RETURN_ON_CL_ERROR(err, "clEnqueueNDRangeKernel");
|
||||
|
||||
err = clEnqueueReadBuffer(
|
||||
queue, buffers[1], CL_TRUE, 0, sizeof(OUTPUT) * output.size(),
|
||||
static_cast<void *>(output.data()), 0, NULL, NULL
|
||||
);
|
||||
RETURN_ON_CL_ERROR(err, "clEnqueueReadBuffer");
|
||||
|
||||
if (!verify_vstore(input, output, op))
|
||||
{
|
||||
RETURN_ON_ERROR_MSG(-1, "test_%s %s(%s) failed", op.str().c_str(), type_name<OUTPUT>().c_str(), type_name<INPUT>().c_str());
|
||||
}
|
||||
log_info("test_%s %s(%s) passed\n", op.str().c_str(), type_name<OUTPUT>().c_str(), type_name<INPUT>().c_str());
|
||||
|
||||
clReleaseMemObject(buffers[0]);
|
||||
clReleaseMemObject(buffers[1]);
|
||||
clReleaseKernel(kernel);
|
||||
clReleaseProgram(program);
|
||||
return err;
|
||||
}
|
||||
|
||||
template <class T, cl_int N /* Vector size */>
|
||||
struct vstore_func : public unary_func<
|
||||
typename make_vector_type<T, N>::type,
|
||||
T
|
||||
>
|
||||
{
|
||||
typedef typename make_vector_type<T, N>::type input1_type;
|
||||
typedef typename make_vector_type<T, N>::type result_type;
|
||||
const static size_t vector_size = N;
|
||||
const static size_t vec_alignment = N;
|
||||
|
||||
std::string str()
|
||||
{
|
||||
return "vstore";
|
||||
}
|
||||
|
||||
std::string headers()
|
||||
{
|
||||
return "#include <opencl_vector_load_store>\n";
|
||||
}
|
||||
|
||||
result_type operator()(const input1_type& in)
|
||||
{
|
||||
static_assert(
|
||||
!is_vector_type<T>::value,
|
||||
"T must be scalar type"
|
||||
);
|
||||
return in;
|
||||
}
|
||||
|
||||
bool is_out_half()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
template <cl_int N /* Vector size */>
|
||||
struct vstore_half_func : public unary_func<
|
||||
typename make_vector_type<cl_float, N>::type,
|
||||
cl_half
|
||||
>
|
||||
{
|
||||
typedef typename make_vector_type<cl_float, N>::type input1_type;
|
||||
typedef typename make_vector_type<cl_half, N>::type result_type;
|
||||
const static size_t vector_size = N;
|
||||
const static size_t vec_alignment = N;
|
||||
|
||||
std::string str()
|
||||
{
|
||||
return "vstore_half";
|
||||
}
|
||||
|
||||
std::string headers()
|
||||
{
|
||||
return "#include <opencl_vector_load_store>\n";
|
||||
}
|
||||
|
||||
result_type operator()(const input1_type& in)
|
||||
{
|
||||
result_type r;
|
||||
for(size_t i = 0; i < N; i++)
|
||||
{
|
||||
r.s[i] = float2half_rte(in.s[i]);
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
input1_type min1()
|
||||
{
|
||||
return detail::make_value<input1_type>(-512.f);
|
||||
}
|
||||
|
||||
input1_type max1()
|
||||
{
|
||||
return detail::make_value<input1_type>(512.f);
|
||||
}
|
||||
|
||||
bool is_out_half()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
template <cl_int N /* Vector size */>
|
||||
struct vstorea_half_func : public unary_func<
|
||||
typename make_vector_type<cl_float, N>::type,
|
||||
cl_half
|
||||
>
|
||||
{
|
||||
typedef typename make_vector_type<cl_float, N>::type input1_type;
|
||||
typedef typename make_vector_type<cl_half, N>::type result_type;
|
||||
const static size_t vector_size = N;
|
||||
const static size_t vec_alignment = N == 3 ? 4 : N;
|
||||
|
||||
std::string str()
|
||||
{
|
||||
return "vstorea_half";
|
||||
}
|
||||
|
||||
std::string headers()
|
||||
{
|
||||
return "#include <opencl_vector_load_store>\n";
|
||||
}
|
||||
|
||||
result_type operator()(const input1_type& in)
|
||||
{
|
||||
result_type r;
|
||||
for(size_t i = 0; i < N; i++)
|
||||
{
|
||||
r.s[i] = float2half_rte(in.s[i]);
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
input1_type min1()
|
||||
{
|
||||
return detail::make_value<input1_type>(-512.f);
|
||||
}
|
||||
|
||||
input1_type max1()
|
||||
{
|
||||
return detail::make_value<input1_type>(512.f);
|
||||
}
|
||||
|
||||
bool is_out_half()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
AUTO_TEST_CASE(test_vstore_funcs)
|
||||
(cl_device_id device, cl_context context, cl_command_queue queue, int n_elems)
|
||||
{
|
||||
int error = CL_SUCCESS;
|
||||
int last_error = CL_SUCCESS;
|
||||
|
||||
#define TEST_VSTORE_FUNC_MACRO(CLASS) \
|
||||
last_error = test_vstore_func( \
|
||||
device, context, queue, n_elems, CLASS \
|
||||
); \
|
||||
CHECK_ERROR(last_error) \
|
||||
error |= last_error;
|
||||
|
||||
TEST_VSTORE_FUNC_MACRO((vstore_func<cl_uint, 2>()))
|
||||
TEST_VSTORE_FUNC_MACRO((vstore_func<cl_uint, 3>()))
|
||||
TEST_VSTORE_FUNC_MACRO((vstore_func<cl_int, 4>()))
|
||||
TEST_VSTORE_FUNC_MACRO((vstore_func<cl_float, 8>()))
|
||||
TEST_VSTORE_FUNC_MACRO((vstore_func<cl_uchar, 16>()))
|
||||
|
||||
TEST_VSTORE_FUNC_MACRO((vstore_half_func<2>()))
|
||||
TEST_VSTORE_FUNC_MACRO((vstore_half_func<3>()))
|
||||
TEST_VSTORE_FUNC_MACRO((vstore_half_func<4>()))
|
||||
TEST_VSTORE_FUNC_MACRO((vstore_half_func<8>()))
|
||||
TEST_VSTORE_FUNC_MACRO((vstore_half_func<16>()))
|
||||
|
||||
TEST_VSTORE_FUNC_MACRO((vstorea_half_func<2>()))
|
||||
TEST_VSTORE_FUNC_MACRO((vstorea_half_func<3>()))
|
||||
|
||||
#undef TEST_VSTORE_FUNC_MACRO
|
||||
|
||||
if(error != CL_SUCCESS)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
return error;
|
||||
}
|
||||
|
||||
#endif // TEST_CONFORMANCE_CLCPP_VLOAD_VSTORE_FUNCS_VSTORE_FUNCS_HPP
|
||||
Reference in New Issue
Block a user