| 
 | 1 | +// RUN: %{build} -Wno-error=psabi -o %t.out  | 
 | 2 | +// RUN: %{run} %t.out  | 
 | 3 | + | 
 | 4 | +#include <sycl/detail/core.hpp>  | 
 | 5 | + | 
 | 6 | +// Define vector types for different integer bit widths. We need these to  | 
 | 7 | +// trigger llvm.scmp/ucmp for vector types. std::array or sycl::vec don't  | 
 | 8 | +// trigger these, as they are not lowered to vector types.  | 
 | 9 | +typedef int8_t v4i8_t __attribute__((ext_vector_type(4)));  | 
 | 10 | +typedef int16_t v4i16_t __attribute__((ext_vector_type(4)));  | 
 | 11 | +typedef int32_t v4i32_t __attribute__((ext_vector_type(4)));  | 
 | 12 | +typedef int64_t v4i64_t __attribute__((ext_vector_type(4)));  | 
 | 13 | +typedef uint8_t v4u8_t __attribute__((ext_vector_type(4)));  | 
 | 14 | +typedef uint16_t v4u16_t __attribute__((ext_vector_type(4)));  | 
 | 15 | +typedef uint32_t v4u32_t __attribute__((ext_vector_type(4)));  | 
 | 16 | +typedef uint64_t v4u64_t __attribute__((ext_vector_type(4)));  | 
 | 17 | + | 
 | 18 | +// Check if a given type is a vector type or not. Used in submitAndCheck to  | 
 | 19 | +// branch the check: we need element-wise comparison for vector types. Default  | 
 | 20 | +// case: T is not a vector type.  | 
 | 21 | +template <typename T> struct is_vector : std::false_type {};  | 
 | 22 | +// Specialization for vector types. If T has  | 
 | 23 | +// __attribute__((ext_vector_type(N))), then it's a vector type.  | 
 | 24 | +template <typename T, std::size_t N>  | 
 | 25 | +struct is_vector<T __attribute__((ext_vector_type(N)))> : std::true_type {};  | 
 | 26 | +template <typename T> inline constexpr bool is_vector_v = is_vector<T>::value;  | 
 | 27 | + | 
 | 28 | +// Get the length of a vector type. Used in submitAndCheck to iterate over the  | 
 | 29 | +// elements of the vector type. Default case: length is 1.  | 
 | 30 | +template <typename T> struct vector_length {  | 
 | 31 | +  static constexpr std::size_t value = 1;  | 
 | 32 | +};  | 
 | 33 | +// Specialization for vector types. If T has  | 
 | 34 | +// __attribute__((ext_vector_type(N))), then the length is N.  | 
 | 35 | +template <typename T, std::size_t N>  | 
 | 36 | +struct vector_length<T __attribute__((ext_vector_type(N)))> {  | 
 | 37 | +  static constexpr std::size_t value = N;  | 
 | 38 | +};  | 
 | 39 | +template <typename T>  | 
 | 40 | +inline constexpr std::size_t vector_length_v = vector_length<T>::value;  | 
 | 41 | + | 
 | 42 | +// Get the element type of a vector type. Used in submitVecCombinations to  | 
 | 43 | +// convert unsigned vector types to signed vector types for return type. Primary  | 
 | 44 | +// template for element_type.  | 
 | 45 | +template <typename T> struct element_type;  | 
 | 46 | +// Specialization for vector types. If T has  | 
 | 47 | +// __attribute__((ext_vector_type(N))), return T.  | 
 | 48 | +template <typename T, int N>  | 
 | 49 | +struct element_type<T __attribute__((ext_vector_type(N)))> {  | 
 | 50 | +  using type = T;  | 
 | 51 | +};  | 
 | 52 | +// Helper alias template.  | 
 | 53 | +template <typename T> using element_type_t = typename element_type<T>::type;  | 
 | 54 | + | 
 | 55 | +// TypeList for packing the types that we want to test.  | 
 | 56 | +// Base case for variadic template recursion.  | 
 | 57 | +template <typename...> struct TypeList {};  | 
 | 58 | + | 
 | 59 | +// Function to trigger llvm.scmp/ucmp.  | 
 | 60 | +template <typename RetTy, typename ArgTy>  | 
 | 61 | +void compare(RetTy &res, ArgTy x, ArgTy y) {  | 
 | 62 | +  auto lessOrEq = (x <= y);  | 
 | 63 | +  auto lessThan = (x < y);  | 
 | 64 | +  res = lessOrEq ? (lessThan ? RetTy(-1) : RetTy(0)) : RetTy(1);  | 
 | 65 | +}  | 
 | 66 | + | 
 | 67 | +// Function to submit kernel and check device result with host result.  | 
 | 68 | +template <typename RetTy, typename ArgTy>  | 
 | 69 | +void submitAndCheck(sycl::queue &q, ArgTy x, ArgTy y) {  | 
 | 70 | +  RetTy res;  | 
 | 71 | +  {  | 
 | 72 | +    sycl::buffer<RetTy, 1> res_b{&res, 1};  | 
 | 73 | +    q.submit([&](sycl::handler &cgh) {  | 
 | 74 | +      sycl::accessor acc{res_b, cgh, sycl::write_only};  | 
 | 75 | +      cgh.single_task<>([=] {  | 
 | 76 | +        RetTy tmp;  | 
 | 77 | +        compare<RetTy, ArgTy>(tmp, x, y);  | 
 | 78 | +        acc[0] = tmp;  | 
 | 79 | +      });  | 
 | 80 | +    });  | 
 | 81 | +  }  | 
 | 82 | +  RetTy expectedRes;  | 
 | 83 | +  compare<RetTy, ArgTy>(expectedRes, x, y);  | 
 | 84 | +  if constexpr (is_vector_v<RetTy>) {  | 
 | 85 | +    for (int i = 0; i < vector_length_v<RetTy>; ++i) {  | 
 | 86 | +      assert(res[i] == expectedRes[i]);  | 
 | 87 | +    }  | 
 | 88 | +  } else {  | 
 | 89 | +    assert(res == expectedRes);  | 
 | 90 | +  }  | 
 | 91 | +}  | 
 | 92 | + | 
 | 93 | +// Helper to call submitAndCheck for each combination.  | 
 | 94 | +template <typename RetTypes, typename ArgTypes>  | 
 | 95 | +void submitAndCheckCombination(sycl::queue &q, int x, int y) {  | 
 | 96 | +  submitAndCheck<RetTypes, ArgTypes>(q, x, y);  | 
 | 97 | +}  | 
 | 98 | + | 
 | 99 | +// Function to generate all the combinations possible with the two type lists.  | 
 | 100 | +// It implements the following pseudocode :  | 
 | 101 | +// foreach RetTy : RetTypes  | 
 | 102 | +//   foreach ArgTy : ArgTypes  | 
 | 103 | +//     submitAndCheck<RetTy, ArgTy>(q, x, y);  | 
 | 104 | + | 
 | 105 | +// Recursive case to generate combinations.  | 
 | 106 | +template <typename RetType, typename... RetTypes, typename... ArgTypes>  | 
 | 107 | +void submitCombinations(sycl::queue &q, int x, int y,  | 
 | 108 | +                        TypeList<RetType, RetTypes...>, TypeList<ArgTypes...>) {  | 
 | 109 | +  (submitAndCheckCombination<RetType, ArgTypes>(q, x, y), ...);  | 
 | 110 | +  submitCombinations(q, x, y, TypeList<RetTypes...>{}, TypeList<ArgTypes...>{});  | 
 | 111 | +}  | 
 | 112 | +// Base case to stop recursion.  | 
 | 113 | +template <typename... ArgTypes>  | 
 | 114 | +void submitCombinations(sycl::queue &, int, int, TypeList<>,  | 
 | 115 | +                        TypeList<ArgTypes...>) {}  | 
 | 116 | + | 
 | 117 | +// Function to generate all the combinations out of the given list.  | 
 | 118 | +// It implements the following pseudocode :  | 
 | 119 | +// foreach ArgTy : ArgTypes  | 
 | 120 | +//   submitAndCheck<ArgTy, ArgTy>(q, x, y);  | 
 | 121 | + | 
 | 122 | +// Recursive case to generate combinations.  | 
 | 123 | +template <typename ArgType, typename... ArgTypes>  | 
 | 124 | +void submitVecCombinations(sycl::queue &q, int x, int y,  | 
 | 125 | +                           TypeList<ArgType, ArgTypes...>) {  | 
 | 126 | +  // Use signed types for return type, as it may return -1.  | 
 | 127 | +  using ElemType = std::make_signed_t<element_type_t<ArgType>>;  | 
 | 128 | +  using RetType =  | 
 | 129 | +      ElemType __attribute__((ext_vector_type(vector_length_v<ArgType>)));  | 
 | 130 | +  submitAndCheckCombination<RetType, ArgType>(q, x, y);  | 
 | 131 | +  submitVecCombinations(q, x, y, TypeList<ArgTypes...>{});  | 
 | 132 | +}  | 
 | 133 | +// Base case to stop recursion.  | 
 | 134 | +void submitVecCombinations(sycl::queue &, int, int, TypeList<>) {}  | 
 | 135 | + | 
 | 136 | +int main(int argc, char **argv) {  | 
 | 137 | +  sycl::queue q;  | 
 | 138 | +  // RetTypes includes only signed types because it may return -1.  | 
 | 139 | +  using RetTypes = TypeList<int8_t, int16_t, int32_t, int64_t>;  | 
 | 140 | +  using ArgTypes = TypeList<int8_t, int16_t, int32_t, int64_t, uint8_t,  | 
 | 141 | +                            uint16_t, uint32_t, uint64_t>;  | 
 | 142 | +  submitCombinations(q, 50, 49, RetTypes{}, ArgTypes{});  | 
 | 143 | +  submitCombinations(q, 50, 50, RetTypes{}, ArgTypes{});  | 
 | 144 | +  submitCombinations(q, 50, 51, RetTypes{}, ArgTypes{});  | 
 | 145 | +  using VecTypes = TypeList<v4i8_t, v4i16_t, v4i32_t, v4i64_t, v4u8_t, v4u16_t,  | 
 | 146 | +                            v4u32_t, v4u64_t>;  | 
 | 147 | +  submitVecCombinations(q, 50, 49, VecTypes{});  | 
 | 148 | +  submitVecCombinations(q, 50, 50, VecTypes{});  | 
 | 149 | +  submitVecCombinations(q, 50, 51, VecTypes{});  | 
 | 150 | +  return 0;  | 
 | 151 | +}  | 
0 commit comments