File: | build/gcc/tree-sra.cc |
Warning: | line 2186, column 3 The left operand of '==' is a garbage value |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | /* Scalar Replacement of Aggregates (SRA) converts some structure | |||
2 | references into scalar references, exposing them to the scalar | |||
3 | optimizers. | |||
4 | Copyright (C) 2008-2023 Free Software Foundation, Inc. | |||
5 | Contributed by Martin Jambor <mjambor@suse.cz> | |||
6 | ||||
7 | This file is part of GCC. | |||
8 | ||||
9 | GCC is free software; you can redistribute it and/or modify it under | |||
10 | the terms of the GNU General Public License as published by the Free | |||
11 | Software Foundation; either version 3, or (at your option) any later | |||
12 | version. | |||
13 | ||||
14 | GCC is distributed in the hope that it will be useful, but WITHOUT ANY | |||
15 | WARRANTY; without even the implied warranty of MERCHANTABILITY or | |||
16 | FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |||
17 | for more details. | |||
18 | ||||
19 | You should have received a copy of the GNU General Public License | |||
20 | along with GCC; see the file COPYING3. If not see | |||
21 | <http://www.gnu.org/licenses/>. */ | |||
22 | ||||
23 | /* This file implements Scalar Reduction of Aggregates (SRA). SRA is run | |||
24 | twice, once in the early stages of compilation (early SRA) and once in the | |||
25 | late stages (late SRA). The aim of both is to turn references to scalar | |||
26 | parts of aggregates into uses of independent scalar variables. | |||
27 | ||||
28 | The two passes are nearly identical, the only difference is that early SRA | |||
29 | does not scalarize unions which are used as the result in a GIMPLE_RETURN | |||
30 | statement because together with inlining this can lead to weird type | |||
31 | conversions. | |||
32 | ||||
33 | Both passes operate in four stages: | |||
34 | ||||
35 | 1. The declarations that have properties which make them candidates for | |||
36 | scalarization are identified in function find_var_candidates(). The | |||
37 | candidates are stored in candidate_bitmap. | |||
38 | ||||
39 | 2. The function body is scanned. In the process, declarations which are | |||
40 | used in a manner that prevent their scalarization are removed from the | |||
41 | candidate bitmap. More importantly, for every access into an aggregate, | |||
42 | an access structure (struct access) is created by create_access() and | |||
43 | stored in a vector associated with the aggregate. Among other | |||
44 | information, the aggregate declaration, the offset and size of the access | |||
45 | and its type are stored in the structure. | |||
46 | ||||
47 | On a related note, assign_link structures are created for every assign | |||
48 | statement between candidate aggregates and attached to the related | |||
49 | accesses. | |||
50 | ||||
51 | 3. The vectors of accesses are analyzed. They are first sorted according to | |||
52 | their offset and size and then scanned for partially overlapping accesses | |||
53 | (i.e. those which overlap but one is not entirely within another). Such | |||
54 | an access disqualifies the whole aggregate from being scalarized. | |||
55 | ||||
56 | If there is no such inhibiting overlap, a representative access structure | |||
57 | is chosen for every unique combination of offset and size. Afterwards, | |||
58 | the pass builds a set of trees from these structures, in which children | |||
59 | of an access are within their parent (in terms of offset and size). | |||
60 | ||||
61 | Then accesses are propagated whenever possible (i.e. in cases when it | |||
62 | does not create a partially overlapping access) across assign_links from | |||
63 | the right hand side to the left hand side. | |||
64 | ||||
65 | Then the set of trees for each declaration is traversed again and those | |||
66 | accesses which should be replaced by a scalar are identified. | |||
67 | ||||
68 | 4. The function is traversed again, and for every reference into an | |||
69 | aggregate that has some component which is about to be scalarized, | |||
70 | statements are amended and new statements are created as necessary. | |||
71 | Finally, if a parameter got scalarized, the scalar replacements are | |||
72 | initialized with values from respective parameter aggregates. */ | |||
73 | ||||
74 | #include "config.h" | |||
75 | #include "system.h" | |||
76 | #include "coretypes.h" | |||
77 | #include "backend.h" | |||
78 | #include "target.h" | |||
79 | #include "rtl.h" | |||
80 | #include "tree.h" | |||
81 | #include "gimple.h" | |||
82 | #include "predict.h" | |||
83 | #include "alloc-pool.h" | |||
84 | #include "tree-pass.h" | |||
85 | #include "ssa.h" | |||
86 | #include "cgraph.h" | |||
87 | #include "gimple-pretty-print.h" | |||
88 | #include "alias.h" | |||
89 | #include "fold-const.h" | |||
90 | #include "tree-eh.h" | |||
91 | #include "stor-layout.h" | |||
92 | #include "gimplify.h" | |||
93 | #include "gimple-iterator.h" | |||
94 | #include "gimplify-me.h" | |||
95 | #include "gimple-walk.h" | |||
96 | #include "tree-cfg.h" | |||
97 | #include "tree-dfa.h" | |||
98 | #include "tree-ssa.h" | |||
99 | #include "dbgcnt.h" | |||
100 | #include "builtins.h" | |||
101 | #include "tree-sra.h" | |||
102 | #include "opts.h" | |||
103 | ||||
104 | /* Enumeration of all aggregate reductions we can do. */ | |||
105 | enum sra_mode { SRA_MODE_EARLY_IPA, /* early call regularization */ | |||
106 | SRA_MODE_EARLY_INTRA, /* early intraprocedural SRA */ | |||
107 | SRA_MODE_INTRA }; /* late intraprocedural SRA */ | |||
108 | ||||
109 | /* Global variable describing which aggregate reduction we are performing at | |||
110 | the moment. */ | |||
111 | static enum sra_mode sra_mode; | |||
112 | ||||
113 | struct assign_link; | |||
114 | ||||
115 | /* ACCESS represents each access to an aggregate variable (as a whole or a | |||
116 | part). It can also represent a group of accesses that refer to exactly the | |||
117 | same fragment of an aggregate (i.e. those that have exactly the same offset | |||
118 | and size). Such representatives for a single aggregate, once determined, | |||
119 | are linked in a linked list and have the group fields set. | |||
120 | ||||
121 | Moreover, when doing intraprocedural SRA, a tree is built from those | |||
122 | representatives (by the means of first_child and next_sibling pointers), in | |||
123 | which all items in a subtree are "within" the root, i.e. their offset is | |||
124 | greater or equal to offset of the root and offset+size is smaller or equal | |||
125 | to offset+size of the root. Children of an access are sorted by offset. | |||
126 | ||||
127 | Note that accesses to parts of vector and complex number types always | |||
128 | represented by an access to the whole complex number or a vector. It is a | |||
129 | duty of the modifying functions to replace them appropriately. */ | |||
130 | ||||
131 | struct access | |||
132 | { | |||
133 | /* Values returned by `get_ref_base_and_extent' for each component reference | |||
134 | If EXPR isn't a component reference just set `BASE = EXPR', `OFFSET = 0', | |||
135 | `SIZE = TREE_SIZE (TREE_TYPE (expr))'. */ | |||
136 | HOST_WIDE_INTlong offset; | |||
137 | HOST_WIDE_INTlong size; | |||
138 | tree base; | |||
139 | ||||
140 | /* Expression. It is context dependent so do not use it to create new | |||
141 | expressions to access the original aggregate. See PR 42154 for a | |||
142 | testcase. */ | |||
143 | tree expr; | |||
144 | /* Type. */ | |||
145 | tree type; | |||
146 | ||||
147 | /* The statement this access belongs to. */ | |||
148 | gimple *stmt; | |||
149 | ||||
150 | /* Next group representative for this aggregate. */ | |||
151 | struct access *next_grp; | |||
152 | ||||
153 | /* Pointer to the group representative. Pointer to itself if the struct is | |||
154 | the representative. */ | |||
155 | struct access *group_representative; | |||
156 | ||||
157 | /* After access tree has been constructed, this points to the parent of the | |||
158 | current access, if there is one. NULL for roots. */ | |||
159 | struct access *parent; | |||
160 | ||||
161 | /* If this access has any children (in terms of the definition above), this | |||
162 | points to the first one. */ | |||
163 | struct access *first_child; | |||
164 | ||||
165 | /* In intraprocedural SRA, pointer to the next sibling in the access tree as | |||
166 | described above. */ | |||
167 | struct access *next_sibling; | |||
168 | ||||
169 | /* Pointers to the first and last element in the linked list of assign | |||
170 | links for propagation from LHS to RHS. */ | |||
171 | struct assign_link *first_rhs_link, *last_rhs_link; | |||
172 | ||||
173 | /* Pointers to the first and last element in the linked list of assign | |||
174 | links for propagation from LHS to RHS. */ | |||
175 | struct assign_link *first_lhs_link, *last_lhs_link; | |||
176 | ||||
177 | /* Pointer to the next access in the work queues. */ | |||
178 | struct access *next_rhs_queued, *next_lhs_queued; | |||
179 | ||||
180 | /* Replacement variable for this access "region." Never to be accessed | |||
181 | directly, always only by the means of get_access_replacement() and only | |||
182 | when grp_to_be_replaced flag is set. */ | |||
183 | tree replacement_decl; | |||
184 | ||||
185 | /* Is this access made in reverse storage order? */ | |||
186 | unsigned reverse : 1; | |||
187 | ||||
188 | /* Is this particular access write access? */ | |||
189 | unsigned write : 1; | |||
190 | ||||
191 | /* Is this access currently in the rhs work queue? */ | |||
192 | unsigned grp_rhs_queued : 1; | |||
193 | ||||
194 | /* Is this access currently in the lhs work queue? */ | |||
195 | unsigned grp_lhs_queued : 1; | |||
196 | ||||
197 | /* Does this group contain a write access? This flag is propagated down the | |||
198 | access tree. */ | |||
199 | unsigned grp_write : 1; | |||
200 | ||||
201 | /* Does this group contain a read access? This flag is propagated down the | |||
202 | access tree. */ | |||
203 | unsigned grp_read : 1; | |||
204 | ||||
205 | /* Does this group contain a read access that comes from an assignment | |||
206 | statement? This flag is propagated down the access tree. */ | |||
207 | unsigned grp_assignment_read : 1; | |||
208 | ||||
209 | /* Does this group contain a write access that comes from an assignment | |||
210 | statement? This flag is propagated down the access tree. */ | |||
211 | unsigned grp_assignment_write : 1; | |||
212 | ||||
213 | /* Does this group contain a read access through a scalar type? This flag is | |||
214 | not propagated in the access tree in any direction. */ | |||
215 | unsigned grp_scalar_read : 1; | |||
216 | ||||
217 | /* Does this group contain a write access through a scalar type? This flag | |||
218 | is not propagated in the access tree in any direction. */ | |||
219 | unsigned grp_scalar_write : 1; | |||
220 | ||||
221 | /* In a root of an access tree, true means that the entire tree should be | |||
222 | totally scalarized - that all scalar leafs should be scalarized and | |||
223 | non-root grp_total_scalarization accesses should be honored. Otherwise, | |||
224 | non-root accesses with grp_total_scalarization should never get scalar | |||
225 | replacements. */ | |||
226 | unsigned grp_total_scalarization : 1; | |||
227 | ||||
228 | /* Other passes of the analysis use this bit to make function | |||
229 | analyze_access_subtree create scalar replacements for this group if | |||
230 | possible. */ | |||
231 | unsigned grp_hint : 1; | |||
232 | ||||
233 | /* Is the subtree rooted in this access fully covered by scalar | |||
234 | replacements? */ | |||
235 | unsigned grp_covered : 1; | |||
236 | ||||
237 | /* If set to true, this access and all below it in an access tree must not be | |||
238 | scalarized. */ | |||
239 | unsigned grp_unscalarizable_region : 1; | |||
240 | ||||
241 | /* Whether data have been written to parts of the aggregate covered by this | |||
242 | access which is not to be scalarized. This flag is propagated up in the | |||
243 | access tree. */ | |||
244 | unsigned grp_unscalarized_data : 1; | |||
245 | ||||
246 | /* Set if all accesses in the group consist of the same chain of | |||
247 | COMPONENT_REFs and ARRAY_REFs. */ | |||
248 | unsigned grp_same_access_path : 1; | |||
249 | ||||
250 | /* Does this access and/or group contain a write access through a | |||
251 | BIT_FIELD_REF? */ | |||
252 | unsigned grp_partial_lhs : 1; | |||
253 | ||||
254 | /* Set when a scalar replacement should be created for this variable. */ | |||
255 | unsigned grp_to_be_replaced : 1; | |||
256 | ||||
257 | /* Set when we want a replacement for the sole purpose of having it in | |||
258 | generated debug statements. */ | |||
259 | unsigned grp_to_be_debug_replaced : 1; | |||
260 | ||||
261 | /* Should TREE_NO_WARNING of a replacement be set? */ | |||
262 | unsigned grp_no_warning : 1; | |||
263 | ||||
264 | /* Result of propagation accross link from LHS to RHS. */ | |||
265 | unsigned grp_result_of_prop_from_lhs : 1; | |||
266 | }; | |||
267 | ||||
268 | typedef struct access *access_p; | |||
269 | ||||
270 | ||||
271 | /* Alloc pool for allocating access structures. */ | |||
272 | static object_allocator<struct access> access_pool ("SRA accesses"); | |||
273 | ||||
274 | /* A structure linking lhs and rhs accesses from an aggregate assignment. They | |||
275 | are used to propagate subaccesses from rhs to lhs and vice versa as long as | |||
276 | they don't conflict with what is already there. In the RHS->LHS direction, | |||
277 | we also propagate grp_write flag to lazily mark that the access contains any | |||
278 | meaningful data. */ | |||
279 | struct assign_link | |||
280 | { | |||
281 | struct access *lacc, *racc; | |||
282 | struct assign_link *next_rhs, *next_lhs; | |||
283 | }; | |||
284 | ||||
285 | /* Alloc pool for allocating assign link structures. */ | |||
286 | static object_allocator<assign_link> assign_link_pool ("SRA links"); | |||
287 | ||||
288 | /* Base (tree) -> Vector (vec<access_p> *) map. */ | |||
289 | static hash_map<tree, auto_vec<access_p> > *base_access_vec; | |||
290 | ||||
291 | /* Hash to limit creation of artificial accesses */ | |||
292 | static hash_map<tree, unsigned> *propagation_budget; | |||
293 | ||||
294 | /* Candidate hash table helpers. */ | |||
295 | ||||
296 | struct uid_decl_hasher : nofree_ptr_hash <tree_node> | |||
297 | { | |||
298 | static inline hashval_t hash (const tree_node *); | |||
299 | static inline bool equal (const tree_node *, const tree_node *); | |||
300 | }; | |||
301 | ||||
302 | /* Hash a tree in a uid_decl_map. */ | |||
303 | ||||
304 | inline hashval_t | |||
305 | uid_decl_hasher::hash (const tree_node *item) | |||
306 | { | |||
307 | return item->decl_minimal.uid; | |||
308 | } | |||
309 | ||||
310 | /* Return true if the DECL_UID in both trees are equal. */ | |||
311 | ||||
312 | inline bool | |||
313 | uid_decl_hasher::equal (const tree_node *a, const tree_node *b) | |||
314 | { | |||
315 | return (a->decl_minimal.uid == b->decl_minimal.uid); | |||
316 | } | |||
317 | ||||
318 | /* Set of candidates. */ | |||
319 | static bitmap candidate_bitmap; | |||
320 | static hash_table<uid_decl_hasher> *candidates; | |||
321 | ||||
322 | /* For a candidate UID return the candidates decl. */ | |||
323 | ||||
324 | static inline tree | |||
325 | candidate (unsigned uid) | |||
326 | { | |||
327 | tree_node t; | |||
328 | t.decl_minimal.uid = uid; | |||
329 | return candidates->find_with_hash (&t, static_cast <hashval_t> (uid)); | |||
330 | } | |||
331 | ||||
332 | /* Bitmap of candidates which we should try to entirely scalarize away and | |||
333 | those which cannot be (because they are and need be used as a whole). */ | |||
334 | static bitmap should_scalarize_away_bitmap, cannot_scalarize_away_bitmap; | |||
335 | ||||
336 | /* Bitmap of candidates in the constant pool, which cannot be scalarized | |||
337 | because this would produce non-constant expressions (e.g. Ada). */ | |||
338 | static bitmap disqualified_constants; | |||
339 | ||||
340 | /* Obstack for creation of fancy names. */ | |||
341 | static struct obstack name_obstack; | |||
342 | ||||
343 | /* Head of a linked list of accesses that need to have its subaccesses | |||
344 | propagated to their assignment counterparts. */ | |||
345 | static struct access *rhs_work_queue_head, *lhs_work_queue_head; | |||
346 | ||||
347 | /* Dump contents of ACCESS to file F in a human friendly way. If GRP is true, | |||
348 | representative fields are dumped, otherwise those which only describe the | |||
349 | individual access are. */ | |||
350 | ||||
351 | static struct | |||
352 | { | |||
353 | /* Number of processed aggregates is readily available in | |||
354 | analyze_all_variable_accesses and so is not stored here. */ | |||
355 | ||||
356 | /* Number of created scalar replacements. */ | |||
357 | int replacements; | |||
358 | ||||
359 | /* Number of times sra_modify_expr or sra_modify_assign themselves changed an | |||
360 | expression. */ | |||
361 | int exprs; | |||
362 | ||||
363 | /* Number of statements created by generate_subtree_copies. */ | |||
364 | int subtree_copies; | |||
365 | ||||
366 | /* Number of statements created by load_assign_lhs_subreplacements. */ | |||
367 | int subreplacements; | |||
368 | ||||
369 | /* Number of times sra_modify_assign has deleted a statement. */ | |||
370 | int deleted; | |||
371 | ||||
372 | /* Number of times sra_modify_assign has to deal with subaccesses of LHS and | |||
373 | RHS reparately due to type conversions or nonexistent matching | |||
374 | references. */ | |||
375 | int separate_lhs_rhs_handling; | |||
376 | ||||
377 | /* Number of parameters that were removed because they were unused. */ | |||
378 | int deleted_unused_parameters; | |||
379 | ||||
380 | /* Number of scalars passed as parameters by reference that have been | |||
381 | converted to be passed by value. */ | |||
382 | int scalar_by_ref_to_by_val; | |||
383 | ||||
384 | /* Number of aggregate parameters that were replaced by one or more of their | |||
385 | components. */ | |||
386 | int aggregate_params_reduced; | |||
387 | ||||
388 | /* Numbber of components created when splitting aggregate parameters. */ | |||
389 | int param_reductions_created; | |||
390 | ||||
391 | /* Number of deferred_init calls that are modified. */ | |||
392 | int deferred_init; | |||
393 | ||||
394 | /* Number of deferred_init calls that are created by | |||
395 | generate_subtree_deferred_init. */ | |||
396 | int subtree_deferred_init; | |||
397 | } sra_stats; | |||
398 | ||||
399 | static void | |||
400 | dump_access (FILE *f, struct access *access, bool grp) | |||
401 | { | |||
402 | fprintf (f, "access { "); | |||
403 | fprintf (f, "base = (%d)'", DECL_UID (access->base)((contains_struct_check ((access->base), (TS_DECL_MINIMAL) , "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 403, __FUNCTION__))->decl_minimal.uid)); | |||
404 | print_generic_expr (f, access->base); | |||
405 | fprintf (f, "', offset = " HOST_WIDE_INT_PRINT_DEC"%" "l" "d", access->offset); | |||
406 | fprintf (f, ", size = " HOST_WIDE_INT_PRINT_DEC"%" "l" "d", access->size); | |||
407 | fprintf (f, ", expr = "); | |||
408 | print_generic_expr (f, access->expr); | |||
409 | fprintf (f, ", type = "); | |||
410 | print_generic_expr (f, access->type); | |||
411 | fprintf (f, ", reverse = %d", access->reverse); | |||
412 | if (grp) | |||
413 | fprintf (f, ", grp_read = %d, grp_write = %d, grp_assignment_read = %d, " | |||
414 | "grp_assignment_write = %d, grp_scalar_read = %d, " | |||
415 | "grp_scalar_write = %d, grp_total_scalarization = %d, " | |||
416 | "grp_hint = %d, grp_covered = %d, " | |||
417 | "grp_unscalarizable_region = %d, grp_unscalarized_data = %d, " | |||
418 | "grp_same_access_path = %d, grp_partial_lhs = %d, " | |||
419 | "grp_to_be_replaced = %d, grp_to_be_debug_replaced = %d}\n", | |||
420 | access->grp_read, access->grp_write, access->grp_assignment_read, | |||
421 | access->grp_assignment_write, access->grp_scalar_read, | |||
422 | access->grp_scalar_write, access->grp_total_scalarization, | |||
423 | access->grp_hint, access->grp_covered, | |||
424 | access->grp_unscalarizable_region, access->grp_unscalarized_data, | |||
425 | access->grp_same_access_path, access->grp_partial_lhs, | |||
426 | access->grp_to_be_replaced, access->grp_to_be_debug_replaced); | |||
427 | else | |||
428 | fprintf (f, ", write = %d, grp_total_scalarization = %d, " | |||
429 | "grp_partial_lhs = %d}\n", | |||
430 | access->write, access->grp_total_scalarization, | |||
431 | access->grp_partial_lhs); | |||
432 | } | |||
433 | ||||
434 | /* Dump a subtree rooted in ACCESS to file F, indent by LEVEL. */ | |||
435 | ||||
436 | static void | |||
437 | dump_access_tree_1 (FILE *f, struct access *access, int level) | |||
438 | { | |||
439 | do | |||
440 | { | |||
441 | int i; | |||
442 | ||||
443 | for (i = 0; i < level; i++) | |||
444 | fputs ("* ", f); | |||
445 | ||||
446 | dump_access (f, access, true); | |||
447 | ||||
448 | if (access->first_child) | |||
449 | dump_access_tree_1 (f, access->first_child, level + 1); | |||
450 | ||||
451 | access = access->next_sibling; | |||
452 | } | |||
453 | while (access); | |||
454 | } | |||
455 | ||||
456 | /* Dump all access trees for a variable, given the pointer to the first root in | |||
457 | ACCESS. */ | |||
458 | ||||
459 | static void | |||
460 | dump_access_tree (FILE *f, struct access *access) | |||
461 | { | |||
462 | for (; access; access = access->next_grp) | |||
463 | dump_access_tree_1 (f, access, 0); | |||
464 | } | |||
465 | ||||
466 | /* Return true iff ACC is non-NULL and has subaccesses. */ | |||
467 | ||||
468 | static inline bool | |||
469 | access_has_children_p (struct access *acc) | |||
470 | { | |||
471 | return acc && acc->first_child; | |||
472 | } | |||
473 | ||||
474 | /* Return true iff ACC is (partly) covered by at least one replacement. */ | |||
475 | ||||
476 | static bool | |||
477 | access_has_replacements_p (struct access *acc) | |||
478 | { | |||
479 | struct access *child; | |||
480 | if (acc->grp_to_be_replaced) | |||
481 | return true; | |||
482 | for (child = acc->first_child; child; child = child->next_sibling) | |||
483 | if (access_has_replacements_p (child)) | |||
484 | return true; | |||
485 | return false; | |||
486 | } | |||
487 | ||||
488 | /* Return a vector of pointers to accesses for the variable given in BASE or | |||
489 | NULL if there is none. */ | |||
490 | ||||
491 | static vec<access_p> * | |||
492 | get_base_access_vector (tree base) | |||
493 | { | |||
494 | return base_access_vec->get (base); | |||
495 | } | |||
496 | ||||
497 | /* Find an access with required OFFSET and SIZE in a subtree of accesses rooted | |||
498 | in ACCESS. Return NULL if it cannot be found. */ | |||
499 | ||||
500 | static struct access * | |||
501 | find_access_in_subtree (struct access *access, HOST_WIDE_INTlong offset, | |||
502 | HOST_WIDE_INTlong size) | |||
503 | { | |||
504 | while (access && (access->offset != offset || access->size != size)) | |||
505 | { | |||
506 | struct access *child = access->first_child; | |||
507 | ||||
508 | while (child && (child->offset + child->size <= offset)) | |||
509 | child = child->next_sibling; | |||
510 | access = child; | |||
511 | } | |||
512 | ||||
513 | /* Total scalarization does not replace single field structures with their | |||
514 | single field but rather creates an access for them underneath. Look for | |||
515 | it. */ | |||
516 | if (access) | |||
517 | while (access->first_child | |||
518 | && access->first_child->offset == offset | |||
519 | && access->first_child->size == size) | |||
520 | access = access->first_child; | |||
521 | ||||
522 | return access; | |||
523 | } | |||
524 | ||||
525 | /* Return the first group representative for DECL or NULL if none exists. */ | |||
526 | ||||
527 | static struct access * | |||
528 | get_first_repr_for_decl (tree base) | |||
529 | { | |||
530 | vec<access_p> *access_vec; | |||
531 | ||||
532 | access_vec = get_base_access_vector (base); | |||
533 | if (!access_vec) | |||
534 | return NULLnullptr; | |||
535 | ||||
536 | return (*access_vec)[0]; | |||
537 | } | |||
538 | ||||
539 | /* Find an access representative for the variable BASE and given OFFSET and | |||
540 | SIZE. Requires that access trees have already been built. Return NULL if | |||
541 | it cannot be found. */ | |||
542 | ||||
543 | static struct access * | |||
544 | get_var_base_offset_size_access (tree base, HOST_WIDE_INTlong offset, | |||
545 | HOST_WIDE_INTlong size) | |||
546 | { | |||
547 | struct access *access; | |||
548 | ||||
549 | access = get_first_repr_for_decl (base); | |||
550 | while (access && (access->offset + access->size <= offset)) | |||
551 | access = access->next_grp; | |||
552 | if (!access) | |||
553 | return NULLnullptr; | |||
554 | ||||
555 | return find_access_in_subtree (access, offset, size); | |||
556 | } | |||
557 | ||||
558 | /* Add LINK to the linked list of assign links of RACC. */ | |||
559 | ||||
560 | static void | |||
561 | add_link_to_rhs (struct access *racc, struct assign_link *link) | |||
562 | { | |||
563 | gcc_assert (link->racc == racc)((void)(!(link->racc == racc) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 563, __FUNCTION__), 0 : 0)); | |||
564 | ||||
565 | if (!racc->first_rhs_link) | |||
566 | { | |||
567 | gcc_assert (!racc->last_rhs_link)((void)(!(!racc->last_rhs_link) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 567, __FUNCTION__), 0 : 0)); | |||
568 | racc->first_rhs_link = link; | |||
569 | } | |||
570 | else | |||
571 | racc->last_rhs_link->next_rhs = link; | |||
572 | ||||
573 | racc->last_rhs_link = link; | |||
574 | link->next_rhs = NULLnullptr; | |||
575 | } | |||
576 | ||||
577 | /* Add LINK to the linked list of lhs assign links of LACC. */ | |||
578 | ||||
579 | static void | |||
580 | add_link_to_lhs (struct access *lacc, struct assign_link *link) | |||
581 | { | |||
582 | gcc_assert (link->lacc == lacc)((void)(!(link->lacc == lacc) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 582, __FUNCTION__), 0 : 0)); | |||
583 | ||||
584 | if (!lacc->first_lhs_link) | |||
585 | { | |||
586 | gcc_assert (!lacc->last_lhs_link)((void)(!(!lacc->last_lhs_link) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 586, __FUNCTION__), 0 : 0)); | |||
587 | lacc->first_lhs_link = link; | |||
588 | } | |||
589 | else | |||
590 | lacc->last_lhs_link->next_lhs = link; | |||
591 | ||||
592 | lacc->last_lhs_link = link; | |||
593 | link->next_lhs = NULLnullptr; | |||
594 | } | |||
595 | ||||
596 | /* Move all link structures in their linked list in OLD_ACC to the linked list | |||
597 | in NEW_ACC. */ | |||
598 | static void | |||
599 | relink_to_new_repr (struct access *new_acc, struct access *old_acc) | |||
600 | { | |||
601 | if (old_acc->first_rhs_link) | |||
602 | { | |||
603 | ||||
604 | if (new_acc->first_rhs_link) | |||
605 | { | |||
606 | gcc_assert (!new_acc->last_rhs_link->next_rhs)((void)(!(!new_acc->last_rhs_link->next_rhs) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 606, __FUNCTION__), 0 : 0)); | |||
607 | gcc_assert (!old_acc->last_rhs_link((void)(!(!old_acc->last_rhs_link || !old_acc->last_rhs_link ->next_rhs) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 608, __FUNCTION__), 0 : 0)) | |||
608 | || !old_acc->last_rhs_link->next_rhs)((void)(!(!old_acc->last_rhs_link || !old_acc->last_rhs_link ->next_rhs) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 608, __FUNCTION__), 0 : 0)); | |||
609 | ||||
610 | new_acc->last_rhs_link->next_rhs = old_acc->first_rhs_link; | |||
611 | new_acc->last_rhs_link = old_acc->last_rhs_link; | |||
612 | } | |||
613 | else | |||
614 | { | |||
615 | gcc_assert (!new_acc->last_rhs_link)((void)(!(!new_acc->last_rhs_link) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 615, __FUNCTION__), 0 : 0)); | |||
616 | ||||
617 | new_acc->first_rhs_link = old_acc->first_rhs_link; | |||
618 | new_acc->last_rhs_link = old_acc->last_rhs_link; | |||
619 | } | |||
620 | old_acc->first_rhs_link = old_acc->last_rhs_link = NULLnullptr; | |||
621 | } | |||
622 | else | |||
623 | gcc_assert (!old_acc->last_rhs_link)((void)(!(!old_acc->last_rhs_link) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 623, __FUNCTION__), 0 : 0)); | |||
624 | ||||
625 | if (old_acc->first_lhs_link) | |||
626 | { | |||
627 | ||||
628 | if (new_acc->first_lhs_link) | |||
629 | { | |||
630 | gcc_assert (!new_acc->last_lhs_link->next_lhs)((void)(!(!new_acc->last_lhs_link->next_lhs) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 630, __FUNCTION__), 0 : 0)); | |||
631 | gcc_assert (!old_acc->last_lhs_link((void)(!(!old_acc->last_lhs_link || !old_acc->last_lhs_link ->next_lhs) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 632, __FUNCTION__), 0 : 0)) | |||
632 | || !old_acc->last_lhs_link->next_lhs)((void)(!(!old_acc->last_lhs_link || !old_acc->last_lhs_link ->next_lhs) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 632, __FUNCTION__), 0 : 0)); | |||
633 | ||||
634 | new_acc->last_lhs_link->next_lhs = old_acc->first_lhs_link; | |||
635 | new_acc->last_lhs_link = old_acc->last_lhs_link; | |||
636 | } | |||
637 | else | |||
638 | { | |||
639 | gcc_assert (!new_acc->last_lhs_link)((void)(!(!new_acc->last_lhs_link) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 639, __FUNCTION__), 0 : 0)); | |||
640 | ||||
641 | new_acc->first_lhs_link = old_acc->first_lhs_link; | |||
642 | new_acc->last_lhs_link = old_acc->last_lhs_link; | |||
643 | } | |||
644 | old_acc->first_lhs_link = old_acc->last_lhs_link = NULLnullptr; | |||
645 | } | |||
646 | else | |||
647 | gcc_assert (!old_acc->last_lhs_link)((void)(!(!old_acc->last_lhs_link) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 647, __FUNCTION__), 0 : 0)); | |||
648 | ||||
649 | } | |||
650 | ||||
651 | /* Add ACCESS to the work to queue for propagation of subaccesses from RHS to | |||
652 | LHS (which is actually a stack). */ | |||
653 | ||||
654 | static void | |||
655 | add_access_to_rhs_work_queue (struct access *access) | |||
656 | { | |||
657 | if (access->first_rhs_link && !access->grp_rhs_queued) | |||
658 | { | |||
659 | gcc_assert (!access->next_rhs_queued)((void)(!(!access->next_rhs_queued) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 659, __FUNCTION__), 0 : 0)); | |||
660 | access->next_rhs_queued = rhs_work_queue_head; | |||
661 | access->grp_rhs_queued = 1; | |||
662 | rhs_work_queue_head = access; | |||
663 | } | |||
664 | } | |||
665 | ||||
666 | /* Add ACCESS to the work to queue for propagation of subaccesses from LHS to | |||
667 | RHS (which is actually a stack). */ | |||
668 | ||||
669 | static void | |||
670 | add_access_to_lhs_work_queue (struct access *access) | |||
671 | { | |||
672 | if (access->first_lhs_link && !access->grp_lhs_queued) | |||
673 | { | |||
674 | gcc_assert (!access->next_lhs_queued)((void)(!(!access->next_lhs_queued) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 674, __FUNCTION__), 0 : 0)); | |||
675 | access->next_lhs_queued = lhs_work_queue_head; | |||
676 | access->grp_lhs_queued = 1; | |||
677 | lhs_work_queue_head = access; | |||
678 | } | |||
679 | } | |||
680 | ||||
681 | /* Pop an access from the work queue for propagating from RHS to LHS, and | |||
682 | return it, assuming there is one. */ | |||
683 | ||||
684 | static struct access * | |||
685 | pop_access_from_rhs_work_queue (void) | |||
686 | { | |||
687 | struct access *access = rhs_work_queue_head; | |||
688 | ||||
689 | rhs_work_queue_head = access->next_rhs_queued; | |||
690 | access->next_rhs_queued = NULLnullptr; | |||
691 | access->grp_rhs_queued = 0; | |||
692 | return access; | |||
693 | } | |||
694 | ||||
695 | /* Pop an access from the work queue for propagating from LHS to RHS, and | |||
696 | return it, assuming there is one. */ | |||
697 | ||||
698 | static struct access * | |||
699 | pop_access_from_lhs_work_queue (void) | |||
700 | { | |||
701 | struct access *access = lhs_work_queue_head; | |||
702 | ||||
703 | lhs_work_queue_head = access->next_lhs_queued; | |||
704 | access->next_lhs_queued = NULLnullptr; | |||
705 | access->grp_lhs_queued = 0; | |||
706 | return access; | |||
707 | } | |||
708 | ||||
709 | /* Allocate necessary structures. */ | |||
710 | ||||
711 | static void | |||
712 | sra_initialize (void) | |||
713 | { | |||
714 | candidate_bitmap = BITMAP_ALLOCbitmap_alloc (NULLnullptr); | |||
715 | candidates = new hash_table<uid_decl_hasher> | |||
716 | (vec_safe_length (cfun(cfun + 0)->local_decls) / 2); | |||
717 | should_scalarize_away_bitmap = BITMAP_ALLOCbitmap_alloc (NULLnullptr); | |||
718 | cannot_scalarize_away_bitmap = BITMAP_ALLOCbitmap_alloc (NULLnullptr); | |||
719 | disqualified_constants = BITMAP_ALLOCbitmap_alloc (NULLnullptr); | |||
720 | gcc_obstack_init (&name_obstack)_obstack_begin (((&name_obstack)), (memory_block_pool::block_size ), (0), (mempool_obstack_chunk_alloc), (mempool_obstack_chunk_free )); | |||
721 | base_access_vec = new hash_map<tree, auto_vec<access_p> >; | |||
722 | memset (&sra_stats, 0, sizeof (sra_stats)); | |||
723 | } | |||
724 | ||||
725 | /* Deallocate all general structures. */ | |||
726 | ||||
727 | static void | |||
728 | sra_deinitialize (void) | |||
729 | { | |||
730 | BITMAP_FREE (candidate_bitmap)((void) (bitmap_obstack_free ((bitmap) candidate_bitmap), (candidate_bitmap ) = (bitmap) nullptr)); | |||
731 | delete candidates; | |||
732 | candidates = NULLnullptr; | |||
733 | BITMAP_FREE (should_scalarize_away_bitmap)((void) (bitmap_obstack_free ((bitmap) should_scalarize_away_bitmap ), (should_scalarize_away_bitmap) = (bitmap) nullptr)); | |||
734 | BITMAP_FREE (cannot_scalarize_away_bitmap)((void) (bitmap_obstack_free ((bitmap) cannot_scalarize_away_bitmap ), (cannot_scalarize_away_bitmap) = (bitmap) nullptr)); | |||
735 | BITMAP_FREE (disqualified_constants)((void) (bitmap_obstack_free ((bitmap) disqualified_constants ), (disqualified_constants) = (bitmap) nullptr)); | |||
736 | access_pool.release (); | |||
737 | assign_link_pool.release (); | |||
738 | obstack_free (&name_obstack, NULL)__extension__ ({ struct obstack *__o = (&name_obstack); void *__obj = (void *) (nullptr); if (__obj > (void *) __o-> chunk && __obj < (void *) __o->chunk_limit) __o ->next_free = __o->object_base = (char *) __obj; else _obstack_free (__o, __obj); }); | |||
739 | ||||
740 | delete base_access_vec; | |||
741 | } | |||
742 | ||||
743 | /* Return true if DECL is a VAR_DECL in the constant pool, false otherwise. */ | |||
744 | ||||
745 | static bool constant_decl_p (tree decl) | |||
746 | { | |||
747 | return VAR_P (decl)(((enum tree_code) (decl)->base.code) == VAR_DECL) && DECL_IN_CONSTANT_POOL (decl)((tree_check ((decl), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 747, __FUNCTION__, (VAR_DECL)))->decl_with_vis.in_constant_pool ); | |||
748 | } | |||
749 | ||||
750 | /* Remove DECL from candidates for SRA and write REASON to the dump file if | |||
751 | there is one. */ | |||
752 | ||||
753 | static void | |||
754 | disqualify_candidate (tree decl, const char *reason) | |||
755 | { | |||
756 | if (bitmap_clear_bit (candidate_bitmap, DECL_UID (decl)((contains_struct_check ((decl), (TS_DECL_MINIMAL), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 756, __FUNCTION__))->decl_minimal.uid))) | |||
757 | candidates->remove_elt_with_hash (decl, DECL_UID (decl)((contains_struct_check ((decl), (TS_DECL_MINIMAL), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 757, __FUNCTION__))->decl_minimal.uid)); | |||
758 | if (constant_decl_p (decl)) | |||
759 | bitmap_set_bit (disqualified_constants, DECL_UID (decl)((contains_struct_check ((decl), (TS_DECL_MINIMAL), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 759, __FUNCTION__))->decl_minimal.uid)); | |||
760 | ||||
761 | if (dump_file && (dump_flags & TDF_DETAILS)) | |||
762 | { | |||
763 | fprintf (dump_file, "! Disqualifying "); | |||
764 | print_generic_expr (dump_file, decl); | |||
765 | fprintf (dump_file, " - %s\n", reason); | |||
766 | } | |||
767 | } | |||
768 | ||||
769 | /* Return true iff the type contains a field or an element which does not allow | |||
770 | scalarization. Use VISITED_TYPES to avoid re-checking already checked | |||
771 | (sub-)types. */ | |||
772 | ||||
773 | static bool | |||
774 | type_internals_preclude_sra_p_1 (tree type, const char **msg, | |||
775 | hash_set<tree> *visited_types) | |||
776 | { | |||
777 | tree fld; | |||
778 | tree et; | |||
779 | ||||
780 | if (visited_types->contains (type)) | |||
781 | return false; | |||
782 | visited_types->add (type); | |||
783 | ||||
784 | switch (TREE_CODE (type)((enum tree_code) (type)->base.code)) | |||
785 | { | |||
786 | case RECORD_TYPE: | |||
787 | case UNION_TYPE: | |||
788 | case QUAL_UNION_TYPE: | |||
789 | for (fld = TYPE_FIELDS (type)((tree_check3 ((type), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 789, __FUNCTION__, (RECORD_TYPE), (UNION_TYPE), (QUAL_UNION_TYPE )))->type_non_common.values); fld; fld = DECL_CHAIN (fld)(((contains_struct_check (((contains_struct_check ((fld), (TS_DECL_MINIMAL ), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 789, __FUNCTION__))), (TS_COMMON), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 789, __FUNCTION__))->common.chain))) | |||
790 | if (TREE_CODE (fld)((enum tree_code) (fld)->base.code) == FIELD_DECL) | |||
791 | { | |||
792 | if (TREE_CODE (fld)((enum tree_code) (fld)->base.code) == FUNCTION_DECL) | |||
793 | continue; | |||
794 | tree ft = TREE_TYPE (fld)((contains_struct_check ((fld), (TS_TYPED), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 794, __FUNCTION__))->typed.type); | |||
795 | ||||
796 | if (TREE_THIS_VOLATILE (fld)((fld)->base.volatile_flag)) | |||
797 | { | |||
798 | *msg = "volatile structure field"; | |||
799 | return true; | |||
800 | } | |||
801 | if (!DECL_FIELD_OFFSET (fld)((tree_check ((fld), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 801, __FUNCTION__, (FIELD_DECL)))->field_decl.offset)) | |||
802 | { | |||
803 | *msg = "no structure field offset"; | |||
804 | return true; | |||
805 | } | |||
806 | if (!DECL_SIZE (fld)((contains_struct_check ((fld), (TS_DECL_COMMON), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 806, __FUNCTION__))->decl_common.size)) | |||
807 | { | |||
808 | *msg = "zero structure field size"; | |||
809 | return true; | |||
810 | } | |||
811 | if (!tree_fits_uhwi_p (DECL_FIELD_OFFSET (fld)((tree_check ((fld), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 811, __FUNCTION__, (FIELD_DECL)))->field_decl.offset))) | |||
812 | { | |||
813 | *msg = "structure field offset not fixed"; | |||
814 | return true; | |||
815 | } | |||
816 | if (!tree_fits_uhwi_p (DECL_SIZE (fld)((contains_struct_check ((fld), (TS_DECL_COMMON), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 816, __FUNCTION__))->decl_common.size))) | |||
817 | { | |||
818 | *msg = "structure field size not fixed"; | |||
819 | return true; | |||
820 | } | |||
821 | if (!tree_fits_shwi_p (bit_position (fld))) | |||
822 | { | |||
823 | *msg = "structure field size too big"; | |||
824 | return true; | |||
825 | } | |||
826 | if (AGGREGATE_TYPE_P (ft)(((enum tree_code) (ft)->base.code) == ARRAY_TYPE || (((enum tree_code) (ft)->base.code) == RECORD_TYPE || ((enum tree_code ) (ft)->base.code) == UNION_TYPE || ((enum tree_code) (ft) ->base.code) == QUAL_UNION_TYPE)) | |||
827 | && int_bit_position (fld) % BITS_PER_UNIT(8) != 0) | |||
828 | { | |||
829 | *msg = "structure field is bit field"; | |||
830 | return true; | |||
831 | } | |||
832 | ||||
833 | if (AGGREGATE_TYPE_P (ft)(((enum tree_code) (ft)->base.code) == ARRAY_TYPE || (((enum tree_code) (ft)->base.code) == RECORD_TYPE || ((enum tree_code ) (ft)->base.code) == UNION_TYPE || ((enum tree_code) (ft) ->base.code) == QUAL_UNION_TYPE)) | |||
834 | && type_internals_preclude_sra_p_1 (ft, msg, visited_types)) | |||
835 | return true; | |||
836 | } | |||
837 | ||||
838 | return false; | |||
839 | ||||
840 | case ARRAY_TYPE: | |||
841 | et = TREE_TYPE (type)((contains_struct_check ((type), (TS_TYPED), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 841, __FUNCTION__))->typed.type); | |||
842 | ||||
843 | if (TYPE_VOLATILE (et)((tree_class_check ((et), (tcc_type), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 843, __FUNCTION__))->base.volatile_flag)) | |||
844 | { | |||
845 | *msg = "element type is volatile"; | |||
846 | return true; | |||
847 | } | |||
848 | ||||
849 | if (AGGREGATE_TYPE_P (et)(((enum tree_code) (et)->base.code) == ARRAY_TYPE || (((enum tree_code) (et)->base.code) == RECORD_TYPE || ((enum tree_code ) (et)->base.code) == UNION_TYPE || ((enum tree_code) (et) ->base.code) == QUAL_UNION_TYPE)) | |||
850 | && type_internals_preclude_sra_p_1 (et, msg, visited_types)) | |||
851 | return true; | |||
852 | ||||
853 | return false; | |||
854 | ||||
855 | default: | |||
856 | return false; | |||
857 | } | |||
858 | } | |||
859 | ||||
860 | /* Return true iff the type contains a field or an element which does not allow | |||
861 | scalarization. */ | |||
862 | ||||
863 | bool | |||
864 | type_internals_preclude_sra_p (tree type, const char **msg) | |||
865 | { | |||
866 | hash_set<tree> visited_types; | |||
867 | return type_internals_preclude_sra_p_1 (type, msg, &visited_types); | |||
868 | } | |||
869 | ||||
870 | ||||
871 | /* Allocate an access structure for BASE, OFFSET and SIZE, clear it, fill in | |||
872 | the three fields. Also add it to the vector of accesses corresponding to | |||
873 | the base. Finally, return the new access. */ | |||
874 | ||||
875 | static struct access * | |||
876 | create_access_1 (tree base, HOST_WIDE_INTlong offset, HOST_WIDE_INTlong size) | |||
877 | { | |||
878 | struct access *access = access_pool.allocate (); | |||
879 | ||||
880 | memset (access, 0, sizeof (struct access)); | |||
881 | access->base = base; | |||
882 | access->offset = offset; | |||
883 | access->size = size; | |||
884 | ||||
885 | base_access_vec->get_or_insert (base).safe_push (access); | |||
886 | ||||
887 | return access; | |||
888 | } | |||
889 | ||||
890 | static bool maybe_add_sra_candidate (tree); | |||
891 | ||||
892 | /* Create and insert access for EXPR. Return created access, or NULL if it is | |||
893 | not possible. Also scan for uses of constant pool as we go along and add | |||
894 | to candidates. */ | |||
895 | ||||
896 | static struct access * | |||
897 | create_access (tree expr, gimple *stmt, bool write) | |||
898 | { | |||
899 | struct access *access; | |||
900 | poly_int64 poffset, psize, pmax_size; | |||
901 | tree base = expr; | |||
902 | bool reverse, unscalarizable_region = false; | |||
903 | ||||
904 | base = get_ref_base_and_extent (expr, &poffset, &psize, &pmax_size, | |||
905 | &reverse); | |||
906 | ||||
907 | /* For constant-pool entries, check we can substitute the constant value. */ | |||
908 | if (constant_decl_p (base)) | |||
909 | { | |||
910 | gcc_assert (!bitmap_bit_p (disqualified_constants, DECL_UID (base)))((void)(!(!bitmap_bit_p (disqualified_constants, ((contains_struct_check ((base), (TS_DECL_MINIMAL), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 910, __FUNCTION__))->decl_minimal.uid))) ? fancy_abort ( "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 910, __FUNCTION__), 0 : 0)); | |||
911 | if (expr != base | |||
912 | && !is_gimple_reg_type (TREE_TYPE (expr)((contains_struct_check ((expr), (TS_TYPED), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 912, __FUNCTION__))->typed.type)) | |||
913 | && dump_file && (dump_flags & TDF_DETAILS)) | |||
914 | { | |||
915 | /* This occurs in Ada with accesses to ARRAY_RANGE_REFs, | |||
916 | and elements of multidimensional arrays (which are | |||
917 | multi-element arrays in their own right). */ | |||
918 | fprintf (dump_file, "Allowing non-reg-type load of part" | |||
919 | " of constant-pool entry: "); | |||
920 | print_generic_expr (dump_file, expr); | |||
921 | } | |||
922 | maybe_add_sra_candidate (base); | |||
923 | } | |||
924 | ||||
925 | if (!DECL_P (base)(tree_code_type_tmpl <0>::tree_code_type[(int) (((enum tree_code ) (base)->base.code))] == tcc_declaration) || !bitmap_bit_p (candidate_bitmap, DECL_UID (base)((contains_struct_check ((base), (TS_DECL_MINIMAL), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 925, __FUNCTION__))->decl_minimal.uid))) | |||
926 | return NULLnullptr; | |||
927 | ||||
928 | if (write && TREE_READONLY (base)((non_type_check ((base), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 928, __FUNCTION__))->base.readonly_flag)) | |||
929 | { | |||
930 | disqualify_candidate (base, "Encountered a store to a read-only decl."); | |||
931 | return NULLnullptr; | |||
932 | } | |||
933 | ||||
934 | HOST_WIDE_INTlong offset, size, max_size; | |||
935 | if (!poffset.is_constant (&offset) | |||
936 | || !psize.is_constant (&size) | |||
937 | || !pmax_size.is_constant (&max_size)) | |||
938 | { | |||
939 | disqualify_candidate (base, "Encountered a polynomial-sized access."); | |||
940 | return NULLnullptr; | |||
941 | } | |||
942 | ||||
943 | if (size != max_size) | |||
944 | { | |||
945 | size = max_size; | |||
946 | unscalarizable_region = true; | |||
947 | } | |||
948 | if (size == 0) | |||
949 | return NULLnullptr; | |||
950 | if (offset < 0) | |||
951 | { | |||
952 | disqualify_candidate (base, "Encountered a negative offset access."); | |||
953 | return NULLnullptr; | |||
954 | } | |||
955 | if (size < 0) | |||
956 | { | |||
957 | disqualify_candidate (base, "Encountered an unconstrained access."); | |||
958 | return NULLnullptr; | |||
959 | } | |||
960 | if (offset + size > tree_to_shwi (DECL_SIZE (base)((contains_struct_check ((base), (TS_DECL_COMMON), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 960, __FUNCTION__))->decl_common.size))) | |||
961 | { | |||
962 | disqualify_candidate (base, "Encountered an access beyond the base."); | |||
963 | return NULLnullptr; | |||
964 | } | |||
965 | ||||
966 | access = create_access_1 (base, offset, size); | |||
967 | access->expr = expr; | |||
968 | access->type = TREE_TYPE (expr)((contains_struct_check ((expr), (TS_TYPED), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 968, __FUNCTION__))->typed.type); | |||
969 | access->write = write; | |||
970 | access->grp_unscalarizable_region = unscalarizable_region; | |||
971 | access->stmt = stmt; | |||
972 | access->reverse = reverse; | |||
973 | ||||
974 | return access; | |||
975 | } | |||
976 | ||||
977 | ||||
978 | /* Return true iff TYPE is scalarizable - i.e. a RECORD_TYPE or fixed-length | |||
979 | ARRAY_TYPE with fields that are either of gimple register types (excluding | |||
980 | bit-fields) or (recursively) scalarizable types. CONST_DECL must be true if | |||
981 | we are considering a decl from constant pool. If it is false, char arrays | |||
982 | will be refused. */ | |||
983 | ||||
984 | static bool | |||
985 | scalarizable_type_p (tree type, bool const_decl) | |||
986 | { | |||
987 | if (is_gimple_reg_type (type)) | |||
988 | return true; | |||
989 | if (type_contains_placeholder_p (type)) | |||
990 | return false; | |||
991 | ||||
992 | bool have_predecessor_field = false; | |||
993 | HOST_WIDE_INTlong prev_pos = 0; | |||
994 | ||||
995 | switch (TREE_CODE (type)((enum tree_code) (type)->base.code)) | |||
996 | { | |||
997 | case RECORD_TYPE: | |||
998 | for (tree fld = TYPE_FIELDS (type)((tree_check3 ((type), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 998, __FUNCTION__, (RECORD_TYPE), (UNION_TYPE), (QUAL_UNION_TYPE )))->type_non_common.values); fld; fld = DECL_CHAIN (fld)(((contains_struct_check (((contains_struct_check ((fld), (TS_DECL_MINIMAL ), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 998, __FUNCTION__))), (TS_COMMON), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 998, __FUNCTION__))->common.chain))) | |||
999 | if (TREE_CODE (fld)((enum tree_code) (fld)->base.code) == FIELD_DECL) | |||
1000 | { | |||
1001 | tree ft = TREE_TYPE (fld)((contains_struct_check ((fld), (TS_TYPED), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 1001, __FUNCTION__))->typed.type); | |||
1002 | ||||
1003 | if (zerop (DECL_SIZE (fld)((contains_struct_check ((fld), (TS_DECL_COMMON), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 1003, __FUNCTION__))->decl_common.size))) | |||
1004 | continue; | |||
1005 | ||||
1006 | HOST_WIDE_INTlong pos = int_bit_position (fld); | |||
1007 | if (have_predecessor_field | |||
1008 | && pos <= prev_pos) | |||
1009 | return false; | |||
1010 | ||||
1011 | have_predecessor_field = true; | |||
1012 | prev_pos = pos; | |||
1013 | ||||
1014 | if (DECL_BIT_FIELD (fld)((tree_check ((fld), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 1014, __FUNCTION__, (FIELD_DECL)))->decl_common.decl_flag_1 )) | |||
1015 | return false; | |||
1016 | ||||
1017 | if (!scalarizable_type_p (ft, const_decl)) | |||
1018 | return false; | |||
1019 | } | |||
1020 | ||||
1021 | return true; | |||
1022 | ||||
1023 | case ARRAY_TYPE: | |||
1024 | { | |||
1025 | HOST_WIDE_INTlong min_elem_size; | |||
1026 | if (const_decl) | |||
1027 | min_elem_size = 0; | |||
1028 | else | |||
1029 | min_elem_size = BITS_PER_UNIT(8); | |||
1030 | ||||
1031 | if (TYPE_DOMAIN (type)((tree_check ((type), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 1031, __FUNCTION__, (ARRAY_TYPE)))->type_non_common.values ) == NULL_TREE(tree) nullptr | |||
1032 | || !tree_fits_shwi_p (TYPE_SIZE (type)((tree_class_check ((type), (tcc_type), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 1032, __FUNCTION__))->type_common.size)) | |||
1033 | || !tree_fits_shwi_p (TYPE_SIZE (TREE_TYPE (type))((tree_class_check ((((contains_struct_check ((type), (TS_TYPED ), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 1033, __FUNCTION__))->typed.type)), (tcc_type), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 1033, __FUNCTION__))->type_common.size)) | |||
1034 | || (tree_to_shwi (TYPE_SIZE (TREE_TYPE (type))((tree_class_check ((((contains_struct_check ((type), (TS_TYPED ), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 1034, __FUNCTION__))->typed.type)), (tcc_type), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 1034, __FUNCTION__))->type_common.size)) <= min_elem_size) | |||
1035 | || !tree_fits_shwi_p (TYPE_MIN_VALUE (TYPE_DOMAIN (type))((tree_check5 ((((tree_check ((type), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 1035, __FUNCTION__, (ARRAY_TYPE)))->type_non_common.values )), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 1035, __FUNCTION__, (INTEGER_TYPE), (ENUMERAL_TYPE), (BOOLEAN_TYPE ), (REAL_TYPE), (FIXED_POINT_TYPE)))->type_non_common.minval ))) | |||
1036 | return false; | |||
1037 | if (tree_to_shwi (TYPE_SIZE (type)((tree_class_check ((type), (tcc_type), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 1037, __FUNCTION__))->type_common.size)) == 0 | |||
1038 | && TYPE_MAX_VALUE (TYPE_DOMAIN (type))((tree_check5 ((((tree_check ((type), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 1038, __FUNCTION__, (ARRAY_TYPE)))->type_non_common.values )), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 1038, __FUNCTION__, (INTEGER_TYPE), (ENUMERAL_TYPE), (BOOLEAN_TYPE ), (REAL_TYPE), (FIXED_POINT_TYPE)))->type_non_common.maxval ) == NULL_TREE(tree) nullptr) | |||
1039 | /* Zero-element array, should not prevent scalarization. */ | |||
1040 | ; | |||
1041 | else if ((tree_to_shwi (TYPE_SIZE (type)((tree_class_check ((type), (tcc_type), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 1041, __FUNCTION__))->type_common.size)) <= 0) | |||
1042 | || !tree_fits_shwi_p (TYPE_MAX_VALUE (TYPE_DOMAIN (type))((tree_check5 ((((tree_check ((type), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 1042, __FUNCTION__, (ARRAY_TYPE)))->type_non_common.values )), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 1042, __FUNCTION__, (INTEGER_TYPE), (ENUMERAL_TYPE), (BOOLEAN_TYPE ), (REAL_TYPE), (FIXED_POINT_TYPE)))->type_non_common.maxval ))) | |||
1043 | /* Variable-length array, do not allow scalarization. */ | |||
1044 | return false; | |||
1045 | ||||
1046 | tree elem = TREE_TYPE (type)((contains_struct_check ((type), (TS_TYPED), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 1046, __FUNCTION__))->typed.type); | |||
1047 | if (!scalarizable_type_p (elem, const_decl)) | |||
1048 | return false; | |||
1049 | return true; | |||
1050 | } | |||
1051 | default: | |||
1052 | return false; | |||
1053 | } | |||
1054 | } | |||
1055 | ||||
1056 | /* Return true if REF has an VIEW_CONVERT_EXPR somewhere in it. */ | |||
1057 | ||||
1058 | static inline bool | |||
1059 | contains_view_convert_expr_p (const_tree ref) | |||
1060 | { | |||
1061 | while (handled_component_p (ref)) | |||
1062 | { | |||
1063 | if (TREE_CODE (ref)((enum tree_code) (ref)->base.code) == VIEW_CONVERT_EXPR) | |||
1064 | return true; | |||
1065 | ref = TREE_OPERAND (ref, 0)(*((const_cast<tree*> (tree_operand_check ((ref), (0), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 1065, __FUNCTION__))))); | |||
1066 | } | |||
1067 | ||||
1068 | return false; | |||
1069 | } | |||
1070 | ||||
1071 | /* Return true if REF contains a VIEW_CONVERT_EXPR or a COMPONENT_REF with a | |||
1072 | bit-field field declaration. If TYPE_CHANGING_P is non-NULL, set the bool | |||
1073 | it points to will be set if REF contains any of the above or a MEM_REF | |||
1074 | expression that effectively performs type conversion. */ | |||
1075 | ||||
1076 | static bool | |||
1077 | contains_vce_or_bfcref_p (const_tree ref, bool *type_changing_p = NULLnullptr) | |||
1078 | { | |||
1079 | while (handled_component_p (ref)) | |||
1080 | { | |||
1081 | if (TREE_CODE (ref)((enum tree_code) (ref)->base.code) == VIEW_CONVERT_EXPR | |||
1082 | || (TREE_CODE (ref)((enum tree_code) (ref)->base.code) == COMPONENT_REF | |||
1083 | && DECL_BIT_FIELD (TREE_OPERAND (ref, 1))((tree_check (((*((const_cast<tree*> (tree_operand_check ((ref), (1), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 1083, __FUNCTION__)))))), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 1083, __FUNCTION__, (FIELD_DECL)))->decl_common.decl_flag_1 ))) | |||
1084 | { | |||
1085 | if (type_changing_p) | |||
1086 | *type_changing_p = true; | |||
1087 | return true; | |||
1088 | } | |||
1089 | ref = TREE_OPERAND (ref, 0)(*((const_cast<tree*> (tree_operand_check ((ref), (0), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 1089, __FUNCTION__))))); | |||
1090 | } | |||
1091 | ||||
1092 | if (!type_changing_p | |||
1093 | || TREE_CODE (ref)((enum tree_code) (ref)->base.code) != MEM_REF | |||
1094 | || TREE_CODE (TREE_OPERAND (ref, 0))((enum tree_code) ((*((const_cast<tree*> (tree_operand_check ((ref), (0), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 1094, __FUNCTION__))))))->base.code) != ADDR_EXPR) | |||
1095 | return false; | |||
1096 | ||||
1097 | tree mem = TREE_OPERAND (TREE_OPERAND (ref, 0), 0)(*((const_cast<tree*> (tree_operand_check (((*((const_cast <tree*> (tree_operand_check ((ref), (0), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 1097, __FUNCTION__)))))), (0), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 1097, __FUNCTION__))))); | |||
1098 | if (TYPE_MAIN_VARIANT (TREE_TYPE (ref))((tree_class_check ((((contains_struct_check ((ref), (TS_TYPED ), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 1098, __FUNCTION__))->typed.type)), (tcc_type), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 1098, __FUNCTION__))->type_common.main_variant) | |||
1099 | != TYPE_MAIN_VARIANT (TREE_TYPE (mem))((tree_class_check ((((contains_struct_check ((mem), (TS_TYPED ), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 1099, __FUNCTION__))->typed.type)), (tcc_type), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 1099, __FUNCTION__))->type_common.main_variant)) | |||
1100 | *type_changing_p = true; | |||
1101 | ||||
1102 | return false; | |||
1103 | } | |||
1104 | ||||
1105 | /* Search the given tree for a declaration by skipping handled components and | |||
1106 | exclude it from the candidates. */ | |||
1107 | ||||
1108 | static void | |||
1109 | disqualify_base_of_expr (tree t, const char *reason) | |||
1110 | { | |||
1111 | t = get_base_address (t); | |||
1112 | if (t && DECL_P (t)(tree_code_type_tmpl <0>::tree_code_type[(int) (((enum tree_code ) (t)->base.code))] == tcc_declaration)) | |||
1113 | disqualify_candidate (t, reason); | |||
1114 | } | |||
1115 | ||||
1116 | /* Scan expression EXPR and create access structures for all accesses to | |||
1117 | candidates for scalarization. Return the created access or NULL if none is | |||
1118 | created. */ | |||
1119 | ||||
1120 | static struct access * | |||
1121 | build_access_from_expr_1 (tree expr, gimple *stmt, bool write) | |||
1122 | { | |||
1123 | struct access *ret = NULLnullptr; | |||
1124 | bool partial_ref; | |||
1125 | ||||
1126 | if (TREE_CODE (expr)((enum tree_code) (expr)->base.code) == BIT_FIELD_REF | |||
1127 | || TREE_CODE (expr)((enum tree_code) (expr)->base.code) == IMAGPART_EXPR | |||
1128 | || TREE_CODE (expr)((enum tree_code) (expr)->base.code) == REALPART_EXPR) | |||
1129 | { | |||
1130 | expr = TREE_OPERAND (expr, 0)(*((const_cast<tree*> (tree_operand_check ((expr), (0), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 1130, __FUNCTION__))))); | |||
1131 | partial_ref = true; | |||
1132 | } | |||
1133 | else | |||
1134 | partial_ref = false; | |||
1135 | ||||
1136 | if (storage_order_barrier_p (expr)) | |||
1137 | { | |||
1138 | disqualify_base_of_expr (expr, "storage order barrier."); | |||
1139 | return NULLnullptr; | |||
1140 | } | |||
1141 | ||||
1142 | /* We need to dive through V_C_Es in order to get the size of its parameter | |||
1143 | and not the result type. Ada produces such statements. We are also | |||
1144 | capable of handling the topmost V_C_E but not any of those buried in other | |||
1145 | handled components. */ | |||
1146 | if (TREE_CODE (expr)((enum tree_code) (expr)->base.code) == VIEW_CONVERT_EXPR) | |||
1147 | expr = TREE_OPERAND (expr, 0)(*((const_cast<tree*> (tree_operand_check ((expr), (0), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 1147, __FUNCTION__))))); | |||
1148 | ||||
1149 | if (contains_view_convert_expr_p (expr)) | |||
1150 | { | |||
1151 | disqualify_base_of_expr (expr, "V_C_E under a different handled " | |||
1152 | "component."); | |||
1153 | return NULLnullptr; | |||
1154 | } | |||
1155 | if (TREE_THIS_VOLATILE (expr)((expr)->base.volatile_flag)) | |||
1156 | { | |||
1157 | disqualify_base_of_expr (expr, "part of a volatile reference."); | |||
1158 | return NULLnullptr; | |||
1159 | } | |||
1160 | ||||
1161 | switch (TREE_CODE (expr)((enum tree_code) (expr)->base.code)) | |||
1162 | { | |||
1163 | case MEM_REF: | |||
1164 | if (TREE_CODE (TREE_OPERAND (expr, 0))((enum tree_code) ((*((const_cast<tree*> (tree_operand_check ((expr), (0), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 1164, __FUNCTION__))))))->base.code) != ADDR_EXPR) | |||
1165 | return NULLnullptr; | |||
1166 | /* fall through */ | |||
1167 | case VAR_DECL: | |||
1168 | case PARM_DECL: | |||
1169 | case RESULT_DECL: | |||
1170 | case COMPONENT_REF: | |||
1171 | case ARRAY_REF: | |||
1172 | case ARRAY_RANGE_REF: | |||
1173 | ret = create_access (expr, stmt, write); | |||
1174 | break; | |||
1175 | ||||
1176 | default: | |||
1177 | break; | |||
1178 | } | |||
1179 | ||||
1180 | if (write && partial_ref && ret) | |||
1181 | ret->grp_partial_lhs = 1; | |||
1182 | ||||
1183 | return ret; | |||
1184 | } | |||
1185 | ||||
1186 | /* Scan expression EXPR and create access structures for all accesses to | |||
1187 | candidates for scalarization. Return true if any access has been inserted. | |||
1188 | STMT must be the statement from which the expression is taken, WRITE must be | |||
1189 | true if the expression is a store and false otherwise. */ | |||
1190 | ||||
1191 | static bool | |||
1192 | build_access_from_expr (tree expr, gimple *stmt, bool write) | |||
1193 | { | |||
1194 | struct access *access; | |||
1195 | ||||
1196 | access = build_access_from_expr_1 (expr, stmt, write); | |||
1197 | if (access) | |||
1198 | { | |||
1199 | /* This means the aggregate is accesses as a whole in a way other than an | |||
1200 | assign statement and thus cannot be removed even if we had a scalar | |||
1201 | replacement for everything. */ | |||
1202 | if (cannot_scalarize_away_bitmap) | |||
1203 | bitmap_set_bit (cannot_scalarize_away_bitmap, DECL_UID (access->base)((contains_struct_check ((access->base), (TS_DECL_MINIMAL) , "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 1203, __FUNCTION__))->decl_minimal.uid)); | |||
1204 | return true; | |||
1205 | } | |||
1206 | return false; | |||
1207 | } | |||
1208 | ||||
1209 | /* Return the single non-EH successor edge of BB or NULL if there is none or | |||
1210 | more than one. */ | |||
1211 | ||||
1212 | static edge | |||
1213 | single_non_eh_succ (basic_block bb) | |||
1214 | { | |||
1215 | edge e, res = NULLnullptr; | |||
1216 | edge_iterator ei; | |||
1217 | ||||
1218 | FOR_EACH_EDGE (e, ei, bb->succs)for ((ei) = ei_start_1 (&((bb->succs))); ei_cond ((ei) , &(e)); ei_next (&(ei))) | |||
1219 | if (!(e->flags & EDGE_EH)) | |||
1220 | { | |||
1221 | if (res) | |||
1222 | return NULLnullptr; | |||
1223 | res = e; | |||
1224 | } | |||
1225 | ||||
1226 | return res; | |||
1227 | } | |||
1228 | ||||
1229 | /* Disqualify LHS and RHS for scalarization if STMT has to terminate its BB and | |||
1230 | there is no alternative spot where to put statements SRA might need to | |||
1231 | generate after it. The spot we are looking for is an edge leading to a | |||
1232 | single non-EH successor, if it exists and is indeed single. RHS may be | |||
1233 | NULL, in that case ignore it. */ | |||
1234 | ||||
1235 | static bool | |||
1236 | disqualify_if_bad_bb_terminating_stmt (gimple *stmt, tree lhs, tree rhs) | |||
1237 | { | |||
1238 | if (stmt_ends_bb_p (stmt)) | |||
1239 | { | |||
1240 | if (single_non_eh_succ (gimple_bb (stmt))) | |||
1241 | return false; | |||
1242 | ||||
1243 | disqualify_base_of_expr (lhs, "LHS of a throwing stmt."); | |||
1244 | if (rhs) | |||
1245 | disqualify_base_of_expr (rhs, "RHS of a throwing stmt."); | |||
1246 | return true; | |||
1247 | } | |||
1248 | return false; | |||
1249 | } | |||
1250 | ||||
1251 | /* Return true if the nature of BASE is such that it contains data even if | |||
1252 | there is no write to it in the function. */ | |||
1253 | ||||
1254 | static bool | |||
1255 | comes_initialized_p (tree base) | |||
1256 | { | |||
1257 | return TREE_CODE (base)((enum tree_code) (base)->base.code) == PARM_DECL || constant_decl_p (base); | |||
1258 | } | |||
1259 | ||||
1260 | /* Scan expressions occurring in STMT, create access structures for all accesses | |||
1261 | to candidates for scalarization and remove those candidates which occur in | |||
1262 | statements or expressions that prevent them from being split apart. Return | |||
1263 | true if any access has been inserted. */ | |||
1264 | ||||
1265 | static bool | |||
1266 | build_accesses_from_assign (gimple *stmt) | |||
1267 | { | |||
1268 | tree lhs, rhs; | |||
1269 | struct access *lacc, *racc; | |||
1270 | ||||
1271 | if (!gimple_assign_single_p (stmt) | |||
1272 | /* Scope clobbers don't influence scalarization. */ | |||
1273 | || gimple_clobber_p (stmt)) | |||
1274 | return false; | |||
1275 | ||||
1276 | lhs = gimple_assign_lhs (stmt); | |||
1277 | rhs = gimple_assign_rhs1 (stmt); | |||
1278 | ||||
1279 | if (disqualify_if_bad_bb_terminating_stmt (stmt, lhs, rhs)) | |||
1280 | return false; | |||
1281 | ||||
1282 | racc = build_access_from_expr_1 (rhs, stmt, false); | |||
1283 | lacc = build_access_from_expr_1 (lhs, stmt, true); | |||
1284 | ||||
1285 | if (lacc) | |||
1286 | { | |||
1287 | lacc->grp_assignment_write = 1; | |||
1288 | if (storage_order_barrier_p (rhs)) | |||
1289 | lacc->grp_unscalarizable_region = 1; | |||
1290 | ||||
1291 | if (should_scalarize_away_bitmap && !is_gimple_reg_type (lacc->type)) | |||
1292 | { | |||
1293 | bool type_changing_p = false; | |||
1294 | contains_vce_or_bfcref_p (lhs, &type_changing_p); | |||
1295 | if (type_changing_p) | |||
1296 | bitmap_set_bit (cannot_scalarize_away_bitmap, | |||
1297 | DECL_UID (lacc->base)((contains_struct_check ((lacc->base), (TS_DECL_MINIMAL), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 1297, __FUNCTION__))->decl_minimal.uid)); | |||
1298 | } | |||
1299 | } | |||
1300 | ||||
1301 | if (racc) | |||
1302 | { | |||
1303 | racc->grp_assignment_read = 1; | |||
1304 | if (should_scalarize_away_bitmap && !is_gimple_reg_type (racc->type)) | |||
1305 | { | |||
1306 | bool type_changing_p = false; | |||
1307 | contains_vce_or_bfcref_p (rhs, &type_changing_p); | |||
1308 | ||||
1309 | if (type_changing_p || gimple_has_volatile_ops (stmt)) | |||
1310 | bitmap_set_bit (cannot_scalarize_away_bitmap, | |||
1311 | DECL_UID (racc->base)((contains_struct_check ((racc->base), (TS_DECL_MINIMAL), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 1311, __FUNCTION__))->decl_minimal.uid)); | |||
1312 | else | |||
1313 | bitmap_set_bit (should_scalarize_away_bitmap, | |||
1314 | DECL_UID (racc->base)((contains_struct_check ((racc->base), (TS_DECL_MINIMAL), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 1314, __FUNCTION__))->decl_minimal.uid)); | |||
1315 | } | |||
1316 | if (storage_order_barrier_p (lhs)) | |||
1317 | racc->grp_unscalarizable_region = 1; | |||
1318 | } | |||
1319 | ||||
1320 | if (lacc && racc | |||
1321 | && (sra_mode == SRA_MODE_EARLY_INTRA || sra_mode == SRA_MODE_INTRA) | |||
1322 | && !lacc->grp_unscalarizable_region | |||
1323 | && !racc->grp_unscalarizable_region | |||
1324 | && AGGREGATE_TYPE_P (TREE_TYPE (lhs))(((enum tree_code) (((contains_struct_check ((lhs), (TS_TYPED ), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 1324, __FUNCTION__))->typed.type))->base.code) == ARRAY_TYPE || (((enum tree_code) (((contains_struct_check ((lhs), (TS_TYPED ), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 1324, __FUNCTION__))->typed.type))->base.code) == RECORD_TYPE || ((enum tree_code) (((contains_struct_check ((lhs), (TS_TYPED ), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 1324, __FUNCTION__))->typed.type))->base.code) == UNION_TYPE || ((enum tree_code) (((contains_struct_check ((lhs), (TS_TYPED ), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 1324, __FUNCTION__))->typed.type))->base.code) == QUAL_UNION_TYPE )) | |||
1325 | && lacc->size == racc->size | |||
1326 | && useless_type_conversion_p (lacc->type, racc->type)) | |||
1327 | { | |||
1328 | struct assign_link *link; | |||
1329 | ||||
1330 | link = assign_link_pool.allocate (); | |||
1331 | memset (link, 0, sizeof (struct assign_link)); | |||
1332 | ||||
1333 | link->lacc = lacc; | |||
1334 | link->racc = racc; | |||
1335 | add_link_to_rhs (racc, link); | |||
1336 | add_link_to_lhs (lacc, link); | |||
1337 | add_access_to_rhs_work_queue (racc); | |||
1338 | add_access_to_lhs_work_queue (lacc); | |||
1339 | ||||
1340 | /* Let's delay marking the areas as written until propagation of accesses | |||
1341 | across link, unless the nature of rhs tells us that its data comes | |||
1342 | from elsewhere. */ | |||
1343 | if (!comes_initialized_p (racc->base)) | |||
1344 | lacc->write = false; | |||
1345 | } | |||
1346 | ||||
1347 | return lacc || racc; | |||
1348 | } | |||
1349 | ||||
1350 | /* Callback of walk_stmt_load_store_addr_ops visit_addr used to determine | |||
1351 | GIMPLE_ASM operands with memory constrains which cannot be scalarized. */ | |||
1352 | ||||
1353 | static bool | |||
1354 | asm_visit_addr (gimple *, tree op, tree, void *) | |||
1355 | { | |||
1356 | op = get_base_address (op); | |||
1357 | if (op | |||
1358 | && DECL_P (op)(tree_code_type_tmpl <0>::tree_code_type[(int) (((enum tree_code ) (op)->base.code))] == tcc_declaration)) | |||
1359 | disqualify_candidate (op, "Non-scalarizable GIMPLE_ASM operand."); | |||
1360 | ||||
1361 | return false; | |||
1362 | } | |||
1363 | ||||
1364 | /* Scan function and look for interesting expressions and create access | |||
1365 | structures for them. Return true iff any access is created. */ | |||
1366 | ||||
1367 | static bool | |||
1368 | scan_function (void) | |||
1369 | { | |||
1370 | basic_block bb; | |||
1371 | bool ret = false; | |||
1372 | ||||
1373 | FOR_EACH_BB_FN (bb, cfun)for (bb = ((cfun + 0))->cfg->x_entry_block_ptr->next_bb ; bb != ((cfun + 0))->cfg->x_exit_block_ptr; bb = bb-> next_bb) | |||
1374 | { | |||
1375 | gimple_stmt_iterator gsi; | |||
1376 | for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi)) | |||
1377 | { | |||
1378 | gimple *stmt = gsi_stmt (gsi); | |||
1379 | tree t; | |||
1380 | unsigned i; | |||
1381 | ||||
1382 | switch (gimple_code (stmt)) | |||
1383 | { | |||
1384 | case GIMPLE_RETURN: | |||
1385 | t = gimple_return_retval (as_a <greturn *> (stmt)); | |||
1386 | if (t != NULL_TREE(tree) nullptr) | |||
1387 | ret |= build_access_from_expr (t, stmt, false); | |||
1388 | break; | |||
1389 | ||||
1390 | case GIMPLE_ASSIGN: | |||
1391 | ret |= build_accesses_from_assign (stmt); | |||
1392 | break; | |||
1393 | ||||
1394 | case GIMPLE_CALL: | |||
1395 | for (i = 0; i < gimple_call_num_args (stmt); i++) | |||
1396 | ret |= build_access_from_expr (gimple_call_arg (stmt, i), | |||
1397 | stmt, false); | |||
1398 | ||||
1399 | t = gimple_call_lhs (stmt); | |||
1400 | if (t && !disqualify_if_bad_bb_terminating_stmt (stmt, t, NULLnullptr)) | |||
1401 | { | |||
1402 | /* If the STMT is a call to DEFERRED_INIT, avoid setting | |||
1403 | cannot_scalarize_away_bitmap. */ | |||
1404 | if (gimple_call_internal_p (stmt, IFN_DEFERRED_INIT)) | |||
1405 | ret |= !!build_access_from_expr_1 (t, stmt, true); | |||
1406 | else | |||
1407 | ret |= build_access_from_expr (t, stmt, true); | |||
1408 | } | |||
1409 | break; | |||
1410 | ||||
1411 | case GIMPLE_ASM: | |||
1412 | { | |||
1413 | gasm *asm_stmt = as_a <gasm *> (stmt); | |||
1414 | walk_stmt_load_store_addr_ops (asm_stmt, NULLnullptr, NULLnullptr, NULLnullptr, | |||
1415 | asm_visit_addr); | |||
1416 | for (i = 0; i < gimple_asm_ninputs (asm_stmt); i++) | |||
1417 | { | |||
1418 | t = TREE_VALUE (gimple_asm_input_op (asm_stmt, i))((tree_check ((gimple_asm_input_op (asm_stmt, i)), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 1418, __FUNCTION__, (TREE_LIST)))->list.value); | |||
1419 | ret |= build_access_from_expr (t, asm_stmt, false); | |||
1420 | } | |||
1421 | for (i = 0; i < gimple_asm_noutputs (asm_stmt); i++) | |||
1422 | { | |||
1423 | t = TREE_VALUE (gimple_asm_output_op (asm_stmt, i))((tree_check ((gimple_asm_output_op (asm_stmt, i)), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 1423, __FUNCTION__, (TREE_LIST)))->list.value); | |||
1424 | ret |= build_access_from_expr (t, asm_stmt, true); | |||
1425 | } | |||
1426 | } | |||
1427 | break; | |||
1428 | ||||
1429 | default: | |||
1430 | break; | |||
1431 | } | |||
1432 | } | |||
1433 | } | |||
1434 | ||||
1435 | return ret; | |||
1436 | } | |||
1437 | ||||
1438 | /* Helper of QSORT function. There are pointers to accesses in the array. An | |||
1439 | access is considered smaller than another if it has smaller offset or if the | |||
1440 | offsets are the same but is size is bigger. */ | |||
1441 | ||||
1442 | static int | |||
1443 | compare_access_positions (const void *a, const void *b) | |||
1444 | { | |||
1445 | const access_p *fp1 = (const access_p *) a; | |||
1446 | const access_p *fp2 = (const access_p *) b; | |||
1447 | const access_p f1 = *fp1; | |||
1448 | const access_p f2 = *fp2; | |||
1449 | ||||
1450 | if (f1->offset != f2->offset) | |||
1451 | return f1->offset < f2->offset ? -1 : 1; | |||
1452 | ||||
1453 | if (f1->size == f2->size) | |||
1454 | { | |||
1455 | if (f1->type == f2->type) | |||
1456 | return 0; | |||
1457 | /* Put any non-aggregate type before any aggregate type. */ | |||
1458 | else if (!is_gimple_reg_type (f1->type) | |||
1459 | && is_gimple_reg_type (f2->type)) | |||
1460 | return 1; | |||
1461 | else if (is_gimple_reg_type (f1->type) | |||
1462 | && !is_gimple_reg_type (f2->type)) | |||
1463 | return -1; | |||
1464 | /* Put any complex or vector type before any other scalar type. */ | |||
1465 | else if (TREE_CODE (f1->type)((enum tree_code) (f1->type)->base.code) != COMPLEX_TYPE | |||
1466 | && TREE_CODE (f1->type)((enum tree_code) (f1->type)->base.code) != VECTOR_TYPE | |||
1467 | && (TREE_CODE (f2->type)((enum tree_code) (f2->type)->base.code) == COMPLEX_TYPE | |||
1468 | || TREE_CODE (f2->type)((enum tree_code) (f2->type)->base.code) == VECTOR_TYPE)) | |||
1469 | return 1; | |||
1470 | else if ((TREE_CODE (f1->type)((enum tree_code) (f1->type)->base.code) == COMPLEX_TYPE | |||
1471 | || TREE_CODE (f1->type)((enum tree_code) (f1->type)->base.code) == VECTOR_TYPE) | |||
1472 | && TREE_CODE (f2->type)((enum tree_code) (f2->type)->base.code) != COMPLEX_TYPE | |||
1473 | && TREE_CODE (f2->type)((enum tree_code) (f2->type)->base.code) != VECTOR_TYPE) | |||
1474 | return -1; | |||
1475 | /* Put any integral type before any non-integral type. When splicing, we | |||
1476 | make sure that those with insufficient precision and occupying the | |||
1477 | same space are not scalarized. */ | |||
1478 | else if (INTEGRAL_TYPE_P (f1->type)(((enum tree_code) (f1->type)->base.code) == ENUMERAL_TYPE || ((enum tree_code) (f1->type)->base.code) == BOOLEAN_TYPE || ((enum tree_code) (f1->type)->base.code) == INTEGER_TYPE ) | |||
1479 | && !INTEGRAL_TYPE_P (f2->type)(((enum tree_code) (f2->type)->base.code) == ENUMERAL_TYPE || ((enum tree_code) (f2->type)->base.code) == BOOLEAN_TYPE || ((enum tree_code) (f2->type)->base.code) == INTEGER_TYPE )) | |||
1480 | return -1; | |||
1481 | else if (!INTEGRAL_TYPE_P (f1->type)(((enum tree_code) (f1->type)->base.code) == ENUMERAL_TYPE || ((enum tree_code) (f1->type)->base.code) == BOOLEAN_TYPE || ((enum tree_code) (f1->type)->base.code) == INTEGER_TYPE ) | |||
1482 | && INTEGRAL_TYPE_P (f2->type)(((enum tree_code) (f2->type)->base.code) == ENUMERAL_TYPE || ((enum tree_code) (f2->type)->base.code) == BOOLEAN_TYPE || ((enum tree_code) (f2->type)->base.code) == INTEGER_TYPE )) | |||
1483 | return 1; | |||
1484 | /* Put the integral type with the bigger precision first. */ | |||
1485 | else if (INTEGRAL_TYPE_P (f1->type)(((enum tree_code) (f1->type)->base.code) == ENUMERAL_TYPE || ((enum tree_code) (f1->type)->base.code) == BOOLEAN_TYPE || ((enum tree_code) (f1->type)->base.code) == INTEGER_TYPE ) | |||
1486 | && INTEGRAL_TYPE_P (f2->type)(((enum tree_code) (f2->type)->base.code) == ENUMERAL_TYPE || ((enum tree_code) (f2->type)->base.code) == BOOLEAN_TYPE || ((enum tree_code) (f2->type)->base.code) == INTEGER_TYPE ) | |||
1487 | && (TYPE_PRECISION (f2->type)((tree_class_check ((f2->type), (tcc_type), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 1487, __FUNCTION__))->type_common.precision) != TYPE_PRECISION (f1->type)((tree_class_check ((f1->type), (tcc_type), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 1487, __FUNCTION__))->type_common.precision))) | |||
1488 | return TYPE_PRECISION (f2->type)((tree_class_check ((f2->type), (tcc_type), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 1488, __FUNCTION__))->type_common.precision) - TYPE_PRECISION (f1->type)((tree_class_check ((f1->type), (tcc_type), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 1488, __FUNCTION__))->type_common.precision); | |||
1489 | /* Stabilize the sort. */ | |||
1490 | return TYPE_UID (f1->type)((tree_class_check ((f1->type), (tcc_type), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 1490, __FUNCTION__))->type_common.uid) - TYPE_UID (f2->type)((tree_class_check ((f2->type), (tcc_type), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 1490, __FUNCTION__))->type_common.uid); | |||
1491 | } | |||
1492 | ||||
1493 | /* We want the bigger accesses first, thus the opposite operator in the next | |||
1494 | line: */ | |||
1495 | return f1->size > f2->size ? -1 : 1; | |||
1496 | } | |||
1497 | ||||
1498 | ||||
1499 | /* Append a name of the declaration to the name obstack. A helper function for | |||
1500 | make_fancy_name. */ | |||
1501 | ||||
1502 | static void | |||
1503 | make_fancy_decl_name (tree decl) | |||
1504 | { | |||
1505 | char buffer[32]; | |||
1506 | ||||
1507 | tree name = DECL_NAME (decl)((contains_struct_check ((decl), (TS_DECL_MINIMAL), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 1507, __FUNCTION__))->decl_minimal.name); | |||
1508 | if (name) | |||
1509 | obstack_grow (&name_obstack, IDENTIFIER_POINTER (name),__extension__ ({ struct obstack *__o = (&name_obstack); size_t __len = (((tree_check ((name), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 1510, __FUNCTION__, (IDENTIFIER_NODE)))->identifier.id.len )); if (__extension__ ({ struct obstack const *__o1 = (__o); ( size_t) (__o1->chunk_limit - __o1->next_free); }) < __len ) _obstack_newchunk (__o, __len); memcpy (__o->next_free, ( (const char *) (tree_check ((name), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 1509, __FUNCTION__, (IDENTIFIER_NODE)))->identifier.id.str ), __len); __o->next_free += __len; (void) 0; }) | |||
1510 | IDENTIFIER_LENGTH (name))__extension__ ({ struct obstack *__o = (&name_obstack); size_t __len = (((tree_check ((name), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 1510, __FUNCTION__, (IDENTIFIER_NODE)))->identifier.id.len )); if (__extension__ ({ struct obstack const *__o1 = (__o); ( size_t) (__o1->chunk_limit - __o1->next_free); }) < __len ) _obstack_newchunk (__o, __len); memcpy (__o->next_free, ( (const char *) (tree_check ((name), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 1509, __FUNCTION__, (IDENTIFIER_NODE)))->identifier.id.str ), __len); __o->next_free += __len; (void) 0; }); | |||
1511 | else | |||
1512 | { | |||
1513 | sprintf (buffer, "D%u", DECL_UID (decl)((contains_struct_check ((decl), (TS_DECL_MINIMAL), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 1513, __FUNCTION__))->decl_minimal.uid)); | |||
1514 | obstack_grow (&name_obstack, buffer, strlen (buffer))__extension__ ({ struct obstack *__o = (&name_obstack); size_t __len = (strlen (buffer)); if (__extension__ ({ struct obstack const *__o1 = (__o); (size_t) (__o1->chunk_limit - __o1-> next_free); }) < __len) _obstack_newchunk (__o, __len); memcpy (__o->next_free, buffer, __len); __o->next_free += __len ; (void) 0; }); | |||
1515 | } | |||
1516 | } | |||
1517 | ||||
1518 | /* Helper for make_fancy_name. */ | |||
1519 | ||||
1520 | static void | |||
1521 | make_fancy_name_1 (tree expr) | |||
1522 | { | |||
1523 | char buffer[32]; | |||
1524 | tree index; | |||
1525 | ||||
1526 | if (DECL_P (expr)(tree_code_type_tmpl <0>::tree_code_type[(int) (((enum tree_code ) (expr)->base.code))] == tcc_declaration)) | |||
1527 | { | |||
1528 | make_fancy_decl_name (expr); | |||
1529 | return; | |||
1530 | } | |||
1531 | ||||
1532 | switch (TREE_CODE (expr)((enum tree_code) (expr)->base.code)) | |||
1533 | { | |||
1534 | case COMPONENT_REF: | |||
1535 | make_fancy_name_1 (TREE_OPERAND (expr, 0)(*((const_cast<tree*> (tree_operand_check ((expr), (0), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 1535, __FUNCTION__)))))); | |||
1536 | obstack_1grow (&name_obstack, '$')__extension__ ({ struct obstack *__o = (&name_obstack); if (__extension__ ({ struct obstack const *__o1 = (__o); (size_t ) (__o1->chunk_limit - __o1->next_free); }) < 1) _obstack_newchunk (__o, 1); ((void) (*((__o)->next_free)++ = ('$'))); }); | |||
1537 | make_fancy_decl_name (TREE_OPERAND (expr, 1)(*((const_cast<tree*> (tree_operand_check ((expr), (1), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 1537, __FUNCTION__)))))); | |||
1538 | break; | |||
1539 | ||||
1540 | case ARRAY_REF: | |||
1541 | make_fancy_name_1 (TREE_OPERAND (expr, 0)(*((const_cast<tree*> (tree_operand_check ((expr), (0), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 1541, __FUNCTION__)))))); | |||
1542 | obstack_1grow (&name_obstack, '$')__extension__ ({ struct obstack *__o = (&name_obstack); if (__extension__ ({ struct obstack const *__o1 = (__o); (size_t ) (__o1->chunk_limit - __o1->next_free); }) < 1) _obstack_newchunk (__o, 1); ((void) (*((__o)->next_free)++ = ('$'))); }); | |||
1543 | /* Arrays with only one element may not have a constant as their | |||
1544 | index. */ | |||
1545 | index = TREE_OPERAND (expr, 1)(*((const_cast<tree*> (tree_operand_check ((expr), (1), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 1545, __FUNCTION__))))); | |||
1546 | if (TREE_CODE (index)((enum tree_code) (index)->base.code) != INTEGER_CST) | |||
1547 | break; | |||
1548 | sprintf (buffer, HOST_WIDE_INT_PRINT_DEC"%" "l" "d", TREE_INT_CST_LOW (index)((unsigned long) (*tree_int_cst_elt_check ((index), (0), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 1548, __FUNCTION__)))); | |||
1549 | obstack_grow (&name_obstack, buffer, strlen (buffer))__extension__ ({ struct obstack *__o = (&name_obstack); size_t __len = (strlen (buffer)); if (__extension__ ({ struct obstack const *__o1 = (__o); (size_t) (__o1->chunk_limit - __o1-> next_free); }) < __len) _obstack_newchunk (__o, __len); memcpy (__o->next_free, buffer, __len); __o->next_free += __len ; (void) 0; }); | |||
1550 | break; | |||
1551 | ||||
1552 | case ADDR_EXPR: | |||
1553 | make_fancy_name_1 (TREE_OPERAND (expr, 0)(*((const_cast<tree*> (tree_operand_check ((expr), (0), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 1553, __FUNCTION__)))))); | |||
1554 | break; | |||
1555 | ||||
1556 | case MEM_REF: | |||
1557 | make_fancy_name_1 (TREE_OPERAND (expr, 0)(*((const_cast<tree*> (tree_operand_check ((expr), (0), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 1557, __FUNCTION__)))))); | |||
1558 | if (!integer_zerop (TREE_OPERAND (expr, 1)(*((const_cast<tree*> (tree_operand_check ((expr), (1), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 1558, __FUNCTION__))))))) | |||
1559 | { | |||
1560 | obstack_1grow (&name_obstack, '$')__extension__ ({ struct obstack *__o = (&name_obstack); if (__extension__ ({ struct obstack const *__o1 = (__o); (size_t ) (__o1->chunk_limit - __o1->next_free); }) < 1) _obstack_newchunk (__o, 1); ((void) (*((__o)->next_free)++ = ('$'))); }); | |||
1561 | sprintf (buffer, HOST_WIDE_INT_PRINT_DEC"%" "l" "d", | |||
1562 | TREE_INT_CST_LOW (TREE_OPERAND (expr, 1))((unsigned long) (*tree_int_cst_elt_check (((*((const_cast< tree*> (tree_operand_check ((expr), (1), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 1562, __FUNCTION__)))))), (0), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 1562, __FUNCTION__)))); | |||
1563 | obstack_grow (&name_obstack, buffer, strlen (buffer))__extension__ ({ struct obstack *__o = (&name_obstack); size_t __len = (strlen (buffer)); if (__extension__ ({ struct obstack const *__o1 = (__o); (size_t) (__o1->chunk_limit - __o1-> next_free); }) < __len) _obstack_newchunk (__o, __len); memcpy (__o->next_free, buffer, __len); __o->next_free += __len ; (void) 0; }); | |||
1564 | } | |||
1565 | break; | |||
1566 | ||||
1567 | case BIT_FIELD_REF: | |||
1568 | case REALPART_EXPR: | |||
1569 | case IMAGPART_EXPR: | |||
1570 | gcc_unreachable ()(fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 1570, __FUNCTION__)); /* we treat these as scalars. */ | |||
1571 | break; | |||
1572 | default: | |||
1573 | break; | |||
1574 | } | |||
1575 | } | |||
1576 | ||||
1577 | /* Create a human readable name for replacement variable of ACCESS. */ | |||
1578 | ||||
1579 | static char * | |||
1580 | make_fancy_name (tree expr) | |||
1581 | { | |||
1582 | make_fancy_name_1 (expr); | |||
1583 | obstack_1grow (&name_obstack, '\0')__extension__ ({ struct obstack *__o = (&name_obstack); if (__extension__ ({ struct obstack const *__o1 = (__o); (size_t ) (__o1->chunk_limit - __o1->next_free); }) < 1) _obstack_newchunk (__o, 1); ((void) (*((__o)->next_free)++ = ('\0'))); }); | |||
1584 | return XOBFINISH (&name_obstack, char *)((char *) __extension__ ({ struct obstack *__o1 = ((&name_obstack )); void *__value = (void *) __o1->object_base; if (__o1-> next_free == __value) __o1->maybe_empty_object = 1; __o1-> next_free = (sizeof (ptrdiff_t) < sizeof (void *) ? ((__o1 ->object_base) + (((__o1->next_free) - (__o1->object_base ) + (__o1->alignment_mask)) & ~(__o1->alignment_mask ))) : (char *) (((ptrdiff_t) (__o1->next_free) + (__o1-> alignment_mask)) & ~(__o1->alignment_mask))); if ((size_t ) (__o1->next_free - (char *) __o1->chunk) > (size_t ) (__o1->chunk_limit - (char *) __o1->chunk)) __o1-> next_free = __o1->chunk_limit; __o1->object_base = __o1 ->next_free; __value; })); | |||
1585 | } | |||
1586 | ||||
1587 | /* Construct a MEM_REF that would reference a part of aggregate BASE of type | |||
1588 | EXP_TYPE at the given OFFSET and with storage order REVERSE. If BASE is | |||
1589 | something for which get_addr_base_and_unit_offset returns NULL, gsi must | |||
1590 | be non-NULL and is used to insert new statements either before or below | |||
1591 | the current one as specified by INSERT_AFTER. This function is not capable | |||
1592 | of handling bitfields. */ | |||
1593 | ||||
1594 | tree | |||
1595 | build_ref_for_offset (location_t loc, tree base, poly_int64 offset, | |||
1596 | bool reverse, tree exp_type, gimple_stmt_iterator *gsi, | |||
1597 | bool insert_after) | |||
1598 | { | |||
1599 | tree prev_base = base; | |||
1600 | tree off; | |||
1601 | tree mem_ref; | |||
1602 | poly_int64 base_offset; | |||
1603 | unsigned HOST_WIDE_INTlong misalign; | |||
1604 | unsigned int align; | |||
1605 | ||||
1606 | /* Preserve address-space information. */ | |||
1607 | addr_space_t as = TYPE_ADDR_SPACE (TREE_TYPE (base))((tree_class_check ((((contains_struct_check ((base), (TS_TYPED ), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 1607, __FUNCTION__))->typed.type)), (tcc_type), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 1607, __FUNCTION__))->base.u.bits.address_space); | |||
1608 | if (as != TYPE_ADDR_SPACE (exp_type)((tree_class_check ((exp_type), (tcc_type), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 1608, __FUNCTION__))->base.u.bits.address_space)) | |||
1609 | exp_type = build_qualified_type (exp_type, | |||
1610 | TYPE_QUALS (exp_type)((int) ((((tree_class_check ((exp_type), (tcc_type), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 1610, __FUNCTION__))->base.readonly_flag) * TYPE_QUAL_CONST ) | (((tree_class_check ((exp_type), (tcc_type), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 1610, __FUNCTION__))->base.volatile_flag) * TYPE_QUAL_VOLATILE ) | (((tree_class_check ((exp_type), (tcc_type), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 1610, __FUNCTION__))->base.u.bits.atomic_flag) * TYPE_QUAL_ATOMIC ) | (((tree_class_check ((exp_type), (tcc_type), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 1610, __FUNCTION__))->type_common.restrict_flag) * TYPE_QUAL_RESTRICT ) | (((((tree_class_check ((exp_type), (tcc_type), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 1610, __FUNCTION__))->base.u.bits.address_space) & 0xFF ) << 8)))) | |||
1611 | | ENCODE_QUAL_ADDR_SPACE (as)((as & 0xFF) << 8)); | |||
1612 | ||||
1613 | poly_int64 byte_offset = exact_div (offset, BITS_PER_UNIT(8)); | |||
1614 | get_object_alignment_1 (base, &align, &misalign); | |||
1615 | base = get_addr_base_and_unit_offset (base, &base_offset); | |||
1616 | ||||
1617 | /* get_addr_base_and_unit_offset returns NULL for references with a variable | |||
1618 | offset such as array[var_index]. */ | |||
1619 | if (!base) | |||
1620 | { | |||
1621 | gassign *stmt; | |||
1622 | tree tmp, addr; | |||
1623 | ||||
1624 | gcc_checking_assert (gsi)((void)(!(gsi) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 1624, __FUNCTION__), 0 : 0)); | |||
1625 | tmp = make_ssa_name (build_pointer_type (TREE_TYPE (prev_base)((contains_struct_check ((prev_base), (TS_TYPED), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 1625, __FUNCTION__))->typed.type))); | |||
1626 | addr = build_fold_addr_expr (unshare_expr (prev_base))build_fold_addr_expr_loc (((location_t) 0), (unshare_expr (prev_base ))); | |||
1627 | STRIP_USELESS_TYPE_CONVERSION (addr)(addr) = tree_ssa_strip_useless_type_conversions (addr); | |||
1628 | stmt = gimple_build_assign (tmp, addr); | |||
1629 | gimple_set_location (stmt, loc); | |||
1630 | if (insert_after) | |||
1631 | gsi_insert_after (gsi, stmt, GSI_NEW_STMT); | |||
1632 | else | |||
1633 | gsi_insert_before (gsi, stmt, GSI_SAME_STMT); | |||
1634 | ||||
1635 | off = build_int_cst (reference_alias_ptr_type (prev_base), byte_offset); | |||
1636 | base = tmp; | |||
1637 | } | |||
1638 | else if (TREE_CODE (base)((enum tree_code) (base)->base.code) == MEM_REF) | |||
1639 | { | |||
1640 | off = build_int_cst (TREE_TYPE (TREE_OPERAND (base, 1))((contains_struct_check (((*((const_cast<tree*> (tree_operand_check ((base), (1), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 1640, __FUNCTION__)))))), (TS_TYPED), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 1640, __FUNCTION__))->typed.type), | |||
1641 | base_offset + byte_offset); | |||
1642 | off = int_const_binop (PLUS_EXPR, TREE_OPERAND (base, 1)(*((const_cast<tree*> (tree_operand_check ((base), (1), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 1642, __FUNCTION__))))), off); | |||
1643 | base = unshare_expr (TREE_OPERAND (base, 0)(*((const_cast<tree*> (tree_operand_check ((base), (0), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 1643, __FUNCTION__)))))); | |||
1644 | } | |||
1645 | else | |||
1646 | { | |||
1647 | off = build_int_cst (reference_alias_ptr_type (prev_base), | |||
1648 | base_offset + byte_offset); | |||
1649 | base = build_fold_addr_expr (unshare_expr (base))build_fold_addr_expr_loc (((location_t) 0), (unshare_expr (base ))); | |||
1650 | } | |||
1651 | ||||
1652 | unsigned int align_bound = known_alignment (misalign + offset); | |||
1653 | if (align_bound != 0) | |||
1654 | align = MIN (align, align_bound)((align) < (align_bound) ? (align) : (align_bound)); | |||
1655 | if (align != TYPE_ALIGN (exp_type)(((tree_class_check ((exp_type), (tcc_type), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 1655, __FUNCTION__))->type_common.align) ? ((unsigned)1) << (((tree_class_check ((exp_type), (tcc_type), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 1655, __FUNCTION__))->type_common.align) - 1) : 0)) | |||
1656 | exp_type = build_aligned_type (exp_type, align); | |||
1657 | ||||
1658 | mem_ref = fold_build2_loc (loc, MEM_REF, exp_type, base, off); | |||
1659 | REF_REVERSE_STORAGE_ORDER (mem_ref)((tree_check2 ((mem_ref), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 1659, __FUNCTION__, (BIT_FIELD_REF), (MEM_REF)))->base.default_def_flag ) = reverse; | |||
1660 | if (TREE_THIS_VOLATILE (prev_base)((prev_base)->base.volatile_flag)) | |||
1661 | TREE_THIS_VOLATILE (mem_ref)((mem_ref)->base.volatile_flag) = 1; | |||
1662 | if (TREE_SIDE_EFFECTS (prev_base)((non_type_check ((prev_base), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 1662, __FUNCTION__))->base.side_effects_flag)) | |||
1663 | TREE_SIDE_EFFECTS (mem_ref)((non_type_check ((mem_ref), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 1663, __FUNCTION__))->base.side_effects_flag) = 1; | |||
1664 | return mem_ref; | |||
1665 | } | |||
1666 | ||||
1667 | /* Construct and return a memory reference that is equal to a portion of | |||
1668 | MODEL->expr but is based on BASE. If this cannot be done, return NULL. */ | |||
1669 | ||||
1670 | static tree | |||
1671 | build_reconstructed_reference (location_t, tree base, struct access *model) | |||
1672 | { | |||
1673 | tree expr = model->expr; | |||
1674 | /* We have to make sure to start just below the outermost union. */ | |||
1675 | tree start_expr = expr; | |||
1676 | while (handled_component_p (expr)) | |||
1677 | { | |||
1678 | if (TREE_CODE (TREE_TYPE (TREE_OPERAND (expr, 0)))((enum tree_code) (((contains_struct_check (((*((const_cast< tree*> (tree_operand_check ((expr), (0), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 1678, __FUNCTION__)))))), (TS_TYPED), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 1678, __FUNCTION__))->typed.type))->base.code) == UNION_TYPE) | |||
1679 | start_expr = expr; | |||
1680 | expr = TREE_OPERAND (expr, 0)(*((const_cast<tree*> (tree_operand_check ((expr), (0), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 1680, __FUNCTION__))))); | |||
1681 | } | |||
1682 | ||||
1683 | expr = start_expr; | |||
1684 | tree prev_expr = NULL_TREE(tree) nullptr; | |||
1685 | while (!types_compatible_p (TREE_TYPE (expr)((contains_struct_check ((expr), (TS_TYPED), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 1685, __FUNCTION__))->typed.type), TREE_TYPE (base)((contains_struct_check ((base), (TS_TYPED), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 1685, __FUNCTION__))->typed.type))) | |||
1686 | { | |||
1687 | if (!handled_component_p (expr)) | |||
1688 | return NULL_TREE(tree) nullptr; | |||
1689 | prev_expr = expr; | |||
1690 | expr = TREE_OPERAND (expr, 0)(*((const_cast<tree*> (tree_operand_check ((expr), (0), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 1690, __FUNCTION__))))); | |||
1691 | } | |||
1692 | ||||
1693 | /* Guard against broken VIEW_CONVERT_EXPRs... */ | |||
1694 | if (!prev_expr) | |||
1695 | return NULL_TREE(tree) nullptr; | |||
1696 | ||||
1697 | TREE_OPERAND (prev_expr, 0)(*((const_cast<tree*> (tree_operand_check ((prev_expr), (0), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 1697, __FUNCTION__))))) = base; | |||
1698 | tree ref = unshare_expr (model->expr); | |||
1699 | TREE_OPERAND (prev_expr, 0)(*((const_cast<tree*> (tree_operand_check ((prev_expr), (0), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 1699, __FUNCTION__))))) = expr; | |||
1700 | return ref; | |||
1701 | } | |||
1702 | ||||
1703 | /* Construct a memory reference to a part of an aggregate BASE at the given | |||
1704 | OFFSET and of the same type as MODEL. In case this is a reference to a | |||
1705 | bit-field, the function will replicate the last component_ref of model's | |||
1706 | expr to access it. GSI and INSERT_AFTER have the same meaning as in | |||
1707 | build_ref_for_offset. */ | |||
1708 | ||||
1709 | static tree | |||
1710 | build_ref_for_model (location_t loc, tree base, HOST_WIDE_INTlong offset, | |||
1711 | struct access *model, gimple_stmt_iterator *gsi, | |||
1712 | bool insert_after) | |||
1713 | { | |||
1714 | gcc_assert (offset >= 0)((void)(!(offset >= 0) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 1714, __FUNCTION__), 0 : 0)); | |||
1715 | if (TREE_CODE (model->expr)((enum tree_code) (model->expr)->base.code) == COMPONENT_REF | |||
1716 | && DECL_BIT_FIELD (TREE_OPERAND (model->expr, 1))((tree_check (((*((const_cast<tree*> (tree_operand_check ((model->expr), (1), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 1716, __FUNCTION__)))))), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 1716, __FUNCTION__, (FIELD_DECL)))->decl_common.decl_flag_1 )) | |||
1717 | { | |||
1718 | /* This access represents a bit-field. */ | |||
1719 | tree t, exp_type, fld = TREE_OPERAND (model->expr, 1)(*((const_cast<tree*> (tree_operand_check ((model->expr ), (1), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 1719, __FUNCTION__))))); | |||
1720 | ||||
1721 | offset -= int_bit_position (fld); | |||
1722 | exp_type = TREE_TYPE (TREE_OPERAND (model->expr, 0))((contains_struct_check (((*((const_cast<tree*> (tree_operand_check ((model->expr), (0), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 1722, __FUNCTION__)))))), (TS_TYPED), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 1722, __FUNCTION__))->typed.type); | |||
1723 | t = build_ref_for_offset (loc, base, offset, model->reverse, exp_type, | |||
1724 | gsi, insert_after); | |||
1725 | /* The flag will be set on the record type. */ | |||
1726 | REF_REVERSE_STORAGE_ORDER (t)((tree_check2 ((t), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 1726, __FUNCTION__, (BIT_FIELD_REF), (MEM_REF)))->base.default_def_flag ) = 0; | |||
1727 | return fold_build3_loc (loc, COMPONENT_REF, TREE_TYPE (fld)((contains_struct_check ((fld), (TS_TYPED), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 1727, __FUNCTION__))->typed.type), t, fld, | |||
1728 | NULL_TREE(tree) nullptr); | |||
1729 | } | |||
1730 | else | |||
1731 | { | |||
1732 | tree res; | |||
1733 | if (model->grp_same_access_path | |||
1734 | && !TREE_THIS_VOLATILE (base)((base)->base.volatile_flag) | |||
1735 | && (TYPE_ADDR_SPACE (TREE_TYPE (base))((tree_class_check ((((contains_struct_check ((base), (TS_TYPED ), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 1735, __FUNCTION__))->typed.type)), (tcc_type), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 1735, __FUNCTION__))->base.u.bits.address_space) | |||
1736 | == TYPE_ADDR_SPACE (TREE_TYPE (model->expr))((tree_class_check ((((contains_struct_check ((model->expr ), (TS_TYPED), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 1736, __FUNCTION__))->typed.type)), (tcc_type), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 1736, __FUNCTION__))->base.u.bits.address_space)) | |||
1737 | && offset <= model->offset | |||
1738 | /* build_reconstructed_reference can still fail if we have already | |||
1739 | massaged BASE because of another type incompatibility. */ | |||
1740 | && (res = build_reconstructed_reference (loc, base, model))) | |||
1741 | return res; | |||
1742 | else | |||
1743 | return build_ref_for_offset (loc, base, offset, model->reverse, | |||
1744 | model->type, gsi, insert_after); | |||
1745 | } | |||
1746 | } | |||
1747 | ||||
1748 | /* Attempt to build a memory reference that we could but into a gimple | |||
1749 | debug_bind statement. Similar to build_ref_for_model but punts if it has to | |||
1750 | create statements and return s NULL instead. This function also ignores | |||
1751 | alignment issues and so its results should never end up in non-debug | |||
1752 | statements. */ | |||
1753 | ||||
1754 | static tree | |||
1755 | build_debug_ref_for_model (location_t loc, tree base, HOST_WIDE_INTlong offset, | |||
1756 | struct access *model) | |||
1757 | { | |||
1758 | poly_int64 base_offset; | |||
1759 | tree off; | |||
1760 | ||||
1761 | if (TREE_CODE (model->expr)((enum tree_code) (model->expr)->base.code) == COMPONENT_REF | |||
1762 | && DECL_BIT_FIELD (TREE_OPERAND (model->expr, 1))((tree_check (((*((const_cast<tree*> (tree_operand_check ((model->expr), (1), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 1762, __FUNCTION__)))))), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 1762, __FUNCTION__, (FIELD_DECL)))->decl_common.decl_flag_1 )) | |||
1763 | return NULL_TREE(tree) nullptr; | |||
1764 | ||||
1765 | base = get_addr_base_and_unit_offset (base, &base_offset); | |||
1766 | if (!base) | |||
1767 | return NULL_TREE(tree) nullptr; | |||
1768 | if (TREE_CODE (base)((enum tree_code) (base)->base.code) == MEM_REF) | |||
1769 | { | |||
1770 | off = build_int_cst (TREE_TYPE (TREE_OPERAND (base, 1))((contains_struct_check (((*((const_cast<tree*> (tree_operand_check ((base), (1), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 1770, __FUNCTION__)))))), (TS_TYPED), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 1770, __FUNCTION__))->typed.type), | |||
1771 | base_offset + offset / BITS_PER_UNIT(8)); | |||
1772 | off = int_const_binop (PLUS_EXPR, TREE_OPERAND (base, 1)(*((const_cast<tree*> (tree_operand_check ((base), (1), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 1772, __FUNCTION__))))), off); | |||
1773 | base = unshare_expr (TREE_OPERAND (base, 0)(*((const_cast<tree*> (tree_operand_check ((base), (0), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 1773, __FUNCTION__)))))); | |||
1774 | } | |||
1775 | else | |||
1776 | { | |||
1777 | off = build_int_cst (reference_alias_ptr_type (base), | |||
1778 | base_offset + offset / BITS_PER_UNIT(8)); | |||
1779 | base = build_fold_addr_expr (unshare_expr (base))build_fold_addr_expr_loc (((location_t) 0), (unshare_expr (base ))); | |||
1780 | } | |||
1781 | ||||
1782 | return fold_build2_loc (loc, MEM_REF, model->type, base, off); | |||
1783 | } | |||
1784 | ||||
1785 | /* Construct a memory reference consisting of component_refs and array_refs to | |||
1786 | a part of an aggregate *RES (which is of type TYPE). The requested part | |||
1787 | should have type EXP_TYPE at be the given OFFSET. This function might not | |||
1788 | succeed, it returns true when it does and only then *RES points to something | |||
1789 | meaningful. This function should be used only to build expressions that we | |||
1790 | might need to present to user (e.g. in warnings). In all other situations, | |||
1791 | build_ref_for_model or build_ref_for_offset should be used instead. */ | |||
1792 | ||||
1793 | static bool | |||
1794 | build_user_friendly_ref_for_offset (tree *res, tree type, HOST_WIDE_INTlong offset, | |||
1795 | tree exp_type) | |||
1796 | { | |||
1797 | while (1) | |||
1798 | { | |||
1799 | tree fld; | |||
1800 | tree tr_size, index, minidx; | |||
1801 | HOST_WIDE_INTlong el_size; | |||
1802 | ||||
1803 | if (offset == 0 && exp_type | |||
1804 | && types_compatible_p (exp_type, type)) | |||
1805 | return true; | |||
1806 | ||||
1807 | switch (TREE_CODE (type)((enum tree_code) (type)->base.code)) | |||
1808 | { | |||
1809 | case UNION_TYPE: | |||
1810 | case QUAL_UNION_TYPE: | |||
1811 | case RECORD_TYPE: | |||
1812 | for (fld = TYPE_FIELDS (type)((tree_check3 ((type), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 1812, __FUNCTION__, (RECORD_TYPE), (UNION_TYPE), (QUAL_UNION_TYPE )))->type_non_common.values); fld; fld = DECL_CHAIN (fld)(((contains_struct_check (((contains_struct_check ((fld), (TS_DECL_MINIMAL ), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 1812, __FUNCTION__))), (TS_COMMON), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 1812, __FUNCTION__))->common.chain))) | |||
1813 | { | |||
1814 | HOST_WIDE_INTlong pos, size; | |||
1815 | tree tr_pos, expr, *expr_ptr; | |||
1816 | ||||
1817 | if (TREE_CODE (fld)((enum tree_code) (fld)->base.code) != FIELD_DECL) | |||
1818 | continue; | |||
1819 | ||||
1820 | tr_pos = bit_position (fld); | |||
1821 | if (!tr_pos || !tree_fits_uhwi_p (tr_pos)) | |||
1822 | continue; | |||
1823 | pos = tree_to_uhwi (tr_pos); | |||
1824 | gcc_assert (TREE_CODE (type) == RECORD_TYPE || pos == 0)((void)(!(((enum tree_code) (type)->base.code) == RECORD_TYPE || pos == 0) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 1824, __FUNCTION__), 0 : 0)); | |||
1825 | tr_size = DECL_SIZE (fld)((contains_struct_check ((fld), (TS_DECL_COMMON), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 1825, __FUNCTION__))->decl_common.size); | |||
1826 | if (!tr_size || !tree_fits_uhwi_p (tr_size)) | |||
1827 | continue; | |||
1828 | size = tree_to_uhwi (tr_size); | |||
1829 | if (size == 0) | |||
1830 | { | |||
1831 | if (pos != offset) | |||
1832 | continue; | |||
1833 | } | |||
1834 | else if (pos > offset || (pos + size) <= offset) | |||
1835 | continue; | |||
1836 | ||||
1837 | expr = build3 (COMPONENT_REF, TREE_TYPE (fld)((contains_struct_check ((fld), (TS_TYPED), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 1837, __FUNCTION__))->typed.type), *res, fld, | |||
1838 | NULL_TREE(tree) nullptr); | |||
1839 | expr_ptr = &expr; | |||
1840 | if (build_user_friendly_ref_for_offset (expr_ptr, TREE_TYPE (fld)((contains_struct_check ((fld), (TS_TYPED), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 1840, __FUNCTION__))->typed.type), | |||
1841 | offset - pos, exp_type)) | |||
1842 | { | |||
1843 | *res = expr; | |||
1844 | return true; | |||
1845 | } | |||
1846 | } | |||
1847 | return false; | |||
1848 | ||||
1849 | case ARRAY_TYPE: | |||
1850 | tr_size = TYPE_SIZE (TREE_TYPE (type))((tree_class_check ((((contains_struct_check ((type), (TS_TYPED ), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 1850, __FUNCTION__))->typed.type)), (tcc_type), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 1850, __FUNCTION__))->type_common.size); | |||
1851 | if (!tr_size || !tree_fits_uhwi_p (tr_size)) | |||
1852 | return false; | |||
1853 | el_size = tree_to_uhwi (tr_size); | |||
1854 | ||||
1855 | minidx = TYPE_MIN_VALUE (TYPE_DOMAIN (type))((tree_check5 ((((tree_check ((type), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 1855, __FUNCTION__, (ARRAY_TYPE)))->type_non_common.values )), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 1855, __FUNCTION__, (INTEGER_TYPE), (ENUMERAL_TYPE), (BOOLEAN_TYPE ), (REAL_TYPE), (FIXED_POINT_TYPE)))->type_non_common.minval ); | |||
1856 | if (TREE_CODE (minidx)((enum tree_code) (minidx)->base.code) != INTEGER_CST || el_size == 0) | |||
1857 | return false; | |||
1858 | index = build_int_cst (TYPE_DOMAIN (type)((tree_check ((type), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 1858, __FUNCTION__, (ARRAY_TYPE)))->type_non_common.values ), offset / el_size); | |||
1859 | if (!integer_zerop (minidx)) | |||
1860 | index = int_const_binop (PLUS_EXPR, index, minidx); | |||
1861 | *res = build4 (ARRAY_REF, TREE_TYPE (type)((contains_struct_check ((type), (TS_TYPED), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 1861, __FUNCTION__))->typed.type), *res, index, | |||
1862 | NULL_TREE(tree) nullptr, NULL_TREE(tree) nullptr); | |||
1863 | offset = offset % el_size; | |||
1864 | type = TREE_TYPE (type)((contains_struct_check ((type), (TS_TYPED), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 1864, __FUNCTION__))->typed.type); | |||
1865 | break; | |||
1866 | ||||
1867 | default: | |||
1868 | if (offset != 0) | |||
1869 | return false; | |||
1870 | ||||
1871 | if (exp_type) | |||
1872 | return false; | |||
1873 | else | |||
1874 | return true; | |||
1875 | } | |||
1876 | } | |||
1877 | } | |||
1878 | ||||
1879 | /* Print message to dump file why a variable was rejected. */ | |||
1880 | ||||
1881 | static void | |||
1882 | reject (tree var, const char *msg) | |||
1883 | { | |||
1884 | if (dump_file && (dump_flags & TDF_DETAILS)) | |||
1885 | { | |||
1886 | fprintf (dump_file, "Rejected (%d): %s: ", DECL_UID (var)((contains_struct_check ((var), (TS_DECL_MINIMAL), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 1886, __FUNCTION__))->decl_minimal.uid), msg); | |||
1887 | print_generic_expr (dump_file, var); | |||
1888 | fprintf (dump_file, "\n"); | |||
1889 | } | |||
1890 | } | |||
1891 | ||||
1892 | /* Return true if VAR is a candidate for SRA. */ | |||
1893 | ||||
1894 | static bool | |||
1895 | maybe_add_sra_candidate (tree var) | |||
1896 | { | |||
1897 | tree type = TREE_TYPE (var)((contains_struct_check ((var), (TS_TYPED), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 1897, __FUNCTION__))->typed.type); | |||
1898 | const char *msg; | |||
1899 | tree_node **slot; | |||
1900 | ||||
1901 | if (!AGGREGATE_TYPE_P (type)(((enum tree_code) (type)->base.code) == ARRAY_TYPE || ((( enum tree_code) (type)->base.code) == RECORD_TYPE || ((enum tree_code) (type)->base.code) == UNION_TYPE || ((enum tree_code ) (type)->base.code) == QUAL_UNION_TYPE))) | |||
1902 | { | |||
1903 | reject (var, "not aggregate"); | |||
1904 | return false; | |||
1905 | } | |||
1906 | /* Allow constant-pool entries that "need to live in memory". */ | |||
1907 | if (needs_to_live_in_memory (var) && !constant_decl_p (var)) | |||
1908 | { | |||
1909 | reject (var, "needs to live in memory"); | |||
1910 | return false; | |||
1911 | } | |||
1912 | if (TREE_THIS_VOLATILE (var)((var)->base.volatile_flag)) | |||
1913 | { | |||
1914 | reject (var, "is volatile"); | |||
1915 | return false; | |||
1916 | } | |||
1917 | if (!COMPLETE_TYPE_P (type)(((tree_class_check ((type), (tcc_type), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 1917, __FUNCTION__))->type_common.size) != (tree) nullptr )) | |||
1918 | { | |||
1919 | reject (var, "has incomplete type"); | |||
1920 | return false; | |||
1921 | } | |||
1922 | if (!tree_fits_shwi_p (TYPE_SIZE (type)((tree_class_check ((type), (tcc_type), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 1922, __FUNCTION__))->type_common.size))) | |||
1923 | { | |||
1924 | reject (var, "type size not fixed"); | |||
1925 | return false; | |||
1926 | } | |||
1927 | if (tree_to_shwi (TYPE_SIZE (type)((tree_class_check ((type), (tcc_type), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 1927, __FUNCTION__))->type_common.size)) == 0) | |||
1928 | { | |||
1929 | reject (var, "type size is zero"); | |||
1930 | return false; | |||
1931 | } | |||
1932 | if (type_internals_preclude_sra_p (type, &msg)) | |||
1933 | { | |||
1934 | reject (var, msg); | |||
1935 | return false; | |||
1936 | } | |||
1937 | if (/* Fix for PR 41089. tree-stdarg.cc needs to have va_lists intact but | |||
1938 | we also want to schedule it rather late. Thus we ignore it in | |||
1939 | the early pass. */ | |||
1940 | (sra_mode == SRA_MODE_EARLY_INTRA | |||
1941 | && is_va_list_type (type))) | |||
1942 | { | |||
1943 | reject (var, "is va_list"); | |||
1944 | return false; | |||
1945 | } | |||
1946 | ||||
1947 | bitmap_set_bit (candidate_bitmap, DECL_UID (var)((contains_struct_check ((var), (TS_DECL_MINIMAL), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 1947, __FUNCTION__))->decl_minimal.uid)); | |||
1948 | slot = candidates->find_slot_with_hash (var, DECL_UID (var)((contains_struct_check ((var), (TS_DECL_MINIMAL), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 1948, __FUNCTION__))->decl_minimal.uid), INSERT); | |||
1949 | *slot = var; | |||
1950 | ||||
1951 | if (dump_file && (dump_flags & TDF_DETAILS)) | |||
1952 | { | |||
1953 | fprintf (dump_file, "Candidate (%d): ", DECL_UID (var)((contains_struct_check ((var), (TS_DECL_MINIMAL), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 1953, __FUNCTION__))->decl_minimal.uid)); | |||
1954 | print_generic_expr (dump_file, var); | |||
1955 | fprintf (dump_file, "\n"); | |||
1956 | } | |||
1957 | ||||
1958 | return true; | |||
1959 | } | |||
1960 | ||||
1961 | /* The very first phase of intraprocedural SRA. It marks in candidate_bitmap | |||
1962 | those with type which is suitable for scalarization. */ | |||
1963 | ||||
1964 | static bool | |||
1965 | find_var_candidates (void) | |||
1966 | { | |||
1967 | tree var, parm; | |||
1968 | unsigned int i; | |||
1969 | bool ret = false; | |||
1970 | ||||
1971 | for (parm = DECL_ARGUMENTS (current_function_decl)((tree_check ((current_function_decl), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 1971, __FUNCTION__, (FUNCTION_DECL)))->function_decl.arguments ); | |||
1972 | parm; | |||
1973 | parm = DECL_CHAIN (parm)(((contains_struct_check (((contains_struct_check ((parm), (TS_DECL_MINIMAL ), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 1973, __FUNCTION__))), (TS_COMMON), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 1973, __FUNCTION__))->common.chain))) | |||
1974 | ret |= maybe_add_sra_candidate (parm); | |||
1975 | ||||
1976 | FOR_EACH_LOCAL_DECL (cfun, i, var)for (i = vec_safe_length (((cfun + 0))->local_decls) - 1; vec_safe_iterate ((((cfun + 0))->local_decls), (i), &(var)); (i)--) | |||
1977 | { | |||
1978 | if (!VAR_P (var)(((enum tree_code) (var)->base.code) == VAR_DECL)) | |||
1979 | continue; | |||
1980 | ||||
1981 | ret |= maybe_add_sra_candidate (var); | |||
1982 | } | |||
1983 | ||||
1984 | return ret; | |||
1985 | } | |||
1986 | ||||
1987 | /* Return true if EXP is a reference chain of COMPONENT_REFs and AREAY_REFs | |||
1988 | ending either with a DECL or a MEM_REF with zero offset. */ | |||
1989 | ||||
1990 | static bool | |||
1991 | path_comparable_for_same_access (tree expr) | |||
1992 | { | |||
1993 | while (handled_component_p (expr)) | |||
1994 | { | |||
1995 | if (TREE_CODE (expr)((enum tree_code) (expr)->base.code) == ARRAY_REF) | |||
1996 | { | |||
1997 | /* SSA name indices can occur here too when the array is of sie one. | |||
1998 | But we cannot just re-use array_refs with SSA names elsewhere in | |||
1999 | the function, so disallow non-constant indices. TODO: Remove this | |||
2000 | limitation after teaching build_reconstructed_reference to replace | |||
2001 | the index with the index type lower bound. */ | |||
2002 | if (TREE_CODE (TREE_OPERAND (expr, 1))((enum tree_code) ((*((const_cast<tree*> (tree_operand_check ((expr), (1), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 2002, __FUNCTION__))))))->base.code) != INTEGER_CST) | |||
2003 | return false; | |||
2004 | } | |||
2005 | expr = TREE_OPERAND (expr, 0)(*((const_cast<tree*> (tree_operand_check ((expr), (0), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 2005, __FUNCTION__))))); | |||
2006 | } | |||
2007 | ||||
2008 | if (TREE_CODE (expr)((enum tree_code) (expr)->base.code) == MEM_REF) | |||
2009 | { | |||
2010 | if (!zerop (TREE_OPERAND (expr, 1)(*((const_cast<tree*> (tree_operand_check ((expr), (1), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 2010, __FUNCTION__))))))) | |||
2011 | return false; | |||
2012 | } | |||
2013 | else | |||
2014 | gcc_assert (DECL_P (expr))((void)(!((tree_code_type_tmpl <0>::tree_code_type[(int ) (((enum tree_code) (expr)->base.code))] == tcc_declaration )) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 2014, __FUNCTION__), 0 : 0)); | |||
2015 | ||||
2016 | return true; | |||
2017 | } | |||
2018 | ||||
2019 | /* Assuming that EXP1 consists of only COMPONENT_REFs and ARRAY_REFs, return | |||
2020 | true if the chain of these handled components are exactly the same as EXP2 | |||
2021 | and the expression under them is the same DECL or an equivalent MEM_REF. | |||
2022 | The reference picked by compare_access_positions must go to EXP1. */ | |||
2023 | ||||
2024 | static bool | |||
2025 | same_access_path_p (tree exp1, tree exp2) | |||
2026 | { | |||
2027 | if (TREE_CODE (exp1)((enum tree_code) (exp1)->base.code) != TREE_CODE (exp2)((enum tree_code) (exp2)->base.code)) | |||
2028 | { | |||
2029 | /* Special case single-field structures loaded sometimes as the field | |||
2030 | and sometimes as the structure. If the field is of a scalar type, | |||
2031 | compare_access_positions will put it into exp1. | |||
2032 | ||||
2033 | TODO: The gimple register type condition can be removed if teach | |||
2034 | compare_access_positions to put inner types first. */ | |||
2035 | if (is_gimple_reg_type (TREE_TYPE (exp1)((contains_struct_check ((exp1), (TS_TYPED), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 2035, __FUNCTION__))->typed.type)) | |||
2036 | && TREE_CODE (exp1)((enum tree_code) (exp1)->base.code) == COMPONENT_REF | |||
2037 | && (TYPE_MAIN_VARIANT (TREE_TYPE (TREE_OPERAND (exp1, 0)))((tree_class_check ((((contains_struct_check (((*((const_cast <tree*> (tree_operand_check ((exp1), (0), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 2037, __FUNCTION__)))))), (TS_TYPED), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 2037, __FUNCTION__))->typed.type)), (tcc_type), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 2037, __FUNCTION__))->type_common.main_variant) | |||
2038 | == TYPE_MAIN_VARIANT (TREE_TYPE (exp2))((tree_class_check ((((contains_struct_check ((exp2), (TS_TYPED ), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 2038, __FUNCTION__))->typed.type)), (tcc_type), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 2038, __FUNCTION__))->type_common.main_variant))) | |||
2039 | exp1 = TREE_OPERAND (exp1, 0)(*((const_cast<tree*> (tree_operand_check ((exp1), (0), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 2039, __FUNCTION__))))); | |||
2040 | else | |||
2041 | return false; | |||
2042 | } | |||
2043 | ||||
2044 | if (!operand_equal_p (exp1, exp2, OEP_ADDRESS_OF)) | |||
2045 | return false; | |||
2046 | ||||
2047 | return true; | |||
2048 | } | |||
2049 | ||||
2050 | /* Sort all accesses for the given variable, check for partial overlaps and | |||
2051 | return NULL if there are any. If there are none, pick a representative for | |||
2052 | each combination of offset and size and create a linked list out of them. | |||
2053 | Return the pointer to the first representative and make sure it is the first | |||
2054 | one in the vector of accesses. */ | |||
2055 | ||||
2056 | static struct access * | |||
2057 | sort_and_splice_var_accesses (tree var) | |||
2058 | { | |||
2059 | int i, j, access_count; | |||
2060 | struct access *res, **prev_acc_ptr = &res; | |||
2061 | vec<access_p> *access_vec; | |||
2062 | bool first = true; | |||
2063 | HOST_WIDE_INTlong low = -1, high = 0; | |||
2064 | ||||
2065 | access_vec = get_base_access_vector (var); | |||
2066 | if (!access_vec) | |||
2067 | return NULLnullptr; | |||
2068 | access_count = access_vec->length (); | |||
2069 | ||||
2070 | /* Sort by <OFFSET, SIZE>. */ | |||
2071 | access_vec->qsort (compare_access_positions)qsort (compare_access_positions); | |||
2072 | ||||
2073 | i = 0; | |||
2074 | while (i < access_count) | |||
2075 | { | |||
2076 | struct access *access = (*access_vec)[i]; | |||
2077 | bool grp_write = access->write; | |||
2078 | bool grp_read = !access->write; | |||
2079 | bool grp_scalar_write = access->write | |||
2080 | && is_gimple_reg_type (access->type); | |||
2081 | bool grp_scalar_read = !access->write | |||
2082 | && is_gimple_reg_type (access->type); | |||
2083 | bool grp_assignment_read = access->grp_assignment_read; | |||
2084 | bool grp_assignment_write = access->grp_assignment_write; | |||
2085 | bool multiple_scalar_reads = false; | |||
2086 | bool grp_partial_lhs = access->grp_partial_lhs; | |||
2087 | bool first_scalar = is_gimple_reg_type (access->type); | |||
2088 | bool unscalarizable_region = access->grp_unscalarizable_region; | |||
2089 | bool grp_same_access_path = true; | |||
2090 | bool bf_non_full_precision | |||
2091 | = (INTEGRAL_TYPE_P (access->type)(((enum tree_code) (access->type)->base.code) == ENUMERAL_TYPE || ((enum tree_code) (access->type)->base.code) == BOOLEAN_TYPE || ((enum tree_code) (access->type)->base.code) == INTEGER_TYPE ) | |||
2092 | && TYPE_PRECISION (access->type)((tree_class_check ((access->type), (tcc_type), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 2092, __FUNCTION__))->type_common.precision) != access->size | |||
2093 | && TREE_CODE (access->expr)((enum tree_code) (access->expr)->base.code) == COMPONENT_REF | |||
2094 | && DECL_BIT_FIELD (TREE_OPERAND (access->expr, 1))((tree_check (((*((const_cast<tree*> (tree_operand_check ((access->expr), (1), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 2094, __FUNCTION__)))))), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 2094, __FUNCTION__, (FIELD_DECL)))->decl_common.decl_flag_1 )); | |||
2095 | ||||
2096 | if (first || access->offset >= high) | |||
2097 | { | |||
2098 | first = false; | |||
2099 | low = access->offset; | |||
2100 | high = access->offset + access->size; | |||
2101 | } | |||
2102 | else if (access->offset > low && access->offset + access->size > high) | |||
2103 | return NULLnullptr; | |||
2104 | else | |||
2105 | gcc_assert (access->offset >= low((void)(!(access->offset >= low && access->offset + access->size <= high) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 2106, __FUNCTION__), 0 : 0)) | |||
2106 | && access->offset + access->size <= high)((void)(!(access->offset >= low && access->offset + access->size <= high) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 2106, __FUNCTION__), 0 : 0)); | |||
2107 | ||||
2108 | grp_same_access_path = path_comparable_for_same_access (access->expr); | |||
2109 | ||||
2110 | j = i + 1; | |||
2111 | while (j < access_count) | |||
2112 | { | |||
2113 | struct access *ac2 = (*access_vec)[j]; | |||
2114 | if (ac2->offset != access->offset || ac2->size != access->size) | |||
2115 | break; | |||
2116 | if (ac2->write) | |||
2117 | { | |||
2118 | grp_write = true; | |||
2119 | grp_scalar_write = (grp_scalar_write | |||
2120 | || is_gimple_reg_type (ac2->type)); | |||
2121 | } | |||
2122 | else | |||
2123 | { | |||
2124 | grp_read = true; | |||
2125 | if (is_gimple_reg_type (ac2->type)) | |||
2126 | { | |||
2127 | if (grp_scalar_read) | |||
2128 | multiple_scalar_reads = true; | |||
2129 | else | |||
2130 | grp_scalar_read = true; | |||
2131 | } | |||
2132 | } | |||
2133 | grp_assignment_read |= ac2->grp_assignment_read; | |||
2134 | grp_assignment_write |= ac2->grp_assignment_write; | |||
2135 | grp_partial_lhs |= ac2->grp_partial_lhs; | |||
2136 | unscalarizable_region |= ac2->grp_unscalarizable_region; | |||
2137 | relink_to_new_repr (access, ac2); | |||
2138 | ||||
2139 | /* If there are both aggregate-type and scalar-type accesses with | |||
2140 | this combination of size and offset, the comparison function | |||
2141 | should have put the scalars first. */ | |||
2142 | gcc_assert (first_scalar || !is_gimple_reg_type (ac2->type))((void)(!(first_scalar || !is_gimple_reg_type (ac2->type)) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 2142, __FUNCTION__), 0 : 0)); | |||
2143 | /* It also prefers integral types to non-integral. However, when the | |||
2144 | precision of the selected type does not span the entire area and | |||
2145 | should also be used for a non-integer (i.e. float), we must not | |||
2146 | let that happen. Normally analyze_access_subtree expands the type | |||
2147 | to cover the entire area but for bit-fields it doesn't. */ | |||
2148 | if (bf_non_full_precision && !INTEGRAL_TYPE_P (ac2->type)(((enum tree_code) (ac2->type)->base.code) == ENUMERAL_TYPE || ((enum tree_code) (ac2->type)->base.code) == BOOLEAN_TYPE || ((enum tree_code) (ac2->type)->base.code) == INTEGER_TYPE )) | |||
2149 | { | |||
2150 | if (dump_file && (dump_flags & TDF_DETAILS)) | |||
2151 | { | |||
2152 | fprintf (dump_file, "Cannot scalarize the following access " | |||
2153 | "because insufficient precision integer type was " | |||
2154 | "selected.\n "); | |||
2155 | dump_access (dump_file, access, false); | |||
2156 | } | |||
2157 | unscalarizable_region = true; | |||
2158 | } | |||
2159 | ||||
2160 | if (grp_same_access_path | |||
2161 | && !same_access_path_p (access->expr, ac2->expr)) | |||
2162 | grp_same_access_path = false; | |||
2163 | ||||
2164 | ac2->group_representative = access; | |||
2165 | j++; | |||
2166 | } | |||
2167 | ||||
2168 | i = j; | |||
2169 | ||||
2170 | access->group_representative = access; | |||
2171 | access->grp_write = grp_write; | |||
2172 | access->grp_read = grp_read; | |||
2173 | access->grp_scalar_read = grp_scalar_read; | |||
2174 | access->grp_scalar_write = grp_scalar_write; | |||
2175 | access->grp_assignment_read = grp_assignment_read; | |||
2176 | access->grp_assignment_write = grp_assignment_write; | |||
2177 | access->grp_hint = multiple_scalar_reads && !constant_decl_p (var); | |||
2178 | access->grp_partial_lhs = grp_partial_lhs; | |||
2179 | access->grp_unscalarizable_region = unscalarizable_region; | |||
2180 | access->grp_same_access_path = grp_same_access_path; | |||
2181 | ||||
2182 | *prev_acc_ptr = access; | |||
2183 | prev_acc_ptr = &access->next_grp; | |||
2184 | } | |||
2185 | ||||
2186 | gcc_assert (res == (*access_vec)[0])((void)(!(res == (*access_vec)[0]) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 2186, __FUNCTION__), 0 : 0)); | |||
| ||||
2187 | return res; | |||
2188 | } | |||
2189 | ||||
2190 | /* Create a variable for the given ACCESS which determines the type, name and a | |||
2191 | few other properties. Return the variable declaration and store it also to | |||
2192 | ACCESS->replacement. REG_TREE is used when creating a declaration to base a | |||
2193 | default-definition SSA name on in order to facilitate an uninitialized | |||
2194 | warning. It is used instead of the actual ACCESS type if that is not of a | |||
2195 | gimple register type. */ | |||
2196 | ||||
2197 | static tree | |||
2198 | create_access_replacement (struct access *access, tree reg_type = NULL_TREE(tree) nullptr) | |||
2199 | { | |||
2200 | tree repl; | |||
2201 | ||||
2202 | tree type = access->type; | |||
2203 | if (reg_type && !is_gimple_reg_type (type)) | |||
2204 | type = reg_type; | |||
2205 | ||||
2206 | if (access->grp_to_be_debug_replaced) | |||
2207 | { | |||
2208 | repl = create_tmp_var_raw (access->type); | |||
2209 | DECL_CONTEXT (repl)((contains_struct_check ((repl), (TS_DECL_MINIMAL), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 2209, __FUNCTION__))->decl_minimal.context) = current_function_decl; | |||
2210 | } | |||
2211 | else | |||
2212 | /* Drop any special alignment on the type if it's not on the main | |||
2213 | variant. This avoids issues with weirdo ABIs like AAPCS. */ | |||
2214 | repl = create_tmp_var (build_qualified_type (TYPE_MAIN_VARIANT (type)((tree_class_check ((type), (tcc_type), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 2214, __FUNCTION__))->type_common.main_variant), | |||
2215 | TYPE_QUALS (type)((int) ((((tree_class_check ((type), (tcc_type), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 2215, __FUNCTION__))->base.readonly_flag) * TYPE_QUAL_CONST ) | (((tree_class_check ((type), (tcc_type), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 2215, __FUNCTION__))->base.volatile_flag) * TYPE_QUAL_VOLATILE ) | (((tree_class_check ((type), (tcc_type), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 2215, __FUNCTION__))->base.u.bits.atomic_flag) * TYPE_QUAL_ATOMIC ) | (((tree_class_check ((type), (tcc_type), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 2215, __FUNCTION__))->type_common.restrict_flag) * TYPE_QUAL_RESTRICT ) | (((((tree_class_check ((type), (tcc_type), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 2215, __FUNCTION__))->base.u.bits.address_space) & 0xFF ) << 8))))), "SR"); | |||
2216 | if (access->grp_partial_lhs | |||
2217 | && is_gimple_reg_type (type)) | |||
2218 | DECL_NOT_GIMPLE_REG_P (repl)(contains_struct_check ((repl), (TS_DECL_COMMON), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 2218, __FUNCTION__))->decl_common.not_gimple_reg_flag = 1; | |||
2219 | ||||
2220 | DECL_SOURCE_LOCATION (repl)((contains_struct_check ((repl), (TS_DECL_MINIMAL), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 2220, __FUNCTION__))->decl_minimal.locus) = DECL_SOURCE_LOCATION (access->base)((contains_struct_check ((access->base), (TS_DECL_MINIMAL) , "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 2220, __FUNCTION__))->decl_minimal.locus); | |||
2221 | DECL_ARTIFICIAL (repl)((contains_struct_check ((repl), (TS_DECL_COMMON), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 2221, __FUNCTION__))->decl_common.artificial_flag) = 1; | |||
2222 | DECL_IGNORED_P (repl)((contains_struct_check ((repl), (TS_DECL_COMMON), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 2222, __FUNCTION__))->decl_common.ignored_flag) = DECL_IGNORED_P (access->base)((contains_struct_check ((access->base), (TS_DECL_COMMON), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 2222, __FUNCTION__))->decl_common.ignored_flag); | |||
2223 | ||||
2224 | if (DECL_NAME (access->base)((contains_struct_check ((access->base), (TS_DECL_MINIMAL) , "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 2224, __FUNCTION__))->decl_minimal.name) | |||
2225 | && !DECL_IGNORED_P (access->base)((contains_struct_check ((access->base), (TS_DECL_COMMON), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 2225, __FUNCTION__))->decl_common.ignored_flag) | |||
2226 | && !DECL_ARTIFICIAL (access->base)((contains_struct_check ((access->base), (TS_DECL_COMMON), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 2226, __FUNCTION__))->decl_common.artificial_flag)) | |||
2227 | { | |||
2228 | char *pretty_name = make_fancy_name (access->expr); | |||
2229 | tree debug_expr = unshare_expr_without_location (access->expr), d; | |||
2230 | bool fail = false; | |||
2231 | ||||
2232 | DECL_NAME (repl)((contains_struct_check ((repl), (TS_DECL_MINIMAL), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 2232, __FUNCTION__))->decl_minimal.name) = get_identifier (pretty_name)(__builtin_constant_p (pretty_name) ? get_identifier_with_length ((pretty_name), strlen (pretty_name)) : get_identifier (pretty_name )); | |||
2233 | DECL_NAMELESS (repl)((contains_struct_check ((repl), (TS_DECL_MINIMAL), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 2233, __FUNCTION__))->base.u.bits.nameless_flag) = 1; | |||
2234 | obstack_free (&name_obstack, pretty_name)__extension__ ({ struct obstack *__o = (&name_obstack); void *__obj = (void *) (pretty_name); if (__obj > (void *) __o ->chunk && __obj < (void *) __o->chunk_limit ) __o->next_free = __o->object_base = (char *) __obj; else _obstack_free (__o, __obj); }); | |||
2235 | ||||
2236 | /* Get rid of any SSA_NAMEs embedded in debug_expr, | |||
2237 | as DECL_DEBUG_EXPR isn't considered when looking for still | |||
2238 | used SSA_NAMEs and thus they could be freed. All debug info | |||
2239 | generation cares is whether something is constant or variable | |||
2240 | and that get_ref_base_and_extent works properly on the | |||
2241 | expression. It cannot handle accesses at a non-constant offset | |||
2242 | though, so just give up in those cases. */ | |||
2243 | for (d = debug_expr; | |||
2244 | !fail && (handled_component_p (d) || TREE_CODE (d)((enum tree_code) (d)->base.code) == MEM_REF); | |||
2245 | d = TREE_OPERAND (d, 0)(*((const_cast<tree*> (tree_operand_check ((d), (0), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 2245, __FUNCTION__)))))) | |||
2246 | switch (TREE_CODE (d)((enum tree_code) (d)->base.code)) | |||
2247 | { | |||
2248 | case ARRAY_REF: | |||
2249 | case ARRAY_RANGE_REF: | |||
2250 | if (TREE_OPERAND (d, 1)(*((const_cast<tree*> (tree_operand_check ((d), (1), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 2250, __FUNCTION__))))) | |||
2251 | && TREE_CODE (TREE_OPERAND (d, 1))((enum tree_code) ((*((const_cast<tree*> (tree_operand_check ((d), (1), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 2251, __FUNCTION__))))))->base.code) != INTEGER_CST) | |||
2252 | fail = true; | |||
2253 | if (TREE_OPERAND (d, 3)(*((const_cast<tree*> (tree_operand_check ((d), (3), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 2253, __FUNCTION__))))) | |||
2254 | && TREE_CODE (TREE_OPERAND (d, 3))((enum tree_code) ((*((const_cast<tree*> (tree_operand_check ((d), (3), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 2254, __FUNCTION__))))))->base.code) != INTEGER_CST) | |||
2255 | fail = true; | |||
2256 | /* FALLTHRU */ | |||
2257 | case COMPONENT_REF: | |||
2258 | if (TREE_OPERAND (d, 2)(*((const_cast<tree*> (tree_operand_check ((d), (2), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 2258, __FUNCTION__))))) | |||
2259 | && TREE_CODE (TREE_OPERAND (d, 2))((enum tree_code) ((*((const_cast<tree*> (tree_operand_check ((d), (2), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 2259, __FUNCTION__))))))->base.code) != INTEGER_CST) | |||
2260 | fail = true; | |||
2261 | break; | |||
2262 | case MEM_REF: | |||
2263 | if (TREE_CODE (TREE_OPERAND (d, 0))((enum tree_code) ((*((const_cast<tree*> (tree_operand_check ((d), (0), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 2263, __FUNCTION__))))))->base.code) != ADDR_EXPR) | |||
2264 | fail = true; | |||
2265 | else | |||
2266 | d = TREE_OPERAND (d, 0)(*((const_cast<tree*> (tree_operand_check ((d), (0), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 2266, __FUNCTION__))))); | |||
2267 | break; | |||
2268 | default: | |||
2269 | break; | |||
2270 | } | |||
2271 | if (!fail) | |||
2272 | { | |||
2273 | SET_DECL_DEBUG_EXPR (repl, debug_expr)(decl_debug_expr_insert ((tree_check ((repl), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 2273, __FUNCTION__, (VAR_DECL))), debug_expr)); | |||
2274 | DECL_HAS_DEBUG_EXPR_P (repl)((tree_check ((repl), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 2274, __FUNCTION__, (VAR_DECL)))->decl_common.debug_expr_is_from ) = 1; | |||
2275 | } | |||
2276 | if (access->grp_no_warning) | |||
2277 | suppress_warning (repl /* Be more selective! */); | |||
2278 | else | |||
2279 | copy_warning (repl, access->base); | |||
2280 | } | |||
2281 | else | |||
2282 | suppress_warning (repl /* Be more selective! */); | |||
2283 | ||||
2284 | if (dump_file) | |||
2285 | { | |||
2286 | if (access->grp_to_be_debug_replaced) | |||
2287 | { | |||
2288 | fprintf (dump_file, "Created a debug-only replacement for "); | |||
2289 | print_generic_expr (dump_file, access->base); | |||
2290 | fprintf (dump_file, " offset: %u, size: %u\n", | |||
2291 | (unsigned) access->offset, (unsigned) access->size); | |||
2292 | } | |||
2293 | else | |||
2294 | { | |||
2295 | fprintf (dump_file, "Created a replacement for "); | |||
2296 | print_generic_expr (dump_file, access->base); | |||
2297 | fprintf (dump_file, " offset: %u, size: %u: ", | |||
2298 | (unsigned) access->offset, (unsigned) access->size); | |||
2299 | print_generic_expr (dump_file, repl, TDF_UID); | |||
2300 | fprintf (dump_file, "\n"); | |||
2301 | } | |||
2302 | } | |||
2303 | sra_stats.replacements++; | |||
2304 | ||||
2305 | return repl; | |||
2306 | } | |||
2307 | ||||
2308 | /* Return ACCESS scalar replacement, which must exist. */ | |||
2309 | ||||
2310 | static inline tree | |||
2311 | get_access_replacement (struct access *access) | |||
2312 | { | |||
2313 | gcc_checking_assert (access->replacement_decl)((void)(!(access->replacement_decl) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 2313, __FUNCTION__), 0 : 0)); | |||
2314 | return access->replacement_decl; | |||
2315 | } | |||
2316 | ||||
2317 | ||||
2318 | /* Build a subtree of accesses rooted in *ACCESS, and move the pointer in the | |||
2319 | linked list along the way. Stop when *ACCESS is NULL or the access pointed | |||
2320 | to it is not "within" the root. Return false iff some accesses partially | |||
2321 | overlap. */ | |||
2322 | ||||
2323 | static bool | |||
2324 | build_access_subtree (struct access **access) | |||
2325 | { | |||
2326 | struct access *root = *access, *last_child = NULLnullptr; | |||
2327 | HOST_WIDE_INTlong limit = root->offset + root->size; | |||
2328 | ||||
2329 | *access = (*access)->next_grp; | |||
2330 | while (*access && (*access)->offset + (*access)->size <= limit) | |||
2331 | { | |||
2332 | if (!last_child) | |||
2333 | root->first_child = *access; | |||
2334 | else | |||
2335 | last_child->next_sibling = *access; | |||
2336 | last_child = *access; | |||
2337 | (*access)->parent = root; | |||
2338 | (*access)->grp_write |= root->grp_write; | |||
2339 | ||||
2340 | if (!build_access_subtree (access)) | |||
2341 | return false; | |||
2342 | } | |||
2343 | ||||
2344 | if (*access && (*access)->offset < limit) | |||
2345 | return false; | |||
2346 | ||||
2347 | return true; | |||
2348 | } | |||
2349 | ||||
2350 | /* Build a tree of access representatives, ACCESS is the pointer to the first | |||
2351 | one, others are linked in a list by the next_grp field. Return false iff | |||
2352 | some accesses partially overlap. */ | |||
2353 | ||||
2354 | static bool | |||
2355 | build_access_trees (struct access *access) | |||
2356 | { | |||
2357 | while (access) | |||
2358 | { | |||
2359 | struct access *root = access; | |||
2360 | ||||
2361 | if (!build_access_subtree (&access)) | |||
2362 | return false; | |||
2363 | root->next_grp = access; | |||
2364 | } | |||
2365 | return true; | |||
2366 | } | |||
2367 | ||||
2368 | /* Traverse the access forest where ROOT is the first root and verify that | |||
2369 | various important invariants hold true. */ | |||
2370 | ||||
2371 | DEBUG_FUNCTION__attribute__ ((__used__)) void | |||
2372 | verify_sra_access_forest (struct access *root) | |||
2373 | { | |||
2374 | struct access *access = root; | |||
2375 | tree first_base = root->base; | |||
2376 | gcc_assert (DECL_P (first_base))((void)(!((tree_code_type_tmpl <0>::tree_code_type[(int ) (((enum tree_code) (first_base)->base.code))] == tcc_declaration )) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 2376, __FUNCTION__), 0 : 0)); | |||
2377 | do | |||
2378 | { | |||
2379 | gcc_assert (access->base == first_base)((void)(!(access->base == first_base) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 2379, __FUNCTION__), 0 : 0)); | |||
2380 | if (access->parent) | |||
2381 | gcc_assert (access->offset >= access->parent->offset((void)(!(access->offset >= access->parent->offset && access->size <= access->parent->size) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 2382, __FUNCTION__), 0 : 0)) | |||
2382 | && access->size <= access->parent->size)((void)(!(access->offset >= access->parent->offset && access->size <= access->parent->size) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 2382, __FUNCTION__), 0 : 0)); | |||
2383 | if (access->next_sibling) | |||
2384 | gcc_assert (access->next_sibling->offset((void)(!(access->next_sibling->offset >= access-> offset + access->size) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 2385, __FUNCTION__), 0 : 0)) | |||
2385 | >= access->offset + access->size)((void)(!(access->next_sibling->offset >= access-> offset + access->size) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 2385, __FUNCTION__), 0 : 0)); | |||
2386 | ||||
2387 | poly_int64 poffset, psize, pmax_size; | |||
2388 | bool reverse; | |||
2389 | tree base = get_ref_base_and_extent (access->expr, &poffset, &psize, | |||
2390 | &pmax_size, &reverse); | |||
2391 | HOST_WIDE_INTlong offset, size, max_size; | |||
2392 | if (!poffset.is_constant (&offset) | |||
2393 | || !psize.is_constant (&size) | |||
2394 | || !pmax_size.is_constant (&max_size)) | |||
2395 | gcc_unreachable ()(fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 2395, __FUNCTION__)); | |||
2396 | gcc_assert (base == first_base)((void)(!(base == first_base) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 2396, __FUNCTION__), 0 : 0)); | |||
2397 | gcc_assert (offset == access->offset)((void)(!(offset == access->offset) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 2397, __FUNCTION__), 0 : 0)); | |||
2398 | gcc_assert (access->grp_unscalarizable_region((void)(!(access->grp_unscalarizable_region || access-> grp_total_scalarization || size == max_size) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 2400, __FUNCTION__), 0 : 0)) | |||
2399 | || access->grp_total_scalarization((void)(!(access->grp_unscalarizable_region || access-> grp_total_scalarization || size == max_size) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 2400, __FUNCTION__), 0 : 0)) | |||
2400 | || size == max_size)((void)(!(access->grp_unscalarizable_region || access-> grp_total_scalarization || size == max_size) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 2400, __FUNCTION__), 0 : 0)); | |||
2401 | gcc_assert (access->grp_unscalarizable_region((void)(!(access->grp_unscalarizable_region || !is_gimple_reg_type (access->type) || size == access->size) ? fancy_abort ( "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 2403, __FUNCTION__), 0 : 0)) | |||
2402 | || !is_gimple_reg_type (access->type)((void)(!(access->grp_unscalarizable_region || !is_gimple_reg_type (access->type) || size == access->size) ? fancy_abort ( "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 2403, __FUNCTION__), 0 : 0)) | |||
2403 | || size == access->size)((void)(!(access->grp_unscalarizable_region || !is_gimple_reg_type (access->type) || size == access->size) ? fancy_abort ( "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 2403, __FUNCTION__), 0 : 0)); | |||
2404 | gcc_assert (reverse == access->reverse)((void)(!(reverse == access->reverse) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 2404, __FUNCTION__), 0 : 0)); | |||
2405 | ||||
2406 | if (access->first_child) | |||
2407 | { | |||
2408 | gcc_assert (access->first_child->parent == access)((void)(!(access->first_child->parent == access) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 2408, __FUNCTION__), 0 : 0)); | |||
2409 | access = access->first_child; | |||
2410 | } | |||
2411 | else if (access->next_sibling) | |||
2412 | { | |||
2413 | gcc_assert (access->next_sibling->parent == access->parent)((void)(!(access->next_sibling->parent == access->parent ) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 2413, __FUNCTION__), 0 : 0)); | |||
2414 | access = access->next_sibling; | |||
2415 | } | |||
2416 | else | |||
2417 | { | |||
2418 | while (access->parent && !access->next_sibling) | |||
2419 | access = access->parent; | |||
2420 | if (access->next_sibling) | |||
2421 | access = access->next_sibling; | |||
2422 | else | |||
2423 | { | |||
2424 | gcc_assert (access == root)((void)(!(access == root) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 2424, __FUNCTION__), 0 : 0)); | |||
2425 | root = root->next_grp; | |||
2426 | access = root; | |||
2427 | } | |||
2428 | } | |||
2429 | } | |||
2430 | while (access); | |||
2431 | } | |||
2432 | ||||
2433 | /* Verify access forests of all candidates with accesses by calling | |||
2434 | verify_access_forest on each on them. */ | |||
2435 | ||||
2436 | DEBUG_FUNCTION__attribute__ ((__used__)) void | |||
2437 | verify_all_sra_access_forests (void) | |||
2438 | { | |||
2439 | bitmap_iterator bi; | |||
2440 | unsigned i; | |||
2441 | EXECUTE_IF_SET_IN_BITMAP (candidate_bitmap, 0, i, bi)for (bmp_iter_set_init (&(bi), (candidate_bitmap), (0), & (i)); bmp_iter_set (&(bi), &(i)); bmp_iter_next (& (bi), &(i))) | |||
2442 | { | |||
2443 | tree var = candidate (i); | |||
2444 | struct access *access = get_first_repr_for_decl (var); | |||
2445 | if (access) | |||
2446 | { | |||
2447 | gcc_assert (access->base == var)((void)(!(access->base == var) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 2447, __FUNCTION__), 0 : 0)); | |||
2448 | verify_sra_access_forest (access); | |||
2449 | } | |||
2450 | } | |||
2451 | } | |||
2452 | ||||
2453 | /* Return true if expr contains some ARRAY_REFs into a variable bounded | |||
2454 | array. */ | |||
2455 | ||||
2456 | static bool | |||
2457 | expr_with_var_bounded_array_refs_p (tree expr) | |||
2458 | { | |||
2459 | while (handled_component_p (expr)) | |||
2460 | { | |||
2461 | if (TREE_CODE (expr)((enum tree_code) (expr)->base.code) == ARRAY_REF | |||
2462 | && !tree_fits_shwi_p (array_ref_low_bound (expr))) | |||
2463 | return true; | |||
2464 | expr = TREE_OPERAND (expr, 0)(*((const_cast<tree*> (tree_operand_check ((expr), (0), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 2464, __FUNCTION__))))); | |||
2465 | } | |||
2466 | return false; | |||
2467 | } | |||
2468 | ||||
2469 | /* Analyze the subtree of accesses rooted in ROOT, scheduling replacements when | |||
2470 | both seeming beneficial and when ALLOW_REPLACEMENTS allows it. If TOTALLY | |||
2471 | is set, we are totally scalarizing the aggregate. Also set all sorts of | |||
2472 | access flags appropriately along the way, notably always set grp_read and | |||
2473 | grp_assign_read according to MARK_READ and grp_write when MARK_WRITE is | |||
2474 | true. | |||
2475 | ||||
2476 | Creating a replacement for a scalar access is considered beneficial if its | |||
2477 | grp_hint ot TOTALLY is set (this means either that there is more than one | |||
2478 | direct read access or that we are attempting total scalarization) or | |||
2479 | according to the following table: | |||
2480 | ||||
2481 | Access written to through a scalar type (once or more times) | |||
2482 | | | |||
2483 | | Written to in an assignment statement | |||
2484 | | | | |||
2485 | | | Access read as scalar _once_ | |||
2486 | | | | | |||
2487 | | | | Read in an assignment statement | |||
2488 | | | | | | |||
2489 | | | | | Scalarize Comment | |||
2490 | ----------------------------------------------------------------------------- | |||
2491 | 0 0 0 0 No access for the scalar | |||
2492 | 0 0 0 1 No access for the scalar | |||
2493 | 0 0 1 0 No Single read - won't help | |||
2494 | 0 0 1 1 No The same case | |||
2495 | 0 1 0 0 No access for the scalar | |||
2496 | 0 1 0 1 No access for the scalar | |||
2497 | 0 1 1 0 Yes s = *g; return s.i; | |||
2498 | 0 1 1 1 Yes The same case as above | |||
2499 | 1 0 0 0 No Won't help | |||
2500 | 1 0 0 1 Yes s.i = 1; *g = s; | |||
2501 | 1 0 1 0 Yes s.i = 5; g = s.i; | |||
2502 | 1 0 1 1 Yes The same case as above | |||
2503 | 1 1 0 0 No Won't help. | |||
2504 | 1 1 0 1 Yes s.i = 1; *g = s; | |||
2505 | 1 1 1 0 Yes s = *g; return s.i; | |||
2506 | 1 1 1 1 Yes Any of the above yeses */ | |||
2507 | ||||
2508 | static bool | |||
2509 | analyze_access_subtree (struct access *root, struct access *parent, | |||
2510 | bool allow_replacements, bool totally) | |||
2511 | { | |||
2512 | struct access *child; | |||
2513 | HOST_WIDE_INTlong limit = root->offset + root->size; | |||
2514 | HOST_WIDE_INTlong covered_to = root->offset; | |||
2515 | bool scalar = is_gimple_reg_type (root->type); | |||
2516 | bool hole = false, sth_created = false; | |||
2517 | ||||
2518 | if (parent) | |||
2519 | { | |||
2520 | if (parent->grp_read) | |||
2521 | root->grp_read = 1; | |||
2522 | if (parent->grp_assignment_read) | |||
2523 | root->grp_assignment_read = 1; | |||
2524 | if (parent->grp_write) | |||
2525 | root->grp_write = 1; | |||
2526 | if (parent->grp_assignment_write) | |||
2527 | root->grp_assignment_write = 1; | |||
2528 | if (!parent->grp_same_access_path) | |||
2529 | root->grp_same_access_path = 0; | |||
2530 | } | |||
2531 | ||||
2532 | if (root->grp_unscalarizable_region) | |||
2533 | allow_replacements = false; | |||
2534 | ||||
2535 | if (allow_replacements && expr_with_var_bounded_array_refs_p (root->expr)) | |||
2536 | allow_replacements = false; | |||
2537 | ||||
2538 | if (!totally && root->grp_result_of_prop_from_lhs) | |||
2539 | allow_replacements = false; | |||
2540 | ||||
2541 | for (child = root->first_child; child; child = child->next_sibling) | |||
2542 | { | |||
2543 | hole |= covered_to < child->offset; | |||
2544 | sth_created |= analyze_access_subtree (child, root, | |||
2545 | allow_replacements && !scalar, | |||
2546 | totally); | |||
2547 | ||||
2548 | root->grp_unscalarized_data |= child->grp_unscalarized_data; | |||
2549 | if (child->grp_covered) | |||
2550 | covered_to += child->size; | |||
2551 | else | |||
2552 | hole = true; | |||
2553 | } | |||
2554 | ||||
2555 | if (allow_replacements && scalar && !root->first_child | |||
2556 | && (totally || !root->grp_total_scalarization) | |||
2557 | && (totally | |||
2558 | || root->grp_hint | |||
2559 | || ((root->grp_scalar_read || root->grp_assignment_read) | |||
2560 | && (root->grp_scalar_write || root->grp_assignment_write)))) | |||
2561 | { | |||
2562 | /* Always create access replacements that cover the whole access. | |||
2563 | For integral types this means the precision has to match. | |||
2564 | Avoid assumptions based on the integral type kind, too. */ | |||
2565 | if (INTEGRAL_TYPE_P (root->type)(((enum tree_code) (root->type)->base.code) == ENUMERAL_TYPE || ((enum tree_code) (root->type)->base.code) == BOOLEAN_TYPE || ((enum tree_code) (root->type)->base.code) == INTEGER_TYPE ) | |||
2566 | && (TREE_CODE (root->type)((enum tree_code) (root->type)->base.code) != INTEGER_TYPE | |||
2567 | || TYPE_PRECISION (root->type)((tree_class_check ((root->type), (tcc_type), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 2567, __FUNCTION__))->type_common.precision) != root->size) | |||
2568 | /* But leave bitfield accesses alone. */ | |||
2569 | && (TREE_CODE (root->expr)((enum tree_code) (root->expr)->base.code) != COMPONENT_REF | |||
2570 | || !DECL_BIT_FIELD (TREE_OPERAND (root->expr, 1))((tree_check (((*((const_cast<tree*> (tree_operand_check ((root->expr), (1), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 2570, __FUNCTION__)))))), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 2570, __FUNCTION__, (FIELD_DECL)))->decl_common.decl_flag_1 ))) | |||
2571 | { | |||
2572 | tree rt = root->type; | |||
2573 | gcc_assert ((root->offset % BITS_PER_UNIT) == 0((void)(!((root->offset % (8)) == 0 && (root->size % (8)) == 0) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 2574, __FUNCTION__), 0 : 0)) | |||
2574 | && (root->size % BITS_PER_UNIT) == 0)((void)(!((root->offset % (8)) == 0 && (root->size % (8)) == 0) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 2574, __FUNCTION__), 0 : 0)); | |||
2575 | root->type = build_nonstandard_integer_type (root->size, | |||
2576 | TYPE_UNSIGNED (rt)((tree_class_check ((rt), (tcc_type), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 2576, __FUNCTION__))->base.u.bits.unsigned_flag)); | |||
2577 | root->expr = build_ref_for_offset (UNKNOWN_LOCATION((location_t) 0), root->base, | |||
2578 | root->offset, root->reverse, | |||
2579 | root->type, NULLnullptr, false); | |||
2580 | ||||
2581 | if (dump_file && (dump_flags & TDF_DETAILS)) | |||
2582 | { | |||
2583 | fprintf (dump_file, "Changing the type of a replacement for "); | |||
2584 | print_generic_expr (dump_file, root->base); | |||
2585 | fprintf (dump_file, " offset: %u, size: %u ", | |||
2586 | (unsigned) root->offset, (unsigned) root->size); | |||
2587 | fprintf (dump_file, " to an integer.\n"); | |||
2588 | } | |||
2589 | } | |||
2590 | ||||
2591 | root->grp_to_be_replaced = 1; | |||
2592 | root->replacement_decl = create_access_replacement (root); | |||
2593 | sth_created = true; | |||
2594 | hole = false; | |||
2595 | } | |||
2596 | else | |||
2597 | { | |||
2598 | if (allow_replacements | |||
2599 | && scalar && !root->first_child | |||
2600 | && !root->grp_total_scalarization | |||
2601 | && (root->grp_scalar_write || root->grp_assignment_write) | |||
2602 | && !bitmap_bit_p (cannot_scalarize_away_bitmap, | |||
2603 | DECL_UID (root->base)((contains_struct_check ((root->base), (TS_DECL_MINIMAL), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 2603, __FUNCTION__))->decl_minimal.uid))) | |||
2604 | { | |||
2605 | gcc_checking_assert (!root->grp_scalar_read((void)(!(!root->grp_scalar_read && !root->grp_assignment_read ) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 2606, __FUNCTION__), 0 : 0)) | |||
2606 | && !root->grp_assignment_read)((void)(!(!root->grp_scalar_read && !root->grp_assignment_read ) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 2606, __FUNCTION__), 0 : 0)); | |||
2607 | sth_created = true; | |||
2608 | if (MAY_HAVE_DEBUG_BIND_STMTSglobal_options.x_flag_var_tracking_assignments) | |||
2609 | { | |||
2610 | root->grp_to_be_debug_replaced = 1; | |||
2611 | root->replacement_decl = create_access_replacement (root); | |||
2612 | } | |||
2613 | } | |||
2614 | ||||
2615 | if (covered_to < limit) | |||
2616 | hole = true; | |||
2617 | if (scalar || !allow_replacements) | |||
2618 | root->grp_total_scalarization = 0; | |||
2619 | } | |||
2620 | ||||
2621 | if (!hole || totally) | |||
2622 | root->grp_covered = 1; | |||
2623 | else if (root->grp_write || comes_initialized_p (root->base)) | |||
2624 | root->grp_unscalarized_data = 1; /* not covered and written to */ | |||
2625 | return sth_created; | |||
2626 | } | |||
2627 | ||||
2628 | /* Analyze all access trees linked by next_grp by the means of | |||
2629 | analyze_access_subtree. */ | |||
2630 | static bool | |||
2631 | analyze_access_trees (struct access *access) | |||
2632 | { | |||
2633 | bool ret = false; | |||
2634 | ||||
2635 | while (access) | |||
2636 | { | |||
2637 | if (analyze_access_subtree (access, NULLnullptr, true, | |||
2638 | access->grp_total_scalarization)) | |||
2639 | ret = true; | |||
2640 | access = access->next_grp; | |||
2641 | } | |||
2642 | ||||
2643 | return ret; | |||
2644 | } | |||
2645 | ||||
2646 | /* Return true iff a potential new child of ACC at offset OFFSET and with size | |||
2647 | SIZE would conflict with an already existing one. If exactly such a child | |||
2648 | already exists in ACC, store a pointer to it in EXACT_MATCH. */ | |||
2649 | ||||
2650 | static bool | |||
2651 | child_would_conflict_in_acc (struct access *acc, HOST_WIDE_INTlong norm_offset, | |||
2652 | HOST_WIDE_INTlong size, struct access **exact_match) | |||
2653 | { | |||
2654 | struct access *child; | |||
2655 | ||||
2656 | for (child = acc->first_child; child; child = child->next_sibling) | |||
2657 | { | |||
2658 | if (child->offset == norm_offset && child->size == size) | |||
2659 | { | |||
2660 | *exact_match = child; | |||
2661 | return true; | |||
2662 | } | |||
2663 | ||||
2664 | if (child->offset < norm_offset + size | |||
2665 | && child->offset + child->size > norm_offset) | |||
2666 | return true; | |||
2667 | } | |||
2668 | ||||
2669 | return false; | |||
2670 | } | |||
2671 | ||||
2672 | /* Create a new child access of PARENT, with all properties just like MODEL | |||
2673 | except for its offset and with its grp_write false and grp_read true. | |||
2674 | Return the new access or NULL if it cannot be created. Note that this | |||
2675 | access is created long after all splicing and sorting, it's not located in | |||
2676 | any access vector and is automatically a representative of its group. Set | |||
2677 | the gpr_write flag of the new accesss if SET_GRP_WRITE is true. */ | |||
2678 | ||||
2679 | static struct access * | |||
2680 | create_artificial_child_access (struct access *parent, struct access *model, | |||
2681 | HOST_WIDE_INTlong new_offset, | |||
2682 | bool set_grp_read, bool set_grp_write) | |||
2683 | { | |||
2684 | struct access **child; | |||
2685 | tree expr = parent->base; | |||
2686 | ||||
2687 | gcc_assert (!model->grp_unscalarizable_region)((void)(!(!model->grp_unscalarizable_region) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 2687, __FUNCTION__), 0 : 0)); | |||
2688 | ||||
2689 | struct access *access = access_pool.allocate (); | |||
2690 | memset (access, 0, sizeof (struct access)); | |||
2691 | if (!build_user_friendly_ref_for_offset (&expr, TREE_TYPE (expr)((contains_struct_check ((expr), (TS_TYPED), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 2691, __FUNCTION__))->typed.type), new_offset, | |||
2692 | model->type)) | |||
2693 | { | |||
2694 | access->grp_no_warning = true; | |||
2695 | expr = build_ref_for_model (EXPR_LOCATION (parent->base)((((parent->base)) && ((tree_code_type_tmpl <0> ::tree_code_type[(int) (((enum tree_code) ((parent->base)) ->base.code))]) >= tcc_reference && (tree_code_type_tmpl <0>::tree_code_type[(int) (((enum tree_code) ((parent-> base))->base.code))]) <= tcc_expression)) ? (parent-> base)->exp.locus : ((location_t) 0)), parent->base, | |||
2696 | new_offset, model, NULLnullptr, false); | |||
2697 | } | |||
2698 | ||||
2699 | access->base = parent->base; | |||
2700 | access->expr = expr; | |||
2701 | access->offset = new_offset; | |||
2702 | access->size = model->size; | |||
2703 | access->type = model->type; | |||
2704 | access->parent = parent; | |||
2705 | access->grp_read = set_grp_read; | |||
2706 | access->grp_write = set_grp_write; | |||
2707 | access->reverse = model->reverse; | |||
2708 | ||||
2709 | child = &parent->first_child; | |||
2710 | while (*child && (*child)->offset < new_offset) | |||
2711 | child = &(*child)->next_sibling; | |||
2712 | ||||
2713 | access->next_sibling = *child; | |||
2714 | *child = access; | |||
2715 | ||||
2716 | return access; | |||
2717 | } | |||
2718 | ||||
2719 | ||||
2720 | /* Beginning with ACCESS, traverse its whole access subtree and mark all | |||
2721 | sub-trees as written to. If any of them has not been marked so previously | |||
2722 | and has assignment links leading from it, re-enqueue it. */ | |||
2723 | ||||
2724 | static void | |||
2725 | subtree_mark_written_and_rhs_enqueue (struct access *access) | |||
2726 | { | |||
2727 | if (access->grp_write) | |||
2728 | return; | |||
2729 | access->grp_write = true; | |||
2730 | add_access_to_rhs_work_queue (access); | |||
2731 | ||||
2732 | struct access *child; | |||
2733 | for (child = access->first_child; child; child = child->next_sibling) | |||
2734 | subtree_mark_written_and_rhs_enqueue (child); | |||
2735 | } | |||
2736 | ||||
2737 | /* If there is still budget to create a propagation access for DECL, return | |||
2738 | true and decrement the budget. Otherwise return false. */ | |||
2739 | ||||
2740 | static bool | |||
2741 | budget_for_propagation_access (tree decl) | |||
2742 | { | |||
2743 | unsigned b, *p = propagation_budget->get (decl); | |||
2744 | if (p) | |||
2745 | b = *p; | |||
2746 | else | |||
2747 | b = param_sra_max_propagationsglobal_options.x_param_sra_max_propagations; | |||
2748 | ||||
2749 | if (b == 0) | |||
2750 | return false; | |||
2751 | b--; | |||
2752 | ||||
2753 | if (b == 0 && dump_file && (dump_flags & TDF_DETAILS)) | |||
2754 | { | |||
2755 | fprintf (dump_file, "The propagation budget of "); | |||
2756 | print_generic_expr (dump_file, decl); | |||
2757 | fprintf (dump_file, " (UID: %u) has been exhausted.\n", DECL_UID (decl)((contains_struct_check ((decl), (TS_DECL_MINIMAL), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 2757, __FUNCTION__))->decl_minimal.uid)); | |||
2758 | } | |||
2759 | propagation_budget->put (decl, b); | |||
2760 | return true; | |||
2761 | } | |||
2762 | ||||
2763 | /* Return true if ACC or any of its subaccesses has grp_child set. */ | |||
2764 | ||||
2765 | static bool | |||
2766 | access_or_its_child_written (struct access *acc) | |||
2767 | { | |||
2768 | if (acc->grp_write) | |||
2769 | return true; | |||
2770 | for (struct access *sub = acc->first_child; sub; sub = sub->next_sibling) | |||
2771 | if (access_or_its_child_written (sub)) | |||
2772 | return true; | |||
2773 | return false; | |||
2774 | } | |||
2775 | ||||
2776 | /* Propagate subaccesses and grp_write flags of RACC across an assignment link | |||
2777 | to LACC. Enqueue sub-accesses as necessary so that the write flag is | |||
2778 | propagated transitively. Return true if anything changed. Additionally, if | |||
2779 | RACC is a scalar access but LACC is not, change the type of the latter, if | |||
2780 | possible. */ | |||
2781 | ||||
2782 | static bool | |||
2783 | propagate_subaccesses_from_rhs (struct access *lacc, struct access *racc) | |||
2784 | { | |||
2785 | struct access *rchild; | |||
2786 | HOST_WIDE_INTlong norm_delta = lacc->offset - racc->offset; | |||
2787 | bool ret = false; | |||
2788 | ||||
2789 | /* IF the LHS is still not marked as being written to, we only need to do so | |||
2790 | if the RHS at this level actually was. */ | |||
2791 | if (!lacc->grp_write) | |||
2792 | { | |||
2793 | gcc_checking_assert (!comes_initialized_p (racc->base))((void)(!(!comes_initialized_p (racc->base)) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 2793, __FUNCTION__), 0 : 0)); | |||
2794 | if (racc->grp_write) | |||
2795 | { | |||
2796 | subtree_mark_written_and_rhs_enqueue (lacc); | |||
2797 | ret = true; | |||
2798 | } | |||
2799 | } | |||
2800 | ||||
2801 | if (is_gimple_reg_type (lacc->type) | |||
2802 | || lacc->grp_unscalarizable_region | |||
2803 | || racc->grp_unscalarizable_region) | |||
2804 | { | |||
2805 | if (!lacc->grp_write) | |||
2806 | { | |||
2807 | ret = true; | |||
2808 | subtree_mark_written_and_rhs_enqueue (lacc); | |||
2809 | } | |||
2810 | return ret; | |||
2811 | } | |||
2812 | ||||
2813 | if (is_gimple_reg_type (racc->type)) | |||
2814 | { | |||
2815 | if (!lacc->grp_write) | |||
2816 | { | |||
2817 | ret = true; | |||
2818 | subtree_mark_written_and_rhs_enqueue (lacc); | |||
2819 | } | |||
2820 | if (!lacc->first_child && !racc->first_child) | |||
2821 | { | |||
2822 | /* We are about to change the access type from aggregate to scalar, | |||
2823 | so we need to put the reverse flag onto the access, if any. */ | |||
2824 | const bool reverse | |||
2825 | = TYPE_REVERSE_STORAGE_ORDER (lacc->type)((tree_check4 ((lacc->type), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 2825, __FUNCTION__, (RECORD_TYPE), (UNION_TYPE), (QUAL_UNION_TYPE ), (ARRAY_TYPE)))->base.u.bits.saturating_flag) | |||
2826 | && !POINTER_TYPE_P (racc->type)(((enum tree_code) (racc->type)->base.code) == POINTER_TYPE || ((enum tree_code) (racc->type)->base.code) == REFERENCE_TYPE ) | |||
2827 | && !VECTOR_TYPE_P (racc->type)(((enum tree_code) (racc->type)->base.code) == VECTOR_TYPE ); | |||
2828 | tree t = lacc->base; | |||
2829 | ||||
2830 | lacc->type = racc->type; | |||
2831 | if (build_user_friendly_ref_for_offset (&t, TREE_TYPE (t)((contains_struct_check ((t), (TS_TYPED), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 2831, __FUNCTION__))->typed.type), | |||
2832 | lacc->offset, racc->type)) | |||
2833 | { | |||
2834 | lacc->expr = t; | |||
2835 | lacc->grp_same_access_path = true; | |||
2836 | } | |||
2837 | else | |||
2838 | { | |||
2839 | lacc->expr = build_ref_for_model (EXPR_LOCATION (lacc->base)((((lacc->base)) && ((tree_code_type_tmpl <0> ::tree_code_type[(int) (((enum tree_code) ((lacc->base))-> base.code))]) >= tcc_reference && (tree_code_type_tmpl <0>::tree_code_type[(int) (((enum tree_code) ((lacc-> base))->base.code))]) <= tcc_expression)) ? (lacc->base )->exp.locus : ((location_t) 0)), | |||
2840 | lacc->base, lacc->offset, | |||
2841 | racc, NULLnullptr, false); | |||
2842 | if (TREE_CODE (lacc->expr)((enum tree_code) (lacc->expr)->base.code) == MEM_REF) | |||
2843 | REF_REVERSE_STORAGE_ORDER (lacc->expr)((tree_check2 ((lacc->expr), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 2843, __FUNCTION__, (BIT_FIELD_REF), (MEM_REF)))->base.default_def_flag ) = reverse; | |||
2844 | lacc->grp_no_warning = true; | |||
2845 | lacc->grp_same_access_path = false; | |||
2846 | } | |||
2847 | lacc->reverse = reverse; | |||
2848 | } | |||
2849 | return ret; | |||
2850 | } | |||
2851 | ||||
2852 | for (rchild = racc->first_child; rchild; rchild = rchild->next_sibling) | |||
2853 | { | |||
2854 | struct access *new_acc = NULLnullptr; | |||
2855 | HOST_WIDE_INTlong norm_offset = rchild->offset + norm_delta; | |||
2856 | ||||
2857 | if (child_would_conflict_in_acc (lacc, norm_offset, rchild->size, | |||
2858 | &new_acc)) | |||
2859 | { | |||
2860 | if (new_acc) | |||
2861 | { | |||
2862 | if (!new_acc->grp_write && rchild->grp_write) | |||
2863 | { | |||
2864 | gcc_assert (!lacc->grp_write)((void)(!(!lacc->grp_write) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 2864, __FUNCTION__), 0 : 0)); | |||
2865 | subtree_mark_written_and_rhs_enqueue (new_acc); | |||
2866 | ret = true; | |||
2867 | } | |||
2868 | ||||
2869 | rchild->grp_hint = 1; | |||
2870 | new_acc->grp_hint |= new_acc->grp_read; | |||
2871 | if (rchild->first_child | |||
2872 | && propagate_subaccesses_from_rhs (new_acc, rchild)) | |||
2873 | { | |||
2874 | ret = 1; | |||
2875 | add_access_to_rhs_work_queue (new_acc); | |||
2876 | } | |||
2877 | } | |||
2878 | else | |||
2879 | { | |||
2880 | if (!lacc->grp_write) | |||
2881 | { | |||
2882 | ret = true; | |||
2883 | subtree_mark_written_and_rhs_enqueue (lacc); | |||
2884 | } | |||
2885 | } | |||
2886 | continue; | |||
2887 | } | |||
2888 | ||||
2889 | if (rchild->grp_unscalarizable_region | |||
2890 | || !budget_for_propagation_access (lacc->base)) | |||
2891 | { | |||
2892 | if (!lacc->grp_write && access_or_its_child_written (rchild)) | |||
2893 | { | |||
2894 | ret = true; | |||
2895 | subtree_mark_written_and_rhs_enqueue (lacc); | |||
2896 | } | |||
2897 | continue; | |||
2898 | } | |||
2899 | ||||
2900 | rchild->grp_hint = 1; | |||
2901 | /* Because get_ref_base_and_extent always includes padding in size for | |||
2902 | accesses to DECLs but not necessarily for COMPONENT_REFs of the same | |||
2903 | type, we might be actually attempting to here to create a child of the | |||
2904 | same type as the parent. */ | |||
2905 | if (!types_compatible_p (lacc->type, rchild->type)) | |||
2906 | new_acc = create_artificial_child_access (lacc, rchild, norm_offset, | |||
2907 | false, | |||
2908 | (lacc->grp_write | |||
2909 | || rchild->grp_write)); | |||
2910 | else | |||
2911 | new_acc = lacc; | |||
2912 | gcc_checking_assert (new_acc)((void)(!(new_acc) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 2912, __FUNCTION__), 0 : 0)); | |||
2913 | if (racc->first_child) | |||
2914 | propagate_subaccesses_from_rhs (new_acc, rchild); | |||
2915 | ||||
2916 | add_access_to_rhs_work_queue (lacc); | |||
2917 | ret = true; | |||
2918 | } | |||
2919 | ||||
2920 | return ret; | |||
2921 | } | |||
2922 | ||||
2923 | /* Propagate subaccesses of LACC across an assignment link to RACC if they | |||
2924 | should inhibit total scalarization of the corresponding area. No flags are | |||
2925 | being propagated in the process. Return true if anything changed. */ | |||
2926 | ||||
2927 | static bool | |||
2928 | propagate_subaccesses_from_lhs (struct access *lacc, struct access *racc) | |||
2929 | { | |||
2930 | if (is_gimple_reg_type (racc->type) | |||
2931 | || lacc->grp_unscalarizable_region | |||
2932 | || racc->grp_unscalarizable_region) | |||
2933 | return false; | |||
2934 | ||||
2935 | /* TODO: Do we want set some new racc flag to stop potential total | |||
2936 | scalarization if lacc is a scalar access (and none fo the two have | |||
2937 | children)? */ | |||
2938 | ||||
2939 | bool ret = false; | |||
2940 | HOST_WIDE_INTlong norm_delta = racc->offset - lacc->offset; | |||
2941 | for (struct access *lchild = lacc->first_child; | |||
2942 | lchild; | |||
2943 | lchild = lchild->next_sibling) | |||
2944 | { | |||
2945 | struct access *matching_acc = NULLnullptr; | |||
2946 | HOST_WIDE_INTlong norm_offset = lchild->offset + norm_delta; | |||
2947 | ||||
2948 | if (lchild->grp_unscalarizable_region | |||
2949 | || child_would_conflict_in_acc (racc, norm_offset, lchild->size, | |||
2950 | &matching_acc) | |||
2951 | || !budget_for_propagation_access (racc->base)) | |||
2952 | { | |||
2953 | if (matching_acc | |||
2954 | && propagate_subaccesses_from_lhs (lchild, matching_acc)) | |||
2955 | add_access_to_lhs_work_queue (matching_acc); | |||
2956 | continue; | |||
2957 | } | |||
2958 | ||||
2959 | /* Because get_ref_base_and_extent always includes padding in size for | |||
2960 | accesses to DECLs but not necessarily for COMPONENT_REFs of the same | |||
2961 | type, we might be actually attempting to here to create a child of the | |||
2962 | same type as the parent. */ | |||
2963 | if (!types_compatible_p (racc->type, lchild->type)) | |||
2964 | { | |||
2965 | struct access *new_acc | |||
2966 | = create_artificial_child_access (racc, lchild, norm_offset, | |||
2967 | true, false); | |||
2968 | new_acc->grp_result_of_prop_from_lhs = 1; | |||
2969 | propagate_subaccesses_from_lhs (lchild, new_acc); | |||
2970 | } | |||
2971 | else | |||
2972 | propagate_subaccesses_from_lhs (lchild, racc); | |||
2973 | ret = true; | |||
2974 | } | |||
2975 | return ret; | |||
2976 | } | |||
2977 | ||||
2978 | /* Propagate all subaccesses across assignment links. */ | |||
2979 | ||||
2980 | static void | |||
2981 | propagate_all_subaccesses (void) | |||
2982 | { | |||
2983 | propagation_budget = new hash_map<tree, unsigned>; | |||
2984 | while (rhs_work_queue_head) | |||
2985 | { | |||
2986 | struct access *racc = pop_access_from_rhs_work_queue (); | |||
2987 | struct assign_link *link; | |||
2988 | ||||
2989 | if (racc->group_representative) | |||
2990 | racc= racc->group_representative; | |||
2991 | gcc_assert (racc->first_rhs_link)((void)(!(racc->first_rhs_link) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 2991, __FUNCTION__), 0 : 0)); | |||
2992 | ||||
2993 | for (link = racc->first_rhs_link; link; link = link->next_rhs) | |||
2994 | { | |||
2995 | struct access *lacc = link->lacc; | |||
2996 | ||||
2997 | if (!bitmap_bit_p (candidate_bitmap, DECL_UID (lacc->base)((contains_struct_check ((lacc->base), (TS_DECL_MINIMAL), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 2997, __FUNCTION__))->decl_minimal.uid))) | |||
2998 | continue; | |||
2999 | lacc = lacc->group_representative; | |||
3000 | ||||
3001 | bool reque_parents = false; | |||
3002 | if (!bitmap_bit_p (candidate_bitmap, DECL_UID (racc->base)((contains_struct_check ((racc->base), (TS_DECL_MINIMAL), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 3002, __FUNCTION__))->decl_minimal.uid))) | |||
3003 | { | |||
3004 | if (!lacc->grp_write) | |||
3005 | { | |||
3006 | subtree_mark_written_and_rhs_enqueue (lacc); | |||
3007 | reque_parents = true; | |||
3008 | } | |||
3009 | } | |||
3010 | else if (propagate_subaccesses_from_rhs (lacc, racc)) | |||
3011 | reque_parents = true; | |||
3012 | ||||
3013 | if (reque_parents) | |||
3014 | do | |||
3015 | { | |||
3016 | add_access_to_rhs_work_queue (lacc); | |||
3017 | lacc = lacc->parent; | |||
3018 | } | |||
3019 | while (lacc); | |||
3020 | } | |||
3021 | } | |||
3022 | ||||
3023 | while (lhs_work_queue_head) | |||
3024 | { | |||
3025 | struct access *lacc = pop_access_from_lhs_work_queue (); | |||
3026 | struct assign_link *link; | |||
3027 | ||||
3028 | if (lacc->group_representative) | |||
3029 | lacc = lacc->group_representative; | |||
3030 | gcc_assert (lacc->first_lhs_link)((void)(!(lacc->first_lhs_link) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 3030, __FUNCTION__), 0 : 0)); | |||
3031 | ||||
3032 | if (!bitmap_bit_p (candidate_bitmap, DECL_UID (lacc->base)((contains_struct_check ((lacc->base), (TS_DECL_MINIMAL), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 3032, __FUNCTION__))->decl_minimal.uid))) | |||
3033 | continue; | |||
3034 | ||||
3035 | for (link = lacc->first_lhs_link; link; link = link->next_lhs) | |||
3036 | { | |||
3037 | struct access *racc = link->racc; | |||
3038 | ||||
3039 | if (racc->group_representative) | |||
3040 | racc = racc->group_representative; | |||
3041 | if (!bitmap_bit_p (candidate_bitmap, DECL_UID (racc->base)((contains_struct_check ((racc->base), (TS_DECL_MINIMAL), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 3041, __FUNCTION__))->decl_minimal.uid))) | |||
3042 | continue; | |||
3043 | if (propagate_subaccesses_from_lhs (lacc, racc)) | |||
3044 | add_access_to_lhs_work_queue (racc); | |||
3045 | } | |||
3046 | } | |||
3047 | delete propagation_budget; | |||
3048 | } | |||
3049 | ||||
3050 | /* Return true if the forest beginning with ROOT does not contain | |||
3051 | unscalarizable regions or non-byte aligned accesses. */ | |||
3052 | ||||
3053 | static bool | |||
3054 | can_totally_scalarize_forest_p (struct access *root) | |||
3055 | { | |||
3056 | struct access *access = root; | |||
3057 | do | |||
3058 | { | |||
3059 | if (access->grp_unscalarizable_region | |||
3060 | || (access->offset % BITS_PER_UNIT(8)) != 0 | |||
3061 | || (access->size % BITS_PER_UNIT(8)) != 0 | |||
3062 | || (is_gimple_reg_type (access->type) | |||
3063 | && access->first_child)) | |||
3064 | return false; | |||
3065 | ||||
3066 | if (access->first_child) | |||
3067 | access = access->first_child; | |||
3068 | else if (access->next_sibling) | |||
3069 | access = access->next_sibling; | |||
3070 | else | |||
3071 | { | |||
3072 | while (access->parent && !access->next_sibling) | |||
3073 | access = access->parent; | |||
3074 | if (access->next_sibling) | |||
3075 | access = access->next_sibling; | |||
3076 | else | |||
3077 | { | |||
3078 | gcc_assert (access == root)((void)(!(access == root) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 3078, __FUNCTION__), 0 : 0)); | |||
3079 | root = root->next_grp; | |||
3080 | access = root; | |||
3081 | } | |||
3082 | } | |||
3083 | } | |||
3084 | while (access); | |||
3085 | return true; | |||
3086 | } | |||
3087 | ||||
3088 | /* Create and return an ACCESS in PARENT spanning from POS with SIZE, TYPE and | |||
3089 | reference EXPR for total scalarization purposes and mark it as such. Within | |||
3090 | the children of PARENT, link it in between PTR and NEXT_SIBLING. */ | |||
3091 | ||||
3092 | static struct access * | |||
3093 | create_total_scalarization_access (struct access *parent, HOST_WIDE_INTlong pos, | |||
3094 | HOST_WIDE_INTlong size, tree type, tree expr, | |||
3095 | struct access **ptr, | |||
3096 | struct access *next_sibling) | |||
3097 | { | |||
3098 | struct access *access = access_pool.allocate (); | |||
3099 | memset (access, 0, sizeof (struct access)); | |||
3100 | access->base = parent->base; | |||
3101 | access->offset = pos; | |||
3102 | access->size = size; | |||
3103 | access->expr = expr; | |||
3104 | access->type = type; | |||
3105 | access->parent = parent; | |||
3106 | access->grp_write = parent->grp_write; | |||
3107 | access->grp_total_scalarization = 1; | |||
3108 | access->grp_hint = 1; | |||
3109 | access->grp_same_access_path = path_comparable_for_same_access (expr); | |||
3110 | access->reverse = reverse_storage_order_for_component_p (expr); | |||
3111 | ||||
3112 | access->next_sibling = next_sibling; | |||
3113 | *ptr = access; | |||
3114 | return access; | |||
3115 | } | |||
3116 | ||||
3117 | /* Create and return an ACCESS in PARENT spanning from POS with SIZE, TYPE and | |||
3118 | reference EXPR for total scalarization purposes and mark it as such, link it | |||
3119 | at *PTR and reshape the tree so that those elements at *PTR and their | |||
3120 | siblings which fall within the part described by POS and SIZE are moved to | |||
3121 | be children of the new access. If a partial overlap is detected, return | |||
3122 | NULL. */ | |||
3123 | ||||
3124 | static struct access * | |||
3125 | create_total_access_and_reshape (struct access *parent, HOST_WIDE_INTlong pos, | |||
3126 | HOST_WIDE_INTlong size, tree type, tree expr, | |||
3127 | struct access **ptr) | |||
3128 | { | |||
3129 | struct access **p = ptr; | |||
3130 | ||||
3131 | while (*p && (*p)->offset < pos + size) | |||
3132 | { | |||
3133 | if ((*p)->offset + (*p)->size > pos + size) | |||
3134 | return NULLnullptr; | |||
3135 | p = &(*p)->next_sibling; | |||
3136 | } | |||
3137 | ||||
3138 | struct access *next_child = *ptr; | |||
3139 | struct access *new_acc | |||
3140 | = create_total_scalarization_access (parent, pos, size, type, expr, | |||
3141 | ptr, *p); | |||
3142 | if (p != ptr) | |||
3143 | { | |||
3144 | new_acc->first_child = next_child; | |||
3145 | *p = NULLnullptr; | |||
3146 | for (struct access *a = next_child; a; a = a->next_sibling) | |||
3147 | a->parent = new_acc; | |||
3148 | } | |||
3149 | return new_acc; | |||
3150 | } | |||
3151 | ||||
3152 | static bool totally_scalarize_subtree (struct access *root); | |||
3153 | ||||
3154 | /* Return true if INNER is either the same type as OUTER or if it is the type | |||
3155 | of a record field in OUTER at offset zero, possibly in nested | |||
3156 | sub-records. */ | |||
3157 | ||||
3158 | static bool | |||
3159 | access_and_field_type_match_p (tree outer, tree inner) | |||
3160 | { | |||
3161 | if (TYPE_MAIN_VARIANT (outer)((tree_class_check ((outer), (tcc_type), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 3161, __FUNCTION__))->type_common.main_variant) == TYPE_MAIN_VARIANT (inner)((tree_class_check ((inner), (tcc_type), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 3161, __FUNCTION__))->type_common.main_variant)) | |||
3162 | return true; | |||
3163 | if (TREE_CODE (outer)((enum tree_code) (outer)->base.code) != RECORD_TYPE) | |||
3164 | return false; | |||
3165 | tree fld = TYPE_FIELDS (outer)((tree_check3 ((outer), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 3165, __FUNCTION__, (RECORD_TYPE), (UNION_TYPE), (QUAL_UNION_TYPE )))->type_non_common.values); | |||
3166 | while (fld) | |||
3167 | { | |||
3168 | if (TREE_CODE (fld)((enum tree_code) (fld)->base.code) == FIELD_DECL) | |||
3169 | { | |||
3170 | if (!zerop (DECL_FIELD_OFFSET (fld)((tree_check ((fld), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 3170, __FUNCTION__, (FIELD_DECL)))->field_decl.offset))) | |||
3171 | return false; | |||
3172 | if (TYPE_MAIN_VARIANT (TREE_TYPE (fld))((tree_class_check ((((contains_struct_check ((fld), (TS_TYPED ), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 3172, __FUNCTION__))->typed.type)), (tcc_type), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 3172, __FUNCTION__))->type_common.main_variant) == inner) | |||
3173 | return true; | |||
3174 | if (TREE_CODE (TREE_TYPE (fld))((enum tree_code) (((contains_struct_check ((fld), (TS_TYPED) , "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 3174, __FUNCTION__))->typed.type))->base.code) == RECORD_TYPE) | |||
3175 | fld = TYPE_FIELDS (TREE_TYPE (fld))((tree_check3 ((((contains_struct_check ((fld), (TS_TYPED), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 3175, __FUNCTION__))->typed.type)), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 3175, __FUNCTION__, (RECORD_TYPE), (UNION_TYPE), (QUAL_UNION_TYPE )))->type_non_common.values); | |||
3176 | else | |||
3177 | return false; | |||
3178 | } | |||
3179 | else | |||
3180 | fld = DECL_CHAIN (fld)(((contains_struct_check (((contains_struct_check ((fld), (TS_DECL_MINIMAL ), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 3180, __FUNCTION__))), (TS_COMMON), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 3180, __FUNCTION__))->common.chain)); | |||
3181 | } | |||
3182 | return false; | |||
3183 | } | |||
3184 | ||||
3185 | /* Return type of total_should_skip_creating_access indicating whether a total | |||
3186 | scalarization access for a field/element should be created, whether it | |||
3187 | already exists or whether the entire total scalarization has to fail. */ | |||
3188 | ||||
3189 | enum total_sra_field_state {TOTAL_FLD_CREATE, TOTAL_FLD_DONE, TOTAL_FLD_FAILED}; | |||
3190 | ||||
3191 | /* Do all the necessary steps in total scalarization when the given aggregate | |||
3192 | type has a TYPE at POS with the given SIZE should be put into PARENT and | |||
3193 | when we have processed all its siblings with smaller offsets up until and | |||
3194 | including LAST_SEEN_SIBLING (which can be NULL). | |||
3195 | ||||
3196 | If some further siblings are to be skipped, set *LAST_SEEN_SIBLING as | |||
3197 | appropriate. Return TOTAL_FLD_CREATE id the caller should carry on with | |||
3198 | creating a new access, TOTAL_FLD_DONE if access or accesses capable of | |||
3199 | representing the described part of the aggregate for the purposes of total | |||
3200 | scalarization already exist or TOTAL_FLD_FAILED if there is a problem which | |||
3201 | prevents total scalarization from happening at all. */ | |||
3202 | ||||
3203 | static enum total_sra_field_state | |||
3204 | total_should_skip_creating_access (struct access *parent, | |||
3205 | struct access **last_seen_sibling, | |||
3206 | tree type, HOST_WIDE_INTlong pos, | |||
3207 | HOST_WIDE_INTlong size) | |||
3208 | { | |||
3209 | struct access *next_child; | |||
3210 | if (!*last_seen_sibling) | |||
3211 | next_child = parent->first_child; | |||
3212 | else | |||
3213 | next_child = (*last_seen_sibling)->next_sibling; | |||
3214 | ||||
3215 | /* First, traverse the chain of siblings until it points to an access with | |||
3216 | offset at least equal to POS. Check all skipped accesses whether they | |||
3217 | span the POS boundary and if so, return with a failure. */ | |||
3218 | while (next_child && next_child->offset < pos) | |||
3219 | { | |||
3220 | if (next_child->offset + next_child->size > pos) | |||
3221 | return TOTAL_FLD_FAILED; | |||
3222 | *last_seen_sibling = next_child; | |||
3223 | next_child = next_child->next_sibling; | |||
3224 | } | |||
3225 | ||||
3226 | /* Now check whether next_child has exactly the right POS and SIZE and if so, | |||
3227 | whether it can represent what we need and can be totally scalarized | |||
3228 | itself. */ | |||
3229 | if (next_child && next_child->offset == pos | |||
3230 | && next_child->size == size) | |||
3231 | { | |||
3232 | if (!is_gimple_reg_type (next_child->type) | |||
3233 | && (!access_and_field_type_match_p (type, next_child->type) | |||
3234 | || !totally_scalarize_subtree (next_child))) | |||
3235 | return TOTAL_FLD_FAILED; | |||
3236 | ||||
3237 | *last_seen_sibling = next_child; | |||
3238 | return TOTAL_FLD_DONE; | |||
3239 | } | |||
3240 | ||||
3241 | /* If the child we're looking at would partially overlap, we just cannot | |||
3242 | totally scalarize. */ | |||
3243 | if (next_child | |||
3244 | && next_child->offset < pos + size | |||
3245 | && next_child->offset + next_child->size > pos + size) | |||
3246 | return TOTAL_FLD_FAILED; | |||
3247 | ||||
3248 | if (is_gimple_reg_type (type)) | |||
3249 | { | |||
3250 | /* We don't scalarize accesses that are children of other scalar type | |||
3251 | accesses, so if we go on and create an access for a register type, | |||
3252 | there should not be any pre-existing children. There are rare cases | |||
3253 | where the requested type is a vector but we already have register | |||
3254 | accesses for all its elements which is equally good. Detect that | |||
3255 | situation or whether we need to bail out. */ | |||
3256 | ||||
3257 | HOST_WIDE_INTlong covered = pos; | |||
3258 | bool skipping = false; | |||
3259 | while (next_child | |||
3260 | && next_child->offset + next_child->size <= pos + size) | |||
3261 | { | |||
3262 | if (next_child->offset != covered | |||
3263 | || !is_gimple_reg_type (next_child->type)) | |||
3264 | return TOTAL_FLD_FAILED; | |||
3265 | ||||
3266 | covered += next_child->size; | |||
3267 | *last_seen_sibling = next_child; | |||
3268 | next_child = next_child->next_sibling; | |||
3269 | skipping = true; | |||
3270 | } | |||
3271 | ||||
3272 | if (skipping) | |||
3273 | { | |||
3274 | if (covered != pos + size) | |||
3275 | return TOTAL_FLD_FAILED; | |||
3276 | else | |||
3277 | return TOTAL_FLD_DONE; | |||
3278 | } | |||
3279 | } | |||
3280 | ||||
3281 | return TOTAL_FLD_CREATE; | |||
3282 | } | |||
3283 | ||||
3284 | /* Go over sub-tree rooted in ROOT and attempt to create scalar accesses | |||
3285 | spanning all uncovered areas covered by ROOT, return false if the attempt | |||
3286 | failed. All created accesses will have grp_unscalarizable_region set (and | |||
3287 | should be ignored if the function returns false). */ | |||
3288 | ||||
3289 | static bool | |||
3290 | totally_scalarize_subtree (struct access *root) | |||
3291 | { | |||
3292 | gcc_checking_assert (!root->grp_unscalarizable_region)((void)(!(!root->grp_unscalarizable_region) ? fancy_abort ( "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 3292, __FUNCTION__), 0 : 0)); | |||
3293 | gcc_checking_assert (!is_gimple_reg_type (root->type))((void)(!(!is_gimple_reg_type (root->type)) ? fancy_abort ( "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 3293, __FUNCTION__), 0 : 0)); | |||
3294 | ||||
3295 | struct access *last_seen_sibling = NULLnullptr; | |||
3296 | ||||
3297 | switch (TREE_CODE (root->type)((enum tree_code) (root->type)->base.code)) | |||
3298 | { | |||
3299 | case RECORD_TYPE: | |||
3300 | for (tree fld = TYPE_FIELDS (root->type)((tree_check3 ((root->type), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 3300, __FUNCTION__, (RECORD_TYPE), (UNION_TYPE), (QUAL_UNION_TYPE )))->type_non_common.values); fld; fld = DECL_CHAIN (fld)(((contains_struct_check (((contains_struct_check ((fld), (TS_DECL_MINIMAL ), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 3300, __FUNCTION__))), (TS_COMMON), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 3300, __FUNCTION__))->common.chain))) | |||
3301 | if (TREE_CODE (fld)((enum tree_code) (fld)->base.code) == FIELD_DECL) | |||
3302 | { | |||
3303 | tree ft = TREE_TYPE (fld)((contains_struct_check ((fld), (TS_TYPED), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 3303, __FUNCTION__))->typed.type); | |||
3304 | HOST_WIDE_INTlong fsize = tree_to_uhwi (DECL_SIZE (fld)((contains_struct_check ((fld), (TS_DECL_COMMON), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 3304, __FUNCTION__))->decl_common.size)); | |||
3305 | if (!fsize) | |||
3306 | continue; | |||
3307 | ||||
3308 | HOST_WIDE_INTlong pos = root->offset + int_bit_position (fld); | |||
3309 | if (pos + fsize > root->offset + root->size) | |||
3310 | return false; | |||
3311 | enum total_sra_field_state | |||
3312 | state = total_should_skip_creating_access (root, | |||
3313 | &last_seen_sibling, | |||
3314 | ft, pos, fsize); | |||
3315 | switch (state) | |||
3316 | { | |||
3317 | case TOTAL_FLD_FAILED: | |||
3318 | return false; | |||
3319 | case TOTAL_FLD_DONE: | |||
3320 | continue; | |||
3321 | case TOTAL_FLD_CREATE: | |||
3322 | break; | |||
3323 | default: | |||
3324 | gcc_unreachable ()(fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 3324, __FUNCTION__)); | |||
3325 | } | |||
3326 | ||||
3327 | struct access **p = (last_seen_sibling | |||
3328 | ? &last_seen_sibling->next_sibling | |||
3329 | : &root->first_child); | |||
3330 | tree nref = build3 (COMPONENT_REF, ft, root->expr, fld, NULL_TREE(tree) nullptr); | |||
3331 | struct access *new_child | |||
3332 | = create_total_access_and_reshape (root, pos, fsize, ft, nref, p); | |||
3333 | if (!new_child) | |||
3334 | return false; | |||
3335 | ||||
3336 | if (!is_gimple_reg_type (ft) | |||
3337 | && !totally_scalarize_subtree (new_child)) | |||
3338 | return false; | |||
3339 | last_seen_sibling = new_child; | |||
3340 | } | |||
3341 | break; | |||
3342 | case ARRAY_TYPE: | |||
3343 | { | |||
3344 | tree elemtype = TREE_TYPE (root->type)((contains_struct_check ((root->type), (TS_TYPED), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 3344, __FUNCTION__))->typed.type); | |||
3345 | tree elem_size = TYPE_SIZE (elemtype)((tree_class_check ((elemtype), (tcc_type), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 3345, __FUNCTION__))->type_common.size); | |||
3346 | gcc_assert (elem_size && tree_fits_shwi_p (elem_size))((void)(!(elem_size && tree_fits_shwi_p (elem_size)) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 3346, __FUNCTION__), 0 : 0)); | |||
3347 | HOST_WIDE_INTlong el_size = tree_to_shwi (elem_size); | |||
3348 | gcc_assert (el_size > 0)((void)(!(el_size > 0) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 3348, __FUNCTION__), 0 : 0)); | |||
3349 | ||||
3350 | tree minidx = TYPE_MIN_VALUE (TYPE_DOMAIN (root->type))((tree_check5 ((((tree_check ((root->type), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 3350, __FUNCTION__, (ARRAY_TYPE)))->type_non_common.values )), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 3350, __FUNCTION__, (INTEGER_TYPE), (ENUMERAL_TYPE), (BOOLEAN_TYPE ), (REAL_TYPE), (FIXED_POINT_TYPE)))->type_non_common.minval ); | |||
3351 | gcc_assert (TREE_CODE (minidx) == INTEGER_CST)((void)(!(((enum tree_code) (minidx)->base.code) == INTEGER_CST ) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 3351, __FUNCTION__), 0 : 0)); | |||
3352 | tree maxidx = TYPE_MAX_VALUE (TYPE_DOMAIN (root->type))((tree_check5 ((((tree_check ((root->type), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 3352, __FUNCTION__, (ARRAY_TYPE)))->type_non_common.values )), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 3352, __FUNCTION__, (INTEGER_TYPE), (ENUMERAL_TYPE), (BOOLEAN_TYPE ), (REAL_TYPE), (FIXED_POINT_TYPE)))->type_non_common.maxval ); | |||
3353 | /* Skip (some) zero-length arrays; others have MAXIDX == MINIDX - 1. */ | |||
3354 | if (!maxidx) | |||
3355 | goto out; | |||
3356 | gcc_assert (TREE_CODE (maxidx) == INTEGER_CST)((void)(!(((enum tree_code) (maxidx)->base.code) == INTEGER_CST ) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 3356, __FUNCTION__), 0 : 0)); | |||
3357 | tree domain = TYPE_DOMAIN (root->type)((tree_check ((root->type), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 3357, __FUNCTION__, (ARRAY_TYPE)))->type_non_common.values ); | |||
3358 | /* MINIDX and MAXIDX are inclusive, and must be interpreted in | |||
3359 | DOMAIN (e.g. signed int, whereas min/max may be size_int). */ | |||
3360 | offset_int idx = wi::to_offset (minidx); | |||
3361 | offset_int max = wi::to_offset (maxidx); | |||
3362 | if (!TYPE_UNSIGNED (domain)((tree_class_check ((domain), (tcc_type), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 3362, __FUNCTION__))->base.u.bits.unsigned_flag)) | |||
3363 | { | |||
3364 | idx = wi::sext (idx, TYPE_PRECISION (domain)((tree_class_check ((domain), (tcc_type), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 3364, __FUNCTION__))->type_common.precision)); | |||
3365 | max = wi::sext (max, TYPE_PRECISION (domain)((tree_class_check ((domain), (tcc_type), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 3365, __FUNCTION__))->type_common.precision)); | |||
3366 | } | |||
3367 | for (HOST_WIDE_INTlong pos = root->offset; | |||
3368 | idx <= max; | |||
3369 | pos += el_size, ++idx) | |||
3370 | { | |||
3371 | enum total_sra_field_state | |||
3372 | state = total_should_skip_creating_access (root, | |||
3373 | &last_seen_sibling, | |||
3374 | elemtype, pos, | |||
3375 | el_size); | |||
3376 | switch (state) | |||
3377 | { | |||
3378 | case TOTAL_FLD_FAILED: | |||
3379 | return false; | |||
3380 | case TOTAL_FLD_DONE: | |||
3381 | continue; | |||
3382 | case TOTAL_FLD_CREATE: | |||
3383 | break; | |||
3384 | default: | |||
3385 | gcc_unreachable ()(fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 3385, __FUNCTION__)); | |||
3386 | } | |||
3387 | ||||
3388 | struct access **p = (last_seen_sibling | |||
3389 | ? &last_seen_sibling->next_sibling | |||
3390 | : &root->first_child); | |||
3391 | tree nref = build4 (ARRAY_REF, elemtype, root->expr, | |||
3392 | wide_int_to_tree (domain, idx), | |||
3393 | NULL_TREE(tree) nullptr, NULL_TREE(tree) nullptr); | |||
3394 | struct access *new_child | |||
3395 | = create_total_access_and_reshape (root, pos, el_size, elemtype, | |||
3396 | nref, p); | |||
3397 | if (!new_child) | |||
3398 | return false; | |||
3399 | ||||
3400 | if (!is_gimple_reg_type (elemtype) | |||
3401 | && !totally_scalarize_subtree (new_child)) | |||
3402 | return false; | |||
3403 | last_seen_sibling = new_child; | |||
3404 | } | |||
3405 | } | |||
3406 | break; | |||
3407 | default: | |||
3408 | gcc_unreachable ()(fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 3408, __FUNCTION__)); | |||
3409 | } | |||
3410 | ||||
3411 | out: | |||
3412 | return true; | |||
3413 | } | |||
3414 | ||||
3415 | /* Go through all accesses collected throughout the (intraprocedural) analysis | |||
3416 | stage, exclude overlapping ones, identify representatives and build trees | |||
3417 | out of them, making decisions about scalarization on the way. Return true | |||
3418 | iff there are any to-be-scalarized variables after this stage. */ | |||
3419 | ||||
3420 | static bool | |||
3421 | analyze_all_variable_accesses (void) | |||
3422 | { | |||
3423 | int res = 0; | |||
3424 | bitmap tmp = BITMAP_ALLOCbitmap_alloc (NULLnullptr); | |||
3425 | bitmap_iterator bi; | |||
3426 | unsigned i; | |||
3427 | ||||
3428 | bitmap_copy (tmp, candidate_bitmap); | |||
3429 | EXECUTE_IF_SET_IN_BITMAP (tmp, 0, i, bi)for (bmp_iter_set_init (&(bi), (tmp), (0), &(i)); bmp_iter_set (&(bi), &(i)); bmp_iter_next (&(bi), &(i))) | |||
| ||||
3430 | { | |||
3431 | tree var = candidate (i); | |||
3432 | struct access *access; | |||
3433 | ||||
3434 | access = sort_and_splice_var_accesses (var); | |||
3435 | if (!access || !build_access_trees (access)) | |||
3436 | disqualify_candidate (var, | |||
3437 | "No or inhibitingly overlapping accesses."); | |||
3438 | } | |||
3439 | ||||
3440 | propagate_all_subaccesses (); | |||
3441 | ||||
3442 | bool optimize_speed_p = !optimize_function_for_size_p (cfun(cfun + 0)); | |||
3443 | /* If the user didn't set PARAM_SRA_MAX_SCALARIZATION_SIZE_<...>, | |||
3444 | fall back to a target default. */ | |||
3445 | unsigned HOST_WIDE_INTlong max_scalarization_size | |||
3446 | = get_move_ratio (optimize_speed_p) * UNITS_PER_WORD(((global_options.x_ix86_isa_flags & (1UL << 1)) != 0) ? 8 : 4); | |||
3447 | ||||
3448 | if (optimize_speed_p) | |||
3449 | { | |||
3450 | if (OPTION_SET_P (param_sra_max_scalarization_size_speed)global_options_set.x_param_sra_max_scalarization_size_speed) | |||
3451 | max_scalarization_size = param_sra_max_scalarization_size_speedglobal_options.x_param_sra_max_scalarization_size_speed; | |||
3452 | } | |||
3453 | else | |||
3454 | { | |||
3455 | if (OPTION_SET_P (param_sra_max_scalarization_size_size)global_options_set.x_param_sra_max_scalarization_size_size) | |||
3456 | max_scalarization_size = param_sra_max_scalarization_size_sizeglobal_options.x_param_sra_max_scalarization_size_size; | |||
3457 | } | |||
3458 | max_scalarization_size *= BITS_PER_UNIT(8); | |||
3459 | ||||
3460 | EXECUTE_IF_SET_IN_BITMAP (candidate_bitmap, 0, i, bi)for (bmp_iter_set_init (&(bi), (candidate_bitmap), (0), & (i)); bmp_iter_set (&(bi), &(i)); bmp_iter_next (& (bi), &(i))) | |||
3461 | if (bitmap_bit_p (should_scalarize_away_bitmap, i) | |||
3462 | && !bitmap_bit_p (cannot_scalarize_away_bitmap, i)) | |||
3463 | { | |||
3464 | tree var = candidate (i); | |||
3465 | if (!VAR_P (var)(((enum tree_code) (var)->base.code) == VAR_DECL)) | |||
3466 | continue; | |||
3467 | ||||
3468 | if (tree_to_uhwi (TYPE_SIZE (TREE_TYPE (var))((tree_class_check ((((contains_struct_check ((var), (TS_TYPED ), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 3468, __FUNCTION__))->typed.type)), (tcc_type), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 3468, __FUNCTION__))->type_common.size)) > max_scalarization_size) | |||
3469 | { | |||
3470 | if (dump_file && (dump_flags & TDF_DETAILS)) | |||
3471 | { | |||
3472 | fprintf (dump_file, "Too big to totally scalarize: "); | |||
3473 | print_generic_expr (dump_file, var); | |||
3474 | fprintf (dump_file, " (UID: %u)\n", DECL_UID (var)((contains_struct_check ((var), (TS_DECL_MINIMAL), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 3474, __FUNCTION__))->decl_minimal.uid)); | |||
3475 | } | |||
3476 | continue; | |||
3477 | } | |||
3478 | ||||
3479 | bool all_types_ok = true; | |||
3480 | for (struct access *access = get_first_repr_for_decl (var); | |||
3481 | access; | |||
3482 | access = access->next_grp) | |||
3483 | if (!can_totally_scalarize_forest_p (access) | |||
3484 | || !scalarizable_type_p (access->type, constant_decl_p (var))) | |||
3485 | { | |||
3486 | all_types_ok = false; | |||
3487 | break; | |||
3488 | } | |||
3489 | if (!all_types_ok) | |||
3490 | continue; | |||
3491 | ||||
3492 | if (dump_file && (dump_flags & TDF_DETAILS)) | |||
3493 | { | |||
3494 | fprintf (dump_file, "Will attempt to totally scalarize "); | |||
3495 | print_generic_expr (dump_file, var); | |||
3496 | fprintf (dump_file, " (UID: %u): \n", DECL_UID (var)((contains_struct_check ((var), (TS_DECL_MINIMAL), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 3496, __FUNCTION__))->decl_minimal.uid)); | |||
3497 | } | |||
3498 | bool scalarized = true; | |||
3499 | for (struct access *access = get_first_repr_for_decl (var); | |||
3500 | access; | |||
3501 | access = access->next_grp) | |||
3502 | if (!is_gimple_reg_type (access->type) | |||
3503 | && !totally_scalarize_subtree (access)) | |||
3504 | { | |||
3505 | scalarized = false; | |||
3506 | break; | |||
3507 | } | |||
3508 | ||||
3509 | if (scalarized) | |||
3510 | for (struct access *access = get_first_repr_for_decl (var); | |||
3511 | access; | |||
3512 | access = access->next_grp) | |||
3513 | access->grp_total_scalarization = true; | |||
3514 | } | |||
3515 | ||||
3516 | if (flag_checkingglobal_options.x_flag_checking) | |||
3517 | verify_all_sra_access_forests (); | |||
3518 | ||||
3519 | bitmap_copy (tmp, candidate_bitmap); | |||
3520 | EXECUTE_IF_SET_IN_BITMAP (tmp, 0, i, bi)for (bmp_iter_set_init (&(bi), (tmp), (0), &(i)); bmp_iter_set (&(bi), &(i)); bmp_iter_next (&(bi), &(i))) | |||
3521 | { | |||
3522 | tree var = candidate (i); | |||
3523 | struct access *access = get_first_repr_for_decl (var); | |||
3524 | ||||
3525 | if (analyze_access_trees (access)) | |||
3526 | { | |||
3527 | res++; | |||
3528 | if (dump_file && (dump_flags & TDF_DETAILS)) | |||
3529 | { | |||
3530 | fprintf (dump_file, "\nAccess trees for "); | |||
3531 | print_generic_expr (dump_file, var); | |||
3532 | fprintf (dump_file, " (UID: %u): \n", DECL_UID (var)((contains_struct_check ((var), (TS_DECL_MINIMAL), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 3532, __FUNCTION__))->decl_minimal.uid)); | |||
3533 | dump_access_tree (dump_file, access); | |||
3534 | fprintf (dump_file, "\n"); | |||
3535 | } | |||
3536 | } | |||
3537 | else | |||
3538 | disqualify_candidate (var, "No scalar replacements to be created."); | |||
3539 | } | |||
3540 | ||||
3541 | BITMAP_FREE (tmp)((void) (bitmap_obstack_free ((bitmap) tmp), (tmp) = (bitmap) nullptr)); | |||
3542 | ||||
3543 | if (res) | |||
3544 | { | |||
3545 | statistics_counter_event (cfun(cfun + 0), "Scalarized aggregates", res); | |||
3546 | return true; | |||
3547 | } | |||
3548 | else | |||
3549 | return false; | |||
3550 | } | |||
3551 | ||||
3552 | /* Generate statements copying scalar replacements of accesses within a subtree | |||
3553 | into or out of AGG. ACCESS, all its children, siblings and their children | |||
3554 | are to be processed. AGG is an aggregate type expression (can be a | |||
3555 | declaration but does not have to be, it can for example also be a mem_ref or | |||
3556 | a series of handled components). TOP_OFFSET is the offset of the processed | |||
3557 | subtree which has to be subtracted from offsets of individual accesses to | |||
3558 | get corresponding offsets for AGG. If CHUNK_SIZE is non-null, copy only | |||
3559 | replacements in the interval <start_offset, start_offset + chunk_size>, | |||
3560 | otherwise copy all. GSI is a statement iterator used to place the new | |||
3561 | statements. WRITE should be true when the statements should write from AGG | |||
3562 | to the replacement and false if vice versa. if INSERT_AFTER is true, new | |||
3563 | statements will be added after the current statement in GSI, they will be | |||
3564 | added before the statement otherwise. */ | |||
3565 | ||||
3566 | static void | |||
3567 | generate_subtree_copies (struct access *access, tree agg, | |||
3568 | HOST_WIDE_INTlong top_offset, | |||
3569 | HOST_WIDE_INTlong start_offset, HOST_WIDE_INTlong chunk_size, | |||
3570 | gimple_stmt_iterator *gsi, bool write, | |||
3571 | bool insert_after, location_t loc) | |||
3572 | { | |||
3573 | /* Never write anything into constant pool decls. See PR70602. */ | |||
3574 | if (!write && constant_decl_p (agg)) | |||
3575 | return; | |||
3576 | do | |||
3577 | { | |||
3578 | if (chunk_size && access->offset >= start_offset + chunk_size) | |||
3579 | return; | |||
3580 | ||||
3581 | if (access->grp_to_be_replaced | |||
3582 | && (chunk_size == 0 | |||
3583 | || access->offset + access->size > start_offset)) | |||
3584 | { | |||
3585 | tree expr, repl = get_access_replacement (access); | |||
3586 | gassign *stmt; | |||
3587 | ||||
3588 | expr = build_ref_for_model (loc, agg, access->offset - top_offset, | |||
3589 | access, gsi, insert_after); | |||
3590 | ||||
3591 | if (write) | |||
3592 | { | |||
3593 | if (access->grp_partial_lhs) | |||
3594 | expr = force_gimple_operand_gsi (gsi, expr, true, NULL_TREE(tree) nullptr, | |||
3595 | !insert_after, | |||
3596 | insert_after ? GSI_NEW_STMT | |||
3597 | : GSI_SAME_STMT); | |||
3598 | stmt = gimple_build_assign (repl, expr); | |||
3599 | } | |||
3600 | else | |||
3601 | { | |||
3602 | suppress_warning (repl /* Be more selective! */); | |||
3603 | if (access->grp_partial_lhs) | |||
3604 | repl = force_gimple_operand_gsi (gsi, repl, true, NULL_TREE(tree) nullptr, | |||
3605 | !insert_after, | |||
3606 | insert_after ? GSI_NEW_STMT | |||
3607 | : GSI_SAME_STMT); | |||
3608 | stmt = gimple_build_assign (expr, repl); | |||
3609 | } | |||
3610 | gimple_set_location (stmt, loc); | |||
3611 | ||||
3612 | if (insert_after) | |||
3613 | gsi_insert_after (gsi, stmt, GSI_NEW_STMT); | |||
3614 | else | |||
3615 | gsi_insert_before (gsi, stmt, GSI_SAME_STMT); | |||
3616 | update_stmt (stmt); | |||
3617 | sra_stats.subtree_copies++; | |||
3618 | } | |||
3619 | else if (write | |||
3620 | && access->grp_to_be_debug_replaced | |||
3621 | && (chunk_size == 0 | |||
3622 | || access->offset + access->size > start_offset)) | |||
3623 | { | |||
3624 | gdebug *ds; | |||
3625 | tree drhs = build_debug_ref_for_model (loc, agg, | |||
3626 | access->offset - top_offset, | |||
3627 | access); | |||
3628 | ds = gimple_build_debug_bind (get_access_replacement (access), | |||
3629 | drhs, gsi_stmt (*gsi)); | |||
3630 | if (insert_after) | |||
3631 | gsi_insert_after (gsi, ds, GSI_NEW_STMT); | |||
3632 | else | |||
3633 | gsi_insert_before (gsi, ds, GSI_SAME_STMT); | |||
3634 | } | |||
3635 | ||||
3636 | if (access->first_child) | |||
3637 | generate_subtree_copies (access->first_child, agg, top_offset, | |||
3638 | start_offset, chunk_size, gsi, | |||
3639 | write, insert_after, loc); | |||
3640 | ||||
3641 | access = access->next_sibling; | |||
3642 | } | |||
3643 | while (access); | |||
3644 | } | |||
3645 | ||||
3646 | /* Assign zero to all scalar replacements in an access subtree. ACCESS is the | |||
3647 | root of the subtree to be processed. GSI is the statement iterator used | |||
3648 | for inserting statements which are added after the current statement if | |||
3649 | INSERT_AFTER is true or before it otherwise. */ | |||
3650 | ||||
3651 | static void | |||
3652 | init_subtree_with_zero (struct access *access, gimple_stmt_iterator *gsi, | |||
3653 | bool insert_after, location_t loc) | |||
3654 | ||||
3655 | { | |||
3656 | struct access *child; | |||
3657 | ||||
3658 | if (access->grp_to_be_replaced) | |||
3659 | { | |||
3660 | gassign *stmt; | |||
3661 | ||||
3662 | stmt = gimple_build_assign (get_access_replacement (access), | |||
3663 | build_zero_cst (access->type)); | |||
3664 | if (insert_after) | |||
3665 | gsi_insert_after (gsi, stmt, GSI_NEW_STMT); | |||
3666 | else | |||
3667 | gsi_insert_before (gsi, stmt, GSI_SAME_STMT); | |||
3668 | update_stmt (stmt); | |||
3669 | gimple_set_location (stmt, loc); | |||
3670 | } | |||
3671 | else if (access->grp_to_be_debug_replaced) | |||
3672 | { | |||
3673 | gdebug *ds | |||
3674 | = gimple_build_debug_bind (get_access_replacement (access), | |||
3675 | build_zero_cst (access->type), | |||
3676 | gsi_stmt (*gsi)); | |||
3677 | if (insert_after) | |||
3678 | gsi_insert_after (gsi, ds, GSI_NEW_STMT); | |||
3679 | else | |||
3680 | gsi_insert_before (gsi, ds, GSI_SAME_STMT); | |||
3681 | } | |||
3682 | ||||
3683 | for (child = access->first_child; child; child = child->next_sibling) | |||
3684 | init_subtree_with_zero (child, gsi, insert_after, loc); | |||
3685 | } | |||
3686 | ||||
3687 | /* Clobber all scalar replacements in an access subtree. ACCESS is the | |||
3688 | root of the subtree to be processed. GSI is the statement iterator used | |||
3689 | for inserting statements which are added after the current statement if | |||
3690 | INSERT_AFTER is true or before it otherwise. */ | |||
3691 | ||||
3692 | static void | |||
3693 | clobber_subtree (struct access *access, gimple_stmt_iterator *gsi, | |||
3694 | bool insert_after, location_t loc) | |||
3695 | ||||
3696 | { | |||
3697 | struct access *child; | |||
3698 | ||||
3699 | if (access->grp_to_be_replaced) | |||
3700 | { | |||
3701 | tree rep = get_access_replacement (access); | |||
3702 | tree clobber = build_clobber (access->type); | |||
3703 | gimple *stmt = gimple_build_assign (rep, clobber); | |||
3704 | ||||
3705 | if (insert_after) | |||
3706 | gsi_insert_after (gsi, stmt, GSI_NEW_STMT); | |||
3707 | else | |||
3708 | gsi_insert_before (gsi, stmt, GSI_SAME_STMT); | |||
3709 | update_stmt (stmt); | |||
3710 | gimple_set_location (stmt, loc); | |||
3711 | } | |||
3712 | ||||
3713 | for (child = access->first_child; child; child = child->next_sibling) | |||
3714 | clobber_subtree (child, gsi, insert_after, loc); | |||
3715 | } | |||
3716 | ||||
3717 | /* Search for an access representative for the given expression EXPR and | |||
3718 | return it or NULL if it cannot be found. */ | |||
3719 | ||||
3720 | static struct access * | |||
3721 | get_access_for_expr (tree expr) | |||
3722 | { | |||
3723 | poly_int64 poffset, psize, pmax_size; | |||
3724 | HOST_WIDE_INTlong offset, max_size; | |||
3725 | tree base; | |||
3726 | bool reverse; | |||
3727 | ||||
3728 | /* FIXME: This should not be necessary but Ada produces V_C_Es with a type of | |||
3729 | a different size than the size of its argument and we need the latter | |||
3730 | one. */ | |||
3731 | if (TREE_CODE (expr)((enum tree_code) (expr)->base.code) == VIEW_CONVERT_EXPR) | |||
3732 | expr = TREE_OPERAND (expr, 0)(*((const_cast<tree*> (tree_operand_check ((expr), (0), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 3732, __FUNCTION__))))); | |||
3733 | ||||
3734 | base = get_ref_base_and_extent (expr, &poffset, &psize, &pmax_size, | |||
3735 | &reverse); | |||
3736 | if (!known_size_p (pmax_size) | |||
3737 | || !pmax_size.is_constant (&max_size) | |||
3738 | || !poffset.is_constant (&offset) | |||
3739 | || !DECL_P (base)(tree_code_type_tmpl <0>::tree_code_type[(int) (((enum tree_code ) (base)->base.code))] == tcc_declaration)) | |||
3740 | return NULLnullptr; | |||
3741 | ||||
3742 | if (tree basesize = DECL_SIZE (base)((contains_struct_check ((base), (TS_DECL_COMMON), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 3742, __FUNCTION__))->decl_common.size)) | |||
3743 | { | |||
3744 | poly_int64 sz; | |||
3745 | if (offset < 0 | |||
3746 | || !poly_int_tree_p (basesize, &sz) | |||
3747 | || known_le (sz, offset)(!maybe_lt (offset, sz))) | |||
3748 | return NULLnullptr; | |||
3749 | } | |||
3750 | ||||
3751 | if (max_size == 0 | |||
3752 | || !bitmap_bit_p (candidate_bitmap, DECL_UID (base)((contains_struct_check ((base), (TS_DECL_MINIMAL), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 3752, __FUNCTION__))->decl_minimal.uid))) | |||
3753 | return NULLnullptr; | |||
3754 | ||||
3755 | return get_var_base_offset_size_access (base, offset, max_size); | |||
3756 | } | |||
3757 | ||||
3758 | /* Replace the expression EXPR with a scalar replacement if there is one and | |||
3759 | generate other statements to do type conversion or subtree copying if | |||
3760 | necessary. GSI is used to place newly created statements, WRITE is true if | |||
3761 | the expression is being written to (it is on a LHS of a statement or output | |||
3762 | in an assembly statement). */ | |||
3763 | ||||
3764 | static bool | |||
3765 | sra_modify_expr (tree *expr, gimple_stmt_iterator *gsi, bool write) | |||
3766 | { | |||
3767 | location_t loc; | |||
3768 | struct access *access; | |||
3769 | tree type, bfr, orig_expr; | |||
3770 | bool partial_cplx_access = false; | |||
3771 | ||||
3772 | if (TREE_CODE (*expr)((enum tree_code) (*expr)->base.code) == BIT_FIELD_REF) | |||
3773 | { | |||
3774 | bfr = *expr; | |||
3775 | expr = &TREE_OPERAND (*expr, 0)(*((const_cast<tree*> (tree_operand_check ((*expr), (0) , "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 3775, __FUNCTION__))))); | |||
3776 | } | |||
3777 | else | |||
3778 | bfr = NULL_TREE(tree) nullptr; | |||
3779 | ||||
3780 | if (TREE_CODE (*expr)((enum tree_code) (*expr)->base.code) == REALPART_EXPR || TREE_CODE (*expr)((enum tree_code) (*expr)->base.code) == IMAGPART_EXPR) | |||
3781 | { | |||
3782 | expr = &TREE_OPERAND (*expr, 0)(*((const_cast<tree*> (tree_operand_check ((*expr), (0) , "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 3782, __FUNCTION__))))); | |||
3783 | partial_cplx_access = true; | |||
3784 | } | |||
3785 | access = get_access_for_expr (*expr); | |||
3786 | if (!access) | |||
3787 | return false; | |||
3788 | type = TREE_TYPE (*expr)((contains_struct_check ((*expr), (TS_TYPED), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 3788, __FUNCTION__))->typed.type); | |||
3789 | orig_expr = *expr; | |||
3790 | ||||
3791 | loc = gimple_location (gsi_stmt (*gsi)); | |||
3792 | gimple_stmt_iterator alt_gsi = gsi_none (); | |||
3793 | if (write && stmt_ends_bb_p (gsi_stmt (*gsi))) | |||
3794 | { | |||
3795 | alt_gsi = gsi_start_edge (single_non_eh_succ (gsi_bb (*gsi))); | |||
3796 | gsi = &alt_gsi; | |||
3797 | } | |||
3798 | ||||
3799 | if (access->grp_to_be_replaced) | |||
3800 | { | |||
3801 | tree repl = get_access_replacement (access); | |||
3802 | /* If we replace a non-register typed access simply use the original | |||
3803 | access expression to extract the scalar component afterwards. | |||
3804 | This happens if scalarizing a function return value or parameter | |||
3805 | like in gcc.c-torture/execute/20041124-1.c, 20050316-1.c and | |||
3806 | gcc.c-torture/compile/20011217-1.c. | |||
3807 | ||||
3808 | We also want to use this when accessing a complex or vector which can | |||
3809 | be accessed as a different type too, potentially creating a need for | |||
3810 | type conversion (see PR42196) and when scalarized unions are involved | |||
3811 | in assembler statements (see PR42398). */ | |||
3812 | if (!bfr && !useless_type_conversion_p (type, access->type)) | |||
3813 | { | |||
3814 | tree ref; | |||
3815 | ||||
3816 | ref = build_ref_for_model (loc, orig_expr, 0, access, gsi, false); | |||
3817 | ||||
3818 | if (partial_cplx_access) | |||
3819 | { | |||
3820 | /* VIEW_CONVERT_EXPRs in partial complex access are always fine in | |||
3821 | the case of a write because in such case the replacement cannot | |||
3822 | be a gimple register. In the case of a load, we have to | |||
3823 | differentiate in between a register an non-register | |||
3824 | replacement. */ | |||
3825 | tree t = build1 (VIEW_CONVERT_EXPR, type, repl); | |||
3826 | gcc_checking_assert (!write || access->grp_partial_lhs)((void)(!(!write || access->grp_partial_lhs) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 3826, __FUNCTION__), 0 : 0)); | |||
3827 | if (!access->grp_partial_lhs) | |||
3828 | { | |||
3829 | tree tmp = make_ssa_name (type); | |||
3830 | gassign *stmt = gimple_build_assign (tmp, t); | |||
3831 | /* This is always a read. */ | |||
3832 | gsi_insert_before (gsi, stmt, GSI_SAME_STMT); | |||
3833 | t = tmp; | |||
3834 | } | |||
3835 | *expr = t; | |||
3836 | } | |||
3837 | else if (write) | |||
3838 | { | |||
3839 | gassign *stmt; | |||
3840 | ||||
3841 | if (access->grp_partial_lhs) | |||
3842 | ref = force_gimple_operand_gsi (gsi, ref, true, NULL_TREE(tree) nullptr, | |||
3843 | false, GSI_NEW_STMT); | |||
3844 | stmt = gimple_build_assign (repl, ref); | |||
3845 | gimple_set_location (stmt, loc); | |||
3846 | gsi_insert_after (gsi, stmt, GSI_NEW_STMT); | |||
3847 | } | |||
3848 | else | |||
3849 | { | |||
3850 | gassign *stmt; | |||
3851 | ||||
3852 | if (access->grp_partial_lhs) | |||
3853 | repl = force_gimple_operand_gsi (gsi, repl, true, NULL_TREE(tree) nullptr, | |||
3854 | true, GSI_SAME_STMT); | |||
3855 | stmt = gimple_build_assign (ref, repl); | |||
3856 | gimple_set_location (stmt, loc); | |||
3857 | gsi_insert_before (gsi, stmt, GSI_SAME_STMT); | |||
3858 | } | |||
3859 | } | |||
3860 | else | |||
3861 | { | |||
3862 | /* If we are going to replace a scalar field in a structure with | |||
3863 | reverse storage order by a stand-alone scalar, we are going to | |||
3864 | effectively byte-swap the scalar and we also need to byte-swap | |||
3865 | the portion of it represented by the bit-field. */ | |||
3866 | if (bfr && REF_REVERSE_STORAGE_ORDER (bfr)((tree_check2 ((bfr), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 3866, __FUNCTION__, (BIT_FIELD_REF), (MEM_REF)))->base.default_def_flag )) | |||
3867 | { | |||
3868 | REF_REVERSE_STORAGE_ORDER (bfr)((tree_check2 ((bfr), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 3868, __FUNCTION__, (BIT_FIELD_REF), (MEM_REF)))->base.default_def_flag ) = 0; | |||
3869 | TREE_OPERAND (bfr, 2)(*((const_cast<tree*> (tree_operand_check ((bfr), (2), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 3869, __FUNCTION__))))) | |||
3870 | = size_binop (MINUS_EXPR, TYPE_SIZE (TREE_TYPE (repl)),size_binop_loc (((location_t) 0), MINUS_EXPR, ((tree_class_check ((((contains_struct_check ((repl), (TS_TYPED), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 3870, __FUNCTION__))->typed.type)), (tcc_type), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 3870, __FUNCTION__))->type_common.size), size_binop_loc ( ((location_t) 0), PLUS_EXPR, (*((const_cast<tree*> (tree_operand_check ((bfr), (1), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 3871, __FUNCTION__))))), (*((const_cast<tree*> (tree_operand_check ((bfr), (2), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 3872, __FUNCTION__))))))) | |||
3871 | size_binop (PLUS_EXPR, TREE_OPERAND (bfr, 1),size_binop_loc (((location_t) 0), MINUS_EXPR, ((tree_class_check ((((contains_struct_check ((repl), (TS_TYPED), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 3870, __FUNCTION__))->typed.type)), (tcc_type), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 3870, __FUNCTION__))->type_common.size), size_binop_loc ( ((location_t) 0), PLUS_EXPR, (*((const_cast<tree*> (tree_operand_check ((bfr), (1), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 3871, __FUNCTION__))))), (*((const_cast<tree*> (tree_operand_check ((bfr), (2), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 3872, __FUNCTION__))))))) | |||
3872 | TREE_OPERAND (bfr, 2)))size_binop_loc (((location_t) 0), MINUS_EXPR, ((tree_class_check ((((contains_struct_check ((repl), (TS_TYPED), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 3870, __FUNCTION__))->typed.type)), (tcc_type), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 3870, __FUNCTION__))->type_common.size), size_binop_loc ( ((location_t) 0), PLUS_EXPR, (*((const_cast<tree*> (tree_operand_check ((bfr), (1), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 3871, __FUNCTION__))))), (*((const_cast<tree*> (tree_operand_check ((bfr), (2), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 3872, __FUNCTION__))))))); | |||
3873 | } | |||
3874 | ||||
3875 | *expr = repl; | |||
3876 | } | |||
3877 | ||||
3878 | sra_stats.exprs++; | |||
3879 | } | |||
3880 | else if (write && access->grp_to_be_debug_replaced) | |||
3881 | { | |||
3882 | gdebug *ds = gimple_build_debug_bind (get_access_replacement (access), | |||
3883 | NULL_TREE(tree) nullptr, | |||
3884 | gsi_stmt (*gsi)); | |||
3885 | gsi_insert_after (gsi, ds, GSI_NEW_STMT); | |||
3886 | } | |||
3887 | ||||
3888 | if (access->first_child && !TREE_READONLY (access->base)((non_type_check ((access->base), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 3888, __FUNCTION__))->base.readonly_flag)) | |||
3889 | { | |||
3890 | HOST_WIDE_INTlong start_offset, chunk_size; | |||
3891 | if (bfr | |||
3892 | && tree_fits_uhwi_p (TREE_OPERAND (bfr, 1)(*((const_cast<tree*> (tree_operand_check ((bfr), (1), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 3892, __FUNCTION__)))))) | |||
3893 | && tree_fits_uhwi_p (TREE_OPERAND (bfr, 2)(*((const_cast<tree*> (tree_operand_check ((bfr), (2), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 3893, __FUNCTION__))))))) | |||
3894 | { | |||
3895 | chunk_size = tree_to_uhwi (TREE_OPERAND (bfr, 1)(*((const_cast<tree*> (tree_operand_check ((bfr), (1), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 3895, __FUNCTION__)))))); | |||
3896 | start_offset = access->offset | |||
3897 | + tree_to_uhwi (TREE_OPERAND (bfr, 2)(*((const_cast<tree*> (tree_operand_check ((bfr), (2), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 3897, __FUNCTION__)))))); | |||
3898 | } | |||
3899 | else | |||
3900 | start_offset = chunk_size = 0; | |||
3901 | ||||
3902 | generate_subtree_copies (access->first_child, orig_expr, access->offset, | |||
3903 | start_offset, chunk_size, gsi, write, write, | |||
3904 | loc); | |||
3905 | } | |||
3906 | return true; | |||
3907 | } | |||
3908 | ||||
3909 | /* Where scalar replacements of the RHS have been written to when a replacement | |||
3910 | of a LHS of an assigments cannot be direclty loaded from a replacement of | |||
3911 | the RHS. */ | |||
3912 | enum unscalarized_data_handling { SRA_UDH_NONE, /* Nothing done so far. */ | |||
3913 | SRA_UDH_RIGHT, /* Data flushed to the RHS. */ | |||
3914 | SRA_UDH_LEFT }; /* Data flushed to the LHS. */ | |||
3915 | ||||
3916 | struct subreplacement_assignment_data | |||
3917 | { | |||
3918 | /* Offset of the access representing the lhs of the assignment. */ | |||
3919 | HOST_WIDE_INTlong left_offset; | |||
3920 | ||||
3921 | /* LHS and RHS of the original assignment. */ | |||
3922 | tree assignment_lhs, assignment_rhs; | |||
3923 | ||||
3924 | /* Access representing the rhs of the whole assignment. */ | |||
3925 | struct access *top_racc; | |||
3926 | ||||
3927 | /* Stmt iterator used for statement insertions after the original assignment. | |||
3928 | It points to the main GSI used to traverse a BB during function body | |||
3929 | modification. */ | |||
3930 | gimple_stmt_iterator *new_gsi; | |||
3931 | ||||
3932 | /* Stmt iterator used for statement insertions before the original | |||
3933 | assignment. Keeps on pointing to the original statement. */ | |||
3934 | gimple_stmt_iterator old_gsi; | |||
3935 | ||||
3936 | /* Location of the assignment. */ | |||
3937 | location_t loc; | |||
3938 | ||||
3939 | /* Keeps the information whether we have needed to refresh replacements of | |||
3940 | the LHS and from which side of the assignments this takes place. */ | |||
3941 | enum unscalarized_data_handling refreshed; | |||
3942 | }; | |||
3943 | ||||
3944 | /* Store all replacements in the access tree rooted in TOP_RACC either to their | |||
3945 | base aggregate if there are unscalarized data or directly to LHS of the | |||
3946 | statement that is pointed to by GSI otherwise. */ | |||
3947 | ||||
3948 | static void | |||
3949 | handle_unscalarized_data_in_subtree (struct subreplacement_assignment_data *sad) | |||
3950 | { | |||
3951 | tree src; | |||
3952 | /* If the RHS is a load from a constant, we do not need to (and must not) | |||
3953 | flush replacements to it and can use it directly as if we did. */ | |||
3954 | if (TREE_READONLY (sad->top_racc->base)((non_type_check ((sad->top_racc->base), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 3954, __FUNCTION__))->base.readonly_flag)) | |||
3955 | { | |||
3956 | sad->refreshed = SRA_UDH_RIGHT; | |||
3957 | return; | |||
3958 | } | |||
3959 | if (sad->top_racc->grp_unscalarized_data) | |||
3960 | { | |||
3961 | src = sad->assignment_rhs; | |||
3962 | sad->refreshed = SRA_UDH_RIGHT; | |||
3963 | } | |||
3964 | else | |||
3965 | { | |||
3966 | src = sad->assignment_lhs; | |||
3967 | sad->refreshed = SRA_UDH_LEFT; | |||
3968 | } | |||
3969 | generate_subtree_copies (sad->top_racc->first_child, src, | |||
3970 | sad->top_racc->offset, 0, 0, | |||
3971 | &sad->old_gsi, false, false, sad->loc); | |||
3972 | } | |||
3973 | ||||
3974 | /* Try to generate statements to load all sub-replacements in an access subtree | |||
3975 | formed by children of LACC from scalar replacements in the SAD->top_racc | |||
3976 | subtree. If that is not possible, refresh the SAD->top_racc base aggregate | |||
3977 | and load the accesses from it. */ | |||
3978 | ||||
3979 | static void | |||
3980 | load_assign_lhs_subreplacements (struct access *lacc, | |||
3981 | struct subreplacement_assignment_data *sad) | |||
3982 | { | |||
3983 | for (lacc = lacc->first_child; lacc; lacc = lacc->next_sibling) | |||
3984 | { | |||
3985 | HOST_WIDE_INTlong offset; | |||
3986 | offset = lacc->offset - sad->left_offset + sad->top_racc->offset; | |||
3987 | ||||
3988 | if (lacc->grp_to_be_replaced) | |||
3989 | { | |||
3990 | struct access *racc; | |||
3991 | gassign *stmt; | |||
3992 | tree rhs; | |||
3993 | ||||
3994 | racc = find_access_in_subtree (sad->top_racc, offset, lacc->size); | |||
3995 | if (racc && racc->grp_to_be_replaced) | |||
3996 | { | |||
3997 | rhs = get_access_replacement (racc); | |||
3998 | if (!useless_type_conversion_p (lacc->type, racc->type)) | |||
3999 | rhs = fold_build1_loc (sad->loc, VIEW_CONVERT_EXPR, | |||
4000 | lacc->type, rhs); | |||
4001 | ||||
4002 | if (racc->grp_partial_lhs && lacc->grp_partial_lhs) | |||
4003 | rhs = force_gimple_operand_gsi (&sad->old_gsi, rhs, true, | |||
4004 | NULL_TREE(tree) nullptr, true, GSI_SAME_STMT); | |||
4005 | } | |||
4006 | else | |||
4007 | { | |||
4008 | /* No suitable access on the right hand side, need to load from | |||
4009 | the aggregate. See if we have to update it first... */ | |||
4010 | if (sad->refreshed == SRA_UDH_NONE) | |||
4011 | handle_unscalarized_data_in_subtree (sad); | |||
4012 | ||||
4013 | if (sad->refreshed == SRA_UDH_LEFT) | |||
4014 | rhs = build_ref_for_model (sad->loc, sad->assignment_lhs, | |||
4015 | lacc->offset - sad->left_offset, | |||
4016 | lacc, sad->new_gsi, true); | |||
4017 | else | |||
4018 | rhs = build_ref_for_model (sad->loc, sad->assignment_rhs, | |||
4019 | lacc->offset - sad->left_offset, | |||
4020 | lacc, sad->new_gsi, true); | |||
4021 | if (lacc->grp_partial_lhs) | |||
4022 | rhs = force_gimple_operand_gsi (sad->new_gsi, | |||
4023 | rhs, true, NULL_TREE(tree) nullptr, | |||
4024 | false, GSI_NEW_STMT); | |||
4025 | } | |||
4026 | ||||
4027 | stmt = gimple_build_assign (get_access_replacement (lacc), rhs); | |||
4028 | gsi_insert_after (sad->new_gsi, stmt, GSI_NEW_STMT); | |||
4029 | gimple_set_location (stmt, sad->loc); | |||
4030 | update_stmt (stmt); | |||
4031 | sra_stats.subreplacements++; | |||
4032 | } | |||
4033 | else | |||
4034 | { | |||
4035 | if (sad->refreshed == SRA_UDH_NONE | |||
4036 | && lacc->grp_read && !lacc->grp_covered) | |||
4037 | handle_unscalarized_data_in_subtree (sad); | |||
4038 | ||||
4039 | if (lacc && lacc->grp_to_be_debug_replaced) | |||
4040 | { | |||
4041 | gdebug *ds; | |||
4042 | tree drhs; | |||
4043 | struct access *racc = find_access_in_subtree (sad->top_racc, | |||
4044 | offset, | |||
4045 | lacc->size); | |||
4046 | ||||
4047 | if (racc && racc->grp_to_be_replaced) | |||
4048 | { | |||
4049 | if (racc->grp_write || constant_decl_p (racc->base)) | |||
4050 | drhs = get_access_replacement (racc); | |||
4051 | else | |||
4052 | drhs = NULLnullptr; | |||
4053 | } | |||
4054 | else if (sad->refreshed == SRA_UDH_LEFT) | |||
4055 | drhs = build_debug_ref_for_model (sad->loc, lacc->base, | |||
4056 | lacc->offset, lacc); | |||
4057 | else if (sad->refreshed == SRA_UDH_RIGHT) | |||
4058 | drhs = build_debug_ref_for_model (sad->loc, sad->top_racc->base, | |||
4059 | offset, lacc); | |||
4060 | else | |||
4061 | drhs = NULL_TREE(tree) nullptr; | |||
4062 | if (drhs | |||
4063 | && !useless_type_conversion_p (lacc->type, TREE_TYPE (drhs)((contains_struct_check ((drhs), (TS_TYPED), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 4063, __FUNCTION__))->typed.type))) | |||
4064 | drhs = fold_build1_loc (sad->loc, VIEW_CONVERT_EXPR, | |||
4065 | lacc->type, drhs); | |||
4066 | ds = gimple_build_debug_bind (get_access_replacement (lacc), | |||
4067 | drhs, gsi_stmt (sad->old_gsi)); | |||
4068 | gsi_insert_after (sad->new_gsi, ds, GSI_NEW_STMT); | |||
4069 | } | |||
4070 | } | |||
4071 | ||||
4072 | if (lacc->first_child) | |||
4073 | load_assign_lhs_subreplacements (lacc, sad); | |||
4074 | } | |||
4075 | } | |||
4076 | ||||
4077 | /* Result code for SRA assignment modification. */ | |||
4078 | enum assignment_mod_result { SRA_AM_NONE, /* nothing done for the stmt */ | |||
4079 | SRA_AM_MODIFIED, /* stmt changed but not | |||
4080 | removed */ | |||
4081 | SRA_AM_REMOVED }; /* stmt eliminated */ | |||
4082 | ||||
4083 | /* Modify assignments with a CONSTRUCTOR on their RHS. STMT contains a pointer | |||
4084 | to the assignment and GSI is the statement iterator pointing at it. Returns | |||
4085 | the same values as sra_modify_assign. */ | |||
4086 | ||||
4087 | static enum assignment_mod_result | |||
4088 | sra_modify_constructor_assign (gimple *stmt, gimple_stmt_iterator *gsi) | |||
4089 | { | |||
4090 | tree lhs = gimple_assign_lhs (stmt); | |||
4091 | struct access *acc = get_access_for_expr (lhs); | |||
4092 | if (!acc) | |||
4093 | return SRA_AM_NONE; | |||
4094 | location_t loc = gimple_location (stmt); | |||
4095 | ||||
4096 | if (gimple_clobber_p (stmt)) | |||
4097 | { | |||
4098 | /* Clobber the replacement variable. */ | |||
4099 | clobber_subtree (acc, gsi, !acc->grp_covered, loc); | |||
4100 | /* Remove clobbers of fully scalarized variables, they are dead. */ | |||
4101 | if (acc->grp_covered) | |||
4102 | { | |||
4103 | unlink_stmt_vdef (stmt); | |||
4104 | gsi_remove (gsi, true); | |||
4105 | release_defs (stmt); | |||
4106 | return SRA_AM_REMOVED; | |||
4107 | } | |||
4108 | else | |||
4109 | return SRA_AM_MODIFIED; | |||
4110 | } | |||
4111 | ||||
4112 | if (CONSTRUCTOR_NELTS (gimple_assign_rhs1 (stmt))(vec_safe_length (((tree_check ((gimple_assign_rhs1 (stmt)), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 4112, __FUNCTION__, (CONSTRUCTOR)))->constructor.elts))) > 0) | |||
4113 | { | |||
4114 | /* I have never seen this code path trigger but if it can happen the | |||
4115 | following should handle it gracefully. */ | |||
4116 | if (access_has_children_p (acc)) | |||
4117 | generate_subtree_copies (acc->first_child, lhs, acc->offset, 0, 0, gsi, | |||
4118 | true, true, loc); | |||
4119 | return SRA_AM_MODIFIED; | |||
4120 | } | |||
4121 | ||||
4122 | if (acc->grp_covered) | |||
4123 | { | |||
4124 | init_subtree_with_zero (acc, gsi, false, loc); | |||
4125 | unlink_stmt_vdef (stmt); | |||
4126 | gsi_remove (gsi, true); | |||
4127 | release_defs (stmt); | |||
4128 | return SRA_AM_REMOVED; | |||
4129 | } | |||
4130 | else | |||
4131 | { | |||
4132 | init_subtree_with_zero (acc, gsi, true, loc); | |||
4133 | return SRA_AM_MODIFIED; | |||
4134 | } | |||
4135 | } | |||
4136 | ||||
4137 | /* Create and return a new suitable default definition SSA_NAME for RACC which | |||
4138 | is an access describing an uninitialized part of an aggregate that is being | |||
4139 | loaded. REG_TREE is used instead of the actual RACC type if that is not of | |||
4140 | a gimple register type. */ | |||
4141 | ||||
4142 | static tree | |||
4143 | get_repl_default_def_ssa_name (struct access *racc, tree reg_type) | |||
4144 | { | |||
4145 | gcc_checking_assert (!racc->grp_to_be_replaced((void)(!(!racc->grp_to_be_replaced && !racc->grp_to_be_debug_replaced ) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 4146, __FUNCTION__), 0 : 0)) | |||
4146 | && !racc->grp_to_be_debug_replaced)((void)(!(!racc->grp_to_be_replaced && !racc->grp_to_be_debug_replaced ) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 4146, __FUNCTION__), 0 : 0)); | |||
4147 | if (!racc->replacement_decl) | |||
4148 | racc->replacement_decl = create_access_replacement (racc, reg_type); | |||
4149 | return get_or_create_ssa_default_def (cfun(cfun + 0), racc->replacement_decl); | |||
4150 | } | |||
4151 | ||||
4152 | ||||
4153 | /* Generate statements to call .DEFERRED_INIT to initialize scalar replacements | |||
4154 | of accesses within a subtree ACCESS; all its children, siblings and their | |||
4155 | children are to be processed. | |||
4156 | GSI is a statement iterator used to place the new statements. */ | |||
4157 | static void | |||
4158 | generate_subtree_deferred_init (struct access *access, | |||
4159 | tree init_type, | |||
4160 | tree decl_name, | |||
4161 | gimple_stmt_iterator *gsi, | |||
4162 | location_t loc) | |||
4163 | { | |||
4164 | do | |||
4165 | { | |||
4166 | if (access->grp_to_be_replaced) | |||
4167 | { | |||
4168 | tree repl = get_access_replacement (access); | |||
4169 | gimple *call | |||
4170 | = gimple_build_call_internal (IFN_DEFERRED_INIT, 3, | |||
4171 | TYPE_SIZE_UNIT (TREE_TYPE (repl))((tree_class_check ((((contains_struct_check ((repl), (TS_TYPED ), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 4171, __FUNCTION__))->typed.type)), (tcc_type), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 4171, __FUNCTION__))->type_common.size_unit), | |||
4172 | init_type, decl_name); | |||
4173 | gimple_call_set_lhs (call, repl); | |||
4174 | gsi_insert_before (gsi, call, GSI_SAME_STMT); | |||
4175 | update_stmt (call); | |||
4176 | gimple_set_location (call, loc); | |||
4177 | sra_stats.subtree_deferred_init++; | |||
4178 | } | |||
4179 | if (access->first_child) | |||
4180 | generate_subtree_deferred_init (access->first_child, init_type, | |||
4181 | decl_name, gsi, loc); | |||
4182 | ||||
4183 | access = access ->next_sibling; | |||
4184 | } | |||
4185 | while (access); | |||
4186 | } | |||
4187 | ||||
4188 | /* For a call to .DEFERRED_INIT: | |||
4189 | var = .DEFERRED_INIT (size_of_var, init_type, name_of_var); | |||
4190 | examine the LHS variable VAR and replace it with a scalar replacement if | |||
4191 | there is one, also replace the RHS call to a call to .DEFERRED_INIT of | |||
4192 | the corresponding scalar relacement variable. Examine the subtree and | |||
4193 | do the scalar replacements in the subtree too. STMT is the call, GSI is | |||
4194 | the statment iterator to place newly created statement. */ | |||
4195 | ||||
4196 | static enum assignment_mod_result | |||
4197 | sra_modify_deferred_init (gimple *stmt, gimple_stmt_iterator *gsi) | |||
4198 | { | |||
4199 | tree lhs = gimple_call_lhs (stmt); | |||
4200 | tree init_type = gimple_call_arg (stmt, 1); | |||
4201 | tree decl_name = gimple_call_arg (stmt, 2); | |||
4202 | ||||
4203 | struct access *lhs_access = get_access_for_expr (lhs); | |||
4204 | if (!lhs_access) | |||
4205 | return SRA_AM_NONE; | |||
4206 | ||||
4207 | location_t loc = gimple_location (stmt); | |||
4208 | ||||
4209 | if (lhs_access->grp_to_be_replaced) | |||
4210 | { | |||
4211 | tree lhs_repl = get_access_replacement (lhs_access); | |||
4212 | gimple_call_set_lhs (stmt, lhs_repl); | |||
4213 | tree arg0_repl = TYPE_SIZE_UNIT (TREE_TYPE (lhs_repl))((tree_class_check ((((contains_struct_check ((lhs_repl), (TS_TYPED ), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 4213, __FUNCTION__))->typed.type)), (tcc_type), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 4213, __FUNCTION__))->type_common.size_unit); | |||
4214 | gimple_call_set_arg (stmt, 0, arg0_repl); | |||
4215 | sra_stats.deferred_init++; | |||
4216 | gcc_assert (!lhs_access->first_child)((void)(!(!lhs_access->first_child) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 4216, __FUNCTION__), 0 : 0)); | |||
4217 | return SRA_AM_MODIFIED; | |||
4218 | } | |||
4219 | ||||
4220 | if (lhs_access->first_child) | |||
4221 | generate_subtree_deferred_init (lhs_access->first_child, | |||
4222 | init_type, decl_name, gsi, loc); | |||
4223 | if (lhs_access->grp_covered) | |||
4224 | { | |||
4225 | unlink_stmt_vdef (stmt); | |||
4226 | gsi_remove (gsi, true); | |||
4227 | release_defs (stmt); | |||
4228 | return SRA_AM_REMOVED; | |||
4229 | } | |||
4230 | ||||
4231 | return SRA_AM_MODIFIED; | |||
4232 | } | |||
4233 | ||||
4234 | /* Examine both sides of the assignment statement pointed to by STMT, replace | |||
4235 | them with a scalare replacement if there is one and generate copying of | |||
4236 | replacements if scalarized aggregates have been used in the assignment. GSI | |||
4237 | is used to hold generated statements for type conversions and subtree | |||
4238 | copying. */ | |||
4239 | ||||
4240 | static enum assignment_mod_result | |||
4241 | sra_modify_assign (gimple *stmt, gimple_stmt_iterator *gsi) | |||
4242 | { | |||
4243 | struct access *lacc, *racc; | |||
4244 | tree lhs, rhs; | |||
4245 | bool modify_this_stmt = false; | |||
4246 | bool force_gimple_rhs = false; | |||
4247 | location_t loc; | |||
4248 | gimple_stmt_iterator orig_gsi = *gsi; | |||
4249 | ||||
4250 | if (!gimple_assign_single_p (stmt)) | |||
4251 | return SRA_AM_NONE; | |||
4252 | lhs = gimple_assign_lhs (stmt); | |||
4253 | rhs = gimple_assign_rhs1 (stmt); | |||
4254 | ||||
4255 | if (TREE_CODE (rhs)((enum tree_code) (rhs)->base.code) == CONSTRUCTOR) | |||
4256 | return sra_modify_constructor_assign (stmt, gsi); | |||
4257 | ||||
4258 | if (TREE_CODE (rhs)((enum tree_code) (rhs)->base.code) == REALPART_EXPR || TREE_CODE (lhs)((enum tree_code) (lhs)->base.code) == REALPART_EXPR | |||
4259 | || TREE_CODE (rhs)((enum tree_code) (rhs)->base.code) == IMAGPART_EXPR || TREE_CODE (lhs)((enum tree_code) (lhs)->base.code) == IMAGPART_EXPR | |||
4260 | || TREE_CODE (rhs)((enum tree_code) (rhs)->base.code) == BIT_FIELD_REF || TREE_CODE (lhs)((enum tree_code) (lhs)->base.code) == BIT_FIELD_REF) | |||
4261 | { | |||
4262 | modify_this_stmt = sra_modify_expr (gimple_assign_rhs1_ptr (stmt), | |||
4263 | gsi, false); | |||
4264 | modify_this_stmt |= sra_modify_expr (gimple_assign_lhs_ptr (stmt), | |||
4265 | gsi, true); | |||
4266 | return modify_this_stmt ? SRA_AM_MODIFIED : SRA_AM_NONE; | |||
4267 | } | |||
4268 | ||||
4269 | lacc = get_access_for_expr (lhs); | |||
4270 | racc = get_access_for_expr (rhs); | |||
4271 | if (!lacc && !racc) | |||
4272 | return SRA_AM_NONE; | |||
4273 | /* Avoid modifying initializations of constant-pool replacements. */ | |||
4274 | if (racc && (racc->replacement_decl == lhs)) | |||
4275 | return SRA_AM_NONE; | |||
4276 | ||||
4277 | loc = gimple_location (stmt); | |||
4278 | if (lacc && lacc->grp_to_be_replaced) | |||
4279 | { | |||
4280 | lhs = get_access_replacement (lacc); | |||
4281 | gimple_assign_set_lhs (stmt, lhs); | |||
4282 | modify_this_stmt = true; | |||
4283 | if (lacc->grp_partial_lhs) | |||
4284 | force_gimple_rhs = true; | |||
4285 | sra_stats.exprs++; | |||
4286 | } | |||
4287 | ||||
4288 | if (racc && racc->grp_to_be_replaced) | |||
4289 | { | |||
4290 | rhs = get_access_replacement (racc); | |||
4291 | modify_this_stmt = true; | |||
4292 | if (racc->grp_partial_lhs) | |||
4293 | force_gimple_rhs = true; | |||
4294 | sra_stats.exprs++; | |||
4295 | } | |||
4296 | else if (racc | |||
4297 | && !racc->grp_unscalarized_data | |||
4298 | && !racc->grp_unscalarizable_region | |||
4299 | && TREE_CODE (lhs)((enum tree_code) (lhs)->base.code) == SSA_NAME | |||
4300 | && !access_has_replacements_p (racc)) | |||
4301 | { | |||
4302 | rhs = get_repl_default_def_ssa_name (racc, TREE_TYPE (lhs)((contains_struct_check ((lhs), (TS_TYPED), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 4302, __FUNCTION__))->typed.type)); | |||
4303 | modify_this_stmt = true; | |||
4304 | sra_stats.exprs++; | |||
4305 | } | |||
4306 | ||||
4307 | if (modify_this_stmt | |||
4308 | && !useless_type_conversion_p (TREE_TYPE (lhs)((contains_struct_check ((lhs), (TS_TYPED), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 4308, __FUNCTION__))->typed.type), TREE_TYPE (rhs)((contains_struct_check ((rhs), (TS_TYPED), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 4308, __FUNCTION__))->typed.type))) | |||
4309 | { | |||
4310 | /* If we can avoid creating a VIEW_CONVERT_EXPR, then do so. | |||
4311 | ??? This should move to fold_stmt which we simply should | |||
4312 | call after building a VIEW_CONVERT_EXPR here. */ | |||
4313 | if (AGGREGATE_TYPE_P (TREE_TYPE (lhs))(((enum tree_code) (((contains_struct_check ((lhs), (TS_TYPED ), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 4313, __FUNCTION__))->typed.type))->base.code) == ARRAY_TYPE || (((enum tree_code) (((contains_struct_check ((lhs), (TS_TYPED ), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 4313, __FUNCTION__))->typed.type))->base.code) == RECORD_TYPE || ((enum tree_code) (((contains_struct_check ((lhs), (TS_TYPED ), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 4313, __FUNCTION__))->typed.type))->base.code) == UNION_TYPE || ((enum tree_code) (((contains_struct_check ((lhs), (TS_TYPED ), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 4313, __FUNCTION__))->typed.type))->base.code) == QUAL_UNION_TYPE )) | |||
4314 | && TYPE_REVERSE_STORAGE_ORDER (TREE_TYPE (lhs))((tree_check4 ((((contains_struct_check ((lhs), (TS_TYPED), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 4314, __FUNCTION__))->typed.type)), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 4314, __FUNCTION__, (RECORD_TYPE), (UNION_TYPE), (QUAL_UNION_TYPE ), (ARRAY_TYPE)))->base.u.bits.saturating_flag) == racc->reverse | |||
4315 | && !contains_bitfld_component_ref_p (lhs)) | |||
4316 | { | |||
4317 | lhs = build_ref_for_model (loc, lhs, 0, racc, gsi, false); | |||
4318 | gimple_assign_set_lhs (stmt, lhs); | |||
4319 | } | |||
4320 | else if (lacc | |||
4321 | && AGGREGATE_TYPE_P (TREE_TYPE (rhs))(((enum tree_code) (((contains_struct_check ((rhs), (TS_TYPED ), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 4321, __FUNCTION__))->typed.type))->base.code) == ARRAY_TYPE || (((enum tree_code) (((contains_struct_check ((rhs), (TS_TYPED ), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 4321, __FUNCTION__))->typed.type))->base.code) == RECORD_TYPE || ((enum tree_code) (((contains_struct_check ((rhs), (TS_TYPED ), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 4321, __FUNCTION__))->typed.type))->base.code) == UNION_TYPE || ((enum tree_code) (((contains_struct_check ((rhs), (TS_TYPED ), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 4321, __FUNCTION__))->typed.type))->base.code) == QUAL_UNION_TYPE )) | |||
4322 | && TYPE_REVERSE_STORAGE_ORDER (TREE_TYPE (rhs))((tree_check4 ((((contains_struct_check ((rhs), (TS_TYPED), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 4322, __FUNCTION__))->typed.type)), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 4322, __FUNCTION__, (RECORD_TYPE), (UNION_TYPE), (QUAL_UNION_TYPE ), (ARRAY_TYPE)))->base.u.bits.saturating_flag) == lacc->reverse | |||
4323 | && !contains_vce_or_bfcref_p (rhs)) | |||
4324 | rhs = build_ref_for_model (loc, rhs, 0, lacc, gsi, false); | |||
4325 | ||||
4326 | if (!useless_type_conversion_p (TREE_TYPE (lhs)((contains_struct_check ((lhs), (TS_TYPED), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 4326, __FUNCTION__))->typed.type), TREE_TYPE (rhs)((contains_struct_check ((rhs), (TS_TYPED), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 4326, __FUNCTION__))->typed.type))) | |||
4327 | { | |||
4328 | rhs = fold_build1_loc (loc, VIEW_CONVERT_EXPR, TREE_TYPE (lhs)((contains_struct_check ((lhs), (TS_TYPED), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 4328, __FUNCTION__))->typed.type), rhs); | |||
4329 | if (is_gimple_reg_type (TREE_TYPE (lhs)((contains_struct_check ((lhs), (TS_TYPED), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 4329, __FUNCTION__))->typed.type)) | |||
4330 | && TREE_CODE (lhs)((enum tree_code) (lhs)->base.code) != SSA_NAME) | |||
4331 | force_gimple_rhs = true; | |||
4332 | } | |||
4333 | } | |||
4334 | ||||
4335 | if (lacc && lacc->grp_to_be_debug_replaced) | |||
4336 | { | |||
4337 | tree dlhs = get_access_replacement (lacc); | |||
4338 | tree drhs = unshare_expr (rhs); | |||
4339 | if (!useless_type_conversion_p (TREE_TYPE (dlhs)((contains_struct_check ((dlhs), (TS_TYPED), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 4339, __FUNCTION__))->typed.type), TREE_TYPE (drhs)((contains_struct_check ((drhs), (TS_TYPED), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 4339, __FUNCTION__))->typed.type))) | |||
4340 | { | |||
4341 | if (AGGREGATE_TYPE_P (TREE_TYPE (drhs))(((enum tree_code) (((contains_struct_check ((drhs), (TS_TYPED ), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 4341, __FUNCTION__))->typed.type))->base.code) == ARRAY_TYPE || (((enum tree_code) (((contains_struct_check ((drhs), (TS_TYPED ), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 4341, __FUNCTION__))->typed.type))->base.code) == RECORD_TYPE || ((enum tree_code) (((contains_struct_check ((drhs), (TS_TYPED ), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 4341, __FUNCTION__))->typed.type))->base.code) == UNION_TYPE || ((enum tree_code) (((contains_struct_check ((drhs), (TS_TYPED ), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 4341, __FUNCTION__))->typed.type))->base.code) == QUAL_UNION_TYPE )) | |||
4342 | && !contains_vce_or_bfcref_p (drhs)) | |||
4343 | drhs = build_debug_ref_for_model (loc, drhs, 0, lacc); | |||
4344 | if (drhs | |||
4345 | && !useless_type_conversion_p (TREE_TYPE (dlhs)((contains_struct_check ((dlhs), (TS_TYPED), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 4345, __FUNCTION__))->typed.type), | |||
4346 | TREE_TYPE (drhs)((contains_struct_check ((drhs), (TS_TYPED), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 4346, __FUNCTION__))->typed.type))) | |||
4347 | drhs = fold_build1_loc (loc, VIEW_CONVERT_EXPR, | |||
4348 | TREE_TYPE (dlhs)((contains_struct_check ((dlhs), (TS_TYPED), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 4348, __FUNCTION__))->typed.type), drhs); | |||
4349 | } | |||
4350 | gdebug *ds = gimple_build_debug_bind (dlhs, drhs, stmt); | |||
4351 | gsi_insert_before (gsi, ds, GSI_SAME_STMT); | |||
4352 | } | |||
4353 | ||||
4354 | /* From this point on, the function deals with assignments in between | |||
4355 | aggregates when at least one has scalar reductions of some of its | |||
4356 | components. There are three possible scenarios: Both the LHS and RHS have | |||
4357 | to-be-scalarized components, 2) only the RHS has or 3) only the LHS has. | |||
4358 | ||||
4359 | In the first case, we would like to load the LHS components from RHS | |||
4360 | components whenever possible. If that is not possible, we would like to | |||
4361 | read it directly from the RHS (after updating it by storing in it its own | |||
4362 | components). If there are some necessary unscalarized data in the LHS, | |||
4363 | those will be loaded by the original assignment too. If neither of these | |||
4364 | cases happen, the original statement can be removed. Most of this is done | |||
4365 | by load_assign_lhs_subreplacements. | |||
4366 | ||||
4367 | In the second case, we would like to store all RHS scalarized components | |||
4368 | directly into LHS and if they cover the aggregate completely, remove the | |||
4369 | statement too. In the third case, we want the LHS components to be loaded | |||
4370 | directly from the RHS (DSE will remove the original statement if it | |||
4371 | becomes redundant). | |||
4372 | ||||
4373 | This is a bit complex but manageable when types match and when unions do | |||
4374 | not cause confusion in a way that we cannot really load a component of LHS | |||
4375 | from the RHS or vice versa (the access representing this level can have | |||
4376 | subaccesses that are accessible only through a different union field at a | |||
4377 | higher level - different from the one used in the examined expression). | |||
4378 | Unions are fun. | |||
4379 | ||||
4380 | Therefore, I specially handle a fourth case, happening when there is a | |||
4381 | specific type cast or it is impossible to locate a scalarized subaccess on | |||
4382 | the other side of the expression. If that happens, I simply "refresh" the | |||
4383 | RHS by storing in it is scalarized components leave the original statement | |||
4384 | there to do the copying and then load the scalar replacements of the LHS. | |||
4385 | This is what the first branch does. */ | |||
4386 | ||||
4387 | if (modify_this_stmt | |||
4388 | || gimple_has_volatile_ops (stmt) | |||
4389 | || contains_vce_or_bfcref_p (rhs) | |||
4390 | || contains_vce_or_bfcref_p (lhs) | |||
4391 | || stmt_ends_bb_p (stmt)) | |||
4392 | { | |||
4393 | /* No need to copy into a constant, it comes pre-initialized. */ | |||
4394 | if (access_has_children_p (racc) && !TREE_READONLY (racc->base)((non_type_check ((racc->base), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 4394, __FUNCTION__))->base.readonly_flag)) | |||
4395 | generate_subtree_copies (racc->first_child, rhs, racc->offset, 0, 0, | |||
4396 | gsi, false, false, loc); | |||
4397 | if (access_has_children_p (lacc)) | |||
4398 | { | |||
4399 | gimple_stmt_iterator alt_gsi = gsi_none (); | |||
4400 | if (stmt_ends_bb_p (stmt)) | |||
4401 | { | |||
4402 | alt_gsi = gsi_start_edge (single_non_eh_succ (gsi_bb (*gsi))); | |||
4403 | gsi = &alt_gsi; | |||
4404 | } | |||
4405 | generate_subtree_copies (lacc->first_child, lhs, lacc->offset, 0, 0, | |||
4406 | gsi, true, true, loc); | |||
4407 | } | |||
4408 | sra_stats.separate_lhs_rhs_handling++; | |||
4409 | ||||
4410 | /* This gimplification must be done after generate_subtree_copies, | |||
4411 | lest we insert the subtree copies in the middle of the gimplified | |||
4412 | sequence. */ | |||
4413 | if (force_gimple_rhs) | |||
4414 | rhs = force_gimple_operand_gsi (&orig_gsi, rhs, true, NULL_TREE(tree) nullptr, | |||
4415 | true, GSI_SAME_STMT); | |||
4416 | if (gimple_assign_rhs1 (stmt) != rhs) | |||
4417 | { | |||
4418 | modify_this_stmt = true; | |||
4419 | gimple_assign_set_rhs_from_tree (&orig_gsi, rhs); | |||
4420 | gcc_assert (stmt == gsi_stmt (orig_gsi))((void)(!(stmt == gsi_stmt (orig_gsi)) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 4420, __FUNCTION__), 0 : 0)); | |||
4421 | } | |||
4422 | ||||
4423 | return modify_this_stmt ? SRA_AM_MODIFIED : SRA_AM_NONE; | |||
4424 | } | |||
4425 | else | |||
4426 | { | |||
4427 | if (access_has_children_p (lacc) | |||
4428 | && access_has_children_p (racc) | |||
4429 | /* When an access represents an unscalarizable region, it usually | |||
4430 | represents accesses with variable offset and thus must not be used | |||
4431 | to generate new memory accesses. */ | |||
4432 | && !lacc->grp_unscalarizable_region | |||
4433 | && !racc->grp_unscalarizable_region) | |||
4434 | { | |||
4435 | struct subreplacement_assignment_data sad; | |||
4436 | ||||
4437 | sad.left_offset = lacc->offset; | |||
4438 | sad.assignment_lhs = lhs; | |||
4439 | sad.assignment_rhs = rhs; | |||
4440 | sad.top_racc = racc; | |||
4441 | sad.old_gsi = *gsi; | |||
4442 | sad.new_gsi = gsi; | |||
4443 | sad.loc = gimple_location (stmt); | |||
4444 | sad.refreshed = SRA_UDH_NONE; | |||
4445 | ||||
4446 | if (lacc->grp_read && !lacc->grp_covered) | |||
4447 | handle_unscalarized_data_in_subtree (&sad); | |||
4448 | ||||
4449 | load_assign_lhs_subreplacements (lacc, &sad); | |||
4450 | if (sad.refreshed != SRA_UDH_RIGHT) | |||
4451 | { | |||
4452 | gsi_next (gsi); | |||
4453 | unlink_stmt_vdef (stmt); | |||
4454 | gsi_remove (&sad.old_gsi, true); | |||
4455 | release_defs (stmt); | |||
4456 | sra_stats.deleted++; | |||
4457 | return SRA_AM_REMOVED; | |||
4458 | } | |||
4459 | } | |||
4460 | else | |||
4461 | { | |||
4462 | if (access_has_children_p (racc) | |||
4463 | && !racc->grp_unscalarized_data | |||
4464 | && TREE_CODE (lhs)((enum tree_code) (lhs)->base.code) != SSA_NAME) | |||
4465 | { | |||
4466 | if (dump_file) | |||
4467 | { | |||
4468 | fprintf (dump_file, "Removing load: "); | |||
4469 | print_gimple_stmt (dump_file, stmt, 0); | |||
4470 | } | |||
4471 | generate_subtree_copies (racc->first_child, lhs, | |||
4472 | racc->offset, 0, 0, gsi, | |||
4473 | false, false, loc); | |||
4474 | gcc_assert (stmt == gsi_stmt (*gsi))((void)(!(stmt == gsi_stmt (*gsi)) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 4474, __FUNCTION__), 0 : 0)); | |||
4475 | unlink_stmt_vdef (stmt); | |||
4476 | gsi_remove (gsi, true); | |||
4477 | release_defs (stmt); | |||
4478 | sra_stats.deleted++; | |||
4479 | return SRA_AM_REMOVED; | |||
4480 | } | |||
4481 | /* Restore the aggregate RHS from its components so the | |||
4482 | prevailing aggregate copy does the right thing. */ | |||
4483 | if (access_has_children_p (racc) && !TREE_READONLY (racc->base)((non_type_check ((racc->base), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 4483, __FUNCTION__))->base.readonly_flag)) | |||
4484 | generate_subtree_copies (racc->first_child, rhs, racc->offset, 0, 0, | |||
4485 | gsi, false, false, loc); | |||
4486 | /* Re-load the components of the aggregate copy destination. | |||
4487 | But use the RHS aggregate to load from to expose more | |||
4488 | optimization opportunities. */ | |||
4489 | if (access_has_children_p (lacc)) | |||
4490 | generate_subtree_copies (lacc->first_child, rhs, lacc->offset, | |||
4491 | 0, 0, gsi, true, true, loc); | |||
4492 | } | |||
4493 | ||||
4494 | return SRA_AM_NONE; | |||
4495 | } | |||
4496 | } | |||
4497 | ||||
4498 | /* Set any scalar replacements of values in the constant pool to the initial | |||
4499 | value of the constant. (Constant-pool decls like *.LC0 have effectively | |||
4500 | been initialized before the program starts, we must do the same for their | |||
4501 | replacements.) Thus, we output statements like 'SR.1 = *.LC0[0];' into | |||
4502 | the function's entry block. */ | |||
4503 | ||||
4504 | static void | |||
4505 | initialize_constant_pool_replacements (void) | |||
4506 | { | |||
4507 | gimple_seq seq = NULLnullptr; | |||
4508 | gimple_stmt_iterator gsi = gsi_start (seq); | |||
4509 | bitmap_iterator bi; | |||
4510 | unsigned i; | |||
4511 | ||||
4512 | EXECUTE_IF_SET_IN_BITMAP (candidate_bitmap, 0, i, bi)for (bmp_iter_set_init (&(bi), (candidate_bitmap), (0), & (i)); bmp_iter_set (&(bi), &(i)); bmp_iter_next (& (bi), &(i))) | |||
4513 | { | |||
4514 | tree var = candidate (i); | |||
4515 | if (!constant_decl_p (var)) | |||
4516 | continue; | |||
4517 | ||||
4518 | struct access *access = get_first_repr_for_decl (var); | |||
4519 | ||||
4520 | while (access) | |||
4521 | { | |||
4522 | if (access->replacement_decl) | |||
4523 | { | |||
4524 | gassign *stmt | |||
4525 | = gimple_build_assign (get_access_replacement (access), | |||
4526 | unshare_expr (access->expr)); | |||
4527 | if (dump_file && (dump_flags & TDF_DETAILS)) | |||
4528 | { | |||
4529 | fprintf (dump_file, "Generating constant initializer: "); | |||
4530 | print_gimple_stmt (dump_file, stmt, 0); | |||
4531 | fprintf (dump_file, "\n"); | |||
4532 | } | |||
4533 | gsi_insert_after (&gsi, stmt, GSI_NEW_STMT); | |||
4534 | update_stmt (stmt); | |||
4535 | } | |||
4536 | ||||
4537 | if (access->first_child) | |||
4538 | access = access->first_child; | |||
4539 | else if (access->next_sibling) | |||
4540 | access = access->next_sibling; | |||
4541 | else | |||
4542 | { | |||
4543 | while (access->parent && !access->next_sibling) | |||
4544 | access = access->parent; | |||
4545 | if (access->next_sibling) | |||
4546 | access = access->next_sibling; | |||
4547 | else | |||
4548 | access = access->next_grp; | |||
4549 | } | |||
4550 | } | |||
4551 | } | |||
4552 | ||||
4553 | seq = gsi_seq (gsi); | |||
4554 | if (seq) | |||
4555 | gsi_insert_seq_on_edge_immediate ( | |||
4556 | single_succ_edge (ENTRY_BLOCK_PTR_FOR_FN (cfun)(((cfun + 0))->cfg->x_entry_block_ptr)), seq); | |||
4557 | } | |||
4558 | ||||
4559 | /* Traverse the function body and all modifications as decided in | |||
4560 | analyze_all_variable_accesses. Return true iff the CFG has been | |||
4561 | changed. */ | |||
4562 | ||||
4563 | static bool | |||
4564 | sra_modify_function_body (void) | |||
4565 | { | |||
4566 | bool cfg_changed = false; | |||
4567 | basic_block bb; | |||
4568 | ||||
4569 | initialize_constant_pool_replacements (); | |||
4570 | ||||
4571 | FOR_EACH_BB_FN (bb, cfun)for (bb = ((cfun + 0))->cfg->x_entry_block_ptr->next_bb ; bb != ((cfun + 0))->cfg->x_exit_block_ptr; bb = bb-> next_bb) | |||
4572 | { | |||
4573 | gimple_stmt_iterator gsi = gsi_start_bb (bb); | |||
4574 | while (!gsi_end_p (gsi)) | |||
4575 | { | |||
4576 | gimple *stmt = gsi_stmt (gsi); | |||
4577 | enum assignment_mod_result assign_result; | |||
4578 | bool modified = false, deleted = false; | |||
4579 | tree *t; | |||
4580 | unsigned i; | |||
4581 | ||||
4582 | switch (gimple_code (stmt)) | |||
4583 | { | |||
4584 | case GIMPLE_RETURN: | |||
4585 | t = gimple_return_retval_ptr (as_a <greturn *> (stmt)); | |||
4586 | if (*t != NULL_TREE(tree) nullptr) | |||
4587 | modified |= sra_modify_expr (t, &gsi, false); | |||
4588 | break; | |||
4589 | ||||
4590 | case GIMPLE_ASSIGN: | |||
4591 | assign_result = sra_modify_assign (stmt, &gsi); | |||
4592 | modified |= assign_result == SRA_AM_MODIFIED; | |||
4593 | deleted = assign_result == SRA_AM_REMOVED; | |||
4594 | break; | |||
4595 | ||||
4596 | case GIMPLE_CALL: | |||
4597 | /* Handle calls to .DEFERRED_INIT specially. */ | |||
4598 | if (gimple_call_internal_p (stmt, IFN_DEFERRED_INIT)) | |||
4599 | { | |||
4600 | assign_result = sra_modify_deferred_init (stmt, &gsi); | |||
4601 | modified |= assign_result == SRA_AM_MODIFIED; | |||
4602 | deleted = assign_result == SRA_AM_REMOVED; | |||
4603 | } | |||
4604 | else | |||
4605 | { | |||
4606 | /* Operands must be processed before the lhs. */ | |||
4607 | for (i = 0; i < gimple_call_num_args (stmt); i++) | |||
4608 | { | |||
4609 | t = gimple_call_arg_ptr (stmt, i); | |||
4610 | modified |= sra_modify_expr (t, &gsi, false); | |||
4611 | } | |||
4612 | ||||
4613 | if (gimple_call_lhs (stmt)) | |||
4614 | { | |||
4615 | t = gimple_call_lhs_ptr (stmt); | |||
4616 | modified |= sra_modify_expr (t, &gsi, true); | |||
4617 | } | |||
4618 | } | |||
4619 | break; | |||
4620 | ||||
4621 | case GIMPLE_ASM: | |||
4622 | { | |||
4623 | gasm *asm_stmt = as_a <gasm *> (stmt); | |||
4624 | for (i = 0; i < gimple_asm_ninputs (asm_stmt); i++) | |||
4625 | { | |||
4626 | t = &TREE_VALUE (gimple_asm_input_op (asm_stmt, i))((tree_check ((gimple_asm_input_op (asm_stmt, i)), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 4626, __FUNCTION__, (TREE_LIST)))->list.value); | |||
4627 | modified |= sra_modify_expr (t, &gsi, false); | |||
4628 | } | |||
4629 | for (i = 0; i < gimple_asm_noutputs (asm_stmt); i++) | |||
4630 | { | |||
4631 | t = &TREE_VALUE (gimple_asm_output_op (asm_stmt, i))((tree_check ((gimple_asm_output_op (asm_stmt, i)), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 4631, __FUNCTION__, (TREE_LIST)))->list.value); | |||
4632 | modified |= sra_modify_expr (t, &gsi, true); | |||
4633 | } | |||
4634 | } | |||
4635 | break; | |||
4636 | ||||
4637 | default: | |||
4638 | break; | |||
4639 | } | |||
4640 | ||||
4641 | if (modified) | |||
4642 | { | |||
4643 | update_stmt (stmt); | |||
4644 | if (maybe_clean_eh_stmt (stmt) | |||
4645 | && gimple_purge_dead_eh_edges (gimple_bb (stmt))) | |||
4646 | cfg_changed = true; | |||
4647 | } | |||
4648 | if (!deleted) | |||
4649 | gsi_next (&gsi); | |||
4650 | } | |||
4651 | } | |||
4652 | ||||
4653 | gsi_commit_edge_inserts (); | |||
4654 | return cfg_changed; | |||
4655 | } | |||
4656 | ||||
4657 | /* Generate statements initializing scalar replacements of parts of function | |||
4658 | parameters. */ | |||
4659 | ||||
4660 | static void | |||
4661 | initialize_parameter_reductions (void) | |||
4662 | { | |||
4663 | gimple_stmt_iterator gsi; | |||
4664 | gimple_seq seq = NULLnullptr; | |||
4665 | tree parm; | |||
4666 | ||||
4667 | gsi = gsi_start (seq); | |||
4668 | for (parm = DECL_ARGUMENTS (current_function_decl)((tree_check ((current_function_decl), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 4668, __FUNCTION__, (FUNCTION_DECL)))->function_decl.arguments ); | |||
4669 | parm; | |||
4670 | parm = DECL_CHAIN (parm)(((contains_struct_check (((contains_struct_check ((parm), (TS_DECL_MINIMAL ), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 4670, __FUNCTION__))), (TS_COMMON), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 4670, __FUNCTION__))->common.chain))) | |||
4671 | { | |||
4672 | vec<access_p> *access_vec; | |||
4673 | struct access *access; | |||
4674 | ||||
4675 | if (!bitmap_bit_p (candidate_bitmap, DECL_UID (parm)((contains_struct_check ((parm), (TS_DECL_MINIMAL), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-sra.cc" , 4675, __FUNCTION__))->decl_minimal.uid))) | |||
4676 | continue; | |||
4677 | access_vec = get_base_access_vector (parm); | |||
4678 | if (!access_vec) | |||
4679 | continue; | |||
4680 | ||||
4681 | for (access = (*access_vec)[0]; | |||
4682 | access; | |||
4683 | access = access->next_grp) | |||
4684 | generate_subtree_copies (access, parm, 0, 0, 0, &gsi, true, true, | |||
4685 | EXPR_LOCATION (parm)((((parm)) && ((tree_code_type_tmpl <0>::tree_code_type [(int) (((enum tree_code) ((parm))->base.code))]) >= tcc_reference && (tree_code_type_tmpl <0>::tree_code_type[(int ) (((enum tree_code) ((parm))->base.code))]) <= tcc_expression )) ? (parm)->exp.locus : ((location_t) 0))); | |||
4686 | } | |||
4687 | ||||
4688 | seq = gsi_seq (gsi); | |||
4689 | if (seq) | |||
4690 | gsi_insert_seq_on_edge_immediate (single_succ_edge (ENTRY_BLOCK_PTR_FOR_FN (cfun)(((cfun + 0))->cfg->x_entry_block_ptr)), seq); | |||
4691 | } | |||
4692 | ||||
4693 | /* The "main" function of intraprocedural SRA passes. Runs the analysis and if | |||
4694 | it reveals there are components of some aggregates to be scalarized, it runs | |||
4695 | the required transformations. */ | |||
4696 | static unsigned int | |||
4697 | perform_intra_sra (void) | |||
4698 | { | |||
4699 | int ret = 0; | |||
4700 | sra_initialize (); | |||
4701 | ||||
4702 | if (!find_var_candidates ()) | |||
4703 | goto out; | |||
4704 | ||||
4705 | if (!scan_function ()) | |||
4706 | goto out; | |||
4707 | ||||
4708 | if (!analyze_all_variable_accesses ()) | |||
4709 | goto out; | |||
4710 | ||||
4711 | if (sra_modify_function_body ()) | |||
4712 | ret = TODO_update_ssa(1 << 11) | TODO_cleanup_cfg(1 << 5); | |||
4713 | else | |||
4714 | ret = TODO_update_ssa(1 << 11); | |||
4715 | initialize_parameter_reductions (); | |||
4716 | ||||
4717 | statistics_counter_event (cfun(cfun + 0), "Scalar replacements created", | |||
4718 | sra_stats.replacements); | |||
4719 | statistics_counter_event (cfun(cfun + 0), "Modified expressions", sra_stats.exprs); | |||
4720 | statistics_counter_event (cfun(cfun + 0), "Subtree copy stmts", | |||
4721 | sra_stats.subtree_copies); | |||
4722 | statistics_counter_event (cfun(cfun + 0), "Subreplacement stmts", | |||
4723 | sra_stats.subreplacements); | |||
4724 | statistics_counter_event (cfun(cfun + 0), "Deleted stmts", sra_stats.deleted); | |||
4725 | statistics_counter_event (cfun(cfun + 0), "Separate LHS and RHS handling", | |||
4726 | sra_stats.separate_lhs_rhs_handling); | |||
4727 | ||||
4728 | out: | |||
4729 | sra_deinitialize (); | |||
4730 | return ret; | |||
4731 | } | |||
4732 | ||||
4733 | /* Perform early intraprocedural SRA. */ | |||
4734 | static unsigned int | |||
4735 | early_intra_sra (void) | |||
4736 | { | |||
4737 | sra_mode = SRA_MODE_EARLY_INTRA; | |||
4738 | return perform_intra_sra (); | |||
4739 | } | |||
4740 | ||||
4741 | /* Perform "late" intraprocedural SRA. */ | |||
4742 | static unsigned int | |||
4743 | late_intra_sra (void) | |||
4744 | { | |||
4745 | sra_mode = SRA_MODE_INTRA; | |||
4746 | return perform_intra_sra (); | |||
4747 | } | |||
4748 | ||||
4749 | ||||
4750 | static bool | |||
4751 | gate_intra_sra (void) | |||
4752 | { | |||
4753 | return flag_tree_sraglobal_options.x_flag_tree_sra != 0 && dbg_cnt (tree_sra); | |||
4754 | } | |||
4755 | ||||
4756 | ||||
4757 | namespace { | |||
4758 | ||||
4759 | const pass_data pass_data_sra_early = | |||
4760 | { | |||
4761 | GIMPLE_PASS, /* type */ | |||
4762 | "esra", /* name */ | |||
4763 | OPTGROUP_NONE, /* optinfo_flags */ | |||
4764 | TV_TREE_SRA, /* tv_id */ | |||
4765 | ( PROP_cfg(1 << 3) | PROP_ssa(1 << 5) ), /* properties_required */ | |||
4766 | 0, /* properties_provided */ | |||
4767 | 0, /* properties_destroyed */ | |||
4768 | 0, /* todo_flags_start */ | |||
4769 | TODO_update_ssa(1 << 11), /* todo_flags_finish */ | |||
4770 | }; | |||
4771 | ||||
4772 | class pass_sra_early : public gimple_opt_pass | |||
4773 | { | |||
4774 | public: | |||
4775 | pass_sra_early (gcc::context *ctxt) | |||
4776 | : gimple_opt_pass (pass_data_sra_early, ctxt) | |||
4777 | {} | |||
4778 | ||||
4779 | /* opt_pass methods: */ | |||
4780 | bool gate (function *) final override { return gate_intra_sra (); } | |||
4781 | unsigned int execute (function *) final override | |||
4782 | { | |||
4783 | return early_intra_sra (); | |||
4784 | } | |||
4785 | ||||
4786 | }; // class pass_sra_early | |||
4787 | ||||
4788 | } // anon namespace | |||
4789 | ||||
4790 | gimple_opt_pass * | |||
4791 | make_pass_sra_early (gcc::context *ctxt) | |||
4792 | { | |||
4793 | return new pass_sra_early (ctxt); | |||
4794 | } | |||
4795 | ||||
4796 | namespace { | |||
4797 | ||||
4798 | const pass_data pass_data_sra = | |||
4799 | { | |||
4800 | GIMPLE_PASS, /* type */ | |||
4801 | "sra", /* name */ | |||
4802 | OPTGROUP_NONE, /* optinfo_flags */ | |||
4803 | TV_TREE_SRA, /* tv_id */ | |||
4804 | ( PROP_cfg(1 << 3) | PROP_ssa(1 << 5) ), /* properties_required */ | |||
4805 | 0, /* properties_provided */ | |||
4806 | 0, /* properties_destroyed */ | |||
4807 | TODO_update_address_taken(1 << 21), /* todo_flags_start */ | |||
4808 | TODO_update_ssa(1 << 11), /* todo_flags_finish */ | |||
4809 | }; | |||
4810 | ||||
4811 | class pass_sra : public gimple_opt_pass | |||
4812 | { | |||
4813 | public: | |||
4814 | pass_sra (gcc::context *ctxt) | |||
4815 | : gimple_opt_pass (pass_data_sra, ctxt) | |||
4816 | {} | |||
4817 | ||||
4818 | /* opt_pass methods: */ | |||
4819 | bool gate (function *) final override { return gate_intra_sra (); } | |||
4820 | unsigned int execute (function *) final override { return late_intra_sra (); } | |||
4821 | ||||
4822 | }; // class pass_sra | |||
4823 | ||||
4824 | } // anon namespace | |||
4825 | ||||
4826 | gimple_opt_pass * | |||
4827 | make_pass_sra (gcc::context *ctxt) | |||
4828 | { | |||
4829 | return new pass_sra (ctxt); | |||
4830 | } |