7aa82867faf5df9c70f3e6d24da5a9c038273138
[ghc-hetmet.git] / ghc / includes / COptWraps.lh
1 \section[COptWraps]{Wrappers for calls to ``STG C'' routines}
2
3 % this file is part of the C-as-assembler document
4
5 \begin{code}
6 #ifndef COPTWRAPS_H
7 #define COPTWRAPS_H
8 \end{code}
9
10 %************************************************************************
11 %*                                                                      *
12 \subsection[COptWraps-portable]{Wrappers for ``portable~C''}
13 %*                                                                      *
14 %************************************************************************
15
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.
25
26 In short,
27 \begin{itemize}
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.
32 \end{itemize}
33     
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.)
37
38 \begin{code}
39
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)
46
47 #if ! (defined(__GNUC__) && defined(__STG_GCC_REGS__))
48
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)
55
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)
62
63 /* 
64  * Generic call_GC wrappers have gone away in favor of these partially
65  * evaluated versions.
66  */
67
68 #define DO_GC(args)                         \
69     do {SaveAllStgRegs(); PerformGC(args); RestoreAllStgRegs();} while(0)
70 #define DO_STACKOVERFLOW(headroom,args)     \
71     do {SaveAllStgRegs(); StackOverflow(headroom,args); RestoreAllStgRegs();} while(0)
72 #define DO_YIELD(args)              \
73     do {SaveAllStgRegs(); Yield(args); RestoreAllStgRegs();} while(0)
74
75 \end{code}
76
77 %************************************************************************
78 %*                                                                      *
79 \subsection[COptWraps-optimised]{Wrappers in ``optimised~C''}
80 %*                                                                      *
81 %************************************************************************
82
83 We {\em expect} the call-wrappery to be boring---the defaults shown
84 herein will kick in--- but you never know.
85
86 For example: Don't try an @STGCALL6@ on a SPARC!  That's because you
87 cannot pass that many arguments to \tr{f} just by heaving them into
88 \tr{%o*} registers; anything else is too painful to contemplate.
89
90 \begin{code}
91 #else /* __GNUC__ && __STG_GCC_REGS__ */
92
93 #if !(defined(CALLER_SAVES_SYSTEM) || defined(CALLER_SAVES_USER))
94 #define STGCALL0(t,p,f)           f()
95 #define STGCALL1(t,p,f,a)         f(a)
96 #define STGCALL2(t,p,f,a,b)       f(a,b)
97 #define STGCALL3(t,p,f,a,b,c)     f(a,b,c)
98 #define STGCALL4(t,p,f,a,b,c,d)   f(a,b,c,d)
99 #define STGCALL5(t,p,f,a,b,c,d,e) f(a,b,c,d,e)
100
101 #else
102
103 extern void callWrapper(STG_NO_ARGS);
104
105 #define STGCALL0(t,p,f)             \
106     ({t (*_w)p = (t (*)p) callWrapper; (*_w)((void *)f);})
107
108 #define STGCALL1(t,p,f,a)           \
109     ({t (*_w)p = (t (*)p) callWrapper; (*_w)((void *)f,a);})
110
111 #define STGCALL2(t,p,f,a,b)         \
112     ({t (*_w)p = (t (*)p) callWrapper; (*_w)((void *)f,a,b);})
113
114 #define STGCALL3(t,p,f,a,b,c)       \
115     ({t (*_w)p = (t (*)p) callWrapper; (*_w)((void *)f,a,b,c);})
116
117 #define STGCALL4(t,p,f,a,b,c,d)     \
118     ({t (*_w)p = (t (*)p) callWrapper; (*_w)((void *)f,a,b,c,d);})
119
120 #define STGCALL5(t,p,f,a,b,c,d,e)   \
121     ({t (*_w)p = (t (*)p) callWrapper; (*_w)((void *)f,a,b,c,d,e);})
122
123 #endif
124
125 #if !defined(CALLER_SAVES_SYSTEM)
126 #define SAFESTGCALL0(t,p,f)           f()
127 #define SAFESTGCALL1(t,p,f,a)         f(a)
128 #define SAFESTGCALL2(t,p,f,a,b)       f(a,b)
129 #define SAFESTGCALL3(t,p,f,a,b,c)     f(a,b,c)
130 #define SAFESTGCALL4(t,p,f,a,b,c,d)   f(a,b,c,d)
131 #define SAFESTGCALL5(t,p,f,a,b,c,d,e) f(a,b,c,d,e)
132
133 #else
134
135 extern void callWrapper_safe(STG_NO_ARGS);
136
137 #define SAFESTGCALL0(t,p,f)             \
138     ({t (*_w)p = (t (*)p) callWrapper_safe; (*_w)((void *)f);})
139
140 #define SAFESTGCALL1(t,p,f,a)           \
141     ({t (*_w)p = (t (*)p) callWrapper_safe; (*_w)((void *)f,a);})
142
143 #define SAFESTGCALL2(t,p,f,a,b)         \
144     ({t (*_w)p = (t (*)p) callWrapper_safe; (*_w)((void *)f,a,b);})
145
146 #define SAFESTGCALL3(t,p,f,a,b,c)       \
147     ({t (*_w)p = (t (*)p) callWrapper_safe; (*_w)((void *)f,a,b,c);})
148
149 #define SAFESTGCALL4(t,p,f,a,b,c,d)     \
150     ({t (*_w)p = (t (*)p) callWrapper_safe; (*_w)((void *)f,a,b,c,d);})
151
152 #define SAFESTGCALL5(t,p,f,a,b,c,d,e)   \
153     ({t (*_w)p = (t (*)p) callWrapper_safe; (*_w)((void *)f,a,b,c,d,e);})
154
155 #endif
156
157 /* 
158  * Generic call_GC wrappers have gone away in favor of these partially
159  * evaluated versions.  These are only here so that we can avoid putting
160  * all of the STG register save/restore code at each call site.
161  */
162
163 #ifndef CALLWRAPPER_C
164 /* 
165  * We may have funny declarations in CallWrapper_C, to avoid sliding the
166  * register windows and other nastiness.
167  */
168 void PerformGC_wrapper PROTO((W_));
169 void StackOverflow_wrapper PROTO((W_, W_));
170 void Yield_wrapper PROTO((W_));
171 #endif
172
173 #define DO_GC(args)                     PerformGC_wrapper(args)
174 #define DO_STACKOVERFLOW(headroom,args) StackOverflow_wrapper(headroom,args)
175 #define DO_YIELD(args)                  Yield_wrapper(args)
176
177 #endif /* __GNUC__ && __STG_GCC_REGS__ */
178 \end{code}
179
180 %************************************************************************
181 %*                                                                      *
182 \subsection[COptWraps-magic]{Magic assembly bits for call wrappers}
183 %*                                                                      *
184 %************************************************************************
185
186 Call wrappers need to be able to call arbitrary functions, regardless of
187 their arguments and return types.  (Okay, we actually only allow up to
188 five arguments, because on the sparc it gets more complicated to handle
189 any more.)  The nasty bit is that the return value can be in either an
190 integer register or a floating point register, and we don't know which.
191 (We {\em don't} handle structure returns, and we don't want to.)
192 Still, we have to stash the result away while we restore caller-saves
193 STG registers, and then we have to pass the result back to our caller
194 in the end.
195
196 Getting this right requires three extremely @MAGIC@ macros, no doubt
197 chock full of assembly gook for the current platform.  These are
198 @MAGIC_CALL_SETUP@, which gets ready for one of these magic calls,
199 @MAGIC_CALL@, which performs the call and stashes away all possible
200 results, and @MAGIC_RETURN@, which collects all possible results back
201 up again.
202
203 For example, in the sparc version, the @SETUP@ guarantees that we
204 have enough space to store all of our argument registers for a wee
205 bit, and it gives a `C' name to the register that we're going to use
206 for the call.  (It helps to do the call in actual `C' fashion, so that
207 gcc knows about register death.)  It also stashes the incoming arguments
208 in the space  provided.  The @MAGIC_CALL@ then reloads the argument
209 registers, rotated by one, so that the function to call is in \tr{%o5},
210 calls the function in `C' fashion, and stashes away the possible return
211 values (either \tr{%o0} or \tr{%f0}) on the stack.  Finally, @MAGIC_RETURN@
212 ensures that \tr{%o0} and \tr{%f0} are both set to the values we stashed
213 away.  Presumably, we then fall into a return instruction and our caller
214 gets whatever it's after.
215
216 %************************************************************************
217 %*                                                                      *
218 \subsubsection[alpha-magic]{Call-wrapper MAGIC for DEC Alpha}
219 %*                                                                      *
220 %************************************************************************
221
222 \begin{code}
223
224 #if defined(__GNUC__) && defined(__STG_GCC_REGS__)
225
226 #if alpha_dec_osf1_TARGET
227     /* Is this too specific */
228
229 #define MAGIC_CALL_SETUP        \
230     long WeNeedThisSpace[7];    \
231     double AndThisSpaceToo[6];  \
232     register void (*f)() __asm__("$21");\
233     __asm__ volatile (          \
234         "stq $16,8($30)\n"      \
235         "\tstq $17,16($30)\n"   \
236         "\tstq $18,24($30)\n"   \
237         "\tstq $19,32($30)\n"   \
238         "\tstq $20,40($30)\n"   \
239         "\tstq $21,48($30)\n"   \
240         "\tstt $f16,56($30)\n"  \
241         "\tstt $f17,64($30)\n"  \
242         "\tstt $f18,72($30)\n"  \
243         "\tstt $f19,80($30)\n"  \
244         "\tstt $f20,88($30)\n"  \
245         "\tstt $f21,96($30)");
246
247 #define MAGIC_CALL              \
248     __asm__ volatile (          \
249         "ldq $21,8($30)\n"      \
250         "\tldq $16,16($30)\n"   \
251         "\tldq $17,24($30)\n"   \
252         "\tldq $18,32($30)\n"   \
253         "\tldq $19,40($30)\n"   \
254         "\tldq $20,48($30)\n"   \
255         "\tldt $f16,56($30)\n"  \
256         "\tldt $f17,64($30)\n"  \
257         "\tldt $f18,72($30)\n"  \
258         "\tldt $f19,80($30)\n"  \
259         "\tldt $f20,88($30)\n"  \
260         "\tldt $f21,96($30)");\
261     (*f)();                     \
262     __asm__ volatile (          \
263         "stq $0,8($30)\n"       \
264         "\tstt $f0,16($30)");
265
266 #define MAGIC_RETURN            \
267     __asm__ volatile (          \
268         "ldq $0,8($30)\n"       \
269         "\tldt $f0,16($30)");
270
271 #define WRAPPER_NAME(f)   /* nothing */
272
273 /* 
274    Threaded code needs to be able to grab the return address, in case we have
275    an intervening context switch.
276  */
277
278 #define SET_RETADDR(loc)  { register StgFunPtrFunPtr ra __asm__ ("$26"); loc = ra; }
279
280 #define WRAPPER_SETUP(f)  SaveAllStgContext();
281
282 #define WRAPPER_RETURN(x)   \
283     do {RestoreAllStgRegs(); if(x) JMP_(EnterNodeCode);} while(0);
284
285 #define SEPARATE_WRAPPER_RESTORE    /* none */
286
287 #endif /* __alpha */
288
289 \end{code}
290
291 %************************************************************************
292 %*                                                                      *
293 \subsubsection[hppa-magic]{Call-wrapper MAGIC for HP-PA}
294 %*                                                                      *
295 %************************************************************************
296
297 \begin{code}
298
299 #if hppa1_1_hp_hpux_TARGET
300     /* Is this too specific */
301
302 #define MAGIC_CALL_SETUP            \
303     long SavedIntArgRegs[4];        \
304     double SavedFltArgRegs[2];      \
305     register void (*f)() __asm__("%r28");\
306     __asm__ volatile (              \
307         "copy %r26,%r28\n"          \
308         "\tstw %r25,8(0,%r3)\n"     \
309         "\tstw %r24,12(0,%r3)\n"    \
310         "\tstw %r23,16(0,%r3)\n"    \
311         "\tldo 40(%r3),%r19\n"      \
312         "\tfstds %fr5,-16(0,%r19)\n"\
313         "\tfstds %fr7, -8(0,%r19)\n");
314
315
316 #define MAGIC_CALL                  \
317     __asm__ volatile (              \
318         "ldw 8(0,%r3),%r26\n"       \
319         "\tldw 12(0,%r3),%r25\n"    \
320         "\tldw 16(0,%r3),%r24\n"    \
321         "\tldw -52(0,%r3),%r23\n"   \
322         "\tldw -56(0,%r3),%r19\n"   \
323         "\tstw %r19,-52(0,%r30)\n"  \
324         "\tldo 40(%r3),%r19\n"      \
325         "\tfldds -16(0,%r19),%fr5\n"\
326         "\tfldds -8(0,%r19),%fr7\n" \
327         "\tldo -64(%r3),%r19\n"     \
328         "\tldo -64(%r30),%r20\n"    \
329         "\tfldds -16(0,%r19),%fr4\n"\
330         "\tfstds %fr4,-16(0,%r20)\n"\
331         "\tfldds -8(0,%r19)%fr4\n"  \
332         "\tfstds %fr4,-8(0,%r19)\n" \
333         "\tfldds 0(0,%r19),%fr4\n"  \
334         "\tfstds %fr4,0(0,%r19)\n"  \
335         "\tfldds 8(0,%r19),%fr4\n"  \
336         "\tfstds %fr4,8(0,%r19)\n");\
337     (*f)();                         \
338     __asm__ volatile (              \
339         "stw %r28,8(0,%r3)\n"       \
340         "\tfstds %fr4,16(0,%r3)");
341
342 #define MAGIC_RETURN                \
343     __asm__ volatile (              \
344         "\tfldds 16(0,%r3),%fr4"    \
345         "ldw 8(0,%r3),%r28\n");
346
347 #define WRAPPER_NAME(f)   /* nothing */
348
349 /* 
350    Threaded code needs to be able to grab the return address, in case we have
351    an intervening context switch.
352  */
353
354 #define SET_RETADDR(loc)  __asm__ volatile ("stw %%r2, %0" : "=m" ((void *)(loc)));
355
356 #define WRAPPER_SETUP(f)  SaveAllStgContext();
357
358 #define WRAPPER_RETURN(x)   \
359     do {RestoreAllStgRegs(); if(x) JMP_(EnterNodeCode);} while(0);
360
361 #define SEPARATE_WRAPPER_RESTORE    /* none */
362
363 #endif /* __hppa */
364
365 \end{code}
366
367 %************************************************************************
368 %*                                                                      *
369 \subsubsection[iX86-magic]{Call-wrapper MAGIC for iX86}
370 %*                                                                      *
371 %************************************************************************
372
373 \begin{code}
374
375 #if i386_TARGET_ARCH || i486_TARGET_ARCH
376
377 /* modelled loosely on SPARC stuff */
378
379 /* NB: no MAGIC_CALL_SETUP, MAGIC_CALL, or MAGIC_RETURN! */
380
381 #define WRAPPER_NAME(f)   __asm__("L" #f "_wrapper")
382
383 #define REAL_NAME(f)   "_" #f
384
385 /* when we come into PerformGC_wrapper:
386
387     - %esp holds Hp (!); get it into 80(%ebx) -- quick!
388
389     - %esp needs to be bumped by (at least) 4, because
390       C thinks an argument was passed on the stack
391       (use 64 just for fun)
392
393     - %eax holds the argument for PerformGC
394
395     - 104(%ebx) hold the return address -- address we want to
396       go back to
397
398     - 100(%ebx) holds a %esp value that we can re-load with
399       if need be
400
401 */
402 #define WRAPPER_SETUP(f)                        \
403     __asm__ volatile (                          \
404         ".globl " REAL_NAME(f) "_wrapper\n"     \
405         REAL_NAME(f) "_wrapper:\n"              \
406         "\tmovl %%esp,80(%%ebx)\n"              \
407         "\tmovl 100(%%ebx),%%esp\n"             \
408         "\tmovl %%eax,%0\n"                     \
409         "\tincl _SP_stack_ptr\n"                \
410         "\tmovl _SP_stack_ptr,%%eax\n"          \
411         "\tmovl %%esp,_SP_stack(,%%eax,4)\n"    \
412         "\tsubl $64,%%esp"                      \
413         : "=r" (args));                         \
414     SaveAllStgContext();
415
416 #define WRAPPER_RETURN(x)                       \
417     do {P_ foo;                                 \
418         RestoreAllStgRegs();                    \
419         if(x) JMP_(EnterNodeCode); /* never used? */ \
420         __asm__ volatile (                      \
421         "movl %1,%0\n"                          \
422         "\tmovl %0,_MainRegTable+100"           \
423         : "=r" (foo) : "m" (SP_stack[SP_stack_ptr--]) ); \
424         __asm__ volatile (                      \
425         "movl 80(%ebx),%esp\n"                  \
426         "\tjmp *104(%ebx)" );                   \
427     } while(0);
428
429 #define SEPARATE_WRAPPER_RESTORE    /* none */
430
431 #endif /* iX86 */
432
433 \end{code}
434
435 %************************************************************************
436 %*                                                                      *
437 \subsubsection[m68k-magic]{Call-wrapper MAGIC for m68k}
438 %*                                                                      *
439 %************************************************************************
440
441 \begin{code}
442
443 #if m68k_TARGET_ARCH
444
445 #define MAGIC_CALL_SETUP  \
446     int WeNeedThisSpace[5];             \
447     register void (*f)() __asm__("a0"); \
448     __asm__ volatile (                  \
449     "movel a6@(8),a0\n"                 \
450     "\tmovel a6@(12),a6@(-20)\n"        \
451     "\tmovel a6@(16),a6@(-16)\n"        \
452     "\tmovel a6@(20),a6@(-12)\n"        \
453     "\tmovel a6@(24),a6@(-8)\n"         \
454     "\tmovel a6@(28),a6@(-4)");
455
456 #define MAGIC_CALL      \
457     (*f)();             \
458      __asm__ volatile ( \
459     "movel d0, sp@-\n"  \
460     "\tmovel d1,sp@-");
461
462 #define MAGIC_RETURN    \
463     __asm__ volatile (  \
464     "movel sp@+,d0\n"   \
465     "\tmovel sp@+,d1");
466
467 #define WRAPPER_NAME(f)   /* nothing */
468
469 #define WRAPPER_SETUP(f)  SaveAllStgContext();
470
471 #define WRAPPER_RETURN(x)  \
472     do {RestoreAllStgRegs(); if(x) JMP_(EnterNodeCode);} while(0);
473
474 #define SEPARATE_WRAPPER_RESTORE    /* none */
475
476 #endif /* __mc680x0__ */
477
478 \end{code}
479
480 %************************************************************************
481 %*                                                                      *
482 \subsubsection[mips-magic]{Call-wrapper MAGIC for MIPS}
483 %*                                                                      *
484 %************************************************************************
485
486 \begin{code}
487 #if mipseb_TARGET_ARCH || mipsel_TARGET_ARCH
488
489 /* shift 4 arg registers down one */
490
491 #define MAGIC_CALL_SETUP  \
492     register void (*f)() __asm__("$2"); \
493     __asm__ volatile (                  \
494     "move $2,$4\n"                      \
495     "\tmove $4,$5\n"                    \
496     "\tmove $5,$6\n"                    \
497     "\tmove $6,$7\n"                    \
498     "\tlw $7,16($sp)\n"                 \
499     "\taddu $sp,$sp,4\n"                \
500     : : : "$2" );
501
502 #define MAGIC_CALL              \
503     (*f)();                     \
504      __asm__ volatile (         \
505     "subu $sp,$sp,4\n"          \
506     "\ts.d $f0, -8($sp)\n"      \
507     "\tsw  $2, -12($sp)");
508
509 #define MAGIC_RETURN            \
510     __asm__ volatile (          \
511     "l.d $f0, -8($sp)\n"        \
512     "\tlw  $2, -12($sp)");
513
514 #define WRAPPER_NAME(f)   /* nothing */
515
516 #define WRAPPER_SETUP(f)  SaveAllStgContext();
517
518 #define WRAPPER_RETURN(x)  \
519     do {RestoreAllStgRegs(); if(x) JMP_(EnterNodeCode);} while(0);
520
521 #define SEPARATE_WRAPPER_RESTORE    /* none */
522
523 #endif /* mips */
524 \end{code}
525
526 %************************************************************************
527 %*                                                                      *
528 \subsubsection[sparc-magic]{Call-wrapper MAGIC for SPARC}
529 %*                                                                      *
530 %************************************************************************
531
532 \begin{code}
533
534 #if sparc_TARGET_ARCH
535
536 #define MAGIC_CALL_SETUP        \
537     int WeNeedThisSpace[6];     \
538     register void (*f)() __asm__("%o5");\
539     __asm__ volatile (          \
540         "std %i0,[%fp-40]\n"    \
541         "\tstd %i2,[%fp-32]\n"  \
542         "\tstd %i4,[%fp-24]");
543
544 #define MAGIC_CALL              \
545     __asm__ volatile (          \
546         "ld [%%fp-40],%%o5\n"   \
547         "\tld [%%fp-36],%%o0\n" \
548         "\tld [%%fp-32],%%o1\n" \
549         "\tld [%%fp-28],%%o2\n" \
550         "\tld [%%fp-24],%%o3\n" \
551         "\tld [%%fp-20],%%o4"   \
552         : : : "%o0", "%o1", "%o2", "%o3", "%o4", "%o5");\
553     (*f)();                     \
554     __asm__ volatile (          \
555         "std %f0,[%fp-40]\n"    \
556         "\tstd %o0,[%fp-32]");
557
558 #define MAGIC_RETURN            \
559     __asm__ volatile (          \
560         "ldd [%fp-40],%f0\n"    \
561         "\tldd [%fp-32],%i0");
562
563 /* 
564    We rename the entry points for wrappers so that we can
565    introduce a new entry point after the prologue.  We want to ensure
566    that the register window does not slide!  However, we insert a 
567    call to abort() to make gcc _believe_ that the window slid.
568  */
569
570 #define WRAPPER_NAME(f)   __asm__("L" #f "_wrapper")
571
572 #ifdef solaris2_TARGET_OS
573 #define REAL_NAME(f)   #f
574 #else
575 #define REAL_NAME(f)   "_" #f
576 #endif
577
578 #define WRAPPER_SETUP(f)                    \
579     __asm__ volatile (                      \
580         ".global " REAL_NAME(f) "_wrapper\n"\
581         REAL_NAME(f) "_wrapper:\n"          \
582         "\tstd %o0,[%sp-24]\n"              \
583         "\tmov %o7,%i7");                   \
584     SaveAllStgContext();                    \
585     __asm__ volatile (                      \
586         "ldd [%sp-24],%i0\n"                \
587         "\tmov %i0,%o0\n"                   \
588         "\tmov %i1,%o1");
589 /* 
590  * In the above, we want to ensure that the arguments are both in the %i registers
591  * and the %o registers, with the assumption that gcc will expect them now to be in
592  * one or the other.  This is a terrible hack.
593  */
594
595 /* 
596    Threaded code needs to be able to grab the return address, in case we have
597    an intervening context switch.  Note that we want the address of the next
598    instruction to be executed, so we add 8 to the link address.
599  */
600
601 #define SET_RETADDR(loc)        \
602     __asm__ volatile (          \
603         "add %%i7,8,%%o7\n"     \
604         "\tst %%o7,%0"          \
605         : "=m" (loc) : : "%o7");
606
607
608 #define WRAPPER_RETURN(x)               \
609     __asm__ volatile (                  \
610         "call Lwrapper_restore" #x "\n" \
611         "\tnop");                       \
612     abort();
613
614 /* 
615    The sparc is a big nuisance.  We use a separate function for 
616    restoring STG registers so that gcc won't try to leave anything
617    (like the address of MainRegTable) in the stack frame that we
618    didn't build.  We also use a leaf return in a format that allows us 
619    to pass %o7 in as an argument known to gcc, in the hope that its
620    value will be preserved during the reloading of STG registers.
621    Note that the current gcc (2.5.6) does not use the delay slot
622    here (%#), but perhaps future versions will.
623  */
624
625 #if defined(CONCURRENT)
626 #define WRAPPER_REENTER    \
627 void wrapper_restore_and_reenter_node(STG_NO_ARGS)  \
628 {                                       \
629      __asm__("Lwrapper_restore1:");     \
630     RestoreAllStgRegs();                \
631     JMP_(EnterNodeCode);                \
632 }
633 #else
634 #define WRAPPER_REENTER
635 #endif
636
637 #define SEPARATE_WRAPPER_RESTORE        \
638 void wrapper_restore(STG_NO_ARGS)       \
639 {                                       \
640     register void *o7 __asm__("%o7");   \
641     __asm__ volatile (                  \
642         "Lwrapper_restore0:\n"          \
643         "\tmov %%i7,%0" : "=r" (o7));   \
644     RestoreAllStgRegs();                \
645     __asm__ volatile ("jmp %0+8%#" : : "r" (o7));       \
646 }                                       \
647 WRAPPER_REENTER
648
649 #endif /* __sparc__ */
650
651 #endif /* __GNUC__ && __STG_GCC_REGS__ */
652
653 \end{code}
654
655 That's all, folks.
656 \begin{code}
657 #endif /* ! COPTWRAPS_H */
658 \end{code}