OSDN Git Service

2011-08-18 Tobias Burnus <burnus@net-b.de>
[pf3gnuchains/gcc-fork.git] / gcc / cselib.c
index f63ea3f..b96c0cd 100644 (file)
@@ -1,6 +1,6 @@
 /* Common subexpression elimination library for GNU compiler.
    Copyright (C) 1987, 1988, 1989, 1992, 1993, 1994, 1995, 1996, 1997, 1998,
-   1999, 2000, 2001, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010
+   1999, 2000, 2001, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011
    Free Software Foundation, Inc.
 
 This file is part of GCC.
@@ -29,12 +29,11 @@ along with GCC; see the file COPYING3.  If not see
 #include "regs.h"
 #include "hard-reg-set.h"
 #include "flags.h"
-#include "real.h"
 #include "insn-config.h"
 #include "recog.h"
 #include "function.h"
 #include "emit-rtl.h"
-#include "toplev.h"
+#include "diagnostic-core.h"
 #include "output.h"
 #include "ggc.h"
 #include "hashtab.h"
@@ -43,8 +42,16 @@ along with GCC; see the file COPYING3.  If not see
 #include "params.h"
 #include "alloc-pool.h"
 #include "target.h"
+#include "bitmap.h"
+
+/* A list of cselib_val structures.  */
+struct elt_list {
+    struct elt_list *next;
+    cselib_val *elt;
+};
 
 static bool cselib_record_memory;
+static bool cselib_preserve_constants;
 static int entry_and_rtx_equal_p (const void *, const void *);
 static hashval_t get_value_hash (const void *);
 static struct elt_list *new_elt_list (struct elt_list *, cselib_val *);
@@ -55,7 +62,8 @@ static void unchain_one_elt_loc_list (struct elt_loc_list **);
 static int discard_useless_locs (void **, void *);
 static int discard_useless_values (void **, void *);
 static void remove_useless_values (void);
-static unsigned int cselib_hash_rtx (rtx, int);
+static int rtx_equal_for_cselib_1 (rtx, rtx, enum machine_mode);
+static unsigned int cselib_hash_rtx (rtx, int, enum machine_mode);
 static cselib_val *new_cselib_val (unsigned int, enum machine_mode, rtx);
 static void add_mem_for_addr (cselib_val *, cselib_val *, rtx);
 static cselib_val *cselib_lookup_mem (rtx, int);
@@ -96,9 +104,47 @@ static unsigned int next_uid;
 /* 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.  */
+/* Count values without known locations, or with only locations that
+   wouldn't have been known except for debug insns.  Whenever this
+   grows too big, we remove these useless values from the table.
+
+   Counting values with only debug values is a bit tricky.  We don't
+   want to increment n_useless_values when we create a value for a
+   debug insn, for this would get n_useless_values out of sync, but we
+   want increment it if all locs in the list that were ever referenced
+   in nondebug insns are removed from the list.
+
+   In the general case, once we do that, we'd have to stop accepting
+   nondebug expressions in the loc list, to avoid having two values
+   equivalent that, without debug insns, would have been made into
+   separate values.  However, because debug insns never introduce
+   equivalences themselves (no assignments), the only means for
+   growing loc lists is through nondebug assignments.  If the locs
+   also happen to be referenced in debug insns, it will work just fine.
+
+   A consequence of this is that there's at most one debug-only loc in
+   each loc list.  If we keep it in the first entry, testing whether
+   we have a debug-only loc list takes O(1).
+
+   Furthermore, since any additional entry in a loc list containing a
+   debug loc would have to come from an assignment (nondebug) that
+   references both the initial debug loc and the newly-equivalent loc,
+   the initial debug loc would be promoted to a nondebug loc, and the
+   loc list would not contain debug locs any more.
+
+   So the only case we have to be careful with in order to keep
+   n_useless_values in sync between debug and nondebug compilations is
+   to avoid incrementing n_useless_values when removing the single loc
+   from a value that turns out to not appear outside debug values.  We
+   increment n_useless_debug_values instead, and leave such values
+   alone until, for other reasons, we garbage-collect useless
+   values.  */
 static int n_useless_values;
+static int n_useless_debug_values;
+
+/* Count values whose locs have been taken exclusively from debug
+   insns for the entire life of the value.  */
+static int n_debug_values;
 
 /* Number of useless values before we remove them from the hash table.  */
 #define MAX_USELESS_VALUES 32
@@ -135,6 +181,12 @@ static int values_became_useless;
    presence in the list by checking the next pointer.  */
 static cselib_val dummy_val;
 
+/* If non-NULL, value of the eliminated arg_pointer_rtx or frame_pointer_rtx
+   that is constant through the whole function and should never be
+   eliminated.  */
+static cselib_val *cfa_base_preserved_val;
+static unsigned int cfa_base_preserved_regno;
+
 /* Used to list all values that contain memory reference.
    May or may not contain the useless values - the list is compacted
    each time memory is invalidated.  */
@@ -182,9 +234,41 @@ new_elt_loc_list (struct elt_loc_list *next, rtx loc)
   el->next = next;
   el->loc = loc;
   el->setting_insn = cselib_current_insn;
+  gcc_assert (!next || !next->setting_insn
+             || !DEBUG_INSN_P (next->setting_insn));
+
+  /* If we're creating the first loc in a debug insn context, we've
+     just created a debug value.  Count it.  */
+  if (!next && cselib_current_insn && DEBUG_INSN_P (cselib_current_insn))
+    n_debug_values++;
+
   return el;
 }
 
+/* Promote loc L to a nondebug cselib_current_insn if L is marked as
+   originating from a debug insn, maintaining the debug values
+   count.  */
+
+static inline void
+promote_debug_loc (struct elt_loc_list *l)
+{
+  if (l->setting_insn && DEBUG_INSN_P (l->setting_insn)
+      && (!cselib_current_insn || !DEBUG_INSN_P (cselib_current_insn)))
+    {
+      n_debug_values--;
+      l->setting_insn = cselib_current_insn;
+      if (cselib_preserve_constants && l->next)
+       {
+         gcc_assert (l->next->setting_insn
+                     && DEBUG_INSN_P (l->next->setting_insn)
+                     && !l->next->next);
+         l->next->setting_insn = cselib_current_insn;
+       }
+      else
+       gcc_assert (!l->next);
+    }
+}
+
 /* The elt_list at *PL is no longer needed.  Unchain it and free its
    storage.  */
 
@@ -229,6 +313,44 @@ cselib_clear_table (void)
   cselib_reset_table (1);
 }
 
