OSDN Git Service

* config/darwin.c (indirect_data): Fix typo in strncmp logic.
[pf3gnuchains/gcc-fork.git] / gcc / cfgexpand.c
index 71dd039..e339505 100644 (file)
@@ -1,5 +1,5 @@
 /* A pass for lowering trees to RTL.
-   Copyright (C) 2004 Free Software Foundation, Inc.
+   Copyright (C) 2004, 2005 Free Software Foundation, Inc.
 
 This file is part of GCC.
 
@@ -38,6 +38,49 @@ Boston, MA 02111-1307, USA.  */
 #include "diagnostic.h"
 #include "toplev.h"
 
+/* Verify that there is exactly single jump instruction since last and attach
+   REG_BR_PROB note specifying probability.
+   ??? We really ought to pass the probability down to RTL expanders and let it
+   re-distribute it when the conditional expands into multiple conditionals.
+   This is however difficult to do.  */
+static void
+add_reg_br_prob_note (FILE *dump_file, rtx last, int probability)
+{
+  if (profile_status == PROFILE_ABSENT)
+    return;
+  for (last = NEXT_INSN (last); last && NEXT_INSN (last); last = NEXT_INSN (last))
+    if (GET_CODE (last) == JUMP_INSN)
+      {
+       /* It is common to emit condjump-around-jump sequence when we don't know
+          how to reverse the conditional.  Special case this.  */
+       if (!any_condjump_p (last)
+           || GET_CODE (NEXT_INSN (last)) != JUMP_INSN
+           || !simplejump_p (NEXT_INSN (last))
+           || GET_CODE (NEXT_INSN (NEXT_INSN (last))) != BARRIER
+           || GET_CODE (NEXT_INSN (NEXT_INSN (NEXT_INSN (last)))) != CODE_LABEL
+           || NEXT_INSN (NEXT_INSN (NEXT_INSN (NEXT_INSN (last)))))
+         goto failed;
+       if (find_reg_note (last, REG_BR_PROB, 0))
+         abort ();
+       REG_NOTES (last)
+         = gen_rtx_EXPR_LIST (REG_BR_PROB,
+                              GEN_INT (REG_BR_PROB_BASE - probability),
+                              REG_NOTES (last));
+       return;
+      }
+  if (!last || GET_CODE (last) != JUMP_INSN || !any_condjump_p (last))
+      goto failed;
+  if (find_reg_note (last, REG_BR_PROB, 0))
+    abort ();
+  REG_NOTES (last)
+    = gen_rtx_EXPR_LIST (REG_BR_PROB,
+                        GEN_INT (probability), REG_NOTES (last));
+  return;
+failed:
+  if (dump_file)
+    fprintf (dump_file, "Failed to add probability note\n");
+}
+
 
 #ifndef LOCAL_ALIGNMENT
 #define LOCAL_ALIGNMENT(TYPE, ALIGNMENT) ALIGNMENT
@@ -790,6 +833,23 @@ expand_used_vars (void)
 }
 
 
+/* If we need to produce a detailed dump, print the tree representation
+   for STMT to the dump file.  SINCE is the last RTX after which the RTL
+   generated for STMT should have been appended.  */
+
+static void
+maybe_dump_rtl_for_tree_stmt (tree stmt, rtx since)
+{
+  if (dump_file && (dump_flags & TDF_DETAILS))
+    {
+      fprintf (dump_file, "\n;; ");
+      print_generic_expr (dump_file, stmt, TDF_SLIM);
+      fprintf (dump_file, "\n");
+
+      print_rtl (dump_file, since ? NEXT_INSN (since) : since);
+    }
+}
+
 /* A subroutine of expand_gimple_basic_block.  Expand one COND_EXPR.
    Returns a new basic block if we've terminated the current basic
    block and created a new one.  */
@@ -804,7 +864,9 @@ expand_gimple_cond_expr (basic_block bb, tree stmt)
   tree pred = COND_EXPR_COND (stmt);
   tree then_exp = COND_EXPR_THEN (stmt);
   tree else_exp = COND_EXPR_ELSE (stmt);
