This extends try_move_mult_to_index folding to be less picky about the outermost array reference and handles a component-ref of an array the same as if that were wrapped with an array-ref with minimum index.
This consolidates array-ref reconstruction to the frontend-closest position we have right now (eventually that function should move to some c-family helper I guess). Bootstrapped and tested on x86_64-unknown-linux-gnu, applied to trunk. Richard. 2011-09-28 Richard Guenther <rguent...@suse.de> PR middle-end/50460 * fold-const.c (try_move_mult_to_index): Handle &a.array the same as &a.array[0]. Index: gcc/fold-const.c =================================================================== *** gcc/fold-const.c (revision 179308) --- gcc/fold-const.c (working copy) *************** try_move_mult_to_index (location_t loc, *** 6870,6875 **** --- 6870,6929 ---- break; } + else if (TREE_CODE (ref) == COMPONENT_REF + && TREE_CODE (TREE_TYPE (ref)) == ARRAY_TYPE) + { + tree domain; + + /* Remember if this was a multi-dimensional array. */ + if (TREE_CODE (TREE_OPERAND (ref, 0)) == ARRAY_REF) + mdim = true; + + domain = TYPE_DOMAIN (TREE_TYPE (ref)); + if (! domain) + continue; + itype = TREE_TYPE (domain); + + step = TYPE_SIZE_UNIT (TREE_TYPE (TREE_TYPE (ref))); + if (TREE_CODE (step) != INTEGER_CST) + continue; + + if (s) + { + if (! tree_int_cst_equal (step, s)) + continue; + } + else + { + /* Try if delta is a multiple of step. */ + tree tmp = div_if_zero_remainder (EXACT_DIV_EXPR, op1, step); + if (! tmp) + continue; + delta = tmp; + } + + /* Only fold here if we can verify we do not overflow one + dimension of a multi-dimensional array. */ + if (mdim) + { + tree tmp; + + if (!TYPE_MIN_VALUE (domain) + || !TYPE_MAX_VALUE (domain) + || TREE_CODE (TYPE_MAX_VALUE (domain)) != INTEGER_CST) + continue; + + tmp = fold_binary_loc (loc, PLUS_EXPR, itype, + fold_convert_loc (loc, itype, + TYPE_MIN_VALUE (domain)), + fold_convert_loc (loc, itype, delta)); + if (TREE_CODE (tmp) != INTEGER_CST + || tree_int_cst_lt (TYPE_MAX_VALUE (domain), tmp)) + continue; + } + + break; + } else mdim = false; *************** try_move_mult_to_index (location_t loc, *** 6892,6903 **** pos = TREE_OPERAND (pos, 0); } ! TREE_OPERAND (pos, 1) = fold_build2_loc (loc, PLUS_EXPR, itype, ! fold_convert_loc (loc, itype, ! TREE_OPERAND (pos, 1)), ! fold_convert_loc (loc, itype, delta)); ! ! return fold_build1_loc (loc, ADDR_EXPR, TREE_TYPE (addr), ret); } --- 6946,6974 ---- pos = TREE_OPERAND (pos, 0); } ! if (TREE_CODE (ref) == ARRAY_REF) ! { ! TREE_OPERAND (pos, 1) ! = fold_build2_loc (loc, PLUS_EXPR, itype, ! fold_convert_loc (loc, itype, TREE_OPERAND (pos, 1)), ! fold_convert_loc (loc, itype, delta)); ! return fold_build1_loc (loc, ADDR_EXPR, TREE_TYPE (addr), ret); ! } ! else if (TREE_CODE (ref) == COMPONENT_REF) ! { ! gcc_assert (ret == pos); ! ret = build4_loc (loc, ARRAY_REF, TREE_TYPE (TREE_TYPE (ref)), ret, ! fold_build2_loc ! (loc, PLUS_EXPR, itype, ! fold_convert_loc (loc, itype, ! TYPE_MIN_VALUE ! (TYPE_DOMAIN (TREE_TYPE (ref)))), ! fold_convert_loc (loc, itype, delta)), ! NULL_TREE, NULL_TREE); ! return build_fold_addr_expr_loc (loc, ret); ! } ! else ! gcc_unreachable (); }