OSDN Git Service

* config/alpha/alpha.c (alpha_emit_floatuns): Ensure we pass a REG
[pf3gnuchains/gcc-fork.git] / gcc / jump.c
index 50a69c5..18303e6 100644 (file)
@@ -1,5 +1,6 @@
 /* Optimize jump instructions, for GNU compiler.
-   Copyright (C) 1987, 88, 89, 91-97, 1998 Free Software Foundation, Inc.
+   Copyright (C) 1987, 1988, 1989, 1991, 1992, 1993, 1994, 1995, 1996, 1997
+   1998, 1999, 2000 Free Software Foundation, Inc.
 
 This file is part of GNU CC.
 
@@ -54,12 +55,15 @@ Boston, MA 02111-1307, USA.  */
 #include "config.h"
 #include "system.h"
 #include "rtl.h"
+#include "tm_p.h"
 #include "flags.h"
 #include "hard-reg-set.h"
 #include "regs.h"
 #include "insn-config.h"
 #include "insn-flags.h"
+#include "insn-attr.h"
 #include "recog.h"
+#include "function.h"
 #include "expr.h"
 #include "real.h"
 #include "except.h"
@@ -88,10 +92,6 @@ Boston, MA 02111-1307, USA.  */
 
 static rtx *jump_chain;
 
-/* List of labels referred to from initializers.
-   These can never be deleted.  */
-rtx forced_labels;
-
 /* Maximum index in jump_chain.  */
 
 static int max_jump_chain;
@@ -108,20 +108,59 @@ int can_reach_end;
 
 static int cross_jump_death_matters = 0;
 
-static int duplicate_loop_exit_test    PROTO((rtx));
-static void find_cross_jump            PROTO((rtx, rtx, int, rtx *, rtx *));
-static void do_cross_jump              PROTO((rtx, rtx, rtx));
-static int jump_back_p                 PROTO((rtx, rtx));
-static int tension_vector_labels       PROTO((rtx, int));
-static void mark_jump_label            PROTO((rtx, rtx, int));
-static void delete_computation         PROTO((rtx));
-static void delete_from_jump_chain     PROTO((rtx));
-static int delete_labelref_insn                PROTO((rtx, rtx, int));
-static void mark_modified_reg          PROTO((rtx, rtx));
-static void redirect_tablejump         PROTO((rtx, rtx));
-#ifndef HAVE_cc0
-static rtx find_insert_position         PROTO((rtx, rtx));
+static int init_label_info             PARAMS ((rtx));
+static void delete_barrier_successors  PARAMS ((rtx));
+static void mark_all_labels            PARAMS ((rtx, int));
+static rtx delete_unreferenced_labels  PARAMS ((rtx));
+static void delete_noop_moves          PARAMS ((rtx));
+static int calculate_can_reach_end     PARAMS ((rtx, int));
+static int duplicate_loop_exit_test    PARAMS ((rtx));
+static void find_cross_jump            PARAMS ((rtx, rtx, int, rtx *, rtx *));
+static void do_cross_jump              PARAMS ((rtx, rtx, rtx));
+static int jump_back_p                 PARAMS ((rtx, rtx));
+static int tension_vector_labels       PARAMS ((rtx, int));
+static void mark_jump_label            PARAMS ((rtx, rtx, int, int));
+static void delete_computation         PARAMS ((rtx));
+static void delete_from_jump_chain     PARAMS ((rtx));
+static int delete_labelref_insn                PARAMS ((rtx, rtx, int));
+static void mark_modified_reg          PARAMS ((rtx, rtx, void *));
+static void redirect_tablejump         PARAMS ((rtx, rtx));
+static void jump_optimize_1            PARAMS ((rtx, int, int, int, int, int));
+#if ! defined(HAVE_cc0) && ! defined(HAVE_conditional_arithmetic)
+static rtx find_insert_position         PARAMS ((rtx, rtx));
 #endif
+static int returnjump_p_1              PARAMS ((rtx *, void *));
+static void delete_prior_computation    PARAMS ((rtx, rtx));
+\f
+/* Main external entry point into the jump optimizer.  See comments before
+   jump_optimize_1 for descriptions of the arguments.  */
+void
+jump_optimize (f, cross_jump, noop_moves, after_regscan)
+     rtx f;
+     int cross_jump;
+     int noop_moves;
+     int after_regscan;
+{
+  jump_optimize_1 (f, cross_jump, noop_moves, after_regscan, 0, 0);
+}
+
+/* Alternate entry into the jump optimizer.  This entry point only rebuilds
+   the JUMP_LABEL field in jumping insns and REG_LABEL notes in non-jumping
+   instructions.  */
+void
+rebuild_jump_labels (f)
+     rtx f;
+{
+  jump_optimize_1 (f, 0, 0, 0, 1, 0);
+}
+
+/* Alternate entry into the jump optimizer.  Do only trivial optimizations.  */
+void
+jump_optimize_minimal (f)
+     rtx f;
+{
+  jump_optimize_1 (f, 0, 0, 0, 0, 1);
+}
 \f
 /* Delete no-op jumps and optimize jumps to jumps
    and jumps around jumps.
@@ -136,104 +175,62 @@ static rtx find_insert_position         PROTO((rtx, rtx));
    If AFTER_REGSCAN is nonzero, then this jump pass is being run immediately
    after regscan, and it is safe to use regno_first_uid and regno_last_uid.
 
+   If MARK_LABELS_ONLY is nonzero, then we only rebuild the jump chain
+   and JUMP_LABEL field for jumping insns.
+
    If `optimize' is zero, don't change any code,
    just determine whether control drops off the end of the function.
    This case occurs when we have -W and not -O.
    It works because `delete_insn' checks the value of `optimize'
-   and refrains from actually deleting when that is 0.  */
+   and refrains from actually deleting when that is 0.
 
-void
-jump_optimize (f, cross_jump, noop_moves, after_regscan)
+   If MINIMAL is nonzero, then we only perform trivial optimizations:
+
+     * Removal of unreachable code after BARRIERs.
+     * Removal of unreferenced CODE_LABELs.
+     * Removal of a jump to the next instruction.
+     * Removal of a conditional jump followed by an unconditional jump
+       to the same target as the conditional jump.
+     * Simplify a conditional jump around an unconditional jump.
+     * Simplify a jump to a jump.
+     * Delete extraneous line number notes.
+  */
+
+static void
+jump_optimize_1 (f, cross_jump, noop_moves, after_regscan,
+                mark_labels_only, minimal)
      rtx f;
      int cross_jump;
      int noop_moves;
      int after_regscan;
+     int mark_labels_only;
+     int minimal;
 {
-  register rtx insn, next, note;
+  register rtx insn, next;
   int changed;
+  int old_max_reg;
   int first = 1;
   int max_uid = 0;
   rtx last_insn;
 
   cross_jump_death_matters = (cross_jump == 2);
+  max_uid = init_label_info (f) + 1;
 
-  /* Initialize LABEL_NUSES and JUMP_LABEL fields.  Delete any REG_LABEL
-     notes whose labels don't occur in the insn any more.  */
-
-  for (insn = f; insn; insn = NEXT_INSN (insn))
-    {
-      if (GET_CODE (insn) == CODE_LABEL)
-       LABEL_NUSES (insn) = (LABEL_PRESERVE_P (insn) != 0);
-      else if (GET_CODE (insn) == JUMP_INSN)
-       JUMP_LABEL (insn) = 0;
-      else if (GET_CODE (insn) == INSN || GET_CODE (insn) == CALL_INSN)
-       for (note = REG_NOTES (insn); note; note = next)
-         {
-           next = XEXP (note, 1);
-           if (REG_NOTE_KIND (note) == REG_LABEL
-               && ! reg_mentioned_p (XEXP (note, 0), PATTERN (insn)))
-             remove_note (insn, note);
-         }
-
-      if (INSN_UID (insn) > max_uid)
-       max_uid = INSN_UID (insn);
-    }
-
-  max_uid++;
-
-  /* Delete insns following barriers, up to next label.  */
+  /* If we are performing cross jump optimizations, then initialize
+     tables mapping UIDs to EH regions to avoid incorrect movement
+     of insns from one EH region to another.  */
+  if (flag_exceptions && cross_jump)
+    init_insn_eh_region (f, max_uid);
 
-  for (insn = f; insn;)
-    {
-      if (GET_CODE (insn) == BARRIER)
-       {
-         insn = NEXT_INSN (insn);
-         while (insn != 0 && GET_CODE (insn) != CODE_LABEL)
-           {
-             if (GET_CODE (insn) == NOTE
-                 && NOTE_LINE_NUMBER (insn) != NOTE_INSN_FUNCTION_END)
-               insn = NEXT_INSN (insn);
-             else
-               insn = delete_insn (insn);
-           }
-         /* INSN is now the code_label.  */
-       }
-      else
-       insn = NEXT_INSN (insn);
-    }
+  if (! mark_labels_only)
+    delete_barrier_successors (f);
 
   /* Leave some extra room for labels and duplicate exit test insns
      we make.  */
   max_jump_chain = max_uid * 14 / 10;
-  jump_chain = (rtx *) alloca (max_jump_chain * sizeof (rtx));
-  bzero ((char *) jump_chain, max_jump_chain * sizeof (rtx));
-
-  /* Mark the label each jump jumps to.
-     Combine consecutive labels, and count uses of labels.
-
-     For each label, make a chain (using `jump_chain')
-     of all the *unconditional* jumps that jump to it;
-     also make a chain of all returns.  */
+  jump_chain = (rtx *) xcalloc (max_jump_chain, sizeof (rtx));
 
-  for (insn = f; insn; insn = NEXT_INSN (insn))
-    if (GET_RTX_CLASS (GET_CODE (insn)) == 'i')
-      {
-       mark_jump_label (PATTERN (insn), insn, cross_jump);
-       if (! INSN_DELETED_P (insn) && GET_CODE (insn) == JUMP_INSN)
-         {
-           if (JUMP_LABEL (insn) != 0 && simplejump_p (insn))
-             {
-               jump_chain[INSN_UID (insn)]
-                 = jump_chain[INSN_UID (JUMP_LABEL (insn))];
-               jump_chain[INSN_UID (JUMP_LABEL (insn))] = insn;
-             }
-           if (GET_CODE (PATTERN (insn)) == RETURN)
-             {
-               jump_chain[INSN_UID (insn)] = jump_chain[0];
-               jump_chain[0] = insn;
-             }
-         }
-      }
+  mark_all_labels (f, cross_jump);
 
   /* Keep track of labels used from static data;
      they cannot ever be deleted.  */
@@ -249,328 +246,25 @@ jump_optimize (f, cross_jump, noop_moves, after_regscan)
   for (insn = exception_handler_labels; insn; insn = XEXP (insn, 1))
     LABEL_NUSES (XEXP (insn, 0))++;
 
-  exception_optimize ();
-
-  /* Delete all labels already not referenced.
-     Also find the last insn.  */
-
-  last_insn = 0;
-  for (insn = f; insn; )
-    {
-      if (GET_CODE (insn) == CODE_LABEL && LABEL_NUSES (insn) == 0)
-       insn = delete_insn (insn);
-      else
-       {
-         last_insn = insn;
-         insn = NEXT_INSN (insn);
-       }
-    }
+  /* Quit now if we just wanted to rebuild the JUMP_LABEL and REG_LABEL
+     notes and recompute LABEL_NUSES.  */
+  if (mark_labels_only)
+    goto end;
 
-  if (!optimize)
-    {
-      /* See if there is still a NOTE_INSN_FUNCTION_END in this function.
-        If so record that this function can drop off the end.  */
-
-      insn = last_insn;
-      {
-       int n_labels = 1;
-       while (insn
-              /* One label can follow the end-note: the return label.  */
-              && ((GET_CODE (insn) == CODE_LABEL && n_labels-- > 0)
-                  /* Ordinary insns can follow it if returning a structure.  */
-                  || GET_CODE (insn) == INSN
-                  /* If machine uses explicit RETURN insns, no epilogue,
-                     then one of them follows the note.  */
-                  || (GET_CODE (insn) == JUMP_INSN
-                      && GET_CODE (PATTERN (insn)) == RETURN)
-                  /* A barrier can follow the return insn.  */
-                  || GET_CODE (insn) == BARRIER
-                  /* Other kinds of notes can follow also.  */
-                  || (GET_CODE (insn) == NOTE
-                      && NOTE_LINE_NUMBER (insn) != NOTE_INSN_FUNCTION_END)))
-         insn = PREV_INSN (insn);
-      }
-
-      /* Report if control can fall through at the end of the function.  */
-      if (insn && GET_CODE (insn) == NOTE
-         && NOTE_LINE_NUMBER (insn) == NOTE_INSN_FUNCTION_END
-         && ! INSN_DELETED_P (insn))
-       can_reach_end = 1;
-
-      /* Zero the "deleted" flag of all the "deleted" insns.  */
-      for (insn = f; insn; insn = NEXT_INSN (insn))
-       INSN_DELETED_P (insn) = 0;
-
-      /* Show that the jump chain is not valid.  */
-      jump_chain = 0;
-      return;
-    }
+  if (! minimal)
+    exception_optimize ();
 
-#ifdef HAVE_return
-  if (HAVE_return)
-    {
-      /* If we fall through to the epilogue, see if we can insert a RETURN insn
-        in front of it.  If the machine allows it at this point (we might be
-        after reload for a leaf routine), it will improve optimization for it
-        to be there.  */
-      insn = get_last_insn ();
-      while (insn && GET_CODE (insn) == NOTE)
-       insn = PREV_INSN (insn);
-
-      if (insn && GET_CODE (insn) != BARRIER)
-       {
-         emit_jump_insn (gen_return ());
-         emit_barrier ();
-       }
-    }
-#endif
+  last_insn = delete_unreferenced_labels (f);
 
   if (noop_moves)
-    for (insn = f; insn; )
-      {
-       next = NEXT_INSN (insn);
-
-       if (GET_CODE (insn) == INSN)
-         {
-           register rtx body = PATTERN (insn);
-
-/* Combine stack_adjusts with following push_insns.  */
-#ifdef PUSH_ROUNDING
-           if (GET_CODE (body) == SET
-               && SET_DEST (body) == stack_pointer_rtx
-               && GET_CODE (SET_SRC (body)) == PLUS
-               && XEXP (SET_SRC (body), 0) == stack_pointer_rtx
-               && GET_CODE (XEXP (SET_SRC (body), 1)) == CONST_INT
-               && INTVAL (XEXP (SET_SRC (body), 1)) > 0)
-             {
-               rtx p;
-               rtx stack_adjust_insn = insn;
-               int stack_adjust_amount = INTVAL (XEXP (SET_SRC (body), 1));
-               int total_pushed = 0;
-               int pushes = 0;
-
-               /* Find all successive push insns.  */
-               p = insn;
-               /* Don't convert more than three pushes;
-                  that starts adding too many displaced addresses
-                  and the whole thing starts becoming a losing
-                  proposition.  */
-               while (pushes < 3)
-                 {
-                   rtx pbody, dest;
-                   p = next_nonnote_insn (p);
-                   if (p == 0 || GET_CODE (p) != INSN)
-                     break;
-                   pbody = PATTERN (p);
-                   if (GET_CODE (pbody) != SET)
-                     break;
-                   dest = SET_DEST (pbody);
-                   /* Allow a no-op move between the adjust and the push.  */
-                   if (GET_CODE (dest) == REG
-                       && GET_CODE (SET_SRC (pbody)) == REG
-                       && REGNO (dest) == REGNO (SET_SRC (pbody)))
-                     continue;
-                   if (! (GET_CODE (dest) == MEM
-                          && GET_CODE (XEXP (dest, 0)) == POST_INC
-                          && XEXP (XEXP (dest, 0), 0) == stack_pointer_rtx))
-                     break;
-                   pushes++;
-                   if (total_pushed + GET_MODE_SIZE (GET_MODE (SET_DEST (pbody)))
-                       > stack_adjust_amount)
-                     break;
-                   total_pushed += GET_MODE_SIZE (GET_MODE (SET_DEST (pbody)));
-                 }
-
-               /* Discard the amount pushed from the stack adjust;
-                  maybe eliminate it entirely.  */
-               if (total_pushed >= stack_adjust_amount)
-                 {
-                   delete_computation (stack_adjust_insn);
-                   total_pushed = stack_adjust_amount;
-                 }
-               else
-                 XEXP (SET_SRC (PATTERN (stack_adjust_insn)), 1)
-                   = GEN_INT (stack_adjust_amount - total_pushed);
-
-               /* Change the appropriate push insns to ordinary stores.  */
-               p = insn;
-               while (total_pushed > 0)
-                 {
-                   rtx pbody, dest;
-                   p = next_nonnote_insn (p);
-                   if (GET_CODE (p) != INSN)
-                     break;
-                   pbody = PATTERN (p);
-                   if (GET_CODE (pbody) == SET)
-                     break;
-                   dest = SET_DEST (pbody);
-                   if (! (GET_CODE (dest) == MEM
-                          && GET_CODE (XEXP (dest, 0)) == POST_INC
-                          && XEXP (XEXP (dest, 0), 0) == stack_pointer_rtx))
-                     break;
-                   total_pushed -= GET_MODE_SIZE (GET_MODE (SET_DEST (pbody)));
-                   /* If this push doesn't fully fit in the space
-                      of the stack adjust that we deleted,
-                      make another stack adjust here for what we
-                      didn't use up.  There should be peepholes
-                      to recognize the resulting sequence of insns.  */
-                   if (total_pushed < 0)
-                     {
-                       emit_insn_before (gen_add2_insn (stack_pointer_rtx,
-                                                        GEN_INT (- total_pushed)),
-                                         p);
-                       break;
-                     }
-                   XEXP (dest, 0)
-                     = plus_constant (stack_pointer_rtx, total_pushed);
-                 }
-             }
-#endif
-
-           /* Detect and delete no-op move instructions
-              resulting from not allocating a parameter in a register.  */
-
-           if (GET_CODE (body) == SET
-               && (SET_DEST (body) == SET_SRC (body)
-                   || (GET_CODE (SET_DEST (body)) == MEM
-                       && GET_CODE (SET_SRC (body)) == MEM
-                       && rtx_equal_p (SET_SRC (body), SET_DEST (body))))
-               && ! (GET_CODE (SET_DEST (body)) == MEM
-                     && MEM_VOLATILE_P (SET_DEST (body)))
-               && ! (GET_CODE (SET_SRC (body)) == MEM
-                     && MEM_VOLATILE_P (SET_SRC (body))))
-             delete_computation (insn);
-
-           /* Detect and ignore no-op move instructions
-              resulting from smart or fortuitous register allocation.  */
-
-           else if (GET_CODE (body) == SET)
-             {
-               int sreg = true_regnum (SET_SRC (body));
-               int dreg = true_regnum (SET_DEST (body));
-
-               if (sreg == dreg && sreg >= 0)
-                 delete_insn (insn);
-               else if (sreg >= 0 && dreg >= 0)
-                 {
-                   rtx trial;
-                   rtx tem = find_equiv_reg (NULL_RTX, insn, 0,
-                                             sreg, NULL_PTR, dreg,
-                                             GET_MODE (SET_SRC (body)));
-
-                   if (tem != 0
-                       && GET_MODE (tem) == GET_MODE (SET_DEST (body)))
-                     {
-                       /* DREG may have been the target of a REG_DEAD note in
-                          the insn which makes INSN redundant.  If so, reorg
-                          would still think it is dead.  So search for such a
-                          note and delete it if we find it.  */
-                       if (! find_regno_note (insn, REG_UNUSED, dreg))
-                         for (trial = prev_nonnote_insn (insn);
-                              trial && GET_CODE (trial) != CODE_LABEL;
-                              trial = prev_nonnote_insn (trial))
-                           if (find_regno_note (trial, REG_DEAD, dreg))
-                             {
-                               remove_death (dreg, trial);
-                               break;
-                             }
-#ifdef PRESERVE_DEATH_INFO_REGNO_P
-                       /* Deleting insn could lose a death-note for SREG
-                          so don't do it if final needs accurate
-                          death-notes.  */
-                       if (PRESERVE_DEATH_INFO_REGNO_P (sreg)
-                           && (trial = find_regno_note (insn, REG_DEAD, sreg)))
-                         {
-                           /* Change this into a USE so that we won't emit
-                              code for it, but still can keep the note.  */
-                           PATTERN (insn)
-                             = gen_rtx_USE (VOIDmode, XEXP (trial, 0));
-                           INSN_CODE (insn) = -1;
-                           /* Remove all reg notes but the REG_DEAD one.  */
-                           REG_NOTES (insn) = trial;
-                           XEXP (trial, 1) = NULL_RTX;
-                         }
-                       else
-#endif
-                         delete_insn (insn);
-                     }
-                 }
-               else if (dreg >= 0 && CONSTANT_P (SET_SRC (body))
-                        && find_equiv_reg (SET_SRC (body), insn, 0, dreg,
-                                           NULL_PTR, 0,
-                                           GET_MODE (SET_DEST (body))))
-                 {
-                   /* This handles the case where we have two consecutive
-                      assignments of the same constant to pseudos that didn't
-                      get a hard reg.  Each SET from the constant will be
-                      converted into a SET of the spill register and an
-                      output reload will be made following it.  This produces
-                      two loads of the same constant into the same spill
-                      register.  */
-
-                   rtx in_insn = insn;
-
-                   /* Look back for a death note for the first reg.
-                      If there is one, it is no longer accurate.  */
-                   while (in_insn && GET_CODE (in_insn) != CODE_LABEL)
-                     {
-                       if ((GET_CODE (in_insn) == INSN
-                            || GET_CODE (in_insn) == JUMP_INSN)
-                           && find_regno_note (in_insn, REG_DEAD, dreg))
-                         {
-                           remove_death (dreg, in_insn);
-                           break;
-                         }
-                       in_insn = PREV_INSN (in_insn);
-                     }
-
-                   /* Delete the second load of the value.  */
-                   delete_insn (insn);
-                 }
-             }
-           else if (GET_CODE (body) == PARALLEL)
-             {
-               /* If each part is a set between two identical registers or
-                  a USE or CLOBBER, delete the insn.  */
-               int i, sreg, dreg;
-               rtx tem;
-
-               for (i = XVECLEN (body, 0) - 1; i >= 0; i--)
-                 {
-                   tem = XVECEXP (body, 0, i);
-                   if (GET_CODE (tem) == USE || GET_CODE (tem) == CLOBBER)
-                     continue;
-
-                   if (GET_CODE (tem) != SET
-                       || (sreg = true_regnum (SET_SRC (tem))) < 0
-                       || (dreg = true_regnum (SET_DEST (tem))) < 0
-                       || dreg != sreg)
-                     break;
-                 }
-                 
-               if (i < 0)
-                 delete_insn (insn);
-             }
-           /* Also delete insns to store bit fields if they are no-ops.  */
-           /* Not worth the hair to detect this in the big-endian case.  */
-           else if (! BYTES_BIG_ENDIAN
-                    && GET_CODE (body) == SET
-                    && GET_CODE (SET_DEST (body)) == ZERO_EXTRACT
-                    && XEXP (SET_DEST (body), 2) == const0_rtx
-                    && XEXP (SET_DEST (body), 0) == SET_SRC (body)
-                    && ! (GET_CODE (SET_SRC (body)) == MEM
-                          && MEM_VOLATILE_P (SET_SRC (body))))
-             delete_insn (insn);
-         }
-      insn = next;
-    }
+    delete_noop_moves (f);
 
   /* If we haven't yet gotten to reload and we have just run regscan,
      delete any insn that sets a register that isn't used elsewhere.
      This helps some of the optimizations below by having less insns
      being jumped around.  */
 
-  if (! reload_completed && after_regscan)
+  if (optimize && ! reload_completed && after_regscan)
     for (insn = f; insn; insn = next)
       {
        rtx set = single_set (insn);
@@ -585,12 +279,18 @@ jump_optimize (f, cross_jump, noop_moves, after_regscan)
               might arrange to use that reg for real.  */             
            && REGNO_LAST_NOTE_UID (REGNO (SET_DEST (set))) == INSN_UID (insn)
            && ! side_effects_p (SET_SRC (set))
-           && ! find_reg_note (insn, REG_RETVAL, 0))
+           && ! find_reg_note (insn, REG_RETVAL, 0)
+           /* An ADDRESSOF expression can turn into a use of the internal arg
+              pointer, so do not delete the initialization of the internal
+              arg pointer yet.  If it is truly dead, flow will delete the
+              initializing insn.  */
+           && SET_DEST (set) != current_function_internal_arg_pointer)
          delete_insn (insn);
       }
 
   /* Now iterate optimizing jumps until nothing changes over one pass.  */
   changed = 1;
