aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
authorDaniel Berlin <dberlin@dbrelin.org>2006-02-15 22:09:45 +0000
committerDaniel Berlin <dberlin@dbrelin.org>2006-02-15 22:09:45 +0000
commit4c5244e6b28ea41a42ff1fe8d5480dab0da17f85 (patch)
treeda2b2114c7702693918635be6c7ae1407c8010c8 /gcc
parent41b719e746015327beb4fd82a7ca27cae8a44262 (diff)
2006-02-15 Daniel Berlin <dberlin@dberlin.org>
* tree.c (init_ttree): Add STRUCT_FIELD_TAG handling. (tree_code_size): Ditto. * tree.h (struct tree_memory_tag): Remove parent_var. (struct tree_struct_field_tag): New. (SFT_OFFSET): New. (SFT_SIZE): New. (union tree_node): Add sft member. * tree-ssa-alias.c (get_tmt_for): Don't handle TYPE_READONLY specially here. (create_sft): Add size and offset argument, set SFT_OFFSET and SFT_SIZE. (create_overlap_variables_for): Update for SFT_OFFSET/SFT_SIZE. * treestruct.def: Add TS_STRUCT_FIELD_TAG. * tree-flow-inline.h (get_subvar_at): Update for SFT_OFFSET/SFT_SIZE. (var_can_have_subvars): Ditto. (overlap_subvar): Ditto. * print-tree.c (print_node): Print out interesting things for SFT's. * tree-flow.h (struct subvar): Remove offset and size members. * tree-ssa-operands.c (get_expr_operands): Update for get_indirect_ref_operands changes. (get_indirect_ref_operands): Call add_virtual_operand instead of add_stmt_operand. Only recurse on base var if requested. (access_can_touch_variable): New function. (add_stmt_operand): Split virtual operand handling into ... (add_virtual_operand): Here. Add offset, size, and for_clobber arguments. Prune alias sets. (add_call_clobber_ops): Call add_virtual_operand. git-svn-id: https://gcc.gnu.org/svn/gcc/trunk@111120 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'gcc')
-rw-r--r--gcc/ChangeLog32
-rw-r--r--gcc/print-tree.c9
-rw-r--r--gcc/tree-flow-inline.h12
-rw-r--r--gcc/tree-flow.h8
-rw-r--r--gcc/tree-ssa-alias.c25
-rw-r--r--gcc/tree-ssa-operands.c388
-rw-r--r--gcc/tree.c5
-rw-r--r--gcc/tree.h21
-rw-r--r--gcc/treestruct.def1
9 files changed, 379 insertions, 122 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 9b388d6cf2b..50477ba7a2e 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,35 @@
+2006-02-15 Daniel Berlin <dberlin@dberlin.org>
+
+ * tree.c (init_ttree): Add STRUCT_FIELD_TAG handling.
+ (tree_code_size): Ditto.
+ * tree.h (struct tree_memory_tag): Remove parent_var.
+ (struct tree_struct_field_tag): New.
+ (SFT_OFFSET): New.
+ (SFT_SIZE): New.
+ (union tree_node): Add sft member.
+ * tree-ssa-alias.c (get_tmt_for): Don't handle TYPE_READONLY
+ specially here.
+ (create_sft): Add size and offset argument, set SFT_OFFSET and
+ SFT_SIZE.
+ (create_overlap_variables_for): Update for SFT_OFFSET/SFT_SIZE.
+ * treestruct.def: Add TS_STRUCT_FIELD_TAG.
+ * tree-flow-inline.h (get_subvar_at): Update for
+ SFT_OFFSET/SFT_SIZE.
+ (var_can_have_subvars): Ditto.
+ (overlap_subvar): Ditto.
+ * print-tree.c (print_node): Print out interesting things for
+ SFT's.
+ * tree-flow.h (struct subvar): Remove offset and size members.
+ * tree-ssa-operands.c (get_expr_operands): Update for
+ get_indirect_ref_operands changes.
+ (get_indirect_ref_operands): Call add_virtual_operand instead of
+ add_stmt_operand. Only recurse on base var if requested.
+ (access_can_touch_variable): New function.
+ (add_stmt_operand): Split virtual operand handling into ...
+ (add_virtual_operand): Here. Add offset, size, and for_clobber
+ arguments. Prune alias sets.
+ (add_call_clobber_ops): Call add_virtual_operand.
+
2006-02-15 Jakub Jelinek <jakub@redhat.com>
PR middle-end/26300
diff --git a/gcc/print-tree.c b/gcc/print-tree.c
index dad7e59e002..02e5c7b9c61 100644
--- a/gcc/print-tree.c
+++ b/gcc/print-tree.c
@@ -510,6 +510,15 @@ print_node (FILE *file, const char *prefix, tree node, int indent)
&& DECL_HAS_VALUE_EXPR_P (node))
print_node (file, "value-expr", DECL_VALUE_EXPR (node), indent + 4);
+ if (TREE_CODE (node) == STRUCT_FIELD_TAG)
+ {
+ fprintf (file, " sft size " HOST_WIDE_INT_PRINT_DEC,
+ SFT_SIZE (node));
+ fprintf (file, " sft offset " HOST_WIDE_INT_PRINT_DEC,
+ SFT_OFFSET (node));
+ print_node_brief (file, "parent var", SFT_PARENT_VAR (node),
+ indent + 4);
+ }
/* Print the decl chain only if decl is at second level. */
if (indent == 4)
print_node (file, "chain", TREE_CHAIN (node), indent + 4);
diff --git a/gcc/tree-flow-inline.h b/gcc/tree-flow-inline.h
index 1abf556fccf..6a37b863c4c 100644
--- a/gcc/tree-flow-inline.h
+++ b/gcc/tree-flow-inline.h
@@ -1450,7 +1450,7 @@ get_subvar_at (tree var, unsigned HOST_WIDE_INT offset)
subvar_t sv;
for (sv = get_subvars_for_var (var); sv; sv = sv->next)
- if (sv->offset == offset)
+ if (SFT_OFFSET (sv->var) == offset)
return sv->var;
return NULL_TREE;
@@ -1491,7 +1491,7 @@ var_can_have_subvars (tree v)
static inline bool
overlap_subvar (unsigned HOST_WIDE_INT offset, unsigned HOST_WIDE_INT size,
- subvar_t sv, bool *exact)
+ tree sv, bool *exact)
{
/* There are three possible cases of overlap.
1. We can have an exact overlap, like so:
@@ -1511,17 +1511,19 @@ overlap_subvar (unsigned HOST_WIDE_INT offset, unsigned HOST_WIDE_INT size,
if (exact)
*exact = false;
- if (offset == sv->offset && size == sv->size)
+ if (offset == SFT_OFFSET (sv) && size == SFT_SIZE (sv))
{
if (exact)
*exact = true;
return true;
}
- else if (offset >= sv->offset && offset < (sv->offset + sv->size))
+ else if (offset >= SFT_OFFSET (sv)
+ && offset < (SFT_OFFSET (sv) + SFT_SIZE (sv)))
{
return true;
}
- else if (offset < sv->offset && (size > sv->offset - offset))
+ else if (offset < SFT_OFFSET (sv)
+ && (size > SFT_OFFSET (sv) - offset))
{
return true;
}
diff --git a/gcc/tree-flow.h b/gcc/tree-flow.h
index 7774c3b42b7..864835b28c9 100644
--- a/gcc/tree-flow.h
+++ b/gcc/tree-flow.h
@@ -149,12 +149,6 @@ struct subvar GTY(())
/* Fake variable. */
tree var;
- /* Offset inside structure. */
- unsigned HOST_WIDE_INT offset;
-
- /* Size of the field. */
- unsigned HOST_WIDE_INT size;
-
/* Next subvar for this structure. */
subvar_t next;
};
@@ -610,7 +604,7 @@ extern tree get_ref_base_and_extent (tree, HOST_WIDE_INT *,
static inline bool var_can_have_subvars (tree);
static inline bool overlap_subvar (unsigned HOST_WIDE_INT,
unsigned HOST_WIDE_INT,
- subvar_t, bool *);
+ tree, bool *);
/* Call-back function for walk_use_def_chains(). At each reaching
definition, a function with this prototype is called. */
diff --git a/gcc/tree-ssa-alias.c b/gcc/tree-ssa-alias.c
index 75a5ae57674..b262fd0f0fd 100644
--- a/gcc/tree-ssa-alias.c
+++ b/gcc/tree-ssa-alias.c
@@ -2061,8 +2061,7 @@ get_tmt_for (tree ptr, struct alias_info *ai)
{
struct alias_map_d *curr = ai->pointers[i];
tree curr_tag = var_ann (curr->var)->type_mem_tag;
- if (tag_set == curr->set
- && TYPE_READONLY (tag_type) == TYPE_READONLY (TREE_TYPE (curr_tag)))
+ if (tag_set == curr->set)
{
tag = curr_tag;
break;
@@ -2099,10 +2098,6 @@ get_tmt_for (tree ptr, struct alias_info *ai)
pointed-to type. */
gcc_assert (tag_set == get_alias_set (tag));
- /* If PTR's pointed-to type is read-only, then TAG's type must also
- be read-only. */
- gcc_assert (TYPE_READONLY (tag_type) == TYPE_READONLY (TREE_TYPE (tag)));
-
return tag;
}
@@ -2749,11 +2744,12 @@ get_or_create_used_part_for (size_t uid)
}
-/* Create and return a structure sub-variable for field type FIELD of
- variable VAR. */
+/* Create and return a structure sub-variable for field type FIELD at
+ offset OFFSET, with size SIZE, of variable VAR. */
static tree
-create_sft (tree var, tree field)
+create_sft (tree var, tree field, unsigned HOST_WIDE_INT offset,
+ unsigned HOST_WIDE_INT size)
{
var_ann_t ann;
tree subvar = create_tag_raw (STRUCT_FIELD_TAG, field, "SFT");
@@ -2771,7 +2767,8 @@ create_sft (tree var, tree field)
ann->type_mem_tag = NULL;
add_referenced_tmp_var (subvar);
SFT_PARENT_VAR (subvar) = var;
-
+ SFT_OFFSET (subvar) = offset;
+ SFT_SIZE (subvar) = size;
return subvar;
}
@@ -2882,19 +2879,17 @@ create_overlap_variables_for (tree var)
&& currfotype == lastfotype))
continue;
sv = GGC_NEW (struct subvar);
- sv->offset = fo->offset;
- sv->size = fosize;
sv->next = *subvars;
- sv->var = create_sft (var, fo->type);
+ sv->var = create_sft (var, fo->type, fo->offset, fosize);
if (dump_file)
{
fprintf (dump_file, "structure field tag %s created for var %s",
get_name (sv->var), get_name (var));
fprintf (dump_file, " offset " HOST_WIDE_INT_PRINT_DEC,
- sv->offset);
+ SFT_OFFSET (sv->var));
fprintf (dump_file, " size " HOST_WIDE_INT_PRINT_DEC,
- sv->size);
+ SFT_SIZE (sv->var));
fprintf (dump_file, "\n");
}
diff --git a/gcc/tree-ssa-operands.c b/gcc/tree-ssa-operands.c
index fbee0b915e1..2d0e71cf372 100644
--- a/gcc/tree-ssa-operands.c
+++ b/gcc/tree-ssa-operands.c
@@ -128,7 +128,8 @@ static unsigned operand_memory_index;
static void get_expr_operands (tree, tree *, int);
static void get_asm_expr_operands (tree);
-static void get_indirect_ref_operands (tree, tree, int);
+static void get_indirect_ref_operands (tree, tree, int, tree, HOST_WIDE_INT,
+ HOST_WIDE_INT, bool);
static void get_tmr_operands (tree, tree, int);
static void get_call_expr_operands (tree, tree);
static inline void append_def (tree *);
@@ -138,6 +139,9 @@ static void append_v_must_def (tree);
static void add_call_clobber_ops (tree, tree);
static void add_call_read_ops (tree, tree);
static void add_stmt_operand (tree *, stmt_ann_t, int);
+static void add_virtual_operand (tree, stmt_ann_t, int, tree,
+ HOST_WIDE_INT, HOST_WIDE_INT,
+ bool);
static void build_ssa_operands (tree stmt);
static def_optype_p free_defs = NULL;
@@ -1123,7 +1127,8 @@ get_expr_operands (tree stmt, tree *expr_p, int flags)
case ALIGN_INDIRECT_REF:
case INDIRECT_REF:
- get_indirect_ref_operands (stmt, expr, flags);
+ get_indirect_ref_operands (stmt, expr, flags, NULL_TREE,
+ 0, -1, true);
return;
case TARGET_MEM_REF:
@@ -1165,7 +1170,7 @@ get_expr_operands (tree stmt, tree *expr_p, int flags)
for (sv = svars; sv; sv = sv->next)
{
bool exact;
- if (overlap_subvar (offset, maxsize, sv, &exact))
+ if (overlap_subvar (offset, maxsize, sv->var, &exact))
{
int subvar_flags = flags;
none = false;
@@ -1178,6 +1183,12 @@ get_expr_operands (tree stmt, tree *expr_p, int flags)
if (!none)
flags |= opf_no_vops;
}
+ else if (TREE_CODE (ref) == INDIRECT_REF)
+ {
+ get_indirect_ref_operands (stmt, ref, flags, expr,
+ offset, maxsize, false);
+ flags |= opf_no_vops;
+ }
/* Even if we found subvars above we need to ensure to see
immediate uses for d in s.a[d]. In case of s.a having
@@ -1416,10 +1427,24 @@ get_asm_expr_operands (tree stmt)
}
/* A subroutine of get_expr_operands to handle INDIRECT_REF,
- ALIGN_INDIRECT_REF and MISALIGNED_INDIRECT_REF. */
+ ALIGN_INDIRECT_REF and MISALIGNED_INDIRECT_REF.
+ STMT is the statement being processed, EXPR is the INDIRECT_REF
+ that got us here. FLAGS is as in get_expr_operands.
+ FULL_REF contains the full pointer dereference expression, if we
+ have it, or NULL otherwise.
+ OFFSET and SIZE are the location of the access inside the
+ dereferenced pointer, if known.
+ RECURSE_ON_BASE should be set to true if we want to continue
+ calling get_expr_operands on the base pointer, and false if
+ something else will do it for us.
+
+*/
static void
-get_indirect_ref_operands (tree stmt, tree expr, int flags)
+get_indirect_ref_operands (tree stmt, tree expr, int flags,
+ tree full_ref,
+ HOST_WIDE_INT offset, HOST_WIDE_INT size,
+ bool recurse_on_base)
{
tree *pptr = &TREE_OPERAND (expr, 0);
tree ptr = *pptr;
@@ -1438,7 +1463,8 @@ get_indirect_ref_operands (tree stmt, tree expr, int flags)
&& pi->name_mem_tag)
{
/* PTR has its own memory tag. Use it. */
- add_stmt_operand (&pi->name_mem_tag, s_ann, flags);
+ add_virtual_operand (pi->name_mem_tag, s_ann, flags,
+ full_ref, offset, size, false);
}
else
{
@@ -1464,8 +1490,10 @@ get_indirect_ref_operands (tree stmt, tree expr, int flags)
if (TREE_CODE (ptr) == SSA_NAME)
ptr = SSA_NAME_VAR (ptr);
v_ann = var_ann (ptr);
+
if (v_ann->type_mem_tag)
- add_stmt_operand (&v_ann->type_mem_tag, s_ann, flags);
+ add_virtual_operand (v_ann->type_mem_tag, s_ann, flags,
+ full_ref, offset, size, false);
}
}
@@ -1483,7 +1511,8 @@ get_indirect_ref_operands (tree stmt, tree expr, int flags)
gcc_unreachable ();
/* Add a USE operand for the base pointer. */
- get_expr_operands (stmt, pptr, opf_none);
+ if (recurse_on_base)
+ get_expr_operands (stmt, pptr, opf_none);
}
/* A subroutine of get_expr_operands to handle TARGET_MEM_REF. */
@@ -1528,7 +1557,7 @@ get_tmr_operands (tree stmt, tree expr, int flags)
for (sv = svars; sv; sv = sv->next)
{
bool exact;
- if (overlap_subvar (offset, maxsize, sv, &exact))
+ if (overlap_subvar (offset, maxsize, sv->var, &exact))
{
int subvar_flags = flags;
if (!exact || size != maxsize)
@@ -1580,30 +1609,151 @@ get_call_expr_operands (tree stmt, tree expr)
}
+/* REF is a tree that contains the entire pointer dereference
+ 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.
+ FOR_CLOBBER is true is this is adding a virtual operand for a call
+ clobber. */
+
+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 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
+ to a type that is the same as SFT_PARENT_VAR. Otherwise, we may
+ be accessing through a pointer to some substruct of the
+ structure, and if we try to prune there, we will have the wrong
+ offset, and get the wrong answer.
+ i.e., we can't prune without more work if we have something like
+ struct gcc_target
+ {
+ struct asm_out
+ {
+ const char *byte_op;
+ struct asm_int_op
+ {
+ const char *hi;
+ } aligned_op;
+ } asm_out;
+ } targetm;
+
+ foo = &targetm.asm_out.aligned_op;
+ return foo->hi;
+
+ SFT.1, which represents hi, will have SFT_OFFSET=32 because in
+ terms of SFT_PARENT_VAR, that is where it is.
+ However, the access through the foo pointer will be at offset 0.
+ */
+ if (size != -1
+ && TREE_CODE (alias) == STRUCT_FIELD_TAG
+ && base
+ && TREE_TYPE (base) == TREE_TYPE (SFT_PARENT_VAR (alias))
+ && !overlap_subvar (offset, size, alias, NULL))
+ {
+#ifdef ACCESS_DEBUGGING
+ fprintf (stderr, "Access to ");
+ print_generic_expr (stderr, ref, 0);
+ fprintf (stderr, " may not touch ");
+ print_generic_expr (stderr, alias, 0);
+ fprintf (stderr, " in function %s\n", get_name (current_function_decl));
+#endif
+ return false;
+ }
+ /* Without strict aliasing, it is impossible for a component access
+ through a pointer to touch a random variable, unless that
+ variable *is* a structure or a pointer.
-/* Add *VAR_P to the appropriate operand array for INFO. FLAGS is as in
- get_expr_operands. If *VAR_P is a GIMPLE register, it will be added to
- the statement's real operands, otherwise it is added to virtual
- operands. */
+
+ IE given p->c, and some random global variable b,
+ there is no legal way that p->c could be an access to b.
+
+ Without strict aliasing on, we consider it legal to do something
+ like:
+ struct foos { int l; };
+ int foo;
+ static struct foos *getfoo(void);
+ int main (void)
+ {
+ struct foos *f = getfoo();
+ f->l = 1;
+ foo = 2;
+ if (f->l == 1)
+ abort();
+ exit(0);
+ }
+ static struct foos *getfoo(void)
+ { return (struct foos *)&foo; }
+
+ (taken from 20000623-1.c)
+ */
+ else if (ref
+ && flag_strict_aliasing
+ && TREE_CODE (ref) != INDIRECT_REF
+ && !MTAG_P (alias)
+ && !AGGREGATE_TYPE_P (TREE_TYPE (alias))
+ && !TREE_CODE (TREE_TYPE (alias)) == COMPLEX_TYPE
+ && !POINTER_TYPE_P (TREE_TYPE (alias)))
+ {
+#ifdef ACCESS_DEBUGGING
+ fprintf (stderr, "Access to ");
+ print_generic_expr (stderr, ref, 0);
+ fprintf (stderr, " may not touch ");
+ print_generic_expr (stderr, alias, 0);
+ fprintf (stderr, " in function %s\n", get_name (current_function_decl));
+#endif
+ return false;
+ }
+ /* 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))
+ && offsetgtz
+ && DECL_SIZE (alias)
+ && TREE_CODE (DECL_SIZE (alias)) == INTEGER_CST
+ && uoffset > TREE_INT_CST_LOW (DECL_SIZE (alias)))
+ {
+#ifdef ACCESS_DEBUGGING
+ fprintf (stderr, "Access to ");
+ print_generic_expr (stderr, ref, 0);
+ fprintf (stderr, " may not touch ");
+ print_generic_expr (stderr, alias, 0);
+ fprintf (stderr, " in function %s\n", get_name (current_function_decl));
+#endif
+ return false;
+ }
+ return true;
+}
-static void
-add_stmt_operand (tree *var_p, stmt_ann_t s_ann, int flags)
+/* Add VAR to the virtual operands array. FLAGS is as in
+ get_expr_operands. FULL_REF is a tree that contains the entire
+ pointer dereference expression, if available, or NULL otherwise.
+ OFFSET and SIZE come from the memory access expression that
+ generated this virtual operand. FOR_CLOBBER is true is this is
+ adding a virtual operand for a call clobber. */
+
+static void
+add_virtual_operand (tree var, stmt_ann_t s_ann, int flags,
+ tree full_ref, HOST_WIDE_INT offset,
+ HOST_WIDE_INT size, bool for_clobber)
{
- bool is_real_op;
- tree var, sym;
+ VEC(tree,gc) *aliases;
+ tree sym;
var_ann_t v_ann;
-
- var = *var_p;
- gcc_assert (SSA_VAR_P (var));
-
- is_real_op = is_gimple_reg (var);
- /* If this is a real operand, the operand is either ssa name or decl.
- Virtual operands may only be decls. */
- gcc_assert (is_real_op || DECL_P (var));
-
+
sym = (TREE_CODE (var) == SSA_NAME ? SSA_NAME_VAR (var) : var);
v_ann = var_ann (sym);
-
+
/* Mark statements with volatile operands. Optimizers should back
off from statements having volatile operands. */
if (TREE_THIS_VOLATILE (sym) && s_ann)
@@ -1623,93 +1773,146 @@ add_stmt_operand (tree *var_p, stmt_ann_t s_ann, int flags)
at runtime, then the program is ill formed. If the statement is
not executed then all is well. At the very least, we cannot ICE. */
if ((flags & opf_non_specific) && unmodifiable_var_p (var))
- {
- gcc_assert (!is_real_op);
- flags &= ~(opf_is_def | opf_kill_def);
- }
+ flags &= ~(opf_is_def | opf_kill_def);
+
- if (is_real_op)
+ /* The variable is not a GIMPLE register. Add it (or its aliases) to
+ virtual operands, unless the caller has specifically requested
+ not to add virtual operands (used when adding operands inside an
+ ADDR_EXPR expression). */
+ if (flags & opf_no_vops)
+ return;
+
+ aliases = v_ann->may_aliases;
+ if (aliases == NULL)
{
- /* The variable is a GIMPLE register. Add it to real operands. */
+ /* The variable is not aliased or it is an alias tag. */
if (flags & opf_is_def)
- append_def (var_p);
+ {
+ if (flags & opf_kill_def)
+ {
+ /* Only regular variables or struct fields may get a
+ V_MUST_DEF operand. */
+ gcc_assert (!MTAG_P (var)
+ || TREE_CODE (var) == STRUCT_FIELD_TAG);
+ /* V_MUST_DEF for non-aliased, non-GIMPLE register
+ variable definitions. */
+ append_v_must_def (var);
+ }
+ else
+ {
+ /* Add a V_MAY_DEF for call-clobbered variables and
+ memory tags. */
+ append_v_may_def (var);
+ }
+ }
else
- append_use (var_p);
+ append_vuse (var);
}
else
{
- VEC(tree,gc) *aliases;
-
- /* The variable is not a GIMPLE register. Add it (or its aliases) to
- virtual operands, unless the caller has specifically requested
- not to add virtual operands (used when adding operands inside an
- ADDR_EXPR expression). */
- if (flags & opf_no_vops)
- return;
+ unsigned i;
+ tree al;
+
+ /* The variable is aliased. Add its aliases to the virtual
+ operands. */
+ gcc_assert (VEC_length (tree, aliases) != 0);
+
+ if (flags & opf_is_def)
+ {
+
+ bool none_added = true;
- aliases = v_ann->may_aliases;
+ for (i = 0; VEC_iterate (tree, aliases, i, al); i++)
+ {
+ if (!access_can_touch_variable (full_ref, al, offset, size))
+ continue;
+
+ none_added = false;
+ append_v_may_def (al);
+ }
- if (aliases == NULL)
- {
- /* The variable is not aliased or it is an alias tag. */
- if (flags & opf_is_def)
+ /* If the variable is also an alias tag, add a virtual
+ operand for it, otherwise we will miss representing
+ references to the members of the variable's alias set.
+ This fixes the bug in gcc.c-torture/execute/20020503-1.c.
+
+ It is also necessary to add bare defs on clobbers for
+ TMT's, so that bare TMT uses caused by pruning all the
+ aliases will link up properly with calls. */
+ if (v_ann->is_alias_tag || none_added
+ || (TREE_CODE (var) == TYPE_MEMORY_TAG && for_clobber))
{
- if (flags & opf_kill_def)
- {
- /* Only regular variables or struct fields may get a
- V_MUST_DEF operand. */
- gcc_assert (!MTAG_P (var)
- || TREE_CODE (var) == STRUCT_FIELD_TAG);
- /* V_MUST_DEF for non-aliased, non-GIMPLE register
- variable definitions. */
- append_v_must_def (var);
- }
- else
- {
- /* Add a V_MAY_DEF for call-clobbered variables and
- memory tags. */
- append_v_may_def (var);
- }
+ /* We should never end up with adding no aliases of an
+ NMT, as that would imply we got the set wrong. */
+ gcc_assert (!(none_added && TREE_CODE (var) == NAME_MEMORY_TAG));
+
+ append_v_may_def (var);
}
- else
- append_vuse (var);
}
else
{
- unsigned i;
- tree al;
-
- /* The variable is aliased. Add its aliases to the virtual
- operands. */
- gcc_assert (VEC_length (tree, aliases) != 0);
-
- if (flags & opf_is_def)
+ bool none_added = true;
+ for (i = 0; VEC_iterate (tree, aliases, i, al); i++)
{
- /* If the variable is also an alias tag, add a virtual
- operand for it, otherwise we will miss representing
- references to the members of the variable's alias set.
- This fixes the bug in gcc.c-torture/execute/20020503-1.c. */
- if (v_ann->is_alias_tag)
- append_v_may_def (var);
-
- for (i = 0; VEC_iterate (tree, aliases, i, al); i++)
- append_v_may_def (al);
+ if (!access_can_touch_variable (full_ref, al, offset, size))
+ continue;
+ none_added = false;
+ append_vuse (al);
}
- else
+
+ /* Similarly, append a virtual uses for VAR itself, when
+ it is an alias tag. */
+ if (v_ann->is_alias_tag || none_added)
{
- /* Similarly, append a virtual uses for VAR itself, when
- it is an alias tag. */
- if (v_ann->is_alias_tag)
- append_vuse (var);
+ gcc_assert (!(none_added && TREE_CODE (var) == NAME_MEMORY_TAG));
- for (i = 0; VEC_iterate (tree, aliases, i, al); i++)
- append_vuse (al);
+ append_vuse (var);
}
}
}
}
-
+/* Add *VAR_P to the appropriate operand array for INFO. FLAGS is as in
+ get_expr_operands. If *VAR_P is a GIMPLE register, it will be added to
+ the statement's real operands, otherwise it is added to virtual
+ operands. */
+
+static void
+add_stmt_operand (tree *var_p, stmt_ann_t s_ann, int flags)
+{
+ bool is_real_op;
+ tree var, sym;
+ var_ann_t v_ann;
+
+ var = *var_p;
+ gcc_assert (SSA_VAR_P (var));
+
+ is_real_op = is_gimple_reg (var);
+ /* If this is a real operand, the operand is either ssa name or decl.
+ Virtual operands may only be decls. */
+ gcc_assert (is_real_op || DECL_P (var));
+
+ sym = (TREE_CODE (var) == SSA_NAME ? SSA_NAME_VAR (var) : var);
+ v_ann = var_ann (sym);
+
+ /* Mark statements with volatile operands. Optimizers should back
+ off from statements having volatile operands. */
+ if (TREE_THIS_VOLATILE (sym) && s_ann)
+ s_ann->has_volatile_ops = true;
+
+ if (is_real_op)
+ {
+ /* The variable is a GIMPLE register. Add it to real operands. */
+ if (flags & opf_is_def)
+ append_def (var_p);
+ else
+ append_use (var_p);
+ }
+ else
+ add_virtual_operand (var, s_ann, flags, NULL_TREE, 0, -1, false);
+}
+
/* Add the base address of REF to the set *ADDRESSES_TAKEN. If
*ADDRESSES_TAKEN is NULL, a new set is created. REF may be
a single variable whose address has been taken or any other valid
@@ -1836,7 +2039,8 @@ add_call_clobber_ops (tree stmt, tree callee)
clobber_stats.static_read_clobbers_avoided++;
}
else
- add_stmt_operand (&var, s_ann, opf_is_def);
+ add_virtual_operand (var, s_ann, opf_is_def,
+ NULL, 0, -1, true);
}
}
diff --git a/gcc/tree.c b/gcc/tree.c
index d66e0c63d6f..0a3d6069058 100644
--- a/gcc/tree.c
+++ b/gcc/tree.c
@@ -276,6 +276,8 @@ init_ttree (void)
tree_contains_struct[NAME_MEMORY_TAG][TS_MEMORY_TAG] = 1;
tree_contains_struct[TYPE_MEMORY_TAG][TS_MEMORY_TAG] = 1;
+ tree_contains_struct[STRUCT_FIELD_TAG][TS_STRUCT_FIELD_TAG] = 1;
+
tree_contains_struct[VAR_DECL][TS_DECL_WITH_VIS] = 1;
tree_contains_struct[FUNCTION_DECL][TS_DECL_WITH_VIS] = 1;
tree_contains_struct[TYPE_DECL][TS_DECL_WITH_VIS] = 1;
@@ -335,8 +337,9 @@ tree_code_size (enum tree_code code)
return sizeof (struct tree_function_decl);
case NAME_MEMORY_TAG:
case TYPE_MEMORY_TAG:
- case STRUCT_FIELD_TAG:
return sizeof (struct tree_memory_tag);
+ case STRUCT_FIELD_TAG:
+ return sizeof (struct tree_struct_field_tag);
default:
return sizeof (struct tree_decl_non_common);
}
diff --git a/gcc/tree.h b/gcc/tree.h
index e89389dea56..f0cb29d0565 100644
--- a/gcc/tree.h
+++ b/gcc/tree.h
@@ -2309,12 +2309,28 @@ struct tree_decl_minimal GTY(())
struct tree_memory_tag GTY(())
{
struct tree_decl_minimal common;
- tree parent_var;
unsigned int is_global:1;
};
#define MTAG_GLOBAL(NODE) (TREE_MEMORY_TAG_CHECK (NODE)->mtag.is_global)
-#define SFT_PARENT_VAR(NODE) (STRUCT_FIELD_TAG_CHECK (NODE)->mtag.parent_var)
+
+struct tree_struct_field_tag GTY(())
+{
+ struct tree_memory_tag common;
+
+ /* Parent variable. */
+ tree parent_var;
+
+ /* Offset inside structure. */
+ unsigned HOST_WIDE_INT offset;
+
+ /* Size of the field. */
+ unsigned HOST_WIDE_INT size;
+
+};
+#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)
/* For any sort of a ..._DECL node, this points to the original (abstract)
decl node which this decl is an instance of, or else it is NULL indicating
@@ -3124,6 +3140,7 @@ union tree_node GTY ((ptr_alias (union lang_tree_node),
struct tree_value_handle GTY ((tag ("TS_VALUE_HANDLE"))) value_handle;
struct tree_constructor GTY ((tag ("TS_CONSTRUCTOR"))) constructor;
struct tree_memory_tag GTY ((tag ("TS_MEMORY_TAG"))) mtag;
+ struct tree_struct_field_tag GTY ((tag ("TS_STRUCT_FIELD_TAG"))) sft;
struct tree_omp_clause GTY ((tag ("TS_OMP_CLAUSE"))) omp_clause;
};
diff --git a/gcc/treestruct.def b/gcc/treestruct.def
index 3131d4be1d9..b826be65242 100644
--- a/gcc/treestruct.def
+++ b/gcc/treestruct.def
@@ -60,4 +60,5 @@ DEFTREESTRUCT(TS_STATEMENT_LIST, "statement list")
DEFTREESTRUCT(TS_VALUE_HANDLE, "value handle")
DEFTREESTRUCT(TS_CONSTRUCTOR, "constructor")
DEFTREESTRUCT(TS_MEMORY_TAG, "memory tag")
+DEFTREESTRUCT(TS_STRUCT_FIELD_TAG, "struct field tag")
DEFTREESTRUCT(TS_OMP_CLAUSE, "omp clause")