OSDN Git Service

Don't include sys/file.h for winnt; use process.h instead.
[pf3gnuchains/gcc-fork.git] / gcc / cse.c
index 21705ab..9bbe8a6 100644 (file)
--- a/gcc/cse.c
+++ b/gcc/cse.c
@@ -445,12 +445,12 @@ struct table_elt
 #ifdef OVERLAPPING_REGNO_P
 #define FIXED_REGNO_P(N)  \
   (((N) == FRAME_POINTER_REGNUM || (N) == HARD_FRAME_POINTER_REGNUM \
-    || fixed_regs[N])    \
+    || fixed_regs[N] || global_regs[N])          \
    && ! OVERLAPPING_REGNO_P ((N)))
 #else
 #define FIXED_REGNO_P(N)  \
   ((N) == FRAME_POINTER_REGNUM || (N) == HARD_FRAME_POINTER_REGNUM \
-   || fixed_regs[N])
+   || fixed_regs[N] || global_regs[N])
 #endif
 
 /* Compute cost of X, as stored in the `cost' field of a table_elt.  Fixed
@@ -458,16 +458,23 @@ struct table_elt
    of 0.  Next come pseudos with a cost of one and other hard registers with
    a cost of 2.  Aside from these special cases, call `rtx_cost'.  */
 
-#define CHEAP_REG(N) \
+#define CHEAP_REGNO(N) \
   ((N) == FRAME_POINTER_REGNUM || (N) == HARD_FRAME_POINTER_REGNUM     \
    || (N) == STACK_POINTER_REGNUM || (N) == ARG_POINTER_REGNUM         \
    || ((N) >= FIRST_VIRTUAL_REGISTER && (N) <= LAST_VIRTUAL_REGISTER)  \
    || ((N) < FIRST_PSEUDO_REGISTER                                     \
        && FIXED_REGNO_P (N) && REGNO_REG_CLASS (N) != NO_REGS))
 
