Tango 0.96 beta2 released
Frits van Bommel
fvbommel at REMwOVExCAPSs.nl
Fri Mar 16 15:00:24 PDT 2007
[Fair warning: this seems to have become a pretty big post]
Sean Kelly wrote:
> Frits van Bommel wrote:
>>
>> I attached a patch, though I'm not sure how much use it'll be if you
>> insist on your own version of std.c.stdarg ...
>
> Thanks. I think the stdarg issues should now be resolved [...]
Sorry to disappoint again.
Unfortunately, build-gdc.sh only compiles files in lib/ (and some in
std/ imported by them). These compile successfully with my patch, AFAICT.
The stuff in tango/ doesn't work quite as well though.
For instance, it turns out tango.text.convert.Layout is pretty screwed
in the current implementation. Again, this has to do with varargs.
At the top it has:
-----
/*******************************************************************************
Platform issues ...
*******************************************************************************/
version (DigitalMars)
alias void* Arg;
else
alias char* Arg;
-----
and it then proceeds to use Arg to receive va_list arguments. Well, I
thought this would be an easy fix:
-----
private import tango.core.Vararg;
alias va_list Arg;
-----
Unfortunately, that doesn't work. Specifically because of how Arg is
used in "public final uint convert (Sink sink, TypeInfo[] arguments, Arg
args, T[] formatStr)":
-----
Arg[64] arglist = void;
foreach (i, arg; arguments)
{
arglist[i] = args;
args += (arg.tsize + int.sizeof - 1) & ~ (int.sizeof - 1);
}
return parse (formatStr, arguments, arglist, sink);
-----
Here it looks like it tries to manually extract the arguments, assuming
they all lie (on the stack) at int.sizeof boundaries. While this may
work on (32-bit?) platforms where varargs are all passed on the stack
like x86 with C or D calling convention[1], on amd64 this is not the
case: va_list isn't a pointer and the variable arguments aren't
necessarily all on the stack.
Since it seems GDC basically uses the C calling convention, I'll give a
short description of the problems I see with it:
The C(++?) calling convention on amd64[2] passes the first several
parameters in registers, and it seems not to deviate from this in case
of varargs. Worse, it uses different sets of registers for different
types of arguments (6 general-purpose registers for integer types &
pointers etc., 8 SSE regs for float/double, and the rest in memory).
Aggregates are potentially split up(!) if certain conditions are met (<
16 bytes, all members are naturally aligned, fits entirely into
registers, and a few more).
Basically, what I'm trying to say is: This would most likely be hell to
implement manually, and the code using it still unportable to yet other
calling conventions.
IMHO what we really need to do is either something like educating
TypeInfo to know how to "increment" a va_list to skip the appropriate
type[3], or changing GDC to just pass varargs on the stack when
compiling an extern(D) function, no matter the local C calling
convention :).
In the mean time, perhaps this function (and any vararg functions
calling it with their own va_list) could be changed to use variadic
template args (I do hope none of these are overridden anywhere, or this
won't work). This will likely result in some code bloat though, with
most calls using their own private instantiation, so it's not a really
nice long-term solution. It _should_ be pretty portable though :).
There were some other errors I less thoroughly investigated, but most of
these look like they can probably easily be fixed (in the first two
cases perhaps even by simply using the same code as for x86?):
* tango.sys.linux.socket static asserts(0) if version(X86) isn't
defined, with comment "// Different values on other platforms." (the X86
branch defines a constant named "SOL_SOCKET", whatever that may be)
* tango.math.IEEE doesn't define the FPU masks for amd64 (just for x86
and PPC it seems).
* tango.text.Regex also seems to assume that va_list is a pointer to a
1-byte type instead of using va_start/va_arg/va_end.
* tango.stdc.posix.setjmp straight static asserts(false, "Architecture
not supported.") on version(X86_64) (though the actual error is an
undefined identifier used after that, presumably because static asserts
are evaluated a bit late in the parsing process)
[1]: IIRC x86 GDC uses the same calling convention for both, and DMD
uses a very similar convention in case of varargs.
[2]: As detailed in http://www.x86-64.org/documentation/abi.pdf,
specifically the section "Parameter passing" on pages 15-22.
[3]: Or a va_arg variant that uses a run-time TypeInfo argument instead
of a compile-time template type argument...
More information about the Digitalmars-d-announce
mailing list