OSDN Git Service

* flow.c (find_unreachable_blocks): New function.
[pf3gnuchains/gcc-fork.git] / gcc / cse.c
index f89067a..43cbf9c 100644 (file)
--- a/gcc/cse.c
+++ b/gcc/cse.c
@@ -1,6 +1,6 @@
 /* Common subexpression elimination for GNU compiler.
    Copyright (C) 1987, 1988, 1989, 1992, 1993, 1994, 1995, 1996, 1997, 1998
-   1999, 2000 Free Software Foundation, Inc.
+   1999, 2000, 2001 Free Software Foundation, Inc.
 
 This file is part of GNU CC.
 
@@ -382,11 +382,14 @@ static int cse_altered;
 
 static int cse_jumps_altered;
 
-/* Nonzero if we put a LABEL_REF into the hash table.  Since we may have put
-   it into an INSN without a REG_LABEL, we have to rerun jump after CSE
-   to put in the note.  */
+/* Nonzero if we put a LABEL_REF into the hash table for an INSN without a
+   REG_LABEL, we have to rerun jump after CSE to put in the note.  */
 static int recorded_label_ref;
 
+/* Says which LABEL_REF was put in the hash table.  Used to see if we need
+   to set the above flag.  */
+static rtx new_label_ref;
+
 /* canon_hash stores 1 in do_not_record
    if it notices a reference to CC0, PC, or some other volatile
    subexpression.  */
