OSDN Git Service

* typeck.c (comptypes): First determine if the types are compatible
[pf3gnuchains/gcc-fork.git] / gcc / cfgrtl.c
index a35fdbd..9239906 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 Free Software Foundation, Inc.
+   1999, 2000, 2001, 2002, 2003, 2004, 2005 Free Software Foundation, Inc.
 
 This file is part of GCC.
 
@@ -69,7 +69,6 @@ static int can_delete_label_p (rtx);
 static void commit_one_edge_insertion (edge, int);
 static rtx last_loop_beg_note (rtx);
 static bool back_edge_of_syntactic_loop_p (basic_block, basic_block);
-basic_block force_nonfallthru_and_redirect (edge, basic_block);
 static basic_block rtl_split_edge (edge);
 static bool rtl_move_block_after (basic_block, basic_block);
 static int rtl_verify_flow_info (void);
@@ -369,14 +368,9 @@ rtl_delete_block (basic_block b)
   rtx insn, end, tmp;
 
   /* If the head of this block is a CODE_LABEL, then it might be the
-     label for an exception handler which can't be reached.
-
-     We need to remove the label from the exception_handler_label list
-     and remove the associated NOTE_INSN_EH_REGION_BEG and
-     NOTE_INSN_EH_REGION_END notes.  */
-
+     label for an exception handler which can't be reached.  We need
+     to remove the label from the exception_handler_label list.  */
   insn = BB_HEAD (b);
-
   if (LABEL_P (insn))
     maybe_remove_eh_handler (insn);
 
@@ -385,10 +379,13 @@ rtl_delete_block (basic_block b)
   if (tablejump_p (end, NULL, &tmp))
     end = tmp;
 
-  /* Include any barrier that may follow the basic block.  */
+  /* Include any barriers that may follow the basic block.  */
   tmp = next_nonnote_insn (end);
-  if (tmp && BARRIER_P (tmp))
-    end = tmp;
+  while (tmp && BARRIER_P (tmp))
+    {
+      end = tmp;
+      tmp = next_nonnote_insn (end);
+    }
 
   /* Selectively delete the entire chain.  */
   BB_HEAD (b) = NULL;
@@ -459,6 +456,7 @@ rtl_split_block (basic_block bb, void *insnp)
   basic_block new_bb;
   rtx insn = insnp;
   edge e;
