OSDN Git Service

(call patterns): Use %. in cror.
[pf3gnuchains/gcc-fork.git] / gcc / jump.c
index e4a6aad..9773ce6 100644 (file)
@@ -1,5 +1,5 @@
 /* Optimize jump instructions, for GNU compiler.
-   Copyright (C) 1987, 1988, 1989, 1991 Free Software Foundation, Inc.
+   Copyright (C) 1987, 88, 89, 91, 92, 1993 Free Software Foundation, Inc.
 
 This file is part of GNU CC.
 
@@ -104,26 +104,18 @@ int can_reach_end;
 static int cross_jump_death_matters = 0;
 
 static int duplicate_loop_exit_test ();
-rtx delete_insn ();
-int redirect_jump ();
-static int redirect_exp ();
 void redirect_tablejump ();
 static int delete_labelref_insn ();
-int invert_jump ();
-static int invert_exp ();
-int condjump_p ();
-int simplejump_p ();
-
-extern rtx gen_jump ();
-
-void squeeze_notes ();
 static void mark_jump_label ();
 void delete_jump ();
+void delete_computation ();
 static void delete_from_jump_chain ();
 static int tension_vector_labels ();
 static void find_cross_jump ();
 static void do_cross_jump ();
 static int jump_back_p ();
+
+extern rtx gen_jump ();
 \f
 /* Delete no-op jumps and optimize jumps to jumps
    and jumps around jumps.
@@ -151,7 +143,7 @@ jump_optimize (f, cross_jump, noop_moves, after_regscan)
      int noop_moves;
      int after_regscan;
 {
-  register rtx insn;
+  register rtx insn, next;
   int changed;
   int first = 1;
   int max_uid = 0;
@@ -307,7 +299,7 @@ jump_optimize (f, cross_jump, noop_moves, after_regscan)
   if (noop_moves)
     for (insn = f; insn; )
       {
-       register rtx next = NEXT_INSN (insn);
+       next = NEXT_INSN (insn);
 
        if (GET_CODE (insn) == INSN)
          {
@@ -354,10 +346,10 @@ jump_optimize (f, cross_jump, noop_moves, after_regscan)
                           && XEXP (XEXP (dest, 0), 0) == stack_pointer_rtx))
                      break;
                    pushes++;
-                   if (total_pushed + GET_MODE_SIZE (SET_DEST (pbody))
+                   if (total_pushed + GET_MODE_SIZE (GET_MODE (SET_DEST (pbody)))
                        > stack_adjust_amount)
                      break;
-                   total_pushed += GET_MODE_SIZE (SET_DEST (pbody));
+                   total_pushed += GET_MODE_SIZE (GET_MODE (SET_DEST (pbody)));
                  }
 
                /* Discard the amount pushed from the stack adjust;
@@ -369,8 +361,7 @@ jump_optimize (f, cross_jump, noop_moves, after_regscan)
                  }
                else
                  XEXP (SET_SRC (PATTERN (stack_adjust_insn)), 1)
-                   = gen_rtx (CONST_INT, VOIDmode, 
-                              stack_adjust_amount - total_pushed);
+                   = GEN_INT (stack_adjust_amount - total_pushed);
 
                /* Change the appropriate push insns to ordinary stores.  */
                p = insn;
@@ -388,7 +379,7 @@ jump_optimize (f, cross_jump, noop_moves, after_regscan)
                           && GET_CODE (XEXP (dest, 0)) == POST_INC
                           && XEXP (XEXP (dest, 0), 0) == stack_pointer_rtx))
                      break;
-                   total_pushed -= GET_MODE_SIZE (SET_DEST (pbody));
+                   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
@@ -397,7 +388,7 @@ jump_optimize (f, cross_jump, noop_moves, after_regscan)
                    if (total_pushed < 0)
                      {
                        emit_insn_before (gen_add2_insn (stack_pointer_rtx,
-                                                        gen_rtx (CONST_INT, VOIDmode, - total_pushed)),
+                                                        GEN_INT (- total_pushed)),
                                          p);
                        break;
                      }
