4#include "native/isa_import.h"
5#include "native/arm/detail/integer_constant.h"
6#include "native/arm/dotprod.h"
11#if NATIVE_HOST_NEON || defined(NATIVE_DOXYGEN)
23 template<isa<arm> Arch>
requires(Arch.has(arm_feature::dotprod))
26 simd<
std::int32_t, 2, Arch> accumulator,
28 simd<
std::int8_t, 8, Arch> rhs) noexcept {
29 if consteval {
return detail::arm_constant::dot<
false, -1>(accumulator, lhs, rhs); }
31 auto result = detail::sdot<Arch>(
32 vget_low_s32(__builtin_bit_cast(int32x4_t, accumulator.to_native())),
33 __builtin_bit_cast(int8x8_t, lhs.to_native()),
34 __builtin_bit_cast(int8x8_t, rhs.to_native()));
40 template<isa<arm> Arch>
requires(!Arch.has(arm_feature::dotprod) &&
requires {
sizeof(simd<std::int32_t, 2, Arch>);
sizeof(simd<std::int8_t, 8, Arch>); })
45 return detail::arm_constant::dot<
false, -1>(accumulator, lhs, rhs);
49 template<isa<arm> Arch,
int Lane>
requires(Arch.has(arm_feature::dotprod) && Lane >= 0 && Lane < 2)
52 simd<
std::int32_t, 2, Arch> accumulator,
54 simd<
std::int8_t, 8, Arch> rhs) noexcept {
55 if consteval {
return detail::arm_constant::dot<false, Lane>(accumulator, lhs, rhs); }
57 auto result = detail::sdot_lane<Arch, Lane>(
58 vget_low_s32(__builtin_bit_cast(int32x4_t, accumulator.to_native())),
59 __builtin_bit_cast(int8x8_t, lhs.to_native()),
60 __builtin_bit_cast(int8x8_t, rhs.to_native()));
66 template<isa<arm> Arch,
int Lane>
requires(!Arch.has(arm_feature::dotprod) && Lane >= 0 && Lane < 2 &&
requires {
sizeof(simd<std::int32_t, 2, Arch>);
sizeof(simd<std::int8_t, 8, Arch>); })
71 return detail::arm_constant::dot<false, Lane>(accumulator, lhs, rhs);
75 template<isa<arm> Arch,
int Lane>
requires(Arch.has(arm_feature::dotprod) && Lane >= 0 && Lane < 4)
78 simd<
std::int32_t, 2, Arch> accumulator,
80 simd<
std::int8_t, 16, Arch> rhs) noexcept {
81 if consteval {
return detail::arm_constant::dot<false, Lane>(accumulator, lhs, rhs); }
83 auto result = detail::sdot_lane<Arch, Lane>(
84 vget_low_s32(__builtin_bit_cast(int32x4_t, accumulator.to_native())),
85 __builtin_bit_cast(int8x8_t, lhs.to_native()),
86 __builtin_bit_cast(int8x16_t, rhs.to_native()));
92 template<isa<arm> Arch,
int Lane>
requires(!Arch.has(arm_feature::dotprod) && Lane >= 0 && Lane < 4 &&
requires {
sizeof(simd<std::int32_t, 2, Arch>);
sizeof(simd<std::int8_t, 8, Arch>);
sizeof(simd<std::int8_t, 16, Arch>); })
97 return detail::arm_constant::dot<false, Lane>(accumulator, lhs, rhs);
101 template<isa<arm> Arch>
requires(Arch.has(arm_feature::dotprod))
104 simd<
std::int32_t, 4, Arch> accumulator,
105 simd<
std::int8_t, 16, Arch> lhs,
106 simd<
std::int8_t, 16, Arch> rhs) noexcept {
107 if consteval {
return detail::arm_constant::dot<
false, -1>(accumulator, lhs, rhs); }
109 auto result = detail::sdot<Arch>(
110 __builtin_bit_cast(int32x4_t, accumulator.to_native()),
111 __builtin_bit_cast(int8x16_t, lhs.to_native()),
112 __builtin_bit_cast(int8x16_t, rhs.to_native()));
118 template<isa<arm> Arch>
requires(!Arch.has(arm_feature::dotprod) &&
requires {
sizeof(simd<std::int32_t, 4, Arch>);
sizeof(simd<std::int8_t, 16, Arch>); })
123 return detail::arm_constant::dot<
false, -1>(accumulator, lhs, rhs);
127 template<isa<arm> Arch,
int Lane>
requires(Arch.has(arm_feature::dotprod) && Lane >= 0 && Lane < 2)
130 simd<
std::int32_t, 4, Arch> accumulator,
131 simd<
std::int8_t, 16, Arch> lhs,
132 simd<
std::int8_t, 8, Arch> rhs) noexcept {
133 if consteval {
return detail::arm_constant::dot<false, Lane>(accumulator, lhs, rhs); }
135 auto result = detail::sdot_lane<Arch, Lane>(
136 __builtin_bit_cast(int32x4_t, accumulator.to_native()),
137 __builtin_bit_cast(int8x16_t, lhs.to_native()),
138 __builtin_bit_cast(int8x8_t, rhs.to_native()));
144 template<isa<arm> Arch,
int Lane>
requires(!Arch.has(arm_feature::dotprod) && Lane >= 0 && Lane < 2 &&
requires {
sizeof(simd<std::int32_t, 4, Arch>);
sizeof(simd<std::int8_t, 16, Arch>);
sizeof(simd<std::int8_t, 8, Arch>); })
149 return detail::arm_constant::dot<false, Lane>(accumulator, lhs, rhs);
153 template<isa<arm> Arch,
int Lane>
requires(Arch.has(arm_feature::dotprod) && Lane >= 0 && Lane < 4)
156 simd<
std::int32_t, 4, Arch> accumulator,
157 simd<
std::int8_t, 16, Arch> lhs,
158 simd<
std::int8_t, 16, Arch> rhs) noexcept {
159 if consteval {
return detail::arm_constant::dot<false, Lane>(accumulator, lhs, rhs); }
161 auto result = detail::sdot_lane<Arch, Lane>(
162 __builtin_bit_cast(int32x4_t, accumulator.to_native()),
163 __builtin_bit_cast(int8x16_t, lhs.to_native()),
164 __builtin_bit_cast(int8x16_t, rhs.to_native()));
170 template<isa<arm> Arch,
int Lane>
requires(!Arch.has(arm_feature::dotprod) && Lane >= 0 && Lane < 4 &&
requires {
sizeof(simd<std::int32_t, 4, Arch>);
sizeof(simd<std::int8_t, 16, Arch>); })
175 return detail::arm_constant::dot<false, Lane>(accumulator, lhs, rhs);
179 template<isa<arm> Arch>
requires(Arch.has(arm_feature::dotprod))
182 simd<
std::uint32_t, 2, Arch> accumulator,
183 simd<
std::uint8_t, 8, Arch> lhs,
184 simd<
std::uint8_t, 8, Arch> rhs) noexcept {
185 if consteval {
return detail::arm_constant::dot<
false, -1>(accumulator, lhs, rhs); }
187 auto result = detail::udot<Arch>(
188 vget_low_u32(__builtin_bit_cast(uint32x4_t, accumulator.to_native())),
189 __builtin_bit_cast(uint8x8_t, lhs.to_native()),
190 __builtin_bit_cast(uint8x8_t, rhs.to_native()));
196 template<isa<arm> Arch>
requires(!Arch.has(arm_feature::dotprod) &&
requires {
sizeof(simd<std::uint32_t, 2, Arch>);
sizeof(simd<std::uint8_t, 8, Arch>); })
201 return detail::arm_constant::dot<
false, -1>(accumulator, lhs, rhs);
205 template<isa<arm> Arch,
int Lane>
requires(Arch.has(arm_feature::dotprod) && Lane >= 0 && Lane < 2)
208 simd<
std::uint32_t, 2, Arch> accumulator,
209 simd<
std::uint8_t, 8, Arch> lhs,
210 simd<
std::uint8_t, 8, Arch> rhs) noexcept {
211 if consteval {
return detail::arm_constant::dot<false, Lane>(accumulator, lhs, rhs); }
213 auto result = detail::udot_lane<Arch, Lane>(
214 vget_low_u32(__builtin_bit_cast(uint32x4_t, accumulator.to_native())),
215 __builtin_bit_cast(uint8x8_t, lhs.to_native()),
216 __builtin_bit_cast(uint8x8_t, rhs.to_native()));
222 template<isa<arm> Arch,
int Lane>
requires(!Arch.has(arm_feature::dotprod) && Lane >= 0 && Lane < 2 &&
requires {
sizeof(simd<std::uint32_t, 2, Arch>);
sizeof(simd<std::uint8_t, 8, Arch>); })
227 return detail::arm_constant::dot<false, Lane>(accumulator, lhs, rhs);
231 template<isa<arm> Arch,
int Lane>
requires(Arch.has(arm_feature::dotprod) && Lane >= 0 && Lane < 4)
234 simd<
std::uint32_t, 2, Arch> accumulator,
235 simd<
std::uint8_t, 8, Arch> lhs,
236 simd<
std::uint8_t, 16, Arch> rhs) noexcept {
237 if consteval {
return detail::arm_constant::dot<false, Lane>(accumulator, lhs, rhs); }
239 auto result = detail::udot_lane<Arch, Lane>(
240 vget_low_u32(__builtin_bit_cast(uint32x4_t, accumulator.to_native())),
241 __builtin_bit_cast(uint8x8_t, lhs.to_native()),
242 __builtin_bit_cast(uint8x16_t, rhs.to_native()));
248 template<isa<arm> Arch,
int Lane>
requires(!Arch.has(arm_feature::dotprod) && Lane >= 0 && Lane < 4 &&
requires {
sizeof(simd<std::uint32_t, 2, Arch>);
sizeof(simd<std::uint8_t, 8, Arch>);
sizeof(simd<std::uint8_t, 16, Arch>); })
253 return detail::arm_constant::dot<false, Lane>(accumulator, lhs, rhs);
257 template<isa<arm> Arch>
requires(Arch.has(arm_feature::dotprod))
260 simd<
std::uint32_t, 4, Arch> accumulator,
261 simd<
std::uint8_t, 16, Arch> lhs,
262 simd<
std::uint8_t, 16, Arch> rhs) noexcept {
263 if consteval {
return detail::arm_constant::dot<
false, -1>(accumulator, lhs, rhs); }
265 auto result = detail::udot<Arch>(
266 __builtin_bit_cast(uint32x4_t, accumulator.to_native()),
267 __builtin_bit_cast(uint8x16_t, lhs.to_native()),
268 __builtin_bit_cast(uint8x16_t, rhs.to_native()));
274 template<isa<arm> Arch>
requires(!Arch.has(arm_feature::dotprod) &&
requires {
sizeof(simd<std::uint32_t, 4, Arch>);
sizeof(simd<std::uint8_t, 16, Arch>); })
279 return detail::arm_constant::dot<
false, -1>(accumulator, lhs, rhs);
283 template<isa<arm> Arch,
int Lane>
requires(Arch.has(arm_feature::dotprod) && Lane >= 0 && Lane < 2)
286 simd<
std::uint32_t, 4, Arch> accumulator,
287 simd<
std::uint8_t, 16, Arch> lhs,
288 simd<
std::uint8_t, 8, Arch> rhs) noexcept {
289 if consteval {
return detail::arm_constant::dot<false, Lane>(accumulator, lhs, rhs); }
291 auto result = detail::udot_lane<Arch, Lane>(
292 __builtin_bit_cast(uint32x4_t, accumulator.to_native()),
293 __builtin_bit_cast(uint8x16_t, lhs.to_native()),
294 __builtin_bit_cast(uint8x8_t, rhs.to_native()));
300 template<isa<arm> Arch,
int Lane>
requires(!Arch.has(arm_feature::dotprod) && Lane >= 0 && Lane < 2 &&
requires {
sizeof(simd<std::uint32_t, 4, Arch>);
sizeof(simd<std::uint8_t, 16, Arch>);
sizeof(simd<std::uint8_t, 8, Arch>); })
305 return detail::arm_constant::dot<false, Lane>(accumulator, lhs, rhs);
309 template<isa<arm> Arch,
int Lane>
requires(Arch.has(arm_feature::dotprod) && Lane >= 0 && Lane < 4)
312 simd<
std::uint32_t, 4, Arch> accumulator,
313 simd<
std::uint8_t, 16, Arch> lhs,
314 simd<
std::uint8_t, 16, Arch> rhs) noexcept {
315 if consteval {
return detail::arm_constant::dot<false, Lane>(accumulator, lhs, rhs); }
317 auto result = detail::udot_lane<Arch, Lane>(
318 __builtin_bit_cast(uint32x4_t, accumulator.to_native()),
319 __builtin_bit_cast(uint8x16_t, lhs.to_native()),
320 __builtin_bit_cast(uint8x16_t, rhs.to_native()));
326 template<isa<arm> Arch,
int Lane>
requires(!Arch.has(arm_feature::dotprod) && Lane >= 0 && Lane < 4 &&
requires {
sizeof(simd<std::uint32_t, 4, Arch>);
sizeof(simd<std::uint8_t, 16, Arch>); })
331 return detail::arm_constant::dot<false, Lane>(accumulator, lhs, rhs);
335 template<isa<arm> Arch,
class A,
class B,
class C>
336 void sdot(A, B, C) =
delete;
337 template<isa<arm> Arch,
int Lane,
class A,
class B,
class C>
338 void sdot_lane(A, B, C) =
delete;
339 template<isa<arm> Arch,
class A,
class B,
class C>
340 void udot(A, B, C) =
delete;
341 template<isa<arm> Arch,
int Lane,
class A,
class B,
class C>
342 void udot_lane(A, B, C) =
delete;
constexpr simd< std::uint32_t, 2, Arch > udot_lane(simd< std::uint32_t, 2, Arch > accumulator, simd< std::uint8_t, 8, Arch > lhs, simd< std::uint8_t, 8, Arch > rhs) noexcept
UDOT by element: broadcast rhs byte group Lane to every accumulator lane.
constexpr simd< std::int32_t, 2, Arch > sdot(simd< std::int32_t, 2, Arch > accumulator, simd< std::int8_t, 8, Arch > lhs, simd< std::int8_t, 8, Arch > rhs) noexcept
SDOT: four byte products per accumulator lane, modulo 2^32.
constexpr simd< std::int32_t, 2, Arch > sdot_lane(simd< std::int32_t, 2, Arch > accumulator, simd< std::int8_t, 8, Arch > lhs, simd< std::int8_t, 8, Arch > rhs) noexcept
SDOT by element: broadcast rhs byte group Lane to every accumulator lane.
constexpr simd< std::uint32_t, 2, Arch > udot(simd< std::uint32_t, 2, Arch > accumulator, simd< std::uint8_t, 8, Arch > lhs, simd< std::uint8_t, 8, Arch > rhs) noexcept
UDOT: four byte products per accumulator lane, modulo 2^32.
#define native_inline
inline [[always_inline]]
#define native_nodiscard
C++17 [[nodiscard]].
#define native_const
[[const]] is not const
Architecture-tagged vectors, register packs and supporting value types. Native arithmetic follows its...
constexpr int target
First matching requirement, with every later choice checked for shadowing.
Standard-library adaptations documented here for SIMD value types.
Omitted architecture arguments use the native.simd provider's baseline.