2 % (c) The GRASP/AQUA Project, Glasgow University, 1993-1994
4 \section[StgMacros]{C macros used in GHC-generated \tr{.hc} files}
11 %************************************************************************
13 \subsection[StgMacros-abbrev]{Abbreviatory(?) and general macros}
15 %************************************************************************
19 /* for function declarations */
20 #define STGFUN(f) F_ f(STG_NO_ARGS)
21 #define STATICFUN(f) static F_ f(STG_NO_ARGS)
23 /* for functions/data that are really external to this module */
24 #define EXTFUN(f) extern F_ f(STG_NO_ARGS)
25 #define EXTDATA(d) extern W_ d[]
26 #define EXTDATA_RO(d) extern const W_ d[] /* read-only */
28 /* for fwd decls to functions/data somewhere else in this module */
29 /* (identical for the mo') */
30 #define INTFUN(f) static F_ f(STG_NO_ARGS)
31 #define INTDATA(d) extern W_ d[]
32 #define INTDATA_RO(d) extern const W_ d[] /* read-only */
34 /* short forms of most of the above */
36 #define FN_(f) F_ f(STG_NO_ARGS)
37 #define IFN_(f) static F_ f(STG_NO_ARGS)
38 #define EF_(f) extern F_ f(STG_NO_ARGS)
39 #define ED_(d) extern W_ d[]
40 #define ED_RO_(d) extern const W_ d[] /* read-only */
41 #define IF_(f) static F_ f(STG_NO_ARGS)
43 /* GCC is uncooperative about the next one: */
44 /* But, the "extern" prevents initialisation... ADR */
46 #define ID_(d) extern W_ d[]
47 #define ID_RO_(d) extern const W_ d[] /* read-only */
49 #define ID_(d) static W_ d[]
50 #define ID_RO_(d) static const W_ d[] /* read-only */
54 General things; note: general-but-``machine-dependent'' macros are
55 given in \tr{StgMachDeps.lh}.
57 I_ STG_MAX PROTO((I_, I_)); /* GCC -Wall loves prototypes */
61 STG_MAX(I_ a, I_ b) { return((a >= b) ? a : b); }
62 /* NB: the naive #define macro version of STG_MAX
63 can lead to exponential CPP explosion, if you
64 have very-nested STG_MAXes.
68 Macros to combine two short words into a single
69 word and split such a word back into two.
71 Dependent on machine word size :-)
74 #define COMBINE_WORDS(word,short1,short2) \
76 ((packed_shorts *)&(word))->wu.s1 = short1; \
77 ((packed_shorts *)&(word))->wu.s2 = short2; \
80 #define SPLIT_WORD(word,short1,short2) \
82 short1 = ((packed_shorts *)&(word))->wu.s1; \
83 short2 = ((packed_shorts *)&(word))->wu.s2; \
88 %************************************************************************
90 \subsection[StgMacros-gen-stg]{General STGish macros}
92 %************************************************************************
94 Common sizes of vector-return tables.
96 Claim: don't need fwd decls for return pts in \tr{VECTBL*}, because
97 the AbsC flattener ensures that things come out sufficiently
101 #ifdef __STG_REV_TBLS__
102 #define UNVECTBL(staticp,label,a) /* nothing */
104 #define UNVECTBL(staticp,label,a) \
106 staticp const W_ label[] = { \
113 #if defined(USE_SPLIT_MARKERS)
114 #define __STG_SPLIT_MARKER(n) FN_(CAT2(__stg_split_marker,n)){ }
116 #define __STG_SPLIT_MARKER(n) /* nothing */
120 %************************************************************************
122 \subsection[StgMacros-exceptions]{Exception-checking macros}
124 %************************************************************************
126 Argument-satisfaction check, stack(s) overflow check, heap overflow
129 The @SUBTRACT(upper, lower)@ macros return a positive result in words
130 indicating the amount by which upper is above lower on the stack.
133 #define SUBTRACT_A_STK( upper, lower ) AREL( (lower) - (upper) )
134 #define SUBTRACT_B_STK( upper, lower ) BREL( (lower) - (upper) )
137 %************************************************************************
139 \subsubsection[StgMacros-arg-satis]{Argument-satisfaction checks}
141 %************************************************************************
143 @ARGS_CHK(n)@ sees of there are @n@ words of args on the A/B stack.
144 If not, it jumps to @UpdatePAP@.
146 @ARGS_CHK@ args are pre-directionified.
147 Notice that we do the comparisons in the form (x < a+n), for
148 some constant n. This generates more efficient code (with GCC at least)
152 #define ARGS_CHK_A(n) \
153 if (SuA /*SUBTRACT_A_STK( SpA, SuA )*/ < (SpA+(n))) { \
157 #define ARGS_CHK_A_LOAD_NODE(n, closure_addr) \
158 if (SuA /*SUBTRACT_A_STK( SpA, SuA )*/ < (SpA+(n))) { \
159 Node = (P_) closure_addr; \
163 #define ARGS_CHK_B(n) \
164 if (SpB /*SUBTRACT_B_STK( SpB, SuB )*/ < (SuB-(n))) { \
169 #define ARGS_CHK_B_LOAD_NODE(n, closure_addr) \
170 if (SpB /*SUBTRACT_B_STK( SpB, SuB )*/ < (SuB-(n))) { \
171 Node = (P_) closure_addr; \
176 %************************************************************************
178 \subsubsection[StgMacros-stk-chks]{Stack-overflow check}
180 %************************************************************************
182 @STK_CHK(a,b)@ [misc args omitted...] checks that we can allocate @a@
183 words of A stack and @b@ words of B stack. If not, it calls
184 @StackOverflow@ (which dies).
186 (It will be different in the parallel case.)
188 NB: args @a@ and @b@ are pre-direction-ified!
190 I_ SqueezeUpdateFrames PROTO((P_, P_, P_));
191 int sanityChk_StkO (P_ stko); /* ToDo: move to a sane place */
193 #if ! defined(CONCURRENT)
195 extern void StackOverflow(STG_NO_ARGS) STG_NORETURN;
197 #if STACK_CHECK_BY_PAGE_FAULT
199 #define STACK_OVERFLOW(liveness,hda,hdb,spa,spb,rtype,reenter) \
200 /* use memory protection instead; still need ticky-ness */
204 #define STACK_OVERFLOW(liveness,hda,hdb,spa,spb,rtype,reenter) \
205 ULTRASAFESTGCALL0(void,(void *),StackOverflow)
207 #endif /* not using page-faulting */
211 I_ StackOverflow PROTO((W_, W_));
214 * On a uniprocessor, we do *NOT* context switch on a stack overflow
215 * (though we may GC). Therefore, we never have to reenter node.
218 #define STACK_OVERFLOW(liveness,hda,hdb,spa,spb,rtype,reenter) \
219 DO_STACKOVERFLOW((hda+hdb)<<2|((rtype)<<1)|(reenter),((spa)<<20)|((spb)<<8)|(liveness))
221 #define STACK_OVERFLOW_HEADROOM(args,y) ((args) >> 2)
222 #define STACK_OVERFLOW_PRIM_RETURN(args,y) ((args) & 2)
223 #define STACK_OVERFLOW_REENTER(args,y) ((args) & 1)
225 #define STACK_OVERFLOW_AWORDS(x,args) (((args) >> 20) & 0x0fff)
226 #define STACK_OVERFLOW_BWORDS(x,args) (((args) >> 8) & 0x0fff)
227 #define STACK_OVERFLOW_LIVENESS(x,args) ((args) & 0xff)
229 #endif /* CONCURRENT */
231 #define STK_CHK(liveness_mask,a_headroom,b_headroom,spa,spb,ret_type,reenter)\
233 DO_ASTK_HWM(); /* ticky-ticky profiling */ \
235 if (STKS_OVERFLOW_OP(((a_headroom) + 1), ((b_headroom) + 1))) { \
236 STACK_OVERFLOW(liveness_mask,a_headroom,b_headroom,spa,spb,ret_type,reenter);\
241 %************************************************************************
243 \subsubsection[StgMacros-heap-chks]{Heap-overflow checks}
245 %************************************************************************
247 Please see the general discussion/commentary about ``what really
248 happens in a GC,'' in \tr{SMinterface.lh}.
251 void PerformGC PROTO((W_));
252 void RealPerformGC PROTO((W_ liveness, W_ reqsize, W_ always_reenter_node, rtsBool do_full_collection));
253 void checkInCCallGC(STG_NO_ARGS);
256 void StgPerformGarbageCollection(STG_NO_ARGS);
261 #define OR_MSG_PENDING /* never */
263 #define HEAP_OVERFLOW(liveness,n,reenter) \
265 DO_GC((((W_)n)<<8)|(liveness)); \
268 #define REQSIZE_BITMASK ((1L << ((BITS_IN(W_) - 8 + 1))) - 1)
269 #define HEAP_OVERFLOW_REQSIZE(args) (((args) >> 8) & REQSIZE_BITMASK)
270 #define HEAP_OVERFLOW_REENTER(args) 0
271 #define HEAP_OVERFLOW_LIVENESS(args) ((args) & 0xff)
273 #else /* CONCURRENT */
275 void ReallyPerformThreadGC PROTO((W_, rtsBool));
277 #define HEAP_OVERFLOW(liveness,n,reenter) \
279 DO_GC((((W_)(n))<<9)|((reenter)<<8)|(liveness)); \
282 #define REQSIZE_BITMASK ((1L << ((BITS_IN(W_) - 9 + 1))) - 1)
283 #define HEAP_OVERFLOW_REQSIZE(args) (((args) >> 9) & REQSIZE_BITMASK)
284 #define HEAP_OVERFLOW_REENTER(args) (((args) >> 8) & 0x1)
285 #define HEAP_OVERFLOW_LIVENESS(args) ((args) & 0xff)
289 #define OR_MSG_PENDING /* never */
293 extern int PacketsWaiting; /*Probes for incoming messages*/
294 extern int heapChkCounter; /*Not currently used! We check for messages when*/
295 /*a thread is resheduled PWT*/
296 /* #define OR_MSG_PENDING || (--heapChkCounter == 0 && PacketsWaiting())*/
297 #define OR_MSG_PENDING /* never */
300 #endif /* CONCURRENT */
302 #if 0 /* alpha_TARGET_ARCH */
303 #define CACHE_LINE 4 /* words */
304 #define LINES_AHEAD 3
305 #define PRE_FETCH(n) \
308 j = ((STG_VOLATILE StgInt *) Hp)[LINES_AHEAD * CACHE_LINE]; \
310 #define EXTRA_HEAP_WORDS (CACHE_LINE * LINES_AHEAD)
312 #define PRE_FETCH(reg)
313 #define EXTRA_HEAP_WORDS 0
317 #define HEAP_CHK(liveness_mask,n,reenter) \
319 /* TICKY_PARANOIA(__FILE__, __LINE__); */ \
320 /* THREAD_CONTEXT_SWITCH(liveness_mask,reenter); */ \
321 ALLOC_HEAP(n); /* ticky profiling */ \
322 GRAN_ALLOC_HEAP(n,liveness_mask); /* Granularity Simulation */ \
323 if (((Hp = Hp + (n)) > HpLim)) { \
324 /* Old: STGCALL3_GC(PerformGC,liveness_mask,n,StgFalse); */\
325 HEAP_OVERFLOW(liveness_mask,n,StgFalse); \
330 #define HEAP_CHK(liveness_mask,n,reenter) \
332 /* TICKY_PARANOIA(__FILE__, __LINE__); */ \
334 ALLOC_HEAP(n); /* ticky profiling */ \
335 if (((Hp = Hp + (n)) > HpLim) OR_INTERVAL_EXPIRED OR_CONTEXT_SWITCH OR_MSG_PENDING) { \
336 HEAP_OVERFLOW(liveness_mask,n,reenter); \
344 #define HEAP_CHK_AND_RESTORE_N(liveness_mask,n,reenter) \
346 /* TICKY_PARANOIA(__FILE__, __LINE__); */ \
348 ALLOC_HEAP(n); /* ticky profiling */ \
349 if (((Hp = Hp + (n)) > HpLim) OR_INTERVAL_EXPIRED OR_CONTEXT_SWITCH OR_MSG_PENDING) { \
350 HEAP_OVERFLOW(liveness_mask,n,reenter); \
351 n = TSO_ARG1(CurrentTSO); \
356 #define HEAP_CHK_AND_RESTORE_N(liveness_mask,n,reenter) \
357 HEAP_CHK(liveness_mask,n,reenter)
364 %************************************************************************
366 \subsection[StgMacros-prim-ops]{Primitive operations}
368 %************************************************************************
370 One thing to be {\em very careful about} with these macros that assign
371 to results is that the assignment must come {\em last}. Some of the
372 other arguments may be in terms of addressing modes that get clobbered
373 by the assignment. (Dirty imperative programming RULES!)
375 The order here is roughly that in \tr{compiler/prelude/PrimOps.lhs}.
377 %************************************************************************
379 \subsubsection[StgMacros-compare-primops]{Primitive comparison ops on basic types}
381 %************************************************************************
383 We cast the chars in case one of them is a literal (so C things work right
384 even for 8-bit chars).
386 #define gtCharZh(r,a,b) r=(I_)((a)> (b))
387 #define geCharZh(r,a,b) r=(I_)((a)>=(b))
388 #define eqCharZh(r,a,b) r=(I_)((a)==(b))
389 #define neCharZh(r,a,b) r=(I_)((a)!=(b))
390 #define ltCharZh(r,a,b) r=(I_)((a)< (b))
391 #define leCharZh(r,a,b) r=(I_)((a)<=(b))
393 /* Int comparisons: >#, >=# etc */
394 #define ZgZh(r,a,b) r=(I_)((a) >(b))
395 #define ZgZeZh(r,a,b) r=(I_)((a)>=(b))
396 #define ZeZeZh(r,a,b) r=(I_)((a)==(b))
397 #define ZdZeZh(r,a,b) r=(I_)((a)!=(b))
398 #define ZlZh(r,a,b) r=(I_)((a) <(b))
399 #define ZlZeZh(r,a,b) r=(I_)((a)<=(b))
401 #define gtWordZh(r,a,b) r=(I_)((a) >(b))
402 #define geWordZh(r,a,b) r=(I_)((a)>=(b))
403 #define eqWordZh(r,a,b) r=(I_)((a)==(b))
404 #define neWordZh(r,a,b) r=(I_)((a)!=(b))
405 #define ltWordZh(r,a,b) r=(I_)((a) <(b))
406 #define leWordZh(r,a,b) r=(I_)((a)<=(b))
408 #define gtAddrZh(r,a,b) r=(I_)((a) >(b))
409 #define geAddrZh(r,a,b) r=(I_)((a)>=(b))
410 #define eqAddrZh(r,a,b) r=(I_)((a)==(b))
411 #define neAddrZh(r,a,b) r=(I_)((a)!=(b))
412 #define ltAddrZh(r,a,b) r=(I_)((a) <(b))
413 #define leAddrZh(r,a,b) r=(I_)((a)<=(b))
415 #define gtFloatZh(r,a,b) r=(I_)((a)> (b))
416 #define geFloatZh(r,a,b) r=(I_)((a)>=(b))
417 #define eqFloatZh(r,a,b) r=(I_)((a)==(b))
418 #define neFloatZh(r,a,b) r=(I_)((a)!=(b))
419 #define ltFloatZh(r,a,b) r=(I_)((a)< (b))
420 #define leFloatZh(r,a,b) r=(I_)((a)<=(b))
422 /* Double comparisons: >##, >=#@ etc */
423 #define ZgZhZh(r,a,b) r=(I_)((a) >(b))
424 #define ZgZeZhZh(r,a,b) r=(I_)((a)>=(b))
425 #define ZeZeZhZh(r,a,b) r=(I_)((a)==(b))
426 #define ZdZeZhZh(r,a,b) r=(I_)((a)!=(b))
427 #define ZlZhZh(r,a,b) r=(I_)((a) <(b))
428 #define ZlZeZhZh(r,a,b) r=(I_)((a)<=(b))
431 %************************************************************************
433 \subsubsection[StgMacros-char-primops]{Primitive @Char#@ ops (and @LitString#@ish things, too)}
435 %************************************************************************
437 We cast the chars in case one of them is a literal (so C things work right
438 even for 8-bit chars).
440 #define ordZh(r,a) r=(I_)((W_) (a))
441 #define chrZh(r,a) r=(StgChar)((W_)(a))
444 %************************************************************************
446 \subsubsection[StgMacros-int-primops]{Primitive @Int#@ ops}
448 %************************************************************************
451 I_ stg_div PROTO((I_ a, I_ b));
453 #define ZpZh(r,a,b) r=(a)+(b)
454 #define ZmZh(r,a,b) r=(a)-(b)
455 #define ZtZh(r,a,b) r=(a)*(b)
456 #define quotIntZh(r,a,b) r=(a)/(b)
457 /* ZdZh not used??? --SDM */
458 #define ZdZh(r,a,b) r=ULTRASAFESTGCALL2(I_,(void *, I_, I_),stg_div,(a),(b))
459 #define remIntZh(r,a,b) r=(a)%(b)
460 #define negateIntZh(r,a) r=-(a)
462 /* Ever used ? -- SOF */
463 #define absIntZh(a) r=(( (a) >= 0 ) ? (a) : (-(a)))
466 %************************************************************************
468 \subsubsection[StgMacros-word-primops]{Primitive @Word#@ ops}
470 %************************************************************************
473 #define quotWordZh(r,a,b) r=((W_)a)/((W_)b)
474 #define remWordZh(r,a,b) r=((W_)a)%((W_)b)
476 #define andZh(r,a,b) r=(a)&(b)
477 #define orZh(r,a,b) r=(a)|(b)
478 #define xorZh(r,a,b) r=(a)^(b)
479 #define notZh(r,a) r=~(a)
481 #define shiftLZh(r,a,b) r=(a)<<(b)
482 #define shiftRLZh(r,a,b) r=(a)>>(b)
483 #define iShiftLZh(r,a,b) r=(a)<<(b)
484 /* Right shifting of signed quantities is not portable in C, so
485 the behaviour you'll get from using these primops depends
486 on the whatever your C compiler is doing. ToDo: fix. -- sof 8/98
488 #define iShiftRAZh(r,a,b) r=(a)>>(b)
489 #define iShiftRLZh(r,a,b) r=(a)>>(b)
491 #define int2WordZh(r,a) r=(W_)(a)
492 #define word2IntZh(r,a) r=(I_)(a)
496 %************************************************************************
498 \subsubsection[StgMacros-addr-primops]{Primitive @Addr#@ ops}
500 %************************************************************************
503 #define int2AddrZh(r,a) r=(A_)(a)
504 #define addr2IntZh(r,a) r=(I_)(a)
507 %************************************************************************
509 \subsubsection[StgMacros-float-primops]{Primitive @Float#@ ops}
511 %************************************************************************
514 #define plusFloatZh(r,a,b) r=(a)+(b)
515 #define minusFloatZh(r,a,b) r=(a)-(b)
516 #define timesFloatZh(r,a,b) r=(a)*(b)
517 #define divideFloatZh(r,a,b) r=(a)/(b)
518 #define negateFloatZh(r,a) r=-(a)
520 #define int2FloatZh(r,a) r=(StgFloat)(a)
521 #define float2IntZh(r,a) r=(I_)(a)
523 #define expFloatZh(r,a) r=(StgFloat) SAFESTGCALL1(StgDouble,(void *, StgDouble),exp,a)
524 #define logFloatZh(r,a) r=(StgFloat) SAFESTGCALL1(StgDouble,(void *, StgDouble),log,a)
525 #define sqrtFloatZh(r,a) r=(StgFloat) SAFESTGCALL1(StgDouble,(void *, StgDouble),sqrt,a)
526 #define sinFloatZh(r,a) r=(StgFloat) SAFESTGCALL1(StgDouble,(void *, StgDouble),sin,a)
527 #define cosFloatZh(r,a) r=(StgFloat) SAFESTGCALL1(StgDouble,(void *, StgDouble),cos,a)
528 #define tanFloatZh(r,a) r=(StgFloat) SAFESTGCALL1(StgDouble,(void *, StgDouble),tan,a)
529 #define asinFloatZh(r,a) r=(StgFloat) SAFESTGCALL1(StgDouble,(void *, StgDouble),asin,a)
530 #define acosFloatZh(r,a) r=(StgFloat) SAFESTGCALL1(StgDouble,(void *, StgDouble),acos,a)
531 #define atanFloatZh(r,a) r=(StgFloat) SAFESTGCALL1(StgDouble,(void *, StgDouble),atan,a)
532 #define sinhFloatZh(r,a) r=(StgFloat) SAFESTGCALL1(StgDouble,(void *, StgDouble),sinh,a)
533 #define coshFloatZh(r,a) r=(StgFloat) SAFESTGCALL1(StgDouble,(void *, StgDouble),cosh,a)
534 #define tanhFloatZh(r,a) r=(StgFloat) SAFESTGCALL1(StgDouble,(void *, StgDouble),tanh,a)
535 #define powerFloatZh(r,a,b) r=(StgFloat) SAFESTGCALL2(StgDouble,(void *, StgDouble,StgDouble),pow,a,b)
537 /* encoding/decoding given w/ Integer stuff */
540 %************************************************************************
542 \subsubsection[StgMacros-double-primops]{Primitive @Double#@ ops}
544 %************************************************************************
547 #define ZpZhZh(r,a,b) r=(a)+(b)
548 #define ZmZhZh(r,a,b) r=(a)-(b)
549 #define ZtZhZh(r,a,b) r=(a)*(b)
550 #define ZdZhZh(r,a,b) r=(a)/(b)
551 #define negateDoubleZh(r,a) r=-(a)
553 #define int2DoubleZh(r,a) r=(StgDouble)(a)
554 #define double2IntZh(r,a) r=(I_)(a)
556 #define float2DoubleZh(r,a) r=(StgDouble)(a)
557 #define double2FloatZh(r,a) r=(StgFloat)(a)
559 #define expDoubleZh(r,a) r=(StgDouble) SAFESTGCALL1(StgDouble,(void *, StgDouble),exp,a)
560 #define logDoubleZh(r,a) r=(StgDouble) SAFESTGCALL1(StgDouble,(void *, StgDouble),log,a)
561 #define sqrtDoubleZh(r,a) r=(StgDouble) SAFESTGCALL1(StgDouble,(void *, StgDouble),sqrt,a)
562 #define sinDoubleZh(r,a) r=(StgDouble) SAFESTGCALL1(StgDouble,(void *, StgDouble),sin,a)
563 #define cosDoubleZh(r,a) r=(StgDouble) SAFESTGCALL1(StgDouble,(void *, StgDouble),cos,a)
564 #define tanDoubleZh(r,a) r=(StgDouble) SAFESTGCALL1(StgDouble,(void *, StgDouble),tan,a)
565 #define asinDoubleZh(r,a) r=(StgDouble) SAFESTGCALL1(StgDouble,(void *, StgDouble),asin,a)
566 #define acosDoubleZh(r,a) r=(StgDouble) SAFESTGCALL1(StgDouble,(void *, StgDouble),acos,a)
567 #define atanDoubleZh(r,a) r=(StgDouble) SAFESTGCALL1(StgDouble,(void *, StgDouble),atan,a)
568 #define sinhDoubleZh(r,a) r=(StgDouble) SAFESTGCALL1(StgDouble,(void *, StgDouble),sinh,a)
569 #define coshDoubleZh(r,a) r=(StgDouble) SAFESTGCALL1(StgDouble,(void *, StgDouble),cosh,a)
570 #define tanhDoubleZh(r,a) r=(StgDouble) SAFESTGCALL1(StgDouble,(void *, StgDouble),tanh,a)
572 #define ZtZtZhZh(r,a,b) r=(StgDouble) SAFESTGCALL2(StgDouble,(void *, StgDouble,StgDouble),pow,a,b)
576 %************************************************************************
578 \subsubsection[StgMacros-64-primops]{Primitive @Int64#@ and @Word64#@ ops}
580 %************************************************************************
582 Apart from the Integer casting primops, all primops over 64-bit (i.e., long long)
583 @Int64#@ and @Word64#@s are defined out-of-line. We just give the prototype
584 of these primops here:
587 #ifdef HAVE_LONG_LONG
588 I_ stg_gtWord64 PROTO((StgWord64, StgWord64));
589 I_ stg_geWord64 PROTO((StgWord64, StgWord64));
590 I_ stg_eqWord64 PROTO((StgWord64, StgWord64));
591 I_ stg_neWord64 PROTO((StgWord64, StgWord64));
592 I_ stg_ltWord64 PROTO((StgWord64, StgWord64));
593 I_ stg_leWord64 PROTO((StgWord64, StgWord64));
595 I_ stg_gtInt64 PROTO((StgInt64, StgInt64));
596 I_ stg_geInt64 PROTO((StgInt64, StgInt64));
597 I_ stg_eqInt64 PROTO((StgInt64, StgInt64));
598 I_ stg_neInt64 PROTO((StgInt64, StgInt64));
599 I_ stg_ltInt64 PROTO((StgInt64, StgInt64));
600 I_ stg_leInt64 PROTO((StgInt64, StgInt64));
602 LW_ stg_remWord64 PROTO((StgWord64, StgWord64));
603 LW_ stg_quotWord64 PROTO((StgWord64, StgWord64));
605 LI_ stg_remInt64 PROTO((StgInt64, StgInt64));
606 LI_ stg_quotInt64 PROTO((StgInt64, StgInt64));
607 LI_ stg_negateInt64 PROTO((StgInt64));
608 LI_ stg_plusInt64 PROTO((StgInt64, StgInt64));
609 LI_ stg_minusInt64 PROTO((StgInt64, StgInt64));
610 LI_ stg_timesInt64 PROTO((StgInt64, StgInt64));
612 LW_ stg_and64 PROTO((StgWord64, StgWord64));
613 LW_ stg_or64 PROTO((StgWord64, StgWord64));
614 LW_ stg_xor64 PROTO((StgWord64, StgWord64));
615 LW_ stg_not64 PROTO((StgWord64));
617 LW_ stg_shiftL64 PROTO((StgWord64, StgInt));
618 LW_ stg_shiftRL64 PROTO((StgWord64, StgInt));
619 LI_ stg_iShiftL64 PROTO((StgInt64, StgInt));
620 LI_ stg_iShiftRL64 PROTO((StgInt64, StgInt));
621 LI_ stg_iShiftRA64 PROTO((StgInt64, StgInt));
623 LI_ stg_intToInt64 PROTO((StgInt));
624 I_ stg_int64ToInt PROTO((StgInt64));
625 LW_ stg_int64ToWord64 PROTO((StgInt64));
627 LW_ stg_wordToWord64 PROTO((StgWord));
628 W_ stg_word64ToWord PROTO((StgWord64));
629 LI_ stg_word64ToInt64 PROTO((StgWord64));
634 %************************************************************************
636 \subsubsection[StgMacros-integer-primops]{Primitive @Integer@-related ops (GMP stuff)}
638 %************************************************************************
640 Dirty macros we use for the real business.
642 INVARIANT: When one of these macros is called, the only live data is
643 tidily on the STG stacks or in the STG registers (the code generator
644 ensures this). If there are any pointer-arguments, they will be in
645 the first \tr{Ret*} registers (e.g., \tr{da} arg of \tr{gmpTake1Return1}).
647 OK, here are the real macros:
649 #define gmpTake1Return1(size_chk_macro, liveness, mpz_op, ar,sr,dr, aa,sa,da) \
652 I_ space = size_chk_macro(sa); \
654 /* Check that there will be enough heap & make Hp visible to GMP allocator */ \
655 GMP_HEAP_LOOKAHEAD(liveness,space); \
657 /* Now we can initialise (post possible GC) */ \
660 arg.d = (unsigned long int *) (BYTE_ARR_CTS(da)); \
662 SAFESTGCALL1(void,(void *, MP_INT *),mpz_init,&result); \
664 /* Perform the operation */ \
665 SAFESTGCALL2(void,(void *, MP_INT *, MP_INT *),mpz_op,&result,&arg); \
667 GMP_HEAP_HANDBACK(); /* restore Hp */ \
668 (ar) = result.alloc; \
669 (sr) = result.size; \
670 (dr) = (B_) (result.d - DATA_HS); \
671 /* pt to *beginning* of object (GMP has been monkeying around in the middle) */ \
675 #define gmpTake2Return1(size_chk_macro, liveness, mpz_op, ar,sr,dr, a1,s1,d1, a2,s2,d2)\
679 I_ space = size_chk_macro(s1,s2); \
681 /* Check that there will be enough heap & make Hp visible to GMP allocator */ \
682 GMP_HEAP_LOOKAHEAD(liveness,space); \
684 /* Now we can initialise (post possible GC) */ \
687 arg1.d = (unsigned long int *) (BYTE_ARR_CTS(d1)); \
690 arg2.d = (unsigned long int *) (BYTE_ARR_CTS(d2)); \
692 SAFESTGCALL1(void,(void *, MP_INT *),mpz_init,&result); \
694 /* Perform the operation */ \
695 SAFESTGCALL3(void,(void *, MP_INT *, MP_INT *, MP_INT *),mpz_op,&result,&arg1,&arg2); \
697 GMP_HEAP_HANDBACK(); /* restore Hp */ \
698 (ar) = result.alloc; \
699 (sr) = result.size; \
700 (dr) = (B_) (result.d - DATA_HS); \
701 /* pt to *beginning* of object (GMP has been monkeying around in the middle) */ \
704 #define gmpTake2Return2(size_chk_macro, liveness, mpz_op, ar1,sr1,dr1, ar2,sr2,dr2, a1,s1,d1, a2,s2,d2) \
709 I_ space = size_chk_macro(s1,s2); \
711 /* Check that there will be enough heap & make Hp visible to GMP allocator */ \
712 GMP_HEAP_LOOKAHEAD(liveness,space); \
714 /* Now we can initialise (post possible GC) */ \
717 arg1.d = (unsigned long int *) (BYTE_ARR_CTS(d1)); \
720 arg2.d = (unsigned long int *) (BYTE_ARR_CTS(d2)); \
722 SAFESTGCALL1(void,(void *, MP_INT *),mpz_init,&result1); \
723 SAFESTGCALL1(void,(void *, MP_INT *),mpz_init,&result2); \
725 /* Perform the operation */ \
726 SAFESTGCALL4(void,(void *, MP_INT *, MP_INT *, MP_INT *, MP_INT *),mpz_op,&result1,&result2,&arg1,&arg2); \
728 GMP_HEAP_HANDBACK(); /* restore Hp */ \
729 (ar1) = result1.alloc; \
730 (sr1) = result1.size; \
731 (dr1) = (B_) (result1.d - DATA_HS); \
732 (ar2) = result2.alloc; \
733 (sr2) = result2.size; \
734 (dr2) = (B_) (result2.d - DATA_HS); \
738 Some handy size-munging macros: sometimes gratuitously {\em conservative}.
739 The \tr{+16} is to allow for the initial allocation of \tr{MP_INT} results.
740 The \tr{__abs} stuff is because negative-ness of GMP things is encoded
743 #define __abs(a) (( (a) >= 0 ) ? (a) : (-(a)))
744 #define GMP_SIZE_ONE() (2 + DATA_HS + 16)
745 #define GMP_SAME_SIZE(a) (__abs(a) + DATA_HS + 16)
746 #define GMP_MAX_SIZE(a,b) ((__abs(a) > __abs(b) ? __abs(a) : __abs(b)) + 1 + DATA_HS + 16)
747 /* NB: the +1 is for the carry (or whatever) */
748 #define GMP_2MAX_SIZE(a,b) (2 * GMP_MAX_SIZE(a,b))
749 #define GMP_ADD_SIZES(a,b) (__abs(a) + __abs(b) + 1 + DATA_HS + 16)
750 /* the +1 may just be paranoia */
753 For the Integer/GMP stuff, we have macros that {\em look ahead} for
754 some space, but don't actually grab it.
756 If there are live pointers at the time of the lookahead, the caller
757 must make sure they are in \tr{Ret1}, \tr{Ret2}, ..., so they can be
758 handled normally. We achieve this by having the code generator {\em
759 always} pass args to may-invoke-GC primitives in registers, using the
760 normal pointers-first policy. This means that, if we do go to garbage
761 collection, everything is already in the Right Place.
763 Saving and restoring Hp register so the MP allocator can see them. If we are
764 performing liftime profiling need to save and restore HpLim as well so that
765 it can be bumped if allocation occurs.
767 The second argument to @GMP_HEAP_LOOKAHEAD@ must be an lvalue so that
768 it can be restored from @TSO_ARG1@ after a failed @HEAP_CHK@ in
772 #define GMP_HEAP_LOOKAHEAD(liveness,n) \
774 HEAP_CHK_AND_RESTORE_N(liveness,n,0); \
776 UN_ALLOC_HEAP(n); /* Undo ticky-ticky */ \
777 SAVE_Hp = Hp; /* Hand over the hp */ \
778 DEBUG_SetGMPAllocBudget(n) \
781 #define GMP_HEAP_HANDBACK() \
783 DEBUG_ResetGMPAllocBudget()
787 void *stgAllocForGMP PROTO((size_t size_in_bytes));
788 void *stgReallocForGMP PROTO((void *ptr, size_t old_size, size_t new_size));
789 void stgDeallocForGMP PROTO((void *ptr, size_t size));
792 extern StgInt DEBUG_GMPAllocBudget;
793 #define DEBUG_SetGMPAllocBudget(n) DEBUG_GMPAllocBudget = (n);
794 #define DEBUG_ResetGMPAllocBudget() DEBUG_GMPAllocBudget = 0;
796 #define DEBUG_SetGMPAllocBudget(n) /*nothing*/
797 #define DEBUG_ResetGMPAllocBudget() /*nothing*/
801 The real business (defining Integer primops):
803 #define negateIntegerZh(ar,sr,dr, liveness, aa,sa,da) \
804 gmpTake1Return1(GMP_SAME_SIZE, liveness, mpz_neg, ar,sr,dr, aa,sa,da)
806 #define plusIntegerZh(ar,sr,dr, liveness, a1,s1,d1, a2,s2,d2) \
807 gmpTake2Return1(GMP_MAX_SIZE, liveness, mpz_add, ar,sr,dr, a1,s1,d1, a2,s2,d2)
808 #define minusIntegerZh(ar,sr,dr, liveness, a1,s1,d1, a2,s2,d2) \
809 gmpTake2Return1(GMP_MAX_SIZE, liveness, mpz_sub, ar,sr,dr, a1,s1,d1, a2,s2,d2)
810 #define timesIntegerZh(ar,sr,dr, liveness, a1,s1,d1, a2,s2,d2) \
811 gmpTake2Return1(GMP_ADD_SIZES, liveness, mpz_mul, ar,sr,dr, a1,s1,d1, a2,s2,d2)
813 /* div, mod, quot, rem are defined w/ quotRem & divMod */
815 #define quotRemIntegerZh(ar1,sr1,dr1, ar2,sr2,dr2, liveness, a1,s1,d1, a2,s2,d2) \
816 gmpTake2Return2(GMP_2MAX_SIZE, liveness, mpz_divmod, ar1,sr1,dr1, ar2,sr2,dr2, a1,s1,d1, a2,s2,d2)
817 #define divModIntegerZh(ar1,sr1,dr1, ar2,sr2,dr2, liveness, a1,s1,d1, a2,s2,d2) \
818 gmpTake2Return2(GMP_2MAX_SIZE, liveness, mpz_mdivmod, ar1,sr1,dr1, ar2,sr2,dr2, a1,s1,d1, a2,s2,d2)
821 Comparison ops (@<@, @>=@, etc.) are defined in terms of the cmp
822 fellow (returns -ve, 0, or +ve).
824 #define cmpIntegerZh(r, hp, a1,s1,d1, a2,s2,d2) /* calls mpz_cmp */ \
827 /* Does not allocate memory */ \
831 arg1.d = (unsigned long int *) (BYTE_ARR_CTS(d1)); \
834 arg2.d = (unsigned long int *) (BYTE_ARR_CTS(d2)); \
836 (r) = SAFESTGCALL2(I_,(void *, MP_INT *, MP_INT *),mpz_cmp,&arg1,&arg2); \
843 #define integer2IntZh(r, hp, aa,sa,da) \
845 /* Does not allocate memory */ \
849 arg.d = (unsigned long int *) (BYTE_ARR_CTS(da)); \
851 (r) = SAFESTGCALL1(I_,(void *, MP_INT *),mpz_get_si,&arg); \
854 /* Since we're forced to know a little bit about MP_INT layout to do this with
855 pre-allocated heap, we just inline the whole of mpz_init_set_si here.
856 ** DIRE WARNING. if mpz_init_set_si changes, so does this! ***
859 #define int2IntegerZh(ar,sr,dr, hp, i) \
860 { StgInt val; /* to snaffle arg to avoid aliasing */ \
862 val = (i); /* snaffle... */ \
864 SET_DATA_HDR((hp),ArrayOfData_info,CCC,DATA_VHS+MIN_MP_INT_SIZE,0); \
866 if ((val) < 0) { (sr) = -1; (hp)[DATA_HS] = -(val); } \
867 else if ((val) > 0) { (sr) = 1; (hp)[DATA_HS] = (val); } \
868 else /* val==0 */ { (sr) = 0; } \
870 (dr) = (B_)(hp); /* dr is an StgByteArray */ \
873 #define word2IntegerZh(ar,sr,dr, hp, i) \
874 { StgWord val; /* to snaffle arg to avoid aliasing */ \
876 val = (i); /* snaffle... */ \
878 SET_DATA_HDR((hp),ArrayOfData_info,CCC,DATA_VHS+MIN_MP_INT_SIZE,0); \
880 if ((val) != 0) { (sr) = 1; (hp)[DATA_HS] = (val); } \
881 else /* val==0 */ { (sr) = 0; } \
883 (dr) = (B_)(hp); /* dr is an StgByteArray */ \
886 #define integer2WordZh(r, hp, aa,sa,da) \
888 /* Does not allocate memory */ \
892 arg.d = (unsigned long int *) (BYTE_ARR_CTS(da)); \
894 (r) = SAFESTGCALL1(I_,(void *, MP_INT *),mpz_get_ui,&arg); \
897 #define integerToInt64Zh(r, hp, aa,sa,da) \
898 { unsigned long int* d; \
900 /* Allocates memory. Chummy with gmp rep. */ \
902 d = (unsigned long int *) (BYTE_ARR_CTS(da)); \
904 if ( (aa) == 0) { (res)=(LI_)0; } \
905 else if ( (aa) == 1) { (res)=(LI_)d[0]; } \
906 else { (res)=(LI_)d[0] + (LI_)d[1] * 0x100000000LL; } \
907 (r)=(LI_)( (sa) < 0 ? -res : res); \
910 #define integerToWord64Zh(r, hp, aa,sa,da) \
911 { unsigned long int* d; \
913 /* Allocates memory. Chummy with gmp rep. */ \
915 d = (unsigned long int *) (BYTE_ARR_CTS(da)); \
917 if ( (aa) == 0) { (res)=(LW_)0; } \
918 else if ( (aa) == 1) { (res)=(LW_)d[0]; } \
919 else { (res)=(LW_)d[0] + (LW_)d[1] * 0x100000000ULL; } \
923 #define int64ToIntegerZh(ar,sr,dr, hp, li) \
924 { StgInt64 val; /* to snaffle arg to avoid aliasing */ \
928 val = (li); /* snaffle... */ \
930 SET_DATA_HDR((hp),ArrayOfData_info,CCC,DATA_VHS+MIN_MP_INT_SIZE,0); \
936 hi = (W_)((LW_)val / 0x100000000ULL); \
937 if ((LW_)(val) >= 0x100000000ULL) { (sr) = 2; (ar) = 2; (hp)[DATA_HS] = ((W_)val); (hp)[DATA_HS+1] = (hi); } \
938 else if ((val) != 0) { (sr) = 1; (ar) = 1; (hp)[DATA_HS] = ((W_)val); } \
939 else /* val==0 */ { (sr) = 0; (ar) = 1; } \
940 (sr) = ( neg ? -(sr) : (sr) ); \
941 (dr) = (B_)(hp); /* dr is an StgByteArray */ \
944 #define word64ToIntegerZh(ar,sr,dr, hp, lw) \
945 { StgWord64 val; /* to snaffle arg to avoid aliasing */ \
948 val = (lw); /* snaffle... */ \
950 SET_DATA_HDR((hp),ArrayOfData_info,CCC,DATA_VHS+MIN_MP_INT_SIZE,0); \
952 hi = (W_)((LW_)val / 0x100000000ULL); \
953 if ((val) >= 0x100000000ULL ) { (sr) = 2; (ar) = 2; (hp)[DATA_HS] = ((W_)val); (hp)[DATA_HS+1] = (hi); } \
954 else if ((val) != 0) { (sr) = 1; (ar) = 1; (hp)[DATA_HS] = ((W_)val); } \
955 else /* val==0 */ { (sr) = 0; (ar) = 1; } \
956 (dr) = (B_)(hp); /* dr is an StgByteArray */ \
963 Then there are a few oddments to make life easier:
967 The "str" argument must be a literal C string.
969 addr2Integer( ..., "foo") OK!
972 addr2Integer( ..., x) NO! NO!
975 #define addr2IntegerZh(ar,sr,dr, liveness, str) \
977 /* taking the number of bytes/8 as the number of words of lookahead \
978 is plenty conservative */ \
979 I_ space = GMP_SAME_SIZE(sizeof(str) / 8 + 1); \
981 GMP_HEAP_LOOKAHEAD(liveness, space); \
983 /* Perform the operation */ \
984 if (SAFESTGCALL3(I_,(void *, MP_INT *, char *, int), mpz_init_set_str,&result,(str),/*base*/10)) \
987 GMP_HEAP_HANDBACK(); /* restore Hp */ \
988 (ar) = result.alloc; \
989 (sr) = result.size; \
990 (dr) = (B_) (result.d - DATA_HS); \
991 /* pt to *beginning* of object (GMP has been monkeying around in the middle) */ \
995 Encoding and decoding float-ish things is pretty Integer-ish. We use
996 these pretty magical support functions, essentially stolen from Lennart:
998 StgFloat __encodeFloat PROTO((MP_INT *, I_));
999 void __decodeFloat PROTO((MP_INT * /*result1*/,
1003 StgDouble __encodeDouble PROTO((MP_INT *, I_));
1004 void __decodeDouble PROTO((MP_INT * /*result1*/,
1009 Some floating-point format info, made with the \tr{enquire} program
1010 (version~4.3) [comes with gcc].
1012 /* this should be done by CPU architecture, insofar as possible [WDP] */
1014 #if sparc_TARGET_ARCH \
1015 || alpha_TARGET_ARCH \
1016 || hppa1_1_TARGET_ARCH \
1017 || i386_TARGET_ARCH \
1018 || m68k_TARGET_ARCH \
1019 || mipsel_TARGET_ARCH \
1020 || mipseb_TARGET_ARCH \
1021 || powerpc_TARGET_ARCH \
1022 || rs6000_TARGET_ARCH
1024 /* yes, it is IEEE floating point */
1025 #include "ieee-flpt.h"
1027 #if alpha_TARGET_ARCH \
1028 || i386_TARGET_ARCH \
1029 || mipsel_TARGET_ARCH
1031 #undef BIGENDIAN /* little-endian weirdos... */
1036 #else /* unknown floating-point format */
1038 ******* ERROR *********** Any ideas about floating-point format?
1040 #endif /* unknown floating-point */
1044 #if alpha_TARGET_ARCH
1045 #define encodeFloatZh(r, hp, aa,sa,da, expon) encodeDoubleZh(r, hp, aa,sa,da, expon)
1047 #define encodeFloatZh(r, hp, aa,sa,da, expon) \
1049 /* Does not allocate memory */ \
1053 arg.d = (unsigned long int *) (BYTE_ARR_CTS(da)); \
1055 r = SAFESTGCALL2(StgFloat,(void *, MP_INT *, I_), __encodeFloat,&arg,(expon)); \
1057 #endif /* ! alpha */
1059 #define encodeDoubleZh(r, hp, aa,sa,da, expon) \
1061 /* Does not allocate memory */ \
1065 arg.d = (unsigned long int *) (BYTE_ARR_CTS(da)); \
1067 r = SAFESTGCALL2(StgDouble,(void *, MP_INT *, I_), __encodeDouble,&arg,(expon));\
1070 #if alpha_TARGET_ARCH
1071 #define decodeFloatZh(exponr, ar,sr,dr, hp, f) decodeDoubleZh(exponr, ar,sr,dr, hp, f)
1073 #define decodeFloatZh(exponr, ar,sr,dr, hp, f) \
1074 { MP_INT mantissa; \
1076 StgFloat arg = (f); \
1078 /* Be prepared to tell Lennart-coded __decodeFloat */ \
1079 /* where mantissa.d can be put (it does not care about the rest) */ \
1080 SET_DATA_HDR(hp,ArrayOfData_info,CCC,DATA_VHS+MIN_MP_INT_SIZE,0); \
1081 mantissa.d = (hp) + DATA_HS; \
1083 /* Perform the operation */ \
1084 SAFESTGCALL3(void,(void *, MP_INT *, I_ *, StgFloat),__decodeFloat,&mantissa,&exponent,arg); \
1086 ar = mantissa.alloc; \
1087 sr = mantissa.size; \
1092 #define decodeDoubleZh(exponr, ar,sr,dr, hp, f) \
1093 { MP_INT mantissa; \
1095 StgDouble arg = (f); \
1097 /* Be prepared to tell Lennart-coded __decodeDouble */ \
1098 /* where mantissa.d can be put (it does not care about the rest) */ \
1099 SET_DATA_HDR(hp,ArrayOfData_info,CCC,DATA_VHS+MIN_MP_INT_SIZE,0); \
1100 mantissa.d = (hp) + DATA_HS; \
1102 /* Perform the operation */ \
1103 SAFESTGCALL3(void,(void *, MP_INT *, I_ *, StgDouble),__decodeDouble,&mantissa,&exponent,arg); \
1105 ar = mantissa.alloc; \
1106 sr = mantissa.size; \
1111 %************************************************************************
1113 \subsubsection[StgMacros-mv-floats]{Moving floats and doubles around (e.g., to/from stacks)}
1115 %************************************************************************
1117 With GCC, we use magic non-standard inlining; for other compilers, we
1118 just use functions (see also \tr{runtime/prims/PrimArith.lc}).
1120 (The @OMIT_...@ is only used in compiling some of the RTS, none of
1121 which uses these anyway.)
1124 #if alpha_TARGET_ARCH \
1125 || i386_TARGET_ARCH \
1128 #define ASSIGN_FLT(dst, src) *(StgFloat *)(dst) = (src);
1129 #define PK_FLT(src) (*(StgFloat *)(src))
1131 #define ASSIGN_DBL(dst, src) *(StgDouble *)(dst) = (src);
1132 #define PK_DBL(src) (*(StgDouble *)(src))
1134 #else /* not m68k || alpha || i[34]86 */
1136 /* Special handling for machines with troublesome alignment constraints */
1138 #define FLOAT_ALIGNMENT_TROUBLES TRUE
1140 #if ! defined(__GNUC__) || ! defined(__STG_GCC_REGS__)
1142 void ASSIGN_DBL PROTO((W_ [], StgDouble));
1143 StgDouble PK_DBL PROTO((W_ []));
1144 void ASSIGN_FLT PROTO((W_ [], StgFloat));
1145 StgFloat PK_FLT PROTO((W_ []));
1147 #else /* yes, its __GNUC__ && we really want them */
1149 #if sparc_TARGET_ARCH
1151 #define ASSIGN_FLT(dst, src) *(StgFloat *)(dst) = (src);
1152 #define PK_FLT(src) (*(StgFloat *)(src))
1154 #define ASSIGN_DBL(dst,src) \
1155 __asm__("st %2,%0\n\tst %R2,%1" : "=m" (((P_)(dst))[0]), \
1156 "=m" (((P_)(dst))[1]) : "f" (src));
1158 #define PK_DBL(src) \
1159 ( { register double d; \
1160 __asm__("ld %1,%0\n\tld %2,%R0" : "=f" (d) : \
1161 "m" (((P_)(src))[0]), "m" (((P_)(src))[1])); d; \
1166 /* (not very) forward prototype declarations */
1167 void ASSIGN_DBL PROTO((W_ [], StgDouble));
1168 StgDouble PK_DBL PROTO((W_ []));
1169 void ASSIGN_FLT PROTO((W_ [], StgFloat));
1170 StgFloat PK_FLT PROTO((W_ []));
1174 ASSIGN_DBL(W_ p_dest[], StgDouble src)
1178 p_dest[0] = y.du.dhi;
1179 p_dest[1] = y.du.dlo;
1182 /* GCC also works with this version, but it generates
1183 the same code as the previous one, and is not ANSI
1185 #define ASSIGN_DBL( p_dest, src ) \
1186 *p_dest = ((double_thing) src).du.dhi; \
1187 *(p_dest+1) = ((double_thing) src).du.dlo \
1195 y.du.dhi = p_src[0];
1196 y.du.dlo = p_src[1];
1202 ASSIGN_FLT(W_ p_dest[], StgFloat src)
1218 #endif /* ! sparc */
1220 #endif /* __GNUC__ */
1222 #endif /* not __m68k__ */
1227 ASSIGN_Word64(W_ p_dest[], StgWord64 src)
1231 p_dest[0] = y.wu.dhi;
1232 p_dest[1] = y.wu.dlo;
1237 PK_Word64(W_ p_src[])
1240 y.wu.dhi = p_src[0];
1241 y.wu.dlo = p_src[1];
1247 ASSIGN_Int64(W_ p_dest[], StgInt64 src)
1251 p_dest[0] = y.iu.dhi;
1252 p_dest[1] = y.iu.dlo;
1257 PK_Int64(W_ p_src[])
1260 y.iu.dhi = p_src[0];
1261 y.iu.dlo = p_src[1];
1268 %************************************************************************
1270 \subsubsection[StgMacros-array-primops]{Primitive arrays}
1272 %************************************************************************
1274 We regularly use this macro to fish the ``contents'' part
1275 out of a DATA or TUPLE closure, which is what is used for
1276 non-ptr and ptr arrays (respectively).
1278 BYTE_ARR_CTS returns a @C_ *@!
1280 We {\em ASSUME} we can use the same macro for both!!
1284 #define BYTE_ARR_CTS(a) \
1285 ({ ASSERT(INFO_PTR(a) == (W_) ArrayOfData_info); \
1286 ((C_ *) (((StgPtr) (a))+DATA_HS)); })
1287 #define PTRS_ARR_CTS(a) \
1288 ({ ASSERT((INFO_PTR(a) == (W_) ArrayOfPtrs_info) \
1289 || (INFO_PTR(a) == (W_) ImMutArrayOfPtrs_info));\
1290 ((a)+MUTUPLE_HS);} )
1292 #define BYTE_ARR_CTS(a) ((char *) (((StgPtr) (a))+DATA_HS))
1293 #define PTRS_ARR_CTS(a) ((a)+MUTUPLE_HS)
1297 extern I_ genSymZh(STG_NO_ARGS);
1298 extern I_ resetGenSymZh(STG_NO_ARGS);
1299 extern I_ incSeqWorldZh(STG_NO_ARGS);
1301 extern I_ byteArrayHasNUL__ PROTO((const char *, I_));
1304 OK, the easy ops first: (all except \tr{newArr*}:
1306 (OLD:) VERY IMPORTANT! The read/write/index primitive ops
1307 on @ByteArray#@s index the array using a {\em BYTE} offset, even
1308 if the thing begin gotten out is a multi-byte @Int#@, @Float#@ etc.
1309 This is because you might be trying to take apart a C struct, where
1310 the offset from the start of the struct isn't a multiple of the
1311 size of the thing you're getting. Hence the @(char *)@ casts.
1313 EVEN MORE IMPORTANT! The above is a lie. The offsets for BlahArrays
1314 are in Blahs. WDP 95/08
1316 In the case of messing with @StgAddrs@ (@A_@), which are really \tr{void *},
1317 we cast to @P_@, because you can't index off an uncast \tr{void *}.
1319 In the case of @Array#@ (which contain pointers), the offset is in units
1320 of one ptr (not bytes).
1323 #define sameMutableArrayZh(r,a,b) r=(I_)((a)==(b))
1324 #define sameMutableByteArrayZh(r,a,b) r=(I_)((B_)(a)==(B_)(b))
1326 #define readArrayZh(r,a,i) r=((PP_) PTRS_ARR_CTS(a))[(i)]
1328 #define readCharArrayZh(r,a,i) indexCharOffAddrZh(r,BYTE_ARR_CTS(a),i)
1329 #define readIntArrayZh(r,a,i) indexIntOffAddrZh(r,BYTE_ARR_CTS(a),i)
1330 #define readStablePtrArrayZh(r,a,i) indexStablePtrOffAddrZh(r,BYTE_ARR_CTS(a),i)
1331 #define readWordArrayZh(r,a,i) indexWordOffAddrZh(r,BYTE_ARR_CTS(a),i)
1332 #define readInt64ArrayZh(r,a,i) indexInt64OffAddrZh(r,BYTE_ARR_CTS(a),i)
1333 #define readWord64ArrayZh(r,a,i) indexWord64OffAddrZh(r,BYTE_ARR_CTS(a),i)
1334 #define readAddrArrayZh(r,a,i) indexAddrOffAddrZh(r,BYTE_ARR_CTS(a),i)
1335 #define readFloatArrayZh(r,a,i) indexFloatOffAddrZh(r,BYTE_ARR_CTS(a),i)
1336 #define readDoubleArrayZh(r,a,i) indexDoubleOffAddrZh(r,BYTE_ARR_CTS(a),i)
1338 /* result ("r") arg ignored in write macros! */
1339 #define writeArrayZh(a,i,v) ((PP_) PTRS_ARR_CTS(a))[(i)]=(v)
1341 #define writeCharArrayZh(a,i,v) ((C_ *)(BYTE_ARR_CTS(a)))[i] = (v)
1342 #define writeIntArrayZh(a,i,v) ((I_ *)(BYTE_ARR_CTS(a)))[i] = (v)
1343 #define writeStablePtrArrayZh(a,i,v) ((StgStablePtr *)(BYTE_ARR_CTS(a)))[i] = (v)
1344 #define writeWordArrayZh(a,i,v) ((W_ *)(BYTE_ARR_CTS(a)))[i] = (v)
1345 #define writeInt64ArrayZh(a,i,v) ((LI_ *)(BYTE_ARR_CTS(a)))[i] = (v)
1346 #define writeWord64ArrayZh(a,i,v) ((LW_ *)(BYTE_ARR_CTS(a)))[i] = (v)
1347 #define writeAddrArrayZh(a,i,v) ((PP_)(BYTE_ARR_CTS(a)))[i] = (v)
1348 #define writeFloatArrayZh(a,i,v) ASSIGN_FLT((P_) (((StgFloat *)(BYTE_ARR_CTS(a))) + i),v)
1349 #define writeDoubleArrayZh(a,i,v) ASSIGN_DBL((P_) (((StgDouble *)(BYTE_ARR_CTS(a))) + i),v)
1351 #define indexArrayZh(r,a,i) r=((PP_) PTRS_ARR_CTS(a))[(i)]
1353 #define indexCharArrayZh(r,a,i) indexCharOffAddrZh(r,BYTE_ARR_CTS(a),i)
1354 #define indexIntArrayZh(r,a,i) indexIntOffAddrZh(r,BYTE_ARR_CTS(a),i)
1355 #define indexStablePtrArrayZh(r,a,i) indexStablePtrOffAddrZh(r,BYTE_ARR_CTS(a),i)
1356 #define indexWordArrayZh(r,a,i) indexWordOffAddrZh(r,BYTE_ARR_CTS(a),i)
1357 #define indexAddrArrayZh(r,a,i) indexAddrOffAddrZh(r,BYTE_ARR_CTS(a),i)
1358 #define indexFloatArrayZh(r,a,i) indexFloatOffAddrZh(r,BYTE_ARR_CTS(a),i)
1359 #define indexDoubleArrayZh(r,a,i) indexDoubleOffAddrZh(r,BYTE_ARR_CTS(a),i)
1360 #define indexInt64ArrayZh(r,a,i) indexInt64OffAddrZh(r,BYTE_ARR_CTS(a),i)
1361 #define indexWord64ArrayZh(r,a,i) indexWord64OffAddrZh(r,BYTE_ARR_CTS(a),i)
1363 #define indexCharOffForeignObjZh(r,fo,i) indexCharOffAddrZh(r,ForeignObj_CLOSURE_DATA(fo),i)
1364 #define indexIntOffForeignObjZh(r,fo,i) indexIntOffAddrZh(r,ForeignObj_CLOSURE_DATA(fo),i)
1365 #define indexStablePtrOffForeignObjZh(r,fo,i) indexStablePtrOffAddrZh(r,ForeignObj_CLOSURE_DATA(fo),i)
1366 #define indexWordOffForeignObjZh(r,fo,i) indexWordOffAddrZh(r,ForeignObj_CLOSURE_DATA(fo),i)
1367 #define indexAddrOffForeignObjZh(r,fo,i) indexAddrOffAddrZh(r,ForeignObj_CLOSURE_DATA(fo),i)
1368 #define indexFloatOffForeignObjZh(r,fo,i) indexFloatOffAddrZh(r,ForeignObj_CLOSURE_DATA(fo),i)
1369 #define indexDoubleOffForeignObjZh(r,fo,i) indexDoubleOffAddrZh(r,ForeignObj_CLOSURE_DATA(fo),i)
1370 #define indexInt64OffForeignObjZh(r,fo,i) indexInt64OffAddrZh(r,ForeignObj_CLOSURE_DATA(fo),i)
1371 #define indexWord64OffForeignObjZh(r,fo,i) indexWord64OffAddrZh(r,ForeignObj_CLOSURE_DATA(fo),i)
1373 #define indexCharOffAddrZh(r,a,i) r= ((C_ *)(a))[i]
1374 #define indexIntOffAddrZh(r,a,i) r= ((I_ *)(a))[i]
1375 #define indexStablePtrOffAddrZh(r,a,i) r= ((StgStablePtr *)(a))[i]
1376 #define indexWordOffAddrZh(r,a,i) r= ((W_ *)(a))[i]
1377 #define indexAddrOffAddrZh(r,a,i) r= ((PP_)(a))[i]
1378 #define indexFloatOffAddrZh(r,a,i) r= PK_FLT((P_) (((StgFloat *)(a)) + i))
1379 #define indexDoubleOffAddrZh(r,a,i) r= PK_DBL((P_) (((StgDouble *)(a)) + i))
1380 #define indexInt64OffAddrZh(r,a,i) r= ((LI_ *)(a))[i]
1381 #define indexWord64OffAddrZh(r,a,i) r= ((LW_ *)(a))[i]
1383 #define writeCharOffAddrZh(a,i,v) ((C_ *)(a))[i] = (v)
1384 #define writeIntOffAddrZh(a,i,v) ((I_ *)(a))[i] = (v)
1385 #define writeStablePtrOffAddrZh(a,i,v) ((StgStablePtr *)(a))[i] = (v)
1386 #define writeWordOffAddrZh(a,i,v) ((W_ *)(a))[i] = (v)
1387 #define writeAddrOffAddrZh(a,i,v) ((PP_)(a))[i] = (v)
1388 #define writeForeignObjOffAddrZh(a,i,v) ((PP_)(a))[i] = ForeignObj_CLOSURE_DATA(v)
1389 #define writeFloatOffAddrZh(a,i,v) ASSIGN_FLT((P_) (((StgFloat *)(a)) + i),v)
1390 #define writeDoubleOffAddrZh(a,i,v) ASSIGN_DBL((P_) (((StgDouble *)(a)) + i),v)
1391 #define writeInt64OffAddrZh(a,i,v) ((LI_ *)(a))[i] = (v)
1392 #define writeWord64OffAddrZh(a,i,v) ((LW_ *)(a))[i] = (v)
1395 /* Freezing arrays-of-ptrs requires changing an info table, for the
1396 benefit of the generational collector. It needs to scavenge mutable
1397 objects, even if they are in old space. When they become immutable,
1398 they can be removed from this scavenge list. */
1399 #define unsafeFreezeArrayZh(r,a) \
1403 FREEZE_MUT_HDR(result,ImMutArrayOfPtrs_info); \
1407 #define unsafeFreezeByteArrayZh(r,a) r=(B_)(a)
1409 #define sizeofByteArrayZh(r,a) r=(W_)sizeof(W_)*(W_)(DATA_CLOSURE_SIZE(a)-DATA_VHS)
1410 #define sizeofMutableByteArrayZh(r,a) r=(W_)sizeof(W_)*(W_)(DATA_CLOSURE_SIZE(a)-DATA_VHS)
1413 Now the \tr{newArr*} ops:
1417 --------------------
1418 Will: ToDo: we need to find suitable places to put this comment, and the
1419 "in-general" one which follows.
1421 ************ Nota Bene. The "n" in this macro is guaranteed to
1422 be a register, *not* (say) Node[1]. That means that it is guaranteed
1423 to survive GC, provided only that the register is kept unaltered.
1424 This is important, because "n" is used after the HEAP_CHK.
1426 In general, *all* parameters to these primitive-op macros are always
1427 registers. (Will: For exactly *which* primitive-op macros is this guaranteed?
1428 Exactly those which can trigger GC?)
1429 ------------------------
1431 NOTE: the above may now be OLD (WDP 94/02/10)
1435 For char arrays, the size is in {\em BYTES}.
1438 #define newCharArrayZh(r,liveness,n) newByteArray(r,liveness,(n) * sizeof(C_))
1439 #define newIntArrayZh(r,liveness,n) newByteArray(r,liveness,(n) * sizeof(I_))
1440 #define newStablePtrArrayZh(r,liveness,n) newByteArray(r,liveness,(n) * sizeof(StgStablePtr))
1441 #define newWordArrayZh(r,liveness,n) newByteArray(r,liveness,(n) * sizeof(W_))
1442 #define newInt64ArrayZh(r,liveness,n) newByteArray(r,liveness,(n) * sizeof(LI_))
1443 #define newWord64ArrayZh(r,liveness,n) newByteArray(r,liveness,(n) * sizeof(LW_))
1444 #define newAddrArrayZh(r,liveness,n) newByteArray(r,liveness,(n) * sizeof(P_))
1445 #define newFloatArrayZh(r,liveness,n) newByteArray(r,liveness,(n) * sizeof(StgFloat))
1446 #define newDoubleArrayZh(r,liveness,n) newByteArray(r,liveness,(n) * sizeof(StgDouble))
1448 #define newByteArray(r,liveness,n) \
1453 HEAP_CHK(liveness,DATA_HS+BYTES_TO_STGWORDS(n),0); \
1454 size = BYTES_TO_STGWORDS(n); \
1455 ALLOC_PRIM(DATA_HS,size,0,DATA_HS+size) /* ticky ticky */; \
1456 CC_ALLOC(CCC,DATA_HS+size,ARR_K); \
1458 result = Hp-(DATA_HS+size)+1; \
1459 SET_DATA_HDR(result,ArrayOfData_info,CCC,DATA_VHS+size,0); \
1464 Arrays of pointers need to be initialised; uses \tr{TUPLES}!
1465 The initialisation value is guaranteed to be in a register,
1466 and will be indicated by the liveness mask, so it's ok to do
1467 a \tr{HEAP_CHK}, which may trigger GC.
1470 /* The new array initialization routine for the NCG */
1471 void newArrZh_init PROTO((P_ result, I_ n, P_ init));
1473 #define newArrayZh(r,liveness,n,init) \
1478 HEAP_CHK(liveness, MUTUPLE_HS+(n),0); \
1479 ALLOC_PRIM(MUTUPLE_HS,(n),0,MUTUPLE_HS+(n)) /* ticky ticky */; \
1480 CC_ALLOC(CCC,MUTUPLE_HS+(n),ARR_K); /* cc prof */ \
1482 result = Hp + 1 - (MUTUPLE_HS+(n)); \
1483 SET_MUTUPLE_HDR(result,ArrayOfPtrs_info,CCC,MUTUPLE_VHS+(n),0) \
1484 for (p = result+MUTUPLE_HS; p < (result+MUTUPLE_HS+(n)); p++) { \
1492 %************************************************************************
1494 \subsubsection[StgMacros-SynchVar-primops]{Synchronizing Variables PrimOps}
1496 %************************************************************************
1499 ED_(PrelBase_Z91Z93_closure);
1501 #define sameMVarZh(r,a,b) r=(I_)((a)==(b))
1503 #define newSynchVarZh(r, hp) \
1505 ALLOC_PRIM(MUTUPLE_HS,3,0,MUTUPLE_HS+3) /* ticky ticky */; \
1506 CC_ALLOC(CCC,MUTUPLE_HS+3,ARR_K); /* cc prof */ \
1507 SET_SVAR_HDR(hp,EmptySVar_info,CCC); \
1508 SVAR_HEAD(hp) = SVAR_TAIL(hp) = SVAR_VALUE(hp) = PrelBase_Z91Z93_closure; \
1516 void Yield PROTO((W_));
1518 #define takeMVarZh(r, liveness, node) \
1520 while (INFO_PTR(node) != (W_) FullSVar_info) { \
1521 if (SVAR_HEAD(node) == PrelBase_Z91Z93_closure) \
1522 SVAR_HEAD(node) = CurrentTSO; \
1524 TSO_LINK(SVAR_TAIL(node)) = CurrentTSO; \
1525 TSO_LINK(CurrentTSO) = (P_) PrelBase_Z91Z93_closure; \
1526 SVAR_TAIL(node) = CurrentTSO; \
1527 DO_YIELD(liveness << 1); \
1529 SET_INFO_PTR(node, EmptySVar_info); \
1530 r = SVAR_VALUE(node); \
1531 SVAR_VALUE(node) = PrelBase_Z91Z93_closure; \
1536 #define takeMVarZh(r, liveness, node) \
1538 if (INFO_PTR(node) != (W_) FullSVar_info) { \
1539 /* Don't wrap the calls; we're done with STG land */\
1541 fprintf(stderr, "takeMVar#: MVar is empty.\n"); \
1542 EXIT(EXIT_FAILURE); \
1544 SET_INFO_PTR(node, EmptySVar_info); \
1545 r = SVAR_VALUE(node); \
1546 SVAR_VALUE(node) = PrelBase_Z91Z93_closure; \
1557 /* Only difference to the !GRAN def: RunnableThreadsHd has been replaced by */
1558 /* ThreadQueueHd i.e. the tso is added at the end of the thread queue on */
1559 /* the CurrentProc. This means we have an implicit context switch after */
1560 /* putMVar even if unfair scheduling is used in GranSim (default)! -- HWL */
1562 #define putMVarZh(node, value) \
1565 if (INFO_PTR(node) == (W_) FullSVar_info) { \
1566 /* Don't wrap the calls; we're done with STG land */\
1568 fprintf(stderr, "putMVar#: MVar already full.\n"); \
1569 EXIT(EXIT_FAILURE); \
1571 SET_INFO_PTR(node, FullSVar_info); \
1572 SVAR_VALUE(node) = value; \
1573 tso = SVAR_HEAD(node); \
1574 if (tso != (P_) PrelBase_Z91Z93_closure) { \
1576 STGCALL3(void,(void *, char *, P_, P_),QP_Event2,do_qp_prof > 1 ? "RA" : "RG",tso,CurrentTSO); \
1577 if (ThreadQueueHd == PrelBase_Z91Z93_closure) \
1578 ThreadQueueHd = tso; \
1580 TSO_LINK(ThreadQueueTl) = tso; \
1581 ThreadQueueTl = tso; \
1582 SVAR_HEAD(node) = TSO_LINK(tso); \
1583 TSO_LINK(tso) = (P_) PrelBase_Z91Z93_closure; \
1584 if(SVAR_HEAD(node) == (P_) PrelBase_Z91Z93_closure) \
1585 SVAR_TAIL(node) = (P_) PrelBase_Z91Z93_closure; \
1591 #define putMVarZh(node, value) \
1594 if (INFO_PTR(node) == (W_) FullSVar_info) { \
1595 /* Don't wrap the calls; we're done with STG land */\
1597 fprintf(stderr, "putMVar#: MVar already full.\n"); \
1598 EXIT(EXIT_FAILURE); \
1600 SET_INFO_PTR(node, FullSVar_info); \
1601 SVAR_VALUE(node) = value; \
1602 tso = SVAR_HEAD(node); \
1603 if (tso != (P_) PrelBase_Z91Z93_closure) { \
1605 STGCALL3(void,(void *, char *, P_, P_),QP_Event2,do_qp_prof > 1 ? "RA" : "RG",tso,CurrentTSO); \
1606 if (RunnableThreadsHd == PrelBase_Z91Z93_closure) \
1607 RunnableThreadsHd = tso; \
1609 TSO_LINK(RunnableThreadsTl) = tso; \
1610 RunnableThreadsTl = tso; \
1611 SVAR_HEAD(node) = TSO_LINK(tso); \
1612 TSO_LINK(tso) = (P_) PrelBase_Z91Z93_closure; \
1613 if(SVAR_HEAD(node) == (P_) PrelBase_Z91Z93_closure) \
1614 SVAR_TAIL(node) = (P_) PrelBase_Z91Z93_closure; \
1622 #define putMVarZh(node, value) \
1625 if (INFO_PTR(node) == (W_) FullSVar_info) { \
1626 /* Don't wrap the calls; we're done with STG land */\
1628 fprintf(stderr, "putMVar#: MVar already full.\n"); \
1629 EXIT(EXIT_FAILURE); \
1631 SET_INFO_PTR(node, FullSVar_info); \
1632 SVAR_VALUE(node) = value; \
1641 #define readIVarZh(r, liveness, node) \
1643 if (INFO_PTR(node) != (W_) ImMutArrayOfPtrs_info) { \
1644 if (SVAR_HEAD(node) == PrelBase_Z91Z93_closure) \
1645 SVAR_HEAD(node) = CurrentTSO; \
1647 TSO_LINK(SVAR_TAIL(node)) = CurrentTSO; \
1648 TSO_LINK(CurrentTSO) = (P_) PrelBase_Z91Z93_closure; \
1649 SVAR_TAIL(node) = CurrentTSO; \
1650 DO_YIELD(liveness << 1); \
1652 r = SVAR_VALUE(node); \
1657 #define readIVarZh(r, liveness, node) \
1659 if (INFO_PTR(node) != (W_) ImMutArrayOfPtrs_info) { \
1660 /* Don't wrap the calls; we're done with STG land */\
1662 fprintf(stderr, "readIVar#: IVar is empty.\n"); \
1663 EXIT(EXIT_FAILURE); \
1665 r = SVAR_VALUE(node); \
1676 /* Only difference to the !GRAN def: RunnableThreadsHd has been replaced by */
1677 /* ThreadQueueHd i.e. the tso is added at the end of the thread queue on */
1678 /* the CurrentProc. This means we have an implicit context switch after */
1679 /* writeIVar even if unfair scheduling is used in GranSim (default)! -- HWL */
1681 #define writeIVarZh(node, value) \
1684 if (INFO_PTR(node) == (W_) ImMutArrayOfPtrs_info) { \
1685 /* Don't wrap the calls; we're done with STG land */\
1687 fprintf(stderr, "writeIVar#: IVar already full.\n");\
1688 EXIT(EXIT_FAILURE); \
1690 tso = SVAR_HEAD(node); \
1691 if (tso != (P_) PrelBase_Z91Z93_closure) { \
1692 if (ThreadQueueHd == PrelBase_Z91Z93_closure) \
1693 ThreadQueueHd = tso; \
1695 TSO_LINK(ThreadQueueTl) = tso; \
1696 while(TSO_LINK(tso) != PrelBase_Z91Z93_closure) { \
1698 STGCALL3(void,(void *, char *, P_, P_),QP_Event2,do_qp_prof > 1 ? "RA" : "RG",tso,CurrentTSO); \
1699 tso = TSO_LINK(tso); \
1702 STGCALL3(void,(void *, char *, P_, P_),QP_Event2,do_qp_prof > 1 ? "RA" : "RG",tso,CurrentTSO); \
1703 ThreadQueueTl = tso; \
1705 /* Don't use freeze, since it's conditional on GC */ \
1706 SET_INFO_PTR(node, ImMutArrayOfPtrs_info); \
1707 MUTUPLE_CLOSURE_SIZE(node) = (MUTUPLE_VHS+1); \
1708 SVAR_VALUE(node) = value; \
1713 #define writeIVarZh(node, value) \
1716 if (INFO_PTR(node) == (W_) ImMutArrayOfPtrs_info) { \
1717 /* Don't wrap the calls; we're done with STG land */\
1719 fprintf(stderr, "writeIVar#: IVar already full.\n");\
1720 EXIT(EXIT_FAILURE); \
1722 tso = SVAR_HEAD(node); \
1723 if (tso != (P_) PrelBase_Z91Z93_closure) { \
1724 if (RunnableThreadsHd == PrelBase_Z91Z93_closure) \
1725 RunnableThreadsHd = tso; \
1727 TSO_LINK(RunnableThreadsTl) = tso; \
1728 while(TSO_LINK(tso) != PrelBase_Z91Z93_closure) { \
1730 STGCALL3(void,(void *, char *, P_, P_),QP_Event2,do_qp_prof > 1 ? "RA" : "RG",tso,CurrentTSO); \
1731 tso = TSO_LINK(tso); \
1734 STGCALL3(void,(void *, char *, P_, P_),QP_Event2,do_qp_prof > 1 ? "RA" : "RG",tso,CurrentTSO); \
1735 RunnableThreadsTl = tso; \
1737 /* Don't use freeze, since it's conditional on GC */ \
1738 SET_INFO_PTR(node, ImMutArrayOfPtrs_info); \
1739 MUTUPLE_CLOSURE_SIZE(node) = (MUTUPLE_VHS+1); \
1740 SVAR_VALUE(node) = value; \
1747 #define writeIVarZh(node, value) \
1750 if (INFO_PTR(node) == (W_) ImMutArrayOfPtrs_info) { \
1751 /* Don't wrap the calls; we're done with STG land */\
1753 fprintf(stderr, "writeIVar#: IVar already full.\n");\
1754 EXIT(EXIT_FAILURE); \
1756 /* Don't use freeze, since it's conditional on GC */ \
1757 SET_INFO_PTR(node, ImMutArrayOfPtrs_info); \
1758 MUTUPLE_CLOSURE_SIZE(node) = (MUTUPLE_VHS+1); \
1759 SVAR_VALUE(node) = value; \
1765 %************************************************************************
1767 \subsubsection[StgMacros-Wait-primops]{Delay/Wait PrimOps}
1769 %************************************************************************
1774 /* ToDo: for GRAN */
1776 #define delayZh(liveness, us) \
1778 if (WaitingThreadsTl == PrelBase_Z91Z93_closure) \
1779 WaitingThreadsHd = CurrentTSO; \
1781 TSO_LINK(WaitingThreadsTl) = CurrentTSO; \
1782 WaitingThreadsTl = CurrentTSO; \
1783 TSO_LINK(CurrentTSO) = PrelBase_Z91Z93_closure; \
1784 TSO_EVENT(CurrentTSO) = (W_) ((us) < 1 ? 1 : (us)); \
1785 DO_YIELD(liveness << 1); \
1790 #define delayZh(liveness, us) \
1793 fprintf(stderr, "delay#: unthreaded build.\n"); \
1794 EXIT(EXIT_FAILURE); \
1801 /* ToDo: something for GRAN */
1803 #define waitReadZh(liveness, fd) \
1805 if (WaitingThreadsTl == PrelBase_Z91Z93_closure) \
1806 WaitingThreadsHd = CurrentTSO; \
1808 TSO_LINK(WaitingThreadsTl) = CurrentTSO; \
1809 WaitingThreadsTl = CurrentTSO; \
1810 TSO_LINK(CurrentTSO) = PrelBase_Z91Z93_closure; \
1811 TSO_EVENT(CurrentTSO) = (W_) (-(fd)); \
1812 DO_YIELD(liveness << 1); \
1817 #define waitReadZh(liveness, fd) \
1820 fprintf(stderr, "waitRead#: unthreaded build.\n"); \
1821 EXIT(EXIT_FAILURE); \
1828 /* ToDo: something for GRAN */
1830 #ifdef HAVE_SYS_TYPES_H
1831 #include <sys/types.h>
1832 #endif HAVE_SYS_TYPES_H */
1834 #define waitWriteZh(liveness, fd) \
1836 if (WaitingThreadsTl == PrelBase_Z91Z93_closure) \
1837 WaitingThreadsHd = CurrentTSO; \
1839 TSO_LINK(WaitingThreadsTl) = CurrentTSO; \
1840 WaitingThreadsTl = CurrentTSO; \
1841 TSO_LINK(CurrentTSO) = PrelBase_Z91Z93_closure; \
1842 TSO_EVENT(CurrentTSO) = (W_) (-(fd+FD_SETSIZE)); \
1843 DO_YIELD(liveness << 1); \
1848 #define waitWriteZh(liveness, fd) \
1851 fprintf(stderr, "waitWrite#: unthreaded build.\n"); \
1852 EXIT(EXIT_FAILURE); \
1859 %************************************************************************
1861 \subsubsection[StgMacros-IO-primops]{Primitive I/O, error-handling primops}
1863 %************************************************************************
1866 extern P_ TopClosure;
1867 EXTFUN(ErrorIO_innards);
1868 EXTFUN(__std_entry_error__);
1870 #define errorIOZh(a) \
1871 do { TopClosure=(a); \
1872 (void) SAFESTGCALL1(I_,(void *, FILE *),fflush,stdout); \
1873 (void) SAFESTGCALL1(I_,(void *, FILE *),fflush,stderr); \
1874 JMP_(ErrorIO_innards); \
1877 /* These are now, I believe, unused. (8/98 SOF) */
1878 #if !defined(CALLER_SAVES_SYSTEM)
1879 /* can use the macros */
1880 #define stg_getc(stream) getc((FILE *) (stream))
1881 #define stg_putc(c,stream) putc((c),((FILE *) (stream)))
1883 /* must not use the macros (they contain embedded calls to _filbuf/whatnot) */
1884 #define stg_getc(stream) SAFESTGCALL1(I_,(void *, FILE *),fgetc,(FILE *) (stream))
1885 #define stg_putc(c,stream) SAFESTGCALL2(I_,(void *, char, FILE *),fputc,(c),((FILE *) (stream)))
1888 int initialize_virtual_timer(int us);
1889 int install_segv_handler(STG_NO_ARGS);
1890 int install_vtalrm_handler(STG_NO_ARGS);
1891 void initUserSignals(STG_NO_ARGS);
1892 void blockUserSignals(STG_NO_ARGS);
1893 void unblockUserSignals(STG_NO_ARGS);
1894 IF_RTS(void blockVtAlrmSignal(STG_NO_ARGS);)
1895 IF_RTS(void unblockVtAlrmSignal(STG_NO_ARGS);)
1896 IF_RTS(void AwaitEvent(I_ delta);)
1898 #if defined(_POSIX_SOURCE) && !defined(nextstep3_TARGET_OS)
1899 /* For nextstep3_TARGET_OS comment see stgdefs.h. CaS */
1900 extern I_ sig_install PROTO((I_, I_, sigset_t *));
1901 #define stg_sig_ignore(s,m) SAFESTGCALL3(I_,(void *, I_, I_),sig_install,s,STG_SIG_IGN,(sigset_t *)m)
1902 #define stg_sig_default(s,m) SAFESTGCALL3(I_,(void *, I_, I_),sig_install,s,STG_SIG_DFL,(sigset_t *)m)
1903 #define stg_sig_catch(s,sp,m) SAFESTGCALL3(I_,(void *, I_, I_),sig_install,s,sp,(sigset_t *)m)
1905 extern I_ sig_install PROTO((I_, I_));
1906 #define stg_sig_ignore(s,m) SAFESTGCALL2(I_,(void *, I_, I_),sig_install,s,STG_SIG_IGN)
1907 #define stg_sig_default(s,m) SAFESTGCALL2(I_,(void *, I_, I_),sig_install,s,STG_SIG_DFL)
1908 #define stg_sig_catch(s,sp,m) SAFESTGCALL2(I_,(void *, I_, I_),sig_install,s,sp)
1911 #define STG_SIG_DFL (-1)
1912 #define STG_SIG_IGN (-2)
1913 #define STG_SIG_ERR (-3)
1915 StgInt getErrorHandler(STG_NO_ARGS);
1917 void raiseError PROTO((StgStablePtr handler));
1918 StgInt catchError PROTO((StgStablePtr newErrorHandler));
1920 void decrementErrorCount(STG_NO_ARGS);
1922 #define stg_catchError(sp) SAFESTGCALL1(I_,(void *, StgStablePtr),catchError,sp)
1923 #define stg_decrementErrorCount() SAFESTGCALL0(void,(void *),decrementErrorCount)
1926 %************************************************************************
1928 \subsubsection[StgMacros-stable-ptr]{Primitive ops for manipulating stable pointers}
1930 %************************************************************************
1933 The type of these should be:
1936 makeStablePointer# :: a -> State# _RealWorld -> StateAndStablePtr# _RealWorld a
1937 deRefStablePointer# :: StablePtr# a -> State# _RealWorld -> StateAndPtr _RealWorld a
1940 Since world-tokens are no longer explicitly passed around, the
1941 implementations have a few less arguments/results.
1943 The simpler one is @deRefStablePointer#@ (which is only a primop
1944 because it is more polymorphic than is allowed of a ccall).
1949 #define deRefStablePtrZh(ri,sp) \
1952 fprintf(stderr, "deRefStablePtr#: no stable pointer support.\n");\
1953 EXIT(EXIT_FAILURE); \
1958 extern StgPtr _deRefStablePointer PROTO((StgInt, StgPtr));
1960 #define deRefStablePtrZh(ri,sp) \
1961 ri = SAFESTGCALL2(I_,(void *, I_, P_),_deRefStablePointer,sp,StorageMgrInfo.StablePointerTable);
1964 Declarations for other stable pointer operations.
1967 void freeStablePointer PROTO((I_ stablePtr));
1969 void enterStablePtr PROTO((StgStablePtr, StgFunPtr));
1970 void performIO PROTO((StgStablePtr));
1971 I_ enterInt PROTO((StgStablePtr));
1972 I_ enterFloat PROTO((StgStablePtr));
1973 P_ deRefStablePointer PROTO((StgStablePtr));
1974 IF_RTS(I_ catchSoftHeapOverflow PROTO((StgStablePtr, I_));)
1975 IF_RTS(I_ getSoftHeapOverflowHandler(STG_NO_ARGS);)
1976 IF_RTS(extern StgStablePtr softHeapOverflowHandler;)
1977 IF_RTS(void shutdownHaskell(STG_NO_ARGS);)
1979 EXTFUN(stopPerformIODirectReturn);
1980 EXTFUN(startPerformIO);
1981 EXTFUN(stopEnterIntDirectReturn);
1982 EXTFUN(startEnterInt);
1983 EXTFUN(stopEnterFloatDirectReturn);
1984 EXTFUN(startEnterFloat);
1986 void enterStablePtr PROTO((StgStablePtr stableIndex, StgFunPtr startCode));
1988 char* createAdjustor PROTO((int cc,StgStablePtr hptr, StgFunPtr wptr));
1989 void freeAdjustor PROTO((void* ptr));
1993 IF_RTS(extern I_ ErrorIO_call_count;)
1996 Somewhat harder is @makeStablePointer#@ --- it is usually simple but
1997 if we're unlucky, it will have to allocate a new table and copy the
1998 old bit over. Since we might, very occasionally, have to call the
1999 garbage collector, this has to be a macro... sigh!
2001 NB @newSP@ is required because it is entirely possible that
2002 @stablePtr@ and @unstablePtr@ are aliases and so we can't do the
2003 assignment to @stablePtr@ until we've finished with @unstablePtr@.
2005 Another obscure piece of coding is the recalculation of the size of
2006 the table. We do this just in case Jim's threads decide they want to
2007 context switch---in which case any stack-allocated variables may get
2008 trashed. (If only there was a special heap check which didn't
2009 consider context switching...)
2014 /* Calculate SP Table size from number of pointers */
2015 #define SPTSizeFromNoPtrs( newNP ) (DYN_VHS + 1 + 2 * (newNP))
2017 /* Calculate number of pointers in new table from number in old table:
2018 any strictly increasing expression will do here */
2019 #define CalcNewNoSPtrs( i ) ((i)*2 + 100)
2021 void enlargeSPTable PROTO((P_, P_));
2023 #define makeStablePtrZh(stablePtr,liveness,unstablePtr) \
2025 EXTDATA_RO(StablePointerTable_info); \
2026 EXTDATA(UnusedSP); \
2027 StgStablePtr newSP; \
2029 if (SPT_EMPTY(StorageMgrInfo.StablePointerTable)) { /* free stack is empty */ \
2030 { /* Variables used before the heap check */ \
2031 I_ OldNoPtrs = SPT_NoPTRS( StorageMgrInfo.StablePointerTable ); \
2032 I_ NewNoPtrs = CalcNewNoSPtrs( OldNoPtrs ); \
2033 I_ NewSize = SPTSizeFromNoPtrs( NewNoPtrs ); \
2034 HEAP_CHK(liveness, _FHS+NewSize, 0); \
2036 { /* Variables used after the heap check - same values */ \
2037 I_ OldNoPtrs = SPT_NoPTRS( StorageMgrInfo.StablePointerTable ); \
2038 I_ NewNoPtrs = CalcNewNoSPtrs( OldNoPtrs ); \
2039 I_ NewSize = SPTSizeFromNoPtrs( NewNoPtrs ); \
2040 P_ SPTable = Hp + 1 - (_FHS + NewSize); \
2042 CC_ALLOC(CCC, _FHS+NewSize, SPT_K); /* cc prof */ \
2043 SET_DYN_HDR(SPTable,StablePointerTable_info,CCC,NewSize,NewNoPtrs);\
2044 SAFESTGCALL2(void, (void *, P_, P_), enlargeSPTable, SPTable, StorageMgrInfo.StablePointerTable); \
2045 StorageMgrInfo.StablePointerTable = SPTable; \
2049 newSP = SPT_POP(StorageMgrInfo.StablePointerTable); \
2050 SPT_SPTR(StorageMgrInfo.StablePointerTable, newSP) = unstablePtr; \
2051 CHECK_SPT_CLOSURE( StorageMgrInfo.StablePointerTable ); \
2052 stablePtr = newSP; \
2057 #define makeStablePtrZh(stablePtr,liveness,unstablePtr) \
2060 fprintf(stderr, "makeStablePtr#: no stable pointer support.\n");\
2061 EXIT(EXIT_FAILURE); \
2067 %************************************************************************
2069 \subsubsection[StgMacros-unsafePointerEquality]{Primitive `op' for breaking referential transparency}
2071 %************************************************************************
2073 The type of this is @reallyUnsafePtrEquality :: a -> a -> Int#@ so we
2074 can expect three parameters: the two arguments and a "register" to put
2077 Message to Will: This primop breaks referential transparency so badly
2078 you might want to leave it out. On the other hand, if you hide it
2079 away in an appropriate monad, it's perfectly safe. [ADR]
2081 Note that this primop is non-deterministic: different results can be
2082 obtained depending on just what the garbage collector (and code
2083 optimiser??) has done. However, we can guarantee that if two objects
2084 are pointer-equal, they have the same denotation --- the converse most
2085 certainly doesn't hold.
2087 ToDo ADR: The degree of non-determinism could be greatly reduced by
2088 following indirections.
2091 #define reallyUnsafePtrEqualityZh(r,a,b) r=((StgPtr)(a) == (StgPtr)(b))
2094 %************************************************************************
2096 \subsubsection[StgMacros-parallel-primop]{Primitive `op' for sparking (etc)}
2098 %************************************************************************
2100 Assuming local sparking in some form, we can now inline the spark request.
2102 We build a doubly-linked list in the heap, so that we can handle FIFO
2103 or LIFO scheduling as we please.
2105 Anything with tag >= 0 is in WHNF, so we discard it.
2110 ED_(PrelBase_Z91Z93_closure);
2114 #define parZh(r,node) \
2115 PARZh(r,node,1,0,0,0,0,0)
2117 #define parAtZh(r,node,where,identifier,gran_info,size_info,par_info,rest) \
2118 parATZh(r,node,where,identifier,gran_info,size_info,par_info,rest,1)
2120 #define parAtAbsZh(r,node,proc,identifier,gran_info,size_info,par_info,rest) \
2121 parATZh(r,node,proc,identifier,gran_info,size_info,par_info,rest,2)
2123 #define parAtRelZh(r,node,proc,identifier,gran_info,size_info,par_info,rest) \
2124 parATZh(r,node,proc,identifier,gran_info,size_info,par_info,rest,3)
2126 #define parAtForNowZh(r,node,where,identifier,gran_info,size_info,par_info,rest) \
2127 parATZh(r,node,where,identifier,gran_info,size_info,par_info,rest,0)
2129 #define parATZh(r,node,where,identifier,gran_info,size_info,par_info,rest,local) \
2132 if (SHOULD_SPARK(node)) { \
2135 result = NewSpark((P_)node,identifier,gran_info,size_info,par_info,local); \
2136 if (local==2) { /* special case for parAtAbs */ \
2137 GranSimSparkAtAbs(result,(I_)where,identifier);\
2138 } else if (local==3) { /* special case for parAtRel */ \
2139 GranSimSparkAtAbs(result,(I_)(CurrentProc+where),identifier); \
2141 GranSimSparkAt(result,where,identifier); \
2143 context_switch = 1; \
2145 RestoreAllStgRegs(); \
2146 } else if (do_qp_prof) { \
2147 I_ tid = threadId++; \
2148 SAFESTGCALL2(void,(I_, P_),QP_Event0,tid,node); \
2150 r = 1; /* return code for successful spark -- HWL */ \
2153 #define parLocalZh(r,node,identifier,gran_info,size_info,par_info,rest) \
2154 PARZh(r,node,rest,identifier,gran_info,size_info,par_info,1)
2156 #define parGlobalZh(r,node,identifier,gran_info,size_info,par_info,rest) \
2157 PARZh(r,node,rest,identifier,gran_info,size_info,par_info,0)
2161 #define PARZh(r,node,rest,identifier,gran_info,size_info,par_info,local) \
2163 if (SHOULD_SPARK(node)) { \
2166 result = NewSpark((P_)node,identifier,gran_info,size_info,par_info,local);\
2167 add_to_spark_queue(result); \
2168 GranSimSpark(local,(P_)node); \
2169 context_switch = 1; \
2171 RestoreAllStgRegs(); \
2172 } else if (do_qp_prof) { \
2173 I_ tid = threadId++; \
2174 SAFESTGCALL2(void,(I_, P_),QP_Event0,tid,node); \
2176 r = 1; /* return code for successful spark -- HWL */ \
2181 #define PARZh(r,node,rest,identifier,gran_info,size_info,par_info,local) \
2184 if (SHOULD_SPARK(node)) { \
2185 result = NewSpark((P_)node,identifier,gran_info,size_info,par_info,local);\
2186 ADD_TO_SPARK_QUEUE(result); \
2187 SAFESTGCALL2(void,(W_),GranSimSpark,local,(P_)node); \
2188 /* context_switch = 1; not needed any more -- HWL */ \
2189 } else if (do_qp_prof) { \
2190 I_ tid = threadId++; \
2191 SAFESTGCALL2(void,(I_, P_),QP_Event0,tid,node); \
2193 r = 1; /* return code for successful spark -- HWL */ \
2198 #define copyableZh(r,node) \
2199 /* copyable not yet implemented!! */
2201 #define noFollowZh(r,node) \
2202 /* noFollow not yet implemented!! */
2206 extern I_ required_thread_count;
2209 #define COUNT_SPARK TSO_GLOBALSPARKS(CurrentTSO)++; sparksCreated++
2215 Note that we must bump the required thread count NOW, rather
2216 than when the thread is actually created.
2219 #define forkZh(r,liveness,node) \
2221 while (PendingSparksTl[REQUIRED_POOL] == PendingSparksLim[REQUIRED_POOL]) \
2222 DO_YIELD((liveness << 1) | 1); \
2224 if (SHOULD_SPARK(node)) { \
2225 *PendingSparksTl[REQUIRED_POOL]++ = (P_)(node); \
2226 } else if (DO_QP_PROF) { \
2227 I_ tid = threadId++; \
2228 SAFESTGCALL2(void,(I_, P_),QP_Event0,tid,node); \
2230 required_thread_count++; \
2231 context_switch = 1; \
2232 r = 1; /* Should not be necessary */ \
2235 #define parZh(r,node) \
2238 if (SHOULD_SPARK(node) && \
2239 PendingSparksTl[ADVISORY_POOL] < PendingSparksLim[ADVISORY_POOL]) { \
2240 *PendingSparksTl[ADVISORY_POOL]++ = (P_)(node); \
2244 I_ tid = threadId++; \
2245 SAFESTGCALL2(void,(I_, P_),QP_Event0,tid,node); \
2248 r = 1; /* Should not be necessary */ \
2253 #endif /* CONCURRENT */
2256 The following seq# code should only be used in unoptimized code.
2257 Be warned: it's a potential bug-farm.
2259 Yes, it completely fails to work for function values, since a PAP
2260 closure will be constructed when the arg satisfaction check fails.
2261 This PAP closure will add the magic values that gets pushed on the B stack
2262 before entering the 'seqee' (new word!), as Jim is just about to tell
2263 us about. Let's hear what he's got to say:
2266 First we push two words on the B stack: the current value of RetReg
2267 (which may or may not be live), and a continuation snatched largely out
2268 of thin air (it's a point within this code block). Then we set RetReg
2269 to the special polymorphic return code for seq, load up Node with the
2270 closure to be evaluated, and we're off. When the eval returns to the
2271 polymorphic seq return point, the two words are popped off the B stack,
2272 RetReg is restored, and we jump to the continuation, completing the
2273 primop and going on our merry way.
2275 [ To workaround the shortcoming of not being able to deal with partially
2276 applied values, we explicitly prohibit this at the Haskell source level
2277 (i.e., we don't define an Eval instance for (->) ).
2284 #define seqZh(r,liveness,node) \
2287 /* STK_CHK(liveness,0,2,0,0,0,0); */ \
2288 /* SpB -= BREL(2); */ \
2289 SpB[BREL(0)] = (W_) RetReg; \
2290 SpB[BREL(1)] = (W_) &&cont; \
2291 RetReg = (StgRetAddr) vtbl_seq; \
2294 InfoPtr = (D_)(INFO_PTR(Node)); \
2295 JMP_(ENTRY_CODE(InfoPtr)); \
2297 r = 1; /* Should be unnecessary */ \
2302 %************************************************************************
2304 \subsubsection[StgMacros-foreign-objects]{Foreign Objects}
2306 %************************************************************************
2308 [Based on previous MallocPtr comments -- SOF]
2310 This macro is used to construct a ForeignObj on the heap.
2312 What this does is plug the pointer (which will be in a local
2313 variable) together with its finalising/free routine, into a fresh heap
2314 object and then sets a result (which will be a register) to point
2315 to the fresh heap object.
2317 To accommodate per-object finalisation, augment the macro with a
2318 finalisation routine argument. Nothing spectacular, just plug the
2319 pointer to the routine into the ForeignObj -- SOF 4/96
2321 Question: what's this "SET_ACTIVITY" stuff - should I be doing this
2322 too? (It's if you want to use the SPAT profiling tools to
2323 characterize program behavior by ``activity'' -- tail-calling,
2324 heap-checking, etc. -- see Ticky.lh. It is quite specialized.
2327 (Swapped first two arguments to make it come into line with what appears
2328 to be `standard' format, return register then liveness mask. -- SOF 4/96)
2333 StgInt eqForeignObj PROTO((StgForeignObj p1, StgForeignObj p2));
2334 StgInt eqStablePtr PROTO((StgStablePtr p1, StgStablePtr p2));
2336 #define makeForeignObjZh(r, liveness, mptr, finalise) \
2340 HEAP_CHK((W_)liveness, _FHS + ForeignObj_SIZE,0); \
2341 CC_ALLOC(CCC,_FHS + ForeignObj_SIZE,ForeignObj_K); /* cc prof */ \
2343 result = Hp + 1 - (_FHS + ForeignObj_SIZE); \
2344 SET_ForeignObj_HDR(result,ForeignObj_info,CCC,_FHS + ForeignObj_SIZE,0); \
2345 ForeignObj_CLOSURE_DATA(result) = (P_)mptr; \
2346 ForeignObj_CLOSURE_FINALISER(result) = (P_)finalise; \
2347 ForeignObj_CLOSURE_LINK(result) = StorageMgrInfo.ForeignObjList; \
2348 StorageMgrInfo.ForeignObjList = result; \
2351 /*fprintf(stderr,"DEBUG: ForeignObj(0x%x) = <0x%x, 0x%x, 0x%x, 0x%x>\n", \
2353 result[0],result[1], \
2354 result[2],result[3]);*/ \
2356 CHECK_ForeignObj_CLOSURE( result ); \
2357 VALIDATE_ForeignObjList( StorageMgrInfo.ForeignObjList ); \
2359 (r) = (P_) result; \
2362 #define writeForeignObjZh(res,datum) ((PP_) ForeignObj_CLOSURE_DATA(res)) = ((P_)datum)
2365 #define makeForeignObjZh(r, liveness, mptr, finalise) \
2368 fprintf(stderr, "makeForeignObj#: no foreign object support.\n");\
2369 EXIT(EXIT_FAILURE); \
2372 #define writeForeignObjZh(res,datum) \
2375 fprintf(stderr, "writeForeignObj#: no foreign object support.\n");\
2376 EXIT(EXIT_FAILURE); \
2383 End-of-file's multi-slurp protection:
2385 #endif /* ! STGMACROS_H */