Description
Describe the Bug:
When performing an inclusive or exclusive scan with host or device backends, the scan fails to compile if both the source and destination sequences are provided as reverse iterators and the underlying source iterators are different, non equality comparable types. This issue likely affects other iterator adaptors as well.
To Reproduce:
The following reproducer may be used:
// icpx [-DONEDPL_USE_DPCPP_BACKEND=1] scan_reverse_iterator.cpp
#include <oneapi/dpl/execution>
#include <oneapi/dpl/algorithm>
#include <oneapi/dpl/numeric>
#include <vector>
#include <iostream>
#if ONEDPL_USE_DPCPP_BACKEND
# define POLICY oneapi::dpl::execution::dpcpp_default
#else
# define POLICY oneapi::dpl::execution::par_unseq
#endif
int main() {
// Create a vector of bool values
std::vector<bool> input = {true, false, true, true, false, true};
std::cout << "Original vector of booleans:" << std::endl;
for (const auto& val : input) {
std::cout << (val ? "true" : "false") << " ";
}
std::cout << std::endl;
// Create a vector to store the result (int type)
std::vector<int> result(input.size());
// Create reverse iterators
auto input_rbegin = std::rbegin(input);
auto input_rend = std::rend(input);
auto result_rbegin = std::rbegin(result);
// Use exclusive_scan with reverse iterators to convert bool to int
// This will scan from right to left (due to reverse iterators)
// The initial value (0) will appear at the rightmost position
oneapi::dpl::exclusive_scan(
POLICY, // Parallel execution policy
input_rbegin, // Start of reversed input range
input_rend, // End of reversed input range
result_rbegin, // Start of reversed output range
int{0} // Initial value
);
std::cout << "\nOriginal vector (left to right):" << std::endl;
for (size_t i = 0; i < input.size(); ++i) {
std::cout << (input[i] ? 1 : 0) << " ";
}
std::cout << std::endl;
std::cout << "\nResult of exclusive_scan with reverse iterators:" << std::endl;
for (const auto& val : result) {
std::cout << val << " ";
}
std::cout << std::endl;
return 0;
}
and compiled with icpx [-DONEDPL_USE_DPCPP_BACKEND=1] scan_reverse_iterator.cpp
. You will be met with a compile error.
Expected Behavior:
Expected behavior is successful compilation of this sample which can be verified by using a oneapi::dpl::execution::seq
policy.
Additional Context:
The reason for this is caused by the fact that we attempt to perform in-place exclusive scan detection for both OpenMP and SYCL device backends to workaround issues. This cannot be done without leveraging UB in which we compare source and destination iterators. The following utility is used:
oneDPL/include/oneapi/dpl/pstl/utils.h
Lines 832 to 863 in ce4acb4
__is_equality_comparable
detects if the iterator comparison is valid by checking its return type and using SFINAE. In the case of two iterators such as std::reverse_iterator<std::vector<bool>::iterator>
and std::reverse_iterator<std::vector<int>::iterator>
, the check returns true as operator==
is defined for any two reverse iterators. However, compilation fails in the body of this comparison as the two vector iterators are not equality comparable.