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

source code of gcc/tree-sra.cc