OSDN Git Service

Daily bump.
[pf3gnuchains/gcc-fork.git] / gcc / bb-reorder.c
index 81369ea..a35b8e6 100644 (file)
@@ -1,6 +1,6 @@
 /* Basic block reordering routines for the GNU compiler.
-   Copyright (C) 2000, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2010
-   Free Software Foundation, Inc.
+   Copyright (C) 2000, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2010, 2011,
+   2012 Free Software Foundation, Inc.
 
    This file is part of GCC.
 
@@ -87,6 +87,7 @@
 #include "tree-pass.h"
 #include "df.h"
 #include "bb-reorder.h"
+#include "except.h"
 
 /* The number of rounds.  In most cases there will only be 4 rounds, but
    when partitioning hot and cold basic blocks into separate sections of
@@ -180,7 +181,6 @@ static fibheapkey_t bb_to_key (basic_block);
 static bool better_edge_p (const_basic_block, const_edge, int, int, int, int, const_edge);
 static void connect_traces (int, struct trace *);
 static bool copy_bb_p (const_basic_block, int);
-static int get_uncond_jump_length (void);
 static bool push_to_next_round_p (const_basic_block, int, int, int, gcov_type);
 \f
 /* Check to see if bb should be pushed into the next round of trace
@@ -1192,7 +1192,7 @@ copy_bb_p (const_basic_block bb, int code_may_grow)
 
 /* Return the length of unconditional jump instruction.  */
 
-static int
+int
 get_uncond_jump_length (void)
 {
   rtx label, jump;
@@ -1208,6 +1208,79 @@ get_uncond_jump_length (void)
   return length;
 }
 
+/* Emit a barrier into the footer of BB.  */
+
+static void
+emit_barrier_after_bb (basic_block bb)
+{
+  rtx barrier = emit_barrier_after (BB_END (bb));
+  bb->il.rtl->footer = unlink_insn_chain (barrier, barrier);
+}
+
+/* The landing pad OLD_LP, in block OLD_BB, has edges from both partitions.
+   Duplicate the landing pad and split the edges so that no EH edge
+   crosses partitions.  */
+
+static void
+fix_up_crossing_landing_pad (eh_landing_pad old_lp, basic_block old_bb)
+{
+  eh_landing_pad new_lp;
+  basic_block new_bb, last_bb, post_bb;
+  rtx new_label, jump, post_label;
+  unsigned new_partition;
+  edge_iterator ei;
+  edge e;
+
+  /* Generate the new landing-pad structure.  */
+  new_lp = gen_eh_landing_pad (old_lp->region);
+  new_lp->post_landing_pad = old_lp->post_landing_pad;
+  new_lp->landing_pad = gen_label_rtx ();
+  LABEL_PRESERVE_P (new_lp->landing_pad) = 1;
+
+  /* Put appropriate instructions in new bb.  */
+  new_label = emit_label (new_lp->landing_pad);
+
+  expand_dw2_landing_pad_for_region (old_lp->region);
+
+  post_bb = BLOCK_FOR_INSN (old_lp->landing_pad);
+  post_bb = single_succ (post_bb);
+  post_label = block_label (post_bb);
+  jump = emit_jump_insn (gen_jump (post_label));
+  JUMP_LABEL (jump) = post_label;
+
+  /* Create new basic block to be dest for lp.  */
+  last_bb = EXIT_BLOCK_PTR->prev_bb;
+  new_bb = create_basic_block (new_label, jump, last_bb);
+  new_bb->aux = last_bb->aux;
+  last_bb->aux = new_bb;
+
+  emit_barrier_after_bb (new_bb);
+
+  make_edge (new_bb, post_bb, 0);
+
+  /* Make sure new bb is in the other partition.  */
+  new_partition = BB_PARTITION (old_bb);
+  new_partition ^= BB_HOT_PARTITION | BB_COLD_PARTITION;
+  BB_SET_PARTITION (new_bb, new_partition);
+
+  /* Fix up the edges.  */
+  for (ei = ei_start (old_bb->preds); (e = ei_safe_edge (ei)) != NULL; )
+    if (BB_PARTITION (e->src) == new_partition)
+      {
+       rtx insn = BB_END (e->src);
+       rtx note = find_reg_note (insn, REG_EH_REGION, NULL_RTX);
+
+       gcc_assert (note != NULL);
+       gcc_checking_assert (INTVAL (XEXP (note, 0)) == old_lp->index);
+       XEXP (note, 0) = GEN_INT (new_lp->index);
+
+       /* Adjust the edge to the new destination.  */
+       redirect_edge_succ (e, new_bb);
+      }
+    else
+      ei_next (&ei);
+}
+
 /* Find the basic blocks that are rarely executed and need to be moved to
    a separate section of the .o file (to cut down on paging and improve
    cache locality).  Return a vector of all edges that cross.  */
