OSDN Git Service

gcc:
[pf3gnuchains/gcc-fork.git] / gcc / cfgrtl.c
index 3129ce6..5d64f3a 100644 (file)
@@ -1,6 +1,6 @@
 /* Control flow graph manipulation code for GNU compiler.
    Copyright (C) 1987, 1988, 1992, 1993, 1994, 1995, 1996, 1997, 1998,
-   1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009
+   1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010
    Free Software Foundation, Inc.
 
 This file is part of GCC.
@@ -42,7 +42,6 @@ along with GCC; see the file COPYING3.  If not see
 #include "coretypes.h"
 #include "tm.h"
 #include "tree.h"
-#include "rtl.h"
 #include "hard-reg-set.h"
 #include "basic-block.h"
 #include "regs.h"
@@ -50,7 +49,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "output.h"
 #include "function.h"
 #include "except.h"
-#include "toplev.h"
+#include "rtl-error.h"
 #include "tm_p.h"
 #include "obstack.h"
 #include "insn-attr.h"
@@ -170,9 +169,7 @@ delete_insn (rtx insn)
       remove_note (insn, note);
     }
 
-  if (JUMP_P (insn)
-      && (GET_CODE (PATTERN (insn)) == ADDR_VEC
-         || GET_CODE (PATTERN (insn)) == ADDR_DIFF_VEC))
+  if (JUMP_TABLE_DATA_P (insn))
     {
       rtx pat = PATTERN (insn);
       int diff_vec_p = GET_CODE (PATTERN (insn)) == ADDR_DIFF_VEC;
@@ -424,7 +421,10 @@ rest_of_pass_free_cfg (void)
   /* The resource.c machinery uses DF but the CFG isn't guaranteed to be
      valid at that point so it would be too late to call df_analyze.  */
   if (optimize > 0 && flag_delayed_branch)
-    df_analyze ();
+    {
+      df_note_add_problem ();
+      df_analyze ();
+    }
 #endif
 
   free_bb_for_insn ();
@@ -435,7 +435,7 @@ struct rtl_opt_pass pass_free_cfg =
 {
  {
   RTL_PASS,
-  NULL,                                 /* name */
+  "*free_cfg",                          /* name */
   NULL,                                 /* gate */
   rest_of_pass_free_cfg,                /* execute */
   NULL,                                 /* sub */
@@ -472,7 +472,7 @@ emit_insn_at_entry (rtx insn)
 }
 
 /* Update BLOCK_FOR_INSN of insns between BEGIN and END
-   (or BARRIER if found) and notify df of the bb change. 
+   (or BARRIER if found) and notify df of the bb change.
    The insn chain range is inclusive
    (i.e. both BEGIN and END will be updated. */
 
@@ -533,7 +533,26 @@ rtl_split_block (basic_block bb, void *insnp)
       insn = first_insn_after_basic_block_note (bb);
 
       if (insn)
-       insn = PREV_INSN (insn);
+       {
+         rtx next = insn;
+
+         insn = PREV_INSN (insn);
+
+         /* If the block contains only debug insns, insn would have
+            been NULL in a non-debug compilation, and then we'd end
+            up emitting a DELETED note.  For -fcompare-debug
+            stability, emit the note too.  */
+         if (insn != BB_END (bb)
+             && DEBUG_INSN_P (next)
+             && DEBUG_INSN_P (BB_END (bb)))
+           {
+             while (next != BB_END (bb) && DEBUG_INSN_P (next))
+               next = NEXT_INSN (next);
+
+             if (next == BB_END (bb))
+               emit_note_after (NOTE_INSN_DELETED, next);
+           }
+       }
       else
        insn = get_last_insn ();
     }
