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]

Fix postreload liveness computation


reload_combine walks the instructions from beginning to end, optimising
across basic-block boundaries if one block falls through to the next.
This behaviour mimics reload, which inherits registers as part of a
similarly-constrained forward pass.

Unfortunately, not all live_at_start sets are valid before reload_combine:

  /* Set up LABEL_LIVE and EVER_LIVE_AT_START.  The register lifetime
     information is a bit fuzzy immediately after reload, but it's
     still good enough to determine which registers are live at a jump
     destination.  */

I think what it means by "a bit fuzzy" is that the liveness is wrong
in cases where reload might inherit across a block boundary.  In other
words, the liveness is wrong for blocks that are only reached via
fallthru edges.  So, rather than look at the live_at_end sets directly,
reload_combine instead tries to work out the liveness from the known-valid
live_at_start sets.  The problem is that it does so only for jumps;
it doesn't consider exceptional edges.  This causes a miscompilation
of eh_personality.cc on sh-elf with a patch I'm working on.

The CFG itself is valid at this point, so I think the fix is simply
to compute the union of all successor non-fallthru live_at_start sets.

Bootstrapped & regression-tested on x86_64-linux-gnu.  Also
regression-tested on sh-elf (,-m2,-m3,-m4,-m4/-ml).  OK to install?

Richard


gcc/
	* postreload.c (LABEL_LIVE): Delete.
	(reload_combine): Create an array of hard sets for each basic
	block, rather than for each label.  At the end of a basic block,
	treat the registers live on entry to non-fallthru successors
	as being live.

Index: gcc/postreload.c
===================================================================
--- gcc/postreload.c	2007-05-21 17:19:00.000000000 +0100
+++ gcc/postreload.c	2007-05-21 17:19:07.000000000 +0100
@@ -688,9 +688,6 @@ struct reg_use { rtx insn, *usep; };
    and the store_ruid / use_ruid fields in reg_state.  */
 static int reload_combine_ruid;
 
-#define LABEL_LIVE(LABEL) \
-  (label_live[CODE_LABEL_NUMBER (LABEL) - min_labelno])
-
 static void
 reload_combine (void)
 {
@@ -698,11 +695,12 @@ reload_combine (void)
   int first_index_reg = -1;
   int last_index_reg = 0;
   int i;
-  basic_block bb;
+  basic_block bb, new_bb;
   unsigned int r;
   int last_label_ruid;
-  int min_labelno, n_labels;
-  HARD_REG_SET ever_live_at_start, *label_live;
+  HARD_REG_SET *live, *bb_live_at_start, *all_live, all_live_tmp;
+  edge_iterator ei;
+  edge e;
 
   /* If reg+reg can be used in offsetable memory addresses, the main chunk of
      reload has already used it where appropriate, so there is no use in
@@ -725,29 +723,18 @@ reload_combine (void)
   if (first_index_reg == -1)
     return;
 
-  /* Set up LABEL_LIVE and EVER_LIVE_AT_START.  The register lifetime
-     information is a bit fuzzy immediately after reload, but it's
-     still good enough to determine which registers are live at a jump
-     destination.  */
-  min_labelno = get_first_label_num ();
-  n_labels = max_label_num () - min_labelno;
-  label_live = XNEWVEC (HARD_REG_SET, n_labels);
-  CLEAR_HARD_REG_SET (ever_live_at_start);
-
-  FOR_EACH_BB_REVERSE (bb)
-    {
-      insn = BB_HEAD (bb);
-      if (LABEL_P (insn))
-	{
-	  HARD_REG_SET live;
-
-	  REG_SET_TO_HARD_REG_SET (live,
-				   bb->il.rtl->global_live_at_start);
-	  compute_use_by_pseudos (&live,
-				  bb->il.rtl->global_live_at_start);
-	  COPY_HARD_REG_SET (LABEL_LIVE (insn), live);
-	  IOR_HARD_REG_SET (ever_live_at_start, live);
-	}
+  /* Set up BB_LIVE_AT_START[B] to the set of hard registers live at
+     the beginning of block B.  This information is only valid for
+     the entry and exit blocks, or for those that start with labels.
+     The live-at-start sets are no longer valid for blocks that are
+     only reached via fallthrough; reload may have inherited from the
+     previous block.  */
+  bb_live_at_start = XNEWVEC (HARD_REG_SET, last_basic_block);
+  FOR_ALL_BB (bb)
+    {
+      live = &bb_live_at_start[bb->index];
+      REG_SET_TO_HARD_REG_SET (*live, bb->il.rtl->global_live_at_start);
+      compute_use_by_pseudos (live, bb->il.rtl->global_live_at_start);
     }
 
   /* Initialize last_label_ruid, reload_combine_ruid and reg_state.  */
@@ -761,6 +748,7 @@ reload_combine (void)
 	reg_state[r].use_index = RELOAD_COMBINE_MAX_USES;
     }
 
+  bb = NULL;
   for (insn = get_last_insn (); insn; insn = PREV_INSN (insn))
     {
       rtx note;
@@ -778,6 +766,35 @@ reload_combine (void)
       if (! INSN_P (insn))
 	continue;
 
+      /* See if INSN is the end of a basic block.  */
+      new_bb = BLOCK_FOR_INSN (insn);
+      if (new_bb && new_bb != bb)
+	{
+	  bb = new_bb;
+	  all_live = NULL;
+	  FOR_EACH_EDGE (e, ei, new_bb->succs)
+	    if ((e->flags & EDGE_FALLTHRU) == 0)
+	      {
+		live = &bb_live_at_start[e->dest->index];
+		if (!all_live)
+		  all_live = live;
+		else
+		  {
+		    if (all_live != &all_live_tmp)
+		      {
+			COPY_HARD_REG_SET (all_live_tmp, *all_live);
+			all_live = &all_live_tmp;
+		      }
+		    IOR_HARD_REG_SET (all_live_tmp, *live);
+		  }
+	      }
+
+	  if (all_live)
+	    for (i = FIRST_PSEUDO_REGISTER - 1; i >= 0; --i)
+	      if (TEST_HARD_REG_BIT (*all_live, i))
+		reg_state[i].use_index = -1;
+	}
+
       reload_combine_ruid++;
 
       /* Look for (set (REGX) (CONST_INT))
@@ -939,23 +956,6 @@ reload_combine (void)
 	     }
 
 	}
-      else if (JUMP_P (insn)
-	       && GET_CODE (PATTERN (insn)) != RETURN)
-	{
-	  /* Non-spill registers might be used at the call destination in
-	     some unknown fashion, so we have to mark the unknown use.  */
-	  HARD_REG_SET *live;
-
-	  if ((condjump_p (insn) || condjump_in_parallel_p (insn))
-	      && JUMP_LABEL (insn))
-	    live = &LABEL_LIVE (JUMP_LABEL (insn));
-	  else
-	    live = &ever_live_at_start;
-
-	  for (i = FIRST_PSEUDO_REGISTER - 1; i >= 0; --i)
-	    if (TEST_HARD_REG_BIT (*live, i))
-	      reg_state[i].use_index = -1;
-	}
 
       reload_combine_note_use (&PATTERN (insn), insn);
       for (note = REG_NOTES (insn); note; note = XEXP (note, 1))
@@ -971,7 +971,7 @@ reload_combine (void)
 	}
     }
 
-  free (label_live);
+  free (bb_live_at_start);
 }
 
 /* Check if DST is a register or a subreg of a register; if it is,


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