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

Reply via email to