[project @ 2000-04-11 16:36:53 by sewardj]
[ghc-hetmet.git] / ghc / rts / StgCRun.c
1 /* -----------------------------------------------------------------------------
2  * $Id: StgCRun.c,v 1.16 2000/04/11 16:36:54 sewardj Exp $
3  *
4  * (c) The GHC Team, 1998-2000
5  *
6  * STG-to-C glue.
7  *
8  * To run an STG function from C land, call
9  *
10  *              rv = StgRun(f,BaseReg);
11  *
12  * where "f" is the STG function to call, and BaseReg is the address of the
13  * RegTable for this run (we might have separate RegTables if we're running
14  * multiple threads on an SMP machine).
15  *
16  * In the end, "f" must JMP to StgReturn (defined below),
17  * passing the return-value "rv" in R1,
18  * to return to the caller of StgRun returning "rv" in
19  * the whatever way C returns a value.
20  *
21  * NOTE: StgRun/StgReturn do *NOT* load or store Hp or any
22  * other registers (other than saving the C callee-saves 
23  * registers).  Instead, the called function "f" must do that
24  * in STG land.
25  * 
26  * GCC will have assumed that pushing/popping of C-stack frames is
27  * going on when it generated its code, and used stack space
28  * accordingly.  However, we actually {\em post-process away} all
29  * such stack-framery (see \tr{ghc/driver/ghc-asm.lprl}). Things will
30  * be OK however, if we initially make sure there are
31  * @RESERVED_C_STACK_BYTES@ on the C-stack to begin with, for local
32  * variables.  
33  *
34  * -------------------------------------------------------------------------- */
35
36 /* include Stg.h first because we want real machine regs in here: we
37  * have to get the value of R1 back from Stg land to C land intact.
38  */
39 #include "Stg.h"
40 #include "Rts.h"
41 #include "StgRun.h"
42
43 #ifdef DEBUG
44 #include "RtsFlags.h"
45 #include "RtsUtils.h"
46 #include "Printer.h"
47 #endif
48
49 #ifdef USE_MINIINTERPRETER
50
51 /* -----------------------------------------------------------------------------
52    any architecture (using miniinterpreter)
53    -------------------------------------------------------------------------- */
54         
55 /* The static @jmp_environment@ variable allows @miniInterpret@ to
56  * communicate with @StgReturn@.
57  * 
58  * Because @StgRun@ may be used recursively, we carefully
59  * save and restore the whole of @jmp_environment@.
60  */
61 #include <setjmp.h>
62 #include <string.h> /* for memcpy */
63
64 static jmp_buf jmp_environment;
65
66 #if 1
67
68 extern StgThreadReturnCode StgRun(StgFunPtr f, StgRegTable *basereg)
69 {
70     jmp_buf save_buf;
71     /* Save jmp_environment for previous call to miniInterpret  */
72     memcpy((void *) jmp_environment, (void *) save_buf, sizeof(jmp_buf));
73     if (setjmp(jmp_environment) == 0) {
74         while ( 1 ) {
75 StgFunPtr f_old;
76             IF_DEBUG(evaluator,
77                      fprintf(stderr,"Jumping to ");
78                      printPtr((P_)f);
79                      fprintf(stderr,"\n");
80                      );
81 f_old = f;
82             f = (StgFunPtr) (f)();
83  if (!IS_CODE_PTR(f)) {
84 fprintf ( stderr,"bad ptr given by %p %s\n", f_old, nameFromOPtr(f_old) );
85 assert(IS_CODE_PTR(f));
86  }
87
88         }
89     }
90     /* Restore jmp_environment for previous call */
91     memcpy((void*) save_buf, (void*) jmp_environment, sizeof(jmp_buf));
92
93     return (StgThreadReturnCode)R1.i;
94 }
95
96 EXTFUN(StgReturn)
97 {
98     longjmp(jmp_environment, 1);
99 }
100
101 #else
102
103 #define CHECK_STACK   0
104 #define STACK_DETAILS 0
105
106 static int enters = 0;
107
108 static void scanStackSeg ( W_* ptr, int nwords )
109 {
110    W_ w;
111 #if CHECK_STACK
112    int nwords0 = nwords;
113 #if STACK_DETAILS
114    while (nwords > 0) {
115       w = *ptr;
116       if (IS_ARG_TAG(w)) {
117          fprintf ( stderr, "%d",w ); nwords--; ptr++;
118          while (w) { fprintf(stderr, "_"); w--; nwords--; ptr++; }
119       }
120       else {
121          fprintf(stderr, "p"); 
122          nwords--; ptr++;
123       }
124    }
125    if (nwords < 0) fprintf(stderr, "erk: nwords < 0\n");
126 #endif
127    checkStackChunk ( ptr, ptr-nwords0 );
128 #endif
129 }
130
131 extern StgFunPtr stg_enterStackTop;
132 extern StgThreadReturnCode StgRun(StgFunPtr f, StgRegTable *basereg)
133 {
134     char* nm;
135     while (1) {
136
137 #if CHECK_STACK
138    {
139    int i;
140    StgTSO*  tso = basereg->rCurrentTSO;
141    StgWord* sb  = tso->stack + tso->stack_size;
142    StgWord* sp;
143    StgWord* su;
144    int ws;
145
146    if (f == &stg_enterStackTop) {
147       sp = tso->sp;
148       su = tso->su;
149    } else {
150       sp  = basereg->rSp;
151       su  = basereg->rSu;
152    }
153
154 #if STACK_DETAILS
155    fprintf(stderr, 
156            "== SB = %p   SP = %p(%p)   SU = %p   SpLim = %p(%p)\n", 
157            sb, sp, tso->sp,   su, basereg->rSpLim, tso->splim);
158 #endif
159
160    if (su >= sb) goto postloop;
161    if (!sp || !su) goto postloop;
162
163    printStack ( sp, sb, su);
164
165    while (1) {
166       ws = su - sp;
167       switch (get_itbl((StgClosure*)su)->type) {
168          case STOP_FRAME: 
169             scanStackSeg(sp,ws);
170 #if STACK_DETAILS
171             fprintf(stderr, "S%d ",ws); 
172             fprintf(stderr, "\n");
173 #endif
174             goto postloop;
175          case UPDATE_FRAME: 
176             scanStackSeg(sp,ws);
177 #if STACK_DETAILS
178             fprintf(stderr,"U%d ",ws); 
179 #endif
180             sp = su + sizeofW(StgUpdateFrame);
181             su = ((StgUpdateFrame*)su)->link;
182             break;
183          case SEQ_FRAME: 
184             scanStackSeg(sp,ws);
185 #if STACK_DETAILS
186             fprintf(stderr,"Q%d ",ws); 
187 #endif
188             sp = su + sizeofW(StgSeqFrame);
189             su = ((StgSeqFrame*)su)->link;
190             break;
191          case CATCH_FRAME: 
192             scanStackSeg(sp,ws);
193 #if STACK_DETAILS
194             fprintf(stderr,"C%d ",ws); 
195 #endif
196             sp = su + sizeofW(StgCatchFrame);
197             su = ((StgCatchFrame*)su)->link;
198             break;
199          default:
200             fprintf(stderr, "?\nweird record on stack\n");
201             assert(0);
202             goto postloop;
203       }
204    }
205    postloop:
206    }
207 #endif
208 #if STACK_DETAILS
209        fprintf(stderr,"\n");
210 #endif
211 #if 1
212        fprintf(stderr,"-- enter %p ", f);
213        nm = nameFromOPtr ( f );
214           if (nm) fprintf(stderr, "%s", nm); else
215           printPtr((P_)f);
216        fprintf ( stderr, "\n");
217 #endif
218 #if STACK_DETAILS
219        fprintf(stderr,"\n");
220 #endif
221     zzz:
222        if (enters % 1000 == 0) fprintf(stderr, "%d enters\n",enters);
223        enters++;
224        f = (StgFunPtr) (f)();
225        if (!f) break;
226     }
227     fprintf (stderr, "miniInterpreter: bye!\n\n" );
228     return (StgThreadReturnCode)R1.i;
229 }
230
231 EXTFUN(StgReturn)
232 {
233    return 0;
234 }
235 #endif
236
237
238
239 #else /* !USE_MINIINTERPRETER */
240
241 #ifdef LEADING_UNDERSCORE
242 #define STG_RETURN "_StgReturn"
243 #else
244 #define STG_RETURN "StgReturn"
245 #endif
246
247 /* -----------------------------------------------------------------------------
248    x86 architecture
249    -------------------------------------------------------------------------- */
250         
251 #ifdef i386_TARGET_ARCH
252
253 StgThreadReturnCode
254 StgRun(StgFunPtr f, StgRegTable *basereg) {
255
256     StgChar space[ RESERVED_C_STACK_BYTES + 4*sizeof(void *) ];
257     StgThreadReturnCode r;
258
259     __asm__ volatile (
260         /* 
261          * save callee-saves registers on behalf of the STG code.
262          */
263         "movl %%esp, %%eax\n\t"
264         "addl %4, %%eax\n\t"
265         "movl %%ebx,0(%%eax)\n\t"
266         "movl %%esi,4(%%eax)\n\t"
267         "movl %%edi,8(%%eax)\n\t"
268         "movl %%ebp,12(%%eax)\n\t"
269         /*
270          * Set BaseReg
271          */
272         "movl %3,%%ebx\n\t"
273         /*
274          * grab the function argument from the stack, and jump to it.
275          */
276         "movl %2,%%eax\n\t"
277         "jmp *%%eax\n\t"
278
279         ".global " STG_RETURN "\n"
280         STG_RETURN ":\n\t"
281
282         "movl %%esi, %%eax\n\t"   /* Return value in R1  */
283
284         /*
285          * restore callee-saves registers.  (Don't stomp on %%eax!)
286          */
287         "movl %%esp, %%edx\n\t"
288         "addl %4, %%edx\n\t"
289         "movl 0(%%edx),%%ebx\n\t"       /* restore the registers saved above */
290         "movl 4(%%edx),%%esi\n\t"
291         "movl 8(%%edx),%%edi\n\t"
292         "movl 12(%%edx),%%ebp\n\t"
293
294       : "=&a" (r), "=m" (space)
295       : "m" (f), "m" (basereg), "i" (RESERVED_C_STACK_BYTES)
296       : "edx" /* stomps on %edx */
297     );
298
299     return r;
300 }
301
302 #endif
303
304 /* -----------------------------------------------------------------------------
305    Sparc architecture
306
307    -- 
308    OLD COMMENT from GHC-3.02:
309
310    We want tailjumps to be calls, because `call xxx' is the only Sparc
311    branch that allows an arbitrary label as a target.  (Gcc's ``goto
312    *target'' construct ends up loading the label into a register and
313    then jumping, at the cost of two extra instructions for the 32-bit
314    load.)
315
316    When entering the threaded world, we stash our return address in a
317    known location so that \tr{%i7} is available as an extra
318    callee-saves register.  Of course, we have to restore this when
319    coming out of the threaded world.
320
321    I hate this god-forsaken architecture.  Since the top of the
322    reserved stack space is used for globals and the bottom is reserved
323    for outgoing arguments, we have to stick our return address
324    somewhere in the middle.  Currently, I'm allowing 100 extra
325    outgoing arguments beyond the first 6.  --JSM
326
327    Updated info (GHC 4.06): we don't appear to use %i7 any more, so
328    I'm not sure whether we still need to save it.  Incedentally, what
329    does the last paragraph above mean when it says "the top of the
330    stack is used for globals"?  What globals?  --SDM
331
332    -------------------------------------------------------------------------- */
333         
334 #ifdef sparc_TARGET_ARCH
335
336 StgThreadReturnCode
337 StgRun(StgFunPtr f, StgRegTable *basereg) {
338
339     StgChar space[RESERVED_C_STACK_BYTES+sizeof(void *)];
340     register void *i7 __asm__("%i7");
341     ((void **)(space))[100] = i7;
342     f();
343     __asm__ volatile (
344             ".align 4\n"                
345             ".global " STG_RETURN "\n"
346             STG_RETURN ":" 
347             : : : "l0","l1","l2","l3","l4","l5","l6","l7");
348     /* we tell the C compiler that l0-l7 are clobbered on return to
349      * StgReturn, otherwise it tries to use these to save eg. the
350      * address of space[100] across the call.  The correct thing
351      * to do would be to save all the callee-saves regs, but we
352      * can't be bothered to do that.
353      *
354      * The code that gcc generates for this little fragment is now
355      * terrible.  We could do much better by coding it directly in
356      * assembler.
357      */
358     __asm__ volatile ("ld %1,%0" 
359                       : "=r" (i7) : "m" (((void **)(space))[100]));
360     return (StgThreadReturnCode)R1.i;
361 }
362
363 #endif
364
365 /* -----------------------------------------------------------------------------
366    alpha architecture
367    -------------------------------------------------------------------------- */
368
369 #ifdef alpha_TARGET_ARCH
370
371 StgThreadReturnCode
372 StgRun(StgFunPtr f, StgRegTable *basereg) 
373 {
374     StgThreadReturnCode ret;
375
376     __asm__ volatile ("stq $9,-8($30)\n\t"
377                       "stq $10,-16($30)\n\t"
378                       "stq $11,-24($30)\n\t"
379                       "stq $12,-32($30)\n\t"
380                       "stq $13,-40($30)\n\t"
381                       "stq $14,-48($30)\n\t"
382                       "stq $15,-56($30)\n\t"
383                       "stt $f2,-64($30)\n\t"
384                       "stt $f3,-72($30)\n\t"
385                       "stt $f4,-80($30)\n\t"
386                       "stt $f5,-88($30)\n\t"
387                       "stt $f6,-96($30)\n\t"
388                       "stt $f7,-104($30)\n\t"
389                       "stt $f8,-112($30)\n\t"
390                       "stt $f9,-120($30)\n\t"
391                       "lda $30,-%0($30)" : :
392                       "K" (RESERVED_C_STACK_BYTES+
393                            8*sizeof(double)+8*sizeof(long)));
394
395     f();
396
397     __asm__ volatile (".align 3\n"
398                       ".globl " STG_RETURN "\n"
399                       STG_RETURN ":\n\t"
400                       "lda %0,($14)\n\t"  /* save R1 */
401                       "lda $30,%0($30)\n\t"
402                       "ldq $9,-8($30)\n\t"
403                       "ldq $10,-16($30)\n\t"
404                       "ldq $11,-24($30)\n\t"
405                       "ldq $12,-32($30)\n\t"
406                       "ldq $13,-40($30)\n\t"
407                       "ldq $14,-48($30)\n\t"
408                       "ldq $15,-56($30)\n\t"
409                       "ldt $f2,-64($30)\n\t"
410                       "ldt $f3,-72($30)\n\t"
411                       "ldt $f4,-80($30)\n\t"
412                       "ldt $f5,-88($30)\n\t"
413                       "ldt $f6,-96($30)\n\t"
414                       "ldt $f7,-104($30)\n\t"
415                       "ldt $f8,-112($30)\n\t" 
416                       "ldt $f9,-120($30)" 
417                       : "=r" (ret)
418                       : "K" (RESERVED_C_STACK_BYTES+
419                            8*sizeof(double)+8*sizeof(long)));
420
421     return ret;
422 }
423
424 #endif /* alpha_TARGET_ARCH */
425
426 /* -----------------------------------------------------------------------------
427    HP-PA architecture
428    -------------------------------------------------------------------------- */
429
430 #ifdef hppa1_1_TARGET_ARCH
431
432 StgThreadReturnCode
433 StgRun(StgFunPtr f, StgRegTable *basereg) 
434 {
435     StgChar space[RESERVED_C_STACK_BYTES+16*sizeof(long)+10*sizeof(double)];
436     StgThreadReturnCode ret;
437
438     __asm__ volatile ("ldo %0(%%r30),%%r19\n"
439                       "\tstw %%r3, 0(0,%%r19)\n"
440                       "\tstw %%r4, 4(0,%%r19)\n"
441                       "\tstw %%r5, 8(0,%%r19)\n"
442                       "\tstw %%r6,12(0,%%r19)\n"
443                       "\tstw %%r7,16(0,%%r19)\n"
444                       "\tstw %%r8,20(0,%%r19)\n"
445                       "\tstw %%r9,24(0,%%r19)\n"
446                       "\tstw %%r10,28(0,%%r19)\n"
447                       "\tstw %%r11,32(0,%%r19)\n"
448                       "\tstw %%r12,36(0,%%r19)\n"
449                       "\tstw %%r13,40(0,%%r19)\n"
450                       "\tstw %%r14,44(0,%%r19)\n"
451                       "\tstw %%r15,48(0,%%r19)\n"
452                       "\tstw %%r16,52(0,%%r19)\n"
453                       "\tstw %%r17,56(0,%%r19)\n"
454                       "\tstw %%r18,60(0,%%r19)\n"
455                       "\tldo 80(%%r19),%%r19\n"
456                       "\tfstds %%fr12,-16(0,%%r19)\n"
457                       "\tfstds %%fr13, -8(0,%%r19)\n"
458                       "\tfstds %%fr14,  0(0,%%r19)\n"
459                       "\tfstds %%fr15,  8(0,%%r19)\n"
460                       "\tldo 32(%%r19),%%r19\n"
461                       "\tfstds %%fr16,-16(0,%%r19)\n"
462                       "\tfstds %%fr17, -8(0,%%r19)\n"
463                       "\tfstds %%fr18,  0(0,%%r19)\n"
464                       "\tfstds %%fr19,  8(0,%%r19)\n"
465                       "\tldo 32(%%r19),%%r19\n"
466                       "\tfstds %%fr20,-16(0,%%r19)\n"
467                       "\tfstds %%fr21, -8(0,%%r19)\n" : :
468                       "n" (-(116 * sizeof(long) + 10 * sizeof(double))) : "%r19"
469                       );
470
471     f();
472
473     __asm__ volatile (".align 4\n"
474                       "\t.EXPORT " STG_RETURN ",CODE\n"
475                       "\t.EXPORT " STG_RETURN ",ENTRY,PRIV_LEV=3\n"
476                       STG_RETURN "\n"
477                       /* "\tldo %0(%%r3),%%r19\n" */
478                       "\tldo %1(%%r30),%%r19\n"
479                       "\tcopy %%r11, %0\n"  /* save R1 */
480                       "\tldw  0(0,%%r19),%%r3\n"
481                       "\tldw  4(0,%%r19),%%r4\n"
482                       "\tldw  8(0,%%r19),%%r5\n"
483                       "\tldw 12(0,%%r19),%%r6\n"
484                       "\tldw 16(0,%%r19),%%r7\n"
485                       "\tldw 20(0,%%r19),%%r8\n"
486                       "\tldw 24(0,%%r19),%%r9\n"
487                       "\tldw 28(0,%%r19),%%r10\n"
488                       "\tldw 32(0,%%r19),%%r11\n"
489                       "\tldw 36(0,%%r19),%%r12\n"
490                       "\tldw 40(0,%%r19),%%r13\n"
491                       "\tldw 44(0,%%r19),%%r14\n"
492                       "\tldw 48(0,%%r19),%%r15\n"
493                       "\tldw 52(0,%%r19),%%r16\n"
494                       "\tldw 56(0,%%r19),%%r17\n"
495                       "\tldw 60(0,%%r19),%%r18\n"
496                       "\tldo 80(%%r19),%%r19\n"
497                       "\tfldds -16(0,%%r19),%%fr12\n"
498                       "\tfldds  -8(0,%%r19),%%fr13\n"
499                       "\tfldds   0(0,%%r19),%%fr14\n"
500                       "\tfldds   8(0,%%r19),%%fr15\n"
501                       "\tldo 32(%%r19),%%r19\n"
502                       "\tfldds -16(0,%%r19),%%fr16\n"
503                       "\tfldds  -8(0,%%r19),%%fr17\n"
504                       "\tfldds   0(0,%%r19),%%fr18\n"
505                       "\tfldds   8(0,%%r19),%%fr19\n"
506                       "\tldo 32(%%r19),%%r19\n"
507                       "\tfldds -16(0,%%r19),%%fr20\n"
508                       "\tfldds  -8(0,%%r19),%%fr21\n" 
509                          : "=r" (ret)
510                          : "n" (-(116 * sizeof(long) + 10 * sizeof(double)))
511                          : "%r19"
512                       );
513
514     return ret;
515 }
516
517 #endif /* hppa1_1_TARGET_ARCH */
518
519 #endif /* !USE_MINIINTERPRETER */