blob: 1afb70e634303c106cce56872aef9b10aefd5fbc [file] [edit]
// REQUIRES: any-device
// RUN: %clangxx -fsycl %s -o %t.out
// RUN: %t.out
//
// Unified test for sycl::range and sycl::id covering all operators defined in
// theirs base class, plus class-specific behaviour for each type.
#include <cassert>
#include <sycl/sycl.hpp>
#include <type_traits>
using sycl::detail::Builder;
// Helper to create values for any dimension from three components.
// Only uses the required number of values based on dimension.
template <template <int> class T, int Dim>
T<Dim> makeValue(std::size_t a, std::size_t b = 0, std::size_t c = 0) {
if constexpr (Dim == 1)
return T<1>(a);
else if constexpr (Dim == 2)
return T<2>(a, b);
else
return T<3>(a, b, c);
}
// Tests binary and compound operators for a specific dimension.
template <template <int> class T, int Dim> void testBinaryOpsForDim() {
const T<Dim> P = makeValue<T, Dim>(8, 9, 10);
const T<Dim> Q = makeValue<T, Dim>(2, 3, 5);
// Binary operators: object op object.
assert((P + Q) == (makeValue<T, Dim>(10, 12, 15)));
assert((P - Q) == (makeValue<T, Dim>(6, 6, 5)));
assert((P * Q) == (makeValue<T, Dim>(16, 27, 50)));
assert((P / Q) == (makeValue<T, Dim>(4, 3, 2)));
assert((P % Q) == (makeValue<T, Dim>(0, 0, 0)));
assert((P << Q) == (makeValue<T, Dim>(32, 72, 320)));
assert((P >> Q) == (makeValue<T, Dim>(2, 1, 0)));
assert((P & Q) == (makeValue<T, Dim>(0, 1, 0)));
assert((P | Q) == (makeValue<T, Dim>(10, 11, 15)));
assert((P ^ Q) == (makeValue<T, Dim>(10, 10, 15)));
assert((P && Q) == (makeValue<T, Dim>(1, 1, 1)));
assert((P || Q) == (makeValue<T, Dim>(1, 1, 1)));
assert((P < Q) == (makeValue<T, Dim>(0, 0, 0)));
assert((P > Q) == (makeValue<T, Dim>(1, 1, 1)));
assert((P <= Q) == (makeValue<T, Dim>(0, 0, 0)));
assert((P >= Q) == (makeValue<T, Dim>(1, 1, 1)));
// Binary operators: object op scalar.
assert((P + 1) == (makeValue<T, Dim>(9, 10, 11)));
assert((P - 1) == (makeValue<T, Dim>(7, 8, 9)));
assert((P * 2) == (makeValue<T, Dim>(16, 18, 20)));
assert((P / 2) == (makeValue<T, Dim>(4, 4, 5)));
assert((P % 4) == (makeValue<T, Dim>(0, 1, 2)));
assert((P << 1) == (makeValue<T, Dim>(16, 18, 20)));
assert((P >> 1) == (makeValue<T, Dim>(4, 4, 5)));
assert((P & 6) == (makeValue<T, Dim>(0, 0, 2)));
assert((P | 1) == (makeValue<T, Dim>(9, 9, 11)));
assert((P ^ 3) == (makeValue<T, Dim>(11, 10, 9)));
assert((P && 0) == (makeValue<T, Dim>(0, 0, 0)));
assert((P || 0) == (makeValue<T, Dim>(1, 1, 1)));
assert((P < 9) == (makeValue<T, Dim>(1, 0, 0)));
assert((P > 9) == (makeValue<T, Dim>(0, 0, 1)));
assert((P <= 9) == (makeValue<T, Dim>(1, 1, 0)));
assert((P >= 9) == (makeValue<T, Dim>(0, 1, 1)));
// Binary operators: scalar op object.
assert((1 + P) == (makeValue<T, Dim>(9, 10, 11)));
assert((20 - Q) == (makeValue<T, Dim>(18, 17, 15)));
assert((2 * P) == (makeValue<T, Dim>(16, 18, 20)));
assert((20 / Q) == (makeValue<T, Dim>(10, 6, 4)));
assert((33 % Q) == (makeValue<T, Dim>(1, 0, 3)));
assert((1 << Q) == (makeValue<T, Dim>(4, 8, 32)));
assert((256 >> Q) == (makeValue<T, Dim>(64, 32, 8)));
assert((15 & Q) == (makeValue<T, Dim>(2, 3, 5)));
assert((1 | Q) == (makeValue<T, Dim>(3, 3, 5)));
assert((3 ^ Q) == (makeValue<T, Dim>(1, 0, 6)));
assert((1 && Q) == (makeValue<T, Dim>(1, 1, 1)));
assert((0 || Q) == (makeValue<T, Dim>(1, 1, 1)));
assert((9 < P) == (makeValue<T, Dim>(0, 0, 1)));
assert((9 > P) == (makeValue<T, Dim>(1, 0, 0)));
assert((9 <= P) == (makeValue<T, Dim>(0, 1, 1)));
assert((9 >= P) == (makeValue<T, Dim>(1, 1, 0)));
// Compound assignment: object op= object.
T<Dim> E = makeValue<T, Dim>(8, 9, 10);
E += Q;
assert(E == (makeValue<T, Dim>(10, 12, 15)));
E -= Q;
assert(E == (makeValue<T, Dim>(8, 9, 10)));
E *= Q;
assert(E == (makeValue<T, Dim>(16, 27, 50)));
E /= Q;
assert(E == (makeValue<T, Dim>(8, 9, 10)));
E %= Q;
assert(E == (makeValue<T, Dim>(0, 0, 0)));
// Compound assignment: object op= scalar.
T<Dim> F = makeValue<T, Dim>(8, 9, 10);
F += 2;
assert(F == (makeValue<T, Dim>(10, 11, 12)));
F -= 2;
assert(F == (makeValue<T, Dim>(8, 9, 10)));
F *= 2;
assert(F == (makeValue<T, Dim>(16, 18, 20)));
F /= 2;
assert(F == (makeValue<T, Dim>(8, 9, 10)));
F %= 6;
assert(F == (makeValue<T, Dim>(2, 3, 4)));
F <<= 1;
assert(F == (makeValue<T, Dim>(4, 6, 8)));
F >>= 1;
assert(F == (makeValue<T, Dim>(2, 3, 4)));
F &= 6;
assert(F == (makeValue<T, Dim>(2, 2, 4)));
F |= 1;
assert(F == (makeValue<T, Dim>(3, 3, 5)));
F ^= 2;
assert(F == (makeValue<T, Dim>(1, 1, 7)));
}
template <template <int> class T> void testCommon() {
// Default construction zero-initialises every dimension.
T<1> Def1;
T<2> Def2;
T<3> Def3;
assert(Def1[0] == 0);
assert(Def2[0] == 0 && Def2[1] == 0);
assert(Def3[0] == 0 && Def3[1] == 0 && Def3[2] == 0);
// Dimensional constructors and element access via get() and const [].
T<1> A1(5);
T<2> A2(3, 7);
T<3> A3(8, 9, 10);
assert(A1.get(0) == 5 && A1[0] == 5);
assert(A2.get(0) == 3 && A2.get(1) == 7);
assert(A3.get(0) == 8 && A3.get(1) == 9 && A3.get(2) == 10);
// dimensions static constexpr.
static_assert(T<1>::dimensions == 1);
static_assert(T<2>::dimensions == 2);
static_assert(T<3>::dimensions == 3);
// Non-const operator[] write.
T<2> Mutable(1, 2);
Mutable[0] = 10;
Mutable[1] = 20;
assert(Mutable[0] == 10 && Mutable[1] == 20);
// Copy constructor and copy assignment.
T<3> CopyCtor(A3);
assert(CopyCtor == A3);
T<3> CopyAssign(1, 1, 1);
CopyAssign = A3;
assert(CopyAssign == A3);
// Move constructor and move assignment.
T<3> MoveSrc1(A3);
T<3> MoveCtor(std::move(MoveSrc1));
assert(MoveCtor == A3);
T<3> MoveSrc2(A3);
T<3> MoveAssign(1, 1, 1);
MoveAssign = std::move(MoveSrc2);
assert(MoveAssign == A3);
// Equality and inequality between same-type objects.
assert((makeValue<T, 3>(8, 9, 10)) == (makeValue<T, 3>(8, 9, 10)));
assert((makeValue<T, 3>(8, 9, 10)) != (makeValue<T, 3>(8, 9, 11)));
// Test binary and compound operators for all dimensions.
testBinaryOpsForDim<T, 1>();
testBinaryOpsForDim<T, 2>();
testBinaryOpsForDim<T, 3>();
// Unary + and -.
T<3> U(8, 9, 10);
assert((+U) == (makeValue<T, 3>(8, 9, 10)));
assert((-U) == (makeValue<T, 3>(static_cast<std::size_t>(-8),
static_cast<std::size_t>(-9),
static_cast<std::size_t>(-10))));
// Pre- and post-increment / decrement.
T<3> Inc(8, 9, 10);
assert((++Inc) == (makeValue<T, 3>(9, 10, 11)));
assert((Inc++) == (makeValue<T, 3>(9, 10, 11)));
assert(Inc == (makeValue<T, 3>(10, 11, 12)));
assert((--Inc) == (makeValue<T, 3>(9, 10, 11)));
assert((Inc--) == (makeValue<T, 3>(9, 10, 11)));
assert(Inc == (makeValue<T, 3>(8, 9, 10)));
}
void testRange() {
testCommon<sycl::range>();
assert(sycl::range<1>(7).size() == 7);
assert(sycl::range<2>(4, 5).size() == 20);
assert(sycl::range<3>(2, 3, 4).size() == 24);
assert(sycl::range<3>(0, 5, 3).size() == 0);
#ifdef __cpp_deduction_guides
auto R1 = sycl::range(7);
auto R2 = sycl::range(4, 5);
auto R3 = sycl::range(2, 3, 4);
static_assert(std::is_same_v<decltype(R1), sycl::range<1>>);
static_assert(std::is_same_v<decltype(R2), sycl::range<2>>);
static_assert(std::is_same_v<decltype(R3), sycl::range<3>>);
assert(R1 == sycl::range<1>(7));
assert(R2 == sycl::range<2>(4, 5));
assert(R3 == sycl::range<3>(2, 3, 4));
#endif
}
void testId() {
testCommon<sycl::id>();
// Construction from range.
assert(sycl::id<1>(sycl::range<1>(2)) == sycl::id<1>(2));
assert(sycl::id<2>(sycl::range<2>(4, 8)) == sycl::id<2>(4, 8));
assert(sycl::id<3>(sycl::range<3>(16, 32, 64)) == sycl::id<3>(16, 32, 64));
// Construction from item (WithOffset=true) preserves the computed id
// coordinates.
sycl::item<1, true> Item1 = Builder::createItem<1, true>({4}, {2}, {1});
sycl::item<2, true> Item2 =
Builder::createItem<2, true>({8, 16}, {4, 8}, {1, 1});
sycl::item<3, true> Item3 =
Builder::createItem<3, true>({32, 64, 128}, {16, 32, 64}, {1, 1, 1});
assert(sycl::id<1>(Item1) == sycl::id<1>(2));
assert(sycl::id<2>(Item2) == sycl::id<2>(4, 8));
assert(sycl::id<3>(Item3) == sycl::id<3>(16, 32, 64));
// Construction from item (WithOffset=false).
sycl::item<1, false> Item1NoOffset = Builder::createItem<1, false>({4}, {2});
sycl::item<2, false> Item2NoOffset =
Builder::createItem<2, false>({8, 16}, {4, 8});
sycl::item<3, false> Item3NoOffset =
Builder::createItem<3, false>({32, 64, 128}, {16, 32, 64});
assert(sycl::id<1>(Item1NoOffset) == sycl::id<1>(2));
assert(sycl::id<2>(Item2NoOffset) == sycl::id<2>(4, 8));
assert(sycl::id<3>(Item3NoOffset) == sycl::id<3>(16, 32, 64));
// Copy-initialization from item must also select id(item) constructor.
sycl::id<1> IdFromItem1NoOffset = Item1NoOffset;
sycl::id<2> IdFromItem2NoOffset = Item2NoOffset;
sycl::id<3> IdFromItem3NoOffset = Item3NoOffset;
assert(IdFromItem1NoOffset == sycl::id<1>(2));
assert(IdFromItem2NoOffset == sycl::id<2>(4, 8));
assert(IdFromItem3NoOffset == sycl::id<3>(16, 32, 64));
#ifdef __cpp_deduction_guides
auto I1 = sycl::id(2);
auto I2 = sycl::id(4, 8);
auto I3 = sycl::id(16, 32, 64);
static_assert(std::is_same_v<decltype(I1), sycl::id<1>>);
static_assert(std::is_same_v<decltype(I2), sycl::id<2>>);
static_assert(std::is_same_v<decltype(I3), sycl::id<3>>);
assert(I1 == sycl::id<1>(2));
assert(I2 == sycl::id<2>(4, 8));
assert(I3 == sycl::id<3>(16, 32, 64));
#endif
// Implicit conversion to size_t (id<1> only).
sycl::id<1> OneDim(16);
std::size_t S = OneDim;
int I = OneDim;
assert(S == 16 && I == 16);
// Scalar equality/inequality operators (id<1> only).
const sycl::id<1> ConstId(10);
assert(ConstId == 10);
assert(10 == ConstId);
assert(ConstId != 19);
assert(19 != ConstId);
assert(ConstId == 10u);
assert(10u == ConstId);
assert(ConstId != static_cast<short>(9));
assert(static_cast<short>(9) != ConstId);
}
int main() {
testRange();
testId();
return 0;
}