Skip to content

Commit 45d516c

Browse files
[SYCL] Fix return type of relational functions on scalars (#7414)
This fix updates scalar versions of relation functions that now return "bool" instead of a signed integer in SYCL 2020 mode. The fix is ABI-breaking and is put under SYCL2020_CONFORMANT_APIS guard. This is a revival of the reverted patch #5975. Signed-off-by: Larsen, Steffen <steffen.larsen@intel.com> Co-authored-by: aelovikov-intel <andrei.elovikov@intel.com>
1 parent 26619e0 commit 45d516c

File tree

4 files changed

+433
-94
lines changed

4 files changed

+433
-94
lines changed

sycl/include/sycl/builtins.hpp

Lines changed: 36 additions & 89 deletions
Original file line numberDiff line numberDiff line change
@@ -1109,198 +1109,145 @@ fast_normalize(T p) __NOEXC {
11091109
return __sycl_std::__invoke_fast_normalize<T>(p);
11101110
}
11111111

1112-
/* --------------- 4.13.7 Relational functions. Device version --------------*/
1113-
// int isequal (half x, half y)
1114-
// shortn isequal (halfn x, halfn y)
1115-
// igeninteger32bit isequal (genfloatf x, genfloatf y)
1116-
// int isequal (double x,double y);
1117-
// longn isequal (doublen x, doublen y)
1112+
/* SYCL 1.2.1 ---- 4.13.7 Relational functions. -----------------------------*/
1113+
/* SYCL 2020 ---- 4.17.9 Relational functions. -----------------------------*/
1114+
11181115
template <typename T,
11191116
typename = detail::enable_if_t<detail::is_genfloat<T>::value, T>>
11201117
detail::common_rel_ret_t<T> isequal(T x, T y) __NOEXC {
11211118
return detail::RelConverter<T>::apply(
1122-
__sycl_std::__invoke_FOrdEqual<detail::rel_ret_t<T>>(x, y));
1119+
__sycl_std::__invoke_FOrdEqual<detail::internal_rel_ret_t<T>>(x, y));
11231120
}
11241121

1125-
// int isnotequal (half x, half y)
1126-
// shortn isnotequal (halfn x, halfn y)
1127-
// igeninteger32bit isnotequal (genfloatf x, genfloatf y)
1128-
// int isnotequal (double x, double y)
1129-
// longn isnotequal (doublen x, doublen y)
11301122
template <typename T,
11311123
typename = detail::enable_if_t<detail::is_genfloat<T>::value, T>>
11321124
detail::common_rel_ret_t<T> isnotequal(T x, T y) __NOEXC {
11331125
return detail::RelConverter<T>::apply(
1134-
__sycl_std::__invoke_FUnordNotEqual<detail::rel_ret_t<T>>(x, y));
1126+
__sycl_std::__invoke_FUnordNotEqual<detail::internal_rel_ret_t<T>>(x, y));
11351127
}
11361128

1137-
// int isgreater (half x, half y)
1138-
// shortn isgreater (halfn x, halfn y)
1139-
// igeninteger32bit isgreater (genfloatf x, genfloatf y)
1140-
// int isgreater (double x, double y)
1141-
// longn isgreater (doublen x, doublen y)
11421129
template <typename T,
11431130
typename = detail::enable_if_t<detail::is_genfloat<T>::value, T>>
11441131
detail::common_rel_ret_t<T> isgreater(T x, T y) __NOEXC {
11451132
return detail::RelConverter<T>::apply(
1146-
__sycl_std::__invoke_FOrdGreaterThan<detail::rel_ret_t<T>>(x, y));
1133+
__sycl_std::__invoke_FOrdGreaterThan<detail::internal_rel_ret_t<T>>(x,
1134+
y));
11471135
}
11481136

1149-
// int isgreaterequal (half x, half y)
1150-
// shortn isgreaterequal (halfn x, halfn y)
1151-
// igeninteger32bit isgreaterequal (genfloatf x, genfloatf y)
1152-
// int isgreaterequal (double x, double y)
1153-
// longn isgreaterequal (doublen x, doublen y)
11541137
template <typename T,
11551138
typename = detail::enable_if_t<detail::is_genfloat<T>::value, T>>
11561139
detail::common_rel_ret_t<T> isgreaterequal(T x, T y) __NOEXC {
11571140
return detail::RelConverter<T>::apply(
1158-
__sycl_std::__invoke_FOrdGreaterThanEqual<detail::rel_ret_t<T>>(x, y));
1141+
__sycl_std::__invoke_FOrdGreaterThanEqual<detail::internal_rel_ret_t<T>>(
1142+
x, y));
11591143
}
11601144

