[project @ 1998-11-26 09:17:22 by sof]
[ghc-hetmet.git] / ghc / runtime / c-as-asm / CallWrap_C.lc
1 %************************************************************************
2 %*                                                                      *
3 \section[CallWrap_C.lc]{``callWrapper'' stuff that can be written in C}
4 %*                                                                      *
5 %************************************************************************
6
7 \begin{code}
8 #define MAIN_REG_MAP        /* These routines are all a bit special */
9 #define CALLWRAPPER_C       /* Don't give standard declarations for wrappers */
10 #include "rtsdefs.h"
11 \end{code}
12
13 %************************************************************************
14 %*                                                                      *
15 \subsection[call-wrapping]{Routines to ``wrap'' special calls to C}
16 %*                                                                      *
17 %************************************************************************
18
19 In most cases, this requires some assembly-language hacking (see the
20 discussion in @COptWraps.lh@.)
21
22 \begin{code}
23 #if defined(__STG_GCC_REGS__)
24
25 # if defined(CALLER_SAVES_SYSTEM) || defined(CALLER_SAVES_USER)
26 void
27 callWrapper(STG_NO_ARGS)
28 {
29     MAGIC_CALL_SETUP
30
31     CALLER_SAVE_Base
32     CALLER_SAVE_StkO
33     CALLER_SAVE_R1
34     CALLER_SAVE_R2
35     CALLER_SAVE_R3
36     CALLER_SAVE_R4
37     CALLER_SAVE_R5
38     CALLER_SAVE_R6
39     CALLER_SAVE_R7
40     CALLER_SAVE_R8
41     CALLER_SAVE_FltReg1
42     CALLER_SAVE_FltReg2
43     CALLER_SAVE_FltReg3
44     CALLER_SAVE_FltReg4
45     CALLER_SAVE_DblReg1
46     CALLER_SAVE_DblReg2
47     CALLER_SAVE_LngReg1
48     CALLER_SAVE_LngReg2
49     CALLER_SAVE_Tag
50     CALLER_SAVE_SpA
51     CALLER_SAVE_SuA
52     CALLER_SAVE_SpB
53     CALLER_SAVE_SuB
54     CALLER_SAVE_Hp
55     CALLER_SAVE_HpLim
56     CALLER_SAVE_Liveness
57     CALLER_SAVE_Ret
58
59     MAGIC_CALL
60
61     CALLER_RESTORE_Base     /* has to be first! */
62
63     CALLER_RESTORE_StkO
64     CALLER_RESTORE_R1
65     CALLER_RESTORE_R2
66     CALLER_RESTORE_R3
67     CALLER_RESTORE_R4
68     CALLER_RESTORE_R5
69     CALLER_RESTORE_R6
70     CALLER_RESTORE_R7
71     CALLER_RESTORE_R8
72     CALLER_RESTORE_FltReg1
73     CALLER_RESTORE_FltReg2
74     CALLER_RESTORE_FltReg3
75     CALLER_RESTORE_FltReg4
76     CALLER_RESTORE_DblReg1
77     CALLER_RESTORE_DblReg2
78     CALLER_RESTORE_LngReg1
79     CALLER_RESTORE_LngReg2
80     CALLER_RESTORE_Tag
81     CALLER_RESTORE_SpA
82     CALLER_RESTORE_SuA
83     CALLER_RESTORE_SpB
84     CALLER_RESTORE_SuB
85     CALLER_RESTORE_Hp
86     CALLER_RESTORE_HpLim
87     CALLER_RESTORE_Liveness
88     CALLER_RESTORE_Ret
89     
90     /* These next two are restore-only */
91     CALLER_RESTORE_StdUpdRetVec
92     CALLER_RESTORE_StkStub
93
94     MAGIC_RETURN
95 }
96 # endif /* defined(CALLER_SAVES_SYSTEM) || defined(CALLER_SAVES_USER) */
97
98 # if defined(CALLER_SAVES_SYSTEM)
99 void
100 callWrapper_safe(STG_NO_ARGS)
101 {
102     MAGIC_CALL_SETUP
103
104     CALLER_SAVE_Base
105     CALLER_SAVE_StkO
106     CALLER_SAVE_SpA
107     CALLER_SAVE_SuA
108     CALLER_SAVE_SpB
109     CALLER_SAVE_SuB
110     CALLER_SAVE_Hp
111     CALLER_SAVE_HpLim
112     CALLER_SAVE_Liveness
113     CALLER_SAVE_Ret
114
115     MAGIC_CALL
116
117     CALLER_RESTORE_Base /* has to be first! */
118
119     CALLER_RESTORE_StkO
120     CALLER_RESTORE_SpA
121     CALLER_RESTORE_SuA
122     CALLER_RESTORE_SpB
123     CALLER_RESTORE_SuB
124     CALLER_RESTORE_Hp
125     CALLER_RESTORE_HpLim
126     CALLER_RESTORE_Liveness
127     CALLER_RESTORE_Ret
128     
129     /* These next two are restore-only */
130     CALLER_RESTORE_StdUpdRetVec
131     CALLER_RESTORE_StkStub
132
133     MAGIC_RETURN
134 }
135 # endif /* defined(CALLER_SAVES_SYSTEM) */
136
137 /* 
138 Nota Bene: 
139
140 Anyone changing the definition of @callWrapper_GC@ should make
141 appropriate changes in the compiler (absCSyn/PprAbsC.lhs :: pprCCall).
142
143 The reason is that \tr{_ccall_GC_} and \tr{_casm_GC_} generate code like this:
144 \begin{verbatim}
145    { R _ccall_result;
146      SaveAllStgRegs();
147      inCCallGC+=1;
148      _ccall_result = << do the call/asm>>;
149      inCCallGC-=1;
150      RestoreAllStgRegs();
151    }
152 \end{verbatim}
153
154 This avoids limiting _ccall_GC_ to 6 arguments and makes it possible
155 to implement _ccall_GC_.  (The local variable avoids the need for some
156 of the deeper magic hidden inside @GC_SETUP@, @GC_CCALL@ and
157 @GC_RETURN@.)
158
159 ADR */
160
161 EXTFUN(EnterNodeCode);
162
163 void *__temp_esp, *__temp_eax;
164
165 void PerformGC_wrapper PROTO((W_))          WRAPPER_NAME(PerformGC);
166 void PerformGC_wrapper(args)
167 W_ args;
168 {
169 #if i386_TARGET_ARCH
170     void *ret_addr;
171
172     WRAPPER_SETUP(PerformGC,ret_addr,args)
173 #else
174     WRAPPER_SETUP(PerformGC, ignore_me, ignore_me)
175 #endif
176     PerformGC(args);
177     WRAPPER_RETURN(0)
178 }
179
180 # ifdef CONCURRENT
181
182 void __DISCARD__ (STG_NO_ARGS) { /*nothing*/ }
183
184 void StackOverflow_wrapper PROTO((W_,W_))   WRAPPER_NAME(StackOverflow);
185 void StackOverflow_wrapper(args1,args2)
186 W_ args1, args2;
187 {
188 #if i386_TARGET_ARCH
189     void *ret_addr, *ignore_me;
190     WRAPPER_SETUP(StackOverflow,ret_addr,ignore_me)
191 #else
192     WRAPPER_SETUP(StackOverflow, ignore_me, ignore_me)
193 #endif
194     if(StackOverflow(args1,args2)) {
195         WRAPPER_RETURN(1)
196     }
197     WRAPPER_RETURN(0)
198 }
199
200 void Yield_wrapper PROTO((W_))              WRAPPER_NAME(Yield);
201 void Yield_wrapper(args)
202 W_ args;
203 {
204 #if i386_TARGET_ARCH
205     void *ret_addr, *ignore_me;
206     WRAPPER_SETUP(Yield, ret_addr, ignore_me)
207 #else
208     WRAPPER_SETUP(Yield, ignore_me, ignore_me)
209 #endif
210     Yield(args);
211     WRAPPER_RETURN(0)
212 }
213
214 #if defined(GRAN)
215 void PerformReschedule_wrapper PROTO((W_, W_))      WRAPPER_NAME(PerformReschedule);
216 void PerformReschedule_wrapper(liveness, always_reenter_node)
217   W_ liveness;
218   W_  always_reenter_node;
219 {
220 #if i386_TARGET_ARCH
221     void *ret_addr, *ignore_me;
222     WRAPPER_SETUP(PerformReschedule, ret_addr, ignore_me)
223 #else
224     WRAPPER_SETUP(PerformReschedule, ignore_me, ignore_me)
225 #endif
226     PerformReschedule(liveness, always_reenter_node);
227     WRAPPER_RETURN(0)
228 }
229
230 /* Similar wrappers for all GrAnSim functions. */
231 /* NB: These are normal functions, which don't call ReSchedule. So we just */
232 /* have to safe/restore the registers. */
233
234 void GranSimAllocate_wrapper PROTO((I_, P_, W_))  WRAPPER_NAME(GranSimAllocate);
235 void GranSimAllocate_wrapper(n, node, liveness)
236 I_ n;
237 P_ node;
238 W_ liveness;
239 {
240 #if i386_TARGET_ARCH
241     void *ret_addr, *ignore_me;
242     WRAPPER_SETUP(GranSimAllocate, ret_addr, ignore_me)
243 #else
244     WRAPPER_SETUP(GranSimAllocate, ignore_me, ignore_me)
245 #endif
246     GranSimAllocate(n, node, liveness);
247     WRAPPER_RETURN(0);
248 }
249
250 void GranSimUnallocate_wrapper PROTO((I_, P_, W_))  WRAPPER_NAME(GranSimUnallocate);
251 void GranSimUnallocate_wrapper(n, node, liveness)
252 I_ n;
253 P_ node;
254 W_ liveness;
255 {
256 #if i386_TARGET_ARCH
257     void *ret_addr, *ignore_me;
258     WRAPPER_SETUP(GranSimUnallocate, ret_addr, ignore_me)
259 #else
260     WRAPPER_SETUP(GranSimUnallocate, ignore_me, ignore_me)
261 #endif
262   GranSimUnallocate(n, node, liveness);
263   WRAPPER_RETURN(0);
264 }
265
266 void GranSimFetch_wrapper PROTO((P_))  WRAPPER_NAME(GranSimFetch);
267 void GranSimFetch_wrapper(node)
268 P_ node;
269 {
270 #if i386_TARGET_ARCH
271     void *ret_addr, *ignore_me;
272     WRAPPER_SETUP(GranSimFetch, ret_addr, ignore_me)
273 #else
274     WRAPPER_SETUP(GranSimFetch, ignore_me, ignore_me)
275 #endif
276     GranSimFetch(node);
277     WRAPPER_RETURN(0);
278 }
279
280 void GranSimExec_wrapper PROTO((W_, W_, W_, W_, W_))  WRAPPER_NAME(GranSimExec);
281 void GranSimExec_wrapper(arith,branch,load,store,floats)
282 W_ arith,branch,load,store,floats;
283 {
284 #if i386_TARGET_ARCH
285     void *ret_addr, *ignore_me;
286     WRAPPER_SETUP(GranSimExec, ret_addr, ignore_me)
287 #else
288     WRAPPER_SETUP(GranSimExec, ignore_me, ignore_me)
289 #endif
290     GranSimExec(arith,branch,load,store,floats);        
291     WRAPPER_RETURN(0);
292 }
293
294 # endif /* GRAN */
295
296 # endif /* CONCURRENT */
297
298 /* 
299  * In the threaded world, context switches may occur during one of these
300  * wrapped calls, and when we come back, our stack will have been trashed.
301  * If gcc, in all of its cleverness, tries to store any temporary values on
302  * the stack, we need to separate the restoration function.  See the sparc
303  * code for an example.
304  */
305
306 SEPARATE_WRAPPER_RESTORE
307
308 #endif /* defined(__STG_GCC_REGS__) */
309
310 /* We can perform a runtime check that we have used @_ccall_GC_@ when
311    appropriate using this flag. */
312 StgInt inCCallGC = 0;
313
314 void
315 checkInCCallGC()
316 {
317   if (inCCallGC == 0) {
318     fprintf(stderr, "Error: entering a closure from C without using _ccall_GC_\n");
319     EXIT(EXIT_FAILURE);
320   }
321 }
322 \end{code}
323