+/* A register is cheap if it is a user variable assigned to the register
+   or if its register number always corresponds to a cheap register.  */
+
+#define CHEAP_REG(N) \
+  ((REG_USERVAR_P (N) && REGNO (N) < FIRST_PSEUDO_REGISTER)    \
+   || CHEAP_REGNO (REGNO (N)))
+
 #define COST(X)                                                \
   (GET_CODE (X) == REG                                 \
-   ? (CHEAP_REG (REGNO (X)) ? 0                                \
+   ? (CHEAP_REG (X) ? 0                                        \
       : REGNO (X) >= FIRST_PSEUDO_REGISTER ? 1         \
       : 2)                                             \
    : rtx_cost (X, SET) * 2)
@@ -611,7 +618,7 @@ static struct table_elt *insert PROTO((rtx, struct table_elt *, unsigned,
                                       enum machine_mode));
 static void merge_equiv_classes PROTO((struct table_elt *,
                                       struct table_elt *));
-static void invalidate         PROTO((rtx));
+static void invalidate         PROTO((rtx, enum machine_mode));
 static void remove_invalid_refs        PROTO((int));
 static void rehash_using_reg   PROTO((rtx));
 static void invalidate_memory  PROTO((struct write_data *));
@@ -717,7 +724,7 @@ rtx_cost (x, outer_code)
   switch (code)
     {
     case REG:
-      return ! CHEAP_REG (REGNO (x));
+      return ! CHEAP_REG (x);
 
     case SUBREG:
       /* If we can't tie these modes, make this expensive.  The larger
@@ -756,10 +763,11 @@ new_basic_block ()
 
   next_qty = max_reg;
 
-  bzero (reg_tick, max_reg * sizeof (int));
+  bzero ((char *) reg_tick, max_reg * sizeof (int));
 
-  bcopy (all_minus_one, reg_in_table, max_reg * sizeof (int));
-  bcopy (consec_ints, reg_qty, max_reg * sizeof (int));
+  bcopy ((char *) all_minus_one, (char *) reg_in_table,
+        max_reg * sizeof (int));
+  bcopy ((char *) consec_ints, (char *) reg_qty, max_reg * sizeof (int));
   CLEAR_HARD_REG_SET (hard_regs_in_table);
 
   /* The per-quantity values used to be initialized here, but it is
@@ -775,7 +783,7 @@ new_basic_block ()
        }
     }
 
-  bzero (table, sizeof table);
+  bzero ((char *) table, sizeof table);
 
   prev_insn = 0;
 
@@ -1472,14 +1480,18 @@ merge_equiv_classes (class1, class2)
    (because, when a memory reference with a varying address is stored in,
    all memory references are removed by invalidate_memory
    so specific invalidation is superfluous).
+   FULL_MODE, if not VOIDmode, indicates that this much should be invalidated
+   instead of just the amount indicated by the mode of X.  This is only used
+   for bitfield stores into memory.
 
    A nonvarying address may be just a register or just
    a symbol reference, or it may be either of those plus
    a numeric offset.  */
 
 static void
-invalidate (x)
+invalidate (x, full_mode)
      rtx x;
+     enum machine_mode full_mode;
 {
   register int i;
   register struct table_elt *p;
@@ -1554,7 +1566,7 @@ invalidate (x)
     {
       if (GET_CODE (SUBREG_REG (x)) != REG)
        abort ();
-      invalidate (SUBREG_REG (x));
+      invalidate (SUBREG_REG (x), VOIDmode);
       return;
     }
 
@@ -1565,7 +1577,10 @@ invalidate (x)
   if (GET_CODE (x) != MEM)
     abort ();
 
-  set_nonvarying_address_components (XEXP (x, 0), GET_MODE_SIZE (GET_MODE (x)),
+  if (full_mode == VOIDmode)
+    full_mode = GET_MODE (x);
+
+  set_nonvarying_address_components (XEXP (x, 0), GET_MODE_SIZE (full_mode),
                                     &base, &start, &end);
 
   for (i = 0; i < NBUCKETS; i++)
@@ -1703,7 +1718,7 @@ invalidate_for_call ()
        if (reg_tick[regno] >= 0)
          reg_tick[regno]++;
 
-       in_table |= TEST_HARD_REG_BIT (hard_regs_in_table, regno);
+       in_table |= (TEST_HARD_REG_BIT (hard_regs_in_table, regno) != 0);
       }
 
   /* In the case where we have no call-clobbered hard registers in the
@@ -1893,7 +1908,7 @@ canon_hash (x, mode)
 
     case SYMBOL_REF:
       hash
-       += ((unsigned) SYMBOL_REF << 7) + (unsigned HOST_WIDE_INT) XEXP (x, 0);
+       += ((unsigned) SYMBOL_REF << 7) + (unsigned HOST_WIDE_INT) XSTR (x, 0);
       return hash;
 
     case MEM:
@@ -2070,9 +2085,11 @@ exp_equiv_p (x, y, validate, equal_values)
       return INTVAL (x) == INTVAL (y);
 
     case LABEL_REF:
-    case SYMBOL_REF:
       return XEXP (x, 0) == XEXP (y, 0);
 
+    case SYMBOL_REF:
+      return XSTR (x, 0) == XSTR (y, 0);
+
     case REG:
       {
        int regno = REGNO (y);
@@ -2220,9 +2237,10 @@ refers_to_p (x, y)
    set PBASE, PSTART, and PEND which correspond to the base of the address,
    the starting offset, and ending offset respectively.
 
-   ADDR is known to be a nonvarying address. 
+   ADDR is known to be a nonvarying address.  */
 
-   cse_address_varies_p returns zero for nonvarying addresses.  */
+/* ??? Despite what the comments say, this function is in fact frequently
+   passed varying addresses.  This does not appear to cause any problems.  */
 
 static void
 set_nonvarying_address_components (addr, size, pbase, pstart, pend)
@@ -2232,7 +2250,7 @@ set_nonvarying_address_components (addr, size, pbase, pstart, pend)
      HOST_WIDE_INT *pstart, *pend;
 {
   rtx base;
-  int start, end;
+  HOST_WIDE_INT start, end;
 
   base = addr;
   start = 0;
@@ -2259,20 +2277,64 @@ set_nonvarying_address_components (addr, size, pbase, pstart, pend)
       base = qty_const[reg_qty[REGNO (XEXP (base, 0))]];
     }
 
-  /* By definition, operand1 of a LO_SUM is the associated constant
-     address.  Use the associated constant address as the base instead.  */
-  if (GET_CODE (base) == LO_SUM)
-    base = XEXP (base, 1);
+  /* Handle everything that we can find inside an address that has been
+     viewed as constant.  */
+
+  while (1)
+    {
+      /* If no part of this switch does a "continue", the code outside
+        will exit this loop.  */
+
+      switch (GET_CODE (base))
+       {
+       case LO_SUM:
+         /* By definition, operand1 of a LO_SUM is the associated constant
+            address.  Use the associated constant address as the base
+            instead.  */
+         base = XEXP (base, 1);
+         continue;
+
+       case CONST:
+         /* Strip off CONST.  */
+         base = XEXP (base, 0);
+         continue;
+
+       case PLUS:
+         if (GET_CODE (XEXP (base, 1)) == CONST_INT)
+           {
+             start += INTVAL (XEXP (base, 1));
+             base = XEXP (base, 0);
+             continue;
+           }
+         break;
+
+       case AND:
+         /* Handle the case of an AND which is the negative of a power of
+            two.  This is used to represent unaligned memory operations.  */
+         if (GET_CODE (XEXP (base, 1)) == CONST_INT
+             && exact_log2 (- INTVAL (XEXP (base, 1))) > 0)
+           {
+             set_nonvarying_address_components (XEXP (base, 0), size,
+                                                pbase, pstart, pend);
+
+             /* Assume the worst misalignment.  START is affected, but not
+                END, so compensate but adjusting SIZE.  Don't lose any
+                constant we already had.  */
+
+             size = *pend - *pstart - INTVAL (XEXP (base, 1)) - 1;
+             start += *pstart - INTVAL (XEXP (base, 1)) - 1;
+             base = *pbase;
+           }
+         break;
+       }
 
-  /* Strip off CONST.  */
-  if (GET_CODE (base) == CONST)
-    base = XEXP (base, 0);
+      break;
+    }
 
-  if (GET_CODE (base) == PLUS
-      && GET_CODE (XEXP (base, 1)) == CONST_INT)
+  if (GET_CODE (base) == CONST_INT)
     {
-      start += INTVAL (XEXP (base, 1));
-      base = XEXP (base, 0);
+      start += INTVAL (base);
+      base = const0_rtx;
     }
 
   end = start + size;
@@ -2305,13 +2367,6 @@ refers_to_mem_p (x, base, start, end)
   register enum rtx_code code;
   register char *fmt;
 
-  if (GET_CODE (base) == CONST_INT)
-    {
-      start += INTVAL (base);
-      end += INTVAL (base);
-      base = const0_rtx;
-    }
-
  repeat:
   if (x == 0)
     return 0;
@@ -2879,70 +2934,67 @@ simplify_unary_operation (code, mode, op, op_mode)
      check the wrong mode (input vs. output) for a conversion operation,
      such as FIX.  At some point, this should be simplified.  */
 
-#if !defined (REAL_IS_NOT_DOUBLE) || defined (REAL_ARITHMETIC)
-  if (code == FLOAT && GET_CODE (op) == CONST_INT)
-    {
-      REAL_VALUE_TYPE d;
+#if !defined(REAL_IS_NOT_DOUBLE) || defined(REAL_ARITHMETIC)
 
-#ifdef REAL_ARITHMETIC
-      REAL_VALUE_FROM_INT (d, INTVAL (op), INTVAL (op) < 0 ? ~0 : 0);
-#else
-      d = (double) INTVAL (op);
-#endif
-      return CONST_DOUBLE_FROM_REAL_VALUE (d, mode);
-    }
-  else if (code == UNSIGNED_FLOAT && GET_CODE (op) == CONST_INT)
+  if (code == FLOAT && GET_MODE (op) == VOIDmode
+      && (GET_CODE (op) == CONST_DOUBLE || GET_CODE (op) == CONST_INT))
     {
+      HOST_WIDE_INT hv, lv;
       REAL_VALUE_TYPE d;
 
-#ifdef REAL_ARITHMETIC
-      REAL_VALUE_FROM_INT (d, INTVAL (op), 0);
-#else
-      d = (double) (unsigned int) INTVAL (op);
-#endif
-      return CONST_DOUBLE_FROM_REAL_VALUE (d, mode);
-    }
-
-  else if (code == FLOAT && GET_CODE (op) == CONST_DOUBLE
-          && GET_MODE (op) == VOIDmode)
-    {
-      REAL_VALUE_TYPE d;
+      if (GET_CODE (op) == CONST_INT)
+       lv = INTVAL (op), hv = INTVAL (op) < 0 ? -1 : 0;
+      else
+       lv = CONST_DOUBLE_LOW (op),  hv = CONST_DOUBLE_HIGH (op);
 
 #ifdef REAL_ARITHMETIC
-      REAL_VALUE_FROM_INT (d, CONST_DOUBLE_LOW (op), CONST_DOUBLE_HIGH (op));
+      REAL_VALUE_FROM_INT (d, lv, hv);
 #else
-      if (CONST_DOUBLE_HIGH (op) < 0)
+      if (hv < 0)
        {
-         d = (double) (~ CONST_DOUBLE_HIGH (op));
+         d = (double) (~ hv);
          d *= ((double) ((HOST_WIDE_INT) 1 << (HOST_BITS_PER_WIDE_INT / 2))
                * (double) ((HOST_WIDE_INT) 1 << (HOST_BITS_PER_WIDE_INT / 2)));
-         d += (double) (unsigned HOST_WIDE_INT) (~ CONST_DOUBLE_LOW (op));
+         d += (double) (unsigned HOST_WIDE_INT) (~ lv);
          d = (- d - 1.0);
        }
       else
        {
-         d = (double) CONST_DOUBLE_HIGH (op);
+         d = (double) hv;
          d *= ((double) ((HOST_WIDE_INT) 1 << (HOST_BITS_PER_WIDE_INT / 2))
                * (double) ((HOST_WIDE_INT) 1 << (HOST_BITS_PER_WIDE_INT / 2)));
-         d += (double) (unsigned HOST_WIDE_INT) CONST_DOUBLE_LOW (op);
+         d += (double) (unsigned HOST_WIDE_INT) lv;
        }
 #endif  /* REAL_ARITHMETIC */
+
       return CONST_DOUBLE_FROM_REAL_VALUE (d, mode);
     }
-  else if (code == UNSIGNED_FLOAT && GET_CODE (op) == CONST_DOUBLE
-          && GET_MODE (op) == VOIDmode)
+  else if (code == UNSIGNED_FLOAT && GET_MODE (op) == VOIDmode
+          && (GET_CODE (op) == CONST_DOUBLE || GET_CODE (op) == CONST_INT))
     {
+      HOST_WIDE_INT hv, lv;
       REAL_VALUE_TYPE d;
 
+      if (GET_CODE (op) == CONST_INT)
+       lv = INTVAL (op), hv = INTVAL (op) < 0 ? -1 : 0;
+      else
+       lv = CONST_DOUBLE_LOW (op),  hv = CONST_DOUBLE_HIGH (op);
+
+      if (GET_MODE_BITSIZE (op_mode) >= HOST_BITS_PER_WIDE_INT * 2)
+       ;
+      else
+       hv = 0, lv &= GET_MODE_MASK (op_mode);
+
 #ifdef REAL_ARITHMETIC
-      REAL_VALUE_FROM_UNSIGNED_INT (d, CONST_DOUBLE_LOW (op),
-                                   CONST_DOUBLE_HIGH (op));
+      REAL_VALUE_FROM_UNSIGNED_INT (d, lv, hv);
 #else
-      d = (double) CONST_DOUBLE_HIGH (op);
+
+      d = (double) (unsigned HOST_WIDE_INT) hv;
       d *= ((double) ((HOST_WIDE_INT) 1 << (HOST_BITS_PER_WIDE_INT / 2))
            * (double) ((HOST_WIDE_INT) 1 << (HOST_BITS_PER_WIDE_INT / 2)));
-      d += (double) (unsigned HOST_WIDE_INT) CONST_DOUBLE_LOW (op);
+      d += (double) (unsigned HOST_WIDE_INT) lv;
 #endif  /* REAL_ARITHMETIC */
+
       return CONST_DOUBLE_FROM_REAL_VALUE (d, mode);
     }
 #endif
@@ -3041,7 +3093,7 @@ simplify_unary_operation (code, mode, op, op_mode)
 
   /* We can do some operations on integer CONST_DOUBLEs.  Also allow
      for a DImode operation on a CONST_INT. */
-  else if (GET_MODE (op) == VOIDmode && width == HOST_BITS_PER_INT * 2
+  else if (GET_MODE (op) == VOIDmode && width <= HOST_BITS_PER_INT * 2
           && (GET_CODE (op) == CONST_DOUBLE || GET_CODE (op) == CONST_INT))
     {
       HOST_WIDE_INT l1, h1, lv, hv;
@@ -3078,10 +3130,7 @@ simplify_unary_operation (code, mode, op, op_mode)
          break;
 
        case TRUNCATE:
-         if (GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_WIDE_INT)
-           return GEN_INT (l1 & GET_MODE_MASK (mode));
-         else
-           return 0;
+         /* This is just a change-of-mode, so do nothing.  */
          break;
 
        case ZERO_EXTEND:
@@ -3171,11 +3220,14 @@ simplify_unary_operation (code, mode, op, op_mode)
          abort ();
        }
 
-      x = immed_real_const_1 (d, mode);
+      x = CONST_DOUBLE_FROM_REAL_VALUE (d, mode);
       set_float_handler (NULL_PTR);
       return x;
     }
-  else if (GET_CODE (op) == CONST_DOUBLE && GET_MODE_CLASS (mode) == MODE_INT
+
+  else if (GET_CODE (op) == CONST_DOUBLE
+          && GET_MODE_CLASS (GET_MODE (op)) == MODE_FLOAT
+          && GET_MODE_CLASS (mode) == MODE_INT
           && width <= HOST_BITS_PER_WIDE_INT && width > 0)
     {
       REAL_VALUE_TYPE d;
@@ -3325,9 +3377,9 @@ simplify_binary_operation (code, mode, op0, op1)
        }
 #endif
 
-      set_float_handler (NULL_PTR);
       value = real_value_truncate (mode, value);
-      return immed_real_const_1 (value, mode);
+      set_float_handler (NULL_PTR);
+      return CONST_DOUBLE_FROM_REAL_VALUE (value, mode);
     }
 #endif  /* not REAL_IS_NOT_DOUBLE, or REAL_ARITHMETIC */
 
@@ -3424,7 +3476,7 @@ simplify_binary_operation (code, mode, op0, op1)
          break;
 
        case LSHIFTRT:   case ASHIFTRT:
-       case ASHIFT:     case LSHIFT:
+       case ASHIFT:
        case ROTATE:     case ROTATERT:
 #ifdef SHIFT_COUNT_TRUNCATED
          if (SHIFT_COUNT_TRUNCATED)
@@ -3437,9 +3489,8 @@ simplify_binary_operation (code, mode, op0, op1)
          if (code == LSHIFTRT || code == ASHIFTRT)
            rshift_double (l1, h1, l2, GET_MODE_BITSIZE (mode), &lv, &hv,
                           code == ASHIFTRT);
-         else if (code == ASHIFT || code == LSHIFT)
-           lshift_double (l1, h1, l2, GET_MODE_BITSIZE (mode), &lv, &hv,
-                          code == ASHIFT);
+         else if (code == ASHIFT)
+           lshift_double (l1, h1, l2, GET_MODE_BITSIZE (mode), &lv, &hv, 1);
          else if (code == ROTATE)
            lrotate_double (l1, h1, l2, GET_MODE_BITSIZE (mode), &lv, &hv);
          else /* code == ROTATERT */
@@ -3672,7 +3723,7 @@ simplify_binary_operation (code, mode, op0, op1)
            return tem;
 
          /* Don't let a relocatable value get a negative coeff.  */
-         if (GET_CODE (op1) == CONST_INT && GET_MODE (op1) != VOIDmode)
+         if (GET_CODE (op1) == CONST_INT && GET_MODE (op0) != VOIDmode)
            return plus_constant (op0, - INTVAL (op1));
          break;
 
@@ -3844,7 +3895,6 @@ simplify_binary_operation (code, mode, op0, op1)
 
          /* ... fall through ... */
 
-       case LSHIFT:
        case ASHIFT:
        case ASHIFTRT:
        case LSHIFTRT:
@@ -3986,7 +4036,6 @@ simplify_binary_operation (code, mode, op0, op1)
       break;
 
     case ASHIFT:
-    case LSHIFT:
       if (arg1 < 0)
        return 0;
 
@@ -4091,7 +4140,7 @@ simplify_plus_minus (code, mode, op0, op1)
   int first = 1, negate = 0, changed;
   int i, j;
 
-  bzero (ops, sizeof ops);
+  bzero ((char *) ops, sizeof ops);
   
   /* Set up the two operands and then expand them until nothing has been
      changed.  If we run out of room in our array, give up; this should
@@ -4432,7 +4481,7 @@ simplify_relational_operation (code, mode, op0, op1)
             be zero, but a SYMBOL_REF can due to #pragma weak.  */
          if (((NONZERO_BASE_PLUS_P (op0) && op1 == const0_rtx)
               || GET_CODE (op0) == LABEL_REF)
-#if FRAME_POINTER_REGNO != ARG_POINTGER_REGNO
+#if FRAME_POINTER_REGNUM != ARG_POINTER_REGNUM
              /* On some machines, the ap reg can be 0 sometimes.  */
              && op0 != arg_pointer_rtx
 #endif
@@ -4443,7 +4492,7 @@ simplify_relational_operation (code, mode, op0, op1)
        case NE:
          if (((NONZERO_BASE_PLUS_P (op0) && op1 == const0_rtx)
               || GET_CODE (op0) == LABEL_REF)
-#if FRAME_POINTER_REGNO != ARG_POINTER_REGNO
+#if FRAME_POINTER_REGNUM != ARG_POINTER_REGNUM
              && op0 != arg_pointer_rtx
 #endif
              )
@@ -4809,8 +4858,7 @@ fold_rtx (x, insn)
                     to compute that in SImode, because a 32-bit shift
                     in SImode is unpredictable.  We know the value is 0.  */
                  if (op0 && op1
-                     && (GET_CODE (elt->exp) == ASHIFT
-                         || GET_CODE (elt->exp) == LSHIFT)
+                     && GET_CODE (elt->exp) == ASHIFT
                      && GET_CODE (op1) == CONST_INT
                      && INTVAL (op1) >= GET_MODE_BITSIZE (mode))
                    {
@@ -4960,7 +5008,11 @@ fold_rtx (x, insn)
                    if (GET_MODE (table) != Pmode)
                      new = gen_rtx (TRUNCATE, GET_MODE (table), new);
 
-                   return new;
+                   /* Indicate this is a constant.  This isn't a 
+                      valid form of CONST, but it will only be used
+                      to fold the next insns and then discarded, so
+                      it should be safe.  */
+                   return gen_rtx (CONST, GET_MODE (new), new);
                  }
              }
          }
@@ -5133,13 +5185,26 @@ fold_rtx (x, insn)
   switch (GET_RTX_CLASS (code))
     {
     case '1':
-      /* We can't simplify extension ops unless we know the original mode.  */
-      if ((code == ZERO_EXTEND || code == SIGN_EXTEND)
-         && mode_arg0 == VOIDmode)
-       break;
-      new = simplify_unary_operation (code, mode,
-                                     const_arg0 ? const_arg0 : folded_arg0,
-                                     mode_arg0);
+      {
+       int is_const = 0;
+
+       /* We can't simplify extension ops unless we know the
+          original mode.  */
+       if ((code == ZERO_EXTEND || code == SIGN_EXTEND)
+           && mode_arg0 == VOIDmode)
+         break;
+
+       /* If we had a CONST, strip it off and put it back later if we
+          fold.  */
+       if (const_arg0 != 0 && GET_CODE (const_arg0) == CONST)
+         is_const = 1, const_arg0 = XEXP (const_arg0, 0);
+
+       new = simplify_unary_operation (code, mode,
+                                       const_arg0 ? const_arg0 : folded_arg0,
+                                       mode_arg0);
+       if (new != 0 && is_const)
+         new = gen_rtx (CONST, mode, new);
+      }
       break;
       
     case '<':
@@ -5157,7 +5222,8 @@ fold_rtx (x, insn)
 #ifdef FLOAT_STORE_FLAG_VALUE
          if (GET_MODE_CLASS (mode) == MODE_FLOAT)
            {
-             true = immed_real_const_1 (FLOAT_STORE_FLAG_VALUE, mode);
+             true = CONST_DOUBLE_FROM_REAL_VALUE (FLOAT_STORE_FLAG_VALUE,
+                                                  mode);
              false = CONST0_RTX (mode);
            }
 #endif
@@ -5266,7 +5332,8 @@ fold_rtx (x, insn)
 #ifdef FLOAT_STORE_FLAG_VALUE
              if (GET_MODE_CLASS (mode) == MODE_FLOAT)
                {
-                 true = immed_real_const_1 (FLOAT_STORE_FLAG_VALUE, mode);
+                 true = CONST_DOUBLE_FROM_REAL_VALUE (FLOAT_STORE_FLAG_VALUE,
+                                                      mode);
                  false = CONST0_RTX (mode);
                }
 #endif
@@ -5295,7 +5362,7 @@ fold_rtx (x, insn)
 #ifdef FLOAT_STORE_FLAG_VALUE
       if (new != 0 && GET_MODE_CLASS (mode) == MODE_FLOAT)
        new = ((new == const0_rtx) ? CONST0_RTX (mode)
-              : immed_real_const_1 (FLOAT_STORE_FLAG_VALUE, mode));
+              : CONST_DOUBLE_FROM_REAL_VALUE (FLOAT_STORE_FLAG_VALUE, mode));
 #endif
       break;
 
@@ -5310,11 +5377,41 @@ fold_rtx (x, insn)
             ADDR_DIFF_VEC table.  */
          if (const_arg1 && GET_CODE (const_arg1) == LABEL_REF)
            {
-             rtx y = lookup_as_function (folded_arg0, MINUS);
+             rtx y
+               = GET_CODE (folded_arg0) == MINUS ? folded_arg0
+                 : lookup_as_function (folded_arg0, MINUS);
 
              if (y != 0 && GET_CODE (XEXP (y, 1)) == LABEL_REF
                  && XEXP (XEXP (y, 1), 0) == XEXP (const_arg1, 0))
                return XEXP (y, 0);
+
+             /* Now try for a CONST of a MINUS like the above.  */
+             if ((y = (GET_CODE (folded_arg0) == CONST ? folded_arg0
+                       : lookup_as_function (folded_arg0, CONST))) != 0
+                 && GET_CODE (XEXP (y, 0)) == MINUS
+                 && GET_CODE (XEXP (XEXP (y, 0), 1)) == LABEL_REF
+                 && XEXP (XEXP (XEXP (y, 0),1), 0) == XEXP (const_arg1, 0))
+               return XEXP (XEXP (y, 0), 0);
+           }
+
+         /* Likewise if the operands are in the other order.  */
+         if (const_arg0 && GET_CODE (const_arg0) == LABEL_REF)
+           {
+             rtx y
+               = GET_CODE (folded_arg1) == MINUS ? folded_arg1
+                 : lookup_as_function (folded_arg1, MINUS);
+
+             if (y != 0 && GET_CODE (XEXP (y, 1)) == LABEL_REF
+                 && XEXP (XEXP (y, 1), 0) == XEXP (const_arg0, 0))
+               return XEXP (y, 0);
+
+             /* Now try for a CONST of a MINUS like the above.  */
+             if ((y = (GET_CODE (folded_arg1) == CONST ? folded_arg1
+                       : lookup_as_function (folded_arg1, CONST))) != 0
+                 && GET_CODE (XEXP (y, 0)) == MINUS
+                 && GET_CODE (XEXP (XEXP (y, 0), 1)) == LABEL_REF
+                 && XEXP (XEXP (XEXP (y, 0),1), 0) == XEXP (const_arg0, 0))
+               return XEXP (XEXP (y, 0), 0);
            }
 
          /* If second operand is a register equivalent to a negative
@@ -5716,6 +5813,13 @@ record_jump_cond (code, mode, op0, op1, reversed_nonequality)
   op0_elt = lookup (op0, op0_hash, mode);
   op1_elt = lookup (op1, op1_hash, mode);
 
+  /* If both operands are already equivalent or if they are not in the
+     table but are identical, do nothing.  */
+  if ((op0_elt != 0 && op1_elt != 0
+       && op0_elt->first_same_value == op1_elt->first_same_value)
+      || op0 == op1 || rtx_equal_p (op0, op1))
+    return;
+
   /* If we aren't setting two things equal all we can do is save this
      comparison.   Similarly if this is floating-point.  In the latter
      case, OP1 might be zero and both -0.0 and 0.0 are equal to it.
@@ -5871,8 +5975,8 @@ cse_insn (insn, in_libcall_block)
      int in_libcall_block;
 {
   register rtx x = PATTERN (insn);
-  rtx tem;
   register int i;
+  rtx tem;
   register int n_sets = 0;
 
   /* Records what this insn does to set CC0.  */
@@ -5898,6 +6002,13 @@ cse_insn (insn, in_libcall_block)
      Also determine whether there is a CLOBBER that invalidates
      all memory references, or all references at varying addresses.  */
 
+  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 (x) == SET)
     {
       sets = (struct set *) alloca (sizeof (struct set));
@@ -5926,7 +6037,7 @@ cse_insn (insn, in_libcall_block)
          canon_reg (SET_SRC (x), insn);
          apply_change_group ();
          fold_rtx (SET_SRC (x), insn);
-         invalidate (SET_DEST (x));
+         invalidate (SET_DEST (x), VOIDmode);
        }
       else
        n_sets = 1;
@@ -5957,10 +6068,10 @@ cse_insn (insn, in_libcall_block)
 
              if (GET_CODE (clobbered) == REG
                  || GET_CODE (clobbered) == SUBREG)
-               invalidate (clobbered);
+               invalidate (clobbered, VOIDmode);
              else if (GET_CODE (clobbered) == STRICT_LOW_PART
                       || GET_CODE (clobbered) == ZERO_EXTRACT)
-               invalidate (XEXP (clobbered, 0));
+               invalidate (XEXP (clobbered, 0), GET_MODE (clobbered));
            }
        }
            
