fix for gcc 4.1.x
[ghc-hetmet.git] / ghc / rts / StgCRun.c
index cf210d2..29d4efe 100644 (file)
@@ -82,17 +82,17 @@ register double fake_f9 __asm__("$f9");
    any architecture (using miniinterpreter)
    -------------------------------------------------------------------------- */
 
-StgThreadReturnCode StgRun(StgFunPtr f, StgRegTable *basereg STG_UNUSED)
+StgRegTable * StgRun(StgFunPtr f, StgRegTable *basereg STG_UNUSED)
 {
     while (f) {
-       if (RtsFlags[0].DebugFlags.interpreter) {
+       IF_DEBUG(interpreter,
            debugBelch("Jumping to ");
            printPtr((P_)f); fflush(stdout);
            debugBelch("\n");
-       }
+           );
        f = (StgFunPtr) (f)();
     }
-    return (StgThreadReturnCode)R1.i;
+    return (StgRegTable *)R1.p;
 }
 
 StgFunPtr StgReturn(void)
@@ -114,11 +114,17 @@ StgFunPtr StgReturn(void)
 
 #ifdef i386_HOST_ARCH
 
-StgThreadReturnCode
+#ifdef darwin_TARGET_OS
+#define STG_GLOBAL ".globl "
+#else
+#define STG_GLOBAL ".global "
+#endif
+
+StgRegTable *
 StgRun(StgFunPtr f, StgRegTable *basereg) {
 
     unsigned char space[ RESERVED_C_STACK_BYTES + 4*sizeof(void *) ];
-    StgThreadReturnCode r;
+    StgRegTable * r;
 
     __asm__ volatile (
        /*
@@ -135,14 +141,32 @@ StgRun(StgFunPtr f, StgRegTable *basereg) {
         */
        "movl %3,%%ebx\n\t"
        /*
-        * grab the function argument from the stack, and jump to it.
+        * grab the function argument from the stack
         */
         "movl %2,%%eax\n\t"
+        
+#if darwin_TARGET_OS
+       /*
+        * Darwin: keep the stack aligned
+        */
+        "subl $12,%%esp\n\t"
+#endif
+
+       /*
+        * jump to it
+        */
         "jmp *%%eax\n\t"
 
-       ".global " STG_RETURN "\n"
+       STG_GLOBAL STG_RETURN "\n"
                STG_RETURN ":\n\t"
 
+#if darwin_TARGET_OS
+       /*
+        * Darwin: keep the stack aligned
+        */
+        "addl $12,%%esp\n\t"
+#endif
+
        "movl %%esi, %%eax\n\t"   /* Return value in R1  */
 
        /*
@@ -177,9 +201,10 @@ StgRun(StgFunPtr f, StgRegTable *basereg) {
 
 #ifdef x86_64_HOST_ARCH
 
-extern StgThreadReturnCode StgRun(StgFunPtr f, StgRegTable *basereg);
+extern StgRegTable * StgRun(StgFunPtr f, StgRegTable *basereg);
 
-static void StgRunIsImplementedInAssembler(void)
+static void GNUC3_ATTRIBUTE(used)
+StgRunIsImplementedInAssembler(void)
 {
     __asm__ volatile (
        /*
@@ -199,7 +224,7 @@ static void StgRunIsImplementedInAssembler(void)
        /*
         * Set BaseReg
         */
-       "movq %%rsi,%%rbx\n\t"
+       "movq %%rsi,%%r13\n\t"
        /*
         * grab the function argument from the stack, and jump to it.
         */
@@ -209,7 +234,7 @@ static void StgRunIsImplementedInAssembler(void)
        ".global " STG_RETURN "\n"
                STG_RETURN ":\n\t"
 
-       "movq %%r13, %%rax\n\t"   /* Return value in R1  */
+       "movq %%rbx, %%rax\n\t"   /* Return value in R1  */
 
        /*
         * restore callee-saves registers.  (Don't stomp on %%rax!)
@@ -225,7 +250,41 @@ static void StgRunIsImplementedInAssembler(void)
        "addq %0, %%rsp\n\t"
        "retq"
 
-       : : "i"(RESERVED_C_STACK_BYTES+48 /*stack frame size*/));
+       : : "i"(RESERVED_C_STACK_BYTES+48+8 /*stack frame size*/));
+    /* 
+       HACK alert!
+
+       The x86_64 ABI specifies that on a procedure call, %rsp is
+       aligned on a 16-byte boundary + 8.  That is, the first
+       argument on the stack after the return address will be
+       16-byte aligned.  
+       
+       Which should be fine: RESERVED_C_STACK_BYTES+48 is a multiple
+       of 16 bytes.  
+       
+       BUT... when we do a C-call from STG land, gcc likes to put the
+       stack alignment adjustment in the prolog.  eg. if we're calling
+       a function with arguments in regs, gcc will insert 'subq $8,%rsp'
+       in the prolog, to keep %rsp aligned (the return address is 8
+       bytes, remember).  The mangler throws away the prolog, so we
+       lose the stack alignment.
+
+       The hack is to add this extra 8 bytes to our %rsp adjustment
+       here, so that throughout STG code, %rsp is 16-byte aligned,
+       ready for a C-call.  
+
+       A quick way to see if this is wrong is to compile this code:
+
+          main = System.Exit.exitWith ExitSuccess
+
+       And run it with +RTS -sstderr.  The stats code in the RTS, in
+       particular statsPrintf(), relies on the stack alignment because
+       it saves the %xmm regs on the stack, so it'll fall over if the
+       stack isn't aligned, and calling exitWith from Haskell invokes
+       shutdownHaskellAndExit using a C call.
+
+       Future gcc releases will almost certainly break this hack...
+    */
 }
 
 #endif /* x86-64 */
