https://gcc.gnu.org/bugzilla/show_bug.cgi?id=64151

--- Comment #2 from Wilco <wdijkstr at arm dot com> ---
(In reply to H.J. Lu from comment #1)
> Revert the reg_class change:
> 
> diff --git a/gcc/ira-costs.c b/gcc/ira-costs.c
> index 72c00cc..16fd6e8 100644
> --- a/gcc/ira-costs.c
> +++ b/gcc/ira-costs.c
> @@ -1466,7 +1466,7 @@ scan_one_insn (rtx_insn *insn)
>          && REG_N_SETS (REGNO (SET_DEST (set))) == 1))
>        && general_operand (SET_SRC (set), GET_MODE (SET_SRC (set))))
>      {
> -      enum reg_class cl = ALL_REGS;
> +      enum reg_class cl = GENERAL_REGS;
>        rtx reg = SET_DEST (set);
>        int num = COST_INDEX (REGNO (reg));
> 
> fixes those regressions.

Confirmed. The intention of this code is to account for reduced memory cost of
constant loads - when they spill they do not need a store, but can be trivially
rematerialized. What happens is that memory_move_cost returns 100 for certain
cases on x86. With ALL_REGS the mem_cost then becomes very negative as it is
not clamped to zero and this forces the register allocator to spill. This is
bad as __builtin_longjmp on x86 loads EBP/ESP directly via 2 separate
instructions which means reload *may* insert spill code inbetween. So if the
base register is spilled and reloaded via EBP, it corrupts ESP:

        movl    -4(%ebp), %edx
        movl    (%edx), %ebp     * restore EBP
        movl    -4(%ebp), %ecx   * oops, this uses a different EBP
        movl    8(%ecx), %esp
        jmp     *%eax

I think there are cases where reload just gives up and inserts dumb spill code
(ie. one reload per use), which means this issue can happen under other
circumstances as well.

It appears ALL_REGS works for x86 and avoids the regression, however this is
not correct either for FP or SIMD registers which would get 100 and then get
spilled.

Reply via email to