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