@@ -568,10 +587,16 @@ rtl_merge_blocks (basic_block a, basic_block b)
 {
   rtx b_head = BB_HEAD (b), b_end = BB_END (b), a_end = BB_END (a);
   rtx del_first = NULL_RTX, del_last = NULL_RTX;
+  rtx b_debug_start = b_end, b_debug_end = b_end;
+  bool forwarder_p = (b->flags & BB_FORWARDER_BLOCK) != 0;
   int b_empty = 0;
 
   if (dump_file)
-    fprintf (dump_file, "merging block %d into block %d\n", b->index, a->index);
+    fprintf (dump_file, "Merging block %d into block %d...\n", b->index,
+            a->index);
+
+  while (DEBUG_INSN_P (b_end))
+    b_end = PREV_INSN (b_debug_start = b_end);
 
   /* If there was a CODE_LABEL beginning B, delete it.  */
   if (LABEL_P (b_head))
@@ -638,13 +663,32 @@ rtl_merge_blocks (basic_block a, basic_block b)
   /* Reassociate the insns of B with A.  */
   if (!b_empty)
     {
-      update_bb_for_insn_chain (a_end, b_end, a);
+      update_bb_for_insn_chain (a_end, b_debug_end, a);
 
-      a_end = b_end;
+      a_end = b_debug_end;
+    }
+  else if (b_end != b_debug_end)
+    {
+      /* Move any deleted labels and other notes between the end of A
+        and the debug insns that make up B after the debug insns,
+        bringing the debug insns into A while keeping the notes after
+        the end of A.  */
+      if (NEXT_INSN (a_end) != b_debug_start)
+       reorder_insns_nobb (NEXT_INSN (a_end), PREV_INSN (b_debug_start),
+                           b_debug_end);
+      update_bb_for_insn_chain (b_debug_start, b_debug_end, a);
+      a_end = b_debug_end;
     }
 
   df_bb_delete (b->index);
   BB_END (a) = a_end;
+
+  /* If B was a forwarder block, propagate the locus on the edge.  */
+  if (forwarder_p && !EDGE_SUCC (b, 0)->goto_locus)
+    EDGE_SUCC (b, 0)->goto_locus = EDGE_SUCC (a, 0)->goto_locus;
+
+  if (dump_file)
+    fprintf (dump_file, "Merged blocks %d and %d.\n", a->index, b->index);
 }
 
 
@@ -923,6 +967,48 @@ patch_jump_insn (rtx insn, rtx old_label, basic_block new_bb)
          ++LABEL_NUSES (new_label);
        }
     }
+  else if ((tmp = extract_asm_operands (PATTERN (insn))) != NULL)
+    {
+      int i, n = ASM_OPERANDS_LABEL_LENGTH (tmp);
+      rtx new_label, note;
+
+      if (new_bb == EXIT_BLOCK_PTR)
+       return false;
+      new_label = block_label (new_bb);
+
+      for (i = 0; i < n; ++i)
+       {
+         rtx old_ref = ASM_OPERANDS_LABEL (tmp, i);
+         gcc_assert (GET_CODE (old_ref) == LABEL_REF);
+         if (XEXP (old_ref, 0) == old_label)
+           {
+             ASM_OPERANDS_LABEL (tmp, i)
+               = gen_rtx_LABEL_REF (Pmode, new_label);
+             --LABEL_NUSES (old_label);
+             ++LABEL_NUSES (new_label);
+           }
+       }
+
+      if (JUMP_LABEL (insn) == old_label)
+       {
+         JUMP_LABEL (insn) = new_label;
+         note = find_reg_note (insn, REG_LABEL_TARGET, new_label);
+         if (note)
+           remove_note (insn, note);
+       }
+      else
+       {
+         note = find_reg_note (insn, REG_LABEL_TARGET, old_label);
+         if (note)
+           remove_note (insn, note);
+         if (JUMP_LABEL (insn) != new_label
+             && !find_reg_note (insn, REG_LABEL_TARGET, new_label))
+           add_reg_note (insn, REG_LABEL_TARGET, new_label);
+       }
+      while ((note = find_reg_note (insn, REG_LABEL_OPERAND, old_label))
+            != NULL_RTX)
+       XEXP (note, 0) = new_label;
+    }
   else
     {
       /* ?? We may play the games with moving the named labels from
@@ -976,8 +1062,7 @@ redirect_branch_edge (edge e, basic_block target)
     /* When expanding this BB might actually contain multiple
        jumps (i.e. not yet split by find_many_sub_basic_blocks).
        Redirect all of those that match our label.  */
-    for (insn = BB_HEAD (src); insn != NEXT_INSN (BB_END (src));
-        insn = NEXT_INSN (insn))
+    FOR_BB_INSNS (src, insn)
       if (JUMP_P (insn) && !patch_jump_insn (insn, old_label, target))
        return NULL;
 
@@ -1184,7 +1269,7 @@ force_nonfallthru_and_redirect (edge e, basic_block target)
   if (abnormal_edge_flags)
     make_edge (src, target, abnormal_edge_flags);
 
-  df_mark_solutions_dirty (); 
+  df_mark_solutions_dirty ();
   return new_bb;
 }
 
