[project @ 2004-08-13 13:04:50 by simonmar]
[ghc-hetmet.git] / ghc / rts / StgCRun.c
index f88f28e..b1d8b5a 100644 (file)
@@ -1,7 +1,7 @@
 /* -----------------------------------------------------------------------------
- * $Id: StgCRun.c,v 1.37 2002/12/11 15:36:51 simonmar Exp $
+ * $Id: StgCRun.c,v 1.42 2004/08/13 13:10:46 simonmar Exp $
  *
- * (c) The GHC Team, 1998-2000
+ * (c) The GHC Team, 1998-2003
  *
  * STG-to-C glue.
  *
@@ -50,7 +50,7 @@
  * that we don't use but which are callee-save registers.  The __divq() routine
  * in libc.a clobbers $s6.
  */
-#include "config.h"
+#include "ghcconfig.h"
 #ifdef alpha_TARGET_ARCH
 #define alpha_EXTRA_CAREFUL
 register long   fake_ra __asm__("$26");
@@ -68,9 +68,10 @@ register double fake_f9 __asm__("$f9");
 #include "Stg.h"
 #include "Rts.h"
 #include "StgRun.h"
+#include "RtsFlags.h"
+#include "Capability.h"
 
 #ifdef DEBUG
-#include "RtsFlags.h"
 #include "RtsUtils.h"
 #include "Printer.h"
 #endif
@@ -81,22 +82,22 @@ register double fake_f9 __asm__("$f9");
    any architecture (using miniinterpreter)
    -------------------------------------------------------------------------- */
 
-extern StgThreadReturnCode StgRun(StgFunPtr f, StgRegTable *basereg STG_UNUSED)
+StgThreadReturnCode StgRun(StgFunPtr f, StgRegTable *basereg STG_UNUSED)
 {
-   while (f) {
-      IF_DEBUG(interpreter,
-              fprintf(stderr,"Jumping to ");
-              printPtr((P_)f); fflush(stdout);
-              fprintf(stderr,"\n");
-             );
-      f = (StgFunPtr) (f)();
-   }
-   return (StgThreadReturnCode)R1.i;
+    while (f) {
+       if (RtsFlags[0].DebugFlags.interpreter) {
+           fprintf(stderr,"Jumping to ");
+           printPtr((P_)f); fflush(stdout);
+           fprintf(stderr,"\n");
+       }
+       f = (StgFunPtr) (f)();
+    }
+    return (StgThreadReturnCode)R1.i;
 }
 
-EXTFUN(StgReturn)
+StgFunPtr StgReturn(void)
 {
-   return 0;
+    return 0;
 }
 
 #else /* !USE_MINIINTERPRETER */