+  old_max_reg = max_reg_num ();
   while (changed)
     {
       changed = 0;
@@ -598,23 +298,10 @@ jump_optimize (f, cross_jump, noop_moves, after_regscan)
       for (insn = f; insn; insn = next)
        {
          rtx reallabelprev;
-         rtx temp, temp1, temp2, temp3, temp4, temp5, temp6;
+         rtx temp, temp1, temp2 = NULL_RTX, temp3, temp4, temp5, temp6;
          rtx nlabel;
          int this_is_simplejump, this_is_condjump, reversep = 0;
          int this_is_condjump_in_parallel;
-#if 0
-         /* If NOT the first iteration, if this is the last jump pass
-            (just before final), do the special peephole optimizations.
-            Avoiding the first iteration gives ordinary jump opts
-            a chance to work before peephole opts.  */
-
-         if (reload_completed && !first && !flag_no_peephole)
-           if (GET_CODE (insn) == INSN || GET_CODE (insn) == JUMP_INSN)
-             peephole (insn);
-#endif
-
-         /* That could have deleted some insns after INSN, so check now
-            what the following insn is.  */
 
          next = NEXT_INSN (insn);
 
@@ -650,6 +337,14 @@ jump_optimize (f, cross_jump, noop_moves, after_regscan)
          if (GET_CODE (PATTERN (insn)) == ADDR_DIFF_VEC)
            changed |= tension_vector_labels (PATTERN (insn), 1);
 
+         /* See if this jump goes to another jump and redirect if so.  */
+         nlabel = follow_jumps (JUMP_LABEL (insn));
+         if (nlabel != JUMP_LABEL (insn))
+           changed |= redirect_jump (insn, nlabel);
+
+         if (! optimize || minimal)
+           continue;
+
          /* If a dispatch table always goes to the same place,
             get rid of it and replace the insn that uses it.  */
 
@@ -661,19 +356,23 @@ jump_optimize (f, cross_jump, noop_moves, after_regscan)
              int diff_vec_p = GET_CODE (PATTERN (insn)) == ADDR_DIFF_VEC;
              int len = XVECLEN (pat, diff_vec_p);
              rtx dispatch = prev_real_insn (insn);
+             rtx set;
 
              for (i = 0; i < len; i++)
                if (XEXP (XVECEXP (pat, diff_vec_p, i), 0)
                    != XEXP (XVECEXP (pat, diff_vec_p, 0), 0))
                  break;
+
              if (i == len
                  && dispatch != 0
                  && GET_CODE (dispatch) == JUMP_INSN
                  && JUMP_LABEL (dispatch) != 0
-                 /* Don't mess with a casesi insn.  */
-                 && !(GET_CODE (PATTERN (dispatch)) == SET
-                      && (GET_CODE (SET_SRC (PATTERN (dispatch)))
-                          == IF_THEN_ELSE))
+                 /* Don't mess with a casesi insn. 
+                    XXX according to the comment before computed_jump_p(),
+                    all casesi insns should be a parallel of the jump
+                    and a USE of a LABEL_REF.  */
+                 && ! ((set = single_set (dispatch)) != NULL
+                       && (GET_CODE (SET_SRC (set)) == IF_THEN_ELSE))
                  && next_real_insn (JUMP_LABEL (dispatch)) == insn)
                {
                  redirect_tablejump (dispatch,
@@ -682,18 +381,18 @@ jump_optimize (f, cross_jump, noop_moves, after_regscan)
                }
            }
 
-         reallabelprev = prev_active_insn (JUMP_LABEL (insn));
-
          /* If a jump references the end of the function, try to turn
             it into a RETURN insn, possibly a conditional one.  */
-         if (JUMP_LABEL (insn)
+         if (JUMP_LABEL (insn) != 0
              && (next_active_insn (JUMP_LABEL (insn)) == 0
                  || GET_CODE (PATTERN (next_active_insn (JUMP_LABEL (insn))))
                      == RETURN))
            changed |= redirect_jump (insn, NULL_RTX);
 
+         reallabelprev = prev_active_insn (JUMP_LABEL (insn));
+
          /* Detect jump to following insn.  */
-         if (reallabelprev == insn && condjump_p (insn))
+         if (reallabelprev == insn && this_is_condjump)
            {
              next = next_real_insn (JUMP_LABEL (insn));
              delete_jump (insn);
@@ -701,6 +400,81 @@ jump_optimize (f, cross_jump, noop_moves, after_regscan)
              continue;
            }
 
+         /* Detect a conditional jump going to the same place
+            as an immediately following unconditional jump.  */
+         else if (this_is_condjump
+                  && (temp = next_active_insn (insn)) != 0
+                  && simplejump_p (temp)
+                  && (next_active_insn (JUMP_LABEL (insn))
+                      == next_active_insn (JUMP_LABEL (temp))))
+           {
+             /* Don't mess up test coverage analysis.  */
+             temp2 = temp;
+             if (flag_test_coverage && !reload_completed)
+               for (temp2 = insn; temp2 != temp; temp2 = NEXT_INSN (temp2))
+                 if (GET_CODE (temp2) == NOTE && NOTE_LINE_NUMBER (temp2) > 0)
+                   break;
+                 
+             if (temp2 == temp)
+               {
+                 delete_jump (insn);
+                 changed = 1;
+                 continue;
+               }
+           }
+
+         /* Detect a conditional jump jumping over an unconditional jump.  */
+
+         else if ((this_is_condjump || this_is_condjump_in_parallel)
+                  && ! this_is_simplejump
+                  && reallabelprev != 0
+                  && GET_CODE (reallabelprev) == JUMP_INSN
+                  && prev_active_insn (reallabelprev) == insn
+                  && no_labels_between_p (insn, reallabelprev)
+                  && simplejump_p (reallabelprev))
+           {
+             /* When we invert the unconditional jump, we will be
+                decrementing the usage count of its old label.
+                Make sure that we don't delete it now because that
+                might cause the following code to be deleted.  */
+             rtx prev_uses = prev_nonnote_insn (reallabelprev);
+             rtx prev_label = JUMP_LABEL (insn);
+
+             if (prev_label)
+               ++LABEL_NUSES (prev_label);
+
+             if (invert_jump (insn, JUMP_LABEL (reallabelprev)))
+               {
+                 /* It is very likely that if there are USE insns before
+                    this jump, they hold REG_DEAD notes.  These REG_DEAD
+                    notes are no longer valid due to this optimization,
+                    and will cause the life-analysis that following passes
+                    (notably delayed-branch scheduling) to think that
+                    these registers are dead when they are not.
+
+                    To prevent this trouble, we just remove the USE insns
+                    from the insn chain.  */
+
+                 while (prev_uses && GET_CODE (prev_uses) == INSN
+                        && GET_CODE (PATTERN (prev_uses)) == USE)
+                   {
+                     rtx useless = prev_uses;
+                     prev_uses = prev_nonnote_insn (prev_uses);
+                     delete_insn (useless);
+                   }
+
+                 delete_insn (reallabelprev);
+                 changed = 1;
+               }
+
+             /* We can now safely delete the label if it is unreferenced
+                since the delete_insn above has deleted the BARRIER.  */
+             if (prev_label && --LABEL_NUSES (prev_label) == 0)
+               delete_insn (prev_label);
+
+             next = NEXT_INSN (insn);
+           }
+
          /* If we have an unconditional jump preceded by a USE, try to put
             the USE before the target and jump there.  This simplifies many
             of the optimizations below since we don't have to worry about
@@ -708,21 +482,22 @@ jump_optimize (f, cross_jump, noop_moves, after_regscan)
             being branch to already has the identical USE or if code
             never falls through to that label.  */
 
-         if (this_is_simplejump
-             && (temp = prev_nonnote_insn (insn)) != 0
-             && GET_CODE (temp) == INSN && GET_CODE (PATTERN (temp)) == USE
-             && (temp1 = prev_nonnote_insn (JUMP_LABEL (insn))) != 0
-             && (GET_CODE (temp1) == BARRIER
-                 || (GET_CODE (temp1) == INSN
-                     && rtx_equal_p (PATTERN (temp), PATTERN (temp1))))
-             /* Don't do this optimization if we have a loop containing only
-                the USE instruction, and the loop start label has a usage
-                count of 1.  This is because we will redo this optimization
-                everytime through the outer loop, and jump opt will never
-                exit.  */
-             && ! ((temp2 = prev_nonnote_insn (temp)) != 0
-                   && temp2 == JUMP_LABEL (insn)
-                   && LABEL_NUSES (temp2) == 1))
+         else if (this_is_simplejump
+                  && (temp = prev_nonnote_insn (insn)) != 0
+                  && GET_CODE (temp) == INSN
+                  && GET_CODE (PATTERN (temp)) == USE
+                  && (temp1 = prev_nonnote_insn (JUMP_LABEL (insn))) != 0
+                  && (GET_CODE (temp1) == BARRIER
+                      || (GET_CODE (temp1) == INSN
+                          && rtx_equal_p (PATTERN (temp), PATTERN (temp1))))
+                  /* Don't do this optimization if we have a loop containing
+                     only the USE instruction, and the loop start label has
+                     a usage count of 1.  This is because we will redo this
+                     optimization everytime through the outer loop, and jump
+                     opt will never exit.  */
+                  && ! ((temp2 = prev_nonnote_insn (temp)) != 0
+                        && temp2 == JUMP_LABEL (insn)
+                        && LABEL_NUSES (temp2) == 1))
            {
              if (GET_CODE (temp1) == BARRIER)
                {
@@ -734,6 +509,7 @@ jump_optimize (f, cross_jump, noop_moves, after_regscan)
              redirect_jump (insn, get_label_before (temp1));
              reallabelprev = prev_real_insn (temp1);
              changed = 1;
+             next = NEXT_INSN (insn);
            }
 
          /* Simplify   if (...) x = a; else x = b; by converting it
@@ -847,7 +623,12 @@ jump_optimize (f, cross_jump, noop_moves, after_regscan)
                  && ! reg_referenced_between_p (temp1, p, NEXT_INSN (temp3))
                  && ! reg_set_between_p (temp1, p, temp3)
                  && (GET_CODE (SET_SRC (temp4)) == CONST_INT
-                     || ! modified_between_p (SET_SRC (temp4), p, temp2)))
+                     || ! modified_between_p (SET_SRC (temp4), p, temp2))
+                 /* Verify that registers used by the jump are not clobbered
+                    by the instruction being moved.  */
+                 && ! regs_set_between_p (PATTERN (temp),
+                                          PREV_INSN (temp2),
+                                          NEXT_INSN (temp2)))
                {
                  emit_insn_after_with_line_notes (PATTERN (temp2), p, temp2);
                  delete_insn (temp2);
@@ -870,6 +651,7 @@ jump_optimize (f, cross_jump, noop_moves, after_regscan)
                      redirect_jump (p, target);
 
                  changed = 1;
+                 next = NEXT_INSN (insn);
                  continue;
                }
            }
@@ -945,6 +727,11 @@ jump_optimize (f, cross_jump, noop_moves, after_regscan)
                                                 NEXT_INSN (temp2))
                  && ! reg_set_between_p (temp1, insert_after, temp)
                  && ! modified_between_p (SET_SRC (temp4), insert_after, temp)
+                 /* Verify that registers used by the jump are not clobbered
+                    by the instruction being moved.  */
+                 && ! regs_set_between_p (PATTERN (temp),
+                                          PREV_INSN (temp3),
+                                          NEXT_INSN (temp3))
                  && invert_jump (temp, JUMP_LABEL (insn)))
                {
                  emit_insn_after_with_line_notes (PATTERN (temp3),
@@ -961,7 +748,8 @@ jump_optimize (f, cross_jump, noop_moves, after_regscan)
                continue;
            }
 
-#ifndef HAVE_cc0
+#if !defined(HAVE_cc0) && !defined(HAVE_conditional_arithmetic)
+
          /* If we have if (...) x = exp;  and branches are expensive,
             EXP is a single insn, does not have any side effects, cannot
             trap, and is not too costly, convert this to
@@ -972,10 +760,14 @@ jump_optimize (f, cross_jump, noop_moves, after_regscan)
             the potential for conflicts.  We also can't do this when we have
             notes on the insn for the same reason as above.
 
+            If we have conditional arithmetic, this will make this
+            harder to optimize later and isn't needed, so don't do it
+            in that case either.
+
             We set:
 
             TEMP to the "x = exp;" insn.
-            TEMP1 to the single set in the "x = exp; insn.
+            TEMP1 to the single set in the "x = exp;" insn.
             TEMP2 to "x".  */
 
          if (! reload_completed
@@ -1009,6 +801,12 @@ jump_optimize (f, cross_jump, noop_moves, after_regscan)
                                                   PREV_INSN (temp3), temp);
                  delete_insn (temp);
                  reallabelprev = prev_active_insn (JUMP_LABEL (insn));
+
+                 if (after_regscan)
+                   {
+                     reg_scan_update (temp3, NEXT_INSN (next), old_max_reg);
+                     old_max_reg = max_reg_num ();
+                   }
                }
            }
 
