Get rid of MSVC's __int64

Use either int64_t, uint64_t or long long and unsigned long long, defined as per C++11 standard
This commit is contained in:
void_17
2026-03-02 15:53:32 +07:00
parent d6ec138710
commit d63f79325f
308 changed files with 5371 additions and 5379 deletions

View File

@@ -29,8 +29,8 @@
#if ! LIBDIVIDE_HAS_STDINT_TYPES
typedef __int32 int32_t;
typedef unsigned __int32 uint32_t;
typedef __int64 int64_t;
typedef unsigned __int64 uint64_t;
typedef int64_t int64_t;
typedef uint64_t uint64_t;
typedef __int8 int8_t;
typedef unsigned __int8 uint8_t;
#endif
@@ -83,7 +83,7 @@ u32: [0-4] shift value
[5] ignored
[6] add indicator
[7] shift path
s32: [0-4] shift value
[5] shift path
[6] add indicator
@@ -106,7 +106,7 @@ enum {
LIBDIVIDE_U32_SHIFT_PATH = 0x80,
LIBDIVIDE_U64_SHIFT_PATH = 0x80,
LIBDIVIDE_S32_SHIFT_PATH = 0x20,
LIBDIVIDE_NEGATIVE_DIVISOR = 0x80
LIBDIVIDE_NEGATIVE_DIVISOR = 0x80
};
@@ -123,7 +123,7 @@ struct libdivide_s32_t {
struct libdivide_u64_t {
uint64_t magic;
uint8_t more;
};
};
struct libdivide_s64_t {
int64_t magic;
@@ -146,7 +146,7 @@ LIBDIVIDE_API struct libdivide_s32_t libdivide_s32_gen(int32_t y);
LIBDIVIDE_API struct libdivide_u32_t libdivide_u32_gen(uint32_t y);
LIBDIVIDE_API struct libdivide_s64_t libdivide_s64_gen(int64_t y);
LIBDIVIDE_API struct libdivide_u64_t libdivide_u64_gen(uint64_t y);
LIBDIVIDE_API int32_t libdivide_s32_do(int32_t numer, const struct libdivide_s32_t *denom);
LIBDIVIDE_API uint32_t libdivide_u32_do(uint32_t numer, const struct libdivide_u32_t *denom);
LIBDIVIDE_API int64_t libdivide_s64_do(int64_t numer, const struct libdivide_s64_t *denom);
@@ -156,19 +156,19 @@ LIBDIVIDE_API int libdivide_u32_get_algorithm(const struct libdivide_u32_t *deno
LIBDIVIDE_API uint32_t libdivide_u32_do_alg0(uint32_t numer, const struct libdivide_u32_t *denom);
LIBDIVIDE_API uint32_t libdivide_u32_do_alg1(uint32_t numer, const struct libdivide_u32_t *denom);
LIBDIVIDE_API uint32_t libdivide_u32_do_alg2(uint32_t numer, const struct libdivide_u32_t *denom);
LIBDIVIDE_API int libdivide_u64_get_algorithm(const struct libdivide_u64_t *denom);
LIBDIVIDE_API uint64_t libdivide_u64_do_alg0(uint64_t numer, const struct libdivide_u64_t *denom);
LIBDIVIDE_API uint64_t libdivide_u64_do_alg1(uint64_t numer, const struct libdivide_u64_t *denom);
LIBDIVIDE_API uint64_t libdivide_u64_do_alg2(uint64_t numer, const struct libdivide_u64_t *denom);
LIBDIVIDE_API int libdivide_s32_get_algorithm(const struct libdivide_s32_t *denom);
LIBDIVIDE_API int32_t libdivide_s32_do_alg0(int32_t numer, const struct libdivide_s32_t *denom);
LIBDIVIDE_API int32_t libdivide_s32_do_alg1(int32_t numer, const struct libdivide_s32_t *denom);
LIBDIVIDE_API int32_t libdivide_s32_do_alg2(int32_t numer, const struct libdivide_s32_t *denom);
LIBDIVIDE_API int32_t libdivide_s32_do_alg3(int32_t numer, const struct libdivide_s32_t *denom);
LIBDIVIDE_API int32_t libdivide_s32_do_alg4(int32_t numer, const struct libdivide_s32_t *denom);
LIBDIVIDE_API int libdivide_s64_get_algorithm(const struct libdivide_s64_t *denom);
LIBDIVIDE_API int64_t libdivide_s64_do_alg0(int64_t numer, const struct libdivide_s64_t *denom);
LIBDIVIDE_API int64_t libdivide_s64_do_alg1(int64_t numer, const struct libdivide_s64_t *denom);
@@ -202,17 +202,17 @@ LIBDIVIDE_API __m128i libdivide_s64_do_vector_alg2(__m128i numers, const struct
LIBDIVIDE_API __m128i libdivide_s64_do_vector_alg3(__m128i numers, const struct libdivide_s64_t * denom);
LIBDIVIDE_API __m128i libdivide_s64_do_vector_alg4(__m128i numers, const struct libdivide_s64_t * denom);
#endif
//////// Internal Utility Functions
static inline uint32_t libdivide__mullhi_u32(uint32_t x, uint32_t y) {
uint64_t xl = x, yl = y;
uint64_t rl = xl * yl;
return (uint32_t)(rl >> 32);
}
static uint64_t libdivide__mullhi_u64(uint64_t x, uint64_t y) {
#if HAS_INT128_T
__uint128_t xl = x, yl = y;
@@ -227,18 +227,18 @@ static uint64_t libdivide__mullhi_u64(uint64_t x, uint64_t y) {
const uint64_t x0y1 = x0 * (uint64_t)y1;
const uint64_t x1y0 = x1 * (uint64_t)y0;
const uint64_t x1y1 = x1 * (uint64_t)y1;
uint64_t temp = x1y0 + x0y0_hi;
uint64_t temp_lo = temp & mask, temp_hi = temp >> 32;
return x1y1 + temp_hi + ((temp_lo + x0y1) >> 32);
#endif
}
static inline int64_t libdivide__mullhi_s64(int64_t x, int64_t y) {
#if HAS_INT128_T
__int128_t xl = x, yl = y;
__int128_t rl = xl * yl;
return (int64_t)(rl >> 64);
return (int64_t)(rl >> 64);
#else
//full 128 bits are x0 * y0 + (x0 * y1 << 32) + (x1 * y0 << 32) + (x1 * y1 << 64)
const uint32_t mask = 0xFFFFFFFF;
@@ -250,7 +250,7 @@ static inline int64_t libdivide__mullhi_s64(int64_t x, int64_t y) {
return x1*(int64_t)y1 + (t >> 32) + (w1 >> 32);
#endif
}
#if LIBDIVIDE_USE_SSE2
static inline __m128i libdivide__u64_to_m128(uint64_t x) {
@@ -275,7 +275,7 @@ static inline __m128i libdivide_get_FFFFFFFF00000000(void) {
__m128i result = _mm_set1_epi8(-1); //optimizes to pcmpeqd on OS X
return _mm_slli_epi64(result, 32);
}
static inline __m128i libdivide_get_00000000FFFFFFFF(void) {
//returns the same as _mm_set1_epi64(0x00000000FFFFFFFFULL) without touching memory
__m128i result = _mm_set1_epi8(-1); //optimizes to pcmpeqd on OS X
@@ -288,7 +288,7 @@ static inline __m128i libdivide_get_0000FFFF(void) {
__m128i result; //we don't care what its contents are
result = _mm_cmpeq_epi8(result, result); //all 1s
result = _mm_srli_epi32(result, 16);
return result;
return result;
}
static inline __m128i libdivide_s64_signbits(__m128i v) {
@@ -302,7 +302,7 @@ static inline __m128i libdivide_s64_signbits(__m128i v) {
static inline __m128i libdivide_u32_to_m128i(uint32_t amt) {
return _mm_set_epi32(0, 0, 0, amt);
}
static inline __m128i libdivide_s64_shift_right_vector(__m128i v, int amt) {
//implementation of _mm_sra_epi64. Here we have two 64 bit values which are shifted right to logically become (64 - amt) values, and are then sign extended from a (64 - amt) bit number.
const int b = 64 - amt;
@@ -320,7 +320,7 @@ static inline __m128i libdivide__mullhi_u32_flat_vector(__m128i a, __m128i b) {
return _mm_or_si128(hi_product_0Z2Z, hi_product_Z1Z3); // = hi_product_0123
}
/* Here, y is assumed to contain one 64 bit value repeated twice. */
static inline __m128i libdivide_mullhi_u64_flat_vector(__m128i x, __m128i y) {
//full 128 bits are x0 * y0 + (x0 * y1 << 32) + (x1 * y0 << 32) + (x1 * y1 << 64)
@@ -331,12 +331,12 @@ static inline __m128i libdivide_mullhi_u64_flat_vector(__m128i x, __m128i y) {
const __m128i x0y1 = _mm_mul_epu32(x0, y1);
const __m128i x1y0 = _mm_mul_epu32(x1, y0);
const __m128i x1y1 = _mm_mul_epu32(x1, y1);
const __m128i temp = _mm_add_epi64(x1y0, x0y0_hi);
__m128i temp_lo = _mm_and_si128(temp, mask), temp_hi = _mm_srli_epi64(temp, 32);
temp_lo = _mm_srli_epi64(_mm_add_epi64(temp_lo, x0y1), 32);
temp_hi = _mm_add_epi64(x1y1, temp_hi);
return _mm_add_epi64(temp_lo, temp_hi);
}
@@ -349,9 +349,9 @@ static inline __m128i libdivide_mullhi_s64_flat_vector(__m128i x, __m128i y) {
p = _mm_sub_epi64(p, t2);
return p;
}
#ifdef LIBDIVIDE_USE_SSE4_1
/* b is one 32 bit value repeated four times. */
static inline __m128i libdivide_mullhi_s32_flat_vector(__m128i a, __m128i b) {
__m128i hi_product_0Z2Z = _mm_srli_epi64(_mm_mul_epi32(a, b), 32);
@@ -359,7 +359,7 @@ static inline __m128i libdivide_mullhi_s32_flat_vector(__m128i a, __m128i b) {
__m128i hi_product_Z1Z3 = _mm_and_si128(_mm_mul_epi32(a1X3X, b), libdivide_get_FFFFFFFF00000000());
return _mm_or_si128(hi_product_0Z2Z, hi_product_Z1Z3); // = hi_product_0123
}
#else
/* SSE2 does not have a signed multiplication instruction, but we can convert unsigned to signed pretty efficiently. Again, b is just a 32 bit value repeated four times. */
@@ -373,7 +373,7 @@ static inline __m128i libdivide_mullhi_s32_flat_vector(__m128i a, __m128i b) {
}
#endif
#endif
static inline int32_t libdivide__count_trailing_zeros32(uint32_t val) {
#if __GNUC__ || __has_builtin(__builtin_ctz)
/* Fast way to count trailing zeros */
@@ -389,7 +389,7 @@ static inline int32_t libdivide__count_trailing_zeros32(uint32_t val) {
return result;
#endif
}
static inline int32_t libdivide__count_trailing_zeros64(uint64_t val) {
#if __LP64__ && (__GNUC__ || __has_builtin(__builtin_ctzll))
/* Fast way to count trailing zeros. Note that we disable this in 32 bit because gcc does something horrible - it calls through to a dynamically bound function. */
@@ -401,11 +401,11 @@ static inline int32_t libdivide__count_trailing_zeros64(uint64_t val) {
return 32 + libdivide__count_trailing_zeros32((uint32_t)(val >> 32));
#endif
}
static inline int32_t libdivide__count_leading_zeros32(uint32_t val) {
#if __GNUC__ || __has_builtin(__builtin_clzll)
/* Fast way to count leading zeros */
return __builtin_clz(val);
return __builtin_clz(val);
#else
/* Dorky way to count leading zeros. Note that this hangs for val = 0! */
int32_t result = 0;
@@ -413,10 +413,10 @@ static inline int32_t libdivide__count_leading_zeros32(uint32_t val) {
val <<= 1;
result++;
}
return result;
return result;
#endif
}
static inline int32_t libdivide__count_leading_zeros64(uint64_t val) {
#if __GNUC__ || __has_builtin(__builtin_clzll)
/* Fast way to count leading zeros */
@@ -450,7 +450,7 @@ static uint32_t libdivide_64_div_32_to_32(uint32_t u1, uint32_t u0, uint32_t v,
return result;
}
#endif
#if LIBDIVIDE_IS_X86_64 && LIBDIVIDE_GCC_STYLE_ASM
static uint64_t libdivide_128_div_64_to_64(uint64_t u1, uint64_t u0, uint64_t v, uint64_t *r) {
//u0 -> rax
@@ -465,10 +465,10 @@ static uint64_t libdivide_128_div_64_to_64(uint64_t u1, uint64_t u0, uint64_t v,
}
#else
/* Code taken from Hacker's Delight, http://www.hackersdelight.org/HDcode/divlu.c . License permits inclusion here per http://www.hackersdelight.org/permissions.htm
*/
static uint64_t libdivide_128_div_64_to_64(uint64_t u1, uint64_t u0, uint64_t v, uint64_t *r) {
static uint64_t libdivide_128_div_64_to_64(uint64_t u1, uint64_t u0, uint64_t v, uint64_t *r) {
const uint64_t b = (1ULL << 32); // Number base (16 bits).
uint64_t un1, un0, // Norm. dividend LSD's.
vn1, vn0, // Norm. divisor digits.
@@ -476,25 +476,25 @@ static uint64_t libdivide_128_div_64_to_64(uint64_t u1, uint64_t u0, uint64_t v,
un64, un21, un10,// Dividend digit pairs.
rhat; // A remainder.
int s; // Shift amount for norm.
if (u1 >= v) { // If overflow, set rem.
if (r != NULL) // to an impossible value,
*r = (uint64_t)(-1); // and return the largest
return (uint64_t)(-1);} // possible quotient.
/* count leading zeros */
s = libdivide__count_leading_zeros64(v); // 0 <= s <= 63.
v = v << s; // Normalize divisor.
vn1 = v >> 32; // Break divisor up into
vn0 = v & 0xFFFFFFFF; // two 32-bit digits.
un64 = (u1 << s) | ((u0 >> (64 - s)) & (-s >> 31));
un10 = u0 << s; // Shift dividend left.
un1 = un10 >> 32; // Break right half of
un0 = un10 & 0xFFFFFFFF; // dividend into two digits.
q1 = un64/vn1; // Compute the first
rhat = un64 - q1*vn1; // quotient digit, q1.
again1:
@@ -502,9 +502,9 @@ again1:
q1 = q1 - 1;
rhat = rhat + vn1;
if (rhat < b) goto again1;}
un21 = un64*b + un1 - q1*v; // Multiply and subtract.
q0 = un21/vn1; // Compute the second
rhat = un21 - q0*vn1; // quotient digit, q0.
again2:
@@ -512,21 +512,21 @@ again2:
q0 = q0 - 1;
rhat = rhat + vn1;
if (rhat < b) goto again2;}
if (r != NULL) // If remainder is wanted,
*r = (un21*b + un0 - q0*v) >> s; // return it.
return q1*b + q0;
}
#endif
#if LIBDIVIDE_ASSERTIONS_ON
#define LIBDIVIDE_ASSERT(x) do { if (! (x)) { fprintf(stderr, "Assertion failure on line %ld: %s\n", (long)__LINE__, #x); exit(-1); } } while (0)
#else
#define LIBDIVIDE_ASSERT(x)
#define LIBDIVIDE_ASSERT(x)
#endif
#ifndef LIBDIVIDE_HEADER_ONLY
////////// UINT32
struct libdivide_u32_t libdivide_u32_gen(uint32_t d) {
@@ -537,14 +537,14 @@ struct libdivide_u32_t libdivide_u32_gen(uint32_t d) {
}
else {
const uint32_t floor_log_2_d = 31 - libdivide__count_leading_zeros32(d);
uint8_t more;
uint32_t rem, proposed_m;
proposed_m = libdivide_64_div_32_to_32(1U << floor_log_2_d, 0, d, &rem);
LIBDIVIDE_ASSERT(rem > 0 && rem < d);
const uint32_t e = d - rem;
/* This power works if e < 2**floor_log_2_d. */
if (e < (1U << floor_log_2_d)) {
/* This power works */
@@ -560,7 +560,7 @@ struct libdivide_u32_t libdivide_u32_gen(uint32_t d) {
result.magic = 1 + proposed_m;
result.more = more;
//result.more's shift should in general be ceil_log_2_d. But if we used the smaller power, we subtract one from the shift because we're using the smaller power. If we're using the larger power, we subtract one from the shift because it's taken care of by the add indicator. So floor_log_2_d happens to be correct in both cases.
}
return result;
}
@@ -582,23 +582,23 @@ uint32_t libdivide_u32_do(uint32_t numer, const struct libdivide_u32_t *denom) {
}
}
int libdivide_u32_get_algorithm(const struct libdivide_u32_t *denom) {
uint8_t more = denom->more;
if (more & LIBDIVIDE_U32_SHIFT_PATH) return 0;
else if (! (more & LIBDIVIDE_ADD_MARKER)) return 1;
else return 2;
}
uint32_t libdivide_u32_do_alg0(uint32_t numer, const struct libdivide_u32_t *denom) {
return numer >> (denom->more & LIBDIVIDE_32_SHIFT_MASK);
}
uint32_t libdivide_u32_do_alg1(uint32_t numer, const struct libdivide_u32_t *denom) {
uint32_t q = libdivide__mullhi_u32(denom->magic, numer);
return q >> denom->more;
}
}
uint32_t libdivide_u32_do_alg2(uint32_t numer, const struct libdivide_u32_t *denom) {
// denom->add != 0
uint32_t q = libdivide__mullhi_u32(denom->magic, numer);
@@ -608,8 +608,8 @@ uint32_t libdivide_u32_do_alg2(uint32_t numer, const struct libdivide_u32_t *den
#if LIBDIVIDE_USE_SSE2
#if LIBDIVIDE_USE_SSE2
__m128i libdivide_u32_do_vector(__m128i numers, const struct libdivide_u32_t *denom) {
uint8_t more = denom->more;
if (more & LIBDIVIDE_U32_SHIFT_PATH) {
@@ -622,7 +622,7 @@ __m128i libdivide_u32_do_vector(__m128i numers, const struct libdivide_u32_t *de
//return t >> denom->shift;
__m128i t = _mm_add_epi32(_mm_srli_epi32(_mm_sub_epi32(numers, q), 1), q);
return _mm_srl_epi32(t, libdivide_u32_to_m128i(more & LIBDIVIDE_32_SHIFT_MASK));
}
else {
//q >> denom->shift
@@ -647,7 +647,7 @@ __m128i libdivide_u32_do_vector_alg2(__m128i numers, const struct libdivide_u32_
}
#endif
/////////// UINT64
struct libdivide_u64_t libdivide_u64_gen(uint64_t d) {
@@ -658,14 +658,14 @@ struct libdivide_u64_t libdivide_u64_gen(uint64_t d) {
}
else {
const uint32_t floor_log_2_d = 63 - libdivide__count_leading_zeros64(d);
uint64_t proposed_m, rem;
uint8_t more;
proposed_m = libdivide_128_div_64_to_64(1ULL << floor_log_2_d, 0, d, &rem); //== (1 << (64 + floor_log_2_d)) / d
LIBDIVIDE_ASSERT(rem > 0 && rem < d);
const uint64_t e = d - rem;
/* This power works if e < 2**floor_log_2_d. */
if (e < (1ULL << floor_log_2_d)) {
/* This power works */
@@ -702,30 +702,30 @@ uint64_t libdivide_u64_do(uint64_t numer, const struct libdivide_u64_t *denom) {
}
}
int libdivide_u64_get_algorithm(const struct libdivide_u64_t *denom) {
uint8_t more = denom->more;
if (more & LIBDIVIDE_U64_SHIFT_PATH) return 0;
else if (! (more & LIBDIVIDE_ADD_MARKER)) return 1;
else return 2;
}
uint64_t libdivide_u64_do_alg0(uint64_t numer, const struct libdivide_u64_t *denom) {
return numer >> (denom->more & LIBDIVIDE_64_SHIFT_MASK);
return numer >> (denom->more & LIBDIVIDE_64_SHIFT_MASK);
}
uint64_t libdivide_u64_do_alg1(uint64_t numer, const struct libdivide_u64_t *denom) {
uint64_t q = libdivide__mullhi_u64(denom->magic, numer);
return q >> denom->more;
}
uint64_t libdivide_u64_do_alg2(uint64_t numer, const struct libdivide_u64_t *denom) {
uint64_t q = libdivide__mullhi_u64(denom->magic, numer);
uint64_t t = ((numer - q) >> 1) + q;
return t >> (denom->more & LIBDIVIDE_64_SHIFT_MASK);
}
#if LIBDIVIDE_USE_SSE2
#if LIBDIVIDE_USE_SSE2
__m128i libdivide_u64_do_vector(__m128i numers, const struct libdivide_u64_t * denom) {
uint8_t more = denom->more;
if (more & LIBDIVIDE_U64_SHIFT_PATH) {
@@ -761,11 +761,11 @@ __m128i libdivide_u64_do_vector_alg2(__m128i numers, const struct libdivide_u64_
return _mm_srl_epi64(t, libdivide_u32_to_m128i(denom->more & LIBDIVIDE_64_SHIFT_MASK));
}
#endif
/////////// SINT32
static inline int32_t libdivide__mullhi_s32(int32_t x, int32_t y) {
int64_t xl = x, yl = y;
@@ -775,7 +775,7 @@ static inline int32_t libdivide__mullhi_s32(int32_t x, int32_t y) {
struct libdivide_s32_t libdivide_s32_gen(int32_t d) {
struct libdivide_s32_t result;
/* If d is a power of 2, or negative a power of 2, we have to use a shift. This is especially important because the magic algorithm fails for -1. To check if d is a power of 2 or its inverse, it suffices to check whether its absolute value has exactly one bit set. This works even for INT_MIN, because abs(INT_MIN) == INT_MIN, and INT_MIN has one bit set and is a power of 2. */
uint32_t absD = (uint32_t)(d < 0 ? -d : d); //gcc optimizes this to the fast abs trick
if ((absD & (absD - 1)) == 0) { //check if exactly one bit is set, don't care if absD is 0 since that's divide by zero
@@ -784,14 +784,14 @@ struct libdivide_s32_t libdivide_s32_gen(int32_t d) {
}
else {
const uint32_t floor_log_2_d = 31 - libdivide__count_leading_zeros32(absD);
LIBDIVIDE_ASSERT(floor_log_2_d >= 1);
LIBDIVIDE_ASSERT(floor_log_2_d >= 1);
uint8_t more;
//the dividend here is 2**(floor_log_2_d + 31), so the low 32 bit word is 0 and the high word is floor_log_2_d - 1
uint32_t rem, proposed_m;
proposed_m = libdivide_64_div_32_to_32(1U << (floor_log_2_d - 1), 0, absD, &rem);
const uint32_t e = absD - rem;
/* We are going to start with a power of floor_log_2_d - 1. This works if works if e < 2**floor_log_2_d. */
if (e < (1U << floor_log_2_d)) {
/* This power works */
@@ -807,7 +807,7 @@ struct libdivide_s32_t libdivide_s32_gen(int32_t d) {
proposed_m += 1;
result.magic = (d < 0 ? -(int32_t)proposed_m : (int32_t)proposed_m);
result.more = more;
}
return result;
}
@@ -832,57 +832,57 @@ int32_t libdivide_s32_do(int32_t numer, const struct libdivide_s32_t *denom) {
q += (q < 0);
return q;
}
}
}
int libdivide_s32_get_algorithm(const struct libdivide_s32_t *denom) {
uint8_t more = denom->more;
int positiveDivisor = ! (more & LIBDIVIDE_NEGATIVE_DIVISOR);
if (more & LIBDIVIDE_S32_SHIFT_PATH) return (positiveDivisor ? 0 : 1);
else if (more & LIBDIVIDE_ADD_MARKER) return (positiveDivisor ? 2 : 3);
else if (more & LIBDIVIDE_ADD_MARKER) return (positiveDivisor ? 2 : 3);
else return 4;
}
int32_t libdivide_s32_do_alg0(int32_t numer, const struct libdivide_s32_t *denom) {
uint8_t shifter = denom->more & LIBDIVIDE_32_SHIFT_MASK;
int32_t q = numer + ((numer >> 31) & ((1 << shifter) - 1));
return q >> shifter;
}
int32_t libdivide_s32_do_alg1(int32_t numer, const struct libdivide_s32_t *denom) {
uint8_t shifter = denom->more & LIBDIVIDE_32_SHIFT_MASK;
int32_t q = numer + ((numer >> 31) & ((1 << shifter) - 1));
return - (q >> shifter);
}
int32_t libdivide_s32_do_alg2(int32_t numer, const struct libdivide_s32_t *denom) {
int32_t q = libdivide__mullhi_s32(denom->magic, numer);
q += numer;
q >>= denom->more & LIBDIVIDE_32_SHIFT_MASK;
q += (q < 0);
q += (q < 0);
return q;
}
int32_t libdivide_s32_do_alg3(int32_t numer, const struct libdivide_s32_t *denom) {
int32_t q = libdivide__mullhi_s32(denom->magic, numer);
q -= numer;
q >>= denom->more & LIBDIVIDE_32_SHIFT_MASK;
q += (q < 0);
return q;
}
int32_t libdivide_s32_do_alg4(int32_t numer, const struct libdivide_s32_t *denom) {
int32_t q = libdivide__mullhi_s32(denom->magic, numer);
q >>= denom->more & LIBDIVIDE_32_SHIFT_MASK;
q += (q < 0);
q += (q < 0);
return q;
}
#if LIBDIVIDE_USE_SSE2
int32_t libdivide_s32_do_alg4(int32_t numer, const struct libdivide_s32_t *denom) {
int32_t q = libdivide__mullhi_s32(denom->magic, numer);
q >>= denom->more & LIBDIVIDE_32_SHIFT_MASK;
q += (q < 0);
return q;
}
#if LIBDIVIDE_USE_SSE2
__m128i libdivide_s32_do_vector(__m128i numers, const struct libdivide_s32_t * denom) {
uint8_t more = denom->more;
if (more & LIBDIVIDE_S32_SHIFT_PATH) {
uint32_t shifter = more & LIBDIVIDE_32_SHIFT_MASK;
__m128i roundToZeroTweak = _mm_set1_epi32((1 << shifter) - 1); //could use _mm_srli_epi32 with an all -1 register
__m128i roundToZeroTweak = _mm_set1_epi32((1 << shifter) - 1); //could use _mm_srli_epi32 with an all -1 register
__m128i q = _mm_add_epi32(numers, _mm_and_si128(_mm_srai_epi32(numers, 31), roundToZeroTweak)); //q = numer + ((numer >> 31) & roundToZeroTweak);
q = _mm_sra_epi32(q, libdivide_u32_to_m128i(shifter)); // q = q >> shifter
__m128i shiftMask = _mm_set1_epi32((int32_t)((int8_t)more >> 7)); //set all bits of shift mask = to the sign bit of more
@@ -893,7 +893,7 @@ __m128i libdivide_s32_do_vector(__m128i numers, const struct libdivide_s32_t * d
__m128i q = libdivide_mullhi_s32_flat_vector(numers, _mm_set1_epi32(denom->magic));
if (more & LIBDIVIDE_ADD_MARKER) {
__m128i sign = _mm_set1_epi32((int32_t)(int8_t)more >> 7); //must be arithmetic shift
q = _mm_add_epi32(q, _mm_sub_epi32(_mm_xor_si128(numers, sign), sign)); // q += ((numer ^ sign) - sign);
q = _mm_add_epi32(q, _mm_sub_epi32(_mm_xor_si128(numers, sign), sign)); // q += ((numer ^ sign) - sign);
}
q = _mm_sra_epi32(q, libdivide_u32_to_m128i(more & LIBDIVIDE_32_SHIFT_MASK)); //q >>= shift
q = _mm_add_epi32(q, _mm_srli_epi32(q, 31)); // q += (q < 0)
@@ -919,7 +919,7 @@ __m128i libdivide_s32_do_vector_alg2(__m128i numers, const struct libdivide_s32_
__m128i q = libdivide_mullhi_s32_flat_vector(numers, _mm_set1_epi32(denom->magic));
q = _mm_add_epi32(q, numers);
q = _mm_sra_epi32(q, libdivide_u32_to_m128i(denom->more & LIBDIVIDE_32_SHIFT_MASK));
q = _mm_add_epi32(q, _mm_srli_epi32(q, 31));
q = _mm_add_epi32(q, _mm_srli_epi32(q, 31));
return q;
}
@@ -927,7 +927,7 @@ __m128i libdivide_s32_do_vector_alg3(__m128i numers, const struct libdivide_s32_
__m128i q = libdivide_mullhi_s32_flat_vector(numers, _mm_set1_epi32(denom->magic));
q = _mm_sub_epi32(q, numers);
q = _mm_sra_epi32(q, libdivide_u32_to_m128i(denom->more & LIBDIVIDE_32_SHIFT_MASK));
q = _mm_add_epi32(q, _mm_srli_epi32(q, 31));
q = _mm_add_epi32(q, _mm_srli_epi32(q, 31));
return q;
}
@@ -935,16 +935,16 @@ __m128i libdivide_s32_do_vector_alg4(__m128i numers, const struct libdivide_s32_
__m128i q = libdivide_mullhi_s32_flat_vector(numers, _mm_set1_epi32(denom->magic));
q = _mm_sra_epi32(q, libdivide_u32_to_m128i(denom->more)); //q >>= shift
q = _mm_add_epi32(q, _mm_srli_epi32(q, 31)); // q += (q < 0)
return q;
return q;
}
#endif
///////////// SINT64
struct libdivide_s64_t libdivide_s64_gen(int64_t d) {
struct libdivide_s64_t result;
/* If d is a power of 2, or negative a power of 2, we have to use a shift. This is especially important because the magic algorithm fails for -1. To check if d is a power of 2 or its inverse, it suffices to check whether its absolute value has exactly one bit set. This works even for INT_MIN, because abs(INT_MIN) == INT_MIN, and INT_MIN has one bit set and is a power of 2. */
const uint64_t absD = (uint64_t)(d < 0 ? -d : d); //gcc optimizes this to the fast abs trick
if ((absD & (absD - 1)) == 0) { //check if exactly one bit is set, don't care if absD is 0 since that's divide by zero
@@ -952,14 +952,14 @@ struct libdivide_s64_t libdivide_s64_gen(int64_t d) {
result.magic = 0;
}
else {
const uint32_t floor_log_2_d = 63 - libdivide__count_leading_zeros64(absD);
const uint32_t floor_log_2_d = 63 - libdivide__count_leading_zeros64(absD);
//the dividend here is 2**(floor_log_2_d + 63), so the low 64 bit word is 0 and the high word is floor_log_2_d - 1
uint8_t more;
uint64_t rem, proposed_m;
proposed_m = libdivide_128_div_64_to_64(1ULL << (floor_log_2_d - 1), 0, absD, &rem);
const uint64_t e = absD - rem;
/* We are going to start with a power of floor_log_2_d - 1. This works if works if e < 2**floor_log_2_d. */
if (e < (1ULL << floor_log_2_d)) {
/* This power works */
@@ -1000,9 +1000,9 @@ int64_t libdivide_s64_do(int64_t numer, const struct libdivide_s64_t *denom) {
q += (q < 0);
return q;
}
}
}
int libdivide_s64_get_algorithm(const struct libdivide_s64_t *denom) {
uint8_t more = denom->more;
int positiveDivisor = ! (more & LIBDIVIDE_NEGATIVE_DIVISOR);
@@ -1010,20 +1010,20 @@ int libdivide_s64_get_algorithm(const struct libdivide_s64_t *denom) {
else if (more & LIBDIVIDE_ADD_MARKER) return (positiveDivisor ? 2 : 3);
else return 4;
}
int64_t libdivide_s64_do_alg0(int64_t numer, const struct libdivide_s64_t *denom) {
uint32_t shifter = denom->more & LIBDIVIDE_64_SHIFT_MASK;
int64_t q = numer + ((numer >> 63) & ((1LL << shifter) - 1));
return q >> shifter;
return q >> shifter;
}
int64_t libdivide_s64_do_alg1(int64_t numer, const struct libdivide_s64_t *denom) {
//denom->shifter != -1 && demo->shiftMask != 0
uint32_t shifter = denom->more & LIBDIVIDE_64_SHIFT_MASK;
int64_t q = numer + ((numer >> 63) & ((1LL << shifter) - 1));
return - (q >> shifter);
}
int64_t libdivide_s64_do_alg2(int64_t numer, const struct libdivide_s64_t *denom) {
int64_t q = libdivide__mullhi_s64(denom->magic, numer);
q += numer;
@@ -1031,20 +1031,20 @@ int64_t libdivide_s64_do_alg2(int64_t numer, const struct libdivide_s64_t *denom
q += (q < 0);
return q;
}
int64_t libdivide_s64_do_alg3(int64_t numer, const struct libdivide_s64_t *denom) {
int64_t q = libdivide__mullhi_s64(denom->magic, numer);
q -= numer;
q >>= denom->more & LIBDIVIDE_64_SHIFT_MASK;
q += (q < 0);
q += (q < 0);
return q;
}
int64_t libdivide_s64_do_alg4(int64_t numer, const struct libdivide_s64_t *denom) {
int64_t q = libdivide__mullhi_s64(denom->magic, numer);
q >>= denom->more;
q += (q < 0);
return q;
return q;
}
@@ -1065,7 +1065,7 @@ __m128i libdivide_s64_do_vector(__m128i numers, const struct libdivide_s64_t * d
__m128i q = libdivide_mullhi_s64_flat_vector(numers, libdivide__u64_to_m128(magic));
if (more & LIBDIVIDE_ADD_MARKER) {
__m128i sign = _mm_set1_epi32((int32_t)((int8_t)more >> 7)); //must be arithmetic shift
q = _mm_add_epi64(q, _mm_sub_epi64(_mm_xor_si128(numers, sign), sign)); // q += ((numer ^ sign) - sign);
q = _mm_add_epi64(q, _mm_sub_epi64(_mm_xor_si128(numers, sign), sign)); // q += ((numer ^ sign) - sign);
}
q = libdivide_s64_shift_right_vector(q, more & LIBDIVIDE_64_SHIFT_MASK); //q >>= denom->mult_path.shift
q = _mm_add_epi64(q, _mm_srli_epi64(q, 63)); // q += (q < 0)
@@ -1102,20 +1102,20 @@ __m128i libdivide_s64_do_vector_alg3(__m128i numers, const struct libdivide_s64_
q = _mm_sub_epi64(q, numers);
q = libdivide_s64_shift_right_vector(q, denom->more & LIBDIVIDE_64_SHIFT_MASK);
q = _mm_add_epi64(q, _mm_srli_epi64(q, 63)); // q += (q < 0)
return q;
return q;
}
__m128i libdivide_s64_do_vector_alg4(__m128i numers, const struct libdivide_s64_t *denom) {
__m128i q = libdivide_mullhi_s64_flat_vector(numers, libdivide__u64_to_m128(denom->magic));
q = libdivide_s64_shift_right_vector(q, denom->more);
q = _mm_add_epi64(q, _mm_srli_epi64(q, 63));
return q;
return q;
}
#endif
/////////// C++ stuff
#ifdef __cplusplus
/* The C++ template design here is a total mess. This needs to be fixed by someone better at templates than I. The current design is:
@@ -1131,7 +1131,7 @@ __m128i libdivide_s64_do_vector_alg4(__m128i numers, const struct libdivide_s64_
*/
namespace libdivide_internal {
#if LIBDIVIDE_USE_SSE2
#define MAYBE_VECTOR(x) x
#define MAYBE_VECTOR_PARAM __m128i vector_func(__m128i, const DenomType *)
@@ -1149,12 +1149,12 @@ namespace libdivide_internal {
#endif
template<typename IntType, typename DenomType, DenomType gen_func(IntType), int get_algo(const DenomType *), IntType do_func(IntType, const DenomType *), MAYBE_VECTOR_PARAM>
class divider_base {
class divider_base {
public:
DenomType denom;
divider_base(IntType d) : denom(gen_func(d)) { }
divider_base(const DenomType & d) : denom(d) { }
IntType perform_divide(IntType val) const { return do_func(val, &denom); }
#if LIBDIVIDE_USE_SSE2
__m128i perform_divide_vector(__m128i val) const { return vector_func(val, &denom); }
@@ -1162,37 +1162,37 @@ namespace libdivide_internal {
int get_algorithm() const { return get_algo(&denom); }
};
template<class T> struct divider_mid { };
template<> struct divider_mid<uint32_t> {
typedef uint32_t IntType;
typedef struct libdivide_u32_t DenomType;
template<IntType do_func(IntType, const DenomType *), MAYBE_VECTOR_PARAM> struct denom {
typedef divider_base<IntType, DenomType, libdivide_u32_gen, libdivide_u32_get_algorithm, do_func, vector_func> divider;
};
template<int ALGO, int J = 0> struct algo { };
template<int J> struct algo<-1, J> { typedef denom<libdivide_u32_do, MAYBE_VECTOR(libdivide_u32_do_vector)>::divider divider; };
template<int J> struct algo<0, J> { typedef denom<libdivide_u32_do_alg0, MAYBE_VECTOR(libdivide_u32_do_vector_alg0)>::divider divider; };
template<int J> struct algo<1, J> { typedef denom<libdivide_u32_do_alg1, MAYBE_VECTOR(libdivide_u32_do_vector_alg1)>::divider divider; };
template<int J> struct algo<2, J> { typedef denom<libdivide_u32_do_alg2, MAYBE_VECTOR(libdivide_u32_do_vector_alg2)>::divider divider; };
/* Define two more bogus ones so that the same (templated, presumably) code can handle both signed and unsigned */
/* Define two more bogus ones so that the same (templated, presumably) code can handle both signed and unsigned */
template<int J> struct algo<3, J> { typedef denom<crash_u32, MAYBE_VECTOR(crash_u32_vector)>::divider divider; };
template<int J> struct algo<4, J> { typedef denom<crash_u32, MAYBE_VECTOR(crash_u32_vector)>::divider divider; };
};
template<> struct divider_mid<int32_t> {
typedef int32_t IntType;
typedef struct libdivide_s32_t DenomType;
template<IntType do_func(IntType, const DenomType *), MAYBE_VECTOR_PARAM> struct denom {
typedef divider_base<IntType, DenomType, libdivide_s32_gen, libdivide_s32_get_algorithm, do_func, vector_func> divider;
};
template<int ALGO, int J = 0> struct algo { };
template<int J> struct algo<-1, J> { typedef denom<libdivide_s32_do, MAYBE_VECTOR(libdivide_s32_do_vector)>::divider divider; };
template<int J> struct algo<0, J> { typedef denom<libdivide_s32_do_alg0, MAYBE_VECTOR(libdivide_s32_do_vector_alg0)>::divider divider; };
@@ -1200,36 +1200,36 @@ namespace libdivide_internal {
template<int J> struct algo<2, J> { typedef denom<libdivide_s32_do_alg2, MAYBE_VECTOR(libdivide_s32_do_vector_alg2)>::divider divider; };
template<int J> struct algo<3, J> { typedef denom<libdivide_s32_do_alg3, MAYBE_VECTOR(libdivide_s32_do_vector_alg3)>::divider divider; };
template<int J> struct algo<4, J> { typedef denom<libdivide_s32_do_alg4, MAYBE_VECTOR(libdivide_s32_do_vector_alg4)>::divider divider; };
};
template<> struct divider_mid<uint64_t> {
typedef uint64_t IntType;
typedef struct libdivide_u64_t DenomType;
template<IntType do_func(IntType, const DenomType *), MAYBE_VECTOR_PARAM> struct denom {
typedef divider_base<IntType, DenomType, libdivide_u64_gen, libdivide_u64_get_algorithm, do_func, vector_func> divider;
};
template<int ALGO, int J = 0> struct algo { };
template<int J> struct algo<-1, J> { typedef denom<libdivide_u64_do, MAYBE_VECTOR(libdivide_u64_do_vector)>::divider divider; };
template<int J> struct algo<0, J> { typedef denom<libdivide_u64_do_alg0, MAYBE_VECTOR(libdivide_u64_do_vector_alg0)>::divider divider; };
template<int J> struct algo<1, J> { typedef denom<libdivide_u64_do_alg1, MAYBE_VECTOR(libdivide_u64_do_vector_alg1)>::divider divider; };
template<int J> struct algo<2, J> { typedef denom<libdivide_u64_do_alg2, MAYBE_VECTOR(libdivide_u64_do_vector_alg2)>::divider divider; };
/* Define two more bogus ones so that the same (templated, presumably) code can handle both signed and unsigned */
template<int J> struct algo<3, J> { typedef denom<crash_u64, MAYBE_VECTOR(crash_u64_vector)>::divider divider; };
template<int J> struct algo<4, J> { typedef denom<crash_u64, MAYBE_VECTOR(crash_u64_vector)>::divider divider; };
};
template<> struct divider_mid<int64_t> {
typedef int64_t IntType;
typedef struct libdivide_s64_t DenomType;
template<IntType do_func(IntType, const DenomType *), MAYBE_VECTOR_PARAM> struct denom {
typedef divider_base<IntType, DenomType, libdivide_s64_gen, libdivide_s64_get_algorithm, do_func, vector_func> divider;
};
template<int ALGO, int J = 0> struct algo { };
template<int J> struct algo<-1, J> { typedef denom<libdivide_s64_do, MAYBE_VECTOR(libdivide_s64_do_vector)>::divider divider; };
template<int J> struct algo<0, J> { typedef denom<libdivide_s64_do_alg0, MAYBE_VECTOR(libdivide_s64_do_vector_alg0)>::divider divider; };
@@ -1248,29 +1248,29 @@ class divider
typename libdivide_internal::divider_mid<T>::template algo<ALGO>::divider sub;
template<int NEW_ALGO, typename S> friend divider<S, NEW_ALGO> unswitch(const divider<S, -1> & d);
divider(const typename libdivide_internal::divider_mid<T>::DenomType & denom) : sub(denom) { }
public:
/* Ordinary constructor, that takes the divisor as a parameter. */
divider(T n) : sub(n) { }
/* Default constructor, that divides by 1 */
divider() : sub(1) { }
/* Divides the parameter by the divisor, returning the quotient */
T perform_divide(T val) const { return sub.perform_divide(val); }
#if LIBDIVIDE_USE_SSE2
/* Treats the vector as either two or four packed values (depending on the size), and divides each of them by the divisor, returning the packed quotients. */
__m128i perform_divide_vector(__m128i val) const { return sub.perform_divide_vector(val); }
__m128i perform_divide_vector(__m128i val) const { return sub.perform_divide_vector(val); }
#endif
/* Returns the index of algorithm, for use in the unswitch function */
int get_algorithm() const { return sub.get_algorithm(); } // returns the algorithm for unswitching
/* operator== */
bool operator==(const divider<T, ALGO> & him) const { return sub.denom.magic == him.sub.denom.magic && sub.denom.more == him.sub.denom.more; }
bool operator!=(const divider<T, ALGO> & him) const { return ! (*this == him); }
};
@@ -1291,10 +1291,10 @@ __m128i operator/(__m128i numer, const divider<int_type, ALGO> & denom) {
return denom.perform_divide_vector(numer);
}
#endif
#endif //__cplusplus
#endif //LIBDIVIDE_HEADER_ONLY
#ifdef __cplusplus
} //close namespace libdivide