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