3#include "native/isa_import.h"
4#include "native/config.h"
14namespace native::detail::x86_neconvert {
15 template<
class T>
constexpr std::uint32_t widen(T value)
noexcept {
16 if constexpr (std::same_as<T, bf16>)
17 return std::uint32_t(value.to_bits()) << 16;
19 return std::bit_cast<std::uint32_t>(
static_cast<float>(value));
21 template<isa<x86> A, std::
size_t N,
unsigned Str
ide,
unsigned Offset,
class T>
22 consteval simd<float, N, A> widen_memory(T
const * source)
noexcept {
24 if constexpr (Stride == 2) {
25 auto last = source[2 * N - 1].to_bits();
28 std::array<float, N> result{};
29 for (std::size_t i = 0; i < N; ++i)
30 result[i] = std::bit_cast<float>(widen(source[Stride * i + Offset]));
31 return simd<float, N, A>::load(result.data());
33 template<isa<x86> A, std::
size_t N>
34 consteval simd<bf16, N, A> narrow(simd<float, N, A> input)
noexcept {
35 std::array<float, N> values{};
36 input.store(values.data());
37 std::array<std::uint16_t, N> result{};
38 for (std::size_t i = 0; i < N; ++i) {
39 auto bits = std::bit_cast<std::uint32_t>(values[i]);
40 auto magnitude = bits & 0x7fffffffu;
41 if (magnitude < 0x00800000u)
42 result[i] = std::uint16_t((bits >> 16) & 0x8000u);
43 else if (magnitude > 0x7f800000u)
44 result[i] = std::uint16_t((bits >> 16) | 0x0040u);
46 result[i] = std::uint16_t((bits + 0x7fffu + ((bits >> 16) & 1u)) >> 16);
48 return simd<bf16, N, A>::load_bits(result.data());
65 template<isa<x86> Arch, std::
size_t N>
66 requires(Arch.has(x86_feature::avxneconvert) && Arch.has(x86_feature::avx) &&
71 return detail::x86_neconvert::widen_memory<Arch, N, 0, 0>(source);
81 template<isa<x86> Arch, std::
size_t N>
82 requires(!(Arch.has(x86_feature::avxneconvert) && Arch.has(x86_feature::avx)) &&
83 (N == 4 || N == 8) &&
requires { sizeof(simd<float, N, Arch>); })
85 return detail::x86_neconvert::widen_memory<Arch, N, 0, 0>(source);
90 template<isa<x86> Arch, std::
size_t N>
91 requires(Arch.has(x86_feature::avxneconvert) && Arch.has(x86_feature::avx) &&
96 return detail::x86_neconvert::widen_memory<Arch, N, 0, 0>(source);
106 template<isa<x86> Arch, std::
size_t N>
107 requires(!(Arch.has(x86_feature::avxneconvert) && Arch.has(x86_feature::avx)) &&
108 (N == 4 || N == 8) &&
requires { sizeof(simd<float, N, Arch>); })
110 return detail::x86_neconvert::widen_memory<Arch, N, 0, 0>(source);
115 template<isa<x86> Arch, std::
size_t N>
116 requires(Arch.has(x86_feature::avxneconvert) && Arch.has(x86_feature::avx) &&
121 return detail::x86_neconvert::widen_memory<Arch, N, 2, 0>(source);
123 if constexpr (N == 4)
125 _mm_cvtneebf16_ps(
reinterpret_cast<__m128bh
const *
>(source)));
128 _mm256_cvtneebf16_ps(
reinterpret_cast<__m256bh
const *
>(source)));
133 template<isa<x86> Arch, std::
size_t N>
134 requires(!(Arch.has(x86_feature::avxneconvert) && Arch.has(x86_feature::avx)) &&
135 (N == 4 || N == 8) &&
requires { sizeof(simd<float, N, Arch>); })
137 return detail::x86_neconvert::widen_memory<Arch, N, 2, 0>(source);
142 template<isa<x86> Arch, std::
size_t N>
143 requires(Arch.has(x86_feature::avxneconvert) && Arch.has(x86_feature::avx) &&
148 return detail::x86_neconvert::widen_memory<Arch, N, 2, 0>(source);
150 if constexpr (N == 4)
152 _mm_cvtneeph_ps(
reinterpret_cast<__m128h
const *
>(source)));
155 _mm256_cvtneeph_ps(
reinterpret_cast<__m256h
const *
>(source)));
160 template<isa<x86> Arch, std::
size_t N>
161 requires(!(Arch.has(x86_feature::avxneconvert) && Arch.has(x86_feature::avx)) &&
162 (N == 4 || N == 8) &&
requires { sizeof(simd<float, N, Arch>); })
164 return detail::x86_neconvert::widen_memory<Arch, N, 2, 0>(source);
169 template<isa<x86> Arch, std::
size_t N>
170 requires(Arch.has(x86_feature::avxneconvert) && Arch.has(x86_feature::avx) &&
175 return detail::x86_neconvert::widen_memory<Arch, N, 2, 1>(source);
177 if constexpr (N == 4)
179 _mm_cvtneobf16_ps(
reinterpret_cast<__m128bh
const *
>(source)));
182 _mm256_cvtneobf16_ps(
reinterpret_cast<__m256bh
const *
>(source)));
187 template<isa<x86> Arch, std::
size_t N>
188 requires(!(Arch.has(x86_feature::avxneconvert) && Arch.has(x86_feature::avx)) &&
189 (N == 4 || N == 8) &&
requires { sizeof(simd<float, N, Arch>); })
191 return detail::x86_neconvert::widen_memory<Arch, N, 2, 1>(source);
196 template<isa<x86> Arch, std::
size_t N>
197 requires(Arch.has(x86_feature::avxneconvert) && Arch.has(x86_feature::avx) &&
202 return detail::x86_neconvert::widen_memory<Arch, N, 2, 1>(source);
204 if constexpr (N == 4)
206 _mm_cvtneoph_ps(
reinterpret_cast<__m128h
const *
>(source)));
209 _mm256_cvtneoph_ps(
reinterpret_cast<__m256h
const *
>(source)));
214 template<isa<x86> Arch, std::
size_t N>
215 requires(!(Arch.has(x86_feature::avxneconvert) && Arch.has(x86_feature::avx)) &&
216 (N == 4 || N == 8) &&
requires { sizeof(simd<float, N, Arch>); })
218 return detail::x86_neconvert::widen_memory<Arch, N, 2, 1>(source);
223 template<isa<x86> Arch, std::
size_t N>
224 requires(Arch.has(x86_feature::avxneconvert) && Arch.has(x86_feature::avx) &&
230 return detail::x86_neconvert::narrow(input);
235 if constexpr (N == 4)
236 return std::bit_cast<R>(_mm_cvtneps_avx_pbh(input.to_native()));
238 return std::bit_cast<R>(_mm256_cvtneps_avx_pbh(input.to_native()));
243 template<isa<x86> Arch, std::
size_t N>
244 requires(!(Arch.has(x86_feature::avxneconvert) && Arch.has(x86_feature::avx)) &&
245 (N == 4 || N == 8) &&
247 sizeof(simd<float, N, Arch>);
248 sizeof(simd<bf16, N, Arch>);
251 return detail::x86_neconvert::narrow(input);
Compiler attributes for host code, with shader-safe shared modifiers.
#define native_inline
inline [[always_inline]]
#define native_nodiscard
C++17 [[nodiscard]].
#define native_target(x)
this indicates a required feature set for the current multiversioned function.
constexpr simd< float, N, Arch > bcstnesh_ps(fp16 const *source) noexcept
constexpr simd< float, N, Arch > cvtneoph_ps(fp16 const *source) noexcept
constexpr simd< float, N, Arch > cvtneeph_ps(fp16 const *source) noexcept
constexpr simd< float, N, Arch > cvtneebf16_ps(bf16 const *source) noexcept
constexpr simd< bf16, N, Arch > cvtneps_bf16(simd< float, N, Arch > input) noexcept
constexpr simd< float, N, Arch > bcstnebf16_ps(bf16 const *source) noexcept
constexpr simd< float, N, Arch > cvtneobf16_ps(bf16 const *source) noexcept
Architecture-tagged vectors, register packs and supporting value types. Native arithmetic follows its...
Omitted architecture arguments use the native.simd provider's baseline.