/* 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__)
  __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(__alliant__)
  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
#define va_dcl
#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 ())

#endif /* _STDARG_H */

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

/* Values returned by __builtin_classify_type.  */

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
};

#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;									\
}))

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

