|
| 1 | +// Basic acceptance test which checks vec::convert implementation on both |
| 2 | +// host and device. Coverage is limited to vec<T, 4> only, rest of vector sizes |
| 3 | +// are covered by SYCL-CTS. |
| 4 | +// |
| 5 | +// Macro is passed to silence warnings about sycl::byte |
| 6 | +// |
| 7 | +// XFAIL: cuda |
| 8 | +// FIXME: un-xfail the test once intel/llvm#11840 is resolved |
| 9 | +// |
| 10 | +// RUN: %{build} -o %t.out -DSYCL2020_DISABLE_DEPRECATION_WARNINGS |
| 11 | +// RUN: %{run} %t.out |
| 12 | +// |
| 13 | +// RUN: %if preview-breaking-changes-supported %{ %{build} -fpreview-breaking-changes -DSYCL2020_DISABLE_DEPRECATION_WARNINGS %s -o %t2.out %} |
| 14 | +// RUN: %if preview-breaking-changes-supported %{ %{run} %t2.out %} |
| 15 | + |
| 16 | +#include <sycl/sycl.hpp> |
| 17 | + |
| 18 | +#include <cstdint> |
| 19 | +#include <iostream> |
| 20 | +#include <string> |
| 21 | +#include <type_traits> |
| 22 | + |
| 23 | +template <typename T> std::string to_string() { return "unknown type"; } |
| 24 | +template <> std::string to_string<std::byte>() { return "std::byte"; } |
| 25 | +template <> std::string to_string<char>() { return "char"; } |
| 26 | +template <> std::string to_string<signed char>() { return "signed char"; } |
| 27 | +template <> std::string to_string<short>() { return "short"; } |
| 28 | +template <> std::string to_string<int>() { return "int"; } |
| 29 | +template <> std::string to_string<long>() { return "long"; } |
| 30 | +template <> std::string to_string<long long>() { return "long long"; } |
| 31 | +template <> std::string to_string<unsigned char>() { return "unsigned char"; } |
| 32 | +template <> std::string to_string<unsigned short>() { return "unsigned short"; } |
| 33 | +template <> std::string to_string<unsigned int>() { return "unsigned int"; } |
| 34 | +template <> std::string to_string<unsigned long>() { return "unsigned long"; } |
| 35 | +template <> std::string to_string<unsigned long long>() { |
| 36 | + return "unsigned long long"; |
| 37 | +} |
| 38 | +template <> std::string to_string<bool>() { return "bool"; } |
| 39 | + |
| 40 | +template <typename T> |
| 41 | +bool check_vectors_equal(sycl::vec<T, 4> a, sycl::vec<T, 4> b, |
| 42 | + const std::string &fail_message) { |
| 43 | + bool result = |
| 44 | + a.x() == b.x() && a.y() == b.y() && a.z() == b.z() && a.w() == b.w(); |
| 45 | + if (!result) { |
| 46 | + std::cout << fail_message << std::endl; |
| 47 | + std::cout << "\t{" << static_cast<int>(a.x()) << ", " |
| 48 | + << static_cast<int>(a.y()) << ", " << static_cast<int>(a.z()) |
| 49 | + << ", " << static_cast<int>(a.w()) << "} vs {" |
| 50 | + << static_cast<int>(b.x()) << ", " << static_cast<int>(b.y()) |
| 51 | + << ", " << static_cast<int>(b.z()) << ", " |
| 52 | + << static_cast<int>(b.w()) << "}" << std::endl; |
| 53 | + } |
| 54 | + |
| 55 | + return result; |
| 56 | +} |
| 57 | + |
| 58 | +template <typename From, typename To> bool check_convert() { |
| 59 | + sycl::vec<From, 4> input; |
| 60 | + if constexpr (std::is_signed_v<From>) { |
| 61 | + input = sycl::vec<From, 4>{static_cast<From>(37), static_cast<From>(0), |
| 62 | + static_cast<From>(-11), static_cast<From>(13)}; |
| 63 | + } else { |
| 64 | + input = sycl::vec<From, 4>{static_cast<From>(37), static_cast<From>(0), |
| 65 | + static_cast<From>(11), static_cast<From>(13)}; |
| 66 | + } |
| 67 | + |
| 68 | + sycl::vec<To, 4> hostResult = input.template convert<To>(); |
| 69 | + |
| 70 | + sycl::buffer<sycl::vec<To, 4>> buf(sycl::range{1}); |
| 71 | + sycl::queue q; |
| 72 | + q.submit([&](sycl::handler &cgh) { |
| 73 | + sycl::accessor acc(buf, cgh); |
| 74 | + cgh.single_task([=]() { acc[0] = input.template convert<To>(); }); |
| 75 | + }).wait(); |
| 76 | + |
| 77 | + auto acc = buf.get_host_access(); |
| 78 | + auto deviceResult = acc[0]; |
| 79 | + |
| 80 | + std::string test = |
| 81 | + "(vec<" + to_string<From>() + ", 4>::convert<" + to_string<To>() + ">)"; |
| 82 | + |
| 83 | + // Host and device results must match. |
| 84 | + bool host_and_device_match = check_vectors_equal( |
| 85 | + hostResult, deviceResult, "host and device results do not match " + test); |
| 86 | + // And they should match with a reference, which is for integer conversions |
| 87 | + // can be computed with a simple static_cast. |
| 88 | + // Strictly speaking, integer conversions are underspecified in the SYCL 2020 |
| 89 | + // spec, but `static_cast` implementation matches SYCL-CTS, so we will leave |
| 90 | + // it here for now as well. |
| 91 | + // See https://github.com/KhronosGroup/SYCL-Docs/issues/492 |
| 92 | + sycl::vec<To, 4> reference{ |
| 93 | + static_cast<To>(input.x()), static_cast<To>(input.y()), |
| 94 | + static_cast<To>(input.z()), static_cast<To>(input.w())}; |
| 95 | + bool device_matches_reference = check_vectors_equal( |
| 96 | + deviceResult, reference, "device results don't match reference " + test); |
| 97 | + bool host_matches_reference = check_vectors_equal( |
| 98 | + hostResult, reference, "host resutls don't match reference " + test); |
| 99 | + |
| 100 | + return host_and_device_match && device_matches_reference && |
| 101 | + host_matches_reference; |
| 102 | +} |
| 103 | + |
| 104 | +template <class T> |
| 105 | +constexpr auto has_unsigned_v = |
| 106 | + std::is_integral_v<T> && !std::is_same_v<T, bool> && |
| 107 | + !std::is_same_v<T, sycl::byte> && !std::is_same_v<T, std::byte>; |
| 108 | + |
| 109 | +template <typename From, typename To> bool check_signed_unsigned_convert_to() { |
| 110 | + bool pass = true; |
| 111 | + pass &= check_convert<From, To>(); |
| 112 | + if constexpr (has_unsigned_v<To>) |
| 113 | + pass &= check_convert<From, std::make_unsigned_t<To>>(); |
| 114 | + if constexpr (has_unsigned_v<From>) |
| 115 | + pass &= check_convert<std::make_unsigned_t<From>, To>(); |
| 116 | + if constexpr (has_unsigned_v<To> && has_unsigned_v<From>) |
| 117 | + pass &= |
| 118 | + check_convert<std::make_unsigned_t<From>, std::make_unsigned_t<To>>(); |
| 119 | + return pass; |
| 120 | +} |
| 121 | + |
| 122 | +template <typename From> bool check_convert_from() { |
| 123 | + bool pass = true; |
| 124 | + pass &= check_signed_unsigned_convert_to<From, sycl::byte>(); |
| 125 | + pass &= check_signed_unsigned_convert_to<From, std::byte>(); |
| 126 | + pass &= check_signed_unsigned_convert_to<From, std::int8_t>(); |
| 127 | + pass &= check_signed_unsigned_convert_to<From, std::int16_t>(); |
| 128 | + pass &= check_signed_unsigned_convert_to<From, std::int32_t>(); |
| 129 | + pass &= check_signed_unsigned_convert_to<From, std::int64_t>(); |
| 130 | + pass &= check_signed_unsigned_convert_to<From, bool>(); |
| 131 | + pass &= check_signed_unsigned_convert_to<From, char>(); |
| 132 | + pass &= check_signed_unsigned_convert_to<From, signed char>(); |
| 133 | + pass &= check_signed_unsigned_convert_to<From, short>(); |
| 134 | + pass &= check_signed_unsigned_convert_to<From, int>(); |
| 135 | + pass &= check_signed_unsigned_convert_to<From, long>(); |
| 136 | + pass &= check_signed_unsigned_convert_to<From, long long>(); |
| 137 | + |
| 138 | + return pass; |
| 139 | +} |
| 140 | + |
| 141 | +int main() { |
| 142 | + bool pass = true; |
| 143 | + pass &= check_convert_from<sycl::byte>(); |
| 144 | + pass &= check_convert_from<std::byte>(); |
| 145 | + pass &= check_convert_from<std::int8_t>(); |
| 146 | + pass &= check_convert_from<std::int16_t>(); |
| 147 | + pass &= check_convert_from<std::int32_t>(); |
| 148 | + pass &= check_convert_from<std::int64_t>(); |
| 149 | + pass &= check_convert_from<char>(); |
| 150 | + pass &= check_convert_from<signed char>(); |
| 151 | + pass &= check_convert_from<short>(); |
| 152 | + pass &= check_convert_from<int>(); |
| 153 | + pass &= check_convert_from<long>(); |
| 154 | + pass &= check_convert_from<long long>(); |
| 155 | + pass &= check_convert_from<bool>(); |
| 156 | + |
| 157 | + return static_cast<int>(!pass); |
| 158 | +} |
0 commit comments