Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

implement known_identity #778

Open
wants to merge 3 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
79 changes: 41 additions & 38 deletions include/hipSYCL/sycl/libkernel/builtins.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -388,8 +388,9 @@ using ulonglong16 = vec<unsigned long long, 16>;
#define HIPSYCL_BUILTIN_GENERATOR_TRINARY_T_T_T(T, name, impl_name) \
HIPSYCL_BUILTIN T name(T a, T b, T c) noexcept { \
if constexpr (std::is_arithmetic_v<T>) { \
return impl_name(detail::data_element(a, 0), detail::data_element(b, 0), \
detail::data_element(c, 0)); \
return static_cast<T>(impl_name(detail::data_element(a, 0), \
detail::data_element(b, 0), \
detail::data_element(c, 0))); \
} else { \
T result; \
for (int i = 0; i < detail::builtin_type_traits<T>::num_elements; ++i) { \
Expand All @@ -405,8 +406,8 @@ using ulonglong16 = vec<unsigned long long, 16>;
#define HIPSYCL_BUILTIN_GENERATOR_BINARY_T_T(T, name, impl_name) \
HIPSYCL_BUILTIN T name(T a, T b) noexcept { \
if constexpr (std::is_arithmetic_v<T>) { \
return impl_name(detail::data_element(a, 0), \
detail::data_element(b, 0)); \
return static_cast<T>(impl_name(detail::data_element(a, 0), \
detail::data_element(b, 0))); \
} else { \
T result; \
for (int i = 0; i < detail::builtin_type_traits<T>::num_elements; ++i) { \
Expand All @@ -422,7 +423,7 @@ using ulonglong16 = vec<unsigned long long, 16>;
template <access::address_space A> \
HIPSYCL_BUILTIN T name(T a, const multi_ptr<T, A> &b) noexcept { \
if constexpr (std::is_arithmetic_v<T>) { \
return impl_name(detail::data_element(a, 0), b.get()); \
return static_cast<T>(impl_name(detail::data_element(a, 0), b.get())); \
} else { \
T result; \
for (int i = 0; i < detail::builtin_type_traits<T>::num_elements; ++i) { \
Expand All @@ -440,8 +441,8 @@ using ulonglong16 = vec<unsigned long long, 16>;
int> = 0> \
HIPSYCL_BUILTIN T name(T a, IntType b) noexcept { \
if constexpr (std::is_arithmetic_v<T>) { \
return impl_name(detail::data_element(a, 0), \
detail::data_element(b, 0)); \
return static_cast<T>(impl_name(detail::data_element(a, 0), \
detail::data_element(b, 0))); \
} else { \
T result; \
for (int i = 0; i < detail::builtin_type_traits<T>::num_elements; ++i) { \
Expand Down Expand Up @@ -474,7 +475,7 @@ using ulonglong16 = vec<unsigned long long, 16>;
#define HIPSYCL_BUILTIN_GENERATOR_UNARY_T(T, name, impl_name) \
HIPSYCL_BUILTIN T name(T a) noexcept { \
if constexpr (std::is_arithmetic_v<T>) { \
return impl_name(detail::data_element(a, 0)); \
return static_cast<T>(impl_name(detail::data_element(a, 0))); \
} else { \
T result; \
for (int i = 0; i < detail::builtin_type_traits<T>::num_elements; ++i) { \
Expand All @@ -485,38 +486,40 @@ using ulonglong16 = vec<unsigned long long, 16>;
} \
}

#define HIPSYCL_BUILTIN_GENERATOR_UNARY_T_RET_INT(T, name, impl_name) \
HIPSYCL_BUILTIN \
typename detail::builtin_type_traits<T>::alternative_data_type<int> name( \
T a) noexcept { \
if constexpr (std::is_arithmetic_v<T>) { \
return impl_name(detail::data_element(a, 0)); \
} else { \
typename detail::builtin_type_traits<T>::alternative_data_type<int> \
result; \
for (int i = 0; i < detail::builtin_type_traits<T>::num_elements; ++i) { \
auto a_i = detail::data_element(a, i); \
detail::data_element(result, i) = impl_name(a_i); \
} \
return result; \
} \
#define HIPSYCL_BUILTIN_GENERATOR_UNARY_T_RET_INT(T, name, impl_name) \
HIPSYCL_BUILTIN \
typename detail::builtin_type_traits<T>::alternative_data_type<int> name( \
T a) noexcept { \
if constexpr (std::is_arithmetic_v<T>) { \
return static_cast<detail::builtin_type_traits<T>::alternative_data_type<int>>( \
static_cast<int>(impl_name(detail::data_element(a, 0)))); \
} else { \
typename detail::builtin_type_traits<T>::alternative_data_type<int> \
result; \
for (int i = 0; i < detail::builtin_type_traits<T>::num_elements; ++i) { \
auto a_i = detail::data_element(a, i); \
detail::data_element(result, i) = impl_name(a_i); \
} \
return result; \
} \
}

#define HIPSYCL_BUILTIN_GENERATOR_UNARY_T_RET_INT64(T, name, impl_name) \
HIPSYCL_BUILTIN \
typename detail::builtin_type_traits<T>::alternative_data_type<int64_t> name(\
T a) noexcept { \
if constexpr (std::is_arithmetic_v<T>) { \
return impl_name(detail::data_element(a, 0)); \
} else { \
typename detail::builtin_type_traits<T>::alternative_data_type<int64_t> \
result; \
for (int i = 0; i < detail::builtin_type_traits<T>::num_elements; ++i) { \
auto a_i = detail::data_element(a, i); \
detail::data_element(result, i) = impl_name(a_i); \
} \
return result; \
} \
#define HIPSYCL_BUILTIN_GENERATOR_UNARY_T_RET_INT64(T, name, impl_name) \
HIPSYCL_BUILTIN \
typename detail::builtin_type_traits<T>::alternative_data_type<int64_t> name( \
T a) noexcept { \
if constexpr (std::is_arithmetic_v<T>) { \
return static_cast<detail::builtin_type_traits<T>::alternative_data_type<int64_t>>( \
static_cast<int64_t>(impl_name(detail::data_element(a, 0)))); \
} else { \
typename detail::builtin_type_traits<T>::alternative_data_type<int64_t> \
result; \
for (int i = 0; i < detail::builtin_type_traits<T>::num_elements; ++i) { \
auto a_i = detail::data_element(a, i); \
detail::data_element(result, i) = impl_name(a_i); \
} \
return result; \
} \
}


Expand Down
167 changes: 158 additions & 9 deletions include/hipSYCL/sycl/libkernel/functional.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -29,56 +29,205 @@
#ifndef HIPSYCL_SYCL_FUNCTIONAL_HPP
#define HIPSYCL_SYCL_FUNCTIONAL_HPP

#include <limits>

#include "backend.hpp"
#include "vec.hpp"

namespace hipsycl {
namespace sycl {

template <typename T> struct plus {
namespace detail {
// simple construct to get type of elements in vector
// detail::builtin_type_traits does not work for void and can not directly be used here.
template<class T>
struct element_type {
using type = T;
};

template<class T, int Dim>
struct element_type<vec<T, Dim>> {
using type = T;
};

template<typename T>
using element_type_t = typename element_type<T>::type;

} // namespace detail

template <typename T = void> struct plus {
HIPSYCL_KERNEL_TARGET
T operator()(const T &x, const T &y) const { return x + y; }
};

template <typename T> struct multiplies {
template <> struct plus<void> {
template<typename T>
HIPSYCL_KERNEL_TARGET
T operator()(const T &x, const T &y) const { return x + y; }
};

template <typename T = void> struct multiplies {
HIPSYCL_KERNEL_TARGET
T operator()(const T &x, const T &y) const { return x * y; }
};

template <> struct multiplies<void> {
template<typename T>
HIPSYCL_KERNEL_TARGET
T operator()(const T &x, const T &y) const { return x * y; }
};

template <typename T> struct bit_and {
template <typename T = void> struct bit_and {
HIPSYCL_KERNEL_TARGET
T operator()(const T &x, const T &y) const { return x & y; }
};

template <typename T> struct bit_or {
template <> struct bit_and<void> {
template<typename T>
HIPSYCL_KERNEL_TARGET
T operator()(const T &x, const T &y) const { return x & y; }
};

template <typename T = void> struct bit_or {
HIPSYCL_KERNEL_TARGET
T operator()(const T &x, const T &y) const { return x | y; }
};

template <> struct bit_or<void> {
template<typename T>
HIPSYCL_KERNEL_TARGET
T operator()(const T &x, const T &y) const { return x | y; }
};

template <typename T> struct bit_xor {
template <typename T = void> struct bit_xor {
HIPSYCL_KERNEL_TARGET
T operator()(const T &x, const T &y) const { return x ^ y; }
};

template <> struct bit_xor<void> {
template<typename T>
HIPSYCL_KERNEL_TARGET
T operator()(const T &x, const T &y) const { return x ^ y; }
};

template <typename T> struct logical_and {
template <typename T = void> struct logical_and {
HIPSYCL_KERNEL_TARGET
T operator()(const T &x, const T &y) const { return static_cast<T>(x && y); }
};

template <> struct logical_and<void> {
template<typename T>
HIPSYCL_KERNEL_TARGET
T operator()(const T &x, const T &y) const { return static_cast<T>(x && y); }
};

template <typename T> struct logical_or {
template <typename T = void> struct logical_or {
HIPSYCL_KERNEL_TARGET
T operator()(const T &x, const T &y) const { return static_cast<T>(x || y); }
};

template <> struct logical_or<void> {
template<typename T>
HIPSYCL_KERNEL_TARGET
T operator()(const T &x, const T &y) const { return static_cast<T>(x || y); }
};

template <typename T> struct minimum {
template <typename T = void> struct minimum {
HIPSYCL_KERNEL_TARGET
T operator()(const T &x, const T &y) const { return (x < y) ? x : y; }
};

template <typename T> struct maximum {
template <> struct minimum<void> {
template<typename T>
HIPSYCL_KERNEL_TARGET
T operator()(const T &x, const T &y) const { return (x < y) ? x : y; }
};

template <typename T = void> struct maximum {
HIPSYCL_KERNEL_TARGET
T operator()(const T &x, const T &y) const { return (x > y) ? x : y; }
};

template <> struct maximum<void> {
template<typename T>
HIPSYCL_KERNEL_TARGET
T operator()(const T &x, const T &y) const { return (x > y) ? x : y; }
};


namespace detail {

template<typename BinaryOperation, typename AccumulatorT, typename Enable = void>
struct known_identity_trait {
static constexpr bool has_known_identity = false; \
};

template<typename T, typename Enable=void>
struct minmax_identity {
inline static constexpr T max_id = static_cast<T>(std::numeric_limits<T>::lowest());
inline static constexpr T min_id = static_cast<T>(std::numeric_limits<T>::max());
};

template<typename T>
struct minmax_identity<T, std::enable_if_t<std::numeric_limits<T>::has_infinity>> {
inline static constexpr T max_id = static_cast<T>(-std::numeric_limits<T>::infinity());
inline static constexpr T min_id = static_cast<T>(std::numeric_limits<T>::infinity());
};

#define HIPSYCL_DEFINE_IDENTITY(op, cond, identity) \
template<typename T, typename U> \
struct known_identity_trait<op<T>, U, std::enable_if_t<cond>> { \
inline static constexpr bool has_known_identity = true; \
inline static constexpr std::remove_cv_t<T> known_identity = (identity); \
}; \
template<typename T> \
struct known_identity_trait<op<void>, T, std::enable_if_t<cond>> { \
inline static constexpr bool has_known_identity = true; \
inline static constexpr std::remove_cv_t<T> known_identity = (identity); \
}

#ifdef __GNUC__
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wbool-operation" // allow ~bool, bool & bool
#endif

// TODO is_arithmetic implicitly covers the current pseudo half = ushort type, resolve once half is implemented
HIPSYCL_DEFINE_IDENTITY(plus, std::is_arithmetic_v<element_type_t<T>>, T{});
HIPSYCL_DEFINE_IDENTITY(multiplies, std::is_arithmetic_v<element_type_t<T>>, T{static_cast<element_type_t<T>>(1)});
HIPSYCL_DEFINE_IDENTITY(bit_or, std::is_integral_v<element_type_t<T>>, T{});
HIPSYCL_DEFINE_IDENTITY(bit_and, std::is_integral_v<element_type_t<T>>, T{static_cast<element_type_t<T>>(~element_type_t<T>{})});
HIPSYCL_DEFINE_IDENTITY(bit_xor, std::is_integral_v<element_type_t<T>>, T{});
HIPSYCL_DEFINE_IDENTITY(logical_or, (std::is_same_v<element_type_t<std::remove_cv_t<T>>, bool>), T{false});
HIPSYCL_DEFINE_IDENTITY(logical_and, (std::is_same_v<element_type_t<std::remove_cv_t<T>>, bool>), T{true});
HIPSYCL_DEFINE_IDENTITY(minimum, std::is_arithmetic_v<element_type_t<T>>, T{minmax_identity<element_type_t<std::remove_cv_t<T>>>::min_id});
HIPSYCL_DEFINE_IDENTITY(maximum, std::is_arithmetic_v<element_type_t<T>>, T{minmax_identity<element_type_t<std::remove_cv_t<T>>>::max_id});

#ifdef __GNUC__
#pragma GCC diagnostic pop
#endif

#undef HIPSYCL_DEFINE_IDENTITY

}

template<typename BinaryOperation, typename AccumulatorT>
struct known_identity {
static constexpr AccumulatorT value = detail::known_identity_trait<
BinaryOperation, AccumulatorT>::known_identity;
};

template <typename BinaryOperation, typename AccumulatorT>
inline constexpr AccumulatorT known_identity_v = known_identity<BinaryOperation, AccumulatorT>::value;

template<typename BinaryOperation, typename AccumulatorT>
struct has_known_identity {
static constexpr bool value = detail::known_identity_trait<
BinaryOperation, AccumulatorT>::has_known_identity;
};

template <typename BinaryOperation, typename AccumulatorT>
inline constexpr bool has_known_identity_v = has_known_identity<BinaryOperation, AccumulatorT>::value;

} // namespace sycl
}

Expand Down