August 01, 2017
https://bugzilla.gdcproject.org/show_bug.cgi?id=268

--- Comment #1 from Johannes Pfau <johannespfau@gmail.com> ---
After some investigation I don't think we can implement thunks for variadic functions in a portable way.

AFAICS the FUNCTION_DECL tree in GCC does not contain any information that this function can be called with varargs so all functions in theory are vararg capable. The build_call functions determine whether vararg ABI should be used simply by comparing the number of specified parameters to the number of declared parameters.

Because all this is 'implicit', there's no generic way to 'pass on' variadic arguments to another function. There's no 'pass all args' implementation in GCC and a manual va_start/va_arg/... can't work either, as there's no information about the number of arguments in general.

Now (this-adjusting) thunks are pretty simple functions so 'pass-on' for varargs can work for these functions. The key is not messing with any registers or stack space in the thunk. However, as GCC does not even have a portable naked attribute, there's no generic way to implement this. This leads to some interesting effects:

------------------------------------------------------------------------------
import core.vararg;
extern(C) int someFunctionI1_Thunk(void* v, int a, ...);
void main()
{ someFunctionI1_Thunk(cast(void*)0, 10, 1, 2, 3, 4, 5, 6,7, 8, 9, 10); }
------------------------------------------------------------------------------
import std.stdio;
import core.vararg;

extern(C) int someFunctionI1(void* v, int a, ...)
{
    va_list va;
    va_start(va, a);
    int param;
    for (int i = 0; i < a; i++)
    {
        va_arg!int(va, param);
        writeln(param);
    }
    va_end(va);
    return 0;
}
------------------------------------------------------------------------------
extern(C) int someFunctionI1(void* v, int a, ...);

extern(C) int someFunctionI1_Thunk(void* v, int a)
{
    return someFunctionI1(v+10, a);
}
------------------------------------------------------------------------------

When compiled with optimizations, this works perfectly as tail call optimization removes the prologue/epilogue of someFunctionI1_Thunk and the add is directly performed on the register. But without optimization, this breaks.

So portable thunks for variadic function may be possible, as long as these thunks only add to the register containing the this pointer and then directly jump to the target, but I'm not aware of portably representing this in GCC.


I'll probably still implement thunks for non-variadic functions in the frontend for GCC <= 4.9. This is trivial to implement and all cases except for variadic functions should work. With optimizations, the resulting code is equivalent to the GCC thunk code. Without optimizations there's obviously some performance impact, but backporting 'force_gimple_thunk' for GCC <= 4.9 is probably not worth the effort.

BTW @ Iain: Why do GCC thunks generate aliases to the target function? Is this an optimization, a workaround for assembler / linker bugs or something entirely different?

-- 
You are receiving this mail because:
You are watching all bug changes.
August 24, 2017
https://bugzilla.gdcproject.org/show_bug.cgi?id=268

Johannes Pfau <johannespfau@gmail.com> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
             Status|NEW                         |RESOLVED
         Resolution|---                         |WONTFIX

--- Comment #2 from Johannes Pfau <johannespfau@gmail.com> ---
I don't think we can get variadic thunks in a generic way, so there's no real benefit for newer GCC versions. Additionally, the frontend thunks will be slower without optimization.

I'll just mark the 'external thunks' in GCC <= 4.9 as won't fix, thunks in all other GCC versions should work as expected.

-- 
You are receiving this mail because:
You are watching all bug changes.