tensor_predictors/mvbernoulli/src/bit_utils.cpp

83 lines
2.0 KiB
C++

#include "bit_utils.h"
#if defined(__GNUC__) && defined(__BMI2__)
#include <x86intrin.h>
#include <bmi2intrin.h> // _pdep_u32
#endif
int bitParity(uint32_t x) {
#ifdef __GNUC__
return __builtin_parity(x);
#else
bool p = static_cast<bool>(x);
while (x &= x - 1) {
p = !p;
}
return static_cast<int>(p);
#endif
}
int bitCount(uint32_t x) {
#ifdef __GNUC__
return __builtin_popcount(x); // `POPulation COUNT`
#else
int count = 0; // counts set bits
// increment count until there are no bits set in x
for (; x; count++) {
x &= x - 1; // unset least significant bit
}
return count;
#endif
}
int bitScanLS(uint32_t x) {
#ifdef __GNUC__
return __builtin_ctz(x); // Count Trailing Zeros
#else
// result storing the Count of Trailing Zeros
int ctz = 0;
// boolean variable storing if a bit has not found (search area is empty)
bool empty;
// logarithmic search for LSB bit index (-1)
ctz += (empty = !(x & static_cast<uint32_t>(65535))) << 4;
x >>= 16 * empty;
ctz += (empty = !(x & static_cast<uint32_t>( 255))) << 3;
x >>= 8 * empty;
ctz += (empty = !(x & static_cast<uint32_t>( 15))) << 2;
x >>= 4 * empty;
ctz += (empty = !(x & static_cast<uint32_t>( 3))) << 1;
x >>= 2 * empty;
ctz += (empty = !(x & static_cast<uint32_t>( 1)));
return ctz;
#endif
}
uint32_t bitDeposit(uint32_t val, uint32_t mask) {
#if (defined(__GNUC__) && defined(__BMI2__))
return _pdep_u32(val, mask);
#else
uint32_t res = 0;
for (uint32_t pos = 1; mask; pos <<= 1) {
if (val & pos) {
res |= mask & -mask;
}
mask &= mask - 1;
}
return res;
#endif
}
uint32_t bitNextPerm(uint32_t val) {
// Sets all least significant 0-bits of val to 1
uint32_t t = val | (val - 1);
// Next set to 1 the most significant bit to change,
// set to 0 the least significant ones, and add the necessary 1 bits.
return (t + 1) | (((~t & -~t) - 1) >> (bitScanLS(val) + 1));
}