[project @ 1998-12-02 13:17:09 by simonm]
[ghc-hetmet.git] / ghc / includes / StgMacros.h
1 /* -----------------------------------------------------------------------------
2  * $Id: StgMacros.h,v 1.2 1998/12/02 13:21:35 simonm Exp $
3  *
4  * Macros used for writing STG-ish C code.
5  *
6  * ---------------------------------------------------------------------------*/
7
8 #ifndef STGMACROS_H
9 #define STGMACROS_H
10
11 /* -----------------------------------------------------------------------------
12   The following macros create function headers.
13
14   Each basic block is represented by a C function with no arguments.
15   We therefore always begin with either
16
17   extern F_ f(void)
18
19   or
20   
21   static F_ f(void)
22
23   The macros can be used either to define the function itself, or to provide
24   prototypes (by following with a ';').
25   --------------------------------------------------------------------------- */
26
27 #define STGFUN(f)       StgFunPtr f(void)
28 #define STATICFUN(f)    static StgFunPtr f(void)
29 #define EXTFUN(f)       extern StgFunPtr f(void)
30
31 #define FN_(f)          F_ f(void)
32 #define IFN_(f)         static F_ f(void)
33 #define IF_(f)          static F_ f(void)
34 #define EF_(f)          extern F_ f(void)
35 #define ED_             extern
36 #define ED_RO_          extern const
37 #define ID_             extern
38 #define ID_RO_          extern const
39 #define EI_             extern const StgInfoTable
40 #define II_             extern const StgInfoTable
41 #define EC_             extern StgClosure
42 #define IC_             extern StgClosure
43
44 /* -----------------------------------------------------------------------------
45    Stack Tagging.
46
47    For a  block of non-pointer words on the stack, we precede the
48    block with a small-integer tag giving the number of non-pointer
49    words in the block.
50    -------------------------------------------------------------------------- */
51
52 #ifndef DEBUG_EXTRA
53 #define ARGTAG_MAX 16           /* probably arbitrary */
54 #define ARG_TAG(n)  (n)
55 #define ARG_SIZE(n) stgCast(StgWord,n)
56
57 typedef enum {
58     REALWORLD_TAG = 0,
59     INT_TAG    = sizeofW(StgInt), 
60     INT64_TAG  = sizeofW(StgInt64), 
61     WORD_TAG   = sizeofW(StgWord), 
62     ADDR_TAG   = sizeofW(StgAddr), 
63     CHAR_TAG   = sizeofW(StgChar),
64     FLOAT_TAG  = sizeofW(StgFloat), 
65     DOUBLE_TAG = sizeofW(StgDouble), 
66     STABLE_TAG = sizeofW(StgWord), 
67 } StackTag;
68
69 #else /* DEBUG_EXTRA */
70
71 typedef enum {
72     ILLEGAL_TAG,
73     REALWORLD_TAG,
74     INT_TAG    ,
75     INT64_TAG  ,
76     WORD_TAG   ,
77     ADDR_TAG   ,
78     CHAR_TAG   ,
79     FLOAT_TAG  ,
80     DOUBLE_TAG ,
81     STABLE_TAG ,
82     ARGTAG_MAX = DOUBLE_TAG
83 } StackTag;
84
85 /* putting this in a .h file generates many copies - but its only a 
86  * debugging build.
87  */
88 static StgWord stg_arg_size[] = {
89     [REALWORLD_TAG] = 0,
90     [INT_TAG   ] = sizeofW(StgInt), 
91     [INT64_TAG ] = sizeofW(StgInt64), 
92     [WORD_TAG  ] = sizeofW(StgWord), 
93     [ADDR_TAG  ] = sizeofW(StgAddr), 
94     [CHAR_TAG  ] = sizeofW(StgChar),
95     [FLOAT_TAG ] = sizeofW(StgFloat), 
96     [DOUBLE_TAG] = sizeofW(StgDouble),
97     [STABLE_TAG] = sizeofW(StgWord)
98 };
99
100 #define ARG_SIZE(tag) stg_arg_size[stgCast(StgWord,tag)]
101
102 #endif /* DEBUG_EXTRA */
103
104 static inline int IS_ARG_TAG( StgWord p );
105 static inline int IS_ARG_TAG( StgWord p ) { return p <= ARGTAG_MAX; }
106
107 /* -----------------------------------------------------------------------------
108    Argument checks.
109    
110    If (Sp + <n_args>) > Su { JMP_(stg_updatePAP); }
111    
112    Sp points to the topmost used word on the stack, and Su points to
113    the most recently pushed update frame.
114
115    Remember that <n_args> must include any tagging of unboxed values.
116
117    ARGS_CHK_LOAD_NODE is for top-level functions, whose entry
118    convention doesn't require that Node is loaded with a pointer to
119    the closure.  Thus we must load node before calling stg_updatePAP if
120    the argument check fails. 
121    -------------------------------------------------------------------------- */
122
123 #define ARGS_CHK(n)                             \
124         if ((P_)(Sp + (n)) > (P_)Su) {          \
125                 JMP_(stg_update_PAP);           \
126         }
127
128 #define ARGS_CHK_LOAD_NODE(n,closure)           \
129         if ((P_)(Sp + (n)) > (P_)Su) {          \
130                 R1.p = (P_)closure;             \
131                 JMP_(stg_update_PAP);           \
132         }
133
134 /* -----------------------------------------------------------------------------
135    Heap/Stack Checks.
136
137    When failing a check, we save a return address on the stack and
138    jump to a pre-compiled code fragment that saves the live registers
139    and returns to the scheduler.
140
141    The return address in most cases will be the beginning of the basic
142    block in which the check resides, since we need to perform the check
143    again on re-entry because someone else might have stolen the resource
144    in the meantime.
145    ------------------------------------------------------------------------- */
146
147 #define STK_CHK(headroom,ret,r,layout,tag_assts)                \
148         if (Sp - headroom < SpLim) {                            \
149             EXTFUN(stg_chk_##layout);                           \
150             tag_assts                                           \
151             (r) = (P_)ret;                                      \
152             JMP_(stg_chk_##layout);                             \
153         }
154        
155 #define HP_CHK(headroom,ret,r,layout,tag_assts)                 \
156         if ((Hp += headroom) > HpLim) {                         \
157             EXTFUN(stg_chk_##layout);                           \
158             tag_assts                                           \
159             (r) = (P_)ret;                                              \
160             JMP_(stg_chk_##layout);                             \
161         }
162
163 #define HP_STK_CHK(stk_headroom,hp_headroom,ret,r,layout,tag_assts) \
164         if (Sp - stk_headroom < SpLim || (Hp += hp_headroom) > HpLim) { \
165             EXTFUN(stg_chk_##layout);                           \
166             tag_assts                                           \
167             (r) = (P_)ret;                                              \
168             JMP_(stg_chk_##layout);                             \
169         }
170
171 /* -----------------------------------------------------------------------------
172    A Heap Check in a case alternative are much simpler: everything is
173    on the stack and covered by a liveness mask already, and there is
174    even a return address with an SRT info table there as well.  
175
176    Just push R1 and return to the scheduler saying 'EnterGHC'
177
178    {STK,HP,HP_STK}_CHK_NP are the various checking macros for
179    bog-standard case alternatives, thunks, and non-top-level
180    functions.  In all these cases, node points to a closure that we
181    can just enter to restart the heap check (the NP stands for 'node points').
182
183    HpLim points to the LAST WORD of valid allocation space.
184    -------------------------------------------------------------------------- */
185
186 #define STK_CHK_NP(headroom,ptrs,tag_assts)                     \
187         if ((Sp - (headroom)) < SpLim) {                        \
188             EXTFUN(stg_gc_enter_##ptrs);                        \
189             tag_assts                                           \
190             JMP_(stg_gc_enter_##ptrs);                          \
191         }
192
193 #define HP_CHK_NP(headroom,ptrs,tag_assts)                      \
194         if ((Hp += (headroom)) > HpLim) {                       \
195             EXTFUN(stg_gc_enter_##ptrs);                        \
196             tag_assts                                           \
197             JMP_(stg_gc_enter_##ptrs);                          \
198         }
199
200 #define HP_CHK_SEQ_NP(headroom,ptrs,tag_assts)                  \
201         if ((Hp += (headroom)) > HpLim) {                       \
202             EXTFUN(stg_gc_seq_##ptrs);                          \
203             tag_assts                                           \
204             JMP_(stg_gc_seq_##ptrs);                            \
205         }
206
207 #define HP_STK_CHK_NP(stk_headroom, hp_headroom, ptrs, tag_assts) \
208         if ((Sp - (stk_headroom)) < SpLim || (Hp += (hp_headroom)) > HpLim) { \
209             EXTFUN(stg_gc_enter_##ptrs);                        \
210             tag_assts                                           \
211             JMP_(stg_gc_enter_##ptrs);                          \
212         }
213
214 /* Heap checks for branches of a primitive case / unboxed tuple return */
215
216 #define GEN_HP_CHK_ALT(headroom,lbl,tag_assts)                  \
217         if ((Hp += (headroom)) > HpLim) {                       \
218             EXTFUN(lbl);                                        \
219             tag_assts                                           \
220             JMP_(lbl);                                          \
221         }
222
223 #define HP_CHK_NOREGS(headroom,tag_assts) \
224     GEN_HP_CHK_ALT(headroom,stg_gc_noregs,tag_assts);
225 #define HP_CHK_UNPT_R1(headroom,tag_assts)  \
226     GEN_HP_CHK_ALT(headroom,stg_gc_unpt_r1,tag_assts);
227 #define HP_CHK_UNBX_R1(headroom,tag_assts)  \
228     GEN_HP_CHK_ALT(headroom,stg_gc_unbx_r1,tag_assts);
229 #define HP_CHK_F1(headroom,tag_assts)       \
230     GEN_HP_CHK_ALT(headroom,stg_gc_f1,tag_assts);
231 #define HP_CHK_D1(headroom,tag_assts)       \
232     GEN_HP_CHK_ALT(headroom,stg_gc_d1,tag_assts);
233
234 #define HP_CHK_L1(headroom,tag_assts)       \
235     GEN_HP_CHK_ALT(headroom,stg_gc_d1,tag_assts);
236
237 #define HP_CHK_UT_ALT(headroom, ptrs, nptrs, r, ret, tag_assts) \
238     GEN_HP_CHK_ALT(headroom, stg_gc_ut_##ptrs##_##nptrs, \
239                      tag_assts r = (P_)ret;)
240
241 /* -----------------------------------------------------------------------------
242    Generic Heap checks.
243
244    These are slow, but have the advantage of being usable in a variety
245    of situations.  
246
247    The one restriction is that any relevant SRTs must already be pointed
248    to from the stack.  The return address doesn't need to have an info
249    table attached: hence it can be any old code pointer.
250
251    The liveness mask is a logical 'XOR' of NO_PTRS and zero or more
252    Rn_PTR constants defined below.  All registers will be saved, but
253    the garbage collector needs to know which ones contain pointers.
254
255    Good places to use a generic heap check: 
256
257         - case alternatives (the return address with an SRT is already
258           on the stack).
259
260         - primitives (no SRT required).
261
262    The stack layout is like this:
263
264           DblReg1-2
265           FltReg1-4
266           R1-8
267           return address
268           liveness mask
269           stg_gen_chk_info
270
271    so the liveness mask depends on the size of an StgDouble (FltRegs
272    and R<n> are guaranteed to be 1 word in size).
273
274    -------------------------------------------------------------------------- */
275
276 /* VERY MAGIC CONSTANTS! 
277  * must agree with code in HeapStackCheck.c, stg_gen_chk
278  */
279
280 #if SIZEOF_DOUBLE > SIZEOF_VOID_P
281 #define ALL_NON_PTRS   0xffff
282 #else /* SIZEOF_DOUBLE == SIZEOF_VOID_P */
283 #define ALL_NON_PTRS   0x3fff
284 #endif
285
286 #define LIVENESS_MASK(ptr_regs)  (ALL_NON_PTRS ^ (ptr_regs))
287
288 #define NO_PTRS   0
289 #define R1_PTR    1<<0
290 #define R2_PTR    1<<1
291 #define R3_PTR    1<<2
292 #define R4_PTR    1<<3
293 #define R5_PTR    1<<4
294 #define R6_PTR    1<<5
295 #define R7_PTR    1<<6
296 #define R8_PTR    1<<7
297
298 #define HP_CHK_GEN(headroom,liveness,reentry,tag_assts) \
299    if ((Hp += (headroom)) > HpLim ) {   \
300         EF_(stg_gen_chk);               \
301         tag_assts                       \
302         R9.w = (W_)LIVENESS_MASK(liveness); \
303         R10.w = (W_)reentry;            \
304         JMP_(stg_gen_chk);              \
305    }
306
307 #define STK_CHK_GEN(headroom,liveness,reentry,tag_assts) \
308    if ((Sp - (headroom)) < SpLim) {     \
309         EF_(stg_gen_chk);               \
310         tag_assts                       \
311         R9.w = (W_)LIVENESS_MASK(liveness); \
312         R10.w = (W_)reentry;            \
313         JMP_(stg_gen_chk);              \
314    }
315
316 #define MAYBE_GC(liveness,reentry)      \
317    if (doYouWantToGC()) {               \
318         EF_(stg_gen_hp);                \
319         R9.w = (W_)LIVENESS_MASK(liveness); \
320         R10.w = (W_)reentry;            \
321         JMP_(stg_gen_hp);               \
322    }
323
324 /* -----------------------------------------------------------------------------
325    Voluntary Yields/Blocks
326
327    We only have a generic version of this at the moment - if it turns
328    out to be slowing us down we can make specialised ones.
329    -------------------------------------------------------------------------- */
330
331 #define YIELD(liveness,reentry)                 \
332   {                                             \
333    EF_(stg_gen_yield);                          \
334    R9.w  = (W_)LIVENESS_MASK(liveness);         \
335    R10.w = (W_)reentry;                         \
336    JMP_(stg_gen_yield);                         \
337   }
338
339 #define BLOCK(liveness,reentry)                 \
340   {                                             \
341    EF_(stg_gen_block);                          \
342    R9.w  = (W_)LIVENESS_MASK(liveness);         \
343    R10.w = (W_)reentry;                         \
344    JMP_(stg_gen_block);                         \
345   }
346
347 #define BLOCK_NP(ptrs)                          \
348   {                                             \
349     EF_(stg_bock_##ptrs);                       \
350     JMP_(stg_block_##ptrs);                     \
351   }
352
353 /* -----------------------------------------------------------------------------
354    CCall_GC needs to push a dummy stack frame containing the contents
355    of volatile registers and variables.  
356
357    We use a RET_DYN frame the same as for a dynamic heap check.
358    ------------------------------------------------------------------------- */
359
360 EI_(stg_gen_chk_info);
361
362 /* -----------------------------------------------------------------------------
363    Vectored Returns
364
365    RETVEC(p,t) where 'p' is a pointer to the info table for a
366    vectored return address, returns the address of the return code for
367    tag 't'.
368
369    Return vectors are placed in *reverse order* immediately before the info
370    table for the return address.  Hence the formula for computing the
371    actual return address is (addr - sizeof(InfoTable) - tag - 1).
372    The extra subtraction of one word is because tags start at zero.
373    -------------------------------------------------------------------------- */
374
375 #ifdef USE_MINIINTERPRETER
376 #define RET_VEC(p,t) ((*(stgCast(StgInfoTable*,p)->vector))[t])
377 #else
378 #define RET_VEC(p,t) (*((P_)(p) - sizeofW(StgInfoTable) - t - 1))
379 #endif
380
381 /* -----------------------------------------------------------------------------
382    Misc
383    -------------------------------------------------------------------------- */
384
385 /* set the tag register (if we have one) */
386 #define SET_TAG(t)  /* nothing */
387
388 /* don't do eager blackholing for now */
389 #define UPD_BH_UPDATABLE(thunk)  /* nothing */
390 #define UPD_BH_SINGLE_ENTRY(thunk)  /* nothing */
391
392 /* -----------------------------------------------------------------------------
393    Moving Floats and Doubles
394
395    ASSIGN_FLT is for assigning a float to memory (usually the
396               stack/heap).  The memory address is guaranteed to be
397               StgWord aligned (currently == sizeof(long)).
398
399    PK_FLT     is for pulling a float out of memory.  The memory is
400               guaranteed to be StgWord aligned.
401    -------------------------------------------------------------------------- */
402
403 static inline void        ASSIGN_FLT (W_ [], StgFloat);
404 static inline StgFloat    PK_FLT     (W_ []);
405
406 #if ALIGNMENT_FLOAT <= ALIGNMENT_LONG
407
408 static inline void     ASSIGN_FLT(W_ p_dest[], StgFloat src) { *(StgFloat *)p_dest = src; }
409 static inline StgFloat PK_FLT    (W_ p_src[])                { return *(StgFloat *)p_src; }
410
411 #else  /* ALIGNMENT_FLOAT > ALIGNMENT_UNSIGNED_INT */
412
413 static inline void ASSIGN_FLT(W_ p_dest[], StgFloat src)
414 {
415     float_thing y;
416     y.f = src;
417     *p_dest = y.fu;
418 }
419
420 static inline StgFloat PK_FLT(W_ p_src[])
421 {
422     float_thing y;
423     y.fu = *p_src;
424     return(y.f);
425 }
426
427 #endif /* ALIGNMENT_FLOAT > ALIGNMENT_LONG */
428
429 #if ALIGNMENT_DOUBLE <= ALIGNMENT_LONG
430
431 static inline void        ASSIGN_DBL (W_ [], StgDouble);
432 static inline StgDouble   PK_DBL     (W_ []);
433
434 static inline void      ASSIGN_DBL(W_ p_dest[], StgDouble src) { *(StgDouble *)p_dest = src; }
435 static inline StgDouble PK_DBL    (W_ p_src[])                 { return *(StgDouble *)p_src; }
436
437 #else   /* ALIGNMENT_DOUBLE > ALIGNMENT_LONG */
438
439 /* Sparc uses two floating point registers to hold a double.  We can
440  * write ASSIGN_DBL and PK_DBL by directly accessing the registers
441  * independently - unfortunately this code isn't writable in C, we
442  * have to use inline assembler.
443  */
444 #if sparc_TARGET_ARCH
445
446 #define ASSIGN_DBL(dst,src) \
447       __asm__("st %2,%0\n\tst %R2,%1" : "=m" (((P_)(dst))[0]), \
448         "=m" (((P_)(dst))[1]) : "f" (src));
449
450 #define PK_DBL(src) \
451     ( { register double d; \
452       __asm__("ld %1,%0\n\tld %2,%R0" : "=f" (d) : \
453         "m" (((P_)(src))[0]), "m" (((P_)(src))[1])); d; \
454     } )
455
456 #else /* ! sparc_TARGET_ARCH */
457
458 static inline void        ASSIGN_DBL (W_ [], StgDouble);
459 static inline StgDouble   PK_DBL     (W_ []);
460
461 typedef struct
462   { StgWord dhi;
463     StgWord dlo;
464   } unpacked_double;
465
466 typedef union
467   { StgDouble d;
468     unpacked_double du;
469   } double_thing;
470
471 static inline void ASSIGN_DBL(W_ p_dest[], StgDouble src)
472 {
473     double_thing y;
474     y.d = src;
475     p_dest[0] = y.du.dhi;
476     p_dest[1] = y.du.dlo;
477 }
478
479 /* GCC also works with this version, but it generates
480    the same code as the previous one, and is not ANSI
481
482 #define ASSIGN_DBL( p_dest, src ) \
483         *p_dest = ((double_thing) src).du.dhi; \
484         *(p_dest+1) = ((double_thing) src).du.dlo \
485 */
486
487 static inline StgDouble PK_DBL(W_ p_src[])
488 {
489     double_thing y;
490     y.du.dhi = p_src[0];
491     y.du.dlo = p_src[1];
492     return(y.d);
493 }
494
495 #endif /* ! sparc_TARGET_ARCH */
496
497 #endif /* ALIGNMENT_DOUBLE > ALIGNMENT_UNSIGNED_INT */
498
499 #ifdef SUPPORT_LONG_LONGS
500
501 typedef struct
502   { StgWord dhi;
503     StgWord dlo;
504   } unpacked_double_word;
505
506 typedef union
507   { StgInt64 i;
508     unpacked_double_word iu;
509   } int64_thing;
510
511 typedef union
512   { StgNat64 w;
513     unpacked_double_word wu;
514   } word64_thing;
515
516 static inline void ASSIGN_Word64(W_ p_dest[], StgNat64 src)
517 {
518     word64_thing y;
519     y.w = src;
520     p_dest[0] = y.wu.dhi;
521     p_dest[1] = y.wu.dlo;
522 }
523
524 static inline StgNat64 PK_Word64(W_ p_src[])
525 {
526     word64_thing y;
527     y.wu.dhi = p_src[0];
528     y.wu.dlo = p_src[1];
529     return(y.w);
530 }
531
532 static inline void ASSIGN_Int64(W_ p_dest[], StgInt64 src)
533 {
534     int64_thing y;
535     y.i = src;
536     p_dest[0] = y.iu.dhi;
537     p_dest[1] = y.iu.dlo;
538 }
539
540 static inline StgInt64 PK_Int64(W_ p_src[])
541 {
542     int64_thing y;
543     y.iu.dhi = p_src[0];
544     y.iu.dlo = p_src[1];
545     return(y.i);
546 }
547 #endif
548
549 /* -----------------------------------------------------------------------------
550    Catch frames
551    -------------------------------------------------------------------------- */
552
553 extern const StgPolyInfoTable catch_frame_info;
554
555 /* -----------------------------------------------------------------------------
556    Seq frames
557
558    A seq frame is very like an update frame, except that it doesn't do
559    an update...
560    -------------------------------------------------------------------------- */
561
562 extern const StgPolyInfoTable seq_frame_info;
563
564 #define PUSH_SEQ_FRAME(sp)                                      \
565         {                                                       \
566                 StgSeqFrame *__frame;                           \
567                 TICK_SEQF_PUSHED();                             \
568                 __frame = (StgSeqFrame *)(sp);                  \
569                 SET_HDR_(__frame,&seq_frame_info,CCCS);         \
570                 __frame->link = Su;                             \
571                 Su = (StgUpdateFrame *)__frame;                 \
572         }
573
574 /* -----------------------------------------------------------------------------
575    Split markers
576    -------------------------------------------------------------------------- */
577
578 #if defined(USE_SPLIT_MARKERS)
579 #define __STG_SPLIT_MARKER(n) FN_(__stg_split_marker##n) { }
580 #else
581 #define __STG_SPLIT_MARKER(n) /* nothing */
582 #endif
583
584 /* -----------------------------------------------------------------------------
585    Closure and Info Macros with casting.
586
587    We don't want to mess around with casts in the generated C code, so
588    we use these casting versions of the closure/info tables macros.
589    -------------------------------------------------------------------------- */
590
591 #define SET_HDR_(c,info,ccs) \
592    SET_HDR((StgClosure *)(c),(StgInfoTable *)(info),ccs)
593
594 /* -----------------------------------------------------------------------------
595    Saving context for exit from the STG world, and loading up context
596    on entry to STG code.
597
598    We save all the STG registers (that is, the ones that are mapped to
599    machine registers) in their places in the TSO.  
600
601    The stack registers go into the current stack object, and the heap
602    registers are saved in global locations.
603    -------------------------------------------------------------------------- */
604
605 static __inline__ void
606 SaveThreadState(void)
607 {
608   /* Don't need to save REG_Base, it won't have changed. */
609
610   CurrentTSO->sp       = Sp;
611   CurrentTSO->su       = Su;
612   CurrentTSO->splim    = SpLim;
613   CloseNursery(Hp);
614
615 #if defined(PROFILING)
616   CurrentTSO->prof.CCCS = CCCS;
617 #endif
618 }
619
620 static __inline__ void 
621 LoadThreadState (void)
622 {
623 #ifdef REG_Base
624   BaseReg = &MainRegTable;
625 #endif
626
627   Sp    = CurrentTSO->sp;
628   Su    = CurrentTSO->su;
629   SpLim = CurrentTSO->splim;
630   OpenNursery(Hp,HpLim);
631
632 # if defined(PROFILING)
633   CCCS = CurrentTSO->prof.CCCS;
634 # endif
635 }
636
637 #endif /* STGMACROS_H */
638