> On 17 Dec 2024, at 5:44 AM, Alexander Monakov <amona...@ispras.ru> wrote:
> 
> 
>> On Mon, 16 Dec 2024, Florian Weimer via Gcc wrote:
>> 
>> I would like to provide a facility to create wrapper functions without
>> lots of argument shuffling.  To achieve that, the wrapping function and
>> the wrapped function should have the same prototype.  There will be a
>> trampoline that puts additional data somewhere (possibly including the
>> address of the wrapped function, but that interpretation is up to the
>> wrapping function) and then transfers control to the wrapper function
>> with an indirect jump (tail call).
>> 
>> For signal safety, I think the hidden argument needs to be in a register
>> (instead of, say, thread-local storage).  Most System V ABI variants
>> seem to reserve a register for use by the dynamic linker, or for the
>> static chain pointer of nested functions.
>> 
>> Is there a way to reuse either register for this purpose and assign it
>> to a local variable reliably at the start of the wrapper function
>> implementation?
> 
> Not in a way that will work with LLVM, I'm afraid, and with GCC
> you'll have to shield wrappers from LTO:
> 
> register void *r10 asm("r10");
> void f(int, int);
> void f_wrap(int a, int b)
> {
>    r10 = f;
>    f(a, b);
> }
> 
> LLVM refuses to translate this. With GCC you must compile with -ffixed-r10,
> otherwise r10 is not reserved, and GCC will warn:
> 
> warning: call-clobbered register used for global register variable
>    1 | register void *r10 asm("r10");
>      |                ^~~:
> 
> 
> This is the only approach I'm aware of, apart of generating wrappers
> in asm (speaking of, is there some reason that wouldn't work for you?).

I have a similar use case for replacing a scalar version of a function with a 
vector version. the vector version has some constant reference data that I want 
to hoist into the caller because it is called in a loop. I don't know how to do 
that without breaking iinterface encapsulation and using ifdef to manually 
hoist the uniform reference data into the caller. also I want it to be 
controlled not at the mercy of random optimizations.

in some trusted environment if I had a transient fiield in a context structure 
passed by pointer that the function loaded into a vector register, then if the 
caller checked an identity invariant (context pointer identity does not change 
in the loop) then it could hoist some vector loads into the caller’s loop 
header. but that wouldn’t work for extern. you would need some vector extern 
ABI for functions called in loops that have a setup call that needs to be 
called in a loop header.

it’s due to loads of vector reference data with requirements for interface 
encapsulation for scalar code which tends to make you want to preserve a simple 
calling convention for the function user. in vulkan you would bind a uniform 
into the function’s environment. but we don't want the caller to need to know 
in advance what might be hoisted.

so I want a function designed for loops to export an implicit loop header setup 
stub contingent on the identity of a context pointer. the calling convention 
says the caller needs to call the setup stub if the context identity changes. 
you could do that with attributes on the context identity and an outline 
function containing the hoist. I could then have a loop header setup call that 
is consistent with both scalar or vector code and the scalar version is 
probably empty.

reference data loads for shuffles are huge.

Reply via email to