1 /** 2 * D header file for C99. 3 * 4 * Copyright: Public Domain 5 * License: Public Domain 6 * Authors: Hauke Duden, Walter Bright 7 * Standards: ISO/IEC 9899:1999 (E) 8 */ 9 module tango.stdc.stdarg; 10 11 12 debug(PRINTF) import tango.stdc.stdio: printf; 13 14 public import core.stdc.stdarg; 15 16 /+ 17 version( GNU ) 18 { 19 public import std.c.stdarg; 20 } 21 else version( LDC ) 22 { 23 public import ldc.cstdarg; 24 } 25 else 26 { 27 version (X86) 28 { 29 /********************* 30 * The argument pointer type. 31 */ 32 alias void* va_list; 33 34 /********** 35 * Initialize ap. 36 * For 32 bit code, parmn should be the last named parameter. 37 * For 64 bit code, parmn should be __va_argsave. 38 */ 39 void va_start(T)(out va_list ap, ref T parmn) 40 { 41 ap = cast(va_list)(cast(void*)&parmn + ((T.sizeof + int.sizeof - 1) & ~(int.sizeof - 1))); 42 } 43 44 /************ 45 * Retrieve and return the next value that is type T. 46 * Should use the other va_arg instead, as this won't work for 64 bit code. 47 */ 48 T va_arg(T)(ref va_list ap) 49 { 50 T arg = *cast(T*)ap; 51 ap = cast(va_list)(cast(void*)ap + ((T.sizeof + int.sizeof - 1) & ~(int.sizeof - 1))); 52 return arg; 53 } 54 55 /************ 56 * Retrieve and return the next value that is type T. 57 * This is the preferred version. 58 */ 59 void va_arg(T)(ref va_list ap, ref T parmn) 60 { 61 parmn = *cast(T*)ap; 62 ap = cast(va_list)(cast(void*)ap + ((T.sizeof + int.sizeof - 1) & ~(int.sizeof - 1))); 63 } 64 65 /************* 66 * Retrieve and store through parmn the next value that is of TypeInfo ti. 67 * Used when the static type is not known. 68 */ 69 void va_arg()(ref va_list ap, TypeInfo ti, void* parmn) 70 { 71 // Wait until everyone updates to get TypeInfo.talign() 72 //auto talign = ti.talign(); 73 //auto p = cast(void*)(cast(size_t)ap + talign - 1) & ~(talign - 1); 74 auto p = ap; 75 auto tsize = ti.tsize(); 76 ap = cast(void*)(cast(size_t)p + ((tsize + size_t.sizeof - 1) & ~(size_t.sizeof - 1))); 77 parmn[0..tsize] = p[0..tsize]; 78 } 79 80 /*********************** 81 * End use of ap. 82 */ 83 void va_end(va_list ap) 84 { 85 } 86 87 void va_copy(out va_list dest, va_list src) 88 { 89 dest = src; 90 } 91 } 92 else version (X86_64) 93 { 94 // Layout of this struct must match __gnuc_va_list for C ABI compatibility 95 struct __va_list 96 { 97 uint offset_regs = 6 * 8; // no regs 98 uint offset_fpregs = 6 * 8 + 8 * 16; // no fp regs 99 void* stack_args; 100 void* reg_args; 101 } 102 103 struct __va_argsave_t 104 { 105 size_t[6] regs; // RDI,RSI,RDX,RCX,R8,R9 106 real[8] fpregs; // XMM0..XMM7 107 __va_list va; 108 } 109 110 /* 111 * Making it an array of 1 causes va_list to be passed as a pointer in 112 * function argument lists 113 */ 114 alias void* va_list; 115 116 void va_start(T)(out va_list ap, ref T parmn) 117 { 118 ap = &parmn.va; 119 } 120 121 T va_arg(T)(va_list ap) 122 { T a; 123 va_arg(ap, a); 124 return a; 125 } 126 127 void va_arg(T)(va_list apx, ref T parmn) 128 { 129 debug(PRINTF) printf("va_arg(T) called\n"); 130 __va_list* ap = cast(__va_list*)apx; 131 static if (is(T U == __argTypes)) 132 { 133 static if (U.length == 0 || T.sizeof > 16 || U[0].sizeof > 8) 134 { // Always passed in memory 135 // The arg may have more strict alignment than the stack 136 auto p = (cast(size_t)ap.stack_args + T.alignof - 1) & ~(T.alignof - 1); 137 ap.stack_args = cast(void*)(p + ((T.sizeof + size_t.sizeof - 1) & ~(size_t.sizeof - 1))); 138 parmn = *cast(T*)p; 139 } 140 else static if (U.length == 1) 141 { // Arg is passed in one register 142 alias U[0] T1; 143 static if (is(T1 == double) || is(T1 == float)) 144 { // Passed in XMM register 145 if (ap.offset_fpregs < (6 * 8 + 16 * 8)) 146 { 147 parmn = *cast(T*)(ap.reg_args + ap.offset_fpregs); 148 ap.offset_fpregs += 16; 149 } 150 else 151 { 152 parmn = *cast(T*)ap.stack_args; 153 ap.stack_args += (T1.sizeof + size_t.sizeof - 1) & ~(size_t.sizeof - 1); 154 } 155 } 156 else 157 { // Passed in regular register 158 if (ap.offset_regs < 6 * 8 && T.sizeof <= 8) 159 { 160 parmn = *cast(T*)(ap.reg_args + ap.offset_regs); 161 ap.offset_regs += 8; 162 } 163 else 164 { 165 auto p = (cast(size_t)ap.stack_args + T.alignof - 1) & ~(T.alignof - 1); 166 ap.stack_args = cast(void*)(p + ((T.sizeof + size_t.sizeof - 1) & ~(size_t.sizeof - 1))); 167 parmn = *cast(T*)p; 168 } 169 } 170 } 171 else static if (U.length == 2) 172 { // Arg is passed in two registers 173 alias U[0] T1; 174 alias U[1] T2; 175 176 static if (is(T1 == double) || is(T1 == float)) 177 { 178 if (ap.offset_fpregs < (6 * 8 + 16 * 8)) 179 { 180 *cast(T1*)&parmn = *cast(T1*)(ap.reg_args + ap.offset_fpregs); 181 ap.offset_fpregs += 16; 182 } 183 else 184 { 185 *cast(T1*)&parmn = *cast(T1*)ap.stack_args; 186 ap.stack_args += (T1.sizeof + size_t.sizeof - 1) & ~(size_t.sizeof - 1); 187 } 188 } 189 else 190 { 191 if (ap.offset_regs < 6 * 8 && T1.sizeof <= 8) 192 { 193 *cast(T1*)&parmn = *cast(T1*)(ap.reg_args + ap.offset_regs); 194 ap.offset_regs += 8; 195 } 196 else 197 { 198 *cast(T1*)&parmn = *cast(T1*)ap.stack_args; 199 ap.stack_args += 8; 200 } 201 } 202 203 auto p = cast(void*)&parmn + 8; 204 static if (is(T2 == double) || is(T2 == float)) 205 { 206 if (ap.offset_fpregs < (6 * 8 + 16 * 8)) 207 { 208 *cast(T2*)p = *cast(T2*)(ap.reg_args + ap.offset_fpregs); 209 ap.offset_fpregs += 16; 210 } 211 else 212 { 213 *cast(T2*)p = *cast(T2*)ap.stack_args; 214 ap.stack_args += (T2.sizeof + size_t.sizeof - 1) & ~(size_t.sizeof - 1); 215 } 216 } 217 else 218 { 219 void* a = void; 220 if (ap.offset_regs < 6 * 8 && T2.sizeof <= 8) 221 { 222 a = ap.reg_args + ap.offset_regs; 223 ap.offset_regs += 8; 224 } 225 else 226 { 227 a = ap.stack_args; 228 ap.stack_args += 8; 229 } 230 // Be careful not to go past the size of the actual argument 231 const sz2 = T.sizeof - 8; 232 p[0..sz2] = a[0..sz2]; 233 } 234 } 235 else 236 { 237 static assert(0); 238 } 239 } 240 else 241 { 242 static assert(0, "not a valid argument type for va_arg"); 243 } 244 } 245 246 void va_arg()(va_list apx, TypeInfo ti, void* parmn) 247 { 248 __va_list* ap = cast(__va_list*)apx; 249 TypeInfo arg1, arg2; 250 if (!ti.argTypes(arg1, arg2)) 251 { 252 if (arg1 && arg1.tsize() <= 8) 253 { 254 // Arg is passed in one register 255 auto tsize = arg1.tsize(); 256 void* p; 257 auto s = arg1.toString(); 258 if (s == "double" || s == "float" || s == "idouble" || s == "ifloat") 259 { // Passed in XMM register 260 if (ap.offset_fpregs < (6 * 8 + 16 * 8)) 261 { 262 p = ap.reg_args + ap.offset_fpregs; 263 ap.offset_fpregs += 16; 264 } 265 else 266 { 267 p = ap.stack_args; 268 ap.stack_args += (tsize + size_t.sizeof - 1) & ~(size_t.sizeof - 1); 269 } 270 } 271 else 272 { // Passed in regular register 273 if (ap.offset_regs < 6 * 8) 274 { 275 p = ap.reg_args + ap.offset_regs; 276 ap.offset_regs += 8; 277 } 278 else 279 { 280 p = ap.stack_args; 281 ap.stack_args += 8; 282 } 283 } 284 parmn[0..tsize] = p[0..tsize]; 285 286 if (arg2) 287 { 288 parmn += 8; 289 tsize = arg2.tsize(); 290 s = arg2.toString(); 291 if (s == "double" || s == "float" || s == "idouble" || s == "ifloat") 292 { // Passed in XMM register 293 if (ap.offset_fpregs < (6 * 8 + 16 * 8)) 294 { 295 p = ap.reg_args + ap.offset_fpregs; 296 ap.offset_fpregs += 16; 297 } 298 else 299 { 300 p = ap.stack_args; 301 ap.stack_args += (tsize + size_t.sizeof - 1) & ~(size_t.sizeof - 1); 302 } 303 } 304 else 305 { // Passed in regular register 306 if (ap.offset_regs < 6 * 8) 307 { 308 p = ap.reg_args + ap.offset_regs; 309 ap.offset_regs += 8; 310 } 311 else 312 { 313 p = ap.stack_args; 314 ap.stack_args += 8; 315 } 316 } 317 tsize = ti.tsize() - 8; 318 parmn[0..tsize] = p[0..tsize]; 319 } 320 } 321 else 322 { 323 // Always passed in memory 324 // The arg may have more strict alignment than the stack 325 auto talign = ti.talign(); 326 auto tsize = ti.tsize(); 327 328 329 auto p = cast(void*)((cast(size_t)ap.stack_args + talign - 1) & ~(talign - 1)); 330 ap.stack_args = cast(void*)(cast(size_t)p + ((tsize + size_t.sizeof - 1) & ~(size_t.sizeof - 1))); 331 parmn[0..tsize] = p[0..tsize]; 332 } 333 } 334 else 335 { 336 assert(0, "not a valid argument type for va_arg"); 337 } 338 } 339 340 void va_end(va_list ap) 341 { 342 } 343 344 void va_copy(out va_list dest, va_list src) 345 { 346 dest = src; 347 } 348 } 349 else 350 { 351 static assert(0); 352 } 353 } 354 +/