-\section[COptWraps]{Wrappers for calls to ``STG C'' routines}
-
-% this file is part of the C-as-assembler document
-
-\begin{code}
-#ifndef COPTWRAPS_H
-#define COPTWRAPS_H
-\end{code}
-
-%************************************************************************
-%* *
-\subsection[COptWraps-portable]{Wrappers for ``portable~C''}
-%* *
-%************************************************************************
-
-@STGCALL@ macros are used when we really have to be careful about saving
-any caller-saves STG registers. @SAFESTGCALL@ macros are used
-when the caller has previously arranged to save/restore volatile user
-registers (vanilla, float, and double STG registers), and we only have to
-worry about the ``system'' registers (stack and heap pointers, @STK_STUB@,
-etc.). @STGCALL_GC@ macros are used whenever the callee is going to
-need to access (and perhaps modify) some STG registers. @ULTRASAFESTGCALL@
-is available for our own routines that we are absolutely certain will not
-damage any STG registers.
-
-In short,
-\begin{itemize}
-\item @STGCALL@ saves/restores all caller-saves STG registers.
-\item @SAFESTGCALL@ saves/restores only caller-saves STG ``system'' registers.
-\item @ULTRASAFECALL@ is a simple call, without a wrapper.
-\item @STGCALL_GC@ saves/restores {\em all} STG registers.
-\end{itemize}
-
-Several macros are provided to handle outcalls to functions requiring from
-one to five arguments. (If we could assume GCC, we could use macro varargs,
-but unfortunately, we have to cater to ANSI C as well.)
-
-\begin{code}
-
-#define ULTRASAFESTGCALL0(t,p,f) f()
-#define ULTRASAFESTGCALL1(t,p,f,a) f(a)
-#define ULTRASAFESTGCALL2(t,p,f,a,b) f(a,b)
-#define ULTRASAFESTGCALL3(t,p,f,a,b,c) f(a,b,c)
-#define ULTRASAFESTGCALL4(t,p,f,a,b,c,d) f(a,b,c,d)
-#define ULTRASAFESTGCALL5(t,p,f,a,b,c,d,e) f(a,b,c,d,e)
-
-#if ! (defined(__GNUC__) && defined(__STG_GCC_REGS__))
-
-#define STGCALL0(t,p,f) f()
-#define STGCALL1(t,p,f,a) f(a)
-#define STGCALL2(t,p,f,a,b) f(a,b)
-#define STGCALL3(t,p,f,a,b,c) f(a,b,c)
-#define STGCALL4(t,p,f,a,b,c,d) f(a,b,c,d)
-#define STGCALL5(t,p,f,a,b,c,d,e) f(a,b,c,d,e)
-
-#define SAFESTGCALL0(t,p,f) f()
-#define SAFESTGCALL1(t,p,f,a) f(a)
-#define SAFESTGCALL2(t,p,f,a,b) f(a,b)
-#define SAFESTGCALL3(t,p,f,a,b,c) f(a,b,c)
-#define SAFESTGCALL4(t,p,f,a,b,c,d) f(a,b,c,d)
-#define SAFESTGCALL5(t,p,f,a,b,c,d,e) f(a,b,c,d,e)
-
-/*
- * Generic call_GC wrappers have gone away in favor of these partially
- * evaluated versions.
- */
-
-#define DO_GC(args) \
- 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}
-
-%************************************************************************
-%* *
-\subsection[COptWraps-optimised]{Wrappers in ``optimised~C''}
-%* *
-%************************************************************************
-
-We {\em expect} the call-wrappery to be boring---the defaults shown
-herein will kick in--- but you never know.
-
-For example: Don't try an @STGCALL6@ on a SPARC! That's because you
-cannot pass that many arguments to \tr{f} just by heaving them into
-\tr{%o*} registers; anything else is too painful to contemplate.
-
-\begin{code}
-#else /* __GNUC__ && __STG_GCC_REGS__ */
-
-#if !(defined(CALLER_SAVES_SYSTEM) || defined(CALLER_SAVES_USER))
-#define STGCALL0(t,p,f) f()
-#define STGCALL1(t,p,f,a) f(a)
-#define STGCALL2(t,p,f,a,b) f(a,b)
-#define STGCALL3(t,p,f,a,b,c) f(a,b,c)
-#define STGCALL4(t,p,f,a,b,c,d) f(a,b,c,d)
-#define STGCALL5(t,p,f,a,b,c,d,e) f(a,b,c,d,e)
-
-#else
-
-extern void callWrapper(STG_NO_ARGS);
-
-#define STGCALL0(t,p,f) \
- ({t (*_w)p = (t (*)p) callWrapper; (*_w)((void *)f);})
-
-#define STGCALL1(t,p,f,a) \
- ({t (*_w)p = (t (*)p) callWrapper; (*_w)((void *)f,a);})
-
-#define STGCALL2(t,p,f,a,b) \
- ({t (*_w)p = (t (*)p) callWrapper; (*_w)((void *)f,a,b);})
-
-#define STGCALL3(t,p,f,a,b,c) \
- ({t (*_w)p = (t (*)p) callWrapper; (*_w)((void *)f,a,b,c);})
-
-#define STGCALL4(t,p,f,a,b,c,d) \
- ({t (*_w)p = (t (*)p) callWrapper; (*_w)((void *)f,a,b,c,d);})
-
-#define STGCALL5(t,p,f,a,b,c,d,e) \
- ({t (*_w)p = (t (*)p) callWrapper; (*_w)((void *)f,a,b,c,d,e);})
-
-#endif
-
-#if !defined(CALLER_SAVES_SYSTEM)
-#define SAFESTGCALL0(t,p,f) f()
-#define SAFESTGCALL1(t,p,f,a) f(a)
-#define SAFESTGCALL2(t,p,f,a,b) f(a,b)
-#define SAFESTGCALL3(t,p,f,a,b,c) f(a,b,c)
-#define SAFESTGCALL4(t,p,f,a,b,c,d) f(a,b,c,d)
-#define SAFESTGCALL5(t,p,f,a,b,c,d,e) f(a,b,c,d,e)
-
-#else
-
-extern void callWrapper_safe(STG_NO_ARGS);
-
-#define SAFESTGCALL0(t,p,f) \
- ({t (*_w)p = (t (*)p) callWrapper_safe; (*_w)((void *)f);})
-
-#define SAFESTGCALL1(t,p,f,a) \
- ({t (*_w)p = (t (*)p) callWrapper_safe; (*_w)((void *)f,a);})
-
-#define SAFESTGCALL2(t,p,f,a,b) \
- ({t (*_w)p = (t (*)p) callWrapper_safe; (*_w)((void *)f,a,b);})
-
-#define SAFESTGCALL3(t,p,f,a,b,c) \
- ({t (*_w)p = (t (*)p) callWrapper_safe; (*_w)((void *)f,a,b,c);})
-
-#define SAFESTGCALL4(t,p,f,a,b,c,d) \
- ({t (*_w)p = (t (*)p) callWrapper_safe; (*_w)((void *)f,a,b,c,d);})
-
-#define SAFESTGCALL5(t,p,f,a,b,c,d,e) \
- ({t (*_w)p = (t (*)p) callWrapper_safe; (*_w)((void *)f,a,b,c,d,e);})
-
-#endif
-
-/*
- * Generic call_GC wrappers have gone away in favor of these partially
- * evaluated versions. These are only here so that we can avoid putting
- * all of the STG register save/restore code at each call site.
- */
-
-#ifndef CALLWRAPPER_C
-/*
- * We may have funny declarations in CallWrapper_C, to avoid sliding the
- * register windows and other nastiness.
- */
-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}
-
-%************************************************************************
-%* *
-\subsection[COptWraps-magic]{Magic assembly bits for call wrappers}
-%* *
-%************************************************************************
-
-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
-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.)
-Still, we have to stash the result away while we restore caller-saves
-STG registers, and then we have to pass the result back to our caller
-in the end.
-
-Getting this right requires three extremely @MAGIC@ macros, no doubt
-chock full of assembly gook for the current platform. These are
-@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
-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
-gcc knows about register death.) It also stashes the incoming arguments
-in the space provided. The @MAGIC_CALL@ then reloads the argument
-registers, rotated by one, so that the function to call is in \tr{%o5},
-calls the function in `C' fashion, and stashes away the possible return
-values (either \tr{%o0} or \tr{%f0}) on the stack. Finally, @MAGIC_RETURN@
-ensures that \tr{%o0} and \tr{%f0} are both set to the values we stashed
-away. Presumably, we then fall into a return instruction and our caller
-gets whatever it's after.
-
-%************************************************************************
-%* *
-\subsubsection[alpha-magic]{Call-wrapper MAGIC for DEC Alpha}
-%* *
-%************************************************************************
-
-\begin{code}
-
-#if defined(__GNUC__) && defined(__STG_GCC_REGS__)
-
-#if alpha_TARGET_ARCH
-
-#define MAGIC_CALL_SETUP \
- long WeNeedThisSpace[7]; \
- double AndThisSpaceToo[6]; \
- register void (*f)() __asm__("$21");\
- __asm__ volatile ( \
- "stq $16,8($30)\n" \
- "\tstq $17,16($30)\n" \
- "\tstq $18,24($30)\n" \
- "\tstq $19,32($30)\n" \
- "\tstq $20,40($30)\n" \
- "\tstq $21,48($30)\n" \
- "\tstt $f16,56($30)\n" \
- "\tstt $f17,64($30)\n" \
- "\tstt $f18,72($30)\n" \
- "\tstt $f19,80($30)\n" \
- "\tstt $f20,88($30)\n" \
- "\tstt $f21,96($30)");
-
-#define MAGIC_CALL \
- __asm__ volatile ( \
- "ldq $21,8($30)\n" \
- "\tldq $16,16($30)\n" \
- "\tldq $17,24($30)\n" \
- "\tldq $18,32($30)\n" \
- "\tldq $19,40($30)\n" \
- "\tldq $20,48($30)\n" \
- "\tldt $f16,56($30)\n" \
- "\tldt $f17,64($30)\n" \
- "\tldt $f18,72($30)\n" \
- "\tldt $f19,80($30)\n" \
- "\tldt $f20,88($30)\n" \
- "\tldt $f21,96($30)");\
- (*f)(); \
- __asm__ volatile ( \
- "stq $0,8($30)\n" \
- "\tstt $f0,16($30)");
-
-#define MAGIC_RETURN \
- __asm__ volatile ( \
- "ldq $0,8($30)\n" \
- "\tldt $f0,16($30)");
-
-#define WRAPPER_NAME(f) /* nothing */
-
-/*
- 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__ ("$26"); loc = ra; }
-
-#define WRAPPER_SETUP(f,ignore1,ignore2) SaveAllStgContext();
-
-#define WRAPPER_RETURN(x) \
- do {RestoreAllStgRegs(); if(x) JMP_(EnterNodeCode);} while(0);
-
-#define SEPARATE_WRAPPER_RESTORE /* none */
-
-#endif /* __alpha */
-
-\end{code}
-
-%************************************************************************
-%* *
-\subsubsection[hppa-magic]{Call-wrapper MAGIC for HP-PA}
-%* *
-%************************************************************************
-
-\begin{code}
-
-#if hppa1_1_TARGET_ARCH
-
-#define MAGIC_CALL_SETUP \
- long SavedIntArgRegs[4]; \
- double SavedFltArgRegs[2]; \
- register void (*f)() __asm__("%r28");\
- __asm__ volatile ( \
- "copy %r26,%r28\n" \
- "\tstw %r25,8(0,%r3)\n" \
- "\tstw %r24,12(0,%r3)\n" \
- "\tstw %r23,16(0,%r3)\n" \
- "\tldo 40(%r3),%r19\n" \
- "\tfstds %fr5,-16(0,%r19)\n"\
- "\tfstds %fr7, -8(0,%r19)\n");
-
-
-#define MAGIC_CALL \
- __asm__ volatile ( \
- "ldw 8(0,%r3),%r26\n" \
- "\tldw 12(0,%r3),%r25\n" \
- "\tldw 16(0,%r3),%r24\n" \
- "\tldw -52(0,%r3),%r23\n" \
- "\tldw -56(0,%r3),%r19\n" \
- "\tstw %r19,-52(0,%r30)\n" \
- "\tldo 40(%r3),%r19\n" \
- "\tfldds -16(0,%r19),%fr5\n"\
- "\tfldds -8(0,%r19),%fr7\n" \
- "\tldo -64(%r3),%r19\n" \
- "\tldo -64(%r30),%r20\n" \
- "\tfldds -16(0,%r19),%fr4\n"\
- "\tfstds %fr4,-16(0,%r20)\n"\
- "\tfldds -8(0,%r19)%fr4\n" \
- "\tfstds %fr4,-8(0,%r19)\n" \
- "\tfldds 0(0,%r19),%fr4\n" \
- "\tfstds %fr4,0(0,%r19)\n" \
- "\tfldds 8(0,%r19),%fr4\n" \
- "\tfstds %fr4,8(0,%r19)\n");\
- (*f)(); \
- __asm__ volatile ( \
- "stw %r28,8(0,%r3)\n" \
- "\tfstds %fr4,16(0,%r3)");
-
-#define MAGIC_RETURN \
- __asm__ volatile ( \
- "\tfldds 16(0,%r3),%fr4" \
- "ldw 8(0,%r3),%r28\n");
-
-#define WRAPPER_NAME(f) /* nothing */
-
-/*
- Threaded code needs to be able to grab the return address, in case we have
- an intervening context switch.
- */
-
-#define SET_RETADDR(loc) __asm__ volatile ("stw %%r2, %0" : "=m" ((void *)(loc)));
-
-#define WRAPPER_SETUP(f,ignore1,ignore2) SaveAllStgContext();
-
-#define WRAPPER_RETURN(x) \
- do {RestoreAllStgRegs(); if(x) JMP_(EnterNodeCode);} while(0);
-
-#define SEPARATE_WRAPPER_RESTORE /* none */
-
-#endif /* __hppa */
-
-\end{code}
-
-%************************************************************************
-%* *
-\subsubsection[iX86-magic]{Call-wrapper MAGIC for iX86}
-%* *
-%************************************************************************
-
-\begin{code}
-#if i386_TARGET_ARCH
-
-/* modelled loosely on SPARC stuff */
-
-/* NB: no MAGIC_CALL_SETUP, MAGIC_CALL, or MAGIC_RETURN! */
-
-#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
-
-/*
- Threaded code needs to be able to grab the return address, in case we have
- an intervening context switch.
- */
-
-#define SET_RETADDR(loc,val) loc = val;
-
-/* 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)
-
- NB: mangler makes sure that __temp_{eax,esp} get loaded.
- (This is about as ugly as it can get.)
-*/
-
-#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);
-
-/* 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_RETURN(x) \
- do {RestoreAllStgRegs(); if(x) JMP_(EnterNodeCode);} while(0);
-
-#define SEPARATE_WRAPPER_RESTORE /* none */
-
-#endif /* iX86 */
-\end{code}
-
-%************************************************************************
-%* *
-\subsubsection[m68k-magic]{Call-wrapper MAGIC for m68k}
-%* *
-%************************************************************************
-
-\begin{code}
-
-#if m68k_TARGET_ARCH
-
-#define MAGIC_CALL_SETUP \
- int WeNeedThisSpace[5]; \
- register void (*f)() __asm__("a0"); \
- __asm__ volatile ( \
- "movel a6@(8),a0\n" \
- "\tmovel a6@(12),a6@(-20)\n" \
- "\tmovel a6@(16),a6@(-16)\n" \
- "\tmovel a6@(20),a6@(-12)\n" \
- "\tmovel a6@(24),a6@(-8)\n" \
- "\tmovel a6@(28),a6@(-4)");
-
-#define MAGIC_CALL \
- (*f)(); \
- __asm__ volatile ( \
- "movel d0, sp@-\n" \
- "\tmovel d1,sp@-");
-
-#define MAGIC_RETURN \
- __asm__ volatile ( \
- "movel sp@+,d0\n" \
- "\tmovel sp@+,d1");
-
-#define WRAPPER_NAME(f) /* nothing */
-
-#define WRAPPER_SETUP(f,ignore1,ignore2) SaveAllStgContext();
-
-#define WRAPPER_RETURN(x) \
- do {RestoreAllStgRegs(); if(x) JMP_(EnterNodeCode);} while(0);
-
-#define SEPARATE_WRAPPER_RESTORE /* none */
-
-#endif /* __mc680x0__ */
-
-\end{code}
-
-%************************************************************************
-%* *
-\subsubsection[mips-magic]{Call-wrapper MAGIC for MIPS}
-%* *
-%************************************************************************
-
-\begin{code}
-#if mipseb_TARGET_ARCH || mipsel_TARGET_ARCH
-
-/* shift 4 arg registers down one */
-
-#define MAGIC_CALL_SETUP \
- register void (*f)() __asm__("$2"); \
- __asm__ volatile ( \
- "move $2,$4\n" \
- "\tmove $4,$5\n" \
- "\tmove $5,$6\n" \
- "\tmove $6,$7\n" \
- "\tlw $7,16($sp)\n" \
- "\taddu $sp,$sp,4\n" \
- : : : "$2" );
-
-#define MAGIC_CALL \
- (*f)(); \
- __asm__ volatile ( \
- "subu $sp,$sp,4\n" \
- "\ts.d $f0, -8($sp)\n" \
- "\tsw $2, -12($sp)");
-
-#define MAGIC_RETURN \
- __asm__ volatile ( \
- "l.d $f0, -8($sp)\n" \
- "\tlw $2, -12($sp)");
-
-#define WRAPPER_NAME(f) /* nothing */
-
-/*
- 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);
-
-#define SEPARATE_WRAPPER_RESTORE /* none */
-
-#endif /* mips */
-\end{code}
-
-%************************************************************************
-%* *
-\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 \
- int WeNeedThisSpace[6]; \
- register void (*f)() __asm__("%o5");\
- __asm__ volatile ( \
- "std %i0,[%fp-40]\n" \
- "\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" \
- "\tld [%%fp-36],%%o0\n" \
- "\tld [%%fp-32],%%o1\n" \
- "\tld [%%fp-28],%%o2\n" \
- "\tld [%%fp-24],%%o3\n" \
- "\tld [%%fp-20],%%o4" \
- : : : "%o0", "%o1", "%o2", "%o3", "%o4", "%o5");\
- (*f)(); \
- __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 ( \
- "ldd [%fp-40],%f0\n" \
- "\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.
- */
-
-#define WRAPPER_NAME(f) __asm__("L" #f "_wrapper")
-
-#ifdef solaris2_TARGET_OS
-#define REAL_NAME(f) #f
-#else
-#define REAL_NAME(f) "_" #f
-#endif
-
-#define WRAPPER_SETUP(f,ignore1,ignore2) \
- __asm__ volatile ( \
- ".global " REAL_NAME(f) "_wrapper\n"\
- REAL_NAME(f) "_wrapper:\n" \
- "\tstd %o0,[%sp-24]\n" \
- "\tmov %o7,%i7"); \
- SaveAllStgContext(); \
- __asm__ volatile ( \
- "ldd [%sp-24],%i0\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.
- */
-
-/*
- 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) \
- __asm__ volatile ( \
- "add %%i7,8,%%o7\n" \
- "\tst %%o7,%0" \
- : "=m" (loc) : : "%o7");
-
-
-#define WRAPPER_RETURN(x) \
- __asm__ volatile ( \
- "call Lwrapper_restore" #x "\n" \
- "\tnop"); \
- abort();
-
-/*
- The sparc is a big nuisance. We use a separate function for
- restoring STG registers so that gcc won't try to leave anything
- (like the address of MainRegTable) in the stack frame that we
- didn't build. We also use a leaf return in a format that allows us
- to pass %o7 in as an argument known to gcc, in the hope that its
- value will be preserved during the reloading of STG registers.
- Note that the current gcc (2.5.6) does not use the delay slot
- here (%#), but perhaps future versions will.
- */
-
-#if defined(CONCURRENT)
-#define WRAPPER_REENTER \
-void wrapper_restore_and_reenter_node(STG_NO_ARGS) \
-{ \
- __asm__("Lwrapper_restore1:"); \
- RestoreAllStgRegs(); \
- JMP_(EnterNodeCode); \
-}
-#else
-#define WRAPPER_REENTER
-#endif
-
-#define SEPARATE_WRAPPER_RESTORE \
-void wrapper_restore(STG_NO_ARGS) \
-{ \
- register void *o7 __asm__("%o7"); \
- __asm__ volatile ( \
- "Lwrapper_restore0:\n" \
- "\tmov %%i7,%0" : "=r" (o7)); \
- RestoreAllStgRegs(); \
- __asm__ volatile ("jmp %0+8%#" : : "r" (o7)); \
-} \
-WRAPPER_REENTER
-
-#endif /* __sparc__ */
-
-#endif /* __GNUC__ && __STG_GCC_REGS__ */
-
-\end{code}
-
-That's all, folks.
-\begin{code}
-#endif /* ! COPTWRAPS_H */
-\end{code}