[project @ 2001-02-14 10:33:05 by simonmar]
[ghc-hetmet.git] / ghc / includes / TailCalls.h
1 /* -----------------------------------------------------------------------------
2  * $Id: TailCalls.h,v 1.7 2001/02/14 10:33:05 simonmar Exp $
3  *
4  * (c) The GHC Team, 1998-1999
5  *
6  * Stuff for implementing proper tail jumps.
7  *
8  * ---------------------------------------------------------------------------*/
9
10 #ifndef TAILCALLS_H
11 #define TAILCALLS_H
12
13 /* -----------------------------------------------------------------------------
14    Unmangled tail-jumping: use the mini interpretter.
15    -------------------------------------------------------------------------- */
16
17 #ifdef USE_MINIINTERPRETER
18
19 #define JMP_(cont) return(stgCast(StgFunPtr,cont))
20 #define FB_
21 #define FE_
22
23 #else
24
25 /* -----------------------------------------------------------------------------
26    Tail calling on x86
27    -------------------------------------------------------------------------- */
28
29 #if i386_TARGET_ARCH
30
31 extern void __DISCARD__(void);
32
33 /* Note about discard: possibly there to fool GCC into clearing up
34    before we do the jump eg. if there are some arguments left on the C
35    stack that GCC hasn't popped yet.  Also possibly to fool any
36    optimisations (a function call often acts as a barrier).  Not sure
37    if any of this is necessary now -- SDM
38
39    Comment to above note: I don't think the __DISCARD__() in JMP_ is 
40    necessary.  Arguments should be popped from the C stack immediately
41    after returning from a function, as long as we pass -fno-defer-pop
42    to gcc.  Moreover, a goto to a first-class label acts as a barrier 
43    for optimisations in the same way a function call does. 
44    -= chak
45    */
46
47 /* The goto here seems to cause gcc -O2 to delete all the code after
48    it - including the FE_ marker and the epilogue code - exactly what
49    we want! -- SDM
50    */
51
52 #define JMP_(cont)                      \
53     {                                   \
54       void *target;                     \
55       __DISCARD__();                    \
56       target = (void *)(cont);          \
57       goto *target;                     \
58     }
59
60 #endif /* i386_TARGET_ARCH */
61
62 /* -----------------------------------------------------------------------------
63    Tail calling on Sparc
64    -------------------------------------------------------------------------- */
65
66 #ifdef sparc_TARGET_ARCH
67
68 #define JMP_(cont)      ((F_) (cont))()
69         /* Oh so happily, the above turns into a "call" instruction,
70            which, on a SPARC, is nothing but a "jmpl" with the
71            return address in %o7 [which we don't care about].
72         */
73
74 /* Don't need these for sparc mangling */
75 #define FB_
76 #define FE_
77
78 #endif /* sparc_TARGET_ARCH */
79
80 /* -----------------------------------------------------------------------------
81    Tail calling on Alpha
82    -------------------------------------------------------------------------- */
83
84 #ifdef alpha_TARGET_ARCH
85
86 register void *_procedure __asm__("$27");
87
88 #define JMP_(cont)                              \
89     do { _procedure = (void *)(cont);           \
90          goto *_procedure;                      \
91        } while(0)
92
93 /* Don't need these for alpha mangling */
94 #define FB_
95 #define FE_
96
97 #endif /* alpha_TARGET_ARCH */
98
99 /* -----------------------------------------------------------------------------
100    Tail calling on HP
101
102 Description of HP's weird procedure linkage, many thanks to Andy Bennet
103 <andy_bennett@hp.com>:
104
105 I've been digging a little further into the problem of how HP-UX does
106 dynamic procedure calls. My solution in the last e-mail inserting an extra
107 'if' statement into the JMP_ I think is probably the best general solution I
108 can come up with. There are still a few problems with it however: It wont
109 work, if JMP_ ever has to call anything in a shared library, if this is
110 likely to be required it'll need something more elaborate. It also wont work
111 with PA-RISC 2.0 wide mode (64-bit) which uses a different format PLT.
112
113 I had some feedback from someone in HP's compiler lab and the problem
114 relates to the linker on HP-UX, not gcc as I first suspected. The reason the
115 'hsc' executable works is most likely due to a change in 'ld's behaviour for
116 performance reasons between your revision and mine.
117
118 The major issue relating to this is shared libraries and how they are
119 implented under HP-UX. The whole point of the Procedure Label Table (PLT) is
120 to allow a function pointer to hold the address of the function and a
121 pointer to the library's global data lookup table (DLT) used by position
122 independent code (PIC). This makes the PLT absolutely essential for shared
123 library calls. HP has two linker introduced assembly functions for dealing
124 with dynamic calls, $$dyncall and $$dyncall_external. The former does a
125 check to see if the address is a PLT pointer and dereferences if necessary
126 or just calls the address otherwise; the latter skips the check and just
127 does the indirect jump no matter what.
128
129 Since $$dyncall_external runs faster due to its not having the test, the
130 linker nowadays prefers to generate calls to that, rather than $$dyncall. It
131 makes this decision based on the presence of any shared library. If it even
132 smells an sl's existence at link time, it rigs the runtime system to
133 generate PLT references for everything on the assumption that the result
134 will be slightly more efficient. This is what is crashing GHC since the
135 calls it is generating have no understanding of the procedure label proper.
136 The only way to get real addresses is to link everything archive, including
137 system libraries, at which point it assumes you probably are going to be
138 using calls similar to GHC's (its rigged for HP's +ESfic compiler option)
139 but uses $$dyncall if necessary to cope, just in case you aren't.
140
141    -------------------------------------------------------------------------- */
142
143 #ifdef hppa1_1_hp_hpux_TARGET
144
145 #define JMP_(cont)                              \
146     do { void *_procedure = (void *)(cont);     \
147          if (((int) _procedure) & 2)            \
148             _procedure = (void *)(*((int *) (_procedure - 2))); \
149          goto *_procedure;                      \
150        } while(0)
151
152 #endif /* hppa1_1_hp_hpux_TARGET */
153
154 /* -----------------------------------------------------------------------------
155   FUNBEGIN and FUNEND.
156
157   These are markers indicating the start and end of Real Code in a
158   function.  All instructions between the actual start and end of the
159   function and these markers is shredded by the mangler.
160   -------------------------------------------------------------------------- */
161
162 /*  The following __DISCARD__() has become necessary with gcc 2.96 on x86.
163  *  It prevents gcc from moving stack manipulation code from the function
164  *  body (aka the Real Code) into the function prologue, ie, from moving it
165  *  over the --- BEGIN --- marker.  It should be noted that (like some
166  *  other black magic in GHC's code), there is no essential reason why gcc
167  *  could not move some stack manipulation code across the __DISCARD__() -
168  *  it just doesn't choose to do it at the moment.
169  *  -= chak
170  */
171 #ifndef FB_
172 #define FB_    __asm__ volatile ("--- BEGIN ---"); __DISCARD__ ();
173 #endif
174
175 #ifndef FE_
176 #define FE_    __asm__ volatile ("--- END ---");
177 #endif
178
179 #endif /* !USE_MINIINTERPRETER */
180
181 #endif /* TAILCALLS_H */