This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
Re: [PATCH] Fix PR32921, prune virtual operands of memory accesses based on TBAA
On Fri, 19 Oct 2007, Daniel Berlin wrote:
> On 10/19/07, Richard Guenther <rguenther@suse.de> wrote:
> > On Fri, 19 Oct 2007, Ian Lance Taylor wrote:
> >
> > > Richard Guenther <rguenther@suse.de> writes:
> > >
> > > > But then the killer issue comes along. The way we designed
> > > > CHANGE_DYNAMIC_TYPE_EXPR makes it impossible to do TBAA pruning on
> > > > memory accesses. For g++.dg/init/new16.C we have
> > > >
> > > > int *l = (int *)p;
> > > > *l = 0;
> > > > f = new (p) long;
> > > > *f = -1;
> > > >
> > > > l_7 = (int *) p_6(D);
> > > > *l_7 ={v} 0;
> > > > <<<change_dynamic_type (long int *) p_6(D))>>>
> > > > D.2035_15 = p_6(D);
> > > > f_10 = (long int *) D.2035_15;
> > > > *f_10 ={v} -1;
> > > >
> > > > but we do not have a connection of the CHANGE_DYNAMIC_TYPE_EXPR to
> > > > the memory reference site. So we happily prune SMT.17 from f_10s
> > > > alias set.
> > > >
> > > > l_7 = (int *) p_6(D);
> > > > # SMT.17_20 = VDEF <SMT.17_17>
> > > > *l_7 = 0;
> > > > D.2035_15 = p_6(D);
> > > > f_10 = (long int *) D.2035_15;
> > > > # SMT.16_21 = VDEF <SMT.16_16>
> > > > *f_10 = -1;
> > > >
> > > > Because out IL doesn't really tell the truth. Which even makes me
> > > > uncomfortable to just enable TBAA pruning for SFTs and bare DECLs.
> > > > But I guess that should work.
> > >
> > > The connection we need is supposed to be built by
> > > compute_tbaa_pruning--specifically, it should mark the reference with
> > > no_tbaa_pruning. Why isn't that working for you?
> >
> > Because I didn't know of it. But it also looks like it is local
> > to tree-ssa-structalias.c and not available at operand scanning time
> > (where we call access_can_touch_variable).
>
> This was a mistake. Move it to var_ann.
It looks like we have the global DECL_NO_TBAA_P. This works for new16.C
if I do:
base = get_base_address (ref);
if (base
&& INDIRECT_REF_P (base))
base_var = SSA_NAME_VAR (TREE_OPERAND (base, 0));
else
base_var = NULL_TREE;
/* If the alias sets of the alias and the ref do not conflict then
then the access does not touch the alias. This is pruning based
on TBAA. */
if (flag_strict_aliasing
/* Memory partitions represent multiple types and need different
treatment for TBAA pruning. */
&& TREE_CODE (alias) != MEMORY_PARTITION_TAG
/* We cannot prune symbol memory tags for stores as this breaks
CHANGE_DYNAMIC_TYPE_EXPR handling. Unless the base access
is not marked with DECL_NO_TBAA_P. */
&& (!base_var || !DECL_NO_TBAA_P (base_var) || !is_write)
we then get
l_7 = (int *) p_6(D);
# SMT.17_20 = VDEF <SMT.17_17>
*l_7 = 0;
D.2035_15 = p_6(D);
f_10 = (long int *) D.2035_15;
# SMT.16_21 = VDEF <SMT.16_16>
# SMT.17_22 = VDEF <SMT.17_20>
*f_10 = -1;
...
# VUSE <SMT.16_16>
D.2036_12 = *f_1;
return D.2036_12;
so we prune on the read, which is allowed.
> > But maybe Danny didn't look
> > closely enough at my patch and access_can_touch_variable is the compeltely
> > wrong place to do TBAA pruning.
>
> It's a fine place but i wouldn't try *too* hard.
> At some point we just need to start moving our optimizers to the model
> of using memory dependence analysis, and using the memory def-use
> chains as a starting point, not the end-all be-all of aliasing.
>
> I'm happy to try to get as much as we can out of vdef/vuse directly,
> but there is some limit to precision you will hit where anything more
> will explode time and memory, and we are fairly close to that limit
> already.
Well, pruning virtual operands _saves_ memory ;) (Which is why I also
look at not generating subvariables for unions - we don't seem to make
use of them in optimizers and they certainly consume memory)
So, the following is the current state of the patch. It still breaks
the hell out of Ada - I suppose I need to check TYPE_REF_CAN_ALIAS_ALL
on the pointers the same as DECL_NO_TBAA_P maybe, though I thought this
might be taken care by get_alias_set ().
Richard.
2007-10-19 Richard Guenther <rguenther@suse.de>
PR middle-end/32921
* tree-ssa-operands.c (access_can_touch_variable): Aliases
with non-conflicting alias sets with the reference do not
touch the access. Re-structure function a bit.
* tree-flow-inline.h (var_can_have_subvars): Unions cannot
have subvars.
Index: tree-flow-inline.h
===================================================================
*** tree-flow-inline.h (revision 129483)
--- tree-flow-inline.h (working copy)
*************** var_can_have_subvars (const_tree v)
*** 1634,1640 ****
return false;
/* Aggregates can have subvars. */
! if (AGGREGATE_TYPE_P (TREE_TYPE (v)))
return true;
/* Complex types variables which are not also a gimple register can
--- 1634,1642 ----
return false;
/* Aggregates can have subvars. */
! if (AGGREGATE_TYPE_P (TREE_TYPE (v))
! && TREE_CODE (TREE_TYPE (v)) != UNION_TYPE
! && TREE_CODE (TREE_TYPE (v)) != QUAL_UNION_TYPE)
return true;
/* Complex types variables which are not also a gimple register can
Index: tree-ssa-operands.c
===================================================================
*** tree-ssa-operands.c (revision 129490)
--- tree-ssa-operands.c (working copy)
*************** append_vuse (tree var)
*** 1189,1204 ****
expression, if available, or NULL otherwise. ALIAS is the variable
we are asking if REF can access. OFFSET and SIZE come from the
memory access expression that generated this virtual operand.
XXX: We should handle the NO_ALIAS attributes here. */
static bool
access_can_touch_variable (tree ref, tree alias, HOST_WIDE_INT offset,
! HOST_WIDE_INT size)
{
bool offsetgtz = offset > 0;
unsigned HOST_WIDE_INT uoffset = (unsigned HOST_WIDE_INT) offset;
! tree base = ref ? get_base_address (ref) : NULL;
/* If ALIAS is .GLOBAL_VAR then the memory reference REF must be
using a call-clobbered memory tag. By definition, call-clobbered
--- 1189,1209 ----
expression, if available, or NULL otherwise. ALIAS is the variable
we are asking if REF can access. OFFSET and SIZE come from the
memory access expression that generated this virtual operand.
+ IS_WRITE should be true if the access is a store, otherwise false.
XXX: We should handle the NO_ALIAS attributes here. */
static bool
access_can_touch_variable (tree ref, tree alias, HOST_WIDE_INT offset,
! HOST_WIDE_INT size, bool is_write)
{
bool offsetgtz = offset > 0;
unsigned HOST_WIDE_INT uoffset = (unsigned HOST_WIDE_INT) offset;
! tree base, base_var;
!
! /* For NULL refs we cannot prune based on the unknown access. */
! if (!ref)
! return true;
/* If ALIAS is .GLOBAL_VAR then the memory reference REF must be
using a call-clobbered memory tag. By definition, call-clobbered
*************** access_can_touch_variable (tree ref, tre
*** 1206,1216 ****
if (alias == gimple_global_var (cfun))
return true;
/* If ref is a TARGET_MEM_REF, just return true, as we can't really
! disambiguate them right now. */
! if (ref && TREE_CODE (ref) == TARGET_MEM_REF)
return true;
!
/* If ALIAS is an SFT, it can't be touched if the offset
and size of the access is not overlapping with the SFT offset and
size. This is only true if we are accessing through a pointer
--- 1211,1249 ----
if (alias == gimple_global_var (cfun))
return true;
+ base = get_base_address (ref);
+ if (base
+ && INDIRECT_REF_P (base))
+ base_var = SSA_NAME_VAR (TREE_OPERAND (base, 0));
+ else
+ base_var = NULL_TREE;
+
+ /* If the alias sets of the alias and the ref do not conflict then
+ then the access does not touch the alias. This is pruning based
+ on TBAA. */
+ if (flag_strict_aliasing
+ /* Memory partitions represent multiple types and need different
+ treatment for TBAA pruning. */
+ && TREE_CODE (alias) != MEMORY_PARTITION_TAG
+ /* We cannot prune symbol memory tags for stores as this breaks
+ CHANGE_DYNAMIC_TYPE_EXPR handling. Unless the base access
+ is not marked with DECL_NO_TBAA_P. */
+ && (!base_var || !DECL_NO_TBAA_P (base_var) || !is_write)
+ /* HEAP variables do not have types that are meaningful for TBAA. */
+ && !var_ann (alias)->is_heapvar
+ /* If the inner reference has alias set zero, we cannot use the
+ type of the access for TBAA purposes. This happens with
+ the use of attribute may_alias. */
+ && (!base || get_alias_set (TREE_TYPE (base)) != 0)
+ && !alias_sets_conflict_p (get_alias_set (TREE_TYPE (alias)),
+ get_alias_set (TREE_TYPE (ref))))
+ return false;
+
/* If ref is a TARGET_MEM_REF, just return true, as we can't really
! disambiguate them based on offsets right now. */
! if (TREE_CODE (ref) == TARGET_MEM_REF)
return true;
!
/* If ALIAS is an SFT, it can't be touched if the offset
and size of the access is not overlapping with the SFT offset and
size. This is only true if we are accessing through a pointer
*************** access_can_touch_variable (tree ref, tre
*** 1309,1316 ****
my_char_ref_1 = (char[1:1] &) &my_char;
D.874_2 = (*my_char_ref_1)[1]{lb: 1 sz: 1};
*/
! else if (ref
! && flag_strict_aliasing
&& TREE_CODE (ref) != INDIRECT_REF
&& !MTAG_P (alias)
&& base
--- 1342,1348 ----
my_char_ref_1 = (char[1:1] &) &my_char;
D.874_2 = (*my_char_ref_1)[1]{lb: 1 sz: 1};
*/
! else if (flag_strict_aliasing
&& TREE_CODE (ref) != INDIRECT_REF
&& !MTAG_P (alias)
&& base
*************** access_can_touch_variable (tree ref, tre
*** 1344,1351 ****
/* If the offset of the access is greater than the size of one of
the possible aliases, it can't be touching that alias, because it
would be past the end of the structure. */
! else if (ref
! && flag_strict_aliasing
&& TREE_CODE (ref) != INDIRECT_REF
&& !MTAG_P (alias)
&& !POINTER_TYPE_P (TREE_TYPE (alias))
--- 1376,1382 ----
/* If the offset of the access is greater than the size of one of
the possible aliases, it can't be touching that alias, because it
would be past the end of the structure. */
! else if (flag_strict_aliasing
&& TREE_CODE (ref) != INDIRECT_REF
&& !MTAG_P (alias)
&& !POINTER_TYPE_P (TREE_TYPE (alias))
*************** add_vars_for_offset (tree full_ref, tree
*** 1408,1414 ****
|| (TREE_CODE (var) != STRUCT_FIELD_TAG
&& (!var_can_have_subvars (var) || !get_subvars_for_var (var))))
{
! if (!access_can_touch_variable (full_ref, var, offset, size))
return false;
if (is_def)
--- 1439,1445 ----
|| (TREE_CODE (var) != STRUCT_FIELD_TAG
&& (!var_can_have_subvars (var) || !get_subvars_for_var (var))))
{
! if (!access_can_touch_variable (full_ref, var, offset, size, is_def))
return false;
if (is_def)
*************** add_vars_for_offset (tree full_ref, tree
*** 1428,1434 ****
if (overlap_subvar (SFT_OFFSET (var) + offset, size,
sv->var, NULL)
&& access_can_touch_variable (full_ref, sv->var,
! offset, size))
{
added = true;
if (is_def)
--- 1459,1465 ----
if (overlap_subvar (SFT_OFFSET (var) + offset, size,
sv->var, NULL)
&& access_can_touch_variable (full_ref, sv->var,
! offset, size, is_def))
{
added = true;
if (is_def)
*************** add_vars_for_offset (tree full_ref, tree
*** 1452,1458 ****
if (overlap_subvar (SFT_OFFSET (var) + offset, size,
sv->var, NULL)
&& access_can_touch_variable (full_ref, sv->var, offset,
! size))
{
added = true;
if (is_def)
--- 1483,1489 ----
if (overlap_subvar (SFT_OFFSET (var) + offset, size,
sv->var, NULL)
&& access_can_touch_variable (full_ref, sv->var, offset,
! size, is_def))
{
added = true;
if (is_def)