1 /* -----------------------------------------------------------------------------
2 * $Id: PrimOps.h,v 1.70 2000/12/12 12:19:57 simonmar Exp $
4 * (c) The GHC Team, 1998-2000
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 indexDoubleOffClosurezh(r,a,i) \
39 do { StgClosure* tmp = (StgClosure*)(a); \
40 CHASE_INDIRECTIONS(tmp); \
41 r = PK_DBL(((P_)tmp + i); \
44 #define indexPtrOffClosurezh(r,a,i) \
45 do { StgClosure* tmp = (StgClosure*)(a); \
46 CHASE_INDIRECTIONS(tmp); \
50 #define setWordOffClosurezh(r,a,i,b) \
51 do { StgClosure* tmp = (StgClosure*)(a); \
52 CHASE_INDIRECTIONS(tmp); \
57 #define setDoubleOffClosurezh(r,a,i,b) \
58 do { StgClosure* tmp = (StgClosure*)(a); \
59 CHASE_INDIRECTIONS(tmp); \
60 ASSIGN_DBL((P_)tmp + i, b); \
64 #define setPtrOffClosurezh(r,a,i,b) \
65 do { StgClosure* tmp = (StgClosure*)(a); \
66 CHASE_INDIRECTIONS(tmp); \
75 /* -----------------------------------------------------------------------------
77 -------------------------------------------------------------------------- */
79 #define gtCharzh(r,a,b) r=(I_)((a)> (b))
80 #define geCharzh(r,a,b) r=(I_)((a)>=(b))
81 #define eqCharzh(r,a,b) r=(I_)((a)==(b))
82 #define neCharzh(r,a,b) r=(I_)((a)!=(b))
83 #define ltCharzh(r,a,b) r=(I_)((a)< (b))
84 #define leCharzh(r,a,b) r=(I_)((a)<=(b))
86 /* Int comparisons: >#, >=# etc */
87 #define zgzh(r,a,b) r=(I_)((I_)(a) >(I_)(b))
88 #define zgzezh(r,a,b) r=(I_)((I_)(a)>=(I_)(b))
89 #define zezezh(r,a,b) r=(I_)((I_)(a)==(I_)(b))
90 #define zszezh(r,a,b) r=(I_)((I_)(a)!=(I_)(b))
91 #define zlzh(r,a,b) r=(I_)((I_)(a) <(I_)(b))
92 #define zlzezh(r,a,b) r=(I_)((I_)(a)<=(I_)(b))
94 #define gtWordzh(r,a,b) r=(I_)((W_)(a) >(W_)(b))
95 #define geWordzh(r,a,b) r=(I_)((W_)(a)>=(W_)(b))
96 #define eqWordzh(r,a,b) r=(I_)((W_)(a)==(W_)(b))
97 #define neWordzh(r,a,b) r=(I_)((W_)(a)!=(W_)(b))
98 #define ltWordzh(r,a,b) r=(I_)((W_)(a) <(W_)(b))
99 #define leWordzh(r,a,b) r=(I_)((W_)(a)<=(W_)(b))
101 #define gtAddrzh(r,a,b) r=(I_)((a) >(b))
102 #define geAddrzh(r,a,b) r=(I_)((a)>=(b))
103 #define eqAddrzh(r,a,b) r=(I_)((a)==(b))
104 #define neAddrzh(r,a,b) r=(I_)((a)!=(b))
105 #define ltAddrzh(r,a,b) r=(I_)((a) <(b))
106 #define leAddrzh(r,a,b) r=(I_)((a)<=(b))
108 #define gtFloatzh(r,a,b) r=(I_)((a)> (b))
109 #define geFloatzh(r,a,b) r=(I_)((a)>=(b))
110 #define eqFloatzh(r,a,b) r=(I_)((a)==(b))
111 #define neFloatzh(r,a,b) r=(I_)((a)!=(b))
112 #define ltFloatzh(r,a,b) r=(I_)((a)< (b))
113 #define leFloatzh(r,a,b) r=(I_)((a)<=(b))
115 /* Double comparisons: >##, >=#@ etc */
116 #define zgzhzh(r,a,b) r=(I_)((a) >(b))
117 #define zgzezhzh(r,a,b) r=(I_)((a)>=(b))
118 #define zezezhzh(r,a,b) r=(I_)((a)==(b))
119 #define zszezhzh(r,a,b) r=(I_)((a)!=(b))
120 #define zlzhzh(r,a,b) r=(I_)((a) <(b))
121 #define zlzezhzh(r,a,b) r=(I_)((a)<=(b))
123 /* -----------------------------------------------------------------------------
125 -------------------------------------------------------------------------- */
127 #define ordzh(r,a) r=(I_)((W_) (a))
128 #define chrzh(r,a) r=(StgChar)((W_)(a))
130 /* -----------------------------------------------------------------------------
132 -------------------------------------------------------------------------- */
134 I_ stg_div (I_ a, I_ b);
136 #define zpzh(r,a,b) r=(a)+(b)
137 #define zmzh(r,a,b) r=(a)-(b)
138 #define ztzh(r,a,b) r=(a)*(b)
139 #define quotIntzh(r,a,b) r=(a)/(b)
140 #define zszh(r,a,b) r=ULTRASAFESTGCALL2(I_,(void *, I_, I_),stg_div,(a),(b))
141 #define remIntzh(r,a,b) r=(a)%(b)
142 #define negateIntzh(r,a) r=-(a)
144 /* -----------------------------------------------------------------------------
145 * Int operations with carry.
146 * -------------------------------------------------------------------------- */
148 /* With some bit-twiddling, we can define int{Add,Sub}Czh portably in
149 * C, and without needing any comparisons. This may not be the
150 * fastest way to do it - if you have better code, please send it! --SDM
152 * Return : r = a + b, c = 0 if no overflow, 1 on overflow.
154 * We currently don't make use of the r value if c is != 0 (i.e.
155 * overflow), we just convert to big integers and try again. This
156 * could be improved by making r and c the correct values for
157 * plugging into a new J#.
159 #define addIntCzh(r,c,a,b) \
161 c = ((StgWord)(~(a^b) & (a^r))) \
162 >> (BITS_PER_BYTE * sizeof(I_) - 1); \
166 #define subIntCzh(r,c,a,b) \
168 c = ((StgWord)((a^b) & (a^r))) \
169 >> (BITS_PER_BYTE * sizeof(I_) - 1); \
172 /* Multiply with overflow checking.
174 * This is slightly more tricky - the usual sign rules for add/subtract
177 * On x86 hardware we use a hand-crafted assembly fragment to do the job.
179 * On other 32-bit machines we use gcc's 'long long' types, finding
180 * overflow with some careful bit-twiddling.
182 * On 64-bit machines where gcc's 'long long' type is also 64-bits,
183 * we use a crude approximation, testing whether either operand is
184 * larger than 32-bits; if neither is, then we go ahead with the
190 #define mulIntCzh(r,c,a,b) \
192 __asm__("xorl %1,%1\n\t \
197 : "=r" (r), "=&r" (c) : "r" (a), "0" (b)); \
200 #elif SIZEOF_VOID_P == 4
202 #ifdef WORDS_BIGENDIAN
215 #define mulIntCzh(r,c,a,b) \
218 z.l = (StgInt64)a * (StgInt64)b; \
221 if (c == 0 || c == -1) { \
222 c = ((StgWord)((a^b) ^ r)) \
223 >> (BITS_PER_BYTE * sizeof(I_) - 1); \
226 /* Careful: the carry calculation above is extremely delicate. Make sure
227 * you test it thoroughly after changing it.
232 #define HALF_INT (1 << (BITS_PER_BYTE * sizeof(I_) / 2))
234 #define stg_abs(a) ((a) < 0 ? -(a) : (a))
236 #define mulIntCzh(r,c,a,b) \
238 if (stg_abs(a) >= HALF_INT \
239 stg_abs(b) >= HALF_INT) { \
248 /* -----------------------------------------------------------------------------
250 -------------------------------------------------------------------------- */
252 #define quotWordzh(r,a,b) r=((W_)a)/((W_)b)
253 #define remWordzh(r,a,b) r=((W_)a)%((W_)b)
255 #define andzh(r,a,b) r=(a)&(b)
256 #define orzh(r,a,b) r=(a)|(b)
257 #define xorzh(r,a,b) r=(a)^(b)
258 #define notzh(r,a) r=~(a)
260 /* The extra tests below properly define the behaviour when shifting
261 * by offsets larger than the width of the value being shifted. Doing
262 * so is undefined in C (and in fact gives different answers depending
263 * on whether the operation is constant folded or not with gcc on x86!)
266 #define shiftLzh(r,a,b) r=((b) >= BITS_IN(W_)) ? 0 : (a)<<(b)
267 #define shiftRLzh(r,a,b) r=((b) >= BITS_IN(W_)) ? 0 : (a)>>(b)
268 #define iShiftLzh(r,a,b) r=((b) >= BITS_IN(W_)) ? 0 : (a)<<(b)
269 /* Right shifting of signed quantities is not portable in C, so
270 the behaviour you'll get from using these primops depends
271 on the whatever your C compiler is doing. ToDo: fix/document. -- sof 8/98
273 #define iShiftRAzh(r,a,b) r=((b) >= BITS_IN(I_)) ? (((a) < 0) ? -1 : 0) : (a)>>(b)
274 #define iShiftRLzh(r,a,b) r=((b) >= BITS_IN(I_)) ? 0 : ((W_)(a))>>(b)
276 #define int2Wordzh(r,a) r=(W_)(a)
277 #define word2Intzh(r,a) r=(I_)(a)
279 /* -----------------------------------------------------------------------------
281 -------------------------------------------------------------------------- */
283 #define int2Addrzh(r,a) r=(A_)(a)
284 #define addr2Intzh(r,a) r=(I_)(a)
286 #define readCharOffAddrzh(r,a,i) r= ((unsigned char *)(a))[i]
287 /* unsigned char is for compatibility: the index is still in bytes. */
288 #define readIntOffAddrzh(r,a,i) r= ((I_ *)(a))[i]
289 #define readWordOffAddrzh(r,a,i) r= ((W_ *)(a))[i]
290 #define readAddrOffAddrzh(r,a,i) r= ((PP_)(a))[i]
291 #define readFloatOffAddrzh(r,a,i) r= PK_FLT((P_) (((StgFloat *)(a)) + i))
292 #define readDoubleOffAddrzh(r,a,i) r= PK_DBL((P_) (((StgDouble *)(a)) + i))
293 #define readStablePtrOffAddrzh(r,a,i) r= ((StgStablePtr *)(a))[i]
294 #define readInt8OffAddrzh(r,a,i) r= ((StgInt8 *)(a))[i]
295 #define readInt16OffAddrzh(r,a,i) r= ((StgInt16 *)(a))[i]
296 #define readInt32OffAddrzh(r,a,i) r= ((StgInt32 *)(a))[i]
297 #define readWord8OffAddrzh(r,a,i) r= ((StgWord8 *)(a))[i]
298 #define readWord16OffAddrzh(r,a,i) r= ((StgWord16 *)(a))[i]
299 #define readWord32OffAddrzh(r,a,i) r= ((StgWord32 *)(a))[i]
300 #ifdef SUPPORT_LONG_LONGS
301 #define readInt64OffAddrzh(r,a,i) r= ((LI_ *)(a))[i]
302 #define readWord64OffAddrzh(r,a,i) r= ((LW_ *)(a))[i]
305 #define writeCharOffAddrzh(a,i,v) ((unsigned char *)(a))[i] = (unsigned char)(v)
306 /* unsigned char is for compatibility: the index is still in bytes. */
307 #define writeIntOffAddrzh(a,i,v) ((I_ *)(a))[i] = (v)
308 #define writeWordOffAddrzh(a,i,v) ((W_ *)(a))[i] = (v)
309 #define writeAddrOffAddrzh(a,i,v) ((PP_)(a))[i] = (v)
310 #define writeForeignObjOffAddrzh(a,i,v) ((PP_)(a))[i] = ForeignObj_CLOSURE_DATA(v)
311 #define writeFloatOffAddrzh(a,i,v) ASSIGN_FLT((P_) (((StgFloat *)(a)) + i),v)
312 #define writeDoubleOffAddrzh(a,i,v) ASSIGN_DBL((P_) (((StgDouble *)(a)) + i),v)
313 #define writeStablePtrOffAddrzh(a,i,v) ((StgStablePtr *)(a))[i] = (v)
314 #define writeInt8OffAddrzh(a,i,v) ((StgInt8 *)(a))[i] = (v)
315 #define writeInt16OffAddrzh(a,i,v) ((StgInt16 *)(a))[i] = (v)
316 #define writeInt32OffAddrzh(a,i,v) ((StgInt32 *)(a))[i] = (v)
317 #define writeWord8OffAddrzh(a,i,v) ((StgWord8 *)(a))[i] = (v)
318 #define writeWord16OffAddrzh(a,i,v) ((StgWord16 *)(a))[i] = (v)
319 #define writeWord32OffAddrzh(a,i,v) ((StgWord32 *)(a))[i] = (v)
320 #ifdef SUPPORT_LONG_LONGS
321 #define writeInt64OffAddrzh(a,i,v) ((LI_ *)(a))[i] = (v)
322 #define writeWord64OffAddrzh(a,i,v) ((LW_ *)(a))[i] = (v)
325 #define indexCharOffAddrzh(r,a,i) r= ((unsigned char *)(a))[i]
326 /* unsigned char is for compatibility: the index is still in bytes. */
327 #define indexIntOffAddrzh(r,a,i) r= ((I_ *)(a))[i]
328 #define indexWordOffAddrzh(r,a,i) r= ((W_ *)(a))[i]
329 #define indexAddrOffAddrzh(r,a,i) r= ((PP_)(a))[i]
330 #define indexFloatOffAddrzh(r,a,i) r= PK_FLT((P_) (((StgFloat *)(a)) + i))
331 #define indexDoubleOffAddrzh(r,a,i) r= PK_DBL((P_) (((StgDouble *)(a)) + i))
332 #define indexStablePtrOffAddrzh(r,a,i) r= ((StgStablePtr *)(a))[i]
333 #define indexInt8OffAddrzh(r,a,i) r= ((StgInt8 *)(a))[i]
334 #define indexInt16OffAddrzh(r,a,i) r= ((StgInt16 *)(a))[i]
335 #define indexInt32OffAddrzh(r,a,i) r= ((StgInt32 *)(a))[i]
336 #define indexWord8OffAddrzh(r,a,i) r= ((StgWord8 *)(a))[i]
337 #define indexWord16OffAddrzh(r,a,i) r= ((StgWord16 *)(a))[i]
338 #define indexWord32OffAddrzh(r,a,i) r= ((StgWord32 *)(a))[i]
339 #ifdef SUPPORT_LONG_LONGS
340 #define indexInt64OffAddrzh(r,a,i) r= ((LI_ *)(a))[i]
341 #define indexWord64OffAddrzh(r,a,i) r= ((LW_ *)(a))[i]
344 /* -----------------------------------------------------------------------------
346 -------------------------------------------------------------------------- */
348 #define plusFloatzh(r,a,b) r=(a)+(b)
349 #define minusFloatzh(r,a,b) r=(a)-(b)
350 #define timesFloatzh(r,a,b) r=(a)*(b)
351 #define divideFloatzh(r,a,b) r=(a)/(b)
352 #define negateFloatzh(r,a) r=-(a)
354 #define int2Floatzh(r,a) r=(StgFloat)(a)
355 #define float2Intzh(r,a) r=(I_)(a)
357 #define expFloatzh(r,a) r=(StgFloat) RET_PRIM_STGCALL1(StgDouble,exp,a)
358 #define logFloatzh(r,a) r=(StgFloat) RET_PRIM_STGCALL1(StgDouble,log,a)
359 #define sqrtFloatzh(r,a) r=(StgFloat) RET_PRIM_STGCALL1(StgDouble,sqrt,a)
360 #define sinFloatzh(r,a) r=(StgFloat) RET_PRIM_STGCALL1(StgDouble,sin,a)
361 #define cosFloatzh(r,a) r=(StgFloat) RET_PRIM_STGCALL1(StgDouble,cos,a)
362 #define tanFloatzh(r,a) r=(StgFloat) RET_PRIM_STGCALL1(StgDouble,tan,a)
363 #define asinFloatzh(r,a) r=(StgFloat) RET_PRIM_STGCALL1(StgDouble,asin,a)
364 #define acosFloatzh(r,a) r=(StgFloat) RET_PRIM_STGCALL1(StgDouble,acos,a)
365 #define atanFloatzh(r,a) r=(StgFloat) RET_PRIM_STGCALL1(StgDouble,atan,a)
366 #define sinhFloatzh(r,a) r=(StgFloat) RET_PRIM_STGCALL1(StgDouble,sinh,a)
367 #define coshFloatzh(r,a) r=(StgFloat) RET_PRIM_STGCALL1(StgDouble,cosh,a)
368 #define tanhFloatzh(r,a) r=(StgFloat) RET_PRIM_STGCALL1(StgDouble,tanh,a)
369 #define powerFloatzh(r,a,b) r=(StgFloat) RET_PRIM_STGCALL2(StgDouble,pow,a,b)
371 /* -----------------------------------------------------------------------------
373 -------------------------------------------------------------------------- */
375 #define zpzhzh(r,a,b) r=(a)+(b)
376 #define zmzhzh(r,a,b) r=(a)-(b)
377 #define ztzhzh(r,a,b) r=(a)*(b)
378 #define zszhzh(r,a,b) r=(a)/(b)
379 #define negateDoublezh(r,a) r=-(a)
381 #define int2Doublezh(r,a) r=(StgDouble)(a)
382 #define double2Intzh(r,a) r=(I_)(a)
384 #define float2Doublezh(r,a) r=(StgDouble)(a)
385 #define double2Floatzh(r,a) r=(StgFloat)(a)
387 #define expDoublezh(r,a) r=(StgDouble) RET_PRIM_STGCALL1(StgDouble,exp,a)
388 #define logDoublezh(r,a) r=(StgDouble) RET_PRIM_STGCALL1(StgDouble,log,a)
389 #define sqrtDoublezh(r,a) r=(StgDouble) RET_PRIM_STGCALL1(StgDouble,sqrt,a)
390 #define sinDoublezh(r,a) r=(StgDouble) RET_PRIM_STGCALL1(StgDouble,sin,a)
391 #define cosDoublezh(r,a) r=(StgDouble) RET_PRIM_STGCALL1(StgDouble,cos,a)
392 #define tanDoublezh(r,a) r=(StgDouble) RET_PRIM_STGCALL1(StgDouble,tan,a)
393 #define asinDoublezh(r,a) r=(StgDouble) RET_PRIM_STGCALL1(StgDouble,asin,a)
394 #define acosDoublezh(r,a) r=(StgDouble) RET_PRIM_STGCALL1(StgDouble,acos,a)
395 #define atanDoublezh(r,a) r=(StgDouble) RET_PRIM_STGCALL1(StgDouble,atan,a)
396 #define sinhDoublezh(r,a) r=(StgDouble) RET_PRIM_STGCALL1(StgDouble,sinh,a)
397 #define coshDoublezh(r,a) r=(StgDouble) RET_PRIM_STGCALL1(StgDouble,cosh,a)
398 #define tanhDoublezh(r,a) r=(StgDouble) RET_PRIM_STGCALL1(StgDouble,tanh,a)
400 #define ztztzhzh(r,a,b) r=(StgDouble) RET_PRIM_STGCALL2(StgDouble,pow,a,b)
402 /* -----------------------------------------------------------------------------
404 -------------------------------------------------------------------------- */
406 /* We can do integer2Int and cmpInteger inline, since they don't need
407 * to allocate any memory.
409 * integer2Int# is now modular.
412 #define integer2Intzh(r, sa,da) \
413 { StgWord word0 = ((StgWord *)BYTE_ARR_CTS(da))[0]; \
419 ( size < 0 && word0 != 0x8000000 ) ? \
424 #define integer2Wordzh(r, sa,da) \
425 { StgWord word0 = ((StgWord *)BYTE_ARR_CTS(da))[0]; \
427 (r) = ( size == 0 ) ? 0 : word0 ; \
430 #define cmpIntegerzh(r, s1,d1, s2,d2) \
434 arg1._mp_size = (s1); \
435 arg1._mp_alloc= ((StgArrWords *)d1)->words; \
436 arg1._mp_d = (unsigned long int *) (BYTE_ARR_CTS(d1)); \
437 arg2._mp_size = (s2); \
438 arg2._mp_alloc= ((StgArrWords *)d2)->words; \
439 arg2._mp_d = (unsigned long int *) (BYTE_ARR_CTS(d2)); \
441 (r) = RET_PRIM_STGCALL2(I_,mpz_cmp,&arg1,&arg2); \
444 #define cmpIntegerIntzh(r, s,d, i) \
447 arg._mp_size = (s); \
448 arg._mp_alloc = ((StgArrWords *)d)->words; \
449 arg._mp_d = (unsigned long int *) (BYTE_ARR_CTS(d)); \
451 (r) = RET_PRIM_STGCALL2(I_,mpz_cmp_si,&arg,i); \
454 /* NOTE: gcdIntzh and gcdIntegerIntzh work only for positive inputs! */
456 /* mp_limb_t must be able to hold an StgInt for this to work properly */
457 #define gcdIntzh(r,a,b) \
458 { mp_limb_t aa = (mp_limb_t)(a); \
459 r = RET_STGCALL3(StgInt, mpn_gcd_1, (mp_limb_t *)(&aa), 1, (mp_limb_t)(b)); \
462 #define gcdIntegerIntzh(r,sa,a,b) \
463 r = RET_STGCALL3(StgInt, mpn_gcd_1, (mp_limb_t *)(BYTE_ARR_CTS(a)), sa, b)
465 /* The rest are all out-of-line: -------- */
467 /* Integer arithmetic */
468 EXTFUN_RTS(plusIntegerzh_fast);
469 EXTFUN_RTS(minusIntegerzh_fast);
470 EXTFUN_RTS(timesIntegerzh_fast);
471 EXTFUN_RTS(gcdIntegerzh_fast);
472 EXTFUN_RTS(quotRemIntegerzh_fast);
473 EXTFUN_RTS(quotIntegerzh_fast);
474 EXTFUN_RTS(remIntegerzh_fast);
475 EXTFUN_RTS(divExactIntegerzh_fast);
476 EXTFUN_RTS(divModIntegerzh_fast);
479 EXTFUN_RTS(int2Integerzh_fast);
480 EXTFUN_RTS(word2Integerzh_fast);
482 /* Floating-point decodings */
483 EXTFUN_RTS(decodeFloatzh_fast);
484 EXTFUN_RTS(decodeDoublezh_fast);
487 EXTFUN_RTS(andIntegerzh_fast);
488 EXTFUN_RTS(orIntegerzh_fast);
489 EXTFUN_RTS(xorIntegerzh_fast);
490 EXTFUN_RTS(complementIntegerzh_fast);
492 /* -----------------------------------------------------------------------------
494 -------------------------------------------------------------------------- */
496 #ifdef SUPPORT_LONG_LONGS
498 #define integerToWord64zh(r, sa,da) \
499 { unsigned long int* d; \
503 d = (unsigned long int *) (BYTE_ARR_CTS(da)); \
507 } else if ( s == 1) { \
510 res = (LW_)d[0] + (LW_)d[1] * 0x100000000ULL; \
515 #define integerToInt64zh(r, sa,da) \
516 { unsigned long int* d; \
520 d = (unsigned long int *) (BYTE_ARR_CTS(da)); \
524 } else if ( s == 1) { \
527 res = (LI_)d[0] + (LI_)d[1] * 0x100000000LL; \
536 EXTFUN_RTS(int64ToIntegerzh_fast);
537 EXTFUN_RTS(word64ToIntegerzh_fast);
539 /* The rest are (way!) out of line, implemented via C entry points.
541 I_ stg_gtWord64 (StgWord64, StgWord64);
542 I_ stg_geWord64 (StgWord64, StgWord64);
543 I_ stg_eqWord64 (StgWord64, StgWord64);
544 I_ stg_neWord64 (StgWord64, StgWord64);
545 I_ stg_ltWord64 (StgWord64, StgWord64);
546 I_ stg_leWord64 (StgWord64, StgWord64);
548 I_ stg_gtInt64 (StgInt64, StgInt64);
549 I_ stg_geInt64 (StgInt64, StgInt64);
550 I_ stg_eqInt64 (StgInt64, StgInt64);
551 I_ stg_neInt64 (StgInt64, StgInt64);
552 I_ stg_ltInt64 (StgInt64, StgInt64);
553 I_ stg_leInt64 (StgInt64, StgInt64);
555 LW_ stg_remWord64 (StgWord64, StgWord64);
556 LW_ stg_quotWord64 (StgWord64, StgWord64);
558 LI_ stg_remInt64 (StgInt64, StgInt64);
559 LI_ stg_quotInt64 (StgInt64, StgInt64);
560 LI_ stg_negateInt64 (StgInt64);
561 LI_ stg_plusInt64 (StgInt64, StgInt64);
562 LI_ stg_minusInt64 (StgInt64, StgInt64);
563 LI_ stg_timesInt64 (StgInt64, StgInt64);
565 LW_ stg_and64 (StgWord64, StgWord64);
566 LW_ stg_or64 (StgWord64, StgWord64);
567 LW_ stg_xor64 (StgWord64, StgWord64);
568 LW_ stg_not64 (StgWord64);
570 LW_ stg_shiftL64 (StgWord64, StgInt);
571 LW_ stg_shiftRL64 (StgWord64, StgInt);
572 LI_ stg_iShiftL64 (StgInt64, StgInt);
573 LI_ stg_iShiftRL64 (StgInt64, StgInt);
574 LI_ stg_iShiftRA64 (StgInt64, StgInt);
576 LI_ stg_intToInt64 (StgInt);
577 I_ stg_int64ToInt (StgInt64);
578 LW_ stg_int64ToWord64 (StgInt64);
580 LW_ stg_wordToWord64 (StgWord);
581 W_ stg_word64ToWord (StgWord64);
582 LI_ stg_word64ToInt64 (StgWord64);
585 /* -----------------------------------------------------------------------------
587 -------------------------------------------------------------------------- */
589 /* We cast to void* instead of StgChar* because this avoids a warning
590 * about increasing the alignment requirements.
592 #define REAL_BYTE_ARR_CTS(a) ((void *) (((StgArrWords *)(a))->payload))
593 #define REAL_PTRS_ARR_CTS(a) ((P_) (((StgMutArrPtrs *)(a))->payload))
596 #define BYTE_ARR_CTS(a) \
597 ({ ASSERT(GET_INFO((StgArrWords *)(a)) == &stg_ARR_WORDS_info); \
598 REAL_BYTE_ARR_CTS(a); })
599 #define PTRS_ARR_CTS(a) \
600 ({ ASSERT((GET_INFO((StgMutArrPtrs *)(a)) == &stg_MUT_ARR_PTRS_FROZEN_info) \
601 || (GET_INFO((StgMutArrPtrs *)(a)) == &stg_MUT_ARR_PTRS_info)); \
602 REAL_PTRS_ARR_CTS(a); })
604 #define BYTE_ARR_CTS(a) REAL_BYTE_ARR_CTS(a)
605 #define PTRS_ARR_CTS(a) REAL_PTRS_ARR_CTS(a)
608 extern I_ genSymZh(void);
609 extern I_ resetGenSymZh(void);
611 /*--- everything except new*Array is done inline: */
613 #define sameMutableArrayzh(r,a,b) r=(I_)((a)==(b))
614 #define sameMutableByteArrayzh(r,a,b) r=(I_)((a)==(b))
616 #define readArrayzh(r,a,i) r=((PP_) PTRS_ARR_CTS(a))[(i)]
618 #define readCharArrayzh(r,a,i) indexCharOffAddrzh(r,BYTE_ARR_CTS(a),i)
619 #define readIntArrayzh(r,a,i) indexIntOffAddrzh(r,BYTE_ARR_CTS(a),i)
620 #define readWordArrayzh(r,a,i) indexWordOffAddrzh(r,BYTE_ARR_CTS(a),i)
621 #define readAddrArrayzh(r,a,i) indexAddrOffAddrzh(r,BYTE_ARR_CTS(a),i)
622 #define readFloatArrayzh(r,a,i) indexFloatOffAddrzh(r,BYTE_ARR_CTS(a),i)
623 #define readDoubleArrayzh(r,a,i) indexDoubleOffAddrzh(r,BYTE_ARR_CTS(a),i)
624 #define readStablePtrArrayzh(r,a,i) indexStablePtrOffAddrzh(r,BYTE_ARR_CTS(a),i)
625 #define readInt8Arrayzh(r,a,i) indexInt8OffAddrzh(r,BYTE_ARR_CTS(a),i)
626 #define readInt16Arrayzh(r,a,i) indexInt16OffAddrzh(r,BYTE_ARR_CTS(a),i)
627 #define readInt32Arrayzh(r,a,i) indexInt32OffAddrzh(r,BYTE_ARR_CTS(a),i)
628 #define readWord8Arrayzh(r,a,i) indexWord8OffAddrzh(r,BYTE_ARR_CTS(a),i)
629 #define readWord16Arrayzh(r,a,i) indexWord16OffAddrzh(r,BYTE_ARR_CTS(a),i)
630 #define readWord32Arrayzh(r,a,i) indexWord32OffAddrzh(r,BYTE_ARR_CTS(a),i)
631 #ifdef SUPPORT_LONG_LONGS
632 #define readInt64Arrayzh(r,a,i) indexInt64OffAddrzh(r,BYTE_ARR_CTS(a),i)
633 #define readWord64Arrayzh(r,a,i) indexWord64OffAddrzh(r,BYTE_ARR_CTS(a),i)
636 /* result ("r") arg ignored in write macros! */
637 #define writeArrayzh(a,i,v) ((PP_) PTRS_ARR_CTS(a))[(i)]=(v)
639 #define writeCharArrayzh(a,i,v) ((unsigned char *)(BYTE_ARR_CTS(a)))[i] = (unsigned char)(v)
640 /* unsigned char is for compatibility: the index is still in bytes. */
641 #define writeIntArrayzh(a,i,v) ((I_ *)(BYTE_ARR_CTS(a)))[i] = (v)
642 #define writeWordArrayzh(a,i,v) ((W_ *)(BYTE_ARR_CTS(a)))[i] = (v)
643 #define writeAddrArrayzh(a,i,v) ((PP_)(BYTE_ARR_CTS(a)))[i] = (v)
644 #define writeFloatArrayzh(a,i,v) \
645 ASSIGN_FLT((P_) (((StgFloat *)(BYTE_ARR_CTS(a))) + i),v)
646 #define writeDoubleArrayzh(a,i,v) \
647 ASSIGN_DBL((P_) (((StgDouble *)(BYTE_ARR_CTS(a))) + i),v)
648 #define writeStablePtrArrayzh(a,i,v) ((StgStablePtr *)(BYTE_ARR_CTS(a)))[i] = (v)
649 #define writeInt8Arrayzh(a,i,v) ((StgInt8 *)(BYTE_ARR_CTS(a)))[i] = (v)
650 #define writeInt16Arrayzh(a,i,v) ((StgInt16 *)(BYTE_ARR_CTS(a)))[i] = (v)
651 #define writeInt32Arrayzh(a,i,v) ((StgInt32 *)(BYTE_ARR_CTS(a)))[i] = (v)
652 #define writeWord8Arrayzh(a,i,v) ((StgWord8 *)(BYTE_ARR_CTS(a)))[i] = (v)
653 #define writeWord16Arrayzh(a,i,v) ((StgWord16 *)(BYTE_ARR_CTS(a)))[i] = (v)
654 #define writeWord32Arrayzh(a,i,v) ((StgWord32 *)(BYTE_ARR_CTS(a)))[i] = (v)
655 #ifdef SUPPORT_LONG_LONGS
656 #define writeInt64Arrayzh(a,i,v) ((LI_ *)(BYTE_ARR_CTS(a)))[i] = (v)
657 #define writeWord64Arrayzh(a,i,v) ((LW_ *)(BYTE_ARR_CTS(a)))[i] = (v)
660 #define indexArrayzh(r,a,i) r=((PP_) PTRS_ARR_CTS(a))[(i)]
662 #define indexCharArrayzh(r,a,i) indexCharOffAddrzh(r,BYTE_ARR_CTS(a),i)
663 #define indexIntArrayzh(r,a,i) indexIntOffAddrzh(r,BYTE_ARR_CTS(a),i)
664 #define indexWordArrayzh(r,a,i) indexWordOffAddrzh(r,BYTE_ARR_CTS(a),i)
665 #define indexAddrArrayzh(r,a,i) indexAddrOffAddrzh(r,BYTE_ARR_CTS(a),i)
666 #define indexFloatArrayzh(r,a,i) indexFloatOffAddrzh(r,BYTE_ARR_CTS(a),i)
667 #define indexDoubleArrayzh(r,a,i) indexDoubleOffAddrzh(r,BYTE_ARR_CTS(a),i)
668 #define indexStablePtrArrayzh(r,a,i) indexStablePtrOffAddrzh(r,BYTE_ARR_CTS(a),i)
669 #define indexInt8Arrayzh(r,a,i) indexInt8OffAddrzh(r,BYTE_ARR_CTS(a),i)
670 #define indexInt16Arrayzh(r,a,i) indexInt16OffAddrzh(r,BYTE_ARR_CTS(a),i)
671 #define indexInt32Arrayzh(r,a,i) indexInt32OffAddrzh(r,BYTE_ARR_CTS(a),i)
672 #define indexWord8Arrayzh(r,a,i) indexWord8OffAddrzh(r,BYTE_ARR_CTS(a),i)
673 #define indexWord16Arrayzh(r,a,i) indexWord16OffAddrzh(r,BYTE_ARR_CTS(a),i)
674 #define indexWord32Arrayzh(r,a,i) indexWord32OffAddrzh(r,BYTE_ARR_CTS(a),i)
675 #ifdef SUPPORT_LONG_LONGS
676 #define indexInt64Arrayzh(r,a,i) indexInt64OffAddrzh(r,BYTE_ARR_CTS(a),i)
677 #define indexWord64Arrayzh(r,a,i) indexWord64OffAddrzh(r,BYTE_ARR_CTS(a),i)
680 /* Freezing arrays-of-ptrs requires changing an info table, for the
681 benefit of the generational collector. It needs to scavenge mutable
682 objects, even if they are in old space. When they become immutable,
683 they can be removed from this scavenge list. */
685 #define unsafeFreezzeArrayzh(r,a) \
687 SET_INFO((StgClosure *)a,&stg_MUT_ARR_PTRS_FROZEN_info); \
691 #define unsafeFreezzeByteArrayzh(r,a) r=(a)
693 EXTFUN_RTS(unsafeThawArrayzh_fast);
695 #define sizzeofByteArrayzh(r,a) \
696 r = (((StgArrWords *)(a))->words * sizeof(W_))
697 #define sizzeofMutableByteArrayzh(r,a) \
698 r = (((StgArrWords *)(a))->words * sizeof(W_))
700 /* and the out-of-line ones... */
702 EXTFUN_RTS(newByteArrayzh_fast);
703 EXTFUN_RTS(newArrayzh_fast);
705 /* encoding and decoding of floats/doubles. */
707 /* We only support IEEE floating point format */
708 #include "ieee-flpt.h"
710 /* The decode operations are out-of-line because they need to allocate
713 EXTFUN_RTS(decodeFloatzh_fast);
714 EXTFUN_RTS(decodeDoublezh_fast);
716 /* grimy low-level support functions defined in StgPrimFloat.c */
718 extern StgDouble __encodeDouble (I_ size, StgByteArray arr, I_ e);
719 extern StgDouble __int_encodeDouble (I_ j, I_ e);
720 extern StgFloat __encodeFloat (I_ size, StgByteArray arr, I_ e);
721 extern StgFloat __int_encodeFloat (I_ j, I_ e);
722 extern void __decodeDouble (MP_INT *man, I_ *_exp, StgDouble dbl);
723 extern void __decodeFloat (MP_INT *man, I_ *_exp, StgFloat flt);
724 extern StgInt isDoubleNaN(StgDouble d);
725 extern StgInt isDoubleInfinite(StgDouble d);
726 extern StgInt isDoubleDenormalized(StgDouble d);
727 extern StgInt isDoubleNegativeZero(StgDouble d);
728 extern StgInt isFloatNaN(StgFloat f);
729 extern StgInt isFloatInfinite(StgFloat f);
730 extern StgInt isFloatDenormalized(StgFloat f);
731 extern StgInt isFloatNegativeZero(StgFloat f);
733 /* -----------------------------------------------------------------------------
736 newMutVar is out of line.
737 -------------------------------------------------------------------------- */
739 EXTFUN_RTS(newMutVarzh_fast);
741 #define readMutVarzh(r,a) r=(P_)(((StgMutVar *)(a))->var)
742 #define writeMutVarzh(a,v) (P_)(((StgMutVar *)(a))->var)=(v)
743 #define sameMutVarzh(r,a,b) r=(I_)((a)==(b))
745 /* -----------------------------------------------------------------------------
748 All out of line, because they either allocate or may block.
749 -------------------------------------------------------------------------- */
750 #define sameMVarzh(r,a,b) r=(I_)((a)==(b))
752 /* Assume external decl of EMPTY_MVAR_info is in scope by now */
753 #define isEmptyMVarzh(r,a) r=(I_)((GET_INFO((StgMVar*)(a))) == &stg_EMPTY_MVAR_info )
754 EXTFUN_RTS(newMVarzh_fast);
755 EXTFUN_RTS(takeMVarzh_fast);
756 EXTFUN_RTS(tryTakeMVarzh_fast);
757 EXTFUN_RTS(putMVarzh_fast);
760 /* -----------------------------------------------------------------------------
762 -------------------------------------------------------------------------- */
764 EXTFUN_RTS(waitReadzh_fast);
765 EXTFUN_RTS(waitWritezh_fast);
766 EXTFUN_RTS(delayzh_fast);
768 /* -----------------------------------------------------------------------------
769 Primitive I/O, error-handling PrimOps
770 -------------------------------------------------------------------------- */
772 EXTFUN_RTS(catchzh_fast);
773 EXTFUN_RTS(raisezh_fast);
775 extern void stg_exit(I_ n) __attribute__ ((noreturn));
777 /* -----------------------------------------------------------------------------
778 Stable Name / Stable Pointer PrimOps
779 -------------------------------------------------------------------------- */
783 EXTFUN_RTS(makeStableNamezh_fast);
785 #define stableNameToIntzh(r,s) (r = ((StgStableName *)s)->sn)
787 #define eqStableNamezh(r,sn1,sn2) \
788 (r = (((StgStableName *)sn1)->sn == ((StgStableName *)sn2)->sn))
790 #define makeStablePtrzh(r,a) \
791 r = RET_STGCALL1(StgStablePtr,getStablePtr,a)
793 #define deRefStablePtrzh(r,sp) do { \
794 ASSERT(stable_ptr_table[stgCast(StgWord,sp) & ~STABLEPTR_WEIGHT_MASK].weight > 0); \
795 r = stable_ptr_table[stgCast(StgWord,sp) & ~STABLEPTR_WEIGHT_MASK].addr; \
798 #define eqStablePtrzh(r,sp1,sp2) \
799 (r = ((stgCast(StgWord,sp1) & ~STABLEPTR_WEIGHT_MASK) == (stgCast(StgWord,sp2) & ~STABLEPTR_WEIGHT_MASK)))
803 /* -----------------------------------------------------------------------------
804 Concurrency/Exception PrimOps.
805 -------------------------------------------------------------------------- */
807 EXTFUN_RTS(forkzh_fast);
808 EXTFUN_RTS(yieldzh_fast);
809 EXTFUN_RTS(killThreadzh_fast);
810 EXTFUN_RTS(seqzh_fast);
811 EXTFUN_RTS(blockAsyncExceptionszh_fast);
812 EXTFUN_RTS(unblockAsyncExceptionszh_fast);
814 #define myThreadIdzh(t) (t = CurrentTSO)
816 extern int cmp_thread(const StgTSO *tso1, const StgTSO *tso2);
818 /* ------------------------------------------------------------------------
821 A par in the Haskell code is ultimately translated to a parzh macro
822 (with a case wrapped around it to guarantee that the macro is actually
823 executed; see compiler/prelude/PrimOps.lhs)
824 In GUM and SMP we only add a pointer to the spark pool.
825 In GranSim we call an RTS fct, forwarding additional parameters which
826 supply info on granularity of the computation, size of the result value
827 and the degree of parallelism in the sparked expression.
828 ---------------------------------------------------------------------- */
832 #define parzh(r,node) PAR(r,node,1,0,0,0,0,0)
835 #define parAtzh(r,node,where,identifier,gran_info,size_info,par_info,rest) \
836 parAT(r,node,where,identifier,gran_info,size_info,par_info,rest,1)
839 #define parAtAbszh(r,node,proc,identifier,gran_info,size_info,par_info,rest) \
840 parAT(r,node,proc,identifier,gran_info,size_info,par_info,rest,2)
843 #define parAtRelzh(r,node,proc,identifier,gran_info,size_info,par_info,rest) \
844 parAT(r,node,proc,identifier,gran_info,size_info,par_info,rest,3)
846 //@cindex _parAtForNow_
847 #define parAtForNowzh(r,node,where,identifier,gran_info,size_info,par_info,rest) \
848 parAT(r,node,where,identifier,gran_info,size_info,par_info,rest,0)
850 #define parAT(r,node,where,identifier,gran_info,size_info,par_info,rest,local) \
852 if (closure_SHOULD_SPARK((StgClosure*)node)) { \
856 STGCALL6(newSpark, node,identifier,gran_info,size_info,par_info,local); \
858 case 2: p = where; /* parAtAbs means absolute PE no. expected */ \
860 case 3: p = CurrentProc+where; /* parAtRel means rel PE no. expected */\
862 default: p = where_is(where); /* parAt means closure expected */ \
865 /* update GranSim state according to this spark */ \
866 STGCALL3(GranSimSparkAtAbs, result, (I_)p, identifier); \
871 #define parLocalzh(r,node,identifier,gran_info,size_info,par_info,rest) \
872 PAR(r,node,rest,identifier,gran_info,size_info,par_info,1)
874 //@cindex _parGlobal_
875 #define parGlobalzh(r,node,identifier,gran_info,size_info,par_info,rest) \
876 PAR(r,node,rest,identifier,gran_info,size_info,par_info,0)
878 #define PAR(r,node,rest,identifier,gran_info,size_info,par_info,local) \
880 if (closure_SHOULD_SPARK((StgClosure*)node)) { \
882 result = RET_STGCALL6(rtsSpark*, newSpark, \
883 node,identifier,gran_info,size_info,par_info,local);\
884 STGCALL1(add_to_spark_queue,result); \
885 STGCALL2(GranSimSpark, local,(P_)node); \
889 #define copyablezh(r,node) \
890 /* copyable not yet implemented!! */
892 #define noFollowzh(r,node) \
893 /* noFollow not yet implemented!! */
895 #elif defined(SMP) || defined(PAR)
897 #define parzh(r,node) \
899 extern unsigned int context_switch; \
900 if (closure_SHOULD_SPARK((StgClosure *)node) && \
901 SparkTl < SparkLim) { \
902 *SparkTl++ = (StgClosure *)(node); \
904 r = context_switch = 1; \
906 #else /* !GRAN && !SMP && !PAR */
907 #define parzh(r,node) r = 1
910 /* -----------------------------------------------------------------------------
912 -------------------------------------------------------------------------- */
914 /* warning: extremely non-referentially transparent, need to hide in
915 an appropriate monad.
917 ToDo: follow indirections.
920 #define reallyUnsafePtrEqualityzh(r,a,b) r=((StgPtr)(a) == (StgPtr)(b))
922 /* -----------------------------------------------------------------------------
923 Weak Pointer PrimOps.
924 -------------------------------------------------------------------------- */
928 EXTFUN_RTS(mkWeakzh_fast);
929 EXTFUN_RTS(finalizzeWeakzh_fast);
931 #define deRefWeakzh(code,val,w) \
932 if (((StgWeak *)w)->header.info == &stg_WEAK_info) { \
934 val = (P_)((StgWeak *)w)->value; \
940 #define sameWeakzh(w1,w2) ((w1)==(w2))
944 /* -----------------------------------------------------------------------------
945 Foreign Object PrimOps.
946 -------------------------------------------------------------------------- */
950 #define ForeignObj_CLOSURE_DATA(c) (((StgForeignObj *)c)->data)
952 #define foreignObjToAddrzh(r,fo) r=ForeignObj_CLOSURE_DATA(fo)
953 #define touchzh(o) /* nothing */
955 EXTFUN_RTS(mkForeignObjzh_fast);
957 #define writeForeignObjzh(res,datum) \
958 (ForeignObj_CLOSURE_DATA(res) = (P_)(datum))
960 #define eqForeignObj(f1,f2) ((f1)==(f2))
962 #define indexCharOffForeignObjzh(r,fo,i) indexCharOffAddrzh(r,ForeignObj_CLOSURE_DATA(fo),i)
963 #define indexIntOffForeignObjzh(r,fo,i) indexIntOffAddrzh(r,ForeignObj_CLOSURE_DATA(fo),i)
964 #define indexWordOffForeignObjzh(r,fo,i) indexWordOffAddrzh(r,ForeignObj_CLOSURE_DATA(fo),i)
965 #define indexAddrOffForeignObjzh(r,fo,i) indexAddrOffAddrzh(r,ForeignObj_CLOSURE_DATA(fo),i)
966 #define indexFloatOffForeignObjzh(r,fo,i) indexFloatOffAddrzh(r,ForeignObj_CLOSURE_DATA(fo),i)
967 #define indexDoubleOffForeignObjzh(r,fo,i) indexDoubleOffAddrzh(r,ForeignObj_CLOSURE_DATA(fo),i)
968 #define indexStablePtrOffForeignObjzh(r,fo,i) indexStablePtrOffAddrzh(r,ForeignObj_CLOSURE_DATA(fo),i)
969 #define indexInt8OffForeignObjzh(r,fo,i) indexInt8OffAddrzh(r,ForeignObj_CLOSURE_DATA(fo),i)
970 #define indexInt16OffForeignObjzh(r,fo,i) indexInt16OffAddrzh(r,ForeignObj_CLOSURE_DATA(fo),i)
971 #define indexInt32OffForeignObjzh(r,fo,i) indexInt32OffAddrzh(r,ForeignObj_CLOSURE_DATA(fo),i)
972 #define indexWord8OffForeignObjzh(r,fo,i) indexWord8OffAddrzh(r,ForeignObj_CLOSURE_DATA(fo),i)
973 #define indexWord16OffForeignObjzh(r,fo,i) indexWord16OffAddrzh(r,ForeignObj_CLOSURE_DATA(fo),i)
974 #define indexWord32OffForeignObjzh(r,fo,i) indexWord32OffAddrzh(r,ForeignObj_CLOSURE_DATA(fo),i)
975 #ifdef SUPPORT_LONG_LONGS
976 #define indexInt64OffForeignObjzh(r,fo,i) indexInt64OffAddrzh(r,ForeignObj_CLOSURE_DATA(fo),i)
977 #define indexWord64OffForeignObjzh(r,fo,i) indexWord64OffAddrzh(r,ForeignObj_CLOSURE_DATA(fo),i)
983 /* -----------------------------------------------------------------------------
985 -------------------------------------------------------------------------- */
988 #define dataToTagzh(r,a) \
989 do { StgClosure* tmp = (StgClosure*)(a); \
990 CHASE_INDIRECTIONS(tmp); \
991 r = (GET_TAG(((StgClosure *)tmp)->header.info)); \
994 /* Original version doesn't chase indirections. */
995 #define dataToTagzh(r,a) r=(GET_TAG(((StgClosure *)a)->header.info))
998 /* tagToEnum# is handled directly by the code generator. */
1000 /* -----------------------------------------------------------------------------
1002 -------------------------------------------------------------------------- */
1004 EXTFUN_RTS(newBCOzh_fast);
1005 #define getBCOPtrszh(r,bco) r=((StgBCO *)bco)->ptrs
1007 /* -----------------------------------------------------------------------------
1008 Signal processing. Not really primops, but called directly from
1010 -------------------------------------------------------------------------- */
1012 #define STG_SIG_DFL (-1)
1013 #define STG_SIG_IGN (-2)
1014 #define STG_SIG_ERR (-3)
1015 #define STG_SIG_HAN (-4)
1017 extern StgInt sig_install (StgInt, StgInt, StgStablePtr, sigset_t *);
1018 #define stg_sig_default(sig,mask) sig_install(sig,STG_SIG_DFL,0,(sigset_t *)mask)
1019 #define stg_sig_ignore(sig,mask) sig_install(sig,STG_SIG_IGN,0,(sigset_t *)mask)
1020 #define stg_sig_catch(sig,ptr,mask) sig_install(sig,STG_SIG_HAN,ptr,(sigset_t *)mask)
1022 #endif /* PRIMOPS_H */