From: Richard Guenther Date: Tue, 30 Aug 2011 14:06:00 +0000 (+0000) Subject: re PR tree-optimization/48571 (Missed data-dependence for (bogus?) reconstructed... X-Git-Tag: releases/gcc-4.7.0~4109 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=315f5f1bfbcbc444e5853fb54fa37edae58e5f91;p=thirdparty%2Fgcc.git re PR tree-optimization/48571 (Missed data-dependence for (bogus?) reconstructed array-refs) 2011-08-30 Richard Guenther PR middle-end/48571 * gimple.h (maybe_fold_offset_to_address): Remove. (maybe_fold_offset_to_reference): Likewise. (maybe_fold_stmt_addition): Likewise. (may_propagate_address_into_dereference): Likewise. * tree-inline.c (remap_gimple_op_r): Do not reconstruct array references. * gimple-fold.c (canonicalize_constructor_val): Likewise. Canonicalize invariant POINTER_PLUS_EXPRs to invariant MEM_REF addresses instead. (may_propagate_address_into_dereference): Remove. (maybe_fold_offset_to_array_ref): Likewise. (maybe_fold_offset_to_reference): Likewise. (maybe_fold_offset_to_address): Likewise. (maybe_fold_stmt_addition): Likewise. (fold_gimple_assign): Do not reconstruct array references but instead canonicalize invariant POINTER_PLUS_EXPRs to invariant MEM_REF addresses. (gimple_fold_stmt_to_constant_1): Likewise. * tree-ssa-forwprop.c (forward_propagate_addr_expr_1): Likewise. * gimplify.c (gimplify_conversion): Likewise. (gimplify_expr): Likewise. * gcc.c-torture/execute/pr48571-1.c: New testcase. * gcc.dg/tree-ssa/ssa-ccp-25.c: Remove. * gcc.dg/tree-ssa/ssa-ccp-26.c: Likewise. * gcc.dg/pr36902.c: XFAIL. From-SVN: r178312 --- diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 03db902f3cdc..0313a8400cbe 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,28 @@ +2011-08-30 Richard Guenther + + PR middle-end/48571 + * gimple.h (maybe_fold_offset_to_address): Remove. + (maybe_fold_offset_to_reference): Likewise. + (maybe_fold_stmt_addition): Likewise. + (may_propagate_address_into_dereference): Likewise. + * tree-inline.c (remap_gimple_op_r): Do not reconstruct + array references. + * gimple-fold.c (canonicalize_constructor_val): Likewise. + Canonicalize invariant POINTER_PLUS_EXPRs to invariant MEM_REF + addresses instead. + (may_propagate_address_into_dereference): Remove. + (maybe_fold_offset_to_array_ref): Likewise. + (maybe_fold_offset_to_reference): Likewise. + (maybe_fold_offset_to_address): Likewise. + (maybe_fold_stmt_addition): Likewise. + (fold_gimple_assign): Do not reconstruct array references but + instead canonicalize invariant POINTER_PLUS_EXPRs to invariant + MEM_REF addresses. + (gimple_fold_stmt_to_constant_1): Likewise. + * tree-ssa-forwprop.c (forward_propagate_addr_expr_1): Likewise. + * gimplify.c (gimplify_conversion): Likewise. + (gimplify_expr): Likewise. + 2011-08-30 Ilya Tocar * config/i386/fmaintrin.h: New. diff --git a/gcc/gimple-fold.c b/gcc/gimple-fold.c index 19f34000654d..72dc42a5bdc9 100644 --- a/gcc/gimple-fold.c +++ b/gcc/gimple-fold.c @@ -116,14 +116,17 @@ tree canonicalize_constructor_val (tree cval) { STRIP_NOPS (cval); - if (TREE_CODE (cval) == POINTER_PLUS_EXPR) - { - tree t = maybe_fold_offset_to_address (EXPR_LOCATION (cval), - TREE_OPERAND (cval, 0), - TREE_OPERAND (cval, 1), - TREE_TYPE (cval)); - if (t) - cval = t; + if (TREE_CODE (cval) == POINTER_PLUS_EXPR + && TREE_CODE (TREE_OPERAND (cval, 1)) == INTEGER_CST) + { + tree ptr = TREE_OPERAND (cval, 0); + if (is_gimple_min_invariant (ptr)) + cval = build1_loc (EXPR_LOCATION (cval), + ADDR_EXPR, TREE_TYPE (ptr), + fold_build2 (MEM_REF, TREE_TYPE (TREE_TYPE (ptr)), + ptr, + fold_convert (ptr_type_node, + TREE_OPERAND (cval, 1)))); } if (TREE_CODE (cval) == ADDR_EXPR) { @@ -173,384 +176,6 @@ get_symbol_constant_value (tree sym) } -/* Return true if we may propagate the address expression ADDR into the - dereference DEREF and cancel them. */ - -bool -may_propagate_address_into_dereference (tree addr, tree deref) -{ - gcc_assert (TREE_CODE (deref) == MEM_REF - && TREE_CODE (addr) == ADDR_EXPR); - - /* Don't propagate if ADDR's operand has incomplete type. */ - if (!COMPLETE_TYPE_P (TREE_TYPE (TREE_OPERAND (addr, 0)))) - return false; - - /* If the address is invariant then we do not need to preserve restrict - qualifications. But we do need to preserve volatile qualifiers until - we can annotate the folded dereference itself properly. */ - if (is_gimple_min_invariant (addr) - && (!TREE_THIS_VOLATILE (deref) - || TYPE_VOLATILE (TREE_TYPE (addr)))) - return useless_type_conversion_p (TREE_TYPE (deref), - TREE_TYPE (TREE_OPERAND (addr, 0))); - - /* Else both the address substitution and the folding must result in - a valid useless type conversion sequence. */ - return (useless_type_conversion_p (TREE_TYPE (TREE_OPERAND (deref, 0)), - TREE_TYPE (addr)) - && useless_type_conversion_p (TREE_TYPE (deref), - TREE_TYPE (TREE_OPERAND (addr, 0)))); -} - - -/* A subroutine of fold_stmt. Attempts to fold *(A+O) to A[X]. - BASE is an array type. OFFSET is a byte displacement. - - LOC is the location of the original expression. */ - -static tree -maybe_fold_offset_to_array_ref (location_t loc, tree base, tree offset) -{ - tree min_idx, idx, idx_type, elt_offset = integer_zero_node; - tree array_type, elt_type, elt_size; - tree domain_type; - - /* If BASE is an ARRAY_REF, we can pick up another offset (this time - measured in units of the size of elements type) from that ARRAY_REF). - We can't do anything if either is variable. - - The case we handle here is *(&A[N]+O). */ - if (TREE_CODE (base) == ARRAY_REF) - { - tree low_bound = array_ref_low_bound (base); - - elt_offset = TREE_OPERAND (base, 1); - if (TREE_CODE (low_bound) != INTEGER_CST - || TREE_CODE (elt_offset) != INTEGER_CST) - return NULL_TREE; - - elt_offset = int_const_binop (MINUS_EXPR, elt_offset, low_bound); - base = TREE_OPERAND (base, 0); - } - - /* Ignore stupid user tricks of indexing non-array variables. */ - array_type = TREE_TYPE (base); - if (TREE_CODE (array_type) != ARRAY_TYPE) - return NULL_TREE; - elt_type = TREE_TYPE (array_type); - - /* Use signed size type for intermediate computation on the index. */ - idx_type = ssizetype; - - /* If OFFSET and ELT_OFFSET are zero, we don't care about the size of the - element type (so we can use the alignment if it's not constant). - Otherwise, compute the offset as an index by using a division. If the - division isn't exact, then don't do anything. */ - elt_size = TYPE_SIZE_UNIT (elt_type); - if (!elt_size) - return NULL; - if (integer_zerop (offset)) - { - if (TREE_CODE (elt_size) != INTEGER_CST) - elt_size = size_int (TYPE_ALIGN (elt_type)); - - idx = build_int_cst (idx_type, 0); - } - else - { - unsigned HOST_WIDE_INT lquo, lrem; - HOST_WIDE_INT hquo, hrem; - double_int soffset; - - /* The final array offset should be signed, so we need - to sign-extend the (possibly pointer) offset here - and use signed division. */ - soffset = double_int_sext (tree_to_double_int (offset), - TYPE_PRECISION (TREE_TYPE (offset))); - if (TREE_CODE (elt_size) != INTEGER_CST - || div_and_round_double (TRUNC_DIV_EXPR, 0, - soffset.low, soffset.high, - TREE_INT_CST_LOW (elt_size), - TREE_INT_CST_HIGH (elt_size), - &lquo, &hquo, &lrem, &hrem) - || lrem || hrem) - return NULL_TREE; - - idx = build_int_cst_wide (idx_type, lquo, hquo); - } - - /* Assume the low bound is zero. If there is a domain type, get the - low bound, if any, convert the index into that type, and add the - low bound. */ - min_idx = build_int_cst (idx_type, 0); - domain_type = TYPE_DOMAIN (array_type); - if (domain_type) - { - idx_type = domain_type; - if (TYPE_MIN_VALUE (idx_type)) - min_idx = TYPE_MIN_VALUE (idx_type); - else - min_idx = fold_convert (idx_type, min_idx); - - if (TREE_CODE (min_idx) != INTEGER_CST) - return NULL_TREE; - - elt_offset = fold_convert (idx_type, elt_offset); - } - - if (!integer_zerop (min_idx)) - idx = int_const_binop (PLUS_EXPR, idx, min_idx); - if (!integer_zerop (elt_offset)) - idx = int_const_binop (PLUS_EXPR, idx, elt_offset); - - /* Make sure to possibly truncate late after offsetting. */ - idx = fold_convert (idx_type, idx); - - /* We don't want to construct access past array bounds. For example - char *(c[4]); - c[3][2]; - should not be simplified into (*c)[14] or tree-vrp will - give false warnings. - This is only an issue for multi-dimensional arrays. */ - if (TREE_CODE (elt_type) == ARRAY_TYPE - && domain_type) - { - if (TYPE_MAX_VALUE (domain_type) - && TREE_CODE (TYPE_MAX_VALUE (domain_type)) == INTEGER_CST - && tree_int_cst_lt (TYPE_MAX_VALUE (domain_type), idx)) - return NULL_TREE; - else if (TYPE_MIN_VALUE (domain_type) - && TREE_CODE (TYPE_MIN_VALUE (domain_type)) == INTEGER_CST - && tree_int_cst_lt (idx, TYPE_MIN_VALUE (domain_type))) - return NULL_TREE; - else if (compare_tree_int (idx, 0) < 0) - return NULL_TREE; - } - - { - tree t = build4 (ARRAY_REF, elt_type, base, idx, NULL_TREE, NULL_TREE); - SET_EXPR_LOCATION (t, loc); - return t; - } -} - - -/* Attempt to express (ORIG_TYPE)BASE+OFFSET as BASE[index]. - LOC is the location of original expression. - - Before attempting the conversion strip off existing ADDR_EXPRs. */ - -tree -maybe_fold_offset_to_reference (location_t loc, tree base, tree offset, - tree orig_type) -{ - tree ret; - - STRIP_NOPS (base); - if (TREE_CODE (base) != ADDR_EXPR) - return NULL_TREE; - - base = TREE_OPERAND (base, 0); - if (types_compatible_p (orig_type, TREE_TYPE (base)) - && integer_zerop (offset)) - return base; - - ret = maybe_fold_offset_to_array_ref (loc, base, offset); - if (ret && types_compatible_p (orig_type, TREE_TYPE (ret))) - return ret; - return NULL_TREE; -} - -/* Attempt to express (ORIG_TYPE)ADDR+OFFSET as (*ADDR)[index]. - LOC is the location of the original expression. */ - -tree -maybe_fold_offset_to_address (location_t loc, tree addr, tree offset, - tree orig_type) -{ - tree base, ret; - - STRIP_NOPS (addr); - if (TREE_CODE (addr) != ADDR_EXPR) - return NULL_TREE; - base = TREE_OPERAND (addr, 0); - ret = maybe_fold_offset_to_array_ref (loc, base, offset); - if (ret) - { - ret = build_fold_addr_expr (ret); - if (!useless_type_conversion_p (orig_type, TREE_TYPE (ret))) - return NULL_TREE; - SET_EXPR_LOCATION (ret, loc); - } - - return ret; -} - - -/* A quaint feature extant in our address arithmetic is that there - can be hidden type changes here. The type of the result need - not be the same as the type of the input pointer. - - What we're after here is an expression of the form - (T *)(&array + const) - where array is OP0, const is OP1, RES_TYPE is T and - the cast doesn't actually exist, but is implicit in the - type of the POINTER_PLUS_EXPR. We'd like to turn this into - &array[x] - which may be able to propagate further. */ - -tree -maybe_fold_stmt_addition (location_t loc, tree res_type, tree op0, tree op1) -{ - tree ptd_type; - tree t; - - /* 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 - /* As we will end up creating a variable index array access - in the outermost array dimension make sure there isn't - a more inner array that the index could overflow to. */ - && TREE_CODE (TREE_OPERAND (op0, 0)) != ARRAY_REF - && integer_zerop (TREE_OPERAND (op0, 1)) - && TREE_CODE (op1) == SSA_NAME) - { - gimple offset_def = SSA_NAME_DEF_STMT (op1); - tree elsz = TYPE_SIZE_UNIT (TREE_TYPE (op0)); - if (!host_integerp (elsz, 1) - || !is_gimple_assign (offset_def)) - return NULL_TREE; - - /* Do not build array references of something that we can't - see the true number of array dimensions for. */ - if (!DECL_P (TREE_OPERAND (op0, 0)) - && !handled_component_p (TREE_OPERAND (op0, 0))) - 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), elsz)) - return build_fold_addr_expr - (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 (elsz) - && gimple_assign_rhs_code (offset_def) != MULT_EXPR) - return build_fold_addr_expr - (build4 (ARRAY_REF, TREE_TYPE (op0), - TREE_OPERAND (op0, 0), - op1, - TREE_OPERAND (op0, 2), - TREE_OPERAND (op0, 3))); - } - else if (TREE_CODE (TREE_TYPE (op0)) == ARRAY_TYPE - /* Dto. */ - && TREE_CODE (TREE_TYPE (TREE_TYPE (op0))) != ARRAY_TYPE - && TREE_CODE (op1) == SSA_NAME) - { - gimple offset_def = SSA_NAME_DEF_STMT (op1); - tree elsz = TYPE_SIZE_UNIT (TREE_TYPE (TREE_TYPE (op0))); - if (!host_integerp (elsz, 1) - || !is_gimple_assign (offset_def)) - return NULL_TREE; - - /* Do not build array references of something that we can't - see the true number of array dimensions for. */ - if (!DECL_P (op0) - && !handled_component_p (op0)) - 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), elsz)) - return build_fold_addr_expr - (build4 (ARRAY_REF, TREE_TYPE (TREE_TYPE (op0)), - op0, gimple_assign_rhs1 (offset_def), - integer_zero_node, NULL_TREE)); - else if (integer_onep (elsz) - && gimple_assign_rhs_code (offset_def) != MULT_EXPR) - return build_fold_addr_expr - (build4 (ARRAY_REF, TREE_TYPE (TREE_TYPE (op0)), - op0, op1, - integer_zero_node, NULL_TREE)); - } - - 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) - { - tree array_obj = TREE_OPERAND (op0, 0); - tree array_idx = TREE_OPERAND (op0, 1); - tree elt_type = TREE_TYPE (op0); - tree elt_size = TYPE_SIZE_UNIT (elt_type); - tree min_idx; - - if (TREE_CODE (array_idx) != INTEGER_CST) - break; - if (TREE_CODE (elt_size) != INTEGER_CST) - break; - - /* Un-bias the index by the min index of the array type. */ - min_idx = TYPE_DOMAIN (TREE_TYPE (array_obj)); - if (min_idx) - { - min_idx = TYPE_MIN_VALUE (min_idx); - if (min_idx) - { - if (TREE_CODE (min_idx) != INTEGER_CST) - break; - - array_idx = fold_convert (TREE_TYPE (min_idx), array_idx); - if (!integer_zerop (min_idx)) - array_idx = int_const_binop (MINUS_EXPR, array_idx, - min_idx); - } - } - - /* Convert the index to a byte offset. */ - array_idx = fold_convert (sizetype, array_idx); - array_idx = int_const_binop (MULT_EXPR, array_idx, elt_size); - - /* Update the operands for the next round, or for folding. */ - op1 = int_const_binop (PLUS_EXPR, - array_idx, op1); - op0 = array_obj; - } - - ptd_type = TREE_TYPE (res_type); - /* If we want a pointer to void, reconstruct the reference from the - array element type. A pointer to that can be trivially converted - to void *. This happens as we fold (void *)(ptr p+ off). */ - if (VOID_TYPE_P (ptd_type) - && TREE_CODE (TREE_TYPE (op0)) == ARRAY_TYPE) - ptd_type = TREE_TYPE (TREE_TYPE (op0)); - - /* At which point we can try some of the same things as for indirects. */ - t = maybe_fold_offset_to_array_ref (loc, op0, op1); - if (t) - { - t = build_fold_addr_expr (t); - if (!useless_type_conversion_p (res_type, TREE_TYPE (t))) - return NULL_TREE; - SET_EXPR_LOCATION (t, loc); - } - - return t; -} /* Subroutine of fold_stmt. We perform several simplifications of the memory reference tree EXPR and make sure to re-gimplify them properly @@ -783,41 +408,14 @@ fold_gimple_assign (gimple_stmt_iterator *si) if (valid_gimple_rhs_p (result)) return result; } - else if (CONVERT_EXPR_CODE_P (subcode) - && POINTER_TYPE_P (gimple_expr_type (stmt)) - && POINTER_TYPE_P (TREE_TYPE (gimple_assign_rhs1 (stmt)))) - { - tree type = gimple_expr_type (stmt); - tree t = maybe_fold_offset_to_address (loc, - gimple_assign_rhs1 (stmt), - integer_zero_node, type); - if (t) - return t; - } } break; case GIMPLE_BINARY_RHS: - /* Try to fold pointer addition. */ - if (gimple_assign_rhs_code (stmt) == POINTER_PLUS_EXPR) - { - tree type = TREE_TYPE (gimple_assign_rhs1 (stmt)); - if (TREE_CODE (TREE_TYPE (type)) == ARRAY_TYPE) - { - type = build_pointer_type (TREE_TYPE (TREE_TYPE (type))); - if (!useless_type_conversion_p - (TREE_TYPE (gimple_assign_lhs (stmt)), type)) - type = TREE_TYPE (gimple_assign_rhs1 (stmt)); - } - result = maybe_fold_stmt_addition (gimple_location (stmt), - type, - gimple_assign_rhs1 (stmt), - gimple_assign_rhs2 (stmt)); - } /* Try to canonicalize for boolean-typed X the comparisons X == 0, X == 1, X != 0, and X != 1. */ - else if (gimple_assign_rhs_code (stmt) == EQ_EXPR - || gimple_assign_rhs_code (stmt) == NE_EXPR) + if (gimple_assign_rhs_code (stmt) == EQ_EXPR + || gimple_assign_rhs_code (stmt) == NE_EXPR) { tree lhs = gimple_assign_lhs (stmt); tree op1 = gimple_assign_rhs1 (stmt); @@ -2945,29 +2543,20 @@ gimple_fold_stmt_to_constant_1 (gimple stmt, tree (*valueize) (tree)) /* Handle unary operators that can appear in GIMPLE form. Note that we know the single operand must be a constant, so this should almost always return a simplified RHS. */ - tree lhs = gimple_assign_lhs (stmt); + tree lhs = gimple_assign_lhs (stmt); tree op0 = (*valueize) (gimple_assign_rhs1 (stmt)); /* Conversions are useless for CCP purposes if they are value-preserving. Thus the restrictions that - useless_type_conversion_p places for pointer type conversions - do not apply here. Substitution later will only substitute to - allowed places. */ + useless_type_conversion_p places for restrict qualification + of pointer types should not apply here. + Substitution later will only substitute to allowed places. */ if (CONVERT_EXPR_CODE_P (subcode) && POINTER_TYPE_P (TREE_TYPE (lhs)) - && POINTER_TYPE_P (TREE_TYPE (op0))) - { - tree tem; - /* Try to re-construct array references on-the-fly. */ - if (!useless_type_conversion_p (TREE_TYPE (lhs), - TREE_TYPE (op0)) - && ((tem = maybe_fold_offset_to_address - (loc, - op0, integer_zero_node, TREE_TYPE (lhs))) - != NULL_TREE)) - return tem; - return op0; - } + && POINTER_TYPE_P (TREE_TYPE (op0)) + && (TYPE_ADDR_SPACE (TREE_TYPE (lhs)) + == TYPE_ADDR_SPACE (TREE_TYPE (op0)))) + return op0; return fold_unary_ignore_overflow_loc (loc, subcode, diff --git a/gcc/gimple.h b/gcc/gimple.h index 27b20482876a..7f831dffcaf0 100644 --- a/gcc/gimple.h +++ b/gcc/gimple.h @@ -5069,12 +5069,8 @@ void gimplify_and_update_call_from_tree (gimple_stmt_iterator *, tree); tree gimple_fold_builtin (gimple); bool fold_stmt (gimple_stmt_iterator *); bool fold_stmt_inplace (gimple); -tree maybe_fold_offset_to_address (location_t, tree, tree, tree); -tree maybe_fold_offset_to_reference (location_t, tree, tree, tree); -tree maybe_fold_stmt_addition (location_t, tree, tree, tree); tree get_symbol_constant_value (tree); tree canonicalize_constructor_val (tree); -bool may_propagate_address_into_dereference (tree, tree); extern tree maybe_fold_and_comparisons (enum tree_code, tree, tree, enum tree_code, tree, tree); extern tree maybe_fold_or_comparisons (enum tree_code, tree, tree, diff --git a/gcc/gimplify.c b/gcc/gimplify.c index a22b5d3121f6..d7bc818dfb98 100644 --- a/gcc/gimplify.c +++ b/gcc/gimplify.c @@ -1799,7 +1799,6 @@ canonicalize_addr_expr (tree *expr_p) static enum gimplify_status gimplify_conversion (tree *expr_p) { - tree tem; location_t loc = EXPR_LOCATION (*expr_p); gcc_assert (CONVERT_EXPR_P (*expr_p)); @@ -1810,17 +1809,6 @@ gimplify_conversion (tree *expr_p) if (tree_ssa_useless_type_conversion (*expr_p)) *expr_p = TREE_OPERAND (*expr_p, 0); - /* Attempt to avoid NOP_EXPR by producing reference to a subtype. - For example this fold (subclass *)&A into &A->subclass avoiding - a need for statement. */ - if (CONVERT_EXPR_P (*expr_p) - && POINTER_TYPE_P (TREE_TYPE (*expr_p)) - && POINTER_TYPE_P (TREE_TYPE (TREE_OPERAND (*expr_p, 0))) - && (tem = maybe_fold_offset_to_address - (EXPR_LOCATION (*expr_p), TREE_OPERAND (*expr_p, 0), - integer_zero_node, TREE_TYPE (*expr_p))) != NULL_TREE) - *expr_p = tem; - /* If we still have a conversion at the toplevel, then canonicalize some constructs. */ if (CONVERT_EXPR_P (*expr_p)) @@ -7302,36 +7290,33 @@ gimplify_expr (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p, goto expr_3; case POINTER_PLUS_EXPR: - /* Convert ((type *)A)+offset into &A->field_of_type_and_offset. - The second is gimple immediate saving a need for extra statement. - */ - if (TREE_CODE (TREE_OPERAND (*expr_p, 1)) == INTEGER_CST - && (tmp = maybe_fold_offset_to_address - (EXPR_LOCATION (*expr_p), - TREE_OPERAND (*expr_p, 0), TREE_OPERAND (*expr_p, 1), - TREE_TYPE (*expr_p)))) - { - *expr_p = tmp; - ret = GS_OK; - break; - } - /* Convert (void *)&a + 4 into (void *)&a[1]. */ - if (TREE_CODE (TREE_OPERAND (*expr_p, 0)) == NOP_EXPR - && TREE_CODE (TREE_OPERAND (*expr_p, 1)) == INTEGER_CST - && POINTER_TYPE_P (TREE_TYPE (TREE_OPERAND (TREE_OPERAND (*expr_p, - 0),0))) - && (tmp = maybe_fold_offset_to_address - (EXPR_LOCATION (*expr_p), - TREE_OPERAND (TREE_OPERAND (*expr_p, 0), 0), - TREE_OPERAND (*expr_p, 1), - TREE_TYPE (TREE_OPERAND (TREE_OPERAND (*expr_p, 0), - 0))))) - { - *expr_p = fold_convert (TREE_TYPE (*expr_p), tmp); - ret = GS_OK; - break; - } - /* FALLTHRU */ + { + enum gimplify_status r0, r1; + r0 = gimplify_expr (&TREE_OPERAND (*expr_p, 0), pre_p, + post_p, is_gimple_val, fb_rvalue); + r1 = gimplify_expr (&TREE_OPERAND (*expr_p, 1), pre_p, + post_p, is_gimple_val, fb_rvalue); + recalculate_side_effects (*expr_p); + ret = MIN (r0, r1); + /* Convert &X + CST to invariant &MEM[&X, CST]. Do this + after gimplifying operands - this is similar to how + it would be folding all gimplified stmts on creation + to have them canonicalized, which is what we eventually + should do anyway. */ + if (TREE_CODE (TREE_OPERAND (*expr_p, 1)) == INTEGER_CST + && is_gimple_min_invariant (TREE_OPERAND (*expr_p, 0))) + { + *expr_p = build_fold_addr_expr_with_type_loc + (input_location, + fold_build2 (MEM_REF, TREE_TYPE (TREE_TYPE (*expr_p)), + TREE_OPERAND (*expr_p, 0), + fold_convert (ptr_type_node, + TREE_OPERAND (*expr_p, 1))), + TREE_TYPE (*expr_p)); + ret = MIN (ret, GS_OK); + } + break; + } default: switch (TREE_CODE_CLASS (TREE_CODE (*expr_p))) diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 55d74a9dddfa..2449a63ac63b 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,11 @@ +2011-08-30 Richard Guenther + + PR middle-end/48571 + * gcc.c-torture/execute/pr48571-1.c: New testcase. + * gcc.dg/tree-ssa/ssa-ccp-25.c: Remove. + * gcc.dg/tree-ssa/ssa-ccp-26.c: Likewise. + * gcc.dg/pr36902.c: XFAIL. + 2011-08-30 Ilya Tocar * gcc.target/i386/fma-check.h: New. diff --git a/gcc/testsuite/gcc.c-torture/execute/pr48571-1.c b/gcc/testsuite/gcc.c-torture/execute/pr48571-1.c new file mode 100644 index 000000000000..063058e43b3a --- /dev/null +++ b/gcc/testsuite/gcc.c-torture/execute/pr48571-1.c @@ -0,0 +1,28 @@ +unsigned int c[624]; +void __attribute__((noinline)) +bar (void) +{ + unsigned int i; + /* Obfuscated c[i] = c[i-1] * 2. */ + for (i = 1; i < 624; ++i) + *(unsigned int *)((void *)c + (__SIZE_TYPE__)i * 4) + = 2 * *(unsigned int *)((void *)c + ((__SIZE_TYPE__)i + + ((__SIZE_TYPE__)-4)/4) * 4); +} +extern void abort (void); +int +main() +{ + unsigned int i, j; + for (i = 0; i < 624; ++i) + c[i] = 1; + bar(); + j = 1; + for (i = 0; i < 624; ++i) + { + if (c[i] != j) + abort (); + j = j * 2; + } + return 0; +} diff --git a/gcc/testsuite/gcc.dg/pr36902.c b/gcc/testsuite/gcc.dg/pr36902.c index 43a2d14f981f..a065124ae716 100644 --- a/gcc/testsuite/gcc.dg/pr36902.c +++ b/gcc/testsuite/gcc.dg/pr36902.c @@ -44,7 +44,7 @@ foo2(unsigned char * to, const unsigned char * from, int n) *to = *from; break; case 5: - to[4] = from [4]; /* { dg-warning "array subscript is above array bounds" } */ + to[4] = from [4]; /* { dg-warning "array subscript is above array bounds" "" { xfail *-*-* } } */ break; } return to; diff --git a/gcc/testsuite/gcc.dg/tree-ssa/ssa-ccp-25.c b/gcc/testsuite/gcc.dg/tree-ssa/ssa-ccp-25.c deleted file mode 100644 index 7912a57f09ed..000000000000 --- a/gcc/testsuite/gcc.dg/tree-ssa/ssa-ccp-25.c +++ /dev/null @@ -1,14 +0,0 @@ -/* { 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\\\[\[iD\]\\\." "ccp1" } } */ -/* { dg-final { scan-tree-dump "= .*&a\\\]\\\[\[iD\]\\\." "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 deleted file mode 100644 index c0a548155cb4..000000000000 --- a/gcc/testsuite/gcc.dg/tree-ssa/ssa-ccp-26.c +++ /dev/null @@ -1,11 +0,0 @@ -/* { 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-inline.c b/gcc/tree-inline.c index e9daff63cc35..741e8e4d005c 100644 --- a/gcc/tree-inline.c +++ b/gcc/tree-inline.c @@ -853,43 +853,14 @@ remap_gimple_op_r (tree *tp, int *walk_subtrees, void *data) tree ptr = TREE_OPERAND (*tp, 0); tree type = remap_type (TREE_TYPE (*tp), id); tree old = *tp; - tree tem; /* We need to re-canonicalize MEM_REFs from inline substitutions that can happen when a pointer argument is an ADDR_EXPR. Recurse here manually to allow that. */ walk_tree (&ptr, remap_gimple_op_r, data, NULL); - if ((tem = maybe_fold_offset_to_reference (EXPR_LOCATION (*tp), - ptr, - TREE_OPERAND (*tp, 1), - type)) - && TREE_THIS_VOLATILE (tem) == TREE_THIS_VOLATILE (old)) - { - tree *tem_basep = &tem; - while (handled_component_p (*tem_basep)) - tem_basep = &TREE_OPERAND (*tem_basep, 0); - if (TREE_CODE (*tem_basep) == MEM_REF) - *tem_basep - = build2 (MEM_REF, TREE_TYPE (*tem_basep), - TREE_OPERAND (*tem_basep, 0), - fold_convert (TREE_TYPE (TREE_OPERAND (*tp, 1)), - TREE_OPERAND (*tem_basep, 1))); - else - *tem_basep - = build2 (MEM_REF, TREE_TYPE (*tem_basep), - build_fold_addr_expr (*tem_basep), - build_int_cst - (TREE_TYPE (TREE_OPERAND (*tp, 1)), 0)); - *tp = tem; - TREE_THIS_VOLATILE (*tem_basep) = TREE_THIS_VOLATILE (old); - TREE_THIS_NOTRAP (*tem_basep) = TREE_THIS_NOTRAP (old); - } - else - { - *tp = fold_build2 (MEM_REF, type, - ptr, TREE_OPERAND (*tp, 1)); - TREE_THIS_NOTRAP (*tp) = TREE_THIS_NOTRAP (old); - } + *tp = fold_build2 (MEM_REF, type, + ptr, TREE_OPERAND (*tp, 1)); + TREE_THIS_NOTRAP (*tp) = TREE_THIS_NOTRAP (old); TREE_THIS_VOLATILE (*tp) = TREE_THIS_VOLATILE (old); TREE_NO_WARNING (*tp) = TREE_NO_WARNING (old); *walk_subtrees = 0; diff --git a/gcc/tree-ssa-forwprop.c b/gcc/tree-ssa-forwprop.c index 00121796613c..7dd5e08ac6d1 100644 --- a/gcc/tree-ssa-forwprop.c +++ b/gcc/tree-ssa-forwprop.c @@ -1002,31 +1002,21 @@ forward_propagate_addr_expr_1 (tree name, tree def_rhs, return false; rhs2 = gimple_assign_rhs2 (use_stmt); - /* Try to optimize &x[C1] p+ C2 where C2 is a multiple of the size - of the elements in X into &x[C1 + C2/element size]. */ + /* Optimize &x[C1] p+ C2 to &x p+ C3 with C3 = C1 * element_size + C2. */ if (TREE_CODE (rhs2) == INTEGER_CST) { - tree new_rhs = maybe_fold_stmt_addition (gimple_location (use_stmt), - TREE_TYPE (def_rhs), - def_rhs, rhs2); - if (new_rhs) - { - tree type = TREE_TYPE (gimple_assign_lhs (use_stmt)); - new_rhs = unshare_expr (new_rhs); - if (!useless_type_conversion_p (type, TREE_TYPE (new_rhs))) - { - if (!is_gimple_min_invariant (new_rhs)) - new_rhs = force_gimple_operand_gsi (use_stmt_gsi, new_rhs, - true, NULL_TREE, - true, GSI_SAME_STMT); - new_rhs = fold_convert (type, new_rhs); - } - gimple_assign_set_rhs_from_tree (use_stmt_gsi, new_rhs); - use_stmt = gsi_stmt (*use_stmt_gsi); - update_stmt (use_stmt); - tidy_after_forward_propagate_addr (use_stmt); - return true; - } + tree new_rhs = build1_loc (gimple_location (use_stmt), + ADDR_EXPR, TREE_TYPE (def_rhs), + fold_build2 (MEM_REF, + TREE_TYPE (TREE_TYPE (def_rhs)), + unshare_expr (def_rhs), + fold_convert (ptr_type_node, + rhs2))); + gimple_assign_set_rhs_from_tree (use_stmt_gsi, new_rhs); + use_stmt = gsi_stmt (*use_stmt_gsi); + update_stmt (use_stmt); + tidy_after_forward_propagate_addr (use_stmt); + return true; } /* Try to optimize &x[0] p+ OFFSET where OFFSET is defined by