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