[Bug target/32871] [avr] Bad optimisation - gcc is pushing too many registers

hutchinsonandy at aim dot com gcc-bugzilla@gcc.gnu.org
Sun Mar 2 17:22:00 GMT 2008



------- Comment #3 from hutchinsonandy at aim dot com  2008-03-02 17:22 -------
Problem is caused by bug in gcc DF or at least incorrect documentation
regarding prolog/epilog register save/resotres

As specified in internals manual AVR prolog/epilog uses
df_regs_ever_live_p(reg) to determine which register should be saved on stack
(if it is not call_used_register).

However, if function has arguments that are stored in non call_used_registers
(R8-R17), then this test gives incorrect result and these registers will always
saved/restored by prolog/epilog.  (Argument register never need to be
saved/restored.)


This problem only applies to targets that pass arguments in non
call_used_registers.

Unfortunately no part of gcc including DF appears to have proper information to
use directly.

In the absence of a change to gcc, the target can determine which registers are
REALLY used as arguments and exclude these from save/restores.  So it requires
going thru all function arguments again using target argument macros.

Will post patch when it's finished testing. But here is key routine:

/* Returns HARD_REG_SET indicating which registers are used for arguments */

static void
avr_args (HARD_REG_SET *set)
{
    int reg;
    int i;
    rtx arg;
    CUMULATIVE_ARGS cum;

    tree decl = DECL_ARGUMENTS (current_function_decl);
    INIT_CUMULATIVE_ARGS (cum, TREE_TYPE (current_function_decl), NULL_RTX,
decl, -1);

    for (; decl; decl = TREE_CHAIN (decl))
    {
        if ( TREE_CODE (decl) == PARM_DECL
        && DECL_NAME (decl) && !DECL_ARTIFICIAL (decl))  
       {
           enum machine_mode mode = DECL_MODE (decl);
            /* Get argument RTX */
            /* This target does not use named attribute */
            arg = FUNCTION_ARG (cum, mode, DECL_ARG_TYPE (decl), 1);
            FUNCTION_ARG_ADVANCE (cum, mode, DECL_ARG_TYPE (decl), 1);
            if REG_P(arg)
            {
                reg = REGNO (arg);
                for (i = 0;i < HARD_REGNO_NREGS (reg, mode);i++)
                {
                  if (set)
                      SET_HARD_REG_BIT (*set, reg + i);  
                }
            }
        }
    }
}


-- 


http://gcc.gnu.org/bugzilla/show_bug.cgi?id=32871



More information about the Gcc-bugs mailing list