aboutsummaryrefslogtreecommitdiff
path: root/gcc/tree-ssa-structalias.cc
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/tree-ssa-structalias.cc')
-rw-r--r--gcc/tree-ssa-structalias.cc3370
1 files changed, 355 insertions, 3015 deletions
diff --git a/gcc/tree-ssa-structalias.cc b/gcc/tree-ssa-structalias.cc
index 0215243..0035e50 100644
--- a/gcc/tree-ssa-structalias.cc
+++ b/gcc/tree-ssa-structalias.cc
@@ -48,6 +48,9 @@
#include "ipa-modref.h"
#include "attr-fnspec.h"
+#include "tree-ssa-structalias.h"
+#include "pta-andersen.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.
@@ -201,172 +204,357 @@
And probably more. */
-static bool use_field_sensitive = true;
-static int in_ipa_mode = 0;
-
-/* Used for predecessor bitmaps. */
-static bitmap_obstack predbitmap_obstack;
+namespace pointer_analysis {
/* Used for points-to sets. */
-static bitmap_obstack pta_obstack;
+bitmap_obstack pta_obstack;
-/* Used for oldsolution members of variables. */
-static bitmap_obstack oldpta_obstack;
+/* Used for oldsolution members of variables. */
+bitmap_obstack oldpta_obstack;
-/* Used for per-solver-iteration bitmaps. */
-static bitmap_obstack iteration_obstack;
+/* Table of variable info structures for constraint variables.
+ Indexed directly by variable info id. */
+vec<varinfo_t> varmap;
-static unsigned int create_variable_info_for (tree, const char *, bool);
-typedef struct constraint_graph *constraint_graph_t;
-static void unify_nodes (constraint_graph_t, unsigned int, unsigned int, bool);
+/* List of constraints that we use to build the constraint graph from. */
+vec<constraint_t> constraints;
+
+/* Map from trees to variable infos. */
+static hash_map<tree, varinfo_t> *vi_for_tree;
-struct constraint;
-typedef struct constraint *constraint_t;
+/* The representative variable for a variable. The points-to solution for a
+ var can be found in its rep. Trivially, a var can be its own rep.
+ The solver provides this array once it is done solving. */
+unsigned int *var_rep;
-#define EXECUTE_IF_IN_NONNULL_BITMAP(a, b, c, d) \
- if (a) \
- EXECUTE_IF_SET_IN_BITMAP (a, b, c, d)
+struct constraint_stats stats;
-static struct constraint_stats
+/* Find the first varinfo in the same variable as START that overlaps with
+ OFFSET. Return NULL if we can't find one. */
+
+varinfo_t
+first_vi_for_offset (varinfo_t start, unsigned HOST_WIDE_INT offset)
{
- unsigned int total_vars;
- unsigned int nonpointer_vars;
- unsigned int unified_vars_static;
- unsigned int unified_vars_dynamic;
- unsigned int iterations;
- unsigned int num_edges;
- unsigned int num_implicit_edges;
- unsigned int num_avoided_edges;
- unsigned int points_to_sets_created;
-} stats;
-
-struct variable_info
+ /* If the offset is outside of the variable, bail out. */
+ if (offset >= start->fullsize)
+ return NULL;
+
+ /* If we cannot reach offset from start, lookup the first field
+ and start from there. */
+ if (start->offset > offset)
+ start = get_varinfo (start->head);
+
+ while (start)
+ {
+ /* We may not find a variable in the field list with the actual
+ offset 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 >= start->offset
+ && (offset - start->offset) < start->size)
+ return start;
+
+ start = vi_next (start);
+ }
+
+ return NULL;
+}
+
+/* Find the first varinfo in the same variable as START that overlaps with
+ OFFSET. If there is no such varinfo the varinfo directly preceding
+ OFFSET is returned. */
+
+varinfo_t
+first_or_preceding_vi_for_offset (varinfo_t start,
+ unsigned HOST_WIDE_INT offset)
{
- /* ID of this variable */
- unsigned int id;
+ /* If we cannot reach offset from start, lookup the first field
+ and start from there. */
+ if (start->offset > offset)
+ start = get_varinfo (start->head);
- /* 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;
+ /* We may not find a variable in the field list with the actual
+ offset when we have glommed a structure to a variable.
+ In that case, however, offset should still be within the size
+ of the variable.
+ If we got beyond the offset we look for return the field
+ directly preceding offset which may be the last field. */
+ while (start->next
+ && offset >= start->offset
+ && !((offset - start->offset) < start->size))
+ start = vi_next (start);
- /* True if this is a special variable whose solution set should not be
- changed. */
- unsigned int is_special_var : 1;
+ return start;
+}
- /* True for variables whose size is not known or variable. */
- unsigned int is_unknown_size_var : 1;
+/* Print out constraint C to FILE. */
- /* True for (sub-)fields that represent a whole variable. */
- unsigned int is_full_var : 1;
+void
+dump_constraint (FILE *file, constraint_t c)
+{
+ if (c->lhs.type == ADDRESSOF)
+ fprintf (file, "&");
+ else if (c->lhs.type == DEREF)
+ fprintf (file, "*");
+ if (dump_file)
+ fprintf (file, "%s", get_varinfo (c->lhs.var)->name);
+ else
+ fprintf (file, "V%d", c->lhs.var);
+ if (c->lhs.offset == UNKNOWN_OFFSET)
+ fprintf (file, " + UNKNOWN");
+ else 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, "*");
+ if (dump_file)
+ fprintf (file, "%s", get_varinfo (c->rhs.var)->name);
+ else
+ fprintf (file, "V%d", c->rhs.var);
+ if (c->rhs.offset == UNKNOWN_OFFSET)
+ fprintf (file, " + UNKNOWN");
+ else if (c->rhs.offset != 0)
+ fprintf (file, " + " HOST_WIDE_INT_PRINT_DEC, c->rhs.offset);
+}
- /* True if this is a heap variable. */
- unsigned int is_heap_var : 1;
+/* Print out constraint C to stderr. */
- /* True if this is a register variable. */
- unsigned int is_reg_var : 1;
+DEBUG_FUNCTION void
+debug_constraint (constraint_t c)
+{
+ dump_constraint (stderr, c);
+ fprintf (stderr, "\n");
+}
- /* True if this field may contain pointers. */
- unsigned int may_have_pointers : 1;
+/* Print out all constraints to FILE. */
- /* True if this field has only restrict qualified pointers. */
- unsigned int only_restrict_pointers : 1;
+void
+dump_constraints (FILE *file, int from)
+{
+ int i;
+ constraint_t c;
+ for (i = from; constraints.iterate (i, &c); i++)
+ if (c)
+ {
+ dump_constraint (file, c);
+ fprintf (file, "\n");
+ }
+}
- /* True if this represents a heap var created for a restrict qualified
- pointer. */
- unsigned int is_restrict_var : 1;
+/* Print out all constraints to stderr. */
- /* True if this represents a global variable. */
- unsigned int is_global_var : 1;
+DEBUG_FUNCTION void
+debug_constraints (void)
+{
+ dump_constraints (stderr, 0);
+}
- /* True if this represents a module escape point for IPA analysis. */
- unsigned int is_ipa_escape_point : 1;
+/* Print out the points-to solution for VAR to FILE. */
- /* True if this represents a IPA function info. */
- unsigned int is_fn_info : 1;
+void
+dump_solution_for_var (FILE *file, unsigned int var)
+{
+ varinfo_t vi = get_varinfo (var);
+ unsigned int i;
+ bitmap_iterator bi;
- /* True if this appears as RHS in a ADDRESSOF constraint. */
- unsigned int address_taken : 1;
+ /* Dump the solution for unified vars anyway, this avoids difficulties
+ in scanning dumps in the testsuite. */
+ fprintf (file, "%s = { ", vi->name);
+ vi = get_varinfo (var_rep[var]);
+ EXECUTE_IF_SET_IN_BITMAP (vi->solution, 0, i, bi)
+ fprintf (file, "%s ", get_varinfo (i)->name);
+ fprintf (file, "}");
- /* ??? Store somewhere better. */
- unsigned short ruid;
+ /* But note when the variable was unified. */
+ if (vi->id != var)
+ fprintf (file, " same as %s", vi->name);
- /* The ID of the variable for the next field in this structure
- or zero for the last field in this structure. */
- unsigned next;
+ fprintf (file, "\n");
+}
- /* The ID of the variable for the first field in this structure. */
- unsigned head;
+/* Print the points-to solution for VAR to stderr. */
- /* Offset of this variable, in bits, from the base variable */
- unsigned HOST_WIDE_INT offset;
+DEBUG_FUNCTION void
+debug_solution_for_var (unsigned int var)
+{
+ dump_solution_for_var (stderr, var);
+}
- /* Size of the variable, in bits. */
- unsigned HOST_WIDE_INT size;
+/* Dump stats information to OUTFILE. */
- /* Full size of the base variable, in bits. */
- unsigned HOST_WIDE_INT fullsize;
+void
+dump_sa_stats (FILE *outfile)
+{
+ fprintf (outfile, "Points-to Stats:\n");
+ fprintf (outfile, "Total vars: %d\n", stats.total_vars);
+ fprintf (outfile, "Non-pointer vars: %d\n",
+ stats.nonpointer_vars);
+ fprintf (outfile, "Statically unified vars: %d\n",
+ stats.unified_vars_static);
+ fprintf (outfile, "Dynamically unified vars: %d\n",
+ stats.unified_vars_dynamic);
+ fprintf (outfile, "Iterations: %d\n", stats.iterations);
+ fprintf (outfile, "Number of edges: %d\n", stats.num_edges);
+ fprintf (outfile, "Number of implicit edges: %d\n",
+ stats.num_implicit_edges);
+ fprintf (outfile, "Number of avoided edges: %d\n",
+ stats.num_avoided_edges);
+}
- /* In IPA mode the shadow UID in case the variable needs to be duplicated in
- the final points-to solution because it reaches its containing
- function recursively. Zero if none is needed. */
- unsigned int shadow_var_uid;
+/* Dump points-to information to OUTFILE. */
- /* Name of this variable */
- const char *name;
+void
+dump_sa_points_to_info (FILE *outfile)
+{
+ fprintf (outfile, "\nPoints-to sets\n\n");
- /* Tree that this variable is associated with. */
- tree decl;
+ for (unsigned i = 1; i < varmap.length (); i++)
+ {
+ varinfo_t vi = get_varinfo (i);
+ if (!vi->may_have_pointers)
+ continue;
+ dump_solution_for_var (outfile, i);
+ }
+}
- /* Points-to set for this variable. */
- bitmap solution;
- /* Old points-to set for this variable. */
- bitmap oldsolution;
-};
-typedef struct variable_info *varinfo_t;
+/* Debug points-to information to stderr. */
-static varinfo_t first_vi_for_offset (varinfo_t, unsigned HOST_WIDE_INT);
-static varinfo_t first_or_preceding_vi_for_offset (varinfo_t,
- unsigned HOST_WIDE_INT);
-static varinfo_t lookup_vi_for_tree (tree);
-static inline bool type_can_have_subvars (const_tree);
-static void make_param_constraints (varinfo_t);
+DEBUG_FUNCTION void
+debug_sa_points_to_info (void)
+{
+ dump_sa_points_to_info (stderr);
+}
-/* Pool of variable info structures. */
-static object_allocator<variable_info> variable_info_pool
- ("Variable info pool");
+/* Dump varinfo VI to FILE. */
-/* Map varinfo to final pt_solution. */
-static hash_map<varinfo_t, pt_solution *> *final_solutions;
-struct obstack final_solutions_obstack;
+void
+dump_varinfo (FILE *file, varinfo_t vi)
+{
+ if (vi == NULL)
+ return;
-/* Table of variable info structures for constraint variables.
- Indexed directly by variable info id. */
-static vec<varinfo_t> varmap;
+ fprintf (file, "%u: %s\n", vi->id, vi->name);
-/* Return the varmap element N */
+ const char *sep = " ";
+ if (vi->is_artificial_var)
+ fprintf (file, "%sartificial", sep);
+ if (vi->is_special_var)
+ fprintf (file, "%sspecial", sep);
+ if (vi->is_unknown_size_var)
+ fprintf (file, "%sunknown-size", sep);
+ if (vi->is_full_var)
+ fprintf (file, "%sfull", sep);
+ if (vi->is_heap_var)
+ fprintf (file, "%sheap", sep);
+ if (vi->may_have_pointers)
+ fprintf (file, "%smay-have-pointers", sep);
+ if (vi->only_restrict_pointers)
+ fprintf (file, "%sonly-restrict-pointers", sep);
+ if (vi->is_restrict_var)
+ fprintf (file, "%sis-restrict-var", sep);
+ if (vi->is_global_var)
+ fprintf (file, "%sglobal", sep);
+ if (vi->is_ipa_escape_point)
+ fprintf (file, "%sipa-escape-point", sep);
+ if (vi->is_fn_info)
+ fprintf (file, "%sfn-info", sep);
+ if (vi->ruid)
+ fprintf (file, "%srestrict-uid:%u", sep, vi->ruid);
+ if (vi->next)
+ fprintf (file, "%snext:%u", sep, vi->next);
+ if (vi->head != vi->id)
+ fprintf (file, "%shead:%u", sep, vi->head);
+ if (vi->offset)
+ fprintf (file, "%soffset:" HOST_WIDE_INT_PRINT_DEC, sep, vi->offset);
+ if (vi->size != ~HOST_WIDE_INT_0U)
+ fprintf (file, "%ssize:" HOST_WIDE_INT_PRINT_DEC, sep, vi->size);
+ if (vi->fullsize != ~HOST_WIDE_INT_0U && vi->fullsize != vi->size)
+ fprintf (file, "%sfullsize:" HOST_WIDE_INT_PRINT_DEC, sep,
+ vi->fullsize);
+ fprintf (file, "\n");
-static inline varinfo_t
-get_varinfo (unsigned int n)
+ if (vi->solution && !bitmap_empty_p (vi->solution))
+ {
+ bitmap_iterator bi;
+ unsigned i;
+ fprintf (file, " solution: {");
+ EXECUTE_IF_SET_IN_BITMAP (vi->solution, 0, i, bi)
+ fprintf (file, " %u", i);
+ fprintf (file, " }\n");
+ }
+
+ if (vi->oldsolution && !bitmap_empty_p (vi->oldsolution)
+ && !bitmap_equal_p (vi->solution, vi->oldsolution))
+ {
+ bitmap_iterator bi;
+ unsigned i;
+ fprintf (file, " oldsolution: {");
+ EXECUTE_IF_SET_IN_BITMAP (vi->oldsolution, 0, i, bi)
+ fprintf (file, " %u", i);
+ fprintf (file, " }\n");
+ }
+}
+
+/* Dump varinfo VI to stderr. */
+
+DEBUG_FUNCTION void
+debug_varinfo (varinfo_t vi)
+{
+ dump_varinfo (stderr, vi);
+}
+
+/* Dump varmap to FILE. */
+
+void
+dump_varmap (FILE *file)
{
- return varmap[n];
+ if (varmap.length () == 0)
+ return;
+
+ fprintf (file, "variables:\n");
+
+ for (unsigned int i = 0; i < varmap.length (); ++i)
+ {
+ varinfo_t vi = get_varinfo (i);
+ dump_varinfo (file, vi);
+ }
+
+ fprintf (file, "\n");
}
-/* Return the next variable in the list of sub-variables of VI
- or NULL if VI is the last sub-variable. */
+/* Dump varmap to stderr. */
-static inline varinfo_t
-vi_next (varinfo_t vi)
+DEBUG_FUNCTION void
+debug_varmap (void)
{
- return get_varinfo (vi->next);
+ dump_varmap (stderr);
}
-/* Static IDs for the special variables. Variable ID zero is unused
- and used as terminator for the sub-variable chain. */
-enum { nothing_id = 1, anything_id = 2, string_id = 3,
- escaped_id = 4, nonlocal_id = 5, escaped_return_id = 6,
- storedanything_id = 7, integer_id = 8 };
+} // namespace pointer_analysis
+
+
+using namespace pointer_analysis;
+
+static bool use_field_sensitive = true;
+static int in_ipa_mode = 0;
+
+static unsigned int create_variable_info_for (tree, const char *, bool);
+static varinfo_t lookup_vi_for_tree (tree);
+static inline bool type_can_have_subvars (const_tree);
+static void make_param_constraints (varinfo_t);
+
+/* Pool of variable info structures. */
+static object_allocator<variable_info> variable_info_pool
+ ("Variable info pool");
+
+/* Map varinfo to final pt_solution. */
+static hash_map<varinfo_t, pt_solution *> *final_solutions;
+static struct obstack final_solutions_obstack;
/* Return a new variable info structure consisting for a variable
named NAME, and using constraint graph node NODE. Append it
@@ -502,166 +690,15 @@ get_call_clobber_vi (gcall *call)
}
-enum constraint_expr_type {SCALAR, DEREF, ADDRESSOF};
-
-/* 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. */
- HOST_WIDE_INT offset;
-};
-
-/* Use 0x8000... as special unknown offset. */
-#define UNKNOWN_OFFSET HOST_WIDE_INT_MIN
-
-typedef struct constraint_expr ce_s;
static void get_constraint_for_1 (tree, vec<ce_s> *, bool, bool);
static void get_constraint_for (tree, vec<ce_s> *);
static void get_constraint_for_rhs (tree, vec<ce_s> *);
static void do_deref (vec<ce_s> *);
-/* 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;
-};
+/* Allocator for 'constraints' vector. */
-/* List of constraints that we use to build the constraint graph from. */
-
-static vec<constraint_t> constraints;
static object_allocator<constraint> constraint_pool ("Constraint pool");
-/* The constraint graph is represented as an array of bitmaps
- containing successor nodes. */
-
-struct constraint_graph
-{
- /* Size of this graph, which may be different than the number of
- nodes in the variable map. */
- unsigned int size;
-
- /* Explicit successors of each node. */
- bitmap *succs;
-
- /* Implicit predecessors of each node (Used for variable
- substitution). */
- bitmap *implicit_preds;
-
- /* Explicit predecessors of each node (Used for variable substitution). */
- bitmap *preds;
-
- /* Indirect cycle representatives, or -1 if the node has no indirect
- cycles. */
- int *indirect_cycles;
-
- /* Representative node for a node. rep[a] == a unless the node has
- been unified. */
- unsigned int *rep;
-
- /* Equivalence class representative for a label. This is used for
- variable substitution. */
- int *eq_rep;
-
- /* Pointer equivalence label for a node. All nodes with the same
- pointer equivalence label can be unified together at some point
- (either during constraint optimization or after the constraint
- graph is built). */
- unsigned int *pe;
-
- /* Pointer equivalence representative for a label. This is used to
- handle nodes that are pointer equivalent but not location
- equivalent. We can unite these once the addressof constraints
- are transformed into initial points-to sets. */
- int *pe_rep;
-
- /* Pointer equivalence label for each node, used during variable
- substitution. */
- unsigned int *pointer_label;
-
- /* Location equivalence label for each node, used during location
- equivalence finding. */
- unsigned int *loc_label;
-
- /* Pointed-by set for each node, used during location equivalence
- finding. This is pointed-by rather than pointed-to, because it
- is constructed using the predecessor graph. */
- bitmap *pointed_by;
-
- /* Points to sets for pointer equivalence. This is *not* the actual
- points-to sets for nodes. */
- bitmap *points_to;
-
- /* Bitmap of nodes where the bit is set if the node is a direct
- node. Used for variable substitution. */
- sbitmap direct_nodes;
-
- /* Bitmap of nodes where the bit is set if the node is address
- taken. Used for variable substitution. */
- bitmap address_taken;
-
- /* Vector of complex constraints for each graph node. Complex
- constraints are those involving dereferences or offsets that are
- not 0. */
- vec<constraint_t> *complex;
-};
-
-static constraint_graph_t graph;
-
-/* During variable substitution and the offline version of indirect
- cycle finding, we create nodes to represent dereferences and
- address taken constraints. These represent where these start and
- end. */
-#define FIRST_REF_NODE (varmap).length ()
-#define LAST_REF_NODE (FIRST_REF_NODE + (FIRST_REF_NODE - 1))
-
-/* Return the representative node for NODE, if NODE has been unioned
- with another NODE.
- This function performs path compression along the way to finding
- the representative. */
-
-static unsigned int
-find (unsigned int node)
-{
- gcc_checking_assert (node < graph->size);
- if (graph->rep[node] != node)
- return graph->rep[node] = find (graph->rep[node]);
- return node;
-}
-
-/* Union the TO and FROM nodes to the TO nodes.
- Note that at some point in the future, we may want to do
- union-by-rank, in which case we are going to have to return the
- node we unified to. */
-
-static bool
-unite (unsigned int to, unsigned int from)
-{
- gcc_checking_assert (to < graph->size && from < graph->size);
- if (to != from && graph->rep[from] != to)
- {
- graph->rep[from] = to;
- return true;
- }
- return false;
-}
-
/* Create a new constraint consisting of LHS and RHS expressions. */
static constraint_t
@@ -674,2312 +711,6 @@ new_constraint (const struct constraint_expr lhs,
return ret;
}
-/* Print out constraint C to FILE. */
-
-static void
-dump_constraint (FILE *file, constraint_t c)
-{
- if (c->lhs.type == ADDRESSOF)
- fprintf (file, "&");
- else if (c->lhs.type == DEREF)
- fprintf (file, "*");
- if (dump_file)
- fprintf (file, "%s", get_varinfo (c->lhs.var)->name);
- else
- fprintf (file, "V%d", c->lhs.var);
- if (c->lhs.offset == UNKNOWN_OFFSET)
- fprintf (file, " + UNKNOWN");
- else 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, "*");
- if (dump_file)
- fprintf (file, "%s", get_varinfo (c->rhs.var)->name);
- else
- fprintf (file, "V%d", c->rhs.var);
- if (c->rhs.offset == UNKNOWN_OFFSET)
- fprintf (file, " + UNKNOWN");
- else if (c->rhs.offset != 0)
- fprintf (file, " + " HOST_WIDE_INT_PRINT_DEC, c->rhs.offset);
-}
-
-
-void debug_constraint (constraint_t);
-void debug_constraints (void);
-void debug_constraint_graph (void);
-void debug_solution_for_var (unsigned int);
-void debug_sa_points_to_info (void);
-void debug_varinfo (varinfo_t);
-void debug_varmap (void);
-
-/* Print out constraint C to stderr. */
-
-DEBUG_FUNCTION void
-debug_constraint (constraint_t c)
-{
- dump_constraint (stderr, c);
- fprintf (stderr, "\n");
-}
-
-/* Print out all constraints to FILE */
-
-static void
-dump_constraints (FILE *file, int from)
-{
- int i;
- constraint_t c;
- for (i = from; constraints.iterate (i, &c); i++)
- if (c)
- {
- dump_constraint (file, c);
- fprintf (file, "\n");
- }
-}
-
-/* Print out all constraints to stderr. */
-
-DEBUG_FUNCTION void
-debug_constraints (void)
-{
- dump_constraints (stderr, 0);
-}
-
-/* Print the constraint graph in dot format. */
-
-static void
-dump_constraint_graph (FILE *file)
-{
- unsigned int i;
-
- /* Only print the graph if it has already been initialized: */
- if (!graph)
- return;
-
- /* Prints the header of the dot file: */
- fprintf (file, "strict digraph {\n");
- fprintf (file, " node [\n shape = box\n ]\n");
- fprintf (file, " edge [\n fontsize = \"12\"\n ]\n");
- fprintf (file, "\n // List of nodes and complex constraints in "
- "the constraint graph:\n");
-
- /* The next lines print the nodes in the graph together with the
- complex constraints attached to them. */
- for (i = 1; i < graph->size; i++)
- {
- if (i == FIRST_REF_NODE)
- continue;
- if (find (i) != i)
- continue;
- if (i < FIRST_REF_NODE)
- fprintf (file, "\"%s\"", get_varinfo (i)->name);
- else
- fprintf (file, "\"*%s\"", get_varinfo (i - FIRST_REF_NODE)->name);
- if (graph->complex[i].exists ())
- {
- unsigned j;
- constraint_t c;
- fprintf (file, " [label=\"\\N\\n");
- for (j = 0; graph->complex[i].iterate (j, &c); ++j)
- {
- dump_constraint (file, c);
- fprintf (file, "\\l");
- }
- fprintf (file, "\"]");
- }
- fprintf (file, ";\n");
- }
-
- /* Go over the edges. */
- fprintf (file, "\n // Edges in the constraint graph:\n");
- for (i = 1; i < graph->size; i++)
- {
- unsigned j;
- bitmap_iterator bi;
- if (find (i) != i)
- continue;
- EXECUTE_IF_IN_NONNULL_BITMAP (graph->succs[i], 0, j, bi)
- {
- unsigned to = find (j);
- if (i == to)
- continue;
- if (i < FIRST_REF_NODE)
- fprintf (file, "\"%s\"", get_varinfo (i)->name);
- else
- fprintf (file, "\"*%s\"", get_varinfo (i - FIRST_REF_NODE)->name);
- fprintf (file, " -> ");
- if (to < FIRST_REF_NODE)
- fprintf (file, "\"%s\"", get_varinfo (to)->name);
- else
- fprintf (file, "\"*%s\"", get_varinfo (to - FIRST_REF_NODE)->name);
- fprintf (file, ";\n");
- }
- }
-
- /* Prints the tail of the dot file. */
- fprintf (file, "}\n");
-}
-
-/* Print out the constraint graph to stderr. */
-
-DEBUG_FUNCTION void
-debug_constraint_graph (void)
-{
- dump_constraint_graph (stderr);
-}
-
-/* SOLVER FUNCTIONS
-
- The solver is a simple worklist solver, that works on the following
- algorithm:
-
- sbitmap changed_nodes = all zeroes;
- changed_count = 0;
- For each node that is not already collapsed:
- changed_count++;
- set bit in changed nodes
-
- 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 (const constraint &a, const 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> vec,
- constraint &lookfor)
-{
- unsigned int place;
- constraint_t found;
-
- if (!vec.exists ())
- return NULL;
-
- place = vec.lower_bound (&lookfor, constraint_less);
- if (place >= vec.length ())
- return NULL;
- found = vec[place];
- if (!constraint_equal (*found, lookfor))
- return NULL;
- return found;
-}
-
-/* Union two constraint vectors, TO and FROM. Put the result in TO.
- Returns true of TO set is changed. */
-
-static bool
-constraint_set_union (vec<constraint_t> *to,
- vec<constraint_t> *from)
-{
- int i;
- constraint_t c;
- bool any_change = false;
-
- FOR_EACH_VEC_ELT (*from, i, c)
- {
- if (constraint_vec_find (*to, *c) == NULL)
- {
- unsigned int place = to->lower_bound (c, constraint_less);
- to->safe_insert (place, c);
- any_change = true;
- }
- }
- return any_change;
-}
-
-/* Expands the solution in SET to all sub-fields of variables included. */
-
-static bitmap
-solution_set_expand (bitmap set, bitmap *expanded)
-{
- bitmap_iterator bi;
- unsigned j;
-
- if (*expanded)
- return *expanded;
-
- *expanded = BITMAP_ALLOC (&iteration_obstack);
-
- /* In a first pass expand variables, once for each head to avoid
- quadratic behavior, to include all sub-fields. */
- unsigned prev_head = 0;
- EXECUTE_IF_SET_IN_BITMAP (set, 0, j, bi)
- {
- varinfo_t v = get_varinfo (j);
- if (v->is_artificial_var
- || v->is_full_var)
- continue;
- if (v->head != prev_head)
- {
- varinfo_t head = get_varinfo (v->head);
- unsigned num = 1;
- for (varinfo_t n = vi_next (head); n != NULL; n = vi_next (n))
- {
- if (n->id != head->id + num)
- {
- /* Usually sub variables are adjacent but since we
- create pointed-to restrict representatives there
- can be gaps as well. */
- bitmap_set_range (*expanded, head->id, num);
- head = n;
- num = 1;
- }
- else
- num++;
- }
-
- bitmap_set_range (*expanded, head->id, num);
- prev_head = v->head;
- }
- }
-
- /* And finally set the rest of the bits from SET in an efficient way. */
- bitmap_ior_into (*expanded, set);
-
- return *expanded;
-}
-
-/* Union solution sets TO and DELTA, and add INC to each member of DELTA in the
- process. */
-
-static bool
-set_union_with_increment (bitmap to, bitmap delta, HOST_WIDE_INT inc,
- bitmap *expanded_delta)
-{
- bool changed = false;
- bitmap_iterator bi;
- unsigned int i;
-
- /* If the solution of DELTA contains anything it is good enough to transfer
- this to TO. */
- if (bitmap_bit_p (delta, anything_id))
- return bitmap_set_bit (to, anything_id);
-
- /* If the offset is unknown we have to expand the solution to
- all subfields. */
- if (inc == UNKNOWN_OFFSET)
- {
- delta = solution_set_expand (delta, expanded_delta);
- changed |= bitmap_ior_into (to, delta);
- return changed;
- }
-
- /* For non-zero offset union the offsetted solution into the destination. */
- EXECUTE_IF_SET_IN_BITMAP (delta, 0, i, bi)
- {
- varinfo_t vi = get_varinfo (i);
-
- /* If this is a variable with just one field just set its bit
- in the result. */
- if (vi->is_artificial_var
- || vi->is_unknown_size_var
- || vi->is_full_var)
- changed |= bitmap_set_bit (to, i);
- else
- {
- HOST_WIDE_INT fieldoffset = vi->offset + inc;
- unsigned HOST_WIDE_INT size = vi->size;
-
- /* If the offset makes the pointer point to before the
- variable use offset zero for the field lookup. */
- if (fieldoffset < 0)
- vi = get_varinfo (vi->head);
- else
- vi = first_or_preceding_vi_for_offset (vi, fieldoffset);
-
- do
- {
- changed |= bitmap_set_bit (to, vi->id);
- if (vi->is_full_var
- || vi->next == 0)
- break;
-
- /* We have to include all fields that overlap the current field
- shifted by inc. */
- vi = vi_next (vi);
- }
- while (vi->offset < fieldoffset + size);
- }
- }
-
- return changed;
-}
-
-/* Insert constraint C into the list of complex constraints for graph
- node VAR. */
-
-static void
-insert_into_complex (constraint_graph_t graph,
- unsigned int var, constraint_t c)
-{
- vec<constraint_t> complex = graph->complex[var];
- unsigned int place = complex.lower_bound (c, constraint_less);
-
- /* Only insert constraints that do not already exist. */
- if (place >= complex.length ()
- || !constraint_equal (*c, *complex[place]))
- graph->complex[var].safe_insert (place, c);
-}
-
-
-/* Condense two variable nodes into a single variable node, by moving
- all associated info from FROM to TO. Returns true if TO node's
- constraint set changes after the merge. */
-
-static bool
-merge_node_constraints (constraint_graph_t graph, unsigned int to,
- unsigned int from)
-{
- unsigned int i;
- constraint_t c;
- bool any_change = false;
-
- gcc_checking_assert (find (from) == to);
-
- /* Move all complex constraints from src node into to node */
- FOR_EACH_VEC_ELT (graph->complex[from], i, c)
- {
- /* In complex constraints for node FROM, we may have either
- a = *FROM, and *FROM = a, or an offseted constraint which are
- always added to the rhs node's constraints. */
-
- if (c->rhs.type == DEREF)
- c->rhs.var = to;
- else if (c->lhs.type == DEREF)
- c->lhs.var = to;
- else
- c->rhs.var = to;
-
- }
- any_change = constraint_set_union (&graph->complex[to],
- &graph->complex[from]);
- graph->complex[from].release ();
- return any_change;
-}
-
-
-/* Remove edges involving NODE from GRAPH. */
-
-static void
-clear_edges_for_node (constraint_graph_t graph, unsigned int node)
-{
- if (graph->succs[node])
- BITMAP_FREE (graph->succs[node]);
-}
-
-/* Merge GRAPH nodes FROM and TO into node TO. */
-
-static void
-merge_graph_nodes (constraint_graph_t graph, unsigned int to,
- unsigned int from)
-{
- if (graph->indirect_cycles[from] != -1)
- {
- /* If we have indirect cycles with the from node, and we have
- none on the to node, the to node has indirect cycles from the
- from node now that they are unified.
- If indirect cycles exist on both, unify the nodes that they
- are in a cycle with, since we know they are in a cycle with
- each other. */
- if (graph->indirect_cycles[to] == -1)
- graph->indirect_cycles[to] = graph->indirect_cycles[from];
- }
-
- /* Merge all the successor edges. */
- if (graph->succs[from])
- {
- if (!graph->succs[to])
- graph->succs[to] = BITMAP_ALLOC (&pta_obstack);
- bitmap_ior_into (graph->succs[to],
- graph->succs[from]);
- }
-
- clear_edges_for_node (graph, from);
-}
-
-
-/* Add an indirect graph edge to GRAPH, going from TO to FROM if
- it doesn't exist in the graph already. */
-
-static void
-add_implicit_graph_edge (constraint_graph_t graph, unsigned int to,
- unsigned int from)
-{
- if (to == from)
- return;
-
- if (!graph->implicit_preds[to])
- graph->implicit_preds[to] = BITMAP_ALLOC (&predbitmap_obstack);
-
- if (bitmap_set_bit (graph->implicit_preds[to], from))
- stats.num_implicit_edges++;
-}
-
-/* Add a predecessor graph edge to GRAPH, going from TO to FROM if
- it doesn't exist in the graph already.
- Return false if the edge already existed, true otherwise. */
-
-static void
-add_pred_graph_edge (constraint_graph_t graph, unsigned int to,
- unsigned int from)
-{
- if (!graph->preds[to])
- graph->preds[to] = BITMAP_ALLOC (&predbitmap_obstack);
- bitmap_set_bit (graph->preds[to], from);
-}
-
-/* Add a graph edge to GRAPH, going from FROM to TO if
- it doesn't exist in the graph already.
- Return false if the edge already existed, true otherwise. */
-
-static bool
-add_graph_edge (constraint_graph_t graph, unsigned int to,
- unsigned int from)
-{
- if (to == from)
- {
- return false;
- }
- else
- {
- bool r = false;
-
- if (!graph->succs[from])
- graph->succs[from] = BITMAP_ALLOC (&pta_obstack);
-
- /* The graph solving process does not avoid "triangles", thus
- there can be multiple paths from a node to another involving
- intermediate other nodes. That causes extra copying which is
- most difficult to avoid when the intermediate node is ESCAPED
- because there are no edges added from ESCAPED. Avoid
- adding the direct edge FROM -> TO when we have FROM -> ESCAPED
- and TO contains ESCAPED.
- ??? Note this is only a heuristic, it does not prevent the
- situation from occuring. The heuristic helps PR38474 and
- PR99912 significantly. */
- if (to < FIRST_REF_NODE
- && bitmap_bit_p (graph->succs[from], find (escaped_id))
- && bitmap_bit_p (get_varinfo (find (to))->solution, escaped_id))
- {
- stats.num_avoided_edges++;
- return false;
- }
-
- if (bitmap_set_bit (graph->succs[from], to))
- {
- r = true;
- if (to < FIRST_REF_NODE && from < FIRST_REF_NODE)
- stats.num_edges++;
- }
- return r;
- }
-}
-
-
-/* Initialize the constraint graph structure to contain SIZE nodes. */
-
-static void
-init_graph (unsigned int size)
-{
- unsigned int j;
-
- graph = XCNEW (struct constraint_graph);
- graph->size = size;
- graph->succs = XCNEWVEC (bitmap, graph->size);
- graph->indirect_cycles = XNEWVEC (int, graph->size);
- graph->rep = XNEWVEC (unsigned int, graph->size);
- /* ??? Macros do not support template types with multiple arguments,
- so we use a typedef to work around it. */
- typedef vec<constraint_t> vec_constraint_t_heap;
- graph->complex = XCNEWVEC (vec_constraint_t_heap, size);
- graph->pe = XCNEWVEC (unsigned int, graph->size);
- graph->pe_rep = XNEWVEC (int, graph->size);
-
- for (j = 0; j < graph->size; j++)
- {
- graph->rep[j] = j;
- graph->pe_rep[j] = -1;
- graph->indirect_cycles[j] = -1;
- }
-}
-
-/* Build the constraint graph, adding only predecessor edges right now. */
-
-static void
-build_pred_graph (void)
-{
- int i;
- constraint_t c;
- unsigned int j;
-
- graph->implicit_preds = XCNEWVEC (bitmap, graph->size);
- graph->preds = XCNEWVEC (bitmap, graph->size);
- graph->pointer_label = XCNEWVEC (unsigned int, graph->size);
- graph->loc_label = XCNEWVEC (unsigned int, graph->size);
- graph->pointed_by = XCNEWVEC (bitmap, graph->size);
- graph->points_to = XCNEWVEC (bitmap, graph->size);
- graph->eq_rep = XNEWVEC (int, graph->size);
- graph->direct_nodes = sbitmap_alloc (graph->size);
- graph->address_taken = BITMAP_ALLOC (&predbitmap_obstack);
- bitmap_clear (graph->direct_nodes);
-
- for (j = 1; j < FIRST_REF_NODE; j++)
- {
- if (!get_varinfo (j)->is_special_var)
- bitmap_set_bit (graph->direct_nodes, j);
- }
-
- for (j = 0; j < graph->size; j++)
- graph->eq_rep[j] = -1;
-
- for (j = 0; j < varmap.length (); j++)
- graph->indirect_cycles[j] = -1;
-
- FOR_EACH_VEC_ELT (constraints, i, c)
- {
- struct constraint_expr lhs = c->lhs;
- struct constraint_expr rhs = c->rhs;
- unsigned int lhsvar = lhs.var;
- unsigned int rhsvar = rhs.var;
-
- if (lhs.type == DEREF)
- {
- /* *x = y. */
- if (rhs.offset == 0 && lhs.offset == 0 && rhs.type == SCALAR)
- {
- if (lhs.var == anything_id)
- add_pred_graph_edge (graph, storedanything_id, rhsvar);
- else
- add_pred_graph_edge (graph, FIRST_REF_NODE + lhsvar, rhsvar);
- }
- }
- else if (rhs.type == DEREF)
- {
- /* x = *y */
- if (rhs.offset == 0 && lhs.offset == 0 && lhs.type == SCALAR)
- add_pred_graph_edge (graph, lhsvar, FIRST_REF_NODE + rhsvar);
- else
- bitmap_clear_bit (graph->direct_nodes, lhsvar);
- }
- else if (rhs.type == ADDRESSOF)
- {
- varinfo_t v;
-
- /* x = &y */
- if (graph->points_to[lhsvar] == NULL)
- graph->points_to[lhsvar] = BITMAP_ALLOC (&predbitmap_obstack);
- bitmap_set_bit (graph->points_to[lhsvar], rhsvar);
-
- if (graph->pointed_by[rhsvar] == NULL)
- graph->pointed_by[rhsvar] = BITMAP_ALLOC (&predbitmap_obstack);
- bitmap_set_bit (graph->pointed_by[rhsvar], lhsvar);
-
- /* Implicitly, *x = y */
- add_implicit_graph_edge (graph, FIRST_REF_NODE + lhsvar, rhsvar);
-
- /* All related variables are no longer direct nodes. */
- bitmap_clear_bit (graph->direct_nodes, rhsvar);
- v = get_varinfo (rhsvar);
- if (!v->is_full_var)
- {
- v = get_varinfo (v->head);
- do
- {
- bitmap_clear_bit (graph->direct_nodes, v->id);
- v = vi_next (v);
- }
- while (v != NULL);
- }
- bitmap_set_bit (graph->address_taken, rhsvar);
- }
- else if (lhsvar > anything_id
- && lhsvar != rhsvar && lhs.offset == 0 && rhs.offset == 0)
- {
- /* x = y */
- add_pred_graph_edge (graph, lhsvar, rhsvar);
- /* Implicitly, *x = *y */
- add_implicit_graph_edge (graph, FIRST_REF_NODE + lhsvar,
- FIRST_REF_NODE + rhsvar);
- }
- else if (lhs.offset != 0 || rhs.offset != 0)
- {
- if (rhs.offset != 0)
- bitmap_clear_bit (graph->direct_nodes, lhs.var);
- else if (lhs.offset != 0)
- bitmap_clear_bit (graph->direct_nodes, rhs.var);
- }
- }
-}
-
-/* Build the constraint graph, adding successor edges. */
-
-static void
-build_succ_graph (void)
-{
- unsigned i, t;
- constraint_t c;
-
- FOR_EACH_VEC_ELT (constraints, i, c)
- {
- struct constraint_expr lhs;
- struct constraint_expr rhs;
- unsigned int lhsvar;
- unsigned int rhsvar;
-
- if (!c)
- continue;
-
- lhs = c->lhs;
- rhs = c->rhs;
- lhsvar = find (lhs.var);
- rhsvar = find (rhs.var);
-
- if (lhs.type == DEREF)
- {
- if (rhs.offset == 0 && lhs.offset == 0 && rhs.type == SCALAR)
- {
- if (lhs.var == anything_id)
- add_graph_edge (graph, storedanything_id, rhsvar);
- else
- add_graph_edge (graph, FIRST_REF_NODE + lhsvar, rhsvar);
- }
- }
- else if (rhs.type == DEREF)
- {
- if (rhs.offset == 0 && lhs.offset == 0 && lhs.type == SCALAR)
- add_graph_edge (graph, lhsvar, FIRST_REF_NODE + rhsvar);
- }
- else if (rhs.type == ADDRESSOF)
- {
- /* x = &y */
- gcc_checking_assert (find (rhs.var) == rhs.var);
- bitmap_set_bit (get_varinfo (lhsvar)->solution, rhsvar);
- }
- else if (lhsvar > anything_id
- && lhsvar != rhsvar && lhs.offset == 0 && rhs.offset == 0)
- {
- add_graph_edge (graph, lhsvar, rhsvar);
- }
- }
-
- /* Add edges from STOREDANYTHING to all nodes that can receive pointers. */
- t = find (storedanything_id);
- for (i = integer_id + 1; i < FIRST_REF_NODE; ++i)
- {
- if (get_varinfo (i)->may_have_pointers)
- add_graph_edge (graph, find (i), t);
- }
-
- /* Everything stored to ANYTHING also potentially escapes. */
- add_graph_edge (graph, find (escaped_id), t);
-}
-
-
-/* Changed variables on the last iteration. */
-static bitmap changed;
-
-/* Strongly Connected Component visitation info. */
-
-class scc_info
-{
-public:
- scc_info (size_t size);
- ~scc_info ();
-
- auto_sbitmap visited;
- auto_sbitmap deleted;
- unsigned int *dfs;
- unsigned int *node_mapping;
- int current_index;
- auto_vec<unsigned> scc_stack;
-};
-
-
-/* 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, class scc_info *si, unsigned int n)
-{
- unsigned int i;
- bitmap_iterator bi;
- unsigned int my_dfs;
-
- bitmap_set_bit (si->visited, n);
- si->dfs[n] = si->current_index ++;
- my_dfs = si->dfs[n];
-
- /* Visit all the successors. */
- EXECUTE_IF_IN_NONNULL_BITMAP (graph->succs[n], 0, i, bi)
- {
- unsigned int w;
-
- if (i > LAST_REF_NODE)
- break;
-
- w = find (i);
- if (bitmap_bit_p (si->deleted, w))
- continue;
-
- if (!bitmap_bit_p (si->visited, w))
- scc_visit (graph, si, w);
-
- unsigned int t = find (w);
- gcc_checking_assert (find (n) == n);
- if (si->dfs[t] < si->dfs[n])
- si->dfs[n] = si->dfs[t];
- }
-
- /* See if any components have been identified. */
- if (si->dfs[n] == my_dfs)
- {
- if (si->scc_stack.length () > 0
- && si->dfs[si->scc_stack.last ()] >= my_dfs)
- {
- bitmap scc = BITMAP_ALLOC (NULL);
- unsigned int lowest_node;
- bitmap_iterator bi;
-
- bitmap_set_bit (scc, n);
-
- while (si->scc_stack.length () != 0
- && si->dfs[si->scc_stack.last ()] >= my_dfs)
- {
- unsigned int w = si->scc_stack.pop ();
-
- bitmap_set_bit (scc, w);
- }
-
- lowest_node = bitmap_first_set_bit (scc);
- gcc_assert (lowest_node < FIRST_REF_NODE);
-
- /* Collapse the SCC nodes into a single node, and mark the
- indirect cycles. */
- EXECUTE_IF_SET_IN_BITMAP (scc, 0, i, bi)
- {
- if (i < FIRST_REF_NODE)
- {
- if (unite (lowest_node, i))
- unify_nodes (graph, lowest_node, i, false);
- }
- else
- {
- unite (lowest_node, i);
- graph->indirect_cycles[i - FIRST_REF_NODE] = lowest_node;
- }
- }
- bitmap_set_bit (si->deleted, lowest_node);
- }
- else
- bitmap_set_bit (si->deleted, n);
- }
- else
- si->scc_stack.safe_push (n);
-}
-
-/* Unify node FROM into node TO, updating the changed count if
- necessary when UPDATE_CHANGED is true. */
-
-static void
-unify_nodes (constraint_graph_t graph, unsigned int to, unsigned int from,
- bool update_changed)
-{
- gcc_checking_assert (to != from && find (to) == to);
-
- if (dump_file && (dump_flags & TDF_DETAILS))
- fprintf (dump_file, "Unifying %s to %s\n",
- get_varinfo (from)->name,
- get_varinfo (to)->name);
-
- if (update_changed)
- stats.unified_vars_dynamic++;
- else
- stats.unified_vars_static++;
-
- merge_graph_nodes (graph, to, from);
- if (merge_node_constraints (graph, to, from))
- {
- if (update_changed)
- bitmap_set_bit (changed, to);
- }
-
- /* Mark TO as changed if FROM was changed. If TO was already marked
- as changed, decrease the changed count. */
-
- if (update_changed
- && bitmap_clear_bit (changed, from))
- bitmap_set_bit (changed, to);
- varinfo_t fromvi = get_varinfo (from);
- if (fromvi->solution)
- {
- /* If the solution changes because of the merging, we need to mark
- the variable as changed. */
- varinfo_t tovi = get_varinfo (to);
- if (bitmap_ior_into (tovi->solution, fromvi->solution))
- {
- if (update_changed)
- bitmap_set_bit (changed, to);
- }
-
- BITMAP_FREE (fromvi->solution);
- if (fromvi->oldsolution)
- BITMAP_FREE (fromvi->oldsolution);
-
- if (stats.iterations > 0
- && tovi->oldsolution)
- BITMAP_FREE (tovi->oldsolution);
- }
- if (graph->succs[to])
- bitmap_clear_bit (graph->succs[to], to);
-}
-
-/* Add a copy edge FROM -> TO, optimizing special cases. Returns TRUE
- if the solution of TO changed. */
-
-static bool
-solve_add_graph_edge (constraint_graph_t graph, unsigned int to,
- unsigned int from)
-{
- /* Adding edges from the special vars is pointless.
- They don't have sets that can change. */
- if (get_varinfo (from)->is_special_var)
- return bitmap_ior_into (get_varinfo (to)->solution,
- get_varinfo (from)->solution);
- /* Merging the solution from ESCAPED needlessly increases
- the set. Use ESCAPED as representative instead. */
- else if (from == find (escaped_id))
- return bitmap_set_bit (get_varinfo (to)->solution, escaped_id);
- else if (get_varinfo (from)->may_have_pointers
- && add_graph_edge (graph, to, from))
- return bitmap_ior_into (get_varinfo (to)->solution,
- get_varinfo (from)->solution);
- return false;
-}
-
-/* Process a constraint C that represents x = *(y + off), using DELTA as the
- starting solution for y. */
-
-static void
-do_sd_constraint (constraint_graph_t graph, constraint_t c,
- bitmap delta, bitmap *expanded_delta)
-{
- unsigned int lhs = c->lhs.var;
- bool flag = false;
- bitmap sol = get_varinfo (lhs)->solution;
- unsigned int j;
- bitmap_iterator bi;
- HOST_WIDE_INT roffset = c->rhs.offset;
-
- /* Our IL does not allow this. */
- gcc_checking_assert (c->lhs.offset == 0);
-
- /* If the solution of Y contains anything it is good enough to transfer
- this to the LHS. */
- if (bitmap_bit_p (delta, anything_id))
- {
- flag |= bitmap_set_bit (sol, anything_id);
- goto done;
- }
-
- /* If we do not know at with offset the rhs is dereferenced compute
- the reachability set of DELTA, conservatively assuming it is
- dereferenced at all valid offsets. */
- if (roffset == UNKNOWN_OFFSET)
- {
- delta = solution_set_expand (delta, expanded_delta);
- /* No further offset processing is necessary. */
- roffset = 0;
- }
-
- /* 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)
- {
- varinfo_t v = get_varinfo (j);
- HOST_WIDE_INT fieldoffset = v->offset + roffset;
- unsigned HOST_WIDE_INT size = v->size;
- unsigned int t;
-
- if (v->is_full_var)
- ;
- else if (roffset != 0)
- {
- if (fieldoffset < 0)
- v = get_varinfo (v->head);
- else
- v = first_or_preceding_vi_for_offset (v, fieldoffset);
- }
-
- /* We have to include all fields that overlap the current field
- shifted by roffset. */
- do
- {
- t = find (v->id);
-
- flag |= solve_add_graph_edge (graph, lhs, t);
-
- if (v->is_full_var
- || v->next == 0)
- break;
-
- v = vi_next (v);
- }
- while (v->offset < fieldoffset + size);
- }
-
-done:
- /* If the LHS solution changed, mark the var as changed. */
- if (flag)
- bitmap_set_bit (changed, lhs);
-}
-
-/* Process a constraint C that represents *(x + off) = y using DELTA
- as the starting solution for x. */
-
-static void
-do_ds_constraint (constraint_t c, bitmap delta, bitmap *expanded_delta)
-{
- unsigned int rhs = c->rhs.var;
- bitmap sol = get_varinfo (rhs)->solution;
- unsigned int j;
- bitmap_iterator bi;
- HOST_WIDE_INT loff = c->lhs.offset;
- bool escaped_p = false;
-
- /* Our IL does not allow this. */
- gcc_checking_assert (c->rhs.offset == 0);
-
- /* If the solution of y contains ANYTHING simply use the ANYTHING
- solution. This avoids needlessly increasing the points-to sets. */
- if (bitmap_bit_p (sol, anything_id))
- sol = get_varinfo (find (anything_id))->solution;
-
- /* If the solution for x contains ANYTHING we have to merge the
- solution of y into all pointer variables which we do via
- STOREDANYTHING. */
- if (bitmap_bit_p (delta, anything_id))
- {
- unsigned t = find (storedanything_id);
- if (solve_add_graph_edge (graph, t, rhs))
- bitmap_set_bit (changed, t);
- return;
- }
-
- /* If we do not know at with offset the rhs is dereferenced compute
- the reachability set of DELTA, conservatively assuming it is
- dereferenced at all valid offsets. */
- if (loff == UNKNOWN_OFFSET)
- {
- delta = solution_set_expand (delta, expanded_delta);
- loff = 0;
- }
-
- /* 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)
- {
- varinfo_t v = get_varinfo (j);
- unsigned int t;
- HOST_WIDE_INT fieldoffset = v->offset + loff;
- unsigned HOST_WIDE_INT size = v->size;
-
- if (v->is_full_var)
- ;
- else if (loff != 0)
- {
- if (fieldoffset < 0)
- v = get_varinfo (v->head);
- else
- v = first_or_preceding_vi_for_offset (v, fieldoffset);
- }
-
- /* We have to include all fields that overlap the current field
- shifted by loff. */
- do
- {
- if (v->may_have_pointers)
- {
- /* If v is a global variable then this is an escape point. */
- if (v->is_global_var
- && !escaped_p)
- {
- t = find (escaped_id);
- if (add_graph_edge (graph, t, rhs)
- && bitmap_ior_into (get_varinfo (t)->solution, sol))
- bitmap_set_bit (changed, t);
- /* Enough to let rhs escape once. */
- escaped_p = true;
- }
-
- if (v->is_special_var)
- break;
-
- t = find (v->id);
-
- if (solve_add_graph_edge (graph, t, rhs))
- bitmap_set_bit (changed, t);
- }
-
- if (v->is_full_var
- || v->next == 0)
- break;
-
- v = vi_next (v);
- }
- while (v->offset < fieldoffset + size);
- }
-}
-
-/* Handle a non-simple (simple meaning requires no iteration),
- constraint (IE *x = &y, x = *y, *x = y, and x = y with offsets involved). */
-
-static void
-do_complex_constraint (constraint_graph_t graph, constraint_t c, bitmap delta,
- bitmap *expanded_delta)
-{
- if (c->lhs.type == DEREF)
- {
- if (c->rhs.type == ADDRESSOF)
- {
- gcc_unreachable ();
- }
- else
- {
- /* *x = y */
- do_ds_constraint (c, delta, expanded_delta);
- }
- }
- else if (c->rhs.type == DEREF)
- {
- /* x = *y */
- if (!(get_varinfo (c->lhs.var)->is_special_var))
- do_sd_constraint (graph, c, delta, expanded_delta);
- }
- else
- {
- bitmap tmp;
- bool flag = false;
-
- gcc_checking_assert (c->rhs.type == SCALAR && c->lhs.type == SCALAR
- && c->rhs.offset != 0 && c->lhs.offset == 0);
- tmp = get_varinfo (c->lhs.var)->solution;
-
- flag = set_union_with_increment (tmp, delta, c->rhs.offset,
- expanded_delta);
-
- if (flag)
- bitmap_set_bit (changed, c->lhs.var);
- }
-}
-
-/* Initialize and return a new SCC info structure. */
-
-scc_info::scc_info (size_t size) :
- visited (size), deleted (size), current_index (0), scc_stack (1)
-{
- bitmap_clear (visited);
- bitmap_clear (deleted);
- node_mapping = XNEWVEC (unsigned int, size);
- dfs = XCNEWVEC (unsigned int, size);
-
- for (size_t i = 0; i < size; i++)
- node_mapping[i] = i;
-}
-
-/* Free an SCC info structure pointed to by SI */
-
-scc_info::~scc_info ()
-{
- free (node_mapping);
- free (dfs);
-}
-
-
-/* Find indirect cycles in GRAPH that occur, using strongly connected
- components, and note them in the indirect cycles map.
-
- This technique comes from Ben Hardekopf and Calvin Lin,
- "It Pays to be Lazy: Fast and Accurate Pointer Analysis for Millions of
- Lines of Code", submitted to PLDI 2007. */
-
-static void
-find_indirect_cycles (constraint_graph_t graph)
-{
- unsigned int i;
- unsigned int size = graph->size;
- scc_info si (size);
-
- for (i = 0; i < MIN (LAST_REF_NODE, size); i ++ )
- if (!bitmap_bit_p (si.visited, i) && find (i) == i)
- scc_visit (graph, &si, i);
-}
-
-/* Visit the graph in topological order starting at node N, and store the
- order in TOPO_ORDER using VISITED to indicate visited nodes. */
-
-static void
-topo_visit (constraint_graph_t graph, vec<unsigned> &topo_order,
- sbitmap visited, unsigned int n)
-{
- bitmap_iterator bi;
- unsigned int j;
-
- bitmap_set_bit (visited, n);
-
- if (graph->succs[n])
- EXECUTE_IF_SET_IN_BITMAP (graph->succs[n], 0, j, bi)
- {
- unsigned k = find (j);
- if (!bitmap_bit_p (visited, k))
- topo_visit (graph, topo_order, visited, k);
- }
-
- /* Also consider copy with offset complex constraints as implicit edges. */
- for (auto c : graph->complex[n])
- {
- /* Constraints are ordered so that SCALAR = SCALAR appear first. */
- if (c->lhs.type != SCALAR || c->rhs.type != SCALAR)
- break;
- gcc_checking_assert (c->rhs.var == n);
- unsigned k = find (c->lhs.var);
- if (!bitmap_bit_p (visited, k))
- topo_visit (graph, topo_order, visited, k);
- }
-
- topo_order.quick_push (n);
-}
-
-/* Compute a topological ordering for GRAPH, and return the result. */
-
-static auto_vec<unsigned>
-compute_topo_order (constraint_graph_t graph)
-{
- unsigned int i;
- unsigned int size = graph->size;
-
- auto_sbitmap visited (size);
- bitmap_clear (visited);
-
- /* For the heuristic in add_graph_edge to work optimally make sure to
- first visit the connected component of the graph containing
- ESCAPED. Do this by extracting the connected component
- with ESCAPED and append that to all other components as solve_graph
- pops from the order. */
- auto_vec<unsigned> tail (size);
- topo_visit (graph, tail, visited, find (escaped_id));
-
- auto_vec<unsigned> topo_order (size);
-
- for (i = 0; i != size; ++i)
- if (!bitmap_bit_p (visited, i) && find (i) == i)
- topo_visit (graph, topo_order, visited, i);
-
- topo_order.splice (tail);
- return topo_order;
-}
-
-/* Structure used to for hash value numbering of pointer equivalence
- classes. */
-
-typedef struct equiv_class_label
-{
- hashval_t hashcode;
- unsigned int equivalence_class;
- bitmap labels;
-} *equiv_class_label_t;
-typedef const struct equiv_class_label *const_equiv_class_label_t;
-
-/* Equiv_class_label hashtable helpers. */
-
-struct equiv_class_hasher : nofree_ptr_hash <equiv_class_label>
-{
- static inline hashval_t hash (const equiv_class_label *);
- static inline bool equal (const equiv_class_label *,
- const equiv_class_label *);
-};
-
-/* Hash function for a equiv_class_label_t */
-
-inline hashval_t
-equiv_class_hasher::hash (const equiv_class_label *ecl)
-{
- return ecl->hashcode;
-}
-
-/* Equality function for two equiv_class_label_t's. */
-
-inline bool
-equiv_class_hasher::equal (const equiv_class_label *eql1,
- const equiv_class_label *eql2)
-{
- return (eql1->hashcode == eql2->hashcode
- && bitmap_equal_p (eql1->labels, eql2->labels));
-}
-
-/* A hashtable for mapping a bitmap of labels->pointer equivalence
- classes. */
-static hash_table<equiv_class_hasher> *pointer_equiv_class_table;
-
-/* A hashtable for mapping a bitmap of labels->location equivalence
- classes. */
-static hash_table<equiv_class_hasher> *location_equiv_class_table;
-
-struct obstack equiv_class_obstack;
-
-/* Lookup a equivalence class in TABLE by the bitmap of LABELS with
- hash HAS it contains. Sets *REF_LABELS to the bitmap LABELS
- is equivalent to. */
-
-static equiv_class_label *
-equiv_class_lookup_or_add (hash_table<equiv_class_hasher> *table,
- bitmap labels)
-{
- equiv_class_label **slot;
- equiv_class_label ecl;
-
- ecl.labels = labels;
- ecl.hashcode = bitmap_hash (labels);
- slot = table->find_slot (&ecl, INSERT);
- if (!*slot)
- {
- *slot = XOBNEW (&equiv_class_obstack, struct equiv_class_label);
- (*slot)->labels = labels;
- (*slot)->hashcode = ecl.hashcode;
- (*slot)->equivalence_class = 0;
- }
-
- return *slot;
-}
-
-/* Perform offline variable substitution.
-
- This is a worst case quadratic 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 "Exploiting Pointer and Location
- Equivalence to Optimize Pointer Analysis. In the 14th International
- Static Analysis Symposium (SAS), August 2007." It is known as the
- "HU" algorithm, and is equivalent to value numbering the collapsed
- constraint graph including evaluating unions.
-
- The general method of finding equivalence classes is as follows:
- Add fake nodes (REF nodes) and edges for *a = b and a = *b constraints.
- Initialize all non-REF nodes to be direct nodes.
- For each constraint a = a U {b}, we set pts(a) = pts(a) u {fresh
- variable}
- For each constraint containing the dereference, we also do the same
- thing.
-
- We then compute SCC's in the graph and unify nodes in the same SCC,
- including pts sets.
-
- For each non-collapsed node x:
- Visit all unvisited explicit incoming edges.
- Ignoring all non-pointers, set pts(x) = Union of pts(a) for y
- where y->x.
- Lookup the equivalence class for pts(x).
- If we found one, equivalence_class(x) = found class.
- Otherwise, equivalence_class(x) = new class, and new_class is
- added to the lookup table.
-
- All direct nodes with the same equivalence class can be replaced
- with a single representative node.
- All unlabeled nodes (label == 0) are not pointers and all edges
- involving them can be eliminated.
- We perform these optimizations during rewrite_constraints
-
- In addition to pointer equivalence class finding, we also perform
- location equivalence class finding. This is the set of variables
- that always appear together in points-to sets. We use this to
- compress the size of the points-to sets. */
-
-/* Current maximum pointer equivalence class id. */
-static int pointer_equiv_class;
-
-/* Current maximum location equivalence class id. */
-static int location_equiv_class;
-
-/* Recursive routine to find strongly connected components in GRAPH,
- and label it's nodes with DFS numbers. */
-
-static void
-condense_visit (constraint_graph_t graph, class scc_info *si, unsigned int n)
-{
- unsigned int i;
- bitmap_iterator bi;
- unsigned int my_dfs;
-
- gcc_checking_assert (si->node_mapping[n] == n);
- bitmap_set_bit (si->visited, n);
- si->dfs[n] = si->current_index ++;
- my_dfs = si->dfs[n];
-
- /* Visit all the successors. */
- EXECUTE_IF_IN_NONNULL_BITMAP (graph->preds[n], 0, i, bi)
- {
- unsigned int w = si->node_mapping[i];
-
- if (bitmap_bit_p (si->deleted, w))
- continue;
-
- if (!bitmap_bit_p (si->visited, w))
- condense_visit (graph, si, w);
-
- unsigned int t = si->node_mapping[w];
- gcc_checking_assert (si->node_mapping[n] == n);
- if (si->dfs[t] < si->dfs[n])
- si->dfs[n] = si->dfs[t];
- }
-
- /* Visit all the implicit predecessors. */
- EXECUTE_IF_IN_NONNULL_BITMAP (graph->implicit_preds[n], 0, i, bi)
- {
- unsigned int w = si->node_mapping[i];
-
- if (bitmap_bit_p (si->deleted, w))
- continue;
-
- if (!bitmap_bit_p (si->visited, w))
- condense_visit (graph, si, w);
-
- unsigned int t = si->node_mapping[w];
- gcc_assert (si->node_mapping[n] == n);
- if (si->dfs[t] < si->dfs[n])
- si->dfs[n] = si->dfs[t];
- }
-
- /* See if any components have been identified. */
- if (si->dfs[n] == my_dfs)
- {
- if (si->scc_stack.length () != 0
- && si->dfs[si->scc_stack.last ()] >= my_dfs)
- {
- /* Find the first node of the SCC and do non-bitmap work. */
- bool direct_p = true;
- unsigned first = si->scc_stack.length ();
- do
- {
- --first;
- unsigned int w = si->scc_stack[first];
- si->node_mapping[w] = n;
- if (!bitmap_bit_p (graph->direct_nodes, w))
- direct_p = false;
- }
- while (first > 0
- && si->dfs[si->scc_stack[first - 1]] >= my_dfs);
- if (!direct_p)
- bitmap_clear_bit (graph->direct_nodes, n);
-
- /* Want to reduce to node n, push that first. */
- si->scc_stack.reserve (1);
- si->scc_stack.quick_push (si->scc_stack[first]);
- si->scc_stack[first] = n;
-
- unsigned scc_size = si->scc_stack.length () - first;
- unsigned split = scc_size / 2;
- unsigned carry = scc_size - split * 2;
- while (split > 0)
- {
- for (unsigned i = 0; i < split; ++i)
- {
- unsigned a = si->scc_stack[first + i];
- unsigned b = si->scc_stack[first + split + carry + i];
-
- /* Unify our nodes. */
- if (graph->preds[b])
- {
- if (!graph->preds[a])
- std::swap (graph->preds[a], graph->preds[b]);
- else
- bitmap_ior_into_and_free (graph->preds[a],
- &graph->preds[b]);
- }
- if (graph->implicit_preds[b])
- {
- if (!graph->implicit_preds[a])
- std::swap (graph->implicit_preds[a],
- graph->implicit_preds[b]);
- else
- bitmap_ior_into_and_free (graph->implicit_preds[a],
- &graph->implicit_preds[b]);
- }
- if (graph->points_to[b])
- {
- if (!graph->points_to[a])
- std::swap (graph->points_to[a], graph->points_to[b]);
- else
- bitmap_ior_into_and_free (graph->points_to[a],
- &graph->points_to[b]);
- }
- }
- unsigned remain = split + carry;
- split = remain / 2;
- carry = remain - split * 2;
- }
- /* Actually pop the SCC. */
- si->scc_stack.truncate (first);
- }
- bitmap_set_bit (si->deleted, n);
- }
- else
- si->scc_stack.safe_push (n);
-}
-
-/* Label pointer equivalences.
-
- This performs a value numbering of the constraint graph to
- discover which variables will always have the same points-to sets
- under the current set of constraints.
-
- The way it value numbers is to store the set of points-to bits
- generated by the constraints and graph edges. This is just used as a
- hash and equality comparison. The *actual set of points-to bits* is
- completely irrelevant, in that we don't care about being able to
- extract them later.
-
- The equality values (currently bitmaps) just have to satisfy a few
- constraints, the main ones being:
- 1. The combining operation must be order independent.
- 2. The end result of a given set of operations must be unique iff the
- combination of input values is unique
- 3. Hashable. */
-
-static void
-label_visit (constraint_graph_t graph, class scc_info *si, unsigned int n)
-{
- unsigned int i, first_pred;
- bitmap_iterator bi;
-
- bitmap_set_bit (si->visited, n);
-
- /* Label and union our incoming edges's points to sets. */
- first_pred = -1U;
- EXECUTE_IF_IN_NONNULL_BITMAP (graph->preds[n], 0, i, bi)
- {
- unsigned int w = si->node_mapping[i];
- if (!bitmap_bit_p (si->visited, w))
- label_visit (graph, si, w);
-
- /* Skip unused edges */
- if (w == n || graph->pointer_label[w] == 0)
- continue;
-
- if (graph->points_to[w])
- {
- if (!graph->points_to[n])
- {
- if (first_pred == -1U)
- first_pred = w;
- else
- {
- graph->points_to[n] = BITMAP_ALLOC (&predbitmap_obstack);
- bitmap_ior (graph->points_to[n],
- graph->points_to[first_pred],
- graph->points_to[w]);
- }
- }
- else
- bitmap_ior_into (graph->points_to[n], graph->points_to[w]);
- }
- }
-
- /* Indirect nodes get fresh variables and a new pointer equiv class. */
- if (!bitmap_bit_p (graph->direct_nodes, n))
- {
- if (!graph->points_to[n])
- {
- graph->points_to[n] = BITMAP_ALLOC (&predbitmap_obstack);
- if (first_pred != -1U)
- bitmap_copy (graph->points_to[n], graph->points_to[first_pred]);
- }
- bitmap_set_bit (graph->points_to[n], FIRST_REF_NODE + n);
- graph->pointer_label[n] = pointer_equiv_class++;
- equiv_class_label_t ecl;
- ecl = equiv_class_lookup_or_add (pointer_equiv_class_table,
- graph->points_to[n]);
- ecl->equivalence_class = graph->pointer_label[n];
- return;
- }
-
- /* If there was only a single non-empty predecessor the pointer equiv
- class is the same. */
- if (!graph->points_to[n])
- {
- if (first_pred != -1U)
- {
- graph->pointer_label[n] = graph->pointer_label[first_pred];
- graph->points_to[n] = graph->points_to[first_pred];
- }
- return;
- }
-
- if (!bitmap_empty_p (graph->points_to[n]))
- {
- equiv_class_label_t ecl;
- ecl = equiv_class_lookup_or_add (pointer_equiv_class_table,
- graph->points_to[n]);
- if (ecl->equivalence_class == 0)
- ecl->equivalence_class = pointer_equiv_class++;
- else
- {
- BITMAP_FREE (graph->points_to[n]);
- graph->points_to[n] = ecl->labels;
- }
- graph->pointer_label[n] = ecl->equivalence_class;
- }
-}
-
-/* Print the pred graph in dot format. */
-
-static void
-dump_pred_graph (class scc_info *si, FILE *file)
-{
- unsigned int i;
-
- /* Only print the graph if it has already been initialized: */
- if (!graph)
- return;
-
- /* Prints the header of the dot file: */
- fprintf (file, "strict digraph {\n");
- fprintf (file, " node [\n shape = box\n ]\n");
- fprintf (file, " edge [\n fontsize = \"12\"\n ]\n");
- fprintf (file, "\n // List of nodes and complex constraints in "
- "the constraint graph:\n");
-
- /* The next lines print the nodes in the graph together with the
- complex constraints attached to them. */
- for (i = 1; i < graph->size; i++)
- {
- if (i == FIRST_REF_NODE)
- continue;
- if (si->node_mapping[i] != i)
- continue;
- if (i < FIRST_REF_NODE)
- fprintf (file, "\"%s\"", get_varinfo (i)->name);
- else
- fprintf (file, "\"*%s\"", get_varinfo (i - FIRST_REF_NODE)->name);
- if (graph->points_to[i]
- && !bitmap_empty_p (graph->points_to[i]))
- {
- if (i < FIRST_REF_NODE)
- fprintf (file, "[label=\"%s = {", get_varinfo (i)->name);
- else
- fprintf (file, "[label=\"*%s = {",
- get_varinfo (i - FIRST_REF_NODE)->name);
- unsigned j;
- bitmap_iterator bi;
- EXECUTE_IF_SET_IN_BITMAP (graph->points_to[i], 0, j, bi)
- fprintf (file, " %d", j);
- fprintf (file, " }\"]");
- }
- fprintf (file, ";\n");
- }
-
- /* Go over the edges. */
- fprintf (file, "\n // Edges in the constraint graph:\n");
- for (i = 1; i < graph->size; i++)
- {
- unsigned j;
- bitmap_iterator bi;
- if (si->node_mapping[i] != i)
- continue;
- EXECUTE_IF_IN_NONNULL_BITMAP (graph->preds[i], 0, j, bi)
- {
- unsigned from = si->node_mapping[j];
- if (from < FIRST_REF_NODE)
- fprintf (file, "\"%s\"", get_varinfo (from)->name);
- else
- fprintf (file, "\"*%s\"", get_varinfo (from - FIRST_REF_NODE)->name);
- fprintf (file, " -> ");
- if (i < FIRST_REF_NODE)
- fprintf (file, "\"%s\"", get_varinfo (i)->name);
- else
- fprintf (file, "\"*%s\"", get_varinfo (i - FIRST_REF_NODE)->name);
- fprintf (file, ";\n");
- }
- }
-
- /* Prints the tail of the dot file. */
- fprintf (file, "}\n");
-}
-
-/* Perform offline variable substitution, discovering equivalence
- classes, and eliminating non-pointer variables. */
-
-static class scc_info *
-perform_var_substitution (constraint_graph_t graph)
-{
- unsigned int i;
- unsigned int size = graph->size;
- scc_info *si = new scc_info (size);
-
- bitmap_obstack_initialize (&iteration_obstack);
- gcc_obstack_init (&equiv_class_obstack);
- pointer_equiv_class_table = new hash_table<equiv_class_hasher> (511);
- location_equiv_class_table
- = new hash_table<equiv_class_hasher> (511);
- pointer_equiv_class = 1;
- location_equiv_class = 1;
-
- /* Condense the nodes, which means to find SCC's, count incoming
- predecessors, and unite nodes in SCC's. */
- for (i = 1; i < FIRST_REF_NODE; i++)
- if (!bitmap_bit_p (si->visited, si->node_mapping[i]))
- condense_visit (graph, si, si->node_mapping[i]);
-
- if (dump_file && (dump_flags & TDF_GRAPH))
- {
- fprintf (dump_file, "\n\n// The constraint graph before var-substitution "
- "in dot format:\n");
- dump_pred_graph (si, dump_file);
- fprintf (dump_file, "\n\n");
- }
-
- bitmap_clear (si->visited);
- /* Actually the label the nodes for pointer equivalences */
- for (i = 1; i < FIRST_REF_NODE; i++)
- if (!bitmap_bit_p (si->visited, si->node_mapping[i]))
- label_visit (graph, si, si->node_mapping[i]);
-
- /* Calculate location equivalence labels. */
- for (i = 1; i < FIRST_REF_NODE; i++)
- {
- bitmap pointed_by;
- bitmap_iterator bi;
- unsigned int j;
-
- if (!graph->pointed_by[i])
- continue;
- pointed_by = BITMAP_ALLOC (&iteration_obstack);
-
- /* Translate the pointed-by mapping for pointer equivalence
- labels. */
- EXECUTE_IF_SET_IN_BITMAP (graph->pointed_by[i], 0, j, bi)
- {
- bitmap_set_bit (pointed_by,
- graph->pointer_label[si->node_mapping[j]]);
- }
- /* The original pointed_by is now dead. */
- BITMAP_FREE (graph->pointed_by[i]);
-
- /* Look up the location equivalence label if one exists, or make
- one otherwise. */
- equiv_class_label_t ecl;
- ecl = equiv_class_lookup_or_add (location_equiv_class_table, pointed_by);
- if (ecl->equivalence_class == 0)
- ecl->equivalence_class = location_equiv_class++;
- else
- {
- if (dump_file && (dump_flags & TDF_DETAILS))
- fprintf (dump_file, "Found location equivalence for node %s\n",
- get_varinfo (i)->name);
- BITMAP_FREE (pointed_by);
- }
- graph->loc_label[i] = ecl->equivalence_class;
-
- }
-
- if (dump_file && (dump_flags & TDF_DETAILS))
- for (i = 1; i < FIRST_REF_NODE; i++)
- {
- unsigned j = si->node_mapping[i];
- if (j != i)
- {
- fprintf (dump_file, "%s node id %d ",
- bitmap_bit_p (graph->direct_nodes, i)
- ? "Direct" : "Indirect", i);
- if (i < FIRST_REF_NODE)
- fprintf (dump_file, "\"%s\"", get_varinfo (i)->name);
- else
- fprintf (dump_file, "\"*%s\"",
- get_varinfo (i - FIRST_REF_NODE)->name);
- fprintf (dump_file, " mapped to SCC leader node id %d ", j);
- if (j < FIRST_REF_NODE)
- fprintf (dump_file, "\"%s\"\n", get_varinfo (j)->name);
- else
- fprintf (dump_file, "\"*%s\"\n",
- get_varinfo (j - FIRST_REF_NODE)->name);
- }
- else
- {
- fprintf (dump_file,
- "Equivalence classes for %s node id %d ",
- bitmap_bit_p (graph->direct_nodes, i)
- ? "direct" : "indirect", i);
- if (i < FIRST_REF_NODE)
- fprintf (dump_file, "\"%s\"", get_varinfo (i)->name);
- else
- fprintf (dump_file, "\"*%s\"",
- get_varinfo (i - FIRST_REF_NODE)->name);
- fprintf (dump_file,
- ": pointer %d, location %d\n",
- graph->pointer_label[i], graph->loc_label[i]);
- }
- }
-
- /* Quickly eliminate our non-pointer variables. */
-
- for (i = 1; i < FIRST_REF_NODE; i++)
- {
- unsigned int node = si->node_mapping[i];
-
- if (graph->pointer_label[node] == 0)
- {
- if (dump_file && (dump_flags & TDF_DETAILS))
- fprintf (dump_file,
- "%s is a non-pointer variable, eliminating edges.\n",
- get_varinfo (node)->name);
- stats.nonpointer_vars++;
- clear_edges_for_node (graph, node);
- }
- }
-
- return si;
-}
-
-/* Free information that was only necessary for variable
- substitution. */
-
-static void
-free_var_substitution_info (class scc_info *si)
-{
- delete si;
- free (graph->pointer_label);
- free (graph->loc_label);
- free (graph->pointed_by);
- free (graph->points_to);
- free (graph->eq_rep);
- sbitmap_free (graph->direct_nodes);
- delete pointer_equiv_class_table;
- pointer_equiv_class_table = NULL;
- delete location_equiv_class_table;
- location_equiv_class_table = NULL;
- obstack_free (&equiv_class_obstack, NULL);
- bitmap_obstack_release (&iteration_obstack);
-}
-
-/* Return an existing node that is equivalent to NODE, which has
- equivalence class LABEL, if one exists. Return NODE otherwise. */
-
-static unsigned int
-find_equivalent_node (constraint_graph_t graph,
- unsigned int node, unsigned int label)
-{
- /* If the address version of this variable is unused, we can
- substitute it for anything else with the same label.
- Otherwise, we know the pointers are equivalent, but not the
- locations, and we can unite them later. */
-
- if (!bitmap_bit_p (graph->address_taken, node))
- {
- gcc_checking_assert (label < graph->size);
-
- if (graph->eq_rep[label] != -1)
- {
- /* Unify the two variables since we know they are equivalent. */
- if (unite (graph->eq_rep[label], node))
- unify_nodes (graph, graph->eq_rep[label], node, false);
- return graph->eq_rep[label];
- }
- else
- {
- graph->eq_rep[label] = node;
- graph->pe_rep[label] = node;
- }
- }
- else
- {
- gcc_checking_assert (label < graph->size);
- graph->pe[node] = label;
- if (graph->pe_rep[label] == -1)
- graph->pe_rep[label] = node;
- }
-
- return node;
-}
-
-/* Unite pointer equivalent but not location equivalent nodes in
- GRAPH. This may only be performed once variable substitution is
- finished. */
-
-static void
-unite_pointer_equivalences (constraint_graph_t graph)
-{
- unsigned int i;
-
- /* Go through the pointer equivalences and unite them to their
- representative, if they aren't already. */
- for (i = 1; i < FIRST_REF_NODE; i++)
- {
- unsigned int label = graph->pe[i];
- if (label)
- {
- int label_rep = graph->pe_rep[label];
-
- if (label_rep == -1)
- continue;
-
- label_rep = find (label_rep);
- if (label_rep >= 0 && unite (label_rep, find (i)))
- unify_nodes (graph, label_rep, i, false);
- }
- }
-}
-
-/* Move complex constraints to the GRAPH nodes they belong to. */
-
-static void
-move_complex_constraints (constraint_graph_t graph)
-{
- int i;
- constraint_t c;
-
- FOR_EACH_VEC_ELT (constraints, i, c)
- {
- if (c)
- {
- struct constraint_expr lhs = c->lhs;
- struct constraint_expr rhs = c->rhs;
-
- if (lhs.type == DEREF)
- {
- insert_into_complex (graph, lhs.var, c);
- }
- else if (rhs.type == DEREF)
- {
- if (!(get_varinfo (lhs.var)->is_special_var))
- insert_into_complex (graph, rhs.var, c);
- }
- else if (rhs.type != ADDRESSOF && lhs.var > anything_id
- && (lhs.offset != 0 || rhs.offset != 0))
- {
- insert_into_complex (graph, rhs.var, c);
- }
- }
- }
-}
-
-
-/* Optimize and rewrite complex constraints while performing
- collapsing of equivalent nodes. SI is the SCC_INFO that is the
- result of perform_variable_substitution. */
-
-static void
-rewrite_constraints (constraint_graph_t graph,
- class scc_info *si)
-{
- int i;
- constraint_t c;
-
- if (flag_checking)
- {
- for (unsigned int j = 0; j < graph->size; j++)
- gcc_assert (find (j) == j);
- }
-
- FOR_EACH_VEC_ELT (constraints, i, c)
- {
- struct constraint_expr lhs = c->lhs;
- struct constraint_expr rhs = c->rhs;
- unsigned int lhsvar = find (lhs.var);
- unsigned int rhsvar = find (rhs.var);
- unsigned int lhsnode, rhsnode;
- unsigned int lhslabel, rhslabel;
-
- lhsnode = si->node_mapping[lhsvar];
- rhsnode = si->node_mapping[rhsvar];
- lhslabel = graph->pointer_label[lhsnode];
- rhslabel = graph->pointer_label[rhsnode];
-
- /* See if it is really a non-pointer variable, and if so, ignore
- the constraint. */
- if (lhslabel == 0)
- {
- if (dump_file && (dump_flags & TDF_DETAILS))
- {
-
- fprintf (dump_file, "%s is a non-pointer variable, "
- "ignoring constraint:",
- get_varinfo (lhs.var)->name);
- dump_constraint (dump_file, c);
- fprintf (dump_file, "\n");
- }
- constraints[i] = NULL;
- continue;
- }
-
- if (rhslabel == 0)
- {
- if (dump_file && (dump_flags & TDF_DETAILS))
- {
-
- fprintf (dump_file, "%s is a non-pointer variable, "
- "ignoring constraint:",
- get_varinfo (rhs.var)->name);
- dump_constraint (dump_file, c);
- fprintf (dump_file, "\n");
- }
- constraints[i] = NULL;
- continue;
- }
-
- lhsvar = find_equivalent_node (graph, lhsvar, lhslabel);
- rhsvar = find_equivalent_node (graph, rhsvar, rhslabel);
- c->lhs.var = lhsvar;
- c->rhs.var = rhsvar;
- }
-}
-
-/* Eliminate indirect cycles involving NODE. Return true if NODE was
- part of an SCC, false otherwise. */
-
-static bool
-eliminate_indirect_cycles (unsigned int node)
-{
- if (graph->indirect_cycles[node] != -1
- && !bitmap_empty_p (get_varinfo (node)->solution))
- {
- unsigned int i;
- auto_vec<unsigned> queue;
- int queuepos;
- unsigned int to = find (graph->indirect_cycles[node]);
- bitmap_iterator bi;
-
- /* We can't touch the solution set and call unify_nodes
- at the same time, because unify_nodes is going to do
- bitmap unions into it. */
-
- EXECUTE_IF_SET_IN_BITMAP (get_varinfo (node)->solution, 0, i, bi)
- {
- if (find (i) == i && i != to)
- {
- if (unite (to, i))
- queue.safe_push (i);
- }
- }
-
- for (queuepos = 0;
- queue.iterate (queuepos, &i);
- queuepos++)
- {
- unify_nodes (graph, to, i, true);
- }
- return true;
- }
- return false;
-}
-
-/* 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 = graph->size;
- unsigned int i;
- bitmap pts;
-
- changed = BITMAP_ALLOC (NULL);
-
- /* Mark all initial non-collapsed nodes as changed. */
- for (i = 1; i < size; i++)
- {
- varinfo_t ivi = get_varinfo (i);
- if (find (i) == i && !bitmap_empty_p (ivi->solution)
- && ((graph->succs[i] && !bitmap_empty_p (graph->succs[i]))
- || graph->complex[i].length () > 0))
- bitmap_set_bit (changed, i);
- }
-
- /* Allocate a bitmap to be used to store the changed bits. */
- pts = BITMAP_ALLOC (&pta_obstack);
-
- while (!bitmap_empty_p (changed))
- {
- unsigned int i;
- stats.iterations++;
-
- bitmap_obstack_initialize (&iteration_obstack);
-
- auto_vec<unsigned> topo_order = compute_topo_order (graph);
- while (topo_order.length () != 0)
- {
- i = topo_order.pop ();
-
- /* If this variable is not a representative, skip it. */
- if (find (i) != i)
- continue;
-
- /* In certain indirect cycle cases, we may merge this
- variable to another. */
- if (eliminate_indirect_cycles (i) && find (i) != i)
- continue;
-
- /* If the node has changed, we need to process the
- complex constraints and outgoing edges again. For complex
- constraints that modify i itself, like the common group of
- callarg = callarg + UNKNOWN;
- callarg = *callarg + UNKNOWN;
- *callarg = callescape;
- make sure to iterate immediately because that maximizes
- cache reuse and expands the graph quickest, leading to
- better visitation order in the next iteration. */
- while (bitmap_clear_bit (changed, i))
- {
- bitmap solution;
- vec<constraint_t> &complex = graph->complex[i];
- varinfo_t vi = get_varinfo (i);
- bool solution_empty;
-
- /* Compute the changed set of solution bits. If anything
- is in the solution just propagate that. */
- if (bitmap_bit_p (vi->solution, anything_id))
- {
- /* If anything is also in the old solution there is
- nothing to do.
- ??? But we shouldn't ended up with "changed" set ... */
- if (vi->oldsolution
- && bitmap_bit_p (vi->oldsolution, anything_id))
- break;
- bitmap_copy (pts, get_varinfo (find (anything_id))->solution);
- }
- else if (vi->oldsolution)
- bitmap_and_compl (pts, vi->solution, vi->oldsolution);
- else
- bitmap_copy (pts, vi->solution);
-
- if (bitmap_empty_p (pts))
- break;
-
- if (vi->oldsolution)
- bitmap_ior_into (vi->oldsolution, pts);
- else
- {
- vi->oldsolution = BITMAP_ALLOC (&oldpta_obstack);
- bitmap_copy (vi->oldsolution, pts);
- }
-
- solution = vi->solution;
- solution_empty = bitmap_empty_p (solution);
-
- /* Process the complex constraints */
- hash_set<constraint_t> *cvisited = nullptr;
- if (flag_checking)
- cvisited = new hash_set<constraint_t>;
- bitmap expanded_pts = NULL;
- for (unsigned j = 0; j < complex.length (); ++j)
- {
- constraint_t c = complex[j];
- /* At unification time only the directly involved nodes
- will get their complex constraints updated. Update
- our complex constraints now but keep the constraint
- vector sorted and clear of duplicates. Also make
- sure to evaluate each prevailing constraint only once. */
- unsigned int new_lhs = find (c->lhs.var);
- unsigned int new_rhs = find (c->rhs.var);
- if (c->lhs.var != new_lhs || c->rhs.var != new_rhs)
- {
- constraint tem = *c;
- tem.lhs.var = new_lhs;
- tem.rhs.var = new_rhs;
- unsigned int place
- = complex.lower_bound (&tem, constraint_less);
- c->lhs.var = new_lhs;
- c->rhs.var = new_rhs;
- if (place != j)
- {
- complex.ordered_remove (j);
- if (j < place)
- --place;
- if (place < complex.length ())
- {
- if (constraint_equal (*complex[place], *c))
- {
- j--;
- continue;
- }
- else
- complex.safe_insert (place, c);
- }
- else
- complex.quick_push (c);
- if (place > j)
- {
- j--;
- continue;
- }
- }
- }
-
- /* The only complex constraint that can change our
- solution to non-empty, given an empty solution,
- is a constraint where the lhs side is receiving
- some set from elsewhere. */
- if (cvisited && cvisited->add (c))
- gcc_unreachable ();
- if (!solution_empty || c->lhs.type != DEREF)
- do_complex_constraint (graph, c, pts, &expanded_pts);
- }
- if (cvisited)
- {
- /* When checking, verify the order of constraints is
- maintained and each constraint is evaluated exactly
- once. */
- for (unsigned j = 1; j < complex.length (); ++j)
- gcc_assert (constraint_less (complex[j-1], complex[j]));
- gcc_assert (cvisited->elements () == complex.length ());
- delete cvisited;
- }
- BITMAP_FREE (expanded_pts);
-
- solution_empty = bitmap_empty_p (solution);
-
- if (!solution_empty)
- {
- bitmap_iterator bi;
- unsigned eff_escaped_id = find (escaped_id);
- unsigned j;
-
- /* Propagate solution to all successors. */
- unsigned to_remove = ~0U;
- EXECUTE_IF_IN_NONNULL_BITMAP (graph->succs[i],
- 0, j, bi)
- {
- if (to_remove != ~0U)
- {
- bitmap_clear_bit (graph->succs[i], to_remove);
- to_remove = ~0U;
- }
- unsigned int to = find (j);
- if (to != j)
- {
- /* Update the succ graph, avoiding duplicate
- work. */
- to_remove = j;
- if (! bitmap_set_bit (graph->succs[i], to))
- continue;
- /* We eventually end up processing 'to' twice
- as it is undefined whether bitmap iteration
- iterates over bits set during iteration.
- Play safe instead of doing tricks. */
- }
- /* Don't try to propagate to ourselves. */
- if (to == i)
- {
- to_remove = j;
- continue;
- }
- /* Early node unification can lead to edges from
- escaped - remove them. */
- if (i == eff_escaped_id)
- {
- to_remove = j;
- if (bitmap_set_bit (get_varinfo (to)->solution,
- escaped_id))
- bitmap_set_bit (changed, to);
- continue;
- }
-
- if (bitmap_ior_into (get_varinfo (to)->solution, pts))
- bitmap_set_bit (changed, to);
- }
- if (to_remove != ~0U)
- bitmap_clear_bit (graph->succs[i], to_remove);
- }
- }
- }
- bitmap_obstack_release (&iteration_obstack);
- }
-
- BITMAP_FREE (pts);
- BITMAP_FREE (changed);
- bitmap_obstack_release (&oldpta_obstack);
-}
-
-/* Map from trees to variable infos. */
-static hash_map<tree, varinfo_t> *vi_for_tree;
-
-
/* Insert ID as the variable id for tree T in the vi_for_tree map. */
static void
@@ -3003,7 +734,7 @@ lookup_vi_for_tree (tree t)
return *slot;
}
-/* Return a printable name for DECL */
+/* Return a printable name for DECL. */
static const char *
alias_get_name (tree decl)
@@ -3191,10 +922,10 @@ process_constraint (constraint_t t)
if (!get_varinfo (lhs.var)->may_have_pointers)
return;
- /* This can happen in our IR with things like n->a = *p */
+ /* This can happen in our IR with things like n->a = *p. */
if (rhs.type == DEREF && lhs.type == DEREF && rhs.var != anything_id)
{
- /* Split into tmp = *rhs, *lhs = tmp */
+ /* Split into tmp = *rhs, *lhs = tmp. */
struct constraint_expr tmplhs;
tmplhs = new_scalar_tmp_constraint_exp ("doubledereftmp", true);
process_constraint (new_constraint (tmplhs, rhs));
@@ -3202,7 +933,7 @@ process_constraint (constraint_t t)
}
else if ((rhs.type != SCALAR || rhs.offset != 0) && lhs.type == DEREF)
{
- /* Split into tmp = &rhs, *lhs = tmp */
+ /* Split into tmp = &rhs, *lhs = tmp. */
struct constraint_expr tmplhs;
tmplhs = new_scalar_tmp_constraint_exp ("derefaddrtmp", true);
process_constraint (new_constraint (tmplhs, rhs));
@@ -3370,7 +1101,7 @@ get_constraint_for_component_ref (tree t, vec<ce_s> *results,
tree forzero;
/* Some people like to do cute things like take the address of
- &0->a.b */
+ &0->a.b. */
forzero = t;
while (handled_component_p (forzero)
|| INDIRECT_REF_P (forzero)
@@ -3444,7 +1175,7 @@ get_constraint_for_component_ref (tree t, vec<ce_s> *results,
{
/* 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,
+ ignore this constraint. When we handle pointer subtraction,
we may have to do something cute here. */
if (maybe_lt (poly_uint64 (bitpos), get_varinfo (result.var)->fullsize)
@@ -3481,7 +1212,7 @@ get_constraint_for_component_ref (tree t, vec<ce_s> *results,
results->safe_push (cexpr);
}
else if (results->length () == 0)
- /* Assert that we found *some* field there. The user couldn't be
+ /* Assert that we found *some* field there. The user couldn't be
accessing *only* padding. */
/* Still the user could access one past the end of an array
embedded in a struct resulting in accessing *only* padding. */
@@ -3535,7 +1266,7 @@ get_constraint_for_component_ref (tree t, vec<ce_s> *results,
/* Dereference the constraint expression CONS, and return the result.
DEREF (ADDRESSOF) = SCALAR
DEREF (SCALAR) = DEREF
- DEREF (DEREF) = (temp = DEREF1; result = DEREF(temp))
+ DEREF (DEREF) = (temp = DEREF1; result = DEREF (temp))
This is needed so that we can handle dereferencing DEREF constraints. */
static void
@@ -3594,7 +1325,7 @@ get_constraint_for_1 (tree t, vec<ce_s> *results, bool address_p,
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
+ 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.
@@ -3745,7 +1476,7 @@ get_constraint_for_1 (tree t, vec<ce_s> *results, bool address_p,
tmp.truncate (0);
}
/* We do not know whether the constructor was complete,
- so technically we have to add &NOTHING or &ANYTHING
+ so technically we have to add &NOTHING or &ANYTHING
like we do for an empty constructor as well. */
return;
}
@@ -4144,7 +1875,7 @@ get_function_part_constraint (varinfo_t fi, unsigned part)
/* Produce constraints for argument ARG of call STMT with eaf flags
FLAGS. RESULTS is array holding constraints for return value.
CALLESCAPE_ID is variable where call loocal escapes are added.
- WRITES_GLOVEL_MEMORY is true if callee may write global memory. */
+ WRITES_GLOVEL_MEMORY is true if callee may write global memory. */
static void
handle_call_arg (gcall *stmt, tree arg, vec<ce_s> *results, int flags,
@@ -4510,7 +2241,7 @@ handle_lhs_call (gcall *stmt, tree lhs, int flags, vec<ce_s> &rhsc,
rhsc.truncate (0);
vi = make_heapvar ("HEAP", true);
/* We are marking allocated storage local, we deal with it becoming
- global by escaping and setting of vars_contains_escaped_heap. */
+ global by escaping and setting of vars_contains_escaped_heap. */
DECL_EXTERNAL (vi->decl) = 0;
vi->is_global_var = 0;
/* If this is not a real malloc call assume the memory was
@@ -4698,8 +2429,8 @@ find_func_aliases_for_builtin_call (struct function *fn, gcall *t)
}
case BUILT_IN_STACK_SAVE:
case BUILT_IN_STACK_RESTORE:
- /* Nothing interesting happens. */
- return true;
+ /* Nothing interesting happens. */
+ return true;
case BUILT_IN_ALLOCA:
case BUILT_IN_ALLOCA_WITH_ALIGN:
case BUILT_IN_ALLOCA_WITH_ALIGN_AND_MAX:
@@ -4723,7 +2454,7 @@ find_func_aliases_for_builtin_call (struct function *fn, gcall *t)
return true;
}
case BUILT_IN_POSIX_MEMALIGN:
- {
+ {
tree ptrptr = gimple_call_arg (t, 0);
get_constraint_for (ptrptr, &lhsc);
do_deref (&lhsc);
@@ -4806,7 +2537,7 @@ find_func_aliases_for_builtin_call (struct function *fn, gcall *t)
}
break;
/* String / character search functions return a pointer into the
- source string or NULL. */
+ source string or NULL. */
case BUILT_IN_INDEX:
case BUILT_IN_STRCHR:
case BUILT_IN_STRRCHR:
@@ -4827,7 +2558,7 @@ find_func_aliases_for_builtin_call (struct function *fn, gcall *t)
}
return true;
/* Pure functions that return something not based on any object and
- that use the memory pointed to by their arguments (but not
+ that use the memory pointed to by their arguments (but not
transitively). */
case BUILT_IN_STRCMP:
case BUILT_IN_STRCMP_EQ:
@@ -5192,7 +2923,7 @@ find_func_aliases (struct function *fn, gimple *origt)
}
}
/* In IPA mode, we need to generate constraints to pass call
- arguments through their calls. There are two cases,
+ arguments through their calls. There are two cases,
either a GIMPLE_CALL returning a value, or just a plain
GIMPLE_CALL when we are not.
@@ -5337,7 +3068,7 @@ find_func_aliases (struct function *fn, gimple *origt)
constraint = TREE_STRING_POINTER (TREE_VALUE (TREE_PURPOSE (link)));
oconstraints[i] = constraint;
parse_output_constraint (&constraint, i, 0, 0, &allows_mem,
- &allows_reg, &is_inout);
+ &allows_reg, &is_inout, nullptr);
/* A memory constraint makes the address of the operand escape. */
if (!allows_reg && allows_mem)
@@ -5370,7 +3101,7 @@ find_func_aliases (struct function *fn, gimple *origt)
constraint = TREE_STRING_POINTER (TREE_VALUE (TREE_PURPOSE (link)));
parse_input_constraint (&constraint, 0, 0, noutputs, 0, oconstraints,
- &allows_mem, &allows_reg);
+ &allows_mem, &allows_reg, nullptr);
/* A memory constraint makes the address of the operand escape. */
if (!allows_reg && allows_mem)
@@ -5445,7 +3176,7 @@ find_func_clobbers (struct function *fn, gimple *origt)
|| (TREE_CODE (tem) == MEM_REF
&& !(TREE_CODE (TREE_OPERAND (tem, 0)) == ADDR_EXPR
&& auto_var_in_fn_p
- (TREE_OPERAND (TREE_OPERAND (tem, 0), 0), fn->decl))))
+ (TREE_OPERAND (TREE_OPERAND (tem, 0), 0), fn->decl))))
{
struct constraint_expr lhsc, *rhsp;
unsigned i;
@@ -5474,7 +3205,7 @@ find_func_clobbers (struct function *fn, gimple *origt)
|| (TREE_CODE (tem) == MEM_REF
&& !(TREE_CODE (TREE_OPERAND (tem, 0)) == ADDR_EXPR
&& auto_var_in_fn_p
- (TREE_OPERAND (TREE_OPERAND (tem, 0), 0), fn->decl))))
+ (TREE_OPERAND (TREE_OPERAND (tem, 0), 0), fn->decl))))
{
struct constraint_expr lhs, *rhsp;
unsigned i;
@@ -5786,65 +3517,6 @@ find_func_clobbers (struct function *fn, gimple *origt)
}
-/* Find the first varinfo in the same variable as START that overlaps with
- OFFSET. Return NULL if we can't find one. */
-
-static varinfo_t
-first_vi_for_offset (varinfo_t start, unsigned HOST_WIDE_INT offset)
-{
- /* If the offset is outside of the variable, bail out. */
- if (offset >= start->fullsize)
- return NULL;
-
- /* If we cannot reach offset from start, lookup the first field
- and start from there. */
- if (start->offset > offset)
- start = get_varinfo (start->head);
-
- while (start)
- {
- /* We may not find a variable in the field list with the actual
- offset 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 >= start->offset
- && (offset - start->offset) < start->size)
- return start;
-
- start = vi_next (start);
- }
-
- return NULL;
-}
-
-/* Find the first varinfo in the same variable as START that overlaps with
- OFFSET. If there is no such varinfo the varinfo directly preceding
- OFFSET is returned. */
-
-static varinfo_t
-first_or_preceding_vi_for_offset (varinfo_t start,
- unsigned HOST_WIDE_INT offset)
-{
- /* If we cannot reach offset from start, lookup the first field
- and start from there. */
- if (start->offset > offset)
- start = get_varinfo (start->head);
-
- /* We may not find a variable in the field list with the actual
- offset when we have glommed a structure to a variable.
- In that case, however, offset should still be within the size
- of the variable.
- If we got beyond the offset we look for return the field
- directly preceding offset which may be the last field. */
- while (start->next
- && offset >= start->offset
- && !((offset - start->offset) < start->size))
- start = vi_next (start);
-
- return start;
-}
-
-
/* This structure is 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
@@ -5871,7 +3543,7 @@ struct fieldoff
typedef struct fieldoff fieldoff_s;
-/* qsort comparison function for two fieldoff's PA and PB */
+/* qsort comparison function for two fieldoff's PA and PB. */
static int
fieldoff_compare (const void *pa, const void *pb)
@@ -6599,38 +4271,6 @@ create_variable_info_for (tree decl, const char *name, bool add_id)
return id;
}
-/* Print out the points-to solution for VAR to FILE. */
-
-static void
-dump_solution_for_var (FILE *file, unsigned int var)
-{
- varinfo_t vi = get_varinfo (var);
- unsigned int i;
- bitmap_iterator bi;
-
- /* Dump the solution for unified vars anyway, this avoids difficulties
- in scanning dumps in the testsuite. */
- fprintf (file, "%s = { ", vi->name);
- vi = get_varinfo (find (var));
- EXECUTE_IF_SET_IN_BITMAP (vi->solution, 0, i, bi)
- fprintf (file, "%s ", get_varinfo (i)->name);
- fprintf (file, "}");
-
- /* But note when the variable was unified. */
- if (vi->id != var)
- fprintf (file, " same as %s", vi->name);
-
- fprintf (file, "\n");
-}
-
-/* Print the points-to solution for VAR to stderr. */
-
-DEBUG_FUNCTION void
-debug_solution_for_var (unsigned int var)
-{
- dump_solution_for_var (stderr, var);
-}
-
/* Register the constraints for function parameter related VI. */
static void
@@ -6718,7 +4358,7 @@ struct shared_bitmap_hasher : free_ptr_hash <shared_bitmap_info>
const shared_bitmap_info *);
};
-/* Hash function for a shared_bitmap_info_t */
+/* Hash function for a shared_bitmap_info_t. */
inline hashval_t
shared_bitmap_hasher::hash (const shared_bitmap_info *bi)
@@ -6726,7 +4366,7 @@ shared_bitmap_hasher::hash (const shared_bitmap_info *bi)
return bi->hashcode;
}
-/* Equality function for two shared_bitmap_info_t's. */
+/* Equality function for two shared_bitmap_info_t's. */
inline bool
shared_bitmap_hasher::equal (const shared_bitmap_info *sbi1,
@@ -6784,8 +4424,8 @@ set_uids_in_ptset (bitmap into, bitmap from, struct pt_solution *pt,
{
unsigned int i;
bitmap_iterator bi;
- varinfo_t escaped_vi = get_varinfo (find (escaped_id));
- varinfo_t escaped_return_vi = get_varinfo (find (escaped_return_id));
+ varinfo_t escaped_vi = get_varinfo (var_rep[escaped_id]);
+ varinfo_t escaped_return_vi = get_varinfo (var_rep[escaped_return_id]);
bool everything_escaped
= escaped_vi->solution && bitmap_bit_p (escaped_vi->solution, anything_id);
@@ -6883,7 +4523,7 @@ find_what_var_points_to (tree fndecl, varinfo_t orig_vi)
/* This variable may have been collapsed, let's get the real
variable. */
- vi = get_varinfo (find (orig_vi->id));
+ vi = get_varinfo (var_rep[orig_vi->id]);
/* See if we have already computed the solution and return it. */
pt_solution **slot = &final_solutions->get_or_insert (vi);
@@ -6910,7 +4550,7 @@ find_what_var_points_to (tree fndecl, varinfo_t orig_vi)
else
pt->escaped = 1;
/* Expand some special vars of ESCAPED in-place here. */
- varinfo_t evi = get_varinfo (find (escaped_id));
+ varinfo_t evi = get_varinfo (var_rep[escaped_id]);
if (bitmap_bit_p (evi->solution, nonlocal_id))
pt->nonlocal = 1;
}
@@ -7137,7 +4777,7 @@ pt_solution_includes_global (struct pt_solution *pt, bool escaped_local_p)
|| pt->nonlocal
|| pt->vars_contains_nonlocal
/* The following is a hack to make the malloc escape hack work.
- In reality we'd need different sets for escaped-through-return
+ In reality we'd need different sets for escaped-through-return
and escaped-to-callees and passes would need to be updated. */
|| pt->vars_contains_escaped_heap)
return true;
@@ -7273,52 +4913,6 @@ pt_solutions_intersect (struct pt_solution *pt1, struct pt_solution *pt2)
return res;
}
-/* Dump stats information to OUTFILE. */
-
-static void
-dump_sa_stats (FILE *outfile)
-{
- fprintf (outfile, "Points-to Stats:\n");
- fprintf (outfile, "Total vars: %d\n", stats.total_vars);
- fprintf (outfile, "Non-pointer vars: %d\n",
- stats.nonpointer_vars);
- fprintf (outfile, "Statically unified vars: %d\n",
- stats.unified_vars_static);
- fprintf (outfile, "Dynamically unified vars: %d\n",
- stats.unified_vars_dynamic);
- fprintf (outfile, "Iterations: %d\n", stats.iterations);
- fprintf (outfile, "Number of edges: %d\n", stats.num_edges);
- fprintf (outfile, "Number of implicit edges: %d\n",
- stats.num_implicit_edges);
- fprintf (outfile, "Number of avoided edges: %d\n",
- stats.num_avoided_edges);
-}
-
-/* Dump points-to information to OUTFILE. */
-
-static void
-dump_sa_points_to_info (FILE *outfile)
-{
- fprintf (outfile, "\nPoints-to sets\n\n");
-
- for (unsigned i = 1; i < varmap.length (); i++)
- {
- varinfo_t vi = get_varinfo (i);
- if (!vi->may_have_pointers)
- continue;
- dump_solution_for_var (outfile, i);
- }
-}
-
-
-/* Debug points-to information to stderr. */
-
-DEBUG_FUNCTION void
-debug_sa_points_to_info (void)
-{
- dump_sa_points_to_info (stderr);
-}
-
/* Initialize the always-existing constraint variables for NULL
ANYTHING, READONLY, and INTEGER */
@@ -7511,7 +5105,7 @@ init_base_vars (void)
process_constraint (new_constraint (lhs, rhs));
}
-/* Initialize things necessary to perform PTA */
+/* Initialize things necessary to perform PTA. */
static void
init_alias_vars (void)
@@ -7520,7 +5114,6 @@ init_alias_vars (void)
bitmap_obstack_initialize (&pta_obstack);
bitmap_obstack_initialize (&oldpta_obstack);
- bitmap_obstack_initialize (&predbitmap_obstack);
constraints.create (8);
varmap.create (8);
@@ -7537,144 +5130,6 @@ init_alias_vars (void)
gcc_obstack_init (&final_solutions_obstack);
}
-/* Remove the REF and ADDRESS edges from GRAPH, as well as all the
- predecessor edges. */
-
-static void
-remove_preds_and_fake_succs (constraint_graph_t graph)
-{
- unsigned int i;
-
- /* Clear the implicit ref and address nodes from the successor
- lists. */
- for (i = 1; i < FIRST_REF_NODE; i++)
- {
- if (graph->succs[i])
- bitmap_clear_range (graph->succs[i], FIRST_REF_NODE,
- FIRST_REF_NODE * 2);
- }
-
- /* Free the successor list for the non-ref nodes. */
- for (i = FIRST_REF_NODE + 1; i < graph->size; i++)
- {
- if (graph->succs[i])
- BITMAP_FREE (graph->succs[i]);
- }
-
- /* Now reallocate the size of the successor list as, and blow away
- the predecessor bitmaps. */
- graph->size = varmap.length ();
- graph->succs = XRESIZEVEC (bitmap, graph->succs, graph->size);
-
- free (graph->implicit_preds);
- graph->implicit_preds = NULL;
- free (graph->preds);
- graph->preds = NULL;
- bitmap_obstack_release (&predbitmap_obstack);
-}
-
-/* Solve the constraint set. */
-
-static void
-solve_constraints (void)
-{
- class scc_info *si;
-
- /* Sort varinfos so that ones that cannot be pointed to are last.
- This makes bitmaps more efficient. */
- unsigned int *map = XNEWVEC (unsigned int, varmap.length ());
- for (unsigned i = 0; i < integer_id + 1; ++i)
- map[i] = i;
- /* Start with address-taken vars, followed by not address-taken vars
- to move vars never appearing in the points-to solution bitmaps last. */
- unsigned j = integer_id + 1;
- for (unsigned i = integer_id + 1; i < varmap.length (); ++i)
- if (varmap[varmap[i]->head]->address_taken)
- map[i] = j++;
- for (unsigned i = integer_id + 1; i < varmap.length (); ++i)
- if (! varmap[varmap[i]->head]->address_taken)
- map[i] = j++;
- /* Shuffle varmap according to map. */
- for (unsigned i = integer_id + 1; i < varmap.length (); ++i)
- {
- while (map[varmap[i]->id] != i)
- std::swap (varmap[i], varmap[map[varmap[i]->id]]);
- gcc_assert (bitmap_empty_p (varmap[i]->solution));
- varmap[i]->id = i;
- varmap[i]->next = map[varmap[i]->next];
- varmap[i]->head = map[varmap[i]->head];
- }
- /* Finally rewrite constraints. */
- for (unsigned i = 0; i < constraints.length (); ++i)
- {
- constraints[i]->lhs.var = map[constraints[i]->lhs.var];
- constraints[i]->rhs.var = map[constraints[i]->rhs.var];
- }
- free (map);
-
- if (dump_file)
- fprintf (dump_file,
- "\nCollapsing static cycles and doing variable "
- "substitution\n");
-
- init_graph (varmap.length () * 2);
-
- if (dump_file)
- fprintf (dump_file, "Building predecessor graph\n");
- build_pred_graph ();
-
- if (dump_file)
- fprintf (dump_file, "Detecting pointer and location "
- "equivalences\n");
- si = perform_var_substitution (graph);
-
- if (dump_file)
- fprintf (dump_file, "Rewriting constraints and unifying "
- "variables\n");
- rewrite_constraints (graph, si);
-
- build_succ_graph ();
-
- free_var_substitution_info (si);
-
- /* Attach complex constraints to graph nodes. */
- move_complex_constraints (graph);
-
- if (dump_file)
- fprintf (dump_file, "Uniting pointer but not location equivalent "
- "variables\n");
- unite_pointer_equivalences (graph);
-
- if (dump_file)
- fprintf (dump_file, "Finding indirect cycles\n");
- find_indirect_cycles (graph);
-
- /* Implicit nodes and predecessors are no longer necessary at this
- point. */
- remove_preds_and_fake_succs (graph);
-
- if (dump_file && (dump_flags & TDF_GRAPH))
- {
- fprintf (dump_file, "\n\n// The constraint graph before solve-graph "
- "in dot format:\n");
- dump_constraint_graph (dump_file);
- fprintf (dump_file, "\n\n");
- }
-
- if (dump_file)
- fprintf (dump_file, "Solving graph\n");
-
- solve_graph (graph);
-
- if (dump_file && (dump_flags & TDF_GRAPH))
- {
- fprintf (dump_file, "\n\n// The constraint graph after solve-graph "
- "in dot format:\n");
- dump_constraint_graph (dump_file);
- fprintf (dump_file, "\n\n");
- }
-}
-
/* Create points-to sets for the current function. See the comments
at the start of the file for an algorithmic overview. */
@@ -7845,8 +5300,6 @@ compute_points_to_sets (void)
static void
delete_points_to_sets (void)
{
- unsigned int i;
-
delete shared_bitmap_table;
shared_bitmap_table = NULL;
if (dump_file && (dump_flags & TDF_STATS))
@@ -7858,16 +5311,7 @@ delete_points_to_sets (void)
bitmap_obstack_release (&pta_obstack);
constraints.release ();
- for (i = 0; i < graph->size; i++)
- graph->complex[i].release ();
- free (graph->complex);
-
- free (graph->rep);
- free (graph->succs);
- free (graph->pe);
- free (graph->pe_rep);
- free (graph->indirect_cycles);
- free (graph);
+ free (var_rep);
varmap.release ();
variable_info_pool.release ();
@@ -7914,14 +5358,14 @@ visit_loadstore (gimple *, tree base, tree ref, void *data)
if (! vi)
return false;
- vi = get_varinfo (find (vi->id));
+ vi = get_varinfo (var_rep[vi->id]);
if (bitmap_intersect_p (rvars, vi->solution)
|| (escaped_p && bitmap_bit_p (vi->solution, escaped_id)))
return false;
}
/* Do not overwrite existing cliques (that includes clique, base
- pairs we just set). */
+ pairs we just set). */
if (MR_DEPENDENCE_CLIQUE (base) == 0)
{
MR_DEPENDENCE_CLIQUE (base) = clique;
@@ -8050,7 +5494,7 @@ compute_dependence_clique (void)
varinfo_t vi = lookup_vi_for_tree (p);
if (!vi)
continue;
- vi = get_varinfo (find (vi->id));
+ vi = get_varinfo (var_rep[vi->id]);
bitmap_iterator bi;
unsigned j;
varinfo_t restrict_var = NULL;
@@ -8101,11 +5545,11 @@ compute_dependence_clique (void)
maybe_set_dependence_info);
if (used)
{
- /* Add all subvars to the set of restrict pointed-to set. */
+ /* Add all subvars to the set of restrict pointed-to set. */
for (unsigned sv = restrict_var->head; sv != 0;
sv = get_varinfo (sv)->next)
bitmap_set_bit (rvars, sv);
- varinfo_t escaped = get_varinfo (find (escaped_id));
+ varinfo_t escaped = get_varinfo (var_rep[escaped_id]);
if (bitmap_bit_p (escaped->solution, restrict_var->id))
escaped_p = true;
}
@@ -8261,7 +5705,7 @@ struct pt_solution ipa_escaped_pt
= { true, false, false, false, false, false,
false, false, false, false, false, NULL };
-/* Associate node with varinfo DATA. Worker for
+/* Associate node with varinfo DATA. Worker for
cgraph_for_symbol_thunks_and_aliases. */
static bool
associate_varinfo_to_alias (struct cgraph_node *node, void *data)
@@ -8275,111 +5719,6 @@ associate_varinfo_to_alias (struct cgraph_node *node, void *data)
return false;
}
-/* Dump varinfo VI to FILE. */
-
-static void
-dump_varinfo (FILE *file, varinfo_t vi)
-{
- if (vi == NULL)
- return;
-
- fprintf (file, "%u: %s\n", vi->id, vi->name);
-
- const char *sep = " ";
- if (vi->is_artificial_var)
- fprintf (file, "%sartificial", sep);
- if (vi->is_special_var)
- fprintf (file, "%sspecial", sep);
- if (vi->is_unknown_size_var)
- fprintf (file, "%sunknown-size", sep);
- if (vi->is_full_var)
- fprintf (file, "%sfull", sep);
- if (vi->is_heap_var)
- fprintf (file, "%sheap", sep);
- if (vi->may_have_pointers)
- fprintf (file, "%smay-have-pointers", sep);
- if (vi->only_restrict_pointers)
- fprintf (file, "%sonly-restrict-pointers", sep);
- if (vi->is_restrict_var)
- fprintf (file, "%sis-restrict-var", sep);
- if (vi->is_global_var)
- fprintf (file, "%sglobal", sep);
- if (vi->is_ipa_escape_point)
- fprintf (file, "%sipa-escape-point", sep);
- if (vi->is_fn_info)
- fprintf (file, "%sfn-info", sep);
- if (vi->ruid)
- fprintf (file, "%srestrict-uid:%u", sep, vi->ruid);
- if (vi->next)
- fprintf (file, "%snext:%u", sep, vi->next);
- if (vi->head != vi->id)
- fprintf (file, "%shead:%u", sep, vi->head);
- if (vi->offset)
- fprintf (file, "%soffset:" HOST_WIDE_INT_PRINT_DEC, sep, vi->offset);
- if (vi->size != ~HOST_WIDE_INT_0U)
- fprintf (file, "%ssize:" HOST_WIDE_INT_PRINT_DEC, sep, vi->size);
- if (vi->fullsize != ~HOST_WIDE_INT_0U && vi->fullsize != vi->size)
- fprintf (file, "%sfullsize:" HOST_WIDE_INT_PRINT_DEC, sep,
- vi->fullsize);
- fprintf (file, "\n");
-
- if (vi->solution && !bitmap_empty_p (vi->solution))
- {
- bitmap_iterator bi;
- unsigned i;
- fprintf (file, " solution: {");
- EXECUTE_IF_SET_IN_BITMAP (vi->solution, 0, i, bi)
- fprintf (file, " %u", i);
- fprintf (file, " }\n");
- }
-
- if (vi->oldsolution && !bitmap_empty_p (vi->oldsolution)
- && !bitmap_equal_p (vi->solution, vi->oldsolution))
- {
- bitmap_iterator bi;
- unsigned i;
- fprintf (file, " oldsolution: {");
- EXECUTE_IF_SET_IN_BITMAP (vi->oldsolution, 0, i, bi)
- fprintf (file, " %u", i);
- fprintf (file, " }\n");
- }
-}
-
-/* Dump varinfo VI to stderr. */
-
-DEBUG_FUNCTION void
-debug_varinfo (varinfo_t vi)
-{
- dump_varinfo (stderr, vi);
-}
-
-/* Dump varmap to FILE. */
-
-static void
-dump_varmap (FILE *file)
-{
- if (varmap.length () == 0)
- return;
-
- fprintf (file, "variables:\n");
-
- for (unsigned int i = 0; i < varmap.length (); ++i)
- {
- varinfo_t vi = get_varinfo (i);
- dump_varinfo (file, vi);
- }
-
- fprintf (file, "\n");
-}
-
-/* Dump varmap to stderr. */
-
-DEBUG_FUNCTION void
-debug_varmap (void)
-{
- dump_varmap (stderr);
-}
-
/* Compute whether node is refered to non-locally. Worker for
cgraph_for_symbol_thunks_and_aliases. */
static bool
@@ -8493,7 +5832,7 @@ ipa_pta_execute (void)
varinfo_t vi = get_vi_for_tree (var->decl);
/* For the purpose of IPA PTA unit-local globals are not
- escape points. */
+ escape points. */
bool nonlocal_p = (DECL_EXTERNAL (var->decl)
|| TREE_PUBLIC (var->decl)
|| var->used_from_other_partition
@@ -8592,7 +5931,7 @@ ipa_pta_execute (void)
for (varinfo_t ai = first_vi_for_offset (fi, fi_parm_base);
ai; ai = vi_next (ai))
{
- varinfo_t vi = get_varinfo (find (ai->id));
+ varinfo_t vi = get_varinfo (var_rep[ai->id]);
bitmap_iterator bi;
unsigned j;
EXECUTE_IF_SET_IN_BITMAP (vi->solution, 0, j, bi)
@@ -8608,12 +5947,12 @@ ipa_pta_execute (void)
}
}
/* As well as global variables which are another way of passing
- arguments to recursive invocations. */
+ arguments to recursive invocations. */
else if (fi->is_global_var)
{
for (varinfo_t ai = fi; ai; ai = vi_next (ai))
{
- varinfo_t vi = get_varinfo (find (ai->id));
+ varinfo_t vi = get_varinfo (var_rep[ai->id]);
bitmap_iterator bi;
unsigned j;
EXECUTE_IF_SET_IN_BITMAP (vi->solution, 0, j, bi)
@@ -8708,10 +6047,10 @@ ipa_pta_execute (void)
{
*gimple_call_clobber_set (stmt)
= find_what_var_points_to
- (node->decl, first_vi_for_offset (fi, fi_clobbers));
+ (node->decl, first_vi_for_offset (fi, fi_clobbers));
*gimple_call_use_set (stmt)
= find_what_var_points_to
- (node->decl, first_vi_for_offset (fi, fi_uses));
+ (node->decl, first_vi_for_offset (fi, fi_uses));
}
/* Handle direct calls to external functions. */
else if (decl && (!fi || fi->decl))
@@ -8738,7 +6077,8 @@ ipa_pta_execute (void)
}
pt = gimple_call_clobber_set (stmt);
- if (gimple_call_flags (stmt) & (ECF_CONST|ECF_PURE|ECF_NOVOPS))
+ if (gimple_call_flags (stmt) &
+ (ECF_CONST|ECF_PURE|ECF_NOVOPS))
memset (pt, 0, sizeof (struct pt_solution));
else if ((vi = lookup_call_clobber_vi (stmt)) != NULL)
{
@@ -8763,7 +6103,7 @@ ipa_pta_execute (void)
{
/* We need to accumulate all clobbers/uses of all possible
callees. */
- fi = get_varinfo (find (fi->id));
+ fi = get_varinfo (var_rep[fi->id]);
/* If we cannot constrain the set of functions we'll end up
calling we end up using/clobbering everything. */
if (bitmap_bit_p (fi->solution, anything_id)
@@ -8823,7 +6163,7 @@ ipa_pta_execute (void)
fn->gimple_df->ipa_pta = true;
/* We have to re-set the final-solution cache after each function
- because what is a "global" is dependent on function context. */
+ because what is a "global" is dependent on function context. */
final_solutions->empty ();
obstack_free (&final_solutions_obstack, NULL);
gcc_obstack_init (&final_solutions_obstack);