@@ -434,8 +425,8 @@ jump_optimize (f, cross_jump, noop_moves, after_regscan)
                else if (sreg >= 0 && dreg >= 0)
                  {
                    rtx trial;
-                   rtx tem = find_equiv_reg (0, insn, 0,
-                                             sreg, 0, dreg,
+                   rtx tem = find_equiv_reg (NULL_RTX, insn, 0,
+                                             sreg, NULL_PTR, dreg,
                                              GET_MODE (SET_SRC (body)));
 
 #ifdef PRESERVE_DEATH_INFO_REGNO_P
@@ -464,8 +455,9 @@ jump_optimize (f, cross_jump, noop_moves, after_regscan)
                      }
                  }
                else if (dreg >= 0 && CONSTANT_P (SET_SRC (body))
-                        && find_equiv_reg (SET_SRC (body), insn, 0, dreg, 0,
-                                           0, GET_MODE (SET_DEST (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
@@ -533,19 +525,38 @@ jump_optimize (f, cross_jump, noop_moves, after_regscan)
       insn = next;
     }
 
+  /* 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)
+    for (insn = f; insn; insn = next)
+      {
+       rtx set = single_set (insn);
+
+       next = NEXT_INSN (insn);
+
+       if (set && GET_CODE (SET_DEST (set)) == REG
+           && REGNO (SET_DEST (set)) >= FIRST_PSEUDO_REGISTER
+           && regno_first_uid[REGNO (SET_DEST (set))] == INSN_UID (insn)
+           && regno_last_uid[REGNO (SET_DEST (set))] == INSN_UID (insn)
+           && ! side_effects_p (SET_SRC (set)))
+         delete_insn (insn);
+      }
+
   /* Now iterate optimizing jumps until nothing changes over one pass.  */
   changed = 1;
   while (changed)
     {
-      register rtx next;
       changed = 0;
 
       for (insn = f; insn; insn = next)
        {
          rtx reallabelprev;
-         rtx temp, temp1, temp2, temp3, temp4, temp5;
+         rtx temp, temp1, temp2, temp3, temp4, temp5, temp6;
          rtx nlabel;
-         int this_is_simplejump, this_is_condjump;
+         int this_is_simplejump, this_is_condjump, reversep;
 #if 0
          /* If NOT the first iteration, if this is the last jump pass
             (just before final), do the special peephole optimizations.
@@ -610,6 +621,7 @@ jump_optimize (f, cross_jump, noop_moves, after_regscan)
                    != 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.  */
@@ -630,7 +642,7 @@ jump_optimize (f, cross_jump, noop_moves, after_regscan)
             it into a RETURN insn, possibly a conditional one.  */
          if (JUMP_LABEL (insn)
              && next_active_insn (JUMP_LABEL (insn)) == 0)
-           changed |= redirect_jump (insn, 0);
+           changed |= redirect_jump (insn, NULL_RTX);
 
          /* Detect jump to following insn.  */
          if (reallabelprev == insn && condjump_p (insn))
@@ -640,7 +652,7 @@ jump_optimize (f, cross_jump, noop_moves, after_regscan)
              continue;
            }
 
-         /* If we have an unconditional jump preceeded by a USE, try to put
+         /* 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
             dealing with these USE insns.  We only do this if the label
@@ -657,12 +669,11 @@ jump_optimize (f, cross_jump, noop_moves, after_regscan)
            {
              if (GET_CODE (temp1) == BARRIER)
                {
-                 reorder_insns (temp, temp, temp1);
+                 emit_insn_after (PATTERN (temp), temp1);
                  temp1 = NEXT_INSN (temp1);
                }
-             else
-               delete_insn (temp);
 
+             delete_insn (temp);
              redirect_jump (insn, get_label_before (temp1));
              reallabelprev = prev_real_insn (temp1);
              changed = 1;
@@ -690,31 +701,33 @@ jump_optimize (f, cross_jump, noop_moves, after_regscan)
 
             We set:
 
-            TEMP to the jump insn preceeding "x = a;"
+            TEMP to the jump insn preceding "x = a;"
             TEMP1 to X
             TEMP2 to the insn that sets "x = b;"
-            TEMP3 to the insn that sets "x = a;"  */
+            TEMP3 to the insn that sets "x = a;"
+            TEMP4 to the set of "x = b";  */
 
          if (this_is_simplejump
              && (temp3 = prev_active_insn (insn)) != 0
              && GET_CODE (temp3) == INSN
-             && GET_CODE (PATTERN (temp3)) == SET
-             && GET_CODE (temp1 = SET_DEST (PATTERN (temp3))) == REG
+             && (temp4 = single_set (temp3)) != 0
+             && GET_CODE (temp1 = SET_DEST (temp4)) == REG
 #ifdef SMALL_REGISTER_CLASSES
              && REGNO (temp1) >= FIRST_PSEUDO_REGISTER
 #endif
              && (temp2 = next_active_insn (insn)) != 0
              && GET_CODE (temp2) == INSN
-             && GET_CODE (PATTERN (temp2)) == SET
-             && rtx_equal_p (SET_DEST (PATTERN (temp2)), temp1)
-             && (GET_CODE (SET_SRC (PATTERN (temp2))) == REG
-                 || CONSTANT_P (SET_SRC (PATTERN (temp2))))
+             && (temp4 = single_set (temp2)) != 0
+             && rtx_equal_p (SET_DEST (temp4), temp1)
+             && (GET_CODE (SET_SRC (temp4)) == REG
+                 || GET_CODE (SET_SRC (temp4)) == SUBREG
+                 || CONSTANT_P (SET_SRC (temp4)))
              && (REG_NOTES (temp2) == 0
                  || ((REG_NOTE_KIND (REG_NOTES (temp2)) == REG_EQUAL
                       || REG_NOTE_KIND (REG_NOTES (temp2)) == REG_EQUIV)
                      && XEXP (REG_NOTES (temp2), 1) == 0
                      && rtx_equal_p (XEXP (REG_NOTES (temp2), 0),
-                                     SET_SRC (PATTERN (temp2)))))
+                                     SET_SRC (temp4))))
              && (temp = prev_active_insn (temp3)) != 0
              && condjump_p (temp) && ! simplejump_p (temp)
              /* TEMP must skip over the "x = a;" insn */
@@ -725,9 +738,9 @@ jump_optimize (f, cross_jump, noop_moves, after_regscan)
              /* INSN must either branch to the insn after TEMP2 or the insn
                 after TEMP2 must branch to the same place as INSN.  */
              && (reallabelprev == temp2
-                 || ((temp4 = next_active_insn (temp2)) != 0
-                     && simplejump_p (temp4)
-                     && JUMP_LABEL (temp4) == JUMP_LABEL (insn))))
+                 || ((temp5 = next_active_insn (temp2)) != 0
+                     && simplejump_p (temp5)
+                     && JUMP_LABEL (temp5) == JUMP_LABEL (insn))))
            {
              /* The test expression, X, may be a complicated test with
                 multiple branches.  See if we can find all the uses of
@@ -775,11 +788,11 @@ jump_optimize (f, cross_jump, noop_moves, after_regscan)
                  && no_labels_between_p (p, insn)
                  && ! reg_referenced_between_p (temp1, p, NEXT_INSN (temp3))
                  && ! reg_set_between_p (temp1, p, temp3)
-                 && (GET_CODE (SET_SRC (PATTERN (temp2))) == CONST_INT
-                     || ! reg_set_between_p (SET_SRC (PATTERN (temp2)),
-                                             p, temp2)))
+                 && (GET_CODE (SET_SRC (temp4)) == CONST_INT
+                     || ! reg_set_between_p (SET_SRC (temp4), p, temp2)))
                {
-                 reorder_insns_with_line_notes (temp2, temp2, p);
+                 emit_insn_after_with_line_notes (PATTERN (temp2), p, temp2);
+                 delete_insn (temp2);
 
                  /* Set NEXT to an insn that we know won't go away.  */
                  next = next_active_insn (insn);
@@ -803,12 +816,170 @@ jump_optimize (f, cross_jump, noop_moves, after_regscan)
                }
            }
 
