/* -----------------------------------------------------------------------------
- * $Id: TailCalls.h,v 1.7 2001/02/14 10:33:05 simonmar Exp $
+ * $Id: TailCalls.h,v 1.15 2003/10/12 13:24:52 igloo Exp $
*
* (c) The GHC Team, 1998-1999
*
#else
+extern void __DISCARD__(void);
+
/* -----------------------------------------------------------------------------
Tail calling on x86
-------------------------------------------------------------------------- */
#if i386_TARGET_ARCH
-extern void __DISCARD__(void);
-
/* Note about discard: possibly there to fool GCC into clearing up
before we do the jump eg. if there are some arguments left on the C
stack that GCC hasn't popped yet. Also possibly to fool any
#define JMP_(cont) \
{ \
- void *target; \
+ void *__target; \
__DISCARD__(); \
- target = (void *)(cont); \
- goto *target; \
+ __target = (void *)(cont); \
+ goto *__target; \
}
#endif /* i386_TARGET_ARCH */
/* -----------------------------------------------------------------------------
+ Tail calling on x86_64
+ -------------------------------------------------------------------------- */
+
+#if x86_64_TARGET_ARCH
+
+#define JMP_(cont) \
+ { \
+ void *__target; \
+ __target = (void *)(cont); \
+ goto *__target; \
+ }
+
+#endif /* x86_64_TARGET_ARCH */
+
+/* -----------------------------------------------------------------------------
Tail calling on Sparc
-------------------------------------------------------------------------- */
#ifdef alpha_TARGET_ARCH
+#if IN_STG_CODE
register void *_procedure __asm__("$27");
+#endif
-#define JMP_(cont) \
- do { _procedure = (void *)(cont); \
- goto *_procedure; \
+#define JMP_(cont) \
+ do { _procedure = (void *)(cont); \
+ __DISCARD__(); \
+ goto *_procedure; \
} while(0)
/* Don't need these for alpha mangling */
#endif /* hppa1_1_hp_hpux_TARGET */
/* -----------------------------------------------------------------------------
+ Tail calling on PowerPC
+ -------------------------------------------------------------------------- */
+
+#ifdef powerpc_TARGET_ARCH
+
+#define JMP_(cont) \
+ { \
+ void *target; \
+ target = (void *)(cont); \
+ __DISCARD__(); \
+ goto *target; \
+ }
+
+/*
+ The __DISCARD__ is there because Apple's April 2002 Beta of GCC 3.1
+ sometimes generates incorrect code otherwise.
+ It tends to "forget" to update global register variables in the presence
+ of decrement/increment operators:
+ JMP_(*(--Sp)) is wrongly compiled as JMP_(Sp[-1]).
+ Calling __DISCARD__ in between works around this problem.
+*/
+
+/*
+ I would _love_ to use the following instead,
+ but some versions of Apple's GCC fail to generate code for it
+ if it is called for a casted data pointer - which is exactly what
+ we are going to do...
+
+ #define JMP_(cont) ((F_) (cont))()
+*/
+
+#endif /* powerpc_TARGET_ARCH */
+
+/* -----------------------------------------------------------------------------
+ Tail calling on IA64
+ -------------------------------------------------------------------------- */
+
+#ifdef ia64_TARGET_ARCH
+
+/* The compiler can more intelligently decide how to do this. We therefore
+ * implement it as a call and optimise to a jump at mangle time. */
+#define JMP_(cont) ((F_) (cont))(); __asm__ volatile ("--- TAILCALL ---");
+
+/* Don't emit calls to __DISCARD__ as this causes hassles */
+#define __DISCARD__()
+
+#endif
+
+/* -----------------------------------------------------------------------------
FUNBEGIN and FUNEND.
These are markers indicating the start and end of Real Code in a
* it just doesn't choose to do it at the moment.
* -= chak
*/
+
#ifndef FB_
#define FB_ __asm__ volatile ("--- BEGIN ---"); __DISCARD__ ();
#endif