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

Commit 1548e68

Browse files
authored
[SYCL][ESIMD] Add test on simd load ctor (#769)
1 parent 0d62adf commit 1548e68

File tree

1 file changed

+233
-0
lines changed

1 file changed

+233
-0
lines changed
Lines changed: 233 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,233 @@
1+
//==------- ctor_load_core.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+
// RUN: %clangxx -fsycl %s -fsycl-device-code-split=per_kernel -o %t.out
15+
// RUN: %GPU_RUN_PLACEHOLDER %t.out
16+
//
17+
// Test for simd load constructor.
18+
// The test uses reference data and different alignment flags. Invokes simd
19+
// constructors in different contexts with provided reference data and alignment
20+
// flag.
21+
// It is expected for destination simd instance to store a bitwise same data as
22+
// the reference one.
23+
24+
#include "common.hpp"
25+
26+
using namespace sycl::ext::intel::experimental::esimd;
27+
using namespace esimd_test::api::functional;
28+
29+
// Descriptor class for the case of calling constructor in initializer context.
30+
struct initializer {
31+
static std::string get_description() { return "initializer"; }
32+
33+
template <typename DataT, int NumElems, typename AlignmentT>
34+
static void call_simd_ctor(const DataT *ref_data, DataT *const out,
35+
AlignmentT alignment) {
36+
simd<DataT, NumElems> simd_by_init =
37+
simd<DataT, NumElems>(ref_data, alignment);
38+
simd_by_init.copy_to(out);
39+
}
40+
};
41+
42+
// Descriptor class for the case of calling constructor in variable declaration
43+
// context.
44+
struct var_decl {
45+
static std::string get_description() { return "variable declaration"; }
46+
47+
template <typename DataT, int NumElems, typename AlignmentT>
48+
static void call_simd_ctor(const DataT *ref_data, DataT *const out,
49+
AlignmentT alignment) {
50+
simd<DataT, NumElems> simd_by_var_decl(ref_data, alignment);
51+
simd_by_var_decl.copy_to(out);
52+
}
53+
};
54+
55+
// Descriptor class for the case of calling constructor in rvalue in an
56+
// expression context.
57+
struct rval_in_expr {
58+
static std::string get_description() { return "rvalue in an expression"; }
59+
60+
template <typename DataT, int NumElems, typename AlignmentT>
61+
static void call_simd_ctor(const DataT *ref_data, DataT *const out,
62+
AlignmentT alignment) {
63+
simd<DataT, NumElems> simd_by_rval;
64+
simd_by_rval = simd<DataT, NumElems>(ref_data, alignment);
65+
simd_by_rval.copy_to(out);
66+
}
67+
};
68+
69+
// Descriptor class for the case of calling constructor in const reference
70+
// context.
71+
class const_ref {
72+
public:
73+
static std::string get_description() { return "const reference"; }
74+
75+
template <typename DataT, int NumElems, typename AlignmentT>
76+
static void call_simd_ctor(const DataT *ref_data, DataT *const out,
77+
AlignmentT alignment) {
78+
call_simd_by_const_ref<DataT, NumElems>(
79+
simd<DataT, NumElems>(ref_data, alignment), out);
80+
}
81+
82+
private:
83+
template <typename DataT, int NumElems>
84+
static void
85+
call_simd_by_const_ref(const simd<DataT, NumElems> &simd_by_const_ref,
86+
DataT *out) {
87+
simd_by_const_ref.copy_to(out);
88+
}
89+
};
90+
91+
// Dummy kernel for submitting some code into device side.
92+
template <typename DataT, int NumElems, typename T, typename Alignment>
93+
struct Kernel_for_load_ctor;
94+
95+
namespace alignment {
96+
97+
struct element {
98+
template <typename DataT, int> static size_t get_size() {
99+
return alignof(DataT);
100+
}
101+
static constexpr auto get_value() { return element_aligned; }
102+
};
103+
104+
struct vector {
105+
template <typename DataT, int NumElems> static size_t get_size() {
106+
// Referring to the simd class specialization on the host side is by design.
107+
return alignof(simd<DataT, NumElems>);
108+
}
109+
static constexpr auto get_value() { return vector_aligned; }
110+
};
111+
112+
struct overal {
113+
template <typename, int> static size_t get_size() {
114+
return alignof(std::max_align_t);
115+
}
116+
static constexpr auto get_value() {
117+
return overaligned<alignof(std::max_align_t)>;
118+
}
119+
};
120+
121+
} // namespace alignment
122+
123+
// The main test routine.
124+
// Using functor class to be able to iterate over the pre-defined data types.
125+
template <typename DataT, typename DimT, typename TestCaseT,
126+
typename AlignmentT>
127+
class run_test {
128+
static constexpr int NumElems = DimT::value;
129+
130+
public:
131+
bool operator()(sycl::queue &queue, const std::string &data_type) {
132+
bool passed = true;
133+
const std::vector<DataT> ref_data = generate_ref_data<DataT, NumElems>();
134+
135+
// If current number of elements is equal to one, then run test with each
136+
// one value from reference data.
137+
// If current number of elements is greater than one, then run tests with
138+
// whole reference data.
139+
if constexpr (NumElems == 1) {
140+
for (size_t i = 0; i < ref_data.size(); ++i) {
141+
passed = run_verification(queue, {ref_data[i]}, data_type);
142+
}
143+
} else {
144+
passed = run_verification(queue, ref_data, data_type);
145+
}
146+
return passed;
147+
}
148+
149+
private:
150+
bool run_verification(sycl::queue &queue, const std::vector<DataT> &ref_data,
151+
const std::string &data_type) {
152+
assert(ref_data.size() == NumElems &&
153+
"Reference data size is not equal to the simd vector length.");
154+
155+
bool passed = true;
156+
157+
const size_t alignment_value =
158+
AlignmentT::template get_size<DataT, NumElems>();
159+
const size_t container_extra_size = alignment_value / sizeof(DataT) + 1;
160+
const size_t offset = 1;
161+
162+
shared_allocator<DataT> allocator(queue);
163+
shared_vector<DataT> result(NumElems, allocator);
164+
shared_vector<DataT> shared_ref_data(NumElems + container_extra_size +
165+
offset,
166+
shared_allocator<DataT>(queue));
167+
168+
const size_t object_size = NumElems * sizeof(DataT);
169+
size_t buffer_size = object_size + container_extra_size * sizeof(DataT);
170+
171+
// When we allocate USM there is a high probability that this memory will
172+
// have stronger alignment that required. We increment our pointer by fixed
173+
// offset value to avoid bigger alignment of USM shared.
174+
// The std::align can provide expected alignment on the small values of an
175+
// alignment.
176+
void *ref = shared_ref_data.data() + offset;
177+
if (std::align(alignment_value, object_size, ref, buffer_size) == nullptr) {
178+
return false;
179+
}
180+
DataT *const ref_aligned = static_cast<DataT *>(ref);
181+
182+
for (size_t i = 0; i < NumElems; ++i) {
183+
ref_aligned[i] = ref_data[i];
184+
}
185+
186+
queue.submit([&](sycl::handler &cgh) {
187+
DataT *const out = result.data();
188+
189+
cgh.single_task<
190+
Kernel_for_load_ctor<DataT, NumElems, TestCaseT, AlignmentT>>(
191+
[=]() SYCL_ESIMD_KERNEL {
192+
const auto alignment = AlignmentT::get_value();
193+
TestCaseT::template call_simd_ctor<DataT, NumElems>(ref_aligned,
194+
out, alignment);
195+
});
196+
});
197+
queue.wait_and_throw();
198+
199+
for (size_t i = 0; i < result.size(); ++i) {
200+
if (!are_bitwise_equal(ref_data[i], result[i])) {
201+
passed = false;
202+
203+
const auto description =
204+
ctors::TestDescription<DataT, NumElems, TestCaseT>(
205+
i, result[i], ref_data[i], data_type);
206+
log::fail(description);
207+
}
208+
}
209+
210+
return passed;
211+
}
212+
};
213+
214+
int main(int, char **) {
215+
sycl::queue queue(esimd_test::ESIMDSelector{},
216+
esimd_test::createExceptionHandler());
217+
218+
bool passed = true;
219+
const auto types = get_tested_types<tested_types::all>();
220+
const auto dims = get_all_dimensions();
221+
222+
const auto contexts = unnamed_type_pack<initializer, var_decl, rval_in_expr,
223+
const_ref>::generate();
224+
const auto alignments =
225+
unnamed_type_pack<alignment::element, alignment::vector,
226+
alignment::overal>::generate();
227+
228+
passed &=
229+
for_all_combinations<run_test>(types, dims, contexts, alignments, queue);
230+
231+
std::cout << (passed ? "=== Test passed\n" : "=== Test FAILED\n");
232+
return passed ? 0 : 1;
233+
}

0 commit comments

Comments
 (0)