]>
Commit | Line | Data |
---|---|---|
518dc859 | 1 | /* Interprocedural constant propagation |
932c7744 | 2 | Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012 |
c75c517d | 3 | Free Software Foundation, Inc. |
310bc633 MJ |
4 | |
5 | Contributed by Razya Ladelsky <RAZYA@il.ibm.com> and Martin Jambor | |
6 | <mjambor@suse.cz> | |
b8698a0f | 7 | |
518dc859 | 8 | This file is part of GCC. |
b8698a0f | 9 | |
518dc859 RL |
10 | GCC is free software; you can redistribute it and/or modify it under |
11 | the terms of the GNU General Public License as published by the Free | |
9dcd6f09 | 12 | Software Foundation; either version 3, or (at your option) any later |
518dc859 | 13 | version. |
b8698a0f | 14 | |
518dc859 RL |
15 | GCC is distributed in the hope that it will be useful, but WITHOUT ANY |
16 | WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
17 | FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
18 | for more details. | |
b8698a0f | 19 | |
518dc859 | 20 | You should have received a copy of the GNU General Public License |
9dcd6f09 NC |
21 | along with GCC; see the file COPYING3. If not see |
22 | <http://www.gnu.org/licenses/>. */ | |
518dc859 | 23 | |
310bc633 | 24 | /* Interprocedural constant propagation (IPA-CP). |
b8698a0f | 25 | |
310bc633 | 26 | The goal of this transformation is to |
c43f07af | 27 | |
310bc633 MJ |
28 | 1) discover functions which are always invoked with some arguments with the |
29 | same known constant values and modify the functions so that the | |
30 | subsequent optimizations can take advantage of the knowledge, and | |
c43f07af | 31 | |
310bc633 MJ |
32 | 2) partial specialization - create specialized versions of functions |
33 | transformed in this way if some parameters are known constants only in | |
34 | certain contexts but the estimated tradeoff between speedup and cost size | |
35 | is deemed good. | |
b8698a0f | 36 | |
310bc633 MJ |
37 | The algorithm also propagates types and attempts to perform type based |
38 | devirtualization. Types are propagated much like constants. | |
b8698a0f | 39 | |
310bc633 MJ |
40 | The algorithm basically consists of three stages. In the first, functions |
41 | are analyzed one at a time and jump functions are constructed for all known | |
42 | call-sites. In the second phase, the pass propagates information from the | |
43 | jump functions across the call to reveal what values are available at what | |
44 | call sites, performs estimations of effects of known values on functions and | |
45 | their callees, and finally decides what specialized extra versions should be | |
46 | created. In the third, the special versions materialize and appropriate | |
47 | calls are redirected. | |
c43f07af | 48 | |
310bc633 MJ |
49 | The algorithm used is to a certain extent based on "Interprocedural Constant |
50 | Propagation", by David Callahan, Keith D Cooper, Ken Kennedy, Linda Torczon, | |
51 | Comp86, pg 152-161 and "A Methodology for Procedure Cloning" by Keith D | |
52 | Cooper, Mary W. Hall, and Ken Kennedy. | |
b8698a0f | 53 | |
518dc859 RL |
54 | |
55 | First stage - intraprocedural analysis | |
56 | ======================================= | |
310bc633 | 57 | |
c43f07af | 58 | This phase computes jump_function and modification flags. |
b8698a0f | 59 | |
310bc633 MJ |
60 | A jump function for a call-site represents the values passed as an actual |
61 | arguments of a given call-site. In principle, there are three types of | |
62 | values: | |
63 | ||
64 | Pass through - the caller's formal parameter is passed as an actual | |
65 | argument, plus an operation on it can be performed. | |
ea2c620c | 66 | Constant - a constant is passed as an actual argument. |
518dc859 | 67 | Unknown - neither of the above. |
b8698a0f | 68 | |
310bc633 MJ |
69 | All jump function types are described in detail in ipa-prop.h, together with |
70 | the data structures that represent them and methods of accessing them. | |
b8698a0f | 71 | |
310bc633 | 72 | ipcp_generate_summary() is the main function of the first stage. |
518dc859 RL |
73 | |
74 | Second stage - interprocedural analysis | |
75 | ======================================== | |
b8698a0f | 76 | |
310bc633 MJ |
77 | This stage is itself divided into two phases. In the first, we propagate |
78 | known values over the call graph, in the second, we make cloning decisions. | |
79 | It uses a different algorithm than the original Callahan's paper. | |
b8698a0f | 80 | |
310bc633 MJ |
81 | First, we traverse the functions topologically from callers to callees and, |
82 | for each strongly connected component (SCC), we propagate constants | |
83 | according to previously computed jump functions. We also record what known | |
84 | values depend on other known values and estimate local effects. Finally, we | |
073a8998 | 85 | propagate cumulative information about these effects from dependent values |
310bc633 | 86 | to those on which they depend. |
518dc859 | 87 | |
310bc633 MJ |
88 | Second, we again traverse the call graph in the same topological order and |
89 | make clones for functions which we know are called with the same values in | |
90 | all contexts and decide about extra specialized clones of functions just for | |
91 | some contexts - these decisions are based on both local estimates and | |
92 | cumulative estimates propagated from callees. | |
518dc859 | 93 | |
310bc633 MJ |
94 | ipcp_propagate_stage() and ipcp_decision_stage() together constitute the |
95 | third stage. | |
96 | ||
97 | Third phase - materialization of clones, call statement updates. | |
518dc859 | 98 | ============================================ |
310bc633 MJ |
99 | |
100 | This stage is currently performed by call graph code (mainly in cgraphunit.c | |
101 | and tree-inline.c) according to instructions inserted to the call graph by | |
102 | the second stage. */ | |
518dc859 RL |
103 | |
104 | #include "config.h" | |
105 | #include "system.h" | |
106 | #include "coretypes.h" | |
107 | #include "tree.h" | |
108 | #include "target.h" | |
3949c4a7 | 109 | #include "gimple.h" |
518dc859 RL |
110 | #include "cgraph.h" |
111 | #include "ipa-prop.h" | |
112 | #include "tree-flow.h" | |
113 | #include "tree-pass.h" | |
114 | #include "flags.h" | |
518dc859 | 115 | #include "diagnostic.h" |
cf835838 | 116 | #include "tree-pretty-print.h" |
3cc1cccc | 117 | #include "tree-inline.h" |
5e45130d | 118 | #include "params.h" |
10a5dd5d | 119 | #include "ipa-inline.h" |
310bc633 | 120 | #include "ipa-utils.h" |
518dc859 | 121 | |
310bc633 | 122 | struct ipcp_value; |
ca30a539 | 123 | |
310bc633 | 124 | /* Describes a particular source for an IPA-CP value. */ |
ca30a539 | 125 | |
310bc633 MJ |
126 | struct ipcp_value_source |
127 | { | |
128 | /* The incoming edge that brought the value. */ | |
129 | struct cgraph_edge *cs; | |
130 | /* If the jump function that resulted into his value was a pass-through or an | |
131 | ancestor, this is the ipcp_value of the caller from which the described | |
132 | value has been derived. Otherwise it is NULL. */ | |
133 | struct ipcp_value *val; | |
134 | /* Next pointer in a linked list of sources of a value. */ | |
135 | struct ipcp_value_source *next; | |
136 | /* If the jump function that resulted into his value was a pass-through or an | |
137 | ancestor, this is the index of the parameter of the caller the jump | |
138 | function references. */ | |
139 | int index; | |
140 | }; | |
ca30a539 | 141 | |
310bc633 | 142 | /* Describes one particular value stored in struct ipcp_lattice. */ |
ca30a539 | 143 | |
310bc633 | 144 | struct ipcp_value |
518dc859 | 145 | { |
310bc633 MJ |
146 | /* The actual value for the given parameter. This is either an IPA invariant |
147 | or a TREE_BINFO describing a type that can be used for | |
148 | devirtualization. */ | |
149 | tree value; | |
150 | /* The list of sources from which this value originates. */ | |
151 | struct ipcp_value_source *sources; | |
152 | /* Next pointers in a linked list of all values in a lattice. */ | |
153 | struct ipcp_value *next; | |
154 | /* Next pointers in a linked list of values in a strongly connected component | |
155 | of values. */ | |
156 | struct ipcp_value *scc_next; | |
157 | /* Next pointers in a linked list of SCCs of values sorted topologically | |
158 | according their sources. */ | |
159 | struct ipcp_value *topo_next; | |
160 | /* A specialized node created for this value, NULL if none has been (so far) | |
161 | created. */ | |
162 | struct cgraph_node *spec_node; | |
163 | /* Depth first search number and low link for topological sorting of | |
164 | values. */ | |
165 | int dfs, low_link; | |
166 | /* Time benefit and size cost that specializing the function for this value | |
167 | would bring about in this function alone. */ | |
168 | int local_time_benefit, local_size_cost; | |
169 | /* Time benefit and size cost that specializing the function for this value | |
170 | can bring about in it's callees (transitively). */ | |
171 | int prop_time_benefit, prop_size_cost; | |
172 | /* True if this valye is currently on the topo-sort stack. */ | |
173 | bool on_stack; | |
174 | }; | |
518dc859 | 175 | |
310bc633 | 176 | /* Allocation pools for values and their sources in ipa-cp. */ |
518dc859 | 177 | |
310bc633 MJ |
178 | alloc_pool ipcp_values_pool; |
179 | alloc_pool ipcp_sources_pool; | |
518dc859 | 180 | |
310bc633 MJ |
181 | /* Lattice describing potential values of a formal parameter of a function and |
182 | some of their other properties. TOP is represented by a lattice with zero | |
183 | values and with contains_variable and bottom flags cleared. BOTTOM is | |
184 | represented by a lattice with the bottom flag set. In that case, values and | |
185 | contains_variable flag should be disregarded. */ | |
186 | ||
187 | struct ipcp_lattice | |
518dc859 | 188 | { |
310bc633 MJ |
189 | /* The list of known values and types in this lattice. Note that values are |
190 | not deallocated if a lattice is set to bottom because there may be value | |
191 | sources referencing them. */ | |
192 | struct ipcp_value *values; | |
193 | /* Number of known values and types in this lattice. */ | |
194 | int values_count; | |
195 | /* The lattice contains a variable component (in addition to values). */ | |
196 | bool contains_variable; | |
197 | /* The value of the lattice is bottom (i.e. variable and unusable for any | |
198 | propagation). */ | |
199 | bool bottom; | |
200 | /* There is a virtual call based on this parameter. */ | |
201 | bool virt_call; | |
202 | }; | |
518dc859 | 203 | |
310bc633 MJ |
204 | /* Maximal count found in program. */ |
205 | ||
206 | static gcov_type max_count; | |
207 | ||
208 | /* Original overall size of the program. */ | |
209 | ||
210 | static long overall_size, max_new_size; | |
211 | ||
212 | /* Head of the linked list of topologically sorted values. */ | |
213 | ||
214 | static struct ipcp_value *values_topo; | |
215 | ||
216 | /* Return the lattice corresponding to the Ith formal parameter of the function | |
217 | described by INFO. */ | |
218 | static inline struct ipcp_lattice * | |
219 | ipa_get_lattice (struct ipa_node_params *info, int i) | |
518dc859 | 220 | { |
d7da5cc8 | 221 | gcc_assert (i >= 0 && i < ipa_get_param_count (info)); |
310bc633 MJ |
222 | gcc_checking_assert (!info->ipcp_orig_node); |
223 | gcc_checking_assert (info->lattices); | |
224 | return &(info->lattices[i]); | |
518dc859 RL |
225 | } |
226 | ||
310bc633 MJ |
227 | /* Return whether LAT is a lattice with a single constant and without an |
228 | undefined value. */ | |
229 | ||
c43f07af | 230 | static inline bool |
310bc633 | 231 | ipa_lat_is_single_const (struct ipcp_lattice *lat) |
518dc859 | 232 | { |
310bc633 MJ |
233 | if (lat->bottom |
234 | || lat->contains_variable | |
235 | || lat->values_count != 1) | |
518dc859 | 236 | return false; |
310bc633 MJ |
237 | else |
238 | return true; | |
518dc859 RL |
239 | } |
240 | ||
310bc633 MJ |
241 | /* Return true iff the CS is an edge within a strongly connected component as |
242 | computed by ipa_reduced_postorder. */ | |
3e293154 | 243 | |
518dc859 | 244 | static inline bool |
310bc633 | 245 | edge_within_scc (struct cgraph_edge *cs) |
518dc859 | 246 | { |
960bfb69 | 247 | struct ipa_dfs_info *caller_dfs = (struct ipa_dfs_info *) cs->caller->symbol.aux; |
310bc633 MJ |
248 | struct ipa_dfs_info *callee_dfs; |
249 | struct cgraph_node *callee = cgraph_function_node (cs->callee, NULL); | |
250 | ||
960bfb69 | 251 | callee_dfs = (struct ipa_dfs_info *) callee->symbol.aux; |
310bc633 MJ |
252 | return (caller_dfs |
253 | && callee_dfs | |
254 | && caller_dfs->scc_no == callee_dfs->scc_no); | |
518dc859 RL |
255 | } |
256 | ||
310bc633 MJ |
257 | /* Print V which is extracted from a value in a lattice to F. */ |
258 | ||
518dc859 | 259 | static void |
310bc633 | 260 | print_ipcp_constant_value (FILE * f, tree v) |
518dc859 | 261 | { |
310bc633 | 262 | if (TREE_CODE (v) == TREE_BINFO) |
518dc859 | 263 | { |
310bc633 MJ |
264 | fprintf (f, "BINFO "); |
265 | print_generic_expr (f, BINFO_TYPE (v), 0); | |
518dc859 | 266 | } |
310bc633 MJ |
267 | else if (TREE_CODE (v) == ADDR_EXPR |
268 | && TREE_CODE (TREE_OPERAND (v, 0)) == CONST_DECL) | |
518dc859 | 269 | { |
310bc633 MJ |
270 | fprintf (f, "& "); |
271 | print_generic_expr (f, DECL_INITIAL (TREE_OPERAND (v, 0)), 0); | |
518dc859 | 272 | } |
310bc633 MJ |
273 | else |
274 | print_generic_expr (f, v, 0); | |
518dc859 RL |
275 | } |
276 | ||
c43f07af | 277 | /* Print all ipcp_lattices of all functions to F. */ |
310bc633 | 278 | |
518dc859 | 279 | static void |
310bc633 | 280 | print_all_lattices (FILE * f, bool dump_sources, bool dump_benefits) |
518dc859 RL |
281 | { |
282 | struct cgraph_node *node; | |
283 | int i, count; | |
3cc1cccc | 284 | |
310bc633 MJ |
285 | fprintf (f, "\nLattices:\n"); |
286 | FOR_EACH_FUNCTION_WITH_GIMPLE_BODY (node) | |
518dc859 | 287 | { |
0eae6bab MJ |
288 | struct ipa_node_params *info; |
289 | ||
0eae6bab | 290 | info = IPA_NODE_REF (node); |
310bc633 | 291 | fprintf (f, " Node: %s/%i:\n", cgraph_node_name (node), node->uid); |
c43f07af | 292 | count = ipa_get_param_count (info); |
518dc859 RL |
293 | for (i = 0; i < count; i++) |
294 | { | |
632b4f8e | 295 | struct ipcp_lattice *lat = ipa_get_lattice (info, i); |
310bc633 MJ |
296 | struct ipcp_value *val; |
297 | bool prev = false; | |
3e293154 | 298 | |
ca30a539 | 299 | fprintf (f, " param [%d]: ", i); |
310bc633 MJ |
300 | if (lat->bottom) |
301 | { | |
302 | fprintf (f, "BOTTOM\n"); | |
303 | continue; | |
304 | } | |
305 | ||
306 | if (!lat->values_count && !lat->contains_variable) | |
307 | { | |
308 | fprintf (f, "TOP\n"); | |
309 | continue; | |
310 | } | |
311 | ||
312 | if (lat->contains_variable) | |
313 | { | |
314 | fprintf (f, "VARIABLE"); | |
315 | prev = true; | |
316 | if (dump_benefits) | |
317 | fprintf (f, "\n"); | |
318 | } | |
319 | ||
320 | for (val = lat->values; val; val = val->next) | |
518dc859 | 321 | { |
310bc633 MJ |
322 | if (dump_benefits && prev) |
323 | fprintf (f, " "); | |
324 | else if (!dump_benefits && prev) | |
325 | fprintf (f, ", "); | |
326 | else | |
327 | prev = true; | |
328 | ||
329 | print_ipcp_constant_value (f, val->value); | |
330 | ||
331 | if (dump_sources) | |
add5d998 | 332 | { |
310bc633 MJ |
333 | struct ipcp_value_source *s; |
334 | ||
335 | fprintf (f, " [from:"); | |
336 | for (s = val->sources; s; s = s->next) | |
337 | fprintf (f, " %i(%i)", s->cs->caller->uid,s->cs->frequency); | |
338 | fprintf (f, "]"); | |
add5d998 | 339 | } |
310bc633 MJ |
340 | |
341 | if (dump_benefits) | |
342 | fprintf (f, " [loc_time: %i, loc_size: %i, " | |
343 | "prop_time: %i, prop_size: %i]\n", | |
344 | val->local_time_benefit, val->local_size_cost, | |
345 | val->prop_time_benefit, val->prop_size_cost); | |
518dc859 | 346 | } |
310bc633 | 347 | if (!dump_benefits) |
3949c4a7 | 348 | fprintf (f, "\n"); |
518dc859 RL |
349 | } |
350 | } | |
351 | } | |
352 | ||
310bc633 MJ |
353 | /* Determine whether it is at all technically possible to create clones of NODE |
354 | and store this information in the ipa_node_params structure associated | |
355 | with NODE. */ | |
27dbd3ac | 356 | |
310bc633 MJ |
357 | static void |
358 | determine_versionability (struct cgraph_node *node) | |
27dbd3ac | 359 | { |
310bc633 | 360 | const char *reason = NULL; |
0818c24c | 361 | |
aa229804 MJ |
362 | /* There are a number of generic reasons functions cannot be versioned. We |
363 | also cannot remove parameters if there are type attributes such as fnspec | |
364 | present. */ | |
310bc633 MJ |
365 | if (node->alias || node->thunk.thunk_p) |
366 | reason = "alias or thunk"; | |
124f1be6 | 367 | else if (!node->local.versionable) |
d7da5cc8 | 368 | reason = "not a tree_versionable_function"; |
310bc633 MJ |
369 | else if (cgraph_function_body_availability (node) <= AVAIL_OVERWRITABLE) |
370 | reason = "insufficient body availability"; | |
27dbd3ac | 371 | |
310bc633 MJ |
372 | if (reason && dump_file && !node->alias && !node->thunk.thunk_p) |
373 | fprintf (dump_file, "Function %s/%i is not versionable, reason: %s.\n", | |
374 | cgraph_node_name (node), node->uid, reason); | |
27dbd3ac | 375 | |
124f1be6 | 376 | node->local.versionable = (reason == NULL); |
27dbd3ac RH |
377 | } |
378 | ||
310bc633 MJ |
379 | /* Return true if it is at all technically possible to create clones of a |
380 | NODE. */ | |
381 | ||
ca30a539 | 382 | static bool |
310bc633 | 383 | ipcp_versionable_function_p (struct cgraph_node *node) |
ca30a539 | 384 | { |
124f1be6 | 385 | return node->local.versionable; |
310bc633 | 386 | } |
ca30a539 | 387 | |
310bc633 | 388 | /* Structure holding accumulated information about callers of a node. */ |
749f25d8 | 389 | |
310bc633 MJ |
390 | struct caller_statistics |
391 | { | |
392 | gcov_type count_sum; | |
393 | int n_calls, n_hot_calls, freq_sum; | |
394 | }; | |
ca30a539 | 395 | |
310bc633 | 396 | /* Initialize fields of STAT to zeroes. */ |
530f3a1b | 397 | |
310bc633 MJ |
398 | static inline void |
399 | init_caller_stats (struct caller_statistics *stats) | |
400 | { | |
401 | stats->count_sum = 0; | |
402 | stats->n_calls = 0; | |
403 | stats->n_hot_calls = 0; | |
404 | stats->freq_sum = 0; | |
405 | } | |
406 | ||
407 | /* Worker callback of cgraph_for_node_and_aliases accumulating statistics of | |
408 | non-thunk incoming edges to NODE. */ | |
409 | ||
410 | static bool | |
411 | gather_caller_stats (struct cgraph_node *node, void *data) | |
412 | { | |
413 | struct caller_statistics *stats = (struct caller_statistics *) data; | |
414 | struct cgraph_edge *cs; | |
415 | ||
416 | for (cs = node->callers; cs; cs = cs->next_caller) | |
417 | if (cs->caller->thunk.thunk_p) | |
418 | cgraph_for_node_and_aliases (cs->caller, gather_caller_stats, | |
419 | stats, false); | |
420 | else | |
421 | { | |
422 | stats->count_sum += cs->count; | |
423 | stats->freq_sum += cs->frequency; | |
424 | stats->n_calls++; | |
425 | if (cgraph_maybe_hot_edge_p (cs)) | |
426 | stats->n_hot_calls ++; | |
427 | } | |
428 | return false; | |
429 | ||
430 | } | |
431 | ||
432 | /* Return true if this NODE is viable candidate for cloning. */ | |
433 | ||
434 | static bool | |
435 | ipcp_cloning_candidate_p (struct cgraph_node *node) | |
436 | { | |
437 | struct caller_statistics stats; | |
438 | ||
439 | gcc_checking_assert (cgraph_function_with_gimple_body_p (node)); | |
b8698a0f | 440 | |
310bc633 | 441 | if (!flag_ipa_cp_clone) |
ca30a539 JH |
442 | { |
443 | if (dump_file) | |
310bc633 MJ |
444 | fprintf (dump_file, "Not considering %s for cloning; " |
445 | "-fipa-cp-clone disabled.\n", | |
ca30a539 JH |
446 | cgraph_node_name (node)); |
447 | return false; | |
448 | } | |
ca30a539 | 449 | |
960bfb69 | 450 | if (!optimize_function_for_speed_p (DECL_STRUCT_FUNCTION (node->symbol.decl))) |
ca30a539 JH |
451 | { |
452 | if (dump_file) | |
310bc633 MJ |
453 | fprintf (dump_file, "Not considering %s for cloning; " |
454 | "optimizing it for size.\n", | |
ca30a539 JH |
455 | cgraph_node_name (node)); |
456 | return false; | |
457 | } | |
458 | ||
310bc633 MJ |
459 | init_caller_stats (&stats); |
460 | cgraph_for_node_and_aliases (node, gather_caller_stats, &stats, false); | |
461 | ||
462 | if (inline_summary (node)->self_size < stats.n_calls) | |
ca30a539 JH |
463 | { |
464 | if (dump_file) | |
310bc633 | 465 | fprintf (dump_file, "Considering %s for cloning; code might shrink.\n", |
ca30a539 | 466 | cgraph_node_name (node)); |
310bc633 | 467 | return true; |
ca30a539 JH |
468 | } |
469 | ||
470 | /* When profile is available and function is hot, propagate into it even if | |
471 | calls seems cold; constant propagation can improve function's speed | |
61502ca8 | 472 | significantly. */ |
ca30a539 JH |
473 | if (max_count) |
474 | { | |
310bc633 | 475 | if (stats.count_sum > node->count * 90 / 100) |
ca30a539 JH |
476 | { |
477 | if (dump_file) | |
310bc633 MJ |
478 | fprintf (dump_file, "Considering %s for cloning; " |
479 | "usually called directly.\n", | |
ca30a539 JH |
480 | cgraph_node_name (node)); |
481 | return true; | |
482 | } | |
483 | } | |
310bc633 | 484 | if (!stats.n_hot_calls) |
ca30a539 JH |
485 | { |
486 | if (dump_file) | |
487 | fprintf (dump_file, "Not considering %s for cloning; no hot calls.\n", | |
488 | cgraph_node_name (node)); | |
ed102b70 | 489 | return false; |
ca30a539 JH |
490 | } |
491 | if (dump_file) | |
492 | fprintf (dump_file, "Considering %s for cloning.\n", | |
493 | cgraph_node_name (node)); | |
494 | return true; | |
495 | } | |
496 | ||
310bc633 MJ |
497 | /* Arrays representing a topological ordering of call graph nodes and a stack |
498 | of noes used during constant propagation. */ | |
3949c4a7 | 499 | |
310bc633 | 500 | struct topo_info |
3949c4a7 | 501 | { |
310bc633 MJ |
502 | struct cgraph_node **order; |
503 | struct cgraph_node **stack; | |
504 | int nnodes, stack_top; | |
505 | }; | |
506 | ||
507 | /* Allocate the arrays in TOPO and topologically sort the nodes into order. */ | |
508 | ||
509 | static void | |
510 | build_toporder_info (struct topo_info *topo) | |
511 | { | |
512 | topo->order = XCNEWVEC (struct cgraph_node *, cgraph_n_nodes); | |
513 | topo->stack = XCNEWVEC (struct cgraph_node *, cgraph_n_nodes); | |
514 | topo->stack_top = 0; | |
515 | topo->nnodes = ipa_reduced_postorder (topo->order, true, true, NULL); | |
3949c4a7 MJ |
516 | } |
517 | ||
310bc633 MJ |
518 | /* Free information about strongly connected components and the arrays in |
519 | TOPO. */ | |
520 | ||
518dc859 | 521 | static void |
310bc633 MJ |
522 | free_toporder_info (struct topo_info *topo) |
523 | { | |
524 | ipa_free_postorder_info (); | |
525 | free (topo->order); | |
526 | free (topo->stack); | |
527 | } | |
528 | ||
529 | /* Add NODE to the stack in TOPO, unless it is already there. */ | |
530 | ||
531 | static inline void | |
532 | push_node_to_stack (struct topo_info *topo, struct cgraph_node *node) | |
518dc859 | 533 | { |
c43f07af | 534 | struct ipa_node_params *info = IPA_NODE_REF (node); |
310bc633 MJ |
535 | if (info->node_enqueued) |
536 | return; | |
537 | info->node_enqueued = 1; | |
538 | topo->stack[topo->stack_top++] = node; | |
539 | } | |
518dc859 | 540 | |
310bc633 MJ |
541 | /* Pop a node from the stack in TOPO and return it or return NULL if the stack |
542 | is empty. */ | |
ca30a539 | 543 | |
310bc633 MJ |
544 | static struct cgraph_node * |
545 | pop_node_from_stack (struct topo_info *topo) | |
546 | { | |
547 | if (topo->stack_top) | |
3949c4a7 | 548 | { |
310bc633 MJ |
549 | struct cgraph_node *node; |
550 | topo->stack_top--; | |
551 | node = topo->stack[topo->stack_top]; | |
552 | IPA_NODE_REF (node)->node_enqueued = 0; | |
553 | return node; | |
3949c4a7 | 554 | } |
310bc633 MJ |
555 | else |
556 | return NULL; | |
518dc859 RL |
557 | } |
558 | ||
310bc633 MJ |
559 | /* Set lattice LAT to bottom and return true if it previously was not set as |
560 | such. */ | |
561 | ||
562 | static inline bool | |
563 | set_lattice_to_bottom (struct ipcp_lattice *lat) | |
518dc859 | 564 | { |
310bc633 MJ |
565 | bool ret = !lat->bottom; |
566 | lat->bottom = true; | |
567 | return ret; | |
568 | } | |
518dc859 | 569 | |
310bc633 MJ |
570 | /* Mark lattice as containing an unknown value and return true if it previously |
571 | was not marked as such. */ | |
129a37fc | 572 | |
310bc633 MJ |
573 | static inline bool |
574 | set_lattice_contains_variable (struct ipcp_lattice *lat) | |
575 | { | |
576 | bool ret = !lat->contains_variable; | |
577 | lat->contains_variable = true; | |
578 | return ret; | |
518dc859 RL |
579 | } |
580 | ||
310bc633 | 581 | /* Initialize ipcp_lattices. */ |
43558bcc | 582 | |
518dc859 | 583 | static void |
310bc633 | 584 | initialize_node_lattices (struct cgraph_node *node) |
518dc859 | 585 | { |
310bc633 MJ |
586 | struct ipa_node_params *info = IPA_NODE_REF (node); |
587 | struct cgraph_edge *ie; | |
588 | bool disable = false, variable = false; | |
589 | int i; | |
518dc859 | 590 | |
310bc633 | 591 | gcc_checking_assert (cgraph_function_with_gimple_body_p (node)); |
d7da5cc8 | 592 | if (!node->local.local) |
310bc633 MJ |
593 | { |
594 | /* When cloning is allowed, we can assume that externally visible | |
595 | functions are not called. We will compensate this by cloning | |
596 | later. */ | |
597 | if (ipcp_versionable_function_p (node) | |
598 | && ipcp_cloning_candidate_p (node)) | |
599 | variable = true; | |
600 | else | |
601 | disable = true; | |
602 | } | |
518dc859 | 603 | |
310bc633 MJ |
604 | if (disable || variable) |
605 | { | |
606 | for (i = 0; i < ipa_get_param_count (info) ; i++) | |
607 | { | |
608 | struct ipcp_lattice *lat = ipa_get_lattice (info, i); | |
609 | if (disable) | |
610 | set_lattice_to_bottom (lat); | |
611 | else | |
612 | set_lattice_contains_variable (lat); | |
613 | } | |
614 | if (dump_file && (dump_flags & TDF_DETAILS) | |
615 | && node->alias && node->thunk.thunk_p) | |
616 | fprintf (dump_file, "Marking all lattices of %s/%i as %s\n", | |
617 | cgraph_node_name (node), node->uid, | |
618 | disable ? "BOTTOM" : "VARIABLE"); | |
619 | } | |
518dc859 | 620 | |
310bc633 MJ |
621 | for (ie = node->indirect_calls; ie; ie = ie->next_callee) |
622 | if (ie->indirect_info->polymorphic) | |
0818c24c | 623 | { |
310bc633 MJ |
624 | gcc_checking_assert (ie->indirect_info->param_index >= 0); |
625 | ipa_get_lattice (info, ie->indirect_info->param_index)->virt_call = 1; | |
0818c24c | 626 | } |
518dc859 RL |
627 | } |
628 | ||
310bc633 MJ |
629 | /* Return the result of a (possibly arithmetic) pass through jump function |
630 | JFUNC on the constant value INPUT. Return NULL_TREE if that cannot be | |
631 | determined or itself is considered an interprocedural invariant. */ | |
3949c4a7 | 632 | |
310bc633 MJ |
633 | static tree |
634 | ipa_get_jf_pass_through_result (struct ipa_jump_func *jfunc, tree input) | |
3949c4a7 | 635 | { |
310bc633 | 636 | tree restype, res; |
3949c4a7 | 637 | |
7b872d9e | 638 | if (ipa_get_jf_pass_through_operation (jfunc) == NOP_EXPR) |
310bc633 | 639 | return input; |
7b872d9e MJ |
640 | else if (TREE_CODE (input) == TREE_BINFO) |
641 | return NULL_TREE; | |
3949c4a7 | 642 | |
7b872d9e MJ |
643 | gcc_checking_assert (is_gimple_ip_invariant (input)); |
644 | if (TREE_CODE_CLASS (ipa_get_jf_pass_through_operation (jfunc)) | |
310bc633 MJ |
645 | == tcc_comparison) |
646 | restype = boolean_type_node; | |
647 | else | |
648 | restype = TREE_TYPE (input); | |
7b872d9e MJ |
649 | res = fold_binary (ipa_get_jf_pass_through_operation (jfunc), restype, |
650 | input, ipa_get_jf_pass_through_operand (jfunc)); | |
3949c4a7 | 651 | |
310bc633 MJ |
652 | if (res && !is_gimple_ip_invariant (res)) |
653 | return NULL_TREE; | |
3949c4a7 | 654 | |
310bc633 | 655 | return res; |
3949c4a7 MJ |
656 | } |
657 | ||
310bc633 MJ |
658 | /* Return the result of an ancestor jump function JFUNC on the constant value |
659 | INPUT. Return NULL_TREE if that cannot be determined. */ | |
3949c4a7 | 660 | |
310bc633 MJ |
661 | static tree |
662 | ipa_get_jf_ancestor_result (struct ipa_jump_func *jfunc, tree input) | |
3949c4a7 | 663 | { |
7b872d9e MJ |
664 | if (TREE_CODE (input) == TREE_BINFO) |
665 | return get_binfo_at_offset (input, | |
666 | ipa_get_jf_ancestor_offset (jfunc), | |
667 | ipa_get_jf_ancestor_type (jfunc)); | |
668 | else if (TREE_CODE (input) == ADDR_EXPR) | |
3949c4a7 | 669 | { |
310bc633 MJ |
670 | tree t = TREE_OPERAND (input, 0); |
671 | t = build_ref_for_offset (EXPR_LOCATION (t), t, | |
7b872d9e MJ |
672 | ipa_get_jf_ancestor_offset (jfunc), |
673 | ipa_get_jf_ancestor_type (jfunc), NULL, false); | |
310bc633 | 674 | return build_fold_addr_expr (t); |
3949c4a7 MJ |
675 | } |
676 | else | |
310bc633 MJ |
677 | return NULL_TREE; |
678 | } | |
3949c4a7 | 679 | |
c7573249 MJ |
680 | /* Extract the acual BINFO being described by JFUNC which must be a known type |
681 | jump function. */ | |
682 | ||
683 | static tree | |
684 | ipa_value_from_known_type_jfunc (struct ipa_jump_func *jfunc) | |
685 | { | |
7b872d9e | 686 | tree base_binfo = TYPE_BINFO (ipa_get_jf_known_type_base_type (jfunc)); |
c7573249 MJ |
687 | if (!base_binfo) |
688 | return NULL_TREE; | |
689 | return get_binfo_at_offset (base_binfo, | |
7b872d9e MJ |
690 | ipa_get_jf_known_type_offset (jfunc), |
691 | ipa_get_jf_known_type_component_type (jfunc)); | |
c7573249 MJ |
692 | } |
693 | ||
310bc633 MJ |
694 | /* Determine whether JFUNC evaluates to a known value (that is either a |
695 | constant or a binfo) and if so, return it. Otherwise return NULL. INFO | |
696 | describes the caller node so that pass-through jump functions can be | |
697 | evaluated. */ | |
698 | ||
d2d668fb | 699 | tree |
310bc633 MJ |
700 | ipa_value_from_jfunc (struct ipa_node_params *info, struct ipa_jump_func *jfunc) |
701 | { | |
702 | if (jfunc->type == IPA_JF_CONST) | |
7b872d9e | 703 | return ipa_get_jf_constant (jfunc); |
310bc633 | 704 | else if (jfunc->type == IPA_JF_KNOWN_TYPE) |
c7573249 | 705 | return ipa_value_from_known_type_jfunc (jfunc); |
310bc633 MJ |
706 | else if (jfunc->type == IPA_JF_PASS_THROUGH |
707 | || jfunc->type == IPA_JF_ANCESTOR) | |
3949c4a7 | 708 | { |
310bc633 MJ |
709 | tree input; |
710 | int idx; | |
3949c4a7 | 711 | |
310bc633 | 712 | if (jfunc->type == IPA_JF_PASS_THROUGH) |
7b872d9e | 713 | idx = ipa_get_jf_pass_through_formal_id (jfunc); |
310bc633 | 714 | else |
7b872d9e | 715 | idx = ipa_get_jf_ancestor_formal_id (jfunc); |
3949c4a7 | 716 | |
310bc633 MJ |
717 | if (info->ipcp_orig_node) |
718 | input = VEC_index (tree, info->known_vals, idx); | |
719 | else | |
3949c4a7 | 720 | { |
310bc633 MJ |
721 | struct ipcp_lattice *lat; |
722 | ||
723 | if (!info->lattices) | |
3949c4a7 | 724 | { |
310bc633 MJ |
725 | gcc_checking_assert (!flag_ipa_cp); |
726 | return NULL_TREE; | |
3949c4a7 | 727 | } |
310bc633 MJ |
728 | lat = ipa_get_lattice (info, idx); |
729 | if (!ipa_lat_is_single_const (lat)) | |
730 | return NULL_TREE; | |
731 | input = lat->values->value; | |
732 | } | |
733 | ||
734 | if (!input) | |
735 | return NULL_TREE; | |
736 | ||
737 | if (jfunc->type == IPA_JF_PASS_THROUGH) | |
7b872d9e | 738 | return ipa_get_jf_pass_through_result (jfunc, input); |
310bc633 | 739 | else |
7b872d9e | 740 | return ipa_get_jf_ancestor_result (jfunc, input); |
3949c4a7 | 741 | } |
310bc633 MJ |
742 | else |
743 | return NULL_TREE; | |
3949c4a7 MJ |
744 | } |
745 | ||
3949c4a7 | 746 | |
310bc633 MJ |
747 | /* If checking is enabled, verify that no lattice is in the TOP state, i.e. not |
748 | bottom, not containing a variable component and without any known value at | |
749 | the same time. */ | |
3949c4a7 | 750 | |
310bc633 MJ |
751 | DEBUG_FUNCTION void |
752 | ipcp_verify_propagated_values (void) | |
518dc859 | 753 | { |
310bc633 | 754 | struct cgraph_node *node; |
ca30a539 | 755 | |
310bc633 | 756 | FOR_EACH_FUNCTION_WITH_GIMPLE_BODY (node) |
518dc859 | 757 | { |
c43f07af | 758 | struct ipa_node_params *info = IPA_NODE_REF (node); |
310bc633 | 759 | int i, count = ipa_get_param_count (info); |
c43f07af | 760 | |
310bc633 | 761 | for (i = 0; i < count; i++) |
518dc859 | 762 | { |
310bc633 | 763 | struct ipcp_lattice *lat = ipa_get_lattice (info, i); |
c43f07af | 764 | |
310bc633 MJ |
765 | if (!lat->bottom |
766 | && !lat->contains_variable | |
767 | && lat->values_count == 0) | |
518dc859 | 768 | { |
310bc633 | 769 | if (dump_file) |
518dc859 | 770 | { |
310bc633 MJ |
771 | fprintf (dump_file, "\nIPA lattices after constant " |
772 | "propagation:\n"); | |
773 | print_all_lattices (dump_file, true, false); | |
518dc859 | 774 | } |
3949c4a7 | 775 | |
310bc633 | 776 | gcc_unreachable (); |
518dc859 RL |
777 | } |
778 | } | |
779 | } | |
780 | } | |
781 | ||
310bc633 MJ |
782 | /* Return true iff X and Y should be considered equal values by IPA-CP. */ |
783 | ||
784 | static bool | |
785 | values_equal_for_ipcp_p (tree x, tree y) | |
786 | { | |
787 | gcc_checking_assert (x != NULL_TREE && y != NULL_TREE); | |
788 | ||
789 | if (x == y) | |
790 | return true; | |
791 | ||
792 | if (TREE_CODE (x) == TREE_BINFO || TREE_CODE (y) == TREE_BINFO) | |
793 | return false; | |
794 | ||
795 | if (TREE_CODE (x) == ADDR_EXPR | |
796 | && TREE_CODE (y) == ADDR_EXPR | |
797 | && TREE_CODE (TREE_OPERAND (x, 0)) == CONST_DECL | |
798 | && TREE_CODE (TREE_OPERAND (y, 0)) == CONST_DECL) | |
799 | return operand_equal_p (DECL_INITIAL (TREE_OPERAND (x, 0)), | |
800 | DECL_INITIAL (TREE_OPERAND (y, 0)), 0); | |
801 | else | |
802 | return operand_equal_p (x, y, 0); | |
803 | } | |
804 | ||
805 | /* Add a new value source to VAL, marking that a value comes from edge CS and | |
806 | (if the underlying jump function is a pass-through or an ancestor one) from | |
807 | a caller value SRC_VAL of a caller parameter described by SRC_INDEX. */ | |
808 | ||
518dc859 | 809 | static void |
310bc633 MJ |
810 | add_value_source (struct ipcp_value *val, struct cgraph_edge *cs, |
811 | struct ipcp_value *src_val, int src_idx) | |
518dc859 | 812 | { |
310bc633 | 813 | struct ipcp_value_source *src; |
ca30a539 | 814 | |
310bc633 MJ |
815 | src = (struct ipcp_value_source *) pool_alloc (ipcp_sources_pool); |
816 | src->cs = cs; | |
817 | src->val = src_val; | |
818 | src->index = src_idx; | |
fb3f88cc | 819 | |
310bc633 MJ |
820 | src->next = val->sources; |
821 | val->sources = src; | |
822 | } | |
823 | ||
824 | ||
825 | /* Try to add NEWVAL to LAT, potentially creating a new struct ipcp_value for | |
826 | it. CS, SRC_VAL and SRC_INDEX are meant for add_value_source and have the | |
827 | same meaning. */ | |
828 | ||
829 | static bool | |
830 | add_value_to_lattice (struct ipcp_lattice *lat, tree newval, | |
831 | struct cgraph_edge *cs, struct ipcp_value *src_val, | |
832 | int src_idx) | |
833 | { | |
834 | struct ipcp_value *val; | |
835 | ||
836 | if (lat->bottom) | |
837 | return false; | |
838 | ||
839 | ||
840 | for (val = lat->values; val; val = val->next) | |
841 | if (values_equal_for_ipcp_p (val->value, newval)) | |
842 | { | |
843 | if (edge_within_scc (cs)) | |
844 | { | |
845 | struct ipcp_value_source *s; | |
846 | for (s = val->sources; s ; s = s->next) | |
847 | if (s->cs == cs) | |
848 | break; | |
849 | if (s) | |
850 | return false; | |
851 | } | |
852 | ||
853 | add_value_source (val, cs, src_val, src_idx); | |
854 | return false; | |
855 | } | |
856 | ||
857 | if (lat->values_count == PARAM_VALUE (PARAM_IPA_CP_VALUE_LIST_SIZE)) | |
858 | { | |
859 | /* We can only free sources, not the values themselves, because sources | |
860 | of other values in this this SCC might point to them. */ | |
861 | for (val = lat->values; val; val = val->next) | |
862 | { | |
863 | while (val->sources) | |
864 | { | |
865 | struct ipcp_value_source *src = val->sources; | |
866 | val->sources = src->next; | |
867 | pool_free (ipcp_sources_pool, src); | |
868 | } | |
869 | } | |
870 | ||
871 | lat->values = NULL; | |
872 | return set_lattice_to_bottom (lat); | |
873 | } | |
874 | ||
875 | lat->values_count++; | |
876 | val = (struct ipcp_value *) pool_alloc (ipcp_values_pool); | |
877 | memset (val, 0, sizeof (*val)); | |
878 | ||
879 | add_value_source (val, cs, src_val, src_idx); | |
880 | val->value = newval; | |
881 | val->next = lat->values; | |
882 | lat->values = val; | |
883 | return true; | |
884 | } | |
fb3f88cc | 885 | |
310bc633 MJ |
886 | /* Propagate values through a pass-through jump function JFUNC associated with |
887 | edge CS, taking values from SRC_LAT and putting them into DEST_LAT. SRC_IDX | |
888 | is the index of the source parameter. */ | |
889 | ||
890 | static bool | |
891 | propagate_vals_accross_pass_through (struct cgraph_edge *cs, | |
892 | struct ipa_jump_func *jfunc, | |
893 | struct ipcp_lattice *src_lat, | |
894 | struct ipcp_lattice *dest_lat, | |
895 | int src_idx) | |
896 | { | |
897 | struct ipcp_value *src_val; | |
898 | bool ret = false; | |
899 | ||
7b872d9e | 900 | if (ipa_get_jf_pass_through_operation (jfunc) == NOP_EXPR) |
310bc633 MJ |
901 | for (src_val = src_lat->values; src_val; src_val = src_val->next) |
902 | ret |= add_value_to_lattice (dest_lat, src_val->value, cs, | |
903 | src_val, src_idx); | |
904 | /* Do not create new values when propagating within an SCC because if there | |
7b872d9e MJ |
905 | are arithmetic functions with circular dependencies, there is infinite |
906 | number of them and we would just make lattices bottom. */ | |
310bc633 MJ |
907 | else if (edge_within_scc (cs)) |
908 | ret = set_lattice_contains_variable (dest_lat); | |
909 | else | |
910 | for (src_val = src_lat->values; src_val; src_val = src_val->next) | |
0818c24c | 911 | { |
310bc633 MJ |
912 | tree cstval = src_val->value; |
913 | ||
914 | if (TREE_CODE (cstval) == TREE_BINFO) | |
915 | { | |
916 | ret |= set_lattice_contains_variable (dest_lat); | |
917 | continue; | |
918 | } | |
919 | cstval = ipa_get_jf_pass_through_result (jfunc, cstval); | |
920 | ||
921 | if (cstval) | |
922 | ret |= add_value_to_lattice (dest_lat, cstval, cs, src_val, src_idx); | |
923 | else | |
924 | ret |= set_lattice_contains_variable (dest_lat); | |
0818c24c | 925 | } |
310bc633 MJ |
926 | |
927 | return ret; | |
928 | } | |
929 | ||
930 | /* Propagate values through an ancestor jump function JFUNC associated with | |
931 | edge CS, taking values from SRC_LAT and putting them into DEST_LAT. SRC_IDX | |
932 | is the index of the source parameter. */ | |
933 | ||
934 | static bool | |
935 | propagate_vals_accross_ancestor (struct cgraph_edge *cs, | |
936 | struct ipa_jump_func *jfunc, | |
937 | struct ipcp_lattice *src_lat, | |
938 | struct ipcp_lattice *dest_lat, | |
939 | int src_idx) | |
940 | { | |
941 | struct ipcp_value *src_val; | |
942 | bool ret = false; | |
943 | ||
944 | if (edge_within_scc (cs)) | |
945 | return set_lattice_contains_variable (dest_lat); | |
946 | ||
947 | for (src_val = src_lat->values; src_val; src_val = src_val->next) | |
948 | { | |
7b872d9e | 949 | tree t = ipa_get_jf_ancestor_result (jfunc, src_val->value); |
310bc633 MJ |
950 | |
951 | if (t) | |
952 | ret |= add_value_to_lattice (dest_lat, t, cs, src_val, src_idx); | |
953 | else | |
954 | ret |= set_lattice_contains_variable (dest_lat); | |
955 | } | |
956 | ||
957 | return ret; | |
958 | } | |
959 | ||
960 | /* Propagate values across jump function JFUNC that is associated with edge CS | |
961 | and put the values into DEST_LAT. */ | |
962 | ||
963 | static bool | |
964 | propagate_accross_jump_function (struct cgraph_edge *cs, | |
965 | struct ipa_jump_func *jfunc, | |
966 | struct ipcp_lattice *dest_lat) | |
967 | { | |
968 | if (dest_lat->bottom) | |
969 | return false; | |
970 | ||
971 | if (jfunc->type == IPA_JF_CONST | |
972 | || jfunc->type == IPA_JF_KNOWN_TYPE) | |
973 | { | |
974 | tree val; | |
975 | ||
976 | if (jfunc->type == IPA_JF_KNOWN_TYPE) | |
c7573249 MJ |
977 | { |
978 | val = ipa_value_from_known_type_jfunc (jfunc); | |
979 | if (!val) | |
980 | return set_lattice_contains_variable (dest_lat); | |
981 | } | |
310bc633 | 982 | else |
7b872d9e | 983 | val = ipa_get_jf_constant (jfunc); |
310bc633 MJ |
984 | return add_value_to_lattice (dest_lat, val, cs, NULL, 0); |
985 | } | |
986 | else if (jfunc->type == IPA_JF_PASS_THROUGH | |
987 | || jfunc->type == IPA_JF_ANCESTOR) | |
988 | { | |
989 | struct ipa_node_params *caller_info = IPA_NODE_REF (cs->caller); | |
990 | struct ipcp_lattice *src_lat; | |
991 | int src_idx; | |
992 | bool ret; | |
993 | ||
994 | if (jfunc->type == IPA_JF_PASS_THROUGH) | |
7b872d9e | 995 | src_idx = ipa_get_jf_pass_through_formal_id (jfunc); |
310bc633 | 996 | else |
7b872d9e | 997 | src_idx = ipa_get_jf_ancestor_formal_id (jfunc); |
310bc633 MJ |
998 | |
999 | src_lat = ipa_get_lattice (caller_info, src_idx); | |
1000 | if (src_lat->bottom) | |
1001 | return set_lattice_contains_variable (dest_lat); | |
1002 | ||
1003 | /* If we would need to clone the caller and cannot, do not propagate. */ | |
1004 | if (!ipcp_versionable_function_p (cs->caller) | |
1005 | && (src_lat->contains_variable | |
1006 | || (src_lat->values_count > 1))) | |
1007 | return set_lattice_contains_variable (dest_lat); | |
1008 | ||
1009 | if (jfunc->type == IPA_JF_PASS_THROUGH) | |
1010 | ret = propagate_vals_accross_pass_through (cs, jfunc, src_lat, | |
1011 | dest_lat, src_idx); | |
1012 | else | |
1013 | ret = propagate_vals_accross_ancestor (cs, jfunc, src_lat, dest_lat, | |
1014 | src_idx); | |
1015 | ||
1016 | if (src_lat->contains_variable) | |
1017 | ret |= set_lattice_contains_variable (dest_lat); | |
1018 | ||
1019 | return ret; | |
1020 | } | |
1021 | ||
1022 | /* TODO: We currently do not handle member method pointers in IPA-CP (we only | |
1023 | use it for indirect inlining), we should propagate them too. */ | |
1024 | return set_lattice_contains_variable (dest_lat); | |
1025 | } | |
1026 | ||
1027 | /* Propagate constants from the caller to the callee of CS. INFO describes the | |
1028 | caller. */ | |
1029 | ||
1030 | static bool | |
1031 | propagate_constants_accross_call (struct cgraph_edge *cs) | |
1032 | { | |
1033 | struct ipa_node_params *callee_info; | |
1034 | enum availability availability; | |
1035 | struct cgraph_node *callee, *alias_or_thunk; | |
1036 | struct ipa_edge_args *args; | |
1037 | bool ret = false; | |
d7da5cc8 | 1038 | int i, args_count, parms_count; |
310bc633 MJ |
1039 | |
1040 | callee = cgraph_function_node (cs->callee, &availability); | |
1041 | if (!callee->analyzed) | |
1042 | return false; | |
1043 | gcc_checking_assert (cgraph_function_with_gimple_body_p (callee)); | |
1044 | callee_info = IPA_NODE_REF (callee); | |
310bc633 MJ |
1045 | |
1046 | args = IPA_EDGE_REF (cs); | |
d7da5cc8 MJ |
1047 | args_count = ipa_get_cs_argument_count (args); |
1048 | parms_count = ipa_get_param_count (callee_info); | |
310bc633 MJ |
1049 | |
1050 | /* If this call goes through a thunk we must not propagate to the first (0th) | |
1051 | parameter. However, we might need to uncover a thunk from below a series | |
1052 | of aliases first. */ | |
1053 | alias_or_thunk = cs->callee; | |
1054 | while (alias_or_thunk->alias) | |
1055 | alias_or_thunk = cgraph_alias_aliased_node (alias_or_thunk); | |
1056 | if (alias_or_thunk->thunk.thunk_p) | |
1057 | { | |
1058 | ret |= set_lattice_contains_variable (ipa_get_lattice (callee_info, 0)); | |
1059 | i = 1; | |
1060 | } | |
1061 | else | |
1062 | i = 0; | |
1063 | ||
d7da5cc8 | 1064 | for (; (i < args_count) && (i < parms_count); i++) |
310bc633 MJ |
1065 | { |
1066 | struct ipa_jump_func *jump_func = ipa_get_ith_jump_func (args, i); | |
1067 | struct ipcp_lattice *dest_lat = ipa_get_lattice (callee_info, i); | |
1068 | ||
1069 | if (availability == AVAIL_OVERWRITABLE) | |
1070 | ret |= set_lattice_contains_variable (dest_lat); | |
1071 | else | |
1072 | ret |= propagate_accross_jump_function (cs, jump_func, dest_lat); | |
1073 | } | |
d7da5cc8 MJ |
1074 | for (; i < parms_count; i++) |
1075 | ret |= set_lattice_contains_variable (ipa_get_lattice (callee_info, i)); | |
1076 | ||
310bc633 MJ |
1077 | return ret; |
1078 | } | |
1079 | ||
1080 | /* If an indirect edge IE can be turned into a direct one based on KNOWN_VALS | |
1081 | (which can contain both constants and binfos) or KNOWN_BINFOS (which can be | |
81fa35bd | 1082 | NULL) return the destination. */ |
310bc633 | 1083 | |
d2d668fb MK |
1084 | tree |
1085 | ipa_get_indirect_edge_target (struct cgraph_edge *ie, | |
1086 | VEC (tree, heap) *known_vals, | |
8810cc52 MJ |
1087 | VEC (tree, heap) *known_binfos, |
1088 | VEC (ipa_agg_jump_function_p, heap) *known_aggs) | |
310bc633 MJ |
1089 | { |
1090 | int param_index = ie->indirect_info->param_index; | |
1091 | HOST_WIDE_INT token, anc_offset; | |
1092 | tree otr_type; | |
1093 | tree t; | |
1094 | ||
1095 | if (param_index == -1) | |
1096 | return NULL_TREE; | |
1097 | ||
1098 | if (!ie->indirect_info->polymorphic) | |
1099 | { | |
8810cc52 MJ |
1100 | tree t; |
1101 | ||
1102 | if (ie->indirect_info->agg_contents) | |
1103 | { | |
1104 | if (VEC_length (ipa_agg_jump_function_p, known_aggs) | |
1105 | > (unsigned int) param_index) | |
1106 | { | |
1107 | struct ipa_agg_jump_function *agg; | |
1108 | agg = VEC_index (ipa_agg_jump_function_p, known_aggs, | |
1109 | param_index); | |
1110 | t = ipa_find_agg_cst_for_param (agg, ie->indirect_info->offset, | |
1111 | ie->indirect_info->by_ref); | |
1112 | } | |
1113 | else | |
1114 | t = NULL; | |
1115 | } | |
1116 | else | |
1117 | t = (VEC_length (tree, known_vals) > (unsigned int) param_index | |
1118 | ? VEC_index (tree, known_vals, param_index) : NULL); | |
1119 | ||
310bc633 MJ |
1120 | if (t && |
1121 | TREE_CODE (t) == ADDR_EXPR | |
1122 | && TREE_CODE (TREE_OPERAND (t, 0)) == FUNCTION_DECL) | |
81fa35bd | 1123 | return TREE_OPERAND (t, 0); |
310bc633 MJ |
1124 | else |
1125 | return NULL_TREE; | |
1126 | } | |
1127 | ||
8810cc52 | 1128 | gcc_assert (!ie->indirect_info->agg_contents); |
310bc633 | 1129 | token = ie->indirect_info->otr_token; |
8b7773a4 | 1130 | anc_offset = ie->indirect_info->offset; |
310bc633 MJ |
1131 | otr_type = ie->indirect_info->otr_type; |
1132 | ||
1133 | t = VEC_index (tree, known_vals, param_index); | |
9ab6f957 ILT |
1134 | if (!t && known_binfos |
1135 | && VEC_length (tree, known_binfos) > (unsigned int) param_index) | |
310bc633 MJ |
1136 | t = VEC_index (tree, known_binfos, param_index); |
1137 | if (!t) | |
1138 | return NULL_TREE; | |
1139 | ||
1140 | if (TREE_CODE (t) != TREE_BINFO) | |
1141 | { | |
1142 | tree binfo; | |
1143 | binfo = gimple_extract_devirt_binfo_from_cst (t); | |
1144 | if (!binfo) | |
1145 | return NULL_TREE; | |
1146 | binfo = get_binfo_at_offset (binfo, anc_offset, otr_type); | |
1147 | if (!binfo) | |
1148 | return NULL_TREE; | |
81fa35bd | 1149 | return gimple_get_virt_method_for_binfo (token, binfo); |
310bc633 MJ |
1150 | } |
1151 | else | |
1152 | { | |
1153 | tree binfo; | |
1154 | ||
1155 | binfo = get_binfo_at_offset (t, anc_offset, otr_type); | |
1156 | if (!binfo) | |
1157 | return NULL_TREE; | |
81fa35bd | 1158 | return gimple_get_virt_method_for_binfo (token, binfo); |
310bc633 MJ |
1159 | } |
1160 | } | |
1161 | ||
1162 | /* Calculate devirtualization time bonus for NODE, assuming we know KNOWN_CSTS | |
1163 | and KNOWN_BINFOS. */ | |
1164 | ||
1165 | static int | |
1166 | devirtualization_time_bonus (struct cgraph_node *node, | |
1167 | VEC (tree, heap) *known_csts, | |
1168 | VEC (tree, heap) *known_binfos) | |
1169 | { | |
1170 | struct cgraph_edge *ie; | |
1171 | int res = 0; | |
1172 | ||
1173 | for (ie = node->indirect_calls; ie; ie = ie->next_callee) | |
1174 | { | |
1175 | struct cgraph_node *callee; | |
1176 | struct inline_summary *isummary; | |
81fa35bd | 1177 | tree target; |
310bc633 | 1178 | |
8810cc52 MJ |
1179 | target = ipa_get_indirect_edge_target (ie, known_csts, known_binfos, |
1180 | NULL); | |
310bc633 MJ |
1181 | if (!target) |
1182 | continue; | |
1183 | ||
1184 | /* Only bare minimum benefit for clearly un-inlineable targets. */ | |
1185 | res += 1; | |
1186 | callee = cgraph_get_node (target); | |
1187 | if (!callee || !callee->analyzed) | |
1188 | continue; | |
1189 | isummary = inline_summary (callee); | |
1190 | if (!isummary->inlinable) | |
1191 | continue; | |
1192 | ||
1193 | /* FIXME: The values below need re-considering and perhaps also | |
1194 | integrating into the cost metrics, at lest in some very basic way. */ | |
1195 | if (isummary->size <= MAX_INLINE_INSNS_AUTO / 4) | |
1196 | res += 31; | |
1197 | else if (isummary->size <= MAX_INLINE_INSNS_AUTO / 2) | |
1198 | res += 15; | |
1199 | else if (isummary->size <= MAX_INLINE_INSNS_AUTO | |
960bfb69 | 1200 | || DECL_DECLARED_INLINE_P (callee->symbol.decl)) |
310bc633 MJ |
1201 | res += 7; |
1202 | } | |
1203 | ||
1204 | return res; | |
1205 | } | |
1206 | ||
1207 | /* Return true if cloning NODE is a good idea, given the estimated TIME_BENEFIT | |
1208 | and SIZE_COST and with the sum of frequencies of incoming edges to the | |
1209 | potential new clone in FREQUENCIES. */ | |
1210 | ||
1211 | static bool | |
1212 | good_cloning_opportunity_p (struct cgraph_node *node, int time_benefit, | |
1213 | int freq_sum, gcov_type count_sum, int size_cost) | |
1214 | { | |
1215 | if (time_benefit == 0 | |
1216 | || !flag_ipa_cp_clone | |
960bfb69 | 1217 | || !optimize_function_for_speed_p (DECL_STRUCT_FUNCTION (node->symbol.decl))) |
310bc633 MJ |
1218 | return false; |
1219 | ||
df0227c4 | 1220 | gcc_assert (size_cost > 0); |
310bc633 | 1221 | |
310bc633 MJ |
1222 | if (max_count) |
1223 | { | |
df0227c4 MJ |
1224 | int factor = (count_sum * 1000) / max_count; |
1225 | HOST_WIDEST_INT evaluation = (((HOST_WIDEST_INT) time_benefit * factor) | |
1226 | / size_cost); | |
310bc633 MJ |
1227 | |
1228 | if (dump_file && (dump_flags & TDF_DETAILS)) | |
1229 | fprintf (dump_file, " good_cloning_opportunity_p (time: %i, " | |
1230 | "size: %i, count_sum: " HOST_WIDE_INT_PRINT_DEC | |
df0227c4 MJ |
1231 | ") -> evaluation: " HOST_WIDEST_INT_PRINT_DEC |
1232 | ", threshold: %i\n", | |
310bc633 MJ |
1233 | time_benefit, size_cost, (HOST_WIDE_INT) count_sum, |
1234 | evaluation, 500); | |
1235 | ||
1236 | return evaluation >= PARAM_VALUE (PARAM_IPA_CP_EVAL_THRESHOLD); | |
1237 | } | |
1238 | else | |
1239 | { | |
df0227c4 MJ |
1240 | HOST_WIDEST_INT evaluation = (((HOST_WIDEST_INT) time_benefit * freq_sum) |
1241 | / size_cost); | |
310bc633 MJ |
1242 | |
1243 | if (dump_file && (dump_flags & TDF_DETAILS)) | |
1244 | fprintf (dump_file, " good_cloning_opportunity_p (time: %i, " | |
df0227c4 MJ |
1245 | "size: %i, freq_sum: %i) -> evaluation: " |
1246 | HOST_WIDEST_INT_PRINT_DEC ", threshold: %i\n", | |
310bc633 MJ |
1247 | time_benefit, size_cost, freq_sum, evaluation, |
1248 | CGRAPH_FREQ_BASE /2); | |
1249 | ||
1250 | return evaluation >= PARAM_VALUE (PARAM_IPA_CP_EVAL_THRESHOLD); | |
1251 | } | |
1252 | } | |
1253 | ||
1254 | ||
1255 | /* Allocate KNOWN_CSTS and KNOWN_BINFOS and populate them with values of | |
1256 | parameters that are known independent of the context. INFO describes the | |
1257 | function. If REMOVABLE_PARAMS_COST is non-NULL, the movement cost of all | |
1258 | removable parameters will be stored in it. */ | |
1259 | ||
1260 | static bool | |
1261 | gather_context_independent_values (struct ipa_node_params *info, | |
1262 | VEC (tree, heap) **known_csts, | |
1263 | VEC (tree, heap) **known_binfos, | |
1264 | int *removable_params_cost) | |
1265 | { | |
1266 | int i, count = ipa_get_param_count (info); | |
1267 | bool ret = false; | |
1268 | ||
1269 | *known_csts = NULL; | |
1270 | *known_binfos = NULL; | |
1271 | VEC_safe_grow_cleared (tree, heap, *known_csts, count); | |
1272 | VEC_safe_grow_cleared (tree, heap, *known_binfos, count); | |
1273 | ||
1274 | if (removable_params_cost) | |
1275 | *removable_params_cost = 0; | |
1276 | ||
1277 | for (i = 0; i < count ; i++) | |
1278 | { | |
1279 | struct ipcp_lattice *lat = ipa_get_lattice (info, i); | |
1280 | ||
1281 | if (ipa_lat_is_single_const (lat)) | |
1282 | { | |
1283 | struct ipcp_value *val = lat->values; | |
1284 | if (TREE_CODE (val->value) != TREE_BINFO) | |
1285 | { | |
1286 | VEC_replace (tree, *known_csts, i, val->value); | |
1287 | if (removable_params_cost) | |
1288 | *removable_params_cost | |
1289 | += estimate_move_cost (TREE_TYPE (val->value)); | |
1290 | ret = true; | |
1291 | } | |
1292 | else if (lat->virt_call) | |
1293 | { | |
1294 | VEC_replace (tree, *known_binfos, i, val->value); | |
1295 | ret = true; | |
1296 | } | |
1297 | else if (removable_params_cost | |
1298 | && !ipa_is_param_used (info, i)) | |
1299 | *removable_params_cost | |
1300 | += estimate_move_cost (TREE_TYPE (ipa_get_param (info, i))); | |
1301 | } | |
1302 | else if (removable_params_cost | |
1303 | && !ipa_is_param_used (info, i)) | |
1304 | *removable_params_cost | |
1305 | += estimate_move_cost (TREE_TYPE (ipa_get_param (info, i))); | |
1306 | } | |
1307 | ||
1308 | return ret; | |
1309 | } | |
1310 | ||
1311 | /* Iterate over known values of parameters of NODE and estimate the local | |
1312 | effects in terms of time and size they have. */ | |
1313 | ||
1314 | static void | |
1315 | estimate_local_effects (struct cgraph_node *node) | |
1316 | { | |
1317 | struct ipa_node_params *info = IPA_NODE_REF (node); | |
1318 | int i, count = ipa_get_param_count (info); | |
1319 | VEC (tree, heap) *known_csts, *known_binfos; | |
1320 | bool always_const; | |
1321 | int base_time = inline_summary (node)->time; | |
1322 | int removable_params_cost; | |
1323 | ||
1324 | if (!count || !ipcp_versionable_function_p (node)) | |
1325 | return; | |
1326 | ||
ca30a539 | 1327 | if (dump_file && (dump_flags & TDF_DETAILS)) |
310bc633 MJ |
1328 | fprintf (dump_file, "\nEstimating effects for %s/%i, base_time: %i.\n", |
1329 | cgraph_node_name (node), node->uid, base_time); | |
1330 | ||
1331 | always_const = gather_context_independent_values (info, &known_csts, | |
1332 | &known_binfos, | |
1333 | &removable_params_cost); | |
1334 | if (always_const) | |
ca30a539 | 1335 | { |
310bc633 MJ |
1336 | struct caller_statistics stats; |
1337 | int time, size; | |
1338 | ||
1339 | init_caller_stats (&stats); | |
1340 | cgraph_for_node_and_aliases (node, gather_caller_stats, &stats, false); | |
d2d668fb MK |
1341 | estimate_ipcp_clone_size_and_time (node, known_csts, known_binfos, |
1342 | &size, &time); | |
310bc633 MJ |
1343 | time -= devirtualization_time_bonus (node, known_csts, known_binfos); |
1344 | time -= removable_params_cost; | |
1345 | size -= stats.n_calls * removable_params_cost; | |
1346 | ||
1347 | if (dump_file) | |
1348 | fprintf (dump_file, " - context independent values, size: %i, " | |
1349 | "time_benefit: %i\n", size, base_time - time); | |
1350 | ||
1351 | if (size <= 0 | |
1352 | || cgraph_will_be_removed_from_program_if_no_direct_calls (node)) | |
1353 | { | |
1354 | info->clone_for_all_contexts = true; | |
1355 | base_time = time; | |
1356 | ||
1357 | if (dump_file) | |
1358 | fprintf (dump_file, " Decided to specialize for all " | |
1359 | "known contexts, code not going to grow.\n"); | |
1360 | } | |
1361 | else if (good_cloning_opportunity_p (node, base_time - time, | |
1362 | stats.freq_sum, stats.count_sum, | |
1363 | size)) | |
1364 | { | |
1365 | if (size + overall_size <= max_new_size) | |
1366 | { | |
1367 | info->clone_for_all_contexts = true; | |
1368 | base_time = time; | |
1369 | overall_size += size; | |
1370 | ||
1371 | if (dump_file) | |
1372 | fprintf (dump_file, " Decided to specialize for all " | |
1373 | "known contexts, growth deemed beneficial.\n"); | |
1374 | } | |
1375 | else if (dump_file && (dump_flags & TDF_DETAILS)) | |
1376 | fprintf (dump_file, " Not cloning for all contexts because " | |
1377 | "max_new_size would be reached with %li.\n", | |
1378 | size + overall_size); | |
1379 | } | |
ca30a539 JH |
1380 | } |
1381 | ||
310bc633 | 1382 | for (i = 0; i < count ; i++) |
ca30a539 | 1383 | { |
310bc633 MJ |
1384 | struct ipcp_lattice *lat = ipa_get_lattice (info, i); |
1385 | struct ipcp_value *val; | |
1386 | int emc; | |
1387 | ||
1388 | if (lat->bottom | |
1389 | || !lat->values | |
1390 | || VEC_index (tree, known_csts, i) | |
1391 | || VEC_index (tree, known_binfos, i)) | |
1392 | continue; | |
1393 | ||
1394 | for (val = lat->values; val; val = val->next) | |
1395 | { | |
1396 | int time, size, time_benefit; | |
1397 | ||
1398 | if (TREE_CODE (val->value) != TREE_BINFO) | |
1399 | { | |
1400 | VEC_replace (tree, known_csts, i, val->value); | |
1401 | VEC_replace (tree, known_binfos, i, NULL_TREE); | |
1402 | emc = estimate_move_cost (TREE_TYPE (val->value)); | |
1403 | } | |
1404 | else if (lat->virt_call) | |
1405 | { | |
1406 | VEC_replace (tree, known_csts, i, NULL_TREE); | |
1407 | VEC_replace (tree, known_binfos, i, val->value); | |
1408 | emc = 0; | |
1409 | } | |
1410 | else | |
1411 | continue; | |
1412 | ||
d2d668fb MK |
1413 | estimate_ipcp_clone_size_and_time (node, known_csts, known_binfos, |
1414 | &size, &time); | |
310bc633 MJ |
1415 | time_benefit = base_time - time |
1416 | + devirtualization_time_bonus (node, known_csts, known_binfos) | |
1417 | + removable_params_cost + emc; | |
1418 | ||
0318fc77 MJ |
1419 | gcc_checking_assert (size >=0); |
1420 | /* The inliner-heuristics based estimates may think that in certain | |
1421 | contexts some functions do not have any size at all but we want | |
1422 | all specializations to have at least a tiny cost, not least not to | |
1423 | divide by zero. */ | |
1424 | if (size == 0) | |
1425 | size = 1; | |
1426 | ||
310bc633 MJ |
1427 | if (dump_file && (dump_flags & TDF_DETAILS)) |
1428 | { | |
1429 | fprintf (dump_file, " - estimates for value "); | |
1430 | print_ipcp_constant_value (dump_file, val->value); | |
1431 | fprintf (dump_file, " for parameter "); | |
1432 | print_generic_expr (dump_file, ipa_get_param (info, i), 0); | |
1433 | fprintf (dump_file, ": time_benefit: %i, size: %i\n", | |
1434 | time_benefit, size); | |
1435 | } | |
1436 | ||
1437 | val->local_time_benefit = time_benefit; | |
1438 | val->local_size_cost = size; | |
1439 | } | |
ca30a539 | 1440 | } |
310bc633 MJ |
1441 | |
1442 | VEC_free (tree, heap, known_csts); | |
1443 | VEC_free (tree, heap, known_binfos); | |
1444 | } | |
1445 | ||
1446 | ||
1447 | /* Add value CUR_VAL and all yet-unsorted values it is dependent on to the | |
1448 | topological sort of values. */ | |
1449 | ||
1450 | static void | |
1451 | add_val_to_toposort (struct ipcp_value *cur_val) | |
1452 | { | |
1453 | static int dfs_counter = 0; | |
1454 | static struct ipcp_value *stack; | |
1455 | struct ipcp_value_source *src; | |
1456 | ||
1457 | if (cur_val->dfs) | |
1458 | return; | |
1459 | ||
1460 | dfs_counter++; | |
1461 | cur_val->dfs = dfs_counter; | |
1462 | cur_val->low_link = dfs_counter; | |
1463 | ||
1464 | cur_val->topo_next = stack; | |
1465 | stack = cur_val; | |
1466 | cur_val->on_stack = true; | |
1467 | ||
1468 | for (src = cur_val->sources; src; src = src->next) | |
1469 | if (src->val) | |
1470 | { | |
1471 | if (src->val->dfs == 0) | |
1472 | { | |
1473 | add_val_to_toposort (src->val); | |
1474 | if (src->val->low_link < cur_val->low_link) | |
1475 | cur_val->low_link = src->val->low_link; | |
1476 | } | |
1477 | else if (src->val->on_stack | |
1478 | && src->val->dfs < cur_val->low_link) | |
1479 | cur_val->low_link = src->val->dfs; | |
1480 | } | |
1481 | ||
1482 | if (cur_val->dfs == cur_val->low_link) | |
ca30a539 | 1483 | { |
310bc633 MJ |
1484 | struct ipcp_value *v, *scc_list = NULL; |
1485 | ||
1486 | do | |
1487 | { | |
1488 | v = stack; | |
1489 | stack = v->topo_next; | |
1490 | v->on_stack = false; | |
1491 | ||
1492 | v->scc_next = scc_list; | |
1493 | scc_list = v; | |
1494 | } | |
1495 | while (v != cur_val); | |
1496 | ||
1497 | cur_val->topo_next = values_topo; | |
1498 | values_topo = cur_val; | |
ca30a539 | 1499 | } |
518dc859 RL |
1500 | } |
1501 | ||
310bc633 MJ |
1502 | /* Add all values in lattices associated with NODE to the topological sort if |
1503 | they are not there yet. */ | |
1504 | ||
1505 | static void | |
1506 | add_all_node_vals_to_toposort (struct cgraph_node *node) | |
518dc859 | 1507 | { |
310bc633 MJ |
1508 | struct ipa_node_params *info = IPA_NODE_REF (node); |
1509 | int i, count = ipa_get_param_count (info); | |
1510 | ||
1511 | for (i = 0; i < count ; i++) | |
1512 | { | |
1513 | struct ipcp_lattice *lat = ipa_get_lattice (info, i); | |
1514 | struct ipcp_value *val; | |
1515 | ||
1516 | if (lat->bottom || !lat->values) | |
1517 | continue; | |
1518 | for (val = lat->values; val; val = val->next) | |
1519 | add_val_to_toposort (val); | |
1520 | } | |
518dc859 RL |
1521 | } |
1522 | ||
310bc633 MJ |
1523 | /* One pass of constants propagation along the call graph edges, from callers |
1524 | to callees (requires topological ordering in TOPO), iterate over strongly | |
1525 | connected components. */ | |
1526 | ||
518dc859 | 1527 | static void |
310bc633 | 1528 | propagate_constants_topo (struct topo_info *topo) |
518dc859 | 1529 | { |
310bc633 | 1530 | int i; |
518dc859 | 1531 | |
310bc633 | 1532 | for (i = topo->nnodes - 1; i >= 0; i--) |
518dc859 | 1533 | { |
310bc633 MJ |
1534 | struct cgraph_node *v, *node = topo->order[i]; |
1535 | struct ipa_dfs_info *node_dfs_info; | |
1536 | ||
1537 | if (!cgraph_function_with_gimple_body_p (node)) | |
0eae6bab | 1538 | continue; |
310bc633 | 1539 | |
960bfb69 | 1540 | node_dfs_info = (struct ipa_dfs_info *) node->symbol.aux; |
310bc633 MJ |
1541 | /* First, iteratively propagate within the strongly connected component |
1542 | until all lattices stabilize. */ | |
1543 | v = node_dfs_info->next_cycle; | |
1544 | while (v) | |
1545 | { | |
1546 | push_node_to_stack (topo, v); | |
960bfb69 | 1547 | v = ((struct ipa_dfs_info *) v->symbol.aux)->next_cycle; |
310bc633 MJ |
1548 | } |
1549 | ||
1550 | v = node; | |
1551 | while (v) | |
1552 | { | |
1553 | struct cgraph_edge *cs; | |
1554 | ||
1555 | for (cs = v->callees; cs; cs = cs->next_callee) | |
1556 | if (edge_within_scc (cs) | |
1557 | && propagate_constants_accross_call (cs)) | |
1558 | push_node_to_stack (topo, cs->callee); | |
1559 | v = pop_node_from_stack (topo); | |
1560 | } | |
1561 | ||
1562 | /* Afterwards, propagate along edges leading out of the SCC, calculates | |
1563 | the local effects of the discovered constants and all valid values to | |
1564 | their topological sort. */ | |
1565 | v = node; | |
1566 | while (v) | |
1567 | { | |
1568 | struct cgraph_edge *cs; | |
1569 | ||
1570 | estimate_local_effects (v); | |
1571 | add_all_node_vals_to_toposort (v); | |
1572 | for (cs = v->callees; cs; cs = cs->next_callee) | |
1573 | if (!edge_within_scc (cs)) | |
1574 | propagate_constants_accross_call (cs); | |
1575 | ||
960bfb69 | 1576 | v = ((struct ipa_dfs_info *) v->symbol.aux)->next_cycle; |
310bc633 | 1577 | } |
518dc859 RL |
1578 | } |
1579 | } | |
1580 | ||
df0227c4 MJ |
1581 | |
1582 | /* Return the sum of A and B if none of them is bigger than INT_MAX/2, return | |
1583 | the bigger one if otherwise. */ | |
1584 | ||
1585 | static int | |
1586 | safe_add (int a, int b) | |
1587 | { | |
1588 | if (a > INT_MAX/2 || b > INT_MAX/2) | |
1589 | return a > b ? a : b; | |
1590 | else | |
1591 | return a + b; | |
1592 | } | |
1593 | ||
1594 | ||
310bc633 | 1595 | /* Propagate the estimated effects of individual values along the topological |
073a8998 | 1596 | from the dependent values to those they depend on. */ |
310bc633 | 1597 | |
518dc859 | 1598 | static void |
310bc633 | 1599 | propagate_effects (void) |
518dc859 | 1600 | { |
310bc633 | 1601 | struct ipcp_value *base; |
518dc859 | 1602 | |
310bc633 | 1603 | for (base = values_topo; base; base = base->topo_next) |
518dc859 | 1604 | { |
310bc633 MJ |
1605 | struct ipcp_value_source *src; |
1606 | struct ipcp_value *val; | |
1607 | int time = 0, size = 0; | |
1608 | ||
1609 | for (val = base; val; val = val->scc_next) | |
1610 | { | |
df0227c4 MJ |
1611 | time = safe_add (time, |
1612 | val->local_time_benefit + val->prop_time_benefit); | |
1613 | size = safe_add (size, val->local_size_cost + val->prop_size_cost); | |
310bc633 MJ |
1614 | } |
1615 | ||
1616 | for (val = base; val; val = val->scc_next) | |
1617 | for (src = val->sources; src; src = src->next) | |
1618 | if (src->val | |
1619 | && cgraph_maybe_hot_edge_p (src->cs)) | |
1620 | { | |
df0227c4 MJ |
1621 | src->val->prop_time_benefit = safe_add (time, |
1622 | src->val->prop_time_benefit); | |
1623 | src->val->prop_size_cost = safe_add (size, | |
1624 | src->val->prop_size_cost); | |
310bc633 | 1625 | } |
518dc859 RL |
1626 | } |
1627 | } | |
1628 | ||
310bc633 MJ |
1629 | |
1630 | /* Propagate constants, binfos and their effects from the summaries | |
1631 | interprocedurally. */ | |
1632 | ||
518dc859 | 1633 | static void |
310bc633 | 1634 | ipcp_propagate_stage (struct topo_info *topo) |
518dc859 RL |
1635 | { |
1636 | struct cgraph_node *node; | |
518dc859 | 1637 | |
310bc633 MJ |
1638 | if (dump_file) |
1639 | fprintf (dump_file, "\n Propagating constants:\n\n"); | |
1640 | ||
1641 | if (in_lto_p) | |
1642 | ipa_update_after_lto_read (); | |
1643 | ||
1644 | ||
1645 | FOR_EACH_DEFINED_FUNCTION (node) | |
1646 | { | |
1647 | struct ipa_node_params *info = IPA_NODE_REF (node); | |
1648 | ||
1649 | determine_versionability (node); | |
1650 | if (cgraph_function_with_gimple_body_p (node)) | |
1651 | { | |
1652 | info->lattices = XCNEWVEC (struct ipcp_lattice, | |
1653 | ipa_get_param_count (info)); | |
1654 | initialize_node_lattices (node); | |
1655 | } | |
1656 | if (node->count > max_count) | |
1657 | max_count = node->count; | |
1658 | overall_size += inline_summary (node)->self_size; | |
1659 | } | |
1660 | ||
1661 | max_new_size = overall_size; | |
1662 | if (max_new_size < PARAM_VALUE (PARAM_LARGE_UNIT_INSNS)) | |
1663 | max_new_size = PARAM_VALUE (PARAM_LARGE_UNIT_INSNS); | |
1664 | max_new_size += max_new_size * PARAM_VALUE (PARAM_IPCP_UNIT_GROWTH) / 100 + 1; | |
1665 | ||
1666 | if (dump_file) | |
1667 | fprintf (dump_file, "\noverall_size: %li, max_new_size: %li\n", | |
1668 | overall_size, max_new_size); | |
1669 | ||
1670 | propagate_constants_topo (topo); | |
1671 | #ifdef ENABLE_CHECKING | |
1672 | ipcp_verify_propagated_values (); | |
1673 | #endif | |
1674 | propagate_effects (); | |
1675 | ||
1676 | if (dump_file) | |
1677 | { | |
1678 | fprintf (dump_file, "\nIPA lattices after all propagation:\n"); | |
1679 | print_all_lattices (dump_file, (dump_flags & TDF_DETAILS), true); | |
1680 | } | |
1681 | } | |
1682 | ||
1683 | /* Discover newly direct outgoing edges from NODE which is a new clone with | |
1684 | known KNOWN_VALS and make them direct. */ | |
1685 | ||
1686 | static void | |
1687 | ipcp_discover_new_direct_edges (struct cgraph_node *node, | |
1688 | VEC (tree, heap) *known_vals) | |
1689 | { | |
1690 | struct cgraph_edge *ie, *next_ie; | |
0f378cb5 | 1691 | bool found = false; |
310bc633 MJ |
1692 | |
1693 | for (ie = node->indirect_calls; ie; ie = next_ie) | |
1694 | { | |
81fa35bd | 1695 | tree target; |
310bc633 MJ |
1696 | |
1697 | next_ie = ie->next_callee; | |
8810cc52 | 1698 | target = ipa_get_indirect_edge_target (ie, known_vals, NULL, NULL); |
310bc633 | 1699 | if (target) |
0f378cb5 JH |
1700 | { |
1701 | ipa_make_edge_direct_to_target (ie, target); | |
1702 | found = true; | |
1703 | } | |
310bc633 | 1704 | } |
0f378cb5 JH |
1705 | /* Turning calls to direct calls will improve overall summary. */ |
1706 | if (found) | |
1707 | inline_update_overall_summary (node); | |
310bc633 MJ |
1708 | } |
1709 | ||
1710 | /* Vector of pointers which for linked lists of clones of an original crgaph | |
1711 | edge. */ | |
1712 | ||
1713 | static VEC (cgraph_edge_p, heap) *next_edge_clone; | |
1714 | ||
1715 | static inline void | |
1716 | grow_next_edge_clone_vector (void) | |
1717 | { | |
1718 | if (VEC_length (cgraph_edge_p, next_edge_clone) | |
1719 | <= (unsigned) cgraph_edge_max_uid) | |
1720 | VEC_safe_grow_cleared (cgraph_edge_p, heap, next_edge_clone, | |
1721 | cgraph_edge_max_uid + 1); | |
1722 | } | |
1723 | ||
1724 | /* Edge duplication hook to grow the appropriate linked list in | |
1725 | next_edge_clone. */ | |
1726 | ||
1727 | static void | |
1728 | ipcp_edge_duplication_hook (struct cgraph_edge *src, struct cgraph_edge *dst, | |
1729 | __attribute__((unused)) void *data) | |
1730 | { | |
1731 | grow_next_edge_clone_vector (); | |
1732 | VEC_replace (cgraph_edge_p, next_edge_clone, dst->uid, | |
1733 | VEC_index (cgraph_edge_p, next_edge_clone, src->uid)); | |
1734 | VEC_replace (cgraph_edge_p, next_edge_clone, src->uid, dst); | |
1735 | } | |
1736 | ||
1737 | /* Get the next clone in the linked list of clones of an edge. */ | |
1738 | ||
1739 | static inline struct cgraph_edge * | |
1740 | get_next_cgraph_edge_clone (struct cgraph_edge *cs) | |
1741 | { | |
1742 | return VEC_index (cgraph_edge_p, next_edge_clone, cs->uid); | |
1743 | } | |
1744 | ||
1745 | /* Return true if edge CS does bring about the value described by SRC. */ | |
1746 | ||
1747 | static bool | |
1748 | cgraph_edge_brings_value_p (struct cgraph_edge *cs, | |
1749 | struct ipcp_value_source *src) | |
1750 | { | |
1751 | struct ipa_node_params *caller_info = IPA_NODE_REF (cs->caller); | |
1752 | ||
1753 | if (IPA_NODE_REF (cs->callee)->ipcp_orig_node | |
1754 | || caller_info->node_dead) | |
1755 | return false; | |
1756 | if (!src->val) | |
1757 | return true; | |
1758 | ||
1759 | if (caller_info->ipcp_orig_node) | |
1760 | { | |
1761 | tree t = VEC_index (tree, caller_info->known_vals, src->index); | |
1762 | return (t != NULL_TREE | |
1763 | && values_equal_for_ipcp_p (src->val->value, t)); | |
1764 | } | |
1765 | else | |
518dc859 | 1766 | { |
310bc633 MJ |
1767 | struct ipcp_lattice *lat = ipa_get_lattice (caller_info, src->index); |
1768 | if (ipa_lat_is_single_const (lat) | |
1769 | && values_equal_for_ipcp_p (src->val->value, lat->values->value)) | |
1770 | return true; | |
1771 | else | |
1772 | return false; | |
1773 | } | |
1774 | } | |
1775 | ||
1776 | /* Given VAL, iterate over all its sources and if they still hold, add their | |
1777 | edge frequency and their number into *FREQUENCY and *CALLER_COUNT | |
1778 | respectively. */ | |
1779 | ||
1780 | static bool | |
1781 | get_info_about_necessary_edges (struct ipcp_value *val, int *freq_sum, | |
1782 | gcov_type *count_sum, int *caller_count) | |
1783 | { | |
1784 | struct ipcp_value_source *src; | |
1785 | int freq = 0, count = 0; | |
1786 | gcov_type cnt = 0; | |
1787 | bool hot = false; | |
1788 | ||
1789 | for (src = val->sources; src; src = src->next) | |
1790 | { | |
1791 | struct cgraph_edge *cs = src->cs; | |
1792 | while (cs) | |
518dc859 | 1793 | { |
310bc633 MJ |
1794 | if (cgraph_edge_brings_value_p (cs, src)) |
1795 | { | |
1796 | count++; | |
1797 | freq += cs->frequency; | |
1798 | cnt += cs->count; | |
1799 | hot |= cgraph_maybe_hot_edge_p (cs); | |
1800 | } | |
1801 | cs = get_next_cgraph_edge_clone (cs); | |
518dc859 RL |
1802 | } |
1803 | } | |
310bc633 MJ |
1804 | |
1805 | *freq_sum = freq; | |
1806 | *count_sum = cnt; | |
1807 | *caller_count = count; | |
1808 | return hot; | |
518dc859 RL |
1809 | } |
1810 | ||
310bc633 MJ |
1811 | /* Return a vector of incoming edges that do bring value VAL. It is assumed |
1812 | their number is known and equal to CALLER_COUNT. */ | |
1813 | ||
1814 | static VEC (cgraph_edge_p,heap) * | |
1815 | gather_edges_for_value (struct ipcp_value *val, int caller_count) | |
518dc859 | 1816 | { |
310bc633 MJ |
1817 | struct ipcp_value_source *src; |
1818 | VEC (cgraph_edge_p,heap) *ret; | |
1819 | ||
1820 | ret = VEC_alloc (cgraph_edge_p, heap, caller_count); | |
1821 | for (src = val->sources; src; src = src->next) | |
1822 | { | |
1823 | struct cgraph_edge *cs = src->cs; | |
1824 | while (cs) | |
1825 | { | |
1826 | if (cgraph_edge_brings_value_p (cs, src)) | |
1827 | VEC_quick_push (cgraph_edge_p, ret, cs); | |
1828 | cs = get_next_cgraph_edge_clone (cs); | |
1829 | } | |
1830 | } | |
1831 | ||
1832 | return ret; | |
518dc859 RL |
1833 | } |
1834 | ||
310bc633 MJ |
1835 | /* Construct a replacement map for a know VALUE for a formal parameter PARAM. |
1836 | Return it or NULL if for some reason it cannot be created. */ | |
1837 | ||
518dc859 | 1838 | static struct ipa_replace_map * |
310bc633 | 1839 | get_replacement_map (tree value, tree parm) |
518dc859 | 1840 | { |
310bc633 | 1841 | tree req_type = TREE_TYPE (parm); |
518dc859 | 1842 | struct ipa_replace_map *replace_map; |
518dc859 | 1843 | |
310bc633 | 1844 | if (!useless_type_conversion_p (req_type, TREE_TYPE (value))) |
cc58ceee | 1845 | { |
310bc633 MJ |
1846 | if (fold_convertible_p (req_type, value)) |
1847 | value = fold_build1 (NOP_EXPR, req_type, value); | |
1848 | else if (TYPE_SIZE (req_type) == TYPE_SIZE (TREE_TYPE (value))) | |
1849 | value = fold_build1 (VIEW_CONVERT_EXPR, req_type, value); | |
1850 | else | |
cc58ceee | 1851 | { |
310bc633 MJ |
1852 | if (dump_file) |
1853 | { | |
1854 | fprintf (dump_file, " const "); | |
1855 | print_generic_expr (dump_file, value, 0); | |
1856 | fprintf (dump_file, " can't be converted to param "); | |
1857 | print_generic_expr (dump_file, parm, 0); | |
1858 | fprintf (dump_file, "\n"); | |
1859 | } | |
1860 | return NULL; | |
cc58ceee | 1861 | } |
cc58ceee | 1862 | } |
310bc633 | 1863 | |
cc58ceee | 1864 | replace_map = ggc_alloc_ipa_replace_map (); |
c6f7cfc1 JH |
1865 | if (dump_file) |
1866 | { | |
310bc633 MJ |
1867 | fprintf (dump_file, " replacing param "); |
1868 | print_generic_expr (dump_file, parm, 0); | |
c6f7cfc1 | 1869 | fprintf (dump_file, " with const "); |
310bc633 | 1870 | print_generic_expr (dump_file, value, 0); |
c6f7cfc1 JH |
1871 | fprintf (dump_file, "\n"); |
1872 | } | |
310bc633 MJ |
1873 | replace_map->old_tree = parm; |
1874 | replace_map->new_tree = value; | |
0f1961a2 JH |
1875 | replace_map->replace_p = true; |
1876 | replace_map->ref_p = false; | |
518dc859 RL |
1877 | |
1878 | return replace_map; | |
1879 | } | |
1880 | ||
310bc633 | 1881 | /* Dump new profiling counts */ |
518dc859 | 1882 | |
518dc859 | 1883 | static void |
310bc633 MJ |
1884 | dump_profile_updates (struct cgraph_node *orig_node, |
1885 | struct cgraph_node *new_node) | |
518dc859 | 1886 | { |
310bc633 | 1887 | struct cgraph_edge *cs; |
518dc859 | 1888 | |
310bc633 MJ |
1889 | fprintf (dump_file, " setting count of the specialized node to " |
1890 | HOST_WIDE_INT_PRINT_DEC "\n", (HOST_WIDE_INT) new_node->count); | |
1891 | for (cs = new_node->callees; cs ; cs = cs->next_callee) | |
1892 | fprintf (dump_file, " edge to %s has count " | |
1893 | HOST_WIDE_INT_PRINT_DEC "\n", | |
1894 | cgraph_node_name (cs->callee), (HOST_WIDE_INT) cs->count); | |
1895 | ||
1896 | fprintf (dump_file, " setting count of the original node to " | |
1897 | HOST_WIDE_INT_PRINT_DEC "\n", (HOST_WIDE_INT) orig_node->count); | |
1898 | for (cs = orig_node->callees; cs ; cs = cs->next_callee) | |
1899 | fprintf (dump_file, " edge to %s is left with " | |
1900 | HOST_WIDE_INT_PRINT_DEC "\n", | |
1901 | cgraph_node_name (cs->callee), (HOST_WIDE_INT) cs->count); | |
1902 | } | |
c6f7cfc1 | 1903 | |
310bc633 MJ |
1904 | /* After a specialized NEW_NODE version of ORIG_NODE has been created, update |
1905 | their profile information to reflect this. */ | |
518dc859 | 1906 | |
518dc859 | 1907 | static void |
310bc633 MJ |
1908 | update_profiling_info (struct cgraph_node *orig_node, |
1909 | struct cgraph_node *new_node) | |
518dc859 | 1910 | { |
518dc859 | 1911 | struct cgraph_edge *cs; |
310bc633 MJ |
1912 | struct caller_statistics stats; |
1913 | gcov_type new_sum, orig_sum; | |
1914 | gcov_type remainder, orig_node_count = orig_node->count; | |
1915 | ||
1916 | if (orig_node_count == 0) | |
1917 | return; | |
518dc859 | 1918 | |
310bc633 MJ |
1919 | init_caller_stats (&stats); |
1920 | cgraph_for_node_and_aliases (orig_node, gather_caller_stats, &stats, false); | |
1921 | orig_sum = stats.count_sum; | |
1922 | init_caller_stats (&stats); | |
1923 | cgraph_for_node_and_aliases (new_node, gather_caller_stats, &stats, false); | |
1924 | new_sum = stats.count_sum; | |
1925 | ||
1926 | if (orig_node_count < orig_sum + new_sum) | |
518dc859 | 1927 | { |
310bc633 MJ |
1928 | if (dump_file) |
1929 | fprintf (dump_file, " Problem: node %s/%i has too low count " | |
1930 | HOST_WIDE_INT_PRINT_DEC " while the sum of incoming " | |
1931 | "counts is " HOST_WIDE_INT_PRINT_DEC "\n", | |
1932 | cgraph_node_name (orig_node), orig_node->uid, | |
1933 | (HOST_WIDE_INT) orig_node_count, | |
1934 | (HOST_WIDE_INT) (orig_sum + new_sum)); | |
1935 | ||
1936 | orig_node_count = (orig_sum + new_sum) * 12 / 10; | |
1937 | if (dump_file) | |
1938 | fprintf (dump_file, " proceeding by pretending it was " | |
1939 | HOST_WIDE_INT_PRINT_DEC "\n", | |
1940 | (HOST_WIDE_INT) orig_node_count); | |
518dc859 | 1941 | } |
310bc633 MJ |
1942 | |
1943 | new_node->count = new_sum; | |
1944 | remainder = orig_node_count - new_sum; | |
1945 | orig_node->count = remainder; | |
1946 | ||
1947 | for (cs = new_node->callees; cs ; cs = cs->next_callee) | |
1948 | if (cs->frequency) | |
5bf3d50d MJ |
1949 | cs->count = cs->count * (new_sum * REG_BR_PROB_BASE |
1950 | / orig_node_count) / REG_BR_PROB_BASE; | |
310bc633 MJ |
1951 | else |
1952 | cs->count = 0; | |
1953 | ||
1954 | for (cs = orig_node->callees; cs ; cs = cs->next_callee) | |
5bf3d50d MJ |
1955 | cs->count = cs->count * (remainder * REG_BR_PROB_BASE |
1956 | / orig_node_count) / REG_BR_PROB_BASE; | |
310bc633 MJ |
1957 | |
1958 | if (dump_file) | |
1959 | dump_profile_updates (orig_node, new_node); | |
518dc859 RL |
1960 | } |
1961 | ||
310bc633 MJ |
1962 | /* Update the respective profile of specialized NEW_NODE and the original |
1963 | ORIG_NODE after additional edges with cumulative count sum REDIRECTED_SUM | |
1964 | have been redirected to the specialized version. */ | |
1965 | ||
1966 | static void | |
1967 | update_specialized_profile (struct cgraph_node *new_node, | |
1968 | struct cgraph_node *orig_node, | |
1969 | gcov_type redirected_sum) | |
5e45130d | 1970 | { |
a065d52e | 1971 | struct cgraph_edge *cs; |
310bc633 | 1972 | gcov_type new_node_count, orig_node_count = orig_node->count; |
5e45130d | 1973 | |
310bc633 MJ |
1974 | if (dump_file) |
1975 | fprintf (dump_file, " the sum of counts of redirected edges is " | |
1976 | HOST_WIDE_INT_PRINT_DEC "\n", (HOST_WIDE_INT) redirected_sum); | |
1977 | if (orig_node_count == 0) | |
1978 | return; | |
a065d52e | 1979 | |
310bc633 | 1980 | gcc_assert (orig_node_count >= redirected_sum); |
5e45130d | 1981 | |
310bc633 MJ |
1982 | new_node_count = new_node->count; |
1983 | new_node->count += redirected_sum; | |
1984 | orig_node->count -= redirected_sum; | |
a065d52e | 1985 | |
310bc633 MJ |
1986 | for (cs = new_node->callees; cs ; cs = cs->next_callee) |
1987 | if (cs->frequency) | |
1988 | cs->count += cs->count * redirected_sum / new_node_count; | |
1989 | else | |
1990 | cs->count = 0; | |
a065d52e | 1991 | |
310bc633 MJ |
1992 | for (cs = orig_node->callees; cs ; cs = cs->next_callee) |
1993 | { | |
5bf3d50d MJ |
1994 | gcov_type dec = cs->count * (redirected_sum * REG_BR_PROB_BASE |
1995 | / orig_node_count) / REG_BR_PROB_BASE; | |
310bc633 MJ |
1996 | if (dec < cs->count) |
1997 | cs->count -= dec; | |
1998 | else | |
1999 | cs->count = 0; | |
2000 | } | |
a065d52e | 2001 | |
310bc633 MJ |
2002 | if (dump_file) |
2003 | dump_profile_updates (orig_node, new_node); | |
5e45130d JH |
2004 | } |
2005 | ||
310bc633 MJ |
2006 | /* Create a specialized version of NODE with known constants and types of |
2007 | parameters in KNOWN_VALS and redirect all edges in CALLERS to it. */ | |
a065d52e | 2008 | |
310bc633 MJ |
2009 | static struct cgraph_node * |
2010 | create_specialized_node (struct cgraph_node *node, | |
2011 | VEC (tree, heap) *known_vals, | |
2012 | VEC (cgraph_edge_p,heap) *callers) | |
5e45130d | 2013 | { |
310bc633 MJ |
2014 | struct ipa_node_params *new_info, *info = IPA_NODE_REF (node); |
2015 | VEC (ipa_replace_map_p,gc)* replace_trees = NULL; | |
2016 | struct cgraph_node *new_node; | |
2017 | int i, count = ipa_get_param_count (info); | |
2018 | bitmap args_to_skip; | |
5e45130d | 2019 | |
310bc633 MJ |
2020 | gcc_assert (!info->ipcp_orig_node); |
2021 | ||
2022 | if (node->local.can_change_signature) | |
5e45130d | 2023 | { |
310bc633 MJ |
2024 | args_to_skip = BITMAP_GGC_ALLOC (); |
2025 | for (i = 0; i < count; i++) | |
2026 | { | |
2027 | tree t = VEC_index (tree, known_vals, i); | |
2028 | ||
2029 | if ((t && TREE_CODE (t) != TREE_BINFO) | |
2030 | || !ipa_is_param_used (info, i)) | |
2031 | bitmap_set_bit (args_to_skip, i); | |
2032 | } | |
2033 | } | |
2034 | else | |
d7da5cc8 MJ |
2035 | { |
2036 | args_to_skip = NULL; | |
2037 | if (dump_file && (dump_flags & TDF_DETAILS)) | |
2038 | fprintf (dump_file, " cannot change function signature\n"); | |
2039 | } | |
310bc633 MJ |
2040 | |
2041 | for (i = 0; i < count ; i++) | |
2042 | { | |
2043 | tree t = VEC_index (tree, known_vals, i); | |
2044 | if (t && TREE_CODE (t) != TREE_BINFO) | |
2045 | { | |
2046 | struct ipa_replace_map *replace_map; | |
2047 | ||
2048 | replace_map = get_replacement_map (t, ipa_get_param (info, i)); | |
2049 | if (replace_map) | |
2050 | VEC_safe_push (ipa_replace_map_p, gc, replace_trees, replace_map); | |
2051 | } | |
5e45130d JH |
2052 | } |
2053 | ||
310bc633 MJ |
2054 | new_node = cgraph_create_virtual_clone (node, callers, replace_trees, |
2055 | args_to_skip, "constprop"); | |
2056 | if (dump_file && (dump_flags & TDF_DETAILS)) | |
2057 | fprintf (dump_file, " the new node is %s/%i.\n", | |
2058 | cgraph_node_name (new_node), new_node->uid); | |
2059 | gcc_checking_assert (ipa_node_params_vector | |
2060 | && (VEC_length (ipa_node_params_t, | |
2061 | ipa_node_params_vector) | |
2062 | > (unsigned) cgraph_max_uid)); | |
2063 | update_profiling_info (node, new_node); | |
2064 | new_info = IPA_NODE_REF (new_node); | |
2065 | new_info->ipcp_orig_node = node; | |
2066 | new_info->known_vals = known_vals; | |
5e45130d | 2067 | |
310bc633 MJ |
2068 | ipcp_discover_new_direct_edges (new_node, known_vals); |
2069 | ||
2070 | VEC_free (cgraph_edge_p, heap, callers); | |
2071 | return new_node; | |
5e45130d JH |
2072 | } |
2073 | ||
310bc633 MJ |
2074 | /* Given a NODE, and a subset of its CALLERS, try to populate blanks slots in |
2075 | KNOWN_VALS with constants and types that are also known for all of the | |
2076 | CALLERS. */ | |
3949c4a7 MJ |
2077 | |
2078 | static void | |
310bc633 MJ |
2079 | find_more_values_for_callers_subset (struct cgraph_node *node, |
2080 | VEC (tree, heap) *known_vals, | |
2081 | VEC (cgraph_edge_p,heap) *callers) | |
3949c4a7 MJ |
2082 | { |
2083 | struct ipa_node_params *info = IPA_NODE_REF (node); | |
310bc633 | 2084 | int i, count = ipa_get_param_count (info); |
3949c4a7 | 2085 | |
310bc633 | 2086 | for (i = 0; i < count ; i++) |
3949c4a7 | 2087 | { |
310bc633 MJ |
2088 | struct cgraph_edge *cs; |
2089 | tree newval = NULL_TREE; | |
2090 | int j; | |
3949c4a7 | 2091 | |
310bc633 MJ |
2092 | if (ipa_get_lattice (info, i)->bottom |
2093 | || VEC_index (tree, known_vals, i)) | |
3949c4a7 MJ |
2094 | continue; |
2095 | ||
310bc633 | 2096 | FOR_EACH_VEC_ELT (cgraph_edge_p, callers, j, cs) |
49c471e3 | 2097 | { |
310bc633 MJ |
2098 | struct ipa_jump_func *jump_func; |
2099 | tree t; | |
40591473 | 2100 | |
128c61ee MJ |
2101 | if (i >= ipa_get_cs_argument_count (IPA_EDGE_REF (cs))) |
2102 | { | |
2103 | newval = NULL_TREE; | |
2104 | break; | |
2105 | } | |
310bc633 | 2106 | jump_func = ipa_get_ith_jump_func (IPA_EDGE_REF (cs), i); |
310bc633 MJ |
2107 | t = ipa_value_from_jfunc (IPA_NODE_REF (cs->caller), jump_func); |
2108 | if (!t | |
2109 | || (newval | |
2110 | && !values_equal_for_ipcp_p (t, newval))) | |
3949c4a7 | 2111 | { |
310bc633 MJ |
2112 | newval = NULL_TREE; |
2113 | break; | |
3949c4a7 | 2114 | } |
310bc633 MJ |
2115 | else |
2116 | newval = t; | |
3949c4a7 MJ |
2117 | } |
2118 | ||
310bc633 MJ |
2119 | if (newval) |
2120 | { | |
2121 | if (dump_file && (dump_flags & TDF_DETAILS)) | |
2122 | { | |
2123 | fprintf (dump_file, " adding an extra known value "); | |
2124 | print_ipcp_constant_value (dump_file, newval); | |
2125 | fprintf (dump_file, " for parameter "); | |
2126 | print_generic_expr (dump_file, ipa_get_param (info, i), 0); | |
2127 | fprintf (dump_file, "\n"); | |
2128 | } | |
5e45130d | 2129 | |
310bc633 MJ |
2130 | VEC_replace (tree, known_vals, i, newval); |
2131 | } | |
5e45130d | 2132 | } |
5e45130d JH |
2133 | } |
2134 | ||
310bc633 MJ |
2135 | /* Given an original NODE and a VAL for which we have already created a |
2136 | specialized clone, look whether there are incoming edges that still lead | |
2137 | into the old node but now also bring the requested value and also conform to | |
2138 | all other criteria such that they can be redirected the the special node. | |
2139 | This function can therefore redirect the final edge in a SCC. */ | |
3e66255c MJ |
2140 | |
2141 | static void | |
310bc633 | 2142 | perhaps_add_new_callers (struct cgraph_node *node, struct ipcp_value *val) |
3e66255c | 2143 | { |
310bc633 MJ |
2144 | struct ipa_node_params *dest_info = IPA_NODE_REF (val->spec_node); |
2145 | struct ipcp_value_source *src; | |
2146 | int count = ipa_get_param_count (dest_info); | |
2147 | gcov_type redirected_sum = 0; | |
3e66255c | 2148 | |
310bc633 | 2149 | for (src = val->sources; src; src = src->next) |
3e66255c | 2150 | { |
310bc633 MJ |
2151 | struct cgraph_edge *cs = src->cs; |
2152 | while (cs) | |
2153 | { | |
2154 | enum availability availability; | |
2155 | bool insufficient = false; | |
3e66255c | 2156 | |
310bc633 MJ |
2157 | if (cgraph_function_node (cs->callee, &availability) == node |
2158 | && availability > AVAIL_OVERWRITABLE | |
2159 | && cgraph_edge_brings_value_p (cs, src)) | |
2160 | { | |
2161 | struct ipa_node_params *caller_info; | |
2162 | struct ipa_edge_args *args; | |
2163 | int i; | |
2164 | ||
2165 | caller_info = IPA_NODE_REF (cs->caller); | |
2166 | args = IPA_EDGE_REF (cs); | |
2167 | for (i = 0; i < count; i++) | |
2168 | { | |
2169 | struct ipa_jump_func *jump_func; | |
2170 | tree val, t; | |
2171 | ||
2172 | val = VEC_index (tree, dest_info->known_vals, i); | |
2173 | if (!val) | |
2174 | continue; | |
3e66255c | 2175 | |
128c61ee MJ |
2176 | if (i >= ipa_get_cs_argument_count (args)) |
2177 | { | |
2178 | insufficient = true; | |
2179 | break; | |
2180 | } | |
310bc633 MJ |
2181 | jump_func = ipa_get_ith_jump_func (args, i); |
2182 | t = ipa_value_from_jfunc (caller_info, jump_func); | |
2183 | if (!t || !values_equal_for_ipcp_p (val, t)) | |
2184 | { | |
2185 | insufficient = true; | |
2186 | break; | |
2187 | } | |
2188 | } | |
2189 | ||
2190 | if (!insufficient) | |
2191 | { | |
2192 | if (dump_file) | |
2193 | fprintf (dump_file, " - adding an extra caller %s/%i" | |
2194 | " of %s/%i\n", | |
036c0102 UB |
2195 | xstrdup (cgraph_node_name (cs->caller)), |
2196 | cs->caller->uid, | |
2197 | xstrdup (cgraph_node_name (val->spec_node)), | |
310bc633 MJ |
2198 | val->spec_node->uid); |
2199 | ||
2200 | cgraph_redirect_edge_callee (cs, val->spec_node); | |
2201 | redirected_sum += cs->count; | |
2202 | } | |
2203 | } | |
2204 | cs = get_next_cgraph_edge_clone (cs); | |
2205 | } | |
3e66255c | 2206 | } |
310bc633 MJ |
2207 | |
2208 | if (redirected_sum) | |
2209 | update_specialized_profile (val->spec_node, node, redirected_sum); | |
3e66255c MJ |
2210 | } |
2211 | ||
2212 | ||
310bc633 MJ |
2213 | /* Copy KNOWN_BINFOS to KNOWN_VALS. */ |
2214 | ||
518dc859 | 2215 | static void |
310bc633 MJ |
2216 | move_binfos_to_values (VEC (tree, heap) *known_vals, |
2217 | VEC (tree, heap) *known_binfos) | |
518dc859 | 2218 | { |
310bc633 | 2219 | tree t; |
5e45130d | 2220 | int i; |
518dc859 | 2221 | |
310bc633 MJ |
2222 | for (i = 0; VEC_iterate (tree, known_binfos, i, t); i++) |
2223 | if (t) | |
2224 | VEC_replace (tree, known_vals, i, t); | |
2225 | } | |
5e45130d | 2226 | |
5e45130d | 2227 | |
310bc633 | 2228 | /* Decide whether and what specialized clones of NODE should be created. */ |
5e45130d | 2229 | |
310bc633 MJ |
2230 | static bool |
2231 | decide_whether_version_node (struct cgraph_node *node) | |
2232 | { | |
2233 | struct ipa_node_params *info = IPA_NODE_REF (node); | |
2234 | int i, count = ipa_get_param_count (info); | |
2235 | VEC (tree, heap) *known_csts, *known_binfos; | |
2236 | bool ret = false; | |
5e45130d | 2237 | |
310bc633 MJ |
2238 | if (count == 0) |
2239 | return false; | |
5e45130d | 2240 | |
310bc633 MJ |
2241 | if (dump_file && (dump_flags & TDF_DETAILS)) |
2242 | fprintf (dump_file, "\nEvaluating opportunities for %s/%i.\n", | |
2243 | cgraph_node_name (node), node->uid); | |
5e45130d | 2244 | |
310bc633 MJ |
2245 | gather_context_independent_values (info, &known_csts, &known_binfos, |
2246 | NULL); | |
5e45130d | 2247 | |
310bc633 MJ |
2248 | for (i = 0; i < count ; i++) |
2249 | { | |
2250 | struct ipcp_lattice *lat = ipa_get_lattice (info, i); | |
2251 | struct ipcp_value *val; | |
5e45130d | 2252 | |
310bc633 MJ |
2253 | if (lat->bottom |
2254 | || VEC_index (tree, known_csts, i) | |
2255 | || VEC_index (tree, known_binfos, i)) | |
2256 | continue; | |
61e03ffc | 2257 | |
310bc633 | 2258 | for (val = lat->values; val; val = val->next) |
518dc859 | 2259 | { |
310bc633 MJ |
2260 | int freq_sum, caller_count; |
2261 | gcov_type count_sum; | |
2262 | VEC (cgraph_edge_p, heap) *callers; | |
2263 | VEC (tree, heap) *kv; | |
5e45130d | 2264 | |
310bc633 | 2265 | if (val->spec_node) |
c6f7cfc1 | 2266 | { |
310bc633 | 2267 | perhaps_add_new_callers (node, val); |
c6f7cfc1 JH |
2268 | continue; |
2269 | } | |
310bc633 MJ |
2270 | else if (val->local_size_cost + overall_size > max_new_size) |
2271 | { | |
2272 | if (dump_file && (dump_flags & TDF_DETAILS)) | |
2273 | fprintf (dump_file, " Ignoring candidate value because " | |
2274 | "max_new_size would be reached with %li.\n", | |
2275 | val->local_size_cost + overall_size); | |
2276 | continue; | |
2277 | } | |
2278 | else if (!get_info_about_necessary_edges (val, &freq_sum, &count_sum, | |
2279 | &caller_count)) | |
2280 | continue; | |
c6f7cfc1 | 2281 | |
310bc633 | 2282 | if (dump_file && (dump_flags & TDF_DETAILS)) |
518dc859 | 2283 | { |
310bc633 MJ |
2284 | fprintf (dump_file, " - considering value "); |
2285 | print_ipcp_constant_value (dump_file, val->value); | |
2286 | fprintf (dump_file, " for parameter "); | |
2287 | print_generic_expr (dump_file, ipa_get_param (info, i), 0); | |
2288 | fprintf (dump_file, " (caller_count: %i)\n", caller_count); | |
518dc859 | 2289 | } |
310bc633 MJ |
2290 | |
2291 | ||
2292 | if (!good_cloning_opportunity_p (node, val->local_time_benefit, | |
2293 | freq_sum, count_sum, | |
2294 | val->local_size_cost) | |
2295 | && !good_cloning_opportunity_p (node, | |
2296 | val->local_time_benefit | |
2297 | + val->prop_time_benefit, | |
2298 | freq_sum, count_sum, | |
2299 | val->local_size_cost | |
2300 | + val->prop_size_cost)) | |
2301 | continue; | |
2302 | ||
cc58ceee | 2303 | if (dump_file) |
310bc633 MJ |
2304 | fprintf (dump_file, " Creating a specialized node of %s/%i.\n", |
2305 | cgraph_node_name (node), node->uid); | |
2306 | ||
2307 | callers = gather_edges_for_value (val, caller_count); | |
2308 | kv = VEC_copy (tree, heap, known_csts); | |
2309 | move_binfos_to_values (kv, known_binfos); | |
2310 | VEC_replace (tree, kv, i, val->value); | |
2311 | find_more_values_for_callers_subset (node, kv, callers); | |
2312 | val->spec_node = create_specialized_node (node, kv, callers); | |
2313 | overall_size += val->local_size_cost; | |
2314 | info = IPA_NODE_REF (node); | |
2315 | ||
2316 | /* TODO: If for some lattice there is only one other known value | |
2317 | left, make a special node for it too. */ | |
2318 | ret = true; | |
2319 | ||
2320 | VEC_replace (tree, kv, i, val->value); | |
cc58ceee | 2321 | } |
310bc633 | 2322 | } |
cc58ceee | 2323 | |
310bc633 MJ |
2324 | if (info->clone_for_all_contexts) |
2325 | { | |
2326 | VEC (cgraph_edge_p, heap) *callers; | |
cc58ceee | 2327 | |
310bc633 MJ |
2328 | if (dump_file) |
2329 | fprintf (dump_file, " - Creating a specialized node of %s/%i " | |
2330 | "for all known contexts.\n", cgraph_node_name (node), | |
2331 | node->uid); | |
5e45130d | 2332 | |
310bc633 MJ |
2333 | callers = collect_callers_of_node (node); |
2334 | move_binfos_to_values (known_csts, known_binfos); | |
2335 | create_specialized_node (node, known_csts, callers); | |
2336 | info = IPA_NODE_REF (node); | |
2337 | info->clone_for_all_contexts = false; | |
2338 | ret = true; | |
2339 | } | |
2340 | else | |
2341 | VEC_free (tree, heap, known_csts); | |
5e45130d | 2342 | |
310bc633 MJ |
2343 | VEC_free (tree, heap, known_binfos); |
2344 | return ret; | |
2345 | } | |
9187e02d | 2346 | |
310bc633 | 2347 | /* Transitively mark all callees of NODE within the same SCC as not dead. */ |
3949c4a7 | 2348 | |
310bc633 MJ |
2349 | static void |
2350 | spread_undeadness (struct cgraph_node *node) | |
2351 | { | |
2352 | struct cgraph_edge *cs; | |
5e45130d | 2353 | |
310bc633 MJ |
2354 | for (cs = node->callees; cs; cs = cs->next_callee) |
2355 | if (edge_within_scc (cs)) | |
2356 | { | |
2357 | struct cgraph_node *callee; | |
2358 | struct ipa_node_params *info; | |
129a37fc | 2359 | |
310bc633 MJ |
2360 | callee = cgraph_function_node (cs->callee, NULL); |
2361 | info = IPA_NODE_REF (callee); | |
5e45130d | 2362 | |
310bc633 MJ |
2363 | if (info->node_dead) |
2364 | { | |
2365 | info->node_dead = 0; | |
2366 | spread_undeadness (callee); | |
2367 | } | |
2368 | } | |
2369 | } | |
2370 | ||
2371 | /* Return true if NODE has a caller from outside of its SCC that is not | |
2372 | dead. Worker callback for cgraph_for_node_and_aliases. */ | |
2373 | ||
2374 | static bool | |
2375 | has_undead_caller_from_outside_scc_p (struct cgraph_node *node, | |
2376 | void *data ATTRIBUTE_UNUSED) | |
2377 | { | |
2378 | struct cgraph_edge *cs; | |
2379 | ||
2380 | for (cs = node->callers; cs; cs = cs->next_caller) | |
2381 | if (cs->caller->thunk.thunk_p | |
2382 | && cgraph_for_node_and_aliases (cs->caller, | |
2383 | has_undead_caller_from_outside_scc_p, | |
2384 | NULL, true)) | |
2385 | return true; | |
2386 | else if (!edge_within_scc (cs) | |
2387 | && !IPA_NODE_REF (cs->caller)->node_dead) | |
2388 | return true; | |
2389 | return false; | |
2390 | } | |
2391 | ||
2392 | ||
2393 | /* Identify nodes within the same SCC as NODE which are no longer needed | |
2394 | because of new clones and will be removed as unreachable. */ | |
2395 | ||
2396 | static void | |
2397 | identify_dead_nodes (struct cgraph_node *node) | |
2398 | { | |
2399 | struct cgraph_node *v; | |
960bfb69 | 2400 | for (v = node; v ; v = ((struct ipa_dfs_info *) v->symbol.aux)->next_cycle) |
310bc633 MJ |
2401 | if (cgraph_will_be_removed_from_program_if_no_direct_calls (v) |
2402 | && !cgraph_for_node_and_aliases (v, | |
2403 | has_undead_caller_from_outside_scc_p, | |
2404 | NULL, true)) | |
2405 | IPA_NODE_REF (v)->node_dead = 1; | |
2406 | ||
960bfb69 | 2407 | for (v = node; v ; v = ((struct ipa_dfs_info *) v->symbol.aux)->next_cycle) |
310bc633 MJ |
2408 | if (!IPA_NODE_REF (v)->node_dead) |
2409 | spread_undeadness (v); | |
2410 | ||
2411 | if (dump_file && (dump_flags & TDF_DETAILS)) | |
2412 | { | |
960bfb69 | 2413 | for (v = node; v ; v = ((struct ipa_dfs_info *) v->symbol.aux)->next_cycle) |
310bc633 MJ |
2414 | if (IPA_NODE_REF (v)->node_dead) |
2415 | fprintf (dump_file, " Marking node as dead: %s/%i.\n", | |
2416 | cgraph_node_name (v), v->uid); | |
5e45130d | 2417 | } |
310bc633 MJ |
2418 | } |
2419 | ||
2420 | /* The decision stage. Iterate over the topological order of call graph nodes | |
2421 | TOPO and make specialized clones if deemed beneficial. */ | |
2422 | ||
2423 | static void | |
2424 | ipcp_decision_stage (struct topo_info *topo) | |
2425 | { | |
2426 | int i; | |
2427 | ||
2428 | if (dump_file) | |
2429 | fprintf (dump_file, "\nIPA decision stage:\n\n"); | |
5e45130d | 2430 | |
310bc633 | 2431 | for (i = topo->nnodes - 1; i >= 0; i--) |
5e45130d | 2432 | { |
310bc633 MJ |
2433 | struct cgraph_node *node = topo->order[i]; |
2434 | bool change = false, iterate = true; | |
2435 | ||
2436 | while (iterate) | |
2437 | { | |
2438 | struct cgraph_node *v; | |
2439 | iterate = false; | |
960bfb69 | 2440 | for (v = node; v ; v = ((struct ipa_dfs_info *) v->symbol.aux)->next_cycle) |
310bc633 MJ |
2441 | if (cgraph_function_with_gimple_body_p (v) |
2442 | && ipcp_versionable_function_p (v)) | |
2443 | iterate |= decide_whether_version_node (v); | |
2444 | ||
2445 | change |= iterate; | |
2446 | } | |
2447 | if (change) | |
2448 | identify_dead_nodes (node); | |
518dc859 | 2449 | } |
518dc859 RL |
2450 | } |
2451 | ||
2452 | /* The IPCP driver. */ | |
310bc633 | 2453 | |
3cc1cccc | 2454 | static unsigned int |
518dc859 RL |
2455 | ipcp_driver (void) |
2456 | { | |
310bc633 MJ |
2457 | struct cgraph_2edge_hook_list *edge_duplication_hook_holder; |
2458 | struct topo_info topo; | |
2459 | ||
310bc633 MJ |
2460 | ipa_check_create_node_params (); |
2461 | ipa_check_create_edge_args (); | |
2462 | grow_next_edge_clone_vector (); | |
2463 | edge_duplication_hook_holder = | |
2464 | cgraph_add_edge_duplication_hook (&ipcp_edge_duplication_hook, NULL); | |
2465 | ipcp_values_pool = create_alloc_pool ("IPA-CP values", | |
2466 | sizeof (struct ipcp_value), 32); | |
2467 | ipcp_sources_pool = create_alloc_pool ("IPA-CP value sources", | |
2468 | sizeof (struct ipcp_value_source), 64); | |
518dc859 RL |
2469 | if (dump_file) |
2470 | { | |
ca30a539 JH |
2471 | fprintf (dump_file, "\nIPA structures before propagation:\n"); |
2472 | if (dump_flags & TDF_DETAILS) | |
2473 | ipa_print_all_params (dump_file); | |
2474 | ipa_print_all_jump_functions (dump_file); | |
518dc859 | 2475 | } |
310bc633 MJ |
2476 | |
2477 | /* Topological sort. */ | |
2478 | build_toporder_info (&topo); | |
2479 | /* Do the interprocedural propagation. */ | |
2480 | ipcp_propagate_stage (&topo); | |
2481 | /* Decide what constant propagation and cloning should be performed. */ | |
2482 | ipcp_decision_stage (&topo); | |
2483 | ||
518dc859 | 2484 | /* Free all IPCP structures. */ |
310bc633 MJ |
2485 | free_toporder_info (&topo); |
2486 | VEC_free (cgraph_edge_p, heap, next_edge_clone); | |
2487 | cgraph_remove_edge_duplication_hook (edge_duplication_hook_holder); | |
e33c6cd6 | 2488 | ipa_free_all_structures_after_ipa_cp (); |
518dc859 RL |
2489 | if (dump_file) |
2490 | fprintf (dump_file, "\nIPA constant propagation end\n"); | |
c2924966 | 2491 | return 0; |
518dc859 RL |
2492 | } |
2493 | ||
3949c4a7 MJ |
2494 | /* Initialization and computation of IPCP data structures. This is the initial |
2495 | intraprocedural analysis of functions, which gathers information to be | |
2496 | propagated later on. */ | |
2497 | ||
129a37fc JH |
2498 | static void |
2499 | ipcp_generate_summary (void) | |
2500 | { | |
3949c4a7 MJ |
2501 | struct cgraph_node *node; |
2502 | ||
129a37fc JH |
2503 | if (dump_file) |
2504 | fprintf (dump_file, "\nIPA constant propagation start:\n"); | |
129a37fc | 2505 | ipa_register_cgraph_hooks (); |
3949c4a7 | 2506 | |
c47d0034 | 2507 | FOR_EACH_FUNCTION_WITH_GIMPLE_BODY (node) |
3949c4a7 | 2508 | { |
960bfb69 JH |
2509 | node->local.versionable |
2510 | = tree_versionable_function_p (node->symbol.decl); | |
3949c4a7 MJ |
2511 | ipa_analyze_node (node); |
2512 | } | |
129a37fc JH |
2513 | } |
2514 | ||
fb3f88cc | 2515 | /* Write ipcp summary for nodes in SET. */ |
310bc633 | 2516 | |
fb3f88cc | 2517 | static void |
f27c1867 | 2518 | ipcp_write_summary (void) |
fb3f88cc | 2519 | { |
f27c1867 | 2520 | ipa_prop_write_jump_functions (); |
fb3f88cc JH |
2521 | } |
2522 | ||
2523 | /* Read ipcp summary. */ | |
310bc633 | 2524 | |
fb3f88cc JH |
2525 | static void |
2526 | ipcp_read_summary (void) | |
2527 | { | |
2528 | ipa_prop_read_jump_functions (); | |
2529 | } | |
2530 | ||
518dc859 | 2531 | /* Gate for IPCP optimization. */ |
310bc633 | 2532 | |
518dc859 RL |
2533 | static bool |
2534 | cgraph_gate_cp (void) | |
2535 | { | |
556ede65 | 2536 | /* FIXME: We should remove the optimize check after we ensure we never run |
61502ca8 | 2537 | IPA passes when not optimizing. */ |
556ede65 | 2538 | return flag_ipa_cp && optimize; |
518dc859 RL |
2539 | } |
2540 | ||
7e5487a2 | 2541 | struct ipa_opt_pass_d pass_ipa_cp = |
8ddbbcae JH |
2542 | { |
2543 | { | |
129a37fc | 2544 | IPA_PASS, |
518dc859 | 2545 | "cp", /* name */ |
2b4e6bf1 | 2546 | OPTGROUP_NONE, /* optinfo_flags */ |
518dc859 RL |
2547 | cgraph_gate_cp, /* gate */ |
2548 | ipcp_driver, /* execute */ | |
2549 | NULL, /* sub */ | |
2550 | NULL, /* next */ | |
2551 | 0, /* static_pass_number */ | |
2552 | TV_IPA_CONSTANT_PROP, /* tv_id */ | |
2553 | 0, /* properties_required */ | |
535b544a | 2554 | 0, /* properties_provided */ |
518dc859 RL |
2555 | 0, /* properties_destroyed */ |
2556 | 0, /* todo_flags_start */ | |
8f940ee6 | 2557 | TODO_dump_symtab | |
49ba8180 | 2558 | TODO_remove_functions | TODO_ggc_collect /* todo_flags_finish */ |
129a37fc JH |
2559 | }, |
2560 | ipcp_generate_summary, /* generate_summary */ | |
fb3f88cc JH |
2561 | ipcp_write_summary, /* write_summary */ |
2562 | ipcp_read_summary, /* read_summary */ | |
e792884f JH |
2563 | NULL, /* write_optimization_summary */ |
2564 | NULL, /* read_optimization_summary */ | |
e33c6cd6 | 2565 | NULL, /* stmt_fixup */ |
129a37fc JH |
2566 | 0, /* TODOs */ |
2567 | NULL, /* function_transform */ | |
2568 | NULL, /* variable_transform */ | |
518dc859 | 2569 | }; |