@@ -5976,7 +6087,7 @@ cse_insn (insn, in_libcall_block)
                  canon_reg (SET_SRC (y), insn);
                  apply_change_group ();
                  fold_rtx (SET_SRC (y), insn);
-                 invalidate (SET_DEST (y));
+                 invalidate (SET_DEST (y), VOIDmode);
                }
              else if (SET_DEST (y) == pc_rtx
                       && GET_CODE (SET_SRC (y)) == LABEL_REF)
@@ -6032,14 +6143,15 @@ cse_insn (insn, in_libcall_block)
       fold_rtx (x, insn);
     }
 
-  if (n_sets == 1 && REG_NOTES (insn) != 0)
-    {
-      /* Store the equivalent value in SRC_EQV, if different.  */
-      rtx tem = find_reg_note (insn, REG_EQUAL, NULL_RTX);
-
-      if (tem && ! rtx_equal_p (XEXP (tem, 0), SET_SRC (sets[0].rtl)))
-        src_eqv = canon_reg (XEXP (tem, 0), NULL_RTX);
-    }
+  /* Store the equivalent value in SRC_EQV, if different, or if the DEST
+     is a STRICT_LOW_PART.  The latter condition is necessary because SRC_EQV
+     is handled specially for this case, and if it isn't set, then there will
+     be no equivalence for the destinatation.  */
+  if (n_sets == 1 && REG_NOTES (insn) != 0
+      && (tem = find_reg_note (insn, REG_EQUAL, NULL_RTX)) != 0
+      && (! rtx_equal_p (XEXP (tem, 0), SET_SRC (sets[0].rtl))
+         || GET_CODE (SET_DEST (sets[0].rtl)) == STRICT_LOW_PART))
+    src_eqv = canon_reg (XEXP (tem, 0), NULL_RTX);
 
   /* Canonicalize sources and addresses of destinations.
      We do this in a separate pass to avoid problems when a MATCH_DUP is
@@ -6677,7 +6789,7 @@ cse_insn (insn, in_libcall_block)
       if (n_sets == 1 && src_const && GET_CODE (dest) == REG
          && GET_CODE (src_const) != REG)
        {
-         rtx tem = find_reg_note (insn, REG_EQUAL, NULL_RTX);
+         tem = find_reg_note (insn, REG_EQUAL, NULL_RTX);
          
          /* Record the actual constant value in a REG_EQUAL note, making
             a new one if one does not already exist.  */
