OSDN Git Service

2000-08-10 Alexandre Petit-Bianco <apbianco@cygnus.com>
[pf3gnuchains/gcc-fork.git] / gcc / simplify-rtx.c
index 9e26743..e97e7b7 100644 (file)
@@ -1,4 +1,4 @@
-/* Common subexpression elimination for GNU compiler.
+/* RTL simplification functions for GNU compiler.
    Copyright (C) 1987, 1988, 1989, 1992, 1993, 1994, 1995, 1996, 1997, 1998,
    1999, 2000 Free Software Foundation, Inc.
 
@@ -21,7 +21,6 @@ Boston, MA 02111-1307, USA.  */
 
 
 #include "config.h"
-/* stdio.h must precede rtl.h for FFS.  */
 #include "system.h"
 #include <setjmp.h>
 
@@ -93,11 +92,100 @@ Boston, MA 02111-1307, USA.  */
           || XEXP (X, 0) == virtual_outgoing_args_rtx))        \
    || GET_CODE (X) == ADDRESSOF)
 
+/* Much code operates on (low, high) pairs; the low value is an
+   unsigned wide int, the high value a signed wide int.  We
+   occasionally need to sign extend from low to high as if low were a
+   signed wide int.  */
+#define HWI_SIGN_EXTEND(low) \
+ ((((HOST_WIDE_INT) low) < 0) ? ((HOST_WIDE_INT) -1) : ((HOST_WIDE_INT) 0))
 
-static rtx simplify_plus_minus PARAMS ((enum rtx_code, enum machine_mode,
-                                      rtx, rtx));
-static void check_fold_consts  PARAMS ((PTR));
+static rtx simplify_plus_minus         PARAMS ((enum rtx_code,
+                                                enum machine_mode, rtx, rtx));
+static void check_fold_consts          PARAMS ((PTR));
+static int entry_and_rtx_equal_p       PARAMS ((const void *, const void *));
+static unsigned int get_value_hash     PARAMS ((const void *));
+static struct elt_list *new_elt_list   PARAMS ((struct elt_list *,
+                                                cselib_val *));
+static struct elt_loc_list *new_elt_loc_list PARAMS ((struct elt_loc_list *,
+                                                     rtx));
+static void unchain_one_value          PARAMS ((cselib_val *));
+static void unchain_one_elt_list       PARAMS ((struct elt_list **));
+static void unchain_one_elt_loc_list   PARAMS ((struct elt_loc_list **));
+static void clear_table                        PARAMS ((void));
+static int discard_useless_locs                PARAMS ((void **, void *));
+static int discard_useless_values      PARAMS ((void **, void *));
+static void remove_useless_values      PARAMS ((void));
+static unsigned int hash_rtx           PARAMS ((rtx, enum machine_mode, int));
+static cselib_val *new_cselib_val      PARAMS ((unsigned int,
+                                                enum machine_mode));
+static void add_mem_for_addr           PARAMS ((cselib_val *, cselib_val *,
+                                                rtx));
+static cselib_val *cselib_lookup_mem   PARAMS ((rtx, int));
+static rtx cselib_subst_to_values      PARAMS ((rtx));
+static void cselib_invalidate_regno    PARAMS ((unsigned int,
+                                                enum machine_mode));
+static int cselib_mem_conflict_p       PARAMS ((rtx, rtx));
+static int cselib_invalidate_mem_1     PARAMS ((void **, void *));
+static void cselib_invalidate_mem      PARAMS ((rtx));
+static void cselib_invalidate_rtx      PARAMS ((rtx, rtx, void *));
+static void cselib_record_set          PARAMS ((rtx, cselib_val *,
+                                                cselib_val *));
+static void cselib_record_sets         PARAMS ((rtx));
+
+/* There are three ways in which cselib can look up an rtx:
+   - for a REG, the reg_values table (which is indexed by regno) is used
+   - for a MEM, we recursively look up its address and then follow the
+     addr_list of that value
+   - for everything else, we compute a hash value and go through the hash
+     table.  Since different rtx's can still have the same hash value,
+     this involves walking the table entries for a given value and comparing
+     the locations of the entries with the rtx we are looking up.  */
+
+/* A table that enables us to look up elts by their value.  */
+static htab_t hash_table;
 
+/* This is a global so we don't have to pass this through every function.
+   It is used in new_elt_loc_list to set SETTING_INSN.  */
+static rtx cselib_current_insn;
+
+/* Every new unknown value gets a unique number.  */
+static unsigned int next_unknown_value;
+
+/* The number of registers we had when the varrays were last resized.  */
+static unsigned int cselib_nregs;
+
+/* Count values without known locations.  Whenever this grows too big, we
+   remove these useless values from the table.  */
+static int n_useless_values;
+
+/* Number of useless values before we remove them from the hash table.  */
+#define MAX_USELESS_VALUES 32
+
+/* This table maps from register number to values.  It does not contain
+   pointers to cselib_val structures, but rather elt_lists.  The purpose is
+   to be able to refer to the same register in different modes.  */
+static varray_type reg_values;
+#define REG_VALUES(I) VARRAY_ELT_LIST (reg_values, (I))
+
+/* We pass this to cselib_invalidate_mem to invalidate all of
+   memory for a non-const call instruction.  */
+static rtx callmem;
+
+/* Memory for our structures is allocated from this obstack.  */
+static struct obstack cselib_obstack;
+
+/* Used to quickly free all memory.  */
+static char *cselib_startobj;
+
+/* Caches for unused structures.  */
+static cselib_val *empty_vals;
+static struct elt_list *empty_elt_lists;
+static struct elt_loc_list *empty_elt_loc_lists;
+
+/* Set by discard_useless_locs if it deleted the last location of any
+   value.  */
+static int values_became_useless;
+\f
 /* Make a binary operation by properly ordering the operands and 
    seeing if the expression folds.  */
 
@@ -164,7 +252,7 @@ simplify_unary_operation (code, mode, op, op_mode)
       REAL_VALUE_TYPE d;
 
       if (GET_CODE (op) == CONST_INT)
