[project @ 2000-03-13 10:53:55 by simonmar]
[ghc-hetmet.git] / ghc / rts / StgCRun.c
index 09127d8..4ebfcf0 100644 (file)
@@ -1,10 +1,35 @@
 /* -----------------------------------------------------------------------------
- * $Id: StgCRun.c,v 1.3 1999/02/05 16:02:57 simonm Exp $
+ * $Id: StgCRun.c,v 1.14 2000/03/08 10:58:38 simonmar Exp $
  *
- * (c) The GHC Team, 1998-1999
+ * (c) The GHC Team, 1998-2000
  *
- * STG-to-C glue.  Some architectures have this code written in
- * straight assembler (see StgRun.S), some in C.
+ * STG-to-C glue.
+ *
+ * To run an STG function from C land, call
+ *
+ *             rv = StgRun(f,BaseReg);
+ *
+ * where "f" is the STG function to call, and BaseReg is the address of the
+ * RegTable for this run (we might have separate RegTables if we're running
+ * multiple threads on an SMP machine).
+ *
+ * In the end, "f" must JMP to StgReturn (defined below),
+ * passing the return-value "rv" in R1,
+ * to return to the caller of StgRun returning "rv" in
+ * the whatever way C returns a value.
+ *
+ * NOTE: StgRun/StgReturn do *NOT* load or store Hp or any
+ * other registers (other than saving the C callee-saves 
+ * registers).  Instead, the called function "f" must do that
+ * in STG land.
+ * 
+ * GCC will have assumed that pushing/popping of C-stack frames is
+ * going on when it generated its code, and used stack space
+ * accordingly.  However, we actually {\em post-process away} all
+ * such stack-framery (see \tr{ghc/driver/ghc-asm.lprl}). Things will
+ * be OK however, if we initially make sure there are
+ * @RESERVED_C_STACK_BYTES@ on the C-stack to begin with, for local
+ * variables.  
  *
  * -------------------------------------------------------------------------- */
 
 
 static jmp_buf jmp_environment;
 
