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

            Bug ID: 65827
           Summary: LRA use smaller reg class than original reg for reload
                    and it spill fail if reg class no hard reg available
           Product: gcc
           Version: 5.0
            Status: UNCONFIRMED
          Severity: normal
          Priority: P3
         Component: rtl-optimization
          Assignee: unassigned at gcc dot gnu.org
          Reporter: npickito at gmail dot com

Created attachment 35375
  --> https://gcc.gnu.org/bugzilla/attachment.cgi?id=35375&action=edit
LRA dump

Target: nds32le-elf
Configure option: --target=nds32le-elf --enable-languages=c
--enable-checking=yes
Testcase: gcc.c-torture/execute/pr65427.c

What's happen:
../../src-5.0.0/gcc/testsuite/gcc.c-torture/execute/pr65427.c: In function
‘foo’:
../../src-5.0.0/gcc/testsuite/gcc.c-torture/execute/pr65427.c:17:1: error:
unable to find a register to spill
 }
 ^
../../src-5.0.0/gcc/testsuite/gcc.c-torture/execute/pr65427.c:17:1: error: this
is the insn:
(insn 91 73 221 2 (set (reg/f:SI 227 [143])
        (symbol_ref:SI ("b") <var_decl 0x7f9543aa3360 b>))
../../src-5.0.0/gcc/testsuite/gcc.c-torture/execute/pr65427.c:14 28
{*move_addr}
     (expr_list:REG_EQUIV (symbol_ref:SI ("b") <var_decl 0x7f9543aa3360 b>)
        (nil)))
../../src-5.0.0/gcc/testsuite/gcc.c-torture/execute/pr65427.c:17:1: internal
compiler error: in assign_by_spills, at lra-assigns.c:1428
0xa09f78 _fatal_insn(char const*, rtx_def const*, char const*, int, char
const*)
    ../../../../src-5.0.0/gcc/rtl-error.c:110
0x92beca assign_by_spills
    ../../../../src-5.0.0/gcc/lra-assigns.c:1428
0x92c593 lra_assign()
    ../../../../src-5.0.0/gcc/lra-assigns.c:1603
0x928149 lra(_IO_FILE*)
    ../../../../src-5.0.0/gcc/lra.c:2365
0x8e8ea9 do_reload
    ../../../../src-5.0.0/gcc/ira.c:5418
0x8e8ea9 execute
    ../../../../src-5.0.0/gcc/ira.c:5589


How to reproduce:
nds32le-elf-gcc testsuite/gcc.c-torture/execute/pr65427.c -O2

What's happen in detail:
(full lra dump in attachment)
...
            0 Non input pseudo reload: reject++
          alt=0,overall=7,losers=1,rld_nregs=1
            0 Non input pseudo reload: reject++
          alt=1,overall=7,losers=1,rld_nregs=1
         Choosing alt 0 in insn 91:  (0) =l  (1) i {*move_addr} (sp_off=-224)
      Creating newreg=227 from oldreg=143, assigning class LOW_REGS to r227 
   91: r227:SI=`b'
      REG_EQUIV `b'
    Inserting insn reload after:
  221: r143:SI=r227:SI
...

LOW_REGS = r0-r7
GENERAL_REGS = r0-r31

r227 is create from r143 and it's pick LOW_REGS,
and then LRA can't find any register to spill in LOW_REGS class since all
register in LOW_REGS are used by our movmemqi expander.

However reg_pref[r143].allocnoclass is GENERAL_REGS
and its have available hard. register,
but LRA don't get try for that and give up,


r227 setup it's reg class in:

lra-constraints.c
3844           if (get_reload_reg (type, mode, old, goal_alt[i],
3845                               loc != curr_id->operand_loc[i], "",
&new_reg)

So I think does LRA should consider the allocno class for original reg,
not just the goal_alt[i] of this point?



Possible solution:

Setup prefclass from goal_alt but set allocnoclass from orig_reg's allocnoclass
if possible

diff --git a/gcc/lra.c b/gcc/lra.c
index f4d7a3c..601aec4 100644
--- a/gcc/lra.c
+++ b/gcc/lra.c
@@ -212,6 +212,7 @@ lra_create_new_reg_with_unique_value (machine_mode md_mode,
rtx original,
                       enum reg_class rclass, const char *title)
 {
   machine_mode mode;
+  enum reg_class orig_rclass;
   rtx new_reg;

   if (original == NULL_RTX || (mode = GET_MODE (original)) == VOIDmode)
@@ -243,7 +244,16 @@ lra_create_new_reg_with_unique_value (machine_mode
md_mode, rtx original,
       fprintf (lra_dump_file, "\n");
     }
   expand_reg_data (max_reg_num ());
-  setup_reg_classes (REGNO (new_reg), rclass, NO_REGS, rclass);
+
+  if (REG_P (original))
+    orig_rclass = reg_allocno_class (REGNO (original));
+  else
+    orig_rclass = NO_REGS;
+
+  setup_reg_classes (REGNO (new_reg),
+             rclass,
+             NO_REGS,
+             orig_rclass == NO_REGS ? rclass: orig_rclass);
   return new_reg;
 }

Reply via email to