-         /* If we have  x = a; if (...) x = b;
-            and either A or B is zero, or if we have  if (...) x = 0;
-            and jumps are expensive, try to use a store-flag insn to
-            avoid the jump.  (If the jump would be faster, the machine
-            should not have defined the scc insns!).  These cases are often
-            made by the previous optimization.
+#ifndef HAVE_cc0
+         /* 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
+            t = exp; if (...) x = t;
+
+            Don't do this when we have CC0 because it is unlikely to help
+            and we'd need to worry about where to place the new insn and
+            the potential for conflicts.  We also can't do this when we have
+            notes on the insn for the same reason as above.
+
+            We set:
+
+            TEMP to the "x = exp;" insn.
+            TEMP1 to the single set in the "x = exp; insn.
+            TEMP2 to "x".  */
+
+         if (! reload_completed
+             && this_is_condjump && ! this_is_simplejump
+             && BRANCH_COST >= 3
+             && (temp = next_nonnote_insn (insn)) != 0
+             && GET_CODE (temp) == INSN
+             && REG_NOTES (temp) == 0
+             && (reallabelprev == temp
+                 || ((temp2 = next_active_insn (temp)) != 0
+                     && simplejump_p (temp2)
+                     && JUMP_LABEL (temp2) == JUMP_LABEL (insn)))
+             && (temp1 = single_set (temp)) != 0
+             && (temp2 = SET_DEST (temp1), GET_CODE (temp2) == REG)
+             && GET_MODE_CLASS (GET_MODE (temp2)) == MODE_INT
+#ifdef SMALL_REGISTER_CLASSES
+             && REGNO (temp2) >= FIRST_PSEUDO_REGISTER
+#endif
+             && GET_CODE (SET_SRC (temp1)) != REG
+             && GET_CODE (SET_SRC (temp1)) != SUBREG
+             && GET_CODE (SET_SRC (temp1)) != CONST_INT
+             && ! side_effects_p (SET_SRC (temp1))
+             && ! may_trap_p (SET_SRC (temp1))
+             && rtx_cost (SET_SRC (temp1)) < 10)
+           {
+             rtx new = gen_reg_rtx (GET_MODE (temp2));
+
+             if (validate_change (temp, &SET_DEST (temp1), new, 0))
+               {
+                 next = emit_insn_after (gen_move_insn (temp2, new), insn);
+                 emit_insn_after_with_line_notes (PATTERN (temp), 
+                                                  PREV_INSN (insn), temp);
+                 delete_insn (temp);
+               }
+           }
+
+         /* Similarly, if it takes two insns to compute EXP but they
+            have the same destination.  Here TEMP3 will be the second
+            insn and TEMP4 the SET from that insn.  */
+
+         if (! reload_completed
+             && this_is_condjump && ! this_is_simplejump
+             && BRANCH_COST >= 4
+             && (temp = next_nonnote_insn (insn)) != 0
+             && GET_CODE (temp) == INSN
+             && REG_NOTES (temp) == 0
+             && (temp3 = next_nonnote_insn (temp)) != 0
+             && GET_CODE (temp3) == INSN
+             && REG_NOTES (temp3) == 0
+             && (reallabelprev == temp3
+                 || ((temp2 = next_active_insn (temp3)) != 0
+                     && simplejump_p (temp2)
+                     && JUMP_LABEL (temp2) == JUMP_LABEL (insn)))
+             && (temp1 = single_set (temp)) != 0
+             && (temp2 = SET_DEST (temp1), GET_CODE (temp2) == REG)
+             && GET_MODE_CLASS (GET_MODE (temp2)) == MODE_INT
+#ifdef SMALL_REGISTER_CLASSES
+             && REGNO (temp2) >= FIRST_PSEUDO_REGISTER
+#endif
+             && ! side_effects_p (SET_SRC (temp1))
+             && ! may_trap_p (SET_SRC (temp1))
+             && rtx_cost (SET_SRC (temp1)) < 10
+             && (temp4 = single_set (temp3)) != 0
+             && rtx_equal_p (SET_DEST (temp4), temp2)
+             && ! side_effects_p (SET_SRC (temp4))
+             && ! may_trap_p (SET_SRC (temp4))
+             && rtx_cost (SET_SRC (temp4)) < 10)
+           {
+             rtx new = gen_reg_rtx (GET_MODE (temp2));
+
+             if (validate_change (temp, &SET_DEST (temp1), new, 0))
+               {
+                 next = emit_insn_after (gen_move_insn (temp2, new), insn);
+                 emit_insn_after_with_line_notes (PATTERN (temp),
+                                                  PREV_INSN (insn), temp);
+                 emit_insn_after_with_line_notes
+                   (replace_rtx (PATTERN (temp3), temp2, new),
+                    PREV_INSN (insn), temp3);
+                 delete_insn (temp);
+                 delete_insn (temp3);
+               }
+           }
+
+         /* Finally, handle the case where two insns are used to 
+            compute EXP but a temporary register is used.  Here we must
+            ensure that the temporary register is not used anywhere else. */
+
+         if (! reload_completed
+             && after_regscan
+             && this_is_condjump && ! this_is_simplejump
+             && BRANCH_COST >= 4
+             && (temp = next_nonnote_insn (insn)) != 0
+             && GET_CODE (temp) == INSN
+             && REG_NOTES (temp) == 0
+             && (temp3 = next_nonnote_insn (temp)) != 0
+             && GET_CODE (temp3) == INSN
+             && REG_NOTES (temp3) == 0
+             && (reallabelprev == temp3
+                 || ((temp2 = next_active_insn (temp3)) != 0
+                     && simplejump_p (temp2)
+                     && JUMP_LABEL (temp2) == JUMP_LABEL (insn)))
+             && (temp1 = single_set (temp)) != 0
+             && (temp5 = SET_DEST (temp1), GET_CODE (temp5) == REG)
+             && REGNO (temp5) >= FIRST_PSEUDO_REGISTER
+             && regno_first_uid[REGNO (temp5)] == INSN_UID (temp)
+             && regno_last_uid[REGNO (temp5)] == INSN_UID (temp3)
+             && ! side_effects_p (SET_SRC (temp1))
+             && ! may_trap_p (SET_SRC (temp1))
+             && rtx_cost (SET_SRC (temp1)) < 10
+             && (temp4 = single_set (temp3)) != 0
+             && (temp2 = SET_DEST (temp4), GET_CODE (temp2) == REG)
+             && GET_MODE_CLASS (GET_MODE (temp2)) == MODE_INT
+#ifdef SMALL_REGISTER_CLASSES
+             && REGNO (temp2) >= FIRST_PSEUDO_REGISTER
+#endif
+             && rtx_equal_p (SET_DEST (temp4), temp2)
+             && ! side_effects_p (SET_SRC (temp4))
+             && ! may_trap_p (SET_SRC (temp4))
+             && rtx_cost (SET_SRC (temp4)) < 10)
+           {
+             rtx new = gen_reg_rtx (GET_MODE (temp2));
+
+             if (validate_change (temp3, &SET_DEST (temp4), new, 0))
+               {
+                 next = emit_insn_after (gen_move_insn (temp2, new), insn);
+                 emit_insn_after_with_line_notes (PATTERN (temp),
+                                                  PREV_INSN (insn), temp);
+                 emit_insn_after_with_line_notes (PATTERN (temp3),
+                                                  PREV_INSN (insn), temp3);
+                 delete_insn (temp);
+                 delete_insn (temp3);
+               }
+           }
+#endif /* HAVE_cc0 */
+
+         /* We deal with four cases:
+
+            1) x = a; if (...) x = b; and either A or B is zero,
+            2) if (...) x = 0; and jumps are expensive,
+            3) x = a; if (...) x = b; and A and B are constants where all the
+               set bits in A are also set in B and jumps are expensive, and
+            4) x = a; if (...) x = b; and A and B non-zero, and jumps are
+               more expensive.
+            5) if (...) x = b; if jumps are even more expensive.
+
+            In each of these try to use a store-flag insn to avoid the jump.
+            (If the jump would be faster, the machine should not have
+            defined the scc insns!).  These cases are often made by the
+            previous optimization.
 
             INSN here is the jump around the store.  We set:
 
@@ -832,18 +1003,23 @@ jump_optimize (f, cross_jump, noop_moves, after_regscan)
 #endif
              && GET_MODE_CLASS (GET_MODE (temp1)) == MODE_INT
              && (GET_CODE (temp2 = SET_SRC (PATTERN (temp))) == REG
+                 || GET_CODE (temp2) == SUBREG
                  || GET_CODE (temp2) == CONST_INT)
-             /* Allow either form, but prefer the former if both apply.  */
+             /* Allow either form, but prefer the former if both apply. 
+                There is no point in using the old value of TEMP1 if
+                it is a register, since cse will alias them.  It can
+                lose if the old value were a hard register since CSE
+                won't replace hard registers.  */
              && (((temp3 = reg_set_last (temp1, insn)) != 0
-                  && ((GET_CODE (temp3) == REG
-#ifdef SMALL_REGISTER_CLASSES
-                       && REGNO (temp3) >= FIRST_PSEUDO_REGISTER
-#endif
-                       )
-                      || GET_CODE (temp3) == CONST_INT))
+                  && GET_CODE (temp3) == CONST_INT)
                  /* Make the latter case look like  x = x; if (...) x = 0;  */