@@ -6865,10 +6977,10 @@ cse_insn (insn, in_libcall_block)
        {
          if (GET_CODE (dest) == REG || GET_CODE (dest) == SUBREG
              || GET_CODE (dest) == MEM)
-           invalidate (dest);
+           invalidate (dest, VOIDmode);
          else if (GET_CODE (dest) == STRICT_LOW_PART
                   || GET_CODE (dest) == ZERO_EXTRACT)
-           invalidate (XEXP (dest, 0));
+           invalidate (XEXP (dest, 0), GET_MODE (dest));
          sets[i].rtl = 0;
        }
 
@@ -7003,18 +7115,21 @@ cse_insn (insn, in_libcall_block)
   for (i = 0; i < n_sets; i++)
     if (sets[i].rtl)
       {
-       register rtx dest = sets[i].inner_dest;
+       /* We can't use the inner dest, because the mode associated with
+          a ZERO_EXTRACT is significant.  */
+       register rtx dest = SET_DEST (sets[i].rtl);
 
        /* Needed for registers to remove the register from its
           previous quantity's chain.
           Needed for memory if this is a nonvarying address, unless
           we have just done an invalidate_memory that covers even those.  */
        if (GET_CODE (dest) == REG || GET_CODE (dest) == SUBREG
-           || (! writes_memory.all && ! cse_rtx_addr_varies_p (dest)))
-         invalidate (dest);
+           || (GET_CODE (dest) == MEM && ! writes_memory.all
+               && ! cse_rtx_addr_varies_p (dest)))
+         invalidate (dest, VOIDmode);
        else if (GET_CODE (dest) == STRICT_LOW_PART
                 || GET_CODE (dest) == ZERO_EXTRACT)
