12namespace native::detail::x86_instruction_constant {
14 constexpr auto lanes(V value)
noexcept {
15 std::array<typename V::value_type, V::lanes> result{};
16 value.store(result.data());
20 template<
unsigned Imm8,
class V>
21 constexpr V carryless(V a, V b)
noexcept {
22 auto aa = lanes(a), bb = lanes(b);
23 decltype(aa) result{};
24 for (std::size_t lane = 0; lane < V::lanes; lane += 2) {
25 auto x = aa[lane + (Imm8 & 1)];
26 auto y = bb[lane + ((Imm8 >> 4) & 1)];
27 for (
unsigned bit = 0; bit < 64; ++bit)
if ((y >> bit) & 1) {
28 result[lane] ^= x << bit;
29 if (bit) result[lane + 1] ^= x >> (64 - bit);
32 return V::load(result.data());
36 constexpr V population(V value, V source, std::uint64_t
mask)
noexcept {
37 auto input = lanes(value), result = lanes(source);
38 for (std::size_t lane = 0; lane < V::lanes; ++lane)
39 if ((
mask >> lane) & 1)
40 result[lane] =
static_cast<typename V::value_type
>(std::popcount(input[lane]));
41 return V::load(result.data());
44 constexpr std::uint8_t field_product(std::uint8_t a, std::uint8_t b)
noexcept {
45 unsigned x = a, y = b, result = 0;
46 for (
unsigned bit = 0; bit < 8; ++bit) {
47 if (y & 1) result ^= x;
49 x = (x << 1) ^ ((x & 0x80) ? 0x11b : 0);
51 return static_cast<std::uint8_t
>(result);
54 constexpr std::uint8_t field_inverse(std::uint8_t value)
noexcept {
56 std::uint8_t result = 1;
57 for (
unsigned exponent = 254; exponent; exponent >>= 1) {
58 if (exponent & 1) result = field_product(result, value);
59 value = field_product(value, value);
65 constexpr V field_multiply(V a, V b, V source, std::uint64_t
mask)
noexcept {
66 auto aa = lanes(a), bb = lanes(b), result = lanes(source);
67 for (std::size_t lane = 0; lane < V::lanes; ++lane)
68 if ((
mask >> lane) & 1) result[lane] = field_product(aa[lane], bb[lane]);
69 return V::load(result.data());
72 template<
unsigned Imm8,
bool Inverse,
class V,
class M>
73 constexpr V field_affine(V a, M matrix, V source, std::uint64_t
mask)
noexcept {
74 auto aa = lanes(a), result = lanes(source);
75 auto rows = lanes(matrix);
76 for (std::size_t lane = 0; lane < V::lanes; ++lane)
if ((
mask >> lane) & 1) {
77 auto value = Inverse ? field_inverse(aa[lane]) : aa[lane];
79 for (
unsigned bit = 0; bit < 8; ++bit) {
80 auto row =
static_cast<unsigned>(rows[lane / 8] >> (8 * (7 - bit))) & 255;
81 byte ^= (std::popcount(row & value) & 1u) << bit;
83 result[lane] =
static_cast<std::uint8_t
>(byte);
85 return V::load(result.data());
88 template<
bool Saturate,
class V,
class A,
class B>
89 constexpr V dot(V accumulator, A a, B b, std::uint64_t
mask,
bool zero)
noexcept {
90 using T =
typename V::value_type;
91 auto result = lanes(accumulator);
94 constexpr auto group = A::lanes / V::lanes;
95 for (std::size_t lane = 0; lane < V::lanes; ++lane) {
96 if (!((
mask >> lane) & 1)) {
97 if (zero) result[lane] = 0;
102 std::int64_t sum = result[lane];
103 for (std::size_t part = 0; part < group; ++part)
104 sum += std::int64_t(aa[group * lane + part]) * std::int64_t(bb[group * lane + part]);
105 if constexpr (Saturate) {
106 if (sum < std::numeric_limits<T>::min()) sum = std::numeric_limits<T>::min();
107 if (sum > std::numeric_limits<T>::max()) sum = std::numeric_limits<T>::max();
109 result[lane] = std::bit_cast<T>(
static_cast<std::uint32_t
>(sum));
111 return V::load(result.data());
typename mask_traits< std::remove_cvref_t< T > >::type mask