On Tue, 28 Feb 2012, Richard Guenther wrote: > > I am testing the following patch to fix PR52406. We cannot simply > feed DR_BASE_OBJECT to the alias-oracle as it does not reflect > a real memory access. Only if we query two 'structurally compatible' > references we may do this. So the following patch reverts to > using DR_REF instead and improves data-ref index disambiguation > by handling COMPONENT_REFs as extra access dimension (similar to how > we handle REALPART/IMAGPART_EXPR).
So, this didn't exactly work out. The following instead tries to make sure we have the "real" base object in DR_BASE_OBJECT so we _can_ use the tree alias-oracle to disambiguate different ones (so DR_BASE_OBJECT has to have a meaningful size, and a.b[0].c cannot simply be the base-object for a.b[i].c, instead a or a.b would be valid base-objects for it). Now, things get interesting if you consider *(p + i) style accesses where we cannot really create an artificial access that covers the whole base object - instead I mark the base MEM_REF of such accesses with TREE_NO_WARNING (ugh) and special-case for them in dr_may_alias_p. Fortunately there are almost no users of DR_BASE_OBJECT, and the ones in the vectorizer are even wrong. The patch has become quite invasive so I am considering to delay it until after 4.7.0 and eventually backport it. Bootstrapped and tested on x86_64-unknown-linux-gnu. Richard. 2012-02-29 Richard Guenther <rguent...@suse.de> PR tree-optimization/52406 * tree-data-ref.c (dr_analyze_indices): For COMPONENT_REFs add indices to allow their disambiguation. Make DR_BASE_OBJECT be an artificial access that covers the whole indexed object, or mark it with TREE_NO_WARNING if we cannot do so. Canonicalize plain decl base-objects to their MEM_REF variant. (dr_may_alias_p): When the base-object of either data reference has unknown size use only points-to information. (compute_affine_dependence): Make dumps easier to read and more verbose. * tree-vect-data-ref.c (vector_alignment_reachable_p): Use DR_REF when looking for packed references. (vect_supportable_dr_alignment): Likewise. * gcc.dg/torture/pr52406.c: New testcase. Index: gcc/tree-data-ref.c =================================================================== *** gcc/tree-data-ref.c (revision 184656) --- gcc/tree-data-ref.c (working copy) *************** static void *** 856,862 **** dr_analyze_indices (struct data_reference *dr, loop_p nest, loop_p loop) { VEC (tree, heap) *access_fns = NULL; ! tree ref, *aref, op; tree base, off, access_fn; basic_block before_loop; --- 856,862 ---- dr_analyze_indices (struct data_reference *dr, loop_p nest, loop_p loop) { VEC (tree, heap) *access_fns = NULL; ! tree ref, op; tree base, off, access_fn; basic_block before_loop; *************** dr_analyze_indices (struct data_referenc *** 869,875 **** return; } ! ref = unshare_expr (DR_REF (dr)); before_loop = block_before_loop (nest); /* REALPART_EXPR and IMAGPART_EXPR can be handled like accesses --- 869,875 ---- return; } ! ref = DR_REF (dr); before_loop = block_before_loop (nest); /* REALPART_EXPR and IMAGPART_EXPR can be handled like accesses *************** dr_analyze_indices (struct data_referenc *** 887,947 **** } /* Analyze access functions of dimensions we know to be independent. */ ! aref = &ref; ! while (handled_component_p (*aref)) { ! if (TREE_CODE (*aref) == ARRAY_REF) { ! op = TREE_OPERAND (*aref, 1); access_fn = analyze_scalar_evolution (loop, op); access_fn = instantiate_scev (before_loop, loop, access_fn); VEC_safe_push (tree, heap, access_fns, access_fn); - /* For ARRAY_REFs the base is the reference with the index replaced - by zero if we can not strip it as the outermost component. */ - if (*aref == ref) - { - *aref = TREE_OPERAND (*aref, 0); - continue; - } - else - TREE_OPERAND (*aref, 1) = build_int_cst (TREE_TYPE (op), 0); } ! aref = &TREE_OPERAND (*aref, 0); } /* If the address operand of a MEM_REF base has an evolution in the analyzed nest, add it as an additional independent access-function. */ ! if (TREE_CODE (*aref) == MEM_REF) { ! op = TREE_OPERAND (*aref, 0); access_fn = analyze_scalar_evolution (loop, op); access_fn = instantiate_scev (before_loop, loop, access_fn); if (TREE_CODE (access_fn) == POLYNOMIAL_CHREC) { tree orig_type; base = initial_condition (access_fn); orig_type = TREE_TYPE (base); STRIP_USELESS_TYPE_CONVERSION (base); split_constant_offset (base, &base, &off); /* Fold the MEM_REF offset into the evolutions initial value to make more bases comparable. */ ! if (!integer_zerop (TREE_OPERAND (*aref, 1))) { off = size_binop (PLUS_EXPR, off, ! fold_convert (ssizetype, ! TREE_OPERAND (*aref, 1))); ! TREE_OPERAND (*aref, 1) ! = build_int_cst (TREE_TYPE (TREE_OPERAND (*aref, 1)), 0); } access_fn = chrec_replace_initial_condition (access_fn, fold_convert (orig_type, off)); ! *aref = fold_build2_loc (EXPR_LOCATION (*aref), ! MEM_REF, TREE_TYPE (*aref), ! base, TREE_OPERAND (*aref, 1)); VEC_safe_push (tree, heap, access_fns, access_fn); } } DR_BASE_OBJECT (dr) = ref; DR_ACCESS_FNS (dr) = access_fns; --- 887,970 ---- } /* Analyze access functions of dimensions we know to be independent. */ ! while (handled_component_p (ref)) { ! if (TREE_CODE (ref) == ARRAY_REF) { ! op = TREE_OPERAND (ref, 1); access_fn = analyze_scalar_evolution (loop, op); access_fn = instantiate_scev (before_loop, loop, access_fn); VEC_safe_push (tree, heap, access_fns, access_fn); } + else if (TREE_CODE (ref) == COMPONENT_REF + && TREE_CODE (TREE_TYPE (TREE_OPERAND (ref, 0))) == RECORD_TYPE) + { + /* For COMPONENT_REFs of records (but not unions!) use the + FIELD_DECL offset as constant access function so we can + disambiguate a[i].f1 and a[i].f2. */ + tree off = component_ref_field_offset (ref); + off = size_binop (PLUS_EXPR, + size_binop (MULT_EXPR, + fold_convert (bitsizetype, off), + bitsize_int (BITS_PER_UNIT)), + DECL_FIELD_BIT_OFFSET (TREE_OPERAND (ref, 1))); + VEC_safe_push (tree, heap, access_fns, off); + } + else + /* If we have an unhandled component we could not translate + to an access function stop analyzing. We have determined + our base object in this case. */ + break; ! ref = TREE_OPERAND (ref, 0); } /* If the address operand of a MEM_REF base has an evolution in the analyzed nest, add it as an additional independent access-function. */ ! if (TREE_CODE (ref) == MEM_REF) { ! op = TREE_OPERAND (ref, 0); access_fn = analyze_scalar_evolution (loop, op); access_fn = instantiate_scev (before_loop, loop, access_fn); if (TREE_CODE (access_fn) == POLYNOMIAL_CHREC) { tree orig_type; + tree memoff = TREE_OPERAND (ref, 1); base = initial_condition (access_fn); orig_type = TREE_TYPE (base); STRIP_USELESS_TYPE_CONVERSION (base); split_constant_offset (base, &base, &off); /* Fold the MEM_REF offset into the evolutions initial value to make more bases comparable. */ ! if (!integer_zerop (memoff)) { off = size_binop (PLUS_EXPR, off, ! fold_convert (ssizetype, memoff)); ! memoff = build_int_cst (TREE_TYPE (memoff), 0); } access_fn = chrec_replace_initial_condition (access_fn, fold_convert (orig_type, off)); ! /* ??? This is still not a suitable base object for ! dr_may_alias_p - the base object needs to be an ! access that covers the object as whole. With ! an evolution in the pointer this cannot be ! guaranteed. ! As a band-aid, mark the access so we can special-case ! it in dr_may_alias_p. */ ! ref = fold_build2_loc (EXPR_LOCATION (ref), ! MEM_REF, TREE_TYPE (ref), ! base, memoff); ! TREE_NO_WARNING (ref) = true; VEC_safe_push (tree, heap, access_fns, access_fn); } } + else if (DECL_P (ref)) + { + /* Canonicalize DR_BASE_OBJECT to MEM_REF form. */ + ref = build2 (MEM_REF, TREE_TYPE (ref), + build_fold_addr_expr (ref), + build_int_cst (reference_alias_ptr_type (ref), 0)); + } DR_BASE_OBJECT (dr) = ref; DR_ACCESS_FNS (dr) = access_fns; *************** dr_may_alias_p (const struct data_refere *** 1345,1350 **** --- 1368,1394 ---- return false; } + /* If we had an evolution in a MEM_REF BASE_OBJECT we do not know + the size of the base-object. So we cannot do any offset/overlap + based analysis but have to rely on points-to information only. */ + if (TREE_CODE (addr_a) == MEM_REF + && TREE_NO_WARNING (addr_a)) + { + if (TREE_CODE (addr_b) == MEM_REF + && TREE_NO_WARNING (addr_b)) + return ptr_derefs_may_alias_p (TREE_OPERAND (addr_a, 0), + TREE_OPERAND (addr_b, 0)); + else + return ptr_derefs_may_alias_p (TREE_OPERAND (addr_a, 0), + build_fold_addr_expr (addr_b)); + } + else if (TREE_CODE (addr_b) == MEM_REF + && TREE_NO_WARNING (addr_b)) + return ptr_derefs_may_alias_p (build_fold_addr_expr (addr_a), + TREE_OPERAND (addr_b, 0)); + + /* Otherwise DR_BASE_OBJECT is an access that covers the whole object + that is being subsetted in the loop nest. */ if (DR_IS_WRITE (a) && DR_IS_WRITE (b)) return refs_output_dependent_p (addr_a, addr_b); else if (DR_IS_READ (a) && DR_IS_WRITE (b)) *************** compute_affine_dependence (struct data_d *** 4049,4059 **** if (dump_file && (dump_flags & TDF_DETAILS)) { fprintf (dump_file, "(compute_affine_dependence\n"); ! fprintf (dump_file, " (stmt_a = \n"); ! print_gimple_stmt (dump_file, DR_STMT (dra), 0, 0); ! fprintf (dump_file, ")\n (stmt_b = \n"); ! print_gimple_stmt (dump_file, DR_STMT (drb), 0, 0); ! fprintf (dump_file, ")\n"); } /* Analyze only when the dependence relation is not yet known. */ --- 4093,4102 ---- if (dump_file && (dump_flags & TDF_DETAILS)) { fprintf (dump_file, "(compute_affine_dependence\n"); ! fprintf (dump_file, " stmt_a: "); ! print_gimple_stmt (dump_file, DR_STMT (dra), 0, TDF_SLIM); ! fprintf (dump_file, " stmt_b: "); ! print_gimple_stmt (dump_file, DR_STMT (drb), 0, TDF_SLIM); } /* Analyze only when the dependence relation is not yet known. */ *************** compute_affine_dependence (struct data_d *** 4129,4135 **** } if (dump_file && (dump_flags & TDF_DETAILS)) ! fprintf (dump_file, ")\n"); } /* Compute in DEPENDENCE_RELATIONS the data dependence graph for all --- 4172,4185 ---- } if (dump_file && (dump_flags & TDF_DETAILS)) ! { ! if (DDR_ARE_DEPENDENT (ddr) == chrec_known) ! fprintf (dump_file, ") -> no dependence\n"); ! else if (DDR_ARE_DEPENDENT (ddr) == chrec_dont_know) ! fprintf (dump_file, ") -> dependence analysis failed\n"); ! else ! fprintf (dump_file, ")\n"); ! } } /* Compute in DEPENDENCE_RELATIONS the data dependence graph for all Index: gcc/tree-vect-data-refs.c =================================================================== *** gcc/tree-vect-data-refs.c (revision 184656) --- gcc/tree-vect-data-refs.c (working copy) *************** vector_alignment_reachable_p (struct dat *** 1141,1151 **** if (!known_alignment_for_access_p (dr)) { tree type = (TREE_TYPE (DR_REF (dr))); ! tree ba = DR_BASE_OBJECT (dr); ! bool is_packed = false; ! ! if (ba) ! is_packed = contains_packed_reference (ba); if (compare_tree_int (TYPE_SIZE (type), TYPE_ALIGN (type)) > 0) is_packed = true; --- 1141,1147 ---- if (!known_alignment_for_access_p (dr)) { tree type = (TREE_TYPE (DR_REF (dr))); ! bool is_packed = contains_packed_reference (DR_REF (dr)); if (compare_tree_int (TYPE_SIZE (type), TYPE_ALIGN (type)) > 0) is_packed = true; *************** vect_supportable_dr_alignment (struct da *** 4672,4683 **** return dr_explicit_realign_optimized; } if (!known_alignment_for_access_p (dr)) ! { ! tree ba = DR_BASE_OBJECT (dr); ! ! if (ba) ! is_packed = contains_packed_reference (ba); ! } if (targetm.vectorize. support_vector_misalignment (mode, type, --- 4668,4674 ---- return dr_explicit_realign_optimized; } if (!known_alignment_for_access_p (dr)) ! is_packed = contains_packed_reference (DR_REF (dr)); if (targetm.vectorize. support_vector_misalignment (mode, type, *************** vect_supportable_dr_alignment (struct da *** 4691,4702 **** tree type = (TREE_TYPE (DR_REF (dr))); if (!known_alignment_for_access_p (dr)) ! { ! tree ba = DR_BASE_OBJECT (dr); ! ! if (ba) ! is_packed = contains_packed_reference (ba); ! } if (targetm.vectorize. support_vector_misalignment (mode, type, --- 4682,4688 ---- tree type = (TREE_TYPE (DR_REF (dr))); if (!known_alignment_for_access_p (dr)) ! is_packed = contains_packed_reference (DR_REF (dr)); if (targetm.vectorize. support_vector_misalignment (mode, type, Index: gcc/testsuite/gcc.dg/torture/pr52406.c =================================================================== *** gcc/testsuite/gcc.dg/torture/pr52406.c (revision 0) --- gcc/testsuite/gcc.dg/torture/pr52406.c (revision 0) *************** *** 0 **** --- 1,29 ---- + /* { dg-do run } */ + + extern void abort (void); + struct { int f1; } a[2]; + + int *b, *const k = &a[1].f1; + static int **c = &b; + + int e, f, d; + + int + main () + { + int **l = &b; + *l = k; + for (; d <= 0; d++) + { + int *j = &e; + **c = 1; + *l = k; + *k ^= 0; + f = **l; + *j = f; + } + if (e != 1) + abort (); + return 0; + } +