@@ -164,6 +165,71 @@ StgRun(StgFunPtr f, StgRegTable *basereg) {
 
 #endif
 
+/* ----------------------------------------------------------------------------
+   x86-64 is almost the same as plain x86.
+
+   I've done it using entirely inline assembler, because I couldn't
+   get gcc to generate the correct subtraction from %rsp by using
+   the local array variable trick.  It didn't seem to reserve
+   enough space.  Oh well, it's not much harder this way.
+
+   ------------------------------------------------------------------------- */
+
+#ifdef x86_64_TARGET_ARCH
+
+extern StgThreadReturnCode StgRun(StgFunPtr f, StgRegTable *basereg);
+
+static void StgRunIsImplementedInAssembler(void)
+{
+    __asm__ volatile (
+       /*
+        * save callee-saves registers on behalf of the STG code.
+        */
+       ".globl StgRun\n"
+       "StgRun:\n\t"
+       "subq %0, %%rsp\n\t"
+       "movq %%rsp, %%rax\n\t"
+       "addq %0-48, %%rax\n\t"
+        "movq %%rbx,0(%%rax)\n\t"
+        "movq %%rbp,8(%%rax)\n\t"
+        "movq %%r12,16(%%rax)\n\t"
+        "movq %%r13,24(%%rax)\n\t"
+        "movq %%r14,32(%%rax)\n\t"
+        "movq %%r15,40(%%rax)\n\t"
+       /*
+        * Set BaseReg
+        */
+       "movq %%rsi,%%rbx\n\t"
+       /*
+        * grab the function argument from the stack, and jump to it.
+        */
+        "movq %%rdi,%%rax\n\t"
+        "jmp *%%rax\n\t"
+
+       ".global " STG_RETURN "\n"
+               STG_RETURN ":\n\t"
+
+       "movq %%r13, %%rax\n\t"   /* Return value in R1  */
+
+       /*
+        * restore callee-saves registers.  (Don't stomp on %%rax!)
+        */
+       "movq %%rsp, %%rdx\n\t"
+       "addq %0-48, %%rdx\n\t"
+        "movq 0(%%rdx),%%rbx\n\t"      /* restore the registers saved above */
+        "movq 8(%%rdx),%%rbp\n\t"
+        "movq 16(%%rdx),%%r12\n\t"
+        "movq 24(%%rdx),%%r13\n\t"
+        "movq 32(%%rdx),%%r14\n\t"
+        "movq 40(%%rdx),%%r15\n\t"
+       "addq %0, %%rsp\n\t"
+       "retq"
+
+       : : "i"(RESERVED_C_STACK_BYTES+48 /*stack frame size*/));
+}
+
+#endif /* x86-64 */
+
 /* -----------------------------------------------------------------------------
    Sparc architecture
 
@@ -465,6 +531,7 @@ StgRun(StgFunPtr f, StgRegTable *basereg)
 
 extern StgThreadReturnCode StgRun(StgFunPtr f, StgRegTable *basereg);
 
+#ifdef darwin_TARGET_OS
 static void StgRunIsImplementedInAssembler(void)
 {
        __asm__ volatile (
@@ -472,19 +539,96 @@ static void StgRunIsImplementedInAssembler(void)
                "_StgRun:\n"
                "\tmflr r0\n"
                "\tbl saveFP # f14\n"
-               "\tstmw r14,-216(r1)\n"
-               "\tstwu r1,-8480(r1)\n"
+               "\tstmw r13,-220(r1)\n"
+               "\tstwu r1,-%0(r1)\n"
+                "\tmr r27,r4\n" // BaseReg == r27
                "\tmtctr r3\n"
                "\tmr r12,r3\n"
                "\tbctr\n"
                ".globl _StgReturn\n"
                "_StgReturn:\n"
                "\tmr r3,r14\n"
-               "\tla r1,8480(r1)\n"
-               "\tlmw r14,-216(r1)\n"
+               "\tla r1,%0(r1)\n"
+               "\tlmw r13,-220(r1)\n"
                "\tb restFP # f14\n"
-       );      /* RESERVED_C_STACK_BYTES + stack frame size == 8192 + 288 == 8480 */
+       : : "i"(RESERVED_C_STACK_BYTES+288 /*stack frame size*/));
 }