@@ -1061,6 +859,12 @@ jump_optimize (f, cross_jump, noop_moves, after_regscan)
                  delete_insn (temp);
                  delete_insn (temp3);
                  reallabelprev = prev_active_insn (JUMP_LABEL (insn));
+
+                 if (after_regscan)
+                   {
+                     reg_scan_update (temp6, NEXT_INSN (next), old_max_reg);
+                     old_max_reg = max_reg_num ();
+                   }
                }
            }
 
@@ -1121,12 +925,321 @@ jump_optimize (f, cross_jump, noop_moves, after_regscan)
                  delete_insn (temp);
                  delete_insn (temp3);
                  reallabelprev = prev_active_insn (JUMP_LABEL (insn));
-               }
+
+                 if (after_regscan)
+                   {
+                     reg_scan_update (temp6, NEXT_INSN (next), old_max_reg);
+                     old_max_reg = max_reg_num ();
+                   }
+               }
            }
 #endif /* HAVE_cc0 */
 
+#ifdef HAVE_conditional_arithmetic
+         /* ??? This is disabled in genconfig, as this simple-minded
+            transformation can incredibly lengthen register lifetimes.
+
+            Consider this example from cexp.c's yyparse:
+
+               234 (set (pc)
+                     (if_then_else (ne (reg:DI 149) (const_int 0 [0x0]))
+                       (label_ref 248) (pc)))
+               237 (set (reg/i:DI 0 $0) (const_int 1 [0x1]))
+               239 (set (pc) (label_ref 2382))
+               248 (code_label ("yybackup"))
+
+            This will be transformed to:
+
+               237 (set (reg/i:DI 0 $0)
+                     (if_then_else:DI (eq (reg:DI 149) (const_int 0 [0x0]))
+                       (const_int 1 [0x1]) (reg/i:DI 0 $0)))
+               239 (set (pc)
+                     (if_then_else (eq (reg:DI 149) (const_int 0 [0x0]))
+                       (label_ref 2382) (pc)))
+
+            which, from this narrow viewpoint looks fine.  Except that
+            between this and 3 other ocurrences of the same pattern, $0
+            is now live for basically the entire function, and we'll 
+            get an abort in caller_save.
+
+            Any replacement for this code should recall that a set of
+            a register that is not live need not, and indeed should not,
+            be conditionalized.  Either that, or delay the transformation
+            until after register allocation.  */
+
+         /* See if this is a conditional jump around a small number of
+            instructions that we can conditionalize.  Don't do this before
+            the initial CSE pass or after reload.
+
+            We reject any insns that have side effects or may trap.
+            Strictly speaking, this is not needed since the machine may
+            support conditionalizing these too, but we won't deal with that
+            now.  Specifically, this means that we can't conditionalize a 
+            CALL_INSN, which some machines, such as the ARC, can do, but
+            this is a very minor optimization.  */
+         if (this_is_condjump && ! this_is_simplejump
+             && cse_not_expected && ! reload_completed
+             && BRANCH_COST > 2
+             && can_reverse_comparison_p (XEXP (SET_SRC (PATTERN (insn)), 0),
+                                          insn))
+           {
+             rtx ourcond = XEXP (SET_SRC (PATTERN (insn)), 0);
+             int num_insns = 0;
+             char *storage = (char *) oballoc (0);
+             int last_insn = 0, failed = 0;
+             rtx changed_jump = 0;
+
+             ourcond = gen_rtx (reverse_condition (GET_CODE (ourcond)),
+                                VOIDmode, XEXP (ourcond, 0),
+                                XEXP (ourcond, 1));
+
+             /* Scan forward BRANCH_COST real insns looking for the JUMP_LABEL
+                of this insn.  We see if we think we can conditionalize the
+                insns we pass.  For now, we only deal with insns that have
+                one SET.  We stop after an insn that modifies anything in
+                OURCOND, if we have too many insns, or if we have an insn
+                with a side effect or that may trip.  Note that we will
+                be modifying any unconditional jumps we encounter to be
+                conditional; this will have the effect of also doing this
+                optimization on the "else" the next time around.  */
+             for (temp1 = NEXT_INSN (insn);
+                  num_insns <= BRANCH_COST && ! failed && temp1 != 0
+                  && GET_CODE (temp1) != CODE_LABEL;
+                  temp1 = NEXT_INSN (temp1))
+               {
+                 /* Ignore everything but an active insn.  */
+                 if (GET_RTX_CLASS (GET_CODE (temp1)) != 'i'
+                     || GET_CODE (PATTERN (temp1)) == USE
+                     || GET_CODE (PATTERN (temp1)) == CLOBBER)
+                   continue;
+
+                 /* If this was an unconditional jump, record it since we'll
+                    need to remove the BARRIER if we succeed.  We can only
+                    have one such jump since there must be a label after
+                    the BARRIER and it's either ours, in which case it's the
+                    only one or some other, in which case we'd fail.
+                    Likewise if it's a CALL_INSN followed by a BARRIER.  */
+
+                 if (simplejump_p (temp1)
+                     || (GET_CODE (temp1) == CALL_INSN
+                         && NEXT_INSN (temp1) != 0
+                         && GET_CODE (NEXT_INSN (temp1)) == BARRIER))
+                   {
+                     if (changed_jump == 0)
+                       changed_jump = temp1;
+                     else
+                       changed_jump
+                         = gen_rtx_INSN_LIST (VOIDmode, temp1, changed_jump);
+                   }
+
+                 /* See if we are allowed another insn and if this insn
+                    if one we think we may be able to handle.  */
+                 if (++num_insns > BRANCH_COST
+                     || last_insn
+                     || (((temp2 = single_set (temp1)) == 0
+                          || side_effects_p (SET_SRC (temp2))
+                          || may_trap_p (SET_SRC (temp2)))
+                         && GET_CODE (temp1) != CALL_INSN))
+                     failed = 1;
+                 else if (temp2 != 0)
+                   validate_change (temp1, &SET_SRC (temp2),
+                                    gen_rtx_IF_THEN_ELSE
+                                    (GET_MODE (SET_DEST (temp2)),
+                                     copy_rtx (ourcond),
+                                     SET_SRC (temp2), SET_DEST (temp2)),
+                                    1);
+                 else
+                   {
+                     /* This is a CALL_INSN that doesn't have a SET.  */
+                     rtx *call_loc = &PATTERN (temp1);
+
+                     if (GET_CODE (*call_loc) == PARALLEL)
+                       call_loc = &XVECEXP (*call_loc, 0, 0);
+
+                     validate_change (temp1, call_loc,
+                                      gen_rtx_IF_THEN_ELSE
+                                      (VOIDmode, copy_rtx (ourcond),
+                                       *call_loc, const0_rtx),
+                                      1);
+                   }
+
+
+                 if (modified_in_p (ourcond, temp1))
+                   last_insn = 1;
+               }
+
+             /* If we've reached our jump label, haven't failed, and all
+                the changes above are valid, we can delete this jump
+                insn.  Also remove a BARRIER after any jump that used
+                to be unconditional and remove any REG_EQUAL or REG_EQUIV
+                that might have previously been present on insns we
+                made conditional.  */
+             if (temp1 == JUMP_LABEL (insn) && ! failed
+                 && apply_change_group ())
+               {
+                 for (temp1 = NEXT_INSN (insn); temp1 != JUMP_LABEL (insn);
+                      temp1 = NEXT_INSN (temp1))
+                   if (GET_RTX_CLASS (GET_CODE (temp1)) == 'i')
+                     for (temp2 = REG_NOTES (temp1); temp2 != 0;
+                          temp2 = XEXP (temp2, 1))
+                       if (REG_NOTE_KIND (temp2) == REG_EQUAL
+                           || REG_NOTE_KIND (temp2) == REG_EQUIV)
+                         remove_note (temp1, temp2);
+
+                 if (changed_jump != 0)
+                   {
+                     while (GET_CODE (changed_jump) == INSN_LIST)
+                       {
+                         delete_barrier (NEXT_INSN (XEXP (changed_jump, 0)));
+                         changed_jump = XEXP (changed_jump, 1);
+                       }
+
+                     delete_barrier (NEXT_INSN (changed_jump));
+                   }
+
+                 delete_insn (insn);
+                 changed = 1;
+                 continue;
+               }
+             else
+               {
+                 cancel_changes (0);
+                 obfree (storage);
+               }
+           }
+#endif
+         /* If branches are expensive, convert
+               if (foo) bar++;    to    bar += (foo != 0);
+            and similarly for "bar--;" 
+
+            INSN is the conditional branch around the arithmetic.  We set:
+
+            TEMP is the arithmetic insn.
+            TEMP1 is the SET doing the arithmetic.
+            TEMP2 is the operand being incremented or decremented.
+            TEMP3 to the condition being tested.
+            TEMP4 to the earliest insn used to find the condition.  */
+
+         if ((BRANCH_COST >= 2
+#ifdef HAVE_incscc
+              || HAVE_incscc
+#endif
+#ifdef HAVE_decscc
+              || HAVE_decscc
+#endif
+             )
+             && ! reload_completed
+             && this_is_condjump && ! this_is_simplejump
+             && (temp = next_nonnote_insn (insn)) != 0
+             && (temp1 = single_set (temp)) != 0
+             && (temp2 = SET_DEST (temp1),
+                 GET_MODE_CLASS (GET_MODE (temp2)) == MODE_INT)
+             && GET_CODE (SET_SRC (temp1)) == PLUS
+             && (XEXP (SET_SRC (temp1), 1) == const1_rtx
+                 || XEXP (SET_SRC (temp1), 1) == constm1_rtx)
+             && rtx_equal_p (temp2, XEXP (SET_SRC (temp1), 0))
+             && ! side_effects_p (temp2)
+             && ! may_trap_p (temp2)
+             /* INSN must either branch to the insn after TEMP or the insn
+                after TEMP must branch to the same place as INSN.  */
+             && (reallabelprev == temp
+                 || ((temp3 = next_active_insn (temp)) != 0
+                     && simplejump_p (temp3)
+                     && JUMP_LABEL (temp3) == JUMP_LABEL (insn)))
+             && (temp3 = get_condition (insn, &temp4)) != 0
+             /* We must be comparing objects whose modes imply the size.
+                We could handle BLKmode if (1) emit_store_flag could
+                and (2) we could find the size reliably.  */
+             && GET_MODE (XEXP (temp3, 0)) != BLKmode
+             && can_reverse_comparison_p (temp3, insn))
+           {
+             rtx temp6, target = 0, seq, init_insn = 0, init = temp2;
+             enum rtx_code code = reverse_condition (GET_CODE (temp3));
+
+             start_sequence ();
+
+             /* It must be the case that TEMP2 is not modified in the range
+                [TEMP4, INSN).  The one exception we make is if the insn
+                before INSN sets TEMP2 to something which is also unchanged
+                in that range.  In that case, we can move the initialization
+                into our sequence.  */
+
+             if ((temp5 = prev_active_insn (insn)) != 0
+                 && no_labels_between_p (temp5, insn)
+                 && GET_CODE (temp5) == INSN
+                 && (temp6 = single_set (temp5)) != 0
+                 && rtx_equal_p (temp2, SET_DEST (temp6))
+                 && (CONSTANT_P (SET_SRC (temp6))
+                     || GET_CODE (SET_SRC (temp6)) == REG
+                     || GET_CODE (SET_SRC (temp6)) == SUBREG))
+               {
+                 emit_insn (PATTERN (temp5));
+                 init_insn = temp5;
+                 init = SET_SRC (temp6);
+               }
+
+             if (CONSTANT_P (init)
+                 || ! reg_set_between_p (init, PREV_INSN (temp4), insn))
+               target = emit_store_flag (gen_reg_rtx (GET_MODE (temp2)), code,
+                                         XEXP (temp3, 0), XEXP (temp3, 1),
+                                         VOIDmode,
+                                         (code == LTU || code == LEU
+                                          || code == GTU || code == GEU), 1);
+
+             /* If we can do the store-flag, do the addition or
+                subtraction.  */
+
+             if (target)
+               target = expand_binop (GET_MODE (temp2),
+                                      (XEXP (SET_SRC (temp1), 1) == const1_rtx
+                                       ? add_optab : sub_optab),
+                                      temp2, target, temp2, 0, OPTAB_WIDEN);
+
+             if (target != 0)
+               {
+                 /* Put the result back in temp2 in case it isn't already.
+                    Then replace the jump, possible a CC0-setting insn in
+                    front of the jump, and TEMP, with the sequence we have
+                    made.  */
+
+                 if (target != temp2)
+                   emit_move_insn (temp2, target);
+
+                 seq = get_insns ();
+                 end_sequence ();
+
+                 emit_insns_before (seq, temp4);
+                 delete_insn (temp);
+
+                 if (init_insn)
+                   delete_insn (init_insn);
+
+                 next = NEXT_INSN (insn);
+#ifdef HAVE_cc0
+                 delete_insn (prev_nonnote_insn (insn));
+#endif
+                 delete_insn (insn);
+
+                 if (after_regscan)
+                   {
+                     reg_scan_update (seq, NEXT_INSN (next), old_max_reg);
+                     old_max_reg = max_reg_num ();
+                   }
+
+                 changed = 1;
+                 continue;
+               }
+             else
+               end_sequence ();
+           }
+
          /* Try to use a conditional move (if the target has them), or a
-            store-flag insn.  The general case is:
+            store-flag insn.  If the target has conditional arithmetic as
+            well as conditional move, the above code will have done something.
+            Note that we prefer the above code since it is more general: the
+            code below can make changes that require work to undo.
+
+            The general case here is:
 
             1) x = a; if (...) x = b; and
             2) if (...) x = b;
@@ -1139,24 +1252,30 @@ jump_optimize (f, cross_jump, noop_moves, after_regscan)
 
             INSN here is the jump around the store.  We set:
 
-            TEMP to the "x = b;" insn.
+            TEMP to the "x op= b;" insn.
             TEMP1 to X.
             TEMP2 to B.
             TEMP3 to A (X in the second case).
             TEMP4 to the condition being tested.
-            TEMP5 to the earliest insn used to find the condition.  */
+            TEMP5 to the earliest insn used to find the condition.
+            TEMP6 to the SET of TEMP.  */
 
          if (/* We can't do this after reload has completed.  */
              ! reload_completed
+#ifdef HAVE_conditional_arithmetic
+             /* Defer this until after CSE so the above code gets the
+                first crack at it.  */
+             && cse_not_expected
+#endif
              && this_is_condjump && ! this_is_simplejump
              /* Set TEMP to the "x = b;" insn.  */
              && (temp = next_nonnote_insn (insn)) != 0
              && GET_CODE (temp) == INSN
-             && GET_CODE (PATTERN (temp)) == SET
-             && GET_CODE (temp1 = SET_DEST (PATTERN (temp))) == REG
+             && (temp6 = single_set (temp)) != NULL_RTX
+             && GET_CODE (temp1 = SET_DEST (temp6)) == REG
              && (! SMALL_REGISTER_CLASSES
                  || REGNO (temp1) >= FIRST_PSEUDO_REGISTER)
-             && ! side_effects_p (temp2 = SET_SRC (PATTERN (temp)))
+             && ! side_effects_p (temp2 = SET_SRC (temp6))
              && ! may_trap_p (temp2)
              /* Allow either form, but prefer the former if both apply. 
                 There is no point in using the old value of TEMP1 if
@@ -1201,7 +1320,7 @@ jump_optimize (f, cross_jump, noop_moves, after_regscan)
                enum rtx_code code = GET_CODE (temp4);
                rtx var = temp1;
                rtx cond0, cond1, aval, bval;
-               rtx target;
+               rtx target, new_insn;
 
                /* Copy the compared variables into cond0 and cond1, so that
                   any side effects performed in or after the old comparison,
@@ -1210,20 +1329,44 @@ jump_optimize (f, cross_jump, noop_moves, after_regscan)
                   insn?  After all, we're going to delete it.  We'd have
                   to modify emit_conditional_move to take a comparison rtx
                   instead or write a new function.  */
-               cond0 = gen_reg_rtx (GET_MODE (XEXP (temp4, 0)));
+
                /* We want the target to be able to simplify comparisons with
                   zero (and maybe other constants as well), so don't create
                   pseudos for them.  There's no need to either.  */
+               if (GET_CODE (XEXP (temp4, 0)) == CONST_INT
+                   || GET_CODE (XEXP (temp4, 0)) == CONST_DOUBLE)
+                 cond0 = XEXP (temp4, 0);
+               else
+                 cond0 = gen_reg_rtx (GET_MODE (XEXP (temp4, 0)));
+
                if (GET_CODE (XEXP (temp4, 1)) == CONST_INT
                    || GET_CODE (XEXP (temp4, 1)) == CONST_DOUBLE)
                  cond1 = XEXP (temp4, 1);
                else
                  cond1 = gen_reg_rtx (GET_MODE (XEXP (temp4, 1)));
 
+               /* Careful about copying these values -- an IOR or what may
+                  need to do other things, like clobber flags.  */
+               /* ??? Assume for the moment that AVAL is ok.  */
                aval = temp3;
-               bval = temp2;
 
                start_sequence ();
+
+               /* We're dealing with a single_set insn with no side effects
+                  on SET_SRC.  We do need to be reasonably certain that if
+                  we need to force BVAL into a register that we won't 
+                  clobber the flags -- general_operand should suffice.  */
+               if (general_operand (temp2, GET_MODE (var)))
+                 bval = temp2;
+               else
+                 {
+                   bval = gen_reg_rtx (GET_MODE (var));
+                   new_insn = copy_rtx (temp);
+                   temp6 = single_set (new_insn);
+                   SET_DEST (temp6) = bval;
+                   emit_insn (PATTERN (new_insn));
+                 }
+
                target = emit_conditional_move (var, code,
                                                cond0, cond1, VOIDmode,
                                                aval, bval, GET_MODE (var),
@@ -1232,7 +1375,8 @@ jump_optimize (f, cross_jump, noop_moves, after_regscan)
 
                if (target)
                  {
-                   rtx seq1,seq2;
+                   rtx seq1, seq2, last;
+                   int copy_ok;
 
                    /* Save the conditional move sequence but don't emit it
                       yet.  On some machines, like the alpha, it is possible
@@ -1242,8 +1386,9 @@ jump_optimize (f, cross_jump, noop_moves, after_regscan)
                    seq2 = get_insns ();
                    end_sequence ();
 
-                   /* Now that we can't fail, generate the copy insns that
-                      preserve the compared values.  */
+                   /* "Now that we can't fail..."  Famous last words.
+                      Generate the copy insns that preserve the compared
+                      values.  */
                    start_sequence ();
                    emit_move_insn (cond0, XEXP (temp4, 0));
                    if (cond1 != XEXP (temp4, 1))
@@ -1251,18 +1396,42 @@ jump_optimize (f, cross_jump, noop_moves, after_regscan)
                    seq1 = get_insns ();
                    end_sequence ();
 
-                   emit_insns_before (seq1, temp5);
-                   /* Insert conditional move after insn, to be sure that
-                      the jump and a possible compare won't be separated */
-                   emit_insns_after (seq2, insn);
-
-                   /* ??? We can also delete the insn that sets X to A.
-                      Flow will do it too though.  */
-                   delete_insn (temp);
-                   next = NEXT_INSN (insn);
-                   delete_jump (insn);
-                   changed = 1;
-                   continue;
+                   /* Validate the sequence -- this may be some weird
+                      bit-extract-and-test instruction for which there
+                      exists no complimentary bit-extract insn.  */
+                   copy_ok = 1;
+                   for (last = seq1; last ; last = NEXT_INSN (last))
+                     if (recog_memoized (last) < 0)
+                       {
+                         copy_ok = 0;
+                         break;
+                       }
+
+                   if (copy_ok)
+                     {
+                       emit_insns_before (seq1, temp5);
+
+                       /* Insert conditional move after insn, to be sure
+                          that the jump and a possible compare won't be
+                          separated.  */
+                       last = emit_insns_after (seq2, insn);
+
+                       /* ??? We can also delete the insn that sets X to A.
+                          Flow will do it too though.  */
+                       delete_insn (temp);
+                       next = NEXT_INSN (insn);
+                       delete_jump (insn);
+
+                       if (after_regscan)
+                         {
+                           reg_scan_update (seq1, NEXT_INSN (last),
+                                            old_max_reg);
+                           old_max_reg = max_reg_num ();
+                         }
+
+                       changed = 1;
+                       continue;
+                     }
                  }
                else
                  end_sequence ();
@@ -1282,6 +1451,9 @@ jump_optimize (f, cross_jump, noop_moves, after_regscan)
                 5) if (...) x = b; if jumps are even more expensive.  */
 
              if (GET_MODE_CLASS (GET_MODE (temp1)) == MODE_INT
+                 /* We will be passing this as operand into expand_and.  No
+                    good if it's not valid as an operand.  */
+                 && general_operand (temp2, GET_MODE (temp2))
                  && ((GET_CODE (temp3) == CONST_INT)
                      /* Make the latter case look like
                         x = x; if (...) x = 0;  */
@@ -1299,11 +1471,13 @@ jump_optimize (f, cross_jump, noop_moves, after_regscan)
                         /* Check that the mask is a power of two,
                            so that it can probably be generated
                            with a shift.  */
+                           && GET_CODE (temp3) == CONST_INT
                            && exact_log2 (INTVAL (temp3)) >= 0))
                       && (reversep = 0, temp2 == const0_rtx))
                      || ((BRANCH_COST >= 2
                           || STORE_FLAG_VALUE == -1
                           || (STORE_FLAG_VALUE == 1
+                              && GET_CODE (temp2) == CONST_INT
                               && exact_log2 (INTVAL (temp2)) >= 0))
                          && temp3 == const0_rtx
                          && (reversep = can_reverse_comparison_p (temp4, insn)))