-       lv = INTVAL (op), hv = INTVAL (op) < 0 ? -1 : 0;
+       lv = INTVAL (op), hv = HWI_SIGN_EXTEND (lv);
       else
        lv = CONST_DOUBLE_LOW (op),  hv = CONST_DOUBLE_HIGH (op);
 
@@ -197,7 +285,7 @@ simplify_unary_operation (code, mode, op, op_mode)
       REAL_VALUE_TYPE d;
 
       if (GET_CODE (op) == CONST_INT)
-       lv = INTVAL (op), hv = INTVAL (op) < 0 ? -1 : 0;
+       lv = INTVAL (op), hv = HWI_SIGN_EXTEND (lv);
       else
        lv = CONST_DOUBLE_LOW (op),  hv = CONST_DOUBLE_HIGH (op);
 
@@ -317,12 +405,13 @@ simplify_unary_operation (code, mode, op, op_mode)
   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;
+      unsigned HOST_WIDE_INT l1, lv;
+      HOST_WIDE_INT h1, hv;
 
       if (GET_CODE (op) == CONST_DOUBLE)
        l1 = CONST_DOUBLE_LOW (op), h1 = CONST_DOUBLE_HIGH (op);
       else
-       l1 = INTVAL (op), h1 = l1 < 0 ? -1 : 0;
+       l1 = INTVAL (op), h1 = HWI_SIGN_EXTEND (l1);
 
       switch (code)
        {
@@ -376,7 +465,7 @@ simplify_unary_operation (code, mode, op, op_mode)
                            << (GET_MODE_BITSIZE (op_mode) - 1))) != 0)
                lv -= (HOST_WIDE_INT) 1 << GET_MODE_BITSIZE (op_mode);
 
-             hv = (lv < 0) ? ~ (HOST_WIDE_INT) 0 : 0;
+             hv = HWI_SIGN_EXTEND (lv);
            }
          break;
 
@@ -627,17 +716,18 @@ simplify_binary_operation (code, mode, op0, op1)
       && (GET_CODE (op0) == CONST_DOUBLE || GET_CODE (op0) == CONST_INT)
       && (GET_CODE (op1) == CONST_DOUBLE || GET_CODE (op1) == CONST_INT))
     {
-      HOST_WIDE_INT l1, l2, h1, h2, lv, hv;
+      unsigned HOST_WIDE_INT l1, l2, lv;
+      HOST_WIDE_INT h1, h2, hv;
 
       if (GET_CODE (op0) == CONST_DOUBLE)
        l1 = CONST_DOUBLE_LOW (op0), h1 = CONST_DOUBLE_HIGH (op0);
       else
-       l1 = INTVAL (op0), h1 = l1 < 0 ? -1 : 0;
+       l1 = INTVAL (op0), h1 = HWI_SIGN_EXTEND (l1);
 
       if (GET_CODE (op1) == CONST_DOUBLE)
        l2 = CONST_DOUBLE_LOW (op1), h2 = CONST_DOUBLE_HIGH (op1);
       else
-       l2 = INTVAL (op1), h2 = l2 < 0 ? -1 : 0;
+       l2 = INTVAL (op1), h2 = HWI_SIGN_EXTEND (l2);
 
       switch (code)
        {
@@ -721,7 +811,7 @@ simplify_binary_operation (code, mode, op0, op1)
            l2 &= (GET_MODE_BITSIZE (mode) - 1), h2 = 0;
 #endif
 
-         if (h2 != 0 || l2 < 0 || l2 >= GET_MODE_BITSIZE (mode))
+         if (h2 != 0 || l2 >= GET_MODE_BITSIZE (mode))
            return 0;
 
          if (code == LSHIFTRT || code == ASHIFTRT)
@@ -858,11 +948,29 @@ simplify_binary_operation (code, mode, op0, op1)
               || ! FLOAT_MODE_P (mode) || flag_fast_math)
              && op1 == CONST0_RTX (mode))
            return op0;
+#endif
+
+         /* Convert (compare (gt (flags) 0) (lt (flags) 0)) to (flags).  */
+         if (((GET_CODE (op0) == GT && GET_CODE (op1) == LT)
+              || (GET_CODE (op0) == GTU && GET_CODE (op1) == LTU))
+             && XEXP (op0, 1) == const0_rtx && XEXP (op1, 1) == const0_rtx)
+           {
+             rtx xop00 = XEXP (op0, 0);
+             rtx xop10 = XEXP (op1, 0);
+
+#ifdef HAVE_cc0
+             if (GET_CODE (xop00) == CC0 && GET_CODE (xop10) == CC0)
 #else
-         /* Do nothing here.  */
+             if (GET_CODE (xop00) == REG && GET_CODE (xop10) == REG
+                 && GET_MODE (xop00) == GET_MODE (xop10)
+                 && REGNO (xop00) == REGNO (xop10)
+                 && GET_MODE_CLASS (GET_MODE (xop00)) == MODE_CC
+                 && GET_MODE_CLASS (GET_MODE (xop10)) == MODE_CC)
 #endif
-         break;
-             
+               return xop00;
+           }
+
+         break;              
        case MINUS:
          /* None of these optimizations can be done for IEEE
             floating point.  */
@@ -1583,6 +1691,11 @@ simplify_relational_operation (code, mode, op0, op1)
   int equal, op0lt, op0ltu, op1lt, op1ltu;
   rtx tem;
 
+  if (mode == VOIDmode
+      && (GET_MODE (op0) != VOIDmode
+         || GET_MODE (op1) != VOIDmode))
+    abort();
+
   /* If op0 is a compare, extract the comparison arguments from it.  */
   if (GET_CODE (op0) == COMPARE && op1 == const0_rtx)
     op1 = XEXP (op0, 1), op0 = XEXP (op0, 0);
@@ -1670,7 +1783,7 @@ simplify_relational_operation (code, mode, op0, op1)
       else
        {
          l0u = l0s = INTVAL (op0);
-         h0u = h0s = l0s < 0 ? -1 : 0;
+         h0u = h0s = HWI_SIGN_EXTEND (l0s);
        }
          
       if (GET_CODE (op1) == CONST_DOUBLE)
