re PR tree-optimization/33870 (miscompiles sqlite)

2007-11-16  Richard Guenther  <rguenther@suse.de>

	PR tree-optimization/33870
	* tree.h (struct tree_memory_tag): Add base_for_components flag.
	(struct tree_struct_field_tag): Remove nesting_level field.
	(SFT_NESTING_LEVEL): Remove.
	(SFT_BASE_FOR_COMPONENTS_P): Add.
	* tree-flow.h (struct fieldoff): Remove nesting_level field.  Add
	base_for_components flag.
	(push_fields_onto_fieldstack): Remove nesting_level parameter.
	* tree-ssa-alias.c (create_sft): Likewise.  Add base_for_components
	parameter.
	(create_overlap_variables_for): Deal with it.
	* tree-dfa.c (dump_subvars_for): Likewise.
	(dump_variable): Likewise.
	* tree-ssa-structalias.c (push_fields_onto_fieldstack): Likewise.
	Set base_for_components for first elements of sub-structures.
	(create_variable_info_for): Handle base_for_components.
	(set_uids_in_ptset): Always set SFT_UNPARTITIONABLE_P for
	pointed-to SFTs if SFT_BASE_FOR_COMPONENTS_P is set.
	* tree-ssa-operands.c (ref_nesting_level): Remove.
	(add_vars_for_offset): Remove full_ref parameter, always add
	the offset of the pointed-to SFT.
	(add_virtual_operand): Adjust for changed signature of
	add_vars_for_offset.

	* gcc.dg/torture/pr33870.c: New testcase.

From-SVN: r130231
This commit is contained in:
Richard Guenther 2007-11-16 14:40:04 +00:00 committed by Richard Biener
parent bf3bde19e0
commit 99739a3e63
9 changed files with 178 additions and 173 deletions

View File

@ -1,3 +1,29 @@
2007-11-16 Richard Guenther <rguenther@suse.de>
PR tree-optimization/33870
* tree.h (struct tree_memory_tag): Add base_for_components flag.
(struct tree_struct_field_tag): Remove nesting_level field.
(SFT_NESTING_LEVEL): Remove.
(SFT_BASE_FOR_COMPONENTS_P): Add.
* tree-flow.h (struct fieldoff): Remove nesting_level field. Add
base_for_components flag.
(push_fields_onto_fieldstack): Remove nesting_level parameter.
* tree-ssa-alias.c (create_sft): Likewise. Add base_for_components
parameter.
(create_overlap_variables_for): Deal with it.
* tree-dfa.c (dump_subvars_for): Likewise.
(dump_variable): Likewise.
* tree-ssa-structalias.c (push_fields_onto_fieldstack): Likewise.
Set base_for_components for first elements of sub-structures.
(create_variable_info_for): Handle base_for_components.
(set_uids_in_ptset): Always set SFT_UNPARTITIONABLE_P for
pointed-to SFTs if SFT_BASE_FOR_COMPONENTS_P is set.
* tree-ssa-operands.c (ref_nesting_level): Remove.
(add_vars_for_offset): Remove full_ref parameter, always add
the offset of the pointed-to SFT.
(add_virtual_operand): Adjust for changed signature of
add_vars_for_offset.
2007-11-16 Sa Liu <saliu@de.ibm.com>
* config/spu/spu.md (floatunssidf2, floatunsdidf2): Inlined

View File

@ -1,3 +1,8 @@
2007-11-16 Richard Guenther <rguenther@suse.de>
PR tree-optimization/33870
* gcc.dg/torture/pr33870.c: New testcase.
2007-11-16 Paul Thomas <pault@gcc.gnu.org>
PR fortran/33986

View File

@ -0,0 +1,30 @@
/* { dg-do run } */
/* { dg-options "--param max-aliased-vops=1" } */
struct X {
int i;
int a[4];
} m;
int a[4];
int __attribute__((noinline)) foo(int b)
{
int (*p)[4] = b ? &a : &m.a;
a[3] = 0;
(*p)[3] = 1;
return (*p)[3] + (*p)[2] + (*p)[1] + a[0] + a[3];
}
extern void abort (void);
int main()
{
int i;
for (i = 0; i < 4; ++i)
a[i] = 0;
if (foo(1) != 2)
abort ();
return 0;
}

View File

