Skip to content

Commit 7057ebe

Browse files
committed
[SYCL] Fix statically known identity values for MIN/MAX reductions
Signed-off-by: Vyacheslav N Klochkov <[email protected]>
1 parent 65c378e commit 7057ebe

10 files changed

+67
-83
lines changed

sycl/include/CL/sycl/intel/reduction.hpp

Lines changed: 18 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -209,14 +209,18 @@ class reducer<T, BinaryOperation,
209209
template <typename _T = T, class _BinaryOperation = BinaryOperation>
210210
static enable_if_t<IsMinimumIdentityOp<_T, _BinaryOperation>::value, _T>
211211
getIdentity() {
212-
return (std::numeric_limits<_T>::max)();
212+
return std::numeric_limits<_T>::has_infinity
213+
? std::numeric_limits<_T>::infinity()
214+
: (std::numeric_limits<_T>::max)();
213215
}
214216

215217
/// Returns minimal possible value as identity for MAX operations.
216218
template <typename _T = T, class _BinaryOperation = BinaryOperation>
217219
static enable_if_t<IsMaximumIdentityOp<_T, _BinaryOperation>::value, _T>
218220
getIdentity() {
219-
return (std::numeric_limits<_T>::min)();
221+
return std::numeric_limits<_T>::has_infinity
222+
? -std::numeric_limits<_T>::infinity()
223+
: std::numeric_limits<_T>::lowest();
220224
}
221225