@@ -1681,13 +1794,13 @@ simplify_relational_operation (code, mode, op0, op1)
       else
        {
          l1u = l1s = INTVAL (op1);
-         h1u = h1s = l1s < 0 ? -1 : 0;
+         h1u = h1s = HWI_SIGN_EXTEND (l1s);
        }
 
       /* If WIDTH is nonzero and smaller than HOST_BITS_PER_WIDE_INT,
         we have to sign or zero-extend the values.  */
       if (width != 0 && width <= HOST_BITS_PER_WIDE_INT)
-       h0u = h1u = 0, h0s = l0s < 0 ? -1 : 0, h1s = l1s < 0 ? -1 : 0;
+       h0u = h1u = 0, h0s = HWI_SIGN_EXTEND (l0s), h1s = HWI_SIGN_EXTEND (l1s);
 
       if (width != 0 && width < HOST_BITS_PER_WIDE_INT)
        {
@@ -1702,8 +1815,8 @@ simplify_relational_operation (code, mode, op0, op1)
        }
 
       equal = (h0u == h1u && l0u == l1u);
-      op0lt = (h0s < h1s || (h0s == h1s && l0s < l1s));
-      op1lt = (h1s < h0s || (h1s == h0s && l1s < l0s));
+      op0lt = (h0s < h1s || (h0s == h1s && l0u < l1u));
+      op1lt = (h1s < h0s || (h1s == h0s && l1u < l0u));
       op0ltu = (h0u < h1u || (h0u == h1u && l0u < l1u));
       op1ltu = (h1u < h0u || (h1u == h0u && l1u < l0u));
     }
@@ -1809,7 +1922,7 @@ simplify_ternary_operation (code, mode, op0_mode, op0, op1, op2)
      enum machine_mode mode, op0_mode;
      rtx op0, op1, op2;
 {
-  int width = GET_MODE_BITSIZE (mode);
+  unsigned int width = GET_MODE_BITSIZE (mode);
 
   /* VOIDmode means "infinite" precision.  */
   if (width == 0)
@@ -1822,8 +1935,8 @@ simplify_ternary_operation (code, mode, op0_mode, op0, op1, op2)
       if (GET_CODE (op0) == CONST_INT
          && GET_CODE (op1) == CONST_INT
          && GET_CODE (op2) == CONST_INT
-         && INTVAL (op1) + INTVAL (op2) <= GET_MODE_BITSIZE (op0_mode)
-         && width <= HOST_BITS_PER_WIDE_INT)
+         && ((unsigned) INTVAL (op1) + (unsigned) INTVAL (op2) <= width)
+         && width <= (unsigned) HOST_BITS_PER_WIDE_INT)
        {
          /* Extracting a bit-field from a constant */
          HOST_WIDE_INT val = INTVAL (op0);
@@ -1872,14 +1985,37 @@ simplify_ternary_operation (code, mode, op0_mode, op0, op1, op2)
        return op2;
       else if (GET_RTX_CLASS (GET_CODE (op0)) == '<' && ! side_effects_p (op0))
        {
-         rtx temp;
-         temp = simplify_relational_operation (GET_CODE (op0), op0_mode,
-                                               XEXP (op0, 0), XEXP (op0, 1));
+         enum machine_mode cmp_mode = (GET_MODE (XEXP (op0, 0)) == VOIDmode
+                                       ? GET_MODE (XEXP (op0, 1))
+                                       : GET_MODE (XEXP (op0, 0)));
+         rtx temp
+            = simplify_relational_operation (GET_CODE (op0), cmp_mode,
+                                             XEXP (op0, 0), XEXP (op0, 1));
+
          /* See if any simplifications were possible.  */
          if (temp == const0_rtx)
            return op2;
          else if (temp == const1_rtx)
            return op1;
+         else if (temp)
+           op0 = temp;
+
+         /* Look for happy constants in op1 and op2.  */
+         if (GET_CODE (op1) == CONST_INT && GET_CODE (op2) == CONST_INT)
+           {
+             HOST_WIDE_INT t = INTVAL (op1);
+             HOST_WIDE_INT f = INTVAL (op2);
+             
+             if (t == STORE_FLAG_VALUE && f == 0)
+               code = GET_CODE (op0);
+             else if (t == 0 && f == STORE_FLAG_VALUE
+                      && can_reverse_comparison_p (op0, NULL_RTX))
+               code = reverse_condition (GET_CODE (op0));
+             else
+               break;
+
+             return gen_rtx_fmt_ee (code, mode, XEXP (op0, 0), XEXP (op0, 1));
+           }
        }
       break;
 
@@ -1962,93 +2098,17 @@ simplify_rtx (x)
     }
 }
 \f