-extern StgThreadReturnCode StgRun(StgFunPtr f)
+#if 1
+
+extern StgThreadReturnCode StgRun(StgFunPtr f, StgRegTable *basereg)
 {
     jmp_buf save_buf;
     /* Save jmp_environment for previous call to miniInterpret  */
     memcpy((void *) jmp_environment, (void *) save_buf, sizeof(jmp_buf));
     if (setjmp(jmp_environment) == 0) {
        while ( 1 ) {
-           IF_DEBUG(evaluator,
+            IF_DEBUG(evaluator,
                     fprintf(stderr,"Jumping to ");
                     printPtr((P_)f);
                     fprintf(stderr,"\n");
@@ -64,6 +91,113 @@ EXTFUN(StgReturn)
     longjmp(jmp_environment, 1);
 }
 
+#else
+
+static void scanStackSeg ( W_* ptr, int nwords )
+{
+   W_ w;
+   int nwords0 = nwords;
+   while (nwords > 0) {
+      w = *ptr;
+      if (IS_ARG_TAG(w)) {
+         fprintf ( stderr, "%d",w ); nwords--; ptr++;
+        while (w) { fprintf(stderr, "_"); w--; nwords--; ptr++; }
+      }
+      else {
+         fprintf(stderr, "p"); 
+         nwords--; ptr++;
+      }
+   }
+   if (nwords < 0) fprintf(stderr, "erk: nwords < 0\n");
+   checkStackChunk ( ptr, ptr-nwords0 );
+}
+
+
+extern StgThreadReturnCode StgRun(StgFunPtr f, StgRegTable *basereg)
+{
+    char* nm;
+    while (1) {
+
+#define STACK_DETAILS 0
+
+#if STACK_DETAILS
+   {
+   int i;
+   StgWord* sp  = basereg->rSp;
+   StgWord* su  = basereg->rSu;
+   StgTSO*  tso = basereg->rCurrentTSO;
+   StgWord* sb  = tso->stack + tso->stack_size;
+   int ws;
+
+   fprintf(stderr, "== SP = %p   SU = %p\n", sp,su);
+
+   if (su >= sb) goto postloop;
+   if (!sp || !su) goto postloop;
+
+   //printStack ( sp, sb, su);
+
+   while (1) {
+      ws = su - sp;
+      switch (get_itbl((StgClosure*)su)->type) {
+         case STOP_FRAME: 
+            scanStackSeg(sp,ws);
+            fprintf(stderr, "S%d ",ws); 
+            fprintf(stderr, "\n");
+            goto postloop;
+         case UPDATE_FRAME: 
+            scanStackSeg(sp,ws);
+            fprintf(stderr,"U%d ",ws); 
+            sp = su + sizeofW(StgUpdateFrame);
+            su = ((StgUpdateFrame*)su)->link;
+            break;
+         case SEQ_FRAME: 
+            scanStackSeg(sp,ws);
+            fprintf(stderr,"Q%d ",ws); 
+            sp = su + sizeofW(StgSeqFrame);
+            su = ((StgSeqFrame*)su)->link;
+            break;
+         case CATCH_FRAME: 
+            scanStackSeg(sp,ws);
+            fprintf(stderr,"C%d ",ws); 
+            sp = su + sizeofW(StgCatchFrame);
+            su = ((StgCatchFrame*)su)->link;
+            break;
+         default:
+            fprintf(stderr, "?\nweird record on stack\n");
+            goto postloop;
+      }
+   }
+   postloop:
+   }
+#endif    
+
+#if STACK_DETAILS
+       fprintf(stderr,"\n");
+#endif
+       fprintf(stderr,"-- enter: ");
+       nm = nameFromOPtr ( f );
+       if (nm)
+            fprintf(stderr, "%s (%p)", nm, f); else
+            printPtr((P_)f);
+       fprintf ( stderr, "\n");
+#if STACK_DETAILS
+       fprintf(stderr,"\n");
+#endif
+       f = (StgFunPtr) (f)();
+       if (!f) break;
+    }
+    fprintf (stderr, "miniInterpreter: bye!\n\n" );
+    return (StgThreadReturnCode)R1.i;
+}
+
+EXTFUN(StgReturn)
+{
+   return 0;
+}
+#endif
+
+
+
 #else /* !USE_MINIINTERPRETER */
 
 #ifdef LEADING_UNDERSCORE
@@ -73,22 +207,118 @@ EXTFUN(StgReturn)
 #endif
 
 /* -----------------------------------------------------------------------------
-   sparc architecture
+   x86 architecture
+   -------------------------------------------------------------------------- */
+       
+#ifdef i386_TARGET_ARCH
+
+StgThreadReturnCode
+StgRun(StgFunPtr f, StgRegTable *basereg) {
+
+    StgChar space[ RESERVED_C_STACK_BYTES + 4*sizeof(void *) ];
+    StgThreadReturnCode r;
+
+    __asm__ volatile (
+       /* 
+        * save callee-saves registers on behalf of the STG code.
+        */
+       "movl %%esp, %%eax\n\t"
+       "addl %4, %%eax\n\t"
+        "movl %%ebx,0(%%eax)\n\t"
+        "movl %%esi,4(%%eax)\n\t"
+        "movl %%edi,8(%%eax)\n\t"
+        "movl %%ebp,12(%%eax)\n\t"
+       /*
+        * Set BaseReg
+        */
+       "movl %3,%%ebx\n\t"
+       /*
+        * grab the function argument from the stack, and jump to it.
+        */
+        "movl %2,%%eax\n\t"
+        "jmp *%%eax\n\t"
+
+       ".global " STG_RETURN "\n"
+               STG_RETURN ":\n\t"
+
+       "movl %%esi, %%eax\n\t"   /* Return value in R1  */
+
+       /*
+        * restore callee-saves registers.  (Don't stomp on %%eax!)
+        */
+       "movl %%esp, %%edx\n\t"
+       "addl %4, %%edx\n\t"
+        "movl 0(%%edx),%%ebx\n\t"      /* restore the registers saved above */
+        "movl 4(%%edx),%%esi\n\t"
+        "movl 8(%%edx),%%edi\n\t"
+        "movl 12(%%edx),%%ebp\n\t"
+
+      : "=&a" (r), "=m" (space)
+      : "m" (f), "m" (basereg), "i" (RESERVED_C_STACK_BYTES)
+      : "edx" /* stomps on %edx */
+    );
+
+    return r;
+}
+
+#endif
+
+/* -----------------------------------------------------------------------------
+   Sparc architecture
+
+   -- 
+   OLD COMMENT from GHC-3.02:
+
+   We want tailjumps to be calls, because `call xxx' is the only Sparc
+   branch that allows an arbitrary label as a target.  (Gcc's ``goto
+   *target'' construct ends up loading the label into a register and
+   then jumping, at the cost of two extra instructions for the 32-bit
+   load.)
+
+   When entering the threaded world, we stash our return address in a
+   known location so that \tr{%i7} is available as an extra
+   callee-saves register.  Of course, we have to restore this when
+   coming out of the threaded world.
+
+   I hate this god-forsaken architecture.  Since the top of the
+   reserved stack space is used for globals and the bottom is reserved
+   for outgoing arguments, we have to stick our return address
+   somewhere in the middle.  Currently, I'm allowing 100 extra
+   outgoing arguments beyond the first 6.  --JSM
+
+   Updated info (GHC 4.06): we don't appear to use %i7 any more, so
+   I'm not sure whether we still need to save it.  Incedentally, what
+   does the last paragraph above mean when it says "the top of the
+   stack is used for globals"?  What globals?  --SDM
+
    -------------------------------------------------------------------------- */
        
 #ifdef sparc_TARGET_ARCH
 
 StgThreadReturnCode
-StgRun(StgFunPtr f) {
+StgRun(StgFunPtr f, StgRegTable *basereg) {
 
     StgChar space[RESERVED_C_STACK_BYTES+sizeof(void *)];
     register void *i7 __asm__("%i7");
     ((void **)(space))[100] = i7;
     f();
-    __asm__ volatile (".align 4\n"             
+    __asm__ volatile (
+           ".align 4\n"                
             ".global " STG_RETURN "\n"
-                   STG_RETURN ":\n"
-           "\tld %1,%0" : "=r" (i7) : "m" (((void **)(space))[100]));
+                   STG_RETURN ":" 
+           : : : "l0","l1","l2","l3","l4","l5","l6","l7");
+    /* we tell the C compiler that l0-l7 are clobbered on return to
+     * StgReturn, otherwise it tries to use these to save eg. the
+     * address of space[100] across the call.  The correct thing
+     * to do would be to save all the callee-saves regs, but we
+     * can't be bothered to do that.
+     *
+     * The code that gcc generates for this little fragment is now
+     * terrible.  We could do much better by coding it directly in
+     * assembler.
+     */
+    __asm__ volatile ("ld %1,%0" 
+                     : "=r" (i7) : "m" (((void **)(space))[100]));
     return (StgThreadReturnCode)R1.i;
 }
 
@@ -101,8 +331,10 @@ StgRun(StgFunPtr f) {
 #ifdef alpha_TARGET_ARCH
 
 StgThreadReturnCode
-StgRun(StgFunPtr f) 
+StgRun(StgFunPtr f, StgRegTable *basereg) 
 {
+    StgThreadReturnCode ret;
+
     __asm__ volatile ("stq $9,-8($30)\n\t"
                       "stq $10,-16($30)\n\t"
                       "stq $11,-24($30)\n\t"
@@ -127,6 +359,7 @@ StgRun(StgFunPtr f)
     __asm__ volatile (".align 3\n"
                              ".globl " STG_RETURN "\n"
                       STG_RETURN ":\n\t"
+                     "lda %0,($14)\n\t"  /* save R1 */
                              "lda $30,%0($30)\n\t"
                              "ldq $9,-8($30)\n\t"
                              "ldq $10,-16($30)\n\t"
@@ -142,13 +375,107 @@ StgRun(StgFunPtr f)
                              "ldt $f6,-96($30)\n\t"
                      "ldt $f7,-104($30)\n\t"
                      "ldt $f8,-112($30)\n\t" 
-                     "ldt $f9,-120($30)" : :
-                      "K" (RESERVED_C_STACK_BYTES+
+                     "ldt $f9,-120($30)" 
+                     : "=r" (ret)
+                     : "K" (RESERVED_C_STACK_BYTES+
                           8*sizeof(double)+8*sizeof(long)));
 
-    return (StgThreadReturnCode)R1.i;
+    return ret;
+}
+
+#endif /* alpha_TARGET_ARCH */
+
+/* -----------------------------------------------------------------------------
+   HP-PA architecture
+   -------------------------------------------------------------------------- */
+
+#ifdef hppa1_1_TARGET_ARCH
+
+StgThreadReturnCode
+StgRun(StgFunPtr f, StgRegTable *basereg) 
+{
+    StgChar space[RESERVED_C_STACK_BYTES+16*sizeof(long)+10*sizeof(double)];
+    StgThreadReturnCode ret;
+
+    __asm__ volatile ("ldo %0(%%r30),%%r19\n"
+                     "\tstw %%r3, 0(0,%%r19)\n"
+                      "\tstw %%r4, 4(0,%%r19)\n"
+                      "\tstw %%r5, 8(0,%%r19)\n"
+                      "\tstw %%r6,12(0,%%r19)\n"
+                      "\tstw %%r7,16(0,%%r19)\n"
+                      "\tstw %%r8,20(0,%%r19)\n"
+                      "\tstw %%r9,24(0,%%r19)\n"
+                     "\tstw %%r10,28(0,%%r19)\n"
+                      "\tstw %%r11,32(0,%%r19)\n"
+                      "\tstw %%r12,36(0,%%r19)\n"
+                      "\tstw %%r13,40(0,%%r19)\n"
+                      "\tstw %%r14,44(0,%%r19)\n"
+                      "\tstw %%r15,48(0,%%r19)\n"
+                      "\tstw %%r16,52(0,%%r19)\n"
+                      "\tstw %%r17,56(0,%%r19)\n"
+                      "\tstw %%r18,60(0,%%r19)\n"
+                     "\tldo 80(%%r19),%%r19\n"
+                     "\tfstds %%fr12,-16(0,%%r19)\n"
+                     "\tfstds %%fr13, -8(0,%%r19)\n"
+                     "\tfstds %%fr14,  0(0,%%r19)\n"
+                     "\tfstds %%fr15,  8(0,%%r19)\n"
+                     "\tldo 32(%%r19),%%r19\n"
+                     "\tfstds %%fr16,-16(0,%%r19)\n"
+                     "\tfstds %%fr17, -8(0,%%r19)\n"
+                     "\tfstds %%fr18,  0(0,%%r19)\n"
+                     "\tfstds %%fr19,  8(0,%%r19)\n"
+                     "\tldo 32(%%r19),%%r19\n"
+                     "\tfstds %%fr20,-16(0,%%r19)\n"
+                     "\tfstds %%fr21, -8(0,%%r19)\n" : :
+                      "n" (-(116 * sizeof(long) + 10 * sizeof(double))) : "%r19"
+                     );
+
+    f();
+
+    __asm__ volatile (".align 4\n"
+                             "\t.EXPORT " STG_RETURN ",CODE\n"
+                     "\t.EXPORT " STG_RETURN ",ENTRY,PRIV_LEV=3\n"
+                      STG_RETURN "\n"
+                      /* "\tldo %0(%%r3),%%r19\n" */
+                      "\tldo %1(%%r30),%%r19\n"
+                      "\tcopy %%r11, %0\n"  /* save R1 */
+                     "\tldw  0(0,%%r19),%%r3\n"
+                      "\tldw  4(0,%%r19),%%r4\n"
+                      "\tldw  8(0,%%r19),%%r5\n"
+                      "\tldw 12(0,%%r19),%%r6\n"
+                      "\tldw 16(0,%%r19),%%r7\n"
+                      "\tldw 20(0,%%r19),%%r8\n"
+                      "\tldw 24(0,%%r19),%%r9\n"
+                     "\tldw 28(0,%%r19),%%r10\n"
+                      "\tldw 32(0,%%r19),%%r11\n"
+                      "\tldw 36(0,%%r19),%%r12\n"
+                      "\tldw 40(0,%%r19),%%r13\n"
+                      "\tldw 44(0,%%r19),%%r14\n"
+                      "\tldw 48(0,%%r19),%%r15\n"
+                      "\tldw 52(0,%%r19),%%r16\n"
+                      "\tldw 56(0,%%r19),%%r17\n"
+                      "\tldw 60(0,%%r19),%%r18\n"
+                     "\tldo 80(%%r19),%%r19\n"
+                     "\tfldds -16(0,%%r19),%%fr12\n"
+                     "\tfldds  -8(0,%%r19),%%fr13\n"
+                     "\tfldds   0(0,%%r19),%%fr14\n"
+                     "\tfldds   8(0,%%r19),%%fr15\n"
+                     "\tldo 32(%%r19),%%r19\n"
+                     "\tfldds -16(0,%%r19),%%fr16\n"
+                     "\tfldds  -8(0,%%r19),%%fr17\n"
+                     "\tfldds   0(0,%%r19),%%fr18\n"
+                     "\tfldds   8(0,%%r19),%%fr19\n"
+                     "\tldo 32(%%r19),%%r19\n"
+                     "\tfldds -16(0,%%r19),%%fr20\n"
+                     "\tfldds  -8(0,%%r19),%%fr21\n" 
+                        : "=r" (ret)
+                        : "n" (-(116 * sizeof(long) + 10 * sizeof(double)))
+                        : "%r19"
+                     );
+
+    return ret;
 }
 
-#endif /* sparc_TARGET_ARCH */
+#endif /* hppa1_1_TARGET_ARCH */
 
 #endif /* !USE_MINIINTERPRETER */