/* -----------------------------------------------------------------------------
- * $Id: StgCRun.c,v 1.25 2001/08/07 20:06:41 ken 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.
*
* -------------------------------------------------------------------------- */
+#include "PosixSource.h"
+
/*
* We define the following (unused) global register variables, because for
* 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)
-------------------------------------------------------------------------- */
-
-/* The static @jmp_environment@ variable allows @miniInterpret@ to
- * communicate with @StgReturn@.
- *
- * Because @StgRun@ may be used recursively, we carefully
- * save and restore the whole of @jmp_environment@.
- */
-#include <setjmp.h>
-#include <string.h> /* for memcpy */
-
-static jmp_buf jmp_environment;
-
-#if 1
-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)();
return 0;
}
-#else
-
-#define CHECK_STACK 0
-#define STACK_DETAILS 0
-
-static int enters = 0;
-
-static void scanStackSeg ( W_* ptr, int nwords )
-{
- W_ w;
-#if CHECK_STACK
- int nwords0 = nwords;
-#if STACK_DETAILS
- 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");
-#endif
- checkStackChunk ( ptr, ptr-nwords0 );
-#endif
-}
-
-extern StgFunPtr stg_enterStackTop;
-extern StgThreadReturnCode StgRun(StgFunPtr f, StgRegTable *basereg)
-{
- char* nm;
- while (1) {
-
-#if CHECK_STACK
- {
- int i;
- StgTSO* tso = basereg->rCurrentTSO;
- StgWord* sb = tso->stack + tso->stack_size;
- StgWord* sp;
- StgWord* su;
- int ws;
-
- if (f == &stg_enterStackTop) {
- sp = tso->sp;
- su = tso->su;
- } else {
- sp = basereg->rSp;
- su = basereg->rSu;
- }
-
-#if STACK_DETAILS
- fprintf(stderr,
- "== SB = %p SP = %p(%p) SU = %p SpLim = %p(%p)\n",
- sb, sp, tso->sp, su, basereg->rSpLim, tso->stack + RESERVED_STACK_WORDS);
-#endif
-
- 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);
-#if STACK_DETAILS
- fprintf(stderr, "S%d ",ws);
- fprintf(stderr, "\n");
-#endif
- goto postloop;
- case UPDATE_FRAME:
- scanStackSeg(sp,ws);
-#if STACK_DETAILS
- fprintf(stderr,"U%d ",ws);
-#endif
- sp = su + sizeofW(StgUpdateFrame);
- su = ((StgUpdateFrame*)su)->link;
- break;
- case SEQ_FRAME:
- scanStackSeg(sp,ws);
-#if STACK_DETAILS
- fprintf(stderr,"Q%d ",ws);
-#endif
- sp = su + sizeofW(StgSeqFrame);
- su = ((StgSeqFrame*)su)->link;
- break;
- case CATCH_FRAME:
- scanStackSeg(sp,ws);
-#if STACK_DETAILS
- fprintf(stderr,"C%d ",ws);
-#endif
- sp = su + sizeofW(StgCatchFrame);
- su = ((StgCatchFrame*)su)->link;
- break;
- default:
- fprintf(stderr, "?\nweird record on stack\n");
- assert(0);
- goto postloop;
- }
- }
- postloop:
- }
-#endif
-#if STACK_DETAILS
- fprintf(stderr,"\n");
-#endif
-#if 1
- fprintf(stderr,"-- enter %p ", f);
- nm = nameFromOPtr ( f );
- if (nm) fprintf(stderr, "%s", nm); else
- printPtr((P_)f);
- fprintf ( stderr, "\n");
-#endif
-#if STACK_DETAILS
- fprintf(stderr,"\n");
-#endif
- zzz:
- if (enters % 1000 == 0) fprintf(stderr, "%d enters\n",enters);
- enters++;
- 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
/* -----------------------------------------------------------------------------
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 */
+