In conventional C++, it's possible to create a multi-dimensional "viewer" or "wrapper" to a 1D buffer in linear memory by (1) defining a custom ArrayWrapper class, (2) overriding the ()
or []
operator as its "accessor", doing the address calculation inside this member function, and (3) returning a reference to the value. Thus, a 4D array can be accessed via the syntactic sugar array(a, b, c, d) = val
. This improves code readability, and also decouples the viewer from the actual memory layout of the array.
#include <iostream>
#include <cstdlib>
template <typename T>
class ArrayWrapper
{
public:
ArrayWrapper(T *buf) : array(buf) {};
inline T& operator() (size_t a, size_t b, size_t c, size_t d)
{
return array[a + b + c + d];
}
const inline T& operator() (size_t a, size_t b, size_t c, size_t d) const
{
return array[a + b + c + d];
}
T *array;
};
int main(void)
{
int *buf = (int *) malloc(sizeof(int) * 100);
ArrayWrapper<int> array(buf);
array(1, 2, 3, 4) = 42;
std::cout << array(1, 2, 3, 4) << std::endl;
}
However, this wrapper is not usable in a DPC++ / SYCL 2020 kernel.
int main(void)
{
sycl::queue Q;
auto buf = sycl::malloc_shared<int>(20, Q);
ArrayWrapper<int> array(buf);
Q.single_task([=]() {
array(1, 2, 3, 4) = 42;
});
Q.wait();
std::cout << array(1, 2, 3, 4) << std::endl;
}
Compiling this function with Intel DPC++ compiler returns the following error:
question-sycl.cpp:37:21: error: expression is not assignable
array(1, 2, 3, 4) = 42;
~~~~~~~~~~~~~~~~~ ^
1 error generated.
make: *** [Makefile:8: question-sycl.elf] Error 1
This is the result due to the use of C++ lambda function, which "captures" variable outside its scope as const
variables by default. In conventional C++, this can be solved by either explicitly asking the lambda function to capture a reference Q.single_task([&array]() {}
, or declaring the lambda as a mutable function Q.single_task([=]() mutable {}
. However, both usages appear to be unsupported in SYCL and prohibited by the DPC++ compiler.
Is there a way to implement the same syntactic sugar array(a, b, c, d) = val
in DPC++ / SYCL 2020? I noticed that memory access in SYCL is provided by two abstractions called buffers and accessors. Unfortunately, they only support 1D, 2D, or 3D arrays, not higher dimensions. What is the best way to define a convenient wrapper for accessing high-dimension arrays?