@@ -656,7 +659,7 @@ static struct table_elt *insert PARAMS ((rtx, struct table_elt *, unsigned,
 static void merge_equiv_classes PARAMS ((struct table_elt *,
                                         struct table_elt *));
 static void invalidate         PARAMS ((rtx, enum machine_mode));
-static int cse_rtx_varies_p    PARAMS ((rtx));
+static int cse_rtx_varies_p    PARAMS ((rtx, int));
 static void remove_invalid_refs        PARAMS ((unsigned int));
 static void remove_invalid_subreg_refs PARAMS ((unsigned int, unsigned int,
                                                 enum machine_mode));
@@ -1217,11 +1220,11 @@ mention_regs (x)
          /* If reg_tick has been incremented more than once since
             reg_in_table was last set, that means that the entire
             register has been set before, so discard anything memorized
-            for the entrire register, including all SUBREG expressions.  */
+            for the entire register, including all SUBREG expressions.  */
          if (REG_IN_TABLE (i) != REG_TICK (i) - 1)
            remove_invalid_refs (i);
          else
-           remove_invalid_subreg_refs (i, SUBREG_WORD (x), GET_MODE (x));
+           remove_invalid_subreg_refs (i, SUBREG_BYTE (x), GET_MODE (x));
        }
 
       REG_IN_TABLE (i) = REG_TICK (i);
@@ -1242,7 +1245,7 @@ mention_regs (x)
     {
       if (GET_CODE (XEXP (x, 0)) == REG
          && ! REGNO_QTY_VALID_P (REGNO (XEXP (x, 0))))
-       if (insert_regs (XEXP (x, 0), NULL_PTR, 0))
+       if (insert_regs (XEXP (x, 0), NULL, 0))
          {
            rehash_using_reg (XEXP (x, 0));
            changed = 1;
@@ -1250,7 +1253,7 @@ mention_regs (x)
 
       if (GET_CODE (XEXP (x, 1)) == REG
          && ! REGNO_QTY_VALID_P (REGNO (XEXP (x, 1))))
-       if (insert_regs (XEXP (x, 1), NULL_PTR, 0))
+       if (insert_regs (XEXP (x, 1), NULL, 0))
          {
            rehash_using_reg (XEXP (x, 1));
            changed = 1;
@@ -1343,7 +1346,7 @@ insert_regs (x, classp, modified)
   else if (GET_CODE (x) == SUBREG && GET_CODE (SUBREG_REG (x)) == REG
           && ! REGNO_QTY_VALID_P (REGNO (SUBREG_REG (x))))
     {
-      insert_regs (SUBREG_REG (x), NULL_PTR, 0);
+      insert_regs (SUBREG_REG (x), NULL, 0);
       mention_regs (x);
       return 1;
     }
@@ -1581,7 +1584,7 @@ insert (x, classp, hash, mode)
   if (GET_CODE (x) == LABEL_REF
       || (GET_CODE (x) == CONST && GET_CODE (XEXP (x, 0)) == PLUS
          && GET_CODE (XEXP (XEXP (x, 0), 0)) == LABEL_REF))
-    recorded_label_ref = 1;
+    new_label_ref = x;
 
   /* Put an element for X into the right hash bucket.  */
 
@@ -1721,7 +1724,7 @@ insert (x, classp, hash, mode)
          subhash = safe_hash (subexp, mode) & HASH_MASK;
          subelt = lookup (subexp, subhash, mode);
          if (subelt == 0)
-           subelt = insert (subexp, NULL_PTR, subhash, mode);
+           subelt = insert (subexp, NULL, subhash, mode);
          /* Initialize SUBELT's circular chain if it has none.  */
          if (subelt->related_value == 0)
            subelt->related_value = subelt;
@@ -1996,38 +1999,37 @@ remove_invalid_refs (regno)
       {
        next = p->next_same_hash;
        if (GET_CODE (p->exp) != REG
-           && refers_to_regno_p (regno, regno + 1, p->exp, NULL_PTR))
+           && refers_to_regno_p (regno, regno + 1, p->exp, (rtx*)0))
          remove_from_table (p, i);
       }
 }
 
-/* Likewise for a subreg with subreg_reg WORD and mode MODE.  */
+/* Likewise for a subreg with subreg_reg REGNO, subreg_byte OFFSET,
+   and mode MODE.  */
 static void
-remove_invalid_subreg_refs (regno, word, mode)
+remove_invalid_subreg_refs (regno, offset, mode)
      unsigned int regno;
-     unsigned int word;
+     unsigned int offset;
      enum machine_mode mode;
 {
   unsigned int i;
   struct table_elt *p, *next;
-  unsigned int end = word + (GET_MODE_SIZE (mode) - 1) / UNITS_PER_WORD;
+  unsigned int end = offset + (GET_MODE_SIZE (mode) - 1);
 
   for (i = 0; i < HASH_SIZE; i++)
     for (p = table[i]; p; p = next)
       {
-       rtx exp;
+       rtx exp = p->exp;
        next = p->next_same_hash;
 
-       exp = p->exp;
-       if (GET_CODE (p->exp) != REG
+       if (GET_CODE (exp) != REG
            && (GET_CODE (exp) != SUBREG
                || GET_CODE (SUBREG_REG (exp)) != REG
                || REGNO (SUBREG_REG (exp)) != regno
-               || (((SUBREG_WORD (exp)
-                     + (GET_MODE_SIZE (GET_MODE (exp)) - 1) / UNITS_PER_WORD)
-                    >= word)
-                   && SUBREG_WORD (exp) <= end))
-           && refers_to_regno_p (regno, regno + 1, p->exp, NULL_PTR))
+               || (((SUBREG_BYTE (exp)
+                     + (GET_MODE_SIZE (GET_MODE (exp)) - 1)) >= offset)
+                   && SUBREG_BYTE (exp) <= end))
+           && refers_to_regno_p (regno, regno + 1, p->exp, (rtx*)0))
          remove_from_table (p, i);
       }
 }
@@ -2299,7 +2301,8 @@ canon_hash (x, mode)
        if (GET_CODE (SUBREG_REG (x)) == REG)
          {
            hash += (((unsigned) SUBREG << 7)
-                    + REGNO (SUBREG_REG (x)) + SUBREG_WORD (x));
+                    + REGNO (SUBREG_REG (x))
+                    + (SUBREG_BYTE (x) / UNITS_PER_WORD));
            return hash;
          }
        break;
@@ -2691,8 +2694,9 @@ exp_equiv_p (x, y, validate, equal_values)
    against certain constants or near-constants.  */
 
 static int
-cse_rtx_varies_p (x)
+cse_rtx_varies_p (x, from_alias)
      register rtx x;
