1/* The ! __SH3E_VARG case is similar to the default gvarargs.h .  */
2
3#if (defined (__SH3E__) || defined (__SH4_SINGLE__) || defined (__SH4__) || defined (__SH4_SINGLE_ONLY__)) && ! defined (__HITACHI__)
4#define __SH3E_VARG
5#endif
6
7/* Define __gnuc_va_list.  */
8
9#ifndef __GNUC_VA_LIST
10#define __GNUC_VA_LIST
11
12#ifdef __SH3E_VARG
13
14typedef long __va_greg;
15typedef float __va_freg;
16
17typedef struct {
18  __va_greg * __va_next_o;		/* next available register */
19  __va_greg * __va_next_o_limit;	/* past last available register */
20  __va_freg * __va_next_fp;		/* next available fp register */
21  __va_freg * __va_next_fp_limit;	/* last available fp register */
22  __va_greg * __va_next_stack;		/* next extended word on stack */
23} __gnuc_va_list;
24
25#else /* ! SH3E */
26
27typedef void *__gnuc_va_list;
28
29#endif /* ! SH3E */
30
31#endif /* __GNUC_VA_LIST */
32
33/* If this is for internal libc use, don't define anything but
34   __gnuc_va_list.  */
35#if defined (_STDARG_H) || defined (_VARARGS_H)
36
37#ifdef _STDARG_H
38
39#ifdef __SH3E_VARG
40
41#define va_start(AP, LASTARG) \
42__extension__ \
43  ({ \
44     (AP).__va_next_fp = (__va_freg *) __builtin_saveregs (); \
45     (AP).__va_next_fp_limit = ((AP).__va_next_fp + \
46			      (__builtin_args_info (1) < 8 ? 8 - __builtin_args_info (1) : 0)); \
47     (AP).__va_next_o = (__va_greg *) (AP).__va_next_fp_limit; \
48     (AP).__va_next_o_limit = ((AP).__va_next_o + \
49			     (__builtin_args_info (0) < 4 ? 4 - __builtin_args_info (0) : 0)); \
50     (AP).__va_next_stack = (__va_greg *) __builtin_next_arg (LASTARG); \
51  })
52
53#else /* ! SH3E */
54
55#define va_start(AP, LASTARG) 						\
56 ((AP) = ((__gnuc_va_list) __builtin_next_arg (LASTARG)))
57
58#endif /* ! SH3E */
59
60#else /* _VARARGS_H */
61
62#define va_alist  __builtin_va_alist
63#define va_dcl    int __builtin_va_alist;...
64
65#ifdef __SH3E_VARG
66
67#define va_start(AP) \
68__extension__ \
69  ({ \
70     (AP).__va_next_fp = (__va_freg *) __builtin_saveregs (); \
71     (AP).__va_next_fp_limit = ((AP).__va_next_fp + \
72			      (__builtin_args_info (1) < 8 ? 8 - __builtin_args_info (1) : 0)); \
73     (AP).__va_next_o = (__va_greg *) (AP).__va_next_fp_limit; \
74     (AP).__va_next_o_limit = ((AP).__va_next_o + \
75			     (__builtin_args_info (0) < 4 ? 4 - __builtin_args_info (0) : 0)); \
76     (AP).__va_next_stack \
77       = ((__va_greg *) __builtin_next_arg (__builtin_va_alist) \
78	  - (__builtin_args_info (0) >= 4 || __builtin_args_info (1) >= 8 \
79	     ? 1 : 0)); \
80  })
81
82#else /* ! SH3E */
83
84#define va_start(AP)  ((AP) = (char *) &__builtin_va_alist)
85
86#endif /* ! SH3E */
87
88#endif /* _STDARG */
89
90#ifndef va_end
91void va_end (__gnuc_va_list);		/* Defined in libgcc.a */
92
93/* Values returned by __builtin_classify_type.  */
94
95enum __va_type_classes {
96  __no_type_class = -1,
97  __void_type_class,
98  __integer_type_class,
99  __char_type_class,
100  __enumeral_type_class,
101  __boolean_type_class,
102  __pointer_type_class,
103  __reference_type_class,
104  __offset_type_class,
105  __real_type_class,
106  __complex_type_class,
107  __function_type_class,
108  __method_type_class,
109  __record_type_class,
110  __union_type_class,
111  __array_type_class,
112  __string_type_class,
113  __set_type_class,
114  __file_type_class,
115  __lang_type_class
116};
117
118#endif
119#define va_end(pvar)	((void)0)
120
121#ifdef __LITTLE_ENDIAN__
122#define __LITTLE_ENDIAN_P 1
123#else
124#define __LITTLE_ENDIAN_P 0
125#endif
126
127#define __SCALAR_TYPE(TYPE)					\
128  ((TYPE) == __integer_type_class				\
129   || (TYPE) == __char_type_class				\
130   || (TYPE) == __enumeral_type_class)
131
132/* RECORD_TYPE args passed using the C calling convention are
133   passed by invisible reference.  ??? RECORD_TYPE args passed
134   in the stack are made to be word-aligned; for an aggregate that is
135   not word-aligned, we advance the pointer to the first non-reg slot.  */
136
137  /* When this is a smaller-than-int integer, using
138     auto-increment in the promoted (SImode) is fastest;
139     however, there is no way to express that is C.  Therefore,
140     we use an asm.
141     We want the MEM_IN_STRUCT_P bit set in the emitted RTL, therefore we
142     use unions even when it would otherwise be unnecessary.  */
143
144/* gcc has an extension that allows to use a casted lvalue as an lvalue,
145   But it doesn't work in C++ with -pedantic - even in the presence of
146   __extension__ .  We work around this problem by using a reference type.  */
147#ifdef __cplusplus
148#define __VA_REF &
149#else
150#define __VA_REF
151#endif
152
153#define __va_arg_sh1(AP, TYPE) __extension__ 				\
154({(sizeof (TYPE) == 1							\
155   ? ({union {TYPE t; char c;} __t;					\
156       __asm(""								\
157	     : "=r" (__t.c)						\
158	     : "0" ((((union { int i, j; } *__VA_REF) (AP))++)->i));	\
159       __t.t;})								\
160   : sizeof (TYPE) == 2							\
161   ? ({union {TYPE t; short s;} __t;					\
162       __asm(""								\
163	     : "=r" (__t.s)						\
164	     : "0" ((((union { int i, j; } *__VA_REF) (AP))++)->i));	\
165       __t.t;})								\
166   : sizeof (TYPE) >= 4 || __LITTLE_ENDIAN_P				\
167   ? (((union { TYPE t; int i;} *__VA_REF) (AP))++)->t			\
168   : ((union {TYPE t;TYPE u;}*) ((char *)++(int *__VA_REF)(AP) - sizeof (TYPE)))->t);})
169
170#ifdef __SH3E_VARG
171
172#define __PASS_AS_FLOAT(TYPE_CLASS,SIZE) \
173  (TYPE_CLASS == __real_type_class && SIZE == 4)
174
175#define __TARGET_SH4_P 0
176
177#if defined(__SH4__) || defined(__SH4_SINGLE__)
178#undef __PASS_AS_FLOAT
179#define __PASS_AS_FLOAT(TYPE_CLASS,SIZE) \
180  (TYPE_CLASS == __real_type_class && SIZE <= 8 \
181   || TYPE_CLASS == __complex_type_class && SIZE <= 16)
182#undef __TARGET_SH4_P
183#define __TARGET_SH4_P 1
184#endif
185
186#define va_arg(pvar,TYPE)					\
187__extension__							\
188({int __type = __builtin_classify_type (* (TYPE *) 0);		\
189  void * __result_p;						\
190  if (__PASS_AS_FLOAT (__type, sizeof(TYPE)))			\
191    {								\
192      if ((pvar).__va_next_fp < (pvar).__va_next_fp_limit)	\
193	{							\
194	  if (((__type == __real_type_class && sizeof (TYPE) > 4)\
195	       || sizeof (TYPE) > 8)				\
196	      && (((int) (pvar).__va_next_fp ^ (int) (pvar).__va_next_fp_limit)\
197		  & 4))						\
198	    (pvar).__va_next_fp++;				\
199	  __result_p = &(pvar).__va_next_fp;			\
200	}							\
201      else							\
202	__result_p = &(pvar).__va_next_stack;			\
203    }								\
204  else								\
205    {								\
206      if ((pvar).__va_next_o + ((sizeof (TYPE) + 3) / 4)	\
207	  <= (pvar).__va_next_o_limit) 				\
208	__result_p = &(pvar).__va_next_o;			\
209      else							\
210	{							\
211	  if (sizeof (TYPE) > 4)				\
212	   if (! __TARGET_SH4_P)				\
213	    (pvar).__va_next_o = (pvar).__va_next_o_limit;	\
214								\
215	  __result_p = &(pvar).__va_next_stack;			\
216	}							\
217    } 								\
218  __va_arg_sh1(*(void **)__result_p, TYPE);})
219
220#else /* ! SH3E */
221
222#define va_arg(AP, TYPE) __va_arg_sh1((AP), TYPE)
223
224#endif /* SH3E */
225
226/* Copy __gnuc_va_list into another variable of this type.  */
227#define __va_copy(dest, src) ((dest) = (src))
228
229#endif /* defined (_STDARG_H) || defined (_VARARGS_H) */
230