@@ -144,93 +144,14 @@ inline __SYCL_CONSTEXPR_HALF float half2Float(const uint16_t &Val) {
144
144
return Result;
145
145
}
146
146
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
-
226
147
namespace half_impl {
227
148
class half ;
228
149
229
150
// Several aliases are defined below:
230
151
// - StorageT: actual representation of half data type. It is used by scalar
231
152
// 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.
234
155
//
235
156
// - BIsRepresentationT: data type which is used by built-in functions. It is
236
157
// distinguished from StorageT, because on host, we can still operate on the
@@ -258,7 +179,7 @@ using Vec16StorageT = VecElemT __attribute__((ext_vector_type(16)));
258
179
#endif // __INTEL_PREVIEW_BREAKING_CHANGES
259
180
260
181
#else // SYCL_DEVICE_ONLY
261
- using StorageT = detail::host_half_impl::half ;
182
+ using StorageT = uint16_t ;
262
183
// No need to extract underlying data type for built-in functions operating on
263
184
// host
264
185
using BIsRepresentationT = half;
@@ -278,6 +199,12 @@ using Vec16StorageT = std::array<VecElemT, 16>;
278
199
279
200
#endif // SYCL_DEVICE_ONLY
280
201
202
+ // Creation token to disambiguate constructors.
203
+ struct RawHostHalfToken {
204
+ constexpr explicit RawHostHalfToken (uint16_t Val) : Value{Val} {}
205
+ uint16_t Value;
206
+ };
207
+
281
208
#ifndef __SYCL_DEVICE_ONLY__
282
209
class half {
283
210
#else
@@ -288,18 +215,16 @@ class [[__sycl_detail__::__uses_aspects__(aspect::fp16)]] half {
288
215
constexpr half (const half &) = default ;
289
216
constexpr half (half &&) = default ;
290
217
218
+ #ifdef __SYCL_DEVICE_ONLY__
291
219
__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__
292
223
293
224
constexpr half &operator =(const half &rhs) = default ;
294
225
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
-
302
226
// Operator +=, -=, *=, /=
227
+ #ifdef __SYCL_DEVICE_ONLY__
303
228
__SYCL_CONSTEXPR_HALF half &operator +=(const half &rhs) {
304
229
Data += rhs.Data ;
305
230
return *this ;
@@ -319,6 +244,27 @@ class [[__sycl_detail__::__uses_aspects__(aspect::fp16)]] half {
319
244
Data /= rhs.Data ;
320
245
return *this ;
321
246
}
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__
322
268
323
269
// Operator ++, --
324
270
__SYCL_CONSTEXPR_HALF half &operator ++() {
@@ -342,9 +288,17 @@ class [[__sycl_detail__::__uses_aspects__(aspect::fp16)]] half {
342
288
operator --();
343
289
return ret;
344
290
}
291
+
292
+ // Operator neg
293
+ #ifdef __SYCL_DEVICE_ONLY__
345
294
__SYCL_CONSTEXPR_HALF friend half operator -(const half other) {
346
295
return half (-other.Data );
347
296
}
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__
348
302
349
303
// Operator +, -, *, /
350
304
#define OP (op, op_eq ) \
@@ -461,71 +415,71 @@ class [[__sycl_detail__::__uses_aspects__(aspect::fp16)]] half {
461
415
#define OP (op ) \
462
416
__SYCL_CONSTEXPR_HALF friend bool operator op (const half &lhs, \
463
417
const half &rhs) { \
464
- return lhs.Data op rhs.Data ; \
418
+ return lhs.getFPRep () op rhs.getFPRep (); \
465
419
} \
466
420
__SYCL_CONSTEXPR_HALF friend bool operator op (const half &lhs, \
467
421
const double &rhs) { \
468
- return lhs.Data op rhs; \
422
+ return lhs.getFPRep () op rhs; \
469
423
} \
470
424
__SYCL_CONSTEXPR_HALF friend bool operator op (const double &lhs, \
471
425
const half &rhs) { \
472
- return lhs op rhs.Data ; \
426
+ return lhs op rhs.getFPRep (); \
473
427
} \
474
428
__SYCL_CONSTEXPR_HALF friend bool operator op (const half &lhs, \
475
429
const float &rhs) { \
476
- return lhs.Data op rhs; \
430
+ return lhs.getFPRep () op rhs; \
477
431
} \
478
432
__SYCL_CONSTEXPR_HALF friend bool operator op (const float &lhs, \
479
433
const half &rhs) { \
480
- return lhs op rhs.Data ; \
434
+ return lhs op rhs.getFPRep (); \
481
435
} \
482
436
__SYCL_CONSTEXPR_HALF friend bool operator op (const half &lhs, \
483
437
const int &rhs) { \
484
- return lhs.Data op rhs; \
438
+ return lhs.getFPRep () op rhs; \
485
439
} \
486
440
__SYCL_CONSTEXPR_HALF friend bool operator op (const int &lhs, \
487
441
const half &rhs) { \
488
- return lhs op rhs.Data ; \
442
+ return lhs op rhs.getFPRep (); \
489
443
} \
490
444
__SYCL_CONSTEXPR_HALF friend bool operator op (const half &lhs, \
491
445
const long &rhs) { \
492
- return lhs.Data op rhs; \
446
+ return lhs.getFPRep () op rhs; \
493
447
} \
494
448
__SYCL_CONSTEXPR_HALF friend bool operator op (const long &lhs, \
495
449
const half &rhs) { \
496
- return lhs op rhs.Data ; \
450
+ return lhs op rhs.getFPRep (); \
497
451
} \
498
452
__SYCL_CONSTEXPR_HALF friend bool operator op (const half &lhs, \
499
453
const long long &rhs) { \
500
- return lhs.Data op rhs; \
454
+ return lhs.getFPRep () op rhs; \
501
455
} \
502
456
__SYCL_CONSTEXPR_HALF friend bool operator op (const long long &lhs, \
503
457
const half &rhs) { \
504
- return lhs op rhs.Data ; \
458
+ return lhs op rhs.getFPRep (); \
505
459
} \
506
460
__SYCL_CONSTEXPR_HALF friend bool operator op (const half &lhs, \
507
461
const unsigned int &rhs) { \
508
- return lhs.Data op rhs; \
462
+ return lhs.getFPRep () op rhs; \
509
463
} \
510
464
__SYCL_CONSTEXPR_HALF friend bool operator op (const unsigned int &lhs, \
511
465
const half &rhs) { \
512
- return lhs op rhs.Data ; \
466
+ return lhs op rhs.getFPRep (); \
513
467
} \
514
468
__SYCL_CONSTEXPR_HALF friend bool operator op (const half &lhs, \
515
469
const unsigned long &rhs) { \
516
- return lhs.Data op rhs; \
470
+ return lhs.getFPRep () op rhs; \
517
471
} \
518
472
__SYCL_CONSTEXPR_HALF friend bool operator op (const unsigned long &lhs, \
519
473
const half &rhs) { \
520
- return lhs op rhs.Data ; \
474
+ return lhs op rhs.getFPRep (); \
521
475
} \
522
476
__SYCL_CONSTEXPR_HALF friend bool operator op ( \
523
477
const half &lhs, const unsigned long long &rhs) { \
524
- return lhs.Data op rhs; \
478
+ return lhs.getFPRep () op rhs; \
525
479
} \
526
480
__SYCL_CONSTEXPR_HALF friend bool operator op (const unsigned long long &lhs, \
527
481
const half &rhs) { \
528
- return lhs op rhs.Data ; \
482
+ return lhs op rhs.getFPRep (); \
529
483
}
530
484
OP (==)
531
485
OP (!=)
@@ -537,9 +491,13 @@ class [[__sycl_detail__::__uses_aspects__(aspect::fp16)]] half {
537
491
#undef OP
538
492
539
493
// Operator float
494
+ #ifdef __SYCL_DEVICE_ONLY__
540
495
__SYCL_CONSTEXPR_HALF operator float () const {
541
496
return static_cast <float >(Data);
542
497
}
498
+ #else
499
+ __SYCL_CONSTEXPR_HALF operator float () const { return half2Float (Data); }
500
+ #endif // __SYCL_DEVICE_ONLY__
543
501
544
502
// Operator << and >>
545
503
inline friend std::ostream &operator <<(std::ostream &O,
@@ -560,8 +518,32 @@ class [[__sycl_detail__::__uses_aspects__(aspect::fp16)]] half {
560
518
friend class sycl ::ext::intel::esimd::detail::WrapperElementTypeProxy;
561
519
562
520
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
+
563
539
StorageT Data;
564
540
};
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__
565
547
} // namespace half_impl
566
548
567
549
// According to the C++ standard, math functions from cmath/math.h should work
@@ -644,7 +626,8 @@ template <> struct numeric_limits<sycl::half> {
644
626
#ifdef __SYCL_DEVICE_ONLY__
645
627
return __builtin_huge_valf ();
646
628
#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 ));
648
631
#endif
649
632
}
650
633
0 commit comments