OSDN Git Service

PR rtl-opt/42269
[pf3gnuchains/gcc-fork.git] / gcc / cfgcleanup.c
index 01ddf99..ffe36e4 100644 (file)
@@ -958,7 +958,7 @@ old_insns_match_p (int mode ATTRIBUTE_UNUSED, rtx i1, rtx i2)
   if (NOTE_INSN_BASIC_BLOCK_P (i1) && NOTE_INSN_BASIC_BLOCK_P (i2))
     return true;
 
-   p1 = PATTERN (i1);
+  p1 = PATTERN (i1);
   p2 = PATTERN (i2);
 
   if (GET_CODE (p1) != GET_CODE (p2))
@@ -1057,10 +1057,10 @@ flow_find_cross_jump (int mode ATTRIBUTE_UNUSED, basic_block bb1,
   while (true)
     {
       /* Ignore notes.  */
-      while (!INSN_P (i1) && i1 != BB_HEAD (bb1))
+      while (!NONDEBUG_INSN_P (i1) && i1 != BB_HEAD (bb1))
        i1 = PREV_INSN (i1);
 
-      while (!INSN_P (i2) && i2 != BB_HEAD (bb2))
+      while (!NONDEBUG_INSN_P (i2) && i2 != BB_HEAD (bb2))
        i2 = PREV_INSN (i2);
 
       if (i1 == BB_HEAD (bb1) || i2 == BB_HEAD (bb2))
@@ -1111,13 +1111,13 @@ flow_find_cross_jump (int mode ATTRIBUTE_UNUSED, basic_block bb1,
      Two, it keeps line number notes as matched as may be.  */
   if (ninsns)
     {
-      while (last1 != BB_HEAD (bb1) && !INSN_P (PREV_INSN (last1)))
+      while (last1 != BB_HEAD (bb1) && !NONDEBUG_INSN_P (PREV_INSN (last1)))
        last1 = PREV_INSN (last1);
 
       if (last1 != BB_HEAD (bb1) && LABEL_P (PREV_INSN (last1)))
        last1 = PREV_INSN (last1);
 
-      while (last2 != BB_HEAD (bb2) && !INSN_P (PREV_INSN (last2)))
+      while (last2 != BB_HEAD (bb2) && !NONDEBUG_INSN_P (PREV_INSN (last2)))
        last2 = PREV_INSN (last2);
 
       if (last2 != BB_HEAD (bb2) && LABEL_P (PREV_INSN (last2)))
@@ -1557,8 +1557,12 @@ try_crossjump_to_edge (int mode, edge e1, edge e2)
          /* Skip possible basic block header.  */
          if (LABEL_P (newpos2))
            newpos2 = NEXT_INSN (newpos2);
+         while (DEBUG_INSN_P (newpos2))
+           newpos2 = NEXT_INSN (newpos2);
          if (NOTE_P (newpos2))
            newpos2 = NEXT_INSN (newpos2);
+         while (DEBUG_INSN_P (newpos2))
+           newpos2 = NEXT_INSN (newpos2);
        }
 
       if (dump_file)
@@ -1643,9 +1647,16 @@ try_crossjump_to_edge (int mode, edge e1, edge e2)
   /* Skip possible basic block header.  */
   if (LABEL_P (newpos1))
     newpos1 = NEXT_INSN (newpos1);
+
+  while (DEBUG_INSN_P (newpos1))
+    newpos1 = NEXT_INSN (newpos1);
+
   if (NOTE_INSN_BASIC_BLOCK_P (newpos1))
     newpos1 = NEXT_INSN (newpos1);
 
+  while (DEBUG_INSN_P (newpos1))
+    newpos1 = NEXT_INSN (newpos1);
+
   redirect_from = split_block (src1, PREV_INSN (newpos1))->src;
   to_remove = single_succ (redirect_from);
 
@@ -1803,6 +1814,24 @@ try_crossjump_bb (int mode, basic_block bb)
   return changed;
 }
 
+/* Return true if BB contains just bb note, or bb note followed
+   by only DEBUG_INSNs.  */
+
+static bool
+trivially_empty_bb_p (basic_block bb)
+{
+  rtx insn = BB_END (bb);
+
+  while (1)
+    {
+      if (insn == BB_HEAD (bb))
+       return true;
+      if (!DEBUG_INSN_P (insn))
+       return false;
+      insn = PREV_INSN (insn);
+    }
+}
+
 /* Do simple CFG optimizations - basic block merging, simplifying of jump
    instructions etc.  Return nonzero if changes were made.  */
 
@@ -1846,16 +1875,18 @@ try_optimize_cfg (int mode)
 
              /* Delete trivially dead basic blocks.  This is either
                 blocks with no predecessors, or empty blocks with no
-                successors.  Empty blocks may result from expanding
+                successors.  However if the empty block with no
+                successors is the successor of the ENTRY_BLOCK, it is
+                kept.  This ensures that the ENTRY_BLOCK will have a
+                successor which is a precondition for many RTL
+                passes.  Empty blocks may result from expanding
                 __builtin_unreachable ().  */
              if (EDGE_COUNT (b->preds) == 0
-                 || (EDGE_COUNT (b->succs) == 0 && BB_HEAD (b) == BB_END (b)))
+                 || (EDGE_COUNT (b->succs) == 0
+                     && trivially_empty_bb_p (b)
+                     && single_succ_edge (ENTRY_BLOCK_PTR)->dest != b))
                {
                  c = b->prev_bb;
-                 if (dump_file)
-                   fprintf (dump_file, "Deleting block %i.\n",
-                            b->index);
-
                  delete_basic_block (b);
                  if (!(mode & CLEANUP_CFGLAYOUT))
                    changed = true;
@@ -1921,6 +1952,7 @@ try_optimize_cfg (int mode)
                  delete_basic_block (b);
                  changed = true;
                  b = c;
+                 continue;
                }
 
              if (single_succ_p (b)
@@ -2025,20 +2057,64 @@ bool
 delete_unreachable_blocks (void)
 {
   bool changed = false;
-  basic_block b, next_bb;
+  basic_block b, prev_bb;
 
   find_unreachable_blocks ();
 
-  /* Delete all unreachable basic blocks.  */
-
-  for (b = ENTRY_BLOCK_PTR->next_bb; b != EXIT_BLOCK_PTR; b = next_bb)
+  /* When we're in GIMPLE mode and there may be debug insns, we should
+     delete blocks in reverse dominator order, so as to get a chance
+     to substitute all released DEFs into debug stmts.  If we don't
+     have dominators information, walking blocks backward gets us a
+     better chance of retaining most debug information than
+     otherwise.  */
+  if (MAY_HAVE_DEBUG_STMTS && current_ir_type () == IR_GIMPLE
+      && dom_info_available_p (CDI_DOMINATORS))
     {
-      next_bb = b->next_bb;
+      for (b = EXIT_BLOCK_PTR->prev_bb; b != ENTRY_BLOCK_PTR; b = prev_bb)
+       {
+         prev_bb = b->prev_bb;
 
-      if (!(b->flags & BB_REACHABLE))
+         if (!(b->flags & BB_REACHABLE))
+           {
+             /* Speed up the removal of blocks that don't dominate
+                others.  Walking backwards, this should be the common
+                case.  */
+             if (!first_dom_son (CDI_DOMINATORS, b))
+               delete_basic_block (b);
+             else
+               {
+                 VEC (basic_block, heap) *h
+                   = get_all_dominated_blocks (CDI_DOMINATORS, b);
+
+                 while (VEC_length (basic_block, h))
+                   {
+                     b = VEC_pop (basic_block, h);
+
+                     prev_bb = b->prev_bb;
+
+                     gcc_assert (!(b->flags & BB_REACHABLE));
+
+                     delete_basic_block (b);
+                   }
+
+                 VEC_free (basic_block, heap, h);
+               }
+
+             changed = true;
+           }
+       }
+    }
+  else
+    {
+      for (b = EXIT_BLOCK_PTR->prev_bb; b != ENTRY_BLOCK_PTR; b = prev_bb)
        {
-         delete_basic_block (b);
-         changed = true;
+         prev_bb = b->prev_bb;
+
+         if (!(b->flags & BB_REACHABLE))
+           {
+             delete_basic_block (b);
+             changed = true;
+           }
        }
     }