-                 || ((temp3 = temp1, BRANCH_COST > 1)
-                     && temp2 == const0_rtx))
+                 || (temp3 = temp1,
+                     ((BRANCH_COST >= 2
+                       && temp2 == const0_rtx)
+#ifdef HAVE_conditional_move
+                      || 1
+#endif
+                      || BRANCH_COST >= 3)))
              /* INSN must either branch to the insn after TEMP or the insn
                 after TEMP must branch to the same place as INSN.  */
              && (reallabelprev == temp
@@ -851,34 +1027,66 @@ jump_optimize (f, cross_jump, noop_moves, after_regscan)
                      && simplejump_p (temp4)
                      && JUMP_LABEL (temp4) == JUMP_LABEL (insn)))
              && (temp4 = get_condition (insn, &temp5)) != 0
-
-             /* If B is zero, OK; if A is zero, can only do this if we
-                can reverse the condition.  */
-             && (temp2 == const0_rtx
+             /* 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 (temp4, 0)) != BLKmode
+
+             /* If B is zero, OK; if A is zero, can only do (1) if we
+                can reverse the condition.  See if (3) applies possibly
+                by reversing the condition.  Prefer reversing to (4) when
+                branches are very expensive.  */
+             && ((reversep = 0, temp2 == const0_rtx)
                  || (temp3 == const0_rtx
-                     && (can_reverse_comparison_p (temp4, insn)))))
+                     && (reversep = can_reverse_comparison_p (temp4, insn)))
+                 || (BRANCH_COST >= 2
+                     && GET_CODE (temp2) == CONST_INT
+                     && GET_CODE (temp3) == CONST_INT
+                     && ((INTVAL (temp2) & INTVAL (temp3)) == INTVAL (temp2)
+                         || ((INTVAL (temp2) & INTVAL (temp3)) == INTVAL (temp3)
+                             && (reversep = can_reverse_comparison_p (temp4,
+                                                                      insn)))))
+#ifdef HAVE_conditional_move
+                 || 1
+#endif
+                 || BRANCH_COST >= 3)
+#ifdef HAVE_cc0
+             /* If the previous insn sets CC0 and something else, we can't
+                do this since we are going to delete that insn.  */
+
+             && ! ((temp6 = prev_nonnote_insn (insn)) != 0
+                   && GET_CODE (temp6) == INSN
+                   && (sets_cc0_p (PATTERN (temp6)) == -1
+                       || (sets_cc0_p (PATTERN (temp6)) == 1
+                           && FIND_REG_INC_NOTE (temp6, NULL_RTX))))
+#endif
+             )
            {
              enum rtx_code code = GET_CODE (temp4);
-             rtx yes = temp3, var = temp1;
+             rtx uval, cval, var = temp1;
              int normalizep;
              rtx target;
 
              /* If necessary, reverse the condition.  */
-             if (temp3 == const0_rtx)
-               code = reverse_condition (code), yes = temp2;
+             if (reversep)
+               code = reverse_condition (code), uval = temp2, cval = temp3;
+             else
+               uval = temp3, cval = temp2;
 
              /* See if we can do this with a store-flag insn. */
              start_sequence ();
 
-             /* If YES is the constant 1, it is best to just compute
-                the result directly.  If YES is constant and STORE_FLAG_VALUE
+             /* If CVAL is non-zero, normalize to -1.  Otherwise,
+                if UVAL is the constant 1, it is best to just compute
+                the result directly.  If UVAL is constant and STORE_FLAG_VALUE
                 includes all of its bits, it is best to compute the flag
-                value unnormalized and `and' it with YES.  Otherwise,
-                normalize to -1 and `and' with YES.  */
-             normalizep = (yes == const1_rtx ? 1
-                           : (GET_CODE (yes) == CONST_INT
-                              && (INTVAL (yes) & ~ STORE_FLAG_VALUE) == 0) ? 0
-                           : -1);
+                value unnormalized and `and' it with UVAL.  Otherwise,
+                normalize to -1 and `and' with UVAL.  */
+             normalizep = (cval != const0_rtx ? -1
+                           : (uval == const1_rtx ? 1
+                              : (GET_CODE (uval) == CONST_INT
+                                 && (INTVAL (uval) & ~STORE_FLAG_VALUE) == 0)
+                              ? 0 : -1));
 
              /* We will be putting the store-flag insn immediately in
                 front of the comparison that was originally being done,
@@ -898,22 +1106,90 @@ jump_optimize (f, cross_jump, noop_moves, after_regscan)
                                        normalizep);
              if (target)
                {
+                 rtx before = insn;
                  rtx seq;
 
-                 if (normalizep != 1)
-                   target = expand_and (yes, target,
-                                        (GET_CODE (target) == REG
-                                         ? target : 0));
-                 seq = gen_sequence ();
+                 /* Put the store-flag insns in front of the first insn
+                    used to compute the condition to ensure that we
+                    use the same values of them as the current 
+                    comparison.  However, the remainder of the insns we
+                    generate will be placed directly in front of the
+                    jump insn, in case any of the pseudos we use
+                    are modified earlier.  */
+
+                 seq = get_insns ();
                  end_sequence ();
-                 emit_insn_before (seq, temp5);
-                 emit_insn_after (gen_move_insn (var, target), insn);
-                 delete_insn (temp);
-                 next = NEXT_INSN (insn);
+
+                 emit_insns_before (seq, temp5);
+
+                 start_sequence ();
+
+                 /* Both CVAL and UVAL are non-zero.  */
+                 if (cval != const0_rtx && uval != const0_rtx)
+                   {
+                     rtx tem1, tem2;
+
+                     tem1 = expand_and (uval, target, NULL_RTX);
+                     if (GET_CODE (cval) == CONST_INT
+                         && GET_CODE (uval) == CONST_INT
+                         && (INTVAL (cval) & INTVAL (uval)) == INTVAL (cval))
+                       tem2 = cval;
+                     else
+                       {
+                         tem2 = expand_unop (GET_MODE (var), one_cmpl_optab,
+                                             target, NULL_RTX, 0);
+                         tem2 = expand_and (cval, tem2,
+                                            (GET_CODE (tem2) == REG
+                                             ? tem2 : 0));
+                       }
+
+                     /* If we usually make new pseudos, do so here.  This
+                        turns out to help machines that have conditional
+                        move insns.  */
+
+                     if (flag_expensive_optimizations)
+                       target = 0;
+
+                     target = expand_binop (GET_MODE (var), ior_optab,
+                                            tem1, tem2, target,
+                                            1, OPTAB_WIDEN);
+                   }
+                 else if (normalizep != 1)
+                   {
+                     /* We know that either CVAL or UVAL is zero.  If
+                        UVAL is zero, negate TARGET and `and' with CVAL.
+                        Otherwise, `and' with UVAL.  */
+                     if (uval == const0_rtx)
+                       {
+                         target = expand_unop (GET_MODE (var), one_cmpl_optab,
+                                               target, NULL_RTX, 0);
+                         uval = cval;
+                       }
+
+                     target = expand_and (uval, target,
+                                          (GET_CODE (target) == REG
+                                           && ! preserve_subexpressions_p ()
+                                           ? target : NULL_RTX));
+                   }
+                 
+                 emit_move_insn (var, target);
+                 seq = get_insns ();
+                 end_sequence ();
+
 #ifdef HAVE_cc0
-                 delete_insn (prev_nonnote_insn (insn));
+                 /* If INSN uses CC0, we must not separate it from the
+                    insn that sets cc0.  */
+
+                 if (reg_mentioned_p (cc0_rtx, PATTERN (before)))
+                   before = prev_nonnote_insn (before);
 #endif
-                 delete_insn (insn);
+
+                 emit_insns_before (seq, before);
+
+                 delete_insn (temp);
+                 next = NEXT_INSN (insn);
+
+                 delete_jump (insn);
                  changed = 1;
                  continue;
                }
