@@ -158,6 +158,13 @@ template <template <typename> typename F> struct get_scalar_binary_op<F<void>> {
158
158
using type = F<void >;
159
159
};
160
160
161
+ // ---- is_max_or_min
162
+ template <typename T> struct is_max_or_min : std::false_type {};
163
+ template <typename T>
164
+ struct is_max_or_min <sycl::maximum<T>> : std::true_type {};
165
+ template <typename T>
166
+ struct is_max_or_min <sycl::minimum<T>> : std::true_type {};
167
+
161
168
// ---- identity_for_ga_op
162
169
// the group algorithms support std::complex, limited to sycl::plus operation
163
170
// get the correct identity for group algorithm operation.
@@ -678,8 +685,34 @@ exclusive_scan_over_group(Group g, T x, BinaryOperation binary_op) {
678
685
sycl::detail::ExtractMask (sycl::detail::GetMask (g))[0 ]);
679
686
}
680
687
#endif
681
- return sycl::detail::calc<__spv::GroupOperation::ExclusiveScan>(
688
+ // For the first work item in the group, we cannot return the result
689
+ // of calc when T is a signed char or short type and the
690
+ // BinaryOperation is maximum or minimum. calc uses SPIRV group
691
+ // collective instructions, which only operate on 32 or 64 bit
692
+ // integers. So, when using calc with a short or char type, the
693
+ // argument is converted to a 32 bit integer, the 32 bit group
694
+ // operation is performed, and then converted back to the original
695
+ // short or char type. For an exclusive scan, the first work item
696
+ // returns the identity for the supplied operation. However, the
697
+ // identity of a 32 bit signed integer maximum or minimum when
698
+ // converted to a signed char or short does not correspond to the
699
+ // identity of a signed char or short maximum or minimum. For
700
+ // example, the identity of a signed 32 bit maximum is
701
+ // INT_MIN=-2**31, and when converted to a signed char, results in
702
+ // 0. However, the identity of a signed char maximum is
703
+ // SCHAR_MIN=-2**7. Therefore, we need the following check to
704
+ // circumvent this issue.
705
+ auto res = sycl::detail::calc<__spv::GroupOperation::ExclusiveScan>(
682
706
g, typename sycl::detail::GroupOpTag<T>::type (), x, binary_op);
707
+ if constexpr ((std::is_same_v<signed char , T> ||
708
+ std::is_same_v<signed short , T> ||
709
+ (std::is_signed_v<char > && std::is_same_v<char , T>)) &&
710
+ detail::is_max_or_min<BinaryOperation>::value) {
711
+ auto local_id = sycl::detail::get_local_linear_id (g);
712
+ if (local_id == 0 )
713
+ return sycl::known_identity_v<BinaryOperation, T>;
714
+ }
715
+ return res;
683
716
#else
684
717
(void )g;
685
718
throw sycl::exception (make_error_code (errc::feature_not_supported),
0 commit comments