@@ -1221,7 +1294,6 @@ find_rarely_executed_basic_blocks_and_crossing_edges (void)
   edge_iterator ei;
 
   /* Mark which partition (hot/cold) each basic block belongs in.  */
-
   FOR_EACH_BB (bb)
     {
       if (probably_never_executed_bb_p (bb))
@@ -1230,22 +1302,72 @@ find_rarely_executed_basic_blocks_and_crossing_edges (void)
        BB_SET_PARTITION (bb, BB_HOT_PARTITION);
     }
 
-  /* Mark every edge that crosses between sections.  */
-
-  FOR_EACH_BB (bb)
-    FOR_EACH_EDGE (e, ei, bb->succs)
+  /* The format of .gcc_except_table does not allow landing pads to
+     be in a different partition as the throw.  Fix this by either
+     moving or duplicating the landing pads.  */
+  if (cfun->eh->lp_array)
     {
-      if (e->src != ENTRY_BLOCK_PTR
-         && e->dest != EXIT_BLOCK_PTR
-         && BB_PARTITION (e->src) != BB_PARTITION (e->dest))
+      unsigned i;
+      eh_landing_pad lp;
+
+      FOR_EACH_VEC_ELT (eh_landing_pad, cfun->eh->lp_array, i, lp)
        {
-         e->flags |= EDGE_CROSSING;
-         VEC_safe_push (edge, heap, crossing_edges, e);
+         bool all_same, all_diff;
+
+         if (lp == NULL
+             || lp->landing_pad == NULL_RTX
+             || !LABEL_P (lp->landing_pad))
+           continue;
+
+         all_same = all_diff = true;
+         bb = BLOCK_FOR_INSN (lp->landing_pad);
+         FOR_EACH_EDGE (e, ei, bb->preds)
+           {
+             gcc_assert (e->flags & EDGE_EH);
+             if (BB_PARTITION (bb) == BB_PARTITION (e->src))
+               all_diff = false;
+             else
+               all_same = false;
+           }
+
+         if (all_same)
+           ;
+         else if (all_diff)
+           {
+             int which = BB_PARTITION (bb);
+             which ^= BB_HOT_PARTITION | BB_COLD_PARTITION;
+             BB_SET_PARTITION (bb, which);
+           }
+         else
+           fix_up_crossing_landing_pad (lp, bb);
        }
-      else
-       e->flags &= ~EDGE_CROSSING;
     }
 
+  /* Mark every edge that crosses between sections.  */
+
+  FOR_EACH_BB (bb)
+    FOR_EACH_EDGE (e, ei, bb->succs)
+      {
+       unsigned int flags = e->flags;
+      
+        /* We should never have EDGE_CROSSING set yet.  */
+       gcc_checking_assert ((flags & EDGE_CROSSING) == 0);
+
+       if (e->src != ENTRY_BLOCK_PTR
+           && e->dest != EXIT_BLOCK_PTR
+           && BB_PARTITION (e->src) != BB_PARTITION (e->dest))
+         {
+           VEC_safe_push (edge, heap, crossing_edges, e);
+           flags |= EDGE_CROSSING;
+         }
+
+       /* Now that we've split eh edges as appropriate, allow landing pads
+          to be merged with the post-landing pads.  */
+       flags &= ~EDGE_PRESERVE;
+
+       e->flags = flags;
+      }
+
   return crossing_edges;
 }
 