@@ -928,12 +1204,19 @@ jump_optimize (f, cross_jump, noop_moves, after_regscan)
             INSN is the conditional branch around the arithmetic.  We set:
 
             TEMP is the arithmetic insn.
-            TEMP1 is the SET doing the arthmetic.
+            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
+         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
@@ -951,18 +1234,43 @@ jump_optimize (f, cross_jump, noop_moves, after_regscan)
                      && 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 target, seq;
+             rtx temp6, target = 0, seq, init_insn = 0, init = temp2;
              enum rtx_code code = reverse_condition (GET_CODE (temp3));
 
              start_sequence ();
 
-             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);
+             /* 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
+                 && 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.  */
@@ -971,7 +1279,7 @@ jump_optimize (f, cross_jump, noop_moves, after_regscan)
                target = expand_binop (GET_MODE (temp2),
                                       (XEXP (SET_SRC (temp1), 1) == const1_rtx
                                        ? add_optab : sub_optab),
-                                      temp2, target, temp2, OPTAB_WIDEN);
+                                      temp2, target, temp2, 0, OPTAB_WIDEN);
 
              if (target != 0)
                {
@@ -988,6 +1296,10 @@ jump_optimize (f, cross_jump, noop_moves, after_regscan)
 
                  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));
@@ -1110,7 +1422,7 @@ jump_optimize (f, cross_jump, noop_moves, after_regscan)
 
             It is questionable whether we want this optimization anyways,
             since if the user wrote code like this because he/she knew that
