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  */
isl_sioimath_is_small(isl_sioimath val)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  */
isl_sioimath_is_big(isl_sioimath val)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  */
isl_sioimath_get_small(isl_sioimath val)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  */
isl_sioimath_get_big(isl_sioimath val)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  */
isl_sioimath_decode_small(isl_sioimath val,int32_t * small)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  */
isl_sioimath_decode_big(isl_sioimath val,mp_int * big)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  */
isl_sioimath_encode_small(int32_t val)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  */
isl_sioimath_encode_big(mp_int val)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 
isl_siomath_uint32_to_digits(uint32_t num,mp_digit * digits,mp_size * used)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 
isl_siomath_ulong_to_digits(unsigned long num,mp_digit * digits,mp_size * used)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 
isl_siomath_uint64_to_digits(uint64_t num,mp_digit * digits,mp_size * used)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  */
isl_sioimath_bigarg_src(isl_sioimath arg,isl_sioimath_scratchspace_t * scratch)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  */
isl_sioimath_siarg_src(signed long arg,isl_sioimath_scratchspace_t * scratch)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  */
isl_sioimath_si64arg_src(int64_t arg,isl_sioimath_scratchspace_t * scratch)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  */
isl_sioimath_uiarg_src(unsigned long arg,isl_sioimath_scratchspace_t * scratch)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  */
isl_sioimath_reinit_big(isl_sioimath_ptr ptr)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  */
isl_sioimath_set_small(isl_sioimath_ptr ptr,int32_t val)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  */
isl_sioimath_set_int32(isl_sioimath_ptr ptr,int32_t val)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  */
isl_sioimath_set_int64(isl_sioimath_ptr ptr,int64_t val)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  */
isl_sioimath_promote(isl_sioimath_ptr dst)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  */
isl_sioimath_try_demote(isl_sioimath_ptr dst)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  */
isl_sioimath_init(isl_sioimath_ptr dst)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  */
isl_sioimath_clear(isl_sioimath_ptr dst)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  */
isl_sioimath_set(isl_sioimath_ptr dst,isl_sioimath_src val)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  */
isl_sioimath_set_si(isl_sioimath_ptr dst,long val)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  */
isl_sioimath_set_ui(isl_sioimath_ptr dst,unsigned long val)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  */
isl_sioimath_fits_slong(isl_sioimath_src val)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  */
isl_sioimath_get_si(isl_sioimath_src val)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  */
isl_sioimath_fits_ulong(isl_sioimath_src val)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  */
isl_sioimath_get_ui(isl_sioimath_src val)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  */
isl_sioimath_get_d(isl_sioimath_src val)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  */
isl_sioimath_get_str(isl_sioimath_src val)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  */
isl_sioimath_abs(isl_sioimath_ptr dst,isl_sioimath_src arg)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  */
isl_sioimath_neg(isl_sioimath_ptr dst,isl_sioimath_src arg)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  */
isl_sioimath_swap(isl_sioimath_ptr lhs,isl_sioimath_ptr rhs)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  */
isl_sioimath_add_ui(isl_sioimath_ptr dst,isl_sioimath lhs,unsigned long rhs)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  */
isl_sioimath_sub_ui(isl_sioimath_ptr dst,isl_sioimath lhs,unsigned long rhs)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  */
isl_sioimath_add(isl_sioimath_ptr dst,isl_sioimath_src lhs,isl_sioimath_src rhs)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  */
isl_sioimath_sub(isl_sioimath_ptr dst,isl_sioimath_src lhs,isl_sioimath_src rhs)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  */
isl_sioimath_mul(isl_sioimath_ptr dst,isl_sioimath_src lhs,isl_sioimath_src rhs)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  */
isl_sioimath_mul_2exp(isl_sioimath_ptr dst,isl_sioimath lhs,unsigned long rhs)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  */
isl_sioimath_mul_si(isl_sioimath_ptr dst,isl_sioimath lhs,signed long rhs)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  */
isl_sioimath_mul_ui(isl_sioimath_ptr dst,isl_sioimath lhs,unsigned long rhs)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  */
isl_sioimath_pow_ui(isl_sioimath_ptr dst,isl_sioimath_src lhs,unsigned long rhs)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  */
isl_sioimath_addmul(isl_sioimath_ptr dst,isl_sioimath_src lhs,isl_sioimath_src rhs)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  */
isl_sioimath_addmul_ui(isl_sioimath_ptr dst,isl_sioimath_src lhs,unsigned long rhs)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  */
isl_sioimath_submul(isl_sioimath_ptr dst,isl_sioimath_src lhs,isl_sioimath_src rhs)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  */
isl_sioimath_submul_ui(isl_sioimath_ptr dst,isl_sioimath_src lhs,unsigned long rhs)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  */
isl_sioimath_tdiv_q(isl_sioimath_ptr dst,isl_sioimath_src lhs,isl_sioimath_src rhs)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  */
isl_sioimath_tdiv_q_ui(isl_sioimath_ptr dst,isl_sioimath_src lhs,unsigned long rhs)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  */
isl_sioimath_cdiv_q(isl_sioimath_ptr dst,isl_sioimath_src lhs,isl_sioimath_src rhs)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  */
isl_sioimath_cdiv_q_ui(isl_sioimath_ptr dst,isl_sioimath_src lhs,unsigned long rhs)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  */
isl_sioimath_fdiv_q(isl_sioimath_ptr dst,isl_sioimath_src lhs,isl_sioimath_src rhs)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  */
isl_sioimath_fdiv_q_ui(isl_sioimath_ptr dst,isl_sioimath_src lhs,unsigned long rhs)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  */
isl_sioimath_fdiv_r(isl_sioimath_ptr dst,isl_sioimath_src lhs,isl_sioimath_src rhs)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  */
isl_sioimath_sgn(isl_sioimath_src arg)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  */
isl_sioimath_cmp(isl_sioimath_src lhs,isl_sioimath_src rhs)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  */
isl_sioimath_cmp_si(isl_sioimath_src lhs,signed long rhs)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  */
isl_sioimath_abs_cmp(isl_sioimath_src lhs,isl_sioimath_src rhs)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  */
isl_sioimath_is_divisible_by(isl_sioimath_src lhs,isl_sioimath_src rhs)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  */
isl_sioimath_hash(isl_sioimath_src arg,uint32_t hash)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  */
isl_sioimath_sizeinbase(isl_sioimath_src arg,int base)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