Skip to content

Commit f0d0f0c

Browse files
[SYCL] Use sycl:: math functions over std:: in our headers (#11209)
We want to avoid including `<cmath>` as it pollutes global namespace. A prerequisite for this is not using any `std::` math functions which this PR implements.
1 parent ce22c19 commit f0d0f0c

File tree

6 files changed

+242
-207
lines changed

6 files changed

+242
-207
lines changed
Lines changed: 219 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,219 @@
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

Comments
 (0)