138fd1498Szrj /* Tree based points-to analysis
238fd1498Szrj Copyright (C) 2005-2018 Free Software Foundation, Inc.
338fd1498Szrj Contributed by Daniel Berlin <dberlin@dberlin.org>
438fd1498Szrj
538fd1498Szrj This file is part of GCC.
638fd1498Szrj
738fd1498Szrj GCC is free software; you can redistribute it and/or modify
838fd1498Szrj under the terms of the GNU General Public License as published by
938fd1498Szrj the Free Software Foundation; either version 3 of the License, or
1038fd1498Szrj (at your option) any later version.
1138fd1498Szrj
1238fd1498Szrj GCC is distributed in the hope that it will be useful,
1338fd1498Szrj but WITHOUT ANY WARRANTY; without even the implied warranty of
1438fd1498Szrj MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1538fd1498Szrj GNU General Public License for more details.
1638fd1498Szrj
1738fd1498Szrj You should have received a copy of the GNU General Public License
1838fd1498Szrj along with GCC; see the file COPYING3. If not see
1938fd1498Szrj <http://www.gnu.org/licenses/>. */
2038fd1498Szrj
2138fd1498Szrj #include "config.h"
2238fd1498Szrj #include "system.h"
2338fd1498Szrj #include "coretypes.h"
2438fd1498Szrj #include "backend.h"
2538fd1498Szrj #include "rtl.h"
2638fd1498Szrj #include "tree.h"
2738fd1498Szrj #include "gimple.h"
2838fd1498Szrj #include "alloc-pool.h"
2938fd1498Szrj #include "tree-pass.h"
3038fd1498Szrj #include "ssa.h"
3138fd1498Szrj #include "cgraph.h"
3238fd1498Szrj #include "tree-pretty-print.h"
3338fd1498Szrj #include "diagnostic-core.h"
3438fd1498Szrj #include "fold-const.h"
3538fd1498Szrj #include "stor-layout.h"
3638fd1498Szrj #include "stmt.h"
3738fd1498Szrj #include "gimple-iterator.h"
3838fd1498Szrj #include "tree-into-ssa.h"
3938fd1498Szrj #include "tree-dfa.h"
4038fd1498Szrj #include "params.h"
4138fd1498Szrj #include "gimple-walk.h"
4238fd1498Szrj #include "varasm.h"
4338fd1498Szrj #include "stringpool.h"
4438fd1498Szrj #include "attribs.h"
4538fd1498Szrj
4638fd1498Szrj /* The idea behind this analyzer is to generate set constraints from the
4738fd1498Szrj program, then solve the resulting constraints in order to generate the
4838fd1498Szrj points-to sets.
4938fd1498Szrj
5038fd1498Szrj Set constraints are a way of modeling program analysis problems that
5138fd1498Szrj involve sets. They consist of an inclusion constraint language,
5238fd1498Szrj describing the variables (each variable is a set) and operations that
5338fd1498Szrj are involved on the variables, and a set of rules that derive facts
5438fd1498Szrj from these operations. To solve a system of set constraints, you derive
5538fd1498Szrj all possible facts under the rules, which gives you the correct sets
5638fd1498Szrj as a consequence.
5738fd1498Szrj
5838fd1498Szrj See "Efficient Field-sensitive pointer analysis for C" by "David
5938fd1498Szrj J. Pearce and Paul H. J. Kelly and Chris Hankin, at
6038fd1498Szrj http://citeseer.ist.psu.edu/pearce04efficient.html
6138fd1498Szrj
6238fd1498Szrj Also see "Ultra-fast Aliasing Analysis using CLA: A Million Lines
6338fd1498Szrj of C Code in a Second" by ""Nevin Heintze and Olivier Tardieu" at
6438fd1498Szrj http://citeseer.ist.psu.edu/heintze01ultrafast.html
6538fd1498Szrj
6638fd1498Szrj There are three types of real constraint expressions, DEREF,
6738fd1498Szrj ADDRESSOF, and SCALAR. Each constraint expression consists
6838fd1498Szrj of a constraint type, a variable, and an offset.
6938fd1498Szrj
7038fd1498Szrj SCALAR is a constraint expression type used to represent x, whether
7138fd1498Szrj it appears on the LHS or the RHS of a statement.
7238fd1498Szrj DEREF is a constraint expression type used to represent *x, whether
7338fd1498Szrj it appears on the LHS or the RHS of a statement.
7438fd1498Szrj ADDRESSOF is a constraint expression used to represent &x, whether
7538fd1498Szrj it appears on the LHS or the RHS of a statement.
7638fd1498Szrj
7738fd1498Szrj Each pointer variable in the program is assigned an integer id, and
7838fd1498Szrj each field of a structure variable is assigned an integer id as well.
7938fd1498Szrj
8038fd1498Szrj Structure variables are linked to their list of fields through a "next
8138fd1498Szrj field" in each variable that points to the next field in offset
8238fd1498Szrj order.
8338fd1498Szrj Each variable for a structure field has
8438fd1498Szrj
8538fd1498Szrj 1. "size", that tells the size in bits of that field.
8638fd1498Szrj 2. "fullsize, that tells the size in bits of the entire structure.
8738fd1498Szrj 3. "offset", that tells the offset in bits from the beginning of the
8838fd1498Szrj structure to this field.
8938fd1498Szrj
9038fd1498Szrj Thus,
9138fd1498Szrj struct f
9238fd1498Szrj {
9338fd1498Szrj int a;
9438fd1498Szrj int b;
9538fd1498Szrj } foo;
9638fd1498Szrj int *bar;
9738fd1498Szrj
9838fd1498Szrj looks like
9938fd1498Szrj
10038fd1498Szrj foo.a -> id 1, size 32, offset 0, fullsize 64, next foo.b
10138fd1498Szrj foo.b -> id 2, size 32, offset 32, fullsize 64, next NULL
10238fd1498Szrj bar -> id 3, size 32, offset 0, fullsize 32, next NULL
10338fd1498Szrj
10438fd1498Szrj
10538fd1498Szrj In order to solve the system of set constraints, the following is
10638fd1498Szrj done:
10738fd1498Szrj
10838fd1498Szrj 1. Each constraint variable x has a solution set associated with it,
10938fd1498Szrj Sol(x).
11038fd1498Szrj
11138fd1498Szrj 2. Constraints are separated into direct, copy, and complex.
11238fd1498Szrj Direct constraints are ADDRESSOF constraints that require no extra
11338fd1498Szrj processing, such as P = &Q
11438fd1498Szrj Copy constraints are those of the form P = Q.
11538fd1498Szrj Complex constraints are all the constraints involving dereferences
11638fd1498Szrj and offsets (including offsetted copies).
11738fd1498Szrj
11838fd1498Szrj 3. All direct constraints of the form P = &Q are processed, such
11938fd1498Szrj that Q is added to Sol(P)
12038fd1498Szrj
12138fd1498Szrj 4. All complex constraints for a given constraint variable are stored in a
12238fd1498Szrj linked list attached to that variable's node.
12338fd1498Szrj
12438fd1498Szrj 5. A directed graph is built out of the copy constraints. Each
12538fd1498Szrj constraint variable is a node in the graph, and an edge from
12638fd1498Szrj Q to P is added for each copy constraint of the form P = Q
12738fd1498Szrj
12838fd1498Szrj 6. The graph is then walked, and solution sets are
12938fd1498Szrj propagated along the copy edges, such that an edge from Q to P
13038fd1498Szrj causes Sol(P) <- Sol(P) union Sol(Q).
13138fd1498Szrj
13238fd1498Szrj 7. As we visit each node, all complex constraints associated with
13338fd1498Szrj that node are processed by adding appropriate copy edges to the graph, or the
13438fd1498Szrj appropriate variables to the solution set.
13538fd1498Szrj
13638fd1498Szrj 8. The process of walking the graph is iterated until no solution
13738fd1498Szrj sets change.
13838fd1498Szrj
13938fd1498Szrj Prior to walking the graph in steps 6 and 7, We perform static
14038fd1498Szrj cycle elimination on the constraint graph, as well
14138fd1498Szrj as off-line variable substitution.
14238fd1498Szrj
14338fd1498Szrj TODO: Adding offsets to pointer-to-structures can be handled (IE not punted
14438fd1498Szrj on and turned into anything), but isn't. You can just see what offset
14538fd1498Szrj inside the pointed-to struct it's going to access.
14638fd1498Szrj
14738fd1498Szrj TODO: Constant bounded arrays can be handled as if they were structs of the
14838fd1498Szrj same number of elements.
14938fd1498Szrj
15038fd1498Szrj TODO: Modeling heap and incoming pointers becomes much better if we
15138fd1498Szrj add fields to them as we discover them, which we could do.
15238fd1498Szrj
15338fd1498Szrj TODO: We could handle unions, but to be honest, it's probably not
15438fd1498Szrj worth the pain or slowdown. */
15538fd1498Szrj
15638fd1498Szrj /* IPA-PTA optimizations possible.
15738fd1498Szrj
15838fd1498Szrj When the indirect function called is ANYTHING we can add disambiguation
15938fd1498Szrj based on the function signatures (or simply the parameter count which
16038fd1498Szrj is the varinfo size). We also do not need to consider functions that
16138fd1498Szrj do not have their address taken.
16238fd1498Szrj
16338fd1498Szrj The is_global_var bit which marks escape points is overly conservative
16438fd1498Szrj in IPA mode. Split it to is_escape_point and is_global_var - only
16538fd1498Szrj externally visible globals are escape points in IPA mode.
16638fd1498Szrj There is now is_ipa_escape_point but this is only used in a few
16738fd1498Szrj selected places.
16838fd1498Szrj
16938fd1498Szrj The way we introduce DECL_PT_UID to avoid fixing up all points-to
17038fd1498Szrj sets in the translation unit when we copy a DECL during inlining
17138fd1498Szrj pessimizes precision. The advantage is that the DECL_PT_UID keeps
17238fd1498Szrj compile-time and memory usage overhead low - the points-to sets
17338fd1498Szrj do not grow or get unshared as they would during a fixup phase.
17438fd1498Szrj An alternative solution is to delay IPA PTA until after all
17538fd1498Szrj inlining transformations have been applied.
17638fd1498Szrj
17738fd1498Szrj The way we propagate clobber/use information isn't optimized.
17838fd1498Szrj It should use a new complex constraint that properly filters
17938fd1498Szrj out local variables of the callee (though that would make
18038fd1498Szrj the sets invalid after inlining). OTOH we might as well
18138fd1498Szrj admit defeat to WHOPR and simply do all the clobber/use analysis
18238fd1498Szrj and propagation after PTA finished but before we threw away
18338fd1498Szrj points-to information for memory variables. WHOPR and PTA
18438fd1498Szrj do not play along well anyway - the whole constraint solving
18538fd1498Szrj would need to be done in WPA phase and it will be very interesting
18638fd1498Szrj to apply the results to local SSA names during LTRANS phase.
18738fd1498Szrj
18838fd1498Szrj We probably should compute a per-function unit-ESCAPE solution
18938fd1498Szrj propagating it simply like the clobber / uses solutions. The
19038fd1498Szrj solution can go alongside the non-IPA espaced solution and be
19138fd1498Szrj used to query which vars escape the unit through a function.
19238fd1498Szrj This is also required to make the escaped-HEAP trick work in IPA mode.
19338fd1498Szrj
19438fd1498Szrj We never put function decls in points-to sets so we do not
19538fd1498Szrj keep the set of called functions for indirect calls.
19638fd1498Szrj
19738fd1498Szrj And probably more. */
19838fd1498Szrj
19938fd1498Szrj static bool use_field_sensitive = true;
20038fd1498Szrj static int in_ipa_mode = 0;
20138fd1498Szrj
20238fd1498Szrj /* Used for predecessor bitmaps. */
20338fd1498Szrj static bitmap_obstack predbitmap_obstack;
20438fd1498Szrj
20538fd1498Szrj /* Used for points-to sets. */
20638fd1498Szrj static bitmap_obstack pta_obstack;
20738fd1498Szrj
20838fd1498Szrj /* Used for oldsolution members of variables. */
20938fd1498Szrj static bitmap_obstack oldpta_obstack;
21038fd1498Szrj
21138fd1498Szrj /* Used for per-solver-iteration bitmaps. */
21238fd1498Szrj static bitmap_obstack iteration_obstack;
21338fd1498Szrj
21438fd1498Szrj static unsigned int create_variable_info_for (tree, const char *, bool);
21538fd1498Szrj typedef struct constraint_graph *constraint_graph_t;
21638fd1498Szrj static void unify_nodes (constraint_graph_t, unsigned int, unsigned int, bool);
21738fd1498Szrj
21838fd1498Szrj struct constraint;
21938fd1498Szrj typedef struct constraint *constraint_t;
22038fd1498Szrj
22138fd1498Szrj
22238fd1498Szrj #define EXECUTE_IF_IN_NONNULL_BITMAP(a, b, c, d) \
22338fd1498Szrj if (a) \
22438fd1498Szrj EXECUTE_IF_SET_IN_BITMAP (a, b, c, d)
22538fd1498Szrj
22638fd1498Szrj static struct constraint_stats
22738fd1498Szrj {
22838fd1498Szrj unsigned int total_vars;
22938fd1498Szrj unsigned int nonpointer_vars;
23038fd1498Szrj unsigned int unified_vars_static;
23138fd1498Szrj unsigned int unified_vars_dynamic;
23238fd1498Szrj unsigned int iterations;
23338fd1498Szrj unsigned int num_edges;
23438fd1498Szrj unsigned int num_implicit_edges;
23538fd1498Szrj unsigned int points_to_sets_created;
23638fd1498Szrj } stats;
23738fd1498Szrj
23838fd1498Szrj struct variable_info
23938fd1498Szrj {
24038fd1498Szrj /* ID of this variable */
24138fd1498Szrj unsigned int id;
24238fd1498Szrj
24338fd1498Szrj /* True if this is a variable created by the constraint analysis, such as
24438fd1498Szrj heap variables and constraints we had to break up. */
24538fd1498Szrj unsigned int is_artificial_var : 1;
24638fd1498Szrj
24738fd1498Szrj /* True if this is a special variable whose solution set should not be
24838fd1498Szrj changed. */
24938fd1498Szrj unsigned int is_special_var : 1;
25038fd1498Szrj
25138fd1498Szrj /* True for variables whose size is not known or variable. */
25238fd1498Szrj unsigned int is_unknown_size_var : 1;
25338fd1498Szrj
25438fd1498Szrj /* True for (sub-)fields that represent a whole variable. */
25538fd1498Szrj unsigned int is_full_var : 1;
25638fd1498Szrj
25738fd1498Szrj /* True if this is a heap variable. */
25838fd1498Szrj unsigned int is_heap_var : 1;
25938fd1498Szrj
26038fd1498Szrj /* True if this is a register variable. */
26138fd1498Szrj unsigned int is_reg_var : 1;
26238fd1498Szrj
26338fd1498Szrj /* True if this field may contain pointers. */
26438fd1498Szrj unsigned int may_have_pointers : 1;
26538fd1498Szrj
26638fd1498Szrj /* True if this field has only restrict qualified pointers. */
26738fd1498Szrj unsigned int only_restrict_pointers : 1;
26838fd1498Szrj
26938fd1498Szrj /* True if this represents a heap var created for a restrict qualified
27038fd1498Szrj pointer. */
27138fd1498Szrj unsigned int is_restrict_var : 1;
27238fd1498Szrj
27338fd1498Szrj /* True if this represents a global variable. */
27438fd1498Szrj unsigned int is_global_var : 1;
27538fd1498Szrj
27638fd1498Szrj /* True if this represents a module escape point for IPA analysis. */
27738fd1498Szrj unsigned int is_ipa_escape_point : 1;
27838fd1498Szrj
27938fd1498Szrj /* True if this represents a IPA function info. */
28038fd1498Szrj unsigned int is_fn_info : 1;
28138fd1498Szrj
28238fd1498Szrj /* ??? Store somewhere better. */
28338fd1498Szrj unsigned short ruid;
28438fd1498Szrj
28538fd1498Szrj /* The ID of the variable for the next field in this structure
28638fd1498Szrj or zero for the last field in this structure. */
28738fd1498Szrj unsigned next;
28838fd1498Szrj
28938fd1498Szrj /* The ID of the variable for the first field in this structure. */
29038fd1498Szrj unsigned head;
29138fd1498Szrj
29238fd1498Szrj /* Offset of this variable, in bits, from the base variable */
29338fd1498Szrj unsigned HOST_WIDE_INT offset;
29438fd1498Szrj
29538fd1498Szrj /* Size of the variable, in bits. */
29638fd1498Szrj unsigned HOST_WIDE_INT size;
29738fd1498Szrj
29838fd1498Szrj /* Full size of the base variable, in bits. */
29938fd1498Szrj unsigned HOST_WIDE_INT fullsize;
30038fd1498Szrj
30138fd1498Szrj /* Name of this variable */
30238fd1498Szrj const char *name;
30338fd1498Szrj
30438fd1498Szrj /* Tree that this variable is associated with. */
30538fd1498Szrj tree decl;
30638fd1498Szrj
30738fd1498Szrj /* Points-to set for this variable. */
30838fd1498Szrj bitmap solution;
30938fd1498Szrj
31038fd1498Szrj /* Old points-to set for this variable. */
31138fd1498Szrj bitmap oldsolution;
31238fd1498Szrj };
31338fd1498Szrj typedef struct variable_info *varinfo_t;
31438fd1498Szrj
31538fd1498Szrj static varinfo_t first_vi_for_offset (varinfo_t, unsigned HOST_WIDE_INT);
31638fd1498Szrj static varinfo_t first_or_preceding_vi_for_offset (varinfo_t,
31738fd1498Szrj unsigned HOST_WIDE_INT);
31838fd1498Szrj static varinfo_t lookup_vi_for_tree (tree);
31938fd1498Szrj static inline bool type_can_have_subvars (const_tree);
32038fd1498Szrj static void make_param_constraints (varinfo_t);
32138fd1498Szrj
32238fd1498Szrj /* Pool of variable info structures. */
32338fd1498Szrj static object_allocator<variable_info> variable_info_pool
32438fd1498Szrj ("Variable info pool");
32538fd1498Szrj
32638fd1498Szrj /* Map varinfo to final pt_solution. */
32738fd1498Szrj static hash_map<varinfo_t, pt_solution *> *final_solutions;
32838fd1498Szrj struct obstack final_solutions_obstack;
32938fd1498Szrj
33038fd1498Szrj /* Table of variable info structures for constraint variables.
33138fd1498Szrj Indexed directly by variable info id. */
33238fd1498Szrj static vec<varinfo_t> varmap;
33338fd1498Szrj
33438fd1498Szrj /* Return the varmap element N */
33538fd1498Szrj
33638fd1498Szrj static inline varinfo_t
get_varinfo(unsigned int n)33738fd1498Szrj get_varinfo (unsigned int n)
33838fd1498Szrj {
33938fd1498Szrj return varmap[n];
34038fd1498Szrj }
34138fd1498Szrj
34238fd1498Szrj /* Return the next variable in the list of sub-variables of VI
34338fd1498Szrj or NULL if VI is the last sub-variable. */
34438fd1498Szrj
34538fd1498Szrj static inline varinfo_t
vi_next(varinfo_t vi)34638fd1498Szrj vi_next (varinfo_t vi)
34738fd1498Szrj {
34838fd1498Szrj return get_varinfo (vi->next);
34938fd1498Szrj }
35038fd1498Szrj
35138fd1498Szrj /* Static IDs for the special variables. Variable ID zero is unused
35238fd1498Szrj and used as terminator for the sub-variable chain. */
35338fd1498Szrj enum { nothing_id = 1, anything_id = 2, string_id = 3,
35438fd1498Szrj escaped_id = 4, nonlocal_id = 5,
35538fd1498Szrj storedanything_id = 6, integer_id = 7 };
35638fd1498Szrj
35738fd1498Szrj /* Return a new variable info structure consisting for a variable
35838fd1498Szrj named NAME, and using constraint graph node NODE. Append it
35938fd1498Szrj to the vector of variable info structures. */
36038fd1498Szrj
36138fd1498Szrj static varinfo_t
new_var_info(tree t,const char * name,bool add_id)36238fd1498Szrj new_var_info (tree t, const char *name, bool add_id)
36338fd1498Szrj {
36438fd1498Szrj unsigned index = varmap.length ();
36538fd1498Szrj varinfo_t ret = variable_info_pool.allocate ();
36638fd1498Szrj
36738fd1498Szrj if (dump_file && add_id)
36838fd1498Szrj {
36938fd1498Szrj char *tempname = xasprintf ("%s(%d)", name, index);
37038fd1498Szrj name = ggc_strdup (tempname);
37138fd1498Szrj free (tempname);
37238fd1498Szrj }
37338fd1498Szrj
37438fd1498Szrj ret->id = index;
37538fd1498Szrj ret->name = name;
37638fd1498Szrj ret->decl = t;
37738fd1498Szrj /* Vars without decl are artificial and do not have sub-variables. */
37838fd1498Szrj ret->is_artificial_var = (t == NULL_TREE);
37938fd1498Szrj ret->is_special_var = false;
38038fd1498Szrj ret->is_unknown_size_var = false;
38138fd1498Szrj ret->is_full_var = (t == NULL_TREE);
38238fd1498Szrj ret->is_heap_var = false;
38338fd1498Szrj ret->may_have_pointers = true;
38438fd1498Szrj ret->only_restrict_pointers = false;
38538fd1498Szrj ret->is_restrict_var = false;
38638fd1498Szrj ret->ruid = 0;
38738fd1498Szrj ret->is_global_var = (t == NULL_TREE);
38838fd1498Szrj ret->is_ipa_escape_point = false;
38938fd1498Szrj ret->is_fn_info = false;
39038fd1498Szrj if (t && DECL_P (t))
39138fd1498Szrj ret->is_global_var = (is_global_var (t)
39238fd1498Szrj /* We have to treat even local register variables
39338fd1498Szrj as escape points. */
39438fd1498Szrj || (VAR_P (t) && DECL_HARD_REGISTER (t)));
39538fd1498Szrj ret->is_reg_var = (t && TREE_CODE (t) == SSA_NAME);
39638fd1498Szrj ret->solution = BITMAP_ALLOC (&pta_obstack);
39738fd1498Szrj ret->oldsolution = NULL;
39838fd1498Szrj ret->next = 0;
39938fd1498Szrj ret->head = ret->id;
40038fd1498Szrj
40138fd1498Szrj stats.total_vars++;
40238fd1498Szrj
40338fd1498Szrj varmap.safe_push (ret);
40438fd1498Szrj
40538fd1498Szrj return ret;
40638fd1498Szrj }
40738fd1498Szrj
40838fd1498Szrj /* A map mapping call statements to per-stmt variables for uses
40938fd1498Szrj and clobbers specific to the call. */
41038fd1498Szrj static hash_map<gimple *, varinfo_t> *call_stmt_vars;
41138fd1498Szrj
41238fd1498Szrj /* Lookup or create the variable for the call statement CALL. */
41338fd1498Szrj
41438fd1498Szrj static varinfo_t
get_call_vi(gcall * call)41538fd1498Szrj get_call_vi (gcall *call)
41638fd1498Szrj {
41738fd1498Szrj varinfo_t vi, vi2;
41838fd1498Szrj
41938fd1498Szrj bool existed;
42038fd1498Szrj varinfo_t *slot_p = &call_stmt_vars->get_or_insert (call, &existed);
42138fd1498Szrj if (existed)
42238fd1498Szrj return *slot_p;
42338fd1498Szrj
42438fd1498Szrj vi = new_var_info (NULL_TREE, "CALLUSED", true);
42538fd1498Szrj vi->offset = 0;
42638fd1498Szrj vi->size = 1;
42738fd1498Szrj vi->fullsize = 2;
42838fd1498Szrj vi->is_full_var = true;
42938fd1498Szrj vi->is_reg_var = true;
43038fd1498Szrj
43138fd1498Szrj vi2 = new_var_info (NULL_TREE, "CALLCLOBBERED", true);
43238fd1498Szrj vi2->offset = 1;
43338fd1498Szrj vi2->size = 1;
43438fd1498Szrj vi2->fullsize = 2;
43538fd1498Szrj vi2->is_full_var = true;
43638fd1498Szrj vi2->is_reg_var = true;
43738fd1498Szrj
43838fd1498Szrj vi->next = vi2->id;
43938fd1498Szrj
44038fd1498Szrj *slot_p = vi;
44138fd1498Szrj return vi;
44238fd1498Szrj }
44338fd1498Szrj
44438fd1498Szrj /* Lookup the variable for the call statement CALL representing
44538fd1498Szrj the uses. Returns NULL if there is nothing special about this call. */
44638fd1498Szrj
44738fd1498Szrj static varinfo_t
lookup_call_use_vi(gcall * call)44838fd1498Szrj lookup_call_use_vi (gcall *call)
44938fd1498Szrj {
45038fd1498Szrj varinfo_t *slot_p = call_stmt_vars->get (call);
45138fd1498Szrj if (slot_p)
45238fd1498Szrj return *slot_p;
45338fd1498Szrj
45438fd1498Szrj return NULL;
45538fd1498Szrj }
45638fd1498Szrj
45738fd1498Szrj /* Lookup the variable for the call statement CALL representing
45838fd1498Szrj the clobbers. Returns NULL if there is nothing special about this call. */
45938fd1498Szrj
46038fd1498Szrj static varinfo_t
lookup_call_clobber_vi(gcall * call)46138fd1498Szrj lookup_call_clobber_vi (gcall *call)
46238fd1498Szrj {
46338fd1498Szrj varinfo_t uses = lookup_call_use_vi (call);
46438fd1498Szrj if (!uses)
46538fd1498Szrj return NULL;
46638fd1498Szrj
46738fd1498Szrj return vi_next (uses);
46838fd1498Szrj }
46938fd1498Szrj
47038fd1498Szrj /* Lookup or create the variable for the call statement CALL representing
47138fd1498Szrj the uses. */
47238fd1498Szrj
47338fd1498Szrj static varinfo_t
get_call_use_vi(gcall * call)47438fd1498Szrj get_call_use_vi (gcall *call)
47538fd1498Szrj {
47638fd1498Szrj return get_call_vi (call);
47738fd1498Szrj }
47838fd1498Szrj
47938fd1498Szrj /* Lookup or create the variable for the call statement CALL representing
48038fd1498Szrj the clobbers. */
48138fd1498Szrj
48238fd1498Szrj static varinfo_t ATTRIBUTE_UNUSED
get_call_clobber_vi(gcall * call)48338fd1498Szrj get_call_clobber_vi (gcall *call)
48438fd1498Szrj {
48538fd1498Szrj return vi_next (get_call_vi (call));
48638fd1498Szrj }
48738fd1498Szrj
48838fd1498Szrj
48938fd1498Szrj enum constraint_expr_type {SCALAR, DEREF, ADDRESSOF};
49038fd1498Szrj
49138fd1498Szrj /* An expression that appears in a constraint. */
49238fd1498Szrj
49338fd1498Szrj struct constraint_expr
49438fd1498Szrj {
49538fd1498Szrj /* Constraint type. */
49638fd1498Szrj constraint_expr_type type;
49738fd1498Szrj
49838fd1498Szrj /* Variable we are referring to in the constraint. */
49938fd1498Szrj unsigned int var;
50038fd1498Szrj
50138fd1498Szrj /* Offset, in bits, of this constraint from the beginning of
50238fd1498Szrj variables it ends up referring to.
50338fd1498Szrj
50438fd1498Szrj IOW, in a deref constraint, we would deref, get the result set,
50538fd1498Szrj then add OFFSET to each member. */
50638fd1498Szrj HOST_WIDE_INT offset;
50738fd1498Szrj };
50838fd1498Szrj
50938fd1498Szrj /* Use 0x8000... as special unknown offset. */
51038fd1498Szrj #define UNKNOWN_OFFSET HOST_WIDE_INT_MIN
51138fd1498Szrj
51238fd1498Szrj typedef struct constraint_expr ce_s;
51338fd1498Szrj static void get_constraint_for_1 (tree, vec<ce_s> *, bool, bool);
51438fd1498Szrj static void get_constraint_for (tree, vec<ce_s> *);
51538fd1498Szrj static void get_constraint_for_rhs (tree, vec<ce_s> *);
51638fd1498Szrj static void do_deref (vec<ce_s> *);
51738fd1498Szrj
51838fd1498Szrj /* Our set constraints are made up of two constraint expressions, one
51938fd1498Szrj LHS, and one RHS.
52038fd1498Szrj
52138fd1498Szrj As described in the introduction, our set constraints each represent an
52238fd1498Szrj operation between set valued variables.
52338fd1498Szrj */
52438fd1498Szrj struct constraint
52538fd1498Szrj {
52638fd1498Szrj struct constraint_expr lhs;
52738fd1498Szrj struct constraint_expr rhs;
52838fd1498Szrj };
52938fd1498Szrj
53038fd1498Szrj /* List of constraints that we use to build the constraint graph from. */
53138fd1498Szrj
53238fd1498Szrj static vec<constraint_t> constraints;
53338fd1498Szrj static object_allocator<constraint> constraint_pool ("Constraint pool");
53438fd1498Szrj
53538fd1498Szrj /* The constraint graph is represented as an array of bitmaps
53638fd1498Szrj containing successor nodes. */
53738fd1498Szrj
53838fd1498Szrj struct constraint_graph
53938fd1498Szrj {
54038fd1498Szrj /* Size of this graph, which may be different than the number of
54138fd1498Szrj nodes in the variable map. */
54238fd1498Szrj unsigned int size;
54338fd1498Szrj
54438fd1498Szrj /* Explicit successors of each node. */
54538fd1498Szrj bitmap *succs;
54638fd1498Szrj
54738fd1498Szrj /* Implicit predecessors of each node (Used for variable
54838fd1498Szrj substitution). */
54938fd1498Szrj bitmap *implicit_preds;
55038fd1498Szrj
55138fd1498Szrj /* Explicit predecessors of each node (Used for variable substitution). */
55238fd1498Szrj bitmap *preds;
55338fd1498Szrj
55438fd1498Szrj /* Indirect cycle representatives, or -1 if the node has no indirect
55538fd1498Szrj cycles. */
55638fd1498Szrj int *indirect_cycles;
55738fd1498Szrj
55838fd1498Szrj /* Representative node for a node. rep[a] == a unless the node has
55938fd1498Szrj been unified. */
56038fd1498Szrj unsigned int *rep;
56138fd1498Szrj
56238fd1498Szrj /* Equivalence class representative for a label. This is used for
56338fd1498Szrj variable substitution. */
56438fd1498Szrj int *eq_rep;
56538fd1498Szrj
56638fd1498Szrj /* Pointer equivalence label for a node. All nodes with the same
56738fd1498Szrj pointer equivalence label can be unified together at some point
56838fd1498Szrj (either during constraint optimization or after the constraint
56938fd1498Szrj graph is built). */
57038fd1498Szrj unsigned int *pe;
57138fd1498Szrj
57238fd1498Szrj /* Pointer equivalence representative for a label. This is used to
57338fd1498Szrj handle nodes that are pointer equivalent but not location
57438fd1498Szrj equivalent. We can unite these once the addressof constraints
57538fd1498Szrj are transformed into initial points-to sets. */
57638fd1498Szrj int *pe_rep;
57738fd1498Szrj
57838fd1498Szrj /* Pointer equivalence label for each node, used during variable
57938fd1498Szrj substitution. */
58038fd1498Szrj unsigned int *pointer_label;
58138fd1498Szrj
58238fd1498Szrj /* Location equivalence label for each node, used during location
58338fd1498Szrj equivalence finding. */
58438fd1498Szrj unsigned int *loc_label;
58538fd1498Szrj
58638fd1498Szrj /* Pointed-by set for each node, used during location equivalence
58738fd1498Szrj finding. This is pointed-by rather than pointed-to, because it
58838fd1498Szrj is constructed using the predecessor graph. */
58938fd1498Szrj bitmap *pointed_by;
59038fd1498Szrj
59138fd1498Szrj /* Points to sets for pointer equivalence. This is *not* the actual
59238fd1498Szrj points-to sets for nodes. */
59338fd1498Szrj bitmap *points_to;
59438fd1498Szrj
59538fd1498Szrj /* Bitmap of nodes where the bit is set if the node is a direct
59638fd1498Szrj node. Used for variable substitution. */
59738fd1498Szrj sbitmap direct_nodes;
59838fd1498Szrj
59938fd1498Szrj /* Bitmap of nodes where the bit is set if the node is address
60038fd1498Szrj taken. Used for variable substitution. */
60138fd1498Szrj bitmap address_taken;
60238fd1498Szrj
60338fd1498Szrj /* Vector of complex constraints for each graph node. Complex
60438fd1498Szrj constraints are those involving dereferences or offsets that are
60538fd1498Szrj not 0. */
60638fd1498Szrj vec<constraint_t> *complex;
60738fd1498Szrj };
60838fd1498Szrj
60938fd1498Szrj static constraint_graph_t graph;
61038fd1498Szrj
61138fd1498Szrj /* During variable substitution and the offline version of indirect
61238fd1498Szrj cycle finding, we create nodes to represent dereferences and
61338fd1498Szrj address taken constraints. These represent where these start and
61438fd1498Szrj end. */
61538fd1498Szrj #define FIRST_REF_NODE (varmap).length ()
61638fd1498Szrj #define LAST_REF_NODE (FIRST_REF_NODE + (FIRST_REF_NODE - 1))
61738fd1498Szrj
61838fd1498Szrj /* Return the representative node for NODE, if NODE has been unioned
61938fd1498Szrj with another NODE.
62038fd1498Szrj This function performs path compression along the way to finding
62138fd1498Szrj the representative. */
62238fd1498Szrj
62338fd1498Szrj static unsigned int
find(unsigned int node)62438fd1498Szrj find (unsigned int node)
62538fd1498Szrj {
62638fd1498Szrj gcc_checking_assert (node < graph->size);
62738fd1498Szrj if (graph->rep[node] != node)
62838fd1498Szrj return graph->rep[node] = find (graph->rep[node]);
62938fd1498Szrj return node;
63038fd1498Szrj }
63138fd1498Szrj
63238fd1498Szrj /* Union the TO and FROM nodes to the TO nodes.
63338fd1498Szrj Note that at some point in the future, we may want to do
63438fd1498Szrj union-by-rank, in which case we are going to have to return the
63538fd1498Szrj node we unified to. */
63638fd1498Szrj
63738fd1498Szrj static bool
unite(unsigned int to,unsigned int from)63838fd1498Szrj unite (unsigned int to, unsigned int from)
63938fd1498Szrj {
64038fd1498Szrj gcc_checking_assert (to < graph->size && from < graph->size);
64138fd1498Szrj if (to != from && graph->rep[from] != to)
64238fd1498Szrj {
64338fd1498Szrj graph->rep[from] = to;
64438fd1498Szrj return true;
64538fd1498Szrj }
64638fd1498Szrj return false;
64738fd1498Szrj }
64838fd1498Szrj
64938fd1498Szrj /* Create a new constraint consisting of LHS and RHS expressions. */
65038fd1498Szrj
65138fd1498Szrj static constraint_t
new_constraint(const struct constraint_expr lhs,const struct constraint_expr rhs)65238fd1498Szrj new_constraint (const struct constraint_expr lhs,
65338fd1498Szrj const struct constraint_expr rhs)
65438fd1498Szrj {
65538fd1498Szrj constraint_t ret = constraint_pool.allocate ();
65638fd1498Szrj ret->lhs = lhs;
65738fd1498Szrj ret->rhs = rhs;
65838fd1498Szrj return ret;
65938fd1498Szrj }
66038fd1498Szrj
66138fd1498Szrj /* Print out constraint C to FILE. */
66238fd1498Szrj
66338fd1498Szrj static void
dump_constraint(FILE * file,constraint_t c)66438fd1498Szrj dump_constraint (FILE *file, constraint_t c)
66538fd1498Szrj {
66638fd1498Szrj if (c->lhs.type == ADDRESSOF)
66738fd1498Szrj fprintf (file, "&");
66838fd1498Szrj else if (c->lhs.type == DEREF)
66938fd1498Szrj fprintf (file, "*");
67038fd1498Szrj fprintf (file, "%s", get_varinfo (c->lhs.var)->name);
67138fd1498Szrj if (c->lhs.offset == UNKNOWN_OFFSET)
67238fd1498Szrj fprintf (file, " + UNKNOWN");
67338fd1498Szrj else if (c->lhs.offset != 0)
67438fd1498Szrj fprintf (file, " + " HOST_WIDE_INT_PRINT_DEC, c->lhs.offset);
67538fd1498Szrj fprintf (file, " = ");
67638fd1498Szrj if (c->rhs.type == ADDRESSOF)
67738fd1498Szrj fprintf (file, "&");
67838fd1498Szrj else if (c->rhs.type == DEREF)
67938fd1498Szrj fprintf (file, "*");
68038fd1498Szrj fprintf (file, "%s", get_varinfo (c->rhs.var)->name);
68138fd1498Szrj if (c->rhs.offset == UNKNOWN_OFFSET)
68238fd1498Szrj fprintf (file, " + UNKNOWN");
68338fd1498Szrj else if (c->rhs.offset != 0)
68438fd1498Szrj fprintf (file, " + " HOST_WIDE_INT_PRINT_DEC, c->rhs.offset);
68538fd1498Szrj }
68638fd1498Szrj
68738fd1498Szrj
68838fd1498Szrj void debug_constraint (constraint_t);
68938fd1498Szrj void debug_constraints (void);
69038fd1498Szrj void debug_constraint_graph (void);
69138fd1498Szrj void debug_solution_for_var (unsigned int);
69238fd1498Szrj void debug_sa_points_to_info (void);
69338fd1498Szrj void debug_varinfo (varinfo_t);
69438fd1498Szrj void debug_varmap (void);
69538fd1498Szrj
69638fd1498Szrj /* Print out constraint C to stderr. */
69738fd1498Szrj
69838fd1498Szrj DEBUG_FUNCTION void
debug_constraint(constraint_t c)69938fd1498Szrj debug_constraint (constraint_t c)
70038fd1498Szrj {
70138fd1498Szrj dump_constraint (stderr, c);
70238fd1498Szrj fprintf (stderr, "\n");
70338fd1498Szrj }
70438fd1498Szrj
70538fd1498Szrj /* Print out all constraints to FILE */
70638fd1498Szrj
70738fd1498Szrj static void
dump_constraints(FILE * file,int from)70838fd1498Szrj dump_constraints (FILE *file, int from)
70938fd1498Szrj {
71038fd1498Szrj int i;
71138fd1498Szrj constraint_t c;
71238fd1498Szrj for (i = from; constraints.iterate (i, &c); i++)
71338fd1498Szrj if (c)
71438fd1498Szrj {
71538fd1498Szrj dump_constraint (file, c);
71638fd1498Szrj fprintf (file, "\n");
71738fd1498Szrj }
71838fd1498Szrj }
71938fd1498Szrj
72038fd1498Szrj /* Print out all constraints to stderr. */
72138fd1498Szrj
72238fd1498Szrj DEBUG_FUNCTION void
debug_constraints(void)72338fd1498Szrj debug_constraints (void)
72438fd1498Szrj {
72538fd1498Szrj dump_constraints (stderr, 0);
72638fd1498Szrj }
72738fd1498Szrj
72838fd1498Szrj /* Print the constraint graph in dot format. */
72938fd1498Szrj
73038fd1498Szrj static void
dump_constraint_graph(FILE * file)73138fd1498Szrj dump_constraint_graph (FILE *file)
73238fd1498Szrj {
73338fd1498Szrj unsigned int i;
73438fd1498Szrj
73538fd1498Szrj /* Only print the graph if it has already been initialized: */
73638fd1498Szrj if (!graph)
73738fd1498Szrj return;
73838fd1498Szrj
73938fd1498Szrj /* Prints the header of the dot file: */
74038fd1498Szrj fprintf (file, "strict digraph {\n");
74138fd1498Szrj fprintf (file, " node [\n shape = box\n ]\n");
74238fd1498Szrj fprintf (file, " edge [\n fontsize = \"12\"\n ]\n");
74338fd1498Szrj fprintf (file, "\n // List of nodes and complex constraints in "
74438fd1498Szrj "the constraint graph:\n");
74538fd1498Szrj
74638fd1498Szrj /* The next lines print the nodes in the graph together with the
74738fd1498Szrj complex constraints attached to them. */
74838fd1498Szrj for (i = 1; i < graph->size; i++)
74938fd1498Szrj {
75038fd1498Szrj if (i == FIRST_REF_NODE)
75138fd1498Szrj continue;
75238fd1498Szrj if (find (i) != i)
75338fd1498Szrj continue;
75438fd1498Szrj if (i < FIRST_REF_NODE)
75538fd1498Szrj fprintf (file, "\"%s\"", get_varinfo (i)->name);
75638fd1498Szrj else
75738fd1498Szrj fprintf (file, "\"*%s\"", get_varinfo (i - FIRST_REF_NODE)->name);
75838fd1498Szrj if (graph->complex[i].exists ())
75938fd1498Szrj {
76038fd1498Szrj unsigned j;
76138fd1498Szrj constraint_t c;
76238fd1498Szrj fprintf (file, " [label=\"\\N\\n");
76338fd1498Szrj for (j = 0; graph->complex[i].iterate (j, &c); ++j)
76438fd1498Szrj {
76538fd1498Szrj dump_constraint (file, c);
76638fd1498Szrj fprintf (file, "\\l");
76738fd1498Szrj }
76838fd1498Szrj fprintf (file, "\"]");
76938fd1498Szrj }
77038fd1498Szrj fprintf (file, ";\n");
77138fd1498Szrj }
77238fd1498Szrj
77338fd1498Szrj /* Go over the edges. */
77438fd1498Szrj fprintf (file, "\n // Edges in the constraint graph:\n");
77538fd1498Szrj for (i = 1; i < graph->size; i++)
77638fd1498Szrj {
77738fd1498Szrj unsigned j;
77838fd1498Szrj bitmap_iterator bi;
77938fd1498Szrj if (find (i) != i)
78038fd1498Szrj continue;
78138fd1498Szrj EXECUTE_IF_IN_NONNULL_BITMAP (graph->succs[i], 0, j, bi)
78238fd1498Szrj {
78338fd1498Szrj unsigned to = find (j);
78438fd1498Szrj if (i == to)
78538fd1498Szrj continue;
78638fd1498Szrj if (i < FIRST_REF_NODE)
78738fd1498Szrj fprintf (file, "\"%s\"", get_varinfo (i)->name);
78838fd1498Szrj else
78938fd1498Szrj fprintf (file, "\"*%s\"", get_varinfo (i - FIRST_REF_NODE)->name);
79038fd1498Szrj fprintf (file, " -> ");
79138fd1498Szrj if (to < FIRST_REF_NODE)
79238fd1498Szrj fprintf (file, "\"%s\"", get_varinfo (to)->name);
79338fd1498Szrj else
79438fd1498Szrj fprintf (file, "\"*%s\"", get_varinfo (to - FIRST_REF_NODE)->name);
79538fd1498Szrj fprintf (file, ";\n");
79638fd1498Szrj }
79738fd1498Szrj }
79838fd1498Szrj
79938fd1498Szrj /* Prints the tail of the dot file. */
80038fd1498Szrj fprintf (file, "}\n");
80138fd1498Szrj }
80238fd1498Szrj
80338fd1498Szrj /* Print out the constraint graph to stderr. */
80438fd1498Szrj
80538fd1498Szrj DEBUG_FUNCTION void
debug_constraint_graph(void)80638fd1498Szrj debug_constraint_graph (void)
80738fd1498Szrj {
80838fd1498Szrj dump_constraint_graph (stderr);
80938fd1498Szrj }
81038fd1498Szrj
81138fd1498Szrj /* SOLVER FUNCTIONS
81238fd1498Szrj
81338fd1498Szrj The solver is a simple worklist solver, that works on the following
81438fd1498Szrj algorithm:
81538fd1498Szrj
81638fd1498Szrj sbitmap changed_nodes = all zeroes;
81738fd1498Szrj changed_count = 0;
81838fd1498Szrj For each node that is not already collapsed:
81938fd1498Szrj changed_count++;
82038fd1498Szrj set bit in changed nodes
82138fd1498Szrj
82238fd1498Szrj while (changed_count > 0)
82338fd1498Szrj {
82438fd1498Szrj compute topological ordering for constraint graph
82538fd1498Szrj
82638fd1498Szrj find and collapse cycles in the constraint graph (updating
82738fd1498Szrj changed if necessary)
82838fd1498Szrj
82938fd1498Szrj for each node (n) in the graph in topological order:
83038fd1498Szrj changed_count--;
83138fd1498Szrj
83238fd1498Szrj Process each complex constraint associated with the node,
83338fd1498Szrj updating changed if necessary.
83438fd1498Szrj
83538fd1498Szrj For each outgoing edge from n, propagate the solution from n to
83638fd1498Szrj the destination of the edge, updating changed as necessary.
83738fd1498Szrj
83838fd1498Szrj } */
83938fd1498Szrj
84038fd1498Szrj /* Return true if two constraint expressions A and B are equal. */
84138fd1498Szrj
84238fd1498Szrj static bool
constraint_expr_equal(struct constraint_expr a,struct constraint_expr b)84338fd1498Szrj constraint_expr_equal (struct constraint_expr a, struct constraint_expr b)
84438fd1498Szrj {
84538fd1498Szrj return a.type == b.type && a.var == b.var && a.offset == b.offset;
84638fd1498Szrj }
84738fd1498Szrj
84838fd1498Szrj /* Return true if constraint expression A is less than constraint expression
84938fd1498Szrj B. This is just arbitrary, but consistent, in order to give them an
85038fd1498Szrj ordering. */
85138fd1498Szrj
85238fd1498Szrj static bool
constraint_expr_less(struct constraint_expr a,struct constraint_expr b)85338fd1498Szrj constraint_expr_less (struct constraint_expr a, struct constraint_expr b)
85438fd1498Szrj {
85538fd1498Szrj if (a.type == b.type)
85638fd1498Szrj {
85738fd1498Szrj if (a.var == b.var)
85838fd1498Szrj return a.offset < b.offset;
85938fd1498Szrj else
86038fd1498Szrj return a.var < b.var;
86138fd1498Szrj }
86238fd1498Szrj else
86338fd1498Szrj return a.type < b.type;
86438fd1498Szrj }
86538fd1498Szrj
86638fd1498Szrj /* Return true if constraint A is less than constraint B. This is just
86738fd1498Szrj arbitrary, but consistent, in order to give them an ordering. */
86838fd1498Szrj
86938fd1498Szrj static bool
constraint_less(const constraint_t & a,const constraint_t & b)87038fd1498Szrj constraint_less (const constraint_t &a, const constraint_t &b)
87138fd1498Szrj {
87238fd1498Szrj if (constraint_expr_less (a->lhs, b->lhs))
87338fd1498Szrj return true;
87438fd1498Szrj else if (constraint_expr_less (b->lhs, a->lhs))
87538fd1498Szrj return false;
87638fd1498Szrj else
87738fd1498Szrj return constraint_expr_less (a->rhs, b->rhs);
87838fd1498Szrj }
87938fd1498Szrj
88038fd1498Szrj /* Return true if two constraints A and B are equal. */
88138fd1498Szrj
88238fd1498Szrj static bool
constraint_equal(struct constraint a,struct constraint b)88338fd1498Szrj constraint_equal (struct constraint a, struct constraint b)
88438fd1498Szrj {
88538fd1498Szrj return constraint_expr_equal (a.lhs, b.lhs)
88638fd1498Szrj && constraint_expr_equal (a.rhs, b.rhs);
88738fd1498Szrj }
88838fd1498Szrj
88938fd1498Szrj
89038fd1498Szrj /* Find a constraint LOOKFOR in the sorted constraint vector VEC */
89138fd1498Szrj
89238fd1498Szrj static constraint_t
constraint_vec_find(vec<constraint_t> vec,struct constraint lookfor)89338fd1498Szrj constraint_vec_find (vec<constraint_t> vec,
89438fd1498Szrj struct constraint lookfor)
89538fd1498Szrj {
89638fd1498Szrj unsigned int place;
89738fd1498Szrj constraint_t found;
89838fd1498Szrj
89938fd1498Szrj if (!vec.exists ())
90038fd1498Szrj return NULL;
90138fd1498Szrj
90238fd1498Szrj place = vec.lower_bound (&lookfor, constraint_less);
90338fd1498Szrj if (place >= vec.length ())
90438fd1498Szrj return NULL;
90538fd1498Szrj found = vec[place];
90638fd1498Szrj if (!constraint_equal (*found, lookfor))
90738fd1498Szrj return NULL;
90838fd1498Szrj return found;
90938fd1498Szrj }
91038fd1498Szrj
91138fd1498Szrj /* Union two constraint vectors, TO and FROM. Put the result in TO.
91238fd1498Szrj Returns true of TO set is changed. */
91338fd1498Szrj
91438fd1498Szrj static bool
constraint_set_union(vec<constraint_t> * to,vec<constraint_t> * from)91538fd1498Szrj constraint_set_union (vec<constraint_t> *to,
91638fd1498Szrj vec<constraint_t> *from)
91738fd1498Szrj {
91838fd1498Szrj int i;
91938fd1498Szrj constraint_t c;
92038fd1498Szrj bool any_change = false;
92138fd1498Szrj
92238fd1498Szrj FOR_EACH_VEC_ELT (*from, i, c)
92338fd1498Szrj {
92438fd1498Szrj if (constraint_vec_find (*to, *c) == NULL)
92538fd1498Szrj {
92638fd1498Szrj unsigned int place = to->lower_bound (c, constraint_less);
92738fd1498Szrj to->safe_insert (place, c);
92838fd1498Szrj any_change = true;
92938fd1498Szrj }
93038fd1498Szrj }
93138fd1498Szrj return any_change;
93238fd1498Szrj }
93338fd1498Szrj
93438fd1498Szrj /* Expands the solution in SET to all sub-fields of variables included. */
93538fd1498Szrj
93638fd1498Szrj static bitmap
solution_set_expand(bitmap set,bitmap * expanded)93738fd1498Szrj solution_set_expand (bitmap set, bitmap *expanded)
93838fd1498Szrj {
93938fd1498Szrj bitmap_iterator bi;
94038fd1498Szrj unsigned j;
94138fd1498Szrj
94238fd1498Szrj if (*expanded)
94338fd1498Szrj return *expanded;
94438fd1498Szrj
94538fd1498Szrj *expanded = BITMAP_ALLOC (&iteration_obstack);
94638fd1498Szrj
94738fd1498Szrj /* In a first pass expand to the head of the variables we need to
94838fd1498Szrj add all sub-fields off. This avoids quadratic behavior. */
94938fd1498Szrj EXECUTE_IF_SET_IN_BITMAP (set, 0, j, bi)
95038fd1498Szrj {
95138fd1498Szrj varinfo_t v = get_varinfo (j);
95238fd1498Szrj if (v->is_artificial_var
95338fd1498Szrj || v->is_full_var)
95438fd1498Szrj continue;
95538fd1498Szrj bitmap_set_bit (*expanded, v->head);
95638fd1498Szrj }
95738fd1498Szrj
95838fd1498Szrj /* In the second pass now expand all head variables with subfields. */
95938fd1498Szrj EXECUTE_IF_SET_IN_BITMAP (*expanded, 0, j, bi)
96038fd1498Szrj {
96138fd1498Szrj varinfo_t v = get_varinfo (j);
96238fd1498Szrj if (v->head != j)
96338fd1498Szrj continue;
96438fd1498Szrj for (v = vi_next (v); v != NULL; v = vi_next (v))
96538fd1498Szrj bitmap_set_bit (*expanded, v->id);
96638fd1498Szrj }
96738fd1498Szrj
96838fd1498Szrj /* And finally set the rest of the bits from SET. */
96938fd1498Szrj bitmap_ior_into (*expanded, set);
97038fd1498Szrj
97138fd1498Szrj return *expanded;
97238fd1498Szrj }
97338fd1498Szrj
97438fd1498Szrj /* Union solution sets TO and DELTA, and add INC to each member of DELTA in the
97538fd1498Szrj process. */
97638fd1498Szrj
97738fd1498Szrj static bool
set_union_with_increment(bitmap to,bitmap delta,HOST_WIDE_INT inc,bitmap * expanded_delta)97838fd1498Szrj set_union_with_increment (bitmap to, bitmap delta, HOST_WIDE_INT inc,
97938fd1498Szrj bitmap *expanded_delta)
98038fd1498Szrj {
98138fd1498Szrj bool changed = false;
98238fd1498Szrj bitmap_iterator bi;
98338fd1498Szrj unsigned int i;
98438fd1498Szrj
98538fd1498Szrj /* If the solution of DELTA contains anything it is good enough to transfer
98638fd1498Szrj this to TO. */
98738fd1498Szrj if (bitmap_bit_p (delta, anything_id))
98838fd1498Szrj return bitmap_set_bit (to, anything_id);
98938fd1498Szrj
99038fd1498Szrj /* If the offset is unknown we have to expand the solution to
99138fd1498Szrj all subfields. */
99238fd1498Szrj if (inc == UNKNOWN_OFFSET)
99338fd1498Szrj {
99438fd1498Szrj delta = solution_set_expand (delta, expanded_delta);
99538fd1498Szrj changed |= bitmap_ior_into (to, delta);
99638fd1498Szrj return changed;
99738fd1498Szrj }
99838fd1498Szrj
99938fd1498Szrj /* For non-zero offset union the offsetted solution into the destination. */
100038fd1498Szrj EXECUTE_IF_SET_IN_BITMAP (delta, 0, i, bi)
100138fd1498Szrj {
100238fd1498Szrj varinfo_t vi = get_varinfo (i);
100338fd1498Szrj
100438fd1498Szrj /* If this is a variable with just one field just set its bit
100538fd1498Szrj in the result. */
100638fd1498Szrj if (vi->is_artificial_var
100738fd1498Szrj || vi->is_unknown_size_var
100838fd1498Szrj || vi->is_full_var)
100938fd1498Szrj changed |= bitmap_set_bit (to, i);
101038fd1498Szrj else
101138fd1498Szrj {
101238fd1498Szrj HOST_WIDE_INT fieldoffset = vi->offset + inc;
101338fd1498Szrj unsigned HOST_WIDE_INT size = vi->size;
101438fd1498Szrj
101538fd1498Szrj /* If the offset makes the pointer point to before the
101638fd1498Szrj variable use offset zero for the field lookup. */
101738fd1498Szrj if (fieldoffset < 0)
101838fd1498Szrj vi = get_varinfo (vi->head);
101938fd1498Szrj else
102038fd1498Szrj vi = first_or_preceding_vi_for_offset (vi, fieldoffset);
102138fd1498Szrj
102238fd1498Szrj do
102338fd1498Szrj {
102438fd1498Szrj changed |= bitmap_set_bit (to, vi->id);
102538fd1498Szrj if (vi->is_full_var
102638fd1498Szrj || vi->next == 0)
102738fd1498Szrj break;
102838fd1498Szrj
102938fd1498Szrj /* We have to include all fields that overlap the current field
103038fd1498Szrj shifted by inc. */
103138fd1498Szrj vi = vi_next (vi);
103238fd1498Szrj }
103338fd1498Szrj while (vi->offset < fieldoffset + size);
103438fd1498Szrj }
103538fd1498Szrj }
103638fd1498Szrj
103738fd1498Szrj return changed;
103838fd1498Szrj }
103938fd1498Szrj
104038fd1498Szrj /* Insert constraint C into the list of complex constraints for graph
104138fd1498Szrj node VAR. */
104238fd1498Szrj
104338fd1498Szrj static void
insert_into_complex(constraint_graph_t graph,unsigned int var,constraint_t c)104438fd1498Szrj insert_into_complex (constraint_graph_t graph,
104538fd1498Szrj unsigned int var, constraint_t c)
104638fd1498Szrj {
104738fd1498Szrj vec<constraint_t> complex = graph->complex[var];
104838fd1498Szrj unsigned int place = complex.lower_bound (c, constraint_less);
104938fd1498Szrj
105038fd1498Szrj /* Only insert constraints that do not already exist. */
105138fd1498Szrj if (place >= complex.length ()
105238fd1498Szrj || !constraint_equal (*c, *complex[place]))
105338fd1498Szrj graph->complex[var].safe_insert (place, c);
105438fd1498Szrj }
105538fd1498Szrj
105638fd1498Szrj
105738fd1498Szrj /* Condense two variable nodes into a single variable node, by moving
105838fd1498Szrj all associated info from FROM to TO. Returns true if TO node's
105938fd1498Szrj constraint set changes after the merge. */
106038fd1498Szrj
106138fd1498Szrj static bool
merge_node_constraints(constraint_graph_t graph,unsigned int to,unsigned int from)106238fd1498Szrj merge_node_constraints (constraint_graph_t graph, unsigned int to,
106338fd1498Szrj unsigned int from)
106438fd1498Szrj {
106538fd1498Szrj unsigned int i;
106638fd1498Szrj constraint_t c;
106738fd1498Szrj bool any_change = false;
106838fd1498Szrj
106938fd1498Szrj gcc_checking_assert (find (from) == to);
107038fd1498Szrj
107138fd1498Szrj /* Move all complex constraints from src node into to node */
107238fd1498Szrj FOR_EACH_VEC_ELT (graph->complex[from], i, c)
107338fd1498Szrj {
107438fd1498Szrj /* In complex constraints for node FROM, we may have either
107538fd1498Szrj a = *FROM, and *FROM = a, or an offseted constraint which are
107638fd1498Szrj always added to the rhs node's constraints. */
107738fd1498Szrj
107838fd1498Szrj if (c->rhs.type == DEREF)
107938fd1498Szrj c->rhs.var = to;
108038fd1498Szrj else if (c->lhs.type == DEREF)
108138fd1498Szrj c->lhs.var = to;
108238fd1498Szrj else
108338fd1498Szrj c->rhs.var = to;
108438fd1498Szrj
108538fd1498Szrj }
108638fd1498Szrj any_change = constraint_set_union (&graph->complex[to],
108738fd1498Szrj &graph->complex[from]);
108838fd1498Szrj graph->complex[from].release ();
108938fd1498Szrj return any_change;
109038fd1498Szrj }
109138fd1498Szrj
109238fd1498Szrj
109338fd1498Szrj /* Remove edges involving NODE from GRAPH. */
109438fd1498Szrj
109538fd1498Szrj static void
clear_edges_for_node(constraint_graph_t graph,unsigned int node)109638fd1498Szrj clear_edges_for_node (constraint_graph_t graph, unsigned int node)
109738fd1498Szrj {
109838fd1498Szrj if (graph->succs[node])
109938fd1498Szrj BITMAP_FREE (graph->succs[node]);
110038fd1498Szrj }
110138fd1498Szrj
110238fd1498Szrj /* Merge GRAPH nodes FROM and TO into node TO. */
110338fd1498Szrj
110438fd1498Szrj static void
merge_graph_nodes(constraint_graph_t graph,unsigned int to,unsigned int from)110538fd1498Szrj merge_graph_nodes (constraint_graph_t graph, unsigned int to,
110638fd1498Szrj unsigned int from)
110738fd1498Szrj {
110838fd1498Szrj if (graph->indirect_cycles[from] != -1)
110938fd1498Szrj {
111038fd1498Szrj /* If we have indirect cycles with the from node, and we have
111138fd1498Szrj none on the to node, the to node has indirect cycles from the
111238fd1498Szrj from node now that they are unified.
111338fd1498Szrj If indirect cycles exist on both, unify the nodes that they
111438fd1498Szrj are in a cycle with, since we know they are in a cycle with
111538fd1498Szrj each other. */
111638fd1498Szrj if (graph->indirect_cycles[to] == -1)
111738fd1498Szrj graph->indirect_cycles[to] = graph->indirect_cycles[from];
111838fd1498Szrj }
111938fd1498Szrj
112038fd1498Szrj /* Merge all the successor edges. */
112138fd1498Szrj if (graph->succs[from])
112238fd1498Szrj {
112338fd1498Szrj if (!graph->succs[to])
112438fd1498Szrj graph->succs[to] = BITMAP_ALLOC (&pta_obstack);
112538fd1498Szrj bitmap_ior_into (graph->succs[to],
112638fd1498Szrj graph->succs[from]);
112738fd1498Szrj }
112838fd1498Szrj
112938fd1498Szrj clear_edges_for_node (graph, from);
113038fd1498Szrj }
113138fd1498Szrj
113238fd1498Szrj
113338fd1498Szrj /* Add an indirect graph edge to GRAPH, going from TO to FROM if
113438fd1498Szrj it doesn't exist in the graph already. */
113538fd1498Szrj
113638fd1498Szrj static void
add_implicit_graph_edge(constraint_graph_t graph,unsigned int to,unsigned int from)113738fd1498Szrj add_implicit_graph_edge (constraint_graph_t graph, unsigned int to,
113838fd1498Szrj unsigned int from)
113938fd1498Szrj {
114038fd1498Szrj if (to == from)
114138fd1498Szrj return;
114238fd1498Szrj
114338fd1498Szrj if (!graph->implicit_preds[to])
114438fd1498Szrj graph->implicit_preds[to] = BITMAP_ALLOC (&predbitmap_obstack);
114538fd1498Szrj
114638fd1498Szrj if (bitmap_set_bit (graph->implicit_preds[to], from))
114738fd1498Szrj stats.num_implicit_edges++;
114838fd1498Szrj }
114938fd1498Szrj
115038fd1498Szrj /* Add a predecessor graph edge to GRAPH, going from TO to FROM if
115138fd1498Szrj it doesn't exist in the graph already.
115238fd1498Szrj Return false if the edge already existed, true otherwise. */
115338fd1498Szrj
115438fd1498Szrj static void
add_pred_graph_edge(constraint_graph_t graph,unsigned int to,unsigned int from)115538fd1498Szrj add_pred_graph_edge (constraint_graph_t graph, unsigned int to,
115638fd1498Szrj unsigned int from)
115738fd1498Szrj {
115838fd1498Szrj if (!graph->preds[to])
115938fd1498Szrj graph->preds[to] = BITMAP_ALLOC (&predbitmap_obstack);
116038fd1498Szrj bitmap_set_bit (graph->preds[to], from);
116138fd1498Szrj }
116238fd1498Szrj
116338fd1498Szrj /* Add a graph edge to GRAPH, going from FROM to TO if
116438fd1498Szrj it doesn't exist in the graph already.
116538fd1498Szrj Return false if the edge already existed, true otherwise. */
116638fd1498Szrj
116738fd1498Szrj static bool
add_graph_edge(constraint_graph_t graph,unsigned int to,unsigned int from)116838fd1498Szrj add_graph_edge (constraint_graph_t graph, unsigned int to,
116938fd1498Szrj unsigned int from)
117038fd1498Szrj {
117138fd1498Szrj if (to == from)
117238fd1498Szrj {
117338fd1498Szrj return false;
117438fd1498Szrj }
117538fd1498Szrj else
117638fd1498Szrj {
117738fd1498Szrj bool r = false;
117838fd1498Szrj
117938fd1498Szrj if (!graph->succs[from])
118038fd1498Szrj graph->succs[from] = BITMAP_ALLOC (&pta_obstack);
118138fd1498Szrj if (bitmap_set_bit (graph->succs[from], to))
118238fd1498Szrj {
118338fd1498Szrj r = true;
118438fd1498Szrj if (to < FIRST_REF_NODE && from < FIRST_REF_NODE)
118538fd1498Szrj stats.num_edges++;
118638fd1498Szrj }
118738fd1498Szrj return r;
118838fd1498Szrj }
118938fd1498Szrj }
119038fd1498Szrj
119138fd1498Szrj
119238fd1498Szrj /* Initialize the constraint graph structure to contain SIZE nodes. */
119338fd1498Szrj
119438fd1498Szrj static void
init_graph(unsigned int size)119538fd1498Szrj init_graph (unsigned int size)
119638fd1498Szrj {
119738fd1498Szrj unsigned int j;
119838fd1498Szrj
119938fd1498Szrj graph = XCNEW (struct constraint_graph);
120038fd1498Szrj graph->size = size;
120138fd1498Szrj graph->succs = XCNEWVEC (bitmap, graph->size);
120238fd1498Szrj graph->indirect_cycles = XNEWVEC (int, graph->size);
120338fd1498Szrj graph->rep = XNEWVEC (unsigned int, graph->size);
120438fd1498Szrj /* ??? Macros do not support template types with multiple arguments,
120538fd1498Szrj so we use a typedef to work around it. */
120638fd1498Szrj typedef vec<constraint_t> vec_constraint_t_heap;
120738fd1498Szrj graph->complex = XCNEWVEC (vec_constraint_t_heap, size);
120838fd1498Szrj graph->pe = XCNEWVEC (unsigned int, graph->size);
120938fd1498Szrj graph->pe_rep = XNEWVEC (int, graph->size);
121038fd1498Szrj
121138fd1498Szrj for (j = 0; j < graph->size; j++)
121238fd1498Szrj {
121338fd1498Szrj graph->rep[j] = j;
121438fd1498Szrj graph->pe_rep[j] = -1;
121538fd1498Szrj graph->indirect_cycles[j] = -1;
121638fd1498Szrj }
121738fd1498Szrj }
121838fd1498Szrj
121938fd1498Szrj /* Build the constraint graph, adding only predecessor edges right now. */
122038fd1498Szrj
122138fd1498Szrj static void
build_pred_graph(void)122238fd1498Szrj build_pred_graph (void)
122338fd1498Szrj {
122438fd1498Szrj int i;
122538fd1498Szrj constraint_t c;
122638fd1498Szrj unsigned int j;
122738fd1498Szrj
122838fd1498Szrj graph->implicit_preds = XCNEWVEC (bitmap, graph->size);
122938fd1498Szrj graph->preds = XCNEWVEC (bitmap, graph->size);
123038fd1498Szrj graph->pointer_label = XCNEWVEC (unsigned int, graph->size);
123138fd1498Szrj graph->loc_label = XCNEWVEC (unsigned int, graph->size);
123238fd1498Szrj graph->pointed_by = XCNEWVEC (bitmap, graph->size);
123338fd1498Szrj graph->points_to = XCNEWVEC (bitmap, graph->size);
123438fd1498Szrj graph->eq_rep = XNEWVEC (int, graph->size);
123538fd1498Szrj graph->direct_nodes = sbitmap_alloc (graph->size);
123638fd1498Szrj graph->address_taken = BITMAP_ALLOC (&predbitmap_obstack);
123738fd1498Szrj bitmap_clear (graph->direct_nodes);
123838fd1498Szrj
123938fd1498Szrj for (j = 1; j < FIRST_REF_NODE; j++)
124038fd1498Szrj {
124138fd1498Szrj if (!get_varinfo (j)->is_special_var)
124238fd1498Szrj bitmap_set_bit (graph->direct_nodes, j);
124338fd1498Szrj }
124438fd1498Szrj
124538fd1498Szrj for (j = 0; j < graph->size; j++)
124638fd1498Szrj graph->eq_rep[j] = -1;
124738fd1498Szrj
124838fd1498Szrj for (j = 0; j < varmap.length (); j++)
124938fd1498Szrj graph->indirect_cycles[j] = -1;
125038fd1498Szrj
125138fd1498Szrj FOR_EACH_VEC_ELT (constraints, i, c)
125238fd1498Szrj {
125338fd1498Szrj struct constraint_expr lhs = c->lhs;
125438fd1498Szrj struct constraint_expr rhs = c->rhs;
125538fd1498Szrj unsigned int lhsvar = lhs.var;
125638fd1498Szrj unsigned int rhsvar = rhs.var;
125738fd1498Szrj
125838fd1498Szrj if (lhs.type == DEREF)
125938fd1498Szrj {
126038fd1498Szrj /* *x = y. */
126138fd1498Szrj if (rhs.offset == 0 && lhs.offset == 0 && rhs.type == SCALAR)
126238fd1498Szrj add_pred_graph_edge (graph, FIRST_REF_NODE + lhsvar, rhsvar);
126338fd1498Szrj }
126438fd1498Szrj else if (rhs.type == DEREF)
126538fd1498Szrj {
126638fd1498Szrj /* x = *y */
126738fd1498Szrj if (rhs.offset == 0 && lhs.offset == 0 && lhs.type == SCALAR)
126838fd1498Szrj add_pred_graph_edge (graph, lhsvar, FIRST_REF_NODE + rhsvar);
126938fd1498Szrj else
127038fd1498Szrj bitmap_clear_bit (graph->direct_nodes, lhsvar);
127138fd1498Szrj }
127238fd1498Szrj else if (rhs.type == ADDRESSOF)
127338fd1498Szrj {
127438fd1498Szrj varinfo_t v;
127538fd1498Szrj
127638fd1498Szrj /* x = &y */
127738fd1498Szrj if (graph->points_to[lhsvar] == NULL)
127838fd1498Szrj graph->points_to[lhsvar] = BITMAP_ALLOC (&predbitmap_obstack);
127938fd1498Szrj bitmap_set_bit (graph->points_to[lhsvar], rhsvar);
128038fd1498Szrj
128138fd1498Szrj if (graph->pointed_by[rhsvar] == NULL)
128238fd1498Szrj graph->pointed_by[rhsvar] = BITMAP_ALLOC (&predbitmap_obstack);
128338fd1498Szrj bitmap_set_bit (graph->pointed_by[rhsvar], lhsvar);
128438fd1498Szrj
128538fd1498Szrj /* Implicitly, *x = y */
128638fd1498Szrj add_implicit_graph_edge (graph, FIRST_REF_NODE + lhsvar, rhsvar);
128738fd1498Szrj
128838fd1498Szrj /* All related variables are no longer direct nodes. */
128938fd1498Szrj bitmap_clear_bit (graph->direct_nodes, rhsvar);
129038fd1498Szrj v = get_varinfo (rhsvar);
129138fd1498Szrj if (!v->is_full_var)
129238fd1498Szrj {
129338fd1498Szrj v = get_varinfo (v->head);
129438fd1498Szrj do
129538fd1498Szrj {
129638fd1498Szrj bitmap_clear_bit (graph->direct_nodes, v->id);
129738fd1498Szrj v = vi_next (v);
129838fd1498Szrj }
129938fd1498Szrj while (v != NULL);
130038fd1498Szrj }
130138fd1498Szrj bitmap_set_bit (graph->address_taken, rhsvar);
130238fd1498Szrj }
130338fd1498Szrj else if (lhsvar > anything_id
130438fd1498Szrj && lhsvar != rhsvar && lhs.offset == 0 && rhs.offset == 0)
130538fd1498Szrj {
130638fd1498Szrj /* x = y */
130738fd1498Szrj add_pred_graph_edge (graph, lhsvar, rhsvar);
130838fd1498Szrj /* Implicitly, *x = *y */
130938fd1498Szrj add_implicit_graph_edge (graph, FIRST_REF_NODE + lhsvar,
131038fd1498Szrj FIRST_REF_NODE + rhsvar);
131138fd1498Szrj }
131238fd1498Szrj else if (lhs.offset != 0 || rhs.offset != 0)
131338fd1498Szrj {
131438fd1498Szrj if (rhs.offset != 0)
131538fd1498Szrj bitmap_clear_bit (graph->direct_nodes, lhs.var);
131638fd1498Szrj else if (lhs.offset != 0)
131738fd1498Szrj bitmap_clear_bit (graph->direct_nodes, rhs.var);
131838fd1498Szrj }
131938fd1498Szrj }
132038fd1498Szrj }
132138fd1498Szrj
132238fd1498Szrj /* Build the constraint graph, adding successor edges. */
132338fd1498Szrj
132438fd1498Szrj static void
build_succ_graph(void)132538fd1498Szrj build_succ_graph (void)
132638fd1498Szrj {
132738fd1498Szrj unsigned i, t;
132838fd1498Szrj constraint_t c;
132938fd1498Szrj
133038fd1498Szrj FOR_EACH_VEC_ELT (constraints, i, c)
133138fd1498Szrj {
133238fd1498Szrj struct constraint_expr lhs;
133338fd1498Szrj struct constraint_expr rhs;
133438fd1498Szrj unsigned int lhsvar;
133538fd1498Szrj unsigned int rhsvar;
133638fd1498Szrj
133738fd1498Szrj if (!c)
133838fd1498Szrj continue;
133938fd1498Szrj
134038fd1498Szrj lhs = c->lhs;
134138fd1498Szrj rhs = c->rhs;
134238fd1498Szrj lhsvar = find (lhs.var);
134338fd1498Szrj rhsvar = find (rhs.var);
134438fd1498Szrj
134538fd1498Szrj if (lhs.type == DEREF)
134638fd1498Szrj {
134738fd1498Szrj if (rhs.offset == 0 && lhs.offset == 0 && rhs.type == SCALAR)
134838fd1498Szrj add_graph_edge (graph, FIRST_REF_NODE + lhsvar, rhsvar);
134938fd1498Szrj }
135038fd1498Szrj else if (rhs.type == DEREF)
135138fd1498Szrj {
135238fd1498Szrj if (rhs.offset == 0 && lhs.offset == 0 && lhs.type == SCALAR)
135338fd1498Szrj add_graph_edge (graph, lhsvar, FIRST_REF_NODE + rhsvar);
135438fd1498Szrj }
135538fd1498Szrj else if (rhs.type == ADDRESSOF)
135638fd1498Szrj {
135738fd1498Szrj /* x = &y */
135838fd1498Szrj gcc_checking_assert (find (rhs.var) == rhs.var);
135938fd1498Szrj bitmap_set_bit (get_varinfo (lhsvar)->solution, rhsvar);
136038fd1498Szrj }
136138fd1498Szrj else if (lhsvar > anything_id
136238fd1498Szrj && lhsvar != rhsvar && lhs.offset == 0 && rhs.offset == 0)
136338fd1498Szrj {
136438fd1498Szrj add_graph_edge (graph, lhsvar, rhsvar);
136538fd1498Szrj }
136638fd1498Szrj }
136738fd1498Szrj
136838fd1498Szrj /* Add edges from STOREDANYTHING to all non-direct nodes that can
136938fd1498Szrj receive pointers. */
137038fd1498Szrj t = find (storedanything_id);
137138fd1498Szrj for (i = integer_id + 1; i < FIRST_REF_NODE; ++i)
137238fd1498Szrj {
137338fd1498Szrj if (!bitmap_bit_p (graph->direct_nodes, i)
137438fd1498Szrj && get_varinfo (i)->may_have_pointers)
137538fd1498Szrj add_graph_edge (graph, find (i), t);
137638fd1498Szrj }
137738fd1498Szrj
137838fd1498Szrj /* Everything stored to ANYTHING also potentially escapes. */
137938fd1498Szrj add_graph_edge (graph, find (escaped_id), t);
138038fd1498Szrj }
138138fd1498Szrj
138238fd1498Szrj
138338fd1498Szrj /* Changed variables on the last iteration. */
138438fd1498Szrj static bitmap changed;
138538fd1498Szrj
138638fd1498Szrj /* Strongly Connected Component visitation info. */
138738fd1498Szrj
138838fd1498Szrj struct scc_info
138938fd1498Szrj {
139038fd1498Szrj scc_info (size_t size);
139138fd1498Szrj ~scc_info ();
139238fd1498Szrj
139338fd1498Szrj auto_sbitmap visited;
139438fd1498Szrj auto_sbitmap deleted;
139538fd1498Szrj unsigned int *dfs;
139638fd1498Szrj unsigned int *node_mapping;
139738fd1498Szrj int current_index;
139838fd1498Szrj auto_vec<unsigned> scc_stack;
139938fd1498Szrj };
140038fd1498Szrj
140138fd1498Szrj
140238fd1498Szrj /* Recursive routine to find strongly connected components in GRAPH.
140338fd1498Szrj SI is the SCC info to store the information in, and N is the id of current
140438fd1498Szrj graph node we are processing.
140538fd1498Szrj
140638fd1498Szrj This is Tarjan's strongly connected component finding algorithm, as
140738fd1498Szrj modified by Nuutila to keep only non-root nodes on the stack.
140838fd1498Szrj The algorithm can be found in "On finding the strongly connected
140938fd1498Szrj connected components in a directed graph" by Esko Nuutila and Eljas
141038fd1498Szrj Soisalon-Soininen, in Information Processing Letters volume 49,
141138fd1498Szrj number 1, pages 9-14. */
141238fd1498Szrj
141338fd1498Szrj static void
scc_visit(constraint_graph_t graph,struct scc_info * si,unsigned int n)141438fd1498Szrj scc_visit (constraint_graph_t graph, struct scc_info *si, unsigned int n)
141538fd1498Szrj {
141638fd1498Szrj unsigned int i;
141738fd1498Szrj bitmap_iterator bi;
141838fd1498Szrj unsigned int my_dfs;
141938fd1498Szrj
142038fd1498Szrj bitmap_set_bit (si->visited, n);
142138fd1498Szrj si->dfs[n] = si->current_index ++;
142238fd1498Szrj my_dfs = si->dfs[n];
142338fd1498Szrj
142438fd1498Szrj /* Visit all the successors. */
142538fd1498Szrj EXECUTE_IF_IN_NONNULL_BITMAP (graph->succs[n], 0, i, bi)
142638fd1498Szrj {
142738fd1498Szrj unsigned int w;
142838fd1498Szrj
142938fd1498Szrj if (i > LAST_REF_NODE)
143038fd1498Szrj break;
143138fd1498Szrj
143238fd1498Szrj w = find (i);
143338fd1498Szrj if (bitmap_bit_p (si->deleted, w))
143438fd1498Szrj continue;
143538fd1498Szrj
143638fd1498Szrj if (!bitmap_bit_p (si->visited, w))
143738fd1498Szrj scc_visit (graph, si, w);
143838fd1498Szrj
143938fd1498Szrj unsigned int t = find (w);
144038fd1498Szrj gcc_checking_assert (find (n) == n);
144138fd1498Szrj if (si->dfs[t] < si->dfs[n])
144238fd1498Szrj si->dfs[n] = si->dfs[t];
144338fd1498Szrj }
144438fd1498Szrj
144538fd1498Szrj /* See if any components have been identified. */
144638fd1498Szrj if (si->dfs[n] == my_dfs)
144738fd1498Szrj {
144838fd1498Szrj if (si->scc_stack.length () > 0
144938fd1498Szrj && si->dfs[si->scc_stack.last ()] >= my_dfs)
145038fd1498Szrj {
145138fd1498Szrj bitmap scc = BITMAP_ALLOC (NULL);
145238fd1498Szrj unsigned int lowest_node;
145338fd1498Szrj bitmap_iterator bi;
145438fd1498Szrj
145538fd1498Szrj bitmap_set_bit (scc, n);
145638fd1498Szrj
145738fd1498Szrj while (si->scc_stack.length () != 0
145838fd1498Szrj && si->dfs[si->scc_stack.last ()] >= my_dfs)
145938fd1498Szrj {
146038fd1498Szrj unsigned int w = si->scc_stack.pop ();
146138fd1498Szrj
146238fd1498Szrj bitmap_set_bit (scc, w);
146338fd1498Szrj }
146438fd1498Szrj
146538fd1498Szrj lowest_node = bitmap_first_set_bit (scc);
146638fd1498Szrj gcc_assert (lowest_node < FIRST_REF_NODE);
146738fd1498Szrj
146838fd1498Szrj /* Collapse the SCC nodes into a single node, and mark the
146938fd1498Szrj indirect cycles. */
147038fd1498Szrj EXECUTE_IF_SET_IN_BITMAP (scc, 0, i, bi)
147138fd1498Szrj {
147238fd1498Szrj if (i < FIRST_REF_NODE)
147338fd1498Szrj {
147438fd1498Szrj if (unite (lowest_node, i))
147538fd1498Szrj unify_nodes (graph, lowest_node, i, false);
147638fd1498Szrj }
147738fd1498Szrj else
147838fd1498Szrj {
147938fd1498Szrj unite (lowest_node, i);
148038fd1498Szrj graph->indirect_cycles[i - FIRST_REF_NODE] = lowest_node;
148138fd1498Szrj }
148238fd1498Szrj }
148338fd1498Szrj }
148438fd1498Szrj bitmap_set_bit (si->deleted, n);
148538fd1498Szrj }
148638fd1498Szrj else
148738fd1498Szrj si->scc_stack.safe_push (n);
148838fd1498Szrj }
148938fd1498Szrj
149038fd1498Szrj /* Unify node FROM into node TO, updating the changed count if
149138fd1498Szrj necessary when UPDATE_CHANGED is true. */
149238fd1498Szrj
149338fd1498Szrj static void
unify_nodes(constraint_graph_t graph,unsigned int to,unsigned int from,bool update_changed)149438fd1498Szrj unify_nodes (constraint_graph_t graph, unsigned int to, unsigned int from,
149538fd1498Szrj bool update_changed)
149638fd1498Szrj {
149738fd1498Szrj gcc_checking_assert (to != from && find (to) == to);
149838fd1498Szrj
149938fd1498Szrj if (dump_file && (dump_flags & TDF_DETAILS))
150038fd1498Szrj fprintf (dump_file, "Unifying %s to %s\n",
150138fd1498Szrj get_varinfo (from)->name,
150238fd1498Szrj get_varinfo (to)->name);
150338fd1498Szrj
150438fd1498Szrj if (update_changed)
150538fd1498Szrj stats.unified_vars_dynamic++;
150638fd1498Szrj else
150738fd1498Szrj stats.unified_vars_static++;
150838fd1498Szrj
150938fd1498Szrj merge_graph_nodes (graph, to, from);
151038fd1498Szrj if (merge_node_constraints (graph, to, from))
151138fd1498Szrj {
151238fd1498Szrj if (update_changed)
151338fd1498Szrj bitmap_set_bit (changed, to);
151438fd1498Szrj }
151538fd1498Szrj
151638fd1498Szrj /* Mark TO as changed if FROM was changed. If TO was already marked
151738fd1498Szrj as changed, decrease the changed count. */
151838fd1498Szrj
151938fd1498Szrj if (update_changed
152038fd1498Szrj && bitmap_clear_bit (changed, from))
152138fd1498Szrj bitmap_set_bit (changed, to);
152238fd1498Szrj varinfo_t fromvi = get_varinfo (from);
152338fd1498Szrj if (fromvi->solution)
152438fd1498Szrj {
152538fd1498Szrj /* If the solution changes because of the merging, we need to mark
152638fd1498Szrj the variable as changed. */
152738fd1498Szrj varinfo_t tovi = get_varinfo (to);
152838fd1498Szrj if (bitmap_ior_into (tovi->solution, fromvi->solution))
152938fd1498Szrj {
153038fd1498Szrj if (update_changed)
153138fd1498Szrj bitmap_set_bit (changed, to);
153238fd1498Szrj }
153338fd1498Szrj
153438fd1498Szrj BITMAP_FREE (fromvi->solution);
153538fd1498Szrj if (fromvi->oldsolution)
153638fd1498Szrj BITMAP_FREE (fromvi->oldsolution);
153738fd1498Szrj
153838fd1498Szrj if (stats.iterations > 0
153938fd1498Szrj && tovi->oldsolution)
154038fd1498Szrj BITMAP_FREE (tovi->oldsolution);
154138fd1498Szrj }
154238fd1498Szrj if (graph->succs[to])
154338fd1498Szrj bitmap_clear_bit (graph->succs[to], to);
154438fd1498Szrj }
154538fd1498Szrj
154638fd1498Szrj /* Information needed to compute the topological ordering of a graph. */
154738fd1498Szrj
154838fd1498Szrj struct topo_info
154938fd1498Szrj {
155038fd1498Szrj /* sbitmap of visited nodes. */
155138fd1498Szrj sbitmap visited;
155238fd1498Szrj /* Array that stores the topological order of the graph, *in
155338fd1498Szrj reverse*. */
155438fd1498Szrj vec<unsigned> topo_order;
155538fd1498Szrj };
155638fd1498Szrj
155738fd1498Szrj
155838fd1498Szrj /* Initialize and return a topological info structure. */
155938fd1498Szrj
156038fd1498Szrj static struct topo_info *
init_topo_info(void)156138fd1498Szrj init_topo_info (void)
156238fd1498Szrj {
156338fd1498Szrj size_t size = graph->size;
156438fd1498Szrj struct topo_info *ti = XNEW (struct topo_info);
156538fd1498Szrj ti->visited = sbitmap_alloc (size);
156638fd1498Szrj bitmap_clear (ti->visited);
156738fd1498Szrj ti->topo_order.create (1);
156838fd1498Szrj return ti;
156938fd1498Szrj }
157038fd1498Szrj
157138fd1498Szrj
157238fd1498Szrj /* Free the topological sort info pointed to by TI. */
157338fd1498Szrj
157438fd1498Szrj static void
free_topo_info(struct topo_info * ti)157538fd1498Szrj free_topo_info (struct topo_info *ti)
157638fd1498Szrj {
157738fd1498Szrj sbitmap_free (ti->visited);
157838fd1498Szrj ti->topo_order.release ();
157938fd1498Szrj free (ti);
158038fd1498Szrj }
158138fd1498Szrj
158238fd1498Szrj /* Visit the graph in topological order, and store the order in the
158338fd1498Szrj topo_info structure. */
158438fd1498Szrj
158538fd1498Szrj static void
topo_visit(constraint_graph_t graph,struct topo_info * ti,unsigned int n)158638fd1498Szrj topo_visit (constraint_graph_t graph, struct topo_info *ti,
158738fd1498Szrj unsigned int n)
158838fd1498Szrj {
158938fd1498Szrj bitmap_iterator bi;
159038fd1498Szrj unsigned int j;
159138fd1498Szrj
159238fd1498Szrj bitmap_set_bit (ti->visited, n);
159338fd1498Szrj
159438fd1498Szrj if (graph->succs[n])
159538fd1498Szrj EXECUTE_IF_SET_IN_BITMAP (graph->succs[n], 0, j, bi)
159638fd1498Szrj {
159738fd1498Szrj if (!bitmap_bit_p (ti->visited, j))
159838fd1498Szrj topo_visit (graph, ti, j);
159938fd1498Szrj }
160038fd1498Szrj
160138fd1498Szrj ti->topo_order.safe_push (n);
160238fd1498Szrj }
160338fd1498Szrj
160438fd1498Szrj /* Process a constraint C that represents x = *(y + off), using DELTA as the
160538fd1498Szrj starting solution for y. */
160638fd1498Szrj
160738fd1498Szrj static void
do_sd_constraint(constraint_graph_t graph,constraint_t c,bitmap delta,bitmap * expanded_delta)160838fd1498Szrj do_sd_constraint (constraint_graph_t graph, constraint_t c,
160938fd1498Szrj bitmap delta, bitmap *expanded_delta)
161038fd1498Szrj {
161138fd1498Szrj unsigned int lhs = c->lhs.var;
161238fd1498Szrj bool flag = false;
161338fd1498Szrj bitmap sol = get_varinfo (lhs)->solution;
161438fd1498Szrj unsigned int j;
161538fd1498Szrj bitmap_iterator bi;
161638fd1498Szrj HOST_WIDE_INT roffset = c->rhs.offset;
161738fd1498Szrj
161838fd1498Szrj /* Our IL does not allow this. */
161938fd1498Szrj gcc_checking_assert (c->lhs.offset == 0);
162038fd1498Szrj
162138fd1498Szrj /* If the solution of Y contains anything it is good enough to transfer
162238fd1498Szrj this to the LHS. */
162338fd1498Szrj if (bitmap_bit_p (delta, anything_id))
162438fd1498Szrj {
162538fd1498Szrj flag |= bitmap_set_bit (sol, anything_id);
162638fd1498Szrj goto done;
162738fd1498Szrj }
162838fd1498Szrj
162938fd1498Szrj /* If we do not know at with offset the rhs is dereferenced compute
163038fd1498Szrj the reachability set of DELTA, conservatively assuming it is
163138fd1498Szrj dereferenced at all valid offsets. */
163238fd1498Szrj if (roffset == UNKNOWN_OFFSET)
163338fd1498Szrj {
163438fd1498Szrj delta = solution_set_expand (delta, expanded_delta);
163538fd1498Szrj /* No further offset processing is necessary. */
163638fd1498Szrj roffset = 0;
163738fd1498Szrj }
163838fd1498Szrj
163938fd1498Szrj /* For each variable j in delta (Sol(y)), add
164038fd1498Szrj an edge in the graph from j to x, and union Sol(j) into Sol(x). */
164138fd1498Szrj EXECUTE_IF_SET_IN_BITMAP (delta, 0, j, bi)
164238fd1498Szrj {
164338fd1498Szrj varinfo_t v = get_varinfo (j);
164438fd1498Szrj HOST_WIDE_INT fieldoffset = v->offset + roffset;
164538fd1498Szrj unsigned HOST_WIDE_INT size = v->size;
164638fd1498Szrj unsigned int t;
164738fd1498Szrj
164838fd1498Szrj if (v->is_full_var)
164938fd1498Szrj ;
165038fd1498Szrj else if (roffset != 0)
165138fd1498Szrj {
165238fd1498Szrj if (fieldoffset < 0)
165338fd1498Szrj v = get_varinfo (v->head);
165438fd1498Szrj else
165538fd1498Szrj v = first_or_preceding_vi_for_offset (v, fieldoffset);
165638fd1498Szrj }
165738fd1498Szrj
165838fd1498Szrj /* We have to include all fields that overlap the current field
165938fd1498Szrj shifted by roffset. */
166038fd1498Szrj do
166138fd1498Szrj {
166238fd1498Szrj t = find (v->id);
166338fd1498Szrj
166438fd1498Szrj /* Adding edges from the special vars is pointless.
166538fd1498Szrj They don't have sets that can change. */
166638fd1498Szrj if (get_varinfo (t)->is_special_var)
166738fd1498Szrj flag |= bitmap_ior_into (sol, get_varinfo (t)->solution);
166838fd1498Szrj /* Merging the solution from ESCAPED needlessly increases
166938fd1498Szrj the set. Use ESCAPED as representative instead. */
167038fd1498Szrj else if (v->id == escaped_id)
167138fd1498Szrj flag |= bitmap_set_bit (sol, escaped_id);
167238fd1498Szrj else if (v->may_have_pointers
167338fd1498Szrj && add_graph_edge (graph, lhs, t))
167438fd1498Szrj flag |= bitmap_ior_into (sol, get_varinfo (t)->solution);
167538fd1498Szrj
167638fd1498Szrj if (v->is_full_var
167738fd1498Szrj || v->next == 0)
167838fd1498Szrj break;
167938fd1498Szrj
168038fd1498Szrj v = vi_next (v);
168138fd1498Szrj }
168238fd1498Szrj while (v->offset < fieldoffset + size);
168338fd1498Szrj }
168438fd1498Szrj
168538fd1498Szrj done:
168638fd1498Szrj /* If the LHS solution changed, mark the var as changed. */
168738fd1498Szrj if (flag)
168838fd1498Szrj {
168938fd1498Szrj get_varinfo (lhs)->solution = sol;
169038fd1498Szrj bitmap_set_bit (changed, lhs);
169138fd1498Szrj }
169238fd1498Szrj }
169338fd1498Szrj
169438fd1498Szrj /* Process a constraint C that represents *(x + off) = y using DELTA
169538fd1498Szrj as the starting solution for x. */
169638fd1498Szrj
169738fd1498Szrj static void
do_ds_constraint(constraint_t c,bitmap delta,bitmap * expanded_delta)169838fd1498Szrj do_ds_constraint (constraint_t c, bitmap delta, bitmap *expanded_delta)
169938fd1498Szrj {
170038fd1498Szrj unsigned int rhs = c->rhs.var;
170138fd1498Szrj bitmap sol = get_varinfo (rhs)->solution;
170238fd1498Szrj unsigned int j;
170338fd1498Szrj bitmap_iterator bi;
170438fd1498Szrj HOST_WIDE_INT loff = c->lhs.offset;
170538fd1498Szrj bool escaped_p = false;
170638fd1498Szrj
170738fd1498Szrj /* Our IL does not allow this. */
170838fd1498Szrj gcc_checking_assert (c->rhs.offset == 0);
170938fd1498Szrj
171038fd1498Szrj /* If the solution of y contains ANYTHING simply use the ANYTHING
171138fd1498Szrj solution. This avoids needlessly increasing the points-to sets. */
171238fd1498Szrj if (bitmap_bit_p (sol, anything_id))
171338fd1498Szrj sol = get_varinfo (find (anything_id))->solution;
171438fd1498Szrj
171538fd1498Szrj /* If the solution for x contains ANYTHING we have to merge the
171638fd1498Szrj solution of y into all pointer variables which we do via
171738fd1498Szrj STOREDANYTHING. */
171838fd1498Szrj if (bitmap_bit_p (delta, anything_id))
171938fd1498Szrj {
172038fd1498Szrj unsigned t = find (storedanything_id);
172138fd1498Szrj if (add_graph_edge (graph, t, rhs))
172238fd1498Szrj {
172338fd1498Szrj if (bitmap_ior_into (get_varinfo (t)->solution, sol))
172438fd1498Szrj bitmap_set_bit (changed, t);
172538fd1498Szrj }
172638fd1498Szrj return;
172738fd1498Szrj }
172838fd1498Szrj
172938fd1498Szrj /* If we do not know at with offset the rhs is dereferenced compute
173038fd1498Szrj the reachability set of DELTA, conservatively assuming it is
173138fd1498Szrj dereferenced at all valid offsets. */
173238fd1498Szrj if (loff == UNKNOWN_OFFSET)
173338fd1498Szrj {
173438fd1498Szrj delta = solution_set_expand (delta, expanded_delta);
173538fd1498Szrj loff = 0;
173638fd1498Szrj }
173738fd1498Szrj
173838fd1498Szrj /* For each member j of delta (Sol(x)), add an edge from y to j and
173938fd1498Szrj union Sol(y) into Sol(j) */
174038fd1498Szrj EXECUTE_IF_SET_IN_BITMAP (delta, 0, j, bi)
174138fd1498Szrj {
174238fd1498Szrj varinfo_t v = get_varinfo (j);
174338fd1498Szrj unsigned int t;
174438fd1498Szrj HOST_WIDE_INT fieldoffset = v->offset + loff;
174538fd1498Szrj unsigned HOST_WIDE_INT size = v->size;
174638fd1498Szrj
174738fd1498Szrj if (v->is_full_var)
174838fd1498Szrj ;
174938fd1498Szrj else if (loff != 0)
175038fd1498Szrj {
175138fd1498Szrj if (fieldoffset < 0)
175238fd1498Szrj v = get_varinfo (v->head);
175338fd1498Szrj else
175438fd1498Szrj v = first_or_preceding_vi_for_offset (v, fieldoffset);
175538fd1498Szrj }
175638fd1498Szrj
175738fd1498Szrj /* We have to include all fields that overlap the current field
175838fd1498Szrj shifted by loff. */
175938fd1498Szrj do
176038fd1498Szrj {
176138fd1498Szrj if (v->may_have_pointers)
176238fd1498Szrj {
176338fd1498Szrj /* If v is a global variable then this is an escape point. */
176438fd1498Szrj if (v->is_global_var
176538fd1498Szrj && !escaped_p)
176638fd1498Szrj {
176738fd1498Szrj t = find (escaped_id);
176838fd1498Szrj if (add_graph_edge (graph, t, rhs)
176938fd1498Szrj && bitmap_ior_into (get_varinfo (t)->solution, sol))
177038fd1498Szrj bitmap_set_bit (changed, t);
177138fd1498Szrj /* Enough to let rhs escape once. */
177238fd1498Szrj escaped_p = true;
177338fd1498Szrj }
177438fd1498Szrj
177538fd1498Szrj if (v->is_special_var)
177638fd1498Szrj break;
177738fd1498Szrj
177838fd1498Szrj t = find (v->id);
177938fd1498Szrj if (add_graph_edge (graph, t, rhs)
178038fd1498Szrj && bitmap_ior_into (get_varinfo (t)->solution, sol))
178138fd1498Szrj bitmap_set_bit (changed, t);
178238fd1498Szrj }
178338fd1498Szrj
178438fd1498Szrj if (v->is_full_var
178538fd1498Szrj || v->next == 0)
178638fd1498Szrj break;
178738fd1498Szrj
178838fd1498Szrj v = vi_next (v);
178938fd1498Szrj }
179038fd1498Szrj while (v->offset < fieldoffset + size);
179138fd1498Szrj }
179238fd1498Szrj }
179338fd1498Szrj
179438fd1498Szrj /* Handle a non-simple (simple meaning requires no iteration),
179538fd1498Szrj constraint (IE *x = &y, x = *y, *x = y, and x = y with offsets involved). */
179638fd1498Szrj
179738fd1498Szrj static void
do_complex_constraint(constraint_graph_t graph,constraint_t c,bitmap delta,bitmap * expanded_delta)179838fd1498Szrj do_complex_constraint (constraint_graph_t graph, constraint_t c, bitmap delta,
179938fd1498Szrj bitmap *expanded_delta)
180038fd1498Szrj {
180138fd1498Szrj if (c->lhs.type == DEREF)
180238fd1498Szrj {
180338fd1498Szrj if (c->rhs.type == ADDRESSOF)
180438fd1498Szrj {
180538fd1498Szrj gcc_unreachable ();
180638fd1498Szrj }
180738fd1498Szrj else
180838fd1498Szrj {
180938fd1498Szrj /* *x = y */
181038fd1498Szrj do_ds_constraint (c, delta, expanded_delta);
181138fd1498Szrj }
181238fd1498Szrj }
181338fd1498Szrj else if (c->rhs.type == DEREF)
181438fd1498Szrj {
181538fd1498Szrj /* x = *y */
181638fd1498Szrj if (!(get_varinfo (c->lhs.var)->is_special_var))
181738fd1498Szrj do_sd_constraint (graph, c, delta, expanded_delta);
181838fd1498Szrj }
181938fd1498Szrj else
182038fd1498Szrj {
182138fd1498Szrj bitmap tmp;
182238fd1498Szrj bool flag = false;
182338fd1498Szrj
182438fd1498Szrj gcc_checking_assert (c->rhs.type == SCALAR && c->lhs.type == SCALAR
182538fd1498Szrj && c->rhs.offset != 0 && c->lhs.offset == 0);
182638fd1498Szrj tmp = get_varinfo (c->lhs.var)->solution;
182738fd1498Szrj
182838fd1498Szrj flag = set_union_with_increment (tmp, delta, c->rhs.offset,
182938fd1498Szrj expanded_delta);
183038fd1498Szrj
183138fd1498Szrj if (flag)
183238fd1498Szrj bitmap_set_bit (changed, c->lhs.var);
183338fd1498Szrj }
183438fd1498Szrj }
183538fd1498Szrj
183638fd1498Szrj /* Initialize and return a new SCC info structure. */
183738fd1498Szrj
scc_info(size_t size)183838fd1498Szrj scc_info::scc_info (size_t size) :
183938fd1498Szrj visited (size), deleted (size), current_index (0), scc_stack (1)
184038fd1498Szrj {
184138fd1498Szrj bitmap_clear (visited);
184238fd1498Szrj bitmap_clear (deleted);
184338fd1498Szrj node_mapping = XNEWVEC (unsigned int, size);
184438fd1498Szrj dfs = XCNEWVEC (unsigned int, size);
184538fd1498Szrj
184638fd1498Szrj for (size_t i = 0; i < size; i++)
184738fd1498Szrj node_mapping[i] = i;
184838fd1498Szrj }
184938fd1498Szrj
185038fd1498Szrj /* Free an SCC info structure pointed to by SI */
185138fd1498Szrj
~scc_info()185238fd1498Szrj scc_info::~scc_info ()
185338fd1498Szrj {
185438fd1498Szrj free (node_mapping);
185538fd1498Szrj free (dfs);
185638fd1498Szrj }
185738fd1498Szrj
185838fd1498Szrj
185938fd1498Szrj /* Find indirect cycles in GRAPH that occur, using strongly connected
186038fd1498Szrj components, and note them in the indirect cycles map.
186138fd1498Szrj
186238fd1498Szrj This technique comes from Ben Hardekopf and Calvin Lin,
186338fd1498Szrj "It Pays to be Lazy: Fast and Accurate Pointer Analysis for Millions of
186438fd1498Szrj Lines of Code", submitted to PLDI 2007. */
186538fd1498Szrj
186638fd1498Szrj static void
find_indirect_cycles(constraint_graph_t graph)186738fd1498Szrj find_indirect_cycles (constraint_graph_t graph)
186838fd1498Szrj {
186938fd1498Szrj unsigned int i;
187038fd1498Szrj unsigned int size = graph->size;
187138fd1498Szrj scc_info si (size);
187238fd1498Szrj
187338fd1498Szrj for (i = 0; i < MIN (LAST_REF_NODE, size); i ++ )
187438fd1498Szrj if (!bitmap_bit_p (si.visited, i) && find (i) == i)
187538fd1498Szrj scc_visit (graph, &si, i);
187638fd1498Szrj }
187738fd1498Szrj
187838fd1498Szrj /* Compute a topological ordering for GRAPH, and store the result in the
187938fd1498Szrj topo_info structure TI. */
188038fd1498Szrj
188138fd1498Szrj static void
compute_topo_order(constraint_graph_t graph,struct topo_info * ti)188238fd1498Szrj compute_topo_order (constraint_graph_t graph,
188338fd1498Szrj struct topo_info *ti)
188438fd1498Szrj {
188538fd1498Szrj unsigned int i;
188638fd1498Szrj unsigned int size = graph->size;
188738fd1498Szrj
188838fd1498Szrj for (i = 0; i != size; ++i)
188938fd1498Szrj if (!bitmap_bit_p (ti->visited, i) && find (i) == i)
189038fd1498Szrj topo_visit (graph, ti, i);
189138fd1498Szrj }
189238fd1498Szrj
189338fd1498Szrj /* Structure used to for hash value numbering of pointer equivalence
189438fd1498Szrj classes. */
189538fd1498Szrj
189638fd1498Szrj typedef struct equiv_class_label
189738fd1498Szrj {
189838fd1498Szrj hashval_t hashcode;
189938fd1498Szrj unsigned int equivalence_class;
190038fd1498Szrj bitmap labels;
190138fd1498Szrj } *equiv_class_label_t;
190238fd1498Szrj typedef const struct equiv_class_label *const_equiv_class_label_t;
190338fd1498Szrj
190438fd1498Szrj /* Equiv_class_label hashtable helpers. */
190538fd1498Szrj
190638fd1498Szrj struct equiv_class_hasher : free_ptr_hash <equiv_class_label>
190738fd1498Szrj {
190838fd1498Szrj static inline hashval_t hash (const equiv_class_label *);
190938fd1498Szrj static inline bool equal (const equiv_class_label *,
191038fd1498Szrj const equiv_class_label *);
191138fd1498Szrj };
191238fd1498Szrj
191338fd1498Szrj /* Hash function for a equiv_class_label_t */
191438fd1498Szrj
191538fd1498Szrj inline hashval_t
hash(const equiv_class_label * ecl)191638fd1498Szrj equiv_class_hasher::hash (const equiv_class_label *ecl)
191738fd1498Szrj {
191838fd1498Szrj return ecl->hashcode;
191938fd1498Szrj }
192038fd1498Szrj
192138fd1498Szrj /* Equality function for two equiv_class_label_t's. */
192238fd1498Szrj
192338fd1498Szrj inline bool
equal(const equiv_class_label * eql1,const equiv_class_label * eql2)192438fd1498Szrj equiv_class_hasher::equal (const equiv_class_label *eql1,
192538fd1498Szrj const equiv_class_label *eql2)
192638fd1498Szrj {
192738fd1498Szrj return (eql1->hashcode == eql2->hashcode
192838fd1498Szrj && bitmap_equal_p (eql1->labels, eql2->labels));
192938fd1498Szrj }
193038fd1498Szrj
193138fd1498Szrj /* A hashtable for mapping a bitmap of labels->pointer equivalence
193238fd1498Szrj classes. */
193338fd1498Szrj static hash_table<equiv_class_hasher> *pointer_equiv_class_table;
193438fd1498Szrj
193538fd1498Szrj /* A hashtable for mapping a bitmap of labels->location equivalence
193638fd1498Szrj classes. */
193738fd1498Szrj static hash_table<equiv_class_hasher> *location_equiv_class_table;
193838fd1498Szrj
193938fd1498Szrj /* Lookup a equivalence class in TABLE by the bitmap of LABELS with
194038fd1498Szrj hash HAS it contains. Sets *REF_LABELS to the bitmap LABELS
194138fd1498Szrj is equivalent to. */
194238fd1498Szrj
194338fd1498Szrj static equiv_class_label *
equiv_class_lookup_or_add(hash_table<equiv_class_hasher> * table,bitmap labels)194438fd1498Szrj equiv_class_lookup_or_add (hash_table<equiv_class_hasher> *table,
194538fd1498Szrj bitmap labels)
194638fd1498Szrj {
194738fd1498Szrj equiv_class_label **slot;
194838fd1498Szrj equiv_class_label ecl;
194938fd1498Szrj
195038fd1498Szrj ecl.labels = labels;
195138fd1498Szrj ecl.hashcode = bitmap_hash (labels);
195238fd1498Szrj slot = table->find_slot (&ecl, INSERT);
195338fd1498Szrj if (!*slot)
195438fd1498Szrj {
195538fd1498Szrj *slot = XNEW (struct equiv_class_label);
195638fd1498Szrj (*slot)->labels = labels;
195738fd1498Szrj (*slot)->hashcode = ecl.hashcode;
195838fd1498Szrj (*slot)->equivalence_class = 0;
195938fd1498Szrj }
196038fd1498Szrj
196138fd1498Szrj return *slot;
196238fd1498Szrj }
196338fd1498Szrj
196438fd1498Szrj /* Perform offline variable substitution.
196538fd1498Szrj
196638fd1498Szrj This is a worst case quadratic time way of identifying variables
196738fd1498Szrj that must have equivalent points-to sets, including those caused by
196838fd1498Szrj static cycles, and single entry subgraphs, in the constraint graph.
196938fd1498Szrj
197038fd1498Szrj The technique is described in "Exploiting Pointer and Location
197138fd1498Szrj Equivalence to Optimize Pointer Analysis. In the 14th International
197238fd1498Szrj Static Analysis Symposium (SAS), August 2007." It is known as the
197338fd1498Szrj "HU" algorithm, and is equivalent to value numbering the collapsed
197438fd1498Szrj constraint graph including evaluating unions.
197538fd1498Szrj
197638fd1498Szrj The general method of finding equivalence classes is as follows:
197738fd1498Szrj Add fake nodes (REF nodes) and edges for *a = b and a = *b constraints.
197838fd1498Szrj Initialize all non-REF nodes to be direct nodes.
197938fd1498Szrj For each constraint a = a U {b}, we set pts(a) = pts(a) u {fresh
198038fd1498Szrj variable}
198138fd1498Szrj For each constraint containing the dereference, we also do the same
198238fd1498Szrj thing.
198338fd1498Szrj
198438fd1498Szrj We then compute SCC's in the graph and unify nodes in the same SCC,
198538fd1498Szrj including pts sets.
198638fd1498Szrj
198738fd1498Szrj For each non-collapsed node x:
198838fd1498Szrj Visit all unvisited explicit incoming edges.
198938fd1498Szrj Ignoring all non-pointers, set pts(x) = Union of pts(a) for y
199038fd1498Szrj where y->x.
199138fd1498Szrj Lookup the equivalence class for pts(x).
199238fd1498Szrj If we found one, equivalence_class(x) = found class.
199338fd1498Szrj Otherwise, equivalence_class(x) = new class, and new_class is
199438fd1498Szrj added to the lookup table.
199538fd1498Szrj
199638fd1498Szrj All direct nodes with the same equivalence class can be replaced
199738fd1498Szrj with a single representative node.
199838fd1498Szrj All unlabeled nodes (label == 0) are not pointers and all edges
199938fd1498Szrj involving them can be eliminated.
200038fd1498Szrj We perform these optimizations during rewrite_constraints
200138fd1498Szrj
200238fd1498Szrj In addition to pointer equivalence class finding, we also perform
200338fd1498Szrj location equivalence class finding. This is the set of variables
200438fd1498Szrj that always appear together in points-to sets. We use this to
200538fd1498Szrj compress the size of the points-to sets. */
200638fd1498Szrj
200738fd1498Szrj /* Current maximum pointer equivalence class id. */
200838fd1498Szrj static int pointer_equiv_class;
200938fd1498Szrj
201038fd1498Szrj /* Current maximum location equivalence class id. */
201138fd1498Szrj static int location_equiv_class;
201238fd1498Szrj
201338fd1498Szrj /* Recursive routine to find strongly connected components in GRAPH,
201438fd1498Szrj and label it's nodes with DFS numbers. */
201538fd1498Szrj
201638fd1498Szrj static void
condense_visit(constraint_graph_t graph,struct scc_info * si,unsigned int n)201738fd1498Szrj condense_visit (constraint_graph_t graph, struct scc_info *si, unsigned int n)
201838fd1498Szrj {
201938fd1498Szrj unsigned int i;
202038fd1498Szrj bitmap_iterator bi;
202138fd1498Szrj unsigned int my_dfs;
202238fd1498Szrj
202338fd1498Szrj gcc_checking_assert (si->node_mapping[n] == n);
202438fd1498Szrj bitmap_set_bit (si->visited, n);
202538fd1498Szrj si->dfs[n] = si->current_index ++;
202638fd1498Szrj my_dfs = si->dfs[n];
202738fd1498Szrj
202838fd1498Szrj /* Visit all the successors. */
202938fd1498Szrj EXECUTE_IF_IN_NONNULL_BITMAP (graph->preds[n], 0, i, bi)
203038fd1498Szrj {
203138fd1498Szrj unsigned int w = si->node_mapping[i];
203238fd1498Szrj
203338fd1498Szrj if (bitmap_bit_p (si->deleted, w))
203438fd1498Szrj continue;
203538fd1498Szrj
203638fd1498Szrj if (!bitmap_bit_p (si->visited, w))
203738fd1498Szrj condense_visit (graph, si, w);
203838fd1498Szrj
203938fd1498Szrj unsigned int t = si->node_mapping[w];
204038fd1498Szrj gcc_checking_assert (si->node_mapping[n] == n);
204138fd1498Szrj if (si->dfs[t] < si->dfs[n])
204238fd1498Szrj si->dfs[n] = si->dfs[t];
204338fd1498Szrj }
204438fd1498Szrj
204538fd1498Szrj /* Visit all the implicit predecessors. */
204638fd1498Szrj EXECUTE_IF_IN_NONNULL_BITMAP (graph->implicit_preds[n], 0, i, bi)
204738fd1498Szrj {
204838fd1498Szrj unsigned int w = si->node_mapping[i];
204938fd1498Szrj
205038fd1498Szrj if (bitmap_bit_p (si->deleted, w))
205138fd1498Szrj continue;
205238fd1498Szrj
205338fd1498Szrj if (!bitmap_bit_p (si->visited, w))
205438fd1498Szrj condense_visit (graph, si, w);
205538fd1498Szrj
205638fd1498Szrj unsigned int t = si->node_mapping[w];
205738fd1498Szrj gcc_assert (si->node_mapping[n] == n);
205838fd1498Szrj if (si->dfs[t] < si->dfs[n])
205938fd1498Szrj si->dfs[n] = si->dfs[t];
206038fd1498Szrj }
206138fd1498Szrj
206238fd1498Szrj /* See if any components have been identified. */
206338fd1498Szrj if (si->dfs[n] == my_dfs)
206438fd1498Szrj {
206538fd1498Szrj while (si->scc_stack.length () != 0
206638fd1498Szrj && si->dfs[si->scc_stack.last ()] >= my_dfs)
206738fd1498Szrj {
206838fd1498Szrj unsigned int w = si->scc_stack.pop ();
206938fd1498Szrj si->node_mapping[w] = n;
207038fd1498Szrj
207138fd1498Szrj if (!bitmap_bit_p (graph->direct_nodes, w))
207238fd1498Szrj bitmap_clear_bit (graph->direct_nodes, n);
207338fd1498Szrj
207438fd1498Szrj /* Unify our nodes. */
207538fd1498Szrj if (graph->preds[w])
207638fd1498Szrj {
207738fd1498Szrj if (!graph->preds[n])
207838fd1498Szrj graph->preds[n] = BITMAP_ALLOC (&predbitmap_obstack);
207938fd1498Szrj bitmap_ior_into (graph->preds[n], graph->preds[w]);
208038fd1498Szrj }
208138fd1498Szrj if (graph->implicit_preds[w])
208238fd1498Szrj {
208338fd1498Szrj if (!graph->implicit_preds[n])
208438fd1498Szrj graph->implicit_preds[n] = BITMAP_ALLOC (&predbitmap_obstack);
208538fd1498Szrj bitmap_ior_into (graph->implicit_preds[n],
208638fd1498Szrj graph->implicit_preds[w]);
208738fd1498Szrj }
208838fd1498Szrj if (graph->points_to[w])
208938fd1498Szrj {
209038fd1498Szrj if (!graph->points_to[n])
209138fd1498Szrj graph->points_to[n] = BITMAP_ALLOC (&predbitmap_obstack);
209238fd1498Szrj bitmap_ior_into (graph->points_to[n],
209338fd1498Szrj graph->points_to[w]);
209438fd1498Szrj }
209538fd1498Szrj }
209638fd1498Szrj bitmap_set_bit (si->deleted, n);
209738fd1498Szrj }
209838fd1498Szrj else
209938fd1498Szrj si->scc_stack.safe_push (n);
210038fd1498Szrj }
210138fd1498Szrj
210238fd1498Szrj /* Label pointer equivalences.
210338fd1498Szrj
210438fd1498Szrj This performs a value numbering of the constraint graph to
210538fd1498Szrj discover which variables will always have the same points-to sets
210638fd1498Szrj under the current set of constraints.
210738fd1498Szrj
210838fd1498Szrj The way it value numbers is to store the set of points-to bits
210938fd1498Szrj generated by the constraints and graph edges. This is just used as a
211038fd1498Szrj hash and equality comparison. The *actual set of points-to bits* is
211138fd1498Szrj completely irrelevant, in that we don't care about being able to
211238fd1498Szrj extract them later.
211338fd1498Szrj
211438fd1498Szrj The equality values (currently bitmaps) just have to satisfy a few
211538fd1498Szrj constraints, the main ones being:
211638fd1498Szrj 1. The combining operation must be order independent.
211738fd1498Szrj 2. The end result of a given set of operations must be unique iff the
211838fd1498Szrj combination of input values is unique
211938fd1498Szrj 3. Hashable. */
212038fd1498Szrj
212138fd1498Szrj static void
label_visit(constraint_graph_t graph,struct scc_info * si,unsigned int n)212238fd1498Szrj label_visit (constraint_graph_t graph, struct scc_info *si, unsigned int n)
212338fd1498Szrj {
212438fd1498Szrj unsigned int i, first_pred;
212538fd1498Szrj bitmap_iterator bi;
212638fd1498Szrj
212738fd1498Szrj bitmap_set_bit (si->visited, n);
212838fd1498Szrj
212938fd1498Szrj /* Label and union our incoming edges's points to sets. */
213038fd1498Szrj first_pred = -1U;
213138fd1498Szrj EXECUTE_IF_IN_NONNULL_BITMAP (graph->preds[n], 0, i, bi)
213238fd1498Szrj {
213338fd1498Szrj unsigned int w = si->node_mapping[i];
213438fd1498Szrj if (!bitmap_bit_p (si->visited, w))
213538fd1498Szrj label_visit (graph, si, w);
213638fd1498Szrj
213738fd1498Szrj /* Skip unused edges */
213838fd1498Szrj if (w == n || graph->pointer_label[w] == 0)
213938fd1498Szrj continue;
214038fd1498Szrj
214138fd1498Szrj if (graph->points_to[w])
214238fd1498Szrj {
214338fd1498Szrj if (!graph->points_to[n])
214438fd1498Szrj {
214538fd1498Szrj if (first_pred == -1U)
214638fd1498Szrj first_pred = w;
214738fd1498Szrj else
214838fd1498Szrj {
214938fd1498Szrj graph->points_to[n] = BITMAP_ALLOC (&predbitmap_obstack);
215038fd1498Szrj bitmap_ior (graph->points_to[n],
215138fd1498Szrj graph->points_to[first_pred],
215238fd1498Szrj graph->points_to[w]);
215338fd1498Szrj }
215438fd1498Szrj }
215538fd1498Szrj else
215638fd1498Szrj bitmap_ior_into (graph->points_to[n], graph->points_to[w]);
215738fd1498Szrj }
215838fd1498Szrj }
215938fd1498Szrj
216038fd1498Szrj /* Indirect nodes get fresh variables and a new pointer equiv class. */
216138fd1498Szrj if (!bitmap_bit_p (graph->direct_nodes, n))
216238fd1498Szrj {
216338fd1498Szrj if (!graph->points_to[n])
216438fd1498Szrj {
216538fd1498Szrj graph->points_to[n] = BITMAP_ALLOC (&predbitmap_obstack);
216638fd1498Szrj if (first_pred != -1U)
216738fd1498Szrj bitmap_copy (graph->points_to[n], graph->points_to[first_pred]);
216838fd1498Szrj }
216938fd1498Szrj bitmap_set_bit (graph->points_to[n], FIRST_REF_NODE + n);
217038fd1498Szrj graph->pointer_label[n] = pointer_equiv_class++;
217138fd1498Szrj equiv_class_label_t ecl;
217238fd1498Szrj ecl = equiv_class_lookup_or_add (pointer_equiv_class_table,
217338fd1498Szrj graph->points_to[n]);
217438fd1498Szrj ecl->equivalence_class = graph->pointer_label[n];
217538fd1498Szrj return;
217638fd1498Szrj }
217738fd1498Szrj
217838fd1498Szrj /* If there was only a single non-empty predecessor the pointer equiv
217938fd1498Szrj class is the same. */
218038fd1498Szrj if (!graph->points_to[n])
218138fd1498Szrj {
218238fd1498Szrj if (first_pred != -1U)
218338fd1498Szrj {
218438fd1498Szrj graph->pointer_label[n] = graph->pointer_label[first_pred];
218538fd1498Szrj graph->points_to[n] = graph->points_to[first_pred];
218638fd1498Szrj }
218738fd1498Szrj return;
218838fd1498Szrj }
218938fd1498Szrj
219038fd1498Szrj if (!bitmap_empty_p (graph->points_to[n]))
219138fd1498Szrj {
219238fd1498Szrj equiv_class_label_t ecl;
219338fd1498Szrj ecl = equiv_class_lookup_or_add (pointer_equiv_class_table,
219438fd1498Szrj graph->points_to[n]);
219538fd1498Szrj if (ecl->equivalence_class == 0)
219638fd1498Szrj ecl->equivalence_class = pointer_equiv_class++;
219738fd1498Szrj else
219838fd1498Szrj {
219938fd1498Szrj BITMAP_FREE (graph->points_to[n]);
220038fd1498Szrj graph->points_to[n] = ecl->labels;
220138fd1498Szrj }
220238fd1498Szrj graph->pointer_label[n] = ecl->equivalence_class;
220338fd1498Szrj }
220438fd1498Szrj }
220538fd1498Szrj
220638fd1498Szrj /* Print the pred graph in dot format. */
220738fd1498Szrj
220838fd1498Szrj static void
dump_pred_graph(struct scc_info * si,FILE * file)220938fd1498Szrj dump_pred_graph (struct scc_info *si, FILE *file)
221038fd1498Szrj {
221138fd1498Szrj unsigned int i;
221238fd1498Szrj
221338fd1498Szrj /* Only print the graph if it has already been initialized: */
221438fd1498Szrj if (!graph)
221538fd1498Szrj return;
221638fd1498Szrj
221738fd1498Szrj /* Prints the header of the dot file: */
221838fd1498Szrj fprintf (file, "strict digraph {\n");
221938fd1498Szrj fprintf (file, " node [\n shape = box\n ]\n");
222038fd1498Szrj fprintf (file, " edge [\n fontsize = \"12\"\n ]\n");
222138fd1498Szrj fprintf (file, "\n // List of nodes and complex constraints in "
222238fd1498Szrj "the constraint graph:\n");
222338fd1498Szrj
222438fd1498Szrj /* The next lines print the nodes in the graph together with the
222538fd1498Szrj complex constraints attached to them. */
222638fd1498Szrj for (i = 1; i < graph->size; i++)
222738fd1498Szrj {
222838fd1498Szrj if (i == FIRST_REF_NODE)
222938fd1498Szrj continue;
223038fd1498Szrj if (si->node_mapping[i] != i)
223138fd1498Szrj continue;
223238fd1498Szrj if (i < FIRST_REF_NODE)
223338fd1498Szrj fprintf (file, "\"%s\"", get_varinfo (i)->name);
223438fd1498Szrj else
223538fd1498Szrj fprintf (file, "\"*%s\"", get_varinfo (i - FIRST_REF_NODE)->name);
223638fd1498Szrj if (graph->points_to[i]
223738fd1498Szrj && !bitmap_empty_p (graph->points_to[i]))
223838fd1498Szrj {
223938fd1498Szrj if (i < FIRST_REF_NODE)
224038fd1498Szrj fprintf (file, "[label=\"%s = {", get_varinfo (i)->name);
224138fd1498Szrj else
224238fd1498Szrj fprintf (file, "[label=\"*%s = {",
224338fd1498Szrj get_varinfo (i - FIRST_REF_NODE)->name);
224438fd1498Szrj unsigned j;
224538fd1498Szrj bitmap_iterator bi;
224638fd1498Szrj EXECUTE_IF_SET_IN_BITMAP (graph->points_to[i], 0, j, bi)
224738fd1498Szrj fprintf (file, " %d", j);
224838fd1498Szrj fprintf (file, " }\"]");
224938fd1498Szrj }
225038fd1498Szrj fprintf (file, ";\n");
225138fd1498Szrj }
225238fd1498Szrj
225338fd1498Szrj /* Go over the edges. */
225438fd1498Szrj fprintf (file, "\n // Edges in the constraint graph:\n");
225538fd1498Szrj for (i = 1; i < graph->size; i++)
225638fd1498Szrj {
225738fd1498Szrj unsigned j;
225838fd1498Szrj bitmap_iterator bi;
225938fd1498Szrj if (si->node_mapping[i] != i)
226038fd1498Szrj continue;
226138fd1498Szrj EXECUTE_IF_IN_NONNULL_BITMAP (graph->preds[i], 0, j, bi)
226238fd1498Szrj {
226338fd1498Szrj unsigned from = si->node_mapping[j];
226438fd1498Szrj if (from < FIRST_REF_NODE)
226538fd1498Szrj fprintf (file, "\"%s\"", get_varinfo (from)->name);
226638fd1498Szrj else
226738fd1498Szrj fprintf (file, "\"*%s\"", get_varinfo (from - FIRST_REF_NODE)->name);
226838fd1498Szrj fprintf (file, " -> ");
226938fd1498Szrj if (i < FIRST_REF_NODE)
227038fd1498Szrj fprintf (file, "\"%s\"", get_varinfo (i)->name);
227138fd1498Szrj else
227238fd1498Szrj fprintf (file, "\"*%s\"", get_varinfo (i - FIRST_REF_NODE)->name);
227338fd1498Szrj fprintf (file, ";\n");
227438fd1498Szrj }
227538fd1498Szrj }
227638fd1498Szrj
227738fd1498Szrj /* Prints the tail of the dot file. */
227838fd1498Szrj fprintf (file, "}\n");
227938fd1498Szrj }
228038fd1498Szrj
228138fd1498Szrj /* Perform offline variable substitution, discovering equivalence
228238fd1498Szrj classes, and eliminating non-pointer variables. */
228338fd1498Szrj
228438fd1498Szrj static struct scc_info *
perform_var_substitution(constraint_graph_t graph)228538fd1498Szrj perform_var_substitution (constraint_graph_t graph)
228638fd1498Szrj {
228738fd1498Szrj unsigned int i;
228838fd1498Szrj unsigned int size = graph->size;
228938fd1498Szrj scc_info *si = new scc_info (size);
229038fd1498Szrj
229138fd1498Szrj bitmap_obstack_initialize (&iteration_obstack);
229238fd1498Szrj pointer_equiv_class_table = new hash_table<equiv_class_hasher> (511);
229338fd1498Szrj location_equiv_class_table
229438fd1498Szrj = new hash_table<equiv_class_hasher> (511);
229538fd1498Szrj pointer_equiv_class = 1;
229638fd1498Szrj location_equiv_class = 1;
229738fd1498Szrj
229838fd1498Szrj /* Condense the nodes, which means to find SCC's, count incoming
229938fd1498Szrj predecessors, and unite nodes in SCC's. */
230038fd1498Szrj for (i = 1; i < FIRST_REF_NODE; i++)
230138fd1498Szrj if (!bitmap_bit_p (si->visited, si->node_mapping[i]))
230238fd1498Szrj condense_visit (graph, si, si->node_mapping[i]);
230338fd1498Szrj
230438fd1498Szrj if (dump_file && (dump_flags & TDF_GRAPH))
230538fd1498Szrj {
230638fd1498Szrj fprintf (dump_file, "\n\n// The constraint graph before var-substitution "
230738fd1498Szrj "in dot format:\n");
230838fd1498Szrj dump_pred_graph (si, dump_file);
230938fd1498Szrj fprintf (dump_file, "\n\n");
231038fd1498Szrj }
231138fd1498Szrj
231238fd1498Szrj bitmap_clear (si->visited);
231338fd1498Szrj /* Actually the label the nodes for pointer equivalences */
231438fd1498Szrj for (i = 1; i < FIRST_REF_NODE; i++)
231538fd1498Szrj if (!bitmap_bit_p (si->visited, si->node_mapping[i]))
231638fd1498Szrj label_visit (graph, si, si->node_mapping[i]);
231738fd1498Szrj
231838fd1498Szrj /* Calculate location equivalence labels. */
231938fd1498Szrj for (i = 1; i < FIRST_REF_NODE; i++)
232038fd1498Szrj {
232138fd1498Szrj bitmap pointed_by;
232238fd1498Szrj bitmap_iterator bi;
232338fd1498Szrj unsigned int j;
232438fd1498Szrj
232538fd1498Szrj if (!graph->pointed_by[i])
232638fd1498Szrj continue;
232738fd1498Szrj pointed_by = BITMAP_ALLOC (&iteration_obstack);
232838fd1498Szrj
232938fd1498Szrj /* Translate the pointed-by mapping for pointer equivalence
233038fd1498Szrj labels. */
233138fd1498Szrj EXECUTE_IF_SET_IN_BITMAP (graph->pointed_by[i], 0, j, bi)
233238fd1498Szrj {
233338fd1498Szrj bitmap_set_bit (pointed_by,
233438fd1498Szrj graph->pointer_label[si->node_mapping[j]]);
233538fd1498Szrj }
233638fd1498Szrj /* The original pointed_by is now dead. */
233738fd1498Szrj BITMAP_FREE (graph->pointed_by[i]);
233838fd1498Szrj
233938fd1498Szrj /* Look up the location equivalence label if one exists, or make
234038fd1498Szrj one otherwise. */
234138fd1498Szrj equiv_class_label_t ecl;
234238fd1498Szrj ecl = equiv_class_lookup_or_add (location_equiv_class_table, pointed_by);
234338fd1498Szrj if (ecl->equivalence_class == 0)
234438fd1498Szrj ecl->equivalence_class = location_equiv_class++;
234538fd1498Szrj else
234638fd1498Szrj {
234738fd1498Szrj if (dump_file && (dump_flags & TDF_DETAILS))
234838fd1498Szrj fprintf (dump_file, "Found location equivalence for node %s\n",
234938fd1498Szrj get_varinfo (i)->name);
235038fd1498Szrj BITMAP_FREE (pointed_by);
235138fd1498Szrj }
235238fd1498Szrj graph->loc_label[i] = ecl->equivalence_class;
235338fd1498Szrj
235438fd1498Szrj }
235538fd1498Szrj
235638fd1498Szrj if (dump_file && (dump_flags & TDF_DETAILS))
235738fd1498Szrj for (i = 1; i < FIRST_REF_NODE; i++)
235838fd1498Szrj {
235938fd1498Szrj unsigned j = si->node_mapping[i];
236038fd1498Szrj if (j != i)
236138fd1498Szrj {
236238fd1498Szrj fprintf (dump_file, "%s node id %d ",
236338fd1498Szrj bitmap_bit_p (graph->direct_nodes, i)
236438fd1498Szrj ? "Direct" : "Indirect", i);
236538fd1498Szrj if (i < FIRST_REF_NODE)
236638fd1498Szrj fprintf (dump_file, "\"%s\"", get_varinfo (i)->name);
236738fd1498Szrj else
236838fd1498Szrj fprintf (dump_file, "\"*%s\"",
236938fd1498Szrj get_varinfo (i - FIRST_REF_NODE)->name);
237038fd1498Szrj fprintf (dump_file, " mapped to SCC leader node id %d ", j);
237138fd1498Szrj if (j < FIRST_REF_NODE)
237238fd1498Szrj fprintf (dump_file, "\"%s\"\n", get_varinfo (j)->name);
237338fd1498Szrj else
237438fd1498Szrj fprintf (dump_file, "\"*%s\"\n",
237538fd1498Szrj get_varinfo (j - FIRST_REF_NODE)->name);
237638fd1498Szrj }
237738fd1498Szrj else
237838fd1498Szrj {
237938fd1498Szrj fprintf (dump_file,
238038fd1498Szrj "Equivalence classes for %s node id %d ",
238138fd1498Szrj bitmap_bit_p (graph->direct_nodes, i)
238238fd1498Szrj ? "direct" : "indirect", i);
238338fd1498Szrj if (i < FIRST_REF_NODE)
238438fd1498Szrj fprintf (dump_file, "\"%s\"", get_varinfo (i)->name);
238538fd1498Szrj else
238638fd1498Szrj fprintf (dump_file, "\"*%s\"",
238738fd1498Szrj get_varinfo (i - FIRST_REF_NODE)->name);
238838fd1498Szrj fprintf (dump_file,
238938fd1498Szrj ": pointer %d, location %d\n",
239038fd1498Szrj graph->pointer_label[i], graph->loc_label[i]);
239138fd1498Szrj }
239238fd1498Szrj }
239338fd1498Szrj
239438fd1498Szrj /* Quickly eliminate our non-pointer variables. */
239538fd1498Szrj
239638fd1498Szrj for (i = 1; i < FIRST_REF_NODE; i++)
239738fd1498Szrj {
239838fd1498Szrj unsigned int node = si->node_mapping[i];
239938fd1498Szrj
240038fd1498Szrj if (graph->pointer_label[node] == 0)
240138fd1498Szrj {
240238fd1498Szrj if (dump_file && (dump_flags & TDF_DETAILS))
240338fd1498Szrj fprintf (dump_file,
240438fd1498Szrj "%s is a non-pointer variable, eliminating edges.\n",
240538fd1498Szrj get_varinfo (node)->name);
240638fd1498Szrj stats.nonpointer_vars++;
240738fd1498Szrj clear_edges_for_node (graph, node);
240838fd1498Szrj }
240938fd1498Szrj }
241038fd1498Szrj
241138fd1498Szrj return si;
241238fd1498Szrj }
241338fd1498Szrj
241438fd1498Szrj /* Free information that was only necessary for variable
241538fd1498Szrj substitution. */
241638fd1498Szrj
241738fd1498Szrj static void
free_var_substitution_info(struct scc_info * si)241838fd1498Szrj free_var_substitution_info (struct scc_info *si)
241938fd1498Szrj {
242038fd1498Szrj delete si;
242138fd1498Szrj free (graph->pointer_label);
242238fd1498Szrj free (graph->loc_label);
242338fd1498Szrj free (graph->pointed_by);
242438fd1498Szrj free (graph->points_to);
242538fd1498Szrj free (graph->eq_rep);
242638fd1498Szrj sbitmap_free (graph->direct_nodes);
242738fd1498Szrj delete pointer_equiv_class_table;
242838fd1498Szrj pointer_equiv_class_table = NULL;
242938fd1498Szrj delete location_equiv_class_table;
243038fd1498Szrj location_equiv_class_table = NULL;
243138fd1498Szrj bitmap_obstack_release (&iteration_obstack);
243238fd1498Szrj }
243338fd1498Szrj
243438fd1498Szrj /* Return an existing node that is equivalent to NODE, which has
243538fd1498Szrj equivalence class LABEL, if one exists. Return NODE otherwise. */
243638fd1498Szrj
243738fd1498Szrj static unsigned int
find_equivalent_node(constraint_graph_t graph,unsigned int node,unsigned int label)243838fd1498Szrj find_equivalent_node (constraint_graph_t graph,
243938fd1498Szrj unsigned int node, unsigned int label)
244038fd1498Szrj {
244138fd1498Szrj /* If the address version of this variable is unused, we can
244238fd1498Szrj substitute it for anything else with the same label.
244338fd1498Szrj Otherwise, we know the pointers are equivalent, but not the
244438fd1498Szrj locations, and we can unite them later. */
244538fd1498Szrj
244638fd1498Szrj if (!bitmap_bit_p (graph->address_taken, node))
244738fd1498Szrj {
244838fd1498Szrj gcc_checking_assert (label < graph->size);
244938fd1498Szrj
245038fd1498Szrj if (graph->eq_rep[label] != -1)
245138fd1498Szrj {
245238fd1498Szrj /* Unify the two variables since we know they are equivalent. */
245338fd1498Szrj if (unite (graph->eq_rep[label], node))
245438fd1498Szrj unify_nodes (graph, graph->eq_rep[label], node, false);
245538fd1498Szrj return graph->eq_rep[label];
245638fd1498Szrj }
245738fd1498Szrj else
245838fd1498Szrj {
245938fd1498Szrj graph->eq_rep[label] = node;
246038fd1498Szrj graph->pe_rep[label] = node;
246138fd1498Szrj }
246238fd1498Szrj }
246338fd1498Szrj else
246438fd1498Szrj {
246538fd1498Szrj gcc_checking_assert (label < graph->size);
246638fd1498Szrj graph->pe[node] = label;
246738fd1498Szrj if (graph->pe_rep[label] == -1)
246838fd1498Szrj graph->pe_rep[label] = node;
246938fd1498Szrj }
247038fd1498Szrj
247138fd1498Szrj return node;
247238fd1498Szrj }
247338fd1498Szrj
247438fd1498Szrj /* Unite pointer equivalent but not location equivalent nodes in
247538fd1498Szrj GRAPH. This may only be performed once variable substitution is
247638fd1498Szrj finished. */
247738fd1498Szrj
247838fd1498Szrj static void
unite_pointer_equivalences(constraint_graph_t graph)247938fd1498Szrj unite_pointer_equivalences (constraint_graph_t graph)
248038fd1498Szrj {
248138fd1498Szrj unsigned int i;
248238fd1498Szrj
248338fd1498Szrj /* Go through the pointer equivalences and unite them to their
248438fd1498Szrj representative, if they aren't already. */
248538fd1498Szrj for (i = 1; i < FIRST_REF_NODE; i++)
248638fd1498Szrj {
248738fd1498Szrj unsigned int label = graph->pe[i];
248838fd1498Szrj if (label)
248938fd1498Szrj {
249038fd1498Szrj int label_rep = graph->pe_rep[label];
249138fd1498Szrj
249238fd1498Szrj if (label_rep == -1)
249338fd1498Szrj continue;
249438fd1498Szrj
249538fd1498Szrj label_rep = find (label_rep);
249638fd1498Szrj if (label_rep >= 0 && unite (label_rep, find (i)))
249738fd1498Szrj unify_nodes (graph, label_rep, i, false);
249838fd1498Szrj }
249938fd1498Szrj }
250038fd1498Szrj }
250138fd1498Szrj
250238fd1498Szrj /* Move complex constraints to the GRAPH nodes they belong to. */
250338fd1498Szrj
250438fd1498Szrj static void
move_complex_constraints(constraint_graph_t graph)250538fd1498Szrj move_complex_constraints (constraint_graph_t graph)
250638fd1498Szrj {
250738fd1498Szrj int i;
250838fd1498Szrj constraint_t c;
250938fd1498Szrj
251038fd1498Szrj FOR_EACH_VEC_ELT (constraints, i, c)
251138fd1498Szrj {
251238fd1498Szrj if (c)
251338fd1498Szrj {
251438fd1498Szrj struct constraint_expr lhs = c->lhs;
251538fd1498Szrj struct constraint_expr rhs = c->rhs;
251638fd1498Szrj
251738fd1498Szrj if (lhs.type == DEREF)
251838fd1498Szrj {
251938fd1498Szrj insert_into_complex (graph, lhs.var, c);
252038fd1498Szrj }
252138fd1498Szrj else if (rhs.type == DEREF)
252238fd1498Szrj {
252338fd1498Szrj if (!(get_varinfo (lhs.var)->is_special_var))
252438fd1498Szrj insert_into_complex (graph, rhs.var, c);
252538fd1498Szrj }
252638fd1498Szrj else if (rhs.type != ADDRESSOF && lhs.var > anything_id
252738fd1498Szrj && (lhs.offset != 0 || rhs.offset != 0))
252838fd1498Szrj {
252938fd1498Szrj insert_into_complex (graph, rhs.var, c);
253038fd1498Szrj }
253138fd1498Szrj }
253238fd1498Szrj }
253338fd1498Szrj }
253438fd1498Szrj
253538fd1498Szrj
253638fd1498Szrj /* Optimize and rewrite complex constraints while performing
253738fd1498Szrj collapsing of equivalent nodes. SI is the SCC_INFO that is the
253838fd1498Szrj result of perform_variable_substitution. */
253938fd1498Szrj
254038fd1498Szrj static void
rewrite_constraints(constraint_graph_t graph,struct scc_info * si)254138fd1498Szrj rewrite_constraints (constraint_graph_t graph,
254238fd1498Szrj struct scc_info *si)
254338fd1498Szrj {
254438fd1498Szrj int i;
254538fd1498Szrj constraint_t c;
254638fd1498Szrj
254738fd1498Szrj if (flag_checking)
254838fd1498Szrj {
254938fd1498Szrj for (unsigned int j = 0; j < graph->size; j++)
255038fd1498Szrj gcc_assert (find (j) == j);
255138fd1498Szrj }
255238fd1498Szrj
255338fd1498Szrj FOR_EACH_VEC_ELT (constraints, i, c)
255438fd1498Szrj {
255538fd1498Szrj struct constraint_expr lhs = c->lhs;
255638fd1498Szrj struct constraint_expr rhs = c->rhs;
255738fd1498Szrj unsigned int lhsvar = find (lhs.var);
255838fd1498Szrj unsigned int rhsvar = find (rhs.var);
255938fd1498Szrj unsigned int lhsnode, rhsnode;
256038fd1498Szrj unsigned int lhslabel, rhslabel;
256138fd1498Szrj
256238fd1498Szrj lhsnode = si->node_mapping[lhsvar];
256338fd1498Szrj rhsnode = si->node_mapping[rhsvar];
256438fd1498Szrj lhslabel = graph->pointer_label[lhsnode];
256538fd1498Szrj rhslabel = graph->pointer_label[rhsnode];
256638fd1498Szrj
256738fd1498Szrj /* See if it is really a non-pointer variable, and if so, ignore
256838fd1498Szrj the constraint. */
256938fd1498Szrj if (lhslabel == 0)
257038fd1498Szrj {
257138fd1498Szrj if (dump_file && (dump_flags & TDF_DETAILS))
257238fd1498Szrj {
257338fd1498Szrj
257438fd1498Szrj fprintf (dump_file, "%s is a non-pointer variable, "
257538fd1498Szrj "ignoring constraint:",
257638fd1498Szrj get_varinfo (lhs.var)->name);
257738fd1498Szrj dump_constraint (dump_file, c);
257838fd1498Szrj fprintf (dump_file, "\n");
257938fd1498Szrj }
258038fd1498Szrj constraints[i] = NULL;
258138fd1498Szrj continue;
258238fd1498Szrj }
258338fd1498Szrj
258438fd1498Szrj if (rhslabel == 0)
258538fd1498Szrj {
258638fd1498Szrj if (dump_file && (dump_flags & TDF_DETAILS))
258738fd1498Szrj {
258838fd1498Szrj
258938fd1498Szrj fprintf (dump_file, "%s is a non-pointer variable, "
259038fd1498Szrj "ignoring constraint:",
259138fd1498Szrj get_varinfo (rhs.var)->name);
259238fd1498Szrj dump_constraint (dump_file, c);
259338fd1498Szrj fprintf (dump_file, "\n");
259438fd1498Szrj }
259538fd1498Szrj constraints[i] = NULL;
259638fd1498Szrj continue;
259738fd1498Szrj }
259838fd1498Szrj
259938fd1498Szrj lhsvar = find_equivalent_node (graph, lhsvar, lhslabel);
260038fd1498Szrj rhsvar = find_equivalent_node (graph, rhsvar, rhslabel);
260138fd1498Szrj c->lhs.var = lhsvar;
260238fd1498Szrj c->rhs.var = rhsvar;
260338fd1498Szrj }
260438fd1498Szrj }
260538fd1498Szrj
260638fd1498Szrj /* Eliminate indirect cycles involving NODE. Return true if NODE was
260738fd1498Szrj part of an SCC, false otherwise. */
260838fd1498Szrj
260938fd1498Szrj static bool
eliminate_indirect_cycles(unsigned int node)261038fd1498Szrj eliminate_indirect_cycles (unsigned int node)
261138fd1498Szrj {
261238fd1498Szrj if (graph->indirect_cycles[node] != -1
261338fd1498Szrj && !bitmap_empty_p (get_varinfo (node)->solution))
261438fd1498Szrj {
261538fd1498Szrj unsigned int i;
261638fd1498Szrj auto_vec<unsigned> queue;
261738fd1498Szrj int queuepos;
261838fd1498Szrj unsigned int to = find (graph->indirect_cycles[node]);
261938fd1498Szrj bitmap_iterator bi;
262038fd1498Szrj
262138fd1498Szrj /* We can't touch the solution set and call unify_nodes
262238fd1498Szrj at the same time, because unify_nodes is going to do
262338fd1498Szrj bitmap unions into it. */
262438fd1498Szrj
262538fd1498Szrj EXECUTE_IF_SET_IN_BITMAP (get_varinfo (node)->solution, 0, i, bi)
262638fd1498Szrj {
262738fd1498Szrj if (find (i) == i && i != to)
262838fd1498Szrj {
262938fd1498Szrj if (unite (to, i))
263038fd1498Szrj queue.safe_push (i);
263138fd1498Szrj }
263238fd1498Szrj }
263338fd1498Szrj
263438fd1498Szrj for (queuepos = 0;
263538fd1498Szrj queue.iterate (queuepos, &i);
263638fd1498Szrj queuepos++)
263738fd1498Szrj {
263838fd1498Szrj unify_nodes (graph, to, i, true);
263938fd1498Szrj }
264038fd1498Szrj return true;
264138fd1498Szrj }
264238fd1498Szrj return false;
264338fd1498Szrj }
264438fd1498Szrj
264538fd1498Szrj /* Solve the constraint graph GRAPH using our worklist solver.
264638fd1498Szrj This is based on the PW* family of solvers from the "Efficient Field
264738fd1498Szrj Sensitive Pointer Analysis for C" paper.
264838fd1498Szrj It works by iterating over all the graph nodes, processing the complex
264938fd1498Szrj constraints and propagating the copy constraints, until everything stops
265038fd1498Szrj changed. This corresponds to steps 6-8 in the solving list given above. */
265138fd1498Szrj
265238fd1498Szrj static void
solve_graph(constraint_graph_t graph)265338fd1498Szrj solve_graph (constraint_graph_t graph)
265438fd1498Szrj {
265538fd1498Szrj unsigned int size = graph->size;
265638fd1498Szrj unsigned int i;
265738fd1498Szrj bitmap pts;
265838fd1498Szrj
265938fd1498Szrj changed = BITMAP_ALLOC (NULL);
266038fd1498Szrj
266138fd1498Szrj /* Mark all initial non-collapsed nodes as changed. */
266238fd1498Szrj for (i = 1; i < size; i++)
266338fd1498Szrj {
266438fd1498Szrj varinfo_t ivi = get_varinfo (i);
266538fd1498Szrj if (find (i) == i && !bitmap_empty_p (ivi->solution)
266638fd1498Szrj && ((graph->succs[i] && !bitmap_empty_p (graph->succs[i]))
266738fd1498Szrj || graph->complex[i].length () > 0))
266838fd1498Szrj bitmap_set_bit (changed, i);
266938fd1498Szrj }
267038fd1498Szrj
267138fd1498Szrj /* Allocate a bitmap to be used to store the changed bits. */
267238fd1498Szrj pts = BITMAP_ALLOC (&pta_obstack);
267338fd1498Szrj
267438fd1498Szrj while (!bitmap_empty_p (changed))
267538fd1498Szrj {
267638fd1498Szrj unsigned int i;
267738fd1498Szrj struct topo_info *ti = init_topo_info ();
267838fd1498Szrj stats.iterations++;
267938fd1498Szrj
268038fd1498Szrj bitmap_obstack_initialize (&iteration_obstack);
268138fd1498Szrj
268238fd1498Szrj compute_topo_order (graph, ti);
268338fd1498Szrj
268438fd1498Szrj while (ti->topo_order.length () != 0)
268538fd1498Szrj {
268638fd1498Szrj
268738fd1498Szrj i = ti->topo_order.pop ();
268838fd1498Szrj
268938fd1498Szrj /* If this variable is not a representative, skip it. */
269038fd1498Szrj if (find (i) != i)
269138fd1498Szrj continue;
269238fd1498Szrj
269338fd1498Szrj /* In certain indirect cycle cases, we may merge this
269438fd1498Szrj variable to another. */
269538fd1498Szrj if (eliminate_indirect_cycles (i) && find (i) != i)
269638fd1498Szrj continue;
269738fd1498Szrj
269838fd1498Szrj /* If the node has changed, we need to process the
269938fd1498Szrj complex constraints and outgoing edges again. */
270038fd1498Szrj if (bitmap_clear_bit (changed, i))
270138fd1498Szrj {
270238fd1498Szrj unsigned int j;
270338fd1498Szrj constraint_t c;
270438fd1498Szrj bitmap solution;
270538fd1498Szrj vec<constraint_t> complex = graph->complex[i];
270638fd1498Szrj varinfo_t vi = get_varinfo (i);
270738fd1498Szrj bool solution_empty;
270838fd1498Szrj
270938fd1498Szrj /* Compute the changed set of solution bits. If anything
271038fd1498Szrj is in the solution just propagate that. */
271138fd1498Szrj if (bitmap_bit_p (vi->solution, anything_id))
271238fd1498Szrj {
271338fd1498Szrj /* If anything is also in the old solution there is
271438fd1498Szrj nothing to do.
271538fd1498Szrj ??? But we shouldn't ended up with "changed" set ... */
271638fd1498Szrj if (vi->oldsolution
271738fd1498Szrj && bitmap_bit_p (vi->oldsolution, anything_id))
271838fd1498Szrj continue;
271938fd1498Szrj bitmap_copy (pts, get_varinfo (find (anything_id))->solution);
272038fd1498Szrj }
272138fd1498Szrj else if (vi->oldsolution)
272238fd1498Szrj bitmap_and_compl (pts, vi->solution, vi->oldsolution);
272338fd1498Szrj else
272438fd1498Szrj bitmap_copy (pts, vi->solution);
272538fd1498Szrj
272638fd1498Szrj if (bitmap_empty_p (pts))
272738fd1498Szrj continue;
272838fd1498Szrj
272938fd1498Szrj if (vi->oldsolution)
273038fd1498Szrj bitmap_ior_into (vi->oldsolution, pts);
273138fd1498Szrj else
273238fd1498Szrj {
273338fd1498Szrj vi->oldsolution = BITMAP_ALLOC (&oldpta_obstack);
273438fd1498Szrj bitmap_copy (vi->oldsolution, pts);
273538fd1498Szrj }
273638fd1498Szrj
273738fd1498Szrj solution = vi->solution;
273838fd1498Szrj solution_empty = bitmap_empty_p (solution);
273938fd1498Szrj
274038fd1498Szrj /* Process the complex constraints */
274138fd1498Szrj bitmap expanded_pts = NULL;
274238fd1498Szrj FOR_EACH_VEC_ELT (complex, j, c)
274338fd1498Szrj {
274438fd1498Szrj /* XXX: This is going to unsort the constraints in
274538fd1498Szrj some cases, which will occasionally add duplicate
274638fd1498Szrj constraints during unification. This does not
274738fd1498Szrj affect correctness. */
274838fd1498Szrj c->lhs.var = find (c->lhs.var);
274938fd1498Szrj c->rhs.var = find (c->rhs.var);
275038fd1498Szrj
275138fd1498Szrj /* The only complex constraint that can change our
275238fd1498Szrj solution to non-empty, given an empty solution,
275338fd1498Szrj is a constraint where the lhs side is receiving
275438fd1498Szrj some set from elsewhere. */
275538fd1498Szrj if (!solution_empty || c->lhs.type != DEREF)
275638fd1498Szrj do_complex_constraint (graph, c, pts, &expanded_pts);
275738fd1498Szrj }
275838fd1498Szrj BITMAP_FREE (expanded_pts);
275938fd1498Szrj
276038fd1498Szrj solution_empty = bitmap_empty_p (solution);
276138fd1498Szrj
276238fd1498Szrj if (!solution_empty)
276338fd1498Szrj {
276438fd1498Szrj bitmap_iterator bi;
276538fd1498Szrj unsigned eff_escaped_id = find (escaped_id);
276638fd1498Szrj
276738fd1498Szrj /* Propagate solution to all successors. */
276838fd1498Szrj unsigned to_remove = ~0U;
276938fd1498Szrj EXECUTE_IF_IN_NONNULL_BITMAP (graph->succs[i],
277038fd1498Szrj 0, j, bi)
277138fd1498Szrj {
277238fd1498Szrj if (to_remove != ~0U)
277338fd1498Szrj {
277438fd1498Szrj bitmap_clear_bit (graph->succs[i], to_remove);
277538fd1498Szrj to_remove = ~0U;
277638fd1498Szrj }
277738fd1498Szrj unsigned int to = find (j);
277838fd1498Szrj if (to != j)
277938fd1498Szrj {
278038fd1498Szrj /* Update the succ graph, avoiding duplicate
278138fd1498Szrj work. */
278238fd1498Szrj to_remove = j;
278338fd1498Szrj if (! bitmap_set_bit (graph->succs[i], to))
278438fd1498Szrj continue;
278538fd1498Szrj /* We eventually end up processing 'to' twice
278638fd1498Szrj as it is undefined whether bitmap iteration
278738fd1498Szrj iterates over bits set during iteration.
278838fd1498Szrj Play safe instead of doing tricks. */
278938fd1498Szrj }
279038fd1498Szrj /* Don't try to propagate to ourselves. */
279138fd1498Szrj if (to == i)
279238fd1498Szrj continue;
279338fd1498Szrj
279438fd1498Szrj bitmap tmp = get_varinfo (to)->solution;
279538fd1498Szrj bool flag = false;
279638fd1498Szrj
279738fd1498Szrj /* If we propagate from ESCAPED use ESCAPED as
279838fd1498Szrj placeholder. */
279938fd1498Szrj if (i == eff_escaped_id)
280038fd1498Szrj flag = bitmap_set_bit (tmp, escaped_id);
280138fd1498Szrj else
280238fd1498Szrj flag = bitmap_ior_into (tmp, pts);
280338fd1498Szrj
280438fd1498Szrj if (flag)
280538fd1498Szrj bitmap_set_bit (changed, to);
280638fd1498Szrj }
280738fd1498Szrj if (to_remove != ~0U)
280838fd1498Szrj bitmap_clear_bit (graph->succs[i], to_remove);
280938fd1498Szrj }
281038fd1498Szrj }
281138fd1498Szrj }
281238fd1498Szrj free_topo_info (ti);
281338fd1498Szrj bitmap_obstack_release (&iteration_obstack);
281438fd1498Szrj }
281538fd1498Szrj
281638fd1498Szrj BITMAP_FREE (pts);
281738fd1498Szrj BITMAP_FREE (changed);
281838fd1498Szrj bitmap_obstack_release (&oldpta_obstack);
281938fd1498Szrj }
282038fd1498Szrj
282138fd1498Szrj /* Map from trees to variable infos. */
282238fd1498Szrj static hash_map<tree, varinfo_t> *vi_for_tree;
282338fd1498Szrj
282438fd1498Szrj
282538fd1498Szrj /* Insert ID as the variable id for tree T in the vi_for_tree map. */
282638fd1498Szrj
282738fd1498Szrj static void
insert_vi_for_tree(tree t,varinfo_t vi)282838fd1498Szrj insert_vi_for_tree (tree t, varinfo_t vi)
282938fd1498Szrj {
283038fd1498Szrj gcc_assert (vi);
283138fd1498Szrj gcc_assert (!vi_for_tree->put (t, vi));
283238fd1498Szrj }
283338fd1498Szrj
283438fd1498Szrj /* Find the variable info for tree T in VI_FOR_TREE. If T does not
283538fd1498Szrj exist in the map, return NULL, otherwise, return the varinfo we found. */
283638fd1498Szrj
283738fd1498Szrj static varinfo_t
lookup_vi_for_tree(tree t)283838fd1498Szrj lookup_vi_for_tree (tree t)
283938fd1498Szrj {
284038fd1498Szrj varinfo_t *slot = vi_for_tree->get (t);
284138fd1498Szrj if (slot == NULL)
284238fd1498Szrj return NULL;
284338fd1498Szrj
284438fd1498Szrj return *slot;
284538fd1498Szrj }
284638fd1498Szrj
284738fd1498Szrj /* Return a printable name for DECL */
284838fd1498Szrj
284938fd1498Szrj static const char *
alias_get_name(tree decl)285038fd1498Szrj alias_get_name (tree decl)
285138fd1498Szrj {
285238fd1498Szrj const char *res = "NULL";
285338fd1498Szrj if (dump_file)
285438fd1498Szrj {
285538fd1498Szrj char *temp = NULL;
285638fd1498Szrj if (TREE_CODE (decl) == SSA_NAME)
285738fd1498Szrj {
285838fd1498Szrj res = get_name (decl);
285938fd1498Szrj temp = xasprintf ("%s_%u", res ? res : "", SSA_NAME_VERSION (decl));
286038fd1498Szrj }
286138fd1498Szrj else if (HAS_DECL_ASSEMBLER_NAME_P (decl)
286238fd1498Szrj && DECL_ASSEMBLER_NAME_SET_P (decl))
286338fd1498Szrj res = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME_RAW (decl));
286438fd1498Szrj else if (DECL_P (decl))
286538fd1498Szrj {
286638fd1498Szrj res = get_name (decl);
286738fd1498Szrj if (!res)
286838fd1498Szrj temp = xasprintf ("D.%u", DECL_UID (decl));
286938fd1498Szrj }
287038fd1498Szrj
287138fd1498Szrj if (temp)
287238fd1498Szrj {
287338fd1498Szrj res = ggc_strdup (temp);
287438fd1498Szrj free (temp);
287538fd1498Szrj }
287638fd1498Szrj }
287738fd1498Szrj
287838fd1498Szrj return res;
287938fd1498Szrj }
288038fd1498Szrj
288138fd1498Szrj /* Find the variable id for tree T in the map.
288238fd1498Szrj If T doesn't exist in the map, create an entry for it and return it. */
288338fd1498Szrj
288438fd1498Szrj static varinfo_t
get_vi_for_tree(tree t)288538fd1498Szrj get_vi_for_tree (tree t)
288638fd1498Szrj {
288738fd1498Szrj varinfo_t *slot = vi_for_tree->get (t);
288838fd1498Szrj if (slot == NULL)
288938fd1498Szrj {
289038fd1498Szrj unsigned int id = create_variable_info_for (t, alias_get_name (t), false);
289138fd1498Szrj return get_varinfo (id);
289238fd1498Szrj }
289338fd1498Szrj
289438fd1498Szrj return *slot;
289538fd1498Szrj }
289638fd1498Szrj
289738fd1498Szrj /* Get a scalar constraint expression for a new temporary variable. */
289838fd1498Szrj
289938fd1498Szrj static struct constraint_expr
new_scalar_tmp_constraint_exp(const char * name,bool add_id)290038fd1498Szrj new_scalar_tmp_constraint_exp (const char *name, bool add_id)
290138fd1498Szrj {
290238fd1498Szrj struct constraint_expr tmp;
290338fd1498Szrj varinfo_t vi;
290438fd1498Szrj
290538fd1498Szrj vi = new_var_info (NULL_TREE, name, add_id);
290638fd1498Szrj vi->offset = 0;
290738fd1498Szrj vi->size = -1;
290838fd1498Szrj vi->fullsize = -1;
290938fd1498Szrj vi->is_full_var = 1;
291038fd1498Szrj vi->is_reg_var = 1;
291138fd1498Szrj
291238fd1498Szrj tmp.var = vi->id;
291338fd1498Szrj tmp.type = SCALAR;
291438fd1498Szrj tmp.offset = 0;
291538fd1498Szrj
291638fd1498Szrj return tmp;
291738fd1498Szrj }
291838fd1498Szrj
291938fd1498Szrj /* Get a constraint expression vector from an SSA_VAR_P node.
292038fd1498Szrj If address_p is true, the result will be taken its address of. */
292138fd1498Szrj
292238fd1498Szrj static void
get_constraint_for_ssa_var(tree t,vec<ce_s> * results,bool address_p)292338fd1498Szrj get_constraint_for_ssa_var (tree t, vec<ce_s> *results, bool address_p)
292438fd1498Szrj {
292538fd1498Szrj struct constraint_expr cexpr;
292638fd1498Szrj varinfo_t vi;
292738fd1498Szrj
292838fd1498Szrj /* We allow FUNCTION_DECLs here even though it doesn't make much sense. */
292938fd1498Szrj gcc_assert (TREE_CODE (t) == SSA_NAME || DECL_P (t));
293038fd1498Szrj
293138fd1498Szrj /* For parameters, get at the points-to set for the actual parm
293238fd1498Szrj decl. */
293338fd1498Szrj if (TREE_CODE (t) == SSA_NAME
293438fd1498Szrj && SSA_NAME_IS_DEFAULT_DEF (t)
293538fd1498Szrj && (TREE_CODE (SSA_NAME_VAR (t)) == PARM_DECL
293638fd1498Szrj || TREE_CODE (SSA_NAME_VAR (t)) == RESULT_DECL))
293738fd1498Szrj {
293838fd1498Szrj get_constraint_for_ssa_var (SSA_NAME_VAR (t), results, address_p);
293938fd1498Szrj return;
294038fd1498Szrj }
294138fd1498Szrj
294238fd1498Szrj /* For global variables resort to the alias target. */
294338fd1498Szrj if (VAR_P (t) && (TREE_STATIC (t) || DECL_EXTERNAL (t)))
294438fd1498Szrj {
294538fd1498Szrj varpool_node *node = varpool_node::get (t);
294638fd1498Szrj if (node && node->alias && node->analyzed)
294738fd1498Szrj {
294838fd1498Szrj node = node->ultimate_alias_target ();
294938fd1498Szrj /* Canonicalize the PT uid of all aliases to the ultimate target.
295038fd1498Szrj ??? Hopefully the set of aliases can't change in a way that
295138fd1498Szrj changes the ultimate alias target. */
295238fd1498Szrj gcc_assert ((! DECL_PT_UID_SET_P (node->decl)
295338fd1498Szrj || DECL_PT_UID (node->decl) == DECL_UID (node->decl))
295438fd1498Szrj && (! DECL_PT_UID_SET_P (t)
295538fd1498Szrj || DECL_PT_UID (t) == DECL_UID (node->decl)));
295638fd1498Szrj DECL_PT_UID (t) = DECL_UID (node->decl);
295738fd1498Szrj t = node->decl;
295838fd1498Szrj }
295938fd1498Szrj
296038fd1498Szrj /* If this is decl may bind to NULL note that. */
296138fd1498Szrj if (address_p
296238fd1498Szrj && (! node || ! node->nonzero_address ()))
296338fd1498Szrj {
296438fd1498Szrj cexpr.var = nothing_id;
296538fd1498Szrj cexpr.type = SCALAR;
296638fd1498Szrj cexpr.offset = 0;
296738fd1498Szrj results->safe_push (cexpr);
296838fd1498Szrj }
296938fd1498Szrj }
297038fd1498Szrj
297138fd1498Szrj vi = get_vi_for_tree (t);
297238fd1498Szrj cexpr.var = vi->id;
297338fd1498Szrj cexpr.type = SCALAR;
297438fd1498Szrj cexpr.offset = 0;
297538fd1498Szrj
297638fd1498Szrj /* If we are not taking the address of the constraint expr, add all
297738fd1498Szrj sub-fiels of the variable as well. */
297838fd1498Szrj if (!address_p
297938fd1498Szrj && !vi->is_full_var)
298038fd1498Szrj {
298138fd1498Szrj for (; vi; vi = vi_next (vi))
298238fd1498Szrj {
298338fd1498Szrj cexpr.var = vi->id;
298438fd1498Szrj results->safe_push (cexpr);
298538fd1498Szrj }
298638fd1498Szrj return;
298738fd1498Szrj }
298838fd1498Szrj
298938fd1498Szrj results->safe_push (cexpr);
299038fd1498Szrj }
299138fd1498Szrj
299238fd1498Szrj /* Process constraint T, performing various simplifications and then
299338fd1498Szrj adding it to our list of overall constraints. */
299438fd1498Szrj
299538fd1498Szrj static void
process_constraint(constraint_t t)299638fd1498Szrj process_constraint (constraint_t t)
299738fd1498Szrj {
299838fd1498Szrj struct constraint_expr rhs = t->rhs;
299938fd1498Szrj struct constraint_expr lhs = t->lhs;
300038fd1498Szrj
300138fd1498Szrj gcc_assert (rhs.var < varmap.length ());
300238fd1498Szrj gcc_assert (lhs.var < varmap.length ());
300338fd1498Szrj
300438fd1498Szrj /* If we didn't get any useful constraint from the lhs we get
300538fd1498Szrj &ANYTHING as fallback from get_constraint_for. Deal with
300638fd1498Szrj it here by turning it into *ANYTHING. */
300738fd1498Szrj if (lhs.type == ADDRESSOF
300838fd1498Szrj && lhs.var == anything_id)
300938fd1498Szrj lhs.type = DEREF;
301038fd1498Szrj
301138fd1498Szrj /* ADDRESSOF on the lhs is invalid. */
301238fd1498Szrj gcc_assert (lhs.type != ADDRESSOF);
301338fd1498Szrj
301438fd1498Szrj /* We shouldn't add constraints from things that cannot have pointers.
301538fd1498Szrj It's not completely trivial to avoid in the callers, so do it here. */
301638fd1498Szrj if (rhs.type != ADDRESSOF
301738fd1498Szrj && !get_varinfo (rhs.var)->may_have_pointers)
301838fd1498Szrj return;
301938fd1498Szrj
302038fd1498Szrj /* Likewise adding to the solution of a non-pointer var isn't useful. */
302138fd1498Szrj if (!get_varinfo (lhs.var)->may_have_pointers)
302238fd1498Szrj return;
302338fd1498Szrj
302438fd1498Szrj /* This can happen in our IR with things like n->a = *p */
302538fd1498Szrj if (rhs.type == DEREF && lhs.type == DEREF && rhs.var != anything_id)
302638fd1498Szrj {
302738fd1498Szrj /* Split into tmp = *rhs, *lhs = tmp */
302838fd1498Szrj struct constraint_expr tmplhs;
302938fd1498Szrj tmplhs = new_scalar_tmp_constraint_exp ("doubledereftmp", true);
303038fd1498Szrj process_constraint (new_constraint (tmplhs, rhs));
303138fd1498Szrj process_constraint (new_constraint (lhs, tmplhs));
303238fd1498Szrj }
303338fd1498Szrj else if ((rhs.type != SCALAR || rhs.offset != 0) && lhs.type == DEREF)
303438fd1498Szrj {
303538fd1498Szrj /* Split into tmp = &rhs, *lhs = tmp */
303638fd1498Szrj struct constraint_expr tmplhs;
303738fd1498Szrj tmplhs = new_scalar_tmp_constraint_exp ("derefaddrtmp", true);
303838fd1498Szrj process_constraint (new_constraint (tmplhs, rhs));
303938fd1498Szrj process_constraint (new_constraint (lhs, tmplhs));
304038fd1498Szrj }
304138fd1498Szrj else
304238fd1498Szrj {
304338fd1498Szrj gcc_assert (rhs.type != ADDRESSOF || rhs.offset == 0);
304438fd1498Szrj constraints.safe_push (t);
304538fd1498Szrj }
304638fd1498Szrj }
304738fd1498Szrj
304838fd1498Szrj
304938fd1498Szrj /* Return the position, in bits, of FIELD_DECL from the beginning of its
305038fd1498Szrj structure. */
305138fd1498Szrj
305238fd1498Szrj static HOST_WIDE_INT
bitpos_of_field(const tree fdecl)305338fd1498Szrj bitpos_of_field (const tree fdecl)
305438fd1498Szrj {
305538fd1498Szrj if (!tree_fits_shwi_p (DECL_FIELD_OFFSET (fdecl))
305638fd1498Szrj || !tree_fits_shwi_p (DECL_FIELD_BIT_OFFSET (fdecl)))
305738fd1498Szrj return -1;
305838fd1498Szrj
305938fd1498Szrj return (tree_to_shwi (DECL_FIELD_OFFSET (fdecl)) * BITS_PER_UNIT
306038fd1498Szrj + tree_to_shwi (DECL_FIELD_BIT_OFFSET (fdecl)));
306138fd1498Szrj }
306238fd1498Szrj
306338fd1498Szrj
306438fd1498Szrj /* Get constraint expressions for offsetting PTR by OFFSET. Stores the
306538fd1498Szrj resulting constraint expressions in *RESULTS. */
306638fd1498Szrj
306738fd1498Szrj static void
get_constraint_for_ptr_offset(tree ptr,tree offset,vec<ce_s> * results)306838fd1498Szrj get_constraint_for_ptr_offset (tree ptr, tree offset,
306938fd1498Szrj vec<ce_s> *results)
307038fd1498Szrj {
307138fd1498Szrj struct constraint_expr c;
307238fd1498Szrj unsigned int j, n;
307338fd1498Szrj HOST_WIDE_INT rhsoffset;
307438fd1498Szrj
307538fd1498Szrj /* If we do not do field-sensitive PTA adding offsets to pointers
307638fd1498Szrj does not change the points-to solution. */
307738fd1498Szrj if (!use_field_sensitive)
307838fd1498Szrj {
307938fd1498Szrj get_constraint_for_rhs (ptr, results);
308038fd1498Szrj return;
308138fd1498Szrj }
308238fd1498Szrj
308338fd1498Szrj /* If the offset is not a non-negative integer constant that fits
308438fd1498Szrj in a HOST_WIDE_INT, we have to fall back to a conservative
308538fd1498Szrj solution which includes all sub-fields of all pointed-to
308638fd1498Szrj variables of ptr. */
308738fd1498Szrj if (offset == NULL_TREE
308838fd1498Szrj || TREE_CODE (offset) != INTEGER_CST)
308938fd1498Szrj rhsoffset = UNKNOWN_OFFSET;
309038fd1498Szrj else
309138fd1498Szrj {
309238fd1498Szrj /* Sign-extend the offset. */
309338fd1498Szrj offset_int soffset = offset_int::from (wi::to_wide (offset), SIGNED);
309438fd1498Szrj if (!wi::fits_shwi_p (soffset))
309538fd1498Szrj rhsoffset = UNKNOWN_OFFSET;
309638fd1498Szrj else
309738fd1498Szrj {
309838fd1498Szrj /* Make sure the bit-offset also fits. */
309938fd1498Szrj HOST_WIDE_INT rhsunitoffset = soffset.to_shwi ();
310038fd1498Szrj rhsoffset = rhsunitoffset * (unsigned HOST_WIDE_INT) BITS_PER_UNIT;
310138fd1498Szrj if (rhsunitoffset != rhsoffset / BITS_PER_UNIT)
310238fd1498Szrj rhsoffset = UNKNOWN_OFFSET;
310338fd1498Szrj }
310438fd1498Szrj }
310538fd1498Szrj
310638fd1498Szrj get_constraint_for_rhs (ptr, results);
310738fd1498Szrj if (rhsoffset == 0)
310838fd1498Szrj return;
310938fd1498Szrj
311038fd1498Szrj /* As we are eventually appending to the solution do not use
311138fd1498Szrj vec::iterate here. */
311238fd1498Szrj n = results->length ();
311338fd1498Szrj for (j = 0; j < n; j++)
311438fd1498Szrj {
311538fd1498Szrj varinfo_t curr;
311638fd1498Szrj c = (*results)[j];
311738fd1498Szrj curr = get_varinfo (c.var);
311838fd1498Szrj
311938fd1498Szrj if (c.type == ADDRESSOF
312038fd1498Szrj /* If this varinfo represents a full variable just use it. */
312138fd1498Szrj && curr->is_full_var)
312238fd1498Szrj ;
312338fd1498Szrj else if (c.type == ADDRESSOF
312438fd1498Szrj /* If we do not know the offset add all subfields. */
312538fd1498Szrj && rhsoffset == UNKNOWN_OFFSET)
312638fd1498Szrj {
312738fd1498Szrj varinfo_t temp = get_varinfo (curr->head);
312838fd1498Szrj do
312938fd1498Szrj {
313038fd1498Szrj struct constraint_expr c2;
313138fd1498Szrj c2.var = temp->id;
313238fd1498Szrj c2.type = ADDRESSOF;
313338fd1498Szrj c2.offset = 0;
313438fd1498Szrj if (c2.var != c.var)
313538fd1498Szrj results->safe_push (c2);
313638fd1498Szrj temp = vi_next (temp);
313738fd1498Szrj }
313838fd1498Szrj while (temp);
313938fd1498Szrj }
314038fd1498Szrj else if (c.type == ADDRESSOF)
314138fd1498Szrj {
314238fd1498Szrj varinfo_t temp;
314338fd1498Szrj unsigned HOST_WIDE_INT offset = curr->offset + rhsoffset;
314438fd1498Szrj
314538fd1498Szrj /* If curr->offset + rhsoffset is less than zero adjust it. */
314638fd1498Szrj if (rhsoffset < 0
314738fd1498Szrj && curr->offset < offset)
314838fd1498Szrj offset = 0;
314938fd1498Szrj
315038fd1498Szrj /* We have to include all fields that overlap the current
315138fd1498Szrj field shifted by rhsoffset. And we include at least
315238fd1498Szrj the last or the first field of the variable to represent
315338fd1498Szrj reachability of off-bound addresses, in particular &object + 1,
315438fd1498Szrj conservatively correct. */
315538fd1498Szrj temp = first_or_preceding_vi_for_offset (curr, offset);
315638fd1498Szrj c.var = temp->id;
315738fd1498Szrj c.offset = 0;
315838fd1498Szrj temp = vi_next (temp);
315938fd1498Szrj while (temp
316038fd1498Szrj && temp->offset < offset + curr->size)
316138fd1498Szrj {
316238fd1498Szrj struct constraint_expr c2;
316338fd1498Szrj c2.var = temp->id;
316438fd1498Szrj c2.type = ADDRESSOF;
316538fd1498Szrj c2.offset = 0;
316638fd1498Szrj results->safe_push (c2);
316738fd1498Szrj temp = vi_next (temp);
316838fd1498Szrj }
316938fd1498Szrj }
317038fd1498Szrj else if (c.type == SCALAR)
317138fd1498Szrj {
317238fd1498Szrj gcc_assert (c.offset == 0);
317338fd1498Szrj c.offset = rhsoffset;
317438fd1498Szrj }
317538fd1498Szrj else
317638fd1498Szrj /* We shouldn't get any DEREFs here. */
317738fd1498Szrj gcc_unreachable ();
317838fd1498Szrj
317938fd1498Szrj (*results)[j] = c;
318038fd1498Szrj }
318138fd1498Szrj }
318238fd1498Szrj
318338fd1498Szrj
318438fd1498Szrj /* Given a COMPONENT_REF T, return the constraint_expr vector for it.
318538fd1498Szrj If address_p is true the result will be taken its address of.
318638fd1498Szrj If lhs_p is true then the constraint expression is assumed to be used
318738fd1498Szrj as the lhs. */
318838fd1498Szrj
318938fd1498Szrj static void
get_constraint_for_component_ref(tree t,vec<ce_s> * results,bool address_p,bool lhs_p)319038fd1498Szrj get_constraint_for_component_ref (tree t, vec<ce_s> *results,
319138fd1498Szrj bool address_p, bool lhs_p)
319238fd1498Szrj {
319338fd1498Szrj tree orig_t = t;
319438fd1498Szrj poly_int64 bitsize = -1;
319538fd1498Szrj poly_int64 bitmaxsize = -1;
319638fd1498Szrj poly_int64 bitpos;
319738fd1498Szrj bool reverse;
319838fd1498Szrj tree forzero;
319938fd1498Szrj
320038fd1498Szrj /* Some people like to do cute things like take the address of
320138fd1498Szrj &0->a.b */
320238fd1498Szrj forzero = t;
320338fd1498Szrj while (handled_component_p (forzero)
320438fd1498Szrj || INDIRECT_REF_P (forzero)
320538fd1498Szrj || TREE_CODE (forzero) == MEM_REF)
320638fd1498Szrj forzero = TREE_OPERAND (forzero, 0);
320738fd1498Szrj
320838fd1498Szrj if (CONSTANT_CLASS_P (forzero) && integer_zerop (forzero))
320938fd1498Szrj {
321038fd1498Szrj struct constraint_expr temp;
321138fd1498Szrj
321238fd1498Szrj temp.offset = 0;
321338fd1498Szrj temp.var = integer_id;
321438fd1498Szrj temp.type = SCALAR;
321538fd1498Szrj results->safe_push (temp);
321638fd1498Szrj return;
321738fd1498Szrj }
321838fd1498Szrj
321938fd1498Szrj t = get_ref_base_and_extent (t, &bitpos, &bitsize, &bitmaxsize, &reverse);
322038fd1498Szrj
322138fd1498Szrj /* We can end up here for component references on a
322238fd1498Szrj VIEW_CONVERT_EXPR <>(&foobar) or things like a
322338fd1498Szrj BIT_FIELD_REF <&MEM[(void *)&b + 4B], ...>. So for
322438fd1498Szrj symbolic constants simply give up. */
322538fd1498Szrj if (TREE_CODE (t) == ADDR_EXPR)
322638fd1498Szrj {
322738fd1498Szrj constraint_expr result;
322838fd1498Szrj result.type = SCALAR;
322938fd1498Szrj result.var = anything_id;
323038fd1498Szrj result.offset = 0;
323138fd1498Szrj results->safe_push (result);
323238fd1498Szrj return;
323338fd1498Szrj }
323438fd1498Szrj
323538fd1498Szrj /* Pretend to take the address of the base, we'll take care of
323638fd1498Szrj adding the required subset of sub-fields below. */
323738fd1498Szrj get_constraint_for_1 (t, results, true, lhs_p);
323838fd1498Szrj /* Strip off nothing_id. */
323938fd1498Szrj if (results->length () == 2)
324038fd1498Szrj {
324138fd1498Szrj gcc_assert ((*results)[0].var == nothing_id);
324238fd1498Szrj results->unordered_remove (0);
324338fd1498Szrj }
324438fd1498Szrj gcc_assert (results->length () == 1);
324538fd1498Szrj struct constraint_expr &result = results->last ();
324638fd1498Szrj
324738fd1498Szrj if (result.type == SCALAR
324838fd1498Szrj && get_varinfo (result.var)->is_full_var)
324938fd1498Szrj /* For single-field vars do not bother about the offset. */
325038fd1498Szrj result.offset = 0;
325138fd1498Szrj else if (result.type == SCALAR)
325238fd1498Szrj {
325338fd1498Szrj /* In languages like C, you can access one past the end of an
325438fd1498Szrj array. You aren't allowed to dereference it, so we can
325538fd1498Szrj ignore this constraint. When we handle pointer subtraction,
325638fd1498Szrj we may have to do something cute here. */
325738fd1498Szrj
325838fd1498Szrj if (maybe_lt (poly_uint64 (bitpos), get_varinfo (result.var)->fullsize)
325938fd1498Szrj && maybe_ne (bitmaxsize, 0))
326038fd1498Szrj {
326138fd1498Szrj /* It's also not true that the constraint will actually start at the
326238fd1498Szrj right offset, it may start in some padding. We only care about
326338fd1498Szrj setting the constraint to the first actual field it touches, so
326438fd1498Szrj walk to find it. */
326538fd1498Szrj struct constraint_expr cexpr = result;
326638fd1498Szrj varinfo_t curr;
326738fd1498Szrj results->pop ();
326838fd1498Szrj cexpr.offset = 0;
326938fd1498Szrj for (curr = get_varinfo (cexpr.var); curr; curr = vi_next (curr))
327038fd1498Szrj {
327138fd1498Szrj if (ranges_maybe_overlap_p (poly_int64 (curr->offset),
327238fd1498Szrj curr->size, bitpos, bitmaxsize))
327338fd1498Szrj {
327438fd1498Szrj cexpr.var = curr->id;
327538fd1498Szrj results->safe_push (cexpr);
327638fd1498Szrj if (address_p)
327738fd1498Szrj break;
327838fd1498Szrj }
327938fd1498Szrj }
328038fd1498Szrj /* If we are going to take the address of this field then
328138fd1498Szrj to be able to compute reachability correctly add at least
328238fd1498Szrj the last field of the variable. */
328338fd1498Szrj if (address_p && results->length () == 0)
328438fd1498Szrj {
328538fd1498Szrj curr = get_varinfo (cexpr.var);
328638fd1498Szrj while (curr->next != 0)
328738fd1498Szrj curr = vi_next (curr);
328838fd1498Szrj cexpr.var = curr->id;
328938fd1498Szrj results->safe_push (cexpr);
329038fd1498Szrj }
329138fd1498Szrj else if (results->length () == 0)
329238fd1498Szrj /* Assert that we found *some* field there. The user couldn't be
329338fd1498Szrj accessing *only* padding. */
329438fd1498Szrj /* Still the user could access one past the end of an array
329538fd1498Szrj embedded in a struct resulting in accessing *only* padding. */
329638fd1498Szrj /* Or accessing only padding via type-punning to a type
329738fd1498Szrj that has a filed just in padding space. */
329838fd1498Szrj {
329938fd1498Szrj cexpr.type = SCALAR;
330038fd1498Szrj cexpr.var = anything_id;
330138fd1498Szrj cexpr.offset = 0;
330238fd1498Szrj results->safe_push (cexpr);
330338fd1498Szrj }
330438fd1498Szrj }
330538fd1498Szrj else if (known_eq (bitmaxsize, 0))
330638fd1498Szrj {
330738fd1498Szrj if (dump_file && (dump_flags & TDF_DETAILS))
330838fd1498Szrj fprintf (dump_file, "Access to zero-sized part of variable, "
330938fd1498Szrj "ignoring\n");
331038fd1498Szrj }
331138fd1498Szrj else
331238fd1498Szrj if (dump_file && (dump_flags & TDF_DETAILS))
331338fd1498Szrj fprintf (dump_file, "Access to past the end of variable, ignoring\n");
331438fd1498Szrj }
331538fd1498Szrj else if (result.type == DEREF)
331638fd1498Szrj {
331738fd1498Szrj /* If we do not know exactly where the access goes say so. Note
331838fd1498Szrj that only for non-structure accesses we know that we access
331938fd1498Szrj at most one subfiled of any variable. */
332038fd1498Szrj HOST_WIDE_INT const_bitpos;
332138fd1498Szrj if (!bitpos.is_constant (&const_bitpos)
332238fd1498Szrj || const_bitpos == -1
332338fd1498Szrj || maybe_ne (bitsize, bitmaxsize)
332438fd1498Szrj || AGGREGATE_TYPE_P (TREE_TYPE (orig_t))
332538fd1498Szrj || result.offset == UNKNOWN_OFFSET)
332638fd1498Szrj result.offset = UNKNOWN_OFFSET;
332738fd1498Szrj else
332838fd1498Szrj result.offset += const_bitpos;
332938fd1498Szrj }
333038fd1498Szrj else if (result.type == ADDRESSOF)
333138fd1498Szrj {
333238fd1498Szrj /* We can end up here for component references on constants like
333338fd1498Szrj VIEW_CONVERT_EXPR <>({ 0, 1, 2, 3 })[i]. */
333438fd1498Szrj result.type = SCALAR;
333538fd1498Szrj result.var = anything_id;
333638fd1498Szrj result.offset = 0;
333738fd1498Szrj }
333838fd1498Szrj else
333938fd1498Szrj gcc_unreachable ();
334038fd1498Szrj }
334138fd1498Szrj
334238fd1498Szrj
334338fd1498Szrj /* Dereference the constraint expression CONS, and return the result.
334438fd1498Szrj DEREF (ADDRESSOF) = SCALAR
334538fd1498Szrj DEREF (SCALAR) = DEREF
334638fd1498Szrj DEREF (DEREF) = (temp = DEREF1; result = DEREF(temp))
334738fd1498Szrj This is needed so that we can handle dereferencing DEREF constraints. */
334838fd1498Szrj
334938fd1498Szrj static void
do_deref(vec<ce_s> * constraints)335038fd1498Szrj do_deref (vec<ce_s> *constraints)
335138fd1498Szrj {
335238fd1498Szrj struct constraint_expr *c;
335338fd1498Szrj unsigned int i = 0;
335438fd1498Szrj
335538fd1498Szrj FOR_EACH_VEC_ELT (*constraints, i, c)
335638fd1498Szrj {
335738fd1498Szrj if (c->type == SCALAR)
335838fd1498Szrj c->type = DEREF;
335938fd1498Szrj else if (c->type == ADDRESSOF)
336038fd1498Szrj c->type = SCALAR;
336138fd1498Szrj else if (c->type == DEREF)
336238fd1498Szrj {
336338fd1498Szrj struct constraint_expr tmplhs;
336438fd1498Szrj tmplhs = new_scalar_tmp_constraint_exp ("dereftmp", true);
336538fd1498Szrj process_constraint (new_constraint (tmplhs, *c));
336638fd1498Szrj c->var = tmplhs.var;
336738fd1498Szrj }
336838fd1498Szrj else
336938fd1498Szrj gcc_unreachable ();
337038fd1498Szrj }
337138fd1498Szrj }
337238fd1498Szrj
337338fd1498Szrj /* Given a tree T, return the constraint expression for taking the
337438fd1498Szrj address of it. */
337538fd1498Szrj
337638fd1498Szrj static void
get_constraint_for_address_of(tree t,vec<ce_s> * results)337738fd1498Szrj get_constraint_for_address_of (tree t, vec<ce_s> *results)
337838fd1498Szrj {
337938fd1498Szrj struct constraint_expr *c;
338038fd1498Szrj unsigned int i;
338138fd1498Szrj
338238fd1498Szrj get_constraint_for_1 (t, results, true, true);
338338fd1498Szrj
338438fd1498Szrj FOR_EACH_VEC_ELT (*results, i, c)
338538fd1498Szrj {
338638fd1498Szrj if (c->type == DEREF)
338738fd1498Szrj c->type = SCALAR;
338838fd1498Szrj else
338938fd1498Szrj c->type = ADDRESSOF;
339038fd1498Szrj }
339138fd1498Szrj }
339238fd1498Szrj
339338fd1498Szrj /* Given a tree T, return the constraint expression for it. */
339438fd1498Szrj
339538fd1498Szrj static void
get_constraint_for_1(tree t,vec<ce_s> * results,bool address_p,bool lhs_p)339638fd1498Szrj get_constraint_for_1 (tree t, vec<ce_s> *results, bool address_p,
339738fd1498Szrj bool lhs_p)
339838fd1498Szrj {
339938fd1498Szrj struct constraint_expr temp;
340038fd1498Szrj
340138fd1498Szrj /* x = integer is all glommed to a single variable, which doesn't
340238fd1498Szrj point to anything by itself. That is, of course, unless it is an
340338fd1498Szrj integer constant being treated as a pointer, in which case, we
340438fd1498Szrj will return that this is really the addressof anything. This
340538fd1498Szrj happens below, since it will fall into the default case. The only
340638fd1498Szrj case we know something about an integer treated like a pointer is
340738fd1498Szrj when it is the NULL pointer, and then we just say it points to
340838fd1498Szrj NULL.
340938fd1498Szrj
341038fd1498Szrj Do not do that if -fno-delete-null-pointer-checks though, because
341138fd1498Szrj in that case *NULL does not fail, so it _should_ alias *anything.
341238fd1498Szrj It is not worth adding a new option or renaming the existing one,
341338fd1498Szrj since this case is relatively obscure. */
341438fd1498Szrj if ((TREE_CODE (t) == INTEGER_CST
341538fd1498Szrj && integer_zerop (t))
341638fd1498Szrj /* The only valid CONSTRUCTORs in gimple with pointer typed
341738fd1498Szrj elements are zero-initializer. But in IPA mode we also
341838fd1498Szrj process global initializers, so verify at least. */
341938fd1498Szrj || (TREE_CODE (t) == CONSTRUCTOR
342038fd1498Szrj && CONSTRUCTOR_NELTS (t) == 0))
342138fd1498Szrj {
342238fd1498Szrj if (flag_delete_null_pointer_checks)
342338fd1498Szrj temp.var = nothing_id;
342438fd1498Szrj else
342538fd1498Szrj temp.var = nonlocal_id;
342638fd1498Szrj temp.type = ADDRESSOF;
342738fd1498Szrj temp.offset = 0;
342838fd1498Szrj results->safe_push (temp);
342938fd1498Szrj return;
343038fd1498Szrj }
343138fd1498Szrj
343238fd1498Szrj /* String constants are read-only, ideally we'd have a CONST_DECL
343338fd1498Szrj for those. */
343438fd1498Szrj if (TREE_CODE (t) == STRING_CST)
343538fd1498Szrj {
343638fd1498Szrj temp.var = string_id;
343738fd1498Szrj temp.type = SCALAR;
343838fd1498Szrj temp.offset = 0;
343938fd1498Szrj results->safe_push (temp);
344038fd1498Szrj return;
344138fd1498Szrj }
344238fd1498Szrj
344338fd1498Szrj switch (TREE_CODE_CLASS (TREE_CODE (t)))
344438fd1498Szrj {
344538fd1498Szrj case tcc_expression:
344638fd1498Szrj {
344738fd1498Szrj switch (TREE_CODE (t))
344838fd1498Szrj {
344938fd1498Szrj case ADDR_EXPR:
345038fd1498Szrj get_constraint_for_address_of (TREE_OPERAND (t, 0), results);
345138fd1498Szrj return;
345238fd1498Szrj default:;
345338fd1498Szrj }
345438fd1498Szrj break;
345538fd1498Szrj }
345638fd1498Szrj case tcc_reference:
345738fd1498Szrj {
345838fd1498Szrj switch (TREE_CODE (t))
345938fd1498Szrj {
346038fd1498Szrj case MEM_REF:
346138fd1498Szrj {
346238fd1498Szrj struct constraint_expr cs;
346338fd1498Szrj varinfo_t vi, curr;
346438fd1498Szrj get_constraint_for_ptr_offset (TREE_OPERAND (t, 0),
346538fd1498Szrj TREE_OPERAND (t, 1), results);
346638fd1498Szrj do_deref (results);
346738fd1498Szrj
346838fd1498Szrj /* If we are not taking the address then make sure to process
346938fd1498Szrj all subvariables we might access. */
347038fd1498Szrj if (address_p)
347138fd1498Szrj return;
347238fd1498Szrj
347338fd1498Szrj cs = results->last ();
347438fd1498Szrj if (cs.type == DEREF
347538fd1498Szrj && type_can_have_subvars (TREE_TYPE (t)))
347638fd1498Szrj {
347738fd1498Szrj /* For dereferences this means we have to defer it
347838fd1498Szrj to solving time. */
347938fd1498Szrj results->last ().offset = UNKNOWN_OFFSET;
348038fd1498Szrj return;
348138fd1498Szrj }
348238fd1498Szrj if (cs.type != SCALAR)
348338fd1498Szrj return;
348438fd1498Szrj
348538fd1498Szrj vi = get_varinfo (cs.var);
348638fd1498Szrj curr = vi_next (vi);
348738fd1498Szrj if (!vi->is_full_var
348838fd1498Szrj && curr)
348938fd1498Szrj {
349038fd1498Szrj unsigned HOST_WIDE_INT size;
349138fd1498Szrj if (tree_fits_uhwi_p (TYPE_SIZE (TREE_TYPE (t))))
349238fd1498Szrj size = tree_to_uhwi (TYPE_SIZE (TREE_TYPE (t)));
349338fd1498Szrj else
349438fd1498Szrj size = -1;
349538fd1498Szrj for (; curr; curr = vi_next (curr))
349638fd1498Szrj {
349738fd1498Szrj if (curr->offset - vi->offset < size)
349838fd1498Szrj {
349938fd1498Szrj cs.var = curr->id;
350038fd1498Szrj results->safe_push (cs);
350138fd1498Szrj }
350238fd1498Szrj else
350338fd1498Szrj break;
350438fd1498Szrj }
350538fd1498Szrj }
350638fd1498Szrj return;
350738fd1498Szrj }
350838fd1498Szrj case ARRAY_REF:
350938fd1498Szrj case ARRAY_RANGE_REF:
351038fd1498Szrj case COMPONENT_REF:
351138fd1498Szrj case IMAGPART_EXPR:
351238fd1498Szrj case REALPART_EXPR:
351338fd1498Szrj case BIT_FIELD_REF:
351438fd1498Szrj get_constraint_for_component_ref (t, results, address_p, lhs_p);
351538fd1498Szrj return;
351638fd1498Szrj case VIEW_CONVERT_EXPR:
351738fd1498Szrj get_constraint_for_1 (TREE_OPERAND (t, 0), results, address_p,
351838fd1498Szrj lhs_p);
351938fd1498Szrj return;
352038fd1498Szrj /* We are missing handling for TARGET_MEM_REF here. */
352138fd1498Szrj default:;
352238fd1498Szrj }
352338fd1498Szrj break;
352438fd1498Szrj }
352538fd1498Szrj case tcc_exceptional:
352638fd1498Szrj {
352738fd1498Szrj switch (TREE_CODE (t))
352838fd1498Szrj {
352938fd1498Szrj case SSA_NAME:
353038fd1498Szrj {
353138fd1498Szrj get_constraint_for_ssa_var (t, results, address_p);
353238fd1498Szrj return;
353338fd1498Szrj }
353438fd1498Szrj case CONSTRUCTOR:
353538fd1498Szrj {
353638fd1498Szrj unsigned int i;
353738fd1498Szrj tree val;
353838fd1498Szrj auto_vec<ce_s> tmp;
353938fd1498Szrj FOR_EACH_CONSTRUCTOR_VALUE (CONSTRUCTOR_ELTS (t), i, val)
354038fd1498Szrj {
354138fd1498Szrj struct constraint_expr *rhsp;
354238fd1498Szrj unsigned j;
354338fd1498Szrj get_constraint_for_1 (val, &tmp, address_p, lhs_p);
354438fd1498Szrj FOR_EACH_VEC_ELT (tmp, j, rhsp)
354538fd1498Szrj results->safe_push (*rhsp);
354638fd1498Szrj tmp.truncate (0);
354738fd1498Szrj }
354838fd1498Szrj /* We do not know whether the constructor was complete,
354938fd1498Szrj so technically we have to add &NOTHING or &ANYTHING
355038fd1498Szrj like we do for an empty constructor as well. */
355138fd1498Szrj return;
355238fd1498Szrj }
355338fd1498Szrj default:;
355438fd1498Szrj }
355538fd1498Szrj break;
355638fd1498Szrj }
355738fd1498Szrj case tcc_declaration:
355838fd1498Szrj {
355938fd1498Szrj get_constraint_for_ssa_var (t, results, address_p);
356038fd1498Szrj return;
356138fd1498Szrj }
356238fd1498Szrj case tcc_constant:
356338fd1498Szrj {
356438fd1498Szrj /* We cannot refer to automatic variables through constants. */
356538fd1498Szrj temp.type = ADDRESSOF;
356638fd1498Szrj temp.var = nonlocal_id;
356738fd1498Szrj temp.offset = 0;
356838fd1498Szrj results->safe_push (temp);
356938fd1498Szrj return;
357038fd1498Szrj }
357138fd1498Szrj default:;
357238fd1498Szrj }
357338fd1498Szrj
357438fd1498Szrj /* The default fallback is a constraint from anything. */
357538fd1498Szrj temp.type = ADDRESSOF;
357638fd1498Szrj temp.var = anything_id;
357738fd1498Szrj temp.offset = 0;
357838fd1498Szrj results->safe_push (temp);
357938fd1498Szrj }
358038fd1498Szrj
358138fd1498Szrj /* Given a gimple tree T, return the constraint expression vector for it. */
358238fd1498Szrj
358338fd1498Szrj static void
get_constraint_for(tree t,vec<ce_s> * results)358438fd1498Szrj get_constraint_for (tree t, vec<ce_s> *results)
358538fd1498Szrj {
358638fd1498Szrj gcc_assert (results->length () == 0);
358738fd1498Szrj
358838fd1498Szrj get_constraint_for_1 (t, results, false, true);
358938fd1498Szrj }
359038fd1498Szrj
359138fd1498Szrj /* Given a gimple tree T, return the constraint expression vector for it
359238fd1498Szrj to be used as the rhs of a constraint. */
359338fd1498Szrj
359438fd1498Szrj static void
get_constraint_for_rhs(tree t,vec<ce_s> * results)359538fd1498Szrj get_constraint_for_rhs (tree t, vec<ce_s> *results)
359638fd1498Szrj {
359738fd1498Szrj gcc_assert (results->length () == 0);
359838fd1498Szrj
359938fd1498Szrj get_constraint_for_1 (t, results, false, false);
360038fd1498Szrj }
360138fd1498Szrj
360238fd1498Szrj
360338fd1498Szrj /* Efficiently generates constraints from all entries in *RHSC to all
360438fd1498Szrj entries in *LHSC. */
360538fd1498Szrj
360638fd1498Szrj static void
process_all_all_constraints(vec<ce_s> lhsc,vec<ce_s> rhsc)360738fd1498Szrj process_all_all_constraints (vec<ce_s> lhsc,
360838fd1498Szrj vec<ce_s> rhsc)
360938fd1498Szrj {
361038fd1498Szrj struct constraint_expr *lhsp, *rhsp;
361138fd1498Szrj unsigned i, j;
361238fd1498Szrj
361338fd1498Szrj if (lhsc.length () <= 1 || rhsc.length () <= 1)
361438fd1498Szrj {
361538fd1498Szrj FOR_EACH_VEC_ELT (lhsc, i, lhsp)
361638fd1498Szrj FOR_EACH_VEC_ELT (rhsc, j, rhsp)
361738fd1498Szrj process_constraint (new_constraint (*lhsp, *rhsp));
361838fd1498Szrj }
361938fd1498Szrj else
362038fd1498Szrj {
362138fd1498Szrj struct constraint_expr tmp;
362238fd1498Szrj tmp = new_scalar_tmp_constraint_exp ("allalltmp", true);
362338fd1498Szrj FOR_EACH_VEC_ELT (rhsc, i, rhsp)
362438fd1498Szrj process_constraint (new_constraint (tmp, *rhsp));
362538fd1498Szrj FOR_EACH_VEC_ELT (lhsc, i, lhsp)
362638fd1498Szrj process_constraint (new_constraint (*lhsp, tmp));
362738fd1498Szrj }
362838fd1498Szrj }
362938fd1498Szrj
363038fd1498Szrj /* Handle aggregate copies by expanding into copies of the respective
363138fd1498Szrj fields of the structures. */
363238fd1498Szrj
363338fd1498Szrj static void
do_structure_copy(tree lhsop,tree rhsop)363438fd1498Szrj do_structure_copy (tree lhsop, tree rhsop)
363538fd1498Szrj {
363638fd1498Szrj struct constraint_expr *lhsp, *rhsp;
363738fd1498Szrj auto_vec<ce_s> lhsc;
363838fd1498Szrj auto_vec<ce_s> rhsc;
363938fd1498Szrj unsigned j;
364038fd1498Szrj
364138fd1498Szrj get_constraint_for (lhsop, &lhsc);
364238fd1498Szrj get_constraint_for_rhs (rhsop, &rhsc);
364338fd1498Szrj lhsp = &lhsc[0];
364438fd1498Szrj rhsp = &rhsc[0];
364538fd1498Szrj if (lhsp->type == DEREF
364638fd1498Szrj || (lhsp->type == ADDRESSOF && lhsp->var == anything_id)
364738fd1498Szrj || rhsp->type == DEREF)
364838fd1498Szrj {
364938fd1498Szrj if (lhsp->type == DEREF)
365038fd1498Szrj {
365138fd1498Szrj gcc_assert (lhsc.length () == 1);
365238fd1498Szrj lhsp->offset = UNKNOWN_OFFSET;
365338fd1498Szrj }
365438fd1498Szrj if (rhsp->type == DEREF)
365538fd1498Szrj {
365638fd1498Szrj gcc_assert (rhsc.length () == 1);
365738fd1498Szrj rhsp->offset = UNKNOWN_OFFSET;
365838fd1498Szrj }
365938fd1498Szrj process_all_all_constraints (lhsc, rhsc);
366038fd1498Szrj }
366138fd1498Szrj else if (lhsp->type == SCALAR
366238fd1498Szrj && (rhsp->type == SCALAR
366338fd1498Szrj || rhsp->type == ADDRESSOF))
366438fd1498Szrj {
366538fd1498Szrj HOST_WIDE_INT lhssize, lhsoffset;
366638fd1498Szrj HOST_WIDE_INT rhssize, rhsoffset;
366738fd1498Szrj bool reverse;
366838fd1498Szrj unsigned k = 0;
366938fd1498Szrj if (!get_ref_base_and_extent_hwi (lhsop, &lhsoffset, &lhssize, &reverse)
367038fd1498Szrj || !get_ref_base_and_extent_hwi (rhsop, &rhsoffset, &rhssize,
367138fd1498Szrj &reverse))
367238fd1498Szrj {
367338fd1498Szrj process_all_all_constraints (lhsc, rhsc);
367438fd1498Szrj return;
367538fd1498Szrj }
367638fd1498Szrj for (j = 0; lhsc.iterate (j, &lhsp);)
367738fd1498Szrj {
367838fd1498Szrj varinfo_t lhsv, rhsv;
367938fd1498Szrj rhsp = &rhsc[k];
368038fd1498Szrj lhsv = get_varinfo (lhsp->var);
368138fd1498Szrj rhsv = get_varinfo (rhsp->var);
368238fd1498Szrj if (lhsv->may_have_pointers
368338fd1498Szrj && (lhsv->is_full_var
368438fd1498Szrj || rhsv->is_full_var
368538fd1498Szrj || ranges_overlap_p (lhsv->offset + rhsoffset, lhsv->size,
368638fd1498Szrj rhsv->offset + lhsoffset, rhsv->size)))
368738fd1498Szrj process_constraint (new_constraint (*lhsp, *rhsp));
368838fd1498Szrj if (!rhsv->is_full_var
368938fd1498Szrj && (lhsv->is_full_var
369038fd1498Szrj || (lhsv->offset + rhsoffset + lhsv->size
369138fd1498Szrj > rhsv->offset + lhsoffset + rhsv->size)))
369238fd1498Szrj {
369338fd1498Szrj ++k;
369438fd1498Szrj if (k >= rhsc.length ())
369538fd1498Szrj break;
369638fd1498Szrj }
369738fd1498Szrj else
369838fd1498Szrj ++j;
369938fd1498Szrj }
370038fd1498Szrj }
370138fd1498Szrj else
370238fd1498Szrj gcc_unreachable ();
370338fd1498Szrj }
370438fd1498Szrj
370538fd1498Szrj /* Create constraints ID = { rhsc }. */
370638fd1498Szrj
370738fd1498Szrj static void
make_constraints_to(unsigned id,vec<ce_s> rhsc)370838fd1498Szrj make_constraints_to (unsigned id, vec<ce_s> rhsc)
370938fd1498Szrj {
371038fd1498Szrj struct constraint_expr *c;
371138fd1498Szrj struct constraint_expr includes;
371238fd1498Szrj unsigned int j;
371338fd1498Szrj
371438fd1498Szrj includes.var = id;
371538fd1498Szrj includes.offset = 0;
371638fd1498Szrj includes.type = SCALAR;
371738fd1498Szrj
371838fd1498Szrj FOR_EACH_VEC_ELT (rhsc, j, c)
371938fd1498Szrj process_constraint (new_constraint (includes, *c));
372038fd1498Szrj }
372138fd1498Szrj
372238fd1498Szrj /* Create a constraint ID = OP. */
372338fd1498Szrj
372438fd1498Szrj static void
make_constraint_to(unsigned id,tree op)372538fd1498Szrj make_constraint_to (unsigned id, tree op)
372638fd1498Szrj {
372738fd1498Szrj auto_vec<ce_s> rhsc;
372838fd1498Szrj get_constraint_for_rhs (op, &rhsc);
372938fd1498Szrj make_constraints_to (id, rhsc);
373038fd1498Szrj }
373138fd1498Szrj
373238fd1498Szrj /* Create a constraint ID = &FROM. */
373338fd1498Szrj
373438fd1498Szrj static void
make_constraint_from(varinfo_t vi,int from)373538fd1498Szrj make_constraint_from (varinfo_t vi, int from)
373638fd1498Szrj {
373738fd1498Szrj struct constraint_expr lhs, rhs;
373838fd1498Szrj
373938fd1498Szrj lhs.var = vi->id;
374038fd1498Szrj lhs.offset = 0;
374138fd1498Szrj lhs.type = SCALAR;
374238fd1498Szrj
374338fd1498Szrj rhs.var = from;
374438fd1498Szrj rhs.offset = 0;
374538fd1498Szrj rhs.type = ADDRESSOF;
374638fd1498Szrj process_constraint (new_constraint (lhs, rhs));
374738fd1498Szrj }
374838fd1498Szrj
374938fd1498Szrj /* Create a constraint ID = FROM. */
375038fd1498Szrj
375138fd1498Szrj static void
make_copy_constraint(varinfo_t vi,int from)375238fd1498Szrj make_copy_constraint (varinfo_t vi, int from)
375338fd1498Szrj {
375438fd1498Szrj struct constraint_expr lhs, rhs;
375538fd1498Szrj
375638fd1498Szrj lhs.var = vi->id;
375738fd1498Szrj lhs.offset = 0;
375838fd1498Szrj lhs.type = SCALAR;
375938fd1498Szrj
376038fd1498Szrj rhs.var = from;
376138fd1498Szrj rhs.offset = 0;
376238fd1498Szrj rhs.type = SCALAR;
376338fd1498Szrj process_constraint (new_constraint (lhs, rhs));
376438fd1498Szrj }
376538fd1498Szrj
376638fd1498Szrj /* Make constraints necessary to make OP escape. */
376738fd1498Szrj
376838fd1498Szrj static void
make_escape_constraint(tree op)376938fd1498Szrj make_escape_constraint (tree op)
377038fd1498Szrj {
377138fd1498Szrj make_constraint_to (escaped_id, op);
377238fd1498Szrj }
377338fd1498Szrj
377438fd1498Szrj /* Add constraints to that the solution of VI is transitively closed. */
377538fd1498Szrj
377638fd1498Szrj static void
make_transitive_closure_constraints(varinfo_t vi)377738fd1498Szrj make_transitive_closure_constraints (varinfo_t vi)
377838fd1498Szrj {
377938fd1498Szrj struct constraint_expr lhs, rhs;
378038fd1498Szrj
378138fd1498Szrj /* VAR = *(VAR + UNKNOWN); */
378238fd1498Szrj lhs.type = SCALAR;
378338fd1498Szrj lhs.var = vi->id;
378438fd1498Szrj lhs.offset = 0;
378538fd1498Szrj rhs.type = DEREF;
378638fd1498Szrj rhs.var = vi->id;
378738fd1498Szrj rhs.offset = UNKNOWN_OFFSET;
378838fd1498Szrj process_constraint (new_constraint (lhs, rhs));
378938fd1498Szrj }
379038fd1498Szrj
379138fd1498Szrj /* Add constraints to that the solution of VI has all subvariables added. */
379238fd1498Szrj
379338fd1498Szrj static void
make_any_offset_constraints(varinfo_t vi)379438fd1498Szrj make_any_offset_constraints (varinfo_t vi)
379538fd1498Szrj {
379638fd1498Szrj struct constraint_expr lhs, rhs;
379738fd1498Szrj
379838fd1498Szrj /* VAR = VAR + UNKNOWN; */
379938fd1498Szrj lhs.type = SCALAR;
380038fd1498Szrj lhs.var = vi->id;
380138fd1498Szrj lhs.offset = 0;
380238fd1498Szrj rhs.type = SCALAR;
380338fd1498Szrj rhs.var = vi->id;
380438fd1498Szrj rhs.offset = UNKNOWN_OFFSET;
380538fd1498Szrj process_constraint (new_constraint (lhs, rhs));
380638fd1498Szrj }
380738fd1498Szrj
380838fd1498Szrj /* Temporary storage for fake var decls. */
380938fd1498Szrj struct obstack fake_var_decl_obstack;
381038fd1498Szrj
381138fd1498Szrj /* Build a fake VAR_DECL acting as referrer to a DECL_UID. */
381238fd1498Szrj
381338fd1498Szrj static tree
build_fake_var_decl(tree type)381438fd1498Szrj build_fake_var_decl (tree type)
381538fd1498Szrj {
381638fd1498Szrj tree decl = (tree) XOBNEW (&fake_var_decl_obstack, struct tree_var_decl);
381738fd1498Szrj memset (decl, 0, sizeof (struct tree_var_decl));
381838fd1498Szrj TREE_SET_CODE (decl, VAR_DECL);
381938fd1498Szrj TREE_TYPE (decl) = type;
382038fd1498Szrj DECL_UID (decl) = allocate_decl_uid ();
382138fd1498Szrj SET_DECL_PT_UID (decl, -1);
382238fd1498Szrj layout_decl (decl, 0);
382338fd1498Szrj return decl;
382438fd1498Szrj }
382538fd1498Szrj
382638fd1498Szrj /* Create a new artificial heap variable with NAME.
382738fd1498Szrj Return the created variable. */
382838fd1498Szrj
382938fd1498Szrj static varinfo_t
make_heapvar(const char * name,bool add_id)383038fd1498Szrj make_heapvar (const char *name, bool add_id)
383138fd1498Szrj {
383238fd1498Szrj varinfo_t vi;
383338fd1498Szrj tree heapvar;
383438fd1498Szrj
383538fd1498Szrj heapvar = build_fake_var_decl (ptr_type_node);
383638fd1498Szrj DECL_EXTERNAL (heapvar) = 1;
383738fd1498Szrj
383838fd1498Szrj vi = new_var_info (heapvar, name, add_id);
383938fd1498Szrj vi->is_artificial_var = true;
384038fd1498Szrj vi->is_heap_var = true;
384138fd1498Szrj vi->is_unknown_size_var = true;
384238fd1498Szrj vi->offset = 0;
384338fd1498Szrj vi->fullsize = ~0;
384438fd1498Szrj vi->size = ~0;
384538fd1498Szrj vi->is_full_var = true;
384638fd1498Szrj insert_vi_for_tree (heapvar, vi);
384738fd1498Szrj
384838fd1498Szrj return vi;
384938fd1498Szrj }
385038fd1498Szrj
385138fd1498Szrj /* Create a new artificial heap variable with NAME and make a
385238fd1498Szrj constraint from it to LHS. Set flags according to a tag used
385338fd1498Szrj for tracking restrict pointers. */
385438fd1498Szrj
385538fd1498Szrj static varinfo_t
make_constraint_from_restrict(varinfo_t lhs,const char * name,bool add_id)385638fd1498Szrj make_constraint_from_restrict (varinfo_t lhs, const char *name, bool add_id)
385738fd1498Szrj {
385838fd1498Szrj varinfo_t vi = make_heapvar (name, add_id);
385938fd1498Szrj vi->is_restrict_var = 1;
386038fd1498Szrj vi->is_global_var = 1;
386138fd1498Szrj vi->may_have_pointers = 1;
386238fd1498Szrj make_constraint_from (lhs, vi->id);
386338fd1498Szrj return vi;
386438fd1498Szrj }
386538fd1498Szrj
386638fd1498Szrj /* Create a new artificial heap variable with NAME and make a
386738fd1498Szrj constraint from it to LHS. Set flags according to a tag used
386838fd1498Szrj for tracking restrict pointers and make the artificial heap
386938fd1498Szrj point to global memory. */
387038fd1498Szrj
387138fd1498Szrj static varinfo_t
make_constraint_from_global_restrict(varinfo_t lhs,const char * name,bool add_id)387238fd1498Szrj make_constraint_from_global_restrict (varinfo_t lhs, const char *name,
387338fd1498Szrj bool add_id)
387438fd1498Szrj {
387538fd1498Szrj varinfo_t vi = make_constraint_from_restrict (lhs, name, add_id);
387638fd1498Szrj make_copy_constraint (vi, nonlocal_id);
387738fd1498Szrj return vi;
387838fd1498Szrj }
387938fd1498Szrj
388038fd1498Szrj /* In IPA mode there are varinfos for different aspects of reach
388138fd1498Szrj function designator. One for the points-to set of the return
388238fd1498Szrj value, one for the variables that are clobbered by the function,
388338fd1498Szrj one for its uses and one for each parameter (including a single
388438fd1498Szrj glob for remaining variadic arguments). */
388538fd1498Szrj
388638fd1498Szrj enum { fi_clobbers = 1, fi_uses = 2,
388738fd1498Szrj fi_static_chain = 3, fi_result = 4, fi_parm_base = 5 };
388838fd1498Szrj
388938fd1498Szrj /* Get a constraint for the requested part of a function designator FI
389038fd1498Szrj when operating in IPA mode. */
389138fd1498Szrj
389238fd1498Szrj static struct constraint_expr
get_function_part_constraint(varinfo_t fi,unsigned part)389338fd1498Szrj get_function_part_constraint (varinfo_t fi, unsigned part)
389438fd1498Szrj {
389538fd1498Szrj struct constraint_expr c;
389638fd1498Szrj
389738fd1498Szrj gcc_assert (in_ipa_mode);
389838fd1498Szrj
389938fd1498Szrj if (fi->id == anything_id)
390038fd1498Szrj {
390138fd1498Szrj /* ??? We probably should have a ANYFN special variable. */
390238fd1498Szrj c.var = anything_id;
390338fd1498Szrj c.offset = 0;
390438fd1498Szrj c.type = SCALAR;
390538fd1498Szrj }
390638fd1498Szrj else if (TREE_CODE (fi->decl) == FUNCTION_DECL)
390738fd1498Szrj {
390838fd1498Szrj varinfo_t ai = first_vi_for_offset (fi, part);
390938fd1498Szrj if (ai)
391038fd1498Szrj c.var = ai->id;
391138fd1498Szrj else
391238fd1498Szrj c.var = anything_id;
391338fd1498Szrj c.offset = 0;
391438fd1498Szrj c.type = SCALAR;
391538fd1498Szrj }
391638fd1498Szrj else
391738fd1498Szrj {
391838fd1498Szrj c.var = fi->id;
391938fd1498Szrj c.offset = part;
392038fd1498Szrj c.type = DEREF;
392138fd1498Szrj }
392238fd1498Szrj
392338fd1498Szrj return c;
392438fd1498Szrj }
392538fd1498Szrj
392638fd1498Szrj /* For non-IPA mode, generate constraints necessary for a call on the
392738fd1498Szrj RHS. */
392838fd1498Szrj
392938fd1498Szrj static void
handle_rhs_call(gcall * stmt,vec<ce_s> * results)393038fd1498Szrj handle_rhs_call (gcall *stmt, vec<ce_s> *results)
393138fd1498Szrj {
393238fd1498Szrj struct constraint_expr rhsc;
393338fd1498Szrj unsigned i;
393438fd1498Szrj bool returns_uses = false;
393538fd1498Szrj
393638fd1498Szrj for (i = 0; i < gimple_call_num_args (stmt); ++i)
393738fd1498Szrj {
393838fd1498Szrj tree arg = gimple_call_arg (stmt, i);
393938fd1498Szrj int flags = gimple_call_arg_flags (stmt, i);
394038fd1498Szrj
394138fd1498Szrj /* If the argument is not used we can ignore it. */
394238fd1498Szrj if (flags & EAF_UNUSED)
394338fd1498Szrj continue;
394438fd1498Szrj
394538fd1498Szrj /* As we compute ESCAPED context-insensitive we do not gain
394638fd1498Szrj any precision with just EAF_NOCLOBBER but not EAF_NOESCAPE
394738fd1498Szrj set. The argument would still get clobbered through the
394838fd1498Szrj escape solution. */
394938fd1498Szrj if ((flags & EAF_NOCLOBBER)
395038fd1498Szrj && (flags & EAF_NOESCAPE))
395138fd1498Szrj {
395238fd1498Szrj varinfo_t uses = get_call_use_vi (stmt);
395338fd1498Szrj varinfo_t tem = new_var_info (NULL_TREE, "callarg", true);
395438fd1498Szrj tem->is_reg_var = true;
395538fd1498Szrj make_constraint_to (tem->id, arg);
395638fd1498Szrj make_any_offset_constraints (tem);
395738fd1498Szrj if (!(flags & EAF_DIRECT))
395838fd1498Szrj make_transitive_closure_constraints (tem);
395938fd1498Szrj make_copy_constraint (uses, tem->id);
396038fd1498Szrj returns_uses = true;
396138fd1498Szrj }
396238fd1498Szrj else if (flags & EAF_NOESCAPE)
396338fd1498Szrj {
396438fd1498Szrj struct constraint_expr lhs, rhs;
396538fd1498Szrj varinfo_t uses = get_call_use_vi (stmt);
396638fd1498Szrj varinfo_t clobbers = get_call_clobber_vi (stmt);
396738fd1498Szrj varinfo_t tem = new_var_info (NULL_TREE, "callarg", true);
396838fd1498Szrj tem->is_reg_var = true;
396938fd1498Szrj make_constraint_to (tem->id, arg);
397038fd1498Szrj make_any_offset_constraints (tem);
397138fd1498Szrj if (!(flags & EAF_DIRECT))
397238fd1498Szrj make_transitive_closure_constraints (tem);
397338fd1498Szrj make_copy_constraint (uses, tem->id);
397438fd1498Szrj make_copy_constraint (clobbers, tem->id);
397538fd1498Szrj /* Add *tem = nonlocal, do not add *tem = callused as
397638fd1498Szrj EAF_NOESCAPE parameters do not escape to other parameters
397738fd1498Szrj and all other uses appear in NONLOCAL as well. */
397838fd1498Szrj lhs.type = DEREF;
397938fd1498Szrj lhs.var = tem->id;
398038fd1498Szrj lhs.offset = 0;
398138fd1498Szrj rhs.type = SCALAR;
398238fd1498Szrj rhs.var = nonlocal_id;
398338fd1498Szrj rhs.offset = 0;
398438fd1498Szrj process_constraint (new_constraint (lhs, rhs));
398538fd1498Szrj returns_uses = true;
398638fd1498Szrj }
398738fd1498Szrj else
398838fd1498Szrj make_escape_constraint (arg);
398938fd1498Szrj }
399038fd1498Szrj
399138fd1498Szrj /* If we added to the calls uses solution make sure we account for
399238fd1498Szrj pointers to it to be returned. */
399338fd1498Szrj if (returns_uses)
399438fd1498Szrj {
399538fd1498Szrj rhsc.var = get_call_use_vi (stmt)->id;
399638fd1498Szrj rhsc.offset = UNKNOWN_OFFSET;
399738fd1498Szrj rhsc.type = SCALAR;
399838fd1498Szrj results->safe_push (rhsc);
399938fd1498Szrj }
400038fd1498Szrj
400138fd1498Szrj /* The static chain escapes as well. */
400238fd1498Szrj if (gimple_call_chain (stmt))
400338fd1498Szrj make_escape_constraint (gimple_call_chain (stmt));
400438fd1498Szrj
400538fd1498Szrj /* And if we applied NRV the address of the return slot escapes as well. */
400638fd1498Szrj if (gimple_call_return_slot_opt_p (stmt)
400738fd1498Szrj && gimple_call_lhs (stmt) != NULL_TREE
400838fd1498Szrj && TREE_ADDRESSABLE (TREE_TYPE (gimple_call_lhs (stmt))))
400938fd1498Szrj {
401038fd1498Szrj auto_vec<ce_s> tmpc;
401138fd1498Szrj struct constraint_expr lhsc, *c;
401238fd1498Szrj get_constraint_for_address_of (gimple_call_lhs (stmt), &tmpc);
401338fd1498Szrj lhsc.var = escaped_id;
401438fd1498Szrj lhsc.offset = 0;
401538fd1498Szrj lhsc.type = SCALAR;
401638fd1498Szrj FOR_EACH_VEC_ELT (tmpc, i, c)
401738fd1498Szrj process_constraint (new_constraint (lhsc, *c));
401838fd1498Szrj }
401938fd1498Szrj
402038fd1498Szrj /* Regular functions return nonlocal memory. */
402138fd1498Szrj rhsc.var = nonlocal_id;
402238fd1498Szrj rhsc.offset = 0;
402338fd1498Szrj rhsc.type = SCALAR;
402438fd1498Szrj results->safe_push (rhsc);
402538fd1498Szrj }
402638fd1498Szrj
402738fd1498Szrj /* For non-IPA mode, generate constraints necessary for a call
402838fd1498Szrj that returns a pointer and assigns it to LHS. This simply makes
402938fd1498Szrj the LHS point to global and escaped variables. */
403038fd1498Szrj
403138fd1498Szrj static void
handle_lhs_call(gcall * stmt,tree lhs,int flags,vec<ce_s> rhsc,tree fndecl)403238fd1498Szrj handle_lhs_call (gcall *stmt, tree lhs, int flags, vec<ce_s> rhsc,
403338fd1498Szrj tree fndecl)
403438fd1498Szrj {
403538fd1498Szrj auto_vec<ce_s> lhsc;
403638fd1498Szrj
403738fd1498Szrj get_constraint_for (lhs, &lhsc);
403838fd1498Szrj /* If the store is to a global decl make sure to
403938fd1498Szrj add proper escape constraints. */
404038fd1498Szrj lhs = get_base_address (lhs);
404138fd1498Szrj if (lhs
404238fd1498Szrj && DECL_P (lhs)
404338fd1498Szrj && is_global_var (lhs))
404438fd1498Szrj {
404538fd1498Szrj struct constraint_expr tmpc;
404638fd1498Szrj tmpc.var = escaped_id;
404738fd1498Szrj tmpc.offset = 0;
404838fd1498Szrj tmpc.type = SCALAR;
404938fd1498Szrj lhsc.safe_push (tmpc);
405038fd1498Szrj }
405138fd1498Szrj
405238fd1498Szrj /* If the call returns an argument unmodified override the rhs
405338fd1498Szrj constraints. */
405438fd1498Szrj if (flags & ERF_RETURNS_ARG
405538fd1498Szrj && (flags & ERF_RETURN_ARG_MASK) < gimple_call_num_args (stmt))
405638fd1498Szrj {
405738fd1498Szrj tree arg;
405838fd1498Szrj rhsc.create (0);
405938fd1498Szrj arg = gimple_call_arg (stmt, flags & ERF_RETURN_ARG_MASK);
406038fd1498Szrj get_constraint_for (arg, &rhsc);
406138fd1498Szrj process_all_all_constraints (lhsc, rhsc);
406238fd1498Szrj rhsc.release ();
406338fd1498Szrj }
406438fd1498Szrj else if (flags & ERF_NOALIAS)
406538fd1498Szrj {
406638fd1498Szrj varinfo_t vi;
406738fd1498Szrj struct constraint_expr tmpc;
406838fd1498Szrj rhsc.create (0);
406938fd1498Szrj vi = make_heapvar ("HEAP", true);
407038fd1498Szrj /* We are marking allocated storage local, we deal with it becoming
407138fd1498Szrj global by escaping and setting of vars_contains_escaped_heap. */
407238fd1498Szrj DECL_EXTERNAL (vi->decl) = 0;
407338fd1498Szrj vi->is_global_var = 0;
407438fd1498Szrj /* If this is not a real malloc call assume the memory was
407538fd1498Szrj initialized and thus may point to global memory. All
407638fd1498Szrj builtin functions with the malloc attribute behave in a sane way. */
407738fd1498Szrj if (!fndecl
407838fd1498Szrj || DECL_BUILT_IN_CLASS (fndecl) != BUILT_IN_NORMAL)
407938fd1498Szrj make_constraint_from (vi, nonlocal_id);
408038fd1498Szrj tmpc.var = vi->id;
408138fd1498Szrj tmpc.offset = 0;
408238fd1498Szrj tmpc.type = ADDRESSOF;
408338fd1498Szrj rhsc.safe_push (tmpc);
408438fd1498Szrj process_all_all_constraints (lhsc, rhsc);
408538fd1498Szrj rhsc.release ();
408638fd1498Szrj }
408738fd1498Szrj else
408838fd1498Szrj process_all_all_constraints (lhsc, rhsc);
408938fd1498Szrj }
409038fd1498Szrj
409138fd1498Szrj /* For non-IPA mode, generate constraints necessary for a call of a
409238fd1498Szrj const function that returns a pointer in the statement STMT. */
409338fd1498Szrj
409438fd1498Szrj static void
handle_const_call(gcall * stmt,vec<ce_s> * results)409538fd1498Szrj handle_const_call (gcall *stmt, vec<ce_s> *results)
409638fd1498Szrj {
409738fd1498Szrj struct constraint_expr rhsc;
409838fd1498Szrj unsigned int k;
409938fd1498Szrj bool need_uses = false;
410038fd1498Szrj
410138fd1498Szrj /* Treat nested const functions the same as pure functions as far
410238fd1498Szrj as the static chain is concerned. */
410338fd1498Szrj if (gimple_call_chain (stmt))
410438fd1498Szrj {
410538fd1498Szrj varinfo_t uses = get_call_use_vi (stmt);
410638fd1498Szrj make_constraint_to (uses->id, gimple_call_chain (stmt));
410738fd1498Szrj need_uses = true;
410838fd1498Szrj }
410938fd1498Szrj
411038fd1498Szrj /* And if we applied NRV the address of the return slot escapes as well. */
411138fd1498Szrj if (gimple_call_return_slot_opt_p (stmt)
411238fd1498Szrj && gimple_call_lhs (stmt) != NULL_TREE
411338fd1498Szrj && TREE_ADDRESSABLE (TREE_TYPE (gimple_call_lhs (stmt))))
411438fd1498Szrj {
411538fd1498Szrj varinfo_t uses = get_call_use_vi (stmt);
411638fd1498Szrj auto_vec<ce_s> tmpc;
411738fd1498Szrj get_constraint_for_address_of (gimple_call_lhs (stmt), &tmpc);
411838fd1498Szrj make_constraints_to (uses->id, tmpc);
411938fd1498Szrj need_uses = true;
412038fd1498Szrj }
412138fd1498Szrj
412238fd1498Szrj if (need_uses)
412338fd1498Szrj {
412438fd1498Szrj varinfo_t uses = get_call_use_vi (stmt);
412538fd1498Szrj make_any_offset_constraints (uses);
412638fd1498Szrj make_transitive_closure_constraints (uses);
412738fd1498Szrj rhsc.var = uses->id;
412838fd1498Szrj rhsc.offset = 0;
412938fd1498Szrj rhsc.type = SCALAR;
413038fd1498Szrj results->safe_push (rhsc);
413138fd1498Szrj }
413238fd1498Szrj
413338fd1498Szrj /* May return offsetted arguments. */
413438fd1498Szrj varinfo_t tem = NULL;
413538fd1498Szrj if (gimple_call_num_args (stmt) != 0)
413638fd1498Szrj {
413738fd1498Szrj tem = new_var_info (NULL_TREE, "callarg", true);
413838fd1498Szrj tem->is_reg_var = true;
413938fd1498Szrj }
414038fd1498Szrj for (k = 0; k < gimple_call_num_args (stmt); ++k)
414138fd1498Szrj {
414238fd1498Szrj tree arg = gimple_call_arg (stmt, k);
414338fd1498Szrj auto_vec<ce_s> argc;
414438fd1498Szrj get_constraint_for_rhs (arg, &argc);
414538fd1498Szrj make_constraints_to (tem->id, argc);
414638fd1498Szrj }
414738fd1498Szrj if (tem)
414838fd1498Szrj {
414938fd1498Szrj ce_s ce;
415038fd1498Szrj ce.type = SCALAR;
415138fd1498Szrj ce.var = tem->id;
415238fd1498Szrj ce.offset = UNKNOWN_OFFSET;
415338fd1498Szrj results->safe_push (ce);
415438fd1498Szrj }
415538fd1498Szrj
415638fd1498Szrj /* May return addresses of globals. */
415738fd1498Szrj rhsc.var = nonlocal_id;
415838fd1498Szrj rhsc.offset = 0;
415938fd1498Szrj rhsc.type = ADDRESSOF;
416038fd1498Szrj results->safe_push (rhsc);
416138fd1498Szrj }
416238fd1498Szrj
416338fd1498Szrj /* For non-IPA mode, generate constraints necessary for a call to a
416438fd1498Szrj pure function in statement STMT. */
416538fd1498Szrj
416638fd1498Szrj static void
handle_pure_call(gcall * stmt,vec<ce_s> * results)416738fd1498Szrj handle_pure_call (gcall *stmt, vec<ce_s> *results)
416838fd1498Szrj {
416938fd1498Szrj struct constraint_expr rhsc;
417038fd1498Szrj unsigned i;
417138fd1498Szrj varinfo_t uses = NULL;
417238fd1498Szrj
417338fd1498Szrj /* Memory reached from pointer arguments is call-used. */
417438fd1498Szrj for (i = 0; i < gimple_call_num_args (stmt); ++i)
417538fd1498Szrj {
417638fd1498Szrj tree arg = gimple_call_arg (stmt, i);
417738fd1498Szrj if (!uses)
417838fd1498Szrj {
417938fd1498Szrj uses = get_call_use_vi (stmt);
418038fd1498Szrj make_any_offset_constraints (uses);
418138fd1498Szrj make_transitive_closure_constraints (uses);
418238fd1498Szrj }
418338fd1498Szrj make_constraint_to (uses->id, arg);
418438fd1498Szrj }
418538fd1498Szrj
418638fd1498Szrj /* The static chain is used as well. */
418738fd1498Szrj if (gimple_call_chain (stmt))
418838fd1498Szrj {
418938fd1498Szrj if (!uses)
419038fd1498Szrj {
419138fd1498Szrj uses = get_call_use_vi (stmt);
419238fd1498Szrj make_any_offset_constraints (uses);
419338fd1498Szrj make_transitive_closure_constraints (uses);
419438fd1498Szrj }
419538fd1498Szrj make_constraint_to (uses->id, gimple_call_chain (stmt));
419638fd1498Szrj }
419738fd1498Szrj
419838fd1498Szrj /* And if we applied NRV the address of the return slot. */
419938fd1498Szrj if (gimple_call_return_slot_opt_p (stmt)
420038fd1498Szrj && gimple_call_lhs (stmt) != NULL_TREE
420138fd1498Szrj && TREE_ADDRESSABLE (TREE_TYPE (gimple_call_lhs (stmt))))
420238fd1498Szrj {
420338fd1498Szrj if (!uses)
420438fd1498Szrj {
420538fd1498Szrj uses = get_call_use_vi (stmt);
420638fd1498Szrj make_any_offset_constraints (uses);
420738fd1498Szrj make_transitive_closure_constraints (uses);
420838fd1498Szrj }
420938fd1498Szrj auto_vec<ce_s> tmpc;
421038fd1498Szrj get_constraint_for_address_of (gimple_call_lhs (stmt), &tmpc);
421138fd1498Szrj make_constraints_to (uses->id, tmpc);
421238fd1498Szrj }
421338fd1498Szrj
421438fd1498Szrj /* Pure functions may return call-used and nonlocal memory. */
421538fd1498Szrj if (uses)
421638fd1498Szrj {
421738fd1498Szrj rhsc.var = uses->id;
421838fd1498Szrj rhsc.offset = 0;
421938fd1498Szrj rhsc.type = SCALAR;
422038fd1498Szrj results->safe_push (rhsc);
422138fd1498Szrj }
422238fd1498Szrj rhsc.var = nonlocal_id;
422338fd1498Szrj rhsc.offset = 0;
422438fd1498Szrj rhsc.type = SCALAR;
422538fd1498Szrj results->safe_push (rhsc);
422638fd1498Szrj }
422738fd1498Szrj
422838fd1498Szrj
422938fd1498Szrj /* Return the varinfo for the callee of CALL. */
423038fd1498Szrj
423138fd1498Szrj static varinfo_t
get_fi_for_callee(gcall * call)423238fd1498Szrj get_fi_for_callee (gcall *call)
423338fd1498Szrj {
423438fd1498Szrj tree decl, fn = gimple_call_fn (call);
423538fd1498Szrj
423638fd1498Szrj if (fn && TREE_CODE (fn) == OBJ_TYPE_REF)
423738fd1498Szrj fn = OBJ_TYPE_REF_EXPR (fn);
423838fd1498Szrj
423938fd1498Szrj /* If we can directly resolve the function being called, do so.
424038fd1498Szrj Otherwise, it must be some sort of indirect expression that
424138fd1498Szrj we should still be able to handle. */
424238fd1498Szrj decl = gimple_call_addr_fndecl (fn);
424338fd1498Szrj if (decl)
424438fd1498Szrj return get_vi_for_tree (decl);
424538fd1498Szrj
424638fd1498Szrj /* If the function is anything other than a SSA name pointer we have no
424738fd1498Szrj clue and should be getting ANYFN (well, ANYTHING for now). */
424838fd1498Szrj if (!fn || TREE_CODE (fn) != SSA_NAME)
424938fd1498Szrj return get_varinfo (anything_id);
425038fd1498Szrj
425138fd1498Szrj if (SSA_NAME_IS_DEFAULT_DEF (fn)
425238fd1498Szrj && (TREE_CODE (SSA_NAME_VAR (fn)) == PARM_DECL
425338fd1498Szrj || TREE_CODE (SSA_NAME_VAR (fn)) == RESULT_DECL))
425438fd1498Szrj fn = SSA_NAME_VAR (fn);
425538fd1498Szrj
425638fd1498Szrj return get_vi_for_tree (fn);
425738fd1498Szrj }
425838fd1498Szrj
425938fd1498Szrj /* Create constraints for assigning call argument ARG to the incoming parameter
426038fd1498Szrj INDEX of function FI. */
426138fd1498Szrj
426238fd1498Szrj static void
find_func_aliases_for_call_arg(varinfo_t fi,unsigned index,tree arg)426338fd1498Szrj find_func_aliases_for_call_arg (varinfo_t fi, unsigned index, tree arg)
426438fd1498Szrj {
426538fd1498Szrj struct constraint_expr lhs;
426638fd1498Szrj lhs = get_function_part_constraint (fi, fi_parm_base + index);
426738fd1498Szrj
426838fd1498Szrj auto_vec<ce_s, 2> rhsc;
426938fd1498Szrj get_constraint_for_rhs (arg, &rhsc);
427038fd1498Szrj
427138fd1498Szrj unsigned j;
427238fd1498Szrj struct constraint_expr *rhsp;
427338fd1498Szrj FOR_EACH_VEC_ELT (rhsc, j, rhsp)
427438fd1498Szrj process_constraint (new_constraint (lhs, *rhsp));
427538fd1498Szrj }
427638fd1498Szrj
427738fd1498Szrj /* Return true if FNDECL may be part of another lto partition. */
427838fd1498Szrj
427938fd1498Szrj static bool
fndecl_maybe_in_other_partition(tree fndecl)428038fd1498Szrj fndecl_maybe_in_other_partition (tree fndecl)
428138fd1498Szrj {
428238fd1498Szrj cgraph_node *fn_node = cgraph_node::get (fndecl);
428338fd1498Szrj if (fn_node == NULL)
428438fd1498Szrj return true;
428538fd1498Szrj
428638fd1498Szrj return fn_node->in_other_partition;
428738fd1498Szrj }
428838fd1498Szrj
428938fd1498Szrj /* Create constraints for the builtin call T. Return true if the call
429038fd1498Szrj was handled, otherwise false. */
429138fd1498Szrj
429238fd1498Szrj static bool
find_func_aliases_for_builtin_call(struct function * fn,gcall * t)429338fd1498Szrj find_func_aliases_for_builtin_call (struct function *fn, gcall *t)
429438fd1498Szrj {
429538fd1498Szrj tree fndecl = gimple_call_fndecl (t);
429638fd1498Szrj auto_vec<ce_s, 2> lhsc;
429738fd1498Szrj auto_vec<ce_s, 4> rhsc;
429838fd1498Szrj varinfo_t fi;
429938fd1498Szrj
430038fd1498Szrj if (gimple_call_builtin_p (t, BUILT_IN_NORMAL))
430138fd1498Szrj /* ??? All builtins that are handled here need to be handled
430238fd1498Szrj in the alias-oracle query functions explicitly! */
430338fd1498Szrj switch (DECL_FUNCTION_CODE (fndecl))
430438fd1498Szrj {
430538fd1498Szrj /* All the following functions return a pointer to the same object
430638fd1498Szrj as their first argument points to. The functions do not add
430738fd1498Szrj to the ESCAPED solution. The functions make the first argument
430838fd1498Szrj pointed to memory point to what the second argument pointed to
430938fd1498Szrj memory points to. */
431038fd1498Szrj case BUILT_IN_STRCPY:
431138fd1498Szrj case BUILT_IN_STRNCPY:
431238fd1498Szrj case BUILT_IN_BCOPY:
431338fd1498Szrj case BUILT_IN_MEMCPY:
431438fd1498Szrj case BUILT_IN_MEMMOVE:
431538fd1498Szrj case BUILT_IN_MEMPCPY:
431638fd1498Szrj case BUILT_IN_STPCPY:
431738fd1498Szrj case BUILT_IN_STPNCPY:
431838fd1498Szrj case BUILT_IN_STRCAT:
431938fd1498Szrj case BUILT_IN_STRNCAT:
432038fd1498Szrj case BUILT_IN_STRCPY_CHK:
432138fd1498Szrj case BUILT_IN_STRNCPY_CHK:
432238fd1498Szrj case BUILT_IN_MEMCPY_CHK:
432338fd1498Szrj case BUILT_IN_MEMMOVE_CHK:
432438fd1498Szrj case BUILT_IN_MEMPCPY_CHK:
432538fd1498Szrj case BUILT_IN_STPCPY_CHK:
432638fd1498Szrj case BUILT_IN_STPNCPY_CHK:
432738fd1498Szrj case BUILT_IN_STRCAT_CHK:
432838fd1498Szrj case BUILT_IN_STRNCAT_CHK:
432938fd1498Szrj case BUILT_IN_TM_MEMCPY:
433038fd1498Szrj case BUILT_IN_TM_MEMMOVE:
433138fd1498Szrj {
433238fd1498Szrj tree res = gimple_call_lhs (t);
433338fd1498Szrj tree dest = gimple_call_arg (t, (DECL_FUNCTION_CODE (fndecl)
433438fd1498Szrj == BUILT_IN_BCOPY ? 1 : 0));
433538fd1498Szrj tree src = gimple_call_arg (t, (DECL_FUNCTION_CODE (fndecl)
433638fd1498Szrj == BUILT_IN_BCOPY ? 0 : 1));
433738fd1498Szrj if (res != NULL_TREE)
433838fd1498Szrj {
433938fd1498Szrj get_constraint_for (res, &lhsc);
434038fd1498Szrj if (DECL_FUNCTION_CODE (fndecl) == BUILT_IN_MEMPCPY
434138fd1498Szrj || DECL_FUNCTION_CODE (fndecl) == BUILT_IN_STPCPY
434238fd1498Szrj || DECL_FUNCTION_CODE (fndecl) == BUILT_IN_STPNCPY
434338fd1498Szrj || DECL_FUNCTION_CODE (fndecl) == BUILT_IN_MEMPCPY_CHK
434438fd1498Szrj || DECL_FUNCTION_CODE (fndecl) == BUILT_IN_STPCPY_CHK
434538fd1498Szrj || DECL_FUNCTION_CODE (fndecl) == BUILT_IN_STPNCPY_CHK)
434638fd1498Szrj get_constraint_for_ptr_offset (dest, NULL_TREE, &rhsc);
434738fd1498Szrj else
434838fd1498Szrj get_constraint_for (dest, &rhsc);
434938fd1498Szrj process_all_all_constraints (lhsc, rhsc);
435038fd1498Szrj lhsc.truncate (0);
435138fd1498Szrj rhsc.truncate (0);
435238fd1498Szrj }
435338fd1498Szrj get_constraint_for_ptr_offset (dest, NULL_TREE, &lhsc);
435438fd1498Szrj get_constraint_for_ptr_offset (src, NULL_TREE, &rhsc);
435538fd1498Szrj do_deref (&lhsc);
435638fd1498Szrj do_deref (&rhsc);
435738fd1498Szrj process_all_all_constraints (lhsc, rhsc);
435838fd1498Szrj return true;
435938fd1498Szrj }
436038fd1498Szrj case BUILT_IN_MEMSET:
436138fd1498Szrj case BUILT_IN_MEMSET_CHK:
436238fd1498Szrj case BUILT_IN_TM_MEMSET:
436338fd1498Szrj {
436438fd1498Szrj tree res = gimple_call_lhs (t);
436538fd1498Szrj tree dest = gimple_call_arg (t, 0);
436638fd1498Szrj unsigned i;
436738fd1498Szrj ce_s *lhsp;
436838fd1498Szrj struct constraint_expr ac;
436938fd1498Szrj if (res != NULL_TREE)
437038fd1498Szrj {
437138fd1498Szrj get_constraint_for (res, &lhsc);
437238fd1498Szrj get_constraint_for (dest, &rhsc);
437338fd1498Szrj process_all_all_constraints (lhsc, rhsc);
437438fd1498Szrj lhsc.truncate (0);
437538fd1498Szrj }
437638fd1498Szrj get_constraint_for_ptr_offset (dest, NULL_TREE, &lhsc);
437738fd1498Szrj do_deref (&lhsc);
437838fd1498Szrj if (flag_delete_null_pointer_checks
437938fd1498Szrj && integer_zerop (gimple_call_arg (t, 1)))
438038fd1498Szrj {
438138fd1498Szrj ac.type = ADDRESSOF;
438238fd1498Szrj ac.var = nothing_id;
438338fd1498Szrj }
438438fd1498Szrj else
438538fd1498Szrj {
438638fd1498Szrj ac.type = SCALAR;
438738fd1498Szrj ac.var = integer_id;
438838fd1498Szrj }
438938fd1498Szrj ac.offset = 0;
439038fd1498Szrj FOR_EACH_VEC_ELT (lhsc, i, lhsp)
439138fd1498Szrj process_constraint (new_constraint (*lhsp, ac));
439238fd1498Szrj return true;
439338fd1498Szrj }
439438fd1498Szrj case BUILT_IN_POSIX_MEMALIGN:
439538fd1498Szrj {
439638fd1498Szrj tree ptrptr = gimple_call_arg (t, 0);
439738fd1498Szrj get_constraint_for (ptrptr, &lhsc);
439838fd1498Szrj do_deref (&lhsc);
439938fd1498Szrj varinfo_t vi = make_heapvar ("HEAP", true);
440038fd1498Szrj /* We are marking allocated storage local, we deal with it becoming
440138fd1498Szrj global by escaping and setting of vars_contains_escaped_heap. */
440238fd1498Szrj DECL_EXTERNAL (vi->decl) = 0;
440338fd1498Szrj vi->is_global_var = 0;
440438fd1498Szrj struct constraint_expr tmpc;
440538fd1498Szrj tmpc.var = vi->id;
440638fd1498Szrj tmpc.offset = 0;
440738fd1498Szrj tmpc.type = ADDRESSOF;
440838fd1498Szrj rhsc.safe_push (tmpc);
440938fd1498Szrj process_all_all_constraints (lhsc, rhsc);
441038fd1498Szrj return true;
441138fd1498Szrj }
441238fd1498Szrj case BUILT_IN_ASSUME_ALIGNED:
441338fd1498Szrj {
441438fd1498Szrj tree res = gimple_call_lhs (t);
441538fd1498Szrj tree dest = gimple_call_arg (t, 0);
441638fd1498Szrj if (res != NULL_TREE)
441738fd1498Szrj {
441838fd1498Szrj get_constraint_for (res, &lhsc);
441938fd1498Szrj get_constraint_for (dest, &rhsc);
442038fd1498Szrj process_all_all_constraints (lhsc, rhsc);
442138fd1498Szrj }
442238fd1498Szrj return true;
442338fd1498Szrj }
442438fd1498Szrj /* All the following functions do not return pointers, do not
442538fd1498Szrj modify the points-to sets of memory reachable from their
442638fd1498Szrj arguments and do not add to the ESCAPED solution. */
442738fd1498Szrj case BUILT_IN_SINCOS:
442838fd1498Szrj case BUILT_IN_SINCOSF:
442938fd1498Szrj case BUILT_IN_SINCOSL:
443038fd1498Szrj case BUILT_IN_FREXP:
443138fd1498Szrj case BUILT_IN_FREXPF:
443238fd1498Szrj case BUILT_IN_FREXPL:
443338fd1498Szrj case BUILT_IN_GAMMA_R:
443438fd1498Szrj case BUILT_IN_GAMMAF_R:
443538fd1498Szrj case BUILT_IN_GAMMAL_R:
443638fd1498Szrj case BUILT_IN_LGAMMA_R:
443738fd1498Szrj case BUILT_IN_LGAMMAF_R:
443838fd1498Szrj case BUILT_IN_LGAMMAL_R:
443938fd1498Szrj case BUILT_IN_MODF:
444038fd1498Szrj case BUILT_IN_MODFF:
444138fd1498Szrj case BUILT_IN_MODFL:
444238fd1498Szrj case BUILT_IN_REMQUO:
444338fd1498Szrj case BUILT_IN_REMQUOF:
444438fd1498Szrj case BUILT_IN_REMQUOL:
444538fd1498Szrj case BUILT_IN_FREE:
444638fd1498Szrj return true;
444738fd1498Szrj case BUILT_IN_STRDUP:
444838fd1498Szrj case BUILT_IN_STRNDUP:
444938fd1498Szrj case BUILT_IN_REALLOC:
445038fd1498Szrj if (gimple_call_lhs (t))
445138fd1498Szrj {
445238fd1498Szrj handle_lhs_call (t, gimple_call_lhs (t),
445338fd1498Szrj gimple_call_return_flags (t) | ERF_NOALIAS,
445438fd1498Szrj vNULL, fndecl);
445538fd1498Szrj get_constraint_for_ptr_offset (gimple_call_lhs (t),
445638fd1498Szrj NULL_TREE, &lhsc);
445738fd1498Szrj get_constraint_for_ptr_offset (gimple_call_arg (t, 0),
445838fd1498Szrj NULL_TREE, &rhsc);
445938fd1498Szrj do_deref (&lhsc);
446038fd1498Szrj do_deref (&rhsc);
446138fd1498Szrj process_all_all_constraints (lhsc, rhsc);
446238fd1498Szrj lhsc.truncate (0);
446338fd1498Szrj rhsc.truncate (0);
446438fd1498Szrj /* For realloc the resulting pointer can be equal to the
446538fd1498Szrj argument as well. But only doing this wouldn't be
446638fd1498Szrj correct because with ptr == 0 realloc behaves like malloc. */
446738fd1498Szrj if (DECL_FUNCTION_CODE (fndecl) == BUILT_IN_REALLOC)
446838fd1498Szrj {
446938fd1498Szrj get_constraint_for (gimple_call_lhs (t), &lhsc);
447038fd1498Szrj get_constraint_for (gimple_call_arg (t, 0), &rhsc);
447138fd1498Szrj process_all_all_constraints (lhsc, rhsc);
447238fd1498Szrj }
447338fd1498Szrj return true;
447438fd1498Szrj }
447538fd1498Szrj break;
447638fd1498Szrj /* String / character search functions return a pointer into the
447738fd1498Szrj source string or NULL. */
447838fd1498Szrj case BUILT_IN_INDEX:
447938fd1498Szrj case BUILT_IN_STRCHR:
448038fd1498Szrj case BUILT_IN_STRRCHR:
448138fd1498Szrj case BUILT_IN_MEMCHR:
448238fd1498Szrj case BUILT_IN_STRSTR:
448338fd1498Szrj case BUILT_IN_STRPBRK:
448438fd1498Szrj if (gimple_call_lhs (t))
448538fd1498Szrj {
448638fd1498Szrj tree src = gimple_call_arg (t, 0);
448738fd1498Szrj get_constraint_for_ptr_offset (src, NULL_TREE, &rhsc);
448838fd1498Szrj constraint_expr nul;
448938fd1498Szrj nul.var = nothing_id;
449038fd1498Szrj nul.offset = 0;
449138fd1498Szrj nul.type = ADDRESSOF;
449238fd1498Szrj rhsc.safe_push (nul);
449338fd1498Szrj get_constraint_for (gimple_call_lhs (t), &lhsc);
449438fd1498Szrj process_all_all_constraints (lhsc, rhsc);
449538fd1498Szrj }
449638fd1498Szrj return true;
449738fd1498Szrj /* Pure functions that return something not based on any object and
449838fd1498Szrj that use the memory pointed to by their arguments (but not
449938fd1498Szrj transitively). */
450038fd1498Szrj case BUILT_IN_STRCMP:
450138fd1498Szrj case BUILT_IN_STRNCMP:
450238fd1498Szrj case BUILT_IN_STRCASECMP:
450338fd1498Szrj case BUILT_IN_STRNCASECMP:
450438fd1498Szrj case BUILT_IN_MEMCMP:
450538fd1498Szrj case BUILT_IN_BCMP:
450638fd1498Szrj case BUILT_IN_STRSPN:
450738fd1498Szrj case BUILT_IN_STRCSPN:
450838fd1498Szrj {
450938fd1498Szrj varinfo_t uses = get_call_use_vi (t);
451038fd1498Szrj make_any_offset_constraints (uses);
451138fd1498Szrj make_constraint_to (uses->id, gimple_call_arg (t, 0));
451238fd1498Szrj make_constraint_to (uses->id, gimple_call_arg (t, 1));
451338fd1498Szrj /* No constraints are necessary for the return value. */
451438fd1498Szrj return true;
451538fd1498Szrj }
451638fd1498Szrj case BUILT_IN_STRLEN:
451738fd1498Szrj {
451838fd1498Szrj varinfo_t uses = get_call_use_vi (t);
451938fd1498Szrj make_any_offset_constraints (uses);
452038fd1498Szrj make_constraint_to (uses->id, gimple_call_arg (t, 0));
452138fd1498Szrj /* No constraints are necessary for the return value. */
452238fd1498Szrj return true;
452338fd1498Szrj }
452438fd1498Szrj case BUILT_IN_OBJECT_SIZE:
452538fd1498Szrj case BUILT_IN_CONSTANT_P:
452638fd1498Szrj {
452738fd1498Szrj /* No constraints are necessary for the return value or the
452838fd1498Szrj arguments. */
452938fd1498Szrj return true;
453038fd1498Szrj }
453138fd1498Szrj /* Trampolines are special - they set up passing the static
453238fd1498Szrj frame. */
453338fd1498Szrj case BUILT_IN_INIT_TRAMPOLINE:
453438fd1498Szrj {
453538fd1498Szrj tree tramp = gimple_call_arg (t, 0);
453638fd1498Szrj tree nfunc = gimple_call_arg (t, 1);
453738fd1498Szrj tree frame = gimple_call_arg (t, 2);
453838fd1498Szrj unsigned i;
453938fd1498Szrj struct constraint_expr lhs, *rhsp;
454038fd1498Szrj if (in_ipa_mode)
454138fd1498Szrj {
454238fd1498Szrj varinfo_t nfi = NULL;
454338fd1498Szrj gcc_assert (TREE_CODE (nfunc) == ADDR_EXPR);
454438fd1498Szrj nfi = lookup_vi_for_tree (TREE_OPERAND (nfunc, 0));
454538fd1498Szrj if (nfi)
454638fd1498Szrj {
454738fd1498Szrj lhs = get_function_part_constraint (nfi, fi_static_chain);
454838fd1498Szrj get_constraint_for (frame, &rhsc);
454938fd1498Szrj FOR_EACH_VEC_ELT (rhsc, i, rhsp)
455038fd1498Szrj process_constraint (new_constraint (lhs, *rhsp));
455138fd1498Szrj rhsc.truncate (0);
455238fd1498Szrj
455338fd1498Szrj /* Make the frame point to the function for
455438fd1498Szrj the trampoline adjustment call. */
455538fd1498Szrj get_constraint_for (tramp, &lhsc);
455638fd1498Szrj do_deref (&lhsc);
455738fd1498Szrj get_constraint_for (nfunc, &rhsc);
455838fd1498Szrj process_all_all_constraints (lhsc, rhsc);
455938fd1498Szrj
456038fd1498Szrj return true;
456138fd1498Szrj }
456238fd1498Szrj }
456338fd1498Szrj /* Else fallthru to generic handling which will let
456438fd1498Szrj the frame escape. */
456538fd1498Szrj break;
456638fd1498Szrj }
456738fd1498Szrj case BUILT_IN_ADJUST_TRAMPOLINE:
456838fd1498Szrj {
456938fd1498Szrj tree tramp = gimple_call_arg (t, 0);
457038fd1498Szrj tree res = gimple_call_lhs (t);
457138fd1498Szrj if (in_ipa_mode && res)
457238fd1498Szrj {
457338fd1498Szrj get_constraint_for (res, &lhsc);
457438fd1498Szrj get_constraint_for (tramp, &rhsc);
457538fd1498Szrj do_deref (&rhsc);
457638fd1498Szrj process_all_all_constraints (lhsc, rhsc);
457738fd1498Szrj }
457838fd1498Szrj return true;
457938fd1498Szrj }
458038fd1498Szrj CASE_BUILT_IN_TM_STORE (1):
458138fd1498Szrj CASE_BUILT_IN_TM_STORE (2):
458238fd1498Szrj CASE_BUILT_IN_TM_STORE (4):
458338fd1498Szrj CASE_BUILT_IN_TM_STORE (8):
458438fd1498Szrj CASE_BUILT_IN_TM_STORE (FLOAT):
458538fd1498Szrj CASE_BUILT_IN_TM_STORE (DOUBLE):
458638fd1498Szrj CASE_BUILT_IN_TM_STORE (LDOUBLE):
458738fd1498Szrj CASE_BUILT_IN_TM_STORE (M64):
458838fd1498Szrj CASE_BUILT_IN_TM_STORE (M128):
458938fd1498Szrj CASE_BUILT_IN_TM_STORE (M256):
459038fd1498Szrj {
459138fd1498Szrj tree addr = gimple_call_arg (t, 0);
459238fd1498Szrj tree src = gimple_call_arg (t, 1);
459338fd1498Szrj
459438fd1498Szrj get_constraint_for (addr, &lhsc);
459538fd1498Szrj do_deref (&lhsc);
459638fd1498Szrj get_constraint_for (src, &rhsc);
459738fd1498Szrj process_all_all_constraints (lhsc, rhsc);
459838fd1498Szrj return true;
459938fd1498Szrj }
460038fd1498Szrj CASE_BUILT_IN_TM_LOAD (1):
460138fd1498Szrj CASE_BUILT_IN_TM_LOAD (2):
460238fd1498Szrj CASE_BUILT_IN_TM_LOAD (4):
460338fd1498Szrj CASE_BUILT_IN_TM_LOAD (8):
460438fd1498Szrj CASE_BUILT_IN_TM_LOAD (FLOAT):
460538fd1498Szrj CASE_BUILT_IN_TM_LOAD (DOUBLE):
460638fd1498Szrj CASE_BUILT_IN_TM_LOAD (LDOUBLE):
460738fd1498Szrj CASE_BUILT_IN_TM_LOAD (M64):
460838fd1498Szrj CASE_BUILT_IN_TM_LOAD (M128):
460938fd1498Szrj CASE_BUILT_IN_TM_LOAD (M256):
461038fd1498Szrj {
461138fd1498Szrj tree dest = gimple_call_lhs (t);
461238fd1498Szrj tree addr = gimple_call_arg (t, 0);
461338fd1498Szrj
461438fd1498Szrj get_constraint_for (dest, &lhsc);
461538fd1498Szrj get_constraint_for (addr, &rhsc);
461638fd1498Szrj do_deref (&rhsc);
461738fd1498Szrj process_all_all_constraints (lhsc, rhsc);
461838fd1498Szrj return true;
461938fd1498Szrj }
462038fd1498Szrj /* Variadic argument handling needs to be handled in IPA
462138fd1498Szrj mode as well. */
462238fd1498Szrj case BUILT_IN_VA_START:
462338fd1498Szrj {
462438fd1498Szrj tree valist = gimple_call_arg (t, 0);
462538fd1498Szrj struct constraint_expr rhs, *lhsp;
462638fd1498Szrj unsigned i;
462738fd1498Szrj get_constraint_for_ptr_offset (valist, NULL_TREE, &lhsc);
462838fd1498Szrj do_deref (&lhsc);
462938fd1498Szrj /* The va_list gets access to pointers in variadic
463038fd1498Szrj arguments. Which we know in the case of IPA analysis
463138fd1498Szrj and otherwise are just all nonlocal variables. */
463238fd1498Szrj if (in_ipa_mode)
463338fd1498Szrj {
463438fd1498Szrj fi = lookup_vi_for_tree (fn->decl);
463538fd1498Szrj rhs = get_function_part_constraint (fi, ~0);
463638fd1498Szrj rhs.type = ADDRESSOF;
463738fd1498Szrj }
463838fd1498Szrj else
463938fd1498Szrj {
464038fd1498Szrj rhs.var = nonlocal_id;
464138fd1498Szrj rhs.type = ADDRESSOF;
464238fd1498Szrj rhs.offset = 0;
464338fd1498Szrj }
464438fd1498Szrj FOR_EACH_VEC_ELT (lhsc, i, lhsp)
464538fd1498Szrj process_constraint (new_constraint (*lhsp, rhs));
464638fd1498Szrj /* va_list is clobbered. */
464738fd1498Szrj make_constraint_to (get_call_clobber_vi (t)->id, valist);
464838fd1498Szrj return true;
464938fd1498Szrj }
465038fd1498Szrj /* va_end doesn't have any effect that matters. */
465138fd1498Szrj case BUILT_IN_VA_END:
465238fd1498Szrj return true;
465338fd1498Szrj /* Alternate return. Simply give up for now. */
465438fd1498Szrj case BUILT_IN_RETURN:
465538fd1498Szrj {
465638fd1498Szrj fi = NULL;
465738fd1498Szrj if (!in_ipa_mode
465838fd1498Szrj || !(fi = get_vi_for_tree (fn->decl)))
465938fd1498Szrj make_constraint_from (get_varinfo (escaped_id), anything_id);
466038fd1498Szrj else if (in_ipa_mode
466138fd1498Szrj && fi != NULL)
466238fd1498Szrj {
466338fd1498Szrj struct constraint_expr lhs, rhs;
466438fd1498Szrj lhs = get_function_part_constraint (fi, fi_result);
466538fd1498Szrj rhs.var = anything_id;
466638fd1498Szrj rhs.offset = 0;
466738fd1498Szrj rhs.type = SCALAR;
466838fd1498Szrj process_constraint (new_constraint (lhs, rhs));
466938fd1498Szrj }
467038fd1498Szrj return true;
467138fd1498Szrj }
467238fd1498Szrj case BUILT_IN_GOMP_PARALLEL:
467338fd1498Szrj case BUILT_IN_GOACC_PARALLEL:
467438fd1498Szrj {
467538fd1498Szrj if (in_ipa_mode)
467638fd1498Szrj {
467738fd1498Szrj unsigned int fnpos, argpos;
467838fd1498Szrj switch (DECL_FUNCTION_CODE (fndecl))
467938fd1498Szrj {
468038fd1498Szrj case BUILT_IN_GOMP_PARALLEL:
468138fd1498Szrj /* __builtin_GOMP_parallel (fn, data, num_threads, flags). */
468238fd1498Szrj fnpos = 0;
468338fd1498Szrj argpos = 1;
468438fd1498Szrj break;
468538fd1498Szrj case BUILT_IN_GOACC_PARALLEL:
468638fd1498Szrj /* __builtin_GOACC_parallel (device, fn, mapnum, hostaddrs,
468738fd1498Szrj sizes, kinds, ...). */
468838fd1498Szrj fnpos = 1;
468938fd1498Szrj argpos = 3;
469038fd1498Szrj break;
469138fd1498Szrj default:
469238fd1498Szrj gcc_unreachable ();
469338fd1498Szrj }
469438fd1498Szrj
469538fd1498Szrj tree fnarg = gimple_call_arg (t, fnpos);
469638fd1498Szrj gcc_assert (TREE_CODE (fnarg) == ADDR_EXPR);
469738fd1498Szrj tree fndecl = TREE_OPERAND (fnarg, 0);
469838fd1498Szrj if (fndecl_maybe_in_other_partition (fndecl))
469938fd1498Szrj /* Fallthru to general call handling. */
470038fd1498Szrj break;
470138fd1498Szrj
470238fd1498Szrj tree arg = gimple_call_arg (t, argpos);
470338fd1498Szrj
470438fd1498Szrj varinfo_t fi = get_vi_for_tree (fndecl);
470538fd1498Szrj find_func_aliases_for_call_arg (fi, 0, arg);
470638fd1498Szrj return true;
470738fd1498Szrj }
470838fd1498Szrj /* Else fallthru to generic call handling. */
470938fd1498Szrj break;
471038fd1498Szrj }
471138fd1498Szrj /* printf-style functions may have hooks to set pointers to
471238fd1498Szrj point to somewhere into the generated string. Leave them
471338fd1498Szrj for a later exercise... */
471438fd1498Szrj default:
471538fd1498Szrj /* Fallthru to general call handling. */;
471638fd1498Szrj }
471738fd1498Szrj
471838fd1498Szrj return false;
471938fd1498Szrj }
472038fd1498Szrj
472138fd1498Szrj /* Create constraints for the call T. */
472238fd1498Szrj
472338fd1498Szrj static void
find_func_aliases_for_call(struct function * fn,gcall * t)472438fd1498Szrj find_func_aliases_for_call (struct function *fn, gcall *t)
472538fd1498Szrj {
472638fd1498Szrj tree fndecl = gimple_call_fndecl (t);
472738fd1498Szrj varinfo_t fi;
472838fd1498Szrj
472938fd1498Szrj if (fndecl != NULL_TREE
473038fd1498Szrj && DECL_BUILT_IN (fndecl)
473138fd1498Szrj && find_func_aliases_for_builtin_call (fn, t))
473238fd1498Szrj return;
473338fd1498Szrj
473438fd1498Szrj fi = get_fi_for_callee (t);
473538fd1498Szrj if (!in_ipa_mode
473638fd1498Szrj || (fndecl && !fi->is_fn_info))
473738fd1498Szrj {
473838fd1498Szrj auto_vec<ce_s, 16> rhsc;
473938fd1498Szrj int flags = gimple_call_flags (t);
474038fd1498Szrj
474138fd1498Szrj /* Const functions can return their arguments and addresses
474238fd1498Szrj of global memory but not of escaped memory. */
474338fd1498Szrj if (flags & (ECF_CONST|ECF_NOVOPS))
474438fd1498Szrj {
474538fd1498Szrj if (gimple_call_lhs (t))
474638fd1498Szrj handle_const_call (t, &rhsc);
474738fd1498Szrj }
474838fd1498Szrj /* Pure functions can return addresses in and of memory
474938fd1498Szrj reachable from their arguments, but they are not an escape
475038fd1498Szrj point for reachable memory of their arguments. */
475138fd1498Szrj else if (flags & (ECF_PURE|ECF_LOOPING_CONST_OR_PURE))
475238fd1498Szrj handle_pure_call (t, &rhsc);
475338fd1498Szrj else
475438fd1498Szrj handle_rhs_call (t, &rhsc);
475538fd1498Szrj if (gimple_call_lhs (t))
475638fd1498Szrj handle_lhs_call (t, gimple_call_lhs (t),
475738fd1498Szrj gimple_call_return_flags (t), rhsc, fndecl);
475838fd1498Szrj }
475938fd1498Szrj else
476038fd1498Szrj {
476138fd1498Szrj auto_vec<ce_s, 2> rhsc;
476238fd1498Szrj tree lhsop;
476338fd1498Szrj unsigned j;
476438fd1498Szrj
476538fd1498Szrj /* Assign all the passed arguments to the appropriate incoming
476638fd1498Szrj parameters of the function. */
476738fd1498Szrj for (j = 0; j < gimple_call_num_args (t); j++)
476838fd1498Szrj {
476938fd1498Szrj tree arg = gimple_call_arg (t, j);
477038fd1498Szrj find_func_aliases_for_call_arg (fi, j, arg);
477138fd1498Szrj }
477238fd1498Szrj
477338fd1498Szrj /* If we are returning a value, assign it to the result. */
477438fd1498Szrj lhsop = gimple_call_lhs (t);
477538fd1498Szrj if (lhsop)
477638fd1498Szrj {
477738fd1498Szrj auto_vec<ce_s, 2> lhsc;
477838fd1498Szrj struct constraint_expr rhs;
477938fd1498Szrj struct constraint_expr *lhsp;
478038fd1498Szrj bool aggr_p = aggregate_value_p (lhsop, gimple_call_fntype (t));
478138fd1498Szrj
478238fd1498Szrj get_constraint_for (lhsop, &lhsc);
478338fd1498Szrj rhs = get_function_part_constraint (fi, fi_result);
478438fd1498Szrj if (aggr_p)
478538fd1498Szrj {
478638fd1498Szrj auto_vec<ce_s, 2> tem;
478738fd1498Szrj tem.quick_push (rhs);
478838fd1498Szrj do_deref (&tem);
478938fd1498Szrj gcc_checking_assert (tem.length () == 1);
479038fd1498Szrj rhs = tem[0];
479138fd1498Szrj }
479238fd1498Szrj FOR_EACH_VEC_ELT (lhsc, j, lhsp)
479338fd1498Szrj process_constraint (new_constraint (*lhsp, rhs));
479438fd1498Szrj
479538fd1498Szrj /* If we pass the result decl by reference, honor that. */
479638fd1498Szrj if (aggr_p)
479738fd1498Szrj {
479838fd1498Szrj struct constraint_expr lhs;
479938fd1498Szrj struct constraint_expr *rhsp;
480038fd1498Szrj
480138fd1498Szrj get_constraint_for_address_of (lhsop, &rhsc);
480238fd1498Szrj lhs = get_function_part_constraint (fi, fi_result);
480338fd1498Szrj FOR_EACH_VEC_ELT (rhsc, j, rhsp)
480438fd1498Szrj process_constraint (new_constraint (lhs, *rhsp));
480538fd1498Szrj rhsc.truncate (0);
480638fd1498Szrj }
480738fd1498Szrj }
480838fd1498Szrj
480938fd1498Szrj /* If we use a static chain, pass it along. */
481038fd1498Szrj if (gimple_call_chain (t))
481138fd1498Szrj {
481238fd1498Szrj struct constraint_expr lhs;
481338fd1498Szrj struct constraint_expr *rhsp;
481438fd1498Szrj
481538fd1498Szrj get_constraint_for (gimple_call_chain (t), &rhsc);
481638fd1498Szrj lhs = get_function_part_constraint (fi, fi_static_chain);
481738fd1498Szrj FOR_EACH_VEC_ELT (rhsc, j, rhsp)
481838fd1498Szrj process_constraint (new_constraint (lhs, *rhsp));
481938fd1498Szrj }
482038fd1498Szrj }
482138fd1498Szrj }
482238fd1498Szrj
482338fd1498Szrj /* Walk statement T setting up aliasing constraints according to the
482438fd1498Szrj references found in T. This function is the main part of the
482538fd1498Szrj constraint builder. AI points to auxiliary alias information used
482638fd1498Szrj when building alias sets and computing alias grouping heuristics. */
482738fd1498Szrj
482838fd1498Szrj static void
find_func_aliases(struct function * fn,gimple * origt)482938fd1498Szrj find_func_aliases (struct function *fn, gimple *origt)
483038fd1498Szrj {
483138fd1498Szrj gimple *t = origt;
483238fd1498Szrj auto_vec<ce_s, 16> lhsc;
483338fd1498Szrj auto_vec<ce_s, 16> rhsc;
483438fd1498Szrj struct constraint_expr *c;
483538fd1498Szrj varinfo_t fi;
483638fd1498Szrj
483738fd1498Szrj /* Now build constraints expressions. */
483838fd1498Szrj if (gimple_code (t) == GIMPLE_PHI)
483938fd1498Szrj {
484038fd1498Szrj size_t i;
484138fd1498Szrj unsigned int j;
484238fd1498Szrj
484338fd1498Szrj /* For a phi node, assign all the arguments to
484438fd1498Szrj the result. */
484538fd1498Szrj get_constraint_for (gimple_phi_result (t), &lhsc);
484638fd1498Szrj for (i = 0; i < gimple_phi_num_args (t); i++)
484738fd1498Szrj {
484838fd1498Szrj tree strippedrhs = PHI_ARG_DEF (t, i);
484938fd1498Szrj
485038fd1498Szrj STRIP_NOPS (strippedrhs);
485138fd1498Szrj get_constraint_for_rhs (gimple_phi_arg_def (t, i), &rhsc);
485238fd1498Szrj
485338fd1498Szrj FOR_EACH_VEC_ELT (lhsc, j, c)
485438fd1498Szrj {
485538fd1498Szrj struct constraint_expr *c2;
485638fd1498Szrj while (rhsc.length () > 0)
485738fd1498Szrj {
485838fd1498Szrj c2 = &rhsc.last ();
485938fd1498Szrj process_constraint (new_constraint (*c, *c2));
486038fd1498Szrj rhsc.pop ();
486138fd1498Szrj }
486238fd1498Szrj }
486338fd1498Szrj }
486438fd1498Szrj }
486538fd1498Szrj /* In IPA mode, we need to generate constraints to pass call
486638fd1498Szrj arguments through their calls. There are two cases,
486738fd1498Szrj either a GIMPLE_CALL returning a value, or just a plain
486838fd1498Szrj GIMPLE_CALL when we are not.
486938fd1498Szrj
487038fd1498Szrj In non-ipa mode, we need to generate constraints for each
487138fd1498Szrj pointer passed by address. */
487238fd1498Szrj else if (is_gimple_call (t))
487338fd1498Szrj find_func_aliases_for_call (fn, as_a <gcall *> (t));
487438fd1498Szrj
487538fd1498Szrj /* Otherwise, just a regular assignment statement. Only care about
487638fd1498Szrj operations with pointer result, others are dealt with as escape
487738fd1498Szrj points if they have pointer operands. */
487838fd1498Szrj else if (is_gimple_assign (t))
487938fd1498Szrj {
488038fd1498Szrj /* Otherwise, just a regular assignment statement. */
488138fd1498Szrj tree lhsop = gimple_assign_lhs (t);
488238fd1498Szrj tree rhsop = (gimple_num_ops (t) == 2) ? gimple_assign_rhs1 (t) : NULL;
488338fd1498Szrj
488438fd1498Szrj if (rhsop && TREE_CLOBBER_P (rhsop))
488538fd1498Szrj /* Ignore clobbers, they don't actually store anything into
488638fd1498Szrj the LHS. */
488738fd1498Szrj ;
488838fd1498Szrj else if (rhsop && AGGREGATE_TYPE_P (TREE_TYPE (lhsop)))
488938fd1498Szrj do_structure_copy (lhsop, rhsop);
489038fd1498Szrj else
489138fd1498Szrj {
489238fd1498Szrj enum tree_code code = gimple_assign_rhs_code (t);
489338fd1498Szrj
489438fd1498Szrj get_constraint_for (lhsop, &lhsc);
489538fd1498Szrj
489638fd1498Szrj if (code == POINTER_PLUS_EXPR)
489738fd1498Szrj get_constraint_for_ptr_offset (gimple_assign_rhs1 (t),
489838fd1498Szrj gimple_assign_rhs2 (t), &rhsc);
489938fd1498Szrj else if (code == BIT_AND_EXPR
490038fd1498Szrj && TREE_CODE (gimple_assign_rhs2 (t)) == INTEGER_CST)
490138fd1498Szrj {
490238fd1498Szrj /* Aligning a pointer via a BIT_AND_EXPR is offsetting
490338fd1498Szrj the pointer. Handle it by offsetting it by UNKNOWN. */
490438fd1498Szrj get_constraint_for_ptr_offset (gimple_assign_rhs1 (t),
490538fd1498Szrj NULL_TREE, &rhsc);
490638fd1498Szrj }
490738fd1498Szrj else if ((CONVERT_EXPR_CODE_P (code)
490838fd1498Szrj && !(POINTER_TYPE_P (gimple_expr_type (t))
490938fd1498Szrj && !POINTER_TYPE_P (TREE_TYPE (rhsop))))
491038fd1498Szrj || gimple_assign_single_p (t))
491138fd1498Szrj get_constraint_for_rhs (rhsop, &rhsc);
491238fd1498Szrj else if (code == COND_EXPR)
491338fd1498Szrj {
491438fd1498Szrj /* The result is a merge of both COND_EXPR arms. */
491538fd1498Szrj auto_vec<ce_s, 2> tmp;
491638fd1498Szrj struct constraint_expr *rhsp;
491738fd1498Szrj unsigned i;
491838fd1498Szrj get_constraint_for_rhs (gimple_assign_rhs2 (t), &rhsc);
491938fd1498Szrj get_constraint_for_rhs (gimple_assign_rhs3 (t), &tmp);
492038fd1498Szrj FOR_EACH_VEC_ELT (tmp, i, rhsp)
492138fd1498Szrj rhsc.safe_push (*rhsp);
492238fd1498Szrj }
492338fd1498Szrj else if (truth_value_p (code))
492438fd1498Szrj /* Truth value results are not pointer (parts). Or at least
492538fd1498Szrj very unreasonable obfuscation of a part. */
492638fd1498Szrj ;
492738fd1498Szrj else
492838fd1498Szrj {
492938fd1498Szrj /* All other operations are merges. */
493038fd1498Szrj auto_vec<ce_s, 4> tmp;
493138fd1498Szrj struct constraint_expr *rhsp;
493238fd1498Szrj unsigned i, j;
493338fd1498Szrj get_constraint_for_rhs (gimple_assign_rhs1 (t), &rhsc);
493438fd1498Szrj for (i = 2; i < gimple_num_ops (t); ++i)
493538fd1498Szrj {
493638fd1498Szrj get_constraint_for_rhs (gimple_op (t, i), &tmp);
493738fd1498Szrj FOR_EACH_VEC_ELT (tmp, j, rhsp)
493838fd1498Szrj rhsc.safe_push (*rhsp);
493938fd1498Szrj tmp.truncate (0);
494038fd1498Szrj }
494138fd1498Szrj }
494238fd1498Szrj process_all_all_constraints (lhsc, rhsc);
494338fd1498Szrj }
494438fd1498Szrj /* If there is a store to a global variable the rhs escapes. */
494538fd1498Szrj if ((lhsop = get_base_address (lhsop)) != NULL_TREE
494638fd1498Szrj && DECL_P (lhsop))
494738fd1498Szrj {
494838fd1498Szrj varinfo_t vi = get_vi_for_tree (lhsop);
494938fd1498Szrj if ((! in_ipa_mode && vi->is_global_var)
495038fd1498Szrj || vi->is_ipa_escape_point)
495138fd1498Szrj make_escape_constraint (rhsop);
495238fd1498Szrj }
495338fd1498Szrj }
495438fd1498Szrj /* Handle escapes through return. */
495538fd1498Szrj else if (gimple_code (t) == GIMPLE_RETURN
495638fd1498Szrj && gimple_return_retval (as_a <greturn *> (t)) != NULL_TREE)
495738fd1498Szrj {
495838fd1498Szrj greturn *return_stmt = as_a <greturn *> (t);
495938fd1498Szrj fi = NULL;
496038fd1498Szrj if (!in_ipa_mode
496138fd1498Szrj || !(fi = get_vi_for_tree (fn->decl)))
496238fd1498Szrj make_escape_constraint (gimple_return_retval (return_stmt));
496338fd1498Szrj else if (in_ipa_mode)
496438fd1498Szrj {
496538fd1498Szrj struct constraint_expr lhs ;
496638fd1498Szrj struct constraint_expr *rhsp;
496738fd1498Szrj unsigned i;
496838fd1498Szrj
496938fd1498Szrj lhs = get_function_part_constraint (fi, fi_result);
497038fd1498Szrj get_constraint_for_rhs (gimple_return_retval (return_stmt), &rhsc);
497138fd1498Szrj FOR_EACH_VEC_ELT (rhsc, i, rhsp)
497238fd1498Szrj process_constraint (new_constraint (lhs, *rhsp));
497338fd1498Szrj }
497438fd1498Szrj }
497538fd1498Szrj /* Handle asms conservatively by adding escape constraints to everything. */
497638fd1498Szrj else if (gasm *asm_stmt = dyn_cast <gasm *> (t))
497738fd1498Szrj {
497838fd1498Szrj unsigned i, noutputs;
497938fd1498Szrj const char **oconstraints;
498038fd1498Szrj const char *constraint;
498138fd1498Szrj bool allows_mem, allows_reg, is_inout;
498238fd1498Szrj
498338fd1498Szrj noutputs = gimple_asm_noutputs (asm_stmt);
498438fd1498Szrj oconstraints = XALLOCAVEC (const char *, noutputs);
498538fd1498Szrj
498638fd1498Szrj for (i = 0; i < noutputs; ++i)
498738fd1498Szrj {
498838fd1498Szrj tree link = gimple_asm_output_op (asm_stmt, i);
498938fd1498Szrj tree op = TREE_VALUE (link);
499038fd1498Szrj
499138fd1498Szrj constraint = TREE_STRING_POINTER (TREE_VALUE (TREE_PURPOSE (link)));
499238fd1498Szrj oconstraints[i] = constraint;
499338fd1498Szrj parse_output_constraint (&constraint, i, 0, 0, &allows_mem,
499438fd1498Szrj &allows_reg, &is_inout);
499538fd1498Szrj
499638fd1498Szrj /* A memory constraint makes the address of the operand escape. */
499738fd1498Szrj if (!allows_reg && allows_mem)
499838fd1498Szrj make_escape_constraint (build_fold_addr_expr (op));
499938fd1498Szrj
500038fd1498Szrj /* The asm may read global memory, so outputs may point to
500138fd1498Szrj any global memory. */
500238fd1498Szrj if (op)
500338fd1498Szrj {
500438fd1498Szrj auto_vec<ce_s, 2> lhsc;
500538fd1498Szrj struct constraint_expr rhsc, *lhsp;
500638fd1498Szrj unsigned j;
500738fd1498Szrj get_constraint_for (op, &lhsc);
500838fd1498Szrj rhsc.var = nonlocal_id;
500938fd1498Szrj rhsc.offset = 0;
501038fd1498Szrj rhsc.type = SCALAR;
501138fd1498Szrj FOR_EACH_VEC_ELT (lhsc, j, lhsp)
501238fd1498Szrj process_constraint (new_constraint (*lhsp, rhsc));
501338fd1498Szrj }
501438fd1498Szrj }
501538fd1498Szrj for (i = 0; i < gimple_asm_ninputs (asm_stmt); ++i)
501638fd1498Szrj {
501738fd1498Szrj tree link = gimple_asm_input_op (asm_stmt, i);
501838fd1498Szrj tree op = TREE_VALUE (link);
501938fd1498Szrj
502038fd1498Szrj constraint = TREE_STRING_POINTER (TREE_VALUE (TREE_PURPOSE (link)));
502138fd1498Szrj
502238fd1498Szrj parse_input_constraint (&constraint, 0, 0, noutputs, 0, oconstraints,
502338fd1498Szrj &allows_mem, &allows_reg);
502438fd1498Szrj
502538fd1498Szrj /* A memory constraint makes the address of the operand escape. */
502638fd1498Szrj if (!allows_reg && allows_mem)
502738fd1498Szrj make_escape_constraint (build_fold_addr_expr (op));
502838fd1498Szrj /* Strictly we'd only need the constraint to ESCAPED if
502938fd1498Szrj the asm clobbers memory, otherwise using something
503038fd1498Szrj along the lines of per-call clobbers/uses would be enough. */
503138fd1498Szrj else if (op)
503238fd1498Szrj make_escape_constraint (op);
503338fd1498Szrj }
503438fd1498Szrj }
503538fd1498Szrj }
503638fd1498Szrj
503738fd1498Szrj
503838fd1498Szrj /* Create a constraint adding to the clobber set of FI the memory
503938fd1498Szrj pointed to by PTR. */
504038fd1498Szrj
504138fd1498Szrj static void
process_ipa_clobber(varinfo_t fi,tree ptr)504238fd1498Szrj process_ipa_clobber (varinfo_t fi, tree ptr)
504338fd1498Szrj {
504438fd1498Szrj vec<ce_s> ptrc = vNULL;
504538fd1498Szrj struct constraint_expr *c, lhs;
504638fd1498Szrj unsigned i;
504738fd1498Szrj get_constraint_for_rhs (ptr, &ptrc);
504838fd1498Szrj lhs = get_function_part_constraint (fi, fi_clobbers);
504938fd1498Szrj FOR_EACH_VEC_ELT (ptrc, i, c)
505038fd1498Szrj process_constraint (new_constraint (lhs, *c));
505138fd1498Szrj ptrc.release ();
505238fd1498Szrj }
505338fd1498Szrj
505438fd1498Szrj /* Walk statement T setting up clobber and use constraints according to the
505538fd1498Szrj references found in T. This function is a main part of the
505638fd1498Szrj IPA constraint builder. */
505738fd1498Szrj
505838fd1498Szrj static void
find_func_clobbers(struct function * fn,gimple * origt)505938fd1498Szrj find_func_clobbers (struct function *fn, gimple *origt)
506038fd1498Szrj {
506138fd1498Szrj gimple *t = origt;
506238fd1498Szrj auto_vec<ce_s, 16> lhsc;
506338fd1498Szrj auto_vec<ce_s, 16> rhsc;
506438fd1498Szrj varinfo_t fi;
506538fd1498Szrj
506638fd1498Szrj /* Add constraints for clobbered/used in IPA mode.
506738fd1498Szrj We are not interested in what automatic variables are clobbered
506838fd1498Szrj or used as we only use the information in the caller to which
506938fd1498Szrj they do not escape. */
507038fd1498Szrj gcc_assert (in_ipa_mode);
507138fd1498Szrj
507238fd1498Szrj /* If the stmt refers to memory in any way it better had a VUSE. */
507338fd1498Szrj if (gimple_vuse (t) == NULL_TREE)
507438fd1498Szrj return;
507538fd1498Szrj
507638fd1498Szrj /* We'd better have function information for the current function. */
507738fd1498Szrj fi = lookup_vi_for_tree (fn->decl);
507838fd1498Szrj gcc_assert (fi != NULL);
507938fd1498Szrj
508038fd1498Szrj /* Account for stores in assignments and calls. */
508138fd1498Szrj if (gimple_vdef (t) != NULL_TREE
508238fd1498Szrj && gimple_has_lhs (t))
508338fd1498Szrj {
508438fd1498Szrj tree lhs = gimple_get_lhs (t);
508538fd1498Szrj tree tem = lhs;
508638fd1498Szrj while (handled_component_p (tem))
508738fd1498Szrj tem = TREE_OPERAND (tem, 0);
508838fd1498Szrj if ((DECL_P (tem)
508938fd1498Szrj && !auto_var_in_fn_p (tem, fn->decl))
509038fd1498Szrj || INDIRECT_REF_P (tem)
509138fd1498Szrj || (TREE_CODE (tem) == MEM_REF
509238fd1498Szrj && !(TREE_CODE (TREE_OPERAND (tem, 0)) == ADDR_EXPR
509338fd1498Szrj && auto_var_in_fn_p
509438fd1498Szrj (TREE_OPERAND (TREE_OPERAND (tem, 0), 0), fn->decl))))
509538fd1498Szrj {
509638fd1498Szrj struct constraint_expr lhsc, *rhsp;
509738fd1498Szrj unsigned i;
509838fd1498Szrj lhsc = get_function_part_constraint (fi, fi_clobbers);
509938fd1498Szrj get_constraint_for_address_of (lhs, &rhsc);
510038fd1498Szrj FOR_EACH_VEC_ELT (rhsc, i, rhsp)
510138fd1498Szrj process_constraint (new_constraint (lhsc, *rhsp));
510238fd1498Szrj rhsc.truncate (0);
510338fd1498Szrj }
510438fd1498Szrj }
510538fd1498Szrj
510638fd1498Szrj /* Account for uses in assigments and returns. */
510738fd1498Szrj if (gimple_assign_single_p (t)
510838fd1498Szrj || (gimple_code (t) == GIMPLE_RETURN
510938fd1498Szrj && gimple_return_retval (as_a <greturn *> (t)) != NULL_TREE))
511038fd1498Szrj {
511138fd1498Szrj tree rhs = (gimple_assign_single_p (t)
511238fd1498Szrj ? gimple_assign_rhs1 (t)
511338fd1498Szrj : gimple_return_retval (as_a <greturn *> (t)));
511438fd1498Szrj tree tem = rhs;
511538fd1498Szrj while (handled_component_p (tem))
511638fd1498Szrj tem = TREE_OPERAND (tem, 0);
511738fd1498Szrj if ((DECL_P (tem)
511838fd1498Szrj && !auto_var_in_fn_p (tem, fn->decl))
511938fd1498Szrj || INDIRECT_REF_P (tem)
512038fd1498Szrj || (TREE_CODE (tem) == MEM_REF
512138fd1498Szrj && !(TREE_CODE (TREE_OPERAND (tem, 0)) == ADDR_EXPR
512238fd1498Szrj && auto_var_in_fn_p
512338fd1498Szrj (TREE_OPERAND (TREE_OPERAND (tem, 0), 0), fn->decl))))
512438fd1498Szrj {
512538fd1498Szrj struct constraint_expr lhs, *rhsp;
512638fd1498Szrj unsigned i;
512738fd1498Szrj lhs = get_function_part_constraint (fi, fi_uses);
512838fd1498Szrj get_constraint_for_address_of (rhs, &rhsc);
512938fd1498Szrj FOR_EACH_VEC_ELT (rhsc, i, rhsp)
513038fd1498Szrj process_constraint (new_constraint (lhs, *rhsp));
513138fd1498Szrj rhsc.truncate (0);
513238fd1498Szrj }
513338fd1498Szrj }
513438fd1498Szrj
513538fd1498Szrj if (gcall *call_stmt = dyn_cast <gcall *> (t))
513638fd1498Szrj {
513738fd1498Szrj varinfo_t cfi = NULL;
513838fd1498Szrj tree decl = gimple_call_fndecl (t);
513938fd1498Szrj struct constraint_expr lhs, rhs;
514038fd1498Szrj unsigned i, j;
514138fd1498Szrj
514238fd1498Szrj /* For builtins we do not have separate function info. For those
514338fd1498Szrj we do not generate escapes for we have to generate clobbers/uses. */
514438fd1498Szrj if (gimple_call_builtin_p (t, BUILT_IN_NORMAL))
514538fd1498Szrj switch (DECL_FUNCTION_CODE (decl))
514638fd1498Szrj {
514738fd1498Szrj /* The following functions use and clobber memory pointed to
514838fd1498Szrj by their arguments. */
514938fd1498Szrj case BUILT_IN_STRCPY:
515038fd1498Szrj case BUILT_IN_STRNCPY:
515138fd1498Szrj case BUILT_IN_BCOPY:
515238fd1498Szrj case BUILT_IN_MEMCPY:
515338fd1498Szrj case BUILT_IN_MEMMOVE:
515438fd1498Szrj case BUILT_IN_MEMPCPY:
515538fd1498Szrj case BUILT_IN_STPCPY:
515638fd1498Szrj case BUILT_IN_STPNCPY:
515738fd1498Szrj case BUILT_IN_STRCAT:
515838fd1498Szrj case BUILT_IN_STRNCAT:
515938fd1498Szrj case BUILT_IN_STRCPY_CHK:
516038fd1498Szrj case BUILT_IN_STRNCPY_CHK:
516138fd1498Szrj case BUILT_IN_MEMCPY_CHK:
516238fd1498Szrj case BUILT_IN_MEMMOVE_CHK:
516338fd1498Szrj case BUILT_IN_MEMPCPY_CHK:
516438fd1498Szrj case BUILT_IN_STPCPY_CHK:
516538fd1498Szrj case BUILT_IN_STPNCPY_CHK:
516638fd1498Szrj case BUILT_IN_STRCAT_CHK:
516738fd1498Szrj case BUILT_IN_STRNCAT_CHK:
516838fd1498Szrj {
516938fd1498Szrj tree dest = gimple_call_arg (t, (DECL_FUNCTION_CODE (decl)
517038fd1498Szrj == BUILT_IN_BCOPY ? 1 : 0));
517138fd1498Szrj tree src = gimple_call_arg (t, (DECL_FUNCTION_CODE (decl)
517238fd1498Szrj == BUILT_IN_BCOPY ? 0 : 1));
517338fd1498Szrj unsigned i;
517438fd1498Szrj struct constraint_expr *rhsp, *lhsp;
517538fd1498Szrj get_constraint_for_ptr_offset (dest, NULL_TREE, &lhsc);
517638fd1498Szrj lhs = get_function_part_constraint (fi, fi_clobbers);
517738fd1498Szrj FOR_EACH_VEC_ELT (lhsc, i, lhsp)
517838fd1498Szrj process_constraint (new_constraint (lhs, *lhsp));
517938fd1498Szrj get_constraint_for_ptr_offset (src, NULL_TREE, &rhsc);
518038fd1498Szrj lhs = get_function_part_constraint (fi, fi_uses);
518138fd1498Szrj FOR_EACH_VEC_ELT (rhsc, i, rhsp)
518238fd1498Szrj process_constraint (new_constraint (lhs, *rhsp));
518338fd1498Szrj return;
518438fd1498Szrj }
518538fd1498Szrj /* The following function clobbers memory pointed to by
518638fd1498Szrj its argument. */
518738fd1498Szrj case BUILT_IN_MEMSET:
518838fd1498Szrj case BUILT_IN_MEMSET_CHK:
518938fd1498Szrj case BUILT_IN_POSIX_MEMALIGN:
519038fd1498Szrj {
519138fd1498Szrj tree dest = gimple_call_arg (t, 0);
519238fd1498Szrj unsigned i;
519338fd1498Szrj ce_s *lhsp;
519438fd1498Szrj get_constraint_for_ptr_offset (dest, NULL_TREE, &lhsc);
519538fd1498Szrj lhs = get_function_part_constraint (fi, fi_clobbers);
519638fd1498Szrj FOR_EACH_VEC_ELT (lhsc, i, lhsp)
519738fd1498Szrj process_constraint (new_constraint (lhs, *lhsp));
519838fd1498Szrj return;
519938fd1498Szrj }
520038fd1498Szrj /* The following functions clobber their second and third
520138fd1498Szrj arguments. */
520238fd1498Szrj case BUILT_IN_SINCOS:
520338fd1498Szrj case BUILT_IN_SINCOSF:
520438fd1498Szrj case BUILT_IN_SINCOSL:
520538fd1498Szrj {
520638fd1498Szrj process_ipa_clobber (fi, gimple_call_arg (t, 1));
520738fd1498Szrj process_ipa_clobber (fi, gimple_call_arg (t, 2));
520838fd1498Szrj return;
520938fd1498Szrj }
521038fd1498Szrj /* The following functions clobber their second argument. */
521138fd1498Szrj case BUILT_IN_FREXP:
521238fd1498Szrj case BUILT_IN_FREXPF:
521338fd1498Szrj case BUILT_IN_FREXPL:
521438fd1498Szrj case BUILT_IN_LGAMMA_R:
521538fd1498Szrj case BUILT_IN_LGAMMAF_R:
521638fd1498Szrj case BUILT_IN_LGAMMAL_R:
521738fd1498Szrj case BUILT_IN_GAMMA_R:
521838fd1498Szrj case BUILT_IN_GAMMAF_R:
521938fd1498Szrj case BUILT_IN_GAMMAL_R:
522038fd1498Szrj case BUILT_IN_MODF:
522138fd1498Szrj case BUILT_IN_MODFF:
522238fd1498Szrj case BUILT_IN_MODFL:
522338fd1498Szrj {
522438fd1498Szrj process_ipa_clobber (fi, gimple_call_arg (t, 1));
522538fd1498Szrj return;
522638fd1498Szrj }
522738fd1498Szrj /* The following functions clobber their third argument. */
522838fd1498Szrj case BUILT_IN_REMQUO:
522938fd1498Szrj case BUILT_IN_REMQUOF:
523038fd1498Szrj case BUILT_IN_REMQUOL:
523138fd1498Szrj {
523238fd1498Szrj process_ipa_clobber (fi, gimple_call_arg (t, 2));
523338fd1498Szrj return;
523438fd1498Szrj }
523538fd1498Szrj /* The following functions neither read nor clobber memory. */
523638fd1498Szrj case BUILT_IN_ASSUME_ALIGNED:
523738fd1498Szrj case BUILT_IN_FREE:
523838fd1498Szrj return;
523938fd1498Szrj /* Trampolines are of no interest to us. */
524038fd1498Szrj case BUILT_IN_INIT_TRAMPOLINE:
524138fd1498Szrj case BUILT_IN_ADJUST_TRAMPOLINE:
524238fd1498Szrj return;
524338fd1498Szrj case BUILT_IN_VA_START:
524438fd1498Szrj case BUILT_IN_VA_END:
524538fd1498Szrj return;
524638fd1498Szrj case BUILT_IN_GOMP_PARALLEL:
524738fd1498Szrj case BUILT_IN_GOACC_PARALLEL:
524838fd1498Szrj {
524938fd1498Szrj unsigned int fnpos, argpos;
525038fd1498Szrj unsigned int implicit_use_args[2];
525138fd1498Szrj unsigned int num_implicit_use_args = 0;
525238fd1498Szrj switch (DECL_FUNCTION_CODE (decl))
525338fd1498Szrj {
525438fd1498Szrj case BUILT_IN_GOMP_PARALLEL:
525538fd1498Szrj /* __builtin_GOMP_parallel (fn, data, num_threads, flags). */
525638fd1498Szrj fnpos = 0;
525738fd1498Szrj argpos = 1;
525838fd1498Szrj break;
525938fd1498Szrj case BUILT_IN_GOACC_PARALLEL:
526038fd1498Szrj /* __builtin_GOACC_parallel (device, fn, mapnum, hostaddrs,
526138fd1498Szrj sizes, kinds, ...). */
526238fd1498Szrj fnpos = 1;
526338fd1498Szrj argpos = 3;
526438fd1498Szrj implicit_use_args[num_implicit_use_args++] = 4;
526538fd1498Szrj implicit_use_args[num_implicit_use_args++] = 5;
526638fd1498Szrj break;
526738fd1498Szrj default:
526838fd1498Szrj gcc_unreachable ();
526938fd1498Szrj }
527038fd1498Szrj
527138fd1498Szrj tree fnarg = gimple_call_arg (t, fnpos);
527238fd1498Szrj gcc_assert (TREE_CODE (fnarg) == ADDR_EXPR);
527338fd1498Szrj tree fndecl = TREE_OPERAND (fnarg, 0);
527438fd1498Szrj if (fndecl_maybe_in_other_partition (fndecl))
527538fd1498Szrj /* Fallthru to general call handling. */
527638fd1498Szrj break;
527738fd1498Szrj
527838fd1498Szrj varinfo_t cfi = get_vi_for_tree (fndecl);
527938fd1498Szrj
528038fd1498Szrj tree arg = gimple_call_arg (t, argpos);
528138fd1498Szrj
528238fd1498Szrj /* Parameter passed by value is used. */
528338fd1498Szrj lhs = get_function_part_constraint (fi, fi_uses);
528438fd1498Szrj struct constraint_expr *rhsp;
528538fd1498Szrj get_constraint_for (arg, &rhsc);
528638fd1498Szrj FOR_EACH_VEC_ELT (rhsc, j, rhsp)
528738fd1498Szrj process_constraint (new_constraint (lhs, *rhsp));
528838fd1498Szrj rhsc.truncate (0);
528938fd1498Szrj
529038fd1498Szrj /* Handle parameters used by the call, but not used in cfi, as
529138fd1498Szrj implicitly used by cfi. */
529238fd1498Szrj lhs = get_function_part_constraint (cfi, fi_uses);
529338fd1498Szrj for (unsigned i = 0; i < num_implicit_use_args; ++i)
529438fd1498Szrj {
529538fd1498Szrj tree arg = gimple_call_arg (t, implicit_use_args[i]);
529638fd1498Szrj get_constraint_for (arg, &rhsc);
529738fd1498Szrj FOR_EACH_VEC_ELT (rhsc, j, rhsp)
529838fd1498Szrj process_constraint (new_constraint (lhs, *rhsp));
529938fd1498Szrj rhsc.truncate (0);
530038fd1498Szrj }
530138fd1498Szrj
530238fd1498Szrj /* The caller clobbers what the callee does. */
530338fd1498Szrj lhs = get_function_part_constraint (fi, fi_clobbers);
530438fd1498Szrj rhs = get_function_part_constraint (cfi, fi_clobbers);
530538fd1498Szrj process_constraint (new_constraint (lhs, rhs));
530638fd1498Szrj
530738fd1498Szrj /* The caller uses what the callee does. */
530838fd1498Szrj lhs = get_function_part_constraint (fi, fi_uses);
530938fd1498Szrj rhs = get_function_part_constraint (cfi, fi_uses);
531038fd1498Szrj process_constraint (new_constraint (lhs, rhs));
531138fd1498Szrj
531238fd1498Szrj return;
531338fd1498Szrj }
531438fd1498Szrj /* printf-style functions may have hooks to set pointers to
531538fd1498Szrj point to somewhere into the generated string. Leave them
531638fd1498Szrj for a later exercise... */
531738fd1498Szrj default:
531838fd1498Szrj /* Fallthru to general call handling. */;
531938fd1498Szrj }
532038fd1498Szrj
532138fd1498Szrj /* Parameters passed by value are used. */
532238fd1498Szrj lhs = get_function_part_constraint (fi, fi_uses);
532338fd1498Szrj for (i = 0; i < gimple_call_num_args (t); i++)
532438fd1498Szrj {
532538fd1498Szrj struct constraint_expr *rhsp;
532638fd1498Szrj tree arg = gimple_call_arg (t, i);
532738fd1498Szrj
532838fd1498Szrj if (TREE_CODE (arg) == SSA_NAME
532938fd1498Szrj || is_gimple_min_invariant (arg))
533038fd1498Szrj continue;
533138fd1498Szrj
533238fd1498Szrj get_constraint_for_address_of (arg, &rhsc);
533338fd1498Szrj FOR_EACH_VEC_ELT (rhsc, j, rhsp)
533438fd1498Szrj process_constraint (new_constraint (lhs, *rhsp));
533538fd1498Szrj rhsc.truncate (0);
533638fd1498Szrj }
533738fd1498Szrj
533838fd1498Szrj /* Build constraints for propagating clobbers/uses along the
533938fd1498Szrj callgraph edges. */
534038fd1498Szrj cfi = get_fi_for_callee (call_stmt);
534138fd1498Szrj if (cfi->id == anything_id)
534238fd1498Szrj {
534338fd1498Szrj if (gimple_vdef (t))
534438fd1498Szrj make_constraint_from (first_vi_for_offset (fi, fi_clobbers),
534538fd1498Szrj anything_id);
534638fd1498Szrj make_constraint_from (first_vi_for_offset (fi, fi_uses),
534738fd1498Szrj anything_id);
534838fd1498Szrj return;
534938fd1498Szrj }
535038fd1498Szrj
535138fd1498Szrj /* For callees without function info (that's external functions),
535238fd1498Szrj ESCAPED is clobbered and used. */
535338fd1498Szrj if (gimple_call_fndecl (t)
535438fd1498Szrj && !cfi->is_fn_info)
535538fd1498Szrj {
535638fd1498Szrj varinfo_t vi;
535738fd1498Szrj
535838fd1498Szrj if (gimple_vdef (t))
535938fd1498Szrj make_copy_constraint (first_vi_for_offset (fi, fi_clobbers),
536038fd1498Szrj escaped_id);
536138fd1498Szrj make_copy_constraint (first_vi_for_offset (fi, fi_uses), escaped_id);
536238fd1498Szrj
536338fd1498Szrj /* Also honor the call statement use/clobber info. */
536438fd1498Szrj if ((vi = lookup_call_clobber_vi (call_stmt)) != NULL)
536538fd1498Szrj make_copy_constraint (first_vi_for_offset (fi, fi_clobbers),
536638fd1498Szrj vi->id);
536738fd1498Szrj if ((vi = lookup_call_use_vi (call_stmt)) != NULL)
536838fd1498Szrj make_copy_constraint (first_vi_for_offset (fi, fi_uses),
536938fd1498Szrj vi->id);
537038fd1498Szrj return;
537138fd1498Szrj }
537238fd1498Szrj
537338fd1498Szrj /* Otherwise the caller clobbers and uses what the callee does.
537438fd1498Szrj ??? This should use a new complex constraint that filters
537538fd1498Szrj local variables of the callee. */
537638fd1498Szrj if (gimple_vdef (t))
537738fd1498Szrj {
537838fd1498Szrj lhs = get_function_part_constraint (fi, fi_clobbers);
537938fd1498Szrj rhs = get_function_part_constraint (cfi, fi_clobbers);
538038fd1498Szrj process_constraint (new_constraint (lhs, rhs));
538138fd1498Szrj }
538238fd1498Szrj lhs = get_function_part_constraint (fi, fi_uses);
538338fd1498Szrj rhs = get_function_part_constraint (cfi, fi_uses);
538438fd1498Szrj process_constraint (new_constraint (lhs, rhs));
538538fd1498Szrj }
538638fd1498Szrj else if (gimple_code (t) == GIMPLE_ASM)
538738fd1498Szrj {
538838fd1498Szrj /* ??? Ick. We can do better. */
538938fd1498Szrj if (gimple_vdef (t))
539038fd1498Szrj make_constraint_from (first_vi_for_offset (fi, fi_clobbers),
539138fd1498Szrj anything_id);
539238fd1498Szrj make_constraint_from (first_vi_for_offset (fi, fi_uses),
539338fd1498Szrj anything_id);
539438fd1498Szrj }
539538fd1498Szrj }
539638fd1498Szrj
539738fd1498Szrj
539838fd1498Szrj /* Find the first varinfo in the same variable as START that overlaps with
539938fd1498Szrj OFFSET. Return NULL if we can't find one. */
540038fd1498Szrj
540138fd1498Szrj static varinfo_t
first_vi_for_offset(varinfo_t start,unsigned HOST_WIDE_INT offset)540238fd1498Szrj first_vi_for_offset (varinfo_t start, unsigned HOST_WIDE_INT offset)
540338fd1498Szrj {
540438fd1498Szrj /* If the offset is outside of the variable, bail out. */
540538fd1498Szrj if (offset >= start->fullsize)
540638fd1498Szrj return NULL;
540738fd1498Szrj
540838fd1498Szrj /* If we cannot reach offset from start, lookup the first field
540938fd1498Szrj and start from there. */
541038fd1498Szrj if (start->offset > offset)
541138fd1498Szrj start = get_varinfo (start->head);
541238fd1498Szrj
541338fd1498Szrj while (start)
541438fd1498Szrj {
541538fd1498Szrj /* We may not find a variable in the field list with the actual
541638fd1498Szrj offset when we have glommed a structure to a variable.
541738fd1498Szrj In that case, however, offset should still be within the size
541838fd1498Szrj of the variable. */
541938fd1498Szrj if (offset >= start->offset
542038fd1498Szrj && (offset - start->offset) < start->size)
542138fd1498Szrj return start;
542238fd1498Szrj
542338fd1498Szrj start = vi_next (start);
542438fd1498Szrj }
542538fd1498Szrj
542638fd1498Szrj return NULL;
542738fd1498Szrj }
542838fd1498Szrj
542938fd1498Szrj /* Find the first varinfo in the same variable as START that overlaps with
543038fd1498Szrj OFFSET. If there is no such varinfo the varinfo directly preceding
543138fd1498Szrj OFFSET is returned. */
543238fd1498Szrj
543338fd1498Szrj static varinfo_t
first_or_preceding_vi_for_offset(varinfo_t start,unsigned HOST_WIDE_INT offset)543438fd1498Szrj first_or_preceding_vi_for_offset (varinfo_t start,
543538fd1498Szrj unsigned HOST_WIDE_INT offset)
543638fd1498Szrj {
543738fd1498Szrj /* If we cannot reach offset from start, lookup the first field
543838fd1498Szrj and start from there. */
543938fd1498Szrj if (start->offset > offset)
544038fd1498Szrj start = get_varinfo (start->head);
544138fd1498Szrj
544238fd1498Szrj /* We may not find a variable in the field list with the actual
544338fd1498Szrj offset when we have glommed a structure to a variable.
544438fd1498Szrj In that case, however, offset should still be within the size
544538fd1498Szrj of the variable.
544638fd1498Szrj If we got beyond the offset we look for return the field
544738fd1498Szrj directly preceding offset which may be the last field. */
544838fd1498Szrj while (start->next
544938fd1498Szrj && offset >= start->offset
545038fd1498Szrj && !((offset - start->offset) < start->size))
545138fd1498Szrj start = vi_next (start);
545238fd1498Szrj
545338fd1498Szrj return start;
545438fd1498Szrj }
545538fd1498Szrj
545638fd1498Szrj
545738fd1498Szrj /* This structure is used during pushing fields onto the fieldstack
545838fd1498Szrj to track the offset of the field, since bitpos_of_field gives it
545938fd1498Szrj relative to its immediate containing type, and we want it relative
546038fd1498Szrj to the ultimate containing object. */
546138fd1498Szrj
546238fd1498Szrj struct fieldoff
546338fd1498Szrj {
546438fd1498Szrj /* Offset from the base of the base containing object to this field. */
546538fd1498Szrj HOST_WIDE_INT offset;
546638fd1498Szrj
546738fd1498Szrj /* Size, in bits, of the field. */
546838fd1498Szrj unsigned HOST_WIDE_INT size;
546938fd1498Szrj
547038fd1498Szrj unsigned has_unknown_size : 1;
547138fd1498Szrj
547238fd1498Szrj unsigned must_have_pointers : 1;
547338fd1498Szrj
547438fd1498Szrj unsigned may_have_pointers : 1;
547538fd1498Szrj
547638fd1498Szrj unsigned only_restrict_pointers : 1;
547738fd1498Szrj
547838fd1498Szrj tree restrict_pointed_type;
547938fd1498Szrj };
548038fd1498Szrj typedef struct fieldoff fieldoff_s;
548138fd1498Szrj
548238fd1498Szrj
548338fd1498Szrj /* qsort comparison function for two fieldoff's PA and PB */
548438fd1498Szrj
548538fd1498Szrj static int
fieldoff_compare(const void * pa,const void * pb)548638fd1498Szrj fieldoff_compare (const void *pa, const void *pb)
548738fd1498Szrj {
548838fd1498Szrj const fieldoff_s *foa = (const fieldoff_s *)pa;
548938fd1498Szrj const fieldoff_s *fob = (const fieldoff_s *)pb;
549038fd1498Szrj unsigned HOST_WIDE_INT foasize, fobsize;
549138fd1498Szrj
549238fd1498Szrj if (foa->offset < fob->offset)
549338fd1498Szrj return -1;
549438fd1498Szrj else if (foa->offset > fob->offset)
549538fd1498Szrj return 1;
549638fd1498Szrj
549738fd1498Szrj foasize = foa->size;
549838fd1498Szrj fobsize = fob->size;
549938fd1498Szrj if (foasize < fobsize)
550038fd1498Szrj return -1;
550138fd1498Szrj else if (foasize > fobsize)
550238fd1498Szrj return 1;
550338fd1498Szrj return 0;
550438fd1498Szrj }
550538fd1498Szrj
550638fd1498Szrj /* Sort a fieldstack according to the field offset and sizes. */
550738fd1498Szrj static void
sort_fieldstack(vec<fieldoff_s> fieldstack)550838fd1498Szrj sort_fieldstack (vec<fieldoff_s> fieldstack)
550938fd1498Szrj {
551038fd1498Szrj fieldstack.qsort (fieldoff_compare);
551138fd1498Szrj }
551238fd1498Szrj
551338fd1498Szrj /* Return true if T is a type that can have subvars. */
551438fd1498Szrj
551538fd1498Szrj static inline bool
type_can_have_subvars(const_tree t)551638fd1498Szrj type_can_have_subvars (const_tree t)
551738fd1498Szrj {
551838fd1498Szrj /* Aggregates without overlapping fields can have subvars. */
551938fd1498Szrj return TREE_CODE (t) == RECORD_TYPE;
552038fd1498Szrj }
552138fd1498Szrj
552238fd1498Szrj /* Return true if V is a tree that we can have subvars for.
552338fd1498Szrj Normally, this is any aggregate type. Also complex
552438fd1498Szrj types which are not gimple registers can have subvars. */
552538fd1498Szrj
552638fd1498Szrj static inline bool
var_can_have_subvars(const_tree v)552738fd1498Szrj var_can_have_subvars (const_tree v)
552838fd1498Szrj {
552938fd1498Szrj /* Volatile variables should never have subvars. */
553038fd1498Szrj if (TREE_THIS_VOLATILE (v))
553138fd1498Szrj return false;
553238fd1498Szrj
553338fd1498Szrj /* Non decls or memory tags can never have subvars. */
553438fd1498Szrj if (!DECL_P (v))
553538fd1498Szrj return false;
553638fd1498Szrj
553738fd1498Szrj return type_can_have_subvars (TREE_TYPE (v));
553838fd1498Szrj }
553938fd1498Szrj
554038fd1498Szrj /* Return true if T is a type that does contain pointers. */
554138fd1498Szrj
554238fd1498Szrj static bool
type_must_have_pointers(tree type)554338fd1498Szrj type_must_have_pointers (tree type)
554438fd1498Szrj {
554538fd1498Szrj if (POINTER_TYPE_P (type))
554638fd1498Szrj return true;
554738fd1498Szrj
554838fd1498Szrj if (TREE_CODE (type) == ARRAY_TYPE)
554938fd1498Szrj return type_must_have_pointers (TREE_TYPE (type));
555038fd1498Szrj
555138fd1498Szrj /* A function or method can have pointers as arguments, so track
555238fd1498Szrj those separately. */
555338fd1498Szrj if (TREE_CODE (type) == FUNCTION_TYPE
555438fd1498Szrj || TREE_CODE (type) == METHOD_TYPE)
555538fd1498Szrj return true;
555638fd1498Szrj
555738fd1498Szrj return false;
555838fd1498Szrj }
555938fd1498Szrj
556038fd1498Szrj static bool
field_must_have_pointers(tree t)556138fd1498Szrj field_must_have_pointers (tree t)
556238fd1498Szrj {
556338fd1498Szrj return type_must_have_pointers (TREE_TYPE (t));
556438fd1498Szrj }
556538fd1498Szrj
556638fd1498Szrj /* Given a TYPE, and a vector of field offsets FIELDSTACK, push all
556738fd1498Szrj the fields of TYPE onto fieldstack, recording their offsets along
556838fd1498Szrj the way.
556938fd1498Szrj
557038fd1498Szrj OFFSET is used to keep track of the offset in this entire
557138fd1498Szrj structure, rather than just the immediately containing structure.
557238fd1498Szrj Returns false if the caller is supposed to handle the field we
557338fd1498Szrj recursed for. */
557438fd1498Szrj
557538fd1498Szrj static bool
push_fields_onto_fieldstack(tree type,vec<fieldoff_s> * fieldstack,HOST_WIDE_INT offset)557638fd1498Szrj push_fields_onto_fieldstack (tree type, vec<fieldoff_s> *fieldstack,
557738fd1498Szrj HOST_WIDE_INT offset)
557838fd1498Szrj {
557938fd1498Szrj tree field;
558038fd1498Szrj bool empty_p = true;
558138fd1498Szrj
558238fd1498Szrj if (TREE_CODE (type) != RECORD_TYPE)
558338fd1498Szrj return false;
558438fd1498Szrj
558538fd1498Szrj /* If the vector of fields is growing too big, bail out early.
558638fd1498Szrj Callers check for vec::length <= MAX_FIELDS_FOR_FIELD_SENSITIVE, make
558738fd1498Szrj sure this fails. */
558838fd1498Szrj if (fieldstack->length () > MAX_FIELDS_FOR_FIELD_SENSITIVE)
558938fd1498Szrj return false;
559038fd1498Szrj
559138fd1498Szrj for (field = TYPE_FIELDS (type); field; field = DECL_CHAIN (field))
559238fd1498Szrj if (TREE_CODE (field) == FIELD_DECL)
559338fd1498Szrj {
559438fd1498Szrj bool push = false;
559538fd1498Szrj HOST_WIDE_INT foff = bitpos_of_field (field);
559638fd1498Szrj tree field_type = TREE_TYPE (field);
559738fd1498Szrj
559838fd1498Szrj if (!var_can_have_subvars (field)
559938fd1498Szrj || TREE_CODE (field_type) == QUAL_UNION_TYPE
560038fd1498Szrj || TREE_CODE (field_type) == UNION_TYPE)
560138fd1498Szrj push = true;
560238fd1498Szrj else if (!push_fields_onto_fieldstack
560338fd1498Szrj (field_type, fieldstack, offset + foff)
560438fd1498Szrj && (DECL_SIZE (field)
560538fd1498Szrj && !integer_zerop (DECL_SIZE (field))))
560638fd1498Szrj /* Empty structures may have actual size, like in C++. So
560738fd1498Szrj see if we didn't push any subfields and the size is
560838fd1498Szrj nonzero, push the field onto the stack. */
560938fd1498Szrj push = true;
561038fd1498Szrj
561138fd1498Szrj if (push)
561238fd1498Szrj {
561338fd1498Szrj fieldoff_s *pair = NULL;
561438fd1498Szrj bool has_unknown_size = false;
561538fd1498Szrj bool must_have_pointers_p;
561638fd1498Szrj
561738fd1498Szrj if (!fieldstack->is_empty ())
561838fd1498Szrj pair = &fieldstack->last ();
561938fd1498Szrj
562038fd1498Szrj /* If there isn't anything at offset zero, create sth. */
562138fd1498Szrj if (!pair
562238fd1498Szrj && offset + foff != 0)
562338fd1498Szrj {
562438fd1498Szrj fieldoff_s e
562538fd1498Szrj = {0, offset + foff, false, false, true, false, NULL_TREE};
562638fd1498Szrj pair = fieldstack->safe_push (e);
562738fd1498Szrj }
562838fd1498Szrj
562938fd1498Szrj if (!DECL_SIZE (field)
563038fd1498Szrj || !tree_fits_uhwi_p (DECL_SIZE (field)))
563138fd1498Szrj has_unknown_size = true;
563238fd1498Szrj
563338fd1498Szrj /* If adjacent fields do not contain pointers merge them. */
563438fd1498Szrj must_have_pointers_p = field_must_have_pointers (field);
563538fd1498Szrj if (pair
563638fd1498Szrj && !has_unknown_size
563738fd1498Szrj && !must_have_pointers_p
563838fd1498Szrj && !pair->must_have_pointers
563938fd1498Szrj && !pair->has_unknown_size
564038fd1498Szrj && pair->offset + (HOST_WIDE_INT)pair->size == offset + foff)
564138fd1498Szrj {
564238fd1498Szrj pair->size += tree_to_uhwi (DECL_SIZE (field));
564338fd1498Szrj }
564438fd1498Szrj else
564538fd1498Szrj {
564638fd1498Szrj fieldoff_s e;
564738fd1498Szrj e.offset = offset + foff;
564838fd1498Szrj e.has_unknown_size = has_unknown_size;
564938fd1498Szrj if (!has_unknown_size)
565038fd1498Szrj e.size = tree_to_uhwi (DECL_SIZE (field));
565138fd1498Szrj else
565238fd1498Szrj e.size = -1;
565338fd1498Szrj e.must_have_pointers = must_have_pointers_p;
565438fd1498Szrj e.may_have_pointers = true;
565538fd1498Szrj e.only_restrict_pointers
565638fd1498Szrj = (!has_unknown_size
565738fd1498Szrj && POINTER_TYPE_P (field_type)
565838fd1498Szrj && TYPE_RESTRICT (field_type));
565938fd1498Szrj if (e.only_restrict_pointers)
566038fd1498Szrj e.restrict_pointed_type = TREE_TYPE (field_type);
566138fd1498Szrj fieldstack->safe_push (e);
566238fd1498Szrj }
566338fd1498Szrj }
566438fd1498Szrj
566538fd1498Szrj empty_p = false;
566638fd1498Szrj }
566738fd1498Szrj
566838fd1498Szrj return !empty_p;
566938fd1498Szrj }
567038fd1498Szrj
567138fd1498Szrj /* Count the number of arguments DECL has, and set IS_VARARGS to true
567238fd1498Szrj if it is a varargs function. */
567338fd1498Szrj
567438fd1498Szrj static unsigned int
count_num_arguments(tree decl,bool * is_varargs)567538fd1498Szrj count_num_arguments (tree decl, bool *is_varargs)
567638fd1498Szrj {
567738fd1498Szrj unsigned int num = 0;
567838fd1498Szrj tree t;
567938fd1498Szrj
568038fd1498Szrj /* Capture named arguments for K&R functions. They do not
568138fd1498Szrj have a prototype and thus no TYPE_ARG_TYPES. */
568238fd1498Szrj for (t = DECL_ARGUMENTS (decl); t; t = DECL_CHAIN (t))
568338fd1498Szrj ++num;
568438fd1498Szrj
568538fd1498Szrj /* Check if the function has variadic arguments. */
568638fd1498Szrj for (t = TYPE_ARG_TYPES (TREE_TYPE (decl)); t; t = TREE_CHAIN (t))
568738fd1498Szrj if (TREE_VALUE (t) == void_type_node)
568838fd1498Szrj break;
568938fd1498Szrj if (!t)
569038fd1498Szrj *is_varargs = true;
569138fd1498Szrj
569238fd1498Szrj return num;
569338fd1498Szrj }
569438fd1498Szrj
569538fd1498Szrj /* Creation function node for DECL, using NAME, and return the index
569638fd1498Szrj of the variable we've created for the function. If NONLOCAL_p, create
569738fd1498Szrj initial constraints. */
569838fd1498Szrj
569938fd1498Szrj static varinfo_t
create_function_info_for(tree decl,const char * name,bool add_id,bool nonlocal_p)570038fd1498Szrj create_function_info_for (tree decl, const char *name, bool add_id,
570138fd1498Szrj bool nonlocal_p)
570238fd1498Szrj {
570338fd1498Szrj struct function *fn = DECL_STRUCT_FUNCTION (decl);
570438fd1498Szrj varinfo_t vi, prev_vi;
570538fd1498Szrj tree arg;
570638fd1498Szrj unsigned int i;
570738fd1498Szrj bool is_varargs = false;
570838fd1498Szrj unsigned int num_args = count_num_arguments (decl, &is_varargs);
570938fd1498Szrj
571038fd1498Szrj /* Create the variable info. */
571138fd1498Szrj
571238fd1498Szrj vi = new_var_info (decl, name, add_id);
571338fd1498Szrj vi->offset = 0;
571438fd1498Szrj vi->size = 1;
571538fd1498Szrj vi->fullsize = fi_parm_base + num_args;
571638fd1498Szrj vi->is_fn_info = 1;
571738fd1498Szrj vi->may_have_pointers = false;
571838fd1498Szrj if (is_varargs)
571938fd1498Szrj vi->fullsize = ~0;
572038fd1498Szrj insert_vi_for_tree (vi->decl, vi);
572138fd1498Szrj
572238fd1498Szrj prev_vi = vi;
572338fd1498Szrj
572438fd1498Szrj /* Create a variable for things the function clobbers and one for
572538fd1498Szrj things the function uses. */
572638fd1498Szrj {
572738fd1498Szrj varinfo_t clobbervi, usevi;
572838fd1498Szrj const char *newname;
572938fd1498Szrj char *tempname;
573038fd1498Szrj
573138fd1498Szrj tempname = xasprintf ("%s.clobber", name);
573238fd1498Szrj newname = ggc_strdup (tempname);
573338fd1498Szrj free (tempname);
573438fd1498Szrj
573538fd1498Szrj clobbervi = new_var_info (NULL, newname, false);
573638fd1498Szrj clobbervi->offset = fi_clobbers;
573738fd1498Szrj clobbervi->size = 1;
573838fd1498Szrj clobbervi->fullsize = vi->fullsize;
573938fd1498Szrj clobbervi->is_full_var = true;
574038fd1498Szrj clobbervi->is_global_var = false;
574138fd1498Szrj clobbervi->is_reg_var = true;
574238fd1498Szrj
574338fd1498Szrj gcc_assert (prev_vi->offset < clobbervi->offset);
574438fd1498Szrj prev_vi->next = clobbervi->id;
574538fd1498Szrj prev_vi = clobbervi;
574638fd1498Szrj
574738fd1498Szrj tempname = xasprintf ("%s.use", name);
574838fd1498Szrj newname = ggc_strdup (tempname);
574938fd1498Szrj free (tempname);
575038fd1498Szrj
575138fd1498Szrj usevi = new_var_info (NULL, newname, false);
575238fd1498Szrj usevi->offset = fi_uses;
575338fd1498Szrj usevi->size = 1;
575438fd1498Szrj usevi->fullsize = vi->fullsize;
575538fd1498Szrj usevi->is_full_var = true;
575638fd1498Szrj usevi->is_global_var = false;
575738fd1498Szrj usevi->is_reg_var = true;
575838fd1498Szrj
575938fd1498Szrj gcc_assert (prev_vi->offset < usevi->offset);
576038fd1498Szrj prev_vi->next = usevi->id;
576138fd1498Szrj prev_vi = usevi;
576238fd1498Szrj }
576338fd1498Szrj
576438fd1498Szrj /* And one for the static chain. */
576538fd1498Szrj if (fn->static_chain_decl != NULL_TREE)
576638fd1498Szrj {
576738fd1498Szrj varinfo_t chainvi;
576838fd1498Szrj const char *newname;
576938fd1498Szrj char *tempname;
577038fd1498Szrj
577138fd1498Szrj tempname = xasprintf ("%s.chain", name);
577238fd1498Szrj newname = ggc_strdup (tempname);
577338fd1498Szrj free (tempname);
577438fd1498Szrj
577538fd1498Szrj chainvi = new_var_info (fn->static_chain_decl, newname, false);
577638fd1498Szrj chainvi->offset = fi_static_chain;
577738fd1498Szrj chainvi->size = 1;
577838fd1498Szrj chainvi->fullsize = vi->fullsize;
577938fd1498Szrj chainvi->is_full_var = true;
578038fd1498Szrj chainvi->is_global_var = false;
578138fd1498Szrj
578238fd1498Szrj insert_vi_for_tree (fn->static_chain_decl, chainvi);
578338fd1498Szrj
578438fd1498Szrj if (nonlocal_p
578538fd1498Szrj && chainvi->may_have_pointers)
578638fd1498Szrj make_constraint_from (chainvi, nonlocal_id);
578738fd1498Szrj
578838fd1498Szrj gcc_assert (prev_vi->offset < chainvi->offset);
578938fd1498Szrj prev_vi->next = chainvi->id;
579038fd1498Szrj prev_vi = chainvi;
579138fd1498Szrj }
579238fd1498Szrj
579338fd1498Szrj /* Create a variable for the return var. */
579438fd1498Szrj if (DECL_RESULT (decl) != NULL
579538fd1498Szrj || !VOID_TYPE_P (TREE_TYPE (TREE_TYPE (decl))))
579638fd1498Szrj {
579738fd1498Szrj varinfo_t resultvi;
579838fd1498Szrj const char *newname;
579938fd1498Szrj char *tempname;
580038fd1498Szrj tree resultdecl = decl;
580138fd1498Szrj
580238fd1498Szrj if (DECL_RESULT (decl))
580338fd1498Szrj resultdecl = DECL_RESULT (decl);
580438fd1498Szrj
580538fd1498Szrj tempname = xasprintf ("%s.result", name);
580638fd1498Szrj newname = ggc_strdup (tempname);
580738fd1498Szrj free (tempname);
580838fd1498Szrj
580938fd1498Szrj resultvi = new_var_info (resultdecl, newname, false);
581038fd1498Szrj resultvi->offset = fi_result;
581138fd1498Szrj resultvi->size = 1;
581238fd1498Szrj resultvi->fullsize = vi->fullsize;
581338fd1498Szrj resultvi->is_full_var = true;
581438fd1498Szrj if (DECL_RESULT (decl))
581538fd1498Szrj resultvi->may_have_pointers = true;
581638fd1498Szrj
581738fd1498Szrj if (DECL_RESULT (decl))
581838fd1498Szrj insert_vi_for_tree (DECL_RESULT (decl), resultvi);
581938fd1498Szrj
582038fd1498Szrj if (nonlocal_p
582138fd1498Szrj && DECL_RESULT (decl)
582238fd1498Szrj && DECL_BY_REFERENCE (DECL_RESULT (decl)))
582338fd1498Szrj make_constraint_from (resultvi, nonlocal_id);
582438fd1498Szrj
582538fd1498Szrj gcc_assert (prev_vi->offset < resultvi->offset);
582638fd1498Szrj prev_vi->next = resultvi->id;
582738fd1498Szrj prev_vi = resultvi;
582838fd1498Szrj }
582938fd1498Szrj
583038fd1498Szrj /* We also need to make function return values escape. Nothing
583138fd1498Szrj escapes by returning from main though. */
583238fd1498Szrj if (nonlocal_p
583338fd1498Szrj && !MAIN_NAME_P (DECL_NAME (decl)))
583438fd1498Szrj {
583538fd1498Szrj varinfo_t fi, rvi;
583638fd1498Szrj fi = lookup_vi_for_tree (decl);
583738fd1498Szrj rvi = first_vi_for_offset (fi, fi_result);
583838fd1498Szrj if (rvi && rvi->offset == fi_result)
583938fd1498Szrj make_copy_constraint (get_varinfo (escaped_id), rvi->id);
584038fd1498Szrj }
584138fd1498Szrj
584238fd1498Szrj /* Set up variables for each argument. */
584338fd1498Szrj arg = DECL_ARGUMENTS (decl);
584438fd1498Szrj for (i = 0; i < num_args; i++)
584538fd1498Szrj {
584638fd1498Szrj varinfo_t argvi;
584738fd1498Szrj const char *newname;
584838fd1498Szrj char *tempname;
584938fd1498Szrj tree argdecl = decl;
585038fd1498Szrj
585138fd1498Szrj if (arg)
585238fd1498Szrj argdecl = arg;
585338fd1498Szrj
585438fd1498Szrj tempname = xasprintf ("%s.arg%d", name, i);
585538fd1498Szrj newname = ggc_strdup (tempname);
585638fd1498Szrj free (tempname);
585738fd1498Szrj
585838fd1498Szrj argvi = new_var_info (argdecl, newname, false);
585938fd1498Szrj argvi->offset = fi_parm_base + i;
586038fd1498Szrj argvi->size = 1;
586138fd1498Szrj argvi->is_full_var = true;
586238fd1498Szrj argvi->fullsize = vi->fullsize;
586338fd1498Szrj if (arg)
586438fd1498Szrj argvi->may_have_pointers = true;
586538fd1498Szrj
586638fd1498Szrj if (arg)
586738fd1498Szrj insert_vi_for_tree (arg, argvi);
586838fd1498Szrj
586938fd1498Szrj if (nonlocal_p
587038fd1498Szrj && argvi->may_have_pointers)
587138fd1498Szrj make_constraint_from (argvi, nonlocal_id);
587238fd1498Szrj
587338fd1498Szrj gcc_assert (prev_vi->offset < argvi->offset);
587438fd1498Szrj prev_vi->next = argvi->id;
587538fd1498Szrj prev_vi = argvi;
587638fd1498Szrj if (arg)
587738fd1498Szrj arg = DECL_CHAIN (arg);
587838fd1498Szrj }
587938fd1498Szrj
588038fd1498Szrj /* Add one representative for all further args. */
588138fd1498Szrj if (is_varargs)
588238fd1498Szrj {
588338fd1498Szrj varinfo_t argvi;
588438fd1498Szrj const char *newname;
588538fd1498Szrj char *tempname;
588638fd1498Szrj tree decl;
588738fd1498Szrj
588838fd1498Szrj tempname = xasprintf ("%s.varargs", name);
588938fd1498Szrj newname = ggc_strdup (tempname);
589038fd1498Szrj free (tempname);
589138fd1498Szrj
589238fd1498Szrj /* We need sth that can be pointed to for va_start. */
589338fd1498Szrj decl = build_fake_var_decl (ptr_type_node);
589438fd1498Szrj
589538fd1498Szrj argvi = new_var_info (decl, newname, false);
589638fd1498Szrj argvi->offset = fi_parm_base + num_args;
589738fd1498Szrj argvi->size = ~0;
589838fd1498Szrj argvi->is_full_var = true;
589938fd1498Szrj argvi->is_heap_var = true;
590038fd1498Szrj argvi->fullsize = vi->fullsize;
590138fd1498Szrj
590238fd1498Szrj if (nonlocal_p
590338fd1498Szrj && argvi->may_have_pointers)
590438fd1498Szrj make_constraint_from (argvi, nonlocal_id);
590538fd1498Szrj
590638fd1498Szrj gcc_assert (prev_vi->offset < argvi->offset);
590738fd1498Szrj prev_vi->next = argvi->id;
590838fd1498Szrj prev_vi = argvi;
590938fd1498Szrj }
591038fd1498Szrj
591138fd1498Szrj return vi;
591238fd1498Szrj }
591338fd1498Szrj
591438fd1498Szrj
591538fd1498Szrj /* Return true if FIELDSTACK contains fields that overlap.
591638fd1498Szrj FIELDSTACK is assumed to be sorted by offset. */
591738fd1498Szrj
591838fd1498Szrj static bool
check_for_overlaps(vec<fieldoff_s> fieldstack)591938fd1498Szrj check_for_overlaps (vec<fieldoff_s> fieldstack)
592038fd1498Szrj {
592138fd1498Szrj fieldoff_s *fo = NULL;
592238fd1498Szrj unsigned int i;
592338fd1498Szrj HOST_WIDE_INT lastoffset = -1;
592438fd1498Szrj
592538fd1498Szrj FOR_EACH_VEC_ELT (fieldstack, i, fo)
592638fd1498Szrj {
592738fd1498Szrj if (fo->offset == lastoffset)
592838fd1498Szrj return true;
592938fd1498Szrj lastoffset = fo->offset;
593038fd1498Szrj }
593138fd1498Szrj return false;
593238fd1498Szrj }
593338fd1498Szrj
593438fd1498Szrj /* Create a varinfo structure for NAME and DECL, and add it to VARMAP.
593538fd1498Szrj This will also create any varinfo structures necessary for fields
593638fd1498Szrj of DECL. DECL is a function parameter if HANDLE_PARAM is set.
593738fd1498Szrj HANDLED_STRUCT_TYPE is used to register struct types reached by following
593838fd1498Szrj restrict pointers. This is needed to prevent infinite recursion. */
593938fd1498Szrj
594038fd1498Szrj static varinfo_t
create_variable_info_for_1(tree decl,const char * name,bool add_id,bool handle_param,bitmap handled_struct_type)594138fd1498Szrj create_variable_info_for_1 (tree decl, const char *name, bool add_id,
594238fd1498Szrj bool handle_param, bitmap handled_struct_type)
594338fd1498Szrj {
594438fd1498Szrj varinfo_t vi, newvi;
594538fd1498Szrj tree decl_type = TREE_TYPE (decl);
594638fd1498Szrj tree declsize = DECL_P (decl) ? DECL_SIZE (decl) : TYPE_SIZE (decl_type);
594738fd1498Szrj auto_vec<fieldoff_s> fieldstack;
594838fd1498Szrj fieldoff_s *fo;
594938fd1498Szrj unsigned int i;
595038fd1498Szrj
595138fd1498Szrj if (!declsize
595238fd1498Szrj || !tree_fits_uhwi_p (declsize))
595338fd1498Szrj {
595438fd1498Szrj vi = new_var_info (decl, name, add_id);
595538fd1498Szrj vi->offset = 0;
595638fd1498Szrj vi->size = ~0;
595738fd1498Szrj vi->fullsize = ~0;
595838fd1498Szrj vi->is_unknown_size_var = true;
595938fd1498Szrj vi->is_full_var = true;
596038fd1498Szrj vi->may_have_pointers = true;
596138fd1498Szrj return vi;
596238fd1498Szrj }
596338fd1498Szrj
596438fd1498Szrj /* Collect field information. */
596538fd1498Szrj if (use_field_sensitive
596638fd1498Szrj && var_can_have_subvars (decl)
596738fd1498Szrj /* ??? Force us to not use subfields for globals in IPA mode.
596838fd1498Szrj Else we'd have to parse arbitrary initializers. */
596938fd1498Szrj && !(in_ipa_mode
597038fd1498Szrj && is_global_var (decl)))
597138fd1498Szrj {
597238fd1498Szrj fieldoff_s *fo = NULL;
597338fd1498Szrj bool notokay = false;
597438fd1498Szrj unsigned int i;
597538fd1498Szrj
597638fd1498Szrj push_fields_onto_fieldstack (decl_type, &fieldstack, 0);
597738fd1498Szrj
597838fd1498Szrj for (i = 0; !notokay && fieldstack.iterate (i, &fo); i++)
597938fd1498Szrj if (fo->has_unknown_size
598038fd1498Szrj || fo->offset < 0)
598138fd1498Szrj {
598238fd1498Szrj notokay = true;
598338fd1498Szrj break;
598438fd1498Szrj }
598538fd1498Szrj
598638fd1498Szrj /* We can't sort them if we have a field with a variable sized type,
598738fd1498Szrj which will make notokay = true. In that case, we are going to return
598838fd1498Szrj without creating varinfos for the fields anyway, so sorting them is a
598938fd1498Szrj waste to boot. */
599038fd1498Szrj if (!notokay)
599138fd1498Szrj {
599238fd1498Szrj sort_fieldstack (fieldstack);
599338fd1498Szrj /* Due to some C++ FE issues, like PR 22488, we might end up
599438fd1498Szrj what appear to be overlapping fields even though they,
599538fd1498Szrj in reality, do not overlap. Until the C++ FE is fixed,
599638fd1498Szrj we will simply disable field-sensitivity for these cases. */
599738fd1498Szrj notokay = check_for_overlaps (fieldstack);
599838fd1498Szrj }
599938fd1498Szrj
600038fd1498Szrj if (notokay)
600138fd1498Szrj fieldstack.release ();
600238fd1498Szrj }
600338fd1498Szrj
600438fd1498Szrj /* If we didn't end up collecting sub-variables create a full
600538fd1498Szrj variable for the decl. */
600638fd1498Szrj if (fieldstack.length () == 0
600738fd1498Szrj || fieldstack.length () > MAX_FIELDS_FOR_FIELD_SENSITIVE)
600838fd1498Szrj {
600938fd1498Szrj vi = new_var_info (decl, name, add_id);
601038fd1498Szrj vi->offset = 0;
601138fd1498Szrj vi->may_have_pointers = true;
601238fd1498Szrj vi->fullsize = tree_to_uhwi (declsize);
601338fd1498Szrj vi->size = vi->fullsize;
601438fd1498Szrj vi->is_full_var = true;
601538fd1498Szrj if (POINTER_TYPE_P (decl_type)
601638fd1498Szrj && TYPE_RESTRICT (decl_type))
601738fd1498Szrj vi->only_restrict_pointers = 1;
601838fd1498Szrj if (vi->only_restrict_pointers
601938fd1498Szrj && !type_contains_placeholder_p (TREE_TYPE (decl_type))
602038fd1498Szrj && handle_param
602138fd1498Szrj && !bitmap_bit_p (handled_struct_type,
602238fd1498Szrj TYPE_UID (TREE_TYPE (decl_type))))
602338fd1498Szrj {
602438fd1498Szrj varinfo_t rvi;
602538fd1498Szrj tree heapvar = build_fake_var_decl (TREE_TYPE (decl_type));
602638fd1498Szrj DECL_EXTERNAL (heapvar) = 1;
602738fd1498Szrj if (var_can_have_subvars (heapvar))
602838fd1498Szrj bitmap_set_bit (handled_struct_type,
602938fd1498Szrj TYPE_UID (TREE_TYPE (decl_type)));
603038fd1498Szrj rvi = create_variable_info_for_1 (heapvar, "PARM_NOALIAS", true,
603138fd1498Szrj true, handled_struct_type);
603238fd1498Szrj if (var_can_have_subvars (heapvar))
603338fd1498Szrj bitmap_clear_bit (handled_struct_type,
603438fd1498Szrj TYPE_UID (TREE_TYPE (decl_type)));
603538fd1498Szrj rvi->is_restrict_var = 1;
603638fd1498Szrj insert_vi_for_tree (heapvar, rvi);
603738fd1498Szrj make_constraint_from (vi, rvi->id);
603838fd1498Szrj make_param_constraints (rvi);
603938fd1498Szrj }
604038fd1498Szrj fieldstack.release ();
604138fd1498Szrj return vi;
604238fd1498Szrj }
604338fd1498Szrj
604438fd1498Szrj vi = new_var_info (decl, name, add_id);
604538fd1498Szrj vi->fullsize = tree_to_uhwi (declsize);
604638fd1498Szrj if (fieldstack.length () == 1)
604738fd1498Szrj vi->is_full_var = true;
604838fd1498Szrj for (i = 0, newvi = vi;
604938fd1498Szrj fieldstack.iterate (i, &fo);
605038fd1498Szrj ++i, newvi = vi_next (newvi))
605138fd1498Szrj {
605238fd1498Szrj const char *newname = NULL;
605338fd1498Szrj char *tempname;
605438fd1498Szrj
605538fd1498Szrj if (dump_file)
605638fd1498Szrj {
605738fd1498Szrj if (fieldstack.length () != 1)
605838fd1498Szrj {
605938fd1498Szrj tempname
606038fd1498Szrj = xasprintf ("%s." HOST_WIDE_INT_PRINT_DEC
606138fd1498Szrj "+" HOST_WIDE_INT_PRINT_DEC, name,
606238fd1498Szrj fo->offset, fo->size);
606338fd1498Szrj newname = ggc_strdup (tempname);
606438fd1498Szrj free (tempname);
606538fd1498Szrj }
606638fd1498Szrj }
606738fd1498Szrj else
606838fd1498Szrj newname = "NULL";
606938fd1498Szrj
607038fd1498Szrj if (newname)
607138fd1498Szrj newvi->name = newname;
607238fd1498Szrj newvi->offset = fo->offset;
607338fd1498Szrj newvi->size = fo->size;
607438fd1498Szrj newvi->fullsize = vi->fullsize;
607538fd1498Szrj newvi->may_have_pointers = fo->may_have_pointers;
607638fd1498Szrj newvi->only_restrict_pointers = fo->only_restrict_pointers;
607738fd1498Szrj if (handle_param
607838fd1498Szrj && newvi->only_restrict_pointers
607938fd1498Szrj && !type_contains_placeholder_p (fo->restrict_pointed_type)
608038fd1498Szrj && !bitmap_bit_p (handled_struct_type,
608138fd1498Szrj TYPE_UID (fo->restrict_pointed_type)))
608238fd1498Szrj {
608338fd1498Szrj varinfo_t rvi;
608438fd1498Szrj tree heapvar = build_fake_var_decl (fo->restrict_pointed_type);
608538fd1498Szrj DECL_EXTERNAL (heapvar) = 1;
608638fd1498Szrj if (var_can_have_subvars (heapvar))
608738fd1498Szrj bitmap_set_bit (handled_struct_type,
608838fd1498Szrj TYPE_UID (fo->restrict_pointed_type));
608938fd1498Szrj rvi = create_variable_info_for_1 (heapvar, "PARM_NOALIAS", true,
609038fd1498Szrj true, handled_struct_type);
609138fd1498Szrj if (var_can_have_subvars (heapvar))
609238fd1498Szrj bitmap_clear_bit (handled_struct_type,
609338fd1498Szrj TYPE_UID (fo->restrict_pointed_type));
609438fd1498Szrj rvi->is_restrict_var = 1;
609538fd1498Szrj insert_vi_for_tree (heapvar, rvi);
609638fd1498Szrj make_constraint_from (newvi, rvi->id);
609738fd1498Szrj make_param_constraints (rvi);
609838fd1498Szrj }
609938fd1498Szrj if (i + 1 < fieldstack.length ())
610038fd1498Szrj {
610138fd1498Szrj varinfo_t tem = new_var_info (decl, name, false);
610238fd1498Szrj newvi->next = tem->id;
610338fd1498Szrj tem->head = vi->id;
610438fd1498Szrj }
610538fd1498Szrj }
610638fd1498Szrj
610738fd1498Szrj return vi;
610838fd1498Szrj }
610938fd1498Szrj
611038fd1498Szrj static unsigned int
create_variable_info_for(tree decl,const char * name,bool add_id)611138fd1498Szrj create_variable_info_for (tree decl, const char *name, bool add_id)
611238fd1498Szrj {
611338fd1498Szrj varinfo_t vi = create_variable_info_for_1 (decl, name, add_id, false, NULL);
611438fd1498Szrj unsigned int id = vi->id;
611538fd1498Szrj
611638fd1498Szrj insert_vi_for_tree (decl, vi);
611738fd1498Szrj
611838fd1498Szrj if (!VAR_P (decl))
611938fd1498Szrj return id;
612038fd1498Szrj
612138fd1498Szrj /* Create initial constraints for globals. */
612238fd1498Szrj for (; vi; vi = vi_next (vi))
612338fd1498Szrj {
612438fd1498Szrj if (!vi->may_have_pointers
612538fd1498Szrj || !vi->is_global_var)
612638fd1498Szrj continue;
612738fd1498Szrj
612838fd1498Szrj /* Mark global restrict qualified pointers. */
612938fd1498Szrj if ((POINTER_TYPE_P (TREE_TYPE (decl))
613038fd1498Szrj && TYPE_RESTRICT (TREE_TYPE (decl)))
613138fd1498Szrj || vi->only_restrict_pointers)
613238fd1498Szrj {
613338fd1498Szrj varinfo_t rvi
613438fd1498Szrj = make_constraint_from_global_restrict (vi, "GLOBAL_RESTRICT",
613538fd1498Szrj true);
613638fd1498Szrj /* ??? For now exclude reads from globals as restrict sources
613738fd1498Szrj if those are not (indirectly) from incoming parameters. */
613838fd1498Szrj rvi->is_restrict_var = false;
613938fd1498Szrj continue;
614038fd1498Szrj }
614138fd1498Szrj
614238fd1498Szrj /* In non-IPA mode the initializer from nonlocal is all we need. */
614338fd1498Szrj if (!in_ipa_mode
614438fd1498Szrj || DECL_HARD_REGISTER (decl))
614538fd1498Szrj make_copy_constraint (vi, nonlocal_id);
614638fd1498Szrj
614738fd1498Szrj /* In IPA mode parse the initializer and generate proper constraints
614838fd1498Szrj for it. */
614938fd1498Szrj else
615038fd1498Szrj {
615138fd1498Szrj varpool_node *vnode = varpool_node::get (decl);
615238fd1498Szrj
615338fd1498Szrj /* For escaped variables initialize them from nonlocal. */
615438fd1498Szrj if (!vnode->all_refs_explicit_p ())
615538fd1498Szrj make_copy_constraint (vi, nonlocal_id);
615638fd1498Szrj
615738fd1498Szrj /* If this is a global variable with an initializer and we are in
615838fd1498Szrj IPA mode generate constraints for it. */
615938fd1498Szrj ipa_ref *ref;
616038fd1498Szrj for (unsigned idx = 0; vnode->iterate_reference (idx, ref); ++idx)
616138fd1498Szrj {
616238fd1498Szrj auto_vec<ce_s> rhsc;
616338fd1498Szrj struct constraint_expr lhs, *rhsp;
616438fd1498Szrj unsigned i;
616538fd1498Szrj get_constraint_for_address_of (ref->referred->decl, &rhsc);
616638fd1498Szrj lhs.var = vi->id;
616738fd1498Szrj lhs.offset = 0;
616838fd1498Szrj lhs.type = SCALAR;
616938fd1498Szrj FOR_EACH_VEC_ELT (rhsc, i, rhsp)
617038fd1498Szrj process_constraint (new_constraint (lhs, *rhsp));
617138fd1498Szrj /* If this is a variable that escapes from the unit
617238fd1498Szrj the initializer escapes as well. */
617338fd1498Szrj if (!vnode->all_refs_explicit_p ())
617438fd1498Szrj {
617538fd1498Szrj lhs.var = escaped_id;
617638fd1498Szrj lhs.offset = 0;
617738fd1498Szrj lhs.type = SCALAR;
617838fd1498Szrj FOR_EACH_VEC_ELT (rhsc, i, rhsp)
617938fd1498Szrj process_constraint (new_constraint (lhs, *rhsp));
618038fd1498Szrj }
618138fd1498Szrj }
618238fd1498Szrj }
618338fd1498Szrj }
618438fd1498Szrj
618538fd1498Szrj return id;
618638fd1498Szrj }
618738fd1498Szrj
618838fd1498Szrj /* Print out the points-to solution for VAR to FILE. */
618938fd1498Szrj
619038fd1498Szrj static void
dump_solution_for_var(FILE * file,unsigned int var)619138fd1498Szrj dump_solution_for_var (FILE *file, unsigned int var)
619238fd1498Szrj {
619338fd1498Szrj varinfo_t vi = get_varinfo (var);
619438fd1498Szrj unsigned int i;
619538fd1498Szrj bitmap_iterator bi;
619638fd1498Szrj
619738fd1498Szrj /* Dump the solution for unified vars anyway, this avoids difficulties
619838fd1498Szrj in scanning dumps in the testsuite. */
619938fd1498Szrj fprintf (file, "%s = { ", vi->name);
620038fd1498Szrj vi = get_varinfo (find (var));
620138fd1498Szrj EXECUTE_IF_SET_IN_BITMAP (vi->solution, 0, i, bi)
620238fd1498Szrj fprintf (file, "%s ", get_varinfo (i)->name);
620338fd1498Szrj fprintf (file, "}");
620438fd1498Szrj
620538fd1498Szrj /* But note when the variable was unified. */
620638fd1498Szrj if (vi->id != var)
620738fd1498Szrj fprintf (file, " same as %s", vi->name);
620838fd1498Szrj
620938fd1498Szrj fprintf (file, "\n");
621038fd1498Szrj }
621138fd1498Szrj
621238fd1498Szrj /* Print the points-to solution for VAR to stderr. */
621338fd1498Szrj
621438fd1498Szrj DEBUG_FUNCTION void
debug_solution_for_var(unsigned int var)621538fd1498Szrj debug_solution_for_var (unsigned int var)
621638fd1498Szrj {
621738fd1498Szrj dump_solution_for_var (stderr, var);
621838fd1498Szrj }
621938fd1498Szrj
622038fd1498Szrj /* Register the constraints for function parameter related VI. */
622138fd1498Szrj
622238fd1498Szrj static void
make_param_constraints(varinfo_t vi)622338fd1498Szrj make_param_constraints (varinfo_t vi)
622438fd1498Szrj {
622538fd1498Szrj for (; vi; vi = vi_next (vi))
622638fd1498Szrj {
622738fd1498Szrj if (vi->only_restrict_pointers)
622838fd1498Szrj ;
622938fd1498Szrj else if (vi->may_have_pointers)
623038fd1498Szrj make_constraint_from (vi, nonlocal_id);
623138fd1498Szrj
623238fd1498Szrj if (vi->is_full_var)
623338fd1498Szrj break;
623438fd1498Szrj }
623538fd1498Szrj }
623638fd1498Szrj
623738fd1498Szrj /* Create varinfo structures for all of the variables in the
623838fd1498Szrj function for intraprocedural mode. */
623938fd1498Szrj
624038fd1498Szrj static void
intra_create_variable_infos(struct function * fn)624138fd1498Szrj intra_create_variable_infos (struct function *fn)
624238fd1498Szrj {
624338fd1498Szrj tree t;
624438fd1498Szrj bitmap handled_struct_type = NULL;
624538fd1498Szrj
624638fd1498Szrj /* For each incoming pointer argument arg, create the constraint ARG
624738fd1498Szrj = NONLOCAL or a dummy variable if it is a restrict qualified
624838fd1498Szrj passed-by-reference argument. */
624938fd1498Szrj for (t = DECL_ARGUMENTS (fn->decl); t; t = DECL_CHAIN (t))
625038fd1498Szrj {
625138fd1498Szrj if (handled_struct_type == NULL)
625238fd1498Szrj handled_struct_type = BITMAP_ALLOC (NULL);
625338fd1498Szrj
625438fd1498Szrj varinfo_t p
625538fd1498Szrj = create_variable_info_for_1 (t, alias_get_name (t), false, true,
625638fd1498Szrj handled_struct_type);
625738fd1498Szrj insert_vi_for_tree (t, p);
625838fd1498Szrj
625938fd1498Szrj make_param_constraints (p);
626038fd1498Szrj }
626138fd1498Szrj
626238fd1498Szrj if (handled_struct_type != NULL)
626338fd1498Szrj BITMAP_FREE (handled_struct_type);
626438fd1498Szrj
626538fd1498Szrj /* Add a constraint for a result decl that is passed by reference. */
626638fd1498Szrj if (DECL_RESULT (fn->decl)
626738fd1498Szrj && DECL_BY_REFERENCE (DECL_RESULT (fn->decl)))
626838fd1498Szrj {
626938fd1498Szrj varinfo_t p, result_vi = get_vi_for_tree (DECL_RESULT (fn->decl));
627038fd1498Szrj
627138fd1498Szrj for (p = result_vi; p; p = vi_next (p))
627238fd1498Szrj make_constraint_from (p, nonlocal_id);
627338fd1498Szrj }
627438fd1498Szrj
627538fd1498Szrj /* Add a constraint for the incoming static chain parameter. */
627638fd1498Szrj if (fn->static_chain_decl != NULL_TREE)
627738fd1498Szrj {
627838fd1498Szrj varinfo_t p, chain_vi = get_vi_for_tree (fn->static_chain_decl);
627938fd1498Szrj
628038fd1498Szrj for (p = chain_vi; p; p = vi_next (p))
628138fd1498Szrj make_constraint_from (p, nonlocal_id);
628238fd1498Szrj }
628338fd1498Szrj }
628438fd1498Szrj
628538fd1498Szrj /* Structure used to put solution bitmaps in a hashtable so they can
628638fd1498Szrj be shared among variables with the same points-to set. */
628738fd1498Szrj
628838fd1498Szrj typedef struct shared_bitmap_info
628938fd1498Szrj {
629038fd1498Szrj bitmap pt_vars;
629138fd1498Szrj hashval_t hashcode;
629238fd1498Szrj } *shared_bitmap_info_t;
629338fd1498Szrj typedef const struct shared_bitmap_info *const_shared_bitmap_info_t;
629438fd1498Szrj
629538fd1498Szrj /* Shared_bitmap hashtable helpers. */
629638fd1498Szrj
629738fd1498Szrj struct shared_bitmap_hasher : free_ptr_hash <shared_bitmap_info>
629838fd1498Szrj {
629938fd1498Szrj static inline hashval_t hash (const shared_bitmap_info *);
630038fd1498Szrj static inline bool equal (const shared_bitmap_info *,
630138fd1498Szrj const shared_bitmap_info *);
630238fd1498Szrj };
630338fd1498Szrj
630438fd1498Szrj /* Hash function for a shared_bitmap_info_t */
630538fd1498Szrj
630638fd1498Szrj inline hashval_t
hash(const shared_bitmap_info * bi)630738fd1498Szrj shared_bitmap_hasher::hash (const shared_bitmap_info *bi)
630838fd1498Szrj {
630938fd1498Szrj return bi->hashcode;
631038fd1498Szrj }
631138fd1498Szrj
631238fd1498Szrj /* Equality function for two shared_bitmap_info_t's. */
631338fd1498Szrj
631438fd1498Szrj inline bool
equal(const shared_bitmap_info * sbi1,const shared_bitmap_info * sbi2)631538fd1498Szrj shared_bitmap_hasher::equal (const shared_bitmap_info *sbi1,
631638fd1498Szrj const shared_bitmap_info *sbi2)
631738fd1498Szrj {
631838fd1498Szrj return bitmap_equal_p (sbi1->pt_vars, sbi2->pt_vars);
631938fd1498Szrj }
632038fd1498Szrj
632138fd1498Szrj /* Shared_bitmap hashtable. */
632238fd1498Szrj
632338fd1498Szrj static hash_table<shared_bitmap_hasher> *shared_bitmap_table;
632438fd1498Szrj
632538fd1498Szrj /* Lookup a bitmap in the shared bitmap hashtable, and return an already
632638fd1498Szrj existing instance if there is one, NULL otherwise. */
632738fd1498Szrj
632838fd1498Szrj static bitmap
shared_bitmap_lookup(bitmap pt_vars)632938fd1498Szrj shared_bitmap_lookup (bitmap pt_vars)
633038fd1498Szrj {
633138fd1498Szrj shared_bitmap_info **slot;
633238fd1498Szrj struct shared_bitmap_info sbi;
633338fd1498Szrj
633438fd1498Szrj sbi.pt_vars = pt_vars;
633538fd1498Szrj sbi.hashcode = bitmap_hash (pt_vars);
633638fd1498Szrj
633738fd1498Szrj slot = shared_bitmap_table->find_slot (&sbi, NO_INSERT);
633838fd1498Szrj if (!slot)
633938fd1498Szrj return NULL;
634038fd1498Szrj else
634138fd1498Szrj return (*slot)->pt_vars;
634238fd1498Szrj }
634338fd1498Szrj
634438fd1498Szrj
634538fd1498Szrj /* Add a bitmap to the shared bitmap hashtable. */
634638fd1498Szrj
634738fd1498Szrj static void
shared_bitmap_add(bitmap pt_vars)634838fd1498Szrj shared_bitmap_add (bitmap pt_vars)
634938fd1498Szrj {
635038fd1498Szrj shared_bitmap_info **slot;
635138fd1498Szrj shared_bitmap_info_t sbi = XNEW (struct shared_bitmap_info);
635238fd1498Szrj
635338fd1498Szrj sbi->pt_vars = pt_vars;
635438fd1498Szrj sbi->hashcode = bitmap_hash (pt_vars);
635538fd1498Szrj
635638fd1498Szrj slot = shared_bitmap_table->find_slot (sbi, INSERT);
635738fd1498Szrj gcc_assert (!*slot);
635838fd1498Szrj *slot = sbi;
635938fd1498Szrj }
636038fd1498Szrj
636138fd1498Szrj
636238fd1498Szrj /* Set bits in INTO corresponding to the variable uids in solution set FROM. */
636338fd1498Szrj
636438fd1498Szrj static void
set_uids_in_ptset(bitmap into,bitmap from,struct pt_solution * pt,tree fndecl)636538fd1498Szrj set_uids_in_ptset (bitmap into, bitmap from, struct pt_solution *pt,
636638fd1498Szrj tree fndecl)
636738fd1498Szrj {
636838fd1498Szrj unsigned int i;
636938fd1498Szrj bitmap_iterator bi;
637038fd1498Szrj varinfo_t escaped_vi = get_varinfo (find (escaped_id));
637138fd1498Szrj bool everything_escaped
637238fd1498Szrj = escaped_vi->solution && bitmap_bit_p (escaped_vi->solution, anything_id);
637338fd1498Szrj
637438fd1498Szrj EXECUTE_IF_SET_IN_BITMAP (from, 0, i, bi)
637538fd1498Szrj {
637638fd1498Szrj varinfo_t vi = get_varinfo (i);
637738fd1498Szrj
637838fd1498Szrj /* The only artificial variables that are allowed in a may-alias
637938fd1498Szrj set are heap variables. */
638038fd1498Szrj if (vi->is_artificial_var && !vi->is_heap_var)
638138fd1498Szrj continue;
638238fd1498Szrj
638338fd1498Szrj if (everything_escaped
638438fd1498Szrj || (escaped_vi->solution
638538fd1498Szrj && bitmap_bit_p (escaped_vi->solution, i)))
638638fd1498Szrj {
638738fd1498Szrj pt->vars_contains_escaped = true;
638858e805e6Szrj pt->vars_contains_escaped_heap |= vi->is_heap_var;
638938fd1498Szrj }
639038fd1498Szrj
639138fd1498Szrj if (vi->is_restrict_var)
639238fd1498Szrj pt->vars_contains_restrict = true;
639338fd1498Szrj
639438fd1498Szrj if (VAR_P (vi->decl)
639538fd1498Szrj || TREE_CODE (vi->decl) == PARM_DECL
639638fd1498Szrj || TREE_CODE (vi->decl) == RESULT_DECL)
639738fd1498Szrj {
639838fd1498Szrj /* If we are in IPA mode we will not recompute points-to
639938fd1498Szrj sets after inlining so make sure they stay valid. */
640038fd1498Szrj if (in_ipa_mode
640138fd1498Szrj && !DECL_PT_UID_SET_P (vi->decl))
640238fd1498Szrj SET_DECL_PT_UID (vi->decl, DECL_UID (vi->decl));
640338fd1498Szrj
640438fd1498Szrj /* Add the decl to the points-to set. Note that the points-to
640538fd1498Szrj set contains global variables. */
640638fd1498Szrj bitmap_set_bit (into, DECL_PT_UID (vi->decl));
640738fd1498Szrj if (vi->is_global_var
640838fd1498Szrj /* In IPA mode the escaped_heap trick doesn't work as
640938fd1498Szrj ESCAPED is escaped from the unit but
641038fd1498Szrj pt_solution_includes_global needs to answer true for
641138fd1498Szrj all variables not automatic within a function.
641238fd1498Szrj For the same reason is_global_var is not the
641338fd1498Szrj correct flag to track - local variables from other
641438fd1498Szrj functions also need to be considered global.
641538fd1498Szrj Conveniently all HEAP vars are not put in function
641638fd1498Szrj scope. */
641738fd1498Szrj || (in_ipa_mode
641838fd1498Szrj && fndecl
641938fd1498Szrj && ! auto_var_in_fn_p (vi->decl, fndecl)))
642038fd1498Szrj pt->vars_contains_nonlocal = true;
642138fd1498Szrj
642238fd1498Szrj /* If we have a variable that is interposable record that fact
642338fd1498Szrj for pointer comparison simplification. */
642438fd1498Szrj if (VAR_P (vi->decl)
642538fd1498Szrj && (TREE_STATIC (vi->decl) || DECL_EXTERNAL (vi->decl))
642638fd1498Szrj && ! decl_binds_to_current_def_p (vi->decl))
642738fd1498Szrj pt->vars_contains_interposable = true;
642838fd1498Szrj }
642938fd1498Szrj
643038fd1498Szrj else if (TREE_CODE (vi->decl) == FUNCTION_DECL
643138fd1498Szrj || TREE_CODE (vi->decl) == LABEL_DECL)
643238fd1498Szrj {
643338fd1498Szrj /* Nothing should read/write from/to code so we can
643438fd1498Szrj save bits by not including them in the points-to bitmaps.
643538fd1498Szrj Still mark the points-to set as containing global memory
643638fd1498Szrj to make code-patching possible - see PR70128. */
643738fd1498Szrj pt->vars_contains_nonlocal = true;
643838fd1498Szrj }
643938fd1498Szrj }
644038fd1498Szrj }
644138fd1498Szrj
644238fd1498Szrj
644338fd1498Szrj /* Compute the points-to solution *PT for the variable VI. */
644438fd1498Szrj
644538fd1498Szrj static struct pt_solution
find_what_var_points_to(tree fndecl,varinfo_t orig_vi)644638fd1498Szrj find_what_var_points_to (tree fndecl, varinfo_t orig_vi)
644738fd1498Szrj {
644838fd1498Szrj unsigned int i;
644938fd1498Szrj bitmap_iterator bi;
645038fd1498Szrj bitmap finished_solution;
645138fd1498Szrj bitmap result;
645238fd1498Szrj varinfo_t vi;
645338fd1498Szrj struct pt_solution *pt;
645438fd1498Szrj
645538fd1498Szrj /* This variable may have been collapsed, let's get the real
645638fd1498Szrj variable. */
645738fd1498Szrj vi = get_varinfo (find (orig_vi->id));
645838fd1498Szrj
645938fd1498Szrj /* See if we have already computed the solution and return it. */
646038fd1498Szrj pt_solution **slot = &final_solutions->get_or_insert (vi);
646138fd1498Szrj if (*slot != NULL)
646238fd1498Szrj return **slot;
646338fd1498Szrj
646438fd1498Szrj *slot = pt = XOBNEW (&final_solutions_obstack, struct pt_solution);
646538fd1498Szrj memset (pt, 0, sizeof (struct pt_solution));
646638fd1498Szrj
646738fd1498Szrj /* Translate artificial variables into SSA_NAME_PTR_INFO
646838fd1498Szrj attributes. */
646938fd1498Szrj EXECUTE_IF_SET_IN_BITMAP (vi->solution, 0, i, bi)
647038fd1498Szrj {
647138fd1498Szrj varinfo_t vi = get_varinfo (i);
647238fd1498Szrj
647338fd1498Szrj if (vi->is_artificial_var)
647438fd1498Szrj {
647538fd1498Szrj if (vi->id == nothing_id)
647638fd1498Szrj pt->null = 1;
647738fd1498Szrj else if (vi->id == escaped_id)
647838fd1498Szrj {
647938fd1498Szrj if (in_ipa_mode)
648038fd1498Szrj pt->ipa_escaped = 1;
648138fd1498Szrj else
648238fd1498Szrj pt->escaped = 1;
648338fd1498Szrj /* Expand some special vars of ESCAPED in-place here. */
648438fd1498Szrj varinfo_t evi = get_varinfo (find (escaped_id));
648538fd1498Szrj if (bitmap_bit_p (evi->solution, nonlocal_id))
648638fd1498Szrj pt->nonlocal = 1;
648738fd1498Szrj }
648838fd1498Szrj else if (vi->id == nonlocal_id)
648938fd1498Szrj pt->nonlocal = 1;
649038fd1498Szrj else if (vi->is_heap_var)
649138fd1498Szrj /* We represent heapvars in the points-to set properly. */
649238fd1498Szrj ;
649338fd1498Szrj else if (vi->id == string_id)
649438fd1498Szrj /* Nobody cares - STRING_CSTs are read-only entities. */
649538fd1498Szrj ;
649638fd1498Szrj else if (vi->id == anything_id
649738fd1498Szrj || vi->id == integer_id)
649838fd1498Szrj pt->anything = 1;
649938fd1498Szrj }
650038fd1498Szrj }
650138fd1498Szrj
650238fd1498Szrj /* Instead of doing extra work, simply do not create
650338fd1498Szrj elaborate points-to information for pt_anything pointers. */
650438fd1498Szrj if (pt->anything)
650538fd1498Szrj return *pt;
650638fd1498Szrj
650738fd1498Szrj /* Share the final set of variables when possible. */
650838fd1498Szrj finished_solution = BITMAP_GGC_ALLOC ();
650938fd1498Szrj stats.points_to_sets_created++;
651038fd1498Szrj
651138fd1498Szrj set_uids_in_ptset (finished_solution, vi->solution, pt, fndecl);
651238fd1498Szrj result = shared_bitmap_lookup (finished_solution);
651338fd1498Szrj if (!result)
651438fd1498Szrj {
651538fd1498Szrj shared_bitmap_add (finished_solution);
651638fd1498Szrj pt->vars = finished_solution;
651738fd1498Szrj }
651838fd1498Szrj else
651938fd1498Szrj {
652038fd1498Szrj pt->vars = result;
652138fd1498Szrj bitmap_clear (finished_solution);
652238fd1498Szrj }
652338fd1498Szrj
652438fd1498Szrj return *pt;
652538fd1498Szrj }
652638fd1498Szrj
652738fd1498Szrj /* Given a pointer variable P, fill in its points-to set. */
652838fd1498Szrj
652938fd1498Szrj static void
find_what_p_points_to(tree fndecl,tree p)653038fd1498Szrj find_what_p_points_to (tree fndecl, tree p)
653138fd1498Szrj {
653238fd1498Szrj struct ptr_info_def *pi;
653338fd1498Szrj tree lookup_p = p;
653438fd1498Szrj varinfo_t vi;
653538fd1498Szrj bool nonnull = get_ptr_nonnull (p);
653638fd1498Szrj
653738fd1498Szrj /* For parameters, get at the points-to set for the actual parm
653838fd1498Szrj decl. */
653938fd1498Szrj if (TREE_CODE (p) == SSA_NAME
654038fd1498Szrj && SSA_NAME_IS_DEFAULT_DEF (p)
654138fd1498Szrj && (TREE_CODE (SSA_NAME_VAR (p)) == PARM_DECL
654238fd1498Szrj || TREE_CODE (SSA_NAME_VAR (p)) == RESULT_DECL))
654338fd1498Szrj lookup_p = SSA_NAME_VAR (p);
654438fd1498Szrj
654538fd1498Szrj vi = lookup_vi_for_tree (lookup_p);
654638fd1498Szrj if (!vi)
654738fd1498Szrj return;
654838fd1498Szrj
654938fd1498Szrj pi = get_ptr_info (p);
655038fd1498Szrj pi->pt = find_what_var_points_to (fndecl, vi);
655138fd1498Szrj /* Conservatively set to NULL from PTA (to true). */
655238fd1498Szrj pi->pt.null = 1;
655338fd1498Szrj /* Preserve pointer nonnull computed by VRP. See get_ptr_nonnull
655438fd1498Szrj in gcc/tree-ssaname.c for more information. */
655538fd1498Szrj if (nonnull)
655638fd1498Szrj set_ptr_nonnull (p);
655738fd1498Szrj }
655838fd1498Szrj
655938fd1498Szrj
656038fd1498Szrj /* Query statistics for points-to solutions. */
656138fd1498Szrj
656238fd1498Szrj static struct {
656338fd1498Szrj unsigned HOST_WIDE_INT pt_solution_includes_may_alias;
656438fd1498Szrj unsigned HOST_WIDE_INT pt_solution_includes_no_alias;
656538fd1498Szrj unsigned HOST_WIDE_INT pt_solutions_intersect_may_alias;
656638fd1498Szrj unsigned HOST_WIDE_INT pt_solutions_intersect_no_alias;
656738fd1498Szrj } pta_stats;
656838fd1498Szrj
656938fd1498Szrj void
dump_pta_stats(FILE * s)657038fd1498Szrj dump_pta_stats (FILE *s)
657138fd1498Szrj {
657238fd1498Szrj fprintf (s, "\nPTA query stats:\n");
657338fd1498Szrj fprintf (s, " pt_solution_includes: "
657438fd1498Szrj HOST_WIDE_INT_PRINT_DEC" disambiguations, "
657538fd1498Szrj HOST_WIDE_INT_PRINT_DEC" queries\n",
657638fd1498Szrj pta_stats.pt_solution_includes_no_alias,
657738fd1498Szrj pta_stats.pt_solution_includes_no_alias
657838fd1498Szrj + pta_stats.pt_solution_includes_may_alias);
657938fd1498Szrj fprintf (s, " pt_solutions_intersect: "
658038fd1498Szrj HOST_WIDE_INT_PRINT_DEC" disambiguations, "
658138fd1498Szrj HOST_WIDE_INT_PRINT_DEC" queries\n",
658238fd1498Szrj pta_stats.pt_solutions_intersect_no_alias,
658338fd1498Szrj pta_stats.pt_solutions_intersect_no_alias
658438fd1498Szrj + pta_stats.pt_solutions_intersect_may_alias);
658538fd1498Szrj }
658638fd1498Szrj
658738fd1498Szrj
658838fd1498Szrj /* Reset the points-to solution *PT to a conservative default
658938fd1498Szrj (point to anything). */
659038fd1498Szrj
659138fd1498Szrj void
pt_solution_reset(struct pt_solution * pt)659238fd1498Szrj pt_solution_reset (struct pt_solution *pt)
659338fd1498Szrj {
659438fd1498Szrj memset (pt, 0, sizeof (struct pt_solution));
659538fd1498Szrj pt->anything = true;
659638fd1498Szrj pt->null = true;
659738fd1498Szrj }
659838fd1498Szrj
659938fd1498Szrj /* Set the points-to solution *PT to point only to the variables
660038fd1498Szrj in VARS. VARS_CONTAINS_GLOBAL specifies whether that contains
660138fd1498Szrj global variables and VARS_CONTAINS_RESTRICT specifies whether
660238fd1498Szrj it contains restrict tag variables. */
660338fd1498Szrj
660438fd1498Szrj void
pt_solution_set(struct pt_solution * pt,bitmap vars,bool vars_contains_nonlocal)660538fd1498Szrj pt_solution_set (struct pt_solution *pt, bitmap vars,
660638fd1498Szrj bool vars_contains_nonlocal)
660738fd1498Szrj {
660838fd1498Szrj memset (pt, 0, sizeof (struct pt_solution));
660938fd1498Szrj pt->vars = vars;
661038fd1498Szrj pt->vars_contains_nonlocal = vars_contains_nonlocal;
661138fd1498Szrj pt->vars_contains_escaped
661238fd1498Szrj = (cfun->gimple_df->escaped.anything
661338fd1498Szrj || bitmap_intersect_p (cfun->gimple_df->escaped.vars, vars));
661438fd1498Szrj }
661538fd1498Szrj
661638fd1498Szrj /* Set the points-to solution *PT to point only to the variable VAR. */
661738fd1498Szrj
661838fd1498Szrj void
pt_solution_set_var(struct pt_solution * pt,tree var)661938fd1498Szrj pt_solution_set_var (struct pt_solution *pt, tree var)
662038fd1498Szrj {
662138fd1498Szrj memset (pt, 0, sizeof (struct pt_solution));
662238fd1498Szrj pt->vars = BITMAP_GGC_ALLOC ();
662338fd1498Szrj bitmap_set_bit (pt->vars, DECL_PT_UID (var));
662438fd1498Szrj pt->vars_contains_nonlocal = is_global_var (var);
662538fd1498Szrj pt->vars_contains_escaped
662638fd1498Szrj = (cfun->gimple_df->escaped.anything
662738fd1498Szrj || bitmap_bit_p (cfun->gimple_df->escaped.vars, DECL_PT_UID (var)));
662838fd1498Szrj }
662938fd1498Szrj
663038fd1498Szrj /* Computes the union of the points-to solutions *DEST and *SRC and
663138fd1498Szrj stores the result in *DEST. This changes the points-to bitmap
663238fd1498Szrj of *DEST and thus may not be used if that might be shared.
663338fd1498Szrj The points-to bitmap of *SRC and *DEST will not be shared after
663438fd1498Szrj this function if they were not before. */
663538fd1498Szrj
663638fd1498Szrj static void
pt_solution_ior_into(struct pt_solution * dest,struct pt_solution * src)663738fd1498Szrj pt_solution_ior_into (struct pt_solution *dest, struct pt_solution *src)
663838fd1498Szrj {
663938fd1498Szrj dest->anything |= src->anything;
664038fd1498Szrj if (dest->anything)
664138fd1498Szrj {
664238fd1498Szrj pt_solution_reset (dest);
664338fd1498Szrj return;
664438fd1498Szrj }
664538fd1498Szrj
664638fd1498Szrj dest->nonlocal |= src->nonlocal;
664738fd1498Szrj dest->escaped |= src->escaped;
664838fd1498Szrj dest->ipa_escaped |= src->ipa_escaped;
664938fd1498Szrj dest->null |= src->null;
665038fd1498Szrj dest->vars_contains_nonlocal |= src->vars_contains_nonlocal;
665138fd1498Szrj dest->vars_contains_escaped |= src->vars_contains_escaped;
665238fd1498Szrj dest->vars_contains_escaped_heap |= src->vars_contains_escaped_heap;
665338fd1498Szrj if (!src->vars)
665438fd1498Szrj return;
665538fd1498Szrj
665638fd1498Szrj if (!dest->vars)
665738fd1498Szrj dest->vars = BITMAP_GGC_ALLOC ();
665838fd1498Szrj bitmap_ior_into (dest->vars, src->vars);
665938fd1498Szrj }
666038fd1498Szrj
666138fd1498Szrj /* Return true if the points-to solution *PT is empty. */
666238fd1498Szrj
666338fd1498Szrj bool
pt_solution_empty_p(struct pt_solution * pt)666438fd1498Szrj pt_solution_empty_p (struct pt_solution *pt)
666538fd1498Szrj {
666638fd1498Szrj if (pt->anything
666738fd1498Szrj || pt->nonlocal)
666838fd1498Szrj return false;
666938fd1498Szrj
667038fd1498Szrj if (pt->vars
667138fd1498Szrj && !bitmap_empty_p (pt->vars))
667238fd1498Szrj return false;
667338fd1498Szrj
667438fd1498Szrj /* If the solution includes ESCAPED, check if that is empty. */
667538fd1498Szrj if (pt->escaped
667638fd1498Szrj && !pt_solution_empty_p (&cfun->gimple_df->escaped))
667738fd1498Szrj return false;
667838fd1498Szrj
667938fd1498Szrj /* If the solution includes ESCAPED, check if that is empty. */
668038fd1498Szrj if (pt->ipa_escaped
668138fd1498Szrj && !pt_solution_empty_p (&ipa_escaped_pt))
668238fd1498Szrj return false;
668338fd1498Szrj
668438fd1498Szrj return true;
668538fd1498Szrj }
668638fd1498Szrj
668738fd1498Szrj /* Return true if the points-to solution *PT only point to a single var, and
668838fd1498Szrj return the var uid in *UID. */
668938fd1498Szrj
669038fd1498Szrj bool
pt_solution_singleton_or_null_p(struct pt_solution * pt,unsigned * uid)669138fd1498Szrj pt_solution_singleton_or_null_p (struct pt_solution *pt, unsigned *uid)
669238fd1498Szrj {
669338fd1498Szrj if (pt->anything || pt->nonlocal || pt->escaped || pt->ipa_escaped
669438fd1498Szrj || pt->vars == NULL
669538fd1498Szrj || !bitmap_single_bit_set_p (pt->vars))
669638fd1498Szrj return false;
669738fd1498Szrj
669838fd1498Szrj *uid = bitmap_first_set_bit (pt->vars);
669938fd1498Szrj return true;
670038fd1498Szrj }
670138fd1498Szrj
670238fd1498Szrj /* Return true if the points-to solution *PT includes global memory. */
670338fd1498Szrj
670438fd1498Szrj bool
pt_solution_includes_global(struct pt_solution * pt)670538fd1498Szrj pt_solution_includes_global (struct pt_solution *pt)
670638fd1498Szrj {
670738fd1498Szrj if (pt->anything
670838fd1498Szrj || pt->nonlocal
670938fd1498Szrj || pt->vars_contains_nonlocal
671038fd1498Szrj /* The following is a hack to make the malloc escape hack work.
671138fd1498Szrj In reality we'd need different sets for escaped-through-return
671238fd1498Szrj and escaped-to-callees and passes would need to be updated. */
671338fd1498Szrj || pt->vars_contains_escaped_heap)
671438fd1498Szrj return true;
671538fd1498Szrj
671638fd1498Szrj /* 'escaped' is also a placeholder so we have to look into it. */
671738fd1498Szrj if (pt->escaped)
671838fd1498Szrj return pt_solution_includes_global (&cfun->gimple_df->escaped);
671938fd1498Szrj
672038fd1498Szrj if (pt->ipa_escaped)
672138fd1498Szrj return pt_solution_includes_global (&ipa_escaped_pt);
672238fd1498Szrj
672338fd1498Szrj return false;
672438fd1498Szrj }
672538fd1498Szrj
672638fd1498Szrj /* Return true if the points-to solution *PT includes the variable
672738fd1498Szrj declaration DECL. */
672838fd1498Szrj
672938fd1498Szrj static bool
pt_solution_includes_1(struct pt_solution * pt,const_tree decl)673038fd1498Szrj pt_solution_includes_1 (struct pt_solution *pt, const_tree decl)
673138fd1498Szrj {
673238fd1498Szrj if (pt->anything)
673338fd1498Szrj return true;
673438fd1498Szrj
673538fd1498Szrj if (pt->nonlocal
673638fd1498Szrj && is_global_var (decl))
673738fd1498Szrj return true;
673838fd1498Szrj
673938fd1498Szrj if (pt->vars
674038fd1498Szrj && bitmap_bit_p (pt->vars, DECL_PT_UID (decl)))
674138fd1498Szrj return true;
674238fd1498Szrj
674338fd1498Szrj /* If the solution includes ESCAPED, check it. */
674438fd1498Szrj if (pt->escaped
674538fd1498Szrj && pt_solution_includes_1 (&cfun->gimple_df->escaped, decl))
674638fd1498Szrj return true;
674738fd1498Szrj
674838fd1498Szrj /* If the solution includes ESCAPED, check it. */
674938fd1498Szrj if (pt->ipa_escaped
675038fd1498Szrj && pt_solution_includes_1 (&ipa_escaped_pt, decl))
675138fd1498Szrj return true;
675238fd1498Szrj
675338fd1498Szrj return false;
675438fd1498Szrj }
675538fd1498Szrj
675638fd1498Szrj bool
pt_solution_includes(struct pt_solution * pt,const_tree decl)675738fd1498Szrj pt_solution_includes (struct pt_solution *pt, const_tree decl)
675838fd1498Szrj {
675938fd1498Szrj bool res = pt_solution_includes_1 (pt, decl);
676038fd1498Szrj if (res)
676138fd1498Szrj ++pta_stats.pt_solution_includes_may_alias;
676238fd1498Szrj else
676338fd1498Szrj ++pta_stats.pt_solution_includes_no_alias;
676438fd1498Szrj return res;
676538fd1498Szrj }
676638fd1498Szrj
676738fd1498Szrj /* Return true if both points-to solutions PT1 and PT2 have a non-empty
676838fd1498Szrj intersection. */
676938fd1498Szrj
677038fd1498Szrj static bool
pt_solutions_intersect_1(struct pt_solution * pt1,struct pt_solution * pt2)677138fd1498Szrj pt_solutions_intersect_1 (struct pt_solution *pt1, struct pt_solution *pt2)
677238fd1498Szrj {
677338fd1498Szrj if (pt1->anything || pt2->anything)
677438fd1498Szrj return true;
677538fd1498Szrj
677638fd1498Szrj /* If either points to unknown global memory and the other points to
677738fd1498Szrj any global memory they alias. */
677838fd1498Szrj if ((pt1->nonlocal
677938fd1498Szrj && (pt2->nonlocal
678038fd1498Szrj || pt2->vars_contains_nonlocal))
678138fd1498Szrj || (pt2->nonlocal
678238fd1498Szrj && pt1->vars_contains_nonlocal))
678338fd1498Szrj return true;
678438fd1498Szrj
678538fd1498Szrj /* If either points to all escaped memory and the other points to
678638fd1498Szrj any escaped memory they alias. */
678738fd1498Szrj if ((pt1->escaped
678838fd1498Szrj && (pt2->escaped
678938fd1498Szrj || pt2->vars_contains_escaped))
679038fd1498Szrj || (pt2->escaped
679138fd1498Szrj && pt1->vars_contains_escaped))
679238fd1498Szrj return true;
679338fd1498Szrj
679438fd1498Szrj /* Check the escaped solution if required.
679538fd1498Szrj ??? Do we need to check the local against the IPA escaped sets? */
679638fd1498Szrj if ((pt1->ipa_escaped || pt2->ipa_escaped)
679738fd1498Szrj && !pt_solution_empty_p (&ipa_escaped_pt))
679838fd1498Szrj {
679938fd1498Szrj /* If both point to escaped memory and that solution
680038fd1498Szrj is not empty they alias. */
680138fd1498Szrj if (pt1->ipa_escaped && pt2->ipa_escaped)
680238fd1498Szrj return true;
680338fd1498Szrj
680438fd1498Szrj /* If either points to escaped memory see if the escaped solution
680538fd1498Szrj intersects with the other. */
680638fd1498Szrj if ((pt1->ipa_escaped
680738fd1498Szrj && pt_solutions_intersect_1 (&ipa_escaped_pt, pt2))
680838fd1498Szrj || (pt2->ipa_escaped
680938fd1498Szrj && pt_solutions_intersect_1 (&ipa_escaped_pt, pt1)))
681038fd1498Szrj return true;
681138fd1498Szrj }
681238fd1498Szrj
681338fd1498Szrj /* Now both pointers alias if their points-to solution intersects. */
681438fd1498Szrj return (pt1->vars
681538fd1498Szrj && pt2->vars
681638fd1498Szrj && bitmap_intersect_p (pt1->vars, pt2->vars));
681738fd1498Szrj }
681838fd1498Szrj
681938fd1498Szrj bool
pt_solutions_intersect(struct pt_solution * pt1,struct pt_solution * pt2)682038fd1498Szrj pt_solutions_intersect (struct pt_solution *pt1, struct pt_solution *pt2)
682138fd1498Szrj {
682238fd1498Szrj bool res = pt_solutions_intersect_1 (pt1, pt2);
682338fd1498Szrj if (res)
682438fd1498Szrj ++pta_stats.pt_solutions_intersect_may_alias;
682538fd1498Szrj else
682638fd1498Szrj ++pta_stats.pt_solutions_intersect_no_alias;
682738fd1498Szrj return res;
682838fd1498Szrj }
682938fd1498Szrj
683038fd1498Szrj
683138fd1498Szrj /* Dump points-to information to OUTFILE. */
683238fd1498Szrj
683338fd1498Szrj static void
dump_sa_points_to_info(FILE * outfile)683438fd1498Szrj dump_sa_points_to_info (FILE *outfile)
683538fd1498Szrj {
683638fd1498Szrj unsigned int i;
683738fd1498Szrj
683838fd1498Szrj fprintf (outfile, "\nPoints-to sets\n\n");
683938fd1498Szrj
684038fd1498Szrj if (dump_flags & TDF_STATS)
684138fd1498Szrj {
684238fd1498Szrj fprintf (outfile, "Stats:\n");
684338fd1498Szrj fprintf (outfile, "Total vars: %d\n", stats.total_vars);
684438fd1498Szrj fprintf (outfile, "Non-pointer vars: %d\n",
684538fd1498Szrj stats.nonpointer_vars);
684638fd1498Szrj fprintf (outfile, "Statically unified vars: %d\n",
684738fd1498Szrj stats.unified_vars_static);
684838fd1498Szrj fprintf (outfile, "Dynamically unified vars: %d\n",
684938fd1498Szrj stats.unified_vars_dynamic);
685038fd1498Szrj fprintf (outfile, "Iterations: %d\n", stats.iterations);
685138fd1498Szrj fprintf (outfile, "Number of edges: %d\n", stats.num_edges);
685238fd1498Szrj fprintf (outfile, "Number of implicit edges: %d\n",
685338fd1498Szrj stats.num_implicit_edges);
685438fd1498Szrj }
685538fd1498Szrj
685638fd1498Szrj for (i = 1; i < varmap.length (); i++)
685738fd1498Szrj {
685838fd1498Szrj varinfo_t vi = get_varinfo (i);
685938fd1498Szrj if (!vi->may_have_pointers)
686038fd1498Szrj continue;
686138fd1498Szrj dump_solution_for_var (outfile, i);
686238fd1498Szrj }
686338fd1498Szrj }
686438fd1498Szrj
686538fd1498Szrj
686638fd1498Szrj /* Debug points-to information to stderr. */
686738fd1498Szrj
686838fd1498Szrj DEBUG_FUNCTION void
debug_sa_points_to_info(void)686938fd1498Szrj debug_sa_points_to_info (void)
687038fd1498Szrj {
687138fd1498Szrj dump_sa_points_to_info (stderr);
687238fd1498Szrj }
687338fd1498Szrj
687438fd1498Szrj
687538fd1498Szrj /* Initialize the always-existing constraint variables for NULL
687638fd1498Szrj ANYTHING, READONLY, and INTEGER */
687738fd1498Szrj
687838fd1498Szrj static void
init_base_vars(void)687938fd1498Szrj init_base_vars (void)
688038fd1498Szrj {
688138fd1498Szrj struct constraint_expr lhs, rhs;
688238fd1498Szrj varinfo_t var_anything;
688338fd1498Szrj varinfo_t var_nothing;
688438fd1498Szrj varinfo_t var_string;
688538fd1498Szrj varinfo_t var_escaped;
688638fd1498Szrj varinfo_t var_nonlocal;
688738fd1498Szrj varinfo_t var_storedanything;
688838fd1498Szrj varinfo_t var_integer;
688938fd1498Szrj
689038fd1498Szrj /* Variable ID zero is reserved and should be NULL. */
689138fd1498Szrj varmap.safe_push (NULL);
689238fd1498Szrj
689338fd1498Szrj /* Create the NULL variable, used to represent that a variable points
689438fd1498Szrj to NULL. */
689538fd1498Szrj var_nothing = new_var_info (NULL_TREE, "NULL", false);
689638fd1498Szrj gcc_assert (var_nothing->id == nothing_id);
689738fd1498Szrj var_nothing->is_artificial_var = 1;
689838fd1498Szrj var_nothing->offset = 0;
689938fd1498Szrj var_nothing->size = ~0;
690038fd1498Szrj var_nothing->fullsize = ~0;
690138fd1498Szrj var_nothing->is_special_var = 1;
690238fd1498Szrj var_nothing->may_have_pointers = 0;
690338fd1498Szrj var_nothing->is_global_var = 0;
690438fd1498Szrj
690538fd1498Szrj /* Create the ANYTHING variable, used to represent that a variable
690638fd1498Szrj points to some unknown piece of memory. */
690738fd1498Szrj var_anything = new_var_info (NULL_TREE, "ANYTHING", false);
690838fd1498Szrj gcc_assert (var_anything->id == anything_id);
690938fd1498Szrj var_anything->is_artificial_var = 1;
691038fd1498Szrj var_anything->size = ~0;
691138fd1498Szrj var_anything->offset = 0;
691238fd1498Szrj var_anything->fullsize = ~0;
691338fd1498Szrj var_anything->is_special_var = 1;
691438fd1498Szrj
691538fd1498Szrj /* Anything points to anything. This makes deref constraints just
691638fd1498Szrj work in the presence of linked list and other p = *p type loops,
691738fd1498Szrj by saying that *ANYTHING = ANYTHING. */
691838fd1498Szrj lhs.type = SCALAR;
691938fd1498Szrj lhs.var = anything_id;
692038fd1498Szrj lhs.offset = 0;
692138fd1498Szrj rhs.type = ADDRESSOF;
692238fd1498Szrj rhs.var = anything_id;
692338fd1498Szrj rhs.offset = 0;
692438fd1498Szrj
692538fd1498Szrj /* This specifically does not use process_constraint because
692638fd1498Szrj process_constraint ignores all anything = anything constraints, since all
692738fd1498Szrj but this one are redundant. */
692838fd1498Szrj constraints.safe_push (new_constraint (lhs, rhs));
692938fd1498Szrj
693038fd1498Szrj /* Create the STRING variable, used to represent that a variable
693138fd1498Szrj points to a string literal. String literals don't contain
693238fd1498Szrj pointers so STRING doesn't point to anything. */
693338fd1498Szrj var_string = new_var_info (NULL_TREE, "STRING", false);
693438fd1498Szrj gcc_assert (var_string->id == string_id);
693538fd1498Szrj var_string->is_artificial_var = 1;
693638fd1498Szrj var_string->offset = 0;
693738fd1498Szrj var_string->size = ~0;
693838fd1498Szrj var_string->fullsize = ~0;
693938fd1498Szrj var_string->is_special_var = 1;
694038fd1498Szrj var_string->may_have_pointers = 0;
694138fd1498Szrj
694238fd1498Szrj /* Create the ESCAPED variable, used to represent the set of escaped
694338fd1498Szrj memory. */
694438fd1498Szrj var_escaped = new_var_info (NULL_TREE, "ESCAPED", false);
694538fd1498Szrj gcc_assert (var_escaped->id == escaped_id);
694638fd1498Szrj var_escaped->is_artificial_var = 1;
694738fd1498Szrj var_escaped->offset = 0;
694838fd1498Szrj var_escaped->size = ~0;
694938fd1498Szrj var_escaped->fullsize = ~0;
695038fd1498Szrj var_escaped->is_special_var = 0;
695138fd1498Szrj
695238fd1498Szrj /* Create the NONLOCAL variable, used to represent the set of nonlocal
695338fd1498Szrj memory. */
695438fd1498Szrj var_nonlocal = new_var_info (NULL_TREE, "NONLOCAL", false);
695538fd1498Szrj gcc_assert (var_nonlocal->id == nonlocal_id);
695638fd1498Szrj var_nonlocal->is_artificial_var = 1;
695738fd1498Szrj var_nonlocal->offset = 0;
695838fd1498Szrj var_nonlocal->size = ~0;
695938fd1498Szrj var_nonlocal->fullsize = ~0;
696038fd1498Szrj var_nonlocal->is_special_var = 1;
696138fd1498Szrj
696238fd1498Szrj /* ESCAPED = *ESCAPED, because escaped is may-deref'd at calls, etc. */
696338fd1498Szrj lhs.type = SCALAR;
696438fd1498Szrj lhs.var = escaped_id;
696538fd1498Szrj lhs.offset = 0;
696638fd1498Szrj rhs.type = DEREF;
696738fd1498Szrj rhs.var = escaped_id;
696838fd1498Szrj rhs.offset = 0;
696938fd1498Szrj process_constraint (new_constraint (lhs, rhs));
697038fd1498Szrj
697138fd1498Szrj /* ESCAPED = ESCAPED + UNKNOWN_OFFSET, because if a sub-field escapes the
697238fd1498Szrj whole variable escapes. */
697338fd1498Szrj lhs.type = SCALAR;
697438fd1498Szrj lhs.var = escaped_id;
697538fd1498Szrj lhs.offset = 0;
697638fd1498Szrj rhs.type = SCALAR;
697738fd1498Szrj rhs.var = escaped_id;
697838fd1498Szrj rhs.offset = UNKNOWN_OFFSET;
697938fd1498Szrj process_constraint (new_constraint (lhs, rhs));
698038fd1498Szrj
698138fd1498Szrj /* *ESCAPED = NONLOCAL. This is true because we have to assume
698238fd1498Szrj everything pointed to by escaped points to what global memory can
698338fd1498Szrj point to. */
698438fd1498Szrj lhs.type = DEREF;
698538fd1498Szrj lhs.var = escaped_id;
698638fd1498Szrj lhs.offset = 0;
698738fd1498Szrj rhs.type = SCALAR;
698838fd1498Szrj rhs.var = nonlocal_id;
698938fd1498Szrj rhs.offset = 0;
699038fd1498Szrj process_constraint (new_constraint (lhs, rhs));
699138fd1498Szrj
699238fd1498Szrj /* NONLOCAL = &NONLOCAL, NONLOCAL = &ESCAPED. This is true because
699338fd1498Szrj global memory may point to global memory and escaped memory. */
699438fd1498Szrj lhs.type = SCALAR;
699538fd1498Szrj lhs.var = nonlocal_id;
699638fd1498Szrj lhs.offset = 0;
699738fd1498Szrj rhs.type = ADDRESSOF;
699838fd1498Szrj rhs.var = nonlocal_id;
699938fd1498Szrj rhs.offset = 0;
700038fd1498Szrj process_constraint (new_constraint (lhs, rhs));
700138fd1498Szrj rhs.type = ADDRESSOF;
700238fd1498Szrj rhs.var = escaped_id;
700338fd1498Szrj rhs.offset = 0;
700438fd1498Szrj process_constraint (new_constraint (lhs, rhs));
700538fd1498Szrj
700638fd1498Szrj /* Create the STOREDANYTHING variable, used to represent the set of
700738fd1498Szrj variables stored to *ANYTHING. */
700838fd1498Szrj var_storedanything = new_var_info (NULL_TREE, "STOREDANYTHING", false);
700938fd1498Szrj gcc_assert (var_storedanything->id == storedanything_id);
701038fd1498Szrj var_storedanything->is_artificial_var = 1;
701138fd1498Szrj var_storedanything->offset = 0;
701238fd1498Szrj var_storedanything->size = ~0;
701338fd1498Szrj var_storedanything->fullsize = ~0;
701438fd1498Szrj var_storedanything->is_special_var = 0;
701538fd1498Szrj
701638fd1498Szrj /* Create the INTEGER variable, used to represent that a variable points
701738fd1498Szrj to what an INTEGER "points to". */
701838fd1498Szrj var_integer = new_var_info (NULL_TREE, "INTEGER", false);
701938fd1498Szrj gcc_assert (var_integer->id == integer_id);
702038fd1498Szrj var_integer->is_artificial_var = 1;
702138fd1498Szrj var_integer->size = ~0;
702238fd1498Szrj var_integer->fullsize = ~0;
702338fd1498Szrj var_integer->offset = 0;
702438fd1498Szrj var_integer->is_special_var = 1;
702538fd1498Szrj
702638fd1498Szrj /* INTEGER = ANYTHING, because we don't know where a dereference of
702738fd1498Szrj a random integer will point to. */
702838fd1498Szrj lhs.type = SCALAR;
702938fd1498Szrj lhs.var = integer_id;
703038fd1498Szrj lhs.offset = 0;
703138fd1498Szrj rhs.type = ADDRESSOF;
703238fd1498Szrj rhs.var = anything_id;
703338fd1498Szrj rhs.offset = 0;
703438fd1498Szrj process_constraint (new_constraint (lhs, rhs));
703538fd1498Szrj }
703638fd1498Szrj
703738fd1498Szrj /* Initialize things necessary to perform PTA */
703838fd1498Szrj
703938fd1498Szrj static void
init_alias_vars(void)704038fd1498Szrj init_alias_vars (void)
704138fd1498Szrj {
704238fd1498Szrj use_field_sensitive = (MAX_FIELDS_FOR_FIELD_SENSITIVE > 1);
704338fd1498Szrj
704438fd1498Szrj bitmap_obstack_initialize (&pta_obstack);
704538fd1498Szrj bitmap_obstack_initialize (&oldpta_obstack);
704638fd1498Szrj bitmap_obstack_initialize (&predbitmap_obstack);
704738fd1498Szrj
704838fd1498Szrj constraints.create (8);
704938fd1498Szrj varmap.create (8);
705038fd1498Szrj vi_for_tree = new hash_map<tree, varinfo_t>;
705138fd1498Szrj call_stmt_vars = new hash_map<gimple *, varinfo_t>;
705238fd1498Szrj
705338fd1498Szrj memset (&stats, 0, sizeof (stats));
705438fd1498Szrj shared_bitmap_table = new hash_table<shared_bitmap_hasher> (511);
705538fd1498Szrj init_base_vars ();
705638fd1498Szrj
705738fd1498Szrj gcc_obstack_init (&fake_var_decl_obstack);
705838fd1498Szrj
705938fd1498Szrj final_solutions = new hash_map<varinfo_t, pt_solution *>;
706038fd1498Szrj gcc_obstack_init (&final_solutions_obstack);
706138fd1498Szrj }
706238fd1498Szrj
706338fd1498Szrj /* Remove the REF and ADDRESS edges from GRAPH, as well as all the
706438fd1498Szrj predecessor edges. */
706538fd1498Szrj
706638fd1498Szrj static void
remove_preds_and_fake_succs(constraint_graph_t graph)706738fd1498Szrj remove_preds_and_fake_succs (constraint_graph_t graph)
706838fd1498Szrj {
706938fd1498Szrj unsigned int i;
707038fd1498Szrj
707138fd1498Szrj /* Clear the implicit ref and address nodes from the successor
707238fd1498Szrj lists. */
707338fd1498Szrj for (i = 1; i < FIRST_REF_NODE; i++)
707438fd1498Szrj {
707538fd1498Szrj if (graph->succs[i])
707638fd1498Szrj bitmap_clear_range (graph->succs[i], FIRST_REF_NODE,
707738fd1498Szrj FIRST_REF_NODE * 2);
707838fd1498Szrj }
707938fd1498Szrj
708038fd1498Szrj /* Free the successor list for the non-ref nodes. */
708138fd1498Szrj for (i = FIRST_REF_NODE + 1; i < graph->size; i++)
708238fd1498Szrj {
708338fd1498Szrj if (graph->succs[i])
708438fd1498Szrj BITMAP_FREE (graph->succs[i]);
708538fd1498Szrj }
708638fd1498Szrj
708738fd1498Szrj /* Now reallocate the size of the successor list as, and blow away
708838fd1498Szrj the predecessor bitmaps. */
708938fd1498Szrj graph->size = varmap.length ();
709038fd1498Szrj graph->succs = XRESIZEVEC (bitmap, graph->succs, graph->size);
709138fd1498Szrj
709238fd1498Szrj free (graph->implicit_preds);
709338fd1498Szrj graph->implicit_preds = NULL;
709438fd1498Szrj free (graph->preds);
709538fd1498Szrj graph->preds = NULL;
709638fd1498Szrj bitmap_obstack_release (&predbitmap_obstack);
709738fd1498Szrj }
709838fd1498Szrj
709938fd1498Szrj /* Solve the constraint set. */
710038fd1498Szrj
710138fd1498Szrj static void
solve_constraints(void)710238fd1498Szrj solve_constraints (void)
710338fd1498Szrj {
710438fd1498Szrj struct scc_info *si;
710538fd1498Szrj
710638fd1498Szrj /* Sort varinfos so that ones that cannot be pointed to are last.
710738fd1498Szrj This makes bitmaps more efficient. */
710838fd1498Szrj unsigned int *map = XNEWVEC (unsigned int, varmap.length ());
710938fd1498Szrj for (unsigned i = 0; i < integer_id + 1; ++i)
711038fd1498Szrj map[i] = i;
711138fd1498Szrj /* Start with non-register vars (as possibly address-taken), followed
711238fd1498Szrj by register vars as conservative set of vars never appearing in
711338fd1498Szrj the points-to solution bitmaps. */
711438fd1498Szrj unsigned j = integer_id + 1;
711538fd1498Szrj for (unsigned i = integer_id + 1; i < varmap.length (); ++i)
711638fd1498Szrj if (! varmap[i]->is_reg_var)
711738fd1498Szrj map[i] = j++;
711838fd1498Szrj for (unsigned i = integer_id + 1; i < varmap.length (); ++i)
711938fd1498Szrj if (varmap[i]->is_reg_var)
712038fd1498Szrj map[i] = j++;
712138fd1498Szrj /* Shuffle varmap according to map. */
712238fd1498Szrj for (unsigned i = integer_id + 1; i < varmap.length (); ++i)
712338fd1498Szrj {
712438fd1498Szrj while (map[varmap[i]->id] != i)
712538fd1498Szrj std::swap (varmap[i], varmap[map[varmap[i]->id]]);
712638fd1498Szrj gcc_assert (bitmap_empty_p (varmap[i]->solution));
712738fd1498Szrj varmap[i]->id = i;
712838fd1498Szrj varmap[i]->next = map[varmap[i]->next];
712938fd1498Szrj varmap[i]->head = map[varmap[i]->head];
713038fd1498Szrj }
713138fd1498Szrj /* Finally rewrite constraints. */
713238fd1498Szrj for (unsigned i = 0; i < constraints.length (); ++i)
713338fd1498Szrj {
713438fd1498Szrj constraints[i]->lhs.var = map[constraints[i]->lhs.var];
713538fd1498Szrj constraints[i]->rhs.var = map[constraints[i]->rhs.var];
713638fd1498Szrj }
713738fd1498Szrj free (map);
713838fd1498Szrj
713938fd1498Szrj if (dump_file)
714038fd1498Szrj fprintf (dump_file,
714138fd1498Szrj "\nCollapsing static cycles and doing variable "
714238fd1498Szrj "substitution\n");
714338fd1498Szrj
714438fd1498Szrj init_graph (varmap.length () * 2);
714538fd1498Szrj
714638fd1498Szrj if (dump_file)
714738fd1498Szrj fprintf (dump_file, "Building predecessor graph\n");
714838fd1498Szrj build_pred_graph ();
714938fd1498Szrj
715038fd1498Szrj if (dump_file)
715138fd1498Szrj fprintf (dump_file, "Detecting pointer and location "
715238fd1498Szrj "equivalences\n");
715338fd1498Szrj si = perform_var_substitution (graph);
715438fd1498Szrj
715538fd1498Szrj if (dump_file)
715638fd1498Szrj fprintf (dump_file, "Rewriting constraints and unifying "
715738fd1498Szrj "variables\n");
715838fd1498Szrj rewrite_constraints (graph, si);
715938fd1498Szrj
716038fd1498Szrj build_succ_graph ();
716138fd1498Szrj
716238fd1498Szrj free_var_substitution_info (si);
716338fd1498Szrj
716438fd1498Szrj /* Attach complex constraints to graph nodes. */
716538fd1498Szrj move_complex_constraints (graph);
716638fd1498Szrj
716738fd1498Szrj if (dump_file)
716838fd1498Szrj fprintf (dump_file, "Uniting pointer but not location equivalent "
716938fd1498Szrj "variables\n");
717038fd1498Szrj unite_pointer_equivalences (graph);
717138fd1498Szrj
717238fd1498Szrj if (dump_file)
717338fd1498Szrj fprintf (dump_file, "Finding indirect cycles\n");
717438fd1498Szrj find_indirect_cycles (graph);
717538fd1498Szrj
717638fd1498Szrj /* Implicit nodes and predecessors are no longer necessary at this
717738fd1498Szrj point. */
717838fd1498Szrj remove_preds_and_fake_succs (graph);
717938fd1498Szrj
718038fd1498Szrj if (dump_file && (dump_flags & TDF_GRAPH))
718138fd1498Szrj {
718238fd1498Szrj fprintf (dump_file, "\n\n// The constraint graph before solve-graph "
718338fd1498Szrj "in dot format:\n");
718438fd1498Szrj dump_constraint_graph (dump_file);
718538fd1498Szrj fprintf (dump_file, "\n\n");
718638fd1498Szrj }
718738fd1498Szrj
718838fd1498Szrj if (dump_file)
718938fd1498Szrj fprintf (dump_file, "Solving graph\n");
719038fd1498Szrj
719138fd1498Szrj solve_graph (graph);
719238fd1498Szrj
719338fd1498Szrj if (dump_file && (dump_flags & TDF_GRAPH))
719438fd1498Szrj {
719538fd1498Szrj fprintf (dump_file, "\n\n// The constraint graph after solve-graph "
719638fd1498Szrj "in dot format:\n");
719738fd1498Szrj dump_constraint_graph (dump_file);
719838fd1498Szrj fprintf (dump_file, "\n\n");
719938fd1498Szrj }
720038fd1498Szrj
720138fd1498Szrj if (dump_file)
720238fd1498Szrj dump_sa_points_to_info (dump_file);
720338fd1498Szrj }
720438fd1498Szrj
720538fd1498Szrj /* Create points-to sets for the current function. See the comments
720638fd1498Szrj at the start of the file for an algorithmic overview. */
720738fd1498Szrj
720838fd1498Szrj static void
compute_points_to_sets(void)720938fd1498Szrj compute_points_to_sets (void)
721038fd1498Szrj {
721138fd1498Szrj basic_block bb;
721238fd1498Szrj varinfo_t vi;
721338fd1498Szrj
721438fd1498Szrj timevar_push (TV_TREE_PTA);
721538fd1498Szrj
721638fd1498Szrj init_alias_vars ();
721738fd1498Szrj
721838fd1498Szrj intra_create_variable_infos (cfun);
721938fd1498Szrj
722038fd1498Szrj /* Now walk all statements and build the constraint set. */
722138fd1498Szrj FOR_EACH_BB_FN (bb, cfun)
722238fd1498Szrj {
722338fd1498Szrj for (gphi_iterator gsi = gsi_start_phis (bb); !gsi_end_p (gsi);
722438fd1498Szrj gsi_next (&gsi))
722538fd1498Szrj {
722638fd1498Szrj gphi *phi = gsi.phi ();
722738fd1498Szrj
722838fd1498Szrj if (! virtual_operand_p (gimple_phi_result (phi)))
722938fd1498Szrj find_func_aliases (cfun, phi);
723038fd1498Szrj }
723138fd1498Szrj
723238fd1498Szrj for (gimple_stmt_iterator gsi = gsi_start_bb (bb); !gsi_end_p (gsi);
723338fd1498Szrj gsi_next (&gsi))
723438fd1498Szrj {
723538fd1498Szrj gimple *stmt = gsi_stmt (gsi);
723638fd1498Szrj
723738fd1498Szrj find_func_aliases (cfun, stmt);
723838fd1498Szrj }
723938fd1498Szrj }
724038fd1498Szrj
724138fd1498Szrj if (dump_file)
724238fd1498Szrj {
724338fd1498Szrj fprintf (dump_file, "Points-to analysis\n\nConstraints:\n\n");
724438fd1498Szrj dump_constraints (dump_file, 0);
724538fd1498Szrj }
724638fd1498Szrj
724738fd1498Szrj /* From the constraints compute the points-to sets. */
724838fd1498Szrj solve_constraints ();
724938fd1498Szrj
725038fd1498Szrj /* Compute the points-to set for ESCAPED used for call-clobber analysis. */
725138fd1498Szrj cfun->gimple_df->escaped = find_what_var_points_to (cfun->decl,
725238fd1498Szrj get_varinfo (escaped_id));
725338fd1498Szrj
725438fd1498Szrj /* Make sure the ESCAPED solution (which is used as placeholder in
725538fd1498Szrj other solutions) does not reference itself. This simplifies
725638fd1498Szrj points-to solution queries. */
725738fd1498Szrj cfun->gimple_df->escaped.escaped = 0;
725838fd1498Szrj
725938fd1498Szrj /* Compute the points-to sets for pointer SSA_NAMEs. */
726038fd1498Szrj unsigned i;
726138fd1498Szrj tree ptr;
726238fd1498Szrj
726338fd1498Szrj FOR_EACH_SSA_NAME (i, ptr, cfun)
726438fd1498Szrj {
726538fd1498Szrj if (POINTER_TYPE_P (TREE_TYPE (ptr)))
726638fd1498Szrj find_what_p_points_to (cfun->decl, ptr);
726738fd1498Szrj }
726838fd1498Szrj
726938fd1498Szrj /* Compute the call-used/clobbered sets. */
727038fd1498Szrj FOR_EACH_BB_FN (bb, cfun)
727138fd1498Szrj {
727238fd1498Szrj gimple_stmt_iterator gsi;
727338fd1498Szrj
727438fd1498Szrj for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi))
727538fd1498Szrj {
727638fd1498Szrj gcall *stmt;
727738fd1498Szrj struct pt_solution *pt;
727838fd1498Szrj
727938fd1498Szrj stmt = dyn_cast <gcall *> (gsi_stmt (gsi));
728038fd1498Szrj if (!stmt)
728138fd1498Szrj continue;
728238fd1498Szrj
728338fd1498Szrj pt = gimple_call_use_set (stmt);
728438fd1498Szrj if (gimple_call_flags (stmt) & ECF_CONST)
728538fd1498Szrj memset (pt, 0, sizeof (struct pt_solution));
728638fd1498Szrj else if ((vi = lookup_call_use_vi (stmt)) != NULL)
728738fd1498Szrj {
728838fd1498Szrj *pt = find_what_var_points_to (cfun->decl, vi);
728938fd1498Szrj /* Escaped (and thus nonlocal) variables are always
729038fd1498Szrj implicitly used by calls. */
729138fd1498Szrj /* ??? ESCAPED can be empty even though NONLOCAL
729238fd1498Szrj always escaped. */
729338fd1498Szrj pt->nonlocal = 1;
729438fd1498Szrj pt->escaped = 1;
729538fd1498Szrj }
729638fd1498Szrj else
729738fd1498Szrj {
729838fd1498Szrj /* If there is nothing special about this call then
729938fd1498Szrj we have made everything that is used also escape. */
730038fd1498Szrj *pt = cfun->gimple_df->escaped;
730138fd1498Szrj pt->nonlocal = 1;
730238fd1498Szrj }
730338fd1498Szrj
730438fd1498Szrj pt = gimple_call_clobber_set (stmt);
730538fd1498Szrj if (gimple_call_flags (stmt) & (ECF_CONST|ECF_PURE|ECF_NOVOPS))
730638fd1498Szrj memset (pt, 0, sizeof (struct pt_solution));
730738fd1498Szrj else if ((vi = lookup_call_clobber_vi (stmt)) != NULL)
730838fd1498Szrj {
730938fd1498Szrj *pt = find_what_var_points_to (cfun->decl, vi);
731038fd1498Szrj /* Escaped (and thus nonlocal) variables are always
731138fd1498Szrj implicitly clobbered by calls. */
731238fd1498Szrj /* ??? ESCAPED can be empty even though NONLOCAL
731338fd1498Szrj always escaped. */
731438fd1498Szrj pt->nonlocal = 1;
731538fd1498Szrj pt->escaped = 1;
731638fd1498Szrj }
731738fd1498Szrj else
731838fd1498Szrj {
731938fd1498Szrj /* If there is nothing special about this call then
732038fd1498Szrj we have made everything that is used also escape. */
732138fd1498Szrj *pt = cfun->gimple_df->escaped;
732238fd1498Szrj pt->nonlocal = 1;
732338fd1498Szrj }
732438fd1498Szrj }
732538fd1498Szrj }
732638fd1498Szrj
732738fd1498Szrj timevar_pop (TV_TREE_PTA);
732838fd1498Szrj }
732938fd1498Szrj
733038fd1498Szrj
733138fd1498Szrj /* Delete created points-to sets. */
733238fd1498Szrj
733338fd1498Szrj static void
delete_points_to_sets(void)733438fd1498Szrj delete_points_to_sets (void)
733538fd1498Szrj {
733638fd1498Szrj unsigned int i;
733738fd1498Szrj
733838fd1498Szrj delete shared_bitmap_table;
733938fd1498Szrj shared_bitmap_table = NULL;
734038fd1498Szrj if (dump_file && (dump_flags & TDF_STATS))
734138fd1498Szrj fprintf (dump_file, "Points to sets created:%d\n",
734238fd1498Szrj stats.points_to_sets_created);
734338fd1498Szrj
734438fd1498Szrj delete vi_for_tree;
734538fd1498Szrj delete call_stmt_vars;
734638fd1498Szrj bitmap_obstack_release (&pta_obstack);
734738fd1498Szrj constraints.release ();
734838fd1498Szrj
734938fd1498Szrj for (i = 0; i < graph->size; i++)
735038fd1498Szrj graph->complex[i].release ();
735138fd1498Szrj free (graph->complex);
735238fd1498Szrj
735338fd1498Szrj free (graph->rep);
735438fd1498Szrj free (graph->succs);
735538fd1498Szrj free (graph->pe);
735638fd1498Szrj free (graph->pe_rep);
735738fd1498Szrj free (graph->indirect_cycles);
735838fd1498Szrj free (graph);
735938fd1498Szrj
736038fd1498Szrj varmap.release ();
736138fd1498Szrj variable_info_pool.release ();
736238fd1498Szrj constraint_pool.release ();
736338fd1498Szrj
736438fd1498Szrj obstack_free (&fake_var_decl_obstack, NULL);
736538fd1498Szrj
736638fd1498Szrj delete final_solutions;
736738fd1498Szrj obstack_free (&final_solutions_obstack, NULL);
736838fd1498Szrj }
736938fd1498Szrj
737038fd1498Szrj struct vls_data
737138fd1498Szrj {
737238fd1498Szrj unsigned short clique;
737358e805e6Szrj bool escaped_p;
737438fd1498Szrj bitmap rvars;
737538fd1498Szrj };
737638fd1498Szrj
737738fd1498Szrj /* Mark "other" loads and stores as belonging to CLIQUE and with
737838fd1498Szrj base zero. */
737938fd1498Szrj
738038fd1498Szrj static bool
visit_loadstore(gimple *,tree base,tree ref,void * data)738138fd1498Szrj visit_loadstore (gimple *, tree base, tree ref, void *data)
738238fd1498Szrj {
738338fd1498Szrj unsigned short clique = ((vls_data *) data)->clique;
738438fd1498Szrj bitmap rvars = ((vls_data *) data)->rvars;
738558e805e6Szrj bool escaped_p = ((vls_data *) data)->escaped_p;
738638fd1498Szrj if (TREE_CODE (base) == MEM_REF
738738fd1498Szrj || TREE_CODE (base) == TARGET_MEM_REF)
738838fd1498Szrj {
738938fd1498Szrj tree ptr = TREE_OPERAND (base, 0);
739038fd1498Szrj if (TREE_CODE (ptr) == SSA_NAME)
739138fd1498Szrj {
739238fd1498Szrj /* For parameters, get at the points-to set for the actual parm
739338fd1498Szrj decl. */
739438fd1498Szrj if (SSA_NAME_IS_DEFAULT_DEF (ptr)
739538fd1498Szrj && (TREE_CODE (SSA_NAME_VAR (ptr)) == PARM_DECL
739638fd1498Szrj || TREE_CODE (SSA_NAME_VAR (ptr)) == RESULT_DECL))
739738fd1498Szrj ptr = SSA_NAME_VAR (ptr);
739838fd1498Szrj
739938fd1498Szrj /* We need to make sure 'ptr' doesn't include any of
740038fd1498Szrj the restrict tags we added bases for in its points-to set. */
740138fd1498Szrj varinfo_t vi = lookup_vi_for_tree (ptr);
740238fd1498Szrj if (! vi)
740338fd1498Szrj return false;
740438fd1498Szrj
740538fd1498Szrj vi = get_varinfo (find (vi->id));
740658e805e6Szrj if (bitmap_intersect_p (rvars, vi->solution)
740758e805e6Szrj || (escaped_p && bitmap_bit_p (vi->solution, escaped_id)))
740838fd1498Szrj return false;
740938fd1498Szrj }
741038fd1498Szrj
741138fd1498Szrj /* Do not overwrite existing cliques (that includes clique, base
741238fd1498Szrj pairs we just set). */
741338fd1498Szrj if (MR_DEPENDENCE_CLIQUE (base) == 0)
741438fd1498Szrj {
741538fd1498Szrj MR_DEPENDENCE_CLIQUE (base) = clique;
741638fd1498Szrj MR_DEPENDENCE_BASE (base) = 0;
741738fd1498Szrj }
741838fd1498Szrj }
741938fd1498Szrj
742038fd1498Szrj /* For plain decl accesses see whether they are accesses to globals
742138fd1498Szrj and rewrite them to MEM_REFs with { clique, 0 }. */
742238fd1498Szrj if (VAR_P (base)
742338fd1498Szrj && is_global_var (base)
742438fd1498Szrj /* ??? We can't rewrite a plain decl with the walk_stmt_load_store
742538fd1498Szrj ops callback. */
742638fd1498Szrj && base != ref)
742738fd1498Szrj {
742838fd1498Szrj tree *basep = &ref;
742938fd1498Szrj while (handled_component_p (*basep))
743038fd1498Szrj basep = &TREE_OPERAND (*basep, 0);
743138fd1498Szrj gcc_assert (VAR_P (*basep));
743238fd1498Szrj tree ptr = build_fold_addr_expr (*basep);
743338fd1498Szrj tree zero = build_int_cst (TREE_TYPE (ptr), 0);
743438fd1498Szrj *basep = build2 (MEM_REF, TREE_TYPE (*basep), ptr, zero);
743538fd1498Szrj MR_DEPENDENCE_CLIQUE (*basep) = clique;
743638fd1498Szrj MR_DEPENDENCE_BASE (*basep) = 0;
743738fd1498Szrj }
743838fd1498Szrj
743938fd1498Szrj return false;
744038fd1498Szrj }
744138fd1498Szrj
744238fd1498Szrj /* If REF is a MEM_REF then assign a clique, base pair to it, updating
744338fd1498Szrj CLIQUE, *RESTRICT_VAR and LAST_RUID. Return whether dependence info
744438fd1498Szrj was assigned to REF. */
744538fd1498Szrj
744638fd1498Szrj static bool
maybe_set_dependence_info(tree ref,tree ptr,unsigned short & clique,varinfo_t restrict_var,unsigned short & last_ruid)744738fd1498Szrj maybe_set_dependence_info (tree ref, tree ptr,
744838fd1498Szrj unsigned short &clique, varinfo_t restrict_var,
744938fd1498Szrj unsigned short &last_ruid)
745038fd1498Szrj {
745138fd1498Szrj while (handled_component_p (ref))
745238fd1498Szrj ref = TREE_OPERAND (ref, 0);
745338fd1498Szrj if ((TREE_CODE (ref) == MEM_REF
745438fd1498Szrj || TREE_CODE (ref) == TARGET_MEM_REF)
745538fd1498Szrj && TREE_OPERAND (ref, 0) == ptr)
745638fd1498Szrj {
745738fd1498Szrj /* Do not overwrite existing cliques. This avoids overwriting dependence
745838fd1498Szrj info inlined from a function with restrict parameters inlined
745938fd1498Szrj into a function with restrict parameters. This usually means we
746038fd1498Szrj prefer to be precise in innermost loops. */
746138fd1498Szrj if (MR_DEPENDENCE_CLIQUE (ref) == 0)
746238fd1498Szrj {
746338fd1498Szrj if (clique == 0)
746438fd1498Szrj clique = ++cfun->last_clique;
746538fd1498Szrj if (restrict_var->ruid == 0)
746638fd1498Szrj restrict_var->ruid = ++last_ruid;
746738fd1498Szrj MR_DEPENDENCE_CLIQUE (ref) = clique;
746838fd1498Szrj MR_DEPENDENCE_BASE (ref) = restrict_var->ruid;
746938fd1498Szrj return true;
747038fd1498Szrj }
747138fd1498Szrj }
747238fd1498Szrj return false;
747338fd1498Szrj }
747438fd1498Szrj
747538fd1498Szrj /* Compute the set of independend memory references based on restrict
747638fd1498Szrj tags and their conservative propagation to the points-to sets. */
747738fd1498Szrj
747838fd1498Szrj static void
compute_dependence_clique(void)747938fd1498Szrj compute_dependence_clique (void)
748038fd1498Szrj {
748138fd1498Szrj unsigned short clique = 0;
748238fd1498Szrj unsigned short last_ruid = 0;
748338fd1498Szrj bitmap rvars = BITMAP_ALLOC (NULL);
748458e805e6Szrj bool escaped_p = false;
748538fd1498Szrj for (unsigned i = 0; i < num_ssa_names; ++i)
748638fd1498Szrj {
748738fd1498Szrj tree ptr = ssa_name (i);
748838fd1498Szrj if (!ptr || !POINTER_TYPE_P (TREE_TYPE (ptr)))
748938fd1498Szrj continue;
749038fd1498Szrj
749138fd1498Szrj /* Avoid all this when ptr is not dereferenced? */
749238fd1498Szrj tree p = ptr;
749338fd1498Szrj if (SSA_NAME_IS_DEFAULT_DEF (ptr)
749438fd1498Szrj && (TREE_CODE (SSA_NAME_VAR (ptr)) == PARM_DECL
749538fd1498Szrj || TREE_CODE (SSA_NAME_VAR (ptr)) == RESULT_DECL))
749638fd1498Szrj p = SSA_NAME_VAR (ptr);
749738fd1498Szrj varinfo_t vi = lookup_vi_for_tree (p);
749838fd1498Szrj if (!vi)
749938fd1498Szrj continue;
750038fd1498Szrj vi = get_varinfo (find (vi->id));
750138fd1498Szrj bitmap_iterator bi;
750238fd1498Szrj unsigned j;
750338fd1498Szrj varinfo_t restrict_var = NULL;
750438fd1498Szrj EXECUTE_IF_SET_IN_BITMAP (vi->solution, 0, j, bi)
750538fd1498Szrj {
750638fd1498Szrj varinfo_t oi = get_varinfo (j);
750738fd1498Szrj if (oi->is_restrict_var)
750838fd1498Szrj {
750938fd1498Szrj if (restrict_var)
751038fd1498Szrj {
751138fd1498Szrj if (dump_file && (dump_flags & TDF_DETAILS))
751238fd1498Szrj {
751338fd1498Szrj fprintf (dump_file, "found restrict pointed-to "
751438fd1498Szrj "for ");
751538fd1498Szrj print_generic_expr (dump_file, ptr);
751638fd1498Szrj fprintf (dump_file, " but not exclusively\n");
751738fd1498Szrj }
751838fd1498Szrj restrict_var = NULL;
751938fd1498Szrj break;
752038fd1498Szrj }
752138fd1498Szrj restrict_var = oi;
752238fd1498Szrj }
752338fd1498Szrj /* NULL is the only other valid points-to entry. */
752438fd1498Szrj else if (oi->id != nothing_id)
752538fd1498Szrj {
752638fd1498Szrj restrict_var = NULL;
752738fd1498Szrj break;
752838fd1498Szrj }
752938fd1498Szrj }
753038fd1498Szrj /* Ok, found that ptr must(!) point to a single(!) restrict
753138fd1498Szrj variable. */
753238fd1498Szrj /* ??? PTA isn't really a proper propagation engine to compute
753338fd1498Szrj this property.
753438fd1498Szrj ??? We could handle merging of two restricts by unifying them. */
753538fd1498Szrj if (restrict_var)
753638fd1498Szrj {
753738fd1498Szrj /* Now look at possible dereferences of ptr. */
753838fd1498Szrj imm_use_iterator ui;
753938fd1498Szrj gimple *use_stmt;
754038fd1498Szrj bool used = false;
754138fd1498Szrj FOR_EACH_IMM_USE_STMT (use_stmt, ui, ptr)
754238fd1498Szrj {
754338fd1498Szrj /* ??? Calls and asms. */
754438fd1498Szrj if (!gimple_assign_single_p (use_stmt))
754538fd1498Szrj continue;
754638fd1498Szrj used |= maybe_set_dependence_info (gimple_assign_lhs (use_stmt),
754738fd1498Szrj ptr, clique, restrict_var,
754838fd1498Szrj last_ruid);
754938fd1498Szrj used |= maybe_set_dependence_info (gimple_assign_rhs1 (use_stmt),
755038fd1498Szrj ptr, clique, restrict_var,
755138fd1498Szrj last_ruid);
755238fd1498Szrj }
755338fd1498Szrj if (used)
755458e805e6Szrj {
7555*e215fc28Szrj /* Add all subvars to the set of restrict pointed-to set. */
7556*e215fc28Szrj for (unsigned sv = restrict_var->head; sv != 0;
7557*e215fc28Szrj sv = get_varinfo (sv)->next)
7558*e215fc28Szrj bitmap_set_bit (rvars, sv);
755958e805e6Szrj varinfo_t escaped = get_varinfo (find (escaped_id));
756058e805e6Szrj if (bitmap_bit_p (escaped->solution, restrict_var->id))
756158e805e6Szrj escaped_p = true;
756258e805e6Szrj }
756338fd1498Szrj }
756438fd1498Szrj }
756538fd1498Szrj
756638fd1498Szrj if (clique != 0)
756738fd1498Szrj {
756838fd1498Szrj /* Assign the BASE id zero to all accesses not based on a restrict
756938fd1498Szrj pointer. That way they get disambiguated against restrict
757038fd1498Szrj accesses but not against each other. */
757138fd1498Szrj /* ??? For restricts derived from globals (thus not incoming
757238fd1498Szrj parameters) we can't restrict scoping properly thus the following
757338fd1498Szrj is too aggressive there. For now we have excluded those globals from
757438fd1498Szrj getting into the MR_DEPENDENCE machinery. */
757558e805e6Szrj vls_data data = { clique, escaped_p, rvars };
757638fd1498Szrj basic_block bb;
757738fd1498Szrj FOR_EACH_BB_FN (bb, cfun)
757838fd1498Szrj for (gimple_stmt_iterator gsi = gsi_start_bb (bb);
757938fd1498Szrj !gsi_end_p (gsi); gsi_next (&gsi))
758038fd1498Szrj {
758138fd1498Szrj gimple *stmt = gsi_stmt (gsi);
758238fd1498Szrj walk_stmt_load_store_ops (stmt, &data,
758338fd1498Szrj visit_loadstore, visit_loadstore);
758438fd1498Szrj }
758538fd1498Szrj }
758638fd1498Szrj
758738fd1498Szrj BITMAP_FREE (rvars);
758838fd1498Szrj }
758938fd1498Szrj
759038fd1498Szrj /* Compute points-to information for every SSA_NAME pointer in the
759138fd1498Szrj current function and compute the transitive closure of escaped
759238fd1498Szrj variables to re-initialize the call-clobber states of local variables. */
759338fd1498Szrj
759438fd1498Szrj unsigned int
compute_may_aliases(void)759538fd1498Szrj compute_may_aliases (void)
759638fd1498Szrj {
759738fd1498Szrj if (cfun->gimple_df->ipa_pta)
759838fd1498Szrj {
759938fd1498Szrj if (dump_file)
760038fd1498Szrj {
760138fd1498Szrj fprintf (dump_file, "\nNot re-computing points-to information "
760238fd1498Szrj "because IPA points-to information is available.\n\n");
760338fd1498Szrj
760438fd1498Szrj /* But still dump what we have remaining it. */
760538fd1498Szrj dump_alias_info (dump_file);
760638fd1498Szrj }
760738fd1498Szrj
760838fd1498Szrj return 0;
760938fd1498Szrj }
761038fd1498Szrj
761138fd1498Szrj /* For each pointer P_i, determine the sets of variables that P_i may
761238fd1498Szrj point-to. Compute the reachability set of escaped and call-used
761338fd1498Szrj variables. */
761438fd1498Szrj compute_points_to_sets ();
761538fd1498Szrj
761638fd1498Szrj /* Debugging dumps. */
761738fd1498Szrj if (dump_file)
761838fd1498Szrj dump_alias_info (dump_file);
761938fd1498Szrj
762038fd1498Szrj /* Compute restrict-based memory disambiguations. */
762138fd1498Szrj compute_dependence_clique ();
762238fd1498Szrj
762338fd1498Szrj /* Deallocate memory used by aliasing data structures and the internal
762438fd1498Szrj points-to solution. */
762538fd1498Szrj delete_points_to_sets ();
762638fd1498Szrj
762738fd1498Szrj gcc_assert (!need_ssa_update_p (cfun));
762838fd1498Szrj
762938fd1498Szrj return 0;
763038fd1498Szrj }
763138fd1498Szrj
763238fd1498Szrj /* A dummy pass to cause points-to information to be computed via
763338fd1498Szrj TODO_rebuild_alias. */
763438fd1498Szrj
763538fd1498Szrj namespace {
763638fd1498Szrj
763738fd1498Szrj const pass_data pass_data_build_alias =
763838fd1498Szrj {
763938fd1498Szrj GIMPLE_PASS, /* type */
764038fd1498Szrj "alias", /* name */
764138fd1498Szrj OPTGROUP_NONE, /* optinfo_flags */
764238fd1498Szrj TV_NONE, /* tv_id */
764338fd1498Szrj ( PROP_cfg | PROP_ssa ), /* properties_required */
764438fd1498Szrj 0, /* properties_provided */
764538fd1498Szrj 0, /* properties_destroyed */
764638fd1498Szrj 0, /* todo_flags_start */
764738fd1498Szrj TODO_rebuild_alias, /* todo_flags_finish */
764838fd1498Szrj };
764938fd1498Szrj
765038fd1498Szrj class pass_build_alias : public gimple_opt_pass
765138fd1498Szrj {
765238fd1498Szrj public:
pass_build_alias(gcc::context * ctxt)765338fd1498Szrj pass_build_alias (gcc::context *ctxt)
765438fd1498Szrj : gimple_opt_pass (pass_data_build_alias, ctxt)
765538fd1498Szrj {}
765638fd1498Szrj
765738fd1498Szrj /* opt_pass methods: */
gate(function *)765838fd1498Szrj virtual bool gate (function *) { return flag_tree_pta; }
765938fd1498Szrj
766038fd1498Szrj }; // class pass_build_alias
766138fd1498Szrj
766238fd1498Szrj } // anon namespace
766338fd1498Szrj
766438fd1498Szrj gimple_opt_pass *
make_pass_build_alias(gcc::context * ctxt)766538fd1498Szrj make_pass_build_alias (gcc::context *ctxt)
766638fd1498Szrj {
766738fd1498Szrj return new pass_build_alias (ctxt);
766838fd1498Szrj }
766938fd1498Szrj
767038fd1498Szrj /* A dummy pass to cause points-to information to be computed via
767138fd1498Szrj TODO_rebuild_alias. */
767238fd1498Szrj
767338fd1498Szrj namespace {
767438fd1498Szrj
767538fd1498Szrj const pass_data pass_data_build_ealias =
767638fd1498Szrj {
767738fd1498Szrj GIMPLE_PASS, /* type */
767838fd1498Szrj "ealias", /* name */
767938fd1498Szrj OPTGROUP_NONE, /* optinfo_flags */
768038fd1498Szrj TV_NONE, /* tv_id */
768138fd1498Szrj ( PROP_cfg | PROP_ssa ), /* properties_required */
768238fd1498Szrj 0, /* properties_provided */
768338fd1498Szrj 0, /* properties_destroyed */
768438fd1498Szrj 0, /* todo_flags_start */
768538fd1498Szrj TODO_rebuild_alias, /* todo_flags_finish */
768638fd1498Szrj };
768738fd1498Szrj
768838fd1498Szrj class pass_build_ealias : public gimple_opt_pass
768938fd1498Szrj {
769038fd1498Szrj public:
pass_build_ealias(gcc::context * ctxt)769138fd1498Szrj pass_build_ealias (gcc::context *ctxt)
769238fd1498Szrj : gimple_opt_pass (pass_data_build_ealias, ctxt)
769338fd1498Szrj {}
769438fd1498Szrj
769538fd1498Szrj /* opt_pass methods: */
gate(function *)769638fd1498Szrj virtual bool gate (function *) { return flag_tree_pta; }
769738fd1498Szrj
769838fd1498Szrj }; // class pass_build_ealias
769938fd1498Szrj
770038fd1498Szrj } // anon namespace
770138fd1498Szrj
770238fd1498Szrj gimple_opt_pass *
make_pass_build_ealias(gcc::context * ctxt)770338fd1498Szrj make_pass_build_ealias (gcc::context *ctxt)
770438fd1498Szrj {
770538fd1498Szrj return new pass_build_ealias (ctxt);
770638fd1498Szrj }
770738fd1498Szrj
770838fd1498Szrj
770938fd1498Szrj /* IPA PTA solutions for ESCAPED. */
771038fd1498Szrj struct pt_solution ipa_escaped_pt
771138fd1498Szrj = { true, false, false, false, false,
771238fd1498Szrj false, false, false, false, false, NULL };
771338fd1498Szrj
771438fd1498Szrj /* Associate node with varinfo DATA. Worker for
771538fd1498Szrj cgraph_for_symbol_thunks_and_aliases. */
771638fd1498Szrj static bool
associate_varinfo_to_alias(struct cgraph_node * node,void * data)771738fd1498Szrj associate_varinfo_to_alias (struct cgraph_node *node, void *data)
771838fd1498Szrj {
771938fd1498Szrj if ((node->alias
772038fd1498Szrj || (node->thunk.thunk_p
772138fd1498Szrj && ! node->global.inlined_to))
772238fd1498Szrj && node->analyzed)
772338fd1498Szrj insert_vi_for_tree (node->decl, (varinfo_t)data);
772438fd1498Szrj return false;
772538fd1498Szrj }
772638fd1498Szrj
772738fd1498Szrj /* Dump varinfo VI to FILE. */
772838fd1498Szrj
772938fd1498Szrj static void
dump_varinfo(FILE * file,varinfo_t vi)773038fd1498Szrj dump_varinfo (FILE *file, varinfo_t vi)
773138fd1498Szrj {
773238fd1498Szrj if (vi == NULL)
773338fd1498Szrj return;
773438fd1498Szrj
773538fd1498Szrj fprintf (file, "%u: %s\n", vi->id, vi->name);
773638fd1498Szrj
773738fd1498Szrj const char *sep = " ";
773838fd1498Szrj if (vi->is_artificial_var)
773938fd1498Szrj fprintf (file, "%sartificial", sep);
774038fd1498Szrj if (vi->is_special_var)
774138fd1498Szrj fprintf (file, "%sspecial", sep);
774238fd1498Szrj if (vi->is_unknown_size_var)
774338fd1498Szrj fprintf (file, "%sunknown-size", sep);
774438fd1498Szrj if (vi->is_full_var)
774538fd1498Szrj fprintf (file, "%sfull", sep);
774638fd1498Szrj if (vi->is_heap_var)
774738fd1498Szrj fprintf (file, "%sheap", sep);
774838fd1498Szrj if (vi->may_have_pointers)
774938fd1498Szrj fprintf (file, "%smay-have-pointers", sep);
775038fd1498Szrj if (vi->only_restrict_pointers)
775138fd1498Szrj fprintf (file, "%sonly-restrict-pointers", sep);
775238fd1498Szrj if (vi->is_restrict_var)
775338fd1498Szrj fprintf (file, "%sis-restrict-var", sep);
775438fd1498Szrj if (vi->is_global_var)
775538fd1498Szrj fprintf (file, "%sglobal", sep);
775638fd1498Szrj if (vi->is_ipa_escape_point)
775738fd1498Szrj fprintf (file, "%sipa-escape-point", sep);
775838fd1498Szrj if (vi->is_fn_info)
775938fd1498Szrj fprintf (file, "%sfn-info", sep);
776038fd1498Szrj if (vi->ruid)
776138fd1498Szrj fprintf (file, "%srestrict-uid:%u", sep, vi->ruid);
776238fd1498Szrj if (vi->next)
776338fd1498Szrj fprintf (file, "%snext:%u", sep, vi->next);
776438fd1498Szrj if (vi->head != vi->id)
776538fd1498Szrj fprintf (file, "%shead:%u", sep, vi->head);
776638fd1498Szrj if (vi->offset)
776738fd1498Szrj fprintf (file, "%soffset:" HOST_WIDE_INT_PRINT_DEC, sep, vi->offset);
776838fd1498Szrj if (vi->size != ~(unsigned HOST_WIDE_INT)0)
776938fd1498Szrj fprintf (file, "%ssize:" HOST_WIDE_INT_PRINT_DEC, sep, vi->size);
777038fd1498Szrj if (vi->fullsize != ~(unsigned HOST_WIDE_INT)0
777138fd1498Szrj && vi->fullsize != vi->size)
777238fd1498Szrj fprintf (file, "%sfullsize:" HOST_WIDE_INT_PRINT_DEC, sep,
777338fd1498Szrj vi->fullsize);
777438fd1498Szrj fprintf (file, "\n");
777538fd1498Szrj
777638fd1498Szrj if (vi->solution && !bitmap_empty_p (vi->solution))
777738fd1498Szrj {
777838fd1498Szrj bitmap_iterator bi;
777938fd1498Szrj unsigned i;
778038fd1498Szrj fprintf (file, " solution: {");
778138fd1498Szrj EXECUTE_IF_SET_IN_BITMAP (vi->solution, 0, i, bi)
778238fd1498Szrj fprintf (file, " %u", i);
778338fd1498Szrj fprintf (file, " }\n");
778438fd1498Szrj }
778538fd1498Szrj
778638fd1498Szrj if (vi->oldsolution && !bitmap_empty_p (vi->oldsolution)
778738fd1498Szrj && !bitmap_equal_p (vi->solution, vi->oldsolution))
778838fd1498Szrj {
778938fd1498Szrj bitmap_iterator bi;
779038fd1498Szrj unsigned i;
779138fd1498Szrj fprintf (file, " oldsolution: {");
779238fd1498Szrj EXECUTE_IF_SET_IN_BITMAP (vi->oldsolution, 0, i, bi)
779338fd1498Szrj fprintf (file, " %u", i);
779438fd1498Szrj fprintf (file, " }\n");
779538fd1498Szrj }
779638fd1498Szrj }
779738fd1498Szrj
779838fd1498Szrj /* Dump varinfo VI to stderr. */
779938fd1498Szrj
780038fd1498Szrj DEBUG_FUNCTION void
debug_varinfo(varinfo_t vi)780138fd1498Szrj debug_varinfo (varinfo_t vi)
780238fd1498Szrj {
780338fd1498Szrj dump_varinfo (stderr, vi);
780438fd1498Szrj }
780538fd1498Szrj
780638fd1498Szrj /* Dump varmap to FILE. */
780738fd1498Szrj
780838fd1498Szrj static void
dump_varmap(FILE * file)780938fd1498Szrj dump_varmap (FILE *file)
781038fd1498Szrj {
781138fd1498Szrj if (varmap.length () == 0)
781238fd1498Szrj return;
781338fd1498Szrj
781438fd1498Szrj fprintf (file, "variables:\n");
781538fd1498Szrj
781638fd1498Szrj for (unsigned int i = 0; i < varmap.length (); ++i)
781738fd1498Szrj {
781838fd1498Szrj varinfo_t vi = get_varinfo (i);
781938fd1498Szrj dump_varinfo (file, vi);
782038fd1498Szrj }
782138fd1498Szrj
782238fd1498Szrj fprintf (file, "\n");
782338fd1498Szrj }
782438fd1498Szrj
782538fd1498Szrj /* Dump varmap to stderr. */
782638fd1498Szrj
782738fd1498Szrj DEBUG_FUNCTION void
debug_varmap(void)782838fd1498Szrj debug_varmap (void)
782938fd1498Szrj {
783038fd1498Szrj dump_varmap (stderr);
783138fd1498Szrj }
783238fd1498Szrj
783338fd1498Szrj /* Compute whether node is refered to non-locally. Worker for
783438fd1498Szrj cgraph_for_symbol_thunks_and_aliases. */
783538fd1498Szrj static bool
refered_from_nonlocal_fn(struct cgraph_node * node,void * data)783638fd1498Szrj refered_from_nonlocal_fn (struct cgraph_node *node, void *data)
783738fd1498Szrj {
783838fd1498Szrj bool *nonlocal_p = (bool *)data;
783938fd1498Szrj *nonlocal_p |= (node->used_from_other_partition
784038fd1498Szrj || node->externally_visible
784138fd1498Szrj || node->force_output
784238fd1498Szrj || lookup_attribute ("noipa", DECL_ATTRIBUTES (node->decl)));
784338fd1498Szrj return false;
784438fd1498Szrj }
784538fd1498Szrj
784638fd1498Szrj /* Same for varpool nodes. */
784738fd1498Szrj static bool
refered_from_nonlocal_var(struct varpool_node * node,void * data)784838fd1498Szrj refered_from_nonlocal_var (struct varpool_node *node, void *data)
784938fd1498Szrj {
785038fd1498Szrj bool *nonlocal_p = (bool *)data;
785138fd1498Szrj *nonlocal_p |= (node->used_from_other_partition
785238fd1498Szrj || node->externally_visible
785338fd1498Szrj || node->force_output);
785438fd1498Szrj return false;
785538fd1498Szrj }
785638fd1498Szrj
785738fd1498Szrj /* Execute the driver for IPA PTA. */
785838fd1498Szrj static unsigned int
ipa_pta_execute(void)785938fd1498Szrj ipa_pta_execute (void)
786038fd1498Szrj {
786138fd1498Szrj struct cgraph_node *node;
786238fd1498Szrj varpool_node *var;
786338fd1498Szrj unsigned int from = 0;
786438fd1498Szrj
786538fd1498Szrj in_ipa_mode = 1;
786638fd1498Szrj
786738fd1498Szrj init_alias_vars ();
786838fd1498Szrj
786938fd1498Szrj if (dump_file && (dump_flags & TDF_DETAILS))
787038fd1498Szrj {
787138fd1498Szrj symtab->dump (dump_file);
787238fd1498Szrj fprintf (dump_file, "\n");
787338fd1498Szrj }
787438fd1498Szrj
787538fd1498Szrj if (dump_file)
787638fd1498Szrj {
787738fd1498Szrj fprintf (dump_file, "Generating generic constraints\n\n");
787838fd1498Szrj dump_constraints (dump_file, from);
787938fd1498Szrj fprintf (dump_file, "\n");
788038fd1498Szrj from = constraints.length ();
788138fd1498Szrj }
788238fd1498Szrj
788338fd1498Szrj /* Build the constraints. */
788438fd1498Szrj FOR_EACH_DEFINED_FUNCTION (node)
788538fd1498Szrj {
788638fd1498Szrj varinfo_t vi;
788738fd1498Szrj /* Nodes without a body are not interesting. Especially do not
788838fd1498Szrj visit clones at this point for now - we get duplicate decls
788938fd1498Szrj there for inline clones at least. */
789038fd1498Szrj if (!node->has_gimple_body_p () || node->global.inlined_to)
789138fd1498Szrj continue;
789238fd1498Szrj node->get_body ();
789338fd1498Szrj
789438fd1498Szrj gcc_assert (!node->clone_of);
789538fd1498Szrj
789638fd1498Szrj /* For externally visible or attribute used annotated functions use
789738fd1498Szrj local constraints for their arguments.
789838fd1498Szrj For local functions we see all callers and thus do not need initial
789938fd1498Szrj constraints for parameters. */
790038fd1498Szrj bool nonlocal_p = (node->used_from_other_partition
790138fd1498Szrj || node->externally_visible
790238fd1498Szrj || node->force_output
790338fd1498Szrj || lookup_attribute ("noipa",
790438fd1498Szrj DECL_ATTRIBUTES (node->decl)));
790538fd1498Szrj node->call_for_symbol_thunks_and_aliases (refered_from_nonlocal_fn,
790638fd1498Szrj &nonlocal_p, true);
790738fd1498Szrj
790838fd1498Szrj vi = create_function_info_for (node->decl,
790938fd1498Szrj alias_get_name (node->decl), false,
791038fd1498Szrj nonlocal_p);
791138fd1498Szrj if (dump_file
791238fd1498Szrj && from != constraints.length ())
791338fd1498Szrj {
791438fd1498Szrj fprintf (dump_file,
791538fd1498Szrj "Generating intial constraints for %s", node->name ());
791638fd1498Szrj if (DECL_ASSEMBLER_NAME_SET_P (node->decl))
791738fd1498Szrj fprintf (dump_file, " (%s)",
791838fd1498Szrj IDENTIFIER_POINTER
791938fd1498Szrj (DECL_ASSEMBLER_NAME (node->decl)));
792038fd1498Szrj fprintf (dump_file, "\n\n");
792138fd1498Szrj dump_constraints (dump_file, from);
792238fd1498Szrj fprintf (dump_file, "\n");
792338fd1498Szrj
792438fd1498Szrj from = constraints.length ();
792538fd1498Szrj }
792638fd1498Szrj
792738fd1498Szrj node->call_for_symbol_thunks_and_aliases
792838fd1498Szrj (associate_varinfo_to_alias, vi, true);
792938fd1498Szrj }
793038fd1498Szrj
793138fd1498Szrj /* Create constraints for global variables and their initializers. */
793238fd1498Szrj FOR_EACH_VARIABLE (var)
793338fd1498Szrj {
793438fd1498Szrj if (var->alias && var->analyzed)
793538fd1498Szrj continue;
793638fd1498Szrj
793738fd1498Szrj varinfo_t vi = get_vi_for_tree (var->decl);
793838fd1498Szrj
793938fd1498Szrj /* For the purpose of IPA PTA unit-local globals are not
794038fd1498Szrj escape points. */
794138fd1498Szrj bool nonlocal_p = (var->used_from_other_partition
794238fd1498Szrj || var->externally_visible
794338fd1498Szrj || var->force_output);
794438fd1498Szrj var->call_for_symbol_and_aliases (refered_from_nonlocal_var,
794538fd1498Szrj &nonlocal_p, true);
794638fd1498Szrj if (nonlocal_p)
794738fd1498Szrj vi->is_ipa_escape_point = true;
794838fd1498Szrj }
794938fd1498Szrj
795038fd1498Szrj if (dump_file
795138fd1498Szrj && from != constraints.length ())
795238fd1498Szrj {
795338fd1498Szrj fprintf (dump_file,
795438fd1498Szrj "Generating constraints for global initializers\n\n");
795538fd1498Szrj dump_constraints (dump_file, from);
795638fd1498Szrj fprintf (dump_file, "\n");
795738fd1498Szrj from = constraints.length ();
795838fd1498Szrj }
795938fd1498Szrj
796038fd1498Szrj FOR_EACH_DEFINED_FUNCTION (node)
796138fd1498Szrj {
796238fd1498Szrj struct function *func;
796338fd1498Szrj basic_block bb;
796438fd1498Szrj
796538fd1498Szrj /* Nodes without a body are not interesting. */
796638fd1498Szrj if (!node->has_gimple_body_p () || node->clone_of)
796738fd1498Szrj continue;
796838fd1498Szrj
796938fd1498Szrj if (dump_file)
797038fd1498Szrj {
797138fd1498Szrj fprintf (dump_file,
797238fd1498Szrj "Generating constraints for %s", node->name ());
797338fd1498Szrj if (DECL_ASSEMBLER_NAME_SET_P (node->decl))
797438fd1498Szrj fprintf (dump_file, " (%s)",
797538fd1498Szrj IDENTIFIER_POINTER
797638fd1498Szrj (DECL_ASSEMBLER_NAME (node->decl)));
797738fd1498Szrj fprintf (dump_file, "\n");
797838fd1498Szrj }
797938fd1498Szrj
798038fd1498Szrj func = DECL_STRUCT_FUNCTION (node->decl);
798138fd1498Szrj gcc_assert (cfun == NULL);
798238fd1498Szrj
798338fd1498Szrj /* Build constriants for the function body. */
798438fd1498Szrj FOR_EACH_BB_FN (bb, func)
798538fd1498Szrj {
798638fd1498Szrj for (gphi_iterator gsi = gsi_start_phis (bb); !gsi_end_p (gsi);
798738fd1498Szrj gsi_next (&gsi))
798838fd1498Szrj {
798938fd1498Szrj gphi *phi = gsi.phi ();
799038fd1498Szrj
799138fd1498Szrj if (! virtual_operand_p (gimple_phi_result (phi)))
799238fd1498Szrj find_func_aliases (func, phi);
799338fd1498Szrj }
799438fd1498Szrj
799538fd1498Szrj for (gimple_stmt_iterator gsi = gsi_start_bb (bb); !gsi_end_p (gsi);
799638fd1498Szrj gsi_next (&gsi))
799738fd1498Szrj {
799838fd1498Szrj gimple *stmt = gsi_stmt (gsi);
799938fd1498Szrj
800038fd1498Szrj find_func_aliases (func, stmt);
800138fd1498Szrj find_func_clobbers (func, stmt);
800238fd1498Szrj }
800338fd1498Szrj }
800438fd1498Szrj
800538fd1498Szrj if (dump_file)
800638fd1498Szrj {
800738fd1498Szrj fprintf (dump_file, "\n");
800838fd1498Szrj dump_constraints (dump_file, from);
800938fd1498Szrj fprintf (dump_file, "\n");
801038fd1498Szrj from = constraints.length ();
801138fd1498Szrj }
801238fd1498Szrj }
801338fd1498Szrj
801438fd1498Szrj /* From the constraints compute the points-to sets. */
801538fd1498Szrj solve_constraints ();
801638fd1498Szrj
801738fd1498Szrj /* Compute the global points-to sets for ESCAPED.
801838fd1498Szrj ??? Note that the computed escape set is not correct
801938fd1498Szrj for the whole unit as we fail to consider graph edges to
802038fd1498Szrj externally visible functions. */
802138fd1498Szrj ipa_escaped_pt = find_what_var_points_to (NULL, get_varinfo (escaped_id));
802238fd1498Szrj
802338fd1498Szrj /* Make sure the ESCAPED solution (which is used as placeholder in
802438fd1498Szrj other solutions) does not reference itself. This simplifies
802538fd1498Szrj points-to solution queries. */
802638fd1498Szrj ipa_escaped_pt.ipa_escaped = 0;
802738fd1498Szrj
802838fd1498Szrj /* Assign the points-to sets to the SSA names in the unit. */
802938fd1498Szrj FOR_EACH_DEFINED_FUNCTION (node)
803038fd1498Szrj {
803138fd1498Szrj tree ptr;
803238fd1498Szrj struct function *fn;
803338fd1498Szrj unsigned i;
803438fd1498Szrj basic_block bb;
803538fd1498Szrj
803638fd1498Szrj /* Nodes without a body are not interesting. */
803738fd1498Szrj if (!node->has_gimple_body_p () || node->clone_of)
803838fd1498Szrj continue;
803938fd1498Szrj
804038fd1498Szrj fn = DECL_STRUCT_FUNCTION (node->decl);
804138fd1498Szrj
804238fd1498Szrj /* Compute the points-to sets for pointer SSA_NAMEs. */
804338fd1498Szrj FOR_EACH_VEC_ELT (*fn->gimple_df->ssa_names, i, ptr)
804438fd1498Szrj {
804538fd1498Szrj if (ptr
804638fd1498Szrj && POINTER_TYPE_P (TREE_TYPE (ptr)))
804738fd1498Szrj find_what_p_points_to (node->decl, ptr);
804838fd1498Szrj }
804938fd1498Szrj
805038fd1498Szrj /* Compute the call-use and call-clobber sets for indirect calls
805138fd1498Szrj and calls to external functions. */
805238fd1498Szrj FOR_EACH_BB_FN (bb, fn)
805338fd1498Szrj {
805438fd1498Szrj gimple_stmt_iterator gsi;
805538fd1498Szrj
805638fd1498Szrj for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi))
805738fd1498Szrj {
805838fd1498Szrj gcall *stmt;
805938fd1498Szrj struct pt_solution *pt;
806038fd1498Szrj varinfo_t vi, fi;
806138fd1498Szrj tree decl;
806238fd1498Szrj
806338fd1498Szrj stmt = dyn_cast <gcall *> (gsi_stmt (gsi));
806438fd1498Szrj if (!stmt)
806538fd1498Szrj continue;
806638fd1498Szrj
806738fd1498Szrj /* Handle direct calls to functions with body. */
806838fd1498Szrj decl = gimple_call_fndecl (stmt);
806938fd1498Szrj
807038fd1498Szrj {
807138fd1498Szrj tree called_decl = NULL_TREE;
807238fd1498Szrj if (gimple_call_builtin_p (stmt, BUILT_IN_GOMP_PARALLEL))
807338fd1498Szrj called_decl = TREE_OPERAND (gimple_call_arg (stmt, 0), 0);
807438fd1498Szrj else if (gimple_call_builtin_p (stmt, BUILT_IN_GOACC_PARALLEL))
807538fd1498Szrj called_decl = TREE_OPERAND (gimple_call_arg (stmt, 1), 0);
807638fd1498Szrj
807738fd1498Szrj if (called_decl != NULL_TREE
807838fd1498Szrj && !fndecl_maybe_in_other_partition (called_decl))
807938fd1498Szrj decl = called_decl;
808038fd1498Szrj }
808138fd1498Szrj
808238fd1498Szrj if (decl
808338fd1498Szrj && (fi = lookup_vi_for_tree (decl))
808438fd1498Szrj && fi->is_fn_info)
808538fd1498Szrj {
808638fd1498Szrj *gimple_call_clobber_set (stmt)
808738fd1498Szrj = find_what_var_points_to
808838fd1498Szrj (node->decl, first_vi_for_offset (fi, fi_clobbers));
808938fd1498Szrj *gimple_call_use_set (stmt)
809038fd1498Szrj = find_what_var_points_to
809138fd1498Szrj (node->decl, first_vi_for_offset (fi, fi_uses));
809238fd1498Szrj }
809338fd1498Szrj /* Handle direct calls to external functions. */
809438fd1498Szrj else if (decl)
809538fd1498Szrj {
809638fd1498Szrj pt = gimple_call_use_set (stmt);
809738fd1498Szrj if (gimple_call_flags (stmt) & ECF_CONST)
809838fd1498Szrj memset (pt, 0, sizeof (struct pt_solution));
809938fd1498Szrj else if ((vi = lookup_call_use_vi (stmt)) != NULL)
810038fd1498Szrj {
810138fd1498Szrj *pt = find_what_var_points_to (node->decl, vi);
810238fd1498Szrj /* Escaped (and thus nonlocal) variables are always
810338fd1498Szrj implicitly used by calls. */
810438fd1498Szrj /* ??? ESCAPED can be empty even though NONLOCAL
810538fd1498Szrj always escaped. */
810638fd1498Szrj pt->nonlocal = 1;
810738fd1498Szrj pt->ipa_escaped = 1;
810838fd1498Szrj }
810938fd1498Szrj else
811038fd1498Szrj {
811138fd1498Szrj /* If there is nothing special about this call then
811238fd1498Szrj we have made everything that is used also escape. */
811338fd1498Szrj *pt = ipa_escaped_pt;
811438fd1498Szrj pt->nonlocal = 1;
811538fd1498Szrj }
811638fd1498Szrj
811738fd1498Szrj pt = gimple_call_clobber_set (stmt);
811838fd1498Szrj if (gimple_call_flags (stmt) & (ECF_CONST|ECF_PURE|ECF_NOVOPS))
811938fd1498Szrj memset (pt, 0, sizeof (struct pt_solution));
812038fd1498Szrj else if ((vi = lookup_call_clobber_vi (stmt)) != NULL)
812138fd1498Szrj {
812238fd1498Szrj *pt = find_what_var_points_to (node->decl, vi);
812338fd1498Szrj /* Escaped (and thus nonlocal) variables are always
812438fd1498Szrj implicitly clobbered by calls. */
812538fd1498Szrj /* ??? ESCAPED can be empty even though NONLOCAL
812638fd1498Szrj always escaped. */
812738fd1498Szrj pt->nonlocal = 1;
812838fd1498Szrj pt->ipa_escaped = 1;
812938fd1498Szrj }
813038fd1498Szrj else
813138fd1498Szrj {
813238fd1498Szrj /* If there is nothing special about this call then
813338fd1498Szrj we have made everything that is used also escape. */
813438fd1498Szrj *pt = ipa_escaped_pt;
813538fd1498Szrj pt->nonlocal = 1;
813638fd1498Szrj }
813738fd1498Szrj }
813838fd1498Szrj /* Handle indirect calls. */
813938fd1498Szrj else if (!decl
814038fd1498Szrj && (fi = get_fi_for_callee (stmt)))
814138fd1498Szrj {
814238fd1498Szrj /* We need to accumulate all clobbers/uses of all possible
814338fd1498Szrj callees. */
814438fd1498Szrj fi = get_varinfo (find (fi->id));
814538fd1498Szrj /* If we cannot constrain the set of functions we'll end up
814638fd1498Szrj calling we end up using/clobbering everything. */
814738fd1498Szrj if (bitmap_bit_p (fi->solution, anything_id)
814838fd1498Szrj || bitmap_bit_p (fi->solution, nonlocal_id)
814938fd1498Szrj || bitmap_bit_p (fi->solution, escaped_id))
815038fd1498Szrj {
815138fd1498Szrj pt_solution_reset (gimple_call_clobber_set (stmt));
815238fd1498Szrj pt_solution_reset (gimple_call_use_set (stmt));
815338fd1498Szrj }
815438fd1498Szrj else
815538fd1498Szrj {
815638fd1498Szrj bitmap_iterator bi;
815738fd1498Szrj unsigned i;
815838fd1498Szrj struct pt_solution *uses, *clobbers;
815938fd1498Szrj
816038fd1498Szrj uses = gimple_call_use_set (stmt);
816138fd1498Szrj clobbers = gimple_call_clobber_set (stmt);
816238fd1498Szrj memset (uses, 0, sizeof (struct pt_solution));
816338fd1498Szrj memset (clobbers, 0, sizeof (struct pt_solution));
816438fd1498Szrj EXECUTE_IF_SET_IN_BITMAP (fi->solution, 0, i, bi)
816538fd1498Szrj {
816638fd1498Szrj struct pt_solution sol;
816738fd1498Szrj
816838fd1498Szrj vi = get_varinfo (i);
816938fd1498Szrj if (!vi->is_fn_info)
817038fd1498Szrj {
817138fd1498Szrj /* ??? We could be more precise here? */
817238fd1498Szrj uses->nonlocal = 1;
817338fd1498Szrj uses->ipa_escaped = 1;
817438fd1498Szrj clobbers->nonlocal = 1;
817538fd1498Szrj clobbers->ipa_escaped = 1;
817638fd1498Szrj continue;
817738fd1498Szrj }
817838fd1498Szrj
817938fd1498Szrj if (!uses->anything)
818038fd1498Szrj {
818138fd1498Szrj sol = find_what_var_points_to
818238fd1498Szrj (node->decl,
818338fd1498Szrj first_vi_for_offset (vi, fi_uses));
818438fd1498Szrj pt_solution_ior_into (uses, &sol);
818538fd1498Szrj }
818638fd1498Szrj if (!clobbers->anything)
818738fd1498Szrj {
818838fd1498Szrj sol = find_what_var_points_to
818938fd1498Szrj (node->decl,
819038fd1498Szrj first_vi_for_offset (vi, fi_clobbers));
819138fd1498Szrj pt_solution_ior_into (clobbers, &sol);
819238fd1498Szrj }
819338fd1498Szrj }
819438fd1498Szrj }
819538fd1498Szrj }
819638fd1498Szrj }
819738fd1498Szrj }
819838fd1498Szrj
819938fd1498Szrj fn->gimple_df->ipa_pta = true;
820038fd1498Szrj
820138fd1498Szrj /* We have to re-set the final-solution cache after each function
820238fd1498Szrj because what is a "global" is dependent on function context. */
820338fd1498Szrj final_solutions->empty ();
820438fd1498Szrj obstack_free (&final_solutions_obstack, NULL);
820538fd1498Szrj gcc_obstack_init (&final_solutions_obstack);
820638fd1498Szrj }
820738fd1498Szrj
820838fd1498Szrj delete_points_to_sets ();
820938fd1498Szrj
821038fd1498Szrj in_ipa_mode = 0;
821138fd1498Szrj
821238fd1498Szrj return 0;
821338fd1498Szrj }
821438fd1498Szrj
821538fd1498Szrj namespace {
821638fd1498Szrj
821738fd1498Szrj const pass_data pass_data_ipa_pta =
821838fd1498Szrj {
821938fd1498Szrj SIMPLE_IPA_PASS, /* type */
822038fd1498Szrj "pta", /* name */
822138fd1498Szrj OPTGROUP_NONE, /* optinfo_flags */
822238fd1498Szrj TV_IPA_PTA, /* tv_id */
822338fd1498Szrj 0, /* properties_required */
822438fd1498Szrj 0, /* properties_provided */
822538fd1498Szrj 0, /* properties_destroyed */
822638fd1498Szrj 0, /* todo_flags_start */
822738fd1498Szrj 0, /* todo_flags_finish */
822838fd1498Szrj };
822938fd1498Szrj
823038fd1498Szrj class pass_ipa_pta : public simple_ipa_opt_pass
823138fd1498Szrj {
823238fd1498Szrj public:
pass_ipa_pta(gcc::context * ctxt)823338fd1498Szrj pass_ipa_pta (gcc::context *ctxt)
823438fd1498Szrj : simple_ipa_opt_pass (pass_data_ipa_pta, ctxt)
823538fd1498Szrj {}
823638fd1498Szrj
823738fd1498Szrj /* opt_pass methods: */
gate(function *)823838fd1498Szrj virtual bool gate (function *)
823938fd1498Szrj {
824038fd1498Szrj return (optimize
824138fd1498Szrj && flag_ipa_pta
824238fd1498Szrj /* Don't bother doing anything if the program has errors. */
824338fd1498Szrj && !seen_error ());
824438fd1498Szrj }
824538fd1498Szrj
clone()824638fd1498Szrj opt_pass * clone () { return new pass_ipa_pta (m_ctxt); }
824738fd1498Szrj
execute(function *)824838fd1498Szrj virtual unsigned int execute (function *) { return ipa_pta_execute (); }
824938fd1498Szrj
825038fd1498Szrj }; // class pass_ipa_pta
825138fd1498Szrj
825238fd1498Szrj } // anon namespace
825338fd1498Szrj
825438fd1498Szrj simple_ipa_opt_pass *
make_pass_ipa_pta(gcc::context * ctxt)825538fd1498Szrj make_pass_ipa_pta (gcc::context *ctxt)
825638fd1498Szrj {
825738fd1498Szrj return new pass_ipa_pta (ctxt);
825838fd1498Szrj }
8259