Skip to content

Commit

Permalink
bitswap() operations (#65)
Browse files Browse the repository at this point in the history
  • Loading branch information
cyberjunk committed Nov 12, 2023
1 parent 5719ad5 commit 7bd9419
Show file tree
Hide file tree
Showing 3 changed files with 227 additions and 0 deletions.
84 changes: 84 additions & 0 deletions include/CppCore.Test/BitOps.h
Original file line number Diff line number Diff line change
Expand Up @@ -1198,6 +1198,84 @@ namespace CppCore { namespace Test

////////////////////////////////////////////////////

INLINE static bool bitswap8()
{
uint8_t x;
x = 0x00; x = CppCore::bitswap8(x); if (x != 0x00) return false;
x = 0x01; x = CppCore::bitswap8(x); if (x != 0x80) return false;
x = 0x80; x = CppCore::bitswap8(x); if (x != 0x01) return false;
x = 0xFF; x = CppCore::bitswap8(x); if (x != 0xFF) return false;
x = 0x8C; x = CppCore::bitswap8(x); if (x != 0x31) return false;
return true;
}

INLINE static bool bitswap16()
{
uint16_t x;
x = 0x0000; x = CppCore::bitswap16(x); if (x != 0x0000) return false;
x = 0x0001; x = CppCore::bitswap16(x); if (x != 0x8000) return false;
x = 0x8000; x = CppCore::bitswap16(x); if (x != 0x0001) return false;
x = 0xFFFF; x = CppCore::bitswap16(x); if (x != 0xFFFF) return false;
x = 0x8C8C; x = CppCore::bitswap16(x); if (x != 0x3131) return false;
x = 0xDE1A; x = CppCore::bitswap16(x); if (x != 0x587B) return false;
x = 0x9A3A; x = CppCore::bitswap16(x); if (x != 0x5C59) return false;
return true;
}

INLINE static bool bitswap32()
{
uint32_t x;
x = 0x00000000U; x = CppCore::bitswap32(x); if (x != 0x00000000U) return false;
x = 0x00000001U; x = CppCore::bitswap32(x); if (x != 0x80000000U) return false;
x = 0x80000000U; x = CppCore::bitswap32(x); if (x != 0x00000001U) return false;
x = 0xFFFFFFFFU; x = CppCore::bitswap32(x); if (x != 0xFFFFFFFFU) return false;
x = 0x8C8C8C8CU; x = CppCore::bitswap32(x); if (x != 0x31313131U) return false;
x = 0x9A3ADE1AU; x = CppCore::bitswap32(x); if (x != 0x587B5C59U) return false;
return true;
}

INLINE static bool bitswap64()
{
uint64_t x;
x = 0x0000000000000000ULL; x = CppCore::bitswap64(x); if (x != 0x0000000000000000ULL) return false;
x = 0x0000000000000001ULL; x = CppCore::bitswap64(x); if (x != 0x8000000000000000ULL) return false;
x = 0x8000000000000000ULL; x = CppCore::bitswap64(x); if (x != 0x0000000000000001ULL) return false;
x = 0xFFFFFFFFFFFFFFFFULL; x = CppCore::bitswap64(x); if (x != 0xFFFFFFFFFFFFFFFFULL) return false;
x = 0x8C8C8C8C8C8C8C8CULL; x = CppCore::bitswap64(x); if (x != 0x3131313131313131ULL) return false;
x = 0x9A3ADE1AD7B72D2EULL; x = CppCore::bitswap64(x); if (x != 0x74B4EDEB587B5C59ULL) return false;
return true;
}

INLINE static bool bitswap128()
{
#if defined(CPPCORE_CPUFEAT_SSSE3)
union { __m128i x; uint64_t x64[2]; };
x = _mm_set_epi64x(0x0000000000000000ULL,0x0000000000000000ULL); x = CppCore::bitswap128(x); if (x64[1] != 0x0000000000000000ULL || x64[0] != 0x0000000000000000ULL) return false;
x = _mm_set_epi64x(0x0000000000000000ULL,0x0000000000000001ULL); x = CppCore::bitswap128(x); if (x64[1] != 0x8000000000000000ULL || x64[0] != 0x0000000000000000ULL) return false;
x = _mm_set_epi64x(0x8000000000000000ULL,0x0000000000000000ULL); x = CppCore::bitswap128(x); if (x64[1] != 0x0000000000000000ULL || x64[0] != 0x0000000000000001ULL) return false;
x = _mm_set_epi64x(0xFFFFFFFFFFFFFFFFULL,0xFFFFFFFFFFFFFFFFULL); x = CppCore::bitswap128(x); if (x64[1] != 0xFFFFFFFFFFFFFFFFULL || x64[0] != 0xFFFFFFFFFFFFFFFFULL) return false;
x = _mm_set_epi64x(0x8C8C8C8C8C8C8C8CULL,0x8C8C8C8C8C8C8C8CULL); x = CppCore::bitswap128(x); if (x64[1] != 0x3131313131313131ULL || x64[0] != 0x3131313131313131ULL) return false;
x = _mm_set_epi64x(0xB1F5AA5A43F27093ULL,0x9A3ADE1AD7B72D2EULL); x = CppCore::bitswap128(x); if (x64[1] != 0x74B4EDEB587B5C59ULL || x64[0] != 0xC90E4FC25A55AF8DULL) return false;
#endif
return true;
}

INLINE static bool bitswap256()
{
#if defined(CPPCORE_CPUFEAT_AVX2)
union { __m256i x; uint64_t x64[4]; };
x = _mm256_set_epi64x(0x0000000000000000ULL,0x0000000000000000ULL,0x0000000000000000ULL,0x0000000000000000ULL); x = CppCore::bitswap256(x); if (x64[3] != 0x0000000000000000ULL || x64[2] != 0x0000000000000000ULL || x64[1] != 0x0000000000000000ULL || x64[0] != 0x0000000000000000ULL) return false;
x = _mm256_set_epi64x(0x0000000000000000ULL,0x0000000000000000ULL,0x0000000000000000ULL,0x0000000000000001ULL); x = CppCore::bitswap256(x); if (x64[3] != 0x8000000000000000ULL || x64[2] != 0x0000000000000000ULL || x64[1] != 0x0000000000000000ULL || x64[0] != 0x0000000000000000ULL) return false;
x = _mm256_set_epi64x(0x8000000000000000ULL,0x0000000000000000ULL,0x0000000000000000ULL,0x0000000000000000ULL); x = CppCore::bitswap256(x); if (x64[3] != 0x0000000000000000ULL || x64[2] != 0x0000000000000000ULL || x64[1] != 0x0000000000000000ULL || x64[0] != 0x0000000000000001ULL) return false;
x = _mm256_set_epi64x(0xFFFFFFFFFFFFFFFFULL,0xFFFFFFFFFFFFFFFFULL,0xFFFFFFFFFFFFFFFFULL,0xFFFFFFFFFFFFFFFFULL); x = CppCore::bitswap256(x); if (x64[3] != 0xFFFFFFFFFFFFFFFFULL || x64[2] != 0xFFFFFFFFFFFFFFFFULL || x64[1] != 0xFFFFFFFFFFFFFFFFULL || x64[0] != 0xFFFFFFFFFFFFFFFFULL) return false;
x = _mm256_set_epi64x(0x8C8C8C8C8C8C8C8CULL,0x8C8C8C8C8C8C8C8CULL,0x8C8C8C8C8C8C8C8CULL,0x8C8C8C8C8C8C8C8CULL); x = CppCore::bitswap256(x); if (x64[3] != 0x3131313131313131ULL || x64[2] != 0x3131313131313131ULL || x64[1] != 0x3131313131313131ULL || x64[0] != 0x3131313131313131ULL) return false;
x = _mm256_set_epi64x(0xB1F5AA5A43F27093ULL,0x9A3ADE1AD7B72D2EULL,0x9A3ADE1AD7B72D2EULL,0xB1F5AA5A43F27093ULL); x = CppCore::bitswap256(x); if (x64[3] != 0xC90E4FC25A55AF8DULL || x64[2] != 0x74B4EDEB587B5C59ULL || x64[1] != 0x74B4EDEB587B5C59ULL || x64[0] != 0xC90E4FC25A55AF8DULL) return false;
#endif
return true;
}

////////////////////////////////////////////////////

INLINE static bool zbyteidxl32()
{
return
Expand Down Expand Up @@ -1969,6 +2047,12 @@ namespace CppCore { namespace Test { namespace VS {
TEST_METHOD(STORER32) { Assert::AreEqual(true, CppCore::Test::BitOps::storer32()); }
TEST_METHOD(STORER64) { Assert::AreEqual(true, CppCore::Test::BitOps::storer64()); }
TEST_METHOD(STORER128) { Assert::AreEqual(true, CppCore::Test::BitOps::storer128()); }
TEST_METHOD(BITSWAP8) { Assert::AreEqual(true, CppCore::Test::BitOps::bitswap8()); }
TEST_METHOD(BITSWAP16) { Assert::AreEqual(true, CppCore::Test::BitOps::bitswap16()); }
TEST_METHOD(BITSWAP32) { Assert::AreEqual(true, CppCore::Test::BitOps::bitswap32()); }
TEST_METHOD(BITSWAP64) { Assert::AreEqual(true, CppCore::Test::BitOps::bitswap64()); }
TEST_METHOD(BITSWAP128) { Assert::AreEqual(true, CppCore::Test::BitOps::bitswap128()); }
TEST_METHOD(BITSWAP256) { Assert::AreEqual(true, CppCore::Test::BitOps::bitswap256()); }
TEST_METHOD(ZBYTEIDXL32) { Assert::AreEqual(true, CppCore::Test::BitOps::zbyteidxl32()); }
TEST_METHOD(ZBYTEIDXL64) { Assert::AreEqual(true, CppCore::Test::BitOps::zbyteidxl64()); }
TEST_METHOD(ZBYTEIDXL128) { Assert::AreEqual(true, CppCore::Test::BitOps::zbyteidxl128()); }
Expand Down
137 changes: 137 additions & 0 deletions include/CppCore/BitOps.h
Original file line number Diff line number Diff line change
Expand Up @@ -2859,6 +2859,35 @@ namespace CppCore
#endif
}

#if defined(CPPCORE_CPUFEAT_SSSE3)
/// <summary>
/// Swaps byte order in 128-bit unsigned integer.
/// Requires SSSE3.
/// </summary>
static INLINE __m128i byteswap128(__m128i v)
{
const __m128i BSWAP_MASK = _mm_set_epi8(
0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15);
return _mm_shuffle_epi8(v, BSWAP_MASK);
}
#endif

#if defined(CPPCORE_CPUFEAT_AVX2)
/// <summary>
/// Swaps byte order in 256-bit unsigned integer.
/// Requires AVX2.
/// </summary>
static INLINE __m256i byteswap256(__m256i v)
{
const __m256i BSWAP_MASK = _mm256_set_epi8(
0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,
0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15);
return _mm256_permute4x64_epi64(
_mm256_shuffle_epi8(v, BSWAP_MASK),
_MM_SHUFFLE(1, 0, 3, 2));
}
#endif

/// <summary>
/// Swaps byte order in 16-bit unsigned integer.
/// </summary>
Expand Down Expand Up @@ -3018,6 +3047,114 @@ namespace CppCore
x = CppCore::bytedup64(v);
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// BITSWAP: Reverse Bit Order
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

/// <summary>
/// Reverse Bits in 8-Bit Integer
/// </summary>
/// <remarks>
/// From http://graphics.stanford.edu/~seander/bithacks.html
/// </remarks>
static INLINE uint8_t bitswap8(uint8_t x)
{
#if defined(CPPCORE_CPU_64BIT)
return (uint8_t)(((x * 0x80200802ULL) & 0x0884422110ULL) * 0x0101010101ULL >> 32);
#else
return (uint8_t)(((x * 0x0802LU & 0x22110LU) | (x * 0x8020LU & 0x88440LU)) * 0x10101LU >> 16);
#endif
}

/// <summary>
/// Reverse Bits in 32-Bit Integer
/// </summary>
static INLINE uint32_t bitswap32(uint32_t x)
{
#if defined(CPPCORE_CPU_ARM64)
uint64_t x64 = x;
__asm__("RBIT %0, %1" : "=r" (x64) : "r" (x64));
return (uint32_t)(x64 >> 32);
#elif defined(CPPCORE_CPU_ARM)
__asm__("RBIT %0, %1" : "=r" (x) : "r" (x));
return x;
#else
x = ((x >> 1) & 0x55555555U) | ((x & 0x55555555U) << 1);
x = ((x >> 2) & 0x33333333U) | ((x & 0x33333333U) << 2);
x = ((x >> 4) & 0x0F0F0F0FU) | ((x & 0x0F0F0F0FU) << 4);
return CppCore::byteswap32(x); // BSWAP on INTEL
#endif
}

/// <summary>
/// Reverse Bits in 64-Bit Integer
/// </summary>
static INLINE uint64_t bitswap64(uint64_t x)
{
#if defined(CPPCORE_CPU_ARM64)
__asm__("RBIT %0, %1" : "=r" (x) : "r" (x));
return x;
#elif defined(CPPCORE_CPU_ARM)
uint32_t xl = CppCore::bitswap32((uint32_t)(x));
uint32_t xh = CppCore::bitswap32((uint32_t)(x >> 32));
return ((uint64_t)xl << 32) | xh;
#else
x = ((x >> 1) & 0x5555555555555555ULL) | ((x & 0x5555555555555555ULL) << 1);
x = ((x >> 2) & 0x3333333333333333ULL) | ((x & 0x3333333333333333ULL) << 2);
x = ((x >> 4) & 0x0F0F0F0F0F0F0F0FULL) | ((x & 0x0F0F0F0F0F0F0F0FULL) << 4);
return CppCore::byteswap64(x); // BSWAP on INTEL
#endif
}

/// <summary>
/// Reverse Bits in 16-Bit Integer
/// </summary>
static INLINE uint16_t bitswap16(uint16_t x)
{
return (uint16_t)(CppCore::bitswap32(x) >> 16);
}

#if defined(CPPCORE_CPUFEAT_SSSE3)
/// <summary>
/// Reverse Bits in 128-Bit Integer.
/// Requires SSSE3.
/// </summary>
/// <remarks>
/// From https://www.intel.com/content/dam/develop/external/us/en/documents/clmul-wp-rev-2-02-2014-04-20.pdf
/// </remarks>
static INLINE __m128i bitswap128(__m128i x)
{
const __m128i AND_MASK = _mm_set_epi32(0x0f0f0f0f,0x0f0f0f0f,0x0f0f0f0f,0x0f0f0f0f);
const __m128i LOWER_MASK = _mm_set_epi32(0x0f070b03,0x0d050901,0x0e060a02,0x0c040800);
const __m128i HIGHER_MASK = _mm_set_epi32(0xf070b030,0xd0509010,0xe060a020,0xc0408000);
return CppCore::byteswap128(_mm_xor_si128(
_mm_shuffle_epi8(HIGHER_MASK, _mm_and_si128(x, AND_MASK)),
_mm_shuffle_epi8(LOWER_MASK, _mm_and_si128(_mm_srli_epi16(x, 4), AND_MASK))));
}
#endif

#if defined(CPPCORE_CPUFEAT_AVX2)
/// <summary>
/// Reverse Bits in 256-Bit Integer.
/// Requires AVX2.
/// </summary>
static INLINE __m256i bitswap256(__m256i x)
{
const __m256i AND_MASK = _mm256_set_epi32(
0x0f0f0f0f,0x0f0f0f0f,0x0f0f0f0f,0x0f0f0f0f,
0x0f0f0f0f,0x0f0f0f0f,0x0f0f0f0f,0x0f0f0f0f);
const __m256i LOWER_MASK = _mm256_set_epi32(
0x0f070b03,0x0d050901,0x0e060a02,0x0c040800,
0x0f070b03,0x0d050901,0x0e060a02,0x0c040800);
const __m256i HIGHER_MASK = _mm256_set_epi32(
0xf070b030,0xd0509010,0xe060a020,0xc0408000,
0xf070b030,0xd0509010,0xe060a020,0xc0408000);
return CppCore::byteswap256(_mm256_xor_si256(
_mm256_shuffle_epi8(HIGHER_MASK, _mm256_and_si256(x, AND_MASK)),
_mm256_shuffle_epi8(LOWER_MASK, _mm256_and_si256(_mm256_srli_epi32(x, 4), AND_MASK))));
}
#endif

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// MOVBE: REVERSE LOAD
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
Expand Down
6 changes: 6 additions & 0 deletions src/CppCore.Test/Test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -290,6 +290,12 @@ int main()
TEST(CppCore::Test::BitOps::storer16, "storer16: ", std::endl);
TEST(CppCore::Test::BitOps::storer32, "storer32: ", std::endl);
TEST(CppCore::Test::BitOps::storer64, "storer64: ", std::endl);
TEST(CppCore::Test::BitOps::bitswap8, "bitswap8: ", std::endl);
TEST(CppCore::Test::BitOps::bitswap16, "bitswap16: ", std::endl);
TEST(CppCore::Test::BitOps::bitswap32, "bitswap32: ", std::endl);
TEST(CppCore::Test::BitOps::bitswap64, "bitswap64: ", std::endl);
TEST(CppCore::Test::BitOps::bitswap128, "bitswap128: ", std::endl);
TEST(CppCore::Test::BitOps::bitswap256, "bitswap256: ", std::endl);
TEST(CppCore::Test::BitOps::zbyteidxl32, "zbyteidxl32: ", std::endl);
TEST(CppCore::Test::BitOps::zbyteidxl64, "zbyteidxl64: ", std::endl);
TEST(CppCore::Test::BitOps::zbyteidxl128, "zbyteidxl128: ", std::endl);
Expand Down

0 comments on commit 7bd9419

Please sign in to comment.