DPC++ Runtime
Runtime libraries for oneAPI DPC++
half_type_traits.hpp
Go to the documentation of this file.
1 //==-------------- half_type_traits.hpp - DPC++ Explicit SIMD API ----------==//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 // Implementation of SIMD element type traits for the sycl::half type.
9 //===----------------------------------------------------------------------===//
10 
11 #pragma once
12 
14 
15 #include <sycl/half_type.hpp>
16 
18 
19 namespace sycl {
20 inline namespace _V1 {
21 namespace ext::intel::esimd::detail {
22 
23 // 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.
29 using half_raw_type = sycl::detail::half_impl::StorageT;
30 // On device, _Float16 is native Cpp type, so it is the enclosing C++ type
31 using half_enclosing_cpp_type = half_raw_type;
32 #else
33 using half_raw_type = uint16_t;
34 using half_enclosing_cpp_type = float;
35 #endif // __SYCL_DEVICE_ONLY__
36 
37 template <> struct element_type_traits<sycl::half> {
38  using RawT = half_raw_type;
39  using EnclosingCppT = half_enclosing_cpp_type;
40 #ifdef __SYCL_DEVICE_ONLY__
41  // On device, operations on half are translated to operations on _Float16,
42  // which is natively supported by the device compiler
43  static constexpr bool use_native_cpp_ops = true;
44 #else
45  // On host, we can't use native Cpp '+', '-' etc. over uint16_t to emulate the
46  // operations on half type.
47  static constexpr bool use_native_cpp_ops = false;
48 #endif // __SYCL_DEVICE_ONLY__
49 
50  static constexpr bool is_floating_point = true;
51 };
52 
53 // ------------------- Type conversion traits
54 
55 template <int N> struct vector_conversion_traits<sycl::half, N> {
56  using StdT = half_enclosing_cpp_type;
57  using RawT = half_raw_type;
58 
59  static ESIMD_INLINE vector_type_t<RawT, N>
60  convert_to_raw(vector_type_t<StdT, N> Val)
61 #ifdef __SYCL_DEVICE_ONLY__
62  // use_native_cpp_ops trait is true, so must not be implemented
63  ;
64 #else
65  {
66  __ESIMD_UNSUPPORTED_ON_HOST;
67  }
68 #endif // __SYCL_DEVICE_ONLY__
69 
70  static ESIMD_INLINE vector_type_t<StdT, N>
71  convert_to_cpp(vector_type_t<RawT, N> Val)
72 #ifdef __SYCL_DEVICE_ONLY__
73  // use_native_cpp_ops trait is true, so must not be implemented
74  ;
75 #else
76  {
77  __ESIMD_UNSUPPORTED_ON_HOST;
78  }
79 #endif // __SYCL_DEVICE_ONLY__
80 };
81 
82 // Proxy class to access bit representation of a wrapper type both on host and
83 // device. Declared as friend to the sycl::half.
84 // TODO add this functionality to sycl type implementation? With C++20,
85 // std::bit_cast should be a good replacement.
86 class WrapperElementTypeProxy {
87 public:
88  static ESIMD_INLINE half_raw_type bitcast_to_raw_scalar(sycl::half Val) {
89 #ifdef __SYCL_DEVICE_ONLY__
90  return Val.Data;
91 #else
92  return Val.Data.Buf;
93 #endif // __SYCL_DEVICE_ONLY__
94  }
95 
96  static ESIMD_INLINE sycl::half bitcast_to_wrapper_scalar(half_raw_type Val) {
97 #ifndef __SYCL_DEVICE_ONLY__
98  __ESIMD_UNSUPPORTED_ON_HOST;
99 #else
100  sycl::half Res;
101  Res.Data = Val;
102  return Res;
103 #endif // __SYCL_DEVICE_ONLY__
104  }
105 };
106 
107 template <> struct scalar_conversion_traits<sycl::half> {
108  using RawT = half_raw_type;
109 
110  static ESIMD_INLINE RawT bitcast_to_raw(sycl::half Val) {
111  return WrapperElementTypeProxy::bitcast_to_raw_scalar(Val);
112  }
113 
114  static ESIMD_INLINE sycl::half bitcast_to_wrapper(RawT Val) {
115  return WrapperElementTypeProxy::bitcast_to_wrapper_scalar(Val);
116  }
117 };
118 
119 #ifdef __SYCL_DEVICE_ONLY__
120 template <>
121 struct is_esimd_arithmetic_type<half_raw_type, void> : std::true_type {};
122 #endif // __SYCL_DEVICE_ONLY__
123 
124 template <>
125 struct is_esimd_arithmetic_type<sycl::half, void> : std::true_type {};
126 
127 // Misc
128 inline std::ostream &operator<<(std::ostream &O, sycl::half const &rhs) {
129  O << static_cast<float>(rhs);
130  return O;
131 }
132 
133 inline std::istream &operator>>(std::istream &I, sycl::half &rhs) {
134  float ValFloat = 0.0f;
135  I >> ValFloat;
136  rhs = ValFloat;
137  return I;
138 }
139 
140 } // namespace ext::intel::esimd::detail
141 } // namespace _V1
142 } // namespace sycl
143 
detail::host_half_impl::half StorageT
Definition: half_type.hpp:253
auto operator>>(const __ESIMD_DNS::simd_obj_impl< __raw_t< T1 >, N, SimdT< T1, N >> &LHS, const __ESIMD_DNS::simd_obj_impl< __raw_t< T2 >, N, SimdT< T2, N >> &RHS)
Definition: operators.hpp:179
auto operator<<(const __ESIMD_DNS::simd_obj_impl< __raw_t< T1 >, N, SimdT< T1, N >> &LHS, const __ESIMD_DNS::simd_obj_impl< __raw_t< T2 >, N, SimdT< T2, N >> &RHS)
Definition: operators.hpp:178
sycl::detail::half_impl::half half
Definition: aliases.hpp:101
Definition: access.hpp:18