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

[SYCL][COMPAT] Added compare and unordered compare operations #12998

Merged
merged 2 commits into from
Apr 16, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 44 additions & 0 deletions sycl/doc/syclcompat/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ Specifically, this library depends on the following SYCL extensions:
If available, the following extensions extend SYCLcompat functionality:

* [sycl_ext_intel_device_info](https://github.com/intel/llvm/blob/sycl/sycl/doc/extensions/supported/sycl_ext_intel_device_info.md) \[Optional\]
* [sycl_ext_oneapi_bfloat16_math_functions](../extensions/experimental/sycl_ext_oneapi_bfloat16_math_functions.asciidoc) \[Optional\]

## Usage

Expand Down Expand Up @@ -1275,6 +1276,10 @@ static kernel_function_info get_kernel_function_info(const void *function);
length. `syclcompat::length` provides a templated version that wraps over
`sycl::length`.

`compare`, `unordered_compare`, `compare_both`, `unordered_compare_both`,
`compare_mask`, and `unordered_compare_mask`, handle both ordered and unordered
comparisons.

`vectorized_max` and `vectorized_min` are binary operations returning the
max/min of two arguments, where each argument is treated as a `sycl::vec` type.
`vectorized_isgreater` performs elementwise `isgreater`, treating each argument
Expand All @@ -1292,6 +1297,45 @@ inline float fast_length(const float *a, int len);
template <typename ValueT>
inline ValueT length(const ValueT *a, const int len);

// The following definition is enabled when BinaryOperation(ValueT, ValueT) returns bool
// std::enable_if_t<std::is_same_v<std::invoke_result_t<BinaryOperation, ValueT, ValueT>, bool>, bool>
template <typename ValueT, class BinaryOperation>
inline bool
compare(const ValueT a, const ValueT b, const BinaryOperation binary_op);
template <typename ValueT, class BinaryOperation>
inline std::enable_if_t<ValueT::size() == 2, ValueT>
compare(const ValueT a, const ValueT b, const BinaryOperation binary_op);

// The following definition is enabled when BinaryOperation(ValueT, ValueT) returns bool
// std::enable_if_t<std::is_same_v<std::invoke_result_t<BinaryOperation, ValueT, ValueT>, bool>, bool>
template <typename ValueT, class BinaryOperation>
inline bool
unordered_compare(const ValueT a, const ValueT b,
const BinaryOperation binary_op);
template <typename ValueT, class BinaryOperation>
inline std::enable_if_t<ValueT::size() == 2, ValueT>
unordered_compare(const ValueT a, const ValueT b,
const BinaryOperation binary_op);

template <typename ValueT, class BinaryOperation>
inline std::enable_if_t<ValueT::size() == 2, bool>
compare_both(const ValueT a, const ValueT b, const BinaryOperation binary_op);
template <typename ValueT, class BinaryOperation>

inline std::enable_if_t<ValueT::size() == 2, bool>
unordered_compare_both(const ValueT a, const ValueT b,
const BinaryOperation binary_op);

template <typename ValueT, class BinaryOperation>
inline unsigned compare_mask(const sycl::vec<ValueT, 2> a,
const sycl::vec<ValueT, 2> b,
const BinaryOperation binary_op);

template <typename ValueT, class BinaryOperation>
inline unsigned unordered_compare_mask(const sycl::vec<ValueT, 2> a,
const sycl::vec<ValueT, 2> b,
const BinaryOperation binary_op);

template <typename S, typename T> inline T vectorized_max(T a, T b);

template <typename S, typename T> inline T vectorized_min(T a, T b);
Expand Down
124 changes: 124 additions & 0 deletions sycl/include/syclcompat/math.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,15 @@ inline constexpr RetT extend_binary(AT a, BT b, CT c,
return second_op(extend_temp, extend_c);
}

template <typename ValueT> inline bool isnan(const ValueT a) {
return sycl::isnan(a);
}
#ifdef SYCL_EXT_ONEAPI_BFLOAT16_MATH_FUNCTIONS
inline bool isnan(const sycl::ext::oneapi::bfloat16 a) {
return sycl::ext::oneapi::experimental::isnan(a);
}
#endif

} // namespace detail

/// Compute fast_length for variable-length array
Expand Down Expand Up @@ -167,6 +176,121 @@ inline ValueT length(const ValueT *a, const int len) {
}
}

/// Performs comparison.
/// \param [in] a The first value
/// \param [in] b The second value
/// \param [in] binary_op functor that implements the binary operation
/// \returns the comparison result
template <typename ValueT, class BinaryOperation>
inline std::enable_if_t<
std::is_same_v<std::invoke_result_t<BinaryOperation, ValueT, ValueT>, bool>,
bool>
compare(const ValueT a, const ValueT b, const BinaryOperation binary_op) {
return binary_op(a, b);
}
template <typename ValueT>
inline std::enable_if_t<
std::is_same_v<std::invoke_result_t<std::not_equal_to<>, ValueT, ValueT>,
bool>,
bool>
compare(const ValueT a, const ValueT b, const std::not_equal_to<> binary_op) {
return !detail::isnan(a) && !detail::isnan(b) && binary_op(a, b);
}