-            the jump to label1 is taken most of the time, then rewritting
+            the jump to label1 is taken most of the time, then rewriting
             this gives slower code.  */
          /* @@ This should call get_condition to find the values being
             compared, instead of looking for a COMPARE insn when HAVE_cc0
@@ -1418,17 +1730,19 @@ jump_optimize (f, cross_jump, noop_moves, after_regscan)
 
                        /* Include in each range any line number before it.  */
                        while (PREV_INSN (range1beg)
-                              && GET_CODE (PREV_INSN (range1beg)) == NOTE)
+                              && GET_CODE (PREV_INSN (range1beg)) == NOTE
+                              && NOTE_LINE_NUMBER (PREV_INSN (range1beg)) > 0)
                          range1beg = PREV_INSN (range1beg);
 
                        while (PREV_INSN (range2beg)
-                              && GET_CODE (PREV_INSN (range2beg)) == NOTE)
+                              && GET_CODE (PREV_INSN (range2beg)) == NOTE
+                              && NOTE_LINE_NUMBER (PREV_INSN (range2beg)) > 0)
                          range2beg = PREV_INSN (range2beg);
 
                        /* Don't move NOTEs for blocks or loops; shift them
                           outside the ranges, where they'll stay put.  */
-                       squeeze_notes (range1beg, range1end);
-                       squeeze_notes (range2beg, range2end);
+                       range1beg = squeeze_notes (range1beg, range1end);
+                       range2beg = squeeze_notes (range2beg, range2end);
 
                        /* Get current surrounds of the 2 ranges.  */
                        range1before = PREV_INSN (range1beg);
@@ -1692,8 +2006,8 @@ duplicate_loop_exit_test (loop_start)
        case JUMP_INSN:
        case INSN:
          if (++num_insns > 20
-             || find_reg_note (insn, REG_RETVAL, 0)
-             || find_reg_note (insn, REG_LIBCALL, 0))
+             || find_reg_note (insn, REG_RETVAL, NULL_RTX)
+             || find_reg_note (insn, REG_LIBCALL, NULL_RTX))
            return 0;
          break;
        }
@@ -1822,10 +2136,12 @@ duplicate_loop_exit_test (loop_start)
 }
 \f
 /* Move all block-beg, block-end, loop-beg, loop-cont, loop-vtop, and
-   loop-end notes between START and END out before START.  Assume neither
-   START nor END is such a note.  */
+   loop-end notes between START and END out before START.  Assume that
+   END is not such a note.  START may be such a note.  Returns the value
+   of the new starting insn, which may be different if the original start
+   was such a note.  */
 
-void
+rtx
 squeeze_notes (start, end)
      rtx start, end;
 {
@@ -1843,15 +2159,22 @@ squeeze_notes (start, end)
              || NOTE_LINE_NUMBER (insn) == NOTE_INSN_LOOP_CONT
              || NOTE_LINE_NUMBER (insn) == NOTE_INSN_LOOP_VTOP))
        {
-         rtx prev = PREV_INSN (insn);
-         PREV_INSN (insn) = PREV_INSN (start);
-         NEXT_INSN (insn) = start;
-         NEXT_INSN (PREV_INSN (insn)) = insn;
-         PREV_INSN (NEXT_INSN (insn)) = insn;
-         NEXT_INSN (prev) = next;
-         PREV_INSN (next) = prev;
+         if (insn == start)
+           start = next;
+         else
+           {
+             rtx prev = PREV_INSN (insn);
+             PREV_INSN (insn) = PREV_INSN (start);
+             NEXT_INSN (insn) = start;
+             NEXT_INSN (PREV_INSN (insn)) = insn;
+             PREV_INSN (NEXT_INSN (insn)) = insn;
+             NEXT_INSN (prev) = next;
+             PREV_INSN (next) = prev;
+           }
        }
     }
+
+  return start;
 }
 \f
 /* Compare the instructions before insn E1 with those before E2
@@ -1961,10 +2284,10 @@ find_cross_jump (e1, e2, minimum, f1, f2)
          rtx equiv2;
 
          if (!lose && GET_CODE (p1) == GET_CODE (p2)
-             && ((equiv1 = find_reg_note (i1, REG_EQUAL, 0)) != 0
-                 || (equiv1 = find_reg_note (i1, REG_EQUIV, 0)) != 0)
-             && ((equiv2 = find_reg_note (i2, REG_EQUAL, 0)) != 0
-                 || (equiv2 = find_reg_note (i2, REG_EQUIV, 0)) != 0)
+             && ((equiv1 = find_reg_note (i1, REG_EQUAL, NULL_RTX)) != 0
+                 || (equiv1 = find_reg_note (i1, REG_EQUIV, NULL_RTX)) != 0)
+             && ((equiv2 = find_reg_note (i2, REG_EQUAL, NULL_RTX)) != 0
+                 || (equiv2 = find_reg_note (i2, REG_EQUIV, NULL_RTX)) != 0)
              /* If the equivalences are not to a constant, they may
                 reference pseudos that no longer exist, so we can't
                 use them.  */