-static int entry_and_rtx_equal_p       PARAMS ((const void *, const void *));
-static unsigned int get_value_hash     PARAMS ((const void *));
-static struct elt_list *new_elt_list   PARAMS ((struct elt_list *, cselib_val *));
-static struct elt_loc_list *new_elt_loc_list   PARAMS ((struct elt_loc_list *, rtx));
-static void unchain_one_value          PARAMS ((cselib_val *));
-static void unchain_one_elt_list       PARAMS ((struct elt_list **));
-static void unchain_one_elt_loc_list   PARAMS ((struct elt_loc_list **));
-static void clear_table                        PARAMS ((void));
-static int check_value_useless         PARAMS ((cselib_val *));
-static int discard_useless_locs                PARAMS ((void **, void *));
-static int discard_useless_values      PARAMS ((void **, void *));
-static void remove_useless_values      PARAMS ((void));
-static unsigned int hash_rtx           PARAMS ((rtx, enum machine_mode, int));
-static cselib_val *new_cselib_val      PARAMS ((unsigned int,
-                                                enum machine_mode));
-static void add_mem_for_addr           PARAMS ((cselib_val *, cselib_val *,
-                                                rtx));
-static cselib_val *cselib_lookup_mem   PARAMS ((rtx, int));
-static rtx cselib_subst_to_values      PARAMS ((rtx));
-static void cselib_invalidate_regno    PARAMS ((unsigned int,
-                                                enum machine_mode));
-static int cselib_mem_conflict_p       PARAMS ((rtx, rtx));
-static int cselib_invalidate_mem_1     PARAMS ((void **, void *));
-static void cselib_invalidate_mem      PARAMS ((rtx));
-static void cselib_invalidate_rtx      PARAMS ((rtx, rtx, void *));
-static void cselib_record_set          PARAMS ((rtx, cselib_val *,
-                                                cselib_val *));
-static void cselib_record_sets         PARAMS ((rtx));
-
-/* There are three ways in which cselib can look up an rtx:
-   - for a REG, the reg_values table (which is indexed by regno) is used
-   - for a MEM, we recursively look up its address and then follow the
-     addr_list of that value
-   - for everything else, we compute a hash value and go through the hash
-     table.  Since different rtx's can still have the same hash value,
-     this involves walking the table entries for a given value and comparing
-     the locations of the entries with the rtx we are looking up.  */
-
-/* A table that enables us to look up elts by their value.  */
-static htab_t hash_table;
-
-/* This is a global so we don't have to pass this through every function.
-   It is used in new_elt_loc_list to set SETTING_INSN.  */
-static rtx cselib_current_insn;
-
-/* Every new unknown value gets a unique number.  */
-static unsigned int next_unknown_value;
-
-/* The number of registers we had when the varrays were last resized.  */
-static int cselib_nregs;
-
-/* Count values without known locations.  Whenever this grows too big, we
-   remove these useless values from the table.  */
-static int n_useless_values;
-
-/* Number of useless values before we remove them from the hash table.  */
-#define MAX_USELESS_VALUES 32
-
-/* This table maps from register number to values.  It does not contain
-   pointers to cselib_val structures, but rather elt_lists.  The purpose is
-   to be able to refer to the same register in different modes.  */
-static varray_type reg_values;
-#define REG_VALUES(I) VARRAY_ELT_LIST (reg_values, (I))
-
-/* We pass this to cselib_invalidate_mem to invalidate all of
-   memory for a non-const call instruction.  */
-static rtx callmem;
-
-/* Memory for our structures is allocated from this obstack.  */
-static struct obstack cselib_obstack;
-
-/* Used to quickly free all memory.  */
-static char *cselib_startobj;
-
-/* Caches for unused structures.  */
-static cselib_val *empty_vals;
-static struct elt_list *empty_elt_lists;
-static struct elt_loc_list *empty_elt_loc_lists;
 
 /* Allocate a struct elt_list and fill in its two elements with the
    arguments.  */
