root/branches/phobos-1.x/phobos/std/c/stdarg.d

Revision 2124, 10.8 kB (checked in by walter, 2 years ago)

64 bit stuff

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