OSDN Git Service

* array.c: Don't include assert.h.
[pf3gnuchains/gcc-fork.git] / gcc / tree-cfg.c
index 6207fd3..ce0be96 100644 (file)
@@ -99,8 +99,6 @@ static void tree_cfg2vcg (FILE *);
 static void tree_merge_blocks (basic_block, basic_block);
 static bool tree_can_merge_blocks_p (basic_block, basic_block);
 static void remove_bb (basic_block);
-static void group_case_labels (void);
-static void cleanup_dead_labels (void);
 static bool cleanup_control_flow (void);
 static bool cleanup_control_expr_graph (basic_block, block_stmt_iterator);
 static edge find_taken_edge_cond_expr (basic_block, tree);
@@ -127,6 +125,7 @@ build_tree_cfg (tree *tp)
 
   /* Initialize the basic block array.  */
   init_flow ();
+  profile_status = PROFILE_ABSENT;
   n_basic_blocks = 0;
   last_basic_block = 0;
   VARRAY_BB_INIT (basic_block_info, initial_cfg_capacity, "basic_block_info");
@@ -208,7 +207,8 @@ struct tree_opt_pass pass_build_cfg =
   PROP_cfg,                            /* properties_provided */
   0,                                   /* properties_destroyed */
   0,                                   /* todo_flags_start */
-  TODO_verify_stmts                    /* todo_flags_finish */
+  TODO_verify_stmts,                   /* todo_flags_finish */
+  0                                    /* letter */
 };
 
 /* Search the CFG for any computed gotos.  If found, factor them to a 
@@ -448,7 +448,7 @@ make_edges (void)
 
   /* We do not care about fake edges, so remove any that the CFG
      builder inserted for completeness.  */
-  remove_fake_edges ();
+  remove_fake_exit_edges ();
 
   /* Clean up the graph and warn for unreachable code.  */
   cleanup_tree_cfg ();
@@ -461,17 +461,12 @@ static void
 make_ctrl_stmt_edges (basic_block bb)
 {
   tree last = last_stmt (bb);
-  tree first = first_stmt (bb);
 
 #if defined ENABLE_CHECKING
   if (last == NULL_TREE)
     abort();
 #endif
 
-  if (TREE_CODE (first) == LABEL_EXPR
-      && DECL_NONLOCAL (LABEL_EXPR_LABEL (first)))
-    make_edge (ENTRY_BLOCK_PTR, bb, EDGE_ABNORMAL);
-
   switch (TREE_CODE (last))
     {
     case GOTO_EXPR:
@@ -723,10 +718,11 @@ make_goto_expr_edges (basic_block bb)
 
 /* Remove unreachable blocks and other miscellaneous clean up work.  */
 
-void
+bool
 cleanup_tree_cfg (void)
 {
   bool something_changed = true;
+  bool retval = false;
 
   timevar_push (TV_TREE_CLEANUP_CFG);
 
@@ -735,8 +731,9 @@ cleanup_tree_cfg (void)
   while (something_changed)
     {
       something_changed = cleanup_control_flow ();
-      something_changed |= thread_jumps ();
       something_changed |= delete_unreachable_blocks ();
+      something_changed |= thread_jumps ();
+      retval |= something_changed;
     }
 
   /* Merging the blocks creates no new opportunities for the other
@@ -749,6 +746,7 @@ cleanup_tree_cfg (void)
   verify_flow_info ();
 #endif
   timevar_pop (TV_TREE_CLEANUP_CFG);
+  return retval;
 }
 
 
@@ -769,7 +767,16 @@ update_eh_label (struct eh_region *region)
   tree old_label = get_eh_region_tree_label (region);
   if (old_label)
     {
-      tree new_label = label_for_bb[label_to_block (old_label)->index];
+      tree new_label;
+      basic_block bb = label_to_block (old_label);
+
+      /* ??? After optimizing, there may be EH regions with labels
+        that have already been removed from the function body, so
+        there is no basic block for them.  */
+      if (! bb)
+       return;
+
+      new_label = label_for_bb[bb->index];
       set_eh_region_tree_label (region, new_label);
     }
 }
@@ -791,7 +798,7 @@ main_block_label (tree label)
      2) Redirect all references to labels to the leading labels.
      3) Cleanup all useless labels.  */
 
