/Users/buildslave/jenkins/workspace/clang-stage2-coverage-R/llvm/tools/polly/lib/External/isl/imath/gmp_compat.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | Name: gmp_compat.c |
3 | | Purpose: Provide GMP compatiable routines for imath library |
4 | | Author: David Peixotto |
5 | | |
6 | | Copyright (c) 2012 Qualcomm Innovation Center, Inc. All rights reserved. |
7 | | |
8 | | Permission is hereby granted, free of charge, to any person obtaining a copy |
9 | | of this software and associated documentation files (the "Software"), to deal |
10 | | in the Software without restriction, including without limitation the rights |
11 | | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
12 | | copies of the Software, and to permit persons to whom the Software is |
13 | | furnished to do so, subject to the following conditions: |
14 | | |
15 | | The above copyright notice and this permission notice shall be included in |
16 | | all copies or substantial portions of the Software. |
17 | | |
18 | | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
19 | | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
20 | | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
21 | | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
22 | | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
23 | | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE |
24 | | SOFTWARE. |
25 | | */ |
26 | | #include "gmp_compat.h" |
27 | | #include <stdlib.h> |
28 | | #include <assert.h> |
29 | | #include <ctype.h> |
30 | | #include <string.h> |
31 | | #include <stdio.h> |
32 | | |
33 | | #if defined(_MSC_VER) |
34 | | #include <BaseTsd.h> |
35 | | typedef SSIZE_T ssize_t; |
36 | | #endif |
37 | | |
38 | | #ifdef NDEBUG |
39 | 8.70M | #define CHECK(res) (res0 ) |
40 | | #else |
41 | | #define CHECK(res) assert(((res) == MP_OK) && "expected MP_OK") |
42 | | #endif |
43 | | |
44 | | /* *(signed char *)&endian_test will thus either be: |
45 | | * 0b00000001 = 1 on big-endian |
46 | | * 0b11111111 = -1 on little-endian */ |
47 | | static const uint16_t endian_test = 0x1FF; |
48 | 23.1k | #define HOST_ENDIAN (*(signed char *)&endian_test) |
49 | | |
50 | | /************************************************************************* |
51 | | * |
52 | | * Functions with direct translations |
53 | | * |
54 | | *************************************************************************/ |
55 | | /* gmp: mpq_clear */ |
56 | 0 | void GMPQAPI(clear)(mp_rat x) { |
57 | 0 | mp_rat_clear(x); |
58 | 0 | } |
59 | | |
60 | | /* gmp: mpq_cmp */ |
61 | 0 | int GMPQAPI(cmp)(mp_rat op1, mp_rat op2) { |
62 | 0 | return mp_rat_compare(op1, op2); |
63 | 0 | } |
64 | | |
65 | | /* gmp: mpq_init */ |
66 | 0 | void GMPQAPI(init)(mp_rat x) { |
67 | 0 | CHECK(mp_rat_init(x)); |
68 | 0 | } |
69 | | |
70 | | /* gmp: mpq_mul */ |
71 | 0 | void GMPQAPI(mul)(mp_rat product, mp_rat multiplier, mp_rat multiplicand) { |
72 | 0 | CHECK(mp_rat_mul(multiplier, multiplicand, product)); |
73 | 0 | } |
74 | | |
75 | | /* gmp: mpq_set*/ |
76 | 0 | void GMPQAPI(set)(mp_rat rop, mp_rat op) { |
77 | 0 | CHECK(mp_rat_copy(op, rop)); |
78 | 0 | } |
79 | | |
80 | | /* gmp: mpz_abs */ |
81 | 0 | void GMPZAPI(abs)(mp_int rop, mp_int op) { |
82 | 0 | CHECK(mp_int_abs(op, rop)); |
83 | 0 | } |
84 | | |
85 | | /* gmp: mpz_add */ |
86 | 0 | void GMPZAPI(add)(mp_int rop, mp_int op1, mp_int op2) { |
87 | 0 | CHECK(mp_int_add(op1, op2, rop)); |
88 | 0 | } |
89 | | |
90 | | /* gmp: mpz_clear */ |
91 | 0 | void GMPZAPI(clear)(mp_int x) { |
92 | 0 | mp_int_clear(x); |
93 | 0 | } |
94 | | |
95 | | /* gmp: mpz_cmp_si */ |
96 | 0 | int GMPZAPI(cmp_si)(mp_int op1, long op2) { |
97 | 0 | return mp_int_compare_value(op1, op2); |
98 | 0 | } |
99 | | |
100 | | /* gmp: mpz_cmpabs */ |
101 | 0 | int GMPZAPI(cmpabs)(mp_int op1, mp_int op2) { |
102 | 0 | return mp_int_compare_unsigned(op1, op2); |
103 | 0 | } |
104 | | |
105 | | /* gmp: mpz_cmp */ |
106 | 0 | int GMPZAPI(cmp)(mp_int op1, mp_int op2) { |
107 | 0 | return mp_int_compare(op1, op2); |
108 | 0 | } |
109 | | |
110 | | /* gmp: mpz_init */ |
111 | 0 | void GMPZAPI(init)(mp_int x) { |
112 | 0 | CHECK(mp_int_init(x)); |
113 | 0 | } |
114 | | |
115 | | /* gmp: mpz_mul */ |
116 | 0 | void GMPZAPI(mul)(mp_int rop, mp_int op1, mp_int op2) { |
117 | 0 | CHECK(mp_int_mul(op1, op2, rop)); |
118 | 0 | } |
119 | | |
120 | | /* gmp: mpz_neg */ |
121 | 376k | void GMPZAPI(neg)(mp_int rop, mp_int op) { |
122 | 376k | CHECK(mp_int_neg(op, rop)); |
123 | 376k | } |
124 | | |
125 | | /* gmp: mpz_set_si */ |
126 | 0 | void GMPZAPI(set_si)(mp_int rop, long op) { |
127 | 0 | CHECK(mp_int_set_value(rop, op)); |
128 | 0 | } |
129 | | |
130 | | /* gmp: mpz_set */ |
131 | 376k | void GMPZAPI(set)(mp_int rop, mp_int op) { |
132 | 376k | CHECK(mp_int_copy(op, rop)); |
133 | 376k | } |
134 | | |
135 | | /* gmp: mpz_sub */ |
136 | 0 | void GMPZAPI(sub)(mp_int rop, mp_int op1, mp_int op2) { |
137 | 0 | CHECK(mp_int_sub(op1, op2, rop)); |
138 | 0 | } |
139 | | |
140 | | /* gmp: mpz_swap */ |
141 | 0 | void GMPZAPI(swap)(mp_int rop1, mp_int rop2) { |
142 | 0 | mp_int_swap(rop1, rop2); |
143 | 0 | } |
144 | | |
145 | | /* gmp: mpq_sgn */ |
146 | 0 | int GMPQAPI(sgn)(mp_rat op) { |
147 | 0 | return mp_rat_compare_zero(op); |
148 | 0 | } |
149 | | |
150 | | /* gmp: mpz_sgn */ |
151 | 0 | int GMPZAPI(sgn)(mp_int op) { |
152 | 0 | return mp_int_compare_zero(op); |
153 | 0 | } |
154 | | |
155 | | /* gmp: mpq_set_ui */ |
156 | 0 | void GMPQAPI(set_ui)(mp_rat rop, unsigned long op1, unsigned long op2) { |
157 | 0 | CHECK(mp_rat_set_uvalue(rop, op1, op2)); |
158 | 0 | } |
159 | | |
160 | | /* gmp: mpz_set_ui */ |
161 | 0 | void GMPZAPI(set_ui)(mp_int rop, unsigned long op) { |
162 | 0 | CHECK(mp_int_set_uvalue(rop, op)); |
163 | 0 | } |
164 | | |
165 | | /* gmp: mpq_den_ref */ |
166 | 0 | mp_int GMPQAPI(denref)(mp_rat op) { |
167 | 0 | return mp_rat_denom_ref(op); |
168 | 0 | } |
169 | | |
170 | | /* gmp: mpq_num_ref */ |
171 | 0 | mp_int GMPQAPI(numref)(mp_rat op) { |
172 | 0 | return mp_rat_numer_ref(op); |
173 | 0 | } |
174 | | |
175 | | /* gmp: mpq_canonicalize */ |
176 | 0 | void GMPQAPI(canonicalize)(mp_rat op) { |
177 | 0 | CHECK(mp_rat_reduce(op)); |
178 | 0 | } |
179 | | |
180 | | /************************************************************************* |
181 | | * |
182 | | * Functions that can be implemented as a combination of imath functions |
183 | | * |
184 | | *************************************************************************/ |
185 | | /* gmp: mpz_addmul */ |
186 | | /* gmp: rop = rop + (op1 * op2) */ |
187 | 0 | void GMPZAPI(addmul)(mp_int rop, mp_int op1, mp_int op2) { |
188 | 0 | mpz_t tempz; |
189 | 0 | mp_int temp = &tempz; |
190 | 0 | mp_int_init(temp); |
191 | 0 |
|
192 | 0 | CHECK(mp_int_mul(op1, op2, temp)); |
193 | 0 | CHECK(mp_int_add(rop, temp, rop)); |
194 | 0 | mp_int_clear(temp); |
195 | 0 | } |
196 | | |
197 | | /* gmp: mpz_divexact */ |
198 | | /* gmp: only produces correct results when d divides n */ |
199 | 0 | void GMPZAPI(divexact)(mp_int q, mp_int n, mp_int d) { |
200 | 0 | CHECK(mp_int_div(n, d, q, NULL)); |
201 | 0 | } |
202 | | |
203 | | /* gmp: mpz_divisible_p */ |
204 | | /* gmp: return 1 if d divides n, 0 otherwise */ |
205 | | /* gmp: 0 is considered to divide only 0 */ |
206 | 0 | int GMPZAPI(divisible_p)(mp_int n, mp_int d) { |
207 | 0 | /* variables to hold remainder */ |
208 | 0 | mpz_t rz; |
209 | 0 | mp_int r = &rz; |
210 | 0 | int r_is_zero; |
211 | 0 |
|
212 | 0 | /* check for d = 0 */ |
213 | 0 | int n_is_zero = mp_int_compare_zero(n) == 0; |
214 | 0 | int d_is_zero = mp_int_compare_zero(d) == 0; |
215 | 0 | if (d_is_zero) |
216 | 0 | return n_is_zero; |
217 | 0 | |
218 | 0 | /* return true if remainder is 0 */ |
219 | 0 | CHECK(mp_int_init(r)); |
220 | 0 | CHECK(mp_int_div(n, d, NULL, r)); |
221 | 0 | r_is_zero = mp_int_compare_zero(r) == 0; |
222 | 0 | mp_int_clear(r); |
223 | 0 |
|
224 | 0 | return r_is_zero; |
225 | 0 | } |
226 | | |
227 | | /* gmp: mpz_submul */ |
228 | | /* gmp: rop = rop - (op1 * op2) */ |
229 | 0 | void GMPZAPI(submul)(mp_int rop, mp_int op1, mp_int op2) { |
230 | 0 | mpz_t tempz; |
231 | 0 | mp_int temp = &tempz; |
232 | 0 | mp_int_init(temp); |
233 | 0 |
|
234 | 0 | CHECK(mp_int_mul(op1, op2, temp)); |
235 | 0 | CHECK(mp_int_sub(rop, temp, rop)); |
236 | 0 |
|
237 | 0 | mp_int_clear(temp); |
238 | 0 | } |
239 | | |
240 | | /* gmp: mpz_add_ui */ |
241 | 70.2k | void GMPZAPI(add_ui)(mp_int rop, mp_int op1, unsigned long op2) { |
242 | 70.2k | mpz_t tempz; |
243 | 70.2k | mp_int temp = &tempz; |
244 | 70.2k | CHECK(mp_int_init_uvalue(temp, op2)); |
245 | 70.2k | |
246 | 70.2k | CHECK(mp_int_add(op1, temp, rop)); |
247 | 70.2k | |
248 | 70.2k | mp_int_clear(temp); |
249 | 70.2k | } |
250 | | |
251 | | /* gmp: mpz_divexact_ui */ |
252 | | /* gmp: only produces correct results when d divides n */ |
253 | 0 | void GMPZAPI(divexact_ui)(mp_int q, mp_int n, unsigned long d) { |
254 | 0 | mpz_t tempz; |
255 | 0 | mp_int temp = &tempz; |
256 | 0 | CHECK(mp_int_init_uvalue(temp, d)); |
257 | 0 |
|
258 | 0 | CHECK(mp_int_div(n, temp, q, NULL)); |
259 | 0 |
|
260 | 0 | mp_int_clear(temp); |
261 | 0 | } |
262 | | |
263 | | /* gmp: mpz_mul_ui */ |
264 | 0 | void GMPZAPI(mul_ui)(mp_int rop, mp_int op1, unsigned long op2) { |
265 | 0 | mpz_t tempz; |
266 | 0 | mp_int temp = &tempz; |
267 | 0 | CHECK(mp_int_init_uvalue(temp, op2)); |
268 | 0 |
|
269 | 0 | CHECK(mp_int_mul(op1, temp, rop)); |
270 | 0 |
|
271 | 0 | mp_int_clear(temp); |
272 | 0 | } |
273 | | |
274 | | /* gmp: mpz_pow_ui */ |
275 | | /* gmp: 0^0 = 1 */ |
276 | 0 | void GMPZAPI(pow_ui)(mp_int rop, mp_int base, unsigned long exp) { |
277 | 0 | mpz_t tempz; |
278 | 0 | mp_int temp = &tempz; |
279 | 0 |
|
280 | 0 | /* check for 0^0 */ |
281 | 0 | if (exp == 0 && mp_int_compare_zero(base) == 0) { |
282 | 0 | CHECK(mp_int_set_value(rop, 1)); |
283 | 0 | return; |
284 | 0 | } |
285 | 0 |
|
286 | 0 | /* rop = base^exp */ |
287 | 0 | CHECK(mp_int_init_uvalue(temp, exp)); |
288 | 0 | CHECK(mp_int_expt_full(base, temp, rop)); |
289 | 0 | mp_int_clear(temp); |
290 | 0 | } |
291 | | |
292 | | /* gmp: mpz_sub_ui */ |
293 | 113k | void GMPZAPI(sub_ui)(mp_int rop, mp_int op1, unsigned long op2) { |
294 | 113k | mpz_t tempz; |
295 | 113k | mp_int temp = &tempz; |
296 | 113k | CHECK(mp_int_init_uvalue(temp, op2)); |
297 | 113k | |
298 | 113k | CHECK(mp_int_sub(op1, temp, rop)); |
299 | 113k | |
300 | 113k | mp_int_clear(temp); |
301 | 113k | } |
302 | | |
303 | | /************************************************************************* |
304 | | * |
305 | | * Functions with different behavior in corner cases |
306 | | * |
307 | | *************************************************************************/ |
308 | | |
309 | | /* gmp: mpz_gcd */ |
310 | 2.89M | void GMPZAPI(gcd)(mp_int rop, mp_int op1, mp_int op2) { |
311 | 2.89M | int op1_is_zero = mp_int_compare_zero(op1) == 0; |
312 | 2.89M | int op2_is_zero = mp_int_compare_zero(op2) == 0; |
313 | 2.89M | |
314 | 2.89M | if (op1_is_zero && op2_is_zero27 ) { |
315 | 0 | mp_int_zero(rop); |
316 | 0 | return; |
317 | 0 | } |
318 | 2.89M | |
319 | 2.89M | CHECK(mp_int_gcd(op1, op2, rop)); |
320 | 2.89M | } |
321 | | |
322 | | /* gmp: mpz_get_str */ |
323 | 1.46k | char* GMPZAPI(get_str)(char *str, int radix, mp_int op) { |
324 | 1.46k | int i, r, len; |
325 | 1.46k | |
326 | 1.46k | /* Support negative radix like gmp */ |
327 | 1.46k | r = radix; |
328 | 1.46k | if (r < 0) |
329 | 0 | r = -r; |
330 | 1.46k | |
331 | 1.46k | /* Compute the length of the string needed to hold the int */ |
332 | 1.46k | len = mp_int_string_len(op, r); |
333 | 1.46k | if (str == NULL) { |
334 | 1.46k | str = malloc(len); |
335 | 1.46k | } |
336 | 1.46k | |
337 | 1.46k | /* Convert to string using imath function */ |
338 | 1.46k | CHECK(mp_int_to_string(op, r, str, len)); |
339 | 1.46k | |
340 | 1.46k | /* Change case to match gmp */ |
341 | 29.0k | for (i = 0; i < len - 1; i++27.5k ) |
342 | 27.5k | if (radix < 0) |
343 | 0 | str[i] = toupper(str[i]); |
344 | 27.5k | else |
345 | 27.5k | str[i] = tolower(str[i]); |
346 | 1.46k | return str; |
347 | 1.46k | } |
348 | | |
349 | | /* gmp: mpq_get_str */ |
350 | 0 | char* GMPQAPI(get_str)(char *str, int radix, mp_rat op) { |
351 | 0 | int i, r, len; |
352 | 0 |
|
353 | 0 | /* Only print numerator if it is a whole number */ |
354 | 0 | if (mp_int_compare_value(mp_rat_denom_ref(op), 1) == 0) |
355 | 0 | return GMPZAPI(get_str)(str, radix, mp_rat_numer_ref(op)); |
356 | 0 |
|
357 | 0 | /* Support negative radix like gmp */ |
358 | 0 | r = radix; |
359 | 0 | if (r < 0) |
360 | 0 | r = -r; |
361 | 0 |
|
362 | 0 | /* Compute the length of the string needed to hold the int */ |
363 | 0 | len = mp_rat_string_len(op, r); |
364 | 0 | if (str == NULL) { |
365 | 0 | str = malloc(len); |
366 | 0 | } |
367 | 0 |
|
368 | 0 | /* Convert to string using imath function */ |
369 | 0 | CHECK(mp_rat_to_string(op, r, str, len)); |
370 | 0 |
|
371 | 0 | /* Change case to match gmp */ |
372 | 0 | for (i = 0; i < len; i++) |
373 | 0 | if (radix < 0) |
374 | 0 | str[i] = toupper(str[i]); |
375 | 0 | else |
376 | 0 | str[i] = tolower(str[i]); |
377 | 0 |
|
378 | 0 | return str; |
379 | 0 | } |
380 | | |
381 | | /* gmp: mpz_set_str */ |
382 | 0 | int GMPZAPI(set_str)(mp_int rop, char *str, int base) { |
383 | 0 | mp_result res = mp_int_read_string(rop, base, str); |
384 | 0 | return ((res == MP_OK) ? 0 : -1); |
385 | 0 | } |
386 | | |
387 | | /* gmp: mpq_set_str */ |
388 | 0 | int GMPQAPI(set_str)(mp_rat rop, char *s, int base) { |
389 | 0 | char *slash; |
390 | 0 | char *str; |
391 | 0 | mp_result resN; |
392 | 0 | mp_result resD; |
393 | 0 | int res = 0; |
394 | 0 |
|
395 | 0 | /* Copy string to temporary storage so we can modify it below */ |
396 | 0 | str = malloc(strlen(s)+1); |
397 | 0 | strcpy(str, s); |
398 | 0 |
|
399 | 0 | /* Properly format the string as an int by terminating at the / */ |
400 | 0 | slash = strchr(str, '/'); |
401 | 0 | if (slash) |
402 | 0 | *slash = '\0'; |
403 | 0 |
|
404 | 0 | /* Parse numerator */ |
405 | 0 | resN = mp_int_read_string(mp_rat_numer_ref(rop), base, str); |
406 | 0 |
|
407 | 0 | /* Parse denomenator if given or set to 1 if not */ |
408 | 0 | if (slash) |
409 | 0 | resD = mp_int_read_string(mp_rat_denom_ref(rop), base, slash+1); |
410 | 0 | else |
411 | 0 | resD = mp_int_set_uvalue(mp_rat_denom_ref(rop), 1); |
412 | 0 |
|
413 | 0 | /* Return failure if either parse failed */ |
414 | 0 | if (resN != MP_OK || resD != MP_OK) |
415 | 0 | res = -1; |
416 | 0 |
|
417 | 0 | free(str); |
418 | 0 | return res; |
419 | 0 | } |
420 | | |
421 | 0 | static unsigned long get_long_bits(mp_int op) { |
422 | 0 | /* Deal with integer that does not fit into unsigned long. We want to grab |
423 | 0 | * the least significant digits that will fit into the long. Read the digits |
424 | 0 | * into the long starting at the most significant digit that fits into a |
425 | 0 | * long. The long is shifted over by MP_DIGIT_BIT before each digit is added. |
426 | 0 | * The shift is decomposed into two steps to follow the patten used in the |
427 | 0 | * rest of the imath library. The two step shift is used to accomedate |
428 | 0 | * architectures that don't deal well with 32-bit shifts. */ |
429 | 0 | mp_size num_digits_in_long = sizeof(unsigned long) / sizeof(mp_digit); |
430 | 0 | mp_digit *digits = MP_DIGITS(op); |
431 | 0 | unsigned long out = 0; |
432 | 0 | int i; |
433 | 0 |
|
434 | 0 | for (i = num_digits_in_long - 1; i >= 0; i--) { |
435 | 0 | out <<= (MP_DIGIT_BIT/2); |
436 | 0 | out <<= (MP_DIGIT_BIT/2); |
437 | 0 | out |= digits[i]; |
438 | 0 | } |
439 | 0 |
|
440 | 0 | return out; |
441 | 0 | } |
442 | | |
443 | | /* gmp: mpz_get_ui */ |
444 | 0 | unsigned long GMPZAPI(get_ui)(mp_int op) { |
445 | 0 | unsigned long out; |
446 | 0 |
|
447 | 0 | /* Try a standard conversion that fits into an unsigned long */ |
448 | 0 | mp_result res = mp_int_to_uint(op, &out); |
449 | 0 | if (res == MP_OK) |
450 | 0 | return out; |
451 | 0 | |
452 | 0 | /* Abort the try if we don't have a range error in the conversion. |
453 | 0 | * The range error indicates that the value cannot fit into a long. */ |
454 | 0 | CHECK(res == MP_RANGE ? MP_OK : MP_RANGE); |
455 | 0 | if (res != MP_RANGE) |
456 | 0 | return 0; |
457 | 0 | |
458 | 0 | return get_long_bits(op); |
459 | 0 | } |
460 | | |
461 | | /* gmp: mpz_get_si */ |
462 | 0 | long GMPZAPI(get_si)(mp_int op) { |
463 | 0 | long out; |
464 | 0 | unsigned long uout; |
465 | 0 | int long_msb; |
466 | 0 |
|
467 | 0 | /* Try a standard conversion that fits into a long */ |
468 | 0 | mp_result res = mp_int_to_int(op, &out); |
469 | 0 | if (res == MP_OK) |
470 | 0 | return out; |
471 | 0 | |
472 | 0 | /* Abort the try if we don't have a range error in the conversion. |
473 | 0 | * The range error indicates that the value cannot fit into a long. */ |
474 | 0 | CHECK(res == MP_RANGE ? MP_OK : MP_RANGE); |
475 | 0 | if (res != MP_RANGE) |
476 | 0 | return 0; |
477 | 0 | |
478 | 0 | /* get least significant bits into an unsigned long */ |
479 | 0 | uout = get_long_bits(op); |
480 | 0 |
|
481 | 0 | /* clear the top bit */ |
482 | 0 | long_msb = (sizeof(unsigned long) * 8) - 1; |
483 | 0 | uout &= (~(1UL << long_msb)); |
484 | 0 |
|
485 | 0 | /* convert to negative if needed based on sign of op */ |
486 | 0 | if (MP_SIGN(op) == MP_NEG) |
487 | 0 | uout = 0 - uout; |
488 | 0 |
|
489 | 0 | out = (long) uout; |
490 | 0 | return out; |
491 | 0 | } |
492 | | |
493 | | /* gmp: mpz_lcm */ |
494 | 287k | void GMPZAPI(lcm)(mp_int rop, mp_int op1, mp_int op2) { |
495 | 287k | int op1_is_zero = mp_int_compare_zero(op1) == 0; |
496 | 287k | int op2_is_zero = mp_int_compare_zero(op2) == 0; |
497 | 287k | |
498 | 287k | if (op1_is_zero || op2_is_zero) { |
499 | 0 | mp_int_zero(rop); |
500 | 0 | return; |
501 | 0 | } |
502 | 287k | |
503 | 287k | CHECK(mp_int_lcm(op1, op2, rop)); |
504 | 287k | CHECK(mp_int_abs(rop, rop)); |
505 | 287k | } |
506 | | |
507 | | /* gmp: mpz_mul_2exp */ |
508 | | /* gmp: allow big values for op2 when op1 == 0 */ |
509 | 0 | void GMPZAPI(mul_2exp)(mp_int rop, mp_int op1, unsigned long op2) { |
510 | 0 | if (mp_int_compare_zero(op1) == 0) |
511 | 0 | mp_int_zero(rop); |
512 | 0 | else |
513 | 0 | CHECK(mp_int_mul_pow2(op1, op2, rop)); |
514 | 0 | } |
515 | | |
516 | | /************************************************************************* |
517 | | * |
518 | | * Functions needing expanded functionality |
519 | | * |
520 | | *************************************************************************/ |
521 | | /* [Note]Overview of division implementation |
522 | | |
523 | | All division operations (N / D) compute q and r such that |
524 | | |
525 | | N = q * D + r, with 0 <= abs(r) < abs(d) |
526 | | |
527 | | The q and r values are not uniquely specified by N and D. To specify which q |
528 | | and r values should be used, GMP implements three different rounding modes |
529 | | for integer division: |
530 | | |
531 | | ceiling - round q twords +infinity, r has opposite sign as d |
532 | | floor - round q twords -infinity, r has same sign as d |
533 | | truncate - round q twords zero, r has same sign as n |
534 | | |
535 | | The imath library only supports truncate as a rounding mode. We need to |
536 | | implement the other rounding modes in terms of truncating division. We first |
537 | | perform the division in trucate mode and then adjust q accordingly. Once we |
538 | | know q, we can easily compute the correct r according the the formula above |
539 | | by computing: |
540 | | |
541 | | r = N - q * D |
542 | | |
543 | | The main task is to compute q. We can compute the correct q from a trucated |
544 | | version as follows. |
545 | | |
546 | | For ceiling rounding mode, if q is less than 0 then the truncated rounding |
547 | | mode is the same as the ceiling rounding mode. If q is greater than zero |
548 | | then we need to round q up by one because the truncated version was rounded |
549 | | down to zero. If q equals zero then check to see if the result of the |
550 | | divison is positive. A positive result needs to increment q to one. |
551 | | |
552 | | For floor rounding mode, if q is greater than 0 then the trucated rounding |
553 | | mode is the same as the floor rounding mode. If q is less than zero then we |
554 | | need to round q down by one because the trucated mode rounded q up by one |
555 | | twords zero. If q is zero then we need to check to see if the result of the |
556 | | division is negative. A negative result needs to decrement q to negative |
557 | | one. |
558 | | */ |
559 | | |
560 | | /* gmp: mpz_cdiv_q */ |
561 | 134k | void GMPZAPI(cdiv_q)(mp_int q, mp_int n, mp_int d) { |
562 | 134k | mpz_t rz; |
563 | 134k | mp_int r = &rz; |
564 | 134k | int qsign, rsign, nsign, dsign; |
565 | 134k | CHECK(mp_int_init(r)); |
566 | 134k | |
567 | 134k | /* save signs before division because q can alias with n or d */ |
568 | 134k | nsign = mp_int_compare_zero(n); |
569 | 134k | dsign = mp_int_compare_zero(d); |
570 | 134k | |
571 | 134k | /* truncating division */ |
572 | 134k | CHECK(mp_int_div(n, d, q, r)); |
573 | 134k | |
574 | 134k | /* see: [Note]Overview of division implementation */ |
575 | 134k | qsign = mp_int_compare_zero(q); |
576 | 134k | rsign = mp_int_compare_zero(r); |
577 | 134k | if (qsign > 0) { /* q > 0 */ |
578 | 7.78k | if (rsign != 0) { /* r != 0 */ |
579 | 4.02k | CHECK(mp_int_add_value(q, 1, q)); |
580 | 4.02k | } |
581 | 7.78k | } |
582 | 126k | else if (qsign == 0) { /* q == 0 */ |
583 | 96.0k | if (rsign != 0) { /* r != 0 */ |
584 | 13.2k | if ((nsign > 0 && dsign > 08.20k ) || (5.00k nsign < 05.00k && dsign < 05.00k )) { |
585 | 8.20k | CHECK(mp_int_set_value(q, 1)); |
586 | 8.20k | } |
587 | 13.2k | } |
588 | 96.0k | } |
589 | 134k | mp_int_clear(r); |
590 | 134k | } |
591 | | |
592 | | /* gmp: mpz_fdiv_q */ |
593 | 301k | void GMPZAPI(fdiv_q)(mp_int q, mp_int n, mp_int d) { |
594 | 301k | mpz_t rz; |
595 | 301k | mp_int r = &rz; |
596 | 301k | int qsign, rsign, nsign, dsign; |
597 | 301k | CHECK(mp_int_init(r)); |
598 | 301k | |
599 | 301k | /* save signs before division because q can alias with n or d */ |
600 | 301k | nsign = mp_int_compare_zero(n); |
601 | 301k | dsign = mp_int_compare_zero(d); |
602 | 301k | |
603 | 301k | /* truncating division */ |
604 | 301k | CHECK(mp_int_div(n, d, q, r)); |
605 | 301k | |
606 | 301k | /* see: [Note]Overview of division implementation */ |
607 | 301k | qsign = mp_int_compare_zero(q); |
608 | 301k | rsign = mp_int_compare_zero(r); |
609 | 301k | if (qsign < 0) { /* q < 0 */ |
610 | 50.4k | if (rsign != 0) { /* r != 0 */ |
611 | 15.0k | CHECK(mp_int_sub_value(q, 1, q)); |
612 | 15.0k | } |
613 | 50.4k | } |
614 | 251k | else if (qsign == 0) { /* q == 0 */ |
615 | 120k | if (rsign != 0) { /* r != 0 */ |
616 | 29.0k | if ((nsign < 0 && dsign > 09.07k ) || (19.9k nsign > 019.9k && dsign < 019.9k )) { |
617 | 9.07k | CHECK(mp_int_set_value(q, -1)); |
618 | 9.07k | } |
619 | 29.0k | } |
620 | 120k | } |
621 | 301k | mp_int_clear(r); |
622 | 301k | } |
623 | | |
624 | | /* gmp: mpz_fdiv_r */ |
625 | 7.19k | void GMPZAPI(fdiv_r)(mp_int r, mp_int n, mp_int d) { |
626 | 7.19k | mpz_t qz; |
627 | 7.19k | mpz_t tempz; |
628 | 7.19k | mpz_t orig_dz; |
629 | 7.19k | mpz_t orig_nz; |
630 | 7.19k | mp_int q = &qz; |
631 | 7.19k | mp_int temp = &tempz; |
632 | 7.19k | mp_int orig_d = &orig_dz; |
633 | 7.19k | mp_int orig_n = &orig_nz; |
634 | 7.19k | CHECK(mp_int_init(q)); |
635 | 7.19k | CHECK(mp_int_init(temp)); |
636 | 7.19k | /* Make a copy of n in case n and d in case they overlap with q */ |
637 | 7.19k | CHECK(mp_int_init_copy(orig_d, d)); |
638 | 7.19k | CHECK(mp_int_init_copy(orig_n, n)); |
639 | 7.19k | |
640 | 7.19k | /* floor division */ |
641 | 7.19k | GMPZAPI(fdiv_q)(q, n, d); |
642 | 7.19k | |
643 | 7.19k | /* see: [Note]Overview of division implementation */ |
644 | 7.19k | /* n = q * d + r ==> r = n - q * d */ |
645 | 7.19k | mp_int_mul(q, orig_d, temp); |
646 | 7.19k | mp_int_sub(orig_n, temp, r); |
647 | 7.19k | |
648 | 7.19k | mp_int_clear(q); |
649 | 7.19k | mp_int_clear(temp); |
650 | 7.19k | mp_int_clear(orig_d); |
651 | 7.19k | mp_int_clear(orig_n); |
652 | 7.19k | } |
653 | | |
654 | | /* gmp: mpz_tdiv_q */ |
655 | 0 | void GMPZAPI(tdiv_q)(mp_int q, mp_int n, mp_int d) { |
656 | 0 | /* truncating division*/ |
657 | 0 | CHECK(mp_int_div(n, d, q, NULL)); |
658 | 0 | } |
659 | | |
660 | | /* gmp: mpz_fdiv_q_ui */ |
661 | 0 | unsigned long GMPZAPI(fdiv_q_ui)(mp_int q, mp_int n, unsigned long d) { |
662 | 0 | mpz_t tempz; |
663 | 0 | mp_int temp = &tempz; |
664 | 0 | mpz_t rz; |
665 | 0 | mp_int r = &rz; |
666 | 0 | mpz_t orig_nz; |
667 | 0 | mp_int orig_n = &orig_nz; |
668 | 0 | unsigned long rl; |
669 | 0 | CHECK(mp_int_init_uvalue(temp, d)); |
670 | 0 | CHECK(mp_int_init(r)); |
671 | 0 | /* Make a copy of n in case n and q overlap */ |
672 | 0 | CHECK(mp_int_init_copy(orig_n, n)); |
673 | 0 |
|
674 | 0 | /* use floor division mode to compute q and r */ |
675 | 0 | GMPZAPI(fdiv_q)(q, n, temp); |
676 | 0 | GMPZAPI(fdiv_r)(r, orig_n, temp); |
677 | 0 | CHECK(mp_int_to_uint(r, &rl)); |
678 | 0 |
|
679 | 0 | mp_int_clear(temp); |
680 | 0 | mp_int_clear(r); |
681 | 0 | mp_int_clear(orig_n); |
682 | 0 |
|
683 | 0 | return rl; |
684 | 0 | } |
685 | | |
686 | | /* gmp: mpz_export */ |
687 | 3.89k | void* GMPZAPI(export)(void *rop, size_t *countp, int order, size_t size, int endian, size_t nails, mp_int op) { |
688 | 3.89k | int i, j; |
689 | 3.89k | int num_used_bytes; |
690 | 3.89k | size_t num_words, num_missing_bytes; |
691 | 3.89k | ssize_t word_offset; |
692 | 3.89k | unsigned char* dst; |
693 | 3.89k | mp_digit* src; |
694 | 3.89k | int src_bits; |
695 | 3.89k | |
696 | 3.89k | /* We do not have a complete implementation. Assert to ensure our |
697 | 3.89k | * restrictions are in place. */ |
698 | 3.89k | assert(nails == 0 && "Do not support non-full words"); |
699 | 3.89k | assert(endian == 1 || endian == 0 || endian == -1); |
700 | 3.89k | assert(order == 1 || order == -1); |
701 | 3.89k | |
702 | 3.89k | /* Test for zero */ |
703 | 3.89k | if (mp_int_compare_zero(op) == 0) { |
704 | 1.16k | if (countp) |
705 | 0 | *countp = 0; |
706 | 1.16k | return rop; |
707 | 1.16k | } |
708 | 2.73k | |
709 | 2.73k | /* Calculate how many words we need */ |
710 | 2.73k | num_used_bytes = mp_int_unsigned_len(op); |
711 | 2.73k | num_words = (num_used_bytes + (size-1)) / size; /* ceil division */ |
712 | 2.73k | assert(num_used_bytes > 0); |
713 | 2.73k | |
714 | 2.73k | /* Check to see if we will have missing bytes in the last word. |
715 | 2.73k | |
716 | 2.73k | Missing bytes can only occur when the size of words we output is |
717 | 2.73k | greater than the size of words used internally by imath. The number of |
718 | 2.73k | missing bytes is the number of bytes needed to fill out the last word. If |
719 | 2.73k | this number is greater than the size of a single mp_digit, then we need to |
720 | 2.73k | pad the word with extra zeros. Otherwise, the missing bytes can be filled |
721 | 2.73k | directly from the zeros in the last digit in the number. |
722 | 2.73k | */ |
723 | 2.73k | num_missing_bytes = (size * num_words) - num_used_bytes; |
724 | 2.73k | assert(num_missing_bytes < size); |
725 | 2.73k | |
726 | 2.73k | /* Allocate space for the result if needed */ |
727 | 2.73k | if (rop == NULL) { |
728 | 0 | rop = malloc(num_words * size); |
729 | 0 | } |
730 | 2.73k | |
731 | 2.73k | if (endian == 0) { |
732 | 2.73k | endian = HOST_ENDIAN; |
733 | 2.73k | } |
734 | 2.73k | |
735 | 2.73k | /* Initialize dst and src pointers */ |
736 | 2.73k | dst = (unsigned char *) rop + (order >= 0 ? (num_words-1) * size0 : 0) + (endian >= 0 ? size-10 : 0); |
737 | 2.73k | src = MP_DIGITS(op); |
738 | 2.73k | src_bits = MP_DIGIT_BIT; |
739 | 2.73k | |
740 | 2.73k | word_offset = (endian >= 0 ? size0 : -size) + (order < 0 ? size : -size0 ); |
741 | 2.73k | |
742 | 5.49k | for (i = 0; i < num_words; i++2.76k ) { |
743 | 6.76k | for (j = 0; j < size && i * size + j < num_used_bytes6.65k ; j++4.00k ) { |
744 | 4.00k | if (src_bits == 0) { |
745 | 143 | ++src; |
746 | 143 | src_bits = MP_DIGIT_BIT; |
747 | 143 | } |
748 | 4.00k | *dst = (*src >> (MP_DIGIT_BIT - src_bits)) & 0xFF; |
749 | 4.00k | src_bits -= 8; |
750 | 4.00k | dst -= endian; |
751 | 4.00k | } |
752 | 20.8k | for (; j < size; j++18.1k ) { |
753 | 18.1k | *dst = 0; |
754 | 18.1k | dst -= endian; |
755 | 18.1k | } |
756 | 2.76k | dst += word_offset; |
757 | 2.76k | } |
758 | 2.73k | |
759 | 2.73k | if (countp) |
760 | 0 | *countp = num_words; |
761 | 2.73k | return rop; |
762 | 2.73k | } |
763 | | |
764 | | /* gmp: mpz_import */ |
765 | 20.4k | void GMPZAPI(import)(mp_int rop, size_t count, int order, size_t size, int endian, size_t nails, const void* op) { |
766 | 20.4k | mpz_t tmpz; |
767 | 20.4k | mp_int tmp = &tmpz; |
768 | 20.4k | size_t total_size; |
769 | 20.4k | size_t num_digits; |
770 | 20.4k | ssize_t word_offset; |
771 | 20.4k | const unsigned char *src; |
772 | 20.4k | mp_digit *dst; |
773 | 20.4k | int dst_bits; |
774 | 20.4k | int i, j; |
775 | 20.4k | if (count == 0 || op == NULL) |
776 | 20.4k | return0 ; |
777 | 20.4k | |
778 | 20.4k | /* We do not have a complete implementation. Assert to ensure our |
779 | 20.4k | * restrictions are in place. */ |
780 | 20.4k | assert(nails == 0 && "Do not support non-full words"); |
781 | 20.4k | assert(endian == 1 || endian == 0 || endian == -1); |
782 | 20.4k | assert(order == 1 || order == -1); |
783 | 20.4k | |
784 | 20.4k | if (endian == 0) { |
785 | 20.4k | endian = HOST_ENDIAN; |
786 | 20.4k | } |
787 | 20.4k | |
788 | 20.4k | /* Compute number of needed digits by ceil division */ |
789 | 20.4k | total_size = count * size; |
790 | 20.4k | num_digits = (total_size + sizeof(mp_digit) - 1) / sizeof(mp_digit); |
791 | 20.4k | |
792 | 20.4k | /* Init temporary */ |
793 | 20.4k | mp_int_init_size(tmp, num_digits); |
794 | 87.6k | for (i = 0; i < num_digits; i++67.1k ) |
795 | 67.1k | tmp->digits[i] = 0; |
796 | 20.4k | |
797 | 20.4k | /* Copy bytes */ |
798 | 20.4k | src = (const unsigned char *) op + (order >= 0 ? (count-1) * size0 : 0) + (endian >= 0 ? size-10 : 0); |
799 | 20.4k | dst = MP_DIGITS(tmp); |
800 | 20.4k | dst_bits = 0; |
801 | 20.4k | |
802 | 20.4k | word_offset = (endian >= 0 ? size0 : -size) + (order < 0 ? size : -size0 ); |
803 | 20.4k | |
804 | 54.0k | for (i = 0; i < count; i++33.5k ) { |
805 | 302k | for (j = 0; j < size; j++268k ) { |
806 | 268k | if (dst_bits == MP_DIGIT_BIT) { |
807 | 46.7k | ++dst; |
808 | 46.7k | dst_bits = 0; |
809 | 46.7k | } |
810 | 268k | *dst |= ((mp_digit)*src) << dst_bits; |
811 | 268k | dst_bits += 8; |
812 | 268k | src -= endian; |
813 | 268k | } |
814 | 33.5k | src += word_offset; |
815 | 33.5k | } |
816 | 20.4k | |
817 | 20.4k | MP_USED(tmp) = num_digits; |
818 | 20.4k | |
819 | 20.4k | /* Remove leading zeros from number */ |
820 | 20.4k | { |
821 | 20.4k | mp_size uz_ = MP_USED(tmp); |
822 | 20.4k | mp_digit *dz_ = MP_DIGITS(tmp) + uz_ -1; |
823 | 66.0k | while (uz_ > 1 && (*dz_-- == 0)46.5k ) |
824 | 45.5k | --uz_; |
825 | 20.4k | MP_USED(tmp) = uz_; |
826 | 20.4k | } |
827 | 20.4k | |
828 | 20.4k | /* Copy to destination */ |
829 | 20.4k | mp_int_copy(tmp, rop); |
830 | 20.4k | mp_int_clear(tmp); |
831 | 20.4k | } |
832 | | |
833 | | /* gmp: mpz_sizeinbase */ |
834 | 110 | size_t GMPZAPI(sizeinbase)(mp_int op, int base) { |
835 | 110 | mp_result res; |
836 | 110 | size_t size; |
837 | 110 | |
838 | 110 | /* If op == 0, return 1 */ |
839 | 110 | if (mp_int_compare_zero(op) == 0) |
840 | 0 | return 1; |
841 | 110 | |
842 | 110 | /* Compute string length in base */ |
843 | 110 | res = mp_int_string_len(op, base); |
844 | 110 | CHECK((res > 0) == MP_OK); |
845 | 110 | |
846 | 110 | /* Now adjust the final size by getting rid of string artifacts */ |
847 | 110 | size = res; |
848 | 110 | |
849 | 110 | /* subtract one for the null terminator */ |
850 | 110 | size -= 1; |
851 | 110 | |
852 | 110 | /* subtract one for the negative sign */ |
853 | 110 | if (mp_int_compare_zero(op) < 0) |
854 | 29 | size -= 1; |
855 | 110 | |
856 | 110 | return size; |
857 | 110 | } |