Makefile.in (tree-ssa-alias.o): Depend on tree-ssa-structalias.h

* Makefile.in (tree-ssa-alias.o): Depend on tree-ssa-structalias.h
	* tree-cfg.c (CHECK_OP): Only test for is_gimple_val.
	* tree-dfa.c (dump_subvars_for): New.
	(debug_subvars_for): New.
	(dump_variable): Show subvariables if VAR has them.
	* tree-flow-inline.h (get_subvar_at): New.
	(overlap_subvar): Change offset and size to unsigned HOST_WIDE_INT.
	* tree-flow.h (struct ptr_info_def): Remove field pt_malloc.
	Update all users.
	(struct subvar): Change fields offset and size to unsigned
	HOST_WIDE_INT.
	(dump_subvars_for): Declare.
	(debug_subvars_for): Declare.
	(get_subvar_at): Declare.
	(okay_component_ref_for_subvars): Change 2nd and 3rd argument
	to unsigned HOST_WIDE_INT *.
	(overlap_subvar): Likewise.
	* tree-gimple.c (is_gimple_reg): Always return false for
	SFTs and memory tags.
	* tree-pass.h (pass_build_pta, pass_del_pta): Remove.
	Update all callers.
	* tree-ssa-alias.c: Include tree-ssa-structalias.h.
	(compute_may_aliases): Call compute_points_to_sets.
	(collect_points_to_info_for): Remove.
	(compute_points_to_and_addr_escape): Remove.
	(delete_alias_info): Call delete_points_to_sets.
	(compute_flow_sensitive_aliasing): If the call to
	find_what_p_points_to returns false, call set_pt_anything.
	(add_may_alias): Set TREE_ADDRESSABLE when adding a new alias.
	(set_pt_anything): Clear pi->pt_vars.
	(set_pt_malloc): Remove.
	(merge_pointed_to_info): Remove.
	(add_pointed_to_expr): Remove.
	(add_pointed_to_var): Remove.
	(collect_points_to_info_r): Remove.
	(is_escape_site): Make extern.
	(create_sft): New.
	(create_overlap_variables_for): Call it.
	* tree-ssa-copy.c (merge_alias_info): Never merge
	flow-sensitive alias information.
	* tree-ssa-operands.c (get_expr_operands): Adjust variables
	offset and size to be unsigned HOST_WIDE_INT.
	(add_to_addressable_set): Rename from note_addressable.
	Set TREE_ADDRESSABLE as the variables are added to the set.
	Update all users.
	(add_stmt_operand): Do not try to micro-optimize unmodifiable
	operands into VUSEs when adding V_MAY_DEFs for members in an
	alias set.
	* tree-ssa-operands.h (add_to_addressable_set): Declare.
	* tree-ssa-structalias.c: Include tree-ssa-structalias.h last.
	(struct variable_info): Add bitfield is_heap_var.
	(var_anyoffset, anyoffset_tree, anyoffset_id): Declare.
	(new_var_info): Initialize is_heap_var.
	(get_constraint_for): Add HEAP variables to the symbol table.
	Mark them with is_heap_var.
	(update_alias_info): New.  Taken mostly from the old
	compute_points_to_and_addr_escape.
	(handle_ptr_arith): New.
	(find_func_aliases): Call update_alias_info.
	Call handle_ptr_info for tcc_binary expressions.
	Call mark_stmt_modified.
	(create_variable_info_for): If DECL has subvars, do not create
	variables for its subvars.  Always add all the fields.
	(set_uids_in_ptset): If the solution includes ANYOFFSET and
	SFTs, then add all the SFTs of the structure.
	If VI->DECL is an aggregate with subvariables, add the SFT at
	VI->OFFSET.
	(find_what_p_points_to): If VI is an artificial variable,
	translate to bitfields in SSA_NAME_PTR_INFO.
	If the solution is empty, set pi->pt_vars to NULL
	(init_base_vars): Create ANYOFFSET.
	(compute_points_to_sets): Rename from create_alias_vars.
	Make extern.
	(pass_build_pta): Remove.
	(delete_points_to_sets): Rename from delete_alias_vars.
	(pass_del_pta): Remove.
	* tree-ssa-structalias.h (struct alias_info): Move from
	tree-ssa-alias.h.
	(NUM_REFERENCES, NUM_REFERENCES_CLEAR, NUM_REFERENCES_INC,
	NUM_REFERENCES_SET): Likewise.
	(compute_points_to_sets, delete_points_to_sets): Declare.

testsuite/ChangeLog

	* gcc.dg/tree-ssa/pta-fp.c: Use -fdump-tree-alias1.

From-SVN: r101841
This commit is contained in:
Diego Novillo 2005-07-10 00:28:01 +00:00 committed by Diego Novillo
parent 87f8dcd06e
commit e8ca415995
18 changed files with 818 additions and 935 deletions

View File

@ -1,3 +1,87 @@
2005-07-09 Diego Novillo <dnovillo@redhat.com>
* Makefile.in (tree-ssa-alias.o): Depend on tree-ssa-structalias.h
* tree-cfg.c (CHECK_OP): Only test for is_gimple_val.
* tree-dfa.c (dump_subvars_for): New.
(debug_subvars_for): New.
(dump_variable): Show subvariables if VAR has them.
* tree-flow-inline.h (get_subvar_at): New.
(overlap_subvar): Change offset and size to unsigned HOST_WIDE_INT.
* tree-flow.h (struct ptr_info_def): Remove field pt_malloc.
Update all users.
(struct subvar): Change fields offset and size to unsigned
HOST_WIDE_INT.
(dump_subvars_for): Declare.
(debug_subvars_for): Declare.
(get_subvar_at): Declare.
(okay_component_ref_for_subvars): Change 2nd and 3rd argument
to unsigned HOST_WIDE_INT *.
(overlap_subvar): Likewise.
* tree-gimple.c (is_gimple_reg): Always return false for
SFTs and memory tags.
* tree-pass.h (pass_build_pta, pass_del_pta): Remove.
Update all callers.
* tree-ssa-alias.c: Include tree-ssa-structalias.h.
(compute_may_aliases): Call compute_points_to_sets.
(collect_points_to_info_for): Remove.
(compute_points_to_and_addr_escape): Remove.
(delete_alias_info): Call delete_points_to_sets.
(compute_flow_sensitive_aliasing): If the call to
find_what_p_points_to returns false, call set_pt_anything.
(add_may_alias): Set TREE_ADDRESSABLE when adding a new alias.
(set_pt_anything): Clear pi->pt_vars.
(set_pt_malloc): Remove.
(merge_pointed_to_info): Remove.
(add_pointed_to_expr): Remove.
(add_pointed_to_var): Remove.
(collect_points_to_info_r): Remove.
(is_escape_site): Make extern.
(create_sft): New.
(create_overlap_variables_for): Call it.
* tree-ssa-copy.c (merge_alias_info): Never merge
flow-sensitive alias information.
* tree-ssa-operands.c (get_expr_operands): Adjust variables
offset and size to be unsigned HOST_WIDE_INT.
(add_to_addressable_set): Rename from note_addressable.
Set TREE_ADDRESSABLE as the variables are added to the set.
Update all users.
(add_stmt_operand): Do not try to micro-optimize unmodifiable
operands into VUSEs when adding V_MAY_DEFs for members in an
alias set.
* tree-ssa-operands.h (add_to_addressable_set): Declare.
* tree-ssa-structalias.c: Include tree-ssa-structalias.h last.
(struct variable_info): Add bitfield is_heap_var.
(var_anyoffset, anyoffset_tree, anyoffset_id): Declare.
(new_var_info): Initialize is_heap_var.
(get_constraint_for): Add HEAP variables to the symbol table.
Mark them with is_heap_var.
(update_alias_info): New. Taken mostly from the old
compute_points_to_and_addr_escape.
(handle_ptr_arith): New.
(find_func_aliases): Call update_alias_info.
Call handle_ptr_info for tcc_binary expressions.
Call mark_stmt_modified.
(create_variable_info_for): If DECL has subvars, do not create
variables for its subvars. Always add all the fields.
(set_uids_in_ptset): If the solution includes ANYOFFSET and
SFTs, then add all the SFTs of the structure.
If VI->DECL is an aggregate with subvariables, add the SFT at
VI->OFFSET.
(find_what_p_points_to): If VI is an artificial variable,
translate to bitfields in SSA_NAME_PTR_INFO.
If the solution is empty, set pi->pt_vars to NULL
(init_base_vars): Create ANYOFFSET.
(compute_points_to_sets): Rename from create_alias_vars.
Make extern.
(pass_build_pta): Remove.
(delete_points_to_sets): Rename from delete_alias_vars.
(pass_del_pta): Remove.
* tree-ssa-structalias.h (struct alias_info): Move from
tree-ssa-alias.h.
(NUM_REFERENCES, NUM_REFERENCES_CLEAR, NUM_REFERENCES_INC,
NUM_REFERENCES_SET): Likewise.
(compute_points_to_sets, delete_points_to_sets): Declare.
2005-07-09 Richard Henderson <rth@redhat.com>
* config/alpha/alpha.c (emit_insxl, alpha_expand_compare_and_swap_12,

View File

@ -1895,7 +1895,7 @@ tree-ssa-alias.o : tree-ssa-alias.c $(TREE_FLOW_H) $(CONFIG_H) $(SYSTEM_H) \
$(RTL_H) $(TREE_H) $(TM_P_H) $(EXPR_H) $(GGC_H) tree-inline.h $(FLAGS_H) \
function.h $(TIMEVAR_H) convert.h $(TM_H) coretypes.h langhooks.h \
$(TREE_DUMP_H) tree-pass.h $(PARAMS_H) $(BASIC_BLOCK_H) $(DIAGNOSTIC_H) \
hard-reg-set.h $(TREE_GIMPLE_H) vec.h
hard-reg-set.h $(TREE_GIMPLE_H) vec.h tree-ssa-structalias.h
tree-ssa-reassoc.o : tree-ssa-reassoc.c $(TREE_FLOW_H) $(CONFIG_H) \
$(SYSTEM_H) $(TREE_H) $(GGC_H) $(DIAGNOSTIC_H) errors.h $(TIMEVAR_H) \
$(TM_H) coretypes.h $(TREE_DUMP_H) tree-pass.h $(FLAGS_H) tree-iterator.h\

View File

@ -471,10 +471,8 @@ init_optimization_passes (void)
NEXT_PASS (pass_referenced_vars);
NEXT_PASS (pass_create_structure_vars);
NEXT_PASS (pass_build_ssa);
NEXT_PASS (pass_build_pta);
NEXT_PASS (pass_may_alias);
NEXT_PASS (pass_return_slot);
NEXT_PASS (pass_del_pta);
NEXT_PASS (pass_rename_ssa_copies);
NEXT_PASS (pass_early_warn_uninitialized);
@ -490,9 +488,7 @@ init_optimization_passes (void)
NEXT_PASS (pass_dominator);
NEXT_PASS (pass_phiopt);
NEXT_PASS (pass_build_pta);
NEXT_PASS (pass_may_alias);
NEXT_PASS (pass_del_pta);
NEXT_PASS (pass_tail_recursion);
NEXT_PASS (pass_profile);
NEXT_PASS (pass_ch);

View File

@ -1,3 +1,7 @@
2005-07-09 Diego Novillo <dnovillo@redhat.com>
* gcc.dg/tree-ssa/pta-fp.c: Use -fdump-tree-alias1.
2005-07-09 Richard Henderson <rth@redhat.com>
* lib/target-supports.exp (check_effective_target_sync_char_short):

View File

@ -1,5 +1,5 @@
/* { dg-do compile } */
/* { dg-options "-O2 -fdump-tree-pta1" } */
/* { dg-options "-O2 -fdump-tree-alias1" } */
extern double cos (double);
extern double sin (double);
double f(double a)
@ -22,5 +22,5 @@ double f(double a)
}
/* The points-to set of the final function pointer should be "sin cos" */
/* { dg-final { scan-tree-dump-times "sin cos" 1 "pta1"} } */
/* { dg-final { cleanup-tree-dump "pta1" } } */
/* { dg-final { scan-tree-dump-times "sin cos" 1 "alias1"} } */
/* { dg-final { cleanup-tree-dump "alias1" } } */

