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