+  edge_iterator ei;
 
   if (!insn)
     {
@@ -482,15 +480,15 @@ rtl_split_block (basic_block bb, void *insnp)
   BB_END (bb) = insn;
 
   /* Redirect the outgoing edges.  */
-  new_bb->succ = bb->succ;
-  bb->succ = NULL;
-  for (e = new_bb->succ; e; e = e->succ_next)
+  new_bb->succs = bb->succs;
+  bb->succs = NULL;
+  FOR_EACH_EDGE (e, ei, new_bb->succs)
     e->src = new_bb;
 
   if (bb->global_live_at_start)
     {
-      new_bb->global_live_at_start = OBSTACK_ALLOC_REG_SET (&flow_obstack);
-      new_bb->global_live_at_end = OBSTACK_ALLOC_REG_SET (&flow_obstack);
+      new_bb->global_live_at_start = ALLOC_REG_SET (&reg_obstack);
+      new_bb->global_live_at_end = ALLOC_REG_SET (&reg_obstack);
       COPY_REG_SET (new_bb->global_live_at_end, bb->global_live_at_end);
 
       /* We now have to calculate which registers are live at the end
@@ -625,10 +623,12 @@ rtl_can_merge_blocks (basic_block a,basic_block b)
     return false;
 
   /* There must be exactly one edge in between the blocks.  */
-  return (a->succ && !a->succ->succ_next && a->succ->dest == b
-         && !b->pred->pred_next && a != b
+  return (single_succ_p (a)
+         && single_succ (a) == b
+         && single_pred_p (b)
+         && a != b
          /* Must be simple edge.  */
-         && !(a->succ->flags & EDGE_COMPLEX)
+         && !(single_succ_edge (a)->flags & EDGE_COMPLEX)
          && a->next_bb == b
          && a != ENTRY_BLOCK_PTR && b != EXIT_BLOCK_PTR
          /* If the jump insn has side effects,
@@ -665,11 +665,9 @@ try_redirect_by_replacing_jump (edge e, basic_block target, bool in_cfglayout)
 {
   basic_block src = e->src;
   rtx insn = BB_END (src), kill_from;
-  edge tmp;
   rtx set;
   int fallthru = 0;
 
-
   /* If we are partitioning hot/cold basic blocks, we don't want to
      mess up unconditional or indirect jumps that cross between hot
      and cold sections.
@@ -685,12 +683,17 @@ try_redirect_by_replacing_jump (edge e, basic_block target, bool in_cfglayout)
          || BB_PARTITION (src) != BB_PARTITION (target)))
     return NULL;
 
-  /* Verify that all targets will be TARGET.  */
-  for (tmp = src->succ; tmp; tmp = tmp->succ_next)
-    if (tmp->dest != target && tmp != e)
-      break;
+  /* We can replace or remove a complex jump only when we have exactly
+     two edges.  Also, if we have exactly one outgoing edge, we can
+     redirect that.  */
+  if (EDGE_COUNT (src->succs) >= 3
+      /* Verify that all targets will be TARGET.  Specifically, the
+        edge that is not E must also go to TARGET.  */
+      || (EDGE_COUNT (src->succs) == 2
+         && EDGE_SUCC (src, EDGE_SUCC (src, 0) == e)->dest != target))
+    return NULL;
 
-  if (tmp || !onlyjump_p (insn))
+  if (!onlyjump_p (insn))
     return NULL;
   if ((!optimize || reload_completed) && tablejump_p (insn, NULL, NULL))
     return NULL;
@@ -768,7 +771,7 @@ try_redirect_by_replacing_jump (edge e, basic_block target, bool in_cfglayout)
       rtx target_label = block_label (target);
       rtx barrier, label, table;
 
-      emit_jump_insn_after (gen_jump (target_label), insn);
+      emit_jump_insn_after_noloc (gen_jump (target_label), insn);
       JUMP_LABEL (BB_END (src)) = target_label;
       LABEL_NUSES (target_label)++;
       if (dump_file)
@@ -814,9 +817,11 @@ try_redirect_by_replacing_jump (edge e, basic_block target, bool in_cfglayout)
     }
 
   /* Keep only one edge out and set proper flags.  */
-  while (src->succ->succ_next)
-    remove_edge (src->succ);
-  e = src->succ;
+  if (!single_succ_p (src))
+    remove_edge (e);
+  gcc_assert (single_succ_p (src));
+
+  e = single_succ_edge (src);
   if (fallthru)
     e->flags = EDGE_FALLTHRU;
   else
@@ -982,7 +987,7 @@ rtl_redirect_edge_and_branch (edge e, basic_block target)
 /* Like force_nonfallthru below, but additionally performs redirection
    Used by redirect_edge_and_branch_force.  */
 
-basic_block
+static basic_block
 force_nonfallthru_and_redirect (edge e, basic_block target)
 {
   basic_block jump_block, new_bb = NULL, src = e->src;
@@ -1040,28 +1045,37 @@ force_nonfallthru_and_redirect (edge e, basic_block target)
       if (e->src == ENTRY_BLOCK_PTR)
        {
          /* We can't redirect the entry block.  Create an empty block
-             at the start of the function which we use to add the new
-             jump.  */
-         edge *pe1;
-         basic_block bb
-           = create_basic_block (BB_HEAD (e->dest), NULL, ENTRY_BLOCK_PTR);
-
+            at the start of the function which we use to add the new
+            jump.  */
+         edge tmp;
+         edge_iterator ei;
+         bool found = false;
+         
+         basic_block bb = create_basic_block (BB_HEAD (e->dest), NULL, ENTRY_BLOCK_PTR);
+         
          /* Change the existing edge's source to be the new block, and add
             a new edge from the entry block to the new block.  */
          e->src = bb;
-         for (pe1 = &ENTRY_BLOCK_PTR->succ; *pe1; pe1 = &(*pe1)->succ_next)
-           if (*pe1 == e)
-             {
-               *pe1 = e->succ_next;
-               break;
-             }
-         e->succ_next = 0;
-         bb->succ = e;
+         for (ei = ei_start (ENTRY_BLOCK_PTR->succs); (tmp = ei_safe_edge (ei)); )
+           {
+             if (tmp == e)
+               {
+                 VEC_unordered_remove (edge, ENTRY_BLOCK_PTR->succs, ei.index);
+                 found = true;
+                 break;
+               }
+             else
+               ei_next (&ei);
+           }
+         
+         gcc_assert (found);
+         
+         VEC_safe_push (edge, bb->succs, e);
          make_single_succ_edge (ENTRY_BLOCK_PTR, bb, EDGE_FALLTHRU);
        }
     }
 
-  if (e->src->succ->succ_next || abnormal_edge_flags)
+  if (EDGE_COUNT (e->src->succs) >= 2 || abnormal_edge_flags)
     {
       /* Create the new structures.  */
 
@@ -1082,10 +1096,8 @@ force_nonfallthru_and_redirect (edge e, basic_block target)
 
       if (target->global_live_at_start)
        {
-         jump_block->global_live_at_start
-           = OBSTACK_ALLOC_REG_SET (&flow_obstack);
-         jump_block->global_live_at_end
-           = OBSTACK_ALLOC_REG_SET (&flow_obstack);
+         jump_block->global_live_at_start = ALLOC_REG_SET (&reg_obstack);
+         jump_block->global_live_at_end = ALLOC_REG_SET (&reg_obstack);
          COPY_REG_SET (jump_block->global_live_at_start,
                        target->global_live_at_start);
          COPY_REG_SET (jump_block->global_live_at_end,
@@ -1113,7 +1125,7 @@ force_nonfallthru_and_redirect (edge e, basic_block target)
            }
          if (JUMP_P (BB_END (jump_block))
              && !any_condjump_p (BB_END (jump_block))
-             && (jump_block->succ->flags & EDGE_CROSSING))
+             && (single_succ_edge (jump_block)->flags & EDGE_CROSSING))
            REG_NOTES (BB_END (jump_block)) = gen_rtx_EXPR_LIST 
              (REG_CROSSING_JUMP, NULL_RTX, 
               REG_NOTES (BB_END (jump_block)));
@@ -1137,7 +1149,7 @@ force_nonfallthru_and_redirect (edge e, basic_block target)
   if (target == EXIT_BLOCK_PTR)
     {
 #ifdef HAVE_return
-       emit_jump_insn_after (gen_return (), BB_END (jump_block));
+       emit_jump_insn_after_noloc (gen_return (), BB_END (jump_block));
 #else
        gcc_unreachable ();
 #endif
@@ -1145,7 +1157,7 @@ force_nonfallthru_and_redirect (edge e, basic_block target)
   else
     {
       rtx label = block_label (target);
-      emit_jump_insn_after (gen_jump (label), BB_END (jump_block));
+      emit_jump_insn_after_noloc (gen_jump (label), BB_END (jump_block));
       JUMP_LABEL (BB_END (jump_block)) = label;
       LABEL_NUSES (label)++;
     }
@@ -1215,7 +1227,7 @@ rtl_tidy_fallthru_edge (edge e)
   if (JUMP_P (q)
       && onlyjump_p (q)
       && (any_uncondjump_p (q)
-         || (b->succ == e && e->succ_next == NULL)))
+         || single_succ_p (b)))
     {
 #ifdef HAVE_cc0
       /* If this was a conditional jump, we need to also delete
@@ -1303,8 +1315,9 @@ rtl_split_edge (edge edge_in)
   if ((edge_in->flags & EDGE_FALLTHRU) == 0)
     {
       edge e;
+      edge_iterator ei;
 
-      for (e = edge_in->dest->pred; e; e = e->pred_next)
+      FOR_EACH_EDGE (e, ei, edge_in->dest->preds)
        if (e->flags & EDGE_FALLTHRU)
          break;
 
@@ -1364,8 +1377,8 @@ rtl_split_edge (edge edge_in)
   /* ??? This info is likely going to be out of date very soon.  */
   if (edge_in->dest->global_live_at_start)
     {
-      bb->global_live_at_start = OBSTACK_ALLOC_REG_SET (&flow_obstack);
-      bb->global_live_at_end = OBSTACK_ALLOC_REG_SET (&flow_obstack);
+      bb->global_live_at_start = ALLOC_REG_SET (&reg_obstack);
+      bb->global_live_at_end = ALLOC_REG_SET (&reg_obstack);
       COPY_REG_SET (bb->global_live_at_start,
                    edge_in->dest->global_live_at_start);
       COPY_REG_SET (bb->global_live_at_end,
@@ -1440,11 +1453,12 @@ bool
 safe_insert_insn_on_edge (rtx insn, edge e)
 {
   rtx x;
-  regset_head killed_head;
-  regset killed = INITIALIZE_REG_SET (killed_head);
+  regset killed;
   rtx save_regs = NULL_RTX;
-  int regno, noccmode;
+  unsigned regno;
+  int noccmode;
   enum machine_mode mode;
+  reg_set_iterator rsi;
 
 #ifdef AVOID_CCMODE_COPIES
   noccmode = true;
@@ -1452,13 +1466,24 @@ safe_insert_insn_on_edge (rtx insn, edge e)
   noccmode = false;
 #endif
 
+  killed = ALLOC_REG_SET (&reg_obstack);
+
   for (x = insn; x; x = NEXT_INSN (x))
     if (INSN_P (x))
       note_stores (PATTERN (x), mark_killed_regs, killed);
-  bitmap_operation (killed, killed, e->dest->global_live_at_start,
-                   BITMAP_AND);
 
-  EXECUTE_IF_SET_IN_REG_SET (killed, 0, regno,
+  /* Mark all hard registers as killed.  Register allocator/reload cannot
+     cope with the situation when life range of hard register spans operation
+     for that the appropriate register is needed, i.e. it would be unsafe to
+     extend the life ranges of hard registers.  */
+  for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
+    if (!fixed_regs[regno]
+       && !REGNO_PTR_FRAME_P (regno))
+      SET_REGNO_REG_SET (killed, regno);
+
+  bitmap_and_into (killed, e->dest->global_live_at_start);
+
+  EXECUTE_IF_SET_IN_REG_SET (killed, 0, regno, rsi)
     {
       mode = regno < FIRST_PSEUDO_REGISTER
              ? reg_raw_mode[regno]
@@ -1474,7 +1499,7 @@ safe_insert_insn_on_edge (rtx insn, edge e)
                                                    gen_reg_rtx (mode),
                                                    gen_raw_REG (mode, regno)),
                                   save_regs);
-    });
+    }
 
   if (save_regs)
     {
@@ -1501,6 +1526,7 @@ safe_insert_insn_on_edge (rtx insn, edge e)
   insert_insn_on_edge (insn, e);
   
   FREE_REG_SET (killed);
+
   return true;
 }
 
@@ -1518,7 +1544,8 @@ commit_one_edge_insertion (edge e, int watch_calls)
 
   /* Special case -- avoid inserting code between call and storing
      its return value.  */
-  if (watch_calls && (e->flags & EDGE_FALLTHRU) && !e->dest->pred->pred_next
+  if (watch_calls && (e->flags & EDGE_FALLTHRU)
+      && single_pred_p (e->dest)
       && e->src != ENTRY_BLOCK_PTR
       && CALL_P (BB_END (e->src)))
     {
@@ -1538,7 +1565,7 @@ commit_one_edge_insertion (edge e, int watch_calls)
     {
       /* Figure out where to put these things.  If the destination has
          one predecessor, insert there.  Except for the exit block.  */
-      if (e->dest->pred->pred_next == NULL && e->dest != EXIT_BLOCK_PTR)
+      if (single_pred_p (e->dest) && e->dest != EXIT_BLOCK_PTR)
        {
          bb = e->dest;
 
@@ -1564,7 +1591,7 @@ commit_one_edge_insertion (edge e, int watch_calls)
       /* If the source has one successor and the edge is not abnormal,
          insert there.  Except for the entry block.  */
       else if ((e->flags & EDGE_ABNORMAL) == 0
-              && e->src->succ->succ_next == NULL
+              && single_succ_p (e->src)
               && e->src != ENTRY_BLOCK_PTR)
        {
          bb = e->src;
@@ -1619,7 +1646,7 @@ commit_one_edge_insertion (edge e, int watch_calls)
              NOTE_BASIC_BLOCK (new_note) = bb;
              if (JUMP_P (BB_END (bb))
                  && !any_condjump_p (BB_END (bb))
-                 && (bb->succ->flags & EDGE_CROSSING))
+                 && (single_succ_edge (bb)->flags & EDGE_CROSSING))
                REG_NOTES (BB_END (bb)) = gen_rtx_EXPR_LIST 
                  (REG_CROSSING_JUMP, NULL_RTX, REG_NOTES (BB_END (bb)));
              if (after == bb_note)
@@ -1632,11 +1659,11 @@ commit_one_edge_insertion (edge e, int watch_calls)
 
   if (before)
     {
-      emit_insn_before (insns, before);
+      emit_insn_before_noloc (insns, before);
       last = prev_nonnote_insn (before);
     }
   else
-    last = emit_insn_after (insns, after);
+    last = emit_insn_after_noloc (insns, after);
 
   if (returnjump_p (last))
     {
@@ -1645,9 +1672,9 @@ commit_one_edge_insertion (edge e, int watch_calls)
          for the (single) epilogue, which already has a fallthru edge
          to EXIT.  */
 
-      e = bb->succ;
+      e = single_succ_edge (bb);
       gcc_assert (e->dest == EXIT_BLOCK_PTR
-                 && !e->succ_next && (e->flags & EDGE_FALLTHRU));
+                 && single_succ_p (bb) && (e->flags & EDGE_FALLTHRU));
 
       e->flags &= ~EDGE_FALLTHRU;
       emit_barrier_after (last);
@@ -1658,7 +1685,7 @@ commit_one_edge_insertion (edge e, int watch_calls)
   else
     gcc_assert (!JUMP_P (last));
 
-  /* Mark the basic block for find_sub_basic_blocks.  */
+  /* Mark the basic block for find_many_sub_basic_blocks.  */
   bb->aux = &bb->aux;
 }
 
@@ -1677,17 +1704,15 @@ commit_edge_insertions (void)
 
   FOR_BB_BETWEEN (bb, ENTRY_BLOCK_PTR, EXIT_BLOCK_PTR, next_bb)
     {
-      edge e, next;
+      edge e;
+      edge_iterator ei;
 
-      for (e = bb->succ; e; e = next)
-       {
-         next = e->succ_next;
-         if (e->insns.r)
-           {
-             changed = true;
-             commit_one_edge_insertion (e, false);
-           }
-       }
+      FOR_EACH_EDGE (e, ei, bb->succs)
+       if (e->insns.r)
+         {
+           changed = true;
+           commit_one_edge_insertion (e, false);
+         }
     }
 
   if (!changed)
@@ -1724,17 +1749,15 @@ commit_edge_insertions_watch_calls (void)
 
   FOR_BB_BETWEEN (bb, ENTRY_BLOCK_PTR, EXIT_BLOCK_PTR, next_bb)
     {
-      edge e, next;
+      edge e;
+      edge_iterator ei;
 
-      for (e = bb->succ; e; e = next)
-       {
-         next = e->succ_next;
-         if (e->insns.r)
-           {
-             changed = true;
-             commit_one_edge_insertion (e, true);
-           }
-       }
+      FOR_EACH_EDGE (e, ei, bb->succs)
+       if (e->insns.r)
+         {
+           changed = true;
+           commit_one_edge_insertion (e, true);
+         }
     }
 
   if (!changed)
@@ -1904,13 +1927,10 @@ rtl_verify_flow_info_1 (void)
   basic_block *bb_info;
   rtx x;
   int err = 0;
-  basic_block bb, last_bb_seen;
+  basic_block bb;
 
   bb_info = xcalloc (max_uid, sizeof (basic_block));
 
-  /* Check bb chain & numbers.  */
-  last_bb_seen = ENTRY_BLOCK_PTR;
-
   FOR_EACH_BB_REVERSE (bb)
     {
       rtx head = BB_HEAD (bb);
@@ -1963,20 +1983,22 @@ rtl_verify_flow_info_1 (void)
       int n_fallthru = 0, n_eh = 0, n_call = 0, n_abnormal = 0, n_branch = 0;
       edge e, fallthru = NULL;
       rtx note;
+      edge_iterator ei;
 
-      if (INSN_P (BB_END (bb))
+      if (JUMP_P (BB_END (bb))
          && (note = find_reg_note (BB_END (bb), REG_BR_PROB, NULL_RTX))
-         && bb->succ && bb->succ->succ_next
+         && EDGE_COUNT (bb->succs) >= 2
          && any_condjump_p (BB_END (bb)))
        {
-         if (INTVAL (XEXP (note, 0)) != BRANCH_EDGE (bb)->probability)
+         if (INTVAL (XEXP (note, 0)) != BRANCH_EDGE (bb)->probability
+             && profile_status != PROFILE_ABSENT)
            {
              error ("verify_flow_info: REG_BR_PROB does not match cfg %wi %i",
                     INTVAL (XEXP (note, 0)), BRANCH_EDGE (bb)->probability);
              err = 1;
            }
        }
-      for (e = bb->succ; e; e = e->succ_next)
+      FOR_EACH_EDGE (e, ei, bb->succs)
        {
          if (e->flags & EDGE_FALLTHRU)
            {
@@ -2054,7 +2076,9 @@ rtl_verify_flow_info_1 (void)
        }
 
       for (x = BB_HEAD (bb); x != NEXT_INSN (BB_END (bb)); x = NEXT_INSN (x))
-       if (BLOCK_FOR_INSN (x) != bb)
+       /* We may have a barrier inside a basic block before dead code
+          elimination.  There is no BLOCK_FOR_INSN field in a barrier.  */
+       if (!BARRIER_P (x) && BLOCK_FOR_INSN (x) != bb)
          {
            debug_rtx (x);
            if (! BLOCK_FOR_INSN (x))
@@ -2093,7 +2117,7 @@ rtl_verify_flow_info_1 (void)
        }
 
       if (BB_END (bb) == x)
-       /* Do checks for empty blocks her. e */
+       /* Do checks for empty blocks here.  */
        ;
       else
        for (x = NEXT_INSN (x); x; x = NEXT_INSN (x))
@@ -2143,7 +2167,9 @@ rtl_verify_flow_info (void)
   FOR_EACH_BB_REVERSE (bb)
     {
       edge e;
-      for (e = bb->succ; e; e = e->succ_next)
+      edge_iterator ei;
+
+      FOR_EACH_EDGE (e, ei, bb->succs)
        if (e->flags & EDGE_FALLTHRU)
          break;
       if (!e)
@@ -2177,13 +2203,7 @@ rtl_verify_flow_info (void)
          else
            for (insn = NEXT_INSN (BB_END (e->src)); insn != BB_HEAD (e->dest);
                 insn = NEXT_INSN (insn))
-             if (BARRIER_P (insn)
-#ifndef CASE_DROPS_THROUGH
-                 || INSN_P (insn)
-#else
-                 || (INSN_P (insn) && ! JUMP_TABLE_DATA_P (insn))
-#endif
-                 )
+             if (BARRIER_P (insn) || INSN_P (insn))
                {
                  error ("verify_flow_info: Incorrect fallthru %i->%i",
                         e->src->index, e->dest->index);
@@ -2233,8 +2253,7 @@ rtl_verify_flow_info (void)
            }
        }
 
-      if (INSN_P (x)
-         && JUMP_P (x)
+      if (JUMP_P (x)
          && returnjump_p (x) && ! condjump_p (x)
          && ! (NEXT_INSN (x) && BARRIER_P (NEXT_INSN (x))))
            fatal_insn ("return not followed by barrier", x);
@@ -2257,9 +2276,11 @@ rtl_verify_flow_info (void)
 bool
 purge_dead_edges (basic_block bb)
 {
-  edge e, next;
+  edge e;
   rtx insn = BB_END (bb), note;
   bool purged = false;
+  bool found;
+  edge_iterator ei;
 
   /* If this instruction cannot trap, remove REG_EH_REGION notes.  */
   if (NONJUMP_INSN_P (insn)
@@ -2274,23 +2295,31 @@ purge_dead_edges (basic_block bb)
     }
 
   /* Cleanup abnormal edges caused by exceptions or non-local gotos.  */
-  for (e = bb->succ; e; e = next)
+  for (ei = ei_start (bb->succs); (e = ei_safe_edge (ei)); )
     {
-      next = e->succ_next;
       if (e->flags & EDGE_EH)
        {
          if (can_throw_internal (BB_END (bb)))
-           continue;
+           {
+             ei_next (&ei);
+             continue;
+           }
        }
       else if (e->flags & EDGE_ABNORMAL_CALL)
        {
          if (CALL_P (BB_END (bb))
              && (! (note = find_reg_note (insn, REG_EH_REGION, NULL))
                  || INTVAL (XEXP (note, 0)) >= 0))
-           continue;
+           {
+             ei_next (&ei);
+             continue;
+           }
        }
       else
-       continue;
+       {
+         ei_next (&ei);
+         continue;
+       }
 
       remove_edge (e);
       bb->flags |= BB_DIRTY;
@@ -2301,6 +2330,7 @@ purge_dead_edges (basic_block bb)
     {
       rtx note;
       edge b,f;
+      edge_iterator ei;
 
       /* We do care only about conditional jumps and simplejumps.  */
       if (!any_condjump_p (insn)
@@ -2319,10 +2349,8 @@ purge_dead_edges (basic_block bb)
            remove_note (insn, note);
        }
 
-      for (e = bb->succ; e; e = next)
+      for (ei = ei_start (bb->succs); (e = ei_safe_edge (ei)); )
        {
-         next = e->succ_next;
-
          /* Avoid abnormal flags to leak from computed jumps turned
             into simplejumps.  */
 
@@ -2332,22 +2360,32 @@ purge_dead_edges (basic_block bb)
          if ((e->flags & EDGE_FALLTHRU) && any_condjump_p (insn))
            /* A conditional jump can fall through into the next
               block, so we should keep the edge.  */
-           continue;
+           {
+             ei_next (&ei);
+             continue;
+           }
          else if (e->dest != EXIT_BLOCK_PTR
                   && BB_HEAD (e->dest) == JUMP_LABEL (insn))
            /* If the destination block is the target of the jump,
               keep the edge.  */
-           continue;
+           {
+             ei_next (&ei);
+             continue;
+           }
          else if (e->dest == EXIT_BLOCK_PTR && returnjump_p (insn))
            /* If the destination block is the exit block, and this
               instruction is a return, then keep the edge.  */
-           continue;
+           {
+             ei_next (&ei);
+             continue;
+           }
          else if ((e->flags & EDGE_EH) && can_throw_internal (insn))
            /* Keep the edges that correspond to exceptions thrown by
               this instruction and rematerialize the EDGE_ABNORMAL
               flag we just cleared above.  */
            {
              e->flags |= EDGE_ABNORMAL;
+             ei_next (&ei);
              continue;
            }
 
@@ -2357,7 +2395,7 @@ purge_dead_edges (basic_block bb)
          remove_edge (e);
        }
 
-      if (!bb->succ || !purged)
+      if (EDGE_COUNT (bb->succs) == 0 || !purged)
        return purged;
 
       if (dump_file)
@@ -2367,10 +2405,10 @@ purge_dead_edges (basic_block bb)
        return purged;
 
       /* Redistribute probabilities.  */
-      if (!bb->succ->succ_next)
+      if (single_succ_p (bb))
        {
-         bb->succ->probability = REG_BR_PROB_BASE;
-         bb->succ->count = bb->count;
+         single_succ_edge (bb)->probability = REG_BR_PROB_BASE;
+         single_succ_edge (bb)->count = bb->count;
        }
       else
        {
@@ -2394,8 +2432,9 @@ purge_dead_edges (basic_block bb)
         from non-local gotos and the like.  If there were, we shouldn't
         have created the sibcall in the first place.  Second, there
         should of course never have been a fallthru edge.  */
-      gcc_assert (bb->succ && !bb->succ->succ_next);
-      gcc_assert (bb->succ->flags == (EDGE_SIBCALL | EDGE_ABNORMAL));
+      gcc_assert (single_succ_p (bb));
+      gcc_assert (single_succ_edge (bb)->flags
+                 == (EDGE_SIBCALL | EDGE_ABNORMAL));
 
       return 0;
     }
@@ -2405,28 +2444,33 @@ purge_dead_edges (basic_block bb)
      as these are only created by conditional branches.  If we find such an
      edge we know that there used to be a jump here and can then safely
      remove all non-fallthru edges.  */
-  for (e = bb->succ; e && (e->flags & (EDGE_COMPLEX | EDGE_FALLTHRU));
-       e = e->succ_next)
-    ;
+  found = false;
+  FOR_EACH_EDGE (e, ei, bb->succs)
+    if (! (e->flags & (EDGE_COMPLEX | EDGE_FALLTHRU)))
+      {
+       found = true;
+       break;
+      }
 
-  if (!e)
+  if (!found)
     return purged;
 
-  for (e = bb->succ; e; e = next)
+  for (ei = ei_start (bb->succs); (e = ei_safe_edge (ei)); )
     {
-      next = e->succ_next;
       if (!(e->flags & EDGE_FALLTHRU))
        {
          bb->flags |= BB_DIRTY;
          remove_edge (e);
          purged = true;
        }
+      else
+       ei_next (&ei);
     }
 
-  gcc_assert (bb->succ && !bb->succ->succ_next);
+  gcc_assert (single_succ_p (bb));
 
-  bb->succ->probability = REG_BR_PROB_BASE;
-  bb->succ->count = bb->count;
+  single_succ_edge (bb)->probability = REG_BR_PROB_BASE;
+  single_succ_edge (bb)->count = bb->count;
 
   if (dump_file)
     fprintf (dump_file, "Purged non-fallthru edges from bb %i\n",
@@ -2542,10 +2586,11 @@ cfg_layout_redirect_edge_and_branch (edge e, basic_block dest)
        }
       /* In case we are redirecting fallthru edge to the branch edge
          of conditional jump, remove it.  */
-      if (src->succ->succ_next
-         && !src->succ->succ_next->succ_next)
+      if (EDGE_COUNT (src->succs) == 2)
        {
-         edge s = e->succ_next ? e->succ_next : src->succ;
+         /* Find the edge that is different from E.  */
+         edge s = EDGE_SUCC (src, EDGE_SUCC (src, 0) == e);
+
          if (s->dest == dest
              && any_condjump_p (BB_END (src))
              && onlyjump_p (BB_END (src)))
@@ -2679,10 +2724,12 @@ cfg_layout_can_merge_blocks_p (basic_block a, basic_block b)
     return false;
 
   /* There must be exactly one edge in between the blocks.  */
-  return (a->succ && !a->succ->succ_next && a->succ->dest == b
-         && !b->pred->pred_next && a != b
+  return (single_succ_p (a)
+         && single_succ (a) == b
+         && single_pred_p (b) == 1
+         && a != b
          /* Must be simple edge.  */
-         && !(a->succ->flags & EDGE_COMPLEX)
+         && !(single_succ_edge (a)->flags & EDGE_COMPLEX)
          && a != ENTRY_BLOCK_PTR && b != EXIT_BLOCK_PTR
          /* If the jump insn has side effects,
             we can't kill the edge.  */
@@ -2706,7 +2753,7 @@ cfg_layout_merge_blocks (basic_block a, basic_block b)
   /* We should have fallthru edge in a, or we can do dummy redirection to get
      it cleaned up.  */
   if (JUMP_P (BB_END (a)))
-    try_redirect_by_replacing_jump (a->succ, b, true);
+    try_redirect_by_replacing_jump (EDGE_SUCC (a, 0), b, true);
   gcc_assert (!JUMP_P (BB_END (a)));
 
   /* Possible line number notes should appear in between.  */
@@ -2714,7 +2761,7 @@ cfg_layout_merge_blocks (basic_block a, basic_block b)
     {
       rtx first = BB_END (a), last;
 
-      last = emit_insn_after (b->rbi->header, BB_END (a));
+      last = emit_insn_after_noloc (b->rbi->header, BB_END (a));
       delete_insn_chain (NEXT_INSN (first), last);
       b->rbi->header = NULL;
     }
@@ -2724,7 +2771,7 @@ cfg_layout_merge_blocks (basic_block a, basic_block b)
     {
       rtx first = unlink_insn_chain (BB_HEAD (b), BB_END (b));
 
-      emit_insn_after (first, BB_END (a));
+      emit_insn_after_noloc (first, BB_END (a));
       /* Skip possible DELETED_LABEL insn.  */
       if (!NOTE_INSN_BASIC_BLOCK_P (first))
        first = NEXT_INSN (first);
@@ -2778,7 +2825,6 @@ cfg_layout_merge_blocks (basic_block a, basic_block b)
 static basic_block
 cfg_layout_split_edge (edge e)
 {
-  edge new_e;
   basic_block new_bb =
     create_basic_block (e->src != ENTRY_BLOCK_PTR
                        ? NEXT_INSN (BB_END (e->src)) : get_insns (),
@@ -2788,15 +2834,15 @@ cfg_layout_split_edge (edge e)
      create it to avoid getting an ICE later.  */
   if (e->dest->global_live_at_start)
     {
-      new_bb->global_live_at_start = OBSTACK_ALLOC_REG_SET (&flow_obstack);
-      new_bb->global_live_at_end = OBSTACK_ALLOC_REG_SET (&flow_obstack);
+      new_bb->global_live_at_start = ALLOC_REG_SET (&reg_obstack);
+      new_bb->global_live_at_end = ALLOC_REG_SET (&reg_obstack);
       COPY_REG_SET (new_bb->global_live_at_start,
                    e->dest->global_live_at_start);
       COPY_REG_SET (new_bb->global_live_at_end,
                    e->dest->global_live_at_start);
     }
 
-  new_e = make_edge (new_bb, e->dest, EDGE_FALLTHRU);
+  make_edge (new_bb, e->dest, EDGE_FALLTHRU);
   redirect_edge_and_branch_force (e, new_bb);
 
   return new_bb;
@@ -2844,7 +2890,6 @@ need_fake_edge_p (rtx insn)
   if ((CALL_P (insn)
        && !SIBLING_CALL_P (insn)
        && !find_reg_note (insn, REG_NORETURN, NULL)
-       && !find_reg_note (insn, REG_ALWAYS_RETURN, NULL)
        && !CONST_OR_PURE_CALL_P (insn)))
     return true;
 
@@ -2906,13 +2951,12 @@ rtl_flow_call_edges_add (sbitmap blocks)
        {
          edge e;
 
-         for (e = bb->succ; e; e = e->succ_next)
-           if (e->dest == EXIT_BLOCK_PTR)
-             {
-               insert_insn_on_edge (gen_rtx_USE (VOIDmode, const0_rtx), e);
-               commit_edge_insertions ();
-               break;
-             }
+         e = find_edge (bb, EXIT_BLOCK_PTR);
+         if (e)
+           {
+             insert_insn_on_edge (gen_rtx_USE (VOIDmode, const0_rtx), e);
+             commit_edge_insertions ();
+           }
        }
     }
 
@@ -2954,8 +2998,10 @@ rtl_flow_call_edges_add (sbitmap blocks)
 
 #ifdef ENABLE_CHECKING
              if (split_at_insn == BB_END (bb))
-               for (e = bb->succ; e; e = e->succ_next)
-                 gcc_assert (e->dest != EXIT_BLOCK_PTR);
+               {
+                 e = find_edge (bb, EXIT_BLOCK_PTR);
+                 gcc_assert (e == NULL);
+               }
 #endif
 
              /* Note that the following may create a new basic block
@@ -3003,7 +3049,9 @@ struct cfg_hooks rtl_cfg_hooks = {
   rtl_tidy_fallthru_edge,
   rtl_block_ends_with_call_p,
   rtl_block_ends_with_condjump_p,
-  rtl_flow_call_edges_add
+  rtl_flow_call_edges_add,
+  NULL, /* execute_on_growing_pred */
+  NULL /* execute_on_shrinking_pred */
 };
 
 /* Implementation of CFG manipulation for cfg layout RTL, where
@@ -3039,6 +3087,8 @@ struct cfg_hooks cfg_layout_rtl_cfg_hooks = {
   NULL,
   rtl_block_ends_with_call_p,
   rtl_block_ends_with_condjump_p,
-  rtl_flow_call_edges_add
+  rtl_flow_call_edges_add,
+  NULL, /* execute_on_growing_pred */
+  NULL /* execute_on_shrinking_pred */
 };