-static void
+void
 cleanup_dead_labels (void)
 {
   basic_block bb;
@@ -924,7 +931,7 @@ cleanup_dead_labels (void)
    same label.
    Eg. three separate entries 1: 2: 3: become one entry 1..3:  */
 
-static void
+void
 group_case_labels (void)
 {
   basic_block bb;
@@ -1641,7 +1648,8 @@ struct tree_opt_pass pass_remove_useless_stmts =
   0,                                   /* properties_provided */
   0,                                   /* properties_destroyed */
   0,                                   /* todo_flags_start */
-  TODO_dump_func                       /* todo_flags_finish */
+  TODO_dump_func,                      /* todo_flags_finish */
+  0                                    /* letter */
 };
 
 
@@ -1732,13 +1740,14 @@ cfg_remove_useless_stmts_bb (basic_block bb)
          continue;
        }
 
-      /* Invalidate the var if we encounter something that could modify it.  */
+      /* Invalidate the var if we encounter something that could modify it.
+        Likewise for the value it was previously set to.  Note that we only
+        consider values that are either a VAR_DECL or PARM_DECL so we
+        can test for conflict very simply.  */
       if (TREE_CODE (stmt) == ASM_EXPR
-         || TREE_CODE (stmt) == VA_ARG_EXPR
          || (TREE_CODE (stmt) == MODIFY_EXPR
              && (TREE_OPERAND (stmt, 0) == var
-                 || TREE_OPERAND (stmt, 0) == val
-                 || TREE_CODE (TREE_OPERAND (stmt, 1)) == VA_ARG_EXPR)))
+                 || TREE_OPERAND (stmt, 0) == val)))
        return;
   
       bsi_next (&bsi);
@@ -1993,7 +2002,7 @@ cleanup_control_expr_graph (basic_block bb, block_stmt_iterator bsi)
 
 /* Given a control block BB and a predicate VAL, return the edge that
    will be taken out of the block.  If VAL does not match a unique
-   edge, NULL is returned. */
+   edge, NULL is returned.  */
 
 edge
 find_taken_edge (basic_block bb, tree val)
@@ -2168,84 +2177,6 @@ phi_alternatives_equal (basic_block dest, edge e1, edge e2)
 }
 
 
-/* Computing the Dominance Frontier:
-
-   As described in Morgan, section 3.5, this may be done simply by
-   walking the dominator tree bottom-up, computing the frontier for
-   the children before the parent.  When considering a block B,
-   there are two cases:
-
-   (1) A flow graph edge leaving B that does not lead to a child
-   of B in the dominator tree must be a block that is either equal
-   to B or not dominated by B.  Such blocks belong in the frontier
-   of B.
-
-   (2) Consider a block X in the frontier of one of the children C
-   of B.  If X is not equal to B and is not dominated by B, it
-   is in the frontier of B.  */
-
-static void
-compute_dominance_frontiers_1 (bitmap *frontiers, basic_block bb, sbitmap done)
-{
-  edge e;
-  basic_block c;
-
-  SET_BIT (done, bb->index);
-
-  /* Do the frontier of the children first.  Not all children in the
-     dominator tree (blocks dominated by this one) are children in the
-     CFG, so check all blocks.  */
-  for (c = first_dom_son (CDI_DOMINATORS, bb);
-       c;
-       c = next_dom_son (CDI_DOMINATORS, c))
-    {
-      if (! TEST_BIT (done, c->index))
-       compute_dominance_frontiers_1 (frontiers, c, done);
-    }
-      
-  /* Find blocks conforming to rule (1) above.  */
-  for (e = bb->succ; e; e = e->succ_next)
-    {
-      if (e->dest == EXIT_BLOCK_PTR)
-       continue;
-      if (get_immediate_dominator (CDI_DOMINATORS, e->dest) != bb)
-       bitmap_set_bit (frontiers[bb->index], e->dest->index);
-    }
-
-  /* Find blocks conforming to rule (2).  */
-  for (c = first_dom_son (CDI_DOMINATORS, bb);
-       c;
-       c = next_dom_son (CDI_DOMINATORS, c))
-    {
-      int x;
-
-      EXECUTE_IF_SET_IN_BITMAP (frontiers[c->index], 0, x,
-       {
-         if (get_immediate_dominator (CDI_DOMINATORS, BASIC_BLOCK (x)) != bb)
-           bitmap_set_bit (frontiers[bb->index], x);
-       });
-    }
-}
-
-
-void
-compute_dominance_frontiers (bitmap *frontiers)
-{
-  sbitmap done = sbitmap_alloc (last_basic_block);
-
-  timevar_push (TV_DOM_FRONTIERS);
-
-  sbitmap_zero (done);
-
-  compute_dominance_frontiers_1 (frontiers, ENTRY_BLOCK_PTR->succ->dest, done);
-
-  sbitmap_free (done);
-
-  timevar_pop (TV_DOM_FRONTIERS);
-}
-
-
-
 /*---------------------------------------------------------------------------
                              Debugging functions
 ---------------------------------------------------------------------------*/
