Skip to content

Commit 137fd1f

Browse files
steffenlarsensmanna12
authored andcommitted
[SYCL][ABI-Break] Fold host_half_impl::half into half_impl::half (intel#13597)
This commit folds the implementation of host_half_impl::half into half_impl::half and making the vector element representation the same as the half representation. This allows us to avoid strict alias violation for half vectors in their operator[] implementations. Note that this is marked as an ABI break as it removes symbols on Windows, despite these symbols never being in the library. --------- Signed-off-by: Larsen, Steffen <[email protected]>
1 parent 3657bd9 commit 137fd1f

File tree

6 files changed

+95
-161
lines changed

6 files changed

+95
-161
lines changed

sycl/include/sycl/ext/intel/esimd/detail/half_type_traits.hpp

Lines changed: 1 addition & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -21,16 +21,11 @@ inline namespace _V1 {
2121
namespace ext::intel::esimd::detail {
2222

2323
// Standalone definitions to use w/o instantiating element_type_traits.
24-
#ifdef __SYCL_DEVICE_ONLY__
25-
// Can't use sycl::detail::half_impl::StorageT as RawT for both host and
26-
// device as it still maps to struct on/ host (even though the struct is a
27-
// trivial wrapper around uint16_t), and for ESIMD we need a type which can be
28-
// an element of clang vector.
2924
using half_raw_type = sycl::detail::half_impl::StorageT;
25+
#ifdef __SYCL_DEVICE_ONLY__
3026
// On device, _Float16 is native Cpp type, so it is the enclosing C++ type
3127
using half_enclosing_cpp_type = half_raw_type;
3228
#else
33-
using half_raw_type = uint16_t;
3429
using half_enclosing_cpp_type = float;
3530
#endif // __SYCL_DEVICE_ONLY__
3631

@@ -86,11 +81,7 @@ template <int N> struct vector_conversion_traits<sycl::half, N> {
8681
class WrapperElementTypeProxy {
8782
public:
8883
static ESIMD_INLINE half_raw_type bitcast_to_raw_scalar(sycl::half Val) {
89-
#ifdef __SYCL_DEVICE_ONLY__
9084
return Val.Data;
91-
#else
92-
return Val.Data.Buf;
93-
#endif // __SYCL_DEVICE_ONLY__
9485
}
9586

9687
static ESIMD_INLINE sycl::half bitcast_to_wrapper_scalar(half_raw_type Val) {

sycl/include/sycl/half_type.hpp

Lines changed: 90 additions & 107 deletions
Original file line numberDiff line numberDiff line change
@@ -144,93 +144,14 @@ inline __SYCL_CONSTEXPR_HALF float half2Float(const uint16_t &Val) {
144144
return Result;
145145
}
146146

147-
namespace host_half_impl {
148-
149-
// The main host half class
150-
class __SYCL_EXPORT half {
151-
public:
152-
half() = default;
153-
constexpr half(const half &) = default;
154-
constexpr half(half &&) = default;
155-
156-
__SYCL_CONSTEXPR_HALF half(const float &rhs) : Buf(float2Half(rhs)) {}
157-
158-
constexpr half &operator=(const half &rhs) = default;
159-
160-
// Operator +=, -=, *=, /=
161-
__SYCL_CONSTEXPR_HALF half &operator+=(const half &rhs) {
162-
*this = operator float() + static_cast<float>(rhs);
163-
return *this;
164-
}
165-
166-
__SYCL_CONSTEXPR_HALF half &operator-=(const half &rhs) {
167-
*this = operator float() - static_cast<float>(rhs);
168-
return *this;
169-
}
170-
171-
__SYCL_CONSTEXPR_HALF half &operator*=(const half &rhs) {
172-
*this = operator float() * static_cast<float>(rhs);
173-
return *this;
174-
}
175-
176-
__SYCL_CONSTEXPR_HALF half &operator/=(const half &rhs) {
177-
*this = operator float() / static_cast<float>(rhs);
178-
return *this;
179-
}
180-
181-
// Operator ++, --
182-
__SYCL_CONSTEXPR_HALF half &operator++() {
183-
*this += 1;
184-
return *this;
185-
}
186-
187-
__SYCL_CONSTEXPR_HALF half operator++(int) {
188-
half ret(*this);
189-
operator++();
190-
return ret;
191-
}
192-
193-
__SYCL_CONSTEXPR_HALF half &operator--() {
194-
*this -= 1;
195-
return *this;
196-
}
197-
198-
__SYCL_CONSTEXPR_HALF half operator--(int) {
199-
half ret(*this);
200-
operator--();
201-
return ret;
202-
}
203-
204-
// Operator neg
205-
constexpr half &operator-() {
206-
Buf ^= 0x8000;
207-
return *this;
208-
}
209-
210-
// Operator float
211-
__SYCL_CONSTEXPR_HALF operator float() const { return half2Float(Buf); }
212-
213-
template <typename Key> friend struct std::hash;
214-
215-
// Initialize underlying data
216-
constexpr explicit half(uint16_t x) : Buf(x) {}
217-
218-
friend class sycl::ext::intel::esimd::detail::WrapperElementTypeProxy;
219-
220-
private:
221-
uint16_t Buf;
222-
};
223-
224-
} // namespace host_half_impl
225-
226147
namespace half_impl {
227148
class half;
228149

229150
// Several aliases are defined below:
230151
// - StorageT: actual representation of half data type. It is used by scalar
231152
// half values. On device side, it points to some native half data type, while
232-
// on host some custom data type is used to emulate operations of 16-bit
233-
// floating-point values
153+
// on host it is represented by a 16-bit integer that the implementation
154+
// manipulates to emulate half-precision floating-point behavior.
234155
//
235156
// - BIsRepresentationT: data type which is used by built-in functions. It is
236157
// distinguished from StorageT, because on host, we can still operate on the
@@ -258,7 +179,7 @@ using Vec16StorageT = VecElemT __attribute__((ext_vector_type(16)));
258179
#endif // __INTEL_PREVIEW_BREAKING_CHANGES
259180

260181
#else // SYCL_DEVICE_ONLY
261-
using StorageT = detail::host_half_impl::half;
182+
using StorageT = uint16_t;
262183
// No need to extract underlying data type for built-in functions operating on
263184
// host
264185
using BIsRepresentationT = half;
@@ -278,6 +199,12 @@ using Vec16StorageT = std::array<VecElemT, 16>;
278199

279200
#endif // SYCL_DEVICE_ONLY
280201

202+
// Creation token to disambiguate constructors.
203+
struct RawHostHalfToken {
204+
constexpr explicit RawHostHalfToken(uint16_t Val) : Value{Val} {}
205+
uint16_t Value;
206+
};
207+
281208
#ifndef __SYCL_DEVICE_ONLY__
282209
class half {
283210
#else
@@ -288,18 +215,16 @@ class [[__sycl_detail__::__uses_aspects__(aspect::fp16)]] half {
288215
constexpr half(const half &) = default;
289216
constexpr half(half &&) = default;
290217

218+
#ifdef __SYCL_DEVICE_ONLY__
291219
__SYCL_CONSTEXPR_HALF half(const float &rhs) : Data(rhs) {}
220+
#else
221+
__SYCL_CONSTEXPR_HALF half(const float &rhs) : Data(float2Half(rhs)) {}
222+
#endif // __SYCL_DEVICE_ONLY__
292223

293224
constexpr half &operator=(const half &rhs) = default;
294225

295-
#ifndef __SYCL_DEVICE_ONLY__
296-
// Since StorageT and BIsRepresentationT are different on host, these two
297-
// helpers are required for 'vec' class
298-
constexpr half(const detail::host_half_impl::half &rhs) : Data(rhs) {}
299-
constexpr operator detail::host_half_impl::half() const { return Data; }
300-
#endif // __SYCL_DEVICE_ONLY__
301-
302226
// Operator +=, -=, *=, /=
227+
#ifdef __SYCL_DEVICE_ONLY__
303228
__SYCL_CONSTEXPR_HALF half &operator+=(const half &rhs) {
304229
Data += rhs.Data;
305230
return *this;
@@ -319,6 +244,27 @@ class [[__sycl_detail__::__uses_aspects__(aspect::fp16)]] half {
319244
Data /= rhs.Data;
320245
return *this;
321246
}
247+
#else
248+
__SYCL_CONSTEXPR_HALF half &operator+=(const half &rhs) {
249+
*this = operator float() + static_cast<float>(rhs);
250+
return *this;
251+
}
252+
253+
__SYCL_CONSTEXPR_HALF half &operator-=(const half &rhs) {
254+
*this = operator float() - static_cast<float>(rhs);
255+
return *this;
256+
}
257+
258+
__SYCL_CONSTEXPR_HALF half &operator*=(const half &rhs) {
259+
*this = operator float() * static_cast<float>(rhs);
260+
return *this;
261+
}
262+
263+
__SYCL_CONSTEXPR_HALF half &operator/=(const half &rhs) {
264+
*this = operator float() / static_cast<float>(rhs);
265+
return *this;
266+
}
267+
#endif // __SYCL_DEVICE_ONLY__
322268

323269
// Operator ++, --
324270
__SYCL_CONSTEXPR_HALF half &operator++() {
@@ -342,9 +288,17 @@ class [[__sycl_detail__::__uses_aspects__(aspect::fp16)]] half {
342288
operator--();
343289
return ret;
344290
}
291+
292+
// Operator neg
293+
#ifdef __SYCL_DEVICE_ONLY__
345294
__SYCL_CONSTEXPR_HALF friend half operator-(const half other) {
346295
return half(-other.Data);
347296
}
297+
#else
298+
__SYCL_CONSTEXPR_HALF friend half operator-(const half other) {
299+
return half(RawHostHalfToken(other.Data ^ 0x8000));
300+
}
301+
#endif // __SYCL_DEVICE_ONLY__
348302

349303
// Operator +, -, *, /
350304
#define OP(op, op_eq) \
@@ -461,71 +415,71 @@ class [[__sycl_detail__::__uses_aspects__(aspect::fp16)]] half {
461415
#define OP(op) \
462416
__SYCL_CONSTEXPR_HALF friend bool operator op(const half &lhs, \
463417
const half &rhs) { \
464-
return lhs.Data op rhs.Data; \
418+
return lhs.getFPRep() op rhs.getFPRep(); \
465419
} \
466420
__SYCL_CONSTEXPR_HALF friend bool operator op(const half &lhs, \
467421
const double &rhs) { \
468-
return lhs.Data op rhs; \
422+
return lhs.getFPRep() op rhs; \
469423
} \
470424
__SYCL_CONSTEXPR_HALF friend bool operator op(const double &lhs, \
471425
const half &rhs) { \
472-
return lhs op rhs.Data; \
426+
return lhs op rhs.getFPRep(); \
473427
} \
474428
__SYCL_CONSTEXPR_HALF friend bool operator op(const half &lhs, \
475429
const float &rhs) { \
476-
return lhs.Data op rhs; \
430+
return lhs.getFPRep() op rhs; \
477431
} \
478432
__SYCL_CONSTEXPR_HALF friend bool operator op(const float &lhs, \
479433
const half &rhs) { \
480-
return lhs op rhs.Data; \
434+
return lhs op rhs.getFPRep(); \
481435
} \
482436
__SYCL_CONSTEXPR_HALF friend bool operator op(const half &lhs, \
483437
const int &rhs) { \
484-
return lhs.Data op rhs; \
438+
return lhs.getFPRep() op rhs; \
485439
} \
486440
__SYCL_CONSTEXPR_HALF friend bool operator op(const int &lhs, \
487441
const half &rhs) { \
488-
return lhs op rhs.Data; \
442+
return lhs op rhs.getFPRep(); \
489443
} \
490444
__SYCL_CONSTEXPR_HALF friend bool operator op(const half &lhs, \
491445
const long &rhs) { \
492-
return lhs.Data op rhs; \
446+
return lhs.getFPRep() op rhs; \
493447
} \
494448
__SYCL_CONSTEXPR_HALF friend bool operator op(const long &lhs, \
495449
const half &rhs) { \
496-
return lhs op rhs.Data; \
450+
return lhs op rhs.getFPRep(); \
497451
} \
498452
__SYCL_CONSTEXPR_HALF friend bool operator op(const half &lhs, \
499453
const long long &rhs) { \
500-
return lhs.Data op rhs; \
454+
return lhs.getFPRep() op rhs; \
501455
} \
502456
__SYCL_CONSTEXPR_HALF friend bool operator op(const long long &lhs, \
503457
const half &rhs) { \
504-
return lhs op rhs.Data; \
458+
return lhs op rhs.getFPRep(); \
505459
} \
506460
__SYCL_CONSTEXPR_HALF friend bool operator op(const half &lhs, \
507461
const unsigned int &rhs) { \
508-
return lhs.Data op rhs; \
462+
return lhs.getFPRep() op rhs; \
509463
} \
510464
__SYCL_CONSTEXPR_HALF friend bool operator op(const unsigned int &lhs, \
511465
const half &rhs) { \
512-
return lhs op rhs.Data; \
466+
return lhs op rhs.getFPRep(); \
513467
} \
514468
__SYCL_CONSTEXPR_HALF friend bool operator op(const half &lhs, \
515469
const unsigned long &rhs) { \
516-
return lhs.Data op rhs; \
470+
return lhs.getFPRep() op rhs; \
517471
} \
518472
__SYCL_CONSTEXPR_HALF friend bool operator op(const unsigned long &lhs, \
519473
const half &rhs) { \
520-
return lhs op rhs.Data; \
474+
return lhs op rhs.getFPRep(); \
521475
} \
522476
__SYCL_CONSTEXPR_HALF friend bool operator op( \
523477
const half &lhs, const unsigned long long &rhs) { \
524-
return lhs.Data op rhs; \
478+
return lhs.getFPRep() op rhs; \
525479
} \
526480
__SYCL_CONSTEXPR_HALF friend bool operator op(const unsigned long long &lhs, \
527481
const half &rhs) { \
528-
return lhs op rhs.Data; \
482+
return lhs op rhs.getFPRep(); \
529483
}
530484
OP(==)
531485
OP(!=)
@@ -537,9 +491,13 @@ class [[__sycl_detail__::__uses_aspects__(aspect::fp16)]] half {
537491
#undef OP
538492

539493
// Operator float
494+
#ifdef __SYCL_DEVICE_ONLY__
540495
__SYCL_CONSTEXPR_HALF operator float() const {
541496
return static_cast<float>(Data);
542497
}
498+
#else
499+
__SYCL_CONSTEXPR_HALF operator float() const { return half2Float(Data); }
500+
#endif // __SYCL_DEVICE_ONLY__
543501

544502
// Operator << and >>
545503
inline friend std::ostream &operator<<(std::ostream &O,
@@ -560,8 +518,32 @@ class [[__sycl_detail__::__uses_aspects__(aspect::fp16)]] half {
560518
friend class sycl::ext::intel::esimd::detail::WrapperElementTypeProxy;
561519

562520
private:
521+
// When doing operations, we cannot simply work with Data on host as
522+
// it is an integer. Instead, convert it to float. On device we can work with
523+
// Data as it is already a floating point representation.
524+
#ifdef __SYCL_DEVICE_ONLY__
525+
__SYCL_CONSTEXPR_HALF StorageT getFPRep() const { return Data; }
526+
#else
527+
__SYCL_CONSTEXPR_HALF float getFPRep() const { return operator float(); }
528+
#endif
529+
530+
#ifndef __SYCL_DEVICE_ONLY__
531+
// Because sycl::bit_cast might not be constexpr on certain systems,
532+
// implementation needs shortcut for creating a host sycl::half directly from
533+
// a uint16_t representation.
534+
constexpr explicit half(RawHostHalfToken X) : Data(X.Value) {}
535+
536+
friend constexpr inline half CreateHostHalfRaw(uint16_t X);
537+
#endif // __SYCL_DEVICE_ONLY__
538+
563539
StorageT Data;
564540
};
541+
542+
#ifndef __SYCL_DEVICE_ONLY__
543+
constexpr inline half CreateHostHalfRaw(uint16_t X) {
544+
return half(RawHostHalfToken(X));
545+
}
546+
#endif // __SYCL_DEVICE_ONLY__
565547
} // namespace half_impl
566548

567549
// According to the C++ standard, math functions from cmath/math.h should work
@@ -644,7 +626,8 @@ template <> struct numeric_limits<sycl::half> {
644626
#ifdef __SYCL_DEVICE_ONLY__
645627
return __builtin_huge_valf();
646628
#else
647-
return sycl::detail::host_half_impl::half(static_cast<uint16_t>(0x7C00));
629+
return sycl::detail::half_impl::CreateHostHalfRaw(
630+
static_cast<uint16_t>(0x7C00));
648631
#endif
649632
}
650633

sycl/include/sycl/known_identity.hpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -187,7 +187,7 @@ struct known_identity_impl<
187187
#ifdef __SYCL_DEVICE_ONLY__
188188
0;
189189
#else
190-
sycl::detail::host_half_impl::half(static_cast<uint16_t>(0));
190+
sycl::detail::half_impl::CreateHostHalfRaw(static_cast<uint16_t>(0));
191191
#endif
192192
};
193193

@@ -227,7 +227,7 @@ struct known_identity_impl<
227227
#ifdef __SYCL_DEVICE_ONLY__
228228
1;
229229
#else
230-
sycl::detail::host_half_impl::half(static_cast<uint16_t>(0x3C00));
230+
sycl::detail::half_impl::CreateHostHalfRaw(static_cast<uint16_t>(0x3C00));
231231
#endif
232232
};
233233

0 commit comments

Comments
 (0)