Skip to content

Commit f06b064

Browse files
authored
[SYCL][ESIMD] Add a test for esimd copy constructor (intel#578)
1 parent 17894ea commit f06b064

File tree

5 files changed

+488
-2
lines changed

5 files changed

+488
-2
lines changed

SYCL/ESIMD/api/functional/common.hpp

Lines changed: 48 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,15 +8,61 @@
88
//===----------------------------------------------------------------------===//
99
///
1010
/// \file
11-
/// Common file for test on simd class.
11+
/// Common file for tests on simd class.
1212
///
1313
//===----------------------------------------------------------------------===//
1414

1515
#pragma once
1616

17-
#include <CL/sycl.hpp>
1817
#include <sycl/ext/intel/experimental/esimd.hpp>
18+
#include <sycl/sycl.hpp>
1919

2020
#include "../../esimd_test_utils.hpp"
2121
#include "logger.hpp"
2222
#include "type_coverage.hpp"
23+
#include "type_traits.hpp"
24+
#include "value.hpp"
25+
26+
#include <vector>
27+
28+
namespace esimd_test {
29+
namespace api {
30+
namespace functional {
31+
32+
namespace details {
33+
34+
// Bitwise comparison for two values
35+
template <typename T> bool are_bitwise_equal(T lhs, T rhs) {
36+
constexpr size_t size{sizeof(T)};
37+
38+
// Such type-punning is OK from the point of strict aliasing rules
39+
const auto &lhs_bytes = reinterpret_cast<const unsigned char(&)[size]>(lhs);
40+
const auto &rhs_bytes = reinterpret_cast<const unsigned char(&)[size]>(rhs);
41+
42+
bool result{true};
43+
for (size_t i = 0; i < size; ++i) {
44+
result &= lhs_bytes[i] == rhs_bytes[i];
45+
}
46+
return result;
47+
}
48+
49+
} // namespace details
50+
51+
// A wrapper to speed-up bitwise comparison
52+
template <typename T> bool are_bitwise_equal(T lhs, T rhs) {
53+
// We are safe to compare unsigned integral types using `==` operator.
54+
// Still for any other type we might consider the bitwise comparison,
55+
// including:
56+
// - floating-point types, due to nan with opcodes
57+
// - signed integer types, to avoid a possibility of UB on trap
58+
// representation (negative zero) value access
59+
if constexpr (std::is_unsigned_v<T>) {
60+
return lhs == rhs;
61+
} else {
62+
return details::are_bitwise_equal(lhs, rhs);
63+
}
64+
}
65+
66+
} // namespace functional
67+
} // namespace api
68+
} // namespace esimd_test
Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
//===-- common.hpp - Define common code for simd ctors tests --------------===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
///
9+
/// \file
10+
/// This file provides common things for simd ctors tests.
11+
///
12+
//===----------------------------------------------------------------------===//
13+
14+
#pragma once
15+
16+
#include "../common.hpp"
17+
18+
namespace esimd_test {
19+
namespace api {
20+
namespace functional {
21+
namespace ctors {
22+
23+
// Dummy kernel for submitting some code into device side.
24+
template <typename DataT, int NumElems, typename T> struct Kernel;
25+
26+
template <typename DataT>
27+
using shared_allocator = sycl::usm_allocator<DataT, sycl::usm::alloc::shared>;
28+
29+
template <typename DataT>
30+
using shared_vector = std::vector<DataT, shared_allocator<DataT>>;
31+
32+
// Calls simd constructor in provided invocation context, which depends on the
33+
// TestCaseT type. TestCaseT is a struct, that should have call_simd_ctor method
34+
// that should return constructed object of simd class.
35+
// This function returns std::vector instance with the output data.
36+
template <typename DataT, int NumElems, typename TestCaseT>
37+
auto call_simd(sycl::queue &queue, const shared_vector<DataT> &ref_data) {
38+
39+
shared_vector<DataT> result{NumElems, shared_allocator<DataT>{queue}};
40+
41+
queue.submit([&](sycl::handler &cgh) {
42+
const auto ref = ref_data.data();
43+
auto out = result.data();
44+
45+
cgh.single_task<Kernel<DataT, NumElems, TestCaseT>>(
46+
[=]() SYCL_ESIMD_KERNEL {
47+
sycl::ext::intel::experimental::esimd::simd<DataT, NumElems>
48+
result_simd =
49+
TestCaseT::template call_simd_ctor<DataT, NumElems>(ref);
50+
result_simd.copy_to(out);
51+
});
52+
});
53+
return result;
54+
}
55+
56+
// The main test routine.
57+
// Using functor class to be able to iterate over the pre-defined data types.
58+
template <typename DataT, int NumElems, typename TestCaseT> struct test {
59+
bool operator()(sycl::queue &queue, const std::string &data_type) {
60+
bool passed{true};
61+
62+
std::vector<DataT> generated_data{generate_ref_data<DataT, NumElems>()};
63+
shared_vector<DataT> ref_data{generated_data.begin(), generated_data.end(),
64+
shared_allocator<DataT>{queue}};
65+
66+
const auto result_data =
67+
call_simd<DataT, NumElems, TestCaseT>(queue, ref_data);
68+
69+
for (size_t it = 0; it < ref_data.size(); it++) {
70+
if (!are_bitwise_equal(ref_data[it], result_data[it])) {
71+
passed = false;
72+
log::fail<NumElems>(
73+
"Simd by " + TestCaseT::get_description() +
74+
" failed, retrieved: " + std::to_string(result_data[it]) +
75+
", expected: " + std::to_string(ref_data[it]),
76+
data_type);
77+
}
78+
}
79+
80+
return passed;
81+
}
82+
};
83+
84+
} // namespace ctors
85+
} // namespace functional
86+
} // namespace api
87+
} // namespace esimd_test
Lines changed: 134 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,134 @@
1+
//==------- ctor_copy.cpp - DPC++ ESIMD on-device test --------------------==//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
// REQUIRES: gpu, level_zero
9+
// XREQUIRES: gpu
10+
// TODO gpu and level_zero in REQUIRES due to only this platforms supported yet.
11+
// The current "REQUIRES" should be replaced with "gpu" only as mentioned in
12+
// "XREQUIRES".
13+
// UNSUPPORTED: cuda, hip
14+
// XRUN: %clangxx -fsycl %s -fsycl-device-code-split=per_kernel -o %t.out
15+
// XRUN: %GPU_RUN_PLACEHOLDER %t.out
16+
// RUN: false
17+
// XFAIL: *
18+
// TODO Unexpected static_assert was retrieved while calling simd::copy_from()
19+
// function. The issue was created (https://github.com/intel/llvm/issues/5112)
20+
// and the test must be enabled when it is resolved.
21+
//
22+
// Test for esimd copy constructor.
23+
24+
#include "common.hpp"
25+
26+
using namespace sycl;
27+
using namespace sycl::ext::intel::experimental::esimd;
28+
using namespace esimd_test::api::functional::ctors;
29+
using namespace esimd_test::api::functional;
30+
31+
// Descriptor class for the case of calling constructor in initializer context.
32+
struct initializer {
33+
static std::string get_description() { return "initializer"; }
34+
35+
template <typename DataT, int NumElems>
36+
static simd<DataT, NumElems> call_simd_ctor(const DataT *ref_data) {
37+
simd<DataT, NumElems> source_simd;
38+
source_simd.copy_from(ref_data);
39+
simd<DataT, NumElems> simd_by_init = simd<DataT, NumElems>(source_simd);
40+
return simd_by_init;
41+
}
42+
};
43+
44+
// Descriptor class for the case of calling constructor in variable declaration
45+
// context.
46+
struct var_declaration {
47+
static std::string get_description() { return "variable declaration"; }
48+
49+
template <typename DataT, int NumElems>
50+
static simd<DataT, NumElems> call_simd_ctor(const DataT *ref_data) {
51+
simd<DataT, NumElems> source_simd;
52+
source_simd.copy_from(ref_data);
53+
simd<DataT, NumElems> simd_by_var_decl{source_simd};
54+
return simd_by_var_decl;
55+
}
56+
};
57+
58+
// Descriptor class for the case of calling constructor in rvalue in an
59+
// expression context.
60+
struct rval_in_expression {
61+
static std::string get_description() { return "rvalue in an expression"; }
62+
63+
template <typename DataT, int NumElems>
64+
static simd<DataT, NumElems> call_simd_ctor(const DataT *ref_data) {
65+
simd<DataT, NumElems> source_simd;
66+
source_simd.copy_from(ref_data);
67+
simd<DataT, NumElems> simd_by_rval;
68+
simd_by_rval = simd<DataT, NumElems>(source_simd);
69+
return simd_by_rval;
70+
}
71+
};
72+
73+
// Descriptor class for the case of calling constructor in const reference
74+
// context.
75+
class const_ref {
76+
public:
77+
static std::string get_description() { return "const reference"; }
78+
79+
template <typename DataT, int NumElems>
80+
static simd<DataT, NumElems> call_simd_ctor(const DataT *ref_data) {
81+
simd<DataT, NumElems> source_simd;
82+
source_simd.copy_from(ref_data);
83+
return call_simd_by_const_ref<DataT, NumElems>(
84+
simd<DataT, NumElems>(source_simd));
85+
}
86+
87+
private:
88+
template <typename DataT, int NumElems>
89+
static simd<DataT, NumElems>
90+
call_simd_by_const_ref(const simd<DataT, NumElems> &simd_by_const_ref) {
91+
return simd_by_const_ref;
92+
}
93+
};
94+
95+
template <typename DataT, typename TestT>
96+
using run_test_with_one_elem = test<DataT, 1, TestT>;
97+
98+
template <typename DataT, typename TestT>
99+
using run_test_with_eight_elems = test<DataT, 8, TestT>;
100+
101+
template <typename DataT, typename TestT>
102+
using run_test_with_sixteen_elems = test<DataT, 16, TestT>;
103+
104+
template <typename DataT, typename TestT>
105+
using run_test_with_thirty_two_elems = test<DataT, 32, TestT>;
106+
107+
template <typename TestT, typename... T>
108+
bool run_verification_for_type(sycl::queue &queue,
109+
const named_type_pack<T...> &types) {
110+
bool passed{true};
111+
112+
passed &= for_all_types<run_test_with_one_elem, TestT>(types, queue);
113+
passed &= for_all_types<run_test_with_eight_elems, TestT>(types, queue);
114+
passed &= for_all_types<run_test_with_sixteen_elems, TestT>(types, queue);
115+
passed &= for_all_types<run_test_with_thirty_two_elems, TestT>(types, queue);
116+
return passed;
117+
}
118+
119+
int main(int argc, char **argv) {
120+
sycl::queue queue{esimd_test::ESIMDSelector{},
121+
esimd_test::createExceptionHandler()};
122+
123+
bool passed{true};
124+
125+
auto types{get_tested_types<tested_types::all>()};
126+
127+
passed &= run_verification_for_type<initializer>(queue, types);
128+
passed &= run_verification_for_type<var_declaration>(queue, types);
129+
passed &= run_verification_for_type<rval_in_expression>(queue, types);
130+
passed &= run_verification_for_type<const_ref>(queue, types);
131+
132+
std::cout << (passed ? "=== Test passed\n" : "=== Test FAILED\n");
133+
return passed ? 0 : 1;
134+
}
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
//===-- type_traits.hpp - Define functions for iterating with datatypes. --===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
///
9+
/// \file
10+
/// This file provides function for iterating with data types.
11+
///
12+
//===----------------------------------------------------------------------===//
13+
14+
#pragma once
15+
16+
#include <type_traits>
17+
18+
namespace esimd_test {
19+
namespace api {
20+
namespace functional {
21+
namespace type_traits {
22+
23+
template <typename T>
24+
using is_sycl_floating_point =
25+
std::bool_constant<std::is_floating_point_v<T> ||
26+
std::is_same_v<T, sycl::half>>;
27+
28+
template <typename T>
29+
inline constexpr bool is_sycl_floating_point_v{
30+
is_sycl_floating_point<T>::value};
31+
32+
} // namespace type_traits
33+
} // namespace functional
34+
} // namespace api
35+
} // namespace esimd_test

0 commit comments

Comments
 (0)