This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

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


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]