OSDN Git Service

PR c++/46245
[pf3gnuchains/gcc-fork.git] / gcc / recog.c
index 43f901f..afe985e 100644 (file)
@@ -24,7 +24,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "system.h"
 #include "coretypes.h"
 #include "tm.h"
-#include "rtl.h"
+#include "rtl-error.h"
 #include "tm_p.h"
 #include "insn-config.h"
 #include "insn-attr.h"
@@ -35,7 +35,6 @@ along with GCC; see the file COPYING3.  If not see
 #include "expr.h"
 #include "function.h"
 #include "flags.h"
-#include "toplev.h"
 #include "basic-block.h"
 #include "output.h"
 #include "reload.h"
@@ -278,8 +277,8 @@ canonicalize_change_group (rtx insn, rtx x)
       /* Oops, the caller has made X no longer canonical.
         Let's redo the changes in the correct order.  */
       rtx tem = XEXP (x, 0);
-      validate_change (insn, &XEXP (x, 0), XEXP (x, 1), 1);
-      validate_change (insn, &XEXP (x, 1), tem, 1);
+      validate_unshare_change (insn, &XEXP (x, 0), XEXP (x, 1), 1);
+      validate_unshare_change (insn, &XEXP (x, 1), tem, 1);
       return true;
     }
   else
@@ -931,7 +930,9 @@ general_operand (rtx op, enum machine_mode mode)
     return ((GET_MODE (op) == VOIDmode || GET_MODE (op) == mode
             || mode == VOIDmode)
            && (! flag_pic || LEGITIMATE_PIC_OPERAND_P (op))
-           && LEGITIMATE_CONSTANT_P (op));
+           && targetm.legitimate_constant_p (mode == VOIDmode
+                                             ? GET_MODE (op)
+                                             : mode, op));
 
   /* Except for certain constants with VOIDmode, already checked for,
      OP's mode must match MODE if MODE specifies a mode.  */
@@ -1108,7 +1109,9 @@ immediate_operand (rtx op, enum machine_mode mode)
          && (GET_MODE (op) == mode || mode == VOIDmode
              || GET_MODE (op) == VOIDmode)
          && (! flag_pic || LEGITIMATE_PIC_OPERAND_P (op))
-         && LEGITIMATE_CONSTANT_P (op));
+         && targetm.legitimate_constant_p (mode == VOIDmode
+                                           ? GET_MODE (op)
+                                           : mode, op));
 }
 
 /* Returns 1 if OP is an operand that is a CONST_INT.  */
@@ -1158,24 +1161,7 @@ int
 nonmemory_operand (rtx op, enum machine_mode mode)
 {
   if (CONSTANT_P (op))
-    {
-      /* Don't accept CONST_INT or anything similar
-        if the caller wants something floating.  */
-      if (GET_MODE (op) == VOIDmode && mode != VOIDmode
-         && GET_MODE_CLASS (mode) != MODE_INT
-         && GET_MODE_CLASS (mode) != MODE_PARTIAL_INT)
-       return 0;
-
-      if (CONST_INT_P (op)
-         && mode != VOIDmode
-         && trunc_int_for_mode (INTVAL (op), mode) != INTVAL (op))
-       return 0;
-
-      return ((GET_MODE (op) == VOIDmode || GET_MODE (op) == mode
-              || mode == VOIDmode)
-             && (! flag_pic || LEGITIMATE_PIC_OPERAND_P (op))
-             && LEGITIMATE_CONSTANT_P (op));
-    }
+    return immediate_operand (op, mode);
 
   if (GET_MODE (op) != mode && mode != VOIDmode)
     return 0;
@@ -2742,7 +2728,7 @@ constrain_operands (int strict)
                        case PRE_MODIFY:
                        case POST_MODIFY:
                          if (strchr (recog_data.constraints[opno], '<') == NULL
-                             || strchr (recog_data.constraints[opno], '>')
+                             && strchr (recog_data.constraints[opno], '>')
                                 == NULL)
                            return 0;
                          break;
@@ -2768,21 +2754,21 @@ constrain_operands (int strict)
     return 0;
 }
 
