1/**
2 *
3 * 	Varargs for PYR/GNU CC
4 *
5 * WARNING -- WARNING -- DANGER
6 *
7 * The code in this file implements varargs for gcc on a pyr in
8 * a way that is compatible with code compiled by the Pyramid Technology
9 * C compiler.
10 * As such, it depends strongly on the Pyramid conventions for
11 * parameter passing.ct and independent implementation.
12 * These (somewhat bizarre) parameter-passing conventions are described
13 * in the ``OSx Operating System Porting Guide''.
14 *
15 * A quick summary is useful:
16 * 12 of the 48 register-windowed regs available for
17 * parameter passing.  Parameters of a function call that are eligible
18 * to be passed in registers are assigned registers from TR0/PR0 onwards;
19 * all other arguments are passed on the stack.
20 * Structure and union parameters are *never* passed in registers,
21 * even if they are small enough to fit.  They are always passed on
22 * the stack.
23 *
24 * Double-sized parameters cannot be passed in TR11, because
25 * TR12 is not used for passing parameters.  If, in the absence of this
26 * rule, a double-sized param would have been passed in TR11,
27 * that parameter is passed on the stack and no parameters are
28 * passed in TR11.
29 *
30 * It is only known to work for passing 32-bit integer quantities
31 * (ie chars, shorts, ints/enums, longs), doubles, or pointers.
32 * Passing structures on a Pyramid via varargs is a loser.
33 * Passing an object larger than 8 bytes on a pyramid via varargs may
34 * also be a loser.
35 *
36 */
37
38
39/*
40 *  pointer to next stack parameter in __va_buf[0]
41 *  pointer to next parameter register in __va_buf[1]
42 *  Count of registers seen at __va_buf[2]
43 *  saved pr0..pr11 in __va_buf[3..14]
44 *  # of calls to va_arg (debugging) at __va_buf[15]
45 */
46
47/* Define __gnuc_va_list.  */
48
49#ifndef __GNUC_VA_LIST
50#define __GNUC_VA_LIST
51
52typedef void *__voidptr;
53#if 1
54
55typedef struct __va_regs {
56      __voidptr __stackp,__regp,__count;
57      __voidptr __pr0,__pr1,__pr2,__pr3,__pr4,__pr5,__pr6,__pr7,__pr8,__pr9,__pr10,__pr11;
58  } __va_regs;
59
60typedef __va_regs __va_buf;
61#else
62
63/* __va_buf[0] = address of next arg passed on the stack
64   __va_buf[1] = address of next arg passed in a register
65   __va_buf[2] = register-# of next arg passed in a register
66 */
67typedef __voidptr(*__va_buf);
68
69#endif
70
71typedef __va_buf __gnuc_va_list;
72
73#endif /* not __GNUC_VA_LIST */
74
75/* If this is for internal libc use, don't define anything but
76   __gnuc_va_list.  */
77#if defined (_STDARG_H) || defined (_VARARGS_H)
78
79/* In GCC version 2, we want an ellipsis at the end of the declaration
80   of the argument list.  GCC version 1 can't parse it.  */
81
82#if __GNUC__ > 1
83#define __va_ellipsis ...
84#else
85#define __va_ellipsis
86#endif
87
88#define va_alist \
89  __va0,__va1,__va2,__va3,__va4,__va5,__va6,__va7,__va8,__va9,__va10,__va11, \
90 __builtin_va_alist
91
92/* The ... causes current_function_varargs to be set in cc1.  */
93#define va_dcl __voidptr va_alist; __va_ellipsis
94
95
96/* __asm ("rcsp %0" : "=r" ( _AP [0]));*/
97
98#define va_start(_AP)  \
99  _AP =  ((struct __va_regs) {						\
100   &(_AP.__pr0), (void*)&__builtin_va_alist, (void*)0,			\
101        __va0,__va1,__va2,__va3,__va4,__va5,				\
102	__va6,__va7,__va8,__va9,__va10,__va11})
103
104
105/* Avoid errors if compiling GCC v2 with GCC v1.  */
106#if __GNUC__ == 1
107#define __extension__
108#endif
109
110/* We cast to void * and then to TYPE * because this avoids
111   a warning about increasing the alignment requirement.  */
112#define va_arg(_AP, _MODE)	\
113__extension__								\
114(*({__voidptr *__ap = (__voidptr*)&_AP;					\
115  register int __size = sizeof (_MODE);					\
116  register int __onstack =						\
117	  (__size > 8 || ( (int)(__ap[2]) > 11) ||			\
118	    (__size==8 && (int)(__ap[2])==11));				\
119  register int* __param_addr =  ((int*)((__ap) [__onstack]));		\
120									\
121  ((void *)__ap[__onstack])+=__size;					\
122    if (__onstack==0 || (int)(__ap[2])==11)				\
123      __ap[2]+= (__size >> 2);						\
124  (( _MODE *) (void *) __param_addr);					\
125}))
126
127void va_end (__gnuc_va_list);		/* Defined in libgcc.a */
128#define va_end(_X)	((void)0)
129
130#endif /* defined (_STDARG_H) || defined (_VARARGS_H) */
131