@@ -1441,6 +1615,13 @@ jump_optimize (f, cross_jump, noop_moves, after_regscan)
                      delete_insn (temp);
                      next = NEXT_INSN (insn);
                      delete_jump (insn);
+
+                     if (after_regscan)
+                       {
+                         reg_scan_update (seq, NEXT_INSN (next), old_max_reg);
+                         old_max_reg = max_reg_num ();
+                       }
+
                      changed = 1;
                      continue;
                    }
@@ -1449,149 +1630,32 @@ jump_optimize (f, cross_jump, noop_moves, after_regscan)
                }
            }
 
-         /* If branches are expensive, convert
-               if (foo) bar++;    to    bar += (foo != 0);
-            and similarly for "bar--;" 
 
-            INSN is the conditional branch around the arithmetic.  We set:
+         /* Simplify   if (...) x = 1; else {...}  if (x) ...
+            We recognize this case scanning backwards as well.
 
-            TEMP is the arithmetic insn.
-            TEMP1 is the SET doing the arithmetic.
-            TEMP2 is the operand being incremented or decremented.
-            TEMP3 to the condition being tested.
-            TEMP4 to the earliest insn used to find the condition.  */
+            TEMP is the assignment to x;
+            TEMP1 is the label at the head of the second if.  */
+         /* ?? This should call get_condition to find the values being
+            compared, instead of looking for a COMPARE insn when HAVE_cc0
+            is not defined.  This would allow it to work on the m88k.  */
+         /* ?? This optimization is only safe before cse is run if HAVE_cc0
+            is not defined and the condition is tested by a separate compare
+            insn.  This is because the code below assumes that the result
+            of the compare dies in the following branch.
 
-         if ((BRANCH_COST >= 2
-#ifdef HAVE_incscc
-              || HAVE_incscc
-#endif
-#ifdef HAVE_decscc
-              || HAVE_decscc
-#endif
-             )
-             && ! reload_completed
-             && this_is_condjump && ! this_is_simplejump
-             && (temp = next_nonnote_insn (insn)) != 0
-             && (temp1 = single_set (temp)) != 0
-             && (temp2 = SET_DEST (temp1),
-                 GET_MODE_CLASS (GET_MODE (temp2)) == MODE_INT)
-             && GET_CODE (SET_SRC (temp1)) == PLUS
-             && (XEXP (SET_SRC (temp1), 1) == const1_rtx
-                 || XEXP (SET_SRC (temp1), 1) == constm1_rtx)
-             && rtx_equal_p (temp2, XEXP (SET_SRC (temp1), 0))
-             && ! side_effects_p (temp2)
-             && ! may_trap_p (temp2)
-             /* INSN must either branch to the insn after TEMP or the insn
-                after TEMP must branch to the same place as INSN.  */
-             && (reallabelprev == temp
-                 || ((temp3 = next_active_insn (temp)) != 0
-                     && simplejump_p (temp3)
-                     && JUMP_LABEL (temp3) == JUMP_LABEL (insn)))
-             && (temp3 = get_condition (insn, &temp4)) != 0
-             /* We must be comparing objects whose modes imply the size.
-                We could handle BLKmode if (1) emit_store_flag could
-                and (2) we could find the size reliably.  */
-             && GET_MODE (XEXP (temp3, 0)) != BLKmode
-             && can_reverse_comparison_p (temp3, insn))
-           {
-             rtx temp6, target = 0, seq, init_insn = 0, init = temp2;
-             enum rtx_code code = reverse_condition (GET_CODE (temp3));
+            Not only that, but there might be other insns between the
+            compare and branch whose results are live.  Those insns need
+            to be executed.
 
-             start_sequence ();
+            A way to fix this is to move the insns at JUMP_LABEL (insn)
+            to before INSN.  If we are running before flow, they will
+            be deleted if they aren't needed.   But this doesn't work
+            well after flow.
 
-             /* It must be the case that TEMP2 is not modified in the range
-                [TEMP4, INSN).  The one exception we make is if the insn
-                before INSN sets TEMP2 to something which is also unchanged
-                in that range.  In that case, we can move the initialization
-                into our sequence.  */
-
-             if ((temp5 = prev_active_insn (insn)) != 0
-                 && no_labels_between_p (temp5, insn)
-                 && GET_CODE (temp5) == INSN
-                 && (temp6 = single_set (temp5)) != 0
-                 && rtx_equal_p (temp2, SET_DEST (temp6))
-                 && (CONSTANT_P (SET_SRC (temp6))
-                     || GET_CODE (SET_SRC (temp6)) == REG
-                     || GET_CODE (SET_SRC (temp6)) == SUBREG))
-               {
-                 emit_insn (PATTERN (temp5));
-                 init_insn = temp5;
-                 init = SET_SRC (temp6);
-               }
-
-             if (CONSTANT_P (init)
-                 || ! reg_set_between_p (init, PREV_INSN (temp4), insn))
-               target = emit_store_flag (gen_reg_rtx (GET_MODE (temp2)), code,
-                                         XEXP (temp3, 0), XEXP (temp3, 1),
-                                         VOIDmode,
-                                         (code == LTU || code == LEU
-                                          || code == GTU || code == GEU), 1);
-
-             /* If we can do the store-flag, do the addition or
-                subtraction.  */
-
-             if (target)
-               target = expand_binop (GET_MODE (temp2),
-                                      (XEXP (SET_SRC (temp1), 1) == const1_rtx
-                                       ? add_optab : sub_optab),
-                                      temp2, target, temp2, 0, OPTAB_WIDEN);
-
-             if (target != 0)
-               {
-                 /* Put the result back in temp2 in case it isn't already.
-                    Then replace the jump, possible a CC0-setting insn in
-                    front of the jump, and TEMP, with the sequence we have
-                    made.  */
-
-                 if (target != temp2)
-                   emit_move_insn (temp2, target);
-
-                 seq = get_insns ();
-                 end_sequence ();
-
-                 emit_insns_before (seq, temp4);
-                 delete_insn (temp);
-
-                 if (init_insn)
-                   delete_insn (init_insn);
-
-                 next = NEXT_INSN (insn);
-#ifdef HAVE_cc0
-                 delete_insn (prev_nonnote_insn (insn));
-#endif
-                 delete_insn (insn);
-                 changed = 1;
-                 continue;
-               }
-             else
-               end_sequence ();
-           }
-
-         /* Simplify   if (...) x = 1; else {...}  if (x) ...
-            We recognize this case scanning backwards as well.
-
-            TEMP is the assignment to x;
-            TEMP1 is the label at the head of the second if.  */
-         /* ?? This should call get_condition to find the values being
-            compared, instead of looking for a COMPARE insn when HAVE_cc0
-            is not defined.  This would allow it to work on the m88k.  */
-         /* ?? This optimization is only safe before cse is run if HAVE_cc0
-            is not defined and the condition is tested by a separate compare
-            insn.  This is because the code below assumes that the result
-            of the compare dies in the following branch.
-
-            Not only that, but there might be other insns between the
-            compare and branch whose results are live.  Those insns need
-            to be executed.
-
-            A way to fix this is to move the insns at JUMP_LABEL (insn)
-            to before INSN.  If we are running before flow, they will
-            be deleted if they aren't needed.   But this doesn't work
-            well after flow.
-
-            This is really a special-case of jump threading, anyway.  The
-            right thing to do is to replace this and jump threading with
-            much simpler code in cse.
+            This is really a special-case of jump threading, anyway.  The
+            right thing to do is to replace this and jump threading with
+            much simpler code in cse.
 
             This code has been turned off in the non-cc0 case in the
             meantime.  */
@@ -1867,30 +1931,6 @@ jump_optimize (f, cross_jump, noop_moves, after_regscan)
                }
            }
 #endif
-         /* Detect a conditional jump going to the same place
-            as an immediately following unconditional jump.  */
-         else if (this_is_condjump
-                  && (temp = next_active_insn (insn)) != 0
-                  && simplejump_p (temp)
-                  && (next_active_insn (JUMP_LABEL (insn))
-                      == next_active_insn (JUMP_LABEL (temp))))
-           {
-             rtx tem = temp;
-
-             /* ??? Optional.  Disables some optimizations, but makes
-                gcov output more accurate with -O.  */
-             if (flag_test_coverage && !reload_completed)
-               for (tem = insn; tem != temp; tem = NEXT_INSN (tem))
-                 if (GET_CODE (tem) == NOTE && NOTE_LINE_NUMBER (tem) > 0)
-                   break;
-
-             if (tem == temp)
-               {
-                 delete_jump (insn);
-                 changed = 1;
-                 continue;
-               }
-           }
 #ifdef HAVE_trap
          /* Detect a conditional jump jumping over an unconditional trap.  */
          else if (HAVE_trap
@@ -1964,389 +2004,532 @@ jump_optimize (f, cross_jump, noop_moves, after_regscan)
                }
            }
 #endif
+         else
+           {
+             /* Now that the jump has been tensioned,
+                try cross jumping: check for identical code
+                before the jump and before its target label.  */
 
-         /* Detect a conditional jump jumping over an unconditional jump.  */
+             /* First, cross jumping of conditional jumps:  */
 
-         else if ((this_is_condjump || this_is_condjump_in_parallel)
-                  && ! this_is_simplejump
-                  && reallabelprev != 0
-                  && GET_CODE (reallabelprev) == JUMP_INSN
-                  && prev_active_insn (reallabelprev) == insn
-                  && no_labels_between_p (insn, reallabelprev)
-                  && simplejump_p (reallabelprev))
-           {
-             /* When we invert the unconditional jump, we will be
-                decrementing the usage count of its old label.
-                Make sure that we don't delete it now because that
-                might cause the following code to be deleted.  */
-             rtx prev_uses = prev_nonnote_insn (reallabelprev);
-             rtx prev_label = JUMP_LABEL (insn);
+             if (cross_jump && condjump_p (insn))
+               {
+                 rtx newjpos, newlpos;
+                 rtx x = prev_real_insn (JUMP_LABEL (insn));
 
-             if (prev_label)
-               ++LABEL_NUSES (prev_label);
+                 /* A conditional jump may be crossjumped
+                    only if the place it jumps to follows
+                    an opposing jump that comes back here.  */
 
-             if (invert_jump (insn, JUMP_LABEL (reallabelprev)))
+                 if (x != 0 && ! jump_back_p (x, insn))
+                   /* We have no opposing jump;
+                      cannot cross jump this insn.  */
+                   x = 0;
+
+                 newjpos = 0;
+                 /* TARGET is nonzero if it is ok to cross jump
+                    to code before TARGET.  If so, see if matches.  */
+                 if (x != 0)
+                   find_cross_jump (insn, x, 2,
+                                    &newjpos, &newlpos);
+
+                 if (newjpos != 0)
+                   {
+                     do_cross_jump (insn, newjpos, newlpos);
+                     /* Make the old conditional jump
+                        into an unconditional one.  */
+                     SET_SRC (PATTERN (insn))
+                       = gen_rtx_LABEL_REF (VOIDmode, JUMP_LABEL (insn));
+                     INSN_CODE (insn) = -1;
+                     emit_barrier_after (insn);
+                     /* Add to jump_chain unless this is a new label
+                        whose UID is too large.  */
+                     if (INSN_UID (JUMP_LABEL (insn)) < max_jump_chain)
+                       {
+                         jump_chain[INSN_UID (insn)]
+                           = jump_chain[INSN_UID (JUMP_LABEL (insn))];
+                         jump_chain[INSN_UID (JUMP_LABEL (insn))] = insn;
+                       }
+                     changed = 1;
+                     next = insn;
+                   }
+               }
+
+             /* Cross jumping of unconditional jumps:
+                a few differences.  */
+
+             if (cross_jump && simplejump_p (insn))
                {
-                 /* It is very likely that if there are USE insns before
-                    this jump, they hold REG_DEAD notes.  These REG_DEAD
-                    notes are no longer valid due to this optimization,
-                    and will cause the life-analysis that following passes
-                    (notably delayed-branch scheduling) to think that
-                    these registers are dead when they are not.
+                 rtx newjpos, newlpos;
+                 rtx target;
 
-                    To prevent this trouble, we just remove the USE insns
-                    from the insn chain.  */
+                 newjpos = 0;
 
-                 while (prev_uses && GET_CODE (prev_uses) == INSN
-                        && GET_CODE (PATTERN (prev_uses)) == USE)
+                 /* TARGET is nonzero if it is ok to cross jump
+                    to code before TARGET.  If so, see if matches.  */
+                 find_cross_jump (insn, JUMP_LABEL (insn), 1,
+                                  &newjpos, &newlpos);
+
+                 /* If cannot cross jump to code before the label,
+                    see if we can cross jump to another jump to
+                    the same label.  */
+                 /* Try each other jump to this label.  */
+                 if (INSN_UID (JUMP_LABEL (insn)) < max_uid)
+                   for (target = jump_chain[INSN_UID (JUMP_LABEL (insn))];
+                        target != 0 && newjpos == 0;
+                        target = jump_chain[INSN_UID (target)])
+                     if (target != insn
+                         && JUMP_LABEL (target) == JUMP_LABEL (insn)
+                         /* Ignore TARGET if it's deleted.  */
+                         && ! INSN_DELETED_P (target))
+                       find_cross_jump (insn, target, 2,
+                                        &newjpos, &newlpos);
+
+                 if (newjpos != 0)
                    {
-                     rtx useless = prev_uses;
-                     prev_uses = prev_nonnote_insn (prev_uses);
-                     delete_insn (useless);
+                     do_cross_jump (insn, newjpos, newlpos);
+                     changed = 1;
+                     next = insn;
                    }
+               }
 
-                 delete_insn (reallabelprev);
-                 next = insn;
-                 changed = 1;
+             /* This code was dead in the previous jump.c!  */
+             if (cross_jump && GET_CODE (PATTERN (insn)) == RETURN)
+               {
+                 /* Return insns all "jump to the same place"
+                    so we can cross-jump between any two of them.  */
+
+                 rtx newjpos, newlpos, target;
+
+                 newjpos = 0;
+
+                 /* If cannot cross jump to code before the label,
+                    see if we can cross jump to another jump to
+                    the same label.  */
+                 /* Try each other jump to this label.  */
+                 for (target = jump_chain[0];
+                      target != 0 && newjpos == 0;
+                      target = jump_chain[INSN_UID (target)])
+                   if (target != insn
+                       && ! INSN_DELETED_P (target)
+                       && GET_CODE (PATTERN (target)) == RETURN)
+                     find_cross_jump (insn, target, 2,
+                                      &newjpos, &newlpos);
+
+                 if (newjpos != 0)
+                   {
+                     do_cross_jump (insn, newjpos, newlpos);
+                     changed = 1;
+                     next = insn;
+                   }
                }
+           }
+       }
 
