Bug 65827 - LRA use smaller reg class than original reg for reload and it spill fail if reg class no hard reg available
Summary: LRA use smaller reg class than original reg for reload and it spill fail if r...
Status: RESOLVED FIXED
Alias: None
Product: gcc
Classification: Unclassified
Component: rtl-optimization (show other bugs)
Version: 5.0
: P3 normal
Target Milestone: ---
Assignee: Not yet assigned to anyone
URL:
Keywords: missed-optimization, ra
Depends on:
Blocks:
 
Reported: 2015-04-21 09:59 UTC by Kito Cheng
Modified: 2017-01-07 12:30 UTC (History)
2 users (show)

See Also:
Host:
Target: nds32le-elf
Build:
Known to work:
Known to fail:
Last reconfirmed:


Attachments
LRA dump (9.42 KB, text/plain)
2015-04-21 09:59 UTC, Kito Cheng
Details

Note You need to log in before you can comment on or make changes to this bug.
Description Kito Cheng 2015-04-21 09:59:18 UTC
Created attachment 35375 [details]
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;
 }
Comment 1 Andrew Pinski 2016-09-22 07:49:37 UTC
This might have been fixed already.
Comment 2 Chung-Ju Wu 2017-01-07 12:30:24 UTC
(In reply to Andrew Pinski from comment #1)
> This might have been fixed already.

Thanks to reminder. :)
Yes, after I try this PR on trunk, the problem no longer exist.

Target:
  nds32le-elf
Configure option:
  -target=nds32le-elf
  --enable-languages=c
  --enable-checking=yes
  --disable-multilib
Testcase:
  gcc.c-torture/execute/pr65427.c
GCC version:
  gcc version 7.0.0 20170101 (experimental) (GCC)

So I think the status can be set as RESOLVED-FIXED.