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  */
17 module core.vararg;
18 
19 public import core.stdc.stdarg;
20 
21 
22 version (GNU) { /* TypeInfo-based va_arg overload unsupported */ }
23 else:
24 
25 version (ARM)     version = ARM_Any;
26 version (AArch64) version = ARM_Any;
27 version (MIPS32)  version = MIPS_Any;
28 version (MIPS64)  version = MIPS_Any;
29 version (PPC)     version = PPC_Any;
30 version (PPC64)   version = PPC_Any;
31 version (RISCV32) version = RISCV_Any;
32 version (RISCV64) version = RISCV_Any;
33 
34 version (ARM_Any)
35 {
36     // Darwin uses a simpler varargs implementation
37     version (OSX) {}
38     else version (iOS) {}
39     else version (TVOS) {}
40     else version (WatchOS) {}
41     else:
42 
43     version (ARM)     version = AAPCS32;
44     version (AArch64) version = AAPCS64;
45 }
46 
47 
48 ///
49 alias va_arg = core.stdc.stdarg.va_arg;
50 
51 
52 /**
53  * Retrieve and store through parmn the next value that is of TypeInfo ti.
54  * Used when the static type is not known.
55  */
56 void va_arg()(ref va_list ap, TypeInfo ti, void* parmn)
57 {
58     version (X86)
59     {
60         // Wait until everyone updates to get TypeInfo.talign
61         //auto talign = ti.talign;
62         //auto p = cast(void*)(cast(size_t)ap + talign - 1) & ~(talign - 1);
63         auto p = ap;
64         auto tsize = ti.tsize;
65         ap = cast(va_list) (p + tsize.alignUp);
66         parmn[0..tsize] = p[0..tsize];
67     }
68     else version (Win64)
69     {
70         version (LDC) enum isLDC = true;
71         else          enum isLDC = false;
72 
73         // Wait until everyone updates to get TypeInfo.talign
74         //auto talign = ti.talign;
75         //auto p = cast(void*)(cast(size_t)ap + talign - 1) & ~(talign - 1);
76         auto p = ap;
77         auto tsize = ti.tsize;
78         void* q;
79         if (isLDC && tsize == 16 && cast(TypeInfo_Array) ti)
80         {
81             q = p;
82             ap = cast(va_list) (p + tsize);
83         }
84         else
85         {
86             q = (tsize > size_t.sizeof || (tsize & (tsize - 1)) != 0) ? *cast(void**) p : p;
87             ap = cast(va_list) (p + size_t.sizeof);
88         }
89         parmn[0..tsize] = q[0..tsize];
90     }
91     else version (X86_64)
92     {
93         static import core.internal.vararg.sysv_x64;
94         core.internal.vararg.sysv_x64.va_arg(ap, ti, parmn);
95     }
96     else version (AAPCS32)
97     {
98         const tsize = ti.tsize;
99         if (ti.talign >= 8)
100             ap.__ap = ap.__ap.alignUp!8;
101         auto p = ap.__ap;
102         version (BigEndian)
103             p = adjustForBigEndian(p, tsize);
104         ap.__ap += tsize.alignUp;
105         parmn[0..tsize] = p[0..tsize];
106     }
107     else version (AAPCS64)
108     {
109         static import core.internal.vararg.aarch64;
110         core.internal.vararg.aarch64.va_arg(ap, ti, parmn);
111     }
112     else version (ARM_Any)
113     {
114         const tsize = ti.tsize;
115         auto p = cast(void*) ap;
116         version (BigEndian)
117             p = adjustForBigEndian(p, tsize);
118         ap += tsize.alignUp;
119         parmn[0..tsize] = p[0..tsize];
120     }
121     else version (PPC_Any)
122     {
123         if (ti.talign >= 8)
124             ap = ap.alignUp!8;
125         const tsize = ti.tsize;
126         auto p = cast(void*) ap;
127         version (BigEndian)
128             p = adjustForBigEndian(p, tsize);
129         ap += tsize.alignUp;
130         parmn[0..tsize] = p[0..tsize];
131     }
132     else version (MIPS_Any)
133     {
134         const tsize = ti.tsize;
135         auto p = cast(void*) ap;
136         version (BigEndian)
137             p = adjustForBigEndian(p, tsize);
138         ap += tsize.alignUp;
139         parmn[0..tsize] = p[0..tsize];
140     }
141     else version (RISCV_Any)
142     {
143         const tsize = ti.tsize;
144         void* p;
145         if (tsize > (size_t.sizeof << 1))
146             p = *cast(void**) ap;
147         else
148         {
149             if (tsize == (size_t.sizeof << 1))
150                 ap = ap.alignUp!(size_t.sizeof << 1);
151             p = cast(void*) ap;
152         }
153         ap += tsize.alignUp;
154         parmn[0..tsize] = p[0..tsize];
155     }
156     else
157         static assert(0, "Unsupported platform");
158 }