-  rtx last;
+  rtx last2, last;
+
+  last2 = last = get_last_insn ();
 
   extract_true_false_edges_from_block (bb, &true_edge, &false_edge);
   if (EXPR_LOCUS (stmt))
@@ -822,17 +884,26 @@ expand_gimple_cond_expr (basic_block bb, tree stmt)
   if (TREE_CODE (then_exp) == GOTO_EXPR && IS_EMPTY_STMT (else_exp))
     {
       jumpif (pred, label_rtx (GOTO_DESTINATION (then_exp)));
+      add_reg_br_prob_note (dump_file, last, true_edge->probability);
+      maybe_dump_rtl_for_tree_stmt (stmt, last);
+      if (EXPR_LOCUS (then_exp))
+       emit_line_note (*(EXPR_LOCUS (then_exp)));
       return NULL;
     }
   if (TREE_CODE (else_exp) == GOTO_EXPR && IS_EMPTY_STMT (then_exp))
     {
       jumpifnot (pred, label_rtx (GOTO_DESTINATION (else_exp)));
+      add_reg_br_prob_note (dump_file, last, false_edge->probability);
+      maybe_dump_rtl_for_tree_stmt (stmt, last);
+      if (EXPR_LOCUS (else_exp))
+       emit_line_note (*(EXPR_LOCUS (else_exp)));
       return NULL;
     }
   gcc_assert (TREE_CODE (then_exp) == GOTO_EXPR
              && TREE_CODE (else_exp) == GOTO_EXPR);
 
   jumpif (pred, label_rtx (GOTO_DESTINATION (then_exp)));
+  add_reg_br_prob_note (dump_file, last, true_edge->probability);
   last = get_last_insn ();
   expand_expr (else_exp, const0_rtx, VOIDmode, 0);
 
@@ -854,11 +925,10 @@ expand_gimple_cond_expr (basic_block bb, tree stmt)
     BB_END (new_bb) = PREV_INSN (BB_END (new_bb));
   update_bb_for_insn (new_bb);
 
-  if (dump_file)
-    {
-      dump_bb (bb, dump_file, 0);
-      dump_bb (new_bb, dump_file, 0);
-    }
+  maybe_dump_rtl_for_tree_stmt (stmt, last2);
+  
+  if (EXPR_LOCUS (else_exp))
+    emit_line_note (*(EXPR_LOCUS (else_exp)));
 
   return new_bb;
 }
@@ -876,17 +946,22 @@ expand_gimple_cond_expr (basic_block bb, tree stmt)
 static basic_block
 expand_gimple_tailcall (basic_block bb, tree stmt, bool *can_fallthru)
 {
-  rtx last = get_last_insn ();
+  rtx last2, last;
   edge e;
+  edge_iterator ei;
   int probability;
   gcov_type count;
 
+  last2 = last = get_last_insn ();
+
   expand_expr_stmt (stmt);
 
   for (last = NEXT_INSN (last); last; last = NEXT_INSN (last))
     if (CALL_P (last) && SIBLING_CALL_P (last))
       goto found;
 
+  maybe_dump_rtl_for_tree_stmt (stmt, last2);
+
   *can_fallthru = true;
   return NULL;
 
@@ -902,13 +977,11 @@ expand_gimple_tailcall (basic_block bb, tree stmt, bool *can_fallthru)
      all edges here, or redirecting the existing fallthru edge to
      the exit block.  */
 
-  e = bb->succ;
   probability = 0;
   count = 0;
-  while (e)
-    {
-      edge next = e->succ_next;
 
+  for (ei = ei_start (bb->succs); (e = ei_safe_edge (ei)); )
+    {
       if (!(e->flags & (EDGE_ABNORMAL | EDGE_EH)))
        {
          if (e->dest != EXIT_BLOCK_PTR)
@@ -924,13 +997,13 @@ expand_gimple_tailcall (basic_block bb, tree stmt, bool *can_fallthru)
          probability += e->probability;
          remove_edge (e);
        }
-
-      e = next;
+      else
+       ei_next (&ei);
     }
 
   /* This is somewhat ugly: the call_expr expander often emits instructions
      after the sibcall (to perform the function return).  These confuse the
-     find_sub_basic_blocks code, so we need to get rid of these.  */
+     find_many_sub_basic_blocks code, so we need to get rid of these.  */
   last = NEXT_INSN (last);
   gcc_assert (BARRIER_P (last));
 
@@ -962,6 +1035,8 @@ expand_gimple_tailcall (basic_block bb, tree stmt, bool *can_fallthru)
        BB_END (bb) = PREV_INSN (last);
     }
 
+  maybe_dump_rtl_for_tree_stmt (stmt, last2);
+
   return bb;
 }
 