@@ -2537,10 +2468,8 @@ computed_goto_p (tree t)
 bool
 simple_goto_p (tree expr)
 {
-  return  (TREE_CODE (expr) == GOTO_EXPR
-          && TREE_CODE (GOTO_DESTINATION (expr)) == LABEL_DECL
-          && (decl_function_context (GOTO_DESTINATION (expr))
-              == current_function_decl));
+  return (TREE_CODE (expr) == GOTO_EXPR
+         && TREE_CODE (GOTO_DESTINATION (expr)) == LABEL_DECL);
 }
 
 
@@ -2804,6 +2733,19 @@ set_bb_for_stmt (tree t, basic_block bb)
     }
 }
 
+/* Finds iterator for STMT.  */
+
+extern block_stmt_iterator
+stmt_for_bsi (tree stmt)
+{
+  block_stmt_iterator bsi;
+
+  for (bsi = bsi_start (bb_for_stmt (stmt)); !bsi_end_p (bsi); bsi_next (&bsi))
+    if (bsi_stmt (bsi) == stmt)
+      return bsi;
+
+  abort ();
+}
 
 /* Insert statement (or statement list) T before the statement
    pointed-to by iterator I.  M specifies how to update iterator I
@@ -2813,8 +2755,8 @@ void
 bsi_insert_before (block_stmt_iterator *i, tree t, enum bsi_iterator_update m)
 {
   set_bb_for_stmt (t, i->bb);
-  modify_stmt (t);
   tsi_link_before (&i->tsi, t, m);
+  modify_stmt (t);
 }
 
 
@@ -2826,8 +2768,8 @@ void
 bsi_insert_after (block_stmt_iterator *i, tree t, enum bsi_iterator_update m)
 {
   set_bb_for_stmt (t, i->bb);
-  modify_stmt (t);
   tsi_link_after (&i->tsi, t, m);
+  modify_stmt (t);
 }
 
 
@@ -2839,7 +2781,6 @@ bsi_remove (block_stmt_iterator *i)
 {
   tree t = bsi_stmt (*i);
   set_bb_for_stmt (t, NULL);
-  modify_stmt (t);
   tsi_delink (&i->tsi);
 }
 
@@ -2915,10 +2856,12 @@ bsi_replace (const block_stmt_iterator *bsi, tree stmt, bool preserve_eh_info)
 
    In all cases, the returned *BSI points to the correct location.  The
    return value is true if insertion should be done after the location,
-   or false if it should be done before the location.  */
+   or false if it should be done before the location.  If new basic block
+   has to be created, it is stored in *NEW_BB.  */
 
 static bool
-tree_find_edge_insert_loc (edge e, block_stmt_iterator *bsi)
+tree_find_edge_insert_loc (edge e, block_stmt_iterator *bsi,
+                          basic_block *new_bb)
 {
   basic_block dest, src;
   tree tmp;
@@ -2995,6 +2938,8 @@ tree_find_edge_insert_loc (edge e, block_stmt_iterator *bsi)
 
   /* Otherwise, create a new basic block, and split this edge.  */
   dest = split_edge (e);
+  if (new_bb)
+    *new_bb = dest;
   e = dest->pred;
   goto restart;
 }
@@ -3038,7 +2983,7 @@ bsi_commit_edge_inserts_1 (edge e)
 
       PENDING_STMT (e) = NULL_TREE;
 
-      if (tree_find_edge_insert_loc (e, &bsi))
+      if (tree_find_edge_insert_loc (e, &bsi, NULL))
        bsi_insert_after (&bsi, stmt, BSI_NEW_STMT);
       else
        bsi_insert_before (&bsi, stmt, BSI_NEW_STMT);