1161-
// int isless (half x, half y)
1162-
// shortn isless (halfn x, halfn y)
1163-
// igeninteger32bit isless (genfloatf x, genfloatf y)
1164-
// int isless (long x, long y)
1165-
// longn isless (doublen x, doublen y)
11661145
template <typename T,
11671146
typename = detail::enable_if_t<detail::is_genfloat<T>::value, T>>
11681147
detail::common_rel_ret_t<T> isless(T x, T y) __NOEXC {
11691148
return detail::RelConverter<T>::apply(
1170-
__sycl_std::__invoke_FOrdLessThan<detail::rel_ret_t<T>>(x, y));
1149+
__sycl_std::__invoke_FOrdLessThan<detail::internal_rel_ret_t<T>>(x, y));
11711150
}
11721151

1173-
// int islessequal (half x, half y)
1174-
// shortn islessequal (halfn x, halfn y)
1175-
// igeninteger32bit islessequal (genfloatf x, genfloatf y)
1176-
// int islessequal (double x, double y)
1177-
// longn islessequal (doublen x, doublen y)
11781152
template <typename T,
11791153
typename = detail::enable_if_t<detail::is_genfloat<T>::value, T>>
11801154
detail::common_rel_ret_t<T> islessequal(T x, T y) __NOEXC {
11811155
return detail::RelConverter<T>::apply(
1182-
__sycl_std::__invoke_FOrdLessThanEqual<detail::rel_ret_t<T>>(x, y));
1156+
__sycl_std::__invoke_FOrdLessThanEqual<detail::internal_rel_ret_t<T>>(x,
1157+
y));
11831158
}
11841159

1185-
// int islessgreater (half x, half y)
1186-
// shortn islessgreater (halfn x, halfn y)
1187-
// igeninteger32bit islessgreater (genfloatf x, genfloatf y)
1188-
// int islessgreater (double x, double y)
1189-
// longn islessgreater (doublen x, doublen y)
11901160
template <typename T,
11911161
typename = detail::enable_if_t<detail::is_genfloat<T>::value, T>>
11921162
detail::common_rel_ret_t<T> islessgreater(T x, T y) __NOEXC {
11931163
return detail::RelConverter<T>::apply(
1194-
__sycl_std::__invoke_FOrdNotEqual<detail::rel_ret_t<T>>(x, y));
1164+
__sycl_std::__invoke_FOrdNotEqual<detail::internal_rel_ret_t<T>>(x, y));
11951165
}
11961166

1197-
// int isfinite (half x)
1198-
// shortn isfinite (halfn x)
1199-
// igeninteger32bit isfinite (genfloatf x)
1200-
// int isfinite (double x)
1201-
// longn isfinite (doublen x)
12021167
template <typename T,
12031168
typename = detail::enable_if_t<detail::is_genfloat<T>::value, T>>
12041169
detail::common_rel_ret_t<T> isfinite(T x) __NOEXC {
12051170
return detail::RelConverter<T>::apply(
1206-
__sycl_std::__invoke_IsFinite<detail::rel_ret_t<T>>(x));
1171+
__sycl_std::__invoke_IsFinite<detail::internal_rel_ret_t<T>>(x));
12071172
}
12081173

1209-
// int isinf (half x)
1210-
// shortn isinf (halfn x)
1211-
// igeninteger32bit isinf (genfloatf x)
1212-
// int isinf (double x)
1213-
// longn isinf (doublen x)
12141174
template <typename T,
12151175
typename = detail::enable_if_t<detail::is_genfloat<T>::value, T>>
12161176
detail::common_rel_ret_t<T> isinf(T x) __NOEXC {
12171177
return detail::RelConverter<T>::apply(
1218-
__sycl_std::__invoke_IsInf<detail::rel_ret_t<T>>(x));
1178+
__sycl_std::__invoke_IsInf<detail::internal_rel_ret_t<T>>(x));
12191179
}
12201180

1221-
// int isnan (half x)
1222-
// shortn isnan (halfn x)
1223-
// igeninteger32bit isnan (genfloatf x)
1224-
// int isnan (double x)
1225-
// longn isnan (doublen x)
12261181
template <typename T,
12271182
typename = detail::enable_if_t<detail::is_genfloat<T>::value, T>>
12281183
detail::common_rel_ret_t<T> isnan(T x) __NOEXC {
12291184
return detail::RelConverter<T>::apply(
1230-
__sycl_std::__invoke_IsNan<detail::rel_ret_t<T>>(x));
1185+
__sycl_std::__invoke_IsNan<detail::internal_rel_ret_t<T>>(x));
12311186
}
12321187

