[project @ 2005-03-27 13:41:13 by panne]
[ghc-hetmet.git] / ghc / includes / TailCalls.h
1 /* -----------------------------------------------------------------------------
2  *
3  * (c) The GHC Team, 1998-1999
4  *
5  * Stuff for implementing proper tail jumps.
6  *
7  * ---------------------------------------------------------------------------*/
8
9 #ifndef TAILCALLS_H
10 #define TAILCALLS_H
11
12 /* -----------------------------------------------------------------------------
13    Unmangled tail-jumping: use the mini interpretter.
14    -------------------------------------------------------------------------- */
15
16 #ifdef USE_MINIINTERPRETER
17
18 #define JMP_(cont) return((StgFunPtr)(cont))
19 #define FB_
20 #define FE_
21
22 #else
23
24 extern void __DISCARD__(void);
25
26 /* -----------------------------------------------------------------------------
27    Tail calling on x86
28    -------------------------------------------------------------------------- */
29
30 #if i386_HOST_ARCH
31
32 /* Note about discard: possibly there to fool GCC into clearing up
33    before we do the jump eg. if there are some arguments left on the C
34    stack that GCC hasn't popped yet.  Also possibly to fool any
35    optimisations (a function call often acts as a barrier).  Not sure
36    if any of this is necessary now -- SDM
37
38    Comment to above note: I don't think the __DISCARD__() in JMP_ is 
39    necessary.  Arguments should be popped from the C stack immediately
40    after returning from a function, as long as we pass -fno-defer-pop
41    to gcc.  Moreover, a goto to a first-class label acts as a barrier 
42    for optimisations in the same way a function call does. 
43    -= chak
44    */
45
46 /* The goto here seems to cause gcc -O2 to delete all the code after
47    it - including the FE_ marker and the epilogue code - exactly what
48    we want! -- SDM
49    */
50
51 #define JMP_(cont)                      \
52     {                                   \
53       void *__target;                   \
54       __DISCARD__();                    \
55       __target = (void *)(cont);        \
56       goto *__target;                   \
57     }
58
59 #endif /* i386_HOST_ARCH */
60
61 /* -----------------------------------------------------------------------------
62    Tail calling on x86_64
63    -------------------------------------------------------------------------- */
64
65 #if x86_64_HOST_ARCH
66
67 /*
68   NOTE about __DISCARD__():
69
70   On x86_64 this is necessary to work around bugs in the register
71   variable support in gcc.  Without the __DISCARD__() call, gcc will
72   silently throw away assignements to global register variables that
73   happen before the jump.
74
75   Here's the example:
76
77   extern void g(void);
78   static void f(void) {
79     R1 = g;
80     __DISCARD__()
81     goto *R1;
82   }
83
84   without the dummy function call, gcc throws away the assignment to R1
85   (gcc 3.4.3) gcc bug #20359.
86 */
87
88 #define JMP_(cont)                      \
89     {                                   \
90       void *__target;                   \
91       __DISCARD__();                    \
92       __target = (void *)(cont);        \
93       goto *__target;                   \
94     }
95
96 #endif /* x86_64_HOST_ARCH */
97
98 /* -----------------------------------------------------------------------------
99    Tail calling on Sparc
100    -------------------------------------------------------------------------- */
101
102 #ifdef sparc_HOST_ARCH
103
104 #define JMP_(cont)      ((F_) (cont))()
105         /* Oh so happily, the above turns into a "call" instruction,
106            which, on a SPARC, is nothing but a "jmpl" with the
107            return address in %o7 [which we don't care about].
108         */
109
110 /* Don't need these for sparc mangling */
111 #define FB_
112 #define FE_
113
114 #endif /* sparc_HOST_ARCH */
115
116 /* -----------------------------------------------------------------------------
117    Tail calling on Alpha
118    -------------------------------------------------------------------------- */
119
120 #ifdef alpha_HOST_ARCH
121
122 #if IN_STG_CODE
123 register void *_procedure __asm__("$27");
124 #endif
125
126 #define JMP_(cont)                              \
127     do { _procedure = (void *)(cont);           \
128          __DISCARD__();                         \
129          goto *_procedure;                      \
130        } while(0)
131
132 /* Don't need these for alpha mangling */
133 #define FB_
134 #define FE_
135
136 #endif /* alpha_HOST_ARCH */
137
138 /* -----------------------------------------------------------------------------
139    Tail calling on HP
140
141 Description of HP's weird procedure linkage, many thanks to Andy Bennet
142 <andy_bennett@hp.com>:
143
144 I've been digging a little further into the problem of how HP-UX does
145 dynamic procedure calls. My solution in the last e-mail inserting an extra
146 'if' statement into the JMP_ I think is probably the best general solution I
147 can come up with. There are still a few problems with it however: It wont
148 work, if JMP_ ever has to call anything in a shared library, if this is
149 likely to be required it'll need something more elaborate. It also wont work
150 with PA-RISC 2.0 wide mode (64-bit) which uses a different format PLT.
151
152 I had some feedback from someone in HP's compiler lab and the problem
153 relates to the linker on HP-UX, not gcc as I first suspected. The reason the
154 'hsc' executable works is most likely due to a change in 'ld's behaviour for
155 performance reasons between your revision and mine.
156
157 The major issue relating to this is shared libraries and how they are
158 implented under HP-UX. The whole point of the Procedure Label Table (PLT) is
159 to allow a function pointer to hold the address of the function and a
160 pointer to the library's global data lookup table (DLT) used by position
161 independent code (PIC). This makes the PLT absolutely essential for shared
162 library calls. HP has two linker introduced assembly functions for dealing
163 with dynamic calls, $$dyncall and $$dyncall_external. The former does a
164 check to see if the address is a PLT pointer and dereferences if necessary
165 or just calls the address otherwise; the latter skips the check and just
166 does the indirect jump no matter what.
167
168 Since $$dyncall_external runs faster due to its not having the test, the
169 linker nowadays prefers to generate calls to that, rather than $$dyncall. It
170 makes this decision based on the presence of any shared library. If it even
171 smells an sl's existence at link time, it rigs the runtime system to
172 generate PLT references for everything on the assumption that the result
173 will be slightly more efficient. This is what is crashing GHC since the
174 calls it is generating have no understanding of the procedure label proper.
175 The only way to get real addresses is to link everything archive, including
176 system libraries, at which point it assumes you probably are going to be
177 using calls similar to GHC's (its rigged for HP's +ESfic compiler option)
178 but uses $$dyncall if necessary to cope, just in case you aren't.
179
180    -------------------------------------------------------------------------- */
181
182 #ifdef hppa1_1_hp_hpux_TARGET
183
184 #define JMP_(cont)                              \
185     do { void *_procedure = (void *)(cont);     \
186          if (((int) _procedure) & 2)            \
187             _procedure = (void *)(*((int *) (_procedure - 2))); \
188          goto *_procedure;                      \
189        } while(0)
190
191 #endif /* hppa1_1_hp_hpux_TARGET */
192
193 /* -----------------------------------------------------------------------------
194    Tail calling on PowerPC
195    -------------------------------------------------------------------------- */
196
197 #ifdef powerpc_HOST_ARCH
198
199 #define JMP_(cont)                      \
200     {                                   \
201       void *target;                     \
202       target = (void *)(cont);          \
203       __DISCARD__();                    \
204       goto *target;                     \
205     }
206
207 /*
208         The __DISCARD__ is there because Apple's April 2002 Beta of GCC 3.1
209         sometimes generates incorrect code otherwise.
210         It tends to "forget" to update global register variables in the presence
211         of decrement/increment operators:
212         JMP_(*(--Sp)) is wrongly compiled as JMP_(Sp[-1]).
213         Calling __DISCARD__ in between works around this problem.
214 */
215
216 /*
217         I would _love_ to use the following instead,
218         but some versions of Apple's GCC fail to generate code for it
219         if it is called for a casted data pointer - which is exactly what
220         we are going to do...
221
222         #define JMP_(cont)      ((F_) (cont))()
223 */
224
225 #endif /* powerpc_HOST_ARCH */
226
227 #ifdef powerpc64_HOST_ARCH
228 #define JMP_(cont) ((F_) (cont))()
229 #endif
230
231 /* -----------------------------------------------------------------------------
232    Tail calling on IA64
233    -------------------------------------------------------------------------- */
234
235 #ifdef ia64_HOST_ARCH
236
237 /* The compiler can more intelligently decide how to do this.  We therefore
238  * implement it as a call and optimise to a jump at mangle time. */
239 #define JMP_(cont)      ((F_) (cont))(); __asm__ volatile ("--- TAILCALL ---");
240
241 /* Don't emit calls to __DISCARD__ as this causes hassles */
242 #define __DISCARD__()
243
244 #endif
245
246 /* -----------------------------------------------------------------------------
247   FUNBEGIN and FUNEND.
248
249   These are markers indicating the start and end of Real Code in a
250   function.  All instructions between the actual start and end of the
251   function and these markers is shredded by the mangler.
252   -------------------------------------------------------------------------- */
253
254 /*  The following __DISCARD__() has become necessary with gcc 2.96 on x86.
255  *  It prevents gcc from moving stack manipulation code from the function
256  *  body (aka the Real Code) into the function prologue, ie, from moving it
257  *  over the --- BEGIN --- marker.  It should be noted that (like some
258  *  other black magic in GHC's code), there is no essential reason why gcc
259  *  could not move some stack manipulation code across the __DISCARD__() -
260  *  it just doesn't choose to do it at the moment.
261  *  -= chak
262  */
263  
264 #ifndef FB_
265 #define FB_    __asm__ volatile ("--- BEGIN ---"); __DISCARD__ ();
266 #endif
267
268 #ifndef FE_
269 #define FE_    __asm__ volatile ("--- END ---");
270 #endif
271
272 #endif /* !USE_MINIINTERPRETER */
273
274 #endif /* TAILCALLS_H */