-         invalidate (XEXP (dest, 0));
+         invalidate (XEXP (dest, 0), GET_MODE (dest));
       }
 
   /* Make sure registers mentioned in destinations
@@ -7115,8 +7230,9 @@ cse_insn (insn, in_libcall_block)
           already entered SRC and DEST of the SET in the table.  */
 
        if (GET_CODE (dest) == SUBREG
-           && (GET_MODE_SIZE (GET_MODE (SUBREG_REG (dest))) / UNITS_PER_WORD
-               == GET_MODE_SIZE (GET_MODE (dest)) / UNITS_PER_WORD)
+           && (((GET_MODE_SIZE (GET_MODE (SUBREG_REG (dest))) - 1)
+                / UNITS_PER_WORD)
+               == (GET_MODE_SIZE (GET_MODE (dest)) - 1)/ UNITS_PER_WORD)
            && (GET_MODE_SIZE (GET_MODE (dest))
                >= GET_MODE_SIZE (GET_MODE (SUBREG_REG (dest))))
            && sets[i].src_elt != 0)
@@ -7325,7 +7441,7 @@ invalidate_from_clobbers (w, x)
 
       /* This should be *very* rare.  */
       if (TEST_HARD_REG_BIT (hard_regs_in_table, STACK_POINTER_REGNUM))
