xref: /dflybsd-src/contrib/gcc-4.7/gcc/tree-ssa-structalias.c (revision 81fc95a5293ee307c688a350a3feb4734aaddbb4)
1e4b17023SJohn Marino /* Tree based points-to analysis
2e4b17023SJohn Marino    Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010, 2011
3e4b17023SJohn Marino    Free Software Foundation, Inc.
4e4b17023SJohn Marino    Contributed by Daniel Berlin <dberlin@dberlin.org>
5e4b17023SJohn Marino 
6e4b17023SJohn Marino    This file is part of GCC.
7e4b17023SJohn Marino 
8e4b17023SJohn Marino    GCC is free software; you can redistribute it and/or modify
9e4b17023SJohn Marino    under the terms of the GNU General Public License as published by
10e4b17023SJohn Marino    the Free Software Foundation; either version 3 of the License, or
11e4b17023SJohn Marino    (at your option) any later version.
12e4b17023SJohn Marino 
13e4b17023SJohn Marino    GCC is distributed in the hope that it will be useful,
14e4b17023SJohn Marino    but WITHOUT ANY WARRANTY; without even the implied warranty of
15e4b17023SJohn Marino    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16e4b17023SJohn Marino    GNU General Public License for more details.
17e4b17023SJohn Marino 
18e4b17023SJohn Marino    You should have received a copy of the GNU General Public License
19e4b17023SJohn Marino    along with GCC; see the file COPYING3.  If not see
20e4b17023SJohn Marino    <http://www.gnu.org/licenses/>.  */
21e4b17023SJohn Marino 
22e4b17023SJohn Marino #include "config.h"
23e4b17023SJohn Marino #include "system.h"
24e4b17023SJohn Marino #include "coretypes.h"
25e4b17023SJohn Marino #include "tm.h"
26e4b17023SJohn Marino #include "ggc.h"
27e4b17023SJohn Marino #include "obstack.h"
28e4b17023SJohn Marino #include "bitmap.h"
29e4b17023SJohn Marino #include "flags.h"
30e4b17023SJohn Marino #include "basic-block.h"
31e4b17023SJohn Marino #include "output.h"
32e4b17023SJohn Marino #include "tree.h"
33e4b17023SJohn Marino #include "tree-flow.h"
34e4b17023SJohn Marino #include "tree-inline.h"
35e4b17023SJohn Marino #include "diagnostic-core.h"
36e4b17023SJohn Marino #include "gimple.h"
37e4b17023SJohn Marino #include "hashtab.h"
38e4b17023SJohn Marino #include "function.h"
39e4b17023SJohn Marino #include "cgraph.h"
40e4b17023SJohn Marino #include "tree-pass.h"
41e4b17023SJohn Marino #include "timevar.h"
42e4b17023SJohn Marino #include "alloc-pool.h"
43e4b17023SJohn Marino #include "splay-tree.h"
44e4b17023SJohn Marino #include "params.h"
45e4b17023SJohn Marino #include "cgraph.h"
46e4b17023SJohn Marino #include "alias.h"
47e4b17023SJohn Marino #include "pointer-set.h"
48e4b17023SJohn Marino 
49e4b17023SJohn Marino /* The idea behind this analyzer is to generate set constraints from the
50e4b17023SJohn Marino    program, then solve the resulting constraints in order to generate the
51e4b17023SJohn Marino    points-to sets.
52e4b17023SJohn Marino 
53e4b17023SJohn Marino    Set constraints are a way of modeling program analysis problems that
54e4b17023SJohn Marino    involve sets.  They consist of an inclusion constraint language,
55e4b17023SJohn Marino    describing the variables (each variable is a set) and operations that
56e4b17023SJohn Marino    are involved on the variables, and a set of rules that derive facts
57e4b17023SJohn Marino    from these operations.  To solve a system of set constraints, you derive
58e4b17023SJohn Marino    all possible facts under the rules, which gives you the correct sets
59e4b17023SJohn Marino    as a consequence.
60e4b17023SJohn Marino 
61e4b17023SJohn Marino    See  "Efficient Field-sensitive pointer analysis for C" by "David
62e4b17023SJohn Marino    J. Pearce and Paul H. J. Kelly and Chris Hankin, at
63e4b17023SJohn Marino    http://citeseer.ist.psu.edu/pearce04efficient.html
64e4b17023SJohn Marino 
65e4b17023SJohn Marino    Also see "Ultra-fast Aliasing Analysis using CLA: A Million Lines
66e4b17023SJohn Marino    of C Code in a Second" by ""Nevin Heintze and Olivier Tardieu" at
67e4b17023SJohn Marino    http://citeseer.ist.psu.edu/heintze01ultrafast.html
68e4b17023SJohn Marino 
69e4b17023SJohn Marino    There are three types of real constraint expressions, DEREF,
70e4b17023SJohn Marino    ADDRESSOF, and SCALAR.  Each constraint expression consists
71e4b17023SJohn Marino    of a constraint type, a variable, and an offset.
72e4b17023SJohn Marino 
73e4b17023SJohn Marino    SCALAR is a constraint expression type used to represent x, whether
74e4b17023SJohn Marino    it appears on the LHS or the RHS of a statement.
75e4b17023SJohn Marino    DEREF is a constraint expression type used to represent *x, whether
76e4b17023SJohn Marino    it appears on the LHS or the RHS of a statement.
77e4b17023SJohn Marino    ADDRESSOF is a constraint expression used to represent &x, whether
78e4b17023SJohn Marino    it appears on the LHS or the RHS of a statement.
79e4b17023SJohn Marino 
80e4b17023SJohn Marino    Each pointer variable in the program is assigned an integer id, and
81e4b17023SJohn Marino    each field of a structure variable is assigned an integer id as well.
82e4b17023SJohn Marino 
83e4b17023SJohn Marino    Structure variables are linked to their list of fields through a "next
84e4b17023SJohn Marino    field" in each variable that points to the next field in offset
85e4b17023SJohn Marino    order.
86e4b17023SJohn Marino    Each variable for a structure field has
87e4b17023SJohn Marino 
88e4b17023SJohn Marino    1. "size", that tells the size in bits of that field.
89e4b17023SJohn Marino    2. "fullsize, that tells the size in bits of the entire structure.
90e4b17023SJohn Marino    3. "offset", that tells the offset in bits from the beginning of the
91e4b17023SJohn Marino    structure to this field.
92e4b17023SJohn Marino 
93e4b17023SJohn Marino    Thus,
94e4b17023SJohn Marino    struct f
95e4b17023SJohn Marino    {
96e4b17023SJohn Marino      int a;
97e4b17023SJohn Marino      int b;
98e4b17023SJohn Marino    } foo;
99e4b17023SJohn Marino    int *bar;
100e4b17023SJohn Marino 
101e4b17023SJohn Marino    looks like
102e4b17023SJohn Marino 
103e4b17023SJohn Marino    foo.a -> id 1, size 32, offset 0, fullsize 64, next foo.b
104e4b17023SJohn Marino    foo.b -> id 2, size 32, offset 32, fullsize 64, next NULL
105e4b17023SJohn Marino    bar -> id 3, size 32, offset 0, fullsize 32, next NULL
106e4b17023SJohn Marino 
107e4b17023SJohn Marino 
108e4b17023SJohn Marino   In order to solve the system of set constraints, the following is
109e4b17023SJohn Marino   done:
110e4b17023SJohn Marino 
111e4b17023SJohn Marino   1. Each constraint variable x has a solution set associated with it,
112e4b17023SJohn Marino   Sol(x).
113e4b17023SJohn Marino 
114e4b17023SJohn Marino   2. Constraints are separated into direct, copy, and complex.
115e4b17023SJohn Marino   Direct constraints are ADDRESSOF constraints that require no extra
116e4b17023SJohn Marino   processing, such as P = &Q
117e4b17023SJohn Marino   Copy constraints are those of the form P = Q.
118e4b17023SJohn Marino   Complex constraints are all the constraints involving dereferences
119e4b17023SJohn Marino   and offsets (including offsetted copies).
120e4b17023SJohn Marino 
121e4b17023SJohn Marino   3. All direct constraints of the form P = &Q are processed, such
122e4b17023SJohn Marino   that Q is added to Sol(P)
123e4b17023SJohn Marino 
124e4b17023SJohn Marino   4. All complex constraints for a given constraint variable are stored in a
125e4b17023SJohn Marino   linked list attached to that variable's node.
126e4b17023SJohn Marino 
127e4b17023SJohn Marino   5. A directed graph is built out of the copy constraints. Each
128e4b17023SJohn Marino   constraint variable is a node in the graph, and an edge from
129e4b17023SJohn Marino   Q to P is added for each copy constraint of the form P = Q
130e4b17023SJohn Marino 
131e4b17023SJohn Marino   6. The graph is then walked, and solution sets are
132e4b17023SJohn Marino   propagated along the copy edges, such that an edge from Q to P
133e4b17023SJohn Marino   causes Sol(P) <- Sol(P) union Sol(Q).
134e4b17023SJohn Marino 
135e4b17023SJohn Marino   7.  As we visit each node, all complex constraints associated with
136e4b17023SJohn Marino   that node are processed by adding appropriate copy edges to the graph, or the
137e4b17023SJohn Marino   appropriate variables to the solution set.
138e4b17023SJohn Marino 
139e4b17023SJohn Marino   8. The process of walking the graph is iterated until no solution
140e4b17023SJohn Marino   sets change.
141e4b17023SJohn Marino 
142e4b17023SJohn Marino   Prior to walking the graph in steps 6 and 7, We perform static
143e4b17023SJohn Marino   cycle elimination on the constraint graph, as well
144e4b17023SJohn Marino   as off-line variable substitution.
145e4b17023SJohn Marino 
146e4b17023SJohn Marino   TODO: Adding offsets to pointer-to-structures can be handled (IE not punted
147e4b17023SJohn Marino   on and turned into anything), but isn't.  You can just see what offset
148e4b17023SJohn Marino   inside the pointed-to struct it's going to access.
149e4b17023SJohn Marino 
150e4b17023SJohn Marino   TODO: Constant bounded arrays can be handled as if they were structs of the
151e4b17023SJohn Marino   same number of elements.
152e4b17023SJohn Marino 
153e4b17023SJohn Marino   TODO: Modeling heap and incoming pointers becomes much better if we
154e4b17023SJohn Marino   add fields to them as we discover them, which we could do.
155e4b17023SJohn Marino 
156e4b17023SJohn Marino   TODO: We could handle unions, but to be honest, it's probably not
157e4b17023SJohn Marino   worth the pain or slowdown.  */
158e4b17023SJohn Marino 
159e4b17023SJohn Marino /* IPA-PTA optimizations possible.
160e4b17023SJohn Marino 
161e4b17023SJohn Marino    When the indirect function called is ANYTHING we can add disambiguation
162e4b17023SJohn Marino    based on the function signatures (or simply the parameter count which
163e4b17023SJohn Marino    is the varinfo size).  We also do not need to consider functions that
164e4b17023SJohn Marino    do not have their address taken.
165e4b17023SJohn Marino 
166e4b17023SJohn Marino    The is_global_var bit which marks escape points is overly conservative
167e4b17023SJohn Marino    in IPA mode.  Split it to is_escape_point and is_global_var - only
168e4b17023SJohn Marino    externally visible globals are escape points in IPA mode.  This is
169e4b17023SJohn Marino    also needed to fix the pt_solution_includes_global predicate
170e4b17023SJohn Marino    (and thus ptr_deref_may_alias_global_p).
171e4b17023SJohn Marino 
172e4b17023SJohn Marino    The way we introduce DECL_PT_UID to avoid fixing up all points-to
173e4b17023SJohn Marino    sets in the translation unit when we copy a DECL during inlining
174e4b17023SJohn Marino    pessimizes precision.  The advantage is that the DECL_PT_UID keeps
175e4b17023SJohn Marino    compile-time and memory usage overhead low - the points-to sets
176e4b17023SJohn Marino    do not grow or get unshared as they would during a fixup phase.
177e4b17023SJohn Marino    An alternative solution is to delay IPA PTA until after all
178e4b17023SJohn Marino    inlining transformations have been applied.
179e4b17023SJohn Marino 
180e4b17023SJohn Marino    The way we propagate clobber/use information isn't optimized.
181e4b17023SJohn Marino    It should use a new complex constraint that properly filters
182e4b17023SJohn Marino    out local variables of the callee (though that would make
183e4b17023SJohn Marino    the sets invalid after inlining).  OTOH we might as well
184e4b17023SJohn Marino    admit defeat to WHOPR and simply do all the clobber/use analysis
185e4b17023SJohn Marino    and propagation after PTA finished but before we threw away
186e4b17023SJohn Marino    points-to information for memory variables.  WHOPR and PTA
187e4b17023SJohn Marino    do not play along well anyway - the whole constraint solving
188e4b17023SJohn Marino    would need to be done in WPA phase and it will be very interesting
189e4b17023SJohn Marino    to apply the results to local SSA names during LTRANS phase.
190e4b17023SJohn Marino 
191e4b17023SJohn Marino    We probably should compute a per-function unit-ESCAPE solution
192e4b17023SJohn Marino    propagating it simply like the clobber / uses solutions.  The
193e4b17023SJohn Marino    solution can go alongside the non-IPA espaced solution and be
194e4b17023SJohn Marino    used to query which vars escape the unit through a function.
195e4b17023SJohn Marino 
196e4b17023SJohn Marino    We never put function decls in points-to sets so we do not
197e4b17023SJohn Marino    keep the set of called functions for indirect calls.
198e4b17023SJohn Marino 
199e4b17023SJohn Marino    And probably more.  */
200e4b17023SJohn Marino 
201e4b17023SJohn Marino static bool use_field_sensitive = true;
202e4b17023SJohn Marino static int in_ipa_mode = 0;
203e4b17023SJohn Marino 
204e4b17023SJohn Marino /* Used for predecessor bitmaps. */
205e4b17023SJohn Marino static bitmap_obstack predbitmap_obstack;
206e4b17023SJohn Marino 
207e4b17023SJohn Marino /* Used for points-to sets.  */
208e4b17023SJohn Marino static bitmap_obstack pta_obstack;
209e4b17023SJohn Marino 
210e4b17023SJohn Marino /* Used for oldsolution members of variables. */
211e4b17023SJohn Marino static bitmap_obstack oldpta_obstack;
212e4b17023SJohn Marino 
213e4b17023SJohn Marino /* Used for per-solver-iteration bitmaps.  */
214e4b17023SJohn Marino static bitmap_obstack iteration_obstack;
215e4b17023SJohn Marino 
216e4b17023SJohn Marino static unsigned int create_variable_info_for (tree, const char *);
217e4b17023SJohn Marino typedef struct constraint_graph *constraint_graph_t;
218e4b17023SJohn Marino static void unify_nodes (constraint_graph_t, unsigned int, unsigned int, bool);
219e4b17023SJohn Marino 
220e4b17023SJohn Marino struct constraint;
221e4b17023SJohn Marino typedef struct constraint *constraint_t;
222e4b17023SJohn Marino 
223e4b17023SJohn Marino DEF_VEC_P(constraint_t);
224e4b17023SJohn Marino DEF_VEC_ALLOC_P(constraint_t,heap);
225e4b17023SJohn Marino 
226e4b17023SJohn Marino #define EXECUTE_IF_IN_NONNULL_BITMAP(a, b, c, d)	\
227e4b17023SJohn Marino   if (a)						\
228e4b17023SJohn Marino     EXECUTE_IF_SET_IN_BITMAP (a, b, c, d)
229e4b17023SJohn Marino 
230e4b17023SJohn Marino static struct constraint_stats
231e4b17023SJohn Marino {
232e4b17023SJohn Marino   unsigned int total_vars;
233e4b17023SJohn Marino   unsigned int nonpointer_vars;
234e4b17023SJohn Marino   unsigned int unified_vars_static;
235e4b17023SJohn Marino   unsigned int unified_vars_dynamic;
236e4b17023SJohn Marino   unsigned int iterations;
237e4b17023SJohn Marino   unsigned int num_edges;
238e4b17023SJohn Marino   unsigned int num_implicit_edges;
239e4b17023SJohn Marino   unsigned int points_to_sets_created;
240e4b17023SJohn Marino } stats;
241e4b17023SJohn Marino 
242e4b17023SJohn Marino struct variable_info
243e4b17023SJohn Marino {
244e4b17023SJohn Marino   /* ID of this variable  */
245e4b17023SJohn Marino   unsigned int id;
246e4b17023SJohn Marino 
247e4b17023SJohn Marino   /* True if this is a variable created by the constraint analysis, such as
248e4b17023SJohn Marino      heap variables and constraints we had to break up.  */
249e4b17023SJohn Marino   unsigned int is_artificial_var : 1;
250e4b17023SJohn Marino 
251e4b17023SJohn Marino   /* True if this is a special variable whose solution set should not be
252e4b17023SJohn Marino      changed.  */
253e4b17023SJohn Marino   unsigned int is_special_var : 1;
254e4b17023SJohn Marino 
255e4b17023SJohn Marino   /* True for variables whose size is not known or variable.  */
256e4b17023SJohn Marino   unsigned int is_unknown_size_var : 1;
257e4b17023SJohn Marino 
258e4b17023SJohn Marino   /* True for (sub-)fields that represent a whole variable.  */
259e4b17023SJohn Marino   unsigned int is_full_var : 1;
260e4b17023SJohn Marino 
261e4b17023SJohn Marino   /* True if this is a heap variable.  */
262e4b17023SJohn Marino   unsigned int is_heap_var : 1;
263e4b17023SJohn Marino 
264e4b17023SJohn Marino   /* True if this field may contain pointers.  */
265e4b17023SJohn Marino   unsigned int may_have_pointers : 1;
266e4b17023SJohn Marino 
267e4b17023SJohn Marino   /* True if this field has only restrict qualified pointers.  */
268e4b17023SJohn Marino   unsigned int only_restrict_pointers : 1;
269e4b17023SJohn Marino 
270e4b17023SJohn Marino   /* True if this represents a global variable.  */
271e4b17023SJohn Marino   unsigned int is_global_var : 1;
272e4b17023SJohn Marino 
273e4b17023SJohn Marino   /* True if this represents a IPA function info.  */
274e4b17023SJohn Marino   unsigned int is_fn_info : 1;
275e4b17023SJohn Marino 
276e4b17023SJohn Marino   /* A link to the variable for the next field in this structure.  */
277e4b17023SJohn Marino   struct variable_info *next;
278e4b17023SJohn Marino 
279e4b17023SJohn Marino   /* Offset of this variable, in bits, from the base variable  */
280e4b17023SJohn Marino   unsigned HOST_WIDE_INT offset;
281e4b17023SJohn Marino 
282e4b17023SJohn Marino   /* Size of the variable, in bits.  */
283e4b17023SJohn Marino   unsigned HOST_WIDE_INT size;
284e4b17023SJohn Marino 
285e4b17023SJohn Marino   /* Full size of the base variable, in bits.  */
286e4b17023SJohn Marino   unsigned HOST_WIDE_INT fullsize;
287e4b17023SJohn Marino 
288e4b17023SJohn Marino   /* Name of this variable */
289e4b17023SJohn Marino   const char *name;
290e4b17023SJohn Marino 
291e4b17023SJohn Marino   /* Tree that this variable is associated with.  */
292e4b17023SJohn Marino   tree decl;
293e4b17023SJohn Marino 
294e4b17023SJohn Marino   /* Points-to set for this variable.  */
295e4b17023SJohn Marino   bitmap solution;
296e4b17023SJohn Marino 
297e4b17023SJohn Marino   /* Old points-to set for this variable.  */
298e4b17023SJohn Marino   bitmap oldsolution;
299e4b17023SJohn Marino };
300e4b17023SJohn Marino typedef struct variable_info *varinfo_t;
301e4b17023SJohn Marino 
302e4b17023SJohn Marino static varinfo_t first_vi_for_offset (varinfo_t, unsigned HOST_WIDE_INT);
303e4b17023SJohn Marino static varinfo_t first_or_preceding_vi_for_offset (varinfo_t,
304e4b17023SJohn Marino 						   unsigned HOST_WIDE_INT);
305e4b17023SJohn Marino static varinfo_t lookup_vi_for_tree (tree);
306e4b17023SJohn Marino static inline bool type_can_have_subvars (const_tree);
307e4b17023SJohn Marino 
308e4b17023SJohn Marino /* Pool of variable info structures.  */
309e4b17023SJohn Marino static alloc_pool variable_info_pool;
310e4b17023SJohn Marino 
311e4b17023SJohn Marino DEF_VEC_P(varinfo_t);
312e4b17023SJohn Marino 
313e4b17023SJohn Marino DEF_VEC_ALLOC_P(varinfo_t, heap);
314e4b17023SJohn Marino 
315e4b17023SJohn Marino /* Table of variable info structures for constraint variables.
316e4b17023SJohn Marino    Indexed directly by variable info id.  */
VEC(varinfo_t,heap)317e4b17023SJohn Marino static VEC(varinfo_t,heap) *varmap;
318e4b17023SJohn Marino 
319e4b17023SJohn Marino /* Return the varmap element N */
320e4b17023SJohn Marino 
321e4b17023SJohn Marino static inline varinfo_t
322e4b17023SJohn Marino get_varinfo (unsigned int n)
323e4b17023SJohn Marino {
324e4b17023SJohn Marino   return VEC_index (varinfo_t, varmap, n);
325e4b17023SJohn Marino }
326e4b17023SJohn Marino 
327e4b17023SJohn Marino /* Static IDs for the special variables.  */
328e4b17023SJohn Marino enum { nothing_id = 0, anything_id = 1, readonly_id = 2,
329e4b17023SJohn Marino        escaped_id = 3, nonlocal_id = 4,
330e4b17023SJohn Marino        storedanything_id = 5, integer_id = 6 };
331e4b17023SJohn Marino 
332e4b17023SJohn Marino /* Return a new variable info structure consisting for a variable
333e4b17023SJohn Marino    named NAME, and using constraint graph node NODE.  Append it
334e4b17023SJohn Marino    to the vector of variable info structures.  */
335e4b17023SJohn Marino 
336e4b17023SJohn Marino static varinfo_t
new_var_info(tree t,const char * name)337e4b17023SJohn Marino new_var_info (tree t, const char *name)
338e4b17023SJohn Marino {
339e4b17023SJohn Marino   unsigned index = VEC_length (varinfo_t, varmap);
340e4b17023SJohn Marino   varinfo_t ret = (varinfo_t) pool_alloc (variable_info_pool);
341e4b17023SJohn Marino 
342e4b17023SJohn Marino   ret->id = index;
343e4b17023SJohn Marino   ret->name = name;
344e4b17023SJohn Marino   ret->decl = t;
345e4b17023SJohn Marino   /* Vars without decl are artificial and do not have sub-variables.  */
346e4b17023SJohn Marino   ret->is_artificial_var = (t == NULL_TREE);
347e4b17023SJohn Marino   ret->is_special_var = false;
348e4b17023SJohn Marino   ret->is_unknown_size_var = false;
349e4b17023SJohn Marino   ret->is_full_var = (t == NULL_TREE);
350e4b17023SJohn Marino   ret->is_heap_var = false;
351e4b17023SJohn Marino   ret->may_have_pointers = true;
352e4b17023SJohn Marino   ret->only_restrict_pointers = false;
353e4b17023SJohn Marino   ret->is_global_var = (t == NULL_TREE);
354e4b17023SJohn Marino   ret->is_fn_info = false;
355e4b17023SJohn Marino   if (t && DECL_P (t))
356e4b17023SJohn Marino     ret->is_global_var = (is_global_var (t)
357e4b17023SJohn Marino 			  /* We have to treat even local register variables
358e4b17023SJohn Marino 			     as escape points.  */
359e4b17023SJohn Marino 			  || (TREE_CODE (t) == VAR_DECL
360e4b17023SJohn Marino 			      && DECL_HARD_REGISTER (t)));
361e4b17023SJohn Marino   ret->solution = BITMAP_ALLOC (&pta_obstack);
362e4b17023SJohn Marino   ret->oldsolution = NULL;
363e4b17023SJohn Marino   ret->next = NULL;
364e4b17023SJohn Marino 
365e4b17023SJohn Marino   stats.total_vars++;
366e4b17023SJohn Marino 
367e4b17023SJohn Marino   VEC_safe_push (varinfo_t, heap, varmap, ret);
368e4b17023SJohn Marino 
369e4b17023SJohn Marino   return ret;
370e4b17023SJohn Marino }
371e4b17023SJohn Marino 
372e4b17023SJohn Marino 
373e4b17023SJohn Marino /* A map mapping call statements to per-stmt variables for uses
374e4b17023SJohn Marino    and clobbers specific to the call.  */
375e4b17023SJohn Marino struct pointer_map_t *call_stmt_vars;
376e4b17023SJohn Marino 
377e4b17023SJohn Marino /* Lookup or create the variable for the call statement CALL.  */
378e4b17023SJohn Marino 
379e4b17023SJohn Marino static varinfo_t
get_call_vi(gimple call)380e4b17023SJohn Marino get_call_vi (gimple call)
381e4b17023SJohn Marino {
382e4b17023SJohn Marino   void **slot_p;
383e4b17023SJohn Marino   varinfo_t vi, vi2;
384e4b17023SJohn Marino 
385e4b17023SJohn Marino   slot_p = pointer_map_insert (call_stmt_vars, call);
386e4b17023SJohn Marino   if (*slot_p)
387e4b17023SJohn Marino     return (varinfo_t) *slot_p;
388e4b17023SJohn Marino 
389e4b17023SJohn Marino   vi = new_var_info (NULL_TREE, "CALLUSED");
390e4b17023SJohn Marino   vi->offset = 0;
391e4b17023SJohn Marino   vi->size = 1;
392e4b17023SJohn Marino   vi->fullsize = 2;
393e4b17023SJohn Marino   vi->is_full_var = true;
394e4b17023SJohn Marino 
395e4b17023SJohn Marino   vi->next = vi2 = new_var_info (NULL_TREE, "CALLCLOBBERED");
396e4b17023SJohn Marino   vi2->offset = 1;
397e4b17023SJohn Marino   vi2->size = 1;
398e4b17023SJohn Marino   vi2->fullsize = 2;
399e4b17023SJohn Marino   vi2->is_full_var = true;
400e4b17023SJohn Marino 
401e4b17023SJohn Marino   *slot_p = (void *) vi;
402e4b17023SJohn Marino   return vi;
403e4b17023SJohn Marino }
404e4b17023SJohn Marino 
405e4b17023SJohn Marino /* Lookup the variable for the call statement CALL representing
406e4b17023SJohn Marino    the uses.  Returns NULL if there is nothing special about this call.  */
407e4b17023SJohn Marino 
408e4b17023SJohn Marino static varinfo_t
lookup_call_use_vi(gimple call)409e4b17023SJohn Marino lookup_call_use_vi (gimple call)
410e4b17023SJohn Marino {
411e4b17023SJohn Marino   void **slot_p;
412e4b17023SJohn Marino 
413e4b17023SJohn Marino   slot_p = pointer_map_contains (call_stmt_vars, call);
414e4b17023SJohn Marino   if (slot_p)
415e4b17023SJohn Marino     return (varinfo_t) *slot_p;
416e4b17023SJohn Marino 
417e4b17023SJohn Marino   return NULL;
418e4b17023SJohn Marino }
419e4b17023SJohn Marino 
420e4b17023SJohn Marino /* Lookup the variable for the call statement CALL representing
421e4b17023SJohn Marino    the clobbers.  Returns NULL if there is nothing special about this call.  */
422e4b17023SJohn Marino 
423e4b17023SJohn Marino static varinfo_t
lookup_call_clobber_vi(gimple call)424e4b17023SJohn Marino lookup_call_clobber_vi (gimple call)
425e4b17023SJohn Marino {
426e4b17023SJohn Marino   varinfo_t uses = lookup_call_use_vi (call);
427e4b17023SJohn Marino   if (!uses)
428e4b17023SJohn Marino     return NULL;
429e4b17023SJohn Marino 
430e4b17023SJohn Marino   return uses->next;
431e4b17023SJohn Marino }
432e4b17023SJohn Marino 
433e4b17023SJohn Marino /* Lookup or create the variable for the call statement CALL representing
434e4b17023SJohn Marino    the uses.  */
435e4b17023SJohn Marino 
436e4b17023SJohn Marino static varinfo_t
get_call_use_vi(gimple call)437e4b17023SJohn Marino get_call_use_vi (gimple call)
438e4b17023SJohn Marino {
439e4b17023SJohn Marino   return get_call_vi (call);
440e4b17023SJohn Marino }
441e4b17023SJohn Marino 
442e4b17023SJohn Marino /* Lookup or create the variable for the call statement CALL representing
443e4b17023SJohn Marino    the clobbers.  */
444e4b17023SJohn Marino 
445e4b17023SJohn Marino static varinfo_t ATTRIBUTE_UNUSED
get_call_clobber_vi(gimple call)446e4b17023SJohn Marino get_call_clobber_vi (gimple call)
447e4b17023SJohn Marino {
448e4b17023SJohn Marino   return get_call_vi (call)->next;
449e4b17023SJohn Marino }
450e4b17023SJohn Marino 
451e4b17023SJohn Marino 
452e4b17023SJohn Marino typedef enum {SCALAR, DEREF, ADDRESSOF} constraint_expr_type;
453e4b17023SJohn Marino 
454e4b17023SJohn Marino /* An expression that appears in a constraint.  */
455e4b17023SJohn Marino 
456e4b17023SJohn Marino struct constraint_expr
457e4b17023SJohn Marino {
458e4b17023SJohn Marino   /* Constraint type.  */
459e4b17023SJohn Marino   constraint_expr_type type;
460e4b17023SJohn Marino 
461e4b17023SJohn Marino   /* Variable we are referring to in the constraint.  */
462e4b17023SJohn Marino   unsigned int var;
463e4b17023SJohn Marino 
464e4b17023SJohn Marino   /* Offset, in bits, of this constraint from the beginning of
465e4b17023SJohn Marino      variables it ends up referring to.
466e4b17023SJohn Marino 
467e4b17023SJohn Marino      IOW, in a deref constraint, we would deref, get the result set,
468e4b17023SJohn Marino      then add OFFSET to each member.   */
469e4b17023SJohn Marino   HOST_WIDE_INT offset;
470e4b17023SJohn Marino };
471e4b17023SJohn Marino 
472e4b17023SJohn Marino /* Use 0x8000... as special unknown offset.  */
473e4b17023SJohn Marino #define UNKNOWN_OFFSET ((HOST_WIDE_INT)-1 << (HOST_BITS_PER_WIDE_INT-1))
474e4b17023SJohn Marino 
475e4b17023SJohn Marino typedef struct constraint_expr ce_s;
476e4b17023SJohn Marino DEF_VEC_O(ce_s);
477e4b17023SJohn Marino DEF_VEC_ALLOC_O(ce_s, heap);
478e4b17023SJohn Marino static void get_constraint_for_1 (tree, VEC(ce_s, heap) **, bool, bool);
479e4b17023SJohn Marino static void get_constraint_for (tree, VEC(ce_s, heap) **);
480e4b17023SJohn Marino static void get_constraint_for_rhs (tree, VEC(ce_s, heap) **);
481e4b17023SJohn Marino static void do_deref (VEC (ce_s, heap) **);
482e4b17023SJohn Marino 
483e4b17023SJohn Marino /* Our set constraints are made up of two constraint expressions, one
484e4b17023SJohn Marino    LHS, and one RHS.
485e4b17023SJohn Marino 
486e4b17023SJohn Marino    As described in the introduction, our set constraints each represent an
487e4b17023SJohn Marino    operation between set valued variables.
488e4b17023SJohn Marino */
489e4b17023SJohn Marino struct constraint
490e4b17023SJohn Marino {
491e4b17023SJohn Marino   struct constraint_expr lhs;
492e4b17023SJohn Marino   struct constraint_expr rhs;
493e4b17023SJohn Marino };
494e4b17023SJohn Marino 
495e4b17023SJohn Marino /* List of constraints that we use to build the constraint graph from.  */
496e4b17023SJohn Marino 
VEC(constraint_t,heap)497e4b17023SJohn Marino static VEC(constraint_t,heap) *constraints;
498e4b17023SJohn Marino static alloc_pool constraint_pool;
499e4b17023SJohn Marino 
500e4b17023SJohn Marino /* The constraint graph is represented as an array of bitmaps
501e4b17023SJohn Marino    containing successor nodes.  */
502e4b17023SJohn Marino 
503e4b17023SJohn Marino struct constraint_graph
504e4b17023SJohn Marino {
505e4b17023SJohn Marino   /* Size of this graph, which may be different than the number of
506e4b17023SJohn Marino      nodes in the variable map.  */
507e4b17023SJohn Marino   unsigned int size;
508e4b17023SJohn Marino 
509e4b17023SJohn Marino   /* Explicit successors of each node. */
510e4b17023SJohn Marino   bitmap *succs;
511e4b17023SJohn Marino 
512e4b17023SJohn Marino   /* Implicit predecessors of each node (Used for variable
513e4b17023SJohn Marino      substitution). */
514e4b17023SJohn Marino   bitmap *implicit_preds;
515e4b17023SJohn Marino 
516e4b17023SJohn Marino   /* Explicit predecessors of each node (Used for variable substitution).  */
517e4b17023SJohn Marino   bitmap *preds;
518e4b17023SJohn Marino 
519e4b17023SJohn Marino   /* Indirect cycle representatives, or -1 if the node has no indirect
520e4b17023SJohn Marino      cycles.  */
521e4b17023SJohn Marino   int *indirect_cycles;
522e4b17023SJohn Marino 
523e4b17023SJohn Marino   /* Representative node for a node.  rep[a] == a unless the node has
524e4b17023SJohn Marino      been unified. */
525e4b17023SJohn Marino   unsigned int *rep;
526e4b17023SJohn Marino 
527e4b17023SJohn Marino   /* Equivalence class representative for a label.  This is used for
528e4b17023SJohn Marino      variable substitution.  */
529e4b17023SJohn Marino   int *eq_rep;
530e4b17023SJohn Marino 
531e4b17023SJohn Marino   /* Pointer equivalence label for a node.  All nodes with the same
532e4b17023SJohn Marino      pointer equivalence label can be unified together at some point
533e4b17023SJohn Marino      (either during constraint optimization or after the constraint
534e4b17023SJohn Marino      graph is built).  */
535e4b17023SJohn Marino   unsigned int *pe;
536e4b17023SJohn Marino 
537e4b17023SJohn Marino   /* Pointer equivalence representative for a label.  This is used to
538e4b17023SJohn Marino      handle nodes that are pointer equivalent but not location
539e4b17023SJohn Marino      equivalent.  We can unite these once the addressof constraints
540e4b17023SJohn Marino      are transformed into initial points-to sets.  */
541e4b17023SJohn Marino   int *pe_rep;
542e4b17023SJohn Marino 
543e4b17023SJohn Marino   /* Pointer equivalence label for each node, used during variable
544e4b17023SJohn Marino      substitution.  */
545e4b17023SJohn Marino   unsigned int *pointer_label;
546e4b17023SJohn Marino 
547e4b17023SJohn Marino   /* Location equivalence label for each node, used during location
548e4b17023SJohn Marino      equivalence finding.  */
549e4b17023SJohn Marino   unsigned int *loc_label;
550e4b17023SJohn Marino 
551e4b17023SJohn Marino   /* Pointed-by set for each node, used during location equivalence
552e4b17023SJohn Marino      finding.  This is pointed-by rather than pointed-to, because it
553e4b17023SJohn Marino      is constructed using the predecessor graph.  */
554e4b17023SJohn Marino   bitmap *pointed_by;
555e4b17023SJohn Marino 
556e4b17023SJohn Marino   /* Points to sets for pointer equivalence.  This is *not* the actual
557e4b17023SJohn Marino      points-to sets for nodes.  */
558e4b17023SJohn Marino   bitmap *points_to;
559e4b17023SJohn Marino 
560e4b17023SJohn Marino   /* Bitmap of nodes where the bit is set if the node is a direct
561e4b17023SJohn Marino      node.  Used for variable substitution.  */
562e4b17023SJohn Marino   sbitmap direct_nodes;
563e4b17023SJohn Marino 
564e4b17023SJohn Marino   /* Bitmap of nodes where the bit is set if the node is address
565e4b17023SJohn Marino      taken.  Used for variable substitution.  */
566e4b17023SJohn Marino   bitmap address_taken;
567e4b17023SJohn Marino 
568e4b17023SJohn Marino   /* Vector of complex constraints for each graph node.  Complex
569e4b17023SJohn Marino      constraints are those involving dereferences or offsets that are
570e4b17023SJohn Marino      not 0.  */
571e4b17023SJohn Marino   VEC(constraint_t,heap) **complex;
572e4b17023SJohn Marino };
573e4b17023SJohn Marino 
574e4b17023SJohn Marino static constraint_graph_t graph;
575e4b17023SJohn Marino 
576e4b17023SJohn Marino /* During variable substitution and the offline version of indirect
577e4b17023SJohn Marino    cycle finding, we create nodes to represent dereferences and
578e4b17023SJohn Marino    address taken constraints.  These represent where these start and
579e4b17023SJohn Marino    end.  */
580e4b17023SJohn Marino #define FIRST_REF_NODE (VEC_length (varinfo_t, varmap))
581e4b17023SJohn Marino #define LAST_REF_NODE (FIRST_REF_NODE + (FIRST_REF_NODE - 1))
582e4b17023SJohn Marino 
583e4b17023SJohn Marino /* Return the representative node for NODE, if NODE has been unioned
584e4b17023SJohn Marino    with another NODE.
585e4b17023SJohn Marino    This function performs path compression along the way to finding
586e4b17023SJohn Marino    the representative.  */
587e4b17023SJohn Marino 
588e4b17023SJohn Marino static unsigned int
find(unsigned int node)589e4b17023SJohn Marino find (unsigned int node)
590e4b17023SJohn Marino {
591e4b17023SJohn Marino   gcc_assert (node < graph->size);
592e4b17023SJohn Marino   if (graph->rep[node] != node)
593e4b17023SJohn Marino     return graph->rep[node] = find (graph->rep[node]);
594e4b17023SJohn Marino   return node;
595e4b17023SJohn Marino }
596e4b17023SJohn Marino 
597e4b17023SJohn Marino /* Union the TO and FROM nodes to the TO nodes.
598e4b17023SJohn Marino    Note that at some point in the future, we may want to do
599e4b17023SJohn Marino    union-by-rank, in which case we are going to have to return the
600e4b17023SJohn Marino    node we unified to.  */
601e4b17023SJohn Marino 
602e4b17023SJohn Marino static bool
unite(unsigned int to,unsigned int from)603e4b17023SJohn Marino unite (unsigned int to, unsigned int from)
604e4b17023SJohn Marino {
605e4b17023SJohn Marino   gcc_assert (to < graph->size && from < graph->size);
606e4b17023SJohn Marino   if (to != from && graph->rep[from] != to)
607e4b17023SJohn Marino     {
608e4b17023SJohn Marino       graph->rep[from] = to;
609e4b17023SJohn Marino       return true;
610e4b17023SJohn Marino     }
611e4b17023SJohn Marino   return false;
612e4b17023SJohn Marino }
613e4b17023SJohn Marino 
614e4b17023SJohn Marino /* Create a new constraint consisting of LHS and RHS expressions.  */
615e4b17023SJohn Marino 
616e4b17023SJohn Marino static constraint_t
new_constraint(const struct constraint_expr lhs,const struct constraint_expr rhs)617e4b17023SJohn Marino new_constraint (const struct constraint_expr lhs,
618e4b17023SJohn Marino 		const struct constraint_expr rhs)
619e4b17023SJohn Marino {
620e4b17023SJohn Marino   constraint_t ret = (constraint_t) pool_alloc (constraint_pool);
621e4b17023SJohn Marino   ret->lhs = lhs;
622e4b17023SJohn Marino   ret->rhs = rhs;
623e4b17023SJohn Marino   return ret;
624e4b17023SJohn Marino }
625e4b17023SJohn Marino 
626e4b17023SJohn Marino /* Print out constraint C to FILE.  */
627e4b17023SJohn Marino 
628e4b17023SJohn Marino static void
dump_constraint(FILE * file,constraint_t c)629e4b17023SJohn Marino dump_constraint (FILE *file, constraint_t c)
630e4b17023SJohn Marino {
631e4b17023SJohn Marino   if (c->lhs.type == ADDRESSOF)
632e4b17023SJohn Marino     fprintf (file, "&");
633e4b17023SJohn Marino   else if (c->lhs.type == DEREF)
634e4b17023SJohn Marino     fprintf (file, "*");
635e4b17023SJohn Marino   fprintf (file, "%s", get_varinfo (c->lhs.var)->name);
636e4b17023SJohn Marino   if (c->lhs.offset == UNKNOWN_OFFSET)
637e4b17023SJohn Marino     fprintf (file, " + UNKNOWN");
638e4b17023SJohn Marino   else if (c->lhs.offset != 0)
639e4b17023SJohn Marino     fprintf (file, " + " HOST_WIDE_INT_PRINT_DEC, c->lhs.offset);
640e4b17023SJohn Marino   fprintf (file, " = ");
641e4b17023SJohn Marino   if (c->rhs.type == ADDRESSOF)
642e4b17023SJohn Marino     fprintf (file, "&");
643e4b17023SJohn Marino   else if (c->rhs.type == DEREF)
644e4b17023SJohn Marino     fprintf (file, "*");
645e4b17023SJohn Marino   fprintf (file, "%s", get_varinfo (c->rhs.var)->name);
646e4b17023SJohn Marino   if (c->rhs.offset == UNKNOWN_OFFSET)
647e4b17023SJohn Marino     fprintf (file, " + UNKNOWN");
648e4b17023SJohn Marino   else if (c->rhs.offset != 0)
649e4b17023SJohn Marino     fprintf (file, " + " HOST_WIDE_INT_PRINT_DEC, c->rhs.offset);
650e4b17023SJohn Marino }
651e4b17023SJohn Marino 
652e4b17023SJohn Marino 
653e4b17023SJohn Marino void debug_constraint (constraint_t);
654e4b17023SJohn Marino void debug_constraints (void);
655e4b17023SJohn Marino void debug_constraint_graph (void);
656e4b17023SJohn Marino void debug_solution_for_var (unsigned int);
657e4b17023SJohn Marino void debug_sa_points_to_info (void);
658e4b17023SJohn Marino 
659e4b17023SJohn Marino /* Print out constraint C to stderr.  */
660e4b17023SJohn Marino 
661e4b17023SJohn Marino DEBUG_FUNCTION void
debug_constraint(constraint_t c)662e4b17023SJohn Marino debug_constraint (constraint_t c)
663e4b17023SJohn Marino {
664e4b17023SJohn Marino   dump_constraint (stderr, c);
665e4b17023SJohn Marino   fprintf (stderr, "\n");
666e4b17023SJohn Marino }
667e4b17023SJohn Marino 
668e4b17023SJohn Marino /* Print out all constraints to FILE */
669e4b17023SJohn Marino 
670e4b17023SJohn Marino static void
dump_constraints(FILE * file,int from)671e4b17023SJohn Marino dump_constraints (FILE *file, int from)
672e4b17023SJohn Marino {
673e4b17023SJohn Marino   int i;
674e4b17023SJohn Marino   constraint_t c;
675e4b17023SJohn Marino   for (i = from; VEC_iterate (constraint_t, constraints, i, c); i++)
676e4b17023SJohn Marino     if (c)
677e4b17023SJohn Marino       {
678e4b17023SJohn Marino 	dump_constraint (file, c);
679e4b17023SJohn Marino 	fprintf (file, "\n");
680e4b17023SJohn Marino       }
681e4b17023SJohn Marino }
682e4b17023SJohn Marino 
683e4b17023SJohn Marino /* Print out all constraints to stderr.  */
684e4b17023SJohn Marino 
685e4b17023SJohn Marino DEBUG_FUNCTION void
debug_constraints(void)686e4b17023SJohn Marino debug_constraints (void)
687e4b17023SJohn Marino {
688e4b17023SJohn Marino   dump_constraints (stderr, 0);
689e4b17023SJohn Marino }
690e4b17023SJohn Marino 
691e4b17023SJohn Marino /* Print the constraint graph in dot format.  */
692e4b17023SJohn Marino 
693e4b17023SJohn Marino static void
dump_constraint_graph(FILE * file)694e4b17023SJohn Marino dump_constraint_graph (FILE *file)
695e4b17023SJohn Marino {
696e4b17023SJohn Marino   unsigned int i;
697e4b17023SJohn Marino 
698e4b17023SJohn Marino   /* Only print the graph if it has already been initialized:  */
699e4b17023SJohn Marino   if (!graph)
700e4b17023SJohn Marino     return;
701e4b17023SJohn Marino 
702e4b17023SJohn Marino   /* Prints the header of the dot file:  */
703e4b17023SJohn Marino   fprintf (file, "strict digraph {\n");
704e4b17023SJohn Marino   fprintf (file, "  node [\n    shape = box\n  ]\n");
705e4b17023SJohn Marino   fprintf (file, "  edge [\n    fontsize = \"12\"\n  ]\n");
706e4b17023SJohn Marino   fprintf (file, "\n  // List of nodes and complex constraints in "
707e4b17023SJohn Marino 	   "the constraint graph:\n");
708e4b17023SJohn Marino 
709e4b17023SJohn Marino   /* The next lines print the nodes in the graph together with the
710e4b17023SJohn Marino      complex constraints attached to them.  */
711e4b17023SJohn Marino   for (i = 0; i < graph->size; i++)
712e4b17023SJohn Marino     {
713e4b17023SJohn Marino       if (find (i) != i)
714e4b17023SJohn Marino 	continue;
715e4b17023SJohn Marino       if (i < FIRST_REF_NODE)
716e4b17023SJohn Marino 	fprintf (file, "\"%s\"", get_varinfo (i)->name);
717e4b17023SJohn Marino       else
718e4b17023SJohn Marino 	fprintf (file, "\"*%s\"", get_varinfo (i - FIRST_REF_NODE)->name);
719e4b17023SJohn Marino       if (graph->complex[i])
720e4b17023SJohn Marino 	{
721e4b17023SJohn Marino 	  unsigned j;
722e4b17023SJohn Marino 	  constraint_t c;
723e4b17023SJohn Marino 	  fprintf (file, " [label=\"\\N\\n");
724e4b17023SJohn Marino 	  for (j = 0; VEC_iterate (constraint_t, graph->complex[i], j, c); ++j)
725e4b17023SJohn Marino 	    {
726e4b17023SJohn Marino 	      dump_constraint (file, c);
727e4b17023SJohn Marino 	      fprintf (file, "\\l");
728e4b17023SJohn Marino 	    }
729e4b17023SJohn Marino 	  fprintf (file, "\"]");
730e4b17023SJohn Marino 	}
731e4b17023SJohn Marino       fprintf (file, ";\n");
732e4b17023SJohn Marino     }
733e4b17023SJohn Marino 
734e4b17023SJohn Marino   /* Go over the edges.  */
735e4b17023SJohn Marino   fprintf (file, "\n  // Edges in the constraint graph:\n");
736e4b17023SJohn Marino   for (i = 0; i < graph->size; i++)
737e4b17023SJohn Marino     {
738e4b17023SJohn Marino       unsigned j;
739e4b17023SJohn Marino       bitmap_iterator bi;
740e4b17023SJohn Marino       if (find (i) != i)
741e4b17023SJohn Marino 	continue;
742e4b17023SJohn Marino       EXECUTE_IF_IN_NONNULL_BITMAP (graph->succs[i], 0, j, bi)
743e4b17023SJohn Marino 	{
744e4b17023SJohn Marino 	  unsigned to = find (j);
745e4b17023SJohn Marino 	  if (i == to)
746e4b17023SJohn Marino 	    continue;
747e4b17023SJohn Marino 	  if (i < FIRST_REF_NODE)
748e4b17023SJohn Marino 	    fprintf (file, "\"%s\"", get_varinfo (i)->name);
749e4b17023SJohn Marino 	  else
750e4b17023SJohn Marino 	    fprintf (file, "\"*%s\"", get_varinfo (i - FIRST_REF_NODE)->name);
751e4b17023SJohn Marino 	  fprintf (file, " -> ");
752e4b17023SJohn Marino 	  if (to < FIRST_REF_NODE)
753e4b17023SJohn Marino 	    fprintf (file, "\"%s\"", get_varinfo (to)->name);
754e4b17023SJohn Marino 	  else
755e4b17023SJohn Marino 	    fprintf (file, "\"*%s\"", get_varinfo (to - FIRST_REF_NODE)->name);
756e4b17023SJohn Marino 	  fprintf (file, ";\n");
757e4b17023SJohn Marino 	}
758e4b17023SJohn Marino     }
759e4b17023SJohn Marino 
760e4b17023SJohn Marino   /* Prints the tail of the dot file.  */
761e4b17023SJohn Marino   fprintf (file, "}\n");
762e4b17023SJohn Marino }
763e4b17023SJohn Marino 
764e4b17023SJohn Marino /* Print out the constraint graph to stderr.  */
765e4b17023SJohn Marino 
766e4b17023SJohn Marino DEBUG_FUNCTION void
debug_constraint_graph(void)767e4b17023SJohn Marino debug_constraint_graph (void)
768e4b17023SJohn Marino {
769e4b17023SJohn Marino   dump_constraint_graph (stderr);
770e4b17023SJohn Marino }
771e4b17023SJohn Marino 
772e4b17023SJohn Marino /* SOLVER FUNCTIONS
773e4b17023SJohn Marino 
774e4b17023SJohn Marino    The solver is a simple worklist solver, that works on the following
775e4b17023SJohn Marino    algorithm:
776e4b17023SJohn Marino 
777e4b17023SJohn Marino    sbitmap changed_nodes = all zeroes;
778e4b17023SJohn Marino    changed_count = 0;
779e4b17023SJohn Marino    For each node that is not already collapsed:
780e4b17023SJohn Marino        changed_count++;
781e4b17023SJohn Marino        set bit in changed nodes
782e4b17023SJohn Marino 
783e4b17023SJohn Marino    while (changed_count > 0)
784e4b17023SJohn Marino    {
785e4b17023SJohn Marino      compute topological ordering for constraint graph
786e4b17023SJohn Marino 
787e4b17023SJohn Marino      find and collapse cycles in the constraint graph (updating
788e4b17023SJohn Marino      changed if necessary)
789e4b17023SJohn Marino 
790e4b17023SJohn Marino      for each node (n) in the graph in topological order:
791e4b17023SJohn Marino        changed_count--;
792e4b17023SJohn Marino 
793e4b17023SJohn Marino        Process each complex constraint associated with the node,
794e4b17023SJohn Marino        updating changed if necessary.
795e4b17023SJohn Marino 
796e4b17023SJohn Marino        For each outgoing edge from n, propagate the solution from n to
797e4b17023SJohn Marino        the destination of the edge, updating changed as necessary.
798e4b17023SJohn Marino 
799e4b17023SJohn Marino    }  */
800e4b17023SJohn Marino 
801e4b17023SJohn Marino /* Return true if two constraint expressions A and B are equal.  */
802e4b17023SJohn Marino 
803e4b17023SJohn Marino static bool
constraint_expr_equal(struct constraint_expr a,struct constraint_expr b)804e4b17023SJohn Marino constraint_expr_equal (struct constraint_expr a, struct constraint_expr b)
805e4b17023SJohn Marino {
806e4b17023SJohn Marino   return a.type == b.type && a.var == b.var && a.offset == b.offset;
807e4b17023SJohn Marino }
808e4b17023SJohn Marino 
809e4b17023SJohn Marino /* Return true if constraint expression A is less than constraint expression
810e4b17023SJohn Marino    B.  This is just arbitrary, but consistent, in order to give them an
811e4b17023SJohn Marino    ordering.  */
812e4b17023SJohn Marino 
813e4b17023SJohn Marino static bool
constraint_expr_less(struct constraint_expr a,struct constraint_expr b)814e4b17023SJohn Marino constraint_expr_less (struct constraint_expr a, struct constraint_expr b)
815e4b17023SJohn Marino {
816e4b17023SJohn Marino   if (a.type == b.type)
817e4b17023SJohn Marino     {
818e4b17023SJohn Marino       if (a.var == b.var)
819e4b17023SJohn Marino 	return a.offset < b.offset;
820e4b17023SJohn Marino       else
821e4b17023SJohn Marino 	return a.var < b.var;
822e4b17023SJohn Marino     }
823e4b17023SJohn Marino   else
824e4b17023SJohn Marino     return a.type < b.type;
825e4b17023SJohn Marino }
826e4b17023SJohn Marino 
827e4b17023SJohn Marino /* Return true if constraint A is less than constraint B.  This is just
828e4b17023SJohn Marino    arbitrary, but consistent, in order to give them an ordering.  */
829e4b17023SJohn Marino 
830e4b17023SJohn Marino static bool
constraint_less(const constraint_t a,const constraint_t b)831e4b17023SJohn Marino constraint_less (const constraint_t a, const constraint_t b)
832e4b17023SJohn Marino {
833e4b17023SJohn Marino   if (constraint_expr_less (a->lhs, b->lhs))
834e4b17023SJohn Marino     return true;
835e4b17023SJohn Marino   else if (constraint_expr_less (b->lhs, a->lhs))
836e4b17023SJohn Marino     return false;
837e4b17023SJohn Marino   else
838e4b17023SJohn Marino     return constraint_expr_less (a->rhs, b->rhs);
839e4b17023SJohn Marino }
840e4b17023SJohn Marino 
841e4b17023SJohn Marino /* Return true if two constraints A and B are equal.  */
842e4b17023SJohn Marino 
843e4b17023SJohn Marino static bool
constraint_equal(struct constraint a,struct constraint b)844e4b17023SJohn Marino constraint_equal (struct constraint a, struct constraint b)
845e4b17023SJohn Marino {
846e4b17023SJohn Marino   return constraint_expr_equal (a.lhs, b.lhs)
847e4b17023SJohn Marino     && constraint_expr_equal (a.rhs, b.rhs);
848e4b17023SJohn Marino }
849e4b17023SJohn Marino 
850e4b17023SJohn Marino 
851e4b17023SJohn Marino /* Find a constraint LOOKFOR in the sorted constraint vector VEC */
852e4b17023SJohn Marino 
853e4b17023SJohn Marino static constraint_t
constraint_vec_find(VEC (constraint_t,heap)* vec,struct constraint lookfor)854e4b17023SJohn Marino constraint_vec_find (VEC(constraint_t,heap) *vec,
855e4b17023SJohn Marino 		     struct constraint lookfor)
856e4b17023SJohn Marino {
857e4b17023SJohn Marino   unsigned int place;
858e4b17023SJohn Marino   constraint_t found;
859e4b17023SJohn Marino 
860e4b17023SJohn Marino   if (vec == NULL)
861e4b17023SJohn Marino     return NULL;
862e4b17023SJohn Marino 
863e4b17023SJohn Marino   place = VEC_lower_bound (constraint_t, vec, &lookfor, constraint_less);
864e4b17023SJohn Marino   if (place >= VEC_length (constraint_t, vec))
865e4b17023SJohn Marino     return NULL;
866e4b17023SJohn Marino   found = VEC_index (constraint_t, vec, place);
867e4b17023SJohn Marino   if (!constraint_equal (*found, lookfor))
868e4b17023SJohn Marino     return NULL;
869e4b17023SJohn Marino   return found;
870e4b17023SJohn Marino }
871e4b17023SJohn Marino 
872e4b17023SJohn Marino /* Union two constraint vectors, TO and FROM.  Put the result in TO.  */
873e4b17023SJohn Marino 
874e4b17023SJohn Marino static void
constraint_set_union(VEC (constraint_t,heap)** to,VEC (constraint_t,heap)** from)875e4b17023SJohn Marino constraint_set_union (VEC(constraint_t,heap) **to,
876e4b17023SJohn Marino 		      VEC(constraint_t,heap) **from)
877e4b17023SJohn Marino {
878e4b17023SJohn Marino   int i;
879e4b17023SJohn Marino   constraint_t c;
880e4b17023SJohn Marino 
881e4b17023SJohn Marino   FOR_EACH_VEC_ELT (constraint_t, *from, i, c)
882e4b17023SJohn Marino     {
883e4b17023SJohn Marino       if (constraint_vec_find (*to, *c) == NULL)
884e4b17023SJohn Marino 	{
885e4b17023SJohn Marino 	  unsigned int place = VEC_lower_bound (constraint_t, *to, c,
886e4b17023SJohn Marino 						constraint_less);
887e4b17023SJohn Marino 	  VEC_safe_insert (constraint_t, heap, *to, place, c);
888e4b17023SJohn Marino 	}
889e4b17023SJohn Marino     }
890e4b17023SJohn Marino }
891e4b17023SJohn Marino 
892e4b17023SJohn Marino /* Expands the solution in SET to all sub-fields of variables included.
893e4b17023SJohn Marino    Union the expanded result into RESULT.  */
894e4b17023SJohn Marino 
895e4b17023SJohn Marino static void
solution_set_expand(bitmap result,bitmap set)896e4b17023SJohn Marino solution_set_expand (bitmap result, bitmap set)
897e4b17023SJohn Marino {
898e4b17023SJohn Marino   bitmap_iterator bi;
899e4b17023SJohn Marino   bitmap vars = NULL;
900e4b17023SJohn Marino   unsigned j;
901e4b17023SJohn Marino 
902e4b17023SJohn Marino   /* In a first pass record all variables we need to add all
903e4b17023SJohn Marino      sub-fields off.  This avoids quadratic behavior.  */
904e4b17023SJohn Marino   EXECUTE_IF_SET_IN_BITMAP (set, 0, j, bi)
905e4b17023SJohn Marino     {
906e4b17023SJohn Marino       varinfo_t v = get_varinfo (j);
907e4b17023SJohn Marino       if (v->is_artificial_var
908e4b17023SJohn Marino 	  || v->is_full_var)
909e4b17023SJohn Marino 	continue;
910e4b17023SJohn Marino       v = lookup_vi_for_tree (v->decl);
911e4b17023SJohn Marino       if (vars == NULL)
912e4b17023SJohn Marino 	vars = BITMAP_ALLOC (NULL);
913e4b17023SJohn Marino       bitmap_set_bit (vars, v->id);
914e4b17023SJohn Marino     }
915e4b17023SJohn Marino 
916e4b17023SJohn Marino   /* In the second pass now do the addition to the solution and
917e4b17023SJohn Marino      to speed up solving add it to the delta as well.  */
918e4b17023SJohn Marino   if (vars != NULL)
919e4b17023SJohn Marino     {
920e4b17023SJohn Marino       EXECUTE_IF_SET_IN_BITMAP (vars, 0, j, bi)
921e4b17023SJohn Marino 	{
922e4b17023SJohn Marino 	  varinfo_t v = get_varinfo (j);
923e4b17023SJohn Marino 	  for (; v != NULL; v = v->next)
924e4b17023SJohn Marino 	    bitmap_set_bit (result, v->id);
925e4b17023SJohn Marino 	}
926e4b17023SJohn Marino       BITMAP_FREE (vars);
927e4b17023SJohn Marino     }
928e4b17023SJohn Marino }
929e4b17023SJohn Marino 
930e4b17023SJohn Marino /* Take a solution set SET, add OFFSET to each member of the set, and
931e4b17023SJohn Marino    overwrite SET with the result when done.  */
932e4b17023SJohn Marino 
933e4b17023SJohn Marino static void
solution_set_add(bitmap set,HOST_WIDE_INT offset)934e4b17023SJohn Marino solution_set_add (bitmap set, HOST_WIDE_INT offset)
935e4b17023SJohn Marino {
936e4b17023SJohn Marino   bitmap result = BITMAP_ALLOC (&iteration_obstack);
937e4b17023SJohn Marino   unsigned int i;
938e4b17023SJohn Marino   bitmap_iterator bi;
939e4b17023SJohn Marino 
940e4b17023SJohn Marino   /* If the offset is unknown we have to expand the solution to
941e4b17023SJohn Marino      all subfields.  */
942e4b17023SJohn Marino   if (offset == UNKNOWN_OFFSET)
943e4b17023SJohn Marino     {
944e4b17023SJohn Marino       solution_set_expand (set, set);
945e4b17023SJohn Marino       return;
946e4b17023SJohn Marino     }
947e4b17023SJohn Marino 
948e4b17023SJohn Marino   EXECUTE_IF_SET_IN_BITMAP (set, 0, i, bi)
949e4b17023SJohn Marino     {
950e4b17023SJohn Marino       varinfo_t vi = get_varinfo (i);
951e4b17023SJohn Marino 
952e4b17023SJohn Marino       /* If this is a variable with just one field just set its bit
953e4b17023SJohn Marino          in the result.  */
954e4b17023SJohn Marino       if (vi->is_artificial_var
955e4b17023SJohn Marino 	  || vi->is_unknown_size_var
956e4b17023SJohn Marino 	  || vi->is_full_var)
957e4b17023SJohn Marino 	bitmap_set_bit (result, i);
958e4b17023SJohn Marino       else
959e4b17023SJohn Marino 	{
960e4b17023SJohn Marino 	  unsigned HOST_WIDE_INT fieldoffset = vi->offset + offset;
961e4b17023SJohn Marino 
962e4b17023SJohn Marino 	  /* If the offset makes the pointer point to before the
963e4b17023SJohn Marino 	     variable use offset zero for the field lookup.  */
964e4b17023SJohn Marino 	  if (offset < 0
965e4b17023SJohn Marino 	      && fieldoffset > vi->offset)
966e4b17023SJohn Marino 	    fieldoffset = 0;
967e4b17023SJohn Marino 
968e4b17023SJohn Marino 	  if (offset != 0)
969e4b17023SJohn Marino 	    vi = first_or_preceding_vi_for_offset (vi, fieldoffset);
970e4b17023SJohn Marino 
971e4b17023SJohn Marino 	  bitmap_set_bit (result, vi->id);
972e4b17023SJohn Marino 	  /* If the result is not exactly at fieldoffset include the next
973e4b17023SJohn Marino 	     field as well.  See get_constraint_for_ptr_offset for more
974e4b17023SJohn Marino 	     rationale.  */
975e4b17023SJohn Marino 	  if (vi->offset != fieldoffset
976e4b17023SJohn Marino 	      && vi->next != NULL)
977e4b17023SJohn Marino 	    bitmap_set_bit (result, vi->next->id);
978e4b17023SJohn Marino 	}
979e4b17023SJohn Marino     }
980e4b17023SJohn Marino 
981e4b17023SJohn Marino   bitmap_copy (set, result);
982e4b17023SJohn Marino   BITMAP_FREE (result);
983e4b17023SJohn Marino }
984e4b17023SJohn Marino 
985e4b17023SJohn Marino /* Union solution sets TO and FROM, and add INC to each member of FROM in the
986e4b17023SJohn Marino    process.  */
987e4b17023SJohn Marino 
988e4b17023SJohn Marino static bool
set_union_with_increment(bitmap to,bitmap from,HOST_WIDE_INT inc)989e4b17023SJohn Marino set_union_with_increment  (bitmap to, bitmap from, HOST_WIDE_INT inc)
990e4b17023SJohn Marino {
991e4b17023SJohn Marino   if (inc == 0)
992e4b17023SJohn Marino     return bitmap_ior_into (to, from);
993e4b17023SJohn Marino   else
994e4b17023SJohn Marino     {
995e4b17023SJohn Marino       bitmap tmp;
996e4b17023SJohn Marino       bool res;
997e4b17023SJohn Marino 
998e4b17023SJohn Marino       tmp = BITMAP_ALLOC (&iteration_obstack);
999e4b17023SJohn Marino       bitmap_copy (tmp, from);
1000e4b17023SJohn Marino       solution_set_add (tmp, inc);
1001e4b17023SJohn Marino       res = bitmap_ior_into (to, tmp);
1002e4b17023SJohn Marino       BITMAP_FREE (tmp);
1003e4b17023SJohn Marino       return res;
1004e4b17023SJohn Marino     }
1005e4b17023SJohn Marino }
1006e4b17023SJohn Marino 
1007e4b17023SJohn Marino /* Insert constraint C into the list of complex constraints for graph
1008e4b17023SJohn Marino    node VAR.  */
1009e4b17023SJohn Marino 
1010e4b17023SJohn Marino static void
insert_into_complex(constraint_graph_t graph,unsigned int var,constraint_t c)1011e4b17023SJohn Marino insert_into_complex (constraint_graph_t graph,
1012e4b17023SJohn Marino 		     unsigned int var, constraint_t c)
1013e4b17023SJohn Marino {
1014e4b17023SJohn Marino   VEC (constraint_t, heap) *complex = graph->complex[var];
1015e4b17023SJohn Marino   unsigned int place = VEC_lower_bound (constraint_t, complex, c,
1016e4b17023SJohn Marino 					constraint_less);
1017e4b17023SJohn Marino 
1018e4b17023SJohn Marino   /* Only insert constraints that do not already exist.  */
1019e4b17023SJohn Marino   if (place >= VEC_length (constraint_t, complex)
1020e4b17023SJohn Marino       || !constraint_equal (*c, *VEC_index (constraint_t, complex, place)))
1021e4b17023SJohn Marino     VEC_safe_insert (constraint_t, heap, graph->complex[var], place, c);
1022e4b17023SJohn Marino }
1023e4b17023SJohn Marino 
1024e4b17023SJohn Marino 
1025e4b17023SJohn Marino /* Condense two variable nodes into a single variable node, by moving
1026e4b17023SJohn Marino    all associated info from SRC to TO.  */
1027e4b17023SJohn Marino 
1028e4b17023SJohn Marino static void
merge_node_constraints(constraint_graph_t graph,unsigned int to,unsigned int from)1029e4b17023SJohn Marino merge_node_constraints (constraint_graph_t graph, unsigned int to,
1030e4b17023SJohn Marino 			unsigned int from)
1031e4b17023SJohn Marino {
1032e4b17023SJohn Marino   unsigned int i;
1033e4b17023SJohn Marino   constraint_t c;
1034e4b17023SJohn Marino 
1035e4b17023SJohn Marino   gcc_assert (find (from) == to);
1036e4b17023SJohn Marino 
1037e4b17023SJohn Marino   /* Move all complex constraints from src node into to node  */
1038e4b17023SJohn Marino   FOR_EACH_VEC_ELT (constraint_t, graph->complex[from], i, c)
1039e4b17023SJohn Marino     {
1040e4b17023SJohn Marino       /* In complex constraints for node src, we may have either
1041e4b17023SJohn Marino 	 a = *src, and *src = a, or an offseted constraint which are
1042e4b17023SJohn Marino 	 always added to the rhs node's constraints.  */
1043e4b17023SJohn Marino 
1044e4b17023SJohn Marino       if (c->rhs.type == DEREF)
1045e4b17023SJohn Marino 	c->rhs.var = to;
1046e4b17023SJohn Marino       else if (c->lhs.type == DEREF)
1047e4b17023SJohn Marino 	c->lhs.var = to;
1048e4b17023SJohn Marino       else
1049e4b17023SJohn Marino 	c->rhs.var = to;
1050e4b17023SJohn Marino     }
1051e4b17023SJohn Marino   constraint_set_union (&graph->complex[to], &graph->complex[from]);
1052e4b17023SJohn Marino   VEC_free (constraint_t, heap, graph->complex[from]);
1053e4b17023SJohn Marino   graph->complex[from] = NULL;
1054e4b17023SJohn Marino }
1055e4b17023SJohn Marino 
1056e4b17023SJohn Marino 
1057e4b17023SJohn Marino /* Remove edges involving NODE from GRAPH.  */
1058e4b17023SJohn Marino 
1059e4b17023SJohn Marino static void
clear_edges_for_node(constraint_graph_t graph,unsigned int node)1060e4b17023SJohn Marino clear_edges_for_node (constraint_graph_t graph, unsigned int node)
1061e4b17023SJohn Marino {
1062e4b17023SJohn Marino   if (graph->succs[node])
1063e4b17023SJohn Marino     BITMAP_FREE (graph->succs[node]);
1064e4b17023SJohn Marino }
1065e4b17023SJohn Marino 
1066e4b17023SJohn Marino /* Merge GRAPH nodes FROM and TO into node TO.  */
1067e4b17023SJohn Marino 
1068e4b17023SJohn Marino static void
merge_graph_nodes(constraint_graph_t graph,unsigned int to,unsigned int from)1069e4b17023SJohn Marino merge_graph_nodes (constraint_graph_t graph, unsigned int to,
1070e4b17023SJohn Marino 		   unsigned int from)
1071e4b17023SJohn Marino {
1072e4b17023SJohn Marino   if (graph->indirect_cycles[from] != -1)
1073e4b17023SJohn Marino     {
1074e4b17023SJohn Marino       /* If we have indirect cycles with the from node, and we have
1075e4b17023SJohn Marino 	 none on the to node, the to node has indirect cycles from the
1076e4b17023SJohn Marino 	 from node now that they are unified.
1077e4b17023SJohn Marino 	 If indirect cycles exist on both, unify the nodes that they
1078e4b17023SJohn Marino 	 are in a cycle with, since we know they are in a cycle with
1079e4b17023SJohn Marino 	 each other.  */
1080e4b17023SJohn Marino       if (graph->indirect_cycles[to] == -1)
1081e4b17023SJohn Marino 	graph->indirect_cycles[to] = graph->indirect_cycles[from];
1082e4b17023SJohn Marino     }
1083e4b17023SJohn Marino 
1084e4b17023SJohn Marino   /* Merge all the successor edges.  */
1085e4b17023SJohn Marino   if (graph->succs[from])
1086e4b17023SJohn Marino     {
1087e4b17023SJohn Marino       if (!graph->succs[to])
1088e4b17023SJohn Marino 	graph->succs[to] = BITMAP_ALLOC (&pta_obstack);
1089e4b17023SJohn Marino       bitmap_ior_into (graph->succs[to],
1090e4b17023SJohn Marino 		       graph->succs[from]);
1091e4b17023SJohn Marino     }
1092e4b17023SJohn Marino 
1093e4b17023SJohn Marino   clear_edges_for_node (graph, from);
1094e4b17023SJohn Marino }
1095e4b17023SJohn Marino 
1096e4b17023SJohn Marino 
1097e4b17023SJohn Marino /* Add an indirect graph edge to GRAPH, going from TO to FROM if
1098e4b17023SJohn Marino    it doesn't exist in the graph already.  */
1099e4b17023SJohn Marino 
1100e4b17023SJohn Marino static void
add_implicit_graph_edge(constraint_graph_t graph,unsigned int to,unsigned int from)1101e4b17023SJohn Marino add_implicit_graph_edge (constraint_graph_t graph, unsigned int to,
1102e4b17023SJohn Marino 			 unsigned int from)
1103e4b17023SJohn Marino {
1104e4b17023SJohn Marino   if (to == from)
1105e4b17023SJohn Marino     return;
1106e4b17023SJohn Marino 
1107e4b17023SJohn Marino   if (!graph->implicit_preds[to])
1108e4b17023SJohn Marino     graph->implicit_preds[to] = BITMAP_ALLOC (&predbitmap_obstack);
1109e4b17023SJohn Marino 
1110e4b17023SJohn Marino   if (bitmap_set_bit (graph->implicit_preds[to], from))
1111e4b17023SJohn Marino     stats.num_implicit_edges++;
1112e4b17023SJohn Marino }
1113e4b17023SJohn Marino 
1114e4b17023SJohn Marino /* Add a predecessor graph edge to GRAPH, going from TO to FROM if
1115e4b17023SJohn Marino    it doesn't exist in the graph already.
1116e4b17023SJohn Marino    Return false if the edge already existed, true otherwise.  */
1117e4b17023SJohn Marino 
1118e4b17023SJohn Marino static void
add_pred_graph_edge(constraint_graph_t graph,unsigned int to,unsigned int from)1119e4b17023SJohn Marino add_pred_graph_edge (constraint_graph_t graph, unsigned int to,
1120e4b17023SJohn Marino 		     unsigned int from)
1121e4b17023SJohn Marino {
1122e4b17023SJohn Marino   if (!graph->preds[to])
1123e4b17023SJohn Marino     graph->preds[to] = BITMAP_ALLOC (&predbitmap_obstack);
1124e4b17023SJohn Marino   bitmap_set_bit (graph->preds[to], from);
1125e4b17023SJohn Marino }
1126e4b17023SJohn Marino 
1127e4b17023SJohn Marino /* Add a graph edge to GRAPH, going from FROM to TO if
1128e4b17023SJohn Marino    it doesn't exist in the graph already.
1129e4b17023SJohn Marino    Return false if the edge already existed, true otherwise.  */
1130e4b17023SJohn Marino 
1131e4b17023SJohn Marino static bool
add_graph_edge(constraint_graph_t graph,unsigned int to,unsigned int from)1132e4b17023SJohn Marino add_graph_edge (constraint_graph_t graph, unsigned int to,
1133e4b17023SJohn Marino 		unsigned int from)
1134e4b17023SJohn Marino {
1135e4b17023SJohn Marino   if (to == from)
1136e4b17023SJohn Marino     {
1137e4b17023SJohn Marino       return false;
1138e4b17023SJohn Marino     }
1139e4b17023SJohn Marino   else
1140e4b17023SJohn Marino     {
1141e4b17023SJohn Marino       bool r = false;
1142e4b17023SJohn Marino 
1143e4b17023SJohn Marino       if (!graph->succs[from])
1144e4b17023SJohn Marino 	graph->succs[from] = BITMAP_ALLOC (&pta_obstack);
1145e4b17023SJohn Marino       if (bitmap_set_bit (graph->succs[from], to))
1146e4b17023SJohn Marino 	{
1147e4b17023SJohn Marino 	  r = true;
1148e4b17023SJohn Marino 	  if (to < FIRST_REF_NODE && from < FIRST_REF_NODE)
1149e4b17023SJohn Marino 	    stats.num_edges++;
1150e4b17023SJohn Marino 	}
1151e4b17023SJohn Marino       return r;
1152e4b17023SJohn Marino     }
1153e4b17023SJohn Marino }
1154e4b17023SJohn Marino 
1155e4b17023SJohn Marino 
1156e4b17023SJohn Marino /* Return true if {DEST.SRC} is an existing graph edge in GRAPH.  */
1157e4b17023SJohn Marino 
1158e4b17023SJohn Marino static bool
valid_graph_edge(constraint_graph_t graph,unsigned int src,unsigned int dest)1159e4b17023SJohn Marino valid_graph_edge (constraint_graph_t graph, unsigned int src,
1160e4b17023SJohn Marino 		  unsigned int dest)
1161e4b17023SJohn Marino {
1162e4b17023SJohn Marino   return (graph->succs[dest]
1163e4b17023SJohn Marino 	  && bitmap_bit_p (graph->succs[dest], src));
1164e4b17023SJohn Marino }
1165e4b17023SJohn Marino 
1166e4b17023SJohn Marino /* Initialize the constraint graph structure to contain SIZE nodes.  */
1167e4b17023SJohn Marino 
1168e4b17023SJohn Marino static void
init_graph(unsigned int size)1169e4b17023SJohn Marino init_graph (unsigned int size)
1170e4b17023SJohn Marino {
1171e4b17023SJohn Marino   unsigned int j;
1172e4b17023SJohn Marino 
1173e4b17023SJohn Marino   graph = XCNEW (struct constraint_graph);
1174e4b17023SJohn Marino   graph->size = size;
1175e4b17023SJohn Marino   graph->succs = XCNEWVEC (bitmap, graph->size);
1176e4b17023SJohn Marino   graph->indirect_cycles = XNEWVEC (int, graph->size);
1177e4b17023SJohn Marino   graph->rep = XNEWVEC (unsigned int, graph->size);
1178e4b17023SJohn Marino   graph->complex = XCNEWVEC (VEC(constraint_t, heap) *, size);
1179e4b17023SJohn Marino   graph->pe = XCNEWVEC (unsigned int, graph->size);
1180e4b17023SJohn Marino   graph->pe_rep = XNEWVEC (int, graph->size);
1181e4b17023SJohn Marino 
1182e4b17023SJohn Marino   for (j = 0; j < graph->size; j++)
1183e4b17023SJohn Marino     {
1184e4b17023SJohn Marino       graph->rep[j] = j;
1185e4b17023SJohn Marino       graph->pe_rep[j] = -1;
1186e4b17023SJohn Marino       graph->indirect_cycles[j] = -1;
1187e4b17023SJohn Marino     }
1188e4b17023SJohn Marino }
1189e4b17023SJohn Marino 
1190e4b17023SJohn Marino /* Build the constraint graph, adding only predecessor edges right now.  */
1191e4b17023SJohn Marino 
1192e4b17023SJohn Marino static void
build_pred_graph(void)1193e4b17023SJohn Marino build_pred_graph (void)
1194e4b17023SJohn Marino {
1195e4b17023SJohn Marino   int i;
1196e4b17023SJohn Marino   constraint_t c;
1197e4b17023SJohn Marino   unsigned int j;
1198e4b17023SJohn Marino 
1199e4b17023SJohn Marino   graph->implicit_preds = XCNEWVEC (bitmap, graph->size);
1200e4b17023SJohn Marino   graph->preds = XCNEWVEC (bitmap, graph->size);
1201e4b17023SJohn Marino   graph->pointer_label = XCNEWVEC (unsigned int, graph->size);
1202e4b17023SJohn Marino   graph->loc_label = XCNEWVEC (unsigned int, graph->size);
1203e4b17023SJohn Marino   graph->pointed_by = XCNEWVEC (bitmap, graph->size);
1204e4b17023SJohn Marino   graph->points_to = XCNEWVEC (bitmap, graph->size);
1205e4b17023SJohn Marino   graph->eq_rep = XNEWVEC (int, graph->size);
1206e4b17023SJohn Marino   graph->direct_nodes = sbitmap_alloc (graph->size);
1207e4b17023SJohn Marino   graph->address_taken = BITMAP_ALLOC (&predbitmap_obstack);
1208e4b17023SJohn Marino   sbitmap_zero (graph->direct_nodes);
1209e4b17023SJohn Marino 
1210e4b17023SJohn Marino   for (j = 0; j < FIRST_REF_NODE; j++)
1211e4b17023SJohn Marino     {
1212e4b17023SJohn Marino       if (!get_varinfo (j)->is_special_var)
1213e4b17023SJohn Marino 	SET_BIT (graph->direct_nodes, j);
1214e4b17023SJohn Marino     }
1215e4b17023SJohn Marino 
1216e4b17023SJohn Marino   for (j = 0; j < graph->size; j++)
1217e4b17023SJohn Marino     graph->eq_rep[j] = -1;
1218e4b17023SJohn Marino 
1219e4b17023SJohn Marino   for (j = 0; j < VEC_length (varinfo_t, varmap); j++)
1220e4b17023SJohn Marino     graph->indirect_cycles[j] = -1;
1221e4b17023SJohn Marino 
1222e4b17023SJohn Marino   FOR_EACH_VEC_ELT (constraint_t, constraints, i, c)
1223e4b17023SJohn Marino     {
1224e4b17023SJohn Marino       struct constraint_expr lhs = c->lhs;
1225e4b17023SJohn Marino       struct constraint_expr rhs = c->rhs;
1226e4b17023SJohn Marino       unsigned int lhsvar = lhs.var;
1227e4b17023SJohn Marino       unsigned int rhsvar = rhs.var;
1228e4b17023SJohn Marino 
1229e4b17023SJohn Marino       if (lhs.type == DEREF)
1230e4b17023SJohn Marino 	{
1231e4b17023SJohn Marino 	  /* *x = y.  */
1232e4b17023SJohn Marino 	  if (rhs.offset == 0 && lhs.offset == 0 && rhs.type == SCALAR)
1233e4b17023SJohn Marino 	    add_pred_graph_edge (graph, FIRST_REF_NODE + lhsvar, rhsvar);
1234e4b17023SJohn Marino 	}
1235e4b17023SJohn Marino       else if (rhs.type == DEREF)
1236e4b17023SJohn Marino 	{
1237e4b17023SJohn Marino 	  /* x = *y */
1238e4b17023SJohn Marino 	  if (rhs.offset == 0 && lhs.offset == 0 && lhs.type == SCALAR)
1239e4b17023SJohn Marino 	    add_pred_graph_edge (graph, lhsvar, FIRST_REF_NODE + rhsvar);
1240e4b17023SJohn Marino 	  else
1241e4b17023SJohn Marino 	    RESET_BIT (graph->direct_nodes, lhsvar);
1242e4b17023SJohn Marino 	}
1243e4b17023SJohn Marino       else if (rhs.type == ADDRESSOF)
1244e4b17023SJohn Marino 	{
1245e4b17023SJohn Marino 	  varinfo_t v;
1246e4b17023SJohn Marino 
1247e4b17023SJohn Marino 	  /* x = &y */
1248e4b17023SJohn Marino 	  if (graph->points_to[lhsvar] == NULL)
1249e4b17023SJohn Marino 	    graph->points_to[lhsvar] = BITMAP_ALLOC (&predbitmap_obstack);
1250e4b17023SJohn Marino 	  bitmap_set_bit (graph->points_to[lhsvar], rhsvar);
1251e4b17023SJohn Marino 
1252e4b17023SJohn Marino 	  if (graph->pointed_by[rhsvar] == NULL)
1253e4b17023SJohn Marino 	    graph->pointed_by[rhsvar] = BITMAP_ALLOC (&predbitmap_obstack);
1254e4b17023SJohn Marino 	  bitmap_set_bit (graph->pointed_by[rhsvar], lhsvar);
1255e4b17023SJohn Marino 
1256e4b17023SJohn Marino 	  /* Implicitly, *x = y */
1257e4b17023SJohn Marino 	  add_implicit_graph_edge (graph, FIRST_REF_NODE + lhsvar, rhsvar);
1258e4b17023SJohn Marino 
1259e4b17023SJohn Marino 	  /* All related variables are no longer direct nodes.  */
1260e4b17023SJohn Marino 	  RESET_BIT (graph->direct_nodes, rhsvar);
1261e4b17023SJohn Marino           v = get_varinfo (rhsvar);
1262e4b17023SJohn Marino           if (!v->is_full_var)
1263e4b17023SJohn Marino             {
1264e4b17023SJohn Marino               v = lookup_vi_for_tree (v->decl);
1265e4b17023SJohn Marino               do
1266e4b17023SJohn Marino                 {
1267e4b17023SJohn Marino                   RESET_BIT (graph->direct_nodes, v->id);
1268e4b17023SJohn Marino                   v = v->next;
1269e4b17023SJohn Marino                 }
1270e4b17023SJohn Marino               while (v != NULL);
1271e4b17023SJohn Marino             }
1272e4b17023SJohn Marino 	  bitmap_set_bit (graph->address_taken, rhsvar);
1273e4b17023SJohn Marino 	}
1274e4b17023SJohn Marino       else if (lhsvar > anything_id
1275e4b17023SJohn Marino 	       && lhsvar != rhsvar && lhs.offset == 0 && rhs.offset == 0)
1276e4b17023SJohn Marino 	{
1277e4b17023SJohn Marino 	  /* x = y */
1278e4b17023SJohn Marino 	  add_pred_graph_edge (graph, lhsvar, rhsvar);
1279e4b17023SJohn Marino 	  /* Implicitly, *x = *y */
1280e4b17023SJohn Marino 	  add_implicit_graph_edge (graph, FIRST_REF_NODE + lhsvar,
1281e4b17023SJohn Marino 				   FIRST_REF_NODE + rhsvar);
1282e4b17023SJohn Marino 	}
1283e4b17023SJohn Marino       else if (lhs.offset != 0 || rhs.offset != 0)
1284e4b17023SJohn Marino 	{
1285e4b17023SJohn Marino 	  if (rhs.offset != 0)
1286e4b17023SJohn Marino 	    RESET_BIT (graph->direct_nodes, lhs.var);
1287e4b17023SJohn Marino 	  else if (lhs.offset != 0)
1288e4b17023SJohn Marino 	    RESET_BIT (graph->direct_nodes, rhs.var);
1289e4b17023SJohn Marino 	}
1290e4b17023SJohn Marino     }
1291e4b17023SJohn Marino }
1292e4b17023SJohn Marino 
1293e4b17023SJohn Marino /* Build the constraint graph, adding successor edges.  */
1294e4b17023SJohn Marino 
1295e4b17023SJohn Marino static void
build_succ_graph(void)1296e4b17023SJohn Marino build_succ_graph (void)
1297e4b17023SJohn Marino {
1298e4b17023SJohn Marino   unsigned i, t;
1299e4b17023SJohn Marino   constraint_t c;
1300e4b17023SJohn Marino 
1301e4b17023SJohn Marino   FOR_EACH_VEC_ELT (constraint_t, constraints, i, c)
1302e4b17023SJohn Marino     {
1303e4b17023SJohn Marino       struct constraint_expr lhs;
1304e4b17023SJohn Marino       struct constraint_expr rhs;
1305e4b17023SJohn Marino       unsigned int lhsvar;
1306e4b17023SJohn Marino       unsigned int rhsvar;
1307e4b17023SJohn Marino 
1308e4b17023SJohn Marino       if (!c)
1309e4b17023SJohn Marino 	continue;
1310e4b17023SJohn Marino 
1311e4b17023SJohn Marino       lhs = c->lhs;
1312e4b17023SJohn Marino       rhs = c->rhs;
1313e4b17023SJohn Marino       lhsvar = find (lhs.var);
1314e4b17023SJohn Marino       rhsvar = find (rhs.var);
1315e4b17023SJohn Marino 
1316e4b17023SJohn Marino       if (lhs.type == DEREF)
1317e4b17023SJohn Marino 	{
1318e4b17023SJohn Marino 	  if (rhs.offset == 0 && lhs.offset == 0 && rhs.type == SCALAR)
1319e4b17023SJohn Marino 	    add_graph_edge (graph, FIRST_REF_NODE + lhsvar, rhsvar);
1320e4b17023SJohn Marino 	}
1321e4b17023SJohn Marino       else if (rhs.type == DEREF)
1322e4b17023SJohn Marino 	{
1323e4b17023SJohn Marino 	  if (rhs.offset == 0 && lhs.offset == 0 && lhs.type == SCALAR)
1324e4b17023SJohn Marino 	    add_graph_edge (graph, lhsvar, FIRST_REF_NODE + rhsvar);
1325e4b17023SJohn Marino 	}
1326e4b17023SJohn Marino       else if (rhs.type == ADDRESSOF)
1327e4b17023SJohn Marino 	{
1328e4b17023SJohn Marino 	  /* x = &y */
1329e4b17023SJohn Marino 	  gcc_assert (find (rhs.var) == rhs.var);
1330e4b17023SJohn Marino 	  bitmap_set_bit (get_varinfo (lhsvar)->solution, rhsvar);
1331e4b17023SJohn Marino 	}
1332e4b17023SJohn Marino       else if (lhsvar > anything_id
1333e4b17023SJohn Marino 	       && lhsvar != rhsvar && lhs.offset == 0 && rhs.offset == 0)
1334e4b17023SJohn Marino 	{
1335e4b17023SJohn Marino 	  add_graph_edge (graph, lhsvar, rhsvar);
1336e4b17023SJohn Marino 	}
1337e4b17023SJohn Marino     }
1338e4b17023SJohn Marino 
1339e4b17023SJohn Marino   /* Add edges from STOREDANYTHING to all non-direct nodes that can
1340e4b17023SJohn Marino      receive pointers.  */
1341e4b17023SJohn Marino   t = find (storedanything_id);
1342e4b17023SJohn Marino   for (i = integer_id + 1; i < FIRST_REF_NODE; ++i)
1343e4b17023SJohn Marino     {
1344e4b17023SJohn Marino       if (!TEST_BIT (graph->direct_nodes, i)
1345e4b17023SJohn Marino 	  && get_varinfo (i)->may_have_pointers)
1346e4b17023SJohn Marino 	add_graph_edge (graph, find (i), t);
1347e4b17023SJohn Marino     }
1348e4b17023SJohn Marino 
1349e4b17023SJohn Marino   /* Everything stored to ANYTHING also potentially escapes.  */
1350e4b17023SJohn Marino   add_graph_edge (graph, find (escaped_id), t);
1351e4b17023SJohn Marino }
1352e4b17023SJohn Marino 
1353e4b17023SJohn Marino 
1354e4b17023SJohn Marino /* Changed variables on the last iteration.  */
1355e4b17023SJohn Marino static bitmap changed;
1356e4b17023SJohn Marino 
1357e4b17023SJohn Marino /* Strongly Connected Component visitation info.  */
1358e4b17023SJohn Marino 
1359e4b17023SJohn Marino struct scc_info
1360e4b17023SJohn Marino {
1361e4b17023SJohn Marino   sbitmap visited;
1362e4b17023SJohn Marino   sbitmap deleted;
1363e4b17023SJohn Marino   unsigned int *dfs;
1364e4b17023SJohn Marino   unsigned int *node_mapping;
1365e4b17023SJohn Marino   int current_index;
1366e4b17023SJohn Marino   VEC(unsigned,heap) *scc_stack;
1367e4b17023SJohn Marino };
1368e4b17023SJohn Marino 
1369e4b17023SJohn Marino 
1370e4b17023SJohn Marino /* Recursive routine to find strongly connected components in GRAPH.
1371e4b17023SJohn Marino    SI is the SCC info to store the information in, and N is the id of current
1372e4b17023SJohn Marino    graph node we are processing.
1373e4b17023SJohn Marino 
1374e4b17023SJohn Marino    This is Tarjan's strongly connected component finding algorithm, as
1375e4b17023SJohn Marino    modified by Nuutila to keep only non-root nodes on the stack.
1376e4b17023SJohn Marino    The algorithm can be found in "On finding the strongly connected
1377e4b17023SJohn Marino    connected components in a directed graph" by Esko Nuutila and Eljas
1378e4b17023SJohn Marino    Soisalon-Soininen, in Information Processing Letters volume 49,
1379e4b17023SJohn Marino    number 1, pages 9-14.  */
1380e4b17023SJohn Marino 
1381e4b17023SJohn Marino static void
scc_visit(constraint_graph_t graph,struct scc_info * si,unsigned int n)1382e4b17023SJohn Marino scc_visit (constraint_graph_t graph, struct scc_info *si, unsigned int n)
1383e4b17023SJohn Marino {
1384e4b17023SJohn Marino   unsigned int i;
1385e4b17023SJohn Marino   bitmap_iterator bi;
1386e4b17023SJohn Marino   unsigned int my_dfs;
1387e4b17023SJohn Marino 
1388e4b17023SJohn Marino   SET_BIT (si->visited, n);
1389e4b17023SJohn Marino   si->dfs[n] = si->current_index ++;
1390e4b17023SJohn Marino   my_dfs = si->dfs[n];
1391e4b17023SJohn Marino 
1392e4b17023SJohn Marino   /* Visit all the successors.  */
1393e4b17023SJohn Marino   EXECUTE_IF_IN_NONNULL_BITMAP (graph->succs[n], 0, i, bi)
1394e4b17023SJohn Marino     {
1395e4b17023SJohn Marino       unsigned int w;
1396e4b17023SJohn Marino 
1397e4b17023SJohn Marino       if (i > LAST_REF_NODE)
1398e4b17023SJohn Marino 	break;
1399e4b17023SJohn Marino 
1400e4b17023SJohn Marino       w = find (i);
1401e4b17023SJohn Marino       if (TEST_BIT (si->deleted, w))
1402e4b17023SJohn Marino 	continue;
1403e4b17023SJohn Marino 
1404e4b17023SJohn Marino       if (!TEST_BIT (si->visited, w))
1405e4b17023SJohn Marino 	scc_visit (graph, si, w);
1406e4b17023SJohn Marino       {
1407e4b17023SJohn Marino 	unsigned int t = find (w);
1408e4b17023SJohn Marino 	unsigned int nnode = find (n);
1409e4b17023SJohn Marino 	gcc_assert (nnode == n);
1410e4b17023SJohn Marino 
1411e4b17023SJohn Marino 	if (si->dfs[t] < si->dfs[nnode])
1412e4b17023SJohn Marino 	  si->dfs[n] = si->dfs[t];
1413e4b17023SJohn Marino       }
1414e4b17023SJohn Marino     }
1415e4b17023SJohn Marino 
1416e4b17023SJohn Marino   /* See if any components have been identified.  */
1417e4b17023SJohn Marino   if (si->dfs[n] == my_dfs)
1418e4b17023SJohn Marino     {
1419e4b17023SJohn Marino       if (VEC_length (unsigned, si->scc_stack) > 0
1420e4b17023SJohn Marino 	  && si->dfs[VEC_last (unsigned, si->scc_stack)] >= my_dfs)
1421e4b17023SJohn Marino 	{
1422e4b17023SJohn Marino 	  bitmap scc = BITMAP_ALLOC (NULL);
1423e4b17023SJohn Marino 	  unsigned int lowest_node;
1424e4b17023SJohn Marino 	  bitmap_iterator bi;
1425e4b17023SJohn Marino 
1426e4b17023SJohn Marino 	  bitmap_set_bit (scc, n);
1427e4b17023SJohn Marino 
1428e4b17023SJohn Marino 	  while (VEC_length (unsigned, si->scc_stack) != 0
1429e4b17023SJohn Marino 		 && si->dfs[VEC_last (unsigned, si->scc_stack)] >= my_dfs)
1430e4b17023SJohn Marino 	    {
1431e4b17023SJohn Marino 	      unsigned int w = VEC_pop (unsigned, si->scc_stack);
1432e4b17023SJohn Marino 
1433e4b17023SJohn Marino 	      bitmap_set_bit (scc, w);
1434e4b17023SJohn Marino 	    }
1435e4b17023SJohn Marino 
1436e4b17023SJohn Marino 	  lowest_node = bitmap_first_set_bit (scc);
1437e4b17023SJohn Marino 	  gcc_assert (lowest_node < FIRST_REF_NODE);
1438e4b17023SJohn Marino 
1439e4b17023SJohn Marino 	  /* Collapse the SCC nodes into a single node, and mark the
1440e4b17023SJohn Marino 	     indirect cycles.  */
1441e4b17023SJohn Marino 	  EXECUTE_IF_SET_IN_BITMAP (scc, 0, i, bi)
1442e4b17023SJohn Marino 	    {
1443e4b17023SJohn Marino 	      if (i < FIRST_REF_NODE)
1444e4b17023SJohn Marino 		{
1445e4b17023SJohn Marino 		  if (unite (lowest_node, i))
1446e4b17023SJohn Marino 		    unify_nodes (graph, lowest_node, i, false);
1447e4b17023SJohn Marino 		}
1448e4b17023SJohn Marino 	      else
1449e4b17023SJohn Marino 		{
1450e4b17023SJohn Marino 		  unite (lowest_node, i);
1451e4b17023SJohn Marino 		  graph->indirect_cycles[i - FIRST_REF_NODE] = lowest_node;
1452e4b17023SJohn Marino 		}
1453e4b17023SJohn Marino 	    }
1454e4b17023SJohn Marino 	}
1455e4b17023SJohn Marino       SET_BIT (si->deleted, n);
1456e4b17023SJohn Marino     }
1457e4b17023SJohn Marino   else
1458e4b17023SJohn Marino     VEC_safe_push (unsigned, heap, si->scc_stack, n);
1459e4b17023SJohn Marino }
1460e4b17023SJohn Marino 
1461e4b17023SJohn Marino /* Unify node FROM into node TO, updating the changed count if
1462e4b17023SJohn Marino    necessary when UPDATE_CHANGED is true.  */
1463e4b17023SJohn Marino 
1464e4b17023SJohn Marino static void
unify_nodes(constraint_graph_t graph,unsigned int to,unsigned int from,bool update_changed)1465e4b17023SJohn Marino unify_nodes (constraint_graph_t graph, unsigned int to, unsigned int from,
1466e4b17023SJohn Marino 	     bool update_changed)
1467e4b17023SJohn Marino {
1468e4b17023SJohn Marino 
1469e4b17023SJohn Marino   gcc_assert (to != from && find (to) == to);
1470e4b17023SJohn Marino   if (dump_file && (dump_flags & TDF_DETAILS))
1471e4b17023SJohn Marino     fprintf (dump_file, "Unifying %s to %s\n",
1472e4b17023SJohn Marino 	     get_varinfo (from)->name,
1473e4b17023SJohn Marino 	     get_varinfo (to)->name);
1474e4b17023SJohn Marino 
1475e4b17023SJohn Marino   if (update_changed)
1476e4b17023SJohn Marino     stats.unified_vars_dynamic++;
1477e4b17023SJohn Marino   else
1478e4b17023SJohn Marino     stats.unified_vars_static++;
1479e4b17023SJohn Marino 
1480e4b17023SJohn Marino   merge_graph_nodes (graph, to, from);
1481e4b17023SJohn Marino   merge_node_constraints (graph, to, from);
1482e4b17023SJohn Marino 
1483e4b17023SJohn Marino   /* Mark TO as changed if FROM was changed. If TO was already marked
1484e4b17023SJohn Marino      as changed, decrease the changed count.  */
1485e4b17023SJohn Marino 
1486e4b17023SJohn Marino   if (update_changed
1487e4b17023SJohn Marino       && bitmap_bit_p (changed, from))
1488e4b17023SJohn Marino     {
1489e4b17023SJohn Marino       bitmap_clear_bit (changed, from);
1490e4b17023SJohn Marino       bitmap_set_bit (changed, to);
1491e4b17023SJohn Marino     }
1492e4b17023SJohn Marino   if (get_varinfo (from)->solution)
1493e4b17023SJohn Marino     {
1494e4b17023SJohn Marino       /* If the solution changes because of the merging, we need to mark
1495e4b17023SJohn Marino 	 the variable as changed.  */
1496e4b17023SJohn Marino       if (bitmap_ior_into (get_varinfo (to)->solution,
1497e4b17023SJohn Marino 			   get_varinfo (from)->solution))
1498e4b17023SJohn Marino 	{
1499e4b17023SJohn Marino 	  if (update_changed)
1500e4b17023SJohn Marino 	    bitmap_set_bit (changed, to);
1501e4b17023SJohn Marino 	}
1502e4b17023SJohn Marino 
1503e4b17023SJohn Marino       BITMAP_FREE (get_varinfo (from)->solution);
1504e4b17023SJohn Marino       if (get_varinfo (from)->oldsolution)
1505e4b17023SJohn Marino 	BITMAP_FREE (get_varinfo (from)->oldsolution);
1506e4b17023SJohn Marino 
1507e4b17023SJohn Marino       if (stats.iterations > 0
1508e4b17023SJohn Marino 	  && get_varinfo (to)->oldsolution)
1509e4b17023SJohn Marino 	BITMAP_FREE (get_varinfo (to)->oldsolution);
1510e4b17023SJohn Marino     }
1511e4b17023SJohn Marino   if (valid_graph_edge (graph, to, to))
1512e4b17023SJohn Marino     {
1513e4b17023SJohn Marino       if (graph->succs[to])
1514e4b17023SJohn Marino 	bitmap_clear_bit (graph->succs[to], to);
1515e4b17023SJohn Marino     }
1516e4b17023SJohn Marino }
1517e4b17023SJohn Marino 
1518e4b17023SJohn Marino /* Information needed to compute the topological ordering of a graph.  */
1519e4b17023SJohn Marino 
1520e4b17023SJohn Marino struct topo_info
1521e4b17023SJohn Marino {
1522e4b17023SJohn Marino   /* sbitmap of visited nodes.  */
1523e4b17023SJohn Marino   sbitmap visited;
1524e4b17023SJohn Marino   /* Array that stores the topological order of the graph, *in
1525e4b17023SJohn Marino      reverse*.  */
1526e4b17023SJohn Marino   VEC(unsigned,heap) *topo_order;
1527e4b17023SJohn Marino };
1528e4b17023SJohn Marino 
1529e4b17023SJohn Marino 
1530e4b17023SJohn Marino /* Initialize and return a topological info structure.  */
1531e4b17023SJohn Marino 
1532e4b17023SJohn Marino static struct topo_info *
init_topo_info(void)1533e4b17023SJohn Marino init_topo_info (void)
1534e4b17023SJohn Marino {
1535e4b17023SJohn Marino   size_t size = graph->size;
1536e4b17023SJohn Marino   struct topo_info *ti = XNEW (struct topo_info);
1537e4b17023SJohn Marino   ti->visited = sbitmap_alloc (size);
1538e4b17023SJohn Marino   sbitmap_zero (ti->visited);
1539e4b17023SJohn Marino   ti->topo_order = VEC_alloc (unsigned, heap, 1);
1540e4b17023SJohn Marino   return ti;
1541e4b17023SJohn Marino }
1542e4b17023SJohn Marino 
1543e4b17023SJohn Marino 
1544e4b17023SJohn Marino /* Free the topological sort info pointed to by TI.  */
1545e4b17023SJohn Marino 
1546e4b17023SJohn Marino static void
free_topo_info(struct topo_info * ti)1547e4b17023SJohn Marino free_topo_info (struct topo_info *ti)
1548e4b17023SJohn Marino {
1549e4b17023SJohn Marino   sbitmap_free (ti->visited);
1550e4b17023SJohn Marino   VEC_free (unsigned, heap, ti->topo_order);
1551e4b17023SJohn Marino   free (ti);
1552e4b17023SJohn Marino }
1553e4b17023SJohn Marino 
1554e4b17023SJohn Marino /* Visit the graph in topological order, and store the order in the
1555e4b17023SJohn Marino    topo_info structure.  */
1556e4b17023SJohn Marino 
1557e4b17023SJohn Marino static void
topo_visit(constraint_graph_t graph,struct topo_info * ti,unsigned int n)1558e4b17023SJohn Marino topo_visit (constraint_graph_t graph, struct topo_info *ti,
1559e4b17023SJohn Marino 	    unsigned int n)
1560e4b17023SJohn Marino {
1561e4b17023SJohn Marino   bitmap_iterator bi;
1562e4b17023SJohn Marino   unsigned int j;
1563e4b17023SJohn Marino 
1564e4b17023SJohn Marino   SET_BIT (ti->visited, n);
1565e4b17023SJohn Marino 
1566e4b17023SJohn Marino   if (graph->succs[n])
1567e4b17023SJohn Marino     EXECUTE_IF_SET_IN_BITMAP (graph->succs[n], 0, j, bi)
1568e4b17023SJohn Marino       {
1569e4b17023SJohn Marino 	if (!TEST_BIT (ti->visited, j))
1570e4b17023SJohn Marino 	  topo_visit (graph, ti, j);
1571e4b17023SJohn Marino       }
1572e4b17023SJohn Marino 
1573e4b17023SJohn Marino   VEC_safe_push (unsigned, heap, ti->topo_order, n);
1574e4b17023SJohn Marino }
1575e4b17023SJohn Marino 
1576e4b17023SJohn Marino /* Process a constraint C that represents x = *(y + off), using DELTA as the
1577e4b17023SJohn Marino    starting solution for y.  */
1578e4b17023SJohn Marino 
1579e4b17023SJohn Marino static void
do_sd_constraint(constraint_graph_t graph,constraint_t c,bitmap delta)1580e4b17023SJohn Marino do_sd_constraint (constraint_graph_t graph, constraint_t c,
1581e4b17023SJohn Marino 		  bitmap delta)
1582e4b17023SJohn Marino {
1583e4b17023SJohn Marino   unsigned int lhs = c->lhs.var;
1584e4b17023SJohn Marino   bool flag = false;
1585e4b17023SJohn Marino   bitmap sol = get_varinfo (lhs)->solution;
1586e4b17023SJohn Marino   unsigned int j;
1587e4b17023SJohn Marino   bitmap_iterator bi;
1588e4b17023SJohn Marino   HOST_WIDE_INT roffset = c->rhs.offset;
1589e4b17023SJohn Marino 
1590e4b17023SJohn Marino   /* Our IL does not allow this.  */
1591e4b17023SJohn Marino   gcc_assert (c->lhs.offset == 0);
1592e4b17023SJohn Marino 
1593e4b17023SJohn Marino   /* If the solution of Y contains anything it is good enough to transfer
1594e4b17023SJohn Marino      this to the LHS.  */
1595e4b17023SJohn Marino   if (bitmap_bit_p (delta, anything_id))
1596e4b17023SJohn Marino     {
1597e4b17023SJohn Marino       flag |= bitmap_set_bit (sol, anything_id);
1598e4b17023SJohn Marino       goto done;
1599e4b17023SJohn Marino     }
1600e4b17023SJohn Marino 
1601e4b17023SJohn Marino   /* If we do not know at with offset the rhs is dereferenced compute
1602e4b17023SJohn Marino      the reachability set of DELTA, conservatively assuming it is
1603e4b17023SJohn Marino      dereferenced at all valid offsets.  */
1604e4b17023SJohn Marino   if (roffset == UNKNOWN_OFFSET)
1605e4b17023SJohn Marino     {
1606e4b17023SJohn Marino       solution_set_expand (delta, delta);
1607e4b17023SJohn Marino       /* No further offset processing is necessary.  */
1608e4b17023SJohn Marino       roffset = 0;
1609e4b17023SJohn Marino     }
1610e4b17023SJohn Marino 
1611e4b17023SJohn Marino   /* For each variable j in delta (Sol(y)), add
1612e4b17023SJohn Marino      an edge in the graph from j to x, and union Sol(j) into Sol(x).  */
1613e4b17023SJohn Marino   EXECUTE_IF_SET_IN_BITMAP (delta, 0, j, bi)
1614e4b17023SJohn Marino     {
1615e4b17023SJohn Marino       varinfo_t v = get_varinfo (j);
1616e4b17023SJohn Marino       HOST_WIDE_INT fieldoffset = v->offset + roffset;
1617e4b17023SJohn Marino       unsigned int t;
1618e4b17023SJohn Marino 
1619e4b17023SJohn Marino       if (v->is_full_var)
1620e4b17023SJohn Marino 	fieldoffset = v->offset;
1621e4b17023SJohn Marino       else if (roffset != 0)
1622e4b17023SJohn Marino 	v = first_vi_for_offset (v, fieldoffset);
1623e4b17023SJohn Marino       /* If the access is outside of the variable we can ignore it.  */
1624e4b17023SJohn Marino       if (!v)
1625e4b17023SJohn Marino 	continue;
1626e4b17023SJohn Marino 
1627e4b17023SJohn Marino       do
1628e4b17023SJohn Marino 	{
1629e4b17023SJohn Marino 	  t = find (v->id);
1630e4b17023SJohn Marino 
1631e4b17023SJohn Marino 	  /* Adding edges from the special vars is pointless.
1632e4b17023SJohn Marino 	     They don't have sets that can change.  */
1633e4b17023SJohn Marino 	  if (get_varinfo (t)->is_special_var)
1634e4b17023SJohn Marino 	    flag |= bitmap_ior_into (sol, get_varinfo (t)->solution);
1635e4b17023SJohn Marino 	  /* Merging the solution from ESCAPED needlessly increases
1636e4b17023SJohn Marino 	     the set.  Use ESCAPED as representative instead.  */
1637e4b17023SJohn Marino 	  else if (v->id == escaped_id)
1638e4b17023SJohn Marino 	    flag |= bitmap_set_bit (sol, escaped_id);
1639e4b17023SJohn Marino 	  else if (v->may_have_pointers
1640e4b17023SJohn Marino 		   && add_graph_edge (graph, lhs, t))
1641e4b17023SJohn Marino 	    flag |= bitmap_ior_into (sol, get_varinfo (t)->solution);
1642e4b17023SJohn Marino 
1643e4b17023SJohn Marino 	  /* If the variable is not exactly at the requested offset
1644e4b17023SJohn Marino 	     we have to include the next one.  */
1645e4b17023SJohn Marino 	  if (v->offset == (unsigned HOST_WIDE_INT)fieldoffset
1646e4b17023SJohn Marino 	      || v->next == NULL)
1647e4b17023SJohn Marino 	    break;
1648e4b17023SJohn Marino 
1649e4b17023SJohn Marino 	  v = v->next;
1650e4b17023SJohn Marino 	  fieldoffset = v->offset;
1651e4b17023SJohn Marino 	}
1652e4b17023SJohn Marino       while (1);
1653e4b17023SJohn Marino     }
1654e4b17023SJohn Marino 
1655e4b17023SJohn Marino done:
1656e4b17023SJohn Marino   /* If the LHS solution changed, mark the var as changed.  */
1657e4b17023SJohn Marino   if (flag)
1658e4b17023SJohn Marino     {
1659e4b17023SJohn Marino       get_varinfo (lhs)->solution = sol;
1660e4b17023SJohn Marino       bitmap_set_bit (changed, lhs);
1661e4b17023SJohn Marino     }
1662e4b17023SJohn Marino }
1663e4b17023SJohn Marino 
1664e4b17023SJohn Marino /* Process a constraint C that represents *(x + off) = y using DELTA
1665e4b17023SJohn Marino    as the starting solution for x.  */
1666e4b17023SJohn Marino 
1667e4b17023SJohn Marino static void
do_ds_constraint(constraint_t c,bitmap delta)1668e4b17023SJohn Marino do_ds_constraint (constraint_t c, bitmap delta)
1669e4b17023SJohn Marino {
1670e4b17023SJohn Marino   unsigned int rhs = c->rhs.var;
1671e4b17023SJohn Marino   bitmap sol = get_varinfo (rhs)->solution;
1672e4b17023SJohn Marino   unsigned int j;
1673e4b17023SJohn Marino   bitmap_iterator bi;
1674e4b17023SJohn Marino   HOST_WIDE_INT loff = c->lhs.offset;
1675e4b17023SJohn Marino   bool escaped_p = false;
1676e4b17023SJohn Marino 
1677e4b17023SJohn Marino   /* Our IL does not allow this.  */
1678e4b17023SJohn Marino   gcc_assert (c->rhs.offset == 0);
1679e4b17023SJohn Marino 
1680e4b17023SJohn Marino   /* If the solution of y contains ANYTHING simply use the ANYTHING
1681e4b17023SJohn Marino      solution.  This avoids needlessly increasing the points-to sets.  */
1682e4b17023SJohn Marino   if (bitmap_bit_p (sol, anything_id))
1683e4b17023SJohn Marino     sol = get_varinfo (find (anything_id))->solution;
1684e4b17023SJohn Marino 
1685e4b17023SJohn Marino   /* If the solution for x contains ANYTHING we have to merge the
1686e4b17023SJohn Marino      solution of y into all pointer variables which we do via
1687e4b17023SJohn Marino      STOREDANYTHING.  */
1688e4b17023SJohn Marino   if (bitmap_bit_p (delta, anything_id))
1689e4b17023SJohn Marino     {
1690e4b17023SJohn Marino       unsigned t = find (storedanything_id);
1691e4b17023SJohn Marino       if (add_graph_edge (graph, t, rhs))
1692e4b17023SJohn Marino 	{
1693e4b17023SJohn Marino 	  if (bitmap_ior_into (get_varinfo (t)->solution, sol))
1694e4b17023SJohn Marino 	    bitmap_set_bit (changed, t);
1695e4b17023SJohn Marino 	}
1696e4b17023SJohn Marino       return;
1697e4b17023SJohn Marino     }
1698e4b17023SJohn Marino 
1699e4b17023SJohn Marino   /* If we do not know at with offset the rhs is dereferenced compute
1700e4b17023SJohn Marino      the reachability set of DELTA, conservatively assuming it is
1701e4b17023SJohn Marino      dereferenced at all valid offsets.  */
1702e4b17023SJohn Marino   if (loff == UNKNOWN_OFFSET)
1703e4b17023SJohn Marino     {
1704e4b17023SJohn Marino       solution_set_expand (delta, delta);
1705e4b17023SJohn Marino       loff = 0;
1706e4b17023SJohn Marino     }
1707e4b17023SJohn Marino 
1708e4b17023SJohn Marino   /* For each member j of delta (Sol(x)), add an edge from y to j and
1709e4b17023SJohn Marino      union Sol(y) into Sol(j) */
1710e4b17023SJohn Marino   EXECUTE_IF_SET_IN_BITMAP (delta, 0, j, bi)
1711e4b17023SJohn Marino     {
1712e4b17023SJohn Marino       varinfo_t v = get_varinfo (j);
1713e4b17023SJohn Marino       unsigned int t;
1714e4b17023SJohn Marino       HOST_WIDE_INT fieldoffset = v->offset + loff;
1715e4b17023SJohn Marino 
1716e4b17023SJohn Marino       if (v->is_full_var)
1717e4b17023SJohn Marino 	fieldoffset = v->offset;
1718e4b17023SJohn Marino       else if (loff != 0)
1719e4b17023SJohn Marino 	v = first_vi_for_offset (v, fieldoffset);
1720e4b17023SJohn Marino       /* If the access is outside of the variable we can ignore it.  */
1721e4b17023SJohn Marino       if (!v)
1722e4b17023SJohn Marino 	continue;
1723e4b17023SJohn Marino 
1724e4b17023SJohn Marino       do
1725e4b17023SJohn Marino 	{
1726e4b17023SJohn Marino 	  if (v->may_have_pointers)
1727e4b17023SJohn Marino 	    {
1728e4b17023SJohn Marino 	      /* If v is a global variable then this is an escape point.  */
1729e4b17023SJohn Marino 	      if (v->is_global_var
1730e4b17023SJohn Marino 		  && !escaped_p)
1731e4b17023SJohn Marino 		{
1732e4b17023SJohn Marino 		  t = find (escaped_id);
1733e4b17023SJohn Marino 		  if (add_graph_edge (graph, t, rhs)
1734e4b17023SJohn Marino 		      && bitmap_ior_into (get_varinfo (t)->solution, sol))
1735e4b17023SJohn Marino 		    bitmap_set_bit (changed, t);
1736e4b17023SJohn Marino 		  /* Enough to let rhs escape once.  */
1737e4b17023SJohn Marino 		  escaped_p = true;
1738e4b17023SJohn Marino 		}
1739e4b17023SJohn Marino 
1740e4b17023SJohn Marino 	      if (v->is_special_var)
1741e4b17023SJohn Marino 		break;
1742e4b17023SJohn Marino 
1743e4b17023SJohn Marino 	      t = find (v->id);
1744e4b17023SJohn Marino 	      if (add_graph_edge (graph, t, rhs)
1745e4b17023SJohn Marino 		  && bitmap_ior_into (get_varinfo (t)->solution, sol))
1746e4b17023SJohn Marino 		bitmap_set_bit (changed, t);
1747e4b17023SJohn Marino 	    }
1748e4b17023SJohn Marino 
1749e4b17023SJohn Marino 	  /* If the variable is not exactly at the requested offset
1750e4b17023SJohn Marino 	     we have to include the next one.  */
1751e4b17023SJohn Marino 	  if (v->offset == (unsigned HOST_WIDE_INT)fieldoffset
1752e4b17023SJohn Marino 	      || v->next == NULL)
1753e4b17023SJohn Marino 	    break;
1754e4b17023SJohn Marino 
1755e4b17023SJohn Marino 	  v = v->next;
1756e4b17023SJohn Marino 	  fieldoffset = v->offset;
1757e4b17023SJohn Marino 	}
1758e4b17023SJohn Marino       while (1);
1759e4b17023SJohn Marino     }
1760e4b17023SJohn Marino }
1761e4b17023SJohn Marino 
1762e4b17023SJohn Marino /* Handle a non-simple (simple meaning requires no iteration),
1763e4b17023SJohn Marino    constraint (IE *x = &y, x = *y, *x = y, and x = y with offsets involved).  */
1764e4b17023SJohn Marino 
1765e4b17023SJohn Marino static void
do_complex_constraint(constraint_graph_t graph,constraint_t c,bitmap delta)1766e4b17023SJohn Marino do_complex_constraint (constraint_graph_t graph, constraint_t c, bitmap delta)
1767e4b17023SJohn Marino {
1768e4b17023SJohn Marino   if (c->lhs.type == DEREF)
1769e4b17023SJohn Marino     {
1770e4b17023SJohn Marino       if (c->rhs.type == ADDRESSOF)
1771e4b17023SJohn Marino 	{
1772e4b17023SJohn Marino 	  gcc_unreachable();
1773e4b17023SJohn Marino 	}
1774e4b17023SJohn Marino       else
1775e4b17023SJohn Marino 	{
1776e4b17023SJohn Marino 	  /* *x = y */
1777e4b17023SJohn Marino 	  do_ds_constraint (c, delta);
1778e4b17023SJohn Marino 	}
1779e4b17023SJohn Marino     }
1780e4b17023SJohn Marino   else if (c->rhs.type == DEREF)
1781e4b17023SJohn Marino     {
1782e4b17023SJohn Marino       /* x = *y */
1783e4b17023SJohn Marino       if (!(get_varinfo (c->lhs.var)->is_special_var))
1784e4b17023SJohn Marino 	do_sd_constraint (graph, c, delta);
1785e4b17023SJohn Marino     }
1786e4b17023SJohn Marino   else
1787e4b17023SJohn Marino     {
1788e4b17023SJohn Marino       bitmap tmp;
1789e4b17023SJohn Marino       bitmap solution;
1790e4b17023SJohn Marino       bool flag = false;
1791e4b17023SJohn Marino 
1792e4b17023SJohn Marino       gcc_assert (c->rhs.type == SCALAR && c->lhs.type == SCALAR);
1793e4b17023SJohn Marino       solution = get_varinfo (c->rhs.var)->solution;
1794e4b17023SJohn Marino       tmp = get_varinfo (c->lhs.var)->solution;
1795e4b17023SJohn Marino 
1796e4b17023SJohn Marino       flag = set_union_with_increment (tmp, solution, c->rhs.offset);
1797e4b17023SJohn Marino 
1798e4b17023SJohn Marino       if (flag)
1799e4b17023SJohn Marino 	{
1800e4b17023SJohn Marino 	  get_varinfo (c->lhs.var)->solution = tmp;
1801e4b17023SJohn Marino 	  bitmap_set_bit (changed, c->lhs.var);
1802e4b17023SJohn Marino 	}
1803e4b17023SJohn Marino     }
1804e4b17023SJohn Marino }
1805e4b17023SJohn Marino 
1806e4b17023SJohn Marino /* Initialize and return a new SCC info structure.  */
1807e4b17023SJohn Marino 
1808e4b17023SJohn Marino static struct scc_info *
init_scc_info(size_t size)1809e4b17023SJohn Marino init_scc_info (size_t size)
1810e4b17023SJohn Marino {
1811e4b17023SJohn Marino   struct scc_info *si = XNEW (struct scc_info);
1812e4b17023SJohn Marino   size_t i;
1813e4b17023SJohn Marino 
1814e4b17023SJohn Marino   si->current_index = 0;
1815e4b17023SJohn Marino   si->visited = sbitmap_alloc (size);
1816e4b17023SJohn Marino   sbitmap_zero (si->visited);
1817e4b17023SJohn Marino   si->deleted = sbitmap_alloc (size);
1818e4b17023SJohn Marino   sbitmap_zero (si->deleted);
1819e4b17023SJohn Marino   si->node_mapping = XNEWVEC (unsigned int, size);
1820e4b17023SJohn Marino   si->dfs = XCNEWVEC (unsigned int, size);
1821e4b17023SJohn Marino 
1822e4b17023SJohn Marino   for (i = 0; i < size; i++)
1823e4b17023SJohn Marino     si->node_mapping[i] = i;
1824e4b17023SJohn Marino 
1825e4b17023SJohn Marino   si->scc_stack = VEC_alloc (unsigned, heap, 1);
1826e4b17023SJohn Marino   return si;
1827e4b17023SJohn Marino }
1828e4b17023SJohn Marino 
1829e4b17023SJohn Marino /* Free an SCC info structure pointed to by SI */
1830e4b17023SJohn Marino 
1831e4b17023SJohn Marino static void
free_scc_info(struct scc_info * si)1832e4b17023SJohn Marino free_scc_info (struct scc_info *si)
1833e4b17023SJohn Marino {
1834e4b17023SJohn Marino   sbitmap_free (si->visited);
1835e4b17023SJohn Marino   sbitmap_free (si->deleted);
1836e4b17023SJohn Marino   free (si->node_mapping);
1837e4b17023SJohn Marino   free (si->dfs);
1838e4b17023SJohn Marino   VEC_free (unsigned, heap, si->scc_stack);
1839e4b17023SJohn Marino   free (si);
1840e4b17023SJohn Marino }
1841e4b17023SJohn Marino 
1842e4b17023SJohn Marino 
1843e4b17023SJohn Marino /* Find indirect cycles in GRAPH that occur, using strongly connected
1844e4b17023SJohn Marino    components, and note them in the indirect cycles map.
1845e4b17023SJohn Marino 
1846e4b17023SJohn Marino    This technique comes from Ben Hardekopf and Calvin Lin,
1847e4b17023SJohn Marino    "It Pays to be Lazy: Fast and Accurate Pointer Analysis for Millions of
1848e4b17023SJohn Marino    Lines of Code", submitted to PLDI 2007.  */
1849e4b17023SJohn Marino 
1850e4b17023SJohn Marino static void
find_indirect_cycles(constraint_graph_t graph)1851e4b17023SJohn Marino find_indirect_cycles (constraint_graph_t graph)
1852e4b17023SJohn Marino {
1853e4b17023SJohn Marino   unsigned int i;
1854e4b17023SJohn Marino   unsigned int size = graph->size;
1855e4b17023SJohn Marino   struct scc_info *si = init_scc_info (size);
1856e4b17023SJohn Marino 
1857e4b17023SJohn Marino   for (i = 0; i < MIN (LAST_REF_NODE, size); i ++ )
1858e4b17023SJohn Marino     if (!TEST_BIT (si->visited, i) && find (i) == i)
1859e4b17023SJohn Marino       scc_visit (graph, si, i);
1860e4b17023SJohn Marino 
1861e4b17023SJohn Marino   free_scc_info (si);
1862e4b17023SJohn Marino }
1863e4b17023SJohn Marino 
1864e4b17023SJohn Marino /* Compute a topological ordering for GRAPH, and store the result in the
1865e4b17023SJohn Marino    topo_info structure TI.  */
1866e4b17023SJohn Marino 
1867e4b17023SJohn Marino static void
compute_topo_order(constraint_graph_t graph,struct topo_info * ti)1868e4b17023SJohn Marino compute_topo_order (constraint_graph_t graph,
1869e4b17023SJohn Marino 		    struct topo_info *ti)
1870e4b17023SJohn Marino {
1871e4b17023SJohn Marino   unsigned int i;
1872e4b17023SJohn Marino   unsigned int size = graph->size;
1873e4b17023SJohn Marino 
1874e4b17023SJohn Marino   for (i = 0; i != size; ++i)
1875e4b17023SJohn Marino     if (!TEST_BIT (ti->visited, i) && find (i) == i)
1876e4b17023SJohn Marino       topo_visit (graph, ti, i);
1877e4b17023SJohn Marino }
1878e4b17023SJohn Marino 
1879e4b17023SJohn Marino /* Structure used to for hash value numbering of pointer equivalence
1880e4b17023SJohn Marino    classes.  */
1881e4b17023SJohn Marino 
1882e4b17023SJohn Marino typedef struct equiv_class_label
1883e4b17023SJohn Marino {
1884e4b17023SJohn Marino   hashval_t hashcode;
1885e4b17023SJohn Marino   unsigned int equivalence_class;
1886e4b17023SJohn Marino   bitmap labels;
1887e4b17023SJohn Marino } *equiv_class_label_t;
1888e4b17023SJohn Marino typedef const struct equiv_class_label *const_equiv_class_label_t;
1889e4b17023SJohn Marino 
1890e4b17023SJohn Marino /* A hashtable for mapping a bitmap of labels->pointer equivalence
1891e4b17023SJohn Marino    classes.  */
1892e4b17023SJohn Marino static htab_t pointer_equiv_class_table;
1893e4b17023SJohn Marino 
1894e4b17023SJohn Marino /* A hashtable for mapping a bitmap of labels->location equivalence
1895e4b17023SJohn Marino    classes.  */
1896e4b17023SJohn Marino static htab_t location_equiv_class_table;
1897e4b17023SJohn Marino 
1898e4b17023SJohn Marino /* Hash function for a equiv_class_label_t */
1899e4b17023SJohn Marino 
1900e4b17023SJohn Marino static hashval_t
equiv_class_label_hash(const void * p)1901e4b17023SJohn Marino equiv_class_label_hash (const void *p)
1902e4b17023SJohn Marino {
1903e4b17023SJohn Marino   const_equiv_class_label_t const ecl = (const_equiv_class_label_t) p;
1904e4b17023SJohn Marino   return ecl->hashcode;
1905e4b17023SJohn Marino }
1906e4b17023SJohn Marino 
1907e4b17023SJohn Marino /* Equality function for two equiv_class_label_t's.  */
1908e4b17023SJohn Marino 
1909e4b17023SJohn Marino static int
equiv_class_label_eq(const void * p1,const void * p2)1910e4b17023SJohn Marino equiv_class_label_eq (const void *p1, const void *p2)
1911e4b17023SJohn Marino {
1912e4b17023SJohn Marino   const_equiv_class_label_t const eql1 = (const_equiv_class_label_t) p1;
1913e4b17023SJohn Marino   const_equiv_class_label_t const eql2 = (const_equiv_class_label_t) p2;
1914e4b17023SJohn Marino   return (eql1->hashcode == eql2->hashcode
1915e4b17023SJohn Marino 	  && bitmap_equal_p (eql1->labels, eql2->labels));
1916e4b17023SJohn Marino }
1917e4b17023SJohn Marino 
1918e4b17023SJohn Marino /* Lookup a equivalence class in TABLE by the bitmap of LABELS it
1919*5ce9237cSJohn Marino    contains.  Sets *REF_LABELS to the bitmap LABELS is equivalent to.  */
1920e4b17023SJohn Marino 
1921e4b17023SJohn Marino static unsigned int
equiv_class_lookup(htab_t table,bitmap labels,bitmap * ref_labels)1922*5ce9237cSJohn Marino equiv_class_lookup (htab_t table, bitmap labels, bitmap *ref_labels)
1923e4b17023SJohn Marino {
1924e4b17023SJohn Marino   void **slot;
1925e4b17023SJohn Marino   struct equiv_class_label ecl;
1926e4b17023SJohn Marino 
1927e4b17023SJohn Marino   ecl.labels = labels;
1928e4b17023SJohn Marino   ecl.hashcode = bitmap_hash (labels);
1929e4b17023SJohn Marino 
1930e4b17023SJohn Marino   slot = htab_find_slot_with_hash (table, &ecl,
1931e4b17023SJohn Marino 				   ecl.hashcode, NO_INSERT);
1932e4b17023SJohn Marino   if (!slot)
1933*5ce9237cSJohn Marino     {
1934*5ce9237cSJohn Marino       if (ref_labels)
1935*5ce9237cSJohn Marino 	*ref_labels = NULL;
1936e4b17023SJohn Marino       return 0;
1937*5ce9237cSJohn Marino     }
1938e4b17023SJohn Marino   else
1939*5ce9237cSJohn Marino     {
1940*5ce9237cSJohn Marino       equiv_class_label_t ec = (equiv_class_label_t) *slot;
1941*5ce9237cSJohn Marino       if (ref_labels)
1942*5ce9237cSJohn Marino 	*ref_labels = ec->labels;
1943*5ce9237cSJohn Marino       return ec->equivalence_class;
1944*5ce9237cSJohn Marino     }
1945e4b17023SJohn Marino }
1946e4b17023SJohn Marino 
1947e4b17023SJohn Marino 
1948e4b17023SJohn Marino /* Add an equivalence class named EQUIVALENCE_CLASS with labels LABELS
1949e4b17023SJohn Marino    to TABLE.  */
1950e4b17023SJohn Marino 
1951e4b17023SJohn Marino static void
equiv_class_add(htab_t table,unsigned int equivalence_class,bitmap labels)1952e4b17023SJohn Marino equiv_class_add (htab_t table, unsigned int equivalence_class,
1953e4b17023SJohn Marino 		 bitmap labels)
1954e4b17023SJohn Marino {
1955e4b17023SJohn Marino   void **slot;
1956e4b17023SJohn Marino   equiv_class_label_t ecl = XNEW (struct equiv_class_label);
1957e4b17023SJohn Marino 
1958e4b17023SJohn Marino   ecl->labels = labels;
1959e4b17023SJohn Marino   ecl->equivalence_class = equivalence_class;
1960e4b17023SJohn Marino   ecl->hashcode = bitmap_hash (labels);
1961e4b17023SJohn Marino 
1962e4b17023SJohn Marino   slot = htab_find_slot_with_hash (table, ecl,
1963e4b17023SJohn Marino 				   ecl->hashcode, INSERT);
1964e4b17023SJohn Marino   gcc_assert (!*slot);
1965e4b17023SJohn Marino   *slot = (void *) ecl;
1966e4b17023SJohn Marino }
1967e4b17023SJohn Marino 
1968e4b17023SJohn Marino /* Perform offline variable substitution.
1969e4b17023SJohn Marino 
1970e4b17023SJohn Marino    This is a worst case quadratic time way of identifying variables
1971e4b17023SJohn Marino    that must have equivalent points-to sets, including those caused by
1972e4b17023SJohn Marino    static cycles, and single entry subgraphs, in the constraint graph.
1973e4b17023SJohn Marino 
1974e4b17023SJohn Marino    The technique is described in "Exploiting Pointer and Location
1975e4b17023SJohn Marino    Equivalence to Optimize Pointer Analysis. In the 14th International
1976e4b17023SJohn Marino    Static Analysis Symposium (SAS), August 2007."  It is known as the
1977e4b17023SJohn Marino    "HU" algorithm, and is equivalent to value numbering the collapsed
1978e4b17023SJohn Marino    constraint graph including evaluating unions.
1979e4b17023SJohn Marino 
1980e4b17023SJohn Marino    The general method of finding equivalence classes is as follows:
1981e4b17023SJohn Marino    Add fake nodes (REF nodes) and edges for *a = b and a = *b constraints.
1982e4b17023SJohn Marino    Initialize all non-REF nodes to be direct nodes.
1983e4b17023SJohn Marino    For each constraint a = a U {b}, we set pts(a) = pts(a) u {fresh
1984e4b17023SJohn Marino    variable}
1985e4b17023SJohn Marino    For each constraint containing the dereference, we also do the same
1986e4b17023SJohn Marino    thing.
1987e4b17023SJohn Marino 
1988e4b17023SJohn Marino    We then compute SCC's in the graph and unify nodes in the same SCC,
1989e4b17023SJohn Marino    including pts sets.
1990e4b17023SJohn Marino 
1991e4b17023SJohn Marino    For each non-collapsed node x:
1992e4b17023SJohn Marino     Visit all unvisited explicit incoming edges.
1993e4b17023SJohn Marino     Ignoring all non-pointers, set pts(x) = Union of pts(a) for y
1994e4b17023SJohn Marino     where y->x.
1995e4b17023SJohn Marino     Lookup the equivalence class for pts(x).
1996e4b17023SJohn Marino      If we found one, equivalence_class(x) = found class.
1997e4b17023SJohn Marino      Otherwise, equivalence_class(x) = new class, and new_class is
1998e4b17023SJohn Marino     added to the lookup table.
1999e4b17023SJohn Marino 
2000e4b17023SJohn Marino    All direct nodes with the same equivalence class can be replaced
2001e4b17023SJohn Marino    with a single representative node.
2002e4b17023SJohn Marino    All unlabeled nodes (label == 0) are not pointers and all edges
2003e4b17023SJohn Marino    involving them can be eliminated.
2004e4b17023SJohn Marino    We perform these optimizations during rewrite_constraints
2005e4b17023SJohn Marino 
2006e4b17023SJohn Marino    In addition to pointer equivalence class finding, we also perform
2007e4b17023SJohn Marino    location equivalence class finding.  This is the set of variables
2008e4b17023SJohn Marino    that always appear together in points-to sets.  We use this to
2009e4b17023SJohn Marino    compress the size of the points-to sets.  */
2010e4b17023SJohn Marino 
2011e4b17023SJohn Marino /* Current maximum pointer equivalence class id.  */
2012e4b17023SJohn Marino static int pointer_equiv_class;
2013e4b17023SJohn Marino 
2014e4b17023SJohn Marino /* Current maximum location equivalence class id.  */
2015e4b17023SJohn Marino static int location_equiv_class;
2016e4b17023SJohn Marino 
2017e4b17023SJohn Marino /* Recursive routine to find strongly connected components in GRAPH,
2018e4b17023SJohn Marino    and label it's nodes with DFS numbers.  */
2019e4b17023SJohn Marino 
2020e4b17023SJohn Marino static void
condense_visit(constraint_graph_t graph,struct scc_info * si,unsigned int n)2021e4b17023SJohn Marino condense_visit (constraint_graph_t graph, struct scc_info *si, unsigned int n)
2022e4b17023SJohn Marino {
2023e4b17023SJohn Marino   unsigned int i;
2024e4b17023SJohn Marino   bitmap_iterator bi;
2025e4b17023SJohn Marino   unsigned int my_dfs;
2026e4b17023SJohn Marino 
2027e4b17023SJohn Marino   gcc_assert (si->node_mapping[n] == n);
2028e4b17023SJohn Marino   SET_BIT (si->visited, n);
2029e4b17023SJohn Marino   si->dfs[n] = si->current_index ++;
2030e4b17023SJohn Marino   my_dfs = si->dfs[n];
2031e4b17023SJohn Marino 
2032e4b17023SJohn Marino   /* Visit all the successors.  */
2033e4b17023SJohn Marino   EXECUTE_IF_IN_NONNULL_BITMAP (graph->preds[n], 0, i, bi)
2034e4b17023SJohn Marino     {
2035e4b17023SJohn Marino       unsigned int w = si->node_mapping[i];
2036e4b17023SJohn Marino 
2037e4b17023SJohn Marino       if (TEST_BIT (si->deleted, w))
2038e4b17023SJohn Marino 	continue;
2039e4b17023SJohn Marino 
2040e4b17023SJohn Marino       if (!TEST_BIT (si->visited, w))
2041e4b17023SJohn Marino 	condense_visit (graph, si, w);
2042e4b17023SJohn Marino       {
2043e4b17023SJohn Marino 	unsigned int t = si->node_mapping[w];
2044e4b17023SJohn Marino 	unsigned int nnode = si->node_mapping[n];
2045e4b17023SJohn Marino 	gcc_assert (nnode == n);
2046e4b17023SJohn Marino 
2047e4b17023SJohn Marino 	if (si->dfs[t] < si->dfs[nnode])
2048e4b17023SJohn Marino 	  si->dfs[n] = si->dfs[t];
2049e4b17023SJohn Marino       }
2050e4b17023SJohn Marino     }
2051e4b17023SJohn Marino 
2052e4b17023SJohn Marino   /* Visit all the implicit predecessors.  */
2053e4b17023SJohn Marino   EXECUTE_IF_IN_NONNULL_BITMAP (graph->implicit_preds[n], 0, i, bi)
2054e4b17023SJohn Marino     {
2055e4b17023SJohn Marino       unsigned int w = si->node_mapping[i];
2056e4b17023SJohn Marino 
2057e4b17023SJohn Marino       if (TEST_BIT (si->deleted, w))
2058e4b17023SJohn Marino 	continue;
2059e4b17023SJohn Marino 
2060e4b17023SJohn Marino       if (!TEST_BIT (si->visited, w))
2061e4b17023SJohn Marino 	condense_visit (graph, si, w);
2062e4b17023SJohn Marino       {
2063e4b17023SJohn Marino 	unsigned int t = si->node_mapping[w];
2064e4b17023SJohn Marino 	unsigned int nnode = si->node_mapping[n];
2065e4b17023SJohn Marino 	gcc_assert (nnode == n);
2066e4b17023SJohn Marino 
2067e4b17023SJohn Marino 	if (si->dfs[t] < si->dfs[nnode])
2068e4b17023SJohn Marino 	  si->dfs[n] = si->dfs[t];
2069e4b17023SJohn Marino       }
2070e4b17023SJohn Marino     }
2071e4b17023SJohn Marino 
2072e4b17023SJohn Marino   /* See if any components have been identified.  */
2073e4b17023SJohn Marino   if (si->dfs[n] == my_dfs)
2074e4b17023SJohn Marino     {
2075e4b17023SJohn Marino       while (VEC_length (unsigned, si->scc_stack) != 0
2076e4b17023SJohn Marino 	     && si->dfs[VEC_last (unsigned, si->scc_stack)] >= my_dfs)
2077e4b17023SJohn Marino 	{
2078e4b17023SJohn Marino 	  unsigned int w = VEC_pop (unsigned, si->scc_stack);
2079e4b17023SJohn Marino 	  si->node_mapping[w] = n;
2080e4b17023SJohn Marino 
2081e4b17023SJohn Marino 	  if (!TEST_BIT (graph->direct_nodes, w))
2082e4b17023SJohn Marino 	    RESET_BIT (graph->direct_nodes, n);
2083e4b17023SJohn Marino 
2084e4b17023SJohn Marino 	  /* Unify our nodes.  */
2085e4b17023SJohn Marino 	  if (graph->preds[w])
2086e4b17023SJohn Marino 	    {
2087e4b17023SJohn Marino 	      if (!graph->preds[n])
2088e4b17023SJohn Marino 		graph->preds[n] = BITMAP_ALLOC (&predbitmap_obstack);
2089e4b17023SJohn Marino 	      bitmap_ior_into (graph->preds[n], graph->preds[w]);
2090e4b17023SJohn Marino 	    }
2091e4b17023SJohn Marino 	  if (graph->implicit_preds[w])
2092e4b17023SJohn Marino 	    {
2093e4b17023SJohn Marino 	      if (!graph->implicit_preds[n])
2094e4b17023SJohn Marino 		graph->implicit_preds[n] = BITMAP_ALLOC (&predbitmap_obstack);
2095e4b17023SJohn Marino 	      bitmap_ior_into (graph->implicit_preds[n],
2096e4b17023SJohn Marino 			       graph->implicit_preds[w]);
2097e4b17023SJohn Marino 	    }
2098e4b17023SJohn Marino 	  if (graph->points_to[w])
2099e4b17023SJohn Marino 	    {
2100e4b17023SJohn Marino 	      if (!graph->points_to[n])
2101e4b17023SJohn Marino 		graph->points_to[n] = BITMAP_ALLOC (&predbitmap_obstack);
2102e4b17023SJohn Marino 	      bitmap_ior_into (graph->points_to[n],
2103e4b17023SJohn Marino 			       graph->points_to[w]);
2104e4b17023SJohn Marino 	    }
2105e4b17023SJohn Marino 	}
2106e4b17023SJohn Marino       SET_BIT (si->deleted, n);
2107e4b17023SJohn Marino     }
2108e4b17023SJohn Marino   else
2109e4b17023SJohn Marino     VEC_safe_push (unsigned, heap, si->scc_stack, n);
2110e4b17023SJohn Marino }
2111e4b17023SJohn Marino 
2112e4b17023SJohn Marino /* Label pointer equivalences.  */
2113e4b17023SJohn Marino 
2114e4b17023SJohn Marino static void
label_visit(constraint_graph_t graph,struct scc_info * si,unsigned int n)2115e4b17023SJohn Marino label_visit (constraint_graph_t graph, struct scc_info *si, unsigned int n)
2116e4b17023SJohn Marino {
2117e4b17023SJohn Marino   unsigned int i;
2118e4b17023SJohn Marino   bitmap_iterator bi;
2119e4b17023SJohn Marino   SET_BIT (si->visited, n);
2120e4b17023SJohn Marino 
2121e4b17023SJohn Marino   if (!graph->points_to[n])
2122e4b17023SJohn Marino     graph->points_to[n] = BITMAP_ALLOC (&predbitmap_obstack);
2123e4b17023SJohn Marino 
2124e4b17023SJohn Marino   /* Label and union our incoming edges's points to sets.  */
2125e4b17023SJohn Marino   EXECUTE_IF_IN_NONNULL_BITMAP (graph->preds[n], 0, i, bi)
2126e4b17023SJohn Marino     {
2127e4b17023SJohn Marino       unsigned int w = si->node_mapping[i];
2128e4b17023SJohn Marino       if (!TEST_BIT (si->visited, w))
2129e4b17023SJohn Marino 	label_visit (graph, si, w);
2130e4b17023SJohn Marino 
2131e4b17023SJohn Marino       /* Skip unused edges  */
2132e4b17023SJohn Marino       if (w == n || graph->pointer_label[w] == 0)
2133e4b17023SJohn Marino 	continue;
2134e4b17023SJohn Marino 
2135e4b17023SJohn Marino       if (graph->points_to[w])
2136e4b17023SJohn Marino 	bitmap_ior_into(graph->points_to[n], graph->points_to[w]);
2137e4b17023SJohn Marino     }
2138e4b17023SJohn Marino   /* Indirect nodes get fresh variables.  */
2139e4b17023SJohn Marino   if (!TEST_BIT (graph->direct_nodes, n))
2140e4b17023SJohn Marino     bitmap_set_bit (graph->points_to[n], FIRST_REF_NODE + n);
2141e4b17023SJohn Marino 
2142e4b17023SJohn Marino   if (!bitmap_empty_p (graph->points_to[n]))
2143e4b17023SJohn Marino     {
2144*5ce9237cSJohn Marino       bitmap ref_points_to;
2145e4b17023SJohn Marino       unsigned int label = equiv_class_lookup (pointer_equiv_class_table,
2146*5ce9237cSJohn Marino 					       graph->points_to[n],
2147*5ce9237cSJohn Marino 					       &ref_points_to);
2148e4b17023SJohn Marino       if (!label)
2149e4b17023SJohn Marino 	{
2150e4b17023SJohn Marino 	  label = pointer_equiv_class++;
2151e4b17023SJohn Marino 	  equiv_class_add (pointer_equiv_class_table,
2152e4b17023SJohn Marino 			   label, graph->points_to[n]);
2153e4b17023SJohn Marino 	}
2154*5ce9237cSJohn Marino       else
2155*5ce9237cSJohn Marino 	{
2156*5ce9237cSJohn Marino 	  BITMAP_FREE (graph->points_to[n]);
2157*5ce9237cSJohn Marino 	  graph->points_to[n] = ref_points_to;
2158*5ce9237cSJohn Marino 	}
2159e4b17023SJohn Marino       graph->pointer_label[n] = label;
2160e4b17023SJohn Marino     }
2161e4b17023SJohn Marino }
2162e4b17023SJohn Marino 
2163e4b17023SJohn Marino /* Perform offline variable substitution, discovering equivalence
2164e4b17023SJohn Marino    classes, and eliminating non-pointer variables.  */
2165e4b17023SJohn Marino 
2166e4b17023SJohn Marino static struct scc_info *
perform_var_substitution(constraint_graph_t graph)2167e4b17023SJohn Marino perform_var_substitution (constraint_graph_t graph)
2168e4b17023SJohn Marino {
2169e4b17023SJohn Marino   unsigned int i;
2170e4b17023SJohn Marino   unsigned int size = graph->size;
2171e4b17023SJohn Marino   struct scc_info *si = init_scc_info (size);
2172e4b17023SJohn Marino 
2173e4b17023SJohn Marino   bitmap_obstack_initialize (&iteration_obstack);
2174e4b17023SJohn Marino   pointer_equiv_class_table = htab_create (511, equiv_class_label_hash,
2175e4b17023SJohn Marino 					   equiv_class_label_eq, free);
2176e4b17023SJohn Marino   location_equiv_class_table = htab_create (511, equiv_class_label_hash,
2177e4b17023SJohn Marino 					    equiv_class_label_eq, free);
2178e4b17023SJohn Marino   pointer_equiv_class = 1;
2179e4b17023SJohn Marino   location_equiv_class = 1;
2180e4b17023SJohn Marino 
2181e4b17023SJohn Marino   /* Condense the nodes, which means to find SCC's, count incoming
2182e4b17023SJohn Marino      predecessors, and unite nodes in SCC's.  */
2183e4b17023SJohn Marino   for (i = 0; i < FIRST_REF_NODE; i++)
2184e4b17023SJohn Marino     if (!TEST_BIT (si->visited, si->node_mapping[i]))
2185e4b17023SJohn Marino       condense_visit (graph, si, si->node_mapping[i]);
2186e4b17023SJohn Marino 
2187e4b17023SJohn Marino   sbitmap_zero (si->visited);
2188e4b17023SJohn Marino   /* Actually the label the nodes for pointer equivalences  */
2189e4b17023SJohn Marino   for (i = 0; i < FIRST_REF_NODE; i++)
2190e4b17023SJohn Marino     if (!TEST_BIT (si->visited, si->node_mapping[i]))
2191e4b17023SJohn Marino       label_visit (graph, si, si->node_mapping[i]);
2192e4b17023SJohn Marino 
2193e4b17023SJohn Marino   /* Calculate location equivalence labels.  */
2194e4b17023SJohn Marino   for (i = 0; i < FIRST_REF_NODE; i++)
2195e4b17023SJohn Marino     {
2196e4b17023SJohn Marino       bitmap pointed_by;
2197e4b17023SJohn Marino       bitmap_iterator bi;
2198e4b17023SJohn Marino       unsigned int j;
2199e4b17023SJohn Marino       unsigned int label;
2200e4b17023SJohn Marino 
2201e4b17023SJohn Marino       if (!graph->pointed_by[i])
2202e4b17023SJohn Marino 	continue;
2203e4b17023SJohn Marino       pointed_by = BITMAP_ALLOC (&iteration_obstack);
2204e4b17023SJohn Marino 
2205e4b17023SJohn Marino       /* Translate the pointed-by mapping for pointer equivalence
2206e4b17023SJohn Marino 	 labels.  */
2207e4b17023SJohn Marino       EXECUTE_IF_SET_IN_BITMAP (graph->pointed_by[i], 0, j, bi)
2208e4b17023SJohn Marino 	{
2209e4b17023SJohn Marino 	  bitmap_set_bit (pointed_by,
2210e4b17023SJohn Marino 			  graph->pointer_label[si->node_mapping[j]]);
2211e4b17023SJohn Marino 	}
2212e4b17023SJohn Marino       /* The original pointed_by is now dead.  */
2213e4b17023SJohn Marino       BITMAP_FREE (graph->pointed_by[i]);
2214e4b17023SJohn Marino 
2215e4b17023SJohn Marino       /* Look up the location equivalence label if one exists, or make
2216e4b17023SJohn Marino 	 one otherwise.  */
2217e4b17023SJohn Marino       label = equiv_class_lookup (location_equiv_class_table,
2218*5ce9237cSJohn Marino 				  pointed_by, NULL);
2219e4b17023SJohn Marino       if (label == 0)
2220e4b17023SJohn Marino 	{
2221e4b17023SJohn Marino 	  label = location_equiv_class++;
2222e4b17023SJohn Marino 	  equiv_class_add (location_equiv_class_table,
2223e4b17023SJohn Marino 			   label, pointed_by);
2224e4b17023SJohn Marino 	}
2225e4b17023SJohn Marino       else
2226e4b17023SJohn Marino 	{
2227e4b17023SJohn Marino 	  if (dump_file && (dump_flags & TDF_DETAILS))
2228e4b17023SJohn Marino 	    fprintf (dump_file, "Found location equivalence for node %s\n",
2229e4b17023SJohn Marino 		     get_varinfo (i)->name);
2230e4b17023SJohn Marino 	  BITMAP_FREE (pointed_by);
2231e4b17023SJohn Marino 	}
2232e4b17023SJohn Marino       graph->loc_label[i] = label;
2233e4b17023SJohn Marino 
2234e4b17023SJohn Marino     }
2235e4b17023SJohn Marino 
2236e4b17023SJohn Marino   if (dump_file && (dump_flags & TDF_DETAILS))
2237e4b17023SJohn Marino     for (i = 0; i < FIRST_REF_NODE; i++)
2238e4b17023SJohn Marino       {
2239e4b17023SJohn Marino 	bool direct_node = TEST_BIT (graph->direct_nodes, i);
2240e4b17023SJohn Marino 	fprintf (dump_file,
2241e4b17023SJohn Marino 		 "Equivalence classes for %s node id %d:%s are pointer: %d"
2242e4b17023SJohn Marino 		 ", location:%d\n",
2243e4b17023SJohn Marino 		 direct_node ? "Direct node" : "Indirect node", i,
2244e4b17023SJohn Marino 		 get_varinfo (i)->name,
2245e4b17023SJohn Marino 		 graph->pointer_label[si->node_mapping[i]],
2246e4b17023SJohn Marino 		 graph->loc_label[si->node_mapping[i]]);
2247e4b17023SJohn Marino       }
2248e4b17023SJohn Marino 
2249e4b17023SJohn Marino   /* Quickly eliminate our non-pointer variables.  */
2250e4b17023SJohn Marino 
2251e4b17023SJohn Marino   for (i = 0; i < FIRST_REF_NODE; i++)
2252e4b17023SJohn Marino     {
2253e4b17023SJohn Marino       unsigned int node = si->node_mapping[i];
2254e4b17023SJohn Marino 
2255e4b17023SJohn Marino       if (graph->pointer_label[node] == 0)
2256e4b17023SJohn Marino 	{
2257e4b17023SJohn Marino 	  if (dump_file && (dump_flags & TDF_DETAILS))
2258e4b17023SJohn Marino 	    fprintf (dump_file,
2259e4b17023SJohn Marino 		     "%s is a non-pointer variable, eliminating edges.\n",
2260e4b17023SJohn Marino 		     get_varinfo (node)->name);
2261e4b17023SJohn Marino 	  stats.nonpointer_vars++;
2262e4b17023SJohn Marino 	  clear_edges_for_node (graph, node);
2263e4b17023SJohn Marino 	}
2264e4b17023SJohn Marino     }
2265e4b17023SJohn Marino 
2266e4b17023SJohn Marino   return si;
2267e4b17023SJohn Marino }
2268e4b17023SJohn Marino 
2269e4b17023SJohn Marino /* Free information that was only necessary for variable
2270e4b17023SJohn Marino    substitution.  */
2271e4b17023SJohn Marino 
2272e4b17023SJohn Marino static void
free_var_substitution_info(struct scc_info * si)2273e4b17023SJohn Marino free_var_substitution_info (struct scc_info *si)
2274e4b17023SJohn Marino {
2275e4b17023SJohn Marino   free_scc_info (si);
2276e4b17023SJohn Marino   free (graph->pointer_label);
2277e4b17023SJohn Marino   free (graph->loc_label);
2278e4b17023SJohn Marino   free (graph->pointed_by);
2279e4b17023SJohn Marino   free (graph->points_to);
2280e4b17023SJohn Marino   free (graph->eq_rep);
2281e4b17023SJohn Marino   sbitmap_free (graph->direct_nodes);
2282e4b17023SJohn Marino   htab_delete (pointer_equiv_class_table);
2283e4b17023SJohn Marino   htab_delete (location_equiv_class_table);
2284e4b17023SJohn Marino   bitmap_obstack_release (&iteration_obstack);
2285e4b17023SJohn Marino }
2286e4b17023SJohn Marino 
2287e4b17023SJohn Marino /* Return an existing node that is equivalent to NODE, which has
2288e4b17023SJohn Marino    equivalence class LABEL, if one exists.  Return NODE otherwise.  */
2289e4b17023SJohn Marino 
2290e4b17023SJohn Marino static unsigned int
find_equivalent_node(constraint_graph_t graph,unsigned int node,unsigned int label)2291e4b17023SJohn Marino find_equivalent_node (constraint_graph_t graph,
2292e4b17023SJohn Marino 		      unsigned int node, unsigned int label)
2293e4b17023SJohn Marino {
2294e4b17023SJohn Marino   /* If the address version of this variable is unused, we can
2295e4b17023SJohn Marino      substitute it for anything else with the same label.
2296e4b17023SJohn Marino      Otherwise, we know the pointers are equivalent, but not the
2297e4b17023SJohn Marino      locations, and we can unite them later.  */
2298e4b17023SJohn Marino 
2299e4b17023SJohn Marino   if (!bitmap_bit_p (graph->address_taken, node))
2300e4b17023SJohn Marino     {
2301e4b17023SJohn Marino       gcc_assert (label < graph->size);
2302e4b17023SJohn Marino 
2303e4b17023SJohn Marino       if (graph->eq_rep[label] != -1)
2304e4b17023SJohn Marino 	{
2305e4b17023SJohn Marino 	  /* Unify the two variables since we know they are equivalent.  */
2306e4b17023SJohn Marino 	  if (unite (graph->eq_rep[label], node))
2307e4b17023SJohn Marino 	    unify_nodes (graph, graph->eq_rep[label], node, false);
2308e4b17023SJohn Marino 	  return graph->eq_rep[label];
2309e4b17023SJohn Marino 	}
2310e4b17023SJohn Marino       else
2311e4b17023SJohn Marino 	{
2312e4b17023SJohn Marino 	  graph->eq_rep[label] = node;
2313e4b17023SJohn Marino 	  graph->pe_rep[label] = node;
2314e4b17023SJohn Marino 	}
2315e4b17023SJohn Marino     }
2316e4b17023SJohn Marino   else
2317e4b17023SJohn Marino     {
2318e4b17023SJohn Marino       gcc_assert (label < graph->size);
2319e4b17023SJohn Marino       graph->pe[node] = label;
2320e4b17023SJohn Marino       if (graph->pe_rep[label] == -1)
2321e4b17023SJohn Marino 	graph->pe_rep[label] = node;
2322e4b17023SJohn Marino     }
2323e4b17023SJohn Marino 
2324e4b17023SJohn Marino   return node;
2325e4b17023SJohn Marino }
2326e4b17023SJohn Marino 
2327e4b17023SJohn Marino /* Unite pointer equivalent but not location equivalent nodes in
2328e4b17023SJohn Marino    GRAPH.  This may only be performed once variable substitution is
2329e4b17023SJohn Marino    finished.  */
2330e4b17023SJohn Marino 
2331e4b17023SJohn Marino static void
unite_pointer_equivalences(constraint_graph_t graph)2332e4b17023SJohn Marino unite_pointer_equivalences (constraint_graph_t graph)
2333e4b17023SJohn Marino {
2334e4b17023SJohn Marino   unsigned int i;
2335e4b17023SJohn Marino 
2336e4b17023SJohn Marino   /* Go through the pointer equivalences and unite them to their
2337e4b17023SJohn Marino      representative, if they aren't already.  */
2338e4b17023SJohn Marino   for (i = 0; i < FIRST_REF_NODE; i++)
2339e4b17023SJohn Marino     {
2340e4b17023SJohn Marino       unsigned int label = graph->pe[i];
2341e4b17023SJohn Marino       if (label)
2342e4b17023SJohn Marino 	{
2343e4b17023SJohn Marino 	  int label_rep = graph->pe_rep[label];
2344e4b17023SJohn Marino 
2345e4b17023SJohn Marino 	  if (label_rep == -1)
2346e4b17023SJohn Marino 	    continue;
2347e4b17023SJohn Marino 
2348e4b17023SJohn Marino 	  label_rep = find (label_rep);
2349e4b17023SJohn Marino 	  if (label_rep >= 0 && unite (label_rep, find (i)))
2350e4b17023SJohn Marino 	    unify_nodes (graph, label_rep, i, false);
2351e4b17023SJohn Marino 	}
2352e4b17023SJohn Marino     }
2353e4b17023SJohn Marino }
2354e4b17023SJohn Marino 
2355e4b17023SJohn Marino /* Move complex constraints to the GRAPH nodes they belong to.  */
2356e4b17023SJohn Marino 
2357e4b17023SJohn Marino static void
move_complex_constraints(constraint_graph_t graph)2358e4b17023SJohn Marino move_complex_constraints (constraint_graph_t graph)
2359e4b17023SJohn Marino {
2360e4b17023SJohn Marino   int i;
2361e4b17023SJohn Marino   constraint_t c;
2362e4b17023SJohn Marino 
2363e4b17023SJohn Marino   FOR_EACH_VEC_ELT (constraint_t, constraints, i, c)
2364e4b17023SJohn Marino     {
2365e4b17023SJohn Marino       if (c)
2366e4b17023SJohn Marino 	{
2367e4b17023SJohn Marino 	  struct constraint_expr lhs = c->lhs;
2368e4b17023SJohn Marino 	  struct constraint_expr rhs = c->rhs;
2369e4b17023SJohn Marino 
2370e4b17023SJohn Marino 	  if (lhs.type == DEREF)
2371e4b17023SJohn Marino 	    {
2372e4b17023SJohn Marino 	      insert_into_complex (graph, lhs.var, c);
2373e4b17023SJohn Marino 	    }
2374e4b17023SJohn Marino 	  else if (rhs.type == DEREF)
2375e4b17023SJohn Marino 	    {
2376e4b17023SJohn Marino 	      if (!(get_varinfo (lhs.var)->is_special_var))
2377e4b17023SJohn Marino 		insert_into_complex (graph, rhs.var, c);
2378e4b17023SJohn Marino 	    }
2379e4b17023SJohn Marino 	  else if (rhs.type != ADDRESSOF && lhs.var > anything_id
2380e4b17023SJohn Marino 		   && (lhs.offset != 0 || rhs.offset != 0))
2381e4b17023SJohn Marino 	    {
2382e4b17023SJohn Marino 	      insert_into_complex (graph, rhs.var, c);
2383e4b17023SJohn Marino 	    }
2384e4b17023SJohn Marino 	}
2385e4b17023SJohn Marino     }
2386e4b17023SJohn Marino }
2387e4b17023SJohn Marino 
2388e4b17023SJohn Marino 
2389e4b17023SJohn Marino /* Optimize and rewrite complex constraints while performing
2390e4b17023SJohn Marino    collapsing of equivalent nodes.  SI is the SCC_INFO that is the
2391e4b17023SJohn Marino    result of perform_variable_substitution.  */
2392e4b17023SJohn Marino 
2393e4b17023SJohn Marino static void
rewrite_constraints(constraint_graph_t graph,struct scc_info * si)2394e4b17023SJohn Marino rewrite_constraints (constraint_graph_t graph,
2395e4b17023SJohn Marino 		     struct scc_info *si)
2396e4b17023SJohn Marino {
2397e4b17023SJohn Marino   int i;
2398e4b17023SJohn Marino   unsigned int j;
2399e4b17023SJohn Marino   constraint_t c;
2400e4b17023SJohn Marino 
2401e4b17023SJohn Marino   for (j = 0; j < graph->size; j++)
2402e4b17023SJohn Marino     gcc_assert (find (j) == j);
2403e4b17023SJohn Marino 
2404e4b17023SJohn Marino   FOR_EACH_VEC_ELT (constraint_t, constraints, i, c)
2405e4b17023SJohn Marino     {
2406e4b17023SJohn Marino       struct constraint_expr lhs = c->lhs;
2407e4b17023SJohn Marino       struct constraint_expr rhs = c->rhs;
2408e4b17023SJohn Marino       unsigned int lhsvar = find (lhs.var);
2409e4b17023SJohn Marino       unsigned int rhsvar = find (rhs.var);
2410e4b17023SJohn Marino       unsigned int lhsnode, rhsnode;
2411e4b17023SJohn Marino       unsigned int lhslabel, rhslabel;
2412e4b17023SJohn Marino 
2413e4b17023SJohn Marino       lhsnode = si->node_mapping[lhsvar];
2414e4b17023SJohn Marino       rhsnode = si->node_mapping[rhsvar];
2415e4b17023SJohn Marino       lhslabel = graph->pointer_label[lhsnode];
2416e4b17023SJohn Marino       rhslabel = graph->pointer_label[rhsnode];
2417e4b17023SJohn Marino 
2418e4b17023SJohn Marino       /* See if it is really a non-pointer variable, and if so, ignore
2419e4b17023SJohn Marino 	 the constraint.  */
2420e4b17023SJohn Marino       if (lhslabel == 0)
2421e4b17023SJohn Marino 	{
2422e4b17023SJohn Marino 	  if (dump_file && (dump_flags & TDF_DETAILS))
2423e4b17023SJohn Marino 	    {
2424e4b17023SJohn Marino 
2425e4b17023SJohn Marino 	      fprintf (dump_file, "%s is a non-pointer variable,"
2426e4b17023SJohn Marino 		       "ignoring constraint:",
2427e4b17023SJohn Marino 		       get_varinfo (lhs.var)->name);
2428e4b17023SJohn Marino 	      dump_constraint (dump_file, c);
2429e4b17023SJohn Marino 	      fprintf (dump_file, "\n");
2430e4b17023SJohn Marino 	    }
2431e4b17023SJohn Marino 	  VEC_replace (constraint_t, constraints, i, NULL);
2432e4b17023SJohn Marino 	  continue;
2433e4b17023SJohn Marino 	}
2434e4b17023SJohn Marino 
2435e4b17023SJohn Marino       if (rhslabel == 0)
2436e4b17023SJohn Marino 	{
2437e4b17023SJohn Marino 	  if (dump_file && (dump_flags & TDF_DETAILS))
2438e4b17023SJohn Marino 	    {
2439e4b17023SJohn Marino 
2440e4b17023SJohn Marino 	      fprintf (dump_file, "%s is a non-pointer variable,"
2441e4b17023SJohn Marino 		       "ignoring constraint:",
2442e4b17023SJohn Marino 		       get_varinfo (rhs.var)->name);
2443e4b17023SJohn Marino 	      dump_constraint (dump_file, c);
2444e4b17023SJohn Marino 	      fprintf (dump_file, "\n");
2445e4b17023SJohn Marino 	    }
2446e4b17023SJohn Marino 	  VEC_replace (constraint_t, constraints, i, NULL);
2447e4b17023SJohn Marino 	  continue;
2448e4b17023SJohn Marino 	}
2449e4b17023SJohn Marino 
2450e4b17023SJohn Marino       lhsvar = find_equivalent_node (graph, lhsvar, lhslabel);
2451e4b17023SJohn Marino       rhsvar = find_equivalent_node (graph, rhsvar, rhslabel);
2452e4b17023SJohn Marino       c->lhs.var = lhsvar;
2453e4b17023SJohn Marino       c->rhs.var = rhsvar;
2454e4b17023SJohn Marino 
2455e4b17023SJohn Marino     }
2456e4b17023SJohn Marino }
2457e4b17023SJohn Marino 
2458e4b17023SJohn Marino /* Eliminate indirect cycles involving NODE.  Return true if NODE was
2459e4b17023SJohn Marino    part of an SCC, false otherwise.  */
2460e4b17023SJohn Marino 
2461e4b17023SJohn Marino static bool
eliminate_indirect_cycles(unsigned int node)2462e4b17023SJohn Marino eliminate_indirect_cycles (unsigned int node)
2463e4b17023SJohn Marino {
2464e4b17023SJohn Marino   if (graph->indirect_cycles[node] != -1
2465e4b17023SJohn Marino       && !bitmap_empty_p (get_varinfo (node)->solution))
2466e4b17023SJohn Marino     {
2467e4b17023SJohn Marino       unsigned int i;
2468e4b17023SJohn Marino       VEC(unsigned,heap) *queue = NULL;
2469e4b17023SJohn Marino       int queuepos;
2470e4b17023SJohn Marino       unsigned int to = find (graph->indirect_cycles[node]);
2471e4b17023SJohn Marino       bitmap_iterator bi;
2472e4b17023SJohn Marino 
2473e4b17023SJohn Marino       /* We can't touch the solution set and call unify_nodes
2474e4b17023SJohn Marino 	 at the same time, because unify_nodes is going to do
2475e4b17023SJohn Marino 	 bitmap unions into it. */
2476e4b17023SJohn Marino 
2477e4b17023SJohn Marino       EXECUTE_IF_SET_IN_BITMAP (get_varinfo (node)->solution, 0, i, bi)
2478e4b17023SJohn Marino 	{
2479e4b17023SJohn Marino 	  if (find (i) == i && i != to)
2480e4b17023SJohn Marino 	    {
2481e4b17023SJohn Marino 	      if (unite (to, i))
2482e4b17023SJohn Marino 		VEC_safe_push (unsigned, heap, queue, i);
2483e4b17023SJohn Marino 	    }
2484e4b17023SJohn Marino 	}
2485e4b17023SJohn Marino 
2486e4b17023SJohn Marino       for (queuepos = 0;
2487e4b17023SJohn Marino 	   VEC_iterate (unsigned, queue, queuepos, i);
2488e4b17023SJohn Marino 	   queuepos++)
2489e4b17023SJohn Marino 	{
2490e4b17023SJohn Marino 	  unify_nodes (graph, to, i, true);
2491e4b17023SJohn Marino 	}
2492e4b17023SJohn Marino       VEC_free (unsigned, heap, queue);
2493e4b17023SJohn Marino       return true;
2494e4b17023SJohn Marino     }
2495e4b17023SJohn Marino   return false;
2496e4b17023SJohn Marino }
2497e4b17023SJohn Marino 
2498e4b17023SJohn Marino /* Solve the constraint graph GRAPH using our worklist solver.
2499e4b17023SJohn Marino    This is based on the PW* family of solvers from the "Efficient Field
2500e4b17023SJohn Marino    Sensitive Pointer Analysis for C" paper.
2501e4b17023SJohn Marino    It works by iterating over all the graph nodes, processing the complex
2502e4b17023SJohn Marino    constraints and propagating the copy constraints, until everything stops
2503e4b17023SJohn Marino    changed.  This corresponds to steps 6-8 in the solving list given above.  */
2504e4b17023SJohn Marino 
2505e4b17023SJohn Marino static void
solve_graph(constraint_graph_t graph)2506e4b17023SJohn Marino solve_graph (constraint_graph_t graph)
2507e4b17023SJohn Marino {
2508e4b17023SJohn Marino   unsigned int size = graph->size;
2509e4b17023SJohn Marino   unsigned int i;
2510e4b17023SJohn Marino   bitmap pts;
2511e4b17023SJohn Marino 
2512e4b17023SJohn Marino   changed = BITMAP_ALLOC (NULL);
2513e4b17023SJohn Marino 
2514e4b17023SJohn Marino   /* Mark all initial non-collapsed nodes as changed.  */
2515e4b17023SJohn Marino   for (i = 0; i < size; i++)
2516e4b17023SJohn Marino     {
2517e4b17023SJohn Marino       varinfo_t ivi = get_varinfo (i);
2518e4b17023SJohn Marino       if (find (i) == i && !bitmap_empty_p (ivi->solution)
2519e4b17023SJohn Marino 	  && ((graph->succs[i] && !bitmap_empty_p (graph->succs[i]))
2520e4b17023SJohn Marino 	      || VEC_length (constraint_t, graph->complex[i]) > 0))
2521e4b17023SJohn Marino 	bitmap_set_bit (changed, i);
2522e4b17023SJohn Marino     }
2523e4b17023SJohn Marino 
2524e4b17023SJohn Marino   /* Allocate a bitmap to be used to store the changed bits.  */
2525e4b17023SJohn Marino   pts = BITMAP_ALLOC (&pta_obstack);
2526e4b17023SJohn Marino 
2527e4b17023SJohn Marino   while (!bitmap_empty_p (changed))
2528e4b17023SJohn Marino     {
2529e4b17023SJohn Marino       unsigned int i;
2530e4b17023SJohn Marino       struct topo_info *ti = init_topo_info ();
2531e4b17023SJohn Marino       stats.iterations++;
2532e4b17023SJohn Marino 
2533e4b17023SJohn Marino       bitmap_obstack_initialize (&iteration_obstack);
2534e4b17023SJohn Marino 
2535e4b17023SJohn Marino       compute_topo_order (graph, ti);
2536e4b17023SJohn Marino 
2537e4b17023SJohn Marino       while (VEC_length (unsigned, ti->topo_order) != 0)
2538e4b17023SJohn Marino 	{
2539e4b17023SJohn Marino 
2540e4b17023SJohn Marino 	  i = VEC_pop (unsigned, ti->topo_order);
2541e4b17023SJohn Marino 
2542e4b17023SJohn Marino 	  /* If this variable is not a representative, skip it.  */
2543e4b17023SJohn Marino 	  if (find (i) != i)
2544e4b17023SJohn Marino 	    continue;
2545e4b17023SJohn Marino 
2546e4b17023SJohn Marino 	  /* In certain indirect cycle cases, we may merge this
2547e4b17023SJohn Marino 	     variable to another.  */
2548e4b17023SJohn Marino 	  if (eliminate_indirect_cycles (i) && find (i) != i)
2549e4b17023SJohn Marino 	    continue;
2550e4b17023SJohn Marino 
2551e4b17023SJohn Marino 	  /* If the node has changed, we need to process the
2552e4b17023SJohn Marino 	     complex constraints and outgoing edges again.  */
2553e4b17023SJohn Marino 	  if (bitmap_clear_bit (changed, i))
2554e4b17023SJohn Marino 	    {
2555e4b17023SJohn Marino 	      unsigned int j;
2556e4b17023SJohn Marino 	      constraint_t c;
2557e4b17023SJohn Marino 	      bitmap solution;
2558e4b17023SJohn Marino 	      VEC(constraint_t,heap) *complex = graph->complex[i];
2559e4b17023SJohn Marino 	      varinfo_t vi = get_varinfo (i);
2560e4b17023SJohn Marino 	      bool solution_empty;
2561e4b17023SJohn Marino 
2562e4b17023SJohn Marino 	      /* Compute the changed set of solution bits.  */
2563e4b17023SJohn Marino 	      if (vi->oldsolution)
2564e4b17023SJohn Marino 		bitmap_and_compl (pts, vi->solution, vi->oldsolution);
2565e4b17023SJohn Marino 	      else
2566e4b17023SJohn Marino 		bitmap_copy (pts, vi->solution);
2567e4b17023SJohn Marino 
2568e4b17023SJohn Marino 	      if (bitmap_empty_p (pts))
2569e4b17023SJohn Marino 		continue;
2570e4b17023SJohn Marino 
2571e4b17023SJohn Marino 	      if (vi->oldsolution)
2572e4b17023SJohn Marino 		bitmap_ior_into (vi->oldsolution, pts);
2573e4b17023SJohn Marino 	      else
2574e4b17023SJohn Marino 		{
2575e4b17023SJohn Marino 		  vi->oldsolution = BITMAP_ALLOC (&oldpta_obstack);
2576e4b17023SJohn Marino 		  bitmap_copy (vi->oldsolution, pts);
2577e4b17023SJohn Marino 		}
2578e4b17023SJohn Marino 
2579e4b17023SJohn Marino 	      solution = vi->solution;
2580e4b17023SJohn Marino 	      solution_empty = bitmap_empty_p (solution);
2581e4b17023SJohn Marino 
2582e4b17023SJohn Marino 	      /* Process the complex constraints */
2583e4b17023SJohn Marino 	      FOR_EACH_VEC_ELT (constraint_t, complex, j, c)
2584e4b17023SJohn Marino 		{
2585e4b17023SJohn Marino 		  /* XXX: This is going to unsort the constraints in
2586e4b17023SJohn Marino 		     some cases, which will occasionally add duplicate
2587e4b17023SJohn Marino 		     constraints during unification.  This does not
2588e4b17023SJohn Marino 		     affect correctness.  */
2589e4b17023SJohn Marino 		  c->lhs.var = find (c->lhs.var);
2590e4b17023SJohn Marino 		  c->rhs.var = find (c->rhs.var);
2591e4b17023SJohn Marino 
2592e4b17023SJohn Marino 		  /* The only complex constraint that can change our
2593e4b17023SJohn Marino 		     solution to non-empty, given an empty solution,
2594e4b17023SJohn Marino 		     is a constraint where the lhs side is receiving
2595e4b17023SJohn Marino 		     some set from elsewhere.  */
2596e4b17023SJohn Marino 		  if (!solution_empty || c->lhs.type != DEREF)
2597e4b17023SJohn Marino 		    do_complex_constraint (graph, c, pts);
2598e4b17023SJohn Marino 		}
2599e4b17023SJohn Marino 
2600e4b17023SJohn Marino 	      solution_empty = bitmap_empty_p (solution);
2601e4b17023SJohn Marino 
2602e4b17023SJohn Marino 	      if (!solution_empty)
2603e4b17023SJohn Marino 		{
2604e4b17023SJohn Marino 		  bitmap_iterator bi;
2605e4b17023SJohn Marino 		  unsigned eff_escaped_id = find (escaped_id);
2606e4b17023SJohn Marino 
2607e4b17023SJohn Marino 		  /* Propagate solution to all successors.  */
2608e4b17023SJohn Marino 		  EXECUTE_IF_IN_NONNULL_BITMAP (graph->succs[i],
2609e4b17023SJohn Marino 						0, j, bi)
2610e4b17023SJohn Marino 		    {
2611e4b17023SJohn Marino 		      bitmap tmp;
2612e4b17023SJohn Marino 		      bool flag;
2613e4b17023SJohn Marino 
2614e4b17023SJohn Marino 		      unsigned int to = find (j);
2615e4b17023SJohn Marino 		      tmp = get_varinfo (to)->solution;
2616e4b17023SJohn Marino 		      flag = false;
2617e4b17023SJohn Marino 
2618e4b17023SJohn Marino 		      /* Don't try to propagate to ourselves.  */
2619e4b17023SJohn Marino 		      if (to == i)
2620e4b17023SJohn Marino 			continue;
2621e4b17023SJohn Marino 
2622e4b17023SJohn Marino 		      /* If we propagate from ESCAPED use ESCAPED as
2623e4b17023SJohn Marino 		         placeholder.  */
2624e4b17023SJohn Marino 		      if (i == eff_escaped_id)
2625e4b17023SJohn Marino 			flag = bitmap_set_bit (tmp, escaped_id);
2626e4b17023SJohn Marino 		      else
2627e4b17023SJohn Marino 			flag = set_union_with_increment (tmp, pts, 0);
2628e4b17023SJohn Marino 
2629e4b17023SJohn Marino 		      if (flag)
2630e4b17023SJohn Marino 			{
2631e4b17023SJohn Marino 			  get_varinfo (to)->solution = tmp;
2632e4b17023SJohn Marino 			  bitmap_set_bit (changed, to);
2633e4b17023SJohn Marino 			}
2634e4b17023SJohn Marino 		    }
2635e4b17023SJohn Marino 		}
2636e4b17023SJohn Marino 	    }
2637e4b17023SJohn Marino 	}
2638e4b17023SJohn Marino       free_topo_info (ti);
2639e4b17023SJohn Marino       bitmap_obstack_release (&iteration_obstack);
2640e4b17023SJohn Marino     }
2641e4b17023SJohn Marino 
2642e4b17023SJohn Marino   BITMAP_FREE (pts);
2643e4b17023SJohn Marino   BITMAP_FREE (changed);
2644e4b17023SJohn Marino   bitmap_obstack_release (&oldpta_obstack);
2645e4b17023SJohn Marino }
2646e4b17023SJohn Marino 
2647e4b17023SJohn Marino /* Map from trees to variable infos.  */
2648e4b17023SJohn Marino static struct pointer_map_t *vi_for_tree;
2649e4b17023SJohn Marino 
2650e4b17023SJohn Marino 
2651e4b17023SJohn Marino /* Insert ID as the variable id for tree T in the vi_for_tree map.  */
2652e4b17023SJohn Marino 
2653e4b17023SJohn Marino static void
insert_vi_for_tree(tree t,varinfo_t vi)2654e4b17023SJohn Marino insert_vi_for_tree (tree t, varinfo_t vi)
2655e4b17023SJohn Marino {
2656e4b17023SJohn Marino   void **slot = pointer_map_insert (vi_for_tree, t);
2657e4b17023SJohn Marino   gcc_assert (vi);
2658e4b17023SJohn Marino   gcc_assert (*slot == NULL);
2659e4b17023SJohn Marino   *slot = vi;
2660e4b17023SJohn Marino }
2661e4b17023SJohn Marino 
2662e4b17023SJohn Marino /* Find the variable info for tree T in VI_FOR_TREE.  If T does not
2663e4b17023SJohn Marino    exist in the map, return NULL, otherwise, return the varinfo we found.  */
2664e4b17023SJohn Marino 
2665e4b17023SJohn Marino static varinfo_t
lookup_vi_for_tree(tree t)2666e4b17023SJohn Marino lookup_vi_for_tree (tree t)
2667e4b17023SJohn Marino {
2668e4b17023SJohn Marino   void **slot = pointer_map_contains (vi_for_tree, t);
2669e4b17023SJohn Marino   if (slot == NULL)
2670e4b17023SJohn Marino     return NULL;
2671e4b17023SJohn Marino 
2672e4b17023SJohn Marino   return (varinfo_t) *slot;
2673e4b17023SJohn Marino }
2674e4b17023SJohn Marino 
2675e4b17023SJohn Marino /* Return a printable name for DECL  */
2676e4b17023SJohn Marino 
2677e4b17023SJohn Marino static const char *
alias_get_name(tree decl)2678e4b17023SJohn Marino alias_get_name (tree decl)
2679e4b17023SJohn Marino {
2680e4b17023SJohn Marino   const char *res;
2681e4b17023SJohn Marino   char *temp;
2682e4b17023SJohn Marino   int num_printed = 0;
2683e4b17023SJohn Marino 
2684e4b17023SJohn Marino   if (DECL_ASSEMBLER_NAME_SET_P (decl))
2685e4b17023SJohn Marino     res = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl));
2686e4b17023SJohn Marino   else
2687e4b17023SJohn Marino     res= get_name (decl);
2688e4b17023SJohn Marino   if (res != NULL)
2689e4b17023SJohn Marino     return res;
2690e4b17023SJohn Marino 
2691e4b17023SJohn Marino   res = "NULL";
2692e4b17023SJohn Marino   if (!dump_file)
2693e4b17023SJohn Marino     return res;
2694e4b17023SJohn Marino 
2695e4b17023SJohn Marino   if (TREE_CODE (decl) == SSA_NAME)
2696e4b17023SJohn Marino     {
2697e4b17023SJohn Marino       num_printed = asprintf (&temp, "%s_%u",
2698e4b17023SJohn Marino 			      alias_get_name (SSA_NAME_VAR (decl)),
2699e4b17023SJohn Marino 			      SSA_NAME_VERSION (decl));
2700e4b17023SJohn Marino     }
2701e4b17023SJohn Marino   else if (DECL_P (decl))
2702e4b17023SJohn Marino     {
2703e4b17023SJohn Marino       num_printed = asprintf (&temp, "D.%u", DECL_UID (decl));
2704e4b17023SJohn Marino     }
2705e4b17023SJohn Marino   if (num_printed > 0)
2706e4b17023SJohn Marino     {
2707e4b17023SJohn Marino       res = ggc_strdup (temp);
2708e4b17023SJohn Marino       free (temp);
2709e4b17023SJohn Marino     }
2710e4b17023SJohn Marino   return res;
2711e4b17023SJohn Marino }
2712e4b17023SJohn Marino 
2713e4b17023SJohn Marino /* Find the variable id for tree T in the map.
2714e4b17023SJohn Marino    If T doesn't exist in the map, create an entry for it and return it.  */
2715e4b17023SJohn Marino 
2716e4b17023SJohn Marino static varinfo_t
get_vi_for_tree(tree t)2717e4b17023SJohn Marino get_vi_for_tree (tree t)
2718e4b17023SJohn Marino {
2719e4b17023SJohn Marino   void **slot = pointer_map_contains (vi_for_tree, t);
2720e4b17023SJohn Marino   if (slot == NULL)
2721e4b17023SJohn Marino     return get_varinfo (create_variable_info_for (t, alias_get_name (t)));
2722e4b17023SJohn Marino 
2723e4b17023SJohn Marino   return (varinfo_t) *slot;
2724e4b17023SJohn Marino }
2725e4b17023SJohn Marino 
2726e4b17023SJohn Marino /* Get a scalar constraint expression for a new temporary variable.  */
2727e4b17023SJohn Marino 
2728e4b17023SJohn Marino static struct constraint_expr
new_scalar_tmp_constraint_exp(const char * name)2729e4b17023SJohn Marino new_scalar_tmp_constraint_exp (const char *name)
2730e4b17023SJohn Marino {
2731e4b17023SJohn Marino   struct constraint_expr tmp;
2732e4b17023SJohn Marino   varinfo_t vi;
2733e4b17023SJohn Marino 
2734e4b17023SJohn Marino   vi = new_var_info (NULL_TREE, name);
2735e4b17023SJohn Marino   vi->offset = 0;
2736e4b17023SJohn Marino   vi->size = -1;
2737e4b17023SJohn Marino   vi->fullsize = -1;
2738e4b17023SJohn Marino   vi->is_full_var = 1;
2739e4b17023SJohn Marino 
2740e4b17023SJohn Marino   tmp.var = vi->id;
2741e4b17023SJohn Marino   tmp.type = SCALAR;
2742e4b17023SJohn Marino   tmp.offset = 0;
2743e4b17023SJohn Marino 
2744e4b17023SJohn Marino   return tmp;
2745e4b17023SJohn Marino }
2746e4b17023SJohn Marino 
2747e4b17023SJohn Marino /* Get a constraint expression vector from an SSA_VAR_P node.
2748e4b17023SJohn Marino    If address_p is true, the result will be taken its address of.  */
2749e4b17023SJohn Marino 
2750e4b17023SJohn Marino static void
get_constraint_for_ssa_var(tree t,VEC (ce_s,heap)** results,bool address_p)2751e4b17023SJohn Marino get_constraint_for_ssa_var (tree t, VEC(ce_s, heap) **results, bool address_p)
2752e4b17023SJohn Marino {
2753e4b17023SJohn Marino   struct constraint_expr cexpr;
2754e4b17023SJohn Marino   varinfo_t vi;
2755e4b17023SJohn Marino 
2756e4b17023SJohn Marino   /* We allow FUNCTION_DECLs here even though it doesn't make much sense.  */
2757e4b17023SJohn Marino   gcc_assert (SSA_VAR_P (t) || DECL_P (t));
2758e4b17023SJohn Marino 
2759e4b17023SJohn Marino   /* For parameters, get at the points-to set for the actual parm
2760e4b17023SJohn Marino      decl.  */
2761e4b17023SJohn Marino   if (TREE_CODE (t) == SSA_NAME
2762e4b17023SJohn Marino       && (TREE_CODE (SSA_NAME_VAR (t)) == PARM_DECL
2763e4b17023SJohn Marino 	  || TREE_CODE (SSA_NAME_VAR (t)) == RESULT_DECL)
2764e4b17023SJohn Marino       && SSA_NAME_IS_DEFAULT_DEF (t))
2765e4b17023SJohn Marino     {
2766e4b17023SJohn Marino       get_constraint_for_ssa_var (SSA_NAME_VAR (t), results, address_p);
2767e4b17023SJohn Marino       return;
2768e4b17023SJohn Marino     }
2769e4b17023SJohn Marino 
2770e4b17023SJohn Marino   /* For global variables resort to the alias target.  */
2771e4b17023SJohn Marino   if (TREE_CODE (t) == VAR_DECL
2772e4b17023SJohn Marino       && (TREE_STATIC (t) || DECL_EXTERNAL (t)))
2773e4b17023SJohn Marino     {
2774e4b17023SJohn Marino       struct varpool_node *node = varpool_get_node (t);
2775e4b17023SJohn Marino       if (node && node->alias)
2776e4b17023SJohn Marino 	{
2777e4b17023SJohn Marino 	  node = varpool_variable_node (node, NULL);
2778e4b17023SJohn Marino 	  t = node->decl;
2779e4b17023SJohn Marino 	}
2780e4b17023SJohn Marino     }
2781e4b17023SJohn Marino 
2782e4b17023SJohn Marino   vi = get_vi_for_tree (t);
2783e4b17023SJohn Marino   cexpr.var = vi->id;
2784e4b17023SJohn Marino   cexpr.type = SCALAR;
2785e4b17023SJohn Marino   cexpr.offset = 0;
2786e4b17023SJohn Marino   /* If we determine the result is "anything", and we know this is readonly,
2787e4b17023SJohn Marino      say it points to readonly memory instead.  */
2788e4b17023SJohn Marino   if (cexpr.var == anything_id && TREE_READONLY (t))
2789e4b17023SJohn Marino     {
2790e4b17023SJohn Marino       gcc_unreachable ();
2791e4b17023SJohn Marino       cexpr.type = ADDRESSOF;
2792e4b17023SJohn Marino       cexpr.var = readonly_id;
2793e4b17023SJohn Marino     }
2794e4b17023SJohn Marino 
2795e4b17023SJohn Marino   /* If we are not taking the address of the constraint expr, add all
2796e4b17023SJohn Marino      sub-fiels of the variable as well.  */
2797e4b17023SJohn Marino   if (!address_p
2798e4b17023SJohn Marino       && !vi->is_full_var)
2799e4b17023SJohn Marino     {
2800e4b17023SJohn Marino       for (; vi; vi = vi->next)
2801e4b17023SJohn Marino 	{
2802e4b17023SJohn Marino 	  cexpr.var = vi->id;
2803e4b17023SJohn Marino 	  VEC_safe_push (ce_s, heap, *results, &cexpr);
2804e4b17023SJohn Marino 	}
2805e4b17023SJohn Marino       return;
2806e4b17023SJohn Marino     }
2807e4b17023SJohn Marino 
2808e4b17023SJohn Marino   VEC_safe_push (ce_s, heap, *results, &cexpr);
2809e4b17023SJohn Marino }
2810e4b17023SJohn Marino 
2811e4b17023SJohn Marino /* Process constraint T, performing various simplifications and then
2812e4b17023SJohn Marino    adding it to our list of overall constraints.  */
2813e4b17023SJohn Marino 
2814e4b17023SJohn Marino static void
process_constraint(constraint_t t)2815e4b17023SJohn Marino process_constraint (constraint_t t)
2816e4b17023SJohn Marino {
2817e4b17023SJohn Marino   struct constraint_expr rhs = t->rhs;
2818e4b17023SJohn Marino   struct constraint_expr lhs = t->lhs;
2819e4b17023SJohn Marino 
2820e4b17023SJohn Marino   gcc_assert (rhs.var < VEC_length (varinfo_t, varmap));
2821e4b17023SJohn Marino   gcc_assert (lhs.var < VEC_length (varinfo_t, varmap));
2822e4b17023SJohn Marino 
2823e4b17023SJohn Marino   /* If we didn't get any useful constraint from the lhs we get
2824e4b17023SJohn Marino      &ANYTHING as fallback from get_constraint_for.  Deal with
2825e4b17023SJohn Marino      it here by turning it into *ANYTHING.  */
2826e4b17023SJohn Marino   if (lhs.type == ADDRESSOF
2827e4b17023SJohn Marino       && lhs.var == anything_id)
2828e4b17023SJohn Marino     lhs.type = DEREF;
2829e4b17023SJohn Marino 
2830e4b17023SJohn Marino   /* ADDRESSOF on the lhs is invalid.  */
2831e4b17023SJohn Marino   gcc_assert (lhs.type != ADDRESSOF);
2832e4b17023SJohn Marino 
2833e4b17023SJohn Marino   /* We shouldn't add constraints from things that cannot have pointers.
2834e4b17023SJohn Marino      It's not completely trivial to avoid in the callers, so do it here.  */
2835e4b17023SJohn Marino   if (rhs.type != ADDRESSOF
2836e4b17023SJohn Marino       && !get_varinfo (rhs.var)->may_have_pointers)
2837e4b17023SJohn Marino     return;
2838e4b17023SJohn Marino 
2839e4b17023SJohn Marino   /* Likewise adding to the solution of a non-pointer var isn't useful.  */
2840e4b17023SJohn Marino   if (!get_varinfo (lhs.var)->may_have_pointers)
2841e4b17023SJohn Marino     return;
2842e4b17023SJohn Marino 
2843e4b17023SJohn Marino   /* This can happen in our IR with things like n->a = *p */
2844e4b17023SJohn Marino   if (rhs.type == DEREF && lhs.type == DEREF && rhs.var != anything_id)
2845e4b17023SJohn Marino     {
2846e4b17023SJohn Marino       /* Split into tmp = *rhs, *lhs = tmp */
2847e4b17023SJohn Marino       struct constraint_expr tmplhs;
2848e4b17023SJohn Marino       tmplhs = new_scalar_tmp_constraint_exp ("doubledereftmp");
2849e4b17023SJohn Marino       process_constraint (new_constraint (tmplhs, rhs));
2850e4b17023SJohn Marino       process_constraint (new_constraint (lhs, tmplhs));
2851e4b17023SJohn Marino     }
2852e4b17023SJohn Marino   else if (rhs.type == ADDRESSOF && lhs.type == DEREF)
2853e4b17023SJohn Marino     {
2854e4b17023SJohn Marino       /* Split into tmp = &rhs, *lhs = tmp */
2855e4b17023SJohn Marino       struct constraint_expr tmplhs;
2856e4b17023SJohn Marino       tmplhs = new_scalar_tmp_constraint_exp ("derefaddrtmp");
2857e4b17023SJohn Marino       process_constraint (new_constraint (tmplhs, rhs));
2858e4b17023SJohn Marino       process_constraint (new_constraint (lhs, tmplhs));
2859e4b17023SJohn Marino     }
2860e4b17023SJohn Marino   else
2861e4b17023SJohn Marino     {
2862e4b17023SJohn Marino       gcc_assert (rhs.type != ADDRESSOF || rhs.offset == 0);
2863e4b17023SJohn Marino       VEC_safe_push (constraint_t, heap, constraints, t);
2864e4b17023SJohn Marino     }
2865e4b17023SJohn Marino }
2866e4b17023SJohn Marino 
2867e4b17023SJohn Marino 
2868e4b17023SJohn Marino /* Return the position, in bits, of FIELD_DECL from the beginning of its
2869e4b17023SJohn Marino    structure.  */
2870e4b17023SJohn Marino 
2871e4b17023SJohn Marino static HOST_WIDE_INT
bitpos_of_field(const tree fdecl)2872e4b17023SJohn Marino bitpos_of_field (const tree fdecl)
2873e4b17023SJohn Marino {
2874e4b17023SJohn Marino   if (!host_integerp (DECL_FIELD_OFFSET (fdecl), 0)
2875e4b17023SJohn Marino       || !host_integerp (DECL_FIELD_BIT_OFFSET (fdecl), 0))
2876e4b17023SJohn Marino     return -1;
2877e4b17023SJohn Marino 
2878e4b17023SJohn Marino   return (TREE_INT_CST_LOW (DECL_FIELD_OFFSET (fdecl)) * BITS_PER_UNIT
2879e4b17023SJohn Marino 	  + TREE_INT_CST_LOW (DECL_FIELD_BIT_OFFSET (fdecl)));
2880e4b17023SJohn Marino }
2881e4b17023SJohn Marino 
2882e4b17023SJohn Marino 
2883e4b17023SJohn Marino /* Get constraint expressions for offsetting PTR by OFFSET.  Stores the
2884e4b17023SJohn Marino    resulting constraint expressions in *RESULTS.  */
2885e4b17023SJohn Marino 
2886e4b17023SJohn Marino static void
get_constraint_for_ptr_offset(tree ptr,tree offset,VEC (ce_s,heap)** results)2887e4b17023SJohn Marino get_constraint_for_ptr_offset (tree ptr, tree offset,
2888e4b17023SJohn Marino 			       VEC (ce_s, heap) **results)
2889e4b17023SJohn Marino {
2890e4b17023SJohn Marino   struct constraint_expr c;
2891e4b17023SJohn Marino   unsigned int j, n;
2892e4b17023SJohn Marino   HOST_WIDE_INT rhsoffset;
2893e4b17023SJohn Marino 
2894e4b17023SJohn Marino   /* If we do not do field-sensitive PTA adding offsets to pointers
2895e4b17023SJohn Marino      does not change the points-to solution.  */
2896e4b17023SJohn Marino   if (!use_field_sensitive)
2897e4b17023SJohn Marino     {
2898e4b17023SJohn Marino       get_constraint_for_rhs (ptr, results);
2899e4b17023SJohn Marino       return;
2900e4b17023SJohn Marino     }
2901e4b17023SJohn Marino 
2902e4b17023SJohn Marino   /* If the offset is not a non-negative integer constant that fits
2903e4b17023SJohn Marino      in a HOST_WIDE_INT, we have to fall back to a conservative
2904e4b17023SJohn Marino      solution which includes all sub-fields of all pointed-to
2905e4b17023SJohn Marino      variables of ptr.  */
2906e4b17023SJohn Marino   if (offset == NULL_TREE
2907e4b17023SJohn Marino       || TREE_CODE (offset) != INTEGER_CST)
2908e4b17023SJohn Marino     rhsoffset = UNKNOWN_OFFSET;
2909e4b17023SJohn Marino   else
2910e4b17023SJohn Marino     {
2911e4b17023SJohn Marino       /* Sign-extend the offset.  */
2912e4b17023SJohn Marino       double_int soffset
2913e4b17023SJohn Marino 	= double_int_sext (tree_to_double_int (offset),
2914e4b17023SJohn Marino 			   TYPE_PRECISION (TREE_TYPE (offset)));
2915e4b17023SJohn Marino       if (!double_int_fits_in_shwi_p (soffset))
2916e4b17023SJohn Marino 	rhsoffset = UNKNOWN_OFFSET;
2917e4b17023SJohn Marino       else
2918e4b17023SJohn Marino 	{
2919e4b17023SJohn Marino 	  /* Make sure the bit-offset also fits.  */
2920e4b17023SJohn Marino 	  HOST_WIDE_INT rhsunitoffset = soffset.low;
2921e4b17023SJohn Marino 	  rhsoffset = rhsunitoffset * BITS_PER_UNIT;
2922e4b17023SJohn Marino 	  if (rhsunitoffset != rhsoffset / BITS_PER_UNIT)
2923e4b17023SJohn Marino 	    rhsoffset = UNKNOWN_OFFSET;
2924e4b17023SJohn Marino 	}
2925e4b17023SJohn Marino     }
2926e4b17023SJohn Marino 
2927e4b17023SJohn Marino   get_constraint_for_rhs (ptr, results);
2928e4b17023SJohn Marino   if (rhsoffset == 0)
2929e4b17023SJohn Marino     return;
2930e4b17023SJohn Marino 
2931e4b17023SJohn Marino   /* As we are eventually appending to the solution do not use
2932e4b17023SJohn Marino      VEC_iterate here.  */
2933e4b17023SJohn Marino   n = VEC_length (ce_s, *results);
2934e4b17023SJohn Marino   for (j = 0; j < n; j++)
2935e4b17023SJohn Marino     {
2936e4b17023SJohn Marino       varinfo_t curr;
2937e4b17023SJohn Marino       c = *VEC_index (ce_s, *results, j);
2938e4b17023SJohn Marino       curr = get_varinfo (c.var);
2939e4b17023SJohn Marino 
2940e4b17023SJohn Marino       if (c.type == ADDRESSOF
2941e4b17023SJohn Marino 	  /* If this varinfo represents a full variable just use it.  */
2942e4b17023SJohn Marino 	  && curr->is_full_var)
2943e4b17023SJohn Marino 	c.offset = 0;
2944e4b17023SJohn Marino       else if (c.type == ADDRESSOF
2945e4b17023SJohn Marino 	       /* If we do not know the offset add all subfields.  */
2946e4b17023SJohn Marino 	       && rhsoffset == UNKNOWN_OFFSET)
2947e4b17023SJohn Marino 	{
2948e4b17023SJohn Marino 	  varinfo_t temp = lookup_vi_for_tree (curr->decl);
2949e4b17023SJohn Marino 	  do
2950e4b17023SJohn Marino 	    {
2951e4b17023SJohn Marino 	      struct constraint_expr c2;
2952e4b17023SJohn Marino 	      c2.var = temp->id;
2953e4b17023SJohn Marino 	      c2.type = ADDRESSOF;
2954e4b17023SJohn Marino 	      c2.offset = 0;
2955e4b17023SJohn Marino 	      if (c2.var != c.var)
2956e4b17023SJohn Marino 		VEC_safe_push (ce_s, heap, *results, &c2);
2957e4b17023SJohn Marino 	      temp = temp->next;
2958e4b17023SJohn Marino 	    }
2959e4b17023SJohn Marino 	  while (temp);
2960e4b17023SJohn Marino 	}
2961e4b17023SJohn Marino       else if (c.type == ADDRESSOF)
2962e4b17023SJohn Marino 	{
2963e4b17023SJohn Marino 	  varinfo_t temp;
2964e4b17023SJohn Marino 	  unsigned HOST_WIDE_INT offset = curr->offset + rhsoffset;
2965e4b17023SJohn Marino 
2966e4b17023SJohn Marino 	  /* Search the sub-field which overlaps with the
2967e4b17023SJohn Marino 	     pointed-to offset.  If the result is outside of the variable
2968e4b17023SJohn Marino 	     we have to provide a conservative result, as the variable is
2969e4b17023SJohn Marino 	     still reachable from the resulting pointer (even though it
2970e4b17023SJohn Marino 	     technically cannot point to anything).  The last and first
2971e4b17023SJohn Marino 	     sub-fields are such conservative results.
2972e4b17023SJohn Marino 	     ???  If we always had a sub-field for &object + 1 then
2973e4b17023SJohn Marino 	     we could represent this in a more precise way.  */
2974e4b17023SJohn Marino 	  if (rhsoffset < 0
2975e4b17023SJohn Marino 	      && curr->offset < offset)
2976e4b17023SJohn Marino 	    offset = 0;
2977e4b17023SJohn Marino 	  temp = first_or_preceding_vi_for_offset (curr, offset);
2978e4b17023SJohn Marino 
2979e4b17023SJohn Marino 	  /* If the found variable is not exactly at the pointed to
2980e4b17023SJohn Marino 	     result, we have to include the next variable in the
2981e4b17023SJohn Marino 	     solution as well.  Otherwise two increments by offset / 2
2982e4b17023SJohn Marino 	     do not result in the same or a conservative superset
2983e4b17023SJohn Marino 	     solution.  */
2984e4b17023SJohn Marino 	  if (temp->offset != offset
2985e4b17023SJohn Marino 	      && temp->next != NULL)
2986e4b17023SJohn Marino 	    {
2987e4b17023SJohn Marino 	      struct constraint_expr c2;
2988e4b17023SJohn Marino 	      c2.var = temp->next->id;
2989e4b17023SJohn Marino 	      c2.type = ADDRESSOF;
2990e4b17023SJohn Marino 	      c2.offset = 0;
2991e4b17023SJohn Marino 	      VEC_safe_push (ce_s, heap, *results, &c2);
2992e4b17023SJohn Marino 	    }
2993e4b17023SJohn Marino 	  c.var = temp->id;
2994e4b17023SJohn Marino 	  c.offset = 0;
2995e4b17023SJohn Marino 	}
2996e4b17023SJohn Marino       else
2997e4b17023SJohn Marino 	c.offset = rhsoffset;
2998e4b17023SJohn Marino 
2999e4b17023SJohn Marino       VEC_replace (ce_s, *results, j, &c);
3000e4b17023SJohn Marino     }
3001e4b17023SJohn Marino }
3002e4b17023SJohn Marino 
3003e4b17023SJohn Marino 
3004e4b17023SJohn Marino /* Given a COMPONENT_REF T, return the constraint_expr vector for it.
3005e4b17023SJohn Marino    If address_p is true the result will be taken its address of.
3006e4b17023SJohn Marino    If lhs_p is true then the constraint expression is assumed to be used
3007e4b17023SJohn Marino    as the lhs.  */
3008e4b17023SJohn Marino 
3009e4b17023SJohn Marino static void
get_constraint_for_component_ref(tree t,VEC (ce_s,heap)** results,bool address_p,bool lhs_p)3010e4b17023SJohn Marino get_constraint_for_component_ref (tree t, VEC(ce_s, heap) **results,
3011e4b17023SJohn Marino 				  bool address_p, bool lhs_p)
3012e4b17023SJohn Marino {
3013e4b17023SJohn Marino   tree orig_t = t;
3014e4b17023SJohn Marino   HOST_WIDE_INT bitsize = -1;
3015e4b17023SJohn Marino   HOST_WIDE_INT bitmaxsize = -1;
3016e4b17023SJohn Marino   HOST_WIDE_INT bitpos;
3017e4b17023SJohn Marino   tree forzero;
3018e4b17023SJohn Marino   struct constraint_expr *result;
3019e4b17023SJohn Marino 
3020e4b17023SJohn Marino   /* Some people like to do cute things like take the address of
3021e4b17023SJohn Marino      &0->a.b */
3022e4b17023SJohn Marino   forzero = t;
3023e4b17023SJohn Marino   while (handled_component_p (forzero)
3024e4b17023SJohn Marino 	 || INDIRECT_REF_P (forzero)
3025e4b17023SJohn Marino 	 || TREE_CODE (forzero) == MEM_REF)
3026e4b17023SJohn Marino     forzero = TREE_OPERAND (forzero, 0);
3027e4b17023SJohn Marino 
3028e4b17023SJohn Marino   if (CONSTANT_CLASS_P (forzero) && integer_zerop (forzero))
3029e4b17023SJohn Marino     {
3030e4b17023SJohn Marino       struct constraint_expr temp;
3031e4b17023SJohn Marino 
3032e4b17023SJohn Marino       temp.offset = 0;
3033e4b17023SJohn Marino       temp.var = integer_id;
3034e4b17023SJohn Marino       temp.type = SCALAR;
3035e4b17023SJohn Marino       VEC_safe_push (ce_s, heap, *results, &temp);
3036e4b17023SJohn Marino       return;
3037e4b17023SJohn Marino     }
3038e4b17023SJohn Marino 
3039e4b17023SJohn Marino   /* Handle type-punning through unions.  If we are extracting a pointer
3040e4b17023SJohn Marino      from a union via a possibly type-punning access that pointer
3041e4b17023SJohn Marino      points to anything, similar to a conversion of an integer to
3042e4b17023SJohn Marino      a pointer.  */
3043e4b17023SJohn Marino   if (!lhs_p)
3044e4b17023SJohn Marino     {
3045e4b17023SJohn Marino       tree u;
3046e4b17023SJohn Marino       for (u = t;
3047e4b17023SJohn Marino 	   TREE_CODE (u) == COMPONENT_REF || TREE_CODE (u) == ARRAY_REF;
3048e4b17023SJohn Marino 	   u = TREE_OPERAND (u, 0))
3049e4b17023SJohn Marino 	if (TREE_CODE (u) == COMPONENT_REF
3050e4b17023SJohn Marino 	    && TREE_CODE (TREE_TYPE (TREE_OPERAND (u, 0))) == UNION_TYPE)
3051e4b17023SJohn Marino 	  {
3052e4b17023SJohn Marino 	    struct constraint_expr temp;
3053e4b17023SJohn Marino 
3054e4b17023SJohn Marino 	    temp.offset = 0;
3055e4b17023SJohn Marino 	    temp.var = anything_id;
3056e4b17023SJohn Marino 	    temp.type = ADDRESSOF;
3057e4b17023SJohn Marino 	    VEC_safe_push (ce_s, heap, *results, &temp);
3058e4b17023SJohn Marino 	    return;
3059e4b17023SJohn Marino 	  }
3060e4b17023SJohn Marino     }
3061e4b17023SJohn Marino 
3062e4b17023SJohn Marino   t = get_ref_base_and_extent (t, &bitpos, &bitsize, &bitmaxsize);
3063e4b17023SJohn Marino 
3064e4b17023SJohn Marino   /* Pretend to take the address of the base, we'll take care of
3065e4b17023SJohn Marino      adding the required subset of sub-fields below.  */
3066e4b17023SJohn Marino   get_constraint_for_1 (t, results, true, lhs_p);
3067e4b17023SJohn Marino   gcc_assert (VEC_length (ce_s, *results) == 1);
3068e4b17023SJohn Marino   result = VEC_last (ce_s, *results);
3069e4b17023SJohn Marino 
3070e4b17023SJohn Marino   if (result->type == SCALAR
3071e4b17023SJohn Marino       && get_varinfo (result->var)->is_full_var)
3072e4b17023SJohn Marino     /* For single-field vars do not bother about the offset.  */
3073e4b17023SJohn Marino     result->offset = 0;
3074e4b17023SJohn Marino   else if (result->type == SCALAR)
3075e4b17023SJohn Marino     {
3076e4b17023SJohn Marino       /* In languages like C, you can access one past the end of an
3077e4b17023SJohn Marino 	 array.  You aren't allowed to dereference it, so we can
3078e4b17023SJohn Marino 	 ignore this constraint. When we handle pointer subtraction,
3079e4b17023SJohn Marino 	 we may have to do something cute here.  */
3080e4b17023SJohn Marino 
3081e4b17023SJohn Marino       if ((unsigned HOST_WIDE_INT)bitpos < get_varinfo (result->var)->fullsize
3082e4b17023SJohn Marino 	  && bitmaxsize != 0)
3083e4b17023SJohn Marino 	{
3084e4b17023SJohn Marino 	  /* It's also not true that the constraint will actually start at the
3085e4b17023SJohn Marino 	     right offset, it may start in some padding.  We only care about
3086e4b17023SJohn Marino 	     setting the constraint to the first actual field it touches, so
3087e4b17023SJohn Marino 	     walk to find it.  */
3088e4b17023SJohn Marino 	  struct constraint_expr cexpr = *result;
3089e4b17023SJohn Marino 	  varinfo_t curr;
3090e4b17023SJohn Marino 	  VEC_pop (ce_s, *results);
3091e4b17023SJohn Marino 	  cexpr.offset = 0;
3092e4b17023SJohn Marino 	  for (curr = get_varinfo (cexpr.var); curr; curr = curr->next)
3093e4b17023SJohn Marino 	    {
3094e4b17023SJohn Marino 	      if (ranges_overlap_p (curr->offset, curr->size,
3095e4b17023SJohn Marino 				    bitpos, bitmaxsize))
3096e4b17023SJohn Marino 		{
3097e4b17023SJohn Marino 		  cexpr.var = curr->id;
3098e4b17023SJohn Marino 		  VEC_safe_push (ce_s, heap, *results, &cexpr);
3099e4b17023SJohn Marino 		  if (address_p)
3100e4b17023SJohn Marino 		    break;
3101e4b17023SJohn Marino 		}
3102e4b17023SJohn Marino 	    }
3103e4b17023SJohn Marino 	  /* If we are going to take the address of this field then
3104e4b17023SJohn Marino 	     to be able to compute reachability correctly add at least
3105e4b17023SJohn Marino 	     the last field of the variable.  */
3106e4b17023SJohn Marino 	  if (address_p
3107e4b17023SJohn Marino 	      && VEC_length (ce_s, *results) == 0)
3108e4b17023SJohn Marino 	    {
3109e4b17023SJohn Marino 	      curr = get_varinfo (cexpr.var);
3110e4b17023SJohn Marino 	      while (curr->next != NULL)
3111e4b17023SJohn Marino 		curr = curr->next;
3112e4b17023SJohn Marino 	      cexpr.var = curr->id;
3113e4b17023SJohn Marino 	      VEC_safe_push (ce_s, heap, *results, &cexpr);
3114e4b17023SJohn Marino 	    }
3115e4b17023SJohn Marino 	  else if (VEC_length (ce_s, *results) == 0)
3116e4b17023SJohn Marino 	    /* Assert that we found *some* field there. The user couldn't be
3117e4b17023SJohn Marino 	       accessing *only* padding.  */
3118e4b17023SJohn Marino 	    /* Still the user could access one past the end of an array
3119e4b17023SJohn Marino 	       embedded in a struct resulting in accessing *only* padding.  */
3120e4b17023SJohn Marino 	    /* Or accessing only padding via type-punning to a type
3121e4b17023SJohn Marino 	       that has a filed just in padding space.  */
3122e4b17023SJohn Marino 	    {
3123e4b17023SJohn Marino 	      cexpr.type = SCALAR;
3124e4b17023SJohn Marino 	      cexpr.var = anything_id;
3125e4b17023SJohn Marino 	      cexpr.offset = 0;
3126e4b17023SJohn Marino 	      VEC_safe_push (ce_s, heap, *results, &cexpr);
3127e4b17023SJohn Marino 	    }
3128e4b17023SJohn Marino 	}
3129e4b17023SJohn Marino       else if (bitmaxsize == 0)
3130e4b17023SJohn Marino 	{
3131e4b17023SJohn Marino 	  if (dump_file && (dump_flags & TDF_DETAILS))
3132e4b17023SJohn Marino 	    fprintf (dump_file, "Access to zero-sized part of variable,"
3133e4b17023SJohn Marino 		     "ignoring\n");
3134e4b17023SJohn Marino 	}
3135e4b17023SJohn Marino       else
3136e4b17023SJohn Marino 	if (dump_file && (dump_flags & TDF_DETAILS))
3137e4b17023SJohn Marino 	  fprintf (dump_file, "Access to past the end of variable, ignoring\n");
3138e4b17023SJohn Marino     }
3139e4b17023SJohn Marino   else if (result->type == DEREF)
3140e4b17023SJohn Marino     {
3141e4b17023SJohn Marino       /* If we do not know exactly where the access goes say so.  Note
3142e4b17023SJohn Marino 	 that only for non-structure accesses we know that we access
3143e4b17023SJohn Marino 	 at most one subfiled of any variable.  */
3144e4b17023SJohn Marino       if (bitpos == -1
3145e4b17023SJohn Marino 	  || bitsize != bitmaxsize
3146e4b17023SJohn Marino 	  || AGGREGATE_TYPE_P (TREE_TYPE (orig_t))
3147e4b17023SJohn Marino 	  || result->offset == UNKNOWN_OFFSET)
3148e4b17023SJohn Marino 	result->offset = UNKNOWN_OFFSET;
3149e4b17023SJohn Marino       else
3150e4b17023SJohn Marino 	result->offset += bitpos;
3151e4b17023SJohn Marino     }
3152e4b17023SJohn Marino   else if (result->type == ADDRESSOF)
3153e4b17023SJohn Marino     {
3154e4b17023SJohn Marino       /* We can end up here for component references on a
3155e4b17023SJohn Marino          VIEW_CONVERT_EXPR <>(&foobar).  */
3156e4b17023SJohn Marino       result->type = SCALAR;
3157e4b17023SJohn Marino       result->var = anything_id;
3158e4b17023SJohn Marino       result->offset = 0;
3159e4b17023SJohn Marino     }
3160e4b17023SJohn Marino   else
3161e4b17023SJohn Marino     gcc_unreachable ();
3162e4b17023SJohn Marino }
3163e4b17023SJohn Marino 
3164e4b17023SJohn Marino 
3165e4b17023SJohn Marino /* Dereference the constraint expression CONS, and return the result.
3166e4b17023SJohn Marino    DEREF (ADDRESSOF) = SCALAR
3167e4b17023SJohn Marino    DEREF (SCALAR) = DEREF
3168e4b17023SJohn Marino    DEREF (DEREF) = (temp = DEREF1; result = DEREF(temp))
3169e4b17023SJohn Marino    This is needed so that we can handle dereferencing DEREF constraints.  */
3170e4b17023SJohn Marino 
3171e4b17023SJohn Marino static void
do_deref(VEC (ce_s,heap)** constraints)3172e4b17023SJohn Marino do_deref (VEC (ce_s, heap) **constraints)
3173e4b17023SJohn Marino {
3174e4b17023SJohn Marino   struct constraint_expr *c;
3175e4b17023SJohn Marino   unsigned int i = 0;
3176e4b17023SJohn Marino 
3177e4b17023SJohn Marino   FOR_EACH_VEC_ELT (ce_s, *constraints, i, c)
3178e4b17023SJohn Marino     {
3179e4b17023SJohn Marino       if (c->type == SCALAR)
3180e4b17023SJohn Marino 	c->type = DEREF;
3181e4b17023SJohn Marino       else if (c->type == ADDRESSOF)
3182e4b17023SJohn Marino 	c->type = SCALAR;
3183e4b17023SJohn Marino       else if (c->type == DEREF)
3184e4b17023SJohn Marino 	{
3185e4b17023SJohn Marino 	  struct constraint_expr tmplhs;
3186e4b17023SJohn Marino 	  tmplhs = new_scalar_tmp_constraint_exp ("dereftmp");
3187e4b17023SJohn Marino 	  process_constraint (new_constraint (tmplhs, *c));
3188e4b17023SJohn Marino 	  c->var = tmplhs.var;
3189e4b17023SJohn Marino 	}
3190e4b17023SJohn Marino       else
3191e4b17023SJohn Marino 	gcc_unreachable ();
3192e4b17023SJohn Marino     }
3193e4b17023SJohn Marino }
3194e4b17023SJohn Marino 
3195e4b17023SJohn Marino /* Given a tree T, return the constraint expression for taking the
3196e4b17023SJohn Marino    address of it.  */
3197e4b17023SJohn Marino 
3198e4b17023SJohn Marino static void
get_constraint_for_address_of(tree t,VEC (ce_s,heap)** results)3199e4b17023SJohn Marino get_constraint_for_address_of (tree t, VEC (ce_s, heap) **results)
3200e4b17023SJohn Marino {
3201e4b17023SJohn Marino   struct constraint_expr *c;
3202e4b17023SJohn Marino   unsigned int i;
3203e4b17023SJohn Marino 
3204e4b17023SJohn Marino   get_constraint_for_1 (t, results, true, true);
3205e4b17023SJohn Marino 
3206e4b17023SJohn Marino   FOR_EACH_VEC_ELT (ce_s, *results, i, c)
3207e4b17023SJohn Marino     {
3208e4b17023SJohn Marino       if (c->type == DEREF)
3209e4b17023SJohn Marino 	c->type = SCALAR;
3210e4b17023SJohn Marino       else
3211e4b17023SJohn Marino 	c->type = ADDRESSOF;
3212e4b17023SJohn Marino     }
3213e4b17023SJohn Marino }
3214e4b17023SJohn Marino 
3215e4b17023SJohn Marino /* Given a tree T, return the constraint expression for it.  */
3216e4b17023SJohn Marino 
3217e4b17023SJohn Marino static void
get_constraint_for_1(tree t,VEC (ce_s,heap)** results,bool address_p,bool lhs_p)3218e4b17023SJohn Marino get_constraint_for_1 (tree t, VEC (ce_s, heap) **results, bool address_p,
3219e4b17023SJohn Marino 		      bool lhs_p)
3220e4b17023SJohn Marino {
3221e4b17023SJohn Marino   struct constraint_expr temp;
3222e4b17023SJohn Marino 
3223e4b17023SJohn Marino   /* x = integer is all glommed to a single variable, which doesn't
3224e4b17023SJohn Marino      point to anything by itself.  That is, of course, unless it is an
3225e4b17023SJohn Marino      integer constant being treated as a pointer, in which case, we
3226e4b17023SJohn Marino      will return that this is really the addressof anything.  This
3227e4b17023SJohn Marino      happens below, since it will fall into the default case. The only
3228e4b17023SJohn Marino      case we know something about an integer treated like a pointer is
3229e4b17023SJohn Marino      when it is the NULL pointer, and then we just say it points to
3230e4b17023SJohn Marino      NULL.
3231e4b17023SJohn Marino 
3232e4b17023SJohn Marino      Do not do that if -fno-delete-null-pointer-checks though, because
3233e4b17023SJohn Marino      in that case *NULL does not fail, so it _should_ alias *anything.
3234e4b17023SJohn Marino      It is not worth adding a new option or renaming the existing one,
3235e4b17023SJohn Marino      since this case is relatively obscure.  */
3236e4b17023SJohn Marino   if ((TREE_CODE (t) == INTEGER_CST
3237e4b17023SJohn Marino        && integer_zerop (t))
3238e4b17023SJohn Marino       /* The only valid CONSTRUCTORs in gimple with pointer typed
3239e4b17023SJohn Marino 	 elements are zero-initializer.  But in IPA mode we also
3240e4b17023SJohn Marino 	 process global initializers, so verify at least.  */
3241e4b17023SJohn Marino       || (TREE_CODE (t) == CONSTRUCTOR
3242e4b17023SJohn Marino 	  && CONSTRUCTOR_NELTS (t) == 0))
3243e4b17023SJohn Marino     {
3244e4b17023SJohn Marino       if (flag_delete_null_pointer_checks)
3245e4b17023SJohn Marino 	temp.var = nothing_id;
3246e4b17023SJohn Marino       else
3247e4b17023SJohn Marino 	temp.var = nonlocal_id;
3248e4b17023SJohn Marino       temp.type = ADDRESSOF;
3249e4b17023SJohn Marino       temp.offset = 0;
3250e4b17023SJohn Marino       VEC_safe_push (ce_s, heap, *results, &temp);
3251e4b17023SJohn Marino       return;
3252e4b17023SJohn Marino     }
3253e4b17023SJohn Marino 
3254e4b17023SJohn Marino   /* String constants are read-only.  */
3255e4b17023SJohn Marino   if (TREE_CODE (t) == STRING_CST)
3256e4b17023SJohn Marino     {
3257e4b17023SJohn Marino       temp.var = readonly_id;
3258e4b17023SJohn Marino       temp.type = SCALAR;
3259e4b17023SJohn Marino       temp.offset = 0;
3260e4b17023SJohn Marino       VEC_safe_push (ce_s, heap, *results, &temp);
3261e4b17023SJohn Marino       return;
3262e4b17023SJohn Marino     }
3263e4b17023SJohn Marino 
3264e4b17023SJohn Marino   switch (TREE_CODE_CLASS (TREE_CODE (t)))
3265e4b17023SJohn Marino     {
3266e4b17023SJohn Marino     case tcc_expression:
3267e4b17023SJohn Marino       {
3268e4b17023SJohn Marino 	switch (TREE_CODE (t))
3269e4b17023SJohn Marino 	  {
3270e4b17023SJohn Marino 	  case ADDR_EXPR:
3271e4b17023SJohn Marino 	    get_constraint_for_address_of (TREE_OPERAND (t, 0), results);
3272e4b17023SJohn Marino 	    return;
3273e4b17023SJohn Marino 	  default:;
3274e4b17023SJohn Marino 	  }
3275e4b17023SJohn Marino 	break;
3276e4b17023SJohn Marino       }
3277e4b17023SJohn Marino     case tcc_reference:
3278e4b17023SJohn Marino       {
3279e4b17023SJohn Marino 	switch (TREE_CODE (t))
3280e4b17023SJohn Marino 	  {
3281e4b17023SJohn Marino 	  case MEM_REF:
3282e4b17023SJohn Marino 	    {
3283e4b17023SJohn Marino 	      struct constraint_expr cs;
3284e4b17023SJohn Marino 	      varinfo_t vi, curr;
3285e4b17023SJohn Marino 	      get_constraint_for_ptr_offset (TREE_OPERAND (t, 0),
3286e4b17023SJohn Marino 					     TREE_OPERAND (t, 1), results);
3287e4b17023SJohn Marino 	      do_deref (results);
3288e4b17023SJohn Marino 
3289e4b17023SJohn Marino 	      /* If we are not taking the address then make sure to process
3290e4b17023SJohn Marino 		 all subvariables we might access.  */
3291e4b17023SJohn Marino 	      if (address_p)
3292e4b17023SJohn Marino 		return;
3293e4b17023SJohn Marino 
3294e4b17023SJohn Marino 	      cs = *VEC_last (ce_s, *results);
3295e4b17023SJohn Marino 	      if (cs.type == DEREF
3296e4b17023SJohn Marino 		  && type_can_have_subvars (TREE_TYPE (t)))
3297e4b17023SJohn Marino 		{
3298e4b17023SJohn Marino 		  /* For dereferences this means we have to defer it
3299e4b17023SJohn Marino 		     to solving time.  */
3300e4b17023SJohn Marino 		  VEC_last (ce_s, *results)->offset = UNKNOWN_OFFSET;
3301e4b17023SJohn Marino 		  return;
3302e4b17023SJohn Marino 		}
3303e4b17023SJohn Marino 	      if (cs.type != SCALAR)
3304e4b17023SJohn Marino 		return;
3305e4b17023SJohn Marino 
3306e4b17023SJohn Marino 	      vi = get_varinfo (cs.var);
3307e4b17023SJohn Marino 	      curr = vi->next;
3308e4b17023SJohn Marino 	      if (!vi->is_full_var
3309e4b17023SJohn Marino 		  && curr)
3310e4b17023SJohn Marino 		{
3311e4b17023SJohn Marino 		  unsigned HOST_WIDE_INT size;
3312e4b17023SJohn Marino 		  if (host_integerp (TYPE_SIZE (TREE_TYPE (t)), 1))
3313e4b17023SJohn Marino 		    size = TREE_INT_CST_LOW (TYPE_SIZE (TREE_TYPE (t)));
3314e4b17023SJohn Marino 		  else
3315e4b17023SJohn Marino 		    size = -1;
3316e4b17023SJohn Marino 		  for (; curr; curr = curr->next)
3317e4b17023SJohn Marino 		    {
3318e4b17023SJohn Marino 		      if (curr->offset - vi->offset < size)
3319e4b17023SJohn Marino 			{
3320e4b17023SJohn Marino 			  cs.var = curr->id;
3321e4b17023SJohn Marino 			  VEC_safe_push (ce_s, heap, *results, &cs);
3322e4b17023SJohn Marino 			}
3323e4b17023SJohn Marino 		      else
3324e4b17023SJohn Marino 			break;
3325e4b17023SJohn Marino 		    }
3326e4b17023SJohn Marino 		}
3327e4b17023SJohn Marino 	      return;
3328e4b17023SJohn Marino 	    }
3329e4b17023SJohn Marino 	  case ARRAY_REF:
3330e4b17023SJohn Marino 	  case ARRAY_RANGE_REF:
3331e4b17023SJohn Marino 	  case COMPONENT_REF:
3332e4b17023SJohn Marino 	    get_constraint_for_component_ref (t, results, address_p, lhs_p);
3333e4b17023SJohn Marino 	    return;
3334e4b17023SJohn Marino 	  case VIEW_CONVERT_EXPR:
3335e4b17023SJohn Marino 	    get_constraint_for_1 (TREE_OPERAND (t, 0), results, address_p,
3336e4b17023SJohn Marino 				  lhs_p);
3337e4b17023SJohn Marino 	    return;
3338e4b17023SJohn Marino 	  /* We are missing handling for TARGET_MEM_REF here.  */
3339e4b17023SJohn Marino 	  default:;
3340e4b17023SJohn Marino 	  }
3341e4b17023SJohn Marino 	break;
3342e4b17023SJohn Marino       }
3343e4b17023SJohn Marino     case tcc_exceptional:
3344e4b17023SJohn Marino       {
3345e4b17023SJohn Marino 	switch (TREE_CODE (t))
3346e4b17023SJohn Marino 	  {
3347e4b17023SJohn Marino 	  case SSA_NAME:
3348e4b17023SJohn Marino 	    {
3349e4b17023SJohn Marino 	      get_constraint_for_ssa_var (t, results, address_p);
3350e4b17023SJohn Marino 	      return;
3351e4b17023SJohn Marino 	    }
3352e4b17023SJohn Marino 	  case CONSTRUCTOR:
3353e4b17023SJohn Marino 	    {
3354e4b17023SJohn Marino 	      unsigned int i;
3355e4b17023SJohn Marino 	      tree val;
3356e4b17023SJohn Marino 	      VEC (ce_s, heap) *tmp = NULL;
3357e4b17023SJohn Marino 	      FOR_EACH_CONSTRUCTOR_VALUE (CONSTRUCTOR_ELTS (t), i, val)
3358e4b17023SJohn Marino 		{
3359e4b17023SJohn Marino 		  struct constraint_expr *rhsp;
3360e4b17023SJohn Marino 		  unsigned j;
3361e4b17023SJohn Marino 		  get_constraint_for_1 (val, &tmp, address_p, lhs_p);
3362e4b17023SJohn Marino 		  FOR_EACH_VEC_ELT (ce_s, tmp, j, rhsp)
3363e4b17023SJohn Marino 		    VEC_safe_push (ce_s, heap, *results, rhsp);
3364e4b17023SJohn Marino 		  VEC_truncate (ce_s, tmp, 0);
3365e4b17023SJohn Marino 		}
3366e4b17023SJohn Marino 	      VEC_free (ce_s, heap, tmp);
3367e4b17023SJohn Marino 	      /* We do not know whether the constructor was complete,
3368e4b17023SJohn Marino 	         so technically we have to add &NOTHING or &ANYTHING
3369e4b17023SJohn Marino 		 like we do for an empty constructor as well.  */
3370e4b17023SJohn Marino 	      return;
3371e4b17023SJohn Marino 	    }
3372e4b17023SJohn Marino 	  default:;
3373e4b17023SJohn Marino 	  }
3374e4b17023SJohn Marino 	break;
3375e4b17023SJohn Marino       }
3376e4b17023SJohn Marino     case tcc_declaration:
3377e4b17023SJohn Marino       {
3378e4b17023SJohn Marino 	get_constraint_for_ssa_var (t, results, address_p);
3379e4b17023SJohn Marino 	return;
3380e4b17023SJohn Marino       }
3381e4b17023SJohn Marino     case tcc_constant:
3382e4b17023SJohn Marino       {
3383e4b17023SJohn Marino 	/* We cannot refer to automatic variables through constants.  */
3384e4b17023SJohn Marino 	temp.type = ADDRESSOF;
3385e4b17023SJohn Marino 	temp.var = nonlocal_id;
3386e4b17023SJohn Marino 	temp.offset = 0;
3387e4b17023SJohn Marino 	VEC_safe_push (ce_s, heap, *results, &temp);
3388e4b17023SJohn Marino 	return;
3389e4b17023SJohn Marino       }
3390e4b17023SJohn Marino     default:;
3391e4b17023SJohn Marino     }
3392e4b17023SJohn Marino 
3393e4b17023SJohn Marino   /* The default fallback is a constraint from anything.  */
3394e4b17023SJohn Marino   temp.type = ADDRESSOF;
3395e4b17023SJohn Marino   temp.var = anything_id;
3396e4b17023SJohn Marino   temp.offset = 0;
3397e4b17023SJohn Marino   VEC_safe_push (ce_s, heap, *results, &temp);
3398e4b17023SJohn Marino }
3399e4b17023SJohn Marino 
3400e4b17023SJohn Marino /* Given a gimple tree T, return the constraint expression vector for it.  */
3401e4b17023SJohn Marino 
3402e4b17023SJohn Marino static void
get_constraint_for(tree t,VEC (ce_s,heap)** results)3403e4b17023SJohn Marino get_constraint_for (tree t, VEC (ce_s, heap) **results)
3404e4b17023SJohn Marino {
3405e4b17023SJohn Marino   gcc_assert (VEC_length (ce_s, *results) == 0);
3406e4b17023SJohn Marino 
3407e4b17023SJohn Marino   get_constraint_for_1 (t, results, false, true);
3408e4b17023SJohn Marino }
3409e4b17023SJohn Marino 
3410e4b17023SJohn Marino /* Given a gimple tree T, return the constraint expression vector for it
3411e4b17023SJohn Marino    to be used as the rhs of a constraint.  */
3412e4b17023SJohn Marino 
3413e4b17023SJohn Marino static void
get_constraint_for_rhs(tree t,VEC (ce_s,heap)** results)3414e4b17023SJohn Marino get_constraint_for_rhs (tree t, VEC (ce_s, heap) **results)
3415e4b17023SJohn Marino {
3416e4b17023SJohn Marino   gcc_assert (VEC_length (ce_s, *results) == 0);
3417e4b17023SJohn Marino 
3418e4b17023SJohn Marino   get_constraint_for_1 (t, results, false, false);
3419e4b17023SJohn Marino }
3420e4b17023SJohn Marino 
3421e4b17023SJohn Marino 
3422e4b17023SJohn Marino /* Efficiently generates constraints from all entries in *RHSC to all
3423e4b17023SJohn Marino    entries in *LHSC.  */
3424e4b17023SJohn Marino 
3425e4b17023SJohn Marino static void
process_all_all_constraints(VEC (ce_s,heap)* lhsc,VEC (ce_s,heap)* rhsc)3426e4b17023SJohn Marino process_all_all_constraints (VEC (ce_s, heap) *lhsc, VEC (ce_s, heap) *rhsc)
3427e4b17023SJohn Marino {
3428e4b17023SJohn Marino   struct constraint_expr *lhsp, *rhsp;
3429e4b17023SJohn Marino   unsigned i, j;
3430e4b17023SJohn Marino 
3431e4b17023SJohn Marino   if (VEC_length (ce_s, lhsc) <= 1
3432e4b17023SJohn Marino       || VEC_length (ce_s, rhsc) <= 1)
3433e4b17023SJohn Marino     {
3434e4b17023SJohn Marino       FOR_EACH_VEC_ELT (ce_s, lhsc, i, lhsp)
3435e4b17023SJohn Marino 	FOR_EACH_VEC_ELT (ce_s, rhsc, j, rhsp)
3436e4b17023SJohn Marino 	  process_constraint (new_constraint (*lhsp, *rhsp));
3437e4b17023SJohn Marino     }
3438e4b17023SJohn Marino   else
3439e4b17023SJohn Marino     {
3440e4b17023SJohn Marino       struct constraint_expr tmp;
3441e4b17023SJohn Marino       tmp = new_scalar_tmp_constraint_exp ("allalltmp");
3442e4b17023SJohn Marino       FOR_EACH_VEC_ELT (ce_s, rhsc, i, rhsp)
3443e4b17023SJohn Marino 	process_constraint (new_constraint (tmp, *rhsp));
3444e4b17023SJohn Marino       FOR_EACH_VEC_ELT (ce_s, lhsc, i, lhsp)
3445e4b17023SJohn Marino 	process_constraint (new_constraint (*lhsp, tmp));
3446e4b17023SJohn Marino     }
3447e4b17023SJohn Marino }
3448e4b17023SJohn Marino 
3449e4b17023SJohn Marino /* Handle aggregate copies by expanding into copies of the respective
3450e4b17023SJohn Marino    fields of the structures.  */
3451e4b17023SJohn Marino 
3452e4b17023SJohn Marino static void
do_structure_copy(tree lhsop,tree rhsop)3453e4b17023SJohn Marino do_structure_copy (tree lhsop, tree rhsop)
3454e4b17023SJohn Marino {
3455e4b17023SJohn Marino   struct constraint_expr *lhsp, *rhsp;
3456e4b17023SJohn Marino   VEC (ce_s, heap) *lhsc = NULL, *rhsc = NULL;
3457e4b17023SJohn Marino   unsigned j;
3458e4b17023SJohn Marino 
3459e4b17023SJohn Marino   get_constraint_for (lhsop, &lhsc);
3460e4b17023SJohn Marino   get_constraint_for_rhs (rhsop, &rhsc);
3461e4b17023SJohn Marino   lhsp = VEC_index (ce_s, lhsc, 0);
3462e4b17023SJohn Marino   rhsp = VEC_index (ce_s, rhsc, 0);
3463e4b17023SJohn Marino   if (lhsp->type == DEREF
3464e4b17023SJohn Marino       || (lhsp->type == ADDRESSOF && lhsp->var == anything_id)
3465e4b17023SJohn Marino       || rhsp->type == DEREF)
3466e4b17023SJohn Marino     {
3467e4b17023SJohn Marino       if (lhsp->type == DEREF)
3468e4b17023SJohn Marino 	{
3469e4b17023SJohn Marino 	  gcc_assert (VEC_length (ce_s, lhsc) == 1);
3470e4b17023SJohn Marino 	  lhsp->offset = UNKNOWN_OFFSET;
3471e4b17023SJohn Marino 	}
3472e4b17023SJohn Marino       if (rhsp->type == DEREF)
3473e4b17023SJohn Marino 	{
3474e4b17023SJohn Marino 	  gcc_assert (VEC_length (ce_s, rhsc) == 1);
3475e4b17023SJohn Marino 	  rhsp->offset = UNKNOWN_OFFSET;
3476e4b17023SJohn Marino 	}
3477e4b17023SJohn Marino       process_all_all_constraints (lhsc, rhsc);
3478e4b17023SJohn Marino     }
3479e4b17023SJohn Marino   else if (lhsp->type == SCALAR
3480e4b17023SJohn Marino 	   && (rhsp->type == SCALAR
3481e4b17023SJohn Marino 	       || rhsp->type == ADDRESSOF))
3482e4b17023SJohn Marino     {
3483e4b17023SJohn Marino       HOST_WIDE_INT lhssize, lhsmaxsize, lhsoffset;
3484e4b17023SJohn Marino       HOST_WIDE_INT rhssize, rhsmaxsize, rhsoffset;
3485e4b17023SJohn Marino       unsigned k = 0;
3486e4b17023SJohn Marino       get_ref_base_and_extent (lhsop, &lhsoffset, &lhssize, &lhsmaxsize);
3487e4b17023SJohn Marino       get_ref_base_and_extent (rhsop, &rhsoffset, &rhssize, &rhsmaxsize);
3488e4b17023SJohn Marino       for (j = 0; VEC_iterate (ce_s, lhsc, j, lhsp);)
3489e4b17023SJohn Marino 	{
3490e4b17023SJohn Marino 	  varinfo_t lhsv, rhsv;
3491e4b17023SJohn Marino 	  rhsp = VEC_index (ce_s, rhsc, k);
3492e4b17023SJohn Marino 	  lhsv = get_varinfo (lhsp->var);
3493e4b17023SJohn Marino 	  rhsv = get_varinfo (rhsp->var);
3494e4b17023SJohn Marino 	  if (lhsv->may_have_pointers
3495e4b17023SJohn Marino 	      && (lhsv->is_full_var
3496e4b17023SJohn Marino 		  || rhsv->is_full_var
3497e4b17023SJohn Marino 		  || ranges_overlap_p (lhsv->offset + rhsoffset, lhsv->size,
3498e4b17023SJohn Marino 				       rhsv->offset + lhsoffset, rhsv->size)))
3499e4b17023SJohn Marino 	    process_constraint (new_constraint (*lhsp, *rhsp));
3500e4b17023SJohn Marino 	  if (!rhsv->is_full_var
3501e4b17023SJohn Marino 	      && (lhsv->is_full_var
3502e4b17023SJohn Marino 		  || (lhsv->offset + rhsoffset + lhsv->size
3503e4b17023SJohn Marino 		      > rhsv->offset + lhsoffset + rhsv->size)))
3504e4b17023SJohn Marino 	    {
3505e4b17023SJohn Marino 	      ++k;
3506e4b17023SJohn Marino 	      if (k >= VEC_length (ce_s, rhsc))
3507e4b17023SJohn Marino 		break;
3508e4b17023SJohn Marino 	    }
3509e4b17023SJohn Marino 	  else
3510e4b17023SJohn Marino 	    ++j;
3511e4b17023SJohn Marino 	}
3512e4b17023SJohn Marino     }
3513e4b17023SJohn Marino   else
3514e4b17023SJohn Marino     gcc_unreachable ();
3515e4b17023SJohn Marino 
3516e4b17023SJohn Marino   VEC_free (ce_s, heap, lhsc);
3517e4b17023SJohn Marino   VEC_free (ce_s, heap, rhsc);
3518e4b17023SJohn Marino }
3519e4b17023SJohn Marino 
3520e4b17023SJohn Marino /* Create constraints ID = { rhsc }.  */
3521e4b17023SJohn Marino 
3522e4b17023SJohn Marino static void
make_constraints_to(unsigned id,VEC (ce_s,heap)* rhsc)3523e4b17023SJohn Marino make_constraints_to (unsigned id, VEC(ce_s, heap) *rhsc)
3524e4b17023SJohn Marino {
3525e4b17023SJohn Marino   struct constraint_expr *c;
3526e4b17023SJohn Marino   struct constraint_expr includes;
3527e4b17023SJohn Marino   unsigned int j;
3528e4b17023SJohn Marino 
3529e4b17023SJohn Marino   includes.var = id;
3530e4b17023SJohn Marino   includes.offset = 0;
3531e4b17023SJohn Marino   includes.type = SCALAR;
3532e4b17023SJohn Marino 
3533e4b17023SJohn Marino   FOR_EACH_VEC_ELT (ce_s, rhsc, j, c)
3534e4b17023SJohn Marino     process_constraint (new_constraint (includes, *c));
3535e4b17023SJohn Marino }
3536e4b17023SJohn Marino 
3537e4b17023SJohn Marino /* Create a constraint ID = OP.  */
3538e4b17023SJohn Marino 
3539e4b17023SJohn Marino static void
make_constraint_to(unsigned id,tree op)3540e4b17023SJohn Marino make_constraint_to (unsigned id, tree op)
3541e4b17023SJohn Marino {
3542e4b17023SJohn Marino   VEC(ce_s, heap) *rhsc = NULL;
3543e4b17023SJohn Marino   get_constraint_for_rhs (op, &rhsc);
3544e4b17023SJohn Marino   make_constraints_to (id, rhsc);
3545e4b17023SJohn Marino   VEC_free (ce_s, heap, rhsc);
3546e4b17023SJohn Marino }
3547e4b17023SJohn Marino 
3548e4b17023SJohn Marino /* Create a constraint ID = &FROM.  */
3549e4b17023SJohn Marino 
3550e4b17023SJohn Marino static void
make_constraint_from(varinfo_t vi,int from)3551e4b17023SJohn Marino make_constraint_from (varinfo_t vi, int from)
3552e4b17023SJohn Marino {
3553e4b17023SJohn Marino   struct constraint_expr lhs, rhs;
3554e4b17023SJohn Marino 
3555e4b17023SJohn Marino   lhs.var = vi->id;
3556e4b17023SJohn Marino   lhs.offset = 0;
3557e4b17023SJohn Marino   lhs.type = SCALAR;
3558e4b17023SJohn Marino 
3559e4b17023SJohn Marino   rhs.var = from;
3560e4b17023SJohn Marino   rhs.offset = 0;
3561e4b17023SJohn Marino   rhs.type = ADDRESSOF;
3562e4b17023SJohn Marino   process_constraint (new_constraint (lhs, rhs));
3563e4b17023SJohn Marino }
3564e4b17023SJohn Marino 
3565e4b17023SJohn Marino /* Create a constraint ID = FROM.  */
3566e4b17023SJohn Marino 
3567e4b17023SJohn Marino static void
make_copy_constraint(varinfo_t vi,int from)3568e4b17023SJohn Marino make_copy_constraint (varinfo_t vi, int from)
3569e4b17023SJohn Marino {
3570e4b17023SJohn Marino   struct constraint_expr lhs, rhs;
3571e4b17023SJohn Marino 
3572e4b17023SJohn Marino   lhs.var = vi->id;
3573e4b17023SJohn Marino   lhs.offset = 0;
3574e4b17023SJohn Marino   lhs.type = SCALAR;
3575e4b17023SJohn Marino 
3576e4b17023SJohn Marino   rhs.var = from;
3577e4b17023SJohn Marino   rhs.offset = 0;
3578e4b17023SJohn Marino   rhs.type = SCALAR;
3579e4b17023SJohn Marino   process_constraint (new_constraint (lhs, rhs));
3580e4b17023SJohn Marino }
3581e4b17023SJohn Marino 
3582e4b17023SJohn Marino /* Make constraints necessary to make OP escape.  */
3583e4b17023SJohn Marino 
3584e4b17023SJohn Marino static void
make_escape_constraint(tree op)3585e4b17023SJohn Marino make_escape_constraint (tree op)
3586e4b17023SJohn Marino {
3587e4b17023SJohn Marino   make_constraint_to (escaped_id, op);
3588e4b17023SJohn Marino }
3589e4b17023SJohn Marino 
3590e4b17023SJohn Marino /* Add constraints to that the solution of VI is transitively closed.  */
3591e4b17023SJohn Marino 
3592e4b17023SJohn Marino static void
make_transitive_closure_constraints(varinfo_t vi)3593e4b17023SJohn Marino make_transitive_closure_constraints (varinfo_t vi)
3594e4b17023SJohn Marino {
3595e4b17023SJohn Marino   struct constraint_expr lhs, rhs;
3596e4b17023SJohn Marino 
3597e4b17023SJohn Marino   /* VAR = *VAR;  */
3598e4b17023SJohn Marino   lhs.type = SCALAR;
3599e4b17023SJohn Marino   lhs.var = vi->id;
3600e4b17023SJohn Marino   lhs.offset = 0;
3601e4b17023SJohn Marino   rhs.type = DEREF;
3602e4b17023SJohn Marino   rhs.var = vi->id;
3603e4b17023SJohn Marino   rhs.offset = 0;
3604e4b17023SJohn Marino   process_constraint (new_constraint (lhs, rhs));
3605e4b17023SJohn Marino 
3606e4b17023SJohn Marino   /* VAR = VAR + UNKNOWN;  */
3607e4b17023SJohn Marino   lhs.type = SCALAR;
3608e4b17023SJohn Marino   lhs.var = vi->id;
3609e4b17023SJohn Marino   lhs.offset = 0;
3610e4b17023SJohn Marino   rhs.type = SCALAR;
3611e4b17023SJohn Marino   rhs.var = vi->id;
3612e4b17023SJohn Marino   rhs.offset = UNKNOWN_OFFSET;
3613e4b17023SJohn Marino   process_constraint (new_constraint (lhs, rhs));
3614e4b17023SJohn Marino }
3615e4b17023SJohn Marino 
3616e4b17023SJohn Marino /* Temporary storage for fake var decls.  */
3617e4b17023SJohn Marino struct obstack fake_var_decl_obstack;
3618e4b17023SJohn Marino 
3619e4b17023SJohn Marino /* Build a fake VAR_DECL acting as referrer to a DECL_UID.  */
3620e4b17023SJohn Marino 
3621e4b17023SJohn Marino static tree
build_fake_var_decl(tree type)3622e4b17023SJohn Marino build_fake_var_decl (tree type)
3623e4b17023SJohn Marino {
3624e4b17023SJohn Marino   tree decl = (tree) XOBNEW (&fake_var_decl_obstack, struct tree_var_decl);
3625e4b17023SJohn Marino   memset (decl, 0, sizeof (struct tree_var_decl));
3626e4b17023SJohn Marino   TREE_SET_CODE (decl, VAR_DECL);
3627e4b17023SJohn Marino   TREE_TYPE (decl) = type;
3628e4b17023SJohn Marino   DECL_UID (decl) = allocate_decl_uid ();
3629e4b17023SJohn Marino   SET_DECL_PT_UID (decl, -1);
3630e4b17023SJohn Marino   layout_decl (decl, 0);
3631e4b17023SJohn Marino   return decl;
3632e4b17023SJohn Marino }
3633e4b17023SJohn Marino 
3634e4b17023SJohn Marino /* Create a new artificial heap variable with NAME.
3635e4b17023SJohn Marino    Return the created variable.  */
3636e4b17023SJohn Marino 
3637e4b17023SJohn Marino static varinfo_t
make_heapvar(const char * name)3638e4b17023SJohn Marino make_heapvar (const char *name)
3639e4b17023SJohn Marino {
3640e4b17023SJohn Marino   varinfo_t vi;
3641e4b17023SJohn Marino   tree heapvar;
3642e4b17023SJohn Marino 
3643e4b17023SJohn Marino   heapvar = build_fake_var_decl (ptr_type_node);
3644e4b17023SJohn Marino   DECL_EXTERNAL (heapvar) = 1;
3645e4b17023SJohn Marino 
3646e4b17023SJohn Marino   vi = new_var_info (heapvar, name);
3647e4b17023SJohn Marino   vi->is_artificial_var = true;
3648e4b17023SJohn Marino   vi->is_heap_var = true;
3649e4b17023SJohn Marino   vi->is_unknown_size_var = true;
3650e4b17023SJohn Marino   vi->offset = 0;
3651e4b17023SJohn Marino   vi->fullsize = ~0;
3652e4b17023SJohn Marino   vi->size = ~0;
3653e4b17023SJohn Marino   vi->is_full_var = true;
3654e4b17023SJohn Marino   insert_vi_for_tree (heapvar, vi);
3655e4b17023SJohn Marino 
3656e4b17023SJohn Marino   return vi;
3657e4b17023SJohn Marino }
3658e4b17023SJohn Marino 
3659e4b17023SJohn Marino /* Create a new artificial heap variable with NAME and make a
3660e4b17023SJohn Marino    constraint from it to LHS.  Set flags according to a tag used
3661e4b17023SJohn Marino    for tracking restrict pointers.  */
3662e4b17023SJohn Marino 
3663e4b17023SJohn Marino static varinfo_t
make_constraint_from_restrict(varinfo_t lhs,const char * name)3664e4b17023SJohn Marino make_constraint_from_restrict (varinfo_t lhs, const char *name)
3665e4b17023SJohn Marino {
3666e4b17023SJohn Marino   varinfo_t vi = make_heapvar (name);
3667e4b17023SJohn Marino   vi->is_global_var = 1;
3668e4b17023SJohn Marino   vi->may_have_pointers = 1;
3669e4b17023SJohn Marino   make_constraint_from (lhs, vi->id);
3670e4b17023SJohn Marino   return vi;
3671e4b17023SJohn Marino }
3672e4b17023SJohn Marino 
3673e4b17023SJohn Marino /* Create a new artificial heap variable with NAME and make a
3674e4b17023SJohn Marino    constraint from it to LHS.  Set flags according to a tag used
3675e4b17023SJohn Marino    for tracking restrict pointers and make the artificial heap
3676e4b17023SJohn Marino    point to global memory.  */
3677e4b17023SJohn Marino 
3678e4b17023SJohn Marino static varinfo_t
make_constraint_from_global_restrict(varinfo_t lhs,const char * name)3679e4b17023SJohn Marino make_constraint_from_global_restrict (varinfo_t lhs, const char *name)
3680e4b17023SJohn Marino {
3681e4b17023SJohn Marino   varinfo_t vi = make_constraint_from_restrict (lhs, name);
3682e4b17023SJohn Marino   make_copy_constraint (vi, nonlocal_id);
3683e4b17023SJohn Marino   return vi;
3684e4b17023SJohn Marino }
3685e4b17023SJohn Marino 
3686e4b17023SJohn Marino /* In IPA mode there are varinfos for different aspects of reach
3687e4b17023SJohn Marino    function designator.  One for the points-to set of the return
3688e4b17023SJohn Marino    value, one for the variables that are clobbered by the function,
3689e4b17023SJohn Marino    one for its uses and one for each parameter (including a single
3690e4b17023SJohn Marino    glob for remaining variadic arguments).  */
3691e4b17023SJohn Marino 
3692e4b17023SJohn Marino enum { fi_clobbers = 1, fi_uses = 2,
3693e4b17023SJohn Marino        fi_static_chain = 3, fi_result = 4, fi_parm_base = 5 };
3694e4b17023SJohn Marino 
3695e4b17023SJohn Marino /* Get a constraint for the requested part of a function designator FI
3696e4b17023SJohn Marino    when operating in IPA mode.  */
3697e4b17023SJohn Marino 
3698e4b17023SJohn Marino static struct constraint_expr
get_function_part_constraint(varinfo_t fi,unsigned part)3699e4b17023SJohn Marino get_function_part_constraint (varinfo_t fi, unsigned part)
3700e4b17023SJohn Marino {
3701e4b17023SJohn Marino   struct constraint_expr c;
3702e4b17023SJohn Marino 
3703e4b17023SJohn Marino   gcc_assert (in_ipa_mode);
3704e4b17023SJohn Marino 
3705e4b17023SJohn Marino   if (fi->id == anything_id)
3706e4b17023SJohn Marino     {
3707e4b17023SJohn Marino       /* ???  We probably should have a ANYFN special variable.  */
3708e4b17023SJohn Marino       c.var = anything_id;
3709e4b17023SJohn Marino       c.offset = 0;
3710e4b17023SJohn Marino       c.type = SCALAR;
3711e4b17023SJohn Marino     }
3712e4b17023SJohn Marino   else if (TREE_CODE (fi->decl) == FUNCTION_DECL)
3713e4b17023SJohn Marino     {
3714e4b17023SJohn Marino       varinfo_t ai = first_vi_for_offset (fi, part);
3715e4b17023SJohn Marino       if (ai)
3716e4b17023SJohn Marino 	c.var = ai->id;
3717e4b17023SJohn Marino       else
3718e4b17023SJohn Marino 	c.var = anything_id;
3719e4b17023SJohn Marino       c.offset = 0;
3720e4b17023SJohn Marino       c.type = SCALAR;
3721e4b17023SJohn Marino     }
3722e4b17023SJohn Marino   else
3723e4b17023SJohn Marino     {
3724e4b17023SJohn Marino       c.var = fi->id;
3725e4b17023SJohn Marino       c.offset = part;
3726e4b17023SJohn Marino       c.type = DEREF;
3727e4b17023SJohn Marino     }
3728e4b17023SJohn Marino 
3729e4b17023SJohn Marino   return c;
3730e4b17023SJohn Marino }
3731e4b17023SJohn Marino 
3732e4b17023SJohn Marino /* For non-IPA mode, generate constraints necessary for a call on the
3733e4b17023SJohn Marino    RHS.  */
3734e4b17023SJohn Marino 
3735e4b17023SJohn Marino static void
handle_rhs_call(gimple stmt,VEC (ce_s,heap)** results)3736e4b17023SJohn Marino handle_rhs_call (gimple stmt, VEC(ce_s, heap) **results)
3737e4b17023SJohn Marino {
3738e4b17023SJohn Marino   struct constraint_expr rhsc;
3739e4b17023SJohn Marino   unsigned i;
3740e4b17023SJohn Marino   bool returns_uses = false;
3741e4b17023SJohn Marino 
3742e4b17023SJohn Marino   for (i = 0; i < gimple_call_num_args (stmt); ++i)
3743e4b17023SJohn Marino     {
3744e4b17023SJohn Marino       tree arg = gimple_call_arg (stmt, i);
3745e4b17023SJohn Marino       int flags = gimple_call_arg_flags (stmt, i);
3746e4b17023SJohn Marino 
3747e4b17023SJohn Marino       /* If the argument is not used we can ignore it.  */
3748e4b17023SJohn Marino       if (flags & EAF_UNUSED)
3749e4b17023SJohn Marino 	continue;
3750e4b17023SJohn Marino 
3751e4b17023SJohn Marino       /* As we compute ESCAPED context-insensitive we do not gain
3752e4b17023SJohn Marino          any precision with just EAF_NOCLOBBER but not EAF_NOESCAPE
3753e4b17023SJohn Marino 	 set.  The argument would still get clobbered through the
3754e4b17023SJohn Marino 	 escape solution.  */
3755e4b17023SJohn Marino       if ((flags & EAF_NOCLOBBER)
3756e4b17023SJohn Marino 	   && (flags & EAF_NOESCAPE))
3757e4b17023SJohn Marino 	{
3758e4b17023SJohn Marino 	  varinfo_t uses = get_call_use_vi (stmt);
3759e4b17023SJohn Marino 	  if (!(flags & EAF_DIRECT))
3760e4b17023SJohn Marino 	    {
3761e4b17023SJohn Marino 	      varinfo_t tem = new_var_info (NULL_TREE, "callarg");
3762e4b17023SJohn Marino 	      make_constraint_to (tem->id, arg);
3763e4b17023SJohn Marino 	      make_transitive_closure_constraints (tem);
3764e4b17023SJohn Marino 	      make_copy_constraint (uses, tem->id);
3765e4b17023SJohn Marino 	    }
3766e4b17023SJohn Marino 	  else
3767e4b17023SJohn Marino 	    make_constraint_to (uses->id, arg);
3768e4b17023SJohn Marino 	  returns_uses = true;
3769e4b17023SJohn Marino 	}
3770e4b17023SJohn Marino       else if (flags & EAF_NOESCAPE)
3771e4b17023SJohn Marino 	{
3772e4b17023SJohn Marino 	  struct constraint_expr lhs, rhs;
3773e4b17023SJohn Marino 	  varinfo_t uses = get_call_use_vi (stmt);
3774e4b17023SJohn Marino 	  varinfo_t clobbers = get_call_clobber_vi (stmt);
3775e4b17023SJohn Marino 	  varinfo_t tem = new_var_info (NULL_TREE, "callarg");
3776e4b17023SJohn Marino 	  make_constraint_to (tem->id, arg);
3777e4b17023SJohn Marino 	  if (!(flags & EAF_DIRECT))
3778e4b17023SJohn Marino 	    make_transitive_closure_constraints (tem);
3779e4b17023SJohn Marino 	  make_copy_constraint (uses, tem->id);
3780e4b17023SJohn Marino 	  make_copy_constraint (clobbers, tem->id);
3781e4b17023SJohn Marino 	  /* Add *tem = nonlocal, do not add *tem = callused as
3782e4b17023SJohn Marino 	     EAF_NOESCAPE parameters do not escape to other parameters
3783e4b17023SJohn Marino 	     and all other uses appear in NONLOCAL as well.  */
3784e4b17023SJohn Marino 	  lhs.type = DEREF;
3785e4b17023SJohn Marino 	  lhs.var = tem->id;
3786e4b17023SJohn Marino 	  lhs.offset = 0;
3787e4b17023SJohn Marino 	  rhs.type = SCALAR;
3788e4b17023SJohn Marino 	  rhs.var = nonlocal_id;
3789e4b17023SJohn Marino 	  rhs.offset = 0;
3790e4b17023SJohn Marino 	  process_constraint (new_constraint (lhs, rhs));
3791e4b17023SJohn Marino 	  returns_uses = true;
3792e4b17023SJohn Marino 	}
3793e4b17023SJohn Marino       else
3794e4b17023SJohn Marino 	make_escape_constraint (arg);
3795e4b17023SJohn Marino     }
3796e4b17023SJohn Marino 
3797e4b17023SJohn Marino   /* If we added to the calls uses solution make sure we account for
3798e4b17023SJohn Marino      pointers to it to be returned.  */
3799e4b17023SJohn Marino   if (returns_uses)
3800e4b17023SJohn Marino     {
3801e4b17023SJohn Marino       rhsc.var = get_call_use_vi (stmt)->id;
3802e4b17023SJohn Marino       rhsc.offset = 0;
3803e4b17023SJohn Marino       rhsc.type = SCALAR;
3804e4b17023SJohn Marino       VEC_safe_push (ce_s, heap, *results, &rhsc);
3805e4b17023SJohn Marino     }
3806e4b17023SJohn Marino 
3807e4b17023SJohn Marino   /* The static chain escapes as well.  */
3808e4b17023SJohn Marino   if (gimple_call_chain (stmt))
3809e4b17023SJohn Marino     make_escape_constraint (gimple_call_chain (stmt));
3810e4b17023SJohn Marino 
3811e4b17023SJohn Marino   /* And if we applied NRV the address of the return slot escapes as well.  */
3812e4b17023SJohn Marino   if (gimple_call_return_slot_opt_p (stmt)
3813e4b17023SJohn Marino       && gimple_call_lhs (stmt) != NULL_TREE
3814e4b17023SJohn Marino       && TREE_ADDRESSABLE (TREE_TYPE (gimple_call_lhs (stmt))))
3815e4b17023SJohn Marino     {
3816e4b17023SJohn Marino       VEC(ce_s, heap) *tmpc = NULL;
3817e4b17023SJohn Marino       struct constraint_expr lhsc, *c;
3818e4b17023SJohn Marino       get_constraint_for_address_of (gimple_call_lhs (stmt), &tmpc);
3819e4b17023SJohn Marino       lhsc.var = escaped_id;
3820e4b17023SJohn Marino       lhsc.offset = 0;
3821e4b17023SJohn Marino       lhsc.type = SCALAR;
3822e4b17023SJohn Marino       FOR_EACH_VEC_ELT (ce_s, tmpc, i, c)
3823e4b17023SJohn Marino 	process_constraint (new_constraint (lhsc, *c));
3824e4b17023SJohn Marino       VEC_free(ce_s, heap, tmpc);
3825e4b17023SJohn Marino     }
3826e4b17023SJohn Marino 
3827e4b17023SJohn Marino   /* Regular functions return nonlocal memory.  */
3828e4b17023SJohn Marino   rhsc.var = nonlocal_id;
3829e4b17023SJohn Marino   rhsc.offset = 0;
3830e4b17023SJohn Marino   rhsc.type = SCALAR;
3831e4b17023SJohn Marino   VEC_safe_push (ce_s, heap, *results, &rhsc);
3832e4b17023SJohn Marino }
3833e4b17023SJohn Marino 
3834e4b17023SJohn Marino /* For non-IPA mode, generate constraints necessary for a call
3835e4b17023SJohn Marino    that returns a pointer and assigns it to LHS.  This simply makes
3836e4b17023SJohn Marino    the LHS point to global and escaped variables.  */
3837e4b17023SJohn Marino 
3838e4b17023SJohn Marino static void
handle_lhs_call(gimple stmt,tree lhs,int flags,VEC (ce_s,heap)* rhsc,tree fndecl)3839e4b17023SJohn Marino handle_lhs_call (gimple stmt, tree lhs, int flags, VEC(ce_s, heap) *rhsc,
3840e4b17023SJohn Marino 		 tree fndecl)
3841e4b17023SJohn Marino {
3842e4b17023SJohn Marino   VEC(ce_s, heap) *lhsc = NULL;
3843e4b17023SJohn Marino 
3844e4b17023SJohn Marino   get_constraint_for (lhs, &lhsc);
3845e4b17023SJohn Marino   /* If the store is to a global decl make sure to
3846e4b17023SJohn Marino      add proper escape constraints.  */
3847e4b17023SJohn Marino   lhs = get_base_address (lhs);
3848e4b17023SJohn Marino   if (lhs
3849e4b17023SJohn Marino       && DECL_P (lhs)
3850e4b17023SJohn Marino       && is_global_var (lhs))
3851e4b17023SJohn Marino     {
3852e4b17023SJohn Marino       struct constraint_expr tmpc;
3853e4b17023SJohn Marino       tmpc.var = escaped_id;
3854e4b17023SJohn Marino       tmpc.offset = 0;
3855e4b17023SJohn Marino       tmpc.type = SCALAR;
3856e4b17023SJohn Marino       VEC_safe_push (ce_s, heap, lhsc, &tmpc);
3857e4b17023SJohn Marino     }
3858e4b17023SJohn Marino 
3859e4b17023SJohn Marino   /* If the call returns an argument unmodified override the rhs
3860e4b17023SJohn Marino      constraints.  */
3861e4b17023SJohn Marino   flags = gimple_call_return_flags (stmt);
3862e4b17023SJohn Marino   if (flags & ERF_RETURNS_ARG
3863e4b17023SJohn Marino       && (flags & ERF_RETURN_ARG_MASK) < gimple_call_num_args (stmt))
3864e4b17023SJohn Marino     {
3865e4b17023SJohn Marino       tree arg;
3866e4b17023SJohn Marino       rhsc = NULL;
3867e4b17023SJohn Marino       arg = gimple_call_arg (stmt, flags & ERF_RETURN_ARG_MASK);
3868e4b17023SJohn Marino       get_constraint_for (arg, &rhsc);
3869e4b17023SJohn Marino       process_all_all_constraints (lhsc, rhsc);
3870e4b17023SJohn Marino       VEC_free (ce_s, heap, rhsc);
3871e4b17023SJohn Marino     }
3872e4b17023SJohn Marino   else if (flags & ERF_NOALIAS)
3873e4b17023SJohn Marino     {
3874e4b17023SJohn Marino       varinfo_t vi;
3875e4b17023SJohn Marino       struct constraint_expr tmpc;
3876e4b17023SJohn Marino       rhsc = NULL;
3877e4b17023SJohn Marino       vi = make_heapvar ("HEAP");
3878e4b17023SJohn Marino       /* We delay marking allocated storage global until we know if
3879e4b17023SJohn Marino          it escapes.  */
3880e4b17023SJohn Marino       DECL_EXTERNAL (vi->decl) = 0;
3881e4b17023SJohn Marino       vi->is_global_var = 0;
3882e4b17023SJohn Marino       /* If this is not a real malloc call assume the memory was
3883e4b17023SJohn Marino 	 initialized and thus may point to global memory.  All
3884e4b17023SJohn Marino 	 builtin functions with the malloc attribute behave in a sane way.  */
3885e4b17023SJohn Marino       if (!fndecl
3886e4b17023SJohn Marino 	  || DECL_BUILT_IN_CLASS (fndecl) != BUILT_IN_NORMAL)
3887e4b17023SJohn Marino 	make_constraint_from (vi, nonlocal_id);
3888e4b17023SJohn Marino       tmpc.var = vi->id;
3889e4b17023SJohn Marino       tmpc.offset = 0;
3890e4b17023SJohn Marino       tmpc.type = ADDRESSOF;
3891e4b17023SJohn Marino       VEC_safe_push (ce_s, heap, rhsc, &tmpc);
3892e4b17023SJohn Marino       process_all_all_constraints (lhsc, rhsc);
3893e4b17023SJohn Marino       VEC_free (ce_s, heap, rhsc);
3894e4b17023SJohn Marino     }
3895e4b17023SJohn Marino   else
3896e4b17023SJohn Marino     process_all_all_constraints (lhsc, rhsc);
3897e4b17023SJohn Marino 
3898e4b17023SJohn Marino   VEC_free (ce_s, heap, lhsc);
3899e4b17023SJohn Marino }
3900e4b17023SJohn Marino 
3901e4b17023SJohn Marino /* For non-IPA mode, generate constraints necessary for a call of a
3902e4b17023SJohn Marino    const function that returns a pointer in the statement STMT.  */
3903e4b17023SJohn Marino 
3904e4b17023SJohn Marino static void
handle_const_call(gimple stmt,VEC (ce_s,heap)** results)3905e4b17023SJohn Marino handle_const_call (gimple stmt, VEC(ce_s, heap) **results)
3906e4b17023SJohn Marino {
3907e4b17023SJohn Marino   struct constraint_expr rhsc;
3908e4b17023SJohn Marino   unsigned int k;
3909e4b17023SJohn Marino 
3910e4b17023SJohn Marino   /* Treat nested const functions the same as pure functions as far
3911e4b17023SJohn Marino      as the static chain is concerned.  */
3912e4b17023SJohn Marino   if (gimple_call_chain (stmt))
3913e4b17023SJohn Marino     {
3914e4b17023SJohn Marino       varinfo_t uses = get_call_use_vi (stmt);
3915e4b17023SJohn Marino       make_transitive_closure_constraints (uses);
3916e4b17023SJohn Marino       make_constraint_to (uses->id, gimple_call_chain (stmt));
3917e4b17023SJohn Marino       rhsc.var = uses->id;
3918e4b17023SJohn Marino       rhsc.offset = 0;
3919e4b17023SJohn Marino       rhsc.type = SCALAR;
3920e4b17023SJohn Marino       VEC_safe_push (ce_s, heap, *results, &rhsc);
3921e4b17023SJohn Marino     }
3922e4b17023SJohn Marino 
3923e4b17023SJohn Marino   /* May return arguments.  */
3924e4b17023SJohn Marino   for (k = 0; k < gimple_call_num_args (stmt); ++k)
3925e4b17023SJohn Marino     {
3926e4b17023SJohn Marino       tree arg = gimple_call_arg (stmt, k);
3927e4b17023SJohn Marino       VEC(ce_s, heap) *argc = NULL;
3928e4b17023SJohn Marino       unsigned i;
3929e4b17023SJohn Marino       struct constraint_expr *argp;
3930e4b17023SJohn Marino       get_constraint_for_rhs (arg, &argc);
3931e4b17023SJohn Marino       FOR_EACH_VEC_ELT (ce_s, argc, i, argp)
3932e4b17023SJohn Marino 	VEC_safe_push (ce_s, heap, *results, argp);
3933e4b17023SJohn Marino       VEC_free(ce_s, heap, argc);
3934e4b17023SJohn Marino     }
3935e4b17023SJohn Marino 
3936e4b17023SJohn Marino   /* May return addresses of globals.  */
3937e4b17023SJohn Marino   rhsc.var = nonlocal_id;
3938e4b17023SJohn Marino   rhsc.offset = 0;
3939e4b17023SJohn Marino   rhsc.type = ADDRESSOF;
3940e4b17023SJohn Marino   VEC_safe_push (ce_s, heap, *results, &rhsc);
3941e4b17023SJohn Marino }
3942e4b17023SJohn Marino 
3943e4b17023SJohn Marino /* For non-IPA mode, generate constraints necessary for a call to a
3944e4b17023SJohn Marino    pure function in statement STMT.  */
3945e4b17023SJohn Marino 
3946e4b17023SJohn Marino static void
handle_pure_call(gimple stmt,VEC (ce_s,heap)** results)3947e4b17023SJohn Marino handle_pure_call (gimple stmt, VEC(ce_s, heap) **results)
3948e4b17023SJohn Marino {
3949e4b17023SJohn Marino   struct constraint_expr rhsc;
3950e4b17023SJohn Marino   unsigned i;
3951e4b17023SJohn Marino   varinfo_t uses = NULL;
3952e4b17023SJohn Marino 
3953e4b17023SJohn Marino   /* Memory reached from pointer arguments is call-used.  */
3954e4b17023SJohn Marino   for (i = 0; i < gimple_call_num_args (stmt); ++i)
3955e4b17023SJohn Marino     {
3956e4b17023SJohn Marino       tree arg = gimple_call_arg (stmt, i);
3957e4b17023SJohn Marino       if (!uses)
3958e4b17023SJohn Marino 	{
3959e4b17023SJohn Marino 	  uses = get_call_use_vi (stmt);
3960e4b17023SJohn Marino 	  make_transitive_closure_constraints (uses);
3961e4b17023SJohn Marino 	}
3962e4b17023SJohn Marino       make_constraint_to (uses->id, arg);
3963e4b17023SJohn Marino     }
3964e4b17023SJohn Marino 
3965e4b17023SJohn Marino   /* The static chain is used as well.  */
3966e4b17023SJohn Marino   if (gimple_call_chain (stmt))
3967e4b17023SJohn Marino     {
3968e4b17023SJohn Marino       if (!uses)
3969e4b17023SJohn Marino 	{
3970e4b17023SJohn Marino 	  uses = get_call_use_vi (stmt);
3971e4b17023SJohn Marino 	  make_transitive_closure_constraints (uses);
3972e4b17023SJohn Marino 	}
3973e4b17023SJohn Marino       make_constraint_to (uses->id, gimple_call_chain (stmt));
3974e4b17023SJohn Marino     }
3975e4b17023SJohn Marino 
3976e4b17023SJohn Marino   /* Pure functions may return call-used and nonlocal memory.  */
3977e4b17023SJohn Marino   if (uses)
3978e4b17023SJohn Marino     {
3979e4b17023SJohn Marino       rhsc.var = uses->id;
3980e4b17023SJohn Marino       rhsc.offset = 0;
3981e4b17023SJohn Marino       rhsc.type = SCALAR;
3982e4b17023SJohn Marino       VEC_safe_push (ce_s, heap, *results, &rhsc);
3983e4b17023SJohn Marino     }
3984e4b17023SJohn Marino   rhsc.var = nonlocal_id;
3985e4b17023SJohn Marino   rhsc.offset = 0;
3986e4b17023SJohn Marino   rhsc.type = SCALAR;
3987e4b17023SJohn Marino   VEC_safe_push (ce_s, heap, *results, &rhsc);
3988e4b17023SJohn Marino }
3989e4b17023SJohn Marino 
3990e4b17023SJohn Marino 
3991e4b17023SJohn Marino /* Return the varinfo for the callee of CALL.  */
3992e4b17023SJohn Marino 
3993e4b17023SJohn Marino static varinfo_t
get_fi_for_callee(gimple call)3994e4b17023SJohn Marino get_fi_for_callee (gimple call)
3995e4b17023SJohn Marino {
3996e4b17023SJohn Marino   tree decl, fn = gimple_call_fn (call);
3997e4b17023SJohn Marino 
3998e4b17023SJohn Marino   if (fn && TREE_CODE (fn) == OBJ_TYPE_REF)
3999e4b17023SJohn Marino     fn = OBJ_TYPE_REF_EXPR (fn);
4000e4b17023SJohn Marino 
4001e4b17023SJohn Marino   /* If we can directly resolve the function being called, do so.
4002e4b17023SJohn Marino      Otherwise, it must be some sort of indirect expression that
4003e4b17023SJohn Marino      we should still be able to handle.  */
4004e4b17023SJohn Marino   decl = gimple_call_addr_fndecl (fn);
4005e4b17023SJohn Marino   if (decl)
4006e4b17023SJohn Marino     return get_vi_for_tree (decl);
4007e4b17023SJohn Marino 
4008e4b17023SJohn Marino   /* If the function is anything other than a SSA name pointer we have no
4009e4b17023SJohn Marino      clue and should be getting ANYFN (well, ANYTHING for now).  */
4010e4b17023SJohn Marino   if (!fn || TREE_CODE (fn) != SSA_NAME)
4011e4b17023SJohn Marino     return get_varinfo (anything_id);
4012e4b17023SJohn Marino 
4013e4b17023SJohn Marino   if ((TREE_CODE (SSA_NAME_VAR (fn)) == PARM_DECL
4014e4b17023SJohn Marino        || TREE_CODE (SSA_NAME_VAR (fn)) == RESULT_DECL)
4015e4b17023SJohn Marino       && SSA_NAME_IS_DEFAULT_DEF (fn))
4016e4b17023SJohn Marino     fn = SSA_NAME_VAR (fn);
4017e4b17023SJohn Marino 
4018e4b17023SJohn Marino   return get_vi_for_tree (fn);
4019e4b17023SJohn Marino }
4020e4b17023SJohn Marino 
4021e4b17023SJohn Marino /* Create constraints for the builtin call T.  Return true if the call
4022e4b17023SJohn Marino    was handled, otherwise false.  */
4023e4b17023SJohn Marino 
4024e4b17023SJohn Marino static bool
find_func_aliases_for_builtin_call(gimple t)4025e4b17023SJohn Marino find_func_aliases_for_builtin_call (gimple t)
4026e4b17023SJohn Marino {
4027e4b17023SJohn Marino   tree fndecl = gimple_call_fndecl (t);
4028e4b17023SJohn Marino   VEC(ce_s, heap) *lhsc = NULL;
4029e4b17023SJohn Marino   VEC(ce_s, heap) *rhsc = NULL;
4030e4b17023SJohn Marino   varinfo_t fi;
4031e4b17023SJohn Marino 
4032*5ce9237cSJohn Marino   if (gimple_call_builtin_class_p (t, BUILT_IN_NORMAL))
4033e4b17023SJohn Marino     /* ???  All builtins that are handled here need to be handled
4034e4b17023SJohn Marino        in the alias-oracle query functions explicitly!  */
4035e4b17023SJohn Marino     switch (DECL_FUNCTION_CODE (fndecl))
4036e4b17023SJohn Marino       {
4037e4b17023SJohn Marino       /* All the following functions return a pointer to the same object
4038e4b17023SJohn Marino 	 as their first argument points to.  The functions do not add
4039e4b17023SJohn Marino 	 to the ESCAPED solution.  The functions make the first argument
4040e4b17023SJohn Marino 	 pointed to memory point to what the second argument pointed to
4041e4b17023SJohn Marino 	 memory points to.  */
4042e4b17023SJohn Marino       case BUILT_IN_STRCPY:
4043e4b17023SJohn Marino       case BUILT_IN_STRNCPY:
4044e4b17023SJohn Marino       case BUILT_IN_BCOPY:
4045e4b17023SJohn Marino       case BUILT_IN_MEMCPY:
4046e4b17023SJohn Marino       case BUILT_IN_MEMMOVE:
4047e4b17023SJohn Marino       case BUILT_IN_MEMPCPY:
4048e4b17023SJohn Marino       case BUILT_IN_STPCPY:
4049e4b17023SJohn Marino       case BUILT_IN_STPNCPY:
4050e4b17023SJohn Marino       case BUILT_IN_STRCAT:
4051e4b17023SJohn Marino       case BUILT_IN_STRNCAT:
4052e4b17023SJohn Marino       case BUILT_IN_STRCPY_CHK:
4053e4b17023SJohn Marino       case BUILT_IN_STRNCPY_CHK:
4054e4b17023SJohn Marino       case BUILT_IN_MEMCPY_CHK:
4055e4b17023SJohn Marino       case BUILT_IN_MEMMOVE_CHK:
4056e4b17023SJohn Marino       case BUILT_IN_MEMPCPY_CHK:
4057e4b17023SJohn Marino       case BUILT_IN_STPCPY_CHK:
4058e4b17023SJohn Marino       case BUILT_IN_STPNCPY_CHK:
4059e4b17023SJohn Marino       case BUILT_IN_STRCAT_CHK:
4060e4b17023SJohn Marino       case BUILT_IN_STRNCAT_CHK:
4061e4b17023SJohn Marino       case BUILT_IN_TM_MEMCPY:
4062e4b17023SJohn Marino       case BUILT_IN_TM_MEMMOVE:
4063e4b17023SJohn Marino 	{
4064e4b17023SJohn Marino 	  tree res = gimple_call_lhs (t);
4065e4b17023SJohn Marino 	  tree dest = gimple_call_arg (t, (DECL_FUNCTION_CODE (fndecl)
4066e4b17023SJohn Marino 					   == BUILT_IN_BCOPY ? 1 : 0));
4067e4b17023SJohn Marino 	  tree src = gimple_call_arg (t, (DECL_FUNCTION_CODE (fndecl)
4068e4b17023SJohn Marino 					  == BUILT_IN_BCOPY ? 0 : 1));
4069e4b17023SJohn Marino 	  if (res != NULL_TREE)
4070e4b17023SJohn Marino 	    {
4071e4b17023SJohn Marino 	      get_constraint_for (res, &lhsc);
4072e4b17023SJohn Marino 	      if (DECL_FUNCTION_CODE (fndecl) == BUILT_IN_MEMPCPY
4073e4b17023SJohn Marino 		  || DECL_FUNCTION_CODE (fndecl) == BUILT_IN_STPCPY
4074e4b17023SJohn Marino 		  || DECL_FUNCTION_CODE (fndecl) == BUILT_IN_STPNCPY
4075e4b17023SJohn Marino 		  || DECL_FUNCTION_CODE (fndecl) == BUILT_IN_MEMPCPY_CHK
4076e4b17023SJohn Marino 		  || DECL_FUNCTION_CODE (fndecl) == BUILT_IN_STPCPY_CHK
4077e4b17023SJohn Marino 		  || DECL_FUNCTION_CODE (fndecl) == BUILT_IN_STPNCPY_CHK)
4078e4b17023SJohn Marino 		get_constraint_for_ptr_offset (dest, NULL_TREE, &rhsc);
4079e4b17023SJohn Marino 	      else
4080e4b17023SJohn Marino 		get_constraint_for (dest, &rhsc);
4081e4b17023SJohn Marino 	      process_all_all_constraints (lhsc, rhsc);
4082e4b17023SJohn Marino 	      VEC_free (ce_s, heap, lhsc);
4083e4b17023SJohn Marino 	      VEC_free (ce_s, heap, rhsc);
4084e4b17023SJohn Marino 	    }
4085e4b17023SJohn Marino 	  get_constraint_for_ptr_offset (dest, NULL_TREE, &lhsc);
4086e4b17023SJohn Marino 	  get_constraint_for_ptr_offset (src, NULL_TREE, &rhsc);
4087e4b17023SJohn Marino 	  do_deref (&lhsc);
4088e4b17023SJohn Marino 	  do_deref (&rhsc);
4089e4b17023SJohn Marino 	  process_all_all_constraints (lhsc, rhsc);
4090e4b17023SJohn Marino 	  VEC_free (ce_s, heap, lhsc);
4091e4b17023SJohn Marino 	  VEC_free (ce_s, heap, rhsc);
4092e4b17023SJohn Marino 	  return true;
4093e4b17023SJohn Marino 	}
4094e4b17023SJohn Marino       case BUILT_IN_MEMSET:
4095e4b17023SJohn Marino       case BUILT_IN_MEMSET_CHK:
4096e4b17023SJohn Marino       case BUILT_IN_TM_MEMSET:
4097e4b17023SJohn Marino 	{
4098e4b17023SJohn Marino 	  tree res = gimple_call_lhs (t);
4099e4b17023SJohn Marino 	  tree dest = gimple_call_arg (t, 0);
4100e4b17023SJohn Marino 	  unsigned i;
4101e4b17023SJohn Marino 	  ce_s *lhsp;
4102e4b17023SJohn Marino 	  struct constraint_expr ac;
4103e4b17023SJohn Marino 	  if (res != NULL_TREE)
4104e4b17023SJohn Marino 	    {
4105e4b17023SJohn Marino 	      get_constraint_for (res, &lhsc);
4106e4b17023SJohn Marino 	      get_constraint_for (dest, &rhsc);
4107e4b17023SJohn Marino 	      process_all_all_constraints (lhsc, rhsc);
4108e4b17023SJohn Marino 	      VEC_free (ce_s, heap, lhsc);
4109e4b17023SJohn Marino 	      VEC_free (ce_s, heap, rhsc);
4110e4b17023SJohn Marino 	    }
4111e4b17023SJohn Marino 	  get_constraint_for_ptr_offset (dest, NULL_TREE, &lhsc);
4112e4b17023SJohn Marino 	  do_deref (&lhsc);
4113e4b17023SJohn Marino 	  if (flag_delete_null_pointer_checks
4114e4b17023SJohn Marino 	      && integer_zerop (gimple_call_arg (t, 1)))
4115e4b17023SJohn Marino 	    {
4116e4b17023SJohn Marino 	      ac.type = ADDRESSOF;
4117e4b17023SJohn Marino 	      ac.var = nothing_id;
4118e4b17023SJohn Marino 	    }
4119e4b17023SJohn Marino 	  else
4120e4b17023SJohn Marino 	    {
4121e4b17023SJohn Marino 	      ac.type = SCALAR;
4122e4b17023SJohn Marino 	      ac.var = integer_id;
4123e4b17023SJohn Marino 	    }
4124e4b17023SJohn Marino 	  ac.offset = 0;
4125e4b17023SJohn Marino 	  FOR_EACH_VEC_ELT (ce_s, lhsc, i, lhsp)
4126e4b17023SJohn Marino 	      process_constraint (new_constraint (*lhsp, ac));
4127e4b17023SJohn Marino 	  VEC_free (ce_s, heap, lhsc);
4128e4b17023SJohn Marino 	  return true;
4129e4b17023SJohn Marino 	}
4130e4b17023SJohn Marino       case BUILT_IN_ASSUME_ALIGNED:
4131e4b17023SJohn Marino 	{
4132e4b17023SJohn Marino 	  tree res = gimple_call_lhs (t);
4133e4b17023SJohn Marino 	  tree dest = gimple_call_arg (t, 0);
4134e4b17023SJohn Marino 	  if (res != NULL_TREE)
4135e4b17023SJohn Marino 	    {
4136e4b17023SJohn Marino 	      get_constraint_for (res, &lhsc);
4137e4b17023SJohn Marino 	      get_constraint_for (dest, &rhsc);
4138e4b17023SJohn Marino 	      process_all_all_constraints (lhsc, rhsc);
4139e4b17023SJohn Marino 	      VEC_free (ce_s, heap, lhsc);
4140e4b17023SJohn Marino 	      VEC_free (ce_s, heap, rhsc);
4141e4b17023SJohn Marino 	    }
4142e4b17023SJohn Marino 	  return true;
4143e4b17023SJohn Marino 	}
4144e4b17023SJohn Marino       /* All the following functions do not return pointers, do not
4145e4b17023SJohn Marino 	 modify the points-to sets of memory reachable from their
4146e4b17023SJohn Marino 	 arguments and do not add to the ESCAPED solution.  */
4147e4b17023SJohn Marino       case BUILT_IN_SINCOS:
4148e4b17023SJohn Marino       case BUILT_IN_SINCOSF:
4149e4b17023SJohn Marino       case BUILT_IN_SINCOSL:
4150e4b17023SJohn Marino       case BUILT_IN_FREXP:
4151e4b17023SJohn Marino       case BUILT_IN_FREXPF:
4152e4b17023SJohn Marino       case BUILT_IN_FREXPL:
4153e4b17023SJohn Marino       case BUILT_IN_GAMMA_R:
4154e4b17023SJohn Marino       case BUILT_IN_GAMMAF_R:
4155e4b17023SJohn Marino       case BUILT_IN_GAMMAL_R:
4156e4b17023SJohn Marino       case BUILT_IN_LGAMMA_R:
4157e4b17023SJohn Marino       case BUILT_IN_LGAMMAF_R:
4158e4b17023SJohn Marino       case BUILT_IN_LGAMMAL_R:
4159e4b17023SJohn Marino       case BUILT_IN_MODF:
4160e4b17023SJohn Marino       case BUILT_IN_MODFF:
4161e4b17023SJohn Marino       case BUILT_IN_MODFL:
4162e4b17023SJohn Marino       case BUILT_IN_REMQUO:
4163e4b17023SJohn Marino       case BUILT_IN_REMQUOF:
4164e4b17023SJohn Marino       case BUILT_IN_REMQUOL:
4165e4b17023SJohn Marino       case BUILT_IN_FREE:
4166e4b17023SJohn Marino 	return true;
4167e4b17023SJohn Marino       case BUILT_IN_STRDUP:
4168e4b17023SJohn Marino       case BUILT_IN_STRNDUP:
4169e4b17023SJohn Marino 	if (gimple_call_lhs (t))
4170e4b17023SJohn Marino 	  {
4171e4b17023SJohn Marino 	    handle_lhs_call (t, gimple_call_lhs (t), gimple_call_flags (t),
4172e4b17023SJohn Marino 			     NULL, fndecl);
4173e4b17023SJohn Marino 	    get_constraint_for_ptr_offset (gimple_call_lhs (t),
4174e4b17023SJohn Marino 					   NULL_TREE, &lhsc);
4175e4b17023SJohn Marino 	    get_constraint_for_ptr_offset (gimple_call_arg (t, 0),
4176e4b17023SJohn Marino 					   NULL_TREE, &rhsc);
4177e4b17023SJohn Marino 	    do_deref (&lhsc);
4178e4b17023SJohn Marino 	    do_deref (&rhsc);
4179e4b17023SJohn Marino 	    process_all_all_constraints (lhsc, rhsc);
4180e4b17023SJohn Marino 	    VEC_free (ce_s, heap, lhsc);
4181e4b17023SJohn Marino 	    VEC_free (ce_s, heap, rhsc);
4182e4b17023SJohn Marino 	    return true;
4183e4b17023SJohn Marino 	  }
4184e4b17023SJohn Marino 	break;
4185e4b17023SJohn Marino       /* Trampolines are special - they set up passing the static
4186e4b17023SJohn Marino 	 frame.  */
4187e4b17023SJohn Marino       case BUILT_IN_INIT_TRAMPOLINE:
4188e4b17023SJohn Marino 	{
4189e4b17023SJohn Marino 	  tree tramp = gimple_call_arg (t, 0);
4190e4b17023SJohn Marino 	  tree nfunc = gimple_call_arg (t, 1);
4191e4b17023SJohn Marino 	  tree frame = gimple_call_arg (t, 2);
4192e4b17023SJohn Marino 	  unsigned i;
4193e4b17023SJohn Marino 	  struct constraint_expr lhs, *rhsp;
4194e4b17023SJohn Marino 	  if (in_ipa_mode)
4195e4b17023SJohn Marino 	    {
4196e4b17023SJohn Marino 	      varinfo_t nfi = NULL;
4197e4b17023SJohn Marino 	      gcc_assert (TREE_CODE (nfunc) == ADDR_EXPR);
4198e4b17023SJohn Marino 	      nfi = lookup_vi_for_tree (TREE_OPERAND (nfunc, 0));
4199e4b17023SJohn Marino 	      if (nfi)
4200e4b17023SJohn Marino 		{
4201e4b17023SJohn Marino 		  lhs = get_function_part_constraint (nfi, fi_static_chain);
4202e4b17023SJohn Marino 		  get_constraint_for (frame, &rhsc);
4203e4b17023SJohn Marino 		  FOR_EACH_VEC_ELT (ce_s, rhsc, i, rhsp)
4204e4b17023SJohn Marino 		      process_constraint (new_constraint (lhs, *rhsp));
4205e4b17023SJohn Marino 		  VEC_free (ce_s, heap, rhsc);
4206e4b17023SJohn Marino 
4207e4b17023SJohn Marino 		  /* Make the frame point to the function for
4208e4b17023SJohn Marino 		     the trampoline adjustment call.  */
4209e4b17023SJohn Marino 		  get_constraint_for (tramp, &lhsc);
4210e4b17023SJohn Marino 		  do_deref (&lhsc);
4211e4b17023SJohn Marino 		  get_constraint_for (nfunc, &rhsc);
4212e4b17023SJohn Marino 		  process_all_all_constraints (lhsc, rhsc);
4213e4b17023SJohn Marino 		  VEC_free (ce_s, heap, rhsc);
4214e4b17023SJohn Marino 		  VEC_free (ce_s, heap, lhsc);
4215e4b17023SJohn Marino 
4216e4b17023SJohn Marino 		  return true;
4217e4b17023SJohn Marino 		}
4218e4b17023SJohn Marino 	    }
4219e4b17023SJohn Marino 	  /* Else fallthru to generic handling which will let
4220e4b17023SJohn Marino 	     the frame escape.  */
4221e4b17023SJohn Marino 	  break;
4222e4b17023SJohn Marino 	}
4223e4b17023SJohn Marino       case BUILT_IN_ADJUST_TRAMPOLINE:
4224e4b17023SJohn Marino 	{
4225e4b17023SJohn Marino 	  tree tramp = gimple_call_arg (t, 0);
4226e4b17023SJohn Marino 	  tree res = gimple_call_lhs (t);
4227e4b17023SJohn Marino 	  if (in_ipa_mode && res)
4228e4b17023SJohn Marino 	    {
4229e4b17023SJohn Marino 	      get_constraint_for (res, &lhsc);
4230e4b17023SJohn Marino 	      get_constraint_for (tramp, &rhsc);
4231e4b17023SJohn Marino 	      do_deref (&rhsc);
4232e4b17023SJohn Marino 	      process_all_all_constraints (lhsc, rhsc);
4233e4b17023SJohn Marino 	      VEC_free (ce_s, heap, rhsc);
4234e4b17023SJohn Marino 	      VEC_free (ce_s, heap, lhsc);
4235e4b17023SJohn Marino 	    }
4236e4b17023SJohn Marino 	  return true;
4237e4b17023SJohn Marino 	}
4238e4b17023SJohn Marino       CASE_BUILT_IN_TM_STORE (1):
4239e4b17023SJohn Marino       CASE_BUILT_IN_TM_STORE (2):
4240e4b17023SJohn Marino       CASE_BUILT_IN_TM_STORE (4):
4241e4b17023SJohn Marino       CASE_BUILT_IN_TM_STORE (8):
4242e4b17023SJohn Marino       CASE_BUILT_IN_TM_STORE (FLOAT):
4243e4b17023SJohn Marino       CASE_BUILT_IN_TM_STORE (DOUBLE):
4244e4b17023SJohn Marino       CASE_BUILT_IN_TM_STORE (LDOUBLE):
4245e4b17023SJohn Marino       CASE_BUILT_IN_TM_STORE (M64):
4246e4b17023SJohn Marino       CASE_BUILT_IN_TM_STORE (M128):
4247e4b17023SJohn Marino       CASE_BUILT_IN_TM_STORE (M256):
4248e4b17023SJohn Marino 	{
4249e4b17023SJohn Marino 	  tree addr = gimple_call_arg (t, 0);
4250e4b17023SJohn Marino 	  tree src = gimple_call_arg (t, 1);
4251e4b17023SJohn Marino 
4252e4b17023SJohn Marino 	  get_constraint_for (addr, &lhsc);
4253e4b17023SJohn Marino 	  do_deref (&lhsc);
4254e4b17023SJohn Marino 	  get_constraint_for (src, &rhsc);
4255e4b17023SJohn Marino 	  process_all_all_constraints (lhsc, rhsc);
4256e4b17023SJohn Marino 	  VEC_free (ce_s, heap, lhsc);
4257e4b17023SJohn Marino 	  VEC_free (ce_s, heap, rhsc);
4258e4b17023SJohn Marino 	  return true;
4259e4b17023SJohn Marino 	}
4260e4b17023SJohn Marino       CASE_BUILT_IN_TM_LOAD (1):
4261e4b17023SJohn Marino       CASE_BUILT_IN_TM_LOAD (2):
4262e4b17023SJohn Marino       CASE_BUILT_IN_TM_LOAD (4):
4263e4b17023SJohn Marino       CASE_BUILT_IN_TM_LOAD (8):
4264e4b17023SJohn Marino       CASE_BUILT_IN_TM_LOAD (FLOAT):
4265e4b17023SJohn Marino       CASE_BUILT_IN_TM_LOAD (DOUBLE):
4266e4b17023SJohn Marino       CASE_BUILT_IN_TM_LOAD (LDOUBLE):
4267e4b17023SJohn Marino       CASE_BUILT_IN_TM_LOAD (M64):
4268e4b17023SJohn Marino       CASE_BUILT_IN_TM_LOAD (M128):
4269e4b17023SJohn Marino       CASE_BUILT_IN_TM_LOAD (M256):
4270e4b17023SJohn Marino 	{
4271e4b17023SJohn Marino 	  tree dest = gimple_call_lhs (t);
4272e4b17023SJohn Marino 	  tree addr = gimple_call_arg (t, 0);
4273e4b17023SJohn Marino 
4274e4b17023SJohn Marino 	  get_constraint_for (dest, &lhsc);
4275e4b17023SJohn Marino 	  get_constraint_for (addr, &rhsc);
4276e4b17023SJohn Marino 	  do_deref (&rhsc);
4277e4b17023SJohn Marino 	  process_all_all_constraints (lhsc, rhsc);
4278e4b17023SJohn Marino 	  VEC_free (ce_s, heap, lhsc);
4279e4b17023SJohn Marino 	  VEC_free (ce_s, heap, rhsc);
4280e4b17023SJohn Marino 	  return true;
4281e4b17023SJohn Marino 	}
4282e4b17023SJohn Marino       /* Variadic argument handling needs to be handled in IPA
4283e4b17023SJohn Marino 	 mode as well.  */
4284e4b17023SJohn Marino       case BUILT_IN_VA_START:
4285e4b17023SJohn Marino 	{
4286e4b17023SJohn Marino 	  tree valist = gimple_call_arg (t, 0);
4287e4b17023SJohn Marino 	  struct constraint_expr rhs, *lhsp;
4288e4b17023SJohn Marino 	  unsigned i;
4289e4b17023SJohn Marino 	  get_constraint_for (valist, &lhsc);
4290e4b17023SJohn Marino 	  do_deref (&lhsc);
4291e4b17023SJohn Marino 	  /* The va_list gets access to pointers in variadic
4292e4b17023SJohn Marino 	     arguments.  Which we know in the case of IPA analysis
4293e4b17023SJohn Marino 	     and otherwise are just all nonlocal variables.  */
4294e4b17023SJohn Marino 	  if (in_ipa_mode)
4295e4b17023SJohn Marino 	    {
4296e4b17023SJohn Marino 	      fi = lookup_vi_for_tree (cfun->decl);
4297e4b17023SJohn Marino 	      rhs = get_function_part_constraint (fi, ~0);
4298e4b17023SJohn Marino 	      rhs.type = ADDRESSOF;
4299e4b17023SJohn Marino 	    }
4300e4b17023SJohn Marino 	  else
4301e4b17023SJohn Marino 	    {
4302e4b17023SJohn Marino 	      rhs.var = nonlocal_id;
4303e4b17023SJohn Marino 	      rhs.type = ADDRESSOF;
4304e4b17023SJohn Marino 	      rhs.offset = 0;
4305e4b17023SJohn Marino 	    }
4306e4b17023SJohn Marino 	  FOR_EACH_VEC_ELT (ce_s, lhsc, i, lhsp)
4307e4b17023SJohn Marino 	    process_constraint (new_constraint (*lhsp, rhs));
4308e4b17023SJohn Marino 	  VEC_free (ce_s, heap, lhsc);
4309e4b17023SJohn Marino 	  /* va_list is clobbered.  */
4310e4b17023SJohn Marino 	  make_constraint_to (get_call_clobber_vi (t)->id, valist);
4311e4b17023SJohn Marino 	  return true;
4312e4b17023SJohn Marino 	}
4313e4b17023SJohn Marino       /* va_end doesn't have any effect that matters.  */
4314e4b17023SJohn Marino       case BUILT_IN_VA_END:
4315e4b17023SJohn Marino 	return true;
4316e4b17023SJohn Marino       /* Alternate return.  Simply give up for now.  */
4317e4b17023SJohn Marino       case BUILT_IN_RETURN:
4318e4b17023SJohn Marino 	{
4319e4b17023SJohn Marino 	  fi = NULL;
4320e4b17023SJohn Marino 	  if (!in_ipa_mode
4321e4b17023SJohn Marino 	      || !(fi = get_vi_for_tree (cfun->decl)))
4322e4b17023SJohn Marino 	    make_constraint_from (get_varinfo (escaped_id), anything_id);
4323e4b17023SJohn Marino 	  else if (in_ipa_mode
4324e4b17023SJohn Marino 		   && fi != NULL)
4325e4b17023SJohn Marino 	    {
4326e4b17023SJohn Marino 	      struct constraint_expr lhs, rhs;
4327e4b17023SJohn Marino 	      lhs = get_function_part_constraint (fi, fi_result);
4328e4b17023SJohn Marino 	      rhs.var = anything_id;
4329e4b17023SJohn Marino 	      rhs.offset = 0;
4330e4b17023SJohn Marino 	      rhs.type = SCALAR;
4331e4b17023SJohn Marino 	      process_constraint (new_constraint (lhs, rhs));
4332e4b17023SJohn Marino 	    }
4333e4b17023SJohn Marino 	  return true;
4334e4b17023SJohn Marino 	}
4335e4b17023SJohn Marino       /* printf-style functions may have hooks to set pointers to
4336e4b17023SJohn Marino 	 point to somewhere into the generated string.  Leave them
4337e4b17023SJohn Marino 	 for a later excercise...  */
4338e4b17023SJohn Marino       default:
4339e4b17023SJohn Marino 	/* Fallthru to general call handling.  */;
4340e4b17023SJohn Marino       }
4341e4b17023SJohn Marino 
4342e4b17023SJohn Marino   return false;
4343e4b17023SJohn Marino }
4344e4b17023SJohn Marino 
4345e4b17023SJohn Marino /* Create constraints for the call T.  */
4346e4b17023SJohn Marino 
4347e4b17023SJohn Marino static void
find_func_aliases_for_call(gimple t)4348e4b17023SJohn Marino find_func_aliases_for_call (gimple t)
4349e4b17023SJohn Marino {
4350e4b17023SJohn Marino   tree fndecl = gimple_call_fndecl (t);
4351e4b17023SJohn Marino   VEC(ce_s, heap) *lhsc = NULL;
4352e4b17023SJohn Marino   VEC(ce_s, heap) *rhsc = NULL;
4353e4b17023SJohn Marino   varinfo_t fi;
4354e4b17023SJohn Marino 
4355e4b17023SJohn Marino   if (fndecl != NULL_TREE
4356e4b17023SJohn Marino       && DECL_BUILT_IN (fndecl)
4357e4b17023SJohn Marino       && find_func_aliases_for_builtin_call (t))
4358e4b17023SJohn Marino     return;
4359e4b17023SJohn Marino 
4360e4b17023SJohn Marino   fi = get_fi_for_callee (t);
4361e4b17023SJohn Marino   if (!in_ipa_mode
4362e4b17023SJohn Marino       || (fndecl && !fi->is_fn_info))
4363e4b17023SJohn Marino     {
4364e4b17023SJohn Marino       VEC(ce_s, heap) *rhsc = NULL;
4365e4b17023SJohn Marino       int flags = gimple_call_flags (t);
4366e4b17023SJohn Marino 
4367e4b17023SJohn Marino       /* Const functions can return their arguments and addresses
4368e4b17023SJohn Marino 	 of global memory but not of escaped memory.  */
4369e4b17023SJohn Marino       if (flags & (ECF_CONST|ECF_NOVOPS))
4370e4b17023SJohn Marino 	{
4371e4b17023SJohn Marino 	  if (gimple_call_lhs (t))
4372e4b17023SJohn Marino 	    handle_const_call (t, &rhsc);
4373e4b17023SJohn Marino 	}
4374e4b17023SJohn Marino       /* Pure functions can return addresses in and of memory
4375e4b17023SJohn Marino 	 reachable from their arguments, but they are not an escape
4376e4b17023SJohn Marino 	 point for reachable memory of their arguments.  */
4377e4b17023SJohn Marino       else if (flags & (ECF_PURE|ECF_LOOPING_CONST_OR_PURE))
4378e4b17023SJohn Marino 	handle_pure_call (t, &rhsc);
4379e4b17023SJohn Marino       else
4380e4b17023SJohn Marino 	handle_rhs_call (t, &rhsc);
4381e4b17023SJohn Marino       if (gimple_call_lhs (t))
4382e4b17023SJohn Marino 	handle_lhs_call (t, gimple_call_lhs (t), flags, rhsc, fndecl);
4383e4b17023SJohn Marino       VEC_free (ce_s, heap, rhsc);
4384e4b17023SJohn Marino     }
4385e4b17023SJohn Marino   else
4386e4b17023SJohn Marino     {
4387e4b17023SJohn Marino       tree lhsop;
4388e4b17023SJohn Marino       unsigned j;
4389e4b17023SJohn Marino 
4390e4b17023SJohn Marino       /* Assign all the passed arguments to the appropriate incoming
4391e4b17023SJohn Marino 	 parameters of the function.  */
4392e4b17023SJohn Marino       for (j = 0; j < gimple_call_num_args (t); j++)
4393e4b17023SJohn Marino 	{
4394e4b17023SJohn Marino 	  struct constraint_expr lhs ;
4395e4b17023SJohn Marino 	  struct constraint_expr *rhsp;
4396e4b17023SJohn Marino 	  tree arg = gimple_call_arg (t, j);
4397e4b17023SJohn Marino 
4398e4b17023SJohn Marino 	  get_constraint_for_rhs (arg, &rhsc);
4399e4b17023SJohn Marino 	  lhs = get_function_part_constraint (fi, fi_parm_base + j);
4400e4b17023SJohn Marino 	  while (VEC_length (ce_s, rhsc) != 0)
4401e4b17023SJohn Marino 	    {
4402e4b17023SJohn Marino 	      rhsp = VEC_last (ce_s, rhsc);
4403e4b17023SJohn Marino 	      process_constraint (new_constraint (lhs, *rhsp));
4404e4b17023SJohn Marino 	      VEC_pop (ce_s, rhsc);
4405e4b17023SJohn Marino 	    }
4406e4b17023SJohn Marino 	}
4407e4b17023SJohn Marino 
4408e4b17023SJohn Marino       /* If we are returning a value, assign it to the result.  */
4409e4b17023SJohn Marino       lhsop = gimple_call_lhs (t);
4410e4b17023SJohn Marino       if (lhsop)
4411e4b17023SJohn Marino 	{
4412e4b17023SJohn Marino 	  struct constraint_expr rhs;
4413e4b17023SJohn Marino 	  struct constraint_expr *lhsp;
4414e4b17023SJohn Marino 
4415e4b17023SJohn Marino 	  get_constraint_for (lhsop, &lhsc);
4416e4b17023SJohn Marino 	  rhs = get_function_part_constraint (fi, fi_result);
4417e4b17023SJohn Marino 	  if (fndecl
4418e4b17023SJohn Marino 	      && DECL_RESULT (fndecl)
4419e4b17023SJohn Marino 	      && DECL_BY_REFERENCE (DECL_RESULT (fndecl)))
4420e4b17023SJohn Marino 	    {
4421e4b17023SJohn Marino 	      VEC(ce_s, heap) *tem = NULL;
4422e4b17023SJohn Marino 	      VEC_safe_push (ce_s, heap, tem, &rhs);
4423e4b17023SJohn Marino 	      do_deref (&tem);
4424e4b17023SJohn Marino 	      rhs = *VEC_index (ce_s, tem, 0);
4425e4b17023SJohn Marino 	      VEC_free(ce_s, heap, tem);
4426e4b17023SJohn Marino 	    }
4427e4b17023SJohn Marino 	  FOR_EACH_VEC_ELT (ce_s, lhsc, j, lhsp)
4428e4b17023SJohn Marino 	    process_constraint (new_constraint (*lhsp, rhs));
4429e4b17023SJohn Marino 	}
4430e4b17023SJohn Marino 
4431e4b17023SJohn Marino       /* If we pass the result decl by reference, honor that.  */
4432e4b17023SJohn Marino       if (lhsop
4433e4b17023SJohn Marino 	  && fndecl
4434e4b17023SJohn Marino 	  && DECL_RESULT (fndecl)
4435e4b17023SJohn Marino 	  && DECL_BY_REFERENCE (DECL_RESULT (fndecl)))
4436e4b17023SJohn Marino 	{
4437e4b17023SJohn Marino 	  struct constraint_expr lhs;
4438e4b17023SJohn Marino 	  struct constraint_expr *rhsp;
4439e4b17023SJohn Marino 
4440e4b17023SJohn Marino 	  get_constraint_for_address_of (lhsop, &rhsc);
4441e4b17023SJohn Marino 	  lhs = get_function_part_constraint (fi, fi_result);
4442e4b17023SJohn Marino 	  FOR_EACH_VEC_ELT (ce_s, rhsc, j, rhsp)
4443e4b17023SJohn Marino 	    process_constraint (new_constraint (lhs, *rhsp));
4444e4b17023SJohn Marino 	  VEC_free (ce_s, heap, rhsc);
4445e4b17023SJohn Marino 	}
4446e4b17023SJohn Marino 
4447e4b17023SJohn Marino       /* If we use a static chain, pass it along.  */
4448e4b17023SJohn Marino       if (gimple_call_chain (t))
4449e4b17023SJohn Marino 	{
4450e4b17023SJohn Marino 	  struct constraint_expr lhs;
4451e4b17023SJohn Marino 	  struct constraint_expr *rhsp;
4452e4b17023SJohn Marino 
4453e4b17023SJohn Marino 	  get_constraint_for (gimple_call_chain (t), &rhsc);
4454e4b17023SJohn Marino 	  lhs = get_function_part_constraint (fi, fi_static_chain);
4455e4b17023SJohn Marino 	  FOR_EACH_VEC_ELT (ce_s, rhsc, j, rhsp)
4456e4b17023SJohn Marino 	    process_constraint (new_constraint (lhs, *rhsp));
4457e4b17023SJohn Marino 	}
4458e4b17023SJohn Marino     }
4459e4b17023SJohn Marino }
4460e4b17023SJohn Marino 
4461e4b17023SJohn Marino /* Walk statement T setting up aliasing constraints according to the
4462e4b17023SJohn Marino    references found in T.  This function is the main part of the
4463e4b17023SJohn Marino    constraint builder.  AI points to auxiliary alias information used
4464e4b17023SJohn Marino    when building alias sets and computing alias grouping heuristics.  */
4465e4b17023SJohn Marino 
4466e4b17023SJohn Marino static void
find_func_aliases(gimple origt)4467e4b17023SJohn Marino find_func_aliases (gimple origt)
4468e4b17023SJohn Marino {
4469e4b17023SJohn Marino   gimple t = origt;
4470e4b17023SJohn Marino   VEC(ce_s, heap) *lhsc = NULL;
4471e4b17023SJohn Marino   VEC(ce_s, heap) *rhsc = NULL;
4472e4b17023SJohn Marino   struct constraint_expr *c;
4473e4b17023SJohn Marino   varinfo_t fi;
4474e4b17023SJohn Marino 
4475e4b17023SJohn Marino   /* Now build constraints expressions.  */
4476e4b17023SJohn Marino   if (gimple_code (t) == GIMPLE_PHI)
4477e4b17023SJohn Marino     {
4478e4b17023SJohn Marino       size_t i;
4479e4b17023SJohn Marino       unsigned int j;
4480e4b17023SJohn Marino 
4481e4b17023SJohn Marino       /* For a phi node, assign all the arguments to
4482e4b17023SJohn Marino 	 the result.  */
4483e4b17023SJohn Marino       get_constraint_for (gimple_phi_result (t), &lhsc);
4484e4b17023SJohn Marino       for (i = 0; i < gimple_phi_num_args (t); i++)
4485e4b17023SJohn Marino 	{
4486e4b17023SJohn Marino 	  tree strippedrhs = PHI_ARG_DEF (t, i);
4487e4b17023SJohn Marino 
4488e4b17023SJohn Marino 	  STRIP_NOPS (strippedrhs);
4489e4b17023SJohn Marino 	  get_constraint_for_rhs (gimple_phi_arg_def (t, i), &rhsc);
4490e4b17023SJohn Marino 
4491e4b17023SJohn Marino 	  FOR_EACH_VEC_ELT (ce_s, lhsc, j, c)
4492e4b17023SJohn Marino 	    {
4493e4b17023SJohn Marino 	      struct constraint_expr *c2;
4494e4b17023SJohn Marino 	      while (VEC_length (ce_s, rhsc) > 0)
4495e4b17023SJohn Marino 		{
4496e4b17023SJohn Marino 		  c2 = VEC_last (ce_s, rhsc);
4497e4b17023SJohn Marino 		  process_constraint (new_constraint (*c, *c2));
4498e4b17023SJohn Marino 		  VEC_pop (ce_s, rhsc);
4499e4b17023SJohn Marino 		}
4500e4b17023SJohn Marino 	    }
4501e4b17023SJohn Marino 	}
4502e4b17023SJohn Marino     }
4503e4b17023SJohn Marino   /* In IPA mode, we need to generate constraints to pass call
4504e4b17023SJohn Marino      arguments through their calls.   There are two cases,
4505e4b17023SJohn Marino      either a GIMPLE_CALL returning a value, or just a plain
4506e4b17023SJohn Marino      GIMPLE_CALL when we are not.
4507e4b17023SJohn Marino 
4508e4b17023SJohn Marino      In non-ipa mode, we need to generate constraints for each
4509e4b17023SJohn Marino      pointer passed by address.  */
4510e4b17023SJohn Marino   else if (is_gimple_call (t))
4511e4b17023SJohn Marino     find_func_aliases_for_call (t);
4512e4b17023SJohn Marino 
4513e4b17023SJohn Marino   /* Otherwise, just a regular assignment statement.  Only care about
4514e4b17023SJohn Marino      operations with pointer result, others are dealt with as escape
4515e4b17023SJohn Marino      points if they have pointer operands.  */
4516e4b17023SJohn Marino   else if (is_gimple_assign (t))
4517e4b17023SJohn Marino     {
4518e4b17023SJohn Marino       /* Otherwise, just a regular assignment statement.  */
4519e4b17023SJohn Marino       tree lhsop = gimple_assign_lhs (t);
4520e4b17023SJohn Marino       tree rhsop = (gimple_num_ops (t) == 2) ? gimple_assign_rhs1 (t) : NULL;
4521e4b17023SJohn Marino 
4522e4b17023SJohn Marino       if (rhsop && TREE_CLOBBER_P (rhsop))
4523e4b17023SJohn Marino 	/* Ignore clobbers, they don't actually store anything into
4524e4b17023SJohn Marino 	   the LHS.  */
4525e4b17023SJohn Marino 	;
4526e4b17023SJohn Marino       else if (rhsop && AGGREGATE_TYPE_P (TREE_TYPE (lhsop)))
4527e4b17023SJohn Marino 	do_structure_copy (lhsop, rhsop);
4528e4b17023SJohn Marino       else
4529e4b17023SJohn Marino 	{
4530e4b17023SJohn Marino 	  enum tree_code code = gimple_assign_rhs_code (t);
4531e4b17023SJohn Marino 
4532e4b17023SJohn Marino 	  get_constraint_for (lhsop, &lhsc);
4533e4b17023SJohn Marino 
4534e4b17023SJohn Marino 	  if (code == POINTER_PLUS_EXPR)
4535e4b17023SJohn Marino 	    get_constraint_for_ptr_offset (gimple_assign_rhs1 (t),
4536e4b17023SJohn Marino 					   gimple_assign_rhs2 (t), &rhsc);
4537e4b17023SJohn Marino 	  else if (code == BIT_AND_EXPR
4538e4b17023SJohn Marino 		   && TREE_CODE (gimple_assign_rhs2 (t)) == INTEGER_CST)
4539e4b17023SJohn Marino 	    {
4540e4b17023SJohn Marino 	      /* Aligning a pointer via a BIT_AND_EXPR is offsetting
4541e4b17023SJohn Marino 		 the pointer.  Handle it by offsetting it by UNKNOWN.  */
4542e4b17023SJohn Marino 	      get_constraint_for_ptr_offset (gimple_assign_rhs1 (t),
4543e4b17023SJohn Marino 					     NULL_TREE, &rhsc);
4544e4b17023SJohn Marino 	    }
4545e4b17023SJohn Marino 	  else if ((CONVERT_EXPR_CODE_P (code)
4546e4b17023SJohn Marino 		    && !(POINTER_TYPE_P (gimple_expr_type (t))
4547e4b17023SJohn Marino 			 && !POINTER_TYPE_P (TREE_TYPE (rhsop))))
4548e4b17023SJohn Marino 		   || gimple_assign_single_p (t))
4549e4b17023SJohn Marino 	    get_constraint_for_rhs (rhsop, &rhsc);
4550e4b17023SJohn Marino 	  else if (truth_value_p (code))
4551e4b17023SJohn Marino 	    /* Truth value results are not pointer (parts).  Or at least
4552e4b17023SJohn Marino 	       very very unreasonable obfuscation of a part.  */
4553e4b17023SJohn Marino 	    ;
4554e4b17023SJohn Marino 	  else
4555e4b17023SJohn Marino 	    {
4556e4b17023SJohn Marino 	      /* All other operations are merges.  */
4557e4b17023SJohn Marino 	      VEC (ce_s, heap) *tmp = NULL;
4558e4b17023SJohn Marino 	      struct constraint_expr *rhsp;
4559e4b17023SJohn Marino 	      unsigned i, j;
4560e4b17023SJohn Marino 	      get_constraint_for_rhs (gimple_assign_rhs1 (t), &rhsc);
4561e4b17023SJohn Marino 	      for (i = 2; i < gimple_num_ops (t); ++i)
4562e4b17023SJohn Marino 		{
4563e4b17023SJohn Marino 		  get_constraint_for_rhs (gimple_op (t, i), &tmp);
4564e4b17023SJohn Marino 		  FOR_EACH_VEC_ELT (ce_s, tmp, j, rhsp)
4565e4b17023SJohn Marino 		    VEC_safe_push (ce_s, heap, rhsc, rhsp);
4566e4b17023SJohn Marino 		  VEC_truncate (ce_s, tmp, 0);
4567e4b17023SJohn Marino 		}
4568e4b17023SJohn Marino 	      VEC_free (ce_s, heap, tmp);
4569e4b17023SJohn Marino 	    }
4570e4b17023SJohn Marino 	  process_all_all_constraints (lhsc, rhsc);
4571e4b17023SJohn Marino 	}
4572e4b17023SJohn Marino       /* If there is a store to a global variable the rhs escapes.  */
4573e4b17023SJohn Marino       if ((lhsop = get_base_address (lhsop)) != NULL_TREE
4574e4b17023SJohn Marino 	  && DECL_P (lhsop)
4575e4b17023SJohn Marino 	  && is_global_var (lhsop)
4576e4b17023SJohn Marino 	  && (!in_ipa_mode
4577e4b17023SJohn Marino 	      || DECL_EXTERNAL (lhsop) || TREE_PUBLIC (lhsop)))
4578e4b17023SJohn Marino 	make_escape_constraint (rhsop);
4579e4b17023SJohn Marino     }
4580e4b17023SJohn Marino   /* Handle escapes through return.  */
4581e4b17023SJohn Marino   else if (gimple_code (t) == GIMPLE_RETURN
4582e4b17023SJohn Marino 	   && gimple_return_retval (t) != NULL_TREE)
4583e4b17023SJohn Marino     {
4584e4b17023SJohn Marino       fi = NULL;
4585e4b17023SJohn Marino       if (!in_ipa_mode
4586e4b17023SJohn Marino 	  || !(fi = get_vi_for_tree (cfun->decl)))
4587e4b17023SJohn Marino 	make_escape_constraint (gimple_return_retval (t));
4588e4b17023SJohn Marino       else if (in_ipa_mode
4589e4b17023SJohn Marino 	       && fi != NULL)
4590e4b17023SJohn Marino 	{
4591e4b17023SJohn Marino 	  struct constraint_expr lhs ;
4592e4b17023SJohn Marino 	  struct constraint_expr *rhsp;
4593e4b17023SJohn Marino 	  unsigned i;
4594e4b17023SJohn Marino 
4595e4b17023SJohn Marino 	  lhs = get_function_part_constraint (fi, fi_result);
4596e4b17023SJohn Marino 	  get_constraint_for_rhs (gimple_return_retval (t), &rhsc);
4597e4b17023SJohn Marino 	  FOR_EACH_VEC_ELT (ce_s, rhsc, i, rhsp)
4598e4b17023SJohn Marino 	    process_constraint (new_constraint (lhs, *rhsp));
4599e4b17023SJohn Marino 	}
4600e4b17023SJohn Marino     }
4601e4b17023SJohn Marino   /* Handle asms conservatively by adding escape constraints to everything.  */
4602e4b17023SJohn Marino   else if (gimple_code (t) == GIMPLE_ASM)
4603e4b17023SJohn Marino     {
4604e4b17023SJohn Marino       unsigned i, noutputs;
4605e4b17023SJohn Marino       const char **oconstraints;
4606e4b17023SJohn Marino       const char *constraint;
4607e4b17023SJohn Marino       bool allows_mem, allows_reg, is_inout;
4608e4b17023SJohn Marino 
4609e4b17023SJohn Marino       noutputs = gimple_asm_noutputs (t);
4610e4b17023SJohn Marino       oconstraints = XALLOCAVEC (const char *, noutputs);
4611e4b17023SJohn Marino 
4612e4b17023SJohn Marino       for (i = 0; i < noutputs; ++i)
4613e4b17023SJohn Marino 	{
4614e4b17023SJohn Marino 	  tree link = gimple_asm_output_op (t, i);
4615e4b17023SJohn Marino 	  tree op = TREE_VALUE (link);
4616e4b17023SJohn Marino 
4617e4b17023SJohn Marino 	  constraint = TREE_STRING_POINTER (TREE_VALUE (TREE_PURPOSE (link)));
4618e4b17023SJohn Marino 	  oconstraints[i] = constraint;
4619e4b17023SJohn Marino 	  parse_output_constraint (&constraint, i, 0, 0, &allows_mem,
4620e4b17023SJohn Marino 				   &allows_reg, &is_inout);
4621e4b17023SJohn Marino 
4622e4b17023SJohn Marino 	  /* A memory constraint makes the address of the operand escape.  */
4623e4b17023SJohn Marino 	  if (!allows_reg && allows_mem)
4624e4b17023SJohn Marino 	    make_escape_constraint (build_fold_addr_expr (op));
4625e4b17023SJohn Marino 
4626e4b17023SJohn Marino 	  /* The asm may read global memory, so outputs may point to
4627e4b17023SJohn Marino 	     any global memory.  */
4628e4b17023SJohn Marino 	  if (op)
4629e4b17023SJohn Marino 	    {
4630e4b17023SJohn Marino 	      VEC(ce_s, heap) *lhsc = NULL;
4631e4b17023SJohn Marino 	      struct constraint_expr rhsc, *lhsp;
4632e4b17023SJohn Marino 	      unsigned j;
4633e4b17023SJohn Marino 	      get_constraint_for (op, &lhsc);
4634e4b17023SJohn Marino 	      rhsc.var = nonlocal_id;
4635e4b17023SJohn Marino 	      rhsc.offset = 0;
4636e4b17023SJohn Marino 	      rhsc.type = SCALAR;
4637e4b17023SJohn Marino 	      FOR_EACH_VEC_ELT (ce_s, lhsc, j, lhsp)
4638e4b17023SJohn Marino 		process_constraint (new_constraint (*lhsp, rhsc));
4639e4b17023SJohn Marino 	      VEC_free (ce_s, heap, lhsc);
4640e4b17023SJohn Marino 	    }
4641e4b17023SJohn Marino 	}
4642e4b17023SJohn Marino       for (i = 0; i < gimple_asm_ninputs (t); ++i)
4643e4b17023SJohn Marino 	{
4644e4b17023SJohn Marino 	  tree link = gimple_asm_input_op (t, i);
4645e4b17023SJohn Marino 	  tree op = TREE_VALUE (link);
4646e4b17023SJohn Marino 
4647e4b17023SJohn Marino 	  constraint = TREE_STRING_POINTER (TREE_VALUE (TREE_PURPOSE (link)));
4648e4b17023SJohn Marino 
4649e4b17023SJohn Marino 	  parse_input_constraint (&constraint, 0, 0, noutputs, 0, oconstraints,
4650e4b17023SJohn Marino 				  &allows_mem, &allows_reg);
4651e4b17023SJohn Marino 
4652e4b17023SJohn Marino 	  /* A memory constraint makes the address of the operand escape.  */
4653e4b17023SJohn Marino 	  if (!allows_reg && allows_mem)
4654e4b17023SJohn Marino 	    make_escape_constraint (build_fold_addr_expr (op));
4655e4b17023SJohn Marino 	  /* Strictly we'd only need the constraint to ESCAPED if
4656e4b17023SJohn Marino 	     the asm clobbers memory, otherwise using something
4657e4b17023SJohn Marino 	     along the lines of per-call clobbers/uses would be enough.  */
4658e4b17023SJohn Marino 	  else if (op)
4659e4b17023SJohn Marino 	    make_escape_constraint (op);
4660e4b17023SJohn Marino 	}
4661e4b17023SJohn Marino     }
4662e4b17023SJohn Marino 
4663e4b17023SJohn Marino   VEC_free (ce_s, heap, rhsc);
4664e4b17023SJohn Marino   VEC_free (ce_s, heap, lhsc);
4665e4b17023SJohn Marino }
4666e4b17023SJohn Marino 
4667e4b17023SJohn Marino 
4668e4b17023SJohn Marino /* Create a constraint adding to the clobber set of FI the memory
4669e4b17023SJohn Marino    pointed to by PTR.  */
4670e4b17023SJohn Marino 
4671e4b17023SJohn Marino static void
process_ipa_clobber(varinfo_t fi,tree ptr)4672e4b17023SJohn Marino process_ipa_clobber (varinfo_t fi, tree ptr)
4673e4b17023SJohn Marino {
4674e4b17023SJohn Marino   VEC(ce_s, heap) *ptrc = NULL;
4675e4b17023SJohn Marino   struct constraint_expr *c, lhs;
4676e4b17023SJohn Marino   unsigned i;
4677e4b17023SJohn Marino   get_constraint_for_rhs (ptr, &ptrc);
4678e4b17023SJohn Marino   lhs = get_function_part_constraint (fi, fi_clobbers);
4679e4b17023SJohn Marino   FOR_EACH_VEC_ELT (ce_s, ptrc, i, c)
4680e4b17023SJohn Marino     process_constraint (new_constraint (lhs, *c));
4681e4b17023SJohn Marino   VEC_free (ce_s, heap, ptrc);
4682e4b17023SJohn Marino }
4683e4b17023SJohn Marino 
4684e4b17023SJohn Marino /* Walk statement T setting up clobber and use constraints according to the
4685e4b17023SJohn Marino    references found in T.  This function is a main part of the
4686e4b17023SJohn Marino    IPA constraint builder.  */
4687e4b17023SJohn Marino 
4688e4b17023SJohn Marino static void
find_func_clobbers(gimple origt)4689e4b17023SJohn Marino find_func_clobbers (gimple origt)
4690e4b17023SJohn Marino {
4691e4b17023SJohn Marino   gimple t = origt;
4692e4b17023SJohn Marino   VEC(ce_s, heap) *lhsc = NULL;
4693e4b17023SJohn Marino   VEC(ce_s, heap) *rhsc = NULL;
4694e4b17023SJohn Marino   varinfo_t fi;
4695e4b17023SJohn Marino 
4696e4b17023SJohn Marino   /* Add constraints for clobbered/used in IPA mode.
4697e4b17023SJohn Marino      We are not interested in what automatic variables are clobbered
4698e4b17023SJohn Marino      or used as we only use the information in the caller to which
4699e4b17023SJohn Marino      they do not escape.  */
4700e4b17023SJohn Marino   gcc_assert (in_ipa_mode);
4701e4b17023SJohn Marino 
4702e4b17023SJohn Marino   /* If the stmt refers to memory in any way it better had a VUSE.  */
4703e4b17023SJohn Marino   if (gimple_vuse (t) == NULL_TREE)
4704e4b17023SJohn Marino     return;
4705e4b17023SJohn Marino 
4706e4b17023SJohn Marino   /* We'd better have function information for the current function.  */
4707e4b17023SJohn Marino   fi = lookup_vi_for_tree (cfun->decl);
4708e4b17023SJohn Marino   gcc_assert (fi != NULL);
4709e4b17023SJohn Marino 
4710e4b17023SJohn Marino   /* Account for stores in assignments and calls.  */
4711e4b17023SJohn Marino   if (gimple_vdef (t) != NULL_TREE
4712e4b17023SJohn Marino       && gimple_has_lhs (t))
4713e4b17023SJohn Marino     {
4714e4b17023SJohn Marino       tree lhs = gimple_get_lhs (t);
4715e4b17023SJohn Marino       tree tem = lhs;
4716e4b17023SJohn Marino       while (handled_component_p (tem))
4717e4b17023SJohn Marino 	tem = TREE_OPERAND (tem, 0);
4718e4b17023SJohn Marino       if ((DECL_P (tem)
4719e4b17023SJohn Marino 	   && !auto_var_in_fn_p (tem, cfun->decl))
4720e4b17023SJohn Marino 	  || INDIRECT_REF_P (tem)
4721e4b17023SJohn Marino 	  || (TREE_CODE (tem) == MEM_REF
4722e4b17023SJohn Marino 	      && !(TREE_CODE (TREE_OPERAND (tem, 0)) == ADDR_EXPR
4723e4b17023SJohn Marino 		   && auto_var_in_fn_p
4724e4b17023SJohn Marino 		        (TREE_OPERAND (TREE_OPERAND (tem, 0), 0), cfun->decl))))
4725e4b17023SJohn Marino 	{
4726e4b17023SJohn Marino 	  struct constraint_expr lhsc, *rhsp;
4727e4b17023SJohn Marino 	  unsigned i;
4728e4b17023SJohn Marino 	  lhsc = get_function_part_constraint (fi, fi_clobbers);
4729e4b17023SJohn Marino 	  get_constraint_for_address_of (lhs, &rhsc);
4730e4b17023SJohn Marino 	  FOR_EACH_VEC_ELT (ce_s, rhsc, i, rhsp)
4731e4b17023SJohn Marino 	    process_constraint (new_constraint (lhsc, *rhsp));
4732e4b17023SJohn Marino 	  VEC_free (ce_s, heap, rhsc);
4733e4b17023SJohn Marino 	}
4734e4b17023SJohn Marino     }
4735e4b17023SJohn Marino 
4736e4b17023SJohn Marino   /* Account for uses in assigments and returns.  */
4737e4b17023SJohn Marino   if (gimple_assign_single_p (t)
4738e4b17023SJohn Marino       || (gimple_code (t) == GIMPLE_RETURN
4739e4b17023SJohn Marino 	  && gimple_return_retval (t) != NULL_TREE))
4740e4b17023SJohn Marino     {
4741e4b17023SJohn Marino       tree rhs = (gimple_assign_single_p (t)
4742e4b17023SJohn Marino 		  ? gimple_assign_rhs1 (t) : gimple_return_retval (t));
4743e4b17023SJohn Marino       tree tem = rhs;
4744e4b17023SJohn Marino       while (handled_component_p (tem))
4745e4b17023SJohn Marino 	tem = TREE_OPERAND (tem, 0);
4746e4b17023SJohn Marino       if ((DECL_P (tem)
4747e4b17023SJohn Marino 	   && !auto_var_in_fn_p (tem, cfun->decl))
4748e4b17023SJohn Marino 	  || INDIRECT_REF_P (tem)
4749e4b17023SJohn Marino 	  || (TREE_CODE (tem) == MEM_REF
4750e4b17023SJohn Marino 	      && !(TREE_CODE (TREE_OPERAND (tem, 0)) == ADDR_EXPR
4751e4b17023SJohn Marino 		   && auto_var_in_fn_p
4752e4b17023SJohn Marino 		        (TREE_OPERAND (TREE_OPERAND (tem, 0), 0), cfun->decl))))
4753e4b17023SJohn Marino 	{
4754e4b17023SJohn Marino 	  struct constraint_expr lhs, *rhsp;
4755e4b17023SJohn Marino 	  unsigned i;
4756e4b17023SJohn Marino 	  lhs = get_function_part_constraint (fi, fi_uses);
4757e4b17023SJohn Marino 	  get_constraint_for_address_of (rhs, &rhsc);
4758e4b17023SJohn Marino 	  FOR_EACH_VEC_ELT (ce_s, rhsc, i, rhsp)
4759e4b17023SJohn Marino 	    process_constraint (new_constraint (lhs, *rhsp));
4760e4b17023SJohn Marino 	  VEC_free (ce_s, heap, rhsc);
4761e4b17023SJohn Marino 	}
4762e4b17023SJohn Marino     }
4763e4b17023SJohn Marino 
4764e4b17023SJohn Marino   if (is_gimple_call (t))
4765e4b17023SJohn Marino     {
4766e4b17023SJohn Marino       varinfo_t cfi = NULL;
4767e4b17023SJohn Marino       tree decl = gimple_call_fndecl (t);
4768e4b17023SJohn Marino       struct constraint_expr lhs, rhs;
4769e4b17023SJohn Marino       unsigned i, j;
4770e4b17023SJohn Marino 
4771e4b17023SJohn Marino       /* For builtins we do not have separate function info.  For those
4772e4b17023SJohn Marino 	 we do not generate escapes for we have to generate clobbers/uses.  */
4773*5ce9237cSJohn Marino       if (gimple_call_builtin_class_p (t, BUILT_IN_NORMAL))
4774e4b17023SJohn Marino 	switch (DECL_FUNCTION_CODE (decl))
4775e4b17023SJohn Marino 	  {
4776e4b17023SJohn Marino 	  /* The following functions use and clobber memory pointed to
4777e4b17023SJohn Marino 	     by their arguments.  */
4778e4b17023SJohn Marino 	  case BUILT_IN_STRCPY:
4779e4b17023SJohn Marino 	  case BUILT_IN_STRNCPY:
4780e4b17023SJohn Marino 	  case BUILT_IN_BCOPY:
4781e4b17023SJohn Marino 	  case BUILT_IN_MEMCPY:
4782e4b17023SJohn Marino 	  case BUILT_IN_MEMMOVE:
4783e4b17023SJohn Marino 	  case BUILT_IN_MEMPCPY:
4784e4b17023SJohn Marino 	  case BUILT_IN_STPCPY:
4785e4b17023SJohn Marino 	  case BUILT_IN_STPNCPY:
4786e4b17023SJohn Marino 	  case BUILT_IN_STRCAT:
4787e4b17023SJohn Marino 	  case BUILT_IN_STRNCAT:
4788e4b17023SJohn Marino 	  case BUILT_IN_STRCPY_CHK:
4789e4b17023SJohn Marino 	  case BUILT_IN_STRNCPY_CHK:
4790e4b17023SJohn Marino 	  case BUILT_IN_MEMCPY_CHK:
4791e4b17023SJohn Marino 	  case BUILT_IN_MEMMOVE_CHK:
4792e4b17023SJohn Marino 	  case BUILT_IN_MEMPCPY_CHK:
4793e4b17023SJohn Marino 	  case BUILT_IN_STPCPY_CHK:
4794e4b17023SJohn Marino 	  case BUILT_IN_STPNCPY_CHK:
4795e4b17023SJohn Marino 	  case BUILT_IN_STRCAT_CHK:
4796e4b17023SJohn Marino 	  case BUILT_IN_STRNCAT_CHK:
4797e4b17023SJohn Marino 	    {
4798e4b17023SJohn Marino 	      tree dest = gimple_call_arg (t, (DECL_FUNCTION_CODE (decl)
4799e4b17023SJohn Marino 					       == BUILT_IN_BCOPY ? 1 : 0));
4800e4b17023SJohn Marino 	      tree src = gimple_call_arg (t, (DECL_FUNCTION_CODE (decl)
4801e4b17023SJohn Marino 					      == BUILT_IN_BCOPY ? 0 : 1));
4802e4b17023SJohn Marino 	      unsigned i;
4803e4b17023SJohn Marino 	      struct constraint_expr *rhsp, *lhsp;
4804e4b17023SJohn Marino 	      get_constraint_for_ptr_offset (dest, NULL_TREE, &lhsc);
4805e4b17023SJohn Marino 	      lhs = get_function_part_constraint (fi, fi_clobbers);
4806e4b17023SJohn Marino 	      FOR_EACH_VEC_ELT (ce_s, lhsc, i, lhsp)
4807e4b17023SJohn Marino 		process_constraint (new_constraint (lhs, *lhsp));
4808e4b17023SJohn Marino 	      VEC_free (ce_s, heap, lhsc);
4809e4b17023SJohn Marino 	      get_constraint_for_ptr_offset (src, NULL_TREE, &rhsc);
4810e4b17023SJohn Marino 	      lhs = get_function_part_constraint (fi, fi_uses);
4811e4b17023SJohn Marino 	      FOR_EACH_VEC_ELT (ce_s, rhsc, i, rhsp)
4812e4b17023SJohn Marino 		process_constraint (new_constraint (lhs, *rhsp));
4813e4b17023SJohn Marino 	      VEC_free (ce_s, heap, rhsc);
4814e4b17023SJohn Marino 	      return;
4815e4b17023SJohn Marino 	    }
4816e4b17023SJohn Marino 	  /* The following function clobbers memory pointed to by
4817e4b17023SJohn Marino 	     its argument.  */
4818e4b17023SJohn Marino 	  case BUILT_IN_MEMSET:
4819e4b17023SJohn Marino 	  case BUILT_IN_MEMSET_CHK:
4820e4b17023SJohn Marino 	    {
4821e4b17023SJohn Marino 	      tree dest = gimple_call_arg (t, 0);
4822e4b17023SJohn Marino 	      unsigned i;
4823e4b17023SJohn Marino 	      ce_s *lhsp;
4824e4b17023SJohn Marino 	      get_constraint_for_ptr_offset (dest, NULL_TREE, &lhsc);
4825e4b17023SJohn Marino 	      lhs = get_function_part_constraint (fi, fi_clobbers);
4826e4b17023SJohn Marino 	      FOR_EACH_VEC_ELT (ce_s, lhsc, i, lhsp)
4827e4b17023SJohn Marino 		process_constraint (new_constraint (lhs, *lhsp));
4828e4b17023SJohn Marino 	      VEC_free (ce_s, heap, lhsc);
4829e4b17023SJohn Marino 	      return;
4830e4b17023SJohn Marino 	    }
4831e4b17023SJohn Marino 	  /* The following functions clobber their second and third
4832e4b17023SJohn Marino 	     arguments.  */
4833e4b17023SJohn Marino 	  case BUILT_IN_SINCOS:
4834e4b17023SJohn Marino 	  case BUILT_IN_SINCOSF:
4835e4b17023SJohn Marino 	  case BUILT_IN_SINCOSL:
4836e4b17023SJohn Marino 	    {
4837e4b17023SJohn Marino 	      process_ipa_clobber (fi, gimple_call_arg (t, 1));
4838e4b17023SJohn Marino 	      process_ipa_clobber (fi, gimple_call_arg (t, 2));
4839e4b17023SJohn Marino 	      return;
4840e4b17023SJohn Marino 	    }
4841e4b17023SJohn Marino 	  /* The following functions clobber their second argument.  */
4842e4b17023SJohn Marino 	  case BUILT_IN_FREXP:
4843e4b17023SJohn Marino 	  case BUILT_IN_FREXPF:
4844e4b17023SJohn Marino 	  case BUILT_IN_FREXPL:
4845e4b17023SJohn Marino 	  case BUILT_IN_LGAMMA_R:
4846e4b17023SJohn Marino 	  case BUILT_IN_LGAMMAF_R:
4847e4b17023SJohn Marino 	  case BUILT_IN_LGAMMAL_R:
4848e4b17023SJohn Marino 	  case BUILT_IN_GAMMA_R:
4849e4b17023SJohn Marino 	  case BUILT_IN_GAMMAF_R:
4850e4b17023SJohn Marino 	  case BUILT_IN_GAMMAL_R:
4851e4b17023SJohn Marino 	  case BUILT_IN_MODF:
4852e4b17023SJohn Marino 	  case BUILT_IN_MODFF:
4853e4b17023SJohn Marino 	  case BUILT_IN_MODFL:
4854e4b17023SJohn Marino 	    {
4855e4b17023SJohn Marino 	      process_ipa_clobber (fi, gimple_call_arg (t, 1));
4856e4b17023SJohn Marino 	      return;
4857e4b17023SJohn Marino 	    }
4858e4b17023SJohn Marino 	  /* The following functions clobber their third argument.  */
4859e4b17023SJohn Marino 	  case BUILT_IN_REMQUO:
4860e4b17023SJohn Marino 	  case BUILT_IN_REMQUOF:
4861e4b17023SJohn Marino 	  case BUILT_IN_REMQUOL:
4862e4b17023SJohn Marino 	    {
4863e4b17023SJohn Marino 	      process_ipa_clobber (fi, gimple_call_arg (t, 2));
4864e4b17023SJohn Marino 	      return;
4865e4b17023SJohn Marino 	    }
4866e4b17023SJohn Marino 	  /* The following functions neither read nor clobber memory.  */
4867e4b17023SJohn Marino 	  case BUILT_IN_ASSUME_ALIGNED:
4868e4b17023SJohn Marino 	  case BUILT_IN_FREE:
4869e4b17023SJohn Marino 	    return;
4870e4b17023SJohn Marino 	  /* Trampolines are of no interest to us.  */
4871e4b17023SJohn Marino 	  case BUILT_IN_INIT_TRAMPOLINE:
4872e4b17023SJohn Marino 	  case BUILT_IN_ADJUST_TRAMPOLINE:
4873e4b17023SJohn Marino 	    return;
4874e4b17023SJohn Marino 	  case BUILT_IN_VA_START:
4875e4b17023SJohn Marino 	  case BUILT_IN_VA_END:
4876e4b17023SJohn Marino 	    return;
4877e4b17023SJohn Marino 	  /* printf-style functions may have hooks to set pointers to
4878e4b17023SJohn Marino 	     point to somewhere into the generated string.  Leave them
4879e4b17023SJohn Marino 	     for a later excercise...  */
4880e4b17023SJohn Marino 	  default:
4881e4b17023SJohn Marino 	    /* Fallthru to general call handling.  */;
4882e4b17023SJohn Marino 	  }
4883e4b17023SJohn Marino 
4884e4b17023SJohn Marino       /* Parameters passed by value are used.  */
4885e4b17023SJohn Marino       lhs = get_function_part_constraint (fi, fi_uses);
4886e4b17023SJohn Marino       for (i = 0; i < gimple_call_num_args (t); i++)
4887e4b17023SJohn Marino 	{
4888e4b17023SJohn Marino 	  struct constraint_expr *rhsp;
4889e4b17023SJohn Marino 	  tree arg = gimple_call_arg (t, i);
4890e4b17023SJohn Marino 
4891e4b17023SJohn Marino 	  if (TREE_CODE (arg) == SSA_NAME
4892e4b17023SJohn Marino 	      || is_gimple_min_invariant (arg))
4893e4b17023SJohn Marino 	    continue;
4894e4b17023SJohn Marino 
4895e4b17023SJohn Marino 	  get_constraint_for_address_of (arg, &rhsc);
4896e4b17023SJohn Marino 	  FOR_EACH_VEC_ELT (ce_s, rhsc, j, rhsp)
4897e4b17023SJohn Marino 	    process_constraint (new_constraint (lhs, *rhsp));
4898e4b17023SJohn Marino 	  VEC_free (ce_s, heap, rhsc);
4899e4b17023SJohn Marino 	}
4900e4b17023SJohn Marino 
4901e4b17023SJohn Marino       /* Build constraints for propagating clobbers/uses along the
4902e4b17023SJohn Marino 	 callgraph edges.  */
4903e4b17023SJohn Marino       cfi = get_fi_for_callee (t);
4904e4b17023SJohn Marino       if (cfi->id == anything_id)
4905e4b17023SJohn Marino 	{
4906e4b17023SJohn Marino 	  if (gimple_vdef (t))
4907e4b17023SJohn Marino 	    make_constraint_from (first_vi_for_offset (fi, fi_clobbers),
4908e4b17023SJohn Marino 				  anything_id);
4909e4b17023SJohn Marino 	  make_constraint_from (first_vi_for_offset (fi, fi_uses),
4910e4b17023SJohn Marino 				anything_id);
4911e4b17023SJohn Marino 	  return;
4912e4b17023SJohn Marino 	}
4913e4b17023SJohn Marino 
4914e4b17023SJohn Marino       /* For callees without function info (that's external functions),
4915e4b17023SJohn Marino 	 ESCAPED is clobbered and used.  */
4916e4b17023SJohn Marino       if (gimple_call_fndecl (t)
4917e4b17023SJohn Marino 	  && !cfi->is_fn_info)
4918e4b17023SJohn Marino 	{
4919e4b17023SJohn Marino 	  varinfo_t vi;
4920e4b17023SJohn Marino 
4921e4b17023SJohn Marino 	  if (gimple_vdef (t))
4922e4b17023SJohn Marino 	    make_copy_constraint (first_vi_for_offset (fi, fi_clobbers),
4923e4b17023SJohn Marino 				  escaped_id);
4924e4b17023SJohn Marino 	  make_copy_constraint (first_vi_for_offset (fi, fi_uses), escaped_id);
4925e4b17023SJohn Marino 
4926e4b17023SJohn Marino 	  /* Also honor the call statement use/clobber info.  */
4927e4b17023SJohn Marino 	  if ((vi = lookup_call_clobber_vi (t)) != NULL)
4928e4b17023SJohn Marino 	    make_copy_constraint (first_vi_for_offset (fi, fi_clobbers),
4929e4b17023SJohn Marino 				  vi->id);
4930e4b17023SJohn Marino 	  if ((vi = lookup_call_use_vi (t)) != NULL)
4931e4b17023SJohn Marino 	    make_copy_constraint (first_vi_for_offset (fi, fi_uses),
4932e4b17023SJohn Marino 				  vi->id);
4933e4b17023SJohn Marino 	  return;
4934e4b17023SJohn Marino 	}
4935e4b17023SJohn Marino 
4936e4b17023SJohn Marino       /* Otherwise the caller clobbers and uses what the callee does.
4937e4b17023SJohn Marino 	 ???  This should use a new complex constraint that filters
4938e4b17023SJohn Marino 	 local variables of the callee.  */
4939e4b17023SJohn Marino       if (gimple_vdef (t))
4940e4b17023SJohn Marino 	{
4941e4b17023SJohn Marino 	  lhs = get_function_part_constraint (fi, fi_clobbers);
4942e4b17023SJohn Marino 	  rhs = get_function_part_constraint (cfi, fi_clobbers);
4943e4b17023SJohn Marino 	  process_constraint (new_constraint (lhs, rhs));
4944e4b17023SJohn Marino 	}
4945e4b17023SJohn Marino       lhs = get_function_part_constraint (fi, fi_uses);
4946e4b17023SJohn Marino       rhs = get_function_part_constraint (cfi, fi_uses);
4947e4b17023SJohn Marino       process_constraint (new_constraint (lhs, rhs));
4948e4b17023SJohn Marino     }
4949e4b17023SJohn Marino   else if (gimple_code (t) == GIMPLE_ASM)
4950e4b17023SJohn Marino     {
4951e4b17023SJohn Marino       /* ???  Ick.  We can do better.  */
4952e4b17023SJohn Marino       if (gimple_vdef (t))
4953e4b17023SJohn Marino 	make_constraint_from (first_vi_for_offset (fi, fi_clobbers),
4954e4b17023SJohn Marino 			      anything_id);
4955e4b17023SJohn Marino       make_constraint_from (first_vi_for_offset (fi, fi_uses),
4956e4b17023SJohn Marino 			    anything_id);
4957e4b17023SJohn Marino     }
4958e4b17023SJohn Marino 
4959e4b17023SJohn Marino   VEC_free (ce_s, heap, rhsc);
4960e4b17023SJohn Marino }
4961e4b17023SJohn Marino 
4962e4b17023SJohn Marino 
4963e4b17023SJohn Marino /* Find the first varinfo in the same variable as START that overlaps with
4964e4b17023SJohn Marino    OFFSET.  Return NULL if we can't find one.  */
4965e4b17023SJohn Marino 
4966e4b17023SJohn Marino static varinfo_t
first_vi_for_offset(varinfo_t start,unsigned HOST_WIDE_INT offset)4967e4b17023SJohn Marino first_vi_for_offset (varinfo_t start, unsigned HOST_WIDE_INT offset)
4968e4b17023SJohn Marino {
4969e4b17023SJohn Marino   /* If the offset is outside of the variable, bail out.  */
4970e4b17023SJohn Marino   if (offset >= start->fullsize)
4971e4b17023SJohn Marino     return NULL;
4972e4b17023SJohn Marino 
4973e4b17023SJohn Marino   /* If we cannot reach offset from start, lookup the first field
4974e4b17023SJohn Marino      and start from there.  */
4975e4b17023SJohn Marino   if (start->offset > offset)
4976e4b17023SJohn Marino     start = lookup_vi_for_tree (start->decl);
4977e4b17023SJohn Marino 
4978e4b17023SJohn Marino   while (start)
4979e4b17023SJohn Marino     {
4980e4b17023SJohn Marino       /* We may not find a variable in the field list with the actual
4981e4b17023SJohn Marino 	 offset when when we have glommed a structure to a variable.
4982e4b17023SJohn Marino 	 In that case, however, offset should still be within the size
4983e4b17023SJohn Marino 	 of the variable. */
4984e4b17023SJohn Marino       if (offset >= start->offset
4985e4b17023SJohn Marino 	  && (offset - start->offset) < start->size)
4986e4b17023SJohn Marino 	return start;
4987e4b17023SJohn Marino 
4988e4b17023SJohn Marino       start= start->next;
4989e4b17023SJohn Marino     }
4990e4b17023SJohn Marino 
4991e4b17023SJohn Marino   return NULL;
4992e4b17023SJohn Marino }
4993e4b17023SJohn Marino 
4994e4b17023SJohn Marino /* Find the first varinfo in the same variable as START that overlaps with
4995e4b17023SJohn Marino    OFFSET.  If there is no such varinfo the varinfo directly preceding
4996e4b17023SJohn Marino    OFFSET is returned.  */
4997e4b17023SJohn Marino 
4998e4b17023SJohn Marino static varinfo_t
first_or_preceding_vi_for_offset(varinfo_t start,unsigned HOST_WIDE_INT offset)4999e4b17023SJohn Marino first_or_preceding_vi_for_offset (varinfo_t start,
5000e4b17023SJohn Marino 				  unsigned HOST_WIDE_INT offset)
5001e4b17023SJohn Marino {
5002e4b17023SJohn Marino   /* If we cannot reach offset from start, lookup the first field
5003e4b17023SJohn Marino      and start from there.  */
5004e4b17023SJohn Marino   if (start->offset > offset)
5005e4b17023SJohn Marino     start = lookup_vi_for_tree (start->decl);
5006e4b17023SJohn Marino 
5007e4b17023SJohn Marino   /* We may not find a variable in the field list with the actual
5008e4b17023SJohn Marino      offset when when we have glommed a structure to a variable.
5009e4b17023SJohn Marino      In that case, however, offset should still be within the size
5010e4b17023SJohn Marino      of the variable.
5011e4b17023SJohn Marino      If we got beyond the offset we look for return the field
5012e4b17023SJohn Marino      directly preceding offset which may be the last field.  */
5013e4b17023SJohn Marino   while (start->next
5014e4b17023SJohn Marino 	 && offset >= start->offset
5015e4b17023SJohn Marino 	 && !((offset - start->offset) < start->size))
5016e4b17023SJohn Marino     start = start->next;
5017e4b17023SJohn Marino 
5018e4b17023SJohn Marino   return start;
5019e4b17023SJohn Marino }
5020e4b17023SJohn Marino 
5021e4b17023SJohn Marino 
5022e4b17023SJohn Marino /* This structure is used during pushing fields onto the fieldstack
5023e4b17023SJohn Marino    to track the offset of the field, since bitpos_of_field gives it
5024e4b17023SJohn Marino    relative to its immediate containing type, and we want it relative
5025e4b17023SJohn Marino    to the ultimate containing object.  */
5026e4b17023SJohn Marino 
5027e4b17023SJohn Marino struct fieldoff
5028e4b17023SJohn Marino {
5029e4b17023SJohn Marino   /* Offset from the base of the base containing object to this field.  */
5030e4b17023SJohn Marino   HOST_WIDE_INT offset;
5031e4b17023SJohn Marino 
5032e4b17023SJohn Marino   /* Size, in bits, of the field.  */
5033e4b17023SJohn Marino   unsigned HOST_WIDE_INT size;
5034e4b17023SJohn Marino 
5035e4b17023SJohn Marino   unsigned has_unknown_size : 1;
5036e4b17023SJohn Marino 
5037e4b17023SJohn Marino   unsigned must_have_pointers : 1;
5038e4b17023SJohn Marino 
5039e4b17023SJohn Marino   unsigned may_have_pointers : 1;
5040e4b17023SJohn Marino 
5041e4b17023SJohn Marino   unsigned only_restrict_pointers : 1;
5042e4b17023SJohn Marino };
5043e4b17023SJohn Marino typedef struct fieldoff fieldoff_s;
5044e4b17023SJohn Marino 
5045e4b17023SJohn Marino DEF_VEC_O(fieldoff_s);
5046e4b17023SJohn Marino DEF_VEC_ALLOC_O(fieldoff_s,heap);
5047e4b17023SJohn Marino 
5048e4b17023SJohn Marino /* qsort comparison function for two fieldoff's PA and PB */
5049e4b17023SJohn Marino 
5050e4b17023SJohn Marino static int
fieldoff_compare(const void * pa,const void * pb)5051e4b17023SJohn Marino fieldoff_compare (const void *pa, const void *pb)
5052e4b17023SJohn Marino {
5053e4b17023SJohn Marino   const fieldoff_s *foa = (const fieldoff_s *)pa;
5054e4b17023SJohn Marino   const fieldoff_s *fob = (const fieldoff_s *)pb;
5055e4b17023SJohn Marino   unsigned HOST_WIDE_INT foasize, fobsize;
5056e4b17023SJohn Marino 
5057e4b17023SJohn Marino   if (foa->offset < fob->offset)
5058e4b17023SJohn Marino     return -1;
5059e4b17023SJohn Marino   else if (foa->offset > fob->offset)
5060e4b17023SJohn Marino     return 1;
5061e4b17023SJohn Marino 
5062e4b17023SJohn Marino   foasize = foa->size;
5063e4b17023SJohn Marino   fobsize = fob->size;
5064e4b17023SJohn Marino   if (foasize < fobsize)
5065e4b17023SJohn Marino     return -1;
5066e4b17023SJohn Marino   else if (foasize > fobsize)
5067e4b17023SJohn Marino     return 1;
5068e4b17023SJohn Marino   return 0;
5069e4b17023SJohn Marino }
5070e4b17023SJohn Marino 
5071e4b17023SJohn Marino /* Sort a fieldstack according to the field offset and sizes.  */
5072e4b17023SJohn Marino static void
sort_fieldstack(VEC (fieldoff_s,heap)* fieldstack)5073e4b17023SJohn Marino sort_fieldstack (VEC(fieldoff_s,heap) *fieldstack)
5074e4b17023SJohn Marino {
5075e4b17023SJohn Marino   VEC_qsort (fieldoff_s, fieldstack, fieldoff_compare);
5076e4b17023SJohn Marino }
5077e4b17023SJohn Marino 
5078e4b17023SJohn Marino /* Return true if T is a type that can have subvars.  */
5079e4b17023SJohn Marino 
5080e4b17023SJohn Marino static inline bool
type_can_have_subvars(const_tree t)5081e4b17023SJohn Marino type_can_have_subvars (const_tree t)
5082e4b17023SJohn Marino {
5083e4b17023SJohn Marino   /* Aggregates without overlapping fields can have subvars.  */
5084e4b17023SJohn Marino   return TREE_CODE (t) == RECORD_TYPE;
5085e4b17023SJohn Marino }
5086e4b17023SJohn Marino 
5087e4b17023SJohn Marino /* Return true if V is a tree that we can have subvars for.
5088e4b17023SJohn Marino    Normally, this is any aggregate type.  Also complex
5089e4b17023SJohn Marino    types which are not gimple registers can have subvars.  */
5090e4b17023SJohn Marino 
5091e4b17023SJohn Marino static inline bool
var_can_have_subvars(const_tree v)5092e4b17023SJohn Marino var_can_have_subvars (const_tree v)
5093e4b17023SJohn Marino {
5094e4b17023SJohn Marino   /* Volatile variables should never have subvars.  */
5095e4b17023SJohn Marino   if (TREE_THIS_VOLATILE (v))
5096e4b17023SJohn Marino     return false;
5097e4b17023SJohn Marino 
5098e4b17023SJohn Marino   /* Non decls or memory tags can never have subvars.  */
5099e4b17023SJohn Marino   if (!DECL_P (v))
5100e4b17023SJohn Marino     return false;
5101e4b17023SJohn Marino 
5102e4b17023SJohn Marino   return type_can_have_subvars (TREE_TYPE (v));
5103e4b17023SJohn Marino }
5104e4b17023SJohn Marino 
5105e4b17023SJohn Marino /* Return true if T is a type that does contain pointers.  */
5106e4b17023SJohn Marino 
5107e4b17023SJohn Marino static bool
type_must_have_pointers(tree type)5108e4b17023SJohn Marino type_must_have_pointers (tree type)
5109e4b17023SJohn Marino {
5110e4b17023SJohn Marino   if (POINTER_TYPE_P (type))
5111e4b17023SJohn Marino     return true;
5112e4b17023SJohn Marino 
5113e4b17023SJohn Marino   if (TREE_CODE (type) == ARRAY_TYPE)
5114e4b17023SJohn Marino     return type_must_have_pointers (TREE_TYPE (type));
5115e4b17023SJohn Marino 
5116e4b17023SJohn Marino   /* A function or method can have pointers as arguments, so track
5117e4b17023SJohn Marino      those separately.  */
5118e4b17023SJohn Marino   if (TREE_CODE (type) == FUNCTION_TYPE
5119e4b17023SJohn Marino       || TREE_CODE (type) == METHOD_TYPE)
5120e4b17023SJohn Marino     return true;
5121e4b17023SJohn Marino 
5122e4b17023SJohn Marino   return false;
5123e4b17023SJohn Marino }
5124e4b17023SJohn Marino 
5125e4b17023SJohn Marino static bool
field_must_have_pointers(tree t)5126e4b17023SJohn Marino field_must_have_pointers (tree t)
5127e4b17023SJohn Marino {
5128e4b17023SJohn Marino   return type_must_have_pointers (TREE_TYPE (t));
5129e4b17023SJohn Marino }
5130e4b17023SJohn Marino 
5131e4b17023SJohn Marino /* Given a TYPE, and a vector of field offsets FIELDSTACK, push all
5132e4b17023SJohn Marino    the fields of TYPE onto fieldstack, recording their offsets along
5133e4b17023SJohn Marino    the way.
5134e4b17023SJohn Marino 
5135e4b17023SJohn Marino    OFFSET is used to keep track of the offset in this entire
5136e4b17023SJohn Marino    structure, rather than just the immediately containing structure.
5137e4b17023SJohn Marino    Returns false if the caller is supposed to handle the field we
5138e4b17023SJohn Marino    recursed for.  */
5139e4b17023SJohn Marino 
5140e4b17023SJohn Marino static bool
push_fields_onto_fieldstack(tree type,VEC (fieldoff_s,heap)** fieldstack,HOST_WIDE_INT offset)5141e4b17023SJohn Marino push_fields_onto_fieldstack (tree type, VEC(fieldoff_s,heap) **fieldstack,
5142e4b17023SJohn Marino 			     HOST_WIDE_INT offset)
5143e4b17023SJohn Marino {
5144e4b17023SJohn Marino   tree field;
5145e4b17023SJohn Marino   bool empty_p = true;
5146e4b17023SJohn Marino 
5147e4b17023SJohn Marino   if (TREE_CODE (type) != RECORD_TYPE)
5148e4b17023SJohn Marino     return false;
5149e4b17023SJohn Marino 
5150e4b17023SJohn Marino   /* If the vector of fields is growing too big, bail out early.
5151e4b17023SJohn Marino      Callers check for VEC_length <= MAX_FIELDS_FOR_FIELD_SENSITIVE, make
5152e4b17023SJohn Marino      sure this fails.  */
5153e4b17023SJohn Marino   if (VEC_length (fieldoff_s, *fieldstack) > MAX_FIELDS_FOR_FIELD_SENSITIVE)
5154e4b17023SJohn Marino     return false;
5155e4b17023SJohn Marino 
5156e4b17023SJohn Marino   for (field = TYPE_FIELDS (type); field; field = DECL_CHAIN (field))
5157e4b17023SJohn Marino     if (TREE_CODE (field) == FIELD_DECL)
5158e4b17023SJohn Marino       {
5159e4b17023SJohn Marino 	bool push = false;
5160e4b17023SJohn Marino 	HOST_WIDE_INT foff = bitpos_of_field (field);
5161e4b17023SJohn Marino 
5162e4b17023SJohn Marino 	if (!var_can_have_subvars (field)
5163e4b17023SJohn Marino 	    || TREE_CODE (TREE_TYPE (field)) == QUAL_UNION_TYPE
5164e4b17023SJohn Marino 	    || TREE_CODE (TREE_TYPE (field)) == UNION_TYPE)
5165e4b17023SJohn Marino 	  push = true;
5166e4b17023SJohn Marino 	else if (!push_fields_onto_fieldstack
5167e4b17023SJohn Marino 		    (TREE_TYPE (field), fieldstack, offset + foff)
5168e4b17023SJohn Marino 		 && (DECL_SIZE (field)
5169e4b17023SJohn Marino 		     && !integer_zerop (DECL_SIZE (field))))
5170e4b17023SJohn Marino 	  /* Empty structures may have actual size, like in C++.  So
5171e4b17023SJohn Marino 	     see if we didn't push any subfields and the size is
5172e4b17023SJohn Marino 	     nonzero, push the field onto the stack.  */
5173e4b17023SJohn Marino 	  push = true;
5174e4b17023SJohn Marino 
5175e4b17023SJohn Marino 	if (push)
5176e4b17023SJohn Marino 	  {
5177e4b17023SJohn Marino 	    fieldoff_s *pair = NULL;
5178e4b17023SJohn Marino 	    bool has_unknown_size = false;
5179e4b17023SJohn Marino 	    bool must_have_pointers_p;
5180e4b17023SJohn Marino 
5181e4b17023SJohn Marino 	    if (!VEC_empty (fieldoff_s, *fieldstack))
5182e4b17023SJohn Marino 	      pair = VEC_last (fieldoff_s, *fieldstack);
5183e4b17023SJohn Marino 
5184e4b17023SJohn Marino 	    /* If there isn't anything at offset zero, create sth.  */
5185e4b17023SJohn Marino 	    if (!pair
5186e4b17023SJohn Marino 		&& offset + foff != 0)
5187e4b17023SJohn Marino 	      {
5188e4b17023SJohn Marino 		pair = VEC_safe_push (fieldoff_s, heap, *fieldstack, NULL);
5189e4b17023SJohn Marino 		pair->offset = 0;
5190e4b17023SJohn Marino 		pair->size = offset + foff;
5191e4b17023SJohn Marino 		pair->has_unknown_size = false;
5192e4b17023SJohn Marino 		pair->must_have_pointers = false;
5193e4b17023SJohn Marino 		pair->may_have_pointers = false;
5194e4b17023SJohn Marino 		pair->only_restrict_pointers = false;
5195e4b17023SJohn Marino 	      }
5196e4b17023SJohn Marino 
5197e4b17023SJohn Marino 	    if (!DECL_SIZE (field)
5198e4b17023SJohn Marino 		|| !host_integerp (DECL_SIZE (field), 1))
5199e4b17023SJohn Marino 	      has_unknown_size = true;
5200e4b17023SJohn Marino 
5201e4b17023SJohn Marino 	    /* If adjacent fields do not contain pointers merge them.  */
5202e4b17023SJohn Marino 	    must_have_pointers_p = field_must_have_pointers (field);
5203e4b17023SJohn Marino 	    if (pair
5204e4b17023SJohn Marino 		&& !has_unknown_size
5205e4b17023SJohn Marino 		&& !must_have_pointers_p
5206e4b17023SJohn Marino 		&& !pair->must_have_pointers
5207e4b17023SJohn Marino 		&& !pair->has_unknown_size
5208e4b17023SJohn Marino 		&& pair->offset + (HOST_WIDE_INT)pair->size == offset + foff)
5209e4b17023SJohn Marino 	      {
5210e4b17023SJohn Marino 		pair->size += TREE_INT_CST_LOW (DECL_SIZE (field));
5211e4b17023SJohn Marino 	      }
5212e4b17023SJohn Marino 	    else
5213e4b17023SJohn Marino 	      {
5214e4b17023SJohn Marino 		pair = VEC_safe_push (fieldoff_s, heap, *fieldstack, NULL);
5215e4b17023SJohn Marino 		pair->offset = offset + foff;
5216e4b17023SJohn Marino 		pair->has_unknown_size = has_unknown_size;
5217e4b17023SJohn Marino 		if (!has_unknown_size)
5218e4b17023SJohn Marino 		  pair->size = TREE_INT_CST_LOW (DECL_SIZE (field));
5219e4b17023SJohn Marino 		else
5220e4b17023SJohn Marino 		  pair->size = -1;
5221e4b17023SJohn Marino 		pair->must_have_pointers = must_have_pointers_p;
5222e4b17023SJohn Marino 		pair->may_have_pointers = true;
5223e4b17023SJohn Marino 		pair->only_restrict_pointers
5224e4b17023SJohn Marino 		  = (!has_unknown_size
5225e4b17023SJohn Marino 		     && POINTER_TYPE_P (TREE_TYPE (field))
5226e4b17023SJohn Marino 		     && TYPE_RESTRICT (TREE_TYPE (field)));
5227e4b17023SJohn Marino 	      }
5228e4b17023SJohn Marino 	  }
5229e4b17023SJohn Marino 
5230e4b17023SJohn Marino 	empty_p = false;
5231e4b17023SJohn Marino       }
5232e4b17023SJohn Marino 
5233e4b17023SJohn Marino   return !empty_p;
5234e4b17023SJohn Marino }
5235e4b17023SJohn Marino 
5236e4b17023SJohn Marino /* Count the number of arguments DECL has, and set IS_VARARGS to true
5237e4b17023SJohn Marino    if it is a varargs function.  */
5238e4b17023SJohn Marino 
5239e4b17023SJohn Marino static unsigned int
count_num_arguments(tree decl,bool * is_varargs)5240e4b17023SJohn Marino count_num_arguments (tree decl, bool *is_varargs)
5241e4b17023SJohn Marino {
5242e4b17023SJohn Marino   unsigned int num = 0;
5243e4b17023SJohn Marino   tree t;
5244e4b17023SJohn Marino 
5245e4b17023SJohn Marino   /* Capture named arguments for K&R functions.  They do not
5246e4b17023SJohn Marino      have a prototype and thus no TYPE_ARG_TYPES.  */
5247e4b17023SJohn Marino   for (t = DECL_ARGUMENTS (decl); t; t = DECL_CHAIN (t))
5248e4b17023SJohn Marino     ++num;
5249e4b17023SJohn Marino 
5250e4b17023SJohn Marino   /* Check if the function has variadic arguments.  */
5251e4b17023SJohn Marino   for (t = TYPE_ARG_TYPES (TREE_TYPE (decl)); t; t = TREE_CHAIN (t))
5252e4b17023SJohn Marino     if (TREE_VALUE (t) == void_type_node)
5253e4b17023SJohn Marino       break;
5254e4b17023SJohn Marino   if (!t)
5255e4b17023SJohn Marino     *is_varargs = true;
5256e4b17023SJohn Marino 
5257e4b17023SJohn Marino   return num;
5258e4b17023SJohn Marino }
5259e4b17023SJohn Marino 
5260e4b17023SJohn Marino /* Creation function node for DECL, using NAME, and return the index
5261e4b17023SJohn Marino    of the variable we've created for the function.  */
5262e4b17023SJohn Marino 
5263e4b17023SJohn Marino static varinfo_t
create_function_info_for(tree decl,const char * name)5264e4b17023SJohn Marino create_function_info_for (tree decl, const char *name)
5265e4b17023SJohn Marino {
5266e4b17023SJohn Marino   struct function *fn = DECL_STRUCT_FUNCTION (decl);
5267e4b17023SJohn Marino   varinfo_t vi, prev_vi;
5268e4b17023SJohn Marino   tree arg;
5269e4b17023SJohn Marino   unsigned int i;
5270e4b17023SJohn Marino   bool is_varargs = false;
5271e4b17023SJohn Marino   unsigned int num_args = count_num_arguments (decl, &is_varargs);
5272e4b17023SJohn Marino 
5273e4b17023SJohn Marino   /* Create the variable info.  */
5274e4b17023SJohn Marino 
5275e4b17023SJohn Marino   vi = new_var_info (decl, name);
5276e4b17023SJohn Marino   vi->offset = 0;
5277e4b17023SJohn Marino   vi->size = 1;
5278e4b17023SJohn Marino   vi->fullsize = fi_parm_base + num_args;
5279e4b17023SJohn Marino   vi->is_fn_info = 1;
5280e4b17023SJohn Marino   vi->may_have_pointers = false;
5281e4b17023SJohn Marino   if (is_varargs)
5282e4b17023SJohn Marino     vi->fullsize = ~0;
5283e4b17023SJohn Marino   insert_vi_for_tree (vi->decl, vi);
5284e4b17023SJohn Marino 
5285e4b17023SJohn Marino   prev_vi = vi;
5286e4b17023SJohn Marino 
5287e4b17023SJohn Marino   /* Create a variable for things the function clobbers and one for
5288e4b17023SJohn Marino      things the function uses.  */
5289e4b17023SJohn Marino     {
5290e4b17023SJohn Marino       varinfo_t clobbervi, usevi;
5291e4b17023SJohn Marino       const char *newname;
5292e4b17023SJohn Marino       char *tempname;
5293e4b17023SJohn Marino 
5294e4b17023SJohn Marino       asprintf (&tempname, "%s.clobber", name);
5295e4b17023SJohn Marino       newname = ggc_strdup (tempname);
5296e4b17023SJohn Marino       free (tempname);
5297e4b17023SJohn Marino 
5298e4b17023SJohn Marino       clobbervi = new_var_info (NULL, newname);
5299e4b17023SJohn Marino       clobbervi->offset = fi_clobbers;
5300e4b17023SJohn Marino       clobbervi->size = 1;
5301e4b17023SJohn Marino       clobbervi->fullsize = vi->fullsize;
5302e4b17023SJohn Marino       clobbervi->is_full_var = true;
5303e4b17023SJohn Marino       clobbervi->is_global_var = false;
5304e4b17023SJohn Marino       gcc_assert (prev_vi->offset < clobbervi->offset);
5305e4b17023SJohn Marino       prev_vi->next = clobbervi;
5306e4b17023SJohn Marino       prev_vi = clobbervi;
5307e4b17023SJohn Marino 
5308e4b17023SJohn Marino       asprintf (&tempname, "%s.use", name);
5309e4b17023SJohn Marino       newname = ggc_strdup (tempname);
5310e4b17023SJohn Marino       free (tempname);
5311e4b17023SJohn Marino 
5312e4b17023SJohn Marino       usevi = new_var_info (NULL, newname);
5313e4b17023SJohn Marino       usevi->offset = fi_uses;
5314e4b17023SJohn Marino       usevi->size = 1;
5315e4b17023SJohn Marino       usevi->fullsize = vi->fullsize;
5316e4b17023SJohn Marino       usevi->is_full_var = true;
5317e4b17023SJohn Marino       usevi->is_global_var = false;
5318e4b17023SJohn Marino       gcc_assert (prev_vi->offset < usevi->offset);
5319e4b17023SJohn Marino       prev_vi->next = usevi;
5320e4b17023SJohn Marino       prev_vi = usevi;
5321e4b17023SJohn Marino     }
5322e4b17023SJohn Marino 
5323e4b17023SJohn Marino   /* And one for the static chain.  */
5324e4b17023SJohn Marino   if (fn->static_chain_decl != NULL_TREE)
5325e4b17023SJohn Marino     {
5326e4b17023SJohn Marino       varinfo_t chainvi;
5327e4b17023SJohn Marino       const char *newname;
5328e4b17023SJohn Marino       char *tempname;
5329e4b17023SJohn Marino 
5330e4b17023SJohn Marino       asprintf (&tempname, "%s.chain", name);
5331e4b17023SJohn Marino       newname = ggc_strdup (tempname);
5332e4b17023SJohn Marino       free (tempname);
5333e4b17023SJohn Marino 
5334e4b17023SJohn Marino       chainvi = new_var_info (fn->static_chain_decl, newname);
5335e4b17023SJohn Marino       chainvi->offset = fi_static_chain;
5336e4b17023SJohn Marino       chainvi->size = 1;
5337e4b17023SJohn Marino       chainvi->fullsize = vi->fullsize;
5338e4b17023SJohn Marino       chainvi->is_full_var = true;
5339e4b17023SJohn Marino       chainvi->is_global_var = false;
5340e4b17023SJohn Marino       gcc_assert (prev_vi->offset < chainvi->offset);
5341e4b17023SJohn Marino       prev_vi->next = chainvi;
5342e4b17023SJohn Marino       prev_vi = chainvi;
5343e4b17023SJohn Marino       insert_vi_for_tree (fn->static_chain_decl, chainvi);
5344e4b17023SJohn Marino     }
5345e4b17023SJohn Marino 
5346e4b17023SJohn Marino   /* Create a variable for the return var.  */
5347e4b17023SJohn Marino   if (DECL_RESULT (decl) != NULL
5348e4b17023SJohn Marino       || !VOID_TYPE_P (TREE_TYPE (TREE_TYPE (decl))))
5349e4b17023SJohn Marino     {
5350e4b17023SJohn Marino       varinfo_t resultvi;
5351e4b17023SJohn Marino       const char *newname;
5352e4b17023SJohn Marino       char *tempname;
5353e4b17023SJohn Marino       tree resultdecl = decl;
5354e4b17023SJohn Marino 
5355e4b17023SJohn Marino       if (DECL_RESULT (decl))
5356e4b17023SJohn Marino 	resultdecl = DECL_RESULT (decl);
5357e4b17023SJohn Marino 
5358e4b17023SJohn Marino       asprintf (&tempname, "%s.result", name);
5359e4b17023SJohn Marino       newname = ggc_strdup (tempname);
5360e4b17023SJohn Marino       free (tempname);
5361e4b17023SJohn Marino 
5362e4b17023SJohn Marino       resultvi = new_var_info (resultdecl, newname);
5363e4b17023SJohn Marino       resultvi->offset = fi_result;
5364e4b17023SJohn Marino       resultvi->size = 1;
5365e4b17023SJohn Marino       resultvi->fullsize = vi->fullsize;
5366e4b17023SJohn Marino       resultvi->is_full_var = true;
5367e4b17023SJohn Marino       if (DECL_RESULT (decl))
5368e4b17023SJohn Marino 	resultvi->may_have_pointers = true;
5369e4b17023SJohn Marino       gcc_assert (prev_vi->offset < resultvi->offset);
5370e4b17023SJohn Marino       prev_vi->next = resultvi;
5371e4b17023SJohn Marino       prev_vi = resultvi;
5372e4b17023SJohn Marino       if (DECL_RESULT (decl))
5373e4b17023SJohn Marino 	insert_vi_for_tree (DECL_RESULT (decl), resultvi);
5374e4b17023SJohn Marino     }
5375e4b17023SJohn Marino 
5376e4b17023SJohn Marino   /* Set up variables for each argument.  */
5377e4b17023SJohn Marino   arg = DECL_ARGUMENTS (decl);
5378e4b17023SJohn Marino   for (i = 0; i < num_args; i++)
5379e4b17023SJohn Marino     {
5380e4b17023SJohn Marino       varinfo_t argvi;
5381e4b17023SJohn Marino       const char *newname;
5382e4b17023SJohn Marino       char *tempname;
5383e4b17023SJohn Marino       tree argdecl = decl;
5384e4b17023SJohn Marino 
5385e4b17023SJohn Marino       if (arg)
5386e4b17023SJohn Marino 	argdecl = arg;
5387e4b17023SJohn Marino 
5388e4b17023SJohn Marino       asprintf (&tempname, "%s.arg%d", name, i);
5389e4b17023SJohn Marino       newname = ggc_strdup (tempname);
5390e4b17023SJohn Marino       free (tempname);
5391e4b17023SJohn Marino 
5392e4b17023SJohn Marino       argvi = new_var_info (argdecl, newname);
5393e4b17023SJohn Marino       argvi->offset = fi_parm_base + i;
5394e4b17023SJohn Marino       argvi->size = 1;
5395e4b17023SJohn Marino       argvi->is_full_var = true;
5396e4b17023SJohn Marino       argvi->fullsize = vi->fullsize;
5397e4b17023SJohn Marino       if (arg)
5398e4b17023SJohn Marino 	argvi->may_have_pointers = true;
5399e4b17023SJohn Marino       gcc_assert (prev_vi->offset < argvi->offset);
5400e4b17023SJohn Marino       prev_vi->next = argvi;
5401e4b17023SJohn Marino       prev_vi = argvi;
5402e4b17023SJohn Marino       if (arg)
5403e4b17023SJohn Marino 	{
5404e4b17023SJohn Marino 	  insert_vi_for_tree (arg, argvi);
5405e4b17023SJohn Marino 	  arg = DECL_CHAIN (arg);
5406e4b17023SJohn Marino 	}
5407e4b17023SJohn Marino     }
5408e4b17023SJohn Marino 
5409e4b17023SJohn Marino   /* Add one representative for all further args.  */
5410e4b17023SJohn Marino   if (is_varargs)
5411e4b17023SJohn Marino     {
5412e4b17023SJohn Marino       varinfo_t argvi;
5413e4b17023SJohn Marino       const char *newname;
5414e4b17023SJohn Marino       char *tempname;
5415e4b17023SJohn Marino       tree decl;
5416e4b17023SJohn Marino 
5417e4b17023SJohn Marino       asprintf (&tempname, "%s.varargs", name);
5418e4b17023SJohn Marino       newname = ggc_strdup (tempname);
5419e4b17023SJohn Marino       free (tempname);
5420e4b17023SJohn Marino 
5421e4b17023SJohn Marino       /* We need sth that can be pointed to for va_start.  */
5422e4b17023SJohn Marino       decl = build_fake_var_decl (ptr_type_node);
5423e4b17023SJohn Marino 
5424e4b17023SJohn Marino       argvi = new_var_info (decl, newname);
5425e4b17023SJohn Marino       argvi->offset = fi_parm_base + num_args;
5426e4b17023SJohn Marino       argvi->size = ~0;
5427e4b17023SJohn Marino       argvi->is_full_var = true;
5428e4b17023SJohn Marino       argvi->is_heap_var = true;
5429e4b17023SJohn Marino       argvi->fullsize = vi->fullsize;
5430e4b17023SJohn Marino       gcc_assert (prev_vi->offset < argvi->offset);
5431e4b17023SJohn Marino       prev_vi->next = argvi;
5432e4b17023SJohn Marino       prev_vi = argvi;
5433e4b17023SJohn Marino     }
5434e4b17023SJohn Marino 
5435e4b17023SJohn Marino   return vi;
5436e4b17023SJohn Marino }
5437e4b17023SJohn Marino 
5438e4b17023SJohn Marino 
5439e4b17023SJohn Marino /* Return true if FIELDSTACK contains fields that overlap.
5440e4b17023SJohn Marino    FIELDSTACK is assumed to be sorted by offset.  */
5441e4b17023SJohn Marino 
5442e4b17023SJohn Marino static bool
check_for_overlaps(VEC (fieldoff_s,heap)* fieldstack)5443e4b17023SJohn Marino check_for_overlaps (VEC (fieldoff_s,heap) *fieldstack)
5444e4b17023SJohn Marino {
5445e4b17023SJohn Marino   fieldoff_s *fo = NULL;
5446e4b17023SJohn Marino   unsigned int i;
5447e4b17023SJohn Marino   HOST_WIDE_INT lastoffset = -1;
5448e4b17023SJohn Marino 
5449e4b17023SJohn Marino   FOR_EACH_VEC_ELT (fieldoff_s, fieldstack, i, fo)
5450e4b17023SJohn Marino     {
5451e4b17023SJohn Marino       if (fo->offset == lastoffset)
5452e4b17023SJohn Marino 	return true;
5453e4b17023SJohn Marino       lastoffset = fo->offset;
5454e4b17023SJohn Marino     }
5455e4b17023SJohn Marino   return false;
5456e4b17023SJohn Marino }
5457e4b17023SJohn Marino 
5458e4b17023SJohn Marino /* Create a varinfo structure for NAME and DECL, and add it to VARMAP.
5459e4b17023SJohn Marino    This will also create any varinfo structures necessary for fields
5460e4b17023SJohn Marino    of DECL.  */
5461e4b17023SJohn Marino 
5462e4b17023SJohn Marino static varinfo_t
create_variable_info_for_1(tree decl,const char * name)5463e4b17023SJohn Marino create_variable_info_for_1 (tree decl, const char *name)
5464e4b17023SJohn Marino {
5465e4b17023SJohn Marino   varinfo_t vi, newvi;
5466e4b17023SJohn Marino   tree decl_type = TREE_TYPE (decl);
5467e4b17023SJohn Marino   tree declsize = DECL_P (decl) ? DECL_SIZE (decl) : TYPE_SIZE (decl_type);
5468e4b17023SJohn Marino   VEC (fieldoff_s,heap) *fieldstack = NULL;
5469e4b17023SJohn Marino   fieldoff_s *fo;
5470e4b17023SJohn Marino   unsigned int i;
5471e4b17023SJohn Marino 
5472e4b17023SJohn Marino   if (!declsize
5473e4b17023SJohn Marino       || !host_integerp (declsize, 1))
5474e4b17023SJohn Marino     {
5475e4b17023SJohn Marino       vi = new_var_info (decl, name);
5476e4b17023SJohn Marino       vi->offset = 0;
5477e4b17023SJohn Marino       vi->size = ~0;
5478e4b17023SJohn Marino       vi->fullsize = ~0;
5479e4b17023SJohn Marino       vi->is_unknown_size_var = true;
5480e4b17023SJohn Marino       vi->is_full_var = true;
5481e4b17023SJohn Marino       vi->may_have_pointers = true;
5482e4b17023SJohn Marino       return vi;
5483e4b17023SJohn Marino     }
5484e4b17023SJohn Marino 
5485e4b17023SJohn Marino   /* Collect field information.  */
5486e4b17023SJohn Marino   if (use_field_sensitive
5487e4b17023SJohn Marino       && var_can_have_subvars (decl)
5488e4b17023SJohn Marino       /* ???  Force us to not use subfields for global initializers
5489e4b17023SJohn Marino 	 in IPA mode.  Else we'd have to parse arbitrary initializers.  */
5490e4b17023SJohn Marino       && !(in_ipa_mode
5491e4b17023SJohn Marino 	   && is_global_var (decl)
5492e4b17023SJohn Marino 	   && DECL_INITIAL (decl)))
5493e4b17023SJohn Marino     {
5494e4b17023SJohn Marino       fieldoff_s *fo = NULL;
5495e4b17023SJohn Marino       bool notokay = false;
5496e4b17023SJohn Marino       unsigned int i;
5497e4b17023SJohn Marino 
5498e4b17023SJohn Marino       push_fields_onto_fieldstack (decl_type, &fieldstack, 0);
5499e4b17023SJohn Marino 
5500e4b17023SJohn Marino       for (i = 0; !notokay && VEC_iterate (fieldoff_s, fieldstack, i, fo); i++)
5501e4b17023SJohn Marino 	if (fo->has_unknown_size
5502e4b17023SJohn Marino 	    || fo->offset < 0)
5503e4b17023SJohn Marino 	  {
5504e4b17023SJohn Marino 	    notokay = true;
5505e4b17023SJohn Marino 	    break;
5506e4b17023SJohn Marino 	  }
5507e4b17023SJohn Marino 
5508e4b17023SJohn Marino       /* We can't sort them if we have a field with a variable sized type,
5509e4b17023SJohn Marino 	 which will make notokay = true.  In that case, we are going to return
5510e4b17023SJohn Marino 	 without creating varinfos for the fields anyway, so sorting them is a
5511e4b17023SJohn Marino 	 waste to boot.  */
5512e4b17023SJohn Marino       if (!notokay)
5513e4b17023SJohn Marino 	{
5514e4b17023SJohn Marino 	  sort_fieldstack (fieldstack);
5515e4b17023SJohn Marino 	  /* Due to some C++ FE issues, like PR 22488, we might end up
5516e4b17023SJohn Marino 	     what appear to be overlapping fields even though they,
5517e4b17023SJohn Marino 	     in reality, do not overlap.  Until the C++ FE is fixed,
5518e4b17023SJohn Marino 	     we will simply disable field-sensitivity for these cases.  */
5519e4b17023SJohn Marino 	  notokay = check_for_overlaps (fieldstack);
5520e4b17023SJohn Marino 	}
5521e4b17023SJohn Marino 
5522e4b17023SJohn Marino       if (notokay)
5523e4b17023SJohn Marino 	VEC_free (fieldoff_s, heap, fieldstack);
5524e4b17023SJohn Marino     }
5525e4b17023SJohn Marino 
5526e4b17023SJohn Marino   /* If we didn't end up collecting sub-variables create a full
5527e4b17023SJohn Marino      variable for the decl.  */
5528e4b17023SJohn Marino   if (VEC_length (fieldoff_s, fieldstack) <= 1
5529e4b17023SJohn Marino       || VEC_length (fieldoff_s, fieldstack) > MAX_FIELDS_FOR_FIELD_SENSITIVE)
5530e4b17023SJohn Marino     {
5531e4b17023SJohn Marino       vi = new_var_info (decl, name);
5532e4b17023SJohn Marino       vi->offset = 0;
5533e4b17023SJohn Marino       vi->may_have_pointers = true;
5534e4b17023SJohn Marino       vi->fullsize = TREE_INT_CST_LOW (declsize);
5535e4b17023SJohn Marino       vi->size = vi->fullsize;
5536e4b17023SJohn Marino       vi->is_full_var = true;
5537e4b17023SJohn Marino       VEC_free (fieldoff_s, heap, fieldstack);
5538e4b17023SJohn Marino       return vi;
5539e4b17023SJohn Marino     }
5540e4b17023SJohn Marino 
5541e4b17023SJohn Marino   vi = new_var_info (decl, name);
5542e4b17023SJohn Marino   vi->fullsize = TREE_INT_CST_LOW (declsize);
5543e4b17023SJohn Marino   for (i = 0, newvi = vi;
5544e4b17023SJohn Marino        VEC_iterate (fieldoff_s, fieldstack, i, fo);
5545e4b17023SJohn Marino        ++i, newvi = newvi->next)
5546e4b17023SJohn Marino     {
5547e4b17023SJohn Marino       const char *newname = "NULL";
5548e4b17023SJohn Marino       char *tempname;
5549e4b17023SJohn Marino 
5550e4b17023SJohn Marino       if (dump_file)
5551e4b17023SJohn Marino 	{
5552e4b17023SJohn Marino 	  asprintf (&tempname, "%s." HOST_WIDE_INT_PRINT_DEC
5553e4b17023SJohn Marino 		    "+" HOST_WIDE_INT_PRINT_DEC, name, fo->offset, fo->size);
5554e4b17023SJohn Marino 	  newname = ggc_strdup (tempname);
5555e4b17023SJohn Marino 	  free (tempname);
5556e4b17023SJohn Marino 	}
5557e4b17023SJohn Marino       newvi->name = newname;
5558e4b17023SJohn Marino       newvi->offset = fo->offset;
5559e4b17023SJohn Marino       newvi->size = fo->size;
5560e4b17023SJohn Marino       newvi->fullsize = vi->fullsize;
5561e4b17023SJohn Marino       newvi->may_have_pointers = fo->may_have_pointers;
5562e4b17023SJohn Marino       newvi->only_restrict_pointers = fo->only_restrict_pointers;
5563e4b17023SJohn Marino       if (i + 1 < VEC_length (fieldoff_s, fieldstack))
5564e4b17023SJohn Marino 	newvi->next = new_var_info (decl, name);
5565e4b17023SJohn Marino     }
5566e4b17023SJohn Marino 
5567e4b17023SJohn Marino   VEC_free (fieldoff_s, heap, fieldstack);
5568e4b17023SJohn Marino 
5569e4b17023SJohn Marino   return vi;
5570e4b17023SJohn Marino }
5571e4b17023SJohn Marino 
5572e4b17023SJohn Marino static unsigned int
create_variable_info_for(tree decl,const char * name)5573e4b17023SJohn Marino create_variable_info_for (tree decl, const char *name)
5574e4b17023SJohn Marino {
5575e4b17023SJohn Marino   varinfo_t vi = create_variable_info_for_1 (decl, name);
5576e4b17023SJohn Marino   unsigned int id = vi->id;
5577e4b17023SJohn Marino 
5578e4b17023SJohn Marino   insert_vi_for_tree (decl, vi);
5579e4b17023SJohn Marino 
5580e4b17023SJohn Marino   if (TREE_CODE (decl) != VAR_DECL)
5581e4b17023SJohn Marino     return id;
5582e4b17023SJohn Marino 
5583e4b17023SJohn Marino   /* Create initial constraints for globals.  */
5584e4b17023SJohn Marino   for (; vi; vi = vi->next)
5585e4b17023SJohn Marino     {
5586e4b17023SJohn Marino       if (!vi->may_have_pointers
5587e4b17023SJohn Marino 	  || !vi->is_global_var)
5588e4b17023SJohn Marino 	continue;
5589e4b17023SJohn Marino 
5590e4b17023SJohn Marino       /* Mark global restrict qualified pointers.  */
5591e4b17023SJohn Marino       if ((POINTER_TYPE_P (TREE_TYPE (decl))
5592e4b17023SJohn Marino 	   && TYPE_RESTRICT (TREE_TYPE (decl)))
5593e4b17023SJohn Marino 	  || vi->only_restrict_pointers)
5594e4b17023SJohn Marino 	{
5595e4b17023SJohn Marino 	  make_constraint_from_global_restrict (vi, "GLOBAL_RESTRICT");
5596e4b17023SJohn Marino 	  continue;
5597e4b17023SJohn Marino 	}
5598e4b17023SJohn Marino 
5599e4b17023SJohn Marino       /* In non-IPA mode the initializer from nonlocal is all we need.  */
5600e4b17023SJohn Marino       if (!in_ipa_mode
5601e4b17023SJohn Marino 	  || DECL_HARD_REGISTER (decl))
5602e4b17023SJohn Marino 	make_copy_constraint (vi, nonlocal_id);
5603e4b17023SJohn Marino 
5604e4b17023SJohn Marino       /* In IPA mode parse the initializer and generate proper constraints
5605e4b17023SJohn Marino 	 for it.  */
5606e4b17023SJohn Marino       else
5607e4b17023SJohn Marino 	{
5608e4b17023SJohn Marino 	  struct varpool_node *vnode = varpool_get_node (decl);
5609e4b17023SJohn Marino 
5610e4b17023SJohn Marino 	  /* For escaped variables initialize them from nonlocal.  */
5611e4b17023SJohn Marino 	  if (!varpool_all_refs_explicit_p (vnode))
5612e4b17023SJohn Marino 	    make_copy_constraint (vi, nonlocal_id);
5613e4b17023SJohn Marino 
5614e4b17023SJohn Marino 	  /* If this is a global variable with an initializer and we are in
5615e4b17023SJohn Marino 	     IPA mode generate constraints for it.  */
5616e4b17023SJohn Marino 	  if (DECL_INITIAL (decl))
5617e4b17023SJohn Marino 	    {
5618e4b17023SJohn Marino 	      VEC (ce_s, heap) *rhsc = NULL;
5619e4b17023SJohn Marino 	      struct constraint_expr lhs, *rhsp;
5620e4b17023SJohn Marino 	      unsigned i;
5621e4b17023SJohn Marino 	      get_constraint_for_rhs (DECL_INITIAL (decl), &rhsc);
5622e4b17023SJohn Marino 	      lhs.var = vi->id;
5623e4b17023SJohn Marino 	      lhs.offset = 0;
5624e4b17023SJohn Marino 	      lhs.type = SCALAR;
5625e4b17023SJohn Marino 	      FOR_EACH_VEC_ELT (ce_s, rhsc, i, rhsp)
5626e4b17023SJohn Marino 		process_constraint (new_constraint (lhs, *rhsp));
5627e4b17023SJohn Marino 	      /* If this is a variable that escapes from the unit
5628e4b17023SJohn Marino 		 the initializer escapes as well.  */
5629e4b17023SJohn Marino 	      if (!varpool_all_refs_explicit_p (vnode))
5630e4b17023SJohn Marino 		{
5631e4b17023SJohn Marino 		  lhs.var = escaped_id;
5632e4b17023SJohn Marino 		  lhs.offset = 0;
5633e4b17023SJohn Marino 		  lhs.type = SCALAR;
5634e4b17023SJohn Marino 		  FOR_EACH_VEC_ELT (ce_s, rhsc, i, rhsp)
5635e4b17023SJohn Marino 		    process_constraint (new_constraint (lhs, *rhsp));
5636e4b17023SJohn Marino 		}
5637e4b17023SJohn Marino 	      VEC_free (ce_s, heap, rhsc);
5638e4b17023SJohn Marino 	    }
5639e4b17023SJohn Marino 	}
5640e4b17023SJohn Marino     }
5641e4b17023SJohn Marino 
5642e4b17023SJohn Marino   return id;
5643e4b17023SJohn Marino }
5644e4b17023SJohn Marino 
5645e4b17023SJohn Marino /* Print out the points-to solution for VAR to FILE.  */
5646e4b17023SJohn Marino 
5647e4b17023SJohn Marino static void
dump_solution_for_var(FILE * file,unsigned int var)5648e4b17023SJohn Marino dump_solution_for_var (FILE *file, unsigned int var)
5649e4b17023SJohn Marino {
5650e4b17023SJohn Marino   varinfo_t vi = get_varinfo (var);
5651e4b17023SJohn Marino   unsigned int i;
5652e4b17023SJohn Marino   bitmap_iterator bi;
5653e4b17023SJohn Marino 
5654e4b17023SJohn Marino   /* Dump the solution for unified vars anyway, this avoids difficulties
5655e4b17023SJohn Marino      in scanning dumps in the testsuite.  */
5656e4b17023SJohn Marino   fprintf (file, "%s = { ", vi->name);
5657e4b17023SJohn Marino   vi = get_varinfo (find (var));
5658e4b17023SJohn Marino   EXECUTE_IF_SET_IN_BITMAP (vi->solution, 0, i, bi)
5659e4b17023SJohn Marino     fprintf (file, "%s ", get_varinfo (i)->name);
5660e4b17023SJohn Marino   fprintf (file, "}");
5661e4b17023SJohn Marino 
5662e4b17023SJohn Marino   /* But note when the variable was unified.  */
5663e4b17023SJohn Marino   if (vi->id != var)
5664e4b17023SJohn Marino     fprintf (file, " same as %s", vi->name);
5665e4b17023SJohn Marino 
5666e4b17023SJohn Marino   fprintf (file, "\n");
5667e4b17023SJohn Marino }
5668e4b17023SJohn Marino 
5669e4b17023SJohn Marino /* Print the points-to solution for VAR to stdout.  */
5670e4b17023SJohn Marino 
5671e4b17023SJohn Marino DEBUG_FUNCTION void
debug_solution_for_var(unsigned int var)5672e4b17023SJohn Marino debug_solution_for_var (unsigned int var)
5673e4b17023SJohn Marino {
5674e4b17023SJohn Marino   dump_solution_for_var (stdout, var);
5675e4b17023SJohn Marino }
5676e4b17023SJohn Marino 
5677e4b17023SJohn Marino /* Create varinfo structures for all of the variables in the
5678e4b17023SJohn Marino    function for intraprocedural mode.  */
5679e4b17023SJohn Marino 
5680e4b17023SJohn Marino static void
intra_create_variable_infos(void)5681e4b17023SJohn Marino intra_create_variable_infos (void)
5682e4b17023SJohn Marino {
5683e4b17023SJohn Marino   tree t;
5684e4b17023SJohn Marino 
5685e4b17023SJohn Marino   /* For each incoming pointer argument arg, create the constraint ARG
5686e4b17023SJohn Marino      = NONLOCAL or a dummy variable if it is a restrict qualified
5687e4b17023SJohn Marino      passed-by-reference argument.  */
5688e4b17023SJohn Marino   for (t = DECL_ARGUMENTS (current_function_decl); t; t = DECL_CHAIN (t))
5689e4b17023SJohn Marino     {
5690e4b17023SJohn Marino       varinfo_t p = get_vi_for_tree (t);
5691e4b17023SJohn Marino 
5692e4b17023SJohn Marino       /* For restrict qualified pointers to objects passed by
5693e4b17023SJohn Marino          reference build a real representative for the pointed-to object.
5694e4b17023SJohn Marino 	 Treat restrict qualified references the same.  */
5695e4b17023SJohn Marino       if (TYPE_RESTRICT (TREE_TYPE (t))
5696e4b17023SJohn Marino 	  && ((DECL_BY_REFERENCE (t) && POINTER_TYPE_P (TREE_TYPE (t)))
5697e4b17023SJohn Marino 	      || TREE_CODE (TREE_TYPE (t)) == REFERENCE_TYPE)
5698e4b17023SJohn Marino 	  && !type_contains_placeholder_p (TREE_TYPE (TREE_TYPE (t))))
5699e4b17023SJohn Marino 	{
5700e4b17023SJohn Marino 	  struct constraint_expr lhsc, rhsc;
5701e4b17023SJohn Marino 	  varinfo_t vi;
5702e4b17023SJohn Marino 	  tree heapvar = build_fake_var_decl (TREE_TYPE (TREE_TYPE (t)));
5703e4b17023SJohn Marino 	  DECL_EXTERNAL (heapvar) = 1;
5704e4b17023SJohn Marino 	  vi = create_variable_info_for_1 (heapvar, "PARM_NOALIAS");
5705e4b17023SJohn Marino 	  insert_vi_for_tree (heapvar, vi);
5706e4b17023SJohn Marino 	  lhsc.var = p->id;
5707e4b17023SJohn Marino 	  lhsc.type = SCALAR;
5708e4b17023SJohn Marino 	  lhsc.offset = 0;
5709e4b17023SJohn Marino 	  rhsc.var = vi->id;
5710e4b17023SJohn Marino 	  rhsc.type = ADDRESSOF;
5711e4b17023SJohn Marino 	  rhsc.offset = 0;
5712e4b17023SJohn Marino 	  process_constraint (new_constraint (lhsc, rhsc));
5713e4b17023SJohn Marino 	  for (; vi; vi = vi->next)
5714e4b17023SJohn Marino 	    if (vi->may_have_pointers)
5715e4b17023SJohn Marino 	      {
5716e4b17023SJohn Marino 		if (vi->only_restrict_pointers)
5717e4b17023SJohn Marino 		  make_constraint_from_global_restrict (vi, "GLOBAL_RESTRICT");
5718e4b17023SJohn Marino 		else
5719e4b17023SJohn Marino 		  make_copy_constraint (vi, nonlocal_id);
5720e4b17023SJohn Marino 	      }
5721e4b17023SJohn Marino 	  continue;
5722e4b17023SJohn Marino 	}
5723e4b17023SJohn Marino 
5724e4b17023SJohn Marino       if (POINTER_TYPE_P (TREE_TYPE (t))
5725e4b17023SJohn Marino 	  && TYPE_RESTRICT (TREE_TYPE (t)))
5726e4b17023SJohn Marino 	make_constraint_from_global_restrict (p, "PARM_RESTRICT");
5727e4b17023SJohn Marino       else
5728e4b17023SJohn Marino 	{
5729e4b17023SJohn Marino 	  for (; p; p = p->next)
5730e4b17023SJohn Marino 	    {
5731e4b17023SJohn Marino 	      if (p->only_restrict_pointers)
5732e4b17023SJohn Marino 		make_constraint_from_global_restrict (p, "PARM_RESTRICT");
5733e4b17023SJohn Marino 	      else if (p->may_have_pointers)
5734e4b17023SJohn Marino 		make_constraint_from (p, nonlocal_id);
5735e4b17023SJohn Marino 	    }
5736e4b17023SJohn Marino 	}
5737e4b17023SJohn Marino     }
5738e4b17023SJohn Marino 
5739e4b17023SJohn Marino   /* Add a constraint for a result decl that is passed by reference.  */
5740e4b17023SJohn Marino   if (DECL_RESULT (cfun->decl)
5741e4b17023SJohn Marino       && DECL_BY_REFERENCE (DECL_RESULT (cfun->decl)))
5742e4b17023SJohn Marino     {
5743e4b17023SJohn Marino       varinfo_t p, result_vi = get_vi_for_tree (DECL_RESULT (cfun->decl));
5744e4b17023SJohn Marino 
5745e4b17023SJohn Marino       for (p = result_vi; p; p = p->next)
5746e4b17023SJohn Marino 	make_constraint_from (p, nonlocal_id);
5747e4b17023SJohn Marino     }
5748e4b17023SJohn Marino 
5749e4b17023SJohn Marino   /* Add a constraint for the incoming static chain parameter.  */
5750e4b17023SJohn Marino   if (cfun->static_chain_decl != NULL_TREE)
5751e4b17023SJohn Marino     {
5752e4b17023SJohn Marino       varinfo_t p, chain_vi = get_vi_for_tree (cfun->static_chain_decl);
5753e4b17023SJohn Marino 
5754e4b17023SJohn Marino       for (p = chain_vi; p; p = p->next)
5755e4b17023SJohn Marino 	make_constraint_from (p, nonlocal_id);
5756e4b17023SJohn Marino     }
5757e4b17023SJohn Marino }
5758e4b17023SJohn Marino 
5759e4b17023SJohn Marino /* Structure used to put solution bitmaps in a hashtable so they can
5760e4b17023SJohn Marino    be shared among variables with the same points-to set.  */
5761e4b17023SJohn Marino 
5762e4b17023SJohn Marino typedef struct shared_bitmap_info
5763e4b17023SJohn Marino {
5764e4b17023SJohn Marino   bitmap pt_vars;
5765e4b17023SJohn Marino   hashval_t hashcode;
5766e4b17023SJohn Marino } *shared_bitmap_info_t;
5767e4b17023SJohn Marino typedef const struct shared_bitmap_info *const_shared_bitmap_info_t;
5768e4b17023SJohn Marino 
5769e4b17023SJohn Marino static htab_t shared_bitmap_table;
5770e4b17023SJohn Marino 
5771e4b17023SJohn Marino /* Hash function for a shared_bitmap_info_t */
5772e4b17023SJohn Marino 
5773e4b17023SJohn Marino static hashval_t
shared_bitmap_hash(const void * p)5774e4b17023SJohn Marino shared_bitmap_hash (const void *p)
5775e4b17023SJohn Marino {
5776e4b17023SJohn Marino   const_shared_bitmap_info_t const bi = (const_shared_bitmap_info_t) p;
5777e4b17023SJohn Marino   return bi->hashcode;
5778e4b17023SJohn Marino }
5779e4b17023SJohn Marino 
5780e4b17023SJohn Marino /* Equality function for two shared_bitmap_info_t's. */
5781e4b17023SJohn Marino 
5782e4b17023SJohn Marino static int
shared_bitmap_eq(const void * p1,const void * p2)5783e4b17023SJohn Marino shared_bitmap_eq (const void *p1, const void *p2)
5784e4b17023SJohn Marino {
5785e4b17023SJohn Marino   const_shared_bitmap_info_t const sbi1 = (const_shared_bitmap_info_t) p1;
5786e4b17023SJohn Marino   const_shared_bitmap_info_t const sbi2 = (const_shared_bitmap_info_t) p2;
5787e4b17023SJohn Marino   return bitmap_equal_p (sbi1->pt_vars, sbi2->pt_vars);
5788e4b17023SJohn Marino }
5789e4b17023SJohn Marino 
5790e4b17023SJohn Marino /* Lookup a bitmap in the shared bitmap hashtable, and return an already
5791e4b17023SJohn Marino    existing instance if there is one, NULL otherwise.  */
5792e4b17023SJohn Marino 
5793e4b17023SJohn Marino static bitmap
shared_bitmap_lookup(bitmap pt_vars)5794e4b17023SJohn Marino shared_bitmap_lookup (bitmap pt_vars)
5795e4b17023SJohn Marino {
5796e4b17023SJohn Marino   void **slot;
5797e4b17023SJohn Marino   struct shared_bitmap_info sbi;
5798e4b17023SJohn Marino 
5799e4b17023SJohn Marino   sbi.pt_vars = pt_vars;
5800e4b17023SJohn Marino   sbi.hashcode = bitmap_hash (pt_vars);
5801e4b17023SJohn Marino 
5802e4b17023SJohn Marino   slot = htab_find_slot_with_hash (shared_bitmap_table, &sbi,
5803e4b17023SJohn Marino 				   sbi.hashcode, NO_INSERT);
5804e4b17023SJohn Marino   if (!slot)
5805e4b17023SJohn Marino     return NULL;
5806e4b17023SJohn Marino   else
5807e4b17023SJohn Marino     return ((shared_bitmap_info_t) *slot)->pt_vars;
5808e4b17023SJohn Marino }
5809e4b17023SJohn Marino 
5810e4b17023SJohn Marino 
5811e4b17023SJohn Marino /* Add a bitmap to the shared bitmap hashtable.  */
5812e4b17023SJohn Marino 
5813e4b17023SJohn Marino static void
shared_bitmap_add(bitmap pt_vars)5814e4b17023SJohn Marino shared_bitmap_add (bitmap pt_vars)
5815e4b17023SJohn Marino {
5816e4b17023SJohn Marino   void **slot;
5817e4b17023SJohn Marino   shared_bitmap_info_t sbi = XNEW (struct shared_bitmap_info);
5818e4b17023SJohn Marino 
5819e4b17023SJohn Marino   sbi->pt_vars = pt_vars;
5820e4b17023SJohn Marino   sbi->hashcode = bitmap_hash (pt_vars);
5821e4b17023SJohn Marino 
5822e4b17023SJohn Marino   slot = htab_find_slot_with_hash (shared_bitmap_table, sbi,
5823e4b17023SJohn Marino 				   sbi->hashcode, INSERT);
5824e4b17023SJohn Marino   gcc_assert (!*slot);
5825e4b17023SJohn Marino   *slot = (void *) sbi;
5826e4b17023SJohn Marino }
5827e4b17023SJohn Marino 
5828e4b17023SJohn Marino 
5829e4b17023SJohn Marino /* Set bits in INTO corresponding to the variable uids in solution set FROM.  */
5830e4b17023SJohn Marino 
5831e4b17023SJohn Marino static void
set_uids_in_ptset(bitmap into,bitmap from,struct pt_solution * pt)5832e4b17023SJohn Marino set_uids_in_ptset (bitmap into, bitmap from, struct pt_solution *pt)
5833e4b17023SJohn Marino {
5834e4b17023SJohn Marino   unsigned int i;
5835e4b17023SJohn Marino   bitmap_iterator bi;
5836e4b17023SJohn Marino 
5837e4b17023SJohn Marino   EXECUTE_IF_SET_IN_BITMAP (from, 0, i, bi)
5838e4b17023SJohn Marino     {
5839e4b17023SJohn Marino       varinfo_t vi = get_varinfo (i);
5840e4b17023SJohn Marino 
5841e4b17023SJohn Marino       /* The only artificial variables that are allowed in a may-alias
5842e4b17023SJohn Marino 	 set are heap variables.  */
5843e4b17023SJohn Marino       if (vi->is_artificial_var && !vi->is_heap_var)
5844e4b17023SJohn Marino 	continue;
5845e4b17023SJohn Marino 
5846e4b17023SJohn Marino       if (TREE_CODE (vi->decl) == VAR_DECL
5847e4b17023SJohn Marino 	  || TREE_CODE (vi->decl) == PARM_DECL
5848e4b17023SJohn Marino 	  || TREE_CODE (vi->decl) == RESULT_DECL)
5849e4b17023SJohn Marino 	{
5850e4b17023SJohn Marino 	  /* If we are in IPA mode we will not recompute points-to
5851e4b17023SJohn Marino 	     sets after inlining so make sure they stay valid.  */
5852e4b17023SJohn Marino 	  if (in_ipa_mode
5853e4b17023SJohn Marino 	      && !DECL_PT_UID_SET_P (vi->decl))
5854e4b17023SJohn Marino 	    SET_DECL_PT_UID (vi->decl, DECL_UID (vi->decl));
5855e4b17023SJohn Marino 
5856e4b17023SJohn Marino 	  /* Add the decl to the points-to set.  Note that the points-to
5857e4b17023SJohn Marino 	     set contains global variables.  */
5858e4b17023SJohn Marino 	  bitmap_set_bit (into, DECL_PT_UID (vi->decl));
5859e4b17023SJohn Marino 	  if (vi->is_global_var)
5860e4b17023SJohn Marino 	    pt->vars_contains_global = true;
5861e4b17023SJohn Marino 	}
5862e4b17023SJohn Marino     }
5863e4b17023SJohn Marino }
5864e4b17023SJohn Marino 
5865e4b17023SJohn Marino 
5866e4b17023SJohn Marino /* Compute the points-to solution *PT for the variable VI.  */
5867e4b17023SJohn Marino 
5868e4b17023SJohn Marino static void
find_what_var_points_to(varinfo_t orig_vi,struct pt_solution * pt)5869e4b17023SJohn Marino find_what_var_points_to (varinfo_t orig_vi, struct pt_solution *pt)
5870e4b17023SJohn Marino {
5871e4b17023SJohn Marino   unsigned int i;
5872e4b17023SJohn Marino   bitmap_iterator bi;
5873e4b17023SJohn Marino   bitmap finished_solution;
5874e4b17023SJohn Marino   bitmap result;
5875e4b17023SJohn Marino   varinfo_t vi;
5876e4b17023SJohn Marino 
5877e4b17023SJohn Marino   memset (pt, 0, sizeof (struct pt_solution));
5878e4b17023SJohn Marino 
5879e4b17023SJohn Marino   /* This variable may have been collapsed, let's get the real
5880e4b17023SJohn Marino      variable.  */
5881e4b17023SJohn Marino   vi = get_varinfo (find (orig_vi->id));
5882e4b17023SJohn Marino 
5883e4b17023SJohn Marino   /* Translate artificial variables into SSA_NAME_PTR_INFO
5884e4b17023SJohn Marino      attributes.  */
5885e4b17023SJohn Marino   EXECUTE_IF_SET_IN_BITMAP (vi->solution, 0, i, bi)
5886e4b17023SJohn Marino     {
5887e4b17023SJohn Marino       varinfo_t vi = get_varinfo (i);
5888e4b17023SJohn Marino 
5889e4b17023SJohn Marino       if (vi->is_artificial_var)
5890e4b17023SJohn Marino 	{
5891e4b17023SJohn Marino 	  if (vi->id == nothing_id)
5892e4b17023SJohn Marino 	    pt->null = 1;
5893e4b17023SJohn Marino 	  else if (vi->id == escaped_id)
5894e4b17023SJohn Marino 	    {
5895e4b17023SJohn Marino 	      if (in_ipa_mode)
5896e4b17023SJohn Marino 		pt->ipa_escaped = 1;
5897e4b17023SJohn Marino 	      else
5898e4b17023SJohn Marino 		pt->escaped = 1;
5899e4b17023SJohn Marino 	    }
5900e4b17023SJohn Marino 	  else if (vi->id == nonlocal_id)
5901e4b17023SJohn Marino 	    pt->nonlocal = 1;
5902e4b17023SJohn Marino 	  else if (vi->is_heap_var)
5903e4b17023SJohn Marino 	    /* We represent heapvars in the points-to set properly.  */
5904e4b17023SJohn Marino 	    ;
5905e4b17023SJohn Marino 	  else if (vi->id == readonly_id)
5906e4b17023SJohn Marino 	    /* Nobody cares.  */
5907e4b17023SJohn Marino 	    ;
5908e4b17023SJohn Marino 	  else if (vi->id == anything_id
5909e4b17023SJohn Marino 		   || vi->id == integer_id)
5910e4b17023SJohn Marino 	    pt->anything = 1;
5911e4b17023SJohn Marino 	}
5912e4b17023SJohn Marino     }
5913e4b17023SJohn Marino 
5914e4b17023SJohn Marino   /* Instead of doing extra work, simply do not create
5915e4b17023SJohn Marino      elaborate points-to information for pt_anything pointers.  */
5916e4b17023SJohn Marino   if (pt->anything)
5917e4b17023SJohn Marino     return;
5918e4b17023SJohn Marino 
5919e4b17023SJohn Marino   /* Share the final set of variables when possible.  */
5920e4b17023SJohn Marino   finished_solution = BITMAP_GGC_ALLOC ();
5921e4b17023SJohn Marino   stats.points_to_sets_created++;
5922e4b17023SJohn Marino 
5923e4b17023SJohn Marino   set_uids_in_ptset (finished_solution, vi->solution, pt);
5924e4b17023SJohn Marino   result = shared_bitmap_lookup (finished_solution);
5925e4b17023SJohn Marino   if (!result)
5926e4b17023SJohn Marino     {
5927e4b17023SJohn Marino       shared_bitmap_add (finished_solution);
5928e4b17023SJohn Marino       pt->vars = finished_solution;
5929e4b17023SJohn Marino     }
5930e4b17023SJohn Marino   else
5931e4b17023SJohn Marino     {
5932e4b17023SJohn Marino       pt->vars = result;
5933e4b17023SJohn Marino       bitmap_clear (finished_solution);
5934e4b17023SJohn Marino     }
5935e4b17023SJohn Marino }
5936e4b17023SJohn Marino 
5937e4b17023SJohn Marino /* Given a pointer variable P, fill in its points-to set.  */
5938e4b17023SJohn Marino 
5939e4b17023SJohn Marino static void
find_what_p_points_to(tree p)5940e4b17023SJohn Marino find_what_p_points_to (tree p)
5941e4b17023SJohn Marino {
5942e4b17023SJohn Marino   struct ptr_info_def *pi;
5943e4b17023SJohn Marino   tree lookup_p = p;
5944e4b17023SJohn Marino   varinfo_t vi;
5945e4b17023SJohn Marino 
5946e4b17023SJohn Marino   /* For parameters, get at the points-to set for the actual parm
5947e4b17023SJohn Marino      decl.  */
5948e4b17023SJohn Marino   if (TREE_CODE (p) == SSA_NAME
5949e4b17023SJohn Marino       && (TREE_CODE (SSA_NAME_VAR (p)) == PARM_DECL
5950e4b17023SJohn Marino 	  || TREE_CODE (SSA_NAME_VAR (p)) == RESULT_DECL)
5951e4b17023SJohn Marino       && SSA_NAME_IS_DEFAULT_DEF (p))
5952e4b17023SJohn Marino     lookup_p = SSA_NAME_VAR (p);
5953e4b17023SJohn Marino 
5954e4b17023SJohn Marino   vi = lookup_vi_for_tree (lookup_p);
5955e4b17023SJohn Marino   if (!vi)
5956e4b17023SJohn Marino     return;
5957e4b17023SJohn Marino 
5958e4b17023SJohn Marino   pi = get_ptr_info (p);
5959e4b17023SJohn Marino   find_what_var_points_to (vi, &pi->pt);
5960e4b17023SJohn Marino }
5961e4b17023SJohn Marino 
5962e4b17023SJohn Marino 
5963e4b17023SJohn Marino /* Query statistics for points-to solutions.  */
5964e4b17023SJohn Marino 
5965e4b17023SJohn Marino static struct {
5966e4b17023SJohn Marino   unsigned HOST_WIDE_INT pt_solution_includes_may_alias;
5967e4b17023SJohn Marino   unsigned HOST_WIDE_INT pt_solution_includes_no_alias;
5968e4b17023SJohn Marino   unsigned HOST_WIDE_INT pt_solutions_intersect_may_alias;
5969e4b17023SJohn Marino   unsigned HOST_WIDE_INT pt_solutions_intersect_no_alias;
5970e4b17023SJohn Marino } pta_stats;
5971e4b17023SJohn Marino 
5972e4b17023SJohn Marino void
dump_pta_stats(FILE * s)5973e4b17023SJohn Marino dump_pta_stats (FILE *s)
5974e4b17023SJohn Marino {
5975e4b17023SJohn Marino   fprintf (s, "\nPTA query stats:\n");
5976e4b17023SJohn Marino   fprintf (s, "  pt_solution_includes: "
5977e4b17023SJohn Marino 	   HOST_WIDE_INT_PRINT_DEC" disambiguations, "
5978e4b17023SJohn Marino 	   HOST_WIDE_INT_PRINT_DEC" queries\n",
5979e4b17023SJohn Marino 	   pta_stats.pt_solution_includes_no_alias,
5980e4b17023SJohn Marino 	   pta_stats.pt_solution_includes_no_alias
5981e4b17023SJohn Marino 	   + pta_stats.pt_solution_includes_may_alias);
5982e4b17023SJohn Marino   fprintf (s, "  pt_solutions_intersect: "
5983e4b17023SJohn Marino 	   HOST_WIDE_INT_PRINT_DEC" disambiguations, "
5984e4b17023SJohn Marino 	   HOST_WIDE_INT_PRINT_DEC" queries\n",
5985e4b17023SJohn Marino 	   pta_stats.pt_solutions_intersect_no_alias,
5986e4b17023SJohn Marino 	   pta_stats.pt_solutions_intersect_no_alias
5987e4b17023SJohn Marino 	   + pta_stats.pt_solutions_intersect_may_alias);
5988e4b17023SJohn Marino }
5989e4b17023SJohn Marino 
5990e4b17023SJohn Marino 
5991e4b17023SJohn Marino /* Reset the points-to solution *PT to a conservative default
5992e4b17023SJohn Marino    (point to anything).  */
5993e4b17023SJohn Marino 
5994e4b17023SJohn Marino void
pt_solution_reset(struct pt_solution * pt)5995e4b17023SJohn Marino pt_solution_reset (struct pt_solution *pt)
5996e4b17023SJohn Marino {
5997e4b17023SJohn Marino   memset (pt, 0, sizeof (struct pt_solution));
5998e4b17023SJohn Marino   pt->anything = true;
5999e4b17023SJohn Marino }
6000e4b17023SJohn Marino 
6001e4b17023SJohn Marino /* Set the points-to solution *PT to point only to the variables
6002e4b17023SJohn Marino    in VARS.  VARS_CONTAINS_GLOBAL specifies whether that contains
6003e4b17023SJohn Marino    global variables and VARS_CONTAINS_RESTRICT specifies whether
6004e4b17023SJohn Marino    it contains restrict tag variables.  */
6005e4b17023SJohn Marino 
6006e4b17023SJohn Marino void
pt_solution_set(struct pt_solution * pt,bitmap vars,bool vars_contains_global)6007e4b17023SJohn Marino pt_solution_set (struct pt_solution *pt, bitmap vars, bool vars_contains_global)
6008e4b17023SJohn Marino {
6009e4b17023SJohn Marino   memset (pt, 0, sizeof (struct pt_solution));
6010e4b17023SJohn Marino   pt->vars = vars;
6011e4b17023SJohn Marino   pt->vars_contains_global = vars_contains_global;
6012e4b17023SJohn Marino }
6013e4b17023SJohn Marino 
6014e4b17023SJohn Marino /* Set the points-to solution *PT to point only to the variable VAR.  */
6015e4b17023SJohn Marino 
6016e4b17023SJohn Marino void
pt_solution_set_var(struct pt_solution * pt,tree var)6017e4b17023SJohn Marino pt_solution_set_var (struct pt_solution *pt, tree var)
6018e4b17023SJohn Marino {
6019e4b17023SJohn Marino   memset (pt, 0, sizeof (struct pt_solution));
6020e4b17023SJohn Marino   pt->vars = BITMAP_GGC_ALLOC ();
6021e4b17023SJohn Marino   bitmap_set_bit (pt->vars, DECL_PT_UID (var));
6022e4b17023SJohn Marino   pt->vars_contains_global = is_global_var (var);
6023e4b17023SJohn Marino }
6024e4b17023SJohn Marino 
6025e4b17023SJohn Marino /* Computes the union of the points-to solutions *DEST and *SRC and
6026e4b17023SJohn Marino    stores the result in *DEST.  This changes the points-to bitmap
6027e4b17023SJohn Marino    of *DEST and thus may not be used if that might be shared.
6028e4b17023SJohn Marino    The points-to bitmap of *SRC and *DEST will not be shared after
6029e4b17023SJohn Marino    this function if they were not before.  */
6030e4b17023SJohn Marino 
6031e4b17023SJohn Marino static void
pt_solution_ior_into(struct pt_solution * dest,struct pt_solution * src)6032e4b17023SJohn Marino pt_solution_ior_into (struct pt_solution *dest, struct pt_solution *src)
6033e4b17023SJohn Marino {
6034e4b17023SJohn Marino   dest->anything |= src->anything;
6035e4b17023SJohn Marino   if (dest->anything)
6036e4b17023SJohn Marino     {
6037e4b17023SJohn Marino       pt_solution_reset (dest);
6038e4b17023SJohn Marino       return;
6039e4b17023SJohn Marino     }
6040e4b17023SJohn Marino 
6041e4b17023SJohn Marino   dest->nonlocal |= src->nonlocal;
6042e4b17023SJohn Marino   dest->escaped |= src->escaped;
6043e4b17023SJohn Marino   dest->ipa_escaped |= src->ipa_escaped;
6044e4b17023SJohn Marino   dest->null |= src->null;
6045e4b17023SJohn Marino   dest->vars_contains_global |= src->vars_contains_global;
6046e4b17023SJohn Marino   if (!src->vars)
6047e4b17023SJohn Marino     return;
6048e4b17023SJohn Marino 
6049e4b17023SJohn Marino   if (!dest->vars)
6050e4b17023SJohn Marino     dest->vars = BITMAP_GGC_ALLOC ();
6051e4b17023SJohn Marino   bitmap_ior_into (dest->vars, src->vars);
6052e4b17023SJohn Marino }
6053e4b17023SJohn Marino 
6054e4b17023SJohn Marino /* Return true if the points-to solution *PT is empty.  */
6055e4b17023SJohn Marino 
6056e4b17023SJohn Marino bool
pt_solution_empty_p(struct pt_solution * pt)6057e4b17023SJohn Marino pt_solution_empty_p (struct pt_solution *pt)
6058e4b17023SJohn Marino {
6059e4b17023SJohn Marino   if (pt->anything
6060e4b17023SJohn Marino       || pt->nonlocal)
6061e4b17023SJohn Marino     return false;
6062e4b17023SJohn Marino 
6063e4b17023SJohn Marino   if (pt->vars
6064e4b17023SJohn Marino       && !bitmap_empty_p (pt->vars))
6065e4b17023SJohn Marino     return false;
6066e4b17023SJohn Marino 
6067e4b17023SJohn Marino   /* If the solution includes ESCAPED, check if that is empty.  */
6068e4b17023SJohn Marino   if (pt->escaped
6069e4b17023SJohn Marino       && !pt_solution_empty_p (&cfun->gimple_df->escaped))
6070e4b17023SJohn Marino     return false;
6071e4b17023SJohn Marino 
6072e4b17023SJohn Marino   /* If the solution includes ESCAPED, check if that is empty.  */
6073e4b17023SJohn Marino   if (pt->ipa_escaped
6074e4b17023SJohn Marino       && !pt_solution_empty_p (&ipa_escaped_pt))
6075e4b17023SJohn Marino     return false;
6076e4b17023SJohn Marino 
6077e4b17023SJohn Marino   return true;
6078e4b17023SJohn Marino }
6079e4b17023SJohn Marino 
6080e4b17023SJohn Marino /* Return true if the points-to solution *PT only point to a single var, and
6081e4b17023SJohn Marino    return the var uid in *UID.  */
6082e4b17023SJohn Marino 
6083e4b17023SJohn Marino bool
pt_solution_singleton_p(struct pt_solution * pt,unsigned * uid)6084e4b17023SJohn Marino pt_solution_singleton_p (struct pt_solution *pt, unsigned *uid)
6085e4b17023SJohn Marino {
6086e4b17023SJohn Marino   if (pt->anything || pt->nonlocal || pt->escaped || pt->ipa_escaped
6087e4b17023SJohn Marino       || pt->null || pt->vars == NULL
6088e4b17023SJohn Marino       || !bitmap_single_bit_set_p (pt->vars))
6089e4b17023SJohn Marino     return false;
6090e4b17023SJohn Marino 
6091e4b17023SJohn Marino   *uid = bitmap_first_set_bit (pt->vars);
6092e4b17023SJohn Marino   return true;
6093e4b17023SJohn Marino }
6094e4b17023SJohn Marino 
6095e4b17023SJohn Marino /* Return true if the points-to solution *PT includes global memory.  */
6096e4b17023SJohn Marino 
6097e4b17023SJohn Marino bool
pt_solution_includes_global(struct pt_solution * pt)6098e4b17023SJohn Marino pt_solution_includes_global (struct pt_solution *pt)
6099e4b17023SJohn Marino {
6100e4b17023SJohn Marino   if (pt->anything
6101e4b17023SJohn Marino       || pt->nonlocal
6102e4b17023SJohn Marino       || pt->vars_contains_global)
6103e4b17023SJohn Marino     return true;
6104e4b17023SJohn Marino 
6105e4b17023SJohn Marino   if (pt->escaped)
6106e4b17023SJohn Marino     return pt_solution_includes_global (&cfun->gimple_df->escaped);
6107e4b17023SJohn Marino 
6108e4b17023SJohn Marino   if (pt->ipa_escaped)
6109e4b17023SJohn Marino     return pt_solution_includes_global (&ipa_escaped_pt);
6110e4b17023SJohn Marino 
6111e4b17023SJohn Marino   /* ???  This predicate is not correct for the IPA-PTA solution
6112e4b17023SJohn Marino      as we do not properly distinguish between unit escape points
6113e4b17023SJohn Marino      and global variables.  */
6114e4b17023SJohn Marino   if (cfun->gimple_df->ipa_pta)
6115e4b17023SJohn Marino     return true;
6116e4b17023SJohn Marino 
6117e4b17023SJohn Marino   return false;
6118e4b17023SJohn Marino }
6119e4b17023SJohn Marino 
6120e4b17023SJohn Marino /* Return true if the points-to solution *PT includes the variable
6121e4b17023SJohn Marino    declaration DECL.  */
6122e4b17023SJohn Marino 
6123e4b17023SJohn Marino static bool
pt_solution_includes_1(struct pt_solution * pt,const_tree decl)6124e4b17023SJohn Marino pt_solution_includes_1 (struct pt_solution *pt, const_tree decl)
6125e4b17023SJohn Marino {
6126e4b17023SJohn Marino   if (pt->anything)
6127e4b17023SJohn Marino     return true;
6128e4b17023SJohn Marino 
6129e4b17023SJohn Marino   if (pt->nonlocal
6130e4b17023SJohn Marino       && is_global_var (decl))
6131e4b17023SJohn Marino     return true;
6132e4b17023SJohn Marino 
6133e4b17023SJohn Marino   if (pt->vars
6134e4b17023SJohn Marino       && bitmap_bit_p (pt->vars, DECL_PT_UID (decl)))
6135e4b17023SJohn Marino     return true;
6136e4b17023SJohn Marino 
6137e4b17023SJohn Marino   /* If the solution includes ESCAPED, check it.  */
6138e4b17023SJohn Marino   if (pt->escaped
6139e4b17023SJohn Marino       && pt_solution_includes_1 (&cfun->gimple_df->escaped, decl))
6140e4b17023SJohn Marino     return true;
6141e4b17023SJohn Marino 
6142e4b17023SJohn Marino   /* If the solution includes ESCAPED, check it.  */
6143e4b17023SJohn Marino   if (pt->ipa_escaped
6144e4b17023SJohn Marino       && pt_solution_includes_1 (&ipa_escaped_pt, decl))
6145e4b17023SJohn Marino     return true;
6146e4b17023SJohn Marino 
6147e4b17023SJohn Marino   return false;
6148e4b17023SJohn Marino }
6149e4b17023SJohn Marino 
6150e4b17023SJohn Marino bool
pt_solution_includes(struct pt_solution * pt,const_tree decl)6151e4b17023SJohn Marino pt_solution_includes (struct pt_solution *pt, const_tree decl)
6152e4b17023SJohn Marino {
6153e4b17023SJohn Marino   bool res = pt_solution_includes_1 (pt, decl);
6154e4b17023SJohn Marino   if (res)
6155e4b17023SJohn Marino     ++pta_stats.pt_solution_includes_may_alias;
6156e4b17023SJohn Marino   else
6157e4b17023SJohn Marino     ++pta_stats.pt_solution_includes_no_alias;
6158e4b17023SJohn Marino   return res;
6159e4b17023SJohn Marino }
6160e4b17023SJohn Marino 
6161e4b17023SJohn Marino /* Return true if both points-to solutions PT1 and PT2 have a non-empty
6162e4b17023SJohn Marino    intersection.  */
6163e4b17023SJohn Marino 
6164e4b17023SJohn Marino static bool
pt_solutions_intersect_1(struct pt_solution * pt1,struct pt_solution * pt2)6165e4b17023SJohn Marino pt_solutions_intersect_1 (struct pt_solution *pt1, struct pt_solution *pt2)
6166e4b17023SJohn Marino {
6167e4b17023SJohn Marino   if (pt1->anything || pt2->anything)
6168e4b17023SJohn Marino     return true;
6169e4b17023SJohn Marino 
6170e4b17023SJohn Marino   /* If either points to unknown global memory and the other points to
6171e4b17023SJohn Marino      any global memory they alias.  */
6172e4b17023SJohn Marino   if ((pt1->nonlocal
6173e4b17023SJohn Marino        && (pt2->nonlocal
6174e4b17023SJohn Marino 	   || pt2->vars_contains_global))
6175e4b17023SJohn Marino       || (pt2->nonlocal
6176e4b17023SJohn Marino 	  && pt1->vars_contains_global))
6177e4b17023SJohn Marino     return true;
6178e4b17023SJohn Marino 
6179e4b17023SJohn Marino   /* Check the escaped solution if required.  */
6180e4b17023SJohn Marino   if ((pt1->escaped || pt2->escaped)
6181e4b17023SJohn Marino       && !pt_solution_empty_p (&cfun->gimple_df->escaped))
6182e4b17023SJohn Marino     {
6183e4b17023SJohn Marino       /* If both point to escaped memory and that solution
6184e4b17023SJohn Marino 	 is not empty they alias.  */
6185e4b17023SJohn Marino       if (pt1->escaped && pt2->escaped)
6186e4b17023SJohn Marino 	return true;
6187e4b17023SJohn Marino 
6188e4b17023SJohn Marino       /* If either points to escaped memory see if the escaped solution
6189e4b17023SJohn Marino 	 intersects with the other.  */
6190e4b17023SJohn Marino       if ((pt1->escaped
6191e4b17023SJohn Marino 	   && pt_solutions_intersect_1 (&cfun->gimple_df->escaped, pt2))
6192e4b17023SJohn Marino 	  || (pt2->escaped
6193e4b17023SJohn Marino 	      && pt_solutions_intersect_1 (&cfun->gimple_df->escaped, pt1)))
6194e4b17023SJohn Marino 	return true;
6195e4b17023SJohn Marino     }
6196e4b17023SJohn Marino 
6197e4b17023SJohn Marino   /* Check the escaped solution if required.
6198e4b17023SJohn Marino      ???  Do we need to check the local against the IPA escaped sets?  */
6199e4b17023SJohn Marino   if ((pt1->ipa_escaped || pt2->ipa_escaped)
6200e4b17023SJohn Marino       && !pt_solution_empty_p (&ipa_escaped_pt))
6201e4b17023SJohn Marino     {
6202e4b17023SJohn Marino       /* If both point to escaped memory and that solution
6203e4b17023SJohn Marino 	 is not empty they alias.  */
6204e4b17023SJohn Marino       if (pt1->ipa_escaped && pt2->ipa_escaped)
6205e4b17023SJohn Marino 	return true;
6206e4b17023SJohn Marino 
6207e4b17023SJohn Marino       /* If either points to escaped memory see if the escaped solution
6208e4b17023SJohn Marino 	 intersects with the other.  */
6209e4b17023SJohn Marino       if ((pt1->ipa_escaped
6210e4b17023SJohn Marino 	   && pt_solutions_intersect_1 (&ipa_escaped_pt, pt2))
6211e4b17023SJohn Marino 	  || (pt2->ipa_escaped
6212e4b17023SJohn Marino 	      && pt_solutions_intersect_1 (&ipa_escaped_pt, pt1)))
6213e4b17023SJohn Marino 	return true;
6214e4b17023SJohn Marino     }
6215e4b17023SJohn Marino 
6216e4b17023SJohn Marino   /* Now both pointers alias if their points-to solution intersects.  */
6217e4b17023SJohn Marino   return (pt1->vars
6218e4b17023SJohn Marino 	  && pt2->vars
6219e4b17023SJohn Marino 	  && bitmap_intersect_p (pt1->vars, pt2->vars));
6220e4b17023SJohn Marino }
6221e4b17023SJohn Marino 
6222e4b17023SJohn Marino bool
pt_solutions_intersect(struct pt_solution * pt1,struct pt_solution * pt2)6223e4b17023SJohn Marino pt_solutions_intersect (struct pt_solution *pt1, struct pt_solution *pt2)
6224e4b17023SJohn Marino {
6225e4b17023SJohn Marino   bool res = pt_solutions_intersect_1 (pt1, pt2);
6226e4b17023SJohn Marino   if (res)
6227e4b17023SJohn Marino     ++pta_stats.pt_solutions_intersect_may_alias;
6228e4b17023SJohn Marino   else
6229e4b17023SJohn Marino     ++pta_stats.pt_solutions_intersect_no_alias;
6230e4b17023SJohn Marino   return res;
6231e4b17023SJohn Marino }
6232e4b17023SJohn Marino 
6233e4b17023SJohn Marino 
6234e4b17023SJohn Marino /* Dump points-to information to OUTFILE.  */
6235e4b17023SJohn Marino 
6236e4b17023SJohn Marino static void
dump_sa_points_to_info(FILE * outfile)6237e4b17023SJohn Marino dump_sa_points_to_info (FILE *outfile)
6238e4b17023SJohn Marino {
6239e4b17023SJohn Marino   unsigned int i;
6240e4b17023SJohn Marino 
6241e4b17023SJohn Marino   fprintf (outfile, "\nPoints-to sets\n\n");
6242e4b17023SJohn Marino 
6243e4b17023SJohn Marino   if (dump_flags & TDF_STATS)
6244e4b17023SJohn Marino     {
6245e4b17023SJohn Marino       fprintf (outfile, "Stats:\n");
6246e4b17023SJohn Marino       fprintf (outfile, "Total vars:               %d\n", stats.total_vars);
6247e4b17023SJohn Marino       fprintf (outfile, "Non-pointer vars:          %d\n",
6248e4b17023SJohn Marino 	       stats.nonpointer_vars);
6249e4b17023SJohn Marino       fprintf (outfile, "Statically unified vars:  %d\n",
6250e4b17023SJohn Marino 	       stats.unified_vars_static);
6251e4b17023SJohn Marino       fprintf (outfile, "Dynamically unified vars: %d\n",
6252e4b17023SJohn Marino 	       stats.unified_vars_dynamic);
6253e4b17023SJohn Marino       fprintf (outfile, "Iterations:               %d\n", stats.iterations);
6254e4b17023SJohn Marino       fprintf (outfile, "Number of edges:          %d\n", stats.num_edges);
6255e4b17023SJohn Marino       fprintf (outfile, "Number of implicit edges: %d\n",
6256e4b17023SJohn Marino 	       stats.num_implicit_edges);
6257e4b17023SJohn Marino     }
6258e4b17023SJohn Marino 
6259e4b17023SJohn Marino   for (i = 0; i < VEC_length (varinfo_t, varmap); i++)
6260e4b17023SJohn Marino     {
6261e4b17023SJohn Marino       varinfo_t vi = get_varinfo (i);
6262e4b17023SJohn Marino       if (!vi->may_have_pointers)
6263e4b17023SJohn Marino 	continue;
6264e4b17023SJohn Marino       dump_solution_for_var (outfile, i);
6265e4b17023SJohn Marino     }
6266e4b17023SJohn Marino }
6267e4b17023SJohn Marino 
6268e4b17023SJohn Marino 
6269e4b17023SJohn Marino /* Debug points-to information to stderr.  */
6270e4b17023SJohn Marino 
6271e4b17023SJohn Marino DEBUG_FUNCTION void
debug_sa_points_to_info(void)6272e4b17023SJohn Marino debug_sa_points_to_info (void)
6273e4b17023SJohn Marino {
6274e4b17023SJohn Marino   dump_sa_points_to_info (stderr);
6275e4b17023SJohn Marino }
6276e4b17023SJohn Marino 
6277e4b17023SJohn Marino 
6278e4b17023SJohn Marino /* Initialize the always-existing constraint variables for NULL
6279e4b17023SJohn Marino    ANYTHING, READONLY, and INTEGER */
6280e4b17023SJohn Marino 
6281e4b17023SJohn Marino static void
init_base_vars(void)6282e4b17023SJohn Marino init_base_vars (void)
6283e4b17023SJohn Marino {
6284e4b17023SJohn Marino   struct constraint_expr lhs, rhs;
6285e4b17023SJohn Marino   varinfo_t var_anything;
6286e4b17023SJohn Marino   varinfo_t var_nothing;
6287e4b17023SJohn Marino   varinfo_t var_readonly;
6288e4b17023SJohn Marino   varinfo_t var_escaped;
6289e4b17023SJohn Marino   varinfo_t var_nonlocal;
6290e4b17023SJohn Marino   varinfo_t var_storedanything;
6291e4b17023SJohn Marino   varinfo_t var_integer;
6292e4b17023SJohn Marino 
6293e4b17023SJohn Marino   /* Create the NULL variable, used to represent that a variable points
6294e4b17023SJohn Marino      to NULL.  */
6295e4b17023SJohn Marino   var_nothing = new_var_info (NULL_TREE, "NULL");
6296e4b17023SJohn Marino   gcc_assert (var_nothing->id == nothing_id);
6297e4b17023SJohn Marino   var_nothing->is_artificial_var = 1;
6298e4b17023SJohn Marino   var_nothing->offset = 0;
6299e4b17023SJohn Marino   var_nothing->size = ~0;
6300e4b17023SJohn Marino   var_nothing->fullsize = ~0;
6301e4b17023SJohn Marino   var_nothing->is_special_var = 1;
6302e4b17023SJohn Marino   var_nothing->may_have_pointers = 0;
6303e4b17023SJohn Marino   var_nothing->is_global_var = 0;
6304e4b17023SJohn Marino 
6305e4b17023SJohn Marino   /* Create the ANYTHING variable, used to represent that a variable
6306e4b17023SJohn Marino      points to some unknown piece of memory.  */
6307e4b17023SJohn Marino   var_anything = new_var_info (NULL_TREE, "ANYTHING");
6308e4b17023SJohn Marino   gcc_assert (var_anything->id == anything_id);
6309e4b17023SJohn Marino   var_anything->is_artificial_var = 1;
6310e4b17023SJohn Marino   var_anything->size = ~0;
6311e4b17023SJohn Marino   var_anything->offset = 0;
6312e4b17023SJohn Marino   var_anything->next = NULL;
6313e4b17023SJohn Marino   var_anything->fullsize = ~0;
6314e4b17023SJohn Marino   var_anything->is_special_var = 1;
6315e4b17023SJohn Marino 
6316e4b17023SJohn Marino   /* Anything points to anything.  This makes deref constraints just
6317e4b17023SJohn Marino      work in the presence of linked list and other p = *p type loops,
6318e4b17023SJohn Marino      by saying that *ANYTHING = ANYTHING. */
6319e4b17023SJohn Marino   lhs.type = SCALAR;
6320e4b17023SJohn Marino   lhs.var = anything_id;
6321e4b17023SJohn Marino   lhs.offset = 0;
6322e4b17023SJohn Marino   rhs.type = ADDRESSOF;
6323e4b17023SJohn Marino   rhs.var = anything_id;
6324e4b17023SJohn Marino   rhs.offset = 0;
6325e4b17023SJohn Marino 
6326e4b17023SJohn Marino   /* This specifically does not use process_constraint because
6327e4b17023SJohn Marino      process_constraint ignores all anything = anything constraints, since all
6328e4b17023SJohn Marino      but this one are redundant.  */
6329e4b17023SJohn Marino   VEC_safe_push (constraint_t, heap, constraints, new_constraint (lhs, rhs));
6330e4b17023SJohn Marino 
6331e4b17023SJohn Marino   /* Create the READONLY variable, used to represent that a variable
6332e4b17023SJohn Marino      points to readonly memory.  */
6333e4b17023SJohn Marino   var_readonly = new_var_info (NULL_TREE, "READONLY");
6334e4b17023SJohn Marino   gcc_assert (var_readonly->id == readonly_id);
6335e4b17023SJohn Marino   var_readonly->is_artificial_var = 1;
6336e4b17023SJohn Marino   var_readonly->offset = 0;
6337e4b17023SJohn Marino   var_readonly->size = ~0;
6338e4b17023SJohn Marino   var_readonly->fullsize = ~0;
6339e4b17023SJohn Marino   var_readonly->next = NULL;
6340e4b17023SJohn Marino   var_readonly->is_special_var = 1;
6341e4b17023SJohn Marino 
6342e4b17023SJohn Marino   /* readonly memory points to anything, in order to make deref
6343e4b17023SJohn Marino      easier.  In reality, it points to anything the particular
6344e4b17023SJohn Marino      readonly variable can point to, but we don't track this
6345e4b17023SJohn Marino      separately. */
6346e4b17023SJohn Marino   lhs.type = SCALAR;
6347e4b17023SJohn Marino   lhs.var = readonly_id;
6348e4b17023SJohn Marino   lhs.offset = 0;
6349e4b17023SJohn Marino   rhs.type = ADDRESSOF;
6350e4b17023SJohn Marino   rhs.var = readonly_id;  /* FIXME */
6351e4b17023SJohn Marino   rhs.offset = 0;
6352e4b17023SJohn Marino   process_constraint (new_constraint (lhs, rhs));
6353e4b17023SJohn Marino 
6354e4b17023SJohn Marino   /* Create the ESCAPED variable, used to represent the set of escaped
6355e4b17023SJohn Marino      memory.  */
6356e4b17023SJohn Marino   var_escaped = new_var_info (NULL_TREE, "ESCAPED");
6357e4b17023SJohn Marino   gcc_assert (var_escaped->id == escaped_id);
6358e4b17023SJohn Marino   var_escaped->is_artificial_var = 1;
6359e4b17023SJohn Marino   var_escaped->offset = 0;
6360e4b17023SJohn Marino   var_escaped->size = ~0;
6361e4b17023SJohn Marino   var_escaped->fullsize = ~0;
6362e4b17023SJohn Marino   var_escaped->is_special_var = 0;
6363e4b17023SJohn Marino 
6364e4b17023SJohn Marino   /* Create the NONLOCAL variable, used to represent the set of nonlocal
6365e4b17023SJohn Marino      memory.  */
6366e4b17023SJohn Marino   var_nonlocal = new_var_info (NULL_TREE, "NONLOCAL");
6367e4b17023SJohn Marino   gcc_assert (var_nonlocal->id == nonlocal_id);
6368e4b17023SJohn Marino   var_nonlocal->is_artificial_var = 1;
6369e4b17023SJohn Marino   var_nonlocal->offset = 0;
6370e4b17023SJohn Marino   var_nonlocal->size = ~0;
6371e4b17023SJohn Marino   var_nonlocal->fullsize = ~0;
6372e4b17023SJohn Marino   var_nonlocal->is_special_var = 1;
6373e4b17023SJohn Marino 
6374e4b17023SJohn Marino   /* ESCAPED = *ESCAPED, because escaped is may-deref'd at calls, etc.  */
6375e4b17023SJohn Marino   lhs.type = SCALAR;
6376e4b17023SJohn Marino   lhs.var = escaped_id;
6377e4b17023SJohn Marino   lhs.offset = 0;
6378e4b17023SJohn Marino   rhs.type = DEREF;
6379e4b17023SJohn Marino   rhs.var = escaped_id;
6380e4b17023SJohn Marino   rhs.offset = 0;
6381e4b17023SJohn Marino   process_constraint (new_constraint (lhs, rhs));
6382e4b17023SJohn Marino 
6383e4b17023SJohn Marino   /* ESCAPED = ESCAPED + UNKNOWN_OFFSET, because if a sub-field escapes the
6384e4b17023SJohn Marino      whole variable escapes.  */
6385e4b17023SJohn Marino   lhs.type = SCALAR;
6386e4b17023SJohn Marino   lhs.var = escaped_id;
6387e4b17023SJohn Marino   lhs.offset = 0;
6388e4b17023SJohn Marino   rhs.type = SCALAR;
6389e4b17023SJohn Marino   rhs.var = escaped_id;
6390e4b17023SJohn Marino   rhs.offset = UNKNOWN_OFFSET;
6391e4b17023SJohn Marino   process_constraint (new_constraint (lhs, rhs));
6392e4b17023SJohn Marino 
6393e4b17023SJohn Marino   /* *ESCAPED = NONLOCAL.  This is true because we have to assume
6394e4b17023SJohn Marino      everything pointed to by escaped points to what global memory can
6395e4b17023SJohn Marino      point to.  */
6396e4b17023SJohn Marino   lhs.type = DEREF;
6397e4b17023SJohn Marino   lhs.var = escaped_id;
6398e4b17023SJohn Marino   lhs.offset = 0;
6399e4b17023SJohn Marino   rhs.type = SCALAR;
6400e4b17023SJohn Marino   rhs.var = nonlocal_id;
6401e4b17023SJohn Marino   rhs.offset = 0;
6402e4b17023SJohn Marino   process_constraint (new_constraint (lhs, rhs));
6403e4b17023SJohn Marino 
6404e4b17023SJohn Marino   /* NONLOCAL = &NONLOCAL, NONLOCAL = &ESCAPED.  This is true because
6405e4b17023SJohn Marino      global memory may point to global memory and escaped memory.  */
6406e4b17023SJohn Marino   lhs.type = SCALAR;
6407e4b17023SJohn Marino   lhs.var = nonlocal_id;
6408e4b17023SJohn Marino   lhs.offset = 0;
6409e4b17023SJohn Marino   rhs.type = ADDRESSOF;
6410e4b17023SJohn Marino   rhs.var = nonlocal_id;
6411e4b17023SJohn Marino   rhs.offset = 0;
6412e4b17023SJohn Marino   process_constraint (new_constraint (lhs, rhs));
6413e4b17023SJohn Marino   rhs.type = ADDRESSOF;
6414e4b17023SJohn Marino   rhs.var = escaped_id;
6415e4b17023SJohn Marino   rhs.offset = 0;
6416e4b17023SJohn Marino   process_constraint (new_constraint (lhs, rhs));
6417e4b17023SJohn Marino 
6418e4b17023SJohn Marino   /* Create the STOREDANYTHING variable, used to represent the set of
6419e4b17023SJohn Marino      variables stored to *ANYTHING.  */
6420e4b17023SJohn Marino   var_storedanything = new_var_info (NULL_TREE, "STOREDANYTHING");
6421e4b17023SJohn Marino   gcc_assert (var_storedanything->id == storedanything_id);
6422e4b17023SJohn Marino   var_storedanything->is_artificial_var = 1;
6423e4b17023SJohn Marino   var_storedanything->offset = 0;
6424e4b17023SJohn Marino   var_storedanything->size = ~0;
6425e4b17023SJohn Marino   var_storedanything->fullsize = ~0;
6426e4b17023SJohn Marino   var_storedanything->is_special_var = 0;
6427e4b17023SJohn Marino 
6428e4b17023SJohn Marino   /* Create the INTEGER variable, used to represent that a variable points
6429e4b17023SJohn Marino      to what an INTEGER "points to".  */
6430e4b17023SJohn Marino   var_integer = new_var_info (NULL_TREE, "INTEGER");
6431e4b17023SJohn Marino   gcc_assert (var_integer->id == integer_id);
6432e4b17023SJohn Marino   var_integer->is_artificial_var = 1;
6433e4b17023SJohn Marino   var_integer->size = ~0;
6434e4b17023SJohn Marino   var_integer->fullsize = ~0;
6435e4b17023SJohn Marino   var_integer->offset = 0;
6436e4b17023SJohn Marino   var_integer->next = NULL;
6437e4b17023SJohn Marino   var_integer->is_special_var = 1;
6438e4b17023SJohn Marino 
6439e4b17023SJohn Marino   /* INTEGER = ANYTHING, because we don't know where a dereference of
6440e4b17023SJohn Marino      a random integer will point to.  */
6441e4b17023SJohn Marino   lhs.type = SCALAR;
6442e4b17023SJohn Marino   lhs.var = integer_id;
6443e4b17023SJohn Marino   lhs.offset = 0;
6444e4b17023SJohn Marino   rhs.type = ADDRESSOF;
6445e4b17023SJohn Marino   rhs.var = anything_id;
6446e4b17023SJohn Marino   rhs.offset = 0;
6447e4b17023SJohn Marino   process_constraint (new_constraint (lhs, rhs));
6448e4b17023SJohn Marino }
6449e4b17023SJohn Marino 
6450e4b17023SJohn Marino /* Initialize things necessary to perform PTA */
6451e4b17023SJohn Marino 
6452e4b17023SJohn Marino static void
init_alias_vars(void)6453e4b17023SJohn Marino init_alias_vars (void)
6454e4b17023SJohn Marino {
6455e4b17023SJohn Marino   use_field_sensitive = (MAX_FIELDS_FOR_FIELD_SENSITIVE > 1);
6456e4b17023SJohn Marino 
6457e4b17023SJohn Marino   bitmap_obstack_initialize (&pta_obstack);
6458e4b17023SJohn Marino   bitmap_obstack_initialize (&oldpta_obstack);
6459e4b17023SJohn Marino   bitmap_obstack_initialize (&predbitmap_obstack);
6460e4b17023SJohn Marino 
6461e4b17023SJohn Marino   constraint_pool = create_alloc_pool ("Constraint pool",
6462e4b17023SJohn Marino 				       sizeof (struct constraint), 30);
6463e4b17023SJohn Marino   variable_info_pool = create_alloc_pool ("Variable info pool",
6464e4b17023SJohn Marino 					  sizeof (struct variable_info), 30);
6465e4b17023SJohn Marino   constraints = VEC_alloc (constraint_t, heap, 8);
6466e4b17023SJohn Marino   varmap = VEC_alloc (varinfo_t, heap, 8);
6467e4b17023SJohn Marino   vi_for_tree = pointer_map_create ();
6468e4b17023SJohn Marino   call_stmt_vars = pointer_map_create ();
6469e4b17023SJohn Marino 
6470e4b17023SJohn Marino   memset (&stats, 0, sizeof (stats));
6471e4b17023SJohn Marino   shared_bitmap_table = htab_create (511, shared_bitmap_hash,
6472e4b17023SJohn Marino 				     shared_bitmap_eq, free);
6473e4b17023SJohn Marino   init_base_vars ();
6474e4b17023SJohn Marino 
6475e4b17023SJohn Marino   gcc_obstack_init (&fake_var_decl_obstack);
6476e4b17023SJohn Marino }
6477e4b17023SJohn Marino 
6478e4b17023SJohn Marino /* Remove the REF and ADDRESS edges from GRAPH, as well as all the
6479e4b17023SJohn Marino    predecessor edges.  */
6480e4b17023SJohn Marino 
6481e4b17023SJohn Marino static void
remove_preds_and_fake_succs(constraint_graph_t graph)6482e4b17023SJohn Marino remove_preds_and_fake_succs (constraint_graph_t graph)
6483e4b17023SJohn Marino {
6484e4b17023SJohn Marino   unsigned int i;
6485e4b17023SJohn Marino 
6486e4b17023SJohn Marino   /* Clear the implicit ref and address nodes from the successor
6487e4b17023SJohn Marino      lists.  */
6488e4b17023SJohn Marino   for (i = 0; i < FIRST_REF_NODE; i++)
6489e4b17023SJohn Marino     {
6490e4b17023SJohn Marino       if (graph->succs[i])
6491e4b17023SJohn Marino 	bitmap_clear_range (graph->succs[i], FIRST_REF_NODE,
6492e4b17023SJohn Marino 			    FIRST_REF_NODE * 2);
6493e4b17023SJohn Marino     }
6494e4b17023SJohn Marino 
6495e4b17023SJohn Marino   /* Free the successor list for the non-ref nodes.  */
6496e4b17023SJohn Marino   for (i = FIRST_REF_NODE; i < graph->size; i++)
6497e4b17023SJohn Marino     {
6498e4b17023SJohn Marino       if (graph->succs[i])
6499e4b17023SJohn Marino 	BITMAP_FREE (graph->succs[i]);
6500e4b17023SJohn Marino     }
6501e4b17023SJohn Marino 
6502e4b17023SJohn Marino   /* Now reallocate the size of the successor list as, and blow away
6503e4b17023SJohn Marino      the predecessor bitmaps.  */
6504e4b17023SJohn Marino   graph->size = VEC_length (varinfo_t, varmap);
6505e4b17023SJohn Marino   graph->succs = XRESIZEVEC (bitmap, graph->succs, graph->size);
6506e4b17023SJohn Marino 
6507e4b17023SJohn Marino   free (graph->implicit_preds);
6508e4b17023SJohn Marino   graph->implicit_preds = NULL;
6509e4b17023SJohn Marino   free (graph->preds);
6510e4b17023SJohn Marino   graph->preds = NULL;
6511e4b17023SJohn Marino   bitmap_obstack_release (&predbitmap_obstack);
6512e4b17023SJohn Marino }
6513e4b17023SJohn Marino 
6514e4b17023SJohn Marino /* Solve the constraint set.  */
6515e4b17023SJohn Marino 
6516e4b17023SJohn Marino static void
solve_constraints(void)6517e4b17023SJohn Marino solve_constraints (void)
6518e4b17023SJohn Marino {
6519e4b17023SJohn Marino   struct scc_info *si;
6520e4b17023SJohn Marino 
6521e4b17023SJohn Marino   if (dump_file)
6522e4b17023SJohn Marino     fprintf (dump_file,
6523e4b17023SJohn Marino 	     "\nCollapsing static cycles and doing variable "
6524e4b17023SJohn Marino 	     "substitution\n");
6525e4b17023SJohn Marino 
6526e4b17023SJohn Marino   init_graph (VEC_length (varinfo_t, varmap) * 2);
6527e4b17023SJohn Marino 
6528e4b17023SJohn Marino   if (dump_file)
6529e4b17023SJohn Marino     fprintf (dump_file, "Building predecessor graph\n");
6530e4b17023SJohn Marino   build_pred_graph ();
6531e4b17023SJohn Marino 
6532e4b17023SJohn Marino   if (dump_file)
6533e4b17023SJohn Marino     fprintf (dump_file, "Detecting pointer and location "
6534e4b17023SJohn Marino 	     "equivalences\n");
6535e4b17023SJohn Marino   si = perform_var_substitution (graph);
6536e4b17023SJohn Marino 
6537e4b17023SJohn Marino   if (dump_file)
6538e4b17023SJohn Marino     fprintf (dump_file, "Rewriting constraints and unifying "
6539e4b17023SJohn Marino 	     "variables\n");
6540e4b17023SJohn Marino   rewrite_constraints (graph, si);
6541e4b17023SJohn Marino 
6542e4b17023SJohn Marino   build_succ_graph ();
6543e4b17023SJohn Marino 
6544e4b17023SJohn Marino   free_var_substitution_info (si);
6545e4b17023SJohn Marino 
6546e4b17023SJohn Marino   /* Attach complex constraints to graph nodes.  */
6547e4b17023SJohn Marino   move_complex_constraints (graph);
6548e4b17023SJohn Marino 
6549e4b17023SJohn Marino   if (dump_file)
6550e4b17023SJohn Marino     fprintf (dump_file, "Uniting pointer but not location equivalent "
6551e4b17023SJohn Marino 	     "variables\n");
6552e4b17023SJohn Marino   unite_pointer_equivalences (graph);
6553e4b17023SJohn Marino 
6554e4b17023SJohn Marino   if (dump_file)
6555e4b17023SJohn Marino     fprintf (dump_file, "Finding indirect cycles\n");
6556e4b17023SJohn Marino   find_indirect_cycles (graph);
6557e4b17023SJohn Marino 
6558e4b17023SJohn Marino   /* Implicit nodes and predecessors are no longer necessary at this
6559e4b17023SJohn Marino      point. */
6560e4b17023SJohn Marino   remove_preds_and_fake_succs (graph);
6561e4b17023SJohn Marino 
6562e4b17023SJohn Marino   if (dump_file && (dump_flags & TDF_GRAPH))
6563e4b17023SJohn Marino     {
6564e4b17023SJohn Marino       fprintf (dump_file, "\n\n// The constraint graph before solve-graph "
6565e4b17023SJohn Marino 	       "in dot format:\n");
6566e4b17023SJohn Marino       dump_constraint_graph (dump_file);
6567e4b17023SJohn Marino       fprintf (dump_file, "\n\n");
6568e4b17023SJohn Marino     }
6569e4b17023SJohn Marino 
6570e4b17023SJohn Marino   if (dump_file)
6571e4b17023SJohn Marino     fprintf (dump_file, "Solving graph\n");
6572e4b17023SJohn Marino 
6573e4b17023SJohn Marino   solve_graph (graph);
6574e4b17023SJohn Marino 
6575e4b17023SJohn Marino   if (dump_file && (dump_flags & TDF_GRAPH))
6576e4b17023SJohn Marino     {
6577e4b17023SJohn Marino       fprintf (dump_file, "\n\n// The constraint graph after solve-graph "
6578e4b17023SJohn Marino 	       "in dot format:\n");
6579e4b17023SJohn Marino       dump_constraint_graph (dump_file);
6580e4b17023SJohn Marino       fprintf (dump_file, "\n\n");
6581e4b17023SJohn Marino     }
6582e4b17023SJohn Marino 
6583e4b17023SJohn Marino   if (dump_file)
6584e4b17023SJohn Marino     dump_sa_points_to_info (dump_file);
6585e4b17023SJohn Marino }
6586e4b17023SJohn Marino 
6587e4b17023SJohn Marino /* Create points-to sets for the current function.  See the comments
6588e4b17023SJohn Marino    at the start of the file for an algorithmic overview.  */
6589e4b17023SJohn Marino 
6590e4b17023SJohn Marino static void
compute_points_to_sets(void)6591e4b17023SJohn Marino compute_points_to_sets (void)
6592e4b17023SJohn Marino {
6593e4b17023SJohn Marino   basic_block bb;
6594e4b17023SJohn Marino   unsigned i;
6595e4b17023SJohn Marino   varinfo_t vi;
6596e4b17023SJohn Marino 
6597e4b17023SJohn Marino   timevar_push (TV_TREE_PTA);
6598e4b17023SJohn Marino 
6599e4b17023SJohn Marino   init_alias_vars ();
6600e4b17023SJohn Marino 
6601e4b17023SJohn Marino   intra_create_variable_infos ();
6602e4b17023SJohn Marino 
6603e4b17023SJohn Marino   /* Now walk all statements and build the constraint set.  */
6604e4b17023SJohn Marino   FOR_EACH_BB (bb)
6605e4b17023SJohn Marino     {
6606e4b17023SJohn Marino       gimple_stmt_iterator gsi;
6607e4b17023SJohn Marino 
6608e4b17023SJohn Marino       for (gsi = gsi_start_phis (bb); !gsi_end_p (gsi); gsi_next (&gsi))
6609e4b17023SJohn Marino 	{
6610e4b17023SJohn Marino 	  gimple phi = gsi_stmt (gsi);
6611e4b17023SJohn Marino 
6612e4b17023SJohn Marino 	  if (is_gimple_reg (gimple_phi_result (phi)))
6613e4b17023SJohn Marino 	    find_func_aliases (phi);
6614e4b17023SJohn Marino 	}
6615e4b17023SJohn Marino 
6616e4b17023SJohn Marino       for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi))
6617e4b17023SJohn Marino 	{
6618e4b17023SJohn Marino 	  gimple stmt = gsi_stmt (gsi);
6619e4b17023SJohn Marino 
6620e4b17023SJohn Marino 	  find_func_aliases (stmt);
6621e4b17023SJohn Marino 	}
6622e4b17023SJohn Marino     }
6623e4b17023SJohn Marino 
6624e4b17023SJohn Marino   if (dump_file)
6625e4b17023SJohn Marino     {
6626e4b17023SJohn Marino       fprintf (dump_file, "Points-to analysis\n\nConstraints:\n\n");
6627e4b17023SJohn Marino       dump_constraints (dump_file, 0);
6628e4b17023SJohn Marino     }
6629e4b17023SJohn Marino 
6630e4b17023SJohn Marino   /* From the constraints compute the points-to sets.  */
6631e4b17023SJohn Marino   solve_constraints ();
6632e4b17023SJohn Marino 
6633e4b17023SJohn Marino   /* Compute the points-to set for ESCAPED used for call-clobber analysis.  */
6634e4b17023SJohn Marino   find_what_var_points_to (get_varinfo (escaped_id),
6635e4b17023SJohn Marino 			   &cfun->gimple_df->escaped);
6636e4b17023SJohn Marino 
6637e4b17023SJohn Marino   /* Make sure the ESCAPED solution (which is used as placeholder in
6638e4b17023SJohn Marino      other solutions) does not reference itself.  This simplifies
6639e4b17023SJohn Marino      points-to solution queries.  */
6640e4b17023SJohn Marino   cfun->gimple_df->escaped.escaped = 0;
6641e4b17023SJohn Marino 
6642e4b17023SJohn Marino   /* Mark escaped HEAP variables as global.  */
6643e4b17023SJohn Marino   FOR_EACH_VEC_ELT (varinfo_t, varmap, i, vi)
6644e4b17023SJohn Marino     if (vi->is_heap_var
6645e4b17023SJohn Marino 	&& !vi->is_global_var)
6646e4b17023SJohn Marino       DECL_EXTERNAL (vi->decl) = vi->is_global_var
6647e4b17023SJohn Marino 	= pt_solution_includes (&cfun->gimple_df->escaped, vi->decl);
6648e4b17023SJohn Marino 
6649e4b17023SJohn Marino   /* Compute the points-to sets for pointer SSA_NAMEs.  */
6650e4b17023SJohn Marino   for (i = 0; i < num_ssa_names; ++i)
6651e4b17023SJohn Marino     {
6652e4b17023SJohn Marino       tree ptr = ssa_name (i);
6653e4b17023SJohn Marino       if (ptr
6654e4b17023SJohn Marino 	  && POINTER_TYPE_P (TREE_TYPE (ptr)))
6655e4b17023SJohn Marino 	find_what_p_points_to (ptr);
6656e4b17023SJohn Marino     }
6657e4b17023SJohn Marino 
6658e4b17023SJohn Marino   /* Compute the call-used/clobbered sets.  */
6659e4b17023SJohn Marino   FOR_EACH_BB (bb)
6660e4b17023SJohn Marino     {
6661e4b17023SJohn Marino       gimple_stmt_iterator gsi;
6662e4b17023SJohn Marino 
6663e4b17023SJohn Marino       for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi))
6664e4b17023SJohn Marino 	{
6665e4b17023SJohn Marino 	  gimple stmt = gsi_stmt (gsi);
6666e4b17023SJohn Marino 	  struct pt_solution *pt;
6667e4b17023SJohn Marino 	  if (!is_gimple_call (stmt))
6668e4b17023SJohn Marino 	    continue;
6669e4b17023SJohn Marino 
6670e4b17023SJohn Marino 	  pt = gimple_call_use_set (stmt);
6671e4b17023SJohn Marino 	  if (gimple_call_flags (stmt) & ECF_CONST)
6672e4b17023SJohn Marino 	    memset (pt, 0, sizeof (struct pt_solution));
6673e4b17023SJohn Marino 	  else if ((vi = lookup_call_use_vi (stmt)) != NULL)
6674e4b17023SJohn Marino 	    {
6675e4b17023SJohn Marino 	      find_what_var_points_to (vi, pt);
6676e4b17023SJohn Marino 	      /* Escaped (and thus nonlocal) variables are always
6677e4b17023SJohn Marino 	         implicitly used by calls.  */
6678e4b17023SJohn Marino 	      /* ???  ESCAPED can be empty even though NONLOCAL
6679e4b17023SJohn Marino 		 always escaped.  */
6680e4b17023SJohn Marino 	      pt->nonlocal = 1;
6681e4b17023SJohn Marino 	      pt->escaped = 1;
6682e4b17023SJohn Marino 	    }
6683e4b17023SJohn Marino 	  else
6684e4b17023SJohn Marino 	    {
6685e4b17023SJohn Marino 	      /* If there is nothing special about this call then
6686e4b17023SJohn Marino 		 we have made everything that is used also escape.  */
6687e4b17023SJohn Marino 	      *pt = cfun->gimple_df->escaped;
6688e4b17023SJohn Marino 	      pt->nonlocal = 1;
6689e4b17023SJohn Marino 	    }
6690e4b17023SJohn Marino 
6691e4b17023SJohn Marino 	  pt = gimple_call_clobber_set (stmt);
6692e4b17023SJohn Marino 	  if (gimple_call_flags (stmt) & (ECF_CONST|ECF_PURE|ECF_NOVOPS))
6693e4b17023SJohn Marino 	    memset (pt, 0, sizeof (struct pt_solution));
6694e4b17023SJohn Marino 	  else if ((vi = lookup_call_clobber_vi (stmt)) != NULL)
6695e4b17023SJohn Marino 	    {
6696e4b17023SJohn Marino 	      find_what_var_points_to (vi, pt);
6697e4b17023SJohn Marino 	      /* Escaped (and thus nonlocal) variables are always
6698e4b17023SJohn Marino 	         implicitly clobbered by calls.  */
6699e4b17023SJohn Marino 	      /* ???  ESCAPED can be empty even though NONLOCAL
6700e4b17023SJohn Marino 		 always escaped.  */
6701e4b17023SJohn Marino 	      pt->nonlocal = 1;
6702e4b17023SJohn Marino 	      pt->escaped = 1;
6703e4b17023SJohn Marino 	    }
6704e4b17023SJohn Marino 	  else
6705e4b17023SJohn Marino 	    {
6706e4b17023SJohn Marino 	      /* If there is nothing special about this call then
6707e4b17023SJohn Marino 		 we have made everything that is used also escape.  */
6708e4b17023SJohn Marino 	      *pt = cfun->gimple_df->escaped;
6709e4b17023SJohn Marino 	      pt->nonlocal = 1;
6710e4b17023SJohn Marino 	    }
6711e4b17023SJohn Marino 	}
6712e4b17023SJohn Marino     }
6713e4b17023SJohn Marino 
6714e4b17023SJohn Marino   timevar_pop (TV_TREE_PTA);
6715e4b17023SJohn Marino }
6716e4b17023SJohn Marino 
6717e4b17023SJohn Marino 
6718e4b17023SJohn Marino /* Delete created points-to sets.  */
6719e4b17023SJohn Marino 
6720e4b17023SJohn Marino static void
delete_points_to_sets(void)6721e4b17023SJohn Marino delete_points_to_sets (void)
6722e4b17023SJohn Marino {
6723e4b17023SJohn Marino   unsigned int i;
6724e4b17023SJohn Marino 
6725e4b17023SJohn Marino   htab_delete (shared_bitmap_table);
6726e4b17023SJohn Marino   if (dump_file && (dump_flags & TDF_STATS))
6727e4b17023SJohn Marino     fprintf (dump_file, "Points to sets created:%d\n",
6728e4b17023SJohn Marino 	     stats.points_to_sets_created);
6729e4b17023SJohn Marino 
6730e4b17023SJohn Marino   pointer_map_destroy (vi_for_tree);
6731e4b17023SJohn Marino   pointer_map_destroy (call_stmt_vars);
6732e4b17023SJohn Marino   bitmap_obstack_release (&pta_obstack);
6733e4b17023SJohn Marino   VEC_free (constraint_t, heap, constraints);
6734e4b17023SJohn Marino 
6735e4b17023SJohn Marino   for (i = 0; i < graph->size; i++)
6736e4b17023SJohn Marino     VEC_free (constraint_t, heap, graph->complex[i]);
6737e4b17023SJohn Marino   free (graph->complex);
6738e4b17023SJohn Marino 
6739e4b17023SJohn Marino   free (graph->rep);
6740e4b17023SJohn Marino   free (graph->succs);
6741e4b17023SJohn Marino   free (graph->pe);
6742e4b17023SJohn Marino   free (graph->pe_rep);
6743e4b17023SJohn Marino   free (graph->indirect_cycles);
6744e4b17023SJohn Marino   free (graph);
6745e4b17023SJohn Marino 
6746e4b17023SJohn Marino   VEC_free (varinfo_t, heap, varmap);
6747e4b17023SJohn Marino   free_alloc_pool (variable_info_pool);
6748e4b17023SJohn Marino   free_alloc_pool (constraint_pool);
6749e4b17023SJohn Marino 
6750e4b17023SJohn Marino   obstack_free (&fake_var_decl_obstack, NULL);
6751e4b17023SJohn Marino }
6752e4b17023SJohn Marino 
6753e4b17023SJohn Marino 
6754e4b17023SJohn Marino /* Compute points-to information for every SSA_NAME pointer in the
6755e4b17023SJohn Marino    current function and compute the transitive closure of escaped
6756e4b17023SJohn Marino    variables to re-initialize the call-clobber states of local variables.  */
6757e4b17023SJohn Marino 
6758e4b17023SJohn Marino unsigned int
compute_may_aliases(void)6759e4b17023SJohn Marino compute_may_aliases (void)
6760e4b17023SJohn Marino {
6761e4b17023SJohn Marino   if (cfun->gimple_df->ipa_pta)
6762e4b17023SJohn Marino     {
6763e4b17023SJohn Marino       if (dump_file)
6764e4b17023SJohn Marino 	{
6765e4b17023SJohn Marino 	  fprintf (dump_file, "\nNot re-computing points-to information "
6766e4b17023SJohn Marino 		   "because IPA points-to information is available.\n\n");
6767e4b17023SJohn Marino 
6768e4b17023SJohn Marino 	  /* But still dump what we have remaining it.  */
6769e4b17023SJohn Marino 	  dump_alias_info (dump_file);
6770e4b17023SJohn Marino 
6771e4b17023SJohn Marino 	  if (dump_flags & TDF_DETAILS)
6772e4b17023SJohn Marino 	    dump_referenced_vars (dump_file);
6773e4b17023SJohn Marino 	}
6774e4b17023SJohn Marino 
6775e4b17023SJohn Marino       return 0;
6776e4b17023SJohn Marino     }
6777e4b17023SJohn Marino 
6778e4b17023SJohn Marino   /* For each pointer P_i, determine the sets of variables that P_i may
6779e4b17023SJohn Marino      point-to.  Compute the reachability set of escaped and call-used
6780e4b17023SJohn Marino      variables.  */
6781e4b17023SJohn Marino   compute_points_to_sets ();
6782e4b17023SJohn Marino 
6783e4b17023SJohn Marino   /* Debugging dumps.  */
6784e4b17023SJohn Marino   if (dump_file)
6785e4b17023SJohn Marino     {
6786e4b17023SJohn Marino       dump_alias_info (dump_file);
6787e4b17023SJohn Marino 
6788e4b17023SJohn Marino       if (dump_flags & TDF_DETAILS)
6789e4b17023SJohn Marino 	dump_referenced_vars (dump_file);
6790e4b17023SJohn Marino     }
6791e4b17023SJohn Marino 
6792e4b17023SJohn Marino   /* Deallocate memory used by aliasing data structures and the internal
6793e4b17023SJohn Marino      points-to solution.  */
6794e4b17023SJohn Marino   delete_points_to_sets ();
6795e4b17023SJohn Marino 
6796e4b17023SJohn Marino   gcc_assert (!need_ssa_update_p (cfun));
6797e4b17023SJohn Marino 
6798e4b17023SJohn Marino   return 0;
6799e4b17023SJohn Marino }
6800e4b17023SJohn Marino 
6801e4b17023SJohn Marino static bool
gate_tree_pta(void)6802e4b17023SJohn Marino gate_tree_pta (void)
6803e4b17023SJohn Marino {
6804e4b17023SJohn Marino   return flag_tree_pta;
6805e4b17023SJohn Marino }
6806e4b17023SJohn Marino 
6807e4b17023SJohn Marino /* A dummy pass to cause points-to information to be computed via
6808e4b17023SJohn Marino    TODO_rebuild_alias.  */
6809e4b17023SJohn Marino 
6810e4b17023SJohn Marino struct gimple_opt_pass pass_build_alias =
6811e4b17023SJohn Marino {
6812e4b17023SJohn Marino  {
6813e4b17023SJohn Marino   GIMPLE_PASS,
6814e4b17023SJohn Marino   "alias",		    /* name */
6815e4b17023SJohn Marino   gate_tree_pta,	    /* gate */
6816e4b17023SJohn Marino   NULL,                     /* execute */
6817e4b17023SJohn Marino   NULL,                     /* sub */
6818e4b17023SJohn Marino   NULL,                     /* next */
6819e4b17023SJohn Marino   0,                        /* static_pass_number */
6820e4b17023SJohn Marino   TV_NONE,                  /* tv_id */
6821e4b17023SJohn Marino   PROP_cfg | PROP_ssa,      /* properties_required */
6822e4b17023SJohn Marino   0,			    /* properties_provided */
6823e4b17023SJohn Marino   0,                        /* properties_destroyed */
6824e4b17023SJohn Marino   0,                        /* todo_flags_start */
6825e4b17023SJohn Marino   TODO_rebuild_alias        /* todo_flags_finish */
6826e4b17023SJohn Marino  }
6827e4b17023SJohn Marino };
6828e4b17023SJohn Marino 
6829e4b17023SJohn Marino /* A dummy pass to cause points-to information to be computed via
6830e4b17023SJohn Marino    TODO_rebuild_alias.  */
6831e4b17023SJohn Marino 
6832e4b17023SJohn Marino struct gimple_opt_pass pass_build_ealias =
6833e4b17023SJohn Marino {
6834e4b17023SJohn Marino  {
6835e4b17023SJohn Marino   GIMPLE_PASS,
6836e4b17023SJohn Marino   "ealias",		    /* name */
6837e4b17023SJohn Marino   gate_tree_pta,	    /* gate */
6838e4b17023SJohn Marino   NULL,                     /* execute */
6839e4b17023SJohn Marino   NULL,                     /* sub */
6840e4b17023SJohn Marino   NULL,                     /* next */
6841e4b17023SJohn Marino   0,                        /* static_pass_number */
6842e4b17023SJohn Marino   TV_NONE,                  /* tv_id */
6843e4b17023SJohn Marino   PROP_cfg | PROP_ssa,      /* properties_required */
6844e4b17023SJohn Marino   0,			    /* properties_provided */
6845e4b17023SJohn Marino   0,                        /* properties_destroyed */
6846e4b17023SJohn Marino   0,                        /* todo_flags_start */
6847e4b17023SJohn Marino   TODO_rebuild_alias        /* todo_flags_finish */
6848e4b17023SJohn Marino  }
6849e4b17023SJohn Marino };
6850e4b17023SJohn Marino 
6851e4b17023SJohn Marino 
6852e4b17023SJohn Marino /* Return true if we should execute IPA PTA.  */
6853e4b17023SJohn Marino static bool
gate_ipa_pta(void)6854e4b17023SJohn Marino gate_ipa_pta (void)
6855e4b17023SJohn Marino {
6856e4b17023SJohn Marino   return (optimize
6857e4b17023SJohn Marino 	  && flag_ipa_pta
6858e4b17023SJohn Marino 	  /* Don't bother doing anything if the program has errors.  */
6859e4b17023SJohn Marino 	  && !seen_error ());
6860e4b17023SJohn Marino }
6861e4b17023SJohn Marino 
6862e4b17023SJohn Marino /* IPA PTA solutions for ESCAPED.  */
6863e4b17023SJohn Marino struct pt_solution ipa_escaped_pt
6864e4b17023SJohn Marino   = { true, false, false, false, false, false, NULL };
6865e4b17023SJohn Marino 
6866e4b17023SJohn Marino /* Associate node with varinfo DATA. Worker for
6867e4b17023SJohn Marino    cgraph_for_node_and_aliases.  */
6868e4b17023SJohn Marino static bool
associate_varinfo_to_alias(struct cgraph_node * node,void * data)6869e4b17023SJohn Marino associate_varinfo_to_alias (struct cgraph_node *node, void *data)
6870e4b17023SJohn Marino {
6871e4b17023SJohn Marino   if (node->alias || node->thunk.thunk_p)
6872e4b17023SJohn Marino     insert_vi_for_tree (node->decl, (varinfo_t)data);
6873e4b17023SJohn Marino   return false;
6874e4b17023SJohn Marino }
6875e4b17023SJohn Marino 
6876e4b17023SJohn Marino /* Execute the driver for IPA PTA.  */
6877e4b17023SJohn Marino static unsigned int
ipa_pta_execute(void)6878e4b17023SJohn Marino ipa_pta_execute (void)
6879e4b17023SJohn Marino {
6880e4b17023SJohn Marino   struct cgraph_node *node;
6881e4b17023SJohn Marino   struct varpool_node *var;
6882e4b17023SJohn Marino   int from;
6883e4b17023SJohn Marino 
6884e4b17023SJohn Marino   in_ipa_mode = 1;
6885e4b17023SJohn Marino 
6886e4b17023SJohn Marino   init_alias_vars ();
6887e4b17023SJohn Marino 
6888e4b17023SJohn Marino   if (dump_file && (dump_flags & TDF_DETAILS))
6889e4b17023SJohn Marino     {
6890e4b17023SJohn Marino       dump_cgraph (dump_file);
6891e4b17023SJohn Marino       fprintf (dump_file, "\n");
6892e4b17023SJohn Marino     }
6893e4b17023SJohn Marino 
6894e4b17023SJohn Marino   /* Build the constraints.  */
6895e4b17023SJohn Marino   for (node = cgraph_nodes; node; node = node->next)
6896e4b17023SJohn Marino     {
6897e4b17023SJohn Marino       varinfo_t vi;
6898e4b17023SJohn Marino       /* Nodes without a body are not interesting.  Especially do not
6899e4b17023SJohn Marino          visit clones at this point for now - we get duplicate decls
6900e4b17023SJohn Marino 	 there for inline clones at least.  */
6901e4b17023SJohn Marino       if (!cgraph_function_with_gimple_body_p (node))
6902e4b17023SJohn Marino 	continue;
6903e4b17023SJohn Marino 
6904e4b17023SJohn Marino       gcc_assert (!node->clone_of);
6905e4b17023SJohn Marino 
6906e4b17023SJohn Marino       vi = create_function_info_for (node->decl,
6907e4b17023SJohn Marino 			             alias_get_name (node->decl));
6908e4b17023SJohn Marino       cgraph_for_node_and_aliases (node, associate_varinfo_to_alias, vi, true);
6909e4b17023SJohn Marino     }
6910e4b17023SJohn Marino 
6911e4b17023SJohn Marino   /* Create constraints for global variables and their initializers.  */
6912e4b17023SJohn Marino   for (var = varpool_nodes; var; var = var->next)
6913e4b17023SJohn Marino     {
6914e4b17023SJohn Marino       if (var->alias)
6915e4b17023SJohn Marino 	continue;
6916e4b17023SJohn Marino 
6917e4b17023SJohn Marino       get_vi_for_tree (var->decl);
6918e4b17023SJohn Marino     }
6919e4b17023SJohn Marino 
6920e4b17023SJohn Marino   if (dump_file)
6921e4b17023SJohn Marino     {
6922e4b17023SJohn Marino       fprintf (dump_file,
6923e4b17023SJohn Marino 	       "Generating constraints for global initializers\n\n");
6924e4b17023SJohn Marino       dump_constraints (dump_file, 0);
6925e4b17023SJohn Marino       fprintf (dump_file, "\n");
6926e4b17023SJohn Marino     }
6927e4b17023SJohn Marino   from = VEC_length (constraint_t, constraints);
6928e4b17023SJohn Marino 
6929e4b17023SJohn Marino   for (node = cgraph_nodes; node; node = node->next)
6930e4b17023SJohn Marino     {
6931e4b17023SJohn Marino       struct function *func;
6932e4b17023SJohn Marino       basic_block bb;
6933e4b17023SJohn Marino       tree old_func_decl;
6934e4b17023SJohn Marino 
6935e4b17023SJohn Marino       /* Nodes without a body are not interesting.  */
6936e4b17023SJohn Marino       if (!cgraph_function_with_gimple_body_p (node))
6937e4b17023SJohn Marino 	continue;
6938e4b17023SJohn Marino 
6939e4b17023SJohn Marino       if (dump_file)
6940e4b17023SJohn Marino 	{
6941e4b17023SJohn Marino 	  fprintf (dump_file,
6942e4b17023SJohn Marino 		   "Generating constraints for %s", cgraph_node_name (node));
6943e4b17023SJohn Marino 	  if (DECL_ASSEMBLER_NAME_SET_P (node->decl))
6944e4b17023SJohn Marino 	    fprintf (dump_file, " (%s)",
6945e4b17023SJohn Marino 		     IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (node->decl)));
6946e4b17023SJohn Marino 	  fprintf (dump_file, "\n");
6947e4b17023SJohn Marino 	}
6948e4b17023SJohn Marino 
6949e4b17023SJohn Marino       func = DECL_STRUCT_FUNCTION (node->decl);
6950e4b17023SJohn Marino       old_func_decl = current_function_decl;
6951e4b17023SJohn Marino       push_cfun (func);
6952e4b17023SJohn Marino       current_function_decl = node->decl;
6953e4b17023SJohn Marino 
6954e4b17023SJohn Marino       /* For externally visible or attribute used annotated functions use
6955e4b17023SJohn Marino 	 local constraints for their arguments.
6956e4b17023SJohn Marino 	 For local functions we see all callers and thus do not need initial
6957e4b17023SJohn Marino 	 constraints for parameters.  */
6958e4b17023SJohn Marino       if (node->reachable_from_other_partition
6959e4b17023SJohn Marino 	  || node->local.externally_visible
6960e4b17023SJohn Marino 	  || node->needed)
6961e4b17023SJohn Marino 	{
6962e4b17023SJohn Marino 	  intra_create_variable_infos ();
6963e4b17023SJohn Marino 
6964e4b17023SJohn Marino 	  /* We also need to make function return values escape.  Nothing
6965e4b17023SJohn Marino 	     escapes by returning from main though.  */
6966e4b17023SJohn Marino 	  if (!MAIN_NAME_P (DECL_NAME (node->decl)))
6967e4b17023SJohn Marino 	    {
6968e4b17023SJohn Marino 	      varinfo_t fi, rvi;
6969e4b17023SJohn Marino 	      fi = lookup_vi_for_tree (node->decl);
6970e4b17023SJohn Marino 	      rvi = first_vi_for_offset (fi, fi_result);
6971e4b17023SJohn Marino 	      if (rvi && rvi->offset == fi_result)
6972e4b17023SJohn Marino 		{
6973e4b17023SJohn Marino 		  struct constraint_expr includes;
6974e4b17023SJohn Marino 		  struct constraint_expr var;
6975e4b17023SJohn Marino 		  includes.var = escaped_id;
6976e4b17023SJohn Marino 		  includes.offset = 0;
6977e4b17023SJohn Marino 		  includes.type = SCALAR;
6978e4b17023SJohn Marino 		  var.var = rvi->id;
6979e4b17023SJohn Marino 		  var.offset = 0;
6980e4b17023SJohn Marino 		  var.type = SCALAR;
6981e4b17023SJohn Marino 		  process_constraint (new_constraint (includes, var));
6982e4b17023SJohn Marino 		}
6983e4b17023SJohn Marino 	    }
6984e4b17023SJohn Marino 	}
6985e4b17023SJohn Marino 
6986e4b17023SJohn Marino       /* Build constriants for the function body.  */
6987e4b17023SJohn Marino       FOR_EACH_BB_FN (bb, func)
6988e4b17023SJohn Marino 	{
6989e4b17023SJohn Marino 	  gimple_stmt_iterator gsi;
6990e4b17023SJohn Marino 
6991e4b17023SJohn Marino 	  for (gsi = gsi_start_phis (bb); !gsi_end_p (gsi);
6992e4b17023SJohn Marino 	       gsi_next (&gsi))
6993e4b17023SJohn Marino 	    {
6994e4b17023SJohn Marino 	      gimple phi = gsi_stmt (gsi);
6995e4b17023SJohn Marino 
6996e4b17023SJohn Marino 	      if (is_gimple_reg (gimple_phi_result (phi)))
6997e4b17023SJohn Marino 		find_func_aliases (phi);
6998e4b17023SJohn Marino 	    }
6999e4b17023SJohn Marino 
7000e4b17023SJohn Marino 	  for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi))
7001e4b17023SJohn Marino 	    {
7002e4b17023SJohn Marino 	      gimple stmt = gsi_stmt (gsi);
7003e4b17023SJohn Marino 
7004e4b17023SJohn Marino 	      find_func_aliases (stmt);
7005e4b17023SJohn Marino 	      find_func_clobbers (stmt);
7006e4b17023SJohn Marino 	    }
7007e4b17023SJohn Marino 	}
7008e4b17023SJohn Marino 
7009e4b17023SJohn Marino       current_function_decl = old_func_decl;
7010e4b17023SJohn Marino       pop_cfun ();
7011e4b17023SJohn Marino 
7012e4b17023SJohn Marino       if (dump_file)
7013e4b17023SJohn Marino 	{
7014e4b17023SJohn Marino 	  fprintf (dump_file, "\n");
7015e4b17023SJohn Marino 	  dump_constraints (dump_file, from);
7016e4b17023SJohn Marino 	  fprintf (dump_file, "\n");
7017e4b17023SJohn Marino 	}
7018e4b17023SJohn Marino       from = VEC_length (constraint_t, constraints);
7019e4b17023SJohn Marino     }
7020e4b17023SJohn Marino 
7021e4b17023SJohn Marino   /* From the constraints compute the points-to sets.  */
7022e4b17023SJohn Marino   solve_constraints ();
7023e4b17023SJohn Marino 
7024e4b17023SJohn Marino   /* Compute the global points-to sets for ESCAPED.
7025e4b17023SJohn Marino      ???  Note that the computed escape set is not correct
7026e4b17023SJohn Marino      for the whole unit as we fail to consider graph edges to
7027e4b17023SJohn Marino      externally visible functions.  */
7028e4b17023SJohn Marino   find_what_var_points_to (get_varinfo (escaped_id), &ipa_escaped_pt);
7029e4b17023SJohn Marino 
7030e4b17023SJohn Marino   /* Make sure the ESCAPED solution (which is used as placeholder in
7031e4b17023SJohn Marino      other solutions) does not reference itself.  This simplifies
7032e4b17023SJohn Marino      points-to solution queries.  */
7033e4b17023SJohn Marino   ipa_escaped_pt.ipa_escaped = 0;
7034e4b17023SJohn Marino 
7035e4b17023SJohn Marino   /* Assign the points-to sets to the SSA names in the unit.  */
7036e4b17023SJohn Marino   for (node = cgraph_nodes; node; node = node->next)
7037e4b17023SJohn Marino     {
7038e4b17023SJohn Marino       tree ptr;
7039e4b17023SJohn Marino       struct function *fn;
7040e4b17023SJohn Marino       unsigned i;
7041e4b17023SJohn Marino       varinfo_t fi;
7042e4b17023SJohn Marino       basic_block bb;
7043e4b17023SJohn Marino       struct pt_solution uses, clobbers;
7044e4b17023SJohn Marino       struct cgraph_edge *e;
7045e4b17023SJohn Marino 
7046e4b17023SJohn Marino       /* Nodes without a body are not interesting.  */
7047e4b17023SJohn Marino       if (!cgraph_function_with_gimple_body_p (node))
7048e4b17023SJohn Marino 	continue;
7049e4b17023SJohn Marino 
7050e4b17023SJohn Marino       fn = DECL_STRUCT_FUNCTION (node->decl);
7051e4b17023SJohn Marino 
7052e4b17023SJohn Marino       /* Compute the points-to sets for pointer SSA_NAMEs.  */
7053e4b17023SJohn Marino       FOR_EACH_VEC_ELT (tree, fn->gimple_df->ssa_names, i, ptr)
7054e4b17023SJohn Marino 	{
7055e4b17023SJohn Marino 	  if (ptr
7056e4b17023SJohn Marino 	      && POINTER_TYPE_P (TREE_TYPE (ptr)))
7057e4b17023SJohn Marino 	    find_what_p_points_to (ptr);
7058e4b17023SJohn Marino 	}
7059e4b17023SJohn Marino 
7060e4b17023SJohn Marino       /* Compute the call-use and call-clobber sets for all direct calls.  */
7061e4b17023SJohn Marino       fi = lookup_vi_for_tree (node->decl);
7062e4b17023SJohn Marino       gcc_assert (fi->is_fn_info);
7063e4b17023SJohn Marino       find_what_var_points_to (first_vi_for_offset (fi, fi_clobbers),
7064e4b17023SJohn Marino 			       &clobbers);
7065e4b17023SJohn Marino       find_what_var_points_to (first_vi_for_offset (fi, fi_uses), &uses);
7066e4b17023SJohn Marino       for (e = node->callers; e; e = e->next_caller)
7067e4b17023SJohn Marino 	{
7068e4b17023SJohn Marino 	  if (!e->call_stmt)
7069e4b17023SJohn Marino 	    continue;
7070e4b17023SJohn Marino 
7071e4b17023SJohn Marino 	  *gimple_call_clobber_set (e->call_stmt) = clobbers;
7072e4b17023SJohn Marino 	  *gimple_call_use_set (e->call_stmt) = uses;
7073e4b17023SJohn Marino 	}
7074e4b17023SJohn Marino 
7075e4b17023SJohn Marino       /* Compute the call-use and call-clobber sets for indirect calls
7076e4b17023SJohn Marino 	 and calls to external functions.  */
7077e4b17023SJohn Marino       FOR_EACH_BB_FN (bb, fn)
7078e4b17023SJohn Marino 	{
7079e4b17023SJohn Marino 	  gimple_stmt_iterator gsi;
7080e4b17023SJohn Marino 
7081e4b17023SJohn Marino 	  for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi))
7082e4b17023SJohn Marino 	    {
7083e4b17023SJohn Marino 	      gimple stmt = gsi_stmt (gsi);
7084e4b17023SJohn Marino 	      struct pt_solution *pt;
7085e4b17023SJohn Marino 	      varinfo_t vi;
7086e4b17023SJohn Marino 	      tree decl;
7087e4b17023SJohn Marino 
7088e4b17023SJohn Marino 	      if (!is_gimple_call (stmt))
7089e4b17023SJohn Marino 		continue;
7090e4b17023SJohn Marino 
7091e4b17023SJohn Marino 	      /* Handle direct calls to external functions.  */
7092e4b17023SJohn Marino 	      decl = gimple_call_fndecl (stmt);
7093e4b17023SJohn Marino 	      if (decl
7094e4b17023SJohn Marino 		  && (!(fi = lookup_vi_for_tree (decl))
7095e4b17023SJohn Marino 		      || !fi->is_fn_info))
7096e4b17023SJohn Marino 		{
7097e4b17023SJohn Marino 		  pt = gimple_call_use_set (stmt);
7098e4b17023SJohn Marino 		  if (gimple_call_flags (stmt) & ECF_CONST)
7099e4b17023SJohn Marino 		    memset (pt, 0, sizeof (struct pt_solution));
7100e4b17023SJohn Marino 		  else if ((vi = lookup_call_use_vi (stmt)) != NULL)
7101e4b17023SJohn Marino 		    {
7102e4b17023SJohn Marino 		      find_what_var_points_to (vi, pt);
7103e4b17023SJohn Marino 		      /* Escaped (and thus nonlocal) variables are always
7104e4b17023SJohn Marino 			 implicitly used by calls.  */
7105e4b17023SJohn Marino 		      /* ???  ESCAPED can be empty even though NONLOCAL
7106e4b17023SJohn Marino 			 always escaped.  */
7107e4b17023SJohn Marino 		      pt->nonlocal = 1;
7108e4b17023SJohn Marino 		      pt->ipa_escaped = 1;
7109e4b17023SJohn Marino 		    }
7110e4b17023SJohn Marino 		  else
7111e4b17023SJohn Marino 		    {
7112e4b17023SJohn Marino 		      /* If there is nothing special about this call then
7113e4b17023SJohn Marino 			 we have made everything that is used also escape.  */
7114e4b17023SJohn Marino 		      *pt = ipa_escaped_pt;
7115e4b17023SJohn Marino 		      pt->nonlocal = 1;
7116e4b17023SJohn Marino 		    }
7117e4b17023SJohn Marino 
7118e4b17023SJohn Marino 		  pt = gimple_call_clobber_set (stmt);
7119e4b17023SJohn Marino 		  if (gimple_call_flags (stmt) & (ECF_CONST|ECF_PURE|ECF_NOVOPS))
7120e4b17023SJohn Marino 		    memset (pt, 0, sizeof (struct pt_solution));
7121e4b17023SJohn Marino 		  else if ((vi = lookup_call_clobber_vi (stmt)) != NULL)
7122e4b17023SJohn Marino 		    {
7123e4b17023SJohn Marino 		      find_what_var_points_to (vi, pt);
7124e4b17023SJohn Marino 		      /* Escaped (and thus nonlocal) variables are always
7125e4b17023SJohn Marino 			 implicitly clobbered by calls.  */
7126e4b17023SJohn Marino 		      /* ???  ESCAPED can be empty even though NONLOCAL
7127e4b17023SJohn Marino 			 always escaped.  */
7128e4b17023SJohn Marino 		      pt->nonlocal = 1;
7129e4b17023SJohn Marino 		      pt->ipa_escaped = 1;
7130e4b17023SJohn Marino 		    }
7131e4b17023SJohn Marino 		  else
7132e4b17023SJohn Marino 		    {
7133e4b17023SJohn Marino 		      /* If there is nothing special about this call then
7134e4b17023SJohn Marino 			 we have made everything that is used also escape.  */
7135e4b17023SJohn Marino 		      *pt = ipa_escaped_pt;
7136e4b17023SJohn Marino 		      pt->nonlocal = 1;
7137e4b17023SJohn Marino 		    }
7138e4b17023SJohn Marino 		}
7139e4b17023SJohn Marino 
7140e4b17023SJohn Marino 	      /* Handle indirect calls.  */
7141e4b17023SJohn Marino 	      if (!decl
7142e4b17023SJohn Marino 		  && (fi = get_fi_for_callee (stmt)))
7143e4b17023SJohn Marino 		{
7144e4b17023SJohn Marino 		  /* We need to accumulate all clobbers/uses of all possible
7145e4b17023SJohn Marino 		     callees.  */
7146e4b17023SJohn Marino 		  fi = get_varinfo (find (fi->id));
7147e4b17023SJohn Marino 		  /* If we cannot constrain the set of functions we'll end up
7148e4b17023SJohn Marino 		     calling we end up using/clobbering everything.  */
7149e4b17023SJohn Marino 		  if (bitmap_bit_p (fi->solution, anything_id)
7150e4b17023SJohn Marino 		      || bitmap_bit_p (fi->solution, nonlocal_id)
7151e4b17023SJohn Marino 		      || bitmap_bit_p (fi->solution, escaped_id))
7152e4b17023SJohn Marino 		    {
7153e4b17023SJohn Marino 		      pt_solution_reset (gimple_call_clobber_set (stmt));
7154e4b17023SJohn Marino 		      pt_solution_reset (gimple_call_use_set (stmt));
7155e4b17023SJohn Marino 		    }
7156e4b17023SJohn Marino 		  else
7157e4b17023SJohn Marino 		    {
7158e4b17023SJohn Marino 		      bitmap_iterator bi;
7159e4b17023SJohn Marino 		      unsigned i;
7160e4b17023SJohn Marino 		      struct pt_solution *uses, *clobbers;
7161e4b17023SJohn Marino 
7162e4b17023SJohn Marino 		      uses = gimple_call_use_set (stmt);
7163e4b17023SJohn Marino 		      clobbers = gimple_call_clobber_set (stmt);
7164e4b17023SJohn Marino 		      memset (uses, 0, sizeof (struct pt_solution));
7165e4b17023SJohn Marino 		      memset (clobbers, 0, sizeof (struct pt_solution));
7166e4b17023SJohn Marino 		      EXECUTE_IF_SET_IN_BITMAP (fi->solution, 0, i, bi)
7167e4b17023SJohn Marino 			{
7168e4b17023SJohn Marino 			  struct pt_solution sol;
7169e4b17023SJohn Marino 
7170e4b17023SJohn Marino 			  vi = get_varinfo (i);
7171e4b17023SJohn Marino 			  if (!vi->is_fn_info)
7172e4b17023SJohn Marino 			    {
7173e4b17023SJohn Marino 			      /* ???  We could be more precise here?  */
7174e4b17023SJohn Marino 			      uses->nonlocal = 1;
7175e4b17023SJohn Marino 			      uses->ipa_escaped = 1;
7176e4b17023SJohn Marino 			      clobbers->nonlocal = 1;
7177e4b17023SJohn Marino 			      clobbers->ipa_escaped = 1;
7178e4b17023SJohn Marino 			      continue;
7179e4b17023SJohn Marino 			    }
7180e4b17023SJohn Marino 
7181e4b17023SJohn Marino 			  if (!uses->anything)
7182e4b17023SJohn Marino 			    {
7183e4b17023SJohn Marino 			      find_what_var_points_to
7184e4b17023SJohn Marino 				  (first_vi_for_offset (vi, fi_uses), &sol);
7185e4b17023SJohn Marino 			      pt_solution_ior_into (uses, &sol);
7186e4b17023SJohn Marino 			    }
7187e4b17023SJohn Marino 			  if (!clobbers->anything)
7188e4b17023SJohn Marino 			    {
7189e4b17023SJohn Marino 			      find_what_var_points_to
7190e4b17023SJohn Marino 				  (first_vi_for_offset (vi, fi_clobbers), &sol);
7191e4b17023SJohn Marino 			      pt_solution_ior_into (clobbers, &sol);
7192e4b17023SJohn Marino 			    }
7193e4b17023SJohn Marino 			}
7194e4b17023SJohn Marino 		    }
7195e4b17023SJohn Marino 		}
7196e4b17023SJohn Marino 	    }
7197e4b17023SJohn Marino 	}
7198e4b17023SJohn Marino 
7199e4b17023SJohn Marino       fn->gimple_df->ipa_pta = true;
7200e4b17023SJohn Marino     }
7201e4b17023SJohn Marino 
7202e4b17023SJohn Marino   delete_points_to_sets ();
7203e4b17023SJohn Marino 
7204e4b17023SJohn Marino   in_ipa_mode = 0;
7205e4b17023SJohn Marino 
7206e4b17023SJohn Marino   return 0;
7207e4b17023SJohn Marino }
7208e4b17023SJohn Marino 
7209e4b17023SJohn Marino struct simple_ipa_opt_pass pass_ipa_pta =
7210e4b17023SJohn Marino {
7211e4b17023SJohn Marino  {
7212e4b17023SJohn Marino   SIMPLE_IPA_PASS,
7213e4b17023SJohn Marino   "pta",		                /* name */
7214e4b17023SJohn Marino   gate_ipa_pta,			/* gate */
7215e4b17023SJohn Marino   ipa_pta_execute,			/* execute */
7216e4b17023SJohn Marino   NULL,					/* sub */
7217e4b17023SJohn Marino   NULL,					/* next */
7218e4b17023SJohn Marino   0,					/* static_pass_number */
7219e4b17023SJohn Marino   TV_IPA_PTA,		        /* tv_id */
7220e4b17023SJohn Marino   0,	                                /* properties_required */
7221e4b17023SJohn Marino   0,					/* properties_provided */
7222e4b17023SJohn Marino   0,					/* properties_destroyed */
7223e4b17023SJohn Marino   0,					/* todo_flags_start */
7224e4b17023SJohn Marino   TODO_update_ssa                       /* todo_flags_finish */
7225e4b17023SJohn Marino  }
7226e4b17023SJohn Marino };
7227