[project @ 2002-04-25 18:48:02 by panne]
[ghc-hetmet.git] / ghc / rts / Adjustor.c
index 85273a8..72cc3b6 100644 (file)
@@ -42,7 +42,7 @@ Haskell side.
 #include "RtsFlags.h"
 
 /* Heavily arch-specific, I'm afraid.. */
-#if defined(i386_TARGET_ARCH) || defined(sparc_TARGET_ARCH) || defined(alpha_TARGET_ARCH)
+#if defined(i386_TARGET_ARCH) || defined(sparc_TARGET_ARCH) || defined(alpha_TARGET_ARCH) || defined(powerpc_TARGET_ARCH)
 
 #if defined(i386_TARGET_ARCH)
 /* Now here's something obscure for you:
@@ -192,6 +192,14 @@ createAdjustor(int cconv, StgStablePtr hptr, StgFunPtr wptr)
     place %i4 and %i5 at [%sp+92] and [%sp+96] respectively.  This
     machinery should then work in all cases.  (Or would it?  Perhaps
     it would trash parts of the caller's frame.  Dunno).  
+
+    SUP, 25 Apr 02: We are quite lucky to push a multiple of 8 bytes in
+    front of the existing arguments, because %sp must stay double-word
+    aligned at all times, see: http://www.sparc.org/standards/psABI3rd.pdf
+    Although we extend the *caller's* stack frame, this shouldn't cause
+    any problems for a C-like caller: alloca is implemented similarly, and
+    local variables should be accessed via %fp, not %sp. In a nutshell:
+    This should work. (Famous last words! :-)
   */
     if ((adjustor = stgMallocBytes(4*(8+1), "createAdjustor")) != NULL) {
        unsigned long *const adj_code = (unsigned long *)adjustor;
@@ -222,6 +230,18 @@ createAdjustor(int cconv, StgStablePtr hptr, StgFunPtr wptr)
        adj_code[7] |= ((unsigned long)hptr) & 0x000003ff;
 
        adj_code[8] = (StgStablePtr)hptr;
+
+       /* flush cache */
+       asm("flush %0" : : "r" (adj_code    ));
+       asm("flush %0" : : "r" (adj_code + 2));
+       asm("flush %0" : : "r" (adj_code + 4));
+       asm("flush %0" : : "r" (adj_code + 6));
+
+       /* max. 5 instructions latency, and we need at >= 1 for returning */
+       asm("nop");
+       asm("nop");
+       asm("nop");
+       asm("nop");
     }
 #elif defined(alpha_TARGET_ARCH)
   /* Magic constant computed by inspecting the code length of
@@ -280,6 +300,70 @@ TODO: Depending on how much allocation overhead stgMallocBytes uses for
        /* Ensure that instruction cache is consistent with our new code */
        __asm__ volatile("call_pal %0" : : "i" (PAL_imb));
     }
+#elif defined(powerpc_TARGET_ARCH)
+/*
+       For PowerPC, the following code is used:
+
+       mr r10,r8
+       mr r9,r7
+       mr r8,r6
+       mr r7,r5
+       mr r6,r4
+       mr r5,r3
+       lis r0,0xDEAD ;hi(wptr)
+       lis r3,0xDEAF ;hi(hptr)
+       ori r0,r0,0xBEEF ; lo(wptr)
+       ori r3,r3,0xFACE ; lo(hptr)
+       mtctr r0
+       bctr
+
+       The arguments (passed in registers r3 - r10) are shuffled along by two to
+       make room for hptr and a dummy argument. As r9 and r10 are overwritten by
+       this code, it only works for up to 6 arguments (when floating point arguments
+       are involved, this may be more or less, depending on the exact situation).
+*/
+       if ((adjustor = stgMallocBytes(4*13, "createAdjustor")) != NULL) {
+               unsigned long *const adj_code = (unsigned long *)adjustor;
+
+               // make room for extra arguments
+               adj_code[0] = 0x7d0a4378;       //mr r10,r8
+               adj_code[1] = 0x7ce93b78;       //mr r9,r7
+               adj_code[2] = 0x7cc83378;       //mr r8,r6
+               adj_code[3] = 0x7ca72b78;       //mr r7,r5
+               adj_code[4] = 0x7c862378;       //mr r6,r4
+               adj_code[5] = 0x7c651b78;       //mr r5,r3
+               
+               adj_code[6] = 0x3c000000;       //lis r0,hi(wptr)
+               adj_code[6] |= ((unsigned long)wptr) >> 16;
+               
+               adj_code[7] = 0x3c600000;       //lis r3,hi(hptr)
+               adj_code[6] |= ((unsigned long)hptr) >> 16;
+               
+               adj_code[8] = 0x60000000;       //ori r0,r0,lo(wptr)
+               adj_code[8] |= ((unsigned long)wptr) & 0xFFFF; 
+               
+               adj_code[9] = 0x60630000;       //ori r3,r3,lo(hptr)
+               adj_code[9] |= ((unsigned long)hptr) & 0xFFFF;
+               
+               adj_code[10] = 0x7c0903a6;      //mtctr r0
+               adj_code[11] = 0x4e800420;      //bctr
+               adj_code[12] = (unsigned long)hptr;
+               
+               // Flush the Instruction cache:
+               //      MakeDataExecutable(adjustor,4*13);
+                       /* This would require us to link with CoreServices.framework */
+               {               /* this should do the same: */
+                       int n = 13;
+                       unsigned long *p = adj_code;
+                       while(n--)
+                       {
+                               __asm__ volatile ("dcbf 0,%0\n\tsync\n\ticbi 0,%0"
+                                                   : : "g" (p));
+                               p++;
+                       }
+                       __asm__ volatile ("sync\n\tisync");
+               }
+       }
 #else
 #error Adjustor creation is not supported on this platform.
 #endif
@@ -313,14 +397,14 @@ freeHaskellFunctionPtr(void* ptr)
     freeStablePtr(*((StgStablePtr*)((unsigned char*)ptr + 0x02)));
  }    
 #elif defined(sparc_TARGET_ARCH)
- if ( *(unsigned char*)ptr != 0x13 ) {
+ if ( *(unsigned long*)ptr != 0x9A10000B ) {
    fprintf(stderr, "freeHaskellFunctionPtr: not for me, guv! %p\n", ptr);
    return;
  }
 
  /* Free the stable pointer first..*/
- freeStablePtr(*((StgStablePtr*)((unsigned char*)ptr + 0x10)));
-#elif defined(sparc_TARGET_ARCH)
+ freeStablePtr(*((StgStablePtr*)((unsigned long*)ptr + 8)));
+#elif defined(alpha_TARGET_ARCH)
  if ( *(StgWord64*)ptr != 0xa77b0018a61b0010L ) {
    fprintf(stderr, "freeHaskellFunctionPtr: not for me, guv! %p\n", ptr);
    return;
@@ -328,6 +412,12 @@ freeHaskellFunctionPtr(void* ptr)
 
  /* Free the stable pointer first..*/
  freeStablePtr(*((StgStablePtr*)((unsigned char*)ptr + 0x10)));
+#elif defined(powerpc_TARGET_ARCH)
+ if ( *(StgWord*)ptr != 0x7d0a4378 ) {
+   fprintf(stderr, "freeHaskellFunctionPtr: not for me, guv! %p\n", ptr);
+   return;
+ }
+ freeStablePtr(*((StgStablePtr*)((unsigned char*)ptr + 4*12)));
 #else
  ASSERT(0);
 #endif