/* -----------------------------------------------------------------------------
- * $Id: StgCRun.c,v 1.26 2001/08/14 13:40:09 sewardj Exp $
+ * $Id: StgCRun.c,v 1.39 2003/06/09 13:17:41 matthewc Exp $
*
* (c) The GHC Team, 1998-2000
*
* 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
+ * 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.
+ * variables.
*
* -------------------------------------------------------------------------- */
* definition has been read. Any point after #include "Stg.h" would be too
* late.
*
- * You can define alpha_EXTRA_CAREFUL here to save $s6, $f8 and $f9 -- registers
- * that we don't use but which are callee-save registers. It shouldn't be
- * necessary.
+ * We define alpha_EXTRA_CAREFUL here to save $s6, $f8 and $f9 -- registers
+ * that we don't use but which are callee-save registers. The __divq() routine
+ * in libc.a clobbers $s6.
*/
#include "config.h"
#ifdef alpha_TARGET_ARCH
-#undef alpha_EXTRA_CAREFUL
+#define alpha_EXTRA_CAREFUL
register long fake_ra __asm__("$26");
+register long fake_gp __asm__("$29");
#ifdef alpha_EXTRA_CAREFUL
register long fake_s6 __asm__("$15");
register double fake_f8 __asm__("$f8");
/* -----------------------------------------------------------------------------
any architecture (using miniinterpreter)
-------------------------------------------------------------------------- */
-
-extern StgThreadReturnCode StgRun(StgFunPtr f, StgRegTable *basereg)
+
+extern StgThreadReturnCode StgRun(StgFunPtr f, StgRegTable *basereg STG_UNUSED)
{
while (f) {
- IF_DEBUG(evaluator,
+ IF_DEBUG(interpreter,
fprintf(stderr,"Jumping to ");
- printPtr((P_)f);
+ printPtr((P_)f); fflush(stdout);
fprintf(stderr,"\n");
);
f = (StgFunPtr) (f)();
/* -----------------------------------------------------------------------------
x86 architecture
-------------------------------------------------------------------------- */
-
+
#ifdef i386_TARGET_ARCH
StgThreadReturnCode
StgThreadReturnCode r;
__asm__ volatile (
- /*
+ /*
* save callee-saves registers on behalf of the STG code.
*/
"movl %%esp, %%eax\n\t"
/* -----------------------------------------------------------------------------
Sparc architecture
- --
+ --
OLD COMMENT from GHC-3.02:
We want tailjumps to be calls, because `call xxx' is the only Sparc
Updated info (GHC 4.08.2): not saving %i7 any more (see below).
-------------------------------------------------------------------------- */
-
+
#ifdef sparc_TARGET_ARCH
StgThreadReturnCode
#endif
f();
__asm__ volatile (
- ".align 4\n"
+ ".align 4\n"
".global " STG_RETURN "\n"
- STG_RETURN ":"
+ 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
* call to f(), this gets clobbered in STG land and we end up
* dereferencing a bogus pointer in StgReturn.
*/
- __asm__ volatile ("ld %1,%0"
+ __asm__ volatile ("ld %1,%0"
: "=r" (i7) : "m" (((void **)(space))[100]));
#endif
return (StgThreadReturnCode)R1.i;
Architecture Reference Manual_, and as a result of asynchronous software
actions."
- -- Compaq Computer Corporation, Houston. Tru64 UNIX Calling Standard for
+ -- Compaq Computer Corporation, Houston. Tru64 UNIX Calling Standard for
Alpha Systems, 5.1 edition, August 2000, section 3.2.1. http://www.
tru64unix.compaq.com/docs/base_doc/DOCUMENTATION/V51_PDF/ARH9MBTE.PDF
-------------------------------------------------------------------------- */
#ifdef alpha_TARGET_ARCH
StgThreadReturnCode
-StgRun(StgFunPtr f, StgRegTable *basereg)
+StgRun(StgFunPtr f, StgRegTable *basereg)
{
register long real_ra __asm__("$26"); volatile long save_ra;
+ register long real_gp __asm__("$29"); volatile long save_gp;
register long real_s0 __asm__("$9" ); volatile long save_s0;
register long real_s1 __asm__("$10"); volatile long save_s1;
#ifdef alpha_EXTRA_CAREFUL
register long real_s6 __asm__("$15"); volatile long save_s6;
#endif
-
+
register double real_f2 __asm__("$f2"); volatile double save_f2;
register double real_f3 __asm__("$f3"); volatile double save_f3;
register double real_f4 __asm__("$f4"); volatile double save_f4;
StgThreadReturnCode ret;
save_ra = real_ra;
+ save_gp = real_gp;
save_s0 = real_s0;
save_s1 = real_s1;
#endif
real_ra = save_ra;
+ real_gp = save_gp;
return ret;
}
#ifdef hppa1_1_TARGET_ARCH
StgThreadReturnCode
-StgRun(StgFunPtr f, StgRegTable *basereg)
+StgRun(StgFunPtr f, StgRegTable *basereg)
{
StgChar space[RESERVED_C_STACK_BYTES+16*sizeof(long)+10*sizeof(double)];
StgThreadReturnCode ret;
"\tfldds 8(0,%%r19),%%fr19\n"
"\tldo 32(%%r19),%%r19\n"
"\tfldds -16(0,%%r19),%%fr20\n"
- "\tfldds -8(0,%%r19),%%fr21\n"
+ "\tfldds -8(0,%%r19),%%fr21\n"
: "=r" (ret)
: "n" (-(116 * sizeof(long) + 10 * sizeof(double)))
: "%r19"
#endif /* hppa1_1_TARGET_ARCH */
+/* -----------------------------------------------------------------------------
+ PowerPC architecture
+
+ Everything is in assembler, so we don't have to deal with GCC...
+
+ -------------------------------------------------------------------------- */
+
+#ifdef powerpc_TARGET_ARCH
+
+extern StgThreadReturnCode StgRun(StgFunPtr f, StgRegTable *basereg);
+
+static void StgRunIsImplementedInAssembler(void)
+{
+ __asm__ volatile (
+ "\n.globl _StgRun\n"
+ "_StgRun:\n"
+ "\tmflr r0\n"
+ "\tbl saveFP # f14\n"
+ "\tstmw r13,-220(r1)\n"
+ "\tstwu r1,-%0(r1)\n"
+ "\tmtctr r3\n"
+ "\tmr r12,r3\n"
+ "\tbctr\n"
+ ".globl _StgReturn\n"
+ "_StgReturn:\n"
+ "\tmr r3,r14\n"
+ "\tla r1,%0(r1)\n"
+ "\tlmw r13,-220(r1)\n"
+ "\tb restFP # f14\n"
+ : : "i"(RESERVED_C_STACK_BYTES+288 /*stack frame size*/));
+}
+
+#endif
+
+/* -----------------------------------------------------------------------------
+ IA64 architecture
+
+ Again, in assembler - so we can fiddle with the register stack, and because
+ gcc doesn't handle asm-clobbered callee-saves correctly.
+
+ loc0 - loc15: preserved locals
+ loc16 - loc28: STG registers
+ loc29: saved ar.pfs
+ loc30: saved b0
+ loc31: saved gp (gcc 3.3 uses this slot)
+ -------------------------------------------------------------------------- */
+
+#ifdef ia64_TARGET_ARCH
+
+/* the memory stack is rarely used, so 16K is excessive */
+#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, %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 */
+ "\tadds r16 = %0-(6*16), sp\n"
+ "\tadds r17 = %0-(5*16), sp ;;\n"
+ "\tstf.spill [r16] = f16,32\n" /* spill callee-saved fp regs */
+ "\tstf.spill [r17] = f17,32\n"
+ "\tmov b6 = r18 ;;\n" /* set target address */
+ "\tstf.spill [r16] = f18,32\n"
+ "\tstf.spill [r17] = f19,32\n"
+ "\tmov loc30 = b0 ;;\n" /* save return address */
+ "\tstf.spill [r16] = f20,32\n"
+ "\tstf.spill [r17] = f21,32\n"
+ "\tbr.few b6 ;;\n" /* branch to function */
+ ".global StgReturn\n"
+ "StgReturn:\n"
+ "\tmov r8 = loc16\n" /* return value in r8 */
+ "\tadds r16 = %0-(6*16), sp\n"
+ "\tadds r17 = %0-(5*16), sp ;;\n"
+ "\tldf.fill f16 = [r16],32\n" /* start restoring fp regs */
+ "\tldf.fill f17 = [r17],32\n"
+ "\tmov ar.pfs = loc29 ;;\n" /* restore register frame */
+ "\tldf.fill f18 = [r16],32\n"
+ "\tldf.fill f19 = [r17],32\n"
+ "\tmov b0 = loc30 ;;\n" /* restore return address */
+ "\tldf.fill f20 = [r16],32\n"
+ "\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"(LOCALS));
+}
+
+#endif
+
#endif /* !USE_MINIINTERPRETER */
+