@ -288,7 +288,8 @@ dump_subvars_for (FILE *file, tree var)
{
print_generic_expr (file, subvar, dump_flags);
fprintf (file, "@" HOST_WIDE_INT_PRINT_UNSIGNED, SFT_OFFSET (subvar));
fprintf (file, "[%u]", SFT_NESTING_LEVEL (subvar));
if (SFT_BASE_FOR_COMPONENTS_P (subvar))
fprintf (file, "[B]");
fprintf (file, " ");
}
@ -424,7 +425,8 @@ dump_variable (FILE *file, tree var)
{
fprintf (file, ", offset: " HOST_WIDE_INT_PRINT_UNSIGNED,
SFT_OFFSET (var));
fprintf (file, ", nesting: %u", SFT_NESTING_LEVEL (var));
fprintf (file, ", base for components: %s",
SFT_BASE_FOR_COMPONENTS_P (var) ? "NO" : "YES");
fprintf (file, ", partitionable: %s",
SFT_UNPARTITIONABLE_P (var) ? "NO" : "YES");
}

View File

@ -1159,22 +1159,21 @@ struct fieldoff
/* Field. */
tree decl;
/* Nesting level. This number represents how many structures are
wrapping this field. */
unsigned nesting_level;
/* Offset from the base of the base containing object to this field. */
HOST_WIDE_INT offset;
/* Alias set for the field. */
alias_set_type alias_set;
/* True, if this offset can be a base for further component accesses. */
unsigned base_for_components : 1;
};
typedef struct fieldoff fieldoff_s;
DEF_VEC_O(fieldoff_s);
DEF_VEC_ALLOC_O(fieldoff_s,heap);
int push_fields_onto_fieldstack (tree, VEC(fieldoff_s,heap) **, HOST_WIDE_INT,
bool *, tree, unsigned);
int push_fields_onto_fieldstack (tree, VEC(fieldoff_s,heap) **,
HOST_WIDE_INT, bool *, tree);
void sort_fieldstack (VEC(fieldoff_s,heap) *);
void init_alias_heapvars (void);

View File

@ -3791,7 +3791,7 @@ get_or_create_used_part_for (size_t uid)
static tree
create_sft (tree var, tree field, unsigned HOST_WIDE_INT offset,
unsigned HOST_WIDE_INT size, alias_set_type alias_set,
unsigned nesting_level)
bool base_for_components)
{
tree subvar = create_tag_raw (STRUCT_FIELD_TAG, field, "SFT");
@ -3811,7 +3811,8 @@ create_sft (tree var, tree field, unsigned HOST_WIDE_INT offset,
SFT_OFFSET (subvar) = offset;
SFT_SIZE (subvar) = size;
SFT_ALIAS_SET (subvar) = alias_set;
SFT_NESTING_LEVEL (subvar) = nesting_level;
SFT_BASE_FOR_COMPONENTS_P (subvar) = base_for_components;
SFT_UNPARTITIONABLE_P (subvar) = false;
return subvar;
}
@ -3833,7 +3834,7 @@ create_overlap_variables_for (tree var)
return;
push_fields_onto_fieldstack (TREE_TYPE (var), &fieldstack, 0, NULL,
TREE_TYPE (var), 0);
TREE_TYPE (var));
/* Make sure to not create SFTs for structs we won't generate variable
infos for. See tree-ssa-structalias.c:create_variable_info_for (). */
if (VEC_length (fieldoff_s, fieldstack) != 0
@ -3919,6 +3920,7 @@ create_overlap_variables_for (tree var)
field, skip it. Note that we always need the field at
offset 0 so we can properly handle pointers to the
structure. */
if ((fo->offset != 0
&& ((fo->offset <= up->minused
&& fo->offset + fosize <= up->minused)
@ -3927,9 +3929,8 @@ create_overlap_variables_for (tree var)
&& fosize == lastfosize
&& currfotype == lastfotype))
continue;
subvar = create_sft (var, fo->type, fo->offset, fosize,
fo->alias_set, fo->nesting_level);
subvar = create_sft (var, fo->type, fo->offset,
fosize, fo->alias_set, fo->base_for_components);
VEC_quick_push (tree, *subvars, subvar);
if (dump_file)
@ -3940,8 +3941,7 @@ create_overlap_variables_for (tree var)
SFT_OFFSET (subvar));
fprintf (dump_file, " size " HOST_WIDE_INT_PRINT_DEC,
SFT_SIZE (subvar));
fprintf (dump_file, " nesting level %d\n",
SFT_NESTING_LEVEL (subvar));
fprintf (dump_file, "\n");
}
lastfotype = currfotype;

View File

