[project @ 2003-04-28 09:57:12 by simonmar]
[ghc-hetmet.git] / ghc / includes / StgMacros.h
1 /* -----------------------------------------------------------------------------
2  * $Id: StgMacros.h,v 1.52 2003/04/28 09:57:12 simonmar Exp $
3  *
4  * (c) The GHC Team, 1998-1999
5  *
6  * Macros used for writing STG-ish C code.
7  *
8  * ---------------------------------------------------------------------------*/
9
10 #ifndef STGMACROS_H
11 #define STGMACROS_H
12
13 /* -----------------------------------------------------------------------------
14   The following macros create function headers.
15
16   Each basic block is represented by a C function with no arguments.
17   We therefore always begin with either
18
19   extern F_ f(void)
20
21   or
22   
23   static F_ f(void)
24
25   The macros can be used either to define the function itself, or to provide
26   prototypes (by following with a ';').
27
28   Note: the various I*_ shorthands in the second block below are used to
29   declare forward references to local symbols. These shorthands *have* to
30   use the 'extern' type specifier and not 'static'. The reason for this is
31   that 'static' declares a reference as being a static/local variable,
32   and *not* as a forward reference to a static variable.
33
34   This might seem obvious, but it had me stumped as to why my info tables
35   were suddenly all filled with 0s.
36
37     -- sof 1/99 
38
39   --------------------------------------------------------------------------- */
40
41 #define STGFUN(f)       StgFunPtr f(void)
42 #define EXTFUN(f)       extern StgFunPtr f(void)
43 #define EXTFUN_RTS(f)   extern DLL_IMPORT_RTS StgFunPtr f(void)
44 #define FN_(f)          F_ f(void)
45 #define IF_(f)          static F_ f(void)
46 #define EF_(f)          extern F_ f(void)
47 #define EDF_(f)         extern DLLIMPORT F_ f(void)
48
49 #define EXTINFO_RTS     extern DLL_IMPORT_RTS const StgInfoTable
50 #define ETI_RTS         extern DLL_IMPORT_RTS const StgThunkInfoTable
51
52 // Info tables as generated by the compiler are simply arrays of words.
53 typedef StgWord StgWordArray[];
54
55 #define ED_             extern
56 #define EDD_            extern DLLIMPORT
57 #define ED_RO_          extern const
58 #define ID_             static
59 #define ID_RO_          static const
60 #define EI_             extern StgWordArray
61 #define ERI_            extern const StgRetInfoTable
62 #define II_             static StgWordArray
63 #define IRI_            static const StgRetInfoTable
64 #define EC_             extern StgClosure
65 #define EDC_            extern DLLIMPORT StgClosure
66 #define IC_             static StgClosure
67 #define ECP_(x)         extern const StgClosure *(x)[]
68 #define EDCP_(x)        extern DLLIMPORT StgClosure *(x)[]
69 #define ICP_(x)         static const StgClosure *(x)[]
70
71 /* -----------------------------------------------------------------------------
72    Entering 
73
74    It isn't safe to "enter" every closure.  Functions in particular
75    have no entry code as such; their entry point contains the code to
76    apply the function.
77    -------------------------------------------------------------------------- */
78
79 #define ENTER()                                 \
80  {                                              \
81  again:                                         \
82   switch (get_itbl(R1.cl)->type) {              \
83   case IND:                                     \
84   case IND_OLDGEN:                              \
85   case IND_PERM:                                \
86   case IND_OLDGEN_PERM:                         \
87   case IND_STATIC:                              \
88       R1.cl = ((StgInd *)R1.cl)->indirectee;    \
89       goto again;                               \
90   case BCO:                                     \
91   case FUN:                                     \
92   case FUN_1_0:                                 \
93   case FUN_0_1:                                 \
94   case FUN_2_0:                                 \
95   case FUN_1_1:                                 \
96   case FUN_0_2:                                 \
97   case FUN_STATIC:                              \
98   case PAP:                                     \
99       JMP_(ENTRY_CODE(Sp[0]));                  \
100   default:                                      \
101       JMP_(GET_ENTRY(R1.cl));                   \
102   }                                             \
103  }
104
105 /* -----------------------------------------------------------------------------
106    Heap/Stack Checks.
107
108    When failing a check, we save a return address on the stack and
109    jump to a pre-compiled code fragment that saves the live registers
110    and returns to the scheduler.
111
112    The return address in most cases will be the beginning of the basic
113    block in which the check resides, since we need to perform the check
114    again on re-entry because someone else might have stolen the resource
115    in the meantime.
116    ------------------------------------------------------------------------- */
117
118 #define STK_CHK_FUN(headroom,assts)             \
119         if (Sp - headroom < SpLim) {            \
120             assts                               \
121             JMP_(stg_gc_fun);                   \
122         }
123
124 #define HP_CHK_FUN(headroom,assts)                                      \
125         DO_GRAN_ALLOCATE(headroom)                                      \
126         if ((Hp += headroom) > HpLim) {                                 \
127             HpAlloc = (headroom);                                       \
128             assts                                                       \
129             JMP_(stg_gc_fun);                                           \
130         }
131
132 // When doing both a heap and a stack check, don't move the heap
133 // pointer unless the stack check succeeds.  Otherwise we might end up
134 // with slop at the end of the current block, which can confuse the
135 // LDV profiler.
136 #define HP_STK_CHK_FUN(stk_headroom,hp_headroom,assts)                  \
137         DO_GRAN_ALLOCATE(hp_headroom)                                   \
138         if (Sp - stk_headroom < SpLim || (Hp += hp_headroom) > HpLim) { \
139             HpAlloc = (hp_headroom);                                    \
140             assts                                                       \
141             JMP_(stg_gc_fun);                                           \
142         }
143
144 /* -----------------------------------------------------------------------------
145    A Heap Check in a case alternative are much simpler: everything is
146    on the stack and covered by a liveness mask already, and there is
147    even a return address with an SRT info table there as well.  
148
149    Just push R1 and return to the scheduler saying 'EnterGHC'
150
151    {STK,HP,HP_STK}_CHK_NP are the various checking macros for
152    bog-standard case alternatives, thunks, and non-top-level
153    functions.  In all these cases, node points to a closure that we
154    can just enter to restart the heap check (the NP stands for 'node points').
155
156    In the NP case GranSim absolutely has to check whether the current node 
157    resides on the current processor. Otherwise a FETCH event has to be
158    scheduled. All that is done in GranSimFetch. -- HWL
159
160    HpLim points to the LAST WORD of valid allocation space.
161    -------------------------------------------------------------------------- */
162
163 #define STK_CHK_NP(headroom,tag_assts)          \
164         if ((Sp - (headroom)) < SpLim) {        \
165             tag_assts                           \
166             JMP_(stg_gc_enter_1);               \
167         }
168
169 #define HP_CHK_NP(headroom,tag_assts)                                   \
170         DO_GRAN_ALLOCATE(headroom)                                      \
171         if ((Hp += (headroom)) > HpLim) {                               \
172             HpAlloc = (headroom);                                       \
173             tag_assts                                                   \
174             JMP_(stg_gc_enter_1);                                       \
175         }                                                       
176
177 // See comment on HP_STK_CHK_FUN above.
178 #define HP_STK_CHK_NP(stk_headroom, hp_headroom, tag_assts) \
179         DO_GRAN_ALLOCATE(hp_headroom)                              \
180         if ((Sp - (stk_headroom)) < SpLim || (Hp += (hp_headroom)) > HpLim) { \
181             HpAlloc = (hp_headroom);                            \
182             tag_assts                                           \
183             JMP_(stg_gc_enter_1);                               \
184         }                                                       
185
186
187 /* Heap checks for branches of a primitive case / unboxed tuple return */
188
189 #define GEN_HP_CHK_ALT(headroom,lbl,tag_assts)                  \
190         DO_GRAN_ALLOCATE(headroom)                              \
191         if ((Hp += (headroom)) > HpLim) {                       \
192             HpAlloc = (headroom);                               \
193             tag_assts                                           \
194             JMP_(lbl);                                          \
195         }                                                       
196
197 #define HP_CHK_NOREGS(headroom,tag_assts) \
198     GEN_HP_CHK_ALT(headroom,stg_gc_noregs,tag_assts);
199 #define HP_CHK_UNPT_R1(headroom,tag_assts)  \
200     GEN_HP_CHK_ALT(headroom,stg_gc_unpt_r1,tag_assts);
201 #define HP_CHK_UNBX_R1(headroom,tag_assts)  \
202     GEN_HP_CHK_ALT(headroom,stg_gc_unbx_r1,tag_assts);
203 #define HP_CHK_F1(headroom,tag_assts)       \
204     GEN_HP_CHK_ALT(headroom,stg_gc_f1,tag_assts);
205 #define HP_CHK_D1(headroom,tag_assts)       \
206     GEN_HP_CHK_ALT(headroom,stg_gc_d1,tag_assts);
207 #define HP_CHK_L1(headroom,tag_assts)       \
208     GEN_HP_CHK_ALT(headroom,stg_gc_l1,tag_assts);
209
210 /* -----------------------------------------------------------------------------
211    Generic Heap checks.
212
213    These are slow, but have the advantage of being usable in a variety
214    of situations.  
215
216    The one restriction is that any relevant SRTs must already be pointed
217    to from the stack.  The return address doesn't need to have an info
218    table attached: hence it can be any old code pointer.
219
220    The liveness mask is a logical 'XOR' of NO_PTRS and zero or more
221    Rn_PTR constants defined below.  All registers will be saved, but
222    the garbage collector needs to know which ones contain pointers.
223
224    Good places to use a generic heap check: 
225
226         - case alternatives (the return address with an SRT is already
227           on the stack).
228
229         - primitives (no SRT required).
230
231    The stack frame layout for a RET_DYN is like this:
232
233           some pointers         |-- GET_PTRS(liveness) words
234           some nonpointers      |-- GET_NONPTRS(liveness) words
235                                
236           L1                    \
237           D1-2                  |-- RET_DYN_NONPTR_REGS_SIZE words
238           F1-4                  /
239                                
240           R1-8                  |-- RET_DYN_BITMAP_SIZE words
241                                
242           return address        \
243           liveness mask         |-- StgRetDyn structure
244           stg_gen_chk_info      /
245
246    we assume that the size of a double is always 2 pointers (wasting a
247    word when it is only one pointer, but avoiding lots of #ifdefs).
248
249    NOTE: if you change the layout of RET_DYN stack frames, then you
250    might also need to adjust the value of RESERVED_STACK_WORDS in
251    Constants.h.
252    -------------------------------------------------------------------------- */
253
254 // VERY MAGIC CONSTANTS! 
255 // must agree with code in HeapStackCheck.c, stg_gen_chk, and
256 // RESERVED_STACK_WORDS in Constants.h.
257 //
258 #define RET_DYN_BITMAP_SIZE 8
259 #define RET_DYN_NONPTR_REGS_SIZE 10
260 #define ALL_NON_PTRS 0xff
261
262 #define LIVENESS_MASK(ptr_regs)  (ALL_NON_PTRS ^ (ptr_regs))
263
264 // We can have up to 255 pointers and 255 nonpointers in the stack
265 // frame.
266 #define N_NONPTRS(n)  ((n)<<16)
267 #define N_PTRS(n)     ((n)<<24)
268
269 #define GET_NONPTRS(l) ((l)>>16 & 0xff)
270 #define GET_PTRS(l)    ((l)>>24 & 0xff)
271 #define GET_LIVENESS(l) ((l) & 0xffff)
272
273 #define NO_PTRS   0
274 #define R1_PTR    1<<0
275 #define R2_PTR    1<<1
276 #define R3_PTR    1<<2
277 #define R4_PTR    1<<3
278 #define R5_PTR    1<<4
279 #define R6_PTR    1<<5
280 #define R7_PTR    1<<6
281 #define R8_PTR    1<<7
282
283 #define HP_CHK_UNBX_TUPLE(headroom,liveness,code)       \
284    if ((Hp += (headroom)) > HpLim ) {                   \
285         HpAlloc = (headroom);                           \
286         code                                            \
287         R9.w = (W_)LIVENESS_MASK(liveness);             \
288         JMP_(stg_gc_ut);                                \
289     }                                                       
290
291 #define HP_CHK_GEN(headroom,liveness,reentry)                   \
292    if ((Hp += (headroom)) > HpLim ) {                           \
293         HpAlloc = (headroom);                                   \
294         R9.w = (W_)LIVENESS_MASK(liveness);                     \
295         R10.w = (W_)reentry;                                    \
296         JMP_(stg_gc_gen);                                       \
297     }                                                       
298
299 #define HP_CHK_GEN_TICKY(headroom,liveness,reentry)     \
300    HP_CHK_GEN(headroom,liveness,reentry);               \
301    TICK_ALLOC_HEAP_NOCTR(headroom)
302
303 #define STK_CHK_GEN(headroom,liveness,reentry)  \
304    if ((Sp - (headroom)) < SpLim) {                             \
305         R9.w = (W_)LIVENESS_MASK(liveness);                     \
306         R10.w = (W_)reentry;                                    \
307         JMP_(stg_gc_gen);                                       \
308    }
309
310 #define MAYBE_GC(liveness,reentry)              \
311    if (doYouWantToGC()) {                       \
312         R9.w = (W_)LIVENESS_MASK(liveness);     \
313         R10.w = (W_)reentry;                    \
314         JMP_(stg_gc_gen_hp);                    \
315    }
316
317 /* -----------------------------------------------------------------------------
318    Voluntary Yields/Blocks
319
320    We only have a generic version of this at the moment - if it turns
321    out to be slowing us down we can make specialised ones.
322    -------------------------------------------------------------------------- */
323
324 EXTFUN_RTS(stg_gen_yield);
325 EXTFUN_RTS(stg_gen_block);
326
327 #define YIELD(liveness,reentry)                 \
328   {                                             \
329    R9.w  = (W_)LIVENESS_MASK(liveness);         \
330    R10.w = (W_)reentry;                         \
331    JMP_(stg_gen_yield);                         \
332   }
333
334 #define BLOCK(liveness,reentry)                 \
335   {                                             \
336    R9.w  = (W_)LIVENESS_MASK(liveness);         \
337    R10.w = (W_)reentry;                         \
338    JMP_(stg_gen_block);                         \
339   }
340
341 #define BLOCK_NP(ptrs)                          \
342   {                                             \
343     EXTFUN_RTS(stg_block_##ptrs);                       \
344     JMP_(stg_block_##ptrs);                     \
345   }
346
347 #if defined(PAR)
348 /*
349   Similar to BLOCK_NP but separates the saving of the thread state from the
350   actual jump via an StgReturn
351 */
352
353 #define SAVE_THREAD_STATE(ptrs)                  \
354   ASSERT(ptrs==1);                               \
355   Sp -= 1;                                       \
356   Sp[0] = R1.w;                                  \
357   SaveThreadState();                             
358
359 #define THREAD_RETURN(ptrs)                      \
360   ASSERT(ptrs==1);                               \
361   CurrentTSO->what_next = ThreadEnterGHC;        \
362   R1.i = ThreadBlocked;                          \
363   JMP_(StgReturn);                               
364 #endif
365
366 /* -----------------------------------------------------------------------------
367    CCall_GC needs to push a dummy stack frame containing the contents
368    of volatile registers and variables.  
369
370    We use a RET_DYN frame the same as for a dynamic heap check.
371    ------------------------------------------------------------------------- */
372
373 /* -----------------------------------------------------------------------------
374    Vectored Returns
375
376    RETVEC(p,t) where 'p' is a pointer to the info table for a
377    vectored return address, returns the address of the return code for
378    tag 't'.
379
380    Return vectors are placed in *reverse order* immediately before the info
381    table for the return address.  Hence the formula for computing the
382    actual return address is (addr - sizeof(RetInfoTable) - tag - 1).
383    The extra subtraction of one word is because tags start at zero.
384    -------------------------------------------------------------------------- */
385
386 #ifdef TABLES_NEXT_TO_CODE
387 #define RET_VEC(p,t) (*((P_)(p) - sizeofW(StgRetInfoTable) - t - 1))
388 #else
389 #define RET_VEC(p,t) (((StgRetInfoTable *)p)->vector[t])
390 #endif
391
392 /* -----------------------------------------------------------------------------
393    Misc
394    -------------------------------------------------------------------------- */
395
396
397 /* set the tag register (if we have one) */
398 #define SET_TAG(t)  /* nothing */
399
400 #ifdef EAGER_BLACKHOLING
401 #  ifdef SMP
402 #    define UPD_BH_UPDATABLE(info)                              \
403         TICK_UPD_BH_UPDATABLE();                                \
404         {                                                       \
405           bdescr *bd = Bdescr(R1.p);                            \
406           if (bd->u.back != (bdescr *)BaseReg) {                \
407              if (bd->gen_no >= 1 || bd->step->no >= 1) {        \
408                  LOCK_THUNK(info);                              \
409              } else {                                           \
410                  EXTFUN_RTS(stg_gc_enter_1_hponly);             \
411                  JMP_(stg_gc_enter_1_hponly);                   \
412              }                                                  \
413           }                                                     \
414         }                                                       \
415         SET_INFO(R1.cl,&stg_BLACKHOLE_info)
416 #    define UPD_BH_SINGLE_ENTRY(info)                           \
417         TICK_UPD_BH_SINGLE_ENTRY();                             \
418         {                                                       \
419           bdescr *bd = Bdescr(R1.p);                            \
420           if (bd->u.back != (bdescr *)BaseReg) {                \
421              if (bd->gen_no >= 1 || bd->step->no >= 1) {        \
422                  LOCK_THUNK(info);                              \
423              } else {                                           \
424                  EXTFUN_RTS(stg_gc_enter_1_hponly);             \
425                  JMP_(stg_gc_enter_1_hponly);                   \
426              }                                                  \
427           }                                                     \
428         }                                                       \
429         SET_INFO(R1.cl,&stg_BLACKHOLE_info)
430 #  else
431 #   ifndef PROFILING
432 #    define UPD_BH_UPDATABLE(info)              \
433         TICK_UPD_BH_UPDATABLE();                \
434         SET_INFO(R1.cl,&stg_BLACKHOLE_info)
435 #    define UPD_BH_SINGLE_ENTRY(info)           \
436         TICK_UPD_BH_SINGLE_ENTRY();             \
437         SET_INFO(R1.cl,&stg_SE_BLACKHOLE_info)
438 #   else
439 // An object is replaced by a blackhole, so we fill the slop with zeros.
440 // 
441 // Todo: maybe use SET_HDR() and remove LDV_recordCreate()?
442 // 
443 #    define UPD_BH_UPDATABLE(info)              \
444         TICK_UPD_BH_UPDATABLE();                \
445         LDV_recordDead_FILL_SLOP_DYNAMIC(R1.cl);               \
446         SET_INFO(R1.cl,&stg_BLACKHOLE_info);    \
447         LDV_recordCreate(R1.cl)
448 #    define UPD_BH_SINGLE_ENTRY(info)           \
449         TICK_UPD_BH_SINGLE_ENTRY();             \
450         LDV_recordDead_FILL_SLOP_DYNAMIC(R1.cl);               \
451         SET_INFO(R1.cl,&stg_SE_BLACKHOLE_info)  \
452         LDV_recordCreate(R1.cl)
453 #   endif /* PROFILING */
454 #  endif
455 #else /* !EAGER_BLACKHOLING */
456 #  define UPD_BH_UPDATABLE(thunk)    /* nothing */
457 #  define UPD_BH_SINGLE_ENTRY(thunk) /* nothing */
458 #endif /* EAGER_BLACKHOLING */
459
460 #define UPD_FRAME_UPDATEE(p)  ((P_)(((StgUpdateFrame *)(p))->updatee))
461
462 /* -----------------------------------------------------------------------------
463    Moving Floats and Doubles
464
465    ASSIGN_FLT is for assigning a float to memory (usually the
466               stack/heap).  The memory address is guaranteed to be
467               StgWord aligned (currently == sizeof(void *)).
468
469    PK_FLT     is for pulling a float out of memory.  The memory is
470               guaranteed to be StgWord aligned.
471    -------------------------------------------------------------------------- */
472
473 static inline void        ASSIGN_FLT (W_ [], StgFloat);
474 static inline StgFloat    PK_FLT     (W_ []);
475
476 #if ALIGNMENT_FLOAT <= ALIGNMENT_LONG
477
478 static inline void     ASSIGN_FLT(W_ p_dest[], StgFloat src) { *(StgFloat *)p_dest = src; }
479 static inline StgFloat PK_FLT    (W_ p_src[])                { return *(StgFloat *)p_src; }
480
481 #else  /* ALIGNMENT_FLOAT > ALIGNMENT_UNSIGNED_INT */
482
483 static inline void ASSIGN_FLT(W_ p_dest[], StgFloat src)
484 {
485     float_thing y;
486     y.f = src;
487     *p_dest = y.fu;
488 }
489
490 static inline StgFloat PK_FLT(W_ p_src[])
491 {
492     float_thing y;
493     y.fu = *p_src;
494     return(y.f);
495 }
496
497 #endif /* ALIGNMENT_FLOAT > ALIGNMENT_LONG */
498
499 #if ALIGNMENT_DOUBLE <= ALIGNMENT_LONG
500
501 static inline void        ASSIGN_DBL (W_ [], StgDouble);
502 static inline StgDouble   PK_DBL     (W_ []);
503
504 static inline void      ASSIGN_DBL(W_ p_dest[], StgDouble src) { *(StgDouble *)p_dest = src; }
505 static inline StgDouble PK_DBL    (W_ p_src[])                 { return *(StgDouble *)p_src; }
506
507 #else   /* ALIGNMENT_DOUBLE > ALIGNMENT_LONG */
508
509 /* Sparc uses two floating point registers to hold a double.  We can
510  * write ASSIGN_DBL and PK_DBL by directly accessing the registers
511  * independently - unfortunately this code isn't writable in C, we
512  * have to use inline assembler.
513  */
514 #if sparc_TARGET_ARCH
515
516 #define ASSIGN_DBL(dst0,src) \
517     { StgPtr dst = (StgPtr)(dst0); \
518       __asm__("st %2,%0\n\tst %R2,%1" : "=m" (((P_)(dst))[0]), \
519         "=m" (((P_)(dst))[1]) : "f" (src)); \
520     }
521
522 #define PK_DBL(src0) \
523     ( { StgPtr src = (StgPtr)(src0); \
524         register double d; \
525       __asm__("ld %1,%0\n\tld %2,%R0" : "=f" (d) : \
526         "m" (((P_)(src))[0]), "m" (((P_)(src))[1])); d; \
527     } )
528
529 #else /* ! sparc_TARGET_ARCH */
530
531 static inline void        ASSIGN_DBL (W_ [], StgDouble);
532 static inline StgDouble   PK_DBL     (W_ []);
533
534 typedef struct
535   { StgWord dhi;
536     StgWord dlo;
537   } unpacked_double;
538
539 typedef union
540   { StgDouble d;
541     unpacked_double du;
542   } double_thing;
543
544 static inline void ASSIGN_DBL(W_ p_dest[], StgDouble src)
545 {
546     double_thing y;
547     y.d = src;
548     p_dest[0] = y.du.dhi;
549     p_dest[1] = y.du.dlo;
550 }
551
552 /* GCC also works with this version, but it generates
553    the same code as the previous one, and is not ANSI
554
555 #define ASSIGN_DBL( p_dest, src ) \
556         *p_dest = ((double_thing) src).du.dhi; \
557         *(p_dest+1) = ((double_thing) src).du.dlo \
558 */
559
560 static inline StgDouble PK_DBL(W_ p_src[])
561 {
562     double_thing y;
563     y.du.dhi = p_src[0];
564     y.du.dlo = p_src[1];
565     return(y.d);
566 }
567
568 #endif /* ! sparc_TARGET_ARCH */
569
570 #endif /* ALIGNMENT_DOUBLE > ALIGNMENT_UNSIGNED_INT */
571
572 #ifdef SUPPORT_LONG_LONGS
573
574 typedef struct
575   { StgWord dhi;
576     StgWord dlo;
577   } unpacked_double_word;
578
579 typedef union
580   { StgInt64 i;
581     unpacked_double_word iu;
582   } int64_thing;
583
584 typedef union
585   { StgWord64 w;
586     unpacked_double_word wu;
587   } word64_thing;
588
589 static inline void ASSIGN_Word64(W_ p_dest[], StgWord64 src)
590 {
591     word64_thing y;
592     y.w = src;
593     p_dest[0] = y.wu.dhi;
594     p_dest[1] = y.wu.dlo;
595 }
596
597 static inline StgWord64 PK_Word64(W_ p_src[])
598 {
599     word64_thing y;
600     y.wu.dhi = p_src[0];
601     y.wu.dlo = p_src[1];
602     return(y.w);
603 }
604
605 static inline void ASSIGN_Int64(W_ p_dest[], StgInt64 src)
606 {
607     int64_thing y;
608     y.i = src;
609     p_dest[0] = y.iu.dhi;
610     p_dest[1] = y.iu.dlo;
611 }
612
613 static inline StgInt64 PK_Int64(W_ p_src[])
614 {
615     int64_thing y;
616     y.iu.dhi = p_src[0];
617     y.iu.dlo = p_src[1];
618     return(y.i);
619 }
620
621 #elif SIZEOF_VOID_P == 8
622
623 static inline void ASSIGN_Word64(W_ p_dest[], StgWord64 src)
624 {
625         p_dest[0] = src;
626 }
627
628 static inline StgWord64 PK_Word64(W_ p_src[])
629 {
630     return p_src[0];
631 }
632
633 static inline void ASSIGN_Int64(W_ p_dest[], StgInt64 src)
634 {
635     p_dest[0] = src;
636 }
637
638 static inline StgInt64 PK_Int64(W_ p_src[])
639 {
640     return p_src[0];
641 }
642
643 #endif
644
645 /* -----------------------------------------------------------------------------
646    Catch frames
647    -------------------------------------------------------------------------- */
648
649 extern DLL_IMPORT_RTS const StgPolyInfoTable stg_catch_frame_info;
650
651 /* -----------------------------------------------------------------------------
652    Split markers
653    -------------------------------------------------------------------------- */
654
655 #if defined(USE_SPLIT_MARKERS)
656 #if defined(LEADING_UNDERSCORE)
657 #define __STG_SPLIT_MARKER __asm__("\n___stg_split_marker:");
658 #else
659 #define __STG_SPLIT_MARKER __asm__("\n__stg_split_marker:");
660 #endif
661 #else
662 #define __STG_SPLIT_MARKER /* nothing */
663 #endif
664
665 /* -----------------------------------------------------------------------------
666    Closure and Info Macros with casting.
667
668    We don't want to mess around with casts in the generated C code, so
669    we use this casting versions of the closure macro.
670
671    This version of SET_HDR also includes CCS_ALLOC for profiling - the
672    reason we don't use two separate macros is that the cost centre
673    field is sometimes a non-simple expression and we want to share its
674    value between SET_HDR and CCS_ALLOC.
675    -------------------------------------------------------------------------- */
676
677 #define SET_HDR_(c,info,ccs,size)                               \
678   {                                                             \
679       CostCentreStack *tmp = (ccs);                             \
680       SET_HDR((StgClosure *)(c),(StgInfoTable *)(info),tmp);    \
681       CCS_ALLOC(tmp,size);                                      \
682   }
683
684 /* -----------------------------------------------------------------------------
685    Saving context for exit from the STG world, and loading up context
686    on entry to STG code.
687
688    We save all the STG registers (that is, the ones that are mapped to
689    machine registers) in their places in the TSO.  
690
691    The stack registers go into the current stack object, and the
692    current nursery is updated from the heap pointer.
693
694    These functions assume that BaseReg is loaded appropriately (if
695    we have one).
696    -------------------------------------------------------------------------- */
697
698 #if IN_STG_CODE
699
700 static __inline__ void
701 SaveThreadState(void)
702 {
703   StgTSO *tso;
704
705   /* Don't need to save REG_Base, it won't have changed. */
706
707   tso = CurrentTSO;
708   tso->sp       = Sp;
709   CloseNursery(Hp);
710
711 #ifdef REG_CurrentTSO
712   SAVE_CurrentTSO = tso;
713 #endif
714 #ifdef REG_CurrentNursery
715   SAVE_CurrentNursery = CurrentNursery;
716 #endif
717 #if defined(PROFILING)
718   CurrentTSO->prof.CCCS = CCCS;
719 #endif
720 }
721
722 static __inline__ void 
723 LoadThreadState (void)
724 {
725   StgTSO *tso;
726
727 #ifdef REG_CurrentTSO
728   CurrentTSO = SAVE_CurrentTSO;
729 #endif
730
731   tso = CurrentTSO;
732   Sp    = tso->sp;
733   SpLim = (P_)&(tso->stack) + RESERVED_STACK_WORDS;
734   OpenNursery(Hp,HpLim);
735
736 #ifdef REG_CurrentNursery
737   CurrentNursery = SAVE_CurrentNursery;
738 #endif
739 # if defined(PROFILING)
740   CCCS = CurrentTSO->prof.CCCS;
741 # endif
742 }
743
744 #endif
745
746 /* -----------------------------------------------------------------------------
747    Module initialisation
748
749    The module initialisation code looks like this, roughly:
750
751         FN(__stginit_Foo) {
752           JMP_(__stginit_Foo_1_p)
753         }
754
755         FN(__stginit_Foo_1_p) {
756         ...
757         }
758
759    We have one version of the init code with a module version and the
760    'way' attached to it.  The version number helps to catch cases
761    where modules are not compiled in dependency order before being
762    linked: if a module has been compiled since any modules which depend on
763    it, then the latter modules will refer to a different version in their
764    init blocks and a link error will ensue.
765
766    The 'way' suffix helps to catch cases where modules compiled in different
767    ways are linked together (eg. profiled and non-profiled).
768
769    We provide a plain, unadorned, version of the module init code
770    which just jumps to the version with the label and way attached.  The
771    reason for this is that when using foreign exports, the caller of
772    startupHaskell() must supply the name of the init function for the "top"
773    module in the program, and we don't want to require that this name
774    has the version and way info appended to it.
775    -------------------------------------------------------------------------- */
776
777 #define PUSH_INIT_STACK(reg_function)           \
778         *(Sp++) = (W_)reg_function
779
780 #define POP_INIT_STACK()                        \
781         *(--Sp)
782
783 #define MOD_INIT_WRAPPER(label,real_init)       \
784
785
786 #define START_MOD_INIT(plain_lbl, real_lbl)     \
787         static int _module_registered = 0;      \
788         EF_(real_lbl);                          \
789         FN_(plain_lbl) {                        \
790             FB_                                 \
791             JMP_(real_lbl);                     \
792             FE_                                 \
793         }                                       \
794         FN_(real_lbl) {                 \
795             FB_;                                \
796             if (! _module_registered) {         \
797                 _module_registered = 1;         \
798                 { 
799             /* extern decls go here, followed by init code */
800
801 #define REGISTER_FOREIGN_EXPORT(reg_fe_binder)  \
802         STGCALL1(getStablePtr,reg_fe_binder)
803         
804 #define REGISTER_IMPORT(reg_mod_name)           \
805         PUSH_INIT_STACK(reg_mod_name)
806
807 #define END_MOD_INIT()                          \
808         }};                                     \
809         JMP_(POP_INIT_STACK());                 \
810         FE_ }
811
812 /* -----------------------------------------------------------------------------
813    Support for _ccall_GC_ and _casm_GC.
814    -------------------------------------------------------------------------- */
815
816 /* 
817  * Suspending/resuming threads for doing external C-calls (_ccall_GC).
818  * These functions are defined in rts/Schedule.c.
819  */
820 StgInt        suspendThread ( StgRegTable *, rtsBool);
821 StgRegTable * resumeThread  ( StgInt, rtsBool );
822
823 #define SUSPEND_THREAD(token,threaded)          \
824    SaveThreadState();                           \
825    token = suspendThread(BaseReg,threaded);
826
827 #ifdef SMP
828 #define RESUME_THREAD(token,threaded)           \
829     BaseReg = resumeThread(token,threaded);     \
830     LoadThreadState();
831 #else
832 #define RESUME_THREAD(token,threaded)           \
833    (void)resumeThread(token,threaded);          \
834    LoadThreadState();
835 #endif
836
837 #endif /* STGMACROS_H */
838