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