@@ -2113,7 +2436,7 @@ get_label_before (insn)
     {
       rtx prev = PREV_INSN (insn);
 
-      /* Don't put a label between a CALL_INSN and USE insns that preceed
+      /* Don't put a label between a CALL_INSN and USE insns that precede
         it.  */
 
       if (GET_CODE (insn) == CALL_INSN
@@ -2646,12 +2969,22 @@ mark_jump_label (x, insn, cross_jump)
     case CALL:
       return;
 
+    case MEM:
+      /* 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);
+      break;
+
     case LABEL_REF:
       {
        register rtx label = XEXP (x, 0);
        register rtx next;
        if (GET_CODE (label) != CODE_LABEL)
          abort ();
+       /* Ignore references to labels of containing functions.  */
+       if (LABEL_REF_NONLOCAL_P (x))
+         break;
        /* If there are other labels following this one,
           replace it with the last of the consecutive labels.  */
        for (next = NEXT_INSN (label); next; next = NEXT_INSN (next))
@@ -2686,8 +3019,13 @@ mark_jump_label (x, insn, cross_jump)
                    || ! (GET_CODE (next) == JUMP_INSN
                          && (GET_CODE (PATTERN (next)) == ADDR_VEC
                              || GET_CODE (PATTERN (next)) == ADDR_DIFF_VEC)))
-                 REG_NOTES (insn) = gen_rtx (EXPR_LIST, REG_LABEL, label,
-                                             REG_NOTES (insn));
+                 {
+                   REG_NOTES (insn) = gen_rtx (EXPR_LIST, REG_LABEL, label,
+                                               REG_NOTES (insn));
+                   /* Record in the note whether label is nonlocal.  */
+                   LABEL_REF_NONLOCAL_P (REG_NOTES (insn))
+                     = LABEL_REF_NONLOCAL_P (x);
+                 }
              }
          }
        return;
@@ -2701,7 +3039,7 @@ 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), 0, cross_jump);
+         mark_jump_label (XVECEXP (x, eltnum, i), NULL_RTX, cross_jump);
        return;
       }
     }
