OSDN Git Service

* crontab: Spread snapshot building more evenly throughout the
[pf3gnuchains/gcc-fork.git] / gcc / tree-cfg.c
index 26dced0..9eeb783 100644 (file)
@@ -132,6 +132,26 @@ static tree find_case_label_for_value (tree, tree);
 static bool phi_alternatives_equal (basic_block, edge, edge);
 static bool cleanup_forwarder_blocks (void);
 
+void
+init_empty_tree_cfg (void)
+{
+  /* 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");
+
+  /* Build a mapping of labels to their associated blocks.  */
+  VARRAY_BB_INIT (label_to_block_map, initial_cfg_capacity,
+                 "label to block map");
+
+  ENTRY_BLOCK_PTR->next_bb = EXIT_BLOCK_PTR;
+  EXIT_BLOCK_PTR->prev_bb = ENTRY_BLOCK_PTR;
+
+  create_block_annotation (ENTRY_BLOCK_PTR);
+  create_block_annotation (EXIT_BLOCK_PTR);
+}
 
 /*---------------------------------------------------------------------------
                              Create basic blocks
@@ -146,20 +166,9 @@ build_tree_cfg (tree *tp)
   /* Register specific tree functions.  */
   tree_register_cfg_hooks ();
 
-  /* 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");
   memset ((void *) &cfg_stats, 0, sizeof (cfg_stats));
 
-  /* Build a mapping of labels to their associated blocks.  */
-  VARRAY_BB_INIT (label_to_block_map, initial_cfg_capacity,
-                 "label to block map");
-
-  ENTRY_BLOCK_PTR->next_bb = EXIT_BLOCK_PTR;
-  EXIT_BLOCK_PTR->prev_bb = ENTRY_BLOCK_PTR;
+  init_empty_tree_cfg ();
 
   found_computed_goto = 0;
   make_blocks (*tp);
@@ -176,9 +185,6 @@ build_tree_cfg (tree *tp)
   if (n_basic_blocks == 0)
     create_empty_bb (ENTRY_BLOCK_PTR);
 
-  create_block_annotation (ENTRY_BLOCK_PTR);
-  create_block_annotation (EXIT_BLOCK_PTR);
-  
   /* Adjust the size of the array.  */
   VARRAY_GROW (basic_block_info, n_basic_blocks);
 
@@ -206,6 +212,10 @@ build_tree_cfg (tree *tp)
       }
   }
 
+#ifdef ENABLE_CHECKING
+  verify_stmts ();
+#endif
+
   /* Dump a textual representation of the flowgraph.  */
   if (dump_file)
     dump_tree_cfg (dump_file, dump_flags);
@@ -436,7 +446,7 @@ create_bb (void *h, void *e, basic_block after)
 
 /* Fold COND_EXPR_COND of each COND_EXPR.  */
 
-static void
+void
 fold_cond_expr_cond (void)
 {
   basic_block bb;
@@ -823,6 +833,8 @@ label_to_block_fn (struct function *ifun, tree dest)
       bsi_insert_before (&bsi, stmt, BSI_NEW_STMT);
       uid = LABEL_DECL_UID (dest);
     }
+  if (VARRAY_SIZE (ifun->cfg->x_label_to_block_map) <= (unsigned int)uid)
+    return NULL;
   return VARRAY_BB (ifun->cfg->x_label_to_block_map, uid);
 }
 
@@ -1249,6 +1261,7 @@ tree_can_merge_blocks_p (basic_block a, basic_block b)
 {
   tree stmt;
   block_stmt_iterator bsi;
+  tree phi;
 
   if (!single_succ_p (a))
     return false;
@@ -1276,9 +1289,19 @@ tree_can_merge_blocks_p (basic_block a, basic_block b)
       && DECL_NONLOCAL (LABEL_EXPR_LABEL (stmt)))
     return false;
 