-       invalidate (stack_pointer_rtx);
+       invalidate (stack_pointer_rtx, VOIDmode);
     }
 
   if (GET_CODE (x) == CLOBBER)
@@ -7335,10 +7451,10 @@ invalidate_from_clobbers (w, x)
        {
          if (GET_CODE (ref) == REG || GET_CODE (ref) == SUBREG
              || (GET_CODE (ref) == MEM && ! w->all))
-           invalidate (ref);
+           invalidate (ref, VOIDmode);
          else if (GET_CODE (ref) == STRICT_LOW_PART
                   || GET_CODE (ref) == ZERO_EXTRACT)
-           invalidate (XEXP (ref, 0));
+           invalidate (XEXP (ref, 0), GET_MODE (ref));
        }
     }
   else if (GET_CODE (x) == PARALLEL)
@@ -7354,10 +7470,10 @@ invalidate_from_clobbers (w, x)
                {
                  if (GET_CODE (ref) == REG || GET_CODE (ref) == SUBREG
                      || (GET_CODE (ref) == MEM && !w->all))
-                   invalidate (ref);
+                   invalidate (ref, VOIDmode);
                  else if (GET_CODE (ref) == STRICT_LOW_PART
                           || GET_CODE (ref) == ZERO_EXTRACT)
-                   invalidate (XEXP (ref, 0));
+                   invalidate (XEXP (ref, 0), GET_MODE (ref));
                }
            }
        }
