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