@@ -974,12 +1049,13 @@ expand_gimple_basic_block (basic_block bb, FILE * dump_file)
   tree stmt = NULL;
   rtx note, last;
   edge e;
+  edge_iterator ei;
 
   if (dump_file)
     {
-      tree_register_cfg_hooks ();
-      dump_bb (bb, dump_file, 0);
-      rtl_register_cfg_hooks ();
+      fprintf (dump_file,
+              "\n;; Generating RTL for tree basic block %d\n",
+              bb->index);
     }
 
   if (!bsi_end_p (bsi))
@@ -998,27 +1074,26 @@ expand_gimple_basic_block (basic_block bb, FILE * dump_file)
        BB_HEAD (bb) = NEXT_INSN (BB_HEAD (bb));
       bsi_next (&bsi);
       note = emit_note_after (NOTE_INSN_BASIC_BLOCK, BB_HEAD (bb));
+
+      maybe_dump_rtl_for_tree_stmt (stmt, last);
     }
   else
     note = BB_HEAD (bb) = emit_note (NOTE_INSN_BASIC_BLOCK);
 
   NOTE_BASIC_BLOCK (note) = bb;
 
-  e = bb->succ;
-  while (e)
+  for (ei = ei_start (bb->succs); (e = ei_safe_edge (ei)); )
     {
-      edge next = e->succ_next;
-
       /* Clear EDGE_EXECUTABLE.  This flag is never used in the backend.  */
       e->flags &= ~EDGE_EXECUTABLE;
 
       /* At the moment not all abnormal edges match the RTL representation.
-         It is safe to remove them here as find_sub_basic_blocks will
+         It is safe to remove them here as find_many_sub_basic_blocks will
          rediscover them.  In the future we should get this fixed properly.  */
       if (e->flags & EDGE_ABNORMAL)
        remove_edge (e);
-
-      e = next;
+      else
+       ei_next (&ei);
     }
 
   for (; !bsi_end_p (bsi); bsi_next (&bsi))
@@ -1053,13 +1128,17 @@ expand_gimple_basic_block (basic_block bb, FILE * dump_file)
                }
            }
          else
-           expand_expr_stmt (stmt);
+           {
+             last = get_last_insn ();
+             expand_expr_stmt (stmt);
+             maybe_dump_rtl_for_tree_stmt (stmt, last);
+           }
        }
     }
 
   do_pending_stack_adjust ();
 
-  /* Find the the block tail.  The last insn is the block is the insn
+  /* Find the block tail.  The last insn in the block is the insn
      before a barrier and/or table jump insn.  */
   last = get_last_insn ();
   if (BARRIER_P (last))
@@ -1068,8 +1147,6 @@ expand_gimple_basic_block (basic_block bb, FILE * dump_file)
     last = PREV_INSN (PREV_INSN (last));
   BB_END (bb) = last;
 
-  if (dump_file)
-    dump_bb (bb, dump_file, 0);
   update_bb_for_insn (bb);
 
   return bb;
