Skip to content
This repository was archived by the owner on Mar 28, 2023. It is now read-only.

Commit 7ffc560

Browse files
authored
[SYCL][ESIMD] Add test on simd load constructor for fp_extra types (#797)
* [SYCL][ESIMD] Add test on simd load constructor for fp_extra types * [SYCL][ESIMD] Replace "dim" with "size" It makes variable name more self describe * Revert "[SYCL][ESIMD] Replace "dim" with "size"" This reverts commit 26b43da.
1 parent 7991de8 commit 7ffc560

File tree

3 files changed

+264
-193
lines changed

3 files changed

+264
-193
lines changed
Lines changed: 208 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,208 @@
1+
//===-- ctor_load.hpp - Functions for tests on simd load constructor definition.
2+
// -------------------------------------------------------------------===//
3+
//
4+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
5+
// See https://llvm.org/LICENSE.txt for license information.
6+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7+
//
8+
//===----------------------------------------------------------------------===//
9+
///
10+
/// \file
11+
/// This file provides functions for tests on simd load constructor.
12+
///
13+
//===----------------------------------------------------------------------===//
14+
15+
#pragma once
16+
17+
#include "common.hpp"
18+
19+
namespace esimd = sycl::ext::intel::experimental::esimd;
20+
21+
namespace esimd_test::api::functional::ctors {
22+
23+
// Descriptor class for the case of calling constructor in initializer context.
24+
struct initializer {
25+
static std::string get_description() { return "initializer"; }
26+
27+
template <typename DataT, int NumElems, typename AlignmentT>
28+
static void call_simd_ctor(const DataT *ref_data, DataT *const out,
29+
AlignmentT alignment) {
30+
esimd::simd<DataT, NumElems> simd_by_init =
31+
esimd::simd<DataT, NumElems>(ref_data, alignment);
32+
simd_by_init.copy_to(out);
33+
}
34+
};
35+
36+
// Descriptor class for the case of calling constructor in variable declaration
37+
// context.
38+
struct var_decl {
39+
static std::string get_description() { return "variable declaration"; }
40+
41+
template <typename DataT, int NumElems, typename AlignmentT>
42+
static void call_simd_ctor(const DataT *ref_data, DataT *const out,
43+
AlignmentT alignment) {
44+
esimd::simd<DataT, NumElems> simd_by_var_decl(ref_data, alignment);
45+
simd_by_var_decl.copy_to(out);
46+
}
47+
};
48+
49+
// Descriptor class for the case of calling constructor in rvalue in an
50+
// expression context.
51+
struct rval_in_expr {
52+
static std::string get_description() { return "rvalue in an expression"; }
53+
54+
template <typename DataT, int NumElems, typename AlignmentT>
55+
static void call_simd_ctor(const DataT *ref_data, DataT *const out,
56+
AlignmentT alignment) {
57+
esimd::simd<DataT, NumElems> simd_by_rval;
58+
simd_by_rval = esimd::simd<DataT, NumElems>(ref_data, alignment);
59+
simd_by_rval.copy_to(out);
60+
}
61+
};
62+
63+
// Descriptor class for the case of calling constructor in const reference
64+
// context.
65+
class const_ref {
66+
public:
67+
static std::string get_description() { return "const reference"; }
68+
69+
template <typename DataT, int NumElems, typename AlignmentT>
70+
static void call_simd_ctor(const DataT *ref_data, DataT *const out,
71+
AlignmentT alignment) {
72+
call_simd_by_const_ref<DataT, NumElems>(
73+
esimd::simd<DataT, NumElems>(ref_data, alignment), out);
74+
}
75+
76+
private:
77+
template <typename DataT, int NumElems>
78+
static void
79+
call_simd_by_const_ref(const esimd::simd<DataT, NumElems> &simd_by_const_ref,
80+
DataT *out) {
81+
simd_by_const_ref.copy_to(out);
82+
}
83+
};
84+
85+
// Dummy kernel for submitting some code into device side.
86+
template <typename DataT, int NumElems, typename T, typename Alignment>
87+
struct Kernel_for_load_ctor;
88+
89+
namespace alignment {
90+
91+
struct element {
92+
template <typename DataT, int> static size_t get_size() {
93+
return alignof(DataT);
94+
}
95+
static constexpr auto get_value() { return esimd::element_aligned; }
96+
};
97+
98+
struct vector {
99+
template <typename DataT, int NumElems> static size_t get_size() {
100+
// Referring to the simd class specialization on the host side is by design.
101+
return alignof(esimd::simd<DataT, NumElems>);
102+
}
103+
static constexpr auto get_value() { return esimd::vector_aligned; }
104+
};
105+
106+
struct overal {
107+
template <typename, int> static size_t get_size() {
108+
return alignof(std::max_align_t);
109+
}
110+
static constexpr auto get_value() {
111+
return esimd::overaligned<alignof(std::max_align_t)>;
112+
}
113+
};
114+
115+
} // namespace alignment
116+
117+
// The main test routine.
118+
// Using functor class to be able to iterate over the pre-defined data types.
119+
template <typename DataT, typename DimT, typename TestCaseT,
120+
typename AlignmentT>
121+
class run_test {
122+
static constexpr int NumElems = DimT::value;
123+
124+
public:
125+
bool operator()(sycl::queue &queue, const std::string &data_type) {
126+
bool passed = true;
127+
const std::vector<DataT> ref_data = generate_ref_data<DataT, NumElems>();
128+
129+
// If current number of elements is equal to one, then run test with each
130+
// one value from reference data.
131+
// If current number of elements is greater than one, then run tests with
132+
// whole reference data.
133+
if constexpr (NumElems == 1) {
134+
for (size_t i = 0; i < ref_data.size(); ++i) {
135+
passed = run_verification(queue, {ref_data[i]}, data_type);
136+
}
137+
} else {
138+
passed = run_verification(queue, ref_data, data_type);
139+
}
140+
return passed;
141+
}
142+
143+
private:
144+
bool run_verification(sycl::queue &queue, const std::vector<DataT> &ref_data,
145+
const std::string &data_type) {
146+
assert(ref_data.size() == NumElems &&
147+
"Reference data size is not equal to the simd vector length.");
148+
149+
bool passed = true;
150+
151+
const size_t alignment_value =
152+
AlignmentT::template get_size<DataT, NumElems>();
153+
const size_t container_extra_size = alignment_value / sizeof(DataT) + 1;
154+
const size_t offset = 1;
155+
156+
shared_allocator<DataT> allocator(queue);
157+
shared_vector<DataT> result(NumElems, allocator);
158+
shared_vector<DataT> shared_ref_data(NumElems + container_extra_size +
159+
offset,
160+
shared_allocator<DataT>(queue));
161+
162+
const size_t object_size = NumElems * sizeof(DataT);
163+
size_t buffer_size = object_size + container_extra_size * sizeof(DataT);
164+
165+
// When we allocate USM there is a high probability that this memory will
166+
// have stronger alignment that required. We increment our pointer by fixed
167+
// offset value to avoid bigger alignment of USM shared.
168+
// The std::align can provide expected alignment on the small values of an
169+
// alignment.
170+
void *ref = shared_ref_data.data() + offset;
171+
if (std::align(alignment_value, object_size, ref, buffer_size) == nullptr) {
172+
return false;
173+
}
174+
DataT *const ref_aligned = static_cast<DataT *>(ref);
175+
176+
for (size_t i = 0; i < NumElems; ++i) {
177+
ref_aligned[i] = ref_data[i];
178+
}
179+
180+
queue.submit([&](sycl::handler &cgh) {
181+
DataT *const out = result.data();
182+
183+
cgh.single_task<
184+
Kernel_for_load_ctor<DataT, NumElems, TestCaseT, AlignmentT>>(
185+
[=]() SYCL_ESIMD_KERNEL {
186+
const auto alignment = AlignmentT::get_value();
187+
TestCaseT::template call_simd_ctor<DataT, NumElems>(ref_aligned,
188+
out, alignment);
189+
});
190+
});
191+
queue.wait_and_throw();
192+
193+
for (size_t i = 0; i < result.size(); ++i) {
194+
if (!are_bitwise_equal(ref_data[i], result[i])) {
195+
passed = false;
196+
197+
const auto description =
198+
ctors::TestDescription<DataT, NumElems, TestCaseT>(
199+
i, result[i], ref_data[i], data_type);
200+
log::fail(description);
201+
}
202+
}
203+
204+
return passed;
205+
}
206+
};
207+
208+
} // namespace esimd_test::api::functional::ctors

0 commit comments

Comments
 (0)