1 %************************************************************************
3 \section[CallWrap_C.lc]{``callWrapper'' stuff that can be written in C}
5 %************************************************************************
8 #define MAIN_REG_MAP /* These routines are all a bit special */
9 #define CALLWRAPPER_C /* Don't give standard declarations for wrappers */
13 %************************************************************************
15 \subsection[call-wrapping]{Routines to ``wrap'' special calls to C}
17 %************************************************************************
19 In most cases, this requires some assembly-language hacking (see the
20 discussion in @COptWraps.lh@.)
23 #if defined(__STG_GCC_REGS__)
25 # if defined(CALLER_SAVES_SYSTEM) || defined(CALLER_SAVES_USER)
27 callWrapper(STG_NO_ARGS)
59 CALLER_RESTORE_Base /* has to be first! */
70 CALLER_RESTORE_FltReg1
71 CALLER_RESTORE_FltReg2
72 CALLER_RESTORE_FltReg3
73 CALLER_RESTORE_FltReg4
74 CALLER_RESTORE_DblReg1
75 CALLER_RESTORE_DblReg2
83 CALLER_RESTORE_Liveness
86 /* These next two are restore-only */
87 CALLER_RESTORE_StdUpdRetVec
88 CALLER_RESTORE_StkStub
92 # endif /* defined(CALLER_SAVES_SYSTEM) || defined(CALLER_SAVES_USER) */
94 # if defined(CALLER_SAVES_SYSTEM)
96 callWrapper_safe(STG_NO_ARGS)
113 CALLER_RESTORE_Base /* has to be first! */
122 CALLER_RESTORE_Liveness
125 /* These next two are restore-only */
126 CALLER_RESTORE_StdUpdRetVec
127 CALLER_RESTORE_StkStub
131 # endif /* defined(CALLER_SAVES_SYSTEM) */
136 Anyone changing the definition of @callWrapper_GC@ should make
137 appropriate changes in the compiler (absCSyn/PprAbsC.lhs :: pprCCall).
139 The reason is that \tr{_ccall_GC_} and \tr{_casm_GC_} generate code like this:
144 _ccall_result = << do the call/asm>>;
150 This avoids limiting _ccall_GC_ to 6 arguments and makes it possible
151 to implement _ccall_GC_. (The local variable avoids the need for some
152 of the deeper magic hidden inside @GC_SETUP@, @GC_CCALL@ and
157 EXTFUN(EnterNodeCode);
159 void *__temp_esp, *__temp_eax;
161 void PerformGC_wrapper PROTO((W_)) WRAPPER_NAME(PerformGC);
162 void PerformGC_wrapper(args)
168 WRAPPER_SETUP(PerformGC,ret_addr,args)
170 WRAPPER_SETUP(PerformGC, ignore_me, ignore_me)
178 void __DISCARD__ (STG_NO_ARGS) { /*nothing*/ }
180 void StackOverflow_wrapper PROTO((W_,W_)) WRAPPER_NAME(StackOverflow);
181 void StackOverflow_wrapper(args1,args2)
185 void *ret_addr, *ignore_me;
186 WRAPPER_SETUP(StackOverflow,ret_addr,ignore_me)
188 WRAPPER_SETUP(StackOverflow, ignore_me, ignore_me)
190 if(StackOverflow(args1,args2)) {
196 void Yield_wrapper PROTO((W_)) WRAPPER_NAME(Yield);
197 void Yield_wrapper(args)
201 void *ret_addr, *ignore_me;
202 WRAPPER_SETUP(Yield, ret_addr, ignore_me)
204 WRAPPER_SETUP(Yield, ignore_me, ignore_me)
211 void PerformReschedule_wrapper PROTO((W_, W_)) WRAPPER_NAME(PerformReschedule);
212 void PerformReschedule_wrapper(liveness, always_reenter_node)
214 W_ always_reenter_node;
217 void *ret_addr, *ignore_me;
218 WRAPPER_SETUP(PerformReschedule, ret_addr, ignore_me)
220 WRAPPER_SETUP(PerformReschedule, ignore_me, ignore_me)
222 PerformReschedule(liveness, always_reenter_node);
226 /* Similar wrappers for all GrAnSim functions. */
227 /* NB: These are normal functions, which don't call ReSchedule. So we just */
228 /* have to safe/restore the registers. */
230 void GranSimAllocate_wrapper PROTO((I_, P_, W_)) WRAPPER_NAME(GranSimAllocate);
231 void GranSimAllocate_wrapper(n, node, liveness)
237 void *ret_addr, *ignore_me;
238 WRAPPER_SETUP(GranSimAllocate, ret_addr, ignore_me)
240 WRAPPER_SETUP(GranSimAllocate, ignore_me, ignore_me)
242 GranSimAllocate(n, node, liveness);
246 void GranSimUnallocate_wrapper PROTO((I_, P_, W_)) WRAPPER_NAME(GranSimUnallocate);
247 void GranSimUnallocate_wrapper(n, node, liveness)
253 void *ret_addr, *ignore_me;
254 WRAPPER_SETUP(GranSimUnallocate, ret_addr, ignore_me)
256 WRAPPER_SETUP(GranSimUnallocate, ignore_me, ignore_me)
258 GranSimUnallocate(n, node, liveness);
262 void GranSimFetch_wrapper PROTO((P_)) WRAPPER_NAME(GranSimFetch);
263 void GranSimFetch_wrapper(node)
267 void *ret_addr, *ignore_me;
268 WRAPPER_SETUP(GranSimFetch, ret_addr, ignore_me)
270 WRAPPER_SETUP(GranSimFetch, ignore_me, ignore_me)
276 void GranSimExec_wrapper PROTO((W_, W_, W_, W_, W_)) WRAPPER_NAME(GranSimExec);
277 void GranSimExec_wrapper(arith,branch,load,store,floats)
278 W_ arith,branch,load,store,floats;
281 void *ret_addr, *ignore_me;
282 WRAPPER_SETUP(GranSimExec, ret_addr, ignore_me)
284 WRAPPER_SETUP(GranSimExec, ignore_me, ignore_me)
286 GranSimExec(arith,branch,load,store,floats);
292 # endif /* CONCURRENT */
295 * In the threaded world, context switches may occur during one of these
296 * wrapped calls, and when we come back, our stack will have been trashed.
297 * If gcc, in all of its cleverness, tries to store any temporary values on
298 * the stack, we need to separate the restoration function. See the sparc
299 * code for an example.
302 SEPARATE_WRAPPER_RESTORE
304 #endif /* defined(__STG_GCC_REGS__) */
306 /* We can perform a runtime check that we have used @_ccall_GC_@ when
307 appropriate using this flag. */
308 StgInt inCCallGC = 0;
313 if (inCCallGC == 0) {
314 fprintf(stderr, "Error: entering a closure from C without using _ccall_GC_\n");