Skip to content

Commit 8550d74

Browse files
committed
Add AVX implementation
1 parent 7ce00d6 commit 8550d74

3 files changed

Lines changed: 101 additions & 0 deletions

File tree

test/benchmarks/benchmarks.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -362,6 +362,7 @@ BENCHMARK_TEMPLATE(shift, uint256, uint64_t, shl_halves)->DenseRange(-1, 3);
362362
BENCHMARK_TEMPLATE(shift, uint256, uint64_t, experimental::shl_c)->DenseRange(-1, 3);
363363
BENCHMARK_TEMPLATE(shift, uint256, uint64_t, experimental::shl_e)->DenseRange(-1, 3);
364364
BENCHMARK_TEMPLATE(shift, uint256, uint64_t, experimental::shl_w)->DenseRange(-1, 3);
365+
BENCHMARK_TEMPLATE(shift, uint256, uint64_t, experimental::shl_avx)->DenseRange(-1, 3);
365366
BENCHMARK_TEMPLATE(shift, uint256, uint64_t, experimental::shl_bits_1)->DenseRange(-1, 3);
366367
BENCHMARK_TEMPLATE(shift, uint256, uint64_t, experimental::shl_bits_2)->DenseRange(-1, 3);
367368
BENCHMARK_TEMPLATE(shift, uint256, uint64_t, experimental::shl_bits_3)->DenseRange(-1, 3);

test/experimental/shift.hpp

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,68 @@
33
// Licensed under the Apache License, Version 2.0.
44
#pragma once
55

6+
#include <immintrin.h>
67
#include <intx/intx.hpp>
78

89
namespace intx::experimental
910
{
11+
inline uint256 shl_words_avx(const uint256& x, uint64_t sw) noexcept
12+
{
13+
sw = (sw < 4) ? sw : 4;
14+
int idxs[][8] = {
15+
{0, 1, 2, 3, 4, 5, 6, 7},
16+
{-1, -1, 0, 1, 2, 3, 4, 5},
17+
{-1, -1, -1, -1, 0, 1, 2, 3},
18+
{-1, -1, -1, -1, -1, -1, 0, 1},
19+
{-1, -1, -1, -1, -1, -1, -1, -1},
20+
};
21+
22+
auto idx = _mm256_load_si256((__m256i*)idxs[sw]);
23+
auto a = _mm256_load_si256((__m256i*)&x);
24+
25+
auto p = _mm256_permutevar8x32_epi32(a, idx);
26+
27+
auto zero = __m256{};
28+
auto bf = _mm256_blendv_ps(*(__m256*)&p, zero, *(__m256*)&idx);
29+
auto b = *(__m256i*)&bf;
30+
31+
uint256 res;
32+
_mm256_store_si256((__m256i*)&res, b);
33+
34+
return res;
35+
}
36+
37+
inline uint256 shl_bits_avx(const uint256& x, uint64_t sb) noexcept
38+
{
39+
auto a = _mm256_loadu_si256((__m256i*)&x);
40+
auto zero = __m256i{};
41+
42+
auto p = _mm256_permute4x64_epi64(a, 0b10010000);
43+
44+
auto b = _mm256_blend_epi32(p, zero, 0b11);
45+
46+
__m128i rcount{int64_t(64 - sb), 0};
47+
auto c = _mm256_srl_epi64(b, rcount);
48+
49+
__m128i count{int64_t(sb), 0};
50+
auto d = _mm256_sll_epi64(a, count);
51+
52+
auto e = _mm256_or_si256(c, d);
53+
54+
uint256 res;
55+
_mm256_storeu_si256((__m256i*)&res, e);
56+
57+
return res;
58+
}
59+
60+
[[gnu::noinline]] inline uint256 shl_avx(const uint256& x, uint64_t shift) noexcept
61+
{
62+
auto sw = shift / 64;
63+
auto sb = shift % 64;
64+
auto a = shl_words_avx(x, sw);
65+
return shl_bits_avx(a, sb);
66+
}
67+
1068
inline constexpr uint64_t shld(uint64_t x1, uint64_t x2, uint64_t c)
1169
{
1270
if (c == 0)

test/unittests/test_bitwise.cpp

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -347,3 +347,45 @@ TYPED_TEST(uint_test, shift_against_mul)
347347
auto y = a * s;
348348
EXPECT_EQ(x, y);
349349
}
350+
351+
TEST(avx, shl_words)
352+
{
353+
const auto x = 0x18191a1b1c1d1e1f28292a2b2c2d2e2f38393a3b3c3d3e3f48494a4b4c4d4e4f_u256;
354+
EXPECT_EQ(experimental::shl_words_avx(x, 0), x);
355+
EXPECT_EQ(experimental::shl_words_avx(x, 1), x << 64);
356+
EXPECT_EQ(experimental::shl_words_avx(x, 2), x << 128);
357+
EXPECT_EQ(experimental::shl_words_avx(x, 3), x << 192);
358+
EXPECT_EQ(experimental::shl_words_avx(x, 4), 0);
359+
EXPECT_EQ(experimental::shl_words_avx(x, 5), 0);
360+
EXPECT_EQ(experimental::shl_words_avx(x, 123131231), 0);
361+
}
362+
363+
TEST(avx, shl_bits)
364+
{
365+
const auto x = 0x18191a1b1c1d1e1f28292a2b2c2d2e2f38393a3b3c3d3e3f48494a4b4c4d4e4f_u256;
366+
EXPECT_EQ(experimental::shl_bits_avx(x, 0), x);
367+
EXPECT_EQ(experimental::shl_bits_avx(x, 1), x << 1);
368+
EXPECT_EQ(experimental::shl_bits_avx(x, 2), x << 2);
369+
EXPECT_EQ(experimental::shl_bits_avx(x, 3), x << 3);
370+
EXPECT_EQ(experimental::shl_bits_avx(x, 31), x << 31);
371+
EXPECT_EQ(experimental::shl_bits_avx(x, 32), x << 32);
372+
EXPECT_EQ(experimental::shl_bits_avx(x, 33), x << 33);
373+
EXPECT_EQ(experimental::shl_bits_avx(x, 63), x << 63);
374+
EXPECT_EQ(experimental::shl_bits_avx(x, 64), x << 64);
375+
}
376+
377+
TEST(avx, shl_avx)
378+
{
379+
const auto x = 0x18191a1b1c1d1e1f28292a2b2c2d2e2f38393a3b3c3d3e3f48494a4b4c4d4e4f_u256;
380+
EXPECT_EQ(experimental::shl_avx(x, 0), x);
381+
EXPECT_EQ(experimental::shl_avx(x, 1), x << 1);
382+
EXPECT_EQ(experimental::shl_avx(x, 2), x << 2);
383+
EXPECT_EQ(experimental::shl_avx(x, 3), x << 3);
384+
EXPECT_EQ(experimental::shl_avx(x, 31), x << 31);
385+
EXPECT_EQ(experimental::shl_avx(x, 32), x << 32);
386+
EXPECT_EQ(experimental::shl_avx(x, 33), x << 33);
387+
EXPECT_EQ(experimental::shl_avx(x, 63), x << 63);
388+
EXPECT_EQ(experimental::shl_avx(x, 64), x << 64);
389+
EXPECT_EQ(experimental::shl_avx(x, 65), x << 65);
390+
EXPECT_EQ(experimental::shl_avx(x, 255), x << 255);
391+
}

0 commit comments

Comments
 (0)