]> gcc.gnu.org Git - gcc.git/commitdiff
tree-cfg.c (find_taken_edge_computed_goto): New function.
authorJeff Law <law@redhat.com>
Tue, 8 Mar 2005 03:39:19 +0000 (20:39 -0700)
committerJeff Law <law@gcc.gnu.org>
Tue, 8 Mar 2005 03:39:19 +0000 (20:39 -0700)
        * tree-cfg.c (find_taken_edge_computed_goto): New function.
        (find_taken_edge): Call find_taken_edge_computed_goto as
        appropriate.  Allow any gimple invariant rather than just
        INTEGER_CST for VAL.
        (cleanup_control_flow): Cleanup a computed goto which has turned
        into a simple goto.
        (tree_merge_blocks): If block B has any forced labels, move
        them to the start of block A.
        * tree-ssa-dom.c (thread_across_edge): Allow threading across
        computed gotos as well.
        * tree-ssa-threadupdate.c (remove_ctrl_stmt_and_useless_edges): Handle
        removal of unnecessary computed gotos too.
        (lookup_redirection_data): Fix type of INSERT argument.  Callers
        updated.

From-SVN: r96084

gcc/ChangeLog
gcc/tree-cfg.c
gcc/tree-ssa-dom.c
gcc/tree-ssa-threadupdate.c

index a18e5c85a0c1e09e74df460f7564488c6d23cbf7..99505d8b56866fd0de1f8dca61bb6e21ab712dae 100644 (file)
@@ -1,3 +1,20 @@
+2005-03-07  Jeff Law  <law@redhat.com>
+
+       * tree-cfg.c (find_taken_edge_computed_goto): New function.
+       (find_taken_edge): Call find_taken_edge_computed_goto as
+       appropriate.  Allow any gimple invariant rather than just
+       INTEGER_CST for VAL.
+       (cleanup_control_flow): Cleanup a computed goto which has turned
+       into a simple goto.
+       (tree_merge_blocks): If block B has any forced labels, move
+       them to the start of block A.
+       * tree-ssa-dom.c (thread_across_edge): Allow threading across
+       computed gotos as well.
+       * tree-ssa-threadupdate.c (remove_ctrl_stmt_and_useless_edges): Handle
+       removal of unnecessary computed gotos too.
+       (lookup_redirection_data): Fix type of INSERT argument.  Callers
+       updated.
+
 2005-03-08  Kazu Hirata  <kazu@cs.umass.edu>
 
        * tree-ssa-phiopt.c: Update copyright.  Fix indentations.
index 205b5c0e82e7a57019d9184bba51f5a9bf531cde..7622bf77190c3afdc3154079179d58f278cf72d3 100644 (file)
@@ -129,6 +129,7 @@ static bool tree_can_merge_blocks_p (basic_block, basic_block);
 static void remove_bb (basic_block);
 static bool cleanup_control_flow (void);
 static bool cleanup_control_expr_graph (basic_block, block_stmt_iterator);
+static edge find_taken_edge_computed_goto (basic_block, tree);
 static edge find_taken_edge_cond_expr (basic_block, tree);
 static edge find_taken_edge_switch_expr (basic_block, tree);
 static tree find_case_label_for_value (tree, tree);
@@ -1301,7 +1302,22 @@ tree_merge_blocks (basic_block a, basic_block b)
   for (bsi = bsi_start (b); !bsi_end_p (bsi);)
     {
       if (TREE_CODE (bsi_stmt (bsi)) == LABEL_EXPR)
-       bsi_remove (&bsi);
+       {
+         tree label = bsi_stmt (bsi);
+
+         bsi_remove (&bsi);
+         /* Now that we can thread computed gotos, we might have
+            a situation where we have a forced label in block B
+            However, the label at the start of block B might still be
+            used in other ways (think about the runtime checking for
+            Fortran assigned gotos).  So we can not just delete the
+            label.  Instead we move the label to the start of block A.  */
+         if (FORCED_LABEL (LABEL_EXPR_LABEL (label)))
+           {
+             block_stmt_iterator dest_bsi = bsi_start (a);
+             bsi_insert_before (&dest_bsi, label, BSI_NEW_STMT);
+           }
+       }
       else
        {
          set_bb_for_stmt (bsi_stmt (bsi), a);
@@ -2122,6 +2138,43 @@ cleanup_control_flow (void)
          || 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)
+       {
+         edge e;
+         tree label;
+         edge_iterator ei;
+         basic_block target_block;
+
+         /* First look at all the outgoing edges.  Delete any outgoing
+            edges which do not go to the right block.  For the one
+            edge which goes to the right block, fix up its flags.  */
+         label = TREE_OPERAND (GOTO_DESTINATION (stmt), 0);
+         target_block = label_to_block (label);
+         for (ei = ei_start (bb->succs); (e = ei_safe_edge (ei)); )
+           {
+             if (e->dest != target_block)
+               remove_edge (e);
+             else
+               {
+                 /* Turn off the EDGE_ABNORMAL flag.  */
+                 EDGE_SUCC (bb, 0)->flags &= ~EDGE_ABNORMAL;
+
+                 /* And set EDGE_FALLTHRU.  */
+                 EDGE_SUCC (bb, 0)->flags |= EDGE_FALLTHRU;
+                 ei_next (&ei);
+               }
+           }
+
+         /* Remove the GOTO_EXPR as it is not needed.  The CFG has all the
+            relevant information we need.  */
+         bsi_remove (&bsi);
+         retval = true;
+       }
+
       /* Check for indirect calls that have been turned into
         noreturn calls.  */
       if (noreturn_call_p (stmt) && remove_fallthru_edge (bb->succs))
@@ -2229,7 +2282,7 @@ find_taken_edge (basic_block bb, tree val)
   gcc_assert (is_ctrl_stmt (stmt));
   gcc_assert (val);
 
-  if (TREE_CODE (val) != INTEGER_CST)
+  if (! is_gimple_min_invariant (val))
     return NULL;
 
   if (TREE_CODE (stmt) == COND_EXPR)
@@ -2238,9 +2291,31 @@ find_taken_edge (basic_block bb, tree val)
   if (TREE_CODE (stmt) == SWITCH_EXPR)
     return find_taken_edge_switch_expr (bb, val);
 
+  if (computed_goto_p (stmt))
+    return find_taken_edge_computed_goto (bb, TREE_OPERAND( val, 0));
+
   gcc_unreachable ();
 }
 