+/* Remove from hash table all VALUEs except constants
+   and function invariants.  */
+
+static int
+preserve_only_constants (void **x, void *info ATTRIBUTE_UNUSED)
+{
+  cselib_val *v = (cselib_val *)*x;
+
+  if (v->locs != NULL
+      && v->locs->next == NULL)
+    {
+      if (CONSTANT_P (v->locs->loc)
+         && (GET_CODE (v->locs->loc) != CONST
+             || !references_value_p (v->locs->loc, 0)))
+       return 1;
+      if (cfa_base_preserved_val)
+       {
+         if (v == cfa_base_preserved_val)
+           return 1;
+         if (GET_CODE (v->locs->loc) == PLUS
+             && CONST_INT_P (XEXP (v->locs->loc, 1))
+             && XEXP (v->locs->loc, 0) == cfa_base_preserved_val->val_rtx)
+           return 1;
+       }
+    }
+  /* Keep around VALUEs that forward function invariant ENTRY_VALUEs
+     to corresponding parameter VALUEs.  */
+  if (v->locs != NULL
+      && v->locs->next != NULL
+      && v->locs->next->next == NULL
+      && GET_CODE (v->locs->next->loc) == ENTRY_VALUE
+      && GET_CODE (v->locs->loc) == VALUE)
+    return 1;
+
+  htab_clear_slot (cselib_hash_table, x);
+  return 1;
+}
+
 /* Remove all entries from the hash table, arranging for the next
    value to be numbered NUM.  */
 
@@ -237,17 +359,41 @@ cselib_reset_table (unsigned int num)
 {
   unsigned int i;
 
-  for (i = 0; i < n_used_regs; i++)
-    REG_VALUES (used_regs[i]) = 0;
-
   max_value_regs = 0;
 
-  n_used_regs = 0;
+  if (cfa_base_preserved_val)
+    {
+      unsigned int regno = cfa_base_preserved_regno;
+      unsigned int new_used_regs = 0;
+      for (i = 0; i < n_used_regs; i++)
+       if (used_regs[i] == regno)
+         {
+           new_used_regs = 1;
+           continue;
+         }
+       else
+         REG_VALUES (used_regs[i]) = 0;
+      gcc_assert (new_used_regs == 1);
+      n_used_regs = new_used_regs;
+      used_regs[0] = regno;
+      max_value_regs
+       = hard_regno_nregs[regno][GET_MODE (cfa_base_preserved_val->locs->loc)];
+    }
+  else
+    {
+      for (i = 0; i < n_used_regs; i++)
+       REG_VALUES (used_regs[i]) = 0;
+      n_used_regs = 0;
+    }
 
-  /* ??? Preserve constants?  */
-  htab_empty (cselib_hash_table);
+  if (cselib_preserve_constants)
+    htab_traverse (cselib_hash_table, preserve_only_constants, NULL);
+  else
+    htab_empty (cselib_hash_table);
 
   n_useless_values = 0;
+  n_useless_debug_values = 0;
+  n_debug_values = 0;
 
   next_uid = num;
 
@@ -262,6 +408,26 @@ cselib_get_next_uid (void)
   return next_uid;
 }
 
+/* See the documentation of cselib_find_slot below.  */
+static enum machine_mode find_slot_memmode;
+
+/* Search for X, whose hashcode is HASH, in CSELIB_HASH_TABLE,
+   INSERTing if requested.  When X is part of the address of a MEM,
+   MEMMODE should specify the mode of the MEM.  While searching the
+   table, MEMMODE is held in FIND_SLOT_MEMMODE, so that autoinc RTXs
+   in X can be resolved.  */
+
+static void **
+cselib_find_slot (rtx x, hashval_t hash, enum insert_option insert,
+                 enum machine_mode memmode)
+{
+  void **slot;
+  find_slot_memmode = memmode;
+  slot = htab_find_slot_with_hash (cselib_hash_table, x, hash, insert);
+  find_slot_memmode = VOIDmode;
+  return slot;
+}
+
 /* 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.  We know
    that all callers of htab_find_slot_with_hash will wrap CONST_INTs into a
@@ -291,8 +457,11 @@ entry_and_rtx_equal_p (const void *entry, const void *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;
+    if (rtx_equal_for_cselib_1 (l->loc, x, find_slot_memmode))
+      {
+       promote_debug_loc (l);
+       return 1;
+      }
 
   return 0;
 }
@@ -346,7 +515,8 @@ discard_useless_locs (void **x, void *info ATTRIBUTE_UNUSED)
 {
   cselib_val *v = (cselib_val *)*x;
   struct elt_loc_list **p = &v->locs;
-  int had_locs = v->locs != 0;
+  bool had_locs = v->locs != NULL;
+  rtx setting_insn = v->locs ? v->locs->setting_insn : NULL;
 
   while (*p)
     {
@@ -358,7 +528,10 @@ discard_useless_locs (void **x, void *info ATTRIBUTE_UNUSED)
 
   if (had_locs && v->locs == 0 && !PRESERVED_VALUE_P (v->val_rtx))
     {
-      n_useless_values++;
+      if (setting_insn && DEBUG_INSN_P (setting_insn))
+       n_useless_debug_values++;
+      else
+       n_useless_values++;
       values_became_useless = 1;
     }
   return 1;
@@ -392,6 +565,7 @@ static void
 remove_useless_values (void)
 {
   cselib_val **p, *v;
+
   /* First pass: eliminate locations that reference the value.  That in
      turn can make more values useless.  */
   do
@@ -412,6 +586,10 @@ remove_useless_values (void)
       }
   *p = &dummy_val;
 
+  n_useless_values += n_useless_debug_values;
+  n_debug_values -= n_useless_debug_values;
+  n_useless_debug_values = 0;
+
   htab_traverse (cselib_hash_table, discard_useless_values, 0);
 
   gcc_assert (!n_useless_values);
@@ -434,6 +612,21 @@ cselib_preserved_value_p (cselib_val *v)
   return PRESERVED_VALUE_P (v->val_rtx);
 }
 
+/* Arrange for a REG value to be assumed constant through the whole function,
+   never invalidated and preserved across cselib_reset_table calls.  */
+
+void
+cselib_preserve_cfa_base_value (cselib_val *v, unsigned int regno)
+{
+  if (cselib_preserve_constants
+      && v->locs
+      && REG_P (v->locs->loc))
+    {
+      cfa_base_preserved_val = v;
+      cfa_base_preserved_regno = regno;
+    }
+}
+
 /* Clean all non-constant expressions in the hash table, but retain
    their values.  */
 
