mirror of
https://github.com/pmret/gcc-papermario.git
synced 2024-11-09 20:32:32 +01:00
131 lines
4.0 KiB
C
131 lines
4.0 KiB
C
|
/**
|
|||
|
*
|
|||
|
* Varargs for PYR/GNU CC
|
|||
|
*
|
|||
|
* WARNING -- WARNING -- DANGER
|
|||
|
*
|
|||
|
* The code in this file implements varargs for gcc on a pyr in
|
|||
|
* a way that is compatible with code compiled by the Pyramid Technology
|
|||
|
* C compiler.
|
|||
|
* As such, it depends strongly on the Pyramid conventions for
|
|||
|
* parameter passing.ct and independent implementation.
|
|||
|
* These (somewhat bizarre) parameter-passing conventions are described
|
|||
|
* in the ``OSx Operating System Porting Guide''.
|
|||
|
*
|
|||
|
* A quick summary is useful:
|
|||
|
* 12 of the 48 register-windowed regs available for
|
|||
|
* parameter passing. Parameters of a function call that are eligible
|
|||
|
* to be passed in registers are assigned registers from TR0/PR0 onwards;
|
|||
|
* all other arguments are passed on the stack.
|
|||
|
* Structure and union parameters are *never* passed in registers,
|
|||
|
* even if they are small enough to fit. They are always passed on
|
|||
|
* the stack.
|
|||
|
*
|
|||
|
* Double-sized parameters cannot be passed in TR11, because
|
|||
|
* TR12 is not used for passing parameters. If, in the absence of this
|
|||
|
* rule, a double-sized param would have been passed in TR11,
|
|||
|
* that parameter is passed on the stack and no parameters are
|
|||
|
* passed in TR11.
|
|||
|
*
|
|||
|
* It is only known to work for passing 32-bit integer quantities
|
|||
|
* (ie chars, shorts, ints/enums, longs), doubles, or pointers.
|
|||
|
* Passing structures on a Pyramid via varargs is a loser.
|
|||
|
* Passing an object larger than 8 bytes on a pyramid via varargs may
|
|||
|
* also be a loser.
|
|||
|
*
|
|||
|
*/
|
|||
|
|
|||
|
|
|||
|
/*
|
|||
|
* pointer to next stack parameter in __va_buf[0]
|
|||
|
* pointer to next parameter register in __va_buf[1]
|
|||
|
* Count of registers seen at __va_buf[2]
|
|||
|
* saved pr0..pr11 in __va_buf[3..14]
|
|||
|
* # of calls to va_arg (debugging) at __va_buf[15]
|
|||
|
*/
|
|||
|
|
|||
|
/* Define __gnuc_va_list. */
|
|||
|
|
|||
|
#ifndef __GNUC_VA_LIST
|
|||
|
#define __GNUC_VA_LIST
|
|||
|
|
|||
|
typedef void *__voidptr;
|
|||
|
#if 1
|
|||
|
|
|||
|
typedef struct __va_regs {
|
|||
|
__voidptr __stackp,__regp,__count;
|
|||
|
__voidptr __pr0,__pr1,__pr2,__pr3,__pr4,__pr5,__pr6,__pr7,__pr8,__pr9,__pr10,__pr11;
|
|||
|
} __va_regs;
|
|||
|
|
|||
|
typedef __va_regs __va_buf;
|
|||
|
#else
|
|||
|
|
|||
|
/* __va_buf[0] = address of next arg passed on the stack
|
|||
|
__va_buf[1] = address of next arg passed in a register
|
|||
|
__va_buf[2] = register-# of next arg passed in a register
|
|||
|
*/
|
|||
|
typedef __voidptr(*__va_buf);
|
|||
|
|
|||
|
#endif
|
|||
|
|
|||
|
typedef __va_buf __gnuc_va_list;
|
|||
|
|
|||
|
#endif /* not __GNUC_VA_LIST */
|
|||
|
|
|||
|
/* If this is for internal libc use, don't define anything but
|
|||
|
__gnuc_va_list. */
|
|||
|
#if defined (_STDARG_H) || defined (_VARARGS_H)
|
|||
|
|
|||
|
/* In GCC version 2, we want an ellipsis at the end of the declaration
|
|||
|
of the argument list. GCC version 1 can't parse it. */
|
|||
|
|
|||
|
#if __GNUC__ > 1
|
|||
|
#define __va_ellipsis ...
|
|||
|
#else
|
|||
|
#define __va_ellipsis
|
|||
|
#endif
|
|||
|
|
|||
|
#define va_alist \
|
|||
|
__va0,__va1,__va2,__va3,__va4,__va5,__va6,__va7,__va8,__va9,__va10,__va11, \
|
|||
|
__builtin_va_alist
|
|||
|
|
|||
|
/* The ... causes current_function_varargs to be set in cc1. */
|
|||
|
#define va_dcl __voidptr va_alist; __va_ellipsis
|
|||
|
|
|||
|
|
|||
|
/* __asm ("rcsp %0" : "=r" ( _AP [0]));*/
|
|||
|
|
|||
|
#define va_start(_AP) \
|
|||
|
_AP = ((struct __va_regs) { \
|
|||
|
&(_AP.__pr0), (void*)&__builtin_va_alist, (void*)0, \
|
|||
|
__va0,__va1,__va2,__va3,__va4,__va5, \
|
|||
|
__va6,__va7,__va8,__va9,__va10,__va11})
|
|||
|
|
|||
|
|
|||
|
/* Avoid errors if compiling GCC v2 with GCC v1. */
|
|||
|
#if __GNUC__ == 1
|
|||
|
#define __extension__
|
|||
|
#endif
|
|||
|
|
|||
|
/* We cast to void * and then to TYPE * because this avoids
|
|||
|
a warning about increasing the alignment requirement. */
|
|||
|
#define va_arg(_AP, _MODE) \
|
|||
|
__extension__ \
|
|||
|
(*({__voidptr *__ap = (__voidptr*)&_AP; \
|
|||
|
register int __size = sizeof (_MODE); \
|
|||
|
register int __onstack = \
|
|||
|
(__size > 8 || ( (int)(__ap[2]) > 11) || \
|
|||
|
(__size==8 && (int)(__ap[2])==11)); \
|
|||
|
register int* __param_addr = ((int*)((__ap) [__onstack])); \
|
|||
|
\
|
|||
|
((void *)__ap[__onstack])+=__size; \
|
|||
|
if (__onstack==0 || (int)(__ap[2])==11) \
|
|||
|
__ap[2]+= (__size >> 2); \
|
|||
|
(( _MODE *) (void *) __param_addr); \
|
|||
|
}))
|
|||
|
|
|||
|
void va_end (__gnuc_va_list); /* Defined in libgcc.a */
|
|||
|
#define va_end(_X) ((void)0)
|
|||
|
|
|||
|
#endif /* defined (_STDARG_H) || defined (_VARARGS_H) */
|