@@ -7485,11 +7601,12 @@ cse_around_loop (loop_start)
     for (p = last_jump_equiv_class->first_same_value; p;
         p = p->next_same_value)
       if (GET_CODE (p->exp) == MEM || GET_CODE (p->exp) == REG
-         || GET_CODE (p->exp) == SUBREG)
-       invalidate (p->exp);
+         || (GET_CODE (p->exp) == SUBREG
+             && GET_CODE (SUBREG_REG (p->exp)) == REG))
+       invalidate (p->exp, VOIDmode);
       else if (GET_CODE (p->exp) == STRICT_LOW_PART
               || GET_CODE (p->exp) == ZERO_EXTRACT)
-       invalidate (XEXP (p->exp, 0));
+       invalidate (XEXP (p->exp, 0), GET_MODE (p->exp));
 
   /* Process insns starting after LOOP_START until we hit a CALL_INSN or
      a CODE_LABEL (we could handle a CALL_INSN, but it isn't worth it).
@@ -7548,10 +7665,10 @@ invalidate_skipped_set (dest, set)
 
   if (GET_CODE (dest) == REG || GET_CODE (dest) == SUBREG
       || (! skipped_writes_memory.all && ! cse_rtx_addr_varies_p (dest)))
-    invalidate (dest);
+    invalidate (dest, VOIDmode);
   else if (GET_CODE (dest) == STRICT_LOW_PART
           || GET_CODE (dest) == ZERO_EXTRACT)
-    invalidate (XEXP (dest, 0));
+    invalidate (XEXP (dest, 0), GET_MODE (dest));
 }
 
 /* Invalidate all insns from START up to the end of the function or the
@@ -7703,10 +7820,10 @@ cse_set_around_loop (x, insn, loop_start)
   if (GET_CODE (SET_DEST (x)) == REG || GET_CODE (SET_DEST (x)) == SUBREG
       || (GET_CODE (SET_DEST (x)) == MEM && ! writes_memory.all
          && ! cse_rtx_addr_varies_p (SET_DEST (x))))
-    invalidate (SET_DEST (x));
+    invalidate (SET_DEST (x), VOIDmode);
   else if (GET_CODE (SET_DEST (x)) == STRICT_LOW_PART
           || GET_CODE (SET_DEST (x)) == ZERO_EXTRACT)
-    invalidate (XEXP (SET_DEST (x), 0));
+    invalidate (XEXP (SET_DEST (x), 0), GET_MODE (SET_DEST (x)));
 }
 \f
 /* Find the end of INSN's basic block and return its range,
@@ -7978,7 +8095,7 @@ cse_main (f, nregs, after_loop, file)
 
   /* Discard all the free elements of the previous function
      since they are allocated in the temporarily obstack.  */