@@ -1262,7 +1384,7 @@ add_labels_and_missing_jumps (VEC(edge, heap) *crossing_edges)
     {
       basic_block src = e->src;
       basic_block dest = e->dest;
-      rtx label, barrier, new_jump;
+      rtx label, new_jump;
 
       if (dest == EXIT_BLOCK_PTR)
        continue;
@@ -1288,10 +1410,10 @@ add_labels_and_missing_jumps (VEC(edge, heap) *crossing_edges)
 
       new_jump = emit_jump_insn_after (gen_jump (label), BB_END (src));
       BB_END (src) = new_jump;
-      barrier = emit_barrier_after (new_jump);
       JUMP_LABEL (new_jump) = label;
       LABEL_NUSES (label) += 1;
-      src->il.rtl->footer = unlink_insn_chain (barrier, barrier);
+
+      emit_barrier_after_bb (src);
 
       /* Mark edge as non-fallthru.  */
       e->flags &= ~EDGE_FALLTHRU;
@@ -1321,7 +1443,6 @@ fix_up_fall_thru_edges (void)
   int invert_worked;
   rtx old_jump;
   rtx fall_thru_label;
-  rtx barrier;
 
   FOR_EACH_BB (cur_bb)
     {
@@ -1451,19 +1572,7 @@ fix_up_fall_thru_edges (void)
                     }
 
                  /* Add barrier after new jump */
-
-                 if (new_bb)
-                   {
-                     barrier = emit_barrier_after (BB_END (new_bb));
-                     new_bb->il.rtl->footer = unlink_insn_chain (barrier,
-                                                              barrier);
-                   }
-                 else
-                   {
-                     barrier = emit_barrier_after (BB_END (cur_bb));
-                     cur_bb->il.rtl->footer = unlink_insn_chain (barrier,
-                                                              barrier);
-                   }
+                 emit_barrier_after_bb (new_bb ? new_bb : cur_bb);
                }
            }
        }
