2 * D header file for C99.
4 * $(C_HEADER_DESCRIPTION pubs.opengroup.org/onlinepubs/009695399/basedefs/_stdarg.h.html, _stdarg.h)
6 * Copyright: Copyright Digital Mars 2000 - 2009.
7 * License: $(HTTP www.boost.org/LICENSE_1_0.txt, Boost License 1.0).
8 * Authors: Walter Bright, Hauke Duden
9 * Standards: ISO/IEC 9899:1999 (E)
10 * Source: $(DRUNTIMESRC core/stdc/_stdarg.d)
13 /* NOTE: This file has been patched from the original DMD distribution to
14 * work with the GDC compiler.
16 module core
.stdc
.stdarg
;
19 //@nogc: // Not yet, need to make TypeInfo's member functions @nogc first
25 alias __builtin_va_list __gnuc_va_list
;
28 /*********************
29 * The argument pointer type.
31 alias __gnuc_va_list va_list
;
36 * parmn should be the last named parameter.
38 void va_start(T
)(out va_list ap
, ref T parmn
);
42 * Retrieve and return the next value that is type T.
44 T
va_arg(T
)(ref va_list ap
);
48 * Retrieve and store through parmn the next value that is of type T.
50 void va_arg(T
)(ref va_list ap
, ref T parmn
);
54 * Retrieve and store through parmn the next value that is of TypeInfo ti.
55 * Used when the static type is not known.
60 void va_arg()(ref va_list ap
, TypeInfo ti
, void* parmn
)
63 auto tsize
= ti
.tsize
;
64 ap
= cast(va_list
)(cast(size_t
)p
+ ((tsize
+ size_t
.sizeof
- 1) & ~(size_t
.sizeof
- 1)));
65 parmn
[0..tsize
] = p
[0..tsize
];
70 /// Layout of this struct must match __builtin_va_list for C ABI compatibility
73 uint offset_regs
= 6 * 8; // no regs
74 uint offset_fpregs
= 6 * 8 + 8 * 16; // no fp regs
80 void va_arg()(ref va_list apx
, TypeInfo ti
, void* parmn
)
82 __va_list
* ap
= cast(__va_list
*)apx
;
84 if (!ti
.argTypes(arg1
, arg2
))
86 bool inXMMregister(TypeInfo arg
) pure nothrow @safe
88 return (arg
.flags
& 2) != 0;
91 TypeInfo_Vector v1
= arg1 ?
cast(TypeInfo_Vector
)arg1
: null;
92 if (arg1
&& (arg1
.tsize() <= 8 || v1
))
93 { // Arg is passed in one register
94 auto tsize
= arg1
.tsize();
97 auto offset_fpregs_save
= ap
.offset_fpregs
;
98 auto offset_regs_save
= ap
.offset_regs
;
100 if (inXMMregister(arg1
) || v1
)
101 { // Passed in XMM register
102 if (ap
.offset_fpregs
< (6 * 8 + 16 * 8) && !stack
)
104 p
= ap
.reg_args
+ ap
.offset_fpregs
;
105 ap
.offset_fpregs
+= 16;
110 ap
.stack_args
+= (tsize
+ size_t
.sizeof
- 1) & ~(size_t
.sizeof
- 1);
115 { // Passed in regular register
116 if (ap
.offset_regs
< 6 * 8 && !stack
)
118 p
= ap
.reg_args
+ ap
.offset_regs
;
128 parmn
[0..tsize
] = p
[0..tsize
];
132 if (inXMMregister(arg2
))
133 { // Passed in XMM register
134 if (ap
.offset_fpregs
< (6 * 8 + 16 * 8) && !stack
)
136 p
= ap
.reg_args
+ ap
.offset_fpregs
;
137 ap
.offset_fpregs
+= 16;
142 { // arg1 is really on the stack, so rewind and redo
143 ap
.offset_fpregs
= offset_fpregs_save
;
144 ap
.offset_regs
= offset_regs_save
;
149 ap
.stack_args
+= (arg2
.tsize() + size_t
.sizeof
- 1) & ~(size_t
.sizeof
- 1);
153 { // Passed in regular register
154 if (ap
.offset_regs
< 6 * 8 && !stack
)
156 p
= ap
.reg_args
+ ap
.offset_regs
;
162 { // arg1 is really on the stack, so rewind and redo
163 ap
.offset_fpregs
= offset_fpregs_save
;
164 ap
.offset_regs
= offset_regs_save
;
172 auto sz
= ti
.tsize() - 8;
173 (parmn
+ 8)[0..sz
] = p
[0..sz
];
177 { // Always passed in memory
178 // The arg may have more strict alignment than the stack
179 auto talign
= ti
.talign();
180 auto tsize
= ti
.tsize();
181 auto p
= cast(void*)((cast(size_t
)ap
.stack_args
+ talign
- 1) & ~(talign
- 1));
182 ap
.stack_args
= cast(void*)(cast(size_t
)p
+ ((tsize
+ size_t
.sizeof
- 1) & ~(size_t
.sizeof
- 1)));
183 parmn
[0..tsize
] = p
[0..tsize
];
188 assert(false, "not a valid argument type for va_arg");
195 void va_arg()(ref va_list ap
, TypeInfo ti
, void* parmn
)
197 auto p
= *cast(void**) &ap
;
198 auto tsize
= ti
.tsize();
199 *cast(void**) &ap
+= ( tsize
+ size_t
.sizeof
- 1 ) & ~( size_t
.sizeof
- 1 );
200 parmn
[0..tsize
] = p
[0..tsize
];
206 void va_arg()(ref va_list ap
, TypeInfo ti
, void* parmn
)
208 static assert(false, "Unsupported platform");
213 /***********************
216 alias __builtin_va_end va_end
;
219 /***********************
222 alias __builtin_va_copy va_copy
;
227 /*********************
228 * The argument pointer type.
234 * For 32 bit code, parmn should be the last named parameter.
235 * For 64 bit code, parmn should be __va_argsave.
237 void va_start(T
)(out va_list ap
, ref T parmn
)
239 ap
= cast(va_list
)( cast(void*) &parmn
+ ( ( T
.sizeof
+ int.sizeof
- 1 ) & ~( int.sizeof
- 1 ) ) );
243 * Retrieve and return the next value that is type T.
244 * Should use the other va_arg instead, as this won't work for 64 bit code.
246 T
va_arg(T
)(ref va_list ap
)
248 T arg
= *cast(T
*) ap
;
249 ap
= cast(va_list
)( cast(void*) ap
+ ( ( T
.sizeof
+ int.sizeof
- 1 ) & ~( int.sizeof
- 1 ) ) );
254 * Retrieve and return the next value that is type T.
255 * This is the preferred version.
257 void va_arg(T
)(ref va_list ap
, ref T parmn
)
260 ap
= cast(va_list
)(cast(void*)ap
+ ((T
.sizeof
+ int.sizeof
- 1) & ~(int.sizeof
- 1)));
264 * Retrieve and store through parmn the next value that is of TypeInfo ti.
265 * Used when the static type is not known.
267 void va_arg()(ref va_list ap
, TypeInfo ti
, void* parmn
)
269 // Wait until everyone updates to get TypeInfo.talign
270 //auto talign = ti.talign;
271 //auto p = cast(void*)(cast(size_t)ap + talign - 1) & ~(talign - 1);
273 auto tsize
= ti
.tsize
;
274 ap
= cast(va_list
)(cast(size_t
)p
+ ((tsize
+ size_t
.sizeof
- 1) & ~(size_t
.sizeof
- 1)));
275 parmn
[0..tsize
] = p
[0..tsize
];
278 /***********************
281 void va_end(va_list ap
)
286 void va_copy(out va_list dest
, va_list src
)
291 else version (Windows
) // Win64
292 { /* Win64 is characterized by all arguments fitting into a register size.
293 * Smaller ones are padded out to register size, and larger ones are passed by
297 /*********************
298 * The argument pointer type.
304 * parmn should be the last named parameter.
306 void va_start(T
)(out va_list ap
, ref T parmn
); // Compiler intrinsic
309 * Retrieve and return the next value that is type T.
311 T
va_arg(T
)(ref va_list ap
)
313 static if (T
.sizeof
> size_t
.sizeof
)
314 T arg
= **cast(T
**)ap
;
317 ap
= cast(va_list
)(cast(void*)ap
+ ((size_t
.sizeof
+ size_t
.sizeof
- 1) & ~(size_t
.sizeof
- 1)));
322 * Retrieve and return the next value that is type T.
323 * This is the preferred version.
325 void va_arg(T
)(ref va_list ap
, ref T parmn
)
327 static if (T
.sizeof
> size_t
.sizeof
)
328 parmn
= **cast(T
**)ap
;
331 ap
= cast(va_list
)(cast(void*)ap
+ ((size_t
.sizeof
+ size_t
.sizeof
- 1) & ~(size_t
.sizeof
- 1)));
335 * Retrieve and store through parmn the next value that is of TypeInfo ti.
336 * Used when the static type is not known.
338 void va_arg()(ref va_list ap
, TypeInfo ti
, void* parmn
)
340 // Wait until everyone updates to get TypeInfo.talign
341 //auto talign = ti.talign;
342 //auto p = cast(void*)(cast(size_t)ap + talign - 1) & ~(talign - 1);
344 auto tsize
= ti
.tsize
;
345 ap
= cast(va_list
)(cast(size_t
)p
+ ((size_t
.sizeof
+ size_t
.sizeof
- 1) & ~(size_t
.sizeof
- 1)));
346 void* q
= (tsize
> size_t
.sizeof
) ?
*cast(void**)p
: p
;
347 parmn
[0..tsize
] = q
[0..tsize
];
350 /***********************
353 void va_end(va_list ap
)
358 void va_copy(out va_list dest
, va_list src
)
363 else version (X86_64
)
365 // Determine if type is a vector type
366 template isVectorType(T
)
368 enum isVectorType
= false;
371 template isVectorType(T
: __vector(T
[N
]), size_t N
)
373 enum isVectorType
= true;
376 // Layout of this struct must match __gnuc_va_list for C ABI compatibility
379 uint offset_regs
= 6 * 8; // no regs
380 uint offset_fpregs
= 6 * 8 + 8 * 16; // no fp regs
384 alias __va_list
= __va_list_tag
;
386 align(16) struct __va_argsave_t
388 size_t
[6] regs
; // RDI,RSI,RDX,RCX,R8,R9
389 real[8] fpregs
; // XMM0..XMM7
394 * Making it an array of 1 causes va_list to be passed as a pointer in
395 * function argument lists
397 alias va_list
= __va_list
*;
400 void va_start(T
)(out va_list ap
, ref T parmn
); // Compiler intrinsic
403 T
va_arg(T
)(va_list ap
)
410 void va_arg(T
)(va_list apx
, ref T parmn
)
412 __va_list
* ap
= cast(__va_list
*)apx
;
413 static if (is(T U
== __argTypes
))
415 static if (U
.length
== 0 || T
.sizeof
> 16 ||
(U
[0].sizeof
> 8 && !isVectorType
!(U
[0])))
416 { // Always passed in memory
417 // The arg may have more strict alignment than the stack
418 auto p
= (cast(size_t
)ap
.stack_args
+ T
.alignof
- 1) & ~(T
.alignof
- 1);
419 ap
.stack_args
= cast(void*)(p
+ ((T
.sizeof
+ size_t
.sizeof
- 1) & ~(size_t
.sizeof
- 1)));
422 else static if (U
.length
== 1)
423 { // Arg is passed in one register
425 static if (is(T1
== double) ||
is(T1
== float) || isVectorType
!(T1
))
426 { // Passed in XMM register
427 if (ap
.offset_fpregs
< (6 * 8 + 16 * 8))
429 parmn
= *cast(T
*)(ap
.reg_args
+ ap
.offset_fpregs
);
430 ap
.offset_fpregs
+= 16;
434 parmn
= *cast(T
*)ap
.stack_args
;
435 ap
.stack_args
+= (T1
.sizeof
+ size_t
.sizeof
- 1) & ~(size_t
.sizeof
- 1);
439 { // Passed in regular register
440 if (ap
.offset_regs
< 6 * 8 && T
.sizeof
<= 8)
442 parmn
= *cast(T
*)(ap
.reg_args
+ ap
.offset_regs
);
447 auto p
= (cast(size_t
)ap
.stack_args
+ T
.alignof
- 1) & ~(T
.alignof
- 1);
448 ap
.stack_args
= cast(void*)(p
+ ((T
.sizeof
+ size_t
.sizeof
- 1) & ~(size_t
.sizeof
- 1)));
453 else static if (U
.length
== 2)
454 { // Arg is passed in two registers
457 auto p
= cast(void*)&parmn
+ 8;
459 // Both must be in registers, or both on stack, hence 4 cases
461 static if ((is(T1
== double) ||
is(T1
== float)) &&
462 (is(T2
== double) ||
is(T2
== float)))
464 if (ap
.offset_fpregs
< (6 * 8 + 16 * 8) - 16)
466 *cast(T1
*)&parmn
= *cast(T1
*)(ap
.reg_args
+ ap
.offset_fpregs
);
467 *cast(T2
*)p
= *cast(T2
*)(ap
.reg_args
+ ap
.offset_fpregs
+ 16);
468 ap
.offset_fpregs
+= 32;
472 *cast(T1
*)&parmn
= *cast(T1
*)ap
.stack_args
;
473 ap
.stack_args
+= (T1
.sizeof
+ size_t
.sizeof
- 1) & ~(size_t
.sizeof
- 1);
474 *cast(T2
*)p
= *cast(T2
*)ap
.stack_args
;
475 ap
.stack_args
+= (T2
.sizeof
+ size_t
.sizeof
- 1) & ~(size_t
.sizeof
- 1);
478 else static if (is(T1
== double) ||
is(T1
== float))
481 if (ap
.offset_fpregs
< (6 * 8 + 16 * 8) &&
482 ap
.offset_regs
< 6 * 8 && T2
.sizeof
<= 8)
484 *cast(T1
*)&parmn
= *cast(T1
*)(ap
.reg_args
+ ap
.offset_fpregs
);
485 ap
.offset_fpregs
+= 16;
486 a
= ap
.reg_args
+ ap
.offset_regs
;
491 *cast(T1
*)&parmn
= *cast(T1
*)ap
.stack_args
;
492 ap
.stack_args
+= (T1
.sizeof
+ size_t
.sizeof
- 1) & ~(size_t
.sizeof
- 1);
496 // Be careful not to go past the size of the actual argument
497 const sz2
= T
.sizeof
- 8;
498 p
[0..sz2
] = a
[0..sz2
];
500 else static if (is(T2
== double) ||
is(T2
== float))
502 if (ap
.offset_regs
< 6 * 8 && T1
.sizeof
<= 8 &&
503 ap
.offset_fpregs
< (6 * 8 + 16 * 8))
505 *cast(T1
*)&parmn
= *cast(T1
*)(ap
.reg_args
+ ap
.offset_regs
);
507 *cast(T2
*)p
= *cast(T2
*)(ap
.reg_args
+ ap
.offset_fpregs
);
508 ap
.offset_fpregs
+= 16;
512 *cast(T1
*)&parmn
= *cast(T1
*)ap
.stack_args
;
514 *cast(T2
*)p
= *cast(T2
*)ap
.stack_args
;
515 ap
.stack_args
+= (T2
.sizeof
+ size_t
.sizeof
- 1) & ~(size_t
.sizeof
- 1);
518 else // both in regular registers
521 if (ap
.offset_regs
< 5 * 8 && T1
.sizeof
<= 8 && T2
.sizeof
<= 8)
523 *cast(T1
*)&parmn
= *cast(T1
*)(ap
.reg_args
+ ap
.offset_regs
);
525 a
= ap
.reg_args
+ ap
.offset_regs
;
530 *cast(T1
*)&parmn
= *cast(T1
*)ap
.stack_args
;
535 // Be careful not to go past the size of the actual argument
536 const sz2
= T
.sizeof
- 8;
537 p
[0..sz2
] = a
[0..sz2
];
542 static assert(false);
547 static assert(false, "not a valid argument type for va_arg");
552 void va_arg()(va_list apx
, TypeInfo ti
, void* parmn
)
554 __va_list
* ap
= cast(__va_list
*)apx
;
556 if (!ti
.argTypes(arg1
, arg2
))
558 bool inXMMregister(TypeInfo arg
) pure nothrow @safe
560 return (arg
.flags
& 2) != 0;
563 TypeInfo_Vector v1
= arg1 ?
cast(TypeInfo_Vector
)arg1
: null;
564 if (arg1
&& (arg1
.tsize
<= 8 || v1
))
565 { // Arg is passed in one register
566 auto tsize
= arg1
.tsize
;
569 auto offset_fpregs_save
= ap
.offset_fpregs
;
570 auto offset_regs_save
= ap
.offset_regs
;
572 if (inXMMregister(arg1
) || v1
)
573 { // Passed in XMM register
574 if (ap
.offset_fpregs
< (6 * 8 + 16 * 8) && !stack
)
576 p
= ap
.reg_args
+ ap
.offset_fpregs
;
577 ap
.offset_fpregs
+= 16;
582 ap
.stack_args
+= (tsize
+ size_t
.sizeof
- 1) & ~(size_t
.sizeof
- 1);
587 { // Passed in regular register
588 if (ap
.offset_regs
< 6 * 8 && !stack
)
590 p
= ap
.reg_args
+ ap
.offset_regs
;
600 parmn
[0..tsize
] = p
[0..tsize
];
604 if (inXMMregister(arg2
))
605 { // Passed in XMM register
606 if (ap
.offset_fpregs
< (6 * 8 + 16 * 8) && !stack
)
608 p
= ap
.reg_args
+ ap
.offset_fpregs
;
609 ap
.offset_fpregs
+= 16;
614 { // arg1 is really on the stack, so rewind and redo
615 ap
.offset_fpregs
= offset_fpregs_save
;
616 ap
.offset_regs
= offset_regs_save
;
621 ap
.stack_args
+= (arg2
.tsize
+ size_t
.sizeof
- 1) & ~(size_t
.sizeof
- 1);
625 { // Passed in regular register
626 if (ap
.offset_regs
< 6 * 8 && !stack
)
628 p
= ap
.reg_args
+ ap
.offset_regs
;
634 { // arg1 is really on the stack, so rewind and redo
635 ap
.offset_fpregs
= offset_fpregs_save
;
636 ap
.offset_regs
= offset_regs_save
;
644 auto sz
= ti
.tsize
- 8;
645 (parmn
+ 8)[0..sz
] = p
[0..sz
];
649 { // Always passed in memory
650 // The arg may have more strict alignment than the stack
651 auto talign
= ti
.talign
;
652 auto tsize
= ti
.tsize
;
653 auto p
= cast(void*)((cast(size_t
)ap
.stack_args
+ talign
- 1) & ~(talign
- 1));
654 ap
.stack_args
= cast(void*)(cast(size_t
)p
+ ((tsize
+ size_t
.sizeof
- 1) & ~(size_t
.sizeof
- 1)));
655 parmn
[0..tsize
] = p
[0..tsize
];
660 assert(false, "not a valid argument type for va_arg");
665 void va_end(va_list ap
)
669 import core
.stdc
.stdlib
: alloca
;
672 void va_copy(out va_list dest
, va_list src
, void* storage
= alloca(__va_list_tag
.sizeof
))
674 // Instead of copying the pointers, and aliasing the source va_list,
675 // the default argument alloca will allocate storage in the caller's
676 // stack frame. This is still not correct (it should be allocated in
677 // the place where the va_list variable is declared) but most of the
678 // time the caller's stack frame _is_ the place where the va_list is
679 // allocated, so in most cases this will now work.
680 dest
= cast(va_list
)storage
;
686 static assert(false, "Unsupported platform");