+     int from_alias;
 {
   /* We need not check for X and the equivalence class being of the same
      mode because if X is equivalent to a constant in some mode, it
@@ -2745,7 +2749,7 @@ cse_rtx_varies_p (x)
        return 0;
     }
 
-  return rtx_varies_p (x);
+  return rtx_varies_p (x, from_alias);
 }
 \f
 /* Canonicalize an expression:
@@ -2974,7 +2978,7 @@ find_best_addr (insn, loc, mode)
                     || exp_equiv_p (p->exp, p->exp, 1, 0))
                    && ((exp_cost = address_cost (p->exp, mode)) < best_addr_cost
                        || (exp_cost == best_addr_cost
-                           && (p->cost + 1) >> 1 < best_rtx_cost)))
+                           && ((p->cost + 1) >> 1) > best_rtx_cost)))
                  {
                    found_better = 1;
                    best_addr_cost = exp_cost;
@@ -3160,7 +3164,20 @@ find_comparison_args (code, parg1, parg2, pmode1, pmode2)
        p = lookup (arg1, safe_hash (arg1, GET_MODE (arg1)) & HASH_MASK,
                    GET_MODE (arg1));
       if (p)
-       p = p->first_same_value;
+       {
+         p = p->first_same_value;
+
+         /* If what we compare is already known to be constant, that is as
+            good as it gets.
+            We need to break the loop in this case, because otherwise we
+            can have an infinite loop when looking at a reg that is known
+            to be a constant which is the same as a comparison of a reg
+            against zero which appears later in the insn stream, which in
+            turn is constant and the same as the comparison of the first reg
+            against zero...  */
+         if (p->is_const)
+           break;
+       }
 
       for (; p; p = p->next_same_value)
        {
@@ -3237,15 +3254,16 @@ find_comparison_args (code, parg1, parg2, pmode1, pmode2)
       /* If we need to reverse the comparison, make sure that that is
         possible -- we can't necessarily infer the value of GE from LT
         with floating-point operands.  */
-      if (reverse_code && ! can_reverse_comparison_p (x, NULL_RTX))
-       break;
-
-      arg1 = XEXP (x, 0), arg2 = XEXP (x, 1);
-      if (GET_RTX_CLASS (GET_CODE (x)) == '<')
-       code = GET_CODE (x);
-
       if (reverse_code)
-       code = reverse_condition (code);
+       {
+         enum rtx_code reversed = reversed_comparison_code (x, NULL_RTX);
+         if (reversed == UNKNOWN)
+           break;
+         else code = reversed;
+       }
+      else if (GET_RTX_CLASS (GET_CODE (x)) == '<')
+       code = GET_CODE (x);
+      arg1 = XEXP (x, 0), arg2 = XEXP (x, 1);
     }
 
   /* Return our results.  Return the modes from before fold_rtx
@@ -3390,15 +3408,8 @@ fold_rtx (x, insn)
 
       if (folded_arg0 != SUBREG_REG (x))
        {
-         new = 0;
-
-         if (GET_MODE_CLASS (mode) == MODE_INT
-             && GET_MODE_SIZE (mode) == UNITS_PER_WORD
-             && GET_MODE (SUBREG_REG (x)) != VOIDmode)
-           new = operand_subword (folded_arg0, SUBREG_WORD (x), 0,
-                                  GET_MODE (SUBREG_REG (x)));
-         if (new == 0 && subreg_lowpart_p (x))
-           new = gen_lowpart_if_possible (mode, folded_arg0);
+         new = simplify_subreg (mode, folded_arg0,
+                                GET_MODE (SUBREG_REG (x)), SUBREG_BYTE (x));
          if (new)
            return new;
        }
@@ -3798,7 +3809,9 @@ fold_rtx (x, insn)
            if (validate_change (insn, &XEXP (x, i), replacements[j], 0))
              break;
 
-           if (code == NE || code == EQ || GET_RTX_CLASS (code) == 'c')
+           if (code == NE || code == EQ || GET_RTX_CLASS (code) == 'c'
+               || code == LTGT || code == UNEQ || code == ORDERED
+               || code == UNORDERED)
              {
                validate_change (insn, &XEXP (x, i), XEXP (x, 1 - i), 1);
                validate_change (insn, &XEXP (x, 1 - i), replacements[j], 1);
@@ -3830,7 +3843,9 @@ fold_rtx (x, insn)
      operand unless the first operand is also a constant integer.  Otherwise,
      place any constant second unless the first operand is also a constant.  */
 
