[PATCH] Refactor type handling in get_alias_set, fix PR58513
Richard Biener
rguenther@suse.de
Tue Sep 24 11:13:00 GMT 2013
As noted in PR58513 the alias type comparison in operand_equal_p for
MEM_REF and TARGET_MEM_REF is overly restrictive. The following
adds a new alias_ptr_types_compatible_p helper for a less conservative
comparison and refactors get_alias_set and reference_alias_ptr_type
to share code and behave in a more similar manner.
Bootstrapped and tested on x86_64-unknown-linux-gnu, applied to trunk.
Richard.
2013-09-24 Richard Biener <rguenther@suse.de>
PR middle-end/58513
* tree.c (reference_alias_ptr_type): Move ...
* alias.c (reference_alias_ptr_type): ... here and implement
in terms of the new reference_alias_ptr_type_1.
(ref_all_alias_ptr_type_p): New helper.
(get_deref_alias_set_1): Drop flag_strict_aliasing here,
use ref_all_alias_ptr_type_p.
(get_deref_alias_set): Add flag_strict_aliasing check here.
(reference_alias_ptr_type_1): New function, split out from ...
(get_alias_set): ... here.
(alias_ptr_types_compatible_p): New function.
* alias.h (reference_alias_ptr_type): Declare.
(alias_ptr_types_compatible_p): Likewise.
* tree.h (reference_alias_ptr_type): Remove.
* fold-const.c (operand_equal_p): Use alias_ptr_types_compatible_p
to compare MEM_REF alias types.
* g++.dg/vect/pr58513.cc: New testcase.
Index: gcc/tree.c
===================================================================
*** gcc/tree.c.orig 2013-09-24 10:48:25.000000000 +0200
--- gcc/tree.c 2013-09-24 10:48:27.646770499 +0200
*************** mem_ref_offset (const_tree t)
*** 4263,4286 ****
return tree_to_double_int (toff).sext (TYPE_PRECISION (TREE_TYPE (toff)));
}
- /* Return the pointer-type relevant for TBAA purposes from the
- gimple memory reference tree T. This is the type to be used for
- the offset operand of MEM_REF or TARGET_MEM_REF replacements of T. */
-
- tree
- reference_alias_ptr_type (const_tree t)
- {
- const_tree base = t;
- while (handled_component_p (base))
- base = TREE_OPERAND (base, 0);
- if (TREE_CODE (base) == MEM_REF)
- return TREE_TYPE (TREE_OPERAND (base, 1));
- else if (TREE_CODE (base) == TARGET_MEM_REF)
- return TREE_TYPE (TMR_OFFSET (base));
- else
- return build_pointer_type (TYPE_MAIN_VARIANT (TREE_TYPE (base)));
- }
-
/* Return an invariant ADDR_EXPR of type TYPE taking the address of BASE
offsetted by OFFSET units. */
--- 4263,4268 ----
Index: gcc/tree.h
===================================================================
*** gcc/tree.h.orig 2013-09-24 10:48:25.000000000 +0200
--- gcc/tree.h 2013-09-24 10:48:27.662770694 +0200
*************** extern tree build_simple_mem_ref_loc (lo
*** 4345,4351 ****
#define build_simple_mem_ref(T)\
build_simple_mem_ref_loc (UNKNOWN_LOCATION, T)
extern double_int mem_ref_offset (const_tree);
- extern tree reference_alias_ptr_type (const_tree);
extern tree build_invariant_address (tree, tree, HOST_WIDE_INT);
extern tree constant_boolean_node (bool, tree);
extern tree div_if_zero_remainder (enum tree_code, const_tree, const_tree);
--- 4345,4350 ----
Index: gcc/alias.c
===================================================================
*** gcc/alias.c.orig 2013-09-24 10:48:25.000000000 +0200
--- gcc/alias.c 2013-09-24 10:55:15.949616280 +0200
*************** component_uses_parent_alias_set (const_t
*** 547,552 ****
--- 547,564 ----
}
}
+
+ /* Return whether the pointer-type T effective for aliasing may
+ access everything and thus the reference has to be assigned
+ alias-set zero. */
+
+ static bool
+ ref_all_alias_ptr_type_p (const_tree t)
+ {
+ return (TREE_CODE (TREE_TYPE (t)) == VOID_TYPE
+ || TYPE_REF_CAN_ALIAS_ALL (t));
+ }
+
/* Return the alias set for the memory pointed to by T, which may be
either a type or an expression. Return -1 if there is nothing
special about dereferencing T. */
*************** component_uses_parent_alias_set (const_t
*** 554,564 ****
static alias_set_type
get_deref_alias_set_1 (tree t)
{
- /* If we're not doing any alias analysis, just assume everything
- aliases everything else. */
- if (!flag_strict_aliasing)
- return 0;
-
/* All we care about is the type. */
if (! TYPE_P (t))
t = TREE_TYPE (t);
--- 566,571 ----
*************** get_deref_alias_set_1 (tree t)
*** 566,573 ****
/* If we have an INDIRECT_REF via a void pointer, we don't
know anything about what that might alias. Likewise if the
pointer is marked that way. */
! if (TREE_CODE (TREE_TYPE (t)) == VOID_TYPE
! || TYPE_REF_CAN_ALIAS_ALL (t))
return 0;
return -1;
--- 573,579 ----
/* If we have an INDIRECT_REF via a void pointer, we don't
know anything about what that might alias. Likewise if the
pointer is marked that way. */
! if (ref_all_alias_ptr_type_p (t))
return 0;
return -1;
*************** get_deref_alias_set_1 (tree t)
*** 579,584 ****
--- 585,595 ----
alias_set_type
get_deref_alias_set (tree t)
{
+ /* If we're not doing any alias analysis, just assume everything
+ aliases everything else. */
+ if (!flag_strict_aliasing)
+ return 0;
+
alias_set_type set = get_deref_alias_set_1 (t);
/* Fall back to the alias-set of the pointed-to type. */
*************** get_deref_alias_set (tree t)
*** 592,597 ****
--- 603,703 ----
return set;
}
+ /* Return the pointer-type relevant for TBAA purposes from the
+ memory reference tree *T or NULL_TREE in which case *T is
+ adjusted to point to the outermost component reference that
+ can be used for assigning an alias set. */
+
+ static tree
+ reference_alias_ptr_type_1 (tree *t)
+ {
+ tree inner;
+
+ /* Get the base object of the reference. */
+ inner = *t;
+ while (handled_component_p (inner))
+ {
+ /* If there is a VIEW_CONVERT_EXPR in the chain we cannot use
+ the type of any component references that wrap it to
+ determine the alias-set. */
+ if (TREE_CODE (inner) == VIEW_CONVERT_EXPR)
+ *t = TREE_OPERAND (inner, 0);
+ inner = TREE_OPERAND (inner, 0);
+ }
+
+ /* Handle pointer dereferences here, they can override the
+ alias-set. */
+ if (INDIRECT_REF_P (inner)
+ && ref_all_alias_ptr_type_p (TREE_TYPE (TREE_OPERAND (inner, 0))))
+ return TREE_TYPE (TREE_OPERAND (inner, 0));
+ else if (TREE_CODE (inner) == TARGET_MEM_REF)
+ return TREE_TYPE (TMR_OFFSET (inner));
+ else if (TREE_CODE (inner) == MEM_REF
+ && ref_all_alias_ptr_type_p (TREE_TYPE (TREE_OPERAND (inner, 1))))
+ return TREE_TYPE (TREE_OPERAND (inner, 1));
+
+ /* If the innermost reference is a MEM_REF that has a
+ conversion embedded treat it like a VIEW_CONVERT_EXPR above,
+ using the memory access type for determining the alias-set. */
+ if (TREE_CODE (inner) == MEM_REF
+ && (TYPE_MAIN_VARIANT (TREE_TYPE (inner))
+ != TYPE_MAIN_VARIANT
+ (TREE_TYPE (TREE_TYPE (TREE_OPERAND (inner, 1))))))
+ return TREE_TYPE (TREE_OPERAND (inner, 1));
+
+ /* Otherwise, pick up the outermost object that we could have a pointer
+ to, processing conversions as above. */
+ /* ??? Ick, this is worse than quadratic! */
+ while (component_uses_parent_alias_set (*t))
+ {
+ *t = TREE_OPERAND (*t, 0);
+ STRIP_NOPS (*t);
+ }
+
+ return NULL_TREE;
+ }
+
+ /* Return the pointer-type relevant for TBAA purposes from the
+ gimple memory reference tree T. This is the type to be used for
+ the offset operand of MEM_REF or TARGET_MEM_REF replacements of T
+ and guarantees that get_alias_set will return the same alias
+ set for T and the replacement. */
+
+ tree
+ reference_alias_ptr_type (tree t)
+ {
+ tree ptype = reference_alias_ptr_type_1 (&t);
+ /* If there is a given pointer type for aliasing purposes, return it. */
+ if (ptype != NULL_TREE)
+ return ptype;
+
+ /* Otherwise build one from the outermost component reference we
+ may use. */
+ if (TREE_CODE (t) == MEM_REF
+ || TREE_CODE (t) == TARGET_MEM_REF)
+ return TREE_TYPE (TREE_OPERAND (t, 1));
+ else
+ return build_pointer_type (TYPE_MAIN_VARIANT (TREE_TYPE (t)));
+ }
+
+ /* Return whether the pointer-types T1 and T2 used to determine
+ two alias sets of two references will yield the same answer
+ from get_deref_alias_set. */
+
+ bool
+ alias_ptr_types_compatible_p (tree t1, tree t2)
+ {
+ if (TYPE_MAIN_VARIANT (t1) == TYPE_MAIN_VARIANT (t2))
+ return true;
+
+ if (ref_all_alias_ptr_type_p (t1)
+ || ref_all_alias_ptr_type_p (t2))
+ return false;
+
+ return (TYPE_MAIN_VARIANT (TREE_TYPE (t1))
+ == TYPE_MAIN_VARIANT (TREE_TYPE (t2)));
+ }
+
/* Return the alias set for T, which may be either a type or an
expression. Call language-specific routine for help, if needed. */
*************** get_alias_set (tree t)
*** 615,622 ****
aren't types. */
if (! TYPE_P (t))
{
- tree inner;
-
/* Give the language a chance to do something with this tree
before we look at it. */
STRIP_NOPS (t);
--- 721,726 ----
*************** get_alias_set (tree t)
*** 624,674 ****
if (set != -1)
return set;
! /* Get the base object of the reference. */
! inner = t;
! while (handled_component_p (inner))
! {
! /* If there is a VIEW_CONVERT_EXPR in the chain we cannot use
! the type of any component references that wrap it to
! determine the alias-set. */
! if (TREE_CODE (inner) == VIEW_CONVERT_EXPR)
! t = TREE_OPERAND (inner, 0);
! inner = TREE_OPERAND (inner, 0);
! }
!
! /* Handle pointer dereferences here, they can override the
! alias-set. */
! if (INDIRECT_REF_P (inner))
! {
! set = get_deref_alias_set_1 (TREE_OPERAND (inner, 0));
! if (set != -1)
! return set;
! }
! else if (TREE_CODE (inner) == TARGET_MEM_REF)
! return get_deref_alias_set (TMR_OFFSET (inner));
! else if (TREE_CODE (inner) == MEM_REF)
! {
! set = get_deref_alias_set_1 (TREE_OPERAND (inner, 1));
! if (set != -1)
! return set;
! }
!
! /* If the innermost reference is a MEM_REF that has a
! conversion embedded treat it like a VIEW_CONVERT_EXPR above,
! using the memory access type for determining the alias-set. */
! if (TREE_CODE (inner) == MEM_REF
! && TYPE_MAIN_VARIANT (TREE_TYPE (inner))
! != TYPE_MAIN_VARIANT
! (TREE_TYPE (TREE_TYPE (TREE_OPERAND (inner, 1)))))
! return get_deref_alias_set (TREE_OPERAND (inner, 1));
!
! /* Otherwise, pick up the outermost object that we could have a pointer
! to, processing conversions as above. */
! while (component_uses_parent_alias_set (t))
! {
! t = TREE_OPERAND (t, 0);
! STRIP_NOPS (t);
! }
/* If we've already determined the alias set for a decl, just return
it. This is necessary for C++ anonymous unions, whose component
--- 728,738 ----
if (set != -1)
return set;
! /* Get the alias pointer-type to use or the outermost object
! that we could have a pointer to. */
! tree ptype = reference_alias_ptr_type_1 (&t);
! if (ptype != NULL)
! return get_deref_alias_set (ptype);
/* If we've already determined the alias set for a decl, just return
it. This is necessary for C++ anonymous unions, whose component
Index: gcc/alias.h
===================================================================
*** gcc/alias.h.orig 2013-09-24 10:48:25.000000000 +0200
--- gcc/alias.h 2013-09-24 10:48:27.663770703 +0200
*************** extern int alias_sets_conflict_p (alias_
*** 41,46 ****
--- 41,48 ----
extern int alias_sets_must_conflict_p (alias_set_type, alias_set_type);
extern int objects_must_conflict_p (tree, tree);
extern int nonoverlapping_memrefs_p (const_rtx, const_rtx, bool);
+ tree reference_alias_ptr_type (tree);
+ bool alias_ptr_types_compatible_p (tree, tree);
/* This alias set can be used to force a memory to conflict with all
other memories, creating a barrier across which no memory reference
Index: gcc/fold-const.c
===================================================================
*** gcc/fold-const.c.orig 2013-09-24 10:48:25.000000000 +0200
--- gcc/fold-const.c 2013-09-24 10:48:27.665770720 +0200
*************** operand_equal_p (const_tree arg0, const_
*** 2693,2700 ****
&& operand_equal_p (TYPE_SIZE (TREE_TYPE (arg0)),
TYPE_SIZE (TREE_TYPE (arg1)), flags)))
&& types_compatible_p (TREE_TYPE (arg0), TREE_TYPE (arg1))
! && (TYPE_MAIN_VARIANT (TREE_TYPE (TREE_OPERAND (arg0, 1)))
! == TYPE_MAIN_VARIANT (TREE_TYPE (TREE_OPERAND (arg1, 1))))
&& OP_SAME (0) && OP_SAME (1));
case ARRAY_REF:
--- 2693,2701 ----
&& operand_equal_p (TYPE_SIZE (TREE_TYPE (arg0)),
TYPE_SIZE (TREE_TYPE (arg1)), flags)))
&& types_compatible_p (TREE_TYPE (arg0), TREE_TYPE (arg1))
! && alias_ptr_types_compatible_p
! (TREE_TYPE (TREE_OPERAND (arg0, 1)),
! TREE_TYPE (TREE_OPERAND (arg1, 1)))
&& OP_SAME (0) && OP_SAME (1));
case ARRAY_REF:
Index: gcc/testsuite/g++.dg/vect/pr58513.cc
===================================================================
*** /dev/null 1970-01-01 00:00:00.000000000 +0000
--- gcc/testsuite/g++.dg/vect/pr58513.cc 2013-09-24 12:54:23.956450057 +0200
***************
*** 0 ****
--- 1,13 ----
+ // { dg-do compile }
+ // { dg-require-effective-target vect_int }
+
+ int op (const int& x, const int& y) { return x + y; }
+
+ void foo(int* a)
+ {
+ for (int i = 0; i < 1000; ++i)
+ a[i] = op(a[i], 1);
+ }
+
+ // { dg-final { scan-tree-dump "vectorized 1 loops" "vect" } }
+ // { dg-final { cleanup-tree-dump "vect" } }
More information about the Gcc-patches
mailing list