2011-03-09  Bernd Schmidt  <bernds@codesourcery.com>

	Issue #10649
	gcc/
	* dwarf2out.c (dwarf2out_begin_epilogue): Accept simplejumps
	as well as returnjumps.
	* cfganal.c (set_edge_can_fallthru_flag): Revert previous change
	that tried to keep epilogue blocks adjacent.

2011-02-03  Bernd Schmidt  <bernds@codesourcery.com>

	gcc/
	* function.c (prepare_shrink_wrap): New function.
	(thread_prologue_and_epilogue_insns): Call it.

=== modified file 'gcc/cfganal.c'
--- old/gcc/cfganal.c	2011-02-08 10:51:58 +0000
+++ new/gcc/cfganal.c	2011-03-10 14:55:10 +0000
@@ -271,37 +271,6 @@
       EDGE_SUCC (bb, 0)->flags |= EDGE_CAN_FALLTHRU;
       EDGE_SUCC (bb, 1)->flags |= EDGE_CAN_FALLTHRU;
     }
-  /* dwarf2out expects that a NOTE_INSN_EPILOGUE_BEGIN is always paired
-     with a return or a sibcall.  Ensure that this remains the case if
-     they are in different basic blocks.  */
-  FOR_EACH_BB (bb)
-    {
-      edge e;
-      edge_iterator ei;
-      rtx insn, end;
-
-      end = BB_END (bb);
-      FOR_BB_INSNS (bb, insn)
-	if (GET_CODE (insn) == NOTE
-	    && NOTE_KIND (insn) == NOTE_INSN_EPILOGUE_BEG
-	    && !(CALL_P (end) && SIBLING_CALL_P (end))
-	    && !returnjump_p (end))
-	  {
-	    basic_block other_bb = NULL;
-	    FOR_EACH_EDGE (e, ei, bb->succs)
-	      {
-		if (e->flags & EDGE_FALLTHRU)
-		  other_bb = e->dest;
-		else
-		  e->flags &= ~EDGE_CAN_FALLTHRU;
-	      }
-	    FOR_EACH_EDGE (e, ei, other_bb->preds)
-	      {
-		if (!(e->flags & EDGE_FALLTHRU))
-		  e->flags &= ~EDGE_CAN_FALLTHRU;
-	      }	    
-	  }
-    }
 }
 
 /* Find unreachable blocks.  An unreachable block will have 0 in

=== modified file 'gcc/dwarf2out.c'
--- old/gcc/dwarf2out.c	2011-02-08 10:51:58 +0000
+++ new/gcc/dwarf2out.c	2011-03-10 14:55:10 +0000
@@ -2782,10 +2782,10 @@
   dwarf2out_frame_debug_expr (insn, label);
 }
 
-/* Determine if we need to save and restore CFI information around this
-   epilogue.  If SIBCALL is true, then this is a sibcall epilogue.  If
-   we do need to save/restore, then emit the save now, and insert a
-   NOTE_INSN_CFA_RESTORE_STATE at the appropriate place in the stream.  */
+/* Determine if we need to save and restore CFI information around
+   this epilogue.  If we do need to save/restore, then emit the save
+   now, and insert a NOTE_INSN_CFA_RESTORE_STATE at the appropriate
+   place in the stream.  */
 
 void
 dwarf2out_begin_epilogue (rtx insn)
@@ -2800,8 +2800,10 @@
       if (!INSN_P (i))
 	continue;
 
-      /* Look for both regular and sibcalls to end the block.  */
-      if (returnjump_p (i))
+      /* Look for both regular and sibcalls to end the block.  Various
+	 optimization passes may cause us to jump to a common epilogue
+	 tail, so we also accept simplejumps.  */
+      if (returnjump_p (i) || simplejump_p (i))
 	break;
       if (CALL_P (i) && SIBLING_CALL_P (i))
 	break;

=== modified file 'gcc/function.c'
--- old/gcc/function.c	2011-02-08 10:51:58 +0000
+++ new/gcc/function.c	2011-03-10 14:55:10 +0000
@@ -5038,6 +5038,127 @@
       return true;
   return false;
 }
