aboutsummaryrefslogtreecommitdiff
path: root/gcc/pta-andersen.cc
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/pta-andersen.cc')
-rw-r--r--gcc/pta-andersen.cc2565
1 files changed, 2565 insertions, 0 deletions
diff --git a/gcc/pta-andersen.cc b/gcc/pta-andersen.cc
new file mode 100644
index 0000000..0253f05
--- /dev/null
+++ b/gcc/pta-andersen.cc
@@ -0,0 +1,2565 @@
+/* Andersen-style solver for tree based points-to analysis
+ Copyright (C) 2005-2025 Free Software Foundation, Inc.
+ Contributed by Daniel Berlin <dberlin@dberlin.org>
+
+ This file is part of GCC.
+
+ GCC is free software; you can redistribute it and/or modify
+ under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ GCC is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GCC; see the file COPYING3. If not see
+ <http://www.gnu.org/licenses/>. */
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "backend.h"
+
+#include "tree-ssa-structalias.h"
+#include "pta-andersen.h"
+
+/* 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))
+
+#define EXECUTE_IF_IN_NONNULL_BITMAP(a, b, c, d) \
+ if (a) \
+ EXECUTE_IF_SET_IN_BITMAP (a, b, c, d)
+
+using namespace pointer_analysis;
+
+/* Used for predecessor bitmaps. */
+static bitmap_obstack predbitmap_obstack;
+
+/* Used for per-solver-iteration bitmaps. */
+static bitmap_obstack iteration_obstack;
+
+typedef struct constraint_graph *constraint_graph_t;
+
+/* 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;
+
+static void unify_nodes (constraint_graph_t, unsigned int, unsigned int, bool);
+
+
+/* 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;
+}
+
+/* Perform path compression for all nodes in the node representatives
+ union-find structure. */
+
+static void
+union_find_compress_all (void)
+{
+ unsigned int i;
+ for (i = 0; i < graph->size; i++)
+ find (i);
+}
+
+/* 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;
+
+ bitmap_obstack_initialize (&predbitmap_obstack);
+
+ 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 *);
+};
+
+/* 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;
+
+/* 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));
+}
+
+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);
+}
+
+void
+delete_graph (void)
+{
+ unsigned int i;
+ for (i = 0; i < graph->size; i++)
+ graph->complex[i].release ();
+ free (graph->complex);
+
+ free (graph->succs);
+ free (graph->pe);
+ free (graph->pe_rep);
+ free (graph->indirect_cycles);
+ /* We are not doing free (graph->rep) since the representatives mapping is
+ needed outside of the solver too. */
+ free (graph);
+}
+
+/* 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);
+}
+
+namespace pointer_analysis {
+
+/* Solve the constraint set. The entry function of the solver. */
+
+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");
+ }
+
+ /* The mapping node -> representative is one of the outputs of the
+ solver. */
+ union_find_compress_all ();
+ var_rep = graph->rep;
+
+ delete_graph ();
+}
+
+} // namespace pointer_analysis