#ifndef BITUTILS_ARCH_X86_H
#define BITUTILS_ARCH_X86_H
#include "ue2common.h"
#include "util/popcount.h"
#include "util/arch.h"
#include "util/intrinsics.h"
#include "util/arch/common/bitutils.h"
static really_inline
u32 clz32_impl(u32 x) {
return clz32_impl_c(x);
}
static really_inline
u32 clz64_impl(u64a x) {
return clz64_impl_c(x);
}
static really_inline
u32 ctz32_impl(u32 x) {
return ctz32_impl_c(x);
}
static really_inline
u32 ctz64_impl(u64a x) {
return ctz64_impl_c(x);
}
static really_inline
u32 lg2_impl(u32 x) {
return lg2_impl_c(x);
}
static really_inline
u64a lg2_64_impl(u64a x) {
return lg2_64_impl_c(x);
}
static really_inline
u32 findAndClearLSB_32_impl(u32 *v) {
#ifndef NO_ASM
u32 val = *v, offset;
__asm__ ("bsf %1, %0\n"
"btr %0, %1\n"
: "=r" (offset), "=r" (val)
: "1" (val));
*v = val;
assert(offset < 32);
return offset;
#else
return findAndClearLSB_32_impl_c(v);
#endif
}
static really_inline
u32 findAndClearLSB_64_impl(u64a *v) {
#ifdef ARCH_64_BIT
#if !defined(NO_ASM)
u64a val = *v, offset;
__asm__ ("bsfq %1, %0\n"
"btrq %0, %1\n"
: "=r" (offset), "=r" (val)
: "1" (val));
*v = val;
#else
u64a val = *v, offset;
offset = ctz64(val);
*v = val & (val - 1);
#endif assert(offset < 64);
return (u32)offset;
#else
return findAndClearLSB_64_impl_c(v);
#endif
}
static really_inline
u32 findAndClearMSB_32_impl(u32 *v) {
#if !defined(NO_ASM)
u32 val = *v, offset;
__asm__ ("bsr %1, %0\n"
"btr %0, %1\n"
: "=r" (offset), "=r" (val)
: "1" (val));
*v = val;
#else
u32 val = *v;
u32 offset = 31 - clz32_impl(val);
*v = val & ~(1 << offset);
#endif
assert(offset < 32);
return offset;
}
static really_inline
u32 findAndClearMSB_64_impl(u64a *v) {
#ifdef ARCH_64_BIT
#if !defined(NO_ASM)
u64a val = *v, offset;
__asm__ ("bsrq %1, %0\n"
"btrq %0, %1\n"
: "=r" (offset), "=r" (val)
: "1" (val));
*v = val;
#else
u64a val = *v, offset;
offset = 63 - clz64_impl(val);
*v = val & ~(1ULL << offset);
#endif assert(offset < 64);
return (u32)offset;
#else
return findAndClearMSB_64_impl_c(v);
#endif
}
static really_inline
u32 compress32_impl(u32 x, u32 m) {
#if defined(HAVE_BMI2)
return _pext_u32(x, m);
#else
return compress32_impl_c(x, m);
#endif
}
static really_inline
u64a compress64_impl(u64a x, u64a m) {
#if defined(ARCH_X86_64) && defined(HAVE_BMI2)
return _pext_u64(x, m);
#else
return compress64_impl_c(x, m);
#endif
}
static really_inline
m128 compress128_impl(m128 xvec, m128 mvec) {
u64a ALIGN_ATTR(16) x[2];
u64a ALIGN_ATTR(16) m[2];
store128(x, xvec);
store128(m, mvec);
x[0] = compress64_impl(x[0], m[0]);
x[1] = compress64_impl(x[1], m[1]);
return load128(x);
}
static really_inline
u32 expand32_impl(u32 x, u32 m) {
#if defined(HAVE_BMI2)
return _pdep_u32(x, m);
#else
return expand32_impl_c(x, m);
#endif
}
static really_inline
u64a expand64_impl(u64a x, u64a m) {
#if defined(ARCH_X86_64) && defined(HAVE_BMI2)
DEBUG_PRINTF("pdep_u64\n");
return _pdep_u64(x, m);
#else
return expand64_impl_c(x, m);
#endif
}
static really_inline
m128 expand128_impl(m128 xvec, m128 mvec) {
u64a ALIGN_ATTR(16) x[2];
u64a ALIGN_ATTR(16) m[2];
store128(x, xvec);
store128(m, mvec);
DEBUG_PRINTF("calling expand64_impl:\n");
x[0] = expand64_impl(x[0], m[0]);
x[1] = expand64_impl(x[1], m[1]);
return load128(x);
}
static really_inline
u32 bf64_iterate_impl(u64a bitfield, u32 begin) {
if (begin != ~0U) {
assert(begin <= 63);
bitfield &= ~((2ULL << begin) - 1);
}
if (!bitfield) {
return ~0U;
}
return ctz64_impl(bitfield);
}
static really_inline
char bf64_set_impl(u64a *bitfield, u32 i) {
return bf64_set_impl_c(bitfield, i);
}
static really_inline
void bf64_unset_impl(u64a *bitfield, u32 i) {
return bf64_unset_impl_c(bitfield, i);
}
static really_inline
u32 rank_in_mask32_impl(u32 mask, u32 bit) {
return rank_in_mask32_impl_c(mask, bit);
}
static really_inline
u32 rank_in_mask64_impl(u64a mask, u32 bit) {
return rank_in_mask64_impl_c(mask, bit);
}
static really_inline
u32 pext32_impl(u32 x, u32 mask) {
#if defined(HAVE_BMI2)
return _pext_u32(x, mask);
#else
return pext32_impl_c(x, mask);
#endif
}
static really_inline
u64a pext64_impl(u64a x, u64a mask) {
#if defined(HAVE_BMI2) && defined(ARCH_64_BIT)
return _pext_u64(x, mask);
#else
return pext64_impl_c(x, mask);
#endif
}
#if defined(HAVE_BMI2) && defined(ARCH_64_BIT)
static really_inline
u64a pdep64_impl(u64a x, u64a mask) {
return _pdep_u64(x, mask);
}
#else
static really_inline
u64a pdep64_impl(u64a x, u64a mask) {
return pdep64_impl_c(x, mask);
}
#endif
static really_inline
u64a andn_impl(const u32 a, const u8 *b) {
#if defined(HAVE_BMI) && !defined(NO_ASM)
u64a r;
__asm__ ("andn\t%2,%1,%k0" : "=r"(r) : "r"(a), "m"(*(const u32 *)b));
return r;
#else
return andn_impl_c(a, b);
#endif
}
#endif