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

Commit 2206708

Browse files
authored
[ESIMD] Add "smoke" test for esimd::saturate (#791)
Signed-off-by: Konstantin S Bobrovsky <[email protected]>
1 parent 5f8de8a commit 2206708

File tree

1 file changed

+210
-0
lines changed

1 file changed

+210
-0
lines changed

SYCL/ESIMD/api/saturation_smoke.cpp

Lines changed: 210 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,210 @@
1+
//==------- saturation_smoke.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
9+
// UNSUPPORTED: cuda || hip
10+
// RUN: %clangxx -fsycl %s -o %t.out
11+
// RUN: %GPU_RUN_PLACEHOLDER %t.out
12+
//
13+
// The test checks main functionality of esimd::saturate function.
14+
15+
#include "../esimd_test_utils.hpp"
16+
17+
#include <CL/sycl.hpp>
18+
#include <iostream>
19+
#include <sycl/ext/intel/experimental/esimd.hpp>
20+
21+
using namespace cl::sycl;
22+
using namespace sycl::ext::intel::experimental::esimd;
23+
24+
template <class T> struct char_to_int {
25+
using type = typename std::conditional<
26+
sizeof(T) == 1,
27+
typename std::conditional<std::is_signed<T>::value, int, unsigned>::type,
28+
T>::type;
29+
};
30+
31+
template <class T> bool verify(T *data_arr, T *gold_arr, int N) {
32+
int err_cnt = 0;
33+
34+
for (unsigned i = 0; i < N; ++i) {
35+
T val = data_arr[i];
36+
T gold = gold_arr[i];
37+
38+
if (val != gold) {
39+
if (++err_cnt < 10) {
40+
using T1 = typename char_to_int<T>::type;
41+
std::cout << " failed at index " << i << ": " << (T1)val
42+
<< " != " << (T1)gold << " (gold)\n";
43+
}
44+
}
45+
}
46+
if (err_cnt > 0) {
47+
std::cout << " pass rate: " << ((float)(N - err_cnt) / (float)N) * 100.0f
48+
<< "% (" << (N - err_cnt) << "/" << N << ")\n";
49+
}
50+
return err_cnt == 0;
51+
}
52+
53+
template <class From, class To, int Nx> struct DataMgr {
54+
From *src;
55+
To *dst;
56+
To *gold;
57+
static inline constexpr int N = Nx;
58+
59+
DataMgr(From (&&src_data)[N], To (&&gold_data)[N]) {
60+
src = new From[N];
61+
dst = new To[N];
62+
gold = new To[N];
63+
64+
for (int i = 0; i < N; i++) {
65+
src[i] = src_data[i];
66+
dst[i] = (To)2; // 0, 1 can be results of saturation, so use 2
67+
gold[i] = gold_data[i];
68+
}
69+
}
70+
71+
~DataMgr() {
72+
delete[] src;
73+
delete[] dst;
74+
delete[] gold;
75+
}
76+
};
77+
78+
template <class From, class To, template <class, class> class Mgr>
79+
bool test(queue q) {
80+
std::cout << "Testing " << typeid(From).name() << " -> " << typeid(To).name()
81+
<< "\n";
82+
83+
Mgr<From, To> dm;
84+
constexpr int N = Mgr<From, To>::N;
85+
86+
try {
87+
sycl::buffer<From, 1> src_buf(dm.src, N);
88+
sycl::buffer<To, 1> dst_buf(dm.dst, N);
89+
90+
auto e = q.submit([&](handler &cgh) {
91+
auto src_acc = src_buf.template get_access<access::mode::read>(cgh);
92+
auto dst_acc = dst_buf.template get_access<access::mode::write>(cgh);
93+
94+
cgh.single_task([=]() SYCL_ESIMD_KERNEL {
95+
simd<From, N> x(src_acc, 0);
96+
simd<To, N> y = saturate<To>(x);
97+
y.copy_to(dst_acc, 0);
98+
});
99+
});
100+
} catch (sycl::exception const &e) {
101+
std::cout << "SYCL exception caught: " << e.what() << '\n';
102+
return false; // not success
103+
}
104+
return verify<To>(dm.dst, dm.gold, N);
105+
}
106+
107+
// clang-format off
108+
template <class From, class To> struct FpToInt : public DataMgr<From, To, 2> {
109+
static_assert(
110+
(std::is_floating_point_v<From> || std::is_same_v<From, half>) &&
111+
std::is_integral_v<To>);
112+
static inline constexpr int N = 2;
113+
114+
FpToInt() : DataMgr<From, To, N>(
115+
// need this trick with -127 + 130 because INT_MAX is not accurately
116+
// representable with float, and compiler warns:
117+
// implicit conversion from 'int' to 'const float' changes value from
118+
// 2147483647 to 2147483648
119+
// INT_MAX-127 is accurately representable with float. Use +130 to exceed
120+
// representable range to actually test saturation.
121+
// Test data:
122+
{ (From)std::numeric_limits<To>::min() - 10,
123+
(From)(std::numeric_limits<To>::max()-127) + 130 },
124+
// Gold data (saturated test data):
125+
{ std::numeric_limits<To>::min(),
126+
std::numeric_limits<To>::max() })
127+
{}
128+
};
129+
130+
template <class From, class To>
131+
struct UIntToSameOrNarrowAnyInt : public DataMgr<From, To, 1> {
132+
static_assert(std::is_integral_v<To> && std::is_integral_v<From> &&
133+
!std::is_signed_v<From> && (sizeof(From) >= sizeof(To)));
134+
static inline constexpr int N = 1;
135+
136+
UIntToSameOrNarrowAnyInt() : DataMgr<From, To, N>(
137+
{ (From)((From)std::numeric_limits<To>::max() + (From)10) },
138+
{ (To)std::numeric_limits<To>::max() })
139+
{}
140+
};
141+
142+
template <class From, class To>
143+
struct IntToWiderUInt : public DataMgr<From, To, 1> {
144+
static_assert(std::is_signed_v<From> && !std::is_signed_v<To> &&
145+
(sizeof(From) < sizeof(To)));
146+
static inline constexpr int N = 1;
147+
148+
IntToWiderUInt() : DataMgr<From, To, N>(
149+
{ (From)-1 },
150+
{ (To)0 })
151+
{}
152+
};
153+
154+
template <class From, class To>
155+
struct SIntToNarrowAnyInt : public DataMgr<From, To, 2> {
156+
static_assert(std::is_integral_v<From> && std::is_signed_v<From> &&
157+
std::is_integral_v<To> && (sizeof(From) > sizeof(To)));
158+
static inline constexpr int N = 2;
159+
160+
SIntToNarrowAnyInt() : DataMgr<From, To, N>(
161+
{ (From)std::numeric_limits<To>::max() + 10,
162+
(From)std::numeric_limits<To>::min() - 10 },
163+
{ (To)std::numeric_limits<To>::max(),
164+
(To)std::numeric_limits<To>::min() })
165+
{}
166+
};
167+
168+
template <class From, class To> struct FpToFp : public DataMgr<From, To, 5> {
169+
static_assert((std::is_floating_point_v<To> || std::is_same_v<To, half>));
170+
static inline constexpr int N = 5;
171+
172+
FpToFp() : DataMgr<From, To, N>(
173+
{ (From)-10, (From)0, (From)0.5, (From)1, (From)10 },
174+
{ (To)0, (To)0, (To)((From)0.5), (To)1, (To)1 })
175+
{}
176+
};
177+
178+
// clang-format on
179+
180+
int main(int argc, char **argv) {
181+
queue q(esimd_test::ESIMDSelector{}, esimd_test::createExceptionHandler());
182+
auto dev = q.get_device();
183+
std::cout << "Running on " << dev.get_info<info::device::name>() << "\n";
184+
185+
bool passed = true;
186+
passed &= test<half, int, FpToInt>(q);
187+
passed &= test<half, unsigned char, FpToInt>(q);
188+
passed &= test<float, int, FpToInt>(q);
189+
passed &= test<double, short, FpToInt>(q);
190+
191+
passed &= test<unsigned char, char, UIntToSameOrNarrowAnyInt>(q);
192+
passed &= test<unsigned short, short, UIntToSameOrNarrowAnyInt>(q);
193+
passed &= test<unsigned int, int, UIntToSameOrNarrowAnyInt>(q);
194+
passed &= test<unsigned int, char, UIntToSameOrNarrowAnyInt>(q);
195+
passed &= test<unsigned short, unsigned char, UIntToSameOrNarrowAnyInt>(q);
196+
197+
passed &= test<char, unsigned int, IntToWiderUInt>(q);
198+
passed &= test<char, unsigned short, IntToWiderUInt>(q);
199+
passed &= test<short, unsigned int, IntToWiderUInt>(q);
200+
201+
passed &= test<short, char, SIntToNarrowAnyInt>(q);
202+
passed &= test<int, unsigned char, SIntToNarrowAnyInt>(q);
203+
204+
passed &= test<float, float, FpToFp>(q);
205+
passed &= test<half, half, FpToFp>(q);
206+
passed &= test<double, double, FpToFp>(q);
207+
208+
std::cout << (passed ? "Test passed\n" : "Test FAILED\n");
209+
return passed ? 0 : 1;
210+
}

0 commit comments

Comments
 (0)