public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
* [PATCH] Fix VTA sp (and fp) based MEM handling (PR debug/43051, PR  debug/43092)
@ 2010-03-15 13:16 Jakub Jelinek
  2010-03-16 10:51 ` Richard Guenther
  2010-03-23  8:52 ` Alexandre Oliva
  0 siblings, 2 replies; 10+ messages in thread
From: Jakub Jelinek @ 2010-03-15 13:16 UTC (permalink / raw)
  To: Richard Guenther, Alexandre Oliva; +Cc: gcc-patches

Hi!

The following patch fixes a bunch of sp (and fp) based MEM tracking issues.

PR43092 is about an addressable variable with -fomit-frame-pointer
-mno-accumulate-outgoing-args.  With -fno-var-tracking-assignments
this worked, as vt_stack_adjustments remapped the stack based locations to
argp/framep based ones.  vt_stack_adjustments handled well just the
MO_SET/MO_USE/MO_COPY cases (and, apparently, not even those which involved
a SET added in there), but certainly not MO_VAL_SET with its embedded
CONCATs.  Handling that is possible (I actually wrote it in one of the first
versions of this patch), but it handles only the cases where we don't
track VALUEs.  As soon as VALUEs need to be tracked (e.g. if there is some
optimized out variable that was set from such living sp based address), we
run into other issues.  One is that cselib doesn't handle autoinc rtls well
(Alex has a follow-up patch in which it teaches cselib about these; this
final version of the patch doesn't need it for var-tracking though).
Another one is that doing the sp -> argp + offset replacements in
vt_stack_adjustments is too late, we need to create VALUEs for them to
be able to track them properly.  This is done in the vt_initialize /
vt_stack_adjustment reorganization in the patch below.  We compute the stack
adjustments in each bb first, before add_{stores,uses}, and can use that
as VALUEs.  The adjust_sets way of updating MEMs with all the other
reasons to update them unfortunately became quite unmanagable (we don't
want to only optimize src MEM/u with REG_EQUIV/REG_EQUAL note, but also
do that sp (and fp) replacement with argp + const, and delegitimize_address,
avoid_constant_pool_reference and autoinc removal too), and also needed
more VALUEs than necessary (cselib initially looked up what was in the
original instruction, then the hook was called, changed many things
in src and dests, and had to do cselib lookups again for the replaced
things).  This patch instead does all the updates on the insn before calling
cselib_process_insn, using validate_change in_group, changing a valid insn
into a representation that is useful for debug info purposes, then lets cselib
process the insns and afterwards cancel_changes (0) to restore the original
insn.  Always whole set dests and srcs are replaced, not subexpressions
thereof, so even when add_uses/add_stores references the whole stores or
uses or parts thereof, the cancel_changes (0) call doesn't affect them.

This patch also fixes PR43051, where we weren't able to track a variable,
as the MEMs it was said to live at in 2 different predecessors used
different VALUE, by making sure VALUEs that are constant through the
whole function aren't flushed from the cselib hash table after each ebb,
thus the same VALUE is used in all the bbs for the same thing.
Such constants include CONSTANT_P (except for CONST which includes some
VALUEs - in most cases the delegitimization will turn them into real
consts), argp (resp. framep), provided it has been eliminated and thus
it is a constant CFA - some offset, and constant additions to the
argp/framep value.

Bootstrapped/regtested on x86_64-linux and i686-linux, on x86_64-linux
this doesn't change anything in make check, on i686-linux fixes:
+XPASS: gcc.dg/guality/guality.c  -O3 -fomit-frame-pointer  execution test
-FAIL: gcc.dg/guality/pr43077-1.c  -O2  line 42 varb == 2
-FAIL: gcc.dg/guality/pr43077-1.c  -O2  line 42 varc == 3
-FAIL: gcc.dg/guality/pr43077-1.c  -O3 -g  line 42 varb == 2
-FAIL: gcc.dg/guality/pr43077-1.c  -O3 -g  line 42 varc == 3
-FAIL: gcc.dg/guality/pr43077-1.c  -Os  line 42 varb == 2
-FAIL: gcc.dg/guality/pr43077-1.c  -Os  line 42 varc == 3
-FAIL: gcc.dg/guality/pr43077-1.c  -O2 -flto  line 42 varb == 2
-FAIL: gcc.dg/guality/pr43077-1.c  -O2 -flto  line 42 varc == 3
-FAIL: gcc.dg/guality/pr43077-1.c  -O2 -fwhopr  line 42 varb == 2
-FAIL: gcc.dg/guality/pr43077-1.c  -O2 -fwhopr  line 42 varc == 3
-FAIL: gcc.dg/guality/vla-1.c  -O1  line 24 sizeof (a) == 17 * sizeof (short)
-FAIL: gcc.dg/guality/vla-1.c  -O2  line 24 sizeof (a) == 17 * sizeof (short)
-FAIL: gcc.dg/guality/vla-1.c  -O3 -fomit-frame-pointer  line 24 sizeof (a) == 17 * sizeof (short)
-FAIL: gcc.dg/guality/vla-1.c  -O3 -g  line 24 sizeof (a) == 17 * sizeof (short)
-FAIL: gcc.dg/guality/vla-1.c  -Os  line 24 sizeof (a) == 17 * sizeof (short)
(and the new testcase passes on both targets).  Backport of this has been
bootstrapped/regtested on redhat/gcc-4_4-branch on
{x86_64,i686,ppc,ppc64,s390,s390x}-linux too.

Ok for trunk?

2010-03-15  Jakub Jelinek  <jakub@redhat.com>

	PR debug/43051
	PR debug/43092
	* cselib.c (cselib_preserve_constants,
	cfa_base_preserved_val): New static variables.
	(preserve_only_constants): New function.
	(cselib_reset_table): If cfa_base_preserved_val is non-NULL, don't
	clear its REG_VALUES.  If cselib_preserve_constants, don't 
	empty the whole hash table, but preserve there VALUEs with constants,
	cfa_base_preserved_val and cfa_base_preserved_val plus constant.
	(cselib_preserve_cfa_base_value): New function.
	(cselib_invalidate_regno): Don't invalidate cfa_base_preserved_val.
	(cselib_init): Change argument to int bitfield.  Set
	cselib_preserve_constants to whether CSELIB_PRESERVE_CONSTANTS
	is in it.
	(cselib_finish): Clear cselib_preserve_constants and
	cfa_base_preserved_val.
	* cselib.h (enum cselib_record_what): New enum.
	(cselib_init): Change argument to int.
	(cselib_preserve_cfa_base_value): New prototype.
	* postreload.c (reload_cse_regs_1): Adjust cselib_init caller.
	* dse.c (dse_step1): Likewise.
	* cfgcleanup.c (thread_jump): Likewise.
	* sched-deps.c (sched_analyze): Likewise.
	* gcse.c (local_cprop_pass): Likewise.
	* simplify-rtx.c (simplify_replace_fn_rtx): Add argument to callback.
	If FN is non-NULL, call the callback always and whenever it returns
	non-NULL just return that.  Only do rtx_equal_p if FN is NULL.
	* rtl.h (simplify_replace_fn_rtx): Add argument to callback.
	* combine.c (propagate_for_debug_subst): Add old_rtx argument,
	compare from with old_rtx and if it isn't rtx_equal_p, return NULL.
	* Makefile.in (var-tracking.o): Depend on $(RECOG_H).
	* var-tracking.c: Include recog.h.
	(bb_stack_adjust_offset): Remove.
	(vt_stack_adjustments): Don't call it, instead just gather the
	adjustments using insn_stack_adjust_offset_pre_post on each bb insn.
	(adjust_stack_reference): Remove.
	(compute_cfa_pointer): New function.
	(hard_frame_pointer_adjustment, cfa_base_rtx): New static variables.
	(struct adjust_mem_data): New type.
	(adjust_mems, adjust_mem_uses, adjust_mem_stores, adjust_insn): New
	functions.
	(get_address_mode): New function.
	(replace_expr_with_values): Use it.
	(use_type): Don't do cselib_lookup for VAR_LOC_UNKNOWN_P.
	Ise get_address_mode.  For cfa_base_rtx return MO_CLOBBER.
	(adjust_sets): Remove.
	(add_uses): Don't add extra MO_VAL_USE for cfa_base_rtx plus constant.
	Use get_address_mode.
	(get_adjusted_src): Remove.
	(add_stores): Don't call it.  Never reuse expr SET.  Don't add extra
	MO_VAL_USE for cfa_base_rtx plus constant.  Use get_address_mode.
	(add_with_sets): Don't call adjust_sets.
	(fp_setter, vt_init_cfa_base): New functions.
	(vt_initialize): Change return type to bool.  Move most of pool etc.
	initialization to the beginning of the function from end.  Pass
	CSELIB_RECORD_MEMORY | CSELIB_PRESERVE_CONSTANTS to cselib_init.
	If !frame_pointer_needed, call vt_stack_adjustment before mos
	vector is filled, call vt_init_cfa_base if argp/framep has been
	eliminated to sp.  If frame_pointer_needed and argp/framep has
	been eliminated to hard frame pointer, set
	hard_frame_pointer_adjustment and call vt_init_cfa_base after
	encountering fp setter in the prologue.  For MO_ADJUST, call
	log_op_type before pusing the op into mos vector, not afterwards.
	Call adjust_insn before cselib_process_insn/add_with_sets,
	call cancel_changes (0) afterwards.
	(variable_tracking_main_1): Adjust for vt_initialize calling
	vt_stack_adjustments and returning whether it succeeded or not.

	* gcc.dg/guality/pr43051-1.c: New test.

--- gcc/postreload.c.jj	2010-03-15 08:42:27.000000000 +0100
+++ gcc/postreload.c	2010-03-15 08:53:32.000000000 +0100
@@ -198,7 +198,7 @@ reload_cse_regs_1 (rtx first)
   rtx insn;
   rtx testreg = gen_rtx_REG (VOIDmode, -1);
 
-  cselib_init (true);
+  cselib_init (CSELIB_RECORD_MEMORY);
   init_alias_analysis ();
 
   for (insn = first; insn; insn = NEXT_INSN (insn))
--- gcc/dse.c.jj	2010-03-15 08:42:27.000000000 +0100
+++ gcc/dse.c	2010-03-15 08:53:32.000000000 +0100
@@ -2616,7 +2616,7 @@ dse_step1 (void)
   basic_block bb;
   bitmap regs_live = BITMAP_ALLOC (NULL);
 
-  cselib_init (false);
+  cselib_init (0);
   all_blocks = BITMAP_ALLOC (NULL);
   bitmap_set_bit (all_blocks, ENTRY_BLOCK);
   bitmap_set_bit (all_blocks, EXIT_BLOCK);
--- gcc/cfgcleanup.c.jj	2010-03-15 08:42:27.000000000 +0100
+++ gcc/cfgcleanup.c	2010-03-15 08:53:32.000000000 +0100
@@ -337,7 +337,7 @@ thread_jump (edge e, basic_block b)
 	return NULL;
       }
 