@@ -1526,7 +1635,6 @@ fix_crossing_conditional_branches (void)
 {
   basic_block cur_bb;
   basic_block new_bb;
-  basic_block last_bb;
   basic_block dest;
   edge succ1;
   edge succ2;
@@ -1536,10 +1644,6 @@ fix_crossing_conditional_branches (void)
   rtx set_src;
   rtx old_label = NULL_RTX;
   rtx new_label;
-  rtx new_jump;
-  rtx barrier;
-
- last_bb = EXIT_BLOCK_PTR->prev_bb;
 
   FOR_EACH_BB (cur_bb)
     {
@@ -1602,38 +1706,28 @@ fix_crossing_conditional_branches (void)
                new_label = block_label (new_bb);
              else
                {
+                 basic_block last_bb;
+                 rtx new_jump;
+
                  /* Create new basic block to be dest for
                     conditional jump.  */
 
-                 new_bb = create_basic_block (NULL, NULL, last_bb);
-                 new_bb->aux = last_bb->aux;
-                 last_bb->aux = new_bb;
-                 last_bb = new_bb;
                  /* Put appropriate instructions in new bb.  */
 
                  new_label = gen_label_rtx ();
-                 emit_label_before (new_label, BB_HEAD (new_bb));
-                 BB_HEAD (new_bb) = new_label;
+                 emit_label (new_label);
 
-                 if (GET_CODE (old_label) == LABEL_REF)
-                   {
-                     old_label = JUMP_LABEL (old_jump);
-                     new_jump = emit_jump_insn_after (gen_jump
-                                                      (old_label),
-                                                      BB_END (new_bb));
-                   }
-                 else
-                   {
-                     gcc_assert (HAVE_return
-                                 && GET_CODE (old_label) == RETURN);
-                     new_jump = emit_jump_insn_after (gen_return (),
-                                                      BB_END (new_bb));
-                   }
-
-                 barrier = emit_barrier_after (new_jump);
+                 gcc_assert (GET_CODE (old_label) == LABEL_REF);
+                 old_label = JUMP_LABEL (old_jump);
+                 new_jump = emit_jump_insn (gen_jump (old_label));
                  JUMP_LABEL (new_jump) = old_label;
-                 new_bb->il.rtl->footer = unlink_insn_chain (barrier,
-                                                          barrier);
+
+                 last_bb = EXIT_BLOCK_PTR->prev_bb;
+                 new_bb = create_basic_block (new_label, new_jump, last_bb);
+                 new_bb->aux = last_bb->aux;
+                 last_bb->aux = new_bb;
+
+                 emit_barrier_after_bb (new_bb);
 
                  /* Make sure new bb is in same partition as source
                     of conditional branch.  */
@@ -1872,8 +1966,10 @@ insert_section_boundary_note (void)
   rtx new_note;
   int first_partition = 0;
 
-  if (flag_reorder_blocks_and_partition)
-    FOR_EACH_BB (bb)
+  if (!flag_reorder_blocks_and_partition)
+    return;
+
+  FOR_EACH_BB (bb)
     {
       if (!first_partition)
        first_partition = BB_PARTITION (bb);
@@ -2127,6 +2223,8 @@ partition_hot_cold_basic_blocks (void)
   if (n_basic_blocks <= NUM_FIXED_BLOCKS + 1)
     return 0;
 
+  df_set_flags (DF_DEFER_INSN_RESCAN);
+
   crossing_edges = find_rarely_executed_basic_blocks_and_crossing_edges ();
   if (crossing_edges == NULL)
     return 0;
@@ -2156,8 +2254,43 @@ partition_hot_cold_basic_blocks (void)
 
   add_reg_crossing_jump_notes ();
 
+  /* Clear bb->aux fields that the above routines were using.  */
+  clear_aux_for_blocks ();
+
   VEC_free (edge, heap, crossing_edges);
 
+  /* ??? FIXME: DF generates the bb info for a block immediately.
+     And by immediately, I mean *during* creation of the block.
+
+       #0  df_bb_refs_collect
+       #1  in df_bb_refs_record
+       #2  in create_basic_block_structure
+
+     Which means that the bb_has_eh_pred test in df_bb_refs_collect
+     will *always* fail, because no edges can have been added to the
+     block yet.  Which of course means we don't add the right 
+     artificial refs, which means we fail df_verify (much) later.
+
+     Cleanest solution would seem to make DF_DEFER_INSN_RESCAN imply
+     that we also shouldn't grab data from the new blocks those new
+     insns are in either.  In this way one can create the block, link
+     it up properly, and have everything Just Work later, when deferred
+     insns are processed.
+
+     In the meantime, we have no other option but to throw away all
+     of the DF data and recompute it all.  */
+  if (cfun->eh->lp_array)
+    {
+      df_finish_pass (true);
+      df_scan_alloc (NULL);
+      df_scan_blocks ();
+      /* Not all post-landing pads use all of the EH_RETURN_DATA_REGNO
+        data.  We blindly generated all of them when creating the new
+        landing pad.  Delete those assignments we don't use.  */
+      df_set_flags (DF_LR_RUN_DCE);
+      df_analyze ();
+    }
+
   return TODO_verify_flow | TODO_verify_rtl_sharing;
 }
 \f
@@ -2166,7 +2299,17 @@ gate_handle_reorder_blocks (void)
 {
   if (targetm.cannot_modify_jumps_p ())
     return false;
-  return (optimize > 0);
+  /* Don't reorder blocks when optimizing for size because extra jump insns may
+     be created; also barrier may create extra padding.
+
+     More correctly we should have a block reordering mode that tried to
+     minimize the combined size of all the jumps.  This would more or less
+     automatically remove extra jumps, but would also try to use more short
+     jumps instead of long jumps.  */
+  if (!optimize_function_for_speed_p (cfun))
+    return false;
+  return (optimize > 0
+         && (flag_reorder_blocks || flag_reorder_blocks_and_partition));
 }
 
 
@@ -2180,19 +2323,8 @@ rest_of_handle_reorder_blocks (void)
      splitting possibly introduced more crossjumping opportunities.  */
   cfg_layout_initialize (CLEANUP_EXPENSIVE);
 
-  if ((flag_reorder_blocks || flag_reorder_blocks_and_partition)
-      /* Don't reorder blocks when optimizing for size because extra jump insns may
-        be created; also barrier may create extra padding.
-
-        More correctly we should have a block reordering mode that tried to
-        minimize the combined size of all the jumps.  This would more or less
-        automatically remove extra jumps, but would also try to use more short
-        jumps instead of long jumps.  */
-      && optimize_function_for_speed_p (cfun))
-    {
-      reorder_basic_blocks ();
-      cleanup_cfg (CLEANUP_EXPENSIVE);
-    }
+  reorder_basic_blocks ();
+  cleanup_cfg (CLEANUP_EXPENSIVE);
 
   FOR_EACH_BB (bb)
     if (bb->next_bb != EXIT_BLOCK_PTR)
@@ -2231,6 +2363,10 @@ gate_handle_partition_blocks (void)
      user defined section attributes.  Don't call it if either case
      arises.  */
   return (flag_reorder_blocks_and_partition
+          && optimize
+         /* See gate_handle_reorder_blocks.  We should not partition if
+            we are going to omit the reordering.  */
+         && optimize_function_for_speed_p (cfun)
          && !DECL_ONE_ONLY (current_function_decl)
          && !user_defined_section_attribute);
 }