Home | History | Annotate | Line # | Download | only in dist
      1 /*
      2  * Copyright 2015 INRIA Paris-Rocquencourt
      3  *
      4  * Use of this software is governed by the MIT license
      5  *
      6  * Written by Michael Kruse, INRIA Paris-Rocquencourt,
      7  * Domaine de Voluceau, Rocquenqourt, B.P. 105,
      8  * 78153 Le Chesnay Cedex France
      9  */
     10 #ifndef ISL_INT_SIOIMATH_H
     11 #define ISL_INT_SIOIMATH_H
     12 
     13 #include <inttypes.h>
     14 #include <limits.h>
     15 #include <stdint.h>
     16 #include <stdlib.h>
     17 
     18 #include <isl_imath.h>
     19 #include <isl/hash.h>
     20 
     21 #define ARRAY_SIZE(array) (sizeof(array)/sizeof(*array))
     22 
     23 /* Visual Studio before VS2015 does not support the inline keyword when
     24  * compiling in C mode because it was introduced in C99 which it does not
     25  * officially support.  Instead, it has a proprietary extension using __inline.
     26  */
     27 #if defined(_MSC_VER) && (_MSC_VER < 1900)
     28 #define inline __inline
     29 #endif
     30 
     31 /* The type to represent integers optimized for small values. It is either a
     32  * pointer to an mp_int ( = mpz_t*; big representation) or an int32_t (small
     33  * represenation) with a discriminator at the least significant bit. In big
     34  * representation it will be always zero because of heap alignment. It is set
     35  * to 1 for small representation and use the 32 most significant bits for the
     36  * int32_t.
     37  *
     38  * Structure on 64 bit machines, with 8-byte aligment (3 bits):
     39  *
     40  * Big representation:
     41  * MSB                                                          LSB
     42  * |------------------------------------------------------------000
     43  * |                            mpz_t*                            |
     44  * |                           != NULL                            |
     45  *
     46  * Small representation:
     47  * MSB                           32                             LSB
     48  * |------------------------------|00000000000000000000000000000001
     49  * |          int32_t             |
     50  * |  2147483647 ... -2147483647  |
     51  *                                                                ^
     52  *                                                                |
     53  *                                                        discriminator bit
     54  *
     55  * On 32 bit machines isl_sioimath type is blown up to 8 bytes, i.e.
     56  * isl_sioimath is guaranteed to be at least 8 bytes. This is to ensure the
     57  * int32_t can be hidden in that type without data loss. In the future we might
     58  * optimize this to use 31 hidden bits in a 32 bit pointer. We may also use 63
     59  * bits on 64 bit machines, but this comes with the cost of additional overflow
     60  * checks because there is no standardized 128 bit integer we could expand to.
     61  *
     62  * We use native integer types and avoid union structures to avoid assumptions
     63  * on the machine's endianness.
     64  *
     65  * This implementation makes the following assumptions:
     66  * - long can represent any int32_t
     67  * - mp_small is signed long
     68  * - mp_usmall is unsigned long
     69  * - adresses returned by malloc are aligned to 2-byte boundaries (leastmost
     70  *   bit is zero)
     71  */
     72 #if UINT64_MAX > UINTPTR_MAX
     73 typedef uint64_t isl_sioimath;
     74 #else
     75 typedef uintptr_t isl_sioimath;
     76 #endif
     77 
     78 /* The negation of the smallest possible number in int32_t, INT32_MIN
     79  * (0x80000000u, -2147483648), cannot be represented in an int32_t, therefore
     80  * every operation that may produce this value needs to special-case it.
     81  * The operations are:
     82  * abs(INT32_MIN)
     83  * -INT32_MIN   (negation)
     84  * -1 * INT32_MIN (multiplication)
     85  * INT32_MIN/-1 (any division: divexact, fdiv, cdiv, tdiv)
     86  * To avoid checking these cases, we exclude INT32_MIN from small
     87  * representation.
     88  */
     89 #define ISL_SIOIMATH_SMALL_MIN (-INT32_MAX)
     90 
     91 /* Largest possible number in small representation */
     92 #define ISL_SIOIMATH_SMALL_MAX INT32_MAX
     93 
     94 /* Used for function parameters the function modifies. */
     95 typedef isl_sioimath *isl_sioimath_ptr;
     96 
     97 /* Used for function parameters that are read-only. */
     98 typedef isl_sioimath isl_sioimath_src;
     99 
    100 /* Return whether the argument is stored in small representation.
    101  */
    102 inline int isl_sioimath_is_small(isl_sioimath val)
    103 {
    104 	return val & 0x00000001;
    105 }
    106 
    107 /* Return whether the argument is stored in big representation.
    108  */
    109 inline int isl_sioimath_is_big(isl_sioimath val)
    110 {
    111 	return !isl_sioimath_is_small(val);
    112 }
    113 
    114 /* Get the number of an isl_int in small representation. Result is undefined if
    115  * val is not stored in that format.
    116  */
    117 inline int32_t isl_sioimath_get_small(isl_sioimath val)
    118 {
    119 	return val >> 32;
    120 }
    121 
    122 /* Get the number of an in isl_int in big representation. Result is undefined if
    123  * val is not stored in that format.
    124  */
    125 inline mp_int isl_sioimath_get_big(isl_sioimath val)
    126 {
    127 	return (mp_int)(uintptr_t) val;
    128 }
    129 
    130 /* Return 1 if val is stored in small representation and store its value to
    131  * small. We rely on the compiler to optimize the isl_sioimath_get_small such
    132  * that the shift is moved into the branch that executes in case of small
    133  * representation. If there is no such branch, then a single shift is still
    134  * cheaper than introducing branching code.
    135  */
    136 inline int isl_sioimath_decode_small(isl_sioimath val, int32_t *small)
    137 {
    138 	*small = isl_sioimath_get_small(val);
    139 	return isl_sioimath_is_small(val);
    140 }
    141 
    142 /* Return 1 if val is stored in big representation and store its value to big.
    143  */
    144 inline int isl_sioimath_decode_big(isl_sioimath val, mp_int *big)
    145 {
    146 	*big = isl_sioimath_get_big(val);
    147 	return isl_sioimath_is_big(val);
    148 }
    149 
    150 /* Encode a small representation into an isl_int.
    151  */
    152 inline isl_sioimath isl_sioimath_encode_small(int32_t val)
    153 {
    154 	return ((isl_sioimath) val) << 32 | 0x00000001;
    155 }
    156 
    157 /* Encode a big representation.
    158  */
    159 inline isl_sioimath isl_sioimath_encode_big(mp_int val)
    160 {
    161 	return (isl_sioimath)(uintptr_t) val;
    162 }
    163 
    164 /* A common situation is to call an IMath function with at least one argument
    165  * that is currently in small representation or an integer parameter, i.e. a big
    166  * representation of the same number is required. Promoting the original
    167  * argument comes with multiple problems, such as modifying a read-only
    168  * argument, the responsibility of deallocation and the execution cost. Instead,
    169  * we make a copy by 'faking' the IMath internal structure.
    170  *
    171  * We reserve the maximum number of required digits on the stack to avoid heap
    172  * allocations.
    173  *
    174  * mp_digit can be uint32_t or uint16_t. This code must work for little and big
    175  * endian digits. The structure for an uint64_t argument and 32-bit mp_digits is
    176  * sketched below.
    177  *
    178  * |----------------------------|
    179  *            uint64_t
    180  *
    181  * |-------------||-------------|
    182  *    mp_digit        mp_digit
    183  *    digits[1]       digits[0]
    184  * Most sig digit  Least sig digit
    185  */
    186 typedef struct {
    187 	mpz_t big;
    188 	mp_digit digits[(sizeof(uintmax_t) + sizeof(mp_digit) - 1) /
    189 	                sizeof(mp_digit)];
    190 } isl_sioimath_scratchspace_t;
    191 
    192 /* Convert a native integer to IMath's digit representation. A native integer
    193  * might be big- or little endian, but IMath always stores the least significant
    194  * digit in the lowest array indices.  memcpy therefore is not possible.
    195  *
    196  * We also have to consider that long and mp_digit can be of different sizes,
    197  * depending on the compiler (LP64, LLP64) and IMath's USE_64BIT_WORDS. This
    198  * macro should work for all of them.
    199  *
    200  * "used" is set to the number of written digits. It must be minimal (IMath
    201  * checks zeroness using the used field), but always at least one.  Also note
    202  * that the result of num>>(sizeof(num)*CHAR_BIT) is undefined.
    203  */
    204 #define ISL_SIOIMATH_TO_DIGITS(num, digits, used)                              \
    205 	do {                                                                   \
    206 		int i = 0;                                                     \
    207 		do {                                                           \
    208 			(digits)[i] =                                          \
    209 			    ((num) >> (sizeof(mp_digit) * CHAR_BIT * i));      \
    210 			i += 1;                                                \
    211 			if (i >= (sizeof(num) + sizeof(mp_digit) - 1) /        \
    212 			             sizeof(mp_digit))                         \
    213 				break;                                         \
    214 			if (((num) >> (sizeof(mp_digit) * CHAR_BIT * i)) == 0) \
    215 				break;                                         \
    216 		} while (1);                                                   \
    217 		(used) = i;                                                    \
    218 	} while (0)
    219 
    220 inline void isl_siomath_uint32_to_digits(uint32_t num, mp_digit *digits,
    221 	mp_size *used)
    222 {
    223 	ISL_SIOIMATH_TO_DIGITS(num, digits, *used);
    224 }
    225 
    226 inline void isl_siomath_ulong_to_digits(unsigned long num, mp_digit *digits,
    227 	mp_size *used)
    228 {
    229 	ISL_SIOIMATH_TO_DIGITS(num, digits, *used);
    230 }
    231 
    232 inline void isl_siomath_uint64_to_digits(uint64_t num, mp_digit *digits,
    233 	mp_size *used)
    234 {
    235 	ISL_SIOIMATH_TO_DIGITS(num, digits, *used);
    236 }
    237 
    238 /* Get the IMath representation of an isl_int without modifying it.
    239  * For the case it is not in big representation yet, pass some scratch space we
    240  * can use to store the big representation in.
    241  * In order to avoid requiring init and free on the scratch space, we directly
    242  * modify the internal representation.
    243  *
    244  * The name derives from its indented use: getting the big representation of an
    245  * input (src) argument.
    246  */
    247 inline mp_int isl_sioimath_bigarg_src(isl_sioimath arg,
    248 	isl_sioimath_scratchspace_t *scratch)
    249 {
    250 	mp_int big;
    251 	int32_t small;
    252 	uint32_t num;
    253 
    254 	if (isl_sioimath_decode_big(arg, &big))
    255 		return big;
    256 
    257 	small = isl_sioimath_get_small(arg);
    258 	scratch->big.digits = scratch->digits;
    259 	scratch->big.alloc = ARRAY_SIZE(scratch->digits);
    260 	if (small >= 0) {
    261 		scratch->big.sign = MP_ZPOS;
    262 		num = small;
    263 	} else {
    264 		scratch->big.sign = MP_NEG;
    265 		num = -small;
    266 	}
    267 
    268 	isl_siomath_uint32_to_digits(num, scratch->digits, &scratch->big.used);
    269 	return &scratch->big;
    270 }
    271 
    272 /* Create a temporary IMath mp_int for a signed long.
    273  */
    274 inline mp_int isl_sioimath_siarg_src(signed long arg,
    275 	isl_sioimath_scratchspace_t *scratch)
    276 {
    277 	unsigned long num;
    278 
    279 	scratch->big.digits = scratch->digits;
    280 	scratch->big.alloc = ARRAY_SIZE(scratch->digits);
    281 	if (arg >= 0) {
    282 		scratch->big.sign = MP_ZPOS;
    283 		num = arg;
    284 	} else {
    285 		scratch->big.sign = MP_NEG;
    286 		num = (arg == LONG_MIN) ? ((unsigned long) LONG_MAX) + 1 : -arg;
    287 	}
    288 
    289 	isl_siomath_ulong_to_digits(num, scratch->digits, &scratch->big.used);
    290 	return &scratch->big;
    291 }
    292 
    293 /* Create a temporary IMath mp_int for an int64_t.
    294  */
    295 inline mp_int isl_sioimath_si64arg_src(int64_t arg,
    296 	isl_sioimath_scratchspace_t *scratch)
    297 {
    298 	uint64_t num;
    299 
    300 	scratch->big.digits = scratch->digits;
    301 	scratch->big.alloc = ARRAY_SIZE(scratch->digits);
    302 	if (arg >= 0) {
    303 		scratch->big.sign = MP_ZPOS;
    304 		num = arg;
    305 	} else {
    306 		scratch->big.sign = MP_NEG;
    307 		num = (arg == INT64_MIN) ? ((uint64_t) INT64_MAX) + 1 : -arg;
    308 	}
    309 
    310 	isl_siomath_uint64_to_digits(num, scratch->digits, &scratch->big.used);
    311 	return &scratch->big;
    312 }
    313 
    314 /* Create a temporary IMath mp_int for an unsigned long.
    315  */
    316 inline mp_int isl_sioimath_uiarg_src(unsigned long arg,
    317 	isl_sioimath_scratchspace_t *scratch)
    318 {
    319 	scratch->big.digits = scratch->digits;
    320 	scratch->big.alloc = ARRAY_SIZE(scratch->digits);
    321 	scratch->big.sign = MP_ZPOS;
    322 
    323 	isl_siomath_ulong_to_digits(arg, scratch->digits, &scratch->big.used);
    324 	return &scratch->big;
    325 }
    326 
    327 /* Ensure big representation. Does not preserve the current number.
    328  * Callers may use the fact that the value _is_ preserved if the presentation
    329  * was big before.
    330  */
    331 inline mp_int isl_sioimath_reinit_big(isl_sioimath_ptr ptr)
    332 {
    333 	if (isl_sioimath_is_small(*ptr))
    334 		*ptr = isl_sioimath_encode_big(mp_int_alloc());
    335 	return isl_sioimath_get_big(*ptr);
    336 }
    337 
    338 /* Set ptr to a number in small representation.
    339  */
    340 inline void isl_sioimath_set_small(isl_sioimath_ptr ptr, int32_t val)
    341 {
    342 	if (isl_sioimath_is_big(*ptr))
    343 		mp_int_free(isl_sioimath_get_big(*ptr));
    344 	*ptr = isl_sioimath_encode_small(val);
    345 }
    346 
    347 /* Set ptr to val, choosing small representation if possible.
    348  */
    349 inline void isl_sioimath_set_int32(isl_sioimath_ptr ptr, int32_t val)
    350 {
    351 	if (ISL_SIOIMATH_SMALL_MIN <= val && val <= ISL_SIOIMATH_SMALL_MAX) {
    352 		isl_sioimath_set_small(ptr, val);
    353 		return;
    354 	}
    355 
    356 	mp_int_init_value(isl_sioimath_reinit_big(ptr), val);
    357 }
    358 
    359 /* Assign an int64_t number using small representation if possible.
    360  */
    361 inline void isl_sioimath_set_int64(isl_sioimath_ptr ptr, int64_t val)
    362 {
    363 	if (ISL_SIOIMATH_SMALL_MIN <= val && val <= ISL_SIOIMATH_SMALL_MAX) {
    364 		isl_sioimath_set_small(ptr, val);
    365 		return;
    366 	}
    367 
    368 	isl_sioimath_scratchspace_t scratch;
    369 	mp_int_copy(isl_sioimath_si64arg_src(val, &scratch),
    370 	    isl_sioimath_reinit_big(ptr));
    371 }
    372 
    373 /* Convert to big representation while preserving the current number.
    374  */
    375 inline void isl_sioimath_promote(isl_sioimath_ptr dst)
    376 {
    377 	int32_t small;
    378 
    379 	if (isl_sioimath_is_big(*dst))
    380 		return;
    381 
    382 	small = isl_sioimath_get_small(*dst);
    383 	mp_int_set_value(isl_sioimath_reinit_big(dst), small);
    384 }
    385 
    386 /* Convert to small representation while preserving the current number. Does
    387  * nothing if dst doesn't fit small representation.
    388  */
    389 inline void isl_sioimath_try_demote(isl_sioimath_ptr dst)
    390 {
    391 	mp_small small;
    392 
    393 	if (isl_sioimath_is_small(*dst))
    394 		return;
    395 
    396 	if (mp_int_to_int(isl_sioimath_get_big(*dst), &small) != MP_OK)
    397 		return;
    398 
    399 	if (ISL_SIOIMATH_SMALL_MIN <= small && small <= ISL_SIOIMATH_SMALL_MAX)
    400 		isl_sioimath_set_small(dst, small);
    401 }
    402 
    403 /* Initialize an isl_int. The implicit value is 0 in small representation.
    404  */
    405 inline void isl_sioimath_init(isl_sioimath_ptr dst)
    406 {
    407 	*dst = isl_sioimath_encode_small(0);
    408 }
    409 
    410 /* Free the resources taken by an isl_int.
    411  */
    412 inline void isl_sioimath_clear(isl_sioimath_ptr dst)
    413 {
    414 	if (isl_sioimath_is_small(*dst))
    415 		return;
    416 
    417 	mp_int_free(isl_sioimath_get_big(*dst));
    418 }
    419 
    420 /* Copy the value of one isl_int to another.
    421  */
    422 inline void isl_sioimath_set(isl_sioimath_ptr dst, isl_sioimath_src val)
    423 {
    424 	if (isl_sioimath_is_small(val)) {
    425 		isl_sioimath_set_small(dst, isl_sioimath_get_small(val));
    426 		return;
    427 	}
    428 
    429 	mp_int_copy(isl_sioimath_get_big(val), isl_sioimath_reinit_big(dst));
    430 }
    431 
    432 /* Store a signed long into an isl_int.
    433  */
    434 inline void isl_sioimath_set_si(isl_sioimath_ptr dst, long val)
    435 {
    436 	if (ISL_SIOIMATH_SMALL_MIN <= val && val <= ISL_SIOIMATH_SMALL_MAX) {
    437 		isl_sioimath_set_small(dst, val);
    438 		return;
    439 	}
    440 
    441 	mp_int_set_value(isl_sioimath_reinit_big(dst), val);
    442 }
    443 
    444 /* Store an unsigned long into an isl_int.
    445  */
    446 inline void isl_sioimath_set_ui(isl_sioimath_ptr dst, unsigned long val)
    447 {
    448 	if (val <= ISL_SIOIMATH_SMALL_MAX) {
    449 		isl_sioimath_set_small(dst, val);
    450 		return;
    451 	}
    452 
    453 	mp_int_set_uvalue(isl_sioimath_reinit_big(dst), val);
    454 }
    455 
    456 /* Return whether a number can be represented by a signed long.
    457  */
    458 inline int isl_sioimath_fits_slong(isl_sioimath_src val)
    459 {
    460 	mp_small dummy;
    461 
    462 	if (isl_sioimath_is_small(val))
    463 		return 1;
    464 
    465 	return mp_int_to_int(isl_sioimath_get_big(val), &dummy) == MP_OK;
    466 }
    467 
    468 /* Return a number as signed long. Result is undefined if the number cannot be
    469  * represented as long.
    470  */
    471 inline long isl_sioimath_get_si(isl_sioimath_src val)
    472 {
    473 	mp_small result;
    474 
    475 	if (isl_sioimath_is_small(val))
    476 		return isl_sioimath_get_small(val);
    477 
    478 	mp_int_to_int(isl_sioimath_get_big(val), &result);
    479 	return result;
    480 }
    481 
    482 /* Return whether a number can be represented as unsigned long.
    483  */
    484 inline int isl_sioimath_fits_ulong(isl_sioimath_src val)
    485 {
    486 	mp_usmall dummy;
    487 
    488 	if (isl_sioimath_is_small(val))
    489 		return isl_sioimath_get_small(val) >= 0;
    490 
    491 	return mp_int_to_uint(isl_sioimath_get_big(val), &dummy) == MP_OK;
    492 }
    493 
    494 /* Return a number as unsigned long. Result is undefined if the number cannot be
    495  * represented as unsigned long.
    496  */
    497 inline unsigned long isl_sioimath_get_ui(isl_sioimath_src val)
    498 {
    499 	mp_usmall result;
    500 
    501 	if (isl_sioimath_is_small(val))
    502 		return isl_sioimath_get_small(val);
    503 
    504 	mp_int_to_uint(isl_sioimath_get_big(val), &result);
    505 	return result;
    506 }
    507 
    508 /* Return a number as floating point value.
    509  */
    510 inline double isl_sioimath_get_d(isl_sioimath_src val)
    511 {
    512 	mp_int big;
    513 	double result = 0;
    514 	int i;
    515 
    516 	if (isl_sioimath_is_small(val))
    517 		return isl_sioimath_get_small(val);
    518 
    519 	big = isl_sioimath_get_big(val);
    520 	for (i = 0; i < big->used; ++i)
    521 		result = result * (double) ((uintmax_t) MP_DIGIT_MAX + 1) +
    522 		         (double) big->digits[i];
    523 
    524 	if (big->sign == MP_NEG)
    525 		result = -result;
    526 
    527 	return result;
    528 }
    529 
    530 /* Format a number as decimal string.
    531  *
    532  * The largest possible string from small representation is 12 characters
    533  * ("-2147483647").
    534  */
    535 inline char *isl_sioimath_get_str(isl_sioimath_src val)
    536 {
    537 	char *result;
    538 
    539 	if (isl_sioimath_is_small(val)) {
    540 		result = malloc(12);
    541 		snprintf(result, 12, "%" PRIi32, isl_sioimath_get_small(val));
    542 		return result;
    543 	}
    544 
    545 	return impz_get_str(NULL, 10, isl_sioimath_get_big(val));
    546 }
    547 
    548 /* Return the absolute value.
    549  */
    550 inline void isl_sioimath_abs(isl_sioimath_ptr dst, isl_sioimath_src arg)
    551 {
    552 	if (isl_sioimath_is_small(arg)) {
    553 		isl_sioimath_set_small(dst, labs(isl_sioimath_get_small(arg)));
    554 		return;
    555 	}
    556 
    557 	mp_int_abs(isl_sioimath_get_big(arg), isl_sioimath_reinit_big(dst));
    558 }
    559 
    560 /* Return the negation of a number.
    561  */
    562 inline void isl_sioimath_neg(isl_sioimath_ptr dst, isl_sioimath_src arg)
    563 {
    564 	if (isl_sioimath_is_small(arg)) {
    565 		isl_sioimath_set_small(dst, -isl_sioimath_get_small(arg));
    566 		return;
    567 	}
    568 
    569 	mp_int_neg(isl_sioimath_get_big(arg), isl_sioimath_reinit_big(dst));
    570 }
    571 
    572 /* Swap two isl_ints.
    573  *
    574  * isl_sioimath can be copied bytewise; nothing depends on its address. It can
    575  * also be stored in a CPU register.
    576  */
    577 inline void isl_sioimath_swap(isl_sioimath_ptr lhs, isl_sioimath_ptr rhs)
    578 {
    579 	isl_sioimath tmp = *lhs;
    580 	*lhs = *rhs;
    581 	*rhs = tmp;
    582 }
    583 
    584 /* Add an unsigned long to the number.
    585  *
    586  * On LP64 unsigned long exceeds the range of an int64_t, therefore we check in
    587  * advance whether small representation possibly overflows.
    588  */
    589 inline void isl_sioimath_add_ui(isl_sioimath_ptr dst, isl_sioimath lhs,
    590 	unsigned long rhs)
    591 {
    592 	int32_t smalllhs;
    593 	isl_sioimath_scratchspace_t lhsscratch;
    594 
    595 	if (isl_sioimath_decode_small(lhs, &smalllhs) &&
    596 	    (rhs <= (uint64_t) INT64_MAX - (uint64_t) ISL_SIOIMATH_SMALL_MAX)) {
    597 		isl_sioimath_set_int64(dst, (int64_t) smalllhs + rhs);
    598 		return;
    599 	}
    600 
    601 	impz_add_ui(isl_sioimath_reinit_big(dst),
    602 	    isl_sioimath_bigarg_src(lhs, &lhsscratch), rhs);
    603 	isl_sioimath_try_demote(dst);
    604 }
    605 
    606 /* Subtract an unsigned long.
    607  *
    608  * On LP64 unsigned long exceeds the range of an int64_t.  If
    609  * ISL_SIOIMATH_SMALL_MIN-rhs>=INT64_MIN we can do the calculation using int64_t
    610  * without risking an overflow.
    611  */
    612 inline void isl_sioimath_sub_ui(isl_sioimath_ptr dst, isl_sioimath lhs,
    613 				unsigned long rhs)
    614 {
    615 	int32_t smalllhs;
    616 	isl_sioimath_scratchspace_t lhsscratch;
    617 
    618 	if (isl_sioimath_decode_small(lhs, &smalllhs) &&
    619 	    (rhs < (uint64_t) INT64_MIN - (uint64_t) ISL_SIOIMATH_SMALL_MIN)) {
    620 		isl_sioimath_set_int64(dst, (int64_t) smalllhs - rhs);
    621 		return;
    622 	}
    623 
    624 	impz_sub_ui(isl_sioimath_reinit_big(dst),
    625 	    isl_sioimath_bigarg_src(lhs, &lhsscratch), rhs);
    626 	isl_sioimath_try_demote(dst);
    627 }
    628 
    629 /* Sum of two isl_ints.
    630  */
    631 inline void isl_sioimath_add(isl_sioimath_ptr dst, isl_sioimath_src lhs,
    632 	isl_sioimath_src rhs)
    633 {
    634 	isl_sioimath_scratchspace_t scratchlhs, scratchrhs;
    635 	int32_t smalllhs, smallrhs;
    636 
    637 	if (isl_sioimath_decode_small(lhs, &smalllhs) &&
    638 	    isl_sioimath_decode_small(rhs, &smallrhs)) {
    639 		isl_sioimath_set_int64(
    640 		    dst, (int64_t) smalllhs + (int64_t) smallrhs);
    641 		return;
    642 	}
    643 
    644 	mp_int_add(isl_sioimath_bigarg_src(lhs, &scratchlhs),
    645 	    isl_sioimath_bigarg_src(rhs, &scratchrhs),
    646 	    isl_sioimath_reinit_big(dst));
    647 	isl_sioimath_try_demote(dst);
    648 }
    649 
    650 /* Subtract two isl_ints.
    651  */
    652 inline void isl_sioimath_sub(isl_sioimath_ptr dst, isl_sioimath_src lhs,
    653 	isl_sioimath_src rhs)
    654 {
    655 	isl_sioimath_scratchspace_t scratchlhs, scratchrhs;
    656 	int32_t smalllhs, smallrhs;
    657 
    658 	if (isl_sioimath_decode_small(lhs, &smalllhs) &&
    659 	    isl_sioimath_decode_small(rhs, &smallrhs)) {
    660 		isl_sioimath_set_int64(
    661 		    dst, (int64_t) smalllhs - (int64_t) smallrhs);
    662 		return;
    663 	}
    664 
    665 	mp_int_sub(isl_sioimath_bigarg_src(lhs, &scratchlhs),
    666 	    isl_sioimath_bigarg_src(rhs, &scratchrhs),
    667 	    isl_sioimath_reinit_big(dst));
    668 	isl_sioimath_try_demote(dst);
    669 }
    670 
    671 /* Multiply two isl_ints.
    672  */
    673 inline void isl_sioimath_mul(isl_sioimath_ptr dst, isl_sioimath_src lhs,
    674 	isl_sioimath_src rhs)
    675 {
    676 	isl_sioimath_scratchspace_t scratchlhs, scratchrhs;
    677 	int32_t smalllhs, smallrhs;
    678 
    679 	if (isl_sioimath_decode_small(lhs, &smalllhs) &&
    680 	    isl_sioimath_decode_small(rhs, &smallrhs)) {
    681 		isl_sioimath_set_int64(
    682 		    dst, (int64_t) smalllhs * (int64_t) smallrhs);
    683 		return;
    684 	}
    685 
    686 	mp_int_mul(isl_sioimath_bigarg_src(lhs, &scratchlhs),
    687 	    isl_sioimath_bigarg_src(rhs, &scratchrhs),
    688 	    isl_sioimath_reinit_big(dst));
    689 	isl_sioimath_try_demote(dst);
    690 }
    691 
    692 /* Shift lhs by rhs bits to the left and store the result in dst. Effectively,
    693  * this operation computes 'lhs * 2^rhs'.
    694  */
    695 inline void isl_sioimath_mul_2exp(isl_sioimath_ptr dst, isl_sioimath lhs,
    696 	unsigned long rhs)
    697 {
    698 	isl_sioimath_scratchspace_t scratchlhs;
    699 	int32_t smalllhs;
    700 
    701 	if (isl_sioimath_decode_small(lhs, &smalllhs) && (rhs <= 32ul)) {
    702 		isl_sioimath_set_int64(dst, ((int64_t) smalllhs) << rhs);
    703 		return;
    704 	}
    705 
    706 	mp_int_mul_pow2(isl_sioimath_bigarg_src(lhs, &scratchlhs), rhs,
    707 	    isl_sioimath_reinit_big(dst));
    708 }
    709 
    710 /* Multiply an isl_int and a signed long.
    711  */
    712 inline void isl_sioimath_mul_si(isl_sioimath_ptr dst, isl_sioimath lhs,
    713 	signed long rhs)
    714 {
    715 	isl_sioimath_scratchspace_t scratchlhs, scratchrhs;
    716 	int32_t smalllhs;
    717 
    718 	if (isl_sioimath_decode_small(lhs, &smalllhs) && (rhs > LONG_MIN) &&
    719 	    (labs(rhs) <= UINT32_MAX)) {
    720 		isl_sioimath_set_int64(dst, (int64_t) smalllhs * (int64_t) rhs);
    721 		return;
    722 	}
    723 
    724 	mp_int_mul(isl_sioimath_bigarg_src(lhs, &scratchlhs),
    725 	    isl_sioimath_siarg_src(rhs, &scratchrhs),
    726 	    isl_sioimath_reinit_big(dst));
    727 	isl_sioimath_try_demote(dst);
    728 }
    729 
    730 /* Multiply an isl_int and an unsigned long.
    731  */
    732 inline void isl_sioimath_mul_ui(isl_sioimath_ptr dst, isl_sioimath lhs,
    733 	unsigned long rhs)
    734 {
    735 	isl_sioimath_scratchspace_t scratchlhs, scratchrhs;
    736 	int32_t smalllhs;
    737 
    738 	if (isl_sioimath_decode_small(lhs, &smalllhs) && (rhs <= UINT32_MAX)) {
    739 		isl_sioimath_set_int64(dst, (int64_t) smalllhs * (int64_t) rhs);
    740 		return;
    741 	}
    742 
    743 	mp_int_mul(isl_sioimath_bigarg_src(lhs, &scratchlhs),
    744 	    isl_sioimath_uiarg_src(rhs, &scratchrhs),
    745 	    isl_sioimath_reinit_big(dst));
    746 	isl_sioimath_try_demote(dst);
    747 }
    748 
    749 /* Compute the power of an isl_int to an unsigned long.
    750  * Always let IMath do it; the result is unlikely to be small except in some
    751  * special cases.
    752  * Note: 0^0 == 1
    753  */
    754 inline void isl_sioimath_pow_ui(isl_sioimath_ptr dst, isl_sioimath_src lhs,
    755 	unsigned long rhs)
    756 {
    757 	isl_sioimath_scratchspace_t scratchlhs, scratchrhs;
    758 	int32_t smalllhs;
    759 
    760 	switch (rhs) {
    761 	case 0:
    762 		isl_sioimath_set_small(dst, 1);
    763 		return;
    764 	case 1:
    765 		isl_sioimath_set(dst, lhs);
    766 		return;
    767 	case 2:
    768 		isl_sioimath_mul(dst, lhs, lhs);
    769 		return;
    770 	}
    771 
    772 	if (isl_sioimath_decode_small(lhs, &smalllhs)) {
    773 		switch (smalllhs) {
    774 		case 0:
    775 			isl_sioimath_set_small(dst, 0);
    776 			return;
    777 		case 1:
    778 			isl_sioimath_set_small(dst, 1);
    779 			return;
    780 		case 2:
    781 			isl_sioimath_set_small(dst, 1);
    782 			isl_sioimath_mul_2exp(dst, *dst, rhs);
    783 			return;
    784 		default:
    785 			if ((MP_SMALL_MIN <= rhs) && (rhs <= MP_SMALL_MAX)) {
    786 				mp_int_expt_value(smalllhs, rhs,
    787 				    isl_sioimath_reinit_big(dst));
    788 				isl_sioimath_try_demote(dst);
    789 				return;
    790 			}
    791 		}
    792 	}
    793 
    794 	mp_int_expt_full(isl_sioimath_bigarg_src(lhs, &scratchlhs),
    795 	    isl_sioimath_uiarg_src(rhs, &scratchrhs),
    796 	    isl_sioimath_reinit_big(dst));
    797 	isl_sioimath_try_demote(dst);
    798 }
    799 
    800 /* Fused multiply-add.
    801  */
    802 inline void isl_sioimath_addmul(isl_sioimath_ptr dst, isl_sioimath_src lhs,
    803 	isl_sioimath_src rhs)
    804 {
    805 	isl_sioimath tmp;
    806 	isl_sioimath_init(&tmp);
    807 	isl_sioimath_mul(&tmp, lhs, rhs);
    808 	isl_sioimath_add(dst, *dst, tmp);
    809 	isl_sioimath_clear(&tmp);
    810 }
    811 
    812 /* Fused multiply-add with an unsigned long.
    813  */
    814 inline void isl_sioimath_addmul_ui(isl_sioimath_ptr dst, isl_sioimath_src lhs,
    815 	unsigned long rhs)
    816 {
    817 	isl_sioimath tmp;
    818 	isl_sioimath_init(&tmp);
    819 	isl_sioimath_mul_ui(&tmp, lhs, rhs);
    820 	isl_sioimath_add(dst, *dst, tmp);
    821 	isl_sioimath_clear(&tmp);
    822 }
    823 
    824 /* Fused multiply-subtract.
    825  */
    826 inline void isl_sioimath_submul(isl_sioimath_ptr dst, isl_sioimath_src lhs,
    827 	isl_sioimath_src rhs)
    828 {
    829 	isl_sioimath tmp;
    830 	isl_sioimath_init(&tmp);
    831 	isl_sioimath_mul(&tmp, lhs, rhs);
    832 	isl_sioimath_sub(dst, *dst, tmp);
    833 	isl_sioimath_clear(&tmp);
    834 }
    835 
    836 /* Fused multiply-add with an unsigned long.
    837  */
    838 inline void isl_sioimath_submul_ui(isl_sioimath_ptr dst, isl_sioimath_src lhs,
    839 	unsigned long rhs)
    840 {
    841 	isl_sioimath tmp;
    842 	isl_sioimath_init(&tmp);
    843 	isl_sioimath_mul_ui(&tmp, lhs, rhs);
    844 	isl_sioimath_sub(dst, *dst, tmp);
    845 	isl_sioimath_clear(&tmp);
    846 }
    847 
    848 void isl_sioimath_gcd(isl_sioimath_ptr dst, isl_sioimath_src lhs,
    849 		      isl_sioimath_src rhs);
    850 void isl_sioimath_lcm(isl_sioimath_ptr dst, isl_sioimath_src lhs,
    851 		      isl_sioimath_src rhs);
    852 
    853 /* Divide lhs by rhs, rounding to zero (Truncate).
    854  */
    855 inline void isl_sioimath_tdiv_q(isl_sioimath_ptr dst, isl_sioimath_src lhs,
    856 	isl_sioimath_src rhs)
    857 {
    858 	isl_sioimath_scratchspace_t lhsscratch, rhsscratch;
    859 	int32_t lhssmall, rhssmall;
    860 
    861 	if (isl_sioimath_decode_small(lhs, &lhssmall) &&
    862 	    isl_sioimath_decode_small(rhs, &rhssmall)) {
    863 		isl_sioimath_set_small(dst, lhssmall / rhssmall);
    864 		return;
    865 	}
    866 
    867 	mp_int_div(isl_sioimath_bigarg_src(lhs, &lhsscratch),
    868 	    isl_sioimath_bigarg_src(rhs, &rhsscratch),
    869 	    isl_sioimath_reinit_big(dst), NULL);
    870 	isl_sioimath_try_demote(dst);
    871 	return;
    872 }
    873 
    874 /* Divide lhs by an unsigned long rhs, rounding to zero (Truncate).
    875  */
    876 inline void isl_sioimath_tdiv_q_ui(isl_sioimath_ptr dst, isl_sioimath_src lhs,
    877 	unsigned long rhs)
    878 {
    879 	isl_sioimath_scratchspace_t lhsscratch, rhsscratch;
    880 	int32_t lhssmall;
    881 
    882 	if (isl_sioimath_is_small(lhs) && (rhs <= (unsigned long) INT32_MAX)) {
    883 		lhssmall = isl_sioimath_get_small(lhs);
    884 		isl_sioimath_set_small(dst, lhssmall / (int32_t) rhs);
    885 		return;
    886 	}
    887 
    888 	if (rhs <= MP_SMALL_MAX) {
    889 		mp_int_div_value(isl_sioimath_bigarg_src(lhs, &lhsscratch), rhs,
    890 		    isl_sioimath_reinit_big(dst), NULL);
    891 		isl_sioimath_try_demote(dst);
    892 		return;
    893 	}
    894 
    895 	mp_int_div(isl_sioimath_bigarg_src(lhs, &lhsscratch),
    896 	    isl_sioimath_uiarg_src(rhs, &rhsscratch),
    897 	    isl_sioimath_reinit_big(dst), NULL);
    898 	isl_sioimath_try_demote(dst);
    899 }
    900 
    901 /* Divide lhs by rhs, rounding to positive infinity (Ceil).
    902  */
    903 inline void isl_sioimath_cdiv_q(isl_sioimath_ptr dst, isl_sioimath_src lhs,
    904 	isl_sioimath_src rhs)
    905 {
    906 	int32_t lhssmall, rhssmall;
    907 	isl_sioimath_scratchspace_t lhsscratch, rhsscratch;
    908 	int32_t q;
    909 
    910 	if (isl_sioimath_decode_small(lhs, &lhssmall) &&
    911 	    isl_sioimath_decode_small(rhs, &rhssmall)) {
    912 		if ((lhssmall >= 0) && (rhssmall >= 0))
    913 			q = ((int64_t) lhssmall + (int64_t) rhssmall - 1) /
    914 			    rhssmall;
    915 		else if ((lhssmall < 0) && (rhssmall < 0))
    916 			q = ((int64_t) lhssmall + (int64_t) rhssmall + 1) /
    917 			    rhssmall;
    918 		else
    919 			q = lhssmall / rhssmall;
    920 		isl_sioimath_set_small(dst, q);
    921 		return;
    922 	}
    923 
    924 	impz_cdiv_q(isl_sioimath_reinit_big(dst),
    925 	    isl_sioimath_bigarg_src(lhs, &lhsscratch),
    926 	    isl_sioimath_bigarg_src(rhs, &rhsscratch));
    927 	isl_sioimath_try_demote(dst);
    928 }
    929 
    930 /* Compute the division of lhs by a rhs of type unsigned long, rounding towards
    931  * positive infinity (Ceil).
    932  */
    933 inline void isl_sioimath_cdiv_q_ui(isl_sioimath_ptr dst, isl_sioimath_src lhs,
    934 	unsigned long rhs)
    935 {
    936 	isl_sioimath_scratchspace_t lhsscratch, rhsscratch;
    937 	int32_t lhssmall, q;
    938 
    939 	if (isl_sioimath_decode_small(lhs, &lhssmall) && (rhs <= INT32_MAX)) {
    940 		if (lhssmall >= 0)
    941 			q = ((int64_t) lhssmall + ((int64_t) rhs - 1)) /
    942 			    (int64_t) rhs;
    943 		else
    944 			q = lhssmall / (int32_t) rhs;
    945 		isl_sioimath_set_small(dst, q);
    946 		return;
    947 	}
    948 
    949 	impz_cdiv_q(isl_sioimath_reinit_big(dst),
    950 	    isl_sioimath_bigarg_src(lhs, &lhsscratch),
    951 	    isl_sioimath_uiarg_src(rhs, &rhsscratch));
    952 	isl_sioimath_try_demote(dst);
    953 }
    954 
    955 /* Divide lhs by rhs, rounding to negative infinity (Floor).
    956  */
    957 inline void isl_sioimath_fdiv_q(isl_sioimath_ptr dst, isl_sioimath_src lhs,
    958 	isl_sioimath_src rhs)
    959 {
    960 	isl_sioimath_scratchspace_t lhsscratch, rhsscratch;
    961 	int32_t lhssmall, rhssmall;
    962 	int32_t q;
    963 
    964 	if (isl_sioimath_decode_small(lhs, &lhssmall) &&
    965 	    isl_sioimath_decode_small(rhs, &rhssmall)) {
    966 		if ((lhssmall < 0) && (rhssmall >= 0))
    967 			q = ((int64_t) lhssmall - ((int64_t) rhssmall - 1)) /
    968 			    rhssmall;
    969 		else if ((lhssmall >= 0) && (rhssmall < 0))
    970 			q = ((int64_t) lhssmall - ((int64_t) rhssmall + 1)) /
    971 			    rhssmall;
    972 		else
    973 			q = lhssmall / rhssmall;
    974 		isl_sioimath_set_small(dst, q);
    975 		return;
    976 	}
    977 
    978 	impz_fdiv_q(isl_sioimath_reinit_big(dst),
    979 	    isl_sioimath_bigarg_src(lhs, &lhsscratch),
    980 	    isl_sioimath_bigarg_src(rhs, &rhsscratch));
    981 	isl_sioimath_try_demote(dst);
    982 }
    983 
    984 /* Compute the division of lhs by a rhs of type unsigned long, rounding towards
    985  * negative infinity (Floor).
    986  */
    987 inline void isl_sioimath_fdiv_q_ui(isl_sioimath_ptr dst, isl_sioimath_src lhs,
    988 	unsigned long rhs)
    989 {
    990 	isl_sioimath_scratchspace_t lhsscratch, rhsscratch;
    991 	int32_t lhssmall, q;
    992 
    993 	if (isl_sioimath_decode_small(lhs, &lhssmall) && (rhs <= INT32_MAX)) {
    994 		if (lhssmall >= 0)
    995 			q = (uint32_t) lhssmall / rhs;
    996 		else
    997 			q = ((int64_t) lhssmall - ((int64_t) rhs - 1)) /
    998 			    (int64_t) rhs;
    999 		isl_sioimath_set_small(dst, q);
   1000 		return;
   1001 	}
   1002 
   1003 	impz_fdiv_q(isl_sioimath_reinit_big(dst),
   1004 	    isl_sioimath_bigarg_src(lhs, &lhsscratch),
   1005 	    isl_sioimath_uiarg_src(rhs, &rhsscratch));
   1006 	isl_sioimath_try_demote(dst);
   1007 }
   1008 
   1009 /* Get the remainder of: lhs divided by rhs rounded towards negative infinite
   1010  * (Floor).
   1011  */
   1012 inline void isl_sioimath_fdiv_r(isl_sioimath_ptr dst, isl_sioimath_src lhs,
   1013 	isl_sioimath_src rhs)
   1014 {
   1015 	isl_sioimath_scratchspace_t lhsscratch, rhsscratch;
   1016 	int64_t lhssmall, rhssmall;
   1017 	int32_t r;
   1018 
   1019 	if (isl_sioimath_is_small(lhs) && isl_sioimath_is_small(rhs)) {
   1020 		lhssmall = isl_sioimath_get_small(lhs);
   1021 		rhssmall = isl_sioimath_get_small(rhs);
   1022 		r = (rhssmall + lhssmall % rhssmall) % rhssmall;
   1023 		isl_sioimath_set_small(dst, r);
   1024 		return;
   1025 	}
   1026 
   1027 	impz_fdiv_r(isl_sioimath_reinit_big(dst),
   1028 	    isl_sioimath_bigarg_src(lhs, &lhsscratch),
   1029 	    isl_sioimath_bigarg_src(rhs, &rhsscratch));
   1030 	isl_sioimath_try_demote(dst);
   1031 }
   1032 
   1033 void isl_sioimath_read(isl_sioimath_ptr dst, const char *str);
   1034 
   1035 /* Return:
   1036  *   +1 for a positive number
   1037  *   -1 for a negative number
   1038  *    0 if the number is zero
   1039  */
   1040 inline int isl_sioimath_sgn(isl_sioimath_src arg)
   1041 {
   1042 	int32_t small;
   1043 
   1044 	if (isl_sioimath_decode_small(arg, &small))
   1045 		return (small > 0) - (small < 0);
   1046 
   1047 	return mp_int_compare_zero(isl_sioimath_get_big(arg));
   1048 }
   1049 
   1050 /* Return:
   1051  *   +1 if lhs > rhs
   1052  *   -1 if lhs < rhs
   1053  *    0 if lhs = rhs
   1054  */
   1055 inline int isl_sioimath_cmp(isl_sioimath_src lhs, isl_sioimath_src rhs)
   1056 {
   1057 	isl_sioimath_scratchspace_t lhsscratch, rhsscratch;
   1058 	int32_t lhssmall, rhssmall;
   1059 
   1060 	if (isl_sioimath_decode_small(lhs, &lhssmall) &&
   1061 	    isl_sioimath_decode_small(rhs, &rhssmall))
   1062 		return (lhssmall > rhssmall) - (lhssmall < rhssmall);
   1063 
   1064 	if (isl_sioimath_decode_small(rhs, &rhssmall))
   1065 		return mp_int_compare_value(
   1066 		    isl_sioimath_bigarg_src(lhs, &lhsscratch), rhssmall);
   1067 
   1068 	if (isl_sioimath_decode_small(lhs, &lhssmall))
   1069 		return -mp_int_compare_value(
   1070 		           isl_sioimath_bigarg_src(rhs, &rhsscratch), lhssmall);
   1071 
   1072 	return mp_int_compare(
   1073 	    isl_sioimath_get_big(lhs), isl_sioimath_get_big(rhs));
   1074 }
   1075 
   1076 /* As isl_sioimath_cmp, but with signed long rhs.
   1077  */
   1078 inline int isl_sioimath_cmp_si(isl_sioimath_src lhs, signed long rhs)
   1079 {
   1080 	int32_t lhssmall;
   1081 
   1082 	if (isl_sioimath_decode_small(lhs, &lhssmall))
   1083 		return (lhssmall > rhs) - (lhssmall < rhs);
   1084 
   1085 	return mp_int_compare_value(isl_sioimath_get_big(lhs), rhs);
   1086 }
   1087 
   1088 /* Return:
   1089  *   +1 if |lhs| > |rhs|
   1090  *   -1 if |lhs| < |rhs|
   1091  *    0 if |lhs| = |rhs|
   1092  */
   1093 inline int isl_sioimath_abs_cmp(isl_sioimath_src lhs, isl_sioimath_src rhs)
   1094 {
   1095 	isl_sioimath_scratchspace_t lhsscratch, rhsscratch;
   1096 	int32_t lhssmall, rhssmall;
   1097 
   1098 	if (isl_sioimath_decode_small(lhs, &lhssmall) &&
   1099 	    isl_sioimath_decode_small(rhs, &rhssmall)) {
   1100 		lhssmall = labs(lhssmall);
   1101 		rhssmall = labs(rhssmall);
   1102 		return (lhssmall > rhssmall) - (lhssmall < rhssmall);
   1103 	}
   1104 
   1105 	return mp_int_compare_unsigned(
   1106 	    isl_sioimath_bigarg_src(lhs, &lhsscratch),
   1107 	    isl_sioimath_bigarg_src(rhs, &rhsscratch));
   1108 }
   1109 
   1110 /* Return whether lhs is divisible by rhs.
   1111  * In particular, can rhs be multiplied by some integer to result in lhs?
   1112  * If rhs is zero, then this means lhs has to be zero too.
   1113  */
   1114 inline int isl_sioimath_is_divisible_by(isl_sioimath_src lhs,
   1115 					isl_sioimath_src rhs)
   1116 {
   1117 	isl_sioimath_scratchspace_t lhsscratch, rhsscratch;
   1118 	int32_t lhssmall, rhssmall;
   1119 	mpz_t rem;
   1120 	int cmp;
   1121 
   1122 	if (isl_sioimath_sgn(rhs) == 0)
   1123 		return isl_sioimath_sgn(lhs) == 0;
   1124 
   1125 	if (isl_sioimath_decode_small(lhs, &lhssmall) &&
   1126 	    isl_sioimath_decode_small(rhs, &rhssmall))
   1127 		return lhssmall % rhssmall == 0;
   1128 
   1129 	if (isl_sioimath_decode_small(rhs, &rhssmall))
   1130 		return mp_int_divisible_value(
   1131 		    isl_sioimath_bigarg_src(lhs, &lhsscratch), rhssmall);
   1132 
   1133 	mp_int_init(&rem);
   1134 	mp_int_div(isl_sioimath_bigarg_src(lhs, &lhsscratch),
   1135 	    isl_sioimath_bigarg_src(rhs, &rhsscratch), NULL, &rem);
   1136 	cmp = mp_int_compare_zero(&rem);
   1137 	mp_int_clear(&rem);
   1138 	return cmp == 0;
   1139 }
   1140 
   1141 /* Return a hash code of an isl_sioimath.
   1142  * The hash code for a number in small and big representation must be identical
   1143  * on the same machine because small representation if not obligatory if fits.
   1144  */
   1145 inline uint32_t isl_sioimath_hash(isl_sioimath_src arg, uint32_t hash)
   1146 {
   1147 	int32_t small;
   1148 	int i;
   1149 	uint32_t num;
   1150 	mp_digit digits[(sizeof(uint32_t) + sizeof(mp_digit) - 1) /
   1151 	                sizeof(mp_digit)];
   1152 	mp_size used;
   1153 	const unsigned char *digitdata = (const unsigned char *) &digits;
   1154 
   1155 	if (isl_sioimath_decode_small(arg, &small)) {
   1156 		if (small < 0)
   1157 			isl_hash_byte(hash, 0xFF);
   1158 		num = labs(small);
   1159 
   1160 		isl_siomath_uint32_to_digits(num, digits, &used);
   1161 		for (i = 0; i < used * sizeof(mp_digit); i += 1)
   1162 			isl_hash_byte(hash, digitdata[i]);
   1163 		return hash;
   1164 	}
   1165 
   1166 	return isl_imath_hash(isl_sioimath_get_big(arg), hash);
   1167 }
   1168 
   1169 /* Return the number of digits in a number of the given base or more, i.e. the
   1170  * string length without sign and null terminator.
   1171  *
   1172  * Current implementation for small representation returns the maximal number
   1173  * of binary digits in that representation, which can be much larger than the
   1174  * smallest possible solution.
   1175  */
   1176 inline size_t isl_sioimath_sizeinbase(isl_sioimath_src arg, int base)
   1177 {
   1178 	int32_t small;
   1179 
   1180 	if (isl_sioimath_decode_small(arg, &small))
   1181 		return sizeof(int32_t) * CHAR_BIT - 1;
   1182 
   1183 	return impz_sizeinbase(isl_sioimath_get_big(arg), base);
   1184 }
   1185 
   1186 void isl_sioimath_print(FILE *out, isl_sioimath_src i, int width);
   1187 void isl_sioimath_dump(isl_sioimath_src arg);
   1188 
   1189 typedef isl_sioimath isl_int[1];
   1190 #define isl_int_init(i)			isl_sioimath_init((i))
   1191 #define isl_int_clear(i)		isl_sioimath_clear((i))
   1192 
   1193 #define isl_int_set(r, i)		isl_sioimath_set((r), *(i))
   1194 #define isl_int_set_si(r, i)		isl_sioimath_set_si((r), i)
   1195 #define isl_int_set_ui(r, i)		isl_sioimath_set_ui((r), i)
   1196 #define isl_int_fits_slong(r)		isl_sioimath_fits_slong(*(r))
   1197 #define isl_int_get_si(r)		isl_sioimath_get_si(*(r))
   1198 #define isl_int_fits_ulong(r)		isl_sioimath_fits_ulong(*(r))
   1199 #define isl_int_get_ui(r)		isl_sioimath_get_ui(*(r))
   1200 #define isl_int_get_d(r)		isl_sioimath_get_d(*(r))
   1201 #define isl_int_get_str(r)		isl_sioimath_get_str(*(r))
   1202 #define isl_int_abs(r, i)		isl_sioimath_abs((r), *(i))
   1203 #define isl_int_neg(r, i)		isl_sioimath_neg((r), *(i))
   1204 #define isl_int_swap(i, j)		isl_sioimath_swap((i), (j))
   1205 #define isl_int_swap_or_set(i, j)	isl_sioimath_swap((i), (j))
   1206 #define isl_int_add_ui(r, i, j)		isl_sioimath_add_ui((r), *(i), j)
   1207 #define isl_int_sub_ui(r, i, j)		isl_sioimath_sub_ui((r), *(i), j)
   1208 
   1209 #define isl_int_add(r, i, j)		isl_sioimath_add((r), *(i), *(j))
   1210 #define isl_int_sub(r, i, j)		isl_sioimath_sub((r), *(i), *(j))
   1211 #define isl_int_mul(r, i, j)		isl_sioimath_mul((r), *(i), *(j))
   1212 #define isl_int_mul_2exp(r, i, j)	isl_sioimath_mul_2exp((r), *(i), j)
   1213 #define isl_int_mul_si(r, i, j)		isl_sioimath_mul_si((r), *(i), j)
   1214 #define isl_int_mul_ui(r, i, j)		isl_sioimath_mul_ui((r), *(i), j)
   1215 #define isl_int_pow_ui(r, i, j)		isl_sioimath_pow_ui((r), *(i), j)
   1216 #define isl_int_addmul(r, i, j)		isl_sioimath_addmul((r), *(i), *(j))
   1217 #define isl_int_addmul_ui(r, i, j)	isl_sioimath_addmul_ui((r), *(i), j)
   1218 #define isl_int_submul(r, i, j)		isl_sioimath_submul((r), *(i), *(j))
   1219 #define isl_int_submul_ui(r, i, j)	isl_sioimath_submul_ui((r), *(i), j)
   1220 
   1221 #define isl_int_gcd(r, i, j)		isl_sioimath_gcd((r), *(i), *(j))
   1222 #define isl_int_lcm(r, i, j)		isl_sioimath_lcm((r), *(i), *(j))
   1223 #define isl_int_divexact(r, i, j)	isl_sioimath_tdiv_q((r), *(i), *(j))
   1224 #define isl_int_divexact_ui(r, i, j)	isl_sioimath_tdiv_q_ui((r), *(i), j)
   1225 #define isl_int_tdiv_q(r, i, j)		isl_sioimath_tdiv_q((r), *(i), *(j))
   1226 #define isl_int_cdiv_q(r, i, j)		isl_sioimath_cdiv_q((r), *(i), *(j))
   1227 #define isl_int_cdiv_q_ui(r, i, j)	isl_sioimath_cdiv_q_ui((r), *(i), j)
   1228 #define isl_int_fdiv_q(r, i, j)		isl_sioimath_fdiv_q((r), *(i), *(j))
   1229 #define isl_int_fdiv_r(r, i, j)		isl_sioimath_fdiv_r((r), *(i), *(j))
   1230 #define isl_int_fdiv_q_ui(r, i, j)	isl_sioimath_fdiv_q_ui((r), *(i), j)
   1231 
   1232 #define isl_int_read(r, s)		isl_sioimath_read((r), s)
   1233 #define isl_int_sgn(i)			isl_sioimath_sgn(*(i))
   1234 #define isl_int_cmp(i, j)		isl_sioimath_cmp(*(i), *(j))
   1235 #define isl_int_cmp_si(i, si)		isl_sioimath_cmp_si(*(i), si)
   1236 #define isl_int_eq(i, j)		(isl_sioimath_cmp(*(i), *(j)) == 0)
   1237 #define isl_int_ne(i, j)		(isl_sioimath_cmp(*(i), *(j)) != 0)
   1238 #define isl_int_lt(i, j)		(isl_sioimath_cmp(*(i), *(j)) < 0)
   1239 #define isl_int_le(i, j)		(isl_sioimath_cmp(*(i), *(j)) <= 0)
   1240 #define isl_int_gt(i, j)		(isl_sioimath_cmp(*(i), *(j)) > 0)
   1241 #define isl_int_ge(i, j)		(isl_sioimath_cmp(*(i), *(j)) >= 0)
   1242 #define isl_int_abs_cmp(i, j)		isl_sioimath_abs_cmp(*(i), *(j))
   1243 #define isl_int_abs_eq(i, j)		(isl_sioimath_abs_cmp(*(i), *(j)) == 0)
   1244 #define isl_int_abs_ne(i, j)		(isl_sioimath_abs_cmp(*(i), *(j)) != 0)
   1245 #define isl_int_abs_lt(i, j)		(isl_sioimath_abs_cmp(*(i), *(j)) < 0)
   1246 #define isl_int_abs_gt(i, j)		(isl_sioimath_abs_cmp(*(i), *(j)) > 0)
   1247 #define isl_int_abs_ge(i, j)		(isl_sioimath_abs_cmp(*(i), *(j)) >= 0)
   1248 #define isl_int_is_divisible_by(i, j)	isl_sioimath_is_divisible_by(*(i), *(j))
   1249 
   1250 #define isl_int_hash(v, h)		isl_sioimath_hash(*(v), h)
   1251 #define isl_int_free_str(s)		free(s)
   1252 #define isl_int_print(out, i, width)	isl_sioimath_print(out, *(i), width)
   1253 
   1254 #endif /* ISL_INT_SIOIMATH_H */
   1255