-  cselib_init (false);
+  cselib_init (0);
 
   /* First process all values computed in the source basic block.  */
   for (insn = NEXT_INSN (BB_HEAD (e->src));
--- gcc/rtl.h.jj	2010-03-15 08:42:28.000000000 +0100
+++ gcc/rtl.h	2010-03-15 08:53:32.000000000 +0100
@@ -1778,7 +1778,7 @@ extern rtx simplify_subreg (enum machine
 extern rtx simplify_gen_subreg (enum machine_mode, rtx, enum machine_mode,
 				unsigned int);
 extern rtx simplify_replace_fn_rtx (rtx, const_rtx,
-				    rtx (*fn) (rtx, void *), void *);
+				    rtx (*fn) (rtx, const_rtx, void *), void *);
 extern rtx simplify_replace_rtx (rtx, const_rtx, rtx);
 extern rtx simplify_rtx (const_rtx);
 extern rtx avoid_constant_pool_reference (rtx);
--- gcc/sched-deps.c.jj	2010-03-15 08:42:27.000000000 +0100
+++ gcc/sched-deps.c	2010-03-15 08:53:32.000000000 +0100
@@ -3383,7 +3383,7 @@ sched_analyze (struct deps *deps, rtx he
   rtx insn;
 
   if (sched_deps_info->use_cselib)
-    cselib_init (true);
+    cselib_init (CSELIB_RECORD_MEMORY);
 
   deps_start_bb (deps, head);
 
--- gcc/combine.c.jj	2010-03-15 08:42:28.000000000 +0100
+++ gcc/combine.c	2010-03-15 08:53:32.000000000 +0100
@@ -2286,10 +2286,12 @@ struct rtx_subst_pair
    substituted.  */
 
 static rtx
-propagate_for_debug_subst (rtx from ATTRIBUTE_UNUSED, void *data)
+propagate_for_debug_subst (rtx from, const_rtx old_rtx, void *data)
 {
   struct rtx_subst_pair *pair = (struct rtx_subst_pair *)data;
 
+  if (!rtx_equal_p (from, old_rtx))
+    return NULL_RTX;
   if (!pair->adjusted)
     {
       pair->adjusted = true;
--- gcc/Makefile.in.jj	2010-03-15 08:42:33.000000000 +0100
+++ gcc/Makefile.in	2010-03-15 08:53:32.000000000 +0100
@@ -3032,7 +3032,8 @@ var-tracking.o : var-tracking.c $(CONFIG
    $(RTL_H) $(TREE_H) hard-reg-set.h insn-config.h reload.h $(FLAGS_H) \
    $(BASIC_BLOCK_H) output.h sbitmap.h alloc-pool.h $(FIBHEAP_H) $(HASHTAB_H) \
    $(REGS_H) $(EXPR_H) $(TIMEVAR_H) $(TREE_PASS_H) $(TREE_FLOW_H) \
-   cselib.h $(TARGET_H) $(TOPLEV_H) $(PARAMS_H) $(DIAGNOSTIC_H) pointer-set.h
+   cselib.h $(TARGET_H) $(TOPLEV_H) $(PARAMS_H) $(DIAGNOSTIC_H) pointer-set.h \
+   $(RECOG_H)
 profile.o : profile.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) \
    $(TREE_H) $(FLAGS_H) output.h $(REGS_H) $(EXPR_H) $(FUNCTION_H) \
    $(TOPLEV_H) $(COVERAGE_H) $(TREE_FLOW_H) value-prof.h cfghooks.h \
--- gcc/simplify-rtx.c.jj	2010-03-15 08:42:27.000000000 +0100
+++ gcc/simplify-rtx.c	2010-03-15 08:53:32.000000000 +0100
@@ -350,15 +350,14 @@ simplify_gen_relational (enum rtx_code c
   return gen_rtx_fmt_ee (code, mode, op0, op1);
 }
 \f
-/* Replace all occurrences of OLD_RTX in X with FN (X', DATA), where X'
-   is an expression in X that is equal to OLD_RTX.  Canonicalize and
-   simplify the result.
-
-   If FN is null, assume FN (X', DATA) == copy_rtx (DATA).  */
+/* If FN is NULL, replace all occurrences of OLD_RTX in X with copy_rtx (DATA)
+   and simplify the result.  If FN is non-NULL, call this callback on each
+   X, if it returns non-NULL, replace X with its return value and simplify the
+   result.  */
 
 rtx
 simplify_replace_fn_rtx (rtx x, const_rtx old_rtx,
-			 rtx (*fn) (rtx, void *), void *data)
+			 rtx (*fn) (rtx, const_rtx, void *), void *data)
 {
   enum rtx_code code = GET_CODE (x);
   enum machine_mode mode = GET_MODE (x);
@@ -368,17 +367,14 @@ simplify_replace_fn_rtx (rtx x, const_rt
   rtvec vec, newvec;
   int i, j;
 
-  /* If X is OLD_RTX, return FN (X, DATA), with a null FN.  Otherwise,
-     if this is an expression, try to build a new expression, substituting
-     recursively.  If we can't do anything, return our input.  */
-
-  if (rtx_equal_p (x, old_rtx))
+  if (__builtin_expect (fn != NULL, 0))
     {
-      if (fn)
-	return fn (x, data);
-      else
-	return copy_rtx ((rtx) data);
+      newx = fn (x, old_rtx, data);
+      if (newx)
+	return newx;
     }
+  else if (rtx_equal_p (x, old_rtx))
+    return copy_rtx ((rtx) data);
 
   switch (GET_RTX_CLASS (code))
     {
--- gcc/cselib.c.jj	2010-03-15 08:42:27.000000000 +0100
+++ gcc/cselib.c	2010-03-15 08:53:32.000000000 +0100
@@ -45,6 +45,7 @@ along with GCC; see the file COPYING3.  
 #include "target.h"
 
 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 *);
@@ -135,6 +136,11 @@ 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;
+
 /* 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.  */
@@ -229,6 +235,35 @@ cselib_clear_table (void)
   cselib_reset_table (1);
 }
 
+/* Remove from hash table all VALUEs except constants.  */
+
+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;
+	}
+    }
+
+  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,15 +272,37 @@ 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 = REGNO (cfa_base_preserved_val->locs->loc);
+      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;
 
@@ -434,6 +491,18 @@ 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)
+{
+  if (cselib_preserve_constants
+      && v->locs
+      && REG_P (v->locs->loc))
+    cfa_base_preserved_val = v;
+}
+
 /* Clean all non-constant expressions in the hash table, but retain
    their values.  */
 
@@ -1600,7 +1669,7 @@ cselib_invalidate_regno (unsigned int re
 	  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)
 	    {
 	      l = &(*l)->next;
 	      continue;
@@ -2018,7 +2087,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 +2096,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.  */
@@ -2061,6 +2131,8 @@ void
 cselib_finish (void)
 {
   cselib_discard_hook = NULL;
+  cselib_preserve_constants = false;
+  cfa_base_preserved_val = NULL;
   free_alloc_pool (elt_list_pool);
   free_alloc_pool (elt_loc_list_pool);
   free_alloc_pool (cselib_val_pool);
--- gcc/gcse.c.jj	2010-03-15 08:42:27.000000000 +0100
+++ gcc/gcse.c	2010-03-15 08:53:32.000000000 +0100
@@ -2724,7 +2724,7 @@ local_cprop_pass (void)
   struct reg_use *reg_used;
   bool changed = false;
 
-  cselib_init (false);
+  cselib_init (0);
   FOR_EACH_BB (bb)
     {
       FOR_BB_INSNS (bb, insn)
--- gcc/cselib.h.jj	2010-03-15 08:42:27.000000000 +0100
+++ gcc/cselib.h	2010-03-15 08:53:32.000000000 +0100
@@ -66,12 +66,18 @@ struct cselib_set
   cselib_val *dest_addr_elt;
 };
 
+enum cselib_record_what
+{
+  CSELIB_RECORD_MEMORY = 1,
+  CSELIB_PRESERVE_CONSTANTS = 2
+};
+
 extern void (*cselib_discard_hook) (cselib_val *);
 extern void (*cselib_record_sets_hook) (rtx insn, struct cselib_set *sets,
 					int n_sets);
 
 extern cselib_val *cselib_lookup (rtx, enum machine_mode, int);
-extern void cselib_init (bool record_memory);
+extern void cselib_init (int);
 extern void cselib_clear_table (void);
 extern void cselib_finish (void);
 extern void cselib_process_insn (rtx);
@@ -92,5 +98,6 @@ extern unsigned int cselib_get_next_uid 
 extern void cselib_preserve_value (cselib_val *);
 extern bool cselib_preserved_value_p (cselib_val *);
 extern void cselib_preserve_only_values (void);
+extern void cselib_preserve_cfa_base_value (cselib_val *);
 
 extern void dump_cselib_table (FILE *);
--- gcc/testsuite/gcc.dg/guality/pr43051-1.c.jj	2010-03-15 08:53:32.000000000 +0100
+++ gcc/testsuite/gcc.dg/guality/pr43051-1.c	2010-03-15 08:53:32.000000000 +0100
@@ -0,0 +1,57 @@
+/* PR debug/43051 */
+/* { dg-do run } */
+/* { dg-options "-g" } */
+
+extern void abort (void);
+
+static void __attribute__ ((noinline))
+foo (const char *x, long long y, int z)
+{
+  asm volatile ("" : : "r" (x), "r" ((int) y), "r" (z) : "memory");
+}
+
+struct S
+{
+  struct S *n;
+  int v;
+};
+
+struct S a[10];
+
+struct S * __attribute__ ((noinline))
+bar (struct S *c, int v, struct S *e)
+{
+#ifdef __i386__
+  register int si asm ("esi"), di asm ("edi"), bx
+# if !defined (__pic__) && !defined (__APPLE__)
+    asm ("ebx")
+# endif
+    ;
+  asm volatile ("" : "=r" (si), "=r" (di), "=r" (bx));
+#endif
+  while (c < e)
+    {
+      foo ("c", (__UINTPTR_TYPE__) c, 0);	/* { dg-final { gdb-test 34 "c" "\&a\[0\]" } } */
+      foo ("v", v, 1);				/* { dg-final { gdb-test 35 "v" "1" } } */
+      foo ("e", (__UINTPTR_TYPE__) e, 2);	/* { dg-final { gdb-test 36 "e" "\&a\[1\]" } } */
+      if (c->v == v)
+	return c;
+      foo ("c", (__UINTPTR_TYPE__) c, 3);	/* { dg-final { gdb-test 39 "c" "\&a\[0\]" } } */
+      foo ("v", v, 4);				/* { dg-final { gdb-test 40 "v" "1" } } */
+      foo ("e", (__UINTPTR_TYPE__) e, 5);	/* { dg-final { gdb-test 41 "e" "\&a\[1\]" } } */
+      c++;
+    }
+#ifdef __i386__
+  asm volatile ("" : : "r" (si), "r" (di), "r" (bx));
+#endif
+  return 0;
+}
+
+int
+main ()
+{
+  asm volatile ("" : : "r" (&a[0]) : "memory");
+  if (bar (&a[a[0].v], a[0].v + 1, &a[a[0].v + 1]))
+    abort ();
+  return 0;
+}
--- gcc/var-tracking.c.jj	2010-03-15 08:42:28.000000000 +0100
+++ gcc/var-tracking.c	2010-03-15 10:19:34.000000000 +0100
@@ -113,6 +113,7 @@
 #include "params.h"
 #include "diagnostic.h"
 #include "pointer-set.h"
+#include "recog.h"
 
 /* var-tracking.c assumes that tree code with the same value as VALUE rtx code
    has no chance to appear in REG_EXPR/MEM_EXPRs and isn't a decl.
@@ -405,9 +406,8 @@ static void stack_adjust_offset_pre_post
 					  HOST_WIDE_INT *);
 static void insn_stack_adjust_offset_pre_post (rtx, HOST_WIDE_INT *,
 					       HOST_WIDE_INT *);
-static void bb_stack_adjust_offset (basic_block);
 static bool vt_stack_adjustments (void);
-static rtx adjust_stack_reference (rtx, HOST_WIDE_INT);
+static rtx compute_cfa_pointer (HOST_WIDE_INT);
 static hashval_t variable_htab_hash (const void *);
 static int variable_htab_eq (const void *, const void *);
 static void variable_htab_free (void *);
@@ -490,7 +490,7 @@ static void vt_emit_notes (void);
 
 static bool vt_get_decl_and_offset (rtx, tree *, HOST_WIDE_INT *);
 static void vt_add_function_parameters (void);
-static void vt_initialize (void);
+static bool vt_initialize (void);
 static void vt_finalize (void);
 
 /* Given a SET, calculate the amount of stack adjustment it contains
@@ -617,29 +617,6 @@ insn_stack_adjust_offset_pre_post (rtx i
     }
 }
 
-/* Compute stack adjustment in basic block BB.  */
-
-static void
-bb_stack_adjust_offset (basic_block bb)
-{
-  HOST_WIDE_INT offset;
-  unsigned int i;
-  micro_operation *mo;
-
-  offset = VTI (bb)->in.stack_adjust;
-  for (i = 0; VEC_iterate (micro_operation, VTI (bb)->mos, i, mo); i++)
-    {
-      if (mo->type == MO_ADJUST)
-	offset += mo->u.adjust;
-      else if (mo->type != MO_CALL)
-	{
-	  if (MEM_P (mo->u.loc))
-	    mo->u.loc = adjust_stack_reference (mo->u.loc, -offset);
-	}
-    }
-  VTI (bb)->out.stack_adjust = offset;
-}
-
 /* Compute stack adjustments for all blocks by traversing DFS tree.
    Return true when the adjustments on all incoming edges are consistent.
    Heavily borrowed from pre_and_rev_post_order_compute.  */
@@ -652,6 +629,7 @@ vt_stack_adjustments (void)
 
   /* Initialize entry block.  */
   VTI (ENTRY_BLOCK_PTR)->visited = true;
+  VTI (ENTRY_BLOCK_PTR)->in.stack_adjust = INCOMING_FRAME_SP_OFFSET;
   VTI (ENTRY_BLOCK_PTR)->out.stack_adjust = INCOMING_FRAME_SP_OFFSET;
 
   /* Allocate stack for back-tracking up CFG.  */
@@ -675,9 +653,22 @@ vt_stack_adjustments (void)
       /* Check if the edge destination has been visited yet.  */
       if (!VTI (dest)->visited)
 	{
+	  rtx insn;
+	  HOST_WIDE_INT pre, post, offset;
 	  VTI (dest)->visited = true;
-	  VTI (dest)->in.stack_adjust = VTI (src)->out.stack_adjust;
-	  bb_stack_adjust_offset (dest);
+	  VTI (dest)->in.stack_adjust = offset = VTI (src)->out.stack_adjust;
+
+	  if (dest != EXIT_BLOCK_PTR)
+	    for (insn = BB_HEAD (dest);
+		 insn != NEXT_INSN (BB_END (dest));
+		 insn = NEXT_INSN (insn))
+	      if (INSN_P (insn))
+		{
+		  insn_stack_adjust_offset_pre_post (insn, &pre, &post);
+		  offset += pre + post;
+		}
+
+	  VTI (dest)->out.stack_adjust = offset;
 
 	  if (EDGE_COUNT (dest->succs) > 0)
 	    /* Since the DEST node has been visited for the first
@@ -706,13 +697,12 @@ vt_stack_adjustments (void)
   return true;
 }
 
-/* Adjust stack reference MEM by ADJUSTMENT bytes and make it relative
-   to the argument pointer.  Return the new rtx.  */
+/* Compute a CFA-based value for the stack pointer.  */
 
 static rtx
-adjust_stack_reference (rtx mem, HOST_WIDE_INT adjustment)
+compute_cfa_pointer (HOST_WIDE_INT adjustment)
 {
-  rtx addr, cfa, tmp;
+  rtx cfa;
 
 #ifdef FRAME_POINTER_CFA_OFFSET
   adjustment -= FRAME_POINTER_CFA_OFFSET (current_function_decl);
@@ -722,12 +712,216 @@ adjust_stack_reference (rtx mem, HOST_WI
   cfa = plus_constant (arg_pointer_rtx, adjustment);
 #endif
 
-  addr = replace_rtx (copy_rtx (XEXP (mem, 0)), stack_pointer_rtx, cfa);
-  tmp = simplify_rtx (addr);
-  if (tmp)
-    addr = tmp;
+  return cfa;
+}
+
+/* Adjustment for hard_frame_pointer_rtx to cfa base reg,
+   or -1 if the replacement shouldn't be done.  */
+static HOST_WIDE_INT hard_frame_pointer_adjustment = -1;
+
+/* Data for adjust_mems callback.  */
+
+struct adjust_mem_data
+{
+  bool store;
+  enum machine_mode mem_mode;
+  HOST_WIDE_INT stack_adjust;
+  rtx side_effects;
+};
+
+/* Helper function for adjusting used MEMs.  */
 
-  return replace_equiv_address_nv (mem, addr);
+static rtx
+adjust_mems (rtx loc, const_rtx old_rtx, void *data)
+{
+  struct adjust_mem_data *amd = (struct adjust_mem_data *) data;
+  rtx mem, addr = loc, tem;
+  enum machine_mode mem_mode_save;
+  bool store_save;
+  switch (GET_CODE (loc))
+    {
+    case REG:
+      /* Don't do any sp or fp replacements outside of MEM addresses.  */
+      if (amd->mem_mode == VOIDmode)
+	return loc;
+      if (loc == stack_pointer_rtx
+	  && !frame_pointer_needed)
+	return compute_cfa_pointer (amd->stack_adjust);
+      else if (loc == hard_frame_pointer_rtx
+	       && frame_pointer_needed
+	       && hard_frame_pointer_adjustment != -1)
+	return compute_cfa_pointer (hard_frame_pointer_adjustment);
+      return loc;
+    case MEM:
+      mem = loc;
+      if (!amd->store)
+	{
+	  mem = targetm.delegitimize_address (mem);
+	  if (mem != loc && !MEM_P (mem))
+	    return simplify_replace_fn_rtx (mem, old_rtx, adjust_mems, data);
+	}
+
+      addr = XEXP (mem, 0);
+      mem_mode_save = amd->mem_mode;
+      amd->mem_mode = GET_MODE (mem);
+      store_save = amd->store;
+      amd->store = false;
+      addr = simplify_replace_fn_rtx (addr, old_rtx, adjust_mems, data);
+      amd->store = store_save;
+      amd->mem_mode = mem_mode_save;
+      if (mem == loc)
+	addr = targetm.delegitimize_address (addr);
+      if (addr != XEXP (mem, 0))
+	mem = replace_equiv_address_nv (mem, addr);
+      if (!amd->store)
+	mem = avoid_constant_pool_reference (mem);
+      return mem;
+    case PRE_INC:
+    case PRE_DEC:
+      addr = gen_rtx_PLUS (GET_MODE (loc), XEXP (loc, 0),
+			   GEN_INT (GET_CODE (loc) == PRE_INC
+				    ? GET_MODE_SIZE (amd->mem_mode)
+				    : -GET_MODE_SIZE (amd->mem_mode)));
+    case POST_INC:
+    case POST_DEC:
+      if (addr == loc)
+	addr = XEXP (loc, 0);
+      gcc_assert (amd->mem_mode != VOIDmode && amd->mem_mode != BLKmode);
+      addr = simplify_replace_fn_rtx (addr, old_rtx, adjust_mems, data);
+      tem = gen_rtx_PLUS (GET_MODE (loc), XEXP (loc, 0),
+			   GEN_INT ((GET_CODE (loc) == PRE_INC
+				     || GET_CODE (loc) == POST_INC)
+				    ? GET_MODE_SIZE (amd->mem_mode)
+				    : -GET_MODE_SIZE (amd->mem_mode)));
+      amd->side_effects = alloc_EXPR_LIST (0,
+					   gen_rtx_SET (VOIDmode,
+							XEXP (loc, 0),
+							tem),
+					   amd->side_effects);
+      return addr;
+    case PRE_MODIFY:
+      addr = XEXP (loc, 1);
+    case POST_MODIFY:
+      if (addr == loc)
+	addr = XEXP (loc, 0);
+      gcc_assert (amd->mem_mode != VOIDmode && amd->mem_mode != BLKmode);
+      addr = simplify_replace_fn_rtx (addr, old_rtx, adjust_mems, data);
+      amd->side_effects = alloc_EXPR_LIST (0,
+					   gen_rtx_SET (VOIDmode,
+							XEXP (loc, 0),
+							XEXP (loc, 1)),
+					   amd->side_effects);
+      return addr;
+    case SUBREG:
+      /* First try without delegitimization of whole MEMs and
+	 avoid_constant_pool_reference, which is more likely to succeed.  */
+      store_save = amd->store;
+      amd->store = true;
+      addr = simplify_replace_fn_rtx (SUBREG_REG (loc), old_rtx, adjust_mems,
+				      data);
+      amd->store = store_save;
+      mem = simplify_replace_fn_rtx (addr, old_rtx, adjust_mems, data);
+      if (mem == SUBREG_REG (loc))
+	return loc;
+      tem = simplify_gen_subreg (GET_MODE (loc), mem,
+				 GET_MODE (SUBREG_REG (loc)),
+				 SUBREG_BYTE (loc));
+      if (tem)
+	return tem;
+      tem = simplify_gen_subreg (GET_MODE (loc), addr,
+				 GET_MODE (SUBREG_REG (loc)),
+				 SUBREG_BYTE (loc));
+      if (tem)
+	return tem;
+      return gen_rtx_raw_SUBREG (GET_MODE (loc), addr, SUBREG_BYTE (loc));
+    default:
+      break;
+    }
+  return NULL_RTX;
+}
+
+/* Helper function for replacement of uses.  */
+
+static void
+adjust_mem_uses (rtx *x, void *data)
+{
+  rtx new_x = simplify_replace_fn_rtx (*x, NULL_RTX, adjust_mems, data);
+  if (new_x != *x)
+    validate_change (NULL_RTX, x, new_x, true);
+}
+
+/* Helper function for replacement of stores.  */
+
+static void
+adjust_mem_stores (rtx loc, const_rtx expr, void *data)
+{
+  if (MEM_P (loc))
+    {
+      rtx new_dest = simplify_replace_fn_rtx (SET_DEST (expr), NULL_RTX,
+					      adjust_mems, data);
+      if (new_dest != SET_DEST (expr))
+	{
+	  rtx xexpr = CONST_CAST_RTX (expr);
+	  validate_change (NULL_RTX, &SET_DEST (xexpr), new_dest, true);
+	}
+    }
+}
+
+/* Simplify INSN.  Remove all {PRE,POST}_{INC,DEC,MODIFY} rtxes,
+   replace them with their value in the insn and add the side-effects
+   as other sets to the insn.  */
+
+static void
+adjust_insn (basic_block bb, rtx insn)
+{
+  struct adjust_mem_data amd;
+  rtx set;
+  amd.mem_mode = VOIDmode;
+  amd.stack_adjust = -VTI (bb)->out.stack_adjust;
+  amd.side_effects = NULL_RTX;
+
+  amd.store = true;
+  note_stores (PATTERN (insn), adjust_mem_stores, &amd);
+
+  amd.store = false;
+  note_uses (&PATTERN (insn), adjust_mem_uses, &amd);
+
+  /* For read-only MEMs containing some constant, prefer those
+     constants.  */
+  set = single_set (insn);
+  if (set && MEM_P (SET_SRC (set)) && MEM_READONLY_P (SET_SRC (set)))
+    {
+      rtx note = find_reg_equal_equiv_note (insn);
+
+      if (note && CONSTANT_P (XEXP (note, 0)))
+	validate_change (NULL_RTX, &SET_SRC (set), XEXP (note, 0), true);
+    }
+
+  if (amd.side_effects)
+    {
+      rtx *pat, new_pat, s;
+      int i, oldn, newn;
+
+      pat = &PATTERN (insn);
+      if (GET_CODE (*pat) == COND_EXEC)
+	pat = &COND_EXEC_CODE (*pat);
+      if (GET_CODE (*pat) == PARALLEL)
+	oldn = XVECLEN (*pat, 0);
+      else
+	oldn = 1;
+      for (s = amd.side_effects, newn = 0; s; newn++)
+	s = XEXP (s, 1);
+      new_pat = gen_rtx_PARALLEL (VOIDmode, rtvec_alloc (oldn + newn));
+      if (GET_CODE (*pat) == PARALLEL)
+	for (i = 0; i < oldn; i++)
+	  XVECEXP (new_pat, 0, i) = XVECEXP (*pat, 0, i);
+      else
+	XVECEXP (new_pat, 0, 0) = *pat;
+      for (s = amd.side_effects, i = oldn; i < oldn + newn; i++, s = XEXP (s, 1))
+	XVECEXP (new_pat, 0, i) = XEXP (s, 0);
+      free_EXPR_LIST_list (&amd.side_effects);
+      validate_change (NULL_RTX, pat, new_pat, true);
+    }
 }
 
 /* Return true if a decl_or_value DV is a DECL or NULL.  */
@@ -4326,6 +4520,10 @@ var_lowpart (enum machine_mode mode, rtx
   return gen_rtx_REG_offset (loc, mode, regno, offset);
 }
 
+/* arg_pointer_rtx resp. frame_pointer_rtx if stack_pointer_rtx or
+   hard_frame_pointer_rtx is being mapped to it.  */
+static rtx cfa_base_rtx;
+
 /* Carry information about uses and stores while walking rtx.  */
 
 struct count_use_info
@@ -4371,6 +4569,17 @@ find_use_val (rtx x, enum machine_mode m
   return NULL;
 }
 
+/* Helper function to get mode of MEM's address.  */
+
+static inline enum machine_mode
+get_address_mode (rtx mem)
+{
+  enum machine_mode mode = GET_MODE (XEXP (mem, 0));
+  if (mode != VOIDmode)
+    return mode;
+  return targetm.addr_space.address_mode (MEM_ADDR_SPACE (mem));
+}
+
 /* Replace all registers and addresses in an expression with VALUE
    expressions that map back to them, unless the expression is a
    register.  If no mapping is or can be performed, returns NULL.  */
@@ -4382,9 +4591,8 @@ replace_expr_with_values (rtx loc)
     return NULL;
   else if (MEM_P (loc))
     {
-      enum machine_mode address_mode
-	= targetm.addr_space.address_mode (MEM_ADDR_SPACE (loc));
-      cselib_val *addr = cselib_lookup (XEXP (loc, 0), address_mode, 0);
+      cselib_val *addr = cselib_lookup (XEXP (loc, 0),
+					get_address_mode (loc), 0);
       if (addr)
 	return replace_equiv_address_nv (loc, addr->val_rtx);
       else
@@ -4409,12 +4617,15 @@ use_type (rtx loc, struct count_use_info
 	  if (track_expr_p (PAT_VAR_LOCATION_DECL (loc), false))
 	    {
 	      rtx ploc = PAT_VAR_LOCATION_LOC (loc);
-	      cselib_val *val = cselib_lookup (ploc, GET_MODE (loc), 1);
+	      if (! VAR_LOC_UNKNOWN_P (ploc))
+		{
+		  cselib_val *val = cselib_lookup (ploc, GET_MODE (loc), 1);
 
-	      /* ??? flag_float_store and volatile mems are never
-		 given values, but we could in theory use them for
-		 locations.  */
-	      gcc_assert (val || 1);
+		  /* ??? flag_float_store and volatile mems are never
+		     given values, but we could in theory use them for
+		     locations.  */
+		  gcc_assert (val || 1);
+		}
 	      return MO_VAL_LOC;
 	    }
 	  else
@@ -4429,7 +4640,8 @@ use_type (rtx loc, struct count_use_info
 	    {
 	      if (REG_P (loc)
 		  || (find_use_val (loc, GET_MODE (loc), cui)
-		      && cselib_lookup (XEXP (loc, 0), GET_MODE (loc), 0)))
+		      && cselib_lookup (XEXP (loc, 0),
+					get_address_mode (loc), 0)))
 		return MO_VAL_SET;
 	    }
 	  else
@@ -4446,6 +4658,8 @@ use_type (rtx loc, struct count_use_info
     {
       gcc_assert (REGNO (loc) < FIRST_PSEUDO_REGISTER);
 
+      if (loc == cfa_base_rtx)
+	return MO_CLOBBER;
       expr = REG_EXPR (loc);
 
       if (!expr)
@@ -4490,30 +4704,6 @@ log_op_type (rtx x, basic_block bb, rtx 
   fputc ('\n', out);
 }
 
-/* Adjust sets if needed.  Currently this optimizes read-only MEM loads
-   if REG_EQUAL/REG_EQUIV note is present.  */
-
-static void
-adjust_sets (rtx insn, struct cselib_set *sets, int n_sets)
-{
-  if (n_sets == 1 && MEM_P (sets[0].src) && MEM_READONLY_P (sets[0].src))
-    {
-      /* For read-only MEMs containing some constant, prefer those
-	 constants.  */
-      rtx note = find_reg_equal_equiv_note (insn), src;
-
-      if (note && CONSTANT_P (XEXP (note, 0)))
-	{
-	  sets[0].src = src = XEXP (note, 0);
-	  if (GET_CODE (PATTERN (insn)) == COND_EXEC)
-	    src = gen_rtx_IF_THEN_ELSE (GET_MODE (sets[0].dest),
-					COND_EXEC_TEST (PATTERN (insn)),
-					src, sets[0].dest);
-	  sets[0].src_elt = cselib_lookup (src, GET_MODE (sets[0].dest), 1);
-	}
-    }
-}
-
 /* Tell whether the CONCAT used to holds a VALUE and its location
    needs value resolution, i.e., an attempt of mapping the location
    back to other incoming values.  */
@@ -4577,11 +4767,14 @@ add_uses (rtx *ploc, void *data)
 	  gcc_assert (cui->sets);
 
 	  if (MEM_P (vloc)
-	      && !REG_P (XEXP (vloc, 0)) && !MEM_P (XEXP (vloc, 0)))
+	      && !REG_P (XEXP (vloc, 0))
+	      && !MEM_P (XEXP (vloc, 0))
+	      && (GET_CODE (XEXP (vloc, 0)) != PLUS
+		  || XEXP (XEXP (vloc, 0), 0) != cfa_base_rtx
+		  || !CONST_INT_P (XEXP (XEXP (vloc, 0), 1))))
 	    {
 	      rtx mloc = vloc;
-	      enum machine_mode address_mode
-		= targetm.addr_space.address_mode (MEM_ADDR_SPACE (mloc));
+	      enum machine_mode address_mode = get_address_mode (mloc);
 	      cselib_val *val
 		= cselib_lookup (XEXP (mloc, 0), address_mode, 0);
 
@@ -4646,11 +4839,14 @@ add_uses (rtx *ploc, void *data)
 	  gcc_assert (cui->sets);
 
 	  if (MEM_P (oloc)
-	      && !REG_P (XEXP (oloc, 0)) && !MEM_P (XEXP (oloc, 0)))
+	      && !REG_P (XEXP (oloc, 0))
+	      && !MEM_P (XEXP (oloc, 0))
+	      && (GET_CODE (XEXP (oloc, 0)) != PLUS
+		  || XEXP (XEXP (oloc, 0), 0) != cfa_base_rtx
+		  || !CONST_INT_P (XEXP (XEXP (oloc, 0), 1))))
 	    {
 	      rtx mloc = oloc;
-	      enum machine_mode address_mode
-		= targetm.addr_space.address_mode (MEM_ADDR_SPACE (mloc));
+	      enum machine_mode address_mode = get_address_mode (mloc);
 	      cselib_val *val
 		= cselib_lookup (XEXP (mloc, 0), address_mode, 0);
 
@@ -4814,21 +5010,6 @@ reverse_op (rtx val, const_rtx expr)
   return gen_rtx_CONCAT (GET_MODE (v->val_rtx), v->val_rtx, ret);
 }
 
-/* Return SRC, or, if it is a read-only MEM for which adjust_sets
-   replated it with a constant from REG_EQUIV/REG_EQUAL note,
-   that constant.  */
-
-static inline rtx
-get_adjusted_src (struct count_use_info *cui, rtx src)
-{
-  if (cui->n_sets == 1
-      && MEM_P (src)
-      && MEM_READONLY_P (src)
-      && CONSTANT_P (cui->sets[0].src))
-    return cui->sets[0].src;
-  return src;
-}
-
 /* Add stores (register and memory references) LOC which will be tracked
    to VTI (bb)->mos.  EXPR is the RTL expression containing the store.
    CUIP->insn is instruction which the LOC is part of.  */
@@ -4854,6 +5035,7 @@ add_stores (rtx loc, const_rtx expr, voi
 
   if (REG_P (loc))
     {
+      gcc_assert (loc != cfa_base_rtx);
       if ((GET_CODE (expr) == CLOBBER && type != MO_VAL_SET)
 	  || !(track_p = use_type (loc, NULL, &mode2) == MO_USE)
 	  || GET_CODE (expr) == CLOBBER)
@@ -4864,10 +5046,7 @@ add_stores (rtx loc, const_rtx expr, voi
       else
 	{
 	  if (GET_CODE (expr) == SET && SET_DEST (expr) == loc)
-	    {
-	      src = get_adjusted_src (cui, SET_SRC (expr));
-	      src = var_lowpart (mode2, src);
-	    }
+	    src = var_lowpart (mode2, SET_SRC (expr));
 	  loc = var_lowpart (mode2, loc);
 
 	  if (src == NULL)
@@ -4877,10 +5056,7 @@ add_stores (rtx loc, const_rtx expr, voi
 	    }
 	  else
 	    {
-	      rtx xexpr = CONST_CAST_RTX (expr);
-
-	      if (SET_SRC (expr) != src)
-		xexpr = gen_rtx_SET (VOIDmode, loc, src);
+	      rtx xexpr = gen_rtx_SET (VOIDmode, loc, src);
 	      if (same_variable_part_p (src, REG_EXPR (loc), REG_OFFSET (loc)))
 		mo.type = MO_COPY;
 	      else
@@ -4895,12 +5071,16 @@ add_stores (rtx loc, const_rtx expr, voi
 	       || cui->sets))
     {
       if (MEM_P (loc) && type == MO_VAL_SET
-	  && !REG_P (XEXP (loc, 0)) && !MEM_P (XEXP (loc, 0)))
+	  && !REG_P (XEXP (loc, 0))
+	  && !MEM_P (XEXP (loc, 0))
+	  && (GET_CODE (XEXP (loc, 0)) != PLUS
+	      || XEXP (XEXP (loc, 0), 0) != cfa_base_rtx
+	      || !CONST_INT_P (XEXP (XEXP (loc, 0), 1))))
 	{
 	  rtx mloc = loc;
-	  enum machine_mode address_mode
-	    = targetm.addr_space.address_mode (MEM_ADDR_SPACE (mloc));
-	  cselib_val *val = cselib_lookup (XEXP (mloc, 0), address_mode, 0);
+	  enum machine_mode address_mode = get_address_mode (mloc);
+	  cselib_val *val = cselib_lookup (XEXP (mloc, 0),
+					   address_mode, 0);
 
 	  if (val && !cselib_preserved_value_p (val))
 	    {
@@ -4924,10 +5104,7 @@ add_stores (rtx loc, const_rtx expr, voi
       else
 	{
 	  if (GET_CODE (expr) == SET && SET_DEST (expr) == loc)
-	    {
-	      src = get_adjusted_src (cui, SET_SRC (expr));
-	      src = var_lowpart (mode2, src);
-	    }
+	    src = var_lowpart (mode2, SET_SRC (expr));
 	  loc = var_lowpart (mode2, loc);
 
 	  if (src == NULL)
@@ -4937,10 +5114,7 @@ add_stores (rtx loc, const_rtx expr, voi
 	    }
 	  else
 	    {
-	      rtx xexpr = CONST_CAST_RTX (expr);
-
-	      if (SET_SRC (expr) != src)
-		xexpr = gen_rtx_SET (VOIDmode, loc, src);
+	      rtx xexpr = gen_rtx_SET (VOIDmode, loc, src);
 	      if (same_variable_part_p (SET_SRC (xexpr),
 					MEM_EXPR (loc),
 					INT_MEM_OFFSET (loc)))
@@ -4997,13 +5171,12 @@ add_stores (rtx loc, const_rtx expr, voi
     }
   else if (resolve && GET_CODE (mo.u.loc) == SET)
     {
-      src = get_adjusted_src (cui, SET_SRC (expr));
-      nloc = replace_expr_with_values (src);
+      nloc = replace_expr_with_values (SET_SRC (expr));
 
       /* Avoid the mode mismatch between oexpr and expr.  */
       if (!nloc && mode != mode2)
 	{
-	  nloc = src;
+	  nloc = SET_SRC (expr);
 	  gcc_assert (oloc == SET_DEST (expr));
 	}
 
@@ -5102,8 +5275,6 @@ add_with_sets (rtx insn, struct cselib_s
 
   cselib_hook_called = true;
 
-  adjust_sets (insn, sets, n_sets);
-
   cui.insn = insn;
   cui.bb = bb;
   cui.sets = sets;
@@ -6690,7 +6861,7 @@ emit_note_insn_var_location (void **varp
   complete = true;
   last_limit = 0;
   n_var_parts = 0;
-  if (!MAY_HAVE_DEBUG_STMTS)
+  if (!MAY_HAVE_DEBUG_INSNS)
     {
       for (i = 0; i < var->n_var_parts; i++)
 	if (var->var_part[i].cur_loc == NULL && var->var_part[i].loc_chain)
@@ -7688,19 +7859,109 @@ vt_add_function_parameters (void)
 
 }
 
+/* Return true if INSN in the prologue initializes hard_frame_pointer_rtx.  */
+
+static bool
+fp_setter (rtx insn)
+{
+  rtx pat = PATTERN (insn);
+  if (RTX_FRAME_RELATED_P (insn))
+    {
+      rtx expr = find_reg_note (insn, REG_FRAME_RELATED_EXPR, NULL_RTX);
+      if (expr)
+	pat = XEXP (expr, 0);
+    }
+  if (GET_CODE (pat) == SET)
+    return SET_DEST (pat) == hard_frame_pointer_rtx;
+  else if (GET_CODE (pat) == PARALLEL)
+    {
+      int i;
+      for (i = XVECLEN (pat, 0) - 1; i >= 0; i--)
+	if (GET_CODE (XVECEXP (pat, 0, i)) == SET
+	    && SET_DEST (XVECEXP (pat, 0, i)) == hard_frame_pointer_rtx)
+	  return true;
+    }
+  return false;
+}
+
+/* Initialize cfa_base_rtx, create a preserved VALUE for it and
+   ensure it isn't flushed during cselib_reset_table.
+   Can be called only if frame_pointer_rtx resp. arg_pointer_rtx
+   has been eliminated.  */
+
+static void
+vt_init_cfa_base (void)
+{
+  cselib_val *val;
+
+#ifdef FRAME_POINTER_CFA_OFFSET
+  cfa_base_rtx = frame_pointer_rtx;
+#else
+  cfa_base_rtx = arg_pointer_rtx;
+#endif
+  if (!MAY_HAVE_DEBUG_INSNS)
+    return;
+
+  val = cselib_lookup (cfa_base_rtx, GET_MODE (cfa_base_rtx), 1);
+  preserve_value (val);
+  cselib_preserve_cfa_base_value (val);
+  val->locs->setting_insn = get_insns ();
+  var_reg_decl_set (&VTI (ENTRY_BLOCK_PTR)->out, cfa_base_rtx,
+		    VAR_INIT_STATUS_INITIALIZED, dv_from_value (val->val_rtx),
+		    0, NULL_RTX, INSERT);
+}
+
 /* Allocate and initialize the data structures for variable tracking
    and parse the RTL to get the micro operations.  */
 
-static void
+static bool
 vt_initialize (void)
 {
-  basic_block bb;
+  basic_block bb, prologue_bb = NULL;
+  HOST_WIDE_INT fp_cfa_offset = -1;
 
   alloc_aux_for_blocks (sizeof (struct variable_tracking_info_def));
 
+  attrs_pool = create_alloc_pool ("attrs_def pool",
+				  sizeof (struct attrs_def), 1024);
+  var_pool = create_alloc_pool ("variable_def pool",
+				sizeof (struct variable_def)
+				+ (MAX_VAR_PARTS - 1)
+				* sizeof (((variable)NULL)->var_part[0]), 64);
+  loc_chain_pool = create_alloc_pool ("location_chain_def pool",
+				      sizeof (struct location_chain_def),
+				      1024);
+  shared_hash_pool = create_alloc_pool ("shared_hash_def pool",
+					sizeof (struct shared_hash_def), 256);
+  empty_shared_hash = (shared_hash) pool_alloc (shared_hash_pool);
+  empty_shared_hash->refcount = 1;
+  empty_shared_hash->htab
+    = htab_create (1, variable_htab_hash, variable_htab_eq,
+		   variable_htab_free);
+  changed_variables = htab_create (10, variable_htab_hash, variable_htab_eq,
+				   variable_htab_free);
   if (MAY_HAVE_DEBUG_INSNS)
     {
-      cselib_init (true);
+      value_chain_pool = create_alloc_pool ("value_chain_def pool",
+					    sizeof (struct value_chain_def),
+					    1024);
+      value_chains = htab_create (32, value_chain_htab_hash,
+				  value_chain_htab_eq, NULL);
+    }
+
+  /* Init the IN and OUT sets.  */
+  FOR_ALL_BB (bb)
+    {
+      VTI (bb)->visited = false;
+      VTI (bb)->flooded = false;
+      dataflow_set_init (&VTI (bb)->in);
+      dataflow_set_init (&VTI (bb)->out);
+      VTI (bb)->permp = NULL;
+    }
+
+  if (MAY_HAVE_DEBUG_INSNS)
+    {
+      cselib_init (CSELIB_RECORD_MEMORY | CSELIB_PRESERVE_CONSTANTS);
       scratch_regs = BITMAP_ALLOC (NULL);
       valvar_pool = create_alloc_pool ("small variable_def pool",
 				       sizeof (struct variable_def), 256);
@@ -7712,6 +7973,55 @@ vt_initialize (void)
       valvar_pool = NULL;
     }
 
+  if (!frame_pointer_needed)
+    {
+      rtx reg, elim;
+
+      if (!vt_stack_adjustments ())
+	return false;
+
+#ifdef FRAME_POINTER_CFA_OFFSET
+      reg = frame_pointer_rtx;
+#else
+      reg = arg_pointer_rtx;
+#endif
+      elim = eliminate_regs (reg, VOIDmode, NULL_RTX);
+      if (elim != reg)
+	{
+	  if (GET_CODE (elim) == PLUS)
+	    elim = XEXP (elim, 0);
+	  if (elim == stack_pointer_rtx)
+	    vt_init_cfa_base ();
+	}
+    }
+  else if (!crtl->stack_realign_tried)
+    {
+      rtx reg, elim;
+
+#ifdef FRAME_POINTER_CFA_OFFSET
+      reg = frame_pointer_rtx;
+      fp_cfa_offset = FRAME_POINTER_CFA_OFFSET (current_function_decl);
+#else
+      reg = arg_pointer_rtx;
+      fp_cfa_offset = ARG_POINTER_CFA_OFFSET (current_function_decl);
+#endif
+      elim = eliminate_regs (reg, VOIDmode, NULL_RTX);
+      if (elim != reg)
+	{
+	  if (GET_CODE (elim) == PLUS)
+	    {
+	      fp_cfa_offset -= INTVAL (XEXP (elim, 1));
+	      elim = XEXP (elim, 0);
+	    }
+	  if (elim != hard_frame_pointer_rtx)
+	    fp_cfa_offset = -1;
+	  else
+	    prologue_bb = single_succ (ENTRY_BLOCK_PTR);
+	}
+    }
+
+  hard_frame_pointer_adjustment = -1;
+
   FOR_EACH_BB (bb)
     {
       rtx insn;
@@ -7743,6 +8053,8 @@ vt_initialize (void)
       /* Add the micro-operations to the vector.  */
       FOR_BB_BETWEEN (bb, first_bb, last_bb->next_bb, next_bb)
 	{
+	  HOST_WIDE_INT offset = VTI (bb)->out.stack_adjust;
+	  VTI (bb)->out.stack_adjust = VTI (bb)->in.stack_adjust;
 	  for (insn = BB_HEAD (bb); insn != NEXT_INSN (BB_END (bb));
 	       insn = NEXT_INSN (insn))
 	    {
@@ -7757,16 +8069,17 @@ vt_initialize (void)
 			  mo.type = MO_ADJUST;
 			  mo.u.adjust = pre;
 			  mo.insn = insn;
-			  VEC_safe_push (micro_operation, heap, VTI (bb)->mos,
-					 &mo);
-
 			  if (dump_file && (dump_flags & TDF_DETAILS))
 			    log_op_type (PATTERN (insn), bb, insn,
 					 MO_ADJUST, dump_file);
+			  VEC_safe_push (micro_operation, heap, VTI (bb)->mos,
+					 &mo);
+			  VTI (bb)->out.stack_adjust += pre;
 			}
 		    }
 
 		  cselib_hook_called = false;
+		  adjust_insn (bb, insn);
 		  if (MAY_HAVE_DEBUG_INSNS)
 		    {
 		      cselib_process_insn (insn);
@@ -7778,6 +8091,7 @@ vt_initialize (void)
 		    }
 		  if (!cselib_hook_called)
 		    add_with_sets (insn, 0, 0);
+		  cancel_changes (0);
 
 		  if (!frame_pointer_needed && post)
 		    {
@@ -7785,15 +8099,25 @@ vt_initialize (void)
 		      mo.type = MO_ADJUST;
 		      mo.u.adjust = post;
 		      mo.insn = insn;
-		      VEC_safe_push (micro_operation, heap, VTI (bb)->mos,
-				     &mo);
-
 		      if (dump_file && (dump_flags & TDF_DETAILS))
 			log_op_type (PATTERN (insn), bb, insn,
 				     MO_ADJUST, dump_file);
+		      VEC_safe_push (micro_operation, heap, VTI (bb)->mos,
+				     &mo);
+		      VTI (bb)->out.stack_adjust += post;
+		    }
+
+		  if (bb == prologue_bb
+		      && hard_frame_pointer_adjustment == -1
+		      && RTX_FRAME_RELATED_P (insn)
+		      && fp_setter (insn))
+		    {
+		      vt_init_cfa_base ();
+		      hard_frame_pointer_adjustment = fp_cfa_offset;
 		    }
 		}
 	    }
+	  gcc_assert (offset == VTI (bb)->out.stack_adjust);
 	}
 
       bb = last_bb;
@@ -7806,45 +8130,11 @@ vt_initialize (void)
 	}
     }
 
-  attrs_pool = create_alloc_pool ("attrs_def pool",
-				  sizeof (struct attrs_def), 1024);
-  var_pool = create_alloc_pool ("variable_def pool",
-				sizeof (struct variable_def)
-				+ (MAX_VAR_PARTS - 1)
-				* sizeof (((variable)NULL)->var_part[0]), 64);
-  loc_chain_pool = create_alloc_pool ("location_chain_def pool",
-				      sizeof (struct location_chain_def),
-				      1024);
-  shared_hash_pool = create_alloc_pool ("shared_hash_def pool",
-					sizeof (struct shared_hash_def), 256);
-  empty_shared_hash = (shared_hash) pool_alloc (shared_hash_pool);
-  empty_shared_hash->refcount = 1;
-  empty_shared_hash->htab
-    = htab_create (1, variable_htab_hash, variable_htab_eq,
-		   variable_htab_free);
-  changed_variables = htab_create (10, variable_htab_hash, variable_htab_eq,
-				   variable_htab_free);
-  if (MAY_HAVE_DEBUG_INSNS)
-    {
-      value_chain_pool = create_alloc_pool ("value_chain_def pool",
-					    sizeof (struct value_chain_def),
-					    1024);
-      value_chains = htab_create (32, value_chain_htab_hash,
-				  value_chain_htab_eq, NULL);
-    }
-
-  /* Init the IN and OUT sets.  */
-  FOR_ALL_BB (bb)
-    {
-      VTI (bb)->visited = false;
-      VTI (bb)->flooded = false;
-      dataflow_set_init (&VTI (bb)->in);
-      dataflow_set_init (&VTI (bb)->out);
-      VTI (bb)->permp = NULL;
-    }
-
+  hard_frame_pointer_adjustment = -1;
   VTI (ENTRY_BLOCK_PTR)->flooded = true;
   vt_add_function_parameters ();
+  cfa_base_rtx = NULL_RTX;
+  return true;
 }
 
 /* Get rid of all debug insns from the insn stream.  */
@@ -7946,15 +8236,11 @@ variable_tracking_main_1 (void)
     }
 
   mark_dfs_back_edges ();
-  vt_initialize ();
-  if (!frame_pointer_needed)
+  if (!vt_initialize ())
     {
-      if (!vt_stack_adjustments ())
-	{
-	  vt_finalize ();
-	  vt_debug_insns_local (true);
-	  return 0;
-	}
+      vt_finalize ();
+      vt_debug_insns_local (true);
+      return 0;
     }
 
   success = vt_find_locations ();
@@ -7968,10 +8254,8 @@ variable_tracking_main_1 (void)
       /* This is later restored by our caller.  */
       flag_var_tracking_assignments = 0;
 
-      vt_initialize ();
-
-      if (!frame_pointer_needed && !vt_stack_adjustments ())
-	gcc_unreachable ();
+      success = vt_initialize ();
+      gcc_assert (success);
 
       success = vt_find_locations ();
     }

	Jakub

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH] Fix VTA sp (and fp) based MEM handling (PR debug/43051,  PR debug/43092)
  2010-03-15 13:16 [PATCH] Fix VTA sp (and fp) based MEM handling (PR debug/43051, PR debug/43092) Jakub Jelinek
@ 2010-03-16 10:51 ` Richard Guenther
  2010-03-23  8:52 ` Alexandre Oliva
  1 sibling, 0 replies; 10+ messages in thread
From: Richard Guenther @ 2010-03-16 10:51 UTC (permalink / raw)
  To: Jakub Jelinek; +Cc: Alexandre Oliva, gcc-patches

On Mon, 15 Mar 2010, Jakub Jelinek wrote:

> Hi!
> 
> The following patch fixes a bunch of sp (and fp) based MEM tracking issues.
> 
> PR43092 is about an addressable variable with -fomit-frame-pointer
> -mno-accumulate-outgoing-args.  With -fno-var-tracking-assignments
> this worked, as vt_stack_adjustments remapped the stack based locations to
> argp/framep based ones.  vt_stack_adjustments handled well just the
> MO_SET/MO_USE/MO_COPY cases (and, apparently, not even those which involved
> a SET added in there), but certainly not MO_VAL_SET with its embedded
> CONCATs.  Handling that is possible (I actually wrote it in one of the first
> versions of this patch), but it handles only the cases where we don't
> track VALUEs.  As soon as VALUEs need to be tracked (e.g. if there is some
> optimized out variable that was set from such living sp based address), we
> run into other issues.  One is that cselib doesn't handle autoinc rtls well
> (Alex has a follow-up patch in which it teaches cselib about these; this
> final version of the patch doesn't need it for var-tracking though).
> Another one is that doing the sp -> argp + offset replacements in
> vt_stack_adjustments is too late, we need to create VALUEs for them to
> be able to track them properly.  This is done in the vt_initialize /
> vt_stack_adjustment reorganization in the patch below.  We compute the stack
> adjustments in each bb first, before add_{stores,uses}, and can use that
> as VALUEs.  The adjust_sets way of updating MEMs with all the other
> reasons to update them unfortunately became quite unmanagable (we don't
> want to only optimize src MEM/u with REG_EQUIV/REG_EQUAL note, but also
> do that sp (and fp) replacement with argp + const, and delegitimize_address,
> avoid_constant_pool_reference and autoinc removal too), and also needed
> more VALUEs than necessary (cselib initially looked up what was in the
> original instruction, then the hook was called, changed many things
> in src and dests, and had to do cselib lookups again for the replaced
> things).  This patch instead does all the updates on the insn before calling
> cselib_process_insn, using validate_change in_group, changing a valid insn
> into a representation that is useful for debug info purposes, then lets cselib
> process the insns and afterwards cancel_changes (0) to restore the original
> insn.  Always whole set dests and srcs are replaced, not subexpressions
> thereof, so even when add_uses/add_stores references the whole stores or
> uses or parts thereof, the cancel_changes (0) call doesn't affect them.
> 
> This patch also fixes PR43051, where we weren't able to track a variable,
> as the MEMs it was said to live at in 2 different predecessors used
> different VALUE, by making sure VALUEs that are constant through the
> whole function aren't flushed from the cselib hash table after each ebb,
> thus the same VALUE is used in all the bbs for the same thing.
> Such constants include CONSTANT_P (except for CONST which includes some
> VALUEs - in most cases the delegitimization will turn them into real
> consts), argp (resp. framep), provided it has been eliminated and thus
> it is a constant CFA - some offset, and constant additions to the
> argp/framep value.
> 
> Bootstrapped/regtested on x86_64-linux and i686-linux, on x86_64-linux
> this doesn't change anything in make check, on i686-linux fixes:
> +XPASS: gcc.dg/guality/guality.c  -O3 -fomit-frame-pointer  execution test
> -FAIL: gcc.dg/guality/pr43077-1.c  -O2  line 42 varb == 2
> -FAIL: gcc.dg/guality/pr43077-1.c  -O2  line 42 varc == 3
> -FAIL: gcc.dg/guality/pr43077-1.c  -O3 -g  line 42 varb == 2
> -FAIL: gcc.dg/guality/pr43077-1.c  -O3 -g  line 42 varc == 3
> -FAIL: gcc.dg/guality/pr43077-1.c  -Os  line 42 varb == 2
> -FAIL: gcc.dg/guality/pr43077-1.c  -Os  line 42 varc == 3
> -FAIL: gcc.dg/guality/pr43077-1.c  -O2 -flto  line 42 varb == 2
> -FAIL: gcc.dg/guality/pr43077-1.c  -O2 -flto  line 42 varc == 3
> -FAIL: gcc.dg/guality/pr43077-1.c  -O2 -fwhopr  line 42 varb == 2
> -FAIL: gcc.dg/guality/pr43077-1.c  -O2 -fwhopr  line 42 varc == 3
> -FAIL: gcc.dg/guality/vla-1.c  -O1  line 24 sizeof (a) == 17 * sizeof (short)
> -FAIL: gcc.dg/guality/vla-1.c  -O2  line 24 sizeof (a) == 17 * sizeof (short)
> -FAIL: gcc.dg/guality/vla-1.c  -O3 -fomit-frame-pointer  line 24 sizeof (a) == 17 * sizeof (short)
> -FAIL: gcc.dg/guality/vla-1.c  -O3 -g  line 24 sizeof (a) == 17 * sizeof (short)
> -FAIL: gcc.dg/guality/vla-1.c  -Os  line 24 sizeof (a) == 17 * sizeof (short)
> (and the new testcase passes on both targets).  Backport of this has been
> bootstrapped/regtested on redhat/gcc-4_4-branch on
> {x86_64,i686,ppc,ppc64,s390,s390x}-linux too.
> 
> Ok for trunk?

Ok.

Thanks,
Richard.

> 2010-03-15  Jakub Jelinek  <jakub@redhat.com>
> 
> 	PR debug/43051
> 	PR debug/43092
> 	* cselib.c (cselib_preserve_constants,
> 	cfa_base_preserved_val): New static variables.
> 	(preserve_only_constants): New function.
> 	(cselib_reset_table): If cfa_base_preserved_val is non-NULL, don't
> 	clear its REG_VALUES.  If cselib_preserve_constants, don't 
> 	empty the whole hash table, but preserve there VALUEs with constants,
> 	cfa_base_preserved_val and cfa_base_preserved_val plus constant.
> 	(cselib_preserve_cfa_base_value): New function.
> 	(cselib_invalidate_regno): Don't invalidate cfa_base_preserved_val.
> 	(cselib_init): Change argument to int bitfield.  Set
> 	cselib_preserve_constants to whether CSELIB_PRESERVE_CONSTANTS
> 	is in it.
> 	(cselib_finish): Clear cselib_preserve_constants and
> 	cfa_base_preserved_val.
> 	* cselib.h (enum cselib_record_what): New enum.
> 	(cselib_init): Change argument to int.
> 	(cselib_preserve_cfa_base_value): New prototype.
> 	* postreload.c (reload_cse_regs_1): Adjust cselib_init caller.
> 	* dse.c (dse_step1): Likewise.
> 	* cfgcleanup.c (thread_jump): Likewise.
> 	* sched-deps.c (sched_analyze): Likewise.
> 	* gcse.c (local_cprop_pass): Likewise.
> 	* simplify-rtx.c (simplify_replace_fn_rtx): Add argument to callback.
> 	If FN is non-NULL, call the callback always and whenever it returns
> 	non-NULL just return that.  Only do rtx_equal_p if FN is NULL.
> 	* rtl.h (simplify_replace_fn_rtx): Add argument to callback.
> 	* combine.c (propagate_for_debug_subst): Add old_rtx argument,
> 	compare from with old_rtx and if it isn't rtx_equal_p, return NULL.
> 	* Makefile.in (var-tracking.o): Depend on $(RECOG_H).
> 	* var-tracking.c: Include recog.h.
> 	(bb_stack_adjust_offset): Remove.
> 	(vt_stack_adjustments): Don't call it, instead just gather the
> 	adjustments using insn_stack_adjust_offset_pre_post on each bb insn.
> 	(adjust_stack_reference): Remove.
> 	(compute_cfa_pointer): New function.
> 	(hard_frame_pointer_adjustment, cfa_base_rtx): New static variables.
> 	(struct adjust_mem_data): New type.
> 	(adjust_mems, adjust_mem_uses, adjust_mem_stores, adjust_insn): New
> 	functions.
> 	(get_address_mode): New function.
> 	(replace_expr_with_values): Use it.
> 	(use_type): Don't do cselib_lookup for VAR_LOC_UNKNOWN_P.
> 	Ise get_address_mode.  For cfa_base_rtx return MO_CLOBBER.
> 	(adjust_sets): Remove.
> 	(add_uses): Don't add extra MO_VAL_USE for cfa_base_rtx plus constant.
> 	Use get_address_mode.
> 	(get_adjusted_src): Remove.
> 	(add_stores): Don't call it.  Never reuse expr SET.  Don't add extra
> 	MO_VAL_USE for cfa_base_rtx plus constant.  Use get_address_mode.
> 	(add_with_sets): Don't call adjust_sets.
> 	(fp_setter, vt_init_cfa_base): New functions.
> 	(vt_initialize): Change return type to bool.  Move most of pool etc.
> 	initialization to the beginning of the function from end.  Pass
> 	CSELIB_RECORD_MEMORY | CSELIB_PRESERVE_CONSTANTS to cselib_init.
> 	If !frame_pointer_needed, call vt_stack_adjustment before mos
> 	vector is filled, call vt_init_cfa_base if argp/framep has been
> 	eliminated to sp.  If frame_pointer_needed and argp/framep has
> 	been eliminated to hard frame pointer, set
> 	hard_frame_pointer_adjustment and call vt_init_cfa_base after
> 	encountering fp setter in the prologue.  For MO_ADJUST, call
> 	log_op_type before pusing the op into mos vector, not afterwards.
> 	Call adjust_insn before cselib_process_insn/add_with_sets,
> 	call cancel_changes (0) afterwards.
> 	(variable_tracking_main_1): Adjust for vt_initialize calling
> 	vt_stack_adjustments and returning whether it succeeded or not.
> 
> 	* gcc.dg/guality/pr43051-1.c: New test.
> 
> --- gcc/postreload.c.jj	2010-03-15 08:42:27.000000000 +0100
> +++ gcc/postreload.c	2010-03-15 08:53:32.000000000 +0100
> @@ -198,7 +198,7 @@ reload_cse_regs_1 (rtx first)
>    rtx insn;
>    rtx testreg = gen_rtx_REG (VOIDmode, -1);
>  
> -  cselib_init (true);
> +  cselib_init (CSELIB_RECORD_MEMORY);
>    init_alias_analysis ();
>  
>    for (insn = first; insn; insn = NEXT_INSN (insn))
> --- gcc/dse.c.jj	2010-03-15 08:42:27.000000000 +0100
> +++ gcc/dse.c	2010-03-15 08:53:32.000000000 +0100
> @@ -2616,7 +2616,7 @@ dse_step1 (void)
>    basic_block bb;
>    bitmap regs_live = BITMAP_ALLOC (NULL);
>  
> -  cselib_init (false);
> +  cselib_init (0);
>    all_blocks = BITMAP_ALLOC (NULL);
>    bitmap_set_bit (all_blocks, ENTRY_BLOCK);
>    bitmap_set_bit (all_blocks, EXIT_BLOCK);
> --- gcc/cfgcleanup.c.jj	2010-03-15 08:42:27.000000000 +0100
> +++ gcc/cfgcleanup.c	2010-03-15 08:53:32.000000000 +0100
> @@ -337,7 +337,7 @@ thread_jump (edge e, basic_block b)
>  	return NULL;
>        }
>  
> -  cselib_init (false);
> +  cselib_init (0);
>  
>    /* First process all values computed in the source basic block.  */
>    for (insn = NEXT_INSN (BB_HEAD (e->src));
> --- gcc/rtl.h.jj	2010-03-15 08:42:28.000000000 +0100
> +++ gcc/rtl.h	2010-03-15 08:53:32.000000000 +0100
> @@ -1778,7 +1778,7 @@ extern rtx simplify_subreg (enum machine
>  extern rtx simplify_gen_subreg (enum machine_mode, rtx, enum machine_mode,
>  				unsigned int);
>  extern rtx simplify_replace_fn_rtx (rtx, const_rtx,
> -				    rtx (*fn) (rtx, void *), void *);
> +				    rtx (*fn) (rtx, const_rtx, void *), void *);
>  extern rtx simplify_replace_rtx (rtx, const_rtx, rtx);
>  extern rtx simplify_rtx (const_rtx);
>  extern rtx avoid_constant_pool_reference (rtx);
> --- gcc/sched-deps.c.jj	2010-03-15 08:42:27.000000000 +0100
> +++ gcc/sched-deps.c	2010-03-15 08:53:32.000000000 +0100
> @@ -3383,7 +3383,7 @@ sched_analyze (struct deps *deps, rtx he
>    rtx insn;
>  
>    if (sched_deps_info->use_cselib)
> -    cselib_init (true);
> +    cselib_init (CSELIB_RECORD_MEMORY);
>  
>    deps_start_bb (deps, head);
>  
> --- gcc/combine.c.jj	2010-03-15 08:42:28.000000000 +0100
> +++ gcc/combine.c	2010-03-15 08:53:32.000000000 +0100
> @@ -2286,10 +2286,12 @@ struct rtx_subst_pair
>     substituted.  */
>  
>  static rtx
> -propagate_for_debug_subst (rtx from ATTRIBUTE_UNUSED, void *data)
> +propagate_for_debug_subst (rtx from, const_rtx old_rtx, void *data)
>  {
>    struct rtx_subst_pair *pair = (struct rtx_subst_pair *)data;
>  
> +  if (!rtx_equal_p (from, old_rtx))
> +    return NULL_RTX;
>    if (!pair->adjusted)
>      {
>        pair->adjusted = true;
> --- gcc/Makefile.in.jj	2010-03-15 08:42:33.000000000 +0100
> +++ gcc/Makefile.in	2010-03-15 08:53:32.000000000 +0100
> @@ -3032,7 +3032,8 @@ var-tracking.o : var-tracking.c $(CONFIG
>     $(RTL_H) $(TREE_H) hard-reg-set.h insn-config.h reload.h $(FLAGS_H) \
>     $(BASIC_BLOCK_H) output.h sbitmap.h alloc-pool.h $(FIBHEAP_H) $(HASHTAB_H) \
>     $(REGS_H) $(EXPR_H) $(TIMEVAR_H) $(TREE_PASS_H) $(TREE_FLOW_H) \
> -   cselib.h $(TARGET_H) $(TOPLEV_H) $(PARAMS_H) $(DIAGNOSTIC_H) pointer-set.h
> +   cselib.h $(TARGET_H) $(TOPLEV_H) $(PARAMS_H) $(DIAGNOSTIC_H) pointer-set.h \
> +   $(RECOG_H)
>  profile.o : profile.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) \
>     $(TREE_H) $(FLAGS_H) output.h $(REGS_H) $(EXPR_H) $(FUNCTION_H) \
>     $(TOPLEV_H) $(COVERAGE_H) $(TREE_FLOW_H) value-prof.h cfghooks.h \
> --- gcc/simplify-rtx.c.jj	2010-03-15 08:42:27.000000000 +0100
> +++ gcc/simplify-rtx.c	2010-03-15 08:53:32.000000000 +0100
> @@ -350,15 +350,14 @@ simplify_gen_relational (enum rtx_code c
>    return gen_rtx_fmt_ee (code, mode, op0, op1);
>  }
>  \f
> -/* Replace all occurrences of OLD_RTX in X with FN (X', DATA), where X'
> -   is an expression in X that is equal to OLD_RTX.  Canonicalize and
> -   simplify the result.
> -
> -   If FN is null, assume FN (X', DATA) == copy_rtx (DATA).  */
> +/* If FN is NULL, replace all occurrences of OLD_RTX in X with copy_rtx (DATA)
> +   and simplify the result.  If FN is non-NULL, call this callback on each
> +   X, if it returns non-NULL, replace X with its return value and simplify the
> +   result.  */
>  
>  rtx
>  simplify_replace_fn_rtx (rtx x, const_rtx old_rtx,
> -			 rtx (*fn) (rtx, void *), void *data)
> +			 rtx (*fn) (rtx, const_rtx, void *), void *data)
>  {
>    enum rtx_code code = GET_CODE (x);
>    enum machine_mode mode = GET_MODE (x);
> @@ -368,17 +367,14 @@ simplify_replace_fn_rtx (rtx x, const_rt
>    rtvec vec, newvec;
>    int i, j;
>  
> -  /* If X is OLD_RTX, return FN (X, DATA), with a null FN.  Otherwise,
> -     if this is an expression, try to build a new expression, substituting
> -     recursively.  If we can't do anything, return our input.  */
> -
> -  if (rtx_equal_p (x, old_rtx))
> +  if (__builtin_expect (fn != NULL, 0))
>      {
> -      if (fn)
> -	return fn (x, data);
> -      else
> -	return copy_rtx ((rtx) data);
> +      newx = fn (x, old_rtx, data);
> +      if (newx)
> +	return newx;
>      }
> +  else if (rtx_equal_p (x, old_rtx))
> +    return copy_rtx ((rtx) data);
>  
>    switch (GET_RTX_CLASS (code))
>      {
> --- gcc/cselib.c.jj	2010-03-15 08:42:27.000000000 +0100
> +++ gcc/cselib.c	2010-03-15 08:53:32.000000000 +0100
> @@ -45,6 +45,7 @@ along with GCC; see the file COPYING3.  
>  #include "target.h"
>  
>  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 *);
> @@ -135,6 +136,11 @@ 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;
> +
>  /* 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.  */
> @@ -229,6 +235,35 @@ cselib_clear_table (void)
>    cselib_reset_table (1);
>  }
>  
> +/* Remove from hash table all VALUEs except constants.  */
> +
> +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;
> +	}
> +    }
> +
> +  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,15 +272,37 @@ 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 = REGNO (cfa_base_preserved_val->locs->loc);
> +      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;
>  
> @@ -434,6 +491,18 @@ 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)
> +{
> +  if (cselib_preserve_constants
> +      && v->locs
> +      && REG_P (v->locs->loc))
> +    cfa_base_preserved_val = v;
> +}
> +
>  /* Clean all non-constant expressions in the hash table, but retain
>     their values.  */
>  
> @@ -1600,7 +1669,7 @@ cselib_invalidate_regno (unsigned int re
>  	  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)
>  	    {
>  	      l = &(*l)->next;
>  	      continue;
> @@ -2018,7 +2087,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 +2096,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.  */
> @@ -2061,6 +2131,8 @@ void
>  cselib_finish (void)
>  {
>    cselib_discard_hook = NULL;
> +  cselib_preserve_constants = false;
> +  cfa_base_preserved_val = NULL;
>    free_alloc_pool (elt_list_pool);
>    free_alloc_pool (elt_loc_list_pool);
>    free_alloc_pool (cselib_val_pool);
> --- gcc/gcse.c.jj	2010-03-15 08:42:27.000000000 +0100
> +++ gcc/gcse.c	2010-03-15 08:53:32.000000000 +0100
> @@ -2724,7 +2724,7 @@ local_cprop_pass (void)
>    struct reg_use *reg_used;
>    bool changed = false;
>  
> -  cselib_init (false);
> +  cselib_init (0);
>    FOR_EACH_BB (bb)
>      {
>        FOR_BB_INSNS (bb, insn)
> --- gcc/cselib.h.jj	2010-03-15 08:42:27.000000000 +0100
> +++ gcc/cselib.h	2010-03-15 08:53:32.000000000 +0100
> @@ -66,12 +66,18 @@ struct cselib_set
>    cselib_val *dest_addr_elt;
>  };
>  
> +enum cselib_record_what
> +{
> +  CSELIB_RECORD_MEMORY = 1,
> +  CSELIB_PRESERVE_CONSTANTS = 2
> +};
> +
>  extern void (*cselib_discard_hook) (cselib_val *);
>  extern void (*cselib_record_sets_hook) (rtx insn, struct cselib_set *sets,
>  					int n_sets);
>  
>  extern cselib_val *cselib_lookup (rtx, enum machine_mode, int);
> -extern void cselib_init (bool record_memory);
> +extern void cselib_init (int);
>  extern void cselib_clear_table (void);
>  extern void cselib_finish (void);
>  extern void cselib_process_insn (rtx);
> @@ -92,5 +98,6 @@ extern unsigned int cselib_get_next_uid 
>  extern void cselib_preserve_value (cselib_val *);
>  extern bool cselib_preserved_value_p (cselib_val *);
>  extern void cselib_preserve_only_values (void);
> +extern void cselib_preserve_cfa_base_value (cselib_val *);
>  
>  extern void dump_cselib_table (FILE *);
> --- gcc/testsuite/gcc.dg/guality/pr43051-1.c.jj	2010-03-15 08:53:32.000000000 +0100
> +++ gcc/testsuite/gcc.dg/guality/pr43051-1.c	2010-03-15 08:53:32.000000000 +0100
> @@ -0,0 +1,57 @@
> +/* PR debug/43051 */
> +/* { dg-do run } */
> +/* { dg-options "-g" } */
> +
> +extern void abort (void);
> +
> +static void __attribute__ ((noinline))
> +foo (const char *x, long long y, int z)
> +{
> +  asm volatile ("" : : "r" (x), "r" ((int) y), "r" (z) : "memory");
> +}
> +
> +struct S
> +{
> +  struct S *n;
> +  int v;
> +};
> +
> +struct S a[10];
> +
> +struct S * __attribute__ ((noinline))
> +bar (struct S *c, int v, struct S *e)
> +{
> +#ifdef __i386__
> +  register int si asm ("esi"), di asm ("edi"), bx
> +# if !defined (__pic__) && !defined (__APPLE__)
> +    asm ("ebx")
> +# endif
> +    ;
> +  asm volatile ("" : "=r" (si), "=r" (di), "=r" (bx));
> +#endif
> +  while (c < e)
> +    {
> +      foo ("c", (__UINTPTR_TYPE__) c, 0);	/* { dg-final { gdb-test 34 "c" "\&a\[0\]" } } */
> +      foo ("v", v, 1);				/* { dg-final { gdb-test 35 "v" "1" } } */
> +      foo ("e", (__UINTPTR_TYPE__) e, 2);	/* { dg-final { gdb-test 36 "e" "\&a\[1\]" } } */
> +      if (c->v == v)
> +	return c;
> +      foo ("c", (__UINTPTR_TYPE__) c, 3);	/* { dg-final { gdb-test 39 "c" "\&a\[0\]" } } */
> +      foo ("v", v, 4);				/* { dg-final { gdb-test 40 "v" "1" } } */
> +      foo ("e", (__UINTPTR_TYPE__) e, 5);	/* { dg-final { gdb-test 41 "e" "\&a\[1\]" } } */
> +      c++;
> +    }
> +#ifdef __i386__
> +  asm volatile ("" : : "r" (si), "r" (di), "r" (bx));
> +#endif
> +  return 0;
> +}
> +
> +int
> +main ()
> +{
> +  asm volatile ("" : : "r" (&a[0]) : "memory");
> +  if (bar (&a[a[0].v], a[0].v + 1, &a[a[0].v + 1]))
> +    abort ();
> +  return 0;
> +}
> --- gcc/var-tracking.c.jj	2010-03-15 08:42:28.000000000 +0100
> +++ gcc/var-tracking.c	2010-03-15 10:19:34.000000000 +0100
> @@ -113,6 +113,7 @@
>  #include "params.h"
>  #include "diagnostic.h"
>  #include "pointer-set.h"
> +#include "recog.h"
>  
>  /* var-tracking.c assumes that tree code with the same value as VALUE rtx code
>     has no chance to appear in REG_EXPR/MEM_EXPRs and isn't a decl.
> @@ -405,9 +406,8 @@ static void stack_adjust_offset_pre_post
>  					  HOST_WIDE_INT *);
>  static void insn_stack_adjust_offset_pre_post (rtx, HOST_WIDE_INT *,
>  					       HOST_WIDE_INT *);
> -static void bb_stack_adjust_offset (basic_block);
>  static bool vt_stack_adjustments (void);
> -static rtx adjust_stack_reference (rtx, HOST_WIDE_INT);
> +static rtx compute_cfa_pointer (HOST_WIDE_INT);
>  static hashval_t variable_htab_hash (const void *);
>  static int variable_htab_eq (const void *, const void *);
>  static void variable_htab_free (void *);
> @@ -490,7 +490,7 @@ static void vt_emit_notes (void);
>  
>  static bool vt_get_decl_and_offset (rtx, tree *, HOST_WIDE_INT *);
>  static void vt_add_function_parameters (void);
> -static void vt_initialize (void);
> +static bool vt_initialize (void);
>  static void vt_finalize (void);
>  
>  /* Given a SET, calculate the amount of stack adjustment it contains
> @@ -617,29 +617,6 @@ insn_stack_adjust_offset_pre_post (rtx i
>      }
>  }
>  
> -/* Compute stack adjustment in basic block BB.  */
> -
> -static void
> -bb_stack_adjust_offset (basic_block bb)
> -{
> -  HOST_WIDE_INT offset;
> -  unsigned int i;
> -  micro_operation *mo;
> -
> -  offset = VTI (bb)->in.stack_adjust;
> -  for (i = 0; VEC_iterate (micro_operation, VTI (bb)->mos, i, mo); i++)
> -    {
> -      if (mo->type == MO_ADJUST)
> -	offset += mo->u.adjust;
> -      else if (mo->type != MO_CALL)
> -	{
> -	  if (MEM_P (mo->u.loc))
> -	    mo->u.loc = adjust_stack_reference (mo->u.loc, -offset);
> -	}
> -    }
> -  VTI (bb)->out.stack_adjust = offset;
> -}
> -
>  /* Compute stack adjustments for all blocks by traversing DFS tree.
>     Return true when the adjustments on all incoming edges are consistent.
>     Heavily borrowed from pre_and_rev_post_order_compute.  */
> @@ -652,6 +629,7 @@ vt_stack_adjustments (void)
>  
>    /* Initialize entry block.  */
>    VTI (ENTRY_BLOCK_PTR)->visited = true;
> +  VTI (ENTRY_BLOCK_PTR)->in.stack_adjust = INCOMING_FRAME_SP_OFFSET;
>    VTI (ENTRY_BLOCK_PTR)->out.stack_adjust = INCOMING_FRAME_SP_OFFSET;
>  
>    /* Allocate stack for back-tracking up CFG.  */
> @@ -675,9 +653,22 @@ vt_stack_adjustments (void)
>        /* Check if the edge destination has been visited yet.  */
>        if (!VTI (dest)->visited)
>  	{
> +	  rtx insn;
> +	  HOST_WIDE_INT pre, post, offset;
>  	  VTI (dest)->visited = true;
> -	  VTI (dest)->in.stack_adjust = VTI (src)->out.stack_adjust;
> -	  bb_stack_adjust_offset (dest);
> +	  VTI (dest)->in.stack_adjust = offset = VTI (src)->out.stack_adjust;
> +
> +	  if (dest != EXIT_BLOCK_PTR)
> +	    for (insn = BB_HEAD (dest);
> +		 insn != NEXT_INSN (BB_END (dest));
> +		 insn = NEXT_INSN (insn))
> +	      if (INSN_P (insn))
> +		{
> +		  insn_stack_adjust_offset_pre_post (insn, &pre, &post);
> +		  offset += pre + post;
> +		}
> +
> +	  VTI (dest)->out.stack_adjust = offset;
>  
>  	  if (EDGE_COUNT (dest->succs) > 0)
>  	    /* Since the DEST node has been visited for the first
> @@ -706,13 +697,12 @@ vt_stack_adjustments (void)
>    return true;
>  }
>  
> -/* Adjust stack reference MEM by ADJUSTMENT bytes and make it relative
> -   to the argument pointer.  Return the new rtx.  */
> +/* Compute a CFA-based value for the stack pointer.  */
>  
>  static rtx
> -adjust_stack_reference (rtx mem, HOST_WIDE_INT adjustment)
> +compute_cfa_pointer (HOST_WIDE_INT adjustment)
>  {
> -  rtx addr, cfa, tmp;
> +  rtx cfa;
>  
>  #ifdef FRAME_POINTER_CFA_OFFSET
>    adjustment -= FRAME_POINTER_CFA_OFFSET (current_function_decl);
> @@ -722,12 +712,216 @@ adjust_stack_reference (rtx mem, HOST_WI
>    cfa = plus_constant (arg_pointer_rtx, adjustment);
>  #endif
>  
> -  addr = replace_rtx (copy_rtx (XEXP (mem, 0)), stack_pointer_rtx, cfa);
> -  tmp = simplify_rtx (addr);
> -  if (tmp)
> -    addr = tmp;
> +  return cfa;
> +}
> +
> +/* Adjustment for hard_frame_pointer_rtx to cfa base reg,
> +   or -1 if the replacement shouldn't be done.  */
> +static HOST_WIDE_INT hard_frame_pointer_adjustment = -1;
> +
> +/* Data for adjust_mems callback.  */
> +
> +struct adjust_mem_data
> +{
> +  bool store;
> +  enum machine_mode mem_mode;
> +  HOST_WIDE_INT stack_adjust;
> +  rtx side_effects;
> +};
> +
> +/* Helper function for adjusting used MEMs.  */
>  
> -  return replace_equiv_address_nv (mem, addr);
> +static rtx
> +adjust_mems (rtx loc, const_rtx old_rtx, void *data)
> +{
> +  struct adjust_mem_data *amd = (struct adjust_mem_data *) data;
> +  rtx mem, addr = loc, tem;
> +  enum machine_mode mem_mode_save;
> +  bool store_save;
> +  switch (GET_CODE (loc))
> +    {
> +    case REG:
> +      /* Don't do any sp or fp replacements outside of MEM addresses.  */
> +      if (amd->mem_mode == VOIDmode)
> +	return loc;
> +      if (loc == stack_pointer_rtx
> +	  && !frame_pointer_needed)
> +	return compute_cfa_pointer (amd->stack_adjust);
> +      else if (loc == hard_frame_pointer_rtx
> +	       && frame_pointer_needed
> +	       && hard_frame_pointer_adjustment != -1)
> +	return compute_cfa_pointer (hard_frame_pointer_adjustment);
> +      return loc;
> +    case MEM:
> +      mem = loc;
> +      if (!amd->store)
> +	{
> +	  mem = targetm.delegitimize_address (mem);
> +	  if (mem != loc && !MEM_P (mem))
> +	    return simplify_replace_fn_rtx (mem, old_rtx, adjust_mems, data);
> +	}
> +
> +      addr = XEXP (mem, 0);
> +      mem_mode_save = amd->mem_mode;
> +      amd->mem_mode = GET_MODE (mem);
> +      store_save = amd->store;
> +      amd->store = false;
> +      addr = simplify_replace_fn_rtx (addr, old_rtx, adjust_mems, data);
> +      amd->store = store_save;
> +      amd->mem_mode = mem_mode_save;
> +      if (mem == loc)
> +	addr = targetm.delegitimize_address (addr);
> +      if (addr != XEXP (mem, 0))
> +	mem = replace_equiv_address_nv (mem, addr);
> +      if (!amd->store)
> +	mem = avoid_constant_pool_reference (mem);
> +      return mem;
> +    case PRE_INC:
> +    case PRE_DEC:
> +      addr = gen_rtx_PLUS (GET_MODE (loc), XEXP (loc, 0),
> +			   GEN_INT (GET_CODE (loc) == PRE_INC
> +				    ? GET_MODE_SIZE (amd->mem_mode)
> +				    : -GET_MODE_SIZE (amd->mem_mode)));
> +    case POST_INC:
> +    case POST_DEC:
> +      if (addr == loc)
> +	addr = XEXP (loc, 0);
> +      gcc_assert (amd->mem_mode != VOIDmode && amd->mem_mode != BLKmode);
> +      addr = simplify_replace_fn_rtx (addr, old_rtx, adjust_mems, data);
> +      tem = gen_rtx_PLUS (GET_MODE (loc), XEXP (loc, 0),
> +			   GEN_INT ((GET_CODE (loc) == PRE_INC
> +				     || GET_CODE (loc) == POST_INC)
> +				    ? GET_MODE_SIZE (amd->mem_mode)
> +				    : -GET_MODE_SIZE (amd->mem_mode)));
> +      amd->side_effects = alloc_EXPR_LIST (0,
> +					   gen_rtx_SET (VOIDmode,
> +							XEXP (loc, 0),
> +							tem),
> +					   amd->side_effects);
> +      return addr;
> +    case PRE_MODIFY:
> +      addr = XEXP (loc, 1);
> +    case POST_MODIFY:
> +      if (addr == loc)
> +	addr = XEXP (loc, 0);
> +      gcc_assert (amd->mem_mode != VOIDmode && amd->mem_mode != BLKmode);
> +      addr = simplify_replace_fn_rtx (addr, old_rtx, adjust_mems, data);
> +      amd->side_effects = alloc_EXPR_LIST (0,
> +					   gen_rtx_SET (VOIDmode,
> +							XEXP (loc, 0),
> +							XEXP (loc, 1)),
> +					   amd->side_effects);
> +      return addr;
> +    case SUBREG:
> +      /* First try without delegitimization of whole MEMs and
> +	 avoid_constant_pool_reference, which is more likely to succeed.  */
> +      store_save = amd->store;
> +      amd->store = true;
> +      addr = simplify_replace_fn_rtx (SUBREG_REG (loc), old_rtx, adjust_mems,
> +				      data);
> +      amd->store = store_save;
> +      mem = simplify_replace_fn_rtx (addr, old_rtx, adjust_mems, data);
> +      if (mem == SUBREG_REG (loc))
> +	return loc;
> +      tem = simplify_gen_subreg (GET_MODE (loc), mem,
> +				 GET_MODE (SUBREG_REG (loc)),
> +				 SUBREG_BYTE (loc));
> +      if (tem)
> +	return tem;
> +      tem = simplify_gen_subreg (GET_MODE (loc), addr,
> +				 GET_MODE (SUBREG_REG (loc)),
> +				 SUBREG_BYTE (loc));
> +      if (tem)
> +	return tem;
> +      return gen_rtx_raw_SUBREG (GET_MODE (loc), addr, SUBREG_BYTE (loc));
> +    default:
> +      break;
> +    }
> +  return NULL_RTX;
> +}
> +
> +/* Helper function for replacement of uses.  */
> +
> +static void
> +adjust_mem_uses (rtx *x, void *data)
> +{
> +  rtx new_x = simplify_replace_fn_rtx (*x, NULL_RTX, adjust_mems, data);
> +  if (new_x != *x)
> +    validate_change (NULL_RTX, x, new_x, true);
> +}
> +
> +/* Helper function for replacement of stores.  */
> +
> +static void
> +adjust_mem_stores (rtx loc, const_rtx expr, void *data)
> +{
> +  if (MEM_P (loc))
> +    {
> +      rtx new_dest = simplify_replace_fn_rtx (SET_DEST (expr), NULL_RTX,
> +					      adjust_mems, data);
> +      if (new_dest != SET_DEST (expr))
> +	{
> +	  rtx xexpr = CONST_CAST_RTX (expr);
> +	  validate_change (NULL_RTX, &SET_DEST (xexpr), new_dest, true);
> +	}
> +    }
> +}
> +
> +/* Simplify INSN.  Remove all {PRE,POST}_{INC,DEC,MODIFY} rtxes,
> +   replace them with their value in the insn and add the side-effects
> +   as other sets to the insn.  */
> +
> +static void
> +adjust_insn (basic_block bb, rtx insn)
> +{
> +  struct adjust_mem_data amd;
> +  rtx set;
> +  amd.mem_mode = VOIDmode;
> +  amd.stack_adjust = -VTI (bb)->out.stack_adjust;
> +  amd.side_effects = NULL_RTX;
> +
> +  amd.store = true;
> +  note_stores (PATTERN (insn), adjust_mem_stores, &amd);
> +
> +  amd.store = false;
> +  note_uses (&PATTERN (insn), adjust_mem_uses, &amd);
> +
> +  /* For read-only MEMs containing some constant, prefer those
> +     constants.  */
> +  set = single_set (insn);
> +  if (set && MEM_P (SET_SRC (set)) && MEM_READONLY_P (SET_SRC (set)))
> +    {
> +      rtx note = find_reg_equal_equiv_note (insn);
> +
> +      if (note && CONSTANT_P (XEXP (note, 0)))
> +	validate_change (NULL_RTX, &SET_SRC (set), XEXP (note, 0), true);
> +    }
> +
> +  if (amd.side_effects)
> +    {
> +      rtx *pat, new_pat, s;
> +      int i, oldn, newn;
> +
> +      pat = &PATTERN (insn);
> +      if (GET_CODE (*pat) == COND_EXEC)
> +	pat = &COND_EXEC_CODE (*pat);
> +      if (GET_CODE (*pat) == PARALLEL)
> +	oldn = XVECLEN (*pat, 0);
> +      else
> +	oldn = 1;
> +      for (s = amd.side_effects, newn = 0; s; newn++)
> +	s = XEXP (s, 1);
> +      new_pat = gen_rtx_PARALLEL (VOIDmode, rtvec_alloc (oldn + newn));
> +      if (GET_CODE (*pat) == PARALLEL)
> +	for (i = 0; i < oldn; i++)
> +	  XVECEXP (new_pat, 0, i) = XVECEXP (*pat, 0, i);
> +      else
> +	XVECEXP (new_pat, 0, 0) = *pat;
> +      for (s = amd.side_effects, i = oldn; i < oldn + newn; i++, s = XEXP (s, 1))
> +	XVECEXP (new_pat, 0, i) = XEXP (s, 0);
> +      free_EXPR_LIST_list (&amd.side_effects);
> +      validate_change (NULL_RTX, pat, new_pat, true);
> +    }
>  }
>  
>  /* Return true if a decl_or_value DV is a DECL or NULL.  */
> @@ -4326,6 +4520,10 @@ var_lowpart (enum machine_mode mode, rtx
>    return gen_rtx_REG_offset (loc, mode, regno, offset);
>  }
>  
> +/* arg_pointer_rtx resp. frame_pointer_rtx if stack_pointer_rtx or
> +   hard_frame_pointer_rtx is being mapped to it.  */
> +static rtx cfa_base_rtx;
> +
>  /* Carry information about uses and stores while walking rtx.  */
>  
>  struct count_use_info
> @@ -4371,6 +4569,17 @@ find_use_val (rtx x, enum machine_mode m
>    return NULL;
>  }
>  
> +/* Helper function to get mode of MEM's address.  */
> +
> +static inline enum machine_mode
> +get_address_mode (rtx mem)
> +{
> +  enum machine_mode mode = GET_MODE (XEXP (mem, 0));
> +  if (mode != VOIDmode)
> +    return mode;
> +  return targetm.addr_space.address_mode (MEM_ADDR_SPACE (mem));
> +}
> +
>  /* Replace all registers and addresses in an expression with VALUE
>     expressions that map back to them, unless the expression is a
>     register.  If no mapping is or can be performed, returns NULL.  */
> @@ -4382,9 +4591,8 @@ replace_expr_with_values (rtx loc)
>      return NULL;
>    else if (MEM_P (loc))
>      {
> -      enum machine_mode address_mode
> -	= targetm.addr_space.address_mode (MEM_ADDR_SPACE (loc));
> -      cselib_val *addr = cselib_lookup (XEXP (loc, 0), address_mode, 0);
> +      cselib_val *addr = cselib_lookup (XEXP (loc, 0),
> +					get_address_mode (loc), 0);
>        if (addr)
>  	return replace_equiv_address_nv (loc, addr->val_rtx);
>        else
> @@ -4409,12 +4617,15 @@ use_type (rtx loc, struct count_use_info
>  	  if (track_expr_p (PAT_VAR_LOCATION_DECL (loc), false))
>  	    {
>  	      rtx ploc = PAT_VAR_LOCATION_LOC (loc);
> -	      cselib_val *val = cselib_lookup (ploc, GET_MODE (loc), 1);
> +	      if (! VAR_LOC_UNKNOWN_P (ploc))
> +		{
> +		  cselib_val *val = cselib_lookup (ploc, GET_MODE (loc), 1);
>  
> -	      /* ??? flag_float_store and volatile mems are never
> -		 given values, but we could in theory use them for
> -		 locations.  */
> -	      gcc_assert (val || 1);
> +		  /* ??? flag_float_store and volatile mems are never
> +		     given values, but we could in theory use them for
> +		     locations.  */
> +		  gcc_assert (val || 1);
> +		}
>  	      return MO_VAL_LOC;
>  	    }
>  	  else
> @@ -4429,7 +4640,8 @@ use_type (rtx loc, struct count_use_info
>  	    {
>  	      if (REG_P (loc)
>  		  || (find_use_val (loc, GET_MODE (loc), cui)
> -		      && cselib_lookup (XEXP (loc, 0), GET_MODE (loc), 0)))
> +		      && cselib_lookup (XEXP (loc, 0),
> +					get_address_mode (loc), 0)))
>  		return MO_VAL_SET;
>  	    }
>  	  else
> @@ -4446,6 +4658,8 @@ use_type (rtx loc, struct count_use_info
>      {
>        gcc_assert (REGNO (loc) < FIRST_PSEUDO_REGISTER);
>  
> +      if (loc == cfa_base_rtx)
> +	return MO_CLOBBER;
>        expr = REG_EXPR (loc);
>  
>        if (!expr)
> @@ -4490,30 +4704,6 @@ log_op_type (rtx x, basic_block bb, rtx 
>    fputc ('\n', out);
>  }
>  
> -/* Adjust sets if needed.  Currently this optimizes read-only MEM loads
> -   if REG_EQUAL/REG_EQUIV note is present.  */
> -
> -static void
> -adjust_sets (rtx insn, struct cselib_set *sets, int n_sets)
> -{
> -  if (n_sets == 1 && MEM_P (sets[0].src) && MEM_READONLY_P (sets[0].src))
> -    {
> -      /* For read-only MEMs containing some constant, prefer those
> -	 constants.  */
> -      rtx note = find_reg_equal_equiv_note (insn), src;
> -
> -      if (note && CONSTANT_P (XEXP (note, 0)))
> -	{
> -	  sets[0].src = src = XEXP (note, 0);
> -	  if (GET_CODE (PATTERN (insn)) == COND_EXEC)
> -	    src = gen_rtx_IF_THEN_ELSE (GET_MODE (sets[0].dest),
> -					COND_EXEC_TEST (PATTERN (insn)),
> -					src, sets[0].dest);
> -	  sets[0].src_elt = cselib_lookup (src, GET_MODE (sets[0].dest), 1);
> -	}
> -    }
> -}
> -
>  /* Tell whether the CONCAT used to holds a VALUE and its location
>     needs value resolution, i.e., an attempt of mapping the location
>     back to other incoming values.  */
> @@ -4577,11 +4767,14 @@ add_uses (rtx *ploc, void *data)
>  	  gcc_assert (cui->sets);
>  
>  	  if (MEM_P (vloc)
> -	      && !REG_P (XEXP (vloc, 0)) && !MEM_P (XEXP (vloc, 0)))
> +	      && !REG_P (XEXP (vloc, 0))
> +	      && !MEM_P (XEXP (vloc, 0))
> +	      && (GET_CODE (XEXP (vloc, 0)) != PLUS
> +		  || XEXP (XEXP (vloc, 0), 0) != cfa_base_rtx
> +		  || !CONST_INT_P (XEXP (XEXP (vloc, 0), 1))))
>  	    {
>  	      rtx mloc = vloc;
> -	      enum machine_mode address_mode
> -		= targetm.addr_space.address_mode (MEM_ADDR_SPACE (mloc));
> +	      enum machine_mode address_mode = get_address_mode (mloc);
>  	      cselib_val *val
>  		= cselib_lookup (XEXP (mloc, 0), address_mode, 0);
>  
> @@ -4646,11 +4839,14 @@ add_uses (rtx *ploc, void *data)
>  	  gcc_assert (cui->sets);
>  
>  	  if (MEM_P (oloc)
> -	      && !REG_P (XEXP (oloc, 0)) && !MEM_P (XEXP (oloc, 0)))
> +	      && !REG_P (XEXP (oloc, 0))
> +	      && !MEM_P (XEXP (oloc, 0))
> +	      && (GET_CODE (XEXP (oloc, 0)) != PLUS
> +		  || XEXP (XEXP (oloc, 0), 0) != cfa_base_rtx
> +		  || !CONST_INT_P (XEXP (XEXP (oloc, 0), 1))))
>  	    {
>  	      rtx mloc = oloc;
> -	      enum machine_mode address_mode
> -		= targetm.addr_space.address_mode (MEM_ADDR_SPACE (mloc));
> +	      enum machine_mode address_mode = get_address_mode (mloc);
>  	      cselib_val *val
>  		= cselib_lookup (XEXP (mloc, 0), address_mode, 0);
>  
> @@ -4814,21 +5010,6 @@ reverse_op (rtx val, const_rtx expr)
>    return gen_rtx_CONCAT (GET_MODE (v->val_rtx), v->val_rtx, ret);
>  }
>  
> -/* Return SRC, or, if it is a read-only MEM for which adjust_sets
> -   replated it with a constant from REG_EQUIV/REG_EQUAL note,
> -   that constant.  */
> -
> -static inline rtx
> -get_adjusted_src (struct count_use_info *cui, rtx src)
> -{
> -  if (cui->n_sets == 1
> -      && MEM_P (src)
> -      && MEM_READONLY_P (src)
> -      && CONSTANT_P (cui->sets[0].src))
> -    return cui->sets[0].src;
> -  return src;
> -}
> -
>  /* Add stores (register and memory references) LOC which will be tracked
>     to VTI (bb)->mos.  EXPR is the RTL expression containing the store.
>     CUIP->insn is instruction which the LOC is part of.  */
> @@ -4854,6 +5035,7 @@ add_stores (rtx loc, const_rtx expr, voi
>  
>    if (REG_P (loc))
>      {
> +      gcc_assert (loc != cfa_base_rtx);
>        if ((GET_CODE (expr) == CLOBBER && type != MO_VAL_SET)
>  	  || !(track_p = use_type (loc, NULL, &mode2) == MO_USE)
>  	  || GET_CODE (expr) == CLOBBER)
> @@ -4864,10 +5046,7 @@ add_stores (rtx loc, const_rtx expr, voi
>        else
>  	{
>  	  if (GET_CODE (expr) == SET && SET_DEST (expr) == loc)
> -	    {
> -	      src = get_adjusted_src (cui, SET_SRC (expr));
> -	      src = var_lowpart (mode2, src);
> -	    }
> +	    src = var_lowpart (mode2, SET_SRC (expr));
>  	  loc = var_lowpart (mode2, loc);
>  
>  	  if (src == NULL)
> @@ -4877,10 +5056,7 @@ add_stores (rtx loc, const_rtx expr, voi
>  	    }
>  	  else
>  	    {
> -	      rtx xexpr = CONST_CAST_RTX (expr);
> -
> -	      if (SET_SRC (expr) != src)
> -		xexpr = gen_rtx_SET (VOIDmode, loc, src);
> +	      rtx xexpr = gen_rtx_SET (VOIDmode, loc, src);
>  	      if (same_variable_part_p (src, REG_EXPR (loc), REG_OFFSET (loc)))
>  		mo.type = MO_COPY;
>  	      else
> @@ -4895,12 +5071,16 @@ add_stores (rtx loc, const_rtx expr, voi
>  	       || cui->sets))
>      {
>        if (MEM_P (loc) && type == MO_VAL_SET
> -	  && !REG_P (XEXP (loc, 0)) && !MEM_P (XEXP (loc, 0)))
> +	  && !REG_P (XEXP (loc, 0))
> +	  && !MEM_P (XEXP (loc, 0))
> +	  && (GET_CODE (XEXP (loc, 0)) != PLUS
> +	      || XEXP (XEXP (loc, 0), 0) != cfa_base_rtx
> +	      || !CONST_INT_P (XEXP (XEXP (loc, 0), 1))))
>  	{
>  	  rtx mloc = loc;
> -	  enum machine_mode address_mode
> -	    = targetm.addr_space.address_mode (MEM_ADDR_SPACE (mloc));
> -	  cselib_val *val = cselib_lookup (XEXP (mloc, 0), address_mode, 0);
> +	  enum machine_mode address_mode = get_address_mode (mloc);
> +	  cselib_val *val = cselib_lookup (XEXP (mloc, 0),
> +					   address_mode, 0);
>  
>  	  if (val && !cselib_preserved_value_p (val))
>  	    {
> @@ -4924,10 +5104,7 @@ add_stores (rtx loc, const_rtx expr, voi
>        else
>  	{
>  	  if (GET_CODE (expr) == SET && SET_DEST (expr) == loc)
> -	    {
> -	      src = get_adjusted_src (cui, SET_SRC (expr));
> -	      src = var_lowpart (mode2, src);
> -	    }
> +	    src = var_lowpart (mode2, SET_SRC (expr));
>  	  loc = var_lowpart (mode2, loc);
>  
>  	  if (src == NULL)
> @@ -4937,10 +5114,7 @@ add_stores (rtx loc, const_rtx expr, voi
>  	    }
>  	  else
>  	    {
> -	      rtx xexpr = CONST_CAST_RTX (expr);
> -
> -	      if (SET_SRC (expr) != src)
> -		xexpr = gen_rtx_SET (VOIDmode, loc, src);
> +	      rtx xexpr = gen_rtx_SET (VOIDmode, loc, src);
>  	      if (same_variable_part_p (SET_SRC (xexpr),
>  					MEM_EXPR (loc),
>  					INT_MEM_OFFSET (loc)))
> @@ -4997,13 +5171,12 @@ add_stores (rtx loc, const_rtx expr, voi
>      }
>    else if (resolve && GET_CODE (mo.u.loc) == SET)
>      {
> -      src = get_adjusted_src (cui, SET_SRC (expr));
> -      nloc = replace_expr_with_values (src);
> +      nloc = replace_expr_with_values (SET_SRC (expr));
>  
>        /* Avoid the mode mismatch between oexpr and expr.  */
>        if (!nloc && mode != mode2)
>  	{
> -	  nloc = src;
> +	  nloc = SET_SRC (expr);
>  	  gcc_assert (oloc == SET_DEST (expr));
>  	}
>  
> @@ -5102,8 +5275,6 @@ add_with_sets (rtx insn, struct cselib_s
>  
>    cselib_hook_called = true;
>  
> -  adjust_sets (insn, sets, n_sets);
> -
>    cui.insn = insn;
>    cui.bb = bb;
>    cui.sets = sets;
> @@ -6690,7 +6861,7 @@ emit_note_insn_var_location (void **varp
>    complete = true;
>    last_limit = 0;
>    n_var_parts = 0;
> -  if (!MAY_HAVE_DEBUG_STMTS)
> +  if (!MAY_HAVE_DEBUG_INSNS)
>      {
>        for (i = 0; i < var->n_var_parts; i++)
>  	if (var->var_part[i].cur_loc == NULL && var->var_part[i].loc_chain)
> @@ -7688,19 +7859,109 @@ vt_add_function_parameters (void)
>  
>  }
>  
> +/* Return true if INSN in the prologue initializes hard_frame_pointer_rtx.  */
> +
> +static bool
> +fp_setter (rtx insn)
> +{
> +  rtx pat = PATTERN (insn);
> +  if (RTX_FRAME_RELATED_P (insn))
> +    {
> +      rtx expr = find_reg_note (insn, REG_FRAME_RELATED_EXPR, NULL_RTX);
> +      if (expr)
> +	pat = XEXP (expr, 0);
> +    }
> +  if (GET_CODE (pat) == SET)
> +    return SET_DEST (pat) == hard_frame_pointer_rtx;
> +  else if (GET_CODE (pat) == PARALLEL)
> +    {
> +      int i;
> +      for (i = XVECLEN (pat, 0) - 1; i >= 0; i--)
> +	if (GET_CODE (XVECEXP (pat, 0, i)) == SET
> +	    && SET_DEST (XVECEXP (pat, 0, i)) == hard_frame_pointer_rtx)
> +	  return true;
> +    }
> +  return false;
> +}
> +
> +/* Initialize cfa_base_rtx, create a preserved VALUE for it and
> +   ensure it isn't flushed during cselib_reset_table.
> +   Can be called only if frame_pointer_rtx resp. arg_pointer_rtx
> +   has been eliminated.  */
> +
> +static void
> +vt_init_cfa_base (void)
> +{
> +  cselib_val *val;
> +
> +#ifdef FRAME_POINTER_CFA_OFFSET
> +  cfa_base_rtx = frame_pointer_rtx;
> +#else
> +  cfa_base_rtx = arg_pointer_rtx;
> +#endif
> +  if (!MAY_HAVE_DEBUG_INSNS)
> +    return;
> +
> +  val = cselib_lookup (cfa_base_rtx, GET_MODE (cfa_base_rtx), 1);
> +  preserve_value (val);
> +  cselib_preserve_cfa_base_value (val);
> +  val->locs->setting_insn = get_insns ();
> +  var_reg_decl_set (&VTI (ENTRY_BLOCK_PTR)->out, cfa_base_rtx,
> +		    VAR_INIT_STATUS_INITIALIZED, dv_from_value (val->val_rtx),
> +		    0, NULL_RTX, INSERT);
> +}
> +
>  /* Allocate and initialize the data structures for variable tracking
>     and parse the RTL to get the micro operations.  */
>  
> -static void
> +static bool
>  vt_initialize (void)
>  {
> -  basic_block bb;
> +  basic_block bb, prologue_bb = NULL;
> +  HOST_WIDE_INT fp_cfa_offset = -1;
>  
>    alloc_aux_for_blocks (sizeof (struct variable_tracking_info_def));
>  
> +  attrs_pool = create_alloc_pool ("attrs_def pool",
> +				  sizeof (struct attrs_def), 1024);
> +  var_pool = create_alloc_pool ("variable_def pool",
> +				sizeof (struct variable_def)
> +				+ (MAX_VAR_PARTS - 1)
> +				* sizeof (((variable)NULL)->var_part[0]), 64);
> +  loc_chain_pool = create_alloc_pool ("location_chain_def pool",
> +				      sizeof (struct location_chain_def),
> +				      1024);
> +  shared_hash_pool = create_alloc_pool ("shared_hash_def pool",
> +					sizeof (struct shared_hash_def), 256);
> +  empty_shared_hash = (shared_hash) pool_alloc (shared_hash_pool);
> +  empty_shared_hash->refcount = 1;
> +  empty_shared_hash->htab
> +    = htab_create (1, variable_htab_hash, variable_htab_eq,
> +		   variable_htab_free);
> +  changed_variables = htab_create (10, variable_htab_hash, variable_htab_eq,
> +				   variable_htab_free);
>    if (MAY_HAVE_DEBUG_INSNS)
>      {
> -      cselib_init (true);
> +      value_chain_pool = create_alloc_pool ("value_chain_def pool",
> +					    sizeof (struct value_chain_def),
> +					    1024);
> +      value_chains = htab_create (32, value_chain_htab_hash,
> +				  value_chain_htab_eq, NULL);
> +    }
> +
> +  /* Init the IN and OUT sets.  */
> +  FOR_ALL_BB (bb)
> +    {
> +      VTI (bb)->visited = false;
> +      VTI (bb)->flooded = false;
> +      dataflow_set_init (&VTI (bb)->in);
> +      dataflow_set_init (&VTI (bb)->out);
> +      VTI (bb)->permp = NULL;
> +    }
> +
> +  if (MAY_HAVE_DEBUG_INSNS)
> +    {
> +      cselib_init (CSELIB_RECORD_MEMORY | CSELIB_PRESERVE_CONSTANTS);
>        scratch_regs = BITMAP_ALLOC (NULL);
>        valvar_pool = create_alloc_pool ("small variable_def pool",
>  				       sizeof (struct variable_def), 256);
> @@ -7712,6 +7973,55 @@ vt_initialize (void)
>        valvar_pool = NULL;
>      }
>  
> +  if (!frame_pointer_needed)
> +    {
> +      rtx reg, elim;
> +
> +      if (!vt_stack_adjustments ())
> +	return false;
> +
> +#ifdef FRAME_POINTER_CFA_OFFSET
> +      reg = frame_pointer_rtx;
> +#else
> +      reg = arg_pointer_rtx;
> +#endif
> +      elim = eliminate_regs (reg, VOIDmode, NULL_RTX);
> +      if (elim != reg)
> +	{
> +	  if (GET_CODE (elim) == PLUS)
> +	    elim = XEXP (elim, 0);
> +	  if (elim == stack_pointer_rtx)
> +	    vt_init_cfa_base ();
> +	}
> +    }
> +  else if (!crtl->stack_realign_tried)
> +    {
> +      rtx reg, elim;
> +
> +#ifdef FRAME_POINTER_CFA_OFFSET
> +      reg = frame_pointer_rtx;
> +      fp_cfa_offset = FRAME_POINTER_CFA_OFFSET (current_function_decl);
> +#else
> +      reg = arg_pointer_rtx;
> +      fp_cfa_offset = ARG_POINTER_CFA_OFFSET (current_function_decl);
> +#endif
> +      elim = eliminate_regs (reg, VOIDmode, NULL_RTX);
> +      if (elim != reg)
> +	{
> +	  if (GET_CODE (elim) == PLUS)
> +	    {
> +	      fp_cfa_offset -= INTVAL (XEXP (elim, 1));
> +	      elim = XEXP (elim, 0);
> +	    }
> +	  if (elim != hard_frame_pointer_rtx)
> +	    fp_cfa_offset = -1;
> +	  else
> +	    prologue_bb = single_succ (ENTRY_BLOCK_PTR);
> +	}
> +    }
> +
> +  hard_frame_pointer_adjustment = -1;
> +
>    FOR_EACH_BB (bb)
>      {
>        rtx insn;
> @@ -7743,6 +8053,8 @@ vt_initialize (void)
>        /* Add the micro-operations to the vector.  */
>        FOR_BB_BETWEEN (bb, first_bb, last_bb->next_bb, next_bb)
>  	{
> +	  HOST_WIDE_INT offset = VTI (bb)->out.stack_adjust;
> +	  VTI (bb)->out.stack_adjust = VTI (bb)->in.stack_adjust;
>  	  for (insn = BB_HEAD (bb); insn != NEXT_INSN (BB_END (bb));
>  	       insn = NEXT_INSN (insn))
>  	    {
> @@ -7757,16 +8069,17 @@ vt_initialize (void)
>  			  mo.type = MO_ADJUST;
>  			  mo.u.adjust = pre;
>  			  mo.insn = insn;
> -			  VEC_safe_push (micro_operation, heap, VTI (bb)->mos,
> -					 &mo);
> -
>  			  if (dump_file && (dump_flags & TDF_DETAILS))
>  			    log_op_type (PATTERN (insn), bb, insn,
>  					 MO_ADJUST, dump_file);
> +			  VEC_safe_push (micro_operation, heap, VTI (bb)->mos,
> +					 &mo);
> +			  VTI (bb)->out.stack_adjust += pre;
>  			}
>  		    }
>  
>  		  cselib_hook_called = false;
> +		  adjust_insn (bb, insn);
>  		  if (MAY_HAVE_DEBUG_INSNS)
>  		    {
>  		      cselib_process_insn (insn);
> @@ -7778,6 +8091,7 @@ vt_initialize (void)
>  		    }
>  		  if (!cselib_hook_called)
>  		    add_with_sets (insn, 0, 0);
> +		  cancel_changes (0);
>  
>  		  if (!frame_pointer_needed && post)
>  		    {
> @@ -7785,15 +8099,25 @@ vt_initialize (void)
>  		      mo.type = MO_ADJUST;
>  		      mo.u.adjust = post;
>  		      mo.insn = insn;
> -		      VEC_safe_push (micro_operation, heap, VTI (bb)->mos,
> -				     &mo);
> -
>  		      if (dump_file && (dump_flags & TDF_DETAILS))
>  			log_op_type (PATTERN (insn), bb, insn,
>  				     MO_ADJUST, dump_file);
> +		      VEC_safe_push (micro_operation, heap, VTI (bb)->mos,
> +				     &mo);
> +		      VTI (bb)->out.stack_adjust += post;
> +		    }
> +
> +		  if (bb == prologue_bb
> +		      && hard_frame_pointer_adjustment == -1
> +		      && RTX_FRAME_RELATED_P (insn)
> +		      && fp_setter (insn))
> +		    {
> +		      vt_init_cfa_base ();
> +		      hard_frame_pointer_adjustment = fp_cfa_offset;
>  		    }
>  		}
>  	    }
> +	  gcc_assert (offset == VTI (bb)->out.stack_adjust);
>  	}
>  
>        bb = last_bb;
> @@ -7806,45 +8130,11 @@ vt_initialize (void)
>  	}
>      }
>  
> -  attrs_pool = create_alloc_pool ("attrs_def pool",
> -				  sizeof (struct attrs_def), 1024);
> -  var_pool = create_alloc_pool ("variable_def pool",
> -				sizeof (struct variable_def)
> -				+ (MAX_VAR_PARTS - 1)
> -				* sizeof (((variable)NULL)->var_part[0]), 64);
> -  loc_chain_pool = create_alloc_pool ("location_chain_def pool",
> -				      sizeof (struct location_chain_def),
> -				      1024);
> -  shared_hash_pool = create_alloc_pool ("shared_hash_def pool",
> -					sizeof (struct shared_hash_def), 256);
> -  empty_shared_hash = (shared_hash) pool_alloc (shared_hash_pool);
> -  empty_shared_hash->refcount = 1;
> -  empty_shared_hash->htab
> -    = htab_create (1, variable_htab_hash, variable_htab_eq,
> -		   variable_htab_free);
> -  changed_variables = htab_create (10, variable_htab_hash, variable_htab_eq,
> -				   variable_htab_free);
> -  if (MAY_HAVE_DEBUG_INSNS)
> -    {
> -      value_chain_pool = create_alloc_pool ("value_chain_def pool",
> -					    sizeof (struct value_chain_def),
> -					    1024);
> -      value_chains = htab_create (32, value_chain_htab_hash,
> -				  value_chain_htab_eq, NULL);
> -    }
> -
> -  /* Init the IN and OUT sets.  */
> -  FOR_ALL_BB (bb)
> -    {
> -      VTI (bb)->visited = false;
> -      VTI (bb)->flooded = false;
> -      dataflow_set_init (&VTI (bb)->in);
> -      dataflow_set_init (&VTI (bb)->out);
> -      VTI (bb)->permp = NULL;
> -    }
> -
> +  hard_frame_pointer_adjustment = -1;
>    VTI (ENTRY_BLOCK_PTR)->flooded = true;
>    vt_add_function_parameters ();
> +  cfa_base_rtx = NULL_RTX;
> +  return true;
>  }
>  
>  /* Get rid of all debug insns from the insn stream.  */
> @@ -7946,15 +8236,11 @@ variable_tracking_main_1 (void)
>      }
>  
>    mark_dfs_back_edges ();
> -  vt_initialize ();
> -  if (!frame_pointer_needed)
> +  if (!vt_initialize ())
>      {
> -      if (!vt_stack_adjustments ())
> -	{
> -	  vt_finalize ();
> -	  vt_debug_insns_local (true);
> -	  return 0;
> -	}
> +      vt_finalize ();
> +      vt_debug_insns_local (true);
> +      return 0;
>      }
>  
>    success = vt_find_locations ();
> @@ -7968,10 +8254,8 @@ variable_tracking_main_1 (void)
>        /* This is later restored by our caller.  */
>        flag_var_tracking_assignments = 0;
>  
> -      vt_initialize ();
> -
> -      if (!frame_pointer_needed && !vt_stack_adjustments ())
> -	gcc_unreachable ();
> +      success = vt_initialize ();
> +      gcc_assert (success);
>  
>        success = vt_find_locations ();
>      }
> 
> 	Jakub
> 
> 

-- 
Richard Guenther <rguenther@suse.de>
Novell / SUSE Labs
SUSE LINUX Products GmbH - Nuernberg - AG Nuernberg - HRB 16746 - GF: Markus Rex

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH] Fix VTA sp (and fp) based MEM handling (PR debug/43051, PR  debug/43092)
  2010-03-15 13:16 [PATCH] Fix VTA sp (and fp) based MEM handling (PR debug/43051, PR debug/43092) Jakub Jelinek
  2010-03-16 10:51 ` Richard Guenther
@ 2010-03-23  8:52 ` Alexandre Oliva
  2010-09-11  1:17   ` Alexandre Oliva
  1 sibling, 1 reply; 10+ messages in thread
From: Alexandre Oliva @ 2010-03-23  8:52 UTC (permalink / raw)
  To: Jakub Jelinek; +Cc: Richard Guenther, gcc-patches

[-- Attachment #1: Type: text/plain, Size: 356 bytes --]

On Mar 15, 2010, Jakub Jelinek <jakub@redhat.com> wrote:

> One is that cselib doesn't handle autoinc rtls well
> (Alex has a follow-up patch in which it teaches cselib about these; this
> final version of the patch doesn't need it for var-tracking though).

Here it is.  Regstraped on x86_64-linux-gnu, i686-linux-gnu and
ia64-linux-gnu.  Ok to install?


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: vta-cselib-autoinc-pr43092.patch --]
[-- Type: text/x-diff, Size: 30230 bytes --]

for  gcc/ChangeLog
from  Alexandre Oliva  <aoliva@redhat.com>

	* rtl.h (for_each_inc_dec_fn): New type.
	(for_each_inc_dec): Declare.
	* rtlanal.c (struct for_each_inc_dec_ops): New type.
	(for_each_inc_dec_find_inc_dec): New fn.
	(for_each_inc_dec_find_mem): New fn.
	(for_each_inc_dec): New fn.
	* dse.c (struct insn_size): Remove.
	(replace_inc_dec, replace_inc_dec_mem): Remove.
	(emit_inc_dec_insn_before): New fn.
	(check_for_inc_dec): Use it, along with for_each_inc_dec.
	* cselib.h (CSELIB_RECORD_AUTOINC): New enumerator.
	(cselib_lookup_addr): Declare.
	(cselib_lookup): Replace with macro.
	(cselib_subst_to_values_addr): Declare.
	(cselib_subst_to_values): Replace with macro.
	* cselib.c (cselib_record_autoinc): New var.
	(find_slot_memmode): New var.
	(cselib_find_slot): New fn.  Use it instead of
	htab_find_slot_with_hash everywhere.
	(entry_and_rtx_equal_p): Use find_slot_memmode.
	(autoinc_split): New fn.
	(rtx_equal_for_cselib_p): Rename and implement in terms of...
	(rtx_equal_for_cselib_1): ... this.  Take memmode, pass it on.
	Deal with autoinc.
	(cselib_hash_rtx): Likewise.
	(cselib_lookup_mem): Infer pmode from address mode.  Distinguish
	address and MEM modes.
	(cselib_subst_to_values): Rename to...
	(cselib_subst_to_values_addr): ... this.  Add memmode, pass it on.
	Deal with autoinc.
	(cselib_lookup): Rename to...
	(cselib_lookup_addr): ... this.  Likewise.
	(struct cselib_record_autoinc_data): New.
	(cselib_record_autoinc_cb): New fn.
	(cselib_record_sets): Use it, along with for_each_inc_dec.  Pass MEM
	mode to cselib_lookup_addr.
	(cselib_init): Initialize cselib_record_autoinc.
	* var-tracking.c (replace_expr_with_values, use_type): Pass MEM mode
	to cselib_lookup_addr.
	(add_uses): Likewise, also to cselib_subst_to_values_addr.
	(add_stores): Likewise.
	(vt_initialize): Pass CSELIB_RECORD_AUTOINC to cselib_init.

Index: gcc/dse.c
===================================================================
--- gcc/dse.c.orig	2010-03-17 01:05:25.000000000 -0300
+++ gcc/dse.c	2010-03-17 22:14:46.000000000 -0300
@@ -806,81 +806,22 @@ free_store_info (insn_info_t insn_info)
 }
 
 
-struct insn_size {
-  int size;
-  rtx insn;
-};
-
-
-/* Add an insn to do the add inside a x if it is a
-   PRE/POST-INC/DEC/MODIFY.  D is an structure containing the insn and
-   the size of the mode of the MEM that this is inside of.  */
-
 static int
-replace_inc_dec (rtx *r, void *d)
+emit_inc_dec_insn_before (rtx mem ATTRIBUTE_UNUSED,
+			  rtx op ATTRIBUTE_UNUSED,
+			  rtx dest, rtx src, rtx srcoff, void *arg)
 {
-  rtx x = *r;
-  struct insn_size *data = (struct insn_size *)d;
-  switch (GET_CODE (x))
-    {
-    case PRE_INC:
-    case POST_INC:
-      {
-	rtx r1 = XEXP (x, 0);
-	rtx c = gen_int_mode (data->size, GET_MODE (r1));
-	emit_insn_before (gen_rtx_SET (VOIDmode, r1,
-				       gen_rtx_PLUS (GET_MODE (r1), r1, c)),
-			  data->insn);
-	return -1;
-      }
-
-    case PRE_DEC:
-    case POST_DEC:
-      {
-	rtx r1 = XEXP (x, 0);
-	rtx c = gen_int_mode (-data->size, GET_MODE (r1));
-	emit_insn_before (gen_rtx_SET (VOIDmode, r1,
-				       gen_rtx_PLUS (GET_MODE (r1), r1, c)),
-			  data->insn);
-	return -1;
-      }
-
-    case PRE_MODIFY:
-    case POST_MODIFY:
-      {
-	/* We can reuse the add because we are about to delete the
-	   insn that contained it.  */
-	rtx add = XEXP (x, 0);
-	rtx r1 = XEXP (add, 0);
-	emit_insn_before (gen_rtx_SET (VOIDmode, r1, add), data->insn);
-	return -1;
-      }
+  rtx insn = (rtx)arg;
 
-    default:
-      return 0;
-    }
-}
+  if (srcoff)
+    src = gen_rtx_PLUS (GET_MODE (src), src, srcoff);
 
+  /* We can reuse all operands without copying, because we are about
+     to delete the insn that contained it.  */
 
-/* If X is a MEM, check the address to see if it is PRE/POST-INC/DEC/MODIFY
-   and generate an add to replace that.  */
+  emit_insn_before (gen_rtx_SET (VOIDmode, dest, src), insn);
 
-static int
-replace_inc_dec_mem (rtx *r, void *d)
-{
-  rtx x = *r;
-  if (x != NULL_RTX && MEM_P (x))
-    {
-      struct insn_size data;
-
-      data.size = GET_MODE_SIZE (GET_MODE (x));
-      data.insn = (rtx) d;
-
-      for_each_rtx (&XEXP (x, 0), replace_inc_dec, &data);
-
-      return -1;
-    }
-  return 0;
+  return -1;
 }
 
 /* Before we delete INSN, make sure that the auto inc/dec, if it is
@@ -891,7 +832,7 @@ check_for_inc_dec (rtx insn)
 {
   rtx note = find_reg_note (insn, REG_INC, NULL_RTX);
   if (note)
-    for_each_rtx (&insn, replace_inc_dec_mem, insn);
+    for_each_inc_dec (&insn, emit_inc_dec_insn_before, insn);
 }
 
 
Index: gcc/rtl.h
===================================================================
--- gcc/rtl.h.orig	2010-03-17 01:05:25.000000000 -0300
+++ gcc/rtl.h	2010-03-17 22:14:46.000000000 -0300
@@ -1875,6 +1875,9 @@ extern int computed_jump_p (const_rtx);
 typedef int (*rtx_function) (rtx *, void *);
 extern int for_each_rtx (rtx *, rtx_function, void *);
 
+typedef int (*for_each_inc_dec_fn) (rtx, rtx, rtx, rtx, rtx, void *);
+extern int for_each_inc_dec (rtx *, for_each_inc_dec_fn, void *);
+
 typedef int (*rtx_equal_p_callback_function) (const_rtx *, const_rtx *,
                                               rtx *, rtx *);
 extern int rtx_equal_p_cb (const_rtx, const_rtx,
Index: gcc/cselib.c
===================================================================
--- gcc/cselib.c.orig	2010-03-17 01:05:25.000000000 -0300
+++ gcc/cselib.c	2010-03-22 03:41:57.000000000 -0300
@@ -46,6 +46,7 @@ along with GCC; see the file COPYING3.  
 
 static bool cselib_record_memory;
 static bool cselib_preserve_constants;
+static bool cselib_record_autoinc;
 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 *);
@@ -56,7 +57,8 @@ static void unchain_one_elt_loc_list (st
 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);
@@ -319,6 +321,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
@@ -348,7 +370,7 @@ entry_and_rtx_equal_p (const void *entry
   /* 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))
+    if (rtx_equal_for_cselib_1 (l->loc, x, find_slot_memmode))
       return 1;
 
   return 0;
@@ -545,13 +567,59 @@ 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;
+    }
+}
+
+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_addr (x, GET_MODE (x), 0, memmode);
 
       if (e)
 	x = e->val_rtx;
@@ -559,7 +627,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_addr (y, GET_MODE (y), 0, memmode);
 
       if (e)
 	y = e->val_rtx;
@@ -583,7 +651,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;
 	}
 
@@ -601,16 +669,40 @@ 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))
+    {
+      if (cselib_record_autoinc)
+	{
+	  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))
     {
@@ -654,18 +746,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;
 
@@ -717,6 +809,8 @@ wrap_constant (enum machine_mode mode, r
    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 auto-inc 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))
@@ -727,7 +821,7 @@ wrap_constant (enum machine_mode mode, r
    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;
@@ -742,7 +836,7 @@ cselib_hash_rtx (rtx x, int create)
     {
     case MEM:
     case REG:
-      e = cselib_lookup (x, GET_MODE (x), create);
+      e = cselib_lookup_addr (x, GET_MODE (x), create, memmode);
       if (! e)
 	return 0;
 
@@ -783,7 +877,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;
@@ -816,10 +910,32 @@ cselib_hash_rtx (rtx x, int create)
 
     case PRE_DEC:
     case PRE_INC:
+      /* We can't compute these without knowing the MEM mode.  */
+      if (!cselib_record_autoinc)
+	return 0;
+      gcc_assert (memmode != VOIDmode);
+      i = GET_MODE_SIZE (memmode);
+      if (code == PRE_DEC)
+	i = -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:
+      if (!cselib_record_autoinc)
+	return 0;
+      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:
+      if (!cselib_record_autoinc)
+	return 0;
+      gcc_assert (memmode != VOIDmode);
+      return cselib_hash_rtx (XEXP (x, 0), create, memmode);
+
     case PC:
     case CC0:
     case CALL:
@@ -845,7 +961,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;
@@ -857,7 +973,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;
@@ -966,7 +1082,7 @@ add_mem_for_addr (cselib_val *addr_elt, 
 static cselib_val *
 cselib_lookup_mem (rtx x, int create)
 {
-  enum machine_mode mode = GET_MODE (x);
+  enum machine_mode mode = GET_MODE (x), pmode = Pmode;
   void **slot;
   cselib_val *addr;
   cselib_val *mem_elt;
@@ -977,8 +1093,11 @@ cselib_lookup_mem (rtx x, int create)
       || (FLOAT_MODE_P (mode) && flag_float_store))
     return 0;
 
+  if (GET_MODE (XEXP (x, 0)) != VOIDmode)
+    pmode = GET_MODE (XEXP (x, 0));
+
   /* Look up the value for the address.  */
-  addr = cselib_lookup (XEXP (x, 0), mode, create);
+  addr = cselib_lookup_addr (XEXP (x, 0), pmode, create, mode);
   if (! addr)
     return 0;
 
@@ -992,8 +1111,8 @@ cselib_lookup_mem (rtx x, int create)
 
   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;
 }
@@ -1425,10 +1544,12 @@ cselib_expand_value_rtx_1 (rtx orig, str
    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 if
+   cselib_record_autoinc holds.  */
 
 rtx
-cselib_subst_to_values (rtx x)
+cselib_subst_to_values_addr (rtx x, enum machine_mode memmode)
 {
   enum rtx_code code = GET_CODE (x);
   const char *fmt = GET_RTX_FORMAT (code);
@@ -1465,14 +1586,34 @@ cselib_subst_to_values (rtx x)
     case CONST_FIXED:
       return x;
 
-    case POST_INC:
+    case PRE_DEC:
     case PRE_INC:
+      if (!cselib_record_autoinc)
+	{
+	no_autoinc:
+	  e = new_cselib_val (next_uid, GET_MODE (x), x);
+	  return e->val_rtx;
+	}
+      gcc_assert (memmode != VOIDmode);
+      i = GET_MODE_SIZE (memmode);
+      if (code == PRE_DEC)
+	i = -i;
+      return cselib_subst_to_values_addr (plus_constant (XEXP (x, 0), i),
+					  memmode);
+
+    case PRE_MODIFY:
+      if (!cselib_record_autoinc)
+	goto no_autoinc;
+      gcc_assert (memmode != VOIDmode);
+      return cselib_subst_to_values_addr (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;
+      if (!cselib_record_autoinc)
+	goto no_autoinc;
+      gcc_assert (memmode != VOIDmode);
+      return cselib_subst_to_values_addr (XEXP (x, 0), memmode);
 
     default:
       break;
@@ -1482,7 +1623,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_addr (XEXP (x, i), memmode);
 
 	  if (t != XEXP (x, i))
 	    {
@@ -1497,7 +1638,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_addr (XVECEXP (x, i, j), memmode);
 
 	      if (t != XVECEXP (x, i, j))
 		{
@@ -1533,13 +1674,16 @@ cselib_log_lookup (rtx x, cselib_val *re
   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).  */
+/* 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.  */
 
 cselib_val *
-cselib_lookup (rtx x, enum machine_mode mode, int create)
+cselib_lookup_addr (rtx x, enum machine_mode mode,
+		    int create, enum machine_mode memmode)
 {
   void **slot;
   cselib_val *e;
@@ -1585,7 +1729,7 @@ cselib_lookup (rtx x, enum machine_mode 
 	  REG_VALUES (i) = new_elt_list (REG_VALUES (i), NULL);
 	}
       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);
     }
@@ -1593,13 +1737,13 @@ cselib_lookup (rtx x, enum machine_mode 
   if (MEM_P (x))
     return cselib_log_lookup (x, 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);
 
-  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);
 
@@ -1613,7 +1757,8 @@ cselib_lookup (rtx x, enum machine_mode 
      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));
+  e->locs = new_elt_loc_list (e->locs,
+			      cselib_subst_to_values_addr (x, memmode));
   return cselib_log_lookup (x, e);
 }
 
@@ -1768,7 +1913,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_addr (XEXP (x, 0), VOIDmode, 0, GET_MODE (x));
 	  mem_chain = &addr->addr_list;
 	  for (;;)
 	    {
@@ -1882,6 +2027,36 @@ cselib_record_set (rtx dest, cselib_val 
    in a PARALLEL.  Since it's fairly cheap, use a really large number.  */
 #define MAX_SETS (FIRST_PSEUDO_REGISTER * 2)
 
+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: SRCBASE 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 srcbase, 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 (srcbase),
+						 srcbase, srcoff);
+  else
+    data->sets[data->n_sets].src = srcbase;
+
+  data->n_sets++;
+
+  return -1;
+}
+
 /* Record the effects of any sets in INSN.  */
 static void
 cselib_record_sets (rtx insn)
@@ -1934,6 +2109,15 @@ cselib_record_sets (rtx insn)
 	sets[0].src = XEXP (note, 0);
     }
 
+  if (cselib_record_autoinc)
+    {
+      struct cselib_record_autoinc_data data;
+      data.sets = sets;
+      data.n_sets = 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++)
@@ -1958,8 +2142,9 @@ cselib_record_sets (rtx insn)
 	      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);
+	      sets[i].dest_addr_elt = cselib_lookup_addr (XEXP (dest, 0),
+							  address_mode, 1,
+							  GET_MODE (dest));
 	    }
 	  else
 	    sets[i].dest_addr_elt = 0;
@@ -2098,6 +2283,7 @@ cselib_init (int record_what)
   value_pool = create_alloc_pool ("value", RTX_CODE_SIZE (VALUE), 100);
   cselib_record_memory = record_what & CSELIB_RECORD_MEMORY;
   cselib_preserve_constants = record_what & CSELIB_PRESERVE_CONSTANTS;
+  cselib_record_autoinc = record_what & CSELIB_RECORD_AUTOINC;
 
   /* (mem:BLK (scratch)) is a special mechanism to conflict with everything,
      see canon_true_dependence.  This is only created once.  */
Index: gcc/cselib.h
===================================================================
--- gcc/cselib.h.orig	2010-03-17 01:05:25.000000000 -0300
+++ gcc/cselib.h	2010-03-22 03:14:10.000000000 -0300
@@ -69,14 +69,18 @@ struct cselib_set
 enum cselib_record_what
 {
   CSELIB_RECORD_MEMORY = 1,
-  CSELIB_PRESERVE_CONSTANTS = 2
+  CSELIB_PRESERVE_CONSTANTS = 2,
+  CSELIB_RECORD_AUTOINC = 4
 };
 
 extern void (*cselib_discard_hook) (cselib_val *);
 extern void (*cselib_record_sets_hook) (rtx insn, struct cselib_set *sets,
 					int n_sets);
 
-extern cselib_val *cselib_lookup (rtx, enum machine_mode, int);
+extern cselib_val *cselib_lookup_addr (rtx, enum machine_mode,
+				       int, enum machine_mode);
+#define cselib_lookup(x, mode, create) \
+  (cselib_lookup_addr (x, mode, create, VOIDmode))
 extern void cselib_init (int);
 extern void cselib_clear_table (void);
 extern void cselib_finish (void);
@@ -90,7 +94,8 @@ extern rtx cselib_expand_value_rtx_cb (r
 				       cselib_expand_callback, void *);
 extern bool cselib_dummy_expand_value_rtx_cb (rtx, bitmap, int,
 					      cselib_expand_callback, void *);
-extern rtx cselib_subst_to_values (rtx);
+extern rtx cselib_subst_to_values_addr (rtx, enum machine_mode);
+#define cselib_subst_to_values(x) (cselib_subst_to_values_addr (x, VOIDmode))
 extern void cselib_invalidate_rtx (rtx);
 
 extern void cselib_reset_table (unsigned int);
Index: gcc/var-tracking.c
===================================================================
--- gcc/var-tracking.c.orig	2010-03-17 19:08:53.000000000 -0300
+++ gcc/var-tracking.c	2010-03-22 03:15:45.000000000 -0300
@@ -4653,8 +4653,9 @@ replace_expr_with_values (rtx loc)
     return NULL;
   else if (MEM_P (loc))
     {
-      cselib_val *addr = cselib_lookup (XEXP (loc, 0),
-					get_address_mode (loc), 0);
+      cselib_val *addr = cselib_lookup_addr (XEXP (loc, 0),
+					     get_address_mode (loc), 0,
+					     GET_MODE (loc));
       if (addr)
 	return replace_equiv_address_nv (loc, addr->val_rtx);
       else
@@ -4702,8 +4703,9 @@ use_type (rtx loc, struct count_use_info
 	    {
 	      if (REG_P (loc)
 		  || (find_use_val (loc, GET_MODE (loc), cui)
-		      && cselib_lookup (XEXP (loc, 0),
-					get_address_mode (loc), 0)))
+		      && cselib_lookup_addr (XEXP (loc, 0),
+					     get_address_mode (loc), 0,
+					     GET_MODE (loc))))
 		return MO_VAL_SET;
 	    }
 	  else
@@ -4838,13 +4840,15 @@ add_uses (rtx *ploc, void *data)
 	      rtx mloc = vloc;
 	      enum machine_mode address_mode = get_address_mode (mloc);
 	      cselib_val *val
-		= cselib_lookup (XEXP (mloc, 0), address_mode, 0);
+		= cselib_lookup_addr (XEXP (mloc, 0), address_mode, 0,
+				      GET_MODE (mloc));
 
 	      if (val && !cselib_preserved_value_p (val))
 		{
 		  micro_operation moa;
 		  preserve_value (val);
-		  mloc = cselib_subst_to_values (XEXP (mloc, 0));
+		  mloc = cselib_subst_to_values_addr (XEXP (mloc, 0),
+						      GET_MODE (mloc));
 		  moa.type = MO_VAL_USE;
 		  moa.insn = cui->insn;
 		  moa.u.loc = gen_rtx_CONCAT (address_mode,
@@ -4910,13 +4914,15 @@ add_uses (rtx *ploc, void *data)
 	      rtx mloc = oloc;
 	      enum machine_mode address_mode = get_address_mode (mloc);
 	      cselib_val *val
-		= cselib_lookup (XEXP (mloc, 0), address_mode, 0);
+		= cselib_lookup_addr (XEXP (mloc, 0), address_mode, 0,
+				      GET_MODE (mloc));
 
 	      if (val && !cselib_preserved_value_p (val))
 		{
 		  micro_operation moa;
 		  preserve_value (val);
-		  mloc = cselib_subst_to_values (XEXP (mloc, 0));
+		  mloc = cselib_subst_to_values_addr (XEXP (mloc, 0),
+						      GET_MODE (mloc));
 		  moa.type = MO_VAL_USE;
 		  moa.insn = cui->insn;
 		  moa.u.loc = gen_rtx_CONCAT (address_mode,
@@ -5141,14 +5147,16 @@ add_stores (rtx loc, const_rtx expr, voi
 	{
 	  rtx mloc = loc;
 	  enum machine_mode address_mode = get_address_mode (mloc);
-	  cselib_val *val = cselib_lookup (XEXP (mloc, 0),
-					   address_mode, 0);
+	  cselib_val *val = cselib_lookup_addr (XEXP (mloc, 0),
+						address_mode, 0,
+						GET_MODE (mloc));
 
 	  if (val && !cselib_preserved_value_p (val))
 	    {
 	      preserve_value (val);
 	      mo.type = MO_VAL_USE;
-	      mloc = cselib_subst_to_values (XEXP (mloc, 0));
+	      mloc = cselib_subst_to_values_addr (XEXP (mloc, 0),
+						  GET_MODE (mloc));
 	      mo.u.loc = gen_rtx_CONCAT (address_mode, val->val_rtx, mloc);
 	      mo.insn = cui->insn;
 	      if (dump_file && (dump_flags & TDF_DETAILS))
@@ -8023,7 +8031,8 @@ vt_initialize (void)
 
   if (MAY_HAVE_DEBUG_INSNS)
     {
-      cselib_init (CSELIB_RECORD_MEMORY | CSELIB_PRESERVE_CONSTANTS);
+      cselib_init (CSELIB_RECORD_MEMORY | CSELIB_PRESERVE_CONSTANTS
+		   | CSELIB_RECORD_AUTOINC);
       scratch_regs = BITMAP_ALLOC (NULL);
       valvar_pool = create_alloc_pool ("small variable_def pool",
 				       sizeof (struct variable_def), 256);
Index: gcc/rtlanal.c
===================================================================
--- gcc/rtlanal.c.orig	2010-03-12 04:33:41.000000000 -0300
+++ gcc/rtlanal.c	2010-03-17 22:14:47.000000000 -0300
@@ -2870,7 +2870,105 @@ for_each_rtx (rtx *x, rtx_function f, vo
   return for_each_rtx_1 (*x, i, f, data);
 }
 
+\f
+
+struct for_each_inc_dec_ops {
+  for_each_inc_dec_fn fn;
+  void *arg;
+  rtx mem;
+};
+
+static int for_each_inc_dec_find_mem (rtx *r, void *d);
+
+/* Add an insn to do the add inside a x if it is a
+   PRE/POST-INC/DEC/MODIFY.  D is an structure containing the insn and
+   the size of the mode of the MEM that this is inside of.  */
+
+static int
+for_each_inc_dec_find_inc_dec (rtx *r, void *d)
+{
+  rtx x = *r;
+  struct for_each_inc_dec_ops *data = (struct for_each_inc_dec_ops *)d;
+  int size = GET_MODE_SIZE (GET_MODE (data->mem));
+
+  switch (GET_CODE (x))
+    {
+    case PRE_INC:
+    case POST_INC:
+      {
+	rtx r1 = XEXP (x, 0);
+	rtx c = gen_int_mode (size, GET_MODE (r1));
+	return data->fn (data->mem, x, r1, r1, c, data->arg);
+      }
+
+    case PRE_DEC:
+    case POST_DEC:
+      {
+	rtx r1 = XEXP (x, 0);
+	rtx c = gen_int_mode (-size, GET_MODE (r1));
+	return data->fn (data->mem, x, r1, r1, c, data->arg);
+      }
+
+    case PRE_MODIFY:
+    case POST_MODIFY:
+      {
+	rtx r1 = XEXP (x, 0);
+	rtx add = XEXP (x, 1);
+	return data->fn (data->mem, x, r1, add, NULL, data->arg);
+      }
+
+    case MEM:
+      {
+	rtx save = data->mem;
+	int ret = for_each_inc_dec_find_mem (r, d);
+	data->mem = save;
+	return ret;
+      }
+
+    default:
+      return 0;
+    }
+}
+
+/* If X is a MEM, check the address to see if it is PRE/POST-INC/DEC/MODIFY
+   and generate an add to replace that.  */
+
+static int
+for_each_inc_dec_find_mem (rtx *r, void *d)
+{
+  rtx x = *r;
+  if (x != NULL_RTX && MEM_P (x))
+    {
+      struct for_each_inc_dec_ops *data = (struct for_each_inc_dec_ops *) d;
+      int result;
+
+      data->mem = x;
 
+      result = for_each_rtx (&XEXP (x, 0), for_each_inc_dec_find_inc_dec,
+			     data);
+      if (result)
+	return result;
+
+      return -1;
+    }
+  return 0;
+}
+
+int
+for_each_inc_dec (rtx *insn,
+		  for_each_inc_dec_fn fn,
+		  void *arg)
+{
+  struct for_each_inc_dec_ops data;
+
+  data.fn = fn;
+  data.arg = arg;
+  data.mem = NULL;
+
+  return for_each_rtx (insn, for_each_inc_dec_find_mem, &data);
+}
+
+\f
 /* Searches X for any reference to REGNO, returning the rtx of the
    reference found if any.  Otherwise, returns NULL_RTX.  */
 

[-- Attachment #3: Type: text/plain, Size: 257 bytes --]


-- 
Alexandre Oliva, freedom fighter    http://FSFLA.org/~lxoliva/
You must be the change you wish to see in the world. -- Gandhi
Be Free! -- http://FSFLA.org/   FSF Latin America board member
Free Software Evangelist      Red Hat Brazil Compiler Engineer

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH] Fix VTA sp (and fp) based MEM handling (PR debug/43051, PR  debug/43092)
  2010-03-23  8:52 ` Alexandre Oliva
@ 2010-09-11  1:17   ` Alexandre Oliva
  2010-09-11 12:41     ` Steven Bosscher
  0 siblings, 1 reply; 10+ messages in thread
From: Alexandre Oliva @ 2010-09-11  1:17 UTC (permalink / raw)
  To: Jakub Jelinek, bernds; +Cc: Richard Guenther, gcc-patches

[-- Attachment #1: Type: text/plain, Size: 1397 bytes --]

On Mar 23, 2010, Alexandre Oliva <aoliva@redhat.com> wrote:

> On Mar 15, 2010, Jakub Jelinek <jakub@redhat.com> wrote:

>> One is that cselib doesn't handle autoinc rtls well
>> (Alex has a follow-up patch in which it teaches cselib about these; this
>> final version of the patch doesn't need it for var-tracking though).

> Here it is.  Regstraped on x86_64-linux-gnu, i686-linux-gnu and
> ia64-linux-gnu.  Ok to install?

In bug 43494, Bernd suggested us to track autoinc always, rather than
only within VTA.  I implemented that, splitting out the code needed to
introduce the explicit selection into a separate patch.

I also dropped the _addr renamed functions, and adjusted the few callers
that didn't pass a mode for the enclosing MEM.

I found out VTA, for reasons I didn't investigate, could somehow do
without cselib_invalidate_rtx() for autoinc-modified parameters, but
other passes failed without that.  I ended up introducing a loop to
explicitly invalidate dests of implicit autoinc sets.

The first patch implements unconditional autoinc support in cselib.  I
have regstrapped it on x86_64-linux-gnu and i686-linux-gnu.  Ok to
install?

The second patch makes autoinc support in cselib optional, making some
code conditional and conditionally restoring special-case handling that
could be removed if autoinc was unconditional.  I have *not* completed
its regstrap yet.  Should I?


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: vta-cselib-autoinc-pr43092.patch --]
[-- Type: text/x-diff, Size: 37588 bytes --]

for  gcc/ChangeLog
from  Alexandre Oliva  <aoliva@redhat.com>

	PR debug/43092
	PR debug/43494
	* rtl.h (for_each_inc_dec_fn): New type.
	(for_each_inc_dec): Declare.
	* rtlanal.c (struct for_each_inc_dec_ops): New type.
	(for_each_inc_dec_find_inc_dec): New fn.
	(for_each_inc_dec_find_mem): New fn.
	(for_each_inc_dec): New fn.
	* dse.c (struct insn_size): Remove.
	(replace_inc_dec, replace_inc_dec_mem): Remove.
	(emit_inc_dec_insn_before): New fn.
	(check_for_inc_dec): Use it, along with for_each_inc_dec.
	(canon_address): Pass mem modes to cselib_lookup.
	* cselib.h (cselib_lookup): Add memmode argument.  Adjust callers.
	(cselib_lookup_from_insn): Likewise.
	(cselib_subst_to_values): Likewise.
	* cselib.c (find_slot_memmode): New var.
	(cselib_find_slot): New fn.  Use it instead of
	htab_find_slot_with_hash everywhere.
	(entry_and_rtx_equal_p): Use find_slot_memmode.
	(autoinc_split): New fn.
	(rtx_equal_for_cselib_p): Rename and implement in terms of...
	(rtx_equal_for_cselib_1): ... this.  Take memmode, pass it on.
	Deal with autoinc.
	(cselib_hash_rtx): Likewise.
	(cselib_lookup_mem): Infer pmode from address mode.  Distinguish
	address and MEM modes.
	(cselib_subst_to_values): Add memmode, pass it on.
	Deal with autoinc.
	(cselib_lookup): Add memmode argument, pass it on.
	(cselib_lookup_from_insn): Add memmode.
	(struct cselib_record_autoinc_data): New.
	(cselib_record_autoinc_cb): New fn.
	(cselib_record_sets): Use it, along with for_each_inc_dec.  Pass MEM
	mode to cselib_lookup.
	* var-tracking.c (replace_expr_with_values, use_type): Pass MEM mode
	to cselib_lookup.
	(add_uses): Likewise, also to cselib_subst_to_values.
	(add_stores): Likewise.
	* sched-deps.c 	(add_insn_mem_dependence): Pass mode to
	cselib_subst_to_values.
	(sched_analyze_1, sched_analyze_2): Likewise.  Adjusted.
	* gcse.c (do_local_cprop): Adjusted.
	* postreload.c (reload_cse_simplify_set): Adjusted.
	(reload_cse_simplify_operands): Adjusted.
	* sel-sched-dump (debug_mem_addr_value): Pass mode.

Index: gcc/rtl.h
===================================================================
--- gcc/rtl.h.orig	2010-09-08 19:59:18.000000000 -0300
+++ gcc/rtl.h	2010-09-08 19:59:49.000000000 -0300
@@ -1862,6 +1862,9 @@ extern int computed_jump_p (const_rtx);
 typedef int (*rtx_function) (rtx *, void *);
 extern int for_each_rtx (rtx *, rtx_function, void *);
 
+typedef int (*for_each_inc_dec_fn) (rtx, rtx, rtx, rtx, rtx, void *);
+extern int for_each_inc_dec (rtx *, for_each_inc_dec_fn, void *);
+
 typedef int (*rtx_equal_p_callback_function) (const_rtx *, const_rtx *,
                                               rtx *, rtx *);
 extern int rtx_equal_p_cb (const_rtx, const_rtx,
Index: gcc/rtlanal.c
===================================================================
--- gcc/rtlanal.c.orig	2010-09-08 19:59:19.000000000 -0300
+++ gcc/rtlanal.c	2010-09-08 19:59:49.000000000 -0300
@@ -2866,7 +2866,105 @@ for_each_rtx (rtx *x, rtx_function f, vo
   return for_each_rtx_1 (*x, i, f, data);
 }
 
+\f
+
+struct for_each_inc_dec_ops {
+  for_each_inc_dec_fn fn;
+  void *arg;
+  rtx mem;
+};
+
+static int for_each_inc_dec_find_mem (rtx *r, void *d);
+
+/* Add an insn to do the add inside a x if it is a
+   PRE/POST-INC/DEC/MODIFY.  D is an structure containing the insn and
+   the size of the mode of the MEM that this is inside of.  */
+
+static int
+for_each_inc_dec_find_inc_dec (rtx *r, void *d)
+{
+  rtx x = *r;
+  struct for_each_inc_dec_ops *data = (struct for_each_inc_dec_ops *)d;
+  int size = GET_MODE_SIZE (GET_MODE (data->mem));
+
+  switch (GET_CODE (x))
+    {
+    case PRE_INC:
+    case POST_INC:
+      {
+	rtx r1 = XEXP (x, 0);
+	rtx c = gen_int_mode (size, GET_MODE (r1));
+	return data->fn (data->mem, x, r1, r1, c, data->arg);
+      }
+
+    case PRE_DEC:
+    case POST_DEC:
+      {
+	rtx r1 = XEXP (x, 0);
+	rtx c = gen_int_mode (-size, GET_MODE (r1));
+	return data->fn (data->mem, x, r1, r1, c, data->arg);
+      }
+
+    case PRE_MODIFY:
+    case POST_MODIFY:
+      {
+	rtx r1 = XEXP (x, 0);
+	rtx add = XEXP (x, 1);
+	return data->fn (data->mem, x, r1, add, NULL, data->arg);
+      }
+
+    case MEM:
+      {
+	rtx save = data->mem;
+	int ret = for_each_inc_dec_find_mem (r, d);
+	data->mem = save;
+	return ret;
+      }
+
+    default:
+      return 0;
+    }
+}
+
+/* If X is a MEM, check the address to see if it is PRE/POST-INC/DEC/MODIFY
+   and generate an add to replace that.  */
+
+static int
+for_each_inc_dec_find_mem (rtx *r, void *d)
+{
+  rtx x = *r;
+  if (x != NULL_RTX && MEM_P (x))
+    {
+      struct for_each_inc_dec_ops *data = (struct for_each_inc_dec_ops *) d;
+      int result;
+
+      data->mem = x;
 
+      result = for_each_rtx (&XEXP (x, 0), for_each_inc_dec_find_inc_dec,
+			     data);
+      if (result)
+	return result;
+
+      return -1;
+    }
+  return 0;
+}
+
+int
+for_each_inc_dec (rtx *insn,
+		  for_each_inc_dec_fn fn,
+		  void *arg)
+{
+  struct for_each_inc_dec_ops data;
+
+  data.fn = fn;
+  data.arg = arg;
+  data.mem = NULL;
+
+  return for_each_rtx (insn, for_each_inc_dec_find_mem, &data);
+}
+
+\f
 /* Searches X for any reference to REGNO, returning the rtx of the
    reference found if any.  Otherwise, returns NULL_RTX.  */
 
Index: gcc/dse.c
===================================================================
--- gcc/dse.c.orig	2010-09-08 19:59:18.000000000 -0300
+++ gcc/dse.c	2010-09-08 19:59:49.089177241 -0300
@@ -807,81 +807,22 @@ free_store_info (insn_info_t insn_info)
 }
 
 
-struct insn_size {
-  int size;
-  rtx insn;
-};
-
-
-/* Add an insn to do the add inside a x if it is a
-   PRE/POST-INC/DEC/MODIFY.  D is an structure containing the insn and
-   the size of the mode of the MEM that this is inside of.  */
-
 static int
-replace_inc_dec (rtx *r, void *d)
+emit_inc_dec_insn_before (rtx mem ATTRIBUTE_UNUSED,
+			  rtx op ATTRIBUTE_UNUSED,
+			  rtx dest, rtx src, rtx srcoff, void *arg)
 {
-  rtx x = *r;
-  struct insn_size *data = (struct insn_size *)d;
-  switch (GET_CODE (x))
-    {
-    case PRE_INC:
-    case POST_INC:
-      {
-	rtx r1 = XEXP (x, 0);
-	rtx c = gen_int_mode (data->size, GET_MODE (r1));
-	emit_insn_before (gen_rtx_SET (VOIDmode, r1,
-				       gen_rtx_PLUS (GET_MODE (r1), r1, c)),
-			  data->insn);
-	return -1;
-      }
-
-    case PRE_DEC:
-    case POST_DEC:
-      {
-	rtx r1 = XEXP (x, 0);
-	rtx c = gen_int_mode (-data->size, GET_MODE (r1));
-	emit_insn_before (gen_rtx_SET (VOIDmode, r1,
-				       gen_rtx_PLUS (GET_MODE (r1), r1, c)),
-			  data->insn);
-	return -1;
-      }
-
-    case PRE_MODIFY:
-    case POST_MODIFY:
-      {
-	/* We can reuse the add because we are about to delete the
-	   insn that contained it.  */
-	rtx add = XEXP (x, 0);
-	rtx r1 = XEXP (add, 0);
-	emit_insn_before (gen_rtx_SET (VOIDmode, r1, add), data->insn);
-	return -1;
-      }
+  rtx insn = (rtx)arg;
 
-    default:
-      return 0;
-    }
-}
+  if (srcoff)
+    src = gen_rtx_PLUS (GET_MODE (src), src, srcoff);
 
+  /* We can reuse all operands without copying, because we are about
+     to delete the insn that contained it.  */
 
-/* If X is a MEM, check the address to see if it is PRE/POST-INC/DEC/MODIFY
-   and generate an add to replace that.  */
+  emit_insn_before (gen_rtx_SET (VOIDmode, dest, src), insn);
 
-static int
-replace_inc_dec_mem (rtx *r, void *d)
-{
-  rtx x = *r;
-  if (x != NULL_RTX && MEM_P (x))
-    {
-      struct insn_size data;
-
-      data.size = GET_MODE_SIZE (GET_MODE (x));
-      data.insn = (rtx) d;
-
-      for_each_rtx (&XEXP (x, 0), replace_inc_dec, &data);
-
-      return -1;
-    }
-  return 0;
+  return -1;
 }
 
 /* Before we delete INSN, make sure that the auto inc/dec, if it is
@@ -892,7 +833,7 @@ check_for_inc_dec (rtx insn)
 {
   rtx note = find_reg_note (insn, REG_INC, NULL_RTX);
   if (note)
-    for_each_rtx (&insn, replace_inc_dec_mem, insn);
+    for_each_inc_dec (&insn, emit_inc_dec_insn_before, insn);
 }
 
 
@@ -1107,7 +1048,7 @@ canon_address (rtx mem,
 
   *alias_set_out = 0;
 
-  cselib_lookup (mem_address, address_mode, 1);
+  cselib_lookup (mem_address, address_mode, 1, GET_MODE (mem));
 
   if (dump_file)
     {
@@ -1187,7 +1128,7 @@ canon_address (rtx mem,
 	}
     }
 
-  *base = cselib_lookup (address, address_mode, true);
+  *base = cselib_lookup (address, address_mode, true, GET_MODE (mem));
   *group_id = -1;
 
   if (*base == NULL)
Index: gcc/cselib.h
===================================================================
--- gcc/cselib.h.orig	2010-09-08 19:59:18.000000000 -0300
+++ gcc/cselib.h	2010-09-08 19:59:49.000000000 -0300
@@ -76,8 +76,10 @@ extern void (*cselib_discard_hook) (csel
 extern void (*cselib_record_sets_hook) (rtx insn, struct cselib_set *sets,
 					int n_sets);
 
-extern cselib_val *cselib_lookup (rtx, enum machine_mode, int);
-extern cselib_val *cselib_lookup_from_insn (rtx, enum machine_mode, int, rtx);
+extern cselib_val *cselib_lookup (rtx, enum machine_mode,
+				  int, enum machine_mode);
+extern cselib_val *cselib_lookup_from_insn (rtx, enum machine_mode,
+					    int, enum machine_mode, rtx);
 extern void cselib_init (int);
 extern void cselib_clear_table (void);
 extern void cselib_finish (void);
@@ -91,7 +93,7 @@ extern rtx cselib_expand_value_rtx_cb (r
 				       cselib_expand_callback, void *);
 extern bool cselib_dummy_expand_value_rtx_cb (rtx, bitmap, int,
 					      cselib_expand_callback, void *);
-extern rtx cselib_subst_to_values (rtx);
+extern rtx cselib_subst_to_values (rtx, enum machine_mode);
 extern void cselib_invalidate_rtx (rtx);
 
 extern void cselib_reset_table (unsigned int);
Index: gcc/cselib.c
===================================================================
--- gcc/cselib.c.orig	2010-09-08 19:59:19.116292565 -0300
+++ gcc/cselib.c	2010-09-09 15:32:17.000000000 -0300
@@ -57,7 +57,8 @@ static void unchain_one_elt_loc_list (st
 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);
@@ -385,6 +386,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
@@ -414,7 +435,7 @@ entry_and_rtx_equal_p (const void *entry
   /* 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))
+    if (rtx_equal_for_cselib_1 (l->loc, x, find_slot_memmode))
       {
 	promote_debug_loc (l);
 	return 1;
@@ -626,13 +647,59 @@ 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;
+    }
+}
+
+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;
@@ -640,7 +707,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;
@@ -664,7 +731,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;
 	}
 
@@ -682,16 +749,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))
     {
@@ -735,18 +823,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;
 
@@ -798,6 +886,8 @@ wrap_constant (enum machine_mode mode, r
    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 auto-inc 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))
@@ -808,7 +898,7 @@ wrap_constant (enum machine_mode mode, r
    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;
@@ -823,7 +913,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;
 
@@ -864,7 +954,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;
@@ -897,10 +987,26 @@ 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;
+      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:
@@ -926,7 +1032,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;
@@ -938,7 +1044,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;
@@ -1050,7 +1156,7 @@ add_mem_for_addr (cselib_val *addr_elt, 
 static cselib_val *
 cselib_lookup_mem (rtx x, int create)
 {
-  enum machine_mode mode = GET_MODE (x);
+  enum machine_mode mode = GET_MODE (x), pmode = Pmode;
   void **slot;
   cselib_val *addr;
   cselib_val *mem_elt;
@@ -1061,8 +1167,11 @@ cselib_lookup_mem (rtx x, int create)
       || (FLOAT_MODE_P (mode) && flag_float_store))
     return 0;
 
+  if (GET_MODE (XEXP (x, 0)) != VOIDmode)
+    pmode = GET_MODE (XEXP (x, 0));
+
   /* Look up the value for the address.  */
-  addr = cselib_lookup (XEXP (x, 0), mode, create);
+  addr = cselib_lookup (XEXP (x, 0), pmode, create, mode);
   if (! addr)
     return 0;
 
@@ -1079,8 +1188,8 @@ cselib_lookup_mem (rtx x, int create)
 
   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;
 }
@@ -1512,10 +1621,11 @@ cselib_expand_value_rtx_1 (rtx orig, str
    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);
@@ -1552,14 +1662,24 @@ cselib_subst_to_values (rtx x)
     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;
@@ -1569,7 +1689,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))
 	    {
@@ -1584,7 +1704,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))
 		{
@@ -1603,13 +1723,16 @@ cselib_subst_to_values (rtx x)
   return copy;
 }
 
-/* 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).  */
+/* 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_lookup_1 (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;
@@ -1658,7 +1781,7 @@ cselib_lookup_1 (rtx x, enum machine_mod
 	  REG_VALUES (i) = new_elt_list (REG_VALUES (i), NULL);
 	}
       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 e;
     }
@@ -1666,13 +1789,13 @@ cselib_lookup_1 (rtx x, enum machine_mod
   if (MEM_P (x))
     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 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 0;
 
@@ -1686,7 +1809,8 @@ cselib_lookup_1 (rtx x, enum machine_mod
      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));
+  e->locs = new_elt_loc_list (e->locs,
+			      cselib_subst_to_values (x, memmode));
   return e;
 }
 
@@ -1694,14 +1818,14 @@ cselib_lookup_1 (rtx x, enum machine_mod
 
 cselib_val *
 cselib_lookup_from_insn (rtx x, enum machine_mode mode,
-			 int create, rtx insn)
+			 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);
+  ret = cselib_lookup (x, mode, create, memmode);
 
   cselib_current_insn = NULL;
 
@@ -1712,9 +1836,10 @@ cselib_lookup_from_insn (rtx x, enum mac
    maintains invariants related with debug insns.  */
 
 cselib_val *
-cselib_lookup (rtx x, enum machine_mode mode, int create)
+cselib_lookup (rtx x, enum machine_mode mode,
+	       int create, enum machine_mode memmode)
 {
-  cselib_val *ret = cselib_lookup_1 (x, mode, create);
+  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?
@@ -1899,7 +2024,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 (;;)
 	    {
@@ -1949,13 +2074,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.  */
@@ -2018,6 +2136,36 @@ cselib_record_set (rtx dest, cselib_val 
    in a PARALLEL.  Since it's fairly cheap, use a really large number.  */
 #define MAX_SETS (FIRST_PSEUDO_REGISTER * 2)
 
+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: SRCBASE 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 srcbase, 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 (srcbase),
+						 srcbase, srcoff);
+  else
+    data->sets[data->n_sets].src = srcbase;
+
+  data->n_sets++;
+
+  return -1;
+}
+
 /* Record the effects of any sets in INSN.  */
 static void
 cselib_record_sets (rtx insn)
@@ -2027,6 +2175,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)
@@ -2070,6 +2220,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++)
@@ -2088,14 +2243,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;
@@ -2110,6 +2266,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
Index: gcc/var-tracking.c
===================================================================
--- gcc/var-tracking.c.orig	2010-09-08 19:59:19.969555893 -0300
+++ gcc/var-tracking.c	2010-09-08 19:59:49.000000000 -0300
@@ -743,7 +743,7 @@ use_narrower_mode_test (rtx *loc, void *
   switch (GET_CODE (*loc))
     {
     case REG:
-      if (cselib_lookup (*loc, GET_MODE (SUBREG_REG (subreg)), 0))
+      if (cselib_lookup (*loc, GET_MODE (SUBREG_REG (subreg)), 0, VOIDmode))
 	return 1;
       return -1;
     case PLUS:
@@ -3984,8 +3984,10 @@ variable_post_merge_new_vals (void **slo
 			 subsequent rounds.  */
 		      cselib_val *v;
 		      gcc_assert (!cselib_lookup (node->loc,
-						  GET_MODE (node->loc), 0));
-		      v = cselib_lookup (node->loc, GET_MODE (node->loc), 1);
+						  GET_MODE (node->loc), 0,
+						  VOIDmode));
+		      v = cselib_lookup (node->loc, GET_MODE (node->loc), 1,
+					 VOIDmode);
 		      cselib_preserve_value (v);
 		      cselib_invalidate_rtx (node->loc);
 		      cval = v->val_rtx;
@@ -4827,7 +4829,7 @@ find_use_val (rtx x, enum machine_mode m
 	      return cui->sets[i].src_elt;
 	}
       else
-	return cselib_lookup (x, mode, 0);
+	return cselib_lookup (x, mode, 0, VOIDmode);
     }
 
   return NULL;
@@ -4856,14 +4858,15 @@ replace_expr_with_values (rtx loc)
   else if (MEM_P (loc))
     {
       cselib_val *addr = cselib_lookup (XEXP (loc, 0),
-					get_address_mode (loc), 0);
+					get_address_mode (loc), 0,
+					GET_MODE (loc));
       if (addr)
 	return replace_equiv_address_nv (loc, addr->val_rtx);
       else
 	return NULL;
     }
   else
-    return cselib_subst_to_values (loc);
+    return cselib_subst_to_values (loc, VOIDmode);
 }
 
 /* Determine what kind of micro operation to choose for a USE.  Return
@@ -4883,7 +4886,8 @@ use_type (rtx loc, struct count_use_info
 	      rtx ploc = PAT_VAR_LOCATION_LOC (loc);
 	      if (! VAR_LOC_UNKNOWN_P (ploc))
 		{
-		  cselib_val *val = cselib_lookup (ploc, GET_MODE (loc), 1);
+		  cselib_val *val = cselib_lookup (ploc, GET_MODE (loc), 1,
+						   VOIDmode);
 
 		  /* ??? flag_float_store and volatile mems are never
 		     given values, but we could in theory use them for
@@ -4905,7 +4909,8 @@ use_type (rtx loc, struct count_use_info
 	      if (REG_P (loc)
 		  || (find_use_val (loc, GET_MODE (loc), cui)
 		      && cselib_lookup (XEXP (loc, 0),
-					get_address_mode (loc), 0)))
+					get_address_mode (loc), 0,
+					GET_MODE (loc))))
 		return MO_VAL_SET;
 	    }
 	  else
@@ -5067,13 +5072,15 @@ add_uses (rtx *ploc, void *data)
 	      rtx mloc = vloc;
 	      enum machine_mode address_mode = get_address_mode (mloc);
 	      cselib_val *val
-		= cselib_lookup (XEXP (mloc, 0), address_mode, 0);
+		= cselib_lookup (XEXP (mloc, 0), address_mode, 0,
+				 GET_MODE (mloc));
 
 	      if (val && !cselib_preserved_value_p (val))
 		{
 		  micro_operation moa;
 		  preserve_value (val);
-		  mloc = cselib_subst_to_values (XEXP (mloc, 0));
+		  mloc = cselib_subst_to_values (XEXP (mloc, 0),
+						 GET_MODE (mloc));
 		  moa.type = MO_VAL_USE;
 		  moa.insn = cui->insn;
 		  moa.u.loc = gen_rtx_CONCAT (address_mode,
@@ -5143,13 +5150,15 @@ add_uses (rtx *ploc, void *data)
 	      rtx mloc = oloc;
 	      enum machine_mode address_mode = get_address_mode (mloc);
 	      cselib_val *val
-		= cselib_lookup (XEXP (mloc, 0), address_mode, 0);
+		= cselib_lookup (XEXP (mloc, 0), address_mode, 0,
+				GET_MODE (mloc));
 
 	      if (val && !cselib_preserved_value_p (val))
 		{
 		  micro_operation moa;
 		  preserve_value (val);
-		  mloc = cselib_subst_to_values (XEXP (mloc, 0));
+		  mloc = cselib_subst_to_values (XEXP (mloc, 0),
+						GET_MODE (mloc));
 		  moa.type = MO_VAL_USE;
 		  moa.insn = cui->insn;
 		  moa.u.loc = gen_rtx_CONCAT (address_mode,
@@ -5259,7 +5268,7 @@ reverse_op (rtx val, const_rtx expr)
   if (!SCALAR_INT_MODE_P (GET_MODE (src)) || XEXP (src, 0) == cfa_base_rtx)
     return NULL_RTX;
 
-  v = cselib_lookup (XEXP (src, 0), GET_MODE (XEXP (src, 0)), 0);
+  v = cselib_lookup (XEXP (src, 0), GET_MODE (XEXP (src, 0)), 0, VOIDmode);
   if (!v || !cselib_preserved_value_p (v))
     return NULL_RTX;
 
@@ -5380,13 +5389,15 @@ add_stores (rtx loc, const_rtx expr, voi
 	  rtx mloc = loc;
 	  enum machine_mode address_mode = get_address_mode (mloc);
 	  cselib_val *val = cselib_lookup (XEXP (mloc, 0),
-					   address_mode, 0);
+					   address_mode, 0,
+					   GET_MODE (mloc));
 
 	  if (val && !cselib_preserved_value_p (val))
 	    {
 	      preserve_value (val);
 	      mo.type = MO_VAL_USE;
-	      mloc = cselib_subst_to_values (XEXP (mloc, 0));
+	      mloc = cselib_subst_to_values (XEXP (mloc, 0),
+					     GET_MODE (mloc));
 	      mo.u.loc = gen_rtx_CONCAT (address_mode, val->val_rtx, mloc);
 	      mo.insn = cui->insn;
 	      if (dump_file && (dump_flags & TDF_DETAILS))
@@ -5445,7 +5456,7 @@ add_stores (rtx loc, const_rtx expr, voi
 
   if (GET_CODE (PATTERN (cui->insn)) == COND_EXEC)
     {
-      cselib_val *oval = cselib_lookup (oloc, GET_MODE (oloc), 0);
+      cselib_val *oval = cselib_lookup (oloc, GET_MODE (oloc), 0, VOIDmode);
 
       gcc_assert (oval != v);
       gcc_assert (REG_P (oloc) || MEM_P (oloc));
@@ -8139,7 +8150,8 @@ vt_add_function_parameters (void)
 	  if (offset)
 	    continue;
 
-	  val = cselib_lookup (var_lowpart (mode, incoming), mode, true);
+	  val = cselib_lookup (var_lowpart (mode, incoming), mode, true,
+			       VOIDmode);
 
 	  /* ??? Float-typed values in memory are not handled by
 	     cselib.  */
@@ -8227,7 +8239,7 @@ vt_init_cfa_base (void)
     return;
 
   val = cselib_lookup_from_insn (cfa_base_rtx, GET_MODE (cfa_base_rtx), 1,
-				 get_insns ());
+				 VOIDmode, get_insns ());
   preserve_value (val);
   cselib_preserve_cfa_base_value (val, REGNO (cfa_base_rtx));
   var_reg_decl_set (&VTI (ENTRY_BLOCK_PTR)->out, cfa_base_rtx,
Index: gcc/sched-deps.c
===================================================================
--- gcc/sched-deps.c.orig	2010-09-08 19:59:48.973554757 -0300
+++ gcc/sched-deps.c	2010-09-08 19:59:49.000000000 -0300
@@ -1562,7 +1562,7 @@ add_insn_mem_dependence (struct deps_des
   if (sched_deps_info->use_cselib)
     {
       mem = shallow_copy_rtx (mem);
-      XEXP (mem, 0) = cselib_subst_to_values (XEXP (mem, 0));
+      XEXP (mem, 0) = cselib_subst_to_values (XEXP (mem, 0), GET_MODE (mem));
     }
   link = alloc_EXPR_LIST (VOIDmode, canon_rtx (mem), *mem_list);
   *mem_list = link;
@@ -2279,8 +2279,9 @@ sched_analyze_1 (struct deps_desc *deps,
 	    = targetm.addr_space.address_mode (MEM_ADDR_SPACE (dest));
 
 	  t = shallow_copy_rtx (dest);
-	  cselib_lookup_from_insn (XEXP (t, 0), address_mode, 1, insn);
-	  XEXP (t, 0) = cselib_subst_to_values (XEXP (t, 0));
+	  cselib_lookup_from_insn (XEXP (t, 0), address_mode, 1,
+				   GET_MODE (dest), insn);
+	  XEXP (t, 0) = cselib_subst_to_values (XEXP (t, 0), GET_MODE (dest));
 	}
       t = canon_rtx (t);
 
@@ -2436,8 +2437,9 @@ sched_analyze_2 (struct deps_desc *deps,
 	      = targetm.addr_space.address_mode (MEM_ADDR_SPACE (t));
 
 	    t = shallow_copy_rtx (t);
-	    cselib_lookup_from_insn (XEXP (t, 0), address_mode, 1, insn);
-	    XEXP (t, 0) = cselib_subst_to_values (XEXP (t, 0));
+	    cselib_lookup_from_insn (XEXP (t, 0), address_mode, 1,
+				     GET_MODE (x), insn);
+	    XEXP (t, 0) = cselib_subst_to_values (XEXP (t, 0), GET_MODE (x));
 	  }
 
 	if (!DEBUG_INSN_P (insn))
Index: gcc/gcse.c
===================================================================
--- gcc/gcse.c.orig	2010-09-08 19:59:19.000000000 -0300
+++ gcc/gcse.c	2010-09-08 19:59:49.000000000 -0300
@@ -2740,7 +2740,7 @@ do_local_cprop (rtx x, rtx insn)
           || (GET_CODE (PATTERN (insn)) != USE
 	      && asm_noperands (PATTERN (insn)) < 0)))
     {
-      cselib_val *val = cselib_lookup (x, GET_MODE (x), 0);
+      cselib_val *val = cselib_lookup (x, GET_MODE (x), 0, VOIDmode);
       struct elt_loc_list *l;
 
       if (!val)
Index: gcc/postreload.c
===================================================================
--- gcc/postreload.c.orig	2010-09-08 19:59:18.660291727 -0300
+++ gcc/postreload.c	2010-09-08 19:59:49.417177720 -0300
@@ -263,7 +263,7 @@ reload_cse_simplify_set (rtx set, rtx in
     return 0;
 #endif
 
-  val = cselib_lookup (src, GET_MODE (SET_DEST (set)), 0);
+  val = cselib_lookup (src, GET_MODE (SET_DEST (set)), 0, VOIDmode);
   if (! val)
     return 0;
 
@@ -477,7 +477,7 @@ reload_cse_simplify_operands (rtx insn, 
 	    continue;
 	}
 #endif /* LOAD_EXTEND_OP */
-      v = cselib_lookup (op, recog_data.operand_mode[i], 0);
+      v =  cselib_lookup (op, recog_data.operand_mode[i], 0, VOIDmode);
       if (! v)
 	continue;
 
Index: gcc/sel-sched-dump.c
===================================================================
--- gcc/sel-sched-dump.c.orig	2010-09-08 19:59:19.000000000 -0300
+++ gcc/sel-sched-dump.c	2010-09-08 19:59:49.000000000 -0300
@@ -961,8 +961,8 @@ debug_mem_addr_value (rtx x)
   address_mode = targetm.addr_space.address_mode (MEM_ADDR_SPACE (x));
 
   t = shallow_copy_rtx (x);
-  if (cselib_lookup (XEXP (t, 0), address_mode, 0))
-    XEXP (t, 0) = cselib_subst_to_values (XEXP (t, 0));
+  if (cselib_lookup (XEXP (t, 0), address_mode, 0, GET_MODE (x)))
+    XEXP (t, 0) = cselib_subst_to_values (XEXP (t, 0), GET_MODE (x));
 
   t = canon_rtx (t);
   addr = get_addr (XEXP (t, 0));

[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #3: vta-cselib-autoinc-optional.patch --]
[-- Type: text/x-diff, Size: 6546 bytes --]

for  gcc/ChangeLog
from  Alexandre Oliva  <aoliva@redhat.com>

	PR debug/43092
	PR debug/43494
	* cselib.h (CSELIB_RECORD_AUTOINC): New enumerator.
	* cselib.c (cselib_record_autoinc): New var.
	(rtx_equal_for_cselib_1): Test it.
	(cselib_hash_rtx): Likewise.
	(cselib_subst_to_values): Likewise.
	(cselib_record_sets): Likewise.  Move autoinc data into conditional.
	(cselib_init): Initialize cselib_record_autoinc.
	* var-tracking.c (vt_initialize): Pass CSELIB_RECORD_AUTOINC to
	cselib_init.

Index: gcc/cselib.h
===================================================================
--- gcc/cselib.h.orig	2010-09-10 20:24:28.000000000 -0300
+++ gcc/cselib.h	2010-09-10 20:26:34.000000000 -0300
@@ -69,7 +69,8 @@ struct cselib_set
 enum cselib_record_what
 {
   CSELIB_RECORD_MEMORY = 1,
-  CSELIB_PRESERVE_CONSTANTS = 2
+  CSELIB_PRESERVE_CONSTANTS = 2,
+  CSELIB_RECORD_AUTOINC = 4
 };
 
 extern void (*cselib_discard_hook) (cselib_val *);
Index: gcc/cselib.c
===================================================================
--- gcc/cselib.c.orig	2010-09-10 20:24:28.000000000 -0300
+++ gcc/cselib.c	2010-09-10 20:28:29.000000000 -0300
@@ -47,6 +47,7 @@ along with GCC; see the file COPYING3.  
 
 static bool cselib_record_memory;
 static bool cselib_preserve_constants;
+static bool cselib_record_autoinc;
 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 *);
@@ -764,6 +765,9 @@ rtx_equal_for_cselib_1 (rtx x, rtx y, en
       rtx xorig = x, yorig = y;
       rtx xoff = NULL, yoff = NULL;
 
+      if (!cselib_record_autoinc)
+	return 0;
+
       x = autoinc_split (x, &xoff, memmode);
       y = autoinc_split (y, &yoff, memmode);
 
@@ -988,6 +992,8 @@ cselib_hash_rtx (rtx x, int create, enum
     case PRE_DEC:
     case PRE_INC:
       /* We can't compute these without knowing the MEM mode.  */
+      if (!cselib_record_autoinc)
+	return 0;
       gcc_assert (memmode != VOIDmode);
       i = GET_MODE_SIZE (memmode);
       if (code == PRE_DEC)
@@ -998,12 +1004,16 @@ cselib_hash_rtx (rtx x, int create, enum
       return hash ? hash : 1 + (unsigned) PLUS;
 
     case PRE_MODIFY:
+      if (!cselib_record_autoinc)
+	return 0;
       gcc_assert (memmode != VOIDmode);
       return cselib_hash_rtx (XEXP (x, 1), create, memmode);
 
     case POST_DEC:
     case POST_INC:
     case POST_MODIFY:
+      if (!cselib_record_autoinc)
+	return 0;
       gcc_assert (memmode != VOIDmode);
       return cselib_hash_rtx (XEXP (x, 0), create, memmode);
 
@@ -1622,7 +1632,8 @@ cselib_expand_value_rtx_1 (rtx orig, str
    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.
-   If X is within a MEM, MEMMODE must be the mode of the MEM.  */
+   If X is within a MEM, MEMMODE must be the mode of the MEM if
+   cselib_record_autoinc holds.  */
 
 rtx
 cselib_subst_to_values (rtx x, enum machine_mode memmode)
@@ -1664,6 +1675,12 @@ cselib_subst_to_values (rtx x, enum mach
 
     case PRE_DEC:
     case PRE_INC:
+      if (!cselib_record_autoinc)
+	{
+	no_autoinc:
+	  e = new_cselib_val (next_uid, GET_MODE (x), x);
+	  return e->val_rtx;
+	}
       gcc_assert (memmode != VOIDmode);
       i = GET_MODE_SIZE (memmode);
       if (code == PRE_DEC)
@@ -1672,12 +1689,16 @@ cselib_subst_to_values (rtx x, enum mach
 				     memmode);
 
     case PRE_MODIFY:
+      if (!cselib_record_autoinc)
+	goto no_autoinc;
       gcc_assert (memmode != VOIDmode);
       return cselib_subst_to_values (XEXP (x, 1), memmode);
 
     case POST_DEC:
     case POST_INC:
     case POST_MODIFY:
+      if (!cselib_record_autoinc)
+	goto no_autoinc;
       gcc_assert (memmode != VOIDmode);
       return cselib_subst_to_values (XEXP (x, 0), memmode);
 
@@ -2074,6 +2095,13 @@ 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 (!cselib_record_autoinc && push_operand (dest, GET_MODE (dest)))
+    cselib_invalidate_rtx (stack_pointer_rtx);
 }
 
 /* A wrapper for cselib_invalidate_rtx to be called via note_stores.  */
@@ -2176,7 +2204,6 @@ cselib_record_sets (rtx insn)
   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)
@@ -2220,10 +2247,16 @@ 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;
+  if (cselib_record_autoinc)
+    {
+      struct cselib_record_autoinc_data data;
+      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;
+    }
+  else
+    n_sets_before_autoinc = n_sets;
 
   /* Look up the values that are read.  Do this before invalidating the
      locations that are written.  */
@@ -2397,6 +2430,7 @@ cselib_init (int record_what)
   value_pool = create_alloc_pool ("value", RTX_CODE_SIZE (VALUE), 100);
   cselib_record_memory = record_what & CSELIB_RECORD_MEMORY;
   cselib_preserve_constants = record_what & CSELIB_PRESERVE_CONSTANTS;
+  cselib_record_autoinc = record_what & CSELIB_RECORD_AUTOINC;
 
   /* (mem:BLK (scratch)) is a special mechanism to conflict with everything,
      see canon_true_dependence.  This is only created once.  */
Index: gcc/var-tracking.c
===================================================================
--- gcc/var-tracking.c.orig	2010-09-10 20:24:28.000000000 -0300
+++ gcc/var-tracking.c	2010-09-10 20:26:34.000000000 -0300
@@ -8297,7 +8297,8 @@ vt_initialize (void)
 
   if (MAY_HAVE_DEBUG_INSNS)
     {
-      cselib_init (CSELIB_RECORD_MEMORY | CSELIB_PRESERVE_CONSTANTS);
+      cselib_init (CSELIB_RECORD_MEMORY | CSELIB_PRESERVE_CONSTANTS
+		   | CSELIB_RECORD_AUTOINC);
       scratch_regs = BITMAP_ALLOC (NULL);
       valvar_pool = create_alloc_pool ("small variable_def pool",
 				       sizeof (struct variable_def), 256);

[-- Attachment #4: Type: text/plain, Size: 257 bytes --]


-- 
Alexandre Oliva, freedom fighter    http://FSFLA.org/~lxoliva/
You must be the change you wish to see in the world. -- Gandhi
Be Free! -- http://FSFLA.org/   FSF Latin America board member
Free Software Evangelist      Red Hat Brazil Compiler Engineer

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH] Fix VTA sp (and fp) based MEM handling (PR debug/43051, PR debug/43092)
  2010-09-11  1:17   ` Alexandre Oliva
@ 2010-09-11 12:41     ` Steven Bosscher
  2010-09-21 11:45       ` Alexandre Oliva
  0 siblings, 1 reply; 10+ messages in thread
From: Steven Bosscher @ 2010-09-11 12:41 UTC (permalink / raw)
  To: Alexandre Oliva; +Cc: Jakub Jelinek, bernds, Richard Guenther, gcc-patches

On Sat, Sep 11, 2010 at 1:34 AM, Alexandre Oliva <aoliva@redhat.com> wrote:
> The first patch implements unconditional autoinc support in cselib.  I
> have regstrapped it on x86_64-linux-gnu and i686-linux-gnu.  Ok to
> install?

You should document what the arguments are here:

>  +typedef int (*for_each_inc_dec_fn) (rtx, rtx, rtx, rtx, rtx, void *);

and here too:

> +int
> +for_each_inc_dec (rtx *insn,
> +		  for_each_inc_dec_fn fn,
> +		  void *arg)

Looks like INSN doesn't have to be an insn, so maybe not call the
argument INSN but X just like in for_each_rtx.


> -	    cselib_lookup_from_insn (XEXP (t, 0), address_mode, 1, insn);
> -	    XEXP (t, 0) = cselib_subst_to_values (XEXP (t, 0));
> +	    cselib_lookup_from_insn (XEXP (t, 0), address_mode, 1,
> +				     GET_MODE (x), insn);
> +	    XEXP (t, 0) = cselib_subst_to_values (XEXP (t, 0), GET_MODE (x));

GET_MODE (t)?  I know t is a copy of x at this point so it makes no
real difference, but the existing code looks at the properties of t
here and IMHO it would be better to be consistent about that.
Likewise in the hunk for sel-sched-dump.c

Thanks for working on this,

Ciao!
Steven

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH] Fix VTA sp (and fp) based MEM handling (PR debug/43051, PR debug/43092)
  2010-09-11 12:41     ` Steven Bosscher
@ 2010-09-21 11:45       ` Alexandre Oliva
  2011-01-19 22:27         ` [PATCH] Fix VTA sp (and fp) based MEM handling (PR debug/43051, PR debug/43092) and also PR debug/43494 Alexandre Oliva
  0 siblings, 1 reply; 10+ messages in thread
From: Alexandre Oliva @ 2010-09-21 11:45 UTC (permalink / raw)
  To: Steven Bosscher; +Cc: Jakub Jelinek, bernds, Richard Guenther, gcc-patches

[-- Attachment #1: Type: text/plain, Size: 527 bytes --]

On Sep 11, 2010, Steven Bosscher <stevenb.gcc@gmail.com> wrote:

> You should document what the arguments are here:

> Looks like INSN doesn't have to be an insn, so maybe not call the
> argument INSN but X just like in for_each_rtx.

> GET_MODE (t)?  I know t is a copy of x at this point so it makes no
> real difference, but the existing code looks at the properties of t
> here and IMHO it would be better to be consistent about that.
> Likewise in the hunk for sel-sched-dump.c

Thanks, fixed, re-tested.  Ok to install?


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: vta-cselib-autoinc-pr43092.patch --]
[-- Type: text/x-diff, Size: 39349 bytes --]

for  gcc/ChangeLog
from  Alexandre Oliva  <aoliva@redhat.com>

	PR debug/43092
	PR debug/43494
	* rtl.h (for_each_inc_dec_fn): New type.
	(for_each_inc_dec): Declare.
	* rtlanal.c (struct for_each_inc_dec_ops): New type.
	(for_each_inc_dec_find_inc_dec): New fn.
	(for_each_inc_dec_find_mem): New fn.
	(for_each_inc_dec): New fn.
	* dse.c (struct insn_size): Remove.
	(replace_inc_dec, replace_inc_dec_mem): Remove.
	(emit_inc_dec_insn_before): New fn.
	(check_for_inc_dec): Use it, along with for_each_inc_dec.
	(canon_address): Pass mem modes to cselib_lookup.
	* cselib.h (cselib_lookup): Add memmode argument.  Adjust callers.
	(cselib_lookup_from_insn): Likewise.
	(cselib_subst_to_values): Likewise.
	* cselib.c (find_slot_memmode): New var.
	(cselib_find_slot): New fn.  Use it instead of
	htab_find_slot_with_hash everywhere.
	(entry_and_rtx_equal_p): Use find_slot_memmode.
	(autoinc_split): New fn.
	(rtx_equal_for_cselib_p): Rename and implement in terms of...
	(rtx_equal_for_cselib_1): ... this.  Take memmode, pass it on.
	Deal with autoinc.  Special-case recursion into MEMs.
	(cselib_hash_rtx): Likewise.
	(cselib_lookup_mem): Infer pmode from address mode.  Distinguish
	address and MEM modes.
	(cselib_subst_to_values): Add memmode, pass it on.
	Deal with autoinc.
	(cselib_lookup): Add memmode argument, pass it on.
	(cselib_lookup_from_insn): Add memmode.
	(struct cselib_record_autoinc_data): New.
	(cselib_record_autoinc_cb): New fn.
	(cselib_record_sets): Use it, along with for_each_inc_dec.  Pass MEM
	mode to cselib_lookup.
	* var-tracking.c (replace_expr_with_values, use_type): Pass MEM mode
	to cselib_lookup.
	(add_uses): Likewise, also to cselib_subst_to_values.
	(add_stores): Likewise.
	* sched-deps.c 	(add_insn_mem_dependence): Pass mode to
	cselib_subst_to_values.
	(sched_analyze_1, sched_analyze_2): Likewise.  Adjusted.
	* gcse.c (do_local_cprop): Adjusted.
	* postreload.c (reload_cse_simplify_set): Adjusted.
	(reload_cse_simplify_operands): Adjusted.
	* sel-sched-dump (debug_mem_addr_value): Pass mode.

Index: gcc/rtl.h
===================================================================
--- gcc/rtl.h.orig	2010-09-13 00:27:04.105870812 -0300
+++ gcc/rtl.h	2010-09-13 01:05:15.222438247 -0300
@@ -1865,6 +1865,17 @@ extern int computed_jump_p (const_rtx);
 typedef int (*rtx_function) (rtx *, void *);
 extern int for_each_rtx (rtx *, rtx_function, void *);
 
+/* Callback for for_each_inc_dec, to process the autoinc operation OP
+   within MEM.  It sets DEST to SRC + SRCOFF, or SRC if SRCOFF is
+   NULL.  The callback is passed the same opaque ARG passed to
+   for_each_inc_dec.  Return zero to continue looking for other
+   autoinc operations, -1 to skip OP's operands, and any other value
+   to interrupt the traversal and return that value to the caller of
+   for_each_inc_dec.  */
+typedef int (*for_each_inc_dec_fn) (rtx mem, rtx op, rtx dest, rtx src,
+				    rtx srcoff, void *arg);
+extern int for_each_inc_dec (rtx *, for_each_inc_dec_fn, void *arg);
+
 typedef int (*rtx_equal_p_callback_function) (const_rtx *, const_rtx *,
                                               rtx *, rtx *);
 extern int rtx_equal_p_cb (const_rtx, const_rtx,
Index: gcc/rtlanal.c
===================================================================
--- gcc/rtlanal.c.orig	2010-09-13 00:27:04.107867962 -0300
+++ gcc/rtlanal.c	2010-09-13 01:11:25.850435956 -0300
@@ -2866,7 +2866,122 @@ for_each_rtx (rtx *x, rtx_function f, vo
   return for_each_rtx_1 (*x, i, f, data);
 }
 
+\f
+
+/* Data structure that holds the internal state communicated between
+   for_each_inc_dec, for_each_inc_dec_find_mem and
+   for_each_inc_dec_find_inc_dec.  */
+
+struct for_each_inc_dec_ops {
+  /* The function to be called for each autoinc operation found.  */
+  for_each_inc_dec_fn fn;
+  /* The opaque argument to be passed to it.  */
+  void *arg;
+  /* The MEM we're visiting, if any.  */
+  rtx mem;
+};
+
+static int for_each_inc_dec_find_mem (rtx *r, void *d);
 
+/* Add an insn to do the add inside a x if it is a
+   PRE/POST-INC/DEC/MODIFY.  D is an structure containing the insn and
+   the size of the mode of the MEM that this is inside of.  */
+
+static int
+for_each_inc_dec_find_inc_dec (rtx *r, void *d)
+{
+  rtx x = *r;
+  struct for_each_inc_dec_ops *data = (struct for_each_inc_dec_ops *)d;
+  int size = GET_MODE_SIZE (GET_MODE (data->mem));
+
+  switch (GET_CODE (x))
+    {
+    case PRE_INC:
+    case POST_INC:
+      {
+	rtx r1 = XEXP (x, 0);
+	rtx c = gen_int_mode (size, GET_MODE (r1));
+	return data->fn (data->mem, x, r1, r1, c, data->arg);
+      }
+
+    case PRE_DEC:
+    case POST_DEC:
+      {
+	rtx r1 = XEXP (x, 0);
+	rtx c = gen_int_mode (-size, GET_MODE (r1));
+	return data->fn (data->mem, x, r1, r1, c, data->arg);
+      }
+
+    case PRE_MODIFY:
+    case POST_MODIFY:
+      {
+	rtx r1 = XEXP (x, 0);
+	rtx add = XEXP (x, 1);
+	return data->fn (data->mem, x, r1, add, NULL, data->arg);
+      }
+
+    case MEM:
+      {
+	rtx save = data->mem;
+	int ret = for_each_inc_dec_find_mem (r, d);
+	data->mem = save;
+	return ret;
+      }
+
+    default:
+      return 0;
+    }
+}
+
+/* If X is a MEM, check the address to see if it is PRE/POST-INC/DEC/MODIFY
+   and generate an add to replace that.  */
+
+static int
+for_each_inc_dec_find_mem (rtx *r, void *d)
+{
+  rtx x = *r;
+  if (x != NULL_RTX && MEM_P (x))
+    {
+      struct for_each_inc_dec_ops *data = (struct for_each_inc_dec_ops *) d;
+      int result;
+
+      data->mem = x;
+
+      result = for_each_rtx (&XEXP (x, 0), for_each_inc_dec_find_inc_dec,
+			     data);
+      if (result)
+	return result;
+
+      return -1;
+    }
+  return 0;
+}
+
+/* Traverse *X looking for MEMs, and for autoinc operations within
+   them.  For each such autoinc operation found, call FN, passing it
+   the innermost enclosing MEM, the operation itself, the RTX modified
+   by the operation, two RTXs (the second may be NULL) that, once
+   added, represent the value to be held by the modified RTX
+   afterwards, and ARG.  FN is to return -1 to skip looking for other
+   autoinc operations within the visited operation, 0 to continue the
+   traversal, or any other value to have it returned to the caller of
+   for_each_inc_dec.  */
+
+int
+for_each_inc_dec (rtx *x,
+		  for_each_inc_dec_fn fn,
+		  void *arg)
+{
+  struct for_each_inc_dec_ops data;
+
+  data.fn = fn;
+  data.arg = arg;
+  data.mem = NULL;
+
+  return for_each_rtx (x, for_each_inc_dec_find_mem, &data);
+}
+
+\f
 /* Searches X for any reference to REGNO, returning the rtx of the
    reference found if any.  Otherwise, returns NULL_RTX.  */
 
Index: gcc/dse.c
===================================================================
--- gcc/dse.c.orig	2010-09-13 00:27:04.106861222 -0300
+++ gcc/dse.c	2010-09-13 00:42:55.475436829 -0300
@@ -807,81 +807,22 @@ free_store_info (insn_info_t insn_info)
 }
 
 
-struct insn_size {
-  int size;
-  rtx insn;
-};
-
-
-/* Add an insn to do the add inside a x if it is a
-   PRE/POST-INC/DEC/MODIFY.  D is an structure containing the insn and
-   the size of the mode of the MEM that this is inside of.  */
-
 static int
-replace_inc_dec (rtx *r, void *d)
+emit_inc_dec_insn_before (rtx mem ATTRIBUTE_UNUSED,
+			  rtx op ATTRIBUTE_UNUSED,
+			  rtx dest, rtx src, rtx srcoff, void *arg)
 {
-  rtx x = *r;
-  struct insn_size *data = (struct insn_size *)d;
-  switch (GET_CODE (x))
-    {
-    case PRE_INC:
-    case POST_INC:
-      {
-	rtx r1 = XEXP (x, 0);
-	rtx c = gen_int_mode (data->size, GET_MODE (r1));
-	emit_insn_before (gen_rtx_SET (VOIDmode, r1,
-				       gen_rtx_PLUS (GET_MODE (r1), r1, c)),
-			  data->insn);
-	return -1;
-      }
-
-    case PRE_DEC:
-    case POST_DEC:
-      {
-	rtx r1 = XEXP (x, 0);
-	rtx c = gen_int_mode (-data->size, GET_MODE (r1));
-	emit_insn_before (gen_rtx_SET (VOIDmode, r1,
-				       gen_rtx_PLUS (GET_MODE (r1), r1, c)),
-			  data->insn);
-	return -1;
-      }
-
-    case PRE_MODIFY:
-    case POST_MODIFY:
-      {
-	/* We can reuse the add because we are about to delete the
-	   insn that contained it.  */
-	rtx add = XEXP (x, 0);
-	rtx r1 = XEXP (add, 0);
-	emit_insn_before (gen_rtx_SET (VOIDmode, r1, add), data->insn);
-	return -1;
-      }
+  rtx insn = (rtx)arg;
 
-    default:
-      return 0;
-    }
-}
+  if (srcoff)
+    src = gen_rtx_PLUS (GET_MODE (src), src, srcoff);
 
+  /* We can reuse all operands without copying, because we are about
+     to delete the insn that contained it.  */
 
-/* If X is a MEM, check the address to see if it is PRE/POST-INC/DEC/MODIFY
-   and generate an add to replace that.  */
+  emit_insn_before (gen_rtx_SET (VOIDmode, dest, src), insn);
 
-static int
-replace_inc_dec_mem (rtx *r, void *d)
-{
-  rtx x = *r;
-  if (x != NULL_RTX && MEM_P (x))
-    {
-      struct insn_size data;
-
-      data.size = GET_MODE_SIZE (GET_MODE (x));
-      data.insn = (rtx) d;
-
-      for_each_rtx (&XEXP (x, 0), replace_inc_dec, &data);
-
-      return -1;
-    }
-  return 0;
+  return -1;
 }
 
 /* Before we delete INSN, make sure that the auto inc/dec, if it is
@@ -892,7 +833,7 @@ check_for_inc_dec (rtx insn)
 {
   rtx note = find_reg_note (insn, REG_INC, NULL_RTX);
   if (note)
-    for_each_rtx (&insn, replace_inc_dec_mem, insn);
+    for_each_inc_dec (&insn, emit_inc_dec_insn_before, insn);
 }
 
 
@@ -1107,7 +1048,7 @@ canon_address (rtx mem,
 
   *alias_set_out = 0;
 
-  cselib_lookup (mem_address, address_mode, 1);
+  cselib_lookup (mem_address, address_mode, 1, GET_MODE (mem));
 
   if (dump_file)
     {
@@ -1187,7 +1128,7 @@ canon_address (rtx mem,
 	}
     }
 
-  *base = cselib_lookup (address, address_mode, true);
+  *base = cselib_lookup (address, address_mode, true, GET_MODE (mem));
   *group_id = -1;
 
   if (*base == NULL)
Index: gcc/cselib.h
===================================================================
--- gcc/cselib.h.orig	2010-09-13 00:27:04.107867962 -0300
+++ gcc/cselib.h	2010-09-13 00:42:55.496486558 -0300
@@ -76,8 +76,10 @@ extern void (*cselib_discard_hook) (csel
 extern void (*cselib_record_sets_hook) (rtx insn, struct cselib_set *sets,
 					int n_sets);
 
-extern cselib_val *cselib_lookup (rtx, enum machine_mode, int);
-extern cselib_val *cselib_lookup_from_insn (rtx, enum machine_mode, int, rtx);
+extern cselib_val *cselib_lookup (rtx, enum machine_mode,
+				  int, enum machine_mode);
+extern cselib_val *cselib_lookup_from_insn (rtx, enum machine_mode,
+					    int, enum machine_mode, rtx);
 extern void cselib_init (int);
 extern void cselib_clear_table (void);
 extern void cselib_finish (void);
@@ -91,7 +93,7 @@ extern rtx cselib_expand_value_rtx_cb (r
 				       cselib_expand_callback, void *);
 extern bool cselib_dummy_expand_value_rtx_cb (rtx, bitmap, int,
 					      cselib_expand_callback, void *);
-extern rtx cselib_subst_to_values (rtx);
+extern rtx cselib_subst_to_values (rtx, enum machine_mode);
 extern void cselib_invalidate_rtx (rtx);
 
 extern void cselib_reset_table (unsigned int);
Index: gcc/cselib.c
===================================================================
--- gcc/cselib.c.orig	2010-09-13 00:27:04.106861222 -0300
+++ gcc/cselib.c	2010-09-13 01:29:34.145850451 -0300
@@ -57,7 +57,8 @@ static void unchain_one_elt_loc_list (st
 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);
@@ -385,6 +386,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
@@ -414,7 +435,7 @@ entry_and_rtx_equal_p (const void *entry
   /* 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))
+    if (rtx_equal_for_cselib_1 (l->loc, x, find_slot_memmode))
       {
 	promote_debug_loc (l);
 	return 1;
@@ -626,13 +647,59 @@ 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;
+    }
+}
+
+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;
@@ -640,7 +707,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;
@@ -664,7 +731,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;
 	}
 
@@ -682,16 +749,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))
     {
@@ -707,6 +795,11 @@ rtx_equal_for_cselib_p (rtx x, rtx 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;
     }
@@ -739,18 +832,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;
 
@@ -802,6 +895,8 @@ wrap_constant (enum machine_mode mode, r
    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 auto-inc 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))
@@ -812,7 +907,7 @@ wrap_constant (enum machine_mode mode, r
    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;
@@ -827,7 +922,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;
 
@@ -873,7 +968,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;
@@ -906,10 +1001,26 @@ 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;
+      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:
@@ -935,7 +1046,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;
@@ -947,7 +1058,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;
@@ -1059,7 +1170,7 @@ add_mem_for_addr (cselib_val *addr_elt, 
 static cselib_val *
 cselib_lookup_mem (rtx x, int create)
 {
-  enum machine_mode mode = GET_MODE (x);
+  enum machine_mode mode = GET_MODE (x), pmode = Pmode;
   void **slot;
   cselib_val *addr;
   cselib_val *mem_elt;
@@ -1070,8 +1181,11 @@ cselib_lookup_mem (rtx x, int create)
       || (FLOAT_MODE_P (mode) && flag_float_store))
     return 0;
 
+  if (GET_MODE (XEXP (x, 0)) != VOIDmode)
+    pmode = GET_MODE (XEXP (x, 0));
+
   /* Look up the value for the address.  */
-  addr = cselib_lookup (XEXP (x, 0), mode, create);
+  addr = cselib_lookup (XEXP (x, 0), pmode, create, mode);
   if (! addr)
     return 0;
 
@@ -1088,8 +1202,8 @@ cselib_lookup_mem (rtx x, int create)
 
   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;
 }
@@ -1521,10 +1635,11 @@ cselib_expand_value_rtx_1 (rtx orig, str
    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);
@@ -1561,14 +1676,24 @@ cselib_subst_to_values (rtx x)
     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;
@@ -1578,7 +1703,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))
 	    {
@@ -1593,7 +1718,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))
 		{
@@ -1612,13 +1737,16 @@ cselib_subst_to_values (rtx x)
   return copy;
 }
 
-/* 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).  */
+/* 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_lookup_1 (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;
@@ -1667,7 +1795,7 @@ cselib_lookup_1 (rtx x, enum machine_mod
 	  REG_VALUES (i) = new_elt_list (REG_VALUES (i), NULL);
 	}
       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 e;
     }
@@ -1675,13 +1803,13 @@ cselib_lookup_1 (rtx x, enum machine_mod
   if (MEM_P (x))
     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 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 0;
 
@@ -1695,7 +1823,8 @@ cselib_lookup_1 (rtx x, enum machine_mod
      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));
+  e->locs = new_elt_loc_list (e->locs,
+			      cselib_subst_to_values (x, memmode));
   return e;
 }
 
@@ -1703,14 +1832,14 @@ cselib_lookup_1 (rtx x, enum machine_mod
 
 cselib_val *
 cselib_lookup_from_insn (rtx x, enum machine_mode mode,
-			 int create, rtx insn)
+			 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);
+  ret = cselib_lookup (x, mode, create, memmode);
 
   cselib_current_insn = NULL;
 
@@ -1721,9 +1850,10 @@ cselib_lookup_from_insn (rtx x, enum mac
    maintains invariants related with debug insns.  */
 
 cselib_val *
-cselib_lookup (rtx x, enum machine_mode mode, int create)
+cselib_lookup (rtx x, enum machine_mode mode,
+	       int create, enum machine_mode memmode)
 {
-  cselib_val *ret = cselib_lookup_1 (x, mode, create);
+  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?
@@ -1908,7 +2038,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 (;;)
 	    {
@@ -1958,13 +2088,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.  */
@@ -2027,6 +2150,36 @@ cselib_record_set (rtx dest, cselib_val 
    in a PARALLEL.  Since it's fairly cheap, use a really large number.  */
 #define MAX_SETS (FIRST_PSEUDO_REGISTER * 2)
 
+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: SRCBASE 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 srcbase, 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 (srcbase),
+						 srcbase, srcoff);
+  else
+    data->sets[data->n_sets].src = srcbase;
+
+  data->n_sets++;
+
+  return -1;
+}
+
 /* Record the effects of any sets in INSN.  */
 static void
 cselib_record_sets (rtx insn)
@@ -2036,6 +2189,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)
@@ -2079,6 +2234,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++)
@@ -2097,14 +2257,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;
@@ -2119,6 +2280,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
Index: gcc/var-tracking.c
===================================================================
--- gcc/var-tracking.c.orig	2010-09-13 00:27:04.107867962 -0300
+++ gcc/var-tracking.c	2010-09-13 00:42:55.674600787 -0300
@@ -743,7 +743,7 @@ use_narrower_mode_test (rtx *loc, void *
   switch (GET_CODE (*loc))
     {
     case REG:
-      if (cselib_lookup (*loc, GET_MODE (SUBREG_REG (subreg)), 0))
+      if (cselib_lookup (*loc, GET_MODE (SUBREG_REG (subreg)), 0, VOIDmode))
 	return 1;
       return -1;
     case PLUS:
@@ -3984,8 +3984,10 @@ variable_post_merge_new_vals (void **slo
 			 subsequent rounds.  */
 		      cselib_val *v;
 		      gcc_assert (!cselib_lookup (node->loc,
-						  GET_MODE (node->loc), 0));
-		      v = cselib_lookup (node->loc, GET_MODE (node->loc), 1);
+						  GET_MODE (node->loc), 0,
+						  VOIDmode));
+		      v = cselib_lookup (node->loc, GET_MODE (node->loc), 1,
+					 VOIDmode);
 		      cselib_preserve_value (v);
 		      cselib_invalidate_rtx (node->loc);
 		      cval = v->val_rtx;
@@ -4827,7 +4829,7 @@ find_use_val (rtx x, enum machine_mode m
 	      return cui->sets[i].src_elt;
 	}
       else
-	return cselib_lookup (x, mode, 0);
+	return cselib_lookup (x, mode, 0, VOIDmode);
     }
 
   return NULL;
@@ -4856,14 +4858,15 @@ replace_expr_with_values (rtx loc)
   else if (MEM_P (loc))
     {
       cselib_val *addr = cselib_lookup (XEXP (loc, 0),
-					get_address_mode (loc), 0);
+					get_address_mode (loc), 0,
+					GET_MODE (loc));
       if (addr)
 	return replace_equiv_address_nv (loc, addr->val_rtx);
       else
 	return NULL;
     }
   else
-    return cselib_subst_to_values (loc);
+    return cselib_subst_to_values (loc, VOIDmode);
 }
 
 /* Determine what kind of micro operation to choose for a USE.  Return
@@ -4883,7 +4886,8 @@ use_type (rtx loc, struct count_use_info
 	      rtx ploc = PAT_VAR_LOCATION_LOC (loc);
 	      if (! VAR_LOC_UNKNOWN_P (ploc))
 		{
-		  cselib_val *val = cselib_lookup (ploc, GET_MODE (loc), 1);
+		  cselib_val *val = cselib_lookup (ploc, GET_MODE (loc), 1,
+						   VOIDmode);
 
 		  /* ??? flag_float_store and volatile mems are never
 		     given values, but we could in theory use them for
@@ -4905,7 +4909,8 @@ use_type (rtx loc, struct count_use_info
 	      if (REG_P (loc)
 		  || (find_use_val (loc, GET_MODE (loc), cui)
 		      && cselib_lookup (XEXP (loc, 0),
-					get_address_mode (loc), 0)))
+					get_address_mode (loc), 0,
+					GET_MODE (loc))))
 		return MO_VAL_SET;
 	    }
 	  else
@@ -5067,13 +5072,15 @@ add_uses (rtx *ploc, void *data)
 	      rtx mloc = vloc;
 	      enum machine_mode address_mode = get_address_mode (mloc);
 	      cselib_val *val
-		= cselib_lookup (XEXP (mloc, 0), address_mode, 0);
+		= cselib_lookup (XEXP (mloc, 0), address_mode, 0,
+				 GET_MODE (mloc));
 
 	      if (val && !cselib_preserved_value_p (val))
 		{
 		  micro_operation moa;
 		  preserve_value (val);
-		  mloc = cselib_subst_to_values (XEXP (mloc, 0));
+		  mloc = cselib_subst_to_values (XEXP (mloc, 0),
+						 GET_MODE (mloc));
 		  moa.type = MO_VAL_USE;
 		  moa.insn = cui->insn;
 		  moa.u.loc = gen_rtx_CONCAT (address_mode,
@@ -5143,13 +5150,15 @@ add_uses (rtx *ploc, void *data)
 	      rtx mloc = oloc;
 	      enum machine_mode address_mode = get_address_mode (mloc);
 	      cselib_val *val
-		= cselib_lookup (XEXP (mloc, 0), address_mode, 0);
+		= cselib_lookup (XEXP (mloc, 0), address_mode, 0,
+				GET_MODE (mloc));
 
 	      if (val && !cselib_preserved_value_p (val))
 		{
 		  micro_operation moa;
 		  preserve_value (val);
-		  mloc = cselib_subst_to_values (XEXP (mloc, 0));
+		  mloc = cselib_subst_to_values (XEXP (mloc, 0),
+						GET_MODE (mloc));
 		  moa.type = MO_VAL_USE;
 		  moa.insn = cui->insn;
 		  moa.u.loc = gen_rtx_CONCAT (address_mode,
@@ -5259,7 +5268,7 @@ reverse_op (rtx val, const_rtx expr)
   if (!SCALAR_INT_MODE_P (GET_MODE (src)) || XEXP (src, 0) == cfa_base_rtx)
     return NULL_RTX;
 
-  v = cselib_lookup (XEXP (src, 0), GET_MODE (XEXP (src, 0)), 0);
+  v = cselib_lookup (XEXP (src, 0), GET_MODE (XEXP (src, 0)), 0, VOIDmode);
   if (!v || !cselib_preserved_value_p (v))
     return NULL_RTX;
 
@@ -5380,13 +5389,15 @@ add_stores (rtx loc, const_rtx expr, voi
 	  rtx mloc = loc;
 	  enum machine_mode address_mode = get_address_mode (mloc);
 	  cselib_val *val = cselib_lookup (XEXP (mloc, 0),
-					   address_mode, 0);
+					   address_mode, 0,
+					   GET_MODE (mloc));
 
 	  if (val && !cselib_preserved_value_p (val))
 	    {
 	      preserve_value (val);
 	      mo.type = MO_VAL_USE;
-	      mloc = cselib_subst_to_values (XEXP (mloc, 0));
+	      mloc = cselib_subst_to_values (XEXP (mloc, 0),
+					     GET_MODE (mloc));
 	      mo.u.loc = gen_rtx_CONCAT (address_mode, val->val_rtx, mloc);
 	      mo.insn = cui->insn;
 	      if (dump_file && (dump_flags & TDF_DETAILS))
@@ -5445,7 +5456,7 @@ add_stores (rtx loc, const_rtx expr, voi
 
   if (GET_CODE (PATTERN (cui->insn)) == COND_EXEC)
     {
-      cselib_val *oval = cselib_lookup (oloc, GET_MODE (oloc), 0);
+      cselib_val *oval = cselib_lookup (oloc, GET_MODE (oloc), 0, VOIDmode);
 
       gcc_assert (oval != v);
       gcc_assert (REG_P (oloc) || MEM_P (oloc));
@@ -8139,7 +8150,8 @@ vt_add_function_parameters (void)
 	  if (offset)
 	    continue;
 
-	  val = cselib_lookup (var_lowpart (mode, incoming), mode, true);
+	  val = cselib_lookup (var_lowpart (mode, incoming), mode, true,
+			       VOIDmode);
 
 	  /* ??? Float-typed values in memory are not handled by
 	     cselib.  */
@@ -8227,7 +8239,7 @@ vt_init_cfa_base (void)
     return;
 
   val = cselib_lookup_from_insn (cfa_base_rtx, GET_MODE (cfa_base_rtx), 1,
-				 get_insns ());
+				 VOIDmode, get_insns ());
   preserve_value (val);
   cselib_preserve_cfa_base_value (val, REGNO (cfa_base_rtx));
   var_reg_decl_set (&VTI (ENTRY_BLOCK_PTR)->out, cfa_base_rtx,
Index: gcc/sched-deps.c
===================================================================
--- gcc/sched-deps.c.orig	2010-09-13 00:42:54.855436379 -0300
+++ gcc/sched-deps.c	2010-09-13 01:16:05.266503410 -0300
@@ -1562,7 +1562,7 @@ add_insn_mem_dependence (struct deps_des
   if (sched_deps_info->use_cselib)
     {
       mem = shallow_copy_rtx (mem);
-      XEXP (mem, 0) = cselib_subst_to_values (XEXP (mem, 0));
+      XEXP (mem, 0) = cselib_subst_to_values (XEXP (mem, 0), GET_MODE (mem));
     }
   link = alloc_EXPR_LIST (VOIDmode, canon_rtx (mem), *mem_list);
   *mem_list = link;
@@ -2279,8 +2279,9 @@ sched_analyze_1 (struct deps_desc *deps,
 	    = targetm.addr_space.address_mode (MEM_ADDR_SPACE (dest));
 
 	  t = shallow_copy_rtx (dest);
-	  cselib_lookup_from_insn (XEXP (t, 0), address_mode, 1, insn);
-	  XEXP (t, 0) = cselib_subst_to_values (XEXP (t, 0));
+	  cselib_lookup_from_insn (XEXP (t, 0), address_mode, 1,
+				   GET_MODE (t), insn);
+	  XEXP (t, 0) = cselib_subst_to_values (XEXP (t, 0), GET_MODE (t));
 	}
       t = canon_rtx (t);
 
@@ -2436,8 +2437,9 @@ sched_analyze_2 (struct deps_desc *deps,
 	      = targetm.addr_space.address_mode (MEM_ADDR_SPACE (t));
 
 	    t = shallow_copy_rtx (t);
-	    cselib_lookup_from_insn (XEXP (t, 0), address_mode, 1, insn);
-	    XEXP (t, 0) = cselib_subst_to_values (XEXP (t, 0));
+	    cselib_lookup_from_insn (XEXP (t, 0), address_mode, 1,
+				     GET_MODE (t), insn);
+	    XEXP (t, 0) = cselib_subst_to_values (XEXP (t, 0), GET_MODE (t));
 	  }
 
 	if (!DEBUG_INSN_P (insn))
Index: gcc/gcse.c
===================================================================
--- gcc/gcse.c.orig	2010-09-13 00:27:04.106861222 -0300
+++ gcc/gcse.c	2010-09-13 00:42:55.811438927 -0300
@@ -2740,7 +2740,7 @@ do_local_cprop (rtx x, rtx insn)
           || (GET_CODE (PATTERN (insn)) != USE
 	      && asm_noperands (PATTERN (insn)) < 0)))
     {
-      cselib_val *val = cselib_lookup (x, GET_MODE (x), 0);
+      cselib_val *val = cselib_lookup (x, GET_MODE (x), 0, VOIDmode);
       struct elt_loc_list *l;
 
       if (!val)
Index: gcc/postreload.c
===================================================================
--- gcc/postreload.c.orig	2010-09-13 00:27:04.106861222 -0300
+++ gcc/postreload.c	2010-09-13 00:42:55.855514066 -0300
@@ -263,7 +263,7 @@ reload_cse_simplify_set (rtx set, rtx in
     return 0;
 #endif
 
-  val = cselib_lookup (src, GET_MODE (SET_DEST (set)), 0);
+  val = cselib_lookup (src, GET_MODE (SET_DEST (set)), 0, VOIDmode);
   if (! val)
     return 0;
 
@@ -477,7 +477,7 @@ reload_cse_simplify_operands (rtx insn, 
 	    continue;
 	}
 #endif /* LOAD_EXTEND_OP */
-      v = cselib_lookup (op, recog_data.operand_mode[i], 0);
+      v =  cselib_lookup (op, recog_data.operand_mode[i], 0, VOIDmode);
       if (! v)
 	continue;
 
Index: gcc/sel-sched-dump.c
===================================================================
--- gcc/sel-sched-dump.c.orig	2010-09-13 00:27:04.106861222 -0300
+++ gcc/sel-sched-dump.c	2010-09-13 01:17:38.545508615 -0300
@@ -961,8 +961,8 @@ debug_mem_addr_value (rtx x)
   address_mode = targetm.addr_space.address_mode (MEM_ADDR_SPACE (x));
 
   t = shallow_copy_rtx (x);
-  if (cselib_lookup (XEXP (t, 0), address_mode, 0))
-    XEXP (t, 0) = cselib_subst_to_values (XEXP (t, 0));
+  if (cselib_lookup (XEXP (t, 0), address_mode, 0, GET_MODE (t)))
+    XEXP (t, 0) = cselib_subst_to_values (XEXP (t, 0), GET_MODE (t));
 
   t = canon_rtx (t);
   addr = get_addr (XEXP (t, 0));

[-- Attachment #3: Type: text/plain, Size: 257 bytes --]


-- 
Alexandre Oliva, freedom fighter    http://FSFLA.org/~lxoliva/
You must be the change you wish to see in the world. -- Gandhi
Be Free! -- http://FSFLA.org/   FSF Latin America board member
Free Software Evangelist      Red Hat Brazil Compiler Engineer

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH] Fix VTA sp (and fp) based MEM handling (PR debug/43051, PR debug/43092) and also PR debug/43494
  2010-09-21 11:45       ` Alexandre Oliva
@ 2011-01-19 22:27         ` Alexandre Oliva
  2011-01-27 19:42           ` Eric Botcazou
  0 siblings, 1 reply; 10+ messages in thread
From: Alexandre Oliva @ 2011-01-19 22:27 UTC (permalink / raw)
  To: Steven Bosscher; +Cc: Jakub Jelinek, bernds, Richard Guenther, gcc-patches

[-- Attachment #1: Type: text/plain, Size: 161 bytes --]

On Sep 21, 2010, Alexandre Oliva <aoliva@redhat.com> wrote:

> Thanks, fixed, re-tested.  Ok to install?

Ping?  Adjusted to apply on current trunk, re-tested.


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: vta-cselib-autoinc-pr43092.patch --]
[-- Type: text/x-diff, Size: 39414 bytes --]

for  gcc/ChangeLog
from  Alexandre Oliva  <aoliva@redhat.com>

	PR debug/43092
	PR debug/43494
	* rtl.h (for_each_inc_dec_fn): New type.
	(for_each_inc_dec): Declare.
	* rtlanal.c (struct for_each_inc_dec_ops): New type.
	(for_each_inc_dec_find_inc_dec): New fn.
	(for_each_inc_dec_find_mem): New fn.
	(for_each_inc_dec): New fn.
	* dse.c (struct insn_size): Remove.
	(replace_inc_dec, replace_inc_dec_mem): Remove.
	(emit_inc_dec_insn_before): New fn.
	(check_for_inc_dec): Use it, along with for_each_inc_dec.
	(canon_address): Pass mem modes to cselib_lookup.
	* cselib.h (cselib_lookup): Add memmode argument.  Adjust callers.
	(cselib_lookup_from_insn): Likewise.
	(cselib_subst_to_values): Likewise.
	* cselib.c (find_slot_memmode): New var.
	(cselib_find_slot): New fn.  Use it instead of
	htab_find_slot_with_hash everywhere.
	(entry_and_rtx_equal_p): Use find_slot_memmode.
	(autoinc_split): New fn.
	(rtx_equal_for_cselib_p): Rename and implement in terms of...
	(rtx_equal_for_cselib_1): ... this.  Take memmode, pass it on.
	Deal with autoinc.  Special-case recursion into MEMs.
	(cselib_hash_rtx): Likewise.
	(cselib_lookup_mem): Infer pmode from address mode.  Distinguish
	address and MEM modes.
	(cselib_subst_to_values): Add memmode, pass it on.
	Deal with autoinc.
	(cselib_lookup): Add memmode argument, pass it on.
	(cselib_lookup_from_insn): Add memmode.
	(struct cselib_record_autoinc_data): New.
	(cselib_record_autoinc_cb): New fn.
	(cselib_record_sets): Use it, along with for_each_inc_dec.  Pass MEM
	mode to cselib_lookup.
	* var-tracking.c (replace_expr_with_values, use_type): Pass MEM mode
	to cselib_lookup.
	(add_uses): Likewise, also to cselib_subst_to_values.
	(add_stores): Likewise.
	* sched-deps.c 	(add_insn_mem_dependence): Pass mode to
	cselib_subst_to_values.
	(sched_analyze_1, sched_analyze_2): Likewise.  Adjusted.
	* gcse.c (do_local_cprop): Adjusted.
	* postreload.c (reload_cse_simplify_set): Adjusted.
	(reload_cse_simplify_operands): Adjusted.
	* sel-sched-dump (debug_mem_addr_value): Pass mode.

Index: gcc/rtl.h
===================================================================
--- gcc/rtl.h.orig	2011-01-04 23:39:16.000000000 -0200
+++ gcc/rtl.h	2011-01-13 07:54:09.767693527 -0200
@@ -1916,6 +1916,17 @@ extern int computed_jump_p (const_rtx);
 typedef int (*rtx_function) (rtx *, void *);
 extern int for_each_rtx (rtx *, rtx_function, void *);
 
+/* Callback for for_each_inc_dec, to process the autoinc operation OP
+   within MEM.  It sets DEST to SRC + SRCOFF, or SRC if SRCOFF is
+   NULL.  The callback is passed the same opaque ARG passed to
+   for_each_inc_dec.  Return zero to continue looking for other
+   autoinc operations, -1 to skip OP's operands, and any other value
+   to interrupt the traversal and return that value to the caller of
+   for_each_inc_dec.  */
+typedef int (*for_each_inc_dec_fn) (rtx mem, rtx op, rtx dest, rtx src,
+				    rtx srcoff, void *arg);
+extern int for_each_inc_dec (rtx *, for_each_inc_dec_fn, void *arg);
+
 typedef int (*rtx_equal_p_callback_function) (const_rtx *, const_rtx *,
                                               rtx *, rtx *);
 extern int rtx_equal_p_cb (const_rtx, const_rtx,
Index: gcc/rtlanal.c
===================================================================
--- gcc/rtlanal.c.orig	2011-01-04 23:39:16.000000000 -0200
+++ gcc/rtlanal.c	2011-01-13 07:54:09.787938718 -0200
@@ -2886,7 +2886,122 @@ for_each_rtx (rtx *x, rtx_function f, vo
   return for_each_rtx_1 (*x, i, f, data);
 }
 
+\f
+
+/* Data structure that holds the internal state communicated between
+   for_each_inc_dec, for_each_inc_dec_find_mem and
+   for_each_inc_dec_find_inc_dec.  */
+
+struct for_each_inc_dec_ops {
+  /* The function to be called for each autoinc operation found.  */
+  for_each_inc_dec_fn fn;
+  /* The opaque argument to be passed to it.  */
+  void *arg;
+  /* The MEM we're visiting, if any.  */
+  rtx mem;
+};
+
+static int for_each_inc_dec_find_mem (rtx *r, void *d);
 
+/* Add an insn to do the add inside a x if it is a
+   PRE/POST-INC/DEC/MODIFY.  D is an structure containing the insn and
+   the size of the mode of the MEM that this is inside of.  */
+
+static int
+for_each_inc_dec_find_inc_dec (rtx *r, void *d)
+{
+  rtx x = *r;
+  struct for_each_inc_dec_ops *data = (struct for_each_inc_dec_ops *)d;
+  int size = GET_MODE_SIZE (GET_MODE (data->mem));
+
+  switch (GET_CODE (x))
+    {
+    case PRE_INC:
+    case POST_INC:
+      {
+	rtx r1 = XEXP (x, 0);
+	rtx c = gen_int_mode (size, GET_MODE (r1));
+	return data->fn (data->mem, x, r1, r1, c, data->arg);
+      }
+
+    case PRE_DEC:
+    case POST_DEC:
+      {
+	rtx r1 = XEXP (x, 0);
+	rtx c = gen_int_mode (-size, GET_MODE (r1));
+	return data->fn (data->mem, x, r1, r1, c, data->arg);
+      }
+
+    case PRE_MODIFY:
+    case POST_MODIFY:
+      {
+	rtx r1 = XEXP (x, 0);
+	rtx add = XEXP (x, 1);
+	return data->fn (data->mem, x, r1, add, NULL, data->arg);
+      }
+
+    case MEM:
+      {
+	rtx save = data->mem;
+	int ret = for_each_inc_dec_find_mem (r, d);
+	data->mem = save;
+	return ret;
+      }
+
+    default:
+      return 0;
+    }
+}
+
+/* If X is a MEM, check the address to see if it is PRE/POST-INC/DEC/MODIFY
+   and generate an add to replace that.  */
+
+static int
+for_each_inc_dec_find_mem (rtx *r, void *d)
+{
+  rtx x = *r;
+  if (x != NULL_RTX && MEM_P (x))
+    {
+      struct for_each_inc_dec_ops *data = (struct for_each_inc_dec_ops *) d;
+      int result;
+
+      data->mem = x;
+
+      result = for_each_rtx (&XEXP (x, 0), for_each_inc_dec_find_inc_dec,
+			     data);
+      if (result)
+	return result;
+
+      return -1;
+    }
+  return 0;
+}
+
+/* Traverse *X looking for MEMs, and for autoinc operations within
+   them.  For each such autoinc operation found, call FN, passing it
+   the innermost enclosing MEM, the operation itself, the RTX modified
+   by the operation, two RTXs (the second may be NULL) that, once
+   added, represent the value to be held by the modified RTX
+   afterwards, and ARG.  FN is to return -1 to skip looking for other
+   autoinc operations within the visited operation, 0 to continue the
+   traversal, or any other value to have it returned to the caller of
+   for_each_inc_dec.  */
+
+int
+for_each_inc_dec (rtx *x,
+		  for_each_inc_dec_fn fn,
+		  void *arg)
+{
+  struct for_each_inc_dec_ops data;
+
+  data.fn = fn;
+  data.arg = arg;
+  data.mem = NULL;
+
+  return for_each_rtx (x, for_each_inc_dec_find_mem, &data);
+}
+
+\f
 /* Searches X for any reference to REGNO, returning the rtx of the
    reference found if any.  Otherwise, returns NULL_RTX.  */
 
Index: gcc/dse.c
===================================================================
--- gcc/dse.c.orig	2011-01-04 02:48:08.000000000 -0200
+++ gcc/dse.c	2011-01-13 07:54:09.802939348 -0200
@@ -807,81 +807,22 @@ free_store_info (insn_info_t insn_info)
 }
 
 
-struct insn_size {
-  int size;
-  rtx insn;
-};
-
-
-/* Add an insn to do the add inside a x if it is a
-   PRE/POST-INC/DEC/MODIFY.  D is an structure containing the insn and
-   the size of the mode of the MEM that this is inside of.  */
-
 static int
-replace_inc_dec (rtx *r, void *d)
+emit_inc_dec_insn_before (rtx mem ATTRIBUTE_UNUSED,
+			  rtx op ATTRIBUTE_UNUSED,
+			  rtx dest, rtx src, rtx srcoff, void *arg)
 {
-  rtx x = *r;
-  struct insn_size *data = (struct insn_size *)d;
-  switch (GET_CODE (x))
-    {
-    case PRE_INC:
-    case POST_INC:
-      {
-	rtx r1 = XEXP (x, 0);
-	rtx c = gen_int_mode (data->size, GET_MODE (r1));
-	emit_insn_before (gen_rtx_SET (VOIDmode, r1,
-				       gen_rtx_PLUS (GET_MODE (r1), r1, c)),
-			  data->insn);
-	return -1;
-      }
-
-    case PRE_DEC:
-    case POST_DEC:
-      {
-	rtx r1 = XEXP (x, 0);
-	rtx c = gen_int_mode (-data->size, GET_MODE (r1));
-	emit_insn_before (gen_rtx_SET (VOIDmode, r1,
-				       gen_rtx_PLUS (GET_MODE (r1), r1, c)),
-			  data->insn);
-	return -1;
-      }
-
-    case PRE_MODIFY:
-    case POST_MODIFY:
-      {
-	/* We can reuse the add because we are about to delete the
-	   insn that contained it.  */
-	rtx add = XEXP (x, 0);
-	rtx r1 = XEXP (add, 0);
-	emit_insn_before (gen_rtx_SET (VOIDmode, r1, add), data->insn);
-	return -1;
-      }
+  rtx insn = (rtx)arg;
 
-    default:
-      return 0;
-    }
-}
+  if (srcoff)
+    src = gen_rtx_PLUS (GET_MODE (src), src, srcoff);
 
+  /* We can reuse all operands without copying, because we are about
+     to delete the insn that contained it.  */
 
-/* If X is a MEM, check the address to see if it is PRE/POST-INC/DEC/MODIFY
-   and generate an add to replace that.  */
+  emit_insn_before (gen_rtx_SET (VOIDmode, dest, src), insn);
 
-static int
-replace_inc_dec_mem (rtx *r, void *d)
-{
-  rtx x = *r;
-  if (x != NULL_RTX && MEM_P (x))
-    {
-      struct insn_size data;
-
-      data.size = GET_MODE_SIZE (GET_MODE (x));
-      data.insn = (rtx) d;
-
-      for_each_rtx (&XEXP (x, 0), replace_inc_dec, &data);
-
-      return -1;
-    }
-  return 0;
+  return -1;
 }
 
 /* Before we delete INSN, make sure that the auto inc/dec, if it is
@@ -892,7 +833,7 @@ check_for_inc_dec (rtx insn)
 {
   rtx note = find_reg_note (insn, REG_INC, NULL_RTX);
   if (note)
-    for_each_rtx (&insn, replace_inc_dec_mem, insn);
+    for_each_inc_dec (&insn, emit_inc_dec_insn_before, insn);
 }
 
 
@@ -1107,7 +1048,7 @@ canon_address (rtx mem,
 
   *alias_set_out = 0;
 
-  cselib_lookup (mem_address, address_mode, 1);
+  cselib_lookup (mem_address, address_mode, 1, GET_MODE (mem));
 
   if (dump_file)
     {
@@ -1187,7 +1128,7 @@ canon_address (rtx mem,
 	}
     }
 
-  *base = cselib_lookup (address, address_mode, true);
+  *base = cselib_lookup (address, address_mode, true, GET_MODE (mem));
   *group_id = -1;
 
   if (*base == NULL)
Index: gcc/cselib.h
===================================================================
--- gcc/cselib.h.orig	2011-01-04 23:39:16.000000000 -0200
+++ gcc/cselib.h	2011-01-13 07:54:09.808940996 -0200
@@ -70,8 +70,10 @@ extern void (*cselib_discard_hook) (csel
 extern void (*cselib_record_sets_hook) (rtx insn, struct cselib_set *sets,
 					int n_sets);
 
-extern cselib_val *cselib_lookup (rtx, enum machine_mode, int);
-extern cselib_val *cselib_lookup_from_insn (rtx, enum machine_mode, int, rtx);
+extern cselib_val *cselib_lookup (rtx, enum machine_mode,
+				  int, enum machine_mode);
+extern cselib_val *cselib_lookup_from_insn (rtx, enum machine_mode,
+					    int, enum machine_mode, rtx);
 extern void cselib_init (int);
 extern void cselib_clear_table (void);
 extern void cselib_finish (void);
@@ -85,7 +87,7 @@ extern rtx cselib_expand_value_rtx_cb (r
 				       cselib_expand_callback, void *);
 extern bool cselib_dummy_expand_value_rtx_cb (rtx, bitmap, int,
 					      cselib_expand_callback, void *);
-extern rtx cselib_subst_to_values (rtx);
+extern rtx cselib_subst_to_values (rtx, enum machine_mode);
 extern void cselib_invalidate_rtx (rtx);
 
 extern void cselib_reset_table (unsigned int);
Index: gcc/cselib.c
===================================================================
--- gcc/cselib.c.orig	2011-01-04 23:39:16.000000000 -0200
+++ gcc/cselib.c	2011-01-13 07:54:09.858938250 -0200
@@ -62,7 +62,8 @@ static void unchain_one_elt_loc_list (st
 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);
@@ -390,6 +391,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
@@ -419,7 +440,7 @@ entry_and_rtx_equal_p (const void *entry
   /* 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))
+    if (rtx_equal_for_cselib_1 (l->loc, x, find_slot_memmode))
       {
 	promote_debug_loc (l);
 	return 1;
@@ -631,13 +652,59 @@ 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;
+    }
+}
+
+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;
@@ -645,7 +712,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;
@@ -669,7 +736,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;
 	}
 
@@ -687,16 +754,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))
     {
@@ -712,6 +800,11 @@ rtx_equal_for_cselib_p (rtx x, rtx 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;
     }
@@ -744,18 +837,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;
 
@@ -807,6 +900,8 @@ wrap_constant (enum machine_mode mode, r
    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 auto-inc 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))
@@ -817,7 +912,7 @@ wrap_constant (enum machine_mode mode, r
    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;
@@ -832,7 +927,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;
 
@@ -878,7 +973,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;
@@ -911,10 +1006,26 @@ 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;
+      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:
@@ -940,7 +1051,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;
@@ -952,7 +1063,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;
@@ -1064,7 +1175,7 @@ add_mem_for_addr (cselib_val *addr_elt, 
 static cselib_val *
 cselib_lookup_mem (rtx x, int create)
 {
-  enum machine_mode mode = GET_MODE (x);
+  enum machine_mode mode = GET_MODE (x), pmode = Pmode;
   void **slot;
   cselib_val *addr;
   cselib_val *mem_elt;
@@ -1075,8 +1186,11 @@ cselib_lookup_mem (rtx x, int create)
       || (FLOAT_MODE_P (mode) && flag_float_store))
     return 0;
 
+  if (GET_MODE (XEXP (x, 0)) != VOIDmode)
+    pmode = GET_MODE (XEXP (x, 0));
+
   /* Look up the value for the address.  */
-  addr = cselib_lookup (XEXP (x, 0), mode, create);
+  addr = cselib_lookup (XEXP (x, 0), pmode, create, mode);
   if (! addr)
     return 0;
 
@@ -1093,8 +1207,8 @@ cselib_lookup_mem (rtx x, int create)
 
   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;
 }
@@ -1526,10 +1640,11 @@ cselib_expand_value_rtx_1 (rtx orig, str
    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);
@@ -1566,14 +1681,24 @@ cselib_subst_to_values (rtx x)
     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;
@@ -1583,7 +1708,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))
 	    {
@@ -1598,7 +1723,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))
 		{
@@ -1617,13 +1742,16 @@ cselib_subst_to_values (rtx x)
   return copy;
 }
 
-/* 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).  */
+/* 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_lookup_1 (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;
@@ -1672,7 +1800,7 @@ cselib_lookup_1 (rtx x, enum machine_mod
 	  REG_VALUES (i) = new_elt_list (REG_VALUES (i), NULL);
 	}
       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 e;
     }
@@ -1680,13 +1808,13 @@ cselib_lookup_1 (rtx x, enum machine_mod
   if (MEM_P (x))
     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 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 0;
 
@@ -1700,7 +1828,8 @@ cselib_lookup_1 (rtx x, enum machine_mod
      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));
+  e->locs = new_elt_loc_list (e->locs,
+			      cselib_subst_to_values (x, memmode));
   return e;
 }
 
@@ -1708,14 +1837,14 @@ cselib_lookup_1 (rtx x, enum machine_mod
 
 cselib_val *
 cselib_lookup_from_insn (rtx x, enum machine_mode mode,
-			 int create, rtx insn)
+			 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);
+  ret = cselib_lookup (x, mode, create, memmode);
 
   cselib_current_insn = NULL;
 
@@ -1726,9 +1855,10 @@ cselib_lookup_from_insn (rtx x, enum mac
    maintains invariants related with debug insns.  */
 
 cselib_val *
-cselib_lookup (rtx x, enum machine_mode mode, int create)
+cselib_lookup (rtx x, enum machine_mode mode,
+	       int create, enum machine_mode memmode)
 {
-  cselib_val *ret = cselib_lookup_1 (x, mode, create);
+  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?
@@ -1913,7 +2043,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 (;;)
 	    {
@@ -1963,13 +2093,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.  */
@@ -2032,6 +2155,36 @@ cselib_record_set (rtx dest, cselib_val 
    in a PARALLEL.  Since it's fairly cheap, use a really large number.  */
 #define MAX_SETS (FIRST_PSEUDO_REGISTER * 2)
 
+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: SRCBASE 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 srcbase, 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 (srcbase),
+						 srcbase, srcoff);
+  else
+    data->sets[data->n_sets].src = srcbase;
+
+  data->n_sets++;
+
+  return -1;
+}
+
 /* Record the effects of any sets in INSN.  */
 static void
 cselib_record_sets (rtx insn)
@@ -2041,6 +2194,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)
@@ -2084,6 +2239,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++)
@@ -2102,14 +2262,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;
@@ -2124,6 +2285,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
Index: gcc/var-tracking.c
===================================================================
--- gcc/var-tracking.c.orig	2011-01-13 07:53:53.000000000 -0200
+++ gcc/var-tracking.c	2011-01-13 07:55:30.692941100 -0200
@@ -737,7 +737,7 @@ use_narrower_mode_test (rtx *loc, void *
   switch (GET_CODE (*loc))
     {
     case REG:
-      if (cselib_lookup (*loc, GET_MODE (SUBREG_REG (subreg)), 0))
+      if (cselib_lookup (*loc, GET_MODE (SUBREG_REG (subreg)), 0, VOIDmode))
 	return 1;
       return -1;
     case PLUS:
@@ -3954,8 +3954,10 @@ variable_post_merge_new_vals (void **slo
 			 subsequent rounds.  */
 		      cselib_val *v;
 		      gcc_assert (!cselib_lookup (node->loc,
-						  GET_MODE (node->loc), 0));
-		      v = cselib_lookup (node->loc, GET_MODE (node->loc), 1);
+						  GET_MODE (node->loc), 0,
+						  VOIDmode));
+		      v = cselib_lookup (node->loc, GET_MODE (node->loc), 1,
+					 VOIDmode);
 		      cselib_preserve_value (v);
 		      cselib_invalidate_rtx (node->loc);
 		      cval = v->val_rtx;
@@ -4793,7 +4795,7 @@ find_use_val (rtx x, enum machine_mode m
 	      return cui->sets[i].src_elt;
 	}
       else
-	return cselib_lookup (x, mode, 0);
+	return cselib_lookup (x, mode, 0, VOIDmode);
     }
 
   return NULL;
@@ -4822,14 +4824,15 @@ replace_expr_with_values (rtx loc)
   else if (MEM_P (loc))
     {
       cselib_val *addr = cselib_lookup (XEXP (loc, 0),
-					get_address_mode (loc), 0);
+					get_address_mode (loc), 0,
+					GET_MODE (loc));
       if (addr)
 	return replace_equiv_address_nv (loc, addr->val_rtx);
       else
 	return NULL;
     }
   else
-    return cselib_subst_to_values (loc);
+    return cselib_subst_to_values (loc, VOIDmode);
 }
 
 /* Determine what kind of micro operation to choose for a USE.  Return
@@ -4849,7 +4852,8 @@ use_type (rtx loc, struct count_use_info
 	      rtx ploc = PAT_VAR_LOCATION_LOC (loc);
 	      if (! VAR_LOC_UNKNOWN_P (ploc))
 		{
-		  cselib_val *val = cselib_lookup (ploc, GET_MODE (loc), 1);
+		  cselib_val *val = cselib_lookup (ploc, GET_MODE (loc), 1,
+						   VOIDmode);
 
 		  /* ??? flag_float_store and volatile mems are never
 		     given values, but we could in theory use them for
@@ -4871,7 +4875,8 @@ use_type (rtx loc, struct count_use_info
 	      if (REG_P (loc)
 		  || (find_use_val (loc, GET_MODE (loc), cui)
 		      && cselib_lookup (XEXP (loc, 0),
-					get_address_mode (loc), 0)))
+					get_address_mode (loc), 0,
+					GET_MODE (loc))))
 		return MO_VAL_SET;
 	    }
 	  else
@@ -5033,13 +5038,15 @@ add_uses (rtx *ploc, void *data)
 	      rtx mloc = vloc;
 	      enum machine_mode address_mode = get_address_mode (mloc);
 	      cselib_val *val
-		= cselib_lookup (XEXP (mloc, 0), address_mode, 0);
+		= cselib_lookup (XEXP (mloc, 0), address_mode, 0,
+				 GET_MODE (mloc));
 
 	      if (val && !cselib_preserved_value_p (val))
 		{
 		  micro_operation moa;
 		  preserve_value (val);
-		  mloc = cselib_subst_to_values (XEXP (mloc, 0));
+		  mloc = cselib_subst_to_values (XEXP (mloc, 0),
+						 GET_MODE (mloc));
 		  moa.type = MO_VAL_USE;
 		  moa.insn = cui->insn;
 		  moa.u.loc = gen_rtx_CONCAT (address_mode,
@@ -5109,13 +5116,15 @@ add_uses (rtx *ploc, void *data)
 	      rtx mloc = oloc;
 	      enum machine_mode address_mode = get_address_mode (mloc);
 	      cselib_val *val
-		= cselib_lookup (XEXP (mloc, 0), address_mode, 0);
+		= cselib_lookup (XEXP (mloc, 0), address_mode, 0,
+				GET_MODE (mloc));
 
 	      if (val && !cselib_preserved_value_p (val))
 		{
 		  micro_operation moa;
 		  preserve_value (val);
-		  mloc = cselib_subst_to_values (XEXP (mloc, 0));
+		  mloc = cselib_subst_to_values (XEXP (mloc, 0),
+						GET_MODE (mloc));
 		  moa.type = MO_VAL_USE;
 		  moa.insn = cui->insn;
 		  moa.u.loc = gen_rtx_CONCAT (address_mode,
@@ -5225,7 +5234,7 @@ reverse_op (rtx val, const_rtx expr)
   if (!SCALAR_INT_MODE_P (GET_MODE (src)) || XEXP (src, 0) == cfa_base_rtx)
     return NULL_RTX;
 
-  v = cselib_lookup (XEXP (src, 0), GET_MODE (XEXP (src, 0)), 0);
+  v = cselib_lookup (XEXP (src, 0), GET_MODE (XEXP (src, 0)), 0, VOIDmode);
   if (!v || !cselib_preserved_value_p (v))
     return NULL_RTX;
 
@@ -5346,13 +5355,15 @@ add_stores (rtx loc, const_rtx expr, voi
 	  rtx mloc = loc;
 	  enum machine_mode address_mode = get_address_mode (mloc);
 	  cselib_val *val = cselib_lookup (XEXP (mloc, 0),
-					   address_mode, 0);
+					   address_mode, 0,
+					   GET_MODE (mloc));
 
 	  if (val && !cselib_preserved_value_p (val))
 	    {
 	      preserve_value (val);
 	      mo.type = MO_VAL_USE;
-	      mloc = cselib_subst_to_values (XEXP (mloc, 0));
+	      mloc = cselib_subst_to_values (XEXP (mloc, 0),
+					     GET_MODE (mloc));
 	      mo.u.loc = gen_rtx_CONCAT (address_mode, val->val_rtx, mloc);
 	      mo.insn = cui->insn;
 	      if (dump_file && (dump_flags & TDF_DETAILS))
@@ -5411,7 +5422,7 @@ add_stores (rtx loc, const_rtx expr, voi
 
   if (GET_CODE (PATTERN (cui->insn)) == COND_EXEC)
     {
-      cselib_val *oval = cselib_lookup (oloc, GET_MODE (oloc), 0);
+      cselib_val *oval = cselib_lookup (oloc, GET_MODE (oloc), 0, VOIDmode);
 
       gcc_assert (oval != v);
       gcc_assert (REG_P (oloc) || MEM_P (oloc));
@@ -8077,7 +8088,8 @@ vt_add_function_parameter (tree parm)
       if (offset)
 	return;
 
-      val = cselib_lookup (var_lowpart (mode, incoming), mode, true);
+      val = cselib_lookup (var_lowpart (mode, incoming), mode, true,
+			   VOIDmode);
 
       /* ??? Float-typed values in memory are not handled by
 	 cselib.  */
@@ -8197,7 +8209,7 @@ vt_init_cfa_base (void)
 			    frame_pointer_needed
 			    ? hard_frame_pointer_rtx : stack_pointer_rtx);
   val = cselib_lookup_from_insn (cfa_base_rtx, GET_MODE (cfa_base_rtx), 1,
-				 get_insns ());
+				 VOIDmode, get_insns ());
   preserve_value (val);
   cselib_preserve_cfa_base_value (val, REGNO (cfa_base_rtx));
   var_reg_decl_set (&VTI (ENTRY_BLOCK_PTR)->out, cfa_base_rtx,
Index: gcc/sched-deps.c
===================================================================
--- gcc/sched-deps.c.orig	2011-01-13 07:53:53.000000000 -0200
+++ gcc/sched-deps.c	2011-01-13 07:54:09.879692448 -0200
@@ -1566,7 +1566,7 @@ add_insn_mem_dependence (struct deps_des
   if (sched_deps_info->use_cselib)
     {
       mem = shallow_copy_rtx (mem);
-      XEXP (mem, 0) = cselib_subst_to_values (XEXP (mem, 0));
+      XEXP (mem, 0) = cselib_subst_to_values (XEXP (mem, 0), GET_MODE (mem));
     }
   link = alloc_EXPR_LIST (VOIDmode, canon_rtx (mem), *mem_list);
   *mem_list = link;
@@ -2283,8 +2283,9 @@ sched_analyze_1 (struct deps_desc *deps,
 	    = targetm.addr_space.address_mode (MEM_ADDR_SPACE (dest));
 
 	  t = shallow_copy_rtx (dest);
-	  cselib_lookup_from_insn (XEXP (t, 0), address_mode, 1, insn);
-	  XEXP (t, 0) = cselib_subst_to_values (XEXP (t, 0));
+	  cselib_lookup_from_insn (XEXP (t, 0), address_mode, 1,
+				   GET_MODE (t), insn);
+	  XEXP (t, 0) = cselib_subst_to_values (XEXP (t, 0), GET_MODE (t));
 	}
       t = canon_rtx (t);
 
@@ -2440,8 +2441,9 @@ sched_analyze_2 (struct deps_desc *deps,
 	      = targetm.addr_space.address_mode (MEM_ADDR_SPACE (t));
 
 	    t = shallow_copy_rtx (t);
-	    cselib_lookup_from_insn (XEXP (t, 0), address_mode, 1, insn);
-	    XEXP (t, 0) = cselib_subst_to_values (XEXP (t, 0));
+	    cselib_lookup_from_insn (XEXP (t, 0), address_mode, 1,
+				     GET_MODE (t), insn);
+	    XEXP (t, 0) = cselib_subst_to_values (XEXP (t, 0), GET_MODE (t));
 	  }
 
 	if (!DEBUG_INSN_P (insn))
Index: gcc/gcse.c
===================================================================
--- gcc/gcse.c.orig	2011-01-04 02:48:09.000000000 -0200
+++ gcc/gcse.c	2011-01-13 07:54:09.887691573 -0200
@@ -2738,7 +2738,7 @@ do_local_cprop (rtx x, rtx insn)
           || (GET_CODE (PATTERN (insn)) != USE
 	      && asm_noperands (PATTERN (insn)) < 0)))
     {
-      cselib_val *val = cselib_lookup (x, GET_MODE (x), 0);
+      cselib_val *val = cselib_lookup (x, GET_MODE (x), 0, VOIDmode);
       struct elt_loc_list *l;
 
       if (!val)
Index: gcc/postreload.c
===================================================================
--- gcc/postreload.c.orig	2011-01-04 23:39:16.000000000 -0200
+++ gcc/postreload.c	2011-01-13 07:54:09.895942688 -0200
@@ -262,7 +262,7 @@ reload_cse_simplify_set (rtx set, rtx in
     return 0;
 #endif
 
-  val = cselib_lookup (src, GET_MODE (SET_DEST (set)), 0);
+  val = cselib_lookup (src, GET_MODE (SET_DEST (set)), 0, VOIDmode);
   if (! val)
     return 0;
 
@@ -476,7 +476,7 @@ reload_cse_simplify_operands (rtx insn, 
 	    continue;
 	}
 #endif /* LOAD_EXTEND_OP */
-      v = cselib_lookup (op, recog_data.operand_mode[i], 0);
+      v =  cselib_lookup (op, recog_data.operand_mode[i], 0, VOIDmode);
       if (! v)
 	continue;
 
Index: gcc/sel-sched-dump.c
===================================================================
--- gcc/sel-sched-dump.c.orig	2011-01-04 23:39:16.000000000 -0200
+++ gcc/sel-sched-dump.c	2011-01-13 07:54:09.899938479 -0200
@@ -960,8 +960,8 @@ debug_mem_addr_value (rtx x)
   address_mode = targetm.addr_space.address_mode (MEM_ADDR_SPACE (x));
 
   t = shallow_copy_rtx (x);
-  if (cselib_lookup (XEXP (t, 0), address_mode, 0))
-    XEXP (t, 0) = cselib_subst_to_values (XEXP (t, 0));
+  if (cselib_lookup (XEXP (t, 0), address_mode, 0, GET_MODE (t)))
+    XEXP (t, 0) = cselib_subst_to_values (XEXP (t, 0), GET_MODE (t));
 
   t = canon_rtx (t);
   addr = get_addr (XEXP (t, 0));

[-- Attachment #3: Type: text/plain, Size: 257 bytes --]


-- 
Alexandre Oliva, freedom fighter    http://FSFLA.org/~lxoliva/
You must be the change you wish to see in the world. -- Gandhi
Be Free! -- http://FSFLA.org/   FSF Latin America board member
Free Software Evangelist      Red Hat Brazil Compiler Engineer

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH] Fix VTA sp (and fp) based MEM handling (PR debug/43051, PR debug/43092) and also PR debug/43494
  2011-01-19 22:27         ` [PATCH] Fix VTA sp (and fp) based MEM handling (PR debug/43051, PR debug/43092) and also PR debug/43494 Alexandre Oliva
@ 2011-01-27 19:42           ` Eric Botcazou
  2011-01-31 10:45             ` Alexandre Oliva
  0 siblings, 1 reply; 10+ messages in thread
From: Eric Botcazou @ 2011-01-27 19:42 UTC (permalink / raw)
  To: Alexandre Oliva
  Cc: gcc-patches, Steven Bosscher, Jakub Jelinek, bernds, Richard Guenther

[Sorry for the delay]

> Ping?  Adjusted to apply on current trunk, re-tested.

This is PR rtl-optimization/43494, not PR debug/43494.


@@ -1916,6 +1916,17 @@ extern int computed_jump_p (const_rtx);
 typedef int (*rtx_function) (rtx *, void *);
 extern int for_each_rtx (rtx *, rtx_function, void *);
 
+/* Callback for for_each_inc_dec, to process the autoinc operation OP
+   within MEM.  It sets DEST to SRC + SRCOFF, or SRC if SRCOFF is
+   NULL.

The "It" is ambiguous.

"Callback for for_each_inc_dec, to process the autoinc operation OP within
 MEM that sets DEST to SRC + SRCOFF, or SRC if SRCOFF is NULL."


+/* Add an insn to do the add inside a x if it is a
+   PRE/POST-INC/DEC/MODIFY.  D is an structure containing the insn and
+   the size of the mode of the MEM that this is inside of.  */
+
+static int
+for_each_inc_dec_find_inc_dec (rtx *r, void *d)

The comment is obsolete.  Something like:

"Find PRE/POST-INC/DEC/MODIFY operations within *R, extract the operands of
 the equivalent add insn and pass the result to the operator specified by *D".


+  int size = GET_MODE_SIZE (GET_MODE (data->mem));

SIZE doesn't need to be computed in all cases.


+/* If X is a MEM, check the address to see if it is PRE/POST-INC/DEC/MODIFY
+   and generate an add to replace that.  */
+static int
+for_each_inc_dec_find_mem (rtx *r, void *d)

"If *R is a MEM, find PRE/POST-INC/DEC/MODIFY operations within its address,
 extract the operands of the equivalent add insn and pass the result to the
 operator specified by *D"


-/* Add an insn to do the add inside a x if it is a
-   PRE/POST-INC/DEC/MODIFY.  D is an structure containing the insn and
-   the size of the mode of the MEM that this is inside of.  */
-
 static int
-replace_inc_dec (rtx *r, void *d)
+emit_inc_dec_insn_before (rtx mem ATTRIBUTE_UNUSED,
+			  rtx op ATTRIBUTE_UNUSED,
+			  rtx dest, rtx src, rtx srcoff, void *arg)

Missing comment for the function.


@@ -476,7 +476,7 @@ reload_cse_simplify_operands (rtx insn, 
 	    continue;
 	}
 #endif /* LOAD_EXTEND_OP */
-      v = cselib_lookup (op, recog_data.operand_mode[i], 0);
+      v =  cselib_lookup (op, recog_data.operand_mode[i], 0, VOIDmode);
       if (! v)
 	continue;

Superfluous space.


+static int
+rtx_equal_for_cselib_1 (rtx x, rtx y, enum machine_mode memmode)

Missing comment for the function.


@@ -807,6 +900,8 @@ wrap_constant (enum machine_mode mode, r
    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 auto-inc 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))

In every other place you write "autoinc".


@@ -911,10 +1006,26 @@ 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;
+      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;

Maybe a small comment to say that we're directly hashing like a PLUS.


@@ -1064,7 +1175,7 @@ add_mem_for_addr (cselib_val *addr_elt, 
 static cselib_val *
 cselib_lookup_mem (rtx x, int create)
 {
-  enum machine_mode mode = GET_MODE (x);
+  enum machine_mode mode = GET_MODE (x), pmode = Pmode;
   void **slot;
   cselib_val *addr;
   cselib_val *mem_elt;

Use addr_mode instead of pmode and remove the initial value.


@@ -1075,8 +1186,11 @@ cselib_lookup_mem (rtx x, int create)
       || (FLOAT_MODE_P (mode) && flag_float_store))
     return 0;
 
+  if (GET_MODE (XEXP (x, 0)) != VOIDmode)
+    pmode = GET_MODE (XEXP (x, 0));

  addr_mode = GET_MODE (XEXP (x, 0));
  if (addr_mode == VOIDmode)
    addr_mode = Pmode;


@@ -1566,14 +1681,24 @@ cselib_subst_to_values (rtx x)
     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;

Can you adjust the comment for the MEM case in the same function?


+/* Callback for for_each_inc_dec.  Records in ARG the SETs implied by
+   autoinc RTXs: SRCBASE plus SRCOFF if non-NULL is stored in
+   DEST.  */

"Record in ARG".  No need to break the line before "DEST".


+static int
+cselib_record_autoinc_cb (rtx mem ATTRIBUTE_UNUSED, rtx op ATTRIBUTE_UNUSED,
+			  rtx dest, rtx srcbase, rtx srcoff, void *arg)

The prototype in rtl.h has SRC instead of SRCBASE.


+  if (srcoff)
+    data->sets[data->n_sets].src = gen_rtx_PLUS (GET_MODE (srcbase),
+						 srcbase, srcoff);

  if (srcoff)
    data->sets[data->n_sets].src
       = gen_rtx_PLUS (GET_MODE (srcbase), srcbase, srcoff);


@@ -1963,13 +2093,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);
 }

This hunk isn't mentioned in the ChangeLog.  You also need to mention there 
that cselib_record_sets now handles the autoinc stuff, in particular the 
invalidation.  In light of this, isn't

#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

in cselib_process_insn superfluous now?


Otherwise looks OK to me.  Any idea of the impact on compilation performances 
for non-AUTO_INC_DEC targets?

-- 
Eric Botcazou

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH] Fix VTA sp (and fp) based MEM handling (PR debug/43051, PR debug/43092) and also PR debug/43494
  2011-01-27 19:42           ` Eric Botcazou
@ 2011-01-31 10:45             ` Alexandre Oliva
  2011-01-31 18:48               ` Eric Botcazou
  0 siblings, 1 reply; 10+ messages in thread
From: Alexandre Oliva @ 2011-01-31 10:45 UTC (permalink / raw)
  To: Eric Botcazou
  Cc: gcc-patches, Steven Bosscher, Jakub Jelinek, bernds, Richard Guenther

[-- Attachment #1: Type: text/plain, Size: 650 bytes --]

On Jan 27, 2011, Eric Botcazou <ebotcazou@adacore.com> wrote:

> [Sorry for the delay]

The thorough review was Well worth it, thanks!

I've made all the changes you suggested, I'm now going to re-test the
patch because of a few functional changes.  It will take a bit, because
I've just suffered yet another hardware failure, and now both my fast
build machine and its backup are down, so I'm back to an old sluggish PC
and a long queue of patches to test :-(

In the mean time, here's the modified patch.  Ok to install if it
regstraps successfully?  What do you think of the “Remove the if stmt
for the next release” comment?


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: vta-cselib-autoinc-pr43092.patch --]
[-- Type: text/x-diff, Size: 41281 bytes --]

for  gcc/ChangeLog
from  Alexandre Oliva  <aoliva@redhat.com>

	PR debug/43092
	PR rtl-optimization/43494
	* rtl.h (for_each_inc_dec_fn): New type.
	(for_each_inc_dec): Declare.
	* rtlanal.c (struct for_each_inc_dec_ops): New type.
	(for_each_inc_dec_find_inc_dec): New fn.
	(for_each_inc_dec_find_mem): New fn.
	(for_each_inc_dec): New fn.
	* dse.c (struct insn_size): Remove.
	(replace_inc_dec, replace_inc_dec_mem): Remove.
	(emit_inc_dec_insn_before): New fn.
	(check_for_inc_dec): Use it, along with for_each_inc_dec.
	(canon_address): Pass mem modes to cselib_lookup.
	* cselib.h (cselib_lookup): Add memmode argument.  Adjust callers.
	(cselib_lookup_from_insn): Likewise.
	(cselib_subst_to_values): Likewise.
	* cselib.c (find_slot_memmode): New var.
	(cselib_find_slot): New fn.  Use it instead of
	htab_find_slot_with_hash everywhere.
	(entry_and_rtx_equal_p): Use find_slot_memmode.
	(autoinc_split): New fn.
	(rtx_equal_for_cselib_p): Rename and implement in terms of...
	(rtx_equal_for_cselib_1): ... this.  Take memmode, pass it on.
	Deal with autoinc.  Special-case recursion into MEMs.
	(cselib_hash_rtx): Likewise.
	(cselib_lookup_mem): Infer pmode from address mode.  Distinguish
	address and MEM modes.
	(cselib_subst_to_values): Add memmode, pass it on.
	Deal with autoinc.
	(cselib_lookup): Add memmode argument, pass it on.
	(cselib_lookup_from_insn): Add memmode.
	(cselib_invalidate_rtx): Discard obsolete push_operand handling.
	(struct cselib_record_autoinc_data): New.
	(cselib_record_autoinc_cb): New fn.
	(cselib_record_sets): Use it, along with for_each_inc_dec.  Pass MEM
	mode to cselib_lookup.
	(cselib_process_insn): Don't reset autoinced REGs.
	* var-tracking.c (replace_expr_with_values, use_type): Pass MEM mode
	to cselib_lookup.
	(add_uses): Likewise, also to cselib_subst_to_values.
	(add_stores): Likewise.
	* sched-deps.c 	(add_insn_mem_dependence): Pass mode to
	cselib_subst_to_values.
	(sched_analyze_1, sched_analyze_2): Likewise.  Adjusted.
	* gcse.c (do_local_cprop): Adjusted.
	* postreload.c (reload_cse_simplify_set): Adjusted.
	(reload_cse_simplify_operands): Adjusted.
	* sel-sched-dump (debug_mem_addr_value): Pass mode.

Index: gcc/rtl.h
===================================================================
--- gcc/rtl.h.orig	2011-01-14 21:38:08.000000000 -0200
+++ gcc/rtl.h	2011-01-31 03:40:38.368998572 -0200
@@ -1916,6 +1916,17 @@ extern int computed_jump_p (const_rtx);
 typedef int (*rtx_function) (rtx *, void *);
 extern int for_each_rtx (rtx *, rtx_function, void *);
 
+/* Callback for for_each_inc_dec, to process the autoinc operation OP
+   within MEM that sets DEST to SRC + SRCOFF, or SRC if SRCOFF is
+   NULL.  The callback is passed the same opaque ARG passed to
+   for_each_inc_dec.  Return zero to continue looking for other
+   autoinc operations, -1 to skip OP's operands, and any other value
+   to interrupt the traversal and return that value to the caller of
+   for_each_inc_dec.  */
+typedef int (*for_each_inc_dec_fn) (rtx mem, rtx op, rtx dest, rtx src,
+				    rtx srcoff, void *arg);
+extern int for_each_inc_dec (rtx *, for_each_inc_dec_fn, void *arg);
+
 typedef int (*rtx_equal_p_callback_function) (const_rtx *, const_rtx *,
                                               rtx *, rtx *);
 extern int rtx_equal_p_cb (const_rtx, const_rtx,
Index: gcc/rtlanal.c
===================================================================
--- gcc/rtlanal.c.orig	2011-01-14 21:38:08.000000000 -0200
+++ gcc/rtlanal.c	2011-01-31 03:44:41.227239474 -0200
@@ -2886,7 +2886,124 @@ for_each_rtx (rtx *x, rtx_function f, vo
   return for_each_rtx_1 (*x, i, f, data);
 }
 
+\f
+
+/* Data structure that holds the internal state communicated between
+   for_each_inc_dec, for_each_inc_dec_find_mem and
+   for_each_inc_dec_find_inc_dec.  */
+
+struct for_each_inc_dec_ops {
+  /* The function to be called for each autoinc operation found.  */
+  for_each_inc_dec_fn fn;
+  /* The opaque argument to be passed to it.  */
+  void *arg;
+  /* The MEM we're visiting, if any.  */
+  rtx mem;
+};
+
+static int for_each_inc_dec_find_mem (rtx *r, void *d);
+
+/* Find PRE/POST-INC/DEC/MODIFY operations within *R, extract the
+   operands of the equivalent add insn and pass the result to the
+   operator specified by *D.  */
+
+static int
+for_each_inc_dec_find_inc_dec (rtx *r, void *d)
+{
+  rtx x = *r;
+  struct for_each_inc_dec_ops *data = (struct for_each_inc_dec_ops *)d;
+
+  switch (GET_CODE (x))
+    {
+    case PRE_INC:
+    case POST_INC:
+      {
+	int size = GET_MODE_SIZE (GET_MODE (data->mem));
+	rtx r1 = XEXP (x, 0);
+	rtx c = gen_int_mode (size, GET_MODE (r1));
+	return data->fn (data->mem, x, r1, r1, c, data->arg);
+      }
 
+    case PRE_DEC:
+    case POST_DEC:
+      {
+	int size = GET_MODE_SIZE (GET_MODE (data->mem));
+	rtx r1 = XEXP (x, 0);
+	rtx c = gen_int_mode (-size, GET_MODE (r1));
+	return data->fn (data->mem, x, r1, r1, c, data->arg);
+      }
+
+    case PRE_MODIFY:
+    case POST_MODIFY:
+      {
+	rtx r1 = XEXP (x, 0);
+	rtx add = XEXP (x, 1);
+	return data->fn (data->mem, x, r1, add, NULL, data->arg);
+      }
+
+    case MEM:
+      {
+	rtx save = data->mem;
+	int ret = for_each_inc_dec_find_mem (r, d);
+	data->mem = save;
+	return ret;
+      }
+
+    default:
+      return 0;
+    }
+}
+
+/* If *R is a MEM, find PRE/POST-INC/DEC/MODIFY operations within its
+   address, extract the operands of the equivalent add insn and pass
+   the result to the operator specified by *D.  */
+
+static int
+for_each_inc_dec_find_mem (rtx *r, void *d)
+{
+  rtx x = *r;
+  if (x != NULL_RTX && MEM_P (x))
+    {
+      struct for_each_inc_dec_ops *data = (struct for_each_inc_dec_ops *) d;
+      int result;
+
+      data->mem = x;
+
+      result = for_each_rtx (&XEXP (x, 0), for_each_inc_dec_find_inc_dec,
+			     data);
+      if (result)
+	return result;
+
+      return -1;
+    }
+  return 0;
+}
+
+/* Traverse *X looking for MEMs, and for autoinc operations within
+   them.  For each such autoinc operation found, call FN, passing it
+   the innermost enclosing MEM, the operation itself, the RTX modified
+   by the operation, two RTXs (the second may be NULL) that, once
+   added, represent the value to be held by the modified RTX
+   afterwards, and ARG.  FN is to return -1 to skip looking for other
+   autoinc operations within the visited operation, 0 to continue the
+   traversal, or any other value to have it returned to the caller of
+   for_each_inc_dec.  */
+
+int
+for_each_inc_dec (rtx *x,
+		  for_each_inc_dec_fn fn,
+		  void *arg)
+{
+  struct for_each_inc_dec_ops data;
+
+  data.fn = fn;
+  data.arg = arg;
+  data.mem = NULL;
+
+  return for_each_rtx (x, for_each_inc_dec_find_mem, &data);
+}
+
+\f
 /* Searches X for any reference to REGNO, returning the rtx of the
    reference found if any.  Otherwise, returns NULL_RTX.  */
 
Index: gcc/dse.c
===================================================================
--- gcc/dse.c.orig	2011-01-14 17:23:52.000000000 -0200
+++ gcc/dse.c	2011-01-31 03:46:45.331241221 -0200
@@ -806,82 +806,25 @@ free_store_info (insn_info_t insn_info)
   insn_info->store_rec = NULL;
 }
 
-
-struct insn_size {
-  int size;
-  rtx insn;
-};
-
-
-/* Add an insn to do the add inside a x if it is a
-   PRE/POST-INC/DEC/MODIFY.  D is an structure containing the insn and
-   the size of the mode of the MEM that this is inside of.  */
+/* Callback for for_each_inc_dec that emits an INSN that sets DEST to
+   SRC + SRCOFF before insn ARG.  */
 
 static int
-replace_inc_dec (rtx *r, void *d)
+emit_inc_dec_insn_before (rtx mem ATTRIBUTE_UNUSED,
+			  rtx op ATTRIBUTE_UNUSED,
+			  rtx dest, rtx src, rtx srcoff, void *arg)
 {
-  rtx x = *r;
-  struct insn_size *data = (struct insn_size *)d;
-  switch (GET_CODE (x))
-    {
-    case PRE_INC:
-    case POST_INC:
-      {
-	rtx r1 = XEXP (x, 0);
-	rtx c = gen_int_mode (data->size, GET_MODE (r1));
-	emit_insn_before (gen_rtx_SET (VOIDmode, r1,
-				       gen_rtx_PLUS (GET_MODE (r1), r1, c)),
-			  data->insn);
-	return -1;
-      }
-
-    case PRE_DEC:
-    case POST_DEC:
-      {
-	rtx r1 = XEXP (x, 0);
-	rtx c = gen_int_mode (-data->size, GET_MODE (r1));
-	emit_insn_before (gen_rtx_SET (VOIDmode, r1,
-				       gen_rtx_PLUS (GET_MODE (r1), r1, c)),
-			  data->insn);
-	return -1;
-      }
-
-    case PRE_MODIFY:
-    case POST_MODIFY:
-      {
-	/* We can reuse the add because we are about to delete the
-	   insn that contained it.  */
-	rtx add = XEXP (x, 0);
-	rtx r1 = XEXP (add, 0);
-	emit_insn_before (gen_rtx_SET (VOIDmode, r1, add), data->insn);
-	return -1;
-      }
+  rtx insn = (rtx)arg;
 
-    default:
-      return 0;
-    }
-}
+  if (srcoff)
+    src = gen_rtx_PLUS (GET_MODE (src), src, srcoff);
 
+  /* We can reuse all operands without copying, because we are about
+     to delete the insn that contained it.  */
 
-/* If X is a MEM, check the address to see if it is PRE/POST-INC/DEC/MODIFY
-   and generate an add to replace that.  */
+  emit_insn_before (gen_rtx_SET (VOIDmode, dest, src), insn);
 
-static int
-replace_inc_dec_mem (rtx *r, void *d)
-{
-  rtx x = *r;
-  if (x != NULL_RTX && MEM_P (x))
-    {
-      struct insn_size data;
-
-      data.size = GET_MODE_SIZE (GET_MODE (x));
-      data.insn = (rtx) d;
-
-      for_each_rtx (&XEXP (x, 0), replace_inc_dec, &data);
-
-      return -1;
-    }
-  return 0;
+  return -1;
 }
 
 /* Before we delete INSN, make sure that the auto inc/dec, if it is
@@ -892,7 +835,7 @@ check_for_inc_dec (rtx insn)
 {
   rtx note = find_reg_note (insn, REG_INC, NULL_RTX);
   if (note)
-    for_each_rtx (&insn, replace_inc_dec_mem, insn);
+    for_each_inc_dec (&insn, emit_inc_dec_insn_before, insn);
 }
 
 
@@ -1107,7 +1050,7 @@ canon_address (rtx mem,
 
   *alias_set_out = 0;
 
-  cselib_lookup (mem_address, address_mode, 1);
+  cselib_lookup (mem_address, address_mode, 1, GET_MODE (mem));
 
   if (dump_file)
     {
@@ -1187,7 +1130,7 @@ canon_address (rtx mem,
 	}
     }
 
-  *base = cselib_lookup (address, address_mode, true);
+  *base = cselib_lookup (address, address_mode, true, GET_MODE (mem));
   *group_id = -1;
 
   if (*base == NULL)
Index: gcc/cselib.h
===================================================================
--- gcc/cselib.h.orig	2011-01-14 21:38:07.000000000 -0200
+++ gcc/cselib.h	2011-01-31 03:38:46.479240060 -0200
@@ -70,8 +70,10 @@ extern void (*cselib_discard_hook) (csel
 extern void (*cselib_record_sets_hook) (rtx insn, struct cselib_set *sets,
 					int n_sets);
 
-extern cselib_val *cselib_lookup (rtx, enum machine_mode, int);
-extern cselib_val *cselib_lookup_from_insn (rtx, enum machine_mode, int, rtx);
+extern cselib_val *cselib_lookup (rtx, enum machine_mode,
+				  int, enum machine_mode);
+extern cselib_val *cselib_lookup_from_insn (rtx, enum machine_mode,
+					    int, enum machine_mode, rtx);
 extern void cselib_init (int);
 extern void cselib_clear_table (void);
 extern void cselib_finish (void);
@@ -85,7 +87,7 @@ extern rtx cselib_expand_value_rtx_cb (r
 				       cselib_expand_callback, void *);
 extern bool cselib_dummy_expand_value_rtx_cb (rtx, bitmap, int,
 					      cselib_expand_callback, void *);
-extern rtx cselib_subst_to_values (rtx);
+extern rtx cselib_subst_to_values (rtx, enum machine_mode);
 extern void cselib_invalidate_rtx (rtx);
 
 extern void cselib_reset_table (unsigned int);
Index: gcc/cselib.c
===================================================================
--- gcc/cselib.c.orig	2011-01-14 21:38:07.000000000 -0200
+++ gcc/cselib.c	2011-01-31 04:08:34.118235836 -0200
@@ -62,7 +62,8 @@ static void unchain_one_elt_loc_list (st
 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);
@@ -390,6 +391,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
@@ -419,7 +440,7 @@ entry_and_rtx_equal_p (const void *entry
   /* 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))
+    if (rtx_equal_for_cselib_1 (l->loc, x, find_slot_memmode))
       {
 	promote_debug_loc (l);
 	return 1;
@@ -631,13 +652,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;
@@ -645,7 +718,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;
@@ -669,7 +742,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;
 	}
 
@@ -687,16 +760,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))
     {
@@ -712,6 +806,11 @@ rtx_equal_for_cselib_p (rtx x, rtx 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;
     }
@@ -744,18 +843,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;
 
@@ -807,6 +906,8 @@ wrap_constant (enum machine_mode mode, r
    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))
@@ -817,7 +918,7 @@ wrap_constant (enum machine_mode mode, r
    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;
@@ -832,7 +933,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;
 
@@ -878,7 +979,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;
@@ -911,10 +1012,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:
@@ -940,7 +1059,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;
@@ -952,7 +1071,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;
@@ -1065,6 +1184,7 @@ static cselib_val *
 cselib_lookup_mem (rtx x, int create)
 {
   enum machine_mode mode = GET_MODE (x);
+  enum machine_mode pmode;
   void **slot;
   cselib_val *addr;
   cselib_val *mem_elt;
@@ -1075,8 +1195,12 @@ 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;
 
@@ -1093,8 +1217,8 @@ cselib_lookup_mem (rtx x, int create)
 
   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;
 }
@@ -1526,10 +1650,11 @@ cselib_expand_value_rtx_1 (rtx orig, str
    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);
@@ -1552,10 +1677,12 @@ 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.  */
+      gcc_checking_assert (e);
       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;
@@ -1566,14 +1693,24 @@ cselib_subst_to_values (rtx x)
     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;
@@ -1583,7 +1720,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))
 	    {
@@ -1598,7 +1735,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))
 		{
@@ -1617,13 +1754,16 @@ cselib_subst_to_values (rtx x)
   return copy;
 }
 
-/* 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).  */
+/* 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_lookup_1 (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;
@@ -1672,7 +1812,7 @@ cselib_lookup_1 (rtx x, enum machine_mod
 	  REG_VALUES (i) = new_elt_list (REG_VALUES (i), NULL);
 	}
       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 e;
     }
@@ -1680,13 +1820,13 @@ cselib_lookup_1 (rtx x, enum machine_mod
   if (MEM_P (x))
     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 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 0;
 
@@ -1700,7 +1840,8 @@ cselib_lookup_1 (rtx x, enum machine_mod
      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));
+  e->locs = new_elt_loc_list (e->locs,
+			      cselib_subst_to_values (x, memmode));
   return e;
 }
 
@@ -1708,14 +1849,14 @@ cselib_lookup_1 (rtx x, enum machine_mod
 
 cselib_val *
 cselib_lookup_from_insn (rtx x, enum machine_mode mode,
-			 int create, rtx insn)
+			 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);
+  ret = cselib_lookup (x, mode, create, memmode);
 
   cselib_current_insn = NULL;
 
@@ -1726,9 +1867,10 @@ cselib_lookup_from_insn (rtx x, enum mac
    maintains invariants related with debug insns.  */
 
 cselib_val *
-cselib_lookup (rtx x, enum machine_mode mode, int create)
+cselib_lookup (rtx x, enum machine_mode mode,
+	       int create, enum machine_mode memmode)
 {
-  cselib_val *ret = cselib_lookup_1 (x, mode, create);
+  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?
@@ -1913,7 +2055,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 (;;)
 	    {
@@ -1963,13 +2105,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.  */
@@ -2032,7 +2167,35 @@ cselib_record_set (rtx dest, cselib_val 
    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)
 {
@@ -2041,6 +2204,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)
@@ -2084,6 +2249,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++)
@@ -2102,14 +2272,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;
@@ -2124,6 +2295,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
@@ -2208,15 +2382,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))
Index: gcc/var-tracking.c
===================================================================
--- gcc/var-tracking.c.orig	2011-01-20 15:17:25.000000000 -0200
+++ gcc/var-tracking.c	2011-01-31 03:38:46.679239093 -0200
@@ -737,7 +737,7 @@ use_narrower_mode_test (rtx *loc, void *
   switch (GET_CODE (*loc))
     {
     case REG:
-      if (cselib_lookup (*loc, GET_MODE (SUBREG_REG (subreg)), 0))
+      if (cselib_lookup (*loc, GET_MODE (SUBREG_REG (subreg)), 0, VOIDmode))
 	return 1;
       return -1;
     case PLUS:
@@ -3954,8 +3954,10 @@ variable_post_merge_new_vals (void **slo
 			 subsequent rounds.  */
 		      cselib_val *v;
 		      gcc_assert (!cselib_lookup (node->loc,
-						  GET_MODE (node->loc), 0));
-		      v = cselib_lookup (node->loc, GET_MODE (node->loc), 1);
+						  GET_MODE (node->loc), 0,
+						  VOIDmode));
+		      v = cselib_lookup (node->loc, GET_MODE (node->loc), 1,
+					 VOIDmode);
 		      cselib_preserve_value (v);
 		      cselib_invalidate_rtx (node->loc);
 		      cval = v->val_rtx;
@@ -4793,7 +4795,7 @@ find_use_val (rtx x, enum machine_mode m
 	      return cui->sets[i].src_elt;
 	}
       else
-	return cselib_lookup (x, mode, 0);
+	return cselib_lookup (x, mode, 0, VOIDmode);
     }
 
   return NULL;
@@ -4822,14 +4824,15 @@ replace_expr_with_values (rtx loc)
   else if (MEM_P (loc))
     {
       cselib_val *addr = cselib_lookup (XEXP (loc, 0),
-					get_address_mode (loc), 0);
+					get_address_mode (loc), 0,
+					GET_MODE (loc));
       if (addr)
 	return replace_equiv_address_nv (loc, addr->val_rtx);
       else
 	return NULL;
     }
   else
-    return cselib_subst_to_values (loc);
+    return cselib_subst_to_values (loc, VOIDmode);
 }
 
 /* Determine what kind of micro operation to choose for a USE.  Return
@@ -4849,7 +4852,8 @@ use_type (rtx loc, struct count_use_info
 	      rtx ploc = PAT_VAR_LOCATION_LOC (loc);
 	      if (! VAR_LOC_UNKNOWN_P (ploc))
 		{
-		  cselib_val *val = cselib_lookup (ploc, GET_MODE (loc), 1);
+		  cselib_val *val = cselib_lookup (ploc, GET_MODE (loc), 1,
+						   VOIDmode);
 
 		  /* ??? flag_float_store and volatile mems are never
 		     given values, but we could in theory use them for
@@ -4871,7 +4875,8 @@ use_type (rtx loc, struct count_use_info
 	      if (REG_P (loc)
 		  || (find_use_val (loc, GET_MODE (loc), cui)
 		      && cselib_lookup (XEXP (loc, 0),
-					get_address_mode (loc), 0)))
+					get_address_mode (loc), 0,
+					GET_MODE (loc))))
 		return MO_VAL_SET;
 	    }
 	  else
@@ -5033,13 +5038,15 @@ add_uses (rtx *ploc, void *data)
 	      rtx mloc = vloc;
 	      enum machine_mode address_mode = get_address_mode (mloc);
 	      cselib_val *val
-		= cselib_lookup (XEXP (mloc, 0), address_mode, 0);
+		= cselib_lookup (XEXP (mloc, 0), address_mode, 0,
+				 GET_MODE (mloc));
 
 	      if (val && !cselib_preserved_value_p (val))
 		{
 		  micro_operation moa;
 		  preserve_value (val);
-		  mloc = cselib_subst_to_values (XEXP (mloc, 0));
+		  mloc = cselib_subst_to_values (XEXP (mloc, 0),
+						 GET_MODE (mloc));
 		  moa.type = MO_VAL_USE;
 		  moa.insn = cui->insn;
 		  moa.u.loc = gen_rtx_CONCAT (address_mode,
@@ -5109,13 +5116,15 @@ add_uses (rtx *ploc, void *data)
 	      rtx mloc = oloc;
 	      enum machine_mode address_mode = get_address_mode (mloc);
 	      cselib_val *val
-		= cselib_lookup (XEXP (mloc, 0), address_mode, 0);
+		= cselib_lookup (XEXP (mloc, 0), address_mode, 0,
+				GET_MODE (mloc));
 
 	      if (val && !cselib_preserved_value_p (val))
 		{
 		  micro_operation moa;
 		  preserve_value (val);
-		  mloc = cselib_subst_to_values (XEXP (mloc, 0));
+		  mloc = cselib_subst_to_values (XEXP (mloc, 0),
+						GET_MODE (mloc));
 		  moa.type = MO_VAL_USE;
 		  moa.insn = cui->insn;
 		  moa.u.loc = gen_rtx_CONCAT (address_mode,
@@ -5225,7 +5234,7 @@ reverse_op (rtx val, const_rtx expr)
   if (!SCALAR_INT_MODE_P (GET_MODE (src)) || XEXP (src, 0) == cfa_base_rtx)
     return NULL_RTX;
 
-  v = cselib_lookup (XEXP (src, 0), GET_MODE (XEXP (src, 0)), 0);
+  v = cselib_lookup (XEXP (src, 0), GET_MODE (XEXP (src, 0)), 0, VOIDmode);
   if (!v || !cselib_preserved_value_p (v))
     return NULL_RTX;
 
@@ -5346,13 +5355,15 @@ add_stores (rtx loc, const_rtx expr, voi
 	  rtx mloc = loc;
 	  enum machine_mode address_mode = get_address_mode (mloc);
 	  cselib_val *val = cselib_lookup (XEXP (mloc, 0),
-					   address_mode, 0);
+					   address_mode, 0,
+					   GET_MODE (mloc));
 
 	  if (val && !cselib_preserved_value_p (val))
 	    {
 	      preserve_value (val);
 	      mo.type = MO_VAL_USE;
-	      mloc = cselib_subst_to_values (XEXP (mloc, 0));
+	      mloc = cselib_subst_to_values (XEXP (mloc, 0),
+					     GET_MODE (mloc));
 	      mo.u.loc = gen_rtx_CONCAT (address_mode, val->val_rtx, mloc);
 	      mo.insn = cui->insn;
 	      if (dump_file && (dump_flags & TDF_DETAILS))
@@ -5411,7 +5422,7 @@ add_stores (rtx loc, const_rtx expr, voi
 
   if (GET_CODE (PATTERN (cui->insn)) == COND_EXEC)
     {
-      cselib_val *oval = cselib_lookup (oloc, GET_MODE (oloc), 0);
+      cselib_val *oval = cselib_lookup (oloc, GET_MODE (oloc), 0, VOIDmode);
 
       gcc_assert (oval != v);
       gcc_assert (REG_P (oloc) || MEM_P (oloc));
@@ -8077,7 +8088,8 @@ vt_add_function_parameter (tree parm)
       if (offset)
 	return;
 
-      val = cselib_lookup (var_lowpart (mode, incoming), mode, true);
+      val = cselib_lookup (var_lowpart (mode, incoming), mode, true,
+			   VOIDmode);
 
       /* ??? Float-typed values in memory are not handled by
 	 cselib.  */
@@ -8197,7 +8209,7 @@ vt_init_cfa_base (void)
 			    frame_pointer_needed
 			    ? hard_frame_pointer_rtx : stack_pointer_rtx);
   val = cselib_lookup_from_insn (cfa_base_rtx, GET_MODE (cfa_base_rtx), 1,
-				 get_insns ());
+				 VOIDmode, get_insns ());
   preserve_value (val);
   cselib_preserve_cfa_base_value (val, REGNO (cfa_base_rtx));
   var_reg_decl_set (&VTI (ENTRY_BLOCK_PTR)->out, cfa_base_rtx,
Index: gcc/sched-deps.c
===================================================================
--- gcc/sched-deps.c.orig	2011-01-31 03:08:08.760986846 -0200
+++ gcc/sched-deps.c	2011-01-31 03:38:46.725237282 -0200
@@ -1575,7 +1575,7 @@ add_insn_mem_dependence (struct deps_des
   if (sched_deps_info->use_cselib)
     {
       mem = shallow_copy_rtx (mem);
-      XEXP (mem, 0) = cselib_subst_to_values (XEXP (mem, 0));
+      XEXP (mem, 0) = cselib_subst_to_values (XEXP (mem, 0), GET_MODE (mem));
     }
   link = alloc_EXPR_LIST (VOIDmode, canon_rtx (mem), *mem_list);
   *mem_list = link;
@@ -2292,8 +2292,9 @@ sched_analyze_1 (struct deps_desc *deps,
 	    = targetm.addr_space.address_mode (MEM_ADDR_SPACE (dest));
 
 	  t = shallow_copy_rtx (dest);
-	  cselib_lookup_from_insn (XEXP (t, 0), address_mode, 1, insn);
-	  XEXP (t, 0) = cselib_subst_to_values (XEXP (t, 0));
+	  cselib_lookup_from_insn (XEXP (t, 0), address_mode, 1,
+				   GET_MODE (t), insn);
+	  XEXP (t, 0) = cselib_subst_to_values (XEXP (t, 0), GET_MODE (t));
 	}
       t = canon_rtx (t);
 
@@ -2449,8 +2450,9 @@ sched_analyze_2 (struct deps_desc *deps,
 	      = targetm.addr_space.address_mode (MEM_ADDR_SPACE (t));
 
 	    t = shallow_copy_rtx (t);
-	    cselib_lookup_from_insn (XEXP (t, 0), address_mode, 1, insn);
-	    XEXP (t, 0) = cselib_subst_to_values (XEXP (t, 0));
+	    cselib_lookup_from_insn (XEXP (t, 0), address_mode, 1,
+				     GET_MODE (t), insn);
+	    XEXP (t, 0) = cselib_subst_to_values (XEXP (t, 0), GET_MODE (t));
 	  }
 
 	if (!DEBUG_INSN_P (insn))
Index: gcc/gcse.c
===================================================================
--- gcc/gcse.c.orig	2011-01-14 21:38:07.000000000 -0200
+++ gcc/gcse.c	2011-01-31 03:38:46.814238295 -0200
@@ -2738,7 +2738,7 @@ do_local_cprop (rtx x, rtx insn)
           || (GET_CODE (PATTERN (insn)) != USE
 	      && asm_noperands (PATTERN (insn)) < 0)))
     {
-      cselib_val *val = cselib_lookup (x, GET_MODE (x), 0);
+      cselib_val *val = cselib_lookup (x, GET_MODE (x), 0, VOIDmode);
       struct elt_loc_list *l;
 
       if (!val)
Index: gcc/postreload.c
===================================================================
--- gcc/postreload.c.orig	2011-01-28 07:33:22.000000000 -0200
+++ gcc/postreload.c	2011-01-31 03:47:20.711238538 -0200
@@ -262,7 +262,7 @@ reload_cse_simplify_set (rtx set, rtx in
     return 0;
 #endif
 
-  val = cselib_lookup (src, GET_MODE (SET_DEST (set)), 0);
+  val = cselib_lookup (src, GET_MODE (SET_DEST (set)), 0, VOIDmode);
   if (! val)
     return 0;
 
@@ -476,7 +476,7 @@ reload_cse_simplify_operands (rtx insn, 
 	    continue;
 	}
 #endif /* LOAD_EXTEND_OP */
-      v = cselib_lookup (op, recog_data.operand_mode[i], 0);
+      v = cselib_lookup (op, recog_data.operand_mode[i], 0, VOIDmode);
       if (! v)
 	continue;
 
Index: gcc/sel-sched-dump.c
===================================================================
--- gcc/sel-sched-dump.c.orig	2011-01-14 21:38:09.000000000 -0200
+++ gcc/sel-sched-dump.c	2011-01-31 03:38:46.912244675 -0200
@@ -960,8 +960,8 @@ debug_mem_addr_value (rtx x)
   address_mode = targetm.addr_space.address_mode (MEM_ADDR_SPACE (x));
 
   t = shallow_copy_rtx (x);
-  if (cselib_lookup (XEXP (t, 0), address_mode, 0))
-    XEXP (t, 0) = cselib_subst_to_values (XEXP (t, 0));
+  if (cselib_lookup (XEXP (t, 0), address_mode, 0, GET_MODE (t)))
+    XEXP (t, 0) = cselib_subst_to_values (XEXP (t, 0), GET_MODE (t));
 
   t = canon_rtx (t);
   addr = get_addr (XEXP (t, 0));

[-- Attachment #3: Type: text/plain, Size: 258 bytes --]



-- 
Alexandre Oliva, freedom fighter    http://FSFLA.org/~lxoliva/
You must be the change you wish to see in the world. -- Gandhi
Be Free! -- http://FSFLA.org/   FSF Latin America board member
Free Software Evangelist      Red Hat Brazil Compiler Engineer

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH] Fix VTA sp (and fp) based MEM handling (PR debug/43051, PR debug/43092) and also PR debug/43494
  2011-01-31 10:45             ` Alexandre Oliva
@ 2011-01-31 18:48               ` Eric Botcazou
  0 siblings, 0 replies; 10+ messages in thread
From: Eric Botcazou @ 2011-01-31 18:48 UTC (permalink / raw)
  To: Alexandre Oliva
  Cc: gcc-patches, Steven Bosscher, Jakub Jelinek, bernds, Richard Guenther

> In the mean time, here's the modified patch.  Ok to install if it
> regstraps successfully?  What do you think of the “Remove the if stmt
> for the next release” comment?

	(cselib_record_sets): Use it, along with for_each_inc_dec.  Pass MEM
	mode to cselib_lookup.
	(cselib_process_insn): Don't reset autoinced REGs.

(cselib_record_sets): Use it, along with for_each_inc_dec.  Pass MEM
mode to cselib_lookup.  Reset autoinced REGs here instead of...
(cselib_process_insn): ...here.


@@ -1065,6 +1184,7 @@ static cselib_val *
 cselib_lookup_mem (rtx x, int create)
 {
   enum machine_mode mode = GET_MODE (x);
+  enum machine_mode pmode;
   void **slot;
   cselib_val *addr;
   cselib_val *mem_elt;

enum machine_mode addr_mode;


@@ -1552,10 +1677,12 @@ 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.  */
+      gcc_checking_assert (e);
       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;

I'm OK with the comment, but not really with the gcc_checking_assert at this 
stage of the 4.6 development.  Let's postpone it to next stage #1.


OK with these changes, thanks.

-- 
Eric Botcazou

^ permalink raw reply	[flat|nested] 10+ messages in thread

end of thread, other threads:[~2011-01-31 17:28 UTC | newest]

Thread overview: 10+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2010-03-15 13:16 [PATCH] Fix VTA sp (and fp) based MEM handling (PR debug/43051, PR debug/43092) Jakub Jelinek
2010-03-16 10:51 ` Richard Guenther
2010-03-23  8:52 ` Alexandre Oliva
2010-09-11  1:17   ` Alexandre Oliva
2010-09-11 12:41     ` Steven Bosscher
2010-09-21 11:45       ` Alexandre Oliva
2011-01-19 22:27         ` [PATCH] Fix VTA sp (and fp) based MEM handling (PR debug/43051, PR debug/43092) and also PR debug/43494 Alexandre Oliva
2011-01-27 19:42           ` Eric Botcazou
2011-01-31 10:45             ` Alexandre Oliva
2011-01-31 18:48               ` Eric Botcazou

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).