-  /* There may be no PHI nodes at the start of B.  */
-  if (phi_nodes (b))
-    return false;
+  /* It must be possible to eliminate all phi nodes in B.  If ssa form
+     is not up-to-date, we cannot eliminate any phis.  */
+  phi = phi_nodes (b);
+  if (phi)
+    {
+      if (need_ssa_update_p ())
+       return false;
+
+      for (; phi; phi = PHI_CHAIN (phi))
+       if (!is_gimple_reg (PHI_RESULT (phi))
+           && !may_propagate_copy (PHI_RESULT (phi), PHI_ARG_DEF (phi, 0)))
+         return false;
+    }
 
   /* Do not remove user labels.  */
   for (bsi = bsi_start (b); !bsi_end_p (bsi); bsi_next (&bsi))
@@ -1298,6 +1321,55 @@ tree_can_merge_blocks_p (basic_block a, basic_block b)
   return true;
 }
 
+/* Replaces all uses of NAME by VAL.  */
+
+void
+replace_uses_by (tree name, tree val)
+{
+  imm_use_iterator imm_iter;
+  use_operand_p use;
+  tree stmt;
+  edge e;
+  unsigned i;
+  VEC(tree,heap) *stmts = VEC_alloc (tree, heap, 20);
+
+  FOR_EACH_IMM_USE_SAFE (use, imm_iter, name)
+    {
+      stmt = USE_STMT (use);
+
+      SET_USE (use, val);
+
+      if (TREE_CODE (stmt) == PHI_NODE)
+       {
+         e = PHI_ARG_EDGE (stmt, PHI_ARG_INDEX_FROM_USE (use));
+         if (e->flags & EDGE_ABNORMAL)
+           {
+             /* This can only occur for virtual operands, since
+                for the real ones SSA_NAME_OCCURS_IN_ABNORMAL_PHI (name))
+                would prevent replacement.  */
+             gcc_assert (!is_gimple_reg (name));
+             SSA_NAME_OCCURS_IN_ABNORMAL_PHI (val) = 1;
+           }
+       }
+      else
+       VEC_safe_push (tree, heap, stmts, stmt);
+    }
+  /* We do not update the statements in the loop above.  Consider
+     x = w * w;
+
+     If we performed the update in the first loop, the statement
+     would be rescanned after first occurrence of w is replaced,
+     the new uses would be placed to the beginning of the list,
+     and we would never process them.  */
+  for (i = 0; VEC_iterate (tree, stmts, i, stmt); i++)
+    {
+      fold_stmt_inplace (stmt);
+      update_stmt (stmt);
+    }
+
+  VEC_free (tree, heap, stmts);
+}
 
 /* Merge block B into block A.  */
 