-  bzero (table, sizeof table);
+  bzero ((char *) table, sizeof table);
   free_element_chain = 0;
   n_elements_made = 0;
 
@@ -7986,7 +8103,7 @@ cse_main (f, nregs, after_loop, file)
 
   max_uid = get_max_uid ();
   uid_cuid = (int *) alloca ((max_uid + 1) * sizeof (int));
-  bzero (uid_cuid, (max_uid + 1) * sizeof (int));
+  bzero ((char *) uid_cuid, (max_uid + 1) * sizeof (int));
 
   /* Compute the mapping from uids to cuids.
      CUIDs are numbers assigned to insns, like uids,
@@ -8028,7 +8145,7 @@ cse_main (f, nregs, after_loop, file)
 #if ARG_POINTER_REGNUM != FRAME_POINTER_REGNUM
         && ! (i == ARG_POINTER_REGNUM && fixed_regs[i])
 #endif
-#ifdef PIC_OFFSET_TABLE_REGNUM
+#if defined (PIC_OFFSET_TABLE_REGNUM) && !defined (PIC_OFFSET_TABLE_REG_CALL_CLOBBERED)
         && ! (i == PIC_OFFSET_TABLE_REGNUM && flag_pic)
 #endif
         )
@@ -8313,11 +8430,14 @@ count_reg_usage (x, counts, dest, incr)
      rtx dest;
      int incr;
 {
-  enum rtx_code code = GET_CODE (x);
+  enum rtx_code code;
   char *fmt;
   int i, j;
 
-  switch (code)
+  if (x == 0)
+    return;
+
+  switch (code = GET_CODE (x))
     {
     case REG:
       if (x != dest)
@@ -8338,27 +8458,38 @@ count_reg_usage (x, counts, dest, incr)
       /* Unless we are setting a REG, count everything in SET_DEST.  */
       if (GET_CODE (SET_DEST (x)) != REG)
        count_reg_usage (SET_DEST (x), counts, NULL_RTX, incr);
-      count_reg_usage (SET_SRC (x), counts, SET_DEST (x), incr);
+
+      /* If SRC has side-effects, then we can't delete this insn, so the
+        usage of SET_DEST inside SRC counts.
+
+        ??? Strictly-speaking, we might be preserving this insn
+        because some other SET has side-effects, but that's hard
+        to do and can't happen now.  */
+      count_reg_usage (SET_SRC (x), counts,
+                      side_effects_p (SET_SRC (x)) ? NULL_RTX : SET_DEST (x),
+                      incr);
       return;
 
+    case CALL_INSN:
+      count_reg_usage (CALL_INSN_FUNCTION_USAGE (x), counts, NULL_RTX, incr);
+
+      /* ... falls through ...  */
     case INSN:
     case JUMP_INSN:
-    case CALL_INSN:
       count_reg_usage (PATTERN (x), counts, NULL_RTX, incr);
 
       /* Things used in a REG_EQUAL note aren't dead since loop may try to
         use them.  */
 
-      if (REG_NOTES (x))
-       count_reg_usage (REG_NOTES (x), counts, NULL_RTX, incr);
+      count_reg_usage (REG_NOTES (x), counts, NULL_RTX, incr);
       return;
 
     case EXPR_LIST:
     case INSN_LIST:
-      if (REG_NOTE_KIND (x) == REG_EQUAL)
+      if (REG_NOTE_KIND (x) == REG_EQUAL
+         || GET_CODE (XEXP (x,0)) == USE)
        count_reg_usage (XEXP (x, 0), counts, NULL_RTX, incr);
-      if (XEXP (x, 1))
-       count_reg_usage (XEXP (x, 1), counts, NULL_RTX, incr);
+      count_reg_usage (XEXP (x, 1), counts, NULL_RTX, incr);
       return;
     }
 
@@ -8393,7 +8524,7 @@ delete_dead_from_cse (insns, nreg)
   int in_libcall = 0;
 
   /* First count the number of times each register is used.  */
-  bzero (counts, sizeof (int) * nreg);
+  bzero ((char *) counts, sizeof (int) * nreg);
   for (insn = next_real_insn (insns); insn; insn = next_real_insn (insn))
     count_reg_usage (insn, counts, NULL_RTX, 1);