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-2022 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_INT offset;
137 HOST_WIDE_INT 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
hash(const tree_node * item)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
equal(const tree_node * a,const tree_node * b)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
candidate(unsigned uid)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
dump_access(FILE * f,struct access * access,bool grp)400 dump_access (FILE *f, struct access *access, bool grp)
401 {
402 fprintf (f, "access { ");
403 fprintf (f, "base = (%d)'", DECL_UID (access->base));
404 print_generic_expr (f, access->base);
405 fprintf (f, "', offset = " HOST_WIDE_INT_PRINT_DEC, access->offset);
406 fprintf (f, ", size = " HOST_WIDE_INT_PRINT_DEC, 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
dump_access_tree_1(FILE * f,struct access * access,int level)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
dump_access_tree(FILE * f,struct access * access)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
access_has_children_p(struct access * acc)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
access_has_replacements_p(struct access * acc)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> *
get_base_access_vector(tree base)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 *
find_access_in_subtree(struct access * access,HOST_WIDE_INT offset,HOST_WIDE_INT size)501 find_access_in_subtree (struct access *access, HOST_WIDE_INT offset,
502 HOST_WIDE_INT 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 *
get_first_repr_for_decl(tree base)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 NULL;
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 *
get_var_base_offset_size_access(tree base,HOST_WIDE_INT offset,HOST_WIDE_INT size)544 get_var_base_offset_size_access (tree base, HOST_WIDE_INT offset,
545 HOST_WIDE_INT 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 NULL;
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
add_link_to_rhs(struct access * racc,struct assign_link * link)561 add_link_to_rhs (struct access *racc, struct assign_link *link)
562 {
563 gcc_assert (link->racc == racc);
564
565 if (!racc->first_rhs_link)
566 {
567 gcc_assert (!racc->last_rhs_link);
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 = NULL;
575 }
576
577 /* Add LINK to the linked list of lhs assign links of LACC. */
578
579 static void
add_link_to_lhs(struct access * lacc,struct assign_link * link)580 add_link_to_lhs (struct access *lacc, struct assign_link *link)
581 {
582 gcc_assert (link->lacc == lacc);
583
584 if (!lacc->first_lhs_link)
585 {
586 gcc_assert (!lacc->last_lhs_link);
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 = NULL;
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
relink_to_new_repr(struct access * new_acc,struct access * old_acc)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);
607 gcc_assert (!old_acc->last_rhs_link
608 || !old_acc->last_rhs_link->next_rhs);
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);
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 = NULL;
621 }
622 else
623 gcc_assert (!old_acc->last_rhs_link);
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);
631 gcc_assert (!old_acc->last_lhs_link
632 || !old_acc->last_lhs_link->next_lhs);
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);
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 = NULL;
645 }
646 else
647 gcc_assert (!old_acc->last_lhs_link);
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
add_access_to_rhs_work_queue(struct access * access)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);
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
add_access_to_lhs_work_queue(struct access * access)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);
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 *
pop_access_from_rhs_work_queue(void)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 = NULL;
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 *
pop_access_from_lhs_work_queue(void)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 = NULL;
705 access->grp_lhs_queued = 0;
706 return access;
707 }
708
709 /* Allocate necessary structures. */
710
711 static void
sra_initialize(void)712 sra_initialize (void)
713 {
714 candidate_bitmap = BITMAP_ALLOC (NULL);
715 candidates = new hash_table<uid_decl_hasher>
716 (vec_safe_length (cfun->local_decls) / 2);
717 should_scalarize_away_bitmap = BITMAP_ALLOC (NULL);
718 cannot_scalarize_away_bitmap = BITMAP_ALLOC (NULL);
719 disqualified_constants = BITMAP_ALLOC (NULL);
720 gcc_obstack_init (&name_obstack);
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
sra_deinitialize(void)728 sra_deinitialize (void)
729 {
730 BITMAP_FREE (candidate_bitmap);
731 delete candidates;
732 candidates = NULL;
733 BITMAP_FREE (should_scalarize_away_bitmap);
734 BITMAP_FREE (cannot_scalarize_away_bitmap);
735 BITMAP_FREE (disqualified_constants);
736 access_pool.release ();
737 assign_link_pool.release ();
738 obstack_free (&name_obstack, NULL);
739
740 delete base_access_vec;
741 }
742
743 /* Return true if DECL is a VAR_DECL in the constant pool, false otherwise. */
744
constant_decl_p(tree decl)745 static bool constant_decl_p (tree decl)
746 {
747 return VAR_P (decl) && DECL_IN_CONSTANT_POOL (decl);
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
disqualify_candidate(tree decl,const char * reason)754 disqualify_candidate (tree decl, const char *reason)
755 {
756 if (bitmap_clear_bit (candidate_bitmap, DECL_UID (decl)))
757 candidates->remove_elt_with_hash (decl, DECL_UID (decl));
758 if (constant_decl_p (decl))
759 bitmap_set_bit (disqualified_constants, DECL_UID (decl));
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
type_internals_preclude_sra_p_1(tree type,const char ** msg,hash_set<tree> * visited_types)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))
785 {
786 case RECORD_TYPE:
787 case UNION_TYPE:
788 case QUAL_UNION_TYPE:
789 for (fld = TYPE_FIELDS (type); fld; fld = DECL_CHAIN (fld))
790 if (TREE_CODE (fld) == FIELD_DECL)
791 {
792 if (TREE_CODE (fld) == FUNCTION_DECL)
793 continue;
794 tree ft = TREE_TYPE (fld);
795
796 if (TREE_THIS_VOLATILE (fld))
797 {
798 *msg = "volatile structure field";
799 return true;
800 }
801 if (!DECL_FIELD_OFFSET (fld))
802 {
803 *msg = "no structure field offset";
804 return true;
805 }
806 if (!DECL_SIZE (fld))
807 {
808 *msg = "zero structure field size";
809 return true;
810 }
811 if (!tree_fits_uhwi_p (DECL_FIELD_OFFSET (fld)))
812 {
813 *msg = "structure field offset not fixed";
814 return true;
815 }
816 if (!tree_fits_uhwi_p (DECL_SIZE (fld)))
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)
827 && int_bit_position (fld) % BITS_PER_UNIT != 0)
828 {
829 *msg = "structure field is bit field";
830 return true;
831 }
832
833 if (AGGREGATE_TYPE_P (ft)
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);
842
843 if (TYPE_VOLATILE (et))
844 {
845 *msg = "element type is volatile";
846 return true;
847 }
848
849 if (AGGREGATE_TYPE_P (et)
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
type_internals_preclude_sra_p(tree type,const char ** msg)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 *
create_access_1(tree base,HOST_WIDE_INT offset,HOST_WIDE_INT size)876 create_access_1 (tree base, HOST_WIDE_INT offset, HOST_WIDE_INT 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 *
create_access(tree expr,gimple * stmt,bool write)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)));
911 if (expr != base
912 && !is_gimple_reg_type (TREE_TYPE (expr))
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) || !bitmap_bit_p (candidate_bitmap, DECL_UID (base)))
926 return NULL;
927
928 if (write && TREE_READONLY (base))
929 {
930 disqualify_candidate (base, "Encountered a store to a read-only decl.");
931 return NULL;
932 }
933
934 HOST_WIDE_INT 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 NULL;
941 }
942
943 if (size != max_size)
944 {
945 size = max_size;
946 unscalarizable_region = true;
947 }
948 if (size == 0)
949 return NULL;
950 if (offset < 0)
951 {
952 disqualify_candidate (base, "Encountered a negative offset access.");
953 return NULL;
954 }
955 if (size < 0)
956 {
957 disqualify_candidate (base, "Encountered an unconstrained access.");
958 return NULL;
959 }
960 if (offset + size > tree_to_shwi (DECL_SIZE (base)))
961 {
962 disqualify_candidate (base, "Encountered an access beyond the base.");
963 return NULL;
964 }
965
966 access = create_access_1 (base, offset, size);
967 access->expr = expr;
968 access->type = TREE_TYPE (expr);
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
scalarizable_type_p(tree type,bool const_decl)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_INT prev_pos = 0;
994
995 switch (TREE_CODE (type))
996 {
997 case RECORD_TYPE:
998 for (tree fld = TYPE_FIELDS (type); fld; fld = DECL_CHAIN (fld))
999 if (TREE_CODE (fld) == FIELD_DECL)
1000 {
1001 tree ft = TREE_TYPE (fld);
1002
1003 if (zerop (DECL_SIZE (fld)))
1004 continue;
1005
1006 HOST_WIDE_INT 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))
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_INT min_elem_size;
1026 if (const_decl)
1027 min_elem_size = 0;
1028 else
1029 min_elem_size = BITS_PER_UNIT;
1030
1031 if (TYPE_DOMAIN (type) == NULL_TREE
1032 || !tree_fits_shwi_p (TYPE_SIZE (type))
1033 || !tree_fits_shwi_p (TYPE_SIZE (TREE_TYPE (type)))
1034 || (tree_to_shwi (TYPE_SIZE (TREE_TYPE (type))) <= min_elem_size)
1035 || !tree_fits_shwi_p (TYPE_MIN_VALUE (TYPE_DOMAIN (type))))
1036 return false;
1037 if (tree_to_shwi (TYPE_SIZE (type)) == 0
1038 && TYPE_MAX_VALUE (TYPE_DOMAIN (type)) == NULL_TREE)
1039 /* Zero-element array, should not prevent scalarization. */
1040 ;
1041 else if ((tree_to_shwi (TYPE_SIZE (type)) <= 0)
1042 || !tree_fits_shwi_p (TYPE_MAX_VALUE (TYPE_DOMAIN (type))))
1043 /* Variable-length array, do not allow scalarization. */
1044 return false;
1045
1046 tree elem = TREE_TYPE (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
contains_view_convert_expr_p(const_tree ref)1059 contains_view_convert_expr_p (const_tree ref)
1060 {
1061 while (handled_component_p (ref))
1062 {
1063 if (TREE_CODE (ref) == VIEW_CONVERT_EXPR)
1064 return true;
1065 ref = TREE_OPERAND (ref, 0);
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
contains_vce_or_bfcref_p(const_tree ref,bool * type_changing_p=NULL)1077 contains_vce_or_bfcref_p (const_tree ref, bool *type_changing_p = NULL)
1078 {
1079 while (handled_component_p (ref))
1080 {
1081 if (TREE_CODE (ref) == VIEW_CONVERT_EXPR
1082 || (TREE_CODE (ref) == COMPONENT_REF
1083 && DECL_BIT_FIELD (TREE_OPERAND (ref, 1))))
1084 {
1085 if (type_changing_p)
1086 *type_changing_p = true;
1087 return true;
1088 }
1089 ref = TREE_OPERAND (ref, 0);
1090 }
1091
1092 if (!type_changing_p
1093 || TREE_CODE (ref) != MEM_REF
1094 || TREE_CODE (TREE_OPERAND (ref, 0)) != ADDR_EXPR)
1095 return false;
1096
1097 tree mem = TREE_OPERAND (TREE_OPERAND (ref, 0), 0);
1098 if (TYPE_MAIN_VARIANT (TREE_TYPE (ref))
1099 != TYPE_MAIN_VARIANT (TREE_TYPE (mem)))
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
disqualify_base_of_expr(tree t,const char * reason)1109 disqualify_base_of_expr (tree t, const char *reason)
1110 {
1111 t = get_base_address (t);
1112 if (t && DECL_P (t))
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 *
build_access_from_expr_1(tree expr,gimple * stmt,bool write)1121 build_access_from_expr_1 (tree expr, gimple *stmt, bool write)
1122 {
1123 struct access *ret = NULL;
1124 bool partial_ref;
1125
1126 if (TREE_CODE (expr) == BIT_FIELD_REF
1127 || TREE_CODE (expr) == IMAGPART_EXPR
1128 || TREE_CODE (expr) == REALPART_EXPR)
1129 {
1130 expr = TREE_OPERAND (expr, 0);
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 NULL;
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) == VIEW_CONVERT_EXPR)
1147 expr = TREE_OPERAND (expr, 0);
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 NULL;
1154 }
1155 if (TREE_THIS_VOLATILE (expr))
1156 {
1157 disqualify_base_of_expr (expr, "part of a volatile reference.");
1158 return NULL;
1159 }
1160
1161 switch (TREE_CODE (expr))
1162 {
1163 case MEM_REF:
1164 if (TREE_CODE (TREE_OPERAND (expr, 0)) != ADDR_EXPR)
1165 return NULL;
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
build_access_from_expr(tree expr,gimple * stmt,bool write)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));
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
single_non_eh_succ(basic_block bb)1213 single_non_eh_succ (basic_block bb)
1214 {
1215 edge e, res = NULL;
1216 edge_iterator ei;
1217
1218 FOR_EACH_EDGE (e, ei, bb->succs)
1219 if (!(e->flags & EDGE_EH))
1220 {
1221 if (res)
1222 return NULL;
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
disqualify_if_bad_bb_terminating_stmt(gimple * stmt,tree lhs,tree rhs)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
comes_initialized_p(tree base)1255 comes_initialized_p (tree base)
1256 {
1257 return TREE_CODE (base) == 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
build_accesses_from_assign(gimple * stmt)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));
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));
1312 else
1313 bitmap_set_bit (should_scalarize_away_bitmap,
1314 DECL_UID (racc->base));
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))
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
asm_visit_addr(gimple *,tree op,tree,void *)1354 asm_visit_addr (gimple *, tree op, tree, void *)
1355 {
1356 op = get_base_address (op);
1357 if (op
1358 && DECL_P (op))
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
scan_function(void)1368 scan_function (void)
1369 {
1370 basic_block bb;
1371 bool ret = false;
1372
1373 FOR_EACH_BB_FN (bb, cfun)
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)
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, NULL))
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, NULL, NULL, NULL,
1415 asm_visit_addr);
1416 if (stmt_ends_bb_p (asm_stmt)
1417 && !single_succ_p (gimple_bb (asm_stmt)))
1418 {
1419 for (i = 0; i < gimple_asm_ninputs (asm_stmt); i++)
1420 {
1421 t = TREE_VALUE (gimple_asm_input_op (asm_stmt, i));
1422 disqualify_base_of_expr (t, "OP of asm goto.");
1423 }
1424 for (i = 0; i < gimple_asm_noutputs (asm_stmt); i++)
1425 {
1426 t = TREE_VALUE (gimple_asm_output_op (asm_stmt, i));
1427 disqualify_base_of_expr (t, "OP of asm goto.");
1428 }
1429 }
1430 else
1431 {
1432 for (i = 0; i < gimple_asm_ninputs (asm_stmt); i++)
1433 {
1434 t = TREE_VALUE (gimple_asm_input_op (asm_stmt, i));
1435 ret |= build_access_from_expr (t, asm_stmt, false);
1436 }
1437 for (i = 0; i < gimple_asm_noutputs (asm_stmt); i++)
1438 {
1439 t = TREE_VALUE (gimple_asm_output_op (asm_stmt, i));
1440 ret |= build_access_from_expr (t, asm_stmt, true);
1441 }
1442 }
1443 }
1444 break;
1445
1446 default:
1447 break;
1448 }
1449 }
1450 }
1451
1452 return ret;
1453 }
1454
1455 /* Helper of QSORT function. There are pointers to accesses in the array. An
1456 access is considered smaller than another if it has smaller offset or if the
1457 offsets are the same but is size is bigger. */
1458
1459 static int
compare_access_positions(const void * a,const void * b)1460 compare_access_positions (const void *a, const void *b)
1461 {
1462 const access_p *fp1 = (const access_p *) a;
1463 const access_p *fp2 = (const access_p *) b;
1464 const access_p f1 = *fp1;
1465 const access_p f2 = *fp2;
1466
1467 if (f1->offset != f2->offset)
1468 return f1->offset < f2->offset ? -1 : 1;
1469
1470 if (f1->size == f2->size)
1471 {
1472 if (f1->type == f2->type)
1473 return 0;
1474 /* Put any non-aggregate type before any aggregate type. */
1475 else if (!is_gimple_reg_type (f1->type)
1476 && is_gimple_reg_type (f2->type))
1477 return 1;
1478 else if (is_gimple_reg_type (f1->type)
1479 && !is_gimple_reg_type (f2->type))
1480 return -1;
1481 /* Put any complex or vector type before any other scalar type. */
1482 else if (TREE_CODE (f1->type) != COMPLEX_TYPE
1483 && TREE_CODE (f1->type) != VECTOR_TYPE
1484 && (TREE_CODE (f2->type) == COMPLEX_TYPE
1485 || TREE_CODE (f2->type) == VECTOR_TYPE))
1486 return 1;
1487 else if ((TREE_CODE (f1->type) == COMPLEX_TYPE
1488 || TREE_CODE (f1->type) == VECTOR_TYPE)
1489 && TREE_CODE (f2->type) != COMPLEX_TYPE
1490 && TREE_CODE (f2->type) != VECTOR_TYPE)
1491 return -1;
1492 /* Put any integral type before any non-integral type. When splicing, we
1493 make sure that those with insufficient precision and occupying the
1494 same space are not scalarized. */
1495 else if (INTEGRAL_TYPE_P (f1->type)
1496 && !INTEGRAL_TYPE_P (f2->type))
1497 return -1;
1498 else if (!INTEGRAL_TYPE_P (f1->type)
1499 && INTEGRAL_TYPE_P (f2->type))
1500 return 1;
1501 /* Put the integral type with the bigger precision first. */
1502 else if (INTEGRAL_TYPE_P (f1->type)
1503 && INTEGRAL_TYPE_P (f2->type)
1504 && (TYPE_PRECISION (f2->type) != TYPE_PRECISION (f1->type)))
1505 return TYPE_PRECISION (f2->type) - TYPE_PRECISION (f1->type);
1506 /* Stabilize the sort. */
1507 return TYPE_UID (f1->type) - TYPE_UID (f2->type);
1508 }
1509
1510 /* We want the bigger accesses first, thus the opposite operator in the next
1511 line: */
1512 return f1->size > f2->size ? -1 : 1;
1513 }
1514
1515
1516 /* Append a name of the declaration to the name obstack. A helper function for
1517 make_fancy_name. */
1518
1519 static void
make_fancy_decl_name(tree decl)1520 make_fancy_decl_name (tree decl)
1521 {
1522 char buffer[32];
1523
1524 tree name = DECL_NAME (decl);
1525 if (name)
1526 obstack_grow (&name_obstack, IDENTIFIER_POINTER (name),
1527 IDENTIFIER_LENGTH (name));
1528 else
1529 {
1530 sprintf (buffer, "D%u", DECL_UID (decl));
1531 obstack_grow (&name_obstack, buffer, strlen (buffer));
1532 }
1533 }
1534
1535 /* Helper for make_fancy_name. */
1536
1537 static void
make_fancy_name_1(tree expr)1538 make_fancy_name_1 (tree expr)
1539 {
1540 char buffer[32];
1541 tree index;
1542
1543 if (DECL_P (expr))
1544 {
1545 make_fancy_decl_name (expr);
1546 return;
1547 }
1548
1549 switch (TREE_CODE (expr))
1550 {
1551 case COMPONENT_REF:
1552 make_fancy_name_1 (TREE_OPERAND (expr, 0));
1553 obstack_1grow (&name_obstack, '$');
1554 make_fancy_decl_name (TREE_OPERAND (expr, 1));
1555 break;
1556
1557 case ARRAY_REF:
1558 make_fancy_name_1 (TREE_OPERAND (expr, 0));
1559 obstack_1grow (&name_obstack, '$');
1560 /* Arrays with only one element may not have a constant as their
1561 index. */
1562 index = TREE_OPERAND (expr, 1);
1563 if (TREE_CODE (index) != INTEGER_CST)
1564 break;
1565 sprintf (buffer, HOST_WIDE_INT_PRINT_DEC, TREE_INT_CST_LOW (index));
1566 obstack_grow (&name_obstack, buffer, strlen (buffer));
1567 break;
1568
1569 case ADDR_EXPR:
1570 make_fancy_name_1 (TREE_OPERAND (expr, 0));
1571 break;
1572
1573 case MEM_REF:
1574 make_fancy_name_1 (TREE_OPERAND (expr, 0));
1575 if (!integer_zerop (TREE_OPERAND (expr, 1)))
1576 {
1577 obstack_1grow (&name_obstack, '$');
1578 sprintf (buffer, HOST_WIDE_INT_PRINT_DEC,
1579 TREE_INT_CST_LOW (TREE_OPERAND (expr, 1)));
1580 obstack_grow (&name_obstack, buffer, strlen (buffer));
1581 }
1582 break;
1583
1584 case BIT_FIELD_REF:
1585 case REALPART_EXPR:
1586 case IMAGPART_EXPR:
1587 gcc_unreachable (); /* we treat these as scalars. */
1588 break;
1589 default:
1590 break;
1591 }
1592 }
1593
1594 /* Create a human readable name for replacement variable of ACCESS. */
1595
1596 static char *
make_fancy_name(tree expr)1597 make_fancy_name (tree expr)
1598 {
1599 make_fancy_name_1 (expr);
1600 obstack_1grow (&name_obstack, '\0');
1601 return XOBFINISH (&name_obstack, char *);
1602 }
1603
1604 /* Construct a MEM_REF that would reference a part of aggregate BASE of type
1605 EXP_TYPE at the given OFFSET and with storage order REVERSE. If BASE is
1606 something for which get_addr_base_and_unit_offset returns NULL, gsi must
1607 be non-NULL and is used to insert new statements either before or below
1608 the current one as specified by INSERT_AFTER. This function is not capable
1609 of handling bitfields. */
1610
1611 tree
build_ref_for_offset(location_t loc,tree base,poly_int64 offset,bool reverse,tree exp_type,gimple_stmt_iterator * gsi,bool insert_after)1612 build_ref_for_offset (location_t loc, tree base, poly_int64 offset,
1613 bool reverse, tree exp_type, gimple_stmt_iterator *gsi,
1614 bool insert_after)
1615 {
1616 tree prev_base = base;
1617 tree off;
1618 tree mem_ref;
1619 poly_int64 base_offset;
1620 unsigned HOST_WIDE_INT misalign;
1621 unsigned int align;
1622
1623 /* Preserve address-space information. */
1624 addr_space_t as = TYPE_ADDR_SPACE (TREE_TYPE (base));
1625 if (as != TYPE_ADDR_SPACE (exp_type))
1626 exp_type = build_qualified_type (exp_type,
1627 TYPE_QUALS (exp_type)
1628 | ENCODE_QUAL_ADDR_SPACE (as));
1629
1630 poly_int64 byte_offset = exact_div (offset, BITS_PER_UNIT);
1631 get_object_alignment_1 (base, &align, &misalign);
1632 base = get_addr_base_and_unit_offset (base, &base_offset);
1633
1634 /* get_addr_base_and_unit_offset returns NULL for references with a variable
1635 offset such as array[var_index]. */
1636 if (!base)
1637 {
1638 gassign *stmt;
1639 tree tmp, addr;
1640
1641 gcc_checking_assert (gsi);
1642 tmp = make_ssa_name (build_pointer_type (TREE_TYPE (prev_base)));
1643 addr = build_fold_addr_expr (unshare_expr (prev_base));
1644 STRIP_USELESS_TYPE_CONVERSION (addr);
1645 stmt = gimple_build_assign (tmp, addr);
1646 gimple_set_location (stmt, loc);
1647 if (insert_after)
1648 gsi_insert_after (gsi, stmt, GSI_NEW_STMT);
1649 else
1650 gsi_insert_before (gsi, stmt, GSI_SAME_STMT);
1651
1652 off = build_int_cst (reference_alias_ptr_type (prev_base), byte_offset);
1653 base = tmp;
1654 }
1655 else if (TREE_CODE (base) == MEM_REF)
1656 {
1657 off = build_int_cst (TREE_TYPE (TREE_OPERAND (base, 1)),
1658 base_offset + byte_offset);
1659 off = int_const_binop (PLUS_EXPR, TREE_OPERAND (base, 1), off);
1660 base = unshare_expr (TREE_OPERAND (base, 0));
1661 }
1662 else
1663 {
1664 off = build_int_cst (reference_alias_ptr_type (prev_base),
1665 base_offset + byte_offset);
1666 base = build_fold_addr_expr (unshare_expr (base));
1667 }
1668
1669 unsigned int align_bound = known_alignment (misalign + offset);
1670 if (align_bound != 0)
1671 align = MIN (align, align_bound);
1672 if (align != TYPE_ALIGN (exp_type))
1673 exp_type = build_aligned_type (exp_type, align);
1674
1675 mem_ref = fold_build2_loc (loc, MEM_REF, exp_type, base, off);
1676 REF_REVERSE_STORAGE_ORDER (mem_ref) = reverse;
1677 if (TREE_THIS_VOLATILE (prev_base))
1678 TREE_THIS_VOLATILE (mem_ref) = 1;
1679 if (TREE_SIDE_EFFECTS (prev_base))
1680 TREE_SIDE_EFFECTS (mem_ref) = 1;
1681 return mem_ref;
1682 }
1683
1684 /* Construct and return a memory reference that is equal to a portion of
1685 MODEL->expr but is based on BASE. If this cannot be done, return NULL. */
1686
1687 static tree
build_reconstructed_reference(location_t,tree base,struct access * model)1688 build_reconstructed_reference (location_t, tree base, struct access *model)
1689 {
1690 tree expr = model->expr;
1691 /* We have to make sure to start just below the outermost union. */
1692 tree start_expr = expr;
1693 while (handled_component_p (expr))
1694 {
1695 if (TREE_CODE (TREE_TYPE (TREE_OPERAND (expr, 0))) == UNION_TYPE)
1696 start_expr = expr;
1697 expr = TREE_OPERAND (expr, 0);
1698 }
1699
1700 expr = start_expr;
1701 tree prev_expr = NULL_TREE;
1702 while (!types_compatible_p (TREE_TYPE (expr), TREE_TYPE (base)))
1703 {
1704 if (!handled_component_p (expr))
1705 return NULL_TREE;
1706 prev_expr = expr;
1707 expr = TREE_OPERAND (expr, 0);
1708 }
1709
1710 /* Guard against broken VIEW_CONVERT_EXPRs... */
1711 if (!prev_expr)
1712 return NULL_TREE;
1713
1714 TREE_OPERAND (prev_expr, 0) = base;
1715 tree ref = unshare_expr (model->expr);
1716 TREE_OPERAND (prev_expr, 0) = expr;
1717 return ref;
1718 }
1719
1720 /* Construct a memory reference to a part of an aggregate BASE at the given
1721 OFFSET and of the same type as MODEL. In case this is a reference to a
1722 bit-field, the function will replicate the last component_ref of model's
1723 expr to access it. GSI and INSERT_AFTER have the same meaning as in
1724 build_ref_for_offset. */
1725
1726 static tree
build_ref_for_model(location_t loc,tree base,HOST_WIDE_INT offset,struct access * model,gimple_stmt_iterator * gsi,bool insert_after)1727 build_ref_for_model (location_t loc, tree base, HOST_WIDE_INT offset,
1728 struct access *model, gimple_stmt_iterator *gsi,
1729 bool insert_after)
1730 {
1731 gcc_assert (offset >= 0);
1732 if (TREE_CODE (model->expr) == COMPONENT_REF
1733 && DECL_BIT_FIELD (TREE_OPERAND (model->expr, 1)))
1734 {
1735 /* This access represents a bit-field. */
1736 tree t, exp_type, fld = TREE_OPERAND (model->expr, 1);
1737
1738 offset -= int_bit_position (fld);
1739 exp_type = TREE_TYPE (TREE_OPERAND (model->expr, 0));
1740 t = build_ref_for_offset (loc, base, offset, model->reverse, exp_type,
1741 gsi, insert_after);
1742 /* The flag will be set on the record type. */
1743 REF_REVERSE_STORAGE_ORDER (t) = 0;
1744 return fold_build3_loc (loc, COMPONENT_REF, TREE_TYPE (fld), t, fld,
1745 NULL_TREE);
1746 }
1747 else
1748 {
1749 tree res;
1750 if (model->grp_same_access_path
1751 && !TREE_THIS_VOLATILE (base)
1752 && (TYPE_ADDR_SPACE (TREE_TYPE (base))
1753 == TYPE_ADDR_SPACE (TREE_TYPE (model->expr)))
1754 && offset <= model->offset
1755 /* build_reconstructed_reference can still fail if we have already
1756 massaged BASE because of another type incompatibility. */
1757 && (res = build_reconstructed_reference (loc, base, model)))
1758 return res;
1759 else
1760 return build_ref_for_offset (loc, base, offset, model->reverse,
1761 model->type, gsi, insert_after);
1762 }
1763 }
1764
1765 /* Attempt to build a memory reference that we could but into a gimple
1766 debug_bind statement. Similar to build_ref_for_model but punts if it has to
1767 create statements and return s NULL instead. This function also ignores
1768 alignment issues and so its results should never end up in non-debug
1769 statements. */
1770
1771 static tree
build_debug_ref_for_model(location_t loc,tree base,HOST_WIDE_INT offset,struct access * model)1772 build_debug_ref_for_model (location_t loc, tree base, HOST_WIDE_INT offset,
1773 struct access *model)
1774 {
1775 poly_int64 base_offset;
1776 tree off;
1777
1778 if (TREE_CODE (model->expr) == COMPONENT_REF
1779 && DECL_BIT_FIELD (TREE_OPERAND (model->expr, 1)))
1780 return NULL_TREE;
1781
1782 base = get_addr_base_and_unit_offset (base, &base_offset);
1783 if (!base)
1784 return NULL_TREE;
1785 if (TREE_CODE (base) == MEM_REF)
1786 {
1787 off = build_int_cst (TREE_TYPE (TREE_OPERAND (base, 1)),
1788 base_offset + offset / BITS_PER_UNIT);
1789 off = int_const_binop (PLUS_EXPR, TREE_OPERAND (base, 1), off);
1790 base = unshare_expr (TREE_OPERAND (base, 0));
1791 }
1792 else
1793 {
1794 off = build_int_cst (reference_alias_ptr_type (base),
1795 base_offset + offset / BITS_PER_UNIT);
1796 base = build_fold_addr_expr (unshare_expr (base));
1797 }
1798
1799 return fold_build2_loc (loc, MEM_REF, model->type, base, off);
1800 }
1801
1802 /* Construct a memory reference consisting of component_refs and array_refs to
1803 a part of an aggregate *RES (which is of type TYPE). The requested part
1804 should have type EXP_TYPE at be the given OFFSET. This function might not
1805 succeed, it returns true when it does and only then *RES points to something
1806 meaningful. This function should be used only to build expressions that we
1807 might need to present to user (e.g. in warnings). In all other situations,
1808 build_ref_for_model or build_ref_for_offset should be used instead. */
1809
1810 static bool
build_user_friendly_ref_for_offset(tree * res,tree type,HOST_WIDE_INT offset,tree exp_type)1811 build_user_friendly_ref_for_offset (tree *res, tree type, HOST_WIDE_INT offset,
1812 tree exp_type)
1813 {
1814 while (1)
1815 {
1816 tree fld;
1817 tree tr_size, index, minidx;
1818 HOST_WIDE_INT el_size;
1819
1820 if (offset == 0 && exp_type
1821 && types_compatible_p (exp_type, type))
1822 return true;
1823
1824 switch (TREE_CODE (type))
1825 {
1826 case UNION_TYPE:
1827 case QUAL_UNION_TYPE:
1828 case RECORD_TYPE:
1829 for (fld = TYPE_FIELDS (type); fld; fld = DECL_CHAIN (fld))
1830 {
1831 HOST_WIDE_INT pos, size;
1832 tree tr_pos, expr, *expr_ptr;
1833
1834 if (TREE_CODE (fld) != FIELD_DECL)
1835 continue;
1836
1837 tr_pos = bit_position (fld);
1838 if (!tr_pos || !tree_fits_uhwi_p (tr_pos))
1839 continue;
1840 pos = tree_to_uhwi (tr_pos);
1841 gcc_assert (TREE_CODE (type) == RECORD_TYPE || pos == 0);
1842 tr_size = DECL_SIZE (fld);
1843 if (!tr_size || !tree_fits_uhwi_p (tr_size))
1844 continue;
1845 size = tree_to_uhwi (tr_size);
1846 if (size == 0)
1847 {
1848 if (pos != offset)
1849 continue;
1850 }
1851 else if (pos > offset || (pos + size) <= offset)
1852 continue;
1853
1854 expr = build3 (COMPONENT_REF, TREE_TYPE (fld), *res, fld,
1855 NULL_TREE);
1856 expr_ptr = &expr;
1857 if (build_user_friendly_ref_for_offset (expr_ptr, TREE_TYPE (fld),
1858 offset - pos, exp_type))
1859 {
1860 *res = expr;
1861 return true;
1862 }
1863 }
1864 return false;
1865
1866 case ARRAY_TYPE:
1867 tr_size = TYPE_SIZE (TREE_TYPE (type));
1868 if (!tr_size || !tree_fits_uhwi_p (tr_size))
1869 return false;
1870 el_size = tree_to_uhwi (tr_size);
1871
1872 minidx = TYPE_MIN_VALUE (TYPE_DOMAIN (type));
1873 if (TREE_CODE (minidx) != INTEGER_CST || el_size == 0)
1874 return false;
1875 index = build_int_cst (TYPE_DOMAIN (type), offset / el_size);
1876 if (!integer_zerop (minidx))
1877 index = int_const_binop (PLUS_EXPR, index, minidx);
1878 *res = build4 (ARRAY_REF, TREE_TYPE (type), *res, index,
1879 NULL_TREE, NULL_TREE);
1880 offset = offset % el_size;
1881 type = TREE_TYPE (type);
1882 break;
1883
1884 default:
1885 if (offset != 0)
1886 return false;
1887
1888 if (exp_type)
1889 return false;
1890 else
1891 return true;
1892 }
1893 }
1894 }
1895
1896 /* Print message to dump file why a variable was rejected. */
1897
1898 static void
reject(tree var,const char * msg)1899 reject (tree var, const char *msg)
1900 {
1901 if (dump_file && (dump_flags & TDF_DETAILS))
1902 {
1903 fprintf (dump_file, "Rejected (%d): %s: ", DECL_UID (var), msg);
1904 print_generic_expr (dump_file, var);
1905 fprintf (dump_file, "\n");
1906 }
1907 }
1908
1909 /* Return true if VAR is a candidate for SRA. */
1910
1911 static bool
maybe_add_sra_candidate(tree var)1912 maybe_add_sra_candidate (tree var)
1913 {
1914 tree type = TREE_TYPE (var);
1915 const char *msg;
1916 tree_node **slot;
1917
1918 if (!AGGREGATE_TYPE_P (type))
1919 {
1920 reject (var, "not aggregate");
1921 return false;
1922 }
1923 /* Allow constant-pool entries that "need to live in memory". */
1924 if (needs_to_live_in_memory (var) && !constant_decl_p (var))
1925 {
1926 reject (var, "needs to live in memory");
1927 return false;
1928 }
1929 if (TREE_THIS_VOLATILE (var))
1930 {
1931 reject (var, "is volatile");
1932 return false;
1933 }
1934 if (!COMPLETE_TYPE_P (type))
1935 {
1936 reject (var, "has incomplete type");
1937 return false;
1938 }
1939 if (!tree_fits_shwi_p (TYPE_SIZE (type)))
1940 {
1941 reject (var, "type size not fixed");
1942 return false;
1943 }
1944 if (tree_to_shwi (TYPE_SIZE (type)) == 0)
1945 {
1946 reject (var, "type size is zero");
1947 return false;
1948 }
1949 if (type_internals_preclude_sra_p (type, &msg))
1950 {
1951 reject (var, msg);
1952 return false;
1953 }
1954 if (/* Fix for PR 41089. tree-stdarg.cc needs to have va_lists intact but
1955 we also want to schedule it rather late. Thus we ignore it in
1956 the early pass. */
1957 (sra_mode == SRA_MODE_EARLY_INTRA
1958 && is_va_list_type (type)))
1959 {
1960 reject (var, "is va_list");
1961 return false;
1962 }
1963
1964 bitmap_set_bit (candidate_bitmap, DECL_UID (var));
1965 slot = candidates->find_slot_with_hash (var, DECL_UID (var), INSERT);
1966 *slot = var;
1967
1968 if (dump_file && (dump_flags & TDF_DETAILS))
1969 {
1970 fprintf (dump_file, "Candidate (%d): ", DECL_UID (var));
1971 print_generic_expr (dump_file, var);
1972 fprintf (dump_file, "\n");
1973 }
1974
1975 return true;
1976 }
1977
1978 /* The very first phase of intraprocedural SRA. It marks in candidate_bitmap
1979 those with type which is suitable for scalarization. */
1980
1981 static bool
find_var_candidates(void)1982 find_var_candidates (void)
1983 {
1984 tree var, parm;
1985 unsigned int i;
1986 bool ret = false;
1987
1988 for (parm = DECL_ARGUMENTS (current_function_decl);
1989 parm;
1990 parm = DECL_CHAIN (parm))
1991 ret |= maybe_add_sra_candidate (parm);
1992
1993 FOR_EACH_LOCAL_DECL (cfun, i, var)
1994 {
1995 if (!VAR_P (var))
1996 continue;
1997
1998 ret |= maybe_add_sra_candidate (var);
1999 }
2000
2001 return ret;
2002 }
2003
2004 /* Return true if EXP is a reference chain of COMPONENT_REFs and AREAY_REFs
2005 ending either with a DECL or a MEM_REF with zero offset. */
2006
2007 static bool
path_comparable_for_same_access(tree expr)2008 path_comparable_for_same_access (tree expr)
2009 {
2010 while (handled_component_p (expr))
2011 {
2012 if (TREE_CODE (expr) == ARRAY_REF)
2013 {
2014 /* SSA name indices can occur here too when the array is of sie one.
2015 But we cannot just re-use array_refs with SSA names elsewhere in
2016 the function, so disallow non-constant indices. TODO: Remove this
2017 limitation after teaching build_reconstructed_reference to replace
2018 the index with the index type lower bound. */
2019 if (TREE_CODE (TREE_OPERAND (expr, 1)) != INTEGER_CST)
2020 return false;
2021 }
2022 expr = TREE_OPERAND (expr, 0);
2023 }
2024
2025 if (TREE_CODE (expr) == MEM_REF)
2026 {
2027 if (!zerop (TREE_OPERAND (expr, 1)))
2028 return false;
2029 }
2030 else
2031 gcc_assert (DECL_P (expr));
2032
2033 return true;
2034 }
2035
2036 /* Assuming that EXP1 consists of only COMPONENT_REFs and ARRAY_REFs, return
2037 true if the chain of these handled components are exactly the same as EXP2
2038 and the expression under them is the same DECL or an equivalent MEM_REF.
2039 The reference picked by compare_access_positions must go to EXP1. */
2040
2041 static bool
same_access_path_p(tree exp1,tree exp2)2042 same_access_path_p (tree exp1, tree exp2)
2043 {
2044 if (TREE_CODE (exp1) != TREE_CODE (exp2))
2045 {
2046 /* Special case single-field structures loaded sometimes as the field
2047 and sometimes as the structure. If the field is of a scalar type,
2048 compare_access_positions will put it into exp1.
2049
2050 TODO: The gimple register type condition can be removed if teach
2051 compare_access_positions to put inner types first. */
2052 if (is_gimple_reg_type (TREE_TYPE (exp1))
2053 && TREE_CODE (exp1) == COMPONENT_REF
2054 && (TYPE_MAIN_VARIANT (TREE_TYPE (TREE_OPERAND (exp1, 0)))
2055 == TYPE_MAIN_VARIANT (TREE_TYPE (exp2))))
2056 exp1 = TREE_OPERAND (exp1, 0);
2057 else
2058 return false;
2059 }
2060
2061 if (!operand_equal_p (exp1, exp2, OEP_ADDRESS_OF))
2062 return false;
2063
2064 return true;
2065 }
2066
2067 /* Sort all accesses for the given variable, check for partial overlaps and
2068 return NULL if there are any. If there are none, pick a representative for
2069 each combination of offset and size and create a linked list out of them.
2070 Return the pointer to the first representative and make sure it is the first
2071 one in the vector of accesses. */
2072
2073 static struct access *
sort_and_splice_var_accesses(tree var)2074 sort_and_splice_var_accesses (tree var)
2075 {
2076 int i, j, access_count;
2077 struct access *res, **prev_acc_ptr = &res;
2078 vec<access_p> *access_vec;
2079 bool first = true;
2080 HOST_WIDE_INT low = -1, high = 0;
2081
2082 access_vec = get_base_access_vector (var);
2083 if (!access_vec)
2084 return NULL;
2085 access_count = access_vec->length ();
2086
2087 /* Sort by <OFFSET, SIZE>. */
2088 access_vec->qsort (compare_access_positions);
2089
2090 i = 0;
2091 while (i < access_count)
2092 {
2093 struct access *access = (*access_vec)[i];
2094 bool grp_write = access->write;
2095 bool grp_read = !access->write;
2096 bool grp_scalar_write = access->write
2097 && is_gimple_reg_type (access->type);
2098 bool grp_scalar_read = !access->write
2099 && is_gimple_reg_type (access->type);
2100 bool grp_assignment_read = access->grp_assignment_read;
2101 bool grp_assignment_write = access->grp_assignment_write;
2102 bool multiple_scalar_reads = false;
2103 bool grp_partial_lhs = access->grp_partial_lhs;
2104 bool first_scalar = is_gimple_reg_type (access->type);
2105 bool unscalarizable_region = access->grp_unscalarizable_region;
2106 bool grp_same_access_path = true;
2107 bool bf_non_full_precision
2108 = (INTEGRAL_TYPE_P (access->type)
2109 && TYPE_PRECISION (access->type) != access->size
2110 && TREE_CODE (access->expr) == COMPONENT_REF
2111 && DECL_BIT_FIELD (TREE_OPERAND (access->expr, 1)));
2112
2113 if (first || access->offset >= high)
2114 {
2115 first = false;
2116 low = access->offset;
2117 high = access->offset + access->size;
2118 }
2119 else if (access->offset > low && access->offset + access->size > high)
2120 return NULL;
2121 else
2122 gcc_assert (access->offset >= low
2123 && access->offset + access->size <= high);
2124
2125 grp_same_access_path = path_comparable_for_same_access (access->expr);
2126
2127 j = i + 1;
2128 while (j < access_count)
2129 {
2130 struct access *ac2 = (*access_vec)[j];
2131 if (ac2->offset != access->offset || ac2->size != access->size)
2132 break;
2133 if (ac2->write)
2134 {
2135 grp_write = true;
2136 grp_scalar_write = (grp_scalar_write
2137 || is_gimple_reg_type (ac2->type));
2138 }
2139 else
2140 {
2141 grp_read = true;
2142 if (is_gimple_reg_type (ac2->type))
2143 {
2144 if (grp_scalar_read)
2145 multiple_scalar_reads = true;
2146 else
2147 grp_scalar_read = true;
2148 }
2149 }
2150 grp_assignment_read |= ac2->grp_assignment_read;
2151 grp_assignment_write |= ac2->grp_assignment_write;
2152 grp_partial_lhs |= ac2->grp_partial_lhs;
2153 unscalarizable_region |= ac2->grp_unscalarizable_region;
2154 relink_to_new_repr (access, ac2);
2155
2156 /* If there are both aggregate-type and scalar-type accesses with
2157 this combination of size and offset, the comparison function
2158 should have put the scalars first. */
2159 gcc_assert (first_scalar || !is_gimple_reg_type (ac2->type));
2160 /* It also prefers integral types to non-integral. However, when the
2161 precision of the selected type does not span the entire area and
2162 should also be used for a non-integer (i.e. float), we must not
2163 let that happen. Normally analyze_access_subtree expands the type
2164 to cover the entire area but for bit-fields it doesn't. */
2165 if (bf_non_full_precision && !INTEGRAL_TYPE_P (ac2->type))
2166 {
2167 if (dump_file && (dump_flags & TDF_DETAILS))
2168 {
2169 fprintf (dump_file, "Cannot scalarize the following access "
2170 "because insufficient precision integer type was "
2171 "selected.\n ");
2172 dump_access (dump_file, access, false);
2173 }
2174 unscalarizable_region = true;
2175 }
2176
2177 if (grp_same_access_path
2178 && !same_access_path_p (access->expr, ac2->expr))
2179 grp_same_access_path = false;
2180
2181 ac2->group_representative = access;
2182 j++;
2183 }
2184
2185 i = j;
2186
2187 access->group_representative = access;
2188 access->grp_write = grp_write;
2189 access->grp_read = grp_read;
2190 access->grp_scalar_read = grp_scalar_read;
2191 access->grp_scalar_write = grp_scalar_write;
2192 access->grp_assignment_read = grp_assignment_read;
2193 access->grp_assignment_write = grp_assignment_write;
2194 access->grp_hint = multiple_scalar_reads && !constant_decl_p (var);
2195 access->grp_partial_lhs = grp_partial_lhs;
2196 access->grp_unscalarizable_region = unscalarizable_region;
2197 access->grp_same_access_path = grp_same_access_path;
2198
2199 *prev_acc_ptr = access;
2200 prev_acc_ptr = &access->next_grp;
2201 }
2202
2203 gcc_assert (res == (*access_vec)[0]);
2204 return res;
2205 }
2206
2207 /* Create a variable for the given ACCESS which determines the type, name and a
2208 few other properties. Return the variable declaration and store it also to
2209 ACCESS->replacement. REG_TREE is used when creating a declaration to base a
2210 default-definition SSA name on in order to facilitate an uninitialized
2211 warning. It is used instead of the actual ACCESS type if that is not of a
2212 gimple register type. */
2213
2214 static tree
create_access_replacement(struct access * access,tree reg_type=NULL_TREE)2215 create_access_replacement (struct access *access, tree reg_type = NULL_TREE)
2216 {
2217 tree repl;
2218
2219 tree type = access->type;
2220 if (reg_type && !is_gimple_reg_type (type))
2221 type = reg_type;
2222
2223 if (access->grp_to_be_debug_replaced)
2224 {
2225 repl = create_tmp_var_raw (access->type);
2226 DECL_CONTEXT (repl) = current_function_decl;
2227 }
2228 else
2229 /* Drop any special alignment on the type if it's not on the main
2230 variant. This avoids issues with weirdo ABIs like AAPCS. */
2231 repl = create_tmp_var (build_qualified_type (TYPE_MAIN_VARIANT (type),
2232 TYPE_QUALS (type)), "SR");
2233 if (access->grp_partial_lhs
2234 && is_gimple_reg_type (type))
2235 DECL_NOT_GIMPLE_REG_P (repl) = 1;
2236
2237 DECL_SOURCE_LOCATION (repl) = DECL_SOURCE_LOCATION (access->base);
2238 DECL_ARTIFICIAL (repl) = 1;
2239 DECL_IGNORED_P (repl) = DECL_IGNORED_P (access->base);
2240
2241 if (DECL_NAME (access->base)
2242 && !DECL_IGNORED_P (access->base)
2243 && !DECL_ARTIFICIAL (access->base))
2244 {
2245 char *pretty_name = make_fancy_name (access->expr);
2246 tree debug_expr = unshare_expr_without_location (access->expr), d;
2247 bool fail = false;
2248
2249 DECL_NAME (repl) = get_identifier (pretty_name);
2250 DECL_NAMELESS (repl) = 1;
2251 obstack_free (&name_obstack, pretty_name);
2252
2253 /* Get rid of any SSA_NAMEs embedded in debug_expr,
2254 as DECL_DEBUG_EXPR isn't considered when looking for still
2255 used SSA_NAMEs and thus they could be freed. All debug info
2256 generation cares is whether something is constant or variable
2257 and that get_ref_base_and_extent works properly on the
2258 expression. It cannot handle accesses at a non-constant offset
2259 though, so just give up in those cases. */
2260 for (d = debug_expr;
2261 !fail && (handled_component_p (d) || TREE_CODE (d) == MEM_REF);
2262 d = TREE_OPERAND (d, 0))
2263 switch (TREE_CODE (d))
2264 {
2265 case ARRAY_REF:
2266 case ARRAY_RANGE_REF:
2267 if (TREE_OPERAND (d, 1)
2268 && TREE_CODE (TREE_OPERAND (d, 1)) != INTEGER_CST)
2269 fail = true;
2270 if (TREE_OPERAND (d, 3)
2271 && TREE_CODE (TREE_OPERAND (d, 3)) != INTEGER_CST)
2272 fail = true;
2273 /* FALLTHRU */
2274 case COMPONENT_REF:
2275 if (TREE_OPERAND (d, 2)
2276 && TREE_CODE (TREE_OPERAND (d, 2)) != INTEGER_CST)
2277 fail = true;
2278 break;
2279 case MEM_REF:
2280 if (TREE_CODE (TREE_OPERAND (d, 0)) != ADDR_EXPR)
2281 fail = true;
2282 else
2283 d = TREE_OPERAND (d, 0);
2284 break;
2285 default:
2286 break;
2287 }
2288 if (!fail)
2289 {
2290 SET_DECL_DEBUG_EXPR (repl, debug_expr);
2291 DECL_HAS_DEBUG_EXPR_P (repl) = 1;
2292 }
2293 if (access->grp_no_warning)
2294 suppress_warning (repl /* Be more selective! */);
2295 else
2296 copy_warning (repl, access->base);
2297 }
2298 else
2299 suppress_warning (repl /* Be more selective! */);
2300
2301 if (dump_file)
2302 {
2303 if (access->grp_to_be_debug_replaced)
2304 {
2305 fprintf (dump_file, "Created a debug-only replacement for ");
2306 print_generic_expr (dump_file, access->base);
2307 fprintf (dump_file, " offset: %u, size: %u\n",
2308 (unsigned) access->offset, (unsigned) access->size);
2309 }
2310 else
2311 {
2312 fprintf (dump_file, "Created a replacement for ");
2313 print_generic_expr (dump_file, access->base);
2314 fprintf (dump_file, " offset: %u, size: %u: ",
2315 (unsigned) access->offset, (unsigned) access->size);
2316 print_generic_expr (dump_file, repl, TDF_UID);
2317 fprintf (dump_file, "\n");
2318 }
2319 }
2320 sra_stats.replacements++;
2321
2322 return repl;
2323 }
2324
2325 /* Return ACCESS scalar replacement, which must exist. */
2326
2327 static inline tree
get_access_replacement(struct access * access)2328 get_access_replacement (struct access *access)
2329 {
2330 gcc_checking_assert (access->replacement_decl);
2331 return access->replacement_decl;
2332 }
2333
2334
2335 /* Build a subtree of accesses rooted in *ACCESS, and move the pointer in the
2336 linked list along the way. Stop when *ACCESS is NULL or the access pointed
2337 to it is not "within" the root. Return false iff some accesses partially
2338 overlap. */
2339
2340 static bool
build_access_subtree(struct access ** access)2341 build_access_subtree (struct access **access)
2342 {
2343 struct access *root = *access, *last_child = NULL;
2344 HOST_WIDE_INT limit = root->offset + root->size;
2345
2346 *access = (*access)->next_grp;
2347 while (*access && (*access)->offset + (*access)->size <= limit)
2348 {
2349 if (!last_child)
2350 root->first_child = *access;
2351 else
2352 last_child->next_sibling = *access;
2353 last_child = *access;
2354 (*access)->parent = root;
2355 (*access)->grp_write |= root->grp_write;
2356
2357 if (!build_access_subtree (access))
2358 return false;
2359 }
2360
2361 if (*access && (*access)->offset < limit)
2362 return false;
2363
2364 return true;
2365 }
2366
2367 /* Build a tree of access representatives, ACCESS is the pointer to the first
2368 one, others are linked in a list by the next_grp field. Return false iff
2369 some accesses partially overlap. */
2370
2371 static bool
build_access_trees(struct access * access)2372 build_access_trees (struct access *access)
2373 {
2374 while (access)
2375 {
2376 struct access *root = access;
2377
2378 if (!build_access_subtree (&access))
2379 return false;
2380 root->next_grp = access;
2381 }
2382 return true;
2383 }
2384
2385 /* Traverse the access forest where ROOT is the first root and verify that
2386 various important invariants hold true. */
2387
2388 DEBUG_FUNCTION void
verify_sra_access_forest(struct access * root)2389 verify_sra_access_forest (struct access *root)
2390 {
2391 struct access *access = root;
2392 tree first_base = root->base;
2393 gcc_assert (DECL_P (first_base));
2394 do
2395 {
2396 gcc_assert (access->base == first_base);
2397 if (access->parent)
2398 gcc_assert (access->offset >= access->parent->offset
2399 && access->size <= access->parent->size);
2400 if (access->next_sibling)
2401 gcc_assert (access->next_sibling->offset
2402 >= access->offset + access->size);
2403
2404 poly_int64 poffset, psize, pmax_size;
2405 bool reverse;
2406 tree base = get_ref_base_and_extent (access->expr, &poffset, &psize,
2407 &pmax_size, &reverse);
2408 HOST_WIDE_INT offset, size, max_size;
2409 if (!poffset.is_constant (&offset)
2410 || !psize.is_constant (&size)
2411 || !pmax_size.is_constant (&max_size))
2412 gcc_unreachable ();
2413 gcc_assert (base == first_base);
2414 gcc_assert (offset == access->offset);
2415 gcc_assert (access->grp_unscalarizable_region
2416 || access->grp_total_scalarization
2417 || size == max_size);
2418 gcc_assert (access->grp_unscalarizable_region
2419 || !is_gimple_reg_type (access->type)
2420 || size == access->size);
2421 gcc_assert (reverse == access->reverse);
2422
2423 if (access->first_child)
2424 {
2425 gcc_assert (access->first_child->parent == access);
2426 access = access->first_child;
2427 }
2428 else if (access->next_sibling)
2429 {
2430 gcc_assert (access->next_sibling->parent == access->parent);
2431 access = access->next_sibling;
2432 }
2433 else
2434 {
2435 while (access->parent && !access->next_sibling)
2436 access = access->parent;
2437 if (access->next_sibling)
2438 access = access->next_sibling;
2439 else
2440 {
2441 gcc_assert (access == root);
2442 root = root->next_grp;
2443 access = root;
2444 }
2445 }
2446 }
2447 while (access);
2448 }
2449
2450 /* Verify access forests of all candidates with accesses by calling
2451 verify_access_forest on each on them. */
2452
2453 DEBUG_FUNCTION void
verify_all_sra_access_forests(void)2454 verify_all_sra_access_forests (void)
2455 {
2456 bitmap_iterator bi;
2457 unsigned i;
2458 EXECUTE_IF_SET_IN_BITMAP (candidate_bitmap, 0, i, bi)
2459 {
2460 tree var = candidate (i);
2461 struct access *access = get_first_repr_for_decl (var);
2462 if (access)
2463 {
2464 gcc_assert (access->base == var);
2465 verify_sra_access_forest (access);
2466 }
2467 }
2468 }
2469
2470 /* Return true if expr contains some ARRAY_REFs into a variable bounded
2471 array. */
2472
2473 static bool
expr_with_var_bounded_array_refs_p(tree expr)2474 expr_with_var_bounded_array_refs_p (tree expr)
2475 {
2476 while (handled_component_p (expr))
2477 {
2478 if (TREE_CODE (expr) == ARRAY_REF
2479 && !tree_fits_shwi_p (array_ref_low_bound (expr)))
2480 return true;
2481 expr = TREE_OPERAND (expr, 0);
2482 }
2483 return false;
2484 }
2485
2486 /* Analyze the subtree of accesses rooted in ROOT, scheduling replacements when
2487 both seeming beneficial and when ALLOW_REPLACEMENTS allows it. If TOTALLY
2488 is set, we are totally scalarizing the aggregate. Also set all sorts of
2489 access flags appropriately along the way, notably always set grp_read and
2490 grp_assign_read according to MARK_READ and grp_write when MARK_WRITE is
2491 true.
2492
2493 Creating a replacement for a scalar access is considered beneficial if its
2494 grp_hint ot TOTALLY is set (this means either that there is more than one
2495 direct read access or that we are attempting total scalarization) or
2496 according to the following table:
2497
2498 Access written to through a scalar type (once or more times)
2499 |
2500 | Written to in an assignment statement
2501 | |
2502 | | Access read as scalar _once_
2503 | | |
2504 | | | Read in an assignment statement
2505 | | | |
2506 | | | | Scalarize Comment
2507 -----------------------------------------------------------------------------
2508 0 0 0 0 No access for the scalar
2509 0 0 0 1 No access for the scalar
2510 0 0 1 0 No Single read - won't help
2511 0 0 1 1 No The same case
2512 0 1 0 0 No access for the scalar
2513 0 1 0 1 No access for the scalar
2514 0 1 1 0 Yes s = *g; return s.i;
2515 0 1 1 1 Yes The same case as above
2516 1 0 0 0 No Won't help
2517 1 0 0 1 Yes s.i = 1; *g = s;
2518 1 0 1 0 Yes s.i = 5; g = s.i;
2519 1 0 1 1 Yes The same case as above
2520 1 1 0 0 No Won't help.
2521 1 1 0 1 Yes s.i = 1; *g = s;
2522 1 1 1 0 Yes s = *g; return s.i;
2523 1 1 1 1 Yes Any of the above yeses */
2524
2525 static bool
analyze_access_subtree(struct access * root,struct access * parent,bool allow_replacements,bool totally)2526 analyze_access_subtree (struct access *root, struct access *parent,
2527 bool allow_replacements, bool totally)
2528 {
2529 struct access *child;
2530 HOST_WIDE_INT limit = root->offset + root->size;
2531 HOST_WIDE_INT covered_to = root->offset;
2532 bool scalar = is_gimple_reg_type (root->type);
2533 bool hole = false, sth_created = false;
2534
2535 if (parent)
2536 {
2537 if (parent->grp_read)
2538 root->grp_read = 1;
2539 if (parent->grp_assignment_read)
2540 root->grp_assignment_read = 1;
2541 if (parent->grp_write)
2542 root->grp_write = 1;
2543 if (parent->grp_assignment_write)
2544 root->grp_assignment_write = 1;
2545 if (!parent->grp_same_access_path)
2546 root->grp_same_access_path = 0;
2547 }
2548
2549 if (root->grp_unscalarizable_region)
2550 allow_replacements = false;
2551
2552 if (allow_replacements && expr_with_var_bounded_array_refs_p (root->expr))
2553 allow_replacements = false;
2554
2555 if (!totally && root->grp_result_of_prop_from_lhs)
2556 allow_replacements = false;
2557
2558 for (child = root->first_child; child; child = child->next_sibling)
2559 {
2560 hole |= covered_to < child->offset;
2561 sth_created |= analyze_access_subtree (child, root,
2562 allow_replacements && !scalar,
2563 totally);
2564
2565 root->grp_unscalarized_data |= child->grp_unscalarized_data;
2566 if (child->grp_covered)
2567 covered_to += child->size;
2568 else
2569 hole = true;
2570 }
2571
2572 if (allow_replacements && scalar && !root->first_child
2573 && (totally || !root->grp_total_scalarization)
2574 && (totally
2575 || root->grp_hint
2576 || ((root->grp_scalar_read || root->grp_assignment_read)
2577 && (root->grp_scalar_write || root->grp_assignment_write))))
2578 {
2579 /* Always create access replacements that cover the whole access.
2580 For integral types this means the precision has to match.
2581 Avoid assumptions based on the integral type kind, too. */
2582 if (INTEGRAL_TYPE_P (root->type)
2583 && (TREE_CODE (root->type) != INTEGER_TYPE
2584 || TYPE_PRECISION (root->type) != root->size)
2585 /* But leave bitfield accesses alone. */
2586 && (TREE_CODE (root->expr) != COMPONENT_REF
2587 || !DECL_BIT_FIELD (TREE_OPERAND (root->expr, 1))))
2588 {
2589 tree rt = root->type;
2590 gcc_assert ((root->offset % BITS_PER_UNIT) == 0
2591 && (root->size % BITS_PER_UNIT) == 0);
2592 root->type = build_nonstandard_integer_type (root->size,
2593 TYPE_UNSIGNED (rt));
2594 root->expr = build_ref_for_offset (UNKNOWN_LOCATION, root->base,
2595 root->offset, root->reverse,
2596 root->type, NULL, false);
2597
2598 if (dump_file && (dump_flags & TDF_DETAILS))
2599 {
2600 fprintf (dump_file, "Changing the type of a replacement for ");
2601 print_generic_expr (dump_file, root->base);
2602 fprintf (dump_file, " offset: %u, size: %u ",
2603 (unsigned) root->offset, (unsigned) root->size);
2604 fprintf (dump_file, " to an integer.\n");
2605 }
2606 }
2607
2608 root->grp_to_be_replaced = 1;
2609 root->replacement_decl = create_access_replacement (root);
2610 sth_created = true;
2611 hole = false;
2612 }
2613 else
2614 {
2615 if (allow_replacements
2616 && scalar && !root->first_child
2617 && !root->grp_total_scalarization
2618 && (root->grp_scalar_write || root->grp_assignment_write)
2619 && !bitmap_bit_p (cannot_scalarize_away_bitmap,
2620 DECL_UID (root->base)))
2621 {
2622 gcc_checking_assert (!root->grp_scalar_read
2623 && !root->grp_assignment_read);
2624 sth_created = true;
2625 if (MAY_HAVE_DEBUG_BIND_STMTS)
2626 {
2627 root->grp_to_be_debug_replaced = 1;
2628 root->replacement_decl = create_access_replacement (root);
2629 }
2630 }
2631
2632 if (covered_to < limit)
2633 hole = true;
2634 if (scalar || !allow_replacements)
2635 root->grp_total_scalarization = 0;
2636 }
2637
2638 if (!hole || totally)
2639 root->grp_covered = 1;
2640 else if (root->grp_write || comes_initialized_p (root->base))
2641 root->grp_unscalarized_data = 1; /* not covered and written to */
2642 return sth_created;
2643 }
2644
2645 /* Analyze all access trees linked by next_grp by the means of
2646 analyze_access_subtree. */
2647 static bool
analyze_access_trees(struct access * access)2648 analyze_access_trees (struct access *access)
2649 {
2650 bool ret = false;
2651
2652 while (access)
2653 {
2654 if (analyze_access_subtree (access, NULL, true,
2655 access->grp_total_scalarization))
2656 ret = true;
2657 access = access->next_grp;
2658 }
2659
2660 return ret;
2661 }
2662
2663 /* Return true iff a potential new child of ACC at offset OFFSET and with size
2664 SIZE would conflict with an already existing one. If exactly such a child
2665 already exists in ACC, store a pointer to it in EXACT_MATCH. */
2666
2667 static bool
child_would_conflict_in_acc(struct access * acc,HOST_WIDE_INT norm_offset,HOST_WIDE_INT size,struct access ** exact_match)2668 child_would_conflict_in_acc (struct access *acc, HOST_WIDE_INT norm_offset,
2669 HOST_WIDE_INT size, struct access **exact_match)
2670 {
2671 struct access *child;
2672
2673 for (child = acc->first_child; child; child = child->next_sibling)
2674 {
2675 if (child->offset == norm_offset && child->size == size)
2676 {
2677 *exact_match = child;
2678 return true;
2679 }
2680
2681 if (child->offset < norm_offset + size
2682 && child->offset + child->size > norm_offset)
2683 return true;
2684 }
2685
2686 return false;
2687 }
2688
2689 /* Create a new child access of PARENT, with all properties just like MODEL
2690 except for its offset and with its grp_write false and grp_read true.
2691 Return the new access or NULL if it cannot be created. Note that this
2692 access is created long after all splicing and sorting, it's not located in
2693 any access vector and is automatically a representative of its group. Set
2694 the gpr_write flag of the new accesss if SET_GRP_WRITE is true. */
2695
2696 static struct access *
create_artificial_child_access(struct access * parent,struct access * model,HOST_WIDE_INT new_offset,bool set_grp_read,bool set_grp_write)2697 create_artificial_child_access (struct access *parent, struct access *model,
2698 HOST_WIDE_INT new_offset,
2699 bool set_grp_read, bool set_grp_write)
2700 {
2701 struct access **child;
2702 tree expr = parent->base;
2703
2704 gcc_assert (!model->grp_unscalarizable_region);
2705
2706 struct access *access = access_pool.allocate ();
2707 memset (access, 0, sizeof (struct access));
2708 if (!build_user_friendly_ref_for_offset (&expr, TREE_TYPE (expr), new_offset,
2709 model->type))
2710 {
2711 access->grp_no_warning = true;
2712 expr = build_ref_for_model (EXPR_LOCATION (parent->base), parent->base,
2713 new_offset, model, NULL, false);
2714 }
2715
2716 access->base = parent->base;
2717 access->expr = expr;
2718 access->offset = new_offset;
2719 access->size = model->size;
2720 access->type = model->type;
2721 access->parent = parent;
2722 access->grp_read = set_grp_read;
2723 access->grp_write = set_grp_write;
2724 access->reverse = model->reverse;
2725
2726 child = &parent->first_child;
2727 while (*child && (*child)->offset < new_offset)
2728 child = &(*child)->next_sibling;
2729
2730 access->next_sibling = *child;
2731 *child = access;
2732
2733 return access;
2734 }
2735
2736
2737 /* Beginning with ACCESS, traverse its whole access subtree and mark all
2738 sub-trees as written to. If any of them has not been marked so previously
2739 and has assignment links leading from it, re-enqueue it. */
2740
2741 static void
subtree_mark_written_and_rhs_enqueue(struct access * access)2742 subtree_mark_written_and_rhs_enqueue (struct access *access)
2743 {
2744 if (access->grp_write)
2745 return;
2746 access->grp_write = true;
2747 add_access_to_rhs_work_queue (access);
2748
2749 struct access *child;
2750 for (child = access->first_child; child; child = child->next_sibling)
2751 subtree_mark_written_and_rhs_enqueue (child);
2752 }
2753
2754 /* If there is still budget to create a propagation access for DECL, return
2755 true and decrement the budget. Otherwise return false. */
2756
2757 static bool
budget_for_propagation_access(tree decl)2758 budget_for_propagation_access (tree decl)
2759 {
2760 unsigned b, *p = propagation_budget->get (decl);
2761 if (p)
2762 b = *p;
2763 else
2764 b = param_sra_max_propagations;
2765
2766 if (b == 0)
2767 return false;
2768 b--;
2769
2770 if (b == 0 && dump_file && (dump_flags & TDF_DETAILS))
2771 {
2772 fprintf (dump_file, "The propagation budget of ");
2773 print_generic_expr (dump_file, decl);
2774 fprintf (dump_file, " (UID: %u) has been exhausted.\n", DECL_UID (decl));
2775 }
2776 propagation_budget->put (decl, b);
2777 return true;
2778 }
2779
2780 /* Return true if ACC or any of its subaccesses has grp_child set. */
2781
2782 static bool
access_or_its_child_written(struct access * acc)2783 access_or_its_child_written (struct access *acc)
2784 {
2785 if (acc->grp_write)
2786 return true;
2787 for (struct access *sub = acc->first_child; sub; sub = sub->next_sibling)
2788 if (access_or_its_child_written (sub))
2789 return true;
2790 return false;
2791 }
2792
2793 /* Propagate subaccesses and grp_write flags of RACC across an assignment link
2794 to LACC. Enqueue sub-accesses as necessary so that the write flag is
2795 propagated transitively. Return true if anything changed. Additionally, if
2796 RACC is a scalar access but LACC is not, change the type of the latter, if
2797 possible. */
2798
2799 static bool
propagate_subaccesses_from_rhs(struct access * lacc,struct access * racc)2800 propagate_subaccesses_from_rhs (struct access *lacc, struct access *racc)
2801 {
2802 struct access *rchild;
2803 HOST_WIDE_INT norm_delta = lacc->offset - racc->offset;
2804 bool ret = false;
2805
2806 /* IF the LHS is still not marked as being written to, we only need to do so
2807 if the RHS at this level actually was. */
2808 if (!lacc->grp_write)
2809 {
2810 gcc_checking_assert (!comes_initialized_p (racc->base));
2811 if (racc->grp_write)
2812 {
2813 subtree_mark_written_and_rhs_enqueue (lacc);
2814 ret = true;
2815 }
2816 }
2817
2818 if (is_gimple_reg_type (lacc->type)
2819 || lacc->grp_unscalarizable_region
2820 || racc->grp_unscalarizable_region)
2821 {
2822 if (!lacc->grp_write)
2823 {
2824 ret = true;
2825 subtree_mark_written_and_rhs_enqueue (lacc);
2826 }
2827 return ret;
2828 }
2829
2830 if (is_gimple_reg_type (racc->type))
2831 {
2832 if (!lacc->grp_write)
2833 {
2834 ret = true;
2835 subtree_mark_written_and_rhs_enqueue (lacc);
2836 }
2837 if (!lacc->first_child && !racc->first_child)
2838 {
2839 /* We are about to change the access type from aggregate to scalar,
2840 so we need to put the reverse flag onto the access, if any. */
2841 const bool reverse
2842 = TYPE_REVERSE_STORAGE_ORDER (lacc->type)
2843 && !POINTER_TYPE_P (racc->type)
2844 && !VECTOR_TYPE_P (racc->type);
2845 tree t = lacc->base;
2846
2847 lacc->type = racc->type;
2848 if (build_user_friendly_ref_for_offset (&t, TREE_TYPE (t),
2849 lacc->offset, racc->type))
2850 {
2851 lacc->expr = t;
2852 lacc->grp_same_access_path = true;
2853 }
2854 else
2855 {
2856 lacc->expr = build_ref_for_model (EXPR_LOCATION (lacc->base),
2857 lacc->base, lacc->offset,
2858 racc, NULL, false);
2859 if (TREE_CODE (lacc->expr) == MEM_REF)
2860 REF_REVERSE_STORAGE_ORDER (lacc->expr) = reverse;
2861 lacc->grp_no_warning = true;
2862 lacc->grp_same_access_path = false;
2863 }
2864 lacc->reverse = reverse;
2865 }
2866 return ret;
2867 }
2868
2869 for (rchild = racc->first_child; rchild; rchild = rchild->next_sibling)
2870 {
2871 struct access *new_acc = NULL;
2872 HOST_WIDE_INT norm_offset = rchild->offset + norm_delta;
2873
2874 if (child_would_conflict_in_acc (lacc, norm_offset, rchild->size,
2875 &new_acc))
2876 {
2877 if (new_acc)
2878 {
2879 if (!new_acc->grp_write && rchild->grp_write)
2880 {
2881 gcc_assert (!lacc->grp_write);
2882 subtree_mark_written_and_rhs_enqueue (new_acc);
2883 ret = true;
2884 }
2885
2886 rchild->grp_hint = 1;
2887 new_acc->grp_hint |= new_acc->grp_read;
2888 if (rchild->first_child
2889 && propagate_subaccesses_from_rhs (new_acc, rchild))
2890 {
2891 ret = 1;
2892 add_access_to_rhs_work_queue (new_acc);
2893 }
2894 }
2895 else
2896 {
2897 if (!lacc->grp_write)
2898 {
2899 ret = true;
2900 subtree_mark_written_and_rhs_enqueue (lacc);
2901 }
2902 }
2903 continue;
2904 }
2905
2906 if (rchild->grp_unscalarizable_region
2907 || !budget_for_propagation_access (lacc->base))
2908 {
2909 if (!lacc->grp_write && access_or_its_child_written (rchild))
2910 {
2911 ret = true;
2912 subtree_mark_written_and_rhs_enqueue (lacc);
2913 }
2914 continue;
2915 }
2916
2917 rchild->grp_hint = 1;
2918 /* Because get_ref_base_and_extent always includes padding in size for
2919 accesses to DECLs but not necessarily for COMPONENT_REFs of the same
2920 type, we might be actually attempting to here to create a child of the
2921 same type as the parent. */
2922 if (!types_compatible_p (lacc->type, rchild->type))
2923 new_acc = create_artificial_child_access (lacc, rchild, norm_offset,
2924 false,
2925 (lacc->grp_write
2926 || rchild->grp_write));
2927 else
2928 new_acc = lacc;
2929 gcc_checking_assert (new_acc);
2930 if (racc->first_child)
2931 propagate_subaccesses_from_rhs (new_acc, rchild);
2932
2933 add_access_to_rhs_work_queue (lacc);
2934 ret = true;
2935 }
2936
2937 return ret;
2938 }
2939
2940 /* Propagate subaccesses of LACC across an assignment link to RACC if they
2941 should inhibit total scalarization of the corresponding area. No flags are
2942 being propagated in the process. Return true if anything changed. */
2943
2944 static bool
propagate_subaccesses_from_lhs(struct access * lacc,struct access * racc)2945 propagate_subaccesses_from_lhs (struct access *lacc, struct access *racc)
2946 {
2947 if (is_gimple_reg_type (racc->type)
2948 || lacc->grp_unscalarizable_region
2949 || racc->grp_unscalarizable_region)
2950 return false;
2951
2952 /* TODO: Do we want set some new racc flag to stop potential total
2953 scalarization if lacc is a scalar access (and none fo the two have
2954 children)? */
2955
2956 bool ret = false;
2957 HOST_WIDE_INT norm_delta = racc->offset - lacc->offset;
2958 for (struct access *lchild = lacc->first_child;
2959 lchild;
2960 lchild = lchild->next_sibling)
2961 {
2962 struct access *matching_acc = NULL;
2963 HOST_WIDE_INT norm_offset = lchild->offset + norm_delta;
2964
2965 if (lchild->grp_unscalarizable_region
2966 || child_would_conflict_in_acc (racc, norm_offset, lchild->size,
2967 &matching_acc)
2968 || !budget_for_propagation_access (racc->base))
2969 {
2970 if (matching_acc
2971 && propagate_subaccesses_from_lhs (lchild, matching_acc))
2972 add_access_to_lhs_work_queue (matching_acc);
2973 continue;
2974 }
2975
2976 /* Because get_ref_base_and_extent always includes padding in size for
2977 accesses to DECLs but not necessarily for COMPONENT_REFs of the same
2978 type, we might be actually attempting to here to create a child of the
2979 same type as the parent. */
2980 if (!types_compatible_p (racc->type, lchild->type))
2981 {
2982 struct access *new_acc
2983 = create_artificial_child_access (racc, lchild, norm_offset,
2984 true, false);
2985 new_acc->grp_result_of_prop_from_lhs = 1;
2986 propagate_subaccesses_from_lhs (lchild, new_acc);
2987 }
2988 else
2989 propagate_subaccesses_from_lhs (lchild, racc);
2990 ret = true;
2991 }
2992 return ret;
2993 }
2994
2995 /* Propagate all subaccesses across assignment links. */
2996
2997 static void
propagate_all_subaccesses(void)2998 propagate_all_subaccesses (void)
2999 {
3000 propagation_budget = new hash_map<tree, unsigned>;
3001 while (rhs_work_queue_head)
3002 {
3003 struct access *racc = pop_access_from_rhs_work_queue ();
3004 struct assign_link *link;
3005
3006 if (racc->group_representative)
3007 racc= racc->group_representative;
3008 gcc_assert (racc->first_rhs_link);
3009
3010 for (link = racc->first_rhs_link; link; link = link->next_rhs)
3011 {
3012 struct access *lacc = link->lacc;
3013
3014 if (!bitmap_bit_p (candidate_bitmap, DECL_UID (lacc->base)))
3015 continue;
3016 lacc = lacc->group_representative;
3017
3018 bool reque_parents = false;
3019 if (!bitmap_bit_p (candidate_bitmap, DECL_UID (racc->base)))
3020 {
3021 if (!lacc->grp_write)
3022 {
3023 subtree_mark_written_and_rhs_enqueue (lacc);
3024 reque_parents = true;
3025 }
3026 }
3027 else if (propagate_subaccesses_from_rhs (lacc, racc))
3028 reque_parents = true;
3029
3030 if (reque_parents)
3031 do
3032 {
3033 add_access_to_rhs_work_queue (lacc);
3034 lacc = lacc->parent;
3035 }
3036 while (lacc);
3037 }
3038 }
3039
3040 while (lhs_work_queue_head)
3041 {
3042 struct access *lacc = pop_access_from_lhs_work_queue ();
3043 struct assign_link *link;
3044
3045 if (lacc->group_representative)
3046 lacc = lacc->group_representative;
3047 gcc_assert (lacc->first_lhs_link);
3048
3049 if (!bitmap_bit_p (candidate_bitmap, DECL_UID (lacc->base)))
3050 continue;
3051
3052 for (link = lacc->first_lhs_link; link; link = link->next_lhs)
3053 {
3054 struct access *racc = link->racc;
3055
3056 if (racc->group_representative)
3057 racc = racc->group_representative;
3058 if (!bitmap_bit_p (candidate_bitmap, DECL_UID (racc->base)))
3059 continue;
3060 if (propagate_subaccesses_from_lhs (lacc, racc))
3061 add_access_to_lhs_work_queue (racc);
3062 }
3063 }
3064 delete propagation_budget;
3065 }
3066
3067 /* Return true if the forest beginning with ROOT does not contain
3068 unscalarizable regions or non-byte aligned accesses. */
3069
3070 static bool
can_totally_scalarize_forest_p(struct access * root)3071 can_totally_scalarize_forest_p (struct access *root)
3072 {
3073 struct access *access = root;
3074 do
3075 {
3076 if (access->grp_unscalarizable_region
3077 || (access->offset % BITS_PER_UNIT) != 0
3078 || (access->size % BITS_PER_UNIT) != 0
3079 || (is_gimple_reg_type (access->type)
3080 && access->first_child))
3081 return false;
3082
3083 if (access->first_child)
3084 access = access->first_child;
3085 else if (access->next_sibling)
3086 access = access->next_sibling;
3087 else
3088 {
3089 while (access->parent && !access->next_sibling)
3090 access = access->parent;
3091 if (access->next_sibling)
3092 access = access->next_sibling;
3093 else
3094 {
3095 gcc_assert (access == root);
3096 root = root->next_grp;
3097 access = root;
3098 }
3099 }
3100 }
3101 while (access);
3102 return true;
3103 }
3104
3105 /* Create and return an ACCESS in PARENT spanning from POS with SIZE, TYPE and
3106 reference EXPR for total scalarization purposes and mark it as such. Within
3107 the children of PARENT, link it in between PTR and NEXT_SIBLING. */
3108
3109 static struct access *
create_total_scalarization_access(struct access * parent,HOST_WIDE_INT pos,HOST_WIDE_INT size,tree type,tree expr,struct access ** ptr,struct access * next_sibling)3110 create_total_scalarization_access (struct access *parent, HOST_WIDE_INT pos,
3111 HOST_WIDE_INT size, tree type, tree expr,
3112 struct access **ptr,
3113 struct access *next_sibling)
3114 {
3115 struct access *access = access_pool.allocate ();
3116 memset (access, 0, sizeof (struct access));
3117 access->base = parent->base;
3118 access->offset = pos;
3119 access->size = size;
3120 access->expr = expr;
3121 access->type = type;
3122 access->parent = parent;
3123 access->grp_write = parent->grp_write;
3124 access->grp_total_scalarization = 1;
3125 access->grp_hint = 1;
3126 access->grp_same_access_path = path_comparable_for_same_access (expr);
3127 access->reverse = reverse_storage_order_for_component_p (expr);
3128
3129 access->next_sibling = next_sibling;
3130 *ptr = access;
3131 return access;
3132 }
3133
3134 /* Create and return an ACCESS in PARENT spanning from POS with SIZE, TYPE and
3135 reference EXPR for total scalarization purposes and mark it as such, link it
3136 at *PTR and reshape the tree so that those elements at *PTR and their
3137 siblings which fall within the part described by POS and SIZE are moved to
3138 be children of the new access. If a partial overlap is detected, return
3139 NULL. */
3140
3141 static struct access *
create_total_access_and_reshape(struct access * parent,HOST_WIDE_INT pos,HOST_WIDE_INT size,tree type,tree expr,struct access ** ptr)3142 create_total_access_and_reshape (struct access *parent, HOST_WIDE_INT pos,
3143 HOST_WIDE_INT size, tree type, tree expr,
3144 struct access **ptr)
3145 {
3146 struct access **p = ptr;
3147
3148 while (*p && (*p)->offset < pos + size)
3149 {
3150 if ((*p)->offset + (*p)->size > pos + size)
3151 return NULL;
3152 p = &(*p)->next_sibling;
3153 }
3154
3155 struct access *next_child = *ptr;
3156 struct access *new_acc
3157 = create_total_scalarization_access (parent, pos, size, type, expr,
3158 ptr, *p);
3159 if (p != ptr)
3160 {
3161 new_acc->first_child = next_child;
3162 *p = NULL;
3163 for (struct access *a = next_child; a; a = a->next_sibling)
3164 a->parent = new_acc;
3165 }
3166 return new_acc;
3167 }
3168
3169 static bool totally_scalarize_subtree (struct access *root);
3170
3171 /* Return true if INNER is either the same type as OUTER or if it is the type
3172 of a record field in OUTER at offset zero, possibly in nested
3173 sub-records. */
3174
3175 static bool
access_and_field_type_match_p(tree outer,tree inner)3176 access_and_field_type_match_p (tree outer, tree inner)
3177 {
3178 if (TYPE_MAIN_VARIANT (outer) == TYPE_MAIN_VARIANT (inner))
3179 return true;
3180 if (TREE_CODE (outer) != RECORD_TYPE)
3181 return false;
3182 tree fld = TYPE_FIELDS (outer);
3183 while (fld)
3184 {
3185 if (TREE_CODE (fld) == FIELD_DECL)
3186 {
3187 if (!zerop (DECL_FIELD_OFFSET (fld)))
3188 return false;
3189 if (TYPE_MAIN_VARIANT (TREE_TYPE (fld)) == inner)
3190 return true;
3191 if (TREE_CODE (TREE_TYPE (fld)) == RECORD_TYPE)
3192 fld = TYPE_FIELDS (TREE_TYPE (fld));
3193 else
3194 return false;
3195 }
3196 else
3197 fld = DECL_CHAIN (fld);
3198 }
3199 return false;
3200 }
3201
3202 /* Return type of total_should_skip_creating_access indicating whether a total
3203 scalarization access for a field/element should be created, whether it
3204 already exists or whether the entire total scalarization has to fail. */
3205
3206 enum total_sra_field_state {TOTAL_FLD_CREATE, TOTAL_FLD_DONE, TOTAL_FLD_FAILED};
3207
3208 /* Do all the necessary steps in total scalarization when the given aggregate
3209 type has a TYPE at POS with the given SIZE should be put into PARENT and
3210 when we have processed all its siblings with smaller offsets up until and
3211 including LAST_SEEN_SIBLING (which can be NULL).
3212
3213 If some further siblings are to be skipped, set *LAST_SEEN_SIBLING as
3214 appropriate. Return TOTAL_FLD_CREATE id the caller should carry on with
3215 creating a new access, TOTAL_FLD_DONE if access or accesses capable of
3216 representing the described part of the aggregate for the purposes of total
3217 scalarization already exist or TOTAL_FLD_FAILED if there is a problem which
3218 prevents total scalarization from happening at all. */
3219
3220 static enum total_sra_field_state
total_should_skip_creating_access(struct access * parent,struct access ** last_seen_sibling,tree type,HOST_WIDE_INT pos,HOST_WIDE_INT size)3221 total_should_skip_creating_access (struct access *parent,
3222 struct access **last_seen_sibling,
3223 tree type, HOST_WIDE_INT pos,
3224 HOST_WIDE_INT size)
3225 {
3226 struct access *next_child;
3227 if (!*last_seen_sibling)
3228 next_child = parent->first_child;
3229 else
3230 next_child = (*last_seen_sibling)->next_sibling;
3231
3232 /* First, traverse the chain of siblings until it points to an access with
3233 offset at least equal to POS. Check all skipped accesses whether they
3234 span the POS boundary and if so, return with a failure. */
3235 while (next_child && next_child->offset < pos)
3236 {
3237 if (next_child->offset + next_child->size > pos)
3238 return TOTAL_FLD_FAILED;
3239 *last_seen_sibling = next_child;
3240 next_child = next_child->next_sibling;
3241 }
3242
3243 /* Now check whether next_child has exactly the right POS and SIZE and if so,
3244 whether it can represent what we need and can be totally scalarized
3245 itself. */
3246 if (next_child && next_child->offset == pos
3247 && next_child->size == size)
3248 {
3249 if (!is_gimple_reg_type (next_child->type)
3250 && (!access_and_field_type_match_p (type, next_child->type)
3251 || !totally_scalarize_subtree (next_child)))
3252 return TOTAL_FLD_FAILED;
3253
3254 *last_seen_sibling = next_child;
3255 return TOTAL_FLD_DONE;
3256 }
3257
3258 /* If the child we're looking at would partially overlap, we just cannot
3259 totally scalarize. */
3260 if (next_child
3261 && next_child->offset < pos + size
3262 && next_child->offset + next_child->size > pos + size)
3263 return TOTAL_FLD_FAILED;
3264
3265 if (is_gimple_reg_type (type))
3266 {
3267 /* We don't scalarize accesses that are children of other scalar type
3268 accesses, so if we go on and create an access for a register type,
3269 there should not be any pre-existing children. There are rare cases
3270 where the requested type is a vector but we already have register
3271 accesses for all its elements which is equally good. Detect that
3272 situation or whether we need to bail out. */
3273
3274 HOST_WIDE_INT covered = pos;
3275 bool skipping = false;
3276 while (next_child
3277 && next_child->offset + next_child->size <= pos + size)
3278 {
3279 if (next_child->offset != covered
3280 || !is_gimple_reg_type (next_child->type))
3281 return TOTAL_FLD_FAILED;
3282
3283 covered += next_child->size;
3284 *last_seen_sibling = next_child;
3285 next_child = next_child->next_sibling;
3286 skipping = true;
3287 }
3288
3289 if (skipping)
3290 {
3291 if (covered != pos + size)
3292 return TOTAL_FLD_FAILED;
3293 else
3294 return TOTAL_FLD_DONE;
3295 }
3296 }
3297
3298 return TOTAL_FLD_CREATE;
3299 }
3300
3301 /* Go over sub-tree rooted in ROOT and attempt to create scalar accesses
3302 spanning all uncovered areas covered by ROOT, return false if the attempt
3303 failed. All created accesses will have grp_unscalarizable_region set (and
3304 should be ignored if the function returns false). */
3305
3306 static bool
totally_scalarize_subtree(struct access * root)3307 totally_scalarize_subtree (struct access *root)
3308 {
3309 gcc_checking_assert (!root->grp_unscalarizable_region);
3310 gcc_checking_assert (!is_gimple_reg_type (root->type));
3311
3312 struct access *last_seen_sibling = NULL;
3313
3314 switch (TREE_CODE (root->type))
3315 {
3316 case RECORD_TYPE:
3317 for (tree fld = TYPE_FIELDS (root->type); fld; fld = DECL_CHAIN (fld))
3318 if (TREE_CODE (fld) == FIELD_DECL)
3319 {
3320 tree ft = TREE_TYPE (fld);
3321 HOST_WIDE_INT fsize = tree_to_uhwi (DECL_SIZE (fld));
3322 if (!fsize)
3323 continue;
3324
3325 HOST_WIDE_INT pos = root->offset + int_bit_position (fld);
3326 if (pos + fsize > root->offset + root->size)
3327 return false;
3328 enum total_sra_field_state
3329 state = total_should_skip_creating_access (root,
3330 &last_seen_sibling,
3331 ft, pos, fsize);
3332 switch (state)
3333 {
3334 case TOTAL_FLD_FAILED:
3335 return false;
3336 case TOTAL_FLD_DONE:
3337 continue;
3338 case TOTAL_FLD_CREATE:
3339 break;
3340 default:
3341 gcc_unreachable ();
3342 }
3343
3344 struct access **p = (last_seen_sibling
3345 ? &last_seen_sibling->next_sibling
3346 : &root->first_child);
3347 tree nref = build3 (COMPONENT_REF, ft, root->expr, fld, NULL_TREE);
3348 struct access *new_child
3349 = create_total_access_and_reshape (root, pos, fsize, ft, nref, p);
3350 if (!new_child)
3351 return false;
3352
3353 if (!is_gimple_reg_type (ft)
3354 && !totally_scalarize_subtree (new_child))
3355 return false;
3356 last_seen_sibling = new_child;
3357 }
3358 break;
3359 case ARRAY_TYPE:
3360 {
3361 tree elemtype = TREE_TYPE (root->type);
3362 tree elem_size = TYPE_SIZE (elemtype);
3363 gcc_assert (elem_size && tree_fits_shwi_p (elem_size));
3364 HOST_WIDE_INT el_size = tree_to_shwi (elem_size);
3365 gcc_assert (el_size > 0);
3366
3367 tree minidx = TYPE_MIN_VALUE (TYPE_DOMAIN (root->type));
3368 gcc_assert (TREE_CODE (minidx) == INTEGER_CST);
3369 tree maxidx = TYPE_MAX_VALUE (TYPE_DOMAIN (root->type));
3370 /* Skip (some) zero-length arrays; others have MAXIDX == MINIDX - 1. */
3371 if (!maxidx)
3372 goto out;
3373 gcc_assert (TREE_CODE (maxidx) == INTEGER_CST);
3374 tree domain = TYPE_DOMAIN (root->type);
3375 /* MINIDX and MAXIDX are inclusive, and must be interpreted in
3376 DOMAIN (e.g. signed int, whereas min/max may be size_int). */
3377 offset_int idx = wi::to_offset (minidx);
3378 offset_int max = wi::to_offset (maxidx);
3379 if (!TYPE_UNSIGNED (domain))
3380 {
3381 idx = wi::sext (idx, TYPE_PRECISION (domain));
3382 max = wi::sext (max, TYPE_PRECISION (domain));
3383 }
3384 for (HOST_WIDE_INT pos = root->offset;
3385 idx <= max;
3386 pos += el_size, ++idx)
3387 {
3388 enum total_sra_field_state
3389 state = total_should_skip_creating_access (root,
3390 &last_seen_sibling,
3391 elemtype, pos,
3392 el_size);
3393 switch (state)
3394 {
3395 case TOTAL_FLD_FAILED:
3396 return false;
3397 case TOTAL_FLD_DONE:
3398 continue;
3399 case TOTAL_FLD_CREATE:
3400 break;
3401 default:
3402 gcc_unreachable ();
3403 }
3404
3405 struct access **p = (last_seen_sibling
3406 ? &last_seen_sibling->next_sibling
3407 : &root->first_child);
3408 tree nref = build4 (ARRAY_REF, elemtype, root->expr,
3409 wide_int_to_tree (domain, idx),
3410 NULL_TREE, NULL_TREE);
3411 struct access *new_child
3412 = create_total_access_and_reshape (root, pos, el_size, elemtype,
3413 nref, p);
3414 if (!new_child)
3415 return false;
3416
3417 if (!is_gimple_reg_type (elemtype)
3418 && !totally_scalarize_subtree (new_child))
3419 return false;
3420 last_seen_sibling = new_child;
3421 }
3422 }
3423 break;
3424 default:
3425 gcc_unreachable ();
3426 }
3427
3428 out:
3429 return true;
3430 }
3431
3432 /* Go through all accesses collected throughout the (intraprocedural) analysis
3433 stage, exclude overlapping ones, identify representatives and build trees
3434 out of them, making decisions about scalarization on the way. Return true
3435 iff there are any to-be-scalarized variables after this stage. */
3436
3437 static bool
analyze_all_variable_accesses(void)3438 analyze_all_variable_accesses (void)
3439 {
3440 int res = 0;
3441 bitmap tmp = BITMAP_ALLOC (NULL);
3442 bitmap_iterator bi;
3443 unsigned i;
3444
3445 bitmap_copy (tmp, candidate_bitmap);
3446 EXECUTE_IF_SET_IN_BITMAP (tmp, 0, i, bi)
3447 {
3448 tree var = candidate (i);
3449 struct access *access;
3450
3451 access = sort_and_splice_var_accesses (var);
3452 if (!access || !build_access_trees (access))
3453 disqualify_candidate (var,
3454 "No or inhibitingly overlapping accesses.");
3455 }
3456
3457 propagate_all_subaccesses ();
3458
3459 bool optimize_speed_p = !optimize_function_for_size_p (cfun);
3460 /* If the user didn't set PARAM_SRA_MAX_SCALARIZATION_SIZE_<...>,
3461 fall back to a target default. */
3462 unsigned HOST_WIDE_INT max_scalarization_size
3463 = get_move_ratio (optimize_speed_p) * UNITS_PER_WORD;
3464
3465 if (optimize_speed_p)
3466 {
3467 if (OPTION_SET_P (param_sra_max_scalarization_size_speed))
3468 max_scalarization_size = param_sra_max_scalarization_size_speed;
3469 }
3470 else
3471 {
3472 if (OPTION_SET_P (param_sra_max_scalarization_size_size))
3473 max_scalarization_size = param_sra_max_scalarization_size_size;
3474 }
3475 max_scalarization_size *= BITS_PER_UNIT;
3476
3477 EXECUTE_IF_SET_IN_BITMAP (candidate_bitmap, 0, i, bi)
3478 if (bitmap_bit_p (should_scalarize_away_bitmap, i)
3479 && !bitmap_bit_p (cannot_scalarize_away_bitmap, i))
3480 {
3481 tree var = candidate (i);
3482 if (!VAR_P (var))
3483 continue;
3484
3485 if (tree_to_uhwi (TYPE_SIZE (TREE_TYPE (var))) > max_scalarization_size)
3486 {
3487 if (dump_file && (dump_flags & TDF_DETAILS))
3488 {
3489 fprintf (dump_file, "Too big to totally scalarize: ");
3490 print_generic_expr (dump_file, var);
3491 fprintf (dump_file, " (UID: %u)\n", DECL_UID (var));
3492 }
3493 continue;
3494 }
3495
3496 bool all_types_ok = true;
3497 for (struct access *access = get_first_repr_for_decl (var);
3498 access;
3499 access = access->next_grp)
3500 if (!can_totally_scalarize_forest_p (access)
3501 || !scalarizable_type_p (access->type, constant_decl_p (var)))
3502 {
3503 all_types_ok = false;
3504 break;
3505 }
3506 if (!all_types_ok)
3507 continue;
3508
3509 if (dump_file && (dump_flags & TDF_DETAILS))
3510 {
3511 fprintf (dump_file, "Will attempt to totally scalarize ");
3512 print_generic_expr (dump_file, var);
3513 fprintf (dump_file, " (UID: %u): \n", DECL_UID (var));
3514 }
3515 bool scalarized = true;
3516 for (struct access *access = get_first_repr_for_decl (var);
3517 access;
3518 access = access->next_grp)
3519 if (!is_gimple_reg_type (access->type)
3520 && !totally_scalarize_subtree (access))
3521 {
3522 scalarized = false;
3523 break;
3524 }
3525
3526 if (scalarized)
3527 for (struct access *access = get_first_repr_for_decl (var);
3528 access;
3529 access = access->next_grp)
3530 access->grp_total_scalarization = true;
3531 }
3532
3533 if (flag_checking)
3534 verify_all_sra_access_forests ();
3535
3536 bitmap_copy (tmp, candidate_bitmap);
3537 EXECUTE_IF_SET_IN_BITMAP (tmp, 0, i, bi)
3538 {
3539 tree var = candidate (i);
3540 struct access *access = get_first_repr_for_decl (var);
3541
3542 if (analyze_access_trees (access))
3543 {
3544 res++;
3545 if (dump_file && (dump_flags & TDF_DETAILS))
3546 {
3547 fprintf (dump_file, "\nAccess trees for ");
3548 print_generic_expr (dump_file, var);
3549 fprintf (dump_file, " (UID: %u): \n", DECL_UID (var));
3550 dump_access_tree (dump_file, access);
3551 fprintf (dump_file, "\n");
3552 }
3553 }
3554 else
3555 disqualify_candidate (var, "No scalar replacements to be created.");
3556 }
3557
3558 BITMAP_FREE (tmp);
3559
3560 if (res)
3561 {
3562 statistics_counter_event (cfun, "Scalarized aggregates", res);
3563 return true;
3564 }
3565 else
3566 return false;
3567 }
3568
3569 /* Generate statements copying scalar replacements of accesses within a subtree
3570 into or out of AGG. ACCESS, all its children, siblings and their children
3571 are to be processed. AGG is an aggregate type expression (can be a
3572 declaration but does not have to be, it can for example also be a mem_ref or
3573 a series of handled components). TOP_OFFSET is the offset of the processed
3574 subtree which has to be subtracted from offsets of individual accesses to
3575 get corresponding offsets for AGG. If CHUNK_SIZE is non-null, copy only
3576 replacements in the interval <start_offset, start_offset + chunk_size>,
3577 otherwise copy all. GSI is a statement iterator used to place the new
3578 statements. WRITE should be true when the statements should write from AGG
3579 to the replacement and false if vice versa. if INSERT_AFTER is true, new
3580 statements will be added after the current statement in GSI, they will be
3581 added before the statement otherwise. */
3582
3583 static void
generate_subtree_copies(struct access * access,tree agg,HOST_WIDE_INT top_offset,HOST_WIDE_INT start_offset,HOST_WIDE_INT chunk_size,gimple_stmt_iterator * gsi,bool write,bool insert_after,location_t loc)3584 generate_subtree_copies (struct access *access, tree agg,
3585 HOST_WIDE_INT top_offset,
3586 HOST_WIDE_INT start_offset, HOST_WIDE_INT chunk_size,
3587 gimple_stmt_iterator *gsi, bool write,
3588 bool insert_after, location_t loc)
3589 {
3590 /* Never write anything into constant pool decls. See PR70602. */
3591 if (!write && constant_decl_p (agg))
3592 return;
3593 do
3594 {
3595 if (chunk_size && access->offset >= start_offset + chunk_size)
3596 return;
3597
3598 if (access->grp_to_be_replaced
3599 && (chunk_size == 0
3600 || access->offset + access->size > start_offset))
3601 {
3602 tree expr, repl = get_access_replacement (access);
3603 gassign *stmt;
3604
3605 expr = build_ref_for_model (loc, agg, access->offset - top_offset,
3606 access, gsi, insert_after);
3607
3608 if (write)
3609 {
3610 if (access->grp_partial_lhs)
3611 expr = force_gimple_operand_gsi (gsi, expr, true, NULL_TREE,
3612 !insert_after,
3613 insert_after ? GSI_NEW_STMT
3614 : GSI_SAME_STMT);
3615 stmt = gimple_build_assign (repl, expr);
3616 }
3617 else
3618 {
3619 suppress_warning (repl /* Be more selective! */);
3620 if (access->grp_partial_lhs)
3621 repl = force_gimple_operand_gsi (gsi, repl, true, NULL_TREE,
3622 !insert_after,
3623 insert_after ? GSI_NEW_STMT
3624 : GSI_SAME_STMT);
3625 stmt = gimple_build_assign (expr, repl);
3626 }
3627 gimple_set_location (stmt, loc);
3628
3629 if (insert_after)
3630 gsi_insert_after (gsi, stmt, GSI_NEW_STMT);
3631 else
3632 gsi_insert_before (gsi, stmt, GSI_SAME_STMT);
3633 update_stmt (stmt);
3634 sra_stats.subtree_copies++;
3635 }
3636 else if (write
3637 && access->grp_to_be_debug_replaced
3638 && (chunk_size == 0
3639 || access->offset + access->size > start_offset))
3640 {
3641 gdebug *ds;
3642 tree drhs = build_debug_ref_for_model (loc, agg,
3643 access->offset - top_offset,
3644 access);
3645 ds = gimple_build_debug_bind (get_access_replacement (access),
3646 drhs, gsi_stmt (*gsi));
3647 if (insert_after)
3648 gsi_insert_after (gsi, ds, GSI_NEW_STMT);
3649 else
3650 gsi_insert_before (gsi, ds, GSI_SAME_STMT);
3651 }
3652
3653 if (access->first_child)
3654 generate_subtree_copies (access->first_child, agg, top_offset,
3655 start_offset, chunk_size, gsi,
3656 write, insert_after, loc);
3657
3658 access = access->next_sibling;
3659 }
3660 while (access);
3661 }
3662
3663 /* Assign zero to all scalar replacements in an access subtree. ACCESS is the
3664 root of the subtree to be processed. GSI is the statement iterator used
3665 for inserting statements which are added after the current statement if
3666 INSERT_AFTER is true or before it otherwise. */
3667
3668 static void
init_subtree_with_zero(struct access * access,gimple_stmt_iterator * gsi,bool insert_after,location_t loc)3669 init_subtree_with_zero (struct access *access, gimple_stmt_iterator *gsi,
3670 bool insert_after, location_t loc)
3671
3672 {
3673 struct access *child;
3674
3675 if (access->grp_to_be_replaced)
3676 {
3677 gassign *stmt;
3678
3679 stmt = gimple_build_assign (get_access_replacement (access),
3680 build_zero_cst (access->type));
3681 if (insert_after)
3682 gsi_insert_after (gsi, stmt, GSI_NEW_STMT);
3683 else
3684 gsi_insert_before (gsi, stmt, GSI_SAME_STMT);
3685 update_stmt (stmt);
3686 gimple_set_location (stmt, loc);
3687 }
3688 else if (access->grp_to_be_debug_replaced)
3689 {
3690 gdebug *ds
3691 = gimple_build_debug_bind (get_access_replacement (access),
3692 build_zero_cst (access->type),
3693 gsi_stmt (*gsi));
3694 if (insert_after)
3695 gsi_insert_after (gsi, ds, GSI_NEW_STMT);
3696 else
3697 gsi_insert_before (gsi, ds, GSI_SAME_STMT);
3698 }
3699
3700 for (child = access->first_child; child; child = child->next_sibling)
3701 init_subtree_with_zero (child, gsi, insert_after, loc);
3702 }
3703
3704 /* Clobber all scalar replacements in an access subtree. ACCESS is the
3705 root of the subtree to be processed. GSI is the statement iterator used
3706 for inserting statements which are added after the current statement if
3707 INSERT_AFTER is true or before it otherwise. */
3708
3709 static void
clobber_subtree(struct access * access,gimple_stmt_iterator * gsi,bool insert_after,location_t loc)3710 clobber_subtree (struct access *access, gimple_stmt_iterator *gsi,
3711 bool insert_after, location_t loc)
3712
3713 {
3714 struct access *child;
3715
3716 if (access->grp_to_be_replaced)
3717 {
3718 tree rep = get_access_replacement (access);
3719 tree clobber = build_clobber (access->type);
3720 gimple *stmt = gimple_build_assign (rep, clobber);
3721
3722 if (insert_after)
3723 gsi_insert_after (gsi, stmt, GSI_NEW_STMT);
3724 else
3725 gsi_insert_before (gsi, stmt, GSI_SAME_STMT);
3726 update_stmt (stmt);
3727 gimple_set_location (stmt, loc);
3728 }
3729
3730 for (child = access->first_child; child; child = child->next_sibling)
3731 clobber_subtree (child, gsi, insert_after, loc);
3732 }
3733
3734 /* Search for an access representative for the given expression EXPR and
3735 return it or NULL if it cannot be found. */
3736
3737 static struct access *
get_access_for_expr(tree expr)3738 get_access_for_expr (tree expr)
3739 {
3740 poly_int64 poffset, psize, pmax_size;
3741 HOST_WIDE_INT offset, max_size;
3742 tree base;
3743 bool reverse;
3744
3745 /* FIXME: This should not be necessary but Ada produces V_C_Es with a type of
3746 a different size than the size of its argument and we need the latter
3747 one. */
3748 if (TREE_CODE (expr) == VIEW_CONVERT_EXPR)
3749 expr = TREE_OPERAND (expr, 0);
3750
3751 base = get_ref_base_and_extent (expr, &poffset, &psize, &pmax_size,
3752 &reverse);
3753 if (!known_size_p (pmax_size)
3754 || !pmax_size.is_constant (&max_size)
3755 || !poffset.is_constant (&offset)
3756 || !DECL_P (base))
3757 return NULL;
3758
3759 if (tree basesize = DECL_SIZE (base))
3760 {
3761 poly_int64 sz;
3762 if (offset < 0
3763 || !poly_int_tree_p (basesize, &sz)
3764 || known_le (sz, offset))
3765 return NULL;
3766 }
3767
3768 if (max_size == 0
3769 || !bitmap_bit_p (candidate_bitmap, DECL_UID (base)))
3770 return NULL;
3771
3772 return get_var_base_offset_size_access (base, offset, max_size);
3773 }
3774
3775 /* Replace the expression EXPR with a scalar replacement if there is one and
3776 generate other statements to do type conversion or subtree copying if
3777 necessary. GSI is used to place newly created statements, WRITE is true if
3778 the expression is being written to (it is on a LHS of a statement or output
3779 in an assembly statement). */
3780
3781 static bool
sra_modify_expr(tree * expr,gimple_stmt_iterator * gsi,bool write)3782 sra_modify_expr (tree *expr, gimple_stmt_iterator *gsi, bool write)
3783 {
3784 location_t loc;
3785 struct access *access;
3786 tree type, bfr, orig_expr;
3787 bool partial_cplx_access = false;
3788
3789 if (TREE_CODE (*expr) == BIT_FIELD_REF)
3790 {
3791 bfr = *expr;
3792 expr = &TREE_OPERAND (*expr, 0);
3793 }
3794 else
3795 bfr = NULL_TREE;
3796
3797 if (TREE_CODE (*expr) == REALPART_EXPR || TREE_CODE (*expr) == IMAGPART_EXPR)
3798 {
3799 expr = &TREE_OPERAND (*expr, 0);
3800 partial_cplx_access = true;
3801 }
3802 access = get_access_for_expr (*expr);
3803 if (!access)
3804 return false;
3805 type = TREE_TYPE (*expr);
3806 orig_expr = *expr;
3807
3808 loc = gimple_location (gsi_stmt (*gsi));
3809 gimple_stmt_iterator alt_gsi = gsi_none ();
3810 if (write && stmt_ends_bb_p (gsi_stmt (*gsi)))
3811 {
3812 alt_gsi = gsi_start_edge (single_non_eh_succ (gsi_bb (*gsi)));
3813 gsi = &alt_gsi;
3814 }
3815
3816 if (access->grp_to_be_replaced)
3817 {
3818 tree repl = get_access_replacement (access);
3819 /* If we replace a non-register typed access simply use the original
3820 access expression to extract the scalar component afterwards.
3821 This happens if scalarizing a function return value or parameter
3822 like in gcc.c-torture/execute/20041124-1.c, 20050316-1.c and
3823 gcc.c-torture/compile/20011217-1.c.
3824
3825 We also want to use this when accessing a complex or vector which can
3826 be accessed as a different type too, potentially creating a need for
3827 type conversion (see PR42196) and when scalarized unions are involved
3828 in assembler statements (see PR42398). */
3829 if (!bfr && !useless_type_conversion_p (type, access->type))
3830 {
3831 tree ref;
3832
3833 ref = build_ref_for_model (loc, orig_expr, 0, access, gsi, false);
3834
3835 if (partial_cplx_access)
3836 {
3837 /* VIEW_CONVERT_EXPRs in partial complex access are always fine in
3838 the case of a write because in such case the replacement cannot
3839 be a gimple register. In the case of a load, we have to
3840 differentiate in between a register an non-register
3841 replacement. */
3842 tree t = build1 (VIEW_CONVERT_EXPR, type, repl);
3843 gcc_checking_assert (!write || access->grp_partial_lhs);
3844 if (!access->grp_partial_lhs)
3845 {
3846 tree tmp = make_ssa_name (type);
3847 gassign *stmt = gimple_build_assign (tmp, t);
3848 /* This is always a read. */
3849 gsi_insert_before (gsi, stmt, GSI_SAME_STMT);
3850 t = tmp;
3851 }
3852 *expr = t;
3853 }
3854 else if (write)
3855 {
3856 gassign *stmt;
3857
3858 if (access->grp_partial_lhs)
3859 ref = force_gimple_operand_gsi (gsi, ref, true, NULL_TREE,
3860 false, GSI_NEW_STMT);
3861 stmt = gimple_build_assign (repl, ref);
3862 gimple_set_location (stmt, loc);
3863 gsi_insert_after (gsi, stmt, GSI_NEW_STMT);
3864 }
3865 else
3866 {
3867 gassign *stmt;
3868
3869 if (access->grp_partial_lhs)
3870 repl = force_gimple_operand_gsi (gsi, repl, true, NULL_TREE,
3871 true, GSI_SAME_STMT);
3872 stmt = gimple_build_assign (ref, repl);
3873 gimple_set_location (stmt, loc);
3874 gsi_insert_before (gsi, stmt, GSI_SAME_STMT);
3875 }
3876 }
3877 else
3878 {
3879 /* If we are going to replace a scalar field in a structure with
3880 reverse storage order by a stand-alone scalar, we are going to
3881 effectively byte-swap the scalar and we also need to byte-swap
3882 the portion of it represented by the bit-field. */
3883 if (bfr && REF_REVERSE_STORAGE_ORDER (bfr))
3884 {
3885 REF_REVERSE_STORAGE_ORDER (bfr) = 0;
3886 TREE_OPERAND (bfr, 2)
3887 = size_binop (MINUS_EXPR, TYPE_SIZE (TREE_TYPE (repl)),
3888 size_binop (PLUS_EXPR, TREE_OPERAND (bfr, 1),
3889 TREE_OPERAND (bfr, 2)));
3890 }
3891
3892 *expr = repl;
3893 }
3894
3895 sra_stats.exprs++;
3896 }
3897 else if (write && access->grp_to_be_debug_replaced)
3898 {
3899 gdebug *ds = gimple_build_debug_bind (get_access_replacement (access),
3900 NULL_TREE,
3901 gsi_stmt (*gsi));
3902 gsi_insert_after (gsi, ds, GSI_NEW_STMT);
3903 }
3904
3905 if (access->first_child && !TREE_READONLY (access->base))
3906 {
3907 HOST_WIDE_INT start_offset, chunk_size;
3908 if (bfr
3909 && tree_fits_uhwi_p (TREE_OPERAND (bfr, 1))
3910 && tree_fits_uhwi_p (TREE_OPERAND (bfr, 2)))
3911 {
3912 chunk_size = tree_to_uhwi (TREE_OPERAND (bfr, 1));
3913 start_offset = access->offset
3914 + tree_to_uhwi (TREE_OPERAND (bfr, 2));
3915 }
3916 else
3917 start_offset = chunk_size = 0;
3918
3919 generate_subtree_copies (access->first_child, orig_expr, access->offset,
3920 start_offset, chunk_size, gsi, write, write,
3921 loc);
3922 }
3923 return true;
3924 }
3925
3926 /* Where scalar replacements of the RHS have been written to when a replacement
3927 of a LHS of an assigments cannot be direclty loaded from a replacement of
3928 the RHS. */
3929 enum unscalarized_data_handling { SRA_UDH_NONE, /* Nothing done so far. */
3930 SRA_UDH_RIGHT, /* Data flushed to the RHS. */
3931 SRA_UDH_LEFT }; /* Data flushed to the LHS. */
3932
3933 struct subreplacement_assignment_data
3934 {
3935 /* Offset of the access representing the lhs of the assignment. */
3936 HOST_WIDE_INT left_offset;
3937
3938 /* LHS and RHS of the original assignment. */
3939 tree assignment_lhs, assignment_rhs;
3940
3941 /* Access representing the rhs of the whole assignment. */
3942 struct access *top_racc;
3943
3944 /* Stmt iterator used for statement insertions after the original assignment.
3945 It points to the main GSI used to traverse a BB during function body
3946 modification. */
3947 gimple_stmt_iterator *new_gsi;
3948
3949 /* Stmt iterator used for statement insertions before the original
3950 assignment. Keeps on pointing to the original statement. */
3951 gimple_stmt_iterator old_gsi;
3952
3953 /* Location of the assignment. */
3954 location_t loc;
3955
3956 /* Keeps the information whether we have needed to refresh replacements of
3957 the LHS and from which side of the assignments this takes place. */
3958 enum unscalarized_data_handling refreshed;
3959 };
3960
3961 /* Store all replacements in the access tree rooted in TOP_RACC either to their
3962 base aggregate if there are unscalarized data or directly to LHS of the
3963 statement that is pointed to by GSI otherwise. */
3964
3965 static void
handle_unscalarized_data_in_subtree(struct subreplacement_assignment_data * sad)3966 handle_unscalarized_data_in_subtree (struct subreplacement_assignment_data *sad)
3967 {
3968 tree src;
3969 /* If the RHS is a load from a constant, we do not need to (and must not)
3970 flush replacements to it and can use it directly as if we did. */
3971 if (TREE_READONLY (sad->top_racc->base))
3972 {
3973 sad->refreshed = SRA_UDH_RIGHT;
3974 return;
3975 }
3976 if (sad->top_racc->grp_unscalarized_data)
3977 {
3978 src = sad->assignment_rhs;
3979 sad->refreshed = SRA_UDH_RIGHT;
3980 }
3981 else
3982 {
3983 src = sad->assignment_lhs;
3984 sad->refreshed = SRA_UDH_LEFT;
3985 }
3986 generate_subtree_copies (sad->top_racc->first_child, src,
3987 sad->top_racc->offset, 0, 0,
3988 &sad->old_gsi, false, false, sad->loc);
3989 }
3990
3991 /* Try to generate statements to load all sub-replacements in an access subtree
3992 formed by children of LACC from scalar replacements in the SAD->top_racc
3993 subtree. If that is not possible, refresh the SAD->top_racc base aggregate
3994 and load the accesses from it. */
3995
3996 static void
load_assign_lhs_subreplacements(struct access * lacc,struct subreplacement_assignment_data * sad)3997 load_assign_lhs_subreplacements (struct access *lacc,
3998 struct subreplacement_assignment_data *sad)
3999 {
4000 for (lacc = lacc->first_child; lacc; lacc = lacc->next_sibling)
4001 {
4002 HOST_WIDE_INT offset;
4003 offset = lacc->offset - sad->left_offset + sad->top_racc->offset;
4004
4005 if (lacc->grp_to_be_replaced)
4006 {
4007 struct access *racc;
4008 gassign *stmt;
4009 tree rhs;
4010
4011 racc = find_access_in_subtree (sad->top_racc, offset, lacc->size);
4012 if (racc && racc->grp_to_be_replaced)
4013 {
4014 rhs = get_access_replacement (racc);
4015 if (!useless_type_conversion_p (lacc->type, racc->type))
4016 rhs = fold_build1_loc (sad->loc, VIEW_CONVERT_EXPR,
4017 lacc->type, rhs);
4018
4019 if (racc->grp_partial_lhs && lacc->grp_partial_lhs)
4020 rhs = force_gimple_operand_gsi (&sad->old_gsi, rhs, true,
4021 NULL_TREE, true, GSI_SAME_STMT);
4022 }
4023 else
4024 {
4025 /* No suitable access on the right hand side, need to load from
4026 the aggregate. See if we have to update it first... */
4027 if (sad->refreshed == SRA_UDH_NONE)
4028 handle_unscalarized_data_in_subtree (sad);
4029
4030 if (sad->refreshed == SRA_UDH_LEFT)
4031 rhs = build_ref_for_model (sad->loc, sad->assignment_lhs,
4032 lacc->offset - sad->left_offset,
4033 lacc, sad->new_gsi, true);
4034 else
4035 rhs = build_ref_for_model (sad->loc, sad->assignment_rhs,
4036 lacc->offset - sad->left_offset,
4037 lacc, sad->new_gsi, true);
4038 if (lacc->grp_partial_lhs)
4039 rhs = force_gimple_operand_gsi (sad->new_gsi,
4040 rhs, true, NULL_TREE,
4041 false, GSI_NEW_STMT);
4042 }
4043
4044 stmt = gimple_build_assign (get_access_replacement (lacc), rhs);
4045 gsi_insert_after (sad->new_gsi, stmt, GSI_NEW_STMT);
4046 gimple_set_location (stmt, sad->loc);
4047 update_stmt (stmt);
4048 sra_stats.subreplacements++;
4049 }
4050 else
4051 {
4052 if (sad->refreshed == SRA_UDH_NONE
4053 && lacc->grp_read && !lacc->grp_covered)
4054 handle_unscalarized_data_in_subtree (sad);
4055
4056 if (lacc && lacc->grp_to_be_debug_replaced)
4057 {
4058 gdebug *ds;
4059 tree drhs;
4060 struct access *racc = find_access_in_subtree (sad->top_racc,
4061 offset,
4062 lacc->size);
4063
4064 if (racc && racc->grp_to_be_replaced)
4065 {
4066 if (racc->grp_write || constant_decl_p (racc->base))
4067 drhs = get_access_replacement (racc);
4068 else
4069 drhs = NULL;
4070 }
4071 else if (sad->refreshed == SRA_UDH_LEFT)
4072 drhs = build_debug_ref_for_model (sad->loc, lacc->base,
4073 lacc->offset, lacc);
4074 else if (sad->refreshed == SRA_UDH_RIGHT)
4075 drhs = build_debug_ref_for_model (sad->loc, sad->top_racc->base,
4076 offset, lacc);
4077 else
4078 drhs = NULL_TREE;
4079 if (drhs
4080 && !useless_type_conversion_p (lacc->type, TREE_TYPE (drhs)))
4081 drhs = fold_build1_loc (sad->loc, VIEW_CONVERT_EXPR,
4082 lacc->type, drhs);
4083 ds = gimple_build_debug_bind (get_access_replacement (lacc),
4084 drhs, gsi_stmt (sad->old_gsi));
4085 gsi_insert_after (sad->new_gsi, ds, GSI_NEW_STMT);
4086 }
4087 }
4088
4089 if (lacc->first_child)
4090 load_assign_lhs_subreplacements (lacc, sad);
4091 }
4092 }
4093
4094 /* Result code for SRA assignment modification. */
4095 enum assignment_mod_result { SRA_AM_NONE, /* nothing done for the stmt */
4096 SRA_AM_MODIFIED, /* stmt changed but not
4097 removed */
4098 SRA_AM_REMOVED }; /* stmt eliminated */
4099
4100 /* Modify assignments with a CONSTRUCTOR on their RHS. STMT contains a pointer
4101 to the assignment and GSI is the statement iterator pointing at it. Returns
4102 the same values as sra_modify_assign. */
4103
4104 static enum assignment_mod_result
sra_modify_constructor_assign(gimple * stmt,gimple_stmt_iterator * gsi)4105 sra_modify_constructor_assign (gimple *stmt, gimple_stmt_iterator *gsi)
4106 {
4107 tree lhs = gimple_assign_lhs (stmt);
4108 struct access *acc = get_access_for_expr (lhs);
4109 if (!acc)
4110 return SRA_AM_NONE;
4111 location_t loc = gimple_location (stmt);
4112
4113 if (gimple_clobber_p (stmt))
4114 {
4115 /* Clobber the replacement variable. */
4116 clobber_subtree (acc, gsi, !acc->grp_covered, loc);
4117 /* Remove clobbers of fully scalarized variables, they are dead. */
4118 if (acc->grp_covered)
4119 {
4120 unlink_stmt_vdef (stmt);
4121 gsi_remove (gsi, true);
4122 release_defs (stmt);
4123 return SRA_AM_REMOVED;
4124 }
4125 else
4126 return SRA_AM_MODIFIED;
4127 }
4128
4129 if (CONSTRUCTOR_NELTS (gimple_assign_rhs1 (stmt)) > 0)
4130 {
4131 /* I have never seen this code path trigger but if it can happen the
4132 following should handle it gracefully. */
4133 if (access_has_children_p (acc))
4134 generate_subtree_copies (acc->first_child, lhs, acc->offset, 0, 0, gsi,
4135 true, true, loc);
4136 return SRA_AM_MODIFIED;
4137 }
4138
4139 if (acc->grp_covered)
4140 {
4141 init_subtree_with_zero (acc, gsi, false, loc);
4142 unlink_stmt_vdef (stmt);
4143 gsi_remove (gsi, true);
4144 release_defs (stmt);
4145 return SRA_AM_REMOVED;
4146 }
4147 else
4148 {
4149 init_subtree_with_zero (acc, gsi, true, loc);
4150 return SRA_AM_MODIFIED;
4151 }
4152 }
4153
4154 /* Create and return a new suitable default definition SSA_NAME for RACC which
4155 is an access describing an uninitialized part of an aggregate that is being
4156 loaded. REG_TREE is used instead of the actual RACC type if that is not of
4157 a gimple register type. */
4158
4159 static tree
get_repl_default_def_ssa_name(struct access * racc,tree reg_type)4160 get_repl_default_def_ssa_name (struct access *racc, tree reg_type)
4161 {
4162 gcc_checking_assert (!racc->grp_to_be_replaced
4163 && !racc->grp_to_be_debug_replaced);
4164 if (!racc->replacement_decl)
4165 racc->replacement_decl = create_access_replacement (racc, reg_type);
4166 return get_or_create_ssa_default_def (cfun, racc->replacement_decl);
4167 }
4168
4169
4170 /* Generate statements to call .DEFERRED_INIT to initialize scalar replacements
4171 of accesses within a subtree ACCESS; all its children, siblings and their
4172 children are to be processed.
4173 GSI is a statement iterator used to place the new statements. */
4174 static void
generate_subtree_deferred_init(struct access * access,tree init_type,tree decl_name,gimple_stmt_iterator * gsi,location_t loc)4175 generate_subtree_deferred_init (struct access *access,
4176 tree init_type,
4177 tree decl_name,
4178 gimple_stmt_iterator *gsi,
4179 location_t loc)
4180 {
4181 do
4182 {
4183 if (access->grp_to_be_replaced)
4184 {
4185 tree repl = get_access_replacement (access);
4186 gimple *call
4187 = gimple_build_call_internal (IFN_DEFERRED_INIT, 3,
4188 TYPE_SIZE_UNIT (TREE_TYPE (repl)),
4189 init_type, decl_name);
4190 gimple_call_set_lhs (call, repl);
4191 gsi_insert_before (gsi, call, GSI_SAME_STMT);
4192 update_stmt (call);
4193 gimple_set_location (call, loc);
4194 sra_stats.subtree_deferred_init++;
4195 }
4196 if (access->first_child)
4197 generate_subtree_deferred_init (access->first_child, init_type,
4198 decl_name, gsi, loc);
4199
4200 access = access ->next_sibling;
4201 }
4202 while (access);
4203 }
4204
4205 /* For a call to .DEFERRED_INIT:
4206 var = .DEFERRED_INIT (size_of_var, init_type, name_of_var);
4207 examine the LHS variable VAR and replace it with a scalar replacement if
4208 there is one, also replace the RHS call to a call to .DEFERRED_INIT of
4209 the corresponding scalar relacement variable. Examine the subtree and
4210 do the scalar replacements in the subtree too. STMT is the call, GSI is
4211 the statment iterator to place newly created statement. */
4212
4213 static enum assignment_mod_result
sra_modify_deferred_init(gimple * stmt,gimple_stmt_iterator * gsi)4214 sra_modify_deferred_init (gimple *stmt, gimple_stmt_iterator *gsi)
4215 {
4216 tree lhs = gimple_call_lhs (stmt);
4217 tree init_type = gimple_call_arg (stmt, 1);
4218 tree decl_name = gimple_call_arg (stmt, 2);
4219
4220 struct access *lhs_access = get_access_for_expr (lhs);
4221 if (!lhs_access)
4222 return SRA_AM_NONE;
4223
4224 location_t loc = gimple_location (stmt);
4225
4226 if (lhs_access->grp_to_be_replaced)
4227 {
4228 tree lhs_repl = get_access_replacement (lhs_access);
4229 gimple_call_set_lhs (stmt, lhs_repl);
4230 tree arg0_repl = TYPE_SIZE_UNIT (TREE_TYPE (lhs_repl));
4231 gimple_call_set_arg (stmt, 0, arg0_repl);
4232 sra_stats.deferred_init++;
4233 gcc_assert (!lhs_access->first_child);
4234 return SRA_AM_MODIFIED;
4235 }
4236
4237 if (lhs_access->first_child)
4238 generate_subtree_deferred_init (lhs_access->first_child,
4239 init_type, decl_name, gsi, loc);
4240 if (lhs_access->grp_covered)
4241 {
4242 unlink_stmt_vdef (stmt);
4243 gsi_remove (gsi, true);
4244 release_defs (stmt);
4245 return SRA_AM_REMOVED;
4246 }
4247
4248 return SRA_AM_MODIFIED;
4249 }
4250
4251 /* Examine both sides of the assignment statement pointed to by STMT, replace
4252 them with a scalare replacement if there is one and generate copying of
4253 replacements if scalarized aggregates have been used in the assignment. GSI
4254 is used to hold generated statements for type conversions and subtree
4255 copying. */
4256
4257 static enum assignment_mod_result
sra_modify_assign(gimple * stmt,gimple_stmt_iterator * gsi)4258 sra_modify_assign (gimple *stmt, gimple_stmt_iterator *gsi)
4259 {
4260 struct access *lacc, *racc;
4261 tree lhs, rhs;
4262 bool modify_this_stmt = false;
4263 bool force_gimple_rhs = false;
4264 location_t loc;
4265 gimple_stmt_iterator orig_gsi = *gsi;
4266
4267 if (!gimple_assign_single_p (stmt))
4268 return SRA_AM_NONE;
4269 lhs = gimple_assign_lhs (stmt);
4270 rhs = gimple_assign_rhs1 (stmt);
4271
4272 if (TREE_CODE (rhs) == CONSTRUCTOR)
4273 return sra_modify_constructor_assign (stmt, gsi);
4274
4275 if (TREE_CODE (rhs) == REALPART_EXPR || TREE_CODE (lhs) == REALPART_EXPR
4276 || TREE_CODE (rhs) == IMAGPART_EXPR || TREE_CODE (lhs) == IMAGPART_EXPR
4277 || TREE_CODE (rhs) == BIT_FIELD_REF || TREE_CODE (lhs) == BIT_FIELD_REF)
4278 {
4279 modify_this_stmt = sra_modify_expr (gimple_assign_rhs1_ptr (stmt),
4280 gsi, false);
4281 modify_this_stmt |= sra_modify_expr (gimple_assign_lhs_ptr (stmt),
4282 gsi, true);
4283 return modify_this_stmt ? SRA_AM_MODIFIED : SRA_AM_NONE;
4284 }
4285
4286 lacc = get_access_for_expr (lhs);
4287 racc = get_access_for_expr (rhs);
4288 if (!lacc && !racc)
4289 return SRA_AM_NONE;
4290 /* Avoid modifying initializations of constant-pool replacements. */
4291 if (racc && (racc->replacement_decl == lhs))
4292 return SRA_AM_NONE;
4293
4294 loc = gimple_location (stmt);
4295 if (lacc && lacc->grp_to_be_replaced)
4296 {
4297 lhs = get_access_replacement (lacc);
4298 gimple_assign_set_lhs (stmt, lhs);
4299 modify_this_stmt = true;
4300 if (lacc->grp_partial_lhs)
4301 force_gimple_rhs = true;
4302 sra_stats.exprs++;
4303 }
4304
4305 if (racc && racc->grp_to_be_replaced)
4306 {
4307 rhs = get_access_replacement (racc);
4308 modify_this_stmt = true;
4309 if (racc->grp_partial_lhs)
4310 force_gimple_rhs = true;
4311 sra_stats.exprs++;
4312 }
4313 else if (racc
4314 && !racc->grp_unscalarized_data
4315 && !racc->grp_unscalarizable_region
4316 && TREE_CODE (lhs) == SSA_NAME
4317 && !access_has_replacements_p (racc))
4318 {
4319 rhs = get_repl_default_def_ssa_name (racc, TREE_TYPE (lhs));
4320 modify_this_stmt = true;
4321 sra_stats.exprs++;
4322 }
4323
4324 if (modify_this_stmt
4325 && !useless_type_conversion_p (TREE_TYPE (lhs), TREE_TYPE (rhs)))
4326 {
4327 /* If we can avoid creating a VIEW_CONVERT_EXPR, then do so.
4328 ??? This should move to fold_stmt which we simply should
4329 call after building a VIEW_CONVERT_EXPR here. */
4330 if (AGGREGATE_TYPE_P (TREE_TYPE (lhs))
4331 && TYPE_REVERSE_STORAGE_ORDER (TREE_TYPE (lhs)) == racc->reverse
4332 && !contains_bitfld_component_ref_p (lhs))
4333 {
4334 lhs = build_ref_for_model (loc, lhs, 0, racc, gsi, false);
4335 gimple_assign_set_lhs (stmt, lhs);
4336 }
4337 else if (lacc
4338 && AGGREGATE_TYPE_P (TREE_TYPE (rhs))
4339 && TYPE_REVERSE_STORAGE_ORDER (TREE_TYPE (rhs)) == lacc->reverse
4340 && !contains_vce_or_bfcref_p (rhs))
4341 rhs = build_ref_for_model (loc, rhs, 0, lacc, gsi, false);
4342
4343 if (!useless_type_conversion_p (TREE_TYPE (lhs), TREE_TYPE (rhs)))
4344 {
4345 rhs = fold_build1_loc (loc, VIEW_CONVERT_EXPR, TREE_TYPE (lhs), rhs);
4346 if (is_gimple_reg_type (TREE_TYPE (lhs))
4347 && TREE_CODE (lhs) != SSA_NAME)
4348 force_gimple_rhs = true;
4349 }
4350 }
4351
4352 if (lacc && lacc->grp_to_be_debug_replaced)
4353 {
4354 tree dlhs = get_access_replacement (lacc);
4355 tree drhs = unshare_expr (rhs);
4356 if (!useless_type_conversion_p (TREE_TYPE (dlhs), TREE_TYPE (drhs)))
4357 {
4358 if (AGGREGATE_TYPE_P (TREE_TYPE (drhs))
4359 && !contains_vce_or_bfcref_p (drhs))
4360 drhs = build_debug_ref_for_model (loc, drhs, 0, lacc);
4361 if (drhs
4362 && !useless_type_conversion_p (TREE_TYPE (dlhs),
4363 TREE_TYPE (drhs)))
4364 drhs = fold_build1_loc (loc, VIEW_CONVERT_EXPR,
4365 TREE_TYPE (dlhs), drhs);
4366 }
4367 gdebug *ds = gimple_build_debug_bind (dlhs, drhs, stmt);
4368 gsi_insert_before (gsi, ds, GSI_SAME_STMT);
4369 }
4370
4371 /* From this point on, the function deals with assignments in between
4372 aggregates when at least one has scalar reductions of some of its
4373 components. There are three possible scenarios: Both the LHS and RHS have
4374 to-be-scalarized components, 2) only the RHS has or 3) only the LHS has.
4375
4376 In the first case, we would like to load the LHS components from RHS
4377 components whenever possible. If that is not possible, we would like to
4378 read it directly from the RHS (after updating it by storing in it its own
4379 components). If there are some necessary unscalarized data in the LHS,
4380 those will be loaded by the original assignment too. If neither of these
4381 cases happen, the original statement can be removed. Most of this is done
4382 by load_assign_lhs_subreplacements.
4383
4384 In the second case, we would like to store all RHS scalarized components
4385 directly into LHS and if they cover the aggregate completely, remove the
4386 statement too. In the third case, we want the LHS components to be loaded
4387 directly from the RHS (DSE will remove the original statement if it
4388 becomes redundant).
4389
4390 This is a bit complex but manageable when types match and when unions do
4391 not cause confusion in a way that we cannot really load a component of LHS
4392 from the RHS or vice versa (the access representing this level can have
4393 subaccesses that are accessible only through a different union field at a
4394 higher level - different from the one used in the examined expression).
4395 Unions are fun.
4396
4397 Therefore, I specially handle a fourth case, happening when there is a
4398 specific type cast or it is impossible to locate a scalarized subaccess on
4399 the other side of the expression. If that happens, I simply "refresh" the
4400 RHS by storing in it is scalarized components leave the original statement
4401 there to do the copying and then load the scalar replacements of the LHS.
4402 This is what the first branch does. */
4403
4404 if (modify_this_stmt
4405 || gimple_has_volatile_ops (stmt)
4406 || contains_vce_or_bfcref_p (rhs)
4407 || contains_vce_or_bfcref_p (lhs)
4408 || stmt_ends_bb_p (stmt))
4409 {
4410 /* No need to copy into a constant, it comes pre-initialized. */
4411 if (access_has_children_p (racc) && !TREE_READONLY (racc->base))
4412 generate_subtree_copies (racc->first_child, rhs, racc->offset, 0, 0,
4413 gsi, false, false, loc);
4414 if (access_has_children_p (lacc))
4415 {
4416 gimple_stmt_iterator alt_gsi = gsi_none ();
4417 if (stmt_ends_bb_p (stmt))
4418 {
4419 alt_gsi = gsi_start_edge (single_non_eh_succ (gsi_bb (*gsi)));
4420 gsi = &alt_gsi;
4421 }
4422 generate_subtree_copies (lacc->first_child, lhs, lacc->offset, 0, 0,
4423 gsi, true, true, loc);
4424 }
4425 sra_stats.separate_lhs_rhs_handling++;
4426
4427 /* This gimplification must be done after generate_subtree_copies,
4428 lest we insert the subtree copies in the middle of the gimplified
4429 sequence. */
4430 if (force_gimple_rhs)
4431 rhs = force_gimple_operand_gsi (&orig_gsi, rhs, true, NULL_TREE,
4432 true, GSI_SAME_STMT);
4433 if (gimple_assign_rhs1 (stmt) != rhs)
4434 {
4435 modify_this_stmt = true;
4436 gimple_assign_set_rhs_from_tree (&orig_gsi, rhs);
4437 gcc_assert (stmt == gsi_stmt (orig_gsi));
4438 }
4439
4440 return modify_this_stmt ? SRA_AM_MODIFIED : SRA_AM_NONE;
4441 }
4442 else
4443 {
4444 if (access_has_children_p (lacc)
4445 && access_has_children_p (racc)
4446 /* When an access represents an unscalarizable region, it usually
4447 represents accesses with variable offset and thus must not be used
4448 to generate new memory accesses. */
4449 && !lacc->grp_unscalarizable_region
4450 && !racc->grp_unscalarizable_region)
4451 {
4452 struct subreplacement_assignment_data sad;
4453
4454 sad.left_offset = lacc->offset;
4455 sad.assignment_lhs = lhs;
4456 sad.assignment_rhs = rhs;
4457 sad.top_racc = racc;
4458 sad.old_gsi = *gsi;
4459 sad.new_gsi = gsi;
4460 sad.loc = gimple_location (stmt);
4461 sad.refreshed = SRA_UDH_NONE;
4462
4463 if (lacc->grp_read && !lacc->grp_covered)
4464 handle_unscalarized_data_in_subtree (&sad);
4465
4466 load_assign_lhs_subreplacements (lacc, &sad);
4467 if (sad.refreshed != SRA_UDH_RIGHT)
4468 {
4469 gsi_next (gsi);
4470 unlink_stmt_vdef (stmt);
4471 gsi_remove (&sad.old_gsi, true);
4472 release_defs (stmt);
4473 sra_stats.deleted++;
4474 return SRA_AM_REMOVED;
4475 }
4476 }
4477 else
4478 {
4479 if (access_has_children_p (racc)
4480 && !racc->grp_unscalarized_data
4481 && TREE_CODE (lhs) != SSA_NAME)
4482 {
4483 if (dump_file)
4484 {
4485 fprintf (dump_file, "Removing load: ");
4486 print_gimple_stmt (dump_file, stmt, 0);
4487 }
4488 generate_subtree_copies (racc->first_child, lhs,
4489 racc->offset, 0, 0, gsi,
4490 false, false, loc);
4491 gcc_assert (stmt == gsi_stmt (*gsi));
4492 unlink_stmt_vdef (stmt);
4493 gsi_remove (gsi, true);
4494 release_defs (stmt);
4495 sra_stats.deleted++;
4496 return SRA_AM_REMOVED;
4497 }
4498 /* Restore the aggregate RHS from its components so the
4499 prevailing aggregate copy does the right thing. */
4500 if (access_has_children_p (racc) && !TREE_READONLY (racc->base))
4501 generate_subtree_copies (racc->first_child, rhs, racc->offset, 0, 0,
4502 gsi, false, false, loc);
4503 /* Re-load the components of the aggregate copy destination.
4504 But use the RHS aggregate to load from to expose more
4505 optimization opportunities. */
4506 if (access_has_children_p (lacc))
4507 generate_subtree_copies (lacc->first_child, rhs, lacc->offset,
4508 0, 0, gsi, true, true, loc);
4509 }
4510
4511 return SRA_AM_NONE;
4512 }
4513 }
4514
4515 /* Set any scalar replacements of values in the constant pool to the initial
4516 value of the constant. (Constant-pool decls like *.LC0 have effectively
4517 been initialized before the program starts, we must do the same for their
4518 replacements.) Thus, we output statements like 'SR.1 = *.LC0[0];' into
4519 the function's entry block. */
4520
4521 static void
initialize_constant_pool_replacements(void)4522 initialize_constant_pool_replacements (void)
4523 {
4524 gimple_seq seq = NULL;
4525 gimple_stmt_iterator gsi = gsi_start (seq);
4526 bitmap_iterator bi;
4527 unsigned i;
4528
4529 EXECUTE_IF_SET_IN_BITMAP (candidate_bitmap, 0, i, bi)
4530 {
4531 tree var = candidate (i);
4532 if (!constant_decl_p (var))
4533 continue;
4534
4535 struct access *access = get_first_repr_for_decl (var);
4536
4537 while (access)
4538 {
4539 if (access->replacement_decl)
4540 {
4541 gassign *stmt
4542 = gimple_build_assign (get_access_replacement (access),
4543 unshare_expr (access->expr));
4544 if (dump_file && (dump_flags & TDF_DETAILS))
4545 {
4546 fprintf (dump_file, "Generating constant initializer: ");
4547 print_gimple_stmt (dump_file, stmt, 0);
4548 fprintf (dump_file, "\n");
4549 }
4550 gsi_insert_after (&gsi, stmt, GSI_NEW_STMT);
4551 update_stmt (stmt);
4552 }
4553
4554 if (access->first_child)
4555 access = access->first_child;
4556 else if (access->next_sibling)
4557 access = access->next_sibling;
4558 else
4559 {
4560 while (access->parent && !access->next_sibling)
4561 access = access->parent;
4562 if (access->next_sibling)
4563 access = access->next_sibling;
4564 else
4565 access = access->next_grp;
4566 }
4567 }
4568 }
4569
4570 seq = gsi_seq (gsi);
4571 if (seq)
4572 gsi_insert_seq_on_edge_immediate (
4573 single_succ_edge (ENTRY_BLOCK_PTR_FOR_FN (cfun)), seq);
4574 }
4575
4576 /* Traverse the function body and all modifications as decided in
4577 analyze_all_variable_accesses. Return true iff the CFG has been
4578 changed. */
4579
4580 static bool
sra_modify_function_body(void)4581 sra_modify_function_body (void)
4582 {
4583 bool cfg_changed = false;
4584 basic_block bb;
4585
4586 initialize_constant_pool_replacements ();
4587
4588 FOR_EACH_BB_FN (bb, cfun)
4589 {
4590 gimple_stmt_iterator gsi = gsi_start_bb (bb);
4591 while (!gsi_end_p (gsi))
4592 {
4593 gimple *stmt = gsi_stmt (gsi);
4594 enum assignment_mod_result assign_result;
4595 bool modified = false, deleted = false;
4596 tree *t;
4597 unsigned i;
4598
4599 switch (gimple_code (stmt))
4600 {
4601 case GIMPLE_RETURN:
4602 t = gimple_return_retval_ptr (as_a <greturn *> (stmt));
4603 if (*t != NULL_TREE)
4604 modified |= sra_modify_expr (t, &gsi, false);
4605 break;
4606
4607 case GIMPLE_ASSIGN:
4608 assign_result = sra_modify_assign (stmt, &gsi);
4609 modified |= assign_result == SRA_AM_MODIFIED;
4610 deleted = assign_result == SRA_AM_REMOVED;
4611 break;
4612
4613 case GIMPLE_CALL:
4614 /* Handle calls to .DEFERRED_INIT specially. */
4615 if (gimple_call_internal_p (stmt, IFN_DEFERRED_INIT))
4616 {
4617 assign_result = sra_modify_deferred_init (stmt, &gsi);
4618 modified |= assign_result == SRA_AM_MODIFIED;
4619 deleted = assign_result == SRA_AM_REMOVED;
4620 }
4621 else
4622 {
4623 /* Operands must be processed before the lhs. */
4624 for (i = 0; i < gimple_call_num_args (stmt); i++)
4625 {
4626 t = gimple_call_arg_ptr (stmt, i);
4627 modified |= sra_modify_expr (t, &gsi, false);
4628 }
4629
4630 if (gimple_call_lhs (stmt))
4631 {
4632 t = gimple_call_lhs_ptr (stmt);
4633 modified |= sra_modify_expr (t, &gsi, true);
4634 }
4635 }
4636 break;
4637
4638 case GIMPLE_ASM:
4639 {
4640 gasm *asm_stmt = as_a <gasm *> (stmt);
4641 for (i = 0; i < gimple_asm_ninputs (asm_stmt); i++)
4642 {
4643 t = &TREE_VALUE (gimple_asm_input_op (asm_stmt, i));
4644 modified |= sra_modify_expr (t, &gsi, false);
4645 }
4646 for (i = 0; i < gimple_asm_noutputs (asm_stmt); i++)
4647 {
4648 t = &TREE_VALUE (gimple_asm_output_op (asm_stmt, i));
4649 modified |= sra_modify_expr (t, &gsi, true);
4650 }
4651 }
4652 break;
4653
4654 default:
4655 break;
4656 }
4657
4658 if (modified)
4659 {
4660 update_stmt (stmt);
4661 if (maybe_clean_eh_stmt (stmt)
4662 && gimple_purge_dead_eh_edges (gimple_bb (stmt)))
4663 cfg_changed = true;
4664 }
4665 if (!deleted)
4666 gsi_next (&gsi);
4667 }
4668 }
4669
4670 gsi_commit_edge_inserts ();
4671 return cfg_changed;
4672 }
4673
4674 /* Generate statements initializing scalar replacements of parts of function
4675 parameters. */
4676
4677 static void
initialize_parameter_reductions(void)4678 initialize_parameter_reductions (void)
4679 {
4680 gimple_stmt_iterator gsi;
4681 gimple_seq seq = NULL;
4682 tree parm;
4683
4684 gsi = gsi_start (seq);
4685 for (parm = DECL_ARGUMENTS (current_function_decl);
4686 parm;
4687 parm = DECL_CHAIN (parm))
4688 {
4689 vec<access_p> *access_vec;
4690 struct access *access;
4691
4692 if (!bitmap_bit_p (candidate_bitmap, DECL_UID (parm)))
4693 continue;
4694 access_vec = get_base_access_vector (parm);
4695 if (!access_vec)
4696 continue;
4697
4698 for (access = (*access_vec)[0];
4699 access;
4700 access = access->next_grp)
4701 generate_subtree_copies (access, parm, 0, 0, 0, &gsi, true, true,
4702 EXPR_LOCATION (parm));
4703 }
4704
4705 seq = gsi_seq (gsi);
4706 if (seq)
4707 gsi_insert_seq_on_edge_immediate (single_succ_edge (ENTRY_BLOCK_PTR_FOR_FN (cfun)), seq);
4708 }
4709
4710 /* The "main" function of intraprocedural SRA passes. Runs the analysis and if
4711 it reveals there are components of some aggregates to be scalarized, it runs
4712 the required transformations. */
4713 static unsigned int
perform_intra_sra(void)4714 perform_intra_sra (void)
4715 {
4716 int ret = 0;
4717 sra_initialize ();
4718
4719 if (!find_var_candidates ())
4720 goto out;
4721
4722 if (!scan_function ())
4723 goto out;
4724
4725 if (!analyze_all_variable_accesses ())
4726 goto out;
4727
4728 if (sra_modify_function_body ())
4729 ret = TODO_update_ssa | TODO_cleanup_cfg;
4730 else
4731 ret = TODO_update_ssa;
4732 initialize_parameter_reductions ();
4733
4734 statistics_counter_event (cfun, "Scalar replacements created",
4735 sra_stats.replacements);
4736 statistics_counter_event (cfun, "Modified expressions", sra_stats.exprs);
4737 statistics_counter_event (cfun, "Subtree copy stmts",
4738 sra_stats.subtree_copies);
4739 statistics_counter_event (cfun, "Subreplacement stmts",
4740 sra_stats.subreplacements);
4741 statistics_counter_event (cfun, "Deleted stmts", sra_stats.deleted);
4742 statistics_counter_event (cfun, "Separate LHS and RHS handling",
4743 sra_stats.separate_lhs_rhs_handling);
4744
4745 out:
4746 sra_deinitialize ();
4747 return ret;
4748 }
4749
4750 /* Perform early intraprocedural SRA. */
4751 static unsigned int
early_intra_sra(void)4752 early_intra_sra (void)
4753 {
4754 sra_mode = SRA_MODE_EARLY_INTRA;
4755 return perform_intra_sra ();
4756 }
4757
4758 /* Perform "late" intraprocedural SRA. */
4759 static unsigned int
late_intra_sra(void)4760 late_intra_sra (void)
4761 {
4762 sra_mode = SRA_MODE_INTRA;
4763 return perform_intra_sra ();
4764 }
4765
4766
4767 static bool
gate_intra_sra(void)4768 gate_intra_sra (void)
4769 {
4770 return flag_tree_sra != 0 && dbg_cnt (tree_sra);
4771 }
4772
4773
4774 namespace {
4775
4776 const pass_data pass_data_sra_early =
4777 {
4778 GIMPLE_PASS, /* type */
4779 "esra", /* name */
4780 OPTGROUP_NONE, /* optinfo_flags */
4781 TV_TREE_SRA, /* tv_id */
4782 ( PROP_cfg | PROP_ssa ), /* properties_required */
4783 0, /* properties_provided */
4784 0, /* properties_destroyed */
4785 0, /* todo_flags_start */
4786 TODO_update_ssa, /* todo_flags_finish */
4787 };
4788
4789 class pass_sra_early : public gimple_opt_pass
4790 {
4791 public:
pass_sra_early(gcc::context * ctxt)4792 pass_sra_early (gcc::context *ctxt)
4793 : gimple_opt_pass (pass_data_sra_early, ctxt)
4794 {}
4795
4796 /* opt_pass methods: */
gate(function *)4797 virtual bool gate (function *) { return gate_intra_sra (); }
execute(function *)4798 virtual unsigned int execute (function *) { return early_intra_sra (); }
4799
4800 }; // class pass_sra_early
4801
4802 } // anon namespace
4803
4804 gimple_opt_pass *
make_pass_sra_early(gcc::context * ctxt)4805 make_pass_sra_early (gcc::context *ctxt)
4806 {
4807 return new pass_sra_early (ctxt);
4808 }
4809
4810 namespace {
4811
4812 const pass_data pass_data_sra =
4813 {
4814 GIMPLE_PASS, /* type */
4815 "sra", /* name */
4816 OPTGROUP_NONE, /* optinfo_flags */
4817 TV_TREE_SRA, /* tv_id */
4818 ( PROP_cfg | PROP_ssa ), /* properties_required */
4819 0, /* properties_provided */
4820 0, /* properties_destroyed */
4821 TODO_update_address_taken, /* todo_flags_start */
4822 TODO_update_ssa, /* todo_flags_finish */
4823 };
4824
4825 class pass_sra : public gimple_opt_pass
4826 {
4827 public:
pass_sra(gcc::context * ctxt)4828 pass_sra (gcc::context *ctxt)
4829 : gimple_opt_pass (pass_data_sra, ctxt)
4830 {}
4831
4832 /* opt_pass methods: */
gate(function *)4833 virtual bool gate (function *) { return gate_intra_sra (); }
execute(function *)4834 virtual unsigned int execute (function *) { return late_intra_sra (); }
4835
4836 }; // class pass_sra
4837
4838 } // anon namespace
4839
4840 gimple_opt_pass *
make_pass_sra(gcc::context * ctxt)4841 make_pass_sra (gcc::context *ctxt)
4842 {
4843 return new pass_sra (ctxt);
4844 }
4845