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

Richard Sandiford <rsandifo at gcc dot gnu.org> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
                 CC|                            |rsandifo at gcc dot gnu.org

--- Comment #5 from Richard Sandiford <rsandifo at gcc dot gnu.org> ---
Created attachment 58964
  --> https://gcc.gnu.org/bugzilla/attachment.cgi?id=58964&action=edit
Proof of concept patch

The problem seems to be a bad interaction between spilling and register
elimination.  I think it would only occur on targets that use a real target
register as FRAME_POINTER_REGNUM, rather than having a separate
FRAME_POINTER_REGNUM and HARD_FRAME_POINTER_REGNUM.

IRA sees:

(insn 47 46 48 2 (set (reg:QI 24 r24 [+6 ])
        (mem:QI (reg/f:HI 58) [1 *p_2(D)+6 S1 A8 AS1])) "pr116321.c":6:1 86
{movqi_insn_split}
     (expr_list:REG_DEAD (reg/f:HI 58)
        (nil)))
(insn 48 47 49 2 (set (reg:QI 25 r25 [+7 ])
        (mem:QI (reg/f:HI 60) [1 *p_2(D)+7 S1 A8 AS1])) "pr116321.c":6:1 86
{movqi_insn_split}
     (expr_list:REG_DEAD (reg/f:HI 60)
        (nil)))

where both instructions need an r30 base.  As it happens, IRA assigns r30 to
r60 .  However, when it comes to reloading earlier insns, we have to use r30
for the base even though r60 is live, so we need to spill r60:

********** Assignment #1: **********

         Assigning to 91 (cl=POINTER_Z_REGS, orig=58, freq=2000, tfirst=91,
tfreq=2000)...
         Trying 30: spill 60(freq=2000)  Now best 30(cost=0, bad_spills=0,
insn_pseudos=0)

         Trying 31: spill 60(freq=2000)
      Spill r60(hr=30, freq=2000) for r91
           Assign 30 to reload r91 (freq=2000)
         Assigning to 85 (cl=LD_REGS, orig=50, freq=3000, tfirst=85,
tfreq=3000)...
           Assign 30 to reload r85 (freq=3000)
         Assigning to 86 (cl=LD_REGS, orig=52, freq=3000, tfirst=86,
tfreq=3000)...
           Assign 30 to reload r86 (freq=3000)
         Assigning to 87 (cl=LD_REGS, orig=54, freq=3000, tfirst=87,
tfreq=3000)...
           Assign 30 to reload r87 (freq=3000)
         Assigning to 88 (cl=LD_REGS, orig=56, freq=3000, tfirst=88,
tfreq=3000)...
           Assign 30 to reload r88 (freq=3000)
         Assigning to 89 (cl=LD_REGS, orig=58, freq=3000, tfirst=89,
tfreq=3000)...
           Assign 26 to reload r89 (freq=3000)
         Assigning to 90 (cl=LD_REGS, orig=77, freq=3000, tfirst=90,
tfreq=3000)...
           Assign 24 to reload r90 (freq=3000)
  Reassigning non-reload pseudos
           Assign 28 to r60 (freq=2000)

where r28 is the eliminated FRAME_POINTER_REGNUM.  So far so good (AFAICT). 
But when trying to reload insn 48 after the spill, we use get_reg_class to work
out what class the base register (r60) has.  This is structured as:

  if (! HARD_REGISTER_NUM_P (hard_regno = regno))
    hard_regno = lra_get_regno_hard_regno (regno);
  if (hard_regno >= 0)
    {
      hard_regno = lra_get_elimination_hard_regno (hard_regno);
      return REGNO_REG_CLASS (hard_regno);
    }

So we replace r60 with r28 thanks to the assignment, but then apply
eliminations to r28 to get r32 (the stack pointer).  Things go downhill from
there.

This patch is a naive proof-of-concept fix, on the basis that eliminations
should only apply to registers that aren't subject to allocation.  But I
imagine something somewhere else will break.

Reply via email to