diff -Nur gcc-4.8.2.orig/gcc/tree-ssa-forwprop.c gcc-4.8.2/gcc/tree-ssa-forwprop.c
--- gcc-4.8.2.orig/gcc/tree-ssa-forwprop.c	2013-02-25 16:31:31.000000000 +0100
+++ gcc-4.8.2/gcc/tree-ssa-forwprop.c	2014-03-22 19:37:04.797991879 +0100
@@ -688,6 +688,130 @@
      recompute_tree_invariant_for_addr_expr (gimple_assign_rhs1 (stmt));
 }
 
+ /* DEF_RHS contains the address of the 0th element in an array.	 
+    USE_STMT uses type of DEF_RHS to compute the address of an	 
+    arbitrary element within the array.  The (variable) byte offset	 
+    of the element is contained in OFFSET.	 
+ 	 
+    We walk back through the use-def chains of OFFSET to verify that	 
+    it is indeed computing the offset of an element within the array	 
+    and extract the index corresponding to the given byte offset.	 
+ 	 
+    We then try to fold the entire address expression into a form	 
+    &array[index].	 
+ 	 
+    If we are successful, we replace the right hand side of USE_STMT	 
+    with the new address computation.  */	 
+ 	 
+ static bool	 
+ forward_propagate_addr_into_variable_array_index (tree offset,	 
+                                                   tree def_rhs,	 
+                                                   gimple_stmt_iterator *use_stmt_gsi)	 
+ {	 
+   tree index, tunit;	 
+   gimple offset_def, use_stmt = gsi_stmt (*use_stmt_gsi);	 
+   tree new_rhs, tmp;	 
+ 	 
+   if (TREE_CODE (TREE_OPERAND (def_rhs, 0)) == ARRAY_REF)	 
+     tunit = TYPE_SIZE_UNIT (TREE_TYPE (TREE_TYPE (def_rhs)));	 
+   else if (TREE_CODE (TREE_TYPE (TREE_OPERAND (def_rhs, 0))) == ARRAY_TYPE)	 
+     tunit = TYPE_SIZE_UNIT (TREE_TYPE (TREE_TYPE (TREE_TYPE (def_rhs))));	 
+   else	 
+     return false;	 
+   if (!host_integerp (tunit, 1))	 
+     return false;	 
+ 	 
+   /* Get the offset's defining statement.  */	 
+   offset_def = SSA_NAME_DEF_STMT (offset);	 
+ 	 
+   /* Try to find an expression for a proper index.  This is either a	 
+      multiplication expression by the element size or just the ssa name we came	 
+      along in case the element size is one. In that case, however, we do not	 
+      allow multiplications because they can be computing index to a higher	 
+      level dimension (PR 37861). */	 
+   if (integer_onep (tunit))	 
+     {	 
+       if (is_gimple_assign (offset_def)	 
+           && gimple_assign_rhs_code (offset_def) == MULT_EXPR)	 
+         return false;	 
+ 	 
+       index = offset;	 
+     }	 
+   else	 
+     {	 
+       /* The statement which defines OFFSET before type conversion	 
+          must be a simple GIMPLE_ASSIGN.  */	 
+       if (!is_gimple_assign (offset_def))	 
+         return false;	 
+ 	 
+       /* The RHS of the statement which defines OFFSET must be a	 
+          multiplication of an object by the size of the array elements.	 
+          This implicitly verifies that the size of the array elements	 
+          is constant.  */	 
+      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), tunit))	 
+        {	 
+          /* The first operand to the MULT_EXPR is the desired index.  */	 
+          index = gimple_assign_rhs1 (offset_def);	 
+        }	 
+      /* If we have idx * tunit + CST * tunit re-associate that.  */	 
+      else if ((gimple_assign_rhs_code (offset_def) == PLUS_EXPR	 
+                || gimple_assign_rhs_code (offset_def) == MINUS_EXPR)	 
+               && TREE_CODE (gimple_assign_rhs1 (offset_def)) == SSA_NAME	 
+               && TREE_CODE (gimple_assign_rhs2 (offset_def)) == INTEGER_CST	 
+               && (tmp = div_if_zero_remainder (EXACT_DIV_EXPR,	 
+                                                gimple_assign_rhs2 (offset_def),	 
+                                                tunit)) != NULL_TREE)	 
+        {	 
+          gimple offset_def2 = SSA_NAME_DEF_STMT (gimple_assign_rhs1 (offset_def));	 
+          if (is_gimple_assign (offset_def2)	 
+              && gimple_assign_rhs_code (offset_def2) == MULT_EXPR	 
+              && TREE_CODE (gimple_assign_rhs2 (offset_def2)) == INTEGER_CST	 
+              && tree_int_cst_equal (gimple_assign_rhs2 (offset_def2), tunit))	 
+            {	 
+              index = fold_build2 (gimple_assign_rhs_code (offset_def),	 
+                                   TREE_TYPE (offset),	 
+                                   gimple_assign_rhs1 (offset_def2), tmp);	 
+            }	 
+          else	 
+            return false;	 
+        }	 
+      else	 
+         return false;	 
+     }	 
+ 	 
+   /* Replace the pointer addition with array indexing.  */	 
+   index = force_gimple_operand_gsi (use_stmt_gsi, index, true, NULL_TREE,	 
+                                     true, GSI_SAME_STMT);	 
+   if (TREE_CODE (TREE_OPERAND (def_rhs, 0)) == ARRAY_REF)	 
+     {	 
+       new_rhs = unshare_expr (def_rhs);	 
+       TREE_OPERAND (TREE_OPERAND (new_rhs, 0), 1) = index;	 
+     }	 
+   else	 
+     {	 
+       new_rhs = build4 (ARRAY_REF, TREE_TYPE (TREE_TYPE (TREE_TYPE (def_rhs))),	 
+                         unshare_expr (TREE_OPERAND (def_rhs, 0)),	 
+                         index, integer_zero_node, NULL_TREE);	 
+       new_rhs = build_fold_addr_expr (new_rhs);	 
+       if (!useless_type_conversion_p (TREE_TYPE (gimple_assign_lhs (use_stmt)),	 
+                                       TREE_TYPE (new_rhs)))	 
+         {	 
+           new_rhs = force_gimple_operand_gsi (use_stmt_gsi, new_rhs, true,	 
+                                               NULL_TREE, true, GSI_SAME_STMT);	 
+           new_rhs = fold_convert (TREE_TYPE (gimple_assign_lhs (use_stmt)),	 
+                                   new_rhs);	 
+         }	 
+     }	 
+   gimple_assign_set_rhs_from_tree (use_stmt_gsi, new_rhs);	 
+   fold_stmt (use_stmt_gsi);	 
+   tidy_after_forward_propagate_addr (gsi_stmt (*use_stmt_gsi));	 
+   return true;	 
+ }	 
+
+
+
 /* NAME is a SSA_NAME representing DEF_RHS which is of the form
    ADDR_EXPR <whatever>.
 
@@ -977,6 +1101,19 @@
       tidy_after_forward_propagate_addr (use_stmt);
       return true;
     }
+   /* Try to optimize &x[0] p+ OFFSET where OFFSET is defined by	 
+      converting a multiplication of an index by the size of the	 
+      array elements, then the result is converted into the proper	 
+      type for the arithmetic.  */	 
+   if (TREE_CODE (rhs2) == SSA_NAME	 
+       && (TREE_CODE (array_ref) != ARRAY_REF	 
+           || integer_zerop (TREE_OPERAND (array_ref, 1)))	 
+       && useless_type_conversion_p (TREE_TYPE (name), TREE_TYPE (def_rhs))	 
+       /* Avoid problems with IVopts creating PLUS_EXPRs with a	 
+          different type than their operands.  */	 
+       && useless_type_conversion_p (TREE_TYPE (lhs), TREE_TYPE (def_rhs)))	 
+     return forward_propagate_addr_into_variable_array_index (rhs2, def_rhs,	 
+                                                              use_stmt_gsi);	 
 
   return false;
 }
