do {SaveAllStgRegs(); PerformGC(args); RestoreAllStgRegs();} while(0)
#define DO_STACKOVERFLOW(headroom,args) \
do {SaveAllStgRegs(); StackOverflow(headroom,args); RestoreAllStgRegs();} while(0)
+
+#if defined(GRAN)
+
+#define DO_YIELD(args) DO_GRAN_YIELD(args)
+#define DO_GRAN_YIELD(liveness) \
+ do {SaveAllStgRegs(); Yield(liveness); RestoreAllStgRegs();} while(0)
+
+#define DO_PERFORM_RESCHEDULE(liveness_mask,reenter) \
+ do {SaveAllStgRegs(); PerformReschedule(liveness_mask,reenter); RestoreAllStgRegs();} while(0)
+
+#else
+
#define DO_YIELD(args) \
do {SaveAllStgRegs(); Yield(args); RestoreAllStgRegs();} while(0)
+#endif /* GRAN */
+
\end{code}
%************************************************************************
void PerformGC_wrapper PROTO((W_));
void StackOverflow_wrapper PROTO((W_, W_));
void Yield_wrapper PROTO((W_));
+# ifdef GRAN
+void PerformReschedule_wrapper PROTO((W_, W_));
+void GranSimAllocate_wrapper PROTO((I_, P_, W_));
+void GranSimUnallocate_wrapper PROTO((I_, P_, W_));
+void GranSimFetch_wrapper PROTO((P_));
+void GranSimExec_wrapper PROTO((W_, W_, W_, W_, W_));
+# endif
#endif
#define DO_GC(args) PerformGC_wrapper(args)
#define DO_STACKOVERFLOW(headroom,args) StackOverflow_wrapper(headroom,args)
+
+# ifdef GRAN
+
+#define DO_YIELD(args) DO_GRAN_YIELD(args)
+#define DO_GRAN_YIELD(liveness) Yield_wrapper(liveness)
+
+#define DO_PERFORMRESCHEDULE(liveness, always_reenter_node) PerformReschedule_wrapper(liveness, always_reenter_node)
+#define DO_GRANSIMALLOCATE(n, node, liveness) GranSimAllocate_wrapper(n, node, liveness)
+#define DO_GRANSIMUNALLOCATE(n, node, liveness) GranSimUnallocate_wrapper(n, node, liveness)
+#define DO_GRANSIMFETCH(node) GranSimFetch_wrapper(node)
+#define DO_GRANSIMEXEC(arith,branch,load,store,floats) GranSimExec_wrapper(arith,branch,load,store,floats)
+
+# else
+
#define DO_YIELD(args) Yield_wrapper(args)
+# endif
+
#endif /* __GNUC__ && __STG_GCC_REGS__ */
\end{code}
Call wrappers need to be able to call arbitrary functions, regardless of
their arguments and return types. (Okay, we actually only allow up to
-five arguments, because on the sparc it gets more complicated to handle
+five arguments, because on the SPARC it gets more complicated to handle
any more.) The nasty bit is that the return value can be in either an
integer register or a floating point register, and we don't know which.
(We {\em don't} handle structure returns, and we don't want to.)
Getting this right requires three extremely @MAGIC@ macros, no doubt
chock full of assembly gook for the current platform. These are
-@MAGIC_CALL_SETUP@, which gets ready for one of these magic calls,
+@MAGIC_CALL_SET
+UP@, which gets ready for one of these magic calls,
@MAGIC_CALL@, which performs the call and stashes away all possible
results, and @MAGIC_RETURN@, which collects all possible results back
up again.
-For example, in the sparc version, the @SETUP@ guarantees that we
+For example, in the SPARC version, the @SETUP@ guarantees that we
have enough space to store all of our argument registers for a wee
bit, and it gives a `C' name to the register that we're going to use
for the call. (It helps to do the call in actual `C' fashion, so that
#if defined(__GNUC__) && defined(__STG_GCC_REGS__)
-#if alpha_dec_osf1_TARGET
- /* Is this too specific */
+#if alpha_TARGET_ARCH
#define MAGIC_CALL_SETUP \
long WeNeedThisSpace[7]; \
#define SET_RETADDR(loc) { register StgFunPtrFunPtr ra __asm__ ("$26"); loc = ra; }
-#define WRAPPER_SETUP(f) SaveAllStgContext();
+#define WRAPPER_SETUP(f,ignore1,ignore2) SaveAllStgContext();
#define WRAPPER_RETURN(x) \
do {RestoreAllStgRegs(); if(x) JMP_(EnterNodeCode);} while(0);
\begin{code}
-#if hppa1_1_hp_hpux_TARGET
- /* Is this too specific */
+#if hppa1_1_TARGET_ARCH
#define MAGIC_CALL_SETUP \
long SavedIntArgRegs[4]; \
#define SET_RETADDR(loc) __asm__ volatile ("stw %%r2, %0" : "=m" ((void *)(loc)));
-#define WRAPPER_SETUP(f) SaveAllStgContext();
+#define WRAPPER_SETUP(f,ignore1,ignore2) SaveAllStgContext();
#define WRAPPER_RETURN(x) \
do {RestoreAllStgRegs(); if(x) JMP_(EnterNodeCode);} while(0);
%************************************************************************
\begin{code}
-
-#if i386_TARGET_ARCH || i486_TARGET_ARCH
+#if i386_TARGET_ARCH
/* modelled loosely on SPARC stuff */
/* NB: no MAGIC_CALL_SETUP, MAGIC_CALL, or MAGIC_RETURN! */
-#define WRAPPER_NAME(f) __asm__("L" #f "_wrapper")
+#define WRAPPER_NAME(f) /*nothing*/
+#if defined(solaris2_TARGET_OS) || defined(linux_TARGET_OS)
+#define REAL_NAME(f) #f
+#else
#define REAL_NAME(f) "_" #f
+#endif
-/* when we come into PerformGC_wrapper:
+/*
+ Threaded code needs to be able to grab the return address, in case we have
+ an intervening context switch.
+ */
- - %esp holds Hp (!); get it into 80(%ebx) -- quick!
+#define SET_RETADDR(loc,val) loc = val;
- - %esp needs to be bumped by (at least) 4, because
- C thinks an argument was passed on the stack
- (use 64 just for fun)
+/* the grab-%eax-quickly HACK is here because we use a VERY SPECIAL
+ calling convention on iX86 just for calling PerformGC_wrapper.
+ (WDP 95/09)
- - %eax holds the argument for PerformGC
+ NB: mangler makes sure that __temp_{eax,esp} get loaded.
+ (This is about as ugly as it can get.)
+*/
- - 104(%ebx) hold the return address -- address we want to
- go back to
+#define WRAPPER_SETUP(f,ret_addr,args) \
+ __asm__ volatile ( \
+ "movl " REAL_NAME(__temp_esp) ",%%edx\n" \
+ "\tmovl (%%edx),%0\n" \
+ "\tmovl " REAL_NAME(__temp_eax) ",%1" \
+ : "=r" (ret_addr), "=r" (args) ); \
+ SaveAllStgContext(ret_addr);
- - 100(%ebx) holds a %esp value that we can re-load with
- if need be
+/* Note re WRAPPER_SETUP: we have special code just for PerformGC_wrapper;
+ pls see its definition. WDP 95/09
+ Also note the EXTREMELY UGLY slamming in of an "sp_offset"; the
+ return address *is* on the stack, but it is hard to get there
+ before GCC has moved the sp pointer... WDP 95/11
*/
-#define WRAPPER_SETUP(f) \
- __asm__ volatile ( \
- ".globl " REAL_NAME(f) "_wrapper\n" \
- REAL_NAME(f) "_wrapper:\n" \
- "\tmovl %%esp,80(%%ebx)\n" \
- "\tmovl 100(%%ebx),%%esp\n" \
- "\tmovl %%eax,%0" : "=r" (args)); \
- __asm__ volatile ( \
- "movl %%esp,%0\n" \
- "\tsubl $64,%%esp" \
- : "=r" (SP_stack[++SP_stack_ptr])); \
- SaveAllStgContext();
-
-#define WRAPPER_RETURN(x) \
- do {P_ foo; \
- RestoreAllStgRegs(); \
- if(x) JMP_(EnterNodeCode); /* never used? */ \
- __asm__ volatile ( \
- "movl %1,%0\n" \
- "\tmovl %0,_MainRegTable+100" \
- : "=r" (foo) : "m" (SP_stack[SP_stack_ptr--]) ); \
- __asm__ volatile ( \
- "movl 80(%ebx),%esp\n" \
- "\tjmp *104(%ebx)" ); \
- } while(0);
+
+#define WRAPPER_RETURN(x) \
+ do {RestoreAllStgRegs(); if(x) JMP_(EnterNodeCode);} while(0);
#define SEPARATE_WRAPPER_RESTORE /* none */
#endif /* iX86 */
-
\end{code}
%************************************************************************
#define WRAPPER_NAME(f) /* nothing */
-#define WRAPPER_SETUP(f) SaveAllStgContext();
+#define WRAPPER_SETUP(f,ignore1,ignore2) SaveAllStgContext();
#define WRAPPER_RETURN(x) \
do {RestoreAllStgRegs(); if(x) JMP_(EnterNodeCode);} while(0);
#define WRAPPER_NAME(f) /* nothing */
-#define WRAPPER_SETUP(f) SaveAllStgContext();
+/*
+ Threaded code needs to be able to grab the return address, in case we have
+ an intervening context switch.
+ */
+
+#define SET_RETADDR(loc) { register StgFunPtrFunPtr ra __asm__ ("$31"); loc = ra; }
+
+#define WRAPPER_SETUP(f,ignore1,ignore2) SaveAllStgContext();
#define WRAPPER_RETURN(x) \
do {RestoreAllStgRegs(); if(x) JMP_(EnterNodeCode);} while(0);
%************************************************************************
%* *
-\subsubsection[sparc-magic]{Call-wrapper MAGIC for SPARC}
+\subsubsection[powerpc-magic]{Call-wrapper MAGIC for PowerPC}
%* *
%************************************************************************
\begin{code}
+#if powerpc_TARGET_ARCH || rs6000_TARGET_ARCH
+
+#define MAGIC_CALL_SETUP \
+ register void (*f)() __asm__("$2"); \
+ __asm__ volatile ( \
+ "not used!!!????\n" \
+ : : : "$2" );
+#define MAGIC_CALL \
+ (*f)(); \
+ __asm__ volatile ( \
+ "not used!!!????\n");
+
+#define MAGIC_RETURN \
+ __asm__ volatile ( \
+ "not used!!!????\n");
+
+#define WRAPPER_NAME(f) /* nothing */
+
+#define SET_RETADDR(loc) \
+ __asm__ volatile ( \
+ "mflr 0\n" \
+ "\tst 0,%0" \
+ :"=m" (loc) :: "0");
+/* __asm__ volatile ("st %%r0, %0" : "=m" ((void *)(loc))); */
+
+#define WRAPPER_SETUP(f,ignore1,ignore2) SaveAllStgContext();
+
+/* we have to make sure the STG registers are restored.
+GCC tries to restore the value the registers had in
+the beginning of the current call, which we don't want.
+We defeat it by saving the registers in the stack again. :-( */
+
+#define WRAPPER_RETURN(x) \
+ do {RestoreAllStgRegs(); if(x) JMP_(EnterNodeCode);} while(0); \
+ __asm__ volatile ( \
+ "cal 1,136(1)\n" \
+ "\tstm 14,-72(1)\n" \
+ "\tstu 1,-136(1)");
+
+#define SEPARATE_WRAPPER_RESTORE /* none */
+
+#endif /* powerpc */
+\end{code}
+
+%************************************************************************
+%* *
+\subsubsection[sparc-magic]{Call-wrapper MAGIC for SPARC}
+%* *
+%************************************************************************
+
+\begin{code}
#if sparc_TARGET_ARCH
#define MAGIC_CALL_SETUP \
"\tstd %i2,[%fp-32]\n" \
"\tstd %i4,[%fp-24]");
+/* Lest GCC attempt to stick something in
+ the delay slot: with compile with
+ -fno-delayed-branch. A weak solution. WDP 96/07
+*/
#define MAGIC_CALL \
__asm__ volatile ( \
"ld [%%fp-40],%%o5\n" \
__asm__ volatile ( \
"std %f0,[%fp-40]\n" \
"\tstd %o0,[%fp-32]");
+#if 0
+/* We leave nothing to chance here; we have seen
+ GCC stick "unwanted" code in the branch delay
+ slot, causing mischief (WDP 96/05)
+*/
+/* the problem with this one: GCC has no way of
+ knowing there is a "call" in there, so it
+ does not do any calling-convention stuff
+ (e.g., saving used regs). WDP 96/07
+*/
+#define MAGIC_CALL \
+ __asm__ volatile ( \
+ "ld [%%fp-40],%%o5\n" \
+ "\tld [%%fp-36],%%o0\n" \
+ "\tld [%%fp-32],%%o1\n" \
+ "\tld [%%fp-28],%%o2\n" \
+ "\tld [%%fp-24],%%o3\n" \
+ "\tld [%%fp-20],%%o4\n" \
+ "\tcall %%o5\n" \
+ "\tnop\n" \
+ "\tstd %%f0,[%%fp-40]\n"\
+ "\tstd %%o0,[%%fp-32]" \
+ : : : "%o0", "%o1", "%o2", "%o3", "%o4", "%o5", "%o7", "%f0", "memory");
+#endif /* 0 */
#define MAGIC_RETURN \
__asm__ volatile ( \
"\tldd [%fp-32],%i0");
/*
- We rename the entry points for wrappers so that we can
- introduce a new entry point after the prologue. We want to ensure
- that the register window does not slide! However, we insert a
- call to abort() to make gcc _believe_ that the window slid.
+ We rename the entry points for wrappers so that we can introduce a
+ new entry point after the prologue. We want to ensure that the
+ register window does not slide! However, we insert a call to
+ abort() to make gcc _believe_ that the window slid.
*/
#define WRAPPER_NAME(f) __asm__("L" #f "_wrapper")
#define REAL_NAME(f) "_" #f
#endif
-#define WRAPPER_SETUP(f) \
+#define WRAPPER_SETUP(f,ignore1,ignore2) \
__asm__ volatile ( \
".global " REAL_NAME(f) "_wrapper\n"\
REAL_NAME(f) "_wrapper:\n" \
"\tmov %i0,%o0\n" \
"\tmov %i1,%o1");
/*
- * In the above, we want to ensure that the arguments are both in the %i registers
- * and the %o registers, with the assumption that gcc will expect them now to be in
- * one or the other. This is a terrible hack.
+ * In the above, we want to ensure that the arguments are both in the
+ * %i registers and the %o registers, with the assumption that gcc
+ * will expect them now to be in one or the other. This is a terrible
+ * hack.
*/
/*
- Threaded code needs to be able to grab the return address, in case we have
- an intervening context switch. Note that we want the address of the next
- instruction to be executed, so we add 8 to the link address.
+ Threaded code needs to be able to grab the return address, in case
+ we have an intervening context switch. Note that we want the
+ address of the next instruction to be executed, so we add 8 to the
+ link address.
*/
#define SET_RETADDR(loc) \