@@ -3055,6 +3000,25 @@ bsi_insert_on_edge (edge e, tree stmt)
   append_to_statement_list (stmt, &PENDING_STMT (e));
 }
 
+/* Similar to bsi_insert_on_edge+bsi_commit_edge_inserts.  If new block has to
+   be created, it is returned.  */
+
+basic_block
+bsi_insert_on_edge_immediate (edge e, tree stmt)
+{
+  block_stmt_iterator bsi;
+  basic_block new_bb = NULL;
+
+  if (PENDING_STMT (e))
+    abort ();
+
+  if (tree_find_edge_insert_loc (e, &bsi, &new_bb))
+    bsi_insert_after (&bsi, stmt, BSI_NEW_STMT);
+  else
+    bsi_insert_before (&bsi, stmt, BSI_NEW_STMT);
+
+  return new_bb;
+}
 
 /*---------------------------------------------------------------------------
             Tree specific functions for CFG manipulation
@@ -3900,7 +3864,7 @@ static bool
 thread_jumps (void)
 {
   edge e, next, last, old;
-  basic_block bb, dest, tmp;
+  basic_block bb, dest, tmp, old_dest, dom;
   tree phi;
   int arg;
   bool retval = false;
@@ -3987,11 +3951,9 @@ thread_jumps (void)
 
          /* Perform the redirection.  */
          retval = true;
+         old_dest = e->dest;
          e = redirect_edge_and_branch (e, dest);
 
-         /* TODO -- updating dominators in this case is simple.  */
-         free_dominance_info (CDI_DOMINATORS);
-
          if (!old)
            {
              /* Update PHI nodes.   We know that the new argument should
@@ -4005,6 +3967,49 @@ thread_jumps (void)
                  add_phi_arg (&phi, PHI_ARG_DEF (phi, arg), e);
                }
            }
+
+         /* Update the dominators.  */
+         if (dom_computed[CDI_DOMINATORS] >= DOM_CONS_OK)
+           {
+             /* Remove the unreachable blocks (observe that if all blocks
+                were reachable before, only those in the path we threaded
+                over and did not have any predecessor outside of the path
+                become unreachable).  */
+             for (; old_dest != dest; old_dest = tmp)
+               {
+                 tmp = old_dest->succ->dest;
+
+                 if (old_dest->pred)
+                   break;
+
+                 delete_basic_block (old_dest);
+               }
+             /* If the dominator of the destination was in the path, set its
+                dominator to the start of the redirected edge.  */
+             if (get_immediate_dominator (CDI_DOMINATORS, old_dest) == NULL)
+               set_immediate_dominator (CDI_DOMINATORS, old_dest, bb);
+
+             /* Now proceed like if we forwarded just over one edge at a time.
+                Algorithm for forwarding over edge A --> B then is
+
+                if (idom (B) == A)
+                  idom (B) = idom (A);
+                recount_idom (A);  */
+
+             for (; old_dest != dest; old_dest = tmp)
+               {
+                 tmp = old_dest->succ->dest;
+
+                 if (get_immediate_dominator (CDI_DOMINATORS, tmp) == old_dest)
+                   {
+                     dom = get_immediate_dominator (CDI_DOMINATORS, old_dest);
+                     set_immediate_dominator (CDI_DOMINATORS, tmp, dom);
+                   }
+
+                 dom = recount_dominator (CDI_DOMINATORS, old_dest);
+                 set_immediate_dominator (CDI_DOMINATORS, old_dest, dom);
+               }
+           }
        }
 
       /* Reset the forwardable bit on our block since it's no longer in
@@ -4259,8 +4264,16 @@ tree_duplicate_bb (basic_block bb)
 {
   basic_block new_bb;
   block_stmt_iterator bsi, bsi_tgt;
+  tree phi, val;
+  ssa_op_iter op_iter;
 
   new_bb = create_empty_bb (EXIT_BLOCK_PTR->prev_bb);
+
+  for (phi = phi_nodes (bb); phi; phi = TREE_CHAIN (phi))
+    {
+      mark_for_rewrite (PHI_RESULT (phi));
+    }
+
   bsi_tgt = bsi_start (new_bb);
   for (bsi = bsi_start (bb); !bsi_end_p (bsi); bsi_next (&bsi))
     {
@@ -4270,6 +4283,12 @@ tree_duplicate_bb (basic_block bb)
       if (TREE_CODE (stmt) == LABEL_EXPR)
        continue;
 
+      /* Record the definitions.  */
+      get_stmt_operands (stmt);
+
+      FOR_EACH_SSA_TREE_OPERAND (val, stmt, op_iter, SSA_OP_ALL_DEFS)
+       mark_for_rewrite (val);
+
       copy = unshare_expr (stmt);
 
       /* Copy also the virtual operands.  */