1233-
// int isnormal (half x)
1234-
// shortn isnormal (halfn x)
1235-
// igeninteger32bit isnormal (genfloatf x)
1236-
// int isnormal (double x)
1237-
// longn isnormal (doublen x)
12381188
template <typename T,
12391189
typename = detail::enable_if_t<detail::is_genfloat<T>::value, T>>
12401190
detail::common_rel_ret_t<T> isnormal(T x) __NOEXC {
12411191
return detail::RelConverter<T>::apply(
1242-
__sycl_std::__invoke_IsNormal<detail::rel_ret_t<T>>(x));
1192+
__sycl_std::__invoke_IsNormal<detail::internal_rel_ret_t<T>>(x));
12431193
}
12441194

1245-
// int isordered (half x)
1246-
// shortn isordered (halfn x, halfn y)
1247-
// igeninteger32bit isordered (genfloatf x, genfloatf y)
1248-
// int isordered (double x, double y)
1249-
// longn isordered (doublen x, doublen y)
12501195
template <typename T,
12511196
typename = detail::enable_if_t<detail::is_genfloat<T>::value, T>>
12521197
detail::common_rel_ret_t<T> isordered(T x, T y) __NOEXC {
12531198
return detail::RelConverter<T>::apply(
1254-
__sycl_std::__invoke_Ordered<detail::rel_ret_t<T>>(x, y));
1199+
__sycl_std::__invoke_Ordered<detail::internal_rel_ret_t<T>>(x, y));
12551200
}
12561201

1257-
// int isunordered (half x, half y)
1258-
// shortn isunordered (halfn x, halfn y)
1259-
// igeninteger32bit isunordered (genfloatf x, genfloatf y)
1260-
// int isunordered (double x, double y)
1261-
// longn isunordered (doublen x, doublen y)
12621202
template <typename T,
12631203
typename = detail::enable_if_t<detail::is_genfloat<T>::value, T>>
12641204
detail::common_rel_ret_t<T> isunordered(T x, T y) __NOEXC {
12651205
return detail::RelConverter<T>::apply(
1266-
__sycl_std::__invoke_Unordered<detail::rel_ret_t<T>>(x, y));
1206+
__sycl_std::__invoke_Unordered<detail::internal_rel_ret_t<T>>(x, y));
12671207
}
12681208

1269-
// int signbit (half x)
1270-
// shortn signbit (halfn x)
1271-
// igeninteger32bit signbit (genfloatf x)
1272-
// int signbit (double)
1273-
// longn signbit (doublen x)
12741209
template <typename T,
12751210
typename = detail::enable_if_t<detail::is_genfloat<T>::value, T>>
12761211
detail::common_rel_ret_t<T> signbit(T x) __NOEXC {
12771212
return detail::RelConverter<T>::apply(
1278-
__sycl_std::__invoke_SignBitSet<detail::rel_ret_t<T>>(x));
1213+
__sycl_std::__invoke_SignBitSet<detail::internal_rel_ret_t<T>>(x));
12791214
}
12801215

