This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
Re: [PATCH] Fix PR52406
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 <rguenther@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;
+ }
+