Skip to content

Commit 7fb214a

Browse files
[SYCL] Refactor more builtin tests + workaround a bug it uncovered (#12877)
Unfortunately, can't do the same for `sycl::vec` tests because swizzles can't be captured and a macro seems unavoidable. Also, this includes a reworked version of #12875 that has been reverted in #12887. That also uncovered a bug in our `sycl::length` host implementation when the project is compiled using GCC. I'm not sure if that's a GCC bug or yet another instance of UB in `sycl::vec`/`sycl::half` implementation, but the only option at the moment is to workaround, which I'm doing here.
1 parent a4334da commit 7fb214a

File tree

6 files changed

+212
-345
lines changed

6 files changed

+212
-345
lines changed

sycl/source/builtins/geometric_functions.cpp

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,11 +36,22 @@ static inline auto dot_host_impl(T0 x, T1 y) {
3636
}
3737
EXPORT_SCALAR_AND_VEC_2_4(TWO_ARGS, dot, FP_TYPES)
3838

39+
#if defined(__GNUC__) && !defined(__clang__)
40+
// GCC miscompiles if using dot (instead of dot_host_impl) *or* if
41+
// optimizations aren't disabled here. Not sure if a bug in GCC or some UB in
42+
// sycl::vec/sycl::half (like ansi-alias violations).
43+
#pragma GCC push_options
44+
#pragma GCC optimize("O0")
45+
#endif
3946
template <typename T> static inline auto length_host_impl(T x) {
40-
auto d = dot(x, x);
47+
auto d = dot_host_impl(x, x);
4148
return static_cast<decltype(d)>(std::sqrt(d));
4249
}
50+
#if defined(__GNUC__) && !defined(__clang__)
51+
#pragma GCC pop_options
52+
#endif
4353
EXPORT_SCALAR_AND_VEC_2_4(ONE_ARG, length, FP_TYPES)
54+
4455
// fast_length on host is the same as just length.
4556
template <typename T> static inline auto fast_length_host_impl(T x) {
4657
return length_host_impl(x);

sycl/test-e2e/Basic/built-ins/helpers.hpp

Lines changed: 29 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,43 +1,62 @@
11
#include <sycl/sycl.hpp>
22

3-
template <typename T> bool equal(T x, T y) {
3+
template <typename T, typename D> bool equal(T x, T y, D delta) {
44
// Maybe should be C++20's std::equality_comparable.
5-
if constexpr (std::is_scalar_v<T>) {
6-
return x == y;
5+
auto Abs = [](auto x) {
6+
if constexpr (std::is_unsigned_v<decltype(x)>)
7+
return x;
8+
else
9+
return std::abs(x);
10+
};
11+
if constexpr (std::is_scalar_v<T> || std::is_same_v<sycl::half, T>) {
12+
return Abs(x - y) <= delta;
713
} else {
814
for (size_t i = 0; i < x.size(); ++i)
9-
if (x[i] != y[i])
15+
if (Abs(x[i] - y[i]) > delta)
1016
return false;
1117

1218
return true;
1319
}
1420
}
1521

16-
template <typename FuncTy, typename ExpectedTy,
17-
typename... ArgTys>
18-
void test(bool CheckDevice, FuncTy F, ExpectedTy Expected, ArgTys... Args) {
22+
template <typename FuncTy, typename ExpectedTy, typename... ArgTys>
23+
void test(bool CheckDevice, double delta, FuncTy F, ExpectedTy Expected,
24+
ArgTys... Args) {
1925
auto R = F(Args...);
2026
static_assert(std::is_same_v<decltype(Expected), decltype(R)>);
21-
assert(equal(R, Expected));
27+
assert(equal(R, Expected, delta));
2228

2329
if (!CheckDevice)
2430
return;
2531

2632
sycl::buffer<bool, 1> SuccessBuf{1};
33+
34+
// Make sure we don't use fp64 on devices that don't support it.
35+
sycl::detail::get_elem_type_t<ExpectedTy> d(delta);
36+
2737
sycl::queue{}.submit([&](sycl::handler &cgh) {
2838
sycl::accessor Success{SuccessBuf, cgh};
2939
cgh.single_task([=]() {
3040
auto R = F(Args...);
3141
static_assert(std::is_same_v<decltype(Expected), decltype(R)>);
32-
Success[0] = equal(R, Expected);
42+
Success[0] = equal(R, Expected, d);
3343
});
3444
});
3545
assert(sycl::host_accessor{SuccessBuf}[0]);
3646
}
3747

3848
template <typename FuncTy, typename ExpectedTy, typename... ArgTys>
3949
void test(FuncTy F, ExpectedTy Expected, ArgTys... Args) {
40-
test(true /*CheckDevice*/, F, Expected, Args...);
50+
test(true /*CheckDevice*/, 0.0 /*delta*/, F, Expected, Args...);
51+
}
52+
template <typename FuncTy, typename ExpectedTy,
53+
typename... ArgTys>
54+
void test(bool CheckDevice, FuncTy F, ExpectedTy Expected, ArgTys... Args) {
55+
test(CheckDevice, 0.0 /*delta*/, F, Expected, Args...);
56+
}
57+
template <typename FuncTy, typename ExpectedTy, typename... ArgTys>
58+
void test(double delta, FuncTy F, ExpectedTy Expected, ArgTys... Args) {
59+
test(true /*CheckDevice*/, delta, F, Expected, Args...);
4160
}
4261

4362
// MSVC's STL spoils global namespace with math functions, so use explicit

sycl/test-e2e/Basic/built-ins/marray_common.cpp

Lines changed: 62 additions & 104 deletions
Original file line numberDiff line numberDiff line change
@@ -8,115 +8,73 @@
88
#endif
99
#include <cmath>
1010

11-
#include <sycl/sycl.hpp>
12-
13-
#define TEST(FUNC, MARRAY_ELEM_TYPE, DIM, EXPECTED, DELTA, ...) \
14-
{ \
15-
{ \
16-
MARRAY_ELEM_TYPE result[DIM]; \
17-
{ \
18-
sycl::buffer<MARRAY_ELEM_TYPE> b(result, sycl::range{DIM}); \
19-
deviceQueue.submit([&](sycl::handler &cgh) { \
20-
sycl::accessor res_access{b, cgh}; \
21-
cgh.single_task([=]() { \
22-
sycl::marray<MARRAY_ELEM_TYPE, DIM> res = FUNC(__VA_ARGS__); \
23-
for (int i = 0; i < DIM; i++) \
24-
res_access[i] = res[i]; \
25-
}); \
26-
}); \
27-
} \
28-
for (int i = 0; i < DIM; i++) \
29-
assert(abs(result[i] - EXPECTED[i]) <= DELTA); \
30-
} \
31-
}
32-
33-
#define EXPECTED(TYPE, ...) ((TYPE[]){__VA_ARGS__})
11+
#include "helpers.hpp"
3412

3513
int main() {
36-
sycl::queue deviceQueue;
37-
sycl::device dev = deviceQueue.get_device();
14+
using namespace sycl;
15+
16+
marray<float, 2> ma1{1.0f, 2.0f};
17+
marray<float, 2> ma2{1.0f, 2.0f};
18+
marray<float, 2> ma3{3.0f, 2.0f};
19+
marray<double, 2> ma4{1.0, 2.0};
20+
marray<float, 3> ma5{M_PI, M_PI, M_PI};
21+
marray<double, 3> ma6{M_PI, M_PI, M_PI};
22+
marray<half, 3> ma7{M_PI, M_PI, M_PI};
23+
marray<float, 2> ma8{0.3f, 0.6f};
24+
marray<double, 2> ma9{5.0, 8.0};
25+
marray<float, 3> ma10{180, 180, 180};
26+
marray<double, 3> ma11{180, 180, 180};
27+
marray<half, 3> ma12{180, 180, 180};
28+
marray<half, 3> ma13{181, 179, 181};
29+
marray<float, 2> ma14{+0.0f, -0.6f};
30+
marray<double, 2> ma15{-0.0, 0.6f};
3831

39-
sycl::marray<float, 2> ma1{1.0f, 2.0f};
40-
sycl::marray<float, 2> ma2{1.0f, 2.0f};
41-
sycl::marray<float, 2> ma3{3.0f, 2.0f};
42-
sycl::marray<double, 2> ma4{1.0, 2.0};
43-
sycl::marray<float, 3> ma5{M_PI, M_PI, M_PI};
44-
sycl::marray<double, 3> ma6{M_PI, M_PI, M_PI};
45-
sycl::marray<sycl::half, 3> ma7{M_PI, M_PI, M_PI};
46-
sycl::marray<float, 2> ma8{0.3f, 0.6f};
47-
sycl::marray<double, 2> ma9{5.0, 8.0};
48-
sycl::marray<float, 3> ma10{180, 180, 180};
49-
sycl::marray<double, 3> ma11{180, 180, 180};
50-
sycl::marray<sycl::half, 3> ma12{180, 180, 180};
51-
sycl::marray<sycl::half, 3> ma13{181, 179, 181};
52-
sycl::marray<float, 2> ma14{+0.0f, -0.6f};
53-
sycl::marray<double, 2> ma15{-0.0, 0.6f};
32+
bool has_fp16 = queue{}.get_device().has(sycl::aspect::fp16);
33+
bool has_fp64 = queue{}.get_device().has(sycl::aspect::fp64);
5434

55-
// sycl::clamp
56-
TEST(sycl::clamp, float, 2, EXPECTED(float, 1.0f, 2.0f), 0, ma1, ma2, ma3);
57-
TEST(sycl::clamp, float, 2, EXPECTED(float, 1.0f, 2.0f), 0, ma1, 1.0f, 3.0f);
58-
if (dev.has(sycl::aspect::fp64))
59-
TEST(sycl::clamp, double, 2, EXPECTED(double, 1.0, 2.0), 0, ma4, 1.0, 3.0);
60-
// sycl::degrees
61-
TEST(sycl::degrees, float, 3, EXPECTED(float, 180, 180, 180), 0, ma5);
62-
if (dev.has(sycl::aspect::fp64))
63-
TEST(sycl::degrees, double, 3, EXPECTED(double, 180, 180, 180), 0, ma6);
64-
if (dev.has(sycl::aspect::fp16))
65-
TEST(sycl::degrees, sycl::half, 3, EXPECTED(sycl::half, 180, 180, 180), 0.2,
66-
ma7);
67-
// sycl::max
68-
TEST(sycl::max, float, 2, EXPECTED(float, 3.0f, 2.0f), 0, ma1, ma3);
69-
TEST(sycl::max, float, 2, EXPECTED(float, 1.5f, 2.0f), 0, ma1, 1.5f);
70-
if (dev.has(sycl::aspect::fp64))
71-
TEST(sycl::max, double, 2, EXPECTED(double, 1.5, 2.0), 0, ma4, 1.5);
72-
// sycl::min
73-
TEST(sycl::min, float, 2, EXPECTED(float, 1.0f, 2.0f), 0, ma1, ma3);
74-
TEST(sycl::min, float, 2, EXPECTED(float, 1.0f, 1.5f), 0, ma1, 1.5f);
75-
if (dev.has(sycl::aspect::fp64))
76-
TEST(sycl::min, double, 2, EXPECTED(double, 1.0, 1.5), 0, ma4, 1.5);
77-
// sycl::mix
78-
TEST(sycl::mix, float, 2, EXPECTED(float, 1.6f, 2.0f), 0, ma1, ma3, ma8);
79-
TEST(sycl::mix, float, 2, EXPECTED(float, 1.4f, 2.0f), 0, ma1, ma3, 0.2);
80-
if (dev.has(sycl::aspect::fp64))
81-
TEST(sycl::mix, double, 2, EXPECTED(double, 3.0, 5.0), 0, ma4, ma9, 0.5);
82-
// sycl::radians
83-
TEST(sycl::radians, float, 3, EXPECTED(float, M_PI, M_PI, M_PI), 0, ma10);
84-
if (dev.has(sycl::aspect::fp64))
85-
TEST(sycl::radians, double, 3, EXPECTED(double, M_PI, M_PI, M_PI), 0, ma11);
86-
if (dev.has(sycl::aspect::fp16))
87-
TEST(sycl::radians, sycl::half, 3, EXPECTED(sycl::half, M_PI, M_PI, M_PI),
88-
0.002, ma12);
89-
// sycl::step
90-
TEST(sycl::step, float, 2, EXPECTED(float, 1.0f, 1.0f), 0, ma1, ma3);
91-
if (dev.has(sycl::aspect::fp64))
92-
TEST(sycl::step, double, 2, EXPECTED(double, 1.0, 1.0), 0, ma4, ma9);
93-
if (dev.has(sycl::aspect::fp16))
94-
TEST(sycl::step, sycl::half, 3, EXPECTED(sycl::half, 1.0, 0.0, 1.0), 0,
95-
ma12, ma13);
96-
TEST(sycl::step, float, 2, EXPECTED(float, 1.0f, 0.0f), 0, 2.5f, ma3);
97-
if (dev.has(sycl::aspect::fp64))
98-
TEST(sycl::step, double, 2, EXPECTED(double, 0.0f, 1.0f), 0, 6.0f, ma9);
99-
// sycl::smoothstep
100-
TEST(sycl::smoothstep, float, 2, EXPECTED(float, 1.0f, 1.0f), 0, ma8, ma1,
101-
ma2);
102-
if (dev.has(sycl::aspect::fp64))
103-
TEST(sycl::smoothstep, double, 2, EXPECTED(double, 1.0, 1.0f), 0.00000001,
104-
ma4, ma9, ma9);
105-
if (dev.has(sycl::aspect::fp16))
106-
TEST(sycl::smoothstep, sycl::half, 3, EXPECTED(sycl::half, 1.0, 1.0, 1.0),
107-
0, ma7, ma12, ma13);
108-
TEST(sycl::smoothstep, float, 2, EXPECTED(float, 0.0553936f, 0.0f), 0.0000001,
109-
2.5f, 6.0f, ma3);
110-
if (dev.has(sycl::aspect::fp64))
111-
TEST(sycl::smoothstep, double, 2, EXPECTED(double, 0.0f, 1.0f), 0, 6.0f,
112-
8.0f, ma9);
35+
// clamp
36+
test(F(clamp), marray<float, 2>{1.0f, 2.0f}, ma1, ma2, ma3);
37+
test(F(clamp), marray<float, 2>{1.0f, 2.0f}, ma1, 1.0f, 3.0f);
38+
test(has_fp64, F(clamp), marray<double, 2>{1.0, 2.0}, ma4, 1.0, 3.0);
39+
// degrees
40+
test(F(degrees), marray<float, 3>{180, 180, 180}, ma5);
41+
test(has_fp64, F(degrees), marray<double, 3>{180, 180, 180}, ma6);
42+
test(has_fp16, 0.2, F(degrees), marray<half, 3>{180, 180, 180}, ma7);
43+
// max
44+
test(F(max), marray<float, 2>{3.0f, 2.0f}, ma1, ma3);
45+
test(F(max), marray<float, 2>{1.5f, 2.0f}, ma1, 1.5f);
46+
test(has_fp64, F(max), marray<double, 2>{1.5, 2.0}, ma4, 1.5);
47+
// min
48+
test(F(min), marray<float, 2>{1.0f, 2.0f}, ma1, ma3);
49+
test(F(min), marray<float, 2>{1.0f, 1.5f}, ma1, 1.5f);
50+
test(has_fp64, F(min), marray<double, 2>{1.0, 1.5}, ma4, 1.5);
51+
// mix
52+
test(F(mix), marray<float, 2>{1.6f, 2.0f}, ma1, ma3, ma8);
53+
test(F(mix), marray<float, 2>{1.4f, 2.0f}, ma1, ma3, 0.2f);
54+
test(has_fp64, F(mix), marray<double, 2>{3.0, 5.0}, ma4, ma9, 0.5);
55+
// radians
56+
test(F(radians), marray<float, 3>{M_PI, M_PI, M_PI}, ma10);
57+
test(has_fp64, F(radians), marray<double, 3>{M_PI, M_PI, M_PI}, ma11);
58+
test(has_fp16, 0.002, F(radians), marray<half, 3>{M_PI, M_PI, M_PI}, ma12);
59+
// step
60+
test(F(step), marray<float, 2>{1.0f, 1.0f}, ma1, ma3);
61+
test(has_fp64, F(step), marray<double, 2>{1.0, 1.0}, ma4, ma9);
62+
test(has_fp16, F(step), marray<half, 3>{1.0, 0.0, 1.0}, ma12, ma13);
63+
test(F(step), marray<float, 2>{1.0f, 0.0f}, 2.5f, ma3);
64+
test(has_fp64, F(step), marray<double, 2>{0.0f, 1.0f}, 6.0f, ma9);
65+
// smoothstep
66+
test(F(smoothstep), marray<float, 2>{1.0f, 1.0f}, ma8, ma1, ma2);
67+
test(has_fp64, 0.00000001, F(smoothstep), marray<double, 2>{1.0, 1.0f}, ma4,
68+
ma9, ma9);
69+
test(has_fp16, F(smoothstep), marray<half, 3>{1.0, 1.0, 1.0}, ma7, ma12,
70+
ma13);
71+
test(0.0000001, F(smoothstep), marray<float, 2>{0.0553936f, 0.0f}, 2.5f, 6.0f,
72+
ma3);
73+
test(has_fp64, F(smoothstep), marray<double, 2>{0.0f, 1.0f}, 6.0f, 8.0f, ma9);
11374
// sign
114-
TEST(sycl::sign, float, 2, EXPECTED(float, +0.0f, -1.0f), 0, ma14);
115-
if (dev.has(sycl::aspect::fp64))
116-
TEST(sycl::sign, double, 2, EXPECTED(double, -0.0, 1.0), 0, ma15);
117-
if (dev.has(sycl::aspect::fp16))
118-
TEST(sycl::sign, sycl::half, 3, EXPECTED(sycl::half, 1.0, 1.0, 1.0), 0,
119-
ma12);
75+
test(F(sign), marray<float, 2>{+0.0f, -1.0f}, ma14);
76+
test(has_fp64, F(sign), marray<double, 2>{-0.0, 1.0}, ma15);
77+
test(has_fp16, F(sign), marray<half, 3>{1.0, 1.0, 1.0}, ma12);
12078

12179
return 0;
12280
}

0 commit comments

Comments
 (0)