tree.c (init_ttree): Add STRUCT_FIELD_TAG handling.

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.

From-SVN: r111120
This commit is contained in:
Daniel Berlin 2006-02-15 22:09:45 +00:00 committed by Daniel Berlin
parent cce283c7fe
commit 3c0b6c4300
9 changed files with 387 additions and 130 deletions

View File

@ -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

View File

@ -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);

View File

@ -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;
}

View File

@ -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. */

View File

@ -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");
}

View File

@ -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,6 +1609,269 @@ 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.
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;
}
/* 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)
{
VEC(tree,gc) *aliases;
tree sym;
var_ann_t v_ann;
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 the variable cannot be modified and this is a V_MAY_DEF change
it into a VUSE. This happens when read-only variables are marked
call-clobbered and/or aliased to writable variables. So we only
check that this only happens on non-specific stores.
Note that if this is a specific store, i.e. associated with a
modify_expr, then we can't suppress the V_DEF, lest we run into
validation problems.
This can happen when programs cast away const, leaving us with a
store to read-only memory. If the statement is actually executed
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))
flags &= ~(opf_is_def | opf_kill_def);
/* 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 not aliased or it is an alias tag. */
if (flags & opf_is_def)
{
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_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 (!access_can_touch_variable (full_ref, al, offset, size))
continue;
none_added = false;
append_v_may_def (al);
}
/* 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))
{
/* 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
{
bool none_added = true;
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_vuse (al);
}
/* Similarly, append a virtual uses for VAR itself, when
it is an alias tag. */
if (v_ann->is_alias_tag || none_added)
{
gcc_assert (!(none_added && TREE_CODE (var) == NAME_MEMORY_TAG));
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
@ -1609,25 +1901,6 @@ add_stmt_operand (tree *var_p, stmt_ann_t s_ann, int flags)
if (TREE_THIS_VOLATILE (sym) && s_ann)
s_ann->has_volatile_ops = true;
/* If the variable cannot be modified and this is a V_MAY_DEF change
it into a VUSE. This happens when read-only variables are marked
call-clobbered and/or aliased to writable variables. So we only
check that this only happens on non-specific stores.
Note that if this is a specific store, i.e. associated with a
modify_expr, then we can't suppress the V_DEF, lest we run into
validation problems.
This can happen when programs cast away const, leaving us with a
store to read-only memory. If the statement is actually executed
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);
}
if (is_real_op)
{
/* The variable is a GIMPLE register. Add it to real operands. */
@ -1637,79 +1910,9 @@ add_stmt_operand (tree *var_p, stmt_ann_t s_ann, int flags)
append_use (var_p);
}
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;
aliases = v_ann->may_aliases;
if (aliases == NULL)
{
/* The variable is not aliased or it is an alias tag. */
if (flags & opf_is_def)
{
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_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)
{
/* 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);
}
else
{
/* Similarly, append a virtual uses for VAR itself, when
it is an alias tag. */
if (v_ann->is_alias_tag)
append_vuse (var);
for (i = 0; VEC_iterate (tree, aliases, i, al); i++)
append_vuse (al);
}
}
}
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);
}
}

View File

@ -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);
}

View File

@ -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;
};

View File

@ -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")