Playing with a new avr function attribute, I stumbled upon this problem:
On avr, all varargs arguments are passed on the stack, even the named
ones. So I added a "rargs" function attribute that passes named args in
registers if possible. One test case looks like this:
#define RA __attribute__((rargs))
void call_rafun_cast1 (void (*f)(char, ...))
{
((RA void(*)(char,...)) f) (10);
}
void call_rafun_cast0 (RA void (*f)(char, ...))
{
((void(*)(char,...)) f) (20);
}
The code compiles as expected:
// rargs: no push/pop
call_rafun_cast1:
movw r30,r24 ; 20 [c=4 l=1] *movhi/0
ldi r24,lo8(10) ; 14 [c=4 l=1] movqi_insn/1
ijmp ; 7 [c=0 l=1] call_insn/2
// default: push/pop.
call_rafun_cast0:
ldi r18,lo8(20) ; 15 [c=4 l=1] movqi_insn/1
push r18 ; 7 [c=4 l=1] pushqi1/0
movw r30,r24 ; 23 [c=4 l=1] *movhi/0
icall ; 8 [c=0 l=1] call_insn/0
; SP += 1 ; 9 [c=8 l=1] *addhi3_sp
pop __tmp_reg__
ret ; 19 [c=0 l=1] return
Notice that cast0 has a push / pop of the argument as expected, while
cast1 hasn't, also as expected. This is all fine. Now change the code
slightly so that the function bodies become the same (pass 10 instead of
20):
void call_rafun_cast0 (RA void (*f)(char, ...))
{
((void(*)(char,...)) f) (10);
}
The code compiles to:
call_rafun_cast0:
rjmp call_rafun_cast1 ; 7 [c=0 l=1] call_insn/3
which is wrong IMO. The bodies of the functions are the same, but the
prototypes are not, so performing ICF is wrong.
I am not completely sure about a function pointer cast adding / removing
a function attribute. Though GCC seems to compile it as expected
without ICF.
So is this an ICF bug or am I missing some target hook?
For now I only changed the cumulative args hooks, but there are some
VA_LIST and VA_ARG hooks in
https://gcc.gnu.org/onlinedocs/gccint/Register-Arguments.html where I
don't know what to do with them.
All unnamed args are passed the same way in either case; the attribute
only affects passing of named args.
GCC is current trunk.
Johann