+
 static struct elt_list *
 new_elt_list (next, elt)
      struct elt_list *next;
      cselib_val *elt;
 {
   struct elt_list *el = empty_elt_lists;
+
   if (el)
     empty_elt_lists = el->next;
   else
@@ -2061,12 +2121,14 @@ new_elt_list (next, elt)
 
 /* Allocate a struct elt_loc_list and fill in its two elements with the
    arguments.  */
+
 static struct elt_loc_list *
 new_elt_loc_list (next, loc)
      struct elt_loc_list *next;
      rtx loc;
 {
   struct elt_loc_list *el = empty_elt_loc_lists;
+
   if (el)
     empty_elt_loc_lists = el->next;
   else
@@ -2080,22 +2142,26 @@ new_elt_loc_list (next, loc)
 
 /* The elt_list at *PL is no longer needed.  Unchain it and free its
    storage.  */
+
 static void
 unchain_one_elt_list (pl)
      struct elt_list **pl;
 {
   struct elt_list *l = *pl;
+
   *pl = l->next;
   l->next = empty_elt_lists;
   empty_elt_lists = l;
 }
 
 /* Likewise for elt_loc_lists.  */
+
 static void
 unchain_one_elt_loc_list (pl)
      struct elt_loc_list **pl;
 {
   struct elt_loc_list *l = *pl;
+
   *pl = l->next;
   l->next = empty_elt_loc_lists;
   empty_elt_loc_lists = l;
@@ -2103,6 +2169,7 @@ unchain_one_elt_loc_list (pl)
 
 /* Likewise for cselib_vals.  This also frees the addr_list associated with
    V.  */
+
 static void
 unchain_one_value (v)
      cselib_val *v;
@@ -2116,10 +2183,12 @@ unchain_one_value (v)
 
 /* Remove all entries from the hash table.  Also used during
    initialization.  */
+
 static void
 clear_table ()
 {
-  int i;
+  unsigned int i;
+
   for (i = 0; i < cselib_nregs; i++)
     REG_VALUES (i) = 0;
 
@@ -2136,25 +2205,28 @@ clear_table ()
 
 /* The equality test for our hash table.  The first argument ENTRY is a table
    element (i.e. a cselib_val), while the second arg X is an rtx.  */
+
 static int
 entry_and_rtx_equal_p (entry, x_arg)
      const void *entry, *x_arg;
 {
   struct elt_loc_list *l;
-  const cselib_val *v = (const cselib_val *)entry;
-  rtx x = (rtx)x_arg;
+  const cselib_val *v = (const cselib_val *) entry;
+  rtx x = (rtx) x_arg;
 
   /* We don't guarantee that distinct rtx's have different hash values,
      so we need to do a comparison.  */
   for (l = v->locs; l; l = l->next)
     if (rtx_equal_for_cselib_p (l->loc, x))
       return 1;
+
   return 0;
 }
 
 /* The hash function for our hash table.  The value is always computed with
    hash_rtx when adding an element; this function just extracts the hash
    value from a cselib_val structure.  */
+
 static unsigned int
 get_value_hash (entry)
      const void *entry;
@@ -2163,29 +2235,11 @@ get_value_hash (entry)
   return v->value;
 }
 
-/* If there are no more locations that hold a value, the value has become
-   useless.  See whether that is the case for V.  Return 1 if this has
-   just become useless.  */
-static int
-check_value_useless (v)
-     cselib_val *v;
-{
-  if (v->locs != 0)
-    return 0;
-
-  if (v->value == 0)
-    return 0;
-
-  /* This is a marker to indicate that the value will be reclaimed.  */
-  v->value = 0;
-  n_useless_values++;
-  return 1;
-}
-
 /* Return true if X contains a VALUE rtx.  If ONLY_USELESS is set, we
    only return true for values which point to a cselib_val whose value
    element has been set to zero, which implies the cselib_val will be
    removed.  */
+
 int
 references_value_p (x, only_useless)
      rtx x;
@@ -2193,39 +2247,29 @@ references_value_p (x, only_useless)
 {
   enum rtx_code code = GET_CODE (x);
   const char *fmt = GET_RTX_FORMAT (code);
-  int i;
+  int i, j;
 
   if (GET_CODE (x) == VALUE
-      && (! only_useless || CSELIB_VAL_PTR (x)->value == 0))
+      && (! only_useless || CSELIB_VAL_PTR (x)->locs == 0))
     return 1;
 
   for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
     {
-      if (fmt[i] == 'e')
-       {
-         if (references_value_p (XEXP (x, i), only_useless))
-           return 1;
-       }
+      if (fmt[i] == 'e' && references_value_p (XEXP (x, i), only_useless))
+       return 1;
       else if (fmt[i] == 'E')
-       {
-         int j;
-
-         for (j = 0; j < XVECLEN (x, i); j++)
-           if (references_value_p (XVECEXP (x, i, j), only_useless))
-             return 1;
-       }
+       for (j = 0; j < XVECLEN (x, i); j++)
+         if (references_value_p (XVECEXP (x, i, j), only_useless))
+           return 1;
     }
 
   return 0;
 }
 
-/* Set by discard_useless_locs if it deleted the last location of any
-   value.  */
-static int values_became_useless;
-
 /* For all locations found in X, delete locations that reference useless
    values (i.e. values without any location).  Called through
    htab_traverse.  */
+
 static int
 discard_useless_locs (x, info)
      void **x;
@@ -2233,6 +2277,7 @@ discard_useless_locs (x, info)
 {
   cselib_val *v = (cselib_val *)*x;
   struct elt_loc_list **p = &v->locs;
+  int had_locs = v->locs != 0;
 
   while (*p)
     {
@@ -2241,9 +2286,12 @@ discard_useless_locs (x, info)
       else
        p = &(*p)->next;
     }
-  if (check_value_useless (v))
-    values_became_useless = 1;
 
+  if (had_locs && v->locs == 0)
+    {
+      n_useless_values++;
+      values_became_useless = 1;
+    }
   return 1;
 }
 
@@ -2256,17 +2304,19 @@ discard_useless_values (x, info)
 {
   cselib_val *v = (cselib_val *)*x;
 
-  if (v->value == 0)
+  if (v->locs == 0)
     {
       htab_clear_slot (hash_table, x);
       unchain_one_value (v);
       n_useless_values--;
     }
+
   return 1;
 }
 
 /* Clean out useless values (i.e. those which no longer have locations
    associated with them) from the hash table.  */
+
 static void
 remove_useless_values ()
 {
@@ -2288,6 +2338,7 @@ remove_useless_values ()
 
 /* Return nonzero if we can prove that X and Y contain the same value, taking
    our gathered information into account.  */
+
 int
 rtx_equal_for_cselib_p (x, y)
      rtx x, y;
@@ -2299,12 +2350,15 @@ rtx_equal_for_cselib_p (x, y)
   if (GET_CODE (x) == REG || GET_CODE (x) == MEM)
     {
       cselib_val *e = cselib_lookup (x, VOIDmode, 0);
+
       if (e)
        x = e->u.val_rtx;
     }
+
   if (GET_CODE (y) == REG || GET_CODE (y) == MEM)
     {
       cselib_val *e = cselib_lookup (y, VOIDmode, 0);
+
       if (e)
        y = e->u.val_rtx;
     }
@@ -2327,8 +2381,7 @@ rtx_equal_for_cselib_p (x, y)
          /* Avoid infinite recursion.  */
          if (GET_CODE (t) == REG || GET_CODE (t) == MEM)
            continue;
-
-         if (rtx_equal_for_cselib_p (t, y))
+         else if (rtx_equal_for_cselib_p (t, y))
            return 1;
        }
       
@@ -2346,16 +2399,14 @@ rtx_equal_for_cselib_p (x, y)
 
          if (GET_CODE (t) == REG || GET_CODE (t) == MEM)
            continue;
-
-         if (rtx_equal_for_cselib_p (x, t))
+         else if (rtx_equal_for_cselib_p (x, t))
            return 1;
        }
       
       return 0;
     }
 
-  if (GET_CODE (x) != GET_CODE (y)
-      || GET_MODE (x) != GET_MODE (y))
+  if (GET_CODE (x) != GET_CODE (y) || GET_MODE (x) != GET_MODE (y))
     return 0;
 
   /* This won't be handled correctly by the code below.  */
