https://gcc.gnu.org/bugzilla/show_bug.cgi?id=128546
Bug ID: 128546
Summary: [m68k] LRA splits hard reg live ranges forever when a
split succeeds but the reload pseudo still cannot be
assigned
Product: gcc
Version: 16.2.1
Status: UNCONFIRMED
Severity: normal
Priority: P3
Component: rtl-optimization
Assignee: unassigned at gcc dot gnu.org
Reporter: bernie at codewiz dot org
Target Milestone: ---
Created attachment 66107
--> https://gcc.gnu.org/bugzilla/attachment.cgi?id=66107&action=edit
patch candidate
With -mlra, m68k-linux-gnu-gcc 16.2.1 never returns on the attached testcase,
at -O2 with -m68000 or -m68020:
$ m68k-linux-gnu-gcc -O2 -mlra -S lra-split-loop.c
(never returns)
Without -mlra, old reload stops with "unable to find a register to spill in
class 'DATA_REGS'".
All eight data registers hold live values across the short compare,
so the compare's reload pseudo, which needs DATA_REGS, cannot be assigned.
This is the -fdump-rtl-reload output, repeated for each pass:
********** Assignment #N: **********
2nd iter for reload pseudo assignments:
Reload r50 assignment failure
****** Splitting a hard reg after assignment #N: ******
Creating newreg=51 from oldreg=0, assigning class DATA_REGS to split
r51
27: pc={(r50:HI<=0x6)?L41:pc}
...
Spill r51 after risky transformations
After about 10 seconds the dump had 1,056 assignment passes and 1,055
splits. Every pass is the same: the split succeeds, the new split pseudo
needs DATA_REGS as well and is spilled, and r50 fails again.
Nothing in lra() stops this:
- LRA_MAX_FAILED_SPLITS (PR115458) only counts calls to
lra_split_hard_reg_for() that return false. Here every call splits
something and returns true.
- The "maximum number of LRA assignment passes is achieved" internal error
in lra_assign() only exists with flag_checking. A compiler built with
checking enabled probably stops there after about 30 passes, with an ICE.
A release-checking build such as 16.2.1 never stops.
- lra_bad_spill_regno_start only engages after the inheritance and
rematerialization passes are exhausted, and they aren't here.
PR109520 is the same cycle with an asm insn. r14-2500 fixed it by reporting
impossible asm constraints. A non-asm insn can still loop.
This came up in m68k-amigaos, where LRA is the default: a function whose
register arguments occupy d0-d7 and that passes them on to a call hangs
since we started passing short register arguments in HImode.
The attached testcase gets the same register pressure with local register
variables.
Proposed fix
------------
Count every split attempt, not only the failed ones. After LRA_MAX_SPLITS
(30) attempts, call lra_split_hard_reg_for() with a new SPLIT_P argument set
to false.
It then splits nothing and reports the failed reload pseudos through
its existing "unable to find a register to spill" path, as it already
does after LRA_MAX_FAILED_SPLITS failed splits.
With the proposed patch, 16.2.1 stops on the testcase after 20 ms:
lra-split-loop.c: In function 'f':
lra-split-loop.c:28:1: error: unable to find a register to spill
lra-split-loop.c:28:1: error: this is the insn:
(jump_insn 27 49 28 2 (set (pc)
(if_then_else (le (reg:HI 50 [orig:46 _3 ] [46])
(const_int 6 [0x6]))
(label_ref:SI 41)
(pc))) "lra-split-loop.c":23:6 7 {cbranchhi4_insn}
(expr_list:REG_DEAD (reg:HI 50 [orig:46 _3 ] [46])
(int_list:REG_BR_PROB 365072225 (nil)))
-> 41)
lra-split-loop.c:28: confused by earlier errors, bailing out
Whether 30 is the right bound is open. LRA_MAX_FAILED_SPLITS is 10, and
PR115458 needed more than one successful split. The patch makes the bound
an independent macro, with a check that it is above LRA_MAX_FAILED_SPLITS.
The new count starts again in each constraint round, as split_fails_num
does. A cycle that went back through the constraint loop with fewer than
30 splits per round would still not terminate. I haven't seen one, and LRA
has no other unconditional limit on constraint rounds that would catch it.
ChangeLog, for gcc-patches:
PR rtl-optimization/NNNNNN
* lra-int.h (LRA_MAX_SPLITS): Define and check its value.
(lra_split_hard_reg_for): Add SPLIT_P parameter.
* lra-assigns.cc (lra_split_hard_reg_for): Do not split when
SPLIT_P is false.
* lra.cc (lra): Count all hard reg split attempts and stop
splitting after LRA_MAX_SPLITS.