1/* GNU C varargs support for the PowerPC with either the V.4 or Windows NT calling sequences */
2
3#ifndef _WIN32
4/* System V.4 support */
5/* Define __gnuc_va_list.  */
6
7#ifndef __GNUC_VA_LIST
8#define __GNUC_VA_LIST
9
10#ifndef _SYS_VA_LIST_H
11#define _SYS_VA_LIST_H		/* Solaris sys/va_list.h */
12
13/* Solaris decided to rename overflow_arg_area to input_arg_area,
14   so handle it via a macro.  */
15#define __va_overflow(AP) (AP)->overflow_arg_area
16
17/* Note that the names in this structure are in the user's namespace, but
18   that the V.4 abi explicitly states that these names should be used.  */
19typedef struct __va_list_tag {
20  unsigned char gpr;		/* index into the array of 8 GPRs stored in the
21				   register save area gpr=0 corresponds to r3,
22				   gpr=1 to r4, etc. */
23  unsigned char fpr;		/* index into the array of 8 FPRs stored in the
24				   register save area fpr=0 corresponds to f1,
25				   fpr=1 to f2, etc. */
26  char *overflow_arg_area;	/* location on stack that holds the next
27				   overflow argument */
28  char *reg_save_area;		/* where r3:r10 and f1:f8, if saved are stored */
29} __va_list[1], __gnuc_va_list[1];
30
31#else /* _SYS_VA_LIST */
32
33typedef __va_list __gnuc_va_list;
34#define __va_overflow(AP) (AP)->input_arg_area
35
36#endif /* not _SYS_VA_LIST */
37#endif /* not __GNUC_VA_LIST */
38
39/* If this is for internal libc use, don't define anything but
40   __gnuc_va_list.  */
41#if defined (_STDARG_H) || defined (_VARARGS_H)
42
43/* Register save area located below the frame pointer */
44#ifndef __VA_PPC_H__
45#define __VA_PPC_H__
46typedef struct {
47  long   __gp_save[8];		/* save area for GP registers */
48  double __fp_save[8];		/* save area for FP registers */
49} __va_regsave_t;
50
51/* Macros to access the register save area */
52/* We cast to void * and then to TYPE * because this avoids
53   a warning about increasing the alignment requirement.  */
54#define __VA_FP_REGSAVE(AP,OFS,TYPE)					\
55  ((TYPE *) (void *) (&(((__va_regsave_t *)				\
56			 (AP)->reg_save_area)->__fp_save[OFS])))
57
58#define __VA_GP_REGSAVE(AP,OFS,TYPE)					\
59  ((TYPE *) (void *) (&(((__va_regsave_t *)				\
60			 (AP)->reg_save_area)->__gp_save[OFS])))
61
62/* Common code for va_start for both varargs and stdarg.  We allow all
63   the work to be done by __builtin_saveregs.  It returns a pointer to
64   a va_list that was constructed on the stack; we must simply copy it
65   to the user's variable.  */
66
67#define __va_start_common(AP, FAKE) \
68  __builtin_memcpy ((AP), __builtin_saveregs (), sizeof(__gnuc_va_list))
69
70#ifdef _STDARG_H /* stdarg.h support */
71
72/* Calling __builtin_next_arg gives the proper error message if LASTARG is
73   not indeed the last argument.  */
74#define va_start(AP,LASTARG) \
75  (__builtin_next_arg (LASTARG), __va_start_common (AP, 0))
76
77#else /* varargs.h support */
78
79#define va_start(AP) __va_start_common (AP, 1)
80#define va_alist __va_1st_arg
81#define va_dcl register int va_alist; ...
82
83#endif /* _STDARG_H */
84
85#ifdef _SOFT_FLOAT
86#define __va_float_p(TYPE)	0
87#else
88#define __va_float_p(TYPE)	(__builtin_classify_type(*(TYPE *)0) == 8)
89#endif
90
91#define __va_aggregate_p(TYPE)	(__builtin_classify_type(*(TYPE *)0) >= 12)
92#define __va_size(TYPE)		((sizeof(TYPE) + sizeof (long) - 1) / sizeof (long))
93
94/* This symbol isn't defined.  It is used to flag type promotion violations
95   at link time.  We can only do this when optimizing.  Use __builtin_trap
96   instead of abort so that we don't require a prototype for abort.
97
98   __builtin_trap stuff is not available on the gcc-2.95 branch, so we just
99   avoid calling it for now.  */
100
101#ifdef __OPTIMIZE__
102extern void __va_arg_type_violation(void) __attribute__((__noreturn__));
103#else
104#define __va_arg_type_violation()
105#endif
106
107#define va_arg(AP,TYPE)							   \
108__extension__ (*({							   \
109  register TYPE *__ptr;							   \
110									   \
111  if (__va_float_p (TYPE) && sizeof (TYPE) < 16)			   \
112    {									   \
113      unsigned char __fpr = (AP)->fpr;					   \
114      if (__fpr < 8)							   \
115	{								   \
116	  __ptr = __VA_FP_REGSAVE (AP, __fpr, TYPE);			   \
117	  (AP)->fpr = __fpr + 1;					   \
118	}								   \
119      else if (sizeof (TYPE) == 8)					   \
120	{								   \
121	  unsigned long __addr = (unsigned long) (__va_overflow (AP));	   \
122	  __ptr = (TYPE *)((__addr + 7) & -8);				   \
123	  __va_overflow (AP) = (char *)(__ptr + 1);			   \
124	}								   \
125      else								   \
126	{								   \
127	  /* float is promoted to double.  */				   \
128	  __va_arg_type_violation ();					   \
129	}								   \
130    }									   \
131									   \
132  /* Aggregates and long doubles are passed by reference.  */		   \
133  else if (__va_aggregate_p (TYPE) || __va_float_p (TYPE))		   \
134    {									   \
135      unsigned char __gpr = (AP)->gpr;					   \
136      if (__gpr < 8)							   \
137	{								   \
138	  __ptr = * __VA_GP_REGSAVE (AP, __gpr, TYPE *);		   \
139	  (AP)->gpr = __gpr + 1;					   \
140	}								   \
141      else								   \
142	{								   \
143	  TYPE **__pptr = (TYPE **) (__va_overflow (AP));		   \
144	  __ptr = * __pptr;						   \
145	  __va_overflow (AP) = (char *) (__pptr + 1);			   \
146	}								   \
147    }									   \
148									   \
149  /* Only integrals remaining.  */					   \
150  else									   \
151    {									   \
152      /* longlong is aligned.  */					   \
153      if (sizeof (TYPE) == 8)						   \
154	{								   \
155	  unsigned char __gpr = (AP)->gpr;				   \
156	  if (__gpr < 7)						   \
157	    {								   \
158	      __gpr += __gpr & 1;					   \
159	      __ptr = __VA_GP_REGSAVE (AP, __gpr, TYPE);		   \
160	      (AP)->gpr = __gpr + 2;					   \
161	    }								   \
162	  else								   \
163	    {								   \
164	      unsigned long __addr = (unsigned long) (__va_overflow (AP)); \
165	      __ptr = (TYPE *)((__addr + 7) & -8);			   \
166	      (AP)->gpr = 8;						   \
167	      __va_overflow (AP) = (char *)(__ptr + 1);			   \
168	    }								   \
169	}								   \
170      else if (sizeof (TYPE) == 4)					   \
171	{								   \
172	  unsigned char __gpr = (AP)->gpr;				   \
173	  if (__gpr < 8)						   \
174	    {								   \
175	      __ptr = __VA_GP_REGSAVE (AP, __gpr, TYPE);		   \
176	      (AP)->gpr = __gpr + 1;					   \
177	    }								   \
178	  else								   \
179	    {								   \
180	      __ptr = (TYPE *) __va_overflow (AP);			   \
181	      __va_overflow (AP) = (char *)(__ptr + 1);			   \
182	    }								   \
183	}								   \
184      else								   \
185	{								   \
186	  /* Everything else was promoted to int.  */			   \
187	  __va_arg_type_violation ();					   \
188	}								   \
189    }									   \
190  __ptr;								   \
191}))
192
193#define va_end(AP)	((void)0)
194
195/* Copy __gnuc_va_list into another variable of this type.  */
196#define __va_copy(dest, src) *(dest) = *(src)
197
198#endif /* __VA_PPC_H__ */
199#endif /* defined (_STDARG_H) || defined (_VARARGS_H) */
200
201
202#else
203/* Windows NT */
204/* Define __gnuc_va_list.  */
205
206#ifndef __GNUC_VA_LIST
207#define __GNUC_VA_LIST
208typedef char *__gnuc_va_list;
209#endif /* not __GNUC_VA_LIST */
210
211/* If this is for internal libc use, don't define anything but
212   __gnuc_va_list.  */
213#if defined (_STDARG_H) || defined (_VARARGS_H)
214
215#define __va_start_common(AP, LASTARG, FAKE)				\
216  ((__builtin_saveregs ()), ((AP) = ((char *) &LASTARG) + __va_rounded_size (AP)), 0)
217
218#ifdef _STDARG_H /* stdarg.h support */
219
220/* Calling __builtin_next_arg gives the proper error message if LASTARG is
221   not indeed the last argument.  */
222#define va_start(AP,LASTARG)						\
223  (__builtin_saveregs (),						\
224   (AP) = __builtin_next_arg (LASTARG),					\
225   0)
226
227#else /* varargs.h support */
228
229#define va_start(AP)							\
230  (__builtin_saveregs (),						\
231   (AP) = __builtin_next_arg (__va_1st_arg) - sizeof (int),		\
232   0)
233
234#define va_alist __va_1st_arg
235#define va_dcl register int __va_1st_arg; ...
236
237#endif /* _STDARG_H */
238
239#define __va_rounded_size(TYPE) ((sizeof (TYPE) + 3) & ~3)
240#define __va_align(AP, TYPE)						\
241     ((((unsigned long)(AP)) + ((sizeof (TYPE) >= 8) ? 7 : 3))		\
242      & ~((sizeof (TYPE) >= 8) ? 7 : 3))
243
244#define va_arg(AP,TYPE)							\
245( *(TYPE *)((AP = (char *) (__va_align(AP, TYPE)			\
246			    + __va_rounded_size(TYPE)))			\
247	    - __va_rounded_size(TYPE)))
248
249#define va_end(AP)	((void)0)
250
251/* Copy __gnuc_va_list into another variable of this type.  */
252#define __va_copy(dest, src) (dest) = (src)
253
254#endif /* defined (_STDARG_H) || defined (_VARARGS_H) */
255#endif /* Windows NT */
256