@@ -2368,6 +2419,7 @@ rtx_equal_for_cselib_p (x, y)
   for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
     {
       int j;
+
       switch (fmt[i])
        {
        case 'w':
@@ -2431,6 +2483,7 @@ rtx_equal_for_cselib_p (x, y)
    CREATE is nonzero, table elts are created for regs and mem.
    MODE is used in hashing for CONST_INTs only;
    otherwise the mode of X is used.  */
+
 static unsigned int
 hash_rtx (x, mode, create)
      rtx x;
@@ -2455,15 +2508,13 @@ hash_rtx (x, mode, create)
       e = cselib_lookup (x, GET_MODE (x), create);
       if (! e)
        return 0;
+
       hash += e->value;
       return hash;
 
     case CONST_INT:
-      {
-       unsigned HOST_WIDE_INT tem = INTVAL (x);
-       hash += ((unsigned) CONST_INT << 7) + (unsigned) mode + tem;
-       return hash ? hash : CONST_INT;
-      }
+      hash += ((unsigned) CONST_INT << 7) + (unsigned) mode + INTVAL (x);
+      return hash ? hash : CONST_INT;
 
     case CONST_DOUBLE:
       /* This is like the general case, except that it only counts
@@ -2471,10 +2522,7 @@ hash_rtx (x, mode, create)
       hash += (unsigned) code + (unsigned) GET_MODE (x);
       if (GET_MODE (x) != VOIDmode)
        for (i = 2; i < GET_RTX_LENGTH (CONST_DOUBLE); i++)
-         {
-           unsigned HOST_WIDE_INT tem = XWINT (x, i);
-           hash += tem;
-         }
+         hash += XWINT (x, i);
       else
        hash += ((unsigned) CONST_DOUBLE_LOW (x)
                 + (unsigned) CONST_DOUBLE_HIGH (x));
@@ -2495,6 +2543,8 @@ hash_rtx (x, mode, create)
     case PRE_INC:
     case POST_DEC:
     case POST_INC:
+    case POST_MODIFY:
+    case PRE_MODIFY:
     case PC:
     case CC0:
     case CALL:
@@ -2517,8 +2567,8 @@ hash_rtx (x, mode, create)
     {
       if (fmt[i] == 'e')
        {
-         unsigned int tem_hash;
          rtx tem = XEXP (x, i);
+         unsigned int tem_hash;
 
          /* If we are about to do the last recursive call
             needed at this level, change it into iteration.
@@ -2528,57 +2578,63 @@ hash_rtx (x, mode, create)
              x = tem;
              goto repeat;
            }
+
          tem_hash = hash_rtx (tem, 0, create);
          if (tem_hash == 0)
            return 0;
+
          hash += tem_hash;
        }
       else if (fmt[i] == 'E')
        for (j = 0; j < XVECLEN (x, i); j++)
          {
            unsigned int tem_hash = hash_rtx (XVECEXP (x, i, j), 0, create);
+
            if (tem_hash == 0)
              return 0;
+
            hash += tem_hash;
          }
       else if (fmt[i] == 's')
        {
          const unsigned char *p = (const unsigned char *) XSTR (x, i);
+
          if (p)
            while (*p)
              hash += *p++;
        }
       else if (fmt[i] == 'i')
-       {
-         unsigned int tem = XINT (x, i);
-         hash += tem;
-       }
+       hash += XINT (x, i);
       else if (fmt[i] == '0' || fmt[i] == 't')
        /* unused */;
       else
        abort ();
     }
+
   return hash ? hash : 1 + GET_CODE (x);
 }
 
 /* Create a new value structure for VALUE and initialize it.  The mode of the
    value is MODE.  */
+
 static cselib_val *
 new_cselib_val (value, mode)
      unsigned int value;
      enum machine_mode mode;
 {
   cselib_val *e = empty_vals;
+
   if (e)
     empty_vals = e->u.next_free;
   else
     e = (cselib_val *) obstack_alloc (&cselib_obstack, sizeof (cselib_val));
+
   if (value == 0)
     abort ();
+
   e->value = value;
   e->u.val_rtx = gen_rtx_VALUE (mode);
   CSELIB_VAL_PTR (e->u.val_rtx) = e;
-
   e->addr_list = 0;
   e->locs = 0;
   return e;
@@ -2587,6 +2643,7 @@ new_cselib_val (value, mode)
 /* ADDR_ELT is a value that is used as address.  MEM_ELT is the value that
    contains the data at this address.  X is a MEM that represents the
    value.  Update the two value structures to represent this situation.  */
+
 static void
 add_mem_for_addr (addr_elt, mem_elt, x)
      cselib_val *addr_elt, *mem_elt;
@@ -2602,16 +2659,15 @@ add_mem_for_addr (addr_elt, mem_elt, x)
       return;
 
   new = gen_rtx_MEM (GET_MODE (x), addr_elt->u.val_rtx);
-  addr_elt->addr_list = new_elt_list (addr_elt->addr_list, mem_elt);
-
-  RTX_UNCHANGING_P (new) = RTX_UNCHANGING_P (x);
   MEM_COPY_ATTRIBUTES (new, x);
 
+  addr_elt->addr_list = new_elt_list (addr_elt->addr_list, mem_elt);
   mem_elt->locs = new_elt_loc_list (mem_elt->locs, new);
 }
 
 /* Subroutine of cselib_lookup.  Return a value for X, which is a MEM rtx.
    If CREATE, make a new one if we haven't seen it before.  */
+
 static cselib_val *
 cselib_lookup_mem (x, create)
      rtx x;
@@ -2622,9 +2678,8 @@ cselib_lookup_mem (x, create)
   cselib_val *mem_elt;
   struct elt_list *l;
 
-  if (MEM_VOLATILE_P (x) || GET_MODE (x) == BLKmode)
-    return 0;
-  if (FLOAT_MODE_P (GET_MODE (x)) && flag_float_store)
+  if (MEM_VOLATILE_P (x) || GET_MODE (x) == BLKmode
+      || (FLOAT_MODE_P (GET_MODE (x)) && flag_float_store))
     return 0;
 
   /* Look up the value for the address.  */
@@ -2636,11 +2691,13 @@ cselib_lookup_mem (x, create)
   for (l = addr->addr_list; l; l = l->next)
     if (GET_MODE (l->elt->u.val_rtx) == GET_MODE (x))
       return l->elt;
+
   if (! create)
     return 0;
+
   mem_elt = new_cselib_val (++next_unknown_value, GET_MODE (x));
   add_mem_for_addr (addr, mem_elt, x);
-  slot = htab_find_slot_with_hash (hash_table, x, mem_elt->value, 1);
+  slot = htab_find_slot_with_hash (hash_table, x, mem_elt->value, INSERT);
   *slot = mem_elt;
   return mem_elt;
 }
@@ -2650,6 +2707,7 @@ cselib_lookup_mem (x, create)
    to registers and memory.
    X isn't actually modified; if modifications are needed, new rtl is
    allocated.  However, the return value can share rtl with X.  */
+
 static rtx
 cselib_subst_to_values (x)
      rtx x;
