function: Restructure *logue insertion
authorSegher Boessenkool <segher@gcc.gnu.org>
Thu, 19 May 2016 22:17:53 +0000 (00:17 +0200)
committerSegher Boessenkool <segher@gcc.gnu.org>
Thu, 19 May 2016 22:17:53 +0000 (00:17 +0200)
This patch restructures how the prologues/epilogues are inserted.  Sibcalls
that run without prologue are now handled in shrink-wrap.c; it communicates
what is already handled by setting the EDGE_IGNORE flag.  The
try_shrink_wrapping function then doesn't need to be passed the bb_flags
anymore.

* function.c (make_epilogue_seq): Remove epilogue_end parameter.
(thread_prologue_and_epilogue_insns): Remove bb_flags.  Restructure
code.  Ignore sibcalls on EDGE_IGNORE edges.
* shrink-wrap.c (handle_simple_exit): New function.  Set EDGE_IGNORE
on edges for sibcalls that run without prologue.  The rest of the
function is combined from...
(fix_fake_fallthrough_edge): ... this, and ...
(try_shrink_wrapping): ... a part of this.  Remove the bb_with
function argument, make it a local variable.

From-SVN: r236491

gcc/ChangeLog
gcc/function.c
gcc/shrink-wrap.c
gcc/shrink-wrap.h

index c5e637bdaeab087fee7198c1fbb586716204b7ce..fed248d32e81c40ea61ad6d0ed553069e51d4da1 100644 (file)
@@ -1,3 +1,15 @@
+2016-05-19  Segher Boessenkool  <segher@kernel.crashing.org>
+
+       * function.c (make_epilogue_seq): Remove epilogue_end parameter.
+       (thread_prologue_and_epilogue_insns): Remove bb_flags.  Restructure
+       code.  Ignore sibcalls on EDGE_IGNORE edges.
+       * shrink-wrap.c (handle_simple_exit): New function.  Set EDGE_IGNORE
+       on edges for sibcalls that run without prologue.  The rest of the
+       function is combined from...
+       (fix_fake_fallthrough_edge): ... this, and ...
+       (try_shrink_wrapping): ... a part of this.  Remove the bb_with
+       function argument, make it a local variable.
+
 2016-05-19  Sandra Loosemore  <sandra@codesourcery.com>
 
        * config/i386/cygming.h (DWARF2_UNWIND_INFO): Allow 
@@ -6,7 +18,7 @@
        * config/i386/mingw32.h (SHARED_LIBGCC_UNDEFS_SPEC): Handle
        TARGET_64BIT_DEFAULT.
 
-2016-05-16  Ryan Burn  <contact@rnburn.com>
+2016-05-19  Ryan Burn  <contact@rnburn.com>
 
        * Makefile.in (GTFILES): Add cilk.h and cilk-common.c.
        * gengtype.c (open_base_files): Add cilk.h to ifiles.
index 4c236eb50f26f1dfaabd502d4a205004c11d276e..5ff17c75b2682b4bdd7615f59a49ffffe5ca1733 100644 (file)
@@ -5828,13 +5828,13 @@ make_prologue_seq (void)
    or NULL.  */
 
 static rtx_insn *