+#else
+
+// This version is for PowerPC Linux.
+
+// Differences from the Darwin/Mac OS X version:
+// *) Different Assembler Syntax
+// *) Doesn't use Register Saving Helper Functions (although they exist somewhere)
+// *) We may not access positive stack offsets
+//    (no "Red Zone" as in the Darwin ABI)
+// *) The Link Register is saved to a different offset in the caller's stack frame
+//    (Linux: 4(r1), Darwin 8(r1))
+
+static void StgRunIsImplementedInAssembler(void)
+{
+       __asm__ volatile (
+               "\t.globl StgRun\n"
+               "\t.type StgRun,@function\n"
+               "StgRun:\n"
+               "\tmflr 0\n"
+               "\tstw 0,4(1)\n"
+               "\tmr 5,1\n"
+               "\tstwu 1,-%0(1)\n"
+               "\tstmw 13,-220(5)\n"
+               "\tstfd 14,-144(5)\n"
+               "\tstfd 15,-136(5)\n"
+               "\tstfd 16,-128(5)\n"
+               "\tstfd 17,-120(5)\n"
+               "\tstfd 18,-112(5)\n"
+               "\tstfd 19,-104(5)\n"
+               "\tstfd 20,-96(5)\n"
+               "\tstfd 21,-88(5)\n"
+               "\tstfd 22,-80(5)\n"
+               "\tstfd 23,-72(5)\n"
+               "\tstfd 24,-64(5)\n"
+               "\tstfd 25,-56(5)\n"
+               "\tstfd 26,-48(5)\n"
+               "\tstfd 27,-40(5)\n"
+               "\tstfd 28,-32(5)\n"
+               "\tstfd 29,-24(5)\n"
+               "\tstfd 30,-16(5)\n"
+               "\tstfd 31,-8(5)\n"
+               "\tmr 27,4\n"  // BaseReg == r27
+               "\tmtctr 3\n"
+               "\tmr 12,3\n"
+               "\tbctr\n"
+               ".globl StgReturn\n"
+               "\t.type StgReturn,@function\n"
+               "StgReturn:\n"
+               "\tmr 3,14\n"
+               "\tla 5,%0(1)\n"
+               "\tlmw 13,-220(5)\n"
+               "\tlfd 14,-144(5)\n"
+               "\tlfd 15,-136(5)\n"
+               "\tlfd 16,-128(5)\n"
+               "\tlfd 17,-120(5)\n"
+               "\tlfd 18,-112(5)\n"
+               "\tlfd 19,-104(5)\n"
+               "\tlfd 20,-96(5)\n"
+               "\tlfd 21,-88(5)\n"
+               "\tlfd 22,-80(5)\n"
+               "\tlfd 23,-72(5)\n"
+               "\tlfd 24,-64(5)\n"
+               "\tlfd 25,-56(5)\n"
+               "\tlfd 26,-48(5)\n"
+               "\tlfd 27,-40(5)\n"
+               "\tlfd 28,-32(5)\n"
+               "\tlfd 29,-24(5)\n"
+               "\tlfd 30,-16(5)\n"
+               "\tlfd 31,-8(5)\n"
+               "\tmr 1,5\n"
+               "\tlwz 0,4(1)\n"
+               "\tmtlr 0\n"
+               "\tblr\n"
+       : : "i"(RESERVED_C_STACK_BYTES+288 /*stack frame size*/));
+}
+#endif
 
 #endif
 
@@ -498,6 +642,7 @@ static void StgRunIsImplementedInAssembler(void)
    loc16 - loc28: STG registers
            loc29: saved ar.pfs
            loc30: saved b0
+           loc31: saved gp (gcc 3.3 uses this slot)
    -------------------------------------------------------------------------- */
 
 #ifdef ia64_TARGET_ARCH
@@ -506,12 +651,19 @@ static void StgRunIsImplementedInAssembler(void)
 #undef RESERVED_C_STACK_BYTES
 #define RESERVED_C_STACK_BYTES 1024
 
+#if ((__GNUC__ == 3) && (__GNUC_MINOR__ >= 3)) || (__GNUC__ > 3)
+/* gcc 3.3+: leave an extra slot for gp saves */
+#define LOCALS 32
+#else
+#define LOCALS 31
+#endif
+
 static void StgRunIsImplementedInAssembler(void)
 {
     __asm__ volatile(
                ".global StgRun\n"
                "StgRun:\n"
-               "\talloc loc29 = ar.pfs, 0, 31, 8, 0\n" /* setup register frame */
+               "\talloc loc29 = ar.pfs, 0, %1, 8, 0\n" /* setup register frame */
                "\tld8 r18 = [r32],8\n"                 /* get procedure address */
                "\tadds sp = -%0, sp ;;\n"              /* setup stack */
                "\tld8 gp = [r32]\n"                    /* get procedure GP */
@@ -541,7 +693,7 @@ static void StgRunIsImplementedInAssembler(void)
                "\tldf.fill f21 = [r17],32\n"
                "\tadds sp = %0, sp\n"          /* restore stack */
                "\tbr.ret.sptk.many b0 ;;\n"    /* return */
-       : : "i"(RESERVED_C_STACK_BYTES + 6*16));
+       : : "i"(RESERVED_C_STACK_BYTES + 6*16), "i"(LOCALS));
 }
 
 #endif