@@ -2728,14 +3066,35 @@ void
 delete_jump (insn)
      rtx insn;
 {
-  register rtx x = PATTERN (insn);
-  register rtx prev;
+  register rtx set = single_set (insn);
+
+  if (set && GET_CODE (SET_DEST (set)) == PC)
+    delete_computation (insn);
+}
+
+/* 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
+   delete dead code.  We also can't know if the registers being used are
+   dead or not at this point.
+
+   Otherwise, look at all our REG_DEAD notes.  If a previous insn does
+   nothing other than set a register that dies in this insn, we can delete
+   that insn as well.
+
+   On machines with CC0, if CC0 is used in this insn, we may be able to
+   delete the insn that set it.  */
+
+void
+delete_computation (insn)
+     rtx insn;
+{
+  rtx note, next;
 
-  if (GET_CODE (x) == SET
-      && GET_CODE (SET_DEST (x)) == PC)
-    {
-      prev = prev_nonnote_insn (insn);
 #ifdef HAVE_cc0
+  if (reg_referenced_p (cc0_rtx, PATTERN (insn)))
+    {
+      rtx prev = prev_nonnote_insn (insn);
       /* We assume that at this stage
         CC's are always set explicitly
         and always immediately before the jump that
@@ -2746,94 +3105,87 @@ delete_jump (insn)
          && sets_cc0_p (PATTERN (prev)))
        {
          if (sets_cc0_p (PATTERN (prev)) > 0
-             && !FIND_REG_INC_NOTE (prev, 0))
-           delete_insn (prev);
+             && !FIND_REG_INC_NOTE (prev, NULL_RTX))
+           delete_computation (prev);
          else
            /* Otherwise, show that cc0 won't be used.  */
            REG_NOTES (prev) = gen_rtx (EXPR_LIST, REG_UNUSED,
                                        cc0_rtx, REG_NOTES (prev));
        }
-#else
-      {
-       rtx note;
-
-       /* If we are running before flow.c, we need do nothing since flow.c
-          will delete the set of the condition code if it is dead.  We also
-          can't know if the register being used as the condition code is
-          dead or not at this point.
+    }
+#endif
 
-          Otherwise, look at all our REG_DEAD notes.  If a previous insn
-          does nothing other than set a register that dies in this jump,
-          we can delete the insn.  */
+  for (note = REG_NOTES (insn); note; note = next)
+    {
+      rtx our_prev;
 
-       for (note = REG_NOTES (insn); note; note = XEXP (note, 1))
-         {
-           rtx our_prev;
+      next = XEXP (note, 1);
 
-           if (REG_NOTE_KIND (note) != REG_DEAD
-               /* Verify that the REG_NOTE has a legal value.  */
-               || GET_CODE (XEXP (note, 0)) != REG)
-             continue;
+      if (REG_NOTE_KIND (note) != REG_DEAD
+         /* Verify that the REG_NOTE is legitimate.  */
+         || 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;
+      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 (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, 0))
-                     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.  */
+             if (GET_CODE (PATTERN (our_prev)) == PARALLEL)
+               {
+                 /* If we find a SET of something else, we can't
+                    delete the insn.  */
 
-                       int i;
+                 int i;
 
-                       for (i = 0; i < XVECLEN (PATTERN (our_prev), 0); i++)
-                         {
-                           rtx part = XVECEXP (PATTERN (our_prev), 0, 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 (GET_CODE (part) == SET
+                         && SET_DEST (part) != XEXP (note, 0))
+                       break;
+                   }
 
-                       if (i == XVECLEN (PATTERN (our_prev), 0))
-                         delete_insn (our_prev);
-                     }
-                   else if (GET_CODE (PATTERN (our_prev)) == SET
-                            && SET_DEST (PATTERN (our_prev)) == XEXP (note, 0))
-                     delete_insn (our_prev);
+                 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;
-                 }
+             break;
+           }
 
-               /* If OUR_PREV references the register that dies here,
-                  it is an additional use.  Hence any prior SET isn't
-                  dead.  */
-               if (reg_overlap_mentioned_p (XEXP (note, 0),
-                                            PATTERN (our_prev)))
-                 break;
-             }
-         }
-      }
-#endif
-      /* Now delete the jump insn itself.  */
-      delete_insn (insn);
+         /* 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_insn (insn);
 }
 \f
 /* Delete insn INSN from the chain of insns and update label ref counts.
@@ -2848,6 +3200,8 @@ delete_insn (insn)
 {
   register rtx next = NEXT_INSN (insn);
   register rtx prev = PREV_INSN (insn);
+  register int was_code_label = (GET_CODE (insn) == CODE_LABEL);
+  register int dont_really_delete = 0;
 
   while (next && INSN_DELETED_P (next))
     next = NEXT_INSN (next);
@@ -2856,9 +3210,19 @@ delete_insn (insn)
   if (INSN_DELETED_P (insn))
     return next;
 
-  /* Mark this insn as deleted.  */
-
-  INSN_DELETED_P (insn) = 1;
+  /* Don't delete user-declared labels.  Convert them to special NOTEs
+     instead.  */
+  if (was_code_label && LABEL_NAME (insn) != 0
+      && optimize && ! 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.  */
+    INSN_DELETED_P (insn) = 1;
 
   /* If this is an unconditional jump, delete it from the jump chain.  */
   if (simplejump_p (insn))
@@ -2875,7 +3239,7 @@ delete_insn (insn)
 
   /* Patch out INSN (and the barrier if any) */
 
-  if (optimize)
+  if (optimize && ! dont_really_delete)
     {
       if (prev)
        {
@@ -2922,7 +3286,7 @@ delete_insn (insn)
      delete the dispatch table.  The tablejump must have gone already.
      It isn't useful to fall through into a table.  */
 
-  if (GET_CODE (insn) == CODE_LABEL
+  if (was_code_label
       && NEXT_INSN (insn) != 0
       && GET_CODE (NEXT_INSN (insn)) == JUMP_INSN
       && (GET_CODE (PATTERN (NEXT_INSN (insn))) == ADDR_VEC
@@ -2931,18 +3295,21 @@ delete_insn (insn)
 
   /* If INSN was a label, delete insns following it if now unreachable.  */
 
-  if (GET_CODE (insn) == CODE_LABEL && prev
-      && GET_CODE (prev) == BARRIER)
+  if (was_code_label && prev && GET_CODE (prev) == BARRIER)
     {
       register RTX_CODE code;
       while (next != 0
             && ((code = GET_CODE (next)) == INSN
                 || code == JUMP_INSN || code == CALL_INSN
-                || code == NOTE))
+                || code == NOTE
+                || (code == CODE_LABEL && INSN_DELETED_P (next))))
        {
          if (code == NOTE
              && NOTE_LINE_NUMBER (next) != NOTE_INSN_FUNCTION_END)
            next = NEXT_INSN (next);
+         /* Keep going past other deleted labels to delete what follows.  */
+         else if (code == CODE_LABEL && INSN_DELETED_P (next))
+           next = NEXT_INSN (next);
          else
            /* Note: if this deletes a jump, it can cause more
               deletion of unreachable code, after a different label.
@@ -3040,7 +3407,7 @@ invert_jump (jump, nlabel)
    Return 1 if we can do so, 0 if we cannot find a way to do so that
    matches a pattern.  */
 
-static int
+int
 invert_exp (x, insn)
      rtx x;
      rtx insn;
@@ -3188,7 +3555,7 @@ delete_from_jump_chain (jump)
    Return 0 if we found a change we would like to make but it is invalid.
    Otherwise, return 1.  */
 
-static int
+int
 redirect_exp (loc, olabel, nlabel, insn)
      rtx *loc;
      rtx olabel, nlabel;
@@ -3245,7 +3612,7 @@ redirect_exp (loc, olabel, nlabel, insn)
 
    If the old jump target label (before the dispatch table) becomes unused,
    it and the dispatch table may be deleted.  In that case, find the insn
-   before the jump references that label and delete it and logical sucessors
+   before the jump references that label and delete it and logical successors
    too.  */
 
 void
@@ -3384,6 +3751,9 @@ rtx_renumbered_equal_p (x, y)
       return XINT (x, 0) == XINT (y, 0);
 
     case LABEL_REF:
+      /* We can't assume nonlocal labels have their following insns yet.  */
+      if (LABEL_REF_NONLOCAL_P (x) || LABEL_REF_NONLOCAL_P (y))
+       return XEXP (x, 0) == XEXP (y, 0);
       /* Two label-refs are equivalent if they point at labels
         in the same position in the instruction stream.  */
       return (next_real_insn (XEXP (x, 0))
@@ -3407,6 +3777,11 @@ rtx_renumbered_equal_p (x, y)
       register int j;
       switch (fmt[i])
        {
+       case 'w':
+         if (XWINT (x, i) != XWINT (y, i))
+           return 0;
+         break;
+
        case 'i':
          if (XINT (x, i) != XINT (y, i))
            return 0;
@@ -3498,7 +3873,7 @@ true_regnum (x)
    pending equivalences.  If nonzero, the expressions really aren't the
    same.  */
 
-static short *same_regs;
+static int *same_regs;
 
 static int num_same_regs;
 
@@ -3561,12 +3936,12 @@ thread_jumps (f, max_reg, verbose)
   rtx b1op0, b1op1, b2op0, b2op1;
   int changed = 1;
   int i;
-  short *all_reset;
+  int *all_reset;
 
   /* Allocate register tables and quick-reset table.  */
   modified_regs = (char *) alloca (max_reg * sizeof (char));
-  same_regs = (short *) alloca (max_reg * sizeof (short));
-  all_reset = (short *) alloca (max_reg * sizeof (short));
+  same_regs = (int *) alloca (max_reg * sizeof (int));
+  all_reset = (int *) alloca (max_reg * sizeof (int));
   for (i = 0; i < max_reg; i++)
     all_reset[i] = -1;
     
@@ -3585,7 +3960,7 @@ thread_jumps (f, max_reg, verbose)
          bzero (modified_regs, max_reg * sizeof (char));
          modified_mem = 0;
 
-         bcopy (all_reset, same_regs, max_reg * sizeof (short));
+         bcopy (all_reset, same_regs, max_reg * sizeof (int));
          num_same_regs = 0;
 
          label = JUMP_LABEL (b1);
@@ -3771,7 +4146,7 @@ rtx_equal_for_thread_p (x, y, yinsn)
       break;
 
     case MEM:
-      /* If memory modified or either volatile, not eqivalent.
+      /* If memory modified or either volatile, not equivalent.
         Else, check address. */
       if (modified_mem || MEM_VOLATILE_P (x) || MEM_VOLATILE_P (y))
        return 0;
@@ -3819,6 +4194,11 @@ rtx_equal_for_thread_p (x, y, yinsn)
     {
       switch (fmt[i])
        {
+       case 'w':
+         if (XWINT (x, i) != XWINT (y, i))
+           return 0;
+         break;
+
        case 'n':
        case 'i':
          if (XINT (x, i) != XINT (y, i))