-make_epilogue_seq (rtx_insn **epilogue_end)
+make_epilogue_seq (void)
 {
   if (!targetm.have_epilogue ())
     return NULL;
 
   start_sequence ();
-  *epilogue_end = emit_note (NOTE_INSN_EPILOGUE_BEG);
+  emit_note (NOTE_INSN_EPILOGUE_BEG);
   rtx_insn *seq = targetm.gen_epilogue ();
   if (seq)
     emit_jump_insn (seq);
@@ -5905,61 +5905,29 @@ make_epilogue_seq (rtx_insn **epilogue_end)
 void
 thread_prologue_and_epilogue_insns (void)
 {
-  bool inserted;
-  bitmap_head bb_flags;
-  rtx_insn *epilogue_end ATTRIBUTE_UNUSED;
-  edge e, entry_edge, orig_entry_edge, exit_fallthru_edge;
-  edge_iterator ei;
-
   df_analyze ();
 
-  rtl_profile_for_bb (ENTRY_BLOCK_PTR_FOR_FN (cfun));
-
-  inserted = false;
-  epilogue_end = NULL;
-
   /* Can't deal with multiple successors of the entry block at the
      moment.  Function should always have at least one entry
      point.  */
   gcc_assert (single_succ_p (ENTRY_BLOCK_PTR_FOR_FN (cfun)));
-  entry_edge = single_succ_edge (ENTRY_BLOCK_PTR_FOR_FN (cfun));
-  orig_entry_edge = entry_edge;
+
+  edge entry_edge = single_succ_edge (ENTRY_BLOCK_PTR_FOR_FN (cfun));
+  edge orig_entry_edge = entry_edge;
 
   rtx_insn *split_prologue_seq = make_split_prologue_seq ();
   rtx_insn *prologue_seq = make_prologue_seq ();
-  rtx_insn *epilogue_seq = make_epilogue_seq (&epilogue_end);
-
-  bitmap_initialize (&bb_flags, &bitmap_default_obstack);
+  rtx_insn *epilogue_seq = make_epilogue_seq ();
 
   /* Try to perform a kind of shrink-wrapping, making sure the
      prologue/epilogue is emitted only around those parts of the
      function that require it.  */
 
-  try_shrink_wrapping (&entry_edge, &bb_flags, prologue_seq);
+  try_shrink_wrapping (&entry_edge, prologue_seq);
 
-  if (split_prologue_seq != NULL_RTX)
-    {
-      insert_insn_on_edge (split_prologue_seq, orig_entry_edge);
-      inserted = true;
-    }
-  if (prologue_seq != NULL_RTX)
-    {
-      insert_insn_on_edge (prologue_seq, entry_edge);
-      inserted = true;
-    }
-
-  /* If the exit block has no non-fake predecessors, we don't need
-     an epilogue.  */
-  FOR_EACH_EDGE (e, ei, EXIT_BLOCK_PTR_FOR_FN (cfun)->preds)
-    if ((e->flags & EDGE_FAKE) == 0)
-      break;
-  if (e == NULL)
-    goto epilogue_done;
 
   rtl_profile_for_bb (EXIT_BLOCK_PTR_FOR_FN (cfun));
 
-  exit_fallthru_edge = find_fallthru_edge (EXIT_BLOCK_PTR_FOR_FN (cfun)->preds);
-
   /* A small fib -- epilogue is not yet completed, but we wish to re-use
      this marker for the splits of EH_RETURN patterns, and nothing else
      uses the flag in the meantime.  */
@@ -5970,6 +5938,8 @@ thread_prologue_and_epilogue_insns (void)
      code.  In order to be able to properly annotate these with unwind
      info, try to split them now.  If we get a valid split, drop an
      EPILOGUE_BEG note and mark the insns as epilogue insns.  */
+  edge e;
+  edge_iterator ei;
   FOR_EACH_EDGE (e, ei, EXIT_BLOCK_PTR_FOR_FN (cfun)->preds)
     {
       rtx_insn *prev, *last, *trial;
@@ -5989,83 +5959,84 @@ thread_prologue_and_epilogue_insns (void)
       emit_note_after (NOTE_INSN_EPILOGUE_BEG, prev);
     }
 
-  /* If nothing falls through into the exit block, we don't need an
-     epilogue.  */
-  if (exit_fallthru_edge == NULL)
-    goto epilogue_done;
+  edge exit_fallthru_edge = find_fallthru_edge (EXIT_BLOCK_PTR_FOR_FN (cfun)->preds);
 
-  if (epilogue_seq)
+  if (exit_fallthru_edge)
     {
-      insert_insn_on_edge (epilogue_seq, exit_fallthru_edge);
-      inserted = true;
-    }
-  else
-    {
-      basic_block cur_bb;
+      if (epilogue_seq)
+       {
+         insert_insn_on_edge (epilogue_seq, exit_fallthru_edge);
 
-      if (! next_active_insn (BB_END (exit_fallthru_edge->src)))
-       goto epilogue_done;
-      /* We have a fall-through edge to the exit block, the source is not
-         at the end of the function, and there will be an assembler epilogue
-         at the end of the function.
-         We can't use force_nonfallthru here, because that would try to
-        use return.  Inserting a jump 'by hand' is extremely messy, so
-        we take advantage of cfg_layout_finalize using
-        fixup_fallthru_exit_predecessor.  */
-      cfg_layout_initialize (0);
-      FOR_EACH_BB_FN (cur_bb, cfun)
-       if (cur_bb->index >= NUM_FIXED_BLOCKS
-           && cur_bb->next_bb->index >= NUM_FIXED_BLOCKS)
-         cur_bb->aux = cur_bb->next_bb;
-      cfg_layout_finalize ();
+         /* The epilogue insns we inserted may cause the exit edge to no longer
+            be fallthru.  */
+         FOR_EACH_EDGE (e, ei, EXIT_BLOCK_PTR_FOR_FN (cfun)->preds)
+           {
+             if (((e->flags & EDGE_FALLTHRU) != 0)
+                 && returnjump_p (BB_END (e->src)))
+               e->flags &= ~EDGE_FALLTHRU;
+           }
+       }
+      else if (next_active_insn (BB_END (exit_fallthru_edge->src)))
+       {
+         /* We have a fall-through edge to the exit block, the source is not
+            at the end of the function, and there will be an assembler epilogue
+            at the end of the function.
+            We can't use force_nonfallthru here, because that would try to
+            use return.  Inserting a jump 'by hand' is extremely messy, so
+            we take advantage of cfg_layout_finalize using
+            fixup_fallthru_exit_predecessor.  */
+         cfg_layout_initialize (0);
+         basic_block cur_bb;
+         FOR_EACH_BB_FN (cur_bb, cfun)
+           if (cur_bb->index >= NUM_FIXED_BLOCKS
+               && cur_bb->next_bb->index >= NUM_FIXED_BLOCKS)
+             cur_bb->aux = cur_bb->next_bb;
+         cfg_layout_finalize ();
+       }
     }
 
-epilogue_done:
+  /* Insert the prologue.  */
 
-  default_rtl_profile ();
+  rtl_profile_for_bb (ENTRY_BLOCK_PTR_FOR_FN (cfun));
 
-  if (inserted)
+  if (split_prologue_seq || prologue_seq)
     {
-      sbitmap blocks;
+      if (split_prologue_seq)
+       insert_insn_on_edge (split_prologue_seq, orig_entry_edge);
+
+      if (prologue_seq)
+       insert_insn_on_edge (prologue_seq, entry_edge);
 
       commit_edge_insertions ();
 
       /* Look for basic blocks within the prologue insns.  */
-      blocks = sbitmap_alloc (last_basic_block_for_fn (cfun));
+      sbitmap blocks = sbitmap_alloc (last_basic_block_for_fn (cfun));
       bitmap_clear (blocks);
       bitmap_set_bit (blocks, entry_edge->dest->index);
       bitmap_set_bit (blocks, orig_entry_edge->dest->index);
       find_many_sub_basic_blocks (blocks);
       sbitmap_free (blocks);
-
-      /* The epilogue insns we inserted may cause the exit edge to no longer
-        be fallthru.  */
-      FOR_EACH_EDGE (e, ei, EXIT_BLOCK_PTR_FOR_FN (cfun)->preds)
-       {
-         if (((e->flags & EDGE_FALLTHRU) != 0)
-             && returnjump_p (BB_END (e->src)))
-           e->flags &= ~EDGE_FALLTHRU;
-       }
     }
 
+  default_rtl_profile ();
+
   /* Emit sibling epilogues before any sibling call sites.  */
-  for (ei = ei_start (EXIT_BLOCK_PTR_FOR_FN (cfun)->preds); (e =
-                                                            ei_safe_edge (ei));
-                                                            )
-    {
-      basic_block bb = e->src;
-      rtx_insn *insn = BB_END (bb);
-
-      if (!CALL_P (insn)
-         || ! SIBLING_CALL_P (insn)
-         || (targetm.have_simple_return ()
-             && entry_edge != orig_entry_edge
-             && !bitmap_bit_p (&bb_flags, bb->index)))
+  for (ei = ei_start (EXIT_BLOCK_PTR_FOR_FN (cfun)->preds);
+       (e = ei_safe_edge (ei));
+       ei_next (&ei))
+    {
+      /* Skip those already handled, the ones that run without prologue.  */
+      if (e->flags & EDGE_IGNORE)
        {
-         ei_next (&ei);
+         e->flags &= ~EDGE_IGNORE;
          continue;
        }
 
+      rtx_insn *insn = BB_END (e->src);
+
+      if (!(CALL_P (insn) && SIBLING_CALL_P (insn)))
+       continue;
+
       if (rtx_insn *ep_seq = targetm.gen_sibcall_epilogue ())
        {
          start_sequence ();
@@ -6082,10 +6053,9 @@ epilogue_done:
 
          emit_insn_before (seq, insn);
        }
-      ei_next (&ei);
     }
 
-  if (epilogue_end)
+  if (epilogue_seq)
     {
       rtx_insn *insn, *next;
 
@@ -6094,17 +6064,15 @@ epilogue_done:
         of such a note.  Also possibly move
         NOTE_INSN_FUNCTION_BEG notes, as those can be relevant for debug
         info generation.  */
-      for (insn = epilogue_end; insn; insn = next)
+      for (insn = epilogue_seq; insn; insn = next)
        {
          next = NEXT_INSN (insn);
          if (NOTE_P (insn)
              && (NOTE_KIND (insn) == NOTE_INSN_FUNCTION_BEG))
-           reorder_insns (insn, insn, PREV_INSN (epilogue_end));
+           reorder_insns (insn, insn, PREV_INSN (epilogue_seq));
        }
     }
 
-  bitmap_clear (&bb_flags);
-
   /* Threading the prologue and epilogue changes the artificial refs
      in the entry and exit blocks.  */
   epilogue_completed = 1;
index 0ba1fedf161f92312a62e8e0ad114b68042e87b8..b85b1c3b3497c6c1b8d7ee80930cb123025fb23f 100644 (file)
@@ -529,30 +529,49 @@ can_dup_for_shrink_wrapping (basic_block bb, basic_block pro, unsigned max_size)
   return true;
 }
 
-/* If the source of edge E has more than one successor, the verifier for
-   branch probabilities gets confused by the fake edges we make where
-   simple_return statements will be inserted later (because those are not
-   marked as fallthrough edges).  Fix this by creating an extra block just
-   for that fallthrough.  */
+/* Do whatever needs to be done for exits that run without prologue.
+   Sibcalls need nothing done.  Normal exits get a simple_return inserted.  */
 
-static edge
-fix_fake_fallthrough_edge (edge e)
+static void
+handle_simple_exit (edge e)
 {
-  if (EDGE_COUNT (e->src->succs) <= 1)
-    return e;
 
-  basic_block old_bb = e->src;
-  rtx_insn *end = BB_END (old_bb);
-  rtx_note *note = emit_note_after (NOTE_INSN_DELETED, end);
-  basic_block new_bb = create_basic_block (note, note, old_bb);
-  BB_COPY_PARTITION (new_bb, old_bb);
-  BB_END (old_bb) = end;
+  if (e->flags & EDGE_SIBCALL)
+    {
+      /* Tell function.c to take no further action on this edge.  */
+      e->flags |= EDGE_IGNORE;
+
+      e->flags &= ~EDGE_FALLTHRU;
+      emit_barrier_after_bb (e->src);
+      return;
+    }
+
+  /* If the basic block the edge comes from has multiple successors,
+     split the edge.  */
+  if (EDGE_COUNT (e->src->succs) > 1)
+    {
+      basic_block old_bb = e->src;
+      rtx_insn *end = BB_END (old_bb);
+      rtx_note *note = emit_note_after (NOTE_INSN_DELETED, end);
+      basic_block new_bb = create_basic_block (note, note, old_bb);
+      BB_COPY_PARTITION (new_bb, old_bb);
+      BB_END (old_bb) = end;
+
+      redirect_edge_succ (e, new_bb);
+      e->flags |= EDGE_FALLTHRU;
+
+      e = make_edge (new_bb, EXIT_BLOCK_PTR_FOR_FN (cfun), 0);
+    }
 
-  redirect_edge_succ (e, new_bb);
-  e->flags |= EDGE_FALLTHRU;
-  e->flags &= ~EDGE_FAKE;
+  e->flags &= ~EDGE_FALLTHRU;
+  rtx_jump_insn *ret = emit_jump_insn_after (targetm.gen_simple_return (),
+                                            BB_END (e->src));
+  JUMP_LABEL (ret) = simple_return_rtx;
+  emit_barrier_after_bb (e->src);
 
-  return make_edge (new_bb, EXIT_BLOCK_PTR_FOR_FN (cfun), EDGE_FAKE);
+  if (dump_file)
+    fprintf (dump_file, "Made simple_return with UID %d in bb %d\n",
+            INSN_UID (ret), e->src->index);
 }
 
 /* Try to perform a kind of shrink-wrapping, making sure the
@@ -610,13 +629,10 @@ fix_fake_fallthrough_edge (edge e)
    (bb 4 is duplicated to 5; the prologue is inserted on the edge 5->3).
 
    ENTRY_EDGE is the edge where the prologue will be placed, possibly
-   changed by this function.  BB_WITH is a bitmap that, if we do shrink-
-   wrap, will on return contain the interesting blocks that run with
-   prologue.  PROLOGUE_SEQ is the prologue we will insert.  */
+   changed by this function.  PROLOGUE_SEQ is the prologue we will insert.  */
 
 void
-try_shrink_wrapping (edge *entry_edge, bitmap_head *bb_with,
-                    rtx_insn *prologue_seq)
+try_shrink_wrapping (edge *entry_edge, rtx_insn *prologue_seq)
 {
   /* If we cannot shrink-wrap, are told not to shrink-wrap, or it makes
      no sense to shrink-wrap: then do not shrink-wrap!  */
@@ -739,6 +755,7 @@ try_shrink_wrapping (edge *entry_edge, bitmap_head *bb_with,
      reachable from PRO that we already found, and in VEC a stack of
      those we still need to consider (to find successors).  */
 
+  bitmap bb_with = BITMAP_ALLOC (NULL);
   bitmap_set_bit (bb_with, pro->index);
 
   vec<basic_block> vec;
@@ -851,6 +868,7 @@ try_shrink_wrapping (edge *entry_edge, bitmap_head *bb_with,
 
   if (pro == entry)
     {
+      BITMAP_FREE (bb_with);
       free_dominance_info (CDI_DOMINATORS);
       return;
     }
@@ -952,26 +970,7 @@ try_shrink_wrapping (edge *entry_edge, bitmap_head *bb_with,
     if (!bitmap_bit_p (bb_with, bb->index))
       FOR_EACH_EDGE (e, ei, bb->succs)
        if (e->dest == EXIT_BLOCK_PTR_FOR_FN (cfun))
-         {
-           e = fix_fake_fallthrough_edge (e);
-
-           e->flags &= ~EDGE_FALLTHRU;
-           if (!(e->flags & EDGE_SIBCALL))
-             {
-               rtx_insn *ret = targetm.gen_simple_return ();
-               rtx_insn *end = BB_END (e->src);
-               rtx_jump_insn *start = emit_jump_insn_after (ret, end);
-               JUMP_LABEL (start) = simple_return_rtx;
-               e->flags &= ~EDGE_FAKE;
-
-               if (dump_file)
-                 fprintf (dump_file,
-                          "Made simple_return with UID %d in bb %d\n",
-                          INSN_UID (start), e->src->index);
-             }
-
-           emit_barrier_after_bb (e->src);
-         }
+         handle_simple_exit (e);
 
   /* Finally, we want a single edge to put the prologue on.  Make a new
      block before the PRO block; the edge beteen them is the edge we want.
@@ -1004,5 +1003,6 @@ try_shrink_wrapping (edge *entry_edge, bitmap_head *bb_with,
   *entry_edge = make_single_succ_edge (new_bb, pro, EDGE_FALLTHRU);
   force_nonfallthru (*entry_edge);
 
+  BITMAP_FREE (bb_with);
   free_dominance_info (CDI_DOMINATORS);
 }
index 4d821d7349961edcb50700e5cdc9f391dcccfa48..e06ab37952f545ba4b59c391263f7a6a8b35119e 100644 (file)
@@ -24,8 +24,7 @@ along with GCC; see the file COPYING3.  If not see
 
 /* In shrink-wrap.c.  */
 extern bool requires_stack_frame_p (rtx_insn *, HARD_REG_SET, HARD_REG_SET);
-extern void try_shrink_wrapping (edge *entry_edge, bitmap_head *bb_flags,
-                                rtx_insn *prologue_seq);
+extern void try_shrink_wrapping (edge *entry_edge, rtx_insn *prologue_seq);
 #define SHRINK_WRAPPING_ENABLED \
   (flag_shrink_wrap && targetm.have_simple_return ())