@@ -1293,12 +1378,7 @@ rtl_split_edge (edge edge_in)
      Avoid existence of fallthru predecessors.  */
   if ((edge_in->flags & EDGE_FALLTHRU) == 0)
     {
-      edge e;
-      edge_iterator ei;
-
-      FOR_EACH_EDGE (e, ei, edge_in->dest->preds)
-       if (e->flags & EDGE_FALLTHRU)
-         break;
+      edge e = find_fallthru_edge (edge_in->dest->preds);
 
       if (e)
        force_nonfallthru (e);
@@ -1335,7 +1415,22 @@ rtl_split_edge (edge edge_in)
       gcc_assert (redirected);
     }
   else
-    redirect_edge_succ (edge_in, bb);
+    {
+      if (edge_in->src != ENTRY_BLOCK_PTR)
+       {
+         /* For asm goto even splitting of fallthru edge might
+            need insn patching, as other labels might point to the
+            old label.  */
+         rtx last = BB_END (edge_in->src);
+         if (last
+             && JUMP_P (last)
+             && edge_in->dest != EXIT_BLOCK_PTR
+             && extract_asm_operands (PATTERN (last)) != NULL_RTX
+             && patch_jump_insn (last, before, bb))
+           df_set_bb_dirty (edge_in->src);
+       }
+      redirect_edge_succ (edge_in, bb);
+    }
 
   return bb;
 }
@@ -1432,24 +1527,11 @@ commit_one_edge_insertion (edge e)
              && targetm.have_named_sections
              && e->src != ENTRY_BLOCK_PTR
              && BB_PARTITION (e->src) == BB_COLD_PARTITION
-             && !(e->flags & EDGE_CROSSING))
-           {
-             rtx bb_note, cur_insn;
-
-             bb_note = NULL_RTX;
-             for (cur_insn = BB_HEAD (bb); cur_insn != NEXT_INSN (BB_END (bb));
-                  cur_insn = NEXT_INSN (cur_insn))
-               if (NOTE_INSN_BASIC_BLOCK_P (cur_insn))
-                 {
-                   bb_note = cur_insn;
-                   break;
-                 }
-
-             if (JUMP_P (BB_END (bb))
-                 && !any_condjump_p (BB_END (bb))
-                 && (single_succ_edge (bb)->flags & EDGE_CROSSING))
-               add_reg_note (BB_END (bb), REG_CROSSING_JUMP, NULL_RTX);
-           }
+             && !(e->flags & EDGE_CROSSING)
+             && JUMP_P (after)
+             && !any_condjump_p (after)
+             && (single_succ_edge (bb)->flags & EDGE_CROSSING))
+           add_reg_note (after, REG_CROSSING_JUMP, NULL_RTX);
        }
     }
 
@@ -1553,7 +1635,7 @@ rtl_dump_bb (basic_block bb, FILE *outf, int indent, int flags ATTRIBUTE_UNUSED)
   s_indent = (char *) alloca ((size_t) indent + 1);
   memset (s_indent, ' ', (size_t) indent);
   s_indent[indent] = '\0';
