native 0.0.1
Vectors, masks and wide register packs for C++26
Loading...
Searching...
No Matches
native.x86.f16c.ccm
1// SPDX-License-Identifier: BSD-2-Clause OR Apache-2.0
2module;
3#include "native/isa_import.h"
4#include "native/x86/f16c.h"
5#include "native/detail/constexpr_float.h"
6#include "native/targets.h"
7export module native.x86.f16c;
8export import native.x86.features;
9export import native.simd;
10// SPDX-License-Identifier: BSD-2-Clause OR Apache-2.0
11#if NATIVE_HOST_X86 || defined(NATIVE_DOXYGEN)
12namespace native::detail {
13 template<unsigned Imm8> constexpr auto f16c_rounding() noexcept {
14 using r=constexpr_float::rounding;
15 if constexpr(Imm8&4) return r::nearest_even;
16 else if constexpr((Imm8&3)==1) return r::downward;
17 else if constexpr((Imm8&3)==2) return r::upward;
18 else if constexpr((Imm8&3)==3) return r::toward_zero;
19 else return r::nearest_even;
20 }
21 template<isa<x86> Arch,unsigned Imm8,std::size_t N>
22 consteval simd<fp16,N,Arch> f16c_narrow(simd<float,N,Arch> input) noexcept {
23 std::array<float,N> values{};input.store(values.data());
24 auto source=std::bit_cast<std::array<std::uint32_t,N>>(values);
25 std::array<std::uint16_t,N> result{};
26 for(std::size_t i=0;i<N;++i) result[i]=constexpr_float::convert_bits<
27 constexpr_float::binary16,constexpr_float::binary32>(source[i],f16c_rounding<Imm8>());
28 return simd<fp16,N,Arch>::load_bits(result.data());
29 }
30 template<isa<x86> Arch,std::size_t N>
31 consteval simd<float,N,Arch> f16c_widen(simd<fp16,N,Arch> input) noexcept {
32 std::array<std::uint16_t,N> source{};
33 std::array<std::uint32_t,N> result{};
34 input.store_bits(source.data());
35 for(std::size_t i=0;i<N;++i) result[i]=constexpr_float::convert_bits<
36 constexpr_float::binary32,constexpr_float::binary16>(source[i]);
37 auto values=std::bit_cast<std::array<float,N>>(result);
38 return simd<float,N,Arch>::load(values.data());
39 }
40}
41export namespace native {
68
70 template<isa<x86> Arch, unsigned Imm8>
71 requires(Arch.has(x86_feature::f16c) && Imm8 <= 255)
73 simd<fp16, 4, Arch> cvtps_ph(simd<float, 4, Arch> a) noexcept {
74 if consteval { return detail::f16c_narrow<Arch,Imm8>(a); } else {
75 // VCVTPS2PH zeroes the unused high half of its destination.
77 detail::x86_f16c::cvtps_ph<Arch, Imm8>(a.to_native()));
78 }
79 }
80
82 template<isa<x86> Arch, unsigned Imm8>
83 requires(requires { sizeof(simd<float,4,Arch>); sizeof(simd<fp16,4,Arch>); } && !Arch.has(x86_feature::f16c) && Imm8 <= 255)
84 native_nodiscard consteval
86 return detail::f16c_narrow<Arch,Imm8>(a);
87 }
88
90 template<isa<x86> Arch, unsigned Imm8>
91 requires(Arch.has(x86_feature::f16c) && Imm8 <= 255)
94 if consteval { return detail::f16c_narrow<Arch,Imm8>(a); } else {
96 detail::x86_f16c::cvtps_ph<Arch, Imm8>(a.to_native()));
97 }
98 }
99
101 template<isa<x86> Arch, unsigned Imm8>
102 requires(requires { sizeof(simd<float,8,Arch>); sizeof(simd<fp16,8,Arch>); } && !Arch.has(x86_feature::f16c) && Imm8 <= 255)
103 native_nodiscard consteval
105 return detail::f16c_narrow<Arch,Imm8>(a);
106 }
107
109 template<isa<x86> Arch, unsigned Lanes>
110 requires(Arch.has(x86_feature::f16c) && Lanes == 4)
113 if consteval { return detail::f16c_widen<Arch>(a); } else {
115 detail::x86_f16c::cvtph_ps<Arch, 4>(a.to_native()));
116 }
117 }
118
120 template<isa<x86> Arch, unsigned Lanes>
121 requires(requires { sizeof(simd<float,4,Arch>); sizeof(simd<fp16,4,Arch>); } && !Arch.has(x86_feature::f16c) && Lanes == 4)
122 native_nodiscard consteval
124 return detail::f16c_widen<Arch>(a);
125 }
126
128 template<isa<x86> Arch, unsigned Lanes>
129 requires(Arch.has(x86_feature::f16c) && Lanes == 8)
132 if consteval { return detail::f16c_widen<Arch>(a); } else {
134 detail::x86_f16c::cvtph_ps<Arch, 8>(a.to_native()));
135 }
136 }
137
139 template<isa<x86> Arch, unsigned Lanes>
140 requires(requires { sizeof(simd<float,8,Arch>); sizeof(simd<fp16,8,Arch>); } && !Arch.has(x86_feature::f16c) && Lanes == 8)
141 native_nodiscard consteval
143 return detail::f16c_widen<Arch>(a);
144 }
145
147 template<isa<x86> Arch, unsigned Imm8>
148 requires(Arch.has(x86_feature::f16c) && Imm8 <= 255)
150 std::uint16_t cvtss_sh(float a) noexcept {
151 if consteval { return detail::constexpr_float::convert_bits<detail::constexpr_float::binary16,
152 detail::constexpr_float::binary32>(std::bit_cast<std::uint32_t>(a),detail::f16c_rounding<Imm8>()); } else {
153 return detail::x86_f16c::cvtss_sh<Arch, Imm8>(a);
154 }
155 }
156
158 template<isa<x86> Arch, unsigned Imm8>
159 requires(!Arch.has(x86_feature::f16c) && Imm8 <= 255)
160 native_nodiscard consteval
161 std::uint16_t cvtss_sh(float a) noexcept {
162 return detail::constexpr_float::convert_bits<detail::constexpr_float::binary16,
163 detail::constexpr_float::binary32>(std::bit_cast<std::uint32_t>(a),detail::f16c_rounding<Imm8>());
164 }
165
168 template<unsigned Imm8, isa<x86> Arch = NATIVE_BASELINE>
169 requires(Arch.has(x86_feature::f16c) && Imm8 <= 255)
171 std::uint16_t cvtss_sh(float a) noexcept {
172 if consteval { return detail::constexpr_float::convert_bits<detail::constexpr_float::binary16,
173 detail::constexpr_float::binary32>(std::bit_cast<std::uint32_t>(a),detail::f16c_rounding<Imm8>()); } else {
174 return cvtss_sh<Arch, Imm8>(a);
175 }
176 }
177
179 template<unsigned Imm8, isa<x86> Arch = NATIVE_BASELINE>
180 requires(!Arch.has(x86_feature::f16c) && Imm8 <= 255)
181 native_nodiscard consteval
182 std::uint16_t cvtss_sh(float a) noexcept {
183 return detail::constexpr_float::convert_bits<detail::constexpr_float::binary16,
184 detail::constexpr_float::binary32>(std::bit_cast<std::uint32_t>(a),detail::f16c_rounding<Imm8>());
185 }
186
188 template<isa<x86> Arch = NATIVE_BASELINE> requires(Arch.has(x86_feature::f16c))
190 float cvtsh_ss(std::uint16_t a) noexcept {
191 if consteval { return std::bit_cast<float>(detail::constexpr_float::convert_bits<
192 detail::constexpr_float::binary32,detail::constexpr_float::binary16>(a)); } else {
193 return detail::x86_f16c::cvtsh_ss<Arch>(a);
194 }
195 }
196
198 template<isa<x86> Arch = NATIVE_BASELINE> requires(!Arch.has(x86_feature::f16c))
199 native_nodiscard consteval
200 float cvtsh_ss(std::uint16_t a) noexcept {
201 return std::bit_cast<float>(detail::constexpr_float::convert_bits<
202 detail::constexpr_float::binary32,detail::constexpr_float::binary16>(a));
203 }
204
206 template<isa<x86> Arch, unsigned Imm8, class V> void cvtps_ph(V) = delete;
208 template<isa<x86> Arch, unsigned Lanes, class V> void cvtph_ps(V) = delete;
210}
211#endif
#define native_inline
inline [[always_inline]]
Definition attributes.h:212
#define native_nodiscard
C++17 [[nodiscard]].
Definition attributes.h:189
#define native_target(x)
this indicates a required feature set for the current multiversioned function.
Definition attributes.h:476
constexpr simd< fp16, 4, Arch > cvtps_ph(simd< float, 4, Arch > a) noexcept
Convert 4 binary32 lanes to 4 binary16 lanes.
constexpr simd< float, 4, Arch > cvtph_ps(simd< fp16, 4, Arch > a) noexcept
Widen 4 binary16 lanes to 4 binary32 lanes.
constexpr std::uint16_t cvtss_sh(float a) noexcept
Convert one binary32 value to binary16 representation bits.
constexpr float cvtsh_ss(std::uint16_t a) noexcept
Widen one binary16 representation to binary32.
Architecture-tagged vectors, register packs and supporting value types. Native arithmetic follows its...
Omitted architecture arguments use the native.simd provider's baseline.