-  if (code == EQ || code == NE || GET_RTX_CLASS (code) == 'c')
+  if (code == EQ || code == NE || GET_RTX_CLASS (code) == 'c'
+      || code == LTGT || code == UNEQ || code == ORDERED
+      || code == UNORDERED)
     {
       if (must_swap || (const_arg0
                        && (const_arg1 == 0
@@ -3891,15 +3906,15 @@ fold_rtx (x, insn)
       if (const_arg0 == 0 || const_arg1 == 0)
        {
          struct table_elt *p0, *p1;
-         rtx true = const_true_rtx, false = const0_rtx;
+         rtx true_rtx = const_true_rtx, false_rtx = const0_rtx;
          enum machine_mode mode_arg1;
 
 #ifdef FLOAT_STORE_FLAG_VALUE
          if (GET_MODE_CLASS (mode) == MODE_FLOAT)
            {
-             true = (CONST_DOUBLE_FROM_REAL_VALUE
+             true_rtx = (CONST_DOUBLE_FROM_REAL_VALUE
                      (FLOAT_STORE_FLAG_VALUE (mode), mode));
-             false = CONST0_RTX (mode);
+             false_rtx = CONST0_RTX (mode);
            }
 #endif
 
@@ -3933,32 +3948,40 @@ fold_rtx (x, insn)
                      || GET_CODE (folded_arg0) == CONST))
                {
                  if (code == EQ)
-                   return false;
+                   return false_rtx;
                  else if (code == NE)
-                   return true;
+                   return true_rtx;
                }
 
-             /* See if the two operands are the same.  We don't do this
-                for IEEE floating-point since we can't assume x == x
-                since x might be a NaN.  */
-
-             if ((TARGET_FLOAT_FORMAT != IEEE_FLOAT_FORMAT
-                  || ! FLOAT_MODE_P (mode_arg0) || flag_fast_math)
-                 && (folded_arg0 == folded_arg1
-                     || (GET_CODE (folded_arg0) == REG
-                         && GET_CODE (folded_arg1) == REG
-                         && (REG_QTY (REGNO (folded_arg0))
-                             == REG_QTY (REGNO (folded_arg1))))
-                     || ((p0 = lookup (folded_arg0,
-                                       (safe_hash (folded_arg0, mode_arg0)
-                                        & HASH_MASK), mode_arg0))
-                         && (p1 = lookup (folded_arg1,
-                                          (safe_hash (folded_arg1, mode_arg0)
-                                           & HASH_MASK), mode_arg0))
-                         && p0->first_same_value == p1->first_same_value)))
-               return ((code == EQ || code == LE || code == GE
-                        || code == LEU || code == GEU)
-                       ? true : false);
+             /* See if the two operands are the same.  */
+
+             if (folded_arg0 == folded_arg1
+                 || (GET_CODE (folded_arg0) == REG
+                     && GET_CODE (folded_arg1) == REG
+                     && (REG_QTY (REGNO (folded_arg0))
+                         == REG_QTY (REGNO (folded_arg1))))
+                 || ((p0 = lookup (folded_arg0,
+                                   (safe_hash (folded_arg0, mode_arg0)
+                                    & HASH_MASK), mode_arg0))
+                     && (p1 = lookup (folded_arg1,
+                                      (safe_hash (folded_arg1, mode_arg0)
+                                       & HASH_MASK), mode_arg0))
+                     && p0->first_same_value == p1->first_same_value))
+               {
+                  /* Sadly two equal NaNs are not equivalent.  */
+                  if (TARGET_FLOAT_FORMAT != IEEE_FLOAT_FORMAT
+                      || ! FLOAT_MODE_P (mode_arg0) 
+                      || flag_unsafe_math_optimizations)
+                     return ((code == EQ || code == LE || code == GE
+                              || code == LEU || code == GEU || code == UNEQ
+                              || code == UNLE || code == UNGE || code == ORDERED)
+                             ? true_rtx : false_rtx);
+                  /* Take care for the FP compares we can resolve.  */
+                  if (code == UNEQ || code == UNLE || code == UNGE)
+                    return true_rtx;
+                  if (code == LTGT || code == LT || code == GT)
+                    return false_rtx;
+               }
 
              /* If FOLDED_ARG0 is a register, see if the comparison we are
                 doing now is either the same as we did before or the reverse
@@ -3982,7 +4005,7 @@ fold_rtx (x, insn)
                              || (GET_CODE (folded_arg1) == REG
                                  && (REG_QTY (REGNO (folded_arg1)) == ent->comparison_qty))))
                        return (comparison_dominates_p (ent->comparison_code, code)
-                               ? true : false);
+                               ? true_rtx : false_rtx);
                    }
                }
            }
@@ -4006,30 +4029,30 @@ fold_rtx (x, insn)
              int has_sign = (HOST_BITS_PER_WIDE_INT >= sign_bitnum
                              && (INTVAL (inner_const)
                                  & ((HOST_WIDE_INT) 1 << sign_bitnum)));
-             rtx true = const_true_rtx, false = const0_rtx;
+             rtx true_rtx = const_true_rtx, false_rtx = const0_rtx;
 
 #ifdef FLOAT_STORE_FLAG_VALUE
              if (GET_MODE_CLASS (mode) == MODE_FLOAT)
                {
-                 true = (CONST_DOUBLE_FROM_REAL_VALUE
+                 true_rtx = (CONST_DOUBLE_FROM_REAL_VALUE
                          (FLOAT_STORE_FLAG_VALUE (mode), mode));
-                 false = CONST0_RTX (mode);
+                 false_rtx = CONST0_RTX (mode);
                }
 #endif
 
              switch (code)
                {
                case EQ:
-                 return false;
+                 return false_rtx;
                case NE:
-                 return true;
+                 return true_rtx;
                case LT:  case LE:
                  if (has_sign)
-                   return true;
+                   return true_rtx;
                  break;
                case GT:  case GE:
                  if (has_sign)
-                   return false;
+                   return false_rtx;
                  break;
                default:
                  break;
@@ -4363,10 +4386,12 @@ gen_lowpart_if_possible (mode, x)
        offset = (MAX (GET_MODE_SIZE (GET_MODE (x)), UNITS_PER_WORD)
                  - MAX (GET_MODE_SIZE (mode), UNITS_PER_WORD));
       if (BYTES_BIG_ENDIAN)
-       /* Adjust the address so that the address-after-the-data is
-          unchanged.  */
-       offset -= (MIN (UNITS_PER_WORD, GET_MODE_SIZE (mode))
-                  - MIN (UNITS_PER_WORD, GET_MODE_SIZE (GET_MODE (x))));
+       {
+         /* Adjust the address so that the address-after-the-data is
+            unchanged.  */
+         offset -= (MIN (UNITS_PER_WORD, GET_MODE_SIZE (mode))
+                    - MIN (UNITS_PER_WORD, GET_MODE_SIZE (GET_MODE (x))));
+       }
       new = gen_rtx_MEM (mode, plus_constant (XEXP (x, 0), offset));
       if (! memory_address_p (mode, XEXP (new, 0)))
        return 0;
@@ -4421,8 +4446,7 @@ record_jump_equiv (insn, taken)
   code = find_comparison_args (code, &op0, &op1, &mode0, &mode1);
   if (! cond_known_true)
     {
-      reversed_nonequality = (code != EQ && code != NE);
-      code = reverse_condition (code);
+      code = reversed_comparison_code_parts (code, op0, op1, insn);
 
       /* Don't remember if we can't find the inverse.  */
       if (code == UNKNOWN)
@@ -4571,7 +4595,7 @@ record_jump_cond (code, mode, op0, op1, reversed_nonequality)
         new quantity number.  */
       if (op0_elt == 0)
        {
-         if (insert_regs (op0, NULL_PTR, 0))
+         if (insert_regs (op0, NULL, 0))
            {
              rehash_using_reg (op0);
              op0_hash = HASH (op0, mode);
@@ -4583,7 +4607,7 @@ record_jump_cond (code, mode, op0, op1, reversed_nonequality)
                op1_hash = HASH (op1,mode);
            }
 
-         op0_elt = insert (op0, NULL_PTR, op0_hash, mode);
+         op0_elt = insert (op0, NULL, op0_hash, mode);
          op0_elt->in_memory = op0_in_memory;
        }
 
@@ -4599,13 +4623,13 @@ record_jump_cond (code, mode, op0, op1, reversed_nonequality)
          /* Put OP1 in the hash table so it gets a new quantity number.  */
          if (op1_elt == 0)
            {
-             if (insert_regs (op1, NULL_PTR, 0))
+             if (insert_regs (op1, NULL, 0))
                {
                  rehash_using_reg (op1);
                  op1_hash = HASH (op1, mode);
                }
 
-             op1_elt = insert (op1, NULL_PTR, op1_hash, mode);
+             op1_elt = insert (op1, NULL, op1_hash, mode);
              op1_elt->in_memory = op1_in_memory;
            }
 
@@ -4626,25 +4650,25 @@ record_jump_cond (code, mode, op0, op1, reversed_nonequality)
 
   if (op0_elt == 0)
     {
-      if (insert_regs (op0, NULL_PTR, 0))
+      if (insert_regs (op0, NULL, 0))
        {
          rehash_using_reg (op0);
          op0_hash = HASH (op0, mode);
        }
 
-      op0_elt = insert (op0, NULL_PTR, op0_hash, mode);
+      op0_elt = insert (op0, NULL, op0_hash, mode);
       op0_elt->in_memory = op0_in_memory;
     }
 
   if (op1_elt == 0)
     {
-      if (insert_regs (op1, NULL_PTR, 0))
+      if (insert_regs (op1, NULL, 0))
        {
          rehash_using_reg (op1);
          op1_hash = HASH (op1, mode);
        }
 
-      op1_elt = insert (op1, NULL_PTR, op1_hash, mode);
+      op1_elt = insert (op1, NULL, op1_hash, mode);
       op1_elt->in_memory = op1_in_memory;
     }
 
@@ -4717,7 +4741,7 @@ cse_insn (insn, libcall_insn)
   int src_eqv_in_memory = 0;
   unsigned src_eqv_hash = 0;
 
-  struct set *sets = (struct set *) NULL_PTR;
+  struct set *sets = (struct set *) 0;
 
   this_insn = insn;
 
@@ -4729,8 +4753,11 @@ cse_insn (insn, libcall_insn)
   if (GET_CODE (insn) == CALL_INSN)
     {
       for (tem = CALL_INSN_FUNCTION_USAGE (insn); tem; tem = XEXP (tem, 1))
-       if (GET_CODE (XEXP (tem, 0)) == CLOBBER)
-         invalidate (SET_DEST (XEXP (tem, 0)), VOIDmode);
+       {
+         if (GET_CODE (XEXP (tem, 0)) == CLOBBER)
+           invalidate (SET_DEST (XEXP (tem, 0)), VOIDmode);
+         XEXP (tem, 0) = canon_reg (XEXP (tem, 0), insn);
+       }
     }
 
   if (GET_CODE (x) == SET)
@@ -5032,18 +5059,16 @@ cse_insn (insn, libcall_insn)
       sets[i].src_in_memory = hash_arg_in_memory;
 
       /* If SRC is a MEM, there is a REG_EQUIV note for SRC, and DEST is
-        a pseudo that is set more than once, do not record SRC.  Using
-        SRC as a replacement for anything else will be incorrect in that
-        situation.  Note that this usually occurs only for stack slots,
-        in which case all the RTL would be referring to SRC, so we don't
-        lose any optimization opportunities by not having SRC in the
-        hash table.  */
+        a pseudo, do not record SRC.  Using SRC as a replacement for
+        anything else will be incorrect in that situation.  Note that
+        this usually occurs only for stack slots, in which case all the
+        RTL would be referring to SRC, so we don't lose any optimization
+        opportunities by not having SRC in the hash table.  */
 
       if (GET_CODE (src) == MEM
-         && find_reg_note (insn, REG_EQUIV, src) != 0
+         && find_reg_note (insn, REG_EQUIV, NULL_RTX) != 0
          && GET_CODE (dest) == REG
-         && REGNO (dest) >= FIRST_PSEUDO_REGISTER
-         && REG_N_SETS (REGNO (dest)) != 1)
+         && REGNO (dest) >= FIRST_PSEUDO_REGISTER)
        sets[i].src_volatile = 1;
 
 #if 0
@@ -5485,31 +5510,17 @@ cse_insn (insn, libcall_insn)
             check for this separately here.  We will delete such an
             insn below.
 
-            Tablejump insns contain a USE of the table, so simply replacing
-            the operand with the constant won't match.  This is simply an
-            unconditional branch, however, and is therefore valid.  Just
-            insert the substitution here and we will delete and re-emit
-            the insn later.  */
-
+            For other cases such as a table jump or conditional jump
+            where we know the ultimate target, go ahead and replace the
+            operand.  While that may not make a valid insn, we will
+            reemit the jump below (and also insert any necessary
+            barriers).  */
          if (n_sets == 1 && dest == pc_rtx
              && (trial == pc_rtx
                  || (GET_CODE (trial) == LABEL_REF
                      && ! condjump_p (insn))))
            {
-             if (trial == pc_rtx)
-               {
-                 SET_SRC (sets[i].rtl) = trial;
-                 cse_jumps_altered = 1;
-                 break;
-               }
-
-             PATTERN (insn) = gen_jump (XEXP (trial, 0));
-             INSN_CODE (insn) = -1;
-
-             if (NEXT_INSN (insn) != 0
-                 && GET_CODE (NEXT_INSN (insn)) != BARRIER)
-               emit_barrier_after (insn);
-
+             SET_SRC (sets[i].rtl) = trial;
              cse_jumps_altered = 1;
              break;
            }
@@ -5771,13 +5782,17 @@ cse_insn (insn, libcall_insn)
        }
 
       /* If this SET is now setting PC to a label, we know it used to
-        be a conditional or computed branch.  So we see if we can follow
-        it.  If it was a computed branch, delete it and re-emit.  */
+        be a conditional or computed branch.  */
       else if (dest == pc_rtx && GET_CODE (src) == LABEL_REF)
        {
-         /* If this is not in the format for a simple branch and
-            we are the only SET in it, re-emit it.  */
-         if (! simplejump_p (insn) && n_sets == 1)
+         /* We reemit the jump in as many cases as possible just in
+            case the form of an unconditional jump is significantly
+            different than a computed jump or conditional jump.
+
+            If this insn has multiple sets, then reemitting the
+            jump is nontrivial.  So instead we just force rerecognition
+            and hope for the best.  */
+         if (n_sets == 1)
            {
              rtx new = emit_jump_insn_before (gen_jump (XEXP (src, 0)), insn);
              JUMP_LABEL (new) = XEXP (src, 0);
@@ -5785,11 +5800,6 @@ cse_insn (insn, libcall_insn)
              insn = new;
            }
          else
-           /* Otherwise, force rerecognition, since it probably had
-              a different pattern before.
-              This shouldn't really be necessary, since whatever
-              changed the source value above should have done this.
-              Until the right place is found, might as well do this here.  */
            INSN_CODE (insn) = -1;
 
          never_reached_warning (insn);
@@ -6238,23 +6248,32 @@ cse_insn (insn, libcall_insn)
        {
          rtx prev = prev_nonnote_insn (insn);
 
+         /* Do not swap the registers around if the previous instruction
+            attaches a REG_EQUIV note to REG1.
+
+            ??? It's not entirely clear whether we can transfer a REG_EQUIV
+            from the pseudo that originally shadowed an incoming argument
+            to another register.  Some uses of REG_EQUIV might rely on it
+            being attached to REG1 rather than REG2.
+
+            This section previously turned the REG_EQUIV into a REG_EQUAL
+            note.  We cannot do that because REG_EQUIV may provide an
+            uninitialised stack slot when REG_PARM_STACK_SPACE is used. */
+
          if (prev != 0 && GET_CODE (prev) == INSN
              && GET_CODE (PATTERN (prev)) == SET
-             && SET_DEST (PATTERN (prev)) == SET_SRC (sets[0].rtl))
+             && SET_DEST (PATTERN (prev)) == SET_SRC (sets[0].rtl)
+             && ! find_reg_note (prev, REG_EQUIV, NULL_RTX))
            {
              rtx dest = SET_DEST (sets[0].rtl);
              rtx src = SET_SRC (sets[0].rtl);
-             rtx note = find_reg_note (prev, REG_EQUIV, NULL_RTX);
+             rtx note;
 
              validate_change (prev, &SET_DEST (PATTERN (prev)), dest, 1);
              validate_change (insn, &SET_DEST (sets[0].rtl), src, 1);
              validate_change (insn, &SET_SRC (sets[0].rtl), dest, 1);
              apply_change_group ();
 
-             /* If REG1 was equivalent to a constant, REG0 is not.  */
-             if (note)
-               PUT_REG_NOTE_KIND (note, REG_EQUAL);
-
              /* If there was a REG_WAS_0 note on PREV, remove it.  Move
                 any REG_WAS_0 note on INSN to PREV.  */
              note = find_reg_note (prev, REG_WAS_0, NULL_RTX);
@@ -6586,7 +6605,7 @@ invalidate_skipped_set (dest, set, data)
         a BLKmode or nonscalar memory reference or a reference to a
         variable address.  */
       && (MEM_IN_STRUCT_P (dest) || GET_MODE (dest) == BLKmode
-         || cse_rtx_varies_p (XEXP (dest, 0))))
+         || cse_rtx_varies_p (XEXP (dest, 0), 0)))
     {
       invalidate_memory ();
       return;
@@ -7082,7 +7101,7 @@ cse_main (f, nregs, after_loop, file)
 #if ARG_POINTER_REGNUM != FRAME_POINTER_REGNUM
         && ! (i == ARG_POINTER_REGNUM && fixed_regs[i])
 #endif
-#if defined (PIC_OFFSET_TABLE_REGNUM) && !defined (PIC_OFFSET_TABLE_REG_CALL_CLOBBERED)
+#if !defined (PIC_OFFSET_TABLE_REG_CALL_CLOBBERED)
         && ! (i == PIC_OFFSET_TABLE_REGNUM && flag_pic)
 #endif
         )
@@ -7271,7 +7290,17 @@ cse_basic_block (from, to, next_branch, around_loop)
                libcall_insn = 0;
            }
 
+         new_label_ref = 0;
          cse_insn (insn, libcall_insn);
+
+         /* If this insn uses a LABEL_REF and there isn't a REG_LABEL
+            note for it, we must rerun jump since it needs to place the
+            note.  If this is a LABEL_REF for a CODE_LABEL that isn't in
+            the insn chain, don't do this since no REG_LABEL will be added. */
+         if (new_label_ref != 0 && INSN_UID (XEXP (new_label_ref, 0)) != 0
+             && reg_mentioned_p (new_label_ref, PATTERN (insn))
+             && ! find_reg_note (insn, REG_LABEL, XEXP (new_label_ref, 0)))
+           recorded_label_ref = 1;
        }
 
       /* If INSN is now an unconditional jump, skip to the end of our
@@ -7558,14 +7587,7 @@ delete_trivially_dead_insns (insns, nreg)
        live_insn = ! dead_libcall;
       else if (GET_CODE (PATTERN (insn)) == SET)
        {
-         if ((GET_CODE (SET_DEST (PATTERN (insn))) == REG
-              || GET_CODE (SET_DEST (PATTERN (insn))) == SUBREG)
-             && rtx_equal_p (SET_DEST (PATTERN (insn)),
-                             SET_SRC (PATTERN (insn))))
-           ;
-         else if (GET_CODE (SET_DEST (PATTERN (insn))) == STRICT_LOW_PART
-                  && rtx_equal_p (XEXP (SET_DEST (PATTERN (insn)), 0),
-                                  SET_SRC (PATTERN (insn))))
+         if (set_noop_p (PATTERN (insn)))
            ;
 
 #ifdef HAVE_cc0
@@ -7595,9 +7617,7 @@ delete_trivially_dead_insns (insns, nreg)
 
            if (GET_CODE (elt) == SET)
              {
-               if ((GET_CODE (SET_DEST (elt)) == REG
-                    || GET_CODE (SET_DEST (elt)) == SUBREG)
-                   && rtx_equal_p (SET_DEST (elt), SET_SRC (elt)))
+               if (set_noop_p (elt))
                  ;
 
 #ifdef HAVE_cc0