@@ -2664,10 +2722,10 @@ cselib_subst_to_values (x)
   switch (code)
     {
     case REG:
-      i = REGNO (x);
-      for (l = REG_VALUES (i); l; l = l->next)
+      for (l = REG_VALUES (REGNO (x)); l; l = l->next)
        if (GET_MODE (l->elt->u.val_rtx) == GET_MODE (x))
          return l->elt->u.val_rtx;
+
       abort ();
 
     case MEM:
@@ -2691,8 +2749,10 @@ cselib_subst_to_values (x)
       if (fmt[i] == 'e')
        {
          rtx t = cselib_subst_to_values (XEXP (x, i));
+
          if (t != XEXP (x, i) && x == copy)
            copy = shallow_copy_rtx (x);
+
          XEXP (copy, i) = t;
        }
       else if (fmt[i] == 'E')
@@ -2702,18 +2762,22 @@ cselib_subst_to_values (x)
          for (j = 0; j < XVECLEN (x, i); j++)
            {
              rtx t = cselib_subst_to_values (XVECEXP (x, i, j));
+
              if (t != XVECEXP (x, i, j) && XVEC (x, i) == XVEC (copy, i))
                {
                  if (x == copy)
                    copy = shallow_copy_rtx (x);
+
                  XVEC (copy, i) = rtvec_alloc (XVECLEN (x, i));
                  for (k = 0; k < j; k++)
                    XVECEXP (copy, i, k) = XVECEXP (x, i, k);
                }
+
              XVECEXP (copy, i, j) = t;
            }
        }
     }
+
   return copy;
 }
 
@@ -2721,6 +2785,7 @@ cselib_subst_to_values (x)
    If CREATE is zero, we return NULL if we don't know the value.  Otherwise,
    we create a new one if possible, using mode MODE if X doesn't have a mode
    (i.e. because it's a constant).  */
+
 cselib_val *
 cselib_lookup (x, mode, create)
      rtx x;
@@ -2740,16 +2805,19 @@ cselib_lookup (x, mode, create)
   if (GET_CODE (x) == REG)
     {
       struct elt_list *l;
-      int i = REGNO (x);
+      unsigned int i = REGNO (x);
+
       for (l = REG_VALUES (i); l; l = l->next)
        if (mode == GET_MODE (l->elt->u.val_rtx))
          return l->elt;
+
       if (! create)
        return 0;
+
       e = new_cselib_val (++next_unknown_value, GET_MODE (x));
       e->locs = new_elt_loc_list (e->locs, x);
       REG_VALUES (i) = new_elt_list (REG_VALUES (i), e);
-      slot = htab_find_slot_with_hash (hash_table, x, e->value, 1);
+      slot = htab_find_slot_with_hash (hash_table, x, e->value, INSERT);
       *slot = e;
       return e;
     }
@@ -2762,14 +2830,17 @@ cselib_lookup (x, mode, create)
   if (! hashval)
     return 0;
 
-  slot = htab_find_slot_with_hash (hash_table, x, hashval, create);
+  slot = htab_find_slot_with_hash (hash_table, x, hashval,
+                                  create ? INSERT : NO_INSERT);
   if (slot == 0)
     return 0;
+
   e = (cselib_val *) *slot;
   if (e)
     return e;
 
   e = new_cselib_val (hashval, mode);
+
   /* We have to fill the slot before calling cselib_subst_to_values:
      the hash table is inconsistent until we do so, and
      cselib_subst_to_values will need to do lookups.  */
@@ -2841,13 +2912,15 @@ cselib_invalidate_regno (regno, mode)
                  break;
                }
            }
-         check_value_useless (v);
+         if (v->locs == 0)
+           n_useless_values++;
        }
     }
 }
 
 /* The memory at address MEM_BASE is being changed.
    Return whether this change will invalidate VAL.  */
+
 static int
 cselib_mem_conflict_p (mem_base, val)
      rtx mem_base;
@@ -2855,7 +2928,7 @@ cselib_mem_conflict_p (mem_base, val)
 {
   enum rtx_code code;
   const char *fmt;
-  int i;
+  int i, j;
 
   code = GET_CODE (val);
   switch (code)
@@ -2874,10 +2947,10 @@ cselib_mem_conflict_p (mem_base, val)
 
     case MEM:
       if (GET_MODE (mem_base) == BLKmode
-         || GET_MODE (val) == BLKmode)
-       return 1;
-      if (anti_dependence (val, mem_base))
+         || GET_MODE (val) == BLKmode
+         || anti_dependence (val, mem_base))
        return 1;
+
       /* The address may contain nested MEMs.  */
       break;
 
@@ -2886,7 +2959,6 @@ cselib_mem_conflict_p (mem_base, val)
     }
 
   fmt = GET_RTX_FORMAT (code);
-
   for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
     {
       if (fmt[i] == 'e')
@@ -2895,13 +2967,9 @@ cselib_mem_conflict_p (mem_base, val)
            return 1;
        }
       else if (fmt[i] == 'E')
-       {
-         int j;
-
-         for (j = 0; j < XVECLEN (val, i); j++)
-           if (cselib_mem_conflict_p (mem_base, XVECEXP (val, i, j)))
-             return 1;
-       }
+       for (j = 0; j < XVECLEN (val, i); j++)
+         if (cselib_mem_conflict_p (mem_base, XVECEXP (val, i, j)))
+           return 1;
     }
 
   return 0;
@@ -2909,6 +2977,7 @@ cselib_mem_conflict_p (mem_base, val)
 
 /* For the value found in SLOT, walk its locations to determine if any overlap
    INFO (which is a MEM rtx).  */
+
 static int
 cselib_invalidate_mem_1 (slot, info)
      void **slot;
@@ -2917,12 +2986,13 @@ cselib_invalidate_mem_1 (slot, info)
   cselib_val *v = (cselib_val *) *slot;
   rtx mem_rtx = (rtx) info;
   struct elt_loc_list **p = &v->locs;
