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