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