[project @ 1996-01-11 14:06:51 by partain]
[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_TARGET_ARCH
227
228 #define MAGIC_CALL_SETUP        \
229     long WeNeedThisSpace[7];    \
230     double AndThisSpaceToo[6];  \
231     register void (*f)() __asm__("$21");\
232     __asm__ volatile (          \
233         "stq $16,8($30)\n"      \
234         "\tstq $17,16($30)\n"   \
235         "\tstq $18,24($30)\n"   \
236         "\tstq $19,32($30)\n"   \
237         "\tstq $20,40($30)\n"   \
238         "\tstq $21,48($30)\n"   \
239         "\tstt $f16,56($30)\n"  \
240         "\tstt $f17,64($30)\n"  \
241         "\tstt $f18,72($30)\n"  \
242         "\tstt $f19,80($30)\n"  \
243         "\tstt $f20,88($30)\n"  \
244         "\tstt $f21,96($30)");
245
246 #define MAGIC_CALL              \
247     __asm__ volatile (          \
248         "ldq $21,8($30)\n"      \
249         "\tldq $16,16($30)\n"   \
250         "\tldq $17,24($30)\n"   \
251         "\tldq $18,32($30)\n"   \
252         "\tldq $19,40($30)\n"   \
253         "\tldq $20,48($30)\n"   \
254         "\tldt $f16,56($30)\n"  \
255         "\tldt $f17,64($30)\n"  \
256         "\tldt $f18,72($30)\n"  \
257         "\tldt $f19,80($30)\n"  \
258         "\tldt $f20,88($30)\n"  \
259         "\tldt $f21,96($30)");\
260     (*f)();                     \
261     __asm__ volatile (          \
262         "stq $0,8($30)\n"       \
263         "\tstt $f0,16($30)");
264
265 #define MAGIC_RETURN            \
266     __asm__ volatile (          \
267         "ldq $0,8($30)\n"       \
268         "\tldt $f0,16($30)");
269
270 #define WRAPPER_NAME(f)   /* nothing */
271
272 /* 
273    Threaded code needs to be able to grab the return address, in case we have
274    an intervening context switch.
275  */
276
277 #define SET_RETADDR(loc)  { register StgFunPtrFunPtr ra __asm__ ("$26"); loc = ra; }
278
279 #define WRAPPER_SETUP(f,ignore1,ignore2)  SaveAllStgContext();
280
281 #define WRAPPER_RETURN(x)   \
282     do {RestoreAllStgRegs(); if(x) JMP_(EnterNodeCode);} while(0);
283
284 #define SEPARATE_WRAPPER_RESTORE    /* none */
285
286 #endif /* __alpha */
287
288 \end{code}
289
290 %************************************************************************
291 %*                                                                      *
292 \subsubsection[hppa-magic]{Call-wrapper MAGIC for HP-PA}
293 %*                                                                      *
294 %************************************************************************
295
296 \begin{code}
297
298 #if hppa1_1_TARGET_ARCH
299
300 #define MAGIC_CALL_SETUP            \
301     long SavedIntArgRegs[4];        \
302     double SavedFltArgRegs[2];      \
303     register void (*f)() __asm__("%r28");\
304     __asm__ volatile (              \
305         "copy %r26,%r28\n"          \
306         "\tstw %r25,8(0,%r3)\n"     \
307         "\tstw %r24,12(0,%r3)\n"    \
308         "\tstw %r23,16(0,%r3)\n"    \
309         "\tldo 40(%r3),%r19\n"      \
310         "\tfstds %fr5,-16(0,%r19)\n"\
311         "\tfstds %fr7, -8(0,%r19)\n");
312
313
314 #define MAGIC_CALL                  \
315     __asm__ volatile (              \
316         "ldw 8(0,%r3),%r26\n"       \
317         "\tldw 12(0,%r3),%r25\n"    \
318         "\tldw 16(0,%r3),%r24\n"    \
319         "\tldw -52(0,%r3),%r23\n"   \
320         "\tldw -56(0,%r3),%r19\n"   \
321         "\tstw %r19,-52(0,%r30)\n"  \
322         "\tldo 40(%r3),%r19\n"      \
323         "\tfldds -16(0,%r19),%fr5\n"\
324         "\tfldds -8(0,%r19),%fr7\n" \
325         "\tldo -64(%r3),%r19\n"     \
326         "\tldo -64(%r30),%r20\n"    \
327         "\tfldds -16(0,%r19),%fr4\n"\
328         "\tfstds %fr4,-16(0,%r20)\n"\
329         "\tfldds -8(0,%r19)%fr4\n"  \
330         "\tfstds %fr4,-8(0,%r19)\n" \
331         "\tfldds 0(0,%r19),%fr4\n"  \
332         "\tfstds %fr4,0(0,%r19)\n"  \
333         "\tfldds 8(0,%r19),%fr4\n"  \
334         "\tfstds %fr4,8(0,%r19)\n");\
335     (*f)();                         \
336     __asm__ volatile (              \
337         "stw %r28,8(0,%r3)\n"       \
338         "\tfstds %fr4,16(0,%r3)");
339
340 #define MAGIC_RETURN                \
341     __asm__ volatile (              \
342         "\tfldds 16(0,%r3),%fr4"    \
343         "ldw 8(0,%r3),%r28\n");
344
345 #define WRAPPER_NAME(f)   /* nothing */
346
347 /* 
348    Threaded code needs to be able to grab the return address, in case we have
349    an intervening context switch.
350  */
351
352 #define SET_RETADDR(loc)  __asm__ volatile ("stw %%r2, %0" : "=m" ((void *)(loc)));
353
354 #define WRAPPER_SETUP(f,ignore1,ignore2)  SaveAllStgContext();
355
356 #define WRAPPER_RETURN(x)   \
357     do {RestoreAllStgRegs(); if(x) JMP_(EnterNodeCode);} while(0);
358
359 #define SEPARATE_WRAPPER_RESTORE    /* none */
360
361 #endif /* __hppa */
362
363 \end{code}
364
365 %************************************************************************
366 %*                                                                      *
367 \subsubsection[iX86-magic]{Call-wrapper MAGIC for iX86}
368 %*                                                                      *
369 %************************************************************************
370
371 \begin{code}
372 #if i386_TARGET_ARCH
373
374 /* modelled loosely on SPARC stuff */
375
376 /* NB: no MAGIC_CALL_SETUP, MAGIC_CALL, or MAGIC_RETURN! */
377
378 #define WRAPPER_NAME(f) /*nothing*/
379
380 #ifdef solaris2_TARGET_OS
381 #define REAL_NAME(f)   #f
382 #else
383 #define REAL_NAME(f)   "_" #f
384 #endif
385
386 /* 
387    Threaded code needs to be able to grab the return address, in case we have
388    an intervening context switch.
389  */
390
391 #define SET_RETADDR(loc,val) loc = val;
392
393 /* the grab-%eax-quickly HACK is here because we use a VERY SPECIAL
394    calling convention on iX86 just for calling PerformGC_wrapper.
395    (WDP 95/09)
396
397    NB: mangler makes sure that __temp_{eax,esp} get loaded.
398    (This is about as ugly as it can get.)
399 */
400
401 #define WRAPPER_SETUP(f,ret_addr,args)                  \
402     __asm__ volatile (                                  \
403         "movl "   REAL_NAME(__temp_esp)  ",%%edx\n"     \
404         "\tmovl (%%edx),%0\n"                           \
405         "\tmovl " REAL_NAME(__temp_eax) ",%1"           \
406         : "=r" (ret_addr), "=r" (args) );               \
407     SaveAllStgContext(ret_addr);
408
409 /* Note re WRAPPER_SETUP: we have special code just for PerformGC_wrapper;
410    pls see its definition.  WDP 95/09
411
412    Also note the EXTREMELY UGLY slamming in of an "sp_offset"; the
413    return address *is* on the stack, but it is hard to get there
414    before GCC has moved the sp pointer... WDP 95/11
415 */
416
417 #define WRAPPER_RETURN(x)   \
418     do {RestoreAllStgRegs(); if(x) JMP_(EnterNodeCode);} while(0);
419
420 #define SEPARATE_WRAPPER_RESTORE    /* none */
421
422 #endif /* iX86 */
423 \end{code}
424
425 %************************************************************************
426 %*                                                                      *
427 \subsubsection[m68k-magic]{Call-wrapper MAGIC for m68k}
428 %*                                                                      *
429 %************************************************************************
430
431 \begin{code}
432
433 #if m68k_TARGET_ARCH
434
435 #define MAGIC_CALL_SETUP  \
436     int WeNeedThisSpace[5];             \
437     register void (*f)() __asm__("a0"); \
438     __asm__ volatile (                  \
439     "movel a6@(8),a0\n"                 \
440     "\tmovel a6@(12),a6@(-20)\n"        \
441     "\tmovel a6@(16),a6@(-16)\n"        \
442     "\tmovel a6@(20),a6@(-12)\n"        \
443     "\tmovel a6@(24),a6@(-8)\n"         \
444     "\tmovel a6@(28),a6@(-4)");
445
446 #define MAGIC_CALL      \
447     (*f)();             \
448      __asm__ volatile ( \
449     "movel d0, sp@-\n"  \
450     "\tmovel d1,sp@-");
451
452 #define MAGIC_RETURN    \
453     __asm__ volatile (  \
454     "movel sp@+,d0\n"   \
455     "\tmovel sp@+,d1");
456
457 #define WRAPPER_NAME(f)   /* nothing */
458
459 #define WRAPPER_SETUP(f,ignore1,ignore2)  SaveAllStgContext();
460
461 #define WRAPPER_RETURN(x)  \
462     do {RestoreAllStgRegs(); if(x) JMP_(EnterNodeCode);} while(0);
463
464 #define SEPARATE_WRAPPER_RESTORE    /* none */
465
466 #endif /* __mc680x0__ */
467
468 \end{code}
469
470 %************************************************************************
471 %*                                                                      *
472 \subsubsection[mips-magic]{Call-wrapper MAGIC for MIPS}
473 %*                                                                      *
474 %************************************************************************
475
476 \begin{code}
477 #if mipseb_TARGET_ARCH || mipsel_TARGET_ARCH
478
479 /* shift 4 arg registers down one */
480
481 #define MAGIC_CALL_SETUP  \
482     register void (*f)() __asm__("$2"); \
483     __asm__ volatile (                  \
484     "move $2,$4\n"                      \
485     "\tmove $4,$5\n"                    \
486     "\tmove $5,$6\n"                    \
487     "\tmove $6,$7\n"                    \
488     "\tlw $7,16($sp)\n"                 \
489     "\taddu $sp,$sp,4\n"                \
490     : : : "$2" );
491
492 #define MAGIC_CALL              \
493     (*f)();                     \
494      __asm__ volatile (         \
495     "subu $sp,$sp,4\n"          \
496     "\ts.d $f0, -8($sp)\n"      \
497     "\tsw  $2, -12($sp)");
498
499 #define MAGIC_RETURN            \
500     __asm__ volatile (          \
501     "l.d $f0, -8($sp)\n"        \
502     "\tlw  $2, -12($sp)");
503
504 #define WRAPPER_NAME(f)   /* nothing */
505
506 #define WRAPPER_SETUP(f,ignore1,ignore2)  SaveAllStgContext();
507
508 #define WRAPPER_RETURN(x)  \
509     do {RestoreAllStgRegs(); if(x) JMP_(EnterNodeCode);} while(0);
510
511 #define SEPARATE_WRAPPER_RESTORE    /* none */
512
513 #endif /* mips */
514 \end{code}
515
516 %************************************************************************
517 %*                                                                      *
518 \subsubsection[powerpc-magic]{Call-wrapper MAGIC for PowerPC}
519 %*                                                                      *
520 %************************************************************************
521
522 \begin{code}
523 #if powerpc_TARGET_ARCH
524
525 /* shift 4 arg registers down one */
526
527 #define MAGIC_CALL_SETUP  \
528     register void (*f)() __asm__("$2"); \
529     __asm__ volatile (                  \
530     "move $2,$4\n"                      \
531     "\tmove $4,$5\n"                    \
532     "\tmove $5,$6\n"                    \
533     "\tmove $6,$7\n"                    \
534     "\tlw $7,16($sp)\n"                 \
535     "\taddu $sp,$sp,4\n"                \
536     : : : "$2" );
537
538 #define MAGIC_CALL              \
539     (*f)();                     \
540      __asm__ volatile (         \
541     "subu $sp,$sp,4\n"          \
542     "\ts.d $f0, -8($sp)\n"      \
543     "\tsw  $2, -12($sp)");
544
545 #define MAGIC_RETURN            \
546     __asm__ volatile (          \
547     "l.d $f0, -8($sp)\n"        \
548     "\tlw  $2, -12($sp)");
549
550 #define WRAPPER_NAME(f)   /* nothing */
551
552 #define WRAPPER_SETUP(f,ignore1,ignore2)  SaveAllStgContext();
553
554 #define WRAPPER_RETURN(x)  \
555     do {RestoreAllStgRegs(); if(x) JMP_(EnterNodeCode);} while(0);
556
557 #define SEPARATE_WRAPPER_RESTORE    /* none */
558
559 #endif /* powerpc */
560 \end{code}
561
562 %************************************************************************
563 %*                                                                      *
564 \subsubsection[sparc-magic]{Call-wrapper MAGIC for SPARC}
565 %*                                                                      *
566 %************************************************************************
567
568 \begin{code}
569
570 #if sparc_TARGET_ARCH
571
572 #define MAGIC_CALL_SETUP        \
573     int WeNeedThisSpace[6];     \
574     register void (*f)() __asm__("%o5");\
575     __asm__ volatile (          \
576         "std %i0,[%fp-40]\n"    \
577         "\tstd %i2,[%fp-32]\n"  \
578         "\tstd %i4,[%fp-24]");
579
580 #define MAGIC_CALL              \
581     __asm__ volatile (          \
582         "ld [%%fp-40],%%o5\n"   \
583         "\tld [%%fp-36],%%o0\n" \
584         "\tld [%%fp-32],%%o1\n" \
585         "\tld [%%fp-28],%%o2\n" \
586         "\tld [%%fp-24],%%o3\n" \
587         "\tld [%%fp-20],%%o4"   \
588         : : : "%o0", "%o1", "%o2", "%o3", "%o4", "%o5");\
589     (*f)();                     \
590     __asm__ volatile (          \
591         "std %f0,[%fp-40]\n"    \
592         "\tstd %o0,[%fp-32]");
593
594 #define MAGIC_RETURN            \
595     __asm__ volatile (          \
596         "ldd [%fp-40],%f0\n"    \
597         "\tldd [%fp-32],%i0");
598
599 /* 
600    We rename the entry points for wrappers so that we can introduce a
601    new entry point after the prologue.  We want to ensure that the
602    register window does not slide!  However, we insert a call to
603    abort() to make gcc _believe_ that the window slid.
604  */
605
606 #define WRAPPER_NAME(f)   __asm__("L" #f "_wrapper")
607
608 #ifdef solaris2_TARGET_OS
609 #define REAL_NAME(f)   #f
610 #else
611 #define REAL_NAME(f)   "_" #f
612 #endif
613
614 #define WRAPPER_SETUP(f,ignore1,ignore2)    \
615     __asm__ volatile (                      \
616         ".global " REAL_NAME(f) "_wrapper\n"\
617         REAL_NAME(f) "_wrapper:\n"          \
618         "\tstd %o0,[%sp-24]\n"              \
619         "\tmov %o7,%i7");                   \
620     SaveAllStgContext();                    \
621     __asm__ volatile (                      \
622         "ldd [%sp-24],%i0\n"                \
623         "\tmov %i0,%o0\n"                   \
624         "\tmov %i1,%o1");
625 /* 
626  * In the above, we want to ensure that the arguments are both in the
627  * %i registers and the %o registers, with the assumption that gcc
628  * will expect them now to be in one or the other.  This is a terrible
629  * hack.
630  */
631
632 /* 
633    Threaded code needs to be able to grab the return address, in case
634    we have an intervening context switch.  Note that we want the
635    address of the next instruction to be executed, so we add 8 to the
636    link address.
637  */
638
639 #define SET_RETADDR(loc)        \
640     __asm__ volatile (          \
641         "add %%i7,8,%%o7\n"     \
642         "\tst %%o7,%0"          \
643         : "=m" (loc) : : "%o7");
644
645
646 #define WRAPPER_RETURN(x)               \
647     __asm__ volatile (                  \
648         "call Lwrapper_restore" #x "\n" \
649         "\tnop");                       \
650     abort();
651
652 /* 
653    The sparc is a big nuisance.  We use a separate function for 
654    restoring STG registers so that gcc won't try to leave anything
655    (like the address of MainRegTable) in the stack frame that we
656    didn't build.  We also use a leaf return in a format that allows us 
657    to pass %o7 in as an argument known to gcc, in the hope that its
658    value will be preserved during the reloading of STG registers.
659    Note that the current gcc (2.5.6) does not use the delay slot
660    here (%#), but perhaps future versions will.
661  */
662
663 #if defined(CONCURRENT)
664 #define WRAPPER_REENTER    \
665 void wrapper_restore_and_reenter_node(STG_NO_ARGS)  \
666 {                                       \
667      __asm__("Lwrapper_restore1:");     \
668     RestoreAllStgRegs();                \
669     JMP_(EnterNodeCode);                \
670 }
671 #else
672 #define WRAPPER_REENTER
673 #endif
674
675 #define SEPARATE_WRAPPER_RESTORE        \
676 void wrapper_restore(STG_NO_ARGS)       \
677 {                                       \
678     register void *o7 __asm__("%o7");   \
679     __asm__ volatile (                  \
680         "Lwrapper_restore0:\n"          \
681         "\tmov %%i7,%0" : "=r" (o7));   \
682     RestoreAllStgRegs();                \
683     __asm__ volatile ("jmp %0+8%#" : : "r" (o7));       \
684 }                                       \
685 WRAPPER_REENTER
686
687 #endif /* __sparc__ */
688
689 #endif /* __GNUC__ && __STG_GCC_REGS__ */
690
691 \end{code}
692
693 That's all, folks.
694 \begin{code}
695 #endif /* ! COPTWRAPS_H */
696 \end{code}