-/* Return 1 iff OPERAND (assumed to be a REG rtx)
+/* Return true iff OPERAND (assumed to be a REG rtx)
    is a hard reg in class CLASS when its regno is offset by OFFSET
    and changed to mode MODE.
    If REG occupies multiple hard regs, all of them must be in CLASS.  */
 
-int
-reg_fits_class_p (rtx operand, enum reg_class cl, int offset,
+bool
+reg_fits_class_p (const_rtx operand, reg_class_t cl, int offset,
                  enum machine_mode mode)
 {
   int regno = REGNO (operand);
 
   if (cl == NO_REGS)
-    return 0;
+    return false;
 
-  return (regno < FIRST_PSEUDO_REGISTER
+  return (HARD_REGISTER_NUM_P (regno)
          && in_hard_reg_set_p (reg_class_contents[(int) cl],
                                mode, regno + offset));
 }
@@ -2885,15 +2871,8 @@ split_all_insns (void)
                }
              else
                {
-                 rtx last = split_insn (insn);
-                 if (last)
+                 if (split_insn (insn))
                    {
-                     /* The split sequence may include barrier, but the
-                        BB boundary we are interested in will be set to
-                        previous one.  */
-
-                     while (BARRIER_P (last))
-                       last = PREV_INSN (last);
                      SET_BIT (blocks, bb->index);
                      changed = true;
                    }
@@ -2958,6 +2937,10 @@ struct peep2_insn_data
 
 static struct peep2_insn_data peep2_insn_data[MAX_INSNS_PER_PEEP2 + 1];
 static int peep2_current;
+
+static bool peep2_do_rebuild_jump_labels;
+static bool peep2_do_cleanup_cfg;
+
 /* The number of instructions available to match a peep2.  */
 int peep2_current_count;
 
@@ -2966,6 +2949,16 @@ int peep2_current_count;
    DF_LIVE_OUT for the block.  */
 #define PEEP2_EOB      pc_rtx
 
+/* Wrap N to fit into the peep2_insn_data buffer.  */
+
+static int
+peep2_buf_position (int n)
+{
+  if (n >= MAX_INSNS_PER_PEEP2 + 1)
+    n -= MAX_INSNS_PER_PEEP2 + 1;
+  return n;
+}
+
 /* Return the Nth non-note insn after `current', or return NULL_RTX if it
    does not exist.  Used by the recognizer to find the next insn to match
    in a multi-insn pattern.  */
@@ -2975,9 +2968,7 @@ peep2_next_insn (int n)
 {
   gcc_assert (n <= peep2_current_count);
 
-  n += peep2_current;
-  if (n >= MAX_INSNS_PER_PEEP2 + 1)
-    n -= MAX_INSNS_PER_PEEP2 + 1;
+  n = peep2_buf_position (peep2_current + n);
 
   return peep2_insn_data[n].insn;
 }
@@ -2990,9 +2981,7 @@ peep2_regno_dead_p (int ofs, int regno)
 {
   gcc_assert (ofs < MAX_INSNS_PER_PEEP2 + 1);
 
-  ofs += peep2_current;
-  if (ofs >= MAX_INSNS_PER_PEEP2 + 1)
-    ofs -= MAX_INSNS_PER_PEEP2 + 1;
+  ofs = peep2_buf_position (peep2_current + ofs);
 
   gcc_assert (peep2_insn_data[ofs].insn != NULL_RTX);
 
@@ -3008,9 +2997,7 @@ peep2_reg_dead_p (int ofs, rtx reg)
 
   gcc_assert (ofs < MAX_INSNS_PER_PEEP2 + 1);
 
-  ofs += peep2_current;
-  if (ofs >= MAX_INSNS_PER_PEEP2 + 1)
-    ofs -= MAX_INSNS_PER_PEEP2 + 1;
+  ofs = peep2_buf_position (peep2_current + ofs);
 
   gcc_assert (peep2_insn_data[ofs].insn != NULL_RTX);
 
@@ -3045,12 +3032,8 @@ peep2_find_free_register (int from, int to, const char *class_str,
   gcc_assert (from < MAX_INSNS_PER_PEEP2 + 1);
   gcc_assert (to < MAX_INSNS_PER_PEEP2 + 1);
 
-  from += peep2_current;
-  if (from >= MAX_INSNS_PER_PEEP2 + 1)
-    from -= MAX_INSNS_PER_PEEP2 + 1;
-  to += peep2_current;
-  if (to >= MAX_INSNS_PER_PEEP2 + 1)
-    to -= MAX_INSNS_PER_PEEP2 + 1;
+  from = peep2_buf_position (peep2_current + from);
+  to = peep2_buf_position (peep2_current + to);
 
   gcc_assert (peep2_insn_data[from].insn != NULL_RTX);
   REG_SET_TO_HARD_REG_SET (live, peep2_insn_data[from].live_before);
@@ -3059,8 +3042,7 @@ peep2_find_free_register (int from, int to, const char *class_str,
     {
       HARD_REG_SET this_live;
 
-      if (++from >= MAX_INSNS_PER_PEEP2 + 1)
-       from = 0;
+      from = peep2_buf_position (from + 1);
       gcc_assert (peep2_insn_data[from].insn != NULL_RTX);
       REG_SET_TO_HARD_REG_SET (this_live, peep2_insn_data[from].live_before);
       IOR_HARD_REG_SET (live, this_live);
@@ -3153,19 +3135,311 @@ peep2_reinit_state (regset live)
   COPY_REG_SET (peep2_insn_data[MAX_INSNS_PER_PEEP2].live_before, live);
 }
 
+/* While scanning basic block BB, we found a match of length MATCH_LEN,
+   starting at INSN.  Perform the replacement, removing the old insns and
+   replacing them with ATTEMPT.  Returns the last insn emitted, or NULL
+   if the replacement is rejected.  */
+
+static rtx
+peep2_attempt (basic_block bb, rtx insn, int match_len, rtx attempt)
+{
+  int i;
+  rtx last, note, before_try, x;
+  rtx old_insn, new_insn;
+  bool was_call = false;
+
+  /* If we are splittind an RTX_FRAME_RELATED_P insn, do not allow it to
+     match more than one insn, or to be split into more than one insn.  */
+  old_insn = peep2_insn_data[peep2_current].insn;
+  if (RTX_FRAME_RELATED_P (old_insn))
+    {
+      bool any_note = false;
+
+      if (match_len != 0)
+       return NULL;
+
+      /* Look for one "active" insn.  I.e. ignore any "clobber" insns that
+        may be in the stream for the purpose of register allocation.  */
+      if (active_insn_p (attempt))
+       new_insn = attempt;
+      else
+       new_insn = next_active_insn (attempt);
+      if (next_active_insn (new_insn))
+       return NULL;
+
+      /* We have a 1-1 replacement.  Copy over any frame-related info.  */
+      RTX_FRAME_RELATED_P (new_insn) = 1;
+
+      /* Allow the backend to fill in a note during the split.  */
+      for (note = REG_NOTES (new_insn); note ; note = XEXP (note, 1))
+       switch (REG_NOTE_KIND (note))
+         {
+         case REG_FRAME_RELATED_EXPR:
+         case REG_CFA_DEF_CFA:
+         case REG_CFA_ADJUST_CFA:
+         case REG_CFA_OFFSET:
+         case REG_CFA_REGISTER:
+         case REG_CFA_EXPRESSION:
+         case REG_CFA_RESTORE:
+         case REG_CFA_SET_VDRAP:
+           any_note = true;
+           break;
+         default:
+           break;
+         }
+
+      /* If the backend didn't supply a note, copy one over.  */
+      if (!any_note)
+        for (note = REG_NOTES (old_insn); note ; note = XEXP (note, 1))
+         switch (REG_NOTE_KIND (note))
+           {
+           case REG_FRAME_RELATED_EXPR:
+           case REG_CFA_DEF_CFA:
+           case REG_CFA_ADJUST_CFA:
+           case REG_CFA_OFFSET:
+           case REG_CFA_REGISTER:
+           case REG_CFA_EXPRESSION:
+           case REG_CFA_RESTORE:
+           case REG_CFA_SET_VDRAP:
+             add_reg_note (new_insn, REG_NOTE_KIND (note), XEXP (note, 0));
+             any_note = true;
+             break;
+           default:
+             break;
+           }
+
+      /* If there still isn't a note, make sure the unwind info sees the
+        same expression as before the split.  */
+      if (!any_note)
+       {
+         rtx old_set, new_set;
+
+         /* The old insn had better have been simple, or annotated.  */
+         old_set = single_set (old_insn);
+         gcc_assert (old_set != NULL);
+
+         new_set = single_set (new_insn);
+         if (!new_set || !rtx_equal_p (new_set, old_set))
+           add_reg_note (new_insn, REG_FRAME_RELATED_EXPR, old_set);
+       }
+
+      /* Copy prologue/epilogue status.  This is required in order to keep
+        proper placement of EPILOGUE_BEG and the DW_CFA_remember_state.  */
+      maybe_copy_prologue_epilogue_insn (old_insn, new_insn);
+    }
+
+  /* If we are splitting a CALL_INSN, look for the CALL_INSN
+     in SEQ and copy our CALL_INSN_FUNCTION_USAGE and other
+     cfg-related call notes.  */
+  for (i = 0; i <= match_len; ++i)
+    {
+      int j;
+
+      j = peep2_buf_position (peep2_current + i);
+      old_insn = peep2_insn_data[j].insn;
+      if (!CALL_P (old_insn))
+       continue;
+      was_call = true;
+
+      new_insn = attempt;
+      while (new_insn != NULL_RTX)
+       {
+         if (CALL_P (new_insn))
+           break;
+         new_insn = NEXT_INSN (new_insn);
+       }
+
+      gcc_assert (new_insn != NULL_RTX);
+
+      CALL_INSN_FUNCTION_USAGE (new_insn)
+       = CALL_INSN_FUNCTION_USAGE (old_insn);
+
+      for (note = REG_NOTES (old_insn);
+          note;
+          note = XEXP (note, 1))
+       switch (REG_NOTE_KIND (note))
+         {
+         case REG_NORETURN:
+         case REG_SETJMP:
+           add_reg_note (new_insn, REG_NOTE_KIND (note),
+                         XEXP (note, 0));
+           break;
+         default:
+           /* Discard all other reg notes.  */
+           break;
+         }
+
+      /* Croak if there is another call in the sequence.  */
+      while (++i <= match_len)
+       {
+         j = peep2_buf_position (peep2_current + i);
+         old_insn = peep2_insn_data[j].insn;
+         gcc_assert (!CALL_P (old_insn));
+       }
+      break;
+    }
+
+  i = peep2_buf_position (peep2_current + match_len);
+
+  note = find_reg_note (peep2_insn_data[i].insn, REG_EH_REGION, NULL_RTX);
+
+  /* Replace the old sequence with the new.  */
+  last = emit_insn_after_setloc (attempt,
+                                peep2_insn_data[i].insn,
+                                INSN_LOCATOR (peep2_insn_data[i].insn));
+  before_try = PREV_INSN (insn);
+  delete_insn_chain (insn, peep2_insn_data[i].insn, false);
+
+  /* Re-insert the EH_REGION notes.  */
+  if (note || (was_call && nonlocal_goto_handler_labels))
+    {
+      edge eh_edge;
+      edge_iterator ei;
+
+      FOR_EACH_EDGE (eh_edge, ei, bb->succs)
+       if (eh_edge->flags & (EDGE_EH | EDGE_ABNORMAL_CALL))
+         break;
+
+      if (note)
+       copy_reg_eh_region_note_backward (note, last, before_try);
+
+      if (eh_edge)
+       for (x = last; x != before_try; x = PREV_INSN (x))
+         if (x != BB_END (bb)
+             && (can_throw_internal (x)
+                 || can_nonlocal_goto (x)))
+           {
+             edge nfte, nehe;
+             int flags;
+
+             nfte = split_block (bb, x);
+             flags = (eh_edge->flags
+                      & (EDGE_EH | EDGE_ABNORMAL));
+             if (CALL_P (x))
+               flags |= EDGE_ABNORMAL_CALL;
+             nehe = make_edge (nfte->src, eh_edge->dest,
+                               flags);
+
+             nehe->probability = eh_edge->probability;
+             nfte->probability
+               = REG_BR_PROB_BASE - nehe->probability;
+
+             peep2_do_cleanup_cfg |= purge_dead_edges (nfte->dest);
+             bb = nfte->src;
+             eh_edge = nehe;
+           }
+
+      /* Converting possibly trapping insn to non-trapping is
+        possible.  Zap dummy outgoing edges.  */
+      peep2_do_cleanup_cfg |= purge_dead_edges (bb);
+    }
+
+  /* If we generated a jump instruction, it won't have
+     JUMP_LABEL set.  Recompute after we're done.  */
+  for (x = last; x != before_try; x = PREV_INSN (x))
+    if (JUMP_P (x))
+      {
+       peep2_do_rebuild_jump_labels = true;
+       break;
+      }
+
+  return last;
+}
+
+/* After performing a replacement in basic block BB, fix up the life
+   information in our buffer.  LAST is the last of the insns that we
+   emitted as a replacement.  PREV is the insn before the start of
+   the replacement.  MATCH_LEN is the number of instructions that were
+   matched, and which now need to be replaced in the buffer.  */
+
+static void
+peep2_update_life (basic_block bb, int match_len, rtx last, rtx prev)
+{
+  int i = peep2_buf_position (peep2_current + match_len + 1);
+  rtx x;
+  regset_head live;
+
+  INIT_REG_SET (&live);
+  COPY_REG_SET (&live, peep2_insn_data[i].live_before);
+
+  gcc_assert (peep2_current_count >= match_len + 1);
+  peep2_current_count -= match_len + 1;
+
+  x = last;
+  do
+    {
+      if (INSN_P (x))
+       {
+         df_insn_rescan (x);
+         if (peep2_current_count < MAX_INSNS_PER_PEEP2)
+           {
+             peep2_current_count++;
+             if (--i < 0)
+               i = MAX_INSNS_PER_PEEP2;
+             peep2_insn_data[i].insn = x;
+             df_simulate_one_insn_backwards (bb, x, &live);
+             COPY_REG_SET (peep2_insn_data[i].live_before, &live);
+           }
+       }
+      x = PREV_INSN (x);
+    }
+  while (x != prev);
+  CLEAR_REG_SET (&live);
+
+  peep2_current = i;
+}
+
+/* Add INSN, which is in BB, at the end of the peep2 insn buffer if possible.
+   Return true if we added it, false otherwise.  The caller will try to match
+   peepholes against the buffer if we return false; otherwise it will try to
+   add more instructions to the buffer.  */
+
+static bool
+peep2_fill_buffer (basic_block bb, rtx insn, regset live)
+{
+  int pos;
+
+  /* Once we have filled the maximum number of insns the buffer can hold,
+     allow the caller to match the insns against peepholes.  We wait until
+     the buffer is full in case the target has similar peepholes of different
+     length; we always want to match the longest if possible.  */
+  if (peep2_current_count == MAX_INSNS_PER_PEEP2)
+    return false;
+
+  /* If an insn has RTX_FRAME_RELATED_P set, do not allow it to be matched with
+     any other pattern, lest it change the semantics of the frame info.  */
+  if (RTX_FRAME_RELATED_P (insn))
+    {
+      /* Let the buffer drain first.  */
+      if (peep2_current_count > 0)
+       return false;
+      /* Now the insn will be the only thing in the buffer.  */
+    }
+
+  pos = peep2_buf_position (peep2_current + peep2_current_count);
+  peep2_insn_data[pos].insn = insn;
+  COPY_REG_SET (peep2_insn_data[pos].live_before, live);
+  peep2_current_count++;
+
+  df_simulate_one_insn_forwards (bb, insn, live);
+  return true;
+}
+
 /* Perform the peephole2 optimization pass.  */
 
 static void
 peephole2_optimize (void)
 {
-  rtx insn, prev;
+  rtx insn;
   bitmap live;
   int i;
   basic_block bb;
-  bool do_cleanup_cfg = false;
-  bool do_rebuild_jump_labels = false;
+
+  peep2_do_cleanup_cfg = false;
+  peep2_do_rebuild_jump_labels = false;
 
   df_set_flags (DF_LR_RUN_DCE);
+  df_note_add_problem ();
   df_analyze ();
 
   /* Initialize the regsets we're going to use.  */
@@ -3175,214 +3449,60 @@ peephole2_optimize (void)
 
   FOR_EACH_BB_REVERSE (bb)
     {
+      bool past_end = false;
+      int pos;
+
       rtl_profile_for_bb (bb);
 
       /* Start up propagation.  */
-      bitmap_copy (live, DF_LR_OUT (bb));
-      df_simulate_initialize_backwards (bb, live);
+      bitmap_copy (live, DF_LR_IN (bb));
+      df_simulate_initialize_forwards (bb, live);
       peep2_reinit_state (live);
 
-      for (insn = BB_END (bb); ; insn = prev)
+      insn = BB_HEAD (bb);
+      for (;;)
        {
-         prev = PREV_INSN (insn);
-         if (NONDEBUG_INSN_P (insn))
-           {
-             rtx attempt, before_try, x;
-             int match_len;
-             rtx note;
-             bool was_call = false;
-
-             /* Record this insn.  */
-             if (--peep2_current < 0)
-               peep2_current = MAX_INSNS_PER_PEEP2;
-             if (peep2_current_count < MAX_INSNS_PER_PEEP2
-                 && peep2_insn_data[peep2_current].insn == NULL_RTX)
-               peep2_current_count++;
-             peep2_insn_data[peep2_current].insn = insn;
-             df_simulate_one_insn_backwards (bb, insn, live);
-             COPY_REG_SET (peep2_insn_data[peep2_current].live_before, live);
-
-             if (RTX_FRAME_RELATED_P (insn))
-               {
-                 /* If an insn has RTX_FRAME_RELATED_P set, peephole
-                    substitution would lose the
-                    REG_FRAME_RELATED_EXPR that is attached.  */
-                 peep2_reinit_state (live);
-                 attempt = NULL;
-               }
-             else
-               /* Match the peephole.  */
-               attempt = peephole2_insns (PATTERN (insn), insn, &match_len);
-
-             if (attempt != NULL)
-               {
-                 /* If we are splitting a CALL_INSN, look for the CALL_INSN
-                    in SEQ and copy our CALL_INSN_FUNCTION_USAGE and other
-                    cfg-related call notes.  */
-                 for (i = 0; i <= match_len; ++i)
-                   {
-                     int j;
-                     rtx old_insn, new_insn, note;
-
-                     j = i + peep2_current;
-                     if (j >= MAX_INSNS_PER_PEEP2 + 1)
-                       j -= MAX_INSNS_PER_PEEP2 + 1;
-                     old_insn = peep2_insn_data[j].insn;
-                     if (!CALL_P (old_insn))
-                       continue;
-                     was_call = true;
-
-                     new_insn = attempt;
-                     while (new_insn != NULL_RTX)
-                       {
-                         if (CALL_P (new_insn))
-                           break;
-                         new_insn = NEXT_INSN (new_insn);
-                       }
-
-                     gcc_assert (new_insn != NULL_RTX);
-
-                     CALL_INSN_FUNCTION_USAGE (new_insn)
-                       = CALL_INSN_FUNCTION_USAGE (old_insn);
-
-                     for (note = REG_NOTES (old_insn);
-                          note;
-                          note = XEXP (note, 1))
-                       switch (REG_NOTE_KIND (note))
-                         {
-                         case REG_NORETURN:
-                         case REG_SETJMP:
-                           add_reg_note (new_insn, REG_NOTE_KIND (note),
-                                         XEXP (note, 0));
-                           break;
-                         default:
-                           /* Discard all other reg notes.  */
-                           break;
-                         }
-
-                     /* Croak if there is another call in the sequence.  */
-                     while (++i <= match_len)
-                       {
-                         j = i + peep2_current;
-                         if (j >= MAX_INSNS_PER_PEEP2 + 1)
-                           j -= MAX_INSNS_PER_PEEP2 + 1;
-                         old_insn = peep2_insn_data[j].insn;
-                         gcc_assert (!CALL_P (old_insn));
-                       }
-                     break;
-                   }
-
-                 i = match_len + peep2_current;
-                 if (i >= MAX_INSNS_PER_PEEP2 + 1)
-                   i -= MAX_INSNS_PER_PEEP2 + 1;
-
-                 note = find_reg_note (peep2_insn_data[i].insn,
-                                       REG_EH_REGION, NULL_RTX);
-
-                 /* Replace the old sequence with the new.  */
-                 attempt = emit_insn_after_setloc (attempt,
-                                                   peep2_insn_data[i].insn,
-                                      INSN_LOCATOR (peep2_insn_data[i].insn));
-                 before_try = PREV_INSN (insn);
-                 delete_insn_chain (insn, peep2_insn_data[i].insn, false);
+         rtx attempt, head;
+         int match_len;
 
-                 /* Re-insert the EH_REGION notes.  */
-                 if (note || (was_call && nonlocal_goto_handler_labels))
-                   {
-                     edge eh_edge;
-                     edge_iterator ei;
+         if (!past_end && !NONDEBUG_INSN_P (insn))
+           {
+           next_insn:
+             insn = NEXT_INSN (insn);
+             if (insn == NEXT_INSN (BB_END (bb)))
+               past_end = true;
+             continue;
+           }
+         if (!past_end && peep2_fill_buffer (bb, insn, live))
+           goto next_insn;
 
-                     FOR_EACH_EDGE (eh_edge, ei, bb->succs)
-                       if (eh_edge->flags & (EDGE_EH | EDGE_ABNORMAL_CALL))
-                         break;
+         /* If we did not fill an empty buffer, it signals the end of the
+            block.  */
+         if (peep2_current_count == 0)
+           break;
 
-                     if (note)
-                       copy_reg_eh_region_note_backward (note, attempt,
-                                                         before_try);
-
-                     if (eh_edge)
-                       for (x = attempt ; x != before_try ; x = PREV_INSN (x))
-                         if (x != BB_END (bb)
-                             && (can_throw_internal (x)
-                                 || can_nonlocal_goto (x)))
-                           {
-                             edge nfte, nehe;
-                             int flags;
-
-                             nfte = split_block (bb, x);
-                             flags = (eh_edge->flags
-                                      & (EDGE_EH | EDGE_ABNORMAL));
-                             if (CALL_P (x))
-                               flags |= EDGE_ABNORMAL_CALL;
-                             nehe = make_edge (nfte->src, eh_edge->dest,
-                                               flags);
-
-                             nehe->probability = eh_edge->probability;
-                             nfte->probability
-                               = REG_BR_PROB_BASE - nehe->probability;
-
-                             do_cleanup_cfg |= purge_dead_edges (nfte->dest);
-                             bb = nfte->src;
-                             eh_edge = nehe;
-                           }
-
-                     /* Converting possibly trapping insn to non-trapping is
-                        possible.  Zap dummy outgoing edges.  */
-                     do_cleanup_cfg |= purge_dead_edges (bb);
-                   }
+         /* The buffer filled to the current maximum, so try to match.  */
 
-                 if (targetm.have_conditional_execution ())
-                   {
-                     for (i = 0; i < MAX_INSNS_PER_PEEP2 + 1; ++i)
-                       peep2_insn_data[i].insn = NULL_RTX;
-                     peep2_insn_data[peep2_current].insn = PEEP2_EOB;
-                     peep2_current_count = 0;
-                   }
-                 else
-                   {
-                     /* Back up lifetime information past the end of the
-                        newly created sequence.  */
-                     if (++i >= MAX_INSNS_PER_PEEP2 + 1)
-                       i = 0;
-                     bitmap_copy (live, peep2_insn_data[i].live_before);
-
-                     /* Update life information for the new sequence.  */
-                     x = attempt;
-                     do
-                       {
-                         if (INSN_P (x))
-                           {
-                             if (--i < 0)
-                               i = MAX_INSNS_PER_PEEP2;
-                             if (peep2_current_count < MAX_INSNS_PER_PEEP2
-                                 && peep2_insn_data[i].insn == NULL_RTX)
-                               peep2_current_count++;
-                             peep2_insn_data[i].insn = x;
-                             df_insn_rescan (x);
-                             df_simulate_one_insn_backwards (bb, x, live);
-                             bitmap_copy (peep2_insn_data[i].live_before,
-                                          live);
-                           }
-                         x = PREV_INSN (x);
-                       }
-                     while (x != prev);
-
-                     peep2_current = i;
-                   }
+         pos = peep2_buf_position (peep2_current + peep2_current_count);
+         peep2_insn_data[pos].insn = PEEP2_EOB;
+         COPY_REG_SET (peep2_insn_data[pos].live_before, live);
 
-                 /* If we generated a jump instruction, it won't have
-                    JUMP_LABEL set.  Recompute after we're done.  */
-                 for (x = attempt; x != before_try; x = PREV_INSN (x))
-                   if (JUMP_P (x))
-                     {
-                       do_rebuild_jump_labels = true;
-                       break;
-                     }
+         /* Match the peephole.  */
+         head = peep2_insn_data[peep2_current].insn;
+         attempt = peephole2_insns (PATTERN (head), head, &match_len);
+         if (attempt != NULL)
+           {
+             rtx last = peep2_attempt (bb, head, match_len, attempt);
+             if (last)
+               {
+                 peep2_update_life (bb, match_len, last, PREV_INSN (attempt));
+                 continue;
                }
            }
 
-         if (insn == BB_HEAD (bb))
-           break;
+         /* No match: advance the buffer by one insn.  */
+         peep2_current = peep2_buf_position (peep2_current + 1);
+         peep2_current_count--;
        }
     }
 
@@ -3390,7 +3510,7 @@ peephole2_optimize (void)
   for (i = 0; i < MAX_INSNS_PER_PEEP2 + 1; ++i)
     BITMAP_FREE (peep2_insn_data[i].live_before);
   BITMAP_FREE (live);
-  if (do_rebuild_jump_labels)
+  if (peep2_do_rebuild_jump_labels)
     rebuild_jump_labels (get_insns ());
 }
 #endif /* HAVE_peephole2 */