@@ -1082,11 +1159,22 @@ static basic_block
 construct_init_block (void)
 {
   basic_block init_block, first_block;
-  edge e;
+  edge e = NULL, e2;
+  edge_iterator ei;
 
-  for (e = ENTRY_BLOCK_PTR->succ; e; e = e->succ_next)
-    if (e->dest == ENTRY_BLOCK_PTR->next_bb)
-      break;
+  FOR_EACH_EDGE (e2, ei, ENTRY_BLOCK_PTR->succs)
+    {
+      /* Clear EDGE_EXECUTABLE.  This flag is never used in the backend.
+
+        For all other blocks this edge flag is cleared while expanding
+        a basic block in expand_gimple_basic_block, but there we never
+        looked at the successors of the entry block.
+        This caused PR17513.  */
+      e2->flags &= ~EDGE_EXECUTABLE;
+
+      if (e2->dest == ENTRY_BLOCK_PTR->next_bb)
+       e = e2;
+    }
 
   init_block = create_basic_block (NEXT_INSN (get_insns ()),
                                   get_last_insn (),
@@ -1117,7 +1205,9 @@ construct_exit_block (void)
   rtx head = get_last_insn ();
   rtx end;
   basic_block exit_block;
-  edge e, e2, next;
+  edge e, e2;
+  unsigned ix;
+  edge_iterator ei;
 
   /* Make sure the locus is set to the end of the function, so that
      epilogue line numbers and warnings are set properly.  */
@@ -1143,16 +1233,21 @@ construct_exit_block (void)
                                   EXIT_BLOCK_PTR->prev_bb);
   exit_block->frequency = EXIT_BLOCK_PTR->frequency;
   exit_block->count = EXIT_BLOCK_PTR->count;
-  for (e = EXIT_BLOCK_PTR->pred; e; e = next)
+
+  ix = 0;
+  while (ix < EDGE_COUNT (EXIT_BLOCK_PTR->preds))
     {
-      next = e->pred_next;
+      e = EDGE_PRED (EXIT_BLOCK_PTR, ix);
       if (!(e->flags & EDGE_ABNORMAL))
-        redirect_edge_succ (e, exit_block);
+       redirect_edge_succ (e, exit_block);
+      else
+       ix++;
     }
+
   e = make_edge (exit_block, EXIT_BLOCK_PTR, EDGE_FALLTHRU);
   e->probability = REG_BR_PROB_BASE;
   e->count = EXIT_BLOCK_PTR->count;
-  for (e2 = EXIT_BLOCK_PTR->pred; e2; e2 = e2->pred_next)
+  FOR_EACH_EDGE (e2, ei, EXIT_BLOCK_PTR->preds)
     if (e2 != e)
       {
         e->count -= e2->count;
@@ -1183,8 +1278,6 @@ tree_expand_cfg (void)
   basic_block bb, init_block;
   sbitmap blocks;
 
-  profile_status = PROFILE_ABSENT;
-
   /* Some backends want to know that we are expanding to RTL.  */
   currently_expanding_to_rtl = 1;
 
@@ -1217,8 +1310,8 @@ tree_expand_cfg (void)
   /* We're done expanding trees to RTL.  */
   currently_expanding_to_rtl = 0;
 
-  /* Convert from NOTE_INSN_EH_REGION style notes, and do other
-     sorts of eh initialization.  */
+  /* Convert tree EH labels to RTL EH labels, and clean out any unreachable
+     EH regions.  */
   convert_from_eh_region_ranges ();
 
   rebuild_jump_labels (get_insns ());
@@ -1244,6 +1337,13 @@ tree_expand_cfg (void)
   generating_concat_p = 0;
 
   finalize_block_changes ();
+
+  if (dump_file)
+    {
+      fprintf (dump_file,
+              "\n\n;;\n;; Full RTL generated for this function:\n;;\n");
+      /* And the pass manager will dump RTL for us.  */
+    }
 }
 
 struct tree_opt_pass pass_expand =