Loop bound computation uses undefined behavior when accessing arrays outside of their domain. Unfortunately while it tries to honor issues with trailing arrays in allocated storage its implementation is broken (for one, it does consider a TYPE_DECL after the array as a sign that the array is not at struct end). The following patch moves array_at_struct_end_p to expr.c near its natural user (it's also used by graphite) and re-implements it. It also adjusts array_ref_up_bound to not return any bound in the case of an access to a trailing array - at present what it returns is a conservative answer in the wrong sense in two of its four callers (it returns a lower bound for the upper bound). Given the fact that array_ref_low_bound returns an exact answer not returning any lower / upper bound for the upper bound but only what we would consider exact sounds like the most reasonable solution.
Bootstrapped on x86_64-unknown-linux-gnu, testing in progress. This does not yet fully recover bootstrap if you make use of undefined behavior loop bound detection in VRP, but two miscompiles of GCC vanish. Richard. 2012-04-17 Richard Guenther <rguent...@suse.de> * tree-flow.h (array_at_struct_end_p): Move declaration ... * tree.h (array_at_struct_end_p): ... here. * tree-ssa-loop-niter.c (idx_infer_loop_bounds): Infer nothing from array references at struct ends. (array_at_struct_end_p): Move ... * expr.c (array_at_struct_end_p): ... here. Rewrite. (array_ref_up_bound): Return NULL_TREE for array references at struct ends. Index: gcc/tree.h =================================================================== *** gcc/tree.h (revision 186496) --- gcc/tree.h (working copy) *************** extern bool contains_packed_reference (c *** 5068,5073 **** --- 5068,5075 ---- extern tree array_ref_element_size (tree); + bool array_at_struct_end_p (tree); + /* Return a tree representing the lower bound of the array mentioned in EXP, an ARRAY_REF or an ARRAY_RANGE_REF. */ Index: gcc/expr.c =================================================================== *** gcc/expr.c (revision 186496) --- gcc/expr.c (working copy) *************** array_ref_low_bound (tree exp) *** 6778,6783 **** --- 6778,6820 ---- return build_int_cst (TREE_TYPE (TREE_OPERAND (exp, 1)), 0); } + /* Returns true if REF is an array reference to an array at the end of + a structure. If this is the case, the array may be allocated larger + than its upper bound implies. */ + + bool + array_at_struct_end_p (tree ref) + { + if (TREE_CODE (ref) != ARRAY_REF + && TREE_CODE (ref) != ARRAY_RANGE_REF) + return false; + + while (handled_component_p (ref)) + { + /* If the reference chain contains a component reference to a + non-union type and there follows another field the reference + is not at the end of a structure. */ + if (TREE_CODE (ref) == COMPONENT_REF + && TREE_CODE (TREE_TYPE (TREE_OPERAND (ref, 0))) == RECORD_TYPE) + { + tree nextf = DECL_CHAIN (TREE_OPERAND (ref, 1)); + while (nextf && TREE_CODE (nextf) != FIELD_DECL) + nextf = DECL_CHAIN (nextf); + if (nextf) + return false; + } + + ref = TREE_OPERAND (ref, 0); + } + + /* If the reference is based on a declared entity, the size of the array + is constrained by its given domain. */ + if (DECL_P (ref)) + return false; + + return true; + } + /* Return a tree representing the upper bound of the array mentioned in EXP, an ARRAY_REF or an ARRAY_RANGE_REF. */ *************** array_ref_up_bound (tree exp) *** 6789,6795 **** /* If there is a domain type and it has an upper bound, use it, substituting for a PLACEHOLDER_EXPR as needed. */ if (domain_type && TYPE_MAX_VALUE (domain_type)) ! return SUBSTITUTE_PLACEHOLDER_IN_EXPR (TYPE_MAX_VALUE (domain_type), exp); /* Otherwise fail. */ return NULL_TREE; --- 6826,6843 ---- /* If there is a domain type and it has an upper bound, use it, substituting for a PLACEHOLDER_EXPR as needed. */ if (domain_type && TYPE_MAX_VALUE (domain_type)) ! { ! tree max = TYPE_MAX_VALUE (domain_type); ! ! /* For references to arrays at the end of dynamically allocated ! structures TYPE_MAX_VALUE is not an upper bound for the array ! size. */ ! if (TREE_CODE (max) == INTEGER_CST ! && array_at_struct_end_p (exp)) ! return NULL_TREE; ! ! return SUBSTITUTE_PLACEHOLDER_IN_EXPR (max, exp); ! } /* Otherwise fail. */ return NULL_TREE; Index: gcc/tree-flow.h =================================================================== *** gcc/tree-flow.h (revision 186496) --- gcc/tree-flow.h (working copy) *************** tree find_loop_niter (struct loop *, edg *** 686,692 **** tree loop_niter_by_eval (struct loop *, edge); tree find_loop_niter_by_eval (struct loop *, edge *); void estimate_numbers_of_iterations (bool); - bool array_at_struct_end_p (tree); bool scev_probably_wraps_p (tree, tree, gimple, struct loop *, bool); bool convert_affine_scev (struct loop *, tree, tree *, tree *, gimple, bool); --- 686,691 ---- Index: gcc/tree-ssa-loop-niter.c =================================================================== *** gcc/tree-ssa-loop-niter.c (revision 186496) --- gcc/tree-ssa-loop-niter.c (working copy) *************** record_nonwrapping_iv (struct loop *loop *** 2640,2686 **** record_estimate (loop, niter_bound, max, stmt, false, realistic, upper); } - /* Returns true if REF is a reference to an array at the end of a dynamically - allocated structure. If this is the case, the array may be allocated larger - than its upper bound implies. */ - - bool - array_at_struct_end_p (tree ref) - { - tree base = get_base_address (ref); - tree parent, field; - - /* Unless the reference is through a pointer, the size of the array matches - its declaration. */ - if (!base || (!INDIRECT_REF_P (base) && TREE_CODE (base) != MEM_REF)) - return false; - - for (;handled_component_p (ref); ref = parent) - { - parent = TREE_OPERAND (ref, 0); - - if (TREE_CODE (ref) == COMPONENT_REF) - { - /* All fields of a union are at its end. */ - if (TREE_CODE (TREE_TYPE (parent)) == UNION_TYPE) - continue; - - /* Unless the field is at the end of the struct, we are done. */ - field = TREE_OPERAND (ref, 1); - if (DECL_CHAIN (field)) - return false; - } - - /* The other options are ARRAY_REF, ARRAY_RANGE_REF, VIEW_CONVERT_EXPR. - In all these cases, we might be accessing the last element, and - although in practice this will probably never happen, it is legal for - the indices of this last element to exceed the bounds of the array. - Therefore, continue checking. */ - } - - return true; - } - /* Determine information about number of iterations a LOOP from the index IDX of a data reference accessed in STMT. RELIABLE is true if STMT is guaranteed to be executed in every iteration of LOOP. Callback for --- 2648,2653 ---- *************** idx_infer_loop_bounds (tree base, tree * *** 2699,2719 **** struct ilb_data *data = (struct ilb_data *) dta; tree ev, init, step; tree low, high, type, next; ! bool sign, upper = data->reliable, at_end = false; struct loop *loop = data->loop; if (TREE_CODE (base) != ARRAY_REF) return true; - /* For arrays at the end of the structure, we are not guaranteed that they - do not really extend over their declared size. However, for arrays of - size greater than one, this is unlikely to be intended. */ - if (array_at_struct_end_p (base)) - { - at_end = true; - upper = false; - } - ev = instantiate_parameters (loop, analyze_scalar_evolution (loop, *idx)); init = initial_condition (ev); step = evolution_part_in_loop_num (ev, loop->num); --- 2666,2677 ---- struct ilb_data *data = (struct ilb_data *) dta; tree ev, init, step; tree low, high, type, next; ! bool sign, upper = data->reliable; struct loop *loop = data->loop; if (TREE_CODE (base) != ARRAY_REF) return true; ev = instantiate_parameters (loop, analyze_scalar_evolution (loop, *idx)); init = initial_condition (ev); step = evolution_part_in_loop_num (ev, loop->num); *************** idx_infer_loop_bounds (tree base, tree * *** 2738,2749 **** sign = tree_int_cst_sign_bit (step); type = TREE_TYPE (step); - /* The array of length 1 at the end of a structure most likely extends - beyond its bounds. */ - if (at_end - && operand_equal_p (low, high, 0)) - return true; - /* In case the relevant bound of the array does not fit in type, or it does, but bound + step (in type) still belongs into the range of the array, the index may wrap and still stay within the range of the array --- 2696,2701 ----