@@ -1306,10 +1378,40 @@ tree_merge_blocks (basic_block a, basic_block b)
 {
   block_stmt_iterator bsi;
   tree_stmt_iterator last;
+  tree phi;
 
   if (dump_file)
     fprintf (dump_file, "Merging blocks %d and %d\n", a->index, b->index);
 
+  /* Remove the phi nodes.  */
+  bsi = bsi_last (a);
+  for (phi = phi_nodes (b); phi; phi = phi_nodes (b))
+    {
+      tree def = PHI_RESULT (phi), use = PHI_ARG_DEF (phi, 0);
+      tree copy;
+      
+      if (!may_propagate_copy (def, use)
+         /* Propagating pointers might cause the set of vops for statements
+            to be changed, and thus require ssa form update.  */
+         || (is_gimple_reg (def)
+             && POINTER_TYPE_P (TREE_TYPE (def))))
+       {
+         gcc_assert (is_gimple_reg (def));
+
+         /* Note that just emitting the copies is fine -- there is no problem
+            with ordering of phi nodes.  This is because A is the single
+            predecessor of B, therefore results of the phi nodes cannot
+            appear as arguments of the phi nodes.  */
+         copy = build2 (MODIFY_EXPR, void_type_node, def, use);
+         bsi_insert_after (&bsi, copy, BSI_NEW_STMT);
+         SET_PHI_RESULT (phi, NULL_TREE);
+         SSA_NAME_DEF_STMT (def) = copy;
+       }
+      else
+       replace_uses_by (def, use);
+      remove_phi_node (phi, NULL);
+    }
+
   /* Ensure that B follows A.  */
   move_block_after (b, a);
 
@@ -1974,7 +2076,6 @@ remove_bb (basic_block bb)
         {
          release_defs (stmt);
 
-         set_bb_for_stmt (stmt, NULL);
          bsi_remove (&i);
        }
 
@@ -4848,6 +4949,7 @@ tree_duplicate_sese_region (edge entry, edge exit,
   edge exit_copy;
   basic_block *doms;
   edge redirected;
+  int total_freq, entry_freq;
 
   if (!can_copy_bbs_p (region, n_region))
     return false;
@@ -4894,12 +4996,24 @@ tree_duplicate_sese_region (edge entry, edge exit,
 
   gcc_assert (!need_ssa_update_p ());
 
-  /* Record blocks outside the region that are duplicated by something
+  /* Record blocks outside the region that are dominated by something
      inside.  */
   doms = xmalloc (sizeof (basic_block) * n_basic_blocks);
   n_doms = get_dominated_by_region (CDI_DOMINATORS, region, n_region, doms);
 
+  total_freq = entry->dest->frequency;
+  entry_freq = EDGE_FREQUENCY (entry);
+  /* Fix up corner cases, to avoid division by zero or creation of negative
+     frequencies.  */
+  if (total_freq == 0)
+    total_freq = 1;
+  else if (entry_freq > total_freq)
+    entry_freq = total_freq;
+
   copy_bbs (region, n_region, region_copy, &exit, 1, &exit_copy, loop);
+  scale_bbs_frequencies_int (region, n_region, total_freq - entry_freq,
+                            total_freq);
+  scale_bbs_frequencies_int (region_copy, n_region, entry_freq, total_freq);
 
   if (copying_header)
     {
@@ -5606,14 +5720,6 @@ execute_warn_function_return (void)
   edge e;
   edge_iterator ei;
 
-  if (warn_missing_noreturn
-      && !TREE_THIS_VOLATILE (cfun->decl)
-      && EDGE_COUNT (EXIT_BLOCK_PTR->preds) == 0
-      && !lang_hooks.function.missing_noreturn_ok_p (cfun->decl))
-    warning (0, "%Jfunction might be possible candidate for "
-            "attribute %<noreturn%>",
-            cfun->decl);
-
   /* If we have a path to EXIT, then we do return.  */
   if (TREE_THIS_VOLATILE (cfun->decl)
       && EDGE_COUNT (EXIT_BLOCK_PTR->preds) > 0)
@@ -5717,3 +5823,34 @@ struct tree_opt_pass pass_warn_function_return =
   0,                                   /* todo_flags_finish */
   0                                    /* letter */
 };
+
+/* Emit noreturn warnings.  */
+
+static void
+execute_warn_function_noreturn (void)
+{
+  if (warn_missing_noreturn
+      && !TREE_THIS_VOLATILE (cfun->decl)
+      && EDGE_COUNT (EXIT_BLOCK_PTR->preds) == 0
+      && !lang_hooks.function.missing_noreturn_ok_p (cfun->decl))
+    warning (0, "%Jfunction might be possible candidate for "
+            "attribute %<noreturn%>",
+            cfun->decl);
+}
+
+struct tree_opt_pass pass_warn_function_noreturn =
+{
+  NULL,                                        /* name */
+  NULL,                                        /* gate */
+  execute_warn_function_noreturn,      /* execute */
+  NULL,                                        /* sub */
+  NULL,                                        /* next */
+  0,                                   /* static_pass_number */
+  0,                                   /* tv_id */
+  PROP_cfg,                            /* properties_required */
+  0,                                   /* properties_provided */
+  0,                                   /* properties_destroyed */
+  0,                                   /* todo_flags_start */
+  0,                                   /* todo_flags_finish */
+  0                                    /* letter */
+};