summaryrefslogtreecommitdiff
path: root/gnu/egcs/gcc/ginclude/va-i860.h
blob: 56d2c7fe1d3b7b2452cf56a40ab2f81b2c92b6a0 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
/* Note:  We must use the name __builtin_savregs.  GCC attaches special
   significance to that name.  In particular, regardless of where in a
   function __builtin_saveregs is called, GCC moves the call up to the
   very start of the function.  */


/* Define __gnuc_va_list.  */

#ifndef __GNUC_VA_LIST
#define __GNUC_VA_LIST

typedef union {
  float		__freg[8];
  double	__dreg[4];
} __f_regs;

typedef struct {
#if defined (__SVR4__) || defined (__svr4__) || defined (__alliant__) || defined (__PARAGON__)
  __f_regs __float_regs; long __ireg[12];
#else /* pre-SVR4 */
  long __ireg[12]; __f_regs __float_regs;
#endif
} __va_saved_regs;

typedef struct {
#if defined(__SVR4__) || defined(__svr4__) || defined(__alliant__) || defined (__PARAGON__)
  unsigned	__ireg_used;	/* How many int regs consumed 'til now? */
  unsigned	__freg_used;	/* How many flt regs consumed 'til now? */
  long		*__reg_base;	/* Address of where we stored the regs. */
  long *	__mem_ptr;	/* Address of memory overflow args area. */
#else /* pre-SVR4 */
  long		*__reg_base;	/* Address of where we stored the regs. */
  long *	__mem_ptr;	/* Address of memory overflow args area. */
  unsigned	__ireg_used;	/* How many int regs consumed 'til now? */
  unsigned	__freg_used;	/* How many flt regs consumed 'til now? */
#endif
} __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)

#if !defined(_STDARG_H)

/* varargs support */
#define va_alist __builtin_va_alist
#if defined (__PARAGON__)
#define va_dcl int va_alist;
#else	/* __PARAGON__ */
#define va_dcl
#endif	/* __PARAGON__ */
#define va_start(pvar) ((pvar) = * (__gnuc_va_list *) __builtin_saveregs ())

#else /* STDARG.H */

/* ANSI alternative.  */
/* Note that CUMULATIVE_ARGS elements are measured in bytes on the i860,
   so we divide by 4 to get # of registers.  */
#define va_start(pvar, firstarg) \
 ((pvar) = *(__gnuc_va_list *) __builtin_saveregs (),			\
  (pvar).__ireg_used = __builtin_args_info (0) / 4,		\
  (pvar).__freg_used = __builtin_args_info (1) / 4,		\
  (pvar).__mem_ptr = __builtin_next_arg (firstarg))

#endif /* _STDARG_H */

/* Values returned by __builtin_classify_type.  */

#ifndef va_end
enum {
  __no_type_class = -1,
  __void_type_class,
  __integer_type_class,
  __char_type_class,
  __enumeral_type_class,
  __boolean_type_class,
  __pointer_type_class,
  __reference_type_class,
  __offset_type_class,
  __real_type_class,
  __complex_type_class,
  __function_type_class,
  __method_type_class,
  __record_type_class,
  __union_type_class,
  __array_type_class,
  __string_type_class,
  __set_type_class,
  __file_type_class,
  __lang_type_class
};

void va_end (__gnuc_va_list);		/* Defined in libgcc.a */
#endif
#define va_end(__va)	((void) 0)

#define __NUM_PARM_FREGS	8
#define __NUM_PARM_IREGS	12

#define __savereg(__va) ((__va_saved_regs *) ((__va).__reg_base))

/* This macro works both for SVR4 and pre-SVR4 environments.  */

/* Note that parameters are always aligned at least to a word boundary
   (when passed) regardless of what GCC's __alignof__ operator says.  */

/* Make allowances here for adding 128-bit (long double) floats someday.  */

#if 0 /* What was this for? */
#ifndef __GNU_VA_LIST
#define __ireg_used ireg_used
#define __freg_used freg_used
#define __mem_ptr mem_ptr
#define __reg_base reg_base
#endif
#endif /* 0 */

/* Avoid errors if compiling GCC v2 with GCC v1.  */
#if __GNUC__ == 1
#define __extension__
#endif

#define va_arg(__va, __type)						\
__extension__								\
(* (__type *)								\
({									\
  register void *__rv;  /* result value */				\
  register unsigned __align;						\
  switch (__builtin_classify_type (* (__type *) 0))			\
    {									\
    case __real_type_class:						\
      switch (sizeof (__type))						\
	{								\
	  case sizeof (float):						\
	  case sizeof (double):						\
	    if ((__va).__freg_used < __NUM_PARM_FREGS - 1)		\
	      {								\
	        if (((__va).__freg_used & 1) != 0)			\
	          (__va).__freg_used++;	/* skip odd */			\
	        __rv = &__savereg((__va))->__float_regs.__freg[(__va).__freg_used];\
		(__va).__freg_used += 2;				\
	      }								\
	    else							\
	      {								\
	        if ((((unsigned) (__va).__mem_ptr) & (sizeof(double)-1)) != 0) \
	          (__va).__mem_ptr++;	/* skip odd */			\
	        __rv = (__va).__mem_ptr;				\
	        (__va).__mem_ptr += 2;					\
	      }								\
	    if (sizeof (__type) == sizeof (float))			\
	      {								\
	        *((float *) __rv) = *((double *) __rv);			\
		*(((long *) __rv) + 1) = 0xfff00001;			\
	      }								\
	    break;							\
	  default:							\
	    abort ();							\
	}								\
      break;								\
    case __void_type_class:						\
    case __integer_type_class:						\
    case __char_type_class:						\
    case __enumeral_type_class:						\
    case __boolean_type_class:						\
    case __pointer_type_class:						\
    case __reference_type_class:					\
    case __offset_type_class:						\
      if (sizeof (__type) <= 4)						\
	{								\
          __rv = ((__va).__ireg_used < __NUM_PARM_IREGS			\
	          ? (&__savereg((__va))->__ireg[(__va).__ireg_used++])	\
	          : (__va).__mem_ptr++);				\
	  break;							\
	}								\
      else if ((__va).__ireg_used + sizeof (__type) / 4 <= __NUM_PARM_IREGS) \
	{								\
	  __rv = &__savereg((__va))->__ireg[(__va).__ireg_used];	\
	  (__va).__ireg_used += sizeof (__type) / 4;			\
          break;							\
	}								\
      /* Fall through to fetch from memory.  */				\
    case __record_type_class:						\
    case __union_type_class:						\
      __align = (__alignof__ (__type) < sizeof (long)			\
		 ? sizeof (long)					\
		 : __alignof__ (__type));				\
      (__va).__mem_ptr							\
	= (long *)							\
	  ((((unsigned) (__va).__mem_ptr) + (__align-1)) & ~(__align-1)); \
      __rv = (__va).__mem_ptr;						\
      (__va).__mem_ptr							\
	+= ((sizeof (__type) + sizeof (long) - 1) / sizeof (long));	\
      break;								\
    case __complex_type_class:						\
    case __function_type_class:						\
    case __method_type_class:						\
    case __array_type_class:						\
    case __string_type_class:						\
    case __set_type_class:						\
    case __file_type_class:						\
    case __lang_type_class:						\
    case __no_type_class:						\
    default:								\
	abort ();							\
    }									\
  __rv;									\
}))

/* Copy __gnuc_va_list into another variable of this type.  */
#define __va_copy(dest, src) (dest) = (src)

#endif /* defined (_STDARG_H) || defined (_VARARGS_H) */