-  
+
   if (df)
     {
       df_dump_top (bb, outf);
@@ -1620,7 +1702,7 @@ print_rtl_with_bb (FILE *outf, const_rtx rtx_first)
            {
              edge e;
              edge_iterator ei;
-             
+
              fprintf (outf, ";; Start of basic block (");
              FOR_EACH_EDGE (e, ei, bb->preds)
                fprintf (outf, " %d", e->src->index);
@@ -1714,11 +1796,11 @@ get_last_bb_insn (basic_block bb)
     end = tmp;
 
   /* Include any barriers that may follow the basic block.  */
-  tmp = next_nonnote_insn (end);
+  tmp = next_nonnote_insn_bb (end);
   while (tmp && BARRIER_P (tmp))
     {
       end = tmp;
-      tmp = next_nonnote_insn (end);
+      tmp = next_nonnote_insn_bb (end);
     }
 
   return end;
@@ -1840,12 +1922,16 @@ rtl_verify_flow_info_1 (void)
            n_abnormal++;
        }
 
-      if (n_eh && GET_CODE (PATTERN (BB_END (bb))) != RESX
-         && !find_reg_note (BB_END (bb), REG_EH_REGION, NULL_RTX))
+      if (n_eh && !find_reg_note (BB_END (bb), REG_EH_REGION, NULL_RTX))
        {
          error ("missing REG_EH_REGION note in the end of bb %i", bb->index);
          err = 1;
        }
+      if (n_eh > 1)
+       {
+         error ("too many eh edges %i", bb->index);
+         err = 1;
+       }
       if (n_branch
          && (!JUMP_P (BB_END (bb))
              || (n_branch > 1 && (any_uncondjump_p (BB_END (bb))
@@ -1861,7 +1947,8 @@ rtl_verify_flow_info_1 (void)
        }
       if (n_branch != 1 && any_uncondjump_p (BB_END (bb)))
        {
-         error ("wrong amount of branch edges after unconditional jump %i", bb->index);
+         error ("wrong number of branch edges after unconditional jump %i",
+                bb->index);
          err = 1;
        }
       if (n_branch != 1 && any_condjump_p (BB_END (bb))
@@ -1984,7 +2071,6 @@ rtl_verify_flow_info (void)
   FOR_EACH_BB_REVERSE (bb)
     {
       edge e;
-      edge_iterator ei;
       rtx head = BB_HEAD (bb);
       rtx end = BB_END (bb);
 
@@ -2038,9 +2124,7 @@ rtl_verify_flow_info (void)
 
       last_head = PREV_INSN (x);
 
-      FOR_EACH_EDGE (e, ei, bb->succs)
-       if (e->flags & EDGE_FALLTHRU)
-         break;
+      e = find_fallthru_edge (bb->succs);
       if (!e)
        {
          rtx insn;
@@ -2124,9 +2208,7 @@ rtl_verify_flow_info (void)
            case CODE_LABEL:
              /* An addr_vec is placed outside any basic block.  */
              if (NEXT_INSN (x)
-                 && JUMP_P (NEXT_INSN (x))
-                 && (GET_CODE (PATTERN (NEXT_INSN (x))) == ADDR_DIFF_VEC
-                     || GET_CODE (PATTERN (NEXT_INSN (x))) == ADDR_VEC))
+                 && JUMP_TABLE_DATA_P (NEXT_INSN (x)))
                x = NEXT_INSN (x);
 
              /* But in any case, non-deletable labels can appear anywhere.  */
@@ -2166,6 +2248,11 @@ purge_dead_edges (basic_block bb)
   bool found;
   edge_iterator ei;
 
+  if (DEBUG_INSN_P (insn) && insn != BB_HEAD (bb))
+    do
+      insn = PREV_INSN (insn);
+    while ((DEBUG_INSN_P (insn) || NOTE_P (insn)) && insn != BB_HEAD (bb));
+
   /* If this instruction cannot trap, remove REG_EH_REGION notes.  */
   if (NONJUMP_INSN_P (insn)
       && (note = find_reg_note (insn, REG_EH_REGION, NULL)))
@@ -2181,39 +2268,33 @@ purge_dead_edges (basic_block bb)
   /* Cleanup abnormal edges caused by exceptions or non-local gotos.  */
   for (ei = ei_start (bb->succs); (e = ei_safe_edge (ei)); )
     {
+      bool remove = false;
+
       /* There are three types of edges we need to handle correctly here: EH
         edges, abnormal call EH edges, and abnormal call non-EH edges.  The
         latter can appear when nonlocal gotos are used.  */
-      if (e->flags & EDGE_EH)
+      if (e->flags & EDGE_ABNORMAL_CALL)
        {
-         if (can_throw_internal (BB_END (bb))
-             /* If this is a call edge, verify that this is a call insn.  */
-             && (! (e->flags & EDGE_ABNORMAL_CALL)
-                 || CALL_P (BB_END (bb))))
-           {
-             ei_next (&ei);
-             continue;
-           }
+         if (!CALL_P (insn))
+           remove = true;
+         else if (can_nonlocal_goto (insn))
+           ;
+         else if ((e->flags & EDGE_EH) && can_throw_internal (insn))
+           ;
+         else
+           remove = true;
        }
-      else if (e->flags & EDGE_ABNORMAL_CALL)
+      else if (e->flags & EDGE_EH)
+       remove = !can_throw_internal (insn);
+
+      if (remove)
        {
-         if (CALL_P (BB_END (bb))
-             && (! (note = find_reg_note (insn, REG_EH_REGION, NULL))
-                 || INTVAL (XEXP (note, 0)) >= 0))
-           {
-             ei_next (&ei);
-             continue;
-           }
+         remove_edge (e);
+         df_set_bb_dirty (bb);
+         purged = true;
        }
       else
-       {
-         ei_next (&ei);
-         continue;
-       }
-
-      remove_edge (e);
-      df_set_bb_dirty (bb);
-      purged = true;
+       ei_next (&ei);
     }
 
   if (JUMP_P (insn))
@@ -2619,12 +2700,13 @@ cfg_layout_can_merge_blocks_p (basic_block a, basic_block b)
 static void
 cfg_layout_merge_blocks (basic_block a, basic_block b)
 {
-#ifdef ENABLE_CHECKING
-  gcc_assert (cfg_layout_can_merge_blocks_p (a, b));
-#endif
+  bool forwarder_p = (b->flags & BB_FORWARDER_BLOCK) != 0;
+
+  gcc_checking_assert (cfg_layout_can_merge_blocks_p (a, b));
 
   if (dump_file)
-    fprintf (dump_file, "merging block %d into block %d\n", b->index, a->index);
+    fprintf (dump_file, "Merging block %d into block %d...\n", b->index,
+                        a->index);
 
   /* If there was a CODE_LABEL beginning B, delete it.  */
   if (LABEL_P (BB_HEAD (b)))
@@ -2732,9 +2814,12 @@ cfg_layout_merge_blocks (basic_block a, basic_block b)
       b->il.rtl->footer = NULL;
     }
 
+  /* If B was a forwarder block, propagate the locus on the edge.  */
+  if (forwarder_p && !EDGE_SUCC (b, 0)->goto_locus)
+    EDGE_SUCC (b, 0)->goto_locus = EDGE_SUCC (a, 0)->goto_locus;
+
   if (dump_file)
-    fprintf (dump_file, "Merged blocks %d and %d.\n",
-            a->index, b->index);
+    fprintf (dump_file, "Merged blocks %d and %d.\n", a->index, b->index);
 }
 
 /* Split edge E.  */
@@ -2775,7 +2860,8 @@ rtl_block_ends_with_call_p (basic_block bb)
   while (!CALL_P (insn)
         && insn != BB_HEAD (bb)
         && (keep_with_call_p (insn)
-            || NOTE_P (insn)))
+            || NOTE_P (insn)
+            || DEBUG_INSN_P (insn)))
     insn = PREV_INSN (insn);
   return (CALL_P (insn));
 }
@@ -2963,7 +3049,7 @@ rtl_lv_add_condition_to_bb (basic_block first_head ,
   op0 = force_operand (op0, NULL_RTX);
   op1 = force_operand (op1, NULL_RTX);
   do_compare_rtx_and_jump (op0, op1, comp, 0,
-                          mode, NULL_RTX, NULL_RTX, label);
+                          mode, NULL_RTX, NULL_RTX, label, -1);
   jump = get_last_insn ();
   JUMP_LABEL (jump) = label;
   LABEL_NUSES (label)++;
@@ -3000,95 +3086,7 @@ void
 init_rtl_bb_info (basic_block bb)
 {
   gcc_assert (!bb->il.rtl);
-  bb->il.rtl = GGC_CNEW (struct rtl_bb_info);
-}
-
-
-/* Add EXPR to the end of basic block BB.  */
-
-rtx
-insert_insn_end_bb_new (rtx pat, basic_block bb)
-{
-  rtx insn = BB_END (bb);
-  rtx new_insn;
-  rtx pat_end = pat;
-
-  while (NEXT_INSN (pat_end) != NULL_RTX)
-    pat_end = NEXT_INSN (pat_end);
-
-  /* If the last insn is a jump, insert EXPR in front [taking care to
-     handle cc0, etc. properly].  Similarly we need to care trapping
-     instructions in presence of non-call exceptions.  */
-
-  if (JUMP_P (insn)
-      || (NONJUMP_INSN_P (insn)
-          && (!single_succ_p (bb)
-              || single_succ_edge (bb)->flags & EDGE_ABNORMAL)))
-    {
-#ifdef HAVE_cc0
-      rtx note;
-#endif
-      /* If this is a jump table, then we can't insert stuff here.  Since
-         we know the previous real insn must be the tablejump, we insert
-         the new instruction just before the tablejump.  */
-      if (GET_CODE (PATTERN (insn)) == ADDR_VEC
-          || GET_CODE (PATTERN (insn)) == ADDR_DIFF_VEC)
-        insn = prev_real_insn (insn);
-
-#ifdef HAVE_cc0
-      /* FIXME: 'twould be nice to call prev_cc0_setter here but it aborts
-         if cc0 isn't set.  */
-      note = find_reg_note (insn, REG_CC_SETTER, NULL_RTX);
-      if (note)
-        insn = XEXP (note, 0);
-      else
-        {
-          rtx maybe_cc0_setter = prev_nonnote_insn (insn);
-          if (maybe_cc0_setter
-              && INSN_P (maybe_cc0_setter)
-              && sets_cc0_p (PATTERN (maybe_cc0_setter)))
-            insn = maybe_cc0_setter;
-        }
-#endif
-      /* FIXME: What if something in cc0/jump uses value set in new
-         insn?  */
-      new_insn = emit_insn_before_noloc (pat, insn, bb);
-    }
-
-  /* Likewise if the last insn is a call, as will happen in the presence
-     of exception handling.  */
-  else if (CALL_P (insn)
-           && (!single_succ_p (bb)
-               || single_succ_edge (bb)->flags & EDGE_ABNORMAL))
-    {
-      /* Keeping in mind SMALL_REGISTER_CLASSES and parameters in registers,
-         we search backward and place the instructions before the first
-         parameter is loaded.  Do this for everyone for consistency and a
-         presumption that we'll get better code elsewhere as well.  */
-
-      /* Since different machines initialize their parameter registers
-         in different orders, assume nothing.  Collect the set of all
-         parameter registers.  */
-      insn = find_first_parameter_load (insn, BB_HEAD (bb));
-
-      /* If we found all the parameter loads, then we want to insert
-         before the first parameter load.
-
-         If we did not find all the parameter loads, then we might have
-         stopped on the head of the block, which could be a CODE_LABEL.
-         If we inserted before the CODE_LABEL, then we would be putting
-         the insn in the wrong basic block.  In that case, put the insn
-         after the CODE_LABEL.  Also, respect NOTE_INSN_BASIC_BLOCK.  */
-      while (LABEL_P (insn)
-             || NOTE_INSN_BASIC_BLOCK_P (insn))
-        insn = NEXT_INSN (insn);
-
-      new_insn = emit_insn_before_noloc (pat, insn, bb);
-    }
-  else
-    new_insn = emit_insn_after_noloc (pat, insn, bb);
-
-  return new_insn;
+  bb->il.rtl = ggc_alloc_cleared_rtl_bb_info ();
 }
 
 /* Returns true if it is possible to remove edge E by redirecting