OSDN Git Service

* varasm.c (align_variable): New function.
[pf3gnuchains/gcc-fork.git] / gcc / tree-cfgcleanup.c
index 0f8bfc5..ab452c4 100644 (file)
@@ -45,6 +45,7 @@ Boston, MA 02110-1301, USA.  */
 #include "cfglayout.h"
 #include "hashtab.h"
 #include "tree-ssa-propagate.h"
+#include "tree-scalar-evolution.h"
 
 /* Remove any fallthru edge from EV.  Return true if an edge was removed.  */
 
@@ -117,7 +118,7 @@ cleanup_control_expr_graph (basic_block bb, block_stmt_iterator bsi)
   else
     taken_edge = single_succ_edge (bb);
 
-  bsi_remove (&bsi);
+  bsi_remove (&bsi, true);
   taken_edge->flags = EDGE_FALLTHRU;
 
   /* We removed some paths from the cfg.  */
@@ -157,19 +158,24 @@ cleanup_control_flow (void)
     {
       bsi = bsi_last (bb);
 
+      /* If the last statement of the block could throw and now cannot,
+        we need to prune cfg.  */
+      tree_purge_dead_eh_edges (bb);
+
       if (bsi_end_p (bsi))
        continue;
 
       stmt = bsi_stmt (bsi);
+
       if (TREE_CODE (stmt) == COND_EXPR
          || TREE_CODE (stmt) == SWITCH_EXPR)
        retval |= cleanup_control_expr_graph (bb, bsi);
-
       /* If we had a computed goto which has a compile-time determinable
         destination, then we can eliminate the goto.  */
-      if (TREE_CODE (stmt) == GOTO_EXPR
-         && TREE_CODE (GOTO_DESTINATION (stmt)) == ADDR_EXPR
-         && TREE_CODE (TREE_OPERAND (GOTO_DESTINATION (stmt), 0)) == LABEL_DECL)
+      else if (TREE_CODE (stmt) == GOTO_EXPR
+              && TREE_CODE (GOTO_DESTINATION (stmt)) == ADDR_EXPR
+              && (TREE_CODE (TREE_OPERAND (GOTO_DESTINATION (stmt), 0))
+                  == LABEL_DECL))
        {
          edge e;
          tree label;
@@ -207,13 +213,13 @@ cleanup_control_flow (void)
 
          /* Remove the GOTO_EXPR as it is not needed.  The CFG has all the
             relevant information we need.  */
-         bsi_remove (&bsi);
+         bsi_remove (&bsi, true);
          retval = true;
        }
 
       /* Check for indirect calls that have been turned into
         noreturn calls.  */
-      if (noreturn_call_p (stmt) && remove_fallthru_edge (bb->succs))
+      else if (noreturn_call_p (stmt) && remove_fallthru_edge (bb->succs))
        {
          free_dominance_info (CDI_DOMINATORS);
          retval = true;
@@ -433,7 +439,7 @@ remove_forwarder_block (basic_block bb, basic_block **worklist)
        {
          label = bsi_stmt (bsi);
          gcc_assert (TREE_CODE (label) == LABEL_EXPR);
-         bsi_remove (&bsi);
+         bsi_remove (&bsi, false);
          bsi_insert_before (&bsi_to, label, BSI_CONTINUE_LINKING);
        }
     }
@@ -470,7 +476,7 @@ cleanup_forwarder_blocks (void)
 {
   basic_block bb;
   bool changed = false;
-  basic_block *worklist = xmalloc (sizeof (basic_block) * n_basic_blocks);
+  basic_block *worklist = XNEWVEC (basic_block, n_basic_blocks);
   basic_block *current = worklist;
 
   FOR_EACH_BB (bb)
@@ -523,17 +529,24 @@ cleanup_tree_cfg_1 (void)
 }
 
 
-/* Remove unreachable blocks and other miscellaneous clean up work.  */
+/* Remove unreachable blocks and other miscellaneous clean up work.
+   Return true if the flowgraph was modified, false otherwise.  */
 
 bool
 cleanup_tree_cfg (void)
 {
-  bool retval;
+  bool retval, changed;
 
   timevar_push (TV_TREE_CLEANUP_CFG);
 
+  /* Iterate until there are no more cleanups left to do.  If any
+     iteration changed the flowgraph, set CHANGED to true.  */
+  changed = false;
   do
-    retval = cleanup_tree_cfg_1 ();
+    {
+      retval = cleanup_tree_cfg_1 ();
+      changed |= retval;
+    }
   while (retval);
 
   compact_blocks ();
@@ -544,7 +557,7 @@ cleanup_tree_cfg (void)
 
   timevar_pop (TV_TREE_CLEANUP_CFG);
 
-  return retval;
+  return changed;
 }
 
 /* Cleanup cfg and repair loop structures.  */
@@ -552,23 +565,26 @@ cleanup_tree_cfg (void)
 void
 cleanup_tree_cfg_loop (void)
 {
-  bitmap changed_bbs = BITMAP_ALLOC (NULL);
+  bool changed = cleanup_tree_cfg ();
 
-  cleanup_tree_cfg ();
-
-  fix_loop_structure (current_loops, changed_bbs);
-  calculate_dominance_info (CDI_DOMINATORS);
+  if (changed)
+    {
+      bitmap changed_bbs = BITMAP_ALLOC (NULL);
+      fix_loop_structure (current_loops, changed_bbs);
+      calculate_dominance_info (CDI_DOMINATORS);
 
-  /* This usually does nothing.  But sometimes parts of cfg that originally
-     were inside a loop get out of it due to edge removal (since they
-     become unreachable by back edges from latch).  */
-  rewrite_into_loop_closed_ssa (changed_bbs, TODO_update_ssa);
+      /* This usually does nothing.  But sometimes parts of cfg that originally
+        were inside a loop get out of it due to edge removal (since they
+        become unreachable by back edges from latch).  */
+      rewrite_into_loop_closed_ssa (changed_bbs, TODO_update_ssa);
 
-  BITMAP_FREE (changed_bbs);
+      BITMAP_FREE (changed_bbs);
 
 #ifdef ENABLE_CHECKING
-  verify_loop_structure (current_loops);
+      verify_loop_structure (current_loops);
 #endif
+      scev_reset ();
+    }
 }
 
 /* Merge the PHI nodes at BB into those at BB's sole successor.  */
@@ -701,10 +717,10 @@ remove_forwarder_block_with_phi (basic_block bb)
 <L10>:;
 */
 
-static void
+static unsigned int
 merge_phi_nodes (void)
 {
-  basic_block *worklist = xmalloc (sizeof (basic_block) * n_basic_blocks);
+  basic_block *worklist = XNEWVEC (basic_block, n_basic_blocks);
   basic_block *current = worklist;
   basic_block bb;
 
@@ -736,6 +752,40 @@ merge_phi_nodes (void)
             nodes at BB.  */
          *current++ = bb;
        }
+      else
+       {
+         tree phi;
+         unsigned int dest_idx = single_succ_edge (bb)->dest_idx;
+
+         /* BB dominates DEST.  There may be many users of the PHI
+            nodes in BB.  However, there is still a trivial case we
+            can handle.  If the result of every PHI in BB is used
+            only by a PHI in DEST, then we can trivially merge the
+            PHI nodes from BB into DEST.  */
+         for (phi = phi_nodes (bb); phi; phi = PHI_CHAIN (phi))
+           {
+             tree result = PHI_RESULT (phi);
+             use_operand_p imm_use;
+             tree use_stmt;
+
+             /* If the PHI's result is never used, then we can just
+                ignore it.  */
+             if (has_zero_uses (result))
+               continue;
+
+             /* Get the single use of the result of this PHI node.  */
+             if (!single_imm_use (result, &imm_use, &use_stmt)
+                 || TREE_CODE (use_stmt) != PHI_NODE
+                 || bb_for_stmt (use_stmt) != dest
+                 || PHI_ARG_DEF (use_stmt, dest_idx) != result)
+               break;
+           }
+
+         /* If the loop above iterated through all the PHI nodes
+            in BB, then we can merge the PHIs from BB into DEST.  */
+         if (!phi)
+           *current++ = bb;
+       }
     }
 
   /* Now let's drain WORKLIST.  */
@@ -746,6 +796,7 @@ merge_phi_nodes (void)
     }
 
   free (worklist);
+  return 0;
 }
 
 static bool