+/* Given a constant value VAL and the entry block BB to a GOTO_EXPR
+   statement, determine which of the outgoing edges will be taken out of the
+   block.  Return NULL if either edge may be taken.  */
+
+static edge
+find_taken_edge_computed_goto (basic_block bb, tree val)
+{
+  basic_block dest;
+  edge e = NULL;
+
+  dest = label_to_block (val);
+  if (dest)
+    {
+      e = find_edge (bb, dest);
+      gcc_assert (e != NULL);
+    }
+
+  return e;
+}
 
 /* Given a constant value VAL and the entry block BB to a COND_EXPR
    statement, determine which of the two edges will be taken out of the
index a14356500aa83b9e0f46e774d709b2f228882a60..aaa0dc5f491621d2b5514fdda837fd87f983cf91 100644 (file)
@@ -715,7 +715,8 @@ thread_across_edge (struct dom_walk_data *walk_data, edge e)
      arm will be taken.  */
   if (stmt
       && (TREE_CODE (stmt) == COND_EXPR
-         || TREE_CODE (stmt) == SWITCH_EXPR))
+         || TREE_CODE (stmt) == SWITCH_EXPR
+         || TREE_CODE (stmt) == GOTO_EXPR))
     {
       tree cond, cached_lhs;
 
@@ -723,6 +724,8 @@ thread_across_edge (struct dom_walk_data *walk_data, edge e)
         expression in the hash tables.  */
       if (TREE_CODE (stmt) == COND_EXPR)
        cond = COND_EXPR_COND (stmt);
+      else if (TREE_CODE (stmt) == GOTO_EXPR)
+       cond = GOTO_DESTINATION (stmt);
       else
        cond = SWITCH_COND (stmt);
 
@@ -1000,6 +1003,18 @@ dom_opt_finalize_block (struct dom_walk_data *walk_data, basic_block bb)
     {
       thread_across_edge (walk_data, EDGE_SUCC (bb, 0));
     }
+  else if ((last = last_stmt (bb))
+          && TREE_CODE (last) == GOTO_EXPR
+          && TREE_CODE (TREE_OPERAND (last, 0)) == SSA_NAME)
+    {
+      edge_iterator ei;
+      edge e;
+
+      FOR_EACH_EDGE (e, ei, bb->succs)
+       {
+         thread_across_edge (walk_data, e);
+       }
+    }
   else if ((last = last_stmt (bb))
           && TREE_CODE (last) == COND_EXPR
           && (COMPARISON_CLASS_P (COND_EXPR_COND (last))
index d798713a43938dfc08d4f00ce689ecb98a0d27f3..e1e0d3ea889ce2299a5dcb54e87a1a27425e864d 100644 (file)
@@ -169,6 +169,7 @@ remove_ctrl_stmt_and_useless_edges (basic_block bb, basic_block dest_bb)
   if (!bsi_end_p (bsi)
       && bsi_stmt (bsi)
       && (TREE_CODE (bsi_stmt (bsi)) == COND_EXPR
+         || TREE_CODE (bsi_stmt (bsi)) == GOTO_EXPR
          || TREE_CODE (bsi_stmt (bsi)) == SWITCH_EXPR))
     bsi_remove (&bsi);
 
@@ -228,7 +229,7 @@ redirection_data_eq (const void *p1, const void *p2)
    edges associated with E in the hash table.  */
 
 static struct redirection_data *
-lookup_redirection_data (edge e, edge incoming_edge, bool insert)
+lookup_redirection_data (edge e, edge incoming_edge, enum insert_option insert)
 {
   void **slot;
   struct redirection_data *elt;
@@ -733,7 +734,7 @@ thread_block (basic_block bb)
 
          /* Insert the outgoing edge into the hash table if it is not
             already in the hash table.  */
-         lookup_redirection_data (e2, e, true);
+         lookup_redirection_data (e2, e, INSERT);
        }
     }
 
@@ -744,7 +745,7 @@ thread_block (basic_block bb)
   if (all)
     {
       edge e = EDGE_PRED (bb, 0)->aux;
-      lookup_redirection_data (e, NULL, false)->do_not_duplicate = true;
+      lookup_redirection_data (e, NULL, NO_INSERT)->do_not_duplicate = true;
     }
 
   /* Now create duplicates of BB.
This page took 0.083974 seconds and 5 git commands to generate.