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; }