1/**
2 * The vararg module is intended to facilitate vararg manipulation in D.
3 * It should be interface compatible with the C module "stdarg," and the
4 * two modules may share a common implementation if possible (as is done
5 * here).
6 * Copyright: Copyright Digital Mars 2000 - 2009.
7 * License:   $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
8 * Authors:   Walter Bright, Hauke Duden
9 * Source:    $(DRUNTIMESRC core/_vararg.d)
10 */
11
12/*          Copyright Digital Mars 2000 - 2009.
13 * Distributed under the Boost Software License, Version 1.0.
14 *    (See accompanying file LICENSE or copy at
15 *          http://www.boost.org/LICENSE_1_0.txt)
16 */
17module core.vararg;
18
19public import core.stdc.stdarg;
20
21
22version (GNU) { /* TypeInfo-based va_arg overload unsupported */ }
23else:
24
25version (ARM)     version = ARM_Any;
26version (AArch64) version = ARM_Any;
27version (MIPS32)  version = MIPS_Any;
28version (MIPS64)  version = MIPS_Any;
29version (PPC)     version = PPC_Any;
30version (PPC64)   version = PPC_Any;
31
32version (ARM_Any)
33{
34    // Darwin uses a simpler varargs implementation
35    version (OSX) {}
36    else version (iOS) {}
37    else version (TVOS) {}
38    else version (WatchOS) {}
39    else:
40
41    version (ARM)     version = AAPCS32;
42    version (AArch64) version = AAPCS64;
43}
44
45
46///
47alias va_arg = core.stdc.stdarg.va_arg;
48
49
50/**
51 * Retrieve and store through parmn the next value that is of TypeInfo ti.
52 * Used when the static type is not known.
53 */
54void va_arg()(ref va_list ap, TypeInfo ti, void* parmn)
55{
56    version (X86)
57    {
58        // Wait until everyone updates to get TypeInfo.talign
59        //auto talign = ti.talign;
60        //auto p = cast(void*)(cast(size_t)ap + talign - 1) & ~(talign - 1);
61        auto p = ap;
62        auto tsize = ti.tsize;
63        ap = cast(va_list) (p + tsize.alignUp);
64        parmn[0..tsize] = p[0..tsize];
65    }
66    else version (Win64)
67    {
68        version (LDC) enum isLDC = true;
69        else          enum isLDC = false;
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        void* q;
77        if (isLDC && tsize == 16 && cast(TypeInfo_Array) ti)
78        {
79            q = p;
80            ap = cast(va_list) (p + tsize);
81        }
82        else
83        {
84            q = (tsize > size_t.sizeof || (tsize & (tsize - 1)) != 0) ? *cast(void**) p : p;
85            ap = cast(va_list) (p + size_t.sizeof);
86        }
87        parmn[0..tsize] = q[0..tsize];
88    }
89    else version (X86_64)
90    {
91        static import core.internal.vararg.sysv_x64;
92        core.internal.vararg.sysv_x64.va_arg(ap, ti, parmn);
93    }
94    else version (AAPCS32)
95    {
96        const tsize = ti.tsize;
97        if (ti.talign >= 8)
98            ap.__ap = ap.__ap.alignUp!8;
99        auto p = ap.__ap;
100        version (BigEndian)
101            p = adjustForBigEndian(p, tsize);
102        ap.__ap += tsize.alignUp;
103        parmn[0..tsize] = p[0..tsize];
104    }
105    else version (AAPCS64)
106    {
107        static import core.internal.vararg.aarch64;
108        core.internal.vararg.aarch64.va_arg(ap, ti, parmn);
109    }
110    else version (ARM_Any)
111    {
112        const tsize = ti.tsize;
113        auto p = cast(void*) ap;
114        version (BigEndian)
115            p = adjustForBigEndian(p, tsize);
116        ap += tsize.alignUp;
117        parmn[0..tsize] = p[0..tsize];
118    }
119    else version (PPC_Any)
120    {
121        if (ti.talign >= 8)
122            ap = ap.alignUp!8;
123        const tsize = ti.tsize;
124        auto p = cast(void*) ap;
125        version (BigEndian)
126            p = adjustForBigEndian(p, tsize);
127        ap += tsize.alignUp;
128        parmn[0..tsize] = p[0..tsize];
129    }
130    else version (MIPS_Any)
131    {
132        const tsize = ti.tsize;
133        auto p = cast(void*) ap;
134        version (BigEndian)
135            p = adjustForBigEndian(p, tsize);
136        ap += tsize.alignUp;
137        parmn[0..tsize] = p[0..tsize];
138    }
139    else
140        static assert(0, "Unsupported platform");
141}
142