diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 581337c9d392f97ea3fd3514644298f9e54fb03a..f9ffe707a9b3fed564fe7e4831cc1d16d6640eff 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,10 @@
+2009-04-09  Richard Guenther  <rguenther@suse.de>
+
+	* tree-ssa-ccp.c (maybe_fold_stmt_addition): Move non-constant
+	indices into an array reference if possible.
+	* tree-ssa-forwprop.c (tree_ssa_forward_propagate_single_use_vars):
+	Fold POINTER_PLUS_EXPR statements with invariant address.
+
 2009-04-09  Alan Modra  <amodra@bigpond.net.au>
 
 	PR target/39634
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index 27343277a47ca37dc97a1b9a1ce151c2abbaa27c..e56170e1cd0cedf7a32cf37c228a7bfe0091a2ec 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -1,3 +1,8 @@
+2009-04-09  Richard Guenther  <rguenther@suse.de>
+
+	* gcc.dg/tree-ssa/ssa-ccp-25.c: New testcase.
+	* gcc.dg/tree-ssa/ssa-ccp-26.c: Likewise.
+
 2009-04-09  Joseph Myers  <joseph@codesourcery.com>
 
 	PR c/39613
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/ssa-ccp-25.c b/gcc/testsuite/gcc.dg/tree-ssa/ssa-ccp-25.c
new file mode 100644
index 0000000000000000000000000000000000000000..c6e76a2a3fd84a2435d9dd6a6d40f6b821222c74
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/tree-ssa/ssa-ccp-25.c
@@ -0,0 +1,14 @@
+/* { dg-do compile } */
+/* { dg-options "-O -fdump-tree-ccp1 -fdump-tree-forwprop1" } */
+
+int a[256];
+int foo(int i)
+{
+  int *p = &a[0];
+  return *(p + i);
+}
+
+/* { dg-final { scan-tree-dump "&a\\\[D\\\." "ccp1" } } */
+/* { dg-final { scan-tree-dump "= a\\\[D\\\." "forwprop1" } } */
+/* { dg-final { cleanup-tree-dump "ccp1" } } */
+/* { dg-final { cleanup-tree-dump "forwprop1" } } */
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/ssa-ccp-26.c b/gcc/testsuite/gcc.dg/tree-ssa/ssa-ccp-26.c
new file mode 100644
index 0000000000000000000000000000000000000000..542c42939607b8434838a1a5130b1eb8061994a9
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/tree-ssa/ssa-ccp-26.c
@@ -0,0 +1,11 @@
+/* { dg-do compile } */
+/* { dg-options "-O -fdump-tree-forwprop1" } */
+
+int a[256];
+int foo(int i)
+{
+  return (a + 1)[i];
+}
+
+/* { dg-final { scan-tree-dump "= a\\\[D\\\." "forwprop1" } } */
+/* { dg-final { cleanup-tree-dump "forwprop1" } } */
diff --git a/gcc/tree-ssa-ccp.c b/gcc/tree-ssa-ccp.c
index a67850448a79f0b95789d2035c0016a779075473..226fd3dbb27c6c29db1ab03dce506610233f8bed 100644
--- a/gcc/tree-ssa-ccp.c
+++ b/gcc/tree-ssa-ccp.c
@@ -2114,14 +2114,47 @@ maybe_fold_stmt_addition (tree res_type, tree op0, tree op1)
   tree ptd_type;
   tree t;
 
-  /* It had better be a constant.  */
-  if (TREE_CODE (op1) != INTEGER_CST)
-    return NULL_TREE;
   /* The first operand should be an ADDR_EXPR.  */
   if (TREE_CODE (op0) != ADDR_EXPR)
     return NULL_TREE;
   op0 = TREE_OPERAND (op0, 0);
 
+  /* It had better be a constant.  */
+  if (TREE_CODE (op1) != INTEGER_CST)
+    {
+      /* Or op0 should now be A[0] and the non-constant offset defined
+	 via a multiplication by the array element size.  */
+      if (TREE_CODE (op0) == ARRAY_REF
+	  && integer_zerop (TREE_OPERAND (op0, 1))
+	  && TREE_CODE (op1) == SSA_NAME
+	  && host_integerp (TYPE_SIZE_UNIT (TREE_TYPE (op0)), 1))
+	{
+	  gimple offset_def = SSA_NAME_DEF_STMT (op1);
+	  if (!is_gimple_assign (offset_def))
+	    return NULL_TREE;
+
+	  if (gimple_assign_rhs_code (offset_def) == MULT_EXPR
+	      && TREE_CODE (gimple_assign_rhs2 (offset_def)) == INTEGER_CST
+	      && tree_int_cst_equal (gimple_assign_rhs2 (offset_def),
+				     TYPE_SIZE_UNIT (TREE_TYPE (op0))))
+	    return build1 (ADDR_EXPR, res_type,
+			   build4 (ARRAY_REF, TREE_TYPE (op0),
+				   TREE_OPERAND (op0, 0),
+				   gimple_assign_rhs1 (offset_def),
+				   TREE_OPERAND (op0, 2),
+				   TREE_OPERAND (op0, 3)));
+	  else if (integer_onep (TYPE_SIZE_UNIT (TREE_TYPE (op0)))
+		   && gimple_assign_rhs_code (offset_def) != MULT_EXPR)
+	    return build1 (ADDR_EXPR, res_type,
+			   build4 (ARRAY_REF, TREE_TYPE (op0),
+				   TREE_OPERAND (op0, 0),
+				   op1,
+				   TREE_OPERAND (op0, 2),
+				   TREE_OPERAND (op0, 3)));
+	}
+      return NULL_TREE;
+    }
+
   /* If the first operand is an ARRAY_REF, expand it so that we can fold
      the offset into it.  */
   while (TREE_CODE (op0) == ARRAY_REF)
diff --git a/gcc/tree-ssa-forwprop.c b/gcc/tree-ssa-forwprop.c
index ff6bda0b1de87cd1cedb4363ef3ddc25c4ffb876..f75e0afa73ffec1048e5dd3f625bbdeb855ed46e 100644
--- a/gcc/tree-ssa-forwprop.c
+++ b/gcc/tree-ssa-forwprop.c
@@ -1256,6 +1256,15 @@ tree_ssa_forward_propagate_single_use_vars (void)
 		  else
 		    gsi_next (&gsi);
 		}
+	      else if (gimple_assign_rhs_code (stmt) == POINTER_PLUS_EXPR
+		       && is_gimple_min_invariant (rhs))
+		{
+		  /* Make sure to fold &a[0] + off_1 here.  */
+		  fold_stmt_inplace (stmt);
+		  update_stmt (stmt);
+		  if (gimple_assign_rhs_code (stmt) == POINTER_PLUS_EXPR)
+		    gsi_next (&gsi);
+		}
 	      else if ((gimple_assign_rhs_code (stmt) == BIT_NOT_EXPR
 		        || gimple_assign_rhs_code (stmt) == NEGATE_EXPR)
 		       && TREE_CODE (rhs) == SSA_NAME)