Add side-channel attack resilient `powModSecInteger`
[packages/integer-gmp.git] / cbits / gmp-wrappers.cmm
1 /* -----------------------------------------------------------------------------
2  *
3  * (c) The GHC Team, 1998-2012
4  *
5  * Out-of-line primitive operations
6  *
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
11  * out_of_line=True.
12  *
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).
16  *
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.
21  *
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.
25  *
26  * ---------------------------------------------------------------------------*/
27
28 #include "Cmm.h"
29 #include "GmpDerivedConstants.h"
30
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_tstbit;
37 import "integer-gmp" __gmpz_fdiv_q_2exp;
38 import "integer-gmp" __gmpz_gcd;
39 import "integer-gmp" __gmpz_gcdext;
40 import "integer-gmp" __gmpn_gcd_1;
41 import "integer-gmp" __gmpn_cmp;
42 import "integer-gmp" __gmpz_tdiv_q;
43 import "integer-gmp" __gmpz_tdiv_r;
44 import "integer-gmp" __gmpz_fdiv_q;
45 import "integer-gmp" __gmpz_fdiv_r;
46 import "integer-gmp" __gmpz_tdiv_qr;
47 import "integer-gmp" __gmpz_fdiv_qr;
48 import "integer-gmp" __gmpz_divexact;
49 import "integer-gmp" __gmpz_and;
50 import "integer-gmp" __gmpz_xor;
51 import "integer-gmp" __gmpz_ior;
52 import "integer-gmp" __gmpz_com;
53 import "integer-gmp" __gmpz_pow_ui;
54 import "integer-gmp" __gmpz_powm;
55 import "integer-gmp" __gmpz_powm_sec;
56 import "integer-gmp" __gmpz_invert;
57
58 import "integer-gmp" integer_cbits_decodeDouble;
59
60 /* -----------------------------------------------------------------------------
61    Arbitrary-precision Integer operations.
62
63    There are some assumptions in this code that mp_limb_t == W_.  This is
64    the case for all the platforms that GHC supports, currently.
65    -------------------------------------------------------------------------- */
66
67 integer_cmm_int2Integerzh (W_ val)
68 {
69    W_ s, p; /* to avoid aliasing */
70
71    ALLOC_PRIM_N (SIZEOF_StgArrWords + WDS(1), integer_cmm_int2Integerzh, val);
72
73    p = Hp - SIZEOF_StgArrWords;
74    SET_HDR(p, stg_ARR_WORDS_info, CCCS);
75    StgArrWords_bytes(p) = SIZEOF_W;
76
77    /* mpz_set_si is inlined here, makes things simpler */
78    if (%lt(val,0)) {
79         s  = -1;
80         Hp(0) = -val;
81    } else {
82      if (%gt(val,0)) {
83         s = 1;
84         Hp(0) = val;
85      } else {
86         s = 0;
87      }
88   }
89
90    /* returns (# size  :: Int#,
91                  data  :: ByteArray#
92                #)
93    */
94    return (s,p);
95 }
96
97 integer_cmm_word2Integerzh (W_ val)
98 {
99    W_ s, p; /* to avoid aliasing */
100
101    ALLOC_PRIM_N (SIZEOF_StgArrWords + WDS(1), integer_cmm_word2Integerzh, val);
102
103    p = Hp - SIZEOF_StgArrWords;
104    SET_HDR(p, stg_ARR_WORDS_info, CCCS);
105    StgArrWords_bytes(p) = SIZEOF_W;
106
107    if (val != 0) {
108         s = 1;
109         W_[Hp] = val;
110    } else {
111         s = 0;
112    }
113
114    /* returns (# size  :: Int#,
115                  data  :: ByteArray# #)
116    */
117    return (s,p);
118 }
119
120
121 /*
122  * 'long long' primops for converting to/from Integers.
123  */
124
125 #if WORD_SIZE_IN_BITS < 64
126
127 integer_cmm_int64ToIntegerzh (L_ val)
128 {
129    W_ hi, lo, s, neg, words_needed, p;
130
131    neg = 0;
132
133    hi = TO_W_(val >> 32);
134    lo = TO_W_(val);
135
136    if ( hi == 0 || (hi == 0xFFFFFFFF && lo != 0) )  {
137        // minimum is one word
138        words_needed = 1;
139    } else {
140        words_needed = 2;
141    }
142
143    ALLOC_PRIM (SIZEOF_StgArrWords + WDS(words_needed));
144
145    p = Hp - SIZEOF_StgArrWords - WDS(words_needed) + WDS(1);
146    SET_HDR(p, stg_ARR_WORDS_info, CCCS);
147    StgArrWords_bytes(p) = WDS(words_needed);
148
149    if ( %lt(hi,0) ) {
150      neg = 1;
151      lo = -lo;
152      if(lo == 0) {
153        hi = -hi;
154      } else {
155        hi = -hi - 1;
156      }
157    }
158
159    if ( words_needed == 2 )  {
160       s = 2;
161       Hp(-1) = lo;
162       Hp(0) = hi;
163    } else {
164        if ( lo != 0 ) {
165            s = 1;
166            Hp(0) = lo;
167        } else /* val==0 */  {
168            s = 0;
169        }
170    }
171    if ( neg != 0 ) {
172         s = -s;
173    }
174
175    /* returns (# size  :: Int#,
176                  data  :: ByteArray# #)
177    */
178    return (s,p);
179 }
180 integer_cmm_word64ToIntegerzh (L_ val)
181 {
182    W_ hi, lo, s, words_needed, p;
183
184    hi = TO_W_(val >> 32);
185    lo = TO_W_(val);
186
187    if ( hi != 0 ) {
188       words_needed = 2;
189    } else {
190       words_needed = 1;
191    }
192
193    ALLOC_PRIM (SIZEOF_StgArrWords + WDS(words_needed));
194
195    p = Hp - SIZEOF_StgArrWords - WDS(words_needed) + WDS(1);
196    SET_HDR(p, stg_ARR_WORDS_info, CCCS);
197    StgArrWords_bytes(p) = WDS(words_needed);
198
199    if ( hi != 0 ) {
200      s = 2;
201      Hp(-1) = lo;
202      Hp(0)  = hi;
203    } else {
204       if ( lo != 0 ) {
205         s = 1;
206         Hp(0) = lo;
207      } else /* val==0 */  {
208       s = 0;
209      }
210   }
211
212    /* returns (# size  :: Int#,
213                  data  :: ByteArray# #)
214    */
215    return (s,p);
216 }
217
218 #endif /* WORD_SIZE_IN_BITS < 64 */
219
220 #define GMP_TAKE2_RET1(name,mp_fun)                             \
221 name (W_ ws1, P_ d1, W_ ws2, P_ d2)                             \
222 {                                                               \
223   CInt s1, s2;                                                  \
224   W_ mp_tmp1;                                                   \
225   W_ mp_tmp2;                                                   \
226   W_ mp_result1;                                                \
227                                                                 \
228 again:                                                          \
229   STK_CHK_GEN_N (3 * SIZEOF_MP_INT);                            \
230   MAYBE_GC(again);                                              \
231                                                                 \
232   s1 = W_TO_INT(ws1);                                           \
233   s2 = W_TO_INT(ws2);                                           \
234                                                                 \
235   mp_tmp1    = Sp - 1 * SIZEOF_MP_INT;                          \
236   mp_tmp2    = Sp - 2 * SIZEOF_MP_INT;                          \
237   mp_result1 = Sp - 3 * SIZEOF_MP_INT;                          \
238   MP_INT__mp_alloc(mp_tmp1) = W_TO_INT(BYTE_ARR_WDS(d1));       \
239   MP_INT__mp_size(mp_tmp1)  = (s1);                             \
240   MP_INT__mp_d(mp_tmp1)     = BYTE_ARR_CTS(d1);                 \
241   MP_INT__mp_alloc(mp_tmp2) = W_TO_INT(BYTE_ARR_WDS(d2));       \
242   MP_INT__mp_size(mp_tmp2)  = (s2);                             \
243   MP_INT__mp_d(mp_tmp2)     = BYTE_ARR_CTS(d2);                 \
244                                                                 \
245   ccall __gmpz_init(mp_result1 "ptr");                          \
246                                                                 \
247   /* Perform the operation */                                   \
248   ccall mp_fun(mp_result1 "ptr",mp_tmp1  "ptr",mp_tmp2  "ptr"); \
249                                                                 \
250   return (TO_W_(MP_INT__mp_size(mp_result1)),                   \
251          MP_INT__mp_d(mp_result1) - SIZEOF_StgArrWords);        \
252 }
253
254 #define GMP_TAKE3_RET1(name,mp_fun)                             \
255 name (W_ ws1, P_ d1, W_ ws2, P_ d2, W_ ws3, P_ d3)              \
256 {                                                               \
257   CInt s1, s2, s3;                                              \
258   W_ mp_tmp1;                                                   \
259   W_ mp_tmp2;                                                   \
260   W_ mp_tmp3;                                                   \
261   W_ mp_result1;                                                \
262                                                                 \
263 again:                                                          \
264   STK_CHK_GEN_N (4 * SIZEOF_MP_INT);                            \
265   MAYBE_GC(again);                                              \
266                                                                 \
267   s1 = W_TO_INT(ws1);                                           \
268   s2 = W_TO_INT(ws2);                                           \
269   s3 = W_TO_INT(ws3);                                           \
270                                                                 \
271   mp_tmp1    = Sp - 1 * SIZEOF_MP_INT;                          \
272   mp_tmp2    = Sp - 2 * SIZEOF_MP_INT;                          \
273   mp_tmp3    = Sp - 3 * SIZEOF_MP_INT;                          \
274   mp_result1 = Sp - 4 * SIZEOF_MP_INT;                          \
275   MP_INT__mp_alloc(mp_tmp1) = W_TO_INT(BYTE_ARR_WDS(d1));       \
276   MP_INT__mp_size(mp_tmp1)  = (s1);                             \
277   MP_INT__mp_d(mp_tmp1)     = BYTE_ARR_CTS(d1);                 \
278   MP_INT__mp_alloc(mp_tmp2) = W_TO_INT(BYTE_ARR_WDS(d2));       \
279   MP_INT__mp_size(mp_tmp2)  = (s2);                             \
280   MP_INT__mp_d(mp_tmp2)     = BYTE_ARR_CTS(d2);                 \
281   MP_INT__mp_alloc(mp_tmp3) = W_TO_INT(BYTE_ARR_WDS(d3));       \
282   MP_INT__mp_size(mp_tmp3)  = (s3);                             \
283   MP_INT__mp_d(mp_tmp3)     = BYTE_ARR_CTS(d3);                 \
284                                                                 \
285   ccall __gmpz_init(mp_result1 "ptr");                          \
286                                                                 \
287   /* Perform the operation */                                   \
288   ccall mp_fun(mp_result1 "ptr",mp_tmp1  "ptr",mp_tmp2  "ptr",  \
289                mp_tmp3  "ptr");                                 \
290                                                                 \
291   return (TO_W_(MP_INT__mp_size(mp_result1)),                   \
292          MP_INT__mp_d(mp_result1) - SIZEOF_StgArrWords);        \
293 }
294
295 #define GMP_TAKE1_UL1_RET1(name,mp_fun)                         \
296 name (W_ ws1, P_ d1, W_ wul)                                    \
297 {                                                               \
298   CInt s1;                                                      \
299   CLong ul;                                                     \
300   W_ mp_tmp;                                                    \
301   W_ mp_result;                                                 \
302                                                                 \
303   /* call doYouWantToGC() */                                    \
304 again:                                                          \
305   STK_CHK_GEN_N (2 * SIZEOF_MP_INT);                            \
306   MAYBE_GC(again);                                              \
307                                                                 \
308   s1 = W_TO_INT(ws1);                                           \
309   ul = W_TO_LONG(wul);                                          \
310                                                                 \
311   mp_tmp     = Sp - 1 * SIZEOF_MP_INT;                          \
312   mp_result  = Sp - 2 * SIZEOF_MP_INT;                          \
313   MP_INT__mp_alloc(mp_tmp) = W_TO_INT(BYTE_ARR_WDS(d1));        \
314   MP_INT__mp_size(mp_tmp)  = (s1);                              \
315   MP_INT__mp_d(mp_tmp)     = BYTE_ARR_CTS(d1);                  \
316                                                                 \
317   ccall __gmpz_init(mp_result "ptr");                           \
318                                                                 \
319   /* Perform the operation */                                   \
320   ccall mp_fun(mp_result "ptr",mp_tmp "ptr", ul);               \
321                                                                 \
322   return(TO_W_(MP_INT__mp_size(mp_result)),                     \
323          MP_INT__mp_d(mp_result) - SIZEOF_StgArrWords);         \
324 }
325
326 #define GMP_TAKE1_UL1_RETI1(name,mp_fun)                        \
327 name (W_ ws1, P_ d1, W_ wul)                                     \
328 {                                                               \
329   CInt s1, res;                                                 \
330   CLong ul;                                                     \
331   W_ mp_tmp;                                                    \
332                                                                 \
333 again:                                                          \
334   STK_CHK_GEN_N (SIZEOF_MP_INT);                                \
335   MAYBE_GC(again);                                              \
336                                                                 \
337   s1 = W_TO_INT(ws1);                                           \
338   ul = W_TO_LONG(wul);                                          \
339                                                                 \
340   mp_tmp     = Sp - 1 * SIZEOF_MP_INT;                          \
341   MP_INT__mp_alloc(mp_tmp) = W_TO_INT(BYTE_ARR_WDS(d1));        \
342   MP_INT__mp_size(mp_tmp)  = (s1);                              \
343   MP_INT__mp_d(mp_tmp)     = BYTE_ARR_CTS(d1);                  \
344                                                                 \
345   /* Perform the operation */                                   \
346   (res) = ccall mp_fun(mp_tmp "ptr", ul);                       \
347                                                                 \
348   return (TO_W_(res));                                          \
349 }
350
351 #define GMP_TAKE1_RET1(name,mp_fun)                             \
352 name (W_ ws1, P_ d1)                                            \
353 {                                                               \
354   CInt s1;                                                      \
355   W_ mp_tmp1;                                                   \
356   W_ mp_result1;                                                \
357                                                                 \
358 again:                                                          \
359   STK_CHK_GEN_N (2 * SIZEOF_MP_INT);                            \
360   MAYBE_GC(again);                                              \
361                                                                 \
362   s1 = W_TO_INT(ws1);                                           \
363                                                                 \
364   mp_tmp1    = Sp - 1 * SIZEOF_MP_INT;                          \
365   mp_result1 = Sp - 2 * SIZEOF_MP_INT;                          \
366   MP_INT__mp_alloc(mp_tmp1)     = W_TO_INT(BYTE_ARR_WDS(d1));   \
367   MP_INT__mp_size(mp_tmp1)      = (s1);                         \
368   MP_INT__mp_d(mp_tmp1)         = BYTE_ARR_CTS(d1);             \
369                                                                 \
370   ccall __gmpz_init(mp_result1 "ptr");                          \
371                                                                 \
372   /* Perform the operation */                                   \
373   ccall mp_fun(mp_result1 "ptr",mp_tmp1 "ptr");                 \
374                                                                 \
375   return(TO_W_(MP_INT__mp_size(mp_result1)),                    \
376          MP_INT__mp_d(mp_result1) - SIZEOF_StgArrWords);        \
377 }
378
379 #define GMP_TAKE2_RET2(name,mp_fun)                                     \
380 name (W_ ws1, P_ d1, W_ ws2, P_ d2)                                     \
381 {                                                                       \
382   CInt s1, s2;                                                          \
383   W_ mp_tmp1;                                                           \
384   W_ mp_tmp2;                                                           \
385   W_ mp_result1;                                                        \
386   W_ mp_result2;                                                        \
387                                                                         \
388 again:                                                                  \
389   STK_CHK_GEN_N (4 * SIZEOF_MP_INT);                                    \
390   MAYBE_GC(again);                                                      \
391                                                                         \
392   s1 = W_TO_INT(ws1);                                                   \
393   s2 = W_TO_INT(ws2);                                                   \
394                                                                         \
395   mp_tmp1    = Sp - 1 * SIZEOF_MP_INT;                                  \
396   mp_tmp2    = Sp - 2 * SIZEOF_MP_INT;                                  \
397   mp_result1 = Sp - 3 * SIZEOF_MP_INT;                                  \
398   mp_result2 = Sp - 4 * SIZEOF_MP_INT;                                  \
399   MP_INT__mp_alloc(mp_tmp1)     = W_TO_INT(BYTE_ARR_WDS(d1));           \
400   MP_INT__mp_size(mp_tmp1)      = (s1);                                 \
401   MP_INT__mp_d(mp_tmp1)         = BYTE_ARR_CTS(d1);                     \
402   MP_INT__mp_alloc(mp_tmp2)     = W_TO_INT(BYTE_ARR_WDS(d2));           \
403   MP_INT__mp_size(mp_tmp2)      = (s2);                                 \
404   MP_INT__mp_d(mp_tmp2)         = BYTE_ARR_CTS(d2);                     \
405                                                                         \
406   ccall __gmpz_init(mp_result1 "ptr");                                  \
407   ccall __gmpz_init(mp_result2 "ptr");                                  \
408                                                                         \
409   /* Perform the operation */                                           \
410   ccall mp_fun(mp_result1 "ptr",mp_result2 "ptr",mp_tmp1 "ptr",mp_tmp2 "ptr"); \
411                                                                         \
412   return (TO_W_(MP_INT__mp_size(mp_result1)),                           \
413            MP_INT__mp_d(mp_result1) - SIZEOF_StgArrWords,               \
414            TO_W_(MP_INT__mp_size(mp_result2)),                          \
415            MP_INT__mp_d(mp_result2) - SIZEOF_StgArrWords);              \
416 }
417
418 GMP_TAKE2_RET1(integer_cmm_plusIntegerzh,           __gmpz_add)
419 GMP_TAKE2_RET1(integer_cmm_minusIntegerzh,          __gmpz_sub)
420 GMP_TAKE2_RET1(integer_cmm_timesIntegerzh,          __gmpz_mul)
421 GMP_TAKE2_RET1(integer_cmm_gcdIntegerzh,            __gmpz_gcd)
422 #define CMM_GMPZ_GCDEXT(g,s,a,b) __gmpz_gcdext(g,s,NULL,a,b)
423 GMP_TAKE2_RET2(integer_cmm_gcdExtIntegerzh,         CMM_GMPZ_GCDEXT)
424 GMP_TAKE2_RET1(integer_cmm_quotIntegerzh,           __gmpz_tdiv_q)
425 GMP_TAKE2_RET1(integer_cmm_remIntegerzh,            __gmpz_tdiv_r)
426 GMP_TAKE2_RET1(integer_cmm_divIntegerzh,            __gmpz_fdiv_q)
427 GMP_TAKE2_RET1(integer_cmm_modIntegerzh,            __gmpz_fdiv_r)
428 GMP_TAKE2_RET1(integer_cmm_divExactIntegerzh,       __gmpz_divexact)
429 GMP_TAKE2_RET1(integer_cmm_andIntegerzh,            __gmpz_and)
430 GMP_TAKE2_RET1(integer_cmm_orIntegerzh,             __gmpz_ior)
431 GMP_TAKE2_RET1(integer_cmm_xorIntegerzh,            __gmpz_xor)
432 GMP_TAKE1_UL1_RETI1(integer_cmm_testBitIntegerzh,   __gmpz_tstbit)
433 GMP_TAKE1_UL1_RET1(integer_cmm_mul2ExpIntegerzh,    __gmpz_mul_2exp)
434 GMP_TAKE1_UL1_RET1(integer_cmm_fdivQ2ExpIntegerzh,  __gmpz_fdiv_q_2exp)
435 GMP_TAKE1_RET1(integer_cmm_complementIntegerzh,     __gmpz_com)
436
437 GMP_TAKE2_RET2(integer_cmm_quotRemIntegerzh,        __gmpz_tdiv_qr)
438 GMP_TAKE2_RET2(integer_cmm_divModIntegerzh,         __gmpz_fdiv_qr)
439
440 GMP_TAKE3_RET1(integer_cmm_powModIntegerzh,         __gmpz_powm)
441 GMP_TAKE3_RET1(integer_cmm_powModSecIntegerzh,      __gmpz_powm_sec)
442 GMP_TAKE2_RET1(integer_cmm_recipModIntegerzh,       __gmpz_invert)
443 GMP_TAKE1_UL1_RET1(integer_cmm_powIntegerzh,        __gmpz_pow_ui)
444
445 integer_cmm_gcdIntzh (W_ int1, W_ int2)
446 {
447     W_ r;
448     W_ mp_tmp_w;
449
450     STK_CHK_GEN_N (1 * SIZEOF_W);
451
452     mp_tmp_w = Sp - 1 * SIZEOF_W;
453
454     W_[mp_tmp_w] = int1;
455     (r) = ccall __gmpn_gcd_1(mp_tmp_w "ptr", 1, int2);
456
457     return (r);
458 }
459
460
461 integer_cmm_gcdIntegerIntzh (W_ s1, P_ d1, W_ int)
462 {
463     W_ r;
464     (r) = ccall __gmpn_gcd_1 (BYTE_ARR_CTS(d1) "ptr", s1, int);
465     return (r);
466 }
467
468
469 integer_cmm_cmpIntegerIntzh (W_ usize, P_ d1, W_ v_digit)
470 {
471     W_ vsize, u_digit;
472
473     vsize = 0;
474
475     // paraphrased from __gmpz_cmp_si() in the GMP sources
476     if (%gt(v_digit,0)) {
477         vsize = 1;
478     } else {
479         if (%lt(v_digit,0)) {
480             vsize = -1;
481             v_digit = -v_digit;
482         }
483     }
484
485     if (usize != vsize) {
486         return (usize - vsize);
487     }
488
489     if (usize == 0) {
490         return (0);
491     }
492
493     u_digit = W_[BYTE_ARR_CTS(d1)];
494
495     if (u_digit == v_digit) {
496         return (0);
497     }
498
499     if (%gtu(u_digit,v_digit)) { // NB. unsigned: these are mp_limb_t's
500         return (usize);
501     } else {
502         return (-usize);
503     }
504 }
505
506 integer_cmm_cmpIntegerzh (W_ usize, P_ d1, W_ vsize, P_ d2)
507 {
508     W_ size, up, vp;
509     CInt cmp;
510
511     // paraphrased from __gmpz_cmp() in the GMP sources
512
513     if (usize != vsize) {
514         return (usize - vsize);
515     }
516
517     if (usize == 0) {
518         return (0);
519     }
520
521     if (%lt(usize,0)) { // NB. not <, which is unsigned
522         size = -usize;
523     } else {
524         size = usize;
525     }
526
527     up = BYTE_ARR_CTS(d1);
528     vp = BYTE_ARR_CTS(d2);
529
530     (cmp) = ccall __gmpn_cmp(up "ptr", vp "ptr", size);
531
532     if (cmp == 0 :: CInt) {
533         return (0);
534     }
535
536     if (%lt(cmp,0 :: CInt) == %lt(usize,0)) {
537         return (1);
538     } else {
539         return (-1);
540     }
541 }
542
543 #define DOUBLE_MANTISSA_SIZE SIZEOF_DOUBLE
544 #define ARR_SIZE (SIZEOF_StgArrWords + DOUBLE_MANTISSA_SIZE)
545
546 integer_cmm_decodeDoublezh (D_ arg)
547 {
548     D_ arg;
549     W_ p;
550     W_ mp_tmp1;
551     W_ mp_tmp_w;
552
553     STK_CHK_GEN_N (2 * SIZEOF_MP_INT);
554     ALLOC_PRIM (ARR_SIZE);
555
556     mp_tmp1  = Sp - 1 * SIZEOF_MP_INT;
557     mp_tmp_w = Sp - 2 * SIZEOF_MP_INT;
558
559     /* Be prepared to tell Lennart-coded integer_cbits_decodeDouble
560        where mantissa.d can be put (it does not care about the rest) */
561     p = Hp - ARR_SIZE + WDS(1);
562     SET_HDR(p, stg_ARR_WORDS_info, CCCS);
563     StgArrWords_bytes(p) = DOUBLE_MANTISSA_SIZE;
564     MP_INT__mp_d(mp_tmp1) = BYTE_ARR_CTS(p);
565
566     /* Perform the operation */
567     ccall integer_cbits_decodeDouble(mp_tmp1 "ptr", mp_tmp_w "ptr",arg);
568
569     /* returns: (Int# (expn), Int#, ByteArray#) */
570     return (W_[mp_tmp_w], TO_W_(MP_INT__mp_size(mp_tmp1)), p);
571 }