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. */ 19 typedef 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 33 typedef __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__ 46 typedef 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__ 102 extern 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 208 typedef 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