1 /* -----------------------------------------------------------------------------
2 * $Id: PrimOps.h,v 1.62 2000/09/11 11:17:09 sewardj Exp $
4 * (c) The GHC Team, 1998-1999
6 * Macros for primitive operations in STG-ish C code.
8 * ---------------------------------------------------------------------------*/
13 /* -----------------------------------------------------------------------------
14 Helpers for the metacircular interpreter.
15 -------------------------------------------------------------------------- */
19 #define CHASE_INDIRECTIONS(lval) \
24 if (get_itbl((StgClosure*)lval)->type == IND) \
25 { again = 1; lval = ((StgInd*)lval)->indirectee; } \
27 if (get_itbl((StgClosure*)lval)->type == IND_OLDGEN) \
28 { again = 1; lval = ((StgIndOldGen*)lval)->indirectee; } \
32 #define indexWordOffClosurezh(r,a,i) \
33 do { StgClosure* tmp = (StgClosure*)(a); \
34 CHASE_INDIRECTIONS(tmp); \
38 #define indexPtrOffClosurezh(r,a,i) \
39 do { StgClosure* tmp = (StgClosure*)(a); \
40 CHASE_INDIRECTIONS(tmp); \
47 /* These are the original definitions. They don't chase indirections. */
48 #define indexWordOffClosurezh(r,a,i) r= ((W_ *)(a))[i]
49 #define indexPtrOffClosurezh(r,a,i) r= ((P_ *)(a))[i]
54 /* -----------------------------------------------------------------------------
56 -------------------------------------------------------------------------- */
58 #define gtCharzh(r,a,b) r=(I_)((a)> (b))
59 #define geCharzh(r,a,b) r=(I_)((a)>=(b))
60 #define eqCharzh(r,a,b) r=(I_)((a)==(b))
61 #define neCharzh(r,a,b) r=(I_)((a)!=(b))
62 #define ltCharzh(r,a,b) r=(I_)((a)< (b))
63 #define leCharzh(r,a,b) r=(I_)((a)<=(b))
65 /* Int comparisons: >#, >=# etc */
66 #define zgzh(r,a,b) r=(I_)((I_)(a) >(I_)(b))
67 #define zgzezh(r,a,b) r=(I_)((I_)(a)>=(I_)(b))
68 #define zezezh(r,a,b) r=(I_)((I_)(a)==(I_)(b))
69 #define zszezh(r,a,b) r=(I_)((I_)(a)!=(I_)(b))
70 #define zlzh(r,a,b) r=(I_)((I_)(a) <(I_)(b))
71 #define zlzezh(r,a,b) r=(I_)((I_)(a)<=(I_)(b))
73 #define gtWordzh(r,a,b) r=(I_)((W_)(a) >(W_)(b))
74 #define geWordzh(r,a,b) r=(I_)((W_)(a)>=(W_)(b))
75 #define eqWordzh(r,a,b) r=(I_)((W_)(a)==(W_)(b))
76 #define neWordzh(r,a,b) r=(I_)((W_)(a)!=(W_)(b))
77 #define ltWordzh(r,a,b) r=(I_)((W_)(a) <(W_)(b))
78 #define leWordzh(r,a,b) r=(I_)((W_)(a)<=(W_)(b))
80 #define gtAddrzh(r,a,b) r=(I_)((a) >(b))
81 #define geAddrzh(r,a,b) r=(I_)((a)>=(b))
82 #define eqAddrzh(r,a,b) r=(I_)((a)==(b))
83 #define neAddrzh(r,a,b) r=(I_)((a)!=(b))
84 #define ltAddrzh(r,a,b) r=(I_)((a) <(b))
85 #define leAddrzh(r,a,b) r=(I_)((a)<=(b))
87 #define gtFloatzh(r,a,b) r=(I_)((a)> (b))
88 #define geFloatzh(r,a,b) r=(I_)((a)>=(b))
89 #define eqFloatzh(r,a,b) r=(I_)((a)==(b))
90 #define neFloatzh(r,a,b) r=(I_)((a)!=(b))
91 #define ltFloatzh(r,a,b) r=(I_)((a)< (b))
92 #define leFloatzh(r,a,b) r=(I_)((a)<=(b))
94 /* Double comparisons: >##, >=#@ etc */
95 #define zgzhzh(r,a,b) r=(I_)((a) >(b))
96 #define zgzezhzh(r,a,b) r=(I_)((a)>=(b))
97 #define zezezhzh(r,a,b) r=(I_)((a)==(b))
98 #define zszezhzh(r,a,b) r=(I_)((a)!=(b))
99 #define zlzhzh(r,a,b) r=(I_)((a) <(b))
100 #define zlzezhzh(r,a,b) r=(I_)((a)<=(b))
102 /* -----------------------------------------------------------------------------
104 -------------------------------------------------------------------------- */
106 #define ordzh(r,a) r=(I_)((W_) (a))
107 #define chrzh(r,a) r=(StgChar)((W_)(a))
109 /* -----------------------------------------------------------------------------
111 -------------------------------------------------------------------------- */
113 I_ stg_div (I_ a, I_ b);
115 #define zpzh(r,a,b) r=(a)+(b)
116 #define zmzh(r,a,b) r=(a)-(b)
117 #define ztzh(r,a,b) r=(a)*(b)
118 #define quotIntzh(r,a,b) r=(a)/(b)
119 #define zszh(r,a,b) r=ULTRASAFESTGCALL2(I_,(void *, I_, I_),stg_div,(a),(b))
120 #define remIntzh(r,a,b) r=(a)%(b)
121 #define negateIntzh(r,a) r=-(a)
123 /* -----------------------------------------------------------------------------
124 * Int operations with carry.
125 * -------------------------------------------------------------------------- */
127 /* With some bit-twiddling, we can define int{Add,Sub}Czh portably in
128 * C, and without needing any comparisons. This may not be the
129 * fastest way to do it - if you have better code, please send it! --SDM
131 * Return : r = a + b, c = 0 if no overflow, 1 on overflow.
133 * We currently don't make use of the r value if c is != 0 (i.e.
134 * overflow), we just convert to big integers and try again. This
135 * could be improved by making r and c the correct values for
136 * plugging into a new J#.
138 #define addIntCzh(r,c,a,b) \
140 c = ((StgWord)(~(a^b) & (a^r))) \
141 >> (BITS_PER_BYTE * sizeof(I_) - 1); \
145 #define subIntCzh(r,c,a,b) \
147 c = ((StgWord)((a^b) & (a^r))) \
148 >> (BITS_PER_BYTE * sizeof(I_) - 1); \
151 /* Multiply with overflow checking.
153 * This is slightly more tricky - the usual sign rules for add/subtract
156 * On x86 hardware we use a hand-crafted assembly fragment to do the job.
158 * On other 32-bit machines we use gcc's 'long long' types, finding
159 * overflow with some careful bit-twiddling.
161 * On 64-bit machines where gcc's 'long long' type is also 64-bits,
162 * we use a crude approximation, testing whether either operand is
163 * larger than 32-bits; if neither is, then we go ahead with the
169 #define mulIntCzh(r,c,a,b) \
171 __asm__("xorl %1,%1\n\t \
176 : "=r" (r), "=&r" (c) : "r" (a), "0" (b)); \
179 #elif SIZEOF_VOID_P == 4
181 #ifdef WORDS_BIGENDIAN
194 #define mulIntCzh(r,c,a,b) \
197 z.l = (StgInt64)a * (StgInt64)b; \
200 if (c == 0 || c == -1) { \
201 c = ((StgWord)((a^b) ^ r)) \
202 >> (BITS_PER_BYTE * sizeof(I_) - 1); \
205 /* Careful: the carry calculation above is extremely delicate. Make sure
206 * you test it thoroughly after changing it.
211 #define HALF_INT (1 << (BITS_PER_BYTE * sizeof(I_) / 2))
213 #define stg_abs(a) ((a) < 0 ? -(a) : (a))
215 #define mulIntCzh(r,c,a,b) \
217 if (stg_abs(a) >= HALF_INT \
218 stg_abs(b) >= HALF_INT) { \
227 /* -----------------------------------------------------------------------------
229 -------------------------------------------------------------------------- */
231 #define quotWordzh(r,a,b) r=((W_)a)/((W_)b)
232 #define remWordzh(r,a,b) r=((W_)a)%((W_)b)
234 #define andzh(r,a,b) r=(a)&(b)
235 #define orzh(r,a,b) r=(a)|(b)
236 #define xorzh(r,a,b) r=(a)^(b)
237 #define notzh(r,a) r=~(a)
239 /* The extra tests below properly define the behaviour when shifting
240 * by offsets larger than the width of the value being shifted. Doing
241 * so is undefined in C (and in fact gives different answers depending
242 * on whether the operation is constant folded or not with gcc on x86!)
245 #define shiftLzh(r,a,b) r=((b) >= BITS_IN(W_)) ? 0 : (a)<<(b)
246 #define shiftRLzh(r,a,b) r=((b) >= BITS_IN(W_)) ? 0 : (a)>>(b)
247 #define iShiftLzh(r,a,b) r=((b) >= BITS_IN(W_)) ? 0 : (a)<<(b)
248 /* Right shifting of signed quantities is not portable in C, so
249 the behaviour you'll get from using these primops depends
250 on the whatever your C compiler is doing. ToDo: fix/document. -- sof 8/98
252 #define iShiftRAzh(r,a,b) r=((b) >= BITS_IN(I_)) ? (((a) < 0) ? -1 : 0) : (a)>>(b)
253 #define iShiftRLzh(r,a,b) r=((b) >= BITS_IN(I_)) ? 0 : ((W_)(a))>>(b)
255 #define int2Wordzh(r,a) r=(W_)(a)
256 #define word2Intzh(r,a) r=(I_)(a)
258 /* -----------------------------------------------------------------------------
260 -------------------------------------------------------------------------- */
262 #define int2Addrzh(r,a) r=(A_)(a)
263 #define addr2Intzh(r,a) r=(I_)(a)
265 #define readCharOffAddrzh(r,a,i) r= ((unsigned char *)(a))[i]
266 /* unsigned char is for compatibility: the index is still in bytes. */
267 #define readIntOffAddrzh(r,a,i) r= ((I_ *)(a))[i]
268 #define readWordOffAddrzh(r,a,i) r= ((W_ *)(a))[i]
269 #define readAddrOffAddrzh(r,a,i) r= ((PP_)(a))[i]
270 #define readFloatOffAddrzh(r,a,i) r= PK_FLT((P_) (((StgFloat *)(a)) + i))
271 #define readDoubleOffAddrzh(r,a,i) r= PK_DBL((P_) (((StgDouble *)(a)) + i))
272 #define readStablePtrOffAddrzh(r,a,i) r= ((StgStablePtr *)(a))[i]
273 #ifdef SUPPORT_LONG_LONGS
274 #define readInt64OffAddrzh(r,a,i) r= ((LI_ *)(a))[i]
275 #define readWord64OffAddrzh(r,a,i) r= ((LW_ *)(a))[i]
278 #define writeCharOffAddrzh(a,i,v) ((unsigned char *)(a))[i] = (unsigned char)(v)
279 /* unsigned char is for compatibility: the index is still in bytes. */
280 #define writeIntOffAddrzh(a,i,v) ((I_ *)(a))[i] = (v)
281 #define writeWordOffAddrzh(a,i,v) ((W_ *)(a))[i] = (v)
282 #define writeAddrOffAddrzh(a,i,v) ((PP_)(a))[i] = (v)
283 #define writeForeignObjOffAddrzh(a,i,v) ((PP_)(a))[i] = ForeignObj_CLOSURE_DATA(v)
284 #define writeFloatOffAddrzh(a,i,v) ASSIGN_FLT((P_) (((StgFloat *)(a)) + i),v)
285 #define writeDoubleOffAddrzh(a,i,v) ASSIGN_DBL((P_) (((StgDouble *)(a)) + i),v)
286 #define writeStablePtrOffAddrzh(a,i,v) ((StgStablePtr *)(a))[i] = (v)
287 #ifdef SUPPORT_LONG_LONGS
288 #define writeInt64OffAddrzh(a,i,v) ((LI_ *)(a))[i] = (v)
289 #define writeWord64OffAddrzh(a,i,v) ((LW_ *)(a))[i] = (v)
292 #define indexCharOffAddrzh(r,a,i) r= ((unsigned char *)(a))[i]
293 /* unsigned char is for compatibility: the index is still in bytes. */
294 #define indexIntOffAddrzh(r,a,i) r= ((I_ *)(a))[i]
295 #define indexWordOffAddrzh(r,a,i) r= ((W_ *)(a))[i]
296 #define indexAddrOffAddrzh(r,a,i) r= ((PP_)(a))[i]
297 #define indexFloatOffAddrzh(r,a,i) r= PK_FLT((P_) (((StgFloat *)(a)) + i))
298 #define indexDoubleOffAddrzh(r,a,i) r= PK_DBL((P_) (((StgDouble *)(a)) + i))
299 #define indexStablePtrOffAddrzh(r,a,i) r= ((StgStablePtr *)(a))[i]
300 #ifdef SUPPORT_LONG_LONGS
301 #define indexInt64OffAddrzh(r,a,i) r= ((LI_ *)(a))[i]
302 #define indexWord64OffAddrzh(r,a,i) r= ((LW_ *)(a))[i]
305 /* -----------------------------------------------------------------------------
307 -------------------------------------------------------------------------- */
309 #define plusFloatzh(r,a,b) r=(a)+(b)
310 #define minusFloatzh(r,a,b) r=(a)-(b)
311 #define timesFloatzh(r,a,b) r=(a)*(b)
312 #define divideFloatzh(r,a,b) r=(a)/(b)
313 #define negateFloatzh(r,a) r=-(a)
315 #define int2Floatzh(r,a) r=(StgFloat)(a)
316 #define float2Intzh(r,a) r=(I_)(a)
318 #define expFloatzh(r,a) r=(StgFloat) RET_PRIM_STGCALL1(StgDouble,exp,a)
319 #define logFloatzh(r,a) r=(StgFloat) RET_PRIM_STGCALL1(StgDouble,log,a)
320 #define sqrtFloatzh(r,a) r=(StgFloat) RET_PRIM_STGCALL1(StgDouble,sqrt,a)
321 #define sinFloatzh(r,a) r=(StgFloat) RET_PRIM_STGCALL1(StgDouble,sin,a)
322 #define cosFloatzh(r,a) r=(StgFloat) RET_PRIM_STGCALL1(StgDouble,cos,a)
323 #define tanFloatzh(r,a) r=(StgFloat) RET_PRIM_STGCALL1(StgDouble,tan,a)
324 #define asinFloatzh(r,a) r=(StgFloat) RET_PRIM_STGCALL1(StgDouble,asin,a)
325 #define acosFloatzh(r,a) r=(StgFloat) RET_PRIM_STGCALL1(StgDouble,acos,a)
326 #define atanFloatzh(r,a) r=(StgFloat) RET_PRIM_STGCALL1(StgDouble,atan,a)
327 #define sinhFloatzh(r,a) r=(StgFloat) RET_PRIM_STGCALL1(StgDouble,sinh,a)
328 #define coshFloatzh(r,a) r=(StgFloat) RET_PRIM_STGCALL1(StgDouble,cosh,a)
329 #define tanhFloatzh(r,a) r=(StgFloat) RET_PRIM_STGCALL1(StgDouble,tanh,a)
330 #define powerFloatzh(r,a,b) r=(StgFloat) RET_PRIM_STGCALL2(StgDouble,pow,a,b)
332 /* -----------------------------------------------------------------------------
334 -------------------------------------------------------------------------- */
336 #define zpzhzh(r,a,b) r=(a)+(b)
337 #define zmzhzh(r,a,b) r=(a)-(b)
338 #define ztzhzh(r,a,b) r=(a)*(b)
339 #define zszhzh(r,a,b) r=(a)/(b)
340 #define negateDoublezh(r,a) r=-(a)
342 #define int2Doublezh(r,a) r=(StgDouble)(a)
343 #define double2Intzh(r,a) r=(I_)(a)
345 #define float2Doublezh(r,a) r=(StgDouble)(a)
346 #define double2Floatzh(r,a) r=(StgFloat)(a)
348 #define expDoublezh(r,a) r=(StgDouble) RET_PRIM_STGCALL1(StgDouble,exp,a)
349 #define logDoublezh(r,a) r=(StgDouble) RET_PRIM_STGCALL1(StgDouble,log,a)
350 #define sqrtDoublezh(r,a) r=(StgDouble) RET_PRIM_STGCALL1(StgDouble,sqrt,a)
351 #define sinDoublezh(r,a) r=(StgDouble) RET_PRIM_STGCALL1(StgDouble,sin,a)
352 #define cosDoublezh(r,a) r=(StgDouble) RET_PRIM_STGCALL1(StgDouble,cos,a)
353 #define tanDoublezh(r,a) r=(StgDouble) RET_PRIM_STGCALL1(StgDouble,tan,a)
354 #define asinDoublezh(r,a) r=(StgDouble) RET_PRIM_STGCALL1(StgDouble,asin,a)
355 #define acosDoublezh(r,a) r=(StgDouble) RET_PRIM_STGCALL1(StgDouble,acos,a)
356 #define atanDoublezh(r,a) r=(StgDouble) RET_PRIM_STGCALL1(StgDouble,atan,a)
357 #define sinhDoublezh(r,a) r=(StgDouble) RET_PRIM_STGCALL1(StgDouble,sinh,a)
358 #define coshDoublezh(r,a) r=(StgDouble) RET_PRIM_STGCALL1(StgDouble,cosh,a)
359 #define tanhDoublezh(r,a) r=(StgDouble) RET_PRIM_STGCALL1(StgDouble,tanh,a)
361 #define ztztzhzh(r,a,b) r=(StgDouble) RET_PRIM_STGCALL2(StgDouble,pow,a,b)
363 /* -----------------------------------------------------------------------------
365 -------------------------------------------------------------------------- */
367 /* We can do integer2Int and cmpInteger inline, since they don't need
368 * to allocate any memory.
370 * integer2Int# is now modular.
373 #define integer2Intzh(r, sa,da) \
374 { StgWord word0 = ((StgWord *)BYTE_ARR_CTS(da))[0]; \
380 ( size < 0 && word0 != 0x8000000 ) ? \
385 #define integer2Wordzh(r, sa,da) \
386 { StgWord word0 = ((StgWord *)BYTE_ARR_CTS(da))[0]; \
388 (r) = ( size == 0 ) ? 0 : word0 ; \
391 #define cmpIntegerzh(r, s1,d1, s2,d2) \
395 arg1._mp_size = (s1); \
396 arg1._mp_alloc= ((StgArrWords *)d1)->words; \
397 arg1._mp_d = (unsigned long int *) (BYTE_ARR_CTS(d1)); \
398 arg2._mp_size = (s2); \
399 arg2._mp_alloc= ((StgArrWords *)d2)->words; \
400 arg2._mp_d = (unsigned long int *) (BYTE_ARR_CTS(d2)); \
402 (r) = RET_PRIM_STGCALL2(I_,mpz_cmp,&arg1,&arg2); \
405 #define cmpIntegerIntzh(r, s,d, i) \
408 arg._mp_size = (s); \
409 arg._mp_alloc = ((StgArrWords *)d)->words; \
410 arg._mp_d = (unsigned long int *) (BYTE_ARR_CTS(d)); \
412 (r) = RET_PRIM_STGCALL2(I_,mpz_cmp_si,&arg,i); \
415 /* NOTE: gcdIntzh and gcdIntegerIntzh work only for positive inputs! */
417 /* mp_limb_t must be able to hold an StgInt for this to work properly */
418 #define gcdIntzh(r,a,b) \
419 { mp_limb_t aa = (mp_limb_t)(a); \
420 r = RET_STGCALL3(StgInt, mpn_gcd_1, (mp_limb_t *)(&aa), 1, (mp_limb_t)(b)); \
423 #define gcdIntegerIntzh(r,sa,a,b) \
424 r = RET_STGCALL3(StgInt, mpn_gcd_1, (mp_limb_t *)(BYTE_ARR_CTS(a)), sa, b)
426 /* The rest are all out-of-line: -------- */
428 /* Integer arithmetic */
429 EXTFUN_RTS(plusIntegerzh_fast);
430 EXTFUN_RTS(minusIntegerzh_fast);
431 EXTFUN_RTS(timesIntegerzh_fast);
432 EXTFUN_RTS(gcdIntegerzh_fast);
433 EXTFUN_RTS(quotRemIntegerzh_fast);
434 EXTFUN_RTS(quotIntegerzh_fast);
435 EXTFUN_RTS(remIntegerzh_fast);
436 EXTFUN_RTS(divExactIntegerzh_fast);
437 EXTFUN_RTS(divModIntegerzh_fast);
440 EXTFUN_RTS(int2Integerzh_fast);
441 EXTFUN_RTS(word2Integerzh_fast);
442 EXTFUN_RTS(addr2Integerzh_fast);
444 /* Floating-point decodings */
445 EXTFUN_RTS(decodeFloatzh_fast);
446 EXTFUN_RTS(decodeDoublezh_fast);
448 /* -----------------------------------------------------------------------------
450 -------------------------------------------------------------------------- */
452 #ifdef SUPPORT_LONG_LONGS
454 #define integerToWord64zh(r, sa,da) \
455 { unsigned long int* d; \
459 d = (unsigned long int *) (BYTE_ARR_CTS(da)); \
463 } else if ( s == 1) { \
466 res = (LW_)d[0] + (LW_)d[1] * 0x100000000ULL; \
471 #define integerToInt64zh(r, sa,da) \
472 { unsigned long int* d; \
476 d = (unsigned long int *) (BYTE_ARR_CTS(da)); \
480 } else if ( s == 1) { \
483 res = (LI_)d[0] + (LI_)d[1] * 0x100000000LL; \
492 EXTFUN_RTS(int64ToIntegerzh_fast);
493 EXTFUN_RTS(word64ToIntegerzh_fast);
495 /* The rest are (way!) out of line, implemented via C entry points.
497 I_ stg_gtWord64 (StgWord64, StgWord64);
498 I_ stg_geWord64 (StgWord64, StgWord64);
499 I_ stg_eqWord64 (StgWord64, StgWord64);
500 I_ stg_neWord64 (StgWord64, StgWord64);
501 I_ stg_ltWord64 (StgWord64, StgWord64);
502 I_ stg_leWord64 (StgWord64, StgWord64);
504 I_ stg_gtInt64 (StgInt64, StgInt64);
505 I_ stg_geInt64 (StgInt64, StgInt64);
506 I_ stg_eqInt64 (StgInt64, StgInt64);
507 I_ stg_neInt64 (StgInt64, StgInt64);
508 I_ stg_ltInt64 (StgInt64, StgInt64);
509 I_ stg_leInt64 (StgInt64, StgInt64);
511 LW_ stg_remWord64 (StgWord64, StgWord64);
512 LW_ stg_quotWord64 (StgWord64, StgWord64);
514 LI_ stg_remInt64 (StgInt64, StgInt64);
515 LI_ stg_quotInt64 (StgInt64, StgInt64);
516 LI_ stg_negateInt64 (StgInt64);
517 LI_ stg_plusInt64 (StgInt64, StgInt64);
518 LI_ stg_minusInt64 (StgInt64, StgInt64);
519 LI_ stg_timesInt64 (StgInt64, StgInt64);
521 LW_ stg_and64 (StgWord64, StgWord64);
522 LW_ stg_or64 (StgWord64, StgWord64);
523 LW_ stg_xor64 (StgWord64, StgWord64);
524 LW_ stg_not64 (StgWord64);
526 LW_ stg_shiftL64 (StgWord64, StgInt);
527 LW_ stg_shiftRL64 (StgWord64, StgInt);
528 LI_ stg_iShiftL64 (StgInt64, StgInt);
529 LI_ stg_iShiftRL64 (StgInt64, StgInt);
530 LI_ stg_iShiftRA64 (StgInt64, StgInt);
532 LI_ stg_intToInt64 (StgInt);
533 I_ stg_int64ToInt (StgInt64);
534 LW_ stg_int64ToWord64 (StgInt64);
536 LW_ stg_wordToWord64 (StgWord);
537 W_ stg_word64ToWord (StgWord64);
538 LI_ stg_word64ToInt64 (StgWord64);
541 /* -----------------------------------------------------------------------------
543 -------------------------------------------------------------------------- */
545 /* We cast to void* instead of StgChar* because this avoids a warning
546 * about increasing the alignment requirements.
548 #define REAL_BYTE_ARR_CTS(a) ((void *) (((StgArrWords *)(a))->payload))
549 #define REAL_PTRS_ARR_CTS(a) ((P_) (((StgMutArrPtrs *)(a))->payload))
552 #define BYTE_ARR_CTS(a) \
553 ({ ASSERT(GET_INFO((StgArrWords *)(a)) == &ARR_WORDS_info); \
554 REAL_BYTE_ARR_CTS(a); })
555 #define PTRS_ARR_CTS(a) \
556 ({ ASSERT((GET_INFO((StgMutArrPtrs *)(a)) == &MUT_ARR_PTRS_FROZEN_info) \
557 || (GET_INFO((StgMutArrPtrs *)(a)) == &MUT_ARR_PTRS_info)); \
558 REAL_PTRS_ARR_CTS(a); })
560 #define BYTE_ARR_CTS(a) REAL_BYTE_ARR_CTS(a)
561 #define PTRS_ARR_CTS(a) REAL_PTRS_ARR_CTS(a)
564 extern I_ genSymZh(void);
565 extern I_ resetGenSymZh(void);
567 /*--- everything except new*Array is done inline: */
569 #define sameMutableArrayzh(r,a,b) r=(I_)((a)==(b))
570 #define sameMutableByteArrayzh(r,a,b) r=(I_)((a)==(b))
572 #define readArrayzh(r,a,i) r=((PP_) PTRS_ARR_CTS(a))[(i)]
574 #define readCharArrayzh(r,a,i) indexCharOffAddrzh(r,BYTE_ARR_CTS(a),i)
575 #define readIntArrayzh(r,a,i) indexIntOffAddrzh(r,BYTE_ARR_CTS(a),i)
576 #define readWordArrayzh(r,a,i) indexWordOffAddrzh(r,BYTE_ARR_CTS(a),i)
577 #define readAddrArrayzh(r,a,i) indexAddrOffAddrzh(r,BYTE_ARR_CTS(a),i)
578 #define readFloatArrayzh(r,a,i) indexFloatOffAddrzh(r,BYTE_ARR_CTS(a),i)
579 #define readDoubleArrayzh(r,a,i) indexDoubleOffAddrzh(r,BYTE_ARR_CTS(a),i)
580 #define readStablePtrArrayzh(r,a,i) indexStablePtrOffAddrzh(r,BYTE_ARR_CTS(a),i)
581 #ifdef SUPPORT_LONG_LONGS
582 #define readInt64Arrayzh(r,a,i) indexInt64OffAddrzh(r,BYTE_ARR_CTS(a),i)
583 #define readWord64Arrayzh(r,a,i) indexWord64OffAddrzh(r,BYTE_ARR_CTS(a),i)
586 /* result ("r") arg ignored in write macros! */
587 #define writeArrayzh(a,i,v) ((PP_) PTRS_ARR_CTS(a))[(i)]=(v)
589 #define writeCharArrayzh(a,i,v) ((unsigned char *)(BYTE_ARR_CTS(a)))[i] = (unsigned char)(v)
590 /* unsigned char is for compatibility: the index is still in bytes. */
591 #define writeIntArrayzh(a,i,v) ((I_ *)(BYTE_ARR_CTS(a)))[i] = (v)
592 #define writeWordArrayzh(a,i,v) ((W_ *)(BYTE_ARR_CTS(a)))[i] = (v)
593 #define writeAddrArrayzh(a,i,v) ((PP_)(BYTE_ARR_CTS(a)))[i] = (v)
594 #define writeFloatArrayzh(a,i,v) \
595 ASSIGN_FLT((P_) (((StgFloat *)(BYTE_ARR_CTS(a))) + i),v)
596 #define writeDoubleArrayzh(a,i,v) \
597 ASSIGN_DBL((P_) (((StgDouble *)(BYTE_ARR_CTS(a))) + i),v)
598 #define writeStablePtrArrayzh(a,i,v) ((StgStablePtr *)(BYTE_ARR_CTS(a)))[i] = (v)
599 #ifdef SUPPORT_LONG_LONGS
600 #define writeInt64Arrayzh(a,i,v) ((LI_ *)(BYTE_ARR_CTS(a)))[i] = (v)
601 #define writeWord64Arrayzh(a,i,v) ((LW_ *)(BYTE_ARR_CTS(a)))[i] = (v)
604 #define indexArrayzh(r,a,i) r=((PP_) PTRS_ARR_CTS(a))[(i)]
606 #define indexCharArrayzh(r,a,i) indexCharOffAddrzh(r,BYTE_ARR_CTS(a),i)
607 #define indexIntArrayzh(r,a,i) indexIntOffAddrzh(r,BYTE_ARR_CTS(a),i)
608 #define indexWordArrayzh(r,a,i) indexWordOffAddrzh(r,BYTE_ARR_CTS(a),i)
609 #define indexAddrArrayzh(r,a,i) indexAddrOffAddrzh(r,BYTE_ARR_CTS(a),i)
610 #define indexFloatArrayzh(r,a,i) indexFloatOffAddrzh(r,BYTE_ARR_CTS(a),i)
611 #define indexDoubleArrayzh(r,a,i) indexDoubleOffAddrzh(r,BYTE_ARR_CTS(a),i)
612 #define indexStablePtrArrayzh(r,a,i) indexStablePtrOffAddrzh(r,BYTE_ARR_CTS(a),i)
613 #ifdef SUPPORT_LONG_LONGS
614 #define indexInt64Arrayzh(r,a,i) indexInt64OffAddrzh(r,BYTE_ARR_CTS(a),i)
615 #define indexWord64Arrayzh(r,a,i) indexWord64OffAddrzh(r,BYTE_ARR_CTS(a),i)
618 /* Freezing arrays-of-ptrs requires changing an info table, for the
619 benefit of the generational collector. It needs to scavenge mutable
620 objects, even if they are in old space. When they become immutable,
621 they can be removed from this scavenge list. */
623 #define unsafeFreezzeArrayzh(r,a) \
625 SET_INFO((StgClosure *)a,&MUT_ARR_PTRS_FROZEN_info); \
629 #define unsafeFreezzeByteArrayzh(r,a) r=(a)
631 EXTFUN_RTS(unsafeThawArrayzh_fast);
633 #define sizzeofByteArrayzh(r,a) \
634 r = (((StgArrWords *)(a))->words * sizeof(W_))
635 #define sizzeofMutableByteArrayzh(r,a) \
636 r = (((StgArrWords *)(a))->words * sizeof(W_))
638 /* and the out-of-line ones... */
640 EXTFUN_RTS(newCharArrayzh_fast);
641 EXTFUN_RTS(newIntArrayzh_fast);
642 EXTFUN_RTS(newWordArrayzh_fast);
643 EXTFUN_RTS(newAddrArrayzh_fast);
644 EXTFUN_RTS(newFloatArrayzh_fast);
645 EXTFUN_RTS(newDoubleArrayzh_fast);
646 EXTFUN_RTS(newStablePtrArrayzh_fast);
647 EXTFUN_RTS(newArrayzh_fast);
649 /* encoding and decoding of floats/doubles. */
651 /* We only support IEEE floating point format */
652 #include "ieee-flpt.h"
654 /* The decode operations are out-of-line because they need to allocate
657 #ifdef FLOATS_AS_DOUBLES
658 #define decodeFloatzh_fast decodeDoublezh_fast
660 EXTFUN_RTS(decodeFloatzh_fast);
663 EXTFUN_RTS(decodeDoublezh_fast);
665 /* grimy low-level support functions defined in StgPrimFloat.c */
667 extern StgDouble __encodeDouble (I_ size, StgByteArray arr, I_ e);
668 extern StgDouble __int_encodeDouble (I_ j, I_ e);
669 #ifndef FLOATS_AS_DOUBLES
670 extern StgFloat __encodeFloat (I_ size, StgByteArray arr, I_ e);
671 extern StgFloat __int_encodeFloat (I_ j, I_ e);
673 extern void __decodeDouble (MP_INT *man, I_ *_exp, StgDouble dbl);
674 extern void __decodeFloat (MP_INT *man, I_ *_exp, StgFloat flt);
675 extern StgInt isDoubleNaN(StgDouble d);
676 extern StgInt isDoubleInfinite(StgDouble d);
677 extern StgInt isDoubleDenormalized(StgDouble d);
678 extern StgInt isDoubleNegativeZero(StgDouble d);
679 extern StgInt isFloatNaN(StgFloat f);
680 extern StgInt isFloatInfinite(StgFloat f);
681 extern StgInt isFloatDenormalized(StgFloat f);
682 extern StgInt isFloatNegativeZero(StgFloat f);
684 /* -----------------------------------------------------------------------------
687 newMutVar is out of line.
688 -------------------------------------------------------------------------- */
690 EXTFUN_RTS(newMutVarzh_fast);
692 #define readMutVarzh(r,a) r=(P_)(((StgMutVar *)(a))->var)
693 #define writeMutVarzh(a,v) (P_)(((StgMutVar *)(a))->var)=(v)
694 #define sameMutVarzh(r,a,b) r=(I_)((a)==(b))
696 /* -----------------------------------------------------------------------------
699 All out of line, because they either allocate or may block.
700 -------------------------------------------------------------------------- */
701 #define sameMVarzh(r,a,b) r=(I_)((a)==(b))
703 /* Assume external decl of EMPTY_MVAR_info is in scope by now */
704 #define isEmptyMVarzh(r,a) r=(I_)((GET_INFO((StgMVar*)(a))) == &EMPTY_MVAR_info )
705 EXTFUN_RTS(newMVarzh_fast);
706 EXTFUN_RTS(takeMVarzh_fast);
707 EXTFUN_RTS(tryTakeMVarzh_fast);
708 EXTFUN_RTS(putMVarzh_fast);
711 /* -----------------------------------------------------------------------------
713 -------------------------------------------------------------------------- */
715 EXTFUN_RTS(waitReadzh_fast);
716 EXTFUN_RTS(waitWritezh_fast);
717 EXTFUN_RTS(delayzh_fast);
719 /* -----------------------------------------------------------------------------
720 Primitive I/O, error-handling PrimOps
721 -------------------------------------------------------------------------- */
723 EXTFUN_RTS(catchzh_fast);
724 EXTFUN_RTS(raisezh_fast);
726 extern void stg_exit(I_ n) __attribute__ ((noreturn));
728 /* -----------------------------------------------------------------------------
729 Stable Name / Stable Pointer PrimOps
730 -------------------------------------------------------------------------- */
734 EXTFUN_RTS(makeStableNamezh_fast);
736 #define stableNameToIntzh(r,s) (r = ((StgStableName *)s)->sn)
738 #define eqStableNamezh(r,sn1,sn2) \
739 (r = (((StgStableName *)sn1)->sn == ((StgStableName *)sn2)->sn))
741 #define makeStablePtrzh(r,a) \
742 r = RET_STGCALL1(StgStablePtr,getStablePtr,a)
744 #define deRefStablePtrzh(r,sp) do { \
745 ASSERT(stable_ptr_table[stgCast(StgWord,sp) & ~STABLEPTR_WEIGHT_MASK].weight > 0); \
746 r = stable_ptr_table[stgCast(StgWord,sp) & ~STABLEPTR_WEIGHT_MASK].addr; \
749 #define eqStablePtrzh(r,sp1,sp2) \
750 (r = ((stgCast(StgWord,sp1) & ~STABLEPTR_WEIGHT_MASK) == (stgCast(StgWord,sp2) & ~STABLEPTR_WEIGHT_MASK)))
754 /* -----------------------------------------------------------------------------
755 Concurrency/Exception PrimOps.
756 -------------------------------------------------------------------------- */
758 EXTFUN_RTS(forkzh_fast);
759 EXTFUN_RTS(yieldzh_fast);
760 EXTFUN_RTS(killThreadzh_fast);
761 EXTFUN_RTS(seqzh_fast);
762 EXTFUN_RTS(blockAsyncExceptionszh_fast);
763 EXTFUN_RTS(unblockAsyncExceptionszh_fast);
765 #define myThreadIdzh(t) (t = CurrentTSO)
767 extern int cmp_thread(const StgTSO *tso1, const StgTSO *tso2);
769 /* ------------------------------------------------------------------------
772 A par in the Haskell code is ultimately translated to a parzh macro
773 (with a case wrapped around it to guarantee that the macro is actually
774 executed; see compiler/prelude/PrimOps.lhs)
775 In GUM and SMP we only add a pointer to the spark pool.
776 In GranSim we call an RTS fct, forwarding additional parameters which
777 supply info on granularity of the computation, size of the result value
778 and the degree of parallelism in the sparked expression.
779 ---------------------------------------------------------------------- */
783 #define parzh(r,node) PAR(r,node,1,0,0,0,0,0)
786 #define parAtzh(r,node,where,identifier,gran_info,size_info,par_info,rest) \
787 parAT(r,node,where,identifier,gran_info,size_info,par_info,rest,1)
790 #define parAtAbszh(r,node,proc,identifier,gran_info,size_info,par_info,rest) \
791 parAT(r,node,proc,identifier,gran_info,size_info,par_info,rest,2)
794 #define parAtRelzh(r,node,proc,identifier,gran_info,size_info,par_info,rest) \
795 parAT(r,node,proc,identifier,gran_info,size_info,par_info,rest,3)
797 //@cindex _parAtForNow_
798 #define parAtForNowzh(r,node,where,identifier,gran_info,size_info,par_info,rest) \
799 parAT(r,node,where,identifier,gran_info,size_info,par_info,rest,0)
801 #define parAT(r,node,where,identifier,gran_info,size_info,par_info,rest,local) \
803 if (closure_SHOULD_SPARK((StgClosure*)node)) { \
807 STGCALL6(newSpark, node,identifier,gran_info,size_info,par_info,local); \
809 case 2: p = where; /* parAtAbs means absolute PE no. expected */ \
811 case 3: p = CurrentProc+where; /* parAtRel means rel PE no. expected */\
813 default: p = where_is(where); /* parAt means closure expected */ \
816 /* update GranSim state according to this spark */ \
817 STGCALL3(GranSimSparkAtAbs, result, (I_)p, identifier); \
822 #define parLocalzh(r,node,identifier,gran_info,size_info,par_info,rest) \
823 PAR(r,node,rest,identifier,gran_info,size_info,par_info,1)
825 //@cindex _parGlobal_
826 #define parGlobalzh(r,node,identifier,gran_info,size_info,par_info,rest) \
827 PAR(r,node,rest,identifier,gran_info,size_info,par_info,0)
829 #define PAR(r,node,rest,identifier,gran_info,size_info,par_info,local) \
831 if (closure_SHOULD_SPARK((StgClosure*)node)) { \
833 result = RET_STGCALL6(rtsSpark*, newSpark, \
834 node,identifier,gran_info,size_info,par_info,local);\
835 STGCALL1(add_to_spark_queue,result); \
836 STGCALL2(GranSimSpark, local,(P_)node); \
840 #define copyablezh(r,node) \
841 /* copyable not yet implemented!! */
843 #define noFollowzh(r,node) \
844 /* noFollow not yet implemented!! */
846 #elif defined(SMP) || defined(PAR)
848 #define parzh(r,node) \
850 extern unsigned int context_switch; \
851 if (closure_SHOULD_SPARK((StgClosure *)node) && \
852 SparkTl < SparkLim) { \
853 *SparkTl++ = (StgClosure *)(node); \
855 r = context_switch = 1; \
857 #else /* !GRAN && !SMP && !PAR */
858 #define parzh(r,node) r = 1
861 /* -----------------------------------------------------------------------------
863 -------------------------------------------------------------------------- */
865 /* warning: extremely non-referentially transparent, need to hide in
866 an appropriate monad.
868 ToDo: follow indirections.
871 #define reallyUnsafePtrEqualityzh(r,a,b) r=((StgPtr)(a) == (StgPtr)(b))
873 /* -----------------------------------------------------------------------------
874 Weak Pointer PrimOps.
875 -------------------------------------------------------------------------- */
879 EXTFUN_RTS(mkWeakzh_fast);
880 EXTFUN_RTS(finalizzeWeakzh_fast);
882 #define deRefWeakzh(code,val,w) \
883 if (((StgWeak *)w)->header.info == &WEAK_info) { \
885 val = (P_)((StgWeak *)w)->value; \
891 #define sameWeakzh(w1,w2) ((w1)==(w2))
895 /* -----------------------------------------------------------------------------
896 Foreign Object PrimOps.
897 -------------------------------------------------------------------------- */
901 #define ForeignObj_CLOSURE_DATA(c) (((StgForeignObj *)c)->data)
903 #define foreignObjToAddrzh(r,fo) r=ForeignObj_CLOSURE_DATA(fo)
904 #define touchzh(o) /* nothing */
906 EXTFUN_RTS(mkForeignObjzh_fast);
908 #define writeForeignObjzh(res,datum) \
909 (ForeignObj_CLOSURE_DATA(res) = (P_)(datum))
911 #define eqForeignObj(f1,f2) ((f1)==(f2))
913 #define indexCharOffForeignObjzh(r,fo,i) indexCharOffAddrzh(r,ForeignObj_CLOSURE_DATA(fo),i)
914 #define indexIntOffForeignObjzh(r,fo,i) indexIntOffAddrzh(r,ForeignObj_CLOSURE_DATA(fo),i)
915 #define indexWordOffForeignObjzh(r,fo,i) indexWordOffAddrzh(r,ForeignObj_CLOSURE_DATA(fo),i)
916 #define indexAddrOffForeignObjzh(r,fo,i) indexAddrOffAddrzh(r,ForeignObj_CLOSURE_DATA(fo),i)
917 #define indexFloatOffForeignObjzh(r,fo,i) indexFloatOffAddrzh(r,ForeignObj_CLOSURE_DATA(fo),i)
918 #define indexDoubleOffForeignObjzh(r,fo,i) indexDoubleOffAddrzh(r,ForeignObj_CLOSURE_DATA(fo),i)
919 #define indexStablePtrOffForeignObjzh(r,fo,i) indexStablePtrOffAddrzh(r,ForeignObj_CLOSURE_DATA(fo),i)
920 #ifdef SUPPORT_LONG_LONGS
921 #define indexInt64OffForeignObjzh(r,fo,i) indexInt64OffAddrzh(r,ForeignObj_CLOSURE_DATA(fo),i)
922 #define indexWord64OffForeignObjzh(r,fo,i) indexWord64OffAddrzh(r,ForeignObj_CLOSURE_DATA(fo),i)
928 /* -----------------------------------------------------------------------------
930 -------------------------------------------------------------------------- */
933 #define dataToTagzh(r,a) \
934 do { StgClosure* tmp = (StgClosure*)(a); \
935 CHASE_INDIRECTIONS(tmp); \
936 r = (GET_TAG(((StgClosure *)tmp)->header.info)); \
939 /* Original version doesn't chase indirections. */
940 #define dataToTagzh(r,a) r=(GET_TAG(((StgClosure *)a)->header.info))
943 /* tagToEnum# is handled directly by the code generator. */
945 /* -----------------------------------------------------------------------------
946 Signal processing. Not really primops, but called directly from
948 -------------------------------------------------------------------------- */
950 #define STG_SIG_DFL (-1)
951 #define STG_SIG_IGN (-2)
952 #define STG_SIG_ERR (-3)
953 #define STG_SIG_HAN (-4)
955 extern StgInt sig_install (StgInt, StgInt, StgStablePtr, sigset_t *);
956 #define stg_sig_default(sig,mask) sig_install(sig,STG_SIG_DFL,0,(sigset_t *)mask)
957 #define stg_sig_ignore(sig,mask) sig_install(sig,STG_SIG_IGN,0,(sigset_t *)mask)
958 #define stg_sig_catch(sig,ptr,mask) sig_install(sig,STG_SIG_HAN,ptr,(sigset_t *)mask)
960 #endif /* PRIMOPS_H */