1216+
namespace detail {
1217+
#if defined(SYCL2020_CONFORMANT_APIS) && SYCL_LANGUAGE_VERSION >= 202001
1218+
using anyall_ret_t = bool;
1219+
#else
1220+
using anyall_ret_t = int;
1221+
#endif
1222+
} // namespace detail
1223+
12811224
// int any (sigeninteger x)
12821225
template <typename T>
1283-
detail::enable_if_t<detail::is_sigeninteger<T>::value, int> any(T x) __NOEXC {
1226+
detail::enable_if_t<detail::is_sigeninteger<T>::value, detail::anyall_ret_t>
1227+
any(T x) __NOEXC {
12841228
return detail::Boolean<1>(int(detail::msbIsSet(x)));
12851229
}
12861230

12871231
// int any (vigeninteger x)
12881232
template <typename T>
1289-
detail::enable_if_t<detail::is_vigeninteger<T>::value, int> any(T x) __NOEXC {
1233+
detail::enable_if_t<detail::is_vigeninteger<T>::value, detail::anyall_ret_t>
1234+
any(T x) __NOEXC {
12901235
return detail::rel_sign_bit_test_ret_t<T>(
12911236
__sycl_std::__invoke_Any<detail::rel_sign_bit_test_ret_t<T>>(
12921237
detail::rel_sign_bit_test_arg_t<T>(x)));
12931238
}
12941239

12951240
// int all (sigeninteger x)
12961241
template <typename T>
1297-
detail::enable_if_t<detail::is_sigeninteger<T>::value, int> all(T x) __NOEXC {
1242+
detail::enable_if_t<detail::is_sigeninteger<T>::value, detail::anyall_ret_t>
1243+
all(T x) __NOEXC {
12981244
return detail::Boolean<1>(int(detail::msbIsSet(x)));
12991245
}
13001246

13011247
// int all (vigeninteger x)
13021248
template <typename T>
1303-
detail::enable_if_t<detail::is_vigeninteger<T>::value, int> all(T x) __NOEXC {
1249+
detail::enable_if_t<detail::is_vigeninteger<T>::value, detail::anyall_ret_t>
1250+
all(T x) __NOEXC {
13041251
return detail::rel_sign_bit_test_ret_t<T>(
13051252
__sycl_std::__invoke_All<detail::rel_sign_bit_test_ret_t<T>>(
13061253
detail::rel_sign_bit_test_arg_t<T>(x)));

sycl/include/sycl/detail/boolean.hpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -110,7 +110,8 @@ template <> struct Boolean<1> {
110110

111111
// Cast to a signed interger type
112112
template <typename T> operator T() const {
113-
static_assert(is_sgeninteger<T>::value, "Invalid conversion");
113+
static_assert(std::is_same<T, bool>::value || is_sgeninteger<T>::value,
114+
"Invalid conversion");
114115
return value;
115116
}
116117

sycl/include/sycl/detail/generic_type_traits.hpp

Lines changed: 42 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -572,9 +572,37 @@ template <typename T> inline constexpr bool msbIsSet(const T x) {
572572
return (x & msbMask(x));
573573
}
574574

575+
#if defined(SYCL2020_CONFORMANT_APIS) && SYCL_LANGUAGE_VERSION >= 202001
576+
// SYCL 2020 4.17.9 (Relation functions), e.g. table 178
577+
//
578+
// genbool isequal (genfloatf x, genfloatf y)
579+
// genbool isequal (genfloatd x, genfloatd y)
580+
//
581+
// TODO: marray support isn't implemented yet.
582+
template <typename T>
583+
using common_rel_ret_t =
584+
conditional_t<is_vgentype<T>::value, make_singed_integer_t<T>, bool>;
585+
586+
// TODO: Remove this when common_rel_ret_t is promoted.
587+
template <typename T>
588+
using internal_host_rel_ret_t =
589+
conditional_t<is_vgentype<T>::value, make_singed_integer_t<T>, int>;
590+
#else
591+
// SYCL 1.2.1 4.13.7 (Relation functions), e.g.
592+
//
593+
// igeninteger32bit isequal (genfloatf x, genfloatf y)
594+
// igeninteger64bit isequal (genfloatd x, genfloatd y)
595+
//
596+
// However, we have pre-existing bug so
597+
//
598+
// igeninteger32bit isequal (genfloatd x, genfloatd y)
599+
//
600+
// Fixing it would be an ABI-breaking change so isn't done.
575601
template <typename T>
576602
using common_rel_ret_t =
577603
conditional_t<is_vgentype<T>::value, make_singed_integer_t<T>, int>;
604+
template <typename T> using internal_host_rel_ret_t = common_rel_ret_t<T>;
605+
#endif
578606

579607
// forward declaration
580608
template <int N> struct Boolean;
@@ -598,11 +626,21 @@ template <typename T> struct RelationalReturnType {
598626
#ifdef __SYCL_DEVICE_ONLY__
599627
using type = Boolean<TryToGetNumElements<T>::value>;
600628
#else
601-
using type = common_rel_ret_t<T>;
629+
// After changing the return type of scalar relational operations to boolean
630+
// we keep the old representation of the internal implementation of the
631+
// host-side builtins to avoid ABI-breaks.
632+
// TODO: Use common_rel_ret_t when ABI break is allowed and the boolean return
633+
// type for relationals are promoted out of SYCL2020_CONFORMANT_APIS.
634+
// The scalar relational builtins in
635+
// sycl/source/detail/builtins_relational.cpp should likewise be updated
636+
// to return boolean values.
637+
using type = internal_host_rel_ret_t<T>;
602638
#endif
603639
};
604640

605-
template <typename T> using rel_ret_t = typename RelationalReturnType<T>::type;
641+
// Type representing the internal return type of relational builtins.
642+
template <typename T>
643+
using internal_rel_ret_t = typename RelationalReturnType<T>::type;
606644

607645
// Used for any and all built-in functions
608646
template <typename T> struct RelationalTestForSignBitType {
@@ -634,7 +672,7 @@ struct RelConverter<
634672
using ret_t = common_rel_ret_t<T>;
635673
#else
636674
using bool_t = Boolean<N>;
637-
using ret_t = rel_ret_t<T>;
675+
using ret_t = internal_rel_ret_t<T>;
638676
#endif
639677

640678
static ret_t apply(bool_t value) {
@@ -653,7 +691,7 @@ struct RelConverter<
653691
template <typename T>
654692
struct RelConverter<
655693
T, typename detail::enable_if_t<!TryToGetElementType<T>::value>> {
656-
using R = rel_ret_t<T>;
694+
using R = internal_rel_ret_t<T>;
657695
#ifdef __SYCL_DEVICE_ONLY__
658696
using value_t = bool;
659697
#else

0 commit comments

Comments
 (0)