This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
PR 34998: Tracking of subreg liveness in global.c and ra-conflict.c
- From: Richard Sandiford <rsandifo at nildram dot co dot uk>
- To: gcc-patches at gcc dot gnu dot org
- Date: Tue, 29 Jan 2008 10:16:20 +0000
- Subject: PR 34998: Tracking of subreg liveness in global.c and ra-conflict.c
gcc.c-torture/execute/20040709-1.c fails for -EL -mips16 -O3 with:
20040709-1.c:93: internal compiler error: in insert_save, at caller-save.c:745
This is due to the new subreg liveness tracking. We have a pseudo
register FOO and a bb that contains:
A: call
...
B: set of (subreg:HI (reg:SI foo))
...
C: use of (reg:SI foo)
There are no other references to (reg:SI foo) in the function.
We allocate FOO a call-clobbered register, and wrongly think that it is
still live at A. We then abort because we weren't expecting to have to
save and restore FOO's hard register around A.
The reason we get the liveness wrong is that global.c:build_insn_chain
tracks the liveness of each byte of FOO separately, and it treats an
assignment to a subreg as clobbering only the bytes mentioned in that
subreg. However, if an assignment to a subreg of a pseudo only sets
part of a word, the other bytes in that word are supposed to be clobbered
(that is, they become "don't care" bits).
Bootstrapped & regression-tested on x86_64-linux-gnu. Also
regression-tested on mipsisa64-elfoabi. OK to install?
Richard
gcc/
PR rtl-optimization/34998
* ra-conflict.c (clear_reg_in_live): Treat SUBREGs of pseudos
as clobbering all the words covered by the SUBREG, not just all
the bytes.
* global.c (build_insn_chain): Likewise.
Index: gcc/ra-conflict.c
===================================================================
--- gcc/ra-conflict.c 2008-01-28 14:17:58.000000000 +0000
+++ gcc/ra-conflict.c 2008-01-28 14:27:19.000000000 +0000
@@ -467,6 +467,11 @@ clear_reg_in_live (sparseset allocnos_li
ra_init_live_subregs (sparseset_bit_p (allocnos_live, allocnum),
live_subregs, live_subregs_used, allocnum, reg);
+ /* Expand the range to cover entire words.
+ Bytes added here are "don't care". */
+ start = start / UNITS_PER_WORD * UNITS_PER_WORD;
+ last = (last + UNITS_PER_WORD - 1) / UNITS_PER_WORD * UNITS_PER_WORD;
+
/* Ignore the paradoxical bits. */
if ((int)last > live_subregs_used[allocnum])
last = live_subregs_used[allocnum];
Index: gcc/global.c
===================================================================
--- gcc/global.c 2008-01-28 14:04:44.000000000 +0000
+++ gcc/global.c 2008-01-28 14:42:27.000000000 +0000
@@ -1501,6 +1501,13 @@ build_insn_chain (void)
live_subregs,
live_subregs_used,
regno, reg);
+
+ /* Expand the range to cover entire words.
+ Bytes added here are "don't care". */
+ start = start / UNITS_PER_WORD * UNITS_PER_WORD;
+ last = ((last + UNITS_PER_WORD - 1)
+ / UNITS_PER_WORD * UNITS_PER_WORD);
+
/* Ignore the paradoxical bits. */
if ((int)last > live_subregs_used[regno])
last = live_subregs_used[regno];