View File

@ -3083,12 +3083,9 @@ verify_expr (tree *tp, int *walk_subtrees, void *data ATTRIBUTE_UNUSED)
if (TYPE_P (t))
*walk_subtrees = 0;
/* Check operand N for being valid GIMPLE and give error MSG if not.
We check for constants explicitly since they are not considered
gimple invariants if they overflowed. */
/* Check operand N for being valid GIMPLE and give error MSG if not. */
#define CHECK_OP(N, MSG) \
do { if (!CONSTANT_CLASS_P (TREE_OPERAND (t, N)) \
&& !is_gimple_val (TREE_OPERAND (t, N))) \
do { if (!is_gimple_val (TREE_OPERAND (t, N))) \
{ error (MSG); return TREE_OPERAND (t, N); }} while (0)
switch (TREE_CODE (t))

View File

@ -254,6 +254,37 @@ debug_referenced_vars (void)
}
/* Dump sub-variables for VAR to FILE. */
void
dump_subvars_for (FILE *file, tree var)
{
subvar_t sv = get_subvars_for_var (var);
if (!sv)
return;
fprintf (file, "{ ");
for (; sv; sv = sv->next)
{
print_generic_expr (file, sv->var, dump_flags);
fprintf (file, " ");
}
fprintf (file, "}");
}
/* Dumb sub-variables for VAR to stderr. */
void
debug_subvars_for (tree var)
{
dump_subvars_for (stderr, var);
}
/* Dump variable VAR and its may-aliases to FILE. */
void
@ -316,6 +347,12 @@ dump_variable (FILE *file, tree var)
dump_may_aliases_for (file, var);
}
if (get_subvars_for_var (var))
{
fprintf (file, ", sub-vars: ");
dump_subvars_for (file, var);
}
fprintf (file, "\n");
}
@ -741,8 +778,8 @@ find_new_referenced_vars (tree *stmt_p)
size, in bits, of REF inside the return value. */
tree
okay_component_ref_for_subvars (tree ref, HOST_WIDE_INT *poffset,
HOST_WIDE_INT *psize)
okay_component_ref_for_subvars (tree ref, unsigned HOST_WIDE_INT *poffset,
unsigned HOST_WIDE_INT *psize)
{
tree result = NULL;
HOST_WIDE_INT bitsize;

View File

@ -1444,6 +1444,20 @@ get_subvars_for_var (tree var)
return subvars;
}
/* Return the subvariable of VAR at offset OFFSET. */
static inline tree
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)
return sv->var;
return NULL_TREE;
}
/* Return true if V is a tree that we can have subvars for.
Normally, this is any aggregate type, however, due to implementation
limitations ATM, we exclude array types as well. */
@ -1461,7 +1475,7 @@ var_can_have_subvars (tree v)
*EXACT will be set to true upon return. */
static inline bool
overlap_subvar (HOST_WIDE_INT offset, HOST_WIDE_INT size,
overlap_subvar (unsigned HOST_WIDE_INT offset, unsigned HOST_WIDE_INT size,
subvar_t sv, bool *exact)
{
/* There are three possible cases of overlap.

View File

@ -71,9 +71,6 @@ struct ptr_info_def GTY(())
is pointing to. */
unsigned int pt_anything : 1;
/* Nonzero if this pointer is the result of a call to malloc. */
unsigned int pt_malloc : 1;
/* Nonzero if the value of this pointer escapes the current function. */
unsigned int value_escapes_p : 1;
@ -160,19 +157,22 @@ enum mem_tag_kind {
/* This variable represents a structure field. */
STRUCT_FIELD
};
struct subvar;
typedef struct subvar *subvar_t;
/* This structure represents a fake sub-variable for a structure field. */
struct subvar GTY(())
{
/* Fake variable name */
/* Fake variable. */
tree var;
/* Offset inside structure. */
HOST_WIDE_INT offset;
/* Size of field. */
HOST_WIDE_INT size;
unsigned HOST_WIDE_INT offset;
/* Size of the field. */
unsigned HOST_WIDE_INT size;
/* Next subvar for this structure. */
subvar_t next;
};
@ -552,6 +552,8 @@ extern void debug_referenced_vars (void);
extern void dump_referenced_vars (FILE *);
extern void dump_variable (FILE *, tree);
extern void debug_variable (tree);
extern void dump_subvars_for (FILE *, tree);
extern void debug_subvars_for (tree);
extern tree get_virtual_var (tree);
extern void add_referenced_tmp_var (tree);
extern void mark_new_vars_to_rename (tree);
@ -578,11 +580,13 @@ extern void add_type_alias (tree, tree);
extern void new_type_alias (tree, tree);
extern void count_uses_and_derefs (tree, tree, unsigned *, unsigned *, bool *);
static inline subvar_t get_subvars_for_var (tree);
static inline tree get_subvar_at (tree, unsigned HOST_WIDE_INT);
static inline bool ref_contains_array_ref (tree);
extern tree okay_component_ref_for_subvars (tree, HOST_WIDE_INT *,
HOST_WIDE_INT *);
extern tree okay_component_ref_for_subvars (tree, unsigned HOST_WIDE_INT *,
unsigned HOST_WIDE_INT *);
static inline bool var_can_have_subvars (tree);
static inline bool overlap_subvar (HOST_WIDE_INT, HOST_WIDE_INT,
static inline bool overlap_subvar (unsigned HOST_WIDE_INT,
unsigned HOST_WIDE_INT,
subvar_t, bool *);
/* Call-back function for walk_use_def_chains(). At each reaching

View File

@ -268,6 +268,8 @@ is_gimple_reg_type (tree type)
bool
is_gimple_reg (tree t)
{
var_ann_t ann;
if (TREE_CODE (t) == SSA_NAME)
t = SSA_NAME_VAR (t);
@ -305,9 +307,16 @@ is_gimple_reg (tree t)
if (TREE_CODE (TREE_TYPE (t)) == COMPLEX_TYPE)
return DECL_COMPLEX_GIMPLE_REG_P (t);
/* Some compiler temporaries are created to be used exclusively in
virtual operands (currently memory tags and sub-variables).
These variables should never be considered GIMPLE registers. */
if (DECL_ARTIFICIAL (t) && (ann = var_ann (t)) != NULL)
return ann->mem_tag_kind == NOT_A_TAG;
return true;
}
/* Returns true if T is a GIMPLE formal temporary variable. */
bool

View File

@ -276,8 +276,6 @@ extern struct tree_opt_pass pass_store_ccp;
extern struct tree_opt_pass pass_store_copy_prop;
extern struct tree_opt_pass pass_vrp;
extern struct tree_opt_pass pass_create_structure_vars;
extern struct tree_opt_pass pass_build_pta;
extern struct tree_opt_pass pass_del_pta;
extern struct tree_opt_pass pass_uncprop;
extern struct tree_opt_pass pass_return_slot;
extern struct tree_opt_pass pass_reassoc;

View File

@ -40,19 +40,12 @@ Boston, MA 02110-1301, USA. */
#include "tree-flow.h"
#include "tree-inline.h"
#include "tree-pass.h"
#include "tree-ssa-structalias.h"
#include "convert.h"
#include "params.h"
#include "vec.h"
#include "bitmap.h"
/* Keep track of how many times each pointer has been dereferenced in
the program using the aux variable. This is used by the alias
grouping heuristic in compute_flow_insensitive_aliasing. */
#define NUM_REFERENCES(ANN) ((size_t)((ANN)->common.aux))
#define NUM_REFERENCES_CLEAR(ANN) ((ANN)->common.aux) = 0
#define NUM_REFERENCES_INC(ANN) (ANN)->common.aux = (void*) (((size_t)((ANN)->common.aux)) + 1)
#define NUM_REFERENCES_SET(ANN, VAL) (ANN)->common.aux = (void*) ((void *)(VAL))
/* Obstack used to hold grouping bitmaps and other temporary bitmaps used by
aliasing */
static bitmap_obstack alias_obstack;
@ -83,51 +76,6 @@ struct alias_map_d
};
/* Alias information used by compute_may_aliases and its helpers. */
struct alias_info
{
/* SSA names visited while collecting points-to information. If bit I
is set, it means that SSA variable with version I has already been
visited. */
sbitmap ssa_names_visited;
/* Array of SSA_NAME pointers processed by the points-to collector. */
varray_type processed_ptrs;
/* Variables whose address is still needed. */
bitmap addresses_needed;
/* ADDRESSABLE_VARS contains all the global variables and locals that
have had their address taken. */
struct alias_map_d **addressable_vars;
size_t num_addressable_vars;
/* POINTERS contains all the _DECL pointers with unique memory tags
that have been referenced in the program. */
struct alias_map_d **pointers;
size_t num_pointers;
/* Number of function calls found in the program. */
size_t num_calls_found;
/* Number of const/pure function calls found in the program. */
size_t num_pure_const_calls_found;
/* Total number of virtual operands that will be needed to represent
all the aliases of all the pointers found in the program. */
long total_alias_vops;
/* Variables that have been written to. */
bitmap written_vars;
/* Pointers that have been used in an indirect store operation. */
bitmap dereferenced_ptrs_store;
/* Pointers that have been used in an indirect load operation. */
bitmap dereferenced_ptrs_load;
};
/* Counters used to display statistics on alias analysis. */
struct alias_stats_d
{
@ -155,18 +103,12 @@ static void add_may_alias (tree, tree);
static void replace_may_alias (tree, size_t, tree);
static struct alias_info *init_alias_info (void);
static void delete_alias_info (struct alias_info *);
static void compute_points_to_and_addr_escape (struct alias_info *);
static void compute_flow_sensitive_aliasing (struct alias_info *);
static void setup_pointers_and_addressables (struct alias_info *);
static bool collect_points_to_info_r (tree, tree, void *);
static bool is_escape_site (tree, struct alias_info *);
static void add_pointed_to_var (struct alias_info *, tree, tree);
static void create_global_var (void);
static void collect_points_to_info_for (struct alias_info *, tree);
static void maybe_create_global_var (struct alias_info *ai);
static void group_aliases (struct alias_info *);
static void set_pt_anything (tree ptr);
static void set_pt_malloc (tree ptr);
/* Global declarations. */
@ -315,7 +257,7 @@ compute_may_aliases (void)
address of V escapes the current function, making V call-clobbered
(i.e., whether &V is stored in a global variable or if its passed as a
function call argument). */
compute_points_to_and_addr_escape (ai);
compute_points_to_sets (ai);
/* Collect all pointers and addressable variables, compute alias sets,
create memory tags for pointers and promote variables whose address is
@ -506,7 +448,6 @@ init_alias_info (void)
ai->ssa_names_visited = sbitmap_alloc (num_ssa_names);
sbitmap_zero (ai->ssa_names_visited);
VARRAY_TREE_INIT (ai->processed_ptrs, 50, "processed_ptrs");
ai->addresses_needed = BITMAP_ALLOC (&alias_obstack);
ai->written_vars = BITMAP_ALLOC (&alias_obstack);
ai->dereferenced_ptrs_store = BITMAP_ALLOC (&alias_obstack);
ai->dereferenced_ptrs_load = BITMAP_ALLOC (&alias_obstack);
@ -564,7 +505,6 @@ init_alias_info (void)
superset of its former points-to set, then a new
tag will need to be created in create_name_tags. */
pi->pt_anything = 0;
pi->pt_malloc = 0;
pi->pt_null = 0;
pi->value_escapes_p = 0;
pi->is_dereferenced = 0;
@ -592,7 +532,6 @@ delete_alias_info (struct alias_info *ai)
sbitmap_free (ai->ssa_names_visited);
ai->processed_ptrs = NULL;
BITMAP_FREE (ai->addresses_needed);
for (i = 0; i < ai->num_addressable_vars; i++)
free (ai->addressable_vars[i]);
@ -613,171 +552,9 @@ delete_alias_info (struct alias_info *ai)
BITMAP_FREE (ai->dereferenced_ptrs_store);
BITMAP_FREE (ai->dereferenced_ptrs_load);
bitmap_obstack_release (&alias_obstack);
free (ai);
}
/* Walk use-def chains for pointer PTR to determine what variables is PTR
pointing to. */
static void
collect_points_to_info_for (struct alias_info *ai, tree ptr)
{
gcc_assert (POINTER_TYPE_P (TREE_TYPE (ptr)));
if (!TEST_BIT (ai->ssa_names_visited, SSA_NAME_VERSION (ptr)))
{
SET_BIT (ai->ssa_names_visited, SSA_NAME_VERSION (ptr));
walk_use_def_chains (ptr, collect_points_to_info_r, ai, true);
VARRAY_PUSH_TREE (ai->processed_ptrs, ptr);
}
}
/* Traverse use-def links for all the pointers in the program to collect
address escape and points-to information.
This is loosely based on the same idea described in R. Hasti and S.
Horwitz, ``Using static single assignment form to improve
flow-insensitive pointer analysis,'' in SIGPLAN Conference on
Programming Language Design and Implementation, pp. 97-105, 1998. */
static void
compute_points_to_and_addr_escape (struct alias_info *ai)
{
basic_block bb;
unsigned i;
tree op;
ssa_op_iter iter;
timevar_push (TV_TREE_PTA);
FOR_EACH_BB (bb)
{
block_stmt_iterator si;
for (si = bsi_start (bb); !bsi_end_p (si); bsi_next (&si))
{
bitmap addr_taken;
tree stmt = bsi_stmt (si);
bool stmt_escapes_p = is_escape_site (stmt, ai);
bitmap_iterator bi;
/* Mark all the variables whose address are taken by the
statement. Note that this will miss all the addresses taken
in PHI nodes (those are discovered while following the use-def
chains). */
addr_taken = addresses_taken (stmt);
if (addr_taken)
EXECUTE_IF_SET_IN_BITMAP (addr_taken, 0, i, bi)
{
tree var = referenced_var (i);
bitmap_set_bit (ai->addresses_needed, DECL_UID (var));
if (stmt_escapes_p)
mark_call_clobbered (var);
}
FOR_EACH_SSA_TREE_OPERAND (op, stmt, iter, SSA_OP_USE)
{
tree var = SSA_NAME_VAR (op);
var_ann_t v_ann = var_ann (var);
struct ptr_info_def *pi;
bool is_store;
unsigned num_uses, num_derefs;
/* If the operand's variable may be aliased, keep track
of how many times we've referenced it. This is used
for alias grouping in compute_flow_sensitive_aliasing.
Note that we don't need to grow AI->NUM_REFERENCES
because we are processing regular variables, not
memory tags (the array's initial size is set to
NUM_REFERENCED_VARS). */
if (may_be_aliased (var))
NUM_REFERENCES_INC (v_ann);
if (!POINTER_TYPE_P (TREE_TYPE (op)))
continue;
collect_points_to_info_for (ai, op);
pi = SSA_NAME_PTR_INFO (op);
count_uses_and_derefs (op, stmt, &num_uses, &num_derefs,
&is_store);
if (num_derefs > 0)
{
/* Mark OP as dereferenced. In a subsequent pass,
dereferenced pointers that point to a set of
variables will be assigned a name tag to alias
all the variables OP points to. */
pi->is_dereferenced = 1;
/* Keep track of how many time we've dereferenced each
pointer. */
NUM_REFERENCES_INC (v_ann);
/* If this is a store operation, mark OP as being
dereferenced to store, otherwise mark it as being
dereferenced to load. */
if (is_store)
bitmap_set_bit (ai->dereferenced_ptrs_store,
DECL_UID (var));
else
bitmap_set_bit (ai->dereferenced_ptrs_load,
DECL_UID (var));
}
if (stmt_escapes_p && num_derefs < num_uses)
{
/* If STMT is an escape point and STMT contains at
least one direct use of OP, then the value of OP
escapes and so the pointed-to variables need to
be marked call-clobbered. */
pi->value_escapes_p = 1;
/* If the statement makes a function call, assume
that pointer OP will be dereferenced in a store
operation inside the called function. */
if (get_call_expr_in (stmt))
{
bitmap_set_bit (ai->dereferenced_ptrs_store,
DECL_UID (var));
pi->is_dereferenced = 1;
}
}
}
/* Update reference counter for definitions to any
potentially aliased variable. This is used in the alias
grouping heuristics. */
FOR_EACH_SSA_TREE_OPERAND (op, stmt, iter, SSA_OP_DEF)
{
tree var = SSA_NAME_VAR (op);
var_ann_t ann = var_ann (var);
bitmap_set_bit (ai->written_vars, DECL_UID (var));
if (may_be_aliased (var))
NUM_REFERENCES_INC (ann);
if (POINTER_TYPE_P (TREE_TYPE (op)))
collect_points_to_info_for (ai, op);
}
/* Mark variables in V_MAY_DEF operands as being written to. */
FOR_EACH_SSA_TREE_OPERAND (op, stmt, iter, SSA_OP_VIRTUAL_DEFS)
{
tree var = DECL_P (op) ? op : SSA_NAME_VAR (op);
bitmap_set_bit (ai->written_vars, DECL_UID (var));
}
/* After promoting variables and computing aliasing we will
need to re-scan most statements. FIXME: Try to minimize the
number of statements re-scanned. It's not really necessary to
re-scan *all* statements. */
mark_stmt_modified (stmt);
}
}
timevar_pop (TV_TREE_PTA);
delete_points_to_sets ();
}
@ -863,16 +640,10 @@ create_name_tags (void)
if (old_name_tag && old_name_tag != pi->name_mem_tag)
mark_sym_for_renaming (old_name_tag);
}
else if (pi->pt_malloc)
{
/* Otherwise, create a unique name tag for this pointer. */
pi->name_mem_tag = get_nmt_for (ptr);
}
else
{
/* Only pointers that may point to malloc or other variables
may receive a name tag. If the pointer does not point to
a known spot, we should use type tags. */
/* If the pointer does not point to a known spot, we should
use type tags. */
set_pt_anything (ptr);
continue;
}
@ -902,11 +673,8 @@ compute_flow_sensitive_aliasing (struct alias_info *ai)
for (i = 0; i < VARRAY_ACTIVE_SIZE (ai->processed_ptrs); i++)
{
tree ptr = VARRAY_TREE (ai->processed_ptrs, i);
struct ptr_info_def *pi = SSA_NAME_PTR_INFO (ptr);
if (pi->pt_anything || pi->pt_vars == NULL)
{
find_what_p_points_to (ptr);
}
if (!find_what_p_points_to (ptr))
set_pt_anything (ptr);
}
create_name_tags ();
@ -931,9 +699,7 @@ compute_flow_sensitive_aliasing (struct alias_info *ai)
if (pi->pt_vars)
EXECUTE_IF_SET_IN_BITMAP (pi->pt_vars, 0, j, bi)
{
mark_call_clobbered (referenced_var (j));
}
mark_call_clobbered (referenced_var (j));
}
/* Set up aliasing information for PTR's name memory tag (if it has
@ -1009,9 +775,9 @@ compute_flow_insensitive_aliasing (struct alias_info *ai)
So we first check the call_clobbered status of the
tag and variable before querying the bitmap. */
tag_stored_p = is_call_clobbered (tag)
|| bitmap_bit_p (ai->written_vars, DECL_UID (tag));
|| bitmap_bit_p (ai->written_vars, DECL_UID (tag));
var_stored_p = is_call_clobbered (var)
|| bitmap_bit_p (ai->written_vars, DECL_UID (var));
|| bitmap_bit_p (ai->written_vars, DECL_UID (var));
if (!tag_stored_p && !var_stored_p)
continue;
@ -1126,7 +892,7 @@ compute_flow_insensitive_aliasing (struct alias_info *ai)
}
if (dump_file)
fprintf (dump_file, "%s: Total number of aliased vops: %ld\n",
fprintf (dump_file, "\n%s: Total number of aliased vops: %ld\n",
get_name (current_function_decl),
ai->total_alias_vops);
@ -1458,9 +1224,9 @@ setup_pointers_and_addressables (struct alias_info *ai)
of ADDR_EXPR constants into INDIRECT_REF expressions and the
removal of dead pointer assignments done by the early scalar
cleanup passes. */
if (TREE_ADDRESSABLE (var) && v_ann->mem_tag_kind != STRUCT_FIELD)
if (TREE_ADDRESSABLE (var))
{
if (!bitmap_bit_p (ai->addresses_needed, DECL_UID (var))
if (!bitmap_bit_p (addressable_vars, DECL_UID (var))
&& TREE_CODE (var) != RESULT_DECL
&& !is_global_var (var))
{
@ -1470,6 +1236,9 @@ setup_pointers_and_addressables (struct alias_info *ai)
to rename VAR into SSA afterwards. */
mark_sym_for_renaming (var);
/* If VAR can have sub-variables, and any of its
sub-variables has its address taken, then we cannot
remove the addressable flag from VAR. */
if (var_can_have_subvars (var)
&& (svars = get_subvars_for_var (var)))
{
@ -1477,8 +1246,7 @@ setup_pointers_and_addressables (struct alias_info *ai)
for (sv = svars; sv; sv = sv->next)
{
if (bitmap_bit_p (ai->addresses_needed,
DECL_UID (sv->var)))
if (bitmap_bit_p (addressable_vars, DECL_UID (sv->var)))
okay_to_mark = false;
mark_sym_for_renaming (sv->var);
}
@ -1490,22 +1258,6 @@ setup_pointers_and_addressables (struct alias_info *ai)
if (okay_to_mark)
mark_non_addressable (var);
}
else
{
/* Add the variable to the set of addressables. Mostly
used when scanning operands for ASM_EXPRs that
clobber memory. In those cases, we need to clobber
all call-clobbered variables and all addressables. */
bitmap_set_bit (addressable_vars, DECL_UID (var));
if (var_can_have_subvars (var)
&& (svars = get_subvars_for_var (var)))
{
subvar_t sv;
for (sv = svars; sv; sv = sv->next)
bitmap_set_bit (addressable_vars, DECL_UID (sv->var));
}
}
}
/* Global variables and addressable locals may be aliased. Create an
@ -1562,10 +1314,9 @@ setup_pointers_and_addressables (struct alias_info *ai)
references of TAG. Since TAG can be associated with
several pointers, add the dereferences of VAR to the
TAG. */
NUM_REFERENCES_SET (t_ann,
NUM_REFERENCES (t_ann) +
NUM_REFERENCES (v_ann));
NUM_REFERENCES (t_ann)
+ NUM_REFERENCES (v_ann));
}
else
{
@ -1783,8 +1534,16 @@ add_may_alias (tree var, tree alias)
var_ann_t v_ann = get_var_ann (var);
var_ann_t a_ann = get_var_ann (alias);
/* Don't allow self-referential aliases. */
gcc_assert (var != alias);
/* ALIAS must be addressable if it's being added to an alias set. */
#if 1
TREE_ADDRESSABLE (alias) = 1;
#else
gcc_assert (may_be_aliased (alias));
#endif
if (v_ann->may_aliases == NULL)
VARRAY_TREE_INIT (v_ann->may_aliases, 2, "aliases");
@ -1836,7 +1595,7 @@ set_pt_anything (tree ptr)
struct ptr_info_def *pi = get_ptr_info (ptr);
pi->pt_anything = 1;
pi->pt_malloc = 0;
pi->pt_vars = NULL;
/* The pointer used to have a name tag, but we now found it pointing
to an arbitrary location. The name tag needs to be renamed and
@ -1849,341 +1608,6 @@ set_pt_anything (tree ptr)
}
/* Mark pointer PTR as pointing to a malloc'd memory area. */
static void
set_pt_malloc (tree ptr)
{
struct ptr_info_def *pi = SSA_NAME_PTR_INFO (ptr);
/* If the pointer has already been found to point to arbitrary
memory locations, it is unsafe to mark it as pointing to malloc. */
if (pi->pt_anything)
return;
pi->pt_malloc = 1;
}
/* Given two different pointers DEST and ORIG. Merge the points-to
information in ORIG into DEST. AI contains all the alias
information collected up to this point. */
static void
merge_pointed_to_info (struct alias_info *ai, tree dest, tree orig)
{
struct ptr_info_def *dest_pi, *orig_pi;
gcc_assert (dest != orig);
/* Make sure we have points-to information for ORIG. */
collect_points_to_info_for (ai, orig);
dest_pi = get_ptr_info (dest);
orig_pi = SSA_NAME_PTR_INFO (orig);
if (orig_pi)
{
gcc_assert (orig_pi != dest_pi);
/* Notice that we never merge PT_MALLOC. This attribute is only
true if the pointer is the result of a malloc() call.
Otherwise, we can end up in this situation:
P_i = malloc ();
...
P_j = P_i + X;
P_j would be marked as PT_MALLOC, however we currently do not
handle cases of more than one pointer pointing to the same
malloc'd area.
FIXME: If the merging comes from an expression that preserves
the PT_MALLOC attribute (copy assignment, address
arithmetic), we ought to merge PT_MALLOC, but then both
pointers would end up getting different name tags because
create_name_tags is not smart enough to determine that the
two come from the same malloc call. Copy propagation before
aliasing should cure this. */
dest_pi->pt_malloc = 0;
if (orig_pi->pt_malloc || orig_pi->pt_anything)
set_pt_anything (dest);
dest_pi->pt_null |= orig_pi->pt_null;
if (!dest_pi->pt_anything
&& orig_pi->pt_vars
&& !bitmap_empty_p (orig_pi->pt_vars))
{
if (dest_pi->pt_vars == NULL)
{
dest_pi->pt_vars = BITMAP_GGC_ALLOC ();
bitmap_copy (dest_pi->pt_vars, orig_pi->pt_vars);
}
else
bitmap_ior_into (dest_pi->pt_vars, orig_pi->pt_vars);
}
}
else
set_pt_anything (dest);
}
/* Add EXPR to the list of expressions pointed-to by PTR. */
static void
add_pointed_to_expr (struct alias_info *ai, tree ptr, tree expr)
{
if (TREE_CODE (expr) == WITH_SIZE_EXPR)
expr = TREE_OPERAND (expr, 0);
get_ptr_info (ptr);
if (TREE_CODE (expr) == CALL_EXPR
&& (call_expr_flags (expr) & (ECF_MALLOC | ECF_MAY_BE_ALLOCA)))
{
/* If EXPR is a malloc-like call, then the area pointed to PTR
is guaranteed to not alias with anything else. */
set_pt_malloc (ptr);
}
else if (TREE_CODE (expr) == ADDR_EXPR)
{
/* Found P_i = ADDR_EXPR */
add_pointed_to_var (ai, ptr, expr);
}
else if (TREE_CODE (expr) == SSA_NAME && POINTER_TYPE_P (TREE_TYPE (expr)))
{
/* Found P_i = Q_j. */
merge_pointed_to_info (ai, ptr, expr);
}
else if (TREE_CODE (expr) == PLUS_EXPR || TREE_CODE (expr) == MINUS_EXPR)
{
/* Found P_i = PLUS_EXPR or P_i = MINUS_EXPR */
tree op0 = TREE_OPERAND (expr, 0);
tree op1 = TREE_OPERAND (expr, 1);
/* Both operands may be of pointer type. FIXME: Shouldn't
we just expect PTR + OFFSET always? */
if (POINTER_TYPE_P (TREE_TYPE (op0))
&& TREE_CODE (op0) != INTEGER_CST)
{
if (TREE_CODE (op0) == SSA_NAME)
merge_pointed_to_info (ai, ptr, op0);
else if (TREE_CODE (op0) == ADDR_EXPR)
add_pointed_to_var (ai, ptr, op0);
else
set_pt_anything (ptr);
}
if (POINTER_TYPE_P (TREE_TYPE (op1))
&& TREE_CODE (op1) != INTEGER_CST)
{
if (TREE_CODE (op1) == SSA_NAME)
merge_pointed_to_info (ai, ptr, op1);
else if (TREE_CODE (op1) == ADDR_EXPR)
add_pointed_to_var (ai, ptr, op1);
else
set_pt_anything (ptr);
}
/* Neither operand is a pointer? VAR can be pointing anywhere.
FIXME: Shouldn't we asserting here? If we get here, we found
PTR = INT_CST + INT_CST, which should not be a valid pointer
expression. */
if (!(POINTER_TYPE_P (TREE_TYPE (op0))
&& TREE_CODE (op0) != INTEGER_CST)
&& !(POINTER_TYPE_P (TREE_TYPE (op1))
&& TREE_CODE (op1) != INTEGER_CST))
set_pt_anything (ptr);
}
else if (integer_zerop (expr))
{
/* EXPR is the NULL pointer. Mark PTR as pointing to NULL. */
SSA_NAME_PTR_INFO (ptr)->pt_null = 1;
}
else
{
/* If we can't recognize the expression, assume that PTR may
point anywhere. */
set_pt_anything (ptr);
}
}
/* If VALUE is of the form &DECL, add DECL to the set of variables
pointed-to by PTR. Otherwise, add VALUE as a pointed-to expression by
PTR. AI points to the collected alias information. */
static void
add_pointed_to_var (struct alias_info *ai, tree ptr, tree value)
{
struct ptr_info_def *pi = get_ptr_info (ptr);
tree pt_var = NULL_TREE;
HOST_WIDE_INT offset, size;
tree addrop;
size_t uid;
tree ref;
subvar_t svars;
gcc_assert (TREE_CODE (value) == ADDR_EXPR);
addrop = TREE_OPERAND (value, 0);
if (REFERENCE_CLASS_P (addrop))
pt_var = get_base_address (addrop);
else
pt_var = addrop;
/* If this is a component_ref, see if we can get a smaller number of
variables to take the address of. */
if (TREE_CODE (addrop) == COMPONENT_REF
&& (ref = okay_component_ref_for_subvars (addrop, &offset ,&size)))
{
subvar_t sv;
svars = get_subvars_for_var (ref);
uid = DECL_UID (pt_var);
if (pi->pt_vars == NULL)
pi->pt_vars = BITMAP_GGC_ALLOC ();
/* If the variable is a global, mark the pointer as pointing to
global memory (which will make its tag a global variable). */
if (is_global_var (pt_var))
pi->pt_global_mem = 1;
for (sv = svars; sv; sv = sv->next)
{
if (overlap_subvar (offset, size, sv, NULL))
{
bitmap_set_bit (pi->pt_vars, DECL_UID (sv->var));
bitmap_set_bit (ai->addresses_needed, DECL_UID (sv->var));
}
}
}
else if (pt_var && SSA_VAR_P (pt_var))
{
uid = DECL_UID (pt_var);
if (pi->pt_vars == NULL)
pi->pt_vars = BITMAP_GGC_ALLOC ();
/* If this is an aggregate, we may have subvariables for it that need
to be pointed to. */
if (var_can_have_subvars (pt_var)
&& (svars = get_subvars_for_var (pt_var)))
{
subvar_t sv;
for (sv = svars; sv; sv = sv->next)
{
uid = DECL_UID (sv->var);
bitmap_set_bit (ai->addresses_needed, uid);
bitmap_set_bit (pi->pt_vars, uid);
}
}
else
{
bitmap_set_bit (ai->addresses_needed, uid);
bitmap_set_bit (pi->pt_vars, uid);
}
/* If the variable is a global, mark the pointer as pointing to
global memory (which will make its tag a global variable). */
if (is_global_var (pt_var))
pi->pt_global_mem = 1;
}
}
/* Callback for walk_use_def_chains to gather points-to information from the
SSA web.
VAR is an SSA variable or a GIMPLE expression.
STMT is the statement that generates the SSA variable or, if STMT is a
PHI_NODE, VAR is one of the PHI arguments.
DATA is a pointer to a structure of type ALIAS_INFO. */
static bool
collect_points_to_info_r (tree var, tree stmt, void *data)
{
struct alias_info *ai = (struct alias_info *) data;
if (dump_file && (dump_flags & TDF_DETAILS))
{
fprintf (dump_file, "Visiting use-def links for ");
print_generic_expr (dump_file, var, dump_flags);
fprintf (dump_file, "\n");
}
switch (TREE_CODE (stmt))
{
case RETURN_EXPR:
gcc_assert (TREE_CODE (TREE_OPERAND (stmt, 0)) == MODIFY_EXPR);
stmt = TREE_OPERAND (stmt, 0);
/* FALLTHRU */
case MODIFY_EXPR:
{
tree rhs = TREE_OPERAND (stmt, 1);
STRIP_NOPS (rhs);
add_pointed_to_expr (ai, var, rhs);
break;
}
case ASM_EXPR:
/* Pointers defined by __asm__ statements can point anywhere. */
set_pt_anything (var);
break;
case NOP_EXPR:
if (IS_EMPTY_STMT (stmt))
{
tree decl = SSA_NAME_VAR (var);
if (TREE_CODE (decl) == PARM_DECL)
add_pointed_to_expr (ai, var, decl);
else if (DECL_INITIAL (decl))
add_pointed_to_expr (ai, var, DECL_INITIAL (decl));
else
add_pointed_to_expr (ai, var, decl);
}
break;
case PHI_NODE:
{
/* It STMT is a PHI node, then VAR is one of its arguments. The
variable that we are analyzing is the LHS of the PHI node. */
tree lhs = PHI_RESULT (stmt);
switch (TREE_CODE (var))
{
case ADDR_EXPR:
add_pointed_to_var (ai, lhs, var);
break;
case SSA_NAME:
/* Avoid unnecessary merges. */
if (lhs != var)
merge_pointed_to_info (ai, lhs, var);
break;
default:
gcc_assert (is_gimple_min_invariant (var));
add_pointed_to_expr (ai, lhs, var);
break;
}
break;
}
default:
gcc_unreachable ();
}
return false;
}
/* Return true if STMT is an "escape" site from the current function. Escape
sites those statements which might expose the address of a variable
outside the current function. STMT is an escape site iff:
@ -2195,7 +1619,7 @@ collect_points_to_info_r (tree var, tree stmt, void *data)
AI points to the alias information collected so far. */
static bool
bool
is_escape_site (tree stmt, struct alias_info *ai)
{
tree call = get_call_expr_in (stmt);
@ -2271,9 +1695,7 @@ create_memory_tag (tree type, bool is_type_tag)
determine whether they should be considered globals. */
DECL_CONTEXT (tag) = current_function_decl;
/* Memory tags are by definition addressable. This also prevents
is_gimple_ref frome confusing memory tags with optimizable
variables. */
/* Memory tags are by definition addressable. */
TREE_ADDRESSABLE (tag) = 1;
ann = get_var_ann (tag);
@ -2304,7 +1726,6 @@ get_nmt_for (tree ptr)
/* If PTR is a PARM_DECL, it points to a global variable or malloc,
then its name tag should be considered a global variable. */
if (TREE_CODE (SSA_NAME_VAR (ptr)) == PARM_DECL
|| pi->pt_malloc
|| pi->pt_global_mem)
mark_call_clobbered (tag);
@ -2560,9 +1981,6 @@ dump_points_to_info_for (FILE *file, tree ptr)
if (pi->pt_anything)
fprintf (file, ", points-to anything");
if (pi->pt_malloc)
fprintf (file, ", points-to malloc");
if (pi->pt_null)
fprintf (file, ", points-to NULL");
@ -2978,6 +2396,33 @@ get_or_create_used_part_for (size_t uid)
}
/* Create and return a structure sub-variable for field FIELD of
variable VAR. */
static tree
create_sft (tree var, tree field)
{
var_ann_t ann;
tree subvar = create_tmp_var_raw (TREE_TYPE (field), "SFT");
/* We need to copy the various flags from VAR to SUBVAR, so that
they are is_global_var iff the original variable was. */
DECL_CONTEXT (subvar) = DECL_CONTEXT (var);
DECL_EXTERNAL (subvar) = DECL_EXTERNAL (var);
TREE_PUBLIC (subvar) = TREE_PUBLIC (var);
TREE_STATIC (subvar) = TREE_STATIC (var);
TREE_READONLY (subvar) = TREE_READONLY (var);
/* Add the new variable to REFERENCED_VARS. */
ann = get_var_ann (subvar);
ann->mem_tag_kind = STRUCT_FIELD;
ann->type_mem_tag = NULL;
add_referenced_tmp_var (subvar);
return subvar;
}
/* Given an aggregate VAR, create the subvariables that represent its
fields. */
@ -3067,7 +2512,6 @@ create_overlap_variables_for (tree var)
{
subvar_t sv;
HOST_WIDE_INT fosize;
var_ann_t ann;
tree currfotype;
fosize = TREE_INT_CST_LOW (DECL_SIZE (fo->field));
@ -3088,7 +2532,8 @@ create_overlap_variables_for (tree var)
sv->offset = fo->offset;
sv->size = fosize;
sv->next = *subvars;
sv->var = create_tmp_var_raw (TREE_TYPE (fo->field), "SFT");
sv->var = create_sft (var, fo->field);
if (dump_file)
{
fprintf (dump_file, "structure field tag %s created for var %s",
@ -3100,25 +2545,6 @@ create_overlap_variables_for (tree var)
fprintf (dump_file, "\n");
}
/* We need to copy the various flags from var to sv->var, so that
they are is_global_var iff the original variable was. */
DECL_EXTERNAL (sv->var) = DECL_EXTERNAL (var);
TREE_PUBLIC (sv->var) = TREE_PUBLIC (var);
TREE_STATIC (sv->var) = TREE_STATIC (var);
TREE_READONLY (sv->var) = TREE_READONLY (var);
/* Like other memory tags, these need to be marked addressable to
keep is_gimple_reg from thinking they are real. */
TREE_ADDRESSABLE (sv->var) = 1;
DECL_CONTEXT (sv->var) = DECL_CONTEXT (var);
ann = get_var_ann (sv->var);
ann->mem_tag_kind = STRUCT_FIELD;
ann->type_mem_tag = NULL;
add_referenced_tmp_var (sv->var);
lastfotype = currfotype;
lastfooffset = fo->offset;
lastfosize = fosize;

View File

@ -188,7 +188,9 @@ merge_alias_info (tree orig, tree new)
#endif
/* Synchronize the type tags. If both pointers had a tag and they
are different, then something has gone wrong. */
are different, then something has gone wrong. Type tags can
always be merged because they are flow insensitive, all the SSA
names of the same base DECL share the same type tag. */
if (new_ann->type_mem_tag == NULL_TREE)
new_ann->type_mem_tag = orig_ann->type_mem_tag;
else if (orig_ann->type_mem_tag == NULL_TREE)
@ -196,32 +198,41 @@ merge_alias_info (tree orig, tree new)
else
gcc_assert (new_ann->type_mem_tag == orig_ann->type_mem_tag);
/* Synchronize the name tags. If NEW did not have a name tag, get
it from ORIG. This happens when NEW is a compiler generated
temporary which still hasn't had its points-to information filled
in. */
if (SSA_NAME_PTR_INFO (orig))
/* Check that flow-sensitive information is compatible. Notice that
we may not merge flow-sensitive information here. This function
is called when propagating equivalences dictated by the IL, like
a copy operation P_i = Q_j, and from equivalences dictated by
control-flow, like if (P_i == Q_j).
In the former case, P_i and Q_j are equivalent in every block
dominated by the assignment, so their flow-sensitive information
is always the same. However, in the latter case, the pointers
P_i and Q_j are only equivalent in one of the sub-graphs out of
the predicate, so their flow-sensitive information is not the
same in every block dominated by the predicate.
Since we cannot distinguish one case from another in this
function, we can only make sure that if P_i and Q_j have
flow-sensitive information, they should be compatible. */
if (SSA_NAME_PTR_INFO (orig) && SSA_NAME_PTR_INFO (new))
{
struct ptr_info_def *orig_ptr_info = SSA_NAME_PTR_INFO (orig);
struct ptr_info_def *new_ptr_info = SSA_NAME_PTR_INFO (new);
if (new_ptr_info == NULL)
duplicate_ssa_name_ptr_info (new, orig_ptr_info);
else if (orig_ptr_info->name_mem_tag
&& new_ptr_info->name_mem_tag
&& orig_ptr_info->pt_vars
&& new_ptr_info->pt_vars)
{
/* Note that pointer NEW may actually have a different set
of pointed-to variables. However, since NEW is being
copy-propagated into ORIG, it must always be true that
the pointed-to set for pointer NEW is the same, or a
subset, of the pointed-to set for pointer ORIG. If this
isn't the case, we shouldn't have been able to do the
propagation of NEW into ORIG. */
gcc_assert (bitmap_intersect_p (new_ptr_info->pt_vars,
orig_ptr_info->pt_vars));
}
/* Note that pointer NEW and ORIG may actually have different
pointed-to variables (e.g., PR 18291 represented in
testsuite/gcc.c-torture/compile/pr18291.c). However, since
NEW is being copy-propagated into ORIG, it must always be
true that the pointed-to set for pointer NEW is the same, or
a subset, of the pointed-to set for pointer ORIG. If this
isn't the case, we shouldn't have been able to do the
propagation of NEW into ORIG. */
if (orig_ptr_info->name_mem_tag
&& new_ptr_info->name_mem_tag
&& orig_ptr_info->pt_vars
&& new_ptr_info->pt_vars)
gcc_assert (bitmap_intersect_p (new_ptr_info->pt_vars,
orig_ptr_info->pt_vars));
}
}

View File

@ -32,7 +32,6 @@ Boston, MA 02110-1301, USA. */
#include "ggc.h"
#include "timevar.h"
#include "toplev.h"
#include "langhooks.h"
/* This file contains the code required to manage the operands cache of the
@ -148,7 +147,6 @@ static bool ops_active = false;
static GTY (()) struct ssa_operand_memory_d *operand_memory = NULL;
static unsigned operand_memory_index;
static void note_addressable (tree, stmt_ann_t);
static void get_expr_operands (tree, tree *, int);
static void get_asm_expr_operands (tree);
static void get_indirect_ref_operands (tree, tree, int);
@ -1310,7 +1308,7 @@ get_expr_operands (tree stmt, tree *expr_p, int flags)
case IMAGPART_EXPR:
{
tree ref;
HOST_WIDE_INT offset, size;
unsigned HOST_WIDE_INT offset, size;
/* This component ref becomes an access to all of the subvariables
it can touch, if we can determine that, but *NOT* the real one.
If we can't determine which fields we could touch, the recursion
@ -1515,8 +1513,8 @@ get_asm_expr_operands (tree stmt)
if (!allows_reg && allows_mem)
{
tree t = get_base_address (TREE_VALUE (link));
if (t && DECL_P (t))
note_addressable (t, s_ann);
if (t && DECL_P (t) && s_ann)
add_to_addressable_set (t, &s_ann->addresses_taken);
}
get_expr_operands (stmt, &TREE_VALUE (link), opf_is_def);
@ -1534,8 +1532,8 @@ get_asm_expr_operands (tree stmt)
if (!allows_reg && allows_mem)
{
tree t = get_base_address (TREE_VALUE (link));
if (t && DECL_P (t))
note_addressable (t, s_ann);
if (t && DECL_P (t) && s_ann)
add_to_addressable_set (t, &s_ann->addresses_taken);
}
get_expr_operands (stmt, &TREE_VALUE (link), 0);
@ -1688,7 +1686,10 @@ get_tmr_operands (tree stmt, tree expr, int flags)
flags &= ~opf_kill_def;
if (TMR_SYMBOL (expr))
note_addressable (TMR_SYMBOL (expr), stmt_ann (stmt));
{
stmt_ann_t ann = stmt_ann (stmt);
add_to_addressable_set (TMR_SYMBOL (expr), &ann->addresses_taken);
}
if (tag)
add_stmt_operand (&tag, stmt_ann (stmt), flags);
@ -1757,9 +1758,9 @@ add_stmt_operand (tree *var_p, stmt_ann_t s_ann, int flags)
/* If the operand is an ADDR_EXPR, add its operand to the list of
variables that have had their address taken in this statement. */
if (TREE_CODE (var) == ADDR_EXPR)
if (TREE_CODE (var) == ADDR_EXPR && s_ann)
{
note_addressable (TREE_OPERAND (var, 0), s_ann);
add_to_addressable_set (TREE_OPERAND (var, 0), &s_ann->addresses_taken);
return;
}
@ -1861,35 +1862,17 @@ add_stmt_operand (tree *var_p, stmt_ann_t s_ann, int flags)
if (flags & opf_is_def)
{
bool added_may_defs_p = false;
/* 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)
{
added_may_defs_p = true;
append_v_may_def (var);
}
append_v_may_def (var);
for (i = 0; i < VARRAY_ACTIVE_SIZE (aliases); i++)
{
/* While VAR may be modifiable, some of its aliases
may not be. If that's the case, we don't really
need to add them a V_MAY_DEF for them. */
tree alias = VARRAY_TREE (aliases, i);
append_v_may_def (VARRAY_TREE (aliases, i));
if (unmodifiable_var_p (alias))
append_vuse (alias);
else
{
append_v_may_def (alias);
added_may_defs_p = true;
}
}
if (s_ann && added_may_defs_p)
if (s_ann)
s_ann->makes_aliased_stores = 1;
}
else
@ -1910,40 +1893,51 @@ add_stmt_operand (tree *var_p, stmt_ann_t s_ann, int flags)
}
/* Record that VAR had its address taken in the statement with annotations
S_ANN. */
/* 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
GIMPLE memory reference (structure reference, array, etc). If the
base address of REF is a decl that has sub-variables, also add all
of its sub-variables. */
static void
note_addressable (tree var, stmt_ann_t s_ann)
void
add_to_addressable_set (tree ref, bitmap *addresses_taken)
{
tree var;
subvar_t svars;
if (!s_ann)
return;
gcc_assert (addresses_taken);
/* Note that it is *NOT OKAY* to use the target of a COMPONENT_REF
as the only thing we take the address of.
See PR 21407 and the ensuing mailing list discussion. */
var = get_base_address (var);
as the only thing we take the address of. If VAR is a structure,
taking the address of a field means that the whole structure may
be referenced using pointer arithmetic. See PR 21407 and the
ensuing mailing list discussion. */
var = get_base_address (ref);
if (var && SSA_VAR_P (var))
{
if (s_ann->addresses_taken == NULL)
s_ann->addresses_taken = BITMAP_GGC_ALLOC ();
if (*addresses_taken == NULL)
*addresses_taken = BITMAP_GGC_ALLOC ();
if (var_can_have_subvars (var)
&& (svars = get_subvars_for_var (var)))
{
subvar_t sv;
for (sv = svars; sv; sv = sv->next)
bitmap_set_bit (s_ann->addresses_taken, DECL_UID (sv->var));
{
bitmap_set_bit (*addresses_taken, DECL_UID (sv->var));
TREE_ADDRESSABLE (sv->var) = 1;
}
}
else
bitmap_set_bit (s_ann->addresses_taken, DECL_UID (var));
{
bitmap_set_bit (*addresses_taken, DECL_UID (var));
TREE_ADDRESSABLE (var) = 1;
}
}
}
/* Add clobbering definitions for .GLOBAL_VAR or for each of the call
clobbered variables in the function. */

View File

@ -170,6 +170,8 @@ extern bool ssa_ro_call_cache_valid;
extern bool ssa_operands_active (void);
extern void add_to_addressable_set (tree, bitmap *);
enum ssa_op_iter_type {
ssa_op_iter_none = 0,
ssa_op_iter_tree,

View File

@ -26,7 +26,6 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
#include "ggc.h"
#include "obstack.h"
#include "bitmap.h"
#include "tree-ssa-structalias.h"
#include "flags.h"
#include "rtl.h"
#include "tm_p.h"
@ -49,6 +48,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
#include "timevar.h"
#include "alloc-pool.h"
#include "splay-tree.h"
#include "tree-ssa-structalias.h"
/* The idea behind this analyzer is to generate set constraints from the
program, then solve the resulting constraints in order to generate the
@ -223,6 +223,9 @@ struct variable_info
/* True for variables that have unions somewhere in them. */
unsigned int has_union:1;
/* True if this is a heap variable. */
unsigned int is_heap_var:1;
/* Points-to set for this variable. */
bitmap solution;
@ -270,6 +273,12 @@ static varinfo_t var_integer;
static tree integer_tree;
static unsigned int integer_id;
/* Variable that represents arbitrary offsets into an object. Used to
represent pointer arithmetic, which may not legally escape the
bounds of an object. */
static varinfo_t var_anyoffset;
static tree anyoffset_tree;
static unsigned int anyoffset_id;
/* Return a new variable info structure consisting for a variable
named NAME, and using constraint graph node NODE. */
@ -286,6 +295,7 @@ new_var_info (tree t, unsigned int id, const char *name, unsigned int node)
ret->address_taken = false;
ret->indirect_target = false;
ret->is_artificial_var = false;
ret->is_heap_var = false;
ret->is_unknown_size_var = false;
ret->solution = BITMAP_ALLOC (&ptabitmap_obstack);
bitmap_clear (ret->solution);
@ -941,8 +951,11 @@ build_constraint_graph (void)
constraint_t c;
graph = ggc_alloc (sizeof (struct constraint_graph));
graph->succs = ggc_alloc_cleared (VEC_length (varinfo_t, varmap) * sizeof (*graph->succs));
graph->preds = ggc_alloc_cleared (VEC_length (varinfo_t, varmap) * sizeof (*graph->preds));
graph->succs = ggc_alloc_cleared (VEC_length (varinfo_t, varmap)
* sizeof (*graph->succs));
graph->preds = ggc_alloc_cleared (VEC_length (varinfo_t, varmap)
* sizeof (*graph->preds));
for (i = 0; VEC_iterate (constraint_t, constraints, i, c); i++)
{
struct constraint_expr lhs = c->lhs;
@ -983,6 +996,8 @@ build_constraint_graph (void)
}
}
}
/* Changed variables on the last iteration. */
static unsigned int changed_count;
static sbitmap changed;
@ -2137,11 +2152,18 @@ get_constraint_for (tree t)
&ANYTHING added. */
if (call_expr_flags (t) & (ECF_MALLOC | ECF_MAY_BE_ALLOCA))
{
tree heapvar = create_tmp_var_raw (ptr_type_node, "HEAP");
varinfo_t vi;
tree heapvar;
heapvar = create_tmp_var_raw (ptr_type_node, "HEAP");
DECL_EXTERNAL (heapvar) = 1;
add_referenced_tmp_var (heapvar);
temp.var = create_variable_info_for (heapvar,
alias_get_name (heapvar));
get_varinfo (temp.var)->is_artificial_var = 1;
vi = get_varinfo (temp.var);
vi->is_artificial_var = 1;
vi->is_heap_var = 1;
temp.type = ADDRESSOF;
temp.offset = 0;
return temp;
@ -2191,9 +2213,11 @@ get_constraint_for (tree t)
/* Cast from non-pointer to pointers are bad news for us.
Anything else, we see through */
if (!(POINTER_TYPE_P (TREE_TYPE (t)) &&
! POINTER_TYPE_P (TREE_TYPE (op))))
if (!(POINTER_TYPE_P (TREE_TYPE (t))
&& ! POINTER_TYPE_P (TREE_TYPE (op))))
return get_constraint_for (op);
/* FALLTHRU */
}
default:
{
@ -2467,81 +2491,300 @@ ref_contains_indirect_ref (tree ref)
}
/* Tree walker that is the heart of the aliasing infrastructure.
TP is a pointer to the current tree.
WALK_SUBTREES specifies whether to continue traversing subtrees or
not.
Returns NULL_TREE when we should stop.
This function is the main part of the constraint builder. It
walks the trees, calling the appropriate building functions
to process various statements. */
/* Update related alias information kept in AI. This is used when
building name tags, alias sets and deciding grouping heuristics.
STMT is the statement to process. This function also updates
ADDRESSABLE_VARS. */
static void
find_func_aliases (tree t)
update_alias_info (tree stmt, struct alias_info *ai)
{
bitmap addr_taken;
use_operand_p use_p;
def_operand_p def_p;
ssa_op_iter iter;
bool stmt_escapes_p = is_escape_site (stmt, ai);
/* Mark all the variables whose address are taken by the statement. */
addr_taken = addresses_taken (stmt);
if (addr_taken)
{
bitmap_ior_into (addressable_vars, addr_taken);
/* If STMT is an escape point, all the addresses taken by it are
call-clobbered. */
if (stmt_escapes_p)
{
bitmap_iterator bi;
unsigned i;
EXECUTE_IF_SET_IN_BITMAP (addr_taken, 0, i, bi)
mark_call_clobbered (referenced_var (i));
}
}
/* Process each operand use. If an operand may be aliased, keep
track of how many times it's being used. For pointers, determine
whether they are dereferenced by the statement, or whether their
value escapes, etc. */
FOR_EACH_PHI_OR_STMT_USE (use_p, stmt, iter, SSA_OP_USE)
{
tree op, var;
var_ann_t v_ann;
struct ptr_info_def *pi;
bool is_store;
unsigned num_uses, num_derefs;
op = USE_FROM_PTR (use_p);
/* If STMT is a PHI node, OP may be an ADDR_EXPR. If so, add it
to the set of addressable variables. */
if (TREE_CODE (op) == ADDR_EXPR)
{
gcc_assert (TREE_CODE (stmt) == PHI_NODE);
/* PHI nodes don't have annotations for pinning the set
of addresses taken, so we collect them here.
FIXME, should we allow PHI nodes to have annotations
so that they can be treated like regular statements?
Currently, they are treated as second-class
statements. */
add_to_addressable_set (TREE_OPERAND (op, 0), &addressable_vars);
continue;
}
/* Ignore constants. */
if (TREE_CODE (op) != SSA_NAME)
continue;
var = SSA_NAME_VAR (op);
v_ann = var_ann (var);
/* If the operand's variable may be aliased, keep track of how
many times we've referenced it. This is used for alias
grouping in compute_flow_insensitive_aliasing. */
if (may_be_aliased (var))
NUM_REFERENCES_INC (v_ann);
/* We are only interested in pointers. */
if (!POINTER_TYPE_P (TREE_TYPE (op)))
continue;
pi = get_ptr_info (op);
/* Add OP to AI->PROCESSED_PTRS, if it's not there already. */
if (!TEST_BIT (ai->ssa_names_visited, SSA_NAME_VERSION (op)))
{
SET_BIT (ai->ssa_names_visited, SSA_NAME_VERSION (op));
VARRAY_PUSH_TREE (ai->processed_ptrs, op);
}
/* If STMT is a PHI node, then it will not have pointer
dereferences and it will not be an escape point. */
if (TREE_CODE (stmt) == PHI_NODE)
continue;
/* Determine whether OP is a dereferenced pointer, and if STMT
is an escape point, whether OP escapes. */
count_uses_and_derefs (op, stmt, &num_uses, &num_derefs, &is_store);
if (num_derefs > 0)
{
/* Mark OP as dereferenced. In a subsequent pass,
dereferenced pointers that point to a set of
variables will be assigned a name tag to alias
all the variables OP points to. */
pi->is_dereferenced = 1;
/* Keep track of how many time we've dereferenced each
pointer. */
NUM_REFERENCES_INC (v_ann);
/* If this is a store operation, mark OP as being
dereferenced to store, otherwise mark it as being
dereferenced to load. */
if (is_store)
bitmap_set_bit (ai->dereferenced_ptrs_store, DECL_UID (var));
else
bitmap_set_bit (ai->dereferenced_ptrs_load, DECL_UID (var));
}
if (stmt_escapes_p && num_derefs < num_uses)
{
/* If STMT is an escape point and STMT contains at
least one direct use of OP, then the value of OP
escapes and so the pointed-to variables need to
be marked call-clobbered. */
pi->value_escapes_p = 1;
/* If the statement makes a function call, assume
that pointer OP will be dereferenced in a store
operation inside the called function. */
if (get_call_expr_in (stmt))
{
bitmap_set_bit (ai->dereferenced_ptrs_store, DECL_UID (var));
pi->is_dereferenced = 1;
}
}
}
/* Update reference counter for definitions to any potentially
aliased variable. This is used in the alias grouping heuristics. */
FOR_EACH_PHI_OR_STMT_DEF (def_p, stmt, iter, SSA_OP_ALL_DEFS)
{
tree op = DEF_FROM_PTR (def_p);
tree var = SSA_NAME_VAR (op);
var_ann_t ann = var_ann (var);
bitmap_set_bit (ai->written_vars, DECL_UID (var));
if (may_be_aliased (var))
NUM_REFERENCES_INC (ann);
}
}
/* Handle pointer arithmetic EXPR when creating aliasing constraints.
Expressions of the type PTR + CST can be handled in two ways:
1- If the constraint for PTR is ADDRESSOF for a non-structure
variable, then we can use it directly because adding or
subtracting a constant may not alter the original ADDRESSOF
constraing (i.e., pointer arithmetic may not legally go outside
an object's boundaries).
2- If the constraint for PTR is ADDRESSOF for a structure variable,
then if CST is a compile-time constant that can be used as an
offset, we can determine which sub-variable will be pointed-to
by the expression.
Return true if the expression is handled. For any other kind of
expression, return false so that each operand can be added as a
separate constraint by the caller. */
static bool
handle_ptr_arith (struct constraint_expr lhs, tree expr)
{
tree op0, op1;
struct constraint_expr base, offset;
if (TREE_CODE (expr) != PLUS_EXPR)
return false;
op0 = TREE_OPERAND (expr, 0);
op1 = TREE_OPERAND (expr, 1);
base = get_constraint_for (op0);
offset.var = anyoffset_id;
offset.type = ADDRESSOF;
offset.offset = 0;
process_constraint (new_constraint (lhs, base));
process_constraint (new_constraint (lhs, offset));
return true;
}
/* Walk statement T setting up aliasing constraints according to the
references found in T. This function is the main part of the
constraint builder. AI points to auxiliary alias information used
when building alias sets and computing alias grouping heuristics. */
static void
find_func_aliases (tree t, struct alias_info *ai)
{
struct constraint_expr lhs, rhs;
switch (TREE_CODE (t))
{
case PHI_NODE:
{
int i;
/* Only care about pointers and structures containing
pointers. */
if (POINTER_TYPE_P (TREE_TYPE (PHI_RESULT (t)))
|| AGGREGATE_TYPE_P (TREE_TYPE (PHI_RESULT (t))))
{
lhs = get_constraint_for (PHI_RESULT (t));
for (i = 0; i < PHI_NUM_ARGS (t); i++)
{
rhs = get_constraint_for (PHI_ARG_DEF (t, i));
process_constraint (new_constraint (lhs, rhs));
}
}
}
break;
/* Update various related attributes like escaped addresses, pointer
dereferences for loads and stores. This is used when creating
name tags and alias sets. */
update_alias_info (t, ai);
case MODIFY_EXPR:
{
tree lhsop = TREE_OPERAND (t, 0);
tree rhsop = TREE_OPERAND (t, 1);
int i;
/* Now build constraints expressions. */
if (TREE_CODE (t) == PHI_NODE)
{
/* Only care about pointers and structures containing
pointers. */
if (POINTER_TYPE_P (TREE_TYPE (PHI_RESULT (t)))
|| AGGREGATE_TYPE_P (TREE_TYPE (PHI_RESULT (t))))
{
int i;
if (AGGREGATE_TYPE_P (TREE_TYPE (lhsop))
&& AGGREGATE_TYPE_P (TREE_TYPE (rhsop)))
{
do_structure_copy (lhsop, rhsop);
}
else
{
/* Only care about operations with pointers, structures
containing pointers, dereferences, and call
expressions. */
if (POINTER_TYPE_P (TREE_TYPE (lhsop))
|| AGGREGATE_TYPE_P (TREE_TYPE (lhsop))
|| ref_contains_indirect_ref (lhsop)
|| TREE_CODE (rhsop) == CALL_EXPR)
{
lhs = get_constraint_for (lhsop);
switch (TREE_CODE_CLASS (TREE_CODE (rhsop)))
{
/* RHS that consist of unary operations,
exceptional types, or bare decls/constants, get
handled directly by get_constraint_for. */
lhs = get_constraint_for (PHI_RESULT (t));
for (i = 0; i < PHI_NUM_ARGS (t); i++)
{
rhs = get_constraint_for (PHI_ARG_DEF (t, i));
process_constraint (new_constraint (lhs, rhs));
}
}
}
else if (TREE_CODE (t) == MODIFY_EXPR)
{
tree lhsop = TREE_OPERAND (t, 0);
tree rhsop = TREE_OPERAND (t, 1);
int i;
if (AGGREGATE_TYPE_P (TREE_TYPE (lhsop))
&& AGGREGATE_TYPE_P (TREE_TYPE (rhsop)))
{
do_structure_copy (lhsop, rhsop);
}
else
{
/* Only care about operations with pointers, structures
containing pointers, dereferences, and call expressions. */
if (POINTER_TYPE_P (TREE_TYPE (lhsop))
|| AGGREGATE_TYPE_P (TREE_TYPE (lhsop))
|| ref_contains_indirect_ref (lhsop)
|| TREE_CODE (rhsop) == CALL_EXPR)
{
lhs = get_constraint_for (lhsop);
switch (TREE_CODE_CLASS (TREE_CODE (rhsop)))
{
/* RHS that consist of unary operations,
exceptional types, or bare decls/constants, get
handled directly by get_constraint_for. */
case tcc_reference:
case tcc_declaration:
case tcc_constant:
case tcc_exceptional:
case tcc_expression:
case tcc_unary:
{
rhs = get_constraint_for (rhsop);
process_constraint (new_constraint (lhs, rhs));
}
{
rhs = get_constraint_for (rhsop);
process_constraint (new_constraint (lhs, rhs));
/* When taking the address of an aggregate
type, from the LHS we can access any field
of the RHS. */
if (rhs.type == ADDRESSOF
&& rhs.var > anything_id
&& AGGREGATE_TYPE_P (TREE_TYPE (TREE_TYPE (rhsop))))
{
rhs.var = anyoffset_id;
rhs.type = ADDRESSOF;
rhs.offset = 0;
process_constraint (new_constraint (lhs, rhs));
}
}
break;
/* Otherwise, walk each operand. */
case tcc_binary:
{
/* For pointer arithmetic of the form
PTR + CST, we can simply use PTR's
constraint because pointer arithmetic is
not allowed to go out of bounds. */
if (handle_ptr_arith (lhs, rhsop))
break;
}
/* FALLTHRU */
/* Otherwise, walk each operand. Notice that we
can't use the operand interface because we need
to process expressions other than simple operands
(e.g. INDIRECT_REF, ADDR_EXPR, CALL_EXPR). */
default:
for (i = 0; i < TREE_CODE_LENGTH (TREE_CODE (rhsop)); i++)
{
@ -2549,15 +2792,16 @@ find_func_aliases (tree t)
rhs = get_constraint_for (op);
process_constraint (new_constraint (lhs, rhs));
}
}
}
}
}
break;
default:
break;
}
}
}
}
/* After promoting variables and computing aliasing we will
need to re-scan most statements. FIXME: Try to minimize the
number of statements re-scanned. It's not really necessary to
re-scan *all* statements. */
mark_stmt_modified (t);
}
@ -2718,12 +2962,12 @@ create_variable_info_for (tree decl, const char *name)
tree decltype = TREE_TYPE (decl);
bool notokay = false;
bool hasunion;
subvar_t svars;
bool is_global = DECL_P (decl) ? is_global_var (decl) : false;
VEC (fieldoff_s,heap) *fieldstack = NULL;
hasunion = TREE_CODE (decltype) == UNION_TYPE || TREE_CODE (decltype) == QUAL_UNION_TYPE;
hasunion = TREE_CODE (decltype) == UNION_TYPE
|| TREE_CODE (decltype) == QUAL_UNION_TYPE;
if (var_can_have_subvars (decl) && use_field_sensitive && !hasunion)
{
push_fields_onto_fieldstack (decltype, &fieldstack, 0, &hasunion);
@ -2733,62 +2977,6 @@ create_variable_info_for (tree decl, const char *name)
notokay = true;
}
}
/* If this variable already has subvars, just create the variables for the
subvars and we are done.
NOTE: This assumes things haven't generated uses of previously
unused structure fields. */
if (use_field_sensitive
&& !notokay
&& var_can_have_subvars (decl)
&& var_ann (decl)
&& (svars = get_subvars_for_var (decl)))
{
subvar_t sv;
varinfo_t base = NULL;
unsigned int firstindex = index;
for (sv = svars; sv; sv = sv->next)
{
/* For debugging purposes, this will print the names of the
fields as "<var>.<offset>.<size>"
This is only for debugging purposes. */
#define PRINT_LONG_NAMES
#ifdef PRINT_LONG_NAMES
char *tempname;
const char *newname;
asprintf (&tempname,
"%s." HOST_WIDE_INT_PRINT_DEC "." HOST_WIDE_INT_PRINT_DEC,
alias_get_name (decl), sv->offset, sv->size);
newname = ggc_strdup (tempname);
free (tempname);
vi = new_var_info (sv->var, index, newname, index);
#else
vi = new_var_info (sv->var, index, alias_get_name (sv->var), index);
#endif
vi->decl = sv->var;
vi->fullsize = TREE_INT_CST_LOW (TYPE_SIZE (decltype));
vi->size = sv->size;
vi->offset = sv->offset;
if (!base)
{
base = vi;
insert_id_for_tree (decl, index);
}
else
{
insert_into_field_list (base, vi);
}
insert_id_for_tree (sv->var, index);
VEC_safe_push (varinfo_t, gc, varmap, vi);
if (is_global)
make_constraint_to_anything (vi);
index++;
}
return firstindex;
}
/* If the variable doesn't have subvars, we may end up needing to
@ -2935,7 +3123,6 @@ intra_create_variable_infos (void)
lhs.type = SCALAR;
lhs.var = create_variable_info_for (t, alias_get_name (t));
get_varinfo (lhs.var)->is_artificial_var = true;
rhs.var = anything_id;
rhs.type = ADDRESSOF;
rhs.offset = 0;
@ -2958,30 +3145,67 @@ set_uids_in_ptset (bitmap into, bitmap from)
{
unsigned int i;
bitmap_iterator bi;
bool found_anyoffset = false;
subvar_t sv;
EXECUTE_IF_SET_IN_BITMAP (from, 0, i, bi)
{
varinfo_t vi = get_varinfo (i);
/* If we find ANYOFFSET in the solution and the solution
includes SFTs for some structure, then all the SFTs in that
structure will need to be added to the alias set. */
if (vi->id == anyoffset_id)
{
found_anyoffset = true;
continue;
}
/* The only artificial variables that are allowed in a may-alias
set are heap variables. */
if (vi->is_artificial_var && !vi->is_heap_var)
continue;
/* Variables containing unions may need to be converted to their
SFT's, because SFT's can have unions and we cannot. */
if (vi->has_union && get_subvars_for_var (vi->decl) != NULL)
{
subvar_t svars = get_subvars_for_var (vi->decl);
subvar_t sv;
for (sv = svars; sv; sv = sv->next)
/* Variables containing unions may need to be converted to
their SFT's, because SFT's can have unions and we cannot. */
for (sv = get_subvars_for_var (vi->decl); sv; sv = sv->next)
bitmap_set_bit (into, DECL_UID (sv->var));
}
/* We may end up with labels in the points-to set because people
take their address, and they are _DECL's. */
else if (TREE_CODE (vi->decl) == VAR_DECL
|| TREE_CODE (vi->decl) == PARM_DECL)
bitmap_set_bit (into, DECL_UID (vi->decl));
|| TREE_CODE (vi->decl) == PARM_DECL)
{
if (found_anyoffset
&& var_can_have_subvars (vi->decl)
&& get_subvars_for_var (vi->decl))
{
/* If ANYOFFSET is in the solution set and VI->DECL is
an aggregate variable with sub-variables, then any of
the SFTs inside VI->DECL may have been accessed. Add
all the sub-vars for VI->DECL. */
for (sv = get_subvars_for_var (vi->decl); sv; sv = sv->next)
bitmap_set_bit (into, DECL_UID (sv->var));
}
else if (var_can_have_subvars (vi->decl)
&& get_subvars_for_var (vi->decl))
{
/* If VI->DECL is an aggregate for which we created
SFTs, add the SFT corresponding to VI->OFFSET. */
tree sft = get_subvar_at (vi->decl, vi->offset);
bitmap_set_bit (into, DECL_UID (sft));
}
else
{
/* Otherwise, just add VI->DECL to the alias set. */
bitmap_set_bit (into, DECL_UID (vi->decl));
}
}
}
}
static int have_alias_info = false;
static bool have_alias_info = false;
/* Given a pointer variable P, fill in its points-to set, or return
false if we can't. */
@ -2990,8 +3214,10 @@ bool
find_what_p_points_to (tree p)
{
unsigned int id = 0;
if (!have_alias_info)
return false;
if (lookup_id_for_tree (p, &id))
{
varinfo_t vi = get_varinfo (id);
@ -2999,14 +3225,15 @@ find_what_p_points_to (tree p)
if (vi->is_artificial_var)
return false;
/* See if this is a field or a structure */
/* See if this is a field or a structure. */
if (vi->size != vi->fullsize)
{
/* Nothing currently asks about structure fields directly,
but when they do, we need code here to hand back the
points-to set. */
if (!var_can_have_subvars (vi->decl)
|| get_subvars_for_var (vi->decl) == NULL)
return false;
/* Nothing currently asks about structure fields directly, but when
they do, we need code here to hand back the points-to set. */
}
else
{
@ -3018,21 +3245,45 @@ find_what_p_points_to (tree p)
variable. */
vi = get_varinfo (vi->node);
/* Make sure there aren't any artificial vars in the points to set.
XXX: Note that we need to translate our heap variables to
something. */
/* Translate artificial variables into SSA_NAME_PTR_INFO
attributes. */
EXECUTE_IF_SET_IN_BITMAP (vi->solution, 0, i, bi)
{
if (get_varinfo (i)->is_artificial_var)
return false;
varinfo_t vi = get_varinfo (i);
if (vi->is_artificial_var)
{
/* FIXME. READONLY should be handled better so that
flow insensitive aliasing can disregard writeable
aliases. */
if (vi->id == nothing_id)
pi->pt_null = 1;
else if (vi->id == anything_id)
pi->pt_anything = 1;
else if (vi->id == readonly_id)
pi->pt_anything = 1;
else if (vi->id == integer_id)
pi->pt_anything = 1;
else if (vi->is_heap_var)
pi->pt_global_mem = 1;
}
}
pi->pt_anything = false;
if (pi->pt_anything)
return false;
if (!pi->pt_vars)
pi->pt_vars = BITMAP_GGC_ALLOC ();
set_uids_in_ptset (pi->pt_vars, vi->solution);
if (bitmap_empty_p (pi->pt_vars))
pi->pt_vars = NULL;
return true;
}
}
return false;
}
@ -3053,7 +3304,7 @@ dump_sa_points_to_info (FILE *outfile)
{
unsigned int i;
fprintf (outfile, "\nPoints-to information\n\n");
fprintf (outfile, "\nPoints-to sets\n\n");
if (dump_flags & TDF_STATS)
{
@ -3124,6 +3375,7 @@ init_base_vars (void)
rhs.var = anything_id;
rhs.offset = 0;
var_anything->address_taken = true;
/* This specifically does not use process_constraint because
process_constraint ignores all anything = anything constraints, since all
but this one are redundant. */
@ -3177,17 +3429,44 @@ init_base_vars (void)
rhs.var = anything_id;
rhs.offset = 0;
process_constraint (new_constraint (lhs, rhs));
/* Create the ANYOFFSET variable, used to represent an arbitrary offset
inside an object. This is similar to ANYTHING, but less drastic.
It means that the pointer can point anywhere inside an object,
but not outside of it. */
anyoffset_tree = create_tmp_var_raw (void_type_node, "ANYOFFSET");
anyoffset_id = 4;
var_anyoffset = new_var_info (anyoffset_tree, anyoffset_id, "ANYOFFSET",
anyoffset_id);
insert_id_for_tree (anyoffset_tree, anyoffset_id);
var_anyoffset->is_artificial_var = 1;
var_anyoffset->size = ~0;
var_anyoffset->offset = 0;
var_anyoffset->next = NULL;
var_anyoffset->fullsize = ~0;
VEC_safe_push (varinfo_t, gc, varmap, var_anyoffset);
/* ANYOFFSET points to ANYOFFSET. */
lhs.type = SCALAR;
lhs.var = anyoffset_id;
lhs.offset = 0;
rhs.type = ADDRESSOF;
rhs.var = anyoffset_id;
rhs.offset = 0;
process_constraint (new_constraint (lhs, rhs));
}
/* Create points-to sets for the current function. See the comments
at the start of the file for an algorithmic overview. */
static void
create_alias_vars (void)
void
compute_points_to_sets (struct alias_info *ai)
{
basic_block bb;
timevar_push (TV_TREE_PTA);
init_alias_vars ();
constraint_pool = create_alloc_pool ("Constraint pool",
@ -3201,7 +3480,7 @@ create_alias_vars (void)
varmap = VEC_alloc (varinfo_t, gc, 8);
id_for_tree = htab_create (10, tree_id_hash, tree_id_eq, free);
memset (&stats, 0, sizeof (stats));
init_base_vars ();
intra_create_variable_infos ();
@ -3214,28 +3493,29 @@ create_alias_vars (void)
for (phi = phi_nodes (bb); phi; phi = TREE_CHAIN (phi))
if (is_gimple_reg (PHI_RESULT (phi)))
find_func_aliases (phi);
find_func_aliases (phi, ai);
for (bsi = bsi_start (bb); !bsi_end_p (bsi); bsi_next (&bsi))
find_func_aliases (bsi_stmt (bsi));
find_func_aliases (bsi_stmt (bsi), ai);
}
build_constraint_graph ();
if (dump_file)
{
fprintf (dump_file, "Constraints:\n");
fprintf (dump_file, "Points-to analysis\n\nConstraints:\n\n");
dump_constraints (dump_file);
}
if (dump_file)
fprintf (dump_file, "Collapsing static cycles and doing variable substitution:\n");
fprintf (dump_file, "\nCollapsing static cycles and doing variable "
"substitution:\n");
find_and_collapse_graph_cycles (graph, false);
perform_var_substitution (graph);
if (dump_file)
fprintf (dump_file, "Solving graph:\n");
fprintf (dump_file, "\nSolving graph:\n");
solve_graph (graph);
@ -3243,30 +3523,15 @@ create_alias_vars (void)
dump_sa_points_to_info (dump_file);
have_alias_info = true;
timevar_pop (TV_TREE_PTA);
}
struct tree_opt_pass pass_build_pta =
{
"pta", /* name */
NULL, /* gate */
create_alias_vars, /* execute */
NULL, /* sub */
NULL, /* next */
0, /* static_pass_number */
TV_TREE_PTA, /* tv_id */
PROP_cfg, /* properties_required */
PROP_pta, /* properties_provided */
0, /* properties_destroyed */
0, /* todo_flags_start */
0, /* todo_flags_finish */
0 /* letter */
};
/* Delete created points-to sets. */
static void
delete_alias_vars (void)
void
delete_points_to_sets (void)
{
htab_delete (id_for_tree);
free_alloc_pool (variable_info_pool);
@ -3275,20 +3540,3 @@ delete_alias_vars (void)
bitmap_obstack_release (&ptabitmap_obstack);
have_alias_info = false;
}
struct tree_opt_pass pass_del_pta =
{
NULL, /* name */
NULL, /* gate */
delete_alias_vars, /* execute */
NULL, /* sub */
NULL, /* next */
0, /* static_pass_number */
TV_TREE_PTA, /* tv_id */
PROP_pta, /* properties_required */
0, /* properties_provided */
PROP_pta, /* properties_destroyed */
0, /* todo_flags_start */
0, /* todo_flags_finish */
0 /* letter */
};

View File

@ -25,6 +25,66 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
struct constraint;
typedef struct constraint *constraint_t;
/* Alias information used by compute_may_aliases and its helpers. */
struct alias_info
{
/* SSA names visited while collecting points-to information. If bit I
is set, it means that SSA variable with version I has already been
visited. */
sbitmap ssa_names_visited;
/* Array of SSA_NAME pointers processed by the points-to collector. */
varray_type processed_ptrs;
/* ADDRESSABLE_VARS contains all the global variables and locals that
have had their address taken. */
struct alias_map_d **addressable_vars;
size_t num_addressable_vars;
/* POINTERS contains all the _DECL pointers with unique memory tags
that have been referenced in the program. */
struct alias_map_d **pointers;
size_t num_pointers;
/* Number of function calls found in the program. */
size_t num_calls_found;
/* Number of const/pure function calls found in the program. */
size_t num_pure_const_calls_found;
/* Array of counters to keep track of how many times each pointer has
been dereferenced in the program. This is used by the alias grouping
heuristic in compute_flow_insensitive_aliasing. */
varray_type num_references;
/* Total number of virtual operands that will be needed to represent
all the aliases of all the pointers found in the program. */
long total_alias_vops;
/* Variables that have been written to. */
bitmap written_vars;
/* Pointers that have been used in an indirect store operation. */
bitmap dereferenced_ptrs_store;
/* Pointers that have been used in an indirect load operation. */
bitmap dereferenced_ptrs_load;
};
/* Keep track of how many times each pointer has been dereferenced in
the program using the aux variable. This is used by the alias
grouping heuristic in compute_flow_insensitive_aliasing. */
#define NUM_REFERENCES(ANN) ((size_t)((ANN)->common.aux))
#define NUM_REFERENCES_CLEAR(ANN) ((ANN)->common.aux) = 0
#define NUM_REFERENCES_INC(ANN) (ANN)->common.aux = (void*) (((size_t)((ANN)->common.aux)) + 1)
#define NUM_REFERENCES_SET(ANN, VAL) (ANN)->common.aux = (void*) ((void *)(VAL))
/* In tree-ssa-alias.c. */
bool is_escape_site (tree, struct alias_info *);
/* In tree-ssa-structalias.c. */
extern void compute_points_to_sets (struct alias_info *);
extern void delete_points_to_sets (void);
extern void dump_constraint (FILE *, constraint_t);
extern void dump_constraints (FILE *);
extern void debug_constraint (constraint_t);

View File

@ -467,10 +467,9 @@ verify_flow_sensitive_alias_info (void)
}
if (pi->name_mem_tag
&& !pi->pt_malloc
&& (pi->pt_vars == NULL || bitmap_empty_p (pi->pt_vars)))
{
error ("pointers with a memory tag, should have points-to sets or point to malloc");
error ("pointers with a memory tag, should have points-to sets");
goto err;
}