1 \section[COptWraps]{Wrappers for calls to ``STG C'' routines}
3 % this file is part of the C-as-assembler document
10 %************************************************************************
12 \subsection[COptWraps-portable]{Wrappers for ``portable~C''}
14 %************************************************************************
16 @STGCALL@ macros are used when we really have to be careful about saving
17 any caller-saves STG registers. @SAFESTGCALL@ macros are used
18 when the caller has previously arranged to save/restore volatile user
19 registers (vanilla, float, and double STG registers), and we only have to
20 worry about the ``system'' registers (stack and heap pointers, @STK_STUB@,
21 etc.). @STGCALL_GC@ macros are used whenever the callee is going to
22 need to access (and perhaps modify) some STG registers. @ULTRASAFESTGCALL@
23 is available for our own routines that we are absolutely certain will not
24 damage any STG registers.
28 \item @STGCALL@ saves/restores all caller-saves STG registers.
29 \item @SAFESTGCALL@ saves/restores only caller-saves STG ``system'' registers.
30 \item @ULTRASAFECALL@ is a simple call, without a wrapper.
31 \item @STGCALL_GC@ saves/restores {\em all} STG registers.
34 Several macros are provided to handle outcalls to functions requiring from
35 one to five arguments. (If we could assume GCC, we could use macro varargs,
36 but unfortunately, we have to cater to ANSI C as well.)
40 #define ULTRASAFESTGCALL0(t,p,f) f()
41 #define ULTRASAFESTGCALL1(t,p,f,a) f(a)
42 #define ULTRASAFESTGCALL2(t,p,f,a,b) f(a,b)
43 #define ULTRASAFESTGCALL3(t,p,f,a,b,c) f(a,b,c)
44 #define ULTRASAFESTGCALL4(t,p,f,a,b,c,d) f(a,b,c,d)
45 #define ULTRASAFESTGCALL5(t,p,f,a,b,c,d,e) f(a,b,c,d,e)
47 #if ! (defined(__GNUC__) && defined(__STG_GCC_REGS__))
49 #define STGCALL0(t,p,f) f()
50 #define STGCALL1(t,p,f,a) f(a)
51 #define STGCALL2(t,p,f,a,b) f(a,b)
52 #define STGCALL3(t,p,f,a,b,c) f(a,b,c)
53 #define STGCALL4(t,p,f,a,b,c,d) f(a,b,c,d)
54 #define STGCALL5(t,p,f,a,b,c,d,e) f(a,b,c,d,e)
56 #define SAFESTGCALL0(t,p,f) f()
57 #define SAFESTGCALL1(t,p,f,a) f(a)
58 #define SAFESTGCALL2(t,p,f,a,b) f(a,b)
59 #define SAFESTGCALL3(t,p,f,a,b,c) f(a,b,c)
60 #define SAFESTGCALL4(t,p,f,a,b,c,d) f(a,b,c,d)
61 #define SAFESTGCALL5(t,p,f,a,b,c,d,e) f(a,b,c,d,e)
64 * Generic call_GC wrappers have gone away in favor of these partially
69 do {SaveAllStgRegs(); PerformGC(args); RestoreAllStgRegs();} while(0)
70 #define DO_STACKOVERFLOW(headroom,args) \
71 do {SaveAllStgRegs(); StackOverflow(headroom,args); RestoreAllStgRegs();} while(0)
75 #define DO_YIELD(args) DO_GRAN_YIELD(args)
76 #define DO_GRAN_YIELD(liveness) \
77 do {SaveAllStgRegs(); Yield(liveness); RestoreAllStgRegs();} while(0)
79 #define DO_PERFORM_RESCHEDULE(liveness_mask,reenter) \
80 do {SaveAllStgRegs(); PerformReschedule(liveness_mask,reenter); RestoreAllStgRegs();} while(0)
84 #define DO_YIELD(args) \
85 do {SaveAllStgRegs(); Yield(args); RestoreAllStgRegs();} while(0)
91 %************************************************************************
93 \subsection[COptWraps-optimised]{Wrappers in ``optimised~C''}
95 %************************************************************************
97 We {\em expect} the call-wrappery to be boring---the defaults shown
98 herein will kick in--- but you never know.
100 For example: Don't try an @STGCALL6@ on a SPARC! That's because you
101 cannot pass that many arguments to \tr{f} just by heaving them into
102 \tr{%o*} registers; anything else is too painful to contemplate.
105 #else /* __GNUC__ && __STG_GCC_REGS__ */
107 #if !(defined(CALLER_SAVES_SYSTEM) || defined(CALLER_SAVES_USER))
108 #define STGCALL0(t,p,f) f()
109 #define STGCALL1(t,p,f,a) f(a)
110 #define STGCALL2(t,p,f,a,b) f(a,b)
111 #define STGCALL3(t,p,f,a,b,c) f(a,b,c)
112 #define STGCALL4(t,p,f,a,b,c,d) f(a,b,c,d)
113 #define STGCALL5(t,p,f,a,b,c,d,e) f(a,b,c,d,e)
117 extern void callWrapper(STG_NO_ARGS);
119 #define STGCALL0(t,p,f) \
120 ({t (*_w)p = (t (*)p) callWrapper; (*_w)((void *)f);})
122 #define STGCALL1(t,p,f,a) \
123 ({t (*_w)p = (t (*)p) callWrapper; (*_w)((void *)f,a);})
125 #define STGCALL2(t,p,f,a,b) \
126 ({t (*_w)p = (t (*)p) callWrapper; (*_w)((void *)f,a,b);})
128 #define STGCALL3(t,p,f,a,b,c) \
129 ({t (*_w)p = (t (*)p) callWrapper; (*_w)((void *)f,a,b,c);})
131 #define STGCALL4(t,p,f,a,b,c,d) \
132 ({t (*_w)p = (t (*)p) callWrapper; (*_w)((void *)f,a,b,c,d);})
134 #define STGCALL5(t,p,f,a,b,c,d,e) \
135 ({t (*_w)p = (t (*)p) callWrapper; (*_w)((void *)f,a,b,c,d,e);})
139 #if !defined(CALLER_SAVES_SYSTEM)
140 #define SAFESTGCALL0(t,p,f) f()
141 #define SAFESTGCALL1(t,p,f,a) f(a)
142 #define SAFESTGCALL2(t,p,f,a,b) f(a,b)
143 #define SAFESTGCALL3(t,p,f,a,b,c) f(a,b,c)
144 #define SAFESTGCALL4(t,p,f,a,b,c,d) f(a,b,c,d)
145 #define SAFESTGCALL5(t,p,f,a,b,c,d,e) f(a,b,c,d,e)
149 extern void callWrapper_safe(STG_NO_ARGS);
151 #define SAFESTGCALL0(t,p,f) \
152 ({t (*_w)p = (t (*)p) callWrapper_safe; (*_w)((void *)f);})
154 #define SAFESTGCALL1(t,p,f,a) \
155 ({t (*_w)p = (t (*)p) callWrapper_safe; (*_w)((void *)f,a);})
157 #define SAFESTGCALL2(t,p,f,a,b) \
158 ({t (*_w)p = (t (*)p) callWrapper_safe; (*_w)((void *)f,a,b);})
160 #define SAFESTGCALL3(t,p,f,a,b,c) \
161 ({t (*_w)p = (t (*)p) callWrapper_safe; (*_w)((void *)f,a,b,c);})
163 #define SAFESTGCALL4(t,p,f,a,b,c,d) \
164 ({t (*_w)p = (t (*)p) callWrapper_safe; (*_w)((void *)f,a,b,c,d);})
166 #define SAFESTGCALL5(t,p,f,a,b,c,d,e) \
167 ({t (*_w)p = (t (*)p) callWrapper_safe; (*_w)((void *)f,a,b,c,d,e);})
172 * Generic call_GC wrappers have gone away in favor of these partially
173 * evaluated versions. These are only here so that we can avoid putting
174 * all of the STG register save/restore code at each call site.
177 #ifndef CALLWRAPPER_C
179 * We may have funny declarations in CallWrapper_C, to avoid sliding the
180 * register windows and other nastiness.
182 void PerformGC_wrapper PROTO((W_));
183 void StackOverflow_wrapper PROTO((W_, W_));
184 void Yield_wrapper PROTO((W_));
186 void PerformReschedule_wrapper PROTO((W_, W_));
187 void GranSimAllocate_wrapper PROTO((I_, P_, W_));
188 void GranSimUnallocate_wrapper PROTO((I_, P_, W_));
189 void GranSimFetch_wrapper PROTO((P_));
190 void GranSimExec_wrapper PROTO((W_, W_, W_, W_, W_));
194 #define DO_GC(args) PerformGC_wrapper(args)
195 #define DO_STACKOVERFLOW(headroom,args) StackOverflow_wrapper(headroom,args)
199 #define DO_YIELD(args) DO_GRAN_YIELD(args)
200 #define DO_GRAN_YIELD(liveness) Yield_wrapper(liveness)
202 #define DO_PERFORMRESCHEDULE(liveness, always_reenter_node) PerformReschedule_wrapper(liveness, always_reenter_node)
203 #define DO_GRANSIMALLOCATE(n, node, liveness) GranSimAllocate_wrapper(n, node, liveness)
204 #define DO_GRANSIMUNALLOCATE(n, node, liveness) GranSimUnallocate_wrapper(n, node, liveness)
205 #define DO_GRANSIMFETCH(node) GranSimFetch_wrapper(node)
206 #define DO_GRANSIMEXEC(arith,branch,load,store,floats) GranSimExec_wrapper(arith,branch,load,store,floats)
210 #define DO_YIELD(args) Yield_wrapper(args)
214 #endif /* __GNUC__ && __STG_GCC_REGS__ */
217 %************************************************************************
219 \subsection[COptWraps-magic]{Magic assembly bits for call wrappers}
221 %************************************************************************
223 Call wrappers need to be able to call arbitrary functions, regardless of
224 their arguments and return types. (Okay, we actually only allow up to
225 five arguments, because on the SPARC it gets more complicated to handle
226 any more.) The nasty bit is that the return value can be in either an
227 integer register or a floating point register, and we don't know which.
228 (We {\em don't} handle structure returns, and we don't want to.)
229 Still, we have to stash the result away while we restore caller-saves
230 STG registers, and then we have to pass the result back to our caller
233 Getting this right requires three extremely @MAGIC@ macros, no doubt
234 chock full of assembly gook for the current platform. These are
236 UP@, which gets ready for one of these magic calls,
237 @MAGIC_CALL@, which performs the call and stashes away all possible
238 results, and @MAGIC_RETURN@, which collects all possible results back
241 For example, in the SPARC version, the @SETUP@ guarantees that we
242 have enough space to store all of our argument registers for a wee
243 bit, and it gives a `C' name to the register that we're going to use
244 for the call. (It helps to do the call in actual `C' fashion, so that
245 gcc knows about register death.) It also stashes the incoming arguments
246 in the space provided. The @MAGIC_CALL@ then reloads the argument
247 registers, rotated by one, so that the function to call is in \tr{%o5},
248 calls the function in `C' fashion, and stashes away the possible return
249 values (either \tr{%o0} or \tr{%f0}) on the stack. Finally, @MAGIC_RETURN@
250 ensures that \tr{%o0} and \tr{%f0} are both set to the values we stashed
251 away. Presumably, we then fall into a return instruction and our caller
252 gets whatever it's after.
254 %************************************************************************
256 \subsubsection[alpha-magic]{Call-wrapper MAGIC for DEC Alpha}
258 %************************************************************************
262 #if defined(__GNUC__) && defined(__STG_GCC_REGS__)
264 #if alpha_TARGET_ARCH
266 #define MAGIC_CALL_SETUP \
267 long WeNeedThisSpace[7]; \
268 double AndThisSpaceToo[6]; \
269 register void (*f)() __asm__("$21");\
272 "\tstq $17,16($30)\n" \
273 "\tstq $18,24($30)\n" \
274 "\tstq $19,32($30)\n" \
275 "\tstq $20,40($30)\n" \
276 "\tstq $21,48($30)\n" \
277 "\tstt $f16,56($30)\n" \
278 "\tstt $f17,64($30)\n" \
279 "\tstt $f18,72($30)\n" \
280 "\tstt $f19,80($30)\n" \
281 "\tstt $f20,88($30)\n" \
282 "\tstt $f21,96($30)");
287 "\tldq $16,16($30)\n" \
288 "\tldq $17,24($30)\n" \
289 "\tldq $18,32($30)\n" \
290 "\tldq $19,40($30)\n" \
291 "\tldq $20,48($30)\n" \
292 "\tldt $f16,56($30)\n" \
293 "\tldt $f17,64($30)\n" \
294 "\tldt $f18,72($30)\n" \
295 "\tldt $f19,80($30)\n" \
296 "\tldt $f20,88($30)\n" \
297 "\tldt $f21,96($30)");\
301 "\tstt $f0,16($30)");
303 #define MAGIC_RETURN \
306 "\tldt $f0,16($30)");
308 #define WRAPPER_NAME(f) /* nothing */
311 Threaded code needs to be able to grab the return address, in case we have
312 an intervening context switch.
315 #define SET_RETADDR(loc) { register StgFunPtrFunPtr ra __asm__ ("$26"); loc = ra; }
317 #define WRAPPER_SETUP(f,ignore1,ignore2) SaveAllStgContext();
319 #define WRAPPER_RETURN(x) \
320 do {RestoreAllStgRegs(); if(x) JMP_(EnterNodeCode);} while(0);
322 #define SEPARATE_WRAPPER_RESTORE /* none */
328 %************************************************************************
330 \subsubsection[hppa-magic]{Call-wrapper MAGIC for HP-PA}
332 %************************************************************************
336 #if hppa1_1_TARGET_ARCH
338 #define MAGIC_CALL_SETUP \
339 long SavedIntArgRegs[4]; \
340 double SavedFltArgRegs[2]; \
341 register void (*f)() __asm__("%r28");\
344 "\tstw %r25,8(0,%r3)\n" \
345 "\tstw %r24,12(0,%r3)\n" \
346 "\tstw %r23,16(0,%r3)\n" \
347 "\tldo 40(%r3),%r19\n" \
348 "\tfstds %fr5,-16(0,%r19)\n"\
349 "\tfstds %fr7, -8(0,%r19)\n");
354 "ldw 8(0,%r3),%r26\n" \
355 "\tldw 12(0,%r3),%r25\n" \
356 "\tldw 16(0,%r3),%r24\n" \
357 "\tldw -52(0,%r3),%r23\n" \
358 "\tldw -56(0,%r3),%r19\n" \
359 "\tstw %r19,-52(0,%r30)\n" \
360 "\tldo 40(%r3),%r19\n" \
361 "\tfldds -16(0,%r19),%fr5\n"\
362 "\tfldds -8(0,%r19),%fr7\n" \
363 "\tldo -64(%r3),%r19\n" \
364 "\tldo -64(%r30),%r20\n" \
365 "\tfldds -16(0,%r19),%fr4\n"\
366 "\tfstds %fr4,-16(0,%r20)\n"\
367 "\tfldds -8(0,%r19)%fr4\n" \
368 "\tfstds %fr4,-8(0,%r19)\n" \
369 "\tfldds 0(0,%r19),%fr4\n" \
370 "\tfstds %fr4,0(0,%r19)\n" \
371 "\tfldds 8(0,%r19),%fr4\n" \
372 "\tfstds %fr4,8(0,%r19)\n");\
375 "stw %r28,8(0,%r3)\n" \
376 "\tfstds %fr4,16(0,%r3)");
378 #define MAGIC_RETURN \
380 "\tfldds 16(0,%r3),%fr4" \
381 "ldw 8(0,%r3),%r28\n");
383 #define WRAPPER_NAME(f) /* nothing */
386 Threaded code needs to be able to grab the return address, in case we have
387 an intervening context switch.
390 #define SET_RETADDR(loc) __asm__ volatile ("stw %%r2, %0" : "=m" ((void *)(loc)));
392 #define WRAPPER_SETUP(f,ignore1,ignore2) SaveAllStgContext();
394 #define WRAPPER_RETURN(x) \
395 do {RestoreAllStgRegs(); if(x) JMP_(EnterNodeCode);} while(0);
397 #define SEPARATE_WRAPPER_RESTORE /* none */
403 %************************************************************************
405 \subsubsection[iX86-magic]{Call-wrapper MAGIC for iX86}
407 %************************************************************************
412 /* modelled loosely on SPARC stuff */
414 /* NB: no MAGIC_CALL_SETUP, MAGIC_CALL, or MAGIC_RETURN! */
416 #define WRAPPER_NAME(f) /*nothing*/
418 #if defined(solaris2_TARGET_OS) || defined(linux_TARGET_OS)
419 #define REAL_NAME(f) #f
421 #define REAL_NAME(f) "_" #f
425 Threaded code needs to be able to grab the return address, in case we have
426 an intervening context switch.
429 #define SET_RETADDR(loc,val) loc = val;
431 /* the grab-%eax-quickly HACK is here because we use a VERY SPECIAL
432 calling convention on iX86 just for calling PerformGC_wrapper.
435 NB: mangler makes sure that __temp_{eax,esp} get loaded.
436 (This is about as ugly as it can get.)
439 #define WRAPPER_SETUP(f,ret_addr,args) \
441 "movl " REAL_NAME(__temp_esp) ",%%edx\n" \
442 "\tmovl (%%edx),%0\n" \
443 "\tmovl " REAL_NAME(__temp_eax) ",%1" \
444 : "=r" (ret_addr), "=r" (args) ); \
445 SaveAllStgContext(ret_addr);
447 /* Note re WRAPPER_SETUP: we have special code just for PerformGC_wrapper;
448 pls see its definition. WDP 95/09
450 Also note the EXTREMELY UGLY slamming in of an "sp_offset"; the
451 return address *is* on the stack, but it is hard to get there
452 before GCC has moved the sp pointer... WDP 95/11
455 #define WRAPPER_RETURN(x) \
456 do {RestoreAllStgRegs(); if(x) JMP_(EnterNodeCode);} while(0);
458 #define SEPARATE_WRAPPER_RESTORE /* none */
463 %************************************************************************
465 \subsubsection[m68k-magic]{Call-wrapper MAGIC for m68k}
467 %************************************************************************
473 #define MAGIC_CALL_SETUP \
474 int WeNeedThisSpace[5]; \
475 register void (*f)() __asm__("a0"); \
477 "movel a6@(8),a0\n" \
478 "\tmovel a6@(12),a6@(-20)\n" \
479 "\tmovel a6@(16),a6@(-16)\n" \
480 "\tmovel a6@(20),a6@(-12)\n" \
481 "\tmovel a6@(24),a6@(-8)\n" \
482 "\tmovel a6@(28),a6@(-4)");
490 #define MAGIC_RETURN \
495 #define WRAPPER_NAME(f) /* nothing */
497 #define WRAPPER_SETUP(f,ignore1,ignore2) SaveAllStgContext();
499 #define WRAPPER_RETURN(x) \
500 do {RestoreAllStgRegs(); if(x) JMP_(EnterNodeCode);} while(0);
502 #define SEPARATE_WRAPPER_RESTORE /* none */
504 #endif /* __mc680x0__ */
508 %************************************************************************
510 \subsubsection[mips-magic]{Call-wrapper MAGIC for MIPS}
512 %************************************************************************
515 #if mipseb_TARGET_ARCH || mipsel_TARGET_ARCH
517 /* shift 4 arg registers down one */
519 #define MAGIC_CALL_SETUP \
520 register void (*f)() __asm__("$2"); \
526 "\tlw $7,16($sp)\n" \
527 "\taddu $sp,$sp,4\n" \
534 "\ts.d $f0, -8($sp)\n" \
535 "\tsw $2, -12($sp)");
537 #define MAGIC_RETURN \
539 "l.d $f0, -8($sp)\n" \
540 "\tlw $2, -12($sp)");
542 #define WRAPPER_NAME(f) /* nothing */
545 Threaded code needs to be able to grab the return address, in case we have
546 an intervening context switch.
549 #define SET_RETADDR(loc) { register StgFunPtrFunPtr ra __asm__ ("$31"); loc = ra; }
551 #define WRAPPER_SETUP(f,ignore1,ignore2) SaveAllStgContext();
553 #define WRAPPER_RETURN(x) \
554 do {RestoreAllStgRegs(); if(x) JMP_(EnterNodeCode);} while(0);
556 #define SEPARATE_WRAPPER_RESTORE /* none */
561 %************************************************************************
563 \subsubsection[powerpc-magic]{Call-wrapper MAGIC for PowerPC}
565 %************************************************************************
568 #if powerpc_TARGET_ARCH || rs6000_TARGET_ARCH
570 #define MAGIC_CALL_SETUP \
571 register void (*f)() __asm__("$2"); \
573 "not used!!!????\n" \
579 "not used!!!????\n");
581 #define MAGIC_RETURN \
583 "not used!!!????\n");
585 #define WRAPPER_NAME(f) /* nothing */
587 #define SET_RETADDR(loc) \
592 /* __asm__ volatile ("st %%r0, %0" : "=m" ((void *)(loc))); */
594 #define WRAPPER_SETUP(f,ignore1,ignore2) SaveAllStgContext();
596 /* we have to make sure the STG registers are restored.
597 GCC tries to restore the value the registers had in
598 the beginning of the current call, which we don't want.
599 We defeat it by saving the registers in the stack again. :-( */
601 #define WRAPPER_RETURN(x) \
602 do {RestoreAllStgRegs(); if(x) JMP_(EnterNodeCode);} while(0); \
605 "\tstm 14,-72(1)\n" \
608 #define SEPARATE_WRAPPER_RESTORE /* none */
613 %************************************************************************
615 \subsubsection[sparc-magic]{Call-wrapper MAGIC for SPARC}
617 %************************************************************************
620 #if sparc_TARGET_ARCH
622 #define MAGIC_CALL_SETUP \
623 int WeNeedThisSpace[6]; \
624 register void (*f)() __asm__("%o5");\
626 "std %i0,[%fp-40]\n" \
627 "\tstd %i2,[%fp-32]\n" \
628 "\tstd %i4,[%fp-24]");
630 /* Lest GCC attempt to stick something in
631 the delay slot: with compile with
632 -fno-delayed-branch. A weak solution. WDP 96/07
636 "ld [%%fp-40],%%o5\n" \
637 "\tld [%%fp-36],%%o0\n" \
638 "\tld [%%fp-32],%%o1\n" \
639 "\tld [%%fp-28],%%o2\n" \
640 "\tld [%%fp-24],%%o3\n" \
641 "\tld [%%fp-20],%%o4" \
642 : : : "%o0", "%o1", "%o2", "%o3", "%o4", "%o5");\
645 "std %f0,[%fp-40]\n" \
646 "\tstd %o0,[%fp-32]");
648 /* We leave nothing to chance here; we have seen
649 GCC stick "unwanted" code in the branch delay
650 slot, causing mischief (WDP 96/05)
652 /* the problem with this one: GCC has no way of
653 knowing there is a "call" in there, so it
654 does not do any calling-convention stuff
655 (e.g., saving used regs). WDP 96/07
659 "ld [%%fp-40],%%o5\n" \
660 "\tld [%%fp-36],%%o0\n" \
661 "\tld [%%fp-32],%%o1\n" \
662 "\tld [%%fp-28],%%o2\n" \
663 "\tld [%%fp-24],%%o3\n" \
664 "\tld [%%fp-20],%%o4\n" \
667 "\tstd %%f0,[%%fp-40]\n"\
668 "\tstd %%o0,[%%fp-32]" \
669 : : : "%o0", "%o1", "%o2", "%o3", "%o4", "%o5", "%o7", "%f0", "memory");
672 #define MAGIC_RETURN \
674 "ldd [%fp-40],%f0\n" \
675 "\tldd [%fp-32],%i0");
678 We rename the entry points for wrappers so that we can introduce a
679 new entry point after the prologue. We want to ensure that the
680 register window does not slide! However, we insert a call to
681 abort() to make gcc _believe_ that the window slid.
684 #define WRAPPER_NAME(f) __asm__("L" #f "_wrapper")
686 #ifdef solaris2_TARGET_OS
687 #define REAL_NAME(f) #f
689 #define REAL_NAME(f) "_" #f
692 #define WRAPPER_SETUP(f,ignore1,ignore2) \
694 ".global " REAL_NAME(f) "_wrapper\n"\
695 REAL_NAME(f) "_wrapper:\n" \
696 "\tstd %o0,[%sp-24]\n" \
698 SaveAllStgContext(); \
700 "ldd [%sp-24],%i0\n" \
704 * In the above, we want to ensure that the arguments are both in the
705 * %i registers and the %o registers, with the assumption that gcc
706 * will expect them now to be in one or the other. This is a terrible
711 Threaded code needs to be able to grab the return address, in case
712 we have an intervening context switch. Note that we want the
713 address of the next instruction to be executed, so we add 8 to the
717 #define SET_RETADDR(loc) \
719 "add %%i7,8,%%o7\n" \
721 : "=m" (loc) : : "%o7");
724 #define WRAPPER_RETURN(x) \
726 "call Lwrapper_restore" #x "\n" \
731 The sparc is a big nuisance. We use a separate function for
732 restoring STG registers so that gcc won't try to leave anything
733 (like the address of MainRegTable) in the stack frame that we
734 didn't build. We also use a leaf return in a format that allows us
735 to pass %o7 in as an argument known to gcc, in the hope that its
736 value will be preserved during the reloading of STG registers.
737 Note that the current gcc (2.5.6) does not use the delay slot
738 here (%#), but perhaps future versions will.
741 #if defined(CONCURRENT)
742 #define WRAPPER_REENTER \
743 void wrapper_restore_and_reenter_node(STG_NO_ARGS) \
745 __asm__("Lwrapper_restore1:"); \
746 RestoreAllStgRegs(); \
747 JMP_(EnterNodeCode); \
750 #define WRAPPER_REENTER
753 #define SEPARATE_WRAPPER_RESTORE \
754 void wrapper_restore(STG_NO_ARGS) \
756 register void *o7 __asm__("%o7"); \
758 "Lwrapper_restore0:\n" \
759 "\tmov %%i7,%0" : "=r" (o7)); \
760 RestoreAllStgRegs(); \
761 __asm__ volatile ("jmp %0+8%#" : : "r" (o7)); \
765 #endif /* __sparc__ */
767 #endif /* __GNUC__ && __STG_GCC_REGS__ */
773 #endif /* ! COPTWRAPS_H */