+  int had_locs = v->locs != 0;
 
   while (*p)
     {
+      rtx x = (*p)->loc;
       cselib_val *addr;
       struct elt_list **mem_chain;
-      rtx x = (*p)->loc;
 
       /* MEMs may occur in locations only at the top level; below
         that every MEM or REG is substituted by its VALUE.  */
@@ -2945,17 +3015,23 @@ cselib_invalidate_mem_1 (slot, info)
              unchain_one_elt_list (mem_chain);
              break;
            }
+
          mem_chain = &(*mem_chain)->next;
        }
+
       unchain_one_elt_loc_list (p);
     }
-  check_value_useless (v);
+
+  if (had_locs && v->locs == 0)
+    n_useless_values++;
+
   return 1;
 }
 
 /* Invalidate any locations in the table which are changed because of a
    store to MEM_RTX.  If this is called because of a non-const call
    instruction, MEM_RTX is (mem:BLK const0_rtx).  */
+
 static void
 cselib_invalidate_mem (mem_rtx)
      rtx mem_rtx;
@@ -2966,16 +3042,15 @@ cselib_invalidate_mem (mem_rtx)
 /* Invalidate DEST, which is being assigned to or clobbered.  The second and
    the third parameter exist so that this function can be passed to
    note_stores; they are ignored.  */
+
 static void
 cselib_invalidate_rtx (dest, ignore, data)
      rtx dest;
      rtx ignore ATTRIBUTE_UNUSED;
      void *data ATTRIBUTE_UNUSED;
 {
-  while (GET_CODE (dest) == STRICT_LOW_PART
-        || GET_CODE (dest) == SIGN_EXTRACT
-        || GET_CODE (dest) == ZERO_EXTRACT
-        || GET_CODE (dest) == SUBREG)
+  while (GET_CODE (dest) == STRICT_LOW_PART || GET_CODE (dest) == SIGN_EXTRACT
+        || GET_CODE (dest) == ZERO_EXTRACT || GET_CODE (dest) == SUBREG)
     dest = XEXP (dest, 0);
 
   if (GET_CODE (dest) == REG)
@@ -3008,10 +3083,16 @@ cselib_record_set (dest, src_elt, dest_addr_elt)
   if (dreg >= 0)
     {
       REG_VALUES (dreg) = new_elt_list (REG_VALUES (dreg), src_elt);
+      if (src_elt->locs == 0)
+       n_useless_values--;
       src_elt->locs = new_elt_loc_list (src_elt->locs, dest);
     }
   else if (GET_CODE (dest) == MEM && dest_addr_elt != 0)
-    add_mem_for_addr (dest_addr_elt, src_elt, dest);
+    {
+      if (src_elt->locs == 0)
+       n_useless_values--;
+      add_mem_for_addr (dest_addr_elt, src_elt, dest);
+    }
 }
 
 /* Describe a single set that is part of an insn.  */
@@ -3086,11 +3167,13 @@ cselib_record_sets (insn)
 }
 
 /* Record the effects of INSN.  */
+
 void
 cselib_process_insn (insn)
      rtx insn;
 {
   int i;
+  rtx x;
 
   cselib_current_insn = insn;
 
@@ -3106,11 +3189,12 @@ cselib_process_insn (insn)
       return;
     }
 
-  if (GET_RTX_CLASS (GET_CODE (insn)) != 'i')
+  if (! INSN_P (insn))
     {
       cselib_current_insn = 0;
       return;
     }
+
   /* If this is a call instruction, forget anything stored in a
      call clobbered register, or, if this is not a const call, in
      memory.  */
@@ -3130,26 +3214,17 @@ cselib_process_insn (insn)
   /* Clobber any registers which appear in REG_INC notes.  We
      could keep track of the changes to their values, but it is
      unlikely to help.  */
-  {
-    rtx x;
-
-    for (x = REG_NOTES (insn); x; x = XEXP (x, 1))
-      if (REG_NOTE_KIND (x) == REG_INC)
-       cselib_invalidate_rtx (XEXP (x, 0), NULL_RTX, NULL);
-  }
+  for (x = REG_NOTES (insn); x; x = XEXP (x, 1))
+    if (REG_NOTE_KIND (x) == REG_INC)
+      cselib_invalidate_rtx (XEXP (x, 0), NULL_RTX, NULL);
 #endif
 
   /* Look for any CLOBBERs in CALL_INSN_FUNCTION_USAGE, but only
      after we have processed the insn.  */
   if (GET_CODE (insn) == CALL_INSN)
-    {
-      rtx x;
-
-      for (x = CALL_INSN_FUNCTION_USAGE (insn); x; x = XEXP (x, 1))
-       if (GET_CODE (XEXP (x, 0)) == CLOBBER)
-         cselib_invalidate_rtx (XEXP (XEXP (x, 0), 0), NULL_RTX,
-                                    NULL);
-    }
+    for (x = CALL_INSN_FUNCTION_USAGE (insn); x; x = XEXP (x, 1))
+      if (GET_CODE (XEXP (x, 0)) == CLOBBER)
+       cselib_invalidate_rtx (XEXP (XEXP (x, 0), 0), NULL_RTX, NULL);
 
   cselib_current_insn = 0;
 
@@ -3159,18 +3234,22 @@ cselib_process_insn (insn)
 
 /* Make sure our varrays are big enough.  Not called from any cselib routines;
    it must be called by the user if it allocated new registers.  */
+
 void
 cselib_update_varray_sizes ()
 {
-  int nregs = max_reg_num ();
+  unsigned int nregs = max_reg_num ();
+
   if (nregs == cselib_nregs)
     return;
+
   cselib_nregs = nregs;
   VARRAY_GROW (reg_values, nregs);
 }
 
 /* Initialize cselib for one pass.  The caller must also call
    init_alias_analysis.  */
+
 void
 cselib_init ()
 {
@@ -3178,6 +3257,7 @@ cselib_init ()
   if (! callmem)
     {
       extern struct obstack permanent_obstack;
+
       gcc_obstack_init (&cselib_obstack);
       cselib_startobj = obstack_alloc (&cselib_obstack, 0);
 
@@ -3194,6 +3274,7 @@ cselib_init ()
 }
 
 /* Called when the current user is done with cselib.  */
+
 void
 cselib_finish ()
 {