This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
[PATCH][alias-improvement] Fix PR38301, TBAA issues with the vectorizer
- From: Richard Guenther <rguenther at suse dot de>
- To: gcc-patches at gcc dot gnu dot org
- Date: Wed, 7 Jan 2009 12:07:00 +0100 (CET)
- Subject: [PATCH][alias-improvement] Fix PR38301, TBAA issues with the vectorizer
As I chickened out for trunk to fix this this makes the fix on the
alias-improvements branch where it is really easy to do so. I took
the opportunity to split out a get_deref_alias_set from get_alias_set
to avoid building indirect-ref trees just for querying alias sets.
TODO: go over the rest of the codebase and search for opportunities
to use that. (note that it is also a correctness issue - using
get_alias_set on the memory type is incorrect!)
Bootstrapped and tested on x86_64-unknown-linux-gnu, applied to the
branch. It doesn't fix the x86_64 vectorizer issue as I hoped.
Richard.
2009-01-07 Richard Guenther <rguenther@suse.de>
PR tree-optimization/38301
* alias.c (get_deref_alias_set): New function split out from ...
(get_alias_set): ... here.
* alias.h (get_deref_alias_set): Declare.
* tree-vect-transform.c (vect_create_data_ref_ptr): Remove unused
type parameter. Remove restrict pointer handling. Create a
ref-all pointer in case type-based alias sets do not conflict.
(vectorizable_store): Re-instantiate TBAA assert.
(vectorizable_load): Likewise.
Index: gcc/alias.c
===================================================================
*** gcc/alias.c (revision 143063)
--- gcc/alias.c (working copy)
*************** component_uses_parent_alias_set (const_t
*** 482,487 ****
--- 482,560 ----
}
}
+ /* Return the alias set for the memory pointed to by T, which may be
+ either a type or an expression. */
+
+ 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;
+
+ if (! TYPE_P (t))
+ {
+ tree decl = find_base_decl (t);
+
+ if (decl && DECL_POINTER_ALIAS_SET_KNOWN_P (decl))
+ {
+ /* If we haven't computed the actual alias set, do it now. */
+ if (DECL_POINTER_ALIAS_SET (decl) == -2)
+ {
+ tree pointed_to_type = TREE_TYPE (TREE_TYPE (decl));
+
+ /* No two restricted pointers can point at the same thing.
+ However, a restricted pointer can point at the same thing
+ as an unrestricted pointer, if that unrestricted pointer
+ is based on the restricted pointer. So, we make the
+ alias set for the restricted pointer a subset of the
+ alias set for the type pointed to by the type of the
+ decl. */
+ alias_set_type pointed_to_alias_set
+ = get_alias_set (pointed_to_type);
+
+ if (pointed_to_alias_set == 0)
+ /* It's not legal to make a subset of alias set zero. */
+ DECL_POINTER_ALIAS_SET (decl) = 0;
+ else if (AGGREGATE_TYPE_P (pointed_to_type))
+ /* For an aggregate, we must treat the restricted
+ pointer the same as an ordinary pointer. If we
+ were to make the type pointed to by the
+ restricted pointer a subset of the pointed-to
+ type, then we would believe that other subsets
+ of the pointed-to type (such as fields of that
+ type) do not conflict with the type pointed to
+ by the restricted pointer. */
+ DECL_POINTER_ALIAS_SET (decl)
+ = pointed_to_alias_set;
+ else
+ {
+ DECL_POINTER_ALIAS_SET (decl) = new_alias_set ();
+ record_alias_subset (pointed_to_alias_set,
+ DECL_POINTER_ALIAS_SET (decl));
+ }
+ }
+
+ /* We use the alias set indicated in the declaration. */
+ return DECL_POINTER_ALIAS_SET (decl);
+ }
+
+ /* Now all we care about is the type. */
+ t = TREE_TYPE (t);
+ }
+
+ /* 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;
+
+ /* Fall back to the alias-set of the pointed-to type. */
+ return get_alias_set (TREE_TYPE (t));
+ }
+
/* 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)
*** 522,588 ****
STRIP_NOPS (inner);
}
- /* Check for accesses through restrict-qualified pointers. */
if (INDIRECT_REF_P (inner))
! {
! tree decl;
!
! if (TREE_CODE (TREE_OPERAND (inner, 0)) == SSA_NAME)
! decl = SSA_NAME_VAR (TREE_OPERAND (inner, 0));
! else
! decl = find_base_decl (TREE_OPERAND (inner, 0));
!
! if (decl && DECL_POINTER_ALIAS_SET_KNOWN_P (decl))
! {
! /* If we haven't computed the actual alias set, do it now. */
! if (DECL_POINTER_ALIAS_SET (decl) == -2)
! {
! tree pointed_to_type = TREE_TYPE (TREE_TYPE (decl));
!
! /* No two restricted pointers can point at the same thing.
! However, a restricted pointer can point at the same thing
! as an unrestricted pointer, if that unrestricted pointer
! is based on the restricted pointer. So, we make the
! alias set for the restricted pointer a subset of the
! alias set for the type pointed to by the type of the
! decl. */
! alias_set_type pointed_to_alias_set
! = get_alias_set (pointed_to_type);
!
! if (pointed_to_alias_set == 0)
! /* It's not legal to make a subset of alias set zero. */
! DECL_POINTER_ALIAS_SET (decl) = 0;
! else if (AGGREGATE_TYPE_P (pointed_to_type))
! /* For an aggregate, we must treat the restricted
! pointer the same as an ordinary pointer. If we
! were to make the type pointed to by the
! restricted pointer a subset of the pointed-to
! type, then we would believe that other subsets
! of the pointed-to type (such as fields of that
! type) do not conflict with the type pointed to
! by the restricted pointer. */
! DECL_POINTER_ALIAS_SET (decl)
! = pointed_to_alias_set;
! else
! {
! DECL_POINTER_ALIAS_SET (decl) = new_alias_set ();
! record_alias_subset (pointed_to_alias_set,
! DECL_POINTER_ALIAS_SET (decl));
! }
! }
!
! /* We use the alias set indicated in the declaration. */
! return DECL_POINTER_ALIAS_SET (decl);
! }
!
! /* 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. */
! else if (TREE_CODE (TREE_TYPE (inner)) == VOID_TYPE
! || (TYPE_REF_CAN_ALIAS_ALL
! (TREE_TYPE (TREE_OPERAND (inner, 0)))))
! return 0;
! }
/* Otherwise, pick up the outermost object that we could have a pointer
to, processing conversions as above. */
--- 595,602 ----
STRIP_NOPS (inner);
}
if (INDIRECT_REF_P (inner))
! return get_deref_alias_set (TREE_OPERAND (inner, 0));
/* Otherwise, pick up the outermost object that we could have a pointer
to, processing conversions as above. */
Index: gcc/alias.h
===================================================================
*** gcc/alias.h (revision 143063)
--- gcc/alias.h (working copy)
*************** typedef int alias_set_type;
*** 32,37 ****
--- 32,38 ----
extern alias_set_type new_alias_set (void);
extern alias_set_type get_alias_set (tree);
+ extern alias_set_type get_deref_alias_set (tree);
extern alias_set_type get_varargs_alias_set (void);
extern alias_set_type get_frame_alias_set (void);
extern bool component_uses_parent_alias_set (const_tree);
Index: gcc/tree-vect-transform.c
===================================================================
*** gcc/tree-vect-transform.c (revision 143063)
--- gcc/tree-vect-transform.c (working copy)
*************** static bool vect_transform_stmt (gimple,
*** 50,56 ****
slp_tree, slp_instance);
static tree vect_create_destination_var (tree, tree);
static tree vect_create_data_ref_ptr
! (gimple, struct loop*, tree, tree *, gimple *, bool, bool *, tree);
static tree vect_create_addr_base_for_vector_ref
(gimple, gimple_seq *, tree, struct loop *);
static tree vect_get_new_vect_var (tree, enum vect_var_kind, const char *);
--- 50,56 ----
slp_tree, slp_instance);
static tree vect_create_destination_var (tree, tree);
static tree vect_create_data_ref_ptr
! (gimple, struct loop*, tree, tree *, gimple *, bool, bool *);
static tree vect_create_addr_base_for_vector_ref
(gimple, gimple_seq *, tree, struct loop *);
static tree vect_get_new_vect_var (tree, enum vect_var_kind, const char *);
*************** vect_create_addr_base_for_vector_ref (gi
*** 1013,1019 ****
static tree
vect_create_data_ref_ptr (gimple stmt, struct loop *at_loop,
tree offset, tree *initial_address, gimple *ptr_incr,
! bool only_init, bool *inv_p, tree type)
{
tree base_name;
stmt_vec_info stmt_info = vinfo_for_stmt (stmt);
--- 1013,1019 ----
static tree
vect_create_data_ref_ptr (gimple stmt, struct loop *at_loop,
tree offset, tree *initial_address, gimple *ptr_incr,
! bool only_init, bool *inv_p)
{
tree base_name;
stmt_vec_info stmt_info = vinfo_for_stmt (stmt);
*************** vect_create_data_ref_ptr (gimple stmt, s
*** 1071,1092 ****
}
/** (1) Create the new vector-pointer variable: **/
! if (type)
! vect_ptr_type = build_pointer_type (type);
! else
! vect_ptr_type = build_pointer_type (vectype);
!
! if (TREE_CODE (DR_BASE_ADDRESS (dr)) == SSA_NAME
! && TYPE_RESTRICT (TREE_TYPE (DR_BASE_ADDRESS (dr))))
! vect_ptr_type = build_qualified_type (vect_ptr_type, TYPE_QUAL_RESTRICT);
vect_ptr = vect_get_new_vect_var (vect_ptr_type, vect_pointer_var,
get_name (base_name));
! if (TREE_CODE (DR_BASE_ADDRESS (dr)) == SSA_NAME
! && TYPE_RESTRICT (TREE_TYPE (DR_BASE_ADDRESS (dr))))
{
! get_alias_set (base_name);
! DECL_POINTER_ALIAS_SET (vect_ptr)
! = DECL_POINTER_ALIAS_SET (SSA_NAME_VAR (DR_BASE_ADDRESS (dr)));
}
add_referenced_var (vect_ptr);
--- 1071,1099 ----
}
/** (1) Create the new vector-pointer variable: **/
! vect_ptr_type = build_pointer_type (vectype);
vect_ptr = vect_get_new_vect_var (vect_ptr_type, vect_pointer_var,
get_name (base_name));
!
! /* If any of the data-references in the stmt group does not conflict
! with the created vector data-reference use a ref-all pointer instead. */
! if (STMT_VINFO_DR_GROUP_SIZE (stmt_info) > 1)
{
! gimple orig_stmt = STMT_VINFO_DR_GROUP_FIRST_DR (stmt_info);
! do
! {
! if (!alias_sets_conflict_p (get_deref_alias_set (vect_ptr),
! get_alias_set (gimple_assign_lhs (orig_stmt))))
! {
! vect_ptr_type = build_pointer_type_for_mode (vectype,
! ptr_mode, true);
! vect_ptr = vect_get_new_vect_var (vect_ptr_type, vect_pointer_var,
! get_name (base_name));
! break;
! }
! orig_stmt = STMT_VINFO_DR_GROUP_NEXT_DR (vinfo_for_stmt (orig_stmt));
! }
! while (orig_stmt);
}
add_referenced_var (vect_ptr);
*************** vectorizable_store (gimple stmt, gimple_
*** 5377,5383 ****
TREE_TYPE (vec_oprnd)));
dataref_ptr = vect_create_data_ref_ptr (first_stmt, NULL, NULL_TREE,
&dummy, &ptr_incr, false,
! &inv_p, NULL);
gcc_assert (!inv_p);
}
else
--- 5379,5385 ----
TREE_TYPE (vec_oprnd)));
dataref_ptr = vect_create_data_ref_ptr (first_stmt, NULL, NULL_TREE,
&dummy, &ptr_incr, false,
! &inv_p);
gcc_assert (!inv_p);
}
else
*************** vectorizable_store (gimple stmt, gimple_
*** 5426,5431 ****
--- 5428,5437 ----
vec_oprnd = VEC_index (tree, result_chain, i);
data_ref = build_fold_indirect_ref (dataref_ptr);
+ /* If accesses through a pointer to vectype do not alias the original
+ memory reference we have a problem. This should never happen. */
+ gcc_assert (alias_sets_conflict_p (get_alias_set (data_ref),
+ get_alias_set (gimple_assign_lhs (stmt))));
/* Arguments are ready. Create the new vector stmt. */
new_stmt = gimple_build_assign (data_ref, vec_oprnd);
*************** vect_setup_realignment (gimple stmt, gim
*** 5616,5622 ****
pe = loop_preheader_edge (loop_for_initial_load);
vec_dest = vect_create_destination_var (scalar_dest, vectype);
ptr = vect_create_data_ref_ptr (stmt, loop_for_initial_load, NULL_TREE,
! &init_addr, &inc, true, &inv_p, NULL_TREE);
data_ref = build1 (ALIGN_INDIRECT_REF, vectype, ptr);
new_stmt = gimple_build_assign (vec_dest, data_ref);
new_temp = make_ssa_name (vec_dest, new_stmt);
--- 5622,5628 ----
pe = loop_preheader_edge (loop_for_initial_load);
vec_dest = vect_create_destination_var (scalar_dest, vectype);
ptr = vect_create_data_ref_ptr (stmt, loop_for_initial_load, NULL_TREE,
! &init_addr, &inc, true, &inv_p);
data_ref = build1 (ALIGN_INDIRECT_REF, vectype, ptr);
new_stmt = gimple_build_assign (vec_dest, data_ref);
new_temp = make_ssa_name (vec_dest, new_stmt);
*************** vectorizable_load (gimple stmt, gimple_s
*** 6588,6594 ****
dataref_ptr = vect_create_data_ref_ptr (first_stmt,
at_loop, offset,
&dummy, &ptr_incr, false,
! &inv_p, NULL_TREE);
else
dataref_ptr =
bump_vector_ptr (dataref_ptr, ptr_incr, gsi, stmt, NULL_TREE);
--- 6594,6600 ----
dataref_ptr = vect_create_data_ref_ptr (first_stmt,
at_loop, offset,
&dummy, &ptr_incr, false,
! &inv_p);
else
dataref_ptr =
bump_vector_ptr (dataref_ptr, ptr_incr, gsi, stmt, NULL_TREE);
*************** vectorizable_load (gimple stmt, gimple_s
*** 6649,6654 ****
--- 6655,6664 ----
default:
gcc_unreachable ();
}
+ /* If accesses through a pointer to vectype do not alias the original
+ memory reference we have a problem. This should never happen. */
+ gcc_assert (alias_sets_conflict_p (get_alias_set (data_ref),
+ get_alias_set (gimple_assign_rhs1 (stmt))));
vec_dest = vect_create_destination_var (scalar_dest, vectype);
new_stmt = gimple_build_assign (vec_dest, data_ref);
new_temp = make_ssa_name (vec_dest, new_stmt);