File: | build/gcc/ipa-cp.cc |
Warning: | line 5877, column 3 Called C++ object pointer is null |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | /* Interprocedural constant propagation | |||
2 | Copyright (C) 2005-2023 Free Software Foundation, Inc. | |||
3 | ||||
4 | Contributed by Razya Ladelsky <RAZYA@il.ibm.com> and Martin Jambor | |||
5 | <mjambor@suse.cz> | |||
6 | ||||
7 | This file is part of GCC. | |||
8 | ||||
9 | GCC is free software; you can redistribute it and/or modify it under | |||
10 | the terms of the GNU General Public License as published by the Free | |||
11 | Software Foundation; either version 3, or (at your option) any later | |||
12 | version. | |||
13 | ||||
14 | GCC is distributed in the hope that it will be useful, but WITHOUT ANY | |||
15 | WARRANTY; without even the implied warranty of MERCHANTABILITY or | |||
16 | FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |||
17 | for more details. | |||
18 | ||||
19 | You should have received a copy of the GNU General Public License | |||
20 | along with GCC; see the file COPYING3. If not see | |||
21 | <http://www.gnu.org/licenses/>. */ | |||
22 | ||||
23 | /* Interprocedural constant propagation (IPA-CP). | |||
24 | ||||
25 | The goal of this transformation is to | |||
26 | ||||
27 | 1) discover functions which are always invoked with some arguments with the | |||
28 | same known constant values and modify the functions so that the | |||
29 | subsequent optimizations can take advantage of the knowledge, and | |||
30 | ||||
31 | 2) partial specialization - create specialized versions of functions | |||
32 | transformed in this way if some parameters are known constants only in | |||
33 | certain contexts but the estimated tradeoff between speedup and cost size | |||
34 | is deemed good. | |||
35 | ||||
36 | The algorithm also propagates types and attempts to perform type based | |||
37 | devirtualization. Types are propagated much like constants. | |||
38 | ||||
39 | The algorithm basically consists of three stages. In the first, functions | |||
40 | are analyzed one at a time and jump functions are constructed for all known | |||
41 | call-sites. In the second phase, the pass propagates information from the | |||
42 | jump functions across the call to reveal what values are available at what | |||
43 | call sites, performs estimations of effects of known values on functions and | |||
44 | their callees, and finally decides what specialized extra versions should be | |||
45 | created. In the third, the special versions materialize and appropriate | |||
46 | calls are redirected. | |||
47 | ||||
48 | The algorithm used is to a certain extent based on "Interprocedural Constant | |||
49 | Propagation", by David Callahan, Keith D Cooper, Ken Kennedy, Linda Torczon, | |||
50 | Comp86, pg 152-161 and "A Methodology for Procedure Cloning" by Keith D | |||
51 | Cooper, Mary W. Hall, and Ken Kennedy. | |||
52 | ||||
53 | ||||
54 | First stage - intraprocedural analysis | |||
55 | ======================================= | |||
56 | ||||
57 | This phase computes jump_function and modification flags. | |||
58 | ||||
59 | A jump function for a call-site represents the values passed as an actual | |||
60 | arguments of a given call-site. In principle, there are three types of | |||
61 | values: | |||
62 | ||||
63 | Pass through - the caller's formal parameter is passed as an actual | |||
64 | argument, plus an operation on it can be performed. | |||
65 | Constant - a constant is passed as an actual argument. | |||
66 | Unknown - neither of the above. | |||
67 | ||||
68 | All jump function types are described in detail in ipa-prop.h, together with | |||
69 | the data structures that represent them and methods of accessing them. | |||
70 | ||||
71 | ipcp_generate_summary() is the main function of the first stage. | |||
72 | ||||
73 | Second stage - interprocedural analysis | |||
74 | ======================================== | |||
75 | ||||
76 | This stage is itself divided into two phases. In the first, we propagate | |||
77 | known values over the call graph, in the second, we make cloning decisions. | |||
78 | It uses a different algorithm than the original Callahan's paper. | |||
79 | ||||
80 | First, we traverse the functions topologically from callers to callees and, | |||
81 | for each strongly connected component (SCC), we propagate constants | |||
82 | according to previously computed jump functions. We also record what known | |||
83 | values depend on other known values and estimate local effects. Finally, we | |||
84 | propagate cumulative information about these effects from dependent values | |||
85 | to those on which they depend. | |||
86 | ||||
87 | Second, we again traverse the call graph in the same topological order and | |||
88 | make clones for functions which we know are called with the same values in | |||
89 | all contexts and decide about extra specialized clones of functions just for | |||
90 | some contexts - these decisions are based on both local estimates and | |||
91 | cumulative estimates propagated from callees. | |||
92 | ||||
93 | ipcp_propagate_stage() and ipcp_decision_stage() together constitute the | |||
94 | third stage. | |||
95 | ||||
96 | Third phase - materialization of clones, call statement updates. | |||
97 | ============================================ | |||
98 | ||||
99 | This stage is currently performed by call graph code (mainly in cgraphunit.cc | |||
100 | and tree-inline.cc) according to instructions inserted to the call graph by | |||
101 | the second stage. */ | |||
102 | ||||
103 | #define INCLUDE_ALGORITHM | |||
104 | #include "config.h" | |||
105 | #include "system.h" | |||
106 | #include "coretypes.h" | |||
107 | #include "backend.h" | |||
108 | #include "tree.h" | |||
109 | #include "gimple-expr.h" | |||
110 | #include "gimple.h" | |||
111 | #include "predict.h" | |||
112 | #include "alloc-pool.h" | |||
113 | #include "tree-pass.h" | |||
114 | #include "cgraph.h" | |||
115 | #include "diagnostic.h" | |||
116 | #include "fold-const.h" | |||
117 | #include "gimple-iterator.h" | |||
118 | #include "gimple-fold.h" | |||
119 | #include "symbol-summary.h" | |||
120 | #include "tree-vrp.h" | |||
121 | #include "ipa-prop.h" | |||
122 | #include "tree-pretty-print.h" | |||
123 | #include "tree-inline.h" | |||
124 | #include "ipa-fnsummary.h" | |||
125 | #include "ipa-utils.h" | |||
126 | #include "tree-ssa-ccp.h" | |||
127 | #include "stringpool.h" | |||
128 | #include "attribs.h" | |||
129 | #include "dbgcnt.h" | |||
130 | #include "symtab-clones.h" | |||
131 | ||||
132 | template <typename valtype> class ipcp_value; | |||
133 | ||||
134 | /* Describes a particular source for an IPA-CP value. */ | |||
135 | ||||
136 | template <typename valtype> | |||
137 | struct ipcp_value_source | |||
138 | { | |||
139 | public: | |||
140 | /* Aggregate offset of the source, negative if the source is scalar value of | |||
141 | the argument itself. */ | |||
142 | HOST_WIDE_INTlong offset; | |||
143 | /* The incoming edge that brought the value. */ | |||
144 | cgraph_edge *cs; | |||
145 | /* If the jump function that resulted into his value was a pass-through or an | |||
146 | ancestor, this is the ipcp_value of the caller from which the described | |||
147 | value has been derived. Otherwise it is NULL. */ | |||
148 | ipcp_value<valtype> *val; | |||
149 | /* Next pointer in a linked list of sources of a value. */ | |||
150 | ipcp_value_source *next; | |||
151 | /* If the jump function that resulted into his value was a pass-through or an | |||
152 | ancestor, this is the index of the parameter of the caller the jump | |||
153 | function references. */ | |||
154 | int index; | |||
155 | }; | |||
156 | ||||
157 | /* Common ancestor for all ipcp_value instantiations. */ | |||
158 | ||||
159 | class ipcp_value_base | |||
160 | { | |||
161 | public: | |||
162 | /* Time benefit and that specializing the function for this value would bring | |||
163 | about in this function alone. */ | |||
164 | sreal local_time_benefit; | |||
165 | /* Time benefit that specializing the function for this value can bring about | |||
166 | in it's callees. */ | |||
167 | sreal prop_time_benefit; | |||
168 | /* Size cost that specializing the function for this value would bring about | |||
169 | in this function alone. */ | |||
170 | int local_size_cost; | |||
171 | /* Size cost that specializing the function for this value can bring about in | |||
172 | it's callees. */ | |||
173 | int prop_size_cost; | |||
174 | ||||
175 | ipcp_value_base () | |||
176 | : local_time_benefit (0), prop_time_benefit (0), | |||
177 | local_size_cost (0), prop_size_cost (0) {} | |||
178 | }; | |||
179 | ||||
180 | /* Describes one particular value stored in struct ipcp_lattice. */ | |||
181 | ||||
182 | template <typename valtype> | |||
183 | class ipcp_value : public ipcp_value_base | |||
184 | { | |||
185 | public: | |||
186 | /* The actual value for the given parameter. */ | |||
187 | valtype value; | |||
188 | /* The list of sources from which this value originates. */ | |||
189 | ipcp_value_source <valtype> *sources = nullptr; | |||
190 | /* Next pointers in a linked list of all values in a lattice. */ | |||
191 | ipcp_value *next = nullptr; | |||
192 | /* Next pointers in a linked list of values in a strongly connected component | |||
193 | of values. */ | |||
194 | ipcp_value *scc_next = nullptr; | |||
195 | /* Next pointers in a linked list of SCCs of values sorted topologically | |||
196 | according their sources. */ | |||
197 | ipcp_value *topo_next = nullptr; | |||
198 | /* A specialized node created for this value, NULL if none has been (so far) | |||
199 | created. */ | |||
200 | cgraph_node *spec_node = nullptr; | |||
201 | /* Depth first search number and low link for topological sorting of | |||
202 | values. */ | |||
203 | int dfs = 0; | |||
204 | int low_link = 0; | |||
205 | /* SCC number to identify values which recursively feed into each other. | |||
206 | Values in the same SCC have the same SCC number. */ | |||
207 | int scc_no = 0; | |||
208 | /* Non zero if the value is generated from another value in the same lattice | |||
209 | for a self-recursive call, the actual number is how many times the | |||
210 | operation has been performed. In the unlikely event of the value being | |||
211 | present in two chains fo self-recursive value generation chains, it is the | |||
212 | maximum. */ | |||
213 | unsigned self_recursion_generated_level = 0; | |||
214 | /* True if this value is currently on the topo-sort stack. */ | |||
215 | bool on_stack = false; | |||
216 | ||||
217 | void add_source (cgraph_edge *cs, ipcp_value *src_val, int src_idx, | |||
218 | HOST_WIDE_INTlong offset); | |||
219 | ||||
220 | /* Return true if both THIS value and O feed into each other. */ | |||
221 | ||||
222 | bool same_scc (const ipcp_value<valtype> *o) | |||
223 | { | |||
224 | return o->scc_no == scc_no; | |||
225 | } | |||
226 | ||||
227 | /* Return true, if a this value has been generated for a self-recursive call as | |||
228 | a result of an arithmetic pass-through jump-function acting on a value in | |||
229 | the same lattice function. */ | |||
230 | ||||
231 | bool self_recursion_generated_p () | |||
232 | { | |||
233 | return self_recursion_generated_level > 0; | |||
234 | } | |||
235 | }; | |||
236 | ||||
237 | /* Lattice describing potential values of a formal parameter of a function, or | |||
238 | a part of an aggregate. TOP is represented by a lattice with zero values | |||
239 | and with contains_variable and bottom flags cleared. BOTTOM is represented | |||
240 | by a lattice with the bottom flag set. In that case, values and | |||
241 | contains_variable flag should be disregarded. */ | |||
242 | ||||
243 | template <typename valtype> | |||
244 | struct ipcp_lattice | |||
245 | { | |||
246 | public: | |||
247 | /* The list of known values and types in this lattice. Note that values are | |||
248 | not deallocated if a lattice is set to bottom because there may be value | |||
249 | sources referencing them. */ | |||
250 | ipcp_value<valtype> *values; | |||
251 | /* Number of known values and types in this lattice. */ | |||
252 | int values_count; | |||
253 | /* The lattice contains a variable component (in addition to values). */ | |||
254 | bool contains_variable; | |||
255 | /* The value of the lattice is bottom (i.e. variable and unusable for any | |||
256 | propagation). */ | |||
257 | bool bottom; | |||
258 | ||||
259 | inline bool is_single_const (); | |||
260 | inline bool set_to_bottom (); | |||
261 | inline bool set_contains_variable (); | |||
262 | bool add_value (valtype newval, cgraph_edge *cs, | |||
263 | ipcp_value<valtype> *src_val = NULLnullptr, | |||
264 | int src_idx = 0, HOST_WIDE_INTlong offset = -1, | |||
265 | ipcp_value<valtype> **val_p = NULLnullptr, | |||
266 | unsigned same_lat_gen_level = 0); | |||
267 | void print (FILE * f, bool dump_sources, bool dump_benefits); | |||
268 | }; | |||
269 | ||||
270 | /* Lattice of tree values with an offset to describe a part of an | |||
271 | aggregate. */ | |||
272 | ||||
273 | struct ipcp_agg_lattice : public ipcp_lattice<tree> | |||
274 | { | |||
275 | public: | |||
276 | /* Offset that is being described by this lattice. */ | |||
277 | HOST_WIDE_INTlong offset; | |||
278 | /* Size so that we don't have to re-compute it every time we traverse the | |||
279 | list. Must correspond to TYPE_SIZE of all lat values. */ | |||
280 | HOST_WIDE_INTlong size; | |||
281 | /* Next element of the linked list. */ | |||
282 | struct ipcp_agg_lattice *next; | |||
283 | }; | |||
284 | ||||
285 | /* Lattice of known bits, only capable of holding one value. | |||
286 | Bitwise constant propagation propagates which bits of a | |||
287 | value are constant. | |||
288 | For eg: | |||
289 | int f(int x) | |||
290 | { | |||
291 | return some_op (x); | |||
292 | } | |||
293 | ||||
294 | int f1(int y) | |||
295 | { | |||
296 | if (cond) | |||
297 | return f (y & 0xff); | |||
298 | else | |||
299 | return f (y & 0xf); | |||
300 | } | |||
301 | ||||
302 | In the above case, the param 'x' will always have all | |||
303 | the bits (except the bits in lsb) set to 0. | |||
304 | Hence the mask of 'x' would be 0xff. The mask | |||
305 | reflects that the bits in lsb are unknown. | |||
306 | The actual propagated value is given by m_value & ~m_mask. */ | |||
307 | ||||
308 | class ipcp_bits_lattice | |||
309 | { | |||
310 | public: | |||
311 | bool bottom_p () const { return m_lattice_val == IPA_BITS_VARYING; } | |||
312 | bool top_p () const { return m_lattice_val == IPA_BITS_UNDEFINED; } | |||
313 | bool constant_p () const { return m_lattice_val == IPA_BITS_CONSTANT; } | |||
314 | bool set_to_bottom (); | |||
315 | bool set_to_constant (widest_int, widest_int); | |||
316 | bool known_nonzero_p () const; | |||
317 | ||||
318 | widest_int get_value () const { return m_value; } | |||
319 | widest_int get_mask () const { return m_mask; } | |||
320 | ||||
321 | bool meet_with (ipcp_bits_lattice& other, unsigned, signop, | |||
322 | enum tree_code, tree, bool); | |||
323 | ||||
324 | bool meet_with (widest_int, widest_int, unsigned); | |||
325 | ||||
326 | void print (FILE *); | |||
327 | ||||
328 | private: | |||
329 | enum { IPA_BITS_UNDEFINED, IPA_BITS_CONSTANT, IPA_BITS_VARYING } m_lattice_val; | |||
330 | ||||
331 | /* Similar to ccp_lattice_t, mask represents which bits of value are constant. | |||
332 | If a bit in mask is set to 0, then the corresponding bit in | |||
333 | value is known to be constant. */ | |||
334 | widest_int m_value, m_mask; | |||
335 | ||||
336 | bool meet_with_1 (widest_int, widest_int, unsigned, bool); | |||
337 | void get_value_and_mask (tree, widest_int *, widest_int *); | |||
338 | }; | |||
339 | ||||
340 | /* Lattice of value ranges. */ | |||
341 | ||||
342 | class ipcp_vr_lattice | |||
343 | { | |||
344 | public: | |||
345 | value_range m_vr; | |||
346 | ||||
347 | inline bool bottom_p () const; | |||
348 | inline bool top_p () const; | |||
349 | inline bool set_to_bottom (); | |||
350 | bool meet_with (const value_range *p_vr); | |||
351 | bool meet_with (const ipcp_vr_lattice &other); | |||
352 | void init () { gcc_assert (m_vr.undefined_p ())((void)(!(m_vr.undefined_p ()) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-cp.cc" , 352, __FUNCTION__), 0 : 0)); } | |||
353 | void print (FILE * f); | |||
354 | ||||
355 | private: | |||
356 | bool meet_with_1 (const value_range *other_vr); | |||
357 | }; | |||
358 | ||||
359 | /* Structure containing lattices for a parameter itself and for pieces of | |||
360 | aggregates that are passed in the parameter or by a reference in a parameter | |||
361 | plus some other useful flags. */ | |||
362 | ||||
363 | class ipcp_param_lattices | |||
364 | { | |||
365 | public: | |||
366 | /* Lattice describing the value of the parameter itself. */ | |||
367 | ipcp_lattice<tree> itself; | |||
368 | /* Lattice describing the polymorphic contexts of a parameter. */ | |||
369 | ipcp_lattice<ipa_polymorphic_call_context> ctxlat; | |||
370 | /* Lattices describing aggregate parts. */ | |||
371 | ipcp_agg_lattice *aggs; | |||
372 | /* Lattice describing known bits. */ | |||
373 | ipcp_bits_lattice bits_lattice; | |||
374 | /* Lattice describing value range. */ | |||
375 | ipcp_vr_lattice m_value_range; | |||
376 | /* Number of aggregate lattices */ | |||
377 | int aggs_count; | |||
378 | /* True if aggregate data were passed by reference (as opposed to by | |||
379 | value). */ | |||
380 | bool aggs_by_ref; | |||
381 | /* All aggregate lattices contain a variable component (in addition to | |||
382 | values). */ | |||
383 | bool aggs_contain_variable; | |||
384 | /* The value of all aggregate lattices is bottom (i.e. variable and unusable | |||
385 | for any propagation). */ | |||
386 | bool aggs_bottom; | |||
387 | ||||
388 | /* There is a virtual call based on this parameter. */ | |||
389 | bool virt_call; | |||
390 | }; | |||
391 | ||||
392 | /* Allocation pools for values and their sources in ipa-cp. */ | |||
393 | ||||
394 | object_allocator<ipcp_value<tree> > ipcp_cst_values_pool | |||
395 | ("IPA-CP constant values"); | |||
396 | ||||
397 | object_allocator<ipcp_value<ipa_polymorphic_call_context> > | |||
398 | ipcp_poly_ctx_values_pool ("IPA-CP polymorphic contexts"); | |||
399 | ||||
400 | object_allocator<ipcp_value_source<tree> > ipcp_sources_pool | |||
401 | ("IPA-CP value sources"); | |||
402 | ||||
403 | object_allocator<ipcp_agg_lattice> ipcp_agg_lattice_pool | |||
404 | ("IPA_CP aggregate lattices"); | |||
405 | ||||
406 | /* Base count to use in heuristics when using profile feedback. */ | |||
407 | ||||
408 | static profile_count base_count; | |||
409 | ||||
410 | /* Original overall size of the program. */ | |||
411 | ||||
412 | static long overall_size, orig_overall_size; | |||
413 | ||||
414 | /* Node name to unique clone suffix number map. */ | |||
415 | static hash_map<const char *, unsigned> *clone_num_suffixes; | |||
416 | ||||
417 | /* Return the param lattices structure corresponding to the Ith formal | |||
418 | parameter of the function described by INFO. */ | |||
419 | static inline class ipcp_param_lattices * | |||
420 | ipa_get_parm_lattices (class ipa_node_params *info, int i) | |||
421 | { | |||
422 | gcc_assert (i >= 0 && i < ipa_get_param_count (info))((void)(!(i >= 0 && i < ipa_get_param_count (info )) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-cp.cc" , 422, __FUNCTION__), 0 : 0)); | |||
423 | gcc_checking_assert (!info->ipcp_orig_node)((void)(!(!info->ipcp_orig_node) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-cp.cc" , 423, __FUNCTION__), 0 : 0)); | |||
424 | gcc_checking_assert (info->lattices)((void)(!(info->lattices) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-cp.cc" , 424, __FUNCTION__), 0 : 0)); | |||
425 | return &(info->lattices[i]); | |||
426 | } | |||
427 | ||||
428 | /* Return the lattice corresponding to the scalar value of the Ith formal | |||
429 | parameter of the function described by INFO. */ | |||
430 | static inline ipcp_lattice<tree> * | |||
431 | ipa_get_scalar_lat (class ipa_node_params *info, int i) | |||
432 | { | |||
433 | class ipcp_param_lattices *plats = ipa_get_parm_lattices (info, i); | |||
434 | return &plats->itself; | |||
435 | } | |||
436 | ||||
437 | /* Return the lattice corresponding to the scalar value of the Ith formal | |||
438 | parameter of the function described by INFO. */ | |||
439 | static inline ipcp_lattice<ipa_polymorphic_call_context> * | |||
440 | ipa_get_poly_ctx_lat (class ipa_node_params *info, int i) | |||
441 | { | |||
442 | class ipcp_param_lattices *plats = ipa_get_parm_lattices (info, i); | |||
443 | return &plats->ctxlat; | |||
444 | } | |||
445 | ||||
446 | /* Return whether LAT is a lattice with a single constant and without an | |||
447 | undefined value. */ | |||
448 | ||||
449 | template <typename valtype> | |||
450 | inline bool | |||
451 | ipcp_lattice<valtype>::is_single_const () | |||
452 | { | |||
453 | if (bottom || contains_variable || values_count != 1) | |||
454 | return false; | |||
455 | else | |||
456 | return true; | |||
457 | } | |||
458 | ||||
459 | /* Return true iff X and Y should be considered equal values by IPA-CP. */ | |||
460 | ||||
461 | static bool | |||
462 | values_equal_for_ipcp_p (tree x, tree y) | |||
463 | { | |||
464 | gcc_checking_assert (x != NULL_TREE && y != NULL_TREE)((void)(!(x != (tree) nullptr && y != (tree) nullptr) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-cp.cc" , 464, __FUNCTION__), 0 : 0)); | |||
465 | ||||
466 | if (x == y) | |||
467 | return true; | |||
468 | ||||
469 | if (TREE_CODE (x)((enum tree_code) (x)->base.code) == ADDR_EXPR | |||
470 | && TREE_CODE (y)((enum tree_code) (y)->base.code) == ADDR_EXPR | |||
471 | && TREE_CODE (TREE_OPERAND (x, 0))((enum tree_code) ((*((const_cast<tree*> (tree_operand_check ((x), (0), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-cp.cc" , 471, __FUNCTION__))))))->base.code) == CONST_DECL | |||
472 | && TREE_CODE (TREE_OPERAND (y, 0))((enum tree_code) ((*((const_cast<tree*> (tree_operand_check ((y), (0), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-cp.cc" , 472, __FUNCTION__))))))->base.code) == CONST_DECL) | |||
473 | return operand_equal_p (DECL_INITIAL (TREE_OPERAND (x, 0))((contains_struct_check (((*((const_cast<tree*> (tree_operand_check ((x), (0), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-cp.cc" , 473, __FUNCTION__)))))), (TS_DECL_COMMON), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-cp.cc" , 473, __FUNCTION__))->decl_common.initial), | |||
474 | DECL_INITIAL (TREE_OPERAND (y, 0))((contains_struct_check (((*((const_cast<tree*> (tree_operand_check ((y), (0), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-cp.cc" , 474, __FUNCTION__)))))), (TS_DECL_COMMON), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-cp.cc" , 474, __FUNCTION__))->decl_common.initial), 0); | |||
475 | else | |||
476 | return operand_equal_p (x, y, 0); | |||
477 | } | |||
478 | ||||
479 | /* Print V which is extracted from a value in a lattice to F. */ | |||
480 | ||||
481 | static void | |||
482 | print_ipcp_constant_value (FILE * f, tree v) | |||
483 | { | |||
484 | if (TREE_CODE (v)((enum tree_code) (v)->base.code) == ADDR_EXPR | |||
485 | && TREE_CODE (TREE_OPERAND (v, 0))((enum tree_code) ((*((const_cast<tree*> (tree_operand_check ((v), (0), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-cp.cc" , 485, __FUNCTION__))))))->base.code) == CONST_DECL) | |||
486 | { | |||
487 | fprintf (f, "& "); | |||
488 | print_generic_expr (f, DECL_INITIAL (TREE_OPERAND (v, 0))((contains_struct_check (((*((const_cast<tree*> (tree_operand_check ((v), (0), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-cp.cc" , 488, __FUNCTION__)))))), (TS_DECL_COMMON), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-cp.cc" , 488, __FUNCTION__))->decl_common.initial)); | |||
489 | } | |||
490 | else | |||
491 | print_generic_expr (f, v); | |||
492 | } | |||
493 | ||||
494 | /* Print V which is extracted from a value in a lattice to F. */ | |||
495 | ||||
496 | static void | |||
497 | print_ipcp_constant_value (FILE * f, ipa_polymorphic_call_context v) | |||
498 | { | |||
499 | v.dump(f, false); | |||
500 | } | |||
501 | ||||
502 | /* Print a lattice LAT to F. */ | |||
503 | ||||
504 | template <typename valtype> | |||
505 | void | |||
506 | ipcp_lattice<valtype>::print (FILE * f, bool dump_sources, bool dump_benefits) | |||
507 | { | |||
508 | ipcp_value<valtype> *val; | |||
509 | bool prev = false; | |||
510 | ||||
511 | if (bottom) | |||
512 | { | |||
513 | fprintf (f, "BOTTOM\n"); | |||
514 | return; | |||
515 | } | |||
516 | ||||
517 | if (!values_count && !contains_variable) | |||
518 | { | |||
519 | fprintf (f, "TOP\n"); | |||
520 | return; | |||
521 | } | |||
522 | ||||
523 | if (contains_variable) | |||
524 | { | |||
525 | fprintf (f, "VARIABLE"); | |||
526 | prev = true; | |||
527 | if (dump_benefits) | |||
528 | fprintf (f, "\n"); | |||
529 | } | |||
530 | ||||
531 | for (val = values; val; val = val->next) | |||
532 | { | |||
533 | if (dump_benefits && prev) | |||
534 | fprintf (f, " "); | |||
535 | else if (!dump_benefits && prev) | |||
536 | fprintf (f, ", "); | |||
537 | else | |||
538 | prev = true; | |||
539 | ||||
540 | print_ipcp_constant_value (f, val->value); | |||
541 | ||||
542 | if (dump_sources) | |||
543 | { | |||
544 | ipcp_value_source<valtype> *s; | |||
545 | ||||
546 | if (val->self_recursion_generated_p ()) | |||
547 | fprintf (f, " [self_gen(%i), from:", | |||
548 | val->self_recursion_generated_level); | |||
549 | else | |||
550 | fprintf (f, " [scc: %i, from:", val->scc_no); | |||
551 | for (s = val->sources; s; s = s->next) | |||
552 | fprintf (f, " %i(%f)", s->cs->caller->order, | |||
553 | s->cs->sreal_frequency ().to_double ()); | |||
554 | fprintf (f, "]"); | |||
555 | } | |||
556 | ||||
557 | if (dump_benefits) | |||
558 | fprintf (f, " [loc_time: %g, loc_size: %i, " | |||
559 | "prop_time: %g, prop_size: %i]\n", | |||
560 | val->local_time_benefit.to_double (), val->local_size_cost, | |||
561 | val->prop_time_benefit.to_double (), val->prop_size_cost); | |||
562 | } | |||
563 | if (!dump_benefits) | |||
564 | fprintf (f, "\n"); | |||
565 | } | |||
566 | ||||
567 | void | |||
568 | ipcp_bits_lattice::print (FILE *f) | |||
569 | { | |||
570 | if (top_p ()) | |||
571 | fprintf (f, " Bits unknown (TOP)\n"); | |||
572 | else if (bottom_p ()) | |||
573 | fprintf (f, " Bits unusable (BOTTOM)\n"); | |||
574 | else | |||
575 | { | |||
576 | fprintf (f, " Bits: value = "); print_hex (get_value (), f); | |||
577 | fprintf (f, ", mask = "); print_hex (get_mask (), f); | |||
578 | fprintf (f, "\n"); | |||
579 | } | |||
580 | } | |||
581 | ||||
582 | /* Print value range lattice to F. */ | |||
583 | ||||
584 | void | |||
585 | ipcp_vr_lattice::print (FILE * f) | |||
586 | { | |||
587 | dump_value_range (f, &m_vr); | |||
588 | } | |||
589 | ||||
590 | /* Print all ipcp_lattices of all functions to F. */ | |||
591 | ||||
592 | static void | |||
593 | print_all_lattices (FILE * f, bool dump_sources, bool dump_benefits) | |||
594 | { | |||
595 | struct cgraph_node *node; | |||
596 | int i, count; | |||
597 | ||||
598 | fprintf (f, "\nLattices:\n"); | |||
599 | FOR_EACH_FUNCTION_WITH_GIMPLE_BODY (node)for ((node) = symtab->first_function_with_gimple_body (); ( node); (node) = symtab->next_function_with_gimple_body (node )) | |||
600 | { | |||
601 | class ipa_node_params *info; | |||
602 | ||||
603 | info = ipa_node_params_sum->get (node); | |||
604 | /* Skip unoptimized functions and constprop clones since we don't make | |||
605 | lattices for them. */ | |||
606 | if (!info || info->ipcp_orig_node) | |||
607 | continue; | |||
608 | fprintf (f, " Node: %s:\n", node->dump_name ()); | |||
609 | count = ipa_get_param_count (info); | |||
610 | for (i = 0; i < count; i++) | |||
611 | { | |||
612 | struct ipcp_agg_lattice *aglat; | |||
613 | class ipcp_param_lattices *plats = ipa_get_parm_lattices (info, i); | |||
614 | fprintf (f, " param [%d]: ", i); | |||
615 | plats->itself.print (f, dump_sources, dump_benefits); | |||
616 | fprintf (f, " ctxs: "); | |||
617 | plats->ctxlat.print (f, dump_sources, dump_benefits); | |||
618 | plats->bits_lattice.print (f); | |||
619 | fprintf (f, " "); | |||
620 | plats->m_value_range.print (f); | |||
621 | fprintf (f, "\n"); | |||
622 | if (plats->virt_call) | |||
623 | fprintf (f, " virt_call flag set\n"); | |||
624 | ||||
625 | if (plats->aggs_bottom) | |||
626 | { | |||
627 | fprintf (f, " AGGS BOTTOM\n"); | |||
628 | continue; | |||
629 | } | |||
630 | if (plats->aggs_contain_variable) | |||
631 | fprintf (f, " AGGS VARIABLE\n"); | |||
632 | for (aglat = plats->aggs; aglat; aglat = aglat->next) | |||
633 | { | |||
634 | fprintf (f, " %soffset " HOST_WIDE_INT_PRINT_DEC"%" "l" "d" ": ", | |||
635 | plats->aggs_by_ref ? "ref " : "", aglat->offset); | |||
636 | aglat->print (f, dump_sources, dump_benefits); | |||
637 | } | |||
638 | } | |||
639 | } | |||
640 | } | |||
641 | ||||
642 | /* Determine whether it is at all technically possible to create clones of NODE | |||
643 | and store this information in the ipa_node_params structure associated | |||
644 | with NODE. */ | |||
645 | ||||
646 | static void | |||
647 | determine_versionability (struct cgraph_node *node, | |||
648 | class ipa_node_params *info) | |||
649 | { | |||
650 | const char *reason = NULLnullptr; | |||
651 | ||||
652 | /* There are a number of generic reasons functions cannot be versioned. We | |||
653 | also cannot remove parameters if there are type attributes such as fnspec | |||
654 | present. */ | |||
655 | if (node->alias || node->thunk) | |||
656 | reason = "alias or thunk"; | |||
657 | else if (!node->versionable) | |||
658 | reason = "not a tree_versionable_function"; | |||
659 | else if (node->get_availability () <= AVAIL_INTERPOSABLE) | |||
660 | reason = "insufficient body availability"; | |||
661 | else if (!opt_for_fn (node->decl, optimize)(opts_for_fn (node->decl)->x_optimize) | |||
662 | || !opt_for_fn (node->decl, flag_ipa_cp)(opts_for_fn (node->decl)->x_flag_ipa_cp)) | |||
663 | reason = "non-optimized function"; | |||
664 | else if (lookup_attribute ("omp declare simd", DECL_ATTRIBUTES (node->decl)((contains_struct_check ((node->decl), (TS_DECL_COMMON), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-cp.cc" , 664, __FUNCTION__))->decl_common.attributes))) | |||
665 | { | |||
666 | /* Ideally we should clone the SIMD clones themselves and create | |||
667 | vector copies of them, so IPA-cp and SIMD clones can happily | |||
668 | coexist, but that may not be worth the effort. */ | |||
669 | reason = "function has SIMD clones"; | |||
670 | } | |||
671 | else if (lookup_attribute ("target_clones", DECL_ATTRIBUTES (node->decl)((contains_struct_check ((node->decl), (TS_DECL_COMMON), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-cp.cc" , 671, __FUNCTION__))->decl_common.attributes))) | |||
672 | { | |||
673 | /* Ideally we should clone the target clones themselves and create | |||
674 | copies of them, so IPA-cp and target clones can happily | |||
675 | coexist, but that may not be worth the effort. */ | |||
676 | reason = "function target_clones attribute"; | |||
677 | } | |||
678 | /* Don't clone decls local to a comdat group; it breaks and for C++ | |||
679 | decloned constructors, inlining is always better anyway. */ | |||
680 | else if (node->comdat_local_p ()) | |||
681 | reason = "comdat-local function"; | |||
682 | else if (node->calls_comdat_local) | |||
683 | { | |||
684 | /* TODO: call is versionable if we make sure that all | |||
685 | callers are inside of a comdat group. */ | |||
686 | reason = "calls comdat-local function"; | |||
687 | } | |||
688 | ||||
689 | /* Functions calling BUILT_IN_VA_ARG_PACK and BUILT_IN_VA_ARG_PACK_LEN | |||
690 | work only when inlined. Cloning them may still lead to better code | |||
691 | because ipa-cp will not give up on cloning further. If the function is | |||
692 | external this however leads to wrong code because we may end up producing | |||
693 | offline copy of the function. */ | |||
694 | if (DECL_EXTERNAL (node->decl)((contains_struct_check ((node->decl), (TS_DECL_COMMON), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-cp.cc" , 694, __FUNCTION__))->decl_common.decl_flag_1)) | |||
695 | for (cgraph_edge *edge = node->callees; !reason && edge; | |||
696 | edge = edge->next_callee) | |||
697 | if (fndecl_built_in_p (edge->callee->decl, BUILT_IN_NORMAL)) | |||
698 | { | |||
699 | if (DECL_FUNCTION_CODE (edge->callee->decl) == BUILT_IN_VA_ARG_PACK) | |||
700 | reason = "external function which calls va_arg_pack"; | |||
701 | if (DECL_FUNCTION_CODE (edge->callee->decl) | |||
702 | == BUILT_IN_VA_ARG_PACK_LEN) | |||
703 | reason = "external function which calls va_arg_pack_len"; | |||
704 | } | |||
705 | ||||
706 | if (reason && dump_file && !node->alias && !node->thunk) | |||
707 | fprintf (dump_file, "Function %s is not versionable, reason: %s.\n", | |||
708 | node->dump_name (), reason); | |||
709 | ||||
710 | info->versionable = (reason == NULLnullptr); | |||
711 | } | |||
712 | ||||
713 | /* Return true if it is at all technically possible to create clones of a | |||
714 | NODE. */ | |||
715 | ||||
716 | static bool | |||
717 | ipcp_versionable_function_p (struct cgraph_node *node) | |||
718 | { | |||
719 | ipa_node_params *info = ipa_node_params_sum->get (node); | |||
720 | return info && info->versionable; | |||
721 | } | |||
722 | ||||
723 | /* Structure holding accumulated information about callers of a node. */ | |||
724 | ||||
725 | struct caller_statistics | |||
726 | { | |||
727 | /* If requested (see below), self-recursive call counts are summed into this | |||
728 | field. */ | |||
729 | profile_count rec_count_sum; | |||
730 | /* The sum of all ipa counts of all the other (non-recursive) calls. */ | |||
731 | profile_count count_sum; | |||
732 | /* Sum of all frequencies for all calls. */ | |||
733 | sreal freq_sum; | |||
734 | /* Number of calls and hot calls respectively. */ | |||
735 | int n_calls, n_hot_calls; | |||
736 | /* If itself is set up, also count the number of non-self-recursive | |||
737 | calls. */ | |||
738 | int n_nonrec_calls; | |||
739 | /* If non-NULL, this is the node itself and calls from it should have their | |||
740 | counts included in rec_count_sum and not count_sum. */ | |||
741 | cgraph_node *itself; | |||
742 | }; | |||
743 | ||||
744 | /* Initialize fields of STAT to zeroes and optionally set it up so that edges | |||
745 | from IGNORED_CALLER are not counted. */ | |||
746 | ||||
747 | static inline void | |||
748 | init_caller_stats (caller_statistics *stats, cgraph_node *itself = NULLnullptr) | |||
749 | { | |||
750 | stats->rec_count_sum = profile_count::zero (); | |||
751 | stats->count_sum = profile_count::zero (); | |||
752 | stats->n_calls = 0; | |||
753 | stats->n_hot_calls = 0; | |||
754 | stats->n_nonrec_calls = 0; | |||
755 | stats->freq_sum = 0; | |||
756 | stats->itself = itself; | |||
757 | } | |||
758 | ||||
759 | /* Worker callback of cgraph_for_node_and_aliases accumulating statistics of | |||
760 | non-thunk incoming edges to NODE. */ | |||
761 | ||||
762 | static bool | |||
763 | gather_caller_stats (struct cgraph_node *node, void *data) | |||
764 | { | |||
765 | struct caller_statistics *stats = (struct caller_statistics *) data; | |||
766 | struct cgraph_edge *cs; | |||
767 | ||||
768 | for (cs = node->callers; cs; cs = cs->next_caller) | |||
769 | if (!cs->caller->thunk) | |||
770 | { | |||
771 | ipa_node_params *info = ipa_node_params_sum->get (cs->caller); | |||
772 | if (info && info->node_dead) | |||
773 | continue; | |||
774 | ||||
775 | if (cs->count.ipa ().initialized_p ()) | |||
776 | { | |||
777 | if (stats->itself && stats->itself == cs->caller) | |||
778 | stats->rec_count_sum += cs->count.ipa (); | |||
779 | else | |||
780 | stats->count_sum += cs->count.ipa (); | |||
781 | } | |||
782 | stats->freq_sum += cs->sreal_frequency (); | |||
783 | stats->n_calls++; | |||
784 | if (stats->itself && stats->itself != cs->caller) | |||
785 | stats->n_nonrec_calls++; | |||
786 | ||||
787 | if (cs->maybe_hot_p ()) | |||
788 | stats->n_hot_calls ++; | |||
789 | } | |||
790 | return false; | |||
791 | ||||
792 | } | |||
793 | ||||
794 | /* Return true if this NODE is viable candidate for cloning. */ | |||
795 | ||||
796 | static bool | |||
797 | ipcp_cloning_candidate_p (struct cgraph_node *node) | |||
798 | { | |||
799 | struct caller_statistics stats; | |||
800 | ||||
801 | gcc_checking_assert (node->has_gimple_body_p ())((void)(!(node->has_gimple_body_p ()) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-cp.cc" , 801, __FUNCTION__), 0 : 0)); | |||
802 | ||||
803 | if (!opt_for_fn (node->decl, flag_ipa_cp_clone)(opts_for_fn (node->decl)->x_flag_ipa_cp_clone)) | |||
804 | { | |||
805 | if (dump_file) | |||
806 | fprintf (dump_file, "Not considering %s for cloning; " | |||
807 | "-fipa-cp-clone disabled.\n", | |||
808 | node->dump_name ()); | |||
809 | return false; | |||
810 | } | |||
811 | ||||
812 | if (node->optimize_for_size_p ()) | |||
813 | { | |||
814 | if (dump_file) | |||
815 | fprintf (dump_file, "Not considering %s for cloning; " | |||
816 | "optimizing it for size.\n", | |||
817 | node->dump_name ()); | |||
818 | return false; | |||
819 | } | |||
820 | ||||
821 | init_caller_stats (&stats); | |||
822 | node->call_for_symbol_thunks_and_aliases (gather_caller_stats, &stats, false); | |||
823 | ||||
824 | if (ipa_size_summaries->get (node)->self_size < stats.n_calls) | |||
825 | { | |||
826 | if (dump_file) | |||
827 | fprintf (dump_file, "Considering %s for cloning; code might shrink.\n", | |||
828 | node->dump_name ()); | |||
829 | return true; | |||
830 | } | |||
831 | ||||
832 | /* When profile is available and function is hot, propagate into it even if | |||
833 | calls seems cold; constant propagation can improve function's speed | |||
834 | significantly. */ | |||
835 | if (stats.count_sum > profile_count::zero () | |||
836 | && node->count.ipa ().initialized_p ()) | |||
837 | { | |||
838 | if (stats.count_sum > node->count.ipa ().apply_scale (90, 100)) | |||
839 | { | |||
840 | if (dump_file) | |||
841 | fprintf (dump_file, "Considering %s for cloning; " | |||
842 | "usually called directly.\n", | |||
843 | node->dump_name ()); | |||
844 | return true; | |||
845 | } | |||
846 | } | |||
847 | if (!stats.n_hot_calls) | |||
848 | { | |||
849 | if (dump_file) | |||
850 | fprintf (dump_file, "Not considering %s for cloning; no hot calls.\n", | |||
851 | node->dump_name ()); | |||
852 | return false; | |||
853 | } | |||
854 | if (dump_file) | |||
855 | fprintf (dump_file, "Considering %s for cloning.\n", | |||
856 | node->dump_name ()); | |||
857 | return true; | |||
858 | } | |||
859 | ||||
860 | template <typename valtype> | |||
861 | class value_topo_info | |||
862 | { | |||
863 | public: | |||
864 | /* Head of the linked list of topologically sorted values. */ | |||
865 | ipcp_value<valtype> *values_topo; | |||
866 | /* Stack for creating SCCs, represented by a linked list too. */ | |||
867 | ipcp_value<valtype> *stack; | |||
868 | /* Counter driving the algorithm in add_val_to_toposort. */ | |||
869 | int dfs_counter; | |||
870 | ||||
871 | value_topo_info () : values_topo (NULLnullptr), stack (NULLnullptr), dfs_counter (0) | |||
872 | {} | |||
873 | void add_val (ipcp_value<valtype> *cur_val); | |||
874 | void propagate_effects (); | |||
875 | }; | |||
876 | ||||
877 | /* Arrays representing a topological ordering of call graph nodes and a stack | |||
878 | of nodes used during constant propagation and also data required to perform | |||
879 | topological sort of values and propagation of benefits in the determined | |||
880 | order. */ | |||
881 | ||||
882 | class ipa_topo_info | |||
883 | { | |||
884 | public: | |||
885 | /* Array with obtained topological order of cgraph nodes. */ | |||
886 | struct cgraph_node **order; | |||
887 | /* Stack of cgraph nodes used during propagation within SCC until all values | |||
888 | in the SCC stabilize. */ | |||
889 | struct cgraph_node **stack; | |||
890 | int nnodes, stack_top; | |||
891 | ||||
892 | value_topo_info<tree> constants; | |||
893 | value_topo_info<ipa_polymorphic_call_context> contexts; | |||
894 | ||||
895 | ipa_topo_info () : order(NULLnullptr), stack(NULLnullptr), nnodes(0), stack_top(0), | |||
896 | constants () | |||
897 | {} | |||
898 | }; | |||
899 | ||||
900 | /* Skip edges from and to nodes without ipa_cp enabled. | |||
901 | Ignore not available symbols. */ | |||
902 | ||||
903 | static bool | |||
904 | ignore_edge_p (cgraph_edge *e) | |||
905 | { | |||
906 | enum availability avail; | |||
907 | cgraph_node *ultimate_target | |||
908 | = e->callee->function_or_virtual_thunk_symbol (&avail, e->caller); | |||
909 | ||||
910 | return (avail <= AVAIL_INTERPOSABLE | |||
911 | || !opt_for_fn (ultimate_target->decl, optimize)(opts_for_fn (ultimate_target->decl)->x_optimize) | |||
912 | || !opt_for_fn (ultimate_target->decl, flag_ipa_cp)(opts_for_fn (ultimate_target->decl)->x_flag_ipa_cp)); | |||
913 | } | |||
914 | ||||
915 | /* Allocate the arrays in TOPO and topologically sort the nodes into order. */ | |||
916 | ||||
917 | static void | |||
918 | build_toporder_info (class ipa_topo_info *topo) | |||
919 | { | |||
920 | topo->order = XCNEWVEC (struct cgraph_node *, symtab->cgraph_count)((struct cgraph_node * *) xcalloc ((symtab->cgraph_count), sizeof (struct cgraph_node *))); | |||
921 | topo->stack = XCNEWVEC (struct cgraph_node *, symtab->cgraph_count)((struct cgraph_node * *) xcalloc ((symtab->cgraph_count), sizeof (struct cgraph_node *))); | |||
922 | ||||
923 | gcc_checking_assert (topo->stack_top == 0)((void)(!(topo->stack_top == 0) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-cp.cc" , 923, __FUNCTION__), 0 : 0)); | |||
924 | topo->nnodes = ipa_reduced_postorder (topo->order, true, | |||
925 | ignore_edge_p); | |||
926 | } | |||
927 | ||||
928 | /* Free information about strongly connected components and the arrays in | |||
929 | TOPO. */ | |||
930 | ||||
931 | static void | |||
932 | free_toporder_info (class ipa_topo_info *topo) | |||
933 | { | |||
934 | ipa_free_postorder_info (); | |||
935 | free (topo->order); | |||
936 | free (topo->stack); | |||
937 | } | |||
938 | ||||
939 | /* Add NODE to the stack in TOPO, unless it is already there. */ | |||
940 | ||||
941 | static inline void | |||
942 | push_node_to_stack (class ipa_topo_info *topo, struct cgraph_node *node) | |||
943 | { | |||
944 | ipa_node_params *info = ipa_node_params_sum->get (node); | |||
945 | if (info->node_enqueued) | |||
946 | return; | |||
947 | info->node_enqueued = 1; | |||
948 | topo->stack[topo->stack_top++] = node; | |||
949 | } | |||
950 | ||||
951 | /* Pop a node from the stack in TOPO and return it or return NULL if the stack | |||
952 | is empty. */ | |||
953 | ||||
954 | static struct cgraph_node * | |||
955 | pop_node_from_stack (class ipa_topo_info *topo) | |||
956 | { | |||
957 | if (topo->stack_top) | |||
958 | { | |||
959 | struct cgraph_node *node; | |||
960 | topo->stack_top--; | |||
961 | node = topo->stack[topo->stack_top]; | |||
962 | ipa_node_params_sum->get (node)->node_enqueued = 0; | |||
963 | return node; | |||
964 | } | |||
965 | else | |||
966 | return NULLnullptr; | |||
967 | } | |||
968 | ||||
969 | /* Set lattice LAT to bottom and return true if it previously was not set as | |||
970 | such. */ | |||
971 | ||||
972 | template <typename valtype> | |||
973 | inline bool | |||
974 | ipcp_lattice<valtype>::set_to_bottom () | |||
975 | { | |||
976 | bool ret = !bottom; | |||
977 | bottom = true; | |||
978 | return ret; | |||
979 | } | |||
980 | ||||
981 | /* Mark lattice as containing an unknown value and return true if it previously | |||
982 | was not marked as such. */ | |||
983 | ||||
984 | template <typename valtype> | |||
985 | inline bool | |||
986 | ipcp_lattice<valtype>::set_contains_variable () | |||
987 | { | |||
988 | bool ret = !contains_variable; | |||
989 | contains_variable = true; | |||
990 | return ret; | |||
991 | } | |||
992 | ||||
993 | /* Set all aggregate lattices in PLATS to bottom and return true if they were | |||
994 | not previously set as such. */ | |||
995 | ||||
996 | static inline bool | |||
997 | set_agg_lats_to_bottom (class ipcp_param_lattices *plats) | |||
998 | { | |||
999 | bool ret = !plats->aggs_bottom; | |||
1000 | plats->aggs_bottom = true; | |||
1001 | return ret; | |||
1002 | } | |||
1003 | ||||
1004 | /* Mark all aggregate lattices in PLATS as containing an unknown value and | |||
1005 | return true if they were not previously marked as such. */ | |||
1006 | ||||
1007 | static inline bool | |||
1008 | set_agg_lats_contain_variable (class ipcp_param_lattices *plats) | |||
1009 | { | |||
1010 | bool ret = !plats->aggs_contain_variable; | |||
1011 | plats->aggs_contain_variable = true; | |||
1012 | return ret; | |||
1013 | } | |||
1014 | ||||
1015 | bool | |||
1016 | ipcp_vr_lattice::meet_with (const ipcp_vr_lattice &other) | |||
1017 | { | |||
1018 | return meet_with_1 (&other.m_vr); | |||
1019 | } | |||
1020 | ||||
1021 | /* Meet the current value of the lattice with value range described by VR | |||
1022 | lattice. */ | |||
1023 | ||||
1024 | bool | |||
1025 | ipcp_vr_lattice::meet_with (const value_range *p_vr) | |||
1026 | { | |||
1027 | return meet_with_1 (p_vr); | |||
1028 | } | |||
1029 | ||||
1030 | /* Meet the current value of the lattice with value range described by | |||
1031 | OTHER_VR lattice. Return TRUE if anything changed. */ | |||
1032 | ||||
1033 | bool | |||
1034 | ipcp_vr_lattice::meet_with_1 (const value_range *other_vr) | |||
1035 | { | |||
1036 | if (bottom_p ()) | |||
1037 | return false; | |||
1038 | ||||
1039 | if (other_vr->varying_p ()) | |||
1040 | return set_to_bottom (); | |||
1041 | ||||
1042 | value_range save (m_vr); | |||
1043 | m_vr.union_ (*other_vr); | |||
1044 | return m_vr != save; | |||
1045 | } | |||
1046 | ||||
1047 | /* Return true if value range information in the lattice is yet unknown. */ | |||
1048 | ||||
1049 | bool | |||
1050 | ipcp_vr_lattice::top_p () const | |||
1051 | { | |||
1052 | return m_vr.undefined_p (); | |||
1053 | } | |||
1054 | ||||
1055 | /* Return true if value range information in the lattice is known to be | |||
1056 | unusable. */ | |||
1057 | ||||
1058 | bool | |||
1059 | ipcp_vr_lattice::bottom_p () const | |||
1060 | { | |||
1061 | return m_vr.varying_p (); | |||
1062 | } | |||
1063 | ||||
1064 | /* Set value range information in the lattice to bottom. Return true if it | |||
1065 | previously was in a different state. */ | |||
1066 | ||||
1067 | bool | |||
1068 | ipcp_vr_lattice::set_to_bottom () | |||
1069 | { | |||
1070 | if (m_vr.varying_p ()) | |||
1071 | return false; | |||
1072 | /* ?? We create all sorts of VARYING ranges for floats, structures, | |||
1073 | and other types which we cannot handle as ranges. We should | |||
1074 | probably avoid handling them throughout the pass, but it's easier | |||
1075 | to create a sensible VARYING here and let the lattice | |||
1076 | propagate. */ | |||
1077 | m_vr.set_varying (integer_type_nodeinteger_types[itk_int]); | |||
1078 | return true; | |||
1079 | } | |||
1080 | ||||
1081 | /* Set lattice value to bottom, if it already isn't the case. */ | |||
1082 | ||||
1083 | bool | |||
1084 | ipcp_bits_lattice::set_to_bottom () | |||
1085 | { | |||
1086 | if (bottom_p ()) | |||
1087 | return false; | |||
1088 | m_lattice_val = IPA_BITS_VARYING; | |||
1089 | m_value = 0; | |||
1090 | m_mask = -1; | |||
1091 | return true; | |||
1092 | } | |||
1093 | ||||
1094 | /* Set to constant if it isn't already. Only meant to be called | |||
1095 | when switching state from TOP. */ | |||
1096 | ||||
1097 | bool | |||
1098 | ipcp_bits_lattice::set_to_constant (widest_int value, widest_int mask) | |||
1099 | { | |||
1100 | gcc_assert (top_p ())((void)(!(top_p ()) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-cp.cc" , 1100, __FUNCTION__), 0 : 0)); | |||
1101 | m_lattice_val = IPA_BITS_CONSTANT; | |||
1102 | m_value = wi::bit_and (wi::bit_not (mask), value); | |||
1103 | m_mask = mask; | |||
1104 | return true; | |||
1105 | } | |||
1106 | ||||
1107 | /* Return true if any of the known bits are non-zero. */ | |||
1108 | ||||
1109 | bool | |||
1110 | ipcp_bits_lattice::known_nonzero_p () const | |||
1111 | { | |||
1112 | if (!constant_p ()) | |||
1113 | return false; | |||
1114 | return wi::ne_p (wi::bit_and (wi::bit_not (m_mask), m_value), 0); | |||
1115 | } | |||
1116 | ||||
1117 | /* Convert operand to value, mask form. */ | |||
1118 | ||||
1119 | void | |||
1120 | ipcp_bits_lattice::get_value_and_mask (tree operand, widest_int *valuep, widest_int *maskp) | |||
1121 | { | |||
1122 | wide_int get_nonzero_bits (const_tree); | |||
1123 | ||||
1124 | if (TREE_CODE (operand)((enum tree_code) (operand)->base.code) == INTEGER_CST) | |||
1125 | { | |||
1126 | *valuep = wi::to_widest (operand); | |||
1127 | *maskp = 0; | |||
1128 | } | |||
1129 | else | |||
1130 | { | |||
1131 | *valuep = 0; | |||
1132 | *maskp = -1; | |||
1133 | } | |||
1134 | } | |||
1135 | ||||
1136 | /* Meet operation, similar to ccp_lattice_meet, we xor values | |||
1137 | if this->value, value have different values at same bit positions, we want | |||
1138 | to drop that bit to varying. Return true if mask is changed. | |||
1139 | This function assumes that the lattice value is in CONSTANT state. If | |||
1140 | DROP_ALL_ONES, mask out any known bits with value one afterwards. */ | |||
1141 | ||||
1142 | bool | |||
1143 | ipcp_bits_lattice::meet_with_1 (widest_int value, widest_int mask, | |||
1144 | unsigned precision, bool drop_all_ones) | |||
1145 | { | |||
1146 | gcc_assert (constant_p ())((void)(!(constant_p ()) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-cp.cc" , 1146, __FUNCTION__), 0 : 0)); | |||
1147 | ||||
1148 | widest_int old_mask = m_mask; | |||
1149 | m_mask = (m_mask | mask) | (m_value ^ value); | |||
1150 | if (drop_all_ones) | |||
1151 | m_mask |= m_value; | |||
1152 | m_value &= ~m_mask; | |||
1153 | ||||
1154 | if (wi::sext (m_mask, precision) == -1) | |||
1155 | return set_to_bottom (); | |||
1156 | ||||
1157 | return m_mask != old_mask; | |||
1158 | } | |||
1159 | ||||
1160 | /* Meet the bits lattice with operand | |||
1161 | described by <value, mask, sgn, precision. */ | |||
1162 | ||||
1163 | bool | |||
1164 | ipcp_bits_lattice::meet_with (widest_int value, widest_int mask, | |||
1165 | unsigned precision) | |||
1166 | { | |||
1167 | if (bottom_p ()) | |||
1168 | return false; | |||
1169 | ||||
1170 | if (top_p ()) | |||
1171 | { | |||
1172 | if (wi::sext (mask, precision) == -1) | |||
1173 | return set_to_bottom (); | |||
1174 | return set_to_constant (value, mask); | |||
1175 | } | |||
1176 | ||||
1177 | return meet_with_1 (value, mask, precision, false); | |||
1178 | } | |||
1179 | ||||
1180 | /* Meet bits lattice with the result of bit_value_binop (other, operand) | |||
1181 | if code is binary operation or bit_value_unop (other) if code is unary op. | |||
1182 | In the case when code is nop_expr, no adjustment is required. If | |||
1183 | DROP_ALL_ONES, mask out any known bits with value one afterwards. */ | |||
1184 | ||||
1185 | bool | |||
1186 | ipcp_bits_lattice::meet_with (ipcp_bits_lattice& other, unsigned precision, | |||
1187 | signop sgn, enum tree_code code, tree operand, | |||
1188 | bool drop_all_ones) | |||
1189 | { | |||
1190 | if (other.bottom_p ()) | |||
1191 | return set_to_bottom (); | |||
1192 | ||||
1193 | if (bottom_p () || other.top_p ()) | |||
1194 | return false; | |||
1195 | ||||
1196 | widest_int adjusted_value, adjusted_mask; | |||
1197 | ||||
1198 | if (TREE_CODE_CLASS (code)tree_code_type_tmpl <0>::tree_code_type[(int) (code)] == tcc_binary) | |||
1199 | { | |||
1200 | tree type = TREE_TYPE (operand)((contains_struct_check ((operand), (TS_TYPED), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-cp.cc" , 1200, __FUNCTION__))->typed.type); | |||
1201 | widest_int o_value, o_mask; | |||
1202 | get_value_and_mask (operand, &o_value, &o_mask); | |||
1203 | ||||
1204 | bit_value_binop (code, sgn, precision, &adjusted_value, &adjusted_mask, | |||
1205 | sgn, precision, other.get_value (), other.get_mask (), | |||
1206 | TYPE_SIGN (type)((signop) ((tree_class_check ((type), (tcc_type), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-cp.cc" , 1206, __FUNCTION__))->base.u.bits.unsigned_flag)), TYPE_PRECISION (type)((tree_class_check ((type), (tcc_type), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-cp.cc" , 1206, __FUNCTION__))->type_common.precision), o_value, o_mask); | |||
1207 | ||||
1208 | if (wi::sext (adjusted_mask, precision) == -1) | |||
1209 | return set_to_bottom (); | |||
1210 | } | |||
1211 | ||||
1212 | else if (TREE_CODE_CLASS (code)tree_code_type_tmpl <0>::tree_code_type[(int) (code)] == tcc_unary) | |||
1213 | { | |||
1214 | bit_value_unop (code, sgn, precision, &adjusted_value, | |||
1215 | &adjusted_mask, sgn, precision, other.get_value (), | |||
1216 | other.get_mask ()); | |||
1217 | ||||
1218 | if (wi::sext (adjusted_mask, precision) == -1) | |||
1219 | return set_to_bottom (); | |||
1220 | } | |||
1221 | ||||
1222 | else | |||
1223 | return set_to_bottom (); | |||
1224 | ||||
1225 | if (top_p ()) | |||
1226 | { | |||
1227 | if (drop_all_ones) | |||
1228 | { | |||
1229 | adjusted_mask |= adjusted_value; | |||
1230 | adjusted_value &= ~adjusted_mask; | |||
1231 | } | |||
1232 | if (wi::sext (adjusted_mask, precision) == -1) | |||
1233 | return set_to_bottom (); | |||
1234 | return set_to_constant (adjusted_value, adjusted_mask); | |||
1235 | } | |||
1236 | else | |||
1237 | return meet_with_1 (adjusted_value, adjusted_mask, precision, | |||
1238 | drop_all_ones); | |||
1239 | } | |||
1240 | ||||
1241 | /* Dump the contents of the list to FILE. */ | |||
1242 | ||||
1243 | void | |||
1244 | ipa_argagg_value_list::dump (FILE *f) | |||
1245 | { | |||
1246 | bool comma = false; | |||
1247 | for (const ipa_argagg_value &av : m_elts) | |||
1248 | { | |||
1249 | fprintf (f, "%s %i[%u]=", comma ? "," : "", | |||
1250 | av.index, av.unit_offset); | |||
1251 | print_generic_expr (f, av.value); | |||
1252 | if (av.by_ref) | |||
1253 | fprintf (f, "(by_ref)"); | |||
1254 | comma = true; | |||
1255 | } | |||
1256 | fprintf (f, "\n"); | |||
1257 | } | |||
1258 | ||||
1259 | /* Dump the contents of the list to stderr. */ | |||
1260 | ||||
1261 | void | |||
1262 | ipa_argagg_value_list::debug () | |||
1263 | { | |||
1264 | dump (stderrstderr); | |||
1265 | } | |||
1266 | ||||
1267 | /* Return the item describing a constant stored for INDEX at UNIT_OFFSET or | |||
1268 | NULL if there is no such constant. */ | |||
1269 | ||||
1270 | const ipa_argagg_value * | |||
1271 | ipa_argagg_value_list::get_elt (int index, unsigned unit_offset) const | |||
1272 | { | |||
1273 | ipa_argagg_value key; | |||
1274 | key.index = index; | |||
1275 | key.unit_offset = unit_offset; | |||
1276 | const ipa_argagg_value *res | |||
1277 | = std::lower_bound (m_elts.begin (), m_elts.end (), key, | |||
1278 | [] (const ipa_argagg_value &elt, | |||
1279 | const ipa_argagg_value &val) | |||
1280 | { | |||
1281 | if (elt.index < val.index) | |||
1282 | return true; | |||
1283 | if (elt.index > val.index) | |||
1284 | return false; | |||
1285 | if (elt.unit_offset < val.unit_offset) | |||
1286 | return true; | |||
1287 | return false; | |||
1288 | }); | |||
1289 | ||||
1290 | if (res == m_elts.end () | |||
1291 | || res->index != index | |||
1292 | || res->unit_offset != unit_offset) | |||
1293 | res = nullptr; | |||
1294 | ||||
1295 | /* TODO: perhaps remove the check (that the underlying array is indeed | |||
1296 | sorted) if it turns out it can be too slow? */ | |||
1297 | if (!flag_checkingglobal_options.x_flag_checking) | |||
1298 | return res; | |||
1299 | ||||
1300 | const ipa_argagg_value *slow_res = NULLnullptr; | |||
1301 | int prev_index = -1; | |||
1302 | unsigned prev_unit_offset = 0; | |||
1303 | for (const ipa_argagg_value &av : m_elts) | |||
1304 | { | |||
1305 | gcc_assert (prev_index < 0((void)(!(prev_index < 0 || prev_index < av.index || prev_unit_offset < av.unit_offset) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-cp.cc" , 1307, __FUNCTION__), 0 : 0)) | |||
1306 | || prev_index < av.index((void)(!(prev_index < 0 || prev_index < av.index || prev_unit_offset < av.unit_offset) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-cp.cc" , 1307, __FUNCTION__), 0 : 0)) | |||
1307 | || prev_unit_offset < av.unit_offset)((void)(!(prev_index < 0 || prev_index < av.index || prev_unit_offset < av.unit_offset) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-cp.cc" , 1307, __FUNCTION__), 0 : 0)); | |||
1308 | prev_index = av.index; | |||
1309 | prev_unit_offset = av.unit_offset; | |||
1310 | if (av.index == index | |||
1311 | && av.unit_offset == unit_offset) | |||
1312 | slow_res = &av; | |||
1313 | } | |||
1314 | gcc_assert (res == slow_res)((void)(!(res == slow_res) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-cp.cc" , 1314, __FUNCTION__), 0 : 0)); | |||
1315 | ||||
1316 | return res; | |||
1317 | } | |||
1318 | ||||
1319 | /* Return the first item describing a constant stored for parameter with INDEX, | |||
1320 | regardless of offset or reference, or NULL if there is no such constant. */ | |||
1321 | ||||
1322 | const ipa_argagg_value * | |||
1323 | ipa_argagg_value_list::get_elt_for_index (int index) const | |||
1324 | { | |||
1325 | const ipa_argagg_value *res | |||
1326 | = std::lower_bound (m_elts.begin (), m_elts.end (), index, | |||
1327 | [] (const ipa_argagg_value &elt, unsigned idx) | |||
1328 | { | |||
1329 | return elt.index < idx; | |||
1330 | }); | |||
1331 | if (res == m_elts.end () | |||
1332 | || res->index != index) | |||
1333 | res = nullptr; | |||
1334 | return res; | |||
1335 | } | |||
1336 | ||||
1337 | /* Return the aggregate constant stored for INDEX at UNIT_OFFSET, not | |||
1338 | performing any check of whether value is passed by reference, or NULL_TREE | |||
1339 | if there is no such constant. */ | |||
1340 | ||||
1341 | tree | |||
1342 | ipa_argagg_value_list::get_value (int index, unsigned unit_offset) const | |||
1343 | { | |||
1344 | const ipa_argagg_value *av = get_elt (index, unit_offset); | |||
1345 | return av ? av->value : NULL_TREE(tree) nullptr; | |||
1346 | } | |||
1347 | ||||
1348 | /* Return the aggregate constant stored for INDEX at UNIT_OFFSET, if it is | |||
1349 | passed by reference or not according to BY_REF, or NULL_TREE if there is | |||
1350 | no such constant. */ | |||
1351 | ||||
1352 | tree | |||
1353 | ipa_argagg_value_list::get_value (int index, unsigned unit_offset, | |||
1354 | bool by_ref) const | |||
1355 | { | |||
1356 | const ipa_argagg_value *av = get_elt (index, unit_offset); | |||
1357 | if (av && av->by_ref == by_ref) | |||
1358 | return av->value; | |||
1359 | return NULL_TREE(tree) nullptr; | |||
1360 | } | |||
1361 | ||||
1362 | /* Return true if all elements present in OTHER are also present in this | |||
1363 | list. */ | |||
1364 | ||||
1365 | bool | |||
1366 | ipa_argagg_value_list::superset_of_p (const ipa_argagg_value_list &other) const | |||
1367 | { | |||
1368 | unsigned j = 0; | |||
1369 | for (unsigned i = 0; i < other.m_elts.size (); i++) | |||
1370 | { | |||
1371 | unsigned other_index = other.m_elts[i].index; | |||
1372 | unsigned other_offset = other.m_elts[i].unit_offset; | |||
1373 | ||||
1374 | while (j < m_elts.size () | |||
1375 | && (m_elts[j].index < other_index | |||
1376 | || (m_elts[j].index == other_index | |||
1377 | && m_elts[j].unit_offset < other_offset))) | |||
1378 | j++; | |||
1379 | ||||
1380 | if (j >= m_elts.size () | |||
1381 | || m_elts[j].index != other_index | |||
1382 | || m_elts[j].unit_offset != other_offset | |||
1383 | || m_elts[j].by_ref != other.m_elts[i].by_ref | |||
1384 | || !m_elts[j].value | |||
1385 | || !values_equal_for_ipcp_p (m_elts[j].value, other.m_elts[i].value)) | |||
1386 | return false; | |||
1387 | } | |||
1388 | return true; | |||
1389 | } | |||
1390 | ||||
1391 | /* Push all items in this list that describe parameter SRC_INDEX into RES as | |||
1392 | ones describing DST_INDEX while subtracting UNIT_DELTA from their unit | |||
1393 | offsets but skip those which would end up with a negative offset. */ | |||
1394 | ||||
1395 | void | |||
1396 | ipa_argagg_value_list::push_adjusted_values (unsigned src_index, | |||
1397 | unsigned dest_index, | |||
1398 | unsigned unit_delta, | |||
1399 | vec<ipa_argagg_value> *res) const | |||
1400 | { | |||
1401 | const ipa_argagg_value *av = get_elt_for_index (src_index); | |||
1402 | if (!av) | |||
1403 | return; | |||
1404 | unsigned prev_unit_offset = 0; | |||
1405 | bool first = true; | |||
1406 | for (; av < m_elts.end (); ++av) | |||
1407 | { | |||
1408 | if (av->index > src_index) | |||
1409 | return; | |||
1410 | if (av->index == src_index | |||
1411 | && (av->unit_offset >= unit_delta) | |||
1412 | && av->value) | |||
1413 | { | |||
1414 | ipa_argagg_value new_av; | |||
1415 | gcc_checking_assert (av->value)((void)(!(av->value) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-cp.cc" , 1415, __FUNCTION__), 0 : 0)); | |||
1416 | new_av.value = av->value; | |||
1417 | new_av.unit_offset = av->unit_offset - unit_delta; | |||
1418 | new_av.index = dest_index; | |||
1419 | new_av.by_ref = av->by_ref; | |||
1420 | ||||
1421 | /* Quick check that the offsets we push are indeed increasing. */ | |||
1422 | gcc_assert (first((void)(!(first || new_av.unit_offset > prev_unit_offset) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-cp.cc" , 1423, __FUNCTION__), 0 : 0)) | |||
1423 | || new_av.unit_offset > prev_unit_offset)((void)(!(first || new_av.unit_offset > prev_unit_offset) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-cp.cc" , 1423, __FUNCTION__), 0 : 0)); | |||
1424 | prev_unit_offset = new_av.unit_offset; | |||
1425 | first = false; | |||
1426 | ||||
1427 | res->safe_push (new_av); | |||
1428 | } | |||
1429 | } | |||
1430 | } | |||
1431 | ||||
1432 | /* Push to RES information about single lattices describing aggregate values in | |||
1433 | PLATS as those describing parameter DEST_INDEX and the original offset minus | |||
1434 | UNIT_DELTA. Return true if any item has been pushed to RES. */ | |||
1435 | ||||
1436 | static bool | |||
1437 | push_agg_values_from_plats (ipcp_param_lattices *plats, int dest_index, | |||
1438 | unsigned unit_delta, | |||
1439 | vec<ipa_argagg_value> *res) | |||
1440 | { | |||
1441 | if (plats->aggs_contain_variable) | |||
1442 | return false; | |||
1443 | ||||
1444 | bool pushed_sth = false; | |||
1445 | bool first = true; | |||
1446 | unsigned prev_unit_offset = 0; | |||
1447 | for (struct ipcp_agg_lattice *aglat = plats->aggs; aglat; aglat = aglat->next) | |||
1448 | if (aglat->is_single_const () | |||
1449 | && (aglat->offset / BITS_PER_UNIT(8) - unit_delta) >= 0) | |||
1450 | { | |||
1451 | ipa_argagg_value iav; | |||
1452 | iav.value = aglat->values->value; | |||
1453 | iav.unit_offset = aglat->offset / BITS_PER_UNIT(8) - unit_delta; | |||
1454 | iav.index = dest_index; | |||
1455 | iav.by_ref = plats->aggs_by_ref; | |||
1456 | ||||
1457 | gcc_assert (first((void)(!(first || iav.unit_offset > prev_unit_offset) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-cp.cc" , 1458, __FUNCTION__), 0 : 0)) | |||
1458 | || iav.unit_offset > prev_unit_offset)((void)(!(first || iav.unit_offset > prev_unit_offset) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-cp.cc" , 1458, __FUNCTION__), 0 : 0)); | |||
1459 | prev_unit_offset = iav.unit_offset; | |||
1460 | first = false; | |||
1461 | ||||
1462 | pushed_sth = true; | |||
1463 | res->safe_push (iav); | |||
1464 | } | |||
1465 | return pushed_sth; | |||
1466 | } | |||
1467 | ||||
1468 | /* Turn all values in LIST that are not present in OTHER into NULL_TREEs. | |||
1469 | Return the number of remaining valid entries. */ | |||
1470 | ||||
1471 | static unsigned | |||
1472 | intersect_argaggs_with (vec<ipa_argagg_value> &elts, | |||
1473 | const vec<ipa_argagg_value> &other) | |||
1474 | { | |||
1475 | unsigned valid_entries = 0; | |||
1476 | unsigned j = 0; | |||
1477 | for (unsigned i = 0; i < elts.length (); i++) | |||
1478 | { | |||
1479 | if (!elts[i].value) | |||
1480 | continue; | |||
1481 | ||||
1482 | unsigned this_index = elts[i].index; | |||
1483 | unsigned this_offset = elts[i].unit_offset; | |||
1484 | ||||
1485 | while (j < other.length () | |||
1486 | && (other[j].index < this_index | |||
1487 | || (other[j].index == this_index | |||
1488 | && other[j].unit_offset < this_offset))) | |||
1489 | j++; | |||
1490 | ||||
1491 | if (j >= other.length ()) | |||
1492 | { | |||
1493 | elts[i].value = NULL_TREE(tree) nullptr; | |||
1494 | continue; | |||
1495 | } | |||
1496 | ||||
1497 | if (other[j].index == this_index | |||
1498 | && other[j].unit_offset == this_offset | |||
1499 | && other[j].by_ref == elts[i].by_ref | |||
1500 | && other[j].value | |||
1501 | && values_equal_for_ipcp_p (other[j].value, elts[i].value)) | |||
1502 | valid_entries++; | |||
1503 | else | |||
1504 | elts[i].value = NULL_TREE(tree) nullptr; | |||
1505 | } | |||
1506 | return valid_entries; | |||
1507 | } | |||
1508 | ||||
1509 | /* Mark bot aggregate and scalar lattices as containing an unknown variable, | |||
1510 | return true is any of them has not been marked as such so far. */ | |||
1511 | ||||
1512 | static inline bool | |||
1513 | set_all_contains_variable (class ipcp_param_lattices *plats) | |||
1514 | { | |||
1515 | bool ret; | |||
1516 | ret = plats->itself.set_contains_variable (); | |||
1517 | ret |= plats->ctxlat.set_contains_variable (); | |||
1518 | ret |= set_agg_lats_contain_variable (plats); | |||
1519 | ret |= plats->bits_lattice.set_to_bottom (); | |||
1520 | ret |= plats->m_value_range.set_to_bottom (); | |||
1521 | return ret; | |||
1522 | } | |||
1523 | ||||
1524 | /* Worker of call_for_symbol_thunks_and_aliases, increment the integer DATA | |||
1525 | points to by the number of callers to NODE. */ | |||
1526 | ||||
1527 | static bool | |||
1528 | count_callers (cgraph_node *node, void *data) | |||
1529 | { | |||
1530 | int *caller_count = (int *) data; | |||
1531 | ||||
1532 | for (cgraph_edge *cs = node->callers; cs; cs = cs->next_caller) | |||
1533 | /* Local thunks can be handled transparently, but if the thunk cannot | |||
1534 | be optimized out, count it as a real use. */ | |||
1535 | if (!cs->caller->thunk || !cs->caller->local) | |||
1536 | ++*caller_count; | |||
1537 | return false; | |||
1538 | } | |||
1539 | ||||
1540 | /* Worker of call_for_symbol_thunks_and_aliases, it is supposed to be called on | |||
1541 | the one caller of some other node. Set the caller's corresponding flag. */ | |||
1542 | ||||
1543 | static bool | |||
1544 | set_single_call_flag (cgraph_node *node, void *) | |||
1545 | { | |||
1546 | cgraph_edge *cs = node->callers; | |||
1547 | /* Local thunks can be handled transparently, skip them. */ | |||
1548 | while (cs && cs->caller->thunk && cs->caller->local) | |||
1549 | cs = cs->next_caller; | |||
1550 | if (cs) | |||
1551 | if (ipa_node_params* info = ipa_node_params_sum->get (cs->caller)) | |||
1552 | { | |||
1553 | info->node_calling_single_call = true; | |||
1554 | return true; | |||
1555 | } | |||
1556 | return false; | |||
1557 | } | |||
1558 | ||||
1559 | /* Initialize ipcp_lattices. */ | |||
1560 | ||||
1561 | static void | |||
1562 | initialize_node_lattices (struct cgraph_node *node) | |||
1563 | { | |||
1564 | ipa_node_params *info = ipa_node_params_sum->get (node); | |||
1565 | struct cgraph_edge *ie; | |||
1566 | bool disable = false, variable = false; | |||
1567 | int i; | |||
1568 | ||||
1569 | gcc_checking_assert (node->has_gimple_body_p ())((void)(!(node->has_gimple_body_p ()) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-cp.cc" , 1569, __FUNCTION__), 0 : 0)); | |||
1570 | ||||
1571 | if (!ipa_get_param_count (info)) | |||
1572 | disable = true; | |||
1573 | else if (node->local) | |||
1574 | { | |||
1575 | int caller_count = 0; | |||
1576 | node->call_for_symbol_thunks_and_aliases (count_callers, &caller_count, | |||
1577 | true); | |||
1578 | gcc_checking_assert (caller_count > 0)((void)(!(caller_count > 0) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-cp.cc" , 1578, __FUNCTION__), 0 : 0)); | |||
1579 | if (caller_count == 1) | |||
1580 | node->call_for_symbol_thunks_and_aliases (set_single_call_flag, | |||
1581 | NULLnullptr, true); | |||
1582 | } | |||
1583 | else | |||
1584 | { | |||
1585 | /* When cloning is allowed, we can assume that externally visible | |||
1586 | functions are not called. We will compensate this by cloning | |||
1587 | later. */ | |||
1588 | if (ipcp_versionable_function_p (node) | |||
1589 | && ipcp_cloning_candidate_p (node)) | |||
1590 | variable = true; | |||
1591 | else | |||
1592 | disable = true; | |||
1593 | } | |||
1594 | ||||
1595 | if (dump_file && (dump_flags & TDF_DETAILS) | |||
1596 | && !node->alias && !node->thunk) | |||
1597 | { | |||
1598 | fprintf (dump_file, "Initializing lattices of %s\n", | |||
1599 | node->dump_name ()); | |||
1600 | if (disable || variable) | |||
1601 | fprintf (dump_file, " Marking all lattices as %s\n", | |||
1602 | disable ? "BOTTOM" : "VARIABLE"); | |||
1603 | } | |||
1604 | ||||
1605 | auto_vec<bool, 16> surviving_params; | |||
1606 | bool pre_modified = false; | |||
1607 | ||||
1608 | clone_info *cinfo = clone_info::get (node); | |||
1609 | ||||
1610 | if (!disable && cinfo && cinfo->param_adjustments) | |||
1611 | { | |||
1612 | /* At the moment all IPA optimizations should use the number of | |||
1613 | parameters of the prevailing decl as the m_always_copy_start. | |||
1614 | Handling any other value would complicate the code below, so for the | |||
1615 | time bing let's only assert it is so. */ | |||
1616 | gcc_assert ((cinfo->param_adjustments->m_always_copy_start((void)(!((cinfo->param_adjustments->m_always_copy_start == ipa_get_param_count (info)) || cinfo->param_adjustments ->m_always_copy_start < 0) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-cp.cc" , 1618, __FUNCTION__), 0 : 0)) | |||
1617 | == ipa_get_param_count (info))((void)(!((cinfo->param_adjustments->m_always_copy_start == ipa_get_param_count (info)) || cinfo->param_adjustments ->m_always_copy_start < 0) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-cp.cc" , 1618, __FUNCTION__), 0 : 0)) | |||
1618 | || cinfo->param_adjustments->m_always_copy_start < 0)((void)(!((cinfo->param_adjustments->m_always_copy_start == ipa_get_param_count (info)) || cinfo->param_adjustments ->m_always_copy_start < 0) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-cp.cc" , 1618, __FUNCTION__), 0 : 0)); | |||
1619 | ||||
1620 | pre_modified = true; | |||
1621 | cinfo->param_adjustments->get_surviving_params (&surviving_params); | |||
1622 | ||||
1623 | if (dump_file && (dump_flags & TDF_DETAILS) | |||
1624 | && !node->alias && !node->thunk) | |||
1625 | { | |||
1626 | bool first = true; | |||
1627 | for (int j = 0; j < ipa_get_param_count (info); j++) | |||
1628 | { | |||
1629 | if (j < (int) surviving_params.length () | |||
1630 | && surviving_params[j]) | |||
1631 | continue; | |||
1632 | if (first) | |||
1633 | { | |||
1634 | fprintf (dump_file, | |||
1635 | " The following parameters are dead on arrival:"); | |||
1636 | first = false; | |||
1637 | } | |||
1638 | fprintf (dump_file, " %u", j); | |||
1639 | } | |||
1640 | if (!first) | |||
1641 | fprintf (dump_file, "\n"); | |||
1642 | } | |||
1643 | } | |||
1644 | ||||
1645 | for (i = 0; i < ipa_get_param_count (info); i++) | |||
1646 | { | |||
1647 | ipcp_param_lattices *plats = ipa_get_parm_lattices (info, i); | |||
1648 | if (disable | |||
1649 | || !ipa_get_type (info, i) | |||
1650 | || (pre_modified && (surviving_params.length () <= (unsigned) i | |||
1651 | || !surviving_params[i]))) | |||
1652 | { | |||
1653 | plats->itself.set_to_bottom (); | |||
1654 | plats->ctxlat.set_to_bottom (); | |||
1655 | set_agg_lats_to_bottom (plats); | |||
1656 | plats->bits_lattice.set_to_bottom (); | |||
1657 | plats->m_value_range.m_vr = value_range (); | |||
1658 | plats->m_value_range.set_to_bottom (); | |||
1659 | } | |||
1660 | else | |||
1661 | { | |||
1662 | plats->m_value_range.init (); | |||
1663 | if (variable) | |||
1664 | set_all_contains_variable (plats); | |||
1665 | } | |||
1666 | } | |||
1667 | ||||
1668 | for (ie = node->indirect_calls; ie; ie = ie->next_callee) | |||
1669 | if (ie->indirect_info->polymorphic | |||
1670 | && ie->indirect_info->param_index >= 0) | |||
1671 | { | |||
1672 | gcc_checking_assert (ie->indirect_info->param_index >= 0)((void)(!(ie->indirect_info->param_index >= 0) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-cp.cc" , 1672, __FUNCTION__), 0 : 0)); | |||
1673 | ipa_get_parm_lattices (info, | |||
1674 | ie->indirect_info->param_index)->virt_call = 1; | |||
1675 | } | |||
1676 | } | |||
1677 | ||||
1678 | /* Return true if VALUE can be safely IPA-CP propagated to a parameter of type | |||
1679 | PARAM_TYPE. */ | |||
1680 | ||||
1681 | static bool | |||
1682 | ipacp_value_safe_for_type (tree param_type, tree value) | |||
1683 | { | |||
1684 | tree val_type = TREE_TYPE (value)((contains_struct_check ((value), (TS_TYPED), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-cp.cc" , 1684, __FUNCTION__))->typed.type); | |||
1685 | if (param_type == val_type | |||
1686 | || useless_type_conversion_p (param_type, val_type) | |||
1687 | || fold_convertible_p (param_type, value)) | |||
1688 | return true; | |||
1689 | else | |||
1690 | return false; | |||
1691 | } | |||
1692 | ||||
1693 | /* Return the result of a (possibly arithmetic) operation on the constant | |||
1694 | value INPUT. OPERAND is 2nd operand for binary operation. RES_TYPE is | |||
1695 | the type of the parameter to which the result is passed. Return | |||
1696 | NULL_TREE if that cannot be determined or be considered an | |||
1697 | interprocedural invariant. */ | |||
1698 | ||||
1699 | static tree | |||
1700 | ipa_get_jf_arith_result (enum tree_code opcode, tree input, tree operand, | |||
1701 | tree res_type) | |||
1702 | { | |||
1703 | tree res; | |||
1704 | ||||
1705 | if (opcode == NOP_EXPR) | |||
1706 | return input; | |||
1707 | if (!is_gimple_ip_invariant (input)) | |||
1708 | return NULL_TREE(tree) nullptr; | |||
1709 | ||||
1710 | if (opcode == ASSERT_EXPR) | |||
1711 | { | |||
1712 | if (values_equal_for_ipcp_p (input, operand)) | |||
1713 | return input; | |||
1714 | else | |||
1715 | return NULL_TREE(tree) nullptr; | |||
1716 | } | |||
1717 | ||||
1718 | if (!res_type) | |||
1719 | { | |||
1720 | if (TREE_CODE_CLASS (opcode)tree_code_type_tmpl <0>::tree_code_type[(int) (opcode)] == tcc_comparison) | |||
1721 | res_type = boolean_type_nodeglobal_trees[TI_BOOLEAN_TYPE]; | |||
1722 | else if (expr_type_first_operand_type_p (opcode)) | |||
1723 | res_type = TREE_TYPE (input)((contains_struct_check ((input), (TS_TYPED), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-cp.cc" , 1723, __FUNCTION__))->typed.type); | |||
1724 | else | |||
1725 | return NULL_TREE(tree) nullptr; | |||
1726 | } | |||
1727 | ||||
1728 | if (TREE_CODE_CLASS (opcode)tree_code_type_tmpl <0>::tree_code_type[(int) (opcode)] == tcc_unary) | |||
1729 | res = fold_unary (opcode, res_type, input)fold_unary_loc (((location_t) 0), opcode, res_type, input); | |||
1730 | else | |||
1731 | res = fold_binary (opcode, res_type, input, operand)fold_binary_loc (((location_t) 0), opcode, res_type, input, operand ); | |||
1732 | ||||
1733 | if (res && !is_gimple_ip_invariant (res)) | |||
1734 | return NULL_TREE(tree) nullptr; | |||
1735 | ||||
1736 | return res; | |||
1737 | } | |||
1738 | ||||
1739 | /* Return the result of a (possibly arithmetic) pass through jump function | |||
1740 | JFUNC on the constant value INPUT. RES_TYPE is the type of the parameter | |||
1741 | to which the result is passed. Return NULL_TREE if that cannot be | |||
1742 | determined or be considered an interprocedural invariant. */ | |||
1743 | ||||
1744 | static tree | |||
1745 | ipa_get_jf_pass_through_result (struct ipa_jump_func *jfunc, tree input, | |||
1746 | tree res_type) | |||
1747 | { | |||
1748 | return ipa_get_jf_arith_result (ipa_get_jf_pass_through_operation (jfunc), | |||
1749 | input, | |||
1750 | ipa_get_jf_pass_through_operand (jfunc), | |||
1751 | res_type); | |||
1752 | } | |||
1753 | ||||
1754 | /* Return the result of an ancestor jump function JFUNC on the constant value | |||
1755 | INPUT. Return NULL_TREE if that cannot be determined. */ | |||
1756 | ||||
1757 | static tree | |||
1758 | ipa_get_jf_ancestor_result (struct ipa_jump_func *jfunc, tree input) | |||
1759 | { | |||
1760 | gcc_checking_assert (TREE_CODE (input) != TREE_BINFO)((void)(!(((enum tree_code) (input)->base.code) != TREE_BINFO ) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-cp.cc" , 1760, __FUNCTION__), 0 : 0)); | |||
1761 | if (TREE_CODE (input)((enum tree_code) (input)->base.code) == ADDR_EXPR) | |||
1762 | { | |||
1763 | gcc_checking_assert (is_gimple_ip_invariant_address (input))((void)(!(is_gimple_ip_invariant_address (input)) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-cp.cc" , 1763, __FUNCTION__), 0 : 0)); | |||
1764 | poly_int64 off = ipa_get_jf_ancestor_offset (jfunc); | |||
1765 | if (known_eq (off, 0)(!maybe_ne (off, 0))) | |||
1766 | return input; | |||
1767 | poly_int64 byte_offset = exact_div (off, BITS_PER_UNIT(8)); | |||
1768 | return build1 (ADDR_EXPR, TREE_TYPE (input)((contains_struct_check ((input), (TS_TYPED), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-cp.cc" , 1768, __FUNCTION__))->typed.type), | |||
1769 | fold_build2 (MEM_REF, TREE_TYPE (TREE_TYPE (input)), input,fold_build2_loc (((location_t) 0), MEM_REF, ((contains_struct_check ((((contains_struct_check ((input), (TS_TYPED), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-cp.cc" , 1769, __FUNCTION__))->typed.type)), (TS_TYPED), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-cp.cc" , 1769, __FUNCTION__))->typed.type), input, build_int_cst ( global_trees[TI_PTR_TYPE], byte_offset) ) | |||
1770 | build_int_cst (ptr_type_node, byte_offset))fold_build2_loc (((location_t) 0), MEM_REF, ((contains_struct_check ((((contains_struct_check ((input), (TS_TYPED), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-cp.cc" , 1769, __FUNCTION__))->typed.type)), (TS_TYPED), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-cp.cc" , 1769, __FUNCTION__))->typed.type), input, build_int_cst ( global_trees[TI_PTR_TYPE], byte_offset) )); | |||
1771 | } | |||
1772 | else if (ipa_get_jf_ancestor_keep_null (jfunc) | |||
1773 | && zerop (input)) | |||
1774 | return input; | |||
1775 | else | |||
1776 | return NULL_TREE(tree) nullptr; | |||
1777 | } | |||
1778 | ||||
1779 | /* Determine whether JFUNC evaluates to a single known constant value and if | |||
1780 | so, return it. Otherwise return NULL. INFO describes the caller node or | |||
1781 | the one it is inlined to, so that pass-through jump functions can be | |||
1782 | evaluated. PARM_TYPE is the type of the parameter to which the result is | |||
1783 | passed. */ | |||
1784 | ||||
1785 | tree | |||
1786 | ipa_value_from_jfunc (class ipa_node_params *info, struct ipa_jump_func *jfunc, | |||
1787 | tree parm_type) | |||
1788 | { | |||
1789 | if (jfunc->type == IPA_JF_CONST) | |||
1790 | return ipa_get_jf_constant (jfunc); | |||
1791 | else if (jfunc->type == IPA_JF_PASS_THROUGH | |||
1792 | || jfunc->type == IPA_JF_ANCESTOR) | |||
1793 | { | |||
1794 | tree input; | |||
1795 | int idx; | |||
1796 | ||||
1797 | if (jfunc->type == IPA_JF_PASS_THROUGH) | |||
1798 | idx = ipa_get_jf_pass_through_formal_id (jfunc); | |||
1799 | else | |||
1800 | idx = ipa_get_jf_ancestor_formal_id (jfunc); | |||
1801 | ||||
1802 | if (info->ipcp_orig_node) | |||
1803 | input = info->known_csts[idx]; | |||
1804 | else | |||
1805 | { | |||
1806 | ipcp_lattice<tree> *lat; | |||
1807 | ||||
1808 | if (!info->lattices | |||
1809 | || idx >= ipa_get_param_count (info)) | |||
1810 | return NULL_TREE(tree) nullptr; | |||
1811 | lat = ipa_get_scalar_lat (info, idx); | |||
1812 | if (!lat->is_single_const ()) | |||
1813 | return NULL_TREE(tree) nullptr; | |||
1814 | input = lat->values->value; | |||
1815 | } | |||
1816 | ||||
1817 | if (!input) | |||
1818 | return NULL_TREE(tree) nullptr; | |||
1819 | ||||
1820 | if (jfunc->type == IPA_JF_PASS_THROUGH) | |||
1821 | return ipa_get_jf_pass_through_result (jfunc, input, parm_type); | |||
1822 | else | |||
1823 | return ipa_get_jf_ancestor_result (jfunc, input); | |||
1824 | } | |||
1825 | else | |||
1826 | return NULL_TREE(tree) nullptr; | |||
1827 | } | |||
1828 | ||||
1829 | /* Determine whether JFUNC evaluates to single known polymorphic context, given | |||
1830 | that INFO describes the caller node or the one it is inlined to, CS is the | |||
1831 | call graph edge corresponding to JFUNC and CSIDX index of the described | |||
1832 | parameter. */ | |||
1833 | ||||
1834 | ipa_polymorphic_call_context | |||
1835 | ipa_context_from_jfunc (ipa_node_params *info, cgraph_edge *cs, int csidx, | |||
1836 | ipa_jump_func *jfunc) | |||
1837 | { | |||
1838 | ipa_edge_args *args = ipa_edge_args_sum->get (cs); | |||
1839 | ipa_polymorphic_call_context ctx; | |||
1840 | ipa_polymorphic_call_context *edge_ctx | |||
1841 | = cs ? ipa_get_ith_polymorhic_call_context (args, csidx) : NULLnullptr; | |||
1842 | ||||
1843 | if (edge_ctx && !edge_ctx->useless_p ()) | |||
1844 | ctx = *edge_ctx; | |||
1845 | ||||
1846 | if (jfunc->type == IPA_JF_PASS_THROUGH | |||
1847 | || jfunc->type == IPA_JF_ANCESTOR) | |||
1848 | { | |||
1849 | ipa_polymorphic_call_context srcctx; | |||
1850 | int srcidx; | |||
1851 | bool type_preserved = true; | |||
1852 | if (jfunc->type == IPA_JF_PASS_THROUGH) | |||
1853 | { | |||
1854 | if (ipa_get_jf_pass_through_operation (jfunc) != NOP_EXPR) | |||
1855 | return ctx; | |||
1856 | type_preserved = ipa_get_jf_pass_through_type_preserved (jfunc); | |||
1857 | srcidx = ipa_get_jf_pass_through_formal_id (jfunc); | |||
1858 | } | |||
1859 | else | |||
1860 | { | |||
1861 | type_preserved = ipa_get_jf_ancestor_type_preserved (jfunc); | |||
1862 | srcidx = ipa_get_jf_ancestor_formal_id (jfunc); | |||
1863 | } | |||
1864 | if (info->ipcp_orig_node) | |||
1865 | { | |||
1866 | if (info->known_contexts.exists ()) | |||
1867 | srcctx = info->known_contexts[srcidx]; | |||
1868 | } | |||
1869 | else | |||
1870 | { | |||
1871 | if (!info->lattices | |||
1872 | || srcidx >= ipa_get_param_count (info)) | |||
1873 | return ctx; | |||
1874 | ipcp_lattice<ipa_polymorphic_call_context> *lat; | |||
1875 | lat = ipa_get_poly_ctx_lat (info, srcidx); | |||
1876 | if (!lat->is_single_const ()) | |||
1877 | return ctx; | |||
1878 | srcctx = lat->values->value; | |||
1879 | } | |||
1880 | if (srcctx.useless_p ()) | |||
1881 | return ctx; | |||
1882 | if (jfunc->type == IPA_JF_ANCESTOR) | |||
1883 | srcctx.offset_by (ipa_get_jf_ancestor_offset (jfunc)); | |||
1884 | if (!type_preserved) | |||
1885 | srcctx.possible_dynamic_type_change (cs->in_polymorphic_cdtor); | |||
1886 | srcctx.combine_with (ctx); | |||
1887 | return srcctx; | |||
1888 | } | |||
1889 | ||||
1890 | return ctx; | |||
1891 | } | |||
1892 | ||||
1893 | /* Emulate effects of unary OPERATION and/or conversion from SRC_TYPE to | |||
1894 | DST_TYPE on value range in SRC_VR and store it to DST_VR. Return true if | |||
1895 | the result is a range or an anti-range. */ | |||
1896 | ||||
1897 | static bool | |||
1898 | ipa_vr_operation_and_type_effects (value_range *dst_vr, | |||
1899 | value_range *src_vr, | |||
1900 | enum tree_code operation, | |||
1901 | tree dst_type, tree src_type) | |||
1902 | { | |||
1903 | range_fold_unary_expr (dst_vr, operation, dst_type, src_vr, src_type); | |||
1904 | if (dst_vr->varying_p () || dst_vr->undefined_p ()) | |||
1905 | return false; | |||
1906 | return true; | |||
1907 | } | |||
1908 | ||||
1909 | /* Determine value_range of JFUNC given that INFO describes the caller node or | |||
1910 | the one it is inlined to, CS is the call graph edge corresponding to JFUNC | |||
1911 | and PARM_TYPE of the parameter. */ | |||
1912 | ||||
1913 | value_range | |||
1914 | ipa_value_range_from_jfunc (ipa_node_params *info, cgraph_edge *cs, | |||
1915 | ipa_jump_func *jfunc, tree parm_type) | |||
1916 | { | |||
1917 | value_range vr; | |||
1918 | if (jfunc->m_vr) | |||
1919 | ipa_vr_operation_and_type_effects (&vr, | |||
1920 | jfunc->m_vr, | |||
1921 | NOP_EXPR, parm_type, | |||
1922 | jfunc->m_vr->type ()); | |||
1923 | if (vr.singleton_p ()) | |||
1924 | return vr; | |||
1925 | if (jfunc->type == IPA_JF_PASS_THROUGH) | |||
1926 | { | |||
1927 | int idx; | |||
1928 | ipcp_transformation *sum | |||
1929 | = ipcp_get_transformation_summary (cs->caller->inlined_to | |||
1930 | ? cs->caller->inlined_to | |||
1931 | : cs->caller); | |||
1932 | if (!sum || !sum->m_vr) | |||
1933 | return vr; | |||
1934 | ||||
1935 | idx = ipa_get_jf_pass_through_formal_id (jfunc); | |||
1936 | ||||
1937 | if (!(*sum->m_vr)[idx].known) | |||
1938 | return vr; | |||
1939 | tree vr_type = ipa_get_type (info, idx); | |||
1940 | value_range srcvr (wide_int_to_tree (vr_type, (*sum->m_vr)[idx].min), | |||
1941 | wide_int_to_tree (vr_type, (*sum->m_vr)[idx].max), | |||
1942 | (*sum->m_vr)[idx].type); | |||
1943 | ||||
1944 | enum tree_code operation = ipa_get_jf_pass_through_operation (jfunc); | |||
1945 | ||||
1946 | if (TREE_CODE_CLASS (operation)tree_code_type_tmpl <0>::tree_code_type[(int) (operation )] == tcc_unary) | |||
1947 | { | |||
1948 | value_range res; | |||
1949 | ||||
1950 | if (ipa_vr_operation_and_type_effects (&res, | |||
1951 | &srcvr, | |||
1952 | operation, parm_type, | |||
1953 | vr_type)) | |||
1954 | vr.intersect (res); | |||
1955 | } | |||
1956 | else | |||
1957 | { | |||
1958 | value_range op_res, res; | |||
1959 | tree op = ipa_get_jf_pass_through_operand (jfunc); | |||
1960 | value_range op_vr (op, op); | |||
1961 | ||||
1962 | range_fold_binary_expr (&op_res, operation, vr_type, &srcvr, &op_vr); | |||
1963 | if (ipa_vr_operation_and_type_effects (&res, | |||
1964 | &op_res, | |||
1965 | NOP_EXPR, parm_type, | |||
1966 | vr_type)) | |||
1967 | vr.intersect (res); | |||
1968 | } | |||
1969 | } | |||
1970 | return vr; | |||
1971 | } | |||
1972 | ||||
1973 | /* Determine whether ITEM, jump function for an aggregate part, evaluates to a | |||
1974 | single known constant value and if so, return it. Otherwise return NULL. | |||
1975 | NODE and INFO describes the caller node or the one it is inlined to, and | |||
1976 | its related info. */ | |||
1977 | ||||
1978 | tree | |||
1979 | ipa_agg_value_from_jfunc (ipa_node_params *info, cgraph_node *node, | |||
1980 | const ipa_agg_jf_item *item) | |||
1981 | { | |||
1982 | tree value = NULL_TREE(tree) nullptr; | |||
1983 | int src_idx; | |||
1984 | ||||
1985 | if (item->offset < 0 | |||
1986 | || item->jftype == IPA_JF_UNKNOWN | |||
1987 | || item->offset >= (HOST_WIDE_INTlong) UINT_MAX(2147483647 *2U +1U) * BITS_PER_UNIT(8)) | |||
1988 | return NULL_TREE(tree) nullptr; | |||
1989 | ||||
1990 | if (item->jftype == IPA_JF_CONST) | |||
1991 | return item->value.constant; | |||
1992 | ||||
1993 | gcc_checking_assert (item->jftype == IPA_JF_PASS_THROUGH((void)(!(item->jftype == IPA_JF_PASS_THROUGH || item-> jftype == IPA_JF_LOAD_AGG) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-cp.cc" , 1994, __FUNCTION__), 0 : 0)) | |||
1994 | || item->jftype == IPA_JF_LOAD_AGG)((void)(!(item->jftype == IPA_JF_PASS_THROUGH || item-> jftype == IPA_JF_LOAD_AGG) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-cp.cc" , 1994, __FUNCTION__), 0 : 0)); | |||
1995 | ||||
1996 | src_idx = item->value.pass_through.formal_id; | |||
1997 | ||||
1998 | if (info->ipcp_orig_node) | |||
1999 | { | |||
2000 | if (item->jftype == IPA_JF_PASS_THROUGH) | |||
2001 | value = info->known_csts[src_idx]; | |||
2002 | else if (ipcp_transformation *ts = ipcp_get_transformation_summary (node)) | |||
2003 | { | |||
2004 | ipa_argagg_value_list avl (ts); | |||
2005 | value = avl.get_value (src_idx, | |||
2006 | item->value.load_agg.offset / BITS_PER_UNIT(8), | |||
2007 | item->value.load_agg.by_ref); | |||
2008 | } | |||
2009 | } | |||
2010 | else if (info->lattices) | |||
2011 | { | |||
2012 | class ipcp_param_lattices *src_plats | |||
2013 | = ipa_get_parm_lattices (info, src_idx); | |||
2014 | ||||
2015 | if (item->jftype == IPA_JF_PASS_THROUGH) | |||
2016 | { | |||
2017 | struct ipcp_lattice<tree> *lat = &src_plats->itself; | |||
2018 | ||||
2019 | if (!lat->is_single_const ()) | |||
2020 | return NULL_TREE(tree) nullptr; | |||
2021 | ||||
2022 | value = lat->values->value; | |||
2023 | } | |||
2024 | else if (src_plats->aggs | |||
2025 | && !src_plats->aggs_bottom | |||
2026 | && !src_plats->aggs_contain_variable | |||
2027 | && src_plats->aggs_by_ref == item->value.load_agg.by_ref) | |||
2028 | { | |||
2029 | struct ipcp_agg_lattice *aglat; | |||
2030 | ||||
2031 | for (aglat = src_plats->aggs; aglat; aglat = aglat->next) | |||
2032 | { | |||
2033 | if (aglat->offset > item->value.load_agg.offset) | |||
2034 | break; | |||
2035 | ||||
2036 | if (aglat->offset == item->value.load_agg.offset) | |||
2037 | { | |||
2038 | if (aglat->is_single_const ()) | |||
2039 | value = aglat->values->value; | |||
2040 | break; | |||
2041 | } | |||
2042 | } | |||
2043 | } | |||
2044 | } | |||
2045 | ||||
2046 | if (!value) | |||
2047 | return NULL_TREE(tree) nullptr; | |||
2048 | ||||
2049 | if (item->jftype == IPA_JF_LOAD_AGG) | |||
2050 | { | |||
2051 | tree load_type = item->value.load_agg.type; | |||
2052 | tree value_type = TREE_TYPE (value)((contains_struct_check ((value), (TS_TYPED), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-cp.cc" , 2052, __FUNCTION__))->typed.type); | |||
2053 | ||||
2054 | /* Ensure value type is compatible with load type. */ | |||
2055 | if (!useless_type_conversion_p (load_type, value_type)) | |||
2056 | return NULL_TREE(tree) nullptr; | |||
2057 | } | |||
2058 | ||||
2059 | return ipa_get_jf_arith_result (item->value.pass_through.operation, | |||
2060 | value, | |||
2061 | item->value.pass_through.operand, | |||
2062 | item->type); | |||
2063 | } | |||
2064 | ||||
2065 | /* Process all items in AGG_JFUNC relative to caller (or the node the original | |||
2066 | caller is inlined to) NODE which described by INFO and push the results to | |||
2067 | RES as describing values passed in parameter DST_INDEX. */ | |||
2068 | ||||
2069 | void | |||
2070 | ipa_push_agg_values_from_jfunc (ipa_node_params *info, cgraph_node *node, | |||
2071 | ipa_agg_jump_function *agg_jfunc, | |||
2072 | unsigned dst_index, | |||
2073 | vec<ipa_argagg_value> *res) | |||
2074 | { | |||
2075 | unsigned prev_unit_offset = 0; | |||
2076 | bool first = true; | |||
2077 | ||||
2078 | for (const ipa_agg_jf_item &item : agg_jfunc->items) | |||
2079 | { | |||
2080 | tree value = ipa_agg_value_from_jfunc (info, node, &item); | |||
2081 | if (!value) | |||
2082 | continue; | |||
2083 | ||||
2084 | ipa_argagg_value iav; | |||
2085 | iav.value = value; | |||
2086 | iav.unit_offset = item.offset / BITS_PER_UNIT(8); | |||
2087 | iav.index = dst_index; | |||
2088 | iav.by_ref = agg_jfunc->by_ref; | |||
2089 | ||||
2090 | gcc_assert (first((void)(!(first || iav.unit_offset > prev_unit_offset) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-cp.cc" , 2091, __FUNCTION__), 0 : 0)) | |||
2091 | || iav.unit_offset > prev_unit_offset)((void)(!(first || iav.unit_offset > prev_unit_offset) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-cp.cc" , 2091, __FUNCTION__), 0 : 0)); | |||
2092 | prev_unit_offset = iav.unit_offset; | |||
2093 | first = false; | |||
2094 | ||||
2095 | res->safe_push (iav); | |||
2096 | } | |||
2097 | } | |||
2098 | ||||
2099 | /* If checking is enabled, verify that no lattice is in the TOP state, i.e. not | |||
2100 | bottom, not containing a variable component and without any known value at | |||
2101 | the same time. */ | |||
2102 | ||||
2103 | DEBUG_FUNCTION__attribute__ ((__used__)) void | |||
2104 | ipcp_verify_propagated_values (void) | |||
2105 | { | |||
2106 | struct cgraph_node *node; | |||
2107 | ||||
2108 | FOR_EACH_FUNCTION_WITH_GIMPLE_BODY (node)for ((node) = symtab->first_function_with_gimple_body (); ( node); (node) = symtab->next_function_with_gimple_body (node )) | |||
2109 | { | |||
2110 | ipa_node_params *info = ipa_node_params_sum->get (node); | |||
2111 | if (!opt_for_fn (node->decl, flag_ipa_cp)(opts_for_fn (node->decl)->x_flag_ipa_cp) | |||
2112 | || !opt_for_fn (node->decl, optimize)(opts_for_fn (node->decl)->x_optimize)) | |||
2113 | continue; | |||
2114 | int i, count = ipa_get_param_count (info); | |||
2115 | ||||
2116 | for (i = 0; i < count; i++) | |||
2117 | { | |||
2118 | ipcp_lattice<tree> *lat = ipa_get_scalar_lat (info, i); | |||
2119 | ||||
2120 | if (!lat->bottom | |||
2121 | && !lat->contains_variable | |||
2122 | && lat->values_count == 0) | |||
2123 | { | |||
2124 | if (dump_file) | |||
2125 | { | |||
2126 | symtab->dump (dump_file); | |||
2127 | fprintf (dump_file, "\nIPA lattices after constant " | |||
2128 | "propagation, before gcc_unreachable:\n"); | |||
2129 | print_all_lattices (dump_file, true, false); | |||
2130 | } | |||
2131 | ||||
2132 | gcc_unreachable ()(fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-cp.cc" , 2132, __FUNCTION__)); | |||
2133 | } | |||
2134 | } | |||
2135 | } | |||
2136 | } | |||
2137 | ||||
2138 | /* Return true iff X and Y should be considered equal contexts by IPA-CP. */ | |||
2139 | ||||
2140 | static bool | |||
2141 | values_equal_for_ipcp_p (ipa_polymorphic_call_context x, | |||
2142 | ipa_polymorphic_call_context y) | |||
2143 | { | |||
2144 | return x.equal_to (y); | |||
2145 | } | |||
2146 | ||||
2147 | ||||
2148 | /* Add a new value source to the value represented by THIS, marking that a | |||
2149 | value comes from edge CS and (if the underlying jump function is a | |||
2150 | pass-through or an ancestor one) from a caller value SRC_VAL of a caller | |||
2151 | parameter described by SRC_INDEX. OFFSET is negative if the source was the | |||
2152 | scalar value of the parameter itself or the offset within an aggregate. */ | |||
2153 | ||||
2154 | template <typename valtype> | |||
2155 | void | |||
2156 | ipcp_value<valtype>::add_source (cgraph_edge *cs, ipcp_value *src_val, | |||
2157 | int src_idx, HOST_WIDE_INTlong offset) | |||
2158 | { | |||
2159 | ipcp_value_source<valtype> *src; | |||
2160 | ||||
2161 | src = new (ipcp_sources_pool.allocate ()) ipcp_value_source<valtype>; | |||
2162 | src->offset = offset; | |||
2163 | src->cs = cs; | |||
2164 | src->val = src_val; | |||
2165 | src->index = src_idx; | |||
2166 | ||||
2167 | src->next = sources; | |||
2168 | sources = src; | |||
2169 | } | |||
2170 | ||||
2171 | /* Allocate a new ipcp_value holding a tree constant, initialize its value to | |||
2172 | SOURCE and clear all other fields. */ | |||
2173 | ||||
2174 | static ipcp_value<tree> * | |||
2175 | allocate_and_init_ipcp_value (tree cst, unsigned same_lat_gen_level) | |||
2176 | { | |||
2177 | ipcp_value<tree> *val; | |||
2178 | ||||
2179 | val = new (ipcp_cst_values_pool.allocate ()) ipcp_value<tree>(); | |||
2180 | val->value = cst; | |||
2181 | val->self_recursion_generated_level = same_lat_gen_level; | |||
2182 | return val; | |||
2183 | } | |||
2184 | ||||
2185 | /* Allocate a new ipcp_value holding a polymorphic context, initialize its | |||
2186 | value to SOURCE and clear all other fields. */ | |||
2187 | ||||
2188 | static ipcp_value<ipa_polymorphic_call_context> * | |||
2189 | allocate_and_init_ipcp_value (ipa_polymorphic_call_context ctx, | |||
2190 | unsigned same_lat_gen_level) | |||
2191 | { | |||
2192 | ipcp_value<ipa_polymorphic_call_context> *val; | |||
2193 | ||||
2194 | val = new (ipcp_poly_ctx_values_pool.allocate ()) | |||
2195 | ipcp_value<ipa_polymorphic_call_context>(); | |||
2196 | val->value = ctx; | |||
2197 | val->self_recursion_generated_level = same_lat_gen_level; | |||
2198 | return val; | |||
2199 | } | |||
2200 | ||||
2201 | /* Try to add NEWVAL to LAT, potentially creating a new ipcp_value for it. CS, | |||
2202 | SRC_VAL SRC_INDEX and OFFSET are meant for add_source and have the same | |||
2203 | meaning. OFFSET -1 means the source is scalar and not a part of an | |||
2204 | aggregate. If non-NULL, VAL_P records address of existing or newly added | |||
2205 | ipcp_value. | |||
2206 | ||||
2207 | If the value is generated for a self-recursive call as a result of an | |||
2208 | arithmetic pass-through jump-function acting on a value in the same lattice, | |||
2209 | SAME_LAT_GEN_LEVEL must be the length of such chain, otherwise it must be | |||
2210 | zero. If it is non-zero, PARAM_IPA_CP_VALUE_LIST_SIZE limit is ignored. */ | |||
2211 | ||||
2212 | template <typename valtype> | |||
2213 | bool | |||
2214 | ipcp_lattice<valtype>::add_value (valtype newval, cgraph_edge *cs, | |||
2215 | ipcp_value<valtype> *src_val, | |||
2216 | int src_idx, HOST_WIDE_INTlong offset, | |||
2217 | ipcp_value<valtype> **val_p, | |||
2218 | unsigned same_lat_gen_level) | |||
2219 | { | |||
2220 | ipcp_value<valtype> *val, *last_val = NULLnullptr; | |||
2221 | ||||
2222 | if (val_p) | |||
2223 | *val_p = NULLnullptr; | |||
2224 | ||||
2225 | if (bottom) | |||
2226 | return false; | |||
2227 | ||||
2228 | for (val = values; val; last_val = val, val = val->next) | |||
2229 | if (values_equal_for_ipcp_p (val->value, newval)) | |||
2230 | { | |||
2231 | if (val_p) | |||
2232 | *val_p = val; | |||
2233 | ||||
2234 | if (val->self_recursion_generated_level < same_lat_gen_level) | |||
2235 | val->self_recursion_generated_level = same_lat_gen_level; | |||
2236 | ||||
2237 | if (ipa_edge_within_scc (cs)) | |||
2238 | { | |||
2239 | ipcp_value_source<valtype> *s; | |||
2240 | for (s = val->sources; s; s = s->next) | |||
2241 | if (s->cs == cs && s->val == src_val) | |||
2242 | break; | |||
2243 | if (s) | |||
2244 | return false; | |||
2245 | } | |||
2246 | ||||
2247 | val->add_source (cs, src_val, src_idx, offset); | |||
2248 | return false; | |||
2249 | } | |||
2250 | ||||
2251 | if (!same_lat_gen_level && values_count == opt_for_fn (cs->caller->decl,(opts_for_fn (cs->caller->decl)->x_param_ipa_cp_value_list_size ) | |||
2252 | param_ipa_cp_value_list_size)(opts_for_fn (cs->caller->decl)->x_param_ipa_cp_value_list_size )) | |||
2253 | { | |||
2254 | /* We can only free sources, not the values themselves, because sources | |||
2255 | of other values in this SCC might point to them. */ | |||
2256 | for (val = values; val; val = val->next) | |||
2257 | { | |||
2258 | while (val->sources) | |||
2259 | { | |||
2260 | ipcp_value_source<valtype> *src = val->sources; | |||
2261 | val->sources = src->next; | |||
2262 | ipcp_sources_pool.remove ((ipcp_value_source<tree>*)src); | |||
2263 | } | |||
2264 | } | |||
2265 | values = NULLnullptr; | |||
2266 | return set_to_bottom (); | |||
2267 | } | |||
2268 | ||||
2269 | values_count++; | |||
2270 | val = allocate_and_init_ipcp_value (newval, same_lat_gen_level); | |||
2271 | val->add_source (cs, src_val, src_idx, offset); | |||
2272 | val->next = NULLnullptr; | |||
2273 | ||||
2274 | /* Add the new value to end of value list, which can reduce iterations | |||
2275 | of propagation stage for recursive function. */ | |||
2276 | if (last_val) | |||
2277 | last_val->next = val; | |||
2278 | else | |||
2279 | values = val; | |||
2280 | ||||
2281 | if (val_p) | |||
2282 | *val_p = val; | |||
2283 | ||||
2284 | return true; | |||
2285 | } | |||
2286 | ||||
2287 | /* A helper function that returns result of operation specified by OPCODE on | |||
2288 | the value of SRC_VAL. If non-NULL, OPND1_TYPE is expected type for the | |||
2289 | value of SRC_VAL. If the operation is binary, OPND2 is a constant value | |||
2290 | acting as its second operand. If non-NULL, RES_TYPE is expected type of | |||
2291 | the result. */ | |||
2292 | ||||
2293 | static tree | |||
2294 | get_val_across_arith_op (enum tree_code opcode, | |||
2295 | tree opnd1_type, | |||
2296 | tree opnd2, | |||
2297 | ipcp_value<tree> *src_val, | |||
2298 | tree res_type) | |||
2299 | { | |||
2300 | tree opnd1 = src_val->value; | |||
2301 | ||||
2302 | /* Skip source values that is incompatible with specified type. */ | |||
2303 | if (opnd1_type | |||
2304 | && !useless_type_conversion_p (opnd1_type, TREE_TYPE (opnd1)((contains_struct_check ((opnd1), (TS_TYPED), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-cp.cc" , 2304, __FUNCTION__))->typed.type))) | |||
2305 | return NULL_TREE(tree) nullptr; | |||
2306 | ||||
2307 | return ipa_get_jf_arith_result (opcode, opnd1, opnd2, res_type); | |||
2308 | } | |||
2309 | ||||
2310 | /* Propagate values through an arithmetic transformation described by a jump | |||
2311 | function associated with edge CS, taking values from SRC_LAT and putting | |||
2312 | them into DEST_LAT. OPND1_TYPE is expected type for the values in SRC_LAT. | |||
2313 | OPND2 is a constant value if transformation is a binary operation. | |||
2314 | SRC_OFFSET specifies offset in an aggregate if SRC_LAT describes lattice of | |||
2315 | a part of the aggregate. SRC_IDX is the index of the source parameter. | |||
2316 | RES_TYPE is the value type of result being propagated into. Return true if | |||
2317 | DEST_LAT changed. */ | |||
2318 | ||||
2319 | static bool | |||
2320 | propagate_vals_across_arith_jfunc (cgraph_edge *cs, | |||
2321 | enum tree_code opcode, | |||
2322 | tree opnd1_type, | |||
2323 | tree opnd2, | |||
2324 | ipcp_lattice<tree> *src_lat, | |||
2325 | ipcp_lattice<tree> *dest_lat, | |||
2326 | HOST_WIDE_INTlong src_offset, | |||
2327 | int src_idx, | |||
2328 | tree res_type) | |||
2329 | { | |||
2330 | ipcp_value<tree> *src_val; | |||
2331 | bool ret = false; | |||
2332 | ||||
2333 | /* Due to circular dependencies, propagating within an SCC through arithmetic | |||
2334 | transformation would create infinite number of values. But for | |||
2335 | self-feeding recursive function, we could allow propagation in a limited | |||
2336 | count, and this can enable a simple kind of recursive function versioning. | |||
2337 | For other scenario, we would just make lattices bottom. */ | |||
2338 | if (opcode != NOP_EXPR && ipa_edge_within_scc (cs)) | |||
2339 | { | |||
2340 | int i; | |||
2341 | ||||
2342 | int max_recursive_depth = opt_for_fn(cs->caller->decl,(opts_for_fn (cs->caller->decl)->x_param_ipa_cp_max_recursive_depth ) | |||
2343 | param_ipa_cp_max_recursive_depth)(opts_for_fn (cs->caller->decl)->x_param_ipa_cp_max_recursive_depth ); | |||
2344 | if (src_lat != dest_lat || max_recursive_depth < 1) | |||
2345 | return dest_lat->set_contains_variable (); | |||
2346 | ||||
2347 | /* No benefit if recursive execution is in low probability. */ | |||
2348 | if (cs->sreal_frequency () * 100 | |||
2349 | <= ((sreal) 1) * opt_for_fn (cs->caller->decl,(opts_for_fn (cs->caller->decl)->x_param_ipa_cp_min_recursive_probability ) | |||
2350 | param_ipa_cp_min_recursive_probability)(opts_for_fn (cs->caller->decl)->x_param_ipa_cp_min_recursive_probability )) | |||
2351 | return dest_lat->set_contains_variable (); | |||
2352 | ||||
2353 | auto_vec<ipcp_value<tree> *, 8> val_seeds; | |||
2354 | ||||
2355 | for (src_val = src_lat->values; src_val; src_val = src_val->next) | |||
2356 | { | |||
2357 | /* Now we do not use self-recursively generated value as propagation | |||
2358 | source, this is absolutely conservative, but could avoid explosion | |||
2359 | of lattice's value space, especially when one recursive function | |||
2360 | calls another recursive. */ | |||
2361 | if (src_val->self_recursion_generated_p ()) | |||
2362 | { | |||
2363 | ipcp_value_source<tree> *s; | |||
2364 | ||||
2365 | /* If the lattice has already been propagated for the call site, | |||
2366 | no need to do that again. */ | |||
2367 | for (s = src_val->sources; s; s = s->next) | |||
2368 | if (s->cs == cs) | |||
2369 | return dest_lat->set_contains_variable (); | |||
2370 | } | |||
2371 | else | |||
2372 | val_seeds.safe_push (src_val); | |||
2373 | } | |||
2374 | ||||
2375 | gcc_assert ((int) val_seeds.length () <= param_ipa_cp_value_list_size)((void)(!((int) val_seeds.length () <= global_options.x_param_ipa_cp_value_list_size ) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-cp.cc" , 2375, __FUNCTION__), 0 : 0)); | |||
2376 | ||||
2377 | /* Recursively generate lattice values with a limited count. */ | |||
2378 | FOR_EACH_VEC_ELT (val_seeds, i, src_val)for (i = 0; (val_seeds).iterate ((i), &(src_val)); ++(i)) | |||
2379 | { | |||
2380 | for (int j = 1; j < max_recursive_depth; j++) | |||
2381 | { | |||
2382 | tree cstval = get_val_across_arith_op (opcode, opnd1_type, opnd2, | |||
2383 | src_val, res_type); | |||
2384 | if (!cstval | |||
2385 | || !ipacp_value_safe_for_type (res_type, cstval)) | |||
2386 | break; | |||
2387 | ||||
2388 | ret |= dest_lat->add_value (cstval, cs, src_val, src_idx, | |||
2389 | src_offset, &src_val, j); | |||
2390 | gcc_checking_assert (src_val)((void)(!(src_val) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-cp.cc" , 2390, __FUNCTION__), 0 : 0)); | |||
2391 | } | |||
2392 | } | |||
2393 | ret |= dest_lat->set_contains_variable (); | |||
2394 | } | |||
2395 | else | |||
2396 | for (src_val = src_lat->values; src_val; src_val = src_val->next) | |||
2397 | { | |||
2398 | /* Now we do not use self-recursively generated value as propagation | |||
2399 | source, otherwise it is easy to make value space of normal lattice | |||
2400 | overflow. */ | |||
2401 | if (src_val->self_recursion_generated_p ()) | |||
2402 | { | |||
2403 | ret |= dest_lat->set_contains_variable (); | |||
2404 | continue; | |||
2405 | } | |||
2406 | ||||
2407 | tree cstval = get_val_across_arith_op (opcode, opnd1_type, opnd2, | |||
2408 | src_val, res_type); | |||
2409 | if (cstval | |||
2410 | && ipacp_value_safe_for_type (res_type, cstval)) | |||
2411 | ret |= dest_lat->add_value (cstval, cs, src_val, src_idx, | |||
2412 | src_offset); | |||
2413 | else | |||
2414 | ret |= dest_lat->set_contains_variable (); | |||
2415 | } | |||
2416 | ||||
2417 | return ret; | |||
2418 | } | |||
2419 | ||||
2420 | /* Propagate values through a pass-through jump function JFUNC associated with | |||
2421 | edge CS, taking values from SRC_LAT and putting them into DEST_LAT. SRC_IDX | |||
2422 | is the index of the source parameter. PARM_TYPE is the type of the | |||
2423 | parameter to which the result is passed. */ | |||
2424 | ||||
2425 | static bool | |||
2426 | propagate_vals_across_pass_through (cgraph_edge *cs, ipa_jump_func *jfunc, | |||
2427 | ipcp_lattice<tree> *src_lat, | |||
2428 | ipcp_lattice<tree> *dest_lat, int src_idx, | |||
2429 | tree parm_type) | |||
2430 | { | |||
2431 | return propagate_vals_across_arith_jfunc (cs, | |||
2432 | ipa_get_jf_pass_through_operation (jfunc), | |||
2433 | NULL_TREE(tree) nullptr, | |||
2434 | ipa_get_jf_pass_through_operand (jfunc), | |||
2435 | src_lat, dest_lat, -1, src_idx, parm_type); | |||
2436 | } | |||
2437 | ||||
2438 | /* Propagate values through an ancestor jump function JFUNC associated with | |||
2439 | edge CS, taking values from SRC_LAT and putting them into DEST_LAT. SRC_IDX | |||
2440 | is the index of the source parameter. */ | |||
2441 | ||||
2442 | static bool | |||
2443 | propagate_vals_across_ancestor (struct cgraph_edge *cs, | |||
2444 | struct ipa_jump_func *jfunc, | |||
2445 | ipcp_lattice<tree> *src_lat, | |||
2446 | ipcp_lattice<tree> *dest_lat, int src_idx, | |||
2447 | tree param_type) | |||
2448 | { | |||
2449 | ipcp_value<tree> *src_val; | |||
2450 | bool ret = false; | |||
2451 | ||||
2452 | if (ipa_edge_within_scc (cs)) | |||
2453 | return dest_lat->set_contains_variable (); | |||
2454 | ||||
2455 | for (src_val = src_lat->values; src_val; src_val = src_val->next) | |||
2456 | { | |||
2457 | tree t = ipa_get_jf_ancestor_result (jfunc, src_val->value); | |||
2458 | ||||
2459 | if (t && ipacp_value_safe_for_type (param_type, t)) | |||
2460 | ret |= dest_lat->add_value (t, cs, src_val, src_idx); | |||
2461 | else | |||
2462 | ret |= dest_lat->set_contains_variable (); | |||
2463 | } | |||
2464 | ||||
2465 | return ret; | |||
2466 | } | |||
2467 | ||||
2468 | /* Propagate scalar values across jump function JFUNC that is associated with | |||
2469 | edge CS and put the values into DEST_LAT. PARM_TYPE is the type of the | |||
2470 | parameter to which the result is passed. */ | |||
2471 | ||||
2472 | static bool | |||
2473 | propagate_scalar_across_jump_function (struct cgraph_edge *cs, | |||
2474 | struct ipa_jump_func *jfunc, | |||
2475 | ipcp_lattice<tree> *dest_lat, | |||
2476 | tree param_type) | |||
2477 | { | |||
2478 | if (dest_lat->bottom) | |||
2479 | return false; | |||
2480 | ||||
2481 | if (jfunc->type == IPA_JF_CONST) | |||
2482 | { | |||
2483 | tree val = ipa_get_jf_constant (jfunc); | |||
2484 | if (ipacp_value_safe_for_type (param_type, val)) | |||
2485 | return dest_lat->add_value (val, cs, NULLnullptr, 0); | |||
2486 | else | |||
2487 | return dest_lat->set_contains_variable (); | |||
2488 | } | |||
2489 | else if (jfunc->type == IPA_JF_PASS_THROUGH | |||
2490 | || jfunc->type == IPA_JF_ANCESTOR) | |||
2491 | { | |||
2492 | ipa_node_params *caller_info = ipa_node_params_sum->get (cs->caller); | |||
2493 | ipcp_lattice<tree> *src_lat; | |||
2494 | int src_idx; | |||
2495 | bool ret; | |||
2496 | ||||
2497 | if (jfunc->type == IPA_JF_PASS_THROUGH) | |||
2498 | src_idx = ipa_get_jf_pass_through_formal_id (jfunc); | |||
2499 | else | |||
2500 | src_idx = ipa_get_jf_ancestor_formal_id (jfunc); | |||
2501 | ||||
2502 | src_lat = ipa_get_scalar_lat (caller_info, src_idx); | |||
2503 | if (src_lat->bottom) | |||
2504 | return dest_lat->set_contains_variable (); | |||
2505 | ||||
2506 | /* If we would need to clone the caller and cannot, do not propagate. */ | |||
2507 | if (!ipcp_versionable_function_p (cs->caller) | |||
2508 | && (src_lat->contains_variable | |||
2509 | || (src_lat->values_count > 1))) | |||
2510 | return dest_lat->set_contains_variable (); | |||
2511 | ||||
2512 | if (jfunc->type == IPA_JF_PASS_THROUGH) | |||
2513 | ret = propagate_vals_across_pass_through (cs, jfunc, src_lat, | |||
2514 | dest_lat, src_idx, | |||
2515 | param_type); | |||
2516 | else | |||
2517 | ret = propagate_vals_across_ancestor (cs, jfunc, src_lat, dest_lat, | |||
2518 | src_idx, param_type); | |||
2519 | ||||
2520 | if (src_lat->contains_variable) | |||
2521 | ret |= dest_lat->set_contains_variable (); | |||
2522 | ||||
2523 | return ret; | |||
2524 | } | |||
2525 | ||||
2526 | /* TODO: We currently do not handle member method pointers in IPA-CP (we only | |||
2527 | use it for indirect inlining), we should propagate them too. */ | |||
2528 | return dest_lat->set_contains_variable (); | |||
2529 | } | |||
2530 | ||||
2531 | /* Propagate scalar values across jump function JFUNC that is associated with | |||
2532 | edge CS and describes argument IDX and put the values into DEST_LAT. */ | |||
2533 | ||||
2534 | static bool | |||
2535 | propagate_context_across_jump_function (cgraph_edge *cs, | |||
2536 | ipa_jump_func *jfunc, int idx, | |||
2537 | ipcp_lattice<ipa_polymorphic_call_context> *dest_lat) | |||
2538 | { | |||
2539 | if (dest_lat->bottom) | |||
2540 | return false; | |||
2541 | ipa_edge_args *args = ipa_edge_args_sum->get (cs); | |||
2542 | bool ret = false; | |||
2543 | bool added_sth = false; | |||
2544 | bool type_preserved = true; | |||
2545 | ||||
2546 | ipa_polymorphic_call_context edge_ctx, *edge_ctx_ptr | |||
2547 | = ipa_get_ith_polymorhic_call_context (args, idx); | |||
2548 | ||||
2549 | if (edge_ctx_ptr) | |||
2550 | edge_ctx = *edge_ctx_ptr; | |||
2551 | ||||
2552 | if (jfunc->type == IPA_JF_PASS_THROUGH | |||
2553 | || jfunc->type == IPA_JF_ANCESTOR) | |||
2554 | { | |||
2555 | ipa_node_params *caller_info = ipa_node_params_sum->get (cs->caller); | |||
2556 | int src_idx; | |||
2557 | ipcp_lattice<ipa_polymorphic_call_context> *src_lat; | |||
2558 | ||||
2559 | /* TODO: Once we figure out how to propagate speculations, it will | |||
2560 | probably be a good idea to switch to speculation if type_preserved is | |||
2561 | not set instead of punting. */ | |||
2562 | if (jfunc->type == IPA_JF_PASS_THROUGH) | |||
2563 | { | |||
2564 | if (ipa_get_jf_pass_through_operation (jfunc) != NOP_EXPR) | |||
2565 | goto prop_fail; | |||
2566 | type_preserved = ipa_get_jf_pass_through_type_preserved (jfunc); | |||
2567 | src_idx = ipa_get_jf_pass_through_formal_id (jfunc); | |||
2568 | } | |||
2569 | else | |||
2570 | { | |||
2571 | type_preserved = ipa_get_jf_ancestor_type_preserved (jfunc); | |||
2572 | src_idx = ipa_get_jf_ancestor_formal_id (jfunc); | |||
2573 | } | |||
2574 | ||||
2575 | src_lat = ipa_get_poly_ctx_lat (caller_info, src_idx); | |||
2576 | /* If we would need to clone the caller and cannot, do not propagate. */ | |||
2577 | if (!ipcp_versionable_function_p (cs->caller) | |||
2578 | && (src_lat->contains_variable | |||
2579 | || (src_lat->values_count > 1))) | |||
2580 | goto prop_fail; | |||
2581 | ||||
2582 | ipcp_value<ipa_polymorphic_call_context> *src_val; | |||
2583 | for (src_val = src_lat->values; src_val; src_val = src_val->next) | |||
2584 | { | |||
2585 | ipa_polymorphic_call_context cur = src_val->value; | |||
2586 | ||||
2587 | if (!type_preserved) | |||
2588 | cur.possible_dynamic_type_change (cs->in_polymorphic_cdtor); | |||
2589 | if (jfunc->type == IPA_JF_ANCESTOR) | |||
2590 | cur.offset_by (ipa_get_jf_ancestor_offset (jfunc)); | |||
2591 | /* TODO: In cases we know how the context is going to be used, | |||
2592 | we can improve the result by passing proper OTR_TYPE. */ | |||
2593 | cur.combine_with (edge_ctx); | |||
2594 | if (!cur.useless_p ()) | |||
2595 | { | |||
2596 | if (src_lat->contains_variable | |||
2597 | && !edge_ctx.equal_to (cur)) | |||
2598 | ret |= dest_lat->set_contains_variable (); | |||
2599 | ret |= dest_lat->add_value (cur, cs, src_val, src_idx); | |||
2600 | added_sth = true; | |||
2601 | } | |||
2602 | } | |||
2603 | } | |||
2604 | ||||
2605 | prop_fail: | |||
2606 | if (!added_sth) | |||
2607 | { | |||
2608 | if (!edge_ctx.useless_p ()) | |||
2609 | ret |= dest_lat->add_value (edge_ctx, cs); | |||
2610 | else | |||
2611 | ret |= dest_lat->set_contains_variable (); | |||
2612 | } | |||
2613 | ||||
2614 | return ret; | |||
2615 | } | |||
2616 | ||||
2617 | /* Propagate bits across jfunc that is associated with | |||
2618 | edge cs and update dest_lattice accordingly. */ | |||
2619 | ||||
2620 | bool | |||
2621 | propagate_bits_across_jump_function (cgraph_edge *cs, int idx, | |||
2622 | ipa_jump_func *jfunc, | |||
2623 | ipcp_bits_lattice *dest_lattice) | |||
2624 | { | |||
2625 | if (dest_lattice->bottom_p ()) | |||
2626 | return false; | |||
2627 | ||||
2628 | enum availability availability; | |||
2629 | cgraph_node *callee = cs->callee->function_symbol (&availability); | |||
2630 | ipa_node_params *callee_info = ipa_node_params_sum->get (callee); | |||
2631 | tree parm_type = ipa_get_type (callee_info, idx); | |||
2632 | ||||
2633 | /* For K&R C programs, ipa_get_type() could return NULL_TREE. Avoid the | |||
2634 | transform for these cases. Similarly, we can have bad type mismatches | |||
2635 | with LTO, avoid doing anything with those too. */ | |||
2636 | if (!parm_type | |||
2637 | || (!INTEGRAL_TYPE_P (parm_type)(((enum tree_code) (parm_type)->base.code) == ENUMERAL_TYPE || ((enum tree_code) (parm_type)->base.code) == BOOLEAN_TYPE || ((enum tree_code) (parm_type)->base.code) == INTEGER_TYPE ) && !POINTER_TYPE_P (parm_type)(((enum tree_code) (parm_type)->base.code) == POINTER_TYPE || ((enum tree_code) (parm_type)->base.code) == REFERENCE_TYPE ))) | |||
2638 | { | |||
2639 | if (dump_file && (dump_flags & TDF_DETAILS)) | |||
2640 | fprintf (dump_file, "Setting dest_lattice to bottom, because type of " | |||
2641 | "param %i of %s is NULL or unsuitable for bits propagation\n", | |||
2642 | idx, cs->callee->dump_name ()); | |||
2643 | ||||
2644 | return dest_lattice->set_to_bottom (); | |||
2645 | } | |||
2646 | ||||
2647 | unsigned precision = TYPE_PRECISION (parm_type)((tree_class_check ((parm_type), (tcc_type), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-cp.cc" , 2647, __FUNCTION__))->type_common.precision); | |||
2648 | signop sgn = TYPE_SIGN (parm_type)((signop) ((tree_class_check ((parm_type), (tcc_type), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-cp.cc" , 2648, __FUNCTION__))->base.u.bits.unsigned_flag)); | |||
2649 | ||||
2650 | if (jfunc->type == IPA_JF_PASS_THROUGH | |||
2651 | || jfunc->type == IPA_JF_ANCESTOR) | |||
2652 | { | |||
2653 | ipa_node_params *caller_info = ipa_node_params_sum->get (cs->caller); | |||
2654 | tree operand = NULL_TREE(tree) nullptr; | |||
2655 | enum tree_code code; | |||
2656 | unsigned src_idx; | |||
2657 | bool keep_null = false; | |||
2658 | ||||
2659 | if (jfunc->type == IPA_JF_PASS_THROUGH) | |||
2660 | { | |||
2661 | code = ipa_get_jf_pass_through_operation (jfunc); | |||
2662 | src_idx = ipa_get_jf_pass_through_formal_id (jfunc); | |||
2663 | if (code != NOP_EXPR) | |||
2664 | operand = ipa_get_jf_pass_through_operand (jfunc); | |||
2665 | } | |||
2666 | else | |||
2667 | { | |||
2668 | code = POINTER_PLUS_EXPR; | |||
2669 | src_idx = ipa_get_jf_ancestor_formal_id (jfunc); | |||
2670 | unsigned HOST_WIDE_INTlong offset | |||
2671 | = ipa_get_jf_ancestor_offset (jfunc) / BITS_PER_UNIT(8); | |||
2672 | keep_null = (ipa_get_jf_ancestor_keep_null (jfunc) || !offset); | |||
2673 | operand = build_int_cstu (size_type_nodeglobal_trees[TI_SIZE_TYPE], offset); | |||
2674 | } | |||
2675 | ||||
2676 | class ipcp_param_lattices *src_lats | |||
2677 | = ipa_get_parm_lattices (caller_info, src_idx); | |||
2678 | ||||
2679 | /* Try to propagate bits if src_lattice is bottom, but jfunc is known. | |||
2680 | for eg consider: | |||
2681 | int f(int x) | |||
2682 | { | |||
2683 | g (x & 0xff); | |||
2684 | } | |||
2685 | Assume lattice for x is bottom, however we can still propagate | |||
2686 | result of x & 0xff == 0xff, which gets computed during ccp1 pass | |||
2687 | and we store it in jump function during analysis stage. */ | |||
2688 | ||||
2689 | if (!src_lats->bits_lattice.bottom_p ()) | |||
2690 | { | |||
2691 | bool drop_all_ones | |||
2692 | = keep_null && !src_lats->bits_lattice.known_nonzero_p (); | |||
2693 | ||||
2694 | return dest_lattice->meet_with (src_lats->bits_lattice, precision, | |||
2695 | sgn, code, operand, drop_all_ones); | |||
2696 | } | |||
2697 | } | |||
2698 | ||||
2699 | if (jfunc->bits) | |||
2700 | return dest_lattice->meet_with (jfunc->bits->value, jfunc->bits->mask, | |||
2701 | precision); | |||
2702 | else | |||
2703 | return dest_lattice->set_to_bottom (); | |||
2704 | } | |||
2705 | ||||
2706 | /* Propagate value range across jump function JFUNC that is associated with | |||
2707 | edge CS with param of callee of PARAM_TYPE and update DEST_PLATS | |||
2708 | accordingly. */ | |||
2709 | ||||
2710 | static bool | |||
2711 | propagate_vr_across_jump_function (cgraph_edge *cs, ipa_jump_func *jfunc, | |||
2712 | class ipcp_param_lattices *dest_plats, | |||
2713 | tree param_type) | |||
2714 | { | |||
2715 | ipcp_vr_lattice *dest_lat = &dest_plats->m_value_range; | |||
2716 | ||||
2717 | if (dest_lat->bottom_p ()) | |||
2718 | return false; | |||
2719 | ||||
2720 | if (!param_type | |||
2721 | || (!INTEGRAL_TYPE_P (param_type)(((enum tree_code) (param_type)->base.code) == ENUMERAL_TYPE || ((enum tree_code) (param_type)->base.code) == BOOLEAN_TYPE || ((enum tree_code) (param_type)->base.code) == INTEGER_TYPE ) | |||
2722 | && !POINTER_TYPE_P (param_type)(((enum tree_code) (param_type)->base.code) == POINTER_TYPE || ((enum tree_code) (param_type)->base.code) == REFERENCE_TYPE ))) | |||
2723 | return dest_lat->set_to_bottom (); | |||
2724 | ||||
2725 | if (jfunc->type == IPA_JF_PASS_THROUGH) | |||
2726 | { | |||
2727 | enum tree_code operation = ipa_get_jf_pass_through_operation (jfunc); | |||
2728 | ipa_node_params *caller_info = ipa_node_params_sum->get (cs->caller); | |||
2729 | int src_idx = ipa_get_jf_pass_through_formal_id (jfunc); | |||
2730 | class ipcp_param_lattices *src_lats | |||
2731 | = ipa_get_parm_lattices (caller_info, src_idx); | |||
2732 | tree operand_type = ipa_get_type (caller_info, src_idx); | |||
2733 | ||||
2734 | if (src_lats->m_value_range.bottom_p ()) | |||
2735 | return dest_lat->set_to_bottom (); | |||
2736 | ||||
2737 | value_range vr; | |||
2738 | if (TREE_CODE_CLASS (operation)tree_code_type_tmpl <0>::tree_code_type[(int) (operation )] == tcc_unary) | |||
2739 | ipa_vr_operation_and_type_effects (&vr, | |||
2740 | &src_lats->m_value_range.m_vr, | |||
2741 | operation, param_type, | |||
2742 | operand_type); | |||
2743 | /* A crude way to prevent unbounded number of value range updates | |||
2744 | in SCC components. We should allow limited number of updates within | |||
2745 | SCC, too. */ | |||
2746 | else if (!ipa_edge_within_scc (cs)) | |||
2747 | { | |||
2748 | tree op = ipa_get_jf_pass_through_operand (jfunc); | |||
2749 | value_range op_vr (op, op); | |||
2750 | value_range op_res,res; | |||
2751 | ||||
2752 | range_fold_binary_expr (&op_res, operation, operand_type, | |||
2753 | &src_lats->m_value_range.m_vr, &op_vr); | |||
2754 | ipa_vr_operation_and_type_effects (&vr, | |||
2755 | &op_res, | |||
2756 | NOP_EXPR, param_type, | |||
2757 | operand_type); | |||
2758 | } | |||
2759 | if (!vr.undefined_p () && !vr.varying_p ()) | |||
2760 | { | |||
2761 | if (jfunc->m_vr) | |||
2762 | { | |||
2763 | value_range jvr; | |||
2764 | if (ipa_vr_operation_and_type_effects (&jvr, jfunc->m_vr, | |||
2765 | NOP_EXPR, | |||
2766 | param_type, | |||
2767 | jfunc->m_vr->type ())) | |||
2768 | vr.intersect (jvr); | |||
2769 | } | |||
2770 | return dest_lat->meet_with (&vr); | |||
2771 | } | |||
2772 | } | |||
2773 | else if (jfunc->type == IPA_JF_CONST) | |||
2774 | { | |||
2775 | tree val = ipa_get_jf_constant (jfunc); | |||
2776 | if (TREE_CODE (val)((enum tree_code) (val)->base.code) == INTEGER_CST) | |||
2777 | { | |||
2778 | val = fold_convert (param_type, val)fold_convert_loc (((location_t) 0), param_type, val); | |||
2779 | if (TREE_OVERFLOW_P (val)((tree_code_type_tmpl <0>::tree_code_type[(int) (((enum tree_code) (val)->base.code))] == tcc_constant) && ((tree_class_check ((val), (tcc_constant), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-cp.cc" , 2779, __FUNCTION__))->base.public_flag))) | |||
2780 | val = drop_tree_overflow (val); | |||
2781 | ||||
2782 | value_range tmpvr (val, val); | |||
2783 | return dest_lat->meet_with (&tmpvr); | |||
2784 | } | |||
2785 | } | |||
2786 | ||||
2787 | value_range vr; | |||
2788 | if (jfunc->m_vr | |||
2789 | && ipa_vr_operation_and_type_effects (&vr, jfunc->m_vr, NOP_EXPR, | |||
2790 | param_type, | |||
2791 | jfunc->m_vr->type ())) | |||
2792 | return dest_lat->meet_with (&vr); | |||
2793 | else | |||
2794 | return dest_lat->set_to_bottom (); | |||
2795 | } | |||
2796 | ||||
2797 | /* If DEST_PLATS already has aggregate items, check that aggs_by_ref matches | |||
2798 | NEW_AGGS_BY_REF and if not, mark all aggs as bottoms and return true (in all | |||
2799 | other cases, return false). If there are no aggregate items, set | |||
2800 | aggs_by_ref to NEW_AGGS_BY_REF. */ | |||
2801 | ||||
2802 | static bool | |||
2803 | set_check_aggs_by_ref (class ipcp_param_lattices *dest_plats, | |||
2804 | bool new_aggs_by_ref) | |||
2805 | { | |||
2806 | if (dest_plats->aggs) | |||
2807 | { | |||
2808 | if (dest_plats->aggs_by_ref != new_aggs_by_ref) | |||
2809 | { | |||
2810 | set_agg_lats_to_bottom (dest_plats); | |||
2811 | return true; | |||
2812 | } | |||
2813 | } | |||
2814 | else | |||
2815 | dest_plats->aggs_by_ref = new_aggs_by_ref; | |||
2816 | return false; | |||
2817 | } | |||
2818 | ||||
2819 | /* Walk aggregate lattices in DEST_PLATS from ***AGLAT on, until ***aglat is an | |||
2820 | already existing lattice for the given OFFSET and SIZE, marking all skipped | |||
2821 | lattices as containing variable and checking for overlaps. If there is no | |||
2822 | already existing lattice for the OFFSET and VAL_SIZE, create one, initialize | |||
2823 | it with offset, size and contains_variable to PRE_EXISTING, and return true, | |||
2824 | unless there are too many already. If there are two many, return false. If | |||
2825 | there are overlaps turn whole DEST_PLATS to bottom and return false. If any | |||
2826 | skipped lattices were newly marked as containing variable, set *CHANGE to | |||
2827 | true. MAX_AGG_ITEMS is the maximum number of lattices. */ | |||
2828 | ||||
2829 | static bool | |||
2830 | merge_agg_lats_step (class ipcp_param_lattices *dest_plats, | |||
2831 | HOST_WIDE_INTlong offset, HOST_WIDE_INTlong val_size, | |||
2832 | struct ipcp_agg_lattice ***aglat, | |||
2833 | bool pre_existing, bool *change, int max_agg_items) | |||
2834 | { | |||
2835 | gcc_checking_assert (offset >= 0)((void)(!(offset >= 0) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-cp.cc" , 2835, __FUNCTION__), 0 : 0)); | |||
2836 | ||||
2837 | while (**aglat && (**aglat)->offset < offset) | |||
2838 | { | |||
2839 | if ((**aglat)->offset + (**aglat)->size > offset) | |||
2840 | { | |||
2841 | set_agg_lats_to_bottom (dest_plats); | |||
2842 | return false; | |||
2843 | } | |||
2844 | *change |= (**aglat)->set_contains_variable (); | |||
2845 | *aglat = &(**aglat)->next; | |||
2846 | } | |||
2847 | ||||
2848 | if (**aglat && (**aglat)->offset == offset) | |||
2849 | { | |||
2850 | if ((**aglat)->size != val_size) | |||
2851 | { | |||
2852 | set_agg_lats_to_bottom (dest_plats); | |||
2853 | return false; | |||
2854 | } | |||
2855 | gcc_assert (!(**aglat)->next((void)(!(!(**aglat)->next || (**aglat)->next->offset >= offset + val_size) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-cp.cc" , 2856, __FUNCTION__), 0 : 0)) | |||
2856 | || (**aglat)->next->offset >= offset + val_size)((void)(!(!(**aglat)->next || (**aglat)->next->offset >= offset + val_size) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-cp.cc" , 2856, __FUNCTION__), 0 : 0)); | |||
2857 | return true; | |||
2858 | } | |||
2859 | else | |||
2860 | { | |||
2861 | struct ipcp_agg_lattice *new_al; | |||
2862 | ||||
2863 | if (**aglat && (**aglat)->offset < offset + val_size) | |||
2864 | { | |||
2865 | set_agg_lats_to_bottom (dest_plats); | |||
2866 | return false; | |||
2867 | } | |||
2868 | if (dest_plats->aggs_count == max_agg_items) | |||
2869 | return false; | |||
2870 | dest_plats->aggs_count++; | |||
2871 | new_al = ipcp_agg_lattice_pool.allocate (); | |||
2872 | memset (new_al, 0, sizeof (*new_al)); | |||
2873 | ||||
2874 | new_al->offset = offset; | |||
2875 | new_al->size = val_size; | |||
2876 | new_al->contains_variable = pre_existing; | |||
2877 | ||||
2878 | new_al->next = **aglat; | |||
2879 | **aglat = new_al; | |||
2880 | return true; | |||
2881 | } | |||
2882 | } | |||
2883 | ||||
2884 | /* Set all AGLAT and all other aggregate lattices reachable by next pointers as | |||
2885 | containing an unknown value. */ | |||
2886 | ||||
2887 | static bool | |||
2888 | set_chain_of_aglats_contains_variable (struct ipcp_agg_lattice *aglat) | |||
2889 | { | |||
2890 | bool ret = false; | |||
2891 | while (aglat) | |||
2892 | { | |||
2893 | ret |= aglat->set_contains_variable (); | |||
2894 | aglat = aglat->next; | |||
2895 | } | |||
2896 | return ret; | |||
2897 | } | |||
2898 | ||||
2899 | /* Merge existing aggregate lattices in SRC_PLATS to DEST_PLATS, subtracting | |||
2900 | DELTA_OFFSET. CS is the call graph edge and SRC_IDX the index of the source | |||
2901 | parameter used for lattice value sources. Return true if DEST_PLATS changed | |||
2902 | in any way. */ | |||
2903 | ||||
2904 | static bool | |||
2905 | merge_aggregate_lattices (struct cgraph_edge *cs, | |||
2906 | class ipcp_param_lattices *dest_plats, | |||
2907 | class ipcp_param_lattices *src_plats, | |||
2908 | int src_idx, HOST_WIDE_INTlong offset_delta) | |||
2909 | { | |||
2910 | bool pre_existing = dest_plats->aggs != NULLnullptr; | |||
2911 | struct ipcp_agg_lattice **dst_aglat; | |||
2912 | bool ret = false; | |||
2913 | ||||
2914 | if (set_check_aggs_by_ref (dest_plats, src_plats->aggs_by_ref)) | |||
2915 | return true; | |||
2916 | if (src_plats->aggs_bottom) | |||
2917 | return set_agg_lats_contain_variable (dest_plats); | |||
2918 | if (src_plats->aggs_contain_variable) | |||
2919 | ret |= set_agg_lats_contain_variable (dest_plats); | |||
2920 | dst_aglat = &dest_plats->aggs; | |||
2921 | ||||
2922 | int max_agg_items = opt_for_fn (cs->callee->function_symbol ()->decl,(opts_for_fn (cs->callee->function_symbol ()->decl)-> x_param_ipa_max_agg_items) | |||
2923 | param_ipa_max_agg_items)(opts_for_fn (cs->callee->function_symbol ()->decl)-> x_param_ipa_max_agg_items); | |||
2924 | for (struct ipcp_agg_lattice *src_aglat = src_plats->aggs; | |||
2925 | src_aglat; | |||
2926 | src_aglat = src_aglat->next) | |||
2927 | { | |||
2928 | HOST_WIDE_INTlong new_offset = src_aglat->offset - offset_delta; | |||
2929 | ||||
2930 | if (new_offset < 0) | |||
2931 | continue; | |||
2932 | if (merge_agg_lats_step (dest_plats, new_offset, src_aglat->size, | |||
2933 | &dst_aglat, pre_existing, &ret, max_agg_items)) | |||
2934 | { | |||
2935 | struct ipcp_agg_lattice *new_al = *dst_aglat; | |||
2936 | ||||
2937 | dst_aglat = &(*dst_aglat)->next; | |||
2938 | if (src_aglat->bottom) | |||
2939 | { | |||
2940 | ret |= new_al->set_contains_variable (); | |||
2941 | continue; | |||
2942 | } | |||
2943 | if (src_aglat->contains_variable) | |||
2944 | ret |= new_al->set_contains_variable (); | |||
2945 | for (ipcp_value<tree> *val = src_aglat->values; | |||
2946 | val; | |||
2947 | val = val->next) | |||
2948 | ret |= new_al->add_value (val->value, cs, val, src_idx, | |||
2949 | src_aglat->offset); | |||
2950 | } | |||
2951 | else if (dest_plats->aggs_bottom) | |||
2952 | return true; | |||
2953 | } | |||
2954 | ret |= set_chain_of_aglats_contains_variable (*dst_aglat); | |||
2955 | return ret; | |||
2956 | } | |||
2957 | ||||
2958 | /* Determine whether there is anything to propagate FROM SRC_PLATS through a | |||
2959 | pass-through JFUNC and if so, whether it has conform and conforms to the | |||
2960 | rules about propagating values passed by reference. */ | |||
2961 | ||||
2962 | static bool | |||
2963 | agg_pass_through_permissible_p (class ipcp_param_lattices *src_plats, | |||
2964 | struct ipa_jump_func *jfunc) | |||
2965 | { | |||
2966 | return src_plats->aggs | |||
2967 | && (!src_plats->aggs_by_ref | |||
2968 | || ipa_get_jf_pass_through_agg_preserved (jfunc)); | |||
2969 | } | |||
2970 | ||||
2971 | /* Propagate values through ITEM, jump function for a part of an aggregate, | |||
2972 | into corresponding aggregate lattice AGLAT. CS is the call graph edge | |||
2973 | associated with the jump function. Return true if AGLAT changed in any | |||
2974 | way. */ | |||
2975 | ||||
2976 | static bool | |||
2977 | propagate_aggregate_lattice (struct cgraph_edge *cs, | |||
2978 | struct ipa_agg_jf_item *item, | |||
2979 | struct ipcp_agg_lattice *aglat) | |||
2980 | { | |||
2981 | class ipa_node_params *caller_info; | |||
2982 | class ipcp_param_lattices *src_plats; | |||
2983 | struct ipcp_lattice<tree> *src_lat; | |||
2984 | HOST_WIDE_INTlong src_offset; | |||
2985 | int src_idx; | |||
2986 | tree load_type; | |||
2987 | bool ret; | |||
2988 | ||||
2989 | if (item->jftype == IPA_JF_CONST) | |||
2990 | { | |||
2991 | tree value = item->value.constant; | |||
2992 | ||||
2993 | gcc_checking_assert (is_gimple_ip_invariant (value))((void)(!(is_gimple_ip_invariant (value)) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-cp.cc" , 2993, __FUNCTION__), 0 : 0)); | |||
2994 | return aglat->add_value (value, cs, NULLnullptr, 0); | |||
2995 | } | |||
2996 | ||||
2997 | gcc_checking_assert (item->jftype == IPA_JF_PASS_THROUGH((void)(!(item->jftype == IPA_JF_PASS_THROUGH || item-> jftype == IPA_JF_LOAD_AGG) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-cp.cc" , 2998, __FUNCTION__), 0 : 0)) | |||
2998 | || item->jftype == IPA_JF_LOAD_AGG)((void)(!(item->jftype == IPA_JF_PASS_THROUGH || item-> jftype == IPA_JF_LOAD_AGG) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-cp.cc" , 2998, __FUNCTION__), 0 : 0)); | |||
2999 | ||||
3000 | caller_info = ipa_node_params_sum->get (cs->caller); | |||
3001 | src_idx = item->value.pass_through.formal_id; | |||
3002 | src_plats = ipa_get_parm_lattices (caller_info, src_idx); | |||
3003 | ||||
3004 | if (item->jftype == IPA_JF_PASS_THROUGH) | |||
3005 | { | |||
3006 | load_type = NULL_TREE(tree) nullptr; | |||
3007 | src_lat = &src_plats->itself; | |||
3008 | src_offset = -1; | |||
3009 | } | |||
3010 | else | |||
3011 | { | |||
3012 | HOST_WIDE_INTlong load_offset = item->value.load_agg.offset; | |||
3013 | struct ipcp_agg_lattice *src_aglat; | |||
3014 | ||||
3015 | for (src_aglat = src_plats->aggs; src_aglat; src_aglat = src_aglat->next) | |||
3016 | if (src_aglat->offset >= load_offset) | |||
3017 | break; | |||
3018 | ||||
3019 | load_type = item->value.load_agg.type; | |||
3020 | if (!src_aglat | |||
3021 | || src_aglat->offset > load_offset | |||
3022 | || src_aglat->size != tree_to_shwi (TYPE_SIZE (load_type)((tree_class_check ((load_type), (tcc_type), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-cp.cc" , 3022, __FUNCTION__))->type_common.size)) | |||
3023 | || src_plats->aggs_by_ref != item->value.load_agg.by_ref) | |||
3024 | return aglat->set_contains_variable (); | |||
3025 | ||||
3026 | src_lat = src_aglat; | |||
3027 | src_offset = load_offset; | |||
3028 | } | |||
3029 | ||||
3030 | if (src_lat->bottom | |||
3031 | || (!ipcp_versionable_function_p (cs->caller) | |||
3032 | && !src_lat->is_single_const ())) | |||
3033 | return aglat->set_contains_variable (); | |||
3034 | ||||
3035 | ret = propagate_vals_across_arith_jfunc (cs, | |||
3036 | item->value.pass_through.operation, | |||
3037 | load_type, | |||
3038 | item->value.pass_through.operand, | |||
3039 | src_lat, aglat, | |||
3040 | src_offset, | |||
3041 | src_idx, | |||
3042 | item->type); | |||
3043 | ||||
3044 | if (src_lat->contains_variable) | |||
3045 | ret |= aglat->set_contains_variable (); | |||
3046 | ||||
3047 | return ret; | |||
3048 | } | |||
3049 | ||||
3050 | /* Propagate scalar values across jump function JFUNC that is associated with | |||
3051 | edge CS and put the values into DEST_LAT. */ | |||
3052 | ||||
3053 | static bool | |||
3054 | propagate_aggs_across_jump_function (struct cgraph_edge *cs, | |||
3055 | struct ipa_jump_func *jfunc, | |||
3056 | class ipcp_param_lattices *dest_plats) | |||
3057 | { | |||
3058 | bool ret = false; | |||
3059 | ||||
3060 | if (dest_plats->aggs_bottom) | |||
3061 | return false; | |||
3062 | ||||
3063 | if (jfunc->type == IPA_JF_PASS_THROUGH | |||
3064 | && ipa_get_jf_pass_through_operation (jfunc) == NOP_EXPR) | |||
3065 | { | |||
3066 | ipa_node_params *caller_info = ipa_node_params_sum->get (cs->caller); | |||
3067 | int src_idx = ipa_get_jf_pass_through_formal_id (jfunc); | |||
3068 | class ipcp_param_lattices *src_plats; | |||
3069 | ||||
3070 | src_plats = ipa_get_parm_lattices (caller_info, src_idx); | |||
3071 | if (agg_pass_through_permissible_p (src_plats, jfunc)) | |||
3072 | { | |||
3073 | /* Currently we do not produce clobber aggregate jump | |||
3074 | functions, replace with merging when we do. */ | |||
3075 | gcc_assert (!jfunc->agg.items)((void)(!(!jfunc->agg.items) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-cp.cc" , 3075, __FUNCTION__), 0 : 0)); | |||
3076 | ret |= merge_aggregate_lattices (cs, dest_plats, src_plats, | |||
3077 | src_idx, 0); | |||
3078 | return ret; | |||
3079 | } | |||
3080 | } | |||
3081 | else if (jfunc->type == IPA_JF_ANCESTOR | |||
3082 | && ipa_get_jf_ancestor_agg_preserved (jfunc)) | |||
3083 | { | |||
3084 | ipa_node_params *caller_info = ipa_node_params_sum->get (cs->caller); | |||
3085 | int src_idx = ipa_get_jf_ancestor_formal_id (jfunc); | |||
3086 | class ipcp_param_lattices *src_plats; | |||
3087 | ||||
3088 | src_plats = ipa_get_parm_lattices (caller_info, src_idx); | |||
3089 | if (src_plats->aggs && src_plats->aggs_by_ref) | |||
3090 | { | |||
3091 | /* Currently we do not produce clobber aggregate jump | |||
3092 | functions, replace with merging when we do. */ | |||
3093 | gcc_assert (!jfunc->agg.items)((void)(!(!jfunc->agg.items) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-cp.cc" , 3093, __FUNCTION__), 0 : 0)); | |||
3094 | ret |= merge_aggregate_lattices (cs, dest_plats, src_plats, src_idx, | |||
3095 | ipa_get_jf_ancestor_offset (jfunc)); | |||
3096 | } | |||
3097 | else if (!src_plats->aggs_by_ref) | |||
3098 | ret |= set_agg_lats_to_bottom (dest_plats); | |||
3099 | else | |||
3100 | ret |= set_agg_lats_contain_variable (dest_plats); | |||
3101 | return ret; | |||
3102 | } | |||
3103 | ||||
3104 | if (jfunc->agg.items) | |||
3105 | { | |||
3106 | bool pre_existing = dest_plats->aggs != NULLnullptr; | |||
3107 | struct ipcp_agg_lattice **aglat = &dest_plats->aggs; | |||
3108 | struct ipa_agg_jf_item *item; | |||
3109 | int i; | |||
3110 | ||||
3111 | if (set_check_aggs_by_ref (dest_plats, jfunc->agg.by_ref)) | |||
3112 | return true; | |||
3113 | ||||
3114 | int max_agg_items = opt_for_fn (cs->callee->function_symbol ()->decl,(opts_for_fn (cs->callee->function_symbol ()->decl)-> x_param_ipa_max_agg_items) | |||
3115 | param_ipa_max_agg_items)(opts_for_fn (cs->callee->function_symbol ()->decl)-> x_param_ipa_max_agg_items); | |||
3116 | FOR_EACH_VEC_ELT (*jfunc->agg.items, i, item)for (i = 0; (*jfunc->agg.items).iterate ((i), &(item)) ; ++(i)) | |||
3117 | { | |||
3118 | HOST_WIDE_INTlong val_size; | |||
3119 | ||||
3120 | if (item->offset < 0 || item->jftype == IPA_JF_UNKNOWN) | |||
3121 | continue; | |||
3122 | val_size = tree_to_shwi (TYPE_SIZE (item->type)((tree_class_check ((item->type), (tcc_type), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-cp.cc" , 3122, __FUNCTION__))->type_common.size)); | |||
3123 | ||||
3124 | if (merge_agg_lats_step (dest_plats, item->offset, val_size, | |||
3125 | &aglat, pre_existing, &ret, max_agg_items)) | |||
3126 | { | |||
3127 | ret |= propagate_aggregate_lattice (cs, item, *aglat); | |||
3128 | aglat = &(*aglat)->next; | |||
3129 | } | |||
3130 | else if (dest_plats->aggs_bottom) | |||
3131 | return true; | |||
3132 | } | |||
3133 | ||||
3134 | ret |= set_chain_of_aglats_contains_variable (*aglat); | |||
3135 | } | |||
3136 | else | |||
3137 | ret |= set_agg_lats_contain_variable (dest_plats); | |||
3138 | ||||
3139 | return ret; | |||
3140 | } | |||
3141 | ||||
3142 | /* Return true if on the way cfrom CS->caller to the final (non-alias and | |||
3143 | non-thunk) destination, the call passes through a thunk. */ | |||
3144 | ||||
3145 | static bool | |||
3146 | call_passes_through_thunk (cgraph_edge *cs) | |||
3147 | { | |||
3148 | cgraph_node *alias_or_thunk = cs->callee; | |||
3149 | while (alias_or_thunk->alias) | |||
3150 | alias_or_thunk = alias_or_thunk->get_alias_target (); | |||
3151 | return alias_or_thunk->thunk; | |||
3152 | } | |||
3153 | ||||
3154 | /* Propagate constants from the caller to the callee of CS. INFO describes the | |||
3155 | caller. */ | |||
3156 | ||||
3157 | static bool | |||
3158 | propagate_constants_across_call (struct cgraph_edge *cs) | |||
3159 | { | |||
3160 | class ipa_node_params *callee_info; | |||
3161 | enum availability availability; | |||
3162 | cgraph_node *callee; | |||
3163 | class ipa_edge_args *args; | |||
3164 | bool ret = false; | |||
3165 | int i, args_count, parms_count; | |||
3166 | ||||
3167 | callee = cs->callee->function_symbol (&availability); | |||
3168 | if (!callee->definition) | |||
3169 | return false; | |||
3170 | gcc_checking_assert (callee->has_gimple_body_p ())((void)(!(callee->has_gimple_body_p ()) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-cp.cc" , 3170, __FUNCTION__), 0 : 0)); | |||
3171 | callee_info = ipa_node_params_sum->get (callee); | |||
3172 | if (!callee_info) | |||
3173 | return false; | |||
3174 | ||||
3175 | args = ipa_edge_args_sum->get (cs); | |||
3176 | parms_count = ipa_get_param_count (callee_info); | |||
3177 | if (parms_count == 0) | |||
3178 | return false; | |||
3179 | if (!args | |||
3180 | || !opt_for_fn (cs->caller->decl, flag_ipa_cp)(opts_for_fn (cs->caller->decl)->x_flag_ipa_cp) | |||
3181 | || !opt_for_fn (cs->caller->decl, optimize)(opts_for_fn (cs->caller->decl)->x_optimize)) | |||
3182 | { | |||
3183 | for (i = 0; i < parms_count; i++) | |||
3184 | ret |= set_all_contains_variable (ipa_get_parm_lattices (callee_info, | |||
3185 | i)); | |||
3186 | return ret; | |||
3187 | } | |||
3188 | args_count = ipa_get_cs_argument_count (args); | |||
3189 | ||||
3190 | /* If this call goes through a thunk we must not propagate to the first (0th) | |||
3191 | parameter. However, we might need to uncover a thunk from below a series | |||
3192 | of aliases first. */ | |||
3193 | if (call_passes_through_thunk (cs)) | |||
3194 | { | |||
3195 | ret |= set_all_contains_variable (ipa_get_parm_lattices (callee_info, | |||
3196 | 0)); | |||
3197 | i = 1; | |||
3198 | } | |||
3199 | else | |||
3200 | i = 0; | |||
3201 | ||||
3202 | for (; (i < args_count) && (i < parms_count); i++) | |||
3203 | { | |||
3204 | struct ipa_jump_func *jump_func = ipa_get_ith_jump_func (args, i); | |||
3205 | class ipcp_param_lattices *dest_plats; | |||
3206 | tree param_type = ipa_get_type (callee_info, i); | |||
3207 | ||||
3208 | dest_plats = ipa_get_parm_lattices (callee_info, i); | |||
3209 | if (availability == AVAIL_INTERPOSABLE) | |||
3210 | ret |= set_all_contains_variable (dest_plats); | |||
3211 | else | |||
3212 | { | |||
3213 | ret |= propagate_scalar_across_jump_function (cs, jump_func, | |||
3214 | &dest_plats->itself, | |||
3215 | param_type); | |||
3216 | ret |= propagate_context_across_jump_function (cs, jump_func, i, | |||
3217 | &dest_plats->ctxlat); | |||
3218 | ret | |||
3219 | |= propagate_bits_across_jump_function (cs, i, jump_func, | |||
3220 | &dest_plats->bits_lattice); | |||
3221 | ret |= propagate_aggs_across_jump_function (cs, jump_func, | |||
3222 | dest_plats); | |||
3223 | if (opt_for_fn (callee->decl, flag_ipa_vrp)(opts_for_fn (callee->decl)->x_flag_ipa_vrp)) | |||
3224 | ret |= propagate_vr_across_jump_function (cs, jump_func, | |||
3225 | dest_plats, param_type); | |||
3226 | else | |||
3227 | ret |= dest_plats->m_value_range.set_to_bottom (); | |||
3228 | } | |||
3229 | } | |||
3230 | for (; i < parms_count; i++) | |||
3231 | ret |= set_all_contains_variable (ipa_get_parm_lattices (callee_info, i)); | |||
3232 | ||||
3233 | return ret; | |||
3234 | } | |||
3235 | ||||
3236 | /* If an indirect edge IE can be turned into a direct one based on KNOWN_VALS | |||
3237 | KNOWN_CONTEXTS, and known aggregates either in AVS or KNOWN_AGGS return | |||
3238 | the destination. The latter three can be NULL. If AGG_REPS is not NULL, | |||
3239 | KNOWN_AGGS is ignored. */ | |||
3240 | ||||
3241 | static tree | |||
3242 | ipa_get_indirect_edge_target_1 (struct cgraph_edge *ie, | |||
3243 | const vec<tree> &known_csts, | |||
3244 | const vec<ipa_polymorphic_call_context> &known_contexts, | |||
3245 | const ipa_argagg_value_list &avs, | |||
3246 | bool *speculative) | |||
3247 | { | |||
3248 | int param_index = ie->indirect_info->param_index; | |||
3249 | HOST_WIDE_INTlong anc_offset; | |||
3250 | tree t = NULLnullptr; | |||
3251 | tree target = NULLnullptr; | |||
3252 | ||||
3253 | *speculative = false; | |||
3254 | ||||
3255 | if (param_index == -1) | |||
3256 | return NULL_TREE(tree) nullptr; | |||
3257 | ||||
3258 | if (!ie->indirect_info->polymorphic) | |||
3259 | { | |||
3260 | tree t = NULLnullptr; | |||
3261 | ||||
3262 | if (ie->indirect_info->agg_contents) | |||
3263 | { | |||
3264 | t = NULLnullptr; | |||
3265 | if ((unsigned) param_index < known_csts.length () | |||
3266 | && known_csts[param_index]) | |||
3267 | t = ipa_find_agg_cst_from_init (known_csts[param_index], | |||
3268 | ie->indirect_info->offset, | |||
3269 | ie->indirect_info->by_ref); | |||
3270 | ||||
3271 | if (!t && ie->indirect_info->guaranteed_unmodified) | |||
3272 | t = avs.get_value (param_index, | |||
3273 | ie->indirect_info->offset / BITS_PER_UNIT(8), | |||
3274 | ie->indirect_info->by_ref); | |||
3275 | } | |||
3276 | else if ((unsigned) param_index < known_csts.length ()) | |||
3277 | t = known_csts[param_index]; | |||
3278 | ||||
3279 | if (t | |||
3280 | && TREE_CODE (t)((enum tree_code) (t)->base.code) == ADDR_EXPR | |||
3281 | && TREE_CODE (TREE_OPERAND (t, 0))((enum tree_code) ((*((const_cast<tree*> (tree_operand_check ((t), (0), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-cp.cc" , 3281, __FUNCTION__))))))->base.code) == FUNCTION_DECL) | |||
3282 | return TREE_OPERAND (t, 0)(*((const_cast<tree*> (tree_operand_check ((t), (0), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-cp.cc" , 3282, __FUNCTION__))))); | |||
3283 | else | |||
3284 | return NULL_TREE(tree) nullptr; | |||
3285 | } | |||
3286 | ||||
3287 | if (!opt_for_fn (ie->caller->decl, flag_devirtualize)(opts_for_fn (ie->caller->decl)->x_flag_devirtualize )) | |||
3288 | return NULL_TREE(tree) nullptr; | |||
3289 | ||||
3290 | gcc_assert (!ie->indirect_info->agg_contents)((void)(!(!ie->indirect_info->agg_contents) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-cp.cc" , 3290, __FUNCTION__), 0 : 0)); | |||
3291 | gcc_assert (!ie->indirect_info->by_ref)((void)(!(!ie->indirect_info->by_ref) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-cp.cc" , 3291, __FUNCTION__), 0 : 0)); | |||
3292 | anc_offset = ie->indirect_info->offset; | |||
3293 | ||||
3294 | t = NULLnullptr; | |||
3295 | ||||
3296 | if ((unsigned) param_index < known_csts.length () | |||
3297 | && known_csts[param_index]) | |||
3298 | t = ipa_find_agg_cst_from_init (known_csts[param_index], | |||
3299 | ie->indirect_info->offset, true); | |||
3300 | ||||
3301 | /* Try to work out value of virtual table pointer value in replacements. */ | |||
3302 | /* or known aggregate values. */ | |||
3303 | if (!t) | |||
3304 | t = avs.get_value (param_index, | |||
3305 | ie->indirect_info->offset / BITS_PER_UNIT(8), | |||
3306 | true); | |||
3307 | ||||
3308 | /* If we found the virtual table pointer, lookup the target. */ | |||
3309 | if (t) | |||
3310 | { | |||
3311 | tree vtable; | |||
3312 | unsigned HOST_WIDE_INTlong offset; | |||
3313 | if (vtable_pointer_value_to_vtable (t, &vtable, &offset)) | |||
3314 | { | |||
3315 | bool can_refer; | |||
3316 | target = gimple_get_virt_method_for_vtable (ie->indirect_info->otr_token, | |||
3317 | vtable, offset, &can_refer); | |||
3318 | if (can_refer) | |||
3319 | { | |||
3320 | if (!target | |||
3321 | || fndecl_built_in_p (target, BUILT_IN_UNREACHABLE) | |||
3322 | || !possible_polymorphic_call_target_p | |||
3323 | (ie, cgraph_node::get (target))) | |||
3324 | { | |||
3325 | /* Do not speculate builtin_unreachable, it is stupid! */ | |||
3326 | if (ie->indirect_info->vptr_changed) | |||
3327 | return NULLnullptr; | |||
3328 | target = ipa_impossible_devirt_target (ie, target); | |||
3329 | } | |||
3330 | *speculative = ie->indirect_info->vptr_changed; | |||
3331 | if (!*speculative) | |||
3332 | return target; | |||
3333 | } | |||
3334 | } | |||
3335 | } | |||
3336 | ||||
3337 | /* Do we know the constant value of pointer? */ | |||
3338 | if (!t && (unsigned) param_index < known_csts.length ()) | |||
3339 | t = known_csts[param_index]; | |||
3340 | ||||
3341 | gcc_checking_assert (!t || TREE_CODE (t) != TREE_BINFO)((void)(!(!t || ((enum tree_code) (t)->base.code) != TREE_BINFO ) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-cp.cc" , 3341, __FUNCTION__), 0 : 0)); | |||
3342 | ||||
3343 | ipa_polymorphic_call_context context; | |||
3344 | if (known_contexts.length () > (unsigned int) param_index) | |||
3345 | { | |||
3346 | context = known_contexts[param_index]; | |||
3347 | context.offset_by (anc_offset); | |||
3348 | if (ie->indirect_info->vptr_changed) | |||
3349 | context.possible_dynamic_type_change (ie->in_polymorphic_cdtor, | |||
3350 | ie->indirect_info->otr_type); | |||
3351 | if (t) | |||
3352 | { | |||
3353 | ipa_polymorphic_call_context ctx2 = ipa_polymorphic_call_context | |||
3354 | (t, ie->indirect_info->otr_type, anc_offset); | |||
3355 | if (!ctx2.useless_p ()) | |||
3356 | context.combine_with (ctx2, ie->indirect_info->otr_type); | |||
3357 | } | |||
3358 | } | |||
3359 | else if (t) | |||
3360 | { | |||
3361 | context = ipa_polymorphic_call_context (t, ie->indirect_info->otr_type, | |||
3362 | anc_offset); | |||
3363 | if (ie->indirect_info->vptr_changed) | |||
3364 | context.possible_dynamic_type_change (ie->in_polymorphic_cdtor, | |||
3365 | ie->indirect_info->otr_type); | |||
3366 | } | |||
3367 | else | |||
3368 | return NULL_TREE(tree) nullptr; | |||
3369 | ||||
3370 | vec <cgraph_node *>targets; | |||
3371 | bool final; | |||
3372 | ||||
3373 | targets = possible_polymorphic_call_targets | |||
3374 | (ie->indirect_info->otr_type, | |||
3375 | ie->indirect_info->otr_token, | |||
3376 | context, &final); | |||
3377 | if (!final || targets.length () > 1) | |||
3378 | { | |||
3379 | struct cgraph_node *node; | |||
3380 | if (*speculative) | |||
3381 | return target; | |||
3382 | if (!opt_for_fn (ie->caller->decl, flag_devirtualize_speculatively)(opts_for_fn (ie->caller->decl)->x_flag_devirtualize_speculatively ) | |||
3383 | || ie->speculative || !ie->maybe_hot_p ()) | |||
3384 | return NULLnullptr; | |||
3385 | node = try_speculative_devirtualization (ie->indirect_info->otr_type, | |||
3386 | ie->indirect_info->otr_token, | |||
3387 | context); | |||
3388 | if (node) | |||
3389 | { | |||
3390 | *speculative = true; | |||
3391 | target = node->decl; | |||
3392 | } | |||
3393 | else | |||
3394 | return NULLnullptr; | |||
3395 | } | |||
3396 | else | |||
3397 | { | |||
3398 | *speculative = false; | |||
3399 | if (targets.length () == 1) | |||
3400 | target = targets[0]->decl; | |||
3401 | else | |||
3402 | target = ipa_impossible_devirt_target (ie, NULL_TREE(tree) nullptr); | |||
3403 | } | |||
3404 | ||||
3405 | if (target && !possible_polymorphic_call_target_p (ie, | |||
3406 | cgraph_node::get (target))) | |||
3407 | { | |||
3408 | if (*speculative) | |||
3409 | return NULLnullptr; | |||
3410 | target = ipa_impossible_devirt_target (ie, target); | |||
3411 | } | |||
3412 | ||||
3413 | return target; | |||
3414 | } | |||
3415 | ||||
3416 | /* If an indirect edge IE can be turned into a direct one based on data in | |||
3417 | AVALS, return the destination. Store into *SPECULATIVE a boolean determinig | |||
3418 | whether the discovered target is only speculative guess. */ | |||
3419 | ||||
3420 | tree | |||
3421 | ipa_get_indirect_edge_target (struct cgraph_edge *ie, | |||
3422 | ipa_call_arg_values *avals, | |||
3423 | bool *speculative) | |||
3424 | { | |||
3425 | ipa_argagg_value_list avl (avals); | |||
3426 | return ipa_get_indirect_edge_target_1 (ie, avals->m_known_vals, | |||
3427 | avals->m_known_contexts, | |||
3428 | avl, speculative); | |||
3429 | } | |||
3430 | ||||
3431 | /* Calculate devirtualization time bonus for NODE, assuming we know information | |||
3432 | about arguments stored in AVALS. */ | |||
3433 | ||||
3434 | static int | |||
3435 | devirtualization_time_bonus (struct cgraph_node *node, | |||
3436 | ipa_auto_call_arg_values *avals) | |||
3437 | { | |||
3438 | struct cgraph_edge *ie; | |||
3439 | int res = 0; | |||
3440 | ||||
3441 | for (ie = node->indirect_calls; ie; ie = ie->next_callee) | |||
3442 | { | |||
3443 | struct cgraph_node *callee; | |||
3444 | class ipa_fn_summary *isummary; | |||
3445 | enum availability avail; | |||
3446 | tree target; | |||
3447 | bool speculative; | |||
3448 | ||||
3449 | ipa_argagg_value_list avl (avals); | |||
3450 | target = ipa_get_indirect_edge_target_1 (ie, avals->m_known_vals, | |||
3451 | avals->m_known_contexts, | |||
3452 | avl, &speculative); | |||
3453 | if (!target) | |||
3454 | continue; | |||
3455 | ||||
3456 | /* Only bare minimum benefit for clearly un-inlineable targets. */ | |||
3457 | res += 1; | |||
3458 | callee = cgraph_node::get (target); | |||
3459 | if (!callee || !callee->definition) | |||
3460 | continue; | |||
3461 | callee = callee->function_symbol (&avail); | |||
3462 | if (avail < AVAIL_AVAILABLE) | |||
3463 | continue; | |||
3464 | isummary = ipa_fn_summaries->get (callee); | |||
3465 | if (!isummary || !isummary->inlinable) | |||
3466 | continue; | |||
3467 | ||||
3468 | int size = ipa_size_summaries->get (callee)->size; | |||
3469 | /* FIXME: The values below need re-considering and perhaps also | |||
3470 | integrating into the cost metrics, at lest in some very basic way. */ | |||
3471 | int max_inline_insns_auto | |||
3472 | = opt_for_fn (callee->decl, param_max_inline_insns_auto)(opts_for_fn (callee->decl)->x_param_max_inline_insns_auto ); | |||
3473 | if (size <= max_inline_insns_auto / 4) | |||
3474 | res += 31 / ((int)speculative + 1); | |||
3475 | else if (size <= max_inline_insns_auto / 2) | |||
3476 | res += 15 / ((int)speculative + 1); | |||
3477 | else if (size <= max_inline_insns_auto | |||
3478 | || DECL_DECLARED_INLINE_P (callee->decl)((tree_check ((callee->decl), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-cp.cc" , 3478, __FUNCTION__, (FUNCTION_DECL)))->function_decl.declared_inline_flag )) | |||
3479 | res += 7 / ((int)speculative + 1); | |||
3480 | } | |||
3481 | ||||
3482 | return res; | |||
3483 | } | |||
3484 | ||||
3485 | /* Return time bonus incurred because of hints stored in ESTIMATES. */ | |||
3486 | ||||
3487 | static int | |||
3488 | hint_time_bonus (cgraph_node *node, const ipa_call_estimates &estimates) | |||
3489 | { | |||
3490 | int result = 0; | |||
3491 | ipa_hints hints = estimates.hints; | |||
3492 | if (hints & (INLINE_HINT_loop_iterations | INLINE_HINT_loop_stride)) | |||
3493 | result += opt_for_fn (node->decl, param_ipa_cp_loop_hint_bonus)(opts_for_fn (node->decl)->x_param_ipa_cp_loop_hint_bonus ); | |||
3494 | ||||
3495 | sreal bonus_for_one = opt_for_fn (node->decl, param_ipa_cp_loop_hint_bonus)(opts_for_fn (node->decl)->x_param_ipa_cp_loop_hint_bonus ); | |||
3496 | ||||
3497 | if (hints & INLINE_HINT_loop_iterations) | |||
3498 | result += (estimates.loops_with_known_iterations * bonus_for_one).to_int (); | |||
3499 | ||||
3500 | if (hints & INLINE_HINT_loop_stride) | |||
3501 | result += (estimates.loops_with_known_strides * bonus_for_one).to_int (); | |||
3502 | ||||
3503 | return result; | |||
3504 | } | |||
3505 | ||||
3506 | /* If there is a reason to penalize the function described by INFO in the | |||
3507 | cloning goodness evaluation, do so. */ | |||
3508 | ||||
3509 | static inline sreal | |||
3510 | incorporate_penalties (cgraph_node *node, ipa_node_params *info, | |||
3511 | sreal evaluation) | |||
3512 | { | |||
3513 | if (info->node_within_scc && !info->node_is_self_scc) | |||
3514 | evaluation = (evaluation | |||
3515 | * (100 - opt_for_fn (node->decl,(opts_for_fn (node->decl)->x_param_ipa_cp_recursion_penalty ) | |||
3516 | param_ipa_cp_recursion_penalty)(opts_for_fn (node->decl)->x_param_ipa_cp_recursion_penalty ))) / 100; | |||
3517 | ||||
3518 | if (info->node_calling_single_call) | |||
3519 | evaluation = (evaluation | |||
3520 | * (100 - opt_for_fn (node->decl,(opts_for_fn (node->decl)->x_param_ipa_cp_single_call_penalty ) | |||
3521 | param_ipa_cp_single_call_penalty)(opts_for_fn (node->decl)->x_param_ipa_cp_single_call_penalty ))) | |||
3522 | / 100; | |||
3523 | ||||
3524 | return evaluation; | |||
3525 | } | |||
3526 | ||||
3527 | /* Return true if cloning NODE is a good idea, given the estimated TIME_BENEFIT | |||
3528 | and SIZE_COST and with the sum of frequencies of incoming edges to the | |||
3529 | potential new clone in FREQUENCIES. */ | |||
3530 | ||||
3531 | static bool | |||
3532 | good_cloning_opportunity_p (struct cgraph_node *node, sreal time_benefit, | |||
3533 | sreal freq_sum, profile_count count_sum, | |||
3534 | int size_cost) | |||
3535 | { | |||
3536 | if (time_benefit == 0 | |||
3537 | || !opt_for_fn (node->decl, flag_ipa_cp_clone)(opts_for_fn (node->decl)->x_flag_ipa_cp_clone) | |||
3538 | || node->optimize_for_size_p ()) | |||
3539 | return false; | |||
3540 | ||||
3541 | gcc_assert (size_cost > 0)((void)(!(size_cost > 0) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-cp.cc" , 3541, __FUNCTION__), 0 : 0)); | |||
3542 | ||||
3543 | ipa_node_params *info = ipa_node_params_sum->get (node); | |||
3544 | int eval_threshold = opt_for_fn (node->decl, param_ipa_cp_eval_threshold)(opts_for_fn (node->decl)->x_param_ipa_cp_eval_threshold ); | |||
3545 | if (count_sum.nonzero_p ()) | |||
3546 | { | |||
3547 | gcc_assert (base_count.nonzero_p ())((void)(!(base_count.nonzero_p ()) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-cp.cc" , 3547, __FUNCTION__), 0 : 0)); | |||
3548 | sreal factor = count_sum.probability_in (base_count).to_sreal (); | |||
3549 | sreal evaluation = (time_benefit * factor) / size_cost; | |||
3550 | evaluation = incorporate_penalties (node, info, evaluation); | |||
3551 | evaluation *= 1000; | |||
3552 | ||||
3553 | if (dump_file && (dump_flags & TDF_DETAILS)) | |||
3554 | { | |||
3555 | fprintf (dump_file, " good_cloning_opportunity_p (time: %g, " | |||
3556 | "size: %i, count_sum: ", time_benefit.to_double (), | |||
3557 | size_cost); | |||
3558 | count_sum.dump (dump_file); | |||
3559 | fprintf (dump_file, "%s%s) -> evaluation: %.2f, threshold: %i\n", | |||
3560 | info->node_within_scc | |||
3561 | ? (info->node_is_self_scc ? ", self_scc" : ", scc") : "", | |||
3562 | info->node_calling_single_call ? ", single_call" : "", | |||
3563 | evaluation.to_double (), eval_threshold); | |||
3564 | } | |||
3565 | ||||
3566 | return evaluation.to_int () >= eval_threshold; | |||
3567 | } | |||
3568 | else | |||
3569 | { | |||
3570 | sreal evaluation = (time_benefit * freq_sum) / size_cost; | |||
3571 | evaluation = incorporate_penalties (node, info, evaluation); | |||
3572 | evaluation *= 1000; | |||
3573 | ||||
3574 | if (dump_file && (dump_flags & TDF_DETAILS)) | |||
3575 | fprintf (dump_file, " good_cloning_opportunity_p (time: %g, " | |||
3576 | "size: %i, freq_sum: %g%s%s) -> evaluation: %.2f, " | |||
3577 | "threshold: %i\n", | |||
3578 | time_benefit.to_double (), size_cost, freq_sum.to_double (), | |||
3579 | info->node_within_scc | |||
3580 | ? (info->node_is_self_scc ? ", self_scc" : ", scc") : "", | |||
3581 | info->node_calling_single_call ? ", single_call" : "", | |||
3582 | evaluation.to_double (), eval_threshold); | |||
3583 | ||||
3584 | return evaluation.to_int () >= eval_threshold; | |||
3585 | } | |||
3586 | } | |||
3587 | ||||
3588 | /* Grow vectors in AVALS and fill them with information about values of | |||
3589 | parameters that are known to be independent of the context. Only calculate | |||
3590 | m_known_aggs if CALCULATE_AGGS is true. INFO describes the function. If | |||
3591 | REMOVABLE_PARAMS_COST is non-NULL, the movement cost of all removable | |||
3592 | parameters will be stored in it. | |||
3593 | ||||
3594 | TODO: Also grow context independent value range vectors. */ | |||
3595 | ||||
3596 | static bool | |||
3597 | gather_context_independent_values (class ipa_node_params *info, | |||
3598 | ipa_auto_call_arg_values *avals, | |||
3599 | bool calculate_aggs, | |||
3600 | int *removable_params_cost) | |||
3601 | { | |||
3602 | int i, count = ipa_get_param_count (info); | |||
3603 | bool ret = false; | |||
3604 | ||||
3605 | avals->m_known_vals.safe_grow_cleared (count, true); | |||
3606 | avals->m_known_contexts.safe_grow_cleared (count, true); | |||
3607 | ||||
3608 | if (removable_params_cost) | |||
3609 | *removable_params_cost = 0; | |||
3610 | ||||
3611 | for (i = 0; i < count; i++) | |||
3612 | { | |||
3613 | class ipcp_param_lattices *plats = ipa_get_parm_lattices (info, i); | |||
3614 | ipcp_lattice<tree> *lat = &plats->itself; | |||
3615 | ||||
3616 | if (lat->is_single_const ()) | |||
3617 | { | |||
3618 | ipcp_value<tree> *val = lat->values; | |||
3619 | gcc_checking_assert (TREE_CODE (val->value) != TREE_BINFO)((void)(!(((enum tree_code) (val->value)->base.code) != TREE_BINFO) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-cp.cc" , 3619, __FUNCTION__), 0 : 0)); | |||
3620 | avals->m_known_vals[i] = val->value; | |||
3621 | if (removable_params_cost) | |||
3622 | *removable_params_cost | |||
3623 | += estimate_move_cost (TREE_TYPE (val->value)((contains_struct_check ((val->value), (TS_TYPED), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-cp.cc" , 3623, __FUNCTION__))->typed.type), false); | |||
3624 | ret = true; | |||
3625 | } | |||
3626 | else if (removable_params_cost | |||
3627 | && !ipa_is_param_used (info, i)) | |||
3628 | *removable_params_cost | |||
3629 | += ipa_get_param_move_cost (info, i); | |||
3630 | ||||
3631 | if (!ipa_is_param_used (info, i)) | |||
3632 | continue; | |||
3633 | ||||
3634 | ipcp_lattice<ipa_polymorphic_call_context> *ctxlat = &plats->ctxlat; | |||
3635 | /* Do not account known context as reason for cloning. We can see | |||
3636 | if it permits devirtualization. */ | |||
3637 | if (ctxlat->is_single_const ()) | |||
3638 | avals->m_known_contexts[i] = ctxlat->values->value; | |||
3639 | ||||
3640 | if (calculate_aggs) | |||
3641 | ret |= push_agg_values_from_plats (plats, i, 0, &avals->m_known_aggs); | |||
3642 | } | |||
3643 | ||||
3644 | return ret; | |||
3645 | } | |||
3646 | ||||
3647 | /* Perform time and size measurement of NODE with the context given in AVALS, | |||
3648 | calculate the benefit compared to the node without specialization and store | |||
3649 | it into VAL. Take into account REMOVABLE_PARAMS_COST of all | |||
3650 | context-independent or unused removable parameters and EST_MOVE_COST, the | |||
3651 | estimated movement of the considered parameter. */ | |||
3652 | ||||
3653 | static void | |||
3654 | perform_estimation_of_a_value (cgraph_node *node, | |||
3655 | ipa_auto_call_arg_values *avals, | |||
3656 | int removable_params_cost, int est_move_cost, | |||
3657 | ipcp_value_base *val) | |||
3658 | { | |||
3659 | sreal time_benefit; | |||
3660 | ipa_call_estimates estimates; | |||
3661 | ||||
3662 | estimate_ipcp_clone_size_and_time (node, avals, &estimates); | |||
3663 | ||||
3664 | /* Extern inline functions have no cloning local time benefits because they | |||
3665 | will be inlined anyway. The only reason to clone them is if it enables | |||
3666 | optimization in any of the functions they call. */ | |||
3667 | if (DECL_EXTERNAL (node->decl)((contains_struct_check ((node->decl), (TS_DECL_COMMON), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-cp.cc" , 3667, __FUNCTION__))->decl_common.decl_flag_1) && DECL_DECLARED_INLINE_P (node->decl)((tree_check ((node->decl), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-cp.cc" , 3667, __FUNCTION__, (FUNCTION_DECL)))->function_decl.declared_inline_flag )) | |||
3668 | time_benefit = 0; | |||
3669 | else | |||
3670 | time_benefit = (estimates.nonspecialized_time - estimates.time) | |||
3671 | + (devirtualization_time_bonus (node, avals) | |||
3672 | + hint_time_bonus (node, estimates) | |||
3673 | + removable_params_cost + est_move_cost); | |||
3674 | ||||
3675 | int size = estimates.size; | |||
3676 | gcc_checking_assert (size >=0)((void)(!(size >=0) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-cp.cc" , 3676, __FUNCTION__), 0 : 0)); | |||
3677 | /* The inliner-heuristics based estimates may think that in certain | |||
3678 | contexts some functions do not have any size at all but we want | |||
3679 | all specializations to have at least a tiny cost, not least not to | |||
3680 | divide by zero. */ | |||
3681 | if (size == 0) | |||
3682 | size = 1; | |||
3683 | ||||
3684 | val->local_time_benefit = time_benefit; | |||
3685 | val->local_size_cost = size; | |||
3686 | } | |||
3687 | ||||
3688 | /* Get the overall limit oof growth based on parameters extracted from growth. | |||
3689 | it does not really make sense to mix functions with different overall growth | |||
3690 | limits but it is possible and if it happens, we do not want to select one | |||
3691 | limit at random. */ | |||
3692 | ||||
3693 | static long | |||
3694 | get_max_overall_size (cgraph_node *node) | |||
3695 | { | |||
3696 | long max_new_size = orig_overall_size; | |||
3697 | long large_unit = opt_for_fn (node->decl, param_ipa_cp_large_unit_insns)(opts_for_fn (node->decl)->x_param_ipa_cp_large_unit_insns ); | |||
3698 | if (max_new_size < large_unit) | |||
3699 | max_new_size = large_unit; | |||
3700 | int unit_growth = opt_for_fn (node->decl, param_ipa_cp_unit_growth)(opts_for_fn (node->decl)->x_param_ipa_cp_unit_growth); | |||
3701 | max_new_size += max_new_size * unit_growth / 100 + 1; | |||
3702 | return max_new_size; | |||
3703 | } | |||
3704 | ||||
3705 | /* Return true if NODE should be cloned just for a parameter removal, possibly | |||
3706 | dumping a reason if not. */ | |||
3707 | ||||
3708 | static bool | |||
3709 | clone_for_param_removal_p (cgraph_node *node) | |||
3710 | { | |||
3711 | if (!node->can_change_signature) | |||
3712 | { | |||
3713 | if (dump_file && (dump_flags & TDF_DETAILS)) | |||
3714 | fprintf (dump_file, " Not considering cloning to remove parameters, " | |||
3715 | "function cannot change signature.\n"); | |||
3716 | return false; | |||
3717 | } | |||
3718 | if (node->can_be_local_p ()) | |||
3719 | { | |||
3720 | if (dump_file && (dump_flags & TDF_DETAILS)) | |||
3721 | fprintf (dump_file, " Not considering cloning to remove parameters, " | |||
3722 | "IPA-SRA can do it potentially better.\n"); | |||
3723 | return false; | |||
3724 | } | |||
3725 | return true; | |||
3726 | } | |||
3727 | ||||
3728 | /* Iterate over known values of parameters of NODE and estimate the local | |||
3729 | effects in terms of time and size they have. */ | |||
3730 | ||||
3731 | static void | |||
3732 | estimate_local_effects (struct cgraph_node *node) | |||
3733 | { | |||
3734 | ipa_node_params *info = ipa_node_params_sum->get (node); | |||
3735 | int count = ipa_get_param_count (info); | |||
3736 | bool always_const; | |||
3737 | int removable_params_cost; | |||
3738 | ||||
3739 | if (!count || !ipcp_versionable_function_p (node)) | |||
3740 | return; | |||
3741 | ||||
3742 | if (dump_file && (dump_flags & TDF_DETAILS)) | |||
3743 | fprintf (dump_file, "\nEstimating effects for %s.\n", node->dump_name ()); | |||
3744 | ||||
3745 | ipa_auto_call_arg_values avals; | |||
3746 | always_const = gather_context_independent_values (info, &avals, true, | |||
3747 | &removable_params_cost); | |||
3748 | int devirt_bonus = devirtualization_time_bonus (node, &avals); | |||
3749 | if (always_const || devirt_bonus | |||
3750 | || (removable_params_cost && clone_for_param_removal_p (node))) | |||
3751 | { | |||
3752 | struct caller_statistics stats; | |||
3753 | ipa_call_estimates estimates; | |||
3754 | ||||
3755 | init_caller_stats (&stats); | |||
3756 | node->call_for_symbol_thunks_and_aliases (gather_caller_stats, &stats, | |||
3757 | false); | |||
3758 | estimate_ipcp_clone_size_and_time (node, &avals, &estimates); | |||
3759 | sreal time = estimates.nonspecialized_time - estimates.time; | |||
3760 | time += devirt_bonus; | |||
3761 | time += hint_time_bonus (node, estimates); | |||
3762 | time += removable_params_cost; | |||
3763 | int size = estimates.size - stats.n_calls * removable_params_cost; | |||
3764 | ||||
3765 | if (dump_file) | |||
3766 | fprintf (dump_file, " - context independent values, size: %i, " | |||
3767 | "time_benefit: %f\n", size, (time).to_double ()); | |||
3768 | ||||
3769 | if (size <= 0 || node->local) | |||
3770 | { | |||
3771 | info->do_clone_for_all_contexts = true; | |||
3772 | ||||
3773 | if (dump_file) | |||
3774 | fprintf (dump_file, " Decided to specialize for all " | |||
3775 | "known contexts, code not going to grow.\n"); | |||
3776 | } | |||
3777 | else if (good_cloning_opportunity_p (node, time, stats.freq_sum, | |||
3778 | stats.count_sum, size)) | |||
3779 | { | |||
3780 | if (size + overall_size <= get_max_overall_size (node)) | |||
3781 | { | |||
3782 | info->do_clone_for_all_contexts = true; | |||
3783 | overall_size += size; | |||
3784 | ||||
3785 | if (dump_file) | |||
3786 | fprintf (dump_file, " Decided to specialize for all " | |||
3787 | "known contexts, growth (to %li) deemed " | |||
3788 | "beneficial.\n", overall_size); | |||
3789 | } | |||
3790 | else if (dump_file && (dump_flags & TDF_DETAILS)) | |||
3791 | fprintf (dump_file, " Not cloning for all contexts because " | |||
3792 | "maximum unit size would be reached with %li.\n", | |||
3793 | size + overall_size); | |||
3794 | } | |||
3795 | else if (dump_file && (dump_flags & TDF_DETAILS)) | |||
3796 | fprintf (dump_file, " Not cloning for all contexts because " | |||
3797 | "!good_cloning_opportunity_p.\n"); | |||
3798 | ||||
3799 | } | |||
3800 | ||||
3801 | for (int i = 0; i < count; i++) | |||
3802 | { | |||
3803 | class ipcp_param_lattices *plats = ipa_get_parm_lattices (info, i); | |||
3804 | ipcp_lattice<tree> *lat = &plats->itself; | |||
3805 | ipcp_value<tree> *val; | |||
3806 | ||||
3807 | if (lat->bottom | |||
3808 | || !lat->values | |||
3809 | || avals.m_known_vals[i]) | |||
3810 | continue; | |||
3811 | ||||
3812 | for (val = lat->values; val; val = val->next) | |||
3813 | { | |||
3814 | gcc_checking_assert (TREE_CODE (val->value) != TREE_BINFO)((void)(!(((enum tree_code) (val->value)->base.code) != TREE_BINFO) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-cp.cc" , 3814, __FUNCTION__), 0 : 0)); | |||
3815 | avals.m_known_vals[i] = val->value; | |||
3816 | ||||
3817 | int emc = estimate_move_cost (TREE_TYPE (val->value)((contains_struct_check ((val->value), (TS_TYPED), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-cp.cc" , 3817, __FUNCTION__))->typed.type), true); | |||
3818 | perform_estimation_of_a_value (node, &avals, removable_params_cost, | |||
3819 | emc, val); | |||
3820 | ||||
3821 | if (dump_file && (dump_flags & TDF_DETAILS)) | |||
3822 | { | |||
3823 | fprintf (dump_file, " - estimates for value "); | |||
3824 | print_ipcp_constant_value (dump_file, val->value); | |||
3825 | fprintf (dump_file, " for "); | |||
3826 | ipa_dump_param (dump_file, info, i); | |||
3827 | fprintf (dump_file, ": time_benefit: %g, size: %i\n", | |||
3828 | val->local_time_benefit.to_double (), | |||
3829 | val->local_size_cost); | |||
3830 | } | |||
3831 | } | |||
3832 | avals.m_known_vals[i] = NULL_TREE(tree) nullptr; | |||
3833 | } | |||
3834 | ||||
3835 | for (int i = 0; i < count; i++) | |||
3836 | { | |||
3837 | class ipcp_param_lattices *plats = ipa_get_parm_lattices (info, i); | |||
3838 | ||||
3839 | if (!plats->virt_call) | |||
3840 | continue; | |||
3841 | ||||
3842 | ipcp_lattice<ipa_polymorphic_call_context> *ctxlat = &plats->ctxlat; | |||
3843 | ipcp_value<ipa_polymorphic_call_context> *val; | |||
3844 | ||||
3845 | if (ctxlat->bottom | |||
3846 | || !ctxlat->values | |||
3847 | || !avals.m_known_contexts[i].useless_p ()) | |||
3848 | continue; | |||
3849 | ||||
3850 | for (val = ctxlat->values; val; val = val->next) | |||
3851 | { | |||
3852 | avals.m_known_contexts[i] = val->value; | |||
3853 | perform_estimation_of_a_value (node, &avals, removable_params_cost, | |||
3854 | 0, val); | |||
3855 | ||||
3856 | if (dump_file && (dump_flags & TDF_DETAILS)) | |||
3857 | { | |||
3858 | fprintf (dump_file, " - estimates for polymorphic context "); | |||
3859 | print_ipcp_constant_value (dump_file, val->value); | |||
3860 | fprintf (dump_file, " for "); | |||
3861 | ipa_dump_param (dump_file, info, i); | |||
3862 | fprintf (dump_file, ": time_benefit: %g, size: %i\n", | |||
3863 | val->local_time_benefit.to_double (), | |||
3864 | val->local_size_cost); | |||
3865 | } | |||
3866 | } | |||
3867 | avals.m_known_contexts[i] = ipa_polymorphic_call_context (); | |||
3868 | } | |||
3869 | ||||
3870 | unsigned all_ctx_len = avals.m_known_aggs.length (); | |||
3871 | auto_vec<ipa_argagg_value, 32> all_ctx; | |||
3872 | all_ctx.reserve_exact (all_ctx_len); | |||
3873 | all_ctx.splice (avals.m_known_aggs); | |||
3874 | avals.m_known_aggs.safe_grow_cleared (all_ctx_len + 1); | |||
3875 | ||||
3876 | unsigned j = 0; | |||
3877 | for (int index = 0; index < count; index++) | |||
3878 | { | |||
3879 | class ipcp_param_lattices *plats = ipa_get_parm_lattices (info, index); | |||
3880 | ||||
3881 | if (plats->aggs_bottom || !plats->aggs) | |||
3882 | continue; | |||
3883 | ||||
3884 | for (ipcp_agg_lattice *aglat = plats->aggs; aglat; aglat = aglat->next) | |||
3885 | { | |||
3886 | ipcp_value<tree> *val; | |||
3887 | if (aglat->bottom || !aglat->values | |||
3888 | /* If the following is true, the one value is already part of all | |||
3889 | context estimations. */ | |||
3890 | || (!plats->aggs_contain_variable | |||
3891 | && aglat->is_single_const ())) | |||
3892 | continue; | |||
3893 | ||||
3894 | unsigned unit_offset = aglat->offset / BITS_PER_UNIT(8); | |||
3895 | while (j < all_ctx_len | |||
3896 | && (all_ctx[j].index < index | |||
3897 | || (all_ctx[j].index == index | |||
3898 | && all_ctx[j].unit_offset < unit_offset))) | |||
3899 | { | |||
3900 | avals.m_known_aggs[j] = all_ctx[j]; | |||
3901 | j++; | |||
3902 | } | |||
3903 | ||||
3904 | for (unsigned k = j; k < all_ctx_len; k++) | |||
3905 | avals.m_known_aggs[k+1] = all_ctx[k]; | |||
3906 | ||||
3907 | for (val = aglat->values; val; val = val->next) | |||
3908 | { | |||
3909 | avals.m_known_aggs[j].value = val->value; | |||
3910 | avals.m_known_aggs[j].unit_offset = unit_offset; | |||
3911 | avals.m_known_aggs[j].index = index; | |||
3912 | avals.m_known_aggs[j].by_ref = plats->aggs_by_ref; | |||
3913 | ||||
3914 | perform_estimation_of_a_value (node, &avals, | |||
3915 | removable_params_cost, 0, val); | |||
3916 | ||||
3917 | if (dump_file && (dump_flags & TDF_DETAILS)) | |||
3918 | { | |||
3919 | fprintf (dump_file, " - estimates for value "); | |||
3920 | print_ipcp_constant_value (dump_file, val->value); | |||
3921 | fprintf (dump_file, " for "); | |||
3922 | ipa_dump_param (dump_file, info, index); | |||
3923 | fprintf (dump_file, "[%soffset: " HOST_WIDE_INT_PRINT_DEC"%" "l" "d" | |||
3924 | "]: time_benefit: %g, size: %i\n", | |||
3925 | plats->aggs_by_ref ? "ref " : "", | |||
3926 | aglat->offset, | |||
3927 | val->local_time_benefit.to_double (), | |||
3928 | val->local_size_cost); | |||
3929 | } | |||
3930 | } | |||
3931 | } | |||
3932 | } | |||
3933 | } | |||
3934 | ||||
3935 | ||||
3936 | /* Add value CUR_VAL and all yet-unsorted values it is dependent on to the | |||
3937 | topological sort of values. */ | |||
3938 | ||||
3939 | template <typename valtype> | |||
3940 | void | |||
3941 | value_topo_info<valtype>::add_val (ipcp_value<valtype> *cur_val) | |||
3942 | { | |||
3943 | ipcp_value_source<valtype> *src; | |||
3944 | ||||
3945 | if (cur_val->dfs) | |||
3946 | return; | |||
3947 | ||||
3948 | dfs_counter++; | |||
3949 | cur_val->dfs = dfs_counter; | |||
3950 | cur_val->low_link = dfs_counter; | |||
3951 | ||||
3952 | cur_val->topo_next = stack; | |||
3953 | stack = cur_val; | |||
3954 | cur_val->on_stack = true; | |||
3955 | ||||
3956 | for (src = cur_val->sources; src; src = src->next) | |||
3957 | if (src->val) | |||
3958 | { | |||
3959 | if (src->val->dfs == 0) | |||
3960 | { | |||
3961 | add_val (src->val); | |||
3962 | if (src->val->low_link < cur_val->low_link) | |||
3963 | cur_val->low_link = src->val->low_link; | |||
3964 | } | |||
3965 | else if (src->val->on_stack | |||
3966 | && src->val->dfs < cur_val->low_link) | |||
3967 | cur_val->low_link = src->val->dfs; | |||
3968 | } | |||
3969 | ||||
3970 | if (cur_val->dfs == cur_val->low_link) | |||
3971 | { | |||
3972 | ipcp_value<valtype> *v, *scc_list = NULLnullptr; | |||
3973 | ||||
3974 | do | |||
3975 | { | |||
3976 | v = stack; | |||
3977 | stack = v->topo_next; | |||
3978 | v->on_stack = false; | |||
3979 | v->scc_no = cur_val->dfs; | |||
3980 | ||||
3981 | v->scc_next = scc_list; | |||
3982 | scc_list = v; | |||
3983 | } | |||
3984 | while (v != cur_val); | |||
3985 | ||||
3986 | cur_val->topo_next = values_topo; | |||
3987 | values_topo = cur_val; | |||
3988 | } | |||
3989 | } | |||
3990 | ||||
3991 | /* Add all values in lattices associated with NODE to the topological sort if | |||
3992 | they are not there yet. */ | |||
3993 | ||||
3994 | static void | |||
3995 | add_all_node_vals_to_toposort (cgraph_node *node, ipa_topo_info *topo) | |||
3996 | { | |||
3997 | ipa_node_params *info = ipa_node_params_sum->get (node); | |||
3998 | int i, count = ipa_get_param_count (info); | |||
3999 | ||||
4000 | for (i = 0; i < count; i++) | |||
4001 | { | |||
4002 | class ipcp_param_lattices *plats = ipa_get_parm_lattices (info, i); | |||
4003 | ipcp_lattice<tree> *lat = &plats->itself; | |||
4004 | struct ipcp_agg_lattice *aglat; | |||
4005 | ||||
4006 | if (!lat->bottom) | |||
4007 | { | |||
4008 | ipcp_value<tree> *val; | |||
4009 | for (val = lat->values; val; val = val->next) | |||
4010 | topo->constants.add_val (val); | |||
4011 | } | |||
4012 | ||||
4013 | if (!plats->aggs_bottom) | |||
4014 | for (aglat = plats->aggs; aglat; aglat = aglat->next) | |||
4015 | if (!aglat->bottom) | |||
4016 | { | |||
4017 | ipcp_value<tree> *val; | |||
4018 | for (val = aglat->values; val; val = val->next) | |||
4019 | topo->constants.add_val (val); | |||
4020 | } | |||
4021 | ||||
4022 | ipcp_lattice<ipa_polymorphic_call_context> *ctxlat = &plats->ctxlat; | |||
4023 | if (!ctxlat->bottom) | |||
4024 | { | |||
4025 | ipcp_value<ipa_polymorphic_call_context> *ctxval; | |||
4026 | for (ctxval = ctxlat->values; ctxval; ctxval = ctxval->next) | |||
4027 | topo->contexts.add_val (ctxval); | |||
4028 | } | |||
4029 | } | |||
4030 | } | |||
4031 | ||||
4032 | /* One pass of constants propagation along the call graph edges, from callers | |||
4033 | to callees (requires topological ordering in TOPO), iterate over strongly | |||
4034 | connected components. */ | |||
4035 | ||||
4036 | static void | |||
4037 | propagate_constants_topo (class ipa_topo_info *topo) | |||
4038 | { | |||
4039 | int i; | |||
4040 | ||||
4041 | for (i = topo->nnodes - 1; i >= 0; i--) | |||
4042 | { | |||
4043 | unsigned j; | |||
4044 | struct cgraph_node *v, *node = topo->order[i]; | |||
4045 | vec<cgraph_node *> cycle_nodes = ipa_get_nodes_in_cycle (node); | |||
4046 | ||||
4047 | /* First, iteratively propagate within the strongly connected component | |||
4048 | until all lattices stabilize. */ | |||
4049 | FOR_EACH_VEC_ELT (cycle_nodes, j, v)for (j = 0; (cycle_nodes).iterate ((j), &(v)); ++(j)) | |||
4050 | if (v->has_gimple_body_p ()) | |||
4051 | { | |||
4052 | if (opt_for_fn (v->decl, flag_ipa_cp)(opts_for_fn (v->decl)->x_flag_ipa_cp) | |||
4053 | && opt_for_fn (v->decl, optimize)(opts_for_fn (v->decl)->x_optimize)) | |||
4054 | push_node_to_stack (topo, v); | |||
4055 | /* When V is not optimized, we can not push it to stack, but | |||
4056 | still we need to set all its callees lattices to bottom. */ | |||
4057 | else | |||
4058 | { | |||
4059 | for (cgraph_edge *cs = v->callees; cs; cs = cs->next_callee) | |||
4060 | propagate_constants_across_call (cs); | |||
4061 | } | |||
4062 | } | |||
4063 | ||||
4064 | v = pop_node_from_stack (topo); | |||
4065 | while (v) | |||
4066 | { | |||
4067 | struct cgraph_edge *cs; | |||
4068 | class ipa_node_params *info = NULLnullptr; | |||
4069 | bool self_scc = true; | |||
4070 | ||||
4071 | for (cs = v->callees; cs; cs = cs->next_callee) | |||
4072 | if (ipa_edge_within_scc (cs)) | |||
4073 | { | |||
4074 | cgraph_node *callee = cs->callee->function_symbol (); | |||
4075 | ||||
4076 | if (v != callee) | |||
4077 | self_scc = false; | |||
4078 | ||||
4079 | if (!info) | |||
4080 | { | |||
4081 | info = ipa_node_params_sum->get (v); | |||
4082 | info->node_within_scc = true; | |||
4083 | } | |||
4084 | ||||
4085 | if (propagate_constants_across_call (cs)) | |||
4086 | push_node_to_stack (topo, callee); | |||
4087 | } | |||
4088 | ||||
4089 | if (info) | |||
4090 | info->node_is_self_scc = self_scc; | |||
4091 | ||||
4092 | v = pop_node_from_stack (topo); | |||
4093 | } | |||
4094 | ||||
4095 | /* Afterwards, propagate along edges leading out of the SCC, calculates | |||
4096 | the local effects of the discovered constants and all valid values to | |||
4097 | their topological sort. */ | |||
4098 | FOR_EACH_VEC_ELT (cycle_nodes, j, v)for (j = 0; (cycle_nodes).iterate ((j), &(v)); ++(j)) | |||
4099 | if (v->has_gimple_body_p () | |||
4100 | && opt_for_fn (v->decl, flag_ipa_cp)(opts_for_fn (v->decl)->x_flag_ipa_cp) | |||
4101 | && opt_for_fn (v->decl, optimize)(opts_for_fn (v->decl)->x_optimize)) | |||
4102 | { | |||
4103 | struct cgraph_edge *cs; | |||
4104 | ||||
4105 | estimate_local_effects (v); | |||
4106 | add_all_node_vals_to_toposort (v, topo); | |||
4107 | for (cs = v->callees; cs; cs = cs->next_callee) | |||
4108 | if (!ipa_edge_within_scc (cs)) | |||
4109 | propagate_constants_across_call (cs); | |||
4110 | } | |||
4111 | cycle_nodes.release (); | |||
4112 | } | |||
4113 | } | |||
4114 | ||||
4115 | /* Propagate the estimated effects of individual values along the topological | |||
4116 | from the dependent values to those they depend on. */ | |||
4117 | ||||
4118 | template <typename valtype> | |||
4119 | void | |||
4120 | value_topo_info<valtype>::propagate_effects () | |||
4121 | { | |||
4122 | ipcp_value<valtype> *base; | |||
4123 | hash_set<ipcp_value<valtype> *> processed_srcvals; | |||
4124 | ||||
4125 | for (base = values_topo; base; base = base->topo_next) | |||
4126 | { | |||
4127 | ipcp_value_source<valtype> *src; | |||
4128 | ipcp_value<valtype> *val; | |||
4129 | sreal time = 0; | |||
4130 | HOST_WIDE_INTlong size = 0; | |||
4131 | ||||
4132 | for (val = base; val; val = val->scc_next) | |||
4133 | { | |||
4134 | time = time + val->local_time_benefit + val->prop_time_benefit; | |||
4135 | size = size + val->local_size_cost + val->prop_size_cost; | |||
4136 | } | |||
4137 | ||||
4138 | for (val = base; val; val = val->scc_next) | |||
4139 | { | |||
4140 | processed_srcvals.empty (); | |||
4141 | for (src = val->sources; src; src = src->next) | |||
4142 | if (src->val | |||
4143 | && src->cs->maybe_hot_p ()) | |||
4144 | { | |||
4145 | if (!processed_srcvals.add (src->val)) | |||
4146 | { | |||
4147 | HOST_WIDE_INTlong prop_size = size + src->val->prop_size_cost; | |||
4148 | if (prop_size < INT_MAX2147483647) | |||
4149 | src->val->prop_size_cost = prop_size; | |||
4150 | else | |||
4151 | continue; | |||
4152 | } | |||
4153 | ||||
4154 | int special_factor = 1; | |||
4155 | if (val->same_scc (src->val)) | |||
4156 | special_factor | |||
4157 | = opt_for_fn(src->cs->caller->decl,(opts_for_fn (src->cs->caller->decl)->x_param_ipa_cp_recursive_freq_factor ) | |||
4158 | param_ipa_cp_recursive_freq_factor)(opts_for_fn (src->cs->caller->decl)->x_param_ipa_cp_recursive_freq_factor ); | |||
4159 | else if (val->self_recursion_generated_p () | |||
4160 | && (src->cs->callee->function_symbol () | |||
4161 | == src->cs->caller)) | |||
4162 | { | |||
4163 | int max_recur_gen_depth | |||
4164 | = opt_for_fn(src->cs->caller->decl,(opts_for_fn (src->cs->caller->decl)->x_param_ipa_cp_max_recursive_depth ) | |||
4165 | param_ipa_cp_max_recursive_depth)(opts_for_fn (src->cs->caller->decl)->x_param_ipa_cp_max_recursive_depth ); | |||
4166 | special_factor = max_recur_gen_depth | |||
4167 | - val->self_recursion_generated_level + 1; | |||
4168 | } | |||
4169 | ||||
4170 | src->val->prop_time_benefit | |||
4171 | += time * special_factor * src->cs->sreal_frequency (); | |||
4172 | } | |||
4173 | ||||
4174 | if (size < INT_MAX2147483647) | |||
4175 | { | |||
4176 | val->prop_time_benefit = time; | |||
4177 | val->prop_size_cost = size; | |||
4178 | } | |||
4179 | else | |||
4180 | { | |||
4181 | val->prop_time_benefit = 0; | |||
4182 | val->prop_size_cost = 0; | |||
4183 | } | |||
4184 | } | |||
4185 | } | |||
4186 | } | |||
4187 | ||||
4188 | /* Callback for qsort to sort counts of all edges. */ | |||
4189 | ||||
4190 | static int | |||
4191 | compare_edge_profile_counts (const void *a, const void *b) | |||
4192 | { | |||
4193 | const profile_count *cnt1 = (const profile_count *) a; | |||
4194 | const profile_count *cnt2 = (const profile_count *) b; | |||
4195 | ||||
4196 | if (*cnt1 < *cnt2) | |||
4197 | return 1; | |||
4198 | if (*cnt1 > *cnt2) | |||
4199 | return -1; | |||
4200 | return 0; | |||
4201 | } | |||
4202 | ||||
4203 | ||||
4204 | /* Propagate constants, polymorphic contexts and their effects from the | |||
4205 | summaries interprocedurally. */ | |||
4206 | ||||
4207 | static void | |||
4208 | ipcp_propagate_stage (class ipa_topo_info *topo) | |||
4209 | { | |||
4210 | struct cgraph_node *node; | |||
4211 | ||||
4212 | if (dump_file) | |||
4213 | fprintf (dump_file, "\n Propagating constants:\n\n"); | |||
4214 | ||||
4215 | base_count = profile_count::uninitialized (); | |||
4216 | ||||
4217 | bool compute_count_base = false; | |||
4218 | unsigned base_count_pos_percent = 0; | |||
4219 | FOR_EACH_DEFINED_FUNCTION (node)for ((node) = symtab->first_defined_function (); (node); ( node) = symtab->next_defined_function ((node))) | |||
4220 | { | |||
4221 | if (node->has_gimple_body_p () | |||
4222 | && opt_for_fn (node->decl, flag_ipa_cp)(opts_for_fn (node->decl)->x_flag_ipa_cp) | |||
4223 | && opt_for_fn (node->decl, optimize)(opts_for_fn (node->decl)->x_optimize)) | |||
4224 | { | |||
4225 | ipa_node_params *info = ipa_node_params_sum->get (node); | |||
4226 | determine_versionability (node, info); | |||
4227 | ||||
4228 | unsigned nlattices = ipa_get_param_count (info); | |||
4229 | void *chunk = XCNEWVEC (class ipcp_param_lattices, nlattices)((class ipcp_param_lattices *) xcalloc ((nlattices), sizeof ( class ipcp_param_lattices))); | |||
4230 | info->lattices = new (chunk) ipcp_param_lattices[nlattices]; | |||
4231 | initialize_node_lattices (node); | |||
4232 | } | |||
4233 | ipa_size_summary *s = ipa_size_summaries->get (node); | |||
4234 | if (node->definition && !node->alias && s != NULLnullptr) | |||
4235 | overall_size += s->self_size; | |||
4236 | if (node->count.ipa ().initialized_p ()) | |||
4237 | { | |||
4238 | compute_count_base = true; | |||
4239 | unsigned pos_percent = opt_for_fn (node->decl,(opts_for_fn (node->decl)->x_param_ipa_cp_profile_count_base ) | |||
4240 | param_ipa_cp_profile_count_base)(opts_for_fn (node->decl)->x_param_ipa_cp_profile_count_base ); | |||
4241 | base_count_pos_percent = MAX (base_count_pos_percent, pos_percent)((base_count_pos_percent) > (pos_percent) ? (base_count_pos_percent ) : (pos_percent)); | |||
4242 | } | |||
4243 | } | |||
4244 | ||||
4245 | if (compute_count_base) | |||
4246 | { | |||
4247 | auto_vec<profile_count> all_edge_counts; | |||
4248 | all_edge_counts.reserve_exact (symtab->edges_count); | |||
4249 | FOR_EACH_DEFINED_FUNCTION (node)for ((node) = symtab->first_defined_function (); (node); ( node) = symtab->next_defined_function ((node))) | |||
4250 | for (cgraph_edge *cs = node->callees; cs; cs = cs->next_callee) | |||
4251 | { | |||
4252 | profile_count count = cs->count.ipa (); | |||
4253 | if (!count.nonzero_p ()) | |||
4254 | continue; | |||
4255 | ||||
4256 | enum availability avail; | |||
4257 | cgraph_node *tgt | |||
4258 | = cs->callee->function_or_virtual_thunk_symbol (&avail); | |||
4259 | ipa_node_params *info = ipa_node_params_sum->get (tgt); | |||
4260 | if (info && info->versionable) | |||
4261 | all_edge_counts.quick_push (count); | |||
4262 | } | |||
4263 | ||||
4264 | if (!all_edge_counts.is_empty ()) | |||
4265 | { | |||
4266 | gcc_assert (base_count_pos_percent <= 100)((void)(!(base_count_pos_percent <= 100) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-cp.cc" , 4266, __FUNCTION__), 0 : 0)); | |||
4267 | all_edge_counts.qsort (compare_edge_profile_counts)qsort (compare_edge_profile_counts); | |||
4268 | ||||
4269 | unsigned base_count_pos | |||
4270 | = ((all_edge_counts.length () * (base_count_pos_percent)) / 100); | |||
4271 | base_count = all_edge_counts[base_count_pos]; | |||
4272 | ||||
4273 | if (dump_file) | |||
4274 | { | |||
4275 | fprintf (dump_file, "\nSelected base_count from %u edges at " | |||
4276 | "position %u, arriving at: ", all_edge_counts.length (), | |||
4277 | base_count_pos); | |||
4278 | base_count.dump (dump_file); | |||
4279 | fprintf (dump_file, "\n"); | |||
4280 | } | |||
4281 | } | |||
4282 | else if (dump_file) | |||
4283 | fprintf (dump_file, "\nNo candidates with non-zero call count found, " | |||
4284 | "continuing as if without profile feedback.\n"); | |||
4285 | } | |||
4286 | ||||
4287 | orig_overall_size = overall_size; | |||
4288 | ||||
4289 | if (dump_file) | |||
4290 | fprintf (dump_file, "\noverall_size: %li\n", overall_size); | |||
4291 | ||||
4292 | propagate_constants_topo (topo); | |||
4293 | if (flag_checkingglobal_options.x_flag_checking) | |||
4294 | ipcp_verify_propagated_values (); | |||
4295 | topo->constants.propagate_effects (); | |||
4296 | topo->contexts.propagate_effects (); | |||
4297 | ||||
4298 | if (dump_file) | |||
4299 | { | |||
4300 | fprintf (dump_file, "\nIPA lattices after all propagation:\n"); | |||
4301 | print_all_lattices (dump_file, (dump_flags & TDF_DETAILS), true); | |||
4302 | } | |||
4303 | } | |||
4304 | ||||
4305 | /* Discover newly direct outgoing edges from NODE which is a new clone with | |||
4306 | known KNOWN_CSTS and make them direct. */ | |||
4307 | ||||
4308 | static void | |||
4309 | ipcp_discover_new_direct_edges (struct cgraph_node *node, | |||
4310 | vec<tree> known_csts, | |||
4311 | vec<ipa_polymorphic_call_context> | |||
4312 | known_contexts, | |||
4313 | vec<ipa_argagg_value, va_gc> *aggvals) | |||
4314 | { | |||
4315 | struct cgraph_edge *ie, *next_ie; | |||
4316 | bool found = false; | |||
4317 | ||||
4318 | for (ie = node->indirect_calls; ie; ie = next_ie) | |||
4319 | { | |||
4320 | tree target; | |||
4321 | bool speculative; | |||
4322 | ||||
4323 | next_ie = ie->next_callee; | |||
4324 | ipa_argagg_value_list avs (aggvals); | |||
4325 | target = ipa_get_indirect_edge_target_1 (ie, known_csts, known_contexts, | |||
4326 | avs, &speculative); | |||
4327 | if (target) | |||
4328 | { | |||
4329 | bool agg_contents = ie->indirect_info->agg_contents; | |||
4330 | bool polymorphic = ie->indirect_info->polymorphic; | |||
4331 | int param_index = ie->indirect_info->param_index; | |||
4332 | struct cgraph_edge *cs = ipa_make_edge_direct_to_target (ie, target, | |||
4333 | speculative); | |||
4334 | found = true; | |||
4335 | ||||
4336 | if (cs && !agg_contents && !polymorphic) | |||
4337 | { | |||
4338 | ipa_node_params *info = ipa_node_params_sum->get (node); | |||
4339 | int c = ipa_get_controlled_uses (info, param_index); | |||
4340 | if (c != IPA_UNDESCRIBED_USE-1 | |||
4341 | && !ipa_get_param_load_dereferenced (info, param_index)) | |||
4342 | { | |||
4343 | struct ipa_ref *to_del; | |||
4344 | ||||
4345 | c--; | |||
4346 | ipa_set_controlled_uses (info, param_index, c); | |||
4347 | if (dump_file && (dump_flags & TDF_DETAILS)) | |||
4348 | fprintf (dump_file, " controlled uses count of param " | |||
4349 | "%i bumped down to %i\n", param_index, c); | |||
4350 | if (c == 0 | |||
4351 | && (to_del = node->find_reference (cs->callee, NULLnullptr, 0))) | |||
4352 | { | |||
4353 | if (dump_file && (dump_flags & TDF_DETAILS)) | |||
4354 | fprintf (dump_file, " and even removing its " | |||
4355 | "cloning-created reference\n"); | |||
4356 | to_del->remove_reference (); | |||
4357 | } | |||
4358 | } | |||
4359 | } | |||
4360 | } | |||
4361 | } | |||
4362 | /* Turning calls to direct calls will improve overall summary. */ | |||
4363 | if (found) | |||
4364 | ipa_update_overall_fn_summary (node); | |||
4365 | } | |||
4366 | ||||
4367 | class edge_clone_summary; | |||
4368 | static call_summary <edge_clone_summary *> *edge_clone_summaries = NULLnullptr; | |||
4369 | ||||
4370 | /* Edge clone summary. */ | |||
4371 | ||||
4372 | class edge_clone_summary | |||
4373 | { | |||
4374 | public: | |||
4375 | /* Default constructor. */ | |||
4376 | edge_clone_summary (): prev_clone (NULLnullptr), next_clone (NULLnullptr) {} | |||
4377 | ||||
4378 | /* Default destructor. */ | |||
4379 | ~edge_clone_summary () | |||
4380 | { | |||
4381 | if (prev_clone) | |||
4382 | edge_clone_summaries->get (prev_clone)->next_clone = next_clone; | |||
4383 | if (next_clone) | |||
4384 | edge_clone_summaries->get (next_clone)->prev_clone = prev_clone; | |||
4385 | } | |||
4386 | ||||
4387 | cgraph_edge *prev_clone; | |||
4388 | cgraph_edge *next_clone; | |||
4389 | }; | |||
4390 | ||||
4391 | class edge_clone_summary_t: | |||
4392 | public call_summary <edge_clone_summary *> | |||
4393 | { | |||
4394 | public: | |||
4395 | edge_clone_summary_t (symbol_table *symtab): | |||
4396 | call_summary <edge_clone_summary *> (symtab) | |||
4397 | { | |||
4398 | m_initialize_when_cloning = true; | |||
4399 | } | |||
4400 | ||||
4401 | void duplicate (cgraph_edge *src_edge, cgraph_edge *dst_edge, | |||
4402 | edge_clone_summary *src_data, | |||
4403 | edge_clone_summary *dst_data) final override; | |||
4404 | }; | |||
4405 | ||||
4406 | /* Edge duplication hook. */ | |||
4407 | ||||
4408 | void | |||
4409 | edge_clone_summary_t::duplicate (cgraph_edge *src_edge, cgraph_edge *dst_edge, | |||
4410 | edge_clone_summary *src_data, | |||
4411 | edge_clone_summary *dst_data) | |||
4412 | { | |||
4413 | if (src_data->next_clone) | |||
4414 | edge_clone_summaries->get (src_data->next_clone)->prev_clone = dst_edge; | |||
4415 | dst_data->prev_clone = src_edge; | |||
4416 | dst_data->next_clone = src_data->next_clone; | |||
4417 | src_data->next_clone = dst_edge; | |||
4418 | } | |||
4419 | ||||
4420 | /* Return true is CS calls DEST or its clone for all contexts. When | |||
4421 | ALLOW_RECURSION_TO_CLONE is false, also return false for self-recursive | |||
4422 | edges from/to an all-context clone. */ | |||
4423 | ||||
4424 | static bool | |||
4425 | calls_same_node_or_its_all_contexts_clone_p (cgraph_edge *cs, cgraph_node *dest, | |||
4426 | bool allow_recursion_to_clone) | |||
4427 | { | |||
4428 | enum availability availability; | |||
4429 | cgraph_node *callee = cs->callee->function_symbol (&availability); | |||
4430 | ||||
4431 | if (availability <= AVAIL_INTERPOSABLE) | |||
4432 | return false; | |||
4433 | if (callee == dest) | |||
4434 | return true; | |||
4435 | if (!allow_recursion_to_clone && cs->caller == callee) | |||
4436 | return false; | |||
4437 | ||||
4438 | ipa_node_params *info = ipa_node_params_sum->get (callee); | |||
4439 | return info->is_all_contexts_clone && info->ipcp_orig_node == dest; | |||
4440 | } | |||
4441 | ||||
4442 | /* Return true if edge CS does bring about the value described by SRC to | |||
4443 | DEST_VAL of node DEST or its clone for all contexts. */ | |||
4444 | ||||
4445 | static bool | |||
4446 | cgraph_edge_brings_value_p (cgraph_edge *cs, ipcp_value_source<tree> *src, | |||
4447 | cgraph_node *dest, ipcp_value<tree> *dest_val) | |||
4448 | { | |||
4449 | ipa_node_params *caller_info = ipa_node_params_sum->get (cs->caller); | |||
4450 | ||||
4451 | if (!calls_same_node_or_its_all_contexts_clone_p (cs, dest, !src->val) | |||
4452 | || caller_info->node_dead) | |||
4453 | return false; | |||
4454 | ||||
4455 | if (!src->val) | |||
4456 | return true; | |||
4457 | ||||
4458 | if (caller_info->ipcp_orig_node) | |||
4459 | { | |||
4460 | tree t = NULL_TREE(tree) nullptr; | |||
4461 | if (src->offset == -1) | |||
4462 | t = caller_info->known_csts[src->index]; | |||
4463 | else if (ipcp_transformation *ts | |||
4464 | = ipcp_get_transformation_summary (cs->caller)) | |||
4465 | { | |||
4466 | ipa_argagg_value_list avl (ts); | |||
4467 | t = avl.get_value (src->index, src->offset / BITS_PER_UNIT(8)); | |||
4468 | } | |||
4469 | return (t != NULL_TREE(tree) nullptr | |||
4470 | && values_equal_for_ipcp_p (src->val->value, t)); | |||
4471 | } | |||
4472 | else | |||
4473 | { | |||
4474 | if (src->val == dest_val) | |||
4475 | return true; | |||
4476 | ||||
4477 | struct ipcp_agg_lattice *aglat; | |||
4478 | class ipcp_param_lattices *plats = ipa_get_parm_lattices (caller_info, | |||
4479 | src->index); | |||
4480 | if (src->offset == -1) | |||
4481 | return (plats->itself.is_single_const () | |||
4482 | && values_equal_for_ipcp_p (src->val->value, | |||
4483 | plats->itself.values->value)); | |||
4484 | else | |||
4485 | { | |||
4486 | if (plats->aggs_bottom || plats->aggs_contain_variable) | |||
4487 | return false; | |||
4488 | for (aglat = plats->aggs; aglat; aglat = aglat->next) | |||
4489 | if (aglat->offset == src->offset) | |||
4490 | return (aglat->is_single_const () | |||
4491 | && values_equal_for_ipcp_p (src->val->value, | |||
4492 | aglat->values->value)); | |||
4493 | } | |||
4494 | return false; | |||
4495 | } | |||
4496 | } | |||
4497 | ||||
4498 | /* Return true if edge CS does bring about the value described by SRC to | |||
4499 | DST_VAL of node DEST or its clone for all contexts. */ | |||
4500 | ||||
4501 | static bool | |||
4502 | cgraph_edge_brings_value_p (cgraph_edge *cs, | |||
4503 | ipcp_value_source<ipa_polymorphic_call_context> *src, | |||
4504 | cgraph_node *dest, | |||
4505 | ipcp_value<ipa_polymorphic_call_context> *) | |||
4506 | { | |||
4507 | ipa_node_params *caller_info = ipa_node_params_sum->get (cs->caller); | |||
4508 | ||||
4509 | if (!calls_same_node_or_its_all_contexts_clone_p (cs, dest, true) | |||
4510 | || caller_info->node_dead) | |||
4511 | return false; | |||
4512 | if (!src->val) | |||
4513 | return true; | |||
4514 | ||||
4515 | if (caller_info->ipcp_orig_node) | |||
4516 | return (caller_info->known_contexts.length () > (unsigned) src->index) | |||
4517 | && values_equal_for_ipcp_p (src->val->value, | |||
4518 | caller_info->known_contexts[src->index]); | |||
4519 | ||||
4520 | class ipcp_param_lattices *plats = ipa_get_parm_lattices (caller_info, | |||
4521 | src->index); | |||
4522 | return plats->ctxlat.is_single_const () | |||
4523 | && values_equal_for_ipcp_p (src->val->value, | |||
4524 | plats->ctxlat.values->value); | |||
4525 | } | |||
4526 | ||||
4527 | /* Get the next clone in the linked list of clones of an edge. */ | |||
4528 | ||||
4529 | static inline struct cgraph_edge * | |||
4530 | get_next_cgraph_edge_clone (struct cgraph_edge *cs) | |||
4531 | { | |||
4532 | edge_clone_summary *s = edge_clone_summaries->get (cs); | |||
4533 | return s != NULLnullptr ? s->next_clone : NULLnullptr; | |||
4534 | } | |||
4535 | ||||
4536 | /* Given VAL that is intended for DEST, iterate over all its sources and if any | |||
4537 | of them is viable and hot, return true. In that case, for those that still | |||
4538 | hold, add their edge frequency and their number and cumulative profile | |||
4539 | counts of self-ecursive and other edges into *FREQUENCY, *CALLER_COUNT, | |||
4540 | REC_COUNT_SUM and NONREC_COUNT_SUM respectively. */ | |||
4541 | ||||
4542 | template <typename valtype> | |||
4543 | static bool | |||
4544 | get_info_about_necessary_edges (ipcp_value<valtype> *val, cgraph_node *dest, | |||
4545 | sreal *freq_sum, int *caller_count, | |||
4546 | profile_count *rec_count_sum, | |||
4547 | profile_count *nonrec_count_sum) | |||
4548 | { | |||
4549 | ipcp_value_source<valtype> *src; | |||
4550 | sreal freq = 0; | |||
4551 | int count = 0; | |||
4552 | profile_count rec_cnt = profile_count::zero (); | |||
4553 | profile_count nonrec_cnt = profile_count::zero (); | |||
4554 | bool hot = false; | |||
4555 | bool non_self_recursive = false; | |||
4556 | ||||
4557 | for (src = val->sources; src; src = src->next) | |||
4558 | { | |||
4559 | struct cgraph_edge *cs = src->cs; | |||
4560 | while (cs) | |||
4561 | { | |||
4562 | if (cgraph_edge_brings_value_p (cs, src, dest, val)) | |||
4563 | { | |||
4564 | count++; | |||
4565 | freq += cs->sreal_frequency (); | |||
4566 | hot |= cs->maybe_hot_p (); | |||
4567 | if (cs->caller != dest) | |||
4568 | { | |||
4569 | non_self_recursive = true; | |||
4570 | if (cs->count.ipa ().initialized_p ()) | |||
4571 | rec_cnt += cs->count.ipa (); | |||
4572 | } | |||
4573 | else if (cs->count.ipa ().initialized_p ()) | |||
4574 | nonrec_cnt += cs->count.ipa (); | |||
4575 | } | |||
4576 | cs = get_next_cgraph_edge_clone (cs); | |||
4577 | } | |||
4578 | } | |||
4579 | ||||
4580 | /* If the only edges bringing a value are self-recursive ones, do not bother | |||
4581 | evaluating it. */ | |||
4582 | if (!non_self_recursive) | |||
4583 | return false; | |||
4584 | ||||
4585 | *freq_sum = freq; | |||
4586 | *caller_count = count; | |||
4587 | *rec_count_sum = rec_cnt; | |||
4588 | *nonrec_count_sum = nonrec_cnt; | |||
4589 | ||||
4590 | if (!hot && ipa_node_params_sum->get (dest)->node_within_scc) | |||
4591 | { | |||
4592 | struct cgraph_edge *cs; | |||
4593 | ||||
4594 | /* Cold non-SCC source edge could trigger hot recursive execution of | |||
4595 | function. Consider the case as hot and rely on following cost model | |||
4596 | computation to further select right one. */ | |||
4597 | for (cs = dest->callers; cs; cs = cs->next_caller) | |||
4598 | if (cs->caller == dest && cs->maybe_hot_p ()) | |||
4599 | return true; | |||
4600 | } | |||
4601 | ||||
4602 | return hot; | |||
4603 | } | |||
4604 | ||||
4605 | /* Given a NODE, and a set of its CALLERS, try to adjust order of the callers | |||
4606 | to let a non-self-recursive caller be the first element. Thus, we can | |||
4607 | simplify intersecting operations on values that arrive from all of these | |||
4608 | callers, especially when there exists self-recursive call. Return true if | |||
4609 | this kind of adjustment is possible. */ | |||
4610 | ||||
4611 | static bool | |||
4612 | adjust_callers_for_value_intersection (vec<cgraph_edge *> &callers, | |||
4613 | cgraph_node *node) | |||
4614 | { | |||
4615 | for (unsigned i = 0; i < callers.length (); i++) | |||
4616 | { | |||
4617 | cgraph_edge *cs = callers[i]; | |||
4618 | ||||
4619 | if (cs->caller != node) | |||
4620 | { | |||
4621 | if (i > 0) | |||
4622 | { | |||
4623 | callers[i] = callers[0]; | |||
4624 | callers[0] = cs; | |||
4625 | } | |||
4626 | return true; | |||
4627 | } | |||
4628 | } | |||
4629 | return false; | |||
4630 | } | |||
4631 | ||||
4632 | /* Return a vector of incoming edges that do bring value VAL to node DEST. It | |||
4633 | is assumed their number is known and equal to CALLER_COUNT. */ | |||
4634 | ||||
4635 | template <typename valtype> | |||
4636 | static vec<cgraph_edge *> | |||
4637 | gather_edges_for_value (ipcp_value<valtype> *val, cgraph_node *dest, | |||
4638 | int caller_count) | |||
4639 | { | |||
4640 | ipcp_value_source<valtype> *src; | |||
4641 | vec<cgraph_edge *> ret; | |||
4642 | ||||
4643 | ret.create (caller_count); | |||
4644 | for (src = val->sources; src; src = src->next) | |||
4645 | { | |||
4646 | struct cgraph_edge *cs = src->cs; | |||
4647 | while (cs) | |||
4648 | { | |||
4649 | if (cgraph_edge_brings_value_p (cs, src, dest, val)) | |||
4650 | ret.quick_push (cs); | |||
4651 | cs = get_next_cgraph_edge_clone (cs); | |||
4652 | } | |||
4653 | } | |||
4654 | ||||
4655 | if (caller_count > 1) | |||
4656 | adjust_callers_for_value_intersection (ret, dest); | |||
4657 | ||||
4658 | return ret; | |||
4659 | } | |||
4660 | ||||
4661 | /* Construct a replacement map for a know VALUE for a formal parameter PARAM. | |||
4662 | Return it or NULL if for some reason it cannot be created. FORCE_LOAD_REF | |||
4663 | should be set to true when the reference created for the constant should be | |||
4664 | a load one and not an address one because the corresponding parameter p is | |||
4665 | only used as *p. */ | |||
4666 | ||||
4667 | static struct ipa_replace_map * | |||
4668 | get_replacement_map (class ipa_node_params *info, tree value, int parm_num, | |||
4669 | bool force_load_ref) | |||
4670 | { | |||
4671 | struct ipa_replace_map *replace_map; | |||
4672 | ||||
4673 | replace_map = ggc_alloc<ipa_replace_map> (); | |||
4674 | if (dump_file) | |||
4675 | { | |||
4676 | fprintf (dump_file, " replacing "); | |||
4677 | ipa_dump_param (dump_file, info, parm_num); | |||
4678 | ||||
4679 | fprintf (dump_file, " with const "); | |||
4680 | print_generic_expr (dump_file, value); | |||
4681 | ||||
4682 | if (force_load_ref) | |||
4683 | fprintf (dump_file, " - forcing load reference\n"); | |||
4684 | else | |||
4685 | fprintf (dump_file, "\n"); | |||
4686 | } | |||
4687 | replace_map->parm_num = parm_num; | |||
4688 | replace_map->new_tree = value; | |||
4689 | replace_map->force_load_ref = force_load_ref; | |||
4690 | return replace_map; | |||
4691 | } | |||
4692 | ||||
4693 | /* Dump new profiling counts of NODE. SPEC is true when NODE is a specialzied | |||
4694 | one, otherwise it will be referred to as the original node. */ | |||
4695 | ||||
4696 | static void | |||
4697 | dump_profile_updates (cgraph_node *node, bool spec) | |||
4698 | { | |||
4699 | if (spec) | |||
4700 | fprintf (dump_file, " setting count of the specialized node %s to ", | |||
4701 | node->dump_name ()); | |||
4702 | else | |||
4703 | fprintf (dump_file, " setting count of the original node %s to ", | |||
4704 | node->dump_name ()); | |||
4705 | ||||
4706 | node->count.dump (dump_file); | |||
4707 | fprintf (dump_file, "\n"); | |||
4708 | for (cgraph_edge *cs = node->callees; cs; cs = cs->next_callee) | |||
4709 | { | |||
4710 | fprintf (dump_file, " edge to %s has count ", | |||
4711 | cs->callee->dump_name ()); | |||
4712 | cs->count.dump (dump_file); | |||
4713 | fprintf (dump_file, "\n"); | |||
4714 | } | |||
4715 | } | |||
4716 | ||||
4717 | /* With partial train run we do not want to assume that original's count is | |||
4718 | zero whenever we redurect all executed edges to clone. Simply drop profile | |||
4719 | to local one in this case. In eany case, return the new value. ORIG_NODE | |||
4720 | is the original node and its count has not been updaed yet. */ | |||
4721 | ||||
4722 | profile_count | |||
4723 | lenient_count_portion_handling (profile_count remainder, cgraph_node *orig_node) | |||
4724 | { | |||
4725 | if (remainder.ipa_p () && !remainder.ipa ().nonzero_p () | |||
4726 | && orig_node->count.ipa_p () && orig_node->count.ipa ().nonzero_p () | |||
4727 | && opt_for_fn (orig_node->decl, flag_profile_partial_training)(opts_for_fn (orig_node->decl)->x_flag_profile_partial_training )) | |||
4728 | remainder = remainder.guessed_local (); | |||
4729 | ||||
4730 | return remainder; | |||
4731 | } | |||
4732 | ||||
4733 | /* Structure to sum counts coming from nodes other than the original node and | |||
4734 | its clones. */ | |||
4735 | ||||
4736 | struct gather_other_count_struct | |||
4737 | { | |||
4738 | cgraph_node *orig; | |||
4739 | profile_count other_count; | |||
4740 | }; | |||
4741 | ||||
4742 | /* Worker callback of call_for_symbol_thunks_and_aliases summing the number of | |||
4743 | counts that come from non-self-recursive calls.. */ | |||
4744 | ||||
4745 | static bool | |||
4746 | gather_count_of_non_rec_edges (cgraph_node *node, void *data) | |||
4747 | { | |||
4748 | gather_other_count_struct *desc = (gather_other_count_struct *) data; | |||
4749 | for (cgraph_edge *cs = node->callers; cs; cs = cs->next_caller) | |||
4750 | if (cs->caller != desc->orig && cs->caller->clone_of != desc->orig) | |||
4751 | desc->other_count += cs->count.ipa (); | |||
4752 | return false; | |||
4753 | } | |||
4754 | ||||
4755 | /* Structure to help analyze if we need to boost counts of some clones of some | |||
4756 | non-recursive edges to match the new callee count. */ | |||
4757 | ||||
4758 | struct desc_incoming_count_struct | |||
4759 | { | |||
4760 | cgraph_node *orig; | |||
4761 | hash_set <cgraph_edge *> *processed_edges; | |||
4762 | profile_count count; | |||
4763 | unsigned unproc_orig_rec_edges; | |||
4764 | }; | |||
4765 | ||||
4766 | /* Go over edges calling NODE and its thunks and gather information about | |||
4767 | incoming counts so that we know if we need to make any adjustments. */ | |||
4768 | ||||
4769 | static void | |||
4770 | analyze_clone_icoming_counts (cgraph_node *node, | |||
4771 | desc_incoming_count_struct *desc) | |||
4772 | { | |||
4773 | for (cgraph_edge *cs = node->callers; cs; cs = cs->next_caller) | |||
4774 | if (cs->caller->thunk) | |||
4775 | { | |||
4776 | analyze_clone_icoming_counts (cs->caller, desc); | |||
4777 | continue; | |||
4778 | } | |||
4779 | else | |||
4780 | { | |||
4781 | if (cs->count.initialized_p ()) | |||
4782 | desc->count += cs->count.ipa (); | |||
4783 | if (!desc->processed_edges->contains (cs) | |||
4784 | && cs->caller->clone_of == desc->orig) | |||
4785 | desc->unproc_orig_rec_edges++; | |||
4786 | } | |||
4787 | } | |||
4788 | ||||
4789 | /* If caller edge counts of a clone created for a self-recursive arithmetic | |||
4790 | jump function must be adjusted because it is coming from a the "seed" clone | |||
4791 | for the first value and so has been excessively scaled back as if it was not | |||
4792 | a recursive call, adjust it so that the incoming counts of NODE match its | |||
4793 | count. NODE is the node or its thunk. */ | |||
4794 | ||||
4795 | static void | |||
4796 | adjust_clone_incoming_counts (cgraph_node *node, | |||
4797 | desc_incoming_count_struct *desc) | |||
4798 | { | |||
4799 | for (cgraph_edge *cs = node->callers; cs; cs = cs->next_caller) | |||
4800 | if (cs->caller->thunk) | |||
4801 | { | |||
4802 | adjust_clone_incoming_counts (cs->caller, desc); | |||
4803 | profile_count sum = profile_count::zero (); | |||
4804 | for (cgraph_edge *e = cs->caller->callers; e; e = e->next_caller) | |||
4805 | if (e->count.initialized_p ()) | |||
4806 | sum += e->count.ipa (); | |||
4807 | cs->count = cs->count.combine_with_ipa_count (sum); | |||
4808 | } | |||
4809 | else if (!desc->processed_edges->contains (cs) | |||
4810 | && cs->caller->clone_of == desc->orig) | |||
4811 | { | |||
4812 | cs->count += desc->count; | |||
4813 | if (dump_file) | |||
4814 | { | |||
4815 | fprintf (dump_file, " Adjusted count of an incoming edge of " | |||
4816 | "a clone %s -> %s to ", cs->caller->dump_name (), | |||
4817 | cs->callee->dump_name ()); | |||
4818 | cs->count.dump (dump_file); | |||
4819 | fprintf (dump_file, "\n"); | |||
4820 | } | |||
4821 | } | |||
4822 | } | |||
4823 | ||||
4824 | /* When ORIG_NODE has been cloned for values which have been generated fora | |||
4825 | self-recursive call as a result of an arithmetic pass-through | |||
4826 | jump-functions, adjust its count together with counts of all such clones in | |||
4827 | SELF_GEN_CLONES which also at this point contains ORIG_NODE itself. | |||
4828 | ||||
4829 | The function sums the counts of the original node and all its clones that | |||
4830 | cannot be attributed to a specific clone because it comes from a | |||
4831 | non-recursive edge. This sum is then evenly divided between the clones and | |||
4832 | on top of that each one gets all the counts which can be attributed directly | |||
4833 | to it. */ | |||
4834 | ||||
4835 | static void | |||
4836 | update_counts_for_self_gen_clones (cgraph_node *orig_node, | |||
4837 | const vec<cgraph_node *> &self_gen_clones) | |||
4838 | { | |||
4839 | profile_count redist_sum = orig_node->count.ipa (); | |||
4840 | if (!(redist_sum > profile_count::zero ())) | |||
4841 | return; | |||
4842 | ||||
4843 | if (dump_file) | |||
4844 | fprintf (dump_file, " Updating profile of self recursive clone " | |||
4845 | "series\n"); | |||
4846 | ||||
4847 | gather_other_count_struct gocs; | |||
4848 | gocs.orig = orig_node; | |||
4849 | gocs.other_count = profile_count::zero (); | |||
4850 | ||||
4851 | auto_vec <profile_count, 8> other_edges_count; | |||
4852 | for (cgraph_node *n : self_gen_clones) | |||
4853 | { | |||
4854 | gocs.other_count = profile_count::zero (); | |||
4855 | n->call_for_symbol_thunks_and_aliases (gather_count_of_non_rec_edges, | |||
4856 | &gocs, false); | |||
4857 | other_edges_count.safe_push (gocs.other_count); | |||
4858 | redist_sum -= gocs.other_count; | |||
4859 | } | |||
4860 | ||||
4861 | hash_set<cgraph_edge *> processed_edges; | |||
4862 | unsigned i = 0; | |||
4863 | for (cgraph_node *n : self_gen_clones) | |||
4864 | { | |||
4865 | profile_count orig_count = n->count; | |||
4866 | profile_count new_count | |||
4867 | = (redist_sum / self_gen_clones.length () + other_edges_count[i]); | |||
4868 | new_count = lenient_count_portion_handling (new_count, orig_node); | |||
4869 | n->count = new_count; | |||
4870 | profile_count::adjust_for_ipa_scaling (&new_count, &orig_count); | |||
4871 | for (cgraph_edge *cs = n->callees; cs; cs = cs->next_callee) | |||
4872 | { | |||
4873 | cs->count = cs->count.apply_scale (new_count, orig_count); | |||
4874 | processed_edges.add (cs); | |||
4875 | } | |||
4876 | for (cgraph_edge *cs = n->indirect_calls; cs; cs = cs->next_callee) | |||
4877 | cs->count = cs->count.apply_scale (new_count, orig_count); | |||
4878 | ||||
4879 | i++; | |||
4880 | } | |||
4881 | ||||
4882 | /* There are still going to be edges to ORIG_NODE that have one or more | |||
4883 | clones coming from another node clone in SELF_GEN_CLONES and which we | |||
4884 | scaled by the same amount, which means that the total incoming sum of | |||
4885 | counts to ORIG_NODE will be too high, scale such edges back. */ | |||
4886 | for (cgraph_edge *cs = orig_node->callees; cs; cs = cs->next_callee) | |||
4887 | { | |||
4888 | if (cs->callee->ultimate_alias_target () == orig_node) | |||
4889 | { | |||
4890 | unsigned den = 0; | |||
4891 | for (cgraph_edge *e = cs; e; e = get_next_cgraph_edge_clone (e)) | |||
4892 | if (e->callee->ultimate_alias_target () == orig_node | |||
4893 | && processed_edges.contains (e)) | |||
4894 | den++; | |||
4895 | if (den > 0) | |||
4896 | for (cgraph_edge *e = cs; e; e = get_next_cgraph_edge_clone (e)) | |||
4897 | if (e->callee->ultimate_alias_target () == orig_node | |||
4898 | && processed_edges.contains (e)) | |||
4899 | e->count /= den; | |||
4900 | } | |||
4901 | } | |||
4902 | ||||
4903 | /* Edges from the seeds of the valus generated for arithmetic jump-functions | |||
4904 | along self-recursive edges are likely to have fairly low count and so | |||
4905 | edges from them to nodes in the self_gen_clones do not correspond to the | |||
4906 | artificially distributed count of the nodes, the total sum of incoming | |||
4907 | edges to some clones might be too low. Detect this situation and correct | |||
4908 | it. */ | |||
4909 | for (cgraph_node *n : self_gen_clones) | |||
4910 | { | |||
4911 | if (!(n->count.ipa () > profile_count::zero ())) | |||
4912 | continue; | |||
4913 | ||||
4914 | desc_incoming_count_struct desc; | |||
4915 | desc.orig = orig_node; | |||
4916 | desc.processed_edges = &processed_edges; | |||
4917 | desc.count = profile_count::zero (); | |||
4918 | desc.unproc_orig_rec_edges = 0; | |||
4919 | analyze_clone_icoming_counts (n, &desc); | |||
4920 | ||||
4921 | if (n->count.differs_from_p (desc.count)) | |||
4922 | { | |||
4923 | if (n->count > desc.count | |||
4924 | && desc.unproc_orig_rec_edges > 0) | |||
4925 | { | |||
4926 | desc.count = n->count - desc.count; | |||
4927 | desc.count = desc.count /= desc.unproc_orig_rec_edges; | |||
4928 | adjust_clone_incoming_counts (n, &desc); | |||
4929 | } | |||
4930 | else if (dump_file) | |||
4931 | fprintf (dump_file, | |||
4932 | " Unable to fix up incoming counts for %s.\n", | |||
4933 | n->dump_name ()); | |||
4934 | } | |||
4935 | } | |||
4936 | ||||
4937 | if (dump_file) | |||
4938 | for (cgraph_node *n : self_gen_clones) | |||
4939 | dump_profile_updates (n, n != orig_node); | |||
4940 | return; | |||
4941 | } | |||
4942 | ||||
4943 | /* After a specialized NEW_NODE version of ORIG_NODE has been created, update | |||
4944 | their profile information to reflect this. This function should not be used | |||
4945 | for clones generated for arithmetic pass-through jump functions on a | |||
4946 | self-recursive call graph edge, that situation is handled by | |||
4947 | update_counts_for_self_gen_clones. */ | |||
4948 | ||||
4949 | static void | |||
4950 | update_profiling_info (struct cgraph_node *orig_node, | |||
4951 | struct cgraph_node *new_node) | |||
4952 | { | |||
4953 | struct caller_statistics stats; | |||
4954 | profile_count new_sum; | |||
4955 | profile_count remainder, orig_node_count = orig_node->count.ipa (); | |||
4956 | ||||
4957 | if (!(orig_node_count > profile_count::zero ())) | |||
4958 | return; | |||
4959 | ||||
4960 | if (dump_file) | |||
4961 | { | |||
4962 | fprintf (dump_file, " Updating profile from original count: "); | |||
4963 | orig_node_count.dump (dump_file); | |||
4964 | fprintf (dump_file, "\n"); | |||
4965 | } | |||
4966 | ||||
4967 | init_caller_stats (&stats, new_node); | |||
4968 | new_node->call_for_symbol_thunks_and_aliases (gather_caller_stats, &stats, | |||
4969 | false); | |||
4970 | new_sum = stats.count_sum; | |||
4971 | ||||
4972 | bool orig_edges_processed = false; | |||
4973 | if (new_sum > orig_node_count) | |||
4974 | { | |||
4975 | /* TODO: Profile has alreay gone astray, keep what we have but lower it | |||
4976 | to global0 category. */ | |||
4977 | remainder = orig_node->count.global0 (); | |||
4978 | ||||
4979 | for (cgraph_edge *cs = orig_node->callees; cs; cs = cs->next_callee) | |||
4980 | cs->count = cs->count.global0 (); | |||
4981 | for (cgraph_edge *cs = orig_node->indirect_calls; | |||
4982 | cs; | |||
4983 | cs = cs->next_callee) | |||
4984 | cs->count = cs->count.global0 (); | |||
4985 | orig_edges_processed = true; | |||
4986 | } | |||
4987 | else if (stats.rec_count_sum.nonzero_p ()) | |||
4988 | { | |||
4989 | int new_nonrec_calls = stats.n_nonrec_calls; | |||
4990 | /* There are self-recursive edges which are likely to bring in the | |||
4991 | majority of calls but which we must divide in between the original and | |||
4992 | new node. */ | |||
4993 | init_caller_stats (&stats, orig_node); | |||
4994 | orig_node->call_for_symbol_thunks_and_aliases (gather_caller_stats, | |||
4995 | &stats, false); | |||
4996 | int orig_nonrec_calls = stats.n_nonrec_calls; | |||
4997 | profile_count orig_nonrec_call_count = stats.count_sum; | |||
4998 | ||||
4999 | if (orig_node->local) | |||
5000 | { | |||
5001 | if (!orig_nonrec_call_count.nonzero_p ()) | |||
5002 | { | |||
5003 | if (dump_file) | |||
5004 | fprintf (dump_file, " The original is local and the only " | |||
5005 | "incoming edges from non-dead callers with nonzero " | |||
5006 | "counts are self-recursive, assuming it is cold.\n"); | |||
5007 | /* The NEW_NODE count and counts of all its outgoing edges | |||
5008 | are still unmodified copies of ORIG_NODE's. Just clear | |||
5009 | the latter and bail out. */ | |||
5010 | profile_count zero; | |||
5011 | if (opt_for_fn (orig_node->decl, flag_profile_partial_training)(opts_for_fn (orig_node->decl)->x_flag_profile_partial_training )) | |||
5012 | zero = profile_count::zero ().guessed_local (); | |||
5013 | else | |||
5014 | zero = profile_count::adjusted_zero (); | |||
5015 | orig_node->count = zero; | |||
5016 | for (cgraph_edge *cs = orig_node->callees; | |||
5017 | cs; | |||
5018 | cs = cs->next_callee) | |||
5019 | cs->count = zero; | |||
5020 | for (cgraph_edge *cs = orig_node->indirect_calls; | |||
5021 | cs; | |||
5022 | cs = cs->next_callee) | |||
5023 | cs->count = zero; | |||
5024 | return; | |||
5025 | } | |||
5026 | } | |||
5027 | else | |||
5028 | { | |||
5029 | /* Let's behave as if there was another caller that accounts for all | |||
5030 | the calls that were either indirect or from other compilation | |||
5031 | units. */ | |||
5032 | orig_nonrec_calls++; | |||
5033 | profile_count pretend_caller_count | |||
5034 | = (orig_node_count - new_sum - orig_nonrec_call_count | |||
5035 | - stats.rec_count_sum); | |||
5036 | orig_nonrec_call_count += pretend_caller_count; | |||
5037 | } | |||
5038 | ||||
5039 | /* Divide all "unexplained" counts roughly proportionally to sums of | |||
5040 | counts of non-recursive calls. | |||
5041 | ||||
5042 | We put rather arbitrary limits on how many counts we claim because the | |||
5043 | number of non-self-recursive incoming count is only a rough guideline | |||
5044 | and there are cases (such as mcf) where using it blindly just takes | |||
5045 | too many. And if lattices are considered in the opposite order we | |||
5046 | could also take too few. */ | |||
5047 | profile_count unexp = orig_node_count - new_sum - orig_nonrec_call_count; | |||
5048 | ||||
5049 | int limit_den = 2 * (orig_nonrec_calls + new_nonrec_calls); | |||
5050 | profile_count new_part | |||
5051 | = MAX(MIN (unexp.apply_scale (new_sum,((((unexp.apply_scale (new_sum, new_sum + orig_nonrec_call_count )) < (unexp.apply_scale (limit_den - 1, limit_den)) ? (unexp .apply_scale (new_sum, new_sum + orig_nonrec_call_count)) : ( unexp.apply_scale (limit_den - 1, limit_den)))) > (unexp.apply_scale (new_nonrec_calls, limit_den)) ? (((unexp.apply_scale (new_sum , new_sum + orig_nonrec_call_count)) < (unexp.apply_scale ( limit_den - 1, limit_den)) ? (unexp.apply_scale (new_sum, new_sum + orig_nonrec_call_count)) : (unexp.apply_scale (limit_den - 1, limit_den)))) : (unexp.apply_scale (new_nonrec_calls, limit_den ))) | |||
5052 | new_sum + orig_nonrec_call_count),((((unexp.apply_scale (new_sum, new_sum + orig_nonrec_call_count )) < (unexp.apply_scale (limit_den - 1, limit_den)) ? (unexp .apply_scale (new_sum, new_sum + orig_nonrec_call_count)) : ( unexp.apply_scale (limit_den - 1, limit_den)))) > (unexp.apply_scale (new_nonrec_calls, limit_den)) ? (((unexp.apply_scale (new_sum , new_sum + orig_nonrec_call_count)) < (unexp.apply_scale ( limit_den - 1, limit_den)) ? (unexp.apply_scale (new_sum, new_sum + orig_nonrec_call_count)) : (unexp.apply_scale (limit_den - 1, limit_den)))) : (unexp.apply_scale (new_nonrec_calls, limit_den ))) | |||
5053 | unexp.apply_scale (limit_den - 1, limit_den)),((((unexp.apply_scale (new_sum, new_sum + orig_nonrec_call_count )) < (unexp.apply_scale (limit_den - 1, limit_den)) ? (unexp .apply_scale (new_sum, new_sum + orig_nonrec_call_count)) : ( unexp.apply_scale (limit_den - 1, limit_den)))) > (unexp.apply_scale (new_nonrec_calls, limit_den)) ? (((unexp.apply_scale (new_sum , new_sum + orig_nonrec_call_count)) < (unexp.apply_scale ( limit_den - 1, limit_den)) ? (unexp.apply_scale (new_sum, new_sum + orig_nonrec_call_count)) : (unexp.apply_scale (limit_den - 1, limit_den)))) : (unexp.apply_scale (new_nonrec_calls, limit_den ))) | |||
5054 | unexp.apply_scale (new_nonrec_calls, limit_den))((((unexp.apply_scale (new_sum, new_sum + orig_nonrec_call_count )) < (unexp.apply_scale (limit_den - 1, limit_den)) ? (unexp .apply_scale (new_sum, new_sum + orig_nonrec_call_count)) : ( unexp.apply_scale (limit_den - 1, limit_den)))) > (unexp.apply_scale (new_nonrec_calls, limit_den)) ? (((unexp.apply_scale (new_sum , new_sum + orig_nonrec_call_count)) < (unexp.apply_scale ( limit_den - 1, limit_den)) ? (unexp.apply_scale (new_sum, new_sum + orig_nonrec_call_count)) : (unexp.apply_scale (limit_den - 1, limit_den)))) : (unexp.apply_scale (new_nonrec_calls, limit_den ))); | |||
5055 | if (dump_file) | |||
5056 | { | |||
5057 | fprintf (dump_file, " Claiming "); | |||
5058 | new_part.dump (dump_file); | |||
5059 | fprintf (dump_file, " of unexplained "); | |||
5060 | unexp.dump (dump_file); | |||
5061 | fprintf (dump_file, " counts because of self-recursive " | |||
5062 | "calls\n"); | |||
5063 | } | |||
5064 | new_sum += new_part; | |||
5065 | remainder = lenient_count_portion_handling (orig_node_count - new_sum, | |||
5066 | orig_node); | |||
5067 | } | |||
5068 | else | |||
5069 | remainder = lenient_count_portion_handling (orig_node_count - new_sum, | |||
5070 | orig_node); | |||
5071 | ||||
5072 | new_sum = orig_node_count.combine_with_ipa_count (new_sum); | |||
5073 | new_node->count = new_sum; | |||
5074 | orig_node->count = remainder; | |||
5075 | ||||
5076 | profile_count orig_new_node_count = orig_node_count; | |||
5077 | profile_count::adjust_for_ipa_scaling (&new_sum, &orig_new_node_count); | |||
5078 | for (cgraph_edge *cs = new_node->callees; cs; cs = cs->next_callee) | |||
5079 | cs->count = cs->count.apply_scale (new_sum, orig_new_node_count); | |||
5080 | for (cgraph_edge *cs = new_node->indirect_calls; cs; cs = cs->next_callee) | |||
5081 | cs->count = cs->count.apply_scale (new_sum, orig_new_node_count); | |||
5082 | ||||
5083 | if (!orig_edges_processed) | |||
5084 | { | |||
5085 | profile_count::adjust_for_ipa_scaling (&remainder, &orig_node_count); | |||
5086 | for (cgraph_edge *cs = orig_node->callees; cs; cs = cs->next_callee) | |||
5087 | cs->count = cs->count.apply_scale (remainder, orig_node_count); | |||
5088 | for (cgraph_edge *cs = orig_node->indirect_calls; | |||
5089 | cs; | |||
5090 | cs = cs->next_callee) | |||
5091 | cs->count = cs->count.apply_scale (remainder, orig_node_count); | |||
5092 | } | |||
5093 | ||||
5094 | if (dump_file) | |||
5095 | { | |||
5096 | dump_profile_updates (new_node, true); | |||
5097 | dump_profile_updates (orig_node, false); | |||
5098 | } | |||
5099 | } | |||
5100 | ||||
5101 | /* Update the respective profile of specialized NEW_NODE and the original | |||
5102 | ORIG_NODE after additional edges with cumulative count sum REDIRECTED_SUM | |||
5103 | have been redirected to the specialized version. */ | |||
5104 | ||||
5105 | static void | |||
5106 | update_specialized_profile (struct cgraph_node *new_node, | |||
5107 | struct cgraph_node *orig_node, | |||
5108 | profile_count redirected_sum) | |||
5109 | { | |||
5110 | struct cgraph_edge *cs; | |||
5111 | profile_count new_node_count, orig_node_count = orig_node->count.ipa (); | |||
5112 | ||||
5113 | if (dump_file) | |||
5114 | { | |||
5115 | fprintf (dump_file, " the sum of counts of redirected edges is "); | |||
5116 | redirected_sum.dump (dump_file); | |||
5117 | fprintf (dump_file, "\n old ipa count of the original node is "); | |||
5118 | orig_node_count.dump (dump_file); | |||
5119 | fprintf (dump_file, "\n"); | |||
5120 | } | |||
5121 | if (!(orig_node_count > profile_count::zero ())) | |||
5122 | return; | |||
5123 | ||||
5124 | new_node_count = new_node->count; | |||
5125 | new_node->count += redirected_sum; | |||
5126 | orig_node->count | |||
5127 | = lenient_count_portion_handling (orig_node->count - redirected_sum, | |||
5128 | orig_node); | |||
5129 | ||||
5130 | for (cs = new_node->callees; cs; cs = cs->next_callee) | |||
5131 | cs->count += cs->count.apply_scale (redirected_sum, new_node_count); | |||
5132 | ||||
5133 | for (cs = orig_node->callees; cs; cs = cs->next_callee) | |||
5134 | { | |||
5135 | profile_count dec = cs->count.apply_scale (redirected_sum, | |||
5136 | orig_node_count); | |||
5137 | cs->count -= dec; | |||
5138 | } | |||
5139 | ||||
5140 | if (dump_file) | |||
5141 | { | |||
5142 | dump_profile_updates (new_node, true); | |||
5143 | dump_profile_updates (orig_node, false); | |||
5144 | } | |||
5145 | } | |||
5146 | ||||
5147 | static void adjust_references_in_caller (cgraph_edge *cs, | |||
5148 | symtab_node *symbol, int index); | |||
5149 | ||||
5150 | /* Simple structure to pass a symbol and index (with same meaning as parameters | |||
5151 | of adjust_references_in_caller) through a void* parameter of a | |||
5152 | call_for_symbol_thunks_and_aliases callback. */ | |||
5153 | struct symbol_and_index_together | |||
5154 | { | |||
5155 | symtab_node *symbol; | |||
5156 | int index; | |||
5157 | }; | |||
5158 | ||||
5159 | /* Worker callback of call_for_symbol_thunks_and_aliases to recursively call | |||
5160 | adjust_references_in_caller on edges up in the call-graph, if necessary. */ | |||
5161 | static bool | |||
5162 | adjust_refs_in_act_callers (struct cgraph_node *node, void *data) | |||
5163 | { | |||
5164 | symbol_and_index_together *pack = (symbol_and_index_together *) data; | |||
5165 | for (cgraph_edge *cs = node->callers; cs; cs = cs->next_caller) | |||
5166 | if (!cs->caller->thunk) | |||
5167 | adjust_references_in_caller (cs, pack->symbol, pack->index); | |||
5168 | return false; | |||
5169 | } | |||
5170 | ||||
5171 | /* At INDEX of a function being called by CS there is an ADDR_EXPR of a | |||
5172 | variable which is only dereferenced and which is represented by SYMBOL. See | |||
5173 | if we can remove ADDR reference in callers assosiated witht the call. */ | |||
5174 | ||||
5175 | static void | |||
5176 | adjust_references_in_caller (cgraph_edge *cs, symtab_node *symbol, int index) | |||
5177 | { | |||
5178 | ipa_edge_args *args = ipa_edge_args_sum->get (cs); | |||
5179 | ipa_jump_func *jfunc = ipa_get_ith_jump_func (args, index); | |||
5180 | if (jfunc->type == IPA_JF_CONST) | |||
5181 | { | |||
5182 | ipa_ref *to_del = cs->caller->find_reference (symbol, cs->call_stmt, | |||
5183 | cs->lto_stmt_uid); | |||
5184 | if (!to_del) | |||
5185 | return; | |||
5186 | to_del->remove_reference (); | |||
5187 | if (dump_file) | |||
5188 | fprintf (dump_file, " Removed a reference from %s to %s.\n", | |||
5189 | cs->caller->dump_name (), symbol->dump_name ()); | |||
5190 | return; | |||
5191 | } | |||
5192 | ||||
5193 | if (jfunc->type != IPA_JF_PASS_THROUGH | |||
5194 | || ipa_get_jf_pass_through_operation (jfunc) != NOP_EXPR) | |||
5195 | return; | |||
5196 | ||||
5197 | int fidx = ipa_get_jf_pass_through_formal_id (jfunc); | |||
5198 | cgraph_node *caller = cs->caller; | |||
5199 | ipa_node_params *caller_info = ipa_node_params_sum->get (caller); | |||
5200 | /* TODO: This consistency check may be too big and not really | |||
5201 | that useful. Consider removing it. */ | |||
5202 | tree cst; | |||
5203 | if (caller_info->ipcp_orig_node) | |||
5204 | cst = caller_info->known_csts[fidx]; | |||
5205 | else | |||
5206 | { | |||
5207 | ipcp_lattice<tree> *lat = ipa_get_scalar_lat (caller_info, fidx); | |||
5208 | gcc_assert (lat->is_single_const ())((void)(!(lat->is_single_const ()) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-cp.cc" , 5208, __FUNCTION__), 0 : 0)); | |||
5209 | cst = lat->values->value; | |||
5210 | } | |||
5211 | gcc_assert (TREE_CODE (cst) == ADDR_EXPR((void)(!(((enum tree_code) (cst)->base.code) == ADDR_EXPR && (symtab_node::get (get_base_address ((*((const_cast <tree*> (tree_operand_check ((cst), (0), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-cp.cc" , 5212, __FUNCTION__))))))) == symbol)) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-cp.cc" , 5213, __FUNCTION__), 0 : 0)) | |||
5212 | && (symtab_node::get (get_base_address (TREE_OPERAND (cst, 0)))((void)(!(((enum tree_code) (cst)->base.code) == ADDR_EXPR && (symtab_node::get (get_base_address ((*((const_cast <tree*> (tree_operand_check ((cst), (0), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-cp.cc" , 5212, __FUNCTION__))))))) == symbol)) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-cp.cc" , 5213, __FUNCTION__), 0 : 0)) | |||
5213 | == symbol))((void)(!(((enum tree_code) (cst)->base.code) == ADDR_EXPR && (symtab_node::get (get_base_address ((*((const_cast <tree*> (tree_operand_check ((cst), (0), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-cp.cc" , 5212, __FUNCTION__))))))) == symbol)) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-cp.cc" , 5213, __FUNCTION__), 0 : 0)); | |||
5214 | ||||
5215 | int cuses = ipa_get_controlled_uses (caller_info, fidx); | |||
5216 | if (cuses == IPA_UNDESCRIBED_USE-1) | |||
5217 | return; | |||
5218 | gcc_assert (cuses > 0)((void)(!(cuses > 0) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-cp.cc" , 5218, __FUNCTION__), 0 : 0)); | |||
5219 | cuses--; | |||
5220 | ipa_set_controlled_uses (caller_info, fidx, cuses); | |||
5221 | if (cuses) | |||
5222 | return; | |||
5223 | ||||
5224 | if (caller_info->ipcp_orig_node) | |||
5225 | { | |||
5226 | /* Cloning machinery has created a reference here, we need to either | |||
5227 | remove it or change it to a read one. */ | |||
5228 | ipa_ref *to_del = caller->find_reference (symbol, NULLnullptr, 0); | |||
5229 | if (to_del && to_del->use == IPA_REF_ADDR) | |||
5230 | { | |||
5231 | to_del->remove_reference (); | |||
5232 | if (dump_file) | |||
5233 | fprintf (dump_file, " Removed a reference from %s to %s.\n", | |||
5234 | cs->caller->dump_name (), symbol->dump_name ()); | |||
5235 | if (ipa_get_param_load_dereferenced (caller_info, fidx)) | |||
5236 | { | |||
5237 | caller->create_reference (symbol, IPA_REF_LOAD, NULLnullptr); | |||
5238 | if (dump_file) | |||
5239 | fprintf (dump_file, | |||
5240 | " ...and replaced it with LOAD one.\n"); | |||
5241 | } | |||
5242 | } | |||
5243 | } | |||
5244 | ||||
5245 | symbol_and_index_together pack; | |||
5246 | pack.symbol = symbol; | |||
5247 | pack.index = fidx; | |||
5248 | if (caller->can_change_signature) | |||
5249 | caller->call_for_symbol_thunks_and_aliases (adjust_refs_in_act_callers, | |||
5250 | &pack, true); | |||
5251 | } | |||
5252 | ||||
5253 | ||||
5254 | /* Return true if we would like to remove a parameter from NODE when cloning it | |||
5255 | with KNOWN_CSTS scalar constants. */ | |||
5256 | ||||
5257 | static bool | |||
5258 | want_remove_some_param_p (cgraph_node *node, vec<tree> known_csts) | |||
5259 | { | |||
5260 | auto_vec<bool, 16> surviving; | |||
5261 | bool filled_vec = false; | |||
5262 | ipa_node_params *info = ipa_node_params_sum->get (node); | |||
5263 | int i, count = ipa_get_param_count (info); | |||
5264 | ||||
5265 | for (i = 0; i < count; i++) | |||
5266 | { | |||
5267 | if (!known_csts[i] && ipa_is_param_used (info, i)) | |||
5268 | continue; | |||
5269 | ||||
5270 | if (!filled_vec) | |||
5271 | { | |||
5272 | clone_info *info = clone_info::get (node); | |||
5273 | if (!info || !info->param_adjustments) | |||
5274 | return true; | |||
5275 | info->param_adjustments->get_surviving_params (&surviving); | |||
5276 | filled_vec = true; | |||
5277 | } | |||
5278 | if (surviving.length() < (unsigned) i && surviving[i]) | |||
5279 | return true; | |||
5280 | } | |||
5281 | return false; | |||
5282 | } | |||
5283 | ||||
5284 | /* Create a specialized version of NODE with known constants in KNOWN_CSTS, | |||
5285 | known contexts in KNOWN_CONTEXTS and known aggregate values in AGGVALS and | |||
5286 | redirect all edges in CALLERS to it. */ | |||
5287 | ||||
5288 | static struct cgraph_node * | |||
5289 | create_specialized_node (struct cgraph_node *node, | |||
5290 | vec<tree> known_csts, | |||
5291 | vec<ipa_polymorphic_call_context> known_contexts, | |||
5292 | vec<ipa_argagg_value, va_gc> *aggvals, | |||
5293 | vec<cgraph_edge *> &callers) | |||
5294 | { | |||
5295 | ipa_node_params *new_info, *info = ipa_node_params_sum->get (node); | |||
5296 | vec<ipa_replace_map *, va_gc> *replace_trees = NULLnullptr; | |||
5297 | vec<ipa_adjusted_param, va_gc> *new_params = NULLnullptr; | |||
5298 | struct cgraph_node *new_node; | |||
5299 | int i, count = ipa_get_param_count (info); | |||
5300 | clone_info *cinfo = clone_info::get (node); | |||
5301 | ipa_param_adjustments *old_adjustments = cinfo | |||
5302 | ? cinfo->param_adjustments : NULLnullptr; | |||
5303 | ipa_param_adjustments *new_adjustments; | |||
5304 | gcc_assert (!info->ipcp_orig_node)((void)(!(!info->ipcp_orig_node) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-cp.cc" , 5304, __FUNCTION__), 0 : 0)); | |||
5305 | gcc_assert (node->can_change_signature((void)(!(node->can_change_signature || !old_adjustments) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-cp.cc" , 5306, __FUNCTION__), 0 : 0)) | |||
5306 | || !old_adjustments)((void)(!(node->can_change_signature || !old_adjustments) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-cp.cc" , 5306, __FUNCTION__), 0 : 0)); | |||
5307 | ||||
5308 | if (old_adjustments) | |||
5309 | { | |||
5310 | /* At the moment all IPA optimizations should use the number of | |||
5311 | parameters of the prevailing decl as the m_always_copy_start. | |||
5312 | Handling any other value would complicate the code below, so for the | |||
5313 | time bing let's only assert it is so. */ | |||
5314 | gcc_assert (old_adjustments->m_always_copy_start == count((void)(!(old_adjustments->m_always_copy_start == count || old_adjustments->m_always_copy_start < 0) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-cp.cc" , 5315, __FUNCTION__), 0 : 0)) | |||
5315 | || old_adjustments->m_always_copy_start < 0)((void)(!(old_adjustments->m_always_copy_start == count || old_adjustments->m_always_copy_start < 0) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-cp.cc" , 5315, __FUNCTION__), 0 : 0)); | |||
5316 | int old_adj_count = vec_safe_length (old_adjustments->m_adj_params); | |||
5317 | for (i = 0; i < old_adj_count; i++) | |||
5318 | { | |||
5319 | ipa_adjusted_param *old_adj = &(*old_adjustments->m_adj_params)[i]; | |||
5320 | if (!node->can_change_signature | |||
5321 | || old_adj->op != IPA_PARAM_OP_COPY | |||
5322 | || (!known_csts[old_adj->base_index] | |||
5323 | && ipa_is_param_used (info, old_adj->base_index))) | |||
5324 | { | |||
5325 | ipa_adjusted_param new_adj = *old_adj; | |||
5326 | ||||
5327 | new_adj.prev_clone_adjustment = true; | |||
5328 | new_adj.prev_clone_index = i; | |||
5329 | vec_safe_push (new_params, new_adj); | |||
5330 | } | |||
5331 | } | |||
5332 | bool skip_return = old_adjustments->m_skip_return; | |||
5333 | new_adjustments = (new (ggc_alloc <ipa_param_adjustments> ()) | |||
5334 | ipa_param_adjustments (new_params, count, | |||
5335 | skip_return)); | |||
5336 | } | |||
5337 | else if (node->can_change_signature | |||
5338 | && want_remove_some_param_p (node, known_csts)) | |||
5339 | { | |||
5340 | ipa_adjusted_param adj; | |||
5341 | memset (&adj, 0, sizeof (adj)); | |||
5342 | adj.op = IPA_PARAM_OP_COPY; | |||
5343 | for (i = 0; i < count; i++) | |||
5344 | if (!known_csts[i] && ipa_is_param_used (info, i)) | |||
5345 | { | |||
5346 | adj.base_index = i; | |||
5347 | adj.prev_clone_index = i; | |||
5348 | vec_safe_push (new_params, adj); | |||
5349 | } | |||
5350 | new_adjustments = (new (ggc_alloc <ipa_param_adjustments> ()) | |||
5351 | ipa_param_adjustments (new_params, count, false)); | |||
5352 | } | |||
5353 | else | |||
5354 | new_adjustments = NULLnullptr; | |||
5355 | ||||
5356 | auto_vec<cgraph_edge *, 2> self_recursive_calls; | |||
5357 | for (i = callers.length () - 1; i >= 0; i--) | |||
5358 | { | |||
5359 | cgraph_edge *cs = callers[i]; | |||
5360 | if (cs->caller == node) | |||
5361 | { | |||
5362 | self_recursive_calls.safe_push (cs); | |||
5363 | callers.unordered_remove (i); | |||
5364 | } | |||
5365 | } | |||
5366 | replace_trees = cinfo ? vec_safe_copy (cinfo->tree_map) : NULLnullptr; | |||
5367 | for (i = 0; i < count; i++) | |||
5368 | { | |||
5369 | tree t = known_csts[i]; | |||
5370 | if (!t) | |||
5371 | continue; | |||
5372 | ||||
5373 | gcc_checking_assert (TREE_CODE (t) != TREE_BINFO)((void)(!(((enum tree_code) (t)->base.code) != TREE_BINFO) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-cp.cc" , 5373, __FUNCTION__), 0 : 0)); | |||
5374 | ||||
5375 | bool load_ref = false; | |||
5376 | symtab_node *ref_symbol; | |||
5377 | if (TREE_CODE (t)((enum tree_code) (t)->base.code) == ADDR_EXPR) | |||
5378 | { | |||
5379 | tree base = get_base_address (TREE_OPERAND (t, 0)(*((const_cast<tree*> (tree_operand_check ((t), (0), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-cp.cc" , 5379, __FUNCTION__)))))); | |||
5380 | if (TREE_CODE (base)((enum tree_code) (base)->base.code) == VAR_DECL | |||
5381 | && ipa_get_controlled_uses (info, i) == 0 | |||
5382 | && ipa_get_param_load_dereferenced (info, i) | |||
5383 | && (ref_symbol = symtab_node::get (base))) | |||
5384 | { | |||
5385 | load_ref = true; | |||
5386 | if (node->can_change_signature) | |||
5387 | for (cgraph_edge *caller : callers) | |||
5388 | adjust_references_in_caller (caller, ref_symbol, i); | |||
5389 | } | |||
5390 | } | |||
5391 | ||||
5392 | ipa_replace_map *replace_map = get_replacement_map (info, t, i, load_ref); | |||
5393 | if (replace_map) | |||
5394 | vec_safe_push (replace_trees, replace_map); | |||
5395 | } | |||
5396 | ||||
5397 | unsigned &suffix_counter = clone_num_suffixes->get_or_insert ( | |||
5398 | IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (((const char *) (tree_check ((decl_assembler_name (node->decl )), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-cp.cc" , 5399, __FUNCTION__, (IDENTIFIER_NODE)))->identifier.id.str ) | |||
5399 | node->decl))((const char *) (tree_check ((decl_assembler_name (node->decl )), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-cp.cc" , 5399, __FUNCTION__, (IDENTIFIER_NODE)))->identifier.id.str )); | |||
5400 | new_node = node->create_virtual_clone (callers, replace_trees, | |||
5401 | new_adjustments, "constprop", | |||
5402 | suffix_counter); | |||
5403 | suffix_counter++; | |||
5404 | ||||
5405 | bool have_self_recursive_calls = !self_recursive_calls.is_empty (); | |||
5406 | for (unsigned j = 0; j < self_recursive_calls.length (); j++) | |||
5407 | { | |||
5408 | cgraph_edge *cs = get_next_cgraph_edge_clone (self_recursive_calls[j]); | |||
5409 | /* Cloned edges can disappear during cloning as speculation can be | |||
5410 | resolved, check that we have one and that it comes from the last | |||
5411 | cloning. */ | |||
5412 | if (cs && cs->caller == new_node) | |||
5413 | cs->redirect_callee_duplicating_thunks (new_node); | |||
5414 | /* Any future code that would make more than one clone of an outgoing | |||
5415 | edge would confuse this mechanism, so let's check that does not | |||
5416 | happen. */ | |||
5417 | gcc_checking_assert (!cs((void)(!(!cs || !get_next_cgraph_edge_clone (cs) || get_next_cgraph_edge_clone (cs)->caller != new_node) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-cp.cc" , 5419, __FUNCTION__), 0 : 0)) | |||
5418 | || !get_next_cgraph_edge_clone (cs)((void)(!(!cs || !get_next_cgraph_edge_clone (cs) || get_next_cgraph_edge_clone (cs)->caller != new_node) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-cp.cc" , 5419, __FUNCTION__), 0 : 0)) | |||
5419 | || get_next_cgraph_edge_clone (cs)->caller != new_node)((void)(!(!cs || !get_next_cgraph_edge_clone (cs) || get_next_cgraph_edge_clone (cs)->caller != new_node) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-cp.cc" , 5419, __FUNCTION__), 0 : 0)); | |||
5420 | } | |||
5421 | if (have_self_recursive_calls) | |||
5422 | new_node->expand_all_artificial_thunks (); | |||
5423 | ||||
5424 | ipa_set_node_agg_value_chain (new_node, aggvals); | |||
5425 | for (const ipa_argagg_value &av : aggvals) | |||
5426 | new_node->maybe_create_reference (av.value, NULLnullptr); | |||
5427 | ||||
5428 | if (dump_file && (dump_flags & TDF_DETAILS)) | |||
5429 | { | |||
5430 | fprintf (dump_file, " the new node is %s.\n", new_node->dump_name ()); | |||
5431 | if (known_contexts.exists ()) | |||
5432 | { | |||
5433 | for (i = 0; i < count; i++) | |||
5434 | if (!known_contexts[i].useless_p ()) | |||
5435 | { | |||
5436 | fprintf (dump_file, " known ctx %i is ", i); | |||
5437 | known_contexts[i].dump (dump_file); | |||
5438 | } | |||
5439 | } | |||
5440 | if (aggvals) | |||
5441 | { | |||
5442 | fprintf (dump_file, " Aggregate replacements:"); | |||
5443 | ipa_argagg_value_list avs (aggvals); | |||
5444 | avs.dump (dump_file); | |||
5445 | } | |||
5446 | } | |||
5447 | ||||
5448 | new_info = ipa_node_params_sum->get (new_node); | |||
5449 | new_info->ipcp_orig_node = node; | |||
5450 | new_node->ipcp_clone = true; | |||
5451 | new_info->known_csts = known_csts; | |||
5452 | new_info->known_contexts = known_contexts; | |||
5453 | ||||
5454 | ipcp_discover_new_direct_edges (new_node, known_csts, known_contexts, | |||
5455 | aggvals); | |||
5456 | ||||
5457 | return new_node; | |||
5458 | } | |||
5459 | ||||
5460 | /* Return true if JFUNC, which describes a i-th parameter of call CS, is a | |||
5461 | pass-through function to itself when the cgraph_node involved is not an | |||
5462 | IPA-CP clone. When SIMPLE is true, further check if JFUNC is a simple | |||
5463 | no-operation pass-through. */ | |||
5464 | ||||
5465 | static bool | |||
5466 | self_recursive_pass_through_p (cgraph_edge *cs, ipa_jump_func *jfunc, int i, | |||
5467 | bool simple = true) | |||
5468 | { | |||
5469 | enum availability availability; | |||
5470 | if (cs->caller == cs->callee->function_symbol (&availability) | |||
5471 | && availability > AVAIL_INTERPOSABLE | |||
5472 | && jfunc->type == IPA_JF_PASS_THROUGH | |||
5473 | && (!simple || ipa_get_jf_pass_through_operation (jfunc) == NOP_EXPR) | |||
5474 | && ipa_get_jf_pass_through_formal_id (jfunc) == i | |||
5475 | && ipa_node_params_sum->get (cs->caller) | |||
5476 | && !ipa_node_params_sum->get (cs->caller)->ipcp_orig_node) | |||
5477 | return true; | |||
5478 | return false; | |||
5479 | } | |||
5480 | ||||
5481 | /* Return true if JFUNC, which describes a part of an aggregate represented or | |||
5482 | pointed to by the i-th parameter of call CS, is a pass-through function to | |||
5483 | itself when the cgraph_node involved is not an IPA-CP clone.. When | |||
5484 | SIMPLE is true, further check if JFUNC is a simple no-operation | |||
5485 | pass-through. */ | |||
5486 | ||||
5487 | static bool | |||
5488 | self_recursive_agg_pass_through_p (const cgraph_edge *cs, | |||
5489 | const ipa_agg_jf_item *jfunc, | |||
5490 | int i, bool simple = true) | |||
5491 | { | |||
5492 | enum availability availability; | |||
5493 | if (cs->caller == cs->callee->function_symbol (&availability) | |||
5494 | && availability > AVAIL_INTERPOSABLE | |||
5495 | && jfunc->jftype == IPA_JF_LOAD_AGG | |||
5496 | && jfunc->offset == jfunc->value.load_agg.offset | |||
5497 | && (!simple || jfunc->value.pass_through.operation == NOP_EXPR) | |||
5498 | && jfunc->value.pass_through.formal_id == i | |||
5499 | && useless_type_conversion_p (jfunc->value.load_agg.type, jfunc->type) | |||
5500 | && ipa_node_params_sum->get (cs->caller) | |||
5501 | && !ipa_node_params_sum->get (cs->caller)->ipcp_orig_node) | |||
5502 | return true; | |||
5503 | return false; | |||
5504 | } | |||
5505 | ||||
5506 | /* Given a NODE, and a subset of its CALLERS, try to populate blanks slots in | |||
5507 | KNOWN_CSTS with constants that are also known for all of the CALLERS. */ | |||
5508 | ||||
5509 | static void | |||
5510 | find_more_scalar_values_for_callers_subset (struct cgraph_node *node, | |||
5511 | vec<tree> &known_csts, | |||
5512 | const vec<cgraph_edge *> &callers) | |||
5513 | { | |||
5514 | ipa_node_params *info = ipa_node_params_sum->get (node); | |||
5515 | int i, count = ipa_get_param_count (info); | |||
5516 | ||||
5517 | for (i = 0; i < count; i++) | |||
5518 | { | |||
5519 | struct cgraph_edge *cs; | |||
5520 | tree newval = NULL_TREE(tree) nullptr; | |||
5521 | int j; | |||
5522 | bool first = true; | |||
5523 | tree type = ipa_get_type (info, i); | |||
5524 | ||||
5525 | if (ipa_get_scalar_lat (info, i)->bottom || known_csts[i]) | |||
5526 | continue; | |||
5527 | ||||
5528 | FOR_EACH_VEC_ELT (callers, j, cs)for (j = 0; (callers).iterate ((j), &(cs)); ++(j)) | |||
5529 | { | |||
5530 | struct ipa_jump_func *jump_func; | |||
5531 | tree t; | |||
5532 | ||||
5533 | ipa_edge_args *args = ipa_edge_args_sum->get (cs); | |||
5534 | if (!args | |||
5535 | || i >= ipa_get_cs_argument_count (args) | |||
5536 | || (i == 0 | |||
5537 | && call_passes_through_thunk (cs))) | |||
5538 | { | |||
5539 | newval = NULL_TREE(tree) nullptr; | |||
5540 | break; | |||
5541 | } | |||
5542 | jump_func = ipa_get_ith_jump_func (args, i); | |||
5543 | ||||
5544 | /* Besides simple pass-through jump function, arithmetic jump | |||
5545 | function could also introduce argument-direct-pass-through for | |||
5546 | self-feeding recursive call. For example, | |||
5547 | ||||
5548 | fn (int i) | |||
5549 | { | |||
5550 | fn (i & 1); | |||
5551 | } | |||
5552 | ||||
5553 | Given that i is 0, recursive propagation via (i & 1) also gets | |||
5554 | 0. */ | |||
5555 | if (self_recursive_pass_through_p (cs, jump_func, i, false)) | |||
5556 | { | |||
5557 | gcc_assert (newval)((void)(!(newval) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-cp.cc" , 5557, __FUNCTION__), 0 : 0)); | |||
5558 | t = ipa_get_jf_arith_result ( | |||
5559 | ipa_get_jf_pass_through_operation (jump_func), | |||
5560 | newval, | |||
5561 | ipa_get_jf_pass_through_operand (jump_func), | |||
5562 | type); | |||
5563 | } | |||
5564 | else | |||
5565 | t = ipa_value_from_jfunc (ipa_node_params_sum->get (cs->caller), | |||
5566 | jump_func, type); | |||
5567 | if (!t | |||
5568 | || (newval | |||
5569 | && !values_equal_for_ipcp_p (t, newval)) | |||
5570 | || (!first && !newval)) | |||
5571 | { | |||
5572 | newval = NULL_TREE(tree) nullptr; | |||
5573 | break; | |||
5574 | } | |||
5575 | else | |||
5576 | newval = t; | |||
5577 | first = false; | |||
5578 | } | |||
5579 | ||||
5580 | if (newval) | |||
5581 | { | |||
5582 | if (dump_file && (dump_flags & TDF_DETAILS)) | |||
5583 | { | |||
5584 | fprintf (dump_file, " adding an extra known scalar value "); | |||
5585 | print_ipcp_constant_value (dump_file, newval); | |||
5586 | fprintf (dump_file, " for "); | |||
5587 | ipa_dump_param (dump_file, info, i); | |||
5588 | fprintf (dump_file, "\n"); | |||
5589 | } | |||
5590 | ||||
5591 | known_csts[i] = newval; | |||
5592 | } | |||
5593 | } | |||
5594 | } | |||
5595 | ||||
5596 | /* Given a NODE and a subset of its CALLERS, try to populate plank slots in | |||
5597 | KNOWN_CONTEXTS with polymorphic contexts that are also known for all of the | |||
5598 | CALLERS. */ | |||
5599 | ||||
5600 | static void | |||
5601 | find_more_contexts_for_caller_subset (cgraph_node *node, | |||
5602 | vec<ipa_polymorphic_call_context> | |||
5603 | *known_contexts, | |||
5604 | const vec<cgraph_edge *> &callers) | |||
5605 | { | |||
5606 | ipa_node_params *info = ipa_node_params_sum->get (node); | |||
5607 | int i, count = ipa_get_param_count (info); | |||
5608 | ||||
5609 | for (i = 0; i < count; i++) | |||
5610 | { | |||
5611 | cgraph_edge *cs; | |||
5612 | ||||
5613 | if (ipa_get_poly_ctx_lat (info, i)->bottom | |||
5614 | || (known_contexts->exists () | |||
5615 | && !(*known_contexts)[i].useless_p ())) | |||
5616 | continue; | |||
5617 | ||||
5618 | ipa_polymorphic_call_context newval; | |||
5619 | bool first = true; | |||
5620 | int j; | |||
5621 | ||||
5622 | FOR_EACH_VEC_ELT (callers, j, cs)for (j = 0; (callers).iterate ((j), &(cs)); ++(j)) | |||
5623 | { | |||
5624 | ipa_edge_args *args = ipa_edge_args_sum->get (cs); | |||
5625 | if (!args | |||
5626 | || i >= ipa_get_cs_argument_count (args)) | |||
5627 | return; | |||
5628 | ipa_jump_func *jfunc = ipa_get_ith_jump_func (args, i); | |||
5629 | ipa_polymorphic_call_context ctx; | |||
5630 | ctx = ipa_context_from_jfunc (ipa_node_params_sum->get (cs->caller), | |||
5631 | cs, i, jfunc); | |||
5632 | if (first) | |||
5633 | { | |||
5634 | newval = ctx; | |||
5635 | first = false; | |||
5636 | } | |||
5637 | else | |||
5638 | newval.meet_with (ctx); | |||
5639 | if (newval.useless_p ()) | |||
5640 | break; | |||
5641 | } | |||
5642 | ||||
5643 | if (!newval.useless_p ()) | |||
5644 | { | |||
5645 | if (dump_file && (dump_flags & TDF_DETAILS)) | |||
5646 | { | |||
5647 | fprintf (dump_file, " adding an extra known polymorphic " | |||
5648 | "context "); | |||
5649 | print_ipcp_constant_value (dump_file, newval); | |||
5650 | fprintf (dump_file, " for "); | |||
5651 | ipa_dump_param (dump_file, info, i); | |||
5652 | fprintf (dump_file, "\n"); | |||
5653 | } | |||
5654 | ||||
5655 | if (!known_contexts->exists ()) | |||
5656 | known_contexts->safe_grow_cleared (ipa_get_param_count (info), | |||
5657 | true); | |||
5658 | (*known_contexts)[i] = newval; | |||
5659 | } | |||
5660 | ||||
5661 | } | |||
5662 | } | |||
5663 | ||||
5664 | /* Push all aggregate values coming along edge CS for parameter number INDEX to | |||
5665 | RES. If INTERIM is non-NULL, it contains the current interim state of | |||
5666 | collected aggregate values which can be used to compute values passed over | |||
5667 | self-recursive edges. | |||
5668 | ||||
5669 | This basically one iteration of push_agg_values_from_edge over one | |||
5670 | parameter, which allows for simpler early returns. */ | |||
5671 | ||||
5672 | static void | |||
5673 | push_agg_values_for_index_from_edge (struct cgraph_edge *cs, int index, | |||
5674 | vec<ipa_argagg_value> *res, | |||
5675 | const ipa_argagg_value_list *interim) | |||
5676 | { | |||
5677 | bool agg_values_from_caller = false; | |||
5678 | bool agg_jf_preserved = false; | |||
5679 | unsigned unit_delta = UINT_MAX(2147483647 *2U +1U); | |||
5680 | int src_idx = -1; | |||
5681 | ipa_jump_func *jfunc = ipa_get_ith_jump_func (ipa_edge_args_sum->get (cs), | |||
5682 | index); | |||
5683 | ||||
5684 | if (jfunc->type == IPA_JF_PASS_THROUGH | |||
5685 | && ipa_get_jf_pass_through_operation (jfunc) == NOP_EXPR) | |||
5686 | { | |||
5687 | agg_values_from_caller = true; | |||
5688 | agg_jf_preserved = ipa_get_jf_pass_through_agg_preserved (jfunc); | |||
5689 | src_idx = ipa_get_jf_pass_through_formal_id (jfunc); | |||
5690 | unit_delta = 0; | |||
5691 | } | |||
5692 | else if (jfunc->type == IPA_JF_ANCESTOR | |||
5693 | && ipa_get_jf_ancestor_agg_preserved (jfunc)) | |||
5694 | { | |||
5695 | agg_values_from_caller = true; | |||
5696 | agg_jf_preserved = true; | |||
5697 | src_idx = ipa_get_jf_ancestor_formal_id (jfunc); | |||
5698 | unit_delta = ipa_get_jf_ancestor_offset (jfunc) / BITS_PER_UNIT(8); | |||
5699 | } | |||
5700 | ||||
5701 | ipa_node_params *caller_info = ipa_node_params_sum->get (cs->caller); | |||
5702 | if (agg_values_from_caller) | |||
5703 | { | |||
5704 | if (caller_info->ipcp_orig_node) | |||
5705 | { | |||
5706 | struct cgraph_node *orig_node = caller_info->ipcp_orig_node; | |||
5707 | ipcp_transformation *ts | |||
5708 | = ipcp_get_transformation_summary (cs->caller); | |||
5709 | ipa_node_params *orig_info = ipa_node_params_sum->get (orig_node); | |||
5710 | ipcp_param_lattices *orig_plats | |||
5711 | = ipa_get_parm_lattices (orig_info, src_idx); | |||
5712 | if (ts | |||
5713 | && orig_plats->aggs | |||
5714 | && (agg_jf_preserved || !orig_plats->aggs_by_ref)) | |||
5715 | { | |||
5716 | ipa_argagg_value_list src (ts); | |||
5717 | src.push_adjusted_values (src_idx, index, unit_delta, res); | |||
5718 | return; | |||
5719 | } | |||
5720 | } | |||
5721 | else | |||
5722 | { | |||
5723 | ipcp_param_lattices *src_plats | |||
5724 | = ipa_get_parm_lattices (caller_info, src_idx); | |||
5725 | if (src_plats->aggs | |||
5726 | && !src_plats->aggs_bottom | |||
5727 | && (agg_jf_preserved || !src_plats->aggs_by_ref)) | |||
5728 | { | |||
5729 | if (interim && self_recursive_pass_through_p (cs, jfunc, index)) | |||
5730 | { | |||
5731 | interim->push_adjusted_values (src_idx, index, unit_delta, | |||
5732 | res); | |||
5733 | return; | |||
5734 | } | |||
5735 | if (!src_plats->aggs_contain_variable) | |||
5736 | { | |||
5737 | push_agg_values_from_plats (src_plats, index, unit_delta, | |||
5738 | res); | |||
5739 | return; | |||
5740 | } | |||
5741 | } | |||
5742 | } | |||
5743 | } | |||
5744 | ||||
5745 | if (!jfunc->agg.items) | |||
5746 | return; | |||
5747 | bool first = true; | |||
5748 | unsigned prev_unit_offset = 0; | |||
5749 | for (const ipa_agg_jf_item &agg_jf : *jfunc->agg.items) | |||
5750 | { | |||
5751 | tree value, srcvalue; | |||
5752 | /* Besides simple pass-through aggregate jump function, arithmetic | |||
5753 | aggregate jump function could also bring same aggregate value as | |||
5754 | parameter passed-in for self-feeding recursive call. For example, | |||
5755 | ||||
5756 | fn (int *i) | |||
5757 | { | |||
5758 | int j = *i & 1; | |||
5759 | fn (&j); | |||
5760 | } | |||
5761 | ||||
5762 | Given that *i is 0, recursive propagation via (*i & 1) also gets 0. */ | |||
5763 | if (interim | |||
5764 | && self_recursive_agg_pass_through_p (cs, &agg_jf, index, false) | |||
5765 | && (srcvalue = interim->get_value(index, | |||
5766 | agg_jf.offset / BITS_PER_UNIT(8)))) | |||
5767 | value = ipa_get_jf_arith_result (agg_jf.value.pass_through.operation, | |||
5768 | srcvalue, | |||
5769 | agg_jf.value.pass_through.operand, | |||
5770 | agg_jf.type); | |||
5771 | else | |||
5772 | value = ipa_agg_value_from_jfunc (caller_info, cs->caller, | |||
5773 | &agg_jf); | |||
5774 | if (value) | |||
5775 | { | |||
5776 | struct ipa_argagg_value iav; | |||
5777 | iav.value = value; | |||
5778 | iav.unit_offset = agg_jf.offset / BITS_PER_UNIT(8); | |||
5779 | iav.index = index; | |||
5780 | iav.by_ref = jfunc->agg.by_ref; | |||
5781 | ||||
5782 | gcc_assert (first((void)(!(first || iav.unit_offset > prev_unit_offset) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-cp.cc" , 5783, __FUNCTION__), 0 : 0)) | |||
5783 | || iav.unit_offset > prev_unit_offset)((void)(!(first || iav.unit_offset > prev_unit_offset) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-cp.cc" , 5783, __FUNCTION__), 0 : 0)); | |||
5784 | prev_unit_offset = iav.unit_offset; | |||
5785 | first = false; | |||
5786 | ||||
5787 | res->safe_push (iav); | |||
5788 | } | |||
5789 | } | |||
5790 | return; | |||
5791 | } | |||
5792 | ||||
5793 | /* Push all aggregate values coming along edge CS to RES. DEST_INFO is the | |||
5794 | description of ultimate callee of CS or the one it was cloned from (the | |||
5795 | summary where lattices are). If INTERIM is non-NULL, it contains the | |||
5796 | current interim state of collected aggregate values which can be used to | |||
5797 | compute values passed over self-recursive edges (if OPTIMIZE_SELF_RECURSION | |||
5798 | is true) and to skip values which clearly will not be part of intersection | |||
5799 | with INTERIM. */ | |||
5800 | ||||
5801 | static void | |||
5802 | push_agg_values_from_edge (struct cgraph_edge *cs, | |||
5803 | ipa_node_params *dest_info, | |||
5804 | vec<ipa_argagg_value> *res, | |||
5805 | const ipa_argagg_value_list *interim, | |||
5806 | bool optimize_self_recursion) | |||
5807 | { | |||
5808 | ipa_edge_args *args = ipa_edge_args_sum->get (cs); | |||
5809 | if (!args) | |||
5810 | return; | |||
5811 | ||||
5812 | int count = MIN (ipa_get_param_count (dest_info),((ipa_get_param_count (dest_info)) < (ipa_get_cs_argument_count (args)) ? (ipa_get_param_count (dest_info)) : (ipa_get_cs_argument_count (args))) | |||
5813 | ipa_get_cs_argument_count (args))((ipa_get_param_count (dest_info)) < (ipa_get_cs_argument_count (args)) ? (ipa_get_param_count (dest_info)) : (ipa_get_cs_argument_count (args))); | |||
5814 | ||||
5815 | unsigned interim_index = 0; | |||
5816 | for (int index = 0; index < count; index++) | |||
5817 | { | |||
5818 | if (interim) | |||
5819 | { | |||
5820 | while (interim_index < interim->m_elts.size () | |||
5821 | && interim->m_elts[interim_index].value | |||
5822 | && interim->m_elts[interim_index].index < index) | |||
5823 | interim_index++; | |||
5824 | if (interim_index >= interim->m_elts.size () | |||
5825 | || interim->m_elts[interim_index].index > index) | |||
5826 | continue; | |||
5827 | } | |||
5828 | ||||
5829 | ipcp_param_lattices *plats = ipa_get_parm_lattices (dest_info, index); | |||
5830 | if (!ipa_is_param_used (dest_info, index) | |||
5831 | || plats->aggs_bottom) | |||
5832 | continue; | |||
5833 | push_agg_values_for_index_from_edge (cs, index, res, | |||
5834 | optimize_self_recursion ? interim | |||
5835 | : NULLnullptr); | |||
5836 | } | |||
5837 | } | |||
5838 | ||||
5839 | ||||
5840 | /* Look at edges in CALLERS and collect all known aggregate values that arrive | |||
5841 | from all of them. Return nullptr if there are none. */ | |||
5842 | ||||
5843 | static struct vec<ipa_argagg_value, va_gc> * | |||
5844 | find_aggregate_values_for_callers_subset (struct cgraph_node *node, | |||
5845 | const vec<cgraph_edge *> &callers) | |||
5846 | { | |||
5847 | ipa_node_params *dest_info = ipa_node_params_sum->get (node); | |||
5848 | if (dest_info->ipcp_orig_node) | |||
5849 | dest_info = ipa_node_params_sum->get (dest_info->ipcp_orig_node); | |||
5850 | ||||
5851 | /* gather_edges_for_value puts a non-recursive call into the first element of | |||
5852 | callers if it can. */ | |||
5853 | auto_vec<ipa_argagg_value, 32> interim; | |||
5854 | push_agg_values_from_edge (callers[0], dest_info, &interim, NULLnullptr, true); | |||
5855 | ||||
5856 | unsigned valid_entries = interim.length (); | |||
5857 | if (!valid_entries) | |||
5858 | return nullptr; | |||
5859 | ||||
5860 | unsigned caller_count = callers.length(); | |||
5861 | for (unsigned i = 1; i < caller_count; i++) | |||
5862 | { | |||
5863 | auto_vec<ipa_argagg_value, 32> last; | |||
5864 | ipa_argagg_value_list avs (&interim); | |||
5865 | push_agg_values_from_edge (callers[i], dest_info, &last, &avs, true); | |||
5866 | ||||
5867 | valid_entries = intersect_argaggs_with (interim, last); | |||
5868 | if (!valid_entries) | |||
5869 | return nullptr; | |||
5870 | } | |||
5871 | ||||
5872 | vec<ipa_argagg_value, va_gc> *res = NULLnullptr; | |||
5873 | vec_safe_reserve_exact (res, valid_entries); | |||
5874 | for (const ipa_argagg_value &av : interim) | |||
5875 | if (av.value) | |||
5876 | res->quick_push(av); | |||
5877 | gcc_checking_assert (res->length () == valid_entries)((void)(!(res->length () == valid_entries) ? fancy_abort ( "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-cp.cc" , 5877, __FUNCTION__), 0 : 0)); | |||
| ||||
5878 | return res; | |||
5879 | } | |||
5880 | ||||
5881 | /* Determine whether CS also brings all scalar values that the NODE is | |||
5882 | specialized for. */ | |||
5883 | ||||
5884 | static bool | |||
5885 | cgraph_edge_brings_all_scalars_for_node (struct cgraph_edge *cs, | |||
5886 | struct cgraph_node *node) | |||
5887 | { | |||
5888 | ipa_node_params *dest_info = ipa_node_params_sum->get (node); | |||
5889 | int count = ipa_get_param_count (dest_info); | |||
5890 | class ipa_node_params *caller_info; | |||
5891 | class ipa_edge_args *args; | |||
5892 | int i; | |||
5893 | ||||
5894 | caller_info = ipa_node_params_sum->get (cs->caller); | |||
5895 | args = ipa_edge_args_sum->get (cs); | |||
5896 | for (i = 0; i < count; i++) | |||
5897 | { | |||
5898 | struct ipa_jump_func *jump_func; | |||
5899 | tree val, t; | |||
5900 | ||||
5901 | val = dest_info->known_csts[i]; | |||
5902 | if (!val) | |||
5903 | continue; | |||
5904 | ||||
5905 | if (i >= ipa_get_cs_argument_count (args)) | |||
5906 | return false; | |||
5907 | jump_func = ipa_get_ith_jump_func (args, i); | |||
5908 | t = ipa_value_from_jfunc (caller_info, jump_func, | |||
5909 | ipa_get_type (dest_info, i)); | |||
5910 | if (!t || !values_equal_for_ipcp_p (val, t)) | |||
5911 | return false; | |||
5912 | } | |||
5913 | return true; | |||
5914 | } | |||
5915 | ||||
5916 | /* Determine whether CS also brings all aggregate values that NODE is | |||
5917 | specialized for. */ | |||
5918 | ||||
5919 | static bool | |||
5920 | cgraph_edge_brings_all_agg_vals_for_node (struct cgraph_edge *cs, | |||
5921 | struct cgraph_node *node) | |||
5922 | { | |||
5923 | ipcp_transformation *ts = ipcp_get_transformation_summary (node); | |||
5924 | if (!ts || vec_safe_is_empty (ts->m_agg_values)) | |||
5925 | return true; | |||
5926 | ||||
5927 | const ipa_argagg_value_list existing (ts->m_agg_values); | |||
5928 | auto_vec<ipa_argagg_value, 32> edge_values; | |||
5929 | ipa_node_params *dest_info = ipa_node_params_sum->get (node); | |||
5930 | gcc_checking_assert (dest_info->ipcp_orig_node)((void)(!(dest_info->ipcp_orig_node) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-cp.cc" , 5930, __FUNCTION__), 0 : 0)); | |||
5931 | dest_info = ipa_node_params_sum->get (dest_info->ipcp_orig_node); | |||
5932 | push_agg_values_from_edge (cs, dest_info, &edge_values, &existing, false); | |||
5933 | const ipa_argagg_value_list avl (&edge_values); | |||
5934 | return avl.superset_of_p (existing); | |||
5935 | } | |||
5936 | ||||
5937 | /* Given an original NODE and a VAL for which we have already created a | |||
5938 | specialized clone, look whether there are incoming edges that still lead | |||
5939 | into the old node but now also bring the requested value and also conform to | |||
5940 | all other criteria such that they can be redirected the special node. | |||
5941 | This function can therefore redirect the final edge in a SCC. */ | |||
5942 | ||||
5943 | template <typename valtype> | |||
5944 | static void | |||
5945 | perhaps_add_new_callers (cgraph_node *node, ipcp_value<valtype> *val) | |||
5946 | { | |||
5947 | ipcp_value_source<valtype> *src; | |||
5948 | profile_count redirected_sum = profile_count::zero (); | |||
5949 | ||||
5950 | for (src = val->sources; src; src = src->next) | |||
5951 | { | |||
5952 | struct cgraph_edge *cs = src->cs; | |||
5953 | while (cs) | |||
5954 | { | |||
5955 | if (cgraph_edge_brings_value_p (cs, src, node, val) | |||
5956 | && cgraph_edge_brings_all_scalars_for_node (cs, val->spec_node) | |||
5957 | && cgraph_edge_brings_all_agg_vals_for_node (cs, val->spec_node)) | |||
5958 | { | |||
5959 | if (dump_file) | |||
5960 | fprintf (dump_file, " - adding an extra caller %s of %s\n", | |||
5961 | cs->caller->dump_name (), | |||
5962 | val->spec_node->dump_name ()); | |||
5963 | ||||
5964 | cs->redirect_callee_duplicating_thunks (val->spec_node); | |||
5965 | val->spec_node->expand_all_artificial_thunks (); | |||
5966 | if (cs->count.ipa ().initialized_p ()) | |||
5967 | redirected_sum = redirected_sum + cs->count.ipa (); | |||
5968 | } | |||
5969 | cs = get_next_cgraph_edge_clone (cs); | |||
5970 | } | |||
5971 | } | |||
5972 | ||||
5973 | if (redirected_sum.nonzero_p ()) | |||
5974 | update_specialized_profile (val->spec_node, node, redirected_sum); | |||
5975 | } | |||
5976 | ||||
5977 | /* Return true if KNOWN_CONTEXTS contain at least one useful context. */ | |||
5978 | ||||
5979 | static bool | |||
5980 | known_contexts_useful_p (vec<ipa_polymorphic_call_context> known_contexts) | |||
5981 | { | |||
5982 | ipa_polymorphic_call_context *ctx; | |||
5983 | int i; | |||
5984 | ||||
5985 | FOR_EACH_VEC_ELT (known_contexts, i, ctx)for (i = 0; (known_contexts).iterate ((i), &(ctx)); ++(i) ) | |||
5986 | if (!ctx->useless_p ()) | |||
5987 | return true; | |||
5988 | return false; | |||
5989 | } | |||
5990 | ||||
5991 | /* Return a copy of KNOWN_CSTS if it is not empty, otherwise return vNULL. */ | |||
5992 | ||||
5993 | static vec<ipa_polymorphic_call_context> | |||
5994 | copy_useful_known_contexts (const vec<ipa_polymorphic_call_context> &known_contexts) | |||
5995 | { | |||
5996 | if (known_contexts_useful_p (known_contexts)) | |||
5997 | return known_contexts.copy (); | |||
5998 | else | |||
5999 | return vNULL; | |||
6000 | } | |||
6001 | ||||
6002 | /* Copy known scalar values from AVALS into KNOWN_CSTS and modify the copy | |||
6003 | according to VAL and INDEX. If non-empty, replace KNOWN_CONTEXTS with its | |||
6004 | copy too. */ | |||
6005 | ||||
6006 | static void | |||
6007 | copy_known_vectors_add_val (ipa_auto_call_arg_values *avals, | |||
6008 | vec<tree> *known_csts, | |||
6009 | vec<ipa_polymorphic_call_context> *known_contexts, | |||
6010 | ipcp_value<tree> *val, int index) | |||
6011 | { | |||
6012 | *known_csts = avals->m_known_vals.copy (); | |||
6013 | *known_contexts = copy_useful_known_contexts (avals->m_known_contexts); | |||
6014 | (*known_csts)[index] = val->value; | |||
6015 | } | |||
6016 | ||||
6017 | /* Copy known scalar values from AVALS into KNOWN_CSTS. Similarly, copy | |||
6018 | contexts to KNOWN_CONTEXTS and modify the copy according to VAL and | |||
6019 | INDEX. */ | |||
6020 | ||||
6021 | static void | |||
6022 | copy_known_vectors_add_val (ipa_auto_call_arg_values *avals, | |||
6023 | vec<tree> *known_csts, | |||
6024 | vec<ipa_polymorphic_call_context> *known_contexts, | |||
6025 | ipcp_value<ipa_polymorphic_call_context> *val, | |||
6026 | int index) | |||
6027 | { | |||
6028 | *known_csts = avals->m_known_vals.copy (); | |||
6029 | *known_contexts = avals->m_known_contexts.copy (); | |||
6030 | (*known_contexts)[index] = val->value; | |||
6031 | } | |||
6032 | ||||
6033 | /* Return true if OFFSET indicates this was not an aggregate value or there is | |||
6034 | a replacement equivalent to VALUE, INDEX and OFFSET among those in the | |||
6035 | AGGVALS list. */ | |||
6036 | ||||
6037 | DEBUG_FUNCTION__attribute__ ((__used__)) bool | |||
6038 | ipcp_val_agg_replacement_ok_p (vec<ipa_argagg_value, va_gc> *aggvals, | |||
6039 | int index, HOST_WIDE_INTlong offset, tree value) | |||
6040 | { | |||
6041 | if (offset == -1) | |||
6042 | return true; | |||
6043 | ||||
6044 | const ipa_argagg_value_list avl (aggvals); | |||
6045 | tree v = avl.get_value (index, offset / BITS_PER_UNIT(8)); | |||
6046 | return v && values_equal_for_ipcp_p (v, value); | |||
6047 | } | |||
6048 | ||||
6049 | /* Return true if offset is minus one because source of a polymorphic context | |||
6050 | cannot be an aggregate value. */ | |||
6051 | ||||
6052 | DEBUG_FUNCTION__attribute__ ((__used__)) bool | |||
6053 | ipcp_val_agg_replacement_ok_p (vec<ipa_argagg_value, va_gc> *, | |||
6054 | int , HOST_WIDE_INTlong offset, | |||
6055 | ipa_polymorphic_call_context) | |||
6056 | { | |||
6057 | return offset == -1; | |||
6058 | } | |||
6059 | ||||
6060 | /* Decide whether to create a special version of NODE for value VAL of | |||
6061 | parameter at the given INDEX. If OFFSET is -1, the value is for the | |||
6062 | parameter itself, otherwise it is stored at the given OFFSET of the | |||
6063 | parameter. AVALS describes the other already known values. SELF_GEN_CLONES | |||
6064 | is a vector which contains clones created for self-recursive calls with an | |||
6065 | arithmetic pass-through jump function. */ | |||
6066 | ||||
6067 | template <typename valtype> | |||
6068 | static bool | |||
6069 | decide_about_value (struct cgraph_node *node, int index, HOST_WIDE_INTlong offset, | |||
6070 | ipcp_value<valtype> *val, ipa_auto_call_arg_values *avals, | |||
6071 | vec<cgraph_node *> *self_gen_clones) | |||
6072 | { | |||
6073 | int caller_count; | |||
6074 | sreal freq_sum; | |||
6075 | profile_count count_sum, rec_count_sum; | |||
6076 | vec<cgraph_edge *> callers; | |||
6077 | ||||
6078 | if (val->spec_node) | |||
6079 | { | |||
6080 | perhaps_add_new_callers (node, val); | |||
6081 | return false; | |||
6082 | } | |||
6083 | else if (val->local_size_cost + overall_size > get_max_overall_size (node)) | |||
6084 | { | |||
6085 | if (dump_file && (dump_flags & TDF_DETAILS)) | |||
6086 | fprintf (dump_file, " Ignoring candidate value because " | |||
6087 | "maximum unit size would be reached with %li.\n", | |||
6088 | val->local_size_cost + overall_size); | |||
6089 | return false; | |||
6090 | } | |||
6091 | else if (!get_info_about_necessary_edges (val, node, &freq_sum, &caller_count, | |||
6092 | &rec_count_sum, &count_sum)) | |||
6093 | return false; | |||
6094 | ||||
6095 | if (!dbg_cnt (ipa_cp_values)) | |||
6096 | return false; | |||
6097 | ||||
6098 | if (val->self_recursion_generated_p ()) | |||
6099 | { | |||
6100 | /* The edge counts in this case might not have been adjusted yet. | |||
6101 | Nevertleless, even if they were it would be only a guesswork which we | |||
6102 | can do now. The recursive part of the counts can be derived from the | |||
6103 | count of the original node anyway. */ | |||
6104 | if (node->count.ipa ().nonzero_p ()) | |||
6105 | { | |||
6106 | unsigned dem = self_gen_clones->length () + 1; | |||
6107 | rec_count_sum = node->count.ipa () / dem; | |||
6108 | } | |||
6109 | else | |||
6110 | rec_count_sum = profile_count::zero (); | |||
6111 | } | |||
6112 | ||||
6113 | /* get_info_about_necessary_edges only sums up ipa counts. */ | |||
6114 | count_sum += rec_count_sum; | |||
6115 | ||||
6116 | if (dump_file && (dump_flags & TDF_DETAILS)) | |||
6117 | { | |||
6118 | fprintf (dump_file, " - considering value "); | |||
6119 | print_ipcp_constant_value (dump_file, val->value); | |||
6120 | fprintf (dump_file, " for "); | |||
6121 | ipa_dump_param (dump_file, ipa_node_params_sum->get (node), index); | |||
6122 | if (offset != -1) | |||
6123 | fprintf (dump_file, ", offset: " HOST_WIDE_INT_PRINT_DEC"%" "l" "d", offset); | |||
6124 | fprintf (dump_file, " (caller_count: %i)\n", caller_count); | |||
6125 | } | |||
6126 | ||||
6127 | if (!good_cloning_opportunity_p (node, val->local_time_benefit, | |||
6128 | freq_sum, count_sum, | |||
6129 | val->local_size_cost) | |||
6130 | && !good_cloning_opportunity_p (node, val->prop_time_benefit, | |||
6131 | freq_sum, count_sum, val->prop_size_cost)) | |||
6132 | return false; | |||
6133 | ||||
6134 | if (dump_file) | |||
6135 | fprintf (dump_file, " Creating a specialized node of %s.\n", | |||
6136 | node->dump_name ()); | |||
6137 | ||||
6138 | vec<tree> known_csts; | |||
6139 | vec<ipa_polymorphic_call_context> known_contexts; | |||
6140 | ||||
6141 | callers = gather_edges_for_value (val, node, caller_count); | |||
6142 | if (offset == -1) | |||
6143 | copy_known_vectors_add_val (avals, &known_csts, &known_contexts, val, index); | |||
6144 | else | |||
6145 | { | |||
6146 | known_csts = avals->m_known_vals.copy (); | |||
6147 | known_contexts = copy_useful_known_contexts (avals->m_known_contexts); | |||
6148 | } | |||
6149 | find_more_scalar_values_for_callers_subset (node, known_csts, callers); | |||
6150 | find_more_contexts_for_caller_subset (node, &known_contexts, callers); | |||
6151 | vec<ipa_argagg_value, va_gc> *aggvals | |||
6152 | = find_aggregate_values_for_callers_subset (node, callers); | |||
6153 | gcc_checking_assert (ipcp_val_agg_replacement_ok_p (aggvals, index,((void)(!(ipcp_val_agg_replacement_ok_p (aggvals, index, offset , val->value)) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-cp.cc" , 6154, __FUNCTION__), 0 : 0)) | |||
6154 | offset, val->value))((void)(!(ipcp_val_agg_replacement_ok_p (aggvals, index, offset , val->value)) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-cp.cc" , 6154, __FUNCTION__), 0 : 0)); | |||
6155 | val->spec_node = create_specialized_node (node, known_csts, known_contexts, | |||
6156 | aggvals, callers); | |||
6157 | ||||
6158 | if (val->self_recursion_generated_p ()) | |||
6159 | self_gen_clones->safe_push (val->spec_node); | |||
6160 | else | |||
6161 | update_profiling_info (node, val->spec_node); | |||
6162 | ||||
6163 | callers.release (); | |||
6164 | overall_size += val->local_size_cost; | |||
6165 | if (dump_file && (dump_flags & TDF_DETAILS)) | |||
6166 | fprintf (dump_file, " overall size reached %li\n", | |||
6167 | overall_size); | |||
6168 | ||||
6169 | /* TODO: If for some lattice there is only one other known value | |||
6170 | left, make a special node for it too. */ | |||
6171 | ||||
6172 | return true; | |||
6173 | } | |||
6174 | ||||
6175 | /* Decide whether and what specialized clones of NODE should be created. */ | |||
6176 | ||||
6177 | static bool | |||
6178 | decide_whether_version_node (struct cgraph_node *node) | |||
6179 | { | |||
6180 | ipa_node_params *info = ipa_node_params_sum->get (node); | |||
6181 | int i, count = ipa_get_param_count (info); | |||
6182 | bool ret = false; | |||
6183 | ||||
6184 | if (count == 0) | |||
6185 | return false; | |||
6186 | ||||
6187 | if (dump_file && (dump_flags & TDF_DETAILS)) | |||
6188 | fprintf (dump_file, "\nEvaluating opportunities for %s.\n", | |||
6189 | node->dump_name ()); | |||
6190 | ||||
6191 | auto_vec <cgraph_node *, 9> self_gen_clones; | |||
6192 | ipa_auto_call_arg_values avals; | |||
6193 |