@@ -476,13 +669,65 @@ cselib_reg_set_mode (const_rtx x)
 int
 rtx_equal_for_cselib_p (rtx x, rtx y)
 {
+  return rtx_equal_for_cselib_1 (x, y, VOIDmode);
+}
+
+/* If x is a PLUS or an autoinc operation, expand the operation,
+   storing the offset, if any, in *OFF.  */
+
+static rtx
+autoinc_split (rtx x, rtx *off, enum machine_mode memmode)
+{
+  switch (GET_CODE (x))
+    {
+    case PLUS:
+      *off = XEXP (x, 1);
+      return XEXP (x, 0);
+
+    case PRE_DEC:
+      if (memmode == VOIDmode)
+       return x;
+
+      *off = GEN_INT (-GET_MODE_SIZE (memmode));
+      return XEXP (x, 0);
+      break;
+
+    case PRE_INC:
+      if (memmode == VOIDmode)
+       return x;
+
+      *off = GEN_INT (GET_MODE_SIZE (memmode));
+      return XEXP (x, 0);
+
+    case PRE_MODIFY:
+      return XEXP (x, 1);
+
+    case POST_DEC:
+    case POST_INC:
+    case POST_MODIFY:
+      return XEXP (x, 0);
+
+    default:
+      return x;
+    }
+}
+
+/* Return nonzero if we can prove that X and Y contain the same value,
+   taking our gathered information into account.  MEMMODE holds the
+   mode of the enclosing MEM, if any, as required to deal with autoinc
+   addressing modes.  If X and Y are not (known to be) part of
+   addresses, MEMMODE should be VOIDmode.  */
+
+static int
+rtx_equal_for_cselib_1 (rtx x, rtx y, enum machine_mode memmode)
+{
   enum rtx_code code;
   const char *fmt;
   int i;
 
   if (REG_P (x) || MEM_P (x))
     {
-      cselib_val *e = cselib_lookup (x, GET_MODE (x), 0);
+      cselib_val *e = cselib_lookup (x, GET_MODE (x), 0, memmode);
 
       if (e)
        x = e->val_rtx;
@@ -490,7 +735,7 @@ rtx_equal_for_cselib_p (rtx x, rtx y)
 
   if (REG_P (y) || MEM_P (y))
     {
-      cselib_val *e = cselib_lookup (y, GET_MODE (y), 0);
+      cselib_val *e = cselib_lookup (y, GET_MODE (y), 0, memmode);
 
       if (e)
        y = e->val_rtx;
@@ -514,7 +759,7 @@ rtx_equal_for_cselib_p (rtx x, rtx y)
          /* Avoid infinite recursion.  */
          if (REG_P (t) || MEM_P (t))
            continue;
-         else if (rtx_equal_for_cselib_p (t, y))
+         else if (rtx_equal_for_cselib_1 (t, y, memmode))
            return 1;
        }
 
@@ -532,16 +777,37 @@ rtx_equal_for_cselib_p (rtx x, rtx y)
 
          if (REG_P (t) || MEM_P (t))
            continue;
-         else if (rtx_equal_for_cselib_p (x, t))
+         else if (rtx_equal_for_cselib_1 (x, t, memmode))
            return 1;
        }
 
       return 0;
     }
 
-  if (GET_CODE (x) != GET_CODE (y) || GET_MODE (x) != GET_MODE (y))
+  if (GET_MODE (x) != GET_MODE (y))
     return 0;
 
+  if (GET_CODE (x) != GET_CODE (y))
+    {
+      rtx xorig = x, yorig = y;
+      rtx xoff = NULL, yoff = NULL;
+
+      x = autoinc_split (x, &xoff, memmode);
+      y = autoinc_split (y, &yoff, memmode);
+
+      if (!xoff != !yoff)
+       return 0;
+
+      if (xoff && !rtx_equal_for_cselib_1 (xoff, yoff, memmode))
+       return 0;
+
+      /* Don't recurse if nothing changed.  */
+      if (x != xorig || y != yorig)
+       return rtx_equal_for_cselib_1 (x, y, memmode);
+
+      return 0;
+    }
+
   /* These won't be handled correctly by the code below.  */
   switch (GET_CODE (x))
     {
@@ -550,9 +816,27 @@ rtx_equal_for_cselib_p (rtx x, rtx y)
     case DEBUG_EXPR:
       return 0;
 
+    case DEBUG_IMPLICIT_PTR:
+      return DEBUG_IMPLICIT_PTR_DECL (x)
+            == DEBUG_IMPLICIT_PTR_DECL (y);
+
+    case DEBUG_PARAMETER_REF:
+      return DEBUG_PARAMETER_REF_DECL (x)
+            == DEBUG_PARAMETER_REF_DECL (y);
+
+    case ENTRY_VALUE:
+      /* ENTRY_VALUEs are function invariant, it is thus undesirable to
+        use rtx_equal_for_cselib_1 to compare the operands.  */
+      return rtx_equal_p (ENTRY_VALUE_EXP (x), ENTRY_VALUE_EXP (y));
+
     case LABEL_REF:
       return XEXP (x, 0) == XEXP (y, 0);
 
+    case MEM:
+      /* We have to compare any autoinc operations in the addresses
+        using this MEM's mode.  */
+      return rtx_equal_for_cselib_1 (XEXP (x, 0), XEXP (y, 0), GET_MODE (x));
+
     default:
       break;
     }
@@ -585,18 +869,18 @@ rtx_equal_for_cselib_p (rtx x, rtx y)
 
          /* And the corresponding elements must match.  */
          for (j = 0; j < XVECLEN (x, i); j++)
-           if (! rtx_equal_for_cselib_p (XVECEXP (x, i, j),
-                                         XVECEXP (y, i, j)))
+           if (! rtx_equal_for_cselib_1 (XVECEXP (x, i, j),
+                                         XVECEXP (y, i, j), memmode))
              return 0;
          break;
 
        case 'e':
          if (i == 1
              && targetm.commutative_p (x, UNKNOWN)
-             && rtx_equal_for_cselib_p (XEXP (x, 1), XEXP (y, 0))
-             && rtx_equal_for_cselib_p (XEXP (x, 0), XEXP (y, 1)))
+             && rtx_equal_for_cselib_1 (XEXP (x, 1), XEXP (y, 0), memmode)
+             && rtx_equal_for_cselib_1 (XEXP (x, 0), XEXP (y, 1), memmode))
            return 1;
