123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355 |
|
/**
* D header file for C99.
*
* Copyright: Public Domain
* License: Public Domain
* Authors: Hauke Duden, Walter Bright
* Standards: ISO/IEC 9899:1999 (E)
*/
module tango.stdc.stdarg;
debug(PRINTF) import tango.stdc.stdio: printf;
public import core.stdc.stdarg;
/+
version( GNU )
{
public import std.c.stdarg;
}
else version( LDC )
{
public import ldc.cstdarg;
}
else
{
version (X86)
{
/*********************
* The argument pointer type.
*/
alias void* va_list;
/**********
* Initialize ap.
* For 32 bit code, parmn should be the last named parameter.
* For 64 bit code, parmn should be __va_argsave.
*/
void va_start(T)(out va_list ap, ref T parmn)
{
ap = cast(va_list)(cast(void*)&parmn + ((T.sizeof + int.sizeof - 1) & ~(int.sizeof - 1)));
}
/************
* Retrieve and return the next value that is type T.
* Should use the other va_arg instead, as this won't work for 64 bit code.
*/
T va_arg(T)(ref va_list ap)
{
T arg = *cast(T*)ap;
ap = cast(va_list)(cast(void*)ap + ((T.sizeof + int.sizeof - 1) & ~(int.sizeof - 1)));
return arg;
}
/************
* Retrieve and return the next value that is type T.
* This is the preferred version.
*/
void va_arg(T)(ref va_list ap, ref T parmn)
{
parmn = *cast(T*)ap;
ap = cast(va_list)(cast(void*)ap + ((T.sizeof + int.sizeof - 1) & ~(int.sizeof - 1)));
}
/*************
* Retrieve and store through parmn the next value that is of TypeInfo ti.
* Used when the static type is not known.
*/
void va_arg()(ref va_list ap, TypeInfo ti, void* parmn)
{
// Wait until everyone updates to get TypeInfo.talign()
//auto talign = ti.talign();
//auto p = cast(void*)(cast(size_t)ap + talign - 1) & ~(talign - 1);
auto p = ap;
auto tsize = ti.tsize();
ap = cast(void*)(cast(size_t)p + ((tsize + size_t.sizeof - 1) & ~(size_t.sizeof - 1)));
parmn[0..tsize] = p[0..tsize];
}
/***********************
* End use of ap.
*/
void va_end(va_list ap)
{
}
void va_copy(out va_list dest, va_list src)
{
dest = src;
}
}
else version (X86_64)
{
// Layout of this struct must match __gnuc_va_list for C ABI compatibility
struct __va_list
{
uint offset_regs = 6 * 8; // no regs
uint offset_fpregs = 6 * 8 + 8 * 16; // no fp regs
void* stack_args;
void* reg_args;
}
struct __va_argsave_t
{
size_t[6] regs; // RDI,RSI,RDX,RCX,R8,R9
real[8] fpregs; // XMM0..XMM7
__va_list va;
}
/*
* Making it an array of 1 causes va_list to be passed as a pointer in
* function argument lists
*/
alias void* va_list;
void va_start(T)(out va_list ap, ref T parmn)
{
ap = &parmn.va;
}
T va_arg(T)(va_list ap)
{ T a;
va_arg(ap, a);
return a;
}
void va_arg(T)(va_list apx, ref T parmn)
{
debug(PRINTF) printf("va_arg(T) called\n");
__va_list* ap = cast(__va_list*)apx;
static if (is(T U == __argTypes))
{
static if (U.length == 0 || T.sizeof > 16 || U[0].sizeof > 8)
{ // Always passed in memory
// The arg may have more strict alignment than the stack
auto p = (cast(size_t)ap.stack_args + T.alignof - 1) & ~(T.alignof - 1);
ap.stack_args = cast(void*)(p + ((T.sizeof + size_t.sizeof - 1) & ~(size_t.sizeof - 1)));
parmn = *cast(T*)p;
}
else static if (U.length == 1)
{ // Arg is passed in one register
alias U[0] T1;
static if (is(T1 == double) || is(T1 == float))
{ // Passed in XMM register
if (ap.offset_fpregs < (6 * 8 + 16 * 8))
{
parmn = *cast(T*)(ap.reg_args + ap.offset_fpregs);
ap.offset_fpregs += 16;
}
else
{
parmn = *cast(T*)ap.stack_args;
ap.stack_args += (T1.sizeof + size_t.sizeof - 1) & ~(size_t.sizeof - 1);
}
}
else
{ // Passed in regular register
if (ap.offset_regs < 6 * 8 && T.sizeof <= 8)
{
parmn = *cast(T*)(ap.reg_args + ap.offset_regs);
ap.offset_regs += 8;
}
else
{
auto p = (cast(size_t)ap.stack_args + T.alignof - 1) & ~(T.alignof - 1);
ap.stack_args = cast(void*)(p + ((T.sizeof + size_t.sizeof - 1) & ~(size_t.sizeof - 1)));
parmn = *cast(T*)p;
}
}
}
else static if (U.length == 2)
{ // Arg is passed in two registers
alias U[0] T1;
alias U[1] T2;
static if (is(T1 == double) || is(T1 == float))
{
if (ap.offset_fpregs < (6 * 8 + 16 * 8))
{
*cast(T1*)&parmn = *cast(T1*)(ap.reg_args + ap.offset_fpregs);
ap.offset_fpregs += 16;
}
else
{
*cast(T1*)&parmn = *cast(T1*)ap.stack_args;
ap.stack_args += (T1.sizeof + size_t.sizeof - 1) & ~(size_t.sizeof - 1);
}
}
else
{
if (ap.offset_regs < 6 * 8 && T1.sizeof <= 8)
{
*cast(T1*)&parmn = *cast(T1*)(ap.reg_args + ap.offset_regs);
ap.offset_regs += 8;
}
else
{
*cast(T1*)&parmn = *cast(T1*)ap.stack_args;
ap.stack_args += 8;
}
}
auto p = cast(void*)&parmn + 8;
static if (is(T2 == double) || is(T2 == float))
{
if (ap.offset_fpregs < (6 * 8 + 16 * 8))
{
*cast(T2*)p = *cast(T2*)(ap.reg_args + ap.offset_fpregs);
ap.offset_fpregs += 16;
}
else
{
*cast(T2*)p = *cast(T2*)ap.stack_args;
ap.stack_args += (T2.sizeof + size_t.sizeof - 1) & ~(size_t.sizeof - 1);
}
}
else
{
void* a = void;
if (ap.offset_regs < 6 * 8 && T2.sizeof <= 8)
{
a = ap.reg_args + ap.offset_regs;
ap.offset_regs += 8;
}
else
{
a = ap.stack_args;
ap.stack_args += 8;
}
// Be careful not to go past the size of the actual argument
const sz2 = T.sizeof - 8;
p[0..sz2] = a[0..sz2];
}
}
else
{
static assert(0);
}
}
else
{
static assert(0, "not a valid argument type for va_arg");
}
}
void va_arg()(va_list apx, TypeInfo ti, void* parmn)
{
__va_list* ap = cast(__va_list*)apx;
TypeInfo arg1, arg2;
if (!ti.argTypes(arg1, arg2))
{
if (arg1 && arg1.tsize() <= 8)
{
// Arg is passed in one register
auto tsize = arg1.tsize();
void* p;
auto s = arg1.toString();
if (s == "double" || s == "float" || s == "idouble" || s == "ifloat")
{ // Passed in XMM register
if (ap.offset_fpregs < (6 * 8 + 16 * 8))
{
p = ap.reg_args + ap.offset_fpregs;
ap.offset_fpregs += 16;
}
else
{
p = ap.stack_args;
ap.stack_args += (tsize + size_t.sizeof - 1) & ~(size_t.sizeof - 1);
}
}
else
{ // Passed in regular register
if (ap.offset_regs < 6 * 8)
{
p = ap.reg_args + ap.offset_regs;
ap.offset_regs += 8;
}
else
{
p = ap.stack_args;
ap.stack_args += 8;
}
}
parmn[0..tsize] = p[0..tsize];
if (arg2)
{
parmn += 8;
tsize = arg2.tsize();
s = arg2.toString();
if (s == "double" || s == "float" || s == "idouble" || s == "ifloat")
{ // Passed in XMM register
if (ap.offset_fpregs < (6 * 8 + 16 * 8))
{
p = ap.reg_args + ap.offset_fpregs;
ap.offset_fpregs += 16;
}
else
{
p = ap.stack_args;
ap.stack_args += (tsize + size_t.sizeof - 1) & ~(size_t.sizeof - 1);
}
}
else
{ // Passed in regular register
if (ap.offset_regs < 6 * 8)
{
p = ap.reg_args + ap.offset_regs;
ap.offset_regs += 8;
}
else
{
p = ap.stack_args;
ap.stack_args += 8;
}
}
tsize = ti.tsize() - 8;
parmn[0..tsize] = p[0..tsize];
}
}
else
{
// Always passed in memory
// The arg may have more strict alignment than the stack
auto talign = ti.talign();
auto tsize = ti.tsize();
auto p = cast(void*)((cast(size_t)ap.stack_args + talign - 1) & ~(talign - 1));
ap.stack_args = cast(void*)(cast(size_t)p + ((tsize + size_t.sizeof - 1) & ~(size_t.sizeof - 1)));
parmn[0..tsize] = p[0..tsize];
}
}
else
{
assert(0, "not a valid argument type for va_arg");
}
}
void va_end(va_list ap)
{
}
void va_copy(out va_list dest, va_list src)
{
dest = src;
}
}
else
{
static assert(0);
}
}
+/
|