@@ -263,7 +322,7 @@ static void StgRunIsImplementedInAssembler(void)
 
 #ifdef sparc_HOST_ARCH
 
-StgThreadReturnCode
+StgRegTable *
 StgRun(StgFunPtr f, StgRegTable *basereg) {
 
     unsigned char space[RESERVED_C_STACK_BYTES];
@@ -296,7 +355,7 @@ StgRun(StgFunPtr f, StgRegTable *basereg) {
     __asm__ volatile ("ld %1,%0"
                      : "=r" (i7) : "m" (((void **)(space))[100]));
 #endif
-    return (StgThreadReturnCode)R1.i;
+    return (StgRegTable *)R1.i;
 }
 
 #endif
@@ -331,7 +390,7 @@ StgRun(StgFunPtr f, StgRegTable *basereg) {
 
 #ifdef alpha_HOST_ARCH
 
-StgThreadReturnCode
+StgRegTable *
 StgRun(StgFunPtr f, StgRegTable *basereg)
 {
     register long   real_ra __asm__("$26"); volatile long   save_ra;
@@ -360,7 +419,7 @@ StgRun(StgFunPtr f, StgRegTable *basereg)
 
     register StgFunPtr real_pv __asm__("$27");
 
-    StgThreadReturnCode ret;
+    StgRegTable * ret;
 
     save_ra = real_ra;
     save_gp = real_gp;
@@ -433,11 +492,11 @@ StgRun(StgFunPtr f, StgRegTable *basereg)
 
 #ifdef hppa1_1_HOST_ARCH
 
-StgThreadReturnCode
+StgRegTable *
 StgRun(StgFunPtr f, StgRegTable *basereg)
 {
     StgChar space[RESERVED_C_STACK_BYTES+16*sizeof(long)+10*sizeof(double)];
-    StgThreadReturnCode ret;
+    StgRegTable * ret;
 
     __asm__ volatile ("ldo %0(%%r30),%%r19\n"
                      "\tstw %%r3, 0(0,%%r19)\n"
@@ -529,10 +588,11 @@ StgRun(StgFunPtr f, StgRegTable *basereg)
 
 #ifdef powerpc_HOST_ARCH
 
-extern StgThreadReturnCode StgRun(StgFunPtr f, StgRegTable *basereg);
+extern StgRegTable * StgRun(StgFunPtr f, StgRegTable *basereg);
 
 #ifdef darwin_HOST_OS
-static void StgRunIsImplementedInAssembler(void)
+static void GNUC3_ATTRIBUTE(used)
+StgRunIsImplementedInAssembler(void)
 {
 #if HAVE_SUBSECTIONS_VIA_SYMBOLS
             // if the toolchain supports deadstripping, we have to
@@ -570,7 +630,8 @@ static void StgRunIsImplementedInAssembler(void)
 // *) 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)
+static void GNUC3_ATTRIBUTE(used)
+StgRunIsImplementedInAssembler(void)
 {
        __asm__ volatile (
                "\t.globl StgRun\n"
@@ -647,9 +708,10 @@ static void StgRunIsImplementedInAssembler(void)
 #ifdef powerpc64_HOST_ARCH
 
 #ifdef linux_HOST_OS
-extern StgThreadReturnCode StgRun(StgFunPtr f, StgRegTable *basereg);
+extern StgRegTable * StgRun(StgFunPtr f, StgRegTable *basereg);
 
-static void StgRunIsImplementedInAssembler(void)
+static void GNUC3_ATTRIBUTE(used)
+StgRunIsImplementedInAssembler(void)
 {
         // r0 volatile
        // r1 stack pointer
@@ -799,7 +861,8 @@ static void StgRunIsImplementedInAssembler(void)
 #define LOCALS 31
 #endif
 
-static void StgRunIsImplementedInAssembler(void)
+static void GNUC3_ATTRIBUTE(used)
+StgRunIsImplementedInAssembler(void)
 {
     __asm__ volatile(
                ".global StgRun\n"