222226
template <typename _T = T>
@@ -389,17 +393,20 @@ class reduction_impl {
389393
typename _T = T, class _BinaryOperation = BinaryOperation,
390394
enable_if_t<IsKnownIdentityOp<_T, _BinaryOperation>::value> * = nullptr>
391395
reduction_impl(accessor_type &Acc, const T &Identity)
392-
: MAcc(Acc), MIdentity(Identity) {
396+
: MAcc(Acc), MIdentity(getIdentity()) {
393397
assert(Acc.get_count() == 1 &&
394398
"Only scalar/1-element reductions are supported now.");
395-
// For operations with known identity value the operator == is defined.
396-
// It is sort of dilemma here: from one point of view - user may set
397-
// such identity that would be enough for his data, i.e. identity=100 for
398-
// min operation if user knows all data elements are less than 100.
399-
// From another point of view - it is the source of unexpected errors,
400-
// when the input data changes.
401-
// Let's be strict for now and emit an error if identity is not proper.
402-
assert(Identity == getIdentity() && "Unexpected Identity parameter value.");
399+
// For now the implementation ignores the identity value given by user
400+
// when the implementation knows the identity.
401+
// The SPEC could prohibit passing identity parameter to operations with
402+
// known identity, but that could have some bad consequences too.
403+
// For example, at some moment the implementation may NOT know the identity
404+
// for COMPLEX-PLUS reduction. User may create a program that would pass
405+
// COMPLEX value (0,0) as identity for PLUS reduction. At some later moment
406+
// when the implementation starts handling COMPLEX-PLUS as known operation
407+
// the existing user's program remains compilable and working correctly.
408+
// I.e. with this constructor here, adding more reduction operations to the
409+
// list of known operations does not break the existing programs.
403410
}
404411

405412
/// Constructs reduction_impl when the identity value is unknown.

sycl/test/reduction/reduction_ctor.cpp

Lines changed: 5 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -1,48 +1,15 @@
11
// RUN: %clangxx -fsycl %s -o %t.out
22
// RUN: env SYCL_DEVICE_TYPE=HOST %t.out
3-
//==----------------reduction_ctor.cpp - SYCL reduction basic test ---------==//
4-
//
5-
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
6-
// See https://llvm.org/LICENSE.txt for license information.
7-
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
8-
//
9-
//===----------------------------------------------------------------------===//
103

114
// This performs basic checks such as reduction creation, getIdentity() method,
125
// and the combine() method of the aux class 'reducer'.
136

7+
#include "reduction_utils.hpp"
148
#include <CL/sycl.hpp>
159
#include <cassert>
1610

1711
using namespace cl::sycl;
1812

19-
template <typename T, class BinaryOperation, int N>
20-
struct init_data_t {
21-
void initInputData(T IdentityVal,
22-
buffer<T, 1> &InBuf,
23-
T &ExpectedReduValue) {
24-
ExpectedReduValue = IdentityVal;
25-
BinaryOperation Op;
26-
auto In = InBuf.template get_access<access::mode::write>();
27-
for (int I = 0; I < N; ++I) {
28-
In[I] = ((I + 1) % 5) + 1;
29-
ExpectedReduValue = Op(ExpectedReduValue, In[I]);
30-
}
31-
}
32-
};
33-
34-
template <typename T, int N>
35-
struct init_data_t<T, std::multiplies<T>, N> {
36-
void initInputData(T IdentityVal, buffer<T, 1> &InBuf, T &ExpectedReduValue) {
37-
ExpectedReduValue = IdentityVal;
38-
std::multiplies<T> Op;
39-
auto In = InBuf.template get_access<access::mode::write>();
40-
for (int I = 0; I < N; ++I) {
41-
In[I] = 1 + (((I % 37) == 0) ? 1 : 0);
42-
ExpectedReduValue = Op(ExpectedReduValue, In[I]);
43-
}
44-
}
45-
};
4613

4714
template <typename T, typename Reduction>
4815
void test_reducer(Reduction &Redu, T A, T B) {
@@ -157,15 +124,13 @@ int main() {
157124
testBoth<int, intel::bit_or<int>>(0, 1, 8);
158125
testBoth<int, intel::bit_xor<int>>(0, 7, 3);
159126
testBoth<int, intel::bit_and<int>>(~0, 7, 3);
160-
testBoth<int, intel::minimum<int>>(std::numeric_limits<int>::max(), 7, 3);
161-
testBoth<int, intel::maximum<int>>(std::numeric_limits<int>::min(), 7, 3);
127+
testBoth<int, intel::minimum<int>>((std::numeric_limits<int>::max)(), 7, 3);
128+
testBoth<int, intel::maximum<int>>((std::numeric_limits<int>::min)(), 7, 3);
162129

163130
testBoth<float, intel::plus<float>>(0, 1, 7);
164131
testBoth<float, std::multiplies<float>>(1, 1, 7);
165-
testBoth<float, intel::minimum<float>>(
166-
std::numeric_limits<float>::max(), 7, 3);
167-
testBoth<float, intel::maximum<float>>(
168-
std::numeric_limits<float>::min(), 7, 3);
132+
testBoth<float, intel::minimum<float>>(getMaximumFPValue<float>(), 7, 3);
133+
testBoth<float, intel::maximum<float>>(getMinimumFPValue<float>(), 7, 3);
169134

170135
testUnknown<Point<float>, 0, PointPlus<float>>(Point<float>(0), Point<float>(1), Point<float>(7));
171136
testUnknown<Point<float>, 1, PointPlus<float>>(Point<float>(0), Point<float>(1), Point<float>(7));

sycl/test/reduction/reduction_nd_s0_dw.cpp

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -79,17 +79,17 @@ int main() {
7979
test<int, 0, intel::bit_or<int>>(0, 8, 256);
8080
test<int, 0, intel::bit_xor<int>>(0, 8, 256);
8181
test<int, 0, intel::bit_and<int>>(~0, 8, 256);
82-
test<int, 0, intel::minimum<int>>(std::numeric_limits<int>::max(), 8, 256);
83-
test<int, 0, intel::maximum<int>>(std::numeric_limits<int>::min(), 8, 256);
82+
test<int, 0, intel::minimum<int>>((std::numeric_limits<int>::max)(), 8, 256);
83+
test<int, 0, intel::maximum<int>>((std::numeric_limits<int>::min)(), 8, 256);
8484

8585
// Check with various types.
8686
test<float, 0, std::multiplies<float>>(1, 8, 256);
87-
test<float, 0, intel::minimum<float>>(std::numeric_limits<float>::max(), 8, 256);
88-
test<float, 0, intel::maximum<float>>(std::numeric_limits<float>::min(), 8, 256);
87+
test<float, 0, intel::minimum<float>>(getMaximumFPValue<float>(), 8, 256);
88+
test<float, 0, intel::maximum<float>>(getMinimumFPValue<float>(), 8, 256);
8989

9090
test<double, 0, std::multiplies<double>>(1, 8, 256);
91-
test<double, 0, intel::minimum<double>>(std::numeric_limits<double>::max(), 8, 256);
92-
test<double, 0, intel::maximum<double>>(std::numeric_limits<double>::min(), 8, 256);
91+
test<double, 0, intel::minimum<double>>(getMaximumFPValue<double>(), 8, 256);
92+
test<double, 0, intel::maximum<double>>(getMinimumFPValue<double>(), 8, 256);
9393

9494
// Check with CUSTOM type.
9595
test<CustomVec<long long>, 0, CustomVecPlus<long long>>(CustomVec<long long>(0), 8, 256);

sycl/test/reduction/reduction_nd_s0_rw.cpp

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -81,17 +81,17 @@ int main() {
8181
test<int, 0, intel::bit_or<int>>(0, 8, 256);
8282
test<int, 0, intel::bit_xor<int>>(0, 8, 256);
8383
test<int, 0, intel::bit_and<int>>(~0, 8, 256);
84-
test<int, 0, intel::minimum<int>>(std::numeric_limits<int>::max(), 8, 256);
85-
test<int, 0, intel::maximum<int>>(std::numeric_limits<int>::min(), 8, 256);
84+
test<int, 0, intel::minimum<int>>((std::numeric_limits<int>::max)(), 8, 256);
85+
test<int, 0, intel::maximum<int>>((std::numeric_limits<int>::min)(), 8, 256);
8686

8787
// Check with various types.
8888
test<float, 0, std::multiplies<float>>(1, 8, 256);
89-
test<float, 0, intel::minimum<float>>(std::numeric_limits<float>::max(), 8, 256);
90-
test<float, 0, intel::maximum<float>>(std::numeric_limits<float>::min(), 8, 256);
89+
test<float, 0, intel::minimum<float>>(getMaximumFPValue<float>(), 8, 256);
90+
test<float, 0, intel::maximum<float>>(getMinimumFPValue<float>(), 8, 256);
9191

9292
test<double, 0, std::multiplies<double>>(1, 8, 256);
93-
test<double, 0, intel::minimum<double>>(std::numeric_limits<double>::max(), 8, 256);
94-
test<double, 0, intel::maximum<double>>(std::numeric_limits<double>::min(), 8, 256);
93+
test<double, 0, intel::minimum<double>>(getMaximumFPValue<double>(), 8, 256);
94+
test<double, 0, intel::maximum<double>>(getMinimumFPValue<double>(), 8, 256);
9595

9696
// Check with CUSTOM type.
9797
test<CustomVec<long long>, 0, CustomVecPlus<long long>>(CustomVec<long long>(0), 8, 256);

sycl/test/reduction/reduction_nd_s1_dw.cpp

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -80,17 +80,17 @@ int main() {
8080
test<int, 1, intel::bit_or<int>>(0, 8, 256);
8181
test<int, 1, intel::bit_xor<int>>(0, 8, 256);
8282
test<int, 1, intel::bit_and<int>>(~0, 8, 256);
83-
test<int, 1, intel::minimum<int>>(std::numeric_limits<int>::max(), 8, 256);
84-
test<int, 1, intel::maximum<int>>(std::numeric_limits<int>::min(), 8, 256);
83+
test<int, 1, intel::minimum<int>>((std::numeric_limits<int>::max)(), 8, 256);
84+
test<int, 1, intel::maximum<int>>((std::numeric_limits<int>::min)(), 8, 256);
8585

8686
// Check with various types.
8787
test<float, 1, std::multiplies<float>>(1, 8, 256);
88-
test<float, 1, intel::minimum<float>>(std::numeric_limits<float>::max(), 8, 256);
89-
test<float, 1, intel::maximum<float>>(std::numeric_limits<float>::min(), 8, 256);
88+
test<float, 1, intel::minimum<float>>(getMaximumFPValue<float>(), 8, 256);
89+
test<float, 1, intel::maximum<float>>(getMinimumFPValue<float>(), 8, 256);
9090

9191
test<double, 1, std::multiplies<double>>(1, 8, 256);
92-
test<double, 1, intel::minimum<double>>(std::numeric_limits<double>::max(), 8, 256);
93-
test<double, 1, intel::maximum<double>>(std::numeric_limits<double>::min(), 8, 256);
92+
test<double, 1, intel::minimum<double>>(getMaximumFPValue<double>(), 8, 256);
93+
test<double, 1, intel::maximum<double>>(getMinimumFPValue<double>(), 8, 256);
9494

9595
// Check with CUSTOM type.
9696
test<CustomVec<long long>, 1, CustomVecPlus<long long>>(CustomVec<long long>(0), 8, 256);

sycl/test/reduction/reduction_nd_s1_rw.cpp

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -82,17 +82,17 @@ int main() {
8282
test<int, 1, intel::bit_or<int>>(0, 8, 256);
8383
test<int, 1, intel::bit_xor<int>>(0, 8, 256);
8484
test<int, 1, intel::bit_and<int>>(~0, 8, 256);
85-
test<int, 1, intel::minimum<int>>(std::numeric_limits<int>::max(), 8, 256);
86-
test<int, 1, intel::maximum<int>>(std::numeric_limits<int>::min(), 8, 256);
85+
test<int, 1, intel::minimum<int>>((std::numeric_limits<int>::max)(), 8, 256);
86+
test<int, 1, intel::maximum<int>>((std::numeric_limits<int>::min)(), 8, 256);
8787

8888
// Check with various types.
8989
test<float, 1, std::multiplies<float>>(1, 8, 256);
90-
test<float, 1, intel::minimum<float>>(std::numeric_limits<float>::max(), 8, 256);
91-
test<float, 1, intel::maximum<float>>(std::numeric_limits<float>::min(), 8, 256);
90+
test<float, 1, intel::minimum<float>>(getMaximumFPValue<float>(), 8, 256);
91+
test<float, 1, intel::maximum<float>>(getMinimumFPValue<float>(), 8, 256);
9292

9393
test<double, 1, std::multiplies<double>>(1, 8, 256);
94-
test<double, 1, intel::minimum<double>>(std::numeric_limits<double>::max(), 8, 256);
95-
test<double, 1, intel::maximum<double>>(std::numeric_limits<double>::min(), 8, 256);
94+
test<double, 1, intel::minimum<double>>(getMaximumFPValue<double>(), 8, 256);
95+
test<double, 1, intel::maximum<double>>(getMinimumFPValue<double>(), 8, 256);
9696

9797
// Check with CUSTOM type.
9898
test<CustomVec<long long>, 1, CustomVecPlus<long long>>(CustomVec<long long>(0), 8, 256);

sycl/test/reduction/reduction_placeholder.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -72,8 +72,8 @@ int main() {
7272
test<int, 1, intel::bit_or<int>>(0, 4, 128);
7373

7474
// fast reduce
75-
test<float, 1, intel::minimum<float>>(std::numeric_limits<float>::max(), 5, 5 * 7);
76-
test<float, 0, intel::maximum<float>>(std::numeric_limits<float>::min(), 4, 128);
75+
test<float, 1, intel::minimum<float>>(getMaximumFPValue<float>(), 5, 5 * 7);
76+
test<float, 0, intel::maximum<float>>(getMinimumFPValue<float>(), 4, 128);
7777

7878
// generic algorithm
7979
test<int, 0, std::multiplies<int>>(1, 7, 7 * 5);

sycl/test/reduction/reduction_transparent.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -114,12 +114,12 @@ void test(T Identity, size_t WGSize, size_t NWItems) {
114114

115115
int main() {
116116
#if __cplusplus >= 201402L
117-
test<double, 0, intel::maximum<>>((std::numeric_limits<double>::min)(), 7, 7 * 5);
117+
test<double, 0, intel::maximum<>>(getMinimumFPValue<double>(), 7, 7 * 5);
118118
test<signed char, 0, intel::plus<>>(0, 7, 49);
119119
test<unsigned char, 1, std::multiplies<>>(1, 4, 16);
120120
#ifndef SKIP_FOR_HALF
121121
test<half, 1, intel::plus<>>(0, 4, 8);
122-
test<half, 1, intel::minimum<>>((std::numeric_limits<half>::max)(), 8, 32);
122+
test<half, 1, intel::minimum<>>(getMaximumFPValue<half>(), 8, 32);
123123
#endif // SKIP_FOR_HALF
124124
#endif // __cplusplus >= 201402L
125125

sycl/test/reduction/reduction_usm.cpp

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -113,10 +113,8 @@ int main() {
113113
testUSM<int, 1, intel::bit_or<int>>(0, 4, 128);
114114

115115
// fast reduce
116-
testUSM<float, 1, intel::minimum<float>>(
117-
(std::numeric_limits<float>::max)(), 5, 5 * 7);
118-
testUSM<float, 0, intel::maximum<float>>(
119-
(std::numeric_limits<float>::min)(), 4, 128);
116+
testUSM<float, 1, intel::minimum<float>>(getMaximumFPValue<float>(), 5, 5 * 7);
117+
testUSM<float, 0, intel::maximum<float>>(getMinimumFPValue<float>(), 4, 128);
120118

121119
// generic algorithm
122120
testUSM<int, 0, std::multiplies<int>>(1, 7, 7 * 5);

sycl/test/reduction/reduction_utils.hpp

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,3 +52,17 @@ struct CustomVecPlus {
5252
return CV(A.X + B.X, A.Y + B.Y);
5353
}
5454
};
55+
56+
template <typename T>
57+
T getMinimumFPValue() {
58+
return std::numeric_limits<T>::has_infinity
59+
? -std::numeric_limits<T>::infinity()
60+
: std::numeric_limits<T>::lowest();
61+
}
62+
63+
template <typename T>
64+
T getMaximumFPValue() {
65+
return std::numeric_limits<T>::has_infinity
66+
? std::numeric_limits<T>::infinity()
67+
: (std::numeric_limits<T>::max)();
68+
}

0 commit comments

Comments
 (0)