@@ -4332,6 +4351,7 @@ dump_function_to_file (tree fn, FILE *file, int flags)
   if (basic_block_info)
     {
       /* Make a CFG based dump.  */
+      check_bb_profile (ENTRY_BLOCK_PTR, file);
       if (!ignore_topmost_bind)
        fprintf (file, "{\n");
 
@@ -4342,6 +4362,7 @@ dump_function_to_file (tree fn, FILE *file, int flags)
        dump_generic_bb (file, bb, 2, flags);
        
       fprintf (file, "}\n");
+      check_bb_profile (EXIT_BLOCK_PTR, file);
     }
   else
     {
@@ -4746,8 +4767,82 @@ struct tree_opt_pass pass_split_crit_edges =
   PROP_no_crit_edges,            /* properties_provided */
   0,                             /* properties_destroyed */
   0,                             /* todo_flags_start */
-  TODO_dump_func,                             /* todo_flags_finish */
+  TODO_dump_func,                /* todo_flags_finish */
+  0                              /* letter */
 };
+
+\f
+/* Return EXP if it is a valid GIMPLE rvalue, else gimplify it into
+   a temporary, make sure and register it to be renamed if necessary,
+   and finally return the temporary.  Put the statements to compute
+   EXP before the current statement in BSI.  */
+
+tree
+gimplify_val (block_stmt_iterator *bsi, tree type, tree exp)
+{
+  tree t, new_stmt, orig_stmt;
+
+  if (is_gimple_val (exp))
+    return exp;
+
+  t = make_rename_temp (type, NULL);
+  new_stmt = build (MODIFY_EXPR, type, t, exp);
+
+  orig_stmt = bsi_stmt (*bsi);
+  SET_EXPR_LOCUS (new_stmt, EXPR_LOCUS (orig_stmt));
+  TREE_BLOCK (new_stmt) = TREE_BLOCK (orig_stmt);
+
+  bsi_insert_before (bsi, new_stmt, BSI_SAME_STMT);
+
+  return t;
+}
+
+/* Build a ternary operation and gimplify it.  Emit code before BSI.
+   Return the gimple_val holding the result.  */
+
+tree
+gimplify_build3 (block_stmt_iterator *bsi, enum tree_code code,
+                tree type, tree a, tree b, tree c)
+{
+  tree ret;
+
+  ret = fold (build3 (code, type, a, b, c));
+  STRIP_NOPS (ret);
+
+  return gimplify_val (bsi, type, ret);
+}
+
+/* Build a binary operation and gimplify it.  Emit code before BSI.
+   Return the gimple_val holding the result.  */
+
+tree
+gimplify_build2 (block_stmt_iterator *bsi, enum tree_code code,
+                tree type, tree a, tree b)
+{
+  tree ret;
+
+  ret = fold (build2 (code, type, a, b));
+  STRIP_NOPS (ret);
+
+  return gimplify_val (bsi, type, ret);
+}
+
+/* Build a unary operation and gimplify it.  Emit code before BSI.
+   Return the gimple_val holding the result.  */
+
+tree
+gimplify_build1 (block_stmt_iterator *bsi, enum tree_code code, tree type,
+                tree a)
+{
+  tree ret;
+
+  ret = fold (build1 (code, type, a));
+  STRIP_NOPS (ret);
+
+  return gimplify_val (bsi, type, ret);
+}
+
+
 \f
 /* Emit return warnings.  */
 
@@ -4867,7 +4962,8 @@ struct tree_opt_pass pass_warn_function_return =
   0,                                   /* properties_provided */
   0,                                   /* properties_destroyed */
   0,                                   /* todo_flags_start */
-  0                                    /* todo_flags_finish */
+  0,                                   /* todo_flags_finish */
+  0                                    /* letter */
 };
 
 #include "gt-tree-cfg.h"