1 /* Scalar Replacement of Aggregates (SRA) converts some structure
2 references into scalar references, exposing them to the scalar
4 Copyright (C) 2008-2024 Free Software Foundation, Inc.
5 Contributed by Martin Jambor <mjambor@suse.cz>
7 This file is part of GCC.
9 GCC is free software; you can redistribute it and/or modify it under
10 the terms of the GNU General Public License as published by the Free
11 Software Foundation; either version 3, or (at your option) any later
14 GCC is distributed in the hope that it will be useful, but WITHOUT ANY
15 WARRANTY; without even the implied warranty of MERCHANTABILITY or
16 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
19 You should have received a copy of the GNU General Public License
20 along with GCC; see the file COPYING3. If not see
21 <http://www.gnu.org/licenses/>. */
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.
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
33 Both passes operate in four stages:
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.
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.
47 On a related note, assign_link structures are created for every assign
48 statement between candidate aggregates and attached to the related
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.
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).
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.
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.
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. */
76 #include "coretypes.h"
83 #include "alloc-pool.h"
84 #include "tree-pass.h"
87 #include "gimple-pretty-print.h"
89 #include "fold-const.h"
91 #include "stor-layout.h"
93 #include "gimple-iterator.h"
94 #include "gimplify-me.h"
95 #include "gimple-walk.h"
100 #include "builtins.h"
101 #include "tree-sra.h"
104 /* Enumeration of all aggregate reductions we can do. */
105 enum sra_mode
{ SRA_MODE_EARLY_IPA
, /* early call regularization */
106 SRA_MODE_EARLY_INTRA
, /* early intraprocedural SRA */
107 SRA_MODE_INTRA
}; /* late intraprocedural SRA */
109 /* Global variable describing which aggregate reduction we are performing at
111 static enum sra_mode sra_mode
;
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.
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.
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. */
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
;
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
147 /* The statement this access belongs to. */
150 /* Next group representative for this aggregate. */
151 struct access
*next_grp
;
153 /* Pointer to the group representative. Pointer to itself if the struct is
154 the representative. */
155 struct access
*group_representative
;
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
;
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
;
165 /* In intraprocedural SRA, pointer to the next sibling in the access tree as
167 struct access
*next_sibling
;
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
;
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
;
177 /* Pointer to the next access in the work queues. */
178 struct access
*next_rhs_queued
, *next_lhs_queued
;
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
;
185 /* Is this access made in reverse storage order? */
186 unsigned reverse
: 1;
188 /* Is this particular access write access? */
191 /* Is this access currently in the rhs work queue? */
192 unsigned grp_rhs_queued
: 1;
194 /* Is this access currently in the lhs work queue? */
195 unsigned grp_lhs_queued
: 1;
197 /* Does this group contain a write access? This flag is propagated down the
199 unsigned grp_write
: 1;
201 /* Does this group contain a read access? This flag is propagated down the
203 unsigned grp_read
: 1;
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;
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;
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;
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;
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
226 unsigned grp_total_scalarization
: 1;
228 /* Other passes of the analysis use this bit to make function
229 analyze_access_subtree create scalar replacements for this group if
231 unsigned grp_hint
: 1;
233 /* Is the subtree rooted in this access fully covered by scalar
235 unsigned grp_covered
: 1;
237 /* If set to true, this access and all below it in an access tree must not be
239 unsigned grp_unscalarizable_region
: 1;
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
244 unsigned grp_unscalarized_data
: 1;
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;
250 /* Does this access and/or group contain a write access through a
252 unsigned grp_partial_lhs
: 1;
254 /* Set when a scalar replacement should be created for this variable. */
255 unsigned grp_to_be_replaced
: 1;
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;
261 /* Should TREE_NO_WARNING of a replacement be set? */
262 unsigned grp_no_warning
: 1;
264 /* Result of propagation accross link from LHS to RHS. */
265 unsigned grp_result_of_prop_from_lhs
: 1;
268 typedef struct access
*access_p
;
271 /* Alloc pool for allocating access structures. */
272 static object_allocator
<struct access
> access_pool ("SRA accesses");
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
281 struct access
*lacc
, *racc
;
282 struct assign_link
*next_rhs
, *next_lhs
;
285 /* Alloc pool for allocating assign link structures. */
286 static object_allocator
<assign_link
> assign_link_pool ("SRA links");
288 /* Base (tree) -> Vector (vec<access_p> *) map. */
289 static hash_map
<tree
, auto_vec
<access_p
> > *base_access_vec
;
291 /* Hash to limit creation of artificial accesses */
292 static hash_map
<tree
, unsigned> *propagation_budget
;
294 /* Candidate hash table helpers. */
296 struct uid_decl_hasher
: nofree_ptr_hash
<tree_node
>
298 static inline hashval_t
hash (const tree_node
*);
299 static inline bool equal (const tree_node
*, const tree_node
*);
302 /* Hash a tree in a uid_decl_map. */
305 uid_decl_hasher::hash (const tree_node
*item
)
307 return item
->decl_minimal
.uid
;
310 /* Return true if the DECL_UID in both trees are equal. */
313 uid_decl_hasher::equal (const tree_node
*a
, const tree_node
*b
)
315 return (a
->decl_minimal
.uid
== b
->decl_minimal
.uid
);
318 /* Set of candidates. */
319 static bitmap candidate_bitmap
;
320 static hash_table
<uid_decl_hasher
> *candidates
;
322 /* For a candidate UID return the candidates decl. */
325 candidate (unsigned uid
)
328 t
.decl_minimal
.uid
= uid
;
329 return candidates
->find_with_hash (&t
, static_cast <hashval_t
> (uid
));
332 /* Bitmap of candidates which we should try to entirely scalarize away and
333 those which cannot be (because they are and need be used as a whole). */
334 static bitmap should_scalarize_away_bitmap
, cannot_scalarize_away_bitmap
;
336 /* Bitmap of candidates in the constant pool, which cannot be scalarized
337 because this would produce non-constant expressions (e.g. Ada). */
338 static bitmap disqualified_constants
;
340 /* Bitmap of candidates which are passed by reference in call arguments. */
341 static bitmap passed_by_ref_in_call
;
343 /* Obstack for creation of fancy names. */
344 static struct obstack name_obstack
;
346 /* Head of a linked list of accesses that need to have its subaccesses
347 propagated to their assignment counterparts. */
348 static struct access
*rhs_work_queue_head
, *lhs_work_queue_head
;
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. */
356 /* Number of processed aggregates is readily available in
357 analyze_all_variable_accesses and so is not stored here. */
359 /* Number of created scalar replacements. */
362 /* Number of times sra_modify_expr or sra_modify_assign themselves changed an
366 /* Number of statements created by generate_subtree_copies. */
369 /* Number of statements created by load_assign_lhs_subreplacements. */
372 /* Number of times sra_modify_assign has deleted a statement. */
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
378 int separate_lhs_rhs_handling
;
380 /* Number of parameters that were removed because they were unused. */
381 int deleted_unused_parameters
;
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
;
387 /* Number of aggregate parameters that were replaced by one or more of their
389 int aggregate_params_reduced
;
391 /* Numbber of components created when splitting aggregate parameters. */
392 int param_reductions_created
;
394 /* Number of deferred_init calls that are modified. */
397 /* Number of deferred_init calls that are created by
398 generate_subtree_deferred_init. */
399 int subtree_deferred_init
;
403 dump_access (FILE *f
, struct access
*access
, bool grp
)
405 fprintf (f
, "access { ");
406 fprintf (f
, "base = (%d)'", DECL_UID (access
->base
));
407 print_generic_expr (f
, access
->base
);
408 fprintf (f
, "', offset = " HOST_WIDE_INT_PRINT_DEC
, access
->offset
);
409 fprintf (f
, ", size = " HOST_WIDE_INT_PRINT_DEC
, access
->size
);
410 fprintf (f
, ", expr = ");
411 print_generic_expr (f
, access
->expr
);
412 fprintf (f
, ", type = ");
413 print_generic_expr (f
, access
->type
);
414 fprintf (f
, ", reverse = %d", access
->reverse
);
416 fprintf (f
, ", 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
);
431 fprintf (f
, ", write = %d, grp_total_scalarization = %d, "
432 "grp_partial_lhs = %d}\n",
433 access
->write
, access
->grp_total_scalarization
,
434 access
->grp_partial_lhs
);
437 /* Dump a subtree rooted in ACCESS to file F, indent by LEVEL. */
440 dump_access_tree_1 (FILE *f
, struct access
*access
, int level
)
446 for (i
= 0; i
< level
; i
++)
449 dump_access (f
, access
, true);
451 if (access
->first_child
)
452 dump_access_tree_1 (f
, access
->first_child
, level
+ 1);
454 access
= access
->next_sibling
;
459 /* Dump all access trees for a variable, given the pointer to the first root in
463 dump_access_tree (FILE *f
, struct access
*access
)
465 for (; access
; access
= access
->next_grp
)
466 dump_access_tree_1 (f
, access
, 0);
469 /* Return true iff ACC is non-NULL and has subaccesses. */
472 access_has_children_p (struct access
*acc
)
474 return acc
&& acc
->first_child
;
477 /* Return true iff ACC is (partly) covered by at least one replacement. */
480 access_has_replacements_p (struct access
*acc
)
482 struct access
*child
;
483 if (acc
->grp_to_be_replaced
)
485 for (child
= acc
->first_child
; child
; child
= child
->next_sibling
)
486 if (access_has_replacements_p (child
))
491 /* Return a vector of pointers to accesses for the variable given in BASE or
492 NULL if there is none. */
494 static vec
<access_p
> *
495 get_base_access_vector (tree base
)
497 return base_access_vec
->get (base
);
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. */
503 static struct access
*
504 find_access_in_subtree (struct access
*access
, HOST_WIDE_INT offset
,
507 while (access
&& (access
->offset
!= offset
|| access
->size
!= size
))
509 struct access
*child
= access
->first_child
;
511 while (child
&& (child
->offset
+ child
->size
<= offset
))
512 child
= child
->next_sibling
;
516 /* Total scalarization does not replace single field structures with their
517 single field but rather creates an access for them underneath. Look for
520 while (access
->first_child
521 && access
->first_child
->offset
== offset
522 && access
->first_child
->size
== size
)
523 access
= access
->first_child
;
528 /* Return the first group representative for DECL or NULL if none exists. */
530 static struct access
*
531 get_first_repr_for_decl (tree base
)
533 vec
<access_p
> *access_vec
;
535 access_vec
= get_base_access_vector (base
);
539 return (*access_vec
)[0];
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. */
546 static struct access
*
547 get_var_base_offset_size_access (tree base
, HOST_WIDE_INT offset
,
550 struct access
*access
;
552 access
= get_first_repr_for_decl (base
);
553 while (access
&& (access
->offset
+ access
->size
<= offset
))
554 access
= access
->next_grp
;
558 return find_access_in_subtree (access
, offset
, size
);
561 /* Add LINK to the linked list of assign links of RACC. */
564 add_link_to_rhs (struct access
*racc
, struct assign_link
*link
)
566 gcc_assert (link
->racc
== racc
);
568 if (!racc
->first_rhs_link
)
570 gcc_assert (!racc
->last_rhs_link
);
571 racc
->first_rhs_link
= link
;
574 racc
->last_rhs_link
->next_rhs
= link
;
576 racc
->last_rhs_link
= link
;
577 link
->next_rhs
= NULL
;
580 /* Add LINK to the linked list of lhs assign links of LACC. */
583 add_link_to_lhs (struct access
*lacc
, struct assign_link
*link
)
585 gcc_assert (link
->lacc
== lacc
);
587 if (!lacc
->first_lhs_link
)
589 gcc_assert (!lacc
->last_lhs_link
);
590 lacc
->first_lhs_link
= link
;
593 lacc
->last_lhs_link
->next_lhs
= link
;
595 lacc
->last_lhs_link
= link
;
596 link
->next_lhs
= NULL
;
599 /* Move all link structures in their linked list in OLD_ACC to the linked list
602 relink_to_new_repr (struct access
*new_acc
, struct access
*old_acc
)
604 if (old_acc
->first_rhs_link
)
607 if (new_acc
->first_rhs_link
)
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
);
613 new_acc
->last_rhs_link
->next_rhs
= old_acc
->first_rhs_link
;
614 new_acc
->last_rhs_link
= old_acc
->last_rhs_link
;
618 gcc_assert (!new_acc
->last_rhs_link
);
620 new_acc
->first_rhs_link
= old_acc
->first_rhs_link
;
621 new_acc
->last_rhs_link
= old_acc
->last_rhs_link
;
623 old_acc
->first_rhs_link
= old_acc
->last_rhs_link
= NULL
;
626 gcc_assert (!old_acc
->last_rhs_link
);
628 if (old_acc
->first_lhs_link
)
631 if (new_acc
->first_lhs_link
)
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
);
637 new_acc
->last_lhs_link
->next_lhs
= old_acc
->first_lhs_link
;
638 new_acc
->last_lhs_link
= old_acc
->last_lhs_link
;
642 gcc_assert (!new_acc
->last_lhs_link
);
644 new_acc
->first_lhs_link
= old_acc
->first_lhs_link
;
645 new_acc
->last_lhs_link
= old_acc
->last_lhs_link
;
647 old_acc
->first_lhs_link
= old_acc
->last_lhs_link
= NULL
;
650 gcc_assert (!old_acc
->last_lhs_link
);
654 /* Add ACCESS to the work to queue for propagation of subaccesses from RHS to
655 LHS (which is actually a stack). */
658 add_access_to_rhs_work_queue (struct access
*access
)
660 if (access
->first_rhs_link
&& !access
->grp_rhs_queued
)
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
;
669 /* Add ACCESS to the work to queue for propagation of subaccesses from LHS to
670 RHS (which is actually a stack). */
673 add_access_to_lhs_work_queue (struct access
*access
)
675 if (access
->first_lhs_link
&& !access
->grp_lhs_queued
)
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
;
684 /* Pop an access from the work queue for propagating from RHS to LHS, and
685 return it, assuming there is one. */
687 static struct access
*
688 pop_access_from_rhs_work_queue (void)
690 struct access
*access
= rhs_work_queue_head
;
692 rhs_work_queue_head
= access
->next_rhs_queued
;
693 access
->next_rhs_queued
= NULL
;
694 access
->grp_rhs_queued
= 0;
698 /* Pop an access from the work queue for propagating from LHS to RHS, and
699 return it, assuming there is one. */
701 static struct access
*
702 pop_access_from_lhs_work_queue (void)
704 struct access
*access
= lhs_work_queue_head
;
706 lhs_work_queue_head
= access
->next_lhs_queued
;
707 access
->next_lhs_queued
= NULL
;
708 access
->grp_lhs_queued
= 0;
712 /* Allocate necessary structures. */
715 sra_initialize (void)
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 (&sra_stats
, 0, sizeof (sra_stats
));
729 /* Deallocate all general structures. */
732 sra_deinitialize (void)
734 BITMAP_FREE (candidate_bitmap
);
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
);
745 delete base_access_vec
;
748 /* Return true if DECL is a VAR_DECL in the constant pool, false otherwise. */
750 static bool constant_decl_p (tree decl
)
752 return VAR_P (decl
) && DECL_IN_CONSTANT_POOL (decl
);
755 /* Remove DECL from candidates for SRA and write REASON to the dump file if
759 disqualify_candidate (tree decl
, const char *reason
)
761 if (bitmap_clear_bit (candidate_bitmap
, DECL_UID (decl
)))
762 candidates
->remove_elt_with_hash (decl
, DECL_UID (decl
));
763 if (constant_decl_p (decl
))
764 bitmap_set_bit (disqualified_constants
, DECL_UID (decl
));
766 if (dump_file
&& (dump_flags
& TDF_DETAILS
))
768 fprintf (dump_file
, "! Disqualifying ");
769 print_generic_expr (dump_file
, decl
);
770 fprintf (dump_file
, " - %s\n", reason
);
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
779 type_internals_preclude_sra_p_1 (tree type
, const char **msg
,
780 hash_set
<tree
> *visited_types
)
785 if (visited_types
->contains (type
))
787 visited_types
->add (type
);
789 switch (TREE_CODE (type
))
793 case QUAL_UNION_TYPE
:
794 for (fld
= TYPE_FIELDS (type
); fld
; fld
= DECL_CHAIN (fld
))
795 if (TREE_CODE (fld
) == FIELD_DECL
)
797 if (TREE_CODE (fld
) == FUNCTION_DECL
)
799 tree ft
= TREE_TYPE (fld
);
801 if (TREE_THIS_VOLATILE (fld
))
803 *msg
= "volatile structure field";
806 if (!DECL_FIELD_OFFSET (fld
))
808 *msg
= "no structure field offset";
811 if (!DECL_SIZE (fld
))
813 *msg
= "zero structure field size";
816 if (!tree_fits_uhwi_p (DECL_FIELD_OFFSET (fld
)))
818 *msg
= "structure field offset not fixed";
821 if (!tree_fits_uhwi_p (DECL_SIZE (fld
)))
823 *msg
= "structure field size not fixed";
826 if (!tree_fits_shwi_p (bit_position (fld
)))
828 *msg
= "structure field size too big";
831 if (AGGREGATE_TYPE_P (ft
)
832 && int_bit_position (fld
) % BITS_PER_UNIT
!= 0)
834 *msg
= "structure field is bit field";
838 if (AGGREGATE_TYPE_P (ft
)
839 && type_internals_preclude_sra_p_1 (ft
, msg
, visited_types
))
846 et
= TREE_TYPE (type
);
848 if (TYPE_VOLATILE (et
))
850 *msg
= "element type is volatile";
854 if (AGGREGATE_TYPE_P (et
)
855 && type_internals_preclude_sra_p_1 (et
, msg
, visited_types
))
865 /* Return true iff the type contains a field or an element which does not allow
869 type_internals_preclude_sra_p (tree type
, const char **msg
)
871 hash_set
<tree
> visited_types
;
872 return type_internals_preclude_sra_p_1 (type
, msg
, &visited_types
);
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. */
880 static struct access
*
881 create_access_1 (tree base
, HOST_WIDE_INT offset
, HOST_WIDE_INT size
)
883 struct access
*access
= access_pool
.allocate ();
885 memset (access
, 0, sizeof (struct access
));
887 access
->offset
= offset
;
890 base_access_vec
->get_or_insert (base
).safe_push (access
);
895 static bool maybe_add_sra_candidate (tree
);
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
901 static struct access
*
902 create_access (tree expr
, gimple
*stmt
, bool write
)
904 struct access
*access
;
905 poly_int64 poffset
, psize
, pmax_size
;
907 bool reverse
, unscalarizable_region
= false;
909 base
= get_ref_base_and_extent (expr
, &poffset
, &psize
, &pmax_size
,
912 /* For constant-pool entries, check we can substitute the constant value. */
913 if (constant_decl_p (base
)
914 && !bitmap_bit_p (disqualified_constants
, DECL_UID (base
)))
917 && !is_gimple_reg_type (TREE_TYPE (expr
))
918 && dump_file
&& (dump_flags
& TDF_DETAILS
))
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 (dump_file
, "Allowing non-reg-type load of part"
924 " of constant-pool entry: ");
925 print_generic_expr (dump_file
, expr
);
927 maybe_add_sra_candidate (base
);
930 if (!DECL_P (base
) || !bitmap_bit_p (candidate_bitmap
, DECL_UID (base
)))
933 if (write
&& TREE_READONLY (base
))
935 disqualify_candidate (base
, "Encountered a store to a read-only decl.");
939 HOST_WIDE_INT offset
, size
, max_size
;
940 if (!poffset
.is_constant (&offset
)
941 || !psize
.is_constant (&size
)
942 || !pmax_size
.is_constant (&max_size
))
944 disqualify_candidate (base
, "Encountered a polynomial-sized access.");
948 if (size
!= max_size
)
951 unscalarizable_region
= true;
957 disqualify_candidate (base
, "Encountered a negative offset access.");
962 disqualify_candidate (base
, "Encountered an unconstrained access.");
965 if (offset
+ size
> tree_to_shwi (DECL_SIZE (base
)))
967 disqualify_candidate (base
, "Encountered an access beyond the base.");
970 if (TREE_CODE (TREE_TYPE (expr
)) == BITINT_TYPE
971 && size
> WIDE_INT_MAX_PRECISION
- 1)
973 disqualify_candidate (base
, "Encountered too large _BitInt access.");
977 access
= create_access_1 (base
, offset
, size
);
979 access
->type
= TREE_TYPE (expr
);
980 access
->write
= write
;
981 access
->grp_unscalarizable_region
= unscalarizable_region
;
983 access
->reverse
= reverse
;
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. */
994 prepare_iteration_over_array_elts (tree type
, HOST_WIDE_INT
*el_size
,
995 offset_int
*idx
, offset_int
*max
)
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);
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. */
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 (minidx
);
1013 *max
= wi::to_offset (maxidx
);
1014 if (!TYPE_UNSIGNED (domain
))
1016 *idx
= wi::sext (*idx
, TYPE_PRECISION (domain
));
1017 *max
= wi::sext (*max
, TYPE_PRECISION (domain
));
1022 /* A structure to track collecting padding and hold collected padding
1025 class sra_padding_collecting
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;
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. */
1042 void sra_padding_collecting::record_padding (HOST_WIDE_INT offset
)
1044 if (offset
> m_data_until
)
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
;
1052 m_padding
.safe_push (std::make_pair (m_data_until
, psz
));
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.
1062 TOTAL_OFFSET is the offset of TYPE within any outer type that is being
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. */
1070 totally_scalarizable_type_p (tree type
, bool const_decl
,
1071 HOST_WIDE_INT total_offset
,
1072 sra_padding_collecting
*pc
)
1074 if (is_gimple_reg_type (type
))
1078 pc
->record_padding (total_offset
);
1079 pc
->m_data_until
= total_offset
+ tree_to_shwi (TYPE_SIZE (type
));
1083 if (type_contains_placeholder_p (type
))
1086 bool have_predecessor_field
= false;
1087 HOST_WIDE_INT prev_pos
= 0;
1089 switch (TREE_CODE (type
))
1092 for (tree fld
= TYPE_FIELDS (type
); fld
; fld
= DECL_CHAIN (fld
))
1093 if (TREE_CODE (fld
) == FIELD_DECL
)
1095 tree ft
= TREE_TYPE (fld
);
1097 if (!DECL_SIZE (fld
))
1099 if (zerop (DECL_SIZE (fld
)))
1102 HOST_WIDE_INT pos
= int_bit_position (fld
);
1103 if (have_predecessor_field
1107 have_predecessor_field
= true;
1110 if (DECL_BIT_FIELD (fld
))
1113 if (!totally_scalarizable_type_p (ft
, const_decl
, total_offset
+ pos
,
1122 HOST_WIDE_INT min_elem_size
;
1126 min_elem_size
= BITS_PER_UNIT
;
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
))))
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. */
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. */
1143 unsigned old_padding_len
= 0;
1145 old_padding_len
= pc
->m_padding
.length ();
1146 tree elem
= TREE_TYPE (type
);
1147 if (!totally_scalarizable_type_p (elem
, const_decl
, total_offset
, pc
))
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
, &idx
, &max
))
1156 pc
->record_padding (total_offset
+ el_size
);
1158 for (HOST_WIDE_INT pos
= total_offset
+ el_size
;
1160 pos
+= el_size
, ++idx
)
1162 for (unsigned i
= old_padding_len
; i
< new_padding_len
; i
++)
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 (std::make_pair (pp
, psz
));
1170 pc
->m_data_until
= total_offset
+ tree_to_shwi (TYPE_SIZE (type
));
1179 /* Return true if REF has an VIEW_CONVERT_EXPR somewhere in it. */
1182 contains_view_convert_expr_p (const_tree ref
)
1184 while (handled_component_p (ref
))
1186 if (TREE_CODE (ref
) == VIEW_CONVERT_EXPR
)
1188 ref
= TREE_OPERAND (ref
, 0);
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. */
1200 contains_vce_or_bfcref_p (const_tree ref
, bool *type_changing_p
= NULL
)
1202 while (handled_component_p (ref
))
1204 if (TREE_CODE (ref
) == VIEW_CONVERT_EXPR
1205 || (TREE_CODE (ref
) == COMPONENT_REF
1206 && DECL_BIT_FIELD (TREE_OPERAND (ref
, 1))))
1208 if (type_changing_p
)
1209 *type_changing_p
= true;
1212 ref
= TREE_OPERAND (ref
, 0);
1215 if (!type_changing_p
1216 || TREE_CODE (ref
) != MEM_REF
1217 || TREE_CODE (TREE_OPERAND (ref
, 0)) != ADDR_EXPR
)
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;
1228 /* Search the given tree for a declaration by skipping handled components and
1229 exclude it from the candidates. */
1232 disqualify_base_of_expr (tree t
, const char *reason
)
1234 t
= get_base_address (t
);
1235 if (t
&& DECL_P (t
))
1236 disqualify_candidate (t
, reason
);
1239 /* Return true if the BIT_FIELD_REF read EXPR is handled by SRA. */
1242 sra_handled_bf_read_p (tree expr
)
1244 uint64_t size
, offset
;
1245 if (bit_field_size (expr
).is_constant (&size
)
1246 && bit_field_offset (expr
).is_constant (&offset
)
1247 && size
% BITS_PER_UNIT
== 0
1248 && offset
% BITS_PER_UNIT
== 0
1249 && pow2p_hwi (size
))
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
1258 static struct access
*
1259 build_access_from_expr_1 (tree expr
, gimple
*stmt
, bool write
)
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
)
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
)));
1272 struct access
*ret
= NULL
;
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
)
1280 expr
= TREE_OPERAND (expr
, 0);
1284 partial_ref
= false;
1286 if (storage_order_barrier_p (expr
))
1288 disqualify_base_of_expr (expr
, "storage order barrier.");
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);
1299 if (contains_view_convert_expr_p (expr
))
1301 disqualify_base_of_expr (expr
, "V_C_E under a different handled "
1305 if (TREE_THIS_VOLATILE (expr
))
1307 disqualify_base_of_expr (expr
, "part of a volatile reference.");
1311 switch (TREE_CODE (expr
))
1314 if (TREE_CODE (TREE_OPERAND (expr
, 0)) != ADDR_EXPR
)
1322 case ARRAY_RANGE_REF
:
1324 ret
= create_access (expr
, stmt
, write
);
1331 if (write
&& partial_ref
&& ret
)
1332 ret
->grp_partial_lhs
= 1;
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. */
1343 build_access_from_expr (tree expr
, gimple
*stmt
, bool write
)
1345 struct access
*access
;
1347 access
= build_access_from_expr_1 (expr
, stmt
, write
);
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
));
1360 enum out_edge_check
{ SRA_OUTGOING_EDGES_UNCHECKED
, SRA_OUTGOING_EDGES_OK
,
1361 SRA_OUTGOING_EDGES_FAIL
};
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. */
1367 abnormal_edge_after_stmt_p (gimple
*stmt
, enum out_edge_check
*oe_check
)
1369 if (*oe_check
== SRA_OUTGOING_EDGES_OK
)
1371 if (*oe_check
== SRA_OUTGOING_EDGES_FAIL
)
1373 if (stmt_ends_bb_p (stmt
))
1377 FOR_EACH_EDGE (e
, ei
, gimple_bb (stmt
)->succs
)
1378 if (e
->flags
& EDGE_ABNORMAL
)
1380 *oe_check
= SRA_OUTGOING_EDGES_FAIL
;
1384 *oe_check
= SRA_OUTGOING_EDGES_OK
;
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
1397 build_access_from_call_arg (tree expr
, gimple
*stmt
, bool can_be_returned
,
1398 enum out_edge_check
*oe_check
)
1400 if (TREE_CODE (expr
) == ADDR_EXPR
)
1402 tree base
= get_base_address (TREE_OPERAND (expr
, 0));
1404 if (can_be_returned
)
1406 disqualify_base_of_expr (base
, "Address possibly returned, "
1407 "leading to an alis SRA may not know.");
1410 if (abnormal_edge_after_stmt_p (stmt
, oe_check
))
1412 disqualify_base_of_expr (base
, "May lead to need to add statements "
1413 "to abnormal edge.");
1417 bool read
= build_access_from_expr (base
, stmt
, false);
1418 bool write
= build_access_from_expr (base
, stmt
, true);
1421 if (dump_file
&& (dump_flags
& TDF_DETAILS
))
1423 fprintf (dump_file
, "Allowed ADDR_EXPR of ");
1424 print_generic_expr (dump_file
, base
);
1425 fprintf (dump_file
, " because of ");
1426 print_gimple_stmt (dump_file
, stmt
, 0);
1427 fprintf (dump_file
, "\n");
1429 bitmap_set_bit (passed_by_ref_in_call
, DECL_UID (base
));
1436 return build_access_from_expr (expr
, stmt
, false);
1440 /* Return the single non-EH successor edge of BB or NULL if there is none or
1444 single_non_eh_succ (basic_block bb
)
1449 FOR_EACH_EDGE (e
, ei
, bb
->succs
)
1450 if (!(e
->flags
& EDGE_EH
))
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. */
1467 disqualify_if_bad_bb_terminating_stmt (gimple
*stmt
, tree lhs
, tree rhs
)
1469 if (stmt_ends_bb_p (stmt
))
1471 if (single_non_eh_succ (gimple_bb (stmt
)))
1474 disqualify_base_of_expr (lhs
, "LHS of a throwing stmt.");
1476 disqualify_base_of_expr (rhs
, "RHS of a throwing stmt.");
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. */
1486 comes_initialized_p (tree base
)
1488 return TREE_CODE (base
) == PARM_DECL
|| constant_decl_p (base
);
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. */
1497 build_accesses_from_assign (gimple
*stmt
)
1500 struct access
*lacc
, *racc
;
1502 if (!gimple_assign_single_p (stmt
)
1503 /* Scope clobbers don't influence scalarization. */
1504 || gimple_clobber_p (stmt
))
1507 lhs
= gimple_assign_lhs (stmt
);
1508 rhs
= gimple_assign_rhs1 (stmt
);
1510 if (disqualify_if_bad_bb_terminating_stmt (stmt
, lhs
, rhs
))
1513 racc
= build_access_from_expr_1 (rhs
, stmt
, false);
1514 lacc
= build_access_from_expr_1 (lhs
, stmt
, true);
1518 lacc
->grp_assignment_write
= 1;
1519 if (storage_order_barrier_p (rhs
))
1520 lacc
->grp_unscalarizable_region
= 1;
1522 if (should_scalarize_away_bitmap
&& !is_gimple_reg_type (lacc
->type
))
1524 bool type_changing_p
= false;
1525 contains_vce_or_bfcref_p (lhs
, &type_changing_p
);
1526 if (type_changing_p
)
1527 bitmap_set_bit (cannot_scalarize_away_bitmap
,
1528 DECL_UID (lacc
->base
));
1534 racc
->grp_assignment_read
= 1;
1535 if (should_scalarize_away_bitmap
&& !is_gimple_reg_type (racc
->type
))
1537 bool type_changing_p
= false;
1538 contains_vce_or_bfcref_p (rhs
, &type_changing_p
);
1540 if (type_changing_p
|| gimple_has_volatile_ops (stmt
))
1541 bitmap_set_bit (cannot_scalarize_away_bitmap
,
1542 DECL_UID (racc
->base
));
1544 bitmap_set_bit (should_scalarize_away_bitmap
,
1545 DECL_UID (racc
->base
));
1547 if (storage_order_barrier_p (lhs
))
1548 racc
->grp_unscalarizable_region
= 1;
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
))
1559 struct assign_link
*link
;
1561 link
= assign_link_pool
.allocate ();
1562 memset (link
, 0, sizeof (struct assign_link
));
1566 add_link_to_rhs (racc
, link
);
1567 add_link_to_lhs (lacc
, link
);
1568 add_access_to_rhs_work_queue (racc
);
1569 add_access_to_lhs_work_queue (lacc
);
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
1574 if (!comes_initialized_p (racc
->base
))
1575 lacc
->write
= false;
1578 return lacc
|| racc
;
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. */
1587 scan_visit_addr (gimple
*, tree op
, tree
, void *)
1589 op
= get_base_address (op
);
1592 disqualify_candidate (op
, "Address taken in a non-call-argument context.");
1597 /* Scan function and look for interesting expressions and create access
1598 structures for them. Return true iff any access is created. */
1601 scan_function (void)
1606 FOR_EACH_BB_FN (bb
, cfun
)
1608 gimple_stmt_iterator gsi
;
1609 for (gsi
= gsi_start_phis (bb
); !gsi_end_p (gsi
); gsi_next (&gsi
))
1610 walk_stmt_load_store_addr_ops (gsi_stmt (gsi
), NULL
, NULL
, NULL
,
1613 for (gsi
= gsi_start_bb (bb
); !gsi_end_p (gsi
); gsi_next (&gsi
))
1615 gimple
*stmt
= gsi_stmt (gsi
);
1619 if (gimple_code (stmt
) != GIMPLE_CALL
)
1620 walk_stmt_load_store_addr_ops (stmt
, NULL
, NULL
, NULL
,
1623 switch (gimple_code (stmt
))
1626 t
= gimple_return_retval (as_a
<greturn
*> (stmt
));
1628 ret
|= build_access_from_expr (t
, stmt
, false);
1632 ret
|= build_accesses_from_assign (stmt
);
1637 enum out_edge_check oe_check
= SRA_OUTGOING_EDGES_UNCHECKED
;
1638 gcall
*call
= as_a
<gcall
*> (stmt
);
1639 for (i
= 0; i
< gimple_call_num_args (call
); i
++)
1641 bool can_be_returned
;
1642 if (gimple_call_lhs (call
))
1644 int af
= gimple_call_arg_flags (call
, i
);
1645 can_be_returned
= !(af
& EAF_NOT_RETURNED_DIRECTLY
);
1648 can_be_returned
= false;
1649 ret
|= build_access_from_call_arg (gimple_call_arg (call
,
1651 stmt
, can_be_returned
,
1654 if (gimple_call_chain(stmt
))
1655 ret
|= build_access_from_call_arg (gimple_call_chain(call
),
1656 stmt
, false, &oe_check
);
1659 t
= gimple_call_lhs (stmt
);
1660 if (t
&& !disqualify_if_bad_bb_terminating_stmt (stmt
, t
, NULL
))
1662 /* If the STMT is a call to DEFERRED_INIT, avoid setting
1663 cannot_scalarize_away_bitmap. */
1664 if (gimple_call_internal_p (stmt
, IFN_DEFERRED_INIT
))
1665 ret
|= !!build_access_from_expr_1 (t
, stmt
, true);
1667 ret
|= build_access_from_expr (t
, stmt
, true);
1673 gasm
*asm_stmt
= as_a
<gasm
*> (stmt
);
1674 if (stmt_ends_bb_p (asm_stmt
)
1675 && !single_succ_p (gimple_bb (asm_stmt
)))
1677 for (i
= 0; i
< gimple_asm_ninputs (asm_stmt
); i
++)
1679 t
= TREE_VALUE (gimple_asm_input_op (asm_stmt
, i
));
1680 disqualify_base_of_expr (t
, "OP of asm goto.");
1682 for (i
= 0; i
< gimple_asm_noutputs (asm_stmt
); i
++)
1684 t
= TREE_VALUE (gimple_asm_output_op (asm_stmt
, i
));
1685 disqualify_base_of_expr (t
, "OP of asm goto.");
1690 for (i
= 0; i
< gimple_asm_ninputs (asm_stmt
); i
++)
1692 t
= TREE_VALUE (gimple_asm_input_op (asm_stmt
, i
));
1693 ret
|= build_access_from_expr (t
, asm_stmt
, false);
1695 for (i
= 0; i
< gimple_asm_noutputs (asm_stmt
); i
++)
1697 t
= TREE_VALUE (gimple_asm_output_op (asm_stmt
, i
));
1698 ret
|= build_access_from_expr (t
, asm_stmt
, true);
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. */
1718 compare_access_positions (const void *a
, const void *b
)
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
;
1725 if (f1
->offset
!= f2
->offset
)
1726 return f1
->offset
< f2
->offset
? -1 : 1;
1728 if (f1
->size
== f2
->size
)
1730 if (f1
->type
== f2
->type
)
1732 /* Put any non-aggregate type before any aggregate type. */
1733 else if (!is_gimple_reg_type (f1
->type
)
1734 && is_gimple_reg_type (f2
->type
))
1736 else if (is_gimple_reg_type (f1
->type
)
1737 && !is_gimple_reg_type (f2
->type
))
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
)))
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
)
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
))
1756 else if (!INTEGRAL_TYPE_P (f1
->type
)
1757 && INTEGRAL_TYPE_P (f2
->type
))
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
);
1768 /* We want the bigger accesses first, thus the opposite operator in the next
1770 return f1
->size
> f2
->size
? -1 : 1;
1774 /* Append a name of the declaration to the name obstack. A helper function for
1778 make_fancy_decl_name (tree decl
)
1782 tree name
= DECL_NAME (decl
);
1784 obstack_grow (&name_obstack
, IDENTIFIER_POINTER (name
),
1785 IDENTIFIER_LENGTH (name
));
1788 sprintf (buffer
, "D%u", DECL_UID (decl
));
1789 obstack_grow (&name_obstack
, buffer
, strlen (buffer
));
1793 /* Helper for make_fancy_name. */
1796 make_fancy_name_1 (tree expr
)
1803 make_fancy_decl_name (expr
);
1807 switch (TREE_CODE (expr
))
1810 make_fancy_name_1 (TREE_OPERAND (expr
, 0));
1811 obstack_1grow (&name_obstack
, '$');
1812 make_fancy_decl_name (TREE_OPERAND (expr
, 1));
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
1820 index
= TREE_OPERAND (expr
, 1);
1821 if (TREE_CODE (index
) != INTEGER_CST
)
1823 sprintf (buffer
, HOST_WIDE_INT_PRINT_DEC
, TREE_INT_CST_LOW (index
));
1824 obstack_grow (&name_obstack
, buffer
, strlen (buffer
));
1829 make_fancy_name_1 (TREE_OPERAND (expr
, 0));
1833 make_fancy_name_1 (TREE_OPERAND (expr
, 0));
1834 if (!integer_zerop (TREE_OPERAND (expr
, 1)))
1836 obstack_1grow (&name_obstack
, '$');
1837 sprintf (buffer
, HOST_WIDE_INT_PRINT_DEC
,
1838 TREE_INT_CST_LOW (TREE_OPERAND (expr
, 1)));
1839 obstack_grow (&name_obstack
, buffer
, strlen (buffer
));
1845 gcc_unreachable (); /* we treat these as scalars. */
1852 /* Create a human readable name for replacement variable of ACCESS. */
1855 make_fancy_name (tree expr
)
1857 make_fancy_name_1 (expr
);
1858 obstack_1grow (&name_obstack
, '\0');
1859 return XOBFINISH (&name_obstack
, char *);
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. */
1870 build_ref_for_offset (location_t loc
, tree base
, poly_int64 offset
,
1871 bool reverse
, tree exp_type
, gimple_stmt_iterator
*gsi
,
1874 tree prev_base
= base
;
1877 poly_int64 base_offset
;
1878 unsigned HOST_WIDE_INT misalign
;
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
));
1888 poly_int64 byte_offset
= exact_div (offset
, BITS_PER_UNIT
);
1889 get_object_alignment_1 (base
, &align
, &misalign
);
1890 base
= get_addr_base_and_unit_offset (base
, &base_offset
);
1892 /* get_addr_base_and_unit_offset returns NULL for references with a variable
1893 offset such as array[var_index]. */
1899 gcc_checking_assert (gsi
);
1900 tmp
= make_ssa_name (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 (stmt
, loc
);
1906 gsi_insert_after (gsi
, stmt
, GSI_NEW_STMT
);
1908 gsi_insert_before (gsi
, stmt
, GSI_SAME_STMT
);
1910 off
= build_int_cst (reference_alias_ptr_type (prev_base
), byte_offset
);
1913 else if (TREE_CODE (base
) == MEM_REF
)
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));
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
));
1927 unsigned int align_bound
= known_alignment (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
);
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;
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. */
1946 build_reconstructed_reference (location_t
, tree base
, struct access
*model
)
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 (expr
))
1953 if (TREE_CODE (TREE_TYPE (TREE_OPERAND (expr
, 0))) == UNION_TYPE
)
1955 expr
= TREE_OPERAND (expr
, 0);
1959 tree prev_expr
= NULL_TREE
;
1960 while (!types_compatible_p (TREE_TYPE (expr
), TREE_TYPE (base
)))
1962 if (!handled_component_p (expr
))
1965 expr
= TREE_OPERAND (expr
, 0);
1968 /* Guard against broken VIEW_CONVERT_EXPRs... */
1972 TREE_OPERAND (prev_expr
, 0) = base
;
1973 tree ref
= unshare_expr (model
->expr
);
1974 TREE_OPERAND (prev_expr
, 0) = expr
;
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
1988 build_ref_for_model (location_t loc
, tree base
, HOST_WIDE_INT offset
,
1989 struct access
*model
, gimple_stmt_iterator
*gsi
,
1992 gcc_assert (offset
>= 0);
1993 if (TREE_CODE (model
->expr
) == COMPONENT_REF
1994 && DECL_BIT_FIELD (TREE_OPERAND (model
->expr
, 1)))
1996 /* This access represents a bit-field. */
1997 tree t
, exp_type
, fld
= TREE_OPERAND (model
->expr
, 1);
1999 offset
-= int_bit_position (fld
);
2000 exp_type
= TREE_TYPE (TREE_OPERAND (model
->expr
, 0));
2001 t
= build_ref_for_offset (loc
, base
, offset
, model
->reverse
, exp_type
,
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
,
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
)))
2022 return build_ref_for_offset (loc
, base
, offset
, model
->reverse
,
2023 model
->type
, gsi
, insert_after
);
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
2034 build_debug_ref_for_model (location_t loc
, tree base
, HOST_WIDE_INT offset
,
2035 struct access
*model
)
2037 poly_int64 base_offset
;
2040 if (TREE_CODE (model
->expr
) == COMPONENT_REF
2041 && DECL_BIT_FIELD (TREE_OPERAND (model
->expr
, 1)))
2044 base
= get_addr_base_and_unit_offset (base
, &base_offset
);
2047 if (TREE_CODE (base
) == MEM_REF
)
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));
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
));
2061 return fold_build2_loc (loc
, MEM_REF
, model
->type
, base
, off
);
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. */
2073 build_user_friendly_ref_for_offset (tree
*res
, tree type
, HOST_WIDE_INT offset
,
2079 tree tr_size
, index
, minidx
;
2080 HOST_WIDE_INT el_size
;
2082 if (offset
== 0 && exp_type
2083 && types_compatible_p (exp_type
, type
))
2086 switch (TREE_CODE (type
))
2089 case QUAL_UNION_TYPE
:
2091 for (fld
= TYPE_FIELDS (type
); fld
; fld
= DECL_CHAIN (fld
))
2093 HOST_WIDE_INT pos
, size
;
2094 tree tr_pos
, expr
, *expr_ptr
;
2096 if (TREE_CODE (fld
) != FIELD_DECL
)
2099 tr_pos
= bit_position (fld
);
2100 if (!tr_pos
|| !tree_fits_uhwi_p (tr_pos
))
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
))
2107 size
= tree_to_uhwi (tr_size
);
2113 else if (pos
> offset
|| (pos
+ size
) <= offset
)
2116 expr
= build3 (COMPONENT_REF
, TREE_TYPE (fld
), *res
, fld
,
2119 if (build_user_friendly_ref_for_offset (expr_ptr
, TREE_TYPE (fld
),
2120 offset
- pos
, exp_type
))
2129 tr_size
= TYPE_SIZE (TREE_TYPE (type
));
2130 if (!tr_size
|| !tree_fits_uhwi_p (tr_size
))
2132 el_size
= tree_to_uhwi (tr_size
);
2134 minidx
= TYPE_MIN_VALUE (TYPE_DOMAIN (type
));
2135 if (TREE_CODE (minidx
) != INTEGER_CST
|| el_size
== 0)
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
);
2158 /* Print message to dump file why a variable was rejected. */
2161 reject (tree var
, const char *msg
)
2163 if (dump_file
&& (dump_flags
& TDF_DETAILS
))
2165 fprintf (dump_file
, "Rejected (%d): %s: ", DECL_UID (var
), msg
);
2166 print_generic_expr (dump_file
, var
);
2167 fprintf (dump_file
, "\n");
2171 /* Return true if VAR is a candidate for SRA. */
2174 maybe_add_sra_candidate (tree var
)
2176 tree type
= TREE_TYPE (var
);
2180 if (!AGGREGATE_TYPE_P (type
))
2182 reject (var
, "not aggregate");
2186 if ((is_global_var (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 (var
))
2197 reject (var
, "needs to live in memory and escapes or global");
2200 if (TREE_THIS_VOLATILE (var
))
2202 reject (var
, "is volatile");
2205 if (!COMPLETE_TYPE_P (type
))
2207 reject (var
, "has incomplete type");
2210 if (!tree_fits_shwi_p (TYPE_SIZE (type
)))
2212 reject (var
, "type size not fixed");
2215 if (tree_to_shwi (TYPE_SIZE (type
)) == 0)
2217 reject (var
, "type size is zero");
2220 if (type_internals_preclude_sra_p (type
, &msg
))
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
2228 (sra_mode
== SRA_MODE_EARLY_INTRA
2229 && is_va_list_type (type
)))
2231 reject (var
, "is va_list");
2235 bitmap_set_bit (candidate_bitmap
, DECL_UID (var
));
2236 slot
= candidates
->find_slot_with_hash (var
, DECL_UID (var
), INSERT
);
2239 if (dump_file
&& (dump_flags
& TDF_DETAILS
))
2241 fprintf (dump_file
, "Candidate (%d): ", DECL_UID (var
));
2242 print_generic_expr (dump_file
, var
);
2243 fprintf (dump_file
, "\n");
2249 /* The very first phase of intraprocedural SRA. It marks in candidate_bitmap
2250 those with type which is suitable for scalarization. */
2253 find_var_candidates (void)
2259 for (parm
= DECL_ARGUMENTS (current_function_decl
);
2261 parm
= DECL_CHAIN (parm
))
2262 ret
|= maybe_add_sra_candidate (parm
);
2264 FOR_EACH_LOCAL_DECL (cfun
, i
, var
)
2269 ret
|= maybe_add_sra_candidate (var
);
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. */
2279 path_comparable_for_same_access (tree expr
)
2281 while (handled_component_p (expr
))
2283 if (TREE_CODE (expr
) == ARRAY_REF
)
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
)
2293 expr
= TREE_OPERAND (expr
, 0);
2296 if (TREE_CODE (expr
) == MEM_REF
)
2298 if (!zerop (TREE_OPERAND (expr
, 1)))
2302 gcc_assert (DECL_P (expr
));
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. */
2313 same_access_path_p (tree exp1
, tree exp2
)
2315 if (TREE_CODE (exp1
) != TREE_CODE (exp2
))
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.
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);
2332 if (!operand_equal_p (exp1
, exp2
, OEP_ADDRESS_OF
))
2338 /* Return true when either T1 is a type that, when loaded into a register and
2339 stored back to memory will yield the same bits or when both T1 and T2 are
2343 types_risk_mangled_binary_repr_p (tree t1
, tree t2
)
2345 if (mode_can_transfer_bits (TYPE_MODE (t1
)))
2348 return !types_compatible_p (t1
, t2
);
2351 /* Sort all accesses for the given variable, check for partial overlaps and
2352 return NULL if there are any. If there are none, pick a representative for
2353 each combination of offset and size and create a linked list out of them.
2354 Return the pointer to the first representative and make sure it is the first
2355 one in the vector of accesses. */
2357 static struct access
*
2358 sort_and_splice_var_accesses (tree var
)
2360 int i
, j
, access_count
;
2361 struct access
*res
, **prev_acc_ptr
= &res
;
2362 vec
<access_p
> *access_vec
;
2364 HOST_WIDE_INT low
= -1, high
= 0;
2366 access_vec
= get_base_access_vector (var
);
2369 access_count
= access_vec
->length ();
2371 /* Sort by <OFFSET, SIZE>. */
2372 access_vec
->qsort (compare_access_positions
);
2375 while (i
< access_count
)
2377 struct access
*access
= (*access_vec
)[i
];
2378 bool grp_write
= access
->write
;
2379 bool grp_read
= !access
->write
;
2380 bool grp_scalar_write
= access
->write
2381 && is_gimple_reg_type (access
->type
);
2382 bool grp_scalar_read
= !access
->write
2383 && is_gimple_reg_type (access
->type
);
2384 bool grp_assignment_read
= access
->grp_assignment_read
;
2385 bool grp_assignment_write
= access
->grp_assignment_write
;
2386 bool multiple_scalar_reads
= false;
2387 bool grp_partial_lhs
= access
->grp_partial_lhs
;
2388 bool first_scalar
= is_gimple_reg_type (access
->type
);
2389 bool unscalarizable_region
= access
->grp_unscalarizable_region
;
2390 bool grp_same_access_path
= true;
2391 bool bf_non_full_precision
2392 = (INTEGRAL_TYPE_P (access
->type
)
2393 && TYPE_PRECISION (access
->type
) != access
->size
2394 && TREE_CODE (access
->expr
) == COMPONENT_REF
2395 && DECL_BIT_FIELD (TREE_OPERAND (access
->expr
, 1)));
2397 if (first
|| access
->offset
>= high
)
2400 low
= access
->offset
;
2401 high
= access
->offset
+ access
->size
;
2403 else if (access
->offset
> low
&& access
->offset
+ access
->size
> high
)
2406 gcc_assert (access
->offset
>= low
2407 && access
->offset
+ access
->size
<= high
);
2409 if (INTEGRAL_TYPE_P (access
->type
)
2410 && TYPE_PRECISION (access
->type
) != access
->size
2411 && bitmap_bit_p (passed_by_ref_in_call
, DECL_UID (access
->base
)))
2413 /* This can lead to performance regressions because we can generate
2414 excessive zero extensions. */
2415 if (dump_file
&& (dump_flags
& TDF_DETAILS
))
2417 fprintf (dump_file
, "Won't scalarize ");
2418 print_generic_expr (dump_file
, access
->base
);
2419 fprintf (dump_file
, "(%d), it is passed by reference to a call "
2420 "and there are accesses with precision not covering "
2421 "their type size.", DECL_UID (access
->base
));
2426 grp_same_access_path
= path_comparable_for_same_access (access
->expr
);
2429 while (j
< access_count
)
2431 struct access
*ac2
= (*access_vec
)[j
];
2432 if (ac2
->offset
!= access
->offset
|| ac2
->size
!= access
->size
)
2437 grp_scalar_write
= (grp_scalar_write
2438 || is_gimple_reg_type (ac2
->type
));
2443 if (is_gimple_reg_type (ac2
->type
))
2445 if (grp_scalar_read
)
2446 multiple_scalar_reads
= true;
2448 grp_scalar_read
= true;
2451 grp_assignment_read
|= ac2
->grp_assignment_read
;
2452 grp_assignment_write
|= ac2
->grp_assignment_write
;
2453 grp_partial_lhs
|= ac2
->grp_partial_lhs
;
2454 unscalarizable_region
|= ac2
->grp_unscalarizable_region
;
2455 relink_to_new_repr (access
, ac2
);
2457 /* If there are both aggregate-type and scalar-type accesses with
2458 this combination of size and offset, the comparison function
2459 should have put the scalars first. */
2460 gcc_assert (first_scalar
|| !is_gimple_reg_type (ac2
->type
));
2461 /* It also prefers integral types to non-integral. However, when the
2462 precision of the selected type does not span the entire area and
2463 should also be used for a non-integer (i.e. float), we must not
2464 let that happen. Normally analyze_access_subtree expands the type
2465 to cover the entire area but for bit-fields it doesn't. */
2466 if (bf_non_full_precision
&& !INTEGRAL_TYPE_P (ac2
->type
))
2468 if (dump_file
&& (dump_flags
& TDF_DETAILS
))
2470 fprintf (dump_file
, "Cannot scalarize the following access "
2471 "because insufficient precision integer type was "
2473 dump_access (dump_file
, access
, false);
2475 unscalarizable_region
= true;
2477 else if (types_risk_mangled_binary_repr_p (access
->type
, ac2
->type
))
2479 if (dump_file
&& (dump_flags
& TDF_DETAILS
))
2481 fprintf (dump_file
, "Cannot scalarize the following access "
2482 "because data would be held in a mode which is not "
2483 "guaranteed to preserve all bits.\n ");
2484 dump_access (dump_file
, access
, false);
2486 unscalarizable_region
= true;
2489 if (grp_same_access_path
2490 && !same_access_path_p (access
->expr
, ac2
->expr
))
2491 grp_same_access_path
= false;
2493 ac2
->group_representative
= access
;
2499 access
->group_representative
= access
;
2500 access
->grp_write
= grp_write
;
2501 access
->grp_read
= grp_read
;
2502 access
->grp_scalar_read
= grp_scalar_read
;
2503 access
->grp_scalar_write
= grp_scalar_write
;
2504 access
->grp_assignment_read
= grp_assignment_read
;
2505 access
->grp_assignment_write
= grp_assignment_write
;
2506 access
->grp_hint
= multiple_scalar_reads
&& !constant_decl_p (var
);
2507 access
->grp_partial_lhs
= grp_partial_lhs
;
2508 access
->grp_unscalarizable_region
= unscalarizable_region
;
2509 access
->grp_same_access_path
= grp_same_access_path
;
2511 *prev_acc_ptr
= access
;
2512 prev_acc_ptr
= &access
->next_grp
;
2515 gcc_assert (res
== (*access_vec
)[0]);
2519 /* Create a variable for the given ACCESS which determines the type, name and a
2520 few other properties. Return the variable declaration and store it also to
2521 ACCESS->replacement. REG_TREE is used when creating a declaration to base a
2522 default-definition SSA name on in order to facilitate an uninitialized
2523 warning. It is used instead of the actual ACCESS type if that is not of a
2524 gimple register type. */
2527 create_access_replacement (struct access
*access
, tree reg_type
= NULL_TREE
)
2531 tree type
= access
->type
;
2532 if (reg_type
&& !is_gimple_reg_type (type
))
2535 if (access
->grp_to_be_debug_replaced
)
2537 repl
= create_tmp_var_raw (access
->type
);
2538 DECL_CONTEXT (repl
) = current_function_decl
;
2541 /* Drop any special alignment on the type if it's not on the main
2542 variant. This avoids issues with weirdo ABIs like AAPCS. */
2543 repl
= create_tmp_var (build_qualified_type (TYPE_MAIN_VARIANT (type
),
2544 TYPE_QUALS (type
)), "SR");
2545 if (access
->grp_partial_lhs
2546 && is_gimple_reg_type (type
))
2547 DECL_NOT_GIMPLE_REG_P (repl
) = 1;
2549 DECL_SOURCE_LOCATION (repl
) = DECL_SOURCE_LOCATION (access
->base
);
2550 DECL_ARTIFICIAL (repl
) = 1;
2551 DECL_IGNORED_P (repl
) = DECL_IGNORED_P (access
->base
);
2553 if (DECL_NAME (access
->base
)
2554 && !DECL_IGNORED_P (access
->base
)
2555 && !DECL_ARTIFICIAL (access
->base
))
2557 char *pretty_name
= make_fancy_name (access
->expr
);
2558 tree debug_expr
= unshare_expr_without_location (access
->expr
), d
;
2561 DECL_NAME (repl
) = get_identifier (pretty_name
);
2562 DECL_NAMELESS (repl
) = 1;
2563 obstack_free (&name_obstack
, pretty_name
);
2565 /* Get rid of any SSA_NAMEs embedded in debug_expr,
2566 as DECL_DEBUG_EXPR isn't considered when looking for still
2567 used SSA_NAMEs and thus they could be freed. All debug info
2568 generation cares is whether something is constant or variable
2569 and that get_ref_base_and_extent works properly on the
2570 expression. It cannot handle accesses at a non-constant offset
2571 though, so just give up in those cases. */
2572 for (d
= debug_expr
;
2573 !fail
&& (handled_component_p (d
) || TREE_CODE (d
) == MEM_REF
);
2574 d
= TREE_OPERAND (d
, 0))
2575 switch (TREE_CODE (d
))
2578 case ARRAY_RANGE_REF
:
2579 if (TREE_OPERAND (d
, 1)
2580 && TREE_CODE (TREE_OPERAND (d
, 1)) != INTEGER_CST
)
2582 if (TREE_OPERAND (d
, 3)
2583 && TREE_CODE (TREE_OPERAND (d
, 3)) != INTEGER_CST
)
2587 if (TREE_OPERAND (d
, 2)
2588 && TREE_CODE (TREE_OPERAND (d
, 2)) != INTEGER_CST
)
2592 if (TREE_CODE (TREE_OPERAND (d
, 0)) != ADDR_EXPR
)
2595 d
= TREE_OPERAND (d
, 0);
2602 SET_DECL_DEBUG_EXPR (repl
, debug_expr
);
2603 DECL_HAS_DEBUG_EXPR_P (repl
) = 1;
2605 if (access
->grp_no_warning
)
2606 suppress_warning (repl
/* Be more selective! */);
2608 copy_warning (repl
, access
->base
);
2611 suppress_warning (repl
/* Be more selective! */);
2615 if (access
->grp_to_be_debug_replaced
)
2617 fprintf (dump_file
, "Created a debug-only replacement for ");
2618 print_generic_expr (dump_file
, access
->base
);
2619 fprintf (dump_file
, " offset: %u, size: %u\n",
2620 (unsigned) access
->offset
, (unsigned) access
->size
);
2624 fprintf (dump_file
, "Created a replacement for ");
2625 print_generic_expr (dump_file
, access
->base
);
2626 fprintf (dump_file
, " offset: %u, size: %u: ",
2627 (unsigned) access
->offset
, (unsigned) access
->size
);
2628 print_generic_expr (dump_file
, repl
, TDF_UID
);
2629 fprintf (dump_file
, "\n");
2632 sra_stats
.replacements
++;
2637 /* Return ACCESS scalar replacement, which must exist. */
2640 get_access_replacement (struct access
*access
)
2642 gcc_checking_assert (access
->replacement_decl
);
2643 return access
->replacement_decl
;
2647 /* Build a subtree of accesses rooted in *ACCESS, and move the pointer in the
2648 linked list along the way. Stop when *ACCESS is NULL or the access pointed
2649 to it is not "within" the root. Return false iff some accesses partially
2653 build_access_subtree (struct access
**access
)
2655 struct access
*root
= *access
, *last_child
= NULL
;
2656 HOST_WIDE_INT limit
= root
->offset
+ root
->size
;
2658 *access
= (*access
)->next_grp
;
2659 while (*access
&& (*access
)->offset
+ (*access
)->size
<= limit
)
2662 root
->first_child
= *access
;
2664 last_child
->next_sibling
= *access
;
2665 last_child
= *access
;
2666 (*access
)->parent
= root
;
2667 (*access
)->grp_write
|= root
->grp_write
;
2669 if (!build_access_subtree (access
))
2673 if (*access
&& (*access
)->offset
< limit
)
2679 /* Build a tree of access representatives, ACCESS is the pointer to the first
2680 one, others are linked in a list by the next_grp field. Return false iff
2681 some accesses partially overlap. */
2684 build_access_trees (struct access
*access
)
2688 struct access
*root
= access
;
2690 if (!build_access_subtree (&access
))
2692 root
->next_grp
= access
;
2697 /* Traverse the access forest where ROOT is the first root and verify that
2698 various important invariants hold true. */
2701 verify_sra_access_forest (struct access
*root
)
2703 struct access
*access
= root
;
2704 tree first_base
= root
->base
;
2705 gcc_assert (DECL_P (first_base
));
2708 gcc_assert (access
->base
== first_base
);
2710 gcc_assert (access
->offset
>= access
->parent
->offset
2711 && access
->size
<= access
->parent
->size
);
2712 if (access
->next_sibling
)
2713 gcc_assert (access
->next_sibling
->offset
2714 >= access
->offset
+ access
->size
);
2716 poly_int64 poffset
, psize
, pmax_size
;
2718 tree base
= get_ref_base_and_extent (access
->expr
, &poffset
, &psize
,
2719 &pmax_size
, &reverse
);
2720 HOST_WIDE_INT offset
, size
, max_size
;
2721 if (!poffset
.is_constant (&offset
)
2722 || !psize
.is_constant (&size
)
2723 || !pmax_size
.is_constant (&max_size
))
2725 gcc_assert (base
== first_base
);
2726 gcc_assert (offset
== access
->offset
);
2727 gcc_assert (access
->grp_unscalarizable_region
2728 || access
->grp_total_scalarization
2729 || size
== max_size
);
2730 gcc_assert (access
->grp_unscalarizable_region
2731 || !is_gimple_reg_type (access
->type
)
2732 || size
== access
->size
);
2733 gcc_assert (reverse
== access
->reverse
);
2735 if (access
->first_child
)
2737 gcc_assert (access
->first_child
->parent
== access
);
2738 access
= access
->first_child
;
2740 else if (access
->next_sibling
)
2742 gcc_assert (access
->next_sibling
->parent
== access
->parent
);
2743 access
= access
->next_sibling
;
2747 while (access
->parent
&& !access
->next_sibling
)
2748 access
= access
->parent
;
2749 if (access
->next_sibling
)
2750 access
= access
->next_sibling
;
2753 gcc_assert (access
== root
);
2754 root
= root
->next_grp
;
2762 /* Verify access forests of all candidates with accesses by calling
2763 verify_access_forest on each on them. */
2766 verify_all_sra_access_forests (void)
2770 EXECUTE_IF_SET_IN_BITMAP (candidate_bitmap
, 0, i
, bi
)
2772 tree var
= candidate (i
);
2773 struct access
*access
= get_first_repr_for_decl (var
);
2776 gcc_assert (access
->base
== var
);
2777 verify_sra_access_forest (access
);
2782 /* Return true if expr contains some ARRAY_REFs into a variable bounded
2786 expr_with_var_bounded_array_refs_p (tree expr
)
2788 while (handled_component_p (expr
))
2790 if (TREE_CODE (expr
) == ARRAY_REF
2791 && !tree_fits_shwi_p (array_ref_low_bound (expr
)))
2793 expr
= TREE_OPERAND (expr
, 0);
2798 /* Analyze the subtree of accesses rooted in ROOT, scheduling replacements when
2799 both seeming beneficial and when ALLOW_REPLACEMENTS allows it. If TOTALLY
2800 is set, we are totally scalarizing the aggregate. Also set all sorts of
2801 access flags appropriately along the way, notably always set grp_read and
2802 grp_assign_read according to MARK_READ and grp_write when MARK_WRITE is
2805 Creating a replacement for a scalar access is considered beneficial if its
2806 grp_hint ot TOTALLY is set (this means either that there is more than one
2807 direct read access or that we are attempting total scalarization) or
2808 according to the following table:
2810 Access written to through a scalar type (once or more times)
2812 | Written to in an assignment statement
2814 | | Access read as scalar _once_
2816 | | | Read in an assignment statement
2818 | | | | Scalarize Comment
2819 -----------------------------------------------------------------------------
2820 0 0 0 0 No access for the scalar
2821 0 0 0 1 No access for the scalar
2822 0 0 1 0 No Single read - won't help
2823 0 0 1 1 No The same case
2824 0 1 0 0 No access for the scalar
2825 0 1 0 1 No access for the scalar
2826 0 1 1 0 Yes s = *g; return s.i;
2827 0 1 1 1 Yes The same case as above
2828 1 0 0 0 No Won't help
2829 1 0 0 1 Yes s.i = 1; *g = s;
2830 1 0 1 0 Yes s.i = 5; g = s.i;
2831 1 0 1 1 Yes The same case as above
2832 1 1 0 0 No Won't help.
2833 1 1 0 1 Yes s.i = 1; *g = s;
2834 1 1 1 0 Yes s = *g; return s.i;
2835 1 1 1 1 Yes Any of the above yeses */
2838 analyze_access_subtree (struct access
*root
, struct access
*parent
,
2839 bool allow_replacements
, bool totally
)
2841 struct access
*child
;
2842 HOST_WIDE_INT limit
= root
->offset
+ root
->size
;
2843 HOST_WIDE_INT covered_to
= root
->offset
;
2844 bool scalar
= is_gimple_reg_type (root
->type
);
2845 bool hole
= false, sth_created
= false;
2849 if (parent
->grp_read
)
2851 if (parent
->grp_assignment_read
)
2852 root
->grp_assignment_read
= 1;
2853 if (parent
->grp_write
)
2854 root
->grp_write
= 1;
2855 if (parent
->grp_assignment_write
)
2856 root
->grp_assignment_write
= 1;
2857 if (!parent
->grp_same_access_path
)
2858 root
->grp_same_access_path
= 0;
2861 if (root
->grp_unscalarizable_region
)
2862 allow_replacements
= false;
2864 if (allow_replacements
&& expr_with_var_bounded_array_refs_p (root
->expr
))
2865 allow_replacements
= false;
2867 if (!totally
&& root
->grp_result_of_prop_from_lhs
)
2868 allow_replacements
= false;
2870 for (child
= root
->first_child
; child
; child
= child
->next_sibling
)
2872 hole
|= covered_to
< child
->offset
;
2873 sth_created
|= analyze_access_subtree (child
, root
,
2874 allow_replacements
&& !scalar
2875 && !root
->grp_partial_lhs
,
2878 root
->grp_unscalarized_data
|= child
->grp_unscalarized_data
;
2879 if (child
->grp_covered
)
2880 covered_to
+= child
->size
;
2885 if (allow_replacements
&& scalar
&& !root
->first_child
2886 && (totally
|| !root
->grp_total_scalarization
)
2889 || ((root
->grp_scalar_read
|| root
->grp_assignment_read
)
2890 && (root
->grp_scalar_write
|| root
->grp_assignment_write
))))
2892 /* Always create access replacements that cover the whole access.
2893 For integral types this means the precision has to match.
2894 Avoid assumptions based on the integral type kind, too. */
2895 if (INTEGRAL_TYPE_P (root
->type
)
2896 && ((TREE_CODE (root
->type
) != INTEGER_TYPE
2897 && TREE_CODE (root
->type
) != BITINT_TYPE
)
2898 || TYPE_PRECISION (root
->type
) != root
->size
)
2899 /* But leave bitfield accesses alone. */
2900 && (TREE_CODE (root
->expr
) != COMPONENT_REF
2901 || !DECL_BIT_FIELD (TREE_OPERAND (root
->expr
, 1))))
2903 tree rt
= root
->type
;
2904 gcc_assert ((root
->offset
% BITS_PER_UNIT
) == 0
2905 && (root
->size
% BITS_PER_UNIT
) == 0);
2906 if (TREE_CODE (root
->type
) == BITINT_TYPE
)
2907 root
->type
= build_bitint_type (root
->size
, TYPE_UNSIGNED (rt
));
2909 root
->type
= build_nonstandard_integer_type (root
->size
,
2910 TYPE_UNSIGNED (rt
));
2911 root
->expr
= build_ref_for_offset (UNKNOWN_LOCATION
, root
->base
,
2912 root
->offset
, root
->reverse
,
2913 root
->type
, NULL
, false);
2915 if (dump_file
&& (dump_flags
& TDF_DETAILS
))
2917 fprintf (dump_file
, "Changing the type of a replacement for ");
2918 print_generic_expr (dump_file
, root
->base
);
2919 fprintf (dump_file
, " offset: %u, size: %u ",
2920 (unsigned) root
->offset
, (unsigned) root
->size
);
2921 fprintf (dump_file
, " to an integer.\n");
2925 root
->grp_to_be_replaced
= 1;
2926 root
->replacement_decl
= create_access_replacement (root
);
2932 if (allow_replacements
2933 && scalar
&& !root
->first_child
2934 && !root
->grp_total_scalarization
2935 && (root
->grp_scalar_write
|| root
->grp_assignment_write
)
2936 && !bitmap_bit_p (cannot_scalarize_away_bitmap
,
2937 DECL_UID (root
->base
)))
2939 gcc_checking_assert (!root
->grp_scalar_read
2940 && !root
->grp_assignment_read
);
2942 if (MAY_HAVE_DEBUG_BIND_STMTS
)
2944 root
->grp_to_be_debug_replaced
= 1;
2945 root
->replacement_decl
= create_access_replacement (root
);
2949 if (covered_to
< limit
)
2951 if (scalar
|| !allow_replacements
)
2952 root
->grp_total_scalarization
= 0;
2955 if (!hole
|| totally
)
2956 root
->grp_covered
= 1;
2957 else if (root
->grp_write
|| comes_initialized_p (root
->base
))
2958 root
->grp_unscalarized_data
= 1; /* not covered and written to */
2962 /* Analyze all access trees linked by next_grp by the means of
2963 analyze_access_subtree. */
2965 analyze_access_trees (struct access
*access
)
2971 if (analyze_access_subtree (access
, NULL
, true,
2972 access
->grp_total_scalarization
))
2974 access
= access
->next_grp
;
2980 /* Return true iff a potential new child of ACC at offset OFFSET and with size
2981 SIZE would conflict with an already existing one. If exactly such a child
2982 already exists in ACC, store a pointer to it in EXACT_MATCH. */
2985 child_would_conflict_in_acc (struct access
*acc
, HOST_WIDE_INT norm_offset
,
2986 HOST_WIDE_INT size
, struct access
**exact_match
)
2988 struct access
*child
;
2990 for (child
= acc
->first_child
; child
; child
= child
->next_sibling
)
2992 if (child
->offset
== norm_offset
&& child
->size
== size
)
2994 *exact_match
= child
;
2998 if (child
->offset
< norm_offset
+ size
2999 && child
->offset
+ child
->size
> norm_offset
)
3006 /* Create a new child access of PARENT, with all properties just like MODEL
3007 except for its offset and with its grp_write false and grp_read true.
3008 Return the new access or NULL if it cannot be created. Note that this
3009 access is created long after all splicing and sorting, it's not located in
3010 any access vector and is automatically a representative of its group. Set
3011 the gpr_write flag of the new accesss if SET_GRP_WRITE is true. */
3013 static struct access
*
3014 create_artificial_child_access (struct access
*parent
, struct access
*model
,
3015 HOST_WIDE_INT new_offset
,
3016 bool set_grp_read
, bool set_grp_write
)
3018 struct access
**child
;
3019 tree expr
= parent
->base
;
3021 gcc_assert (!model
->grp_unscalarizable_region
);
3023 struct access
*access
= access_pool
.allocate ();
3024 memset (access
, 0, sizeof (struct access
));
3025 if (!build_user_friendly_ref_for_offset (&expr
, TREE_TYPE (expr
), new_offset
,
3028 access
->grp_no_warning
= true;
3029 expr
= build_ref_for_model (EXPR_LOCATION (parent
->base
), parent
->base
,
3030 new_offset
, model
, NULL
, false);
3033 access
->base
= parent
->base
;
3034 access
->expr
= expr
;
3035 access
->offset
= new_offset
;
3036 access
->size
= model
->size
;
3037 access
->type
= model
->type
;
3038 access
->parent
= parent
;
3039 access
->grp_read
= set_grp_read
;
3040 access
->grp_write
= set_grp_write
;
3041 access
->reverse
= model
->reverse
;
3043 child
= &parent
->first_child
;
3044 while (*child
&& (*child
)->offset
< new_offset
)
3045 child
= &(*child
)->next_sibling
;
3047 access
->next_sibling
= *child
;
3054 /* Beginning with ACCESS, traverse its whole access subtree and mark all
3055 sub-trees as written to. If any of them has not been marked so previously
3056 and has assignment links leading from it, re-enqueue it. */
3059 subtree_mark_written_and_rhs_enqueue (struct access
*access
)
3061 if (access
->grp_write
)
3063 access
->grp_write
= true;
3064 add_access_to_rhs_work_queue (access
);
3066 struct access
*child
;
3067 for (child
= access
->first_child
; child
; child
= child
->next_sibling
)
3068 subtree_mark_written_and_rhs_enqueue (child
);
3071 /* If there is still budget to create a propagation access for DECL, return
3072 true and decrement the budget. Otherwise return false. */
3075 budget_for_propagation_access (tree decl
)
3077 unsigned b
, *p
= propagation_budget
->get (decl
);
3081 b
= param_sra_max_propagations
;
3087 if (b
== 0 && dump_file
&& (dump_flags
& TDF_DETAILS
))
3089 fprintf (dump_file
, "The propagation budget of ");
3090 print_generic_expr (dump_file
, decl
);
3091 fprintf (dump_file
, " (UID: %u) has been exhausted.\n", DECL_UID (decl
));
3093 propagation_budget
->put (decl
, b
);
3097 /* Return true if ACC or any of its subaccesses has grp_child set. */
3100 access_or_its_child_written (struct access
*acc
)
3104 for (struct access
*sub
= acc
->first_child
; sub
; sub
= sub
->next_sibling
)
3105 if (access_or_its_child_written (sub
))
3110 /* Propagate subaccesses and grp_write flags of RACC across an assignment link
3111 to LACC. Enqueue sub-accesses as necessary so that the write flag is
3112 propagated transitively. Return true if anything changed. Additionally, if
3113 RACC is a scalar access but LACC is not, change the type of the latter, if
3117 propagate_subaccesses_from_rhs (struct access
*lacc
, struct access
*racc
)
3119 struct access
*rchild
;
3120 HOST_WIDE_INT norm_delta
= lacc
->offset
- racc
->offset
;
3123 /* IF the LHS is still not marked as being written to, we only need to do so
3124 if the RHS at this level actually was. */
3125 if (!lacc
->grp_write
)
3127 gcc_checking_assert (!comes_initialized_p (racc
->base
));
3128 if (racc
->grp_write
)
3130 subtree_mark_written_and_rhs_enqueue (lacc
);
3135 if (is_gimple_reg_type (lacc
->type
)
3136 || lacc
->grp_unscalarizable_region
3137 || racc
->grp_unscalarizable_region
)
3139 if (!lacc
->grp_write
)
3142 subtree_mark_written_and_rhs_enqueue (lacc
);
3147 if (is_gimple_reg_type (racc
->type
))
3149 if (!lacc
->grp_write
)
3152 subtree_mark_written_and_rhs_enqueue (lacc
);
3154 if (!lacc
->first_child
3155 && !racc
->first_child
3156 && !types_risk_mangled_binary_repr_p (racc
->type
, lacc
->type
))
3158 /* We are about to change the access type from aggregate to scalar,
3159 so we need to put the reverse flag onto the access, if any. */
3161 = TYPE_REVERSE_STORAGE_ORDER (lacc
->type
)
3162 && !POINTER_TYPE_P (racc
->type
)
3163 && !VECTOR_TYPE_P (racc
->type
);
3164 tree t
= lacc
->base
;
3166 lacc
->type
= racc
->type
;
3167 if (build_user_friendly_ref_for_offset (&t
, TREE_TYPE (t
),
3168 lacc
->offset
, racc
->type
))
3171 lacc
->grp_same_access_path
= true;
3175 lacc
->expr
= build_ref_for_model (EXPR_LOCATION (lacc
->base
),
3176 lacc
->base
, lacc
->offset
,
3178 if (TREE_CODE (lacc
->expr
) == MEM_REF
)
3179 REF_REVERSE_STORAGE_ORDER (lacc
->expr
) = reverse
;
3180 lacc
->grp_no_warning
= true;
3181 lacc
->grp_same_access_path
= false;
3183 lacc
->reverse
= reverse
;
3188 for (rchild
= racc
->first_child
; rchild
; rchild
= rchild
->next_sibling
)
3190 struct access
*new_acc
= NULL
;
3191 HOST_WIDE_INT norm_offset
= rchild
->offset
+ norm_delta
;
3193 if (child_would_conflict_in_acc (lacc
, norm_offset
, rchild
->size
,
3198 if (!new_acc
->grp_write
&& rchild
->grp_write
)
3200 gcc_assert (!lacc
->grp_write
);
3201 subtree_mark_written_and_rhs_enqueue (new_acc
);
3205 rchild
->grp_hint
= 1;
3206 new_acc
->grp_hint
|= new_acc
->grp_read
;
3207 if (rchild
->first_child
3208 && propagate_subaccesses_from_rhs (new_acc
, rchild
))
3211 add_access_to_rhs_work_queue (new_acc
);
3216 if (!lacc
->grp_write
)
3219 subtree_mark_written_and_rhs_enqueue (lacc
);
3225 if (rchild
->grp_unscalarizable_region
3226 || !budget_for_propagation_access (lacc
->base
))
3228 if (!lacc
->grp_write
&& access_or_its_child_written (rchild
))
3231 subtree_mark_written_and_rhs_enqueue (lacc
);
3236 rchild
->grp_hint
= 1;
3237 /* Because get_ref_base_and_extent always includes padding in size for
3238 accesses to DECLs but not necessarily for COMPONENT_REFs of the same
3239 type, we might be actually attempting to here to create a child of the
3240 same type as the parent. */
3241 if (!types_compatible_p (lacc
->type
, rchild
->type
))
3242 new_acc
= create_artificial_child_access (lacc
, rchild
, norm_offset
,
3245 || rchild
->grp_write
));
3248 gcc_checking_assert (new_acc
);
3249 if (racc
->first_child
)
3250 propagate_subaccesses_from_rhs (new_acc
, rchild
);
3252 add_access_to_rhs_work_queue (lacc
);
3259 /* Propagate subaccesses of LACC across an assignment link to RACC if they
3260 should inhibit total scalarization of the corresponding area. No flags are
3261 being propagated in the process. Return true if anything changed. */
3264 propagate_subaccesses_from_lhs (struct access
*lacc
, struct access
*racc
)
3266 if (is_gimple_reg_type (racc
->type
)
3267 || lacc
->grp_unscalarizable_region
3268 || racc
->grp_unscalarizable_region
)
3271 /* TODO: Do we want set some new racc flag to stop potential total
3272 scalarization if lacc is a scalar access (and none fo the two have
3276 HOST_WIDE_INT norm_delta
= racc
->offset
- lacc
->offset
;
3277 for (struct access
*lchild
= lacc
->first_child
;
3279 lchild
= lchild
->next_sibling
)
3281 struct access
*matching_acc
= NULL
;
3282 HOST_WIDE_INT norm_offset
= lchild
->offset
+ norm_delta
;
3284 if (lchild
->grp_unscalarizable_region
3285 || child_would_conflict_in_acc (racc
, norm_offset
, lchild
->size
,
3287 || !budget_for_propagation_access (racc
->base
))
3290 && propagate_subaccesses_from_lhs (lchild
, matching_acc
))
3291 add_access_to_lhs_work_queue (matching_acc
);
3295 /* Because get_ref_base_and_extent always includes padding in size for
3296 accesses to DECLs but not necessarily for COMPONENT_REFs of the same
3297 type, we might be actually attempting to here to create a child of the
3298 same type as the parent. */
3299 if (!types_compatible_p (racc
->type
, lchild
->type
))
3301 struct access
*new_acc
3302 = create_artificial_child_access (racc
, lchild
, norm_offset
,
3304 new_acc
->grp_result_of_prop_from_lhs
= 1;
3305 propagate_subaccesses_from_lhs (lchild
, new_acc
);
3308 propagate_subaccesses_from_lhs (lchild
, racc
);
3314 /* Propagate all subaccesses across assignment links. */
3317 propagate_all_subaccesses (void)
3319 propagation_budget
= new hash_map
<tree
, unsigned>;
3320 while (rhs_work_queue_head
)
3322 struct access
*racc
= pop_access_from_rhs_work_queue ();
3323 struct assign_link
*link
;
3325 if (racc
->group_representative
)
3326 racc
= racc
->group_representative
;
3327 gcc_assert (racc
->first_rhs_link
);
3329 for (link
= racc
->first_rhs_link
; link
; link
= link
->next_rhs
)
3331 struct access
*lacc
= link
->lacc
;
3333 if (!bitmap_bit_p (candidate_bitmap
, DECL_UID (lacc
->base
)))
3335 lacc
= lacc
->group_representative
;
3337 bool reque_parents
= false;
3338 if (!bitmap_bit_p (candidate_bitmap
, DECL_UID (racc
->base
)))
3340 if (!lacc
->grp_write
)
3342 subtree_mark_written_and_rhs_enqueue (lacc
);
3343 reque_parents
= true;
3346 else if (propagate_subaccesses_from_rhs (lacc
, racc
))
3347 reque_parents
= true;
3352 add_access_to_rhs_work_queue (lacc
);
3353 lacc
= lacc
->parent
;
3359 while (lhs_work_queue_head
)
3361 struct access
*lacc
= pop_access_from_lhs_work_queue ();
3362 struct assign_link
*link
;
3364 if (lacc
->group_representative
)
3365 lacc
= lacc
->group_representative
;
3366 gcc_assert (lacc
->first_lhs_link
);
3368 if (!bitmap_bit_p (candidate_bitmap
, DECL_UID (lacc
->base
)))
3371 for (link
= lacc
->first_lhs_link
; link
; link
= link
->next_lhs
)
3373 struct access
*racc
= link
->racc
;
3375 if (racc
->group_representative
)
3376 racc
= racc
->group_representative
;
3377 if (!bitmap_bit_p (candidate_bitmap
, DECL_UID (racc
->base
)))
3379 if (propagate_subaccesses_from_lhs (lacc
, racc
))
3380 add_access_to_lhs_work_queue (racc
);
3383 delete propagation_budget
;
3386 /* Return true if the forest beginning with ROOT does not contain
3387 unscalarizable regions or non-byte aligned accesses. */
3390 can_totally_scalarize_forest_p (struct access
*root
)
3392 struct access
*access
= root
;
3395 if (access
->grp_unscalarizable_region
3396 || (access
->offset
% BITS_PER_UNIT
) != 0
3397 || (access
->size
% BITS_PER_UNIT
) != 0
3398 || (is_gimple_reg_type (access
->type
)
3399 && access
->first_child
))
3402 if (access
->first_child
)
3403 access
= access
->first_child
;
3404 else if (access
->next_sibling
)
3405 access
= access
->next_sibling
;
3408 while (access
->parent
&& !access
->next_sibling
)
3409 access
= access
->parent
;
3410 if (access
->next_sibling
)
3411 access
= access
->next_sibling
;
3414 gcc_assert (access
== root
);
3415 root
= root
->next_grp
;
3424 /* Create and return an ACCESS in PARENT spanning from POS with SIZE, TYPE and
3425 reference EXPR for total scalarization purposes and mark it as such. Within
3426 the children of PARENT, link it in between PTR and NEXT_SIBLING. */
3428 static struct access
*
3429 create_total_scalarization_access (struct access
*parent
, HOST_WIDE_INT pos
,
3430 HOST_WIDE_INT size
, tree type
, tree expr
,
3431 struct access
**ptr
,
3432 struct access
*next_sibling
)
3434 struct access
*access
= access_pool
.allocate ();
3435 memset (access
, 0, sizeof (struct access
));
3436 access
->base
= parent
->base
;
3437 access
->offset
= pos
;
3438 access
->size
= size
;
3439 access
->expr
= expr
;
3440 access
->type
= type
;
3441 access
->parent
= parent
;
3442 access
->grp_write
= parent
->grp_write
;
3443 access
->grp_total_scalarization
= 1;
3444 access
->grp_hint
= 1;
3445 access
->grp_same_access_path
= path_comparable_for_same_access (expr
);
3446 access
->reverse
= reverse_storage_order_for_component_p (expr
);
3448 access
->next_sibling
= next_sibling
;
3453 /* Create and return an ACCESS in PARENT spanning from POS with SIZE, TYPE and
3454 reference EXPR for total scalarization purposes and mark it as such, link it
3455 at *PTR and reshape the tree so that those elements at *PTR and their
3456 siblings which fall within the part described by POS and SIZE are moved to
3457 be children of the new access. If a partial overlap is detected, return
3460 static struct access
*
3461 create_total_access_and_reshape (struct access
*parent
, HOST_WIDE_INT pos
,
3462 HOST_WIDE_INT size
, tree type
, tree expr
,
3463 struct access
**ptr
)
3465 struct access
**p
= ptr
;
3467 while (*p
&& (*p
)->offset
< pos
+ size
)
3469 if ((*p
)->offset
+ (*p
)->size
> pos
+ size
)
3471 p
= &(*p
)->next_sibling
;
3474 struct access
*next_child
= *ptr
;
3475 struct access
*new_acc
3476 = create_total_scalarization_access (parent
, pos
, size
, type
, expr
,
3480 new_acc
->first_child
= next_child
;
3482 for (struct access
*a
= next_child
; a
; a
= a
->next_sibling
)
3483 a
->parent
= new_acc
;
3488 static bool totally_scalarize_subtree (struct access
*root
);
3490 /* Return true if INNER is either the same type as OUTER or if it is the type
3491 of a record field in OUTER at offset zero, possibly in nested
3495 access_and_field_type_match_p (tree outer
, tree inner
)
3497 if (TYPE_MAIN_VARIANT (outer
) == TYPE_MAIN_VARIANT (inner
))
3499 if (TREE_CODE (outer
) != RECORD_TYPE
)
3501 tree fld
= TYPE_FIELDS (outer
);
3504 if (TREE_CODE (fld
) == FIELD_DECL
)
3506 if (!zerop (DECL_FIELD_OFFSET (fld
)))
3508 if (TYPE_MAIN_VARIANT (TREE_TYPE (fld
)) == inner
)
3510 if (TREE_CODE (TREE_TYPE (fld
)) == RECORD_TYPE
)
3511 fld
= TYPE_FIELDS (TREE_TYPE (fld
));
3516 fld
= DECL_CHAIN (fld
);
3521 /* Return type of total_should_skip_creating_access indicating whether a total
3522 scalarization access for a field/element should be created, whether it
3523 already exists or whether the entire total scalarization has to fail. */
3525 enum total_sra_field_state
{TOTAL_FLD_CREATE
, TOTAL_FLD_DONE
, TOTAL_FLD_FAILED
};
3527 /* Do all the necessary steps in total scalarization when the given aggregate
3528 type has a TYPE at POS with the given SIZE should be put into PARENT and
3529 when we have processed all its siblings with smaller offsets up until and
3530 including LAST_SEEN_SIBLING (which can be NULL).
3532 If some further siblings are to be skipped, set *LAST_SEEN_SIBLING as
3533 appropriate. Return TOTAL_FLD_CREATE id the caller should carry on with
3534 creating a new access, TOTAL_FLD_DONE if access or accesses capable of
3535 representing the described part of the aggregate for the purposes of total
3536 scalarization already exist or TOTAL_FLD_FAILED if there is a problem which
3537 prevents total scalarization from happening at all. */
3539 static enum total_sra_field_state
3540 total_should_skip_creating_access (struct access
*parent
,
3541 struct access
**last_seen_sibling
,
3542 tree type
, HOST_WIDE_INT pos
,
3545 struct access
*next_child
;
3546 if (!*last_seen_sibling
)
3547 next_child
= parent
->first_child
;
3549 next_child
= (*last_seen_sibling
)->next_sibling
;
3551 /* First, traverse the chain of siblings until it points to an access with
3552 offset at least equal to POS. Check all skipped accesses whether they
3553 span the POS boundary and if so, return with a failure. */
3554 while (next_child
&& next_child
->offset
< pos
)
3556 if (next_child
->offset
+ next_child
->size
> pos
)
3557 return TOTAL_FLD_FAILED
;
3558 *last_seen_sibling
= next_child
;
3559 next_child
= next_child
->next_sibling
;
3562 /* Now check whether next_child has exactly the right POS and SIZE and if so,
3563 whether it can represent what we need and can be totally scalarized
3565 if (next_child
&& next_child
->offset
== pos
3566 && next_child
->size
== size
)
3568 if (!is_gimple_reg_type (next_child
->type
)
3569 && (!access_and_field_type_match_p (type
, next_child
->type
)
3570 || !totally_scalarize_subtree (next_child
)))
3571 return TOTAL_FLD_FAILED
;
3573 *last_seen_sibling
= next_child
;
3574 return TOTAL_FLD_DONE
;
3577 /* If the child we're looking at would partially overlap, we just cannot
3578 totally scalarize. */
3580 && next_child
->offset
< pos
+ size
3581 && next_child
->offset
+ next_child
->size
> pos
+ size
)
3582 return TOTAL_FLD_FAILED
;
3584 if (is_gimple_reg_type (type
))
3586 /* We don't scalarize accesses that are children of other scalar type
3587 accesses, so if we go on and create an access for a register type,
3588 there should not be any pre-existing children. There are rare cases
3589 where the requested type is a vector but we already have register
3590 accesses for all its elements which is equally good. Detect that
3591 situation or whether we need to bail out. */
3593 HOST_WIDE_INT covered
= pos
;
3594 bool skipping
= false;
3596 && next_child
->offset
+ next_child
->size
<= pos
+ size
)
3598 if (next_child
->offset
!= covered
3599 || !is_gimple_reg_type (next_child
->type
))
3600 return TOTAL_FLD_FAILED
;
3602 covered
+= next_child
->size
;
3603 *last_seen_sibling
= next_child
;
3604 next_child
= next_child
->next_sibling
;
3610 if (covered
!= pos
+ size
)
3611 return TOTAL_FLD_FAILED
;
3613 return TOTAL_FLD_DONE
;
3617 return TOTAL_FLD_CREATE
;
3620 /* Go over sub-tree rooted in ROOT and attempt to create scalar accesses
3621 spanning all uncovered areas covered by ROOT, return false if the attempt
3622 failed. All created accesses will have grp_unscalarizable_region set (and
3623 should be ignored if the function returns false). */
3626 totally_scalarize_subtree (struct access
*root
)
3628 gcc_checking_assert (!root
->grp_unscalarizable_region
);
3629 gcc_checking_assert (!is_gimple_reg_type (root
->type
));
3631 struct access
*last_seen_sibling
= NULL
;
3633 switch (TREE_CODE (root
->type
))
3636 for (tree fld
= TYPE_FIELDS (root
->type
); fld
; fld
= DECL_CHAIN (fld
))
3637 if (TREE_CODE (fld
) == FIELD_DECL
)
3639 tree ft
= TREE_TYPE (fld
);
3640 HOST_WIDE_INT fsize
= tree_to_uhwi (DECL_SIZE (fld
));
3644 HOST_WIDE_INT pos
= root
->offset
+ int_bit_position (fld
);
3645 if (pos
+ fsize
> root
->offset
+ root
->size
)
3647 enum total_sra_field_state
3648 state
= total_should_skip_creating_access (root
,
3653 case TOTAL_FLD_FAILED
:
3655 case TOTAL_FLD_DONE
:
3657 case TOTAL_FLD_CREATE
:
3663 struct access
**p
= (last_seen_sibling
3664 ? &last_seen_sibling
->next_sibling
3665 : &root
->first_child
);
3666 tree nref
= build3 (COMPONENT_REF
, ft
, root
->expr
, fld
, NULL_TREE
);
3667 struct access
*new_child
3668 = create_total_access_and_reshape (root
, pos
, fsize
, ft
, nref
, p
);
3672 if (!is_gimple_reg_type (ft
)
3673 && !totally_scalarize_subtree (new_child
))
3675 last_seen_sibling
= new_child
;
3680 tree elemtype
= TREE_TYPE (root
->type
);
3681 HOST_WIDE_INT el_size
;
3682 offset_int idx
, max
;
3683 if (!prepare_iteration_over_array_elts (root
->type
, &el_size
,
3687 for (HOST_WIDE_INT pos
= root
->offset
;
3689 pos
+= el_size
, ++idx
)
3691 enum total_sra_field_state
3692 state
= total_should_skip_creating_access (root
,
3698 case TOTAL_FLD_FAILED
:
3700 case TOTAL_FLD_DONE
:
3702 case TOTAL_FLD_CREATE
:
3708 struct access
**p
= (last_seen_sibling
3709 ? &last_seen_sibling
->next_sibling
3710 : &root
->first_child
);
3711 tree nref
= build4 (ARRAY_REF
, elemtype
, root
->expr
,
3712 wide_int_to_tree (TYPE_DOMAIN (root
->type
),
3714 NULL_TREE
, NULL_TREE
);
3715 struct access
*new_child
3716 = create_total_access_and_reshape (root
, pos
, el_size
, elemtype
,
3721 if (!is_gimple_reg_type (elemtype
)
3722 && !totally_scalarize_subtree (new_child
))
3724 last_seen_sibling
= new_child
;
3734 /* Get the total total scalarization size limit in the current function. */
3736 unsigned HOST_WIDE_INT
3737 sra_get_max_scalarization_size (void)
3739 bool optimize_speed_p
= !optimize_function_for_size_p (cfun
);
3740 /* If the user didn't set PARAM_SRA_MAX_SCALARIZATION_SIZE_<...>,
3741 fall back to a target default. */
3742 unsigned HOST_WIDE_INT max_scalarization_size
3743 = get_move_ratio (optimize_speed_p
) * UNITS_PER_WORD
;
3745 if (optimize_speed_p
)
3747 if (OPTION_SET_P (param_sra_max_scalarization_size_speed
))
3748 max_scalarization_size
= param_sra_max_scalarization_size_speed
;
3752 if (OPTION_SET_P (param_sra_max_scalarization_size_size
))
3753 max_scalarization_size
= param_sra_max_scalarization_size_size
;
3755 max_scalarization_size
*= BITS_PER_UNIT
;
3756 return max_scalarization_size
;
3759 /* Go through all accesses collected throughout the (intraprocedural) analysis
3760 stage, exclude overlapping ones, identify representatives and build trees
3761 out of them, making decisions about scalarization on the way. Return true
3762 iff there are any to-be-scalarized variables after this stage. */
3765 analyze_all_variable_accesses (void)
3768 bitmap tmp
= BITMAP_ALLOC (NULL
);
3772 bitmap_copy (tmp
, candidate_bitmap
);
3773 EXECUTE_IF_SET_IN_BITMAP (tmp
, 0, i
, bi
)
3775 tree var
= candidate (i
);
3776 struct access
*access
;
3778 access
= sort_and_splice_var_accesses (var
);
3779 if (!access
|| !build_access_trees (access
))
3780 disqualify_candidate (var
,
3781 "No or inhibitingly overlapping accesses.");
3784 propagate_all_subaccesses ();
3786 unsigned HOST_WIDE_INT max_scalarization_size
3787 = sra_get_max_scalarization_size ();
3788 EXECUTE_IF_SET_IN_BITMAP (candidate_bitmap
, 0, i
, bi
)
3789 if (bitmap_bit_p (should_scalarize_away_bitmap
, i
)
3790 && !bitmap_bit_p (cannot_scalarize_away_bitmap
, i
))
3792 tree var
= candidate (i
);
3796 if (tree_to_uhwi (TYPE_SIZE (TREE_TYPE (var
))) > max_scalarization_size
)
3798 if (dump_file
&& (dump_flags
& TDF_DETAILS
))
3800 fprintf (dump_file
, "Too big to totally scalarize: ");
3801 print_generic_expr (dump_file
, var
);
3802 fprintf (dump_file
, " (UID: %u)\n", DECL_UID (var
));
3807 bool all_types_ok
= true;
3808 for (struct access
*access
= get_first_repr_for_decl (var
);
3810 access
= access
->next_grp
)
3811 if (!can_totally_scalarize_forest_p (access
)
3812 || !totally_scalarizable_type_p (access
->type
,
3813 constant_decl_p (var
),
3816 all_types_ok
= false;
3822 if (dump_file
&& (dump_flags
& TDF_DETAILS
))
3824 fprintf (dump_file
, "Will attempt to totally scalarize ");
3825 print_generic_expr (dump_file
, var
);
3826 fprintf (dump_file
, " (UID: %u): \n", DECL_UID (var
));
3828 bool scalarized
= true;
3829 for (struct access
*access
= get_first_repr_for_decl (var
);
3831 access
= access
->next_grp
)
3832 if (!is_gimple_reg_type (access
->type
)
3833 && !totally_scalarize_subtree (access
))
3840 for (struct access
*access
= get_first_repr_for_decl (var
);
3842 access
= access
->next_grp
)
3843 access
->grp_total_scalarization
= true;
3847 verify_all_sra_access_forests ();
3849 bitmap_copy (tmp
, candidate_bitmap
);
3850 EXECUTE_IF_SET_IN_BITMAP (tmp
, 0, i
, bi
)
3852 tree var
= candidate (i
);
3853 struct access
*access
= get_first_repr_for_decl (var
);
3855 if (analyze_access_trees (access
))
3858 if (dump_file
&& (dump_flags
& TDF_DETAILS
))
3860 fprintf (dump_file
, "\nAccess trees for ");
3861 print_generic_expr (dump_file
, var
);
3862 fprintf (dump_file
, " (UID: %u): \n", DECL_UID (var
));
3863 dump_access_tree (dump_file
, access
);
3864 fprintf (dump_file
, "\n");
3868 disqualify_candidate (var
, "No scalar replacements to be created.");
3875 statistics_counter_event (cfun
, "Scalarized aggregates", res
);
3882 /* Generate statements copying scalar replacements of accesses within a subtree
3883 into or out of AGG. ACCESS, all its children, siblings and their children
3884 are to be processed. AGG is an aggregate type expression (can be a
3885 declaration but does not have to be, it can for example also be a mem_ref or
3886 a series of handled components). TOP_OFFSET is the offset of the processed
3887 subtree which has to be subtracted from offsets of individual accesses to
3888 get corresponding offsets for AGG. If CHUNK_SIZE is non-null, copy only
3889 replacements in the interval <start_offset, start_offset + chunk_size>,
3890 otherwise copy all. GSI is a statement iterator used to place the new
3891 statements. WRITE should be true when the statements should write from AGG
3892 to the replacement and false if vice versa. if INSERT_AFTER is true, new
3893 statements will be added after the current statement in GSI, they will be
3894 added before the statement otherwise. */
3897 generate_subtree_copies (struct access
*access
, tree agg
,
3898 HOST_WIDE_INT top_offset
,
3899 HOST_WIDE_INT start_offset
, HOST_WIDE_INT chunk_size
,
3900 gimple_stmt_iterator
*gsi
, bool write
,
3901 bool insert_after
, location_t loc
)
3903 /* Never write anything into constant pool decls. See PR70602. */
3904 if (!write
&& constant_decl_p (agg
))
3908 if (chunk_size
&& access
->offset
>= start_offset
+ chunk_size
)
3911 if (access
->grp_to_be_replaced
3913 || access
->offset
+ access
->size
> start_offset
))
3915 tree expr
, repl
= get_access_replacement (access
);
3918 expr
= build_ref_for_model (loc
, agg
, access
->offset
- top_offset
,
3919 access
, gsi
, insert_after
);
3923 if (access
->grp_partial_lhs
)
3924 expr
= force_gimple_operand_gsi (gsi
, expr
, true, NULL_TREE
,
3926 insert_after
? GSI_NEW_STMT
3928 stmt
= gimple_build_assign (repl
, expr
);
3932 suppress_warning (repl
/* Be more selective! */);
3933 if (access
->grp_partial_lhs
)
3934 repl
= force_gimple_operand_gsi (gsi
, repl
, true, NULL_TREE
,
3936 insert_after
? GSI_NEW_STMT
3938 stmt
= gimple_build_assign (expr
, repl
);
3940 gimple_set_location (stmt
, loc
);
3943 gsi_insert_after (gsi
, stmt
, GSI_NEW_STMT
);
3945 gsi_insert_before (gsi
, stmt
, GSI_SAME_STMT
);
3947 sra_stats
.subtree_copies
++;
3950 && access
->grp_to_be_debug_replaced
3952 || access
->offset
+ access
->size
> start_offset
))
3955 tree drhs
= build_debug_ref_for_model (loc
, agg
,
3956 access
->offset
- top_offset
,
3958 ds
= gimple_build_debug_bind (get_access_replacement (access
),
3959 drhs
, gsi_stmt (*gsi
));
3961 gsi_insert_after (gsi
, ds
, GSI_NEW_STMT
);
3963 gsi_insert_before (gsi
, ds
, GSI_SAME_STMT
);
3966 if (access
->first_child
)
3967 generate_subtree_copies (access
->first_child
, agg
, top_offset
,
3968 start_offset
, chunk_size
, gsi
,
3969 write
, insert_after
, loc
);
3971 access
= access
->next_sibling
;
3976 /* Assign zero to all scalar replacements in an access subtree. ACCESS is the
3977 root of the subtree to be processed. GSI is the statement iterator used
3978 for inserting statements which are added after the current statement if
3979 INSERT_AFTER is true or before it otherwise. */
3982 init_subtree_with_zero (struct access
*access
, gimple_stmt_iterator
*gsi
,
3983 bool insert_after
, location_t loc
)
3986 struct access
*child
;
3988 if (access
->grp_to_be_replaced
)
3992 stmt
= gimple_build_assign (get_access_replacement (access
),
3993 build_zero_cst (access
->type
));
3995 gsi_insert_after (gsi
, stmt
, GSI_NEW_STMT
);
3997 gsi_insert_before (gsi
, stmt
, GSI_SAME_STMT
);
3999 gimple_set_location (stmt
, loc
);
4001 else if (access
->grp_to_be_debug_replaced
)
4004 = gimple_build_debug_bind (get_access_replacement (access
),
4005 build_zero_cst (access
->type
),
4008 gsi_insert_after (gsi
, ds
, GSI_NEW_STMT
);
4010 gsi_insert_before (gsi
, ds
, GSI_SAME_STMT
);
4013 for (child
= access
->first_child
; child
; child
= child
->next_sibling
)
4014 init_subtree_with_zero (child
, gsi
, insert_after
, loc
);
4017 /* Clobber all scalar replacements in an access subtree. ACCESS is the
4018 root of the subtree to be processed. GSI is the statement iterator used
4019 for inserting statements which are added after the current statement if
4020 INSERT_AFTER is true or before it otherwise. */
4023 clobber_subtree (struct access
*access
, gimple_stmt_iterator
*gsi
,
4024 bool insert_after
, location_t loc
)
4027 struct access
*child
;
4029 if (access
->grp_to_be_replaced
)
4031 tree rep
= get_access_replacement (access
);
4032 tree clobber
= build_clobber (access
->type
);
4033 gimple
*stmt
= gimple_build_assign (rep
, clobber
);
4036 gsi_insert_after (gsi
, stmt
, GSI_NEW_STMT
);
4038 gsi_insert_before (gsi
, stmt
, GSI_SAME_STMT
);
4040 gimple_set_location (stmt
, loc
);
4043 for (child
= access
->first_child
; child
; child
= child
->next_sibling
)
4044 clobber_subtree (child
, gsi
, insert_after
, loc
);
4047 /* Search for an access representative for the given expression EXPR and
4048 return it or NULL if it cannot be found. */
4050 static struct access
*
4051 get_access_for_expr (tree expr
)
4053 poly_int64 poffset
, psize
, pmax_size
;
4054 HOST_WIDE_INT offset
, max_size
;
4058 /* FIXME: This should not be necessary but Ada produces V_C_Es with a type of
4059 a different size than the size of its argument and we need the latter
4061 if (TREE_CODE (expr
) == VIEW_CONVERT_EXPR
)
4062 expr
= TREE_OPERAND (expr
, 0);
4064 base
= get_ref_base_and_extent (expr
, &poffset
, &psize
, &pmax_size
,
4066 if (!known_size_p (pmax_size
)
4067 || !pmax_size
.is_constant (&max_size
)
4068 || !poffset
.is_constant (&offset
)
4072 if (tree basesize
= DECL_SIZE (base
))
4076 || !poly_int_tree_p (basesize
, &sz
)
4077 || known_le (sz
, offset
))
4082 || !bitmap_bit_p (candidate_bitmap
, DECL_UID (base
)))
4085 return get_var_base_offset_size_access (base
, offset
, max_size
);
4088 /* Replace the expression EXPR with a scalar replacement if there is one and
4089 generate other statements to do type conversion or subtree copying if
4090 necessary. WRITE is true if the expression is being written to (it is on a
4091 LHS of a statement or output in an assembly statement). STMT_GSI is used to
4092 place newly created statements before the processed statement, REFRESH_GSI
4093 is used to place them afterwards - unless the processed statement must end a
4094 BB in which case it is placed on the outgoing non-EH edge. REFRESH_GSI and
4095 is then used to continue iteration over the BB. If sra_modify_expr is
4096 called only once with WRITE equal to true on a given statement, both
4097 iterator parameters can point to the same one. */
4100 sra_modify_expr (tree
*expr
, bool write
, gimple_stmt_iterator
*stmt_gsi
,
4101 gimple_stmt_iterator
*refresh_gsi
)
4104 struct access
*access
;
4105 tree type
, bfr
, orig_expr
;
4106 bool partial_cplx_access
= false;
4108 if (TREE_CODE (*expr
) == BIT_FIELD_REF
4109 && (write
|| !sra_handled_bf_read_p (*expr
)))
4112 expr
= &TREE_OPERAND (*expr
, 0);
4117 if (TREE_CODE (*expr
) == REALPART_EXPR
|| TREE_CODE (*expr
) == IMAGPART_EXPR
)
4119 expr
= &TREE_OPERAND (*expr
, 0);
4120 partial_cplx_access
= true;
4122 access
= get_access_for_expr (*expr
);
4125 type
= TREE_TYPE (*expr
);
4128 loc
= gimple_location (gsi_stmt (*stmt_gsi
));
4129 gimple_stmt_iterator alt_gsi
= gsi_none ();
4130 if (write
&& stmt_ends_bb_p (gsi_stmt (*stmt_gsi
)))
4132 alt_gsi
= gsi_start_edge (single_non_eh_succ (gsi_bb (*stmt_gsi
)));
4133 refresh_gsi
= &alt_gsi
;
4136 if (access
->grp_to_be_replaced
)
4138 tree repl
= get_access_replacement (access
);
4139 /* If we replace a non-register typed access simply use the original
4140 access expression to extract the scalar component afterwards.
4141 This happens if scalarizing a function return value or parameter
4142 like in gcc.c-torture/execute/20041124-1.c, 20050316-1.c and
4143 gcc.c-torture/compile/20011217-1.c.
4145 We also want to use this when accessing a complex or vector which can
4146 be accessed as a different type too, potentially creating a need for
4147 type conversion (see PR42196) and when scalarized unions are involved
4148 in assembler statements (see PR42398). */
4149 if (!bfr
&& !useless_type_conversion_p (type
, access
->type
))
4153 ref
= build_ref_for_model (loc
, orig_expr
, 0, access
, stmt_gsi
,
4156 if (partial_cplx_access
)
4158 /* VIEW_CONVERT_EXPRs in partial complex access are always fine in
4159 the case of a write because in such case the replacement cannot
4160 be a gimple register. In the case of a load, we have to
4161 differentiate in between a register an non-register
4163 tree t
= build1 (VIEW_CONVERT_EXPR
, type
, repl
);
4164 gcc_checking_assert (!write
|| access
->grp_partial_lhs
);
4165 if (!access
->grp_partial_lhs
)
4167 tree tmp
= make_ssa_name (type
);
4168 gassign
*stmt
= gimple_build_assign (tmp
, t
);
4169 /* This is always a read. */
4170 gsi_insert_before (stmt_gsi
, stmt
, GSI_SAME_STMT
);
4179 if (access
->grp_partial_lhs
)
4180 ref
= force_gimple_operand_gsi (refresh_gsi
, ref
, true,
4181 NULL_TREE
, false, GSI_NEW_STMT
);
4182 stmt
= gimple_build_assign (repl
, ref
);
4183 gimple_set_location (stmt
, loc
);
4184 gsi_insert_after (refresh_gsi
, stmt
, GSI_NEW_STMT
);
4190 if (access
->grp_partial_lhs
)
4191 repl
= force_gimple_operand_gsi (stmt_gsi
, repl
, true,
4194 stmt
= gimple_build_assign (ref
, repl
);
4195 gimple_set_location (stmt
, loc
);
4196 gsi_insert_before (stmt_gsi
, stmt
, GSI_SAME_STMT
);
4201 /* If we are going to replace a scalar field in a structure with
4202 reverse storage order by a stand-alone scalar, we are going to
4203 effectively byte-swap the scalar and we also need to byte-swap
4204 the portion of it represented by the bit-field. */
4205 if (bfr
&& REF_REVERSE_STORAGE_ORDER (bfr
))
4207 REF_REVERSE_STORAGE_ORDER (bfr
) = 0;
4208 TREE_OPERAND (bfr
, 2)
4209 = size_binop (MINUS_EXPR
, TYPE_SIZE (TREE_TYPE (repl
)),
4210 size_binop (PLUS_EXPR
, TREE_OPERAND (bfr
, 1),
4211 TREE_OPERAND (bfr
, 2)));
4219 else if (write
&& access
->grp_to_be_debug_replaced
)
4221 gdebug
*ds
= gimple_build_debug_bind (get_access_replacement (access
),
4223 gsi_stmt (*stmt_gsi
));
4224 gsi_insert_after (stmt_gsi
, ds
, GSI_NEW_STMT
);
4227 if (access
->first_child
&& !TREE_READONLY (access
->base
))
4229 HOST_WIDE_INT start_offset
, chunk_size
;
4231 && tree_fits_uhwi_p (TREE_OPERAND (bfr
, 1))
4232 && tree_fits_uhwi_p (TREE_OPERAND (bfr
, 2)))
4234 chunk_size
= tree_to_uhwi (TREE_OPERAND (bfr
, 1));
4235 start_offset
= access
->offset
4236 + tree_to_uhwi (TREE_OPERAND (bfr
, 2));
4239 start_offset
= chunk_size
= 0;
4241 generate_subtree_copies (access
->first_child
, orig_expr
, access
->offset
,
4242 start_offset
, chunk_size
,
4243 write
? refresh_gsi
: stmt_gsi
,
4249 /* If EXPR, which must be a call argument, is an ADDR_EXPR, generate writes and
4250 reads from its base before and after the call statement given in CALL_GSI
4251 and return true if any copying took place. Otherwise call sra_modify_expr
4252 on EXPR and return its value. FLAGS is what the gimple_call_arg_flags
4253 return for the given parameter. */
4256 sra_modify_call_arg (tree
*expr
, gimple_stmt_iterator
*call_gsi
,
4257 gimple_stmt_iterator
*refresh_gsi
, int flags
)
4259 if (TREE_CODE (*expr
) != ADDR_EXPR
)
4260 return sra_modify_expr (expr
, false, call_gsi
, refresh_gsi
);
4262 if (flags
& EAF_UNUSED
)
4265 tree base
= get_base_address (TREE_OPERAND (*expr
, 0));
4268 struct access
*access
= get_access_for_expr (base
);
4272 gimple
*stmt
= gsi_stmt (*call_gsi
);
4273 location_t loc
= gimple_location (stmt
);
4274 generate_subtree_copies (access
, base
, 0, 0, 0, call_gsi
, false, false,
4277 if (flags
& EAF_NO_DIRECT_CLOBBER
)
4280 if (!stmt_ends_bb_p (stmt
))
4281 generate_subtree_copies (access
, base
, 0, 0, 0, refresh_gsi
, true,
4287 FOR_EACH_EDGE (e
, ei
, gsi_bb (*call_gsi
)->succs
)
4289 gimple_stmt_iterator alt_gsi
= gsi_start_edge (e
);
4290 generate_subtree_copies (access
, base
, 0, 0, 0, &alt_gsi
, true,
4297 /* Where scalar replacements of the RHS have been written to when a replacement
4298 of a LHS of an assigments cannot be direclty loaded from a replacement of
4300 enum unscalarized_data_handling
{ SRA_UDH_NONE
, /* Nothing done so far. */
4301 SRA_UDH_RIGHT
, /* Data flushed to the RHS. */
4302 SRA_UDH_LEFT
}; /* Data flushed to the LHS. */
4304 struct subreplacement_assignment_data
4306 /* Offset of the access representing the lhs of the assignment. */
4307 HOST_WIDE_INT left_offset
;
4309 /* LHS and RHS of the original assignment. */
4310 tree assignment_lhs
, assignment_rhs
;
4312 /* Access representing the rhs of the whole assignment. */
4313 struct access
*top_racc
;
4315 /* Stmt iterator used for statement insertions after the original assignment.
4316 It points to the main GSI used to traverse a BB during function body
4318 gimple_stmt_iterator
*new_gsi
;
4320 /* Stmt iterator used for statement insertions before the original
4321 assignment. Keeps on pointing to the original statement. */
4322 gimple_stmt_iterator old_gsi
;
4324 /* Location of the assignment. */
4327 /* Keeps the information whether we have needed to refresh replacements of
4328 the LHS and from which side of the assignments this takes place. */
4329 enum unscalarized_data_handling refreshed
;
4332 /* Store all replacements in the access tree rooted in TOP_RACC either to their
4333 base aggregate if there are unscalarized data or directly to LHS of the
4334 statement that is pointed to by GSI otherwise. */
4337 handle_unscalarized_data_in_subtree (struct subreplacement_assignment_data
*sad
)
4340 /* If the RHS is a load from a constant, we do not need to (and must not)
4341 flush replacements to it and can use it directly as if we did. */
4342 if (TREE_READONLY (sad
->top_racc
->base
))
4344 sad
->refreshed
= SRA_UDH_RIGHT
;
4347 if (sad
->top_racc
->grp_unscalarized_data
)
4349 src
= sad
->assignment_rhs
;
4350 sad
->refreshed
= SRA_UDH_RIGHT
;
4354 src
= sad
->assignment_lhs
;
4355 sad
->refreshed
= SRA_UDH_LEFT
;
4357 generate_subtree_copies (sad
->top_racc
->first_child
, src
,
4358 sad
->top_racc
->offset
, 0, 0,
4359 &sad
->old_gsi
, false, false, sad
->loc
);
4362 /* Try to generate statements to load all sub-replacements in an access subtree
4363 formed by children of LACC from scalar replacements in the SAD->top_racc
4364 subtree. If that is not possible, refresh the SAD->top_racc base aggregate
4365 and load the accesses from it. */
4368 load_assign_lhs_subreplacements (struct access
*lacc
,
4369 struct subreplacement_assignment_data
*sad
)
4371 for (lacc
= lacc
->first_child
; lacc
; lacc
= lacc
->next_sibling
)
4373 HOST_WIDE_INT offset
;
4374 offset
= lacc
->offset
- sad
->left_offset
+ sad
->top_racc
->offset
;
4376 if (lacc
->grp_to_be_replaced
)
4378 struct access
*racc
;
4382 racc
= find_access_in_subtree (sad
->top_racc
, offset
, lacc
->size
);
4383 if (racc
&& racc
->grp_to_be_replaced
)
4385 rhs
= get_access_replacement (racc
);
4387 if (!useless_type_conversion_p (lacc
->type
, racc
->type
))
4389 rhs
= fold_build1_loc (sad
->loc
, VIEW_CONVERT_EXPR
,
4394 if (lacc
->grp_partial_lhs
&& (vce
|| racc
->grp_partial_lhs
))
4395 rhs
= force_gimple_operand_gsi (&sad
->old_gsi
, rhs
, true,
4396 NULL_TREE
, true, GSI_SAME_STMT
);
4400 /* No suitable access on the right hand side, need to load from
4401 the aggregate. See if we have to update it first... */
4402 if (sad
->refreshed
== SRA_UDH_NONE
)
4403 handle_unscalarized_data_in_subtree (sad
);
4405 if (sad
->refreshed
== SRA_UDH_LEFT
)
4406 rhs
= build_ref_for_model (sad
->loc
, sad
->assignment_lhs
,
4407 lacc
->offset
- sad
->left_offset
,
4408 lacc
, sad
->new_gsi
, true);
4410 rhs
= build_ref_for_model (sad
->loc
, sad
->assignment_rhs
,
4411 lacc
->offset
- sad
->left_offset
,
4412 lacc
, sad
->new_gsi
, true);
4413 if (lacc
->grp_partial_lhs
)
4414 rhs
= force_gimple_operand_gsi (sad
->new_gsi
,
4415 rhs
, true, NULL_TREE
,
4416 false, GSI_NEW_STMT
);
4419 stmt
= gimple_build_assign (get_access_replacement (lacc
), rhs
);
4420 gsi_insert_after (sad
->new_gsi
, stmt
, GSI_NEW_STMT
);
4421 gimple_set_location (stmt
, sad
->loc
);
4423 sra_stats
.subreplacements
++;
4427 if (sad
->refreshed
== SRA_UDH_NONE
4428 && lacc
->grp_read
&& !lacc
->grp_covered
)
4429 handle_unscalarized_data_in_subtree (sad
);
4431 if (lacc
&& lacc
->grp_to_be_debug_replaced
)
4435 struct access
*racc
= find_access_in_subtree (sad
->top_racc
,
4439 if (racc
&& racc
->grp_to_be_replaced
)
4441 if (racc
->grp_write
|| constant_decl_p (racc
->base
))
4442 drhs
= get_access_replacement (racc
);
4446 else if (sad
->refreshed
== SRA_UDH_LEFT
)
4447 drhs
= build_debug_ref_for_model (sad
->loc
, lacc
->base
,
4448 lacc
->offset
, lacc
);
4449 else if (sad
->refreshed
== SRA_UDH_RIGHT
)
4450 drhs
= build_debug_ref_for_model (sad
->loc
, sad
->top_racc
->base
,
4455 && !useless_type_conversion_p (lacc
->type
, TREE_TYPE (drhs
)))
4456 drhs
= fold_build1_loc (sad
->loc
, VIEW_CONVERT_EXPR
,
4458 ds
= gimple_build_debug_bind (get_access_replacement (lacc
),
4459 drhs
, gsi_stmt (sad
->old_gsi
));
4460 gsi_insert_after (sad
->new_gsi
, ds
, GSI_NEW_STMT
);
4464 if (lacc
->first_child
)
4465 load_assign_lhs_subreplacements (lacc
, sad
);
4469 /* Result code for SRA assignment modification. */
4470 enum assignment_mod_result
{ SRA_AM_NONE
, /* nothing done for the stmt */
4471 SRA_AM_MODIFIED
, /* stmt changed but not
4473 SRA_AM_REMOVED
}; /* stmt eliminated */
4475 /* Modify assignments with a CONSTRUCTOR on their RHS. STMT contains a pointer
4476 to the assignment and GSI is the statement iterator pointing at it. Returns
4477 the same values as sra_modify_assign. */
4479 static enum assignment_mod_result
4480 sra_modify_constructor_assign (gimple
*stmt
, gimple_stmt_iterator
*gsi
)
4482 tree lhs
= gimple_assign_lhs (stmt
);
4483 struct access
*acc
= get_access_for_expr (lhs
);
4486 location_t loc
= gimple_location (stmt
);
4488 if (gimple_clobber_p (stmt
))
4490 /* Clobber the replacement variable. */
4491 clobber_subtree (acc
, gsi
, !acc
->grp_covered
, loc
);
4492 /* Remove clobbers of fully scalarized variables, they are dead. */
4493 if (acc
->grp_covered
)
4495 unlink_stmt_vdef (stmt
);
4496 gsi_remove (gsi
, true);
4497 release_defs (stmt
);
4498 return SRA_AM_REMOVED
;
4501 return SRA_AM_MODIFIED
;
4504 if (CONSTRUCTOR_NELTS (gimple_assign_rhs1 (stmt
)) > 0)
4506 /* I have never seen this code path trigger but if it can happen the
4507 following should handle it gracefully. */
4508 if (access_has_children_p (acc
))
4509 generate_subtree_copies (acc
->first_child
, lhs
, acc
->offset
, 0, 0, gsi
,
4511 return SRA_AM_MODIFIED
;
4514 if (acc
->grp_covered
)
4516 init_subtree_with_zero (acc
, gsi
, false, loc
);
4517 unlink_stmt_vdef (stmt
);
4518 gsi_remove (gsi
, true);
4519 release_defs (stmt
);
4520 return SRA_AM_REMOVED
;
4524 init_subtree_with_zero (acc
, gsi
, true, loc
);
4525 return SRA_AM_MODIFIED
;
4529 /* Create and return a new suitable default definition SSA_NAME for RACC which
4530 is an access describing an uninitialized part of an aggregate that is being
4531 loaded. REG_TREE is used instead of the actual RACC type if that is not of
4532 a gimple register type. */
4535 get_repl_default_def_ssa_name (struct access
*racc
, tree reg_type
)
4537 gcc_checking_assert (!racc
->grp_to_be_replaced
4538 && !racc
->grp_to_be_debug_replaced
);
4539 if (!racc
->replacement_decl
)
4540 racc
->replacement_decl
= create_access_replacement (racc
, reg_type
);
4541 return get_or_create_ssa_default_def (cfun
, racc
->replacement_decl
);
4545 /* Generate statements to call .DEFERRED_INIT to initialize scalar replacements
4546 of accesses within a subtree ACCESS; all its children, siblings and their
4547 children are to be processed.
4548 GSI is a statement iterator used to place the new statements. */
4550 generate_subtree_deferred_init (struct access
*access
,
4553 gimple_stmt_iterator
*gsi
,
4558 if (access
->grp_to_be_replaced
)
4560 tree repl
= get_access_replacement (access
);
4562 = gimple_build_call_internal (IFN_DEFERRED_INIT
, 3,
4563 TYPE_SIZE_UNIT (TREE_TYPE (repl
)),
4564 init_type
, decl_name
);
4565 gimple_call_set_lhs (call
, repl
);
4566 gsi_insert_before (gsi
, call
, GSI_SAME_STMT
);
4568 gimple_set_location (call
, loc
);
4569 sra_stats
.subtree_deferred_init
++;
4571 if (access
->first_child
)
4572 generate_subtree_deferred_init (access
->first_child
, init_type
,
4573 decl_name
, gsi
, loc
);
4575 access
= access
->next_sibling
;
4580 /* For a call to .DEFERRED_INIT:
4581 var = .DEFERRED_INIT (size_of_var, init_type, name_of_var);
4582 examine the LHS variable VAR and replace it with a scalar replacement if
4583 there is one, also replace the RHS call to a call to .DEFERRED_INIT of
4584 the corresponding scalar relacement variable. Examine the subtree and
4585 do the scalar replacements in the subtree too. STMT is the call, GSI is
4586 the statment iterator to place newly created statement. */
4588 static enum assignment_mod_result
4589 sra_modify_deferred_init (gimple
*stmt
, gimple_stmt_iterator
*gsi
)
4591 tree lhs
= gimple_call_lhs (stmt
);
4592 tree init_type
= gimple_call_arg (stmt
, 1);
4593 tree decl_name
= gimple_call_arg (stmt
, 2);
4595 struct access
*lhs_access
= get_access_for_expr (lhs
);
4599 location_t loc
= gimple_location (stmt
);
4601 if (lhs_access
->grp_to_be_replaced
)
4603 tree lhs_repl
= get_access_replacement (lhs_access
);
4604 gimple_call_set_lhs (stmt
, lhs_repl
);
4605 tree arg0_repl
= TYPE_SIZE_UNIT (TREE_TYPE (lhs_repl
));
4606 gimple_call_set_arg (stmt
, 0, arg0_repl
);
4607 sra_stats
.deferred_init
++;
4608 gcc_assert (!lhs_access
->first_child
);
4609 return SRA_AM_MODIFIED
;
4612 if (lhs_access
->first_child
)
4613 generate_subtree_deferred_init (lhs_access
->first_child
,
4614 init_type
, decl_name
, gsi
, loc
);
4615 if (lhs_access
->grp_covered
)
4617 unlink_stmt_vdef (stmt
);
4618 gsi_remove (gsi
, true);
4619 release_defs (stmt
);
4620 return SRA_AM_REMOVED
;
4623 return SRA_AM_MODIFIED
;
4626 /* Examine both sides of the assignment statement pointed to by STMT, replace
4627 them with a scalare replacement if there is one and generate copying of
4628 replacements if scalarized aggregates have been used in the assignment. GSI
4629 is used to hold generated statements for type conversions and subtree
4632 static enum assignment_mod_result
4633 sra_modify_assign (gimple
*stmt
, gimple_stmt_iterator
*gsi
)
4635 struct access
*lacc
, *racc
;
4637 bool modify_this_stmt
= false;
4638 bool force_gimple_rhs
= false;
4640 gimple_stmt_iterator orig_gsi
= *gsi
;
4642 if (!gimple_assign_single_p (stmt
))
4644 lhs
= gimple_assign_lhs (stmt
);
4645 rhs
= gimple_assign_rhs1 (stmt
);
4647 if (TREE_CODE (rhs
) == CONSTRUCTOR
)
4648 return sra_modify_constructor_assign (stmt
, gsi
);
4650 if (TREE_CODE (rhs
) == REALPART_EXPR
|| TREE_CODE (lhs
) == REALPART_EXPR
4651 || TREE_CODE (rhs
) == IMAGPART_EXPR
|| TREE_CODE (lhs
) == IMAGPART_EXPR
4652 || (TREE_CODE (rhs
) == BIT_FIELD_REF
&& !sra_handled_bf_read_p (rhs
))
4653 || TREE_CODE (lhs
) == BIT_FIELD_REF
)
4655 modify_this_stmt
= sra_modify_expr (gimple_assign_rhs1_ptr (stmt
),
4657 modify_this_stmt
|= sra_modify_expr (gimple_assign_lhs_ptr (stmt
),
4659 return modify_this_stmt
? SRA_AM_MODIFIED
: SRA_AM_NONE
;
4662 lacc
= get_access_for_expr (lhs
);
4663 racc
= get_access_for_expr (rhs
);
4666 /* Avoid modifying initializations of constant-pool replacements. */
4667 if (racc
&& (racc
->replacement_decl
== lhs
))
4670 loc
= gimple_location (stmt
);
4671 if (lacc
&& lacc
->grp_to_be_replaced
)
4673 lhs
= get_access_replacement (lacc
);
4674 gimple_assign_set_lhs (stmt
, lhs
);
4675 modify_this_stmt
= true;
4676 if (lacc
->grp_partial_lhs
)
4677 force_gimple_rhs
= true;
4681 if (racc
&& racc
->grp_to_be_replaced
)
4683 rhs
= get_access_replacement (racc
);
4684 modify_this_stmt
= true;
4685 if (racc
->grp_partial_lhs
)
4686 force_gimple_rhs
= true;
4690 && !racc
->grp_unscalarized_data
4691 && !racc
->grp_unscalarizable_region
4692 && TREE_CODE (lhs
) == SSA_NAME
4693 && !access_has_replacements_p (racc
))
4695 rhs
= get_repl_default_def_ssa_name (racc
, TREE_TYPE (lhs
));
4696 modify_this_stmt
= true;
4700 if (modify_this_stmt
4701 && !useless_type_conversion_p (TREE_TYPE (lhs
), TREE_TYPE (rhs
)))
4703 /* If we can avoid creating a VIEW_CONVERT_EXPR, then do so.
4704 ??? This should move to fold_stmt which we simply should
4705 call after building a VIEW_CONVERT_EXPR here. */
4706 if (AGGREGATE_TYPE_P (TREE_TYPE (lhs
))
4707 && TYPE_REVERSE_STORAGE_ORDER (TREE_TYPE (lhs
)) == racc
->reverse
4708 && !contains_bitfld_component_ref_p (lhs
))
4710 lhs
= build_ref_for_model (loc
, lhs
, 0, racc
, gsi
, false);
4711 gimple_assign_set_lhs (stmt
, lhs
);
4714 && AGGREGATE_TYPE_P (TREE_TYPE (rhs
))
4715 && TYPE_REVERSE_STORAGE_ORDER (TREE_TYPE (rhs
)) == lacc
->reverse
4716 && !contains_vce_or_bfcref_p (rhs
))
4717 rhs
= build_ref_for_model (loc
, rhs
, 0, lacc
, gsi
, false);
4719 if (!useless_type_conversion_p (TREE_TYPE (lhs
), TREE_TYPE (rhs
)))
4721 rhs
= fold_build1_loc (loc
, VIEW_CONVERT_EXPR
, TREE_TYPE (lhs
), rhs
);
4722 if (is_gimple_reg_type (TREE_TYPE (lhs
))
4723 && TREE_CODE (lhs
) != SSA_NAME
)
4724 force_gimple_rhs
= true;
4728 if (lacc
&& lacc
->grp_to_be_debug_replaced
)
4730 tree dlhs
= get_access_replacement (lacc
);
4731 tree drhs
= unshare_expr (rhs
);
4732 if (!useless_type_conversion_p (TREE_TYPE (dlhs
), TREE_TYPE (drhs
)))
4734 if (AGGREGATE_TYPE_P (TREE_TYPE (drhs
))
4735 && !contains_vce_or_bfcref_p (drhs
))
4736 drhs
= build_debug_ref_for_model (loc
, drhs
, 0, lacc
);
4738 && !useless_type_conversion_p (TREE_TYPE (dlhs
),
4740 drhs
= fold_build1_loc (loc
, VIEW_CONVERT_EXPR
,
4741 TREE_TYPE (dlhs
), drhs
);
4743 gdebug
*ds
= gimple_build_debug_bind (dlhs
, drhs
, stmt
);
4744 gsi_insert_before (gsi
, ds
, GSI_SAME_STMT
);
4747 /* From this point on, the function deals with assignments in between
4748 aggregates when at least one has scalar reductions of some of its
4749 components. There are three possible scenarios: Both the LHS and RHS have
4750 to-be-scalarized components, 2) only the RHS has or 3) only the LHS has.
4752 In the first case, we would like to load the LHS components from RHS
4753 components whenever possible. If that is not possible, we would like to
4754 read it directly from the RHS (after updating it by storing in it its own
4755 components). If there are some necessary unscalarized data in the LHS,
4756 those will be loaded by the original assignment too. If neither of these
4757 cases happen, the original statement can be removed. Most of this is done
4758 by load_assign_lhs_subreplacements.
4760 In the second case, we would like to store all RHS scalarized components
4761 directly into LHS and if they cover the aggregate completely, remove the
4762 statement too. In the third case, we want the LHS components to be loaded
4763 directly from the RHS (DSE will remove the original statement if it
4766 This is a bit complex but manageable when types match and when unions do
4767 not cause confusion in a way that we cannot really load a component of LHS
4768 from the RHS or vice versa (the access representing this level can have
4769 subaccesses that are accessible only through a different union field at a
4770 higher level - different from the one used in the examined expression).
4773 Therefore, I specially handle a fourth case, happening when there is a
4774 specific type cast or it is impossible to locate a scalarized subaccess on
4775 the other side of the expression. If that happens, I simply "refresh" the
4776 RHS by storing in it is scalarized components leave the original statement
4777 there to do the copying and then load the scalar replacements of the LHS.
4778 This is what the first branch does. */
4780 if (modify_this_stmt
4781 || gimple_has_volatile_ops (stmt
)
4782 || contains_vce_or_bfcref_p (rhs
)
4783 || contains_vce_or_bfcref_p (lhs
)
4784 || stmt_ends_bb_p (stmt
))
4786 /* No need to copy into a constant, it comes pre-initialized. */
4787 if (access_has_children_p (racc
) && !TREE_READONLY (racc
->base
))
4788 generate_subtree_copies (racc
->first_child
, rhs
, racc
->offset
, 0, 0,
4789 gsi
, false, false, loc
);
4790 if (access_has_children_p (lacc
))
4792 gimple_stmt_iterator alt_gsi
= gsi_none ();
4793 if (stmt_ends_bb_p (stmt
))
4795 alt_gsi
= gsi_start_edge (single_non_eh_succ (gsi_bb (*gsi
)));
4798 generate_subtree_copies (lacc
->first_child
, lhs
, lacc
->offset
, 0, 0,
4799 gsi
, true, true, loc
);
4801 sra_stats
.separate_lhs_rhs_handling
++;
4803 /* This gimplification must be done after generate_subtree_copies,
4804 lest we insert the subtree copies in the middle of the gimplified
4806 if (force_gimple_rhs
)
4807 rhs
= force_gimple_operand_gsi (&orig_gsi
, rhs
, true, NULL_TREE
,
4808 true, GSI_SAME_STMT
);
4809 if (gimple_assign_rhs1 (stmt
) != rhs
)
4811 modify_this_stmt
= true;
4812 gimple_assign_set_rhs_from_tree (&orig_gsi
, rhs
);
4813 gcc_assert (stmt
== gsi_stmt (orig_gsi
));
4816 return modify_this_stmt
? SRA_AM_MODIFIED
: SRA_AM_NONE
;
4820 if (access_has_children_p (lacc
)
4821 && access_has_children_p (racc
)
4822 /* When an access represents an unscalarizable region, it usually
4823 represents accesses with variable offset and thus must not be used
4824 to generate new memory accesses. */
4825 && !lacc
->grp_unscalarizable_region
4826 && !racc
->grp_unscalarizable_region
)
4828 struct subreplacement_assignment_data sad
;
4830 sad
.left_offset
= lacc
->offset
;
4831 sad
.assignment_lhs
= lhs
;
4832 sad
.assignment_rhs
= rhs
;
4833 sad
.top_racc
= racc
;
4836 sad
.loc
= gimple_location (stmt
);
4837 sad
.refreshed
= SRA_UDH_NONE
;
4839 if (lacc
->grp_read
&& !lacc
->grp_covered
)
4840 handle_unscalarized_data_in_subtree (&sad
);
4842 load_assign_lhs_subreplacements (lacc
, &sad
);
4843 if (sad
.refreshed
!= SRA_UDH_RIGHT
)
4846 unlink_stmt_vdef (stmt
);
4847 gsi_remove (&sad
.old_gsi
, true);
4848 release_defs (stmt
);
4849 sra_stats
.deleted
++;
4850 return SRA_AM_REMOVED
;
4855 if (access_has_children_p (racc
)
4856 && !racc
->grp_unscalarized_data
4857 && TREE_CODE (lhs
) != SSA_NAME
)
4861 fprintf (dump_file
, "Removing load: ");
4862 print_gimple_stmt (dump_file
, stmt
, 0);
4864 generate_subtree_copies (racc
->first_child
, lhs
,
4865 racc
->offset
, 0, 0, gsi
,
4867 gcc_assert (stmt
== gsi_stmt (*gsi
));
4868 unlink_stmt_vdef (stmt
);
4869 gsi_remove (gsi
, true);
4870 release_defs (stmt
);
4871 sra_stats
.deleted
++;
4872 return SRA_AM_REMOVED
;
4874 /* Restore the aggregate RHS from its components so the
4875 prevailing aggregate copy does the right thing. */
4876 if (access_has_children_p (racc
) && !TREE_READONLY (racc
->base
))
4877 generate_subtree_copies (racc
->first_child
, rhs
, racc
->offset
, 0, 0,
4878 gsi
, false, false, loc
);
4879 /* Re-load the components of the aggregate copy destination.
4880 But use the RHS aggregate to load from to expose more
4881 optimization opportunities. */
4882 if (access_has_children_p (lacc
))
4884 generate_subtree_copies (lacc
->first_child
, rhs
, lacc
->offset
,
4885 0, 0, gsi
, true, true, loc
);
4886 if (lacc
->grp_covered
)
4888 unlink_stmt_vdef (stmt
);
4889 gsi_remove (& orig_gsi
, true);
4890 release_defs (stmt
);
4891 sra_stats
.deleted
++;
4892 return SRA_AM_REMOVED
;
4901 /* Set any scalar replacements of values in the constant pool to the initial
4902 value of the constant. (Constant-pool decls like *.LC0 have effectively
4903 been initialized before the program starts, we must do the same for their
4904 replacements.) Thus, we output statements like 'SR.1 = *.LC0[0];' into
4905 the function's entry block. */
4908 initialize_constant_pool_replacements (void)
4910 gimple_seq seq
= NULL
;
4911 gimple_stmt_iterator gsi
= gsi_start (seq
);
4915 EXECUTE_IF_SET_IN_BITMAP (candidate_bitmap
, 0, i
, bi
)
4917 tree var
= candidate (i
);
4918 if (!constant_decl_p (var
))
4921 struct access
*access
= get_first_repr_for_decl (var
);
4925 if (access
->replacement_decl
)
4928 = gimple_build_assign (get_access_replacement (access
),
4929 unshare_expr (access
->expr
));
4930 if (dump_file
&& (dump_flags
& TDF_DETAILS
))
4932 fprintf (dump_file
, "Generating constant initializer: ");
4933 print_gimple_stmt (dump_file
, stmt
, 0);
4934 fprintf (dump_file
, "\n");
4936 gsi_insert_after (&gsi
, stmt
, GSI_NEW_STMT
);
4940 if (access
->first_child
)
4941 access
= access
->first_child
;
4942 else if (access
->next_sibling
)
4943 access
= access
->next_sibling
;
4946 while (access
->parent
&& !access
->next_sibling
)
4947 access
= access
->parent
;
4948 if (access
->next_sibling
)
4949 access
= access
->next_sibling
;
4951 access
= access
->next_grp
;
4956 seq
= gsi_seq (gsi
);
4958 gsi_insert_seq_on_edge_immediate (
4959 single_succ_edge (ENTRY_BLOCK_PTR_FOR_FN (cfun
)), seq
);
4962 /* Traverse the function body and all modifications as decided in
4963 analyze_all_variable_accesses. Return true iff the CFG has been
4967 sra_modify_function_body (void)
4969 bool cfg_changed
= false;
4972 initialize_constant_pool_replacements ();
4974 FOR_EACH_BB_FN (bb
, cfun
)
4976 gimple_stmt_iterator gsi
= gsi_start_bb (bb
);
4977 while (!gsi_end_p (gsi
))
4979 gimple
*stmt
= gsi_stmt (gsi
);
4980 enum assignment_mod_result assign_result
;
4981 bool modified
= false, deleted
= false;
4985 switch (gimple_code (stmt
))
4988 t
= gimple_return_retval_ptr (as_a
<greturn
*> (stmt
));
4989 if (*t
!= NULL_TREE
)
4990 modified
|= sra_modify_expr (t
, false, &gsi
, &gsi
);
4994 assign_result
= sra_modify_assign (stmt
, &gsi
);
4995 modified
|= assign_result
== SRA_AM_MODIFIED
;
4996 deleted
= assign_result
== SRA_AM_REMOVED
;
5000 /* Handle calls to .DEFERRED_INIT specially. */
5001 if (gimple_call_internal_p (stmt
, IFN_DEFERRED_INIT
))
5003 assign_result
= sra_modify_deferred_init (stmt
, &gsi
);
5004 modified
|= assign_result
== SRA_AM_MODIFIED
;
5005 deleted
= assign_result
== SRA_AM_REMOVED
;
5009 gcall
*call
= as_a
<gcall
*> (stmt
);
5010 gimple_stmt_iterator call_gsi
= gsi
;
5012 /* Operands must be processed before the lhs. */
5013 for (i
= 0; i
< gimple_call_num_args (call
); i
++)
5015 int flags
= gimple_call_arg_flags (call
, i
);
5016 t
= gimple_call_arg_ptr (call
, i
);
5017 modified
|= sra_modify_call_arg (t
, &call_gsi
, &gsi
, flags
);
5019 if (gimple_call_chain (call
))
5021 t
= gimple_call_chain_ptr (call
);
5022 int flags
= gimple_call_static_chain_flags (call
);
5023 modified
|= sra_modify_call_arg (t
, &call_gsi
, &gsi
,
5026 if (gimple_call_lhs (call
))
5028 t
= gimple_call_lhs_ptr (call
);
5029 modified
|= sra_modify_expr (t
, true, &call_gsi
, &gsi
);
5036 gimple_stmt_iterator stmt_gsi
= gsi
;
5037 gasm
*asm_stmt
= as_a
<gasm
*> (stmt
);
5038 for (i
= 0; i
< gimple_asm_ninputs (asm_stmt
); i
++)
5040 t
= &TREE_VALUE (gimple_asm_input_op (asm_stmt
, i
));
5041 modified
|= sra_modify_expr (t
, false, &stmt_gsi
, &gsi
);
5043 for (i
= 0; i
< gimple_asm_noutputs (asm_stmt
); i
++)
5045 t
= &TREE_VALUE (gimple_asm_output_op (asm_stmt
, i
));
5046 modified
|= sra_modify_expr (t
, true, &stmt_gsi
, &gsi
);
5058 if (maybe_clean_eh_stmt (stmt
)
5059 && gimple_purge_dead_eh_edges (gimple_bb (stmt
)))
5067 gsi_commit_edge_inserts ();
5071 /* Generate statements initializing scalar replacements of parts of function
5075 initialize_parameter_reductions (void)
5077 gimple_stmt_iterator gsi
;
5078 gimple_seq seq
= NULL
;
5081 gsi
= gsi_start (seq
);
5082 for (parm
= DECL_ARGUMENTS (current_function_decl
);
5084 parm
= DECL_CHAIN (parm
))
5086 vec
<access_p
> *access_vec
;
5087 struct access
*access
;
5089 if (!bitmap_bit_p (candidate_bitmap
, DECL_UID (parm
)))
5091 access_vec
= get_base_access_vector (parm
);
5095 for (access
= (*access_vec
)[0];
5097 access
= access
->next_grp
)
5098 generate_subtree_copies (access
, parm
, 0, 0, 0, &gsi
, true, true,
5099 EXPR_LOCATION (parm
));
5102 seq
= gsi_seq (gsi
);
5104 gsi_insert_seq_on_edge_immediate (single_succ_edge (ENTRY_BLOCK_PTR_FOR_FN (cfun
)), seq
);
5107 /* The "main" function of intraprocedural SRA passes. Runs the analysis and if
5108 it reveals there are components of some aggregates to be scalarized, it runs
5109 the required transformations. */
5111 perform_intra_sra (void)
5116 if (!find_var_candidates ())
5119 if (!scan_function ())
5122 if (!analyze_all_variable_accesses ())
5125 if (sra_modify_function_body ())
5126 ret
= TODO_update_ssa
| TODO_cleanup_cfg
;
5128 ret
= TODO_update_ssa
;
5129 initialize_parameter_reductions ();
5131 statistics_counter_event (cfun
, "Scalar replacements created",
5132 sra_stats
.replacements
);
5133 statistics_counter_event (cfun
, "Modified expressions", sra_stats
.exprs
);
5134 statistics_counter_event (cfun
, "Subtree copy stmts",
5135 sra_stats
.subtree_copies
);
5136 statistics_counter_event (cfun
, "Subreplacement stmts",
5137 sra_stats
.subreplacements
);
5138 statistics_counter_event (cfun
, "Deleted stmts", sra_stats
.deleted
);
5139 statistics_counter_event (cfun
, "Separate LHS and RHS handling",
5140 sra_stats
.separate_lhs_rhs_handling
);
5143 sra_deinitialize ();
5147 /* Perform early intraprocedural SRA. */
5149 early_intra_sra (void)
5151 sra_mode
= SRA_MODE_EARLY_INTRA
;
5152 return perform_intra_sra ();
5155 /* Perform "late" intraprocedural SRA. */
5157 late_intra_sra (void)
5159 sra_mode
= SRA_MODE_INTRA
;
5160 return perform_intra_sra ();
5165 gate_intra_sra (void)
5167 return flag_tree_sra
!= 0 && dbg_cnt (tree_sra
);
5173 const pass_data pass_data_sra_early
=
5175 GIMPLE_PASS
, /* type */
5177 OPTGROUP_NONE
, /* optinfo_flags */
5178 TV_TREE_SRA
, /* tv_id */
5179 ( PROP_cfg
| PROP_ssa
), /* properties_required */
5180 0, /* properties_provided */
5181 0, /* properties_destroyed */
5182 0, /* todo_flags_start */
5183 TODO_update_ssa
, /* todo_flags_finish */
5186 class pass_sra_early
: public gimple_opt_pass
5189 pass_sra_early (gcc::context
*ctxt
)
5190 : gimple_opt_pass (pass_data_sra_early
, ctxt
)
5193 /* opt_pass methods: */
5194 bool gate (function
*) final override
{ return gate_intra_sra (); }
5195 unsigned int execute (function
*) final override
5197 return early_intra_sra ();
5200 }; // class pass_sra_early
5205 make_pass_sra_early (gcc::context
*ctxt
)
5207 return new pass_sra_early (ctxt
);
5212 const pass_data pass_data_sra
=
5214 GIMPLE_PASS
, /* type */
5216 OPTGROUP_NONE
, /* optinfo_flags */
5217 TV_TREE_SRA
, /* tv_id */
5218 ( PROP_cfg
| PROP_ssa
), /* properties_required */
5219 0, /* properties_provided */
5220 0, /* properties_destroyed */
5221 TODO_update_address_taken
, /* todo_flags_start */
5222 TODO_update_ssa
, /* todo_flags_finish */
5225 class pass_sra
: public gimple_opt_pass
5228 pass_sra (gcc::context
*ctxt
)
5229 : gimple_opt_pass (pass_data_sra
, ctxt
)
5232 /* opt_pass methods: */
5233 bool gate (function
*) final override
{ return gate_intra_sra (); }
5234 unsigned int execute (function
*) final override
{ return late_intra_sra (); }
5236 }; // class pass_sra
5241 make_pass_sra (gcc::context
*ctxt
)
5243 return new pass_sra (ctxt
);
5247 /* If type T cannot be totally scalarized, return false. Otherwise return true
5248 and push to the vector within PC offsets and lengths of all padding in the
5249 type as total scalarization would encounter it. */
5252 check_ts_and_push_padding_to_vec (tree type
, sra_padding_collecting
*pc
)
5254 if (!totally_scalarizable_type_p (type
, true /* optimistic value */,
5258 pc
->record_padding (tree_to_shwi (TYPE_SIZE (type
)));
5262 /* Given two types in an assignment, return true either if any one cannot be
5263 totally scalarized or if they have padding (i.e. not copied bits) */
5266 sra_total_scalarization_would_copy_same_data_p (tree t1
, tree t2
)
5268 sra_padding_collecting p1
;
5269 if (!check_ts_and_push_padding_to_vec (t1
, &p1
))
5272 sra_padding_collecting p2
;
5273 if (!check_ts_and_push_padding_to_vec (t2
, &p2
))
5276 unsigned l
= p1
.m_padding
.length ();
5277 if (l
!= p2
.m_padding
.length ())
5279 for (unsigned i
= 0; i
< l
; i
++)
5280 if (p1
.m_padding
[i
].first
!= p2
.m_padding
[i
].first
5281 || p1
.m_padding
[i
].second
!= p2
.m_padding
[i
].second
)