1 /* -----------------------------------------------------------------------------
3 * (c) The GHC Team, 1998-2012
5 * Out-of-line primitive operations
7 * This file contains the implementations of all the primitive
8 * operations ("primops") which are not expanded inline. See
9 * ghc/compiler/prelude/primops.txt.pp for a list of all the primops;
10 * this file contains code for most of those with the attribute
13 * Entry convention: the entry convention for a primop is that all the
14 * args are in Stg registers (R1, R2, etc.). This is to make writing
15 * the primops easier. (see compiler/codeGen/CgCallConv.hs).
17 * Return convention: results from a primop are generally returned
18 * using the ordinary unboxed tuple return convention. The C-- parser
19 * implements the RET_xxxx() macros to perform unboxed-tuple returns
20 * based on the prevailing return convention.
22 * This file is written in a subset of C--, extended with various
23 * features specific to GHC. It is compiled by GHC directly. For the
24 * syntax of .cmm files, see the parser in ghc/compiler/cmm/CmmParse.y.
26 * ---------------------------------------------------------------------------*/
29 #include "GmpDerivedConstants.h"
31 import "integer-gmp" __gmpz_init;
32 import "integer-gmp" __gmpz_add;
33 import "integer-gmp" __gmpz_sub;
34 import "integer-gmp" __gmpz_mul;
35 import "integer-gmp" __gmpz_mul_2exp;
36 import "integer-gmp" __gmpz_mul_si;
37 import "integer-gmp" __gmpz_tstbit;
38 import "integer-gmp" __gmpz_fdiv_q_2exp;
39 import "integer-gmp" __gmpz_gcd;
40 import "integer-gmp" __gmpz_gcdext;
41 import "integer-gmp" __gmpn_gcd_1;
42 import "integer-gmp" __gmpn_cmp;
43 import "integer-gmp" __gmpz_tdiv_q;
44 import "integer-gmp" __gmpz_tdiv_r;
45 import "integer-gmp" __gmpz_fdiv_q;
46 import "integer-gmp" __gmpz_fdiv_r;
47 import "integer-gmp" __gmpz_tdiv_qr;
48 import "integer-gmp" __gmpz_fdiv_qr;
49 import "integer-gmp" __gmpz_divexact;
50 import "integer-gmp" __gmpz_and;
51 import "integer-gmp" __gmpz_xor;
52 import "integer-gmp" __gmpz_ior;
53 import "integer-gmp" __gmpz_com;
54 import "integer-gmp" __gmpz_pow_ui;
55 import "integer-gmp" __gmpz_powm;
56 import "integer-gmp" __gmpz_powm_sec;
57 import "integer-gmp" __gmpz_invert;
58 import "integer-gmp" __gmpz_nextprime;
59 import "integer-gmp" __gmpz_probab_prime_p;
60 import "integer-gmp" __gmpz_sizeinbase;
61 import "integer-gmp" __gmpz_import;
62 import "integer-gmp" __gmpz_export;
64 import "integer-gmp" integer_cbits_decodeDouble;
66 /* -----------------------------------------------------------------------------
67 Arbitrary-precision Integer operations.
69 There are some assumptions in this code that mp_limb_t == W_. This is
70 the case for all the platforms that GHC supports, currently.
71 -------------------------------------------------------------------------- */
73 /* set mpz_t from Int#/ByteArray# */
74 #define MP_INT_SET_FROM_BA(mp_ptr,i,ba) \
75 MP_INT__mp_alloc(mp_ptr) = W_TO_INT(BYTE_ARR_WDS(ba)); \
76 MP_INT__mp_size(mp_ptr) = W_TO_INT(i); \
77 MP_INT__mp_d(mp_ptr) = BYTE_ARR_CTS(ba)
79 /* convert mpz_t to Int#/ByteArray# return pair */
80 #define MP_INT_AS_PAIR(mp_ptr) \
81 TO_W_(MP_INT__mp_size(mp_ptr)),(MP_INT__mp_d(mp_ptr)-SIZEOF_StgArrWords)
84 /* :: ByteArray# -> Word# -> Word# -> Int# -> (# Int#, ByteArray# #) */
85 integer_cmm_importIntegerFromByteArrayzh (P_ ba, W_ of, W_ sz, W_ e)
91 STK_CHK_GEN_N (SIZEOF_MP_INT);
94 mp_result = Sp - SIZEOF_MP_INT;
96 src_ptr = BYTE_ARR_CTS(ba) + of;
98 ccall __gmpz_init(mp_result "ptr");
99 ccall __gmpz_import(mp_result "ptr", sz, W_TO_INT(e), W_TO_INT(1), W_TO_INT(0), 0, src_ptr "ptr");
101 return(MP_INT_AS_PAIR(mp_result));
104 /* :: Addr# -> Word# -> Int# -> State# s -> (# State# s, Int#, ByteArray# #) */
105 integer_cmm_importIntegerFromAddrzh (W_ src_ptr, W_ sz, W_ e)
110 STK_CHK_GEN_N (SIZEOF_MP_INT);
113 mp_result = Sp - SIZEOF_MP_INT;
115 ccall __gmpz_init(mp_result "ptr");
116 ccall __gmpz_import(mp_result "ptr", sz, W_TO_INT(e), W_TO_INT(1), W_TO_INT(0), 0, src_ptr "ptr");
118 return(MP_INT_AS_PAIR(mp_result));
121 /* :: Int# -> ByteArray# -> MutableByteArray# s -> Word# -> Int# -> State# s -> (# State# s, Word# #) */
122 integer_cmm_exportIntegerToMutableByteArrayzh (W_ ws1, P_ d1, P_ mba, W_ of, W_ e)
129 STK_CHK_GEN_N (SIZEOF_MP_INT + SIZEOF_W);
132 mp_tmp = Sp - SIZEOF_MP_INT;
133 MP_INT_SET_FROM_BA(mp_tmp, ws1, d1);
135 cnt_result = Sp - (SIZEOF_MP_INT + SIZEOF_W);
138 dst_ptr = BYTE_ARR_CTS(mba) + of;
140 ccall __gmpz_export(dst_ptr "ptr", cnt_result "ptr", W_TO_INT(e), W_TO_INT(1), W_TO_INT(0), 0, mp_tmp "ptr");
142 return (W_[cnt_result]);
145 /* :: Int# -> ByteArray# -> Addr# -> Int# -> State# s -> (# State# s, Word# #) */
146 integer_cmm_exportIntegerToAddrzh (W_ ws1, P_ d1, W_ dst_ptr, W_ e)
152 STK_CHK_GEN_N (SIZEOF_MP_INT + SIZEOF_W);
155 mp_tmp = Sp - SIZEOF_MP_INT;
156 MP_INT_SET_FROM_BA(mp_tmp, ws1, d1);
158 cnt_result = Sp - (SIZEOF_MP_INT + SIZEOF_W);
161 ccall __gmpz_export(dst_ptr "ptr", cnt_result "ptr", W_TO_INT(e), W_TO_INT(1), W_TO_INT(0), 0, mp_tmp "ptr");
163 return (W_[cnt_result]);
166 integer_cmm_int2Integerzh (W_ val)
168 W_ s, p; /* to avoid aliasing */
170 ALLOC_PRIM_N (SIZEOF_StgArrWords + WDS(1), integer_cmm_int2Integerzh, val);
172 p = Hp - SIZEOF_StgArrWords;
173 SET_HDR(p, stg_ARR_WORDS_info, CCCS);
174 StgArrWords_bytes(p) = SIZEOF_W;
176 /* mpz_set_si is inlined here, makes things simpler */
189 /* returns (# size :: Int#,
196 integer_cmm_word2Integerzh (W_ val)
198 W_ s, p; /* to avoid aliasing */
200 ALLOC_PRIM_N (SIZEOF_StgArrWords + WDS(1), integer_cmm_word2Integerzh, val);
202 p = Hp - SIZEOF_StgArrWords;
203 SET_HDR(p, stg_ARR_WORDS_info, CCCS);
204 StgArrWords_bytes(p) = SIZEOF_W;
213 /* returns (# size :: Int#,
214 data :: ByteArray# #)
221 * 'long long' primops for converting to/from Integers.
224 #if WORD_SIZE_IN_BITS < 64
226 integer_cmm_int64ToIntegerzh (L_ val)
228 W_ hi, lo, s, neg, words_needed, p;
232 hi = TO_W_(val >> 32);
235 if ( hi == 0 || (hi == 0xFFFFFFFF && lo != 0) ) {
236 // minimum is one word
242 ALLOC_PRIM (SIZEOF_StgArrWords + WDS(words_needed));
244 p = Hp - SIZEOF_StgArrWords - WDS(words_needed) + WDS(1);
245 SET_HDR(p, stg_ARR_WORDS_info, CCCS);
246 StgArrWords_bytes(p) = WDS(words_needed);
258 if ( words_needed == 2 ) {
266 } else /* val==0 */ {
274 /* returns (# size :: Int#,
275 data :: ByteArray# #)
279 integer_cmm_word64ToIntegerzh (L_ val)
281 W_ hi, lo, s, words_needed, p;
283 hi = TO_W_(val >> 32);
292 ALLOC_PRIM (SIZEOF_StgArrWords + WDS(words_needed));
294 p = Hp - SIZEOF_StgArrWords - WDS(words_needed) + WDS(1);
295 SET_HDR(p, stg_ARR_WORDS_info, CCCS);
296 StgArrWords_bytes(p) = WDS(words_needed);
306 } else /* val==0 */ {
311 /* returns (# size :: Int#,
312 data :: ByteArray# #)
317 #endif /* WORD_SIZE_IN_BITS < 64 */
319 #define GMP_TAKE2_RET1(name,mp_fun) \
320 name (W_ ws1, P_ d1, W_ ws2, P_ d2) \
327 STK_CHK_GEN_N (3 * SIZEOF_MP_INT); \
330 mp_tmp1 = Sp - 1 * SIZEOF_MP_INT; \
331 mp_tmp2 = Sp - 2 * SIZEOF_MP_INT; \
332 mp_result1 = Sp - 3 * SIZEOF_MP_INT; \
334 MP_INT_SET_FROM_BA(mp_tmp1,ws1,d1); \
335 MP_INT_SET_FROM_BA(mp_tmp2,ws2,d2); \
337 ccall __gmpz_init(mp_result1 "ptr"); \
339 /* Perform the operation */ \
340 ccall mp_fun(mp_result1 "ptr",mp_tmp1 "ptr",mp_tmp2 "ptr"); \
342 return (MP_INT_AS_PAIR(mp_result1)); \
345 #define GMP_TAKE3_RET1(name,mp_fun) \
346 name (W_ ws1, P_ d1, W_ ws2, P_ d2, W_ ws3, P_ d3) \
354 STK_CHK_GEN_N (4 * SIZEOF_MP_INT); \
357 mp_tmp1 = Sp - 1 * SIZEOF_MP_INT; \
358 mp_tmp2 = Sp - 2 * SIZEOF_MP_INT; \
359 mp_tmp3 = Sp - 3 * SIZEOF_MP_INT; \
360 mp_result1 = Sp - 4 * SIZEOF_MP_INT; \
362 MP_INT_SET_FROM_BA(mp_tmp1,ws1,d1); \
363 MP_INT_SET_FROM_BA(mp_tmp2,ws2,d2); \
364 MP_INT_SET_FROM_BA(mp_tmp3,ws3,d3); \
366 ccall __gmpz_init(mp_result1 "ptr"); \
368 /* Perform the operation */ \
369 ccall mp_fun(mp_result1 "ptr",mp_tmp1 "ptr",mp_tmp2 "ptr", \
372 return (MP_INT_AS_PAIR(mp_result1)); \
375 #define GMP_TAKE1_UL1_RET1(name,mp_fun) \
376 name (W_ ws1, P_ d1, W_ wul) \
381 /* call doYouWantToGC() */ \
383 STK_CHK_GEN_N (2 * SIZEOF_MP_INT); \
386 mp_tmp = Sp - 1 * SIZEOF_MP_INT; \
387 mp_result = Sp - 2 * SIZEOF_MP_INT; \
389 MP_INT_SET_FROM_BA(mp_tmp,ws1,d1); \
391 ccall __gmpz_init(mp_result "ptr"); \
393 /* Perform the operation */ \
394 ccall mp_fun(mp_result "ptr", mp_tmp "ptr", W_TO_LONG(wul)); \
396 return (MP_INT_AS_PAIR(mp_result)); \
399 #define GMP_TAKE1_I1_RETI1(name,mp_fun) \
400 name (W_ ws1, P_ d1, W_ wi) \
406 STK_CHK_GEN_N (SIZEOF_MP_INT); \
409 mp_tmp = Sp - 1 * SIZEOF_MP_INT; \
410 MP_INT_SET_FROM_BA(mp_tmp,ws1,d1); \
412 /* Perform the operation */ \
413 (res) = ccall mp_fun(mp_tmp "ptr", W_TO_INT(wi)); \
415 return (TO_W_(res)); \
418 #define GMP_TAKE1_UL1_RETI1(name,mp_fun) \
419 name (W_ ws1, P_ d1, W_ wul) \
425 STK_CHK_GEN_N (SIZEOF_MP_INT); \
428 mp_tmp = Sp - 1 * SIZEOF_MP_INT; \
429 MP_INT_SET_FROM_BA(mp_tmp,ws1,d1); \
431 /* Perform the operation */ \
432 (res) = ccall mp_fun(mp_tmp "ptr", W_TO_LONG(wul)); \
434 return (TO_W_(res)); \
437 #define GMP_TAKE1_RET1(name,mp_fun) \
438 name (W_ ws1, P_ d1) \
444 STK_CHK_GEN_N (2 * SIZEOF_MP_INT); \
447 mp_tmp1 = Sp - 1 * SIZEOF_MP_INT; \
448 mp_result1 = Sp - 2 * SIZEOF_MP_INT; \
450 MP_INT_SET_FROM_BA(mp_tmp1,ws1,d1); \
452 ccall __gmpz_init(mp_result1 "ptr"); \
454 /* Perform the operation */ \
455 ccall mp_fun(mp_result1 "ptr",mp_tmp1 "ptr"); \
457 return(MP_INT_AS_PAIR(mp_result1)); \
460 #define GMP_TAKE2_RET2(name,mp_fun) \
461 name (W_ ws1, P_ d1, W_ ws2, P_ d2) \
469 STK_CHK_GEN_N (4 * SIZEOF_MP_INT); \
472 mp_tmp1 = Sp - 1 * SIZEOF_MP_INT; \
473 mp_tmp2 = Sp - 2 * SIZEOF_MP_INT; \
474 mp_result1 = Sp - 3 * SIZEOF_MP_INT; \
475 mp_result2 = Sp - 4 * SIZEOF_MP_INT; \
477 MP_INT_SET_FROM_BA(mp_tmp1,ws1,d1); \
478 MP_INT_SET_FROM_BA(mp_tmp2,ws2,d2); \
480 ccall __gmpz_init(mp_result1 "ptr"); \
481 ccall __gmpz_init(mp_result2 "ptr"); \
483 /* Perform the operation */ \
484 ccall mp_fun(mp_result1 "ptr",mp_result2 "ptr",mp_tmp1 "ptr",mp_tmp2 "ptr"); \
486 return (MP_INT_AS_PAIR(mp_result1),MP_INT_AS_PAIR(mp_result2)); \
489 GMP_TAKE2_RET1(integer_cmm_plusIntegerzh, __gmpz_add)
490 GMP_TAKE2_RET1(integer_cmm_minusIntegerzh, __gmpz_sub)
491 GMP_TAKE2_RET1(integer_cmm_timesIntegerzh, __gmpz_mul)
492 GMP_TAKE1_UL1_RET1(integer_cmm_timesIntegerIntzh, __gmpz_mul_si)
493 GMP_TAKE2_RET1(integer_cmm_gcdIntegerzh, __gmpz_gcd)
494 #define CMM_GMPZ_GCDEXT(g,s,a,b) __gmpz_gcdext(g,s,NULL,a,b)
495 GMP_TAKE2_RET2(integer_cmm_gcdExtIntegerzh, CMM_GMPZ_GCDEXT)
496 GMP_TAKE2_RET1(integer_cmm_quotIntegerzh, __gmpz_tdiv_q)
497 GMP_TAKE2_RET1(integer_cmm_remIntegerzh, __gmpz_tdiv_r)
498 GMP_TAKE2_RET1(integer_cmm_divIntegerzh, __gmpz_fdiv_q)
499 GMP_TAKE2_RET1(integer_cmm_modIntegerzh, __gmpz_fdiv_r)
500 GMP_TAKE2_RET1(integer_cmm_divExactIntegerzh, __gmpz_divexact)
501 GMP_TAKE2_RET1(integer_cmm_andIntegerzh, __gmpz_and)
502 GMP_TAKE2_RET1(integer_cmm_orIntegerzh, __gmpz_ior)
503 GMP_TAKE2_RET1(integer_cmm_xorIntegerzh, __gmpz_xor)
504 GMP_TAKE1_UL1_RETI1(integer_cmm_testBitIntegerzh, __gmpz_tstbit)
505 GMP_TAKE1_UL1_RET1(integer_cmm_mul2ExpIntegerzh, __gmpz_mul_2exp)
506 GMP_TAKE1_UL1_RET1(integer_cmm_fdivQ2ExpIntegerzh, __gmpz_fdiv_q_2exp)
507 GMP_TAKE1_RET1(integer_cmm_complementIntegerzh, __gmpz_com)
509 GMP_TAKE2_RET2(integer_cmm_quotRemIntegerzh, __gmpz_tdiv_qr)
510 GMP_TAKE2_RET2(integer_cmm_divModIntegerzh, __gmpz_fdiv_qr)
512 GMP_TAKE3_RET1(integer_cmm_powModIntegerzh, __gmpz_powm)
513 GMP_TAKE3_RET1(integer_cmm_powModSecIntegerzh, __gmpz_powm_sec)
514 GMP_TAKE2_RET1(integer_cmm_recipModIntegerzh, __gmpz_invert)
515 GMP_TAKE1_UL1_RET1(integer_cmm_powIntegerzh, __gmpz_pow_ui)
517 GMP_TAKE1_RET1(integer_cmm_nextPrimeIntegerzh, __gmpz_nextprime)
518 GMP_TAKE1_I1_RETI1(integer_cmm_testPrimeIntegerzh, __gmpz_probab_prime_p)
520 GMP_TAKE1_I1_RETI1(integer_cmm_sizeInBasezh, __gmpz_sizeinbase)
522 integer_cmm_gcdIntzh (W_ int1, W_ int2)
527 STK_CHK_GEN_N (1 * SIZEOF_W);
529 mp_tmp_w = Sp - 1 * SIZEOF_W;
532 (r) = ccall __gmpn_gcd_1(mp_tmp_w "ptr", 1, int2);
538 integer_cmm_gcdIntegerIntzh (W_ s1, P_ d1, W_ int)
541 (r) = ccall __gmpn_gcd_1 (BYTE_ARR_CTS(d1) "ptr", s1, int);
546 integer_cmm_cmpIntegerIntzh (W_ usize, P_ d1, W_ v_digit)
552 // paraphrased from __gmpz_cmp_si() in the GMP sources
553 if (%gt(v_digit,0)) {
556 if (%lt(v_digit,0)) {
562 if (usize != vsize) {
563 return (usize - vsize);
570 u_digit = W_[BYTE_ARR_CTS(d1)];
572 if (u_digit == v_digit) {
576 if (%gtu(u_digit,v_digit)) { // NB. unsigned: these are mp_limb_t's
583 integer_cmm_cmpIntegerzh (W_ usize, P_ d1, W_ vsize, P_ d2)
588 // paraphrased from __gmpz_cmp() in the GMP sources
590 if (usize != vsize) {
591 return (usize - vsize);
598 if (%lt(usize,0)) { // NB. not <, which is unsigned
604 up = BYTE_ARR_CTS(d1);
605 vp = BYTE_ARR_CTS(d2);
607 (cmp) = ccall __gmpn_cmp(up "ptr", vp "ptr", size);
609 if (cmp == 0 :: CInt) {
613 if (%lt(cmp,0 :: CInt) == %lt(usize,0)) {
620 #define DOUBLE_MANTISSA_SIZE SIZEOF_DOUBLE
621 #define ARR_SIZE (SIZEOF_StgArrWords + DOUBLE_MANTISSA_SIZE)
623 integer_cmm_decodeDoublezh (D_ arg)
630 STK_CHK_GEN_N (2 * SIZEOF_MP_INT);
631 ALLOC_PRIM (ARR_SIZE);
633 mp_tmp1 = Sp - 1 * SIZEOF_MP_INT;
634 mp_tmp_w = Sp - 2 * SIZEOF_MP_INT;
636 /* Be prepared to tell Lennart-coded integer_cbits_decodeDouble
637 where mantissa.d can be put (it does not care about the rest) */
638 p = Hp - ARR_SIZE + WDS(1);
639 SET_HDR(p, stg_ARR_WORDS_info, CCCS);
640 StgArrWords_bytes(p) = DOUBLE_MANTISSA_SIZE;
641 MP_INT__mp_d(mp_tmp1) = BYTE_ARR_CTS(p);
643 /* Perform the operation */
644 ccall integer_cbits_decodeDouble(mp_tmp1 "ptr", mp_tmp_w "ptr",arg);
646 /* returns: (Int# (expn), Int#, ByteArray#) */
647 return (W_[mp_tmp_w], TO_W_(MP_INT__mp_size(mp_tmp1)), p);