diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 7c3d87ad6a0e3a664acce94165228b060106c3b8..74c12b44709c78fa2c36741aab736d9f6bbd2e1a 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,14 @@
+2012-09-06  Richard Guenther  <rguenther@suse.de>
+
+	PR tree-optimization/54498
+	* tree-ssa-alias.h (get_continuation_for_phi): Add flag to
+	abort when reaching an already visited region.
+	* tree-ssa-alias.c (maybe_skip_until): Likewise.  And do it.
+	(get_continuation_for_phi_1): Likewise.
+	(walk_non_aliased_vuses): When we translated the reference,
+	abort when we re-visit a region.
+	* tree-ssa-pre.c (translate_vuse_through_block): Adjust.
+
 2012-09-06  David Edelsohn  <dje.gcc@gmail.com>
 
 	* config/rs6000/rs6000.c (rs6000_xcoff_asm_named_section): Add TLS
diff --git a/gcc/tree-ssa-alias.c b/gcc/tree-ssa-alias.c
index 574f418447d42f5fa3fd73c980be08d9e97625f0..8d515703a775e4335d406fac8451388a1b4d5f29 100644
--- a/gcc/tree-ssa-alias.c
+++ b/gcc/tree-ssa-alias.c
@@ -1929,7 +1929,8 @@ stmt_kills_ref_p (gimple stmt, tree ref)
 
 static bool
 maybe_skip_until (gimple phi, tree target, ao_ref *ref,
-		  tree vuse, unsigned int *cnt, bitmap *visited)
+		  tree vuse, unsigned int *cnt, bitmap *visited,
+		  bool abort_on_visited)
 {
   basic_block bb = gimple_bb (phi);
 
@@ -1947,8 +1948,9 @@ maybe_skip_until (gimple phi, tree target, ao_ref *ref,
 	{
 	  /* An already visited PHI node ends the walk successfully.  */
 	  if (bitmap_bit_p (*visited, SSA_NAME_VERSION (PHI_RESULT (def_stmt))))
-	    return true;
-	  vuse = get_continuation_for_phi (def_stmt, ref, cnt, visited);
+	    return !abort_on_visited;
+	  vuse = get_continuation_for_phi (def_stmt, ref, cnt,
+					   visited, abort_on_visited);
 	  if (!vuse)
 	    return false;
 	  continue;
@@ -1967,7 +1969,7 @@ maybe_skip_until (gimple phi, tree target, ao_ref *ref,
       if (gimple_bb (def_stmt) != bb)
 	{
 	  if (!bitmap_set_bit (*visited, SSA_NAME_VERSION (vuse)))
-	    return true;
+	    return !abort_on_visited;
 	  bb = gimple_bb (def_stmt);
 	}
       vuse = gimple_vuse (def_stmt);
@@ -1981,7 +1983,8 @@ maybe_skip_until (gimple phi, tree target, ao_ref *ref,
 
 static tree
 get_continuation_for_phi_1 (gimple phi, tree arg0, tree arg1,
-			    ao_ref *ref, unsigned int *cnt, bitmap *visited)
+			    ao_ref *ref, unsigned int *cnt,
+			    bitmap *visited, bool abort_on_visited)
 {
   gimple def0 = SSA_NAME_DEF_STMT (arg0);
   gimple def1 = SSA_NAME_DEF_STMT (arg1);
@@ -1994,14 +1997,16 @@ get_continuation_for_phi_1 (gimple phi, tree arg0, tree arg1,
 	       && dominated_by_p (CDI_DOMINATORS,
 				  gimple_bb (def1), gimple_bb (def0))))
     {
-      if (maybe_skip_until (phi, arg0, ref, arg1, cnt, visited))
+      if (maybe_skip_until (phi, arg0, ref, arg1, cnt,
+			    visited, abort_on_visited))
 	return arg0;
     }
   else if (gimple_nop_p (def1)
 	   || dominated_by_p (CDI_DOMINATORS,
 			      gimple_bb (def0), gimple_bb (def1)))
     {
-      if (maybe_skip_until (phi, arg1, ref, arg0, cnt, visited))
+      if (maybe_skip_until (phi, arg1, ref, arg0, cnt,
+			    visited, abort_on_visited))
 	return arg1;
     }
   /* Special case of a diamond:
@@ -2038,7 +2043,8 @@ get_continuation_for_phi_1 (gimple phi, tree arg0, tree arg1,
 
 tree
 get_continuation_for_phi (gimple phi, ao_ref *ref,
-			  unsigned int *cnt, bitmap *visited)
+			  unsigned int *cnt, bitmap *visited,
+			  bool abort_on_visited)
 {
   unsigned nargs = gimple_phi_num_args (phi);
 
@@ -2076,7 +2082,7 @@ get_continuation_for_phi (gimple phi, ao_ref *ref,
 	{
 	  arg1 = PHI_ARG_DEF (phi, i);
 	  arg0 = get_continuation_for_phi_1 (phi, arg0, arg1, ref,
-					     cnt, visited);
+					     cnt, visited, abort_on_visited);
 	  if (!arg0)
 	    return NULL_TREE;
 	}
@@ -2113,6 +2119,7 @@ walk_non_aliased_vuses (ao_ref *ref, tree vuse,
   bitmap visited = NULL;
   void *res;
   unsigned int cnt = 0;
+  bool translated = false;
 
   timevar_push (TV_ALIAS_STMT_WALK);
 
@@ -2136,7 +2143,8 @@ walk_non_aliased_vuses (ao_ref *ref, tree vuse,
       if (gimple_nop_p (def_stmt))
 	break;
       else if (gimple_code (def_stmt) == GIMPLE_PHI)
-	vuse = get_continuation_for_phi (def_stmt, ref, &cnt, &visited);
+	vuse = get_continuation_for_phi (def_stmt, ref, &cnt,
+					 &visited, translated);
       else
 	{
 	  cnt++;
@@ -2155,6 +2163,7 @@ walk_non_aliased_vuses (ao_ref *ref, tree vuse,
 	      else if (res != NULL)
 		break;
 	      /* Translation succeeded, continue walking.  */
+	      translated = true;
 	    }
 	  vuse = gimple_vuse (def_stmt);
 	}
diff --git a/gcc/tree-ssa-alias.h b/gcc/tree-ssa-alias.h
index cdff3812181c21e9352f5b385ecb26028c7fe8ac..6f38f20bce580abeb79f481dae4cb4abc1752ed5 100644
--- a/gcc/tree-ssa-alias.h
+++ b/gcc/tree-ssa-alias.h
@@ -108,7 +108,7 @@ extern bool stmt_may_clobber_ref_p_1 (gimple, ao_ref *);
 extern bool call_may_clobber_ref_p (gimple, tree);
 extern bool stmt_kills_ref_p (gimple, tree);
 extern tree get_continuation_for_phi (gimple, ao_ref *,
-				      unsigned int *, bitmap *);
+				      unsigned int *, bitmap *, bool);
 extern void *walk_non_aliased_vuses (ao_ref *, tree,
 				     void *(*)(ao_ref *, tree,
 					       unsigned int, void *),
diff --git a/gcc/tree-ssa-pre.c b/gcc/tree-ssa-pre.c
index bb1a03dfe99752dbdb49eb3fc84d70dab6094029..e64d4f75a9b48ae2e1c28e04da524254ad572681 100644
--- a/gcc/tree-ssa-pre.c
+++ b/gcc/tree-ssa-pre.c
@@ -1291,7 +1291,7 @@ translate_vuse_through_block (VEC (vn_reference_op_s, heap) *operands,
 	  unsigned int cnt;
 	  /* Try to find a vuse that dominates this phi node by skipping
 	     non-clobbering statements.  */
-	  vuse = get_continuation_for_phi (phi, &ref, &cnt, &visited);
+	  vuse = get_continuation_for_phi (phi, &ref, &cnt, &visited, false);
 	  if (visited)
 	    BITMAP_FREE (visited);
 	}