]>
Commit | Line | Data |
---|---|---|
6de9cd9a DN |
1 | /* Scalar Replacement of Aggregates (SRA) converts some structure |
2 | references into scalar references, exposing them to the scalar | |
3 | optimizers. | |
4 | Copyright (C) 2003, 2004 Free Software Foundation, Inc. | |
5 | Contributed by Diego Novillo <dnovillo@redhat.com> | |
6 | ||
7 | This file is part of GCC. | |
19114537 | 8 | |
6de9cd9a DN |
9 | GCC is free software; you can redistribute it and/or modify it |
10 | under the terms of the GNU General Public License as published by the | |
11 | Free Software Foundation; either version 2, or (at your option) any | |
12 | later version. | |
19114537 | 13 | |
6de9cd9a DN |
14 | GCC is distributed in the hope that it will be useful, but WITHOUT |
15 | ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
16 | FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
17 | for more details. | |
19114537 | 18 | |
6de9cd9a DN |
19 | You should have received a copy of the GNU General Public License |
20 | along with GCC; see the file COPYING. If not, write to the Free | |
21 | Software Foundation, 59 Temple Place - Suite 330, Boston, MA | |
22 | 02111-1307, USA. */ | |
23 | ||
24 | #include "config.h" | |
25 | #include "system.h" | |
26 | #include "coretypes.h" | |
27 | #include "tm.h" | |
28 | #include "errors.h" | |
29 | #include "ggc.h" | |
30 | #include "tree.h" | |
31 | ||
32 | /* These RTL headers are needed for basic-block.h. */ | |
33 | #include "rtl.h" | |
34 | #include "tm_p.h" | |
35 | #include "hard-reg-set.h" | |
36 | #include "basic-block.h" | |
37 | #include "diagnostic.h" | |
38 | #include "langhooks.h" | |
39 | #include "tree-inline.h" | |
40 | #include "tree-flow.h" | |
eadf906f | 41 | #include "tree-gimple.h" |
6de9cd9a DN |
42 | #include "tree-dump.h" |
43 | #include "tree-pass.h" | |
44 | #include "timevar.h" | |
45 | #include "flags.h" | |
46 | #include "bitmap.h" | |
97e73bd2 RH |
47 | #include "obstack.h" |
48 | #include "target.h" | |
e1514303 AP |
49 | /* expr.h is needed for MOVE_RATIO. */ |
50 | #include "expr.h" | |
61b58001 | 51 | #include "params.h" |
6de9cd9a DN |
52 | |
53 | ||
97e73bd2 RH |
54 | /* This object of this pass is to replace a non-addressable aggregate with a |
55 | set of independent variables. Most of the time, all of these variables | |
19114537 | 56 | will be scalars. But a secondary objective is to break up larger |
97e73bd2 RH |
57 | aggregates into smaller aggregates. In the process we may find that some |
58 | bits of the larger aggregate can be deleted as unreferenced. | |
6de9cd9a | 59 | |
97e73bd2 RH |
60 | This substitution is done globally. More localized substitutions would |
61 | be the purvey of a load-store motion pass. | |
62 | ||
63 | The optimization proceeds in phases: | |
64 | ||
65 | (1) Identify variables that have types that are candidates for | |
66 | decomposition. | |
67 | ||
68 | (2) Scan the function looking for the ways these variables are used. | |
69 | In particular we're interested in the number of times a variable | |
70 | (or member) is needed as a complete unit, and the number of times | |
71 | a variable (or member) is copied. | |
72 | ||
73 | (3) Based on the usage profile, instantiate substitution variables. | |
74 | ||
75 | (4) Scan the function making replacements. | |
76 | */ | |
6de9cd9a | 77 | |
6de9cd9a DN |
78 | |
79 | /* The set of aggregate variables that are candidates for scalarization. */ | |
80 | static bitmap sra_candidates; | |
81 | ||
82 | /* Set of scalarizable PARM_DECLs that need copy-in operations at the | |
83 | beginning of the function. */ | |
84 | static bitmap needs_copy_in; | |
85 | ||
97e73bd2 RH |
86 | /* Sets of bit pairs that cache type decomposition and instantiation. */ |
87 | static bitmap sra_type_decomp_cache; | |
88 | static bitmap sra_type_inst_cache; | |
89 | ||
90 | /* One of these structures is created for each candidate aggregate | |
91 | and each (accessed) member of such an aggregate. */ | |
6de9cd9a DN |
92 | struct sra_elt |
93 | { | |
97e73bd2 RH |
94 | /* A tree of the elements. Used when we want to traverse everything. */ |
95 | struct sra_elt *parent; | |
96 | struct sra_elt *children; | |
97 | struct sra_elt *sibling; | |
6de9cd9a | 98 | |
97e73bd2 RH |
99 | /* If this element is a root, then this is the VAR_DECL. If this is |
100 | a sub-element, this is some token used to identify the reference. | |
101 | In the case of COMPONENT_REF, this is the FIELD_DECL. In the case | |
102 | of an ARRAY_REF, this is the (constant) index. In the case of a | |
103 | complex number, this is a zero or one. */ | |
104 | tree element; | |
6de9cd9a | 105 | |
97e73bd2 RH |
106 | /* The type of the element. */ |
107 | tree type; | |
6de9cd9a | 108 | |
97e73bd2 RH |
109 | /* A VAR_DECL, for any sub-element we've decided to replace. */ |
110 | tree replacement; | |
6de9cd9a | 111 | |
97e73bd2 RH |
112 | /* The number of times the element is referenced as a whole. I.e. |
113 | given "a.b.c", this would be incremented for C, but not for A or B. */ | |
114 | unsigned int n_uses; | |
6de9cd9a | 115 | |
97e73bd2 RH |
116 | /* The number of times the element is copied to or from another |
117 | scalarizable element. */ | |
118 | unsigned int n_copies; | |
6de9cd9a | 119 | |
97e73bd2 RH |
120 | /* True if TYPE is scalar. */ |
121 | bool is_scalar; | |
6de9cd9a | 122 | |
97e73bd2 RH |
123 | /* True if we saw something about this element that prevents scalarization, |
124 | such as non-constant indexing. */ | |
125 | bool cannot_scalarize; | |
6de9cd9a | 126 | |
97e73bd2 RH |
127 | /* True if we've decided that structure-to-structure assignment |
128 | should happen via memcpy and not per-element. */ | |
129 | bool use_block_copy; | |
a32b97a2 | 130 | |
97e73bd2 RH |
131 | /* A flag for use with/after random access traversals. */ |
132 | bool visited; | |
133 | }; | |
a32b97a2 | 134 | |
97e73bd2 | 135 | /* Random access to the child of a parent is performed by hashing. |
b01d837f | 136 | This prevents quadratic behavior, and allows SRA to function |
97e73bd2 RH |
137 | reasonably on larger records. */ |
138 | static htab_t sra_map; | |
a32b97a2 | 139 | |
97e73bd2 RH |
140 | /* All structures are allocated out of the following obstack. */ |
141 | static struct obstack sra_obstack; | |
a32b97a2 | 142 | |
97e73bd2 RH |
143 | /* Debugging functions. */ |
144 | static void dump_sra_elt_name (FILE *, struct sra_elt *); | |
145 | extern void debug_sra_elt_name (struct sra_elt *); | |
6de9cd9a | 146 | |
97e73bd2 | 147 | \f |
6de9cd9a DN |
148 | /* Return true if DECL is an SRA candidate. */ |
149 | ||
150 | static bool | |
151 | is_sra_candidate_decl (tree decl) | |
152 | { | |
153 | return DECL_P (decl) && bitmap_bit_p (sra_candidates, var_ann (decl)->uid); | |
154 | } | |
155 | ||
97e73bd2 | 156 | /* Return true if TYPE is a scalar type. */ |
6de9cd9a DN |
157 | |
158 | static bool | |
97e73bd2 | 159 | is_sra_scalar_type (tree type) |
6de9cd9a | 160 | { |
97e73bd2 RH |
161 | enum tree_code code = TREE_CODE (type); |
162 | return (code == INTEGER_TYPE || code == REAL_TYPE || code == VECTOR_TYPE | |
163 | || code == ENUMERAL_TYPE || code == BOOLEAN_TYPE | |
164 | || code == CHAR_TYPE || code == POINTER_TYPE || code == OFFSET_TYPE | |
165 | || code == REFERENCE_TYPE); | |
6de9cd9a DN |
166 | } |
167 | ||
97e73bd2 RH |
168 | /* Return true if TYPE can be decomposed into a set of independent variables. |
169 | ||
170 | Note that this doesn't imply that all elements of TYPE can be | |
171 | instantiated, just that if we decide to break up the type into | |
172 | separate pieces that it can be done. */ | |
03797ac5 RK |
173 | |
174 | static bool | |
97e73bd2 | 175 | type_can_be_decomposed_p (tree type) |
03797ac5 | 176 | { |
97e73bd2 RH |
177 | unsigned int cache = TYPE_UID (TYPE_MAIN_VARIANT (type)) * 2; |
178 | tree t; | |
03797ac5 | 179 | |
97e73bd2 RH |
180 | /* Avoid searching the same type twice. */ |
181 | if (bitmap_bit_p (sra_type_decomp_cache, cache+0)) | |
182 | return true; | |
183 | if (bitmap_bit_p (sra_type_decomp_cache, cache+1)) | |
184 | return false; | |
6de9cd9a | 185 | |
8e3c61c5 | 186 | /* The type must have a definite nonzero size. */ |
97e73bd2 RH |
187 | if (TYPE_SIZE (type) == NULL || integer_zerop (TYPE_SIZE (type))) |
188 | goto fail; | |
6de9cd9a | 189 | |
97e73bd2 RH |
190 | /* The type must be a non-union aggregate. */ |
191 | switch (TREE_CODE (type)) | |
6de9cd9a | 192 | { |
97e73bd2 RH |
193 | case RECORD_TYPE: |
194 | { | |
195 | bool saw_one_field = false; | |
6de9cd9a | 196 | |
97e73bd2 RH |
197 | for (t = TYPE_FIELDS (type); t ; t = TREE_CHAIN (t)) |
198 | if (TREE_CODE (t) == FIELD_DECL) | |
6de9cd9a | 199 | { |
97e73bd2 RH |
200 | /* Reject incorrectly represented bit fields. */ |
201 | if (DECL_BIT_FIELD (t) | |
202 | && (tree_low_cst (DECL_SIZE (t), 1) | |
203 | != TYPE_PRECISION (TREE_TYPE (t)))) | |
204 | goto fail; | |
6de9cd9a | 205 | |
97e73bd2 RH |
206 | saw_one_field = true; |
207 | } | |
6de9cd9a | 208 | |
97e73bd2 RH |
209 | /* Record types must have at least one field. */ |
210 | if (!saw_one_field) | |
211 | goto fail; | |
212 | } | |
213 | break; | |
6de9cd9a | 214 | |
97e73bd2 RH |
215 | case ARRAY_TYPE: |
216 | /* Array types must have a fixed lower and upper bound. */ | |
217 | t = TYPE_DOMAIN (type); | |
218 | if (t == NULL) | |
219 | goto fail; | |
220 | if (TYPE_MIN_VALUE (t) == NULL || !TREE_CONSTANT (TYPE_MIN_VALUE (t))) | |
221 | goto fail; | |
222 | if (TYPE_MAX_VALUE (t) == NULL || !TREE_CONSTANT (TYPE_MAX_VALUE (t))) | |
223 | goto fail; | |
224 | break; | |
6de9cd9a | 225 | |
97e73bd2 RH |
226 | case COMPLEX_TYPE: |
227 | break; | |
6de9cd9a | 228 | |
97e73bd2 RH |
229 | default: |
230 | goto fail; | |
231 | } | |
6de9cd9a | 232 | |
97e73bd2 RH |
233 | bitmap_set_bit (sra_type_decomp_cache, cache+0); |
234 | return true; | |
6de9cd9a | 235 | |
97e73bd2 RH |
236 | fail: |
237 | bitmap_set_bit (sra_type_decomp_cache, cache+1); | |
238 | return false; | |
6de9cd9a DN |
239 | } |
240 | ||
97e73bd2 RH |
241 | /* Return true if DECL can be decomposed into a set of independent |
242 | (though not necessarily scalar) variables. */ | |
6de9cd9a | 243 | |
97e73bd2 RH |
244 | static bool |
245 | decl_can_be_decomposed_p (tree var) | |
6de9cd9a | 246 | { |
97e73bd2 RH |
247 | /* Early out for scalars. */ |
248 | if (is_sra_scalar_type (TREE_TYPE (var))) | |
249 | return false; | |
6de9cd9a | 250 | |
97e73bd2 | 251 | /* The variable must not be aliased. */ |
6de9cd9a DN |
252 | if (!is_gimple_non_addressable (var)) |
253 | { | |
254 | if (dump_file && (dump_flags & TDF_DETAILS)) | |
255 | { | |
256 | fprintf (dump_file, "Cannot scalarize variable "); | |
257 | print_generic_expr (dump_file, var, dump_flags); | |
258 | fprintf (dump_file, " because it must live in memory\n"); | |
259 | } | |
260 | return false; | |
261 | } | |
262 | ||
97e73bd2 | 263 | /* The variable must not be volatile. */ |
6de9cd9a DN |
264 | if (TREE_THIS_VOLATILE (var)) |
265 | { | |
266 | if (dump_file && (dump_flags & TDF_DETAILS)) | |
267 | { | |
268 | fprintf (dump_file, "Cannot scalarize variable "); | |
269 | print_generic_expr (dump_file, var, dump_flags); | |
270 | fprintf (dump_file, " because it is declared volatile\n"); | |
271 | } | |
272 | return false; | |
273 | } | |
274 | ||
97e73bd2 RH |
275 | /* We must be able to decompose the variable's type. */ |
276 | if (!type_can_be_decomposed_p (TREE_TYPE (var))) | |
277 | { | |
278 | if (dump_file && (dump_flags & TDF_DETAILS)) | |
279 | { | |
280 | fprintf (dump_file, "Cannot scalarize variable "); | |
281 | print_generic_expr (dump_file, var, dump_flags); | |
282 | fprintf (dump_file, " because its type cannot be decomposed\n"); | |
283 | } | |
284 | return false; | |
285 | } | |
286 | ||
287 | return true; | |
288 | } | |
289 | ||
290 | /* Return true if TYPE can be *completely* decomposed into scalars. */ | |
291 | ||
292 | static bool | |
293 | type_can_instantiate_all_elements (tree type) | |
294 | { | |
295 | if (is_sra_scalar_type (type)) | |
6de9cd9a | 296 | return true; |
97e73bd2 RH |
297 | if (!type_can_be_decomposed_p (type)) |
298 | return false; | |
6de9cd9a | 299 | |
97e73bd2 | 300 | switch (TREE_CODE (type)) |
6de9cd9a | 301 | { |
97e73bd2 RH |
302 | case RECORD_TYPE: |
303 | { | |
304 | unsigned int cache = TYPE_UID (TYPE_MAIN_VARIANT (type)) * 2; | |
305 | tree f; | |
6de9cd9a | 306 | |
97e73bd2 RH |
307 | if (bitmap_bit_p (sra_type_inst_cache, cache+0)) |
308 | return true; | |
309 | if (bitmap_bit_p (sra_type_inst_cache, cache+1)) | |
6de9cd9a | 310 | return false; |
6de9cd9a | 311 | |
97e73bd2 RH |
312 | for (f = TYPE_FIELDS (type); f ; f = TREE_CHAIN (f)) |
313 | if (TREE_CODE (f) == FIELD_DECL) | |
6de9cd9a | 314 | { |
97e73bd2 RH |
315 | if (!type_can_instantiate_all_elements (TREE_TYPE (f))) |
316 | { | |
317 | bitmap_set_bit (sra_type_inst_cache, cache+1); | |
318 | return false; | |
319 | } | |
6de9cd9a | 320 | } |
6de9cd9a | 321 | |
97e73bd2 RH |
322 | bitmap_set_bit (sra_type_inst_cache, cache+0); |
323 | return true; | |
324 | } | |
6de9cd9a | 325 | |
97e73bd2 RH |
326 | case ARRAY_TYPE: |
327 | return type_can_instantiate_all_elements (TREE_TYPE (type)); | |
6de9cd9a | 328 | |
97e73bd2 RH |
329 | case COMPLEX_TYPE: |
330 | return true; | |
6de9cd9a | 331 | |
97e73bd2 | 332 | default: |
1e128c5f | 333 | gcc_unreachable (); |
97e73bd2 RH |
334 | } |
335 | } | |
6de9cd9a | 336 | |
97e73bd2 | 337 | /* Test whether ELT or some sub-element cannot be scalarized. */ |
6de9cd9a | 338 | |
97e73bd2 RH |
339 | static bool |
340 | can_completely_scalarize_p (struct sra_elt *elt) | |
6de9cd9a | 341 | { |
97e73bd2 RH |
342 | struct sra_elt *c; |
343 | ||
344 | if (elt->cannot_scalarize) | |
345 | return false; | |
346 | ||
347 | for (c = elt->children; c ; c = c->sibling) | |
348 | if (!can_completely_scalarize_p (c)) | |
349 | return false; | |
350 | ||
351 | return true; | |
352 | } | |
6de9cd9a | 353 | |
97e73bd2 RH |
354 | \f |
355 | /* A simplified tree hashing algorithm that only handles the types of | |
356 | trees we expect to find in sra_elt->element. */ | |
6de9cd9a | 357 | |
97e73bd2 RH |
358 | static hashval_t |
359 | sra_hash_tree (tree t) | |
360 | { | |
fa27426e RH |
361 | hashval_t h; |
362 | ||
6de9cd9a DN |
363 | switch (TREE_CODE (t)) |
364 | { | |
97e73bd2 RH |
365 | case VAR_DECL: |
366 | case PARM_DECL: | |
367 | case RESULT_DECL: | |
fa27426e RH |
368 | h = DECL_UID (t); |
369 | break; | |
370 | ||
97e73bd2 | 371 | case INTEGER_CST: |
fa27426e RH |
372 | h = TREE_INT_CST_LOW (t) ^ TREE_INT_CST_HIGH (t); |
373 | break; | |
374 | ||
375 | case FIELD_DECL: | |
376 | /* We can have types that are compatible, but have different member | |
377 | lists, so we can't hash fields by ID. Use offsets instead. */ | |
378 | h = iterative_hash_expr (DECL_FIELD_OFFSET (t), 0); | |
379 | h = iterative_hash_expr (DECL_FIELD_BIT_OFFSET (t), h); | |
380 | break; | |
381 | ||
6de9cd9a | 382 | default: |
1e128c5f | 383 | gcc_unreachable (); |
6de9cd9a | 384 | } |
fa27426e RH |
385 | |
386 | return h; | |
6de9cd9a DN |
387 | } |
388 | ||
97e73bd2 | 389 | /* Hash function for type SRA_PAIR. */ |
6de9cd9a | 390 | |
97e73bd2 RH |
391 | static hashval_t |
392 | sra_elt_hash (const void *x) | |
6de9cd9a | 393 | { |
97e73bd2 RH |
394 | const struct sra_elt *e = x; |
395 | const struct sra_elt *p; | |
396 | hashval_t h; | |
6de9cd9a | 397 | |
97e73bd2 | 398 | h = sra_hash_tree (e->element); |
6de9cd9a | 399 | |
97e73bd2 RH |
400 | /* Take into account everything back up the chain. Given that chain |
401 | lengths are rarely very long, this should be acceptable. If we | |
2a7e31df | 402 | truly identify this as a performance problem, it should work to |
97e73bd2 RH |
403 | hash the pointer value "e->parent". */ |
404 | for (p = e->parent; p ; p = p->parent) | |
405 | h = (h * 65521) ^ sra_hash_tree (p->element); | |
6de9cd9a | 406 | |
97e73bd2 RH |
407 | return h; |
408 | } | |
19114537 | 409 | |
97e73bd2 | 410 | /* Equality function for type SRA_PAIR. */ |
6de9cd9a | 411 | |
97e73bd2 RH |
412 | static int |
413 | sra_elt_eq (const void *x, const void *y) | |
414 | { | |
415 | const struct sra_elt *a = x; | |
416 | const struct sra_elt *b = y; | |
fa27426e | 417 | tree ae, be; |
6de9cd9a | 418 | |
97e73bd2 RH |
419 | if (a->parent != b->parent) |
420 | return false; | |
6de9cd9a | 421 | |
fa27426e RH |
422 | ae = a->element; |
423 | be = b->element; | |
6de9cd9a | 424 | |
fa27426e RH |
425 | if (ae == be) |
426 | return true; | |
427 | if (TREE_CODE (ae) != TREE_CODE (be)) | |
97e73bd2 | 428 | return false; |
fa27426e RH |
429 | |
430 | switch (TREE_CODE (ae)) | |
431 | { | |
432 | case VAR_DECL: | |
433 | case PARM_DECL: | |
434 | case RESULT_DECL: | |
435 | /* These are all pointer unique. */ | |
436 | return false; | |
437 | ||
438 | case INTEGER_CST: | |
439 | /* Integers are not pointer unique, so compare their values. */ | |
440 | return tree_int_cst_equal (ae, be); | |
441 | ||
442 | case FIELD_DECL: | |
443 | /* Fields are unique within a record, but not between | |
444 | compatible records. */ | |
445 | if (DECL_FIELD_CONTEXT (ae) == DECL_FIELD_CONTEXT (be)) | |
446 | return false; | |
447 | return fields_compatible_p (ae, be); | |
448 | ||
449 | default: | |
1e128c5f | 450 | gcc_unreachable (); |
fa27426e | 451 | } |
6de9cd9a DN |
452 | } |
453 | ||
97e73bd2 RH |
454 | /* Create or return the SRA_ELT structure for CHILD in PARENT. PARENT |
455 | may be null, in which case CHILD must be a DECL. */ | |
6de9cd9a | 456 | |
97e73bd2 RH |
457 | static struct sra_elt * |
458 | lookup_element (struct sra_elt *parent, tree child, tree type, | |
459 | enum insert_option insert) | |
6de9cd9a | 460 | { |
97e73bd2 RH |
461 | struct sra_elt dummy; |
462 | struct sra_elt **slot; | |
463 | struct sra_elt *elt; | |
6de9cd9a | 464 | |
97e73bd2 RH |
465 | dummy.parent = parent; |
466 | dummy.element = child; | |
467 | ||
468 | slot = (struct sra_elt **) htab_find_slot (sra_map, &dummy, insert); | |
469 | if (!slot && insert == NO_INSERT) | |
470 | return NULL; | |
471 | ||
472 | elt = *slot; | |
473 | if (!elt && insert == INSERT) | |
6de9cd9a | 474 | { |
97e73bd2 RH |
475 | *slot = elt = obstack_alloc (&sra_obstack, sizeof (*elt)); |
476 | memset (elt, 0, sizeof (*elt)); | |
477 | ||
478 | elt->parent = parent; | |
479 | elt->element = child; | |
480 | elt->type = type; | |
481 | elt->is_scalar = is_sra_scalar_type (type); | |
482 | ||
483 | if (parent) | |
484 | { | |
485 | elt->sibling = parent->children; | |
486 | parent->children = elt; | |
487 | } | |
6de9cd9a | 488 | |
97e73bd2 RH |
489 | /* If this is a parameter, then if we want to scalarize, we have |
490 | one copy from the true function parameter. Count it now. */ | |
491 | if (TREE_CODE (child) == PARM_DECL) | |
6de9cd9a | 492 | { |
97e73bd2 RH |
493 | elt->n_copies = 1; |
494 | bitmap_set_bit (needs_copy_in, var_ann (child)->uid); | |
6de9cd9a DN |
495 | } |
496 | } | |
497 | ||
97e73bd2 | 498 | return elt; |
6de9cd9a DN |
499 | } |
500 | ||
97e73bd2 | 501 | /* Return true if the ARRAY_REF in EXPR is a constant, in bounds access. */ |
6de9cd9a | 502 | |
97e73bd2 RH |
503 | static bool |
504 | is_valid_const_index (tree expr) | |
6de9cd9a | 505 | { |
97e73bd2 | 506 | tree dom, t, index = TREE_OPERAND (expr, 1); |
6de9cd9a | 507 | |
97e73bd2 RH |
508 | if (TREE_CODE (index) != INTEGER_CST) |
509 | return false; | |
6de9cd9a | 510 | |
97e73bd2 | 511 | /* Watch out for stupid user tricks, indexing outside the array. |
6de9cd9a | 512 | |
97e73bd2 RH |
513 | Careful, we're not called only on scalarizable types, so do not |
514 | assume constant array bounds. We needn't do anything with such | |
515 | cases, since they'll be referring to objects that we should have | |
516 | already rejected for scalarization, so returning false is fine. */ | |
6de9cd9a | 517 | |
97e73bd2 RH |
518 | dom = TYPE_DOMAIN (TREE_TYPE (TREE_OPERAND (expr, 0))); |
519 | if (dom == NULL) | |
520 | return false; | |
521 | ||
522 | t = TYPE_MIN_VALUE (dom); | |
523 | if (!t || TREE_CODE (t) != INTEGER_CST) | |
524 | return false; | |
525 | if (tree_int_cst_lt (index, t)) | |
526 | return false; | |
527 | ||
528 | t = TYPE_MAX_VALUE (dom); | |
529 | if (!t || TREE_CODE (t) != INTEGER_CST) | |
530 | return false; | |
531 | if (tree_int_cst_lt (t, index)) | |
532 | return false; | |
533 | ||
534 | return true; | |
535 | } | |
536 | ||
19114537 | 537 | /* Create or return the SRA_ELT structure for EXPR if the expression |
97e73bd2 RH |
538 | refers to a scalarizable variable. */ |
539 | ||
540 | static struct sra_elt * | |
541 | maybe_lookup_element_for_expr (tree expr) | |
6de9cd9a | 542 | { |
97e73bd2 RH |
543 | struct sra_elt *elt; |
544 | tree child; | |
545 | ||
546 | switch (TREE_CODE (expr)) | |
547 | { | |
548 | case VAR_DECL: | |
549 | case PARM_DECL: | |
550 | case RESULT_DECL: | |
551 | if (is_sra_candidate_decl (expr)) | |
552 | return lookup_element (NULL, expr, TREE_TYPE (expr), INSERT); | |
553 | return NULL; | |
554 | ||
555 | case ARRAY_REF: | |
556 | /* We can't scalarize variable array indicies. */ | |
557 | if (is_valid_const_index (expr)) | |
558 | child = TREE_OPERAND (expr, 1); | |
559 | else | |
560 | return NULL; | |
561 | break; | |
562 | ||
563 | case COMPONENT_REF: | |
564 | /* Don't look through unions. */ | |
565 | if (TREE_CODE (TREE_TYPE (TREE_OPERAND (expr, 0))) != RECORD_TYPE) | |
566 | return NULL; | |
567 | child = TREE_OPERAND (expr, 1); | |
568 | break; | |
569 | ||
570 | case REALPART_EXPR: | |
571 | child = integer_zero_node; | |
572 | break; | |
573 | case IMAGPART_EXPR: | |
574 | child = integer_one_node; | |
575 | break; | |
576 | ||
577 | default: | |
578 | return NULL; | |
579 | } | |
580 | ||
581 | elt = maybe_lookup_element_for_expr (TREE_OPERAND (expr, 0)); | |
582 | if (elt) | |
583 | return lookup_element (elt, child, TREE_TYPE (expr), INSERT); | |
584 | return NULL; | |
585 | } | |
586 | ||
587 | \f | |
588 | /* Functions to walk just enough of the tree to see all scalarizable | |
589 | references, and categorize them. */ | |
590 | ||
591 | /* A set of callbacks for phases 2 and 4. They'll be invoked for the | |
592 | various kinds of references seen. In all cases, *BSI is an iterator | |
593 | pointing to the statement being processed. */ | |
594 | struct sra_walk_fns | |
595 | { | |
596 | /* Invoked when ELT is required as a unit. Note that ELT might refer to | |
597 | a leaf node, in which case this is a simple scalar reference. *EXPR_P | |
598 | points to the location of the expression. IS_OUTPUT is true if this | |
599 | is a left-hand-side reference. */ | |
600 | void (*use) (struct sra_elt *elt, tree *expr_p, | |
601 | block_stmt_iterator *bsi, bool is_output); | |
602 | ||
603 | /* Invoked when we have a copy between two scalarizable references. */ | |
604 | void (*copy) (struct sra_elt *lhs_elt, struct sra_elt *rhs_elt, | |
605 | block_stmt_iterator *bsi); | |
606 | ||
607 | /* Invoked when ELT is initialized from a constant. VALUE may be NULL, | |
bfeebecf RH |
608 | in which case it should be treated as an empty CONSTRUCTOR. */ |
609 | void (*init) (struct sra_elt *elt, tree value, block_stmt_iterator *bsi); | |
97e73bd2 RH |
610 | |
611 | /* Invoked when we have a copy between one scalarizable reference ELT | |
612 | and one non-scalarizable reference OTHER. IS_OUTPUT is true if ELT | |
613 | is on the left-hand side. */ | |
614 | void (*ldst) (struct sra_elt *elt, tree other, | |
615 | block_stmt_iterator *bsi, bool is_output); | |
616 | ||
617 | /* True during phase 2, false during phase 4. */ | |
618 | /* ??? This is a hack. */ | |
619 | bool initial_scan; | |
620 | }; | |
621 | ||
622 | #ifdef ENABLE_CHECKING | |
1f838355 | 623 | /* Invoked via walk_tree, if *TP contains a candidate decl, return it. */ |
97e73bd2 RH |
624 | |
625 | static tree | |
626 | sra_find_candidate_decl (tree *tp, int *walk_subtrees, | |
627 | void *data ATTRIBUTE_UNUSED) | |
628 | { | |
629 | tree t = *tp; | |
630 | enum tree_code code = TREE_CODE (t); | |
631 | ||
632 | if (code == VAR_DECL || code == PARM_DECL || code == RESULT_DECL) | |
633 | { | |
634 | *walk_subtrees = 0; | |
635 | if (is_sra_candidate_decl (t)) | |
636 | return t; | |
637 | } | |
638 | else if (TYPE_P (t)) | |
639 | *walk_subtrees = 0; | |
640 | ||
641 | return NULL; | |
642 | } | |
643 | #endif | |
644 | ||
645 | /* Walk most expressions looking for a scalarizable aggregate. | |
646 | If we find one, invoke FNS->USE. */ | |
647 | ||
648 | static void | |
649 | sra_walk_expr (tree *expr_p, block_stmt_iterator *bsi, bool is_output, | |
650 | const struct sra_walk_fns *fns) | |
651 | { | |
652 | tree expr = *expr_p; | |
653 | tree inner = expr; | |
78cc4167 | 654 | bool disable_scalarization = false; |
97e73bd2 RH |
655 | |
656 | /* We're looking to collect a reference expression between EXPR and INNER, | |
657 | such that INNER is a scalarizable decl and all other nodes through EXPR | |
658 | are references that we can scalarize. If we come across something that | |
659 | we can't scalarize, we reset EXPR. This has the effect of making it | |
660 | appear that we're referring to the larger expression as a whole. */ | |
661 | ||
662 | while (1) | |
663 | switch (TREE_CODE (inner)) | |
664 | { | |
665 | case VAR_DECL: | |
666 | case PARM_DECL: | |
667 | case RESULT_DECL: | |
668 | /* If there is a scalarizable decl at the bottom, then process it. */ | |
669 | if (is_sra_candidate_decl (inner)) | |
670 | { | |
671 | struct sra_elt *elt = maybe_lookup_element_for_expr (expr); | |
78cc4167 RH |
672 | if (disable_scalarization) |
673 | elt->cannot_scalarize = true; | |
674 | else | |
675 | fns->use (elt, expr_p, bsi, is_output); | |
97e73bd2 RH |
676 | } |
677 | return; | |
678 | ||
679 | case ARRAY_REF: | |
680 | /* Non-constant index means any member may be accessed. Prevent the | |
681 | expression from being scalarized. If we were to treat this as a | |
682 | reference to the whole array, we can wind up with a single dynamic | |
683 | index reference inside a loop being overridden by several constant | |
684 | index references during loop setup. It's possible that this could | |
685 | be avoided by using dynamic usage counts based on BB trip counts | |
19114537 | 686 | (based on loop analysis or profiling), but that hardly seems worth |
97e73bd2 RH |
687 | the effort. */ |
688 | /* ??? Hack. Figure out how to push this into the scan routines | |
689 | without duplicating too much code. */ | |
690 | if (!is_valid_const_index (inner)) | |
691 | { | |
78cc4167 RH |
692 | disable_scalarization = true; |
693 | goto use_all; | |
97e73bd2 RH |
694 | } |
695 | /* ??? Are we assured that non-constant bounds and stride will have | |
696 | the same value everywhere? I don't think Fortran will... */ | |
697 | if (TREE_OPERAND (inner, 2) || TREE_OPERAND (inner, 3)) | |
698 | goto use_all; | |
699 | inner = TREE_OPERAND (inner, 0); | |
700 | break; | |
701 | ||
702 | case COMPONENT_REF: | |
703 | /* A reference to a union member constitutes a reference to the | |
704 | entire union. */ | |
705 | if (TREE_CODE (TREE_TYPE (TREE_OPERAND (inner, 0))) != RECORD_TYPE) | |
706 | goto use_all; | |
707 | /* ??? See above re non-constant stride. */ | |
708 | if (TREE_OPERAND (inner, 2)) | |
709 | goto use_all; | |
710 | inner = TREE_OPERAND (inner, 0); | |
711 | break; | |
712 | ||
713 | case REALPART_EXPR: | |
714 | case IMAGPART_EXPR: | |
715 | inner = TREE_OPERAND (inner, 0); | |
716 | break; | |
717 | ||
718 | case BIT_FIELD_REF: | |
719 | /* A bit field reference (access to *multiple* fields simultaneously) | |
19114537 | 720 | is not currently scalarized. Consider this an access to the |
97e73bd2 RH |
721 | complete outer element, to which walk_tree will bring us next. */ |
722 | goto use_all; | |
723 | ||
724 | case ARRAY_RANGE_REF: | |
725 | /* Similarly, an subrange reference is used to modify indexing. Which | |
726 | means that the canonical element names that we have won't work. */ | |
727 | goto use_all; | |
728 | ||
729 | case VIEW_CONVERT_EXPR: | |
730 | case NOP_EXPR: | |
731 | /* Similarly, a view/nop explicitly wants to look at an object in a | |
732 | type other than the one we've scalarized. */ | |
733 | goto use_all; | |
734 | ||
d25cee4d RH |
735 | case WITH_SIZE_EXPR: |
736 | /* This is a transparent wrapper. The entire inner expression really | |
737 | is being used. */ | |
738 | goto use_all; | |
739 | ||
97e73bd2 RH |
740 | use_all: |
741 | expr_p = &TREE_OPERAND (inner, 0); | |
742 | inner = expr = *expr_p; | |
743 | break; | |
744 | ||
745 | default: | |
746 | #ifdef ENABLE_CHECKING | |
747 | /* Validate that we're not missing any references. */ | |
1e128c5f | 748 | gcc_assert (!walk_tree (&inner, sra_find_candidate_decl, NULL, NULL)); |
97e73bd2 RH |
749 | #endif |
750 | return; | |
751 | } | |
752 | } | |
753 | ||
754 | /* Walk a TREE_LIST of values looking for scalarizable aggregates. | |
755 | If we find one, invoke FNS->USE. */ | |
756 | ||
757 | static void | |
758 | sra_walk_tree_list (tree list, block_stmt_iterator *bsi, bool is_output, | |
759 | const struct sra_walk_fns *fns) | |
760 | { | |
761 | tree op; | |
762 | for (op = list; op ; op = TREE_CHAIN (op)) | |
763 | sra_walk_expr (&TREE_VALUE (op), bsi, is_output, fns); | |
764 | } | |
765 | ||
766 | /* Walk the arguments of a CALL_EXPR looking for scalarizable aggregates. | |
767 | If we find one, invoke FNS->USE. */ | |
768 | ||
769 | static void | |
770 | sra_walk_call_expr (tree expr, block_stmt_iterator *bsi, | |
771 | const struct sra_walk_fns *fns) | |
772 | { | |
773 | sra_walk_tree_list (TREE_OPERAND (expr, 1), bsi, false, fns); | |
774 | } | |
775 | ||
776 | /* Walk the inputs and outputs of an ASM_EXPR looking for scalarizable | |
777 | aggregates. If we find one, invoke FNS->USE. */ | |
778 | ||
779 | static void | |
780 | sra_walk_asm_expr (tree expr, block_stmt_iterator *bsi, | |
781 | const struct sra_walk_fns *fns) | |
782 | { | |
783 | sra_walk_tree_list (ASM_INPUTS (expr), bsi, false, fns); | |
784 | sra_walk_tree_list (ASM_OUTPUTS (expr), bsi, true, fns); | |
785 | } | |
786 | ||
787 | /* Walk a MODIFY_EXPR and categorize the assignment appropriately. */ | |
788 | ||
789 | static void | |
790 | sra_walk_modify_expr (tree expr, block_stmt_iterator *bsi, | |
791 | const struct sra_walk_fns *fns) | |
792 | { | |
793 | struct sra_elt *lhs_elt, *rhs_elt; | |
794 | tree lhs, rhs; | |
795 | ||
796 | lhs = TREE_OPERAND (expr, 0); | |
797 | rhs = TREE_OPERAND (expr, 1); | |
798 | lhs_elt = maybe_lookup_element_for_expr (lhs); | |
799 | rhs_elt = maybe_lookup_element_for_expr (rhs); | |
800 | ||
801 | /* If both sides are scalarizable, this is a COPY operation. */ | |
802 | if (lhs_elt && rhs_elt) | |
803 | { | |
804 | fns->copy (lhs_elt, rhs_elt, bsi); | |
805 | return; | |
806 | } | |
807 | ||
808 | if (lhs_elt) | |
809 | { | |
810 | /* If this is an assignment from a constant, or constructor, then | |
811 | we have access to all of the elements individually. Invoke INIT. */ | |
bfeebecf RH |
812 | if (TREE_CODE (rhs) == COMPLEX_EXPR |
813 | || TREE_CODE (rhs) == COMPLEX_CST | |
814 | || TREE_CODE (rhs) == CONSTRUCTOR) | |
815 | fns->init (lhs_elt, rhs, bsi); | |
97e73bd2 RH |
816 | |
817 | /* If this is an assignment from read-only memory, treat this as if | |
818 | we'd been passed the constructor directly. Invoke INIT. */ | |
819 | else if (TREE_CODE (rhs) == VAR_DECL | |
820 | && TREE_STATIC (rhs) | |
821 | && TREE_READONLY (rhs) | |
bfeebecf RH |
822 | && targetm.binds_local_p (rhs)) |
823 | fns->init (lhs_elt, DECL_INITIAL (rhs), bsi); | |
97e73bd2 RH |
824 | |
825 | /* If this is a copy from a non-scalarizable lvalue, invoke LDST. | |
826 | The lvalue requirement prevents us from trying to directly scalarize | |
827 | the result of a function call. Which would result in trying to call | |
828 | the function multiple times, and other evil things. */ | |
e847cc68 | 829 | else if (!lhs_elt->is_scalar && is_gimple_addressable (rhs)) |
97e73bd2 | 830 | fns->ldst (lhs_elt, rhs, bsi, true); |
19114537 | 831 | |
97e73bd2 RH |
832 | /* Otherwise we're being used in some context that requires the |
833 | aggregate to be seen as a whole. Invoke USE. */ | |
834 | else | |
835 | fns->use (lhs_elt, &TREE_OPERAND (expr, 0), bsi, true); | |
836 | } | |
837 | else | |
838 | { | |
839 | /* LHS_ELT being null only means that the LHS as a whole is not a | |
840 | scalarizable reference. There may be occurrences of scalarizable | |
841 | variables within, which implies a USE. */ | |
842 | sra_walk_expr (&TREE_OPERAND (expr, 0), bsi, true, fns); | |
843 | } | |
844 | ||
845 | /* Likewise for the right-hand side. The only difference here is that | |
846 | we don't have to handle constants, and the RHS may be a call. */ | |
847 | if (rhs_elt) | |
848 | { | |
849 | if (!rhs_elt->is_scalar) | |
850 | fns->ldst (rhs_elt, lhs, bsi, false); | |
851 | else | |
852 | fns->use (rhs_elt, &TREE_OPERAND (expr, 1), bsi, false); | |
853 | } | |
97e73bd2 | 854 | else |
cd709752 RH |
855 | { |
856 | tree call = get_call_expr_in (rhs); | |
857 | if (call) | |
858 | sra_walk_call_expr (call, bsi, fns); | |
859 | else | |
860 | sra_walk_expr (&TREE_OPERAND (expr, 1), bsi, false, fns); | |
861 | } | |
97e73bd2 RH |
862 | } |
863 | ||
864 | /* Entry point to the walk functions. Search the entire function, | |
865 | invoking the callbacks in FNS on each of the references to | |
866 | scalarizable variables. */ | |
867 | ||
868 | static void | |
869 | sra_walk_function (const struct sra_walk_fns *fns) | |
870 | { | |
871 | basic_block bb; | |
bdecd334 | 872 | block_stmt_iterator si, ni; |
97e73bd2 RH |
873 | |
874 | /* ??? Phase 4 could derive some benefit to walking the function in | |
875 | dominator tree order. */ | |
876 | ||
877 | FOR_EACH_BB (bb) | |
bdecd334 | 878 | for (si = bsi_start (bb); !bsi_end_p (si); si = ni) |
97e73bd2 RH |
879 | { |
880 | tree stmt, t; | |
881 | stmt_ann_t ann; | |
882 | ||
883 | stmt = bsi_stmt (si); | |
884 | ann = stmt_ann (stmt); | |
885 | ||
bdecd334 RH |
886 | ni = si; |
887 | bsi_next (&ni); | |
888 | ||
97e73bd2 RH |
889 | /* If the statement has no virtual operands, then it doesn't |
890 | make any structure references that we care about. */ | |
891 | if (NUM_V_MAY_DEFS (V_MAY_DEF_OPS (ann)) == 0 | |
892 | && NUM_VUSES (VUSE_OPS (ann)) == 0 | |
893 | && NUM_V_MUST_DEFS (V_MUST_DEF_OPS (ann)) == 0) | |
894 | continue; | |
895 | ||
896 | switch (TREE_CODE (stmt)) | |
897 | { | |
898 | case RETURN_EXPR: | |
899 | /* If we have "return <retval>" then the return value is | |
900 | already exposed for our pleasure. Walk it as a USE to | |
901 | force all the components back in place for the return. | |
902 | ||
903 | If we have an embedded assignment, then <retval> is of | |
904 | a type that gets returned in registers in this ABI, and | |
905 | we do not wish to extend their lifetimes. Treat this | |
906 | as a USE of the variable on the RHS of this assignment. */ | |
907 | ||
908 | t = TREE_OPERAND (stmt, 0); | |
909 | if (TREE_CODE (t) == MODIFY_EXPR) | |
910 | sra_walk_expr (&TREE_OPERAND (t, 1), &si, false, fns); | |
911 | else | |
912 | sra_walk_expr (&TREE_OPERAND (stmt, 0), &si, false, fns); | |
913 | break; | |
914 | ||
915 | case MODIFY_EXPR: | |
916 | sra_walk_modify_expr (stmt, &si, fns); | |
917 | break; | |
918 | case CALL_EXPR: | |
919 | sra_walk_call_expr (stmt, &si, fns); | |
920 | break; | |
921 | case ASM_EXPR: | |
922 | sra_walk_asm_expr (stmt, &si, fns); | |
923 | break; | |
924 | ||
925 | default: | |
926 | break; | |
927 | } | |
928 | } | |
929 | } | |
930 | \f | |
931 | /* Phase One: Scan all referenced variables in the program looking for | |
932 | structures that could be decomposed. */ | |
933 | ||
934 | static bool | |
935 | find_candidates_for_sra (void) | |
936 | { | |
937 | size_t i; | |
938 | bool any_set = false; | |
939 | ||
940 | for (i = 0; i < num_referenced_vars; i++) | |
941 | { | |
942 | tree var = referenced_var (i); | |
943 | if (decl_can_be_decomposed_p (var)) | |
944 | { | |
945 | bitmap_set_bit (sra_candidates, var_ann (var)->uid); | |
946 | any_set = true; | |
947 | } | |
948 | } | |
19114537 | 949 | |
97e73bd2 RH |
950 | return any_set; |
951 | } | |
952 | ||
953 | \f | |
954 | /* Phase Two: Scan all references to scalarizable variables. Count the | |
955 | number of times they are used or copied respectively. */ | |
956 | ||
957 | /* Callbacks to fill in SRA_WALK_FNS. Everything but USE is | |
958 | considered a copy, because we can decompose the reference such that | |
959 | the sub-elements needn't be contiguous. */ | |
960 | ||
961 | static void | |
962 | scan_use (struct sra_elt *elt, tree *expr_p ATTRIBUTE_UNUSED, | |
963 | block_stmt_iterator *bsi ATTRIBUTE_UNUSED, | |
964 | bool is_output ATTRIBUTE_UNUSED) | |
965 | { | |
966 | elt->n_uses += 1; | |
967 | } | |
968 | ||
969 | static void | |
970 | scan_copy (struct sra_elt *lhs_elt, struct sra_elt *rhs_elt, | |
971 | block_stmt_iterator *bsi ATTRIBUTE_UNUSED) | |
972 | { | |
973 | lhs_elt->n_copies += 1; | |
974 | rhs_elt->n_copies += 1; | |
975 | } | |
976 | ||
bfeebecf | 977 | static void |
97e73bd2 RH |
978 | scan_init (struct sra_elt *lhs_elt, tree rhs ATTRIBUTE_UNUSED, |
979 | block_stmt_iterator *bsi ATTRIBUTE_UNUSED) | |
980 | { | |
981 | lhs_elt->n_copies += 1; | |
982 | } | |
983 | ||
984 | static void | |
985 | scan_ldst (struct sra_elt *elt, tree other ATTRIBUTE_UNUSED, | |
986 | block_stmt_iterator *bsi ATTRIBUTE_UNUSED, | |
987 | bool is_output ATTRIBUTE_UNUSED) | |
988 | { | |
989 | elt->n_copies += 1; | |
990 | } | |
991 | ||
992 | /* Dump the values we collected during the scanning phase. */ | |
993 | ||
994 | static void | |
995 | scan_dump (struct sra_elt *elt) | |
996 | { | |
997 | struct sra_elt *c; | |
998 | ||
999 | dump_sra_elt_name (dump_file, elt); | |
1000 | fprintf (dump_file, ": n_uses=%u n_copies=%u\n", elt->n_uses, elt->n_copies); | |
1001 | ||
1002 | for (c = elt->children; c ; c = c->sibling) | |
1003 | scan_dump (c); | |
1004 | } | |
1005 | ||
1006 | /* Entry point to phase 2. Scan the entire function, building up | |
1007 | scalarization data structures, recording copies and uses. */ | |
1008 | ||
1009 | static void | |
1010 | scan_function (void) | |
1011 | { | |
1012 | static const struct sra_walk_fns fns = { | |
1013 | scan_use, scan_copy, scan_init, scan_ldst, true | |
1014 | }; | |
87c476a2 | 1015 | bitmap_iterator bi; |
97e73bd2 RH |
1016 | |
1017 | sra_walk_function (&fns); | |
1018 | ||
1019 | if (dump_file && (dump_flags & TDF_DETAILS)) | |
1020 | { | |
3cd8c58a | 1021 | unsigned i; |
97e73bd2 RH |
1022 | |
1023 | fputs ("\nScan results:\n", dump_file); | |
87c476a2 | 1024 | EXECUTE_IF_SET_IN_BITMAP (sra_candidates, 0, i, bi) |
97e73bd2 RH |
1025 | { |
1026 | tree var = referenced_var (i); | |
1027 | struct sra_elt *elt = lookup_element (NULL, var, NULL, NO_INSERT); | |
1028 | if (elt) | |
1029 | scan_dump (elt); | |
87c476a2 | 1030 | } |
97e73bd2 RH |
1031 | fputc ('\n', dump_file); |
1032 | } | |
1033 | } | |
1034 | \f | |
1035 | /* Phase Three: Make decisions about which variables to scalarize, if any. | |
1036 | All elements to be scalarized have replacement variables made for them. */ | |
1037 | ||
1038 | /* A subroutine of build_element_name. Recursively build the element | |
1039 | name on the obstack. */ | |
1040 | ||
1041 | static void | |
1042 | build_element_name_1 (struct sra_elt *elt) | |
1043 | { | |
1044 | tree t; | |
1045 | char buffer[32]; | |
1046 | ||
1047 | if (elt->parent) | |
1048 | { | |
1049 | build_element_name_1 (elt->parent); | |
1050 | obstack_1grow (&sra_obstack, '$'); | |
1051 | ||
1052 | if (TREE_CODE (elt->parent->type) == COMPLEX_TYPE) | |
1053 | { | |
1054 | if (elt->element == integer_zero_node) | |
1055 | obstack_grow (&sra_obstack, "real", 4); | |
1056 | else | |
1057 | obstack_grow (&sra_obstack, "imag", 4); | |
1058 | return; | |
1059 | } | |
1060 | } | |
1061 | ||
1062 | t = elt->element; | |
1063 | if (TREE_CODE (t) == INTEGER_CST) | |
1064 | { | |
1065 | /* ??? Eh. Don't bother doing double-wide printing. */ | |
1066 | sprintf (buffer, HOST_WIDE_INT_PRINT_DEC, TREE_INT_CST_LOW (t)); | |
1067 | obstack_grow (&sra_obstack, buffer, strlen (buffer)); | |
1068 | } | |
1069 | else | |
1070 | { | |
1071 | tree name = DECL_NAME (t); | |
1072 | if (name) | |
1073 | obstack_grow (&sra_obstack, IDENTIFIER_POINTER (name), | |
1074 | IDENTIFIER_LENGTH (name)); | |
1075 | else | |
1076 | { | |
1077 | sprintf (buffer, "D%u", DECL_UID (t)); | |
1078 | obstack_grow (&sra_obstack, buffer, strlen (buffer)); | |
1079 | } | |
1080 | } | |
1081 | } | |
1082 | ||
1083 | /* Construct a pretty variable name for an element's replacement variable. | |
1084 | The name is built on the obstack. */ | |
1085 | ||
1086 | static char * | |
1087 | build_element_name (struct sra_elt *elt) | |
1088 | { | |
1089 | build_element_name_1 (elt); | |
1090 | obstack_1grow (&sra_obstack, '\0'); | |
1091 | return obstack_finish (&sra_obstack); | |
1092 | } | |
1093 | ||
1094 | /* Instantiate an element as an independent variable. */ | |
1095 | ||
1096 | static void | |
1097 | instantiate_element (struct sra_elt *elt) | |
1098 | { | |
1099 | struct sra_elt *base_elt; | |
1100 | tree var, base; | |
1101 | ||
1102 | for (base_elt = elt; base_elt->parent; base_elt = base_elt->parent) | |
1103 | continue; | |
1104 | base = base_elt->element; | |
1105 | ||
1106 | elt->replacement = var = make_rename_temp (elt->type, "SR"); | |
1107 | DECL_SOURCE_LOCATION (var) = DECL_SOURCE_LOCATION (base); | |
1108 | TREE_NO_WARNING (var) = TREE_NO_WARNING (base); | |
1109 | DECL_ARTIFICIAL (var) = DECL_ARTIFICIAL (base); | |
310ff872 | 1110 | DECL_IGNORED_P (var) = DECL_IGNORED_P (base); |
97e73bd2 RH |
1111 | |
1112 | if (DECL_NAME (base) && !DECL_IGNORED_P (base)) | |
1113 | { | |
1114 | char *pretty_name = build_element_name (elt); | |
1115 | DECL_NAME (var) = get_identifier (pretty_name); | |
1116 | obstack_free (&sra_obstack, pretty_name); | |
1117 | } | |
1118 | ||
1119 | if (dump_file) | |
1120 | { | |
1121 | fputs (" ", dump_file); | |
1122 | dump_sra_elt_name (dump_file, elt); | |
1123 | fputs (" -> ", dump_file); | |
1124 | print_generic_expr (dump_file, var, dump_flags); | |
1125 | fputc ('\n', dump_file); | |
1126 | } | |
1127 | } | |
1128 | ||
1129 | /* Make one pass across an element tree deciding whether or not it's | |
1130 | profitable to instantiate individual leaf scalars. | |
1131 | ||
1132 | PARENT_USES and PARENT_COPIES are the sum of the N_USES and N_COPIES | |
1133 | fields all the way up the tree. */ | |
1134 | ||
1135 | static void | |
1136 | decide_instantiation_1 (struct sra_elt *elt, unsigned int parent_uses, | |
1137 | unsigned int parent_copies) | |
1138 | { | |
1139 | if (dump_file && !elt->parent) | |
1140 | { | |
1141 | fputs ("Initial instantiation for ", dump_file); | |
1142 | dump_sra_elt_name (dump_file, elt); | |
1143 | fputc ('\n', dump_file); | |
1144 | } | |
1145 | ||
1146 | if (elt->cannot_scalarize) | |
1147 | return; | |
1148 | ||
1149 | if (elt->is_scalar) | |
1150 | { | |
1151 | /* The decision is simple: instantiate if we're used more frequently | |
1152 | than the parent needs to be seen as a complete unit. */ | |
1153 | if (elt->n_uses + elt->n_copies + parent_copies > parent_uses) | |
1154 | instantiate_element (elt); | |
1155 | } | |
1156 | else | |
1157 | { | |
1158 | struct sra_elt *c; | |
1159 | unsigned int this_uses = elt->n_uses + parent_uses; | |
1160 | unsigned int this_copies = elt->n_copies + parent_copies; | |
1161 | ||
1162 | for (c = elt->children; c ; c = c->sibling) | |
1163 | decide_instantiation_1 (c, this_uses, this_copies); | |
1164 | } | |
1165 | } | |
1166 | ||
1167 | /* Compute the size and number of all instantiated elements below ELT. | |
1168 | We will only care about this if the size of the complete structure | |
1169 | fits in a HOST_WIDE_INT, so we don't have to worry about overflow. */ | |
1170 | ||
1171 | static unsigned int | |
1172 | sum_instantiated_sizes (struct sra_elt *elt, unsigned HOST_WIDE_INT *sizep) | |
1173 | { | |
1174 | if (elt->replacement) | |
1175 | { | |
1176 | *sizep += TREE_INT_CST_LOW (TYPE_SIZE_UNIT (elt->type)); | |
1177 | return 1; | |
1178 | } | |
1179 | else | |
1180 | { | |
1181 | struct sra_elt *c; | |
1182 | unsigned int count = 0; | |
1183 | ||
1184 | for (c = elt->children; c ; c = c->sibling) | |
1185 | count += sum_instantiated_sizes (c, sizep); | |
1186 | ||
1187 | return count; | |
1188 | } | |
1189 | } | |
1190 | ||
1191 | /* Instantiate fields in ELT->TYPE that are not currently present as | |
1192 | children of ELT. */ | |
1193 | ||
1194 | static void instantiate_missing_elements (struct sra_elt *elt); | |
1195 | ||
1196 | static void | |
1197 | instantiate_missing_elements_1 (struct sra_elt *elt, tree child, tree type) | |
1198 | { | |
1199 | struct sra_elt *sub = lookup_element (elt, child, type, INSERT); | |
1200 | if (sub->is_scalar) | |
1201 | { | |
1202 | if (sub->replacement == NULL) | |
1203 | instantiate_element (sub); | |
1204 | } | |
1205 | else | |
1206 | instantiate_missing_elements (sub); | |
1207 | } | |
1208 | ||
1209 | static void | |
1210 | instantiate_missing_elements (struct sra_elt *elt) | |
1211 | { | |
1212 | tree type = elt->type; | |
1213 | ||
1214 | switch (TREE_CODE (type)) | |
1215 | { | |
1216 | case RECORD_TYPE: | |
1217 | { | |
1218 | tree f; | |
1219 | for (f = TYPE_FIELDS (type); f ; f = TREE_CHAIN (f)) | |
1220 | if (TREE_CODE (f) == FIELD_DECL) | |
1221 | instantiate_missing_elements_1 (elt, f, TREE_TYPE (f)); | |
1222 | break; | |
1223 | } | |
1224 | ||
1225 | case ARRAY_TYPE: | |
1226 | { | |
1227 | tree i, max, subtype; | |
1228 | ||
1229 | i = TYPE_MIN_VALUE (TYPE_DOMAIN (type)); | |
1230 | max = TYPE_MAX_VALUE (TYPE_DOMAIN (type)); | |
1231 | subtype = TREE_TYPE (type); | |
1232 | ||
1233 | while (1) | |
1234 | { | |
1235 | instantiate_missing_elements_1 (elt, i, subtype); | |
1236 | if (tree_int_cst_equal (i, max)) | |
1237 | break; | |
1238 | i = int_const_binop (PLUS_EXPR, i, integer_one_node, true); | |
1239 | } | |
1240 | ||
1241 | break; | |
1242 | } | |
1243 | ||
1244 | case COMPLEX_TYPE: | |
1245 | type = TREE_TYPE (type); | |
1246 | instantiate_missing_elements_1 (elt, integer_zero_node, type); | |
1247 | instantiate_missing_elements_1 (elt, integer_one_node, type); | |
1248 | break; | |
1249 | ||
1250 | default: | |
1e128c5f | 1251 | gcc_unreachable (); |
97e73bd2 RH |
1252 | } |
1253 | } | |
1254 | ||
1255 | /* Make one pass across an element tree deciding whether to perform block | |
1256 | or element copies. If we decide on element copies, instantiate all | |
1257 | elements. Return true if there are any instantiated sub-elements. */ | |
1258 | ||
1259 | static bool | |
1260 | decide_block_copy (struct sra_elt *elt) | |
1261 | { | |
1262 | struct sra_elt *c; | |
1263 | bool any_inst; | |
1264 | ||
1265 | /* If scalarization is disabled, respect it. */ | |
1266 | if (elt->cannot_scalarize) | |
1267 | { | |
1268 | elt->use_block_copy = 1; | |
1269 | ||
1270 | if (dump_file) | |
1271 | { | |
1272 | fputs ("Scalarization disabled for ", dump_file); | |
1273 | dump_sra_elt_name (dump_file, elt); | |
1274 | fputc ('\n', dump_file); | |
1275 | } | |
1276 | ||
1277 | return false; | |
1278 | } | |
1279 | ||
1280 | /* Don't decide if we've no uses. */ | |
1281 | if (elt->n_uses == 0 && elt->n_copies == 0) | |
1282 | ; | |
1283 | ||
1284 | else if (!elt->is_scalar) | |
1285 | { | |
1286 | tree size_tree = TYPE_SIZE_UNIT (elt->type); | |
1287 | bool use_block_copy = true; | |
1288 | ||
1289 | /* Don't bother trying to figure out the rest if the structure is | |
1290 | so large we can't do easy arithmetic. This also forces block | |
1291 | copies for variable sized structures. */ | |
1292 | if (host_integerp (size_tree, 1)) | |
1293 | { | |
1294 | unsigned HOST_WIDE_INT full_size, inst_size = 0; | |
1295 | unsigned int inst_count; | |
61b58001 BE |
1296 | unsigned int max_size; |
1297 | ||
1298 | /* If the sra-max-structure-size parameter is 0, then the | |
1299 | user has not overridden the parameter and we can choose a | |
1300 | sensible default. */ | |
1301 | max_size = SRA_MAX_STRUCTURE_SIZE | |
1302 | ? SRA_MAX_STRUCTURE_SIZE | |
1303 | : MOVE_RATIO * UNITS_PER_WORD; | |
97e73bd2 RH |
1304 | |
1305 | full_size = tree_low_cst (size_tree, 1); | |
1306 | ||
19114537 | 1307 | /* ??? What to do here. If there are two fields, and we've only |
97e73bd2 RH |
1308 | instantiated one, then instantiating the other is clearly a win. |
1309 | If there are a large number of fields then the size of the copy | |
1310 | is much more of a factor. */ | |
1311 | ||
1312 | /* If the structure is small, and we've made copies, go ahead | |
1313 | and instantiate, hoping that the copies will go away. */ | |
61b58001 | 1314 | if (full_size <= max_size |
97e73bd2 RH |
1315 | && elt->n_copies > elt->n_uses) |
1316 | use_block_copy = false; | |
1317 | else | |
1318 | { | |
1319 | inst_count = sum_instantiated_sizes (elt, &inst_size); | |
1320 | ||
61b58001 | 1321 | if (inst_size * 100 >= full_size * SRA_FIELD_STRUCTURE_RATIO) |
97e73bd2 RH |
1322 | use_block_copy = false; |
1323 | } | |
1324 | ||
1325 | /* In order to avoid block copy, we have to be able to instantiate | |
1326 | all elements of the type. See if this is possible. */ | |
1327 | if (!use_block_copy | |
1328 | && (!can_completely_scalarize_p (elt) | |
1329 | || !type_can_instantiate_all_elements (elt->type))) | |
1330 | use_block_copy = true; | |
1331 | } | |
1332 | elt->use_block_copy = use_block_copy; | |
1333 | ||
1334 | if (dump_file) | |
1335 | { | |
1336 | fprintf (dump_file, "Using %s for ", | |
1337 | use_block_copy ? "block-copy" : "element-copy"); | |
1338 | dump_sra_elt_name (dump_file, elt); | |
1339 | fputc ('\n', dump_file); | |
1340 | } | |
1341 | ||
1342 | if (!use_block_copy) | |
1343 | { | |
1344 | instantiate_missing_elements (elt); | |
1345 | return true; | |
1346 | } | |
1347 | } | |
1348 | ||
1349 | any_inst = elt->replacement != NULL; | |
1350 | ||
1351 | for (c = elt->children; c ; c = c->sibling) | |
1352 | any_inst |= decide_block_copy (c); | |
1353 | ||
1354 | return any_inst; | |
1355 | } | |
1356 | ||
1357 | /* Entry point to phase 3. Instantiate scalar replacement variables. */ | |
1358 | ||
1359 | static void | |
1360 | decide_instantiations (void) | |
1361 | { | |
1362 | unsigned int i; | |
1363 | bool cleared_any; | |
7932a3db | 1364 | bitmap_head done_head; |
87c476a2 | 1365 | bitmap_iterator bi; |
97e73bd2 RH |
1366 | |
1367 | /* We cannot clear bits from a bitmap we're iterating over, | |
1368 | so save up all the bits to clear until the end. */ | |
7932a3db | 1369 | bitmap_initialize (&done_head, &bitmap_default_obstack); |
97e73bd2 RH |
1370 | cleared_any = false; |
1371 | ||
87c476a2 | 1372 | EXECUTE_IF_SET_IN_BITMAP (sra_candidates, 0, i, bi) |
97e73bd2 RH |
1373 | { |
1374 | tree var = referenced_var (i); | |
1375 | struct sra_elt *elt = lookup_element (NULL, var, NULL, NO_INSERT); | |
1376 | if (elt) | |
1377 | { | |
1378 | decide_instantiation_1 (elt, 0, 0); | |
1379 | if (!decide_block_copy (elt)) | |
1380 | elt = NULL; | |
1381 | } | |
1382 | if (!elt) | |
1383 | { | |
1384 | bitmap_set_bit (&done_head, i); | |
1385 | cleared_any = true; | |
1386 | } | |
87c476a2 | 1387 | } |
97e73bd2 RH |
1388 | |
1389 | if (cleared_any) | |
1390 | { | |
eb59b8de NS |
1391 | bitmap_and_compl_into (sra_candidates, &done_head); |
1392 | bitmap_and_compl_into (needs_copy_in, &done_head); | |
97e73bd2 RH |
1393 | } |
1394 | bitmap_clear (&done_head); | |
1395 | ||
1396 | if (dump_file) | |
1397 | fputc ('\n', dump_file); | |
1398 | } | |
1399 | ||
1400 | \f | |
1401 | /* Phase Four: Update the function to match the replacements created. */ | |
1402 | ||
1403 | /* Mark all the variables in V_MAY_DEF or V_MUST_DEF operands for STMT for | |
1404 | renaming. This becomes necessary when we modify all of a non-scalar. */ | |
1405 | ||
1406 | static void | |
1407 | mark_all_v_defs (tree stmt) | |
1408 | { | |
4c124b4c AM |
1409 | tree sym; |
1410 | ssa_op_iter iter; | |
97e73bd2 RH |
1411 | |
1412 | get_stmt_operands (stmt); | |
1413 | ||
4c124b4c | 1414 | FOR_EACH_SSA_TREE_OPERAND (sym, stmt, iter, SSA_OP_VIRTUAL_DEFS) |
97e73bd2 | 1415 | { |
97e73bd2 RH |
1416 | if (TREE_CODE (sym) == SSA_NAME) |
1417 | sym = SSA_NAME_VAR (sym); | |
1418 | bitmap_set_bit (vars_to_rename, var_ann (sym)->uid); | |
1419 | } | |
6de9cd9a DN |
1420 | } |
1421 | ||
97e73bd2 | 1422 | /* Build a single level component reference to ELT rooted at BASE. */ |
6de9cd9a DN |
1423 | |
1424 | static tree | |
97e73bd2 | 1425 | generate_one_element_ref (struct sra_elt *elt, tree base) |
6de9cd9a | 1426 | { |
97e73bd2 | 1427 | switch (TREE_CODE (TREE_TYPE (base))) |
6de9cd9a | 1428 | { |
97e73bd2 | 1429 | case RECORD_TYPE: |
fa27426e RH |
1430 | { |
1431 | tree field = elt->element; | |
1432 | ||
1433 | /* Watch out for compatible records with differing field lists. */ | |
1434 | if (DECL_FIELD_CONTEXT (field) != TYPE_MAIN_VARIANT (TREE_TYPE (base))) | |
1435 | field = find_compatible_field (TREE_TYPE (base), field); | |
1436 | ||
1437 | return build (COMPONENT_REF, elt->type, base, field, NULL); | |
1438 | } | |
6de9cd9a | 1439 | |
97e73bd2 RH |
1440 | case ARRAY_TYPE: |
1441 | return build (ARRAY_REF, elt->type, base, elt->element, NULL, NULL); | |
6de9cd9a | 1442 | |
97e73bd2 RH |
1443 | case COMPLEX_TYPE: |
1444 | if (elt->element == integer_zero_node) | |
1445 | return build (REALPART_EXPR, elt->type, base); | |
1446 | else | |
1447 | return build (IMAGPART_EXPR, elt->type, base); | |
6de9cd9a | 1448 | |
97e73bd2 | 1449 | default: |
1e128c5f | 1450 | gcc_unreachable (); |
97e73bd2 | 1451 | } |
6de9cd9a DN |
1452 | } |
1453 | ||
97e73bd2 | 1454 | /* Build a full component reference to ELT rooted at its native variable. */ |
6de9cd9a DN |
1455 | |
1456 | static tree | |
97e73bd2 RH |
1457 | generate_element_ref (struct sra_elt *elt) |
1458 | { | |
1459 | if (elt->parent) | |
1460 | return generate_one_element_ref (elt, generate_element_ref (elt->parent)); | |
1461 | else | |
1462 | return elt->element; | |
1463 | } | |
1464 | ||
1465 | /* Generate a set of assignment statements in *LIST_P to copy all | |
1466 | instantiated elements under ELT to or from the equivalent structure | |
1467 | rooted at EXPR. COPY_OUT controls the direction of the copy, with | |
1468 | true meaning to copy out of EXPR into ELT. */ | |
1469 | ||
1470 | static void | |
1471 | generate_copy_inout (struct sra_elt *elt, bool copy_out, tree expr, | |
1472 | tree *list_p) | |
6de9cd9a | 1473 | { |
97e73bd2 RH |
1474 | struct sra_elt *c; |
1475 | tree t; | |
1476 | ||
1477 | if (elt->replacement) | |
6de9cd9a | 1478 | { |
97e73bd2 RH |
1479 | if (copy_out) |
1480 | t = build (MODIFY_EXPR, void_type_node, elt->replacement, expr); | |
6de9cd9a | 1481 | else |
97e73bd2 RH |
1482 | t = build (MODIFY_EXPR, void_type_node, expr, elt->replacement); |
1483 | append_to_statement_list (t, list_p); | |
1484 | } | |
1485 | else | |
1486 | { | |
1487 | for (c = elt->children; c ; c = c->sibling) | |
1488 | { | |
1489 | t = generate_one_element_ref (c, unshare_expr (expr)); | |
1490 | generate_copy_inout (c, copy_out, t, list_p); | |
1491 | } | |
1492 | } | |
1493 | } | |
6de9cd9a | 1494 | |
97e73bd2 RH |
1495 | /* Generate a set of assignment statements in *LIST_P to copy all instantiated |
1496 | elements under SRC to their counterparts under DST. There must be a 1-1 | |
1497 | correspondence of instantiated elements. */ | |
6de9cd9a | 1498 | |
97e73bd2 RH |
1499 | static void |
1500 | generate_element_copy (struct sra_elt *dst, struct sra_elt *src, tree *list_p) | |
1501 | { | |
1502 | struct sra_elt *dc, *sc; | |
6de9cd9a | 1503 | |
97e73bd2 RH |
1504 | for (dc = dst->children; dc ; dc = dc->sibling) |
1505 | { | |
1506 | sc = lookup_element (src, dc->element, NULL, NO_INSERT); | |
1e128c5f | 1507 | gcc_assert (sc); |
97e73bd2 | 1508 | generate_element_copy (dc, sc, list_p); |
6de9cd9a DN |
1509 | } |
1510 | ||
97e73bd2 RH |
1511 | if (dst->replacement) |
1512 | { | |
1513 | tree t; | |
6de9cd9a | 1514 | |
1e128c5f | 1515 | gcc_assert (src->replacement); |
6de9cd9a | 1516 | |
97e73bd2 RH |
1517 | t = build (MODIFY_EXPR, void_type_node, dst->replacement, |
1518 | src->replacement); | |
1519 | append_to_statement_list (t, list_p); | |
1520 | } | |
1521 | } | |
6de9cd9a | 1522 | |
97e73bd2 RH |
1523 | /* Generate a set of assignment statements in *LIST_P to zero all instantiated |
1524 | elements under ELT. In addition, do not assign to elements that have been | |
1525 | marked VISITED but do reset the visited flag; this allows easy coordination | |
1526 | with generate_element_init. */ | |
6de9cd9a | 1527 | |
97e73bd2 RH |
1528 | static void |
1529 | generate_element_zero (struct sra_elt *elt, tree *list_p) | |
6de9cd9a | 1530 | { |
97e73bd2 | 1531 | struct sra_elt *c; |
6de9cd9a | 1532 | |
bfeebecf RH |
1533 | if (elt->visited) |
1534 | { | |
1535 | elt->visited = false; | |
1536 | return; | |
1537 | } | |
1538 | ||
97e73bd2 RH |
1539 | for (c = elt->children; c ; c = c->sibling) |
1540 | generate_element_zero (c, list_p); | |
6de9cd9a | 1541 | |
bfeebecf | 1542 | if (elt->replacement) |
6de9cd9a | 1543 | { |
97e73bd2 | 1544 | tree t; |
6de9cd9a | 1545 | |
1e128c5f | 1546 | gcc_assert (elt->is_scalar); |
ec76a0e0 | 1547 | t = fold_convert (elt->type, integer_zero_node); |
6de9cd9a | 1548 | |
97e73bd2 RH |
1549 | t = build (MODIFY_EXPR, void_type_node, elt->replacement, t); |
1550 | append_to_statement_list (t, list_p); | |
6de9cd9a | 1551 | } |
97e73bd2 | 1552 | } |
6de9cd9a | 1553 | |
71956db3 RH |
1554 | /* Generate an assignment VAR = INIT, where INIT may need gimplification. |
1555 | Add the result to *LIST_P. */ | |
1556 | ||
1557 | static void | |
1558 | generate_one_element_init (tree var, tree init, tree *list_p) | |
1559 | { | |
1560 | tree stmt; | |
1561 | ||
1562 | /* The replacement can be almost arbitrarily complex. Gimplify. */ | |
1563 | stmt = build (MODIFY_EXPR, void_type_node, var, init); | |
1564 | gimplify_stmt (&stmt); | |
1565 | ||
1566 | /* The replacement can expose previously unreferenced variables. */ | |
1567 | if (TREE_CODE (stmt) == STATEMENT_LIST) | |
1568 | { | |
1569 | tree_stmt_iterator i; | |
1570 | for (i = tsi_start (stmt); !tsi_end_p (i); tsi_next (&i)) | |
1571 | find_new_referenced_vars (tsi_stmt_ptr (i)); | |
1572 | } | |
1573 | else | |
1574 | find_new_referenced_vars (&stmt); | |
1575 | ||
1576 | append_to_statement_list (stmt, list_p); | |
1577 | } | |
1578 | ||
97e73bd2 RH |
1579 | /* Generate a set of assignment statements in *LIST_P to set all instantiated |
1580 | elements under ELT with the contents of the initializer INIT. In addition, | |
1581 | mark all assigned elements VISITED; this allows easy coordination with | |
402a3dec RK |
1582 | generate_element_zero. Return false if we found a case we couldn't |
1583 | handle. */ | |
6de9cd9a | 1584 | |
402a3dec | 1585 | static bool |
97e73bd2 RH |
1586 | generate_element_init (struct sra_elt *elt, tree init, tree *list_p) |
1587 | { | |
402a3dec | 1588 | bool result = true; |
51fa2e5f | 1589 | enum tree_code init_code; |
97e73bd2 RH |
1590 | struct sra_elt *sub; |
1591 | tree t; | |
6de9cd9a | 1592 | |
402a3dec RK |
1593 | /* We can be passed DECL_INITIAL of a static variable. It might have a |
1594 | conversion, which we strip off here. */ | |
51fa2e5f RK |
1595 | STRIP_USELESS_TYPE_CONVERSION (init); |
1596 | init_code = TREE_CODE (init); | |
1597 | ||
97e73bd2 RH |
1598 | if (elt->is_scalar) |
1599 | { | |
1600 | if (elt->replacement) | |
6de9cd9a | 1601 | { |
71956db3 | 1602 | generate_one_element_init (elt->replacement, init, list_p); |
97e73bd2 | 1603 | elt->visited = true; |
6de9cd9a | 1604 | } |
402a3dec | 1605 | return result; |
97e73bd2 | 1606 | } |
6de9cd9a | 1607 | |
97e73bd2 RH |
1608 | switch (init_code) |
1609 | { | |
1610 | case COMPLEX_CST: | |
1611 | case COMPLEX_EXPR: | |
1612 | for (sub = elt->children; sub ; sub = sub->sibling) | |
6de9cd9a | 1613 | { |
97e73bd2 RH |
1614 | if (sub->element == integer_zero_node) |
1615 | t = (init_code == COMPLEX_EXPR | |
1616 | ? TREE_OPERAND (init, 0) : TREE_REALPART (init)); | |
6de9cd9a | 1617 | else |
97e73bd2 RH |
1618 | t = (init_code == COMPLEX_EXPR |
1619 | ? TREE_OPERAND (init, 1) : TREE_IMAGPART (init)); | |
402a3dec | 1620 | result &= generate_element_init (sub, t, list_p); |
6de9cd9a | 1621 | } |
97e73bd2 | 1622 | break; |
6de9cd9a | 1623 | |
97e73bd2 RH |
1624 | case CONSTRUCTOR: |
1625 | for (t = CONSTRUCTOR_ELTS (init); t ; t = TREE_CHAIN (t)) | |
6de9cd9a | 1626 | { |
97e73bd2 RH |
1627 | sub = lookup_element (elt, TREE_PURPOSE (t), NULL, NO_INSERT); |
1628 | if (sub == NULL) | |
6de9cd9a | 1629 | continue; |
402a3dec | 1630 | result &= generate_element_init (sub, TREE_VALUE (t), list_p); |
97e73bd2 RH |
1631 | } |
1632 | break; | |
6de9cd9a | 1633 | |
97e73bd2 | 1634 | default: |
bfeebecf | 1635 | elt->visited = true; |
402a3dec | 1636 | result = false; |
97e73bd2 | 1637 | } |
402a3dec RK |
1638 | |
1639 | return result; | |
97e73bd2 | 1640 | } |
6de9cd9a | 1641 | |
97e73bd2 RH |
1642 | /* Insert STMT on all the outgoing edges out of BB. Note that if BB |
1643 | has more than one edge, STMT will be replicated for each edge. Also, | |
1644 | abnormal edges will be ignored. */ | |
6de9cd9a | 1645 | |
97e73bd2 RH |
1646 | void |
1647 | insert_edge_copies (tree stmt, basic_block bb) | |
1648 | { | |
1649 | edge e; | |
628f6a4e | 1650 | edge_iterator ei; |
97e73bd2 | 1651 | bool first_copy; |
6de9cd9a | 1652 | |
97e73bd2 | 1653 | first_copy = true; |
628f6a4e | 1654 | FOR_EACH_EDGE (e, ei, bb->succs) |
6de9cd9a | 1655 | { |
97e73bd2 RH |
1656 | /* We don't need to insert copies on abnormal edges. The |
1657 | value of the scalar replacement is not guaranteed to | |
1658 | be valid through an abnormal edge. */ | |
1659 | if (!(e->flags & EDGE_ABNORMAL)) | |
6de9cd9a | 1660 | { |
97e73bd2 RH |
1661 | if (first_copy) |
1662 | { | |
1663 | bsi_insert_on_edge (e, stmt); | |
1664 | first_copy = false; | |
1665 | } | |
1666 | else | |
19114537 | 1667 | bsi_insert_on_edge (e, unsave_expr_now (stmt)); |
6de9cd9a | 1668 | } |
6de9cd9a | 1669 | } |
6de9cd9a DN |
1670 | } |
1671 | ||
97e73bd2 | 1672 | /* Helper function to insert LIST before BSI, and set up line number info. */ |
6de9cd9a DN |
1673 | |
1674 | static void | |
97e73bd2 | 1675 | sra_insert_before (block_stmt_iterator *bsi, tree list) |
6de9cd9a | 1676 | { |
6de9cd9a DN |
1677 | tree stmt = bsi_stmt (*bsi); |
1678 | ||
1679 | if (EXPR_HAS_LOCATION (stmt)) | |
1680 | annotate_all_with_locus (&list, EXPR_LOCATION (stmt)); | |
6de9cd9a DN |
1681 | bsi_insert_before (bsi, list, BSI_SAME_STMT); |
1682 | } | |
1683 | ||
97e73bd2 | 1684 | /* Similarly, but insert after BSI. Handles insertion onto edges as well. */ |
6de9cd9a DN |
1685 | |
1686 | static void | |
97e73bd2 | 1687 | sra_insert_after (block_stmt_iterator *bsi, tree list) |
6de9cd9a | 1688 | { |
97e73bd2 | 1689 | tree stmt = bsi_stmt (*bsi); |
6de9cd9a | 1690 | |
97e73bd2 RH |
1691 | if (EXPR_HAS_LOCATION (stmt)) |
1692 | annotate_all_with_locus (&list, EXPR_LOCATION (stmt)); | |
6de9cd9a | 1693 | |
97e73bd2 RH |
1694 | if (stmt_ends_bb_p (stmt)) |
1695 | insert_edge_copies (list, bsi->bb); | |
1696 | else | |
bdecd334 | 1697 | bsi_insert_after (bsi, list, BSI_SAME_STMT); |
6de9cd9a DN |
1698 | } |
1699 | ||
97e73bd2 | 1700 | /* Similarly, but replace the statement at BSI. */ |
6de9cd9a DN |
1701 | |
1702 | static void | |
97e73bd2 | 1703 | sra_replace (block_stmt_iterator *bsi, tree list) |
6de9cd9a | 1704 | { |
97e73bd2 RH |
1705 | sra_insert_before (bsi, list); |
1706 | bsi_remove (bsi); | |
1707 | if (bsi_end_p (*bsi)) | |
1708 | *bsi = bsi_last (bsi->bb); | |
1709 | else | |
1710 | bsi_prev (bsi); | |
6de9cd9a DN |
1711 | } |
1712 | ||
97e73bd2 | 1713 | /* Scalarize a USE. To recap, this is either a simple reference to ELT, |
f6fe65dc | 1714 | if elt is scalar, or some occurrence of ELT that requires a complete |
97e73bd2 | 1715 | aggregate. IS_OUTPUT is true if ELT is being modified. */ |
6de9cd9a DN |
1716 | |
1717 | static void | |
97e73bd2 RH |
1718 | scalarize_use (struct sra_elt *elt, tree *expr_p, block_stmt_iterator *bsi, |
1719 | bool is_output) | |
6de9cd9a | 1720 | { |
97e73bd2 | 1721 | tree list = NULL, stmt = bsi_stmt (*bsi); |
6de9cd9a | 1722 | |
97e73bd2 | 1723 | if (elt->replacement) |
6de9cd9a | 1724 | { |
97e73bd2 RH |
1725 | /* If we have a replacement, then updating the reference is as |
1726 | simple as modifying the existing statement in place. */ | |
1727 | if (is_output) | |
1728 | mark_all_v_defs (stmt); | |
1729 | *expr_p = elt->replacement; | |
1730 | modify_stmt (stmt); | |
6de9cd9a | 1731 | } |
97e73bd2 | 1732 | else |
6de9cd9a | 1733 | { |
97e73bd2 RH |
1734 | /* Otherwise we need some copies. If ELT is being read, then we want |
1735 | to store all (modified) sub-elements back into the structure before | |
1736 | the reference takes place. If ELT is being written, then we want to | |
1737 | load the changed values back into our shadow variables. */ | |
1738 | /* ??? We don't check modified for reads, we just always write all of | |
1739 | the values. We should be able to record the SSA number of the VOP | |
1740 | for which the values were last read. If that number matches the | |
1741 | SSA number of the VOP in the current statement, then we needn't | |
1742 | emit an assignment. This would also eliminate double writes when | |
1743 | a structure is passed as more than one argument to a function call. | |
1744 | This optimization would be most effective if sra_walk_function | |
1745 | processed the blocks in dominator order. */ | |
1746 | ||
1747 | generate_copy_inout (elt, is_output, generate_element_ref (elt), &list); | |
1748 | if (list == NULL) | |
1749 | return; | |
504c0e4f | 1750 | mark_all_v_defs (expr_first (list)); |
97e73bd2 | 1751 | if (is_output) |
504c0e4f | 1752 | sra_insert_after (bsi, list); |
97e73bd2 RH |
1753 | else |
1754 | sra_insert_before (bsi, list); | |
6de9cd9a | 1755 | } |
6de9cd9a DN |
1756 | } |
1757 | ||
97e73bd2 RH |
1758 | /* Scalarize a COPY. To recap, this is an assignment statement between |
1759 | two scalarizable references, LHS_ELT and RHS_ELT. */ | |
6de9cd9a | 1760 | |
97e73bd2 RH |
1761 | static void |
1762 | scalarize_copy (struct sra_elt *lhs_elt, struct sra_elt *rhs_elt, | |
1763 | block_stmt_iterator *bsi) | |
6de9cd9a | 1764 | { |
97e73bd2 | 1765 | tree list, stmt; |
6de9cd9a | 1766 | |
97e73bd2 | 1767 | if (lhs_elt->replacement && rhs_elt->replacement) |
6de9cd9a | 1768 | { |
97e73bd2 RH |
1769 | /* If we have two scalar operands, modify the existing statement. */ |
1770 | stmt = bsi_stmt (*bsi); | |
6de9cd9a | 1771 | |
97e73bd2 RH |
1772 | /* See the commentary in sra_walk_function concerning |
1773 | RETURN_EXPR, and why we should never see one here. */ | |
1e128c5f | 1774 | gcc_assert (TREE_CODE (stmt) == MODIFY_EXPR); |
97e73bd2 RH |
1775 | |
1776 | TREE_OPERAND (stmt, 0) = lhs_elt->replacement; | |
1777 | TREE_OPERAND (stmt, 1) = rhs_elt->replacement; | |
1778 | modify_stmt (stmt); | |
1779 | } | |
1780 | else if (lhs_elt->use_block_copy || rhs_elt->use_block_copy) | |
1781 | { | |
1782 | /* If either side requires a block copy, then sync the RHS back | |
19114537 | 1783 | to the original structure, leave the original assignment |
97e73bd2 RH |
1784 | statement (which will perform the block copy), then load the |
1785 | LHS values out of its now-updated original structure. */ | |
1786 | /* ??? Could perform a modified pair-wise element copy. That | |
1787 | would at least allow those elements that are instantiated in | |
1788 | both structures to be optimized well. */ | |
1789 | ||
1790 | list = NULL; | |
1791 | generate_copy_inout (rhs_elt, false, | |
1792 | generate_element_ref (rhs_elt), &list); | |
1793 | if (list) | |
6de9cd9a | 1794 | { |
97e73bd2 RH |
1795 | mark_all_v_defs (expr_first (list)); |
1796 | sra_insert_before (bsi, list); | |
6de9cd9a | 1797 | } |
97e73bd2 RH |
1798 | |
1799 | list = NULL; | |
1800 | generate_copy_inout (lhs_elt, true, | |
1801 | generate_element_ref (lhs_elt), &list); | |
1802 | if (list) | |
1803 | sra_insert_after (bsi, list); | |
6de9cd9a | 1804 | } |
97e73bd2 RH |
1805 | else |
1806 | { | |
1807 | /* Otherwise both sides must be fully instantiated. In which | |
1808 | case perform pair-wise element assignments and replace the | |
1809 | original block copy statement. */ | |
1810 | ||
1811 | stmt = bsi_stmt (*bsi); | |
1812 | mark_all_v_defs (stmt); | |
6de9cd9a | 1813 | |
97e73bd2 RH |
1814 | list = NULL; |
1815 | generate_element_copy (lhs_elt, rhs_elt, &list); | |
1e128c5f | 1816 | gcc_assert (list); |
97e73bd2 RH |
1817 | sra_replace (bsi, list); |
1818 | } | |
1819 | } | |
6de9cd9a | 1820 | |
97e73bd2 RH |
1821 | /* Scalarize an INIT. To recap, this is an assignment to a scalarizable |
1822 | reference from some form of constructor: CONSTRUCTOR, COMPLEX_CST or | |
1823 | COMPLEX_EXPR. If RHS is NULL, it should be treated as an empty | |
bfeebecf | 1824 | CONSTRUCTOR. */ |
6de9cd9a | 1825 | |
bfeebecf | 1826 | static void |
97e73bd2 | 1827 | scalarize_init (struct sra_elt *lhs_elt, tree rhs, block_stmt_iterator *bsi) |
6de9cd9a | 1828 | { |
402a3dec | 1829 | bool result = true; |
97e73bd2 | 1830 | tree list = NULL; |
6de9cd9a | 1831 | |
97e73bd2 RH |
1832 | /* Generate initialization statements for all members extant in the RHS. */ |
1833 | if (rhs) | |
71956db3 RH |
1834 | { |
1835 | push_gimplify_context (); | |
1836 | result = generate_element_init (lhs_elt, rhs, &list); | |
1837 | pop_gimplify_context (NULL); | |
1838 | } | |
6de9cd9a | 1839 | |
97e73bd2 RH |
1840 | /* CONSTRUCTOR is defined such that any member not mentioned is assigned |
1841 | a zero value. Initialize the rest of the instantiated elements. */ | |
1842 | generate_element_zero (lhs_elt, &list); | |
402a3dec | 1843 | |
bfeebecf RH |
1844 | if (!result) |
1845 | { | |
1846 | /* If we failed to convert the entire initializer, then we must | |
1847 | leave the structure assignment in place and must load values | |
1848 | from the structure into the slots for which we did not find | |
1849 | constants. The easiest way to do this is to generate a complete | |
1850 | copy-out, and then follow that with the constant assignments | |
1851 | that we were able to build. DCE will clean things up. */ | |
1852 | tree list0 = NULL; | |
1853 | generate_copy_inout (lhs_elt, true, generate_element_ref (lhs_elt), | |
1854 | &list0); | |
1855 | append_to_statement_list (list, &list0); | |
1856 | list = list0; | |
1857 | } | |
6de9cd9a | 1858 | |
bfeebecf | 1859 | if (lhs_elt->use_block_copy || !result) |
97e73bd2 RH |
1860 | { |
1861 | /* Since LHS is not fully instantiated, we must leave the structure | |
1862 | assignment in place. Treating this case differently from a USE | |
1863 | exposes constants to later optimizations. */ | |
bfeebecf RH |
1864 | if (list) |
1865 | { | |
1866 | mark_all_v_defs (expr_first (list)); | |
1867 | sra_insert_after (bsi, list); | |
1868 | } | |
97e73bd2 RH |
1869 | } |
1870 | else | |
1871 | { | |
1872 | /* The LHS is fully instantiated. The list of initializations | |
1873 | replaces the original structure assignment. */ | |
1e128c5f | 1874 | gcc_assert (list); |
97e73bd2 RH |
1875 | mark_all_v_defs (bsi_stmt (*bsi)); |
1876 | sra_replace (bsi, list); | |
6de9cd9a DN |
1877 | } |
1878 | } | |
1879 | ||
97e73bd2 RH |
1880 | /* A subroutine of scalarize_ldst called via walk_tree. Set TREE_NO_TRAP |
1881 | on all INDIRECT_REFs. */ | |
6de9cd9a | 1882 | |
97e73bd2 RH |
1883 | static tree |
1884 | mark_notrap (tree *tp, int *walk_subtrees, void *data ATTRIBUTE_UNUSED) | |
6de9cd9a | 1885 | { |
97e73bd2 | 1886 | tree t = *tp; |
6de9cd9a | 1887 | |
97e73bd2 RH |
1888 | if (TREE_CODE (t) == INDIRECT_REF) |
1889 | { | |
1890 | TREE_THIS_NOTRAP (t) = 1; | |
1891 | *walk_subtrees = 0; | |
1892 | } | |
6615c446 | 1893 | else if (IS_TYPE_OR_DECL_P (t)) |
97e73bd2 | 1894 | *walk_subtrees = 0; |
6de9cd9a | 1895 | |
97e73bd2 | 1896 | return NULL; |
6de9cd9a DN |
1897 | } |
1898 | ||
97e73bd2 RH |
1899 | /* Scalarize a LDST. To recap, this is an assignment between one scalarizable |
1900 | reference ELT and one non-scalarizable reference OTHER. IS_OUTPUT is true | |
1901 | if ELT is on the left-hand side. */ | |
6de9cd9a DN |
1902 | |
1903 | static void | |
97e73bd2 RH |
1904 | scalarize_ldst (struct sra_elt *elt, tree other, |
1905 | block_stmt_iterator *bsi, bool is_output) | |
6de9cd9a | 1906 | { |
97e73bd2 | 1907 | /* Shouldn't have gotten called for a scalar. */ |
1e128c5f | 1908 | gcc_assert (!elt->replacement); |
6de9cd9a | 1909 | |
97e73bd2 RH |
1910 | if (elt->use_block_copy) |
1911 | { | |
1912 | /* Since ELT is not fully instantiated, we have to leave the | |
1913 | block copy in place. Treat this as a USE. */ | |
1914 | scalarize_use (elt, NULL, bsi, is_output); | |
1915 | } | |
1916 | else | |
6de9cd9a | 1917 | { |
97e73bd2 RH |
1918 | /* The interesting case is when ELT is fully instantiated. In this |
1919 | case we can have each element stored/loaded directly to/from the | |
1920 | corresponding slot in OTHER. This avoids a block copy. */ | |
6de9cd9a | 1921 | |
97e73bd2 | 1922 | tree list = NULL, stmt = bsi_stmt (*bsi); |
6de9cd9a | 1923 | |
97e73bd2 RH |
1924 | mark_all_v_defs (stmt); |
1925 | generate_copy_inout (elt, is_output, other, &list); | |
1e128c5f | 1926 | gcc_assert (list); |
6de9cd9a | 1927 | |
97e73bd2 RH |
1928 | /* Preserve EH semantics. */ |
1929 | if (stmt_ends_bb_p (stmt)) | |
6de9cd9a | 1930 | { |
97e73bd2 RH |
1931 | tree_stmt_iterator tsi; |
1932 | tree first; | |
1933 | ||
1934 | /* Extract the first statement from LIST. */ | |
1935 | tsi = tsi_start (list); | |
1936 | first = tsi_stmt (tsi); | |
1937 | tsi_delink (&tsi); | |
1938 | ||
1939 | /* Replace the old statement with this new representative. */ | |
1940 | bsi_replace (bsi, first, true); | |
19114537 | 1941 | |
97e73bd2 RH |
1942 | if (!tsi_end_p (tsi)) |
1943 | { | |
1944 | /* If any reference would trap, then they all would. And more | |
1945 | to the point, the first would. Therefore none of the rest | |
1946 | will trap since the first didn't. Indicate this by | |
1947 | iterating over the remaining statements and set | |
1948 | TREE_THIS_NOTRAP in all INDIRECT_REFs. */ | |
1949 | do | |
1950 | { | |
1951 | walk_tree (tsi_stmt_ptr (tsi), mark_notrap, NULL, NULL); | |
1952 | tsi_next (&tsi); | |
1953 | } | |
1954 | while (!tsi_end_p (tsi)); | |
1955 | ||
1956 | insert_edge_copies (list, bsi->bb); | |
1957 | } | |
6de9cd9a | 1958 | } |
97e73bd2 RH |
1959 | else |
1960 | sra_replace (bsi, list); | |
6de9cd9a DN |
1961 | } |
1962 | } | |
1963 | ||
97e73bd2 | 1964 | /* Generate initializations for all scalarizable parameters. */ |
6de9cd9a | 1965 | |
97e73bd2 RH |
1966 | static void |
1967 | scalarize_parms (void) | |
6de9cd9a | 1968 | { |
97e73bd2 | 1969 | tree list = NULL; |
3cd8c58a | 1970 | unsigned i; |
87c476a2 | 1971 | bitmap_iterator bi; |
6de9cd9a | 1972 | |
87c476a2 | 1973 | EXECUTE_IF_SET_IN_BITMAP (needs_copy_in, 0, i, bi) |
19114537 | 1974 | { |
97e73bd2 RH |
1975 | tree var = referenced_var (i); |
1976 | struct sra_elt *elt = lookup_element (NULL, var, NULL, NO_INSERT); | |
1977 | generate_copy_inout (elt, true, var, &list); | |
87c476a2 | 1978 | } |
6de9cd9a | 1979 | |
97e73bd2 RH |
1980 | if (list) |
1981 | insert_edge_copies (list, ENTRY_BLOCK_PTR); | |
6de9cd9a DN |
1982 | } |
1983 | ||
97e73bd2 RH |
1984 | /* Entry point to phase 4. Update the function to match replacements. */ |
1985 | ||
6de9cd9a | 1986 | static void |
97e73bd2 | 1987 | scalarize_function (void) |
6de9cd9a | 1988 | { |
97e73bd2 RH |
1989 | static const struct sra_walk_fns fns = { |
1990 | scalarize_use, scalarize_copy, scalarize_init, scalarize_ldst, false | |
1991 | }; | |
1992 | ||
1993 | sra_walk_function (&fns); | |
1994 | scalarize_parms (); | |
8e731e4e | 1995 | bsi_commit_edge_inserts (); |
6de9cd9a DN |
1996 | } |
1997 | ||
97e73bd2 RH |
1998 | \f |
1999 | /* Debug helper function. Print ELT in a nice human-readable format. */ | |
6de9cd9a | 2000 | |
97e73bd2 RH |
2001 | static void |
2002 | dump_sra_elt_name (FILE *f, struct sra_elt *elt) | |
2003 | { | |
2004 | if (elt->parent && TREE_CODE (elt->parent->type) == COMPLEX_TYPE) | |
2005 | { | |
2006 | fputs (elt->element == integer_zero_node ? "__real__ " : "__imag__ ", f); | |
2007 | dump_sra_elt_name (f, elt->parent); | |
2008 | } | |
2009 | else | |
2010 | { | |
2011 | if (elt->parent) | |
2012 | dump_sra_elt_name (f, elt->parent); | |
2013 | if (DECL_P (elt->element)) | |
2014 | { | |
2015 | if (TREE_CODE (elt->element) == FIELD_DECL) | |
2016 | fputc ('.', f); | |
2017 | print_generic_expr (f, elt->element, dump_flags); | |
2018 | } | |
2019 | else | |
2020 | fprintf (f, "[" HOST_WIDE_INT_PRINT_DEC "]", | |
2021 | TREE_INT_CST_LOW (elt->element)); | |
2022 | } | |
2023 | } | |
6de9cd9a | 2024 | |
97e73bd2 RH |
2025 | /* Likewise, but callable from the debugger. */ |
2026 | ||
2027 | void | |
2028 | debug_sra_elt_name (struct sra_elt *elt) | |
2029 | { | |
2030 | dump_sra_elt_name (stderr, elt); | |
2031 | fputc ('\n', stderr); | |
2032 | } | |
6de9cd9a | 2033 | |
97e73bd2 | 2034 | /* Main entry point. */ |
6de9cd9a DN |
2035 | |
2036 | static void | |
2037 | tree_sra (void) | |
2038 | { | |
2039 | /* Initialize local variables. */ | |
97e73bd2 | 2040 | gcc_obstack_init (&sra_obstack); |
6de9cd9a | 2041 | sra_candidates = BITMAP_XMALLOC (); |
97e73bd2 RH |
2042 | needs_copy_in = BITMAP_XMALLOC (); |
2043 | sra_type_decomp_cache = BITMAP_XMALLOC (); | |
2044 | sra_type_inst_cache = BITMAP_XMALLOC (); | |
2045 | sra_map = htab_create (101, sra_elt_hash, sra_elt_eq, NULL); | |
6de9cd9a | 2046 | |
97e73bd2 RH |
2047 | /* Scan. If we find anything, instantiate and scalarize. */ |
2048 | if (find_candidates_for_sra ()) | |
6de9cd9a | 2049 | { |
97e73bd2 RH |
2050 | scan_function (); |
2051 | decide_instantiations (); | |
2052 | scalarize_function (); | |
6de9cd9a DN |
2053 | } |
2054 | ||
6de9cd9a DN |
2055 | /* Free allocated memory. */ |
2056 | htab_delete (sra_map); | |
2057 | sra_map = NULL; | |
6de9cd9a | 2058 | BITMAP_XFREE (sra_candidates); |
97e73bd2 RH |
2059 | BITMAP_XFREE (needs_copy_in); |
2060 | BITMAP_XFREE (sra_type_decomp_cache); | |
2061 | BITMAP_XFREE (sra_type_inst_cache); | |
2062 | obstack_free (&sra_obstack, NULL); | |
6de9cd9a DN |
2063 | } |
2064 | ||
2065 | static bool | |
2066 | gate_sra (void) | |
2067 | { | |
2068 | return flag_tree_sra != 0; | |
2069 | } | |
2070 | ||
19114537 | 2071 | struct tree_opt_pass pass_sra = |
6de9cd9a DN |
2072 | { |
2073 | "sra", /* name */ | |
2074 | gate_sra, /* gate */ | |
2075 | tree_sra, /* execute */ | |
2076 | NULL, /* sub */ | |
2077 | NULL, /* next */ | |
2078 | 0, /* static_pass_number */ | |
2079 | TV_TREE_SRA, /* tv_id */ | |
c1b763fa | 2080 | PROP_cfg | PROP_ssa | PROP_alias, /* properties_required */ |
6de9cd9a DN |
2081 | 0, /* properties_provided */ |
2082 | 0, /* properties_destroyed */ | |
2083 | 0, /* todo_flags_start */ | |
2084 | TODO_dump_func | TODO_rename_vars | |
9f8628ba PB |
2085 | | TODO_ggc_collect | TODO_verify_ssa, /* todo_flags_finish */ |
2086 | 0 /* letter */ | |
6de9cd9a | 2087 | }; |