Skip to content

Commit 7f49367

Browse files
[SYCL] Fix accessor fill for unsupported patterns (#8845)
Currently most of the PI backends have similar pattern limitations as OpenCL, i.e. only certain sizes of patterns are supported. This is not currently being considered by the implementation however, potentially causing the backend calls to fail. This commit makes the runtime fall back to a fill kernel if the pattern has an unsupported size. Signed-off-by: Larsen, Steffen <[email protected]>
1 parent 797187d commit 7f49367

File tree

2 files changed

+98
-5
lines changed

2 files changed

+98
-5
lines changed

sycl/include/sycl/handler.hpp

+10-5
Original file line numberDiff line numberDiff line change
@@ -913,6 +913,12 @@ class __SYCL_EXPORT handler {
913913
AccessMode == access::mode::discard_read_write;
914914
}
915915

916+
// PI APIs only support select fill sizes: 1, 2, 4, 8, 16, 32, 64, 128
917+
constexpr static bool isBackendSupportedFillSize(size_t Size) {
918+
return Size == 1 || Size == 2 || Size == 4 || Size == 8 || Size == 16 ||
919+
Size == 32 || Size == 64 || Size == 128;
920+
}
921+
916922
template <int Dims, typename LambdaArgType> struct TransformUserItemType {
917923
using type = typename std::conditional<
918924
std::is_convertible<nd_item<Dims>, LambdaArgType>::value, nd_item<Dims>,
@@ -2392,15 +2398,17 @@ class __SYCL_EXPORT handler {
23922398
fill(accessor<T, Dims, AccessMode, AccessTarget, IsPlaceholder, PropertyListT>
23932399
Dst,
23942400
const T &Pattern) {
2401+
assert(!MIsHost && "fill() should no longer be callable on a host device.");
2402+
23952403
if (Dst.is_placeholder())
23962404
checkIfPlaceholderIsBoundToHandler(Dst);
23972405

23982406
throwIfActionIsCreated();
23992407
// TODO add check:T must be an integral scalar value or a SYCL vector type
24002408
static_assert(isValidTargetForExplicitOp(AccessTarget),
24012409
"Invalid accessor target for the fill method.");
2402-
if (!MIsHost && (((Dims == 1) && isConstOrGlobal(AccessTarget)) ||
2403-
isImageOrImageArray(AccessTarget))) {
2410+
if constexpr (isBackendSupportedFillSize(sizeof(T)) &&
2411+
(Dims == 1 || isImageOrImageArray(AccessTarget))) {
24042412
setType(detail::CG::Fill);
24052413

24062414
detail::AccessorBaseHost *AccBase = (detail::AccessorBaseHost *)&Dst;
@@ -2414,9 +2422,6 @@ class __SYCL_EXPORT handler {
24142422
auto PatternPtr = reinterpret_cast<T *>(MPattern.data());
24152423
*PatternPtr = Pattern;
24162424
} else {
2417-
2418-
// TODO: Temporary implementation for host. Should be handled by memory
2419-
// manger.
24202425
range<Dims> Range = Dst.get_range();
24212426
parallel_for<
24222427
class __fill<T, Dims, AccessMode, AccessTarget, IsPlaceholder>>(

sycl/test-e2e/Basic/fill_accessor.cpp

+88
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
// RUN: %clangxx -fsycl -fsycl-targets=%sycl_triple %s -o %t.out
2+
// RUN: %CPU_RUN_PLACEHOLDER %t.out
3+
// RUN: %GPU_RUN_PLACEHOLDER %t.out
4+
// RUN: %ACC_RUN_PLACEHOLDER %t.out
5+
6+
#include <sycl/sycl.hpp>
7+
8+
#include <algorithm>
9+
#include <array>
10+
#include <numeric>
11+
12+
using namespace sycl;
13+
14+
size_t NumErrors = 0;
15+
16+
template <typename T, size_t N>
17+
std::ostream &operator<<(std::ostream &OS, const std::array<T, N> &Arr) {
18+
OS << "{";
19+
for (size_t I = 0; I < N; ++I) {
20+
if (I)
21+
OS << ",";
22+
OS << Arr[I];
23+
}
24+
OS << "}";
25+
return OS;
26+
}
27+
28+
template <typename T, int Dims>
29+
void CheckFill(queue &Q, range<Dims> Range, T Init, T Expected) {
30+
std::vector<T> Data(Range.size(), Init);
31+
{
32+
buffer<T, Dims> Buffer(Data.data(), Range);
33+
Q.submit([&](handler &CGH) {
34+
accessor Accessor(Buffer, CGH, write_only);
35+
CGH.fill(Accessor, Expected);
36+
}).wait_and_throw();
37+
}
38+
for (size_t I = 0; I < Range.size(); ++I) {
39+
if (Data[I] != Expected) {
40+
std::cout << "Unexpected value " << Data[I] << " at index " << I
41+
<< " after fill. Expected " << Expected << "." << std::endl;
42+
++NumErrors;
43+
return;
44+
}
45+
}
46+
}
47+
48+
template <typename T>
49+
void CheckFillDifferentDims(queue &Q, size_t N, T Init, T Expected) {
50+
CheckFill<T>(Q, range<1>{N}, Init, Expected);
51+
CheckFill<T>(Q, range<2>{N, N}, Init, Expected);
52+
CheckFill<T>(Q, range<3>{N, N, N}, Init, Expected);
53+
}
54+
55+
int main() {
56+
queue Q;
57+
58+
// Test different power-of-two sizes.
59+
CheckFillDifferentDims<char>(Q, 10, 'a', 'z');
60+
CheckFillDifferentDims<std::array<char, 2>>(Q, 10, {'a', 'z'}, {'z', 'a'});
61+
CheckFillDifferentDims<short>(Q, 10, 8, -16);
62+
CheckFillDifferentDims<float>(Q, 10, 123.4, 3.14);
63+
CheckFillDifferentDims<uint64_t>(Q, 10, 42, 24);
64+
CheckFillDifferentDims<std::array<uint64_t, 2>>(Q, 10, {4, 42}, {24, 4});
65+
CheckFillDifferentDims<std::array<uint64_t, 4>>(Q, 10, {4, 42, 424, 4242},
66+
{2424, 424, 24, 4});
67+
CheckFillDifferentDims<std::array<uint64_t, 8>>(
68+
Q, 10, {4, 42, 424, 4242, 42424, 424242, 4242424, 42424242},
69+
{24242424, 2424242, 242424, 24242, 2424, 424, 24, 4});
70+
CheckFillDifferentDims<std::array<uint64_t, 16>>(
71+
Q, 10,
72+
{24242424, 2424242, 242424, 24242, 2424, 424, 24, 4, 4, 42, 424, 4242,
73+
42424, 424242, 4242424, 42424242},
74+
{4, 42, 424, 4242, 42424, 424242, 4242424, 42424242, 24242424, 2424242,
75+
242424, 24242, 2424, 424, 24, 4});
76+
77+
// Test with non-power-of-two sizes.
78+
CheckFillDifferentDims<std::array<char, 5>>(Q, 10, {'a', 'b', 'c', 'd', 'e'},
79+
{'A', 'B', 'C', 'D', 'E'});
80+
std::array<char, 129> InitCharArray129;
81+
std::fill(InitCharArray129.begin(), InitCharArray129.end(), 130);
82+
std::array<char, 129> ExpectedCharArray129;
83+
std::iota(ExpectedCharArray129.begin(), ExpectedCharArray129.end(), 1);
84+
CheckFillDifferentDims<std::array<char, 129>>(Q, 10, InitCharArray129,
85+
ExpectedCharArray129);
86+
87+
return NumErrors;
88+
}

0 commit comments

Comments
 (0)