--- gcc/tree-cfg.c	2013-08-05 22:16:05.000000000 +0200
+++ gcc/tree-cfg.c	2013-09-04 20:01:15.000000000 +0200
@@ -3571,31 +3571,6 @@ verify_gimple_assign_binary (gimple stmt
     case PLUS_EXPR:
     case MINUS_EXPR:
       {
-	/* We use regular PLUS_EXPR and MINUS_EXPR for vectors.
-	   ???  This just makes the checker happy and may not be what is
-	   intended.  */
-	if (TREE_CODE (lhs_type) == VECTOR_TYPE
-	    && POINTER_TYPE_P (TREE_TYPE (lhs_type)))
-	  {
-	    if (TREE_CODE (rhs1_type) != VECTOR_TYPE
-		|| TREE_CODE (rhs2_type) != VECTOR_TYPE)
-	      {
-		error ("invalid non-vector operands to vector valued plus");
-		return true;
-	      }
-	    lhs_type = TREE_TYPE (lhs_type);
-	    rhs1_type = TREE_TYPE (rhs1_type);
-	    rhs2_type = TREE_TYPE (rhs2_type);
-	    /* PLUS_EXPR is commutative, so we might end up canonicalizing
-	       the pointer to 2nd place.  */
-	    if (POINTER_TYPE_P (rhs2_type))
-	      {
-		tree tem = rhs1_type;
-		rhs1_type = rhs2_type;
-		rhs2_type = tem;
-	      }
-	    goto do_pointer_plus_expr_check;
-	  }
 	if (POINTER_TYPE_P (lhs_type)
 	    || POINTER_TYPE_P (rhs1_type)
 	    || POINTER_TYPE_P (rhs2_type))
@@ -3610,7 +3585,18 @@ verify_gimple_assign_binary (gimple stmt
 
     case POINTER_PLUS_EXPR:
       {
-do_pointer_plus_expr_check:
+	if (TREE_CODE (lhs_type) == VECTOR_TYPE)
+	  {
+	    if (TREE_CODE (rhs1_type) != VECTOR_TYPE
+		|| TREE_CODE (rhs2_type) != VECTOR_TYPE)
+	      {
+		error ("invalid non-vector operands to vector valued pointer plus");
+		return true;
+	      }
+	    lhs_type = TREE_TYPE (lhs_type);
+	    rhs1_type = TREE_TYPE (rhs1_type);
+	    rhs2_type = TREE_TYPE (rhs2_type);
+	  }
 	if (!POINTER_TYPE_P (rhs1_type)
 	    || !useless_type_conversion_p (lhs_type, rhs1_type)
 	    || !ptrofftype_p (rhs2_type))
--- gcc/tree.c	2013-08-24 00:16:08.000000000 +0200
+++ gcc/tree.c	2013-09-04 20:01:08.000000000 +0200
@@ -4092,8 +4092,14 @@ build2_stat (enum tree_code code, tree t
 		&& TREE_CODE (arg1) == INTEGER_CST);
 
   if (code == POINTER_PLUS_EXPR && arg0 && arg1 && tt)
-    gcc_assert (POINTER_TYPE_P (tt) && POINTER_TYPE_P (TREE_TYPE (arg0))
-		&& ptrofftype_p (TREE_TYPE (arg1)));
+    gcc_assert ((POINTER_TYPE_P (tt) && POINTER_TYPE_P (TREE_TYPE (arg0))
+		 && ptrofftype_p (TREE_TYPE (arg1)))
+		|| (TREE_CODE (tt) == VECTOR_TYPE
+		    && TREE_CODE (TREE_TYPE (arg0)) == VECTOR_TYPE
+		    && TREE_CODE (TREE_TYPE (arg1)) == VECTOR_TYPE
+		    && POINTER_TYPE_P (TREE_TYPE (tt))
+		    && POINTER_TYPE_P (TREE_TYPE (TREE_TYPE (arg0)))
+		    && ptrofftype_p (TREE_TYPE (TREE_TYPE (arg1)))));
 
   t = make_node_stat (code PASS_MEM_STAT);
   TREE_TYPE (t) = tt;
--- gcc/tree-vect-stmts.c	2013-06-27 17:35:57.000000000 +0200
+++ gcc/tree-vect-stmts.c	2013-09-04 20:01:44.000000000 +0200
@@ -3470,11 +3470,6 @@ vectorizable_operation (gimple stmt, gim
 
   code = gimple_assign_rhs_code (stmt);
 
-  /* For pointer addition, we should use the normal plus for
-     the vector addition.  */
-  if (code == POINTER_PLUS_EXPR)
-    code = PLUS_EXPR;
-
   /* Support only unary or binary operations.  */
   op_type = TREE_CODE_LENGTH (code);
   if (op_type != unary_op && op_type != binary_op && op_type != ternary_op)
--- gcc/tree-vect-loop.c	2013-07-02 13:54:09.000000000 +0200
+++ gcc/tree-vect-loop.c	2013-09-04 20:02:38.000000000 +0200
@@ -3323,8 +3323,9 @@ get_initial_def_for_induction (gimple iv
   induc_def = PHI_RESULT (induction_phi);
 
   /* Create the iv update inside the loop  */
-  new_stmt = gimple_build_assign_with_ops (PLUS_EXPR, vec_dest,
-					   induc_def, vec_step);
+  new_stmt = gimple_build_assign_with_ops (POINTER_TYPE_P (scalar_type)
+					   ? POINTER_PLUS_EXPR : PLUS_EXPR,
+					   vec_dest, induc_def, vec_step);
   vec_def = make_ssa_name (vec_dest, new_stmt);
   gimple_assign_set_lhs (new_stmt, vec_def);
   gsi_insert_before (&si, new_stmt, GSI_SAME_STMT);
--- gcc/tree-ssa-forwprop.c	2013-08-05 22:16:05.000000000 +0200
+++ gcc/tree-ssa-forwprop.c	2013-09-04 23:13:43.000000000 +0200
@@ -2739,6 +2739,44 @@ associate_pointerplus (gimple_stmt_itera
   gimple def_stmt;
   tree ptr, rhs, algn;
 
+  ptr = gimple_assign_rhs1 (stmt);
+  rhs = gimple_assign_rhs2 (stmt);
+
+  /* Pattern match
+       tem = ptr p+ cst1;
+       ... = tem p+ cst2;
+     and produce the simpler
+       ... = ptr p+ cst; */
+  if (TREE_CODE (ptr) == SSA_NAME)
+    {
+      def_stmt = SSA_NAME_DEF_STMT (ptr);
+      if (is_gimple_assign (def_stmt) && can_propagate_from (def_stmt))
+	{
+	  enum tree_code def_code = gimple_assign_rhs_code (def_stmt);
+	  if (def_code == POINTER_PLUS_EXPR)
+	    {
+	      tree def_ptr = gimple_assign_rhs1 (def_stmt);
+	      tree def_rhs = gimple_assign_rhs2 (def_stmt);
+	      if (CONSTANT_CLASS_P (rhs)
+		  && CONSTANT_CLASS_P (def_rhs))
+		{
+		  /* (A p+ CST) p+ CST -> A p+ CST.  */
+		  tree cst = fold_binary (PLUS_EXPR, TREE_TYPE (rhs),
+					  def_rhs, rhs);
+		  if (cst && !TREE_OVERFLOW (cst))
+		    {
+		      gimple_assign_set_rhs_code (stmt, def_code);
+		      gimple_assign_set_rhs1 (stmt, def_ptr);
+		      gimple_assign_set_rhs2 (stmt, cst);
+		      fold_stmt_inplace (gsi);
+		      update_stmt (stmt);
+		      return true;
+		    }
+		}
+	    }
+        }
+    }
+
   /* Pattern match
        tem = (sizetype) ptr;
        tem = tem & algn;
@@ -2746,8 +2784,6 @@ associate_pointerplus (gimple_stmt_itera
        ... = ptr p+ tem;
      and produce the simpler and easier to analyze with respect to alignment
        ... = ptr & ~algn;  */
-  ptr = gimple_assign_rhs1 (stmt);
-  rhs = gimple_assign_rhs2 (stmt);
   if (TREE_CODE (rhs) != SSA_NAME)
     return false;
   def_stmt = SSA_NAME_DEF_STMT (rhs);
--- gcc/testsuite/gcc.target/i386/pr58137.c	1970-01-01 01:00:00.000000000 +0100
+++ gcc/testsuite/gcc.target/i386/pr58137.c	2013-08-19 17:35:57.000000000 +0200
@@ -0,0 +1,34 @@
+/* PR tree-optimization/58137 */
+/* { dg-do compile } */
+/* { dg-options "-O3 -mavx2" } */
+
+typedef unsigned int U32;
+
+struct sv {
+  void* sv_any;
+  U32 sv_refcnt;
+  U32 sv_flags;
+};
+typedef struct sv SV;
+
+struct xrv {
+  SV * xrv_rv;
+};
+typedef struct xrv XRV;
+
+extern XRV * PL_xrv_root;
+
+void
+more_xrv (void)
+{
+  register XRV* xrv;
+  register XRV* xrvend;
+  xrv = PL_xrv_root;
+  xrvend = &xrv[200 / sizeof (XRV) - 1];
+  while (xrv < xrvend)
+  {
+    xrv->xrv_rv = (SV*)(xrv + 1);
+    xrv++;
+  }
+  xrv->xrv_rv = 0;
+}
