|
| 1 | +//==--- builtins_utils_scalar.hpp - SYCL built-in function utilities -------==// |
| 2 | +// |
| 3 | +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
| 4 | +// See https://llvm.org/LICENSE.txt for license information. |
| 5 | +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
| 6 | +// |
| 7 | +//===----------------------------------------------------------------------===// |
| 8 | + |
| 9 | +#pragma once |
| 10 | + |
| 11 | +#include <sycl/access/access.hpp> // for address_space, decorated |
| 12 | +#include <sycl/aliases.hpp> // for half |
| 13 | +#include <sycl/detail/boolean.hpp> // for Boolean |
| 14 | +#include <sycl/detail/builtins.hpp> // for __invoke_select, __in... |
| 15 | +#include <sycl/detail/defines_elementary.hpp> // for __SYCL_ALWAYS_INLINE |
| 16 | +#include <sycl/detail/generic_type_traits.hpp> // for is_svgenfloat, is_sge... |
| 17 | +#include <sycl/detail/type_list.hpp> // for is_contained, type_list |
| 18 | +#include <sycl/detail/type_traits.hpp> // for make_larger_t, marray... |
| 19 | +#include <sycl/half_type.hpp> // for half, intel |
| 20 | +#include <sycl/multi_ptr.hpp> // for address_space_cast |
| 21 | + |
| 22 | +#include <algorithm> |
| 23 | +#include <cstring> |
| 24 | + |
| 25 | +namespace sycl { |
| 26 | +inline namespace _V1 { |
| 27 | + |
| 28 | +#ifdef __SYCL_DEVICE_ONLY__ |
| 29 | +#define __sycl_std |
| 30 | +#else |
| 31 | +namespace __sycl_std = __host_std; |
| 32 | +#endif |
| 33 | + |
| 34 | +namespace detail { |
| 35 | +// Get the element type of T. If T is a scalar, the element type is considered |
| 36 | +// the type of the scalar. |
| 37 | +template <typename T> struct get_elem_type { |
| 38 | + using type = T; |
| 39 | +}; |
| 40 | + |
| 41 | +template <typename T> using get_elem_type_t = typename get_elem_type<T>::type; |
| 42 | +#ifdef __FAST_MATH__ |
| 43 | +template <typename T> |
| 44 | +struct use_fast_math |
| 45 | + : std::is_same<std::remove_cv_t<get_elem_type_t<T>>, float> {}; |
| 46 | +#else |
| 47 | +template <typename> struct use_fast_math : std::false_type {}; |
| 48 | +#endif |
| 49 | +template <typename T> constexpr bool use_fast_math_v = use_fast_math<T>::value; |
| 50 | + |
| 51 | +// sycl::select(sgentype a, sgentype b, bool c) calls OpenCL built-in |
| 52 | +// select(sgentype a, sgentype b, igentype c). This type trait makes the |
| 53 | +// proper conversion for argument c from bool to igentype, based on sgentype |
| 54 | +// == T. |
| 55 | +// TODO: Consider unifying this with select_cl_scalar_integral_signed_t. |
| 56 | +template <typename T> |
| 57 | +using get_select_opencl_builtin_c_arg_type = typename std::conditional_t< |
| 58 | + sizeof(T) == 1, char, |
| 59 | + std::conditional_t< |
| 60 | + sizeof(T) == 2, short, |
| 61 | + std::conditional_t< |
| 62 | + (detail::is_contained< |
| 63 | + T, detail::type_list<long, unsigned long>>::value && |
| 64 | + (sizeof(T) == 4 || sizeof(T) == 8)), |
| 65 | + long, // long and ulong are 32-bit on |
| 66 | + // Windows and 64-bit on Linux |
| 67 | + std::conditional_t< |
| 68 | + sizeof(T) == 4, int, |
| 69 | + std::conditional_t<sizeof(T) == 8, long long, void>>>>>; |
| 70 | + |
| 71 | +// Common utility for selecting a type based on the specified size. |
| 72 | +template <size_t Size, typename T8, typename T16, typename T32, typename T64> |
| 73 | +using select_scalar_by_size_t = std::conditional_t< |
| 74 | + Size == 1, T8, |
| 75 | + std::conditional_t< |
| 76 | + Size == 2, T16, |
| 77 | + std::conditional_t<Size == 4, T32, |
| 78 | + std::conditional_t<Size == 8, T64, void>>>>; |
| 79 | + |
| 80 | +template <typename T, typename... Ts> constexpr bool CheckTypeIn() { |
| 81 | + constexpr bool SameType[] = { |
| 82 | + std::is_same_v<std::remove_cv_t<T>, std::remove_cv_t<Ts>>...}; |
| 83 | + // Replace with std::any_of with C++20. |
| 84 | + for (size_t I = 0; I < sizeof...(Ts); ++I) |
| 85 | + if (SameType[I]) |
| 86 | + return true; |
| 87 | + return false; |
| 88 | +} |
| 89 | + |
| 90 | +// NOTE: We need a constexpr variable definition for the constexpr functions |
| 91 | +// as MSVC thinks function definitions are the same otherwise. |
| 92 | +template <typename... Ts> constexpr bool check_type_in_v = CheckTypeIn<Ts...>(); |
| 93 | + |
| 94 | +template <size_t N, size_t... Ns> constexpr bool CheckSizeIn() { |
| 95 | + constexpr bool SameSize[] = {(N == Ns)...}; |
| 96 | + // Replace with std::any_of with C++20. |
| 97 | + for (size_t I = 0; I < sizeof...(Ns); ++I) |
| 98 | + if (SameSize[I]) |
| 99 | + return true; |
| 100 | + return false; |
| 101 | +} |
| 102 | + |
| 103 | +// Checks if the type of the operation is the same. For scalars and marray that |
| 104 | +// requires the types to be exact matches. For vector and swizzles it requires |
| 105 | +// that the corresponding vector conversion is the same. |
| 106 | +template <typename T1, typename T2, typename = void> |
| 107 | +struct is_same_op : std::is_same<T1, T2> {}; |
| 108 | + |
| 109 | +template <typename T1, typename T2> |
| 110 | +constexpr bool is_same_op_v = is_same_op<T1, T2>::value; |
| 111 | + |
| 112 | +// Constexpr function for checking that all types are the same, considering |
| 113 | +// swizzles and vectors the same if they have the same number of elements and |
| 114 | +// the same element type. |
| 115 | +template <typename T, typename... Ts> constexpr bool CheckAllSameOpType() { |
| 116 | + constexpr bool SameType[] = { |
| 117 | + is_same_op_v<std::remove_cv_t<T>, std::remove_cv_t<Ts>>...}; |
| 118 | + // Replace with std::all_of with C++20. |
| 119 | + for (size_t I = 0; I < sizeof...(Ts); ++I) |
| 120 | + if (!SameType[I]) |
| 121 | + return false; |
| 122 | + return true; |
| 123 | +} |
| 124 | + |
| 125 | +// NOTE: We need a constexpr variable definition for the constexpr functions |
| 126 | +// as MSVC thinks function definitions are the same otherwise. |
| 127 | +template <typename... Ts> |
| 128 | +constexpr bool check_all_same_op_type_v = CheckAllSameOpType<Ts...>(); |
| 129 | +// NOTE: We need a constexpr variable definition for the constexpr functions |
| 130 | +// as MSVC thinks function definitions are the same otherwise. |
| 131 | +template <size_t... Ns> constexpr bool check_size_in_v = CheckSizeIn<Ns...>(); |
| 132 | + |
| 133 | +// Utility traits for getting a signed integer type with the specified size. |
| 134 | +template <size_t Size> struct get_signed_int_by_size { |
| 135 | + using type = select_scalar_by_size_t<Size, int8_t, int16_t, int32_t, int64_t>; |
| 136 | +}; |
| 137 | +template <typename T> struct same_size_signed_int { |
| 138 | + using type = typename get_signed_int_by_size<sizeof(T)>::type; |
| 139 | +}; |
| 140 | + |
| 141 | +template <typename T> |
| 142 | +using same_size_signed_int_t = typename same_size_signed_int<T>::type; |
| 143 | + |
| 144 | +// Utility traits for getting a unsigned integer type with the specified size. |
| 145 | +template <size_t Size> struct get_unsigned_int_by_size { |
| 146 | + using type = |
| 147 | + select_scalar_by_size_t<Size, uint8_t, uint16_t, uint32_t, uint64_t>; |
| 148 | +}; |
| 149 | +template <typename T> struct same_size_unsigned_int { |
| 150 | + using type = typename get_unsigned_int_by_size<sizeof(T)>::type; |
| 151 | +}; |
| 152 | + |
| 153 | +// Utility trait for getting an upsampled integer type. |
| 154 | +// NOTE: For upsampling we look for an integer of double the size of the |
| 155 | +// specified type. |
| 156 | +template <typename T> struct upsampled_int { |
| 157 | + using type = |
| 158 | + std::conditional_t<std::is_unsigned_v<T>, |
| 159 | + typename get_unsigned_int_by_size<sizeof(T) * 2>::type, |
| 160 | + typename get_signed_int_by_size<sizeof(T) * 2>::type>; |
| 161 | +}; |
| 162 | + |
| 163 | +template <typename T> using upsampled_int_t = typename upsampled_int<T>::type; |
| 164 | + |
| 165 | +// Utility for converting a swizzle to a vector or preserve the type if it isn't |
| 166 | +// a swizzle. |
| 167 | +template <typename T> struct simplify_if_swizzle { |
| 168 | + using type = T; |
| 169 | +}; |
| 170 | + |
| 171 | +template <typename T> |
| 172 | +using simplify_if_swizzle_t = typename simplify_if_swizzle<T>::type; |
| 173 | + |
| 174 | +// Utility trait for checking if T's element type is in Ts. |
| 175 | +template <typename T, typename... Ts> |
| 176 | +struct is_valid_elem_type : std::false_type {}; |
| 177 | + |
| 178 | +template <typename T, typename... Ts> |
| 179 | +constexpr bool is_valid_elem_type_v = is_valid_elem_type<T, Ts...>::value; |
| 180 | + |
| 181 | +// Utility trait for getting the decoration of a multi_ptr. |
| 182 | +template <typename T> struct get_multi_ptr_decoration; |
| 183 | +template <typename ElementType, access::address_space Space, |
| 184 | + access::decorated DecorateAddress> |
| 185 | +struct get_multi_ptr_decoration< |
| 186 | + multi_ptr<ElementType, Space, DecorateAddress>> { |
| 187 | + static constexpr access::decorated value = DecorateAddress; |
| 188 | +}; |
| 189 | + |
| 190 | +template <typename T> |
| 191 | +constexpr access::decorated get_multi_ptr_decoration_v = |
| 192 | + get_multi_ptr_decoration<T>::value; |
| 193 | + |
| 194 | +// Utility trait for checking if a multi_ptr has a "writable" address space, |
| 195 | +// i.e. global, local, private or generic. |
| 196 | +template <typename T> struct has_writeable_addr_space : std::false_type {}; |
| 197 | +template <typename ElementType, access::address_space Space, |
| 198 | + access::decorated DecorateAddress> |
| 199 | +struct has_writeable_addr_space<multi_ptr<ElementType, Space, DecorateAddress>> |
| 200 | + : std::bool_constant<Space == access::address_space::global_space || |
| 201 | + Space == access::address_space::local_space || |
| 202 | + Space == access::address_space::private_space || |
| 203 | + Space == access::address_space::generic_space> {}; |
| 204 | + |
| 205 | +template <typename T> |
| 206 | +constexpr bool has_writeable_addr_space_v = has_writeable_addr_space<T>::value; |
| 207 | + |
| 208 | +// Wrapper trait around nan_return to allow propagation through swizzles and |
| 209 | +// marrays. |
| 210 | +template <typename T> struct nan_return_unswizzled { |
| 211 | + using type = typename nan_types<T, T>::ret_type; |
| 212 | +}; |
| 213 | + |
| 214 | +template <typename T> |
| 215 | +using nan_return_unswizzled_t = typename nan_return_unswizzled<T>::type; |
| 216 | + |
| 217 | +} // namespace detail |
| 218 | +} // namespace _V1 |
| 219 | +} // namespace sycl |
0 commit comments