[project @ 1996-06-27 15:55:53 by partain]
[ghc.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
73 #if defined(GRAN)
74
75 #define DO_YIELD(args)   DO_GRAN_YIELD(args)
76 #define DO_GRAN_YIELD(liveness)             \
77     do {SaveAllStgRegs(); Yield(liveness); RestoreAllStgRegs();} while(0)
78
79 #define DO_PERFORM_RESCHEDULE(liveness_mask,reenter)                \
80     do {SaveAllStgRegs(); PerformReschedule(liveness_mask,reenter); RestoreAllStgRegs();} while(0)
81
82 #else
83
84 #define DO_YIELD(args)              \
85     do {SaveAllStgRegs(); Yield(args); RestoreAllStgRegs();} while(0)
86
87 #endif   /* GRAN */
88
89 \end{code}
90
91 %************************************************************************
92 %*                                                                      *
93 \subsection[COptWraps-optimised]{Wrappers in ``optimised~C''}
94 %*                                                                      *
95 %************************************************************************
96
97 We {\em expect} the call-wrappery to be boring---the defaults shown
98 herein will kick in--- but you never know.
99
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.
103
104 \begin{code}
105 #else /* __GNUC__ && __STG_GCC_REGS__ */
106
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)
114
115 #else
116
117 extern void callWrapper(STG_NO_ARGS);
118
119 #define STGCALL0(t,p,f)             \
120     ({t (*_w)p = (t (*)p) callWrapper; (*_w)((void *)f);})
121
122 #define STGCALL1(t,p,f,a)           \
123     ({t (*_w)p = (t (*)p) callWrapper; (*_w)((void *)f,a);})
124
125 #define STGCALL2(t,p,f,a,b)         \
126     ({t (*_w)p = (t (*)p) callWrapper; (*_w)((void *)f,a,b);})
127
128 #define STGCALL3(t,p,f,a,b,c)       \
129     ({t (*_w)p = (t (*)p) callWrapper; (*_w)((void *)f,a,b,c);})
130
131 #define STGCALL4(t,p,f,a,b,c,d)     \
132     ({t (*_w)p = (t (*)p) callWrapper; (*_w)((void *)f,a,b,c,d);})
133
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);})
136
137 #endif
138
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)
146
147 #else
148
149 extern void callWrapper_safe(STG_NO_ARGS);
150
151 #define SAFESTGCALL0(t,p,f)             \
152     ({t (*_w)p = (t (*)p) callWrapper_safe; (*_w)((void *)f);})
153
154 #define SAFESTGCALL1(t,p,f,a)           \
155     ({t (*_w)p = (t (*)p) callWrapper_safe; (*_w)((void *)f,a);})
156
157 #define SAFESTGCALL2(t,p,f,a,b)         \
158     ({t (*_w)p = (t (*)p) callWrapper_safe; (*_w)((void *)f,a,b);})
159
160 #define SAFESTGCALL3(t,p,f,a,b,c)       \
161     ({t (*_w)p = (t (*)p) callWrapper_safe; (*_w)((void *)f,a,b,c);})
162
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);})
165
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);})
168
169 #endif
170
171 /* 
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.
175  */
176
177 #ifndef CALLWRAPPER_C
178 /* 
179  * We may have funny declarations in CallWrapper_C, to avoid sliding the
180  * register windows and other nastiness.
181  */
182 void PerformGC_wrapper PROTO((W_));
183 void StackOverflow_wrapper PROTO((W_, W_));
184 void Yield_wrapper PROTO((W_));
185 #  ifdef GRAN
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_));
191 #  endif
192 #endif
193
194 #define DO_GC(args)                     PerformGC_wrapper(args)
195 #define DO_STACKOVERFLOW(headroom,args) StackOverflow_wrapper(headroom,args)
196
197 #  ifdef GRAN
198
199 #define DO_YIELD(args)   DO_GRAN_YIELD(args)
200 #define DO_GRAN_YIELD(liveness)                 Yield_wrapper(liveness)
201
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)
207
208 #  else
209
210 #define DO_YIELD(args)                  Yield_wrapper(args)
211
212 #  endif
213
214 #endif /* __GNUC__ && __STG_GCC_REGS__ */
215 \end{code}
216
217 %************************************************************************
218 %*                                                                      *
219 \subsection[COptWraps-magic]{Magic assembly bits for call wrappers}
220 %*                                                                      *
221 %************************************************************************
222
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
231 in the end.
232
233 Getting this right requires three extremely @MAGIC@ macros, no doubt
234 chock full of assembly gook for the current platform.  These are
235 @MAGIC_CALL_SETUP@, which gets ready for one of these magic calls,
236 @MAGIC_CALL@, which performs the call and stashes away all possible
237 results, and @MAGIC_RETURN@, which collects all possible results back
238 up again.
239
240 For example, in the SPARC version, the @SETUP@ guarantees that we
241 have enough space to store all of our argument registers for a wee
242 bit, and it gives a `C' name to the register that we're going to use
243 for the call.  (It helps to do the call in actual `C' fashion, so that
244 gcc knows about register death.)  It also stashes the incoming arguments
245 in the space  provided.  The @MAGIC_CALL@ then reloads the argument
246 registers, rotated by one, so that the function to call is in \tr{%o5},
247 calls the function in `C' fashion, and stashes away the possible return
248 values (either \tr{%o0} or \tr{%f0}) on the stack.  Finally, @MAGIC_RETURN@
249 ensures that \tr{%o0} and \tr{%f0} are both set to the values we stashed
250 away.  Presumably, we then fall into a return instruction and our caller
251 gets whatever it's after.
252
253 %************************************************************************
254 %*                                                                      *
255 \subsubsection[alpha-magic]{Call-wrapper MAGIC for DEC Alpha}
256 %*                                                                      *
257 %************************************************************************
258
259 \begin{code}
260
261 #if defined(__GNUC__) && defined(__STG_GCC_REGS__)
262
263 #if alpha_TARGET_ARCH
264
265 #define MAGIC_CALL_SETUP        \
266     long WeNeedThisSpace[7];    \
267     double AndThisSpaceToo[6];  \
268     register void (*f)() __asm__("$21");\
269     __asm__ volatile (          \
270         "stq $16,8($30)\n"      \
271         "\tstq $17,16($30)\n"   \
272         "\tstq $18,24($30)\n"   \
273         "\tstq $19,32($30)\n"   \
274         "\tstq $20,40($30)\n"   \
275         "\tstq $21,48($30)\n"   \
276         "\tstt $f16,56($30)\n"  \
277         "\tstt $f17,64($30)\n"  \
278         "\tstt $f18,72($30)\n"  \
279         "\tstt $f19,80($30)\n"  \
280         "\tstt $f20,88($30)\n"  \
281         "\tstt $f21,96($30)");
282
283 #define MAGIC_CALL              \
284     __asm__ volatile (          \
285         "ldq $21,8($30)\n"      \
286         "\tldq $16,16($30)\n"   \
287         "\tldq $17,24($30)\n"   \
288         "\tldq $18,32($30)\n"   \
289         "\tldq $19,40($30)\n"   \
290         "\tldq $20,48($30)\n"   \
291         "\tldt $f16,56($30)\n"  \
292         "\tldt $f17,64($30)\n"  \
293         "\tldt $f18,72($30)\n"  \
294         "\tldt $f19,80($30)\n"  \
295         "\tldt $f20,88($30)\n"  \
296         "\tldt $f21,96($30)");\
297     (*f)();                     \
298     __asm__ volatile (          \
299         "stq $0,8($30)\n"       \
300         "\tstt $f0,16($30)");
301
302 #define MAGIC_RETURN            \
303     __asm__ volatile (          \
304         "ldq $0,8($30)\n"       \
305         "\tldt $f0,16($30)");
306
307 #define WRAPPER_NAME(f)   /* nothing */
308
309 /* 
310    Threaded code needs to be able to grab the return address, in case we have
311    an intervening context switch.
312  */
313
314 #define SET_RETADDR(loc)  { register StgFunPtrFunPtr ra __asm__ ("$26"); loc = ra; }
315
316 #define WRAPPER_SETUP(f,ignore1,ignore2)  SaveAllStgContext();
317
318 #define WRAPPER_RETURN(x)   \
319     do {RestoreAllStgRegs(); if(x) JMP_(EnterNodeCode);} while(0);
320
321 #define SEPARATE_WRAPPER_RESTORE    /* none */
322
323 #endif /* __alpha */
324
325 \end{code}
326
327 %************************************************************************
328 %*                                                                      *
329 \subsubsection[hppa-magic]{Call-wrapper MAGIC for HP-PA}
330 %*                                                                      *
331 %************************************************************************
332
333 \begin{code}
334
335 #if hppa1_1_TARGET_ARCH
336
337 #define MAGIC_CALL_SETUP            \
338     long SavedIntArgRegs[4];        \
339     double SavedFltArgRegs[2];      \
340     register void (*f)() __asm__("%r28");\
341     __asm__ volatile (              \
342         "copy %r26,%r28\n"          \
343         "\tstw %r25,8(0,%r3)\n"     \
344         "\tstw %r24,12(0,%r3)\n"    \
345         "\tstw %r23,16(0,%r3)\n"    \
346         "\tldo 40(%r3),%r19\n"      \
347         "\tfstds %fr5,-16(0,%r19)\n"\
348         "\tfstds %fr7, -8(0,%r19)\n");
349
350
351 #define MAGIC_CALL                  \
352     __asm__ volatile (              \
353         "ldw 8(0,%r3),%r26\n"       \
354         "\tldw 12(0,%r3),%r25\n"    \
355         "\tldw 16(0,%r3),%r24\n"    \
356         "\tldw -52(0,%r3),%r23\n"   \
357         "\tldw -56(0,%r3),%r19\n"   \
358         "\tstw %r19,-52(0,%r30)\n"  \
359         "\tldo 40(%r3),%r19\n"      \
360         "\tfldds -16(0,%r19),%fr5\n"\
361         "\tfldds -8(0,%r19),%fr7\n" \
362         "\tldo -64(%r3),%r19\n"     \
363         "\tldo -64(%r30),%r20\n"    \
364         "\tfldds -16(0,%r19),%fr4\n"\
365         "\tfstds %fr4,-16(0,%r20)\n"\
366         "\tfldds -8(0,%r19)%fr4\n"  \
367         "\tfstds %fr4,-8(0,%r19)\n" \
368         "\tfldds 0(0,%r19),%fr4\n"  \
369         "\tfstds %fr4,0(0,%r19)\n"  \
370         "\tfldds 8(0,%r19),%fr4\n"  \
371         "\tfstds %fr4,8(0,%r19)\n");\
372     (*f)();                         \
373     __asm__ volatile (              \
374         "stw %r28,8(0,%r3)\n"       \
375         "\tfstds %fr4,16(0,%r3)");
376
377 #define MAGIC_RETURN                \
378     __asm__ volatile (              \
379         "\tfldds 16(0,%r3),%fr4"    \
380         "ldw 8(0,%r3),%r28\n");
381
382 #define WRAPPER_NAME(f)   /* nothing */
383
384 /* 
385    Threaded code needs to be able to grab the return address, in case we have
386    an intervening context switch.
387  */
388
389 #define SET_RETADDR(loc)  __asm__ volatile ("stw %%r2, %0" : "=m" ((void *)(loc)));
390
391 #define WRAPPER_SETUP(f,ignore1,ignore2)  SaveAllStgContext();
392
393 #define WRAPPER_RETURN(x)   \
394     do {RestoreAllStgRegs(); if(x) JMP_(EnterNodeCode);} while(0);
395
396 #define SEPARATE_WRAPPER_RESTORE    /* none */
397
398 #endif /* __hppa */
399
400 \end{code}
401
402 %************************************************************************
403 %*                                                                      *
404 \subsubsection[iX86-magic]{Call-wrapper MAGIC for iX86}
405 %*                                                                      *
406 %************************************************************************
407
408 \begin{code}
409 #if i386_TARGET_ARCH
410
411 /* modelled loosely on SPARC stuff */
412
413 /* NB: no MAGIC_CALL_SETUP, MAGIC_CALL, or MAGIC_RETURN! */
414
415 #define WRAPPER_NAME(f) /*nothing*/
416
417 #if defined(solaris2_TARGET_OS) || defined(linux_TARGET_OS)
418 #define REAL_NAME(f)   #f
419 #else
420 #define REAL_NAME(f)   "_" #f
421 #endif
422
423 /* 
424    Threaded code needs to be able to grab the return address, in case we have
425    an intervening context switch.
426  */
427
428 #define SET_RETADDR(loc,val) loc = val;
429
430 /* the grab-%eax-quickly HACK is here because we use a VERY SPECIAL
431    calling convention on iX86 just for calling PerformGC_wrapper.
432    (WDP 95/09)
433
434    NB: mangler makes sure that __temp_{eax,esp} get loaded.
435    (This is about as ugly as it can get.)
436 */
437
438 #define WRAPPER_SETUP(f,ret_addr,args)                  \
439     __asm__ volatile (                                  \
440         "movl "   REAL_NAME(__temp_esp)  ",%%edx\n"     \
441         "\tmovl (%%edx),%0\n"                           \
442         "\tmovl " REAL_NAME(__temp_eax) ",%1"           \
443         : "=r" (ret_addr), "=r" (args) );               \
444     SaveAllStgContext(ret_addr);
445
446 /* Note re WRAPPER_SETUP: we have special code just for PerformGC_wrapper;
447    pls see its definition.  WDP 95/09
448
449    Also note the EXTREMELY UGLY slamming in of an "sp_offset"; the
450    return address *is* on the stack, but it is hard to get there
451    before GCC has moved the sp pointer... WDP 95/11
452 */
453
454 #define WRAPPER_RETURN(x)   \
455     do {RestoreAllStgRegs(); if(x) JMP_(EnterNodeCode);} while(0);
456
457 #define SEPARATE_WRAPPER_RESTORE    /* none */
458
459 #endif /* iX86 */
460 \end{code}
461
462 %************************************************************************
463 %*                                                                      *
464 \subsubsection[m68k-magic]{Call-wrapper MAGIC for m68k}
465 %*                                                                      *
466 %************************************************************************
467
468 \begin{code}
469
470 #if m68k_TARGET_ARCH
471
472 #define MAGIC_CALL_SETUP  \
473     int WeNeedThisSpace[5];             \
474     register void (*f)() __asm__("a0"); \
475     __asm__ volatile (                  \
476     "movel a6@(8),a0\n"                 \
477     "\tmovel a6@(12),a6@(-20)\n"        \
478     "\tmovel a6@(16),a6@(-16)\n"        \
479     "\tmovel a6@(20),a6@(-12)\n"        \
480     "\tmovel a6@(24),a6@(-8)\n"         \
481     "\tmovel a6@(28),a6@(-4)");
482
483 #define MAGIC_CALL      \
484     (*f)();             \
485      __asm__ volatile ( \
486     "movel d0, sp@-\n"  \
487     "\tmovel d1,sp@-");
488
489 #define MAGIC_RETURN    \
490     __asm__ volatile (  \
491     "movel sp@+,d0\n"   \
492     "\tmovel sp@+,d1");
493
494 #define WRAPPER_NAME(f)   /* nothing */
495
496 #define WRAPPER_SETUP(f,ignore1,ignore2)  SaveAllStgContext();
497
498 #define WRAPPER_RETURN(x)  \
499     do {RestoreAllStgRegs(); if(x) JMP_(EnterNodeCode);} while(0);
500
501 #define SEPARATE_WRAPPER_RESTORE    /* none */
502
503 #endif /* __mc680x0__ */
504
505 \end{code}
506
507 %************************************************************************
508 %*                                                                      *
509 \subsubsection[mips-magic]{Call-wrapper MAGIC for MIPS}
510 %*                                                                      *
511 %************************************************************************
512
513 \begin{code}
514 #if mipseb_TARGET_ARCH || mipsel_TARGET_ARCH
515
516 /* shift 4 arg registers down one */
517
518 #define MAGIC_CALL_SETUP  \
519     register void (*f)() __asm__("$2"); \
520     __asm__ volatile (                  \
521     "move $2,$4\n"                      \
522     "\tmove $4,$5\n"                    \
523     "\tmove $5,$6\n"                    \
524     "\tmove $6,$7\n"                    \
525     "\tlw $7,16($sp)\n"                 \
526     "\taddu $sp,$sp,4\n"                \
527     : : : "$2" );
528
529 #define MAGIC_CALL              \
530     (*f)();                     \
531      __asm__ volatile (         \
532     "subu $sp,$sp,4\n"          \
533     "\ts.d $f0, -8($sp)\n"      \
534     "\tsw  $2, -12($sp)");
535
536 #define MAGIC_RETURN            \
537     __asm__ volatile (          \
538     "l.d $f0, -8($sp)\n"        \
539     "\tlw  $2, -12($sp)");
540
541 #define WRAPPER_NAME(f)   /* nothing */
542
543 #define WRAPPER_SETUP(f,ignore1,ignore2)  SaveAllStgContext();
544
545 #define WRAPPER_RETURN(x)  \
546     do {RestoreAllStgRegs(); if(x) JMP_(EnterNodeCode);} while(0);
547
548 #define SEPARATE_WRAPPER_RESTORE    /* none */
549
550 #endif /* mips */
551 \end{code}
552
553 %************************************************************************
554 %*                                                                      *
555 \subsubsection[powerpc-magic]{Call-wrapper MAGIC for PowerPC}
556 %*                                                                      *
557 %************************************************************************
558
559 \begin{code}
560 #if powerpc_TARGET_ARCH
561
562 /* shift 4 arg registers down one */
563
564 #define MAGIC_CALL_SETUP  \
565     register void (*f)() __asm__("$2"); \
566     __asm__ volatile (                  \
567     "move $2,$4\n"                      \
568     "\tmove $4,$5\n"                    \
569     "\tmove $5,$6\n"                    \
570     "\tmove $6,$7\n"                    \
571     "\tlw $7,16($sp)\n"                 \
572     "\taddu $sp,$sp,4\n"                \
573     : : : "$2" );
574
575 #define MAGIC_CALL              \
576     (*f)();                     \
577      __asm__ volatile (         \
578     "subu $sp,$sp,4\n"          \
579     "\ts.d $f0, -8($sp)\n"      \
580     "\tsw  $2, -12($sp)");
581
582 #define MAGIC_RETURN            \
583     __asm__ volatile (          \
584     "l.d $f0, -8($sp)\n"        \
585     "\tlw  $2, -12($sp)");
586
587 #define WRAPPER_NAME(f)   /* nothing */
588
589 #define WRAPPER_SETUP(f,ignore1,ignore2)  SaveAllStgContext();
590
591 #define WRAPPER_RETURN(x)  \
592     do {RestoreAllStgRegs(); if(x) JMP_(EnterNodeCode);} while(0);
593
594 #define SEPARATE_WRAPPER_RESTORE    /* none */
595
596 #endif /* powerpc */
597 \end{code}
598
599 %************************************************************************
600 %*                                                                      *
601 \subsubsection[sparc-magic]{Call-wrapper MAGIC for SPARC}
602 %*                                                                      *
603 %************************************************************************
604
605 \begin{code}
606 #if sparc_TARGET_ARCH
607
608 #define MAGIC_CALL_SETUP        \
609     int WeNeedThisSpace[6];     \
610     register void (*f)() __asm__("%o5");\
611     __asm__ volatile (          \
612         "std %i0,[%fp-40]\n"    \
613         "\tstd %i2,[%fp-32]\n"  \
614         "\tstd %i4,[%fp-24]");
615
616 /* We leave nothing to chance here; we have seen
617    GCC stick "unwanted" code in the branch delay
618    slot, causing mischief (WDP 96/05)
619 */
620 #ifdef GRAN
621 #define MAGIC_CALL              \
622     __asm__ volatile (          \
623         "ld [%%fp-40],%%o5\n"   \
624         "\tld [%%fp-36],%%o0\n" \
625         "\tld [%%fp-32],%%o1\n" \
626         "\tld [%%fp-28],%%o2\n" \
627         "\tld [%%fp-24],%%o3\n" \
628         "\tld [%%fp-20],%%o4"   \
629         : : : "%o0", "%o1", "%o2", "%o3", "%o4", "%o5");\
630     (*f)();                     \
631     __asm__ volatile (          \
632         "std %f0,[%fp-40]\n"    \
633         "\tstd %o0,[%fp-32]");
634 #else
635 #define MAGIC_CALL              \
636     __asm__ volatile (          \
637         "ld [%%fp-40],%%o5\n"   \
638         "\tld [%%fp-36],%%o0\n" \
639         "\tld [%%fp-32],%%o1\n" \
640         "\tld [%%fp-28],%%o2\n" \
641         "\tld [%%fp-24],%%o3\n" \
642         "\tld [%%fp-20],%%o4\n" \
643         "\tcall %%o5\n"         \
644         "\tnop\n"               \
645         "\tstd %%f0,[%%fp-40]\n"\
646         "\tstd %%o0,[%%fp-32]"  \
647         : : : "%o0", "%o1", "%o2", "%o3", "%o4", "%o5", "%f0", "%g1", "%g2", "%g3", "%g4", "memory");
648 #endif
649
650 #define MAGIC_RETURN            \
651     __asm__ volatile (          \
652         "ldd [%fp-40],%f0\n"    \
653         "\tldd [%fp-32],%i0");
654
655 /* 
656    We rename the entry points for wrappers so that we can introduce a
657    new entry point after the prologue.  We want to ensure that the
658    register window does not slide!  However, we insert a call to
659    abort() to make gcc _believe_ that the window slid.
660  */
661
662 #define WRAPPER_NAME(f)   __asm__("L" #f "_wrapper")
663
664 #ifdef solaris2_TARGET_OS
665 #define REAL_NAME(f)   #f
666 #else
667 #define REAL_NAME(f)   "_" #f
668 #endif
669
670 #define WRAPPER_SETUP(f,ignore1,ignore2)    \
671     __asm__ volatile (                      \
672         ".global " REAL_NAME(f) "_wrapper\n"\
673         REAL_NAME(f) "_wrapper:\n"          \
674         "\tstd %o0,[%sp-24]\n"              \
675         "\tmov %o7,%i7");                   \
676     SaveAllStgContext();                    \
677     __asm__ volatile (                      \
678         "ldd [%sp-24],%i0\n"                \
679         "\tmov %i0,%o0\n"                   \
680         "\tmov %i1,%o1");
681 /* 
682  * In the above, we want to ensure that the arguments are both in the
683  * %i registers and the %o registers, with the assumption that gcc
684  * will expect them now to be in one or the other.  This is a terrible
685  * hack.
686  */
687
688 /* 
689    Threaded code needs to be able to grab the return address, in case
690    we have an intervening context switch.  Note that we want the
691    address of the next instruction to be executed, so we add 8 to the
692    link address.
693  */
694
695 #define SET_RETADDR(loc)        \
696     __asm__ volatile (          \
697         "add %%i7,8,%%o7\n"     \
698         "\tst %%o7,%0"          \
699         : "=m" (loc) : : "%o7");
700
701
702 #define WRAPPER_RETURN(x)               \
703     __asm__ volatile (                  \
704         "call Lwrapper_restore" #x "\n" \
705         "\tnop");                       \
706     abort();
707
708 /* 
709    The sparc is a big nuisance.  We use a separate function for 
710    restoring STG registers so that gcc won't try to leave anything
711    (like the address of MainRegTable) in the stack frame that we
712    didn't build.  We also use a leaf return in a format that allows us 
713    to pass %o7 in as an argument known to gcc, in the hope that its
714    value will be preserved during the reloading of STG registers.
715    Note that the current gcc (2.5.6) does not use the delay slot
716    here (%#), but perhaps future versions will.
717  */
718
719 #if defined(CONCURRENT)
720 #define WRAPPER_REENTER    \
721 void wrapper_restore_and_reenter_node(STG_NO_ARGS)  \
722 {                                       \
723      __asm__("Lwrapper_restore1:");     \
724     RestoreAllStgRegs();                \
725     JMP_(EnterNodeCode);                \
726 }
727 #else
728 #define WRAPPER_REENTER
729 #endif
730
731 #define SEPARATE_WRAPPER_RESTORE        \
732 void wrapper_restore(STG_NO_ARGS)       \
733 {                                       \
734     register void *o7 __asm__("%o7");   \
735     __asm__ volatile (                  \
736         "Lwrapper_restore0:\n"          \
737         "\tmov %%i7,%0" : "=r" (o7));   \
738     RestoreAllStgRegs();                \
739     __asm__ volatile ("jmp %0+8%#" : : "r" (o7));       \
740 }                                       \
741 WRAPPER_REENTER
742
743 #endif /* __sparc__ */
744
745 #endif /* __GNUC__ && __STG_GCC_REGS__ */
746
747 \end{code}
748
749 That's all, folks.
750 \begin{code}
751 #endif /* ! COPTWRAPS_H */
752 \end{code}