aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gcc/ChangeLog18
-rw-r--r--gcc/Makefile.in7
-rw-r--r--gcc/tree-flow.h20
-rw-r--r--gcc/tree-optimize.c4
-rw-r--r--gcc/tree-pass.h2
-rw-r--r--gcc/tree-ssa-alias.c110
-rw-r--r--gcc/tree-ssa-structalias.c3165
-rw-r--r--gcc/tree-ssa-structalias.h33
8 files changed, 3260 insertions, 99 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index b419524..0b4abb2 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,21 @@
+2005-06-08 Daniel Berlin <dberlin@dberlin.org>
+
+ * Makefile.in (OBJS-common): Add tree-ssa-structalias.o.
+ * tree-flow.h (find_what_p_points_to): Add prototype.
+ (push_fields_onto_fieldstack): Ditto.
+ (sort_fieldstack): Ditto.
+ * tree-optimize.c (init_tree_optimization_passes): Add
+ pass_build_pta and pass_del_pta.
+ * tree-pass.h (pass_build_pta): New structure.
+ (pass_del_pta): Ditto.
+ * tree-ssa-alias.c (compute_flow_sensitive_aliasing): Disambiguate
+ using new alias analyzer.
+ (push_fields_onto_fieldstack): Removed from here.
+ (bitpos_of_field): Ditto.
+ (fieldoff_compare): Ditto.
+ * tree-ssa-structalias.c: New file.
+ * tree-ssa-structalias.h: Ditto.
+
2005-06-09 Nathan Sidwell <nathan@codesourcery.com>
* c-typeck.c (build_c_cast): Check type punning on COMPONENT_REF
diff --git a/gcc/Makefile.in b/gcc/Makefile.in
index 9e8bbe0..e1b10be 100644
--- a/gcc/Makefile.in
+++ b/gcc/Makefile.in
@@ -962,8 +962,10 @@ OBJS-common = \
varasm.o varray.o vec.o version.o vmsdbgout.o xcoffout.o alloc-pool.o \
et-forest.o cfghooks.o bt-load.o pretty-print.o $(GGC) web.o passes.o \
rtl-profile.o tree-profile.o rtlhooks.o cfgexpand.o lambda-mat.o \
+ lambda-trans.o lambda-code.o tree-loop-linear.o tree-ssa-sink.o \
lambda-trans.o lambda-code.o tree-loop-linear.o tree-ssa-sink.o \
- tree-vrp.o tree-stdarg.o tree-cfgcleanup.o tree-ssa-reassoc.o
+ tree-vrp.o tree-stdarg.o tree-cfgcleanup.o tree-ssa-reassoc.o \
+ tree-ssa-structalias.o
OBJS-md = $(out_object_file)
@@ -1661,6 +1663,9 @@ stor-layout.o : stor-layout.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) \
$(TREE_H) $(PARAMS_H) $(FLAGS_H) function.h $(EXPR_H) $(RTL_H) \
$(GGC_H) $(TM_P_H) $(TARGET_H) langhooks.h $(REGS_H) gt-stor-layout.h \
toplev.h
+tree-ssa-structalias.o: tree-ssa-structalias.c tree-ssa-structalias.h \
+ $(SYSTEM_H) $(CONFIG_H) $(GGC_H) $(TREE_H) $(TREE_FLOW_H) \
+ $(TM_H) coretypes.h cgraph.h tree-pass.h $(TIMEVAR_H)
tree-ssa.o : tree-ssa.c $(TREE_FLOW_H) $(CONFIG_H) $(SYSTEM_H) \
$(RTL_H) $(TREE_H) $(TM_P_H) $(EXPR_H) output.h $(DIAGNOSTIC_H) \
toplev.h function.h $(TIMEVAR_H) $(TM_H) coretypes.h \
diff --git a/gcc/tree-flow.h b/gcc/tree-flow.h
index d318019..5941b5e 100644
--- a/gcc/tree-flow.h
+++ b/gcc/tree-flow.h
@@ -748,6 +748,9 @@ extern bool thread_through_all_blocks (bitmap);
tree force_gimple_operand (tree, tree *, bool, tree);
tree force_gimple_operand_bsi (block_stmt_iterator *, tree, bool, tree);
+/* In tree-ssa-structalias.c */
+bool find_what_p_points_to (tree);
+
/* In tree-ssa-address.c */
/* Affine combination of trees. We keep track of at most MAX_AFF_ELTS elements
@@ -789,6 +792,23 @@ tree create_mem_ref (block_stmt_iterator *, tree,
rtx addr_for_mem_ref (struct mem_address *, bool);
void get_address_description (tree, struct mem_address *);
tree maybe_fold_tmr (tree);
+/* This structure is simply used during pushing fields onto the fieldstack
+ to track the offset of the field, since bitpos_of_field gives it relative
+ to its immediate containing type, and we want it relative to the ultimate
+ containing object. */
+
+struct fieldoff
+{
+ tree field;
+ HOST_WIDE_INT offset;
+};
+typedef struct fieldoff fieldoff_s;
+
+DEF_VEC_O(fieldoff_s);
+DEF_VEC_ALLOC_O(fieldoff_s,heap);
+int push_fields_onto_fieldstack (tree, VEC(fieldoff_s,heap) **,
+ HOST_WIDE_INT, bool *);
+void sort_fieldstack (VEC(fieldoff_s,heap) *);
#include "tree-flow-inline.h"
diff --git a/gcc/tree-optimize.c b/gcc/tree-optimize.c
index 4284a58..0812b64 100644
--- a/gcc/tree-optimize.c
+++ b/gcc/tree-optimize.c
@@ -396,7 +396,9 @@ init_tree_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_del_pta);
NEXT_PASS (pass_rename_ssa_copies);
NEXT_PASS (pass_early_warn_uninitialized);
@@ -412,7 +414,9 @@ init_tree_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);
diff --git a/gcc/tree-pass.h b/gcc/tree-pass.h
index 0d2d8b8..2c405d2 100644
--- a/gcc/tree-pass.h
+++ b/gcc/tree-pass.h
@@ -221,6 +221,8 @@ 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_reassoc;
diff --git a/gcc/tree-ssa-alias.c b/gcc/tree-ssa-alias.c
index ab23cd0..3e885e9 100644
--- a/gcc/tree-ssa-alias.c
+++ b/gcc/tree-ssa-alias.c
@@ -874,7 +874,16 @@ static void
compute_flow_sensitive_aliasing (struct alias_info *ai)
{
size_t i;
-
+
+ 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);
+ }
+ }
create_name_tags (ai);
for (i = 0; i < VARRAY_ACTIVE_SIZE (ai->processed_ptrs); i++)
@@ -2810,82 +2819,6 @@ new_type_alias (tree ptr, tree var)
/* Note, TAG and its set of aliases are not marked for renaming. */
}
-
-/* This structure is simply used during pushing fields onto the fieldstack
- to track the offset of the field, since bitpos_of_field gives it relative
- to its immediate containing type, and we want it relative to the ultimate
- containing object. */
-
-typedef struct fieldoff
-{
- tree field;
- HOST_WIDE_INT offset;
-} fieldoff_s;
-
-DEF_VEC_O (fieldoff_s);
-DEF_VEC_ALLOC_O(fieldoff_s,heap);
-
-/* Return the position, in bits, of FIELD_DECL from the beginning of its
- structure.
- Return -1 if the position is conditional or otherwise non-constant
- integer. */
-
-static HOST_WIDE_INT
-bitpos_of_field (const tree fdecl)
-{
-
- if (TREE_CODE (DECL_FIELD_OFFSET (fdecl)) != INTEGER_CST
- || TREE_CODE (DECL_FIELD_BIT_OFFSET (fdecl)) != INTEGER_CST)
- return -1;
-
- return (tree_low_cst (DECL_FIELD_OFFSET (fdecl), 1) * 8)
- + tree_low_cst (DECL_FIELD_BIT_OFFSET (fdecl), 1);
-}
-
-/* Given a TYPE, and a vector of field offsets FIELDSTACK, push all the fields
- of TYPE onto fieldstack, recording their offsets along the way.
- OFFSET is used to keep track of the offset in this entire structure, rather
- than just the immediately containing structure. Returns the number
- of fields pushed. */
-
-static int
-push_fields_onto_fieldstack (tree type, VEC(fieldoff_s,heap) **fieldstack,
- HOST_WIDE_INT offset)
-{
- tree field;
- int count = 0;
-
- for (field = TYPE_FIELDS (type); field; field = TREE_CHAIN (field))
- if (TREE_CODE (field) == FIELD_DECL)
- {
- bool push = false;
-
- if (!var_can_have_subvars (field))
- push = true;
- else if (!(push_fields_onto_fieldstack
- (TREE_TYPE (field), fieldstack,
- offset + bitpos_of_field (field)))
- && DECL_SIZE (field)
- && !integer_zerop (DECL_SIZE (field)))
- /* Empty structures may have actual size, like in C++. So
- see if we didn't push any subfields and the size is
- nonzero, push the field onto the stack */
- push = true;
-
- if (push)
- {
- fieldoff_s *pair;
-
- pair = VEC_safe_push (fieldoff_s, heap, *fieldstack, NULL);
- pair->field = field;
- pair->offset = offset + bitpos_of_field (field);
- count++;
- }
- }
- return count;
-}
-
-
/* This represents the used range of a variable. */
typedef struct used_part
@@ -2925,22 +2858,6 @@ get_or_create_used_part_for (size_t uid)
return up;
}
-/* qsort comparison function for two fieldoff's PA and PB */
-
-static int
-fieldoff_compare (const void *pa, const void *pb)
-{
- const fieldoff_s *foa = (const fieldoff_s *)pa;
- const fieldoff_s *fob = (const fieldoff_s *)pb;
- HOST_WIDE_INT foasize, fobsize;
-
- if (foa->offset != fob->offset)
- return foa->offset - fob->offset;
-
- foasize = TREE_INT_CST_LOW (DECL_SIZE (foa->field));
- fobsize = TREE_INT_CST_LOW (DECL_SIZE (fob->field));
- return foasize - fobsize;
-}
/* Given an aggregate VAR, create the subvariables that represent its
fields. */
@@ -2956,7 +2873,7 @@ create_overlap_variables_for (tree var)
return;
up = used_portions[uid];
- push_fields_onto_fieldstack (TREE_TYPE (var), &fieldstack, 0);
+ push_fields_onto_fieldstack (TREE_TYPE (var), &fieldstack, 0, NULL);
if (VEC_length (fieldoff_s, fieldstack) != 0)
{
subvar_t *subvars;
@@ -3024,10 +2941,7 @@ create_overlap_variables_for (tree var)
/* Otherwise, create the variables. */
subvars = lookup_subvars_for_var (var);
- qsort (VEC_address (fieldoff_s, fieldstack),
- VEC_length (fieldoff_s, fieldstack),
- sizeof (fieldoff_s),
- fieldoff_compare);
+ sort_fieldstack (fieldstack);
for (i = VEC_length (fieldoff_s, fieldstack);
VEC_iterate (fieldoff_s, fieldstack, --i, fo);)
diff --git a/gcc/tree-ssa-structalias.c b/gcc/tree-ssa-structalias.c
new file mode 100644
index 0000000..d3b0b82
--- /dev/null
+++ b/gcc/tree-ssa-structalias.c
@@ -0,0 +1,3165 @@
+/* Tree based points-to analysis
+ Copyright (C) 2005 Free Software Foundation, Inc.
+ Contributed by Daniel Berlin <dberlin@dberlin.org>
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify
+under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+GCC is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "tm.h"
+#include "ggc.h"
+#include "obstack.h"
+#include "bitmap.h"
+#include "tree-ssa-structalias.h"
+#include "flags.h"
+#include "rtl.h"
+#include "tm_p.h"
+#include "hard-reg-set.h"
+#include "basic-block.h"
+#include "output.h"
+#include "errors.h"
+#include "expr.h"
+#include "diagnostic.h"
+#include "tree.h"
+#include "c-common.h"
+#include "tree-flow.h"
+#include "tree-inline.h"
+#include "varray.h"
+#include "c-tree.h"
+#include "tree-gimple.h"
+#include "hashtab.h"
+#include "function.h"
+#include "cgraph.h"
+#include "tree-pass.h"
+#include "timevar.h"
+#include "alloc-pool.h"
+#include "splay-tree.h"
+
+/* The idea behind this analyzer is to generate set constraints from the
+ program, then solve the resulting constraints in order to generate the
+ points-to sets.
+
+ Set constraints are a way of modeling program analysis problems that
+ involve sets. They consist of an inclusion constraint language,
+ describing the variables (each variable is a set) and operations that
+ are involved on the variables, and a set of rules that derive facts
+ from these operations. To solve a system of set constraints, you derive
+ all possible facts under the rules, which gives you the correct sets
+ as a consequence.
+
+ See "Efficient Field-sensitive pointer analysis for C" by "David
+ J. Pearce and Paul H. J. Kelly and Chris Hankin, at
+ http://citeseer.ist.psu.edu/pearce04efficient.html
+
+ Also see "Ultra-fast Aliasing Analysis using CLA: A Million Lines
+ of C Code in a Second" by ""Nevin Heintze and Olivier Tardieu" at
+ http://citeseer.ist.psu.edu/heintze01ultrafast.html
+
+ There are three types of constraint expressions, DEREF, ADDRESSOF, and
+ SCALAR. Each constraint expression consists of a constraint type,
+ a variable, and an offset.
+
+ SCALAR is a constraint expression type used to represent x, whether
+ it appears on the LHS or the RHS of a statement.
+ DEREF is a constraint expression type used to represent *x, whether
+ it appears on the LHS or the RHS of a statement.
+ ADDRESSOF is a constraint expression used to represent &x, whether
+ it apepars on the LHS or the RHS of a statement.
+
+ Each pointer variable in the program is assigned an integer id, and
+ each field of a structure variable is assigned an integer id as well.
+
+ Structure variables are linked to their list of fields through a "next
+ field" in each variable that points to the next field in offset
+ order.
+ Each variable for a structure field has
+
+ 1. "size", that tells the size in bits of that field.
+ 2. "fullsize, that tells the size in bits of the entire structure.
+ 3. "offset", that tells the offset in bits from the beginning of the
+ structure to this field.
+
+ Thus,
+ struct f
+ {
+ int a;
+ int b;
+ } foo;
+ int *bar;
+
+ looks like
+
+ foo.a -> id 1, size 32, offset 0, fullsize 64, next foo.b
+ foo.b -> id 2, size 32, offset 32, fullsize 64, next NULL
+ bar -> id 3, size 32, offset 0, fullsize 32, next NULL
+
+
+ In order to solve the system of set constraints, the following is
+ done:
+
+ 1. Each constraint variable x has a solution set associated with it,
+ Sol(x).
+
+ 2. Constraints are separated into direct, copy, and complex.
+ Direct constraints are ADDRESSOF constraints that require no extra
+ processing, such as P = &Q
+ Copy constraints are those of the form P = Q.
+ Complex constraints are all the constraints involving dereferences.
+
+ 3. All direct constraints of the form P = &Q are processed, such
+ that Q is added to Sol(P)
+
+ 4. All complex constraints for a given constraint variable are stored in a
+ linked list attached to that variable's node.
+
+ 5. A directed graph is built out of the copy constraints. Each
+ constraint variable is a node in the graph, and an edge from
+ Q to P is added for each copy constraint of the form P = Q
+
+ 6. The graph is then walked, and solution sets are
+ propagated along the copy edges, such that an edge from Q to P
+ causes Sol(P) <- Sol(P) union Sol(Q).
+
+ 7. As we visit each node, all complex constraints associated with
+ that node are processed by adding approriate copy edges to the graph, or the
+ approriate variables to the solution set.
+
+ 8. The process of walking the graph is iterated until no solution
+ sets change.
+
+ Prior to walking the graph in steps 6 and 7, We perform static
+ cycle elimination on the constraint graph, as well
+ as off-line variable substitution.
+
+ TODO: Adding offsets to pointer-to-structures can be handled (IE not punted
+ on and turned into anything), but isn't. You can just see what offset
+ inside the pointed-to struct it's going to access.
+
+ TODO: Constant bounded arrays can be handled as if they were structs of the
+ same number of elements.
+
+ TODO: Modeling heap and incoming pointers becomes much better if we
+ add fields to them as we discover them, which we could do.
+
+ TODO: We could handle unions, but to be honest, it's probably not
+ worth the pain or slowdown. */
+
+static bool use_field_sensitive = true;
+static unsigned int create_variable_info_for (tree, const char *);
+static struct constraint_expr get_constraint_for (tree);
+static void build_constraint_graph (void);
+
+static bitmap_obstack ptabitmap_obstack;
+static bitmap_obstack iteration_obstack;
+DEF_VEC_P(constraint_t);
+DEF_VEC_ALLOC_P(constraint_t,gc);
+
+static struct constraint_stats
+{
+ unsigned int total_vars;
+ unsigned int collapsed_vars;
+ unsigned int unified_vars_static;
+ unsigned int unified_vars_dynamic;
+ unsigned int iterations;
+} stats;
+
+struct variable_info
+{
+ /* ID of this variable */
+ unsigned int id;
+
+ /* Name of this variable */
+ const char *name;
+
+ /* Tree that this variable is associated with. */
+ tree decl;
+
+ /* Offset of this variable, in bits, from the base variable */
+ unsigned HOST_WIDE_INT offset;
+
+ /* Size of the variable, in bits. */
+ unsigned HOST_WIDE_INT size;
+
+ /* Full size of the base variable, in bits. */
+ unsigned HOST_WIDE_INT fullsize;
+
+ /* A link to the variable for the next field in this structure. */
+ struct variable_info *next;
+
+ /* Node in the graph that represents the constraints and points-to
+ solution for the variable. */
+ unsigned int node;
+
+ /* True if the address of this variable is taken. Needed for
+ variable substitution. */
+ unsigned int address_taken:1;
+
+ /* True if this variable is the target of a dereference. Needed for
+ variable substitution. */
+ unsigned int indirect_target:1;
+
+ /* True if this is a variable created by the constraint analysis, such as
+ heap variables and constraints we had to break up. */
+ unsigned int is_artificial_var:1;
+
+ /* True for variables whose size is not known or variable. */
+ unsigned int is_unknown_size_var:1;
+
+ /* Points-to set for this variable. */
+ bitmap solution;
+
+ /* Variable ids represented by this node. */
+ bitmap variables;
+
+ /* Vector of complex constraints for this node. Complex
+ constraints are those involving dereferences. */
+ VEC(constraint_t,gc) *complex;
+};
+typedef struct variable_info *varinfo_t;
+
+static varinfo_t first_vi_for_offset (varinfo_t, unsigned HOST_WIDE_INT);
+
+/* Pool of variable info structures. */
+static alloc_pool variable_info_pool;
+
+DEF_VEC_P(varinfo_t);
+
+DEF_VEC_ALLOC_P(varinfo_t, gc);
+
+/* Table of variable info structures for constraint variables. Indexed direcly
+ by variable info id. */
+static VEC(varinfo_t,gc) *varmap;
+#define get_varinfo(n) VEC_index(varinfo_t, varmap, n)
+
+/* Variable that represents the unknown pointer. */
+static varinfo_t var_anything;
+static tree anything_tree;
+static unsigned int anything_id;
+
+/* Variable that represents the NULL pointer. */
+static varinfo_t var_nothing;
+static tree nothing_tree;
+static unsigned int nothing_id;
+
+/* Variable that represents read only memory. */
+static varinfo_t var_readonly;
+static tree readonly_tree;
+static unsigned int readonly_id;
+
+/* Variable that represents integers. This is used for when people do things
+ like &0->a.b. */
+static varinfo_t var_integer;
+static tree integer_tree;
+static unsigned int integer_id;
+
+
+/* Return a new variable info structure consisting for a variable
+ named NAME, and using constraint graph node NODE. */
+
+static varinfo_t
+new_var_info (tree t, unsigned int id, const char *name, unsigned int node)
+{
+ varinfo_t ret = pool_alloc (variable_info_pool);
+
+ ret->id = id;
+ ret->name = name;
+ ret->decl = t;
+ ret->node = node;
+ ret->address_taken = false;
+ ret->indirect_target = false;
+ ret->is_artificial_var = false;
+ ret->is_unknown_size_var = false;
+ ret->solution = BITMAP_ALLOC (&ptabitmap_obstack);
+ bitmap_clear (ret->solution);
+ ret->variables = BITMAP_ALLOC (&ptabitmap_obstack);
+ bitmap_clear (ret->variables);
+ ret->complex = NULL;
+ ret->next = NULL;
+ return ret;
+}
+
+typedef enum {SCALAR, DEREF, ADDRESSOF} constraint_expr_type;
+
+/* An expression that appears in a constraint. */
+
+struct constraint_expr
+{
+ /* Constraint type. */
+ constraint_expr_type type;
+
+ /* Variable we are referring to in the constraint. */
+ unsigned int var;
+
+ /* Offset, in bits, of this constraint from the beginning of
+ variables it ends up referring to.
+
+ IOW, in a deref constraint, we would deref, get the result set,
+ then add OFFSET to each member. */
+ unsigned HOST_WIDE_INT offset;
+};
+
+static struct constraint_expr do_deref (struct constraint_expr);
+
+/* Our set constraints are made up of two constraint expressions, one
+ LHS, and one RHS.
+
+ As described in the introduction, our set constraints each represent an
+ operation between set valued variables.
+*/
+struct constraint
+{
+ struct constraint_expr lhs;
+ struct constraint_expr rhs;
+};
+
+/* List of constraints that we use to build the constraint graph from. */
+
+static VEC(constraint_t,gc) *constraints;
+static alloc_pool constraint_pool;
+
+/* An edge in the constraint graph. We technically have no use for
+ the src, since it will always be the same node that we are indexing
+ into the pred/succ arrays with, but it's nice for checking
+ purposes. The edges are weighted, with a bit set in weights for
+ each edge from src to dest with that weight. */
+
+struct constraint_edge
+{
+ unsigned int src;
+ unsigned int dest;
+ bitmap weights;
+};
+
+typedef struct constraint_edge *constraint_edge_t;
+static alloc_pool constraint_edge_pool;
+
+/* Return a new constraint edge from SRC to DEST. */
+
+static constraint_edge_t
+new_constraint_edge (unsigned int src, unsigned int dest)
+{
+ constraint_edge_t ret = pool_alloc (constraint_edge_pool);
+ ret->src = src;
+ ret->dest = dest;
+ ret->weights = NULL;
+ return ret;
+}
+
+DEF_VEC_P(constraint_edge_t);
+DEF_VEC_ALLOC_P(constraint_edge_t,gc);
+
+
+/* The constraint graph is simply a set of adjacency vectors, one per
+ variable. succs[x] is the vector of successors for variable x, and preds[x]
+ is the vector of predecessors for variable x.
+ IOW, all edges are "forward" edges, which is not like our CFG.
+ So remember that
+ preds[x]->src == x, and
+ succs[x]->src == x*/
+
+struct constraint_graph
+{
+ VEC(constraint_edge_t,gc) **succs;
+ VEC(constraint_edge_t,gc) **preds;
+};
+
+typedef struct constraint_graph *constraint_graph_t;
+
+static constraint_graph_t graph;
+
+/* Create a new constraint consisting of LHS and RHS expressions. */
+
+static constraint_t
+new_constraint (const struct constraint_expr lhs,
+ const struct constraint_expr rhs)
+{
+ constraint_t ret = pool_alloc (constraint_pool);
+ ret->lhs = lhs;
+ ret->rhs = rhs;
+ return ret;
+}
+
+/* Print out constraint C to FILE. */
+
+void
+dump_constraint (FILE *file, constraint_t c)
+{
+ if (c->lhs.type == ADDRESSOF)
+ fprintf (file, "&");
+ else if (c->lhs.type == DEREF)
+ fprintf (file, "*");
+ fprintf (file, "%s", get_varinfo (c->lhs.var)->name);
+ if (c->lhs.offset != 0)
+ fprintf (file, " + " HOST_WIDE_INT_PRINT_DEC, c->lhs.offset);
+ fprintf (file, " = ");
+ if (c->rhs.type == ADDRESSOF)
+ fprintf (file, "&");
+ else if (c->rhs.type == DEREF)
+ fprintf (file, "*");
+ fprintf (file, "%s", get_varinfo (c->rhs.var)->name);
+ if (c->rhs.offset != 0)
+ fprintf (file, " + " HOST_WIDE_INT_PRINT_DEC, c->rhs.offset);
+ fprintf (file, "\n");
+}
+
+/* Print out constraint C to stderr. */
+
+void
+debug_constraint (constraint_t c)
+{
+ dump_constraint (stderr, c);
+}
+
+/* Print out all constraints to FILE */
+
+void
+dump_constraints (FILE *file)
+{
+ int i;
+ constraint_t c;
+ for (i = 0; VEC_iterate (constraint_t, constraints, i, c); i++)
+ dump_constraint (file, c);
+}
+
+/* Print out all constraints to stderr. */
+
+void
+debug_constraints (void)
+{
+ dump_constraints (stderr);
+}
+
+/* SOLVER FUNCTIONS
+
+ The solver is a simple worklist solver, that works on the following
+ algorithm:
+
+ sbitmap changed_nodes = all ones;
+ changed_count = number of nodes;
+ For each node that was already collapsed:
+ changed_count--;
+
+
+ while (changed_count > 0)
+ {
+ compute topological ordering for constraint graph
+
+ find and collapse cycles in the constraint graph (updating
+ changed if necessary)
+
+ for each node (n) in the graph in topological order:
+ changed_count--;
+
+ Process each complex constraint associated with the node,
+ updating changed if necessary.
+
+ For each outgoing edge from n, propagate the solution from n to
+ the destination of the edge, updating changed as necessary.
+
+ } */
+
+/* Return true if two constraint expressions A and B are equal. */
+
+static bool
+constraint_expr_equal (struct constraint_expr a, struct constraint_expr b)
+{
+ return a.type == b.type
+ && a.var == b.var
+ && a.offset == b.offset;
+}
+
+/* Return true if constraint expression A is less than constraint expression
+ B. This is just arbitrary, but consistent, in order to give them an
+ ordering. */
+
+static bool
+constraint_expr_less (struct constraint_expr a, struct constraint_expr b)
+{
+ if (a.type == b.type)
+ {
+ if (a.var == b.var)
+ return a.offset < b.offset;
+ else
+ return a.var < b.var;
+ }
+ else
+ return a.type < b.type;
+}
+
+/* Return true if constraint A is less than constraint B. This is just
+ arbitrary, but consistent, in order to give them an ordering. */
+
+static bool
+constraint_less (const constraint_t a, const constraint_t b)
+{
+ if (constraint_expr_less (a->lhs, b->lhs))
+ return true;
+ else if (constraint_expr_less (b->lhs, a->lhs))
+ return false;
+ else
+ return constraint_expr_less (a->rhs, b->rhs);
+}
+
+/* Return true if two constraints A and B are equal. */
+
+static bool
+constraint_equal (struct constraint a, struct constraint b)
+{
+ return constraint_expr_equal (a.lhs, b.lhs)
+ && constraint_expr_equal (a.rhs, b.rhs);
+}
+
+
+/* Find a constraint LOOKFOR in the sorted constraint vector VEC */
+
+static constraint_t
+constraint_vec_find (VEC(constraint_t,gc) *vec,
+ struct constraint lookfor)
+{
+ unsigned int place;
+ constraint_t found;
+
+ if (vec == NULL)
+ return NULL;
+
+ place = VEC_lower_bound (constraint_t, vec, &lookfor, constraint_less);
+ if (place >= VEC_length (constraint_t, vec))
+ return NULL;
+ found = VEC_index (constraint_t, vec, place);
+ if (!constraint_equal (*found, lookfor))
+ return NULL;
+ return found;
+}
+
+/* Union two constraint vectors, TO and FROM. Put the result in TO. */
+
+static void
+constraint_set_union (VEC(constraint_t,gc) **to,
+ VEC(constraint_t,gc) **from)
+{
+ int i;
+ constraint_t c;
+
+ for (i = 0; VEC_iterate (constraint_t, *from, i, c); i++)
+ {
+ if (constraint_vec_find (*to, *c) == NULL)
+ {
+ unsigned int place = VEC_lower_bound (constraint_t, *to, c,
+ constraint_less);
+ VEC_safe_insert (constraint_t, gc, *to, place, c);
+ }
+ }
+}
+
+/* Take a solution set SET, add OFFSET to each member of the set, and
+ overwrite SET with the result when done. */
+
+static void
+solution_set_add (bitmap set, unsigned HOST_WIDE_INT offset)
+{
+ bitmap result = BITMAP_ALLOC (&iteration_obstack);
+ unsigned int i;
+ bitmap_iterator bi;
+
+ EXECUTE_IF_SET_IN_BITMAP (set, 0, i, bi)
+ {
+ /* If this is a properly sized variable, only add offset if it's
+ less than end. Otherwise, it is globbed to a single
+ variable. */
+
+ if ((get_varinfo (i)->offset + offset) < get_varinfo (i)->fullsize)
+ {
+ unsigned HOST_WIDE_INT fieldoffset = get_varinfo (i)->offset + offset;
+ varinfo_t v = first_vi_for_offset (get_varinfo (i), fieldoffset);
+ bitmap_set_bit (result, v->id);
+ }
+ else if (get_varinfo (i)->is_artificial_var
+ || get_varinfo (i)->is_unknown_size_var)
+ {
+ bitmap_set_bit (result, i);
+ }
+ }
+
+ bitmap_copy (set, result);
+ BITMAP_FREE (result);
+}
+
+/* Union solution sets TO and FROM, and add INC to each member of FROM in the
+ process. */
+
+static bool
+set_union_with_increment (bitmap to, bitmap from, unsigned HOST_WIDE_INT inc)
+{
+ if (inc == 0)
+ return bitmap_ior_into (to, from);
+ else
+ {
+ bitmap tmp;
+ bool res;
+
+ tmp = BITMAP_ALLOC (&iteration_obstack);
+ bitmap_copy (tmp, from);
+ solution_set_add (tmp, inc);
+ res = bitmap_ior_into (to, tmp);
+ BITMAP_FREE (tmp);
+ return res;
+ }
+}
+
+/* Insert constraint C into the list of complex constraints for VAR. */
+
+static void
+insert_into_complex (unsigned int var, constraint_t c)
+{
+ varinfo_t vi = get_varinfo (var);
+ unsigned int place = VEC_lower_bound (constraint_t, vi->complex, c,
+ constraint_less);
+ VEC_safe_insert (constraint_t, gc, vi->complex, place, c);
+}
+
+
+/* Compare two constraint edges A and B, return true if they are equal. */
+
+static bool
+constraint_edge_equal (struct constraint_edge a, struct constraint_edge b)
+{
+ return a.src == b.src && a.dest == b.dest;
+}
+
+/* Compare two constraint edges, return true if A is less than B */
+
+static bool
+constraint_edge_less (const constraint_edge_t a, const constraint_edge_t b)
+{
+ if (a->dest < b->dest)
+ return true;
+ else if (a->dest == b->dest)
+ return a->src < b->src;
+ else
+ return false;
+}
+
+/* Find the constraint edge that matches LOOKFOR, in VEC.
+ Return the edge, if found, NULL otherwise. */
+
+static constraint_edge_t
+constraint_edge_vec_find (VEC(constraint_edge_t,gc) *vec,
+ struct constraint_edge lookfor)
+{
+ unsigned int place;
+ constraint_edge_t edge;
+
+ place = VEC_lower_bound (constraint_edge_t, vec, &lookfor,
+ constraint_edge_less);
+ edge = VEC_index (constraint_edge_t, vec, place);
+ if (!constraint_edge_equal (*edge, lookfor))
+ return NULL;
+ return edge;
+}
+
+/* Condense two variable nodes into a single variable node, by moving
+ all associated info from SRC to TO. */
+
+static void
+condense_varmap_nodes (unsigned int to, unsigned int src)
+{
+ varinfo_t tovi = get_varinfo (to);
+ varinfo_t srcvi = get_varinfo (src);
+ unsigned int i;
+ constraint_t c;
+ bitmap_iterator bi;
+
+ /* the src node, and all its variables, are now the to node. */
+ srcvi->node = to;
+ EXECUTE_IF_SET_IN_BITMAP (srcvi->variables, 0, i, bi)
+ get_varinfo (i)->node = to;
+
+ /* Merge the src node variables and the to node variables. */
+ bitmap_set_bit (tovi->variables, src);
+ bitmap_ior_into (tovi->variables, srcvi->variables);
+ bitmap_clear (srcvi->variables);
+
+ /* Move all complex constraints from src node into to node */
+ for (i = 0; VEC_iterate (constraint_t, srcvi->complex, i, c); i++)
+ {
+ /* In complex constraints for node src, we may have either
+ a = *src, and *src = a. */
+
+ if (c->rhs.type == DEREF)
+ c->rhs.var = to;
+ else
+ c->lhs.var = to;
+ }
+ constraint_set_union (&tovi->complex, &srcvi->complex);
+ srcvi->complex = NULL;
+}
+
+/* Erase EDGE from GRAPH. This routine only handles self-edges
+ (e.g. an edge from a to a). */
+
+static void
+erase_graph_self_edge (constraint_graph_t graph, struct constraint_edge edge)
+{
+ VEC(constraint_edge_t,gc) *predvec = graph->preds[edge.src];
+ VEC(constraint_edge_t,gc) *succvec = graph->succs[edge.dest];
+ unsigned int place;
+ gcc_assert (edge.src == edge.dest);
+
+ /* Remove from the successors. */
+ place = VEC_lower_bound (constraint_edge_t, succvec, &edge,
+ constraint_edge_less);
+
+ /* Make sure we found the edge. */
+#ifdef ENABLE_CHECKING
+ {
+ constraint_edge_t tmp = VEC_index (constraint_edge_t, succvec, place);
+ gcc_assert (constraint_edge_equal (*tmp, edge));
+ }
+#endif
+ VEC_ordered_remove (constraint_edge_t, succvec, place);
+
+ /* Remove from the predecessors. */
+ place = VEC_lower_bound (constraint_edge_t, predvec, &edge,
+ constraint_edge_less);
+
+ /* Make sure we found the edge. */
+#ifdef ENABLE_CHECKING
+ {
+ constraint_edge_t tmp = VEC_index (constraint_edge_t, predvec, place);
+ gcc_assert (constraint_edge_equal (*tmp, edge));
+ }
+#endif
+ VEC_ordered_remove (constraint_edge_t, predvec, place);
+}
+
+/* Remove edges involving NODE from GRAPH. */
+
+static void
+clear_edges_for_node (constraint_graph_t graph, unsigned int node)
+{
+ VEC(constraint_edge_t,gc) *succvec = graph->succs[node];
+ VEC(constraint_edge_t,gc) *predvec = graph->preds[node];
+ constraint_edge_t c;
+ int i;
+
+ /* Walk the successors, erase the associated preds. */
+ for (i = 0; VEC_iterate (constraint_edge_t, succvec, i, c); i++)
+ if (c->dest != node)
+ {
+ unsigned int place;
+ struct constraint_edge lookfor;
+ lookfor.src = c->dest;
+ lookfor.dest = node;
+ place = VEC_lower_bound (constraint_edge_t, graph->preds[c->dest],
+ &lookfor, constraint_edge_less);
+ VEC_ordered_remove (constraint_edge_t, graph->preds[c->dest], place);
+ }
+ /* Walk the preds, erase the associated succs. */
+ for (i =0; VEC_iterate (constraint_edge_t, predvec, i, c); i++)
+ if (c->dest != node)
+ {
+ unsigned int place;
+ struct constraint_edge lookfor;
+ lookfor.src = c->dest;
+ lookfor.dest = node;
+ place = VEC_lower_bound (constraint_edge_t, graph->succs[c->dest],
+ &lookfor, constraint_edge_less);
+ VEC_ordered_remove (constraint_edge_t, graph->succs[c->dest], place);
+ }
+
+ graph->preds[node] = NULL;
+ graph->succs[node] = NULL;
+}
+
+static bool edge_added = false;
+
+/* Add edge NEWE to the graph. */
+
+static bool
+add_graph_edge (constraint_graph_t graph, struct constraint_edge newe)
+{
+ unsigned int place;
+ unsigned int src = newe.src;
+ unsigned int dest = newe.dest;
+ VEC(constraint_edge_t,gc) *vec;
+
+ vec = graph->preds[src];
+ place = VEC_lower_bound (constraint_edge_t, vec, &newe,
+ constraint_edge_less);
+ if (place == VEC_length (constraint_edge_t, vec)
+ || VEC_index (constraint_edge_t, vec, place)->dest != dest)
+ {
+ constraint_edge_t edge = new_constraint_edge (src, dest);
+ bitmap weightbitmap;
+
+ weightbitmap = BITMAP_ALLOC (&ptabitmap_obstack);
+ edge->weights = weightbitmap;
+ VEC_safe_insert (constraint_edge_t, gc, graph->preds[edge->src],
+ place, edge);
+ edge = new_constraint_edge (dest, src);
+ edge->weights = weightbitmap;
+ place = VEC_lower_bound (constraint_edge_t, graph->succs[edge->src],
+ edge, constraint_edge_less);
+ VEC_safe_insert (constraint_edge_t, gc, graph->succs[edge->src],
+ place, edge);
+ edge_added = true;
+ return true;
+ }
+ else
+ return false;
+}
+
+
+/* Return the bitmap representing the weights of edge LOOKFOR */
+
+static bitmap
+get_graph_weights (constraint_graph_t graph, struct constraint_edge lookfor)
+{
+ constraint_edge_t edge;
+ unsigned int src = lookfor.src;
+ VEC(constraint_edge_t,gc) *vec;
+ vec = graph->preds[src];
+ edge = constraint_edge_vec_find (vec, lookfor);
+ gcc_assert (edge != NULL);
+ return edge->weights;
+}
+
+
+/* Merge GRAPH nodes FROM and TO into node TO. */
+
+static void
+merge_graph_nodes (constraint_graph_t graph, unsigned int to,
+ unsigned int from)
+{
+ VEC(constraint_edge_t,gc) *succvec = graph->succs[from];
+ VEC(constraint_edge_t,gc) *predvec = graph->preds[from];
+ int i;
+ constraint_edge_t c;
+
+ /* Merge all the predecessor edges. */
+
+ for (i = 0; VEC_iterate (constraint_edge_t, predvec, i, c); i++)
+ {
+ unsigned int d = c->dest;
+ struct constraint_edge olde;
+ struct constraint_edge newe;
+ bitmap temp;
+ bitmap weights;
+ if (c->dest == from)
+ d = to;
+ newe.src = to;
+ newe.dest = d;
+ add_graph_edge (graph, newe);
+ olde.src = from;
+ olde.dest = c->dest;
+ temp = get_graph_weights (graph, olde);
+ weights = get_graph_weights (graph, newe);
+ bitmap_ior_into (weights, temp);
+ }
+
+ /* Merge all the successor edges. */
+ for (i = 0; VEC_iterate (constraint_edge_t, succvec, i, c); i++)
+ {
+ unsigned int d = c->dest;
+ struct constraint_edge olde;
+ struct constraint_edge newe;
+ bitmap temp;
+ bitmap weights;
+ if (c->dest == from)
+ d = to;
+ newe.src = d;
+ newe.dest = to;
+ add_graph_edge (graph, newe);
+ olde.src = c->dest;
+ olde.dest = from;
+ temp = get_graph_weights (graph, olde);
+ weights = get_graph_weights (graph, newe);
+ bitmap_ior_into (weights, temp);
+ }
+ clear_edges_for_node (graph, from);
+}
+
+/* Add a graph edge to GRAPH, going from TO to FROM, with WEIGHT, if
+ it doesn't exist in the graph already.
+ Return false if the edge already existed, true otherwise. */
+
+static bool
+int_add_graph_edge (constraint_graph_t graph, unsigned int to,
+ unsigned int from, unsigned HOST_WIDE_INT weight)
+{
+ if (to == from && weight == 0)
+ {
+ return false;
+ }
+ else
+ {
+ bool r;
+ struct constraint_edge edge;
+ edge.src = to;
+ edge.dest = from;
+ r = add_graph_edge (graph, edge);
+ r |= !bitmap_bit_p (get_graph_weights (graph, edge), weight);
+ bitmap_set_bit (get_graph_weights (graph, edge), weight);
+ return r;
+ }
+}
+
+
+/* Return true if LOOKFOR is an existing graph edge. */
+
+static bool
+valid_graph_edge (constraint_graph_t graph, struct constraint_edge lookfor)
+{
+ return constraint_edge_vec_find (graph->preds[lookfor.src], lookfor) != NULL;
+}
+
+
+/* Build the constraint graph. */
+
+static void
+build_constraint_graph (void)
+{
+ int i = 0;
+ 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));
+ for (i = 0; VEC_iterate (constraint_t, constraints, i, c); i++)
+ {
+ struct constraint_expr lhs = c->lhs;
+ struct constraint_expr rhs = c->rhs;
+ if (lhs.type == DEREF)
+ {
+ /* *x = y or *x = &y (complex) */
+ if (rhs.type == ADDRESSOF || rhs.var > anything_id)
+ insert_into_complex (lhs.var, c);
+ }
+ else if (rhs.type == DEREF)
+ {
+ /* !ANYTHING = *y */
+ if (lhs.var > anything_id)
+ insert_into_complex (rhs.var, c);
+ }
+ else if (rhs.type == ADDRESSOF)
+ {
+ /* x = &y */
+ bitmap_set_bit (get_varinfo (lhs.var)->solution, rhs.var);
+ }
+ else if (rhs.var > anything_id && lhs.var > anything_id)
+ {
+ /* Ignore 0 weighted self edges, as they can't possibly contribute
+ anything */
+ if (lhs.var != rhs.var || rhs.offset != 0 || lhs.offset != 0)
+ {
+
+ struct constraint_edge edge;
+ edge.src = lhs.var;
+ edge.dest = rhs.var;
+ /* x = y (simple) */
+ add_graph_edge (graph, edge);
+ bitmap_set_bit (get_graph_weights (graph, edge),
+ rhs.offset);
+ }
+
+ }
+ }
+}
+/* Changed variables on the last iteration. */
+static unsigned int changed_count;
+static sbitmap changed;
+
+DEF_VEC_I(uint);
+DEF_VEC_ALLOC_I(uint,heap);
+
+
+/* Strongly Connected Component visitation info. */
+
+struct scc_info
+{
+ sbitmap visited;
+ sbitmap in_component;
+ int current_index;
+ unsigned int *visited_index;
+ VEC(uint,heap) *scc_stack;
+ VEC(uint,heap) *unification_queue;
+};
+
+
+/* Recursive routine to find strongly connected components in GRAPH.
+ SI is the SCC info to store the information in, and N is the id of current
+ graph node we are processing.
+
+ This is Tarjan's strongly connected component finding algorithm, as
+ modified by Nuutila to keep only non-root nodes on the stack.
+ The algorithm can be found in "On finding the strongly connected
+ connected components in a directed graph" by Esko Nuutila and Eljas
+ Soisalon-Soininen, in Information Processing Letters volume 49,
+ number 1, pages 9-14. */
+
+static void
+scc_visit (constraint_graph_t graph, struct scc_info *si, unsigned int n)
+{
+ constraint_edge_t c;
+ int i;
+
+ gcc_assert (get_varinfo (n)->node == n);
+ SET_BIT (si->visited, n);
+ RESET_BIT (si->in_component, n);
+ si->visited_index[n] = si->current_index ++;
+
+ /* Visit all the successors. */
+ for (i = 0; VEC_iterate (constraint_edge_t, graph->succs[n], i, c); i++)
+ {
+ /* We only want to find and collapse the zero weight edges. */
+ if (bitmap_bit_p (c->weights, 0))
+ {
+ unsigned int w = c->dest;
+ if (!TEST_BIT (si->visited, w))
+ scc_visit (graph, si, w);
+ if (!TEST_BIT (si->in_component, w))
+ {
+ unsigned int t = get_varinfo (w)->node;
+ unsigned int nnode = get_varinfo (n)->node;
+ if (si->visited_index[t] < si->visited_index[nnode])
+ get_varinfo (n)->node = t;
+ }
+ }
+ }
+
+ /* See if any components have been identified. */
+ if (get_varinfo (n)->node == n)
+ {
+ unsigned int t = si->visited_index[n];
+ SET_BIT (si->in_component, n);
+ while (VEC_length (uint, si->scc_stack) != 0
+ && t < si->visited_index[VEC_last (uint, si->scc_stack)])
+ {
+ unsigned int w = VEC_pop (uint, si->scc_stack);
+ get_varinfo (w)->node = n;
+ SET_BIT (si->in_component, w);
+ /* Mark this node for collapsing. */
+ VEC_safe_push (uint, heap, si->unification_queue, w);
+ }
+ }
+ else
+ VEC_safe_push (uint, heap, si->scc_stack, n);
+}
+
+
+/* Collapse two variables into one variable. */
+
+static void
+collapse_nodes (constraint_graph_t graph, unsigned int to, unsigned int from)
+{
+ bitmap tosol, fromsol;
+ struct constraint_edge edge;
+
+
+ condense_varmap_nodes (to, from);
+ tosol = get_varinfo (to)->solution;
+ fromsol = get_varinfo (from)->solution;
+ bitmap_ior_into (tosol, fromsol);
+ merge_graph_nodes (graph, to, from);
+ edge.src = to;
+ edge.dest = to;
+ if (valid_graph_edge (graph, edge))
+ {
+ bitmap weights = get_graph_weights (graph, edge);
+ bitmap_clear_bit (weights, 0);
+ if (bitmap_empty_p (weights))
+ erase_graph_self_edge (graph, edge);
+ }
+ bitmap_clear (fromsol);
+ get_varinfo (to)->address_taken |= get_varinfo (from)->address_taken;
+ get_varinfo (to)->indirect_target |= get_varinfo (from)->indirect_target;
+}
+
+
+/* Unify nodes in GRAPH that we have found to be part of a cycle.
+ SI is the Strongly Connected Components information structure that tells us
+ what components to unify.
+ UPDATE_CHANGED should be set to true if the changed sbitmap and changed
+ count should be updated to reflect the unification. */
+
+static void
+process_unification_queue (constraint_graph_t graph, struct scc_info *si,
+ bool update_changed)
+{
+ size_t i = 0;
+ bitmap tmp = BITMAP_ALLOC (update_changed ? &iteration_obstack : NULL);
+ bitmap_clear (tmp);
+
+ /* We proceed as follows:
+
+ For each component in the queue (components are delineated by
+ when current_queue_element->node != next_queue_element->node):
+
+ rep = representative node for component
+
+ For each node (tounify) to be unified in the component,
+ merge the solution for tounify into tmp bitmap
+
+ clear solution for tounify
+
+ merge edges from tounify into rep
+
+ merge complex constraints from tounify into rep
+
+ update changed count to note that tounify will never change
+ again
+
+ Merge tmp into solution for rep, marking rep changed if this
+ changed rep's solution.
+
+ Delete any 0 weighted self-edges we now have for rep. */
+ while (i != VEC_length (uint, si->unification_queue))
+ {
+ unsigned int tounify = VEC_index (uint, si->unification_queue, i);
+ unsigned int n = get_varinfo (tounify)->node;
+
+ if (dump_file && (dump_flags & TDF_DETAILS))
+ fprintf (dump_file, "Unifying %s to %s\n",
+ get_varinfo (tounify)->name,
+ get_varinfo (n)->name);
+ if (update_changed)
+ stats.unified_vars_dynamic++;
+ else
+ stats.unified_vars_static++;
+ bitmap_ior_into (tmp, get_varinfo (tounify)->solution);
+ merge_graph_nodes (graph, n, tounify);
+ condense_varmap_nodes (n, tounify);
+
+ if (update_changed && TEST_BIT (changed, tounify))
+ {
+ RESET_BIT (changed, tounify);
+ if (!TEST_BIT (changed, n))
+ SET_BIT (changed, n);
+ else
+ {
+ gcc_assert (changed_count > 0);
+ changed_count--;
+ }
+ }
+
+ bitmap_clear (get_varinfo (tounify)->solution);
+ ++i;
+
+ /* If we've either finished processing the entire queue, or
+ finished processing all nodes for component n, update the solution for
+ n. */
+ if (i == VEC_length (uint, si->unification_queue)
+ || get_varinfo (VEC_index (uint, si->unification_queue, i))->node != n)
+ {
+ struct constraint_edge edge;
+
+ /* If the solution changes because of the merging, we need to mark
+ the variable as changed. */
+ if (bitmap_ior_into (get_varinfo (n)->solution, tmp))
+ {
+ if (update_changed && !TEST_BIT (changed, n))
+ {
+ SET_BIT (changed, n);
+ changed_count++;
+ }
+ }
+ bitmap_clear (tmp);
+ edge.src = n;
+ edge.dest = n;
+ if (valid_graph_edge (graph, edge))
+ {
+ bitmap weights = get_graph_weights (graph, edge);
+ bitmap_clear_bit (weights, 0);
+ if (bitmap_empty_p (weights))
+ erase_graph_self_edge (graph, edge);
+ }
+ }
+ }
+ BITMAP_FREE (tmp);
+}
+
+
+/* Information needed to compute the topological ordering of a graph. */
+
+struct topo_info
+{
+ /* sbitmap of visited nodes. */
+ sbitmap visited;
+ /* Array that stores the topological order of the graph, *in
+ reverse*. */
+ VEC(uint,heap) *topo_order;
+};
+
+
+/* Initialize and return a topological info structure. */
+
+static struct topo_info *
+init_topo_info (void)
+{
+ size_t size = VEC_length (varinfo_t, varmap);
+ struct topo_info *ti = xmalloc (sizeof (struct topo_info));
+ ti->visited = sbitmap_alloc (size);
+ sbitmap_zero (ti->visited);
+ ti->topo_order = VEC_alloc (uint, heap, 1);
+ return ti;
+}
+
+
+/* Free the topological sort info pointed to by TI. */
+
+static void
+free_topo_info (struct topo_info *ti)
+{
+ sbitmap_free (ti->visited);
+ VEC_free (uint, heap, ti->topo_order);
+ free (ti);
+}
+
+/* Visit the graph in topological order, and store the order in the
+ topo_info structure. */
+
+static void
+topo_visit (constraint_graph_t graph, struct topo_info *ti,
+ unsigned int n)
+{
+ VEC(constraint_edge_t,gc) *succs = graph->succs[n];
+ constraint_edge_t c;
+ int i;
+ SET_BIT (ti->visited, n);
+ for (i = 0; VEC_iterate (constraint_edge_t, succs, i, c); i++)
+ {
+ if (!TEST_BIT (ti->visited, c->dest))
+ topo_visit (graph, ti, c->dest);
+ }
+ VEC_safe_push (uint, heap, ti->topo_order, n);
+}
+
+/* Return true if variable N + OFFSET is a legal field of N. */
+
+static bool
+type_safe (unsigned int n, unsigned HOST_WIDE_INT *offset)
+{
+ varinfo_t ninfo = get_varinfo (n);
+
+ /* For things we've globbed to single variables, any offset into the
+ variable acts like the entire variable, so that it becomes offset
+ 0. */
+ if (n == anything_id
+ || ninfo->is_artificial_var
+ || ninfo->is_unknown_size_var)
+ {
+ *offset = 0;
+ return true;
+ }
+ return n > anything_id
+ && (get_varinfo (n)->offset + *offset) < get_varinfo (n)->fullsize;
+}
+
+/* Process a constraint C that represents *x = &y. */
+
+static void
+do_da_constraint (constraint_graph_t graph ATTRIBUTE_UNUSED,
+ constraint_t c, bitmap delta)
+{
+ unsigned int rhs = c->rhs.var;
+ unsigned HOST_WIDE_INT offset = c->lhs.offset;
+ unsigned int j;
+ bitmap_iterator bi;
+
+ /* For each member j of Delta (Sol(x)), add x to Sol(j) */
+ EXECUTE_IF_SET_IN_BITMAP (delta, 0, j, bi)
+ {
+ if (type_safe (j, &offset))
+ {
+ /* *x != NULL && *x != ANYTHING*/
+ varinfo_t v;
+ unsigned int t;
+ bitmap sol;
+ unsigned HOST_WIDE_INT fieldoffset = get_varinfo (j)->offset + offset;
+ v = first_vi_for_offset (get_varinfo (j), fieldoffset);
+ t = v->node;
+ sol = get_varinfo (t)->solution;
+ if (!bitmap_bit_p (sol, rhs))
+ {
+ bitmap_set_bit (sol, rhs);
+ if (!TEST_BIT (changed, t))
+ {
+ SET_BIT (changed, t);
+ changed_count++;
+ }
+ }
+ }
+ else if (dump_file)
+ fprintf (dump_file, "Untypesafe usage in do_da_constraint.\n");
+
+ }
+}
+
+/* Process a constraint C that represents x = *y, using DELTA as the
+ starting solution. */
+
+static void
+do_sd_constraint (constraint_graph_t graph, constraint_t c,
+ bitmap delta)
+{
+ unsigned int lhs = get_varinfo (c->lhs.var)->node;
+ unsigned HOST_WIDE_INT roffset = c->rhs.offset;
+ bool flag = false;
+ bitmap sol = get_varinfo (lhs)->solution;
+ unsigned int j;
+ bitmap_iterator bi;
+
+ /* For each variable j in delta (Sol(y)), add
+ an edge in the graph from j to x, and union Sol(j) into Sol(x). */
+ EXECUTE_IF_SET_IN_BITMAP (delta, 0, j, bi)
+ {
+ if (type_safe (j, &roffset))
+ {
+ varinfo_t v;
+ unsigned HOST_WIDE_INT fieldoffset = get_varinfo (j)->offset + roffset;
+ unsigned int t;
+
+ v = first_vi_for_offset (get_varinfo (j), fieldoffset);
+ t = v->node;
+ if (int_add_graph_edge (graph, lhs, t, 0))
+ flag |= bitmap_ior_into (sol, get_varinfo (t)->solution);
+ }
+ else if (dump_file)
+ fprintf (dump_file, "Untypesafe usage in do_sd_constraint\n");
+
+ }
+
+ /* If the LHS solution changed, mark the var as changed. */
+ if (flag)
+ {
+ get_varinfo (lhs)->solution = sol;
+ if (!TEST_BIT (changed, lhs))
+ {
+ SET_BIT (changed, lhs);
+ changed_count++;
+ }
+ }
+}
+
+/* Process a constraint C that represents *x = y. */
+
+static void
+do_ds_constraint (constraint_graph_t graph, constraint_t c, bitmap delta)
+{
+ unsigned int rhs = get_varinfo (c->rhs.var)->node;
+ unsigned HOST_WIDE_INT loff = c->lhs.offset;
+ unsigned HOST_WIDE_INT roff = c->rhs.offset;
+ bitmap sol = get_varinfo (rhs)->solution;
+ unsigned int j;
+ bitmap_iterator bi;
+
+ /* For each member j of delta (Sol(x)), add an edge from y to j and
+ union Sol(y) into Sol(j) */
+ EXECUTE_IF_SET_IN_BITMAP (delta, 0, j, bi)
+ {
+ if (type_safe (j, &loff))
+ {
+ varinfo_t v;
+ unsigned int t;
+ unsigned HOST_WIDE_INT fieldoffset = get_varinfo (j)->offset + loff;
+
+ v = first_vi_for_offset (get_varinfo (j), fieldoffset);
+ t = v->node;
+ if (int_add_graph_edge (graph, t, rhs, roff))
+ {
+ bitmap tmp = get_varinfo (t)->solution;
+ if (set_union_with_increment (tmp, sol, roff))
+ {
+ get_varinfo (t)->solution = tmp;
+ if (t == rhs)
+ {
+ sol = get_varinfo (rhs)->solution;
+ }
+ if (!TEST_BIT (changed, t))
+ {
+ SET_BIT (changed, t);
+ changed_count++;
+ }
+ }
+ }
+ }
+ else if (dump_file)
+ fprintf (dump_file, "Untypesafe usage in do_ds_constraint\n");
+ }
+}
+
+/* Handle a non-simple (simple meaning requires no iteration), non-copy
+ constraint (IE *x = &y, x = *y, and *x = y). */
+
+static void
+do_complex_constraint (constraint_graph_t graph, constraint_t c, bitmap delta)
+{
+ if (c->lhs.type == DEREF)
+ {
+ if (c->rhs.type == ADDRESSOF)
+ {
+ /* *x = &y */
+ do_da_constraint (graph, c, delta);
+ }
+ else
+ {
+ /* *x = y */
+ do_ds_constraint (graph, c, delta);
+ }
+ }
+ else
+ {
+ /* x = *y */
+ do_sd_constraint (graph, c, delta);
+ }
+}
+
+/* Initialize and return a new SCC info structure. */
+
+static struct scc_info *
+init_scc_info (void)
+{
+ struct scc_info *si = xmalloc (sizeof (struct scc_info));
+ size_t size = VEC_length (varinfo_t, varmap);
+
+ si->current_index = 0;
+ si->visited = sbitmap_alloc (size);
+ sbitmap_zero (si->visited);
+ si->in_component = sbitmap_alloc (size);
+ sbitmap_ones (si->in_component);
+ si->visited_index = xcalloc (sizeof (unsigned int), size + 1);
+ si->scc_stack = VEC_alloc (uint, heap, 1);
+ si->unification_queue = VEC_alloc (uint, heap, 1);
+ return si;
+}
+
+/* Free an SCC info structure pointed to by SI */
+
+static void
+free_scc_info (struct scc_info *si)
+{
+ sbitmap_free (si->visited);
+ sbitmap_free (si->in_component);
+ free (si->visited_index);
+ VEC_free (uint, heap, si->scc_stack);
+ VEC_free (uint, heap, si->unification_queue);
+ free(si);
+}
+
+
+/* Find cycles in GRAPH that occur, using strongly connected components, and
+ collapse the cycles into a single representative node. if UPDATE_CHANGED
+ is true, then update the changed sbitmap to note those nodes whose
+ solutions have changed as a result of collapsing. */
+
+static void
+find_and_collapse_graph_cycles (constraint_graph_t graph, bool update_changed)
+{
+ unsigned int i;
+ unsigned int size = VEC_length (varinfo_t, varmap);
+ struct scc_info *si = init_scc_info ();
+
+ for (i = 0; i != size; ++i)
+ if (!TEST_BIT (si->visited, i) && get_varinfo (i)->node == i)
+ scc_visit (graph, si, i);
+ process_unification_queue (graph, si, update_changed);
+ free_scc_info (si);
+}
+
+/* Compute a topological ordering for GRAPH, and store the result in the
+ topo_info structure TI. */
+
+static void
+compute_topo_order (constraint_graph_t graph,
+ struct topo_info *ti)
+{
+ unsigned int i;
+ unsigned int size = VEC_length (varinfo_t, varmap);
+
+ for (i = 0; i != size; ++i)
+ if (!TEST_BIT (ti->visited, i) && get_varinfo (i)->node == i)
+ topo_visit (graph, ti, i);
+}
+
+/* Return true if bitmap B is empty, or a bitmap other than bit 0 is set. */
+
+static bool
+bitmap_other_than_zero_bit_set (bitmap b)
+{
+ unsigned int i;
+ bitmap_iterator bi;
+
+ if (bitmap_empty_p (b))
+ return false;
+ EXECUTE_IF_SET_IN_BITMAP (b, 1, i, bi)
+ return true;
+ return false;
+}
+
+/* Perform offline variable substitution.
+
+ This is a linear time way of identifying variables that must have
+ equivalent points-to sets, including those caused by static cycles,
+ and single entry subgraphs, in the constraint graph.
+
+ The technique is described in "Off-line variable substitution for
+ scaling points-to analysis" by Atanas Rountev and Satish Chandra,
+ in "ACM SIGPLAN Notices" volume 35, number 5, pages 47-56. */
+
+static void
+perform_var_substitution (constraint_graph_t graph)
+{
+ struct topo_info *ti = init_topo_info ();
+
+ /* Compute the topological ordering of the graph, then visit each
+ node in topological order. */
+ compute_topo_order (graph, ti);
+
+ while (VEC_length (uint, ti->topo_order) != 0)
+ {
+ unsigned int i = VEC_pop (uint, ti->topo_order);
+ unsigned int pred;
+ varinfo_t vi = get_varinfo (i);
+ bool okay_to_elim = false;
+ unsigned int root = VEC_length (varinfo_t, varmap);
+ VEC(constraint_edge_t,gc) *predvec = graph->preds[i];
+ constraint_edge_t ce;
+ bitmap tmp;
+
+ /* We can't eliminate things whose address is taken, or which is
+ the target of a dereference. */
+ if (vi->address_taken || vi->indirect_target)
+ continue;
+
+ /* See if all predecessors of I are ripe for elimination */
+ for (pred = 0; VEC_iterate (constraint_edge_t, predvec, pred, ce); pred++)
+ {
+ bitmap weight;
+ unsigned int w;
+ weight = get_graph_weights (graph, *ce);
+
+ /* We can't eliminate variables that have non-zero weighted
+ edges between them. */
+ if (bitmap_other_than_zero_bit_set (weight))
+ {
+ okay_to_elim = false;
+ break;
+ }
+ w = get_varinfo (ce->dest)->node;
+
+ /* We can't eliminate the node if one of the predecessors is
+ part of a different strongly connected component. */
+ if (!okay_to_elim)
+ {
+ root = w;
+ okay_to_elim = true;
+ }
+ else if (w != root)
+ {
+ okay_to_elim = false;
+ break;
+ }
+
+ /* Theorem 4 in Rountev and Chandra: If i is a direct node,
+ then Solution(i) is a subset of Solution (w), where w is a
+ predecessor in the graph.
+ Corrolary: If all predecessors of i have the same
+ points-to set, then i has that same points-to set as
+ those predecessors. */
+ tmp = BITMAP_ALLOC (NULL);
+ bitmap_and_compl (tmp, get_varinfo (i)->solution,
+ get_varinfo (w)->solution);
+ if (!bitmap_empty_p (tmp))
+ {
+ okay_to_elim = false;
+ BITMAP_FREE (tmp);
+ break;
+ }
+ BITMAP_FREE (tmp);
+ }
+
+ /* See if the root is different than the original node.
+ If so, we've found an equivalence. */
+ if (root != get_varinfo (i)->node && okay_to_elim)
+ {
+ /* Found an equivalence */
+ get_varinfo (i)->node = root;
+ collapse_nodes (graph, root, i);
+ if (dump_file && (dump_flags & TDF_DETAILS))
+ fprintf (dump_file, "Collapsing %s into %s\n",
+ get_varinfo (i)->name,
+ get_varinfo (root)->name);
+ stats.collapsed_vars++;
+ }
+ }
+
+ free_topo_info (ti);
+}
+
+
+/* Solve the constraint graph GRAPH using our worklist solver.
+ This is based on the PW* family of solvers from the "Efficient Field
+ Sensitive Pointer Analysis for C" paper.
+ It works by iterating over all the graph nodes, processing the complex
+ constraints and propagating the copy constraints, until everything stops
+ changed. This corresponds to steps 6-8 in the solving list given above. */
+
+static void
+solve_graph (constraint_graph_t graph)
+{
+ unsigned int size = VEC_length (varinfo_t, varmap);
+ unsigned int i;
+
+ changed_count = size;
+ changed = sbitmap_alloc (size);
+ sbitmap_ones (changed);
+
+ /* The already collapsed/unreachable nodes will never change, so we
+ need to account for them in changed_count. */
+ for (i = 0; i < size; i++)
+ if (get_varinfo (i)->node != i)
+ changed_count--;
+
+ while (changed_count > 0)
+ {
+ unsigned int i;
+ struct topo_info *ti = init_topo_info ();
+ stats.iterations++;
+
+ bitmap_obstack_initialize (&iteration_obstack);
+
+ if (edge_added)
+ {
+ /* We already did cycle elimination once, when we did
+ variable substitution, so we don't need it again for the
+ first iteration. */
+ if (stats.iterations > 1)
+ find_and_collapse_graph_cycles (graph, true);
+
+ edge_added = false;
+ }
+
+ compute_topo_order (graph, ti);
+
+ while (VEC_length (uint, ti->topo_order) != 0)
+ {
+ i = VEC_pop (uint, ti->topo_order);
+ gcc_assert (get_varinfo (i)->node == i);
+
+ /* If the node has changed, we need to process the
+ complex constraints and outgoing edges again. */
+ if (TEST_BIT (changed, i))
+ {
+ unsigned int j;
+ constraint_t c;
+ constraint_edge_t e;
+ bitmap solution;
+ VEC(constraint_t,gc) *complex = get_varinfo (i)->complex;
+ VEC(constraint_edge_t,gc) *succs;
+
+ RESET_BIT (changed, i);
+ changed_count--;
+
+ /* Process the complex constraints */
+ solution = get_varinfo (i)->solution;
+ for (j = 0; VEC_iterate (constraint_t, complex, j, c); j++)
+ do_complex_constraint (graph, c, solution);
+
+ /* Propagate solution to all successors. */
+ succs = graph->succs[i];
+ for (j = 0; VEC_iterate (constraint_edge_t, succs, j, e); j++)
+ {
+ bitmap tmp = get_varinfo (e->dest)->solution;
+ bool flag = false;
+ unsigned int k;
+ bitmap weights = e->weights;
+ bitmap_iterator bi;
+
+ gcc_assert (!bitmap_empty_p (weights));
+ EXECUTE_IF_SET_IN_BITMAP (weights, 0, k, bi)
+ flag |= set_union_with_increment (tmp, solution, k);
+
+ if (flag)
+ {
+ get_varinfo (e->dest)->solution = tmp;
+ if (!TEST_BIT (changed, e->dest))
+ {
+ SET_BIT (changed, e->dest);
+ changed_count++;
+ }
+ }
+ }
+ }
+ }
+ free_topo_info (ti);
+ bitmap_obstack_release (&iteration_obstack);
+ }
+
+ sbitmap_free (changed);
+}
+
+
+/* CONSTRAINT AND VARIABLE GENERATION FUNCTIONS */
+
+/* Map from trees to variable ids. */
+static htab_t id_for_tree;
+
+typedef struct tree_id
+{
+ tree t;
+ unsigned int id;
+} *tree_id_t;
+
+/* Hash a tree id structure. */
+
+static hashval_t
+tree_id_hash (const void *p)
+{
+ const tree_id_t ta = (tree_id_t) p;
+ return htab_hash_pointer (ta->t);
+}
+
+/* Return true if the tree in P1 and the tree in P2 are the same. */
+
+static int
+tree_id_eq (const void *p1, const void *p2)
+{
+ const tree_id_t ta1 = (tree_id_t) p1;
+ const tree_id_t ta2 = (tree_id_t) p2;
+ return ta1->t == ta2->t;
+}
+
+/* Insert ID as the variable id for tree T in the hashtable. */
+
+static void
+insert_id_for_tree (tree t, int id)
+{
+ void **slot;
+ struct tree_id finder;
+ tree_id_t new_pair;
+
+ finder.t = t;
+ slot = htab_find_slot (id_for_tree, &finder, INSERT);
+ gcc_assert (*slot == NULL);
+ new_pair = xmalloc (sizeof (struct tree_id));
+ new_pair->t = t;
+ new_pair->id = id;
+ *slot = (void *)new_pair;
+}
+
+/* Find the variable id for tree T in ID_FOR_TREE. If T does not
+ exist in the hash table, return false, otherwise, return true and
+ set *ID to the id we found. */
+
+static bool
+lookup_id_for_tree (tree t, unsigned int *id)
+{
+ tree_id_t pair;
+ struct tree_id finder;
+
+ finder.t = t;
+ pair = htab_find (id_for_tree, &finder);
+ if (pair == NULL)
+ return false;
+ *id = pair->id;
+ return true;
+}
+
+/* Return a printable name for DECL */
+
+static const char *
+alias_get_name (tree decl)
+{
+ const char *res = get_name (decl);
+ char *temp;
+ int num_printed = 0;
+
+ if (res != NULL)
+ return res;
+
+ res = "NULL";
+ if (TREE_CODE (decl) == SSA_NAME)
+ {
+ num_printed = asprintf (&temp, "%s_%u",
+ alias_get_name (SSA_NAME_VAR (decl)),
+ SSA_NAME_VERSION (decl));
+ }
+ else if (DECL_P (decl))
+ {
+ num_printed = asprintf (&temp, "D.%u", DECL_UID (decl));
+ }
+ if (num_printed > 0)
+ {
+ res = ggc_strdup (temp);
+ free (temp);
+ }
+ return res;
+}
+
+/* Find the variable id for tree T in the hashtable.
+ If T doesn't exist in the hash table, create an entry for it. */
+
+static unsigned int
+get_id_for_tree (tree t)
+{
+ tree_id_t pair;
+ struct tree_id finder;
+
+ finder.t = t;
+ pair = htab_find (id_for_tree, &finder);
+ if (pair == NULL)
+ return create_variable_info_for (t, alias_get_name (t));
+
+ return pair->id;
+}
+
+/* Get a constraint expression from an SSA_VAR_P node. */
+
+static struct constraint_expr
+get_constraint_exp_from_ssa_var (tree t)
+{
+ struct constraint_expr cexpr;
+
+ gcc_assert (SSA_VAR_P (t) || DECL_P (t));
+
+ /* For parameters, get at the points-to set for the actual parm
+ decl. */
+ if (TREE_CODE (t) == SSA_NAME
+ && TREE_CODE (SSA_NAME_VAR (t)) == PARM_DECL
+ && default_def (SSA_NAME_VAR (t)) == t)
+ return get_constraint_exp_from_ssa_var (SSA_NAME_VAR (t));
+
+ cexpr.type = SCALAR;
+
+ if (TREE_READONLY (t))
+ {
+ cexpr.type = ADDRESSOF;
+ cexpr.var = readonly_id;
+ }
+ else
+ cexpr.var = get_id_for_tree (t);
+
+ cexpr.offset = 0;
+ return cexpr;
+}
+
+/* Process a completed constraint T, and add it to the constraint
+ list. */
+
+static void
+process_constraint (constraint_t t)
+{
+ struct constraint_expr rhs = t->rhs;
+ struct constraint_expr lhs = t->lhs;
+
+ gcc_assert (rhs.var < VEC_length (varinfo_t, varmap));
+ gcc_assert (lhs.var < VEC_length (varinfo_t, varmap));
+
+ /* ANYTHING == ANYTHING is pointless. */
+ if (lhs.var == anything_id && rhs.var == anything_id)
+ return;
+
+ /* If we have &ANYTHING = something, convert to SOMETHING = &ANYTHING) */
+ else if (lhs.var == anything_id && lhs.type == ADDRESSOF)
+ {
+ rhs = t->lhs;
+ t->lhs = t->rhs;
+ t->rhs = rhs;
+ process_constraint (t);
+ }
+ /* This can happen in our IR with things like n->a = *p */
+ else if (rhs.type == DEREF && lhs.type == DEREF && rhs.var != anything_id)
+ {
+ /* Split into tmp = *rhs, *lhs = tmp */
+ tree rhsdecl = get_varinfo (rhs.var)->decl;
+ tree pointertype = TREE_TYPE (rhsdecl);
+ tree pointedtotype = TREE_TYPE (pointertype);
+ tree tmpvar = create_tmp_var_raw (pointedtotype, "doubledereftmp");
+ struct constraint_expr tmplhs = get_constraint_exp_from_ssa_var (tmpvar);
+
+ /* If this is an aggregate of known size, we should have passed
+ this off to do_structure_copy, and it should have broken it
+ up. */
+ gcc_assert (!AGGREGATE_TYPE_P (pointedtotype)
+ || get_varinfo (rhs.var)->is_unknown_size_var);
+
+ process_constraint (new_constraint (tmplhs, rhs));
+ process_constraint (new_constraint (lhs, tmplhs));
+ }
+ else if (rhs.type == ADDRESSOF)
+ {
+ varinfo_t vi;
+ gcc_assert (rhs.offset == 0);
+
+ for (vi = get_varinfo (rhs.var); vi != NULL; vi = vi->next)
+ vi->address_taken = true;
+
+ VEC_safe_push (constraint_t, gc, constraints, t);
+ }
+ else
+ {
+ if (lhs.type != DEREF && rhs.type == DEREF)
+ get_varinfo (lhs.var)->indirect_target = true;
+ VEC_safe_push (constraint_t, gc, constraints, t);
+ }
+}
+
+
+/* Return the position, in bits, of FIELD_DECL from the beginning of its
+ structure. */
+
+static unsigned HOST_WIDE_INT
+bitpos_of_field (const tree fdecl)
+{
+
+ if (TREE_CODE (DECL_FIELD_OFFSET (fdecl)) != INTEGER_CST
+ || TREE_CODE (DECL_FIELD_BIT_OFFSET (fdecl)) != INTEGER_CST)
+ return -1;
+
+ return (tree_low_cst (DECL_FIELD_OFFSET (fdecl), 1) * 8)
+ + tree_low_cst (DECL_FIELD_BIT_OFFSET (fdecl), 1);
+}
+
+
+/* Given a COMPONENT_REF T, return the constraint_expr for it. */
+
+static struct constraint_expr
+get_constraint_for_component_ref (tree t)
+{
+ struct constraint_expr result;
+ HOST_WIDE_INT bitsize;
+ HOST_WIDE_INT bitpos;
+ tree offset;
+ enum machine_mode mode;
+ int unsignedp;
+ int volatilep;
+ tree forzero;
+
+ result.offset = 0;
+ result.type = SCALAR;
+ result.var = 0;
+
+ /* Some people like to do cute things like take the address of
+ &0->a.b */
+ forzero = t;
+ while (!SSA_VAR_P (forzero) && !CONSTANT_CLASS_P (forzero))
+ forzero = TREE_OPERAND (forzero, 0);
+
+ if (CONSTANT_CLASS_P (forzero) && integer_zerop (forzero))
+ {
+ result.offset = 0;
+ result.var = integer_id;
+ result.type = SCALAR;
+ return result;
+ }
+
+ t = get_inner_reference (t, &bitsize, &bitpos, &offset, &mode,
+ &unsignedp, &volatilep, false);
+ result = get_constraint_for (t);
+
+ /* This can also happen due to weird offsetof type macros. */
+ if (TREE_CODE (t) != ADDR_EXPR && result.type == ADDRESSOF)
+ result.type = SCALAR;
+
+ /* If we know where this goes, then yay. Otherwise, booo. */
+
+ if (offset == NULL && bitsize != -1)
+ {
+ result.offset = bitpos;
+ }
+ else
+ {
+ result.var = anything_id;
+ result.offset = 0;
+ }
+
+ if (result.type == SCALAR)
+ {
+ /* In languages like C, you can access one past the end of an
+ array. You aren't allowed to dereference it, so we can
+ ignore this constraint. When we handle pointer subtraction,
+ we may have to do something cute here. */
+
+ if (result.offset < get_varinfo (result.var)->fullsize)
+ result.var = first_vi_for_offset (get_varinfo (result.var),
+ result.offset)->id;
+ else
+ if (dump_file && (dump_flags & TDF_DETAILS))
+ fprintf (dump_file, "Access to past the end of variable, ignoring\n");
+
+ result.offset = 0;
+ }
+
+ return result;
+}
+
+
+/* Dereference the constraint expression CONS, and return the result.
+ DEREF (ADDRESSOF) = SCALAR
+ DEREF (SCALAR) = DEREF
+ DEREF (DEREF) = (temp = DEREF1; result = DEREF(temp))
+ This is needed so that we can handle dereferencing DEREF constraints. */
+
+static struct constraint_expr
+do_deref (struct constraint_expr cons)
+{
+ if (cons.type == SCALAR)
+ {
+ cons.type = DEREF;
+ return cons;
+ }
+ else if (cons.type == ADDRESSOF)
+ {
+ cons.type = SCALAR;
+ return cons;
+ }
+ else if (cons.type == DEREF)
+ {
+ tree tmpvar = create_tmp_var_raw (ptr_type_node, "derefmp");
+ struct constraint_expr tmplhs = get_constraint_exp_from_ssa_var (tmpvar);
+ process_constraint (new_constraint (tmplhs, cons));
+ cons.var = tmplhs.var;
+ return cons;
+ }
+ gcc_unreachable ();
+}
+
+
+/* Given a tree T, return the constraint expression for it. */
+
+static struct constraint_expr
+get_constraint_for (tree t)
+{
+ struct constraint_expr temp;
+
+ /* x = integer is all glommed to a single variable, which doesn't
+ point to anything by itself. That is, of course, unless it is an
+ integer constant being treated as a pointer, in which case, we
+ will return that this is really the addressof anything. This
+ happens below, since it will fall into the default case. The only
+ case we know something about an integer treated like a pointer is
+ when it is the NULL pointer, and then we just say it points to
+ NULL. */
+ if (TREE_CODE (t) == INTEGER_CST
+ && !POINTER_TYPE_P (TREE_TYPE (t)))
+ {
+ temp.var = integer_id;
+ temp.type = SCALAR;
+ temp.offset = 0;
+ return temp;
+ }
+ else if (TREE_CODE (t) == INTEGER_CST
+ && integer_zerop (t))
+ {
+ temp.var = nothing_id;
+ temp.type = ADDRESSOF;
+ temp.offset = 0;
+ return temp;
+ }
+
+ switch (TREE_CODE_CLASS (TREE_CODE (t)))
+ {
+ case tcc_expression:
+ {
+ switch (TREE_CODE (t))
+ {
+ case ADDR_EXPR:
+ {
+ temp = get_constraint_for (TREE_OPERAND (t, 0));
+ if (temp.type == DEREF)
+ temp.type = SCALAR;
+ else
+ temp.type = ADDRESSOF;
+ return temp;
+ }
+ break;
+ case CALL_EXPR:
+
+ /* XXX: In interprocedural mode, if we didn't have the
+ body, we would need to do *each pointer argument =
+ &ANYTHING added. */
+ if (call_expr_flags (t) & (ECF_MALLOC | ECF_MAY_BE_ALLOCA))
+ {
+ tree heapvar = create_tmp_var_raw (ptr_type_node, "HEAP");
+ temp.var = create_variable_info_for (heapvar,
+ alias_get_name (heapvar));
+
+ get_varinfo (temp.var)->is_artificial_var = 1;
+ temp.type = ADDRESSOF;
+ temp.offset = 0;
+ return temp;
+ }
+ /* FALLTHRU */
+ default:
+ {
+ temp.type = ADDRESSOF;
+ temp.var = anything_id;
+ temp.offset = 0;
+ return temp;
+ }
+ }
+ }
+ case tcc_reference:
+ {
+ switch (TREE_CODE (t))
+ {
+ case INDIRECT_REF:
+ {
+ temp = get_constraint_for (TREE_OPERAND (t, 0));
+ temp = do_deref (temp);
+ return temp;
+ }
+ case ARRAY_REF:
+ case COMPONENT_REF:
+ temp = get_constraint_for_component_ref (t);
+ return temp;
+ default:
+ {
+ temp.type = ADDRESSOF;
+ temp.var = anything_id;
+ temp.offset = 0;
+ return temp;
+ }
+ }
+ }
+ case tcc_unary:
+ {
+ switch (TREE_CODE (t))
+ {
+ case NOP_EXPR:
+ case CONVERT_EXPR:
+ case NON_LVALUE_EXPR:
+ {
+ tree op = TREE_OPERAND (t, 0);
+
+ /* 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))))
+ return get_constraint_for (op);
+ }
+ default:
+ {
+ temp.type = ADDRESSOF;
+ temp.var = anything_id;
+ temp.offset = 0;
+ return temp;
+ }
+ }
+ }
+ case tcc_exceptional:
+ {
+ switch (TREE_CODE (t))
+ {
+ case PHI_NODE:
+ return get_constraint_for (PHI_RESULT (t));
+ case SSA_NAME:
+ return get_constraint_exp_from_ssa_var (t);
+ default:
+ {
+ temp.type = ADDRESSOF;
+ temp.var = anything_id;
+ temp.offset = 0;
+ return temp;
+ }
+ }
+ }
+ case tcc_declaration:
+ return get_constraint_exp_from_ssa_var (t);
+ default:
+ {
+ temp.type = ADDRESSOF;
+ temp.var = anything_id;
+ temp.offset = 0;
+ return temp;
+ }
+ }
+}
+
+
+/* Handle the structure copy case where we have a simple structure copy
+ between LHS and RHS that is of SIZE (in bits)
+
+ For each field of the lhs variable (lhsfield)
+ For each field of the rhs variable at lhsfield.offset (rhsfield)
+ add the constraint lhsfield = rhsfield
+*/
+
+static void
+do_simple_structure_copy (const struct constraint_expr lhs,
+ const struct constraint_expr rhs,
+ const unsigned HOST_WIDE_INT size)
+{
+ varinfo_t p = get_varinfo (lhs.var);
+ unsigned HOST_WIDE_INT pstart,last;
+
+ pstart = p->offset;
+ last = p->offset + size;
+ for (; p && p->offset < last; p = p->next)
+ {
+ varinfo_t q;
+ struct constraint_expr templhs = lhs;
+ struct constraint_expr temprhs = rhs;
+ unsigned HOST_WIDE_INT fieldoffset;
+
+ templhs.var = p->id;
+ q = get_varinfo (temprhs.var);
+ fieldoffset = p->offset - pstart;
+ q = first_vi_for_offset (q, q->offset + fieldoffset);
+ temprhs.var = q->id;
+ process_constraint (new_constraint (templhs, temprhs));
+ }
+}
+
+
+/* Handle the structure copy case where we have a structure copy between a
+ aggregate on the LHS and a dereference of a pointer on the RHS
+ that is of SIZE (in bits)
+
+ For each field of the lhs variable (lhsfield)
+ rhs.offset = lhsfield->offset
+ add the constraint lhsfield = rhs
+*/
+
+static void
+do_rhs_deref_structure_copy (const struct constraint_expr lhs,
+ const struct constraint_expr rhs,
+ const unsigned HOST_WIDE_INT size)
+{
+ varinfo_t p = get_varinfo (lhs.var);
+ unsigned HOST_WIDE_INT pstart,last;
+ pstart = p->offset;
+ last = p->offset + size;
+
+ for (; p && p->offset < last; p = p->next)
+ {
+ varinfo_t q;
+ struct constraint_expr templhs = lhs;
+ struct constraint_expr temprhs = rhs;
+ unsigned HOST_WIDE_INT fieldoffset;
+
+
+ if (templhs.type == SCALAR)
+ templhs.var = p->id;
+ else
+ templhs.offset = p->offset;
+
+ q = get_varinfo (temprhs.var);
+ fieldoffset = p->offset - pstart;
+ temprhs.offset += fieldoffset;
+ process_constraint (new_constraint (templhs, temprhs));
+ }
+}
+
+/* Handle the structure copy case where we have a structure copy
+ between a aggregate on the RHS and a dereference of a pointer on
+ the LHS that is of SIZE (in bits)
+
+ For each field of the rhs variable (rhsfield)
+ lhs.offset = rhsfield->offset
+ add the constraint lhs = rhsfield
+*/
+
+static void
+do_lhs_deref_structure_copy (const struct constraint_expr lhs,
+ const struct constraint_expr rhs,
+ const unsigned HOST_WIDE_INT size)
+{
+ varinfo_t p = get_varinfo (rhs.var);
+ unsigned HOST_WIDE_INT pstart,last;
+ pstart = p->offset;
+ last = p->offset + size;
+
+ for (; p && p->offset < last; p = p->next)
+ {
+ varinfo_t q;
+ struct constraint_expr templhs = lhs;
+ struct constraint_expr temprhs = rhs;
+ unsigned HOST_WIDE_INT fieldoffset;
+
+
+ if (temprhs.type == SCALAR)
+ temprhs.var = p->id;
+ else
+ temprhs.offset = p->offset;
+
+ q = get_varinfo (templhs.var);
+ fieldoffset = p->offset - pstart;
+ templhs.offset += fieldoffset;
+ process_constraint (new_constraint (templhs, temprhs));
+ }
+}
+
+
+/* Handle aggregate copies by expanding into copies of the respective
+ fields of the structures. */
+
+static void
+do_structure_copy (tree lhsop, tree rhsop)
+{
+ struct constraint_expr lhs, rhs, tmp;
+ varinfo_t p;
+ unsigned HOST_WIDE_INT lhssize;
+ unsigned HOST_WIDE_INT rhssize;
+
+ lhssize = TREE_INT_CST_LOW (TYPE_SIZE (TREE_TYPE (lhsop)));
+ rhssize = TREE_INT_CST_LOW (TYPE_SIZE (TREE_TYPE (rhsop)));
+ lhs = get_constraint_for (lhsop);
+ rhs = get_constraint_for (rhsop);
+
+ /* If we have special var = x, swap it around. */
+ if (lhs.var <= integer_id && rhs.var > integer_id)
+ {
+ tmp = lhs;
+ lhs = rhs;
+ rhs = tmp;
+ }
+
+ /* If the RHS is a special var, set all the LHS fields to that
+ special var. */
+ if (rhs.var <= integer_id)
+ {
+ for (p = get_varinfo (lhs.var); p; p = p->next)
+ {
+ struct constraint_expr templhs = lhs;
+ struct constraint_expr temprhs = rhs;
+ if (templhs.type == SCALAR )
+ templhs.var = p->id;
+ else
+ templhs.offset += p->offset;
+ process_constraint (new_constraint (templhs, temprhs));
+ }
+ }
+ else
+ {
+ if (rhs.type == SCALAR && lhs.type == SCALAR)
+ do_simple_structure_copy (lhs, rhs, MIN (lhssize, rhssize));
+ else if (lhs.type != DEREF && rhs.type == DEREF)
+ do_rhs_deref_structure_copy (lhs, rhs, MIN (lhssize, rhssize));
+ else if (lhs.type == DEREF && rhs.type != DEREF)
+ do_lhs_deref_structure_copy (lhs, rhs, MIN (lhssize, rhssize));
+ else
+ {
+ tree rhsdecl = get_varinfo (rhs.var)->decl;
+ tree pointertype = TREE_TYPE (rhsdecl);
+ tree pointedtotype = TREE_TYPE (pointertype);
+ tree tmpvar;
+ gcc_assert (rhs.type == DEREF && lhs.type == DEREF);
+ tmpvar = create_tmp_var_raw (pointedtotype, "structcopydereftmp");
+ lhs = get_constraint_for (tmpvar);
+ do_rhs_deref_structure_copy (lhs, rhs, MIN (lhssize, rhssize));
+ rhs = lhs;
+ lhs = get_constraint_for (lhsop);
+ do_lhs_deref_structure_copy (lhs, rhs, MIN (lhssize, rhssize));
+ }
+ }
+}
+
+
+/* Return true if REF, a COMPONENT_REF, has an INDIRECT_REF somewhere
+ in it. */
+
+static inline bool
+ref_contains_indirect_ref (tree ref)
+{
+ while (handled_component_p (ref))
+ {
+ if (TREE_CODE (ref) == INDIRECT_REF)
+ return true;
+ ref = TREE_OPERAND (ref, 0);
+ }
+ return false;
+}
+
+
+/* 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. */
+
+static void
+find_func_aliases (tree t)
+{
+ 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;
+
+ case 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));
+ }
+ break;
+
+ /* Otherwise, walk each operand. */
+ default:
+ for (i = 0; i < TREE_CODE_LENGTH (TREE_CODE (rhsop)); i++)
+ {
+ tree op = TREE_OPERAND (rhsop, i);
+ rhs = get_constraint_for (op);
+ process_constraint (new_constraint (lhs, rhs));
+ }
+ }
+ }
+ }
+ }
+ break;
+
+ default:
+ break;
+ }
+}
+
+
+/* Find the first varinfo in the same variable as START that overlaps with
+ OFFSET.
+ Effectively, walk the chain of fields for the variable START to find the
+ first field that overlaps with OFFSET.
+ Abort if we can't find one. */
+
+static varinfo_t
+first_vi_for_offset (varinfo_t start, unsigned HOST_WIDE_INT offset)
+{
+ varinfo_t curr = start;
+ while (curr)
+ {
+ /* We may not find a variable in the field list with the actual
+ offset when when we have glommed a structure to a variable.
+ In that case, however, offset should still be within the size
+ of the variable. */
+ if (offset >= curr->offset && offset < (curr->offset + curr->size))
+ return curr;
+ curr = curr->next;
+ }
+
+ gcc_unreachable ();
+}
+
+
+/* Insert the varinfo FIELD into the field list for BASE, ordered by
+ offset. */
+
+static void
+insert_into_field_list (varinfo_t base, varinfo_t field)
+{
+ varinfo_t prev = base;
+ varinfo_t curr = base->next;
+
+ if (curr == NULL)
+ {
+ prev->next = field;
+ field->next = NULL;
+ }
+ else
+ {
+ while (curr)
+ {
+ if (field->offset <= curr->offset)
+ break;
+ prev = curr;
+ curr = curr->next;
+ }
+ field->next = prev->next;
+ prev->next = field;
+ }
+}
+
+/* qsort comparison function for two fieldoff's PA and PB */
+
+static int
+fieldoff_compare (const void *pa, const void *pb)
+{
+ const fieldoff_s *foa = (const fieldoff_s *)pa;
+ const fieldoff_s *fob = (const fieldoff_s *)pb;
+ HOST_WIDE_INT foasize, fobsize;
+
+ if (foa->offset != fob->offset)
+ return foa->offset - fob->offset;
+
+ foasize = TREE_INT_CST_LOW (DECL_SIZE (foa->field));
+ fobsize = TREE_INT_CST_LOW (DECL_SIZE (fob->field));
+ return foasize - fobsize;
+}
+
+/* Sort a fieldstack according to the field offset and sizes. */
+void sort_fieldstack (VEC(fieldoff_s,heap) *fieldstack)
+{
+ qsort (VEC_address (fieldoff_s, fieldstack),
+ VEC_length (fieldoff_s, fieldstack),
+ sizeof (fieldoff_s),
+ fieldoff_compare);
+}
+
+/* Given a TYPE, and a vector of field offsets FIELDSTACK, push all the fields
+ of TYPE onto fieldstack, recording their offsets along the way.
+ OFFSET is used to keep track of the offset in this entire structure, rather
+ than just the immediately containing structure. Returns the number
+ of fields pushed.
+ HAS_UNION is set to true if we find a union type as a field of
+ TYPE. */
+
+int
+push_fields_onto_fieldstack (tree type, VEC(fieldoff_s,heap) **fieldstack,
+ HOST_WIDE_INT offset, bool *has_union)
+{
+ tree field;
+ int count = 0;
+
+ for (field = TYPE_FIELDS (type); field; field = TREE_CHAIN (field))
+ if (TREE_CODE (field) == FIELD_DECL)
+ {
+ bool push = false;
+
+ if (has_union
+ && (TREE_CODE (TREE_TYPE (field)) == QUAL_UNION_TYPE
+ || TREE_CODE (TREE_TYPE (field)) == UNION_TYPE))
+ *has_union = true;
+
+ if (!var_can_have_subvars (field))
+ push = true;
+ else if (!(push_fields_onto_fieldstack
+ (TREE_TYPE (field), fieldstack,
+ offset + bitpos_of_field (field), has_union))
+ && DECL_SIZE (field)
+ && !integer_zerop (DECL_SIZE (field)))
+ /* Empty structures may have actual size, like in C++. So
+ see if we didn't push any subfields and the size is
+ nonzero, push the field onto the stack */
+ push = true;
+
+ if (push)
+ {
+ fieldoff_s *pair;
+
+ pair = VEC_safe_push (fieldoff_s, heap, *fieldstack, NULL);
+ pair->field = field;
+ pair->offset = offset + bitpos_of_field (field);
+ count++;
+ }
+ }
+
+ return count;
+}
+
+static void
+make_constraint_to_anything (varinfo_t vi)
+{
+ struct constraint_expr lhs, rhs;
+
+ lhs.var = vi->id;
+ lhs.offset = 0;
+ lhs.type = SCALAR;
+
+ rhs.var = anything_id;
+ rhs.offset =0 ;
+ rhs.type = ADDRESSOF;
+ process_constraint (new_constraint (lhs, rhs));
+}
+
+/* Create a varinfo structure for NAME and DECL, and add it to VARMAP.
+ This will also create any varinfo structures necessary for fields
+ of DECL. */
+
+static unsigned int
+create_variable_info_for (tree decl, const char *name)
+{
+ unsigned int index = VEC_length (varinfo_t, varmap);
+ varinfo_t vi;
+ tree decltype = TREE_TYPE (decl);
+ bool notokay = false;
+ subvar_t svars;
+ bool is_global = DECL_P (decl) ? is_global_var (decl) : false;
+
+ VEC (fieldoff_s,heap) *fieldstack = NULL;
+
+ if (var_can_have_subvars (decl) && use_field_sensitive)
+ {
+ push_fields_onto_fieldstack (decltype, &fieldstack, 0, &notokay);
+ if (notokay)
+ VEC_free (fieldoff_s, heap, fieldstack);
+ }
+
+ /* 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
+ sort the field list and create fake variables for all the
+ fields. */
+ vi = new_var_info (decl, index, name, index);
+ vi->decl = decl;
+ vi->offset = 0;
+ if (!TYPE_SIZE (decltype)
+ || TREE_CODE (TYPE_SIZE (decltype)) != INTEGER_CST
+ || TREE_CODE (decltype) == ARRAY_TYPE
+ || TREE_CODE (decltype) == UNION_TYPE
+ || TREE_CODE (decltype) == QUAL_UNION_TYPE)
+ {
+ vi->is_unknown_size_var = true;
+ vi->fullsize = ~0;
+ vi->size = ~0;
+ }
+ else
+ {
+ vi->fullsize = TREE_INT_CST_LOW (TYPE_SIZE (decltype));
+ vi->size = vi->fullsize;
+ }
+
+ insert_id_for_tree (vi->decl, index);
+ VEC_safe_push (varinfo_t, gc, varmap, vi);
+ if (is_global)
+ make_constraint_to_anything (vi);
+
+ stats.total_vars++;
+ if (use_field_sensitive
+ && !notokay
+ && !vi->is_unknown_size_var
+ && var_can_have_subvars (decl))
+ {
+ unsigned int newindex = VEC_length (varinfo_t, varmap);
+ fieldoff_s *fo = NULL;
+ unsigned int i;
+ tree field;
+
+ for (i = 0; !notokay && VEC_iterate (fieldoff_s, fieldstack, i, fo); i++)
+ {
+ if (!DECL_SIZE (fo->field)
+ || TREE_CODE (DECL_SIZE (fo->field)) != INTEGER_CST
+ || TREE_CODE (TREE_TYPE (fo->field)) == ARRAY_TYPE
+ || fo->offset < 0)
+ {
+ notokay = true;
+ break;
+ }
+ }
+ sort_fieldstack (fieldstack);
+
+ if (VEC_length (fieldoff_s, fieldstack) != 0)
+ fo = VEC_index (fieldoff_s, fieldstack, 0);
+
+ if (fo == NULL || notokay)
+ {
+ vi->is_unknown_size_var = 1;
+ vi->fullsize = ~0;
+ vi->size = ~0;
+ VEC_free (fieldoff_s, heap, fieldstack);
+ return index;
+ }
+
+ field = fo->field;
+ gcc_assert (bitpos_of_field (field) == 0);
+ vi->size = TREE_INT_CST_LOW (DECL_SIZE (field));
+ for (i = 1; VEC_iterate (fieldoff_s, fieldstack, i, fo); i++)
+ {
+ varinfo_t newvi;
+ const char *newname;
+ char *tempname;
+
+ field = fo->field;
+ newindex = VEC_length (varinfo_t, varmap);
+ asprintf (&tempname, "%s.%s", vi->name, alias_get_name (field));
+ newname = ggc_strdup (tempname);
+ free (tempname);
+ newvi = new_var_info (decl, newindex, newname, newindex);
+ newvi->offset = fo->offset;
+ newvi->size = TREE_INT_CST_LOW (DECL_SIZE (field));
+ newvi->fullsize = vi->fullsize;
+ insert_into_field_list (vi, newvi);
+ VEC_safe_push (varinfo_t, gc, varmap, newvi);
+ if (is_global)
+ make_constraint_to_anything (newvi);
+
+ stats.total_vars++;
+ }
+ VEC_free (fieldoff_s, heap, fieldstack);
+ }
+ return index;
+}
+
+/* Print out the points-to solution for VAR to FILE. */
+
+void
+dump_solution_for_var (FILE *file, unsigned int var)
+{
+ varinfo_t vi = get_varinfo (var);
+ unsigned int i;
+ bitmap_iterator bi;
+
+ fprintf (file, "%s = {", vi->name);
+ EXECUTE_IF_SET_IN_BITMAP (get_varinfo (vi->node)->solution, 0, i, bi)
+ {
+ fprintf (file, "%s,", get_varinfo (i)->name);
+ }
+ fprintf (file, "}\n");
+}
+
+/* Print the points-to solution for VAR to stdout. */
+
+void
+debug_solution_for_var (unsigned int var)
+{
+ dump_solution_for_var (stdout, var);
+}
+
+
+/* Create varinfo structures for all of the variables in the
+ function for intraprocedural mode. */
+
+static void
+intra_create_variable_infos (void)
+{
+ tree t;
+
+ /* For each incoming argument arg, ARG = &ANYTHING */
+ for (t = DECL_ARGUMENTS (current_function_decl); t; t = TREE_CHAIN (t))
+ {
+ struct constraint_expr lhs;
+ struct constraint_expr rhs;
+ varinfo_t p;
+
+ lhs.offset = 0;
+ 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;
+
+ for (p = get_varinfo (lhs.var); p; p = p->next)
+ {
+ struct constraint_expr temp = lhs;
+ temp.var = p->id;
+ process_constraint (new_constraint (temp, rhs));
+ }
+ }
+
+}
+
+/* Set bits in INTO corresponding to the variable uids in solution set
+ FROM */
+
+static void
+set_uids_in_ptset (bitmap into, bitmap from)
+{
+ unsigned int i;
+ bitmap_iterator bi;
+
+ EXECUTE_IF_SET_IN_BITMAP (from, 0, i, bi)
+ {
+ varinfo_t vi = get_varinfo (i);
+
+ /* We may end up with labels in the points-to set because people
+ take their address, and they are _DECL's. */
+ if (TREE_CODE (vi->decl) == VAR_DECL
+ || TREE_CODE (vi->decl) == PARM_DECL)
+ bitmap_set_bit (into, var_ann (vi->decl)->uid);
+ }
+}
+static int have_alias_info = false;
+
+/* Given a pointer variable P, fill in its points-to set, or return
+ false if we can't. */
+
+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);
+
+ if (vi->is_artificial_var)
+ return false;
+
+ /* See if this is a field or a structure */
+ if (vi->size != vi->fullsize)
+ {
+ if (!var_can_have_subvars (vi->decl)
+ || get_subvars_for_var (vi->decl) == NULL)
+ return false;
+ }
+ else
+ {
+ struct ptr_info_def *pi = get_ptr_info (p);
+ unsigned int i;
+ bitmap_iterator bi;
+
+ /* This variable may have been collapsed, let's get the real
+ 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. */
+ EXECUTE_IF_SET_IN_BITMAP (vi->solution, 0, i, bi)
+ {
+ if (get_varinfo (i)->is_artificial_var)
+ return false;
+ }
+ pi->pt_anything = false;
+ if (!pi->pt_vars)
+ pi->pt_vars = BITMAP_GGC_ALLOC ();
+ set_uids_in_ptset (pi->pt_vars, vi->solution);
+ return true;
+ }
+ }
+ return false;
+}
+
+/* Initialize things necessary to perform PTA */
+
+static void
+init_alias_vars (void)
+{
+ bitmap_obstack_initialize (&ptabitmap_obstack);
+}
+
+/* Dump the points-to information to OUTFILE. */
+
+static void
+dump_sa_points_to_info (FILE *outfile)
+{
+
+ unsigned int i;
+ if (dump_flags & TDF_STATS)
+ {
+ fprintf (outfile, "Stats:\n");
+ fprintf (outfile, "Total vars:%d\n", stats.total_vars);
+ fprintf (outfile, "Statically unified vars:%d\n", stats.unified_vars_static);
+ fprintf (outfile, "Collapsed vars:%d\n", stats.collapsed_vars);
+ fprintf (outfile, "Dynamically unified vars:%d\n", stats.unified_vars_dynamic);
+ fprintf (outfile, "Iterations:%d\n", stats.iterations);
+ }
+ for (i = 0; i < VEC_length (varinfo_t, varmap); i++)
+ dump_solution_for_var (outfile, i);
+}
+
+
+/* Initialize the always-existing constraint variables for NULL
+ ANYTHING, READONLY, and INTEGER */
+
+static void
+init_base_vars (void)
+{
+ struct constraint_expr lhs, rhs;
+
+ /* Create the NULL variable, used to represent that a variable points
+ to NULL. */
+ nothing_tree = create_tmp_var_raw (void_type_node, "NULL");
+ var_nothing = new_var_info (nothing_tree, 0, "NULL", 0);
+ insert_id_for_tree (nothing_tree, 0);
+ var_nothing->is_artificial_var = 1;
+ var_nothing->offset = 0;
+ var_nothing->size = ~0;
+ var_nothing->fullsize = ~0;
+ nothing_id = 0;
+ VEC_safe_push (varinfo_t, gc, varmap, var_nothing);
+
+ /* Create the ANYTHING variable, used to represent that a variable
+ points to some unknown piece of memory. */
+ anything_tree = create_tmp_var_raw (void_type_node, "ANYTHING");
+ var_anything = new_var_info (anything_tree, 1, "ANYTHING", 1);
+ insert_id_for_tree (anything_tree, 1);
+ var_anything->is_artificial_var = 1;
+ var_anything->size = ~0;
+ var_anything->offset = 0;
+ var_anything->next = NULL;
+ var_anything->fullsize = ~0;
+ anything_id = 1;
+
+ /* Anything points to anything. This makes deref constraints just
+ work in the presence of linked list and other p = *p type loops,
+ by saying that *ANYTHING = ANYTHING. */
+ VEC_safe_push (varinfo_t, gc, varmap, var_anything);
+ lhs.type = SCALAR;
+ lhs.var = anything_id;
+ lhs.offset = 0;
+ rhs.type = ADDRESSOF;
+ rhs.var = anything_id;
+ rhs.offset = 0;
+ var_anything->address_taken = true;
+ process_constraint (new_constraint (lhs, rhs));
+
+
+ /* Create the READONLY variable, used to represent that a variable
+ points to readonly memory. */
+ readonly_tree = create_tmp_var_raw (void_type_node, "READONLY");
+ var_readonly = new_var_info (readonly_tree, 2, "READONLY", 2);
+ var_readonly->is_artificial_var = 1;
+ var_readonly->offset = 0;
+ var_readonly->size = ~0;
+ var_readonly->fullsize = ~0;
+ var_readonly->next = NULL;
+ insert_id_for_tree (readonly_tree, 2);
+ readonly_id = 2;
+ VEC_safe_push (varinfo_t, gc, varmap, var_readonly);
+
+ /* readonly memory points to anything, in order to make deref
+ easier. In reality, it points to anything the particular
+ readonly variable can point to, but we don't track this
+ seperately. */
+ lhs.type = SCALAR;
+ lhs.var = readonly_id;
+ lhs.offset = 0;
+ rhs.type = ADDRESSOF;
+ rhs.var = anything_id;
+ rhs.offset = 0;
+ var_readonly->address_taken = true;
+
+ process_constraint (new_constraint (lhs, rhs));
+
+ /* Create the INTEGER variable, used to represent that a variable points
+ to an INTEGER. */
+ integer_tree = create_tmp_var_raw (void_type_node, "INTEGER");
+ var_integer = new_var_info (integer_tree, 3, "INTEGER", 3);
+ insert_id_for_tree (integer_tree, 3);
+ var_integer->is_artificial_var = 1;
+ var_integer->size = ~0;
+ var_integer->fullsize = ~0;
+ var_integer->offset = 0;
+ var_integer->next = NULL;
+ integer_id = 3;
+ VEC_safe_push (varinfo_t, gc, varmap, var_integer);
+}
+
+
+/* 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)
+{
+ basic_block bb;
+
+
+ init_alias_vars ();
+
+ constraint_pool = create_alloc_pool ("Constraint pool",
+ sizeof (struct constraint), 30);
+ variable_info_pool = create_alloc_pool ("Variable info pool",
+ sizeof (struct variable_info), 30);
+ constraint_edge_pool = create_alloc_pool ("Constraint edges",
+ sizeof (struct constraint_edge), 30);
+
+ constraints = VEC_alloc (constraint_t, gc, 8);
+ 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 ();
+
+ /* Now walk all statements and derive aliases. */
+ FOR_EACH_BB (bb)
+ {
+ block_stmt_iterator bsi;
+ tree phi;
+
+ for (phi = phi_nodes (bb); phi; phi = TREE_CHAIN (phi))
+ if (is_gimple_reg (PHI_RESULT (phi)))
+ find_func_aliases (phi);
+
+ for (bsi = bsi_start (bb); !bsi_end_p (bsi); bsi_next (&bsi))
+ find_func_aliases (bsi_stmt (bsi));
+ }
+
+ build_constraint_graph ();
+
+ if (dump_file)
+ {
+ fprintf (dump_file, "Constraints:\n");
+ dump_constraints (dump_file);
+ }
+
+ if (dump_file)
+ fprintf (dump_file, "Collapsing 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");
+
+ solve_graph (graph);
+
+ if (dump_file)
+ dump_sa_points_to_info (dump_file);
+
+ have_alias_info = true;
+}
+
+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)
+{
+ htab_delete (id_for_tree);
+ free_alloc_pool (variable_info_pool);
+ free_alloc_pool (constraint_pool);
+ free_alloc_pool (constraint_edge_pool);
+ 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 */
+};
diff --git a/gcc/tree-ssa-structalias.h b/gcc/tree-ssa-structalias.h
new file mode 100644
index 0000000..4725f28
--- /dev/null
+++ b/gcc/tree-ssa-structalias.h
@@ -0,0 +1,33 @@
+/* Tree based points-to analysis
+ Copyright (C) 2002, 2003 Free Software Foundation, Inc.
+ Contributed by Daniel Berlin <dberlin@dberlin.org>
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify
+under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+GCC is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+#ifndef TREE_ALIAS_COMMON
+#define TREE_ALIAS_COMMON
+
+struct constraint;
+typedef struct constraint *constraint_t;
+extern void dump_constraint (FILE *, constraint_t);
+extern void dump_constraints (FILE *);
+extern void debug_constraint (constraint_t);
+extern void debug_constraints (void);
+extern void dump_solution_for_var (FILE *, unsigned int);
+extern void debug_solution_for_var (unsigned int);
+#endif /* TREE_ALIAS_COMMON */