+
+/* Look for sets of call-saved registers in the first block of the
+   function, and move them down into successor blocks if the register
+   is used only on one path.  This exposes more opportunities for
+   shrink-wrapping.
+   These kinds of sets often occur when incoming argument registers are
+   moved to call-saved registers because their values are live across
+   one or more calls during the function.  */
+
+static void
+prepare_shrink_wrap (basic_block entry_block)
+{
+  rtx insn, curr;
+  FOR_BB_INSNS_SAFE (entry_block, insn, curr)
+    {
+      basic_block next_bb;
+      edge e, live_edge;
+      edge_iterator ei;
+      rtx set, scan;
+      unsigned destreg, srcreg;
+
+      if (!NONDEBUG_INSN_P (insn))
+	continue;
+      set = single_set (insn);
+      if (!set)
+	continue;
+
+      if (!REG_P (SET_SRC (set)) || !REG_P (SET_DEST (set)))
+	continue;
+      srcreg = REGNO (SET_SRC (set));
+      destreg = REGNO (SET_DEST (set));
+      if (hard_regno_nregs[srcreg][GET_MODE (SET_SRC (set))] > 1
+	  || hard_regno_nregs[destreg][GET_MODE (SET_DEST (set))] > 1)
+	continue;
+
+      next_bb = entry_block;
+      scan = insn;
+
+      for (;;)
+	{
+	  live_edge = NULL;
+	  FOR_EACH_EDGE (e, ei, next_bb->succs)
+	    {
+	      if (REGNO_REG_SET_P (df_get_live_in (e->dest), destreg))
+		{
+		  if (live_edge)
+		    {
+		      live_edge = NULL;
+		      break;
+		    }
+		  live_edge = e;
+		}
+	    }
+	  if (!live_edge)
+	    break;
+	  /* We can sometimes encounter dead code.  Don't try to move it
+	     into the exit block.  */
+	  if (live_edge->dest == EXIT_BLOCK_PTR)
+	    break;
+	  if (EDGE_COUNT (live_edge->dest->preds) > 1)
+	    break;
+	  while (scan != BB_END (next_bb))
+	    {
+	      scan = NEXT_INSN (scan);
+	      if (NONDEBUG_INSN_P (scan))
+		{
+		  rtx link;
+		  HARD_REG_SET set_regs;
+
+		  CLEAR_HARD_REG_SET (set_regs);
+		  note_stores (PATTERN (scan), record_hard_reg_sets,
+			       &set_regs);
+		  if (CALL_P (scan))
+		    IOR_HARD_REG_SET (set_regs, call_used_reg_set);
+		  for (link = REG_NOTES (scan); link; link = XEXP (link, 1))
+		    if (REG_NOTE_KIND (link) == REG_INC)
+		      record_hard_reg_sets (XEXP (link, 0), NULL, &set_regs);
+
+		  if (TEST_HARD_REG_BIT (set_regs, srcreg)
+		      || reg_referenced_p (SET_DEST (set),
+					   PATTERN (scan)))
+		    {
+		      scan = NULL_RTX;
+		      break;
+		    }
+		  if (CALL_P (scan))
+		    {
+		      rtx link = CALL_INSN_FUNCTION_USAGE (scan);
+		      while (link)
+			{
+			  rtx tmp = XEXP (link, 0);
+			  if (GET_CODE (tmp) == USE
+			      && reg_referenced_p (SET_DEST (set), tmp))
+			    break;
+			  link = XEXP (link, 1);
+			}
+		      if (link)
+			{
+			  scan = NULL_RTX;
+			  break;
+			}
+		    }
+		}
+	    }
+	  if (!scan)
+	    break;
+	  next_bb = live_edge->dest;
+	}
+
+      if (next_bb != entry_block)
+	{
+	  rtx after = BB_HEAD (next_bb);
+	  while (!NOTE_P (after)
+		 || NOTE_KIND (after) != NOTE_INSN_BASIC_BLOCK)
+	    after = NEXT_INSN (after);
+	  emit_insn_after (PATTERN (insn), after);
+	  delete_insn (insn);
+	}
+    }
+}
+
 #endif
 
 #ifdef HAVE_return
@@ -5215,6 +5336,8 @@
       bitmap_head bb_antic_flags;
       bitmap_head bb_on_list;
 
+      prepare_shrink_wrap (entry_edge->dest);
+
       bitmap_initialize (&bb_antic_flags, &bitmap_default_obstack);
       bitmap_initialize (&bb_on_list, &bitmap_default_obstack);
 

