File: | build/gcc/ipa-prop.cc |
Warning: | line 302, column 5 Forming reference to null pointer |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | /* Interprocedural analyses. | |||
2 | Copyright (C) 2005-2023 Free Software Foundation, Inc. | |||
3 | ||||
4 | This file is part of GCC. | |||
5 | ||||
6 | GCC is free software; you can redistribute it and/or modify it under | |||
7 | the terms of the GNU General Public License as published by the Free | |||
8 | Software Foundation; either version 3, or (at your option) any later | |||
9 | version. | |||
10 | ||||
11 | GCC is distributed in the hope that it will be useful, but WITHOUT ANY | |||
12 | WARRANTY; without even the implied warranty of MERCHANTABILITY or | |||
13 | FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |||
14 | for more details. | |||
15 | ||||
16 | You should have received a copy of the GNU General Public License | |||
17 | along with GCC; see the file COPYING3. If not see | |||
18 | <http://www.gnu.org/licenses/>. */ | |||
19 | ||||
20 | #include "config.h" | |||
21 | #include "system.h" | |||
22 | #include "coretypes.h" | |||
23 | #include "backend.h" | |||
24 | #include "rtl.h" | |||
25 | #include "tree.h" | |||
26 | #include "gimple.h" | |||
27 | #include "alloc-pool.h" | |||
28 | #include "tree-pass.h" | |||
29 | #include "ssa.h" | |||
30 | #include "tree-streamer.h" | |||
31 | #include "cgraph.h" | |||
32 | #include "diagnostic.h" | |||
33 | #include "fold-const.h" | |||
34 | #include "gimple-iterator.h" | |||
35 | #include "gimple-fold.h" | |||
36 | #include "tree-eh.h" | |||
37 | #include "calls.h" | |||
38 | #include "stor-layout.h" | |||
39 | #include "print-tree.h" | |||
40 | #include "gimplify.h" | |||
41 | #include "gimplify-me.h" | |||
42 | #include "gimple-walk.h" | |||
43 | #include "symbol-summary.h" | |||
44 | #include "ipa-prop.h" | |||
45 | #include "tree-cfg.h" | |||
46 | #include "tree-dfa.h" | |||
47 | #include "tree-inline.h" | |||
48 | #include "ipa-fnsummary.h" | |||
49 | #include "gimple-pretty-print.h" | |||
50 | #include "ipa-utils.h" | |||
51 | #include "dbgcnt.h" | |||
52 | #include "domwalk.h" | |||
53 | #include "builtins.h" | |||
54 | #include "tree-cfgcleanup.h" | |||
55 | #include "options.h" | |||
56 | #include "symtab-clones.h" | |||
57 | #include "attr-fnspec.h" | |||
58 | #include "gimple-range.h" | |||
59 | ||||
60 | /* Function summary where the parameter infos are actually stored. */ | |||
61 | ipa_node_params_t *ipa_node_params_sum = NULLnullptr; | |||
62 | ||||
63 | function_summary <ipcp_transformation *> *ipcp_transformation_sum = NULLnullptr; | |||
64 | ||||
65 | /* Edge summary for IPA-CP edge information. */ | |||
66 | ipa_edge_args_sum_t *ipa_edge_args_sum; | |||
67 | ||||
68 | /* Traits for a hash table for reusing already existing ipa_bits. */ | |||
69 | ||||
70 | struct ipa_bit_ggc_hash_traits : public ggc_cache_remove <ipa_bits *> | |||
71 | { | |||
72 | typedef ipa_bits *value_type; | |||
73 | typedef ipa_bits *compare_type; | |||
74 | static hashval_t | |||
75 | hash (const ipa_bits *p) | |||
76 | { | |||
77 | hashval_t t = (hashval_t) p->value.to_shwi (); | |||
78 | return iterative_hash_host_wide_int (p->mask.to_shwi (), t); | |||
79 | } | |||
80 | static bool | |||
81 | equal (const ipa_bits *a, const ipa_bits *b) | |||
82 | { | |||
83 | return a->value == b->value && a->mask == b->mask; | |||
84 | } | |||
85 | static const bool empty_zero_p = true; | |||
86 | static void | |||
87 | mark_empty (ipa_bits *&p) | |||
88 | { | |||
89 | p = NULLnullptr; | |||
90 | } | |||
91 | static bool | |||
92 | is_empty (const ipa_bits *p) | |||
93 | { | |||
94 | return p == NULLnullptr; | |||
95 | } | |||
96 | static bool | |||
97 | is_deleted (const ipa_bits *p) | |||
98 | { | |||
99 | return p == reinterpret_cast<const ipa_bits *> (1); | |||
100 | } | |||
101 | static void | |||
102 | mark_deleted (ipa_bits *&p) | |||
103 | { | |||
104 | p = reinterpret_cast<ipa_bits *> (1); | |||
105 | } | |||
106 | }; | |||
107 | ||||
108 | /* Hash table for avoid repeated allocations of equal ipa_bits. */ | |||
109 | static GTY ((cache)) hash_table<ipa_bit_ggc_hash_traits> *ipa_bits_hash_table; | |||
110 | ||||
111 | /* Traits for a hash table for reusing value_ranges used for IPA. Note that | |||
112 | the equiv bitmap is not hashed and is expected to be NULL. */ | |||
113 | ||||
114 | struct ipa_vr_ggc_hash_traits : public ggc_cache_remove <value_range *> | |||
115 | { | |||
116 | typedef value_range *value_type; | |||
117 | typedef value_range *compare_type; | |||
118 | static hashval_t | |||
119 | hash (const value_range *p) | |||
120 | { | |||
121 | inchash::hash hstate (p->kind ()); | |||
122 | inchash::add_expr (p->min (), hstate); | |||
123 | inchash::add_expr (p->max (), hstate); | |||
124 | return hstate.end (); | |||
125 | } | |||
126 | static bool | |||
127 | equal (const value_range *a, const value_range *b) | |||
128 | { | |||
129 | return (types_compatible_p (a->type (), b->type ()) | |||
130 | && *a == *b); | |||
131 | } | |||
132 | static const bool empty_zero_p = true; | |||
133 | static void | |||
134 | mark_empty (value_range *&p) | |||
135 | { | |||
136 | p = NULLnullptr; | |||
137 | } | |||
138 | static bool | |||
139 | is_empty (const value_range *p) | |||
140 | { | |||
141 | return p == NULLnullptr; | |||
142 | } | |||
143 | static bool | |||
144 | is_deleted (const value_range *p) | |||
145 | { | |||
146 | return p == reinterpret_cast<const value_range *> (1); | |||
147 | } | |||
148 | static void | |||
149 | mark_deleted (value_range *&p) | |||
150 | { | |||
151 | p = reinterpret_cast<value_range *> (1); | |||
152 | } | |||
153 | }; | |||
154 | ||||
155 | /* Hash table for avoid repeated allocations of equal value_ranges. */ | |||
156 | static GTY ((cache)) hash_table<ipa_vr_ggc_hash_traits> *ipa_vr_hash_table; | |||
157 | ||||
158 | /* Holders of ipa cgraph hooks: */ | |||
159 | static struct cgraph_node_hook_list *function_insertion_hook_holder; | |||
160 | ||||
161 | /* Description of a reference to an IPA constant. */ | |||
162 | struct ipa_cst_ref_desc | |||
163 | { | |||
164 | /* Edge that corresponds to the statement which took the reference. */ | |||
165 | struct cgraph_edge *cs; | |||
166 | /* Linked list of duplicates created when call graph edges are cloned. */ | |||
167 | struct ipa_cst_ref_desc *next_duplicate; | |||
168 | /* Number of references in IPA structures, IPA_UNDESCRIBED_USE if the value | |||
169 | if out of control. */ | |||
170 | int refcount; | |||
171 | }; | |||
172 | ||||
173 | /* Allocation pool for reference descriptions. */ | |||
174 | ||||
175 | static object_allocator<ipa_cst_ref_desc> ipa_refdesc_pool | |||
176 | ("IPA-PROP ref descriptions"); | |||
177 | ||||
178 | /* Return true if DECL_FUNCTION_SPECIFIC_OPTIMIZATION of the decl associated | |||
179 | with NODE should prevent us from analyzing it for the purposes of IPA-CP. */ | |||
180 | ||||
181 | static bool | |||
182 | ipa_func_spec_opts_forbid_analysis_p (struct cgraph_node *node) | |||
183 | { | |||
184 | tree fs_opts = DECL_FUNCTION_SPECIFIC_OPTIMIZATION (node->decl)((tree_check ((node->decl), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 184, __FUNCTION__, (FUNCTION_DECL)))->function_decl.function_specific_optimization ); | |||
185 | ||||
186 | if (!fs_opts) | |||
187 | return false; | |||
188 | return !opt_for_fn (node->decl, optimize)(opts_for_fn (node->decl)->x_optimize) || !opt_for_fn (node->decl, flag_ipa_cp)(opts_for_fn (node->decl)->x_flag_ipa_cp); | |||
189 | } | |||
190 | ||||
191 | /* Return index of the formal whose tree is PTREE in function which corresponds | |||
192 | to INFO. */ | |||
193 | ||||
194 | static int | |||
195 | ipa_get_param_decl_index_1 (vec<ipa_param_descriptor, va_gc> *descriptors, | |||
196 | tree ptree) | |||
197 | { | |||
198 | int i, count; | |||
199 | ||||
200 | count = vec_safe_length (descriptors); | |||
201 | for (i = 0; i < count; i++) | |||
202 | if ((*descriptors)[i].decl_or_type == ptree) | |||
203 | return i; | |||
204 | ||||
205 | return -1; | |||
206 | } | |||
207 | ||||
208 | /* Return index of the formal whose tree is PTREE in function which corresponds | |||
209 | to INFO. */ | |||
210 | ||||
211 | int | |||
212 | ipa_get_param_decl_index (class ipa_node_params *info, tree ptree) | |||
213 | { | |||
214 | return ipa_get_param_decl_index_1 (info->descriptors, ptree); | |||
215 | } | |||
216 | ||||
217 | /* Populate the param_decl field in parameter DESCRIPTORS that correspond to | |||
218 | NODE. */ | |||
219 | ||||
220 | static void | |||
221 | ipa_populate_param_decls (struct cgraph_node *node, | |||
222 | vec<ipa_param_descriptor, va_gc> &descriptors) | |||
223 | { | |||
224 | tree fndecl; | |||
225 | tree fnargs; | |||
226 | tree parm; | |||
227 | int param_num; | |||
228 | ||||
229 | fndecl = node->decl; | |||
230 | gcc_assert (gimple_has_body_p (fndecl))((void)(!(gimple_has_body_p (fndecl)) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 230, __FUNCTION__), 0 : 0)); | |||
231 | fnargs = DECL_ARGUMENTS (fndecl)((tree_check ((fndecl), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 231, __FUNCTION__, (FUNCTION_DECL)))->function_decl.arguments ); | |||
232 | param_num = 0; | |||
233 | for (parm = fnargs; parm; parm = DECL_CHAIN (parm)(((contains_struct_check (((contains_struct_check ((parm), (TS_DECL_MINIMAL ), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 233, __FUNCTION__))), (TS_COMMON), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 233, __FUNCTION__))->common.chain))) | |||
234 | { | |||
235 | descriptors[param_num].decl_or_type = parm; | |||
236 | unsigned int cost = estimate_move_cost (TREE_TYPE (parm)((contains_struct_check ((parm), (TS_TYPED), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 236, __FUNCTION__))->typed.type), true); | |||
237 | descriptors[param_num].move_cost = cost; | |||
238 | /* Watch overflow, move_cost is a bitfield. */ | |||
239 | gcc_checking_assert (cost == descriptors[param_num].move_cost)((void)(!(cost == descriptors[param_num].move_cost) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 239, __FUNCTION__), 0 : 0)); | |||
240 | param_num++; | |||
241 | } | |||
242 | } | |||
243 | ||||
244 | /* Return how many formal parameters FNDECL has. */ | |||
245 | ||||
246 | int | |||
247 | count_formal_params (tree fndecl) | |||
248 | { | |||
249 | tree parm; | |||
250 | int count = 0; | |||
251 | gcc_assert (gimple_has_body_p (fndecl))((void)(!(gimple_has_body_p (fndecl)) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 251, __FUNCTION__), 0 : 0)); | |||
252 | ||||
253 | for (parm = DECL_ARGUMENTS (fndecl)((tree_check ((fndecl), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 253, __FUNCTION__, (FUNCTION_DECL)))->function_decl.arguments ); parm; parm = DECL_CHAIN (parm)(((contains_struct_check (((contains_struct_check ((parm), (TS_DECL_MINIMAL ), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 253, __FUNCTION__))), (TS_COMMON), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 253, __FUNCTION__))->common.chain))) | |||
254 | count++; | |||
255 | ||||
256 | return count; | |||
257 | } | |||
258 | ||||
259 | /* Return the declaration of Ith formal parameter of the function corresponding | |||
260 | to INFO. Note there is no setter function as this array is built just once | |||
261 | using ipa_initialize_node_params. */ | |||
262 | ||||
263 | void | |||
264 | ipa_dump_param (FILE *file, class ipa_node_params *info, int i) | |||
265 | { | |||
266 | fprintf (file, "param #%i", i); | |||
267 | if ((*info->descriptors)[i].decl_or_type) | |||
268 | { | |||
269 | fprintf (file, " "); | |||
270 | print_generic_expr (file, (*info->descriptors)[i].decl_or_type); | |||
271 | } | |||
272 | } | |||
273 | ||||
274 | /* If necessary, allocate vector of parameter descriptors in info of NODE. | |||
275 | Return true if they were allocated, false if not. */ | |||
276 | ||||
277 | static bool | |||
278 | ipa_alloc_node_params (struct cgraph_node *node, int param_count) | |||
279 | { | |||
280 | ipa_node_params *info = ipa_node_params_sum->get_create (node); | |||
281 | ||||
282 | if (!info->descriptors && param_count) | |||
283 | { | |||
284 | vec_safe_grow_cleared (info->descriptors, param_count, true); | |||
285 | return true; | |||
286 | } | |||
287 | else | |||
288 | return false; | |||
289 | } | |||
290 | ||||
291 | /* Initialize the ipa_node_params structure associated with NODE by counting | |||
292 | the function parameters, creating the descriptors and populating their | |||
293 | param_decls. */ | |||
294 | ||||
295 | void | |||
296 | ipa_initialize_node_params (struct cgraph_node *node) | |||
297 | { | |||
298 | ipa_node_params *info = ipa_node_params_sum->get_create (node); | |||
299 | ||||
300 | if (!info->descriptors | |||
301 | && ipa_alloc_node_params (node, count_formal_params (node->decl))) | |||
302 | ipa_populate_param_decls (node, *info->descriptors); | |||
| ||||
303 | } | |||
304 | ||||
305 | /* Print the jump functions associated with call graph edge CS to file F. */ | |||
306 | ||||
307 | static void | |||
308 | ipa_print_node_jump_functions_for_edge (FILE *f, struct cgraph_edge *cs) | |||
309 | { | |||
310 | ipa_edge_args *args = ipa_edge_args_sum->get (cs); | |||
311 | int count = ipa_get_cs_argument_count (args); | |||
312 | ||||
313 | for (int i = 0; i < count; i++) | |||
314 | { | |||
315 | struct ipa_jump_func *jump_func; | |||
316 | enum jump_func_type type; | |||
317 | ||||
318 | jump_func = ipa_get_ith_jump_func (args, i); | |||
319 | type = jump_func->type; | |||
320 | ||||
321 | fprintf (f, " param %d: ", i); | |||
322 | if (type == IPA_JF_UNKNOWN) | |||
323 | fprintf (f, "UNKNOWN\n"); | |||
324 | else if (type == IPA_JF_CONST) | |||
325 | { | |||
326 | tree val = jump_func->value.constant.value; | |||
327 | fprintf (f, "CONST: "); | |||
328 | print_generic_expr (f, val); | |||
329 | if (TREE_CODE (val)((enum tree_code) (val)->base.code) == ADDR_EXPR | |||
330 | && TREE_CODE (TREE_OPERAND (val, 0))((enum tree_code) ((*((const_cast<tree*> (tree_operand_check ((val), (0), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 330, __FUNCTION__))))))->base.code) == CONST_DECL) | |||
331 | { | |||
332 | fprintf (f, " -> "); | |||
333 | print_generic_expr (f, DECL_INITIAL (TREE_OPERAND (val, 0))((contains_struct_check (((*((const_cast<tree*> (tree_operand_check ((val), (0), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 333, __FUNCTION__)))))), (TS_DECL_COMMON), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 333, __FUNCTION__))->decl_common.initial)); | |||
334 | } | |||
335 | fprintf (f, "\n"); | |||
336 | } | |||
337 | else if (type == IPA_JF_PASS_THROUGH) | |||
338 | { | |||
339 | fprintf (f, "PASS THROUGH: "); | |||
340 | fprintf (f, "%d, op %s", | |||
341 | jump_func->value.pass_through.formal_id, | |||
342 | get_tree_code_name(jump_func->value.pass_through.operation)); | |||
343 | if (jump_func->value.pass_through.operation != NOP_EXPR) | |||
344 | { | |||
345 | fprintf (f, " "); | |||
346 | print_generic_expr (f, jump_func->value.pass_through.operand); | |||
347 | } | |||
348 | if (jump_func->value.pass_through.agg_preserved) | |||
349 | fprintf (f, ", agg_preserved"); | |||
350 | fprintf (f, "\n"); | |||
351 | } | |||
352 | else if (type == IPA_JF_ANCESTOR) | |||
353 | { | |||
354 | fprintf (f, "ANCESTOR: "); | |||
355 | fprintf (f, "%d, offset " HOST_WIDE_INT_PRINT_DEC"%" "l" "d", | |||
356 | jump_func->value.ancestor.formal_id, | |||
357 | jump_func->value.ancestor.offset); | |||
358 | if (jump_func->value.ancestor.agg_preserved) | |||
359 | fprintf (f, ", agg_preserved"); | |||
360 | if (jump_func->value.ancestor.keep_null) | |||
361 | fprintf (f, ", keep_null"); | |||
362 | fprintf (f, "\n"); | |||
363 | } | |||
364 | ||||
365 | if (jump_func->agg.items) | |||
366 | { | |||
367 | struct ipa_agg_jf_item *item; | |||
368 | int j; | |||
369 | ||||
370 | fprintf (f, " Aggregate passed by %s:\n", | |||
371 | jump_func->agg.by_ref ? "reference" : "value"); | |||
372 | FOR_EACH_VEC_ELT (*jump_func->agg.items, j, item)for (j = 0; (*jump_func->agg.items).iterate ((j), &(item )); ++(j)) | |||
373 | { | |||
374 | fprintf (f, " offset: " HOST_WIDE_INT_PRINT_DEC"%" "l" "d" ", ", | |||
375 | item->offset); | |||
376 | fprintf (f, "type: "); | |||
377 | print_generic_expr (f, item->type); | |||
378 | fprintf (f, ", "); | |||
379 | if (item->jftype == IPA_JF_PASS_THROUGH) | |||
380 | fprintf (f, "PASS THROUGH: %d,", | |||
381 | item->value.pass_through.formal_id); | |||
382 | else if (item->jftype == IPA_JF_LOAD_AGG) | |||
383 | { | |||
384 | fprintf (f, "LOAD AGG: %d", | |||
385 | item->value.pass_through.formal_id); | |||
386 | fprintf (f, " [offset: " HOST_WIDE_INT_PRINT_DEC"%" "l" "d" ", by %s],", | |||
387 | item->value.load_agg.offset, | |||
388 | item->value.load_agg.by_ref ? "reference" | |||
389 | : "value"); | |||
390 | } | |||
391 | ||||
392 | if (item->jftype == IPA_JF_PASS_THROUGH | |||
393 | || item->jftype == IPA_JF_LOAD_AGG) | |||
394 | { | |||
395 | fprintf (f, " op %s", | |||
396 | get_tree_code_name (item->value.pass_through.operation)); | |||
397 | if (item->value.pass_through.operation != NOP_EXPR) | |||
398 | { | |||
399 | fprintf (f, " "); | |||
400 | print_generic_expr (f, item->value.pass_through.operand); | |||
401 | } | |||
402 | } | |||
403 | else if (item->jftype == IPA_JF_CONST) | |||
404 | { | |||
405 | fprintf (f, "CONST: "); | |||
406 | print_generic_expr (f, item->value.constant); | |||
407 | } | |||
408 | else if (item->jftype == IPA_JF_UNKNOWN) | |||
409 | fprintf (f, "UNKNOWN: " HOST_WIDE_INT_PRINT_DEC"%" "l" "d" " bits", | |||
410 | tree_to_uhwi (TYPE_SIZE (item->type)((tree_class_check ((item->type), (tcc_type), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 410, __FUNCTION__))->type_common.size))); | |||
411 | fprintf (f, "\n"); | |||
412 | } | |||
413 | } | |||
414 | ||||
415 | class ipa_polymorphic_call_context *ctx | |||
416 | = ipa_get_ith_polymorhic_call_context (args, i); | |||
417 | if (ctx && !ctx->useless_p ()) | |||
418 | { | |||
419 | fprintf (f, " Context: "); | |||
420 | ctx->dump (dump_file); | |||
421 | } | |||
422 | ||||
423 | if (jump_func->bits) | |||
424 | { | |||
425 | fprintf (f, " value: "); | |||
426 | print_hex (jump_func->bits->value, f); | |||
427 | fprintf (f, ", mask: "); | |||
428 | print_hex (jump_func->bits->mask, f); | |||
429 | fprintf (f, "\n"); | |||
430 | } | |||
431 | else | |||
432 | fprintf (f, " Unknown bits\n"); | |||
433 | ||||
434 | if (jump_func->m_vr) | |||
435 | { | |||
436 | fprintf (f, " VR "); | |||
437 | fprintf (f, "%s[", | |||
438 | (jump_func->m_vr->kind () == VR_ANTI_RANGE) ? "~" : ""); | |||
439 | print_decs (wi::to_wide (jump_func->m_vr->min ()), f); | |||
440 | fprintf (f, ", "); | |||
441 | print_decs (wi::to_wide (jump_func->m_vr->max ()), f); | |||
442 | fprintf (f, "]\n"); | |||
443 | } | |||
444 | else | |||
445 | fprintf (f, " Unknown VR\n"); | |||
446 | } | |||
447 | } | |||
448 | ||||
449 | ||||
450 | /* Print the jump functions of all arguments on all call graph edges going from | |||
451 | NODE to file F. */ | |||
452 | ||||
453 | void | |||
454 | ipa_print_node_jump_functions (FILE *f, struct cgraph_node *node) | |||
455 | { | |||
456 | struct cgraph_edge *cs; | |||
457 | ||||
458 | fprintf (f, " Jump functions of caller %s:\n", node->dump_name ()); | |||
459 | for (cs = node->callees; cs; cs = cs->next_callee) | |||
460 | { | |||
461 | ||||
462 | fprintf (f, " callsite %s -> %s : \n", | |||
463 | node->dump_name (), | |||
464 | cs->callee->dump_name ()); | |||
465 | if (!ipa_edge_args_info_available_for_edge_p (cs)) | |||
466 | fprintf (f, " no arg info\n"); | |||
467 | else | |||
468 | ipa_print_node_jump_functions_for_edge (f, cs); | |||
469 | } | |||
470 | ||||
471 | for (cs = node->indirect_calls; cs; cs = cs->next_callee) | |||
472 | { | |||
473 | class cgraph_indirect_call_info *ii; | |||
474 | ||||
475 | ii = cs->indirect_info; | |||
476 | if (ii->agg_contents) | |||
477 | fprintf (f, " indirect %s callsite, calling param %i, " | |||
478 | "offset " HOST_WIDE_INT_PRINT_DEC"%" "l" "d" ", %s", | |||
479 | ii->member_ptr ? "member ptr" : "aggregate", | |||
480 | ii->param_index, ii->offset, | |||
481 | ii->by_ref ? "by reference" : "by_value"); | |||
482 | else | |||
483 | fprintf (f, " indirect %s callsite, calling param %i, " | |||
484 | "offset " HOST_WIDE_INT_PRINT_DEC"%" "l" "d", | |||
485 | ii->polymorphic ? "polymorphic" : "simple", ii->param_index, | |||
486 | ii->offset); | |||
487 | ||||
488 | if (cs->call_stmt) | |||
489 | { | |||
490 | fprintf (f, ", for stmt "); | |||
491 | print_gimple_stmt (f, cs->call_stmt, 0, TDF_SLIM); | |||
492 | } | |||
493 | else | |||
494 | fprintf (f, "\n"); | |||
495 | if (ii->polymorphic) | |||
496 | ii->context.dump (f); | |||
497 | if (!ipa_edge_args_info_available_for_edge_p (cs)) | |||
498 | fprintf (f, " no arg info\n"); | |||
499 | else | |||
500 | ipa_print_node_jump_functions_for_edge (f, cs); | |||
501 | } | |||
502 | } | |||
503 | ||||
504 | /* Print ipa_jump_func data structures of all nodes in the call graph to F. */ | |||
505 | ||||
506 | void | |||
507 | ipa_print_all_jump_functions (FILE *f) | |||
508 | { | |||
509 | struct cgraph_node *node; | |||
510 | ||||
511 | fprintf (f, "\nJump functions:\n"); | |||
512 | FOR_EACH_FUNCTION (node)for ((node) = symtab->first_function (); (node); (node) = symtab ->next_function ((node))) | |||
513 | { | |||
514 | ipa_print_node_jump_functions (f, node); | |||
515 | } | |||
516 | } | |||
517 | ||||
518 | /* Set jfunc to be a know-really nothing jump function. */ | |||
519 | ||||
520 | static void | |||
521 | ipa_set_jf_unknown (struct ipa_jump_func *jfunc) | |||
522 | { | |||
523 | jfunc->type = IPA_JF_UNKNOWN; | |||
524 | } | |||
525 | ||||
526 | /* Set JFUNC to be a copy of another jmp (to be used by jump function | |||
527 | combination code). The two functions will share their rdesc. */ | |||
528 | ||||
529 | static void | |||
530 | ipa_set_jf_cst_copy (struct ipa_jump_func *dst, | |||
531 | struct ipa_jump_func *src) | |||
532 | ||||
533 | { | |||
534 | gcc_checking_assert (src->type == IPA_JF_CONST)((void)(!(src->type == IPA_JF_CONST) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 534, __FUNCTION__), 0 : 0)); | |||
535 | dst->type = IPA_JF_CONST; | |||
536 | dst->value.constant = src->value.constant; | |||
537 | } | |||
538 | ||||
539 | /* Set JFUNC to be a constant jmp function. */ | |||
540 | ||||
541 | static void | |||
542 | ipa_set_jf_constant (struct ipa_jump_func *jfunc, tree constant, | |||
543 | struct cgraph_edge *cs) | |||
544 | { | |||
545 | jfunc->type = IPA_JF_CONST; | |||
546 | jfunc->value.constant.value = unshare_expr_without_location (constant); | |||
547 | ||||
548 | if (TREE_CODE (constant)((enum tree_code) (constant)->base.code) == ADDR_EXPR | |||
549 | && (TREE_CODE (TREE_OPERAND (constant, 0))((enum tree_code) ((*((const_cast<tree*> (tree_operand_check ((constant), (0), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 549, __FUNCTION__))))))->base.code) == FUNCTION_DECL | |||
550 | || (TREE_CODE (TREE_OPERAND (constant, 0))((enum tree_code) ((*((const_cast<tree*> (tree_operand_check ((constant), (0), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 550, __FUNCTION__))))))->base.code) == VAR_DECL | |||
551 | && TREE_STATIC (TREE_OPERAND (constant, 0))(((*((const_cast<tree*> (tree_operand_check ((constant) , (0), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 551, __FUNCTION__))))))->base.static_flag)))) | |||
552 | { | |||
553 | struct ipa_cst_ref_desc *rdesc; | |||
554 | ||||
555 | rdesc = ipa_refdesc_pool.allocate (); | |||
556 | rdesc->cs = cs; | |||
557 | rdesc->next_duplicate = NULLnullptr; | |||
558 | rdesc->refcount = 1; | |||
559 | jfunc->value.constant.rdesc = rdesc; | |||
560 | } | |||
561 | else | |||
562 | jfunc->value.constant.rdesc = NULLnullptr; | |||
563 | } | |||
564 | ||||
565 | /* Set JFUNC to be a simple pass-through jump function. */ | |||
566 | static void | |||
567 | ipa_set_jf_simple_pass_through (struct ipa_jump_func *jfunc, int formal_id, | |||
568 | bool agg_preserved) | |||
569 | { | |||
570 | jfunc->type = IPA_JF_PASS_THROUGH; | |||
571 | jfunc->value.pass_through.operand = NULL_TREE(tree) nullptr; | |||
572 | jfunc->value.pass_through.formal_id = formal_id; | |||
573 | jfunc->value.pass_through.operation = NOP_EXPR; | |||
574 | jfunc->value.pass_through.agg_preserved = agg_preserved; | |||
575 | } | |||
576 | ||||
577 | /* Set JFUNC to be an unary pass through jump function. */ | |||
578 | ||||
579 | static void | |||
580 | ipa_set_jf_unary_pass_through (struct ipa_jump_func *jfunc, int formal_id, | |||
581 | enum tree_code operation) | |||
582 | { | |||
583 | jfunc->type = IPA_JF_PASS_THROUGH; | |||
584 | jfunc->value.pass_through.operand = NULL_TREE(tree) nullptr; | |||
585 | jfunc->value.pass_through.formal_id = formal_id; | |||
586 | jfunc->value.pass_through.operation = operation; | |||
587 | jfunc->value.pass_through.agg_preserved = false; | |||
588 | } | |||
589 | /* Set JFUNC to be an arithmetic pass through jump function. */ | |||
590 | ||||
591 | static void | |||
592 | ipa_set_jf_arith_pass_through (struct ipa_jump_func *jfunc, int formal_id, | |||
593 | tree operand, enum tree_code operation) | |||
594 | { | |||
595 | jfunc->type = IPA_JF_PASS_THROUGH; | |||
596 | jfunc->value.pass_through.operand = unshare_expr_without_location (operand); | |||
597 | jfunc->value.pass_through.formal_id = formal_id; | |||
598 | jfunc->value.pass_through.operation = operation; | |||
599 | jfunc->value.pass_through.agg_preserved = false; | |||
600 | } | |||
601 | ||||
602 | /* Set JFUNC to be an ancestor jump function. */ | |||
603 | ||||
604 | static void | |||
605 | ipa_set_ancestor_jf (struct ipa_jump_func *jfunc, HOST_WIDE_INTlong offset, | |||
606 | int formal_id, bool agg_preserved, bool keep_null) | |||
607 | { | |||
608 | jfunc->type = IPA_JF_ANCESTOR; | |||
609 | jfunc->value.ancestor.formal_id = formal_id; | |||
610 | jfunc->value.ancestor.offset = offset; | |||
611 | jfunc->value.ancestor.agg_preserved = agg_preserved; | |||
612 | jfunc->value.ancestor.keep_null = keep_null; | |||
613 | } | |||
614 | ||||
615 | /* Get IPA BB information about the given BB. FBI is the context of analyzis | |||
616 | of this function body. */ | |||
617 | ||||
618 | static struct ipa_bb_info * | |||
619 | ipa_get_bb_info (struct ipa_func_body_info *fbi, basic_block bb) | |||
620 | { | |||
621 | gcc_checking_assert (fbi)((void)(!(fbi) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 621, __FUNCTION__), 0 : 0)); | |||
622 | return &fbi->bb_infos[bb->index]; | |||
623 | } | |||
624 | ||||
625 | /* Structure to be passed in between detect_type_change and | |||
626 | check_stmt_for_type_change. */ | |||
627 | ||||
628 | struct prop_type_change_info | |||
629 | { | |||
630 | /* Offset into the object where there is the virtual method pointer we are | |||
631 | looking for. */ | |||
632 | HOST_WIDE_INTlong offset; | |||
633 | /* The declaration or SSA_NAME pointer of the base that we are checking for | |||
634 | type change. */ | |||
635 | tree object; | |||
636 | /* Set to true if dynamic type change has been detected. */ | |||
637 | bool type_maybe_changed; | |||
638 | }; | |||
639 | ||||
640 | /* Return true if STMT can modify a virtual method table pointer. | |||
641 | ||||
642 | This function makes special assumptions about both constructors and | |||
643 | destructors which are all the functions that are allowed to alter the VMT | |||
644 | pointers. It assumes that destructors begin with assignment into all VMT | |||
645 | pointers and that constructors essentially look in the following way: | |||
646 | ||||
647 | 1) The very first thing they do is that they call constructors of ancestor | |||
648 | sub-objects that have them. | |||
649 | ||||
650 | 2) Then VMT pointers of this and all its ancestors is set to new values | |||
651 | corresponding to the type corresponding to the constructor. | |||
652 | ||||
653 | 3) Only afterwards, other stuff such as constructor of member sub-objects | |||
654 | and the code written by the user is run. Only this may include calling | |||
655 | virtual functions, directly or indirectly. | |||
656 | ||||
657 | There is no way to call a constructor of an ancestor sub-object in any | |||
658 | other way. | |||
659 | ||||
660 | This means that we do not have to care whether constructors get the correct | |||
661 | type information because they will always change it (in fact, if we define | |||
662 | the type to be given by the VMT pointer, it is undefined). | |||
663 | ||||
664 | The most important fact to derive from the above is that if, for some | |||
665 | statement in the section 3, we try to detect whether the dynamic type has | |||
666 | changed, we can safely ignore all calls as we examine the function body | |||
667 | backwards until we reach statements in section 2 because these calls cannot | |||
668 | be ancestor constructors or destructors (if the input is not bogus) and so | |||
669 | do not change the dynamic type (this holds true only for automatically | |||
670 | allocated objects but at the moment we devirtualize only these). We then | |||
671 | must detect that statements in section 2 change the dynamic type and can try | |||
672 | to derive the new type. That is enough and we can stop, we will never see | |||
673 | the calls into constructors of sub-objects in this code. Therefore we can | |||
674 | safely ignore all call statements that we traverse. | |||
675 | */ | |||
676 | ||||
677 | static bool | |||
678 | stmt_may_be_vtbl_ptr_store (gimple *stmt) | |||
679 | { | |||
680 | if (is_gimple_call (stmt)) | |||
681 | return false; | |||
682 | if (gimple_clobber_p (stmt)) | |||
683 | return false; | |||
684 | else if (is_gimple_assign (stmt)) | |||
685 | { | |||
686 | tree lhs = gimple_assign_lhs (stmt); | |||
687 | ||||
688 | if (!AGGREGATE_TYPE_P (TREE_TYPE (lhs))(((enum tree_code) (((contains_struct_check ((lhs), (TS_TYPED ), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 688, __FUNCTION__))->typed.type))->base.code) == ARRAY_TYPE || (((enum tree_code) (((contains_struct_check ((lhs), (TS_TYPED ), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 688, __FUNCTION__))->typed.type))->base.code) == RECORD_TYPE || ((enum tree_code) (((contains_struct_check ((lhs), (TS_TYPED ), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 688, __FUNCTION__))->typed.type))->base.code) == UNION_TYPE || ((enum tree_code) (((contains_struct_check ((lhs), (TS_TYPED ), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 688, __FUNCTION__))->typed.type))->base.code) == QUAL_UNION_TYPE ))) | |||
689 | { | |||
690 | if (flag_strict_aliasingglobal_options.x_flag_strict_aliasing | |||
691 | && !POINTER_TYPE_P (TREE_TYPE (lhs))(((enum tree_code) (((contains_struct_check ((lhs), (TS_TYPED ), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 691, __FUNCTION__))->typed.type))->base.code) == POINTER_TYPE || ((enum tree_code) (((contains_struct_check ((lhs), (TS_TYPED ), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 691, __FUNCTION__))->typed.type))->base.code) == REFERENCE_TYPE )) | |||
692 | return false; | |||
693 | ||||
694 | if (TREE_CODE (lhs)((enum tree_code) (lhs)->base.code) == COMPONENT_REF | |||
695 | && !DECL_VIRTUAL_P (TREE_OPERAND (lhs, 1))((contains_struct_check (((*((const_cast<tree*> (tree_operand_check ((lhs), (1), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 695, __FUNCTION__)))))), (TS_DECL_COMMON), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 695, __FUNCTION__))->decl_common.virtual_flag)) | |||
696 | return false; | |||
697 | /* In the future we might want to use get_ref_base_and_extent to find | |||
698 | if there is a field corresponding to the offset and if so, proceed | |||
699 | almost like if it was a component ref. */ | |||
700 | } | |||
701 | } | |||
702 | return true; | |||
703 | } | |||
704 | ||||
705 | /* Callback of walk_aliased_vdefs and a helper function for detect_type_change | |||
706 | to check whether a particular statement may modify the virtual table | |||
707 | pointerIt stores its result into DATA, which points to a | |||
708 | prop_type_change_info structure. */ | |||
709 | ||||
710 | static bool | |||
711 | check_stmt_for_type_change (ao_ref *ao ATTRIBUTE_UNUSED__attribute__ ((__unused__)), tree vdef, void *data) | |||
712 | { | |||
713 | gimple *stmt = SSA_NAME_DEF_STMT (vdef)(tree_check ((vdef), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 713, __FUNCTION__, (SSA_NAME)))->ssa_name.def_stmt; | |||
714 | struct prop_type_change_info *tci = (struct prop_type_change_info *) data; | |||
715 | ||||
716 | if (stmt_may_be_vtbl_ptr_store (stmt)) | |||
717 | { | |||
718 | tci->type_maybe_changed = true; | |||
719 | return true; | |||
720 | } | |||
721 | else | |||
722 | return false; | |||
723 | } | |||
724 | ||||
725 | /* See if ARG is PARAM_DECl describing instance passed by pointer | |||
726 | or reference in FUNCTION. Return false if the dynamic type may change | |||
727 | in between beggining of the function until CALL is invoked. | |||
728 | ||||
729 | Generally functions are not allowed to change type of such instances, | |||
730 | but they call destructors. We assume that methods cannot destroy the THIS | |||
731 | pointer. Also as a special cases, constructor and destructors may change | |||
732 | type of the THIS pointer. */ | |||
733 | ||||
734 | static bool | |||
735 | param_type_may_change_p (tree function, tree arg, gimple *call) | |||
736 | { | |||
737 | /* Pure functions cannot do any changes on the dynamic type; | |||
738 | that require writting to memory. */ | |||
739 | if (flags_from_decl_or_type (function) & (ECF_PURE(1 << 1) | ECF_CONST(1 << 0))) | |||
740 | return false; | |||
741 | /* We need to check if we are within inlined consturctor | |||
742 | or destructor (ideally we would have way to check that the | |||
743 | inline cdtor is actually working on ARG, but we don't have | |||
744 | easy tie on this, so punt on all non-pure cdtors. | |||
745 | We may also record the types of cdtors and once we know type | |||
746 | of the instance match them. | |||
747 | ||||
748 | Also code unification optimizations may merge calls from | |||
749 | different blocks making return values unreliable. So | |||
750 | do nothing during late optimization. */ | |||
751 | if (DECL_STRUCT_FUNCTION (function)((tree_check ((function), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 751, __FUNCTION__, (FUNCTION_DECL)))->function_decl.f)->after_inlining) | |||
752 | return true; | |||
753 | if (TREE_CODE (arg)((enum tree_code) (arg)->base.code) == SSA_NAME | |||
754 | && SSA_NAME_IS_DEFAULT_DEF (arg)(tree_check ((arg), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 754, __FUNCTION__, (SSA_NAME)))->base.default_def_flag | |||
755 | && TREE_CODE (SSA_NAME_VAR (arg))((enum tree_code) (((tree_check ((arg), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 755, __FUNCTION__, (SSA_NAME)))->ssa_name.var == (tree) nullptr || ((enum tree_code) ((arg)->ssa_name.var)->base.code) == IDENTIFIER_NODE ? (tree) nullptr : (arg)->ssa_name.var ))->base.code) == PARM_DECL) | |||
756 | { | |||
757 | /* Normal (non-THIS) argument. */ | |||
758 | if ((SSA_NAME_VAR (arg)((tree_check ((arg), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 758, __FUNCTION__, (SSA_NAME)))->ssa_name.var == (tree) nullptr || ((enum tree_code) ((arg)->ssa_name.var)->base.code) == IDENTIFIER_NODE ? (tree) nullptr : (arg)->ssa_name.var ) != DECL_ARGUMENTS (function)((tree_check ((function), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 758, __FUNCTION__, (FUNCTION_DECL)))->function_decl.arguments ) | |||
759 | || TREE_CODE (TREE_TYPE (function))((enum tree_code) (((contains_struct_check ((function), (TS_TYPED ), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 759, __FUNCTION__))->typed.type))->base.code) != METHOD_TYPE) | |||
760 | /* THIS pointer of an method - here we want to watch constructors | |||
761 | and destructors as those definitely may change the dynamic | |||
762 | type. */ | |||
763 | || (TREE_CODE (TREE_TYPE (function))((enum tree_code) (((contains_struct_check ((function), (TS_TYPED ), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 763, __FUNCTION__))->typed.type))->base.code) == METHOD_TYPE | |||
764 | && !DECL_CXX_CONSTRUCTOR_P (function)((tree_check ((function), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 764, __FUNCTION__, (FUNCTION_DECL)))->decl_with_vis.cxx_constructor ) | |||
765 | && !DECL_CXX_DESTRUCTOR_P (function)((tree_check ((function), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 765, __FUNCTION__, (FUNCTION_DECL)))->decl_with_vis.cxx_destructor ) | |||
766 | && (SSA_NAME_VAR (arg)((tree_check ((arg), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 766, __FUNCTION__, (SSA_NAME)))->ssa_name.var == (tree) nullptr || ((enum tree_code) ((arg)->ssa_name.var)->base.code) == IDENTIFIER_NODE ? (tree) nullptr : (arg)->ssa_name.var ) == DECL_ARGUMENTS (function)((tree_check ((function), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 766, __FUNCTION__, (FUNCTION_DECL)))->function_decl.arguments )))) | |||
767 | { | |||
768 | /* Walk the inline stack and watch out for ctors/dtors. */ | |||
769 | for (tree block = gimple_block (call); block && TREE_CODE (block)((enum tree_code) (block)->base.code) == BLOCK; | |||
770 | block = BLOCK_SUPERCONTEXT (block)((tree_check ((block), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 770, __FUNCTION__, (BLOCK)))->block.supercontext)) | |||
771 | if (inlined_polymorphic_ctor_dtor_block_p (block, false)) | |||
772 | return true; | |||
773 | return false; | |||
774 | } | |||
775 | } | |||
776 | return true; | |||
777 | } | |||
778 | ||||
779 | /* Detect whether the dynamic type of ARG of COMP_TYPE has changed (before | |||
780 | callsite CALL) by looking for assignments to its virtual table pointer. If | |||
781 | it is, return true. ARG is the object itself (not a pointer | |||
782 | to it, unless dereferenced). BASE is the base of the memory access as | |||
783 | returned by get_ref_base_and_extent, as is the offset. | |||
784 | ||||
785 | This is helper function for detect_type_change and detect_type_change_ssa | |||
786 | that does the heavy work which is usually unnecesary. */ | |||
787 | ||||
788 | static bool | |||
789 | detect_type_change_from_memory_writes (ipa_func_body_info *fbi, tree arg, | |||
790 | tree base, tree comp_type, gcall *call, | |||
791 | HOST_WIDE_INTlong offset) | |||
792 | { | |||
793 | struct prop_type_change_info tci; | |||
794 | ao_ref ao; | |||
795 | ||||
796 | gcc_checking_assert (DECL_P (arg)((void)(!((tree_code_type_tmpl <0>::tree_code_type[(int ) (((enum tree_code) (arg)->base.code))] == tcc_declaration ) || ((enum tree_code) (arg)->base.code) == MEM_REF || handled_component_p (arg)) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 798, __FUNCTION__), 0 : 0)) | |||
797 | || TREE_CODE (arg) == MEM_REF((void)(!((tree_code_type_tmpl <0>::tree_code_type[(int ) (((enum tree_code) (arg)->base.code))] == tcc_declaration ) || ((enum tree_code) (arg)->base.code) == MEM_REF || handled_component_p (arg)) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 798, __FUNCTION__), 0 : 0)) | |||
798 | || handled_component_p (arg))((void)(!((tree_code_type_tmpl <0>::tree_code_type[(int ) (((enum tree_code) (arg)->base.code))] == tcc_declaration ) || ((enum tree_code) (arg)->base.code) == MEM_REF || handled_component_p (arg)) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 798, __FUNCTION__), 0 : 0)); | |||
799 | ||||
800 | comp_type = TYPE_MAIN_VARIANT (comp_type)((tree_class_check ((comp_type), (tcc_type), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 800, __FUNCTION__))->type_common.main_variant); | |||
801 | ||||
802 | /* Const calls cannot call virtual methods through VMT and so type changes do | |||
803 | not matter. */ | |||
804 | if (!flag_devirtualizeglobal_options.x_flag_devirtualize || !gimple_vuse (call) | |||
805 | /* Be sure expected_type is polymorphic. */ | |||
806 | || !comp_type | |||
807 | || TREE_CODE (comp_type)((enum tree_code) (comp_type)->base.code) != RECORD_TYPE | |||
808 | || !TYPE_BINFO (TYPE_MAIN_VARIANT (comp_type))((tree_check3 ((((tree_class_check ((comp_type), (tcc_type), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 808, __FUNCTION__))->type_common.main_variant)), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 808, __FUNCTION__, (RECORD_TYPE), (UNION_TYPE), (QUAL_UNION_TYPE )))->type_non_common.maxval) | |||
809 | || !BINFO_VTABLE (TYPE_BINFO (TYPE_MAIN_VARIANT (comp_type)))((tree_check ((((tree_check3 ((((tree_class_check ((comp_type ), (tcc_type), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 809, __FUNCTION__))->type_common.main_variant)), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 809, __FUNCTION__, (RECORD_TYPE), (UNION_TYPE), (QUAL_UNION_TYPE )))->type_non_common.maxval)), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 809, __FUNCTION__, (TREE_BINFO)))->binfo.vtable)) | |||
810 | return true; | |||
811 | ||||
812 | if (fbi->aa_walk_budget == 0) | |||
813 | return false; | |||
814 | ||||
815 | ao_ref_init (&ao, arg); | |||
816 | ao.base = base; | |||
817 | ao.offset = offset; | |||
818 | ao.size = POINTER_SIZE(((global_options.x_ix86_isa_flags & (1UL << 58)) != 0) ? 32 : ((8) * (((global_options.x_ix86_isa_flags & (1UL << 1)) != 0) ? 8 : 4))); | |||
819 | ao.max_size = ao.size; | |||
820 | ||||
821 | tci.offset = offset; | |||
822 | tci.object = get_base_address (arg); | |||
823 | tci.type_maybe_changed = false; | |||
824 | ||||
825 | int walked | |||
826 | = walk_aliased_vdefs (&ao, gimple_vuse (call), check_stmt_for_type_change, | |||
827 | &tci, NULLnullptr, NULLnullptr, fbi->aa_walk_budget); | |||
828 | if (walked >= 0) | |||
829 | fbi->aa_walk_budget -= walked; | |||
830 | else | |||
831 | fbi->aa_walk_budget = 0; | |||
832 | ||||
833 | if (walked >= 0 && !tci.type_maybe_changed) | |||
834 | return false; | |||
835 | ||||
836 | return true; | |||
837 | } | |||
838 | ||||
839 | /* Detect whether the dynamic type of ARG of COMP_TYPE may have changed. | |||
840 | If it is, return true. ARG is the object itself (not a pointer | |||
841 | to it, unless dereferenced). BASE is the base of the memory access as | |||
842 | returned by get_ref_base_and_extent, as is the offset. */ | |||
843 | ||||
844 | static bool | |||
845 | detect_type_change (ipa_func_body_info *fbi, tree arg, tree base, | |||
846 | tree comp_type, gcall *call, | |||
847 | HOST_WIDE_INTlong offset) | |||
848 | { | |||
849 | if (!flag_devirtualizeglobal_options.x_flag_devirtualize) | |||
850 | return false; | |||
851 | ||||
852 | if (TREE_CODE (base)((enum tree_code) (base)->base.code) == MEM_REF | |||
853 | && !param_type_may_change_p (current_function_decl, | |||
854 | TREE_OPERAND (base, 0)(*((const_cast<tree*> (tree_operand_check ((base), (0), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 854, __FUNCTION__))))), | |||
855 | call)) | |||
856 | return false; | |||
857 | return detect_type_change_from_memory_writes (fbi, arg, base, comp_type, | |||
858 | call, offset); | |||
859 | } | |||
860 | ||||
861 | /* Like detect_type_change but ARG is supposed to be a non-dereferenced pointer | |||
862 | SSA name (its dereference will become the base and the offset is assumed to | |||
863 | be zero). */ | |||
864 | ||||
865 | static bool | |||
866 | detect_type_change_ssa (ipa_func_body_info *fbi, tree arg, tree comp_type, | |||
867 | gcall *call) | |||
868 | { | |||
869 | gcc_checking_assert (TREE_CODE (arg) == SSA_NAME)((void)(!(((enum tree_code) (arg)->base.code) == SSA_NAME) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 869, __FUNCTION__), 0 : 0)); | |||
870 | if (!flag_devirtualizeglobal_options.x_flag_devirtualize | |||
871 | || !POINTER_TYPE_P (TREE_TYPE (arg))(((enum tree_code) (((contains_struct_check ((arg), (TS_TYPED ), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 871, __FUNCTION__))->typed.type))->base.code) == POINTER_TYPE || ((enum tree_code) (((contains_struct_check ((arg), (TS_TYPED ), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 871, __FUNCTION__))->typed.type))->base.code) == REFERENCE_TYPE )) | |||
872 | return false; | |||
873 | ||||
874 | if (!param_type_may_change_p (current_function_decl, arg, call)) | |||
875 | return false; | |||
876 | ||||
877 | arg = build2 (MEM_REF, ptr_type_nodeglobal_trees[TI_PTR_TYPE], arg, | |||
878 | build_int_cst (ptr_type_nodeglobal_trees[TI_PTR_TYPE], 0)); | |||
879 | ||||
880 | return detect_type_change_from_memory_writes (fbi, arg, arg, comp_type, | |||
881 | call, 0); | |||
882 | } | |||
883 | ||||
884 | /* Callback of walk_aliased_vdefs. Flags that it has been invoked to the | |||
885 | boolean variable pointed to by DATA. */ | |||
886 | ||||
887 | static bool | |||
888 | mark_modified (ao_ref *ao ATTRIBUTE_UNUSED__attribute__ ((__unused__)), tree vdef ATTRIBUTE_UNUSED__attribute__ ((__unused__)), | |||
889 | void *data) | |||
890 | { | |||
891 | bool *b = (bool *) data; | |||
892 | *b = true; | |||
893 | return true; | |||
894 | } | |||
895 | ||||
896 | /* Find the nearest valid aa status for parameter specified by INDEX that | |||
897 | dominates BB. */ | |||
898 | ||||
899 | static struct ipa_param_aa_status * | |||
900 | find_dominating_aa_status (struct ipa_func_body_info *fbi, basic_block bb, | |||
901 | int index) | |||
902 | { | |||
903 | while (true) | |||
904 | { | |||
905 | bb = get_immediate_dominator (CDI_DOMINATORS, bb); | |||
906 | if (!bb) | |||
907 | return NULLnullptr; | |||
908 | struct ipa_bb_info *bi = ipa_get_bb_info (fbi, bb); | |||
909 | if (!bi->param_aa_statuses.is_empty () | |||
910 | && bi->param_aa_statuses[index].valid) | |||
911 | return &bi->param_aa_statuses[index]; | |||
912 | } | |||
913 | } | |||
914 | ||||
915 | /* Get AA status structure for the given BB and parameter with INDEX. Allocate | |||
916 | structures and/or intialize the result with a dominating description as | |||
917 | necessary. */ | |||
918 | ||||
919 | static struct ipa_param_aa_status * | |||
920 | parm_bb_aa_status_for_bb (struct ipa_func_body_info *fbi, basic_block bb, | |||
921 | int index) | |||
922 | { | |||
923 | gcc_checking_assert (fbi)((void)(!(fbi) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 923, __FUNCTION__), 0 : 0)); | |||
924 | struct ipa_bb_info *bi = ipa_get_bb_info (fbi, bb); | |||
925 | if (bi->param_aa_statuses.is_empty ()) | |||
926 | bi->param_aa_statuses.safe_grow_cleared (fbi->param_count, true); | |||
927 | struct ipa_param_aa_status *paa = &bi->param_aa_statuses[index]; | |||
928 | if (!paa->valid) | |||
929 | { | |||
930 | gcc_checking_assert (!paa->parm_modified((void)(!(!paa->parm_modified && !paa->ref_modified && !paa->pt_modified) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 932, __FUNCTION__), 0 : 0)) | |||
931 | && !paa->ref_modified((void)(!(!paa->parm_modified && !paa->ref_modified && !paa->pt_modified) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 932, __FUNCTION__), 0 : 0)) | |||
932 | && !paa->pt_modified)((void)(!(!paa->parm_modified && !paa->ref_modified && !paa->pt_modified) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 932, __FUNCTION__), 0 : 0)); | |||
933 | struct ipa_param_aa_status *dom_paa; | |||
934 | dom_paa = find_dominating_aa_status (fbi, bb, index); | |||
935 | if (dom_paa) | |||
936 | *paa = *dom_paa; | |||
937 | else | |||
938 | paa->valid = true; | |||
939 | } | |||
940 | ||||
941 | return paa; | |||
942 | } | |||
943 | ||||
944 | /* Return true if a load from a formal parameter PARM_LOAD is known to retrieve | |||
945 | a value known not to be modified in this function before reaching the | |||
946 | statement STMT. FBI holds information about the function we have so far | |||
947 | gathered but do not survive the summary building stage. */ | |||
948 | ||||
949 | static bool | |||
950 | parm_preserved_before_stmt_p (struct ipa_func_body_info *fbi, int index, | |||
951 | gimple *stmt, tree parm_load) | |||
952 | { | |||
953 | struct ipa_param_aa_status *paa; | |||
954 | bool modified = false; | |||
955 | ao_ref refd; | |||
956 | ||||
957 | tree base = get_base_address (parm_load); | |||
958 | gcc_assert (TREE_CODE (base) == PARM_DECL)((void)(!(((enum tree_code) (base)->base.code) == PARM_DECL ) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 958, __FUNCTION__), 0 : 0)); | |||
959 | if (TREE_READONLY (base)((non_type_check ((base), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 959, __FUNCTION__))->base.readonly_flag)) | |||
960 | return true; | |||
961 | ||||
962 | gcc_checking_assert (fbi)((void)(!(fbi) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 962, __FUNCTION__), 0 : 0)); | |||
963 | paa = parm_bb_aa_status_for_bb (fbi, gimple_bb (stmt), index); | |||
964 | if (paa->parm_modified || fbi->aa_walk_budget == 0) | |||
965 | return false; | |||
966 | ||||
967 | gcc_checking_assert (gimple_vuse (stmt) != NULL_TREE)((void)(!(gimple_vuse (stmt) != (tree) nullptr) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 967, __FUNCTION__), 0 : 0)); | |||
968 | ao_ref_init (&refd, parm_load); | |||
969 | int walked = walk_aliased_vdefs (&refd, gimple_vuse (stmt), mark_modified, | |||
970 | &modified, NULLnullptr, NULLnullptr, | |||
971 | fbi->aa_walk_budget); | |||
972 | if (walked < 0) | |||
973 | { | |||
974 | modified = true; | |||
975 | fbi->aa_walk_budget = 0; | |||
976 | } | |||
977 | else | |||
978 | fbi->aa_walk_budget -= walked; | |||
979 | if (paa && modified) | |||
980 | paa->parm_modified = true; | |||
981 | return !modified; | |||
982 | } | |||
983 | ||||
984 | /* If STMT is an assignment that loads a value from an parameter declaration, | |||
985 | return the index of the parameter in ipa_node_params which has not been | |||
986 | modified. Otherwise return -1. */ | |||
987 | ||||
988 | static int | |||
989 | load_from_unmodified_param (struct ipa_func_body_info *fbi, | |||
990 | vec<ipa_param_descriptor, va_gc> *descriptors, | |||
991 | gimple *stmt) | |||
992 | { | |||
993 | int index; | |||
994 | tree op1; | |||
995 | ||||
996 | if (!gimple_assign_single_p (stmt)) | |||
997 | return -1; | |||
998 | ||||
999 | op1 = gimple_assign_rhs1 (stmt); | |||
1000 | if (TREE_CODE (op1)((enum tree_code) (op1)->base.code) != PARM_DECL) | |||
1001 | return -1; | |||
1002 | ||||
1003 | index = ipa_get_param_decl_index_1 (descriptors, op1); | |||
1004 | if (index < 0 | |||
1005 | || !parm_preserved_before_stmt_p (fbi, index, stmt, op1)) | |||
1006 | return -1; | |||
1007 | ||||
1008 | return index; | |||
1009 | } | |||
1010 | ||||
1011 | /* Return true if memory reference REF (which must be a load through parameter | |||
1012 | with INDEX) loads data that are known to be unmodified in this function | |||
1013 | before reaching statement STMT. */ | |||
1014 | ||||
1015 | static bool | |||
1016 | parm_ref_data_preserved_p (struct ipa_func_body_info *fbi, | |||
1017 | int index, gimple *stmt, tree ref) | |||
1018 | { | |||
1019 | struct ipa_param_aa_status *paa; | |||
1020 | bool modified = false; | |||
1021 | ao_ref refd; | |||
1022 | ||||
1023 | gcc_checking_assert (fbi)((void)(!(fbi) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 1023, __FUNCTION__), 0 : 0)); | |||
1024 | paa = parm_bb_aa_status_for_bb (fbi, gimple_bb (stmt), index); | |||
1025 | if (paa->ref_modified || fbi->aa_walk_budget == 0) | |||
1026 | return false; | |||
1027 | ||||
1028 | gcc_checking_assert (gimple_vuse (stmt))((void)(!(gimple_vuse (stmt)) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 1028, __FUNCTION__), 0 : 0)); | |||
1029 | ao_ref_init (&refd, ref); | |||
1030 | int walked = walk_aliased_vdefs (&refd, gimple_vuse (stmt), mark_modified, | |||
1031 | &modified, NULLnullptr, NULLnullptr, | |||
1032 | fbi->aa_walk_budget); | |||
1033 | if (walked < 0) | |||
1034 | { | |||
1035 | modified = true; | |||
1036 | fbi->aa_walk_budget = 0; | |||
1037 | } | |||
1038 | else | |||
1039 | fbi->aa_walk_budget -= walked; | |||
1040 | if (modified) | |||
1041 | paa->ref_modified = true; | |||
1042 | return !modified; | |||
1043 | } | |||
1044 | ||||
1045 | /* Return true if the data pointed to by PARM (which is a parameter with INDEX) | |||
1046 | is known to be unmodified in this function before reaching call statement | |||
1047 | CALL into which it is passed. FBI describes the function body. */ | |||
1048 | ||||
1049 | static bool | |||
1050 | parm_ref_data_pass_through_p (struct ipa_func_body_info *fbi, int index, | |||
1051 | gimple *call, tree parm) | |||
1052 | { | |||
1053 | bool modified = false; | |||
1054 | ao_ref refd; | |||
1055 | ||||
1056 | /* It's unnecessary to calculate anything about memory contnets for a const | |||
1057 | function because it is not goin to use it. But do not cache the result | |||
1058 | either. Also, no such calculations for non-pointers. */ | |||
1059 | if (!gimple_vuse (call) | |||
1060 | || !POINTER_TYPE_P (TREE_TYPE (parm))(((enum tree_code) (((contains_struct_check ((parm), (TS_TYPED ), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 1060, __FUNCTION__))->typed.type))->base.code) == POINTER_TYPE || ((enum tree_code) (((contains_struct_check ((parm), (TS_TYPED ), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 1060, __FUNCTION__))->typed.type))->base.code) == REFERENCE_TYPE )) | |||
1061 | return false; | |||
1062 | ||||
1063 | struct ipa_param_aa_status *paa = parm_bb_aa_status_for_bb (fbi, | |||
1064 | gimple_bb (call), | |||
1065 | index); | |||
1066 | if (paa->pt_modified || fbi->aa_walk_budget == 0) | |||
1067 | return false; | |||
1068 | ||||
1069 | ao_ref_init_from_ptr_and_size (&refd, parm, NULL_TREE(tree) nullptr); | |||
1070 | int walked = walk_aliased_vdefs (&refd, gimple_vuse (call), mark_modified, | |||
1071 | &modified, NULLnullptr, NULLnullptr, | |||
1072 | fbi->aa_walk_budget); | |||
1073 | if (walked < 0) | |||
1074 | { | |||
1075 | fbi->aa_walk_budget = 0; | |||
1076 | modified = true; | |||
1077 | } | |||
1078 | else | |||
1079 | fbi->aa_walk_budget -= walked; | |||
1080 | if (modified) | |||
1081 | paa->pt_modified = true; | |||
1082 | return !modified; | |||
1083 | } | |||
1084 | ||||
1085 | /* Return true if we can prove that OP is a memory reference loading | |||
1086 | data from an aggregate passed as a parameter. | |||
1087 | ||||
1088 | The function works in two modes. If GUARANTEED_UNMODIFIED is NULL, it return | |||
1089 | false if it cannot prove that the value has not been modified before the | |||
1090 | load in STMT. If GUARANTEED_UNMODIFIED is not NULL, it will return true even | |||
1091 | if it cannot prove the value has not been modified, in that case it will | |||
1092 | store false to *GUARANTEED_UNMODIFIED, otherwise it will store true there. | |||
1093 | ||||
1094 | INFO and PARMS_AINFO describe parameters of the current function (but the | |||
1095 | latter can be NULL), STMT is the load statement. If function returns true, | |||
1096 | *INDEX_P, *OFFSET_P and *BY_REF is filled with the parameter index, offset | |||
1097 | within the aggregate and whether it is a load from a value passed by | |||
1098 | reference respectively. | |||
1099 | ||||
1100 | Return false if the offset divided by BITS_PER_UNIT would not fit into an | |||
1101 | unsigned int. */ | |||
1102 | ||||
1103 | bool | |||
1104 | ipa_load_from_parm_agg (struct ipa_func_body_info *fbi, | |||
1105 | vec<ipa_param_descriptor, va_gc> *descriptors, | |||
1106 | gimple *stmt, tree op, int *index_p, | |||
1107 | HOST_WIDE_INTlong *offset_p, poly_int64 *size_p, | |||
1108 | bool *by_ref_p, bool *guaranteed_unmodified) | |||
1109 | { | |||
1110 | int index; | |||
1111 | HOST_WIDE_INTlong size; | |||
1112 | bool reverse; | |||
1113 | tree base = get_ref_base_and_extent_hwi (op, offset_p, &size, &reverse); | |||
1114 | ||||
1115 | if (!base | |||
1116 | || (*offset_p / BITS_PER_UNIT(8)) > UINT_MAX(2147483647 *2U +1U)) | |||
1117 | return false; | |||
1118 | ||||
1119 | /* We can not propagate across volatile loads. */ | |||
1120 | if (TREE_THIS_VOLATILE (op)((op)->base.volatile_flag)) | |||
1121 | return false; | |||
1122 | ||||
1123 | if (DECL_P (base)(tree_code_type_tmpl <0>::tree_code_type[(int) (((enum tree_code ) (base)->base.code))] == tcc_declaration)) | |||
1124 | { | |||
1125 | int index = ipa_get_param_decl_index_1 (descriptors, base); | |||
1126 | if (index >= 0 | |||
1127 | && parm_preserved_before_stmt_p (fbi, index, stmt, op)) | |||
1128 | { | |||
1129 | *index_p = index; | |||
1130 | *by_ref_p = false; | |||
1131 | if (size_p) | |||
1132 | *size_p = size; | |||
1133 | if (guaranteed_unmodified) | |||
1134 | *guaranteed_unmodified = true; | |||
1135 | return true; | |||
1136 | } | |||
1137 | return false; | |||
1138 | } | |||
1139 | ||||
1140 | if (TREE_CODE (base)((enum tree_code) (base)->base.code) != MEM_REF | |||
1141 | || TREE_CODE (TREE_OPERAND (base, 0))((enum tree_code) ((*((const_cast<tree*> (tree_operand_check ((base), (0), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 1141, __FUNCTION__))))))->base.code) != SSA_NAME | |||
1142 | || !integer_zerop (TREE_OPERAND (base, 1)(*((const_cast<tree*> (tree_operand_check ((base), (1), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 1142, __FUNCTION__))))))) | |||
1143 | return false; | |||
1144 | ||||
1145 | if (SSA_NAME_IS_DEFAULT_DEF (TREE_OPERAND (base, 0))(tree_check (((*((const_cast<tree*> (tree_operand_check ((base), (0), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 1145, __FUNCTION__)))))), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 1145, __FUNCTION__, (SSA_NAME)))->base.default_def_flag) | |||
1146 | { | |||
1147 | tree parm = SSA_NAME_VAR (TREE_OPERAND (base, 0))((tree_check (((*((const_cast<tree*> (tree_operand_check ((base), (0), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 1147, __FUNCTION__)))))), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 1147, __FUNCTION__, (SSA_NAME)))->ssa_name.var == (tree) nullptr || ((enum tree_code) (((*((const_cast<tree*> ( tree_operand_check ((base), (0), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 1147, __FUNCTION__))))))->ssa_name.var)->base.code) == IDENTIFIER_NODE ? (tree) nullptr : ((*((const_cast<tree*> (tree_operand_check ((base), (0), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 1147, __FUNCTION__))))))->ssa_name.var); | |||
1148 | index = ipa_get_param_decl_index_1 (descriptors, parm); | |||
1149 | } | |||
1150 | else | |||
1151 | { | |||
1152 | /* This branch catches situations where a pointer parameter is not a | |||
1153 | gimple register, for example: | |||
1154 | ||||
1155 | void hip7(S*) (struct S * p) | |||
1156 | { | |||
1157 | void (*<T2e4>) (struct S *) D.1867; | |||
1158 | struct S * p.1; | |||
1159 | ||||
1160 | <bb 2>: | |||
1161 | p.1_1 = p; | |||
1162 | D.1867_2 = p.1_1->f; | |||
1163 | D.1867_2 (); | |||
1164 | gdp = &p; | |||
1165 | */ | |||
1166 | ||||
1167 | gimple *def = SSA_NAME_DEF_STMT (TREE_OPERAND (base, 0))(tree_check (((*((const_cast<tree*> (tree_operand_check ((base), (0), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 1167, __FUNCTION__)))))), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 1167, __FUNCTION__, (SSA_NAME)))->ssa_name.def_stmt; | |||
1168 | index = load_from_unmodified_param (fbi, descriptors, def); | |||
1169 | } | |||
1170 | ||||
1171 | if (index >= 0) | |||
1172 | { | |||
1173 | bool data_preserved = parm_ref_data_preserved_p (fbi, index, stmt, op); | |||
1174 | if (!data_preserved && !guaranteed_unmodified) | |||
1175 | return false; | |||
1176 | ||||
1177 | *index_p = index; | |||
1178 | *by_ref_p = true; | |||
1179 | if (size_p) | |||
1180 | *size_p = size; | |||
1181 | if (guaranteed_unmodified) | |||
1182 | *guaranteed_unmodified = data_preserved; | |||
1183 | return true; | |||
1184 | } | |||
1185 | return false; | |||
1186 | } | |||
1187 | ||||
1188 | /* If STMT is an assignment that loads a value from a parameter declaration, | |||
1189 | or from an aggregate passed as the parameter either by value or reference, | |||
1190 | return the index of the parameter in ipa_node_params. Otherwise return -1. | |||
1191 | ||||
1192 | FBI holds gathered information about the function. INFO describes | |||
1193 | parameters of the function, STMT is the assignment statement. If it is a | |||
1194 | memory load from an aggregate, *OFFSET_P is filled with offset within the | |||
1195 | aggregate, and *BY_REF_P specifies whether the aggregate is passed by | |||
1196 | reference. */ | |||
1197 | ||||
1198 | static int | |||
1199 | load_from_unmodified_param_or_agg (struct ipa_func_body_info *fbi, | |||
1200 | class ipa_node_params *info, | |||
1201 | gimple *stmt, | |||
1202 | HOST_WIDE_INTlong *offset_p, | |||
1203 | bool *by_ref_p) | |||
1204 | { | |||
1205 | int index = load_from_unmodified_param (fbi, info->descriptors, stmt); | |||
1206 | poly_int64 size; | |||
1207 | ||||
1208 | /* Load value from a parameter declaration. */ | |||
1209 | if (index >= 0) | |||
1210 | { | |||
1211 | *offset_p = -1; | |||
1212 | return index; | |||
1213 | } | |||
1214 | ||||
1215 | if (!gimple_assign_load_p (stmt)) | |||
1216 | return -1; | |||
1217 | ||||
1218 | tree rhs = gimple_assign_rhs1 (stmt); | |||
1219 | ||||
1220 | /* Skip memory reference containing VIEW_CONVERT_EXPR. */ | |||
1221 | for (tree t = rhs; handled_component_p (t); t = TREE_OPERAND (t, 0)(*((const_cast<tree*> (tree_operand_check ((t), (0), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 1221, __FUNCTION__)))))) | |||
1222 | if (TREE_CODE (t)((enum tree_code) (t)->base.code) == VIEW_CONVERT_EXPR) | |||
1223 | return -1; | |||
1224 | ||||
1225 | /* Skip memory reference containing bit-field. */ | |||
1226 | if (TREE_CODE (rhs)((enum tree_code) (rhs)->base.code) == BIT_FIELD_REF | |||
1227 | || contains_bitfld_component_ref_p (rhs)) | |||
1228 | return -1; | |||
1229 | ||||
1230 | if (!ipa_load_from_parm_agg (fbi, info->descriptors, stmt, rhs, &index, | |||
1231 | offset_p, &size, by_ref_p)) | |||
1232 | return -1; | |||
1233 | ||||
1234 | gcc_assert (!maybe_ne (tree_to_poly_int64 (TYPE_SIZE (TREE_TYPE (rhs))),((void)(!(!maybe_ne (tree_to_poly_int64 (((tree_class_check ( (((contains_struct_check ((rhs), (TS_TYPED), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 1234, __FUNCTION__))->typed.type)), (tcc_type), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 1234, __FUNCTION__))->type_common.size)), size)) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 1235, __FUNCTION__), 0 : 0)) | |||
1235 | size))((void)(!(!maybe_ne (tree_to_poly_int64 (((tree_class_check ( (((contains_struct_check ((rhs), (TS_TYPED), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 1234, __FUNCTION__))->typed.type)), (tcc_type), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 1234, __FUNCTION__))->type_common.size)), size)) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 1235, __FUNCTION__), 0 : 0)); | |||
1236 | if (!*by_ref_p) | |||
1237 | { | |||
1238 | tree param_type = ipa_get_type (info, index); | |||
1239 | ||||
1240 | if (!param_type || !AGGREGATE_TYPE_P (param_type)(((enum tree_code) (param_type)->base.code) == ARRAY_TYPE || (((enum tree_code) (param_type)->base.code) == RECORD_TYPE || ((enum tree_code) (param_type)->base.code) == UNION_TYPE || ((enum tree_code) (param_type)->base.code) == QUAL_UNION_TYPE ))) | |||
1241 | return -1; | |||
1242 | } | |||
1243 | else if (TREE_THIS_VOLATILE (rhs)((rhs)->base.volatile_flag)) | |||
1244 | return -1; | |||
1245 | ||||
1246 | return index; | |||
1247 | } | |||
1248 | ||||
1249 | /* Walk pointer adjustemnts from OP (such as POINTER_PLUS and ADDR_EXPR) | |||
1250 | to find original pointer. Initialize RET to the pointer which results from | |||
1251 | the walk. | |||
1252 | If offset is known return true and initialize OFFSET_RET. */ | |||
1253 | ||||
1254 | bool | |||
1255 | unadjusted_ptr_and_unit_offset (tree op, tree *ret, poly_int64 *offset_ret) | |||
1256 | { | |||
1257 | poly_int64 offset = 0; | |||
1258 | bool offset_known = true; | |||
1259 | int i; | |||
1260 | ||||
1261 | for (i = 0; i < param_ipa_jump_function_lookupsglobal_options.x_param_ipa_jump_function_lookups; i++) | |||
1262 | { | |||
1263 | if (TREE_CODE (op)((enum tree_code) (op)->base.code) == ADDR_EXPR) | |||
1264 | { | |||
1265 | poly_int64 extra_offset = 0; | |||
1266 | tree base = get_addr_base_and_unit_offset (TREE_OPERAND (op, 0)(*((const_cast<tree*> (tree_operand_check ((op), (0), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 1266, __FUNCTION__))))), | |||
1267 | &offset); | |||
1268 | if (!base) | |||
1269 | { | |||
1270 | base = get_base_address (TREE_OPERAND (op, 0)(*((const_cast<tree*> (tree_operand_check ((op), (0), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 1270, __FUNCTION__)))))); | |||
1271 | if (TREE_CODE (base)((enum tree_code) (base)->base.code) != MEM_REF) | |||
1272 | break; | |||
1273 | offset_known = false; | |||
1274 | } | |||
1275 | else | |||
1276 | { | |||
1277 | if (TREE_CODE (base)((enum tree_code) (base)->base.code) != MEM_REF) | |||
1278 | break; | |||
1279 | offset += extra_offset; | |||
1280 | } | |||
1281 | op = TREE_OPERAND (base, 0)(*((const_cast<tree*> (tree_operand_check ((base), (0), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 1281, __FUNCTION__))))); | |||
1282 | if (mem_ref_offset (base).to_shwi (&extra_offset)) | |||
1283 | offset += extra_offset; | |||
1284 | else | |||
1285 | offset_known = false; | |||
1286 | } | |||
1287 | else if (TREE_CODE (op)((enum tree_code) (op)->base.code) == SSA_NAME | |||
1288 | && !SSA_NAME_IS_DEFAULT_DEF (op)(tree_check ((op), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 1288, __FUNCTION__, (SSA_NAME)))->base.default_def_flag) | |||
1289 | { | |||
1290 | gimple *pstmt = SSA_NAME_DEF_STMT (op)(tree_check ((op), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 1290, __FUNCTION__, (SSA_NAME)))->ssa_name.def_stmt; | |||
1291 | ||||
1292 | if (gimple_assign_single_p (pstmt)) | |||
1293 | op = gimple_assign_rhs1 (pstmt); | |||
1294 | else if (is_gimple_assign (pstmt) | |||
1295 | && gimple_assign_rhs_code (pstmt) == POINTER_PLUS_EXPR) | |||
1296 | { | |||
1297 | poly_int64 extra_offset = 0; | |||
1298 | if (ptrdiff_tree_p (gimple_assign_rhs2 (pstmt), | |||
1299 | &extra_offset)) | |||
1300 | offset += extra_offset; | |||
1301 | else | |||
1302 | offset_known = false; | |||
1303 | op = gimple_assign_rhs1 (pstmt); | |||
1304 | } | |||
1305 | else | |||
1306 | break; | |||
1307 | } | |||
1308 | else | |||
1309 | break; | |||
1310 | } | |||
1311 | *ret = op; | |||
1312 | *offset_ret = offset; | |||
1313 | return offset_known; | |||
1314 | } | |||
1315 | ||||
1316 | /* Given that an actual argument is an SSA_NAME (given in NAME) and is a result | |||
1317 | of an assignment statement STMT, try to determine whether we are actually | |||
1318 | handling any of the following cases and construct an appropriate jump | |||
1319 | function into JFUNC if so: | |||
1320 | ||||
1321 | 1) The passed value is loaded from a formal parameter which is not a gimple | |||
1322 | register (most probably because it is addressable, the value has to be | |||
1323 | scalar) and we can guarantee the value has not changed. This case can | |||
1324 | therefore be described by a simple pass-through jump function. For example: | |||
1325 | ||||
1326 | foo (int a) | |||
1327 | { | |||
1328 | int a.0; | |||
1329 | ||||
1330 | a.0_2 = a; | |||
1331 | bar (a.0_2); | |||
1332 | ||||
1333 | 2) The passed value can be described by a simple arithmetic pass-through | |||
1334 | jump function. E.g. | |||
1335 | ||||
1336 | foo (int a) | |||
1337 | { | |||
1338 | int D.2064; | |||
1339 | ||||
1340 | D.2064_4 = a.1(D) + 4; | |||
1341 | bar (D.2064_4); | |||
1342 | ||||
1343 | This case can also occur in combination of the previous one, e.g.: | |||
1344 | ||||
1345 | foo (int a, int z) | |||
1346 | { | |||
1347 | int a.0; | |||
1348 | int D.2064; | |||
1349 | ||||
1350 | a.0_3 = a; | |||
1351 | D.2064_4 = a.0_3 + 4; | |||
1352 | foo (D.2064_4); | |||
1353 | ||||
1354 | 3) The passed value is an address of an object within another one (which | |||
1355 | also passed by reference). Such situations are described by an ancestor | |||
1356 | jump function and describe situations such as: | |||
1357 | ||||
1358 | B::foo() (struct B * const this) | |||
1359 | { | |||
1360 | struct A * D.1845; | |||
1361 | ||||
1362 | D.1845_2 = &this_1(D)->D.1748; | |||
1363 | A::bar (D.1845_2); | |||
1364 | ||||
1365 | INFO is the structure describing individual parameters access different | |||
1366 | stages of IPA optimizations. PARMS_AINFO contains the information that is | |||
1367 | only needed for intraprocedural analysis. */ | |||
1368 | ||||
1369 | static void | |||
1370 | compute_complex_assign_jump_func (struct ipa_func_body_info *fbi, | |||
1371 | class ipa_node_params *info, | |||
1372 | struct ipa_jump_func *jfunc, | |||
1373 | gcall *call, gimple *stmt, tree name, | |||
1374 | tree param_type) | |||
1375 | { | |||
1376 | HOST_WIDE_INTlong offset, size; | |||
1377 | tree op1, tc_ssa, base, ssa; | |||
1378 | bool reverse; | |||
1379 | int index; | |||
1380 | ||||
1381 | op1 = gimple_assign_rhs1 (stmt); | |||
1382 | ||||
1383 | if (TREE_CODE (op1)((enum tree_code) (op1)->base.code) == SSA_NAME) | |||
1384 | { | |||
1385 | if (SSA_NAME_IS_DEFAULT_DEF (op1)(tree_check ((op1), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 1385, __FUNCTION__, (SSA_NAME)))->base.default_def_flag) | |||
1386 | index = ipa_get_param_decl_index (info, SSA_NAME_VAR (op1)((tree_check ((op1), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 1386, __FUNCTION__, (SSA_NAME)))->ssa_name.var == (tree) nullptr || ((enum tree_code) ((op1)->ssa_name.var)->base .code) == IDENTIFIER_NODE ? (tree) nullptr : (op1)->ssa_name .var)); | |||
1387 | else | |||
1388 | index = load_from_unmodified_param (fbi, info->descriptors, | |||
1389 | SSA_NAME_DEF_STMT (op1)(tree_check ((op1), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 1389, __FUNCTION__, (SSA_NAME)))->ssa_name.def_stmt); | |||
1390 | tc_ssa = op1; | |||
1391 | } | |||
1392 | else | |||
1393 | { | |||
1394 | index = load_from_unmodified_param (fbi, info->descriptors, stmt); | |||
1395 | tc_ssa = gimple_assign_lhs (stmt); | |||
1396 | } | |||
1397 | ||||
1398 | if (index >= 0) | |||
1399 | { | |||
1400 | switch (gimple_assign_rhs_class (stmt)) | |||
1401 | { | |||
1402 | case GIMPLE_BINARY_RHS: | |||
1403 | { | |||
1404 | tree op2 = gimple_assign_rhs2 (stmt); | |||
1405 | if (!is_gimple_ip_invariant (op2) | |||
1406 | || ((TREE_CODE_CLASS (gimple_assign_rhs_code (stmt))tree_code_type_tmpl <0>::tree_code_type[(int) (gimple_assign_rhs_code (stmt))] | |||
1407 | != tcc_comparison) | |||
1408 | && !useless_type_conversion_p (TREE_TYPE (name)((contains_struct_check ((name), (TS_TYPED), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 1408, __FUNCTION__))->typed.type), | |||
1409 | TREE_TYPE (op1)((contains_struct_check ((op1), (TS_TYPED), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 1409, __FUNCTION__))->typed.type)))) | |||
1410 | return; | |||
1411 | ||||
1412 | ipa_set_jf_arith_pass_through (jfunc, index, op2, | |||
1413 | gimple_assign_rhs_code (stmt)); | |||
1414 | break; | |||
1415 | } | |||
1416 | case GIMPLE_SINGLE_RHS: | |||
1417 | { | |||
1418 | bool agg_p = parm_ref_data_pass_through_p (fbi, index, call, | |||
1419 | tc_ssa); | |||
1420 | ipa_set_jf_simple_pass_through (jfunc, index, agg_p); | |||
1421 | break; | |||
1422 | } | |||
1423 | case GIMPLE_UNARY_RHS: | |||
1424 | if (!CONVERT_EXPR_CODE_P (gimple_assign_rhs_code (stmt))((gimple_assign_rhs_code (stmt)) == NOP_EXPR || (gimple_assign_rhs_code (stmt)) == CONVERT_EXPR)) | |||
1425 | ipa_set_jf_unary_pass_through (jfunc, index, | |||
1426 | gimple_assign_rhs_code (stmt)); | |||
1427 | default:; | |||
1428 | } | |||
1429 | return; | |||
1430 | } | |||
1431 | ||||
1432 | if (TREE_CODE (op1)((enum tree_code) (op1)->base.code) != ADDR_EXPR) | |||
1433 | return; | |||
1434 | op1 = TREE_OPERAND (op1, 0)(*((const_cast<tree*> (tree_operand_check ((op1), (0), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 1434, __FUNCTION__))))); | |||
1435 | base = get_ref_base_and_extent_hwi (op1, &offset, &size, &reverse); | |||
1436 | offset_int mem_offset; | |||
1437 | if (!base | |||
1438 | || TREE_CODE (base)((enum tree_code) (base)->base.code) != MEM_REF | |||
1439 | || !mem_ref_offset (base).is_constant (&mem_offset)) | |||
1440 | return; | |||
1441 | offset += mem_offset.to_short_addr () * BITS_PER_UNIT(8); | |||
1442 | ssa = TREE_OPERAND (base, 0)(*((const_cast<tree*> (tree_operand_check ((base), (0), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 1442, __FUNCTION__))))); | |||
1443 | if (TREE_CODE (ssa)((enum tree_code) (ssa)->base.code) != SSA_NAME | |||
1444 | || !SSA_NAME_IS_DEFAULT_DEF (ssa)(tree_check ((ssa), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 1444, __FUNCTION__, (SSA_NAME)))->base.default_def_flag | |||
1445 | || offset < 0) | |||
1446 | return; | |||
1447 | ||||
1448 | /* Dynamic types are changed in constructors and destructors. */ | |||
1449 | index = ipa_get_param_decl_index (info, SSA_NAME_VAR (ssa)((tree_check ((ssa), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 1449, __FUNCTION__, (SSA_NAME)))->ssa_name.var == (tree) nullptr || ((enum tree_code) ((ssa)->ssa_name.var)->base .code) == IDENTIFIER_NODE ? (tree) nullptr : (ssa)->ssa_name .var)); | |||
1450 | if (index >= 0 && param_type && POINTER_TYPE_P (param_type)(((enum tree_code) (param_type)->base.code) == POINTER_TYPE || ((enum tree_code) (param_type)->base.code) == REFERENCE_TYPE )) | |||
1451 | ipa_set_ancestor_jf (jfunc, offset, index, | |||
1452 | parm_ref_data_pass_through_p (fbi, index, call, ssa), | |||
1453 | false); | |||
1454 | } | |||
1455 | ||||
1456 | /* Extract the base, offset and MEM_REF expression from a statement ASSIGN if | |||
1457 | it looks like: | |||
1458 | ||||
1459 | iftmp.1_3 = &obj_2(D)->D.1762; | |||
1460 | ||||
1461 | The base of the MEM_REF must be a default definition SSA NAME of a | |||
1462 | parameter. Return NULL_TREE if it looks otherwise. If case of success, the | |||
1463 | whole MEM_REF expression is returned and the offset calculated from any | |||
1464 | handled components and the MEM_REF itself is stored into *OFFSET. The whole | |||
1465 | RHS stripped off the ADDR_EXPR is stored into *OBJ_P. */ | |||
1466 | ||||
1467 | static tree | |||
1468 | get_ancestor_addr_info (gimple *assign, tree *obj_p, HOST_WIDE_INTlong *offset) | |||
1469 | { | |||
1470 | HOST_WIDE_INTlong size; | |||
1471 | tree expr, parm, obj; | |||
1472 | bool reverse; | |||
1473 | ||||
1474 | if (!gimple_assign_single_p (assign)) | |||
1475 | return NULL_TREE(tree) nullptr; | |||
1476 | expr = gimple_assign_rhs1 (assign); | |||
1477 | ||||
1478 | if (TREE_CODE (expr)((enum tree_code) (expr)->base.code) != ADDR_EXPR) | |||
1479 | return NULL_TREE(tree) nullptr; | |||
1480 | expr = TREE_OPERAND (expr, 0)(*((const_cast<tree*> (tree_operand_check ((expr), (0), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 1480, __FUNCTION__))))); | |||
1481 | obj = expr; | |||
1482 | expr = get_ref_base_and_extent_hwi (expr, offset, &size, &reverse); | |||
1483 | ||||
1484 | offset_int mem_offset; | |||
1485 | if (!expr | |||
1486 | || TREE_CODE (expr)((enum tree_code) (expr)->base.code) != MEM_REF | |||
1487 | || !mem_ref_offset (expr).is_constant (&mem_offset)) | |||
1488 | return NULL_TREE(tree) nullptr; | |||
1489 | parm = TREE_OPERAND (expr, 0)(*((const_cast<tree*> (tree_operand_check ((expr), (0), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 1489, __FUNCTION__))))); | |||
1490 | if (TREE_CODE (parm)((enum tree_code) (parm)->base.code) != SSA_NAME | |||
1491 | || !SSA_NAME_IS_DEFAULT_DEF (parm)(tree_check ((parm), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 1491, __FUNCTION__, (SSA_NAME)))->base.default_def_flag | |||
1492 | || TREE_CODE (SSA_NAME_VAR (parm))((enum tree_code) (((tree_check ((parm), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 1492, __FUNCTION__, (SSA_NAME)))->ssa_name.var == (tree) nullptr || ((enum tree_code) ((parm)->ssa_name.var)->base .code) == IDENTIFIER_NODE ? (tree) nullptr : (parm)->ssa_name .var))->base.code) != PARM_DECL) | |||
1493 | return NULL_TREE(tree) nullptr; | |||
1494 | ||||
1495 | *offset += mem_offset.to_short_addr () * BITS_PER_UNIT(8); | |||
1496 | *obj_p = obj; | |||
1497 | return expr; | |||
1498 | } | |||
1499 | ||||
1500 | ||||
1501 | /* Given that an actual argument is an SSA_NAME that is a result of a phi | |||
1502 | statement PHI, try to find out whether NAME is in fact a | |||
1503 | multiple-inheritance typecast from a descendant into an ancestor of a formal | |||
1504 | parameter and thus can be described by an ancestor jump function and if so, | |||
1505 | write the appropriate function into JFUNC. | |||
1506 | ||||
1507 | Essentially we want to match the following pattern: | |||
1508 | ||||
1509 | if (obj_2(D) != 0B) | |||
1510 | goto <bb 3>; | |||
1511 | else | |||
1512 | goto <bb 4>; | |||
1513 | ||||
1514 | <bb 3>: | |||
1515 | iftmp.1_3 = &obj_2(D)->D.1762; | |||
1516 | ||||
1517 | <bb 4>: | |||
1518 | # iftmp.1_1 = PHI <iftmp.1_3(3), 0B(2)> | |||
1519 | D.1879_6 = middleman_1 (iftmp.1_1, i_5(D)); | |||
1520 | return D.1879_6; */ | |||
1521 | ||||
1522 | static void | |||
1523 | compute_complex_ancestor_jump_func (struct ipa_func_body_info *fbi, | |||
1524 | class ipa_node_params *info, | |||
1525 | struct ipa_jump_func *jfunc, | |||
1526 | gcall *call, gphi *phi) | |||
1527 | { | |||
1528 | HOST_WIDE_INTlong offset; | |||
1529 | gimple *assign, *cond; | |||
1530 | basic_block phi_bb, assign_bb, cond_bb; | |||
1531 | tree tmp, parm, expr, obj; | |||
1532 | int index, i; | |||
1533 | ||||
1534 | if (gimple_phi_num_args (phi) != 2) | |||
1535 | return; | |||
1536 | ||||
1537 | if (integer_zerop (PHI_ARG_DEF (phi, 1)gimple_phi_arg_def ((phi), (1)))) | |||
1538 | tmp = PHI_ARG_DEF (phi, 0)gimple_phi_arg_def ((phi), (0)); | |||
1539 | else if (integer_zerop (PHI_ARG_DEF (phi, 0)gimple_phi_arg_def ((phi), (0)))) | |||
1540 | tmp = PHI_ARG_DEF (phi, 1)gimple_phi_arg_def ((phi), (1)); | |||
1541 | else | |||
1542 | return; | |||
1543 | if (TREE_CODE (tmp)((enum tree_code) (tmp)->base.code) != SSA_NAME | |||
1544 | || SSA_NAME_IS_DEFAULT_DEF (tmp)(tree_check ((tmp), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 1544, __FUNCTION__, (SSA_NAME)))->base.default_def_flag | |||
1545 | || !POINTER_TYPE_P (TREE_TYPE (tmp))(((enum tree_code) (((contains_struct_check ((tmp), (TS_TYPED ), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 1545, __FUNCTION__))->typed.type))->base.code) == POINTER_TYPE || ((enum tree_code) (((contains_struct_check ((tmp), (TS_TYPED ), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 1545, __FUNCTION__))->typed.type))->base.code) == REFERENCE_TYPE ) | |||
1546 | || TREE_CODE (TREE_TYPE (TREE_TYPE (tmp)))((enum tree_code) (((contains_struct_check ((((contains_struct_check ((tmp), (TS_TYPED), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 1546, __FUNCTION__))->typed.type)), (TS_TYPED), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 1546, __FUNCTION__))->typed.type))->base.code) != RECORD_TYPE) | |||
1547 | return; | |||
1548 | ||||
1549 | assign = SSA_NAME_DEF_STMT (tmp)(tree_check ((tmp), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 1549, __FUNCTION__, (SSA_NAME)))->ssa_name.def_stmt; | |||
1550 | assign_bb = gimple_bb (assign); | |||
1551 | if (!single_pred_p (assign_bb)) | |||
1552 | return; | |||
1553 | expr = get_ancestor_addr_info (assign, &obj, &offset); | |||
1554 | if (!expr) | |||
1555 | return; | |||
1556 | parm = TREE_OPERAND (expr, 0)(*((const_cast<tree*> (tree_operand_check ((expr), (0), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 1556, __FUNCTION__))))); | |||
1557 | index = ipa_get_param_decl_index (info, SSA_NAME_VAR (parm)((tree_check ((parm), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 1557, __FUNCTION__, (SSA_NAME)))->ssa_name.var == (tree) nullptr || ((enum tree_code) ((parm)->ssa_name.var)->base .code) == IDENTIFIER_NODE ? (tree) nullptr : (parm)->ssa_name .var)); | |||
1558 | if (index < 0) | |||
1559 | return; | |||
1560 | ||||
1561 | cond_bb = single_pred (assign_bb); | |||
1562 | cond = last_stmt (cond_bb); | |||
1563 | if (!cond | |||
1564 | || gimple_code (cond) != GIMPLE_COND | |||
1565 | || gimple_cond_code (cond) != NE_EXPR | |||
1566 | || gimple_cond_lhs (cond) != parm | |||
1567 | || !integer_zerop (gimple_cond_rhs (cond))) | |||
1568 | return; | |||
1569 | ||||
1570 | phi_bb = gimple_bb (phi); | |||
1571 | for (i = 0; i < 2; i++) | |||
1572 | { | |||
1573 | basic_block pred = EDGE_PRED (phi_bb, i)(*(phi_bb)->preds)[(i)]->src; | |||
1574 | if (pred != assign_bb && pred != cond_bb) | |||
1575 | return; | |||
1576 | } | |||
1577 | ||||
1578 | ipa_set_ancestor_jf (jfunc, offset, index, | |||
1579 | parm_ref_data_pass_through_p (fbi, index, call, parm), | |||
1580 | true); | |||
1581 | } | |||
1582 | ||||
1583 | /* Inspect the given TYPE and return true iff it has the same structure (the | |||
1584 | same number of fields of the same types) as a C++ member pointer. If | |||
1585 | METHOD_PTR and DELTA are non-NULL, store the trees representing the | |||
1586 | corresponding fields there. */ | |||
1587 | ||||
1588 | static bool | |||
1589 | type_like_member_ptr_p (tree type, tree *method_ptr, tree *delta) | |||
1590 | { | |||
1591 | tree fld; | |||
1592 | ||||
1593 | if (TREE_CODE (type)((enum tree_code) (type)->base.code) != RECORD_TYPE) | |||
1594 | return false; | |||
1595 | ||||
1596 | fld = TYPE_FIELDS (type)((tree_check3 ((type), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 1596, __FUNCTION__, (RECORD_TYPE), (UNION_TYPE), (QUAL_UNION_TYPE )))->type_non_common.values); | |||
1597 | if (!fld || !POINTER_TYPE_P (TREE_TYPE (fld))(((enum tree_code) (((contains_struct_check ((fld), (TS_TYPED ), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 1597, __FUNCTION__))->typed.type))->base.code) == POINTER_TYPE || ((enum tree_code) (((contains_struct_check ((fld), (TS_TYPED ), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 1597, __FUNCTION__))->typed.type))->base.code) == REFERENCE_TYPE ) | |||
1598 | || TREE_CODE (TREE_TYPE (TREE_TYPE (fld)))((enum tree_code) (((contains_struct_check ((((contains_struct_check ((fld), (TS_TYPED), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 1598, __FUNCTION__))->typed.type)), (TS_TYPED), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 1598, __FUNCTION__))->typed.type))->base.code) != METHOD_TYPE | |||
1599 | || !tree_fits_uhwi_p (DECL_FIELD_OFFSET (fld)((tree_check ((fld), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 1599, __FUNCTION__, (FIELD_DECL)))->field_decl.offset))) | |||
1600 | return false; | |||
1601 | ||||
1602 | if (method_ptr) | |||
1603 | *method_ptr = fld; | |||
1604 | ||||
1605 | fld = DECL_CHAIN (fld)(((contains_struct_check (((contains_struct_check ((fld), (TS_DECL_MINIMAL ), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 1605, __FUNCTION__))), (TS_COMMON), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 1605, __FUNCTION__))->common.chain)); | |||
1606 | if (!fld || INTEGRAL_TYPE_P (fld)(((enum tree_code) (fld)->base.code) == ENUMERAL_TYPE || ( (enum tree_code) (fld)->base.code) == BOOLEAN_TYPE || ((enum tree_code) (fld)->base.code) == INTEGER_TYPE) | |||
1607 | || !tree_fits_uhwi_p (DECL_FIELD_OFFSET (fld)((tree_check ((fld), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 1607, __FUNCTION__, (FIELD_DECL)))->field_decl.offset))) | |||
1608 | return false; | |||
1609 | if (delta) | |||
1610 | *delta = fld; | |||
1611 | ||||
1612 | if (DECL_CHAIN (fld)(((contains_struct_check (((contains_struct_check ((fld), (TS_DECL_MINIMAL ), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 1612, __FUNCTION__))), (TS_COMMON), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 1612, __FUNCTION__))->common.chain))) | |||
1613 | return false; | |||
1614 | ||||
1615 | return true; | |||
1616 | } | |||
1617 | ||||
1618 | /* If RHS is an SSA_NAME and it is defined by a simple copy assign statement, | |||
1619 | return the rhs of its defining statement, and this statement is stored in | |||
1620 | *RHS_STMT. Otherwise return RHS as it is. */ | |||
1621 | ||||
1622 | static inline tree | |||
1623 | get_ssa_def_if_simple_copy (tree rhs, gimple **rhs_stmt) | |||
1624 | { | |||
1625 | while (TREE_CODE (rhs)((enum tree_code) (rhs)->base.code) == SSA_NAME && !SSA_NAME_IS_DEFAULT_DEF (rhs)(tree_check ((rhs), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 1625, __FUNCTION__, (SSA_NAME)))->base.default_def_flag) | |||
1626 | { | |||
1627 | gimple *def_stmt = SSA_NAME_DEF_STMT (rhs)(tree_check ((rhs), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 1627, __FUNCTION__, (SSA_NAME)))->ssa_name.def_stmt; | |||
1628 | ||||
1629 | if (gimple_assign_single_p (def_stmt)) | |||
1630 | rhs = gimple_assign_rhs1 (def_stmt); | |||
1631 | else | |||
1632 | break; | |||
1633 | *rhs_stmt = def_stmt; | |||
1634 | } | |||
1635 | return rhs; | |||
1636 | } | |||
1637 | ||||
1638 | /* Simple linked list, describing contents of an aggregate before call. */ | |||
1639 | ||||
1640 | struct ipa_known_agg_contents_list | |||
1641 | { | |||
1642 | /* Offset and size of the described part of the aggregate. */ | |||
1643 | HOST_WIDE_INTlong offset, size; | |||
1644 | ||||
1645 | /* Type of the described part of the aggregate. */ | |||
1646 | tree type; | |||
1647 | ||||
1648 | /* Known constant value or jump function data describing contents. */ | |||
1649 | struct ipa_load_agg_data value; | |||
1650 | ||||
1651 | /* Pointer to the next structure in the list. */ | |||
1652 | struct ipa_known_agg_contents_list *next; | |||
1653 | }; | |||
1654 | ||||
1655 | /* Add an aggregate content item into a linked list of | |||
1656 | ipa_known_agg_contents_list structure, in which all elements | |||
1657 | are sorted ascendingly by offset. */ | |||
1658 | ||||
1659 | static inline void | |||
1660 | add_to_agg_contents_list (struct ipa_known_agg_contents_list **plist, | |||
1661 | struct ipa_known_agg_contents_list *item) | |||
1662 | { | |||
1663 | struct ipa_known_agg_contents_list *list = *plist; | |||
1664 | ||||
1665 | for (; list; list = list->next) | |||
1666 | { | |||
1667 | if (list->offset >= item->offset) | |||
1668 | break; | |||
1669 | ||||
1670 | plist = &list->next; | |||
1671 | } | |||
1672 | ||||
1673 | item->next = list; | |||
1674 | *plist = item; | |||
1675 | } | |||
1676 | ||||
1677 | /* Check whether a given aggregate content is clobbered by certain element in | |||
1678 | a linked list of ipa_known_agg_contents_list. */ | |||
1679 | ||||
1680 | static inline bool | |||
1681 | clobber_by_agg_contents_list_p (struct ipa_known_agg_contents_list *list, | |||
1682 | struct ipa_known_agg_contents_list *item) | |||
1683 | { | |||
1684 | for (; list; list = list->next) | |||
1685 | { | |||
1686 | if (list->offset >= item->offset) | |||
1687 | return list->offset < item->offset + item->size; | |||
1688 | ||||
1689 | if (list->offset + list->size > item->offset) | |||
1690 | return true; | |||
1691 | } | |||
1692 | ||||
1693 | return false; | |||
1694 | } | |||
1695 | ||||
1696 | /* Build aggregate jump function from LIST, assuming there are exactly | |||
1697 | VALUE_COUNT entries there and that offset of the passed argument | |||
1698 | is ARG_OFFSET and store it into JFUNC. */ | |||
1699 | ||||
1700 | static void | |||
1701 | build_agg_jump_func_from_list (struct ipa_known_agg_contents_list *list, | |||
1702 | int value_count, HOST_WIDE_INTlong arg_offset, | |||
1703 | struct ipa_jump_func *jfunc) | |||
1704 | { | |||
1705 | vec_safe_reserve (jfunc->agg.items, value_count, true); | |||
1706 | for (; list; list = list->next) | |||
1707 | { | |||
1708 | struct ipa_agg_jf_item item; | |||
1709 | tree operand = list->value.pass_through.operand; | |||
1710 | ||||
1711 | if (list->value.pass_through.formal_id >= 0) | |||
1712 | { | |||
1713 | /* Content value is derived from some formal paramerter. */ | |||
1714 | if (list->value.offset >= 0) | |||
1715 | item.jftype = IPA_JF_LOAD_AGG; | |||
1716 | else | |||
1717 | item.jftype = IPA_JF_PASS_THROUGH; | |||
1718 | ||||
1719 | item.value.load_agg = list->value; | |||
1720 | if (operand) | |||
1721 | item.value.pass_through.operand | |||
1722 | = unshare_expr_without_location (operand); | |||
1723 | } | |||
1724 | else if (operand) | |||
1725 | { | |||
1726 | /* Content value is known constant. */ | |||
1727 | item.jftype = IPA_JF_CONST; | |||
1728 | item.value.constant = unshare_expr_without_location (operand); | |||
1729 | } | |||
1730 | else | |||
1731 | continue; | |||
1732 | ||||
1733 | item.type = list->type; | |||
1734 | gcc_assert (tree_to_shwi (TYPE_SIZE (list->type)) == list->size)((void)(!(tree_to_shwi (((tree_class_check ((list->type), ( tcc_type), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 1734, __FUNCTION__))->type_common.size)) == list->size ) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 1734, __FUNCTION__), 0 : 0)); | |||
1735 | ||||
1736 | item.offset = list->offset - arg_offset; | |||
1737 | gcc_assert ((item.offset % BITS_PER_UNIT) == 0)((void)(!((item.offset % (8)) == 0) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 1737, __FUNCTION__), 0 : 0)); | |||
1738 | ||||
1739 | jfunc->agg.items->quick_push (item); | |||
1740 | } | |||
1741 | } | |||
1742 | ||||
1743 | /* Given an assignment statement STMT, try to collect information into | |||
1744 | AGG_VALUE that will be used to construct jump function for RHS of the | |||
1745 | assignment, from which content value of an aggregate part comes. | |||
1746 | ||||
1747 | Besides constant and simple pass-through jump functions, also try to | |||
1748 | identify whether it matches the following pattern that can be described by | |||
1749 | a load-value-from-aggregate jump function, which is a derivative of simple | |||
1750 | pass-through jump function. | |||
1751 | ||||
1752 | foo (int *p) | |||
1753 | { | |||
1754 | ... | |||
1755 | ||||
1756 | *(q_5 + 4) = *(p_3(D) + 28) op 1; | |||
1757 | bar (q_5); | |||
1758 | } | |||
1759 | ||||
1760 | Here IPA_LOAD_AGG_DATA data structure is informative enough to describe | |||
1761 | constant, simple pass-through and load-vale-from-aggregate. If value | |||
1762 | is constant, it will be kept in field OPERAND, and field FORMAL_ID is | |||
1763 | set to -1. For simple pass-through and load-value-from-aggregate, field | |||
1764 | FORMAL_ID specifies the related formal parameter index, and field | |||
1765 | OFFSET can be used to distinguish them, -1 means simple pass-through, | |||
1766 | otherwise means load-value-from-aggregate. */ | |||
1767 | ||||
1768 | static void | |||
1769 | analyze_agg_content_value (struct ipa_func_body_info *fbi, | |||
1770 | struct ipa_load_agg_data *agg_value, | |||
1771 | gimple *stmt) | |||
1772 | { | |||
1773 | tree lhs = gimple_assign_lhs (stmt); | |||
1774 | tree rhs1 = gimple_assign_rhs1 (stmt); | |||
1775 | enum tree_code code; | |||
1776 | int index = -1; | |||
1777 | ||||
1778 | /* Initialize jump function data for the aggregate part. */ | |||
1779 | memset (agg_value, 0, sizeof (*agg_value)); | |||
1780 | agg_value->pass_through.operation = NOP_EXPR; | |||
1781 | agg_value->pass_through.formal_id = -1; | |||
1782 | agg_value->offset = -1; | |||
1783 | ||||
1784 | if (AGGREGATE_TYPE_P (TREE_TYPE (lhs))(((enum tree_code) (((contains_struct_check ((lhs), (TS_TYPED ), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 1784, __FUNCTION__))->typed.type))->base.code) == ARRAY_TYPE || (((enum tree_code) (((contains_struct_check ((lhs), (TS_TYPED ), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 1784, __FUNCTION__))->typed.type))->base.code) == RECORD_TYPE || ((enum tree_code) (((contains_struct_check ((lhs), (TS_TYPED ), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 1784, __FUNCTION__))->typed.type))->base.code) == UNION_TYPE || ((enum tree_code) (((contains_struct_check ((lhs), (TS_TYPED ), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 1784, __FUNCTION__))->typed.type))->base.code) == QUAL_UNION_TYPE )) /* TODO: Support aggregate type. */ | |||
1785 | || TREE_THIS_VOLATILE (lhs)((lhs)->base.volatile_flag) | |||
1786 | || TREE_CODE (lhs)((enum tree_code) (lhs)->base.code) == BIT_FIELD_REF | |||
1787 | || contains_bitfld_component_ref_p (lhs)) | |||
1788 | return; | |||
1789 | ||||
1790 | /* Skip SSA copies. */ | |||
1791 | while (gimple_assign_rhs_class (stmt) == GIMPLE_SINGLE_RHS) | |||
1792 | { | |||
1793 | if (TREE_CODE (rhs1)((enum tree_code) (rhs1)->base.code) != SSA_NAME || SSA_NAME_IS_DEFAULT_DEF (rhs1)(tree_check ((rhs1), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 1793, __FUNCTION__, (SSA_NAME)))->base.default_def_flag) | |||
1794 | break; | |||
1795 | ||||
1796 | stmt = SSA_NAME_DEF_STMT (rhs1)(tree_check ((rhs1), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 1796, __FUNCTION__, (SSA_NAME)))->ssa_name.def_stmt; | |||
1797 | if (!is_gimple_assign (stmt)) | |||
1798 | break; | |||
1799 | ||||
1800 | rhs1 = gimple_assign_rhs1 (stmt); | |||
1801 | } | |||
1802 | ||||
1803 | if (gphi *phi = dyn_cast<gphi *> (stmt)) | |||
1804 | { | |||
1805 | /* Also special case like the following (a is a formal parameter): | |||
1806 | ||||
1807 | _12 = *a_11(D).dim[0].stride; | |||
1808 | ... | |||
1809 | # iftmp.22_9 = PHI <_12(2), 1(3)> | |||
1810 | ... | |||
1811 | parm.6.dim[0].stride = iftmp.22_9; | |||
1812 | ... | |||
1813 | __x_MOD_foo (&parm.6, b_31(D)); | |||
1814 | ||||
1815 | The aggregate function describing parm.6.dim[0].stride is encoded as a | |||
1816 | PASS-THROUGH jump function with ASSERT_EXPR operation whith operand 1 | |||
1817 | (the constant from the PHI node). */ | |||
1818 | ||||
1819 | if (gimple_phi_num_args (phi) != 2) | |||
1820 | return; | |||
1821 | tree arg0 = gimple_phi_arg_def (phi, 0); | |||
1822 | tree arg1 = gimple_phi_arg_def (phi, 1); | |||
1823 | tree operand; | |||
1824 | ||||
1825 | if (is_gimple_ip_invariant (arg1)) | |||
1826 | { | |||
1827 | operand = arg1; | |||
1828 | rhs1 = arg0; | |||
1829 | } | |||
1830 | else if (is_gimple_ip_invariant (arg0)) | |||
1831 | { | |||
1832 | operand = arg0; | |||
1833 | rhs1 = arg1; | |||
1834 | } | |||
1835 | else | |||
1836 | return; | |||
1837 | ||||
1838 | rhs1 = get_ssa_def_if_simple_copy (rhs1, &stmt); | |||
1839 | if (!is_gimple_assign (stmt)) | |||
1840 | return; | |||
1841 | ||||
1842 | code = ASSERT_EXPR; | |||
1843 | agg_value->pass_through.operand = operand; | |||
1844 | } | |||
1845 | else if (is_gimple_assign (stmt)) | |||
1846 | { | |||
1847 | code = gimple_assign_rhs_code (stmt); | |||
1848 | switch (gimple_assign_rhs_class (stmt)) | |||
1849 | { | |||
1850 | case GIMPLE_SINGLE_RHS: | |||
1851 | if (is_gimple_ip_invariant (rhs1)) | |||
1852 | { | |||
1853 | agg_value->pass_through.operand = rhs1; | |||
1854 | return; | |||
1855 | } | |||
1856 | code = NOP_EXPR; | |||
1857 | break; | |||
1858 | ||||
1859 | case GIMPLE_UNARY_RHS: | |||
1860 | /* NOTE: A GIMPLE_UNARY_RHS operation might not be tcc_unary | |||
1861 | (truth_not_expr is example), GIMPLE_BINARY_RHS does not imply | |||
1862 | tcc_binary, this subtleness is somewhat misleading. | |||
1863 | ||||
1864 | Since tcc_unary is widely used in IPA-CP code to check an operation | |||
1865 | with one operand, here we only allow tc_unary operation to avoid | |||
1866 | possible problem. Then we can use (opclass == tc_unary) or not to | |||
1867 | distinguish unary and binary. */ | |||
1868 | if (TREE_CODE_CLASS (code)tree_code_type_tmpl <0>::tree_code_type[(int) (code)] != tcc_unary || CONVERT_EXPR_CODE_P (code)((code) == NOP_EXPR || (code) == CONVERT_EXPR)) | |||
1869 | return; | |||
1870 | ||||
1871 | rhs1 = get_ssa_def_if_simple_copy (rhs1, &stmt); | |||
1872 | break; | |||
1873 | ||||
1874 | case GIMPLE_BINARY_RHS: | |||
1875 | { | |||
1876 | gimple *rhs1_stmt = stmt; | |||
1877 | gimple *rhs2_stmt = stmt; | |||
1878 | tree rhs2 = gimple_assign_rhs2 (stmt); | |||
1879 | ||||
1880 | rhs1 = get_ssa_def_if_simple_copy (rhs1, &rhs1_stmt); | |||
1881 | rhs2 = get_ssa_def_if_simple_copy (rhs2, &rhs2_stmt); | |||
1882 | ||||
1883 | if (is_gimple_ip_invariant (rhs2)) | |||
1884 | { | |||
1885 | agg_value->pass_through.operand = rhs2; | |||
1886 | stmt = rhs1_stmt; | |||
1887 | } | |||
1888 | else if (is_gimple_ip_invariant (rhs1)) | |||
1889 | { | |||
1890 | if (TREE_CODE_CLASS (code)tree_code_type_tmpl <0>::tree_code_type[(int) (code)] == tcc_comparison) | |||
1891 | code = swap_tree_comparison (code); | |||
1892 | else if (!commutative_tree_code (code)) | |||
1893 | return; | |||
1894 | ||||
1895 | agg_value->pass_through.operand = rhs1; | |||
1896 | stmt = rhs2_stmt; | |||
1897 | rhs1 = rhs2; | |||
1898 | } | |||
1899 | else | |||
1900 | return; | |||
1901 | ||||
1902 | if (TREE_CODE_CLASS (code)tree_code_type_tmpl <0>::tree_code_type[(int) (code)] != tcc_comparison | |||
1903 | && !useless_type_conversion_p (TREE_TYPE (lhs)((contains_struct_check ((lhs), (TS_TYPED), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 1903, __FUNCTION__))->typed.type), | |||
1904 | TREE_TYPE (rhs1)((contains_struct_check ((rhs1), (TS_TYPED), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 1904, __FUNCTION__))->typed.type))) | |||
1905 | return; | |||
1906 | } | |||
1907 | break; | |||
1908 | ||||
1909 | default: | |||
1910 | return; | |||
1911 | } | |||
1912 | } | |||
1913 | else | |||
1914 | return; | |||
1915 | ||||
1916 | if (TREE_CODE (rhs1)((enum tree_code) (rhs1)->base.code) != SSA_NAME) | |||
1917 | index = load_from_unmodified_param_or_agg (fbi, fbi->info, stmt, | |||
1918 | &agg_value->offset, | |||
1919 | &agg_value->by_ref); | |||
1920 | else if (SSA_NAME_IS_DEFAULT_DEF (rhs1)(tree_check ((rhs1), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 1920, __FUNCTION__, (SSA_NAME)))->base.default_def_flag) | |||
1921 | index = ipa_get_param_decl_index (fbi->info, SSA_NAME_VAR (rhs1)((tree_check ((rhs1), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 1921, __FUNCTION__, (SSA_NAME)))->ssa_name.var == (tree) nullptr || ((enum tree_code) ((rhs1)->ssa_name.var)->base .code) == IDENTIFIER_NODE ? (tree) nullptr : (rhs1)->ssa_name .var)); | |||
1922 | ||||
1923 | if (index >= 0) | |||
1924 | { | |||
1925 | if (agg_value->offset >= 0) | |||
1926 | agg_value->type = TREE_TYPE (rhs1)((contains_struct_check ((rhs1), (TS_TYPED), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 1926, __FUNCTION__))->typed.type); | |||
1927 | agg_value->pass_through.formal_id = index; | |||
1928 | agg_value->pass_through.operation = code; | |||
1929 | } | |||
1930 | else | |||
1931 | agg_value->pass_through.operand = NULL_TREE(tree) nullptr; | |||
1932 | } | |||
1933 | ||||
1934 | /* If STMT is a memory store to the object whose address is BASE, extract | |||
1935 | information (offset, size, and value) into CONTENT, and return true, | |||
1936 | otherwise we conservatively assume the whole object is modified with | |||
1937 | unknown content, and return false. CHECK_REF means that access to object | |||
1938 | is expected to be in form of MEM_REF expression. */ | |||
1939 | ||||
1940 | static bool | |||
1941 | extract_mem_content (struct ipa_func_body_info *fbi, | |||
1942 | gimple *stmt, tree base, bool check_ref, | |||
1943 | struct ipa_known_agg_contents_list *content) | |||
1944 | { | |||
1945 | HOST_WIDE_INTlong lhs_offset, lhs_size; | |||
1946 | bool reverse; | |||
1947 | ||||
1948 | if (!is_gimple_assign (stmt)) | |||
1949 | return false; | |||
1950 | ||||
1951 | tree lhs = gimple_assign_lhs (stmt); | |||
1952 | tree lhs_base = get_ref_base_and_extent_hwi (lhs, &lhs_offset, &lhs_size, | |||
1953 | &reverse); | |||
1954 | if (!lhs_base) | |||
1955 | return false; | |||
1956 | ||||
1957 | if (check_ref) | |||
1958 | { | |||
1959 | if (TREE_CODE (lhs_base)((enum tree_code) (lhs_base)->base.code) != MEM_REF | |||
1960 | || TREE_OPERAND (lhs_base, 0)(*((const_cast<tree*> (tree_operand_check ((lhs_base), ( 0), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 1960, __FUNCTION__))))) != base | |||
1961 | || !integer_zerop (TREE_OPERAND (lhs_base, 1)(*((const_cast<tree*> (tree_operand_check ((lhs_base), ( 1), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 1961, __FUNCTION__))))))) | |||
1962 | return false; | |||
1963 | } | |||
1964 | else if (lhs_base != base) | |||
1965 | return false; | |||
1966 | ||||
1967 | content->offset = lhs_offset; | |||
1968 | content->size = lhs_size; | |||
1969 | content->type = TREE_TYPE (lhs)((contains_struct_check ((lhs), (TS_TYPED), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 1969, __FUNCTION__))->typed.type); | |||
1970 | content->next = NULLnullptr; | |||
1971 | ||||
1972 | analyze_agg_content_value (fbi, &content->value, stmt); | |||
1973 | return true; | |||
1974 | } | |||
1975 | ||||
1976 | /* Traverse statements from CALL backwards, scanning whether an aggregate given | |||
1977 | in ARG is filled in constants or values that are derived from caller's | |||
1978 | formal parameter in the way described by some kinds of jump functions. FBI | |||
1979 | is the context of the caller function for interprocedural analysis. ARG can | |||
1980 | either be an aggregate expression or a pointer to an aggregate. ARG_TYPE is | |||
1981 | the type of the aggregate, JFUNC is the jump function for the aggregate. */ | |||
1982 | ||||
1983 | static void | |||
1984 | determine_known_aggregate_parts (struct ipa_func_body_info *fbi, | |||
1985 | gcall *call, tree arg, | |||
1986 | tree arg_type, | |||
1987 | struct ipa_jump_func *jfunc) | |||
1988 | { | |||
1989 | struct ipa_known_agg_contents_list *list = NULLnullptr, *all_list = NULLnullptr; | |||
1990 | bitmap visited = NULLnullptr; | |||
1991 | int item_count = 0, value_count = 0; | |||
1992 | HOST_WIDE_INTlong arg_offset, arg_size; | |||
1993 | tree arg_base; | |||
1994 | bool check_ref, by_ref; | |||
1995 | ao_ref r; | |||
1996 | int max_agg_items = opt_for_fn (fbi->node->decl, param_ipa_max_agg_items)(opts_for_fn (fbi->node->decl)->x_param_ipa_max_agg_items ); | |||
1997 | ||||
1998 | if (max_agg_items == 0) | |||
1999 | return; | |||
2000 | ||||
2001 | /* The function operates in three stages. First, we prepare check_ref, r, | |||
2002 | arg_base and arg_offset based on what is actually passed as an actual | |||
2003 | argument. */ | |||
2004 | ||||
2005 | if (POINTER_TYPE_P (arg_type)(((enum tree_code) (arg_type)->base.code) == POINTER_TYPE || ((enum tree_code) (arg_type)->base.code) == REFERENCE_TYPE )) | |||
2006 | { | |||
2007 | by_ref = true; | |||
2008 | if (TREE_CODE (arg)((enum tree_code) (arg)->base.code) == SSA_NAME) | |||
2009 | { | |||
2010 | tree type_size; | |||
2011 | if (!tree_fits_uhwi_p (TYPE_SIZE (TREE_TYPE (arg_type))((tree_class_check ((((contains_struct_check ((arg_type), (TS_TYPED ), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 2011, __FUNCTION__))->typed.type)), (tcc_type), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 2011, __FUNCTION__))->type_common.size)) | |||
2012 | || !POINTER_TYPE_P (TREE_TYPE (arg))(((enum tree_code) (((contains_struct_check ((arg), (TS_TYPED ), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 2012, __FUNCTION__))->typed.type))->base.code) == POINTER_TYPE || ((enum tree_code) (((contains_struct_check ((arg), (TS_TYPED ), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 2012, __FUNCTION__))->typed.type))->base.code) == REFERENCE_TYPE )) | |||
2013 | return; | |||
2014 | check_ref = true; | |||
2015 | arg_base = arg; | |||
2016 | arg_offset = 0; | |||
2017 | type_size = TYPE_SIZE (TREE_TYPE (arg_type))((tree_class_check ((((contains_struct_check ((arg_type), (TS_TYPED ), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 2017, __FUNCTION__))->typed.type)), (tcc_type), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 2017, __FUNCTION__))->type_common.size); | |||
2018 | arg_size = tree_to_uhwi (type_size); | |||
2019 | ao_ref_init_from_ptr_and_size (&r, arg_base, NULL_TREE(tree) nullptr); | |||
2020 | } | |||
2021 | else if (TREE_CODE (arg)((enum tree_code) (arg)->base.code) == ADDR_EXPR) | |||
2022 | { | |||
2023 | bool reverse; | |||
2024 | ||||
2025 | arg = TREE_OPERAND (arg, 0)(*((const_cast<tree*> (tree_operand_check ((arg), (0), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 2025, __FUNCTION__))))); | |||
2026 | arg_base = get_ref_base_and_extent_hwi (arg, &arg_offset, | |||
2027 | &arg_size, &reverse); | |||
2028 | if (!arg_base) | |||
2029 | return; | |||
2030 | if (DECL_P (arg_base)(tree_code_type_tmpl <0>::tree_code_type[(int) (((enum tree_code ) (arg_base)->base.code))] == tcc_declaration)) | |||
2031 | { | |||
2032 | check_ref = false; | |||
2033 | ao_ref_init (&r, arg_base); | |||
2034 | } | |||
2035 | else | |||
2036 | return; | |||
2037 | } | |||
2038 | else | |||
2039 | return; | |||
2040 | } | |||
2041 | else | |||
2042 | { | |||
2043 | bool reverse; | |||
2044 | ||||
2045 | gcc_checking_assert (AGGREGATE_TYPE_P (TREE_TYPE (arg)))((void)(!((((enum tree_code) (((contains_struct_check ((arg), (TS_TYPED), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 2045, __FUNCTION__))->typed.type))->base.code) == ARRAY_TYPE || (((enum tree_code) (((contains_struct_check ((arg), (TS_TYPED ), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 2045, __FUNCTION__))->typed.type))->base.code) == RECORD_TYPE || ((enum tree_code) (((contains_struct_check ((arg), (TS_TYPED ), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 2045, __FUNCTION__))->typed.type))->base.code) == UNION_TYPE || ((enum tree_code) (((contains_struct_check ((arg), (TS_TYPED ), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 2045, __FUNCTION__))->typed.type))->base.code) == QUAL_UNION_TYPE ))) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 2045, __FUNCTION__), 0 : 0)); | |||
2046 | ||||
2047 | by_ref = false; | |||
2048 | check_ref = false; | |||
2049 | arg_base = get_ref_base_and_extent_hwi (arg, &arg_offset, | |||
2050 | &arg_size, &reverse); | |||
2051 | if (!arg_base) | |||
2052 | return; | |||
2053 | ||||
2054 | ao_ref_init (&r, arg); | |||
2055 | } | |||
2056 | ||||
2057 | /* Second stage traverses virtual SSA web backwards starting from the call | |||
2058 | statement, only looks at individual dominating virtual operand (its | |||
2059 | definition dominates the call), as long as it is confident that content | |||
2060 | of the aggregate is affected by definition of the virtual operand, it | |||
2061 | builds a sorted linked list of ipa_agg_jf_list describing that. */ | |||
2062 | ||||
2063 | for (tree dom_vuse = gimple_vuse (call); | |||
2064 | dom_vuse && fbi->aa_walk_budget > 0;) | |||
2065 | { | |||
2066 | gimple *stmt = SSA_NAME_DEF_STMT (dom_vuse)(tree_check ((dom_vuse), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 2066, __FUNCTION__, (SSA_NAME)))->ssa_name.def_stmt; | |||
2067 | ||||
2068 | if (gimple_code (stmt) == GIMPLE_PHI) | |||
2069 | { | |||
2070 | dom_vuse = get_continuation_for_phi (stmt, &r, true, | |||
2071 | fbi->aa_walk_budget, | |||
2072 | &visited, false, NULLnullptr, NULLnullptr); | |||
2073 | continue; | |||
2074 | } | |||
2075 | ||||
2076 | fbi->aa_walk_budget--; | |||
2077 | if (stmt_may_clobber_ref_p_1 (stmt, &r)) | |||
2078 | { | |||
2079 | struct ipa_known_agg_contents_list *content | |||
2080 | = XALLOCA (struct ipa_known_agg_contents_list)((struct ipa_known_agg_contents_list *) __builtin_alloca(sizeof (struct ipa_known_agg_contents_list))); | |||
2081 | ||||
2082 | if (!extract_mem_content (fbi, stmt, arg_base, check_ref, content)) | |||
2083 | break; | |||
2084 | ||||
2085 | /* Now we get a dominating virtual operand, and need to check | |||
2086 | whether its value is clobbered any other dominating one. */ | |||
2087 | if ((content->value.pass_through.formal_id >= 0 | |||
2088 | || content->value.pass_through.operand) | |||
2089 | && !clobber_by_agg_contents_list_p (all_list, content)) | |||
2090 | { | |||
2091 | struct ipa_known_agg_contents_list *copy | |||
2092 | = XALLOCA (struct ipa_known_agg_contents_list)((struct ipa_known_agg_contents_list *) __builtin_alloca(sizeof (struct ipa_known_agg_contents_list))); | |||
2093 | ||||
2094 | /* Add to the list consisting of only dominating virtual | |||
2095 | operands, whose definitions can finally reach the call. */ | |||
2096 | add_to_agg_contents_list (&list, (*copy = *content, copy)); | |||
2097 | ||||
2098 | if (++value_count == max_agg_items) | |||
2099 | break; | |||
2100 | } | |||
2101 | ||||
2102 | /* Add to the list consisting of all dominating virtual operands. */ | |||
2103 | add_to_agg_contents_list (&all_list, content); | |||
2104 | ||||
2105 | if (++item_count == 2 * max_agg_items) | |||
2106 | break; | |||
2107 | } | |||
2108 | dom_vuse = gimple_vuse (stmt); | |||
2109 | } | |||
2110 | ||||
2111 | if (visited) | |||
2112 | BITMAP_FREE (visited)((void) (bitmap_obstack_free ((bitmap) visited), (visited) = ( bitmap) nullptr)); | |||
2113 | ||||
2114 | /* Third stage just goes over the list and creates an appropriate vector of | |||
2115 | ipa_agg_jf_item structures out of it, of course only if there are | |||
2116 | any meaningful items to begin with. */ | |||
2117 | ||||
2118 | if (value_count) | |||
2119 | { | |||
2120 | jfunc->agg.by_ref = by_ref; | |||
2121 | build_agg_jump_func_from_list (list, value_count, arg_offset, jfunc); | |||
2122 | } | |||
2123 | } | |||
2124 | ||||
2125 | ||||
2126 | /* Return the Ith param type of callee associated with call graph | |||
2127 | edge E. */ | |||
2128 | ||||
2129 | tree | |||
2130 | ipa_get_callee_param_type (struct cgraph_edge *e, int i) | |||
2131 | { | |||
2132 | int n; | |||
2133 | tree type = (e->callee | |||
2134 | ? TREE_TYPE (e->callee->decl)((contains_struct_check ((e->callee->decl), (TS_TYPED), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 2134, __FUNCTION__))->typed.type) | |||
2135 | : gimple_call_fntype (e->call_stmt)); | |||
2136 | tree t = TYPE_ARG_TYPES (type)((tree_check2 ((type), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 2136, __FUNCTION__, (FUNCTION_TYPE), (METHOD_TYPE)))->type_non_common .values); | |||
2137 | ||||
2138 | for (n = 0; n < i; n++) | |||
2139 | { | |||
2140 | if (!t) | |||
2141 | break; | |||
2142 | t = TREE_CHAIN (t)((contains_struct_check ((t), (TS_COMMON), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 2142, __FUNCTION__))->common.chain); | |||
2143 | } | |||
2144 | if (t) | |||
2145 | return TREE_VALUE (t)((tree_check ((t), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 2145, __FUNCTION__, (TREE_LIST)))->list.value); | |||
2146 | if (!e->callee) | |||
2147 | return NULLnullptr; | |||
2148 | t = DECL_ARGUMENTS (e->callee->decl)((tree_check ((e->callee->decl), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 2148, __FUNCTION__, (FUNCTION_DECL)))->function_decl.arguments ); | |||
2149 | for (n = 0; n < i; n++) | |||
2150 | { | |||
2151 | if (!t) | |||
2152 | return NULLnullptr; | |||
2153 | t = TREE_CHAIN (t)((contains_struct_check ((t), (TS_COMMON), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 2153, __FUNCTION__))->common.chain); | |||
2154 | } | |||
2155 | if (t) | |||
2156 | return TREE_TYPE (t)((contains_struct_check ((t), (TS_TYPED), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 2156, __FUNCTION__))->typed.type); | |||
2157 | return NULLnullptr; | |||
2158 | } | |||
2159 | ||||
2160 | /* Return ipa_bits with VALUE and MASK values, which can be either a newly | |||
2161 | allocated structure or a previously existing one shared with other jump | |||
2162 | functions and/or transformation summaries. */ | |||
2163 | ||||
2164 | ipa_bits * | |||
2165 | ipa_get_ipa_bits_for_value (const widest_int &value, const widest_int &mask) | |||
2166 | { | |||
2167 | ipa_bits tmp; | |||
2168 | tmp.value = value; | |||
2169 | tmp.mask = mask; | |||
2170 | ||||
2171 | ipa_bits **slot = ipa_bits_hash_table->find_slot (&tmp, INSERT); | |||
2172 | if (*slot) | |||
2173 | return *slot; | |||
2174 | ||||
2175 | ipa_bits *res = ggc_alloc<ipa_bits> (); | |||
2176 | res->value = value; | |||
2177 | res->mask = mask; | |||
2178 | *slot = res; | |||
2179 | ||||
2180 | return res; | |||
2181 | } | |||
2182 | ||||
2183 | /* Assign to JF a pointer to ipa_bits structure with VALUE and MASK. Use hash | |||
2184 | table in order to avoid creating multiple same ipa_bits structures. */ | |||
2185 | ||||
2186 | static void | |||
2187 | ipa_set_jfunc_bits (ipa_jump_func *jf, const widest_int &value, | |||
2188 | const widest_int &mask) | |||
2189 | { | |||
2190 | jf->bits = ipa_get_ipa_bits_for_value (value, mask); | |||
2191 | } | |||
2192 | ||||
2193 | /* Return a pointer to a value_range just like *TMP, but either find it in | |||
2194 | ipa_vr_hash_table or allocate it in GC memory. TMP->equiv must be NULL. */ | |||
2195 | ||||
2196 | static value_range * | |||
2197 | ipa_get_value_range (value_range *tmp) | |||
2198 | { | |||
2199 | value_range **slot = ipa_vr_hash_table->find_slot (tmp, INSERT); | |||
2200 | if (*slot) | |||
2201 | return *slot; | |||
2202 | ||||
2203 | value_range *vr = new (ggc_alloc<value_range> ()) value_range; | |||
2204 | *vr = *tmp; | |||
2205 | *slot = vr; | |||
2206 | ||||
2207 | return vr; | |||
2208 | } | |||
2209 | ||||
2210 | /* Return a pointer to a value range consisting of TYPE, MIN, MAX and an empty | |||
2211 | equiv set. Use hash table in order to avoid creating multiple same copies of | |||
2212 | value_ranges. */ | |||
2213 | ||||
2214 | static value_range * | |||
2215 | ipa_get_value_range (enum value_range_kind kind, tree min, tree max) | |||
2216 | { | |||
2217 | value_range tmp (min, max, kind); | |||
2218 | return ipa_get_value_range (&tmp); | |||
2219 | } | |||
2220 | ||||
2221 | /* Assign to JF a pointer to a value_range structure with TYPE, MIN and MAX and | |||
2222 | a NULL equiv bitmap. Use hash table in order to avoid creating multiple | |||
2223 | same value_range structures. */ | |||
2224 | ||||
2225 | static void | |||
2226 | ipa_set_jfunc_vr (ipa_jump_func *jf, enum value_range_kind type, | |||
2227 | tree min, tree max) | |||
2228 | { | |||
2229 | jf->m_vr = ipa_get_value_range (type, min, max); | |||
2230 | } | |||
2231 | ||||
2232 | /* Assign to JF a pointer to a value_range just like TMP but either fetch a | |||
2233 | copy from ipa_vr_hash_table or allocate a new on in GC memory. */ | |||
2234 | ||||
2235 | static void | |||
2236 | ipa_set_jfunc_vr (ipa_jump_func *jf, value_range *tmp) | |||
2237 | { | |||
2238 | jf->m_vr = ipa_get_value_range (tmp); | |||
2239 | } | |||
2240 | ||||
2241 | /* Compute jump function for all arguments of callsite CS and insert the | |||
2242 | information in the jump_functions array in the ipa_edge_args corresponding | |||
2243 | to this callsite. */ | |||
2244 | ||||
2245 | static void | |||
2246 | ipa_compute_jump_functions_for_edge (struct ipa_func_body_info *fbi, | |||
2247 | struct cgraph_edge *cs) | |||
2248 | { | |||
2249 | ipa_node_params *info = ipa_node_params_sum->get (cs->caller); | |||
2250 | ipa_edge_args *args = ipa_edge_args_sum->get_create (cs); | |||
2251 | gcall *call = cs->call_stmt; | |||
2252 | int n, arg_num = gimple_call_num_args (call); | |||
2253 | bool useful_context = false; | |||
2254 | value_range vr; | |||
2255 | ||||
2256 | if (arg_num == 0 || args->jump_functions) | |||
2257 | return; | |||
2258 | vec_safe_grow_cleared (args->jump_functions, arg_num, true); | |||
2259 | if (flag_devirtualizeglobal_options.x_flag_devirtualize) | |||
2260 | vec_safe_grow_cleared (args->polymorphic_call_contexts, arg_num, true); | |||
2261 | ||||
2262 | if (gimple_call_internal_p (call)) | |||
2263 | return; | |||
2264 | if (ipa_func_spec_opts_forbid_analysis_p (cs->caller)) | |||
2265 | return; | |||
2266 | ||||
2267 | for (n = 0; n < arg_num; n++) | |||
2268 | { | |||
2269 | struct ipa_jump_func *jfunc = ipa_get_ith_jump_func (args, n); | |||
2270 | tree arg = gimple_call_arg (call, n); | |||
2271 | tree param_type = ipa_get_callee_param_type (cs, n); | |||
2272 | if (flag_devirtualizeglobal_options.x_flag_devirtualize && POINTER_TYPE_P (TREE_TYPE (arg))(((enum tree_code) (((contains_struct_check ((arg), (TS_TYPED ), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 2272, __FUNCTION__))->typed.type))->base.code) == POINTER_TYPE || ((enum tree_code) (((contains_struct_check ((arg), (TS_TYPED ), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 2272, __FUNCTION__))->typed.type))->base.code) == REFERENCE_TYPE )) | |||
2273 | { | |||
2274 | tree instance; | |||
2275 | class ipa_polymorphic_call_context context (cs->caller->decl, | |||
2276 | arg, cs->call_stmt, | |||
2277 | &instance); | |||
2278 | context.get_dynamic_type (instance, arg, NULLnullptr, cs->call_stmt, | |||
2279 | &fbi->aa_walk_budget); | |||
2280 | *ipa_get_ith_polymorhic_call_context (args, n) = context; | |||
2281 | if (!context.useless_p ()) | |||
2282 | useful_context = true; | |||
2283 | } | |||
2284 | ||||
2285 | if (POINTER_TYPE_P (TREE_TYPE (arg))(((enum tree_code) (((contains_struct_check ((arg), (TS_TYPED ), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 2285, __FUNCTION__))->typed.type))->base.code) == POINTER_TYPE || ((enum tree_code) (((contains_struct_check ((arg), (TS_TYPED ), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 2285, __FUNCTION__))->typed.type))->base.code) == REFERENCE_TYPE )) | |||
2286 | { | |||
2287 | bool addr_nonzero = false; | |||
2288 | bool strict_overflow = false; | |||
2289 | ||||
2290 | if (TREE_CODE (arg)((enum tree_code) (arg)->base.code) == SSA_NAME | |||
2291 | && param_type | |||
2292 | && get_range_query (cfun(cfun + 0))->range_of_expr (vr, arg) | |||
2293 | && vr.nonzero_p ()) | |||
2294 | addr_nonzero = true; | |||
2295 | else if (tree_single_nonzero_warnv_p (arg, &strict_overflow)) | |||
2296 | addr_nonzero = true; | |||
2297 | ||||
2298 | if (addr_nonzero) | |||
2299 | { | |||
2300 | tree z = build_int_cst (TREE_TYPE (arg)((contains_struct_check ((arg), (TS_TYPED), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 2300, __FUNCTION__))->typed.type), 0); | |||
2301 | ipa_set_jfunc_vr (jfunc, VR_ANTI_RANGE, z, z); | |||
2302 | } | |||
2303 | else | |||
2304 | gcc_assert (!jfunc->m_vr)((void)(!(!jfunc->m_vr) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 2304, __FUNCTION__), 0 : 0)); | |||
2305 | } | |||
2306 | else | |||
2307 | { | |||
2308 | if (TREE_CODE (arg)((enum tree_code) (arg)->base.code) == SSA_NAME | |||
2309 | && param_type | |||
2310 | /* Limit the ranger query to integral types as the rest | |||
2311 | of this file uses value_range's, which only hold | |||
2312 | integers and pointers. */ | |||
2313 | && irange::supports_p (TREE_TYPE (arg)((contains_struct_check ((arg), (TS_TYPED), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 2313, __FUNCTION__))->typed.type)) | |||
2314 | && get_range_query (cfun(cfun + 0))->range_of_expr (vr, arg) | |||
2315 | && !vr.undefined_p ()) | |||
2316 | { | |||
2317 | value_range resvr; | |||
2318 | range_fold_unary_expr (&resvr, NOP_EXPR, param_type, | |||
2319 | &vr, TREE_TYPE (arg)((contains_struct_check ((arg), (TS_TYPED), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 2319, __FUNCTION__))->typed.type)); | |||
2320 | if (!resvr.undefined_p () && !resvr.varying_p ()) | |||
2321 | ipa_set_jfunc_vr (jfunc, &resvr); | |||
2322 | else | |||
2323 | gcc_assert (!jfunc->m_vr)((void)(!(!jfunc->m_vr) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 2323, __FUNCTION__), 0 : 0)); | |||
2324 | } | |||
2325 | else | |||
2326 | gcc_assert (!jfunc->m_vr)((void)(!(!jfunc->m_vr) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 2326, __FUNCTION__), 0 : 0)); | |||
2327 | } | |||
2328 | ||||
2329 | if (INTEGRAL_TYPE_P (TREE_TYPE (arg))(((enum tree_code) (((contains_struct_check ((arg), (TS_TYPED ), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 2329, __FUNCTION__))->typed.type))->base.code) == ENUMERAL_TYPE || ((enum tree_code) (((contains_struct_check ((arg), (TS_TYPED ), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 2329, __FUNCTION__))->typed.type))->base.code) == BOOLEAN_TYPE || ((enum tree_code) (((contains_struct_check ((arg), (TS_TYPED ), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 2329, __FUNCTION__))->typed.type))->base.code) == INTEGER_TYPE ) | |||
2330 | && (TREE_CODE (arg)((enum tree_code) (arg)->base.code) == SSA_NAME || TREE_CODE (arg)((enum tree_code) (arg)->base.code) == INTEGER_CST)) | |||
2331 | { | |||
2332 | if (TREE_CODE (arg)((enum tree_code) (arg)->base.code) == SSA_NAME) | |||
2333 | ipa_set_jfunc_bits (jfunc, 0, | |||
2334 | widest_int::from (get_nonzero_bits (arg), | |||
2335 | TYPE_SIGN (TREE_TYPE (arg))((signop) ((tree_class_check ((((contains_struct_check ((arg) , (TS_TYPED), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 2335, __FUNCTION__))->typed.type)), (tcc_type), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 2335, __FUNCTION__))->base.u.bits.unsigned_flag)))); | |||
2336 | else | |||
2337 | ipa_set_jfunc_bits (jfunc, wi::to_widest (arg), 0); | |||
2338 | } | |||
2339 | else if (POINTER_TYPE_P (TREE_TYPE (arg))(((enum tree_code) (((contains_struct_check ((arg), (TS_TYPED ), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 2339, __FUNCTION__))->typed.type))->base.code) == POINTER_TYPE || ((enum tree_code) (((contains_struct_check ((arg), (TS_TYPED ), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 2339, __FUNCTION__))->typed.type))->base.code) == REFERENCE_TYPE )) | |||
2340 | { | |||
2341 | unsigned HOST_WIDE_INTlong bitpos; | |||
2342 | unsigned align; | |||
2343 | ||||
2344 | get_pointer_alignment_1 (arg, &align, &bitpos); | |||
2345 | widest_int mask = wi::bit_and_not | |||
2346 | (wi::mask<widest_int> (TYPE_PRECISION (TREE_TYPE (arg))((tree_class_check ((((contains_struct_check ((arg), (TS_TYPED ), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 2346, __FUNCTION__))->typed.type)), (tcc_type), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 2346, __FUNCTION__))->type_common.precision), false), | |||
2347 | align / BITS_PER_UNIT(8) - 1); | |||
2348 | widest_int value = bitpos / BITS_PER_UNIT(8); | |||
2349 | ipa_set_jfunc_bits (jfunc, value, mask); | |||
2350 | } | |||
2351 | else | |||
2352 | gcc_assert (!jfunc->bits)((void)(!(!jfunc->bits) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 2352, __FUNCTION__), 0 : 0)); | |||
2353 | ||||
2354 | if (is_gimple_ip_invariant (arg) | |||
2355 | || (VAR_P (arg)(((enum tree_code) (arg)->base.code) == VAR_DECL) | |||
2356 | && is_global_var (arg) | |||
2357 | && TREE_READONLY (arg)((non_type_check ((arg), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 2357, __FUNCTION__))->base.readonly_flag))) | |||
2358 | ipa_set_jf_constant (jfunc, arg, cs); | |||
2359 | else if (!is_gimple_reg_type (TREE_TYPE (arg)((contains_struct_check ((arg), (TS_TYPED), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 2359, __FUNCTION__))->typed.type)) | |||
2360 | && TREE_CODE (arg)((enum tree_code) (arg)->base.code) == PARM_DECL) | |||
2361 | { | |||
2362 | int index = ipa_get_param_decl_index (info, arg); | |||
2363 | ||||
2364 | gcc_assert (index >=0)((void)(!(index >=0) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 2364, __FUNCTION__), 0 : 0)); | |||
2365 | /* Aggregate passed by value, check for pass-through, otherwise we | |||
2366 | will attempt to fill in aggregate contents later in this | |||
2367 | for cycle. */ | |||
2368 | if (parm_preserved_before_stmt_p (fbi, index, call, arg)) | |||
2369 | { | |||
2370 | ipa_set_jf_simple_pass_through (jfunc, index, false); | |||
2371 | continue; | |||
2372 | } | |||
2373 | } | |||
2374 | else if (TREE_CODE (arg)((enum tree_code) (arg)->base.code) == SSA_NAME) | |||
2375 | { | |||
2376 | if (SSA_NAME_IS_DEFAULT_DEF (arg)(tree_check ((arg), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 2376, __FUNCTION__, (SSA_NAME)))->base.default_def_flag) | |||
2377 | { | |||
2378 | int index = ipa_get_param_decl_index (info, SSA_NAME_VAR (arg)((tree_check ((arg), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 2378, __FUNCTION__, (SSA_NAME)))->ssa_name.var == (tree) nullptr || ((enum tree_code) ((arg)->ssa_name.var)->base .code) == IDENTIFIER_NODE ? (tree) nullptr : (arg)->ssa_name .var)); | |||
2379 | if (index >= 0) | |||
2380 | { | |||
2381 | bool agg_p; | |||
2382 | agg_p = parm_ref_data_pass_through_p (fbi, index, call, arg); | |||
2383 | ipa_set_jf_simple_pass_through (jfunc, index, agg_p); | |||
2384 | } | |||
2385 | } | |||
2386 | else | |||
2387 | { | |||
2388 | gimple *stmt = SSA_NAME_DEF_STMT (arg)(tree_check ((arg), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 2388, __FUNCTION__, (SSA_NAME)))->ssa_name.def_stmt; | |||
2389 | if (is_gimple_assign (stmt)) | |||
2390 | compute_complex_assign_jump_func (fbi, info, jfunc, | |||
2391 | call, stmt, arg, param_type); | |||
2392 | else if (gimple_code (stmt) == GIMPLE_PHI) | |||
2393 | compute_complex_ancestor_jump_func (fbi, info, jfunc, | |||
2394 | call, | |||
2395 | as_a <gphi *> (stmt)); | |||
2396 | } | |||
2397 | } | |||
2398 | ||||
2399 | /* If ARG is pointer, we cannot use its type to determine the type of aggregate | |||
2400 | passed (because type conversions are ignored in gimple). Usually we can | |||
2401 | safely get type from function declaration, but in case of K&R prototypes or | |||
2402 | variadic functions we can try our luck with type of the pointer passed. | |||
2403 | TODO: Since we look for actual initialization of the memory object, we may better | |||
2404 | work out the type based on the memory stores we find. */ | |||
2405 | if (!param_type) | |||
2406 | param_type = TREE_TYPE (arg)((contains_struct_check ((arg), (TS_TYPED), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 2406, __FUNCTION__))->typed.type); | |||
2407 | ||||
2408 | if ((jfunc->type != IPA_JF_PASS_THROUGH | |||
2409 | || !ipa_get_jf_pass_through_agg_preserved (jfunc)) | |||
2410 | && (jfunc->type != IPA_JF_ANCESTOR | |||
2411 | || !ipa_get_jf_ancestor_agg_preserved (jfunc)) | |||
2412 | && (AGGREGATE_TYPE_P (TREE_TYPE (arg))(((enum tree_code) (((contains_struct_check ((arg), (TS_TYPED ), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 2412, __FUNCTION__))->typed.type))->base.code) == ARRAY_TYPE || (((enum tree_code) (((contains_struct_check ((arg), (TS_TYPED ), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 2412, __FUNCTION__))->typed.type))->base.code) == RECORD_TYPE || ((enum tree_code) (((contains_struct_check ((arg), (TS_TYPED ), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 2412, __FUNCTION__))->typed.type))->base.code) == UNION_TYPE || ((enum tree_code) (((contains_struct_check ((arg), (TS_TYPED ), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 2412, __FUNCTION__))->typed.type))->base.code) == QUAL_UNION_TYPE )) | |||
2413 | || POINTER_TYPE_P (param_type)(((enum tree_code) (param_type)->base.code) == POINTER_TYPE || ((enum tree_code) (param_type)->base.code) == REFERENCE_TYPE ))) | |||
2414 | determine_known_aggregate_parts (fbi, call, arg, param_type, jfunc); | |||
2415 | } | |||
2416 | if (!useful_context) | |||
2417 | vec_free (args->polymorphic_call_contexts); | |||
2418 | } | |||
2419 | ||||
2420 | /* Compute jump functions for all edges - both direct and indirect - outgoing | |||
2421 | from BB. */ | |||
2422 | ||||
2423 | static void | |||
2424 | ipa_compute_jump_functions_for_bb (struct ipa_func_body_info *fbi, basic_block bb) | |||
2425 | { | |||
2426 | struct ipa_bb_info *bi = ipa_get_bb_info (fbi, bb); | |||
2427 | int i; | |||
2428 | struct cgraph_edge *cs; | |||
2429 | ||||
2430 | FOR_EACH_VEC_ELT_REVERSE (bi->cg_edges, i, cs)for (i = (bi->cg_edges).length () - 1; (bi->cg_edges).iterate ((i), &(cs)); (i)--) | |||
2431 | { | |||
2432 | struct cgraph_node *callee = cs->callee; | |||
2433 | ||||
2434 | if (callee) | |||
2435 | { | |||
2436 | callee = callee->ultimate_alias_target (); | |||
2437 | /* We do not need to bother analyzing calls to unknown functions | |||
2438 | unless they may become known during lto/whopr. */ | |||
2439 | if (!callee->definition && !flag_ltoglobal_options.x_flag_lto | |||
2440 | && !gimple_call_fnspec (cs->call_stmt).known_p ()) | |||
2441 | continue; | |||
2442 | } | |||
2443 | ipa_compute_jump_functions_for_edge (fbi, cs); | |||
2444 | } | |||
2445 | } | |||
2446 | ||||
2447 | /* If STMT looks like a statement loading a value from a member pointer formal | |||
2448 | parameter, return that parameter and store the offset of the field to | |||
2449 | *OFFSET_P, if it is non-NULL. Otherwise return NULL (but *OFFSET_P still | |||
2450 | might be clobbered). If USE_DELTA, then we look for a use of the delta | |||
2451 | field rather than the pfn. */ | |||
2452 | ||||
2453 | static tree | |||
2454 | ipa_get_stmt_member_ptr_load_param (gimple *stmt, bool use_delta, | |||
2455 | HOST_WIDE_INTlong *offset_p) | |||
2456 | { | |||
2457 | tree rhs, rec, ref_field, ref_offset, fld, ptr_field, delta_field; | |||
2458 | ||||
2459 | if (!gimple_assign_single_p (stmt)) | |||
2460 | return NULL_TREE(tree) nullptr; | |||
2461 | ||||
2462 | rhs = gimple_assign_rhs1 (stmt); | |||
2463 | if (TREE_CODE (rhs)((enum tree_code) (rhs)->base.code) == COMPONENT_REF) | |||
2464 | { | |||
2465 | ref_field = TREE_OPERAND (rhs, 1)(*((const_cast<tree*> (tree_operand_check ((rhs), (1), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 2465, __FUNCTION__))))); | |||
2466 | rhs = TREE_OPERAND (rhs, 0)(*((const_cast<tree*> (tree_operand_check ((rhs), (0), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 2466, __FUNCTION__))))); | |||
2467 | } | |||
2468 | else | |||
2469 | ref_field = NULL_TREE(tree) nullptr; | |||
2470 | if (TREE_CODE (rhs)((enum tree_code) (rhs)->base.code) != MEM_REF) | |||
2471 | return NULL_TREE(tree) nullptr; | |||
2472 | rec = TREE_OPERAND (rhs, 0)(*((const_cast<tree*> (tree_operand_check ((rhs), (0), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 2472, __FUNCTION__))))); | |||
2473 | if (TREE_CODE (rec)((enum tree_code) (rec)->base.code) != ADDR_EXPR) | |||
2474 | return NULL_TREE(tree) nullptr; | |||
2475 | rec = TREE_OPERAND (rec, 0)(*((const_cast<tree*> (tree_operand_check ((rec), (0), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 2475, __FUNCTION__))))); | |||
2476 | if (TREE_CODE (rec)((enum tree_code) (rec)->base.code) != PARM_DECL | |||
2477 | || !type_like_member_ptr_p (TREE_TYPE (rec)((contains_struct_check ((rec), (TS_TYPED), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 2477, __FUNCTION__))->typed.type), &ptr_field, &delta_field)) | |||
2478 | return NULL_TREE(tree) nullptr; | |||
2479 | ref_offset = TREE_OPERAND (rhs, 1)(*((const_cast<tree*> (tree_operand_check ((rhs), (1), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 2479, __FUNCTION__))))); | |||
2480 | ||||
2481 | if (use_delta) | |||
2482 | fld = delta_field; | |||
2483 | else | |||
2484 | fld = ptr_field; | |||
2485 | if (offset_p) | |||
2486 | *offset_p = int_bit_position (fld); | |||
2487 | ||||
2488 | if (ref_field) | |||
2489 | { | |||
2490 | if (integer_nonzerop (ref_offset)) | |||
2491 | return NULL_TREE(tree) nullptr; | |||
2492 | return ref_field == fld ? rec : NULL_TREE(tree) nullptr; | |||
2493 | } | |||
2494 | else | |||
2495 | return tree_int_cst_equal (byte_position (fld), ref_offset) ? rec | |||
2496 | : NULL_TREE(tree) nullptr; | |||
2497 | } | |||
2498 | ||||
2499 | /* Returns true iff T is an SSA_NAME defined by a statement. */ | |||
2500 | ||||
2501 | static bool | |||
2502 | ipa_is_ssa_with_stmt_def (tree t) | |||
2503 | { | |||
2504 | if (TREE_CODE (t)((enum tree_code) (t)->base.code) == SSA_NAME | |||
2505 | && !SSA_NAME_IS_DEFAULT_DEF (t)(tree_check ((t), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 2505, __FUNCTION__, (SSA_NAME)))->base.default_def_flag) | |||
2506 | return true; | |||
2507 | else | |||
2508 | return false; | |||
2509 | } | |||
2510 | ||||
2511 | /* Find the indirect call graph edge corresponding to STMT and mark it as a | |||
2512 | call to a parameter number PARAM_INDEX. NODE is the caller. Return the | |||
2513 | indirect call graph edge. | |||
2514 | If POLYMORPHIC is true record is as a destination of polymorphic call. */ | |||
2515 | ||||
2516 | static struct cgraph_edge * | |||
2517 | ipa_note_param_call (struct cgraph_node *node, int param_index, | |||
2518 | gcall *stmt, bool polymorphic) | |||
2519 | { | |||
2520 | struct cgraph_edge *cs; | |||
2521 | ||||
2522 | cs = node->get_edge (stmt); | |||
2523 | cs->indirect_info->param_index = param_index; | |||
2524 | cs->indirect_info->agg_contents = 0; | |||
2525 | cs->indirect_info->member_ptr = 0; | |||
2526 | cs->indirect_info->guaranteed_unmodified = 0; | |||
2527 | ipa_node_params *info = ipa_node_params_sum->get (node); | |||
2528 | ipa_set_param_used_by_indirect_call (info, param_index, true); | |||
2529 | if (cs->indirect_info->polymorphic || polymorphic) | |||
2530 | ipa_set_param_used_by_polymorphic_call (info, param_index, true); | |||
2531 | return cs; | |||
2532 | } | |||
2533 | ||||
2534 | /* Analyze the CALL and examine uses of formal parameters of the caller NODE | |||
2535 | (described by INFO). PARMS_AINFO is a pointer to a vector containing | |||
2536 | intermediate information about each formal parameter. Currently it checks | |||
2537 | whether the call calls a pointer that is a formal parameter and if so, the | |||
2538 | parameter is marked with the called flag and an indirect call graph edge | |||
2539 | describing the call is created. This is very simple for ordinary pointers | |||
2540 | represented in SSA but not-so-nice when it comes to member pointers. The | |||
2541 | ugly part of this function does nothing more than trying to match the | |||
2542 | pattern of such a call. An example of such a pattern is the gimple dump | |||
2543 | below, the call is on the last line: | |||
2544 | ||||
2545 | <bb 2>: | |||
2546 | f$__delta_5 = f.__delta; | |||
2547 | f$__pfn_24 = f.__pfn; | |||
2548 | ||||
2549 | or | |||
2550 | <bb 2>: | |||
2551 | f$__delta_5 = MEM[(struct *)&f]; | |||
2552 | f$__pfn_24 = MEM[(struct *)&f + 4B]; | |||
2553 | ||||
2554 | and a few lines below: | |||
2555 | ||||
2556 | <bb 5> | |||
2557 | D.2496_3 = (int) f$__pfn_24; | |||
2558 | D.2497_4 = D.2496_3 & 1; | |||
2559 | if (D.2497_4 != 0) | |||
2560 | goto <bb 3>; | |||
2561 | else | |||
2562 | goto <bb 4>; | |||
2563 | ||||
2564 | <bb 6>: | |||
2565 | D.2500_7 = (unsigned int) f$__delta_5; | |||
2566 | D.2501_8 = &S + D.2500_7; | |||
2567 | D.2502_9 = (int (*__vtbl_ptr_type) (void) * *) D.2501_8; | |||
2568 | D.2503_10 = *D.2502_9; | |||
2569 | D.2504_12 = f$__pfn_24 + -1; | |||
2570 | D.2505_13 = (unsigned int) D.2504_12; | |||
2571 | D.2506_14 = D.2503_10 + D.2505_13; | |||
2572 | D.2507_15 = *D.2506_14; | |||
2573 | iftmp.11_16 = (String:: *) D.2507_15; | |||
2574 | ||||
2575 | <bb 7>: | |||
2576 | # iftmp.11_1 = PHI <iftmp.11_16(3), f$__pfn_24(2)> | |||
2577 | D.2500_19 = (unsigned int) f$__delta_5; | |||
2578 | D.2508_20 = &S + D.2500_19; | |||
2579 | D.2493_21 = iftmp.11_1 (D.2508_20, 4); | |||
2580 | ||||
2581 | Such patterns are results of simple calls to a member pointer: | |||
2582 | ||||
2583 | int doprinting (int (MyString::* f)(int) const) | |||
2584 | { | |||
2585 | MyString S ("somestring"); | |||
2586 | ||||
2587 | return (S.*f)(4); | |||
2588 | } | |||
2589 | ||||
2590 | Moreover, the function also looks for called pointers loaded from aggregates | |||
2591 | passed by value or reference. */ | |||
2592 | ||||
2593 | static void | |||
2594 | ipa_analyze_indirect_call_uses (struct ipa_func_body_info *fbi, gcall *call, | |||
2595 | tree target) | |||
2596 | { | |||
2597 | class ipa_node_params *info = fbi->info; | |||
2598 | HOST_WIDE_INTlong offset; | |||
2599 | bool by_ref; | |||
2600 | ||||
2601 | if (SSA_NAME_IS_DEFAULT_DEF (target)(tree_check ((target), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 2601, __FUNCTION__, (SSA_NAME)))->base.default_def_flag) | |||
2602 | { | |||
2603 | tree var = SSA_NAME_VAR (target)((tree_check ((target), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 2603, __FUNCTION__, (SSA_NAME)))->ssa_name.var == (tree) nullptr || ((enum tree_code) ((target)->ssa_name.var)-> base.code) == IDENTIFIER_NODE ? (tree) nullptr : (target)-> ssa_name.var); | |||
2604 | int index = ipa_get_param_decl_index (info, var); | |||
2605 | if (index >= 0) | |||
2606 | ipa_note_param_call (fbi->node, index, call, false); | |||
2607 | return; | |||
2608 | } | |||
2609 | ||||
2610 | int index; | |||
2611 | gimple *def = SSA_NAME_DEF_STMT (target)(tree_check ((target), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 2611, __FUNCTION__, (SSA_NAME)))->ssa_name.def_stmt; | |||
2612 | bool guaranteed_unmodified; | |||
2613 | if (gimple_assign_single_p (def) | |||
2614 | && ipa_load_from_parm_agg (fbi, info->descriptors, def, | |||
2615 | gimple_assign_rhs1 (def), &index, &offset, | |||
2616 | NULLnullptr, &by_ref, &guaranteed_unmodified)) | |||
2617 | { | |||
2618 | struct cgraph_edge *cs = ipa_note_param_call (fbi->node, index, | |||
2619 | call, false); | |||
2620 | cs->indirect_info->offset = offset; | |||
2621 | cs->indirect_info->agg_contents = 1; | |||
2622 | cs->indirect_info->by_ref = by_ref; | |||
2623 | cs->indirect_info->guaranteed_unmodified = guaranteed_unmodified; | |||
2624 | return; | |||
2625 | } | |||
2626 | ||||
2627 | /* Now we need to try to match the complex pattern of calling a member | |||
2628 | pointer. */ | |||
2629 | if (gimple_code (def) != GIMPLE_PHI | |||
2630 | || gimple_phi_num_args (def) != 2 | |||
2631 | || !POINTER_TYPE_P (TREE_TYPE (target))(((enum tree_code) (((contains_struct_check ((target), (TS_TYPED ), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 2631, __FUNCTION__))->typed.type))->base.code) == POINTER_TYPE || ((enum tree_code) (((contains_struct_check ((target), (TS_TYPED ), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 2631, __FUNCTION__))->typed.type))->base.code) == REFERENCE_TYPE ) | |||
2632 | || TREE_CODE (TREE_TYPE (TREE_TYPE (target)))((enum tree_code) (((contains_struct_check ((((contains_struct_check ((target), (TS_TYPED), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 2632, __FUNCTION__))->typed.type)), (TS_TYPED), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 2632, __FUNCTION__))->typed.type))->base.code) != METHOD_TYPE) | |||
2633 | return; | |||
2634 | ||||
2635 | /* First, we need to check whether one of these is a load from a member | |||
2636 | pointer that is a parameter to this function. */ | |||
2637 | tree n1 = PHI_ARG_DEF (def, 0)gimple_phi_arg_def ((def), (0)); | |||
2638 | tree n2 = PHI_ARG_DEF (def, 1)gimple_phi_arg_def ((def), (1)); | |||
2639 | if (!ipa_is_ssa_with_stmt_def (n1) || !ipa_is_ssa_with_stmt_def (n2)) | |||
2640 | return; | |||
2641 | gimple *d1 = SSA_NAME_DEF_STMT (n1)(tree_check ((n1), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 2641, __FUNCTION__, (SSA_NAME)))->ssa_name.def_stmt; | |||
2642 | gimple *d2 = SSA_NAME_DEF_STMT (n2)(tree_check ((n2), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 2642, __FUNCTION__, (SSA_NAME)))->ssa_name.def_stmt; | |||
2643 | ||||
2644 | tree rec; | |||
2645 | basic_block bb, virt_bb; | |||
2646 | basic_block join = gimple_bb (def); | |||
2647 | if ((rec = ipa_get_stmt_member_ptr_load_param (d1, false, &offset))) | |||
2648 | { | |||
2649 | if (ipa_get_stmt_member_ptr_load_param (d2, false, NULLnullptr)) | |||
2650 | return; | |||
2651 | ||||
2652 | bb = EDGE_PRED (join, 0)(*(join)->preds)[(0)]->src; | |||
2653 | virt_bb = gimple_bb (d2); | |||
2654 | } | |||
2655 | else if ((rec = ipa_get_stmt_member_ptr_load_param (d2, false, &offset))) | |||
2656 | { | |||
2657 | bb = EDGE_PRED (join, 1)(*(join)->preds)[(1)]->src; | |||
2658 | virt_bb = gimple_bb (d1); | |||
2659 | } | |||
2660 | else | |||
2661 | return; | |||
2662 | ||||
2663 | /* Second, we need to check that the basic blocks are laid out in the way | |||
2664 | corresponding to the pattern. */ | |||
2665 | ||||
2666 | if (!single_pred_p (virt_bb) || !single_succ_p (virt_bb) | |||
2667 | || single_pred (virt_bb) != bb | |||
2668 | || single_succ (virt_bb) != join) | |||
2669 | return; | |||
2670 | ||||
2671 | /* Third, let's see that the branching is done depending on the least | |||
2672 | significant bit of the pfn. */ | |||
2673 | ||||
2674 | gimple *branch = last_stmt (bb); | |||
2675 | if (!branch || gimple_code (branch) != GIMPLE_COND) | |||
2676 | return; | |||
2677 | ||||
2678 | if ((gimple_cond_code (branch) != NE_EXPR | |||
2679 | && gimple_cond_code (branch) != EQ_EXPR) | |||
2680 | || !integer_zerop (gimple_cond_rhs (branch))) | |||
2681 | return; | |||
2682 | ||||
2683 | tree cond = gimple_cond_lhs (branch); | |||
2684 | if (!ipa_is_ssa_with_stmt_def (cond)) | |||
2685 | return; | |||
2686 | ||||
2687 | def = SSA_NAME_DEF_STMT (cond)(tree_check ((cond), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 2687, __FUNCTION__, (SSA_NAME)))->ssa_name.def_stmt; | |||
2688 | if (!is_gimple_assign (def) | |||
2689 | || gimple_assign_rhs_code (def) != BIT_AND_EXPR | |||
2690 | || !integer_onep (gimple_assign_rhs2 (def))) | |||
2691 | return; | |||
2692 | ||||
2693 | cond = gimple_assign_rhs1 (def); | |||
2694 | if (!ipa_is_ssa_with_stmt_def (cond)) | |||
2695 | return; | |||
2696 | ||||
2697 | def = SSA_NAME_DEF_STMT (cond)(tree_check ((cond), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 2697, __FUNCTION__, (SSA_NAME)))->ssa_name.def_stmt; | |||
2698 | ||||
2699 | if (is_gimple_assign (def) | |||
2700 | && CONVERT_EXPR_CODE_P (gimple_assign_rhs_code (def))((gimple_assign_rhs_code (def)) == NOP_EXPR || (gimple_assign_rhs_code (def)) == CONVERT_EXPR)) | |||
2701 | { | |||
2702 | cond = gimple_assign_rhs1 (def); | |||
2703 | if (!ipa_is_ssa_with_stmt_def (cond)) | |||
2704 | return; | |||
2705 | def = SSA_NAME_DEF_STMT (cond)(tree_check ((cond), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 2705, __FUNCTION__, (SSA_NAME)))->ssa_name.def_stmt; | |||
2706 | } | |||
2707 | ||||
2708 | tree rec2; | |||
2709 | rec2 = ipa_get_stmt_member_ptr_load_param (def, | |||
2710 | (TARGET_PTRMEMFUNC_VBIT_LOCATIONptrmemfunc_vbit_in_pfn | |||
2711 | == ptrmemfunc_vbit_in_delta), | |||
2712 | NULLnullptr); | |||
2713 | if (rec != rec2) | |||
2714 | return; | |||
2715 | ||||
2716 | index = ipa_get_param_decl_index (info, rec); | |||
2717 | if (index >= 0 | |||
2718 | && parm_preserved_before_stmt_p (fbi, index, call, rec)) | |||
2719 | { | |||
2720 | struct cgraph_edge *cs = ipa_note_param_call (fbi->node, index, | |||
2721 | call, false); | |||
2722 | cs->indirect_info->offset = offset; | |||
2723 | cs->indirect_info->agg_contents = 1; | |||
2724 | cs->indirect_info->member_ptr = 1; | |||
2725 | cs->indirect_info->guaranteed_unmodified = 1; | |||
2726 | } | |||
2727 | ||||
2728 | return; | |||
2729 | } | |||
2730 | ||||
2731 | /* Analyze a CALL to an OBJ_TYPE_REF which is passed in TARGET and if the | |||
2732 | object referenced in the expression is a formal parameter of the caller | |||
2733 | FBI->node (described by FBI->info), create a call note for the | |||
2734 | statement. */ | |||
2735 | ||||
2736 | static void | |||
2737 | ipa_analyze_virtual_call_uses (struct ipa_func_body_info *fbi, | |||
2738 | gcall *call, tree target) | |||
2739 | { | |||
2740 | tree obj = OBJ_TYPE_REF_OBJECT (target)(*((const_cast<tree*> (tree_operand_check (((tree_check ((target), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 2740, __FUNCTION__, (OBJ_TYPE_REF)))), (1), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 2740, __FUNCTION__))))); | |||
2741 | int index; | |||
2742 | HOST_WIDE_INTlong anc_offset; | |||
2743 | ||||
2744 | if (!flag_devirtualizeglobal_options.x_flag_devirtualize) | |||
2745 | return; | |||
2746 | ||||
2747 | if (TREE_CODE (obj)((enum tree_code) (obj)->base.code) != SSA_NAME) | |||
2748 | return; | |||
2749 | ||||
2750 | class ipa_node_params *info = fbi->info; | |||
2751 | if (SSA_NAME_IS_DEFAULT_DEF (obj)(tree_check ((obj), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 2751, __FUNCTION__, (SSA_NAME)))->base.default_def_flag) | |||
2752 | { | |||
2753 | if (TREE_CODE (SSA_NAME_VAR (obj))((enum tree_code) (((tree_check ((obj), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 2753, __FUNCTION__, (SSA_NAME)))->ssa_name.var == (tree) nullptr || ((enum tree_code) ((obj)->ssa_name.var)->base .code) == IDENTIFIER_NODE ? (tree) nullptr : (obj)->ssa_name .var))->base.code) != PARM_DECL) | |||
2754 | return; | |||
2755 | ||||
2756 | anc_offset = 0; | |||
2757 | index = ipa_get_param_decl_index (info, SSA_NAME_VAR (obj)((tree_check ((obj), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 2757, __FUNCTION__, (SSA_NAME)))->ssa_name.var == (tree) nullptr || ((enum tree_code) ((obj)->ssa_name.var)->base .code) == IDENTIFIER_NODE ? (tree) nullptr : (obj)->ssa_name .var)); | |||
2758 | gcc_assert (index >= 0)((void)(!(index >= 0) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 2758, __FUNCTION__), 0 : 0)); | |||
2759 | if (detect_type_change_ssa (fbi, obj, obj_type_ref_class (target), | |||
2760 | call)) | |||
2761 | return; | |||
2762 | } | |||
2763 | else | |||
2764 | { | |||
2765 | gimple *stmt = SSA_NAME_DEF_STMT (obj)(tree_check ((obj), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 2765, __FUNCTION__, (SSA_NAME)))->ssa_name.def_stmt; | |||
2766 | tree expr; | |||
2767 | ||||
2768 | expr = get_ancestor_addr_info (stmt, &obj, &anc_offset); | |||
2769 | if (!expr) | |||
2770 | return; | |||
2771 | index = ipa_get_param_decl_index (info, | |||
2772 | SSA_NAME_VAR (TREE_OPERAND (expr, 0))((tree_check (((*((const_cast<tree*> (tree_operand_check ((expr), (0), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 2772, __FUNCTION__)))))), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 2772, __FUNCTION__, (SSA_NAME)))->ssa_name.var == (tree) nullptr || ((enum tree_code) (((*((const_cast<tree*> ( tree_operand_check ((expr), (0), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 2772, __FUNCTION__))))))->ssa_name.var)->base.code) == IDENTIFIER_NODE ? (tree) nullptr : ((*((const_cast<tree*> (tree_operand_check ((expr), (0), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 2772, __FUNCTION__))))))->ssa_name.var)); | |||
2773 | gcc_assert (index >= 0)((void)(!(index >= 0) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 2773, __FUNCTION__), 0 : 0)); | |||
2774 | if (detect_type_change (fbi, obj, expr, obj_type_ref_class (target), | |||
2775 | call, anc_offset)) | |||
2776 | return; | |||
2777 | } | |||
2778 | ||||
2779 | struct cgraph_edge *cs = ipa_note_param_call (fbi->node, index, | |||
2780 | call, true); | |||
2781 | class cgraph_indirect_call_info *ii = cs->indirect_info; | |||
2782 | ii->offset = anc_offset; | |||
2783 | ii->otr_token = tree_to_uhwi (OBJ_TYPE_REF_TOKEN (target)(*((const_cast<tree*> (tree_operand_check (((tree_check ((target), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 2783, __FUNCTION__, (OBJ_TYPE_REF)))), (2), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 2783, __FUNCTION__)))))); | |||
2784 | ii->otr_type = obj_type_ref_class (target); | |||
2785 | ii->polymorphic = 1; | |||
2786 | } | |||
2787 | ||||
2788 | /* Analyze a call statement CALL whether and how it utilizes formal parameters | |||
2789 | of the caller (described by INFO). PARMS_AINFO is a pointer to a vector | |||
2790 | containing intermediate information about each formal parameter. */ | |||
2791 | ||||
2792 | static void | |||
2793 | ipa_analyze_call_uses (struct ipa_func_body_info *fbi, gcall *call) | |||
2794 | { | |||
2795 | tree target = gimple_call_fn (call); | |||
2796 | ||||
2797 | if (!target | |||
2798 | || (TREE_CODE (target)((enum tree_code) (target)->base.code) != SSA_NAME | |||
2799 | && !virtual_method_call_p (target))) | |||
2800 | return; | |||
2801 | ||||
2802 | struct cgraph_edge *cs = fbi->node->get_edge (call); | |||
2803 | /* If we previously turned the call into a direct call, there is | |||
2804 | no need to analyze. */ | |||
2805 | if (cs && !cs->indirect_unknown_callee) | |||
2806 | return; | |||
2807 | ||||
2808 | if (cs->indirect_info->polymorphic && flag_devirtualizeglobal_options.x_flag_devirtualize) | |||
2809 | { | |||
2810 | tree instance; | |||
2811 | tree target = gimple_call_fn (call); | |||
2812 | ipa_polymorphic_call_context context (current_function_decl, | |||
2813 | target, call, &instance); | |||
2814 | ||||
2815 | gcc_checking_assert (cs->indirect_info->otr_type((void)(!(cs->indirect_info->otr_type == obj_type_ref_class (target)) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 2816, __FUNCTION__), 0 : 0)) | |||
2816 | == obj_type_ref_class (target))((void)(!(cs->indirect_info->otr_type == obj_type_ref_class (target)) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 2816, __FUNCTION__), 0 : 0)); | |||
2817 | gcc_checking_assert (cs->indirect_info->otr_token((void)(!(cs->indirect_info->otr_token == tree_to_shwi ( (*((const_cast<tree*> (tree_operand_check (((tree_check ((target), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 2818, __FUNCTION__, (OBJ_TYPE_REF)))), (2), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 2818, __FUNCTION__))))))) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 2818, __FUNCTION__), 0 : 0)) | |||
2818 | == tree_to_shwi (OBJ_TYPE_REF_TOKEN (target)))((void)(!(cs->indirect_info->otr_token == tree_to_shwi ( (*((const_cast<tree*> (tree_operand_check (((tree_check ((target), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 2818, __FUNCTION__, (OBJ_TYPE_REF)))), (2), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 2818, __FUNCTION__))))))) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 2818, __FUNCTION__), 0 : 0)); | |||
2819 | ||||
2820 | cs->indirect_info->vptr_changed | |||
2821 | = !context.get_dynamic_type (instance, | |||
2822 | OBJ_TYPE_REF_OBJECT (target)(*((const_cast<tree*> (tree_operand_check (((tree_check ((target), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 2822, __FUNCTION__, (OBJ_TYPE_REF)))), (1), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 2822, __FUNCTION__))))), | |||
2823 | obj_type_ref_class (target), call, | |||
2824 | &fbi->aa_walk_budget); | |||
2825 | cs->indirect_info->context = context; | |||
2826 | } | |||
2827 | ||||
2828 | if (TREE_CODE (target)((enum tree_code) (target)->base.code) == SSA_NAME) | |||
2829 | ipa_analyze_indirect_call_uses (fbi, call, target); | |||
2830 | else if (virtual_method_call_p (target)) | |||
2831 | ipa_analyze_virtual_call_uses (fbi, call, target); | |||
2832 | } | |||
2833 | ||||
2834 | ||||
2835 | /* Analyze the call statement STMT with respect to formal parameters (described | |||
2836 | in INFO) of caller given by FBI->NODE. Currently it only checks whether | |||
2837 | formal parameters are called. */ | |||
2838 | ||||
2839 | static void | |||
2840 | ipa_analyze_stmt_uses (struct ipa_func_body_info *fbi, gimple *stmt) | |||
2841 | { | |||
2842 | if (is_gimple_call (stmt)) | |||
2843 | ipa_analyze_call_uses (fbi, as_a <gcall *> (stmt)); | |||
2844 | } | |||
2845 | ||||
2846 | /* Callback of walk_stmt_load_store_addr_ops for the visit_load. | |||
2847 | If OP is a parameter declaration, mark it as used in the info structure | |||
2848 | passed in DATA. */ | |||
2849 | ||||
2850 | static bool | |||
2851 | visit_ref_for_mod_analysis (gimple *, tree op, tree, void *data) | |||
2852 | { | |||
2853 | class ipa_node_params *info = (class ipa_node_params *) data; | |||
2854 | ||||
2855 | op = get_base_address (op); | |||
2856 | if (op | |||
2857 | && TREE_CODE (op)((enum tree_code) (op)->base.code) == PARM_DECL) | |||
2858 | { | |||
2859 | int index = ipa_get_param_decl_index (info, op); | |||
2860 | gcc_assert (index >= 0)((void)(!(index >= 0) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 2860, __FUNCTION__), 0 : 0)); | |||
2861 | ipa_set_param_used (info, index, true); | |||
2862 | } | |||
2863 | ||||
2864 | return false; | |||
2865 | } | |||
2866 | ||||
2867 | /* Scan the statements in BB and inspect the uses of formal parameters. Store | |||
2868 | the findings in various structures of the associated ipa_node_params | |||
2869 | structure, such as parameter flags, notes etc. FBI holds various data about | |||
2870 | the function being analyzed. */ | |||
2871 | ||||
2872 | static void | |||
2873 | ipa_analyze_params_uses_in_bb (struct ipa_func_body_info *fbi, basic_block bb) | |||
2874 | { | |||
2875 | gimple_stmt_iterator gsi; | |||
2876 | for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi)) | |||
2877 | { | |||
2878 | gimple *stmt = gsi_stmt (gsi); | |||
2879 | ||||
2880 | if (is_gimple_debug (stmt)) | |||
2881 | continue; | |||
2882 | ||||
2883 | ipa_analyze_stmt_uses (fbi, stmt); | |||
2884 | walk_stmt_load_store_addr_ops (stmt, fbi->info, | |||
2885 | visit_ref_for_mod_analysis, | |||
2886 | visit_ref_for_mod_analysis, | |||
2887 | visit_ref_for_mod_analysis); | |||
2888 | } | |||
2889 | for (gsi = gsi_start_phis (bb); !gsi_end_p (gsi); gsi_next (&gsi)) | |||
2890 | walk_stmt_load_store_addr_ops (gsi_stmt (gsi), fbi->info, | |||
2891 | visit_ref_for_mod_analysis, | |||
2892 | visit_ref_for_mod_analysis, | |||
2893 | visit_ref_for_mod_analysis); | |||
2894 | } | |||
2895 | ||||
2896 | /* Return true EXPR is a load from a dereference of SSA_NAME NAME. */ | |||
2897 | ||||
2898 | static bool | |||
2899 | load_from_dereferenced_name (tree expr, tree name) | |||
2900 | { | |||
2901 | tree base = get_base_address (expr); | |||
2902 | return (TREE_CODE (base)((enum tree_code) (base)->base.code) == MEM_REF | |||
2903 | && TREE_OPERAND (base, 0)(*((const_cast<tree*> (tree_operand_check ((base), (0), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 2903, __FUNCTION__))))) == name); | |||
2904 | } | |||
2905 | ||||
2906 | /* Calculate controlled uses of parameters of NODE. */ | |||
2907 | ||||
2908 | static void | |||
2909 | ipa_analyze_controlled_uses (struct cgraph_node *node) | |||
2910 | { | |||
2911 | ipa_node_params *info = ipa_node_params_sum->get (node); | |||
2912 | ||||
2913 | for (int i = 0; i < ipa_get_param_count (info); i++) | |||
2914 | { | |||
2915 | tree parm = ipa_get_param (info, i); | |||
2916 | int call_uses = 0; | |||
2917 | bool load_dereferenced = false; | |||
2918 | ||||
2919 | /* For SSA regs see if parameter is used. For non-SSA we compute | |||
2920 | the flag during modification analysis. */ | |||
2921 | if (is_gimple_reg (parm)) | |||
2922 | { | |||
2923 | tree ddef = ssa_default_def (DECL_STRUCT_FUNCTION (node->decl)((tree_check ((node->decl), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 2923, __FUNCTION__, (FUNCTION_DECL)))->function_decl.f), | |||
2924 | parm); | |||
2925 | if (ddef && !has_zero_uses (ddef)) | |||
2926 | { | |||
2927 | imm_use_iterator imm_iter; | |||
2928 | gimple *stmt; | |||
2929 | ||||
2930 | ipa_set_param_used (info, i, true); | |||
2931 | FOR_EACH_IMM_USE_STMT (stmt, imm_iter, ddef)for (struct auto_end_imm_use_stmt_traverse auto_end_imm_use_stmt_traverse ((((stmt) = first_imm_use_stmt (&(imm_iter), (ddef))), & (imm_iter))); !end_imm_use_stmt_p (&(imm_iter)); (void) ( (stmt) = next_imm_use_stmt (&(imm_iter)))) | |||
2932 | { | |||
2933 | if (is_gimple_debug (stmt)) | |||
2934 | continue; | |||
2935 | ||||
2936 | int all_stmt_uses = 0; | |||
2937 | use_operand_p use_p; | |||
2938 | FOR_EACH_IMM_USE_ON_STMT (use_p, imm_iter)for ((use_p) = first_imm_use_on_stmt (&(imm_iter)); !end_imm_use_on_stmt_p (&(imm_iter)); (void) ((use_p) = next_imm_use_on_stmt (& (imm_iter)))) | |||
2939 | all_stmt_uses++; | |||
2940 | ||||
2941 | if (is_gimple_call (stmt)) | |||
2942 | { | |||
2943 | if (gimple_call_internal_p (stmt)) | |||
2944 | { | |||
2945 | call_uses = IPA_UNDESCRIBED_USE-1; | |||
2946 | break; | |||
2947 | } | |||
2948 | int recognized_stmt_uses; | |||
2949 | if (gimple_call_fn (stmt) == ddef) | |||
2950 | recognized_stmt_uses = 1; | |||
2951 | else | |||
2952 | recognized_stmt_uses = 0; | |||
2953 | unsigned arg_count = gimple_call_num_args (stmt); | |||
2954 | for (unsigned i = 0; i < arg_count; i++) | |||
2955 | { | |||
2956 | tree arg = gimple_call_arg (stmt, i); | |||
2957 | if (arg == ddef) | |||
2958 | recognized_stmt_uses++; | |||
2959 | else if (load_from_dereferenced_name (arg, ddef)) | |||
2960 | { | |||
2961 | load_dereferenced = true; | |||
2962 | recognized_stmt_uses++; | |||
2963 | } | |||
2964 | } | |||
2965 | ||||
2966 | if (recognized_stmt_uses != all_stmt_uses) | |||
2967 | { | |||
2968 | call_uses = IPA_UNDESCRIBED_USE-1; | |||
2969 | break; | |||
2970 | } | |||
2971 | if (call_uses >= 0) | |||
2972 | call_uses += all_stmt_uses; | |||
2973 | } | |||
2974 | else if (gimple_assign_single_p (stmt)) | |||
2975 | { | |||
2976 | tree rhs = gimple_assign_rhs1 (stmt); | |||
2977 | if (all_stmt_uses != 1 | |||
2978 | || !load_from_dereferenced_name (rhs, ddef)) | |||
2979 | { | |||
2980 | call_uses = IPA_UNDESCRIBED_USE-1; | |||
2981 | break; | |||
2982 | } | |||
2983 | load_dereferenced = true; | |||
2984 | } | |||
2985 | else | |||
2986 | { | |||
2987 | call_uses = IPA_UNDESCRIBED_USE-1; | |||
2988 | break; | |||
2989 | } | |||
2990 | } | |||
2991 | } | |||
2992 | else | |||
2993 | call_uses = 0; | |||
2994 | } | |||
2995 | else | |||
2996 | call_uses = IPA_UNDESCRIBED_USE-1; | |||
2997 | ipa_set_controlled_uses (info, i, call_uses); | |||
2998 | ipa_set_param_load_dereferenced (info, i, load_dereferenced); | |||
2999 | } | |||
3000 | } | |||
3001 | ||||
3002 | /* Free stuff in BI. */ | |||
3003 | ||||
3004 | static void | |||
3005 | free_ipa_bb_info (struct ipa_bb_info *bi) | |||
3006 | { | |||
3007 | bi->cg_edges.release (); | |||
3008 | bi->param_aa_statuses.release (); | |||
3009 | } | |||
3010 | ||||
3011 | /* Dominator walker driving the analysis. */ | |||
3012 | ||||
3013 | class analysis_dom_walker : public dom_walker | |||
3014 | { | |||
3015 | public: | |||
3016 | analysis_dom_walker (struct ipa_func_body_info *fbi) | |||
3017 | : dom_walker (CDI_DOMINATORS), m_fbi (fbi) {} | |||
3018 | ||||
3019 | edge before_dom_children (basic_block) final override; | |||
3020 | ||||
3021 | private: | |||
3022 | struct ipa_func_body_info *m_fbi; | |||
3023 | }; | |||
3024 | ||||
3025 | edge | |||
3026 | analysis_dom_walker::before_dom_children (basic_block bb) | |||
3027 | { | |||
3028 | ipa_analyze_params_uses_in_bb (m_fbi, bb); | |||
3029 | ipa_compute_jump_functions_for_bb (m_fbi, bb); | |||
3030 | return NULLnullptr; | |||
3031 | } | |||
3032 | ||||
3033 | /* Release body info FBI. */ | |||
3034 | ||||
3035 | void | |||
3036 | ipa_release_body_info (struct ipa_func_body_info *fbi) | |||
3037 | { | |||
3038 | int i; | |||
3039 | struct ipa_bb_info *bi; | |||
3040 | ||||
3041 | FOR_EACH_VEC_ELT (fbi->bb_infos, i, bi)for (i = 0; (fbi->bb_infos).iterate ((i), &(bi)); ++(i )) | |||
3042 | free_ipa_bb_info (bi); | |||
3043 | fbi->bb_infos.release (); | |||
3044 | } | |||
3045 | ||||
3046 | /* Initialize the array describing properties of formal parameters | |||
3047 | of NODE, analyze their uses and compute jump functions associated | |||
3048 | with actual arguments of calls from within NODE. */ | |||
3049 | ||||
3050 | void | |||
3051 | ipa_analyze_node (struct cgraph_node *node) | |||
3052 | { | |||
3053 | struct ipa_func_body_info fbi; | |||
3054 | class ipa_node_params *info; | |||
3055 | ||||
3056 | ipa_check_create_node_params (); | |||
3057 | ipa_check_create_edge_args (); | |||
3058 | info = ipa_node_params_sum->get_create (node); | |||
3059 | ||||
3060 | if (info->analysis_done) | |||
3061 | return; | |||
3062 | info->analysis_done = 1; | |||
3063 | ||||
3064 | if (ipa_func_spec_opts_forbid_analysis_p (node) | |||
3065 | || (count_formal_params (node->decl) | |||
3066 | >= (1 << IPA_PROP_ARG_INDEX_LIMIT_BITS16))) | |||
3067 | { | |||
3068 | gcc_assert (!ipa_get_param_count (info))((void)(!(!ipa_get_param_count (info)) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 3068, __FUNCTION__), 0 : 0)); | |||
3069 | return; | |||
3070 | } | |||
3071 | ||||
3072 | struct function *func = DECL_STRUCT_FUNCTION (node->decl)((tree_check ((node->decl), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 3072, __FUNCTION__, (FUNCTION_DECL)))->function_decl.f); | |||
3073 | push_cfun (func); | |||
3074 | calculate_dominance_info (CDI_DOMINATORS); | |||
3075 | ipa_initialize_node_params (node); | |||
3076 | ipa_analyze_controlled_uses (node); | |||
3077 | ||||
3078 | fbi.node = node; | |||
3079 | fbi.info = info; | |||
3080 | fbi.bb_infos = vNULL; | |||
3081 | fbi.bb_infos.safe_grow_cleared (last_basic_block_for_fn (cfun)(((cfun + 0))->cfg->x_last_basic_block), true); | |||
3082 | fbi.param_count = ipa_get_param_count (info); | |||
3083 | fbi.aa_walk_budget = opt_for_fn (node->decl, param_ipa_max_aa_steps)(opts_for_fn (node->decl)->x_param_ipa_max_aa_steps); | |||
3084 | ||||
3085 | for (struct cgraph_edge *cs = node->callees; cs; cs = cs->next_callee) | |||
3086 | { | |||
3087 | ipa_bb_info *bi = ipa_get_bb_info (&fbi, gimple_bb (cs->call_stmt)); | |||
3088 | bi->cg_edges.safe_push (cs); | |||
3089 | } | |||
3090 | ||||
3091 | for (struct cgraph_edge *cs = node->indirect_calls; cs; cs = cs->next_callee) | |||
3092 | { | |||
3093 | ipa_bb_info *bi = ipa_get_bb_info (&fbi, gimple_bb (cs->call_stmt)); | |||
3094 | bi->cg_edges.safe_push (cs); | |||
3095 | } | |||
3096 | ||||
3097 | analysis_dom_walker (&fbi).walk (ENTRY_BLOCK_PTR_FOR_FN (cfun)(((cfun + 0))->cfg->x_entry_block_ptr)); | |||
3098 | ||||
3099 | ipa_release_body_info (&fbi); | |||
3100 | free_dominance_info (CDI_DOMINATORS); | |||
3101 | pop_cfun (); | |||
3102 | } | |||
3103 | ||||
3104 | /* Update the jump functions associated with call graph edge E when the call | |||
3105 | graph edge CS is being inlined, assuming that E->caller is already (possibly | |||
3106 | indirectly) inlined into CS->callee and that E has not been inlined. */ | |||
3107 | ||||
3108 | static void | |||
3109 | update_jump_functions_after_inlining (struct cgraph_edge *cs, | |||
3110 | struct cgraph_edge *e) | |||
3111 | { | |||
3112 | ipa_edge_args *top = ipa_edge_args_sum->get (cs); | |||
3113 | ipa_edge_args *args = ipa_edge_args_sum->get (e); | |||
3114 | if (!args) | |||
3115 | return; | |||
3116 | int count = ipa_get_cs_argument_count (args); | |||
3117 | int i; | |||
3118 | ||||
3119 | for (i = 0; i < count; i++) | |||
3120 | { | |||
3121 | struct ipa_jump_func *dst = ipa_get_ith_jump_func (args, i); | |||
3122 | class ipa_polymorphic_call_context *dst_ctx | |||
3123 | = ipa_get_ith_polymorhic_call_context (args, i); | |||
3124 | ||||
3125 | if (dst->agg.items) | |||
3126 | { | |||
3127 | struct ipa_agg_jf_item *item; | |||
3128 | int j; | |||
3129 | ||||
3130 | FOR_EACH_VEC_ELT (*dst->agg.items, j, item)for (j = 0; (*dst->agg.items).iterate ((j), &(item)); ++ (j)) | |||
3131 | { | |||
3132 | int dst_fid; | |||
3133 | struct ipa_jump_func *src; | |||
3134 | ||||
3135 | if (item->jftype != IPA_JF_PASS_THROUGH | |||
3136 | && item->jftype != IPA_JF_LOAD_AGG) | |||
3137 | continue; | |||
3138 | ||||
3139 | dst_fid = item->value.pass_through.formal_id; | |||
3140 | if (!top || dst_fid >= ipa_get_cs_argument_count (top)) | |||
3141 | { | |||
3142 | item->jftype = IPA_JF_UNKNOWN; | |||
3143 | continue; | |||
3144 | } | |||
3145 | ||||
3146 | item->value.pass_through.formal_id = -1; | |||
3147 | src = ipa_get_ith_jump_func (top, dst_fid); | |||
3148 | if (src->type == IPA_JF_CONST) | |||
3149 | { | |||
3150 | if (item->jftype == IPA_JF_PASS_THROUGH | |||
3151 | && item->value.pass_through.operation == NOP_EXPR) | |||
3152 | { | |||
3153 | item->jftype = IPA_JF_CONST; | |||
3154 | item->value.constant = src->value.constant.value; | |||
3155 | continue; | |||
3156 | } | |||
3157 | } | |||
3158 | else if (src->type == IPA_JF_PASS_THROUGH | |||
3159 | && src->value.pass_through.operation == NOP_EXPR) | |||
3160 | { | |||
3161 | if (item->jftype == IPA_JF_PASS_THROUGH | |||
3162 | || !item->value.load_agg.by_ref | |||
3163 | || src->value.pass_through.agg_preserved) | |||
3164 | item->value.pass_through.formal_id | |||
3165 | = src->value.pass_through.formal_id; | |||
3166 | } | |||
3167 | else if (src->type == IPA_JF_ANCESTOR) | |||
3168 | { | |||
3169 | if (item->jftype == IPA_JF_PASS_THROUGH) | |||
3170 | { | |||
3171 | if (!src->value.ancestor.offset) | |||
3172 | item->value.pass_through.formal_id | |||
3173 | = src->value.ancestor.formal_id; | |||
3174 | } | |||
3175 | else if (src->value.ancestor.agg_preserved) | |||
3176 | { | |||
3177 | gcc_checking_assert (item->value.load_agg.by_ref)((void)(!(item->value.load_agg.by_ref) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 3177, __FUNCTION__), 0 : 0)); | |||
3178 | ||||
3179 | item->value.pass_through.formal_id | |||
3180 | = src->value.ancestor.formal_id; | |||
3181 | item->value.load_agg.offset | |||
3182 | += src->value.ancestor.offset; | |||
3183 | } | |||
3184 | } | |||
3185 | ||||
3186 | if (item->value.pass_through.formal_id < 0) | |||
3187 | item->jftype = IPA_JF_UNKNOWN; | |||
3188 | } | |||
3189 | } | |||
3190 | ||||
3191 | if (!top) | |||
3192 | { | |||
3193 | ipa_set_jf_unknown (dst); | |||
3194 | continue; | |||
3195 | } | |||
3196 | ||||
3197 | if (dst->type == IPA_JF_ANCESTOR) | |||
3198 | { | |||
3199 | struct ipa_jump_func *src; | |||
3200 | int dst_fid = dst->value.ancestor.formal_id; | |||
3201 | class ipa_polymorphic_call_context *src_ctx | |||
3202 | = ipa_get_ith_polymorhic_call_context (top, dst_fid); | |||
3203 | ||||
3204 | /* Variable number of arguments can cause havoc if we try to access | |||
3205 | one that does not exist in the inlined edge. So make sure we | |||
3206 | don't. */ | |||
3207 | if (dst_fid >= ipa_get_cs_argument_count (top)) | |||
3208 | { | |||
3209 | ipa_set_jf_unknown (dst); | |||
3210 | continue; | |||
3211 | } | |||
3212 | ||||
3213 | src = ipa_get_ith_jump_func (top, dst_fid); | |||
3214 | ||||
3215 | if (src_ctx && !src_ctx->useless_p ()) | |||
3216 | { | |||
3217 | class ipa_polymorphic_call_context ctx = *src_ctx; | |||
3218 | ||||
3219 | /* TODO: Make type preserved safe WRT contexts. */ | |||
3220 | if (!ipa_get_jf_ancestor_type_preserved (dst)) | |||
3221 | ctx.possible_dynamic_type_change (e->in_polymorphic_cdtor); | |||
3222 | ctx.offset_by (dst->value.ancestor.offset); | |||
3223 | if (!ctx.useless_p ()) | |||
3224 | { | |||
3225 | if (!dst_ctx) | |||
3226 | { | |||
3227 | vec_safe_grow_cleared (args->polymorphic_call_contexts, | |||
3228 | count, true); | |||
3229 | dst_ctx = ipa_get_ith_polymorhic_call_context (args, i); | |||
3230 | } | |||
3231 | ||||
3232 | dst_ctx->combine_with (ctx); | |||
3233 | } | |||
3234 | } | |||
3235 | ||||
3236 | /* Parameter and argument in ancestor jump function must be pointer | |||
3237 | type, which means access to aggregate must be by-reference. */ | |||
3238 | gcc_assert (!src->agg.items || src->agg.by_ref)((void)(!(!src->agg.items || src->agg.by_ref) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 3238, __FUNCTION__), 0 : 0)); | |||
3239 | ||||
3240 | if (src->agg.items && dst->value.ancestor.agg_preserved) | |||
3241 | { | |||
3242 | struct ipa_agg_jf_item *item; | |||
3243 | int j; | |||
3244 | ||||
3245 | /* Currently we do not produce clobber aggregate jump functions, | |||
3246 | replace with merging when we do. */ | |||
3247 | gcc_assert (!dst->agg.items)((void)(!(!dst->agg.items) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 3247, __FUNCTION__), 0 : 0)); | |||
3248 | ||||
3249 | dst->agg.items = vec_safe_copy (src->agg.items); | |||
3250 | dst->agg.by_ref = src->agg.by_ref; | |||
3251 | FOR_EACH_VEC_SAFE_ELT (dst->agg.items, j, item)for (j = 0; vec_safe_iterate ((dst->agg.items), (j), & (item)); ++(j)) | |||
3252 | item->offset -= dst->value.ancestor.offset; | |||
3253 | } | |||
3254 | ||||
3255 | if (src->type == IPA_JF_PASS_THROUGH | |||
3256 | && src->value.pass_through.operation == NOP_EXPR) | |||
3257 | { | |||
3258 | dst->value.ancestor.formal_id = src->value.pass_through.formal_id; | |||
3259 | dst->value.ancestor.agg_preserved &= | |||
3260 | src->value.pass_through.agg_preserved; | |||
3261 | } | |||
3262 | else if (src->type == IPA_JF_ANCESTOR) | |||
3263 | { | |||
3264 | dst->value.ancestor.formal_id = src->value.ancestor.formal_id; | |||
3265 | dst->value.ancestor.offset += src->value.ancestor.offset; | |||
3266 | dst->value.ancestor.agg_preserved &= | |||
3267 | src->value.ancestor.agg_preserved; | |||
3268 | dst->value.ancestor.keep_null |= src->value.ancestor.keep_null; | |||
3269 | } | |||
3270 | else | |||
3271 | ipa_set_jf_unknown (dst); | |||
3272 | } | |||
3273 | else if (dst->type == IPA_JF_PASS_THROUGH) | |||
3274 | { | |||
3275 | struct ipa_jump_func *src; | |||
3276 | /* We must check range due to calls with variable number of arguments | |||
3277 | and we cannot combine jump functions with operations. */ | |||
3278 | if (dst->value.pass_through.operation == NOP_EXPR | |||
3279 | && (top && dst->value.pass_through.formal_id | |||
3280 | < ipa_get_cs_argument_count (top))) | |||
3281 | { | |||
3282 | int dst_fid = dst->value.pass_through.formal_id; | |||
3283 | src = ipa_get_ith_jump_func (top, dst_fid); | |||
3284 | bool dst_agg_p = ipa_get_jf_pass_through_agg_preserved (dst); | |||
3285 | class ipa_polymorphic_call_context *src_ctx | |||
3286 | = ipa_get_ith_polymorhic_call_context (top, dst_fid); | |||
3287 | ||||
3288 | if (src_ctx && !src_ctx->useless_p ()) | |||
3289 | { | |||
3290 | class ipa_polymorphic_call_context ctx = *src_ctx; | |||
3291 | ||||
3292 | /* TODO: Make type preserved safe WRT contexts. */ | |||
3293 | if (!ipa_get_jf_pass_through_type_preserved (dst)) | |||
3294 | ctx.possible_dynamic_type_change (e->in_polymorphic_cdtor); | |||
3295 | if (!ctx.useless_p ()) | |||
3296 | { | |||
3297 | if (!dst_ctx) | |||
3298 | { | |||
3299 | vec_safe_grow_cleared (args->polymorphic_call_contexts, | |||
3300 | count, true); | |||
3301 | dst_ctx = ipa_get_ith_polymorhic_call_context (args, i); | |||
3302 | } | |||
3303 | dst_ctx->combine_with (ctx); | |||
3304 | } | |||
3305 | } | |||
3306 | switch (src->type) | |||
3307 | { | |||
3308 | case IPA_JF_UNKNOWN: | |||
3309 | ipa_set_jf_unknown (dst); | |||
3310 | break; | |||
3311 | case IPA_JF_CONST: | |||
3312 | ipa_set_jf_cst_copy (dst, src); | |||
3313 | break; | |||
3314 | ||||
3315 | case IPA_JF_PASS_THROUGH: | |||
3316 | { | |||
3317 | int formal_id = ipa_get_jf_pass_through_formal_id (src); | |||
3318 | enum tree_code operation; | |||
3319 | operation = ipa_get_jf_pass_through_operation (src); | |||
3320 | ||||
3321 | if (operation == NOP_EXPR) | |||
3322 | { | |||
3323 | bool agg_p; | |||
3324 | agg_p = dst_agg_p | |||
3325 | && ipa_get_jf_pass_through_agg_preserved (src); | |||
3326 | ipa_set_jf_simple_pass_through (dst, formal_id, agg_p); | |||
3327 | } | |||
3328 | else if (TREE_CODE_CLASS (operation)tree_code_type_tmpl <0>::tree_code_type[(int) (operation )] == tcc_unary) | |||
3329 | ipa_set_jf_unary_pass_through (dst, formal_id, operation); | |||
3330 | else | |||
3331 | { | |||
3332 | tree operand = ipa_get_jf_pass_through_operand (src); | |||
3333 | ipa_set_jf_arith_pass_through (dst, formal_id, operand, | |||
3334 | operation); | |||
3335 | } | |||
3336 | break; | |||
3337 | } | |||
3338 | case IPA_JF_ANCESTOR: | |||
3339 | { | |||
3340 | bool agg_p; | |||
3341 | agg_p = dst_agg_p | |||
3342 | && ipa_get_jf_ancestor_agg_preserved (src); | |||
3343 | ipa_set_ancestor_jf (dst, | |||
3344 | ipa_get_jf_ancestor_offset (src), | |||
3345 | ipa_get_jf_ancestor_formal_id (src), | |||
3346 | agg_p, | |||
3347 | ipa_get_jf_ancestor_keep_null (src)); | |||
3348 | break; | |||
3349 | } | |||
3350 | default: | |||
3351 | gcc_unreachable ()(fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 3351, __FUNCTION__)); | |||
3352 | } | |||
3353 | ||||
3354 | if (src->agg.items | |||
3355 | && (dst_agg_p || !src->agg.by_ref)) | |||
3356 | { | |||
3357 | /* Currently we do not produce clobber aggregate jump | |||
3358 | functions, replace with merging when we do. */ | |||
3359 | gcc_assert (!dst->agg.items)((void)(!(!dst->agg.items) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 3359, __FUNCTION__), 0 : 0)); | |||
3360 | ||||
3361 | dst->agg.by_ref = src->agg.by_ref; | |||
3362 | dst->agg.items = vec_safe_copy (src->agg.items); | |||
3363 | } | |||
3364 | } | |||
3365 | else | |||
3366 | ipa_set_jf_unknown (dst); | |||
3367 | } | |||
3368 | } | |||
3369 | } | |||
3370 | ||||
3371 | /* If TARGET is an addr_expr of a function declaration, make it the | |||
3372 | (SPECULATIVE)destination of an indirect edge IE and return the edge. | |||
3373 | Otherwise, return NULL. */ | |||
3374 | ||||
3375 | struct cgraph_edge * | |||
3376 | ipa_make_edge_direct_to_target (struct cgraph_edge *ie, tree target, | |||
3377 | bool speculative) | |||
3378 | { | |||
3379 | struct cgraph_node *callee; | |||
3380 | bool unreachable = false; | |||
3381 | ||||
3382 | if (TREE_CODE (target)((enum tree_code) (target)->base.code) == ADDR_EXPR) | |||
3383 | target = TREE_OPERAND (target, 0)(*((const_cast<tree*> (tree_operand_check ((target), (0 ), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 3383, __FUNCTION__))))); | |||
3384 | if (TREE_CODE (target)((enum tree_code) (target)->base.code) != FUNCTION_DECL) | |||
3385 | { | |||
3386 | target = canonicalize_constructor_val (target, NULLnullptr); | |||
3387 | if (!target || TREE_CODE (target)((enum tree_code) (target)->base.code) != FUNCTION_DECL) | |||
3388 | { | |||
3389 | /* Member pointer call that goes through a VMT lookup. */ | |||
3390 | if (ie->indirect_info->member_ptr | |||
3391 | /* Or if target is not an invariant expression and we do not | |||
3392 | know if it will evaulate to function at runtime. | |||
3393 | This can happen when folding through &VAR, where &VAR | |||
3394 | is IP invariant, but VAR itself is not. | |||
3395 | ||||
3396 | TODO: Revisit this when GCC 5 is branched. It seems that | |||
3397 | member_ptr check is not needed and that we may try to fold | |||
3398 | the expression and see if VAR is readonly. */ | |||
3399 | || !is_gimple_ip_invariant (target)) | |||
3400 | { | |||
3401 | if (dump_enabled_p ()) | |||
3402 | { | |||
3403 | dump_printf_loc (MSG_OPTIMIZED_LOCATIONS, ie->call_stmt, | |||
3404 | "discovered direct call non-invariant %s\n", | |||
3405 | ie->caller->dump_name ()); | |||
3406 | } | |||
3407 | return NULLnullptr; | |||
3408 | } | |||
3409 | ||||
3410 | ||||
3411 | if (dump_enabled_p ()) | |||
3412 | { | |||
3413 | dump_printf_loc (MSG_OPTIMIZED_LOCATIONS, ie->call_stmt, | |||
3414 | "discovered direct call to non-function in %s, " | |||
3415 | "making it __builtin_unreachable\n", | |||
3416 | ie->caller->dump_name ()); | |||
3417 | } | |||
3418 | ||||
3419 | target = builtin_decl_unreachable (); | |||
3420 | callee = cgraph_node::get_create (target); | |||
3421 | unreachable = true; | |||
3422 | } | |||
3423 | else | |||
3424 | callee = cgraph_node::get (target); | |||
3425 | } | |||
3426 | else | |||
3427 | callee = cgraph_node::get (target); | |||
3428 | ||||
3429 | /* Because may-edges are not explicitely represented and vtable may be external, | |||
3430 | we may create the first reference to the object in the unit. */ | |||
3431 | if (!callee || callee->inlined_to) | |||
3432 | { | |||
3433 | ||||
3434 | /* We are better to ensure we can refer to it. | |||
3435 | In the case of static functions we are out of luck, since we already | |||
3436 | removed its body. In the case of public functions we may or may | |||
3437 | not introduce the reference. */ | |||
3438 | if (!canonicalize_constructor_val (target, NULLnullptr) | |||
3439 | || !TREE_PUBLIC (target)((target)->base.public_flag)) | |||
3440 | { | |||
3441 | if (dump_file) | |||
3442 | fprintf (dump_file, "ipa-prop: Discovered call to a known target " | |||
3443 | "(%s -> %s) but cannot refer to it. Giving up.\n", | |||
3444 | ie->caller->dump_name (), | |||
3445 | ie->callee->dump_name ()); | |||
3446 | return NULLnullptr; | |||
3447 | } | |||
3448 | callee = cgraph_node::get_create (target); | |||
3449 | } | |||
3450 | ||||
3451 | /* If the edge is already speculated. */ | |||
3452 | if (speculative && ie->speculative) | |||
3453 | { | |||
3454 | if (dump_file) | |||
3455 | { | |||
3456 | cgraph_edge *e2 = ie->speculative_call_for_target (callee); | |||
3457 | if (!e2) | |||
3458 | { | |||
3459 | if (dump_file) | |||
3460 | fprintf (dump_file, "ipa-prop: Discovered call to a " | |||
3461 | "speculative target (%s -> %s) but the call is " | |||
3462 | "already speculated to different target. " | |||
3463 | "Giving up.\n", | |||
3464 | ie->caller->dump_name (), callee->dump_name ()); | |||
3465 | } | |||
3466 | else | |||
3467 | { | |||
3468 | if (dump_file) | |||
3469 | fprintf (dump_file, | |||
3470 | "ipa-prop: Discovered call to a speculative target " | |||
3471 | "(%s -> %s) this agree with previous speculation.\n", | |||
3472 | ie->caller->dump_name (), callee->dump_name ()); | |||
3473 | } | |||
3474 | } | |||
3475 | return NULLnullptr; | |||
3476 | } | |||
3477 | ||||
3478 | if (!dbg_cnt (devirt)) | |||
3479 | return NULLnullptr; | |||
3480 | ||||
3481 | ipa_check_create_node_params (); | |||
3482 | ||||
3483 | /* We cannot make edges to inline clones. It is bug that someone removed | |||
3484 | the cgraph node too early. */ | |||
3485 | gcc_assert (!callee->inlined_to)((void)(!(!callee->inlined_to) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 3485, __FUNCTION__), 0 : 0)); | |||
3486 | ||||
3487 | if (dump_file && !unreachable) | |||
3488 | { | |||
3489 | fprintf (dump_file, "ipa-prop: Discovered %s call to a %s target " | |||
3490 | "(%s -> %s), for stmt ", | |||
3491 | ie->indirect_info->polymorphic ? "a virtual" : "an indirect", | |||
3492 | speculative ? "speculative" : "known", | |||
3493 | ie->caller->dump_name (), | |||
3494 | callee->dump_name ()); | |||
3495 | if (ie->call_stmt) | |||
3496 | print_gimple_stmt (dump_file, ie->call_stmt, 2, TDF_SLIM); | |||
3497 | else | |||
3498 | fprintf (dump_file, "with uid %i\n", ie->lto_stmt_uid); | |||
3499 | } | |||
3500 | if (dump_enabled_p ()) | |||
3501 | { | |||
3502 | dump_printf_loc (MSG_OPTIMIZED_LOCATIONS, ie->call_stmt, | |||
3503 | "converting indirect call in %s to direct call to %s\n", | |||
3504 | ie->caller->dump_name (), callee->dump_name ()); | |||
3505 | } | |||
3506 | if (!speculative) | |||
3507 | { | |||
3508 | struct cgraph_edge *orig = ie; | |||
3509 | ie = cgraph_edge::make_direct (ie, callee); | |||
3510 | /* If we resolved speculative edge the cost is already up to date | |||
3511 | for direct call (adjusted by inline_edge_duplication_hook). */ | |||
3512 | if (ie == orig) | |||
3513 | { | |||
3514 | ipa_call_summary *es = ipa_call_summaries->get (ie); | |||
3515 | es->call_stmt_size -= (eni_size_weights.indirect_call_cost | |||
3516 | - eni_size_weights.call_cost); | |||
3517 | es->call_stmt_time -= (eni_time_weights.indirect_call_cost | |||
3518 | - eni_time_weights.call_cost); | |||
3519 | } | |||
3520 | } | |||
3521 | else | |||
3522 | { | |||
3523 | if (!callee->can_be_discarded_p ()) | |||
3524 | { | |||
3525 | cgraph_node *alias; | |||
3526 | alias = dyn_cast<cgraph_node *> (callee->noninterposable_alias ()); | |||
3527 | if (alias) | |||
3528 | callee = alias; | |||
3529 | } | |||
3530 | /* make_speculative will update ie's cost to direct call cost. */ | |||
3531 | ie = ie->make_speculative | |||
3532 | (callee, ie->count.apply_scale (8, 10)); | |||
3533 | } | |||
3534 | ||||
3535 | return ie; | |||
3536 | } | |||
3537 | ||||
3538 | /* Attempt to locate an interprocedural constant at a given REQ_OFFSET in | |||
3539 | CONSTRUCTOR and return it. Return NULL if the search fails for some | |||
3540 | reason. */ | |||
3541 | ||||
3542 | static tree | |||
3543 | find_constructor_constant_at_offset (tree constructor, HOST_WIDE_INTlong req_offset) | |||
3544 | { | |||
3545 | tree type = TREE_TYPE (constructor)((contains_struct_check ((constructor), (TS_TYPED), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 3545, __FUNCTION__))->typed.type); | |||
3546 | if (TREE_CODE (type)((enum tree_code) (type)->base.code) != ARRAY_TYPE | |||
3547 | && TREE_CODE (type)((enum tree_code) (type)->base.code) != RECORD_TYPE) | |||
3548 | return NULLnullptr; | |||
3549 | ||||
3550 | unsigned ix; | |||
3551 | tree index, val; | |||
3552 | FOR_EACH_CONSTRUCTOR_ELT (CONSTRUCTOR_ELTS (constructor), ix, index, val)for (ix = 0; (ix >= vec_safe_length (((tree_check ((constructor ), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 3552, __FUNCTION__, (CONSTRUCTOR)))->constructor.elts))) ? false : (((void) (val = (*((tree_check ((constructor), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 3552, __FUNCTION__, (CONSTRUCTOR)))->constructor.elts))[ ix].value)), (index = (*((tree_check ((constructor), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 3552, __FUNCTION__, (CONSTRUCTOR)))->constructor.elts))[ ix].index), true); (ix)++) | |||
3553 | { | |||
3554 | HOST_WIDE_INTlong elt_offset; | |||
3555 | if (TREE_CODE (type)((enum tree_code) (type)->base.code) == ARRAY_TYPE) | |||
3556 | { | |||
3557 | offset_int off; | |||
3558 | tree unit_size = TYPE_SIZE_UNIT (TREE_TYPE (type))((tree_class_check ((((contains_struct_check ((type), (TS_TYPED ), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 3558, __FUNCTION__))->typed.type)), (tcc_type), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 3558, __FUNCTION__))->type_common.size_unit); | |||
3559 | gcc_assert (TREE_CODE (unit_size) == INTEGER_CST)((void)(!(((enum tree_code) (unit_size)->base.code) == INTEGER_CST ) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 3559, __FUNCTION__), 0 : 0)); | |||
3560 | ||||
3561 | if (index) | |||
3562 | { | |||
3563 | if (TREE_CODE (index)((enum tree_code) (index)->base.code) == RANGE_EXPR) | |||
3564 | off = wi::to_offset (TREE_OPERAND (index, 0)(*((const_cast<tree*> (tree_operand_check ((index), (0) , "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 3564, __FUNCTION__)))))); | |||
3565 | else | |||
3566 | off = wi::to_offset (index); | |||
3567 | if (TYPE_DOMAIN (type)((tree_check ((type), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 3567, __FUNCTION__, (ARRAY_TYPE)))->type_non_common.values ) && TYPE_MIN_VALUE (TYPE_DOMAIN (type))((tree_check5 ((((tree_check ((type), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 3567, __FUNCTION__, (ARRAY_TYPE)))->type_non_common.values )), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 3567, __FUNCTION__, (INTEGER_TYPE), (ENUMERAL_TYPE), (BOOLEAN_TYPE ), (REAL_TYPE), (FIXED_POINT_TYPE)))->type_non_common.minval )) | |||
3568 | { | |||
3569 | tree low_bound = TYPE_MIN_VALUE (TYPE_DOMAIN (type))((tree_check5 ((((tree_check ((type), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 3569, __FUNCTION__, (ARRAY_TYPE)))->type_non_common.values )), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 3569, __FUNCTION__, (INTEGER_TYPE), (ENUMERAL_TYPE), (BOOLEAN_TYPE ), (REAL_TYPE), (FIXED_POINT_TYPE)))->type_non_common.minval ); | |||
3570 | gcc_assert (TREE_CODE (unit_size) == INTEGER_CST)((void)(!(((enum tree_code) (unit_size)->base.code) == INTEGER_CST ) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 3570, __FUNCTION__), 0 : 0)); | |||
3571 | off = wi::sext (off - wi::to_offset (low_bound), | |||
3572 | TYPE_PRECISION (TREE_TYPE (index))((tree_class_check ((((contains_struct_check ((index), (TS_TYPED ), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 3572, __FUNCTION__))->typed.type)), (tcc_type), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 3572, __FUNCTION__))->type_common.precision)); | |||
3573 | } | |||
3574 | off *= wi::to_offset (unit_size); | |||
3575 | /* ??? Handle more than just the first index of a | |||
3576 | RANGE_EXPR. */ | |||
3577 | } | |||
3578 | else | |||
3579 | off = wi::to_offset (unit_size) * ix; | |||
3580 | ||||
3581 | off = wi::lshift (off, LOG2_BITS_PER_UNIT3); | |||
3582 | if (!wi::fits_shwi_p (off) || wi::neg_p (off)) | |||
3583 | continue; | |||
3584 | elt_offset = off.to_shwi (); | |||
3585 | } | |||
3586 | else if (TREE_CODE (type)((enum tree_code) (type)->base.code) == RECORD_TYPE) | |||
3587 | { | |||
3588 | gcc_checking_assert (index && TREE_CODE (index) == FIELD_DECL)((void)(!(index && ((enum tree_code) (index)->base .code) == FIELD_DECL) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 3588, __FUNCTION__), 0 : 0)); | |||
3589 | if (DECL_BIT_FIELD (index)((tree_check ((index), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 3589, __FUNCTION__, (FIELD_DECL)))->decl_common.decl_flag_1 )) | |||
3590 | continue; | |||
3591 | elt_offset = int_bit_position (index); | |||
3592 | } | |||
3593 | else | |||
3594 | gcc_unreachable ()(fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 3594, __FUNCTION__)); | |||
3595 | ||||
3596 | if (elt_offset > req_offset) | |||
3597 | return NULLnullptr; | |||
3598 | ||||
3599 | if (TREE_CODE (val)((enum tree_code) (val)->base.code) == CONSTRUCTOR) | |||
3600 | return find_constructor_constant_at_offset (val, | |||
3601 | req_offset - elt_offset); | |||
3602 | ||||
3603 | if (elt_offset == req_offset | |||
3604 | && is_gimple_reg_type (TREE_TYPE (val)((contains_struct_check ((val), (TS_TYPED), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 3604, __FUNCTION__))->typed.type)) | |||
3605 | && is_gimple_ip_invariant (val)) | |||
3606 | return val; | |||
3607 | } | |||
3608 | return NULLnullptr; | |||
3609 | } | |||
3610 | ||||
3611 | /* Check whether SCALAR could be used to look up an aggregate interprocedural | |||
3612 | invariant from a static constructor and if so, return it. Otherwise return | |||
3613 | NULL. */ | |||
3614 | ||||
3615 | tree | |||
3616 | ipa_find_agg_cst_from_init (tree scalar, HOST_WIDE_INTlong offset, bool by_ref) | |||
3617 | { | |||
3618 | if (by_ref) | |||
3619 | { | |||
3620 | if (TREE_CODE (scalar)((enum tree_code) (scalar)->base.code) != ADDR_EXPR) | |||
3621 | return NULLnullptr; | |||
3622 | scalar = TREE_OPERAND (scalar, 0)(*((const_cast<tree*> (tree_operand_check ((scalar), (0 ), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 3622, __FUNCTION__))))); | |||
3623 | } | |||
3624 | ||||
3625 | if (!VAR_P (scalar)(((enum tree_code) (scalar)->base.code) == VAR_DECL) | |||
3626 | || !is_global_var (scalar) | |||
3627 | || !TREE_READONLY (scalar)((non_type_check ((scalar), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 3627, __FUNCTION__))->base.readonly_flag) | |||
3628 | || !DECL_INITIAL (scalar)((contains_struct_check ((scalar), (TS_DECL_COMMON), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 3628, __FUNCTION__))->decl_common.initial) | |||
3629 | || TREE_CODE (DECL_INITIAL (scalar))((enum tree_code) (((contains_struct_check ((scalar), (TS_DECL_COMMON ), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 3629, __FUNCTION__))->decl_common.initial))->base.code ) != CONSTRUCTOR) | |||
3630 | return NULLnullptr; | |||
3631 | ||||
3632 | return find_constructor_constant_at_offset (DECL_INITIAL (scalar)((contains_struct_check ((scalar), (TS_DECL_COMMON), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 3632, __FUNCTION__))->decl_common.initial), offset); | |||
3633 | } | |||
3634 | ||||
3635 | /* Retrieve value from AGG_JFUNC for the given OFFSET or return NULL if there | |||
3636 | is none. BY_REF specifies whether the value has to be passed by reference | |||
3637 | or by value. */ | |||
3638 | ||||
3639 | static tree | |||
3640 | ipa_find_agg_cst_from_jfunc_items (struct ipa_agg_jump_function *agg_jfunc, | |||
3641 | ipa_node_params *src_info, | |||
3642 | cgraph_node *src_node, | |||
3643 | HOST_WIDE_INTlong offset, bool by_ref) | |||
3644 | { | |||
3645 | if (by_ref != agg_jfunc->by_ref) | |||
3646 | return NULL_TREE(tree) nullptr; | |||
3647 | ||||
3648 | for (const ipa_agg_jf_item &item : agg_jfunc->items) | |||
3649 | if (item.offset == offset) | |||
3650 | return ipa_agg_value_from_jfunc (src_info, src_node, &item); | |||
3651 | ||||
3652 | return NULL_TREE(tree) nullptr; | |||
3653 | } | |||
3654 | ||||
3655 | /* Remove a reference to SYMBOL from the list of references of a node given by | |||
3656 | reference description RDESC. Return true if the reference has been | |||
3657 | successfully found and removed. */ | |||
3658 | ||||
3659 | static bool | |||
3660 | remove_described_reference (symtab_node *symbol, struct ipa_cst_ref_desc *rdesc) | |||
3661 | { | |||
3662 | struct ipa_ref *to_del; | |||
3663 | struct cgraph_edge *origin; | |||
3664 | ||||
3665 | origin = rdesc->cs; | |||
3666 | if (!origin) | |||
3667 | return false; | |||
3668 | to_del = origin->caller->find_reference (symbol, origin->call_stmt, | |||
3669 | origin->lto_stmt_uid); | |||
3670 | if (!to_del) | |||
3671 | return false; | |||
3672 | ||||
3673 | to_del->remove_reference (); | |||
3674 | if (dump_file) | |||
3675 | fprintf (dump_file, "ipa-prop: Removed a reference from %s to %s.\n", | |||
3676 | origin->caller->dump_name (), symbol->dump_name ()); | |||
3677 | return true; | |||
3678 | } | |||
3679 | ||||
3680 | /* If JFUNC has a reference description with refcount different from | |||
3681 | IPA_UNDESCRIBED_USE, return the reference description, otherwise return | |||
3682 | NULL. JFUNC must be a constant jump function. */ | |||
3683 | ||||
3684 | static struct ipa_cst_ref_desc * | |||
3685 | jfunc_rdesc_usable (struct ipa_jump_func *jfunc) | |||
3686 | { | |||
3687 | struct ipa_cst_ref_desc *rdesc = ipa_get_jf_constant_rdesc (jfunc); | |||
3688 | if (rdesc && rdesc->refcount != IPA_UNDESCRIBED_USE-1) | |||
3689 | return rdesc; | |||
3690 | else | |||
3691 | return NULLnullptr; | |||
3692 | } | |||
3693 | ||||
3694 | /* If the value of constant jump function JFUNC is an address of a function | |||
3695 | declaration, return the associated call graph node. Otherwise return | |||
3696 | NULL. */ | |||
3697 | ||||
3698 | static symtab_node * | |||
3699 | symtab_node_for_jfunc (struct ipa_jump_func *jfunc) | |||
3700 | { | |||
3701 | gcc_checking_assert (jfunc->type == IPA_JF_CONST)((void)(!(jfunc->type == IPA_JF_CONST) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 3701, __FUNCTION__), 0 : 0)); | |||
3702 | tree cst = ipa_get_jf_constant (jfunc); | |||
3703 | if (TREE_CODE (cst)((enum tree_code) (cst)->base.code) != ADDR_EXPR | |||
3704 | || (TREE_CODE (TREE_OPERAND (cst, 0))((enum tree_code) ((*((const_cast<tree*> (tree_operand_check ((cst), (0), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 3704, __FUNCTION__))))))->base.code) != FUNCTION_DECL | |||
3705 | && TREE_CODE (TREE_OPERAND (cst, 0))((enum tree_code) ((*((const_cast<tree*> (tree_operand_check ((cst), (0), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 3705, __FUNCTION__))))))->base.code) != VAR_DECL)) | |||
3706 | return NULLnullptr; | |||
3707 | ||||
3708 | return symtab_node::get (TREE_OPERAND (cst, 0)(*((const_cast<tree*> (tree_operand_check ((cst), (0), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 3708, __FUNCTION__)))))); | |||
3709 | } | |||
3710 | ||||
3711 | ||||
3712 | /* If JFUNC is a constant jump function with a usable rdesc, decrement its | |||
3713 | refcount and if it hits zero, remove reference to SYMBOL from the caller of | |||
3714 | the edge specified in the rdesc. Return false if either the symbol or the | |||
3715 | reference could not be found, otherwise return true. */ | |||
3716 | ||||
3717 | static bool | |||
3718 | try_decrement_rdesc_refcount (struct ipa_jump_func *jfunc) | |||
3719 | { | |||
3720 | struct ipa_cst_ref_desc *rdesc; | |||
3721 | if (jfunc->type == IPA_JF_CONST | |||
3722 | && (rdesc = jfunc_rdesc_usable (jfunc)) | |||
3723 | && --rdesc->refcount == 0) | |||
3724 | { | |||
3725 | symtab_node *symbol = symtab_node_for_jfunc (jfunc); | |||
3726 | if (!symbol) | |||
3727 | return false; | |||
3728 | ||||
3729 | return remove_described_reference (symbol, rdesc); | |||
3730 | } | |||
3731 | return true; | |||
3732 | } | |||
3733 | ||||
3734 | /* Try to find a destination for indirect edge IE that corresponds to a simple | |||
3735 | call or a call of a member function pointer and where the destination is a | |||
3736 | pointer formal parameter described by jump function JFUNC. TARGET_TYPE is | |||
3737 | the type of the parameter to which the result of JFUNC is passed. If it can | |||
3738 | be determined, return the newly direct edge, otherwise return NULL. | |||
3739 | NEW_ROOT and NEW_ROOT_INFO is the node and its info that JFUNC lattices are | |||
3740 | relative to. */ | |||
3741 | ||||
3742 | static struct cgraph_edge * | |||
3743 | try_make_edge_direct_simple_call (struct cgraph_edge *ie, | |||
3744 | struct ipa_jump_func *jfunc, tree target_type, | |||
3745 | struct cgraph_node *new_root, | |||
3746 | class ipa_node_params *new_root_info) | |||
3747 | { | |||
3748 | struct cgraph_edge *cs; | |||
3749 | tree target = NULL_TREE(tree) nullptr; | |||
3750 | bool agg_contents = ie->indirect_info->agg_contents; | |||
3751 | tree scalar = ipa_value_from_jfunc (new_root_info, jfunc, target_type); | |||
3752 | if (agg_contents) | |||
3753 | { | |||
3754 | if (scalar) | |||
3755 | target = ipa_find_agg_cst_from_init (scalar, ie->indirect_info->offset, | |||
3756 | ie->indirect_info->by_ref); | |||
3757 | if (!target && ie->indirect_info->guaranteed_unmodified) | |||
3758 | target = ipa_find_agg_cst_from_jfunc_items (&jfunc->agg, new_root_info, | |||
3759 | new_root, | |||
3760 | ie->indirect_info->offset, | |||
3761 | ie->indirect_info->by_ref); | |||
3762 | } | |||
3763 | else | |||
3764 | target = scalar; | |||
3765 | if (!target) | |||
3766 | return NULLnullptr; | |||
3767 | cs = ipa_make_edge_direct_to_target (ie, target); | |||
3768 | ||||
3769 | if (cs && !agg_contents) | |||
3770 | { | |||
3771 | bool ok; | |||
3772 | gcc_checking_assert (cs->callee((void)(!(cs->callee && (cs != ie || jfunc->type != IPA_JF_CONST || !symtab_node_for_jfunc (jfunc) || cs-> callee == symtab_node_for_jfunc (jfunc))) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 3776, __FUNCTION__), 0 : 0)) | |||
3773 | && (cs != ie((void)(!(cs->callee && (cs != ie || jfunc->type != IPA_JF_CONST || !symtab_node_for_jfunc (jfunc) || cs-> callee == symtab_node_for_jfunc (jfunc))) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 3776, __FUNCTION__), 0 : 0)) | |||
3774 | || jfunc->type != IPA_JF_CONST((void)(!(cs->callee && (cs != ie || jfunc->type != IPA_JF_CONST || !symtab_node_for_jfunc (jfunc) || cs-> callee == symtab_node_for_jfunc (jfunc))) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 3776, __FUNCTION__), 0 : 0)) | |||
3775 | || !symtab_node_for_jfunc (jfunc)((void)(!(cs->callee && (cs != ie || jfunc->type != IPA_JF_CONST || !symtab_node_for_jfunc (jfunc) || cs-> callee == symtab_node_for_jfunc (jfunc))) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 3776, __FUNCTION__), 0 : 0)) | |||
3776 | || cs->callee == symtab_node_for_jfunc (jfunc)))((void)(!(cs->callee && (cs != ie || jfunc->type != IPA_JF_CONST || !symtab_node_for_jfunc (jfunc) || cs-> callee == symtab_node_for_jfunc (jfunc))) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 3776, __FUNCTION__), 0 : 0)); | |||
3777 | ok = try_decrement_rdesc_refcount (jfunc); | |||
3778 | gcc_checking_assert (ok)((void)(!(ok) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 3778, __FUNCTION__), 0 : 0)); | |||
3779 | } | |||
3780 | ||||
3781 | return cs; | |||
3782 | } | |||
3783 | ||||
3784 | /* Return the target to be used in cases of impossible devirtualization. IE | |||
3785 | and target (the latter can be NULL) are dumped when dumping is enabled. */ | |||
3786 | ||||
3787 | tree | |||
3788 | ipa_impossible_devirt_target (struct cgraph_edge *ie, tree target) | |||
3789 | { | |||
3790 | if (dump_file) | |||
3791 | { | |||
3792 | if (target) | |||
3793 | fprintf (dump_file, | |||
3794 | "Type inconsistent devirtualization: %s->%s\n", | |||
3795 | ie->caller->dump_name (), | |||
3796 | IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (target))((const char *) (tree_check ((decl_assembler_name (target)), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 3796, __FUNCTION__, (IDENTIFIER_NODE)))->identifier.id.str )); | |||
3797 | else | |||
3798 | fprintf (dump_file, | |||
3799 | "No devirtualization target in %s\n", | |||
3800 | ie->caller->dump_name ()); | |||
3801 | } | |||
3802 | tree new_target = builtin_decl_unreachable (); | |||
3803 | cgraph_node::get_create (new_target); | |||
3804 | return new_target; | |||
3805 | } | |||
3806 | ||||
3807 | /* Try to find a destination for indirect edge IE that corresponds to a virtual | |||
3808 | call based on a formal parameter which is described by jump function JFUNC | |||
3809 | and if it can be determined, make it direct and return the direct edge. | |||
3810 | Otherwise, return NULL. CTX describes the polymorphic context that the | |||
3811 | parameter the call is based on brings along with it. NEW_ROOT and | |||
3812 | NEW_ROOT_INFO is the node and its info that JFUNC lattices are relative | |||
3813 | to. */ | |||
3814 | ||||
3815 | static struct cgraph_edge * | |||
3816 | try_make_edge_direct_virtual_call (struct cgraph_edge *ie, | |||
3817 | struct ipa_jump_func *jfunc, | |||
3818 | class ipa_polymorphic_call_context ctx, | |||
3819 | struct cgraph_node *new_root, | |||
3820 | class ipa_node_params *new_root_info) | |||
3821 | { | |||
3822 | tree target = NULLnullptr; | |||
3823 | bool speculative = false; | |||
3824 | ||||
3825 | if (!opt_for_fn (ie->caller->decl, flag_devirtualize)(opts_for_fn (ie->caller->decl)->x_flag_devirtualize )) | |||
3826 | return NULLnullptr; | |||
3827 | ||||
3828 | gcc_assert (!ie->indirect_info->by_ref)((void)(!(!ie->indirect_info->by_ref) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 3828, __FUNCTION__), 0 : 0)); | |||
3829 | ||||
3830 | /* Try to do lookup via known virtual table pointer value. */ | |||
3831 | if (!ie->indirect_info->vptr_changed | |||
3832 | || opt_for_fn (ie->caller->decl, flag_devirtualize_speculatively)(opts_for_fn (ie->caller->decl)->x_flag_devirtualize_speculatively )) | |||
3833 | { | |||
3834 | tree vtable; | |||
3835 | unsigned HOST_WIDE_INTlong offset; | |||
3836 | tree t = NULL_TREE(tree) nullptr; | |||
3837 | if (jfunc->type == IPA_JF_CONST) | |||
3838 | t = ipa_find_agg_cst_from_init (ipa_get_jf_constant (jfunc), | |||
3839 | ie->indirect_info->offset, true); | |||
3840 | if (!t) | |||
3841 | t = ipa_find_agg_cst_from_jfunc_items (&jfunc->agg, new_root_info, | |||
3842 | new_root, | |||
3843 | ie->indirect_info->offset, true); | |||
3844 | if (t && vtable_pointer_value_to_vtable (t, &vtable, &offset)) | |||
3845 | { | |||
3846 | bool can_refer; | |||
3847 | t = gimple_get_virt_method_for_vtable (ie->indirect_info->otr_token, | |||
3848 | vtable, offset, &can_refer); | |||
3849 | if (can_refer) | |||
3850 | { | |||
3851 | if (!t | |||
3852 | || fndecl_built_in_p (t, BUILT_IN_UNREACHABLE) | |||
3853 | || fndecl_built_in_p (t, BUILT_IN_UNREACHABLE_TRAP) | |||
3854 | || !possible_polymorphic_call_target_p | |||
3855 | (ie, cgraph_node::get (t))) | |||
3856 | { | |||
3857 | /* Do not speculate builtin_unreachable, it is stupid! */ | |||
3858 | if (!ie->indirect_info->vptr_changed) | |||
3859 | target = ipa_impossible_devirt_target (ie, target); | |||
3860 | else | |||
3861 | target = NULLnullptr; | |||
3862 | } | |||
3863 | else | |||
3864 | { | |||
3865 | target = t; | |||
3866 | speculative = ie->indirect_info->vptr_changed; | |||
3867 | } | |||
3868 | } | |||
3869 | } | |||
3870 | } | |||
3871 | ||||
3872 | ipa_polymorphic_call_context ie_context (ie); | |||
3873 | vec <cgraph_node *>targets; | |||
3874 | bool final; | |||
3875 | ||||
3876 | ctx.offset_by (ie->indirect_info->offset); | |||
3877 | if (ie->indirect_info->vptr_changed) | |||
3878 | ctx.possible_dynamic_type_change (ie->in_polymorphic_cdtor, | |||
3879 | ie->indirect_info->otr_type); | |||
3880 | ctx.combine_with (ie_context, ie->indirect_info->otr_type); | |||
3881 | targets = possible_polymorphic_call_targets | |||
3882 | (ie->indirect_info->otr_type, | |||
3883 | ie->indirect_info->otr_token, | |||
3884 | ctx, &final); | |||
3885 | if (final && targets.length () <= 1) | |||
3886 | { | |||
3887 | speculative = false; | |||
3888 | if (targets.length () == 1) | |||
3889 | target = targets[0]->decl; | |||
3890 | else | |||
3891 | target = ipa_impossible_devirt_target (ie, NULL_TREE(tree) nullptr); | |||
3892 | } | |||
3893 | else if (!target && opt_for_fn (ie->caller->decl, flag_devirtualize_speculatively)(opts_for_fn (ie->caller->decl)->x_flag_devirtualize_speculatively ) | |||
3894 | && !ie->speculative && ie->maybe_hot_p ()) | |||
3895 | { | |||
3896 | cgraph_node *n; | |||
3897 | n = try_speculative_devirtualization (ie->indirect_info->otr_type, | |||
3898 | ie->indirect_info->otr_token, | |||
3899 | ie->indirect_info->context); | |||
3900 | if (n) | |||
3901 | { | |||
3902 | target = n->decl; | |||
3903 | speculative = true; | |||
3904 | } | |||
3905 | } | |||
3906 | ||||
3907 | if (target) | |||
3908 | { | |||
3909 | if (!possible_polymorphic_call_target_p | |||
3910 | (ie, cgraph_node::get_create (target))) | |||
3911 | { | |||
3912 | if (speculative) | |||
3913 | return NULLnullptr; | |||
3914 | target = ipa_impossible_devirt_target (ie, target); | |||
3915 | } | |||
3916 | return ipa_make_edge_direct_to_target (ie, target, speculative); | |||
3917 | } | |||
3918 | else | |||
3919 | return NULLnullptr; | |||
3920 | } | |||
3921 | ||||
3922 | /* Update the param called notes associated with NODE when CS is being inlined, | |||
3923 | assuming NODE is (potentially indirectly) inlined into CS->callee. | |||
3924 | Moreover, if the callee is discovered to be constant, create a new cgraph | |||
3925 | edge for it. Newly discovered indirect edges will be added to *NEW_EDGES, | |||
3926 | unless NEW_EDGES is NULL. Return true iff a new edge(s) were created. */ | |||
3927 | ||||
3928 | static bool | |||
3929 | update_indirect_edges_after_inlining (struct cgraph_edge *cs, | |||
3930 | struct cgraph_node *node, | |||
3931 | vec<cgraph_edge *> *new_edges) | |||
3932 | { | |||
3933 | class ipa_edge_args *top; | |||
3934 | struct cgraph_edge *ie, *next_ie, *new_direct_edge; | |||
3935 | struct cgraph_node *new_root; | |||
3936 | class ipa_node_params *new_root_info, *inlined_node_info; | |||
3937 | bool res = false; | |||
3938 | ||||
3939 | ipa_check_create_edge_args (); | |||
3940 | top = ipa_edge_args_sum->get (cs); | |||
3941 | new_root = cs->caller->inlined_to | |||
3942 | ? cs->caller->inlined_to : cs->caller; | |||
3943 | new_root_info = ipa_node_params_sum->get (new_root); | |||
3944 | inlined_node_info = ipa_node_params_sum->get (cs->callee->function_symbol ()); | |||
3945 | ||||
3946 | for (ie = node->indirect_calls; ie; ie = next_ie) | |||
3947 | { | |||
3948 | class cgraph_indirect_call_info *ici = ie->indirect_info; | |||
3949 | struct ipa_jump_func *jfunc; | |||
3950 | int param_index; | |||
3951 | ||||
3952 | next_ie = ie->next_callee; | |||
3953 | ||||
3954 | if (ici->param_index == -1) | |||
3955 | continue; | |||
3956 | ||||
3957 | /* We must check range due to calls with variable number of arguments: */ | |||
3958 | if (!top || ici->param_index >= ipa_get_cs_argument_count (top)) | |||
3959 | { | |||
3960 | ici->param_index = -1; | |||
3961 | continue; | |||
3962 | } | |||
3963 | ||||
3964 | param_index = ici->param_index; | |||
3965 | jfunc = ipa_get_ith_jump_func (top, param_index); | |||
3966 | ||||
3967 | auto_vec<cgraph_node *, 4> spec_targets; | |||
3968 | if (ie->speculative) | |||
3969 | for (cgraph_edge *direct = ie->first_speculative_call_target (); | |||
3970 | direct; | |||
3971 | direct = direct->next_speculative_call_target ()) | |||
3972 | spec_targets.safe_push (direct->callee); | |||
3973 | ||||
3974 | if (!opt_for_fn (node->decl, flag_indirect_inlining)(opts_for_fn (node->decl)->x_flag_indirect_inlining)) | |||
3975 | new_direct_edge = NULLnullptr; | |||
3976 | else if (ici->polymorphic) | |||
3977 | { | |||
3978 | ipa_polymorphic_call_context ctx; | |||
3979 | ctx = ipa_context_from_jfunc (new_root_info, cs, param_index, jfunc); | |||
3980 | new_direct_edge = try_make_edge_direct_virtual_call (ie, jfunc, ctx, | |||
3981 | new_root, | |||
3982 | new_root_info); | |||
3983 | } | |||
3984 | else | |||
3985 | { | |||
3986 | tree target_type = ipa_get_type (inlined_node_info, param_index); | |||
3987 | new_direct_edge = try_make_edge_direct_simple_call (ie, jfunc, | |||
3988 | target_type, | |||
3989 | new_root, | |||
3990 | new_root_info); | |||
3991 | } | |||
3992 | ||||
3993 | /* If speculation was removed, then we need to do nothing. */ | |||
3994 | if (new_direct_edge && new_direct_edge != ie | |||
3995 | && spec_targets.contains (new_direct_edge->callee)) | |||
3996 | { | |||
3997 | new_direct_edge->indirect_inlining_edge = 1; | |||
3998 | res = true; | |||
3999 | if (!new_direct_edge->speculative) | |||
4000 | continue; | |||
4001 | } | |||
4002 | else if (new_direct_edge) | |||
4003 | { | |||
4004 | new_direct_edge->indirect_inlining_edge = 1; | |||
4005 | if (new_edges) | |||
4006 | { | |||
4007 | new_edges->safe_push (new_direct_edge); | |||
4008 | res = true; | |||
4009 | } | |||
4010 | /* If speculative edge was introduced we still need to update | |||
4011 | call info of the indirect edge. */ | |||
4012 | if (!new_direct_edge->speculative) | |||
4013 | continue; | |||
4014 | } | |||
4015 | if (jfunc->type == IPA_JF_PASS_THROUGH | |||
4016 | && ipa_get_jf_pass_through_operation (jfunc) == NOP_EXPR) | |||
4017 | { | |||
4018 | if (ici->agg_contents | |||
4019 | && !ipa_get_jf_pass_through_agg_preserved (jfunc) | |||
4020 | && !ici->polymorphic) | |||
4021 | ici->param_index = -1; | |||
4022 | else | |||
4023 | { | |||
4024 | ici->param_index = ipa_get_jf_pass_through_formal_id (jfunc); | |||
4025 | if (ici->polymorphic | |||
4026 | && !ipa_get_jf_pass_through_type_preserved (jfunc)) | |||
4027 | ici->vptr_changed = true; | |||
4028 | ipa_set_param_used_by_indirect_call (new_root_info, | |||
4029 | ici->param_index, true); | |||
4030 | if (ici->polymorphic) | |||
4031 | ipa_set_param_used_by_polymorphic_call (new_root_info, | |||
4032 | ici->param_index, true); | |||
4033 | } | |||
4034 | } | |||
4035 | else if (jfunc->type == IPA_JF_ANCESTOR) | |||
4036 | { | |||
4037 | if (ici->agg_contents | |||
4038 | && !ipa_get_jf_ancestor_agg_preserved (jfunc) | |||
4039 | && !ici->polymorphic) | |||
4040 | ici->param_index = -1; | |||
4041 | else | |||
4042 | { | |||
4043 | ici->param_index = ipa_get_jf_ancestor_formal_id (jfunc); | |||
4044 | ici->offset += ipa_get_jf_ancestor_offset (jfunc); | |||
4045 | if (ici->polymorphic | |||
4046 | && !ipa_get_jf_ancestor_type_preserved (jfunc)) | |||
4047 | ici->vptr_changed = true; | |||
4048 | ipa_set_param_used_by_indirect_call (new_root_info, | |||
4049 | ici->param_index, true); | |||
4050 | if (ici->polymorphic) | |||
4051 | ipa_set_param_used_by_polymorphic_call (new_root_info, | |||
4052 | ici->param_index, true); | |||
4053 | } | |||
4054 | } | |||
4055 | else | |||
4056 | /* Either we can find a destination for this edge now or never. */ | |||
4057 | ici->param_index = -1; | |||
4058 | } | |||
4059 | ||||
4060 | return res; | |||
4061 | } | |||
4062 | ||||
4063 | /* Recursively traverse subtree of NODE (including node) made of inlined | |||
4064 | cgraph_edges when CS has been inlined and invoke | |||
4065 | update_indirect_edges_after_inlining on all nodes and | |||
4066 | update_jump_functions_after_inlining on all non-inlined edges that lead out | |||
4067 | of this subtree. Newly discovered indirect edges will be added to | |||
4068 | *NEW_EDGES, unless NEW_EDGES is NULL. Return true iff a new edge(s) were | |||
4069 | created. */ | |||
4070 | ||||
4071 | static bool | |||
4072 | propagate_info_to_inlined_callees (struct cgraph_edge *cs, | |||
4073 | struct cgraph_node *node, | |||
4074 | vec<cgraph_edge *> *new_edges) | |||
4075 | { | |||
4076 | struct cgraph_edge *e; | |||
4077 | bool res; | |||
4078 | ||||
4079 | res = update_indirect_edges_after_inlining (cs, node, new_edges); | |||
4080 | ||||
4081 | for (e = node->callees; e; e = e->next_callee) | |||
4082 | if (!e->inline_failed) | |||
4083 | res |= propagate_info_to_inlined_callees (cs, e->callee, new_edges); | |||
4084 | else | |||
4085 | update_jump_functions_after_inlining (cs, e); | |||
4086 | for (e = node->indirect_calls; e; e = e->next_callee) | |||
4087 | update_jump_functions_after_inlining (cs, e); | |||
4088 | ||||
4089 | return res; | |||
4090 | } | |||
4091 | ||||
4092 | /* Combine two controlled uses counts as done during inlining. */ | |||
4093 | ||||
4094 | static int | |||
4095 | combine_controlled_uses_counters (int c, int d) | |||
4096 | { | |||
4097 | if (c == IPA_UNDESCRIBED_USE-1 || d == IPA_UNDESCRIBED_USE-1) | |||
4098 | return IPA_UNDESCRIBED_USE-1; | |||
4099 | else | |||
4100 | return c + d - 1; | |||
4101 | } | |||
4102 | ||||
4103 | /* Propagate number of controlled users from CS->caleee to the new root of the | |||
4104 | tree of inlined nodes. */ | |||
4105 | ||||
4106 | static void | |||
4107 | propagate_controlled_uses (struct cgraph_edge *cs) | |||
4108 | { | |||
4109 | ipa_edge_args *args = ipa_edge_args_sum->get (cs); | |||
4110 | if (!args) | |||
4111 | return; | |||
4112 | struct cgraph_node *new_root = cs->caller->inlined_to | |||
4113 | ? cs->caller->inlined_to : cs->caller; | |||
4114 | ipa_node_params *new_root_info = ipa_node_params_sum->get (new_root); | |||
4115 | ipa_node_params *old_root_info = ipa_node_params_sum->get (cs->callee); | |||
4116 | int count, i; | |||
4117 | ||||
4118 | if (!old_root_info) | |||
4119 | return; | |||
4120 | ||||
4121 | count = MIN (ipa_get_cs_argument_count (args),((ipa_get_cs_argument_count (args)) < (ipa_get_param_count (old_root_info)) ? (ipa_get_cs_argument_count (args)) : (ipa_get_param_count (old_root_info))) | |||
4122 | ipa_get_param_count (old_root_info))((ipa_get_cs_argument_count (args)) < (ipa_get_param_count (old_root_info)) ? (ipa_get_cs_argument_count (args)) : (ipa_get_param_count (old_root_info))); | |||
4123 | for (i = 0; i < count; i++) | |||
4124 | { | |||
4125 | struct ipa_jump_func *jf = ipa_get_ith_jump_func (args, i); | |||
4126 | struct ipa_cst_ref_desc *rdesc; | |||
4127 | ||||
4128 | if (jf->type == IPA_JF_PASS_THROUGH) | |||
4129 | { | |||
4130 | int src_idx, c, d; | |||
4131 | src_idx = ipa_get_jf_pass_through_formal_id (jf); | |||
4132 | c = ipa_get_controlled_uses (new_root_info, src_idx); | |||
4133 | d = ipa_get_controlled_uses (old_root_info, i); | |||
4134 | ||||
4135 | gcc_checking_assert (ipa_get_jf_pass_through_operation (jf)((void)(!(ipa_get_jf_pass_through_operation (jf) == NOP_EXPR || c == -1) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 4136, __FUNCTION__), 0 : 0)) | |||
4136 | == NOP_EXPR || c == IPA_UNDESCRIBED_USE)((void)(!(ipa_get_jf_pass_through_operation (jf) == NOP_EXPR || c == -1) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 4136, __FUNCTION__), 0 : 0)); | |||
4137 | c = combine_controlled_uses_counters (c, d); | |||
4138 | ipa_set_controlled_uses (new_root_info, src_idx, c); | |||
4139 | bool lderef = true; | |||
4140 | if (c != IPA_UNDESCRIBED_USE-1) | |||
4141 | { | |||
4142 | lderef = (ipa_get_param_load_dereferenced (new_root_info, src_idx) | |||
4143 | || ipa_get_param_load_dereferenced (old_root_info, i)); | |||
4144 | ipa_set_param_load_dereferenced (new_root_info, src_idx, lderef); | |||
4145 | } | |||
4146 | ||||
4147 | if (c == 0 && !lderef && new_root_info->ipcp_orig_node) | |||
4148 | { | |||
4149 | struct cgraph_node *n; | |||
4150 | struct ipa_ref *ref; | |||
4151 | tree t = new_root_info->known_csts[src_idx]; | |||
4152 | ||||
4153 | if (t && TREE_CODE (t)((enum tree_code) (t)->base.code) == ADDR_EXPR | |||
4154 | && 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-prop.cc" , 4154, __FUNCTION__))))))->base.code) == FUNCTION_DECL | |||
4155 | && (n = cgraph_node::get (TREE_OPERAND (t, 0)(*((const_cast<tree*> (tree_operand_check ((t), (0), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 4155, __FUNCTION__))))))) | |||
4156 | && (ref = new_root->find_reference (n, NULLnullptr, 0))) | |||
4157 | { | |||
4158 | if (dump_file) | |||
4159 | fprintf (dump_file, "ipa-prop: Removing cloning-created " | |||
4160 | "reference from %s to %s.\n", | |||
4161 | new_root->dump_name (), | |||
4162 | n->dump_name ()); | |||
4163 | ref->remove_reference (); | |||
4164 | } | |||
4165 | } | |||
4166 | } | |||
4167 | else if (jf->type == IPA_JF_CONST | |||
4168 | && (rdesc = jfunc_rdesc_usable (jf))) | |||
4169 | { | |||
4170 | int d = ipa_get_controlled_uses (old_root_info, i); | |||
4171 | int c = rdesc->refcount; | |||
4172 | tree cst = ipa_get_jf_constant (jf); | |||
4173 | rdesc->refcount = combine_controlled_uses_counters (c, d); | |||
4174 | if (rdesc->refcount != IPA_UNDESCRIBED_USE-1 | |||
4175 | && ipa_get_param_load_dereferenced (old_root_info, i) | |||
4176 | && TREE_CODE (cst)((enum tree_code) (cst)->base.code) == ADDR_EXPR | |||
4177 | && TREE_CODE (TREE_OPERAND (cst, 0))((enum tree_code) ((*((const_cast<tree*> (tree_operand_check ((cst), (0), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 4177, __FUNCTION__))))))->base.code) == VAR_DECL) | |||
4178 | { | |||
4179 | symtab_node *n = symtab_node::get (TREE_OPERAND (cst, 0)(*((const_cast<tree*> (tree_operand_check ((cst), (0), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 4179, __FUNCTION__)))))); | |||
4180 | new_root->create_reference (n, IPA_REF_LOAD, NULLnullptr); | |||
4181 | if (dump_file) | |||
4182 | fprintf (dump_file, "ipa-prop: Address IPA constant will reach " | |||
4183 | "a load so adding LOAD reference from %s to %s.\n", | |||
4184 | new_root->dump_name (), n->dump_name ()); | |||
4185 | } | |||
4186 | if (rdesc->refcount == 0) | |||
4187 | { | |||
4188 | gcc_checking_assert (TREE_CODE (cst) == ADDR_EXPR((void)(!(((enum tree_code) (cst)->base.code) == ADDR_EXPR && ((((enum tree_code) ((*((const_cast<tree*> ( tree_operand_check ((cst), (0), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 4189, __FUNCTION__))))))->base.code) == FUNCTION_DECL) || (((enum tree_code) ((*((const_cast<tree*> (tree_operand_check ((cst), (0), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 4191, __FUNCTION__))))))->base.code) == VAR_DECL))) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 4192, __FUNCTION__), 0 : 0)) | |||
4189 | && ((TREE_CODE (TREE_OPERAND (cst, 0))((void)(!(((enum tree_code) (cst)->base.code) == ADDR_EXPR && ((((enum tree_code) ((*((const_cast<tree*> ( tree_operand_check ((cst), (0), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 4189, __FUNCTION__))))))->base.code) == FUNCTION_DECL) || (((enum tree_code) ((*((const_cast<tree*> (tree_operand_check ((cst), (0), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 4191, __FUNCTION__))))))->base.code) == VAR_DECL))) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 4192, __FUNCTION__), 0 : 0)) | |||
4190 | == FUNCTION_DECL)((void)(!(((enum tree_code) (cst)->base.code) == ADDR_EXPR && ((((enum tree_code) ((*((const_cast<tree*> ( tree_operand_check ((cst), (0), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 4189, __FUNCTION__))))))->base.code) == FUNCTION_DECL) || (((enum tree_code) ((*((const_cast<tree*> (tree_operand_check ((cst), (0), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 4191, __FUNCTION__))))))->base.code) == VAR_DECL))) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 4192, __FUNCTION__), 0 : 0)) | |||
4191 | || (TREE_CODE (TREE_OPERAND (cst, 0))((void)(!(((enum tree_code) (cst)->base.code) == ADDR_EXPR && ((((enum tree_code) ((*((const_cast<tree*> ( tree_operand_check ((cst), (0), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 4189, __FUNCTION__))))))->base.code) == FUNCTION_DECL) || (((enum tree_code) ((*((const_cast<tree*> (tree_operand_check ((cst), (0), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 4191, __FUNCTION__))))))->base.code) == VAR_DECL))) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 4192, __FUNCTION__), 0 : 0)) | |||
4192 | == VAR_DECL)))((void)(!(((enum tree_code) (cst)->base.code) == ADDR_EXPR && ((((enum tree_code) ((*((const_cast<tree*> ( tree_operand_check ((cst), (0), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 4189, __FUNCTION__))))))->base.code) == FUNCTION_DECL) || (((enum tree_code) ((*((const_cast<tree*> (tree_operand_check ((cst), (0), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 4191, __FUNCTION__))))))->base.code) == VAR_DECL))) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 4192, __FUNCTION__), 0 : 0)); | |||
4193 | ||||
4194 | symtab_node *n = symtab_node::get (TREE_OPERAND (cst, 0)(*((const_cast<tree*> (tree_operand_check ((cst), (0), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 4194, __FUNCTION__)))))); | |||
4195 | if (n) | |||
4196 | { | |||
4197 | remove_described_reference (n, rdesc); | |||
4198 | cgraph_node *clone = cs->caller; | |||
4199 | while (clone->inlined_to | |||
4200 | && clone->ipcp_clone | |||
4201 | && clone != rdesc->cs->caller) | |||
4202 | { | |||
4203 | struct ipa_ref *ref; | |||
4204 | ref = clone->find_reference (n, NULLnullptr, 0); | |||
4205 | if (ref) | |||
4206 | { | |||
4207 | if (dump_file) | |||
4208 | fprintf (dump_file, "ipa-prop: Removing " | |||
4209 | "cloning-created reference " | |||
4210 | "from %s to %s.\n", | |||
4211 | clone->dump_name (), | |||
4212 | n->dump_name ()); | |||
4213 | ref->remove_reference (); | |||
4214 | } | |||
4215 | clone = clone->callers->caller; | |||
4216 | } | |||
4217 | } | |||
4218 | } | |||
4219 | } | |||
4220 | } | |||
4221 | ||||
4222 | for (i = ipa_get_param_count (old_root_info); | |||
4223 | i < ipa_get_cs_argument_count (args); | |||
4224 | i++) | |||
4225 | { | |||
4226 | struct ipa_jump_func *jf = ipa_get_ith_jump_func (args, i); | |||
4227 | ||||
4228 | if (jf->type == IPA_JF_CONST) | |||
4229 | { | |||
4230 | struct ipa_cst_ref_desc *rdesc = jfunc_rdesc_usable (jf); | |||
4231 | if (rdesc) | |||
4232 | rdesc->refcount = IPA_UNDESCRIBED_USE-1; | |||
4233 | } | |||
4234 | else if (jf->type == IPA_JF_PASS_THROUGH) | |||
4235 | ipa_set_controlled_uses (new_root_info, | |||
4236 | jf->value.pass_through.formal_id, | |||
4237 | IPA_UNDESCRIBED_USE-1); | |||
4238 | } | |||
4239 | } | |||
4240 | ||||
4241 | /* Update jump functions and call note functions on inlining the call site CS. | |||
4242 | CS is expected to lead to a node already cloned by | |||
4243 | cgraph_clone_inline_nodes. Newly discovered indirect edges will be added to | |||
4244 | *NEW_EDGES, unless NEW_EDGES is NULL. Return true iff a new edge(s) were + | |||
4245 | created. */ | |||
4246 | ||||
4247 | bool | |||
4248 | ipa_propagate_indirect_call_infos (struct cgraph_edge *cs, | |||
4249 | vec<cgraph_edge *> *new_edges) | |||
4250 | { | |||
4251 | bool changed; | |||
4252 | /* Do nothing if the preparation phase has not been carried out yet | |||
4253 | (i.e. during early inlining). */ | |||
4254 | if (!ipa_node_params_sum) | |||
4255 | return false; | |||
4256 | gcc_assert (ipa_edge_args_sum)((void)(!(ipa_edge_args_sum) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 4256, __FUNCTION__), 0 : 0)); | |||
4257 | ||||
4258 | propagate_controlled_uses (cs); | |||
4259 | changed = propagate_info_to_inlined_callees (cs, cs->callee, new_edges); | |||
4260 | ipa_node_params_sum->remove (cs->callee); | |||
4261 | ||||
4262 | ipa_edge_args *args = ipa_edge_args_sum->get (cs); | |||
4263 | if (args) | |||
4264 | { | |||
4265 | bool ok = true; | |||
4266 | if (args->jump_functions) | |||
4267 | { | |||
4268 | struct ipa_jump_func *jf; | |||
4269 | int i; | |||
4270 | FOR_EACH_VEC_ELT (*args->jump_functions, i, jf)for (i = 0; (*args->jump_functions).iterate ((i), &(jf )); ++(i)) | |||
4271 | if (jf->type == IPA_JF_CONST | |||
4272 | && ipa_get_jf_constant_rdesc (jf)) | |||
4273 | { | |||
4274 | ok = false; | |||
4275 | break; | |||
4276 | } | |||
4277 | } | |||
4278 | if (ok) | |||
4279 | ipa_edge_args_sum->remove (cs); | |||
4280 | } | |||
4281 | if (ipcp_transformation_sum) | |||
4282 | ipcp_transformation_sum->remove (cs->callee); | |||
4283 | ||||
4284 | return changed; | |||
4285 | } | |||
4286 | ||||
4287 | /* Ensure that array of edge arguments infos is big enough to accommodate a | |||
4288 | structure for all edges and reallocates it if not. Also, allocate | |||
4289 | associated hash tables is they do not already exist. */ | |||
4290 | ||||
4291 | void | |||
4292 | ipa_check_create_edge_args (void) | |||
4293 | { | |||
4294 | if (!ipa_edge_args_sum) | |||
4295 | ipa_edge_args_sum | |||
4296 | = (new (ggc_alloc_no_dtor<ipa_edge_args_sum_t> ()) | |||
4297 | ipa_edge_args_sum_t (symtab, true)); | |||
4298 | if (!ipa_bits_hash_table) | |||
4299 | ipa_bits_hash_table = hash_table<ipa_bit_ggc_hash_traits>::create_ggc (37); | |||
4300 | if (!ipa_vr_hash_table) | |||
4301 | ipa_vr_hash_table = hash_table<ipa_vr_ggc_hash_traits>::create_ggc (37); | |||
4302 | } | |||
4303 | ||||
4304 | /* Free all ipa_edge structures. */ | |||
4305 | ||||
4306 | void | |||
4307 | ipa_free_all_edge_args (void) | |||
4308 | { | |||
4309 | if (!ipa_edge_args_sum) | |||
4310 | return; | |||
4311 | ||||
4312 | ggc_delete (ipa_edge_args_sum); | |||
4313 | ipa_edge_args_sum = NULLnullptr; | |||
4314 | } | |||
4315 | ||||
4316 | /* Free all ipa_node_params structures. */ | |||
4317 | ||||
4318 | void | |||
4319 | ipa_free_all_node_params (void) | |||
4320 | { | |||
4321 | if (ipa_node_params_sum) | |||
4322 | ggc_delete (ipa_node_params_sum); | |||
4323 | ipa_node_params_sum = NULLnullptr; | |||
4324 | } | |||
4325 | ||||
4326 | /* Initialize IPA CP transformation summary and also allocate any necessary hash | |||
4327 | tables if they do not already exist. */ | |||
4328 | ||||
4329 | void | |||
4330 | ipcp_transformation_initialize (void) | |||
4331 | { | |||
4332 | if (!ipa_bits_hash_table) | |||
4333 | ipa_bits_hash_table = hash_table<ipa_bit_ggc_hash_traits>::create_ggc (37); | |||
4334 | if (!ipa_vr_hash_table) | |||
4335 | ipa_vr_hash_table = hash_table<ipa_vr_ggc_hash_traits>::create_ggc (37); | |||
4336 | if (ipcp_transformation_sum == NULLnullptr) | |||
4337 | { | |||
4338 | ipcp_transformation_sum = ipcp_transformation_t::create_ggc (symtab); | |||
4339 | ipcp_transformation_sum->disable_insertion_hook (); | |||
4340 | } | |||
4341 | } | |||
4342 | ||||
4343 | /* Release the IPA CP transformation summary. */ | |||
4344 | ||||
4345 | void | |||
4346 | ipcp_free_transformation_sum (void) | |||
4347 | { | |||
4348 | if (!ipcp_transformation_sum) | |||
4349 | return; | |||
4350 | ||||
4351 | ipcp_transformation_sum->~function_summary<ipcp_transformation *> (); | |||
4352 | ggc_free (ipcp_transformation_sum); | |||
4353 | ipcp_transformation_sum = NULLnullptr; | |||
4354 | } | |||
4355 | ||||
4356 | /* Set the aggregate replacements of NODE to be AGGVALS. */ | |||
4357 | ||||
4358 | void | |||
4359 | ipa_set_node_agg_value_chain (struct cgraph_node *node, | |||
4360 | vec<ipa_argagg_value, va_gc> *aggs) | |||
4361 | { | |||
4362 | ipcp_transformation_initialize (); | |||
4363 | ipcp_transformation *s = ipcp_transformation_sum->get_create (node); | |||
4364 | s->m_agg_values = aggs; | |||
4365 | } | |||
4366 | ||||
4367 | /* Hook that is called by cgraph.cc when an edge is removed. Adjust reference | |||
4368 | count data structures accordingly. */ | |||
4369 | ||||
4370 | void | |||
4371 | ipa_edge_args_sum_t::remove (cgraph_edge *cs, ipa_edge_args *args) | |||
4372 | { | |||
4373 | if (args->jump_functions) | |||
4374 | { | |||
4375 | struct ipa_jump_func *jf; | |||
4376 | int i; | |||
4377 | FOR_EACH_VEC_ELT (*args->jump_functions, i, jf)for (i = 0; (*args->jump_functions).iterate ((i), &(jf )); ++(i)) | |||
4378 | { | |||
4379 | struct ipa_cst_ref_desc *rdesc; | |||
4380 | try_decrement_rdesc_refcount (jf); | |||
4381 | if (jf->type == IPA_JF_CONST | |||
4382 | && (rdesc = ipa_get_jf_constant_rdesc (jf)) | |||
4383 | && rdesc->cs == cs) | |||
4384 | rdesc->cs = NULLnullptr; | |||
4385 | } | |||
4386 | } | |||
4387 | } | |||
4388 | ||||
4389 | /* Method invoked when an edge is duplicated. Copy ipa_edge_args and adjust | |||
4390 | reference count data strucutres accordingly. */ | |||
4391 | ||||
4392 | void | |||
4393 | ipa_edge_args_sum_t::duplicate (cgraph_edge *src, cgraph_edge *dst, | |||
4394 | ipa_edge_args *old_args, ipa_edge_args *new_args) | |||
4395 | { | |||
4396 | unsigned int i; | |||
4397 | ||||
4398 | new_args->jump_functions = vec_safe_copy (old_args->jump_functions); | |||
4399 | if (old_args->polymorphic_call_contexts) | |||
4400 | new_args->polymorphic_call_contexts | |||
4401 | = vec_safe_copy (old_args->polymorphic_call_contexts); | |||
4402 | ||||
4403 | for (i = 0; i < vec_safe_length (old_args->jump_functions); i++) | |||
4404 | { | |||
4405 | struct ipa_jump_func *src_jf = ipa_get_ith_jump_func (old_args, i); | |||
4406 | struct ipa_jump_func *dst_jf = ipa_get_ith_jump_func (new_args, i); | |||
4407 | ||||
4408 | dst_jf->agg.items = vec_safe_copy (dst_jf->agg.items); | |||
4409 | ||||
4410 | if (src_jf->type == IPA_JF_CONST) | |||
4411 | { | |||
4412 | struct ipa_cst_ref_desc *src_rdesc = jfunc_rdesc_usable (src_jf); | |||
4413 | ||||
4414 | if (!src_rdesc) | |||
4415 | dst_jf->value.constant.rdesc = NULLnullptr; | |||
4416 | else if (src->caller == dst->caller) | |||
4417 | { | |||
4418 | /* Creation of a speculative edge. If the source edge is the one | |||
4419 | grabbing a reference, we must create a new (duplicate) | |||
4420 | reference description. Otherwise they refer to the same | |||
4421 | description corresponding to a reference taken in a function | |||
4422 | src->caller is inlined to. In that case we just must | |||
4423 | increment the refcount. */ | |||
4424 | if (src_rdesc->cs == src) | |||
4425 | { | |||
4426 | symtab_node *n = symtab_node_for_jfunc (src_jf); | |||
4427 | gcc_checking_assert (n)((void)(!(n) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 4427, __FUNCTION__), 0 : 0)); | |||
4428 | ipa_ref *ref | |||
4429 | = src->caller->find_reference (n, src->call_stmt, | |||
4430 | src->lto_stmt_uid); | |||
4431 | gcc_checking_assert (ref)((void)(!(ref) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 4431, __FUNCTION__), 0 : 0)); | |||
4432 | dst->caller->clone_reference (ref, ref->stmt); | |||
4433 | ||||
4434 | ipa_cst_ref_desc *dst_rdesc = ipa_refdesc_pool.allocate (); | |||
4435 | dst_rdesc->cs = dst; | |||
4436 | dst_rdesc->refcount = src_rdesc->refcount; | |||
4437 | dst_rdesc->next_duplicate = NULLnullptr; | |||
4438 | dst_jf->value.constant.rdesc = dst_rdesc; | |||
4439 | } | |||
4440 | else | |||
4441 | { | |||
4442 | src_rdesc->refcount++; | |||
4443 | dst_jf->value.constant.rdesc = src_rdesc; | |||
4444 | } | |||
4445 | } | |||
4446 | else if (src_rdesc->cs == src) | |||
4447 | { | |||
4448 | struct ipa_cst_ref_desc *dst_rdesc = ipa_refdesc_pool.allocate (); | |||
4449 | dst_rdesc->cs = dst; | |||
4450 | dst_rdesc->refcount = src_rdesc->refcount; | |||
4451 | dst_rdesc->next_duplicate = src_rdesc->next_duplicate; | |||
4452 | src_rdesc->next_duplicate = dst_rdesc; | |||
4453 | dst_jf->value.constant.rdesc = dst_rdesc; | |||
4454 | } | |||
4455 | else | |||
4456 | { | |||
4457 | struct ipa_cst_ref_desc *dst_rdesc; | |||
4458 | /* This can happen during inlining, when a JFUNC can refer to a | |||
4459 | reference taken in a function up in the tree of inline clones. | |||
4460 | We need to find the duplicate that refers to our tree of | |||
4461 | inline clones. */ | |||
4462 | ||||
4463 | gcc_assert (dst->caller->inlined_to)((void)(!(dst->caller->inlined_to) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 4463, __FUNCTION__), 0 : 0)); | |||
4464 | for (dst_rdesc = src_rdesc->next_duplicate; | |||
4465 | dst_rdesc; | |||
4466 | dst_rdesc = dst_rdesc->next_duplicate) | |||
4467 | { | |||
4468 | struct cgraph_node *top; | |||
4469 | top = dst_rdesc->cs->caller->inlined_to | |||
4470 | ? dst_rdesc->cs->caller->inlined_to | |||
4471 | : dst_rdesc->cs->caller; | |||
4472 | if (dst->caller->inlined_to == top) | |||
4473 | break; | |||
4474 | } | |||
4475 | gcc_assert (dst_rdesc)((void)(!(dst_rdesc) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 4475, __FUNCTION__), 0 : 0)); | |||
4476 | dst_jf->value.constant.rdesc = dst_rdesc; | |||
4477 | } | |||
4478 | } | |||
4479 | else if (dst_jf->type == IPA_JF_PASS_THROUGH | |||
4480 | && src->caller == dst->caller) | |||
4481 | { | |||
4482 | struct cgraph_node *inline_root = dst->caller->inlined_to | |||
4483 | ? dst->caller->inlined_to : dst->caller; | |||
4484 | ipa_node_params *root_info = ipa_node_params_sum->get (inline_root); | |||
4485 | int idx = ipa_get_jf_pass_through_formal_id (dst_jf); | |||
4486 | ||||
4487 | int c = ipa_get_controlled_uses (root_info, idx); | |||
4488 | if (c != IPA_UNDESCRIBED_USE-1) | |||
4489 | { | |||
4490 | c++; | |||
4491 | ipa_set_controlled_uses (root_info, idx, c); | |||
4492 | } | |||
4493 | } | |||
4494 | } | |||
4495 | } | |||
4496 | ||||
4497 | /* Analyze newly added function into callgraph. */ | |||
4498 | ||||
4499 | static void | |||
4500 | ipa_add_new_function (cgraph_node *node, void *data ATTRIBUTE_UNUSED__attribute__ ((__unused__))) | |||
4501 | { | |||
4502 | if (node->has_gimple_body_p ()) | |||
| ||||
4503 | ipa_analyze_node (node); | |||
4504 | } | |||
4505 | ||||
4506 | /* Hook that is called by summary when a node is duplicated. */ | |||
4507 | ||||
4508 | void | |||
4509 | ipa_node_params_t::duplicate(cgraph_node *, cgraph_node *, | |||
4510 | ipa_node_params *old_info, | |||
4511 | ipa_node_params *new_info) | |||
4512 | { | |||
4513 | new_info->descriptors = vec_safe_copy (old_info->descriptors); | |||
4514 | new_info->lattices = NULLnullptr; | |||
4515 | new_info->ipcp_orig_node = old_info->ipcp_orig_node; | |||
4516 | new_info->known_csts = old_info->known_csts.copy (); | |||
4517 | new_info->known_contexts = old_info->known_contexts.copy (); | |||
4518 | ||||
4519 | new_info->analysis_done = old_info->analysis_done; | |||
4520 | new_info->node_enqueued = old_info->node_enqueued; | |||
4521 | new_info->versionable = old_info->versionable; | |||
4522 | } | |||
4523 | ||||
4524 | /* Duplication of ipcp transformation summaries. */ | |||
4525 | ||||
4526 | void | |||
4527 | ipcp_transformation_t::duplicate(cgraph_node *, cgraph_node *dst, | |||
4528 | ipcp_transformation *src_trans, | |||
4529 | ipcp_transformation *dst_trans) | |||
4530 | { | |||
4531 | /* Avoid redundant work of duplicating vectors we will never use. */ | |||
4532 | if (dst->inlined_to) | |||
4533 | return; | |||
4534 | dst_trans->m_agg_values = vec_safe_copy (src_trans->m_agg_values); | |||
4535 | dst_trans->bits = vec_safe_copy (src_trans->bits); | |||
4536 | dst_trans->m_vr = vec_safe_copy (src_trans->m_vr); | |||
4537 | } | |||
4538 | ||||
4539 | /* Register our cgraph hooks if they are not already there. */ | |||
4540 | ||||
4541 | void | |||
4542 | ipa_register_cgraph_hooks (void) | |||
4543 | { | |||
4544 | ipa_check_create_node_params (); | |||
4545 | ipa_check_create_edge_args (); | |||
4546 | ||||
4547 | function_insertion_hook_holder = | |||
4548 | symtab->add_cgraph_insertion_hook (&ipa_add_new_function, NULLnullptr); | |||
4549 | } | |||
4550 | ||||
4551 | /* Unregister our cgraph hooks if they are not already there. */ | |||
4552 | ||||
4553 | static void | |||
4554 | ipa_unregister_cgraph_hooks (void) | |||
4555 | { | |||
4556 | if (function_insertion_hook_holder) | |||
4557 | symtab->remove_cgraph_insertion_hook (function_insertion_hook_holder); | |||
4558 | function_insertion_hook_holder = NULLnullptr; | |||
4559 | } | |||
4560 | ||||
4561 | /* Free all ipa_node_params and all ipa_edge_args structures if they are no | |||
4562 | longer needed after ipa-cp. */ | |||
4563 | ||||
4564 | void | |||
4565 | ipa_free_all_structures_after_ipa_cp (void) | |||
4566 | { | |||
4567 | if (!optimizeglobal_options.x_optimize && !in_lto_pglobal_options.x_in_lto_p) | |||
4568 | { | |||
4569 | ipa_free_all_edge_args (); | |||
4570 | ipa_free_all_node_params (); | |||
4571 | ipcp_sources_pool.release (); | |||
4572 | ipcp_cst_values_pool.release (); | |||
4573 | ipcp_poly_ctx_values_pool.release (); | |||
4574 | ipcp_agg_lattice_pool.release (); | |||
4575 | ipa_unregister_cgraph_hooks (); | |||
4576 | ipa_refdesc_pool.release (); | |||
4577 | } | |||
4578 | } | |||
4579 | ||||
4580 | /* Free all ipa_node_params and all ipa_edge_args structures if they are no | |||
4581 | longer needed after indirect inlining. */ | |||
4582 | ||||
4583 | void | |||
4584 | ipa_free_all_structures_after_iinln (void) | |||
4585 | { | |||
4586 | ipa_free_all_edge_args (); | |||
4587 | ipa_free_all_node_params (); | |||
4588 | ipa_unregister_cgraph_hooks (); | |||
4589 | ipcp_sources_pool.release (); | |||
4590 | ipcp_cst_values_pool.release (); | |||
4591 | ipcp_poly_ctx_values_pool.release (); | |||
4592 | ipcp_agg_lattice_pool.release (); | |||
4593 | ipa_refdesc_pool.release (); | |||
4594 | } | |||
4595 | ||||
4596 | /* Print ipa_tree_map data structures of all functions in the | |||
4597 | callgraph to F. */ | |||
4598 | ||||
4599 | void | |||
4600 | ipa_print_node_params (FILE *f, struct cgraph_node *node) | |||
4601 | { | |||
4602 | int i, count; | |||
4603 | class ipa_node_params *info; | |||
4604 | ||||
4605 | if (!node->definition) | |||
4606 | return; | |||
4607 | info = ipa_node_params_sum->get (node); | |||
4608 | fprintf (f, " function %s parameter descriptors:\n", node->dump_name ()); | |||
4609 | if (!info) | |||
4610 | { | |||
4611 | fprintf (f, " no params return\n"); | |||
4612 | return; | |||
4613 | } | |||
4614 | count = ipa_get_param_count (info); | |||
4615 | for (i = 0; i < count; i++) | |||
4616 | { | |||
4617 | int c; | |||
4618 | ||||
4619 | fprintf (f, " "); | |||
4620 | ipa_dump_param (f, info, i); | |||
4621 | if (ipa_is_param_used (info, i)) | |||
4622 | fprintf (f, " used"); | |||
4623 | if (ipa_is_param_used_by_ipa_predicates (info, i)) | |||
4624 | fprintf (f, " used_by_ipa_predicates"); | |||
4625 | if (ipa_is_param_used_by_indirect_call (info, i)) | |||
4626 | fprintf (f, " used_by_indirect_call"); | |||
4627 | if (ipa_is_param_used_by_polymorphic_call (info, i)) | |||
4628 | fprintf (f, " used_by_polymorphic_call"); | |||
4629 | c = ipa_get_controlled_uses (info, i); | |||
4630 | if (c == IPA_UNDESCRIBED_USE-1) | |||
4631 | fprintf (f, " undescribed_use"); | |||
4632 | else | |||
4633 | fprintf (f, " controlled_uses=%i %s", c, | |||
4634 | ipa_get_param_load_dereferenced (info, i) | |||
4635 | ? "(load_dereferenced)" : ""); | |||
4636 | fprintf (f, "\n"); | |||
4637 | } | |||
4638 | } | |||
4639 | ||||
4640 | /* Print ipa_tree_map data structures of all functions in the | |||
4641 | callgraph to F. */ | |||
4642 | ||||
4643 | void | |||
4644 | ipa_print_all_params (FILE * f) | |||
4645 | { | |||
4646 | struct cgraph_node *node; | |||
4647 | ||||
4648 | fprintf (f, "\nFunction parameters:\n"); | |||
4649 | FOR_EACH_FUNCTION (node)for ((node) = symtab->first_function (); (node); (node) = symtab ->next_function ((node))) | |||
4650 | ipa_print_node_params (f, node); | |||
4651 | } | |||
4652 | ||||
4653 | /* Stream out jump function JUMP_FUNC to OB. */ | |||
4654 | ||||
4655 | static void | |||
4656 | ipa_write_jump_function (struct output_block *ob, | |||
4657 | struct ipa_jump_func *jump_func) | |||
4658 | { | |||
4659 | struct ipa_agg_jf_item *item; | |||
4660 | struct bitpack_d bp; | |||
4661 | int i, count; | |||
4662 | int flag = 0; | |||
4663 | ||||
4664 | /* ADDR_EXPRs are very comon IP invariants; save some streamer data | |||
4665 | as well as WPA memory by handling them specially. */ | |||
4666 | if (jump_func->type == IPA_JF_CONST | |||
4667 | && TREE_CODE (jump_func->value.constant.value)((enum tree_code) (jump_func->value.constant.value)->base .code) == ADDR_EXPR) | |||
4668 | flag = 1; | |||
4669 | ||||
4670 | streamer_write_uhwi (ob, jump_func->type * 2 + flag); | |||
4671 | switch (jump_func->type) | |||
4672 | { | |||
4673 | case IPA_JF_UNKNOWN: | |||
4674 | break; | |||
4675 | case IPA_JF_CONST: | |||
4676 | gcc_assert (((void)(!(((((jump_func->value.constant.value)) && ((tree_code_type_tmpl <0>::tree_code_type[(int) (((enum tree_code) ((jump_func->value.constant.value))->base.code ))]) >= tcc_reference && (tree_code_type_tmpl < 0>::tree_code_type[(int) (((enum tree_code) ((jump_func-> value.constant.value))->base.code))]) <= tcc_expression )) ? (jump_func->value.constant.value)->exp.locus : ((location_t ) 0)) == ((location_t) 0)) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 4677, __FUNCTION__), 0 : 0)) | |||
4677 | EXPR_LOCATION (jump_func->value.constant.value) == UNKNOWN_LOCATION)((void)(!(((((jump_func->value.constant.value)) && ((tree_code_type_tmpl <0>::tree_code_type[(int) (((enum tree_code) ((jump_func->value.constant.value))->base.code ))]) >= tcc_reference && (tree_code_type_tmpl < 0>::tree_code_type[(int) (((enum tree_code) ((jump_func-> value.constant.value))->base.code))]) <= tcc_expression )) ? (jump_func->value.constant.value)->exp.locus : ((location_t ) 0)) == ((location_t) 0)) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 4677, __FUNCTION__), 0 : 0)); | |||
4678 | stream_write_tree (ob,streamer_hooks.write_tree (ob, flag ? (*((const_cast<tree* > (tree_operand_check ((jump_func->value.constant.value ), (0), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 4680, __FUNCTION__))))) : jump_func->value.constant.value , true, true) | |||
4679 | flagstreamer_hooks.write_tree (ob, flag ? (*((const_cast<tree* > (tree_operand_check ((jump_func->value.constant.value ), (0), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 4680, __FUNCTION__))))) : jump_func->value.constant.value , true, true) | |||
4680 | ? TREE_OPERAND (jump_func->value.constant.value, 0)streamer_hooks.write_tree (ob, flag ? (*((const_cast<tree* > (tree_operand_check ((jump_func->value.constant.value ), (0), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 4680, __FUNCTION__))))) : jump_func->value.constant.value , true, true) | |||
4681 | : jump_func->value.constant.value, true)streamer_hooks.write_tree (ob, flag ? (*((const_cast<tree* > (tree_operand_check ((jump_func->value.constant.value ), (0), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 4680, __FUNCTION__))))) : jump_func->value.constant.value , true, true); | |||
4682 | break; | |||
4683 | case IPA_JF_PASS_THROUGH: | |||
4684 | streamer_write_uhwi (ob, jump_func->value.pass_through.operation); | |||
4685 | if (jump_func->value.pass_through.operation == NOP_EXPR) | |||
4686 | { | |||
4687 | streamer_write_uhwi (ob, jump_func->value.pass_through.formal_id); | |||
4688 | bp = bitpack_create (ob->main_stream); | |||
4689 | bp_pack_value (&bp, jump_func->value.pass_through.agg_preserved, 1); | |||
4690 | streamer_write_bitpack (&bp); | |||
4691 | } | |||
4692 | else if (TREE_CODE_CLASS (jump_func->value.pass_through.operation)tree_code_type_tmpl <0>::tree_code_type[(int) (jump_func ->value.pass_through.operation)] | |||
4693 | == tcc_unary) | |||
4694 | streamer_write_uhwi (ob, jump_func->value.pass_through.formal_id); | |||
4695 | else | |||
4696 | { | |||
4697 | stream_write_tree (ob, jump_func->value.pass_through.operand, true)streamer_hooks.write_tree (ob, jump_func->value.pass_through .operand, true, true); | |||
4698 | streamer_write_uhwi (ob, jump_func->value.pass_through.formal_id); | |||
4699 | } | |||
4700 | break; | |||
4701 | case IPA_JF_ANCESTOR: | |||
4702 | streamer_write_uhwi (ob, jump_func->value.ancestor.offset); | |||
4703 | streamer_write_uhwi (ob, jump_func->value.ancestor.formal_id); | |||
4704 | bp = bitpack_create (ob->main_stream); | |||
4705 | bp_pack_value (&bp, jump_func->value.ancestor.agg_preserved, 1); | |||
4706 | bp_pack_value (&bp, jump_func->value.ancestor.keep_null, 1); | |||
4707 | streamer_write_bitpack (&bp); | |||
4708 | break; | |||
4709 | default: | |||
4710 | fatal_error (UNKNOWN_LOCATION((location_t) 0), "invalid jump function in LTO stream"); | |||
4711 | } | |||
4712 | ||||
4713 | count = vec_safe_length (jump_func->agg.items); | |||
4714 | streamer_write_uhwi (ob, count); | |||
4715 | if (count) | |||
4716 | { | |||
4717 | bp = bitpack_create (ob->main_stream); | |||
4718 | bp_pack_value (&bp, jump_func->agg.by_ref, 1); | |||
4719 | streamer_write_bitpack (&bp); | |||
4720 | } | |||
4721 | ||||
4722 | FOR_EACH_VEC_SAFE_ELT (jump_func->agg.items, i, item)for (i = 0; vec_safe_iterate ((jump_func->agg.items), (i), &(item)); ++(i)) | |||
4723 | { | |||
4724 | stream_write_tree (ob, item->type, true)streamer_hooks.write_tree (ob, item->type, true, true); | |||
4725 | streamer_write_uhwi (ob, item->offset); | |||
4726 | streamer_write_uhwi (ob, item->jftype); | |||
4727 | switch (item->jftype) | |||
4728 | { | |||
4729 | case IPA_JF_UNKNOWN: | |||
4730 | break; | |||
4731 | case IPA_JF_CONST: | |||
4732 | stream_write_tree (ob, item->value.constant, true)streamer_hooks.write_tree (ob, item->value.constant, true, true); | |||
4733 | break; | |||
4734 | case IPA_JF_PASS_THROUGH: | |||
4735 | case IPA_JF_LOAD_AGG: | |||
4736 | streamer_write_uhwi (ob, item->value.pass_through.operation); | |||
4737 | streamer_write_uhwi (ob, item->value.pass_through.formal_id); | |||
4738 | if (TREE_CODE_CLASS (item->value.pass_through.operation)tree_code_type_tmpl <0>::tree_code_type[(int) (item-> value.pass_through.operation)] | |||
4739 | != tcc_unary) | |||
4740 | stream_write_tree (ob, item->value.pass_through.operand, true)streamer_hooks.write_tree (ob, item->value.pass_through.operand , true, true); | |||
4741 | if (item->jftype == IPA_JF_LOAD_AGG) | |||
4742 | { | |||
4743 | stream_write_tree (ob, item->value.load_agg.type, true)streamer_hooks.write_tree (ob, item->value.load_agg.type, true , true); | |||
4744 | streamer_write_uhwi (ob, item->value.load_agg.offset); | |||
4745 | bp = bitpack_create (ob->main_stream); | |||
4746 | bp_pack_value (&bp, item->value.load_agg.by_ref, 1); | |||
4747 | streamer_write_bitpack (&bp); | |||
4748 | } | |||
4749 | break; | |||
4750 | default: | |||
4751 | fatal_error (UNKNOWN_LOCATION((location_t) 0), | |||
4752 | "invalid jump function in LTO stream"); | |||
4753 | } | |||
4754 | } | |||
4755 | ||||
4756 | bp = bitpack_create (ob->main_stream); | |||
4757 | bp_pack_value (&bp, !!jump_func->bits, 1); | |||
4758 | streamer_write_bitpack (&bp); | |||
4759 | if (jump_func->bits) | |||
4760 | { | |||
4761 | streamer_write_widest_int (ob, jump_func->bits->value); | |||
4762 | streamer_write_widest_int (ob, jump_func->bits->mask); | |||
4763 | } | |||
4764 | bp_pack_value (&bp, !!jump_func->m_vr, 1); | |||
4765 | streamer_write_bitpack (&bp); | |||
4766 | if (jump_func->m_vr) | |||
4767 | { | |||
4768 | streamer_write_enum (ob->main_stream, value_rang_type,streamer_write_hwi_in_range ((ob->main_stream), 0, (int)(VR_LAST ) - 1, (int)(jump_func->m_vr->kind ())) | |||
4769 | VR_LAST, jump_func->m_vr->kind ())streamer_write_hwi_in_range ((ob->main_stream), 0, (int)(VR_LAST ) - 1, (int)(jump_func->m_vr->kind ())); | |||
4770 | stream_write_tree (ob, jump_func->m_vr->min (), true)streamer_hooks.write_tree (ob, jump_func->m_vr->min (), true, true); | |||
4771 | stream_write_tree (ob, jump_func->m_vr->max (), true)streamer_hooks.write_tree (ob, jump_func->m_vr->max (), true, true); | |||
4772 | } | |||
4773 | } | |||
4774 | ||||
4775 | /* Read in jump function JUMP_FUNC from IB. */ | |||
4776 | ||||
4777 | static void | |||
4778 | ipa_read_jump_function (class lto_input_block *ib, | |||
4779 | struct ipa_jump_func *jump_func, | |||
4780 | struct cgraph_edge *cs, | |||
4781 | class data_in *data_in, | |||
4782 | bool prevails) | |||
4783 | { | |||
4784 | enum jump_func_type jftype; | |||
4785 | enum tree_code operation; | |||
4786 | int i, count; | |||
4787 | int val = streamer_read_uhwi (ib); | |||
4788 | bool flag = val & 1; | |||
4789 | ||||
4790 | jftype = (enum jump_func_type) (val / 2); | |||
4791 | switch (jftype) | |||
4792 | { | |||
4793 | case IPA_JF_UNKNOWN: | |||
4794 | ipa_set_jf_unknown (jump_func); | |||
4795 | break; | |||
4796 | case IPA_JF_CONST: | |||
4797 | { | |||
4798 | tree t = stream_read_tree (ib, data_in)streamer_hooks.read_tree (ib, data_in); | |||
4799 | if (flag && prevails) | |||
4800 | t = build1 (ADDR_EXPR, build_pointer_type (TREE_TYPE (t)((contains_struct_check ((t), (TS_TYPED), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 4800, __FUNCTION__))->typed.type)), t); | |||
4801 | ipa_set_jf_constant (jump_func, t, cs); | |||
4802 | } | |||
4803 | break; | |||
4804 | case IPA_JF_PASS_THROUGH: | |||
4805 | operation = (enum tree_code) streamer_read_uhwi (ib); | |||
4806 | if (operation == NOP_EXPR) | |||
4807 | { | |||
4808 | int formal_id = streamer_read_uhwi (ib); | |||
4809 | struct bitpack_d bp = streamer_read_bitpack (ib); | |||
4810 | bool agg_preserved = bp_unpack_value (&bp, 1); | |||
4811 | ipa_set_jf_simple_pass_through (jump_func, formal_id, agg_preserved); | |||
4812 | } | |||
4813 | else if (TREE_CODE_CLASS (operation)tree_code_type_tmpl <0>::tree_code_type[(int) (operation )] == tcc_unary) | |||
4814 | { | |||
4815 | int formal_id = streamer_read_uhwi (ib); | |||
4816 | ipa_set_jf_unary_pass_through (jump_func, formal_id, operation); | |||
4817 | } | |||
4818 | else | |||
4819 | { | |||
4820 | tree operand = stream_read_tree (ib, data_in)streamer_hooks.read_tree (ib, data_in); | |||
4821 | int formal_id = streamer_read_uhwi (ib); | |||
4822 | ipa_set_jf_arith_pass_through (jump_func, formal_id, operand, | |||
4823 | operation); | |||
4824 | } | |||
4825 | break; | |||
4826 | case IPA_JF_ANCESTOR: | |||
4827 | { | |||
4828 | HOST_WIDE_INTlong offset = streamer_read_uhwi (ib); | |||
4829 | int formal_id = streamer_read_uhwi (ib); | |||
4830 | struct bitpack_d bp = streamer_read_bitpack (ib); | |||
4831 | bool agg_preserved = bp_unpack_value (&bp, 1); | |||
4832 | bool keep_null = bp_unpack_value (&bp, 1); | |||
4833 | ipa_set_ancestor_jf (jump_func, offset, formal_id, agg_preserved, | |||
4834 | keep_null); | |||
4835 | break; | |||
4836 | } | |||
4837 | default: | |||
4838 | fatal_error (UNKNOWN_LOCATION((location_t) 0), "invalid jump function in LTO stream"); | |||
4839 | } | |||
4840 | ||||
4841 | count = streamer_read_uhwi (ib); | |||
4842 | if (prevails) | |||
4843 | { | |||
4844 | jump_func->agg.items = NULLnullptr; | |||
4845 | vec_safe_reserve (jump_func->agg.items, count, true); | |||
4846 | } | |||
4847 | if (count) | |||
4848 | { | |||
4849 | struct bitpack_d bp = streamer_read_bitpack (ib); | |||
4850 | jump_func->agg.by_ref = bp_unpack_value (&bp, 1); | |||
4851 | } | |||
4852 | for (i = 0; i < count; i++) | |||
4853 | { | |||
4854 | struct ipa_agg_jf_item item; | |||
4855 | item.type = stream_read_tree (ib, data_in)streamer_hooks.read_tree (ib, data_in); | |||
4856 | item.offset = streamer_read_uhwi (ib); | |||
4857 | item.jftype = (enum jump_func_type) streamer_read_uhwi (ib); | |||
4858 | ||||
4859 | switch (item.jftype) | |||
4860 | { | |||
4861 | case IPA_JF_UNKNOWN: | |||
4862 | break; | |||
4863 | case IPA_JF_CONST: | |||
4864 | item.value.constant = stream_read_tree (ib, data_in)streamer_hooks.read_tree (ib, data_in); | |||
4865 | break; | |||
4866 | case IPA_JF_PASS_THROUGH: | |||
4867 | case IPA_JF_LOAD_AGG: | |||
4868 | operation = (enum tree_code) streamer_read_uhwi (ib); | |||
4869 | item.value.pass_through.operation = operation; | |||
4870 | item.value.pass_through.formal_id = streamer_read_uhwi (ib); | |||
4871 | if (TREE_CODE_CLASS (operation)tree_code_type_tmpl <0>::tree_code_type[(int) (operation )] == tcc_unary) | |||
4872 | item.value.pass_through.operand = NULL_TREE(tree) nullptr; | |||
4873 | else | |||
4874 | item.value.pass_through.operand = stream_read_tree (ib, data_in)streamer_hooks.read_tree (ib, data_in); | |||
4875 | if (item.jftype == IPA_JF_LOAD_AGG) | |||
4876 | { | |||
4877 | struct bitpack_d bp; | |||
4878 | item.value.load_agg.type = stream_read_tree (ib, data_in)streamer_hooks.read_tree (ib, data_in); | |||
4879 | item.value.load_agg.offset = streamer_read_uhwi (ib); | |||
4880 | bp = streamer_read_bitpack (ib); | |||
4881 | item.value.load_agg.by_ref = bp_unpack_value (&bp, 1); | |||
4882 | } | |||
4883 | break; | |||
4884 | default: | |||
4885 | fatal_error (UNKNOWN_LOCATION((location_t) 0), | |||
4886 | "invalid jump function in LTO stream"); | |||
4887 | } | |||
4888 | if (prevails) | |||
4889 | jump_func->agg.items->quick_push (item); | |||
4890 | } | |||
4891 | ||||
4892 | struct bitpack_d bp = streamer_read_bitpack (ib); | |||
4893 | bool bits_known = bp_unpack_value (&bp, 1); | |||
4894 | if (bits_known) | |||
4895 | { | |||
4896 | widest_int value = streamer_read_widest_int (ib); | |||
4897 | widest_int mask = streamer_read_widest_int (ib); | |||
4898 | if (prevails) | |||
4899 | ipa_set_jfunc_bits (jump_func, value, mask); | |||
4900 | } | |||
4901 | else | |||
4902 | jump_func->bits = NULLnullptr; | |||
4903 | ||||
4904 | struct bitpack_d vr_bp = streamer_read_bitpack (ib); | |||
4905 | bool vr_known = bp_unpack_value (&vr_bp, 1); | |||
4906 | if (vr_known) | |||
4907 | { | |||
4908 | enum value_range_kind type = streamer_read_enum (ib, value_range_kind,(enum value_range_kind)streamer_read_hwi_in_range ((ib), "value_range_kind" , 0, (int)(VR_LAST) - 1) | |||
4909 | VR_LAST)(enum value_range_kind)streamer_read_hwi_in_range ((ib), "value_range_kind" , 0, (int)(VR_LAST) - 1); | |||
4910 | tree min = stream_read_tree (ib, data_in)streamer_hooks.read_tree (ib, data_in); | |||
4911 | tree max = stream_read_tree (ib, data_in)streamer_hooks.read_tree (ib, data_in); | |||
4912 | if (prevails) | |||
4913 | ipa_set_jfunc_vr (jump_func, type, min, max); | |||
4914 | } | |||
4915 | else | |||
4916 | jump_func->m_vr = NULLnullptr; | |||
4917 | } | |||
4918 | ||||
4919 | /* Stream out parts of cgraph_indirect_call_info corresponding to CS that are | |||
4920 | relevant to indirect inlining to OB. */ | |||
4921 | ||||
4922 | static void | |||
4923 | ipa_write_indirect_edge_info (struct output_block *ob, | |||
4924 | struct cgraph_edge *cs) | |||
4925 | { | |||
4926 | class cgraph_indirect_call_info *ii = cs->indirect_info; | |||
4927 | struct bitpack_d bp; | |||
4928 | ||||
4929 | streamer_write_hwi (ob, ii->param_index); | |||
4930 | bp = bitpack_create (ob->main_stream); | |||
4931 | bp_pack_value (&bp, ii->polymorphic, 1); | |||
4932 | bp_pack_value (&bp, ii->agg_contents, 1); | |||
4933 | bp_pack_value (&bp, ii->member_ptr, 1); | |||
4934 | bp_pack_value (&bp, ii->by_ref, 1); | |||
4935 | bp_pack_value (&bp, ii->guaranteed_unmodified, 1); | |||
4936 | bp_pack_value (&bp, ii->vptr_changed, 1); | |||
4937 | streamer_write_bitpack (&bp); | |||
4938 | if (ii->agg_contents || ii->polymorphic) | |||
4939 | streamer_write_hwi (ob, ii->offset); | |||
4940 | else | |||
4941 | gcc_assert (ii->offset == 0)((void)(!(ii->offset == 0) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 4941, __FUNCTION__), 0 : 0)); | |||
4942 | ||||
4943 | if (ii->polymorphic) | |||
4944 | { | |||
4945 | streamer_write_hwi (ob, ii->otr_token); | |||
4946 | stream_write_tree (ob, ii->otr_type, true)streamer_hooks.write_tree (ob, ii->otr_type, true, true); | |||
4947 | ii->context.stream_out (ob); | |||
4948 | } | |||
4949 | } | |||
4950 | ||||
4951 | /* Read in parts of cgraph_indirect_call_info corresponding to CS that are | |||
4952 | relevant to indirect inlining from IB. */ | |||
4953 | ||||
4954 | static void | |||
4955 | ipa_read_indirect_edge_info (class lto_input_block *ib, | |||
4956 | class data_in *data_in, | |||
4957 | struct cgraph_edge *cs, | |||
4958 | class ipa_node_params *info) | |||
4959 | { | |||
4960 | class cgraph_indirect_call_info *ii = cs->indirect_info; | |||
4961 | struct bitpack_d bp; | |||
4962 | ||||
4963 | ii->param_index = (int) streamer_read_hwi (ib); | |||
4964 | bp = streamer_read_bitpack (ib); | |||
4965 | ii->polymorphic = bp_unpack_value (&bp, 1); | |||
4966 | ii->agg_contents = bp_unpack_value (&bp, 1); | |||
4967 | ii->member_ptr = bp_unpack_value (&bp, 1); | |||
4968 | ii->by_ref = bp_unpack_value (&bp, 1); | |||
4969 | ii->guaranteed_unmodified = bp_unpack_value (&bp, 1); | |||
4970 | ii->vptr_changed = bp_unpack_value (&bp, 1); | |||
4971 | if (ii->agg_contents || ii->polymorphic) | |||
4972 | ii->offset = (HOST_WIDE_INTlong) streamer_read_hwi (ib); | |||
4973 | else | |||
4974 | ii->offset = 0; | |||
4975 | if (ii->polymorphic) | |||
4976 | { | |||
4977 | ii->otr_token = (HOST_WIDE_INTlong) streamer_read_hwi (ib); | |||
4978 | ii->otr_type = stream_read_tree (ib, data_in)streamer_hooks.read_tree (ib, data_in); | |||
4979 | ii->context.stream_in (ib, data_in); | |||
4980 | } | |||
4981 | if (info && ii->param_index >= 0) | |||
4982 | { | |||
4983 | if (ii->polymorphic) | |||
4984 | ipa_set_param_used_by_polymorphic_call (info, | |||
4985 | ii->param_index , true); | |||
4986 | ipa_set_param_used_by_indirect_call (info, | |||
4987 | ii->param_index, true); | |||
4988 | } | |||
4989 | } | |||
4990 | ||||
4991 | /* Stream out NODE info to OB. */ | |||
4992 | ||||
4993 | static void | |||
4994 | ipa_write_node_info (struct output_block *ob, struct cgraph_node *node) | |||
4995 | { | |||
4996 | int node_ref; | |||
4997 | lto_symtab_encoder_t encoder; | |||
4998 | ipa_node_params *info = ipa_node_params_sum->get (node); | |||
4999 | int j; | |||
5000 | struct cgraph_edge *e; | |||
5001 | struct bitpack_d bp; | |||
5002 | ||||
5003 | encoder = ob->decl_state->symtab_node_encoder; | |||
5004 | node_ref = lto_symtab_encoder_encode (encoder, node); | |||
5005 | streamer_write_uhwi (ob, node_ref); | |||
5006 | ||||
5007 | streamer_write_uhwi (ob, ipa_get_param_count (info)); | |||
5008 | for (j = 0; j < ipa_get_param_count (info); j++) | |||
5009 | streamer_write_uhwi (ob, ipa_get_param_move_cost (info, j)); | |||
5010 | bp = bitpack_create (ob->main_stream); | |||
5011 | gcc_assert (info->analysis_done((void)(!(info->analysis_done || ipa_get_param_count (info ) == 0) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 5012, __FUNCTION__), 0 : 0)) | |||
5012 | || ipa_get_param_count (info) == 0)((void)(!(info->analysis_done || ipa_get_param_count (info ) == 0) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 5012, __FUNCTION__), 0 : 0)); | |||
5013 | gcc_assert (!info->node_enqueued)((void)(!(!info->node_enqueued) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 5013, __FUNCTION__), 0 : 0)); | |||
5014 | gcc_assert (!info->ipcp_orig_node)((void)(!(!info->ipcp_orig_node) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 5014, __FUNCTION__), 0 : 0)); | |||
5015 | for (j = 0; j < ipa_get_param_count (info); j++) | |||
5016 | { | |||
5017 | /* TODO: We could just not stream the bit in the undescribed case. */ | |||
5018 | bool d = (ipa_get_controlled_uses (info, j) != IPA_UNDESCRIBED_USE-1) | |||
5019 | ? ipa_get_param_load_dereferenced (info, j) : true; | |||
5020 | bp_pack_value (&bp, d, 1); | |||
5021 | bp_pack_value (&bp, ipa_is_param_used (info, j), 1); | |||
5022 | } | |||
5023 | streamer_write_bitpack (&bp); | |||
5024 | for (j = 0; j < ipa_get_param_count (info); j++) | |||
5025 | { | |||
5026 | streamer_write_hwi (ob, ipa_get_controlled_uses (info, j)); | |||
5027 | stream_write_tree (ob, ipa_get_type (info, j), true)streamer_hooks.write_tree (ob, ipa_get_type (info, j), true, true ); | |||
5028 | } | |||
5029 | for (e = node->callees; e; e = e->next_callee) | |||
5030 | { | |||
5031 | ipa_edge_args *args = ipa_edge_args_sum->get (e); | |||
5032 | ||||
5033 | if (!args) | |||
5034 | { | |||
5035 | streamer_write_uhwi (ob, 0); | |||
5036 | continue; | |||
5037 | } | |||
5038 | ||||
5039 | streamer_write_uhwi (ob, | |||
5040 | ipa_get_cs_argument_count (args) * 2 | |||
5041 | + (args->polymorphic_call_contexts != NULLnullptr)); | |||
5042 | for (j = 0; j < ipa_get_cs_argument_count (args); j++) | |||
5043 | { | |||
5044 | ipa_write_jump_function (ob, ipa_get_ith_jump_func (args, j)); | |||
5045 | if (args->polymorphic_call_contexts != NULLnullptr) | |||
5046 | ipa_get_ith_polymorhic_call_context (args, j)->stream_out (ob); | |||
5047 | } | |||
5048 | } | |||
5049 | for (e = node->indirect_calls; e; e = e->next_callee) | |||
5050 | { | |||
5051 | ipa_edge_args *args = ipa_edge_args_sum->get (e); | |||
5052 | if (!args) | |||
5053 | streamer_write_uhwi (ob, 0); | |||
5054 | else | |||
5055 | { | |||
5056 | streamer_write_uhwi (ob, | |||
5057 | ipa_get_cs_argument_count (args) * 2 | |||
5058 | + (args->polymorphic_call_contexts != NULLnullptr)); | |||
5059 | for (j = 0; j < ipa_get_cs_argument_count (args); j++) | |||
5060 | { | |||
5061 | ipa_write_jump_function (ob, ipa_get_ith_jump_func (args, j)); | |||
5062 | if (args->polymorphic_call_contexts != NULLnullptr) | |||
5063 | ipa_get_ith_polymorhic_call_context (args, j)->stream_out (ob); | |||
5064 | } | |||
5065 | } | |||
5066 | ipa_write_indirect_edge_info (ob, e); | |||
5067 | } | |||
5068 | } | |||
5069 | ||||
5070 | /* Stream in edge E from IB. */ | |||
5071 | ||||
5072 | static void | |||
5073 | ipa_read_edge_info (class lto_input_block *ib, | |||
5074 | class data_in *data_in, | |||
5075 | struct cgraph_edge *e, bool prevails) | |||
5076 | { | |||
5077 | int count = streamer_read_uhwi (ib); | |||
5078 | bool contexts_computed = count & 1; | |||
5079 | ||||
5080 | count /= 2; | |||
5081 | if (!count) | |||
5082 | return; | |||
5083 | if (prevails | |||
5084 | && (e->possibly_call_in_translation_unit_p () | |||
5085 | /* Also stream in jump functions to builtins in hope that they | |||
5086 | will get fnspecs. */ | |||
5087 | || fndecl_built_in_p (e->callee->decl, BUILT_IN_NORMAL))) | |||
5088 | { | |||
5089 | ipa_edge_args *args = ipa_edge_args_sum->get_create (e); | |||
5090 | vec_safe_grow_cleared (args->jump_functions, count, true); | |||
5091 | if (contexts_computed) | |||
5092 | vec_safe_grow_cleared (args->polymorphic_call_contexts, count, true); | |||
5093 | for (int k = 0; k < count; k++) | |||
5094 | { | |||
5095 | ipa_read_jump_function (ib, ipa_get_ith_jump_func (args, k), e, | |||
5096 | data_in, prevails); | |||
5097 | if (contexts_computed) | |||
5098 | ipa_get_ith_polymorhic_call_context (args, k)->stream_in | |||
5099 | (ib, data_in); | |||
5100 | } | |||
5101 | } | |||
5102 | else | |||
5103 | { | |||
5104 | for (int k = 0; k < count; k++) | |||
5105 | { | |||
5106 | struct ipa_jump_func dummy; | |||
5107 | ipa_read_jump_function (ib, &dummy, e, | |||
5108 | data_in, prevails); | |||
5109 | if (contexts_computed) | |||
5110 | { | |||
5111 | class ipa_polymorphic_call_context ctx; | |||
5112 | ctx.stream_in (ib, data_in); | |||
5113 | } | |||
5114 | } | |||
5115 | } | |||
5116 | } | |||
5117 | ||||
5118 | /* Stream in NODE info from IB. */ | |||
5119 | ||||
5120 | static void | |||
5121 | ipa_read_node_info (class lto_input_block *ib, struct cgraph_node *node, | |||
5122 | class data_in *data_in) | |||
5123 | { | |||
5124 | int k; | |||
5125 | struct cgraph_edge *e; | |||
5126 | struct bitpack_d bp; | |||
5127 | bool prevails = node->prevailing_p (); | |||
5128 | ipa_node_params *info | |||
5129 | = prevails ? ipa_node_params_sum->get_create (node) : NULLnullptr; | |||
5130 | ||||
5131 | int param_count = streamer_read_uhwi (ib); | |||
5132 | if (prevails) | |||
5133 | { | |||
5134 | ipa_alloc_node_params (node, param_count); | |||
5135 | for (k = 0; k < param_count; k++) | |||
5136 | (*info->descriptors)[k].move_cost = streamer_read_uhwi (ib); | |||
5137 | if (ipa_get_param_count (info) != 0) | |||
5138 | info->analysis_done = true; | |||
5139 | info->node_enqueued = false; | |||
5140 | } | |||
5141 | else | |||
5142 | for (k = 0; k < param_count; k++) | |||
5143 | streamer_read_uhwi (ib); | |||
5144 | ||||
5145 | bp = streamer_read_bitpack (ib); | |||
5146 | for (k = 0; k < param_count; k++) | |||
5147 | { | |||
5148 | bool load_dereferenced = bp_unpack_value (&bp, 1); | |||
5149 | bool used = bp_unpack_value (&bp, 1); | |||
5150 | ||||
5151 | if (prevails) | |||
5152 | { | |||
5153 | ipa_set_param_load_dereferenced (info, k, load_dereferenced); | |||
5154 | ipa_set_param_used (info, k, used); | |||
5155 | } | |||
5156 | } | |||
5157 | for (k = 0; k < param_count; k++) | |||
5158 | { | |||
5159 | int nuses = streamer_read_hwi (ib); | |||
5160 | tree type = stream_read_tree (ib, data_in)streamer_hooks.read_tree (ib, data_in); | |||
5161 | ||||
5162 | if (prevails) | |||
5163 | { | |||
5164 | ipa_set_controlled_uses (info, k, nuses); | |||
5165 | (*info->descriptors)[k].decl_or_type = type; | |||
5166 | } | |||
5167 | } | |||
5168 | for (e = node->callees; e; e = e->next_callee) | |||
5169 | ipa_read_edge_info (ib, data_in, e, prevails); | |||
5170 | for (e = node->indirect_calls; e; e = e->next_callee) | |||
5171 | { | |||
5172 | ipa_read_edge_info (ib, data_in, e, prevails); | |||
5173 | ipa_read_indirect_edge_info (ib, data_in, e, info); | |||
5174 | } | |||
5175 | } | |||
5176 | ||||
5177 | /* Write jump functions for nodes in SET. */ | |||
5178 | ||||
5179 | void | |||
5180 | ipa_prop_write_jump_functions (void) | |||
5181 | { | |||
5182 | struct output_block *ob; | |||
5183 | unsigned int count = 0; | |||
5184 | lto_symtab_encoder_iterator lsei; | |||
5185 | lto_symtab_encoder_t encoder; | |||
5186 | ||||
5187 | if (!ipa_node_params_sum || !ipa_edge_args_sum) | |||
5188 | return; | |||
5189 | ||||
5190 | ob = create_output_block (LTO_section_jump_functions); | |||
5191 | encoder = ob->decl_state->symtab_node_encoder; | |||
5192 | ob->symbol = NULLnullptr; | |||
5193 | for (lsei = lsei_start_function_in_partition (encoder); !lsei_end_p (lsei); | |||
5194 | lsei_next_function_in_partition (&lsei)) | |||
5195 | { | |||
5196 | cgraph_node *node = lsei_cgraph_node (lsei); | |||
5197 | if (node->has_gimple_body_p () | |||
5198 | && ipa_node_params_sum->get (node) != NULLnullptr) | |||
5199 | count++; | |||
5200 | } | |||
5201 | ||||
5202 | streamer_write_uhwi (ob, count); | |||
5203 | ||||
5204 | /* Process all of the functions. */ | |||
5205 | for (lsei = lsei_start_function_in_partition (encoder); !lsei_end_p (lsei); | |||
5206 | lsei_next_function_in_partition (&lsei)) | |||
5207 | { | |||
5208 | cgraph_node *node = lsei_cgraph_node (lsei); | |||
5209 | if (node->has_gimple_body_p () | |||
5210 | && ipa_node_params_sum->get (node) != NULLnullptr) | |||
5211 | ipa_write_node_info (ob, node); | |||
5212 | } | |||
5213 | streamer_write_char_stream (ob->main_stream, 0); | |||
5214 | produce_asm (ob, NULLnullptr); | |||
5215 | destroy_output_block (ob); | |||
5216 | } | |||
5217 | ||||
5218 | /* Read section in file FILE_DATA of length LEN with data DATA. */ | |||
5219 | ||||
5220 | static void | |||
5221 | ipa_prop_read_section (struct lto_file_decl_data *file_data, const char *data, | |||
5222 | size_t len) | |||
5223 | { | |||
5224 | const struct lto_function_header *header = | |||
5225 | (const struct lto_function_header *) data; | |||
5226 | const int cfg_offset = sizeof (struct lto_function_header); | |||
5227 | const int main_offset = cfg_offset + header->cfg_size; | |||
5228 | const int string_offset = main_offset + header->main_size; | |||
5229 | class data_in *data_in; | |||
5230 | unsigned int i; | |||
5231 | unsigned int count; | |||
5232 | ||||
5233 | lto_input_block ib_main ((const char *) data + main_offset, | |||
5234 | header->main_size, file_data->mode_table); | |||
5235 | ||||
5236 | data_in = | |||
5237 | lto_data_in_create (file_data, (const char *) data + string_offset, | |||
5238 | header->string_size, vNULL); | |||
5239 | count = streamer_read_uhwi (&ib_main); | |||
5240 | ||||
5241 | for (i = 0; i < count; i++) | |||
5242 | { | |||
5243 | unsigned int index; | |||
5244 | struct cgraph_node *node; | |||
5245 | lto_symtab_encoder_t encoder; | |||
5246 | ||||
5247 | index = streamer_read_uhwi (&ib_main); | |||
5248 | encoder = file_data->symtab_node_encoder; | |||
5249 | node = dyn_cast<cgraph_node *> (lto_symtab_encoder_deref (encoder, | |||
5250 | index)); | |||
5251 | gcc_assert (node->definition)((void)(!(node->definition) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 5251, __FUNCTION__), 0 : 0)); | |||
5252 | ipa_read_node_info (&ib_main, node, data_in); | |||
5253 | } | |||
5254 | lto_free_section_data (file_data, LTO_section_jump_functions, NULLnullptr, data, | |||
5255 | len); | |||
5256 | lto_data_in_delete (data_in); | |||
5257 | } | |||
5258 | ||||
5259 | /* Read ipcp jump functions. */ | |||
5260 | ||||
5261 | void | |||
5262 | ipa_prop_read_jump_functions (void) | |||
5263 | { | |||
5264 | struct lto_file_decl_data **file_data_vec = lto_get_file_decl_data (); | |||
5265 | struct lto_file_decl_data *file_data; | |||
5266 | unsigned int j = 0; | |||
5267 | ||||
5268 | ipa_check_create_node_params (); | |||
5269 | ipa_check_create_edge_args (); | |||
5270 | ipa_register_cgraph_hooks (); | |||
5271 | ||||
5272 | while ((file_data = file_data_vec[j++])) | |||
5273 | { | |||
5274 | size_t len; | |||
5275 | const char *data | |||
5276 | = lto_get_summary_section_data (file_data, LTO_section_jump_functions, | |||
5277 | &len); | |||
5278 | if (data) | |||
5279 | ipa_prop_read_section (file_data, data, len); | |||
5280 | } | |||
5281 | } | |||
5282 | ||||
5283 | /* Return true if the IPA-CP transformation summary TS is non-NULL and contains | |||
5284 | useful info. */ | |||
5285 | static bool | |||
5286 | useful_ipcp_transformation_info_p (ipcp_transformation *ts) | |||
5287 | { | |||
5288 | if (!ts) | |||
5289 | return false; | |||
5290 | if (!vec_safe_is_empty (ts->m_agg_values) | |||
5291 | || !vec_safe_is_empty (ts->bits) | |||
5292 | || !vec_safe_is_empty (ts->m_vr)) | |||
5293 | return true; | |||
5294 | return false; | |||
5295 | } | |||
5296 | ||||
5297 | /* Write into OB IPA-CP transfromation summary TS describing NODE. */ | |||
5298 | ||||
5299 | void | |||
5300 | write_ipcp_transformation_info (output_block *ob, cgraph_node *node, | |||
5301 | ipcp_transformation *ts) | |||
5302 | { | |||
5303 | lto_symtab_encoder_t encoder = ob->decl_state->symtab_node_encoder; | |||
5304 | int node_ref = lto_symtab_encoder_encode (encoder, node); | |||
5305 | streamer_write_uhwi (ob, node_ref); | |||
5306 | ||||
5307 | streamer_write_uhwi (ob, vec_safe_length (ts->m_agg_values)); | |||
5308 | for (const ipa_argagg_value &av : ts->m_agg_values) | |||
5309 | { | |||
5310 | struct bitpack_d bp; | |||
5311 | ||||
5312 | stream_write_tree (ob, av.value, true)streamer_hooks.write_tree (ob, av.value, true, true); | |||
5313 | streamer_write_uhwi (ob, av.unit_offset); | |||
5314 | streamer_write_uhwi (ob, av.index); | |||
5315 | ||||
5316 | bp = bitpack_create (ob->main_stream); | |||
5317 | bp_pack_value (&bp, av.by_ref, 1); | |||
5318 | streamer_write_bitpack (&bp); | |||
5319 | } | |||
5320 | ||||
5321 | streamer_write_uhwi (ob, vec_safe_length (ts->m_vr)); | |||
5322 | for (const ipa_vr &parm_vr : ts->m_vr) | |||
5323 | { | |||
5324 | struct bitpack_d bp; | |||
5325 | bp = bitpack_create (ob->main_stream); | |||
5326 | bp_pack_value (&bp, parm_vr.known, 1); | |||
5327 | streamer_write_bitpack (&bp); | |||
5328 | if (parm_vr.known) | |||
5329 | { | |||
5330 | streamer_write_enum (ob->main_stream, value_rang_type,streamer_write_hwi_in_range ((ob->main_stream), 0, (int)(VR_LAST ) - 1, (int)(parm_vr.type)) | |||
5331 | VR_LAST, parm_vr.type)streamer_write_hwi_in_range ((ob->main_stream), 0, (int)(VR_LAST ) - 1, (int)(parm_vr.type)); | |||
5332 | streamer_write_wide_int (ob, parm_vr.min); | |||
5333 | streamer_write_wide_int (ob, parm_vr.max); | |||
5334 | } | |||
5335 | } | |||
5336 | ||||
5337 | streamer_write_uhwi (ob, vec_safe_length (ts->bits)); | |||
5338 | for (const ipa_bits *bits_jfunc : ts->bits) | |||
5339 | { | |||
5340 | struct bitpack_d bp = bitpack_create (ob->main_stream); | |||
5341 | bp_pack_value (&bp, !!bits_jfunc, 1); | |||
5342 | streamer_write_bitpack (&bp); | |||
5343 | if (bits_jfunc) | |||
5344 | { | |||
5345 | streamer_write_widest_int (ob, bits_jfunc->value); | |||
5346 | streamer_write_widest_int (ob, bits_jfunc->mask); | |||
5347 | } | |||
5348 | } | |||
5349 | } | |||
5350 | ||||
5351 | /* Stream in the aggregate value replacement chain for NODE from IB. */ | |||
5352 | ||||
5353 | static void | |||
5354 | read_ipcp_transformation_info (lto_input_block *ib, cgraph_node *node, | |||
5355 | data_in *data_in) | |||
5356 | { | |||
5357 | unsigned int count, i; | |||
5358 | ipcp_transformation_initialize (); | |||
5359 | ipcp_transformation *ts = ipcp_transformation_sum->get_create (node); | |||
5360 | ||||
5361 | count = streamer_read_uhwi (ib); | |||
5362 | if (count > 0) | |||
5363 | { | |||
5364 | vec_safe_grow_cleared (ts->m_agg_values, count, true); | |||
5365 | for (i = 0; i <count; i++) | |||
5366 | { | |||
5367 | ipa_argagg_value *av = &(*ts->m_agg_values)[i];; | |||
5368 | ||||
5369 | av->value = stream_read_tree (ib, data_in)streamer_hooks.read_tree (ib, data_in); | |||
5370 | av->unit_offset = streamer_read_uhwi (ib); | |||
5371 | av->index = streamer_read_uhwi (ib); | |||
5372 | ||||
5373 | bitpack_d bp = streamer_read_bitpack (ib); | |||
5374 | av->by_ref = bp_unpack_value (&bp, 1); | |||
5375 | } | |||
5376 | } | |||
5377 | ||||
5378 | count = streamer_read_uhwi (ib); | |||
5379 | if (count > 0) | |||
5380 | { | |||
5381 | vec_safe_grow_cleared (ts->m_vr, count, true); | |||
5382 | for (i = 0; i < count; i++) | |||
5383 | { | |||
5384 | ipa_vr *parm_vr; | |||
5385 | parm_vr = &(*ts->m_vr)[i]; | |||
5386 | struct bitpack_d bp; | |||
5387 | bp = streamer_read_bitpack (ib); | |||
5388 | parm_vr->known = bp_unpack_value (&bp, 1); | |||
5389 | if (parm_vr->known) | |||
5390 | { | |||
5391 | parm_vr->type = streamer_read_enum (ib, value_range_kind,(enum value_range_kind)streamer_read_hwi_in_range ((ib), "value_range_kind" , 0, (int)(VR_LAST) - 1) | |||
5392 | VR_LAST)(enum value_range_kind)streamer_read_hwi_in_range ((ib), "value_range_kind" , 0, (int)(VR_LAST) - 1); | |||
5393 | parm_vr->min = streamer_read_wide_int (ib); | |||
5394 | parm_vr->max = streamer_read_wide_int (ib); | |||
5395 | } | |||
5396 | } | |||
5397 | } | |||
5398 | count = streamer_read_uhwi (ib); | |||
5399 | if (count > 0) | |||
5400 | { | |||
5401 | vec_safe_grow_cleared (ts->bits, count, true); | |||
5402 | for (i = 0; i < count; i++) | |||
5403 | { | |||
5404 | struct bitpack_d bp = streamer_read_bitpack (ib); | |||
5405 | bool known = bp_unpack_value (&bp, 1); | |||
5406 | if (known) | |||
5407 | { | |||
5408 | const widest_int value = streamer_read_widest_int (ib); | |||
5409 | const widest_int mask = streamer_read_widest_int (ib); | |||
5410 | ipa_bits *bits | |||
5411 | = ipa_get_ipa_bits_for_value (value, mask); | |||
5412 | (*ts->bits)[i] = bits; | |||
5413 | } | |||
5414 | } | |||
5415 | } | |||
5416 | } | |||
5417 | ||||
5418 | /* Write all aggregate replacement for nodes in set. */ | |||
5419 | ||||
5420 | void | |||
5421 | ipcp_write_transformation_summaries (void) | |||
5422 | { | |||
5423 | struct output_block *ob; | |||
5424 | unsigned int count = 0; | |||
5425 | lto_symtab_encoder_t encoder; | |||
5426 | ||||
5427 | ob = create_output_block (LTO_section_ipcp_transform); | |||
5428 | encoder = ob->decl_state->symtab_node_encoder; | |||
5429 | ob->symbol = NULLnullptr; | |||
5430 | ||||
5431 | for (int i = 0; i < lto_symtab_encoder_size (encoder); i++) | |||
5432 | { | |||
5433 | symtab_node *snode = lto_symtab_encoder_deref (encoder, i); | |||
5434 | cgraph_node *cnode = dyn_cast <cgraph_node *> (snode); | |||
5435 | if (!cnode) | |||
5436 | continue; | |||
5437 | ipcp_transformation *ts = ipcp_get_transformation_summary (cnode); | |||
5438 | if (useful_ipcp_transformation_info_p (ts) | |||
5439 | && lto_symtab_encoder_encode_body_p (encoder, cnode)) | |||
5440 | count++; | |||
5441 | } | |||
5442 | ||||
5443 | streamer_write_uhwi (ob, count); | |||
5444 | ||||
5445 | for (int i = 0; i < lto_symtab_encoder_size (encoder); i++) | |||
5446 | { | |||
5447 | symtab_node *snode = lto_symtab_encoder_deref (encoder, i); | |||
5448 | cgraph_node *cnode = dyn_cast <cgraph_node *> (snode); | |||
5449 | if (!cnode) | |||
5450 | continue; | |||
5451 | ipcp_transformation *ts = ipcp_get_transformation_summary (cnode); | |||
5452 | if (useful_ipcp_transformation_info_p (ts) | |||
5453 | && lto_symtab_encoder_encode_body_p (encoder, cnode)) | |||
5454 | write_ipcp_transformation_info (ob, cnode, ts); | |||
5455 | } | |||
5456 | streamer_write_char_stream (ob->main_stream, 0); | |||
5457 | produce_asm (ob, NULLnullptr); | |||
5458 | destroy_output_block (ob); | |||
5459 | } | |||
5460 | ||||
5461 | /* Read replacements section in file FILE_DATA of length LEN with data | |||
5462 | DATA. */ | |||
5463 | ||||
5464 | static void | |||
5465 | read_replacements_section (struct lto_file_decl_data *file_data, | |||
5466 | const char *data, | |||
5467 | size_t len) | |||
5468 | { | |||
5469 | const struct lto_function_header *header = | |||
5470 | (const struct lto_function_header *) data; | |||
5471 | const int cfg_offset = sizeof (struct lto_function_header); | |||
5472 | const int main_offset = cfg_offset + header->cfg_size; | |||
5473 | const int string_offset = main_offset + header->main_size; | |||
5474 | class data_in *data_in; | |||
5475 | unsigned int i; | |||
5476 | unsigned int count; | |||
5477 | ||||
5478 | lto_input_block ib_main ((const char *) data + main_offset, | |||
5479 | header->main_size, file_data->mode_table); | |||
5480 | ||||
5481 | data_in = lto_data_in_create (file_data, (const char *) data + string_offset, | |||
5482 | header->string_size, vNULL); | |||
5483 | count = streamer_read_uhwi (&ib_main); | |||
5484 | ||||
5485 | for (i = 0; i < count; i++) | |||
5486 | { | |||
5487 | unsigned int index; | |||
5488 | struct cgraph_node *node; | |||
5489 | lto_symtab_encoder_t encoder; | |||
5490 | ||||
5491 | index = streamer_read_uhwi (&ib_main); | |||
5492 | encoder = file_data->symtab_node_encoder; | |||
5493 | node = dyn_cast<cgraph_node *> (lto_symtab_encoder_deref (encoder, | |||
5494 | index)); | |||
5495 | read_ipcp_transformation_info (&ib_main, node, data_in); | |||
5496 | } | |||
5497 | lto_free_section_data (file_data, LTO_section_jump_functions, NULLnullptr, data, | |||
5498 | len); | |||
5499 | lto_data_in_delete (data_in); | |||
5500 | } | |||
5501 | ||||
5502 | /* Read IPA-CP aggregate replacements. */ | |||
5503 | ||||
5504 | void | |||
5505 | ipcp_read_transformation_summaries (void) | |||
5506 | { | |||
5507 | struct lto_file_decl_data **file_data_vec = lto_get_file_decl_data (); | |||
5508 | struct lto_file_decl_data *file_data; | |||
5509 | unsigned int j = 0; | |||
5510 | ||||
5511 | while ((file_data = file_data_vec[j++])) | |||
5512 | { | |||
5513 | size_t len; | |||
5514 | const char *data | |||
5515 | = lto_get_summary_section_data (file_data, LTO_section_ipcp_transform, | |||
5516 | &len); | |||
5517 | if (data) | |||
5518 | read_replacements_section (file_data, data, len); | |||
5519 | } | |||
5520 | } | |||
5521 | ||||
5522 | /* Adjust the aggregate replacements in TS to reflect any parameter removals | |||
5523 | which might have already taken place. If after adjustments there are no | |||
5524 | aggregate replacements left, the m_agg_values will be set to NULL. In other | |||
5525 | cases, it may be shrunk. */ | |||
5526 | ||||
5527 | static void | |||
5528 | adjust_agg_replacement_values (cgraph_node *node, ipcp_transformation *ts) | |||
5529 | { | |||
5530 | clone_info *cinfo = clone_info::get (node); | |||
5531 | if (!cinfo || !cinfo->param_adjustments) | |||
5532 | return; | |||
5533 | ||||
5534 | auto_vec<int, 16> new_indices; | |||
5535 | cinfo->param_adjustments->get_updated_indices (&new_indices); | |||
5536 | bool removed_item = false; | |||
5537 | unsigned dst_index = 0; | |||
5538 | unsigned count = ts->m_agg_values->length (); | |||
5539 | for (unsigned i = 0; i < count; i++) | |||
5540 | { | |||
5541 | ipa_argagg_value *v = &(*ts->m_agg_values)[i]; | |||
5542 | gcc_checking_assert (v->index >= 0)((void)(!(v->index >= 0) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 5542, __FUNCTION__), 0 : 0)); | |||
5543 | ||||
5544 | int new_idx = -1; | |||
5545 | if ((unsigned) v->index < new_indices.length ()) | |||
5546 | new_idx = new_indices[v->index]; | |||
5547 | ||||
5548 | if (new_idx >= 0) | |||
5549 | { | |||
5550 | v->index = new_idx; | |||
5551 | if (removed_item) | |||
5552 | (*ts->m_agg_values)[dst_index] = *v; | |||
5553 | dst_index++; | |||
5554 | } | |||
5555 | else | |||
5556 | removed_item = true; | |||
5557 | } | |||
5558 | ||||
5559 | if (dst_index == 0) | |||
5560 | { | |||
5561 | ggc_free (ts->m_agg_values); | |||
5562 | ts->m_agg_values = NULLnullptr; | |||
5563 | } | |||
5564 | else if (removed_item) | |||
5565 | ts->m_agg_values->truncate (dst_index); | |||
5566 | ||||
5567 | return; | |||
5568 | } | |||
5569 | ||||
5570 | /* Dominator walker driving the ipcp modification phase. */ | |||
5571 | ||||
5572 | class ipcp_modif_dom_walker : public dom_walker | |||
5573 | { | |||
5574 | public: | |||
5575 | ipcp_modif_dom_walker (struct ipa_func_body_info *fbi, | |||
5576 | vec<ipa_param_descriptor, va_gc> *descs, | |||
5577 | ipcp_transformation *ts, bool *sc) | |||
5578 | : dom_walker (CDI_DOMINATORS), m_fbi (fbi), m_descriptors (descs), | |||
5579 | m_ts (ts), m_something_changed (sc) {} | |||
5580 | ||||
5581 | edge before_dom_children (basic_block) final override; | |||
5582 | bool cleanup_eh () | |||
5583 | { return gimple_purge_all_dead_eh_edges (m_need_eh_cleanup); } | |||
5584 | ||||
5585 | private: | |||
5586 | struct ipa_func_body_info *m_fbi; | |||
5587 | vec<ipa_param_descriptor, va_gc> *m_descriptors; | |||
5588 | ipcp_transformation *m_ts; | |||
5589 | bool *m_something_changed; | |||
5590 | auto_bitmap m_need_eh_cleanup; | |||
5591 | }; | |||
5592 | ||||
5593 | edge | |||
5594 | ipcp_modif_dom_walker::before_dom_children (basic_block bb) | |||
5595 | { | |||
5596 | gimple_stmt_iterator gsi; | |||
5597 | for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi)) | |||
5598 | { | |||
5599 | gimple *stmt = gsi_stmt (gsi); | |||
5600 | tree rhs, val, t; | |||
5601 | HOST_WIDE_INTlong bit_offset; | |||
5602 | poly_int64 size; | |||
5603 | int index; | |||
5604 | bool by_ref, vce; | |||
5605 | ||||
5606 | if (!gimple_assign_load_p (stmt)) | |||
5607 | continue; | |||
5608 | rhs = gimple_assign_rhs1 (stmt); | |||
5609 | if (!is_gimple_reg_type (TREE_TYPE (rhs)((contains_struct_check ((rhs), (TS_TYPED), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 5609, __FUNCTION__))->typed.type))) | |||
5610 | continue; | |||
5611 | ||||
5612 | vce = false; | |||
5613 | t = rhs; | |||
5614 | while (handled_component_p (t)) | |||
5615 | { | |||
5616 | /* V_C_E can do things like convert an array of integers to one | |||
5617 | bigger integer and similar things we do not handle below. */ | |||
5618 | if (TREE_CODE (t)((enum tree_code) (t)->base.code) == VIEW_CONVERT_EXPR) | |||
5619 | { | |||
5620 | vce = true; | |||
5621 | break; | |||
5622 | } | |||
5623 | t = TREE_OPERAND (t, 0)(*((const_cast<tree*> (tree_operand_check ((t), (0), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 5623, __FUNCTION__))))); | |||
5624 | } | |||
5625 | if (vce) | |||
5626 | continue; | |||
5627 | ||||
5628 | if (!ipa_load_from_parm_agg (m_fbi, m_descriptors, stmt, rhs, &index, | |||
5629 | &bit_offset, &size, &by_ref)) | |||
5630 | continue; | |||
5631 | unsigned unit_offset = bit_offset / BITS_PER_UNIT(8); | |||
5632 | ipa_argagg_value_list avl (m_ts); | |||
5633 | tree v = avl.get_value (index, unit_offset, by_ref); | |||
5634 | ||||
5635 | if (!v | |||
5636 | || maybe_ne (tree_to_poly_int64 (TYPE_SIZE (TREE_TYPE (v))((tree_class_check ((((contains_struct_check ((v), (TS_TYPED) , "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 5636, __FUNCTION__))->typed.type)), (tcc_type), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 5636, __FUNCTION__))->type_common.size)), size)) | |||
5637 | continue; | |||
5638 | ||||
5639 | gcc_checking_assert (is_gimple_ip_invariant (v))((void)(!(is_gimple_ip_invariant (v)) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 5639, __FUNCTION__), 0 : 0)); | |||
5640 | if (!useless_type_conversion_p (TREE_TYPE (rhs)((contains_struct_check ((rhs), (TS_TYPED), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 5640, __FUNCTION__))->typed.type), TREE_TYPE (v)((contains_struct_check ((v), (TS_TYPED), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 5640, __FUNCTION__))->typed.type))) | |||
5641 | { | |||
5642 | if (fold_convertible_p (TREE_TYPE (rhs)((contains_struct_check ((rhs), (TS_TYPED), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 5642, __FUNCTION__))->typed.type), v)) | |||
5643 | val = fold_build1 (NOP_EXPR, TREE_TYPE (rhs), v)fold_build1_loc (((location_t) 0), NOP_EXPR, ((contains_struct_check ((rhs), (TS_TYPED), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 5643, __FUNCTION__))->typed.type), v ); | |||
5644 | else if (TYPE_SIZE (TREE_TYPE (rhs))((tree_class_check ((((contains_struct_check ((rhs), (TS_TYPED ), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 5644, __FUNCTION__))->typed.type)), (tcc_type), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 5644, __FUNCTION__))->type_common.size) | |||
5645 | == TYPE_SIZE (TREE_TYPE (v))((tree_class_check ((((contains_struct_check ((v), (TS_TYPED) , "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 5645, __FUNCTION__))->typed.type)), (tcc_type), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 5645, __FUNCTION__))->type_common.size)) | |||
5646 | val = fold_build1 (VIEW_CONVERT_EXPR, TREE_TYPE (rhs), v)fold_build1_loc (((location_t) 0), VIEW_CONVERT_EXPR, ((contains_struct_check ((rhs), (TS_TYPED), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 5646, __FUNCTION__))->typed.type), v ); | |||
5647 | else | |||
5648 | { | |||
5649 | if (dump_file) | |||
5650 | { | |||
5651 | fprintf (dump_file, " const "); | |||
5652 | print_generic_expr (dump_file, v); | |||
5653 | fprintf (dump_file, " can't be converted to type of "); | |||
5654 | print_generic_expr (dump_file, rhs); | |||
5655 | fprintf (dump_file, "\n"); | |||
5656 | } | |||
5657 | continue; | |||
5658 | } | |||
5659 | } | |||
5660 | else | |||
5661 | val = v; | |||
5662 | ||||
5663 | if (dump_file && (dump_flags & TDF_DETAILS)) | |||
5664 | { | |||
5665 | fprintf (dump_file, "Modifying stmt:\n "); | |||
5666 | print_gimple_stmt (dump_file, stmt, 0); | |||
5667 | } | |||
5668 | gimple_assign_set_rhs_from_tree (&gsi, val); | |||
5669 | update_stmt (stmt); | |||
5670 | ||||
5671 | if (dump_file && (dump_flags & TDF_DETAILS)) | |||
5672 | { | |||
5673 | fprintf (dump_file, "into:\n "); | |||
5674 | print_gimple_stmt (dump_file, stmt, 0); | |||
5675 | fprintf (dump_file, "\n"); | |||
5676 | } | |||
5677 | ||||
5678 | *m_something_changed = true; | |||
5679 | if (maybe_clean_eh_stmt (stmt)) | |||
5680 | bitmap_set_bit (m_need_eh_cleanup, bb->index); | |||
5681 | } | |||
5682 | return NULLnullptr; | |||
5683 | } | |||
5684 | ||||
5685 | /* Return true if we have recorded VALUE and MASK about PARM. | |||
5686 | Set VALUE and MASk accordingly. */ | |||
5687 | ||||
5688 | bool | |||
5689 | ipcp_get_parm_bits (tree parm, tree *value, widest_int *mask) | |||
5690 | { | |||
5691 | cgraph_node *cnode = cgraph_node::get (current_function_decl); | |||
5692 | ipcp_transformation *ts = ipcp_get_transformation_summary (cnode); | |||
5693 | if (!ts || vec_safe_length (ts->bits) == 0) | |||
5694 | return false; | |||
5695 | ||||
5696 | int i = 0; | |||
5697 | for (tree p = DECL_ARGUMENTS (current_function_decl)((tree_check ((current_function_decl), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 5697, __FUNCTION__, (FUNCTION_DECL)))->function_decl.arguments ); | |||
5698 | p != parm; p = DECL_CHAIN (p)(((contains_struct_check (((contains_struct_check ((p), (TS_DECL_MINIMAL ), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 5698, __FUNCTION__))), (TS_COMMON), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 5698, __FUNCTION__))->common.chain))) | |||
5699 | { | |||
5700 | i++; | |||
5701 | /* Ignore static chain. */ | |||
5702 | if (!p) | |||
5703 | return false; | |||
5704 | } | |||
5705 | ||||
5706 | clone_info *cinfo = clone_info::get (cnode); | |||
5707 | if (cinfo && cinfo->param_adjustments) | |||
5708 | { | |||
5709 | i = cinfo->param_adjustments->get_original_index (i); | |||
5710 | if (i < 0) | |||
5711 | return false; | |||
5712 | } | |||
5713 | ||||
5714 | vec<ipa_bits *, va_gc> &bits = *ts->bits; | |||
5715 | if (!bits[i]) | |||
5716 | return false; | |||
5717 | *mask = bits[i]->mask; | |||
5718 | *value = wide_int_to_tree (TREE_TYPE (parm)((contains_struct_check ((parm), (TS_TYPED), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 5718, __FUNCTION__))->typed.type), bits[i]->value); | |||
5719 | return true; | |||
5720 | } | |||
5721 | ||||
5722 | ||||
5723 | /* Update bits info of formal parameters as described in | |||
5724 | ipcp_transformation. */ | |||
5725 | ||||
5726 | static void | |||
5727 | ipcp_update_bits (struct cgraph_node *node) | |||
5728 | { | |||
5729 | ipcp_transformation *ts = ipcp_get_transformation_summary (node); | |||
5730 | ||||
5731 | if (!ts || vec_safe_length (ts->bits) == 0) | |||
5732 | return; | |||
5733 | vec<ipa_bits *, va_gc> &bits = *ts->bits; | |||
5734 | unsigned count = bits.length (); | |||
5735 | if (!count) | |||
5736 | return; | |||
5737 | ||||
5738 | auto_vec<int, 16> new_indices; | |||
5739 | bool need_remapping = false; | |||
5740 | clone_info *cinfo = clone_info::get (node); | |||
5741 | if (cinfo && cinfo->param_adjustments) | |||
5742 | { | |||
5743 | cinfo->param_adjustments->get_updated_indices (&new_indices); | |||
5744 | need_remapping = true; | |||
5745 | } | |||
5746 | auto_vec <tree, 16> parm_decls; | |||
5747 | push_function_arg_decls (&parm_decls, node->decl); | |||
5748 | ||||
5749 | for (unsigned i = 0; i < count; ++i) | |||
5750 | { | |||
5751 | tree parm; | |||
5752 | if (need_remapping) | |||
5753 | { | |||
5754 | if (i >= new_indices.length ()) | |||
5755 | continue; | |||
5756 | int idx = new_indices[i]; | |||
5757 | if (idx < 0) | |||
5758 | continue; | |||
5759 | parm = parm_decls[idx]; | |||
5760 | } | |||
5761 | else | |||
5762 | parm = parm_decls[i]; | |||
5763 | gcc_checking_assert (parm)((void)(!(parm) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 5763, __FUNCTION__), 0 : 0)); | |||
5764 | ||||
5765 | ||||
5766 | if (!bits[i] | |||
5767 | || !(INTEGRAL_TYPE_P (TREE_TYPE (parm))(((enum tree_code) (((contains_struct_check ((parm), (TS_TYPED ), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 5767, __FUNCTION__))->typed.type))->base.code) == ENUMERAL_TYPE || ((enum tree_code) (((contains_struct_check ((parm), (TS_TYPED ), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 5767, __FUNCTION__))->typed.type))->base.code) == BOOLEAN_TYPE || ((enum tree_code) (((contains_struct_check ((parm), (TS_TYPED ), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 5767, __FUNCTION__))->typed.type))->base.code) == INTEGER_TYPE ) | |||
5768 | || POINTER_TYPE_P (TREE_TYPE (parm))(((enum tree_code) (((contains_struct_check ((parm), (TS_TYPED ), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 5768, __FUNCTION__))->typed.type))->base.code) == POINTER_TYPE || ((enum tree_code) (((contains_struct_check ((parm), (TS_TYPED ), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 5768, __FUNCTION__))->typed.type))->base.code) == REFERENCE_TYPE )) | |||
5769 | || !is_gimple_reg (parm)) | |||
5770 | continue; | |||
5771 | ||||
5772 | tree ddef = ssa_default_def (DECL_STRUCT_FUNCTION (node->decl)((tree_check ((node->decl), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 5772, __FUNCTION__, (FUNCTION_DECL)))->function_decl.f), parm); | |||
5773 | if (!ddef) | |||
5774 | continue; | |||
5775 | ||||
5776 | if (dump_file) | |||
5777 | { | |||
5778 | fprintf (dump_file, "Adjusting mask for param %u to ", i); | |||
5779 | print_hex (bits[i]->mask, dump_file); | |||
5780 | fprintf (dump_file, "\n"); | |||
5781 | } | |||
5782 | ||||
5783 | if (INTEGRAL_TYPE_P (TREE_TYPE (ddef))(((enum tree_code) (((contains_struct_check ((ddef), (TS_TYPED ), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 5783, __FUNCTION__))->typed.type))->base.code) == ENUMERAL_TYPE || ((enum tree_code) (((contains_struct_check ((ddef), (TS_TYPED ), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 5783, __FUNCTION__))->typed.type))->base.code) == BOOLEAN_TYPE || ((enum tree_code) (((contains_struct_check ((ddef), (TS_TYPED ), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 5783, __FUNCTION__))->typed.type))->base.code) == INTEGER_TYPE )) | |||
5784 | { | |||
5785 | unsigned prec = TYPE_PRECISION (TREE_TYPE (ddef))((tree_class_check ((((contains_struct_check ((ddef), (TS_TYPED ), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 5785, __FUNCTION__))->typed.type)), (tcc_type), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 5785, __FUNCTION__))->type_common.precision); | |||
5786 | signop sgn = TYPE_SIGN (TREE_TYPE (ddef))((signop) ((tree_class_check ((((contains_struct_check ((ddef ), (TS_TYPED), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 5786, __FUNCTION__))->typed.type)), (tcc_type), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 5786, __FUNCTION__))->base.u.bits.unsigned_flag)); | |||
5787 | ||||
5788 | wide_int nonzero_bits = wide_int::from (bits[i]->mask, prec, UNSIGNED) | |||
5789 | | wide_int::from (bits[i]->value, prec, sgn); | |||
5790 | set_nonzero_bits (ddef, nonzero_bits); | |||
5791 | } | |||
5792 | else | |||
5793 | { | |||
5794 | unsigned tem = bits[i]->mask.to_uhwi (); | |||
5795 | unsigned HOST_WIDE_INTlong bitpos = bits[i]->value.to_uhwi (); | |||
5796 | unsigned align = tem & -tem; | |||
5797 | unsigned misalign = bitpos & (align - 1); | |||
5798 | ||||
5799 | if (align > 1) | |||
5800 | { | |||
5801 | if (dump_file) | |||
5802 | fprintf (dump_file, "Adjusting align: %u, misalign: %u\n", align, misalign); | |||
5803 | ||||
5804 | unsigned old_align, old_misalign; | |||
5805 | struct ptr_info_def *pi = get_ptr_info (ddef); | |||
5806 | bool old_known = get_ptr_info_alignment (pi, &old_align, &old_misalign); | |||
5807 | ||||
5808 | if (old_known | |||
5809 | && old_align > align) | |||
5810 | { | |||
5811 | if (dump_file) | |||
5812 | { | |||
5813 | fprintf (dump_file, "But alignment was already %u.\n", old_align); | |||
5814 | if ((old_misalign & (align - 1)) != misalign) | |||
5815 | fprintf (dump_file, "old_misalign (%u) and misalign (%u) mismatch\n", | |||
5816 | old_misalign, misalign); | |||
5817 | } | |||
5818 | continue; | |||
5819 | } | |||
5820 | ||||
5821 | if (old_known | |||
5822 | && ((misalign & (old_align - 1)) != old_misalign) | |||
5823 | && dump_file) | |||
5824 | fprintf (dump_file, "old_misalign (%u) and misalign (%u) mismatch\n", | |||
5825 | old_misalign, misalign); | |||
5826 | ||||
5827 | set_ptr_info_alignment (pi, align, misalign); | |||
5828 | } | |||
5829 | } | |||
5830 | } | |||
5831 | } | |||
5832 | ||||
5833 | bool | |||
5834 | ipa_vr::nonzero_p (tree expr_type) const | |||
5835 | { | |||
5836 | if (type == VR_ANTI_RANGE && wi::eq_p (min, 0) && wi::eq_p (max, 0)) | |||
5837 | return true; | |||
5838 | ||||
5839 | unsigned prec = TYPE_PRECISION (expr_type)((tree_class_check ((expr_type), (tcc_type), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 5839, __FUNCTION__))->type_common.precision); | |||
5840 | return (type == VR_RANGE | |||
5841 | && TYPE_UNSIGNED (expr_type)((tree_class_check ((expr_type), (tcc_type), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 5841, __FUNCTION__))->base.u.bits.unsigned_flag) | |||
5842 | && wi::eq_p (min, wi::one (prec)) | |||
5843 | && wi::eq_p (max, wi::max_value (prec, TYPE_SIGN (expr_type)((signop) ((tree_class_check ((expr_type), (tcc_type), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 5843, __FUNCTION__))->base.u.bits.unsigned_flag))))); | |||
5844 | } | |||
5845 | ||||
5846 | /* Update value range of formal parameters as described in | |||
5847 | ipcp_transformation. */ | |||
5848 | ||||
5849 | static void | |||
5850 | ipcp_update_vr (struct cgraph_node *node) | |||
5851 | { | |||
5852 | ipcp_transformation *ts = ipcp_get_transformation_summary (node); | |||
5853 | if (!ts || vec_safe_length (ts->m_vr) == 0) | |||
5854 | return; | |||
5855 | const vec<ipa_vr, va_gc> &vr = *ts->m_vr; | |||
5856 | unsigned count = vr.length (); | |||
5857 | if (!count) | |||
5858 | return; | |||
5859 | ||||
5860 | auto_vec<int, 16> new_indices; | |||
5861 | bool need_remapping = false; | |||
5862 | clone_info *cinfo = clone_info::get (node); | |||
5863 | if (cinfo && cinfo->param_adjustments) | |||
5864 | { | |||
5865 | cinfo->param_adjustments->get_updated_indices (&new_indices); | |||
5866 | need_remapping = true; | |||
5867 | } | |||
5868 | auto_vec <tree, 16> parm_decls; | |||
5869 | push_function_arg_decls (&parm_decls, node->decl); | |||
5870 | ||||
5871 | for (unsigned i = 0; i < count; ++i) | |||
5872 | { | |||
5873 | tree parm; | |||
5874 | int remapped_idx; | |||
5875 | if (need_remapping) | |||
5876 | { | |||
5877 | if (i >= new_indices.length ()) | |||
5878 | continue; | |||
5879 | remapped_idx = new_indices[i]; | |||
5880 | if (remapped_idx < 0) | |||
5881 | continue; | |||
5882 | } | |||
5883 | else | |||
5884 | remapped_idx = i; | |||
5885 | ||||
5886 | parm = parm_decls[remapped_idx]; | |||
5887 | ||||
5888 | gcc_checking_assert (parm)((void)(!(parm) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 5888, __FUNCTION__), 0 : 0)); | |||
5889 | tree ddef = ssa_default_def (DECL_STRUCT_FUNCTION (node->decl)((tree_check ((node->decl), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 5889, __FUNCTION__, (FUNCTION_DECL)))->function_decl.f), parm); | |||
5890 | ||||
5891 | if (!ddef || !is_gimple_reg (parm)) | |||
5892 | continue; | |||
5893 | ||||
5894 | if (vr[i].known | |||
5895 | && (vr[i].type == VR_RANGE || vr[i].type == VR_ANTI_RANGE)) | |||
5896 | { | |||
5897 | tree type = TREE_TYPE (ddef)((contains_struct_check ((ddef), (TS_TYPED), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 5897, __FUNCTION__))->typed.type); | |||
5898 | unsigned prec = TYPE_PRECISION (type)((tree_class_check ((type), (tcc_type), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 5898, __FUNCTION__))->type_common.precision); | |||
5899 | if (INTEGRAL_TYPE_P (TREE_TYPE (ddef))(((enum tree_code) (((contains_struct_check ((ddef), (TS_TYPED ), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 5899, __FUNCTION__))->typed.type))->base.code) == ENUMERAL_TYPE || ((enum tree_code) (((contains_struct_check ((ddef), (TS_TYPED ), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 5899, __FUNCTION__))->typed.type))->base.code) == BOOLEAN_TYPE || ((enum tree_code) (((contains_struct_check ((ddef), (TS_TYPED ), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-prop.cc" , 5899, __FUNCTION__))->typed.type))->base.code) == INTEGER_TYPE )) | |||
5900 | { | |||
5901 | if (dump_file) | |||
5902 | { | |||
5903 | fprintf (dump_file, "Setting value range of param %u " | |||
5904 | "(now %i) ", i, remapped_idx |