/// Performs 2 element comparison.
/// \param [in] a The first value
/// \param [in] b The second value
/// \param [in] binary_op functor that implements the binary operation
/// \returns the comparison result
template <typename ValueT, class BinaryOperation>
inline std::enable_if_t<ValueT::size() == 2, ValueT>
compare(const ValueT a, const ValueT b, const BinaryOperation binary_op) {
return {compare(a[0], b[0], binary_op), compare(a[1], b[1], binary_op)};
}

/// Performs unordered comparison.
/// \param [in] a The first value
/// \param [in] b The second value
/// \param [in] binary_op functor that implements the binary operation
/// \returns the comparison result
template <typename ValueT, class BinaryOperation>
inline std::enable_if_t<
std::is_same_v<std::invoke_result_t<BinaryOperation, ValueT, ValueT>, bool>,
bool>
unordered_compare(const ValueT a, const ValueT b,
const BinaryOperation binary_op) {
return detail::isnan(a) || detail::isnan(b) || binary_op(a, b);
}

/// Performs 2 element unordered comparison.
/// \param [in] a The first value
/// \param [in] b The second value
/// \param [in] binary_op functor that implements the binary operation
/// \returns the comparison result
template <typename ValueT, class BinaryOperation>
inline std::enable_if_t<ValueT::size() == 2, ValueT>
unordered_compare(const ValueT a, const ValueT b,
const BinaryOperation binary_op) {
return {unordered_compare(a[0], b[0], binary_op),
unordered_compare(a[1], b[1], binary_op)};
}

/// Performs 2 element comparison and return true if both results are true.
/// \param [in] a The first value
/// \param [in] b The second value
/// \param [in] binary_op functor that implements the binary operation
/// \returns the comparison result
template <typename ValueT, class BinaryOperation>
inline std::enable_if_t<ValueT::size() == 2, bool>
compare_both(const ValueT a, const ValueT b, const BinaryOperation binary_op) {
return compare(a[0], b[0], binary_op) && compare(a[1], b[1], binary_op);
}

/// Performs 2 element unordered comparison and return true if both results are
/// true.
/// \param [in] a The first value
/// \param [in] b The second value
/// \param [in] binary_op functor that implements the binary operation
/// \returns the comparison result
template <typename ValueT, class BinaryOperation>
inline std::enable_if_t<ValueT::size() == 2, bool>
unordered_compare_both(const ValueT a, const ValueT b,
const BinaryOperation binary_op) {
return unordered_compare(a[0], b[0], binary_op) &&
unordered_compare(a[1], b[1], binary_op);
}

/// Performs 2 elements comparison, compare result of each element is 0 (false)
/// or 0xffff (true), returns an unsigned int by composing compare result of two
/// elements.
/// \param [in] a The first value
/// \param [in] b The second value
/// \param [in] binary_op functor that implements the binary operation
/// \returns the comparison result
template <typename ValueT, class BinaryOperation>
inline unsigned compare_mask(const sycl::vec<ValueT, 2> a,
const sycl::vec<ValueT, 2> b,
const BinaryOperation binary_op) {
// Since compare returns 0 or 1, -compare will be 0x00000000 or 0xFFFFFFFF
return ((-compare(a[0], b[0], binary_op)) << 16) |
((-compare(a[1], b[1], binary_op)) & 0xFFFF);
}

/// Performs 2 elements unordered comparison, compare result of each element is
/// 0 (false) or 0xffff (true), returns an unsigned int by composing compare
/// result of two elements.
/// \param [in] a The first value
/// \param [in] b The second value
/// \param [in] binary_op functor that implements the binary operation
/// \returns the comparison result
template <typename ValueT, class BinaryOperation>
inline unsigned unordered_compare_mask(const sycl::vec<ValueT, 2> a,
const sycl::vec<ValueT, 2> b,
const BinaryOperation binary_op) {
return ((-unordered_compare(a[0], b[0], binary_op)) << 16) |
((-unordered_compare(a[1], b[1], binary_op)) & 0xFFFF);
}

/// Compute vectorized max for two values, with each value treated as a vector
/// type \p S
/// \param [in] S The type of the vector
Expand Down
2 changes: 2 additions & 0 deletions sycl/test-e2e/syclcompat/common.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -43,3 +43,5 @@ void instantiate_all_types(Functor &&f) {
using value_type_list =
std::tuple<int, unsigned int, short, unsigned short, long, unsigned long,
long long, unsigned long long, float, double, sycl::half>;

using fp_type_list = std::tuple<float, double, sycl::half>;
Loading
Loading