diff --git a/sycl/test-e2e/LLVMIntrinsicLowering/intrinsic_cmp.cpp b/sycl/test-e2e/LLVMIntrinsicLowering/intrinsic_cmp.cpp new file mode 100644 index 0000000000000..3c19bbedd99cd --- /dev/null +++ b/sycl/test-e2e/LLVMIntrinsicLowering/intrinsic_cmp.cpp @@ -0,0 +1,151 @@ +// RUN: %{build} -Wno-error=psabi -o %t.out +// RUN: %{run} %t.out + +#include + +// Define vector types for different integer bit widths. We need these to +// trigger llvm.scmp/ucmp for vector types. std::array or sycl::vec don't +// trigger these, as they are not lowered to vector types. +typedef int8_t v4i8_t __attribute__((ext_vector_type(4))); +typedef int16_t v4i16_t __attribute__((ext_vector_type(4))); +typedef int32_t v4i32_t __attribute__((ext_vector_type(4))); +typedef int64_t v4i64_t __attribute__((ext_vector_type(4))); +typedef uint8_t v4u8_t __attribute__((ext_vector_type(4))); +typedef uint16_t v4u16_t __attribute__((ext_vector_type(4))); +typedef uint32_t v4u32_t __attribute__((ext_vector_type(4))); +typedef uint64_t v4u64_t __attribute__((ext_vector_type(4))); + +// Check if a given type is a vector type or not. Used in submitAndCheck to +// branch the check: we need element-wise comparison for vector types. Default +// case: T is not a vector type. +template struct is_vector : std::false_type {}; +// Specialization for vector types. If T has +// __attribute__((ext_vector_type(N))), then it's a vector type. +template +struct is_vector : std::true_type {}; +template inline constexpr bool is_vector_v = is_vector::value; + +// Get the length of a vector type. Used in submitAndCheck to iterate over the +// elements of the vector type. Default case: length is 1. +template struct vector_length { + static constexpr std::size_t value = 1; +}; +// Specialization for vector types. If T has +// __attribute__((ext_vector_type(N))), then the length is N. +template +struct vector_length { + static constexpr std::size_t value = N; +}; +template +inline constexpr std::size_t vector_length_v = vector_length::value; + +// Get the element type of a vector type. Used in submitVecCombinations to +// convert unsigned vector types to signed vector types for return type. Primary +// template for element_type. +template struct element_type; +// Specialization for vector types. If T has +// __attribute__((ext_vector_type(N))), return T. +template +struct element_type { + using type = T; +}; +// Helper alias template. +template using element_type_t = typename element_type::type; + +// TypeList for packing the types that we want to test. +// Base case for variadic template recursion. +template struct TypeList {}; + +// Function to trigger llvm.scmp/ucmp. +template +void compare(RetTy &res, ArgTy x, ArgTy y) { + auto lessOrEq = (x <= y); + auto lessThan = (x < y); + res = lessOrEq ? (lessThan ? RetTy(-1) : RetTy(0)) : RetTy(1); +} + +// Function to submit kernel and check device result with host result. +template +void submitAndCheck(sycl::queue &q, ArgTy x, ArgTy y) { + RetTy res; + { + sycl::buffer res_b{&res, 1}; + q.submit([&](sycl::handler &cgh) { + sycl::accessor acc{res_b, cgh, sycl::write_only}; + cgh.single_task<>([=] { + RetTy tmp; + compare(tmp, x, y); + acc[0] = tmp; + }); + }); + } + RetTy expectedRes; + compare(expectedRes, x, y); + if constexpr (is_vector_v) { + for (int i = 0; i < vector_length_v; ++i) { + assert(res[i] == expectedRes[i]); + } + } else { + assert(res == expectedRes); + } +} + +// Helper to call submitAndCheck for each combination. +template +void submitAndCheckCombination(sycl::queue &q, int x, int y) { + submitAndCheck(q, x, y); +} + +// Function to generate all the combinations possible with the two type lists. +// It implements the following pseudocode : +// foreach RetTy : RetTypes +// foreach ArgTy : ArgTypes +// submitAndCheck(q, x, y); + +// Recursive case to generate combinations. +template +void submitCombinations(sycl::queue &q, int x, int y, + TypeList, TypeList) { + (submitAndCheckCombination(q, x, y), ...); + submitCombinations(q, x, y, TypeList{}, TypeList{}); +} +// Base case to stop recursion. +template +void submitCombinations(sycl::queue &, int, int, TypeList<>, + TypeList) {} + +// Function to generate all the combinations out of the given list. +// It implements the following pseudocode : +// foreach ArgTy : ArgTypes +// submitAndCheck(q, x, y); + +// Recursive case to generate combinations. +template +void submitVecCombinations(sycl::queue &q, int x, int y, + TypeList) { + // Use signed types for return type, as it may return -1. + using ElemType = std::make_signed_t>; + using RetType = + ElemType __attribute__((ext_vector_type(vector_length_v))); + submitAndCheckCombination(q, x, y); + submitVecCombinations(q, x, y, TypeList{}); +} +// Base case to stop recursion. +void submitVecCombinations(sycl::queue &, int, int, TypeList<>) {} + +int main(int argc, char **argv) { + sycl::queue q; + // RetTypes includes only signed types because it may return -1. + using RetTypes = TypeList; + using ArgTypes = TypeList; + submitCombinations(q, 50, 49, RetTypes{}, ArgTypes{}); + submitCombinations(q, 50, 50, RetTypes{}, ArgTypes{}); + submitCombinations(q, 50, 51, RetTypes{}, ArgTypes{}); + using VecTypes = TypeList; + submitVecCombinations(q, 50, 49, VecTypes{}); + submitVecCombinations(q, 50, 50, VecTypes{}); + submitVecCombinations(q, 50, 51, VecTypes{}); + return 0; +}