Skip to content

Commit 17894ea

Browse files
authored
[SYCL][ESIMD] Add test for esimd default constructor (intel#565)
1 parent 968c587 commit 17894ea

File tree

4 files changed

+347
-0
lines changed

4 files changed

+347
-0
lines changed

SYCL/ESIMD/api/functional/common.hpp

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
//===-- common.hpp - This file provides common functions for simd constructors
2+
// tests -------------------------------------------------------------===//
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+
/// Common file for test on simd class.
12+
///
13+
//===----------------------------------------------------------------------===//
14+
15+
#pragma once
16+
17+
#include <CL/sycl.hpp>
18+
#include <sycl/ext/intel/experimental/esimd.hpp>
19+
20+
#include "../../esimd_test_utils.hpp"
21+
#include "logger.hpp"
22+
#include "type_coverage.hpp"
Lines changed: 160 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,160 @@
1+
//==------- ctor_default.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 esimd default constructor.
18+
//
19+
// The simd can't be constructed with sycl::half data type. The issue was
20+
// created (https://github.com/intel/llvm/issues/5077) and the TEST_HALF macros
21+
// must be enabled when it is resolved.
22+
23+
#include "../common.hpp"
24+
25+
using namespace cl::sycl;
26+
using namespace sycl::ext::intel::experimental::esimd;
27+
using namespace esimd_test::api::functional;
28+
29+
// Dummy kernel for submitting some code into device side.
30+
template <typename DataT, int NumElems, typename T> struct Kernel;
31+
32+
// Descriptor class for the case of calling constructor in initializer context
33+
struct initializer {
34+
static std::string get_description() { return "initializer"; }
35+
36+
template <typename DataT, int NumElems>
37+
static void call_simd_ctor(DataT *output_data) {
38+
simd<DataT, NumElems> simd_by_init = simd<DataT, NumElems>();
39+
simd_by_init.copy_to(output_data);
40+
}
41+
};
42+
43+
// Descriptor class for the case of calling constructor in variable declaration
44+
// context
45+
struct var_declaration {
46+
static std::string get_description() { return "variable declaration"; }
47+
48+
template <typename DataT, int NumElems>
49+
static void call_simd_ctor(DataT *output_data) {
50+
simd<DataT, NumElems> simd_by_var_decl;
51+
simd_by_var_decl.copy_to(output_data);
52+
}
53+
};
54+
55+
// Descriptor class for the case of calling constructor in rvalue in an
56+
// expression context
57+
struct rval_in_expression {
58+
static std::string get_description() { return "rvalue in an expression"; }
59+
60+
template <typename DataT, int NumElems>
61+
static void call_simd_ctor(DataT *output_data) {
62+
simd<DataT, NumElems> simd_by_rval;
63+
simd_by_rval = simd<DataT, NumElems>();
64+
simd_by_rval.copy_to(output_data);
65+
}
66+
};
67+
68+
// Descriptor class for the case of calling constructor in const reference
69+
// context
70+
struct const_ref {
71+
static std::string get_description() { return "const reference"; }
72+
73+
template <typename DataT, int NumElems>
74+
static void
75+
call_simd_by_const_ref(const simd<DataT, NumElems> &simd_by_const_ref,
76+
DataT *output_data) {
77+
simd_by_const_ref.copy_to(output_data);
78+
}
79+
80+
template <typename DataT, int NumElems>
81+
static void call_simd_ctor(DataT *output_data) {
82+
call_simd_by_const_ref<DataT, NumElems>(simd<DataT, NumElems>(),
83+
output_data);
84+
}
85+
};
86+
87+
// Functor with the main test routine to iterate over the pre-determined
88+
// datatypes
89+
template <typename DataT, int NumElems, typename TestCaseT> struct test {
90+
bool operator()(sycl::queue &queue, const std::string &data_type) {
91+
bool passed{true};
92+
93+
DataT default_val{};
94+
using AllocatorT = sycl::usm_allocator<DataT, sycl::usm::alloc::shared>;
95+
96+
std::vector<DataT, AllocatorT> result{NumElems, AllocatorT{queue}};
97+
queue.submit([&](sycl::handler &cgh) {
98+
auto out = result.data();
99+
cgh.single_task<Kernel<DataT, NumElems, TestCaseT>>(
100+
[=]() SYCL_ESIMD_KERNEL {
101+
TestCaseT::template call_simd_ctor<DataT, NumElems>(out);
102+
});
103+
});
104+
for (const auto &it : result) {
105+
if (it != default_val) {
106+
passed = false;
107+
log::fail<NumElems>(
108+
"In simd by " + TestCaseT::get_description() +
109+
" elem value is not equal to default value, retrieved: " +
110+
std::to_string(it) +
111+
", expected: " + std::to_string(default_val),
112+
data_type);
113+
}
114+
}
115+
return passed;
116+
}
117+
};
118+
119+
template <typename DataT, typename TestT>
120+
using run_test_with_one_elem = test<DataT, 1, TestT>;
121+
122+
template <typename DataT, typename TestT>
123+
using run_test_with_eight_elems = test<DataT, 8, TestT>;
124+
125+
template <typename DataT, typename TestT>
126+
using run_test_with_sixteen_elems = test<DataT, 16, TestT>;
127+
128+
template <typename DataT, typename TestT>
129+
using run_test_with_thirty_two_elems = test<DataT, 32, TestT>;
130+
131+
template <typename TestT, typename... T>
132+
bool run_verification_with_chosen_test_type(
133+
sycl::queue &queue, const named_type_pack<T...> &types) {
134+
bool passed{true};
135+
136+
passed &= for_all_types<run_test_with_one_elem, TestT>(types, queue);
137+
passed &= for_all_types<run_test_with_eight_elems, TestT>(types, queue);
138+
passed &= for_all_types<run_test_with_sixteen_elems, TestT>(types, queue);
139+
passed &= for_all_types<run_test_with_thirty_two_elems, TestT>(types, queue);
140+
return passed;
141+
}
142+
143+
int main(int argc, char **argv) {
144+
sycl::queue queue{esimd_test::ESIMDSelector{},
145+
esimd_test::createExceptionHandler()};
146+
147+
bool passed{true};
148+
149+
const auto types{get_tested_types<tested_types::all>()};
150+
151+
passed &= run_verification_with_chosen_test_type<initializer>(queue, types);
152+
passed &=
153+
run_verification_with_chosen_test_type<var_declaration>(queue, types);
154+
passed &=
155+
run_verification_with_chosen_test_type<rval_in_expression>(queue, types);
156+
passed &= run_verification_with_chosen_test_type<const_ref>(queue, types);
157+
158+
std::cout << (passed ? "=== Test passed\n" : "=== Test FAILED\n");
159+
return passed ? 0 : 1;
160+
}

SYCL/ESIMD/api/functional/logger.hpp

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
//===-- logger.hpp - Define functions for print messages to console. ---===//
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 contains the declarations of the functions that provides easier
11+
/// way to printing messages to the console.
12+
///
13+
//===----------------------------------------------------------------------===//
14+
15+
#pragma once
16+
17+
#include <iostream>
18+
#include <string>
19+
20+
namespace esimd_test {
21+
namespace api {
22+
namespace functional {
23+
namespace log {
24+
25+
// Printing failure message to console with pre-defined format
26+
template <int NumElems = 0>
27+
inline void fail(const std::string &msg,
28+
std::string underlying_data_type = "") {
29+
std::string log_msg{msg};
30+
if (!underlying_data_type.empty()) {
31+
log_msg += ", with data type: ";
32+
log_msg += underlying_data_type;
33+
}
34+
if constexpr (NumElems != 0) {
35+
log_msg += ", with num elements: ";
36+
log_msg += std::to_string(NumElems);
37+
}
38+
std::cout << log_msg << std::endl;
39+
}
40+
41+
// Printing provided string to the console with a forced flush to have all logs
42+
// available in case of `abort()` because of a test crash
43+
inline void note(const std::string &msg) { std::cout << msg << std::endl; }
44+
45+
} // namespace log
46+
} // namespace functional
47+
} // namespace api
48+
} // namespace esimd_test
Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
//===-- type_coverage.hpp - Define generic functions for type coverage. ---===//
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 a generic way to run tests with different types.
11+
///
12+
//===----------------------------------------------------------------------===//
13+
14+
#pragma once
15+
16+
#include <string>
17+
#include <type_traits>
18+
#include <utility>
19+
20+
namespace esimd_test {
21+
namespace api {
22+
namespace functional {
23+
24+
// Type pack to store types and underlying data type names to use with
25+
// type_name_string
26+
template <typename... T> struct named_type_pack {
27+
const std::string names[sizeof...(T)];
28+
29+
template <typename... nameListT>
30+
named_type_pack(nameListT &&... nameList)
31+
: names{std::forward<nameListT>(nameList)...} {}
32+
};
33+
34+
enum class tested_types { all, fp, uint, sint };
35+
36+
// Factory method to retrieve pre-defined named_type_pack, to have the same
37+
// default type coverage over the tests
38+
template <tested_types required> auto get_tested_types() {
39+
if constexpr (required == tested_types::all) {
40+
#ifdef TEST_HALF
41+
return named_type_pack<char, unsigned char, signed char, short,
42+
unsigned short, int, unsigned int, long,
43+
unsigned long, float, sycl::half, double, long long,
44+
unsigned long long>(
45+
{"char", "unsigned char", "signed char", "short", "unsigned short",
46+
"int", "unsigned int", "long", "unsigned long", "float", "sycl::half",
47+
"double", "long long", "unsigned long long"});
48+
#else
49+
return named_type_pack<char, unsigned char, signed char, short,
50+
unsigned short, int, unsigned int, long,
51+
unsigned long, float, double, long long,
52+
unsigned long long>(
53+
{"char", "unsigned char", "signed char", "short", "unsigned short",
54+
"int", "unsigned int", "long", "unsigned long", "float", "double",
55+
"long long", "unsigned long long"});
56+
#endif
57+
} else if constexpr (required == tested_types::fp) {
58+
#ifdef TEST_HALF
59+
return named_type_pack<float, sycl::half, double>(
60+
{"float", "sycl::half", "double"});
61+
#else
62+
return named_type_pack<float, double>({"float", "double"});
63+
#endif
64+
} else if constexpr (required == tested_types::uint) {
65+
if constexpr (!std::is_signed_v<char>) {
66+
return named_type_pack<unsigned char, unsigned short, unsigned int,
67+
unsigned long, unsigned long long, char>(
68+
{"unsigned char", "unsigned short", "unsigned int", "unsigned long",
69+
"unsigned long long", "char"});
70+
} else {
71+
return named_type_pack<unsigned char, unsigned short, unsigned int,
72+
unsigned long, unsigned long long>(
73+
{"unsigned char", "unsigned short", "unsigned int", "unsigned long",
74+
"unsigned long long"});
75+
}
76+
} else if constexpr (required == tested_types::sint) {
77+
if constexpr (std::is_signed_v<char>) {
78+
return named_type_pack<signed char, short, int, long, long long, char>(
79+
{"signed char", "short", "int", "long", "long long", "char"});
80+
} else {
81+
return named_type_pack<signed char, short, int, long, long long>(
82+
{"signed char", "short", "int", "long", "long long"});
83+
}
84+
} else {
85+
static_assert(required != required, "Unexpected tested type");
86+
}
87+
}
88+
89+
// Run action for each of types given by named_type_pack instance
90+
template <template <typename, typename...> class action,
91+
typename... actionArgsT, typename... types, typename... argsT>
92+
inline bool for_all_types(const named_type_pack<types...> &typeList,
93+
argsT &&... args) {
94+
bool passed{true};
95+
96+
// run action for each type from types... parameter pack
97+
size_t typeNameIndex = 0;
98+
99+
int packExpansion[] = {
100+
(passed &= action<types, actionArgsT...>{}(std::forward<argsT>(args)...,
101+
typeList.names[typeNameIndex]),
102+
++typeNameIndex,
103+
0 // Dummy initialization value
104+
)...};
105+
// Every initializer clause is sequenced before any initializer clause that
106+
// follows it in the braced-init-list. Every expression in comma operator is
107+
// also strictly sequenced. So we can use increment safely. We still should
108+
// discard dummy results, but this initialization should not be optimized out
109+
// due side-effects
110+
static_cast<void>(packExpansion);
111+
112+
return passed;
113+
}
114+
115+
} // namespace functional
116+
} // namespace api
117+
} // namespace esimd_test

0 commit comments

Comments
 (0)