-         if (! rtx_equal_for_cselib_p (XEXP (x, i), XEXP (y, i)))
+         if (! rtx_equal_for_cselib_1 (XEXP (x, i), XEXP (y, i), memmode))
            return 0;
          break;
 
@@ -648,6 +932,8 @@ wrap_constant (enum machine_mode mode, rtx x)
    that take commutativity into account.
    If we wanted to also support associative rules, we'd have to use a different
    strategy to avoid returning spurious 0, e.g. return ~(~0U >> 1) .
+   MEMMODE indicates the mode of an enclosing MEM, and it's only
+   used to compute autoinc values.
    We used to have a MODE argument for hashing for CONST_INTs, but that
    didn't make sense, since it caused spurious hash differences between
     (set (reg:SI 1) (const_int))
@@ -658,7 +944,7 @@ wrap_constant (enum machine_mode mode, rtx x)
    in a comparison anyway, since relying on hash differences is unsafe.  */
 
 static unsigned int
-cselib_hash_rtx (rtx x, int create)
+cselib_hash_rtx (rtx x, int create, enum machine_mode memmode)
 {
   cselib_val *e;
   int i, j;
@@ -673,7 +959,7 @@ cselib_hash_rtx (rtx x, int create)
     {
     case MEM:
     case REG:
-      e = cselib_lookup (x, GET_MODE (x), create);
+      e = cselib_lookup (x, GET_MODE (x), create, memmode);
       if (! e)
        return 0;
 
@@ -684,6 +970,35 @@ cselib_hash_rtx (rtx x, int create)
              + DEBUG_TEMP_UID (DEBUG_EXPR_TREE_DECL (x));
       return hash ? hash : (unsigned int) DEBUG_EXPR;
 
+    case DEBUG_IMPLICIT_PTR:
+      hash += ((unsigned) DEBUG_IMPLICIT_PTR << 7)
+             + DECL_UID (DEBUG_IMPLICIT_PTR_DECL (x));
+      return hash ? hash : (unsigned int) DEBUG_IMPLICIT_PTR;
+
+    case DEBUG_PARAMETER_REF:
+      hash += ((unsigned) DEBUG_PARAMETER_REF << 7)
+             + DECL_UID (DEBUG_PARAMETER_REF_DECL (x));
+      return hash ? hash : (unsigned int) DEBUG_PARAMETER_REF;
+
+    case ENTRY_VALUE:
+      /* ENTRY_VALUEs are function invariant, thus try to avoid
+        recursing on argument if ENTRY_VALUE is one of the
+        forms emitted by expand_debug_expr, otherwise
+        ENTRY_VALUE hash would depend on the current value
+        in some register or memory.  */
+      if (REG_P (ENTRY_VALUE_EXP (x)))
+       hash += (unsigned int) REG
+               + (unsigned int) GET_MODE (ENTRY_VALUE_EXP (x))
+               + (unsigned int) REGNO (ENTRY_VALUE_EXP (x));
+      else if (MEM_P (ENTRY_VALUE_EXP (x))
+              && REG_P (XEXP (ENTRY_VALUE_EXP (x), 0)))
+       hash += (unsigned int) MEM
+               + (unsigned int) GET_MODE (XEXP (ENTRY_VALUE_EXP (x), 0))
+               + (unsigned int) REGNO (XEXP (ENTRY_VALUE_EXP (x), 0));
+      else
+       hash += cselib_hash_rtx (ENTRY_VALUE_EXP (x), create, memmode);
+      return hash ? hash : (unsigned int) ENTRY_VALUE;
+
     case CONST_INT:
       hash += ((unsigned) CONST_INT << 7) + INTVAL (x);
       return hash ? hash : (unsigned int) CONST_INT;
@@ -714,7 +1029,7 @@ cselib_hash_rtx (rtx x, int create)
        for (i = 0; i < units; ++i)
          {
            elt = CONST_VECTOR_ELT (x, i);
-           hash += cselib_hash_rtx (elt, 0);
+           hash += cselib_hash_rtx (elt, 0, memmode);
          }
 
        return hash;
@@ -747,10 +1062,28 @@ cselib_hash_rtx (rtx x, int create)
 
     case PRE_DEC:
     case PRE_INC:
+      /* We can't compute these without knowing the MEM mode.  */
+      gcc_assert (memmode != VOIDmode);
+      i = GET_MODE_SIZE (memmode);
+      if (code == PRE_DEC)
+       i = -i;
+      /* Adjust the hash so that (mem:MEMMODE (pre_* (reg))) hashes
+        like (mem:MEMMODE (plus (reg) (const_int I))).  */
+      hash += (unsigned) PLUS - (unsigned)code
+       + cselib_hash_rtx (XEXP (x, 0), create, memmode)
+       + cselib_hash_rtx (GEN_INT (i), create, memmode);
+      return hash ? hash : 1 + (unsigned) PLUS;
+
+    case PRE_MODIFY:
+      gcc_assert (memmode != VOIDmode);
+      return cselib_hash_rtx (XEXP (x, 1), create, memmode);
+
     case POST_DEC:
     case POST_INC:
     case POST_MODIFY:
-    case PRE_MODIFY:
+      gcc_assert (memmode != VOIDmode);
+      return cselib_hash_rtx (XEXP (x, 0), create, memmode);
+
     case PC:
     case CC0:
     case CALL:
@@ -776,7 +1109,7 @@ cselib_hash_rtx (rtx x, int create)
        case 'e':
          {
            rtx tem = XEXP (x, i);
-           unsigned int tem_hash = cselib_hash_rtx (tem, create);
+           unsigned int tem_hash = cselib_hash_rtx (tem, create, memmode);
 
            if (tem_hash == 0)
              return 0;
@@ -788,7 +1121,7 @@ cselib_hash_rtx (rtx x, int create)
          for (j = 0; j < XVECLEN (x, i); j++)
            {
              unsigned int tem_hash
-               = cselib_hash_rtx (XVECEXP (x, i, j), create);
+               = cselib_hash_rtx (XVECEXP (x, i, j), create, memmode);
 
              if (tem_hash == 0)
                return 0;
@@ -851,7 +1184,7 @@ new_cselib_val (unsigned int hash, enum machine_mode mode, rtx x)
   e->locs = 0;
   e->next_containing_mem = 0;
 
-  if (dump_file && (dump_flags & TDF_DETAILS))
+  if (dump_file && (dump_flags & TDF_CSELIB))
     {
       fprintf (dump_file, "cselib value %u:%u ", e->uid, hash);
       if (flag_dump_noaddr || flag_dump_unnumbered)
@@ -878,7 +1211,10 @@ add_mem_for_addr (cselib_val *addr_elt, cselib_val *mem_elt, rtx x)
   for (l = mem_elt->locs; l; l = l->next)
     if (MEM_P (l->loc)
        && CSELIB_VAL_PTR (XEXP (l->loc, 0)) == addr_elt)
-      return;
+      {
+       promote_debug_loc (l);
+       return;
+      }
 
   addr_elt->addr_list = new_elt_list (addr_elt->addr_list, mem_elt);
   mem_elt->locs
@@ -898,6 +1234,7 @@ static cselib_val *
 cselib_lookup_mem (rtx x, int create)
 {
   enum machine_mode mode = GET_MODE (x);
+  enum machine_mode addr_mode;
   void **slot;
   cselib_val *addr;
   cselib_val *mem_elt;
@@ -908,23 +1245,30 @@ cselib_lookup_mem (rtx x, int create)
       || (FLOAT_MODE_P (mode) && flag_float_store))
     return 0;
 
+  addr_mode = GET_MODE (XEXP (x, 0));
+  if (addr_mode == VOIDmode)
+    addr_mode = Pmode;
+
   /* Look up the value for the address.  */
-  addr = cselib_lookup (XEXP (x, 0), mode, create);
+  addr = cselib_lookup (XEXP (x, 0), addr_mode, create, mode);
   if (! addr)
     return 0;
 
   /* Find a value that describes a value of our mode at that address.  */
   for (l = addr->addr_list; l; l = l->next)
     if (GET_MODE (l->elt->val_rtx) == mode)
-      return l->elt;
+      {
+       promote_debug_loc (l->elt->locs);
+       return l->elt;
+      }
 
   if (! create)
     return 0;
 
   mem_elt = new_cselib_val (next_uid, mode, x);
   add_mem_for_addr (addr, mem_elt, x);
-  slot = htab_find_slot_with_hash (cselib_hash_table, wrap_constant (mode, x),
-                                  mem_elt->hash, INSERT);
+  slot = cselib_find_slot (wrap_constant (mode, x), mem_elt->hash,
+                          INSERT, mode);
   *slot = mem_elt;
   return mem_elt;
 }
@@ -962,7 +1306,7 @@ expand_loc (struct elt_loc_list *p, struct expand_value_data *evd,
       else if (!REG_P (p->loc))
        {
          rtx result, note;
-         if (dump_file && (dump_flags & TDF_DETAILS))
+         if (dump_file && (dump_flags & TDF_CSELIB))
            {
              print_inline_rtx (dump_file, p->loc, 0);
              fprintf (dump_file, "\n");
@@ -983,7 +1327,7 @@ expand_loc (struct elt_loc_list *p, struct expand_value_data *evd,
   if (regno != UINT_MAX)
     {
       rtx result;
-      if (dump_file && (dump_flags & TDF_DETAILS))
+      if (dump_file && (dump_flags & TDF_CSELIB))
        fprintf (dump_file, "r%d\n", regno);
 
       result = cselib_expand_value_rtx_1 (reg_result, evd, max_depth - 1);
@@ -991,7 +1335,7 @@ expand_loc (struct elt_loc_list *p, struct expand_value_data *evd,
        return result;
     }
 
-  if (dump_file && (dump_flags & TDF_DETAILS))
+  if (dump_file && (dump_flags & TDF_CSELIB))
     {
       if (reg_result)
        {
@@ -1132,7 +1476,7 @@ cselib_expand_value_rtx_1 (rtx orig, struct expand_value_data *evd,
 
              bitmap_set_bit (evd->regs_active, regno);
 
-             if (dump_file && (dump_flags & TDF_DETAILS))
+             if (dump_file && (dump_flags & TDF_CSELIB))
                fprintf (dump_file, "expanding: r%d into: ", regno);
 
              result = expand_loc (l->elt->locs, evd, max_depth);
@@ -1197,7 +1541,7 @@ cselib_expand_value_rtx_1 (rtx orig, struct expand_value_data *evd,
       {
        rtx result;
 
-       if (dump_file && (dump_flags & TDF_DETAILS))
+       if (dump_file && (dump_flags & TDF_CSELIB))
          {
            fputs ("\nexpanding ", dump_file);
            print_rtl_single (dump_file, orig);
@@ -1356,10 +1700,11 @@ cselib_expand_value_rtx_1 (rtx orig, struct expand_value_data *evd,
    with VALUE expressions.  This way, it becomes independent of changes
    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.  */
+   allocated.  However, the return value can share rtl with X.
+   If X is within a MEM, MEMMODE must be the mode of the MEM.  */
 
 rtx
-cselib_subst_to_values (rtx x)
+cselib_subst_to_values (rtx x, enum machine_mode memmode)
 {
   enum rtx_code code = GET_CODE (x);
   const char *fmt = GET_RTX_FORMAT (code);
@@ -1382,28 +1727,45 @@ cselib_subst_to_values (rtx x)
 
     case MEM:
       e = cselib_lookup_mem (x, 0);
+      /* This used to happen for autoincrements, but we deal with them
+        properly now.  Remove the if stmt for the next release.  */
       if (! e)
        {
-         /* This happens for autoincrements.  Assign a value that doesn't
-            match any other.  */
+         /* Assign a value that doesn't match any other.  */
          e = new_cselib_val (next_uid, GET_MODE (x), x);
        }
       return e->val_rtx;
 
+    case ENTRY_VALUE:
+      e = cselib_lookup (x, GET_MODE (x), 0, memmode);
+      if (! e)
+       break;
+      return e->val_rtx;
+
     case CONST_DOUBLE:
     case CONST_VECTOR:
     case CONST_INT:
     case CONST_FIXED:
       return x;
 
-    case POST_INC:
+    case PRE_DEC:
     case PRE_INC:
+      gcc_assert (memmode != VOIDmode);
+      i = GET_MODE_SIZE (memmode);
+      if (code == PRE_DEC)
+       i = -i;
+      return cselib_subst_to_values (plus_constant (XEXP (x, 0), i),
+                                    memmode);
+
+    case PRE_MODIFY:
+      gcc_assert (memmode != VOIDmode);
+      return cselib_subst_to_values (XEXP (x, 1), memmode);
+
     case POST_DEC:
-    case PRE_DEC:
+    case POST_INC:
     case POST_MODIFY:
-    case PRE_MODIFY:
-      e = new_cselib_val (next_uid, GET_MODE (x), x);
-      return e->val_rtx;
+      gcc_assert (memmode != VOIDmode);
+      return cselib_subst_to_values (XEXP (x, 0), memmode);
 
     default:
       break;
@@ -1413,7 +1775,7 @@ cselib_subst_to_values (rtx x)
     {
       if (fmt[i] == 'e')
        {
-         rtx t = cselib_subst_to_values (XEXP (x, i));
+         rtx t = cselib_subst_to_values (XEXP (x, i), memmode);
 
          if (t != XEXP (x, i))
            {
@@ -1428,7 +1790,7 @@ cselib_subst_to_values (rtx x)
 
          for (j = 0; j < XVECLEN (x, i); j++)
            {
-             rtx t = cselib_subst_to_values (XVECEXP (x, i, j));
+             rtx t = cselib_subst_to_values (XVECEXP (x, i, j), memmode);
 
              if (t != XVECEXP (x, i, j))
                {
@@ -1447,30 +1809,16 @@ cselib_subst_to_values (rtx x)
   return copy;
 }
 
-/* Log a lookup of X to the cselib table along with the result RET.  */
+/* Look up the rtl expression X in our tables and return the value it
+   has.  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).  When X is part
+   of an address, MEMMODE should be the mode of the enclosing MEM if
+   we're tracking autoinc expressions.  */
 
 static cselib_val *
-cselib_log_lookup (rtx x, cselib_val *ret)
-{
-  if (dump_file && (dump_flags & TDF_DETAILS))
-    {
-      fputs ("cselib lookup ", dump_file);
-      print_inline_rtx (dump_file, x, 2);
-      fprintf (dump_file, " => %u:%u\n",
-              ret ? ret->uid : 0,
-              ret ? ret->hash : 0);
-    }
-
-  return ret;
-}
-
-/* Look up the rtl expression X in our tables and return the value it has.
-   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 (rtx x, enum machine_mode mode, int create)
+cselib_lookup_1 (rtx x, enum machine_mode mode,
+                int create, enum machine_mode memmode)
 {
   void **slot;
   cselib_val *e;
@@ -1492,10 +1840,13 @@ cselib_lookup (rtx x, enum machine_mode mode, int create)
        l = l->next;
       for (; l; l = l->next)
        if (mode == GET_MODE (l->elt->val_rtx))
-         return cselib_log_lookup (x, l->elt);
+         {
+           promote_debug_loc (l->elt->locs);
+           return l->elt;
+         }
 
       if (! create)
-       return cselib_log_lookup (x, 0);
+       return 0;
 
       if (i < FIRST_PSEUDO_REGISTER)
        {
@@ -1515,28 +1866,65 @@ cselib_lookup (rtx x, enum machine_mode mode, int create)
          used_regs[n_used_regs++] = i;
          REG_VALUES (i) = new_elt_list (REG_VALUES (i), NULL);
        }
+      else if (cselib_preserve_constants
+              && GET_MODE_CLASS (mode) == MODE_INT)
+       {
+         /* During var-tracking, try harder to find equivalences
+            for SUBREGs.  If a setter sets say a DImode register
+            and user uses that register only in SImode, add a lowpart
+            subreg location.  */
+         struct elt_list *lwider = NULL;
+         l = REG_VALUES (i);
+         if (l && l->elt == NULL)
+           l = l->next;
+         for (; l; l = l->next)
+           if (GET_MODE_CLASS (GET_MODE (l->elt->val_rtx)) == MODE_INT
+               && GET_MODE_SIZE (GET_MODE (l->elt->val_rtx))
+                  > GET_MODE_SIZE (mode)
+               && (lwider == NULL
+                   || GET_MODE_SIZE (GET_MODE (l->elt->val_rtx))
+                      < GET_MODE_SIZE (GET_MODE (lwider->elt->val_rtx))))
+             {
+               struct elt_loc_list *el;
+               if (i < FIRST_PSEUDO_REGISTER
+                   && hard_regno_nregs[i][GET_MODE (l->elt->val_rtx)] != 1)
+                 continue;
+               for (el = l->elt->locs; el; el = el->next)
+                 if (!REG_P (el->loc))
+                   break;
+               if (el)
+                 lwider = l;
+             }
+         if (lwider)
+           {
+             rtx sub = lowpart_subreg (mode, lwider->elt->val_rtx,
+                                       GET_MODE (lwider->elt->val_rtx));
+             if (sub)
+               e->locs->next = new_elt_loc_list (e->locs->next, sub);
+           }
+       }
       REG_VALUES (i)->next = new_elt_list (REG_VALUES (i)->next, e);
-      slot = htab_find_slot_with_hash (cselib_hash_table, x, e->hash, INSERT);
+      slot = cselib_find_slot (x, e->hash, INSERT, memmode);
       *slot = e;
-      return cselib_log_lookup (x, e);
+      return e;
     }
 
   if (MEM_P (x))
-    return cselib_log_lookup (x, cselib_lookup_mem (x, create));
+    return cselib_lookup_mem (x, create);
 
-  hashval = cselib_hash_rtx (x, create);
+  hashval = cselib_hash_rtx (x, create, memmode);
   /* Can't even create if hashing is not possible.  */
   if (! hashval)
-    return cselib_log_lookup (x, 0);
+    return 0;
 
-  slot = htab_find_slot_with_hash (cselib_hash_table, wrap_constant (mode, x),
-                                  hashval, create ? INSERT : NO_INSERT);
+  slot = cselib_find_slot (wrap_constant (mode, x), hashval,
+                          create ? INSERT : NO_INSERT, memmode);
   if (slot == 0)
-    return cselib_log_lookup (x, 0);
+    return 0;
 
   e = (cselib_val *) *slot;
   if (e)
-    return cselib_log_lookup (x, e);
+    return e;
 
   e = new_cselib_val (hashval, mode, x);
 
@@ -1544,8 +1932,54 @@ cselib_lookup (rtx x, enum machine_mode mode, int create)
      the hash table is inconsistent until we do so, and
      cselib_subst_to_values will need to do lookups.  */
   *slot = (void *) e;
-  e->locs = new_elt_loc_list (e->locs, cselib_subst_to_values (x));
-  return cselib_log_lookup (x, e);
+  e->locs = new_elt_loc_list (e->locs,
+                             cselib_subst_to_values (x, memmode));
+  return e;
+}
+
+/* Wrapper for cselib_lookup, that indicates X is in INSN.  */
+
+cselib_val *
+cselib_lookup_from_insn (rtx x, enum machine_mode mode,
+                        int create, enum machine_mode memmode, rtx insn)
+{
+  cselib_val *ret;
+
+  gcc_assert (!cselib_current_insn);
+  cselib_current_insn = insn;
+
+  ret = cselib_lookup (x, mode, create, memmode);
+
+  cselib_current_insn = NULL;
+
+  return ret;
+}
+
+/* Wrapper for cselib_lookup_1, that logs the lookup result and
+   maintains invariants related with debug insns.  */
+
+cselib_val *
+cselib_lookup (rtx x, enum machine_mode mode,
+              int create, enum machine_mode memmode)
+{
+  cselib_val *ret = cselib_lookup_1 (x, mode, create, memmode);
+
+  /* ??? Should we return NULL if we're not to create an entry, the
+     found loc is a debug loc and cselib_current_insn is not DEBUG?
+     If so, we should also avoid converting val to non-DEBUG; probably
+     easiest setting cselib_current_insn to NULL before the call
+     above.  */
+
+  if (dump_file && (dump_flags & TDF_CSELIB))
+    {
+      fputs ("cselib lookup ", dump_file);
+      print_inline_rtx (dump_file, x, 2);
+      fprintf (dump_file, " => %u:%u\n",
+              ret ? ret->uid : 0,
+              ret ? ret->hash : 0);
+    }
+
+  return ret;
 }
 
 /* Invalidate any entries in reg_values that overlap REGNO.  This is called
@@ -1594,13 +2028,17 @@ cselib_invalidate_regno (unsigned int regno, enum machine_mode mode)
       while (*l)
        {
          cselib_val *v = (*l)->elt;
+         bool had_locs;
+         rtx setting_insn;
          struct elt_loc_list **p;
          unsigned int this_last = i;
 
          if (i < FIRST_PSEUDO_REGISTER && v != NULL)
            this_last = end_hard_regno (GET_MODE (v->val_rtx), i) - 1;
 
-         if (this_last < regno || v == NULL)
+         if (this_last < regno || v == NULL
+             || (v == cfa_base_preserved_val
+                 && i == cfa_base_preserved_regno))
            {
              l = &(*l)->next;
              continue;
@@ -1620,6 +2058,9 @@ cselib_invalidate_regno (unsigned int regno, enum machine_mode mode)
          else
            unchain_one_elt_list (l);
 
+         had_locs = v->locs != NULL;
+         setting_insn = v->locs ? v->locs->setting_insn : NULL;
+
          /* Now, we clear the mapping from value to reg.  It must exist, so
             this code will crash intentionally if it doesn't.  */
          for (p = &v->locs; ; p = &(*p)->next)
@@ -1632,8 +2073,14 @@ cselib_invalidate_regno (unsigned int regno, enum machine_mode mode)
                  break;
                }
            }
-         if (v->locs == 0 && !PRESERVED_VALUE_P (v->val_rtx))
-           n_useless_values++;
+
+         if (had_locs && v->locs == 0 && !PRESERVED_VALUE_P (v->val_rtx))
+           {
+             if (setting_insn && DEBUG_INSN_P (setting_insn))
+               n_useless_debug_values++;
+             else
+               n_useless_values++;
+           }
        }
     }
 }
@@ -1671,7 +2118,8 @@ cselib_invalidate_mem (rtx mem_rtx)
     {
       bool has_mem = false;
       struct elt_loc_list **p = &v->locs;
-      int had_locs = v->locs != 0;
+      bool had_locs = v->locs != NULL;
+      rtx setting_insn = v->locs ? v->locs->setting_insn : NULL;
 
       while (*p)
        {
@@ -1699,7 +2147,7 @@ cselib_invalidate_mem (rtx mem_rtx)
          /* This one overlaps.  */
          /* We must have a mapping from this MEM's address to the
             value (E).  Remove that, too.  */
-         addr = cselib_lookup (XEXP (x, 0), VOIDmode, 0);
+         addr = cselib_lookup (XEXP (x, 0), VOIDmode, 0, GET_MODE (x));
          mem_chain = &addr->addr_list;
          for (;;)
            {
@@ -1716,7 +2164,12 @@ cselib_invalidate_mem (rtx mem_rtx)
        }
 
       if (had_locs && v->locs == 0 && !PRESERVED_VALUE_P (v->val_rtx))
-       n_useless_values++;
+       {
+         if (setting_insn && DEBUG_INSN_P (setting_insn))
+           n_useless_debug_values++;
+         else
+           n_useless_values++;
+       }
 
       next = v->next_containing_mem;
       if (has_mem)
@@ -1744,13 +2197,6 @@ cselib_invalidate_rtx (rtx dest)
     cselib_invalidate_regno (REGNO (dest), GET_MODE (dest));
   else if (MEM_P (dest))
     cselib_invalidate_mem (dest);
-
-  /* Some machines don't define AUTO_INC_DEC, but they still use push
-     instructions.  We need to catch that case here in order to
-     invalidate the stack pointer correctly.  Note that invalidating
-     the stack pointer is different from invalidating DEST.  */
-  if (push_operand (dest, GET_MODE (dest)))
-    cselib_invalidate_rtx (stack_pointer_rtx);
 }
 
 /* A wrapper for cselib_invalidate_rtx to be called via note_stores.  */
@@ -1813,7 +2259,35 @@ cselib_record_set (rtx dest, cselib_val *src_elt, cselib_val *dest_addr_elt)
    in a PARALLEL.  Since it's fairly cheap, use a really large number.  */
 #define MAX_SETS (FIRST_PSEUDO_REGISTER * 2)
 
-/* Record the effects of any sets in INSN.  */
+struct cselib_record_autoinc_data
+{
+  struct cselib_set *sets;
+  int n_sets;
+};
+
+/* Callback for for_each_inc_dec.  Records in ARG the SETs implied by
+   autoinc RTXs: SRC plus SRCOFF if non-NULL is stored in DEST.  */
+
+static int
+cselib_record_autoinc_cb (rtx mem ATTRIBUTE_UNUSED, rtx op ATTRIBUTE_UNUSED,
+                         rtx dest, rtx src, rtx srcoff, void *arg)
+{
+  struct cselib_record_autoinc_data *data;
+  data = (struct cselib_record_autoinc_data *)arg;
+
+  data->sets[data->n_sets].dest = dest;
+
+  if (srcoff)
+    data->sets[data->n_sets].src = gen_rtx_PLUS (GET_MODE (src), src, srcoff);
+  else
+    data->sets[data->n_sets].src = src;
+
+  data->n_sets++;
+
+  return -1;
+}
+
+/* Record the effects of any sets and autoincs in INSN.  */
 static void
 cselib_record_sets (rtx insn)
 {
@@ -1822,6 +2296,8 @@ cselib_record_sets (rtx insn)
   struct cselib_set sets[MAX_SETS];
   rtx body = PATTERN (insn);
   rtx cond = 0;
+  int n_sets_before_autoinc;
+  struct cselib_record_autoinc_data data;
 
   body = PATTERN (insn);
   if (GET_CODE (body) == COND_EXEC)
@@ -1865,6 +2341,11 @@ cselib_record_sets (rtx insn)
        sets[0].src = XEXP (note, 0);
     }
 
+  data.sets = sets;
+  data.n_sets = n_sets_before_autoinc = n_sets;
+  for_each_inc_dec (&insn, cselib_record_autoinc_cb, &data);
+  n_sets = data.n_sets;
+
   /* Look up the values that are read.  Do this before invalidating the
      locations that are written.  */
   for (i = 0; i < n_sets; i++)
@@ -1883,14 +2364,15 @@ cselib_record_sets (rtx insn)
          rtx src = sets[i].src;
          if (cond)
            src = gen_rtx_IF_THEN_ELSE (GET_MODE (dest), cond, src, dest);
-         sets[i].src_elt = cselib_lookup (src, GET_MODE (dest), 1);
+         sets[i].src_elt = cselib_lookup (src, GET_MODE (dest), 1, VOIDmode);
          if (MEM_P (dest))
            {
              enum machine_mode address_mode
                = targetm.addr_space.address_mode (MEM_ADDR_SPACE (dest));
 
              sets[i].dest_addr_elt = cselib_lookup (XEXP (dest, 0),
-                                                    address_mode, 1);
+                                                    address_mode, 1,
+                                                    GET_MODE (dest));
            }
          else
            sets[i].dest_addr_elt = 0;
@@ -1905,6 +2387,9 @@ cselib_record_sets (rtx insn)
      locations may go away.  */
   note_stores (body, cselib_invalidate_rtx_note_stores, NULL);
 
+  for (i = n_sets_before_autoinc; i < n_sets; i++)
+    cselib_invalidate_rtx (sets[i].dest);
+
   /* If this is an asm, look for duplicate sets.  This can happen when the
      user uses the same value as an output multiple times.  This is valid
      if the outputs are not actually used thereafter.  Treat this case as
@@ -1957,12 +2442,13 @@ cselib_process_insn (rtx insn)
          && MEM_VOLATILE_P (PATTERN (insn))))
     {
       cselib_reset_table (next_uid);
+      cselib_current_insn = NULL_RTX;
       return;
     }
 
   if (! INSN_P (insn))
     {
-      cselib_current_insn = 0;
+      cselib_current_insn = NULL_RTX;
       return;
     }
 
@@ -1988,15 +2474,6 @@ cselib_process_insn (rtx insn)
 
   cselib_record_sets (insn);
 
-#ifdef AUTO_INC_DEC
-  /* 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.  */
-  for (x = REG_NOTES (insn); x; x = XEXP (x, 1))
-    if (REG_NOTE_KIND (x) == REG_INC)
-      cselib_invalidate_rtx (XEXP (x, 0));
-#endif
-
   /* Look for any CLOBBERs in CALL_INSN_FUNCTION_USAGE, but only
      after we have processed the insn.  */
   if (CALL_P (insn))
@@ -2004,13 +2481,16 @@ cselib_process_insn (rtx insn)
       if (GET_CODE (XEXP (x, 0)) == CLOBBER)
        cselib_invalidate_rtx (XEXP (XEXP (x, 0), 0));
 
-  cselib_current_insn = 0;
+  cselib_current_insn = NULL_RTX;
 
   if (n_useless_values > MAX_USELESS_VALUES
       /* remove_useless_values is linear in the hash table size.  Avoid
          quadratic behavior for very large hashtables with very few
         useless elements.  */
-      && (unsigned int)n_useless_values > cselib_hash_table->n_elements / 4)
+      && ((unsigned int)n_useless_values
+         > (cselib_hash_table->n_elements
+            - cselib_hash_table->n_deleted
+            - n_debug_values) / 4))
     remove_useless_values ();
 }
 
@@ -2018,7 +2498,7 @@ cselib_process_insn (rtx insn)
    init_alias_analysis.  */
 
 void
-cselib_init (bool record_memory)
+cselib_init (int record_what)
 {
   elt_list_pool = create_alloc_pool ("elt_list",
                                     sizeof (struct elt_list), 10);
@@ -2027,7 +2507,8 @@ cselib_init (bool record_memory)
   cselib_val_pool = create_alloc_pool ("cselib_val_list",
                                       sizeof (cselib_val), 10);
   value_pool = create_alloc_pool ("value", RTX_CODE_SIZE (VALUE), 100);
-  cselib_record_memory = record_memory;
+  cselib_record_memory = record_what & CSELIB_RECORD_MEMORY;
+  cselib_preserve_constants = record_what & CSELIB_PRESERVE_CONSTANTS;
 
   /* (mem:BLK (scratch)) is a special mechanism to conflict with everything,
      see canon_true_dependence.  This is only created once.  */
@@ -2041,8 +2522,7 @@ cselib_init (bool record_memory)
   if (!reg_values || reg_values_size < cselib_nregs
       || (reg_values_size > 10 && reg_values_size > cselib_nregs * 4))
     {
-      if (reg_values)
-       free (reg_values);
+      free (reg_values);
       /* Some space for newly emit instructions so we don't end up
         reallocating in between passes.  */
       reg_values_size = cselib_nregs + (63 + cselib_nregs) / 16;
@@ -2061,6 +2541,9 @@ void
 cselib_finish (void)
 {
   cselib_discard_hook = NULL;
+  cselib_preserve_constants = false;
+  cfa_base_preserved_val = NULL;
+  cfa_base_preserved_regno = INVALID_REGNUM;
   free_alloc_pool (elt_list_pool);
   free_alloc_pool (elt_loc_list_pool);
   free_alloc_pool (cselib_val_pool);
@@ -2071,6 +2554,8 @@ cselib_finish (void)
   used_regs = 0;
   cselib_hash_table = 0;
   n_useless_values = 0;
+  n_useless_debug_values = 0;
+  n_debug_values = 0;
   next_uid = 0;
 }