From 238a7237f6908638939de5245fd36380de35538e Mon Sep 17 00:00:00 2001 From: Tropical <42101043+tropicaaal@users.noreply.github.com> Date: Wed, 1 Apr 2026 09:43:09 -0500 Subject: [PATCH] nuke libdivide --- minecraft/Minecraft.World/include/libdivide.h | 1704 ----------------- 1 file changed, 1704 deletions(-) delete mode 100644 minecraft/Minecraft.World/include/libdivide.h diff --git a/minecraft/Minecraft.World/include/libdivide.h b/minecraft/Minecraft.World/include/libdivide.h deleted file mode 100644 index f2a55b186..000000000 --- a/minecraft/Minecraft.World/include/libdivide.h +++ /dev/null @@ -1,1704 +0,0 @@ -/* libdivide.h - Copyright 2010 ridiculous_fish -*/ - -#if defined(_WIN32) || defined(WIN32) -#define LIBDIVIDE_WINDOWS 1 -#endif - -#if defined(_MSC_VER) -#define LIBDIVIDE_VC 1 -#endif - -#ifdef __cplusplus -#include -#include -#include -#else -#include -#include -#include -#endif - -#if !LIBDIVIDE_HAS_STDINT_TYPES && !LIBDIVIDE_VC -/* Visual C++ still doesn't ship with stdint.h (!) */ -#include -#define LIBDIVIDE_HAS_STDINT_TYPES 1 -#endif - -#if !LIBDIVIDE_HAS_STDINT_TYPES -typedef __int32 int32_t; -typedef unsigned __int32 uint32_t; -typedef __int64 int64_t; -typedef unsigned __int64 uint64_t; -typedef __int8 int8_t; -typedef unsigned __int8 uint8_t; -#endif - -#if LIBDIVIDE_USE_SSE2 -#if LIBDIVIDE_VC -#include -#endif -#include -#endif - -#ifndef __has_builtin -#define __has_builtin(x) 0 // Compatibility with non-clang compilers. -#endif - -#ifdef __ICC -#define HAS_INT128_T 0 -#else -#define HAS_INT128_T __LP64__ -#endif - -#if defined(__x86_64__) || defined(_WIN64) || defined(_M_64) -#define LIBDIVIDE_IS_X86_64 1 -#endif - -#if defined(__i386__) -#define LIBDIVIDE_IS_i386 1 -#endif - -#if __GNUC__ || __clang__ -#define LIBDIVIDE_GCC_STYLE_ASM 1 -#endif - -/* libdivide may use the pmuldq (vector signed 32x32->64 mult instruction) which - * is in SSE 4.1. However, signed multiplication can be emulated efficiently - * with unsigned multiplication, and SSE 4.1 is currently rare, so it is OK to - * not turn this on */ -#ifdef LIBDIVIDE_USE_SSE4_1 -#include -#endif - -#ifdef __cplusplus -/* We place libdivide within the libdivide namespace, and that goes in an - * anonymous namespace so that the functions are only visible to files that - * #include this header and don't get external linkage. At least that's the - * theory. */ -namespace { -namespace libdivide { -#endif - -/* Explanation of "more" field: bit 6 is whether to use shift path. If we are -using the shift path, bit 7 is whether the divisor is negative in the signed -case; in the unsigned case it is 0. Bits 0-4 is shift value (for shift path or -mult path). In 32 bit case, bit 5 is always 0. We use bit 7 as the "negative -divisor indicator" so that we can use sign extension to efficiently go to a -full-width -1. - - -u32: [0-4] shift value - [5] ignored - [6] add indicator - [7] shift path - -s32: [0-4] shift value - [5] shift path - [6] add indicator - [7] indicates negative divisor - -u64: [0-5] shift value - [6] add indicator - [7] shift path - -s64: [0-5] shift value - [6] add indicator - [7] indicates negative divisor - magic number of 0 indicates shift path (we ran out of bits!) -*/ - -enum { - LIBDIVIDE_32_SHIFT_MASK = 0x1F, - LIBDIVIDE_64_SHIFT_MASK = 0x3F, - LIBDIVIDE_ADD_MARKER = 0x40, - LIBDIVIDE_U32_SHIFT_PATH = 0x80, - LIBDIVIDE_U64_SHIFT_PATH = 0x80, - LIBDIVIDE_S32_SHIFT_PATH = 0x20, - LIBDIVIDE_NEGATIVE_DIVISOR = 0x80 -}; - -struct libdivide_u32_t { - uint32_t magic; - uint8_t more; -}; - -struct libdivide_s32_t { - int32_t magic; - uint8_t more; -}; - -struct libdivide_u64_t { - uint64_t magic; - uint8_t more; -}; - -struct libdivide_s64_t { - int64_t magic; - uint8_t more; -}; - -#ifndef LIBDIVIDE_API -#ifdef __cplusplus -/* In C++, we don't want our public functions to be static, because they are - * arguments to templates and static functions can't do that. They get internal - * linkage through virtue of the anonymous namespace. In C, they should be - * static. */ -#define LIBDIVIDE_API -#else -#define LIBDIVIDE_API static -#endif -#endif - -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); -LIBDIVIDE_API uint64_t libdivide_u64_do(uint64_t y, - const struct libdivide_u64_t* denom); - -LIBDIVIDE_API int libdivide_u32_get_algorithm( - const struct libdivide_u32_t* denom); -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); -LIBDIVIDE_API int64_t -libdivide_s64_do_alg2(int64_t numer, const struct libdivide_s64_t* denom); -LIBDIVIDE_API int64_t -libdivide_s64_do_alg3(int64_t numer, const struct libdivide_s64_t* denom); -LIBDIVIDE_API int64_t -libdivide_s64_do_alg4(int64_t numer, const struct libdivide_s64_t* denom); - -#if LIBDIVIDE_USE_SSE2 -LIBDIVIDE_API __m128i -libdivide_u32_do_vector(__m128i numers, const struct libdivide_u32_t* denom); -LIBDIVIDE_API __m128i -libdivide_s32_do_vector(__m128i numers, const struct libdivide_s32_t* denom); -LIBDIVIDE_API __m128i -libdivide_u64_do_vector(__m128i numers, const struct libdivide_u64_t* denom); -LIBDIVIDE_API __m128i -libdivide_s64_do_vector(__m128i numers, const struct libdivide_s64_t* denom); - -LIBDIVIDE_API __m128i libdivide_u32_do_vector_alg0( - __m128i numers, const struct libdivide_u32_t* denom); -LIBDIVIDE_API __m128i libdivide_u32_do_vector_alg1( - __m128i numers, const struct libdivide_u32_t* denom); -LIBDIVIDE_API __m128i libdivide_u32_do_vector_alg2( - __m128i numers, const struct libdivide_u32_t* denom); - -LIBDIVIDE_API __m128i libdivide_s32_do_vector_alg0( - __m128i numers, const struct libdivide_s32_t* denom); -LIBDIVIDE_API __m128i libdivide_s32_do_vector_alg1( - __m128i numers, const struct libdivide_s32_t* denom); -LIBDIVIDE_API __m128i libdivide_s32_do_vector_alg2( - __m128i numers, const struct libdivide_s32_t* denom); -LIBDIVIDE_API __m128i libdivide_s32_do_vector_alg3( - __m128i numers, const struct libdivide_s32_t* denom); -LIBDIVIDE_API __m128i libdivide_s32_do_vector_alg4( - __m128i numers, const struct libdivide_s32_t* denom); - -LIBDIVIDE_API __m128i libdivide_u64_do_vector_alg0( - __m128i numers, const struct libdivide_u64_t* denom); -LIBDIVIDE_API __m128i libdivide_u64_do_vector_alg1( - __m128i numers, const struct libdivide_u64_t* denom); -LIBDIVIDE_API __m128i libdivide_u64_do_vector_alg2( - __m128i numers, const struct libdivide_u64_t* denom); - -LIBDIVIDE_API __m128i libdivide_s64_do_vector_alg0( - __m128i numers, const struct libdivide_s64_t* denom); -LIBDIVIDE_API __m128i libdivide_s64_do_vector_alg1( - __m128i numers, const struct libdivide_s64_t* denom); -LIBDIVIDE_API __m128i libdivide_s64_do_vector_alg2( - __m128i numers, const struct libdivide_s64_t* denom); -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; - __uint128_t rl = xl * yl; - return (uint64_t)(rl >> 64); -#else - // full 128 bits are x0 * y0 + (x0 * y1 << 32) + (x1 * y0 << 32) + (x1 * y1 - // << 64) - const uint32_t mask = 0xFFFFFFFF; - const uint32_t x0 = (uint32_t)(x & mask), x1 = (uint32_t)(x >> 32); - const uint32_t y0 = (uint32_t)(y & mask), y1 = (uint32_t)(y >> 32); - const uint32_t x0y0_hi = libdivide__mullhi_u32(x0, y0); - 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); -#else - // full 128 bits are x0 * y0 + (x0 * y1 << 32) + (x1 * y0 << 32) + (x1 * y1 - // << 64) - const uint32_t mask = 0xFFFFFFFF; - const uint32_t x0 = (uint32_t)(x & mask), y0 = (uint32_t)(y & mask); - const int32_t x1 = (int32_t)(x >> 32), y1 = (int32_t)(y >> 32); - const uint32_t x0y0_hi = libdivide__mullhi_u32(x0, y0); - const int64_t t = x1 * (int64_t)y0 + x0y0_hi; - const int64_t w1 = x0 * (int64_t)y1 + (t & mask); - return x1 * (int64_t)y1 + (t >> 32) + (w1 >> 32); -#endif -} - -#if LIBDIVIDE_USE_SSE2 - -static inline __m128i libdivide__u64_to_m128(uint64_t x) { -#if LIBDIVIDE_VC - // 64 bit windows doesn't seem to have an implementation of any of these - // load intrinsics, and 32 bit Visual C++ crashes - _declspec(align(16)) uint64_t temp[2] = {x, x}; - return _mm_load_si128((const __m128i*)temp); -#elif defined(__ICC) - uint64_t __attribute__((aligned(16))) temp[2] = {x, x}; - return _mm_load_si128((const __m128i*)temp); -#elif __clang__ - // clang does not provide this intrinsic either - return (__m128i){x, x}; -#else - // everyone else gets it right - return _mm_set1_epi64x(x); -#endif -} - -static inline __m128i libdivide_get_FFFFFFFF00000000(void) { - // returns the same as _mm_set1_epi64(0xFFFFFFFF00000000ULL) without - // touching memory - __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 - result = _mm_srli_epi64(result, 32); - return result; -} - -static inline __m128i libdivide_get_0000FFFF(void) { - // returns the same as _mm_set1_epi32(0x0000FFFFULL) without touching memory - __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; -} - -static inline __m128i libdivide_s64_signbits(__m128i v) { - // we want to compute v >> 63, that is, _mm_srai_epi64(v, 63). But there is - // no 64 bit shift right arithmetic instruction in SSE2. So we have to fake - // it by first duplicating the high 32 bit values, and then using a 32 bit - // shift. Another option would be to use _mm_srli_epi64(v, 63) and then - // subtract that from 0, but that approach appears to be substantially - // slower for unknown reasons - __m128i hiBitsDuped = _mm_shuffle_epi32(v, _MM_SHUFFLE(3, 3, 1, 1)); - __m128i signBits = _mm_srai_epi32(hiBitsDuped, 31); - return signBits; -} - -/* Returns an __m128i whose low 32 bits are equal to amt and has zero elsewhere. - */ -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; - __m128i m = libdivide__u64_to_m128(1ULL << (b - 1)); - __m128i x = _mm_srl_epi64(v, libdivide_u32_to_m128i(amt)); - __m128i result = _mm_sub_epi64(_mm_xor_si128(x, m), m); // result = x^m - m - return result; -} - -/* Here, b is assumed to contain one 32 bit value repeated four times. If it - * did not, the function would not work. */ -static inline __m128i libdivide__mullhi_u32_flat_vector(__m128i a, __m128i b) { - __m128i hi_product_0Z2Z = _mm_srli_epi64(_mm_mul_epu32(a, b), 32); - __m128i a1X3X = _mm_srli_epi64(a, 32); - __m128i hi_product_Z1Z3 = _mm_and_si128(_mm_mul_epu32(a1X3X, b), - libdivide_get_FFFFFFFF00000000()); - 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) - const __m128i mask = libdivide_get_00000000FFFFFFFF(); - const __m128i x0 = _mm_and_si128(x, mask), - x1 = _mm_srli_epi64( - x, 32); // x0 is low half of 2 64 bit values, x1 is high - // half in low slots - const __m128i y0 = _mm_and_si128(y, mask), y1 = _mm_srli_epi64(y, 32); - const __m128i x0y0_hi = _mm_srli_epi64( - _mm_mul_epu32(x0, y0), - 32); // x0 happens to have the low half of the two 64 bit values in 32 - // bit slots 0 and 2, so _mm_mul_epu32 computes their full - // product, and then we shift right by 32 to get just the high - // values - 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); -} - -/* y is one 64 bit value repeated twice */ -static inline __m128i libdivide_mullhi_s64_flat_vector(__m128i x, __m128i y) { - __m128i p = libdivide_mullhi_u64_flat_vector(x, y); - __m128i t1 = _mm_and_si128(libdivide_s64_signbits(x), y); - p = _mm_sub_epi64(p, t1); - __m128i t2 = _mm_and_si128(libdivide_s64_signbits(y), x); - 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); - __m128i a1X3X = _mm_srli_epi64(a, 32); - __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. */ -static inline __m128i libdivide_mullhi_s32_flat_vector(__m128i a, __m128i b) { - __m128i p = libdivide__mullhi_u32_flat_vector(a, b); - __m128i t1 = _mm_and_si128(_mm_srai_epi32(a, 31), - b); // t1 = (a >> 31) & y, arithmetic shift - __m128i t2 = _mm_and_si128(_mm_srai_epi32(b, 31), a); - p = _mm_sub_epi32(p, t1); - p = _mm_sub_epi32(p, t2); - return p; -} -#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 */ - return __builtin_ctz(val); -#else - /* Dorky way to count trailing zeros. Note that this hangs for val = 0! */ - int32_t result = 0; - val = (val ^ (val - 1)) >> 1; // Set v's trailing 0s to 1s and zero rest - while (val) { - val >>= 1; - result++; - } - 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. */ - return __builtin_ctzll(val); -#else - /* Pretty good way to count trailing zeros. Note that this hangs for val = - * 0! */ - uint32_t lo = val & 0xFFFFFFFF; - if (lo != 0) return libdivide__count_trailing_zeros32(lo); - 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); -#else - /* Dorky way to count leading zeros. Note that this hangs for val = 0! */ - int32_t result = 0; - while (!(val & (1U << 31))) { - val <<= 1; - 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 */ - return __builtin_clzll(val); -#else - /* Dorky way to count leading zeros. Note that this hangs for val = 0! */ - int32_t result = 0; - while (!(val & (1ULL << 63))) { - val <<= 1; - result++; - } - return result; -#endif -} - -// libdivide_64_div_32_to_32: divides a 64 bit uint {u1, u0} by a 32 bit uint -// {v}. The result must fit in 32 bits. Returns the quotient directly and the -// remainder in *r -#if (LIBDIVIDE_IS_i386 || LIBDIVIDE_IS_X86_64) && LIBDIVIDE_GCC_STYLE_ASM -static uint32_t libdivide_64_div_32_to_32(uint32_t u1, uint32_t u0, uint32_t v, - uint32_t* r) { - uint32_t result; - __asm__("divl %[v]" - : "=a"(result), "=d"(*r) - : [v] "r"(v), "a"(u0), "d"(u1)); - return result; -} -#else -static uint32_t libdivide_64_div_32_to_32(uint32_t u1, uint32_t u0, uint32_t v, - uint32_t* r) { - uint64_t n = (((uint64_t)u1) << 32) | u0; - uint32_t result = (uint32_t)(n / v); - *r = (uint32_t)(n - result * (uint64_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 - // u1 -> rdx - // divq - uint64_t result; - __asm__("divq %[v]" - : "=a"(result), "=d"(*r) - : [v] "r"(v), "a"(u0), "d"(u1)); - return result; -} -#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) { - const uint64_t b = (1ULL << 32); // Number base (16 bits). - uint64_t un1, un0, // Norm. dividend LSD's. - vn1, vn0, // Norm. divisor digits. - q1, q0, // Quotient digits. - un64, un21, un10, // Dividend digit pairs. - rhat; // A remainder. - int s; // Shift amount for norm. - - if (u1 >= v) { // If overflow, set rem. - if (r != nullptr) // 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: - if (q1 >= b || q1 * vn0 > b * rhat + un1) { - 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: - if (q0 >= b || q0 * vn0 > b * rhat + un0) { - q0 = q0 - 1; - rhat = rhat + vn1; - if (rhat < b) goto again2; - } - - if (r != nullptr) // 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) -#endif - -#ifndef LIBDIVIDE_HEADER_ONLY - -////////// UINT32 - -struct libdivide_u32_t libdivide_u32_gen(uint32_t d) { - struct libdivide_u32_t result; - if ((d & (d - 1)) == 0) { - result.magic = 0; - result.more = - libdivide__count_trailing_zeros32(d) | LIBDIVIDE_U32_SHIFT_PATH; - } 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 */ - more = floor_log_2_d; - } else { - /* We have to use the general 33-bit algorithm. We need to compute - * (2**power) / d. However, we already have (2**(power-1))/d and its - * remainder. By doubling both, and then correcting the remainder, - * we can compute the larger division. */ - proposed_m += proposed_m; // don't care about overflow here - in - // fact, we expect it - const uint32_t twice_rem = rem + rem; - if (twice_rem >= d || twice_rem < rem) proposed_m += 1; - more = floor_log_2_d | LIBDIVIDE_ADD_MARKER; - } - 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; -} - -uint32_t libdivide_u32_do(uint32_t numer, const struct libdivide_u32_t* denom) { - uint8_t more = denom->more; - if (more & LIBDIVIDE_U32_SHIFT_PATH) { - return numer >> (more & LIBDIVIDE_32_SHIFT_MASK); - } else { - uint32_t q = libdivide__mullhi_u32(denom->magic, numer); - if (more & LIBDIVIDE_ADD_MARKER) { - uint32_t t = ((numer - q) >> 1) + q; - return t >> (more & LIBDIVIDE_32_SHIFT_MASK); - } else { - return q >> - more; // all upper bits are 0 - don't need to mask them off - } - } -} - -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); - uint32_t t = ((numer - q) >> 1) + q; - return t >> (denom->more & LIBDIVIDE_32_SHIFT_MASK); -} - -#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) { - return _mm_srl_epi32( - numers, libdivide_u32_to_m128i(more & LIBDIVIDE_32_SHIFT_MASK)); - } else { - __m128i q = libdivide__mullhi_u32_flat_vector( - numers, _mm_set1_epi32(denom->magic)); - if (more & LIBDIVIDE_ADD_MARKER) { - // uint32_t t = ((numer - q) >> 1) + q; - // 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 - return _mm_srl_epi32(q, libdivide_u32_to_m128i(more)); - } - } -} - -__m128i libdivide_u32_do_vector_alg0(__m128i numers, - const struct libdivide_u32_t* denom) { - return _mm_srl_epi32( - numers, libdivide_u32_to_m128i(denom->more & LIBDIVIDE_32_SHIFT_MASK)); -} - -__m128i libdivide_u32_do_vector_alg1(__m128i numers, - const struct libdivide_u32_t* denom) { - __m128i q = - libdivide__mullhi_u32_flat_vector(numers, _mm_set1_epi32(denom->magic)); - return _mm_srl_epi32(q, libdivide_u32_to_m128i(denom->more)); -} - -__m128i libdivide_u32_do_vector_alg2(__m128i numers, - const struct libdivide_u32_t* denom) { - __m128i q = - libdivide__mullhi_u32_flat_vector(numers, _mm_set1_epi32(denom->magic)); - __m128i t = _mm_add_epi32(_mm_srli_epi32(_mm_sub_epi32(numers, q), 1), q); - return _mm_srl_epi32( - t, libdivide_u32_to_m128i(denom->more & LIBDIVIDE_32_SHIFT_MASK)); -} - -#endif - -/////////// UINT64 - -struct libdivide_u64_t libdivide_u64_gen(uint64_t d) { - struct libdivide_u64_t result; - if ((d & (d - 1)) == 0) { - result.more = - libdivide__count_trailing_zeros64(d) | LIBDIVIDE_U64_SHIFT_PATH; - result.magic = 0; - } 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 */ - more = floor_log_2_d; - } else { - /* We have to use the general 65-bit algorithm. We need to compute - * (2**power) / d. However, we already have (2**(power-1))/d and its - * remainder. By doubling both, and then correcting the remainder, - * we can compute the larger division. */ - proposed_m += proposed_m; // don't care about overflow here - in - // fact, we expect it - const uint64_t twice_rem = rem + rem; - if (twice_rem >= d || twice_rem < rem) proposed_m += 1; - more = floor_log_2_d | LIBDIVIDE_ADD_MARKER; - } - 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, which is why we - // do it outside of the if statement. - } - return result; -} - -uint64_t libdivide_u64_do(uint64_t numer, const struct libdivide_u64_t* denom) { - uint8_t more = denom->more; - if (more & LIBDIVIDE_U64_SHIFT_PATH) { - return numer >> (more & LIBDIVIDE_64_SHIFT_MASK); - } else { - uint64_t q = libdivide__mullhi_u64(denom->magic, numer); - if (more & LIBDIVIDE_ADD_MARKER) { - uint64_t t = ((numer - q) >> 1) + q; - return t >> (more & LIBDIVIDE_64_SHIFT_MASK); - } else { - return q >> - more; // all upper bits are 0 - don't need to mask them off - } - } -} - -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); -} - -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 -__m128i libdivide_u64_do_vector(__m128i numers, - const struct libdivide_u64_t* denom) { - uint8_t more = denom->more; - if (more & LIBDIVIDE_U64_SHIFT_PATH) { - return _mm_srl_epi64( - numers, libdivide_u32_to_m128i(more & LIBDIVIDE_64_SHIFT_MASK)); - } else { - __m128i q = libdivide_mullhi_u64_flat_vector( - numers, libdivide__u64_to_m128(denom->magic)); - if (more & LIBDIVIDE_ADD_MARKER) { - // uint32_t t = ((numer - q) >> 1) + q; - // return t >> denom->shift; - __m128i t = - _mm_add_epi64(_mm_srli_epi64(_mm_sub_epi64(numers, q), 1), q); - return _mm_srl_epi64( - t, libdivide_u32_to_m128i(more & LIBDIVIDE_64_SHIFT_MASK)); - } else { - // q >> denom->shift - return _mm_srl_epi64(q, libdivide_u32_to_m128i(more)); - } - } -} - -__m128i libdivide_u64_do_vector_alg0(__m128i numers, - const struct libdivide_u64_t* denom) { - return _mm_srl_epi64( - numers, libdivide_u32_to_m128i(denom->more & LIBDIVIDE_64_SHIFT_MASK)); -} - -__m128i libdivide_u64_do_vector_alg1(__m128i numers, - const struct libdivide_u64_t* denom) { - __m128i q = libdivide_mullhi_u64_flat_vector( - numers, libdivide__u64_to_m128(denom->magic)); - return _mm_srl_epi64(q, libdivide_u32_to_m128i(denom->more)); -} - -__m128i libdivide_u64_do_vector_alg2(__m128i numers, - const struct libdivide_u64_t* denom) { - __m128i q = libdivide_mullhi_u64_flat_vector( - numers, libdivide__u64_to_m128(denom->magic)); - __m128i t = _mm_add_epi64(_mm_srli_epi64(_mm_sub_epi64(numers, q), 1), q); - 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; - int64_t rl = xl * yl; - return (int32_t)(rl >> 32); // needs to be arithmetic shift -} - -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 - result.magic = 0; - result.more = libdivide__count_trailing_zeros32(absD) | - (d < 0 ? LIBDIVIDE_NEGATIVE_DIVISOR : 0) | - LIBDIVIDE_S32_SHIFT_PATH; - } else { - const uint32_t floor_log_2_d = - 31 - libdivide__count_leading_zeros32(absD); - 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 */ - more = floor_log_2_d - 1; - } else { - /* We need to go one higher. This should not make proposed_m - * overflow, but it will make it negative when interpreted as an - * int32_t. */ - proposed_m += proposed_m; - const uint32_t twice_rem = rem + rem; - if (twice_rem >= absD || twice_rem < rem) proposed_m += 1; - more = floor_log_2_d | LIBDIVIDE_ADD_MARKER | - (d < 0 ? LIBDIVIDE_NEGATIVE_DIVISOR - : 0); // use the general algorithm - } - proposed_m += 1; - result.magic = (d < 0 ? -(int32_t)proposed_m : (int32_t)proposed_m); - result.more = more; - } - return result; -} - -int32_t libdivide_s32_do(int32_t numer, const struct libdivide_s32_t* denom) { - uint8_t more = denom->more; - if (more & LIBDIVIDE_S32_SHIFT_PATH) { - uint8_t shifter = more & LIBDIVIDE_32_SHIFT_MASK; - int32_t q = numer + ((numer >> 31) & ((1 << shifter) - 1)); - q = q >> shifter; - int32_t shiftMask = - (int8_t)more >> 7; // must be arithmetic shift and then sign-extend - q = (q ^ shiftMask) - shiftMask; - return q; - } else { - int32_t q = libdivide__mullhi_s32(denom->magic, numer); - if (more & LIBDIVIDE_ADD_MARKER) { - int32_t sign = (int8_t)more >> - 7; // must be arithmetic shift and then sign extend - q += ((numer ^ sign) - sign); - } - q >>= more & LIBDIVIDE_32_SHIFT_MASK; - 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 - 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); - 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); - 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 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 - q = _mm_sub_epi32(_mm_xor_si128(q, shiftMask), - shiftMask); // q = (q ^ shiftMask) - shiftMask; - return q; - } else { - __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_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) - return q; - } -} - -__m128i libdivide_s32_do_vector_alg0(__m128i numers, - const struct libdivide_s32_t* denom) { - uint8_t shifter = denom->more & LIBDIVIDE_32_SHIFT_MASK; - __m128i roundToZeroTweak = _mm_set1_epi32((1 << shifter) - 1); - __m128i q = _mm_add_epi32( - numers, _mm_and_si128(_mm_srai_epi32(numers, 31), roundToZeroTweak)); - return _mm_sra_epi32(q, libdivide_u32_to_m128i(shifter)); -} - -__m128i libdivide_s32_do_vector_alg1(__m128i numers, - const struct libdivide_s32_t* denom) { - uint8_t shifter = denom->more & LIBDIVIDE_32_SHIFT_MASK; - __m128i roundToZeroTweak = _mm_set1_epi32((1 << shifter) - 1); - __m128i q = _mm_add_epi32( - numers, _mm_and_si128(_mm_srai_epi32(numers, 31), roundToZeroTweak)); - return _mm_sub_epi32(_mm_setzero_si128(), - _mm_sra_epi32(q, libdivide_u32_to_m128i(shifter))); -} - -__m128i libdivide_s32_do_vector_alg2(__m128i numers, - const struct libdivide_s32_t* denom) { - __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)); - return q; -} - -__m128i libdivide_s32_do_vector_alg3(__m128i numers, - const struct libdivide_s32_t* denom) { - __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)); - return q; -} - -__m128i libdivide_s32_do_vector_alg4(__m128i numers, - const struct libdivide_s32_t* denom) { - __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; -} -#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 - result.more = libdivide__count_trailing_zeros64(absD) | - (d < 0 ? LIBDIVIDE_NEGATIVE_DIVISOR : 0); - result.magic = 0; - } else { - 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 */ - more = floor_log_2_d - 1; - } else { - /* We need to go one higher. This should not make proposed_m - * overflow, but it will make it negative when interpreted as an - * int32_t. */ - proposed_m += proposed_m; - const uint64_t twice_rem = rem + rem; - if (twice_rem >= absD || twice_rem < rem) proposed_m += 1; - more = floor_log_2_d | LIBDIVIDE_ADD_MARKER | - (d < 0 ? LIBDIVIDE_NEGATIVE_DIVISOR : 0); - } - proposed_m += 1; - result.more = more; - result.magic = (d < 0 ? -(int64_t)proposed_m : (int64_t)proposed_m); - } - return result; -} - -int64_t libdivide_s64_do(int64_t numer, const struct libdivide_s64_t* denom) { - uint8_t more = denom->more; - int64_t magic = denom->magic; - if (magic == 0) { // shift path - uint32_t shifter = more & LIBDIVIDE_64_SHIFT_MASK; - int64_t q = numer + ((numer >> 63) & ((1LL << shifter) - 1)); - q = q >> shifter; - int64_t shiftMask = - (int8_t)more >> 7; // must be arithmetic shift and then sign-extend - q = (q ^ shiftMask) - shiftMask; - return q; - } else { - int64_t q = libdivide__mullhi_s64(magic, numer); - if (more & LIBDIVIDE_ADD_MARKER) { - int64_t sign = (int8_t)more >> - 7; // must be arithmetic shift and then sign extend - q += ((numer ^ sign) - sign); - } - q >>= more & LIBDIVIDE_64_SHIFT_MASK; - 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); - if (denom->magic == 0) - return (positiveDivisor ? 0 : 1); // shift path - 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; -} - -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; - q >>= denom->more & LIBDIVIDE_64_SHIFT_MASK; - 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); - 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; -} - -#if LIBDIVIDE_USE_SSE2 -__m128i libdivide_s64_do_vector(__m128i numers, - const struct libdivide_s64_t* denom) { - uint8_t more = denom->more; - int64_t magic = denom->magic; - if (magic == 0) { // shift path - uint32_t shifter = more & LIBDIVIDE_64_SHIFT_MASK; - __m128i roundToZeroTweak = libdivide__u64_to_m128((1LL << shifter) - 1); - __m128i q = _mm_add_epi64( - numers, - _mm_and_si128(libdivide_s64_signbits(numers), - roundToZeroTweak)); // q = numer + ((numer >> 63) & - // roundToZeroTweak); - q = libdivide_s64_shift_right_vector(q, shifter); // q = q >> shifter - __m128i shiftMask = _mm_set1_epi32((int32_t)((int8_t)more >> 7)); - q = _mm_sub_epi64(_mm_xor_si128(q, shiftMask), - shiftMask); // q = (q ^ shiftMask) - shiftMask; - return q; - } else { - __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 = 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) - return q; - } -} - -__m128i libdivide_s64_do_vector_alg0(__m128i numers, - const struct libdivide_s64_t* denom) { - uint32_t shifter = denom->more & LIBDIVIDE_64_SHIFT_MASK; - __m128i roundToZeroTweak = libdivide__u64_to_m128((1LL << shifter) - 1); - __m128i q = _mm_add_epi64( - numers, - _mm_and_si128(libdivide_s64_signbits(numers), roundToZeroTweak)); - q = libdivide_s64_shift_right_vector(q, shifter); - return q; -} - -__m128i libdivide_s64_do_vector_alg1(__m128i numers, - const struct libdivide_s64_t* denom) { - uint32_t shifter = denom->more & LIBDIVIDE_64_SHIFT_MASK; - __m128i roundToZeroTweak = libdivide__u64_to_m128((1LL << shifter) - 1); - __m128i q = _mm_add_epi64( - numers, - _mm_and_si128(libdivide_s64_signbits(numers), roundToZeroTweak)); - q = libdivide_s64_shift_right_vector(q, shifter); - return _mm_sub_epi64(_mm_setzero_si128(), q); -} - -__m128i libdivide_s64_do_vector_alg2(__m128i numers, - const struct libdivide_s64_t* denom) { - __m128i q = libdivide_mullhi_s64_flat_vector( - numers, libdivide__u64_to_m128(denom->magic)); - q = _mm_add_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; -} - -__m128i libdivide_s64_do_vector_alg3(__m128i numers, - const struct libdivide_s64_t* denom) { - __m128i q = libdivide_mullhi_s64_flat_vector( - numers, libdivide__u64_to_m128(denom->magic)); - 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; -} - -__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; -} - -#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: - -- The base is a template divider_base that takes the integer type, the libdivide -struct, a generating function, a get algorithm function, a do function, and -either a do vector function or a dummy int. -- The base has storage for the libdivide struct. This is the only storage (so -the C++ class should be no larger than the libdivide struct). - -- Above that, there's divider_mid. This is an empty struct by default, but it -is specialized against our four int types. divider_mid contains a template -struct algo, that contains a typedef for a specialization of divider_base. -struct algo is specialized to take an "algorithm number," where -1 means to use -the general algorithm. - -- Publicly we have class divider, which inherits from divider_mid::algo. This -also take an algorithm number, which defaults to -1 (the general algorithm). -- divider has a operator / which allows you to use a divider as the divisor in a -quotient expression. - -*/ - -namespace libdivide_internal { - -#if LIBDIVIDE_USE_SSE2 -#define MAYBE_VECTOR(x) x -#define MAYBE_VECTOR_PARAM __m128i vector_func(__m128i, const DenomType*) -#else -#define MAYBE_VECTOR(x) 0 -#define MAYBE_VECTOR_PARAM int vector_func -#endif - -/* Some bogus unswitch functions for unsigned types so the same (presumably - * templated) code can work for both signed and unsigned. */ -uint32_t crash_u32(uint32_t, const libdivide_u32_t*) { - abort(); - return *(uint32_t*)nullptr; -} -uint64_t crash_u64(uint64_t, const libdivide_u64_t*) { - abort(); - return *(uint64_t*)nullptr; -} -#if LIBDIVIDE_USE_SSE2 -__m128i crash_u32_vector(__m128i, const libdivide_u32_t*) { - abort(); - return *(__m128i*)nullptr; -} -__m128i crash_u64_vector(__m128i, const libdivide_u64_t*) { - abort(); - return *(__m128i*)nullptr; -} -#endif - -template -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); - } -#endif - - int get_algorithm() const { return get_algo(&denom); } -}; - -template -struct divider_mid {}; - -template <> -struct divider_mid { - typedef uint32_t IntType; - typedef struct libdivide_u32_t DenomType; - template - struct denom { - typedef divider_base - divider; - }; - - template - struct algo {}; - template - struct algo<-1, J> { - typedef denom::divider divider; - }; - template - struct algo<0, J> { - typedef denom::divider - divider; - }; - template - struct algo<1, J> { - typedef denom::divider - divider; - }; - template - struct algo<2, J> { - typedef denom::divider - divider; - }; - - /* Define two more bogus ones so that the same (templated, presumably) code - * can handle both signed and unsigned */ - template - struct algo<3, J> { - typedef denom::divider - divider; - }; - template - struct algo<4, J> { - typedef denom::divider - divider; - }; -}; - -template <> -struct divider_mid { - typedef int32_t IntType; - typedef struct libdivide_s32_t DenomType; - template - struct denom { - typedef divider_base - divider; - }; - - template - struct algo {}; - template - struct algo<-1, J> { - typedef denom::divider divider; - }; - template - struct algo<0, J> { - typedef denom::divider - divider; - }; - template - struct algo<1, J> { - typedef denom::divider - divider; - }; - template - struct algo<2, J> { - typedef denom::divider - divider; - }; - template - struct algo<3, J> { - typedef denom::divider - divider; - }; - template - struct algo<4, J> { - typedef denom::divider - divider; - }; -}; - -template <> -struct divider_mid { - typedef uint64_t IntType; - typedef struct libdivide_u64_t DenomType; - template - struct denom { - typedef divider_base - divider; - }; - - template - struct algo {}; - template - struct algo<-1, J> { - typedef denom::divider divider; - }; - template - struct algo<0, J> { - typedef denom::divider - divider; - }; - template - struct algo<1, J> { - typedef denom::divider - divider; - }; - template - struct algo<2, J> { - typedef denom::divider - divider; - }; - - /* Define two more bogus ones so that the same (templated, presumably) code - * can handle both signed and unsigned */ - template - struct algo<3, J> { - typedef denom::divider - divider; - }; - template - struct algo<4, J> { - typedef denom::divider - divider; - }; -}; - -template <> -struct divider_mid { - typedef int64_t IntType; - typedef struct libdivide_s64_t DenomType; - template - struct denom { - typedef divider_base - divider; - }; - - template - struct algo {}; - template - struct algo<-1, J> { - typedef denom::divider divider; - }; - template - struct algo<0, J> { - typedef denom::divider - divider; - }; - template - struct algo<1, J> { - typedef denom::divider - divider; - }; - template - struct algo<2, J> { - typedef denom::divider - divider; - }; - template - struct algo<3, J> { - typedef denom::divider - divider; - }; - template - struct algo<4, J> { - typedef denom::divider - divider; - }; -}; - -} // namespace libdivide_internal - -template -class divider { -private: - typename libdivide_internal::divider_mid::template algo::divider - sub; - template - friend divider unswitch(const divider& d); - divider(const typename libdivide_internal::divider_mid::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); - } -#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& him) const { - return sub.denom.magic == him.sub.denom.magic && - sub.denom.more == him.sub.denom.more; - } - - bool operator!=(const divider& him) const { - return !(*this == him); - } -}; - -/* Returns a divider specialized for the given algorithm. */ -template -divider unswitch(const divider& d) { - return divider(d.sub.denom); -} - -/* Overload of the / operator for scalar division. */ -template -int_type operator/(int_type numer, const divider& denom) { - return denom.perform_divide(numer); -} - -#if LIBDIVIDE_USE_SSE2 -/* Overload of the / operator for vector division. */ -template -__m128i operator/(__m128i numer, const divider& denom) { - return denom.perform_divide_vector(numer); -} -#endif - -#endif //__cplusplus - -#endif // LIBDIVIDE_HEADER_ONLY -#ifdef __cplusplus -} // close namespace libdivide -} // close anonymous namespace -#endif