@ -1367,36 +1367,10 @@ access_can_touch_variable (tree ref, tree alias, HOST_WIDE_INT offset,
return true;
}
/* Given an aggregate expression FULL_REF, return the number of
aggregates that are containing FULL_REF. So, given a structure
reference a.b.c.d, the nesting level for this expression is 2 (the
number of '.' in the expression minus 1). */
static unsigned
ref_nesting_level (tree full_ref)
{
unsigned nesting_level = 0;
if (!handled_component_p (full_ref))
return 0;
full_ref = TREE_OPERAND (full_ref, 0);
while (handled_component_p (full_ref))
{
nesting_level++;
full_ref = TREE_OPERAND (full_ref, 0);
}
return nesting_level;
}
/* Add the actual variables FULL_REF can access, given a member of
FULL_REF's points-to set VAR, where FULL_REF is an access of SIZE at
OFFSET from var. IS_CALL_SITE is true if this is a call, and IS_DEF
is true if this is supposed to be a vdef, and false if this should
be a VUSE.
/* Add the actual variables accessed, given a member of a points-to set
that is the SFT VAR, where the access is of SIZE at OFFSET from VAR.
IS_CALL_SITE is true if this is a call, and IS_DEF is true if this is
supposed to be a vdef, and false if this should be a VUSE.
The real purpose of this function is to take a points-to set for a
pointer to a structure, say
@ -1411,12 +1385,10 @@ ref_nesting_level (tree full_ref)
This is necessary because foop only actually points to foo's first
member, so that is all the points-to set contains. However, an access
to foop->a may be touching some single SFT if we have created some
SFT's for a structure.
FULL_REF is the original memory expression being analyzed. */
SFT's for a structure. */
static bool
add_vars_for_offset (tree full_ref, tree var, unsigned HOST_WIDE_INT offset,
add_vars_for_offset (tree var, unsigned HOST_WIDE_INT offset,
unsigned HOST_WIDE_INT size, bool is_def)
{
bool added = false;
@ -1424,55 +1396,8 @@ add_vars_for_offset (tree full_ref, tree var, unsigned HOST_WIDE_INT offset,
subvar_t sv;
unsigned int i;
if (full_ref
&& SFT_NESTING_LEVEL (var) > 0
&& ref_nesting_level (full_ref) < SFT_NESTING_LEVEL (var))
{
/* Since VAR is an SFT inside a nested structure, the OFFSET
computed by get_ref_base_and_extent is the offset from the
start of the immediately containing structure. If VAR is an
SFT inside a nested structure, then FULL_REF may be a
reference to the structure immediately enclosing SFT, and so
OFFSET will be the offset from the start of the immediately
enclosing structure.
However, to find out what other SFTs are affected by this
reference, we need to know the offsets starting at the root
structure in the nesting hierarchy.
For instance, given the following structure:
struct X {
int a;
struct Y {
int b;
struct Z {
int c[3];
} d;
} e;
} m;
and the following address expression:
p_1 = &m.e.d;
This structure will receive 5 SFTs, namely 2 for fields 'a'
and 'b' and 3 for the array 'c' in struct Z. So, the
reference p_1->c[2] and m.e.d.c[2] access the exact same
memory location (ie, SFT.5).
Now, alias analysis computed the points-to set for pointer
p_1 as { SFT.3 } because that is the first field that p_1
actually points to. When the expression p_1->c[2] is
analyzed, get_ref_base_and_extent will return an offset of 96
because we are accessing the third element of the array. But
the SFT we are looking for is actually at offset 160,
counting from the top of struct X.
Therefore, we adjust OFFSET by the offset of VAR so that we
can get at all the fields starting at VAR. */
offset += SFT_OFFSET (var);
}
/* Adjust offset by the pointed-to location. */
offset += SFT_OFFSET (var);
/* Add all subvars of var that overlap with the access.
Binary search for the first relevant SFT. */
@ -1575,8 +1500,25 @@ add_virtual_operand (tree var, stmt_ann_t s_ann, int flags,
if it is a potential points-to location. */
if (TREE_CODE (al) == STRUCT_FIELD_TAG
&& TREE_CODE (var) == NAME_MEMORY_TAG)
none_added &= !add_vars_for_offset (full_ref, al, offset, size,
flags & opf_def);
{
if (SFT_BASE_FOR_COMPONENTS_P (al))
{
/* If AL is the first SFT of a component, it can be used
to find other SFTs at [offset, size] adjacent to it. */
none_added &= !add_vars_for_offset (al, offset, size,
flags & opf_def);
}
else if ((unsigned HOST_WIDE_INT)offset < SFT_SIZE (al))
{
/* Otherwise, we only need to consider it if
[offset, size] overlaps with AL. */
if (flags & opf_def)
append_vdef (al);
else
append_vuse (al);
none_added = false;
}
}
else
{
/* Call-clobbered tags may have non-call-clobbered

View File

@ -4053,19 +4053,16 @@ sort_fieldstack (VEC(fieldoff_s,heap) *fieldstack)
TYPE.
ADDRESSABLE_TYPE is the type of the outermost object that could
have its address taken.
NESTING_LEVEL indicates whether TYPE is a structure nested inside
another, it starts at 0 and it is incremented by one on every
structure recursed into. */
have its address taken. */
int
push_fields_onto_fieldstack (tree type, VEC(fieldoff_s,heap) **fieldstack,
HOST_WIDE_INT offset, bool *has_union,
tree addressable_type, unsigned nesting_level)
tree addressable_type)
{
tree field;
int count = 0;
int first_element = VEC_length (fieldoff_s, *fieldstack);
if (TREE_CODE (type) == COMPLEX_TYPE)
{
@ -4076,6 +4073,7 @@ push_fields_onto_fieldstack (tree type, VEC(fieldoff_s,heap) **fieldstack,
real_part->offset = offset;
real_part->decl = NULL_TREE;
real_part->alias_set = -1;
real_part->base_for_components = false;
img_part = VEC_safe_push (fieldoff_s, heap, *fieldstack, NULL);
img_part->type = TREE_TYPE (type);
@ -4083,11 +4081,12 @@ push_fields_onto_fieldstack (tree type, VEC(fieldoff_s,heap) **fieldstack,
img_part->offset = offset + TREE_INT_CST_LOW (TYPE_SIZE (TREE_TYPE (type)));
img_part->decl = NULL_TREE;
img_part->alias_set = -1;
img_part->base_for_components = false;
return 2;
count = 2;
}
if (TREE_CODE (type) == ARRAY_TYPE)
else if (TREE_CODE (type) == ARRAY_TYPE)
{
tree sz = TYPE_SIZE (type);
tree elsz = TYPE_SIZE (TREE_TYPE (type));
@ -4125,8 +4124,7 @@ push_fields_onto_fieldstack (tree type, VEC(fieldoff_s,heap) **fieldstack,
has_union,
(TYPE_NONALIASED_COMPONENT (type)
? addressable_type
: TREE_TYPE (type)),
nesting_level + 1)))
: TREE_TYPE (type)))))
/* Empty structures may have actual size, like in C++. So
see if we didn't push any subfields and the size is
nonzero, push the field onto the stack */
@ -4145,64 +4143,69 @@ push_fields_onto_fieldstack (tree type, VEC(fieldoff_s,heap) **fieldstack,
pair->alias_set = get_alias_set (addressable_type);
else
pair->alias_set = -1;
pair->nesting_level = nesting_level;
pair->base_for_components = false;
count++;
}
else
count += pushed;
}
return count;
}
for (field = TYPE_FIELDS (type); field; field = TREE_CHAIN (field))
if (TREE_CODE (field) == FIELD_DECL)
{
bool push = false;
int pushed = 0;
if (has_union
&& (TREE_CODE (TREE_TYPE (field)) == QUAL_UNION_TYPE
|| TREE_CODE (TREE_TYPE (field)) == UNION_TYPE))
*has_union = true;
if (!var_can_have_subvars (field))
push = true;
else if (!(pushed = push_fields_onto_fieldstack
(TREE_TYPE (field),
fieldstack,
offset + bitpos_of_field (field),
has_union,
(DECL_NONADDRESSABLE_P (field)
? addressable_type
: TREE_TYPE (field)),
nesting_level + 1))
&& DECL_SIZE (field)
&& !integer_zerop (DECL_SIZE (field)))
/* Empty structures may have actual size, like in C++. So
see if we didn't push any subfields and the size is
nonzero, push the field onto the stack */
push = true;
if (push)
else
{
for (field = TYPE_FIELDS (type); field; field = TREE_CHAIN (field))
if (TREE_CODE (field) == FIELD_DECL)
{
fieldoff_s *pair;
bool push = false;
int pushed = 0;
pair = VEC_safe_push (fieldoff_s, heap, *fieldstack, NULL);
pair->type = TREE_TYPE (field);
pair->size = DECL_SIZE (field);
pair->decl = field;
pair->offset = offset + bitpos_of_field (field);
if (DECL_NONADDRESSABLE_P (field))
pair->alias_set = get_alias_set (addressable_type);
if (has_union
&& (TREE_CODE (TREE_TYPE (field)) == QUAL_UNION_TYPE
|| TREE_CODE (TREE_TYPE (field)) == UNION_TYPE))
*has_union = true;
if (!var_can_have_subvars (field))
push = true;
else if (!(pushed = push_fields_onto_fieldstack
(TREE_TYPE (field),
fieldstack,
offset + bitpos_of_field (field),
has_union,
(DECL_NONADDRESSABLE_P (field)
? addressable_type
: TREE_TYPE (field))))
&& DECL_SIZE (field)
&& !integer_zerop (DECL_SIZE (field)))
/* Empty structures may have actual size, like in C++. So
see if we didn't push any subfields and the size is
nonzero, push the field onto the stack */
push = true;
if (push)
{
fieldoff_s *pair;
pair = VEC_safe_push (fieldoff_s, heap, *fieldstack, NULL);
pair->type = TREE_TYPE (field);
pair->size = DECL_SIZE (field);
pair->decl = field;
pair->offset = offset + bitpos_of_field (field);
if (DECL_NONADDRESSABLE_P (field))
pair->alias_set = get_alias_set (addressable_type);
else
pair->alias_set = -1;
pair->base_for_components = false;
count++;
}
else
pair->alias_set = -1;
pair->nesting_level = nesting_level;
count++;
}
else
count += pushed;
}
count += pushed;
}
}
/* Make sure the first pushed field is marked as eligible for
being a base for component references. */
if (count > 0)
VEC_index (fieldoff_s, *fieldstack, first_element)->base_for_components = true;
return count;
}
@ -4397,7 +4400,7 @@ create_variable_info_for (tree decl, const char *name)
if (var_can_have_subvars (decl) && use_field_sensitive && !hasunion)
{
push_fields_onto_fieldstack (decltype, &fieldstack, 0, &hasunion,
decltype, 0);
decltype);
if (hasunion)
{
VEC_free (fieldoff_s, heap, fieldstack);
@ -4774,15 +4777,15 @@ set_uids_in_ptset (tree ptr, bitmap into, bitmap from, bool is_derefed,
{
bitmap_set_bit (into, DECL_UID (sft));
/* If SFT is inside a nested structure, it will
be needed by the operand scanner to adjust
offsets when adding operands to memory
/* Pointed-to SFTs are needed by the operand scanner
to adjust offsets when adding operands to memory
expressions that dereference PTR. This means
that memory partitioning may not partition
this SFT because the operand scanner will not
be able to find the other SFTs next to this
one. */
if (SFT_NESTING_LEVEL (sft) > 0)
one. But we only need to do this if the pointed
to type is aggregate. */
if (SFT_BASE_FOR_COMPONENTS_P (sft))
SFT_UNPARTITIONABLE_P (sft) = true;
}
}

View File

@ -2557,6 +2557,10 @@ struct tree_memory_tag GTY(())
/* True if this tag has global scope. */
unsigned int is_global : 1;
/* True if this tag is the first field of an aggregate type that
can be used to find adjacent SFTs belonging to the same aggregate. */
unsigned int base_for_components : 1;
/* True if this tag should not be grouped into a memory partition. */
unsigned int unpartitionable : 1;
};
@ -2579,23 +2583,17 @@ struct tree_struct_field_tag GTY(())
/* Alias set for a DECL_NONADDRESSABLE_P field. Otherwise -1. */
alias_set_type alias_set;
/* Nesting level for this subvariable. This indicates how many
structures are wrapping this field. Fields at the top level have
a nesting level of 0. */
unsigned int nesting_level;
};
#define SFT_PARENT_VAR(NODE) (STRUCT_FIELD_TAG_CHECK (NODE)->sft.parent_var)
#define SFT_OFFSET(NODE) (STRUCT_FIELD_TAG_CHECK (NODE)->sft.offset)
#define SFT_SIZE(NODE) (STRUCT_FIELD_TAG_CHECK (NODE)->sft.size)
#define SFT_NONADDRESSABLE_P(NODE) \
(STRUCT_FIELD_TAG_CHECK (NODE)->sft.alias_set != -1)
#define SFT_ALIAS_SET(NODE) (STRUCT_FIELD_TAG_CHECK (NODE)->sft.alias_set)
#define SFT_NESTING_LEVEL(NODE) \
(STRUCT_FIELD_TAG_CHECK (NODE)->sft.nesting_level)
#define SFT_UNPARTITIONABLE_P(NODE) \
(STRUCT_FIELD_TAG_CHECK (NODE)->sft.common.unpartitionable)
#define SFT_BASE_FOR_COMPONENTS_P(NODE) \
(STRUCT_FIELD_TAG_CHECK (NODE)->sft.common.base_for_components)
/* Memory Partition Tags (MPTs) group memory symbols under one
common name for the purposes of placing memory PHI nodes. */