1
/* -----------------------------------------------------------------------------
3
* (c) The GHC Team, 1998-2004
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_fdiv_q_2exp;
37
import "integer-gmp" __gmpz_gcd;
38
import "integer-gmp" __gmpn_gcd_1;
39
import "integer-gmp" __gmpn_cmp;
40
import "integer-gmp" __gmpz_tdiv_q;
41
import "integer-gmp" __gmpz_tdiv_r;
42
import "integer-gmp" __gmpz_tdiv_qr;
43
import "integer-gmp" __gmpz_fdiv_qr;
44
import "integer-gmp" __gmpz_divexact;
45
import "integer-gmp" __gmpz_and;
46
import "integer-gmp" __gmpz_xor;
47
import "integer-gmp" __gmpz_ior;
48
import "integer-gmp" __gmpz_com;
50
import "integer-gmp" integer_cbits_decodeDouble;
52
/* -----------------------------------------------------------------------------
53
Arbitrary-precision Integer operations.
55
There are some assumptions in this code that mp_limb_t == W_. This is
56
the case for all the platforms that GHC supports, currently.
57
-------------------------------------------------------------------------- */
59
integer_cmm_int2Integerzh
61
/* arguments: R1 = Int# */
63
W_ val, s, p; /* to avoid aliasing */
66
ALLOC_PRIM( SIZEOF_StgArrWords + WDS(1), NO_PTRS, integer_cmm_int2Integerzh );
68
p = Hp - SIZEOF_StgArrWords;
69
SET_HDR(p, stg_ARR_WORDS_info, W_[CCCS]);
70
StgArrWords_bytes(p) = SIZEOF_W;
72
/* mpz_set_si is inlined here, makes things simpler */
85
/* returns (# size :: Int#,
92
integer_cmm_word2Integerzh
94
/* arguments: R1 = Word# */
96
W_ val, s, p; /* to avoid aliasing */
100
ALLOC_PRIM( SIZEOF_StgArrWords + WDS(1), NO_PTRS, integer_cmm_word2Integerzh);
102
p = Hp - SIZEOF_StgArrWords;
103
SET_HDR(p, stg_ARR_WORDS_info, W_[CCCS]);
104
StgArrWords_bytes(p) = SIZEOF_W;
113
/* returns (# size :: Int#,
114
data :: ByteArray# #)
121
* 'long long' primops for converting to/from Integers.
124
#if WORD_SIZE_IN_BITS < 64
126
integer_cmm_int64ToIntegerzh
128
/* arguments: L1 = Int64# */
131
W_ hi, lo, s, neg, words_needed, p;
136
hi = TO_W_(val >> 32);
139
if ( hi == 0 || (hi == 0xFFFFFFFF && lo != 0) ) {
140
// minimum is one word
146
ALLOC_PRIM( SIZEOF_StgArrWords + WDS(words_needed),
147
NO_PTRS, integer_cmm_int64ToIntegerzh );
149
p = Hp - SIZEOF_StgArrWords - WDS(words_needed) + WDS(1);
150
SET_HDR(p, stg_ARR_WORDS_info, W_[CCCS]);
151
StgArrWords_bytes(p) = WDS(words_needed);
163
if ( words_needed == 2 ) {
171
} else /* val==0 */ {
179
/* returns (# size :: Int#,
180
data :: ByteArray# #)
184
integer_cmm_word64ToIntegerzh
186
/* arguments: L1 = Word64# */
189
W_ hi, lo, s, words_needed, p;
192
hi = TO_W_(val >> 32);
201
ALLOC_PRIM( SIZEOF_StgArrWords + WDS(words_needed),
202
NO_PTRS, integer_cmm_word64ToIntegerzh );
204
p = Hp - SIZEOF_StgArrWords - WDS(words_needed) + WDS(1);
205
SET_HDR(p, stg_ARR_WORDS_info, W_[CCCS]);
206
StgArrWords_bytes(p) = WDS(words_needed);
216
} else /* val==0 */ {
221
/* returns (# size :: Int#,
222
data :: ByteArray# #)
227
#endif /* WORD_SIZE_IN_BITS < 64 */
229
#define GMP_TAKE2_RET1(name,mp_fun) \
238
/* call doYouWantToGC() */ \
239
MAYBE_GC(R2_PTR & R4_PTR, name); \
241
STK_CHK_GEN( 3 * SIZEOF_MP_INT, R2_PTR & R4_PTR, name ); \
248
mp_tmp1 = Sp - 1 * SIZEOF_MP_INT; \
249
mp_tmp2 = Sp - 2 * SIZEOF_MP_INT; \
250
mp_result1 = Sp - 3 * SIZEOF_MP_INT; \
251
MP_INT__mp_alloc(mp_tmp1) = W_TO_INT(BYTE_ARR_WDS(d1)); \
252
MP_INT__mp_size(mp_tmp1) = (s1); \
253
MP_INT__mp_d(mp_tmp1) = BYTE_ARR_CTS(d1); \
254
MP_INT__mp_alloc(mp_tmp2) = W_TO_INT(BYTE_ARR_WDS(d2)); \
255
MP_INT__mp_size(mp_tmp2) = (s2); \
256
MP_INT__mp_d(mp_tmp2) = BYTE_ARR_CTS(d2); \
258
foreign "C" __gmpz_init(mp_result1 "ptr") []; \
260
/* Perform the operation */ \
261
foreign "C" mp_fun(mp_result1 "ptr",mp_tmp1 "ptr",mp_tmp2 "ptr") []; \
263
RET_NP(TO_W_(MP_INT__mp_size(mp_result1)), \
264
MP_INT__mp_d(mp_result1) - SIZEOF_StgArrWords); \
267
#define GMP_TAKE1_UL1_RET1(name,mp_fun) \
276
/* call doYouWantToGC() */ \
277
MAYBE_GC(R2_PTR, name); \
279
STK_CHK_GEN( 2 * SIZEOF_MP_INT, R2_PTR, name ); \
285
mp_tmp = Sp - 1 * SIZEOF_MP_INT; \
286
mp_result = Sp - 2 * SIZEOF_MP_INT; \
287
MP_INT__mp_alloc(mp_tmp) = W_TO_INT(BYTE_ARR_WDS(d1)); \
288
MP_INT__mp_size(mp_tmp) = (s1); \
289
MP_INT__mp_d(mp_tmp) = BYTE_ARR_CTS(d1); \
291
foreign "C" __gmpz_init(mp_result "ptr") []; \
293
/* Perform the operation */ \
294
foreign "C" mp_fun(mp_result "ptr",mp_tmp "ptr", ul) []; \
296
RET_NP(TO_W_(MP_INT__mp_size(mp_result)), \
297
MP_INT__mp_d(mp_result) - SIZEOF_StgArrWords); \
300
#define GMP_TAKE1_RET1(name,mp_fun) \
308
/* call doYouWantToGC() */ \
309
MAYBE_GC(R2_PTR, name); \
311
STK_CHK_GEN( 2 * SIZEOF_MP_INT, R2_PTR, name ); \
316
mp_tmp1 = Sp - 1 * SIZEOF_MP_INT; \
317
mp_result1 = Sp - 2 * SIZEOF_MP_INT; \
318
MP_INT__mp_alloc(mp_tmp1) = W_TO_INT(BYTE_ARR_WDS(d1)); \
319
MP_INT__mp_size(mp_tmp1) = (s1); \
320
MP_INT__mp_d(mp_tmp1) = BYTE_ARR_CTS(d1); \
322
foreign "C" __gmpz_init(mp_result1 "ptr") []; \
324
/* Perform the operation */ \
325
foreign "C" mp_fun(mp_result1 "ptr",mp_tmp1 "ptr") []; \
327
RET_NP(TO_W_(MP_INT__mp_size(mp_result1)), \
328
MP_INT__mp_d(mp_result1) - SIZEOF_StgArrWords); \
331
#define GMP_TAKE2_RET2(name,mp_fun) \
341
/* call doYouWantToGC() */ \
342
MAYBE_GC(R2_PTR & R4_PTR, name); \
344
STK_CHK_GEN( 4 * SIZEOF_MP_INT, R2_PTR & R4_PTR, name ); \
351
mp_tmp1 = Sp - 1 * SIZEOF_MP_INT; \
352
mp_tmp2 = Sp - 2 * SIZEOF_MP_INT; \
353
mp_result1 = Sp - 3 * SIZEOF_MP_INT; \
354
mp_result2 = Sp - 4 * SIZEOF_MP_INT; \
355
MP_INT__mp_alloc(mp_tmp1) = W_TO_INT(BYTE_ARR_WDS(d1)); \
356
MP_INT__mp_size(mp_tmp1) = (s1); \
357
MP_INT__mp_d(mp_tmp1) = BYTE_ARR_CTS(d1); \
358
MP_INT__mp_alloc(mp_tmp2) = W_TO_INT(BYTE_ARR_WDS(d2)); \
359
MP_INT__mp_size(mp_tmp2) = (s2); \
360
MP_INT__mp_d(mp_tmp2) = BYTE_ARR_CTS(d2); \
362
foreign "C" __gmpz_init(mp_result1 "ptr") []; \
363
foreign "C" __gmpz_init(mp_result2 "ptr") []; \
365
/* Perform the operation */ \
366
foreign "C" mp_fun(mp_result1 "ptr",mp_result2 "ptr",mp_tmp1 "ptr",mp_tmp2 "ptr") []; \
368
RET_NPNP(TO_W_(MP_INT__mp_size(mp_result1)), \
369
MP_INT__mp_d(mp_result1) - SIZEOF_StgArrWords, \
370
TO_W_(MP_INT__mp_size(mp_result2)), \
371
MP_INT__mp_d(mp_result2) - SIZEOF_StgArrWords); \
374
GMP_TAKE2_RET1(integer_cmm_plusIntegerzh, __gmpz_add)
375
GMP_TAKE2_RET1(integer_cmm_minusIntegerzh, __gmpz_sub)
376
GMP_TAKE2_RET1(integer_cmm_timesIntegerzh, __gmpz_mul)
377
GMP_TAKE2_RET1(integer_cmm_gcdIntegerzh, __gmpz_gcd)
378
GMP_TAKE2_RET1(integer_cmm_quotIntegerzh, __gmpz_tdiv_q)
379
GMP_TAKE2_RET1(integer_cmm_remIntegerzh, __gmpz_tdiv_r)
380
GMP_TAKE2_RET1(integer_cmm_divExactIntegerzh, __gmpz_divexact)
381
GMP_TAKE2_RET1(integer_cmm_andIntegerzh, __gmpz_and)
382
GMP_TAKE2_RET1(integer_cmm_orIntegerzh, __gmpz_ior)
383
GMP_TAKE2_RET1(integer_cmm_xorIntegerzh, __gmpz_xor)
384
GMP_TAKE1_UL1_RET1(integer_cmm_mul2ExpIntegerzh, __gmpz_mul_2exp)
385
GMP_TAKE1_UL1_RET1(integer_cmm_fdivQ2ExpIntegerzh, __gmpz_fdiv_q_2exp)
386
GMP_TAKE1_RET1(integer_cmm_complementIntegerzh, __gmpz_com)
388
GMP_TAKE2_RET2(integer_cmm_quotRemIntegerzh, __gmpz_tdiv_qr)
389
GMP_TAKE2_RET2(integer_cmm_divModIntegerzh, __gmpz_fdiv_qr)
393
/* R1 = the first Int#; R2 = the second Int# */
397
STK_CHK_GEN( 1 * SIZEOF_MP_INT, NO_PTRS, integer_cmm_gcdIntzh );
399
mp_tmp_w = Sp - 1 * SIZEOF_MP_INT;
402
(r) = foreign "C" __gmpn_gcd_1(mp_tmp_w "ptr", 1, R2) [];
405
/* Result parked in R1, return via info-pointer at TOS */
406
jump %ENTRY_CODE(Sp(0));
410
integer_cmm_gcdIntegerIntzh
412
/* R1 = s1; R2 = d1; R3 = the int */
414
(s1) = foreign "C" __gmpn_gcd_1( BYTE_ARR_CTS(R2) "ptr", R1, R3) [];
417
/* Result parked in R1, return via info-pointer at TOS */
418
jump %ENTRY_CODE(Sp(0));
422
integer_cmm_cmpIntegerIntzh
424
/* R1 = s1; R2 = d1; R3 = the int */
425
W_ usize, vsize, v_digit, u_digit;
431
// paraphrased from __gmpz_cmp_si() in the GMP sources
432
if (%gt(v_digit,0)) {
435
if (%lt(v_digit,0)) {
441
if (usize != vsize) {
443
jump %ENTRY_CODE(Sp(0));
448
jump %ENTRY_CODE(Sp(0));
451
u_digit = W_[BYTE_ARR_CTS(R2)];
453
if (u_digit == v_digit) {
455
jump %ENTRY_CODE(Sp(0));
458
if (%gtu(u_digit,v_digit)) { // NB. unsigned: these are mp_limb_t's
464
jump %ENTRY_CODE(Sp(0));
467
integer_cmm_cmpIntegerzh
469
/* R1 = s1; R2 = d1; R3 = s2; R4 = d2 */
470
W_ usize, vsize, size, up, vp;
473
// paraphrased from __gmpz_cmp() in the GMP sources
477
if (usize != vsize) {
479
jump %ENTRY_CODE(Sp(0));
484
jump %ENTRY_CODE(Sp(0));
487
if (%lt(usize,0)) { // NB. not <, which is unsigned
493
up = BYTE_ARR_CTS(R2);
494
vp = BYTE_ARR_CTS(R4);
496
(cmp) = foreign "C" __gmpn_cmp(up "ptr", vp "ptr", size) [];
498
if (cmp == 0 :: CInt) {
500
jump %ENTRY_CODE(Sp(0));
503
if (%lt(cmp,0 :: CInt) == %lt(usize,0)) {
508
/* Result parked in R1, return via info-pointer at TOS */
509
jump %ENTRY_CODE(Sp(0));
512
#define DOUBLE_MANTISSA_SIZE SIZEOF_DOUBLE
513
#define ARR_SIZE (SIZEOF_StgArrWords + DOUBLE_MANTISSA_SIZE)
515
integer_cmm_decodeDoublezh
522
STK_CHK_GEN( 2 * SIZEOF_MP_INT, NO_PTRS, integer_cmm_decodeDoublezh );
524
mp_tmp1 = Sp - 1 * SIZEOF_MP_INT;
525
mp_tmp_w = Sp - 2 * SIZEOF_MP_INT;
527
/* arguments: D1 = Double# */
530
ALLOC_PRIM( ARR_SIZE, NO_PTRS, integer_cmm_decodeDoublezh );
532
/* Be prepared to tell Lennart-coded integer_cbits_decodeDouble
533
where mantissa.d can be put (it does not care about the rest) */
534
p = Hp - ARR_SIZE + WDS(1);
535
SET_HDR(p, stg_ARR_WORDS_info, W_[CCCS]);
536
StgArrWords_bytes(p) = DOUBLE_MANTISSA_SIZE;
537
MP_INT__mp_d(mp_tmp1) = BYTE_ARR_CTS(p);
539
/* Perform the operation */
540
foreign "C" integer_cbits_decodeDouble(mp_tmp1 "ptr", mp_tmp_w "ptr",arg) [];
542
/* returns: (Int# (expn), Int#, ByteArray#) */
543
RET_NNP(W_[mp_tmp_w], TO_W_(MP_INT__mp_size(mp_tmp1)), p);