-             /* We can now safely delete the label if it is unreferenced
-                since the delete_insn above has deleted the BARRIER.  */
-             if (prev_label && --LABEL_NUSES (prev_label) == 0)
-               delete_insn (prev_label);
+      first = 0;
+    }
+
+  /* Delete extraneous line number notes.
+     Note that two consecutive notes for different lines are not really
+     extraneous.  There should be some indication where that line belonged,
+     even if it became empty.  */
+
+  {
+    rtx last_note = 0;
+
+    for (insn = f; insn; insn = NEXT_INSN (insn))
+      if (GET_CODE (insn) == NOTE && NOTE_LINE_NUMBER (insn) >= 0)
+       {
+         /* Delete this note if it is identical to previous note.  */
+         if (last_note
+             && NOTE_SOURCE_FILE (insn) == NOTE_SOURCE_FILE (last_note)
+             && NOTE_LINE_NUMBER (insn) == NOTE_LINE_NUMBER (last_note))
+           {
+             delete_insn (insn);
              continue;
            }
-         else
+
+         last_note = insn;
+       }
+  }
+
+  /* CAN_REACH_END is persistent for each function.  Once set it should
+     not be cleared.  This is especially true for the case where we
+     delete the NOTE_FUNCTION_END note.  CAN_REACH_END is cleared by
+     the front-end before compiling each function.  */
+  if (! minimal && calculate_can_reach_end (last_insn, optimize != 0))
+    can_reach_end = 1;
+
+end:
+  /* Clean up.  */
+  free (jump_chain);
+  jump_chain = 0;
+}
+\f
+/* Initialize LABEL_NUSES and JUMP_LABEL fields.  Delete any REG_LABEL
+   notes whose labels don't occur in the insn any more.  Returns the
+   largest INSN_UID found.  */
+static int
+init_label_info (f)
+     rtx f;
+{
+  int largest_uid = 0;
+  rtx insn;
+
+  for (insn = f; insn; insn = NEXT_INSN (insn))
+    {
+      if (GET_CODE (insn) == CODE_LABEL)
+       LABEL_NUSES (insn) = (LABEL_PRESERVE_P (insn) != 0);
+      else if (GET_CODE (insn) == JUMP_INSN)
+       JUMP_LABEL (insn) = 0;
+      else if (GET_CODE (insn) == INSN || GET_CODE (insn) == CALL_INSN)
+       {
+         rtx note, next;
+
+         for (note = REG_NOTES (insn); note; note = next)
            {
-             /* Detect a jump to a jump.  */
+             next = XEXP (note, 1);
+             if (REG_NOTE_KIND (note) == REG_LABEL
+                 && ! reg_mentioned_p (XEXP (note, 0), PATTERN (insn)))
+               remove_note (insn, note);
+           }
+       }
+      if (INSN_UID (insn) > largest_uid)
+       largest_uid = INSN_UID (insn);
+    }
 
-             nlabel = follow_jumps (JUMP_LABEL (insn));
-             if (nlabel != JUMP_LABEL (insn)
-                 && redirect_jump (insn, nlabel))
-               {
-                 changed = 1;
-                 next = insn;
-               }
+  return largest_uid;
+}
+
+/* Delete insns following barriers, up to next label. 
+
+   Also delete no-op jumps created by gcse.  */
+
+static void
+delete_barrier_successors (f)
+     rtx f;
+{
+  rtx insn;
+
+  for (insn = f; insn;)
+    {
+      if (GET_CODE (insn) == BARRIER)
+       {
+         insn = NEXT_INSN (insn);
+
+         never_reached_warning (insn);
+
+         while (insn != 0 && GET_CODE (insn) != CODE_LABEL)
+           {
+             if (GET_CODE (insn) == NOTE
+                 && NOTE_LINE_NUMBER (insn) != NOTE_INSN_FUNCTION_END)
+               insn = NEXT_INSN (insn);
+             else
+               insn = delete_insn (insn);
+           }
+         /* INSN is now the code_label.  */
+       }
+
+      /* Also remove (set (pc) (pc)) insns which can be created by
+        gcse.  We eliminate such insns now to avoid having them
+        cause problems later.  */
+      else if (GET_CODE (insn) == JUMP_INSN
+              && GET_CODE (PATTERN (insn)) == SET
+              && SET_SRC (PATTERN (insn)) == pc_rtx
+              && SET_DEST (PATTERN (insn)) == pc_rtx)
+       insn = delete_insn (insn);
+
+      else
+       insn = NEXT_INSN (insn);
+    }
+}
 
-             /* Look for   if (foo) bar; else break;  */
-             /* The insns look like this:
-                insn = condjump label1;
-                ...range1 (some insns)...
-                jump label2;
-                label1:
-                ...range2 (some insns)...
-                jump somewhere unconditionally
-                label2:  */
+/* Mark the label each jump jumps to.
+   Combine consecutive labels, and count uses of labels.
+
+   For each label, make a chain (using `jump_chain')
+   of all the *unconditional* jumps that jump to it;
+   also make a chain of all returns.
+
+   CROSS_JUMP indicates whether we are doing cross jumping
+   and if we are whether we will be paying attention to
+   death notes or not.  */
+
+static void
+mark_all_labels (f, cross_jump)
+     rtx f;
+     int cross_jump;
+{
+  rtx insn;
+
+  for (insn = f; insn; insn = NEXT_INSN (insn))
+    if (GET_RTX_CLASS (GET_CODE (insn)) == 'i')
+      {
+       if (GET_CODE (insn) == CALL_INSN
+           && GET_CODE (PATTERN (insn)) == CALL_PLACEHOLDER)
+         {
+           mark_all_labels (XEXP (PATTERN (insn), 0), cross_jump);
+           mark_all_labels (XEXP (PATTERN (insn), 1), cross_jump);
+           mark_all_labels (XEXP (PATTERN (insn), 2), cross_jump);
+           continue;
+         }
+       
+       mark_jump_label (PATTERN (insn), insn, cross_jump, 0);
+       if (! INSN_DELETED_P (insn) && GET_CODE (insn) == JUMP_INSN)
+         {
+           if (JUMP_LABEL (insn) != 0 && simplejump_p (insn))
              {
-               rtx label1 = next_label (insn);
-               rtx range1end = label1 ? prev_active_insn (label1) : 0;
-               /* Don't do this optimization on the first round, so that
-                  jump-around-a-jump gets simplified before we ask here
-                  whether a jump is unconditional.
-
-                  Also don't do it when we are called after reload since
-                  it will confuse reorg.  */
-               if (! first
-                   && (reload_completed ? ! flag_delayed_branch : 1)
-                   /* Make sure INSN is something we can invert.  */
-                   && condjump_p (insn)
-                   && label1 != 0
-                   && JUMP_LABEL (insn) == label1
-                   && LABEL_NUSES (label1) == 1
-                   && GET_CODE (range1end) == JUMP_INSN
-                   && simplejump_p (range1end))
-                 {
-                   rtx label2 = next_label (label1);
-                   rtx range2end = label2 ? prev_active_insn (label2) : 0;
-                   if (range1end != range2end
-                       && JUMP_LABEL (range1end) == label2
-                       && GET_CODE (range2end) == JUMP_INSN
-                       && GET_CODE (NEXT_INSN (range2end)) == BARRIER
-                       /* Invert the jump condition, so we
-                          still execute the same insns in each case.  */
-                       && invert_jump (insn, label1))
-                     {
-                       rtx range1beg = next_active_insn (insn);
-                       rtx range2beg = next_active_insn (label1);
-                       rtx range1after, range2after;
-                       rtx range1before, range2before;
-                       rtx rangenext;
-
-                       /* Include in each range any notes before it, to be
-                          sure that we get the line number note if any, even
-                          if there are other notes here.  */
-                       while (PREV_INSN (range1beg)
-                              && GET_CODE (PREV_INSN (range1beg)) == NOTE)
-                         range1beg = PREV_INSN (range1beg);
-
-                       while (PREV_INSN (range2beg)
-                              && GET_CODE (PREV_INSN (range2beg)) == NOTE)
-                         range2beg = PREV_INSN (range2beg);
-
-                       /* Don't move NOTEs for blocks or loops; shift them
-                          outside the ranges, where they'll stay put.  */
-                       range1beg = squeeze_notes (range1beg, range1end);
-                       range2beg = squeeze_notes (range2beg, range2end);
-
-                       /* Get current surrounds of the 2 ranges.  */
-                       range1before = PREV_INSN (range1beg);
-                       range2before = PREV_INSN (range2beg);
-                       range1after = NEXT_INSN (range1end);
-                       range2after = NEXT_INSN (range2end);
-
-                       /* Splice range2 where range1 was.  */
-                       NEXT_INSN (range1before) = range2beg;
-                       PREV_INSN (range2beg) = range1before;
-                       NEXT_INSN (range2end) = range1after;
-                       PREV_INSN (range1after) = range2end;
-                       /* Splice range1 where range2 was.  */
-                       NEXT_INSN (range2before) = range1beg;
-                       PREV_INSN (range1beg) = range2before;
-                       NEXT_INSN (range1end) = range2after;
-                       PREV_INSN (range2after) = range1end;
-
-                       /* Check for a loop end note between the end of
-                          range2, and the next code label.  If there is one,
-                          then what we have really seen is
-                          if (foo) break; end_of_loop;
-                          and moved the break sequence outside the loop.
-                          We must move the LOOP_END note to where the
-                          loop really ends now, or we will confuse loop
-                          optimization.  Stop if we find a LOOP_BEG note
-                          first, since we don't want to move the LOOP_END
-                          note in that case.  */
-                       for (;range2after != label2; range2after = rangenext)
-                         {
-                           rangenext = NEXT_INSN (range2after);
-                           if (GET_CODE (range2after) == NOTE)
-                             {
-                               if (NOTE_LINE_NUMBER (range2after)
-                                   == NOTE_INSN_LOOP_END)
-                                 {
-                                   NEXT_INSN (PREV_INSN (range2after))
-                                     = rangenext;
-                                   PREV_INSN (rangenext)
-                                     = PREV_INSN (range2after);
-                                   PREV_INSN (range2after) 
-                                     = PREV_INSN (range1beg);
-                                   NEXT_INSN (range2after) = range1beg;
-                                   NEXT_INSN (PREV_INSN (range1beg))
-                                     = range2after;
-                                   PREV_INSN (range1beg) = range2after;
-                                 }
-                               else if (NOTE_LINE_NUMBER (range2after)
-                                        == NOTE_INSN_LOOP_BEG)
-                                 break;
-                             }
-                         }
-                       changed = 1;
-                       continue;
-                     }
-                 }
+               jump_chain[INSN_UID (insn)]
+                 = jump_chain[INSN_UID (JUMP_LABEL (insn))];
+               jump_chain[INSN_UID (JUMP_LABEL (insn))] = insn;
+             }
+           if (GET_CODE (PATTERN (insn)) == RETURN)
+             {
+               jump_chain[INSN_UID (insn)] = jump_chain[0];
+               jump_chain[0] = insn;
              }
+         }
+      }
+}
+
+/* Delete all labels already not referenced.
+   Also find and return the last insn.  */
+
+static rtx
+delete_unreferenced_labels (f)
+     rtx f;
+{
+  rtx final = NULL_RTX;
+  rtx insn;
+
+  for (insn = f; insn; )
+    {
+      if (GET_CODE (insn) == CODE_LABEL
+          && LABEL_NUSES (insn) == 0
+          && LABEL_ALTERNATE_NAME (insn) == NULL)
+       insn = delete_insn (insn);
+      else
+       {
+         final = insn;
+         insn = NEXT_INSN (insn);
+       }
+    }
 
-             /* Now that the jump has been tensioned,
-                try cross jumping: check for identical code
-                before the jump and before its target label.  */
+  return final;
+}
 
-             /* First, cross jumping of conditional jumps:  */
+/* Delete various simple forms of moves which have no necessary
+   side effect.  */
 
-             if (cross_jump && condjump_p (insn))
-               {
-                 rtx newjpos, newlpos;
-                 rtx x = prev_real_insn (JUMP_LABEL (insn));
+static void
+delete_noop_moves (f)
+     rtx f;
+{
+  rtx insn, next;
 
-                 /* A conditional jump may be crossjumped
-                    only if the place it jumps to follows
-                    an opposing jump that comes back here.  */
+  for (insn = f; insn; )
+    {
+      next = NEXT_INSN (insn);
 
-                 if (x != 0 && ! jump_back_p (x, insn))
-                   /* We have no opposing jump;
-                      cannot cross jump this insn.  */
-                   x = 0;
+      if (GET_CODE (insn) == INSN)
+       {
+         register rtx body = PATTERN (insn);
+
+         /* Detect and delete no-op move instructions
+            resulting from not allocating a parameter in a register.  */
+
+         if (GET_CODE (body) == SET
+             && (SET_DEST (body) == SET_SRC (body)
+                 || (GET_CODE (SET_DEST (body)) == MEM
+                     && GET_CODE (SET_SRC (body)) == MEM
+                     && rtx_equal_p (SET_SRC (body), SET_DEST (body))))
+             && ! (GET_CODE (SET_DEST (body)) == MEM
+                   && MEM_VOLATILE_P (SET_DEST (body)))
+             && ! (GET_CODE (SET_SRC (body)) == MEM
+                   && MEM_VOLATILE_P (SET_SRC (body))))
+           delete_computation (insn);
+
+         /* Detect and ignore no-op move instructions
+            resulting from smart or fortuitous register allocation.  */
+
+         else if (GET_CODE (body) == SET)
+           {
+             int sreg = true_regnum (SET_SRC (body));
+             int dreg = true_regnum (SET_DEST (body));
 
-                 newjpos = 0;
-                 /* TARGET is nonzero if it is ok to cross jump
-                    to code before TARGET.  If so, see if matches.  */
-                 if (x != 0)
-                   find_cross_jump (insn, x, 2,
-                                    &newjpos, &newlpos);
+             if (sreg == dreg && sreg >= 0)
+               delete_insn (insn);
+             else if (sreg >= 0 && dreg >= 0)
+               {
+                 rtx trial;
+                 rtx tem = find_equiv_reg (NULL_RTX, insn, 0,
+                                           sreg, NULL_PTR, dreg,
+                                           GET_MODE (SET_SRC (body)));
 
-                 if (newjpos != 0)
+                 if (tem != 0
+                     && GET_MODE (tem) == GET_MODE (SET_DEST (body)))
                    {
-                     do_cross_jump (insn, newjpos, newlpos);
-                     /* Make the old conditional jump
-                        into an unconditional one.  */
-                     SET_SRC (PATTERN (insn))
-                       = gen_rtx_LABEL_REF (VOIDmode, JUMP_LABEL (insn));
-                     INSN_CODE (insn) = -1;
-                     emit_barrier_after (insn);
-                     /* Add to jump_chain unless this is a new label
-                        whose UID is too large.  */
-                     if (INSN_UID (JUMP_LABEL (insn)) < max_jump_chain)
+                     /* DREG may have been the target of a REG_DEAD note in
+                        the insn which makes INSN redundant.  If so, reorg
+                        would still think it is dead.  So search for such a
+                        note and delete it if we find it.  */
+                     if (! find_regno_note (insn, REG_UNUSED, dreg))
+                       for (trial = prev_nonnote_insn (insn);
+                            trial && GET_CODE (trial) != CODE_LABEL;
+                            trial = prev_nonnote_insn (trial))
+                         if (find_regno_note (trial, REG_DEAD, dreg))
+                           {
+                             remove_death (dreg, trial);
+                             break;
+                           }
+
+                     /* Deleting insn could lose a death-note for SREG.  */
+                     if ((trial = find_regno_note (insn, REG_DEAD, sreg)))
                        {
-                         jump_chain[INSN_UID (insn)]
-                           = jump_chain[INSN_UID (JUMP_LABEL (insn))];
-                         jump_chain[INSN_UID (JUMP_LABEL (insn))] = insn;
+                         /* Change this into a USE so that we won't emit
+                            code for it, but still can keep the note.  */
+                         PATTERN (insn)
+                           = gen_rtx_USE (VOIDmode, XEXP (trial, 0));
+                         INSN_CODE (insn) = -1;
+                         /* Remove all reg notes but the REG_DEAD one.  */
+                         REG_NOTES (insn) = trial;
+                         XEXP (trial, 1) = NULL_RTX;
                        }
-                     changed = 1;
-                     next = insn;
+                     else
+                       delete_insn (insn);
                    }
                }
-
-             /* Cross jumping of unconditional jumps:
-                a few differences.  */
-
-             if (cross_jump && simplejump_p (insn))
+             else if (dreg >= 0 && CONSTANT_P (SET_SRC (body))
+                      && find_equiv_reg (SET_SRC (body), insn, 0, dreg,
+                                         NULL_PTR, 0,
+                                         GET_MODE (SET_DEST (body))))
                {
-                 rtx newjpos, newlpos;
-                 rtx target;
-
-                 newjpos = 0;
-
-                 /* TARGET is nonzero if it is ok to cross jump
-                    to code before TARGET.  If so, see if matches.  */
-                 find_cross_jump (insn, JUMP_LABEL (insn), 1,
-                                  &newjpos, &newlpos);
-
-                 /* If cannot cross jump to code before the label,
-                    see if we can cross jump to another jump to
-                    the same label.  */
-                 /* Try each other jump to this label.  */
-                 if (INSN_UID (JUMP_LABEL (insn)) < max_uid)
-                   for (target = jump_chain[INSN_UID (JUMP_LABEL (insn))];
-                        target != 0 && newjpos == 0;
-                        target = jump_chain[INSN_UID (target)])
-                     if (target != insn
-                         && JUMP_LABEL (target) == JUMP_LABEL (insn)
-                         /* Ignore TARGET if it's deleted.  */
-                         && ! INSN_DELETED_P (target))
-                       find_cross_jump (insn, target, 2,
-                                        &newjpos, &newlpos);
-
-                 if (newjpos != 0)
+                 /* This handles the case where we have two consecutive
+                    assignments of the same constant to pseudos that didn't
+                    get a hard reg.  Each SET from the constant will be
+                    converted into a SET of the spill register and an
+                    output reload will be made following it.  This produces
+                    two loads of the same constant into the same spill
+                    register.  */
+
+                 rtx in_insn = insn;
+
+                 /* Look back for a death note for the first reg.
+                    If there is one, it is no longer accurate.  */
+                 while (in_insn && GET_CODE (in_insn) != CODE_LABEL)
                    {
-                     do_cross_jump (insn, newjpos, newlpos);
-                     changed = 1;
-                     next = insn;
+                     if ((GET_CODE (in_insn) == INSN
+                          || GET_CODE (in_insn) == JUMP_INSN)
+                         && find_regno_note (in_insn, REG_DEAD, dreg))
+                       {
+                         remove_death (dreg, in_insn);
+                         break;
+                       }
+                     in_insn = PREV_INSN (in_insn);
                    }
+
+                 /* Delete the second load of the value.  */
+                 delete_insn (insn);
                }
+           }
+         else if (GET_CODE (body) == PARALLEL)
+           {
+             /* If each part is a set between two identical registers or
+                a USE or CLOBBER, delete the insn.  */
+             int i, sreg, dreg;
+             rtx tem;
 
-             /* This code was dead in the previous jump.c!  */
-             if (cross_jump && GET_CODE (PATTERN (insn)) == RETURN)
+             for (i = XVECLEN (body, 0) - 1; i >= 0; i--)
                {
-                 /* Return insns all "jump to the same place"
-                    so we can cross-jump between any two of them.  */
-
-                 rtx newjpos, newlpos, target;
-
-                 newjpos = 0;
-
-                 /* If cannot cross jump to code before the label,
-                    see if we can cross jump to another jump to
-                    the same label.  */
-                 /* Try each other jump to this label.  */
-                 for (target = jump_chain[0];
-                      target != 0 && newjpos == 0;
-                      target = jump_chain[INSN_UID (target)])
-                   if (target != insn
-                       && ! INSN_DELETED_P (target)
-                       && GET_CODE (PATTERN (target)) == RETURN)
-                     find_cross_jump (insn, target, 2,
-                                      &newjpos, &newlpos);
+                 tem = XVECEXP (body, 0, i);
+                 if (GET_CODE (tem) == USE || GET_CODE (tem) == CLOBBER)
+                   continue;
 
-                 if (newjpos != 0)
-                   {
-                     do_cross_jump (insn, newjpos, newlpos);
-                     changed = 1;
-                     next = insn;
-                   }
+                 if (GET_CODE (tem) != SET
+                     || (sreg = true_regnum (SET_SRC (tem))) < 0
+                     || (dreg = true_regnum (SET_DEST (tem))) < 0
+                     || dreg != sreg)
+                   break;
                }
+                 
+             if (i < 0)
+               delete_insn (insn);
            }
+         /* Also delete insns to store bit fields if they are no-ops.  */
+         /* Not worth the hair to detect this in the big-endian case.  */
+         else if (! BYTES_BIG_ENDIAN
+                  && GET_CODE (body) == SET
+                  && GET_CODE (SET_DEST (body)) == ZERO_EXTRACT
+                  && XEXP (SET_DEST (body), 2) == const0_rtx
+                  && XEXP (SET_DEST (body), 0) == SET_SRC (body)
+                  && ! (GET_CODE (SET_SRC (body)) == MEM
+                        && MEM_VOLATILE_P (SET_SRC (body))))
+           delete_insn (insn);
        }
-
-      first = 0;
+      insn = next;
     }
+}
 
-  /* Delete extraneous line number notes.
-     Note that two consecutive notes for different lines are not really
-     extraneous.  There should be some indication where that line belonged,
-     even if it became empty.  */
+/* See if there is still a NOTE_INSN_FUNCTION_END in this function.
+   If so indicate that this function can drop off the end by returning
+   1, else return 0.
 
-  {
-    rtx last_note = 0;
+   CHECK_DELETED indicates whether we must check if the note being
+   searched for has the deleted flag set.
 
-    for (insn = f; insn; insn = NEXT_INSN (insn))
-      if (GET_CODE (insn) == NOTE && NOTE_LINE_NUMBER (insn) >= 0)
-       {
-         /* Delete this note if it is identical to previous note.  */
-         if (last_note
-             && NOTE_SOURCE_FILE (insn) == NOTE_SOURCE_FILE (last_note)
-             && NOTE_LINE_NUMBER (insn) == NOTE_LINE_NUMBER (last_note))
-           {
-             delete_insn (insn);
-             continue;
-           }
+   DELETE_FINAL_NOTE indicates whether we should delete the note
+   if we find it.  */
 
-         last_note = insn;
-       }
-  }
+static int
+calculate_can_reach_end (last, delete_final_note)
+     rtx last;
+     int delete_final_note;
+{
+  rtx insn = last;
+  int n_labels = 1;
 
-#ifdef HAVE_return
-  if (HAVE_return)
+  while (insn != NULL_RTX)
     {
-      /* If we fall through to the epilogue, see if we can insert a RETURN insn
-        in front of it.  If the machine allows it at this point (we might be
-        after reload for a leaf routine), it will improve optimization for it
-        to be there.  We do this both here and at the start of this pass since
-        the RETURN might have been deleted by some of our optimizations.  */
-      insn = get_last_insn ();
-      while (insn && GET_CODE (insn) == NOTE)
-       insn = PREV_INSN (insn);
-
-      if (insn && GET_CODE (insn) != BARRIER)
-       {
-         emit_jump_insn (gen_return ());
-         emit_barrier ();
-       }
-    }
-#endif
-
-  /* See if there is still a NOTE_INSN_FUNCTION_END in this function.
-     If so, delete it, and record that this function can drop off the end.  */
+      int ok = 0;
+
+      /* One label can follow the end-note: the return label.  */
+      if (GET_CODE (insn) == CODE_LABEL && n_labels-- > 0)
+       ok = 1;
+      /* Ordinary insns can follow it if returning a structure.  */
+      else if (GET_CODE (insn) == INSN)
+       ok = 1;
+      /* If machine uses explicit RETURN insns, no epilogue,
+        then one of them follows the note.  */
+      else if (GET_CODE (insn) == JUMP_INSN
+              && GET_CODE (PATTERN (insn)) == RETURN)
+       ok = 1;
+      /* A barrier can follow the return insn.  */
+      else if (GET_CODE (insn) == BARRIER)
+       ok = 1;
+      /* Other kinds of notes can follow also.  */
+      else if (GET_CODE (insn) == NOTE
+              && NOTE_LINE_NUMBER (insn) != NOTE_INSN_FUNCTION_END)
+       ok = 1;
+
+      if (ok != 1)
+       break;
 
-  insn = last_insn;
-  {
-    int n_labels = 1;
-    while (insn
-          /* One label can follow the end-note: the return label.  */
-          && ((GET_CODE (insn) == CODE_LABEL && n_labels-- > 0)
-              /* Ordinary insns can follow it if returning a structure.  */
-              || GET_CODE (insn) == INSN
-              /* If machine uses explicit RETURN insns, no epilogue,
-                 then one of them follows the note.  */
-              || (GET_CODE (insn) == JUMP_INSN
-                  && GET_CODE (PATTERN (insn)) == RETURN)
-              /* A barrier can follow the return insn.  */
-              || GET_CODE (insn) == BARRIER
-              /* Other kinds of notes can follow also.  */
-              || (GET_CODE (insn) == NOTE
-                  && NOTE_LINE_NUMBER (insn) != NOTE_INSN_FUNCTION_END)))
       insn = PREV_INSN (insn);
-  }
+    }
 
-  /* Report if control can fall through at the end of the function.  */
-  if (insn && GET_CODE (insn) == NOTE
+  /* See if we backed up to the appropriate type of note.  */
+  if (insn != NULL_RTX
+      && GET_CODE (insn) == NOTE
       && NOTE_LINE_NUMBER (insn) == NOTE_INSN_FUNCTION_END)
     {
-      can_reach_end = 1;
-      delete_insn (insn);
+      if (delete_final_note)
+       delete_insn (insn);
+      return 1;
     }
 
-  /* Show JUMP_CHAIN no longer valid.  */
-  jump_chain = 0;
+  return 0;
 }
-\f
+
 /* LOOP_START is a NOTE_INSN_LOOP_BEG note that is followed by an unconditional
    jump.  Assume that this unconditional jump is to the exit test code.  If
    the code is sufficiently simple, make a copy of it before INSN,
@@ -2363,7 +2546,7 @@ duplicate_loop_exit_test (loop_start)
      rtx loop_start;
 {
   rtx insn, set, reg, p, link;
-  rtx copy = 0;
+  rtx copy = 0, first_copy = 0;
   int num_insns = 0;
   rtx exitcode = NEXT_INSN (JUMP_LABEL (next_nonnote_insn (loop_start)));
   rtx lastexit;
@@ -2377,7 +2560,11 @@ duplicate_loop_exit_test (loop_start)
         has a REG_RETVAL or REG_LIBCALL note (hard to adjust)
         is a NOTE_INSN_LOOP_BEG because this means we have a nested loop
         is a NOTE_INSN_BLOCK_{BEG,END} because duplicating these notes
-             are not valid
+             is not valid.
+
+     We also do not do this if we find an insn with ASM_OPERANDS.  While
+     this restriction should not be necessary, copying an insn with
+     ASM_OPERANDS can confuse asm_noperands in some cases.
 
      Also, don't do this if the exit code is more than 20 insns.  */
 
@@ -2403,13 +2590,25 @@ duplicate_loop_exit_test (loop_start)
             This can be avoided by checking here for NOTE_INSN_LOOP_CONT.  */
 
          if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_LOOP_BEG
-             || NOTE_LINE_NUMBER (insn) == NOTE_INSN_BLOCK_BEG
-             || NOTE_LINE_NUMBER (insn) == NOTE_INSN_BLOCK_END
              || NOTE_LINE_NUMBER (insn) == NOTE_INSN_LOOP_CONT)
            return 0;
+
+         if (optimize < 2
+             && (NOTE_LINE_NUMBER (insn) == NOTE_INSN_BLOCK_BEG
+                 || NOTE_LINE_NUMBER (insn) == NOTE_INSN_BLOCK_END))
+           /* If we were to duplicate this code, we would not move
+              the BLOCK notes, and so debugging the moved code would
+              be difficult.  Thus, we only move the code with -O2 or
+              higher.  */
+           return 0;
+
          break;
        case JUMP_INSN:
        case INSN:
+         /* The code below would grossly mishandle REG_WAS_0 notes,
+            so get rid of them here.  */
+         while ((p = find_reg_note (insn, REG_WAS_0, NULL_RTX)) != 0)
+           remove_note (insn, p);
          if (++num_insns > 20
              || find_reg_note (insn, REG_RETVAL, NULL_RTX)
              || find_reg_note (insn, REG_LIBCALL, NULL_RTX))
@@ -2446,10 +2645,7 @@ duplicate_loop_exit_test (loop_start)
            /* We can do the replacement.  Allocate reg_map if this is the
               first replacement we found.  */
            if (reg_map == 0)
-             {
-               reg_map = (rtx *) alloca (max_reg * sizeof (rtx));
-               bzero ((char *) reg_map, max_reg * sizeof (rtx));
-             }
+             reg_map = (rtx *) xcalloc (max_reg, sizeof (rtx));
 
            REG_LOOP_TEST_P (reg) = 1;
 
@@ -2459,65 +2655,72 @@ duplicate_loop_exit_test (loop_start)
 
   /* Now copy each insn.  */
   for (insn = exitcode; insn != lastexit; insn = NEXT_INSN (insn))
-    switch (GET_CODE (insn))
-      {
-      case BARRIER:
-       copy = emit_barrier_before (loop_start);
-       break;
-      case NOTE:
-       /* Only copy line-number notes.  */
-       if (NOTE_LINE_NUMBER (insn) >= 0)
-         {
-           copy = emit_note_before (NOTE_LINE_NUMBER (insn), loop_start);
-           NOTE_SOURCE_FILE (copy) = NOTE_SOURCE_FILE (insn);
-         }
-       break;
-
-      case INSN:
-       copy = emit_insn_before (copy_rtx (PATTERN (insn)), loop_start);
-       if (reg_map)
-         replace_regs (PATTERN (copy), reg_map, max_reg, 1);
-
-       mark_jump_label (PATTERN (copy), copy, 0);
-
-       /* Copy all REG_NOTES except REG_LABEL since mark_jump_label will
-          make them.  */
-       for (link = REG_NOTES (insn); link; link = XEXP (link, 1))
-         if (REG_NOTE_KIND (link) != REG_LABEL)
-           REG_NOTES (copy)
-             = copy_rtx (gen_rtx_EXPR_LIST (REG_NOTE_KIND (link),
-                                            XEXP (link, 0),
-                                            REG_NOTES (copy)));
-       if (reg_map && REG_NOTES (copy))
-         replace_regs (REG_NOTES (copy), reg_map, max_reg, 1);
-       break;
-
-      case JUMP_INSN:
-       copy = emit_jump_insn_before (copy_rtx (PATTERN (insn)), loop_start);
-       if (reg_map)
-         replace_regs (PATTERN (copy), reg_map, max_reg, 1);
-       mark_jump_label (PATTERN (copy), copy, 0);
-       if (REG_NOTES (insn))
-         {
-           REG_NOTES (copy) = copy_rtx (REG_NOTES (insn));
-           if (reg_map)
-             replace_regs (REG_NOTES (copy), reg_map, max_reg, 1);
-         }
-       
-       /* If this is a simple jump, add it to the jump chain.  */
-
-       if (INSN_UID (copy) < max_jump_chain && JUMP_LABEL (copy)
-           && simplejump_p (copy))
-         {
-           jump_chain[INSN_UID (copy)]
-             = jump_chain[INSN_UID (JUMP_LABEL (copy))];
-           jump_chain[INSN_UID (JUMP_LABEL (copy))] = copy;
-         }
-       break;
+    {
+      switch (GET_CODE (insn))
+       {
+       case BARRIER:
+         copy = emit_barrier_before (loop_start);
+         break;
+       case NOTE:
+         /* Only copy line-number notes.  */
+         if (NOTE_LINE_NUMBER (insn) >= 0)
+           {
+             copy = emit_note_before (NOTE_LINE_NUMBER (insn), loop_start);
+             NOTE_SOURCE_FILE (copy) = NOTE_SOURCE_FILE (insn);
+           }
+         break;
+         
+       case INSN:
+         copy = emit_insn_before (copy_insn (PATTERN (insn)), loop_start);
+         if (reg_map)
+           replace_regs (PATTERN (copy), reg_map, max_reg, 1);
+         
+         mark_jump_label (PATTERN (copy), copy, 0, 0);
+         
+         /* Copy all REG_NOTES except REG_LABEL since mark_jump_label will
+            make them.  */
+         for (link = REG_NOTES (insn); link; link = XEXP (link, 1))
+           if (REG_NOTE_KIND (link) != REG_LABEL)
+             REG_NOTES (copy)
+               = copy_insn_1 (gen_rtx_EXPR_LIST (REG_NOTE_KIND (link),
+                                              XEXP (link, 0),
+                                              REG_NOTES (copy)));
+         if (reg_map && REG_NOTES (copy))
+           replace_regs (REG_NOTES (copy), reg_map, max_reg, 1);
+         break;
+         
+       case JUMP_INSN:
+         copy = emit_jump_insn_before (copy_insn (PATTERN (insn)), loop_start);
+         if (reg_map)
+           replace_regs (PATTERN (copy), reg_map, max_reg, 1);
+         mark_jump_label (PATTERN (copy), copy, 0, 0);
+         if (REG_NOTES (insn))
+           {
+             REG_NOTES (copy) = copy_insn_1 (REG_NOTES (insn));
+             if (reg_map)
+               replace_regs (REG_NOTES (copy), reg_map, max_reg, 1);
+           }
+         
+         /* If this is a simple jump, add it to the jump chain.  */
+         
+         if (INSN_UID (copy) < max_jump_chain && JUMP_LABEL (copy)
+             && simplejump_p (copy))
+           {
+             jump_chain[INSN_UID (copy)]
+               = jump_chain[INSN_UID (JUMP_LABEL (copy))];
+             jump_chain[INSN_UID (JUMP_LABEL (copy))] = copy;
+           }
+         break;
+         
+       default:
+         abort ();
+       }
 
-      default:
-       abort ();
-      }
+      /* Record the first insn we copied.  We need it so that we can
+        scan the copied insns for new pseudo registers.  */
+      if (! first_copy)
+       first_copy = copy;
+    }
 
   /* Now clean up by emitting a jump to the end label and deleting the jump
      at the start of the loop.  */
@@ -2525,7 +2728,15 @@ duplicate_loop_exit_test (loop_start)
     {
       copy = emit_jump_insn_before (gen_jump (get_label_after (insn)),
                                    loop_start);
-      mark_jump_label (PATTERN (copy), copy, 0);
+
+      /* Record the first insn we copied.  We need it so that we can
+        scan the copied insns for new pseudo registers.   This may not
+        be strictly necessary since we should have copied at least one
+        insn above.  But I am going to be safe.  */
+      if (! first_copy)
+       first_copy = copy;
+
+      mark_jump_label (PATTERN (copy), copy, 0, 0);
       if (INSN_UID (copy) < max_jump_chain
          && INSN_UID (JUMP_LABEL (copy)) < max_jump_chain)
        {
@@ -2536,10 +2747,19 @@ duplicate_loop_exit_test (loop_start)
       emit_barrier_before (loop_start);
     }
 
+  /* Now scan from the first insn we copied to the last insn we copied
+     (copy) for new pseudo registers.  Do this after the code to jump to
+     the end label since that might create a new pseudo too.  */
+  reg_scan_update (first_copy, copy, max_reg);
+
   /* Mark the exit code as the virtual top of the converted loop.  */
   emit_note_before (NOTE_INSN_LOOP_VTOP, exitcode);
 
   delete_insn (next_nonnote_insn (loop_start));
+  
+  /* Clean up.  */
+  if (reg_map)
+    free (reg_map);
 
   return 1;
 }
@@ -2645,6 +2865,13 @@ find_cross_jump (e1, e2, minimum, f1, f2)
       if (i2 == 0 || GET_CODE (i1) != GET_CODE (i2))
        break;
 
+      /* Avoid moving insns across EH regions if either of the insns
+        can throw.  */
+      if (flag_exceptions
+         && (asynchronous_exceptions || GET_CODE (i1) == CALL_INSN)
+         && !in_same_eh_region (i1, i2))
+       break;
+
       p1 = PATTERN (i1);
       p2 = PATTERN (i2);
        
@@ -2668,7 +2895,7 @@ find_cross_jump (e1, e2, minimum, f1, f2)
         indicates whether or not the insn contains any stack-like
         regs.  */
 
-      if (!lose && cross_jump_death_matters && GET_MODE (i1) == QImode)
+      if (!lose && cross_jump_death_matters && stack_regs_mentioned (i1))
        {
          /* If register stack conversion has already been done, then
             death notes must also be compared before it is certain that
@@ -2952,15 +3179,31 @@ can_reverse_comparison_p (comparison, insn)
       )
     {
       rtx prev = prev_nonnote_insn (insn);
-      rtx set = single_set (prev);
-
-      if (set == 0 || SET_DEST (set) != arg0)
-       return 0;
-
-      arg0 = SET_SRC (set);
+      rtx set;
+
+      /* First see if the condition code mode alone if enough to say we can
+        reverse the condition.  If not, then search backwards for a set of
+        ARG0. We do not need to check for an insn clobbering it since valid
+        code will contain set a set with no intervening clobber.  But
+        stop when we reach a label.  */
+#ifdef REVERSIBLE_CC_MODE
+      if (GET_MODE_CLASS (GET_MODE (arg0)) == MODE_CC
+         && REVERSIBLE_CC_MODE (GET_MODE (arg0)))
+       return 1;
+#endif
+       
+      for (prev = prev_nonnote_insn (insn);
+          prev != 0 && GET_CODE (prev) != CODE_LABEL;
+          prev = prev_nonnote_insn (prev))
+       if ((set = single_set (prev)) != 0
+           && rtx_equal_p (SET_DEST (set), arg0))
+         {
+           arg0 = SET_SRC (set);
 
-      if (GET_CODE (arg0) == COMPARE)
-       arg0 = XEXP (arg0, 0);
+           if (GET_CODE (arg0) == COMPARE)
+             arg0 = XEXP (arg0, 0);
+           break;
+         }
     }
 
   /* We can reverse this if ARG0 is a CONST_INT or if its mode is
@@ -2971,11 +3214,12 @@ can_reverse_comparison_p (comparison, insn)
              && GET_MODE_CLASS (GET_MODE (arg0)) != MODE_FLOAT));
 }
 
-/* Given an rtx-code for a comparison, return the code
-   for the negated comparison.
-   WATCH OUT!  reverse_condition is not safe to use on a jump
-   that might be acting on the results of an IEEE floating point comparison,
-   because of the special treatment of non-signaling nans in comparisons.  
+/* Given an rtx-code for a comparison, return the code for the negated
+   comparison.  If no such code exists, return UNKNOWN.
+
+   WATCH OUT!  reverse_condition is not safe to use on a jump that might
+   be acting on the results of an IEEE floating point comparison, because
+   of the special treatment of non-signaling nans in comparisons.  
    Use can_reverse_comparison_p to be sure.  */
 
 enum rtx_code
@@ -2986,37 +3230,95 @@ reverse_condition (code)
     {
     case EQ:
       return NE;
+    case NE:
+      return EQ;
+    case GT:
+      return LE;
+    case GE:
+      return LT;
+    case LT:
+      return GE;
+    case LE:
+      return GT;
+    case GTU:
+      return LEU;
+    case GEU:
+      return LTU;
+    case LTU:
+      return GEU;
+    case LEU:
+      return GTU;
+    case UNORDERED:
+      return ORDERED;
+    case ORDERED:
+      return UNORDERED;
+
+    case UNLT:
+    case UNLE:
+    case UNGT:
+    case UNGE:
+    case UNEQ:
+    case LTGT:
+      return UNKNOWN;
+
+    default:
+      abort ();
+    }
+}
+
+/* Similar, but we're allowed to generate unordered comparisons, which
+   makes it safe for IEEE floating-point.  Of course, we have to recognize
+   that the target will support them too...  */
 
+enum rtx_code
+reverse_condition_maybe_unordered (code)
+     enum rtx_code code;
+{
+  /* Non-IEEE formats don't have unordered conditions.  */
+  if (TARGET_FLOAT_FORMAT != IEEE_FLOAT_FORMAT)
+    return reverse_condition (code);
+
+  switch (code)
+    {
+    case EQ:
+      return NE;
     case NE:
       return EQ;
-
     case GT:
-      return LE;
-
+      return UNLE;
     case GE:
-      return LT;
-
+      return UNLT;
     case LT:
-      return GE;
-
+      return UNGE;
     case LE:
-      return GT;
-
+      return UNGT;
+    case LTGT:
+      return UNEQ;
     case GTU:
       return LEU;
-
     case GEU:
       return LTU;
-
     case LTU:
       return GEU;
-
     case LEU:
       return GTU;
+    case UNORDERED:
+      return ORDERED;
+    case ORDERED:
+      return UNORDERED;
+    case UNLT:
+      return GE;
+    case UNLE:
+      return GT;
+    case UNGT:
+      return LE;
+    case UNGE:
+      return LT;
+    case UNEQ:
+      return LTGT;
 
     default:
       abort ();
-      return UNKNOWN;
     }
 }
 
@@ -3031,35 +3333,39 @@ swap_condition (code)
     {
     case EQ:
     case NE:
+    case UNORDERED:
+    case ORDERED:
+    case UNEQ:
+    case LTGT:
       return code;
 
     case GT:
       return LT;
-
     case GE:
       return LE;
-
     case LT:
       return GT;
-
     case LE:
       return GE;
-
     case GTU:
       return LTU;
-
     case GEU:
       return LEU;
-
     case LTU:
       return GTU;
-
     case LEU:
       return GEU;
+    case UNLT:
+      return UNGT;
+    case UNLE:
+      return UNGE;
+    case UNGT:
+      return UNLT;
+    case UNGE:
+      return UNLE;
 
     default:
       abort ();
-      return UNKNOWN;
     }
 }
 
@@ -3083,13 +3389,10 @@ unsigned_condition (code)
 
     case GT:
       return GTU;
-
     case GE:
       return GEU;
-
     case LT:
       return LTU;
-
     case LE:
       return LEU;
 
@@ -3116,13 +3419,10 @@ signed_condition (code)
 
     case GTU:
       return GT;
-
     case GEU:
       return GE;
-
     case LTU:
       return LT;
-
     case LEU:
       return LE;
 
@@ -3144,17 +3444,29 @@ comparison_dominates_p (code1, code2)
   switch (code1)
     {
     case EQ:
-      if (code2 == LE || code2 == LEU || code2 == GE || code2 == GEU)
+      if (code2 == LE || code2 == LEU || code2 == GE || code2 == GEU
+         || code2 == ORDERED)
        return 1;
       break;
 
     case LT:
-      if (code2 == LE || code2 == NE)
+      if (code2 == LE || code2 == NE || code2 == ORDERED)
        return 1;
       break;
 
     case GT:
-      if (code2 == GE || code2 == NE)
+      if (code2 == GE || code2 == NE || code2 == ORDERED)
+       return 1;
+      break;
+
+    case GE:
+    case LE:
+      if (code2 == ORDERED)
+       return 1;
+      break;
+
+    case LTGT:
+      if (code2 == NE || code2 == ORDERED)
        return 1;
       break;
 
@@ -3167,6 +3479,11 @@ comparison_dominates_p (code1, code2)
       if (code2 == GEU || code2 == NE)
        return 1;
       break;
+
+    case UNORDERED:
+      if (code2 == NE)
+       return 1;
+      break;
       
     default:
       break;
@@ -3195,27 +3512,27 @@ condjump_p (insn)
      rtx insn;
 {
   register rtx x = PATTERN (insn);
-  if (GET_CODE (x) != SET)
-    return 0;
-  if (GET_CODE (SET_DEST (x)) != PC)
-    return 0;
-  if (GET_CODE (SET_SRC (x)) == LABEL_REF)
-    return 1;
-  if (GET_CODE (SET_SRC (x)) != IF_THEN_ELSE)
+
+  if (GET_CODE (x) != SET
+      || GET_CODE (SET_DEST (x)) != PC)
     return 0;
-  if (XEXP (SET_SRC (x), 2) == pc_rtx
-      && (GET_CODE (XEXP (SET_SRC (x), 1)) == LABEL_REF
-         || GET_CODE (XEXP (SET_SRC (x), 1)) == RETURN))
-    return 1;
-  if (XEXP (SET_SRC (x), 1) == pc_rtx
-      && (GET_CODE (XEXP (SET_SRC (x), 2)) == LABEL_REF
-         || GET_CODE (XEXP (SET_SRC (x), 2)) == RETURN))
+
+  x = SET_SRC (x);
+  if (GET_CODE (x) == LABEL_REF)
     return 1;
+  else return (GET_CODE (x) == IF_THEN_ELSE
+              && ((GET_CODE (XEXP (x, 2)) == PC
+                   && (GET_CODE (XEXP (x, 1)) == LABEL_REF
+                       || GET_CODE (XEXP (x, 1)) == RETURN))
+                  || (GET_CODE (XEXP (x, 1)) == PC
+                      && (GET_CODE (XEXP (x, 2)) == LABEL_REF
+                          || GET_CODE (XEXP (x, 2)) == RETURN))));
+
   return 0;
 }
 
-/* Return nonzero if INSN is a (possibly) conditional jump
-   and nothing more.  */
+/* Return nonzero if INSN is a (possibly) conditional jump inside a
+   PARALLEL.  */
 
 int
 condjump_in_parallel_p (insn)
@@ -3247,6 +3564,75 @@ condjump_in_parallel_p (insn)
   return 0;
 }
 
+/* Return the label of a conditional jump.  */
+
+rtx
+condjump_label (insn)
+     rtx insn;
+{
+  register rtx x = PATTERN (insn);
+
+  if (GET_CODE (x) == PARALLEL)
+    x = XVECEXP (x, 0, 0);
+  if (GET_CODE (x) != SET)
+    return NULL_RTX;
+  if (GET_CODE (SET_DEST (x)) != PC)
+    return NULL_RTX;
+  x = SET_SRC (x);
+  if (GET_CODE (x) == LABEL_REF)
+    return x;
+  if (GET_CODE (x) != IF_THEN_ELSE)
+    return NULL_RTX;
+  if (XEXP (x, 2) == pc_rtx && GET_CODE (XEXP (x, 1)) == LABEL_REF)
+    return XEXP (x, 1);
+  if (XEXP (x, 1) == pc_rtx && GET_CODE (XEXP (x, 2)) == LABEL_REF)
+    return XEXP (x, 2);
+  return NULL_RTX;
+}
+
+/* Return true if INSN is a (possibly conditional) return insn.  */
+
+static int
+returnjump_p_1 (loc, data)
+     rtx *loc;
+     void *data ATTRIBUTE_UNUSED;
+{
+  rtx x = *loc;
+  return x && GET_CODE (x) == RETURN;
+}
+
+int
+returnjump_p (insn)
+     rtx insn;
+{
+  return for_each_rtx (&PATTERN (insn), returnjump_p_1, NULL);
+}
+
+/* Return true if INSN is a jump that only transfers control and
+   nothing more.  */
+
+int
+onlyjump_p (insn)
+     rtx insn;
+{
+  rtx set;
+
+  if (GET_CODE (insn) != JUMP_INSN)
+    return 0;
+
+  set = single_set (insn);
+  if (set == NULL)
+    return 0;
+  if (GET_CODE (SET_DEST (set)) != PC)
+    return 0;
+  if (side_effects_p (SET_SRC (set)))
+    return 0;
+
+  return 1;
+}
+
+#ifdef HAVE_cc0
+
 /* Return 1 if X is an RTX that does nothing but set the condition codes
    and CLOBBER or USE registers.
    Return -1 if X does explicitly set the condition codes,
@@ -3254,9 +3640,8 @@ condjump_in_parallel_p (insn)
 
 int
 sets_cc0_p (x)
-     rtx x;
+     rtx x ATTRIBUTE_UNUSED;
 {
-#ifdef HAVE_cc0
   if (GET_CODE (x) == SET && SET_DEST (x) == cc0_rtx)
     return 1;
   if (GET_CODE (x) == PARALLEL)
@@ -3275,10 +3660,8 @@ sets_cc0_p (x)
       return ! sets_cc0 ? 0 : other_things ? -1 : 1;
     }
   return 0;
-#else
-  abort ();
-#endif
 }
+#endif
 \f
 /* Follow any unconditional jump at LABEL;
    return the ultimate label reached by any such chain of jumps.
@@ -3383,14 +3766,15 @@ tension_vector_labels (x, idx)
    two labels distinct if they are separated by only USE or CLOBBER insns.  */
 
 static void
-mark_jump_label (x, insn, cross_jump)
+mark_jump_label (x, insn, cross_jump, in_mem)
      register rtx x;
      rtx insn;
      int cross_jump;
+     int in_mem;
 {
   register RTX_CODE code = GET_CODE (x);
   register int i;
-  register char *fmt;
+  register const char *fmt;
 
   switch (code)
     {
@@ -3399,17 +3783,22 @@ mark_jump_label (x, insn, cross_jump)
     case REG:
     case SUBREG:
     case CONST_INT:
-    case SYMBOL_REF:
     case CONST_DOUBLE:
     case CLOBBER:
     case CALL:
       return;
 
     case MEM:
+      in_mem = 1;
+      break;
+
+    case SYMBOL_REF:
+      if (!in_mem)
+        return;
+
       /* If this is a constant-pool reference, see if it is a label.  */
-      if (GET_CODE (XEXP (x, 0)) == SYMBOL_REF
-         && CONSTANT_POOL_ADDRESS_P (XEXP (x, 0)))
-       mark_jump_label (get_pool_constant (XEXP (x, 0)), insn, cross_jump);
+      if (CONSTANT_POOL_ADDRESS_P (x))
+        mark_jump_label (get_pool_constant (x), insn, cross_jump, in_mem);
       break;
 
     case LABEL_REF:
@@ -3495,7 +3884,8 @@ mark_jump_label (x, insn, cross_jump)
          int eltnum = code == ADDR_DIFF_VEC ? 1 : 0;
 
          for (i = 0; i < XVECLEN (x, eltnum); i++)
-           mark_jump_label (XVECEXP (x, eltnum, i), NULL_RTX, cross_jump);
+           mark_jump_label (XVECEXP (x, eltnum, i), NULL_RTX, 
+                    cross_jump, in_mem);
        }
       return;
       
@@ -3507,12 +3897,12 @@ mark_jump_label (x, insn, cross_jump)
   for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
     {
       if (fmt[i] == 'e')
-       mark_jump_label (XEXP (x, i), insn, cross_jump);
+       mark_jump_label (XEXP (x, i), insn, cross_jump, in_mem);
       else if (fmt[i] == 'E')
        {
          register int j;
          for (j = 0; j < XVECLEN (x, i); j++)
-           mark_jump_label (XVECEXP (x, i, j), insn, cross_jump);
+           mark_jump_label (XVECEXP (x, i, j), insn, cross_jump, in_mem);
        }
     }
 }
@@ -3531,6 +3921,131 @@ delete_jump (insn)
     delete_computation (insn);
 }
 
+/* Verify INSN is a BARRIER and delete it.  */
+
+void
+delete_barrier (insn)
+     rtx insn;
+{
+  if (GET_CODE (insn) != BARRIER)
+    abort ();
+
+  delete_insn (insn);
+}
+
+/* Recursively delete prior insns that compute the value (used only by INSN
+   which the caller is deleting) stored in the register mentioned by NOTE
+   which is a REG_DEAD note associated with INSN.  */
+
+static void
+delete_prior_computation (note, insn)
+     rtx note;
+     rtx insn;
+{
+  rtx our_prev;
+  rtx reg = XEXP (note, 0);
+
+  for (our_prev = prev_nonnote_insn (insn);
+       our_prev && (GET_CODE (our_prev) == INSN
+                   || GET_CODE (our_prev) == CALL_INSN);
+       our_prev = prev_nonnote_insn (our_prev))
+    {
+      rtx pat = PATTERN (our_prev);
+
+      /* If we reach a CALL which is not calling a const function
+        or the callee pops the arguments, then give up.  */
+      if (GET_CODE (our_prev) == CALL_INSN
+         && (! CONST_CALL_P (our_prev)
+             || GET_CODE (pat) != SET || GET_CODE (SET_SRC (pat)) != CALL))
+       break;
+
+      /* If we reach a SEQUENCE, it is too complex to try to
+        do anything with it, so give up.  */
+      if (GET_CODE (pat) == SEQUENCE)
+       break;
+
+      if (GET_CODE (pat) == USE
+         && GET_CODE (XEXP (pat, 0)) == INSN)
+       /* reorg creates USEs that look like this.  We leave them
+          alone because reorg needs them for its own purposes.  */
+       break;
+
+      if (reg_set_p (reg, pat))
+       {
+         if (side_effects_p (pat) && GET_CODE (our_prev) != CALL_INSN)
+           break;
+
+         if (GET_CODE (pat) == PARALLEL)
+           {
+             /* If we find a SET of something else, we can't
+                delete the insn.  */
+
+             int i;
+
+             for (i = 0; i < XVECLEN (pat, 0); i++)
+               {
+                 rtx part = XVECEXP (pat, 0, i);
+
+                 if (GET_CODE (part) == SET
+                     && SET_DEST (part) != reg)
+                   break;
+               }
+
+             if (i == XVECLEN (pat, 0))
+               delete_computation (our_prev);
+           }
+         else if (GET_CODE (pat) == SET
+                  && GET_CODE (SET_DEST (pat)) == REG)
+           {
+             int dest_regno = REGNO (SET_DEST (pat));
+             int dest_endregno
+                   = dest_regno + (dest_regno < FIRST_PSEUDO_REGISTER 
+                     ? HARD_REGNO_NREGS (dest_regno,
+                               GET_MODE (SET_DEST (pat))) : 1);
+             int regno = REGNO (reg);
+             int endregno = regno + (regno < FIRST_PSEUDO_REGISTER 
+                            ? HARD_REGNO_NREGS (regno, GET_MODE (reg)) : 1);
+
+             if (dest_regno >= regno
+                 && dest_endregno <= endregno)
+               delete_computation (our_prev);
+
+             /* We may have a multi-word hard register and some, but not
+                all, of the words of the register are needed in subsequent
+                insns.  Write REG_UNUSED notes for those parts that were not
+                needed.  */
+             else if (dest_regno <= regno
+                      && dest_endregno >= endregno)
+               {
+                 int i;
+
+                 REG_NOTES (our_prev)
+                   = gen_rtx_EXPR_LIST (REG_UNUSED, reg, REG_NOTES (our_prev));
+
+                 for (i = dest_regno; i < dest_endregno; i++)
+                   if (! find_regno_note (our_prev, REG_UNUSED, i))
+                     break;
+
+                 if (i == dest_endregno)
+                   delete_computation (our_prev);
+               }
+           }
+
+         break;
+       }
+
+      /* If PAT references the register that dies here, it is an
+        additional use.  Hence any prior SET isn't dead.  However, this
+        insn becomes the new place for the REG_DEAD note.  */
+      if (reg_overlap_mentioned_p (reg, pat))
+       {
+         XEXP (note, 1) = REG_NOTES (our_prev);
+         REG_NOTES (our_prev) = note;
+         break;
+       }
+    }
+}
+
 /* Delete INSN and recursively delete insns that compute values used only
    by INSN.  This uses the REG_DEAD notes computed during flow analysis.
    If we are running before flow.c, we need do nothing since flow.c will
@@ -3549,6 +4064,7 @@ delete_computation (insn)
      rtx insn;
 {
   rtx note, next;
+  rtx set;
 
 #ifdef HAVE_cc0
   if (reg_referenced_p (cc0_rtx, PATTERN (insn)))
@@ -3564,7 +4080,7 @@ delete_computation (insn)
          && sets_cc0_p (PATTERN (prev)))
        {
          if (sets_cc0_p (PATTERN (prev)) > 0
-             && !FIND_REG_INC_NOTE (prev, NULL_RTX))
+             && ! side_effects_p (PATTERN (prev)))
            delete_computation (prev);
          else
            /* Otherwise, show that cc0 won't be used.  */
@@ -3574,10 +4090,44 @@ delete_computation (insn)
     }
 #endif
 
-  for (note = REG_NOTES (insn); note; note = next)
+#ifdef INSN_SCHEDULING
+  /* ?!? The schedulers do not keep REG_DEAD notes accurate after
+     reload has completed.  The schedulers need to be fixed.  Until
+     they are, we must not rely on the death notes here.  */
+  if (reload_completed && flag_schedule_insns_after_reload)
+    {
+      delete_insn (insn);
+      return;
+    }
+#endif
+
+  /* The REG_DEAD note may have been omitted for a register
+     which is both set and used by the insn.  */
+  set = single_set (insn);
+  if (set && GET_CODE (SET_DEST (set)) == REG)
     {
-      rtx our_prev;
+    int dest_regno = REGNO (SET_DEST (set));
+    int dest_endregno
+         = dest_regno + (dest_regno < FIRST_PSEUDO_REGISTER 
+           ? HARD_REGNO_NREGS (dest_regno,
+                               GET_MODE (SET_DEST (set))) : 1);
+    int i;
+
+    for (i = dest_regno; i < dest_endregno; i++)
+      {
+       if (! refers_to_regno_p (i, i + 1, SET_SRC (set), NULL_PTR)
+           || find_regno_note (insn, REG_DEAD, i))
+         continue;
+
+       note = gen_rtx_EXPR_LIST (REG_DEAD, (i < FIRST_PSEUDO_REGISTER
+                                            ? gen_rtx_REG (reg_raw_mode[i], i)
+                                            : SET_DEST (set)), NULL_RTX);
+       delete_prior_computation (note, insn);
+      }
+    }
 
+  for (note = REG_NOTES (insn); note; note = next)
+    {
       next = XEXP (note, 1);
 
       if (REG_NOTE_KIND (note) != REG_DEAD
@@ -3585,63 +4135,7 @@ delete_computation (insn)
          || GET_CODE (XEXP (note, 0)) != REG)
        continue;
 
-      for (our_prev = prev_nonnote_insn (insn);
-          our_prev && GET_CODE (our_prev) == INSN;
-          our_prev = prev_nonnote_insn (our_prev))
-       {
-         /* If we reach a SEQUENCE, it is too complex to try to
-            do anything with it, so give up.  */
-         if (GET_CODE (PATTERN (our_prev)) == SEQUENCE)
-           break;
-
-         if (GET_CODE (PATTERN (our_prev)) == USE
-             && GET_CODE (XEXP (PATTERN (our_prev), 0)) == INSN)
-           /* reorg creates USEs that look like this.  We leave them
-              alone because reorg needs them for its own purposes.  */
-           break;
-
-         if (reg_set_p (XEXP (note, 0), PATTERN (our_prev)))
-           {
-             if (FIND_REG_INC_NOTE (our_prev, NULL_RTX))
-               break;
-
-             if (GET_CODE (PATTERN (our_prev)) == PARALLEL)
-               {
-                 /* If we find a SET of something else, we can't
-                    delete the insn.  */
-
-                 int i;
-
-                 for (i = 0; i < XVECLEN (PATTERN (our_prev), 0); i++)
-                   {
-                     rtx part = XVECEXP (PATTERN (our_prev), 0, i);
-
-                     if (GET_CODE (part) == SET
-                         && SET_DEST (part) != XEXP (note, 0))
-                       break;
-                   }
-
-                 if (i == XVECLEN (PATTERN (our_prev), 0))
-                   delete_computation (our_prev);
-               }
-             else if (GET_CODE (PATTERN (our_prev)) == SET
-                      && SET_DEST (PATTERN (our_prev)) == XEXP (note, 0))
-               delete_computation (our_prev);
-
-             break;
-           }
-
-         /* If OUR_PREV references the register that dies here, it is an
-            additional use.  Hence any prior SET isn't dead.  However, this
-            insn becomes the new place for the REG_DEAD note.  */
-         if (reg_overlap_mentioned_p (XEXP (note, 0),
-                                      PATTERN (our_prev)))
-           {
-             XEXP (note, 1) = REG_NOTES (our_prev);
-             REG_NOTES (our_prev) = note;
-             break;
-           }
-       }
+      delete_prior_computation (note, insn);
     }
 
   delete_insn (insn);
@@ -3669,15 +4163,22 @@ delete_insn (insn)
   if (INSN_DELETED_P (insn))
     return next;
 
-  /* Don't delete user-declared labels.  Convert them to special NOTEs
-     instead.  */
-  if (was_code_label && LABEL_NAME (insn) != 0
-      && optimize && ! dont_really_delete)
+  if (was_code_label)
+    remove_node_from_expr_list (insn, &nonlocal_goto_handler_labels);
+
+  /* Don't delete user-declared labels.  When optimizing, convert them
+     to special NOTEs instead.  When not optimizing, leave them alone.  */
+  if (was_code_label && LABEL_NAME (insn) != 0)
     {
-      PUT_CODE (insn, NOTE);
-      NOTE_LINE_NUMBER (insn) = NOTE_INSN_DELETED_LABEL;
-      NOTE_SOURCE_FILE (insn) = 0;
-      dont_really_delete = 1;
+      if (! optimize)
+       dont_really_delete = 1;
+      else if (! dont_really_delete)
+       {
+         PUT_CODE (insn, NOTE);
+         NOTE_LINE_NUMBER (insn) = NOTE_INSN_DELETED_LABEL;
+         NOTE_SOURCE_FILE (insn) = 0;
+         dont_really_delete = 1;
+       }
     }
   else
     /* Mark this insn as deleted.  */
@@ -3698,7 +4199,7 @@ delete_insn (insn)
 
   /* Patch out INSN (and the barrier if any) */
 
-  if (optimize && ! dont_really_delete)
+  if (! dont_really_delete)
     {
       if (prev)
        {
@@ -3723,20 +4224,36 @@ delete_insn (insn)
      and delete the label if it is now unused.  */
 
   if (GET_CODE (insn) == JUMP_INSN && JUMP_LABEL (insn))
-    if (--LABEL_NUSES (JUMP_LABEL (insn)) == 0)
-      {
-       /* This can delete NEXT or PREV,
-          either directly if NEXT is JUMP_LABEL (INSN),
-          or indirectly through more levels of jumps.  */
-       delete_insn (JUMP_LABEL (insn));
-       /* I feel a little doubtful about this loop,
-          but I see no clean and sure alternative way
-          to find the first insn after INSN that is not now deleted.
-          I hope this works.  */
-       while (next && INSN_DELETED_P (next))
-         next = NEXT_INSN (next);
-       return next;
-      }
+    {
+      rtx lab = JUMP_LABEL (insn), lab_next;
+
+      if (--LABEL_NUSES (lab) == 0)
+       {
+         /* This can delete NEXT or PREV,
+            either directly if NEXT is JUMP_LABEL (INSN),
+            or indirectly through more levels of jumps.  */
+         delete_insn (lab);
+
+         /* I feel a little doubtful about this loop,
+            but I see no clean and sure alternative way
+            to find the first insn after INSN that is not now deleted.
+            I hope this works.  */
+         while (next && INSN_DELETED_P (next))
+           next = NEXT_INSN (next);
+         return next;
+       }
+      else if ((lab_next = next_nonnote_insn (lab)) != NULL
+              && GET_CODE (lab_next) == JUMP_INSN
+              && (GET_CODE (PATTERN (lab_next)) == ADDR_VEC
+                  || GET_CODE (PATTERN (lab_next)) == ADDR_DIFF_VEC))
+       {
+         /* If we're deleting the tablejump, delete the dispatch table.
+            We may not be able to kill the label immediately preceeding
+            just yet, as it might be referenced in code leading up to
+            the tablejump.  */
+         delete_insn (lab_next);
+       }
+    }
 
   /* Likewise if we're deleting a dispatch table.  */
 
@@ -3851,6 +4368,52 @@ delete_for_peephole (from, to)
      is also an unconditional jump in that case.  */
 }
 \f
+/* We have determined that INSN is never reached, and are about to
+   delete it.  Print a warning if the user asked for one.
+
+   To try to make this warning more useful, this should only be called
+   once per basic block not reached, and it only warns when the basic
+   block contains more than one line from the current function, and
+   contains at least one operation.  CSE and inlining can duplicate insns,
+   so it's possible to get spurious warnings from this.  */
+
+void
+never_reached_warning (avoided_insn)
+     rtx avoided_insn;
+{
+  rtx insn;
+  rtx a_line_note = NULL;
+  int two_avoided_lines = 0;
+  int contains_insn = 0;
+  
+  if (! warn_notreached)
+    return;
+
+  /* Scan forwards, looking at LINE_NUMBER notes, until
+     we hit a LABEL or we run out of insns.  */
+  
+  for (insn = avoided_insn; insn != NULL; insn = NEXT_INSN (insn))
+    {
+       if (GET_CODE (insn) == CODE_LABEL)
+        break;
+       else if (GET_CODE (insn) == NOTE                /* A line number note? */ 
+               && NOTE_LINE_NUMBER (insn) >= 0)
+       {
+         if (a_line_note == NULL)
+           a_line_note = insn;
+         else
+           two_avoided_lines |= (NOTE_LINE_NUMBER (a_line_note)
+                                 != NOTE_LINE_NUMBER (insn));
+       }
+       else if (GET_RTX_CLASS (GET_CODE (insn)) == 'i')
+        contains_insn = 1;
+    }
+  if (two_avoided_lines && contains_insn)
+    warning_with_file_and_line (NOTE_SOURCE_FILE (a_line_note),
+                               NOTE_LINE_NUMBER (a_line_note),
+                               "will never be executed");
+}
+\f
 /* Invert the condition of the jump JUMP, and make it jump
    to label NLABEL instead of where it jumps now.  */
 
@@ -3902,7 +4465,7 @@ invert_exp (x, insn)
 {
   register RTX_CODE code;
   register int i;
-  register char *fmt;
+  register const char *fmt;
 
   code = GET_CODE (x);
 
@@ -3933,9 +4496,11 @@ invert_exp (x, insn)
   for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
     {
       if (fmt[i] == 'e')
-       if (! invert_exp (XEXP (x, i), insn))
-         return 0;
-      if (fmt[i] == 'E')
+       {
+         if (! invert_exp (XEXP (x, i), insn))
+           return 0;
+       }
+      else if (fmt[i] == 'E')
        {
          register int j;
          for (j = 0; j < XVECLEN (x, i); j++)
@@ -3990,6 +4555,13 @@ redirect_jump (jump, nlabel)
   if (nlabel)
     ++LABEL_NUSES (nlabel);
 
+  /* If we're eliding the jump over exception cleanups at the end of a
+     function, move the function end note so that -Wreturn-type works.  */
+  if (olabel && NEXT_INSN (olabel)
+      && GET_CODE (NEXT_INSN (olabel)) == NOTE
+      && NOTE_LINE_NUMBER (NEXT_INSN (olabel)) == NOTE_INSN_FUNCTION_END)
+    emit_note_after (NOTE_INSN_FUNCTION_END, nlabel);
+
   if (olabel && --LABEL_NUSES (olabel) == 0)
     delete_insn (olabel);
 
@@ -4052,7 +4624,7 @@ redirect_exp (loc, olabel, nlabel, insn)
   register rtx x = *loc;
   register RTX_CODE code = GET_CODE (x);
   register int i;
-  register char *fmt;
+  register const char *fmt;
 
   if (code == LABEL_REF)
     {
@@ -4082,9 +4654,11 @@ redirect_exp (loc, olabel, nlabel, insn)
   for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
     {
       if (fmt[i] == 'e')
-       if (! redirect_exp (&XEXP (x, i), olabel, nlabel, insn))
-         return 0;
-      if (fmt[i] == 'E')
+       {
+         if (! redirect_exp (&XEXP (x, i), olabel, nlabel, insn))
+           return 0;
+       }
+      else if (fmt[i] == 'E')
        {
          register int j;
          for (j = 0; j < XVECLEN (x, i); j++)
@@ -4171,7 +4745,15 @@ delete_labelref_insn (insn, label, delete_this)
 /* Like rtx_equal_p except that it considers two REGs as equal
    if they renumber to the same value and considers two commutative
    operations to be the same if the order of the operands has been
-   reversed.  */
+   reversed.
+
+   ??? Addition is not commutative on the PA due to the weird implicit
+   space register selection rules for memory addresses.  Therefore, we
+   don't consider a + b == b + a.
+
+   We could/should make this test a little tighter.  Possibly only
+   disabling it on the PA via some backend macro or only disabling this
+   case when the PLUS is inside a MEM.  */
 
 int
 rtx_renumbered_equal_p (x, y)
@@ -4179,7 +4761,7 @@ rtx_renumbered_equal_p (x, y)
 {
   register int i;
   register RTX_CODE code = GET_CODE (x);
-  register char *fmt;
+  register const char *fmt;
       
   if (x == y)
     return 1;
@@ -4269,6 +4851,10 @@ rtx_renumbered_equal_p (x, y)
     case SYMBOL_REF:
       return XSTR (x, 0) == XSTR (y, 0);
 
+    case CODE_LABEL:
+      /* If we didn't match EQ equality above, they aren't the same.  */
+      return 0;
+
     default:
       break;
     }
@@ -4279,8 +4865,11 @@ rtx_renumbered_equal_p (x, y)
     return 0;
 
   /* For commutative operations, the RTX match if the operand match in any
-     order.  Also handle the simple binary and unary cases without a loop.  */
-  if (code == EQ || code == NE || GET_RTX_CLASS (code) == 'c')
+     order.  Also handle the simple binary and unary cases without a loop.
+
+     ??? Don't consider PLUS a commutative operator; see comments above.  */
+  if ((code == EQ || code == NE || GET_RTX_CLASS (code) == 'c')
+      && code != PLUS)
     return ((rtx_renumbered_equal_p (XEXP (x, 0), XEXP (y, 0))
             && rtx_renumbered_equal_p (XEXP (x, 1), XEXP (y, 1)))
            || (rtx_renumbered_equal_p (XEXP (x, 0), XEXP (y, 1))
@@ -4413,11 +5002,13 @@ static int modified_mem;
    branch and the second branch.  It marks any changed registers.  */
 
 static void
-mark_modified_reg (dest, x)
+mark_modified_reg (dest, x, data)
      rtx dest;
      rtx x ATTRIBUTE_UNUSED;
+     void *data ATTRIBUTE_UNUSED;
 {
-  int regno, i;
+  int regno;
+  unsigned int i;
 
   if (GET_CODE (dest) == SUBREG)
     dest = SUBREG_REG (dest);
@@ -4462,9 +5053,9 @@ thread_jumps (f, max_reg, flag_before_loop)
   int *all_reset;
 
   /* Allocate register tables and quick-reset table.  */
-  modified_regs = (char *) alloca (max_reg * sizeof (char));
-  same_regs = (int *) alloca (max_reg * sizeof (int));
-  all_reset = (int *) alloca (max_reg * sizeof (int));
+  modified_regs = (char *) xmalloc (max_reg * sizeof (char));
+  same_regs = (int *) xmalloc (max_reg * sizeof (int));
+  all_reset = (int *) xmalloc (max_reg * sizeof (int));
   for (i = 0; i < max_reg; i++)
     all_reset[i] = -1;
     
@@ -4527,7 +5118,7 @@ thread_jumps (f, max_reg, flag_before_loop)
                      modified_regs[i] = 1;
                }
 
-             note_stores (PATTERN (b2), mark_modified_reg);
+             note_stores (PATTERN (b2), mark_modified_reg, NULL);
            }
 
          /* Check the next candidate branch insn from the label
@@ -4560,10 +5151,11 @@ thread_jumps (f, max_reg, flag_before_loop)
          if (rtx_equal_for_thread_p (b1op0, b2op0, b2)
              && rtx_equal_for_thread_p (b1op1, b2op1, b2)
              && (comparison_dominates_p (code1, code2)
-                 || (comparison_dominates_p (code1, reverse_condition (code2))
-                     && can_reverse_comparison_p (XEXP (SET_SRC (PATTERN (b1)),
-                                                        0),
-                                                  b1))))
+                 || (can_reverse_comparison_p (XEXP (SET_SRC (PATTERN (b1)),
+                                                     0),
+                                               b1)
+                     && comparison_dominates_p (code1, reverse_condition (code2)))))
+
            {
              t1 = prev_nonnote_insn (b1);
              t2 = prev_nonnote_insn (b2);
@@ -4622,6 +5214,11 @@ thread_jumps (f, max_reg, flag_before_loop)
            }
        }
     }
+
+  /* Clean up.  */
+  free (modified_regs);
+  free (same_regs);
+  free (all_reset);
 }
 \f
 /* This is like RTX_EQUAL_P except that it knows about our handling of
@@ -4638,7 +5235,7 @@ rtx_equal_for_thread_p (x, y, yinsn)
   register int i;
   register int j;
   register enum rtx_code code;
-  register char *fmt;
+  register const char *fmt;
 
   code = GET_CODE (x);
   /* Rtx's of different codes cannot be equal.  */
@@ -4699,7 +5296,7 @@ rtx_equal_for_thread_p (x, y, yinsn)
          return 1;
        }
       else
-       return (same_regs[REGNO (x)] == REGNO (y));
+       return (same_regs[REGNO (x)] == (int) REGNO (y));
 
       break;
 
@@ -4723,7 +5320,7 @@ rtx_equal_for_thread_p (x, y, yinsn)
       if (GET_CODE (SET_DEST (x)) == REG
           && GET_CODE (SET_DEST (y)) == REG)
        {
-          if (same_regs[REGNO (SET_DEST (x))] == REGNO (SET_DEST (y)))
+          if (same_regs[REGNO (SET_DEST (x))] == (int) REGNO (SET_DEST (y)))
            {
              same_regs[REGNO (SET_DEST (x))] = -1;
              num_same_regs--;
@@ -4795,6 +5392,7 @@ rtx_equal_for_thread_p (x, y, yinsn)
          break;
 
        case '0':
+       case 't':
          break;
 
          /* It is believed that rtx's at this level will never
@@ -4808,7 +5406,7 @@ rtx_equal_for_thread_p (x, y, yinsn)
 }
 \f
 
-#ifndef HAVE_cc0
+#if !defined(HAVE_cc0) && !defined(HAVE_conditional_arithmetic)
 /* Return the insn that NEW can be safely inserted in front of starting at
    the jump insn INSN.  Return 0 if it is not safe to do this jump
    optimization.  Note that NEW must contain a single set. */