1 // Early register allocation pass. 2 // Copyright (C) 2023-2024 Free Software Foundation, Inc. 3 // 4 // This file is part of GCC. 5 // 6 // GCC is free software; you can redistribute it and/or modify it under 7 // the terms of the GNU General Public License as published by the Free 8 // Software Foundation; either version 3, or (at your option) any later 9 // version. 10 // 11 // GCC is distributed in the hope that it will be useful, but WITHOUT ANY 12 // WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 // FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 // for more details. 15 // 16 // You should have received a copy of the GNU General Public License 17 // along with GCC; see the file COPYING3. If not see 18 // <http://www.gnu.org/licenses/>. 19 20 // This pass implements a simple form of early register allocation. 21 // It is restricted to FP/SIMD registers, and it only allocates 22 // a region of FP/SIMD usage if it can do so without any spilling. 23 // It punts on anything too complicated, leaving it to the real 24 // register allocator. 25 // 26 // There are two main purposes: 27 // 28 // (1) The pass runs before scheduling. It therefore has a chance to 29 // bag a spill-free allocation, if there is one, before scheduling 30 // moves things around. 31 // 32 // (2) The pass can make use of strided register operations, such as the 33 // strided forms of LD1 and ST1 in SME2. 34 // 35 // The allocator works at the level of individual FPRs, rather than whole 36 // pseudo registers. It is mostly intended to help optimize ACLE code. 37 // 38 // The pass is very simplistic. There are many things that could be improved. 39 #define IN_TARGET_CODE 1 40 41 #define INCLUDE_ALGORITHM 42 #define INCLUDE_FUNCTIONAL 43 #include "config.h" 44 #include "system.h" 45 #include "coretypes.h" 46 #include "backend.h" 47 #include "rtl.h" 48 #include "df.h" 49 #include "rtl-ssa.h" 50 #include "tree-pass.h" 51 #include "target.h" 52 #include "expr.h" 53 #include "cfgrtl.h" 54 #include "print-rtl.h" 55 #include "insn-attr.h" 56 #include "insn-opinit.h" 57 #include "reload.h" 58 59 template<typename T> 60 class simple_iterator : public wrapper_iterator<T> 61 { 62 public: 63 using wrapper_iterator<T>::wrapper_iterator; 64 65 simple_iterator &operator-- () { --this->m_contents; return *this; } 66 simple_iterator operator-- (int) { return this->m_contents--; } 67 simple_iterator &operator++ () { ++this->m_contents; return *this; } 68 simple_iterator operator++ (int) { return this->m_contents++; } 69 }; 70 71 using namespace rtl_ssa; 72 73 namespace { 74 const pass_data pass_data_early_ra = 75 { 76 RTL_PASS, // type 77 "early_ra", // name 78 OPTGROUP_NONE, // optinfo_flags 79 TV_NONE, // tv_id 80 0, // properties_required 81 0, // properties_provided 82 0, // properties_destroyed 83 0, // todo_flags_start 84 TODO_df_finish, // todo_flags_finish 85 }; 86 87 using allocno_iterator = simple_iterator<unsigned int>; 88 89 // Class that represents one run of the pass. 90 class early_ra 91 { 92 public: 93 early_ra (function *fn); 94 ~early_ra (); 95 void execute (); 96 97 private: 98 // Whether to test only things that are required for correctness, 99 // or whether to take optimization heuristics into account as well. 100 enum test_strictness { CORRECTNESS_ONLY, ALL_REASONS }; 101 102 static_assert (MAX_RECOG_OPERANDS <= 32, "Operand mask is 32 bits"); 103 using operand_mask = uint32_t; 104 105 // Points in the function are represented using "program points". 106 // The program points are allocated in reverse order, with smaller 107 // numbers indicating later points. These special values indicate 108 // the start and end of a region. 109 static constexpr unsigned int START_OF_REGION = ~0U; 110 static constexpr unsigned int END_OF_REGION = 0U; 111 112 // An invalid allocno index, used to represent no allocno. 113 static constexpr unsigned int INVALID_ALLOCNO = ~0U; 114 115 // Enumerates the single FPR sizes that matter for register allocation. 116 // Anything smaller than 64 bits is treated as FPR_D. 117 enum fpr_size_info 118 { 119 FPR_D, 120 FPR_Q, 121 FPR_Z 122 }; 123 124 // A live range for an FPR, containing program points [START_POINT, 125 // END_POINT]. If ALLOCNO is not INVALID_ALLOCNO, the FPR is known 126 // to be equal to ALLOCNO for the duration of the live range. 127 struct fpr_range_info 128 { 129 unsigned int start_point; 130 unsigned int end_point; 131 unsigned int allocno; 132 }; 133 134 // Flags used in pseudo_reg_info. 135 // 136 // Whether the pseudo register occurs in one instruction alternative that 137 // matches (respectively) V0-V7, V0-V15, V0-V31 or a non-FP register. 138 static constexpr unsigned int ALLOWS_FPR8 = 1U << 0; 139 static constexpr unsigned int ALLOWS_FPR16 = 1U << 1; 140 static constexpr unsigned int ALLOWS_FPR32 = 1U << 2; 141 static constexpr unsigned int ALLOWS_NONFPR = 1U << 3; 142 // 143 // Likewise whether the register occurs in an instruction that requires 144 // the associated register type. 145 static constexpr unsigned int NEEDS_FPR8 = 1U << 4; 146 static constexpr unsigned int NEEDS_FPR16 = 1U << 5; 147 static constexpr unsigned int NEEDS_FPR32 = 1U << 6; 148 static constexpr unsigned int NEEDS_NONFPR = 1U << 7; 149 // 150 // Whether the pseudo register is copied to or from a hard FP register. 151 static constexpr unsigned int HAS_FPR_COPY = 1U << 8; 152 // 153 // Whether the pseudo register is copied to or from a hard non-FP register. 154 static constexpr unsigned int HAS_NONFPR_COPY = 1U << 9; 155 // 156 // Whether the pseudo register is used as a multi-register vector operand 157 // to an instruction that supports strided accesses, and whether it is used 158 // as a multi-register vector operand in some other non-move instruction. 159 static constexpr unsigned int HAS_FLEXIBLE_STRIDE = 1U << 10; 160 static constexpr unsigned int HAS_FIXED_STRIDE = 1U << 11; 161 162 // Flags that should be propagated across moves between pseudo registers. 163 static constexpr unsigned int PSEUDO_COPY_FLAGS = ~(HAS_FLEXIBLE_STRIDE 164 | HAS_FIXED_STRIDE); 165 166 // Information about a copy between two registers. 167 struct reg_copy_info 168 { 169 // The two registers, in order. 170 unsigned int regnos[2]; 171 172 // Index I gives the index of the next reg_copy_info involving REGNOS[I], 173 // or 0 if none. 174 unsigned int next_copies[2]; 175 }; 176 177 // Information about a pseudo register. 178 struct pseudo_reg_info 179 { 180 // Flags describing how the register is used, defined above. 181 unsigned int flags : 16; 182 183 // The mode of the pseudo register, cached for convenience. 184 machine_mode mode : 16; 185 186 // The index of the first copy, or 0 if none. 187 unsigned int first_copy; 188 }; 189 190 // Information about a group of allocnos that have a fixed offset 191 // relative to each other. The allocnos in each group must be allocated 192 // together. 193 // 194 // Allocnos that can share the same hard register are eventually 195 // chained together. These chains represent edges on a graph of 196 // allocnos, such that two allocnos joined by an edge use the same FPR. 197 // These chains are formed between individual allocnos rather than 198 // whole groups, although the system is required to be self-consistent. 199 // Each clique in the graph has at least one "full-width" allocno group 200 // that has one allocno for every FPR that needs to be allocated to 201 // the clique. 202 // 203 // One group of allocnos is chosen as the "color representative" of 204 // each clique in the graph. This group will be a full-width group. 205 struct allocno_info; 206 struct allocno_group_info 207 { 208 array_slice<unsigned int> chain_heads (); 209 array_slice<allocno_info> allocnos (); 210 allocno_group_info *color_rep (); 211 allocno_info *allocno (unsigned int); 212 213 // The color representative of the containing clique. 214 allocno_group_info *m_color_rep; 215 216 // The pseudo register associated with this allocno, or INVALID_REGNUM 217 // if none. 218 unsigned int regno; 219 220 // The offset of the first allocno (and thus this group) from the start 221 // of color_rep. 222 unsigned int color_rep_offset : 8; 223 224 // The number of allocnos in the group, and thus the number of FPRs 225 // that need to be allocated. 226 unsigned int size : 8; 227 228 // The gap between FPRs in the group. This is normally 1, but can be 229 // higher if we've decided to use strided multi-register accesses. 230 unsigned int stride : 4; 231 232 // Used temporarily while deciding which allocnos should have non-unit 233 // strides; see find_strided_accesses for details. 234 int consecutive_pref : 4; 235 int strided_polarity : 2; 236 237 // The largest size of FPR needed by references to the allocno group. 238 fpr_size_info fpr_size : 2; 239 240 // True if all non-move accesses can be converted to strided form. 241 unsigned int has_flexible_stride : 1; 242 243 // True if we've assigned a color index to this group. 244 unsigned int has_color : 1; 245 246 // The mask of FPRs that would make valid choices for the first allocno, 247 // taking the requirements of all the allocnos in the group into account. 248 unsigned int fpr_candidates; 249 250 // The index of the color that has been assigned to the containing clique. 251 unsigned int color; 252 }; 253 254 // Represents a single FPR-sized quantity that needs to be allocated. 255 // Each allocno is identified by index (for compactness). 256 // 257 // Quantities that span multiple FPRs are assigned groups of consecutive 258 // allocnos. Quantities that occupy a single FPR are assigned their own 259 // group. 260 struct allocno_info 261 { 262 allocno_group_info *group (); 263 bool is_shared (); 264 bool is_equiv_to (unsigned int); 265 266 // The allocno's unique identifier. 267 unsigned int id; 268 269 // The offset of this allocno into the containing group. 270 unsigned int offset : 8; 271 272 // The number of allocnos in the containing group. 273 unsigned int group_size : 8; 274 275 // If the allocno has an affinity with at least one hard register 276 // (so that choosing that hard register would avoid a copy), this is 277 // the number of one such hard register, otherwise it is 278 // FIRST_PSEUDO_REGISTER. 279 unsigned int hard_regno : 8; 280 281 // Set to 1 if the allocno has a single definition or 2 if it has more. 282 unsigned int num_defs : 2; 283 284 // True if, at START_POINT, another allocno is copied to this one. 285 // See callers of record_copy for what counts as a copy. 286 unsigned int is_copy_dest : 1; 287 288 // True if, at START_POINT, another allocno is copied to this one, 289 // and if the allocnos at both ends of the copy chain have an affinity 290 // with the same hard register. 291 unsigned int is_strong_copy_dest : 1; 292 293 // True if, at END_POINT, this allocno is copied to another one, 294 // and both allocnos have an affinity with the same hard register. 295 unsigned int is_strong_copy_src : 1; 296 297 // True if the allocno is subject to an earlyclobber at END_POINT, 298 // so that it cannot be tied to the destination of the instruction. 299 unsigned int is_earlyclobbered : 1; 300 301 // True if this allocno is known to be equivalent to related_allocno 302 // for the whole of this allocno's lifetime. 303 unsigned int is_equiv : 1; 304 305 // The inclusive range of program points spanned by the allocno. 306 // START_POINT >= END_POINT. 307 unsigned int start_point; 308 unsigned int end_point; 309 310 // If, at END_POINT, this allocno is copied to another allocno, this 311 // is the index of that allocno, otherwise it is INVALID_ALLOCNO. 312 // See callers of record_copy for what counts as a copy. 313 unsigned int copy_dest; 314 315 // If this field is not INVALID_ALLOCNO, it indicates one of two things: 316 // 317 // - if is_equiv, this allocno is equivalent to related_allocno for 318 // the whole of this allocno's lifetime. 319 // 320 // - if !is_equiv, this allocno's live range is a subrange of 321 // related_allocno's and we have committed to making this allocno 322 // share whatever register related_allocno uses. 323 unsigned int related_allocno; 324 325 union 326 { 327 // The program point at which the allocno was last defined, 328 // or START_OF_REGION if none. This is only used temporarily 329 // while recording allocnos; after that, chain_next below is 330 // used instead. 331 unsigned int last_def_point; 332 333 // The next chained allocno in program order (i.e. at lower program 334 // points), or INVALID_ALLOCNO if none. 335 unsigned int chain_next; 336 }; 337 338 union 339 { 340 // The program point before start_point at which the allocno was 341 // last used, or END_OF_REGION if none. This is only used temporarily 342 // while recording allocnos; after that, chain_prev below is used 343 // instead. 344 unsigned int last_use_point; 345 346 // The previous chained allocno in program order (i.e. at higher 347 // program points), or INVALID_ALLOCNO if none. 348 unsigned int chain_prev; 349 }; 350 }; 351 352 // Information about a full allocno group or a subgroup of it. 353 // The subgroup can be empty to indicate "none". 354 struct allocno_subgroup 355 { 356 array_slice<allocno_info> allocnos (); 357 allocno_info *allocno (unsigned int); 358 359 // True if a subgroup is present. 360 operator bool () const { return count; } 361 362 // The containing group. 363 allocno_group_info *group; 364 365 // The offset of the subgroup from the start of GROUP. 366 unsigned int start; 367 368 // The number of allocnos in the subgroup. 369 unsigned int count; 370 }; 371 372 // Represents information about a copy between an allocno and an FPR. 373 // This establishes an affinity between the allocno and the FPR. 374 struct allocno_copy_info 375 { 376 // The allocno involved in the copy. 377 unsigned int allocno; 378 379 // The FPR involved in the copy, relative to V0_REGNUM. 380 unsigned int fpr : 16; 381 382 // A measure of how strong the affinity between the allocno and FPR is. 383 unsigned int weight : 16; 384 }; 385 386 // Information about a possible allocno chain. 387 struct chain_candidate_info 388 { 389 // The candidate target allocno. 390 allocno_info *allocno; 391 392 // A rating of the candidate (higher is better). 393 int score; 394 }; 395 396 // Information about an allocno color. 397 struct color_info 398 { 399 // The color's unique identifier. 400 int id; 401 402 // The allocated hard register, when known. 403 unsigned int hard_regno; 404 405 // The clique's representative group. 406 allocno_group_info *group; 407 408 // The number of FPR preferences recorded in fpr_preferences. 409 unsigned int num_fpr_preferences; 410 411 // Weights in favor of choosing each FPR as the first register for GROUP. 412 int8_t fpr_preferences[32]; 413 }; 414 415 template<typename T, typename... Ts> 416 T *region_allocate (Ts...); 417 418 allocno_info *chain_prev (allocno_info *); 419 allocno_info *chain_next (allocno_info *); 420 421 void dump_pseudo_regs (); 422 void dump_fpr_ranges (); 423 void dump_copies (); 424 void dump_allocnos (); 425 void dump_colors (); 426 427 iterator_range<allocno_iterator> get_group_allocnos (unsigned int); 428 429 void preprocess_move (rtx, rtx); 430 void process_pseudo_reg_constraints (rtx_insn *); 431 void preprocess_insns (); 432 433 int fpr_preference (unsigned int); 434 void propagate_pseudo_reg_info (); 435 436 void choose_fpr_pseudos (); 437 438 void start_new_region (); 439 440 allocno_group_info *create_allocno_group (unsigned int, unsigned int); 441 allocno_subgroup get_allocno_subgroup (rtx); 442 void record_fpr_use (unsigned int); 443 void record_fpr_def (unsigned int); 444 void record_allocno_use (allocno_info *); 445 void record_allocno_def (allocno_info *); 446 allocno_info *find_related_start (allocno_info *, allocno_info *, bool); 447 void accumulate_defs (allocno_info *, allocno_info *); 448 void record_copy (rtx, rtx, bool = false); 449 void record_constraints (rtx_insn *); 450 void record_artificial_refs (unsigned int); 451 void record_insn_refs (rtx_insn *); 452 453 bool consider_strong_copy_src_chain (allocno_info *); 454 int strided_polarity_pref (allocno_info *, allocno_info *); 455 void find_strided_accesses (); 456 457 template<unsigned int allocno_info::*field> 458 static int cmp_increasing (const void *, const void *); 459 bool is_chain_candidate (allocno_info *, allocno_info *, test_strictness); 460 int rate_chain (allocno_info *, allocno_info *); 461 static int cmp_chain_candidates (const void *, const void *); 462 void chain_allocnos (unsigned int &, unsigned int &); 463 void merge_fpr_info (allocno_group_info *, allocno_group_info *, 464 unsigned int); 465 void set_single_color_rep (allocno_info *, allocno_group_info *, 466 unsigned int); 467 void set_color_rep (allocno_group_info *, allocno_group_info *, 468 unsigned int); 469 bool try_to_chain_allocnos (allocno_info *, allocno_info *); 470 void create_color (allocno_group_info *); 471 void form_chains (); 472 473 bool fpr_conflicts_with_allocno_p (unsigned int, allocno_info *); 474 bool call_in_range_p (unsigned int, unsigned int, unsigned int); 475 unsigned int partial_fpr_clobbers (unsigned int, fpr_size_info); 476 477 void process_copies (); 478 479 static int cmp_allocation_order (const void *, const void *); 480 void allocate_colors (); 481 allocno_info *find_independent_subchain (allocno_info *); 482 color_info *find_oldest_color (unsigned int, unsigned int); 483 void broaden_colors (); 484 void finalize_allocation (); 485 486 bool replace_regs (rtx_insn *, df_ref); 487 int try_enforce_constraints (rtx_insn *, vec<std::pair<int, int>> &); 488 void enforce_constraints (rtx_insn *); 489 bool maybe_convert_to_strided_access (rtx_insn *); 490 void apply_allocation (); 491 492 void process_region (); 493 bool is_dead_insn (rtx_insn *); 494 void process_block (basic_block, bool); 495 void process_blocks (); 496 497 // ---------------------------------------------------------------------- 498 499 // The function we're operating on. 500 function *m_fn; 501 502 // Information about each pseudo register, indexed by REGNO. 503 auto_vec<pseudo_reg_info> m_pseudo_regs; 504 505 // All recorded register copies. 506 auto_vec<reg_copy_info> m_pseudo_reg_copies; 507 508 // The set of pseudos that we've decided to allocate an FPR to. 509 auto_bitmap m_fpr_pseudos; 510 511 // ---------------------------------------------------------------------- 512 513 // An obstack for allocating information that is referenced by the member 514 // variables below. 515 obstack m_region_obstack; 516 void *m_region_alloc_start; 517 518 // ---------------------------------------------------------------------- 519 520 // The basic block that we're currently processing. 521 basic_block m_current_bb; 522 523 // The lowest-numbered program point in the current basic block. 524 unsigned int m_current_bb_point; 525 526 // The program point that we're currently processing (described above). 527 unsigned int m_current_point; 528 529 // The set of allocnos that are currently live. 530 auto_bitmap m_live_allocnos; 531 532 // The set of FPRs that are currently live. 533 unsigned int m_live_fprs; 534 535 // A unique one-based identifier for the current region. 536 unsigned int m_current_region; 537 538 // The region in which each FPR was last used, or 0 if none. 539 unsigned int m_fpr_recency[32]; 540 541 // ---------------------------------------------------------------------- 542 543 // A mask of the FPRs that have already been allocated. 544 unsigned int m_allocated_fprs; 545 546 // A mask of the FPRs that must be at least partially preserved by the 547 // current function. 548 unsigned int m_call_preserved_fprs; 549 550 // True if we haven't yet failed to allocate the current region. 551 bool m_allocation_successful; 552 553 // A map from pseudo registers to the first allocno in their associated 554 // allocno groups. 555 hash_map<int_hash<unsigned int, INVALID_REGNUM>, 556 allocno_group_info *> m_regno_to_group; 557 558 // All recorded copies between allocnos and FPRs. 559 auto_vec<allocno_copy_info> m_allocno_copies; 560 561 // All allocnos, by index. 562 auto_vec<allocno_info *> m_allocnos; 563 564 // All allocnos, by increasing START_POINT. 565 auto_vec<allocno_info *> m_sorted_allocnos; 566 567 // Allocnos for which is_shared is true. 568 auto_vec<allocno_info *> m_shared_allocnos; 569 570 // All colors, by index. 571 auto_vec<color_info *> m_colors; 572 573 // The instruction ranges that make up the current region, 574 // as half-open ranges [LAST, FIRST). 575 auto_vec<std::pair<rtx_insn *, rtx_insn *>> m_insn_ranges; 576 577 // The live ranges of each FPR, in order of increasing program point. 578 auto_vec<fpr_range_info> m_fpr_ranges[32]; 579 580 // For each function call id, a list of program points at which a call 581 // to such a function is made. Each list is in order of increasing 582 // program point. 583 auto_vec<unsigned int> m_call_points[NUM_ABI_IDS]; 584 585 // A list of instructions that can be removed if allocation succeeds. 586 auto_vec<rtx_insn *> m_dead_insns; 587 }; 588 589 // True if PAT is something that would typically be treated as a move. 590 static inline bool 591 is_move_set (rtx pat) 592 { 593 if (GET_CODE (pat) != SET) 594 return false; 595 596 rtx dest = SET_DEST (pat); 597 if (SUBREG_P (dest)) 598 dest = SUBREG_REG (dest); 599 if (!OBJECT_P (dest)) 600 return false; 601 602 rtx src = SET_SRC (pat); 603 if (SUBREG_P (src)) 604 src = SUBREG_REG (src); 605 if (!OBJECT_P (src) && !CONSTANT_P (src)) 606 return false; 607 608 return true; 609 } 610 611 // Return true if operand OP is likely to match OP_ALT after register 612 // allocation. 613 static bool 614 likely_operand_match_p (const operand_alternative &op_alt, rtx op) 615 { 616 // Empty constraints match everything. 617 const char *constraint = op_alt.constraint; 618 if (constraint[0] == 0 || constraint[0] == ',') 619 return true; 620 621 for (;;) 622 { 623 char c = *constraint; 624 int len = CONSTRAINT_LEN (c, constraint); 625 if (c == 0 || c == ',') 626 break; 627 628 if (c == 'X') 629 return true; 630 631 auto cn = lookup_constraint (constraint); 632 switch (get_constraint_type (cn)) 633 { 634 case CT_REGISTER: 635 if (REG_P (op) || SUBREG_P (op)) 636 return true; 637 break; 638 639 case CT_MEMORY: 640 case CT_SPECIAL_MEMORY: 641 case CT_RELAXED_MEMORY: 642 if (MEM_P (op)) 643 return true; 644 break; 645 646 case CT_CONST_INT: 647 case CT_ADDRESS: 648 case CT_FIXED_FORM: 649 if (constraint_satisfied_p (op, cn)) 650 return true; 651 break; 652 } 653 654 constraint += len; 655 } 656 657 if (op_alt.matches >= 0) 658 { 659 rtx other = recog_data.operand[op_alt.matches]; 660 if ((REG_P (other) || SUBREG_P (other)) 661 && (REG_P (op) || SUBREG_P (op))) 662 return true; 663 } 664 return false; 665 } 666 667 // Return true if the operands of the current instruction are likely to 668 // match OP_ALT. 669 static bool 670 likely_alternative_match_p (const operand_alternative *op_alt) 671 { 672 for (int i = 0; i < recog_data.n_operands; ++i) 673 if (!likely_operand_match_p (op_alt[i], recog_data.operand[i])) 674 return false; 675 return true; 676 } 677 678 // Return the sum of how disparaged OP_ALT is. 679 static int 680 count_rejects (const operand_alternative *op_alt) 681 { 682 int reject = 0; 683 for (int opno = 0; opno < recog_data.n_operands; ++opno) 684 reject += op_alt[opno].reject; 685 return reject; 686 } 687 688 // Allocate a T from the region obstack. 689 template<typename T, typename... Ts> 690 inline T * 691 early_ra::region_allocate (Ts... args) 692 { 693 static_assert (std::is_trivially_destructible<T>::value, 694 "destructor won't be called"); 695 void *addr = obstack_alloc (&m_region_obstack, sizeof (T)); 696 return new (addr) T (std::forward<Ts> (args)...); 697 } 698 699 early_ra::early_ra (function *fn) : m_fn (fn), m_live_fprs (0) 700 { 701 gcc_obstack_init (&m_region_obstack); 702 m_region_alloc_start = obstack_alloc (&m_region_obstack, 0); 703 bitmap_tree_view (m_live_allocnos); 704 } 705 706 early_ra::~early_ra () 707 { 708 obstack_free (&m_region_obstack, nullptr); 709 } 710 711 // Return an array that, for each allocno A in the group, contains the index 712 // of the allocno at the head of A's chain (that is, the one with the highest 713 // START_POINT). The index is INVALID_ALLOCNO if the chain is empty. 714 inline array_slice<unsigned int> 715 early_ra::allocno_group_info::chain_heads () 716 { 717 auto *start = reinterpret_cast<unsigned int *> (this + 1); 718 return { start, size }; 719 } 720 721 // Return the array of allocnos in the group. 722 inline array_slice<early_ra::allocno_info> 723 early_ra::allocno_group_info::allocnos () 724 { 725 gcc_checking_assert (regno != INVALID_REGNUM); 726 auto *chain_end = reinterpret_cast<unsigned int *> (this + 1) + size; 727 auto *allocno_start = reinterpret_cast<allocno_info *> (chain_end); 728 return { allocno_start, size }; 729 } 730 731 // Return the group's color representative. 732 inline early_ra::allocno_group_info * 733 early_ra::allocno_group_info::color_rep () 734 { 735 gcc_checking_assert (m_color_rep->m_color_rep == m_color_rep); 736 return m_color_rep; 737 } 738 739 // Return the group that contains the allocno. 740 inline early_ra::allocno_group_info * 741 early_ra::allocno_info::group () 742 { 743 auto *chain_end = reinterpret_cast<unsigned int *> (this - offset); 744 return reinterpret_cast<allocno_group_info *> (chain_end - group_size) - 1; 745 } 746 747 // Return true if this allocno's live range is a subrange of related_allocno's 748 // and if we have committed to making this allocno share whatever register 749 // related_allocno uses. 750 inline bool 751 early_ra::allocno_info::is_shared () 752 { 753 return related_allocno != INVALID_ALLOCNO && !is_equiv; 754 } 755 756 // Return true if this allocno is known to be equivalent to ALLOCNO. 757 inline bool 758 early_ra::allocno_info::is_equiv_to (unsigned int allocno) 759 { 760 return is_equiv && related_allocno == allocno; 761 } 762 763 // Return the allocnos in the subgroup. 764 inline array_slice<early_ra::allocno_info> 765 early_ra::allocno_subgroup::allocnos () 766 { 767 if (!count) 768 return {}; 769 return { &group->allocnos ()[start], count }; 770 } 771 772 // Return allocno I in the subgroup, with 0 being the first. 773 inline early_ra::allocno_info * 774 early_ra::allocno_subgroup::allocno (unsigned int i) 775 { 776 return &group->allocnos ()[start + i]; 777 } 778 779 // Return the previous (earlier) allocno in ALLOCNO's chain, or null if none. 780 inline early_ra::allocno_info * 781 early_ra::chain_prev (allocno_info *allocno) 782 { 783 if (allocno->chain_prev != INVALID_ALLOCNO) 784 return m_allocnos[allocno->chain_prev]; 785 return nullptr; 786 } 787 788 // Return the next (later) allocno in ALLOCNO's chain, or null if none. 789 inline early_ra::allocno_info * 790 early_ra::chain_next (allocno_info *allocno) 791 { 792 if (allocno->chain_next != INVALID_ALLOCNO) 793 return m_allocnos[allocno->chain_next]; 794 return nullptr; 795 } 796 797 // Dump the information in m_pseudo_regs. 798 void 799 early_ra::dump_pseudo_regs () 800 { 801 fprintf (dump_file, "\nPseudos:\n"); 802 fprintf (dump_file, " %6s %6s %6s %6s %6s %6s %8s %s\n", 803 "Id", "FPR8", "FPR16", "FPR32", "NONFPR", "Stride", 804 "FPRness", "Copies"); 805 pseudo_reg_info unused_reg = {}; 806 for (unsigned int regno = FIRST_PSEUDO_REGISTER; 807 regno < m_pseudo_regs.length (); ++regno) 808 { 809 const auto ® = m_pseudo_regs[regno]; 810 if (memcmp (®, &unused_reg, sizeof (reg)) == 0) 811 continue; 812 813 fprintf (dump_file, " %6d %6s %6s %6s %6s %6s %8d", regno, 814 reg.flags & NEEDS_FPR8 ? "Req" 815 : reg.flags & ALLOWS_FPR8 ? "OK" : "-", 816 reg.flags & NEEDS_FPR16 ? "Req" 817 : reg.flags & ALLOWS_FPR16 ? "OK" : "-", 818 reg.flags & NEEDS_FPR32 ? "Req" 819 : reg.flags & ALLOWS_FPR32 ? "OK" : "-", 820 reg.flags & NEEDS_NONFPR ? "Req" 821 : reg.flags & ALLOWS_NONFPR ? "OK" : "-", 822 ~reg.flags & HAS_FLEXIBLE_STRIDE ? "-" 823 : reg.flags & HAS_FIXED_STRIDE ? "Some" : "All", 824 fpr_preference (regno)); 825 if (reg.flags & HAS_FPR_COPY) 826 fprintf (dump_file, " FPR"); 827 if (reg.flags & HAS_NONFPR_COPY) 828 fprintf (dump_file, " Non-FPR"); 829 unsigned int copyi = reg.first_copy; 830 while (copyi) 831 { 832 const auto © = m_pseudo_reg_copies[copyi]; 833 if (copy.regnos[0] == regno) 834 { 835 fprintf (dump_file, " r%d", copy.regnos[1]); 836 copyi = copy.next_copies[0]; 837 } 838 else 839 { 840 fprintf (dump_file, " r%d", copy.regnos[0]); 841 copyi = copy.next_copies[1]; 842 } 843 } 844 fprintf (dump_file, "\n"); 845 } 846 } 847 848 // Dump the information in m_fpr_ranges. 849 void 850 early_ra::dump_fpr_ranges () 851 { 852 fprintf (dump_file, "\nFPR live ranges:\n"); 853 for (unsigned int fpr = 0; fpr < 32; ++fpr) 854 { 855 auto &intervals = m_fpr_ranges[fpr]; 856 if (intervals.is_empty ()) 857 continue; 858 859 fprintf (dump_file, " %2d", fpr); 860 for (unsigned int i = 0; i < intervals.length (); ++i) 861 { 862 auto &interval = intervals[i]; 863 if (i && (i % 4) == 0) 864 fprintf (dump_file, "\n "); 865 fprintf (dump_file, " [ %6d %6d ]", interval.start_point, 866 interval.end_point); 867 } 868 fprintf (dump_file, "\n"); 869 } 870 } 871 872 // Dump the information in m_allocno_copies. 873 void 874 early_ra::dump_copies () 875 { 876 fprintf (dump_file, "\nCopies:\n"); 877 fprintf (dump_file, " %8s %3s %6s\n", 878 "Allocno", "FPR", "Weight"); 879 for (const auto © : m_allocno_copies) 880 fprintf (dump_file, " %8d %3d %6d\n", copy.allocno, 881 copy.fpr, copy.weight); 882 } 883 884 // Dump the information in m_allocnos. 885 void 886 early_ra::dump_allocnos () 887 { 888 char buffer[sizeof ("r[:]") + 3 * 3 * sizeof (int) + 1]; 889 fprintf (dump_file, "\nAllocno groups:\n"); 890 fprintf (dump_file, 891 " %12s %12s %4s %6s %8s %s\n", 892 "Ids", "Regno", "Size", "Stride", "Cands", "Heads"); 893 for (unsigned int ai = 0; ai < m_allocnos.length (); ++ai) 894 { 895 auto *allocno = m_allocnos[ai]; 896 if (allocno->offset != 0) 897 continue; 898 auto *group = allocno->group (); 899 snprintf (buffer, sizeof (buffer), "[%d:%d]", allocno->id, 900 allocno->id + group->size - 1); 901 fprintf (dump_file, " %12s", buffer); 902 snprintf (buffer, sizeof (buffer), "r%d[0:%d]", group->regno, 903 group->size - 1); 904 fprintf (dump_file, " %12s %4s %6d %08x", buffer, 905 group->fpr_size == FPR_D ? "D" 906 : group->fpr_size == FPR_Q ? "Q" : "Z", 907 group->stride, 908 group->fpr_candidates); 909 for (auto head : group->chain_heads ()) 910 if (head == INVALID_ALLOCNO) 911 fprintf (dump_file, " -"); 912 else 913 fprintf (dump_file, " %d", head); 914 fprintf (dump_file, "\n"); 915 } 916 917 fprintf (dump_file, "\nAllocno chains:\n"); 918 fprintf (dump_file, " %5s %12s %12s %6s %5s %5s %6s %5s\n", 919 "Id", "Regno", "Range ", "Src", "Dest", "Equiv", "Shared", "FPR"); 920 for (unsigned int ai = 0; ai < m_allocnos.length (); ++ai) 921 { 922 auto *allocno = m_allocnos[ai]; 923 if (allocno->chain_prev != INVALID_ALLOCNO) 924 continue; 925 const char *prefix = "=>"; 926 for (;;) 927 { 928 auto *group = allocno->group (); 929 fprintf (dump_file, " %2s", prefix); 930 fprintf (dump_file, " %5d", allocno->id); 931 snprintf (buffer, sizeof (buffer), "r%d[%d]", group->regno, 932 allocno->offset); 933 fprintf (dump_file, " %12s", buffer); 934 snprintf (buffer, sizeof (buffer), "[%d,%d]", 935 allocno->start_point, allocno->end_point); 936 fprintf (dump_file, " %11s%s %6s", buffer, 937 allocno->is_earlyclobbered ? "*" : " ", 938 allocno->is_strong_copy_dest ? "Strong" 939 : allocno->is_copy_dest ? "Yes" : "-"); 940 if (allocno->copy_dest == INVALID_ALLOCNO) 941 fprintf (dump_file, " %5s", "-"); 942 else 943 fprintf (dump_file, " %5d", allocno->copy_dest); 944 if (allocno->is_equiv) 945 fprintf (dump_file, " %5d", allocno->related_allocno); 946 else 947 fprintf (dump_file, " %5s", "-"); 948 if (allocno->is_shared ()) 949 fprintf (dump_file, " %6d", allocno->related_allocno); 950 else 951 fprintf (dump_file, " %6s", "-"); 952 if (allocno->hard_regno == FIRST_PSEUDO_REGISTER) 953 fprintf (dump_file, " %5s", "-"); 954 else 955 fprintf (dump_file, " %5s", reg_names[allocno->hard_regno]); 956 fprintf (dump_file, "\n"); 957 if (allocno->chain_next == INVALID_ALLOCNO) 958 break; 959 allocno = m_allocnos[allocno->chain_next]; 960 prefix = ""; 961 } 962 } 963 } 964 965 // Dump the information in m_colors. 966 void 967 early_ra::dump_colors () 968 { 969 fprintf (dump_file, "\nColors:\n"); 970 for (unsigned int i = 0; i < m_colors.length (); ++i) 971 { 972 auto *color = m_colors[i]; 973 if (!color->group) 974 continue; 975 976 fprintf (dump_file, " color %d:\n", i); 977 fprintf (dump_file, " chains:\n"); 978 auto heads = color->group->chain_heads (); 979 for (unsigned int i = 0; i < color->group->size; ++i) 980 { 981 fprintf (dump_file, " %2d:", i); 982 auto ai = heads[i]; 983 while (ai != INVALID_ALLOCNO) 984 { 985 auto *allocno = m_allocnos[ai]; 986 fprintf (dump_file, " r%d[%d]", allocno->group ()->regno, 987 allocno->offset); 988 ai = allocno->chain_next; 989 } 990 fprintf (dump_file, "\n"); 991 } 992 fprintf (dump_file, " FPR candidates:"); 993 for (unsigned int fpr = 0; fpr < 32; ++fpr) 994 fprintf (dump_file, "%s%c", fpr % 8 ? "" : " ", 995 color->group->fpr_candidates & (1U << fpr) ? 'Y' : '-'); 996 fprintf (dump_file, "\n"); 997 fprintf (dump_file, " FPR preferences:"); 998 for (unsigned int fpr = 0; fpr < 32; ++fpr) 999 if (color->fpr_preferences[fpr]) 1000 fprintf (dump_file, " %d(%d)", fpr, color->fpr_preferences[fpr]); 1001 fprintf (dump_file, "\n"); 1002 } 1003 } 1004 1005 // Record any necessary information about a move from SRC to DEST. 1006 void 1007 early_ra::preprocess_move (rtx dest, rtx src) 1008 { 1009 if (SUBREG_P (dest)) 1010 dest = SUBREG_REG (dest); 1011 if (!REG_P (dest)) 1012 return; 1013 1014 if (SUBREG_P (src)) 1015 src = SUBREG_REG (src); 1016 if (!REG_P (src)) 1017 return; 1018 1019 // Sort the registers by increasing REGNO. 1020 rtx regs[] = { dest, src }; 1021 if (REGNO (dest) > REGNO (src)) 1022 std::swap (regs[0], regs[1]); 1023 unsigned int regno0 = REGNO (regs[0]); 1024 unsigned int regno1 = REGNO (regs[1]); 1025 1026 // Ignore moves between hard registers. 1027 if (HARD_REGISTER_NUM_P (regno1)) 1028 return; 1029 1030 // For moves between hard registers and pseudos, just record the type 1031 // of hard register involved. 1032 auto ®1 = m_pseudo_regs[regno1]; 1033 reg1.mode = GET_MODE (regs[1]); 1034 if (HARD_REGISTER_NUM_P (regno0)) 1035 { 1036 reg1.flags |= (FP_REGNUM_P (regno0) ? HAS_FPR_COPY : HAS_NONFPR_COPY); 1037 return; 1038 } 1039 1040 // Record a move between two pseudo registers. 1041 auto ®0 = m_pseudo_regs[regno0]; 1042 reg0.mode = GET_MODE (regs[0]); 1043 1044 reg_copy_info copy; 1045 copy.regnos[0] = regno0; 1046 copy.regnos[1] = regno1; 1047 copy.next_copies[0] = reg0.first_copy; 1048 copy.next_copies[1] = reg1.first_copy; 1049 1050 reg0.first_copy = reg1.first_copy = m_pseudo_reg_copies.length (); 1051 m_pseudo_reg_copies.safe_push (copy); 1052 } 1053 1054 // Return true if INSN has a multi-vector operand and if that operand 1055 // could be converted to strided form. 1056 static bool 1057 is_stride_candidate (rtx_insn *insn) 1058 { 1059 if (recog_memoized (insn) < 0) 1060 return false; 1061 1062 auto stride_type = get_attr_stride_type (insn); 1063 return (stride_type == STRIDE_TYPE_LD1_CONSECUTIVE 1064 || stride_type == STRIDE_TYPE_ST1_CONSECUTIVE); 1065 } 1066 1067 // Go through the constraints of INSN, which has already been extracted, 1068 // and record any relevant information about pseudo registers. 1069 void 1070 early_ra::process_pseudo_reg_constraints (rtx_insn *insn) 1071 { 1072 extract_insn (insn); 1073 preprocess_constraints (insn); 1074 1075 // Flags that describe any multi-register vector operands. 1076 unsigned int insn_flags = (is_stride_candidate (insn) 1077 ? HAS_FLEXIBLE_STRIDE 1078 : HAS_FIXED_STRIDE); 1079 1080 auto alts = get_preferred_alternatives (insn); 1081 1082 int operand_matches[MAX_RECOG_OPERANDS]; 1083 unsigned int operand_flags[MAX_RECOG_OPERANDS]; 1084 for (int i = 0; i < recog_data.n_operands; ++i) 1085 { 1086 operand_matches[i] = -1; 1087 operand_flags[i] = 0; 1088 } 1089 1090 // Extract information from the constraints, considering all plausible 1091 // alternatives. 1092 for (int altno = 0; altno < recog_data.n_alternatives; ++altno) 1093 { 1094 if (!(alts & ALTERNATIVE_BIT (altno))) 1095 continue; 1096 1097 auto *op_alt = &recog_op_alt[altno * recog_data.n_operands]; 1098 if (!likely_alternative_match_p (op_alt)) 1099 continue; 1100 1101 // Use SRC_OPNO's constraints to derive information about DEST_OPNO. 1102 auto record_operand = [&](int src_opno, int dest_opno) 1103 { 1104 int matches = op_alt[src_opno].matches; 1105 if (matches >= 0) 1106 operand_matches[dest_opno] = matches; 1107 1108 auto cl = alternative_class (op_alt, src_opno); 1109 if (cl != NO_REGS) 1110 { 1111 if (reg_class_subset_p (cl, FP_REGS)) 1112 operand_flags[dest_opno] |= ALLOWS_FPR32; 1113 if (reg_class_subset_p (cl, FP_LO_REGS)) 1114 operand_flags[dest_opno] |= ALLOWS_FPR16; 1115 if (reg_class_subset_p (cl, FP_LO8_REGS)) 1116 operand_flags[dest_opno] |= ALLOWS_FPR8; 1117 if (!reg_classes_intersect_p (cl, FP_REGS)) 1118 operand_flags[dest_opno] |= ALLOWS_NONFPR; 1119 } 1120 }; 1121 1122 for (int i = 0; i < recog_data.n_operands; ++i) 1123 { 1124 record_operand (i, i); 1125 if (recog_data.constraints[i][0] == '%') 1126 { 1127 record_operand (i, i + 1); 1128 record_operand (i + 1, i); 1129 } 1130 } 1131 } 1132 1133 // Process the information we collected above. 1134 for (int i = 0; i < recog_data.n_operands; ++i) 1135 { 1136 rtx op = recog_data.operand[i]; 1137 machine_mode orig_mode = GET_MODE (op); 1138 if (SUBREG_P (op)) 1139 op = SUBREG_REG (op); 1140 1141 // Record the accumulated information in m_pseudo_regs. 1142 if (REG_P (op) && !HARD_REGISTER_P (op)) 1143 { 1144 // The flags so far just describe what at least one alternative 1145 // would accept. Calculate the associated NEEDS_* information. 1146 auto flags = operand_flags[i]; 1147 if (!(flags & ALLOWS_FPR32) && (flags & ALLOWS_NONFPR)) 1148 flags |= NEEDS_NONFPR; 1149 else if ((flags & ALLOWS_FPR32) && !(flags & ALLOWS_NONFPR)) 1150 { 1151 if (flags & ALLOWS_FPR8) 1152 flags |= NEEDS_FPR8; 1153 if (flags & ALLOWS_FPR16) 1154 flags |= NEEDS_FPR16; 1155 flags |= NEEDS_FPR32; 1156 } 1157 1158 // Look for multi-register vector operands. 1159 if (VECTOR_MODE_P (orig_mode) 1160 && targetm.hard_regno_mode_ok (V0_REGNUM, orig_mode) 1161 && hard_regno_nregs (V0_REGNUM, orig_mode) > 1) 1162 flags |= insn_flags; 1163 1164 m_pseudo_regs[REGNO (op)].flags |= flags; 1165 m_pseudo_regs[REGNO (op)].mode = GET_MODE (op); 1166 } 1167 1168 // Treat matching constraints as equivalent to moves. 1169 if (operand_matches[i] >= 0) 1170 preprocess_move (recog_data.operand[operand_matches[i]], op); 1171 } 1172 } 1173 1174 // Make one pass through the instructions, collecting information that 1175 // will be needed later. 1176 void 1177 early_ra::preprocess_insns () 1178 { 1179 m_pseudo_regs.safe_grow_cleared (max_reg_num ()); 1180 m_pseudo_reg_copies.safe_push (reg_copy_info ()); 1181 for (rtx_insn *insn = get_insns (); insn; insn = NEXT_INSN (insn)) 1182 { 1183 if (!NONDEBUG_INSN_P (insn)) 1184 continue; 1185 1186 // Mark all registers that occur in addresses as needing a GPR. 1187 vec_rtx_properties properties; 1188 properties.add_insn (insn, true); 1189 for (rtx_obj_reference ref : properties.refs ()) 1190 if (ref.is_reg () 1191 && ref.in_address () 1192 && !HARD_REGISTER_NUM_P (ref.regno)) 1193 m_pseudo_regs[ref.regno].flags |= ALLOWS_NONFPR | NEEDS_NONFPR; 1194 1195 if (GET_CODE (PATTERN (insn)) == USE 1196 || GET_CODE (PATTERN (insn)) == CLOBBER) 1197 continue; 1198 1199 rtx set = single_set (insn); 1200 if (set && is_move_set (set)) 1201 preprocess_move (SET_DEST (set), SET_SRC (set)); 1202 else 1203 process_pseudo_reg_constraints (insn); 1204 } 1205 } 1206 1207 // Return a signed integer that says (roughly) how strong an affinity 1208 // pseudo register REGNO has with FPRs. A positive value indicates 1209 // that we should try to allocate an FPR, a negative value indicates 1210 // that we shouldn't, and 0 indicates neutrality. 1211 int 1212 early_ra::fpr_preference (unsigned int regno) 1213 { 1214 auto mode = m_pseudo_regs[regno].mode; 1215 auto flags = m_pseudo_regs[regno].flags; 1216 if (mode == VOIDmode || !targetm.hard_regno_mode_ok (V0_REGNUM, mode)) 1217 return -3; 1218 else if (flags & HAS_FLEXIBLE_STRIDE) 1219 return 3; 1220 else if (flags & NEEDS_FPR32) 1221 return 2; 1222 else if (!(flags & ALLOWS_FPR32) && (flags & ALLOWS_NONFPR)) 1223 return -2; 1224 else if ((flags & HAS_FPR_COPY) && !(flags & HAS_NONFPR_COPY)) 1225 return 1; 1226 else if ((flags & HAS_NONFPR_COPY) && !(flags & HAS_FPR_COPY)) 1227 return -1; 1228 else 1229 return 0; 1230 } 1231 1232 // Propagate information about pseudo-registers along copy edges, 1233 // while doing so doesn't create conflicting FPR preferences. 1234 void 1235 early_ra::propagate_pseudo_reg_info () 1236 { 1237 struct stack_entry { unsigned int regno, copyi; }; 1238 1239 auto_vec<stack_entry, 32> stack; 1240 for (unsigned int i = FIRST_PSEUDO_REGISTER; 1241 i < m_pseudo_regs.length (); ++i) 1242 { 1243 auto start = m_pseudo_regs[i].first_copy; 1244 if (!start) 1245 continue; 1246 1247 stack.quick_push ({ i, start }); 1248 while (!stack.is_empty ()) 1249 { 1250 auto entry = stack.pop (); 1251 auto © = m_pseudo_reg_copies[entry.copyi]; 1252 auto src_regno = entry.regno; 1253 auto dest_regno = (src_regno == copy.regnos[1] 1254 ? copy.regnos[0] 1255 : copy.regnos[1]); 1256 auto next_copyi = (src_regno == copy.regnos[1] 1257 ? copy.next_copies[1] 1258 : copy.next_copies[0]); 1259 if (next_copyi) 1260 stack.safe_push ({ src_regno, next_copyi }); 1261 1262 auto &src_reg = m_pseudo_regs[src_regno]; 1263 auto &dest_reg = m_pseudo_regs[dest_regno]; 1264 1265 if (src_reg.flags & ~dest_reg.flags & PSEUDO_COPY_FLAGS) 1266 { 1267 auto src_preference = fpr_preference (src_regno); 1268 auto dest_preference = fpr_preference (dest_regno); 1269 if ((src_preference >= 0 && dest_preference >= 0) 1270 || (src_preference <= 0 && dest_preference <= 0)) 1271 { 1272 dest_reg.flags |= (src_reg.flags & PSEUDO_COPY_FLAGS); 1273 stack.safe_push ({ dest_regno, dest_reg.first_copy }); 1274 } 1275 } 1276 } 1277 } 1278 } 1279 1280 // Decide which pseudos should be allocated an FPR, setting m_fpr_pseudos 1281 // accordingly. 1282 void 1283 early_ra::choose_fpr_pseudos () 1284 { 1285 for (unsigned int i = FIRST_PSEUDO_REGISTER; 1286 i < m_pseudo_regs.length (); ++i) 1287 if (fpr_preference (i) > 0) 1288 bitmap_set_bit (m_fpr_pseudos, i); 1289 } 1290 1291 // Clear out information about the previous CFG region (if any) 1292 // and set up the data for a new region. 1293 void 1294 early_ra::start_new_region () 1295 { 1296 obstack_free (&m_region_obstack, m_region_alloc_start); 1297 m_regno_to_group.empty (); 1298 m_allocno_copies.truncate (0); 1299 m_allocnos.truncate (0); 1300 m_sorted_allocnos.truncate (0); 1301 m_shared_allocnos.truncate (0); 1302 m_colors.truncate (0); 1303 m_insn_ranges.truncate (0); 1304 for (auto &fpr_ranges : m_fpr_ranges) 1305 fpr_ranges.truncate (0); 1306 for (auto &call_points : m_call_points) 1307 call_points.truncate (0); 1308 gcc_assert (bitmap_empty_p (m_live_allocnos) && m_live_fprs == 0); 1309 m_dead_insns.truncate (0); 1310 m_allocated_fprs = 0; 1311 m_call_preserved_fprs = 0; 1312 m_allocation_successful = true; 1313 m_current_region += 1; 1314 } 1315 1316 // Create and return an allocno group of size SIZE for register REGNO. 1317 // REGNO can be INVALID_REGNUM if the group just exists to allow 1318 // other groups to be chained together, and does not have any new 1319 // allocnos of its own. 1320 early_ra::allocno_group_info * 1321 early_ra::create_allocno_group (unsigned int regno, unsigned int size) 1322 { 1323 static_assert (alignof (unsigned int) == alignof (allocno_info), 1324 "allocno_info alignment"); 1325 unsigned int num_allocnos = (regno != INVALID_REGNUM ? size : 0); 1326 1327 // Allocate an allocno_group_info, followed by an array of chain heads, 1328 // followed by the allocnos themselves. 1329 size_t alloc_size = (sizeof (allocno_group_info) 1330 + size * sizeof (unsigned int) 1331 + num_allocnos * sizeof (allocno_info)); 1332 void *data = obstack_alloc (&m_region_obstack, alloc_size); 1333 1334 // Initialize the group. 1335 auto *group = reinterpret_cast<allocno_group_info *> (data); 1336 memset (group, 0, sizeof (*group)); 1337 group->m_color_rep = group; 1338 group->regno = regno; 1339 group->size = size; 1340 group->stride = 1; 1341 group->fpr_size = FPR_D; 1342 group->fpr_candidates = ~0U; 1343 1344 // Initialize the chain heads. 1345 auto heads = group->chain_heads (); 1346 for (unsigned int i = 0; i < heads.size (); ++i) 1347 heads[i] = (i < num_allocnos ? m_allocnos.length () + i : INVALID_ALLOCNO); 1348 1349 // Initialize the allocnos. 1350 if (num_allocnos > 0) 1351 { 1352 auto allocnos = group->allocnos (); 1353 memset (allocnos.begin (), 0, num_allocnos * sizeof (allocno_info)); 1354 for (unsigned int i = 0; i < num_allocnos; ++i) 1355 { 1356 auto *allocno = &allocnos[i]; 1357 allocno->id = m_allocnos.length (); 1358 allocno->offset = i; 1359 allocno->group_size = size; 1360 allocno->hard_regno = FIRST_PSEUDO_REGISTER; 1361 allocno->start_point = END_OF_REGION; 1362 allocno->end_point = START_OF_REGION; 1363 allocno->copy_dest = INVALID_ALLOCNO; 1364 allocno->related_allocno = INVALID_ALLOCNO; 1365 allocno->chain_next = INVALID_ALLOCNO; 1366 allocno->chain_prev = INVALID_ALLOCNO; 1367 m_allocnos.safe_push (allocno); 1368 } 1369 } 1370 return group; 1371 } 1372 1373 // If REG refers to a pseudo register that might be allocated to FPRs, 1374 // return the associated range of allocnos, creating new ones if necessary. 1375 // Return an empty range otherwise. 1376 early_ra::allocno_subgroup 1377 early_ra::get_allocno_subgroup (rtx reg) 1378 { 1379 if (GET_CODE (reg) == SUBREG) 1380 { 1381 allocno_subgroup inner = get_allocno_subgroup (SUBREG_REG (reg)); 1382 if (!inner) 1383 return {}; 1384 1385 if (!targetm.modes_tieable_p (GET_MODE (SUBREG_REG (reg)), 1386 GET_MODE (reg))) 1387 { 1388 m_allocation_successful = false; 1389 return {}; 1390 } 1391 1392 subreg_info info; 1393 subreg_get_info (V0_REGNUM, GET_MODE (SUBREG_REG (reg)), 1394 SUBREG_BYTE (reg), GET_MODE (reg), &info); 1395 if (!info.representable_p) 1396 { 1397 m_allocation_successful = false; 1398 return {}; 1399 } 1400 1401 inner.start += info.offset; 1402 inner.count = info.nregs; 1403 return inner; 1404 } 1405 1406 if (!REG_P (reg) || HARD_REGISTER_P (reg)) 1407 return {}; 1408 1409 unsigned int regno = REGNO (reg); 1410 if (fpr_preference (regno) <= 0) 1411 return {}; 1412 1413 unsigned int count = hard_regno_nregs (V0_REGNUM, GET_MODE (reg)); 1414 bool existed; 1415 auto &entry = m_regno_to_group.get_or_insert (regno, &existed); 1416 if (!existed) 1417 { 1418 auto *group = create_allocno_group (regno, count); 1419 if (dump_file && (dump_flags & TDF_DETAILS)) 1420 { 1421 auto allocnos = group->allocnos (); 1422 fprintf (dump_file, "Creating allocnos [%d:%d] for r%d\n", 1423 allocnos.front ().id, allocnos.back ().id, regno); 1424 } 1425 1426 auto reg_bits = GET_MODE_BITSIZE (GET_MODE (reg)); 1427 auto fpr_bits = exact_div (reg_bits, count); 1428 auto flags = m_pseudo_regs[regno].flags; 1429 1430 // Punt for now if there is a choice to be made between using an 1431 // FPR and a non-FPR. 1432 if ((flags & NEEDS_NONFPR) 1433 || ((flags & ALLOWS_NONFPR) 1434 && !FLOAT_MODE_P (GET_MODE (reg)) 1435 && !VECTOR_MODE_P (GET_MODE (reg)))) 1436 m_allocation_successful = false; 1437 1438 if (flags & ALLOWS_FPR8) 1439 group->fpr_candidates &= 0xff; 1440 else if (flags & ALLOWS_FPR16) 1441 group->fpr_candidates &= 0xffff; 1442 group->fpr_candidates &= ~0U >> (count - 1); 1443 1444 group->has_flexible_stride = ((flags & HAS_FLEXIBLE_STRIDE) != 0 1445 && (flags & HAS_FIXED_STRIDE) == 0); 1446 1447 group->fpr_size = (maybe_gt (fpr_bits, 128) ? FPR_Z 1448 : maybe_gt (fpr_bits, 64) ? FPR_Q : FPR_D); 1449 1450 entry = group; 1451 } 1452 return { entry, 0, count }; 1453 } 1454 1455 // Record a use of FPR REGNO at the current program point, as part of 1456 // a backwards walk over a block. 1457 void 1458 early_ra::record_fpr_use (unsigned int regno) 1459 { 1460 gcc_assert (IN_RANGE (regno, V0_REGNUM, V31_REGNUM)); 1461 unsigned int offset = regno - V0_REGNUM; 1462 if (!(m_live_fprs & (1U << offset))) 1463 { 1464 m_fpr_ranges[offset].safe_push ({ START_OF_REGION, m_current_point, 1465 INVALID_ALLOCNO }); 1466 m_live_fprs |= 1U << offset; 1467 } 1468 } 1469 1470 // Record a definition of FPR REGNO at the current program point, as part of 1471 // a backwards walk over a block. 1472 void 1473 early_ra::record_fpr_def (unsigned int regno) 1474 { 1475 gcc_assert (IN_RANGE (regno, V0_REGNUM, V31_REGNUM)); 1476 unsigned int offset = regno - V0_REGNUM; 1477 1478 // The definition completes the current live range. If the result 1479 // of the definition is used, the live range extends to the last use. 1480 // Otherwise the live range is just a momentary blip at the current point. 1481 auto &ranges = m_fpr_ranges[offset]; 1482 if (m_live_fprs & (1U << offset)) 1483 { 1484 ranges.last ().start_point = m_current_point; 1485 m_live_fprs &= ~(1U << offset); 1486 } 1487 else 1488 ranges.safe_push ({ m_current_point, m_current_point, INVALID_ALLOCNO }); 1489 } 1490 1491 // Record a use of allocno ALLOCNO at the current program point, as part 1492 // of a backwards walk over a block. 1493 void 1494 early_ra::record_allocno_use (allocno_info *allocno) 1495 { 1496 if (allocno->start_point == m_current_point) 1497 return; 1498 1499 gcc_checking_assert (!allocno->is_shared ()); 1500 bitmap_set_bit (m_live_allocnos, allocno->id); 1501 if (allocno->end_point > m_current_point) 1502 { 1503 allocno->end_point = m_current_point; 1504 allocno->last_def_point = START_OF_REGION; 1505 allocno->last_use_point = END_OF_REGION; 1506 } 1507 else 1508 allocno->last_use_point = allocno->start_point; 1509 allocno->start_point = m_current_point; 1510 allocno->is_copy_dest = false; 1511 allocno->is_strong_copy_src = false; 1512 allocno->related_allocno = INVALID_ALLOCNO; 1513 allocno->is_equiv = false; 1514 } 1515 1516 // Record a definition of the allocno with index AI at the current program 1517 // point, as part of a backwards walk over a block. The allocno is known 1518 // to be live. 1519 void 1520 early_ra::record_allocno_def (allocno_info *allocno) 1521 { 1522 gcc_checking_assert (!allocno->is_shared ()); 1523 allocno->last_use_point = allocno->start_point; 1524 allocno->last_def_point = m_current_point; 1525 allocno->start_point = m_current_point; 1526 allocno->num_defs = MIN (allocno->num_defs + 1, 2); 1527 gcc_checking_assert (!allocno->is_copy_dest 1528 && !allocno->is_strong_copy_src); 1529 if (!bitmap_clear_bit (m_live_allocnos, allocno->id)) 1530 gcc_unreachable (); 1531 } 1532 1533 // SRC_ALLOCNO is copied or tied to DEST_ALLOCNO; IS_EQUIV is true if the 1534 // two allocnos are known to be equal. See whether we can mark a chain of 1535 // allocnos ending at DEST_ALLOCNO as related to SRC_ALLOCNO. Return the 1536 // start of the chain if so, otherwise return null. 1537 // 1538 // If IS_EQUIV, a chain that contains just DEST_ALLOCNO should be treated 1539 // as an equivalence. Otherwise the chain should be shared with SRC_ALLOCNO. 1540 // 1541 // Sharing chains are a rather hacky workaround for the fact that we 1542 // don't collect segmented live ranges, and that in the end we want to do 1543 // simple interval graph coloring. 1544 early_ra::allocno_info * 1545 early_ra::find_related_start (allocno_info *dest_allocno, 1546 allocno_info *src_allocno, bool is_equiv) 1547 { 1548 allocno_info *res = nullptr; 1549 for (;;) 1550 { 1551 if (src_allocno->end_point > dest_allocno->end_point) 1552 // The src allocno dies first. 1553 return res; 1554 1555 if (src_allocno->num_defs != 0) 1556 { 1557 if (dest_allocno->end_point < m_current_bb_point) 1558 // We don't currently track enough information to handle multiple 1559 // definitions across basic block boundaries. 1560 return res; 1561 1562 if (src_allocno->last_def_point >= dest_allocno->end_point) 1563 // There is another definition during the destination's live range. 1564 return res; 1565 } 1566 if (is_equiv) 1567 { 1568 if (dest_allocno->num_defs == 1) 1569 // dest_allocno is equivalent to src_allocno for dest_allocno's 1570 // entire live range. Fall back to that if we can't establish 1571 // a sharing chain. 1572 res = dest_allocno; 1573 } 1574 else 1575 { 1576 if (src_allocno->last_use_point >= dest_allocno->end_point) 1577 // src_allocno is live during dest_allocno's live range, 1578 // and the two allocnos do not necessarily have the same value. 1579 return res; 1580 } 1581 1582 if (dest_allocno->group_size != 1 1583 // Account for definitions by shared registers. 1584 || dest_allocno->num_defs > 1 1585 || DF_REG_DEF_COUNT (dest_allocno->group ()->regno) != 1) 1586 // Currently only single allocnos that are defined once can 1587 // share registers with non-equivalent allocnos. This could be 1588 // relaxed, but at the time of writing, aggregates are not valid 1589 // SSA names and so generally only use a single pseudo throughout 1590 // their lifetime. 1591 return res; 1592 1593 if (dest_allocno->copy_dest == src_allocno->id) 1594 // We've found a complete and valid sharing chain. 1595 return dest_allocno; 1596 1597 if (dest_allocno->copy_dest == INVALID_ALLOCNO) 1598 return res; 1599 1600 auto *next_allocno = m_allocnos[dest_allocno->copy_dest]; 1601 if (!is_chain_candidate (dest_allocno, next_allocno, ALL_REASONS)) 1602 return res; 1603 1604 dest_allocno = next_allocno; 1605 is_equiv = false; 1606 } 1607 } 1608 1609 // Add FROM_ALLOCNO's definition information to TO_ALLOCNO's. 1610 void 1611 early_ra::accumulate_defs (allocno_info *to_allocno, 1612 allocno_info *from_allocno) 1613 { 1614 if (from_allocno->num_defs > 0) 1615 { 1616 to_allocno->num_defs = MIN (from_allocno->num_defs 1617 + to_allocno->num_defs, 2); 1618 to_allocno->last_def_point = MAX (to_allocno->last_def_point, 1619 from_allocno->last_def_point); 1620 } 1621 } 1622 1623 // Record any relevant allocno-related information for an actual or imagined 1624 // copy from SRC to DEST. FROM_MOVE_P is true if the copy was an explicit 1625 // move instruction, false if it represents one way of satisfying the previous 1626 // instruction's constraints. 1627 void 1628 early_ra::record_copy (rtx dest, rtx src, bool from_move_p) 1629 { 1630 auto dest_range = get_allocno_subgroup (dest); 1631 auto src_range = get_allocno_subgroup (src); 1632 if (from_move_p 1633 && dest_range 1634 && REG_P (src) 1635 && FP_REGNUM_P (REGNO (src))) 1636 { 1637 // A copy from an FPR to an allocno group. 1638 unsigned int fpr = REGNO (src) - V0_REGNUM; 1639 m_allocno_copies.safe_push ({ dest_range.allocno (0)->id, fpr, 1640 dest_range.count }); 1641 1642 // If the allocno at the other end of the chain of copies from DEST 1643 // has a copy to the same FPR, record that all intervening copy chains 1644 // could become "strong" ones. This indicates that picking the FPR 1645 // avoids a copy at both ends. 1646 unsigned int hard_regno = REGNO (src); 1647 for (auto &dest_allocno : dest_range.allocnos ()) 1648 if (dest_allocno.hard_regno == hard_regno++) 1649 dest_allocno.is_strong_copy_src = true; 1650 } 1651 else if (from_move_p 1652 && src_range 1653 && REG_P (dest) 1654 && FP_REGNUM_P (REGNO (dest))) 1655 { 1656 // A copy from an allocno group to an FPR. 1657 unsigned int fpr = REGNO (dest) - V0_REGNUM; 1658 m_allocno_copies.safe_push ({ src_range.allocno (0)->id, fpr, 1659 src_range.count }); 1660 for (auto &src_allocno : src_range.allocnos ()) 1661 { 1662 // If the copy comes from a move, see whether the destination 1663 // FPR is known to be equal to the source allocno for the FPR's 1664 // last live range. 1665 if (from_move_p && src_allocno.num_defs == 0) 1666 { 1667 auto &last_range = m_fpr_ranges[fpr].last (); 1668 if (last_range.end_point >= src_allocno.end_point) 1669 last_range.allocno = src_allocno.id; 1670 } 1671 src_allocno.hard_regno = V0_REGNUM + fpr; 1672 fpr += 1; 1673 } 1674 } 1675 else if (src_range && dest_range) 1676 { 1677 // A copy between two allocno groups. We can only have a mismatched 1678 // number of FPRs for imaginary, non-move copies. In that case 1679 // the matching happens on the common lowparts. 1680 gcc_assert (!from_move_p || src_range.count == dest_range.count); 1681 unsigned int count = std::min (src_range.count, dest_range.count); 1682 if (WORDS_BIG_ENDIAN) 1683 { 1684 src_range.start += src_range.count - count; 1685 dest_range.start += dest_range.count - count; 1686 } 1687 src_range.count = count; 1688 dest_range.count = count; 1689 1690 // Ignore (imaginary non-move) copies if the destination is still live. 1691 for (auto &dest_allocno : dest_range.allocnos ()) 1692 if (bitmap_bit_p (m_live_allocnos, dest_allocno.id)) 1693 return; 1694 1695 for (unsigned int i = 0; i < src_range.count; ++i) 1696 { 1697 auto *dest_allocno = dest_range.allocno (i); 1698 auto *src_allocno = src_range.allocno (i); 1699 if (src_allocno->end_point > dest_allocno->start_point) 1700 { 1701 gcc_assert (src_allocno->copy_dest == INVALID_ALLOCNO 1702 || src_allocno->copy_dest == dest_allocno->id); 1703 src_allocno->copy_dest = dest_allocno->id; 1704 src_allocno->hard_regno = dest_allocno->hard_regno; 1705 dest_allocno->is_copy_dest = 1; 1706 } 1707 else if (auto *start_allocno = find_related_start (dest_allocno, 1708 src_allocno, 1709 from_move_p)) 1710 { 1711 auto *next_allocno = dest_allocno; 1712 for (;;) 1713 { 1714 next_allocno->related_allocno = src_allocno->id; 1715 next_allocno->is_equiv = (start_allocno == dest_allocno 1716 && from_move_p); 1717 // If we're sharing two allocnos that are not equivalent, 1718 // carry across the definition information. This is needed 1719 // to prevent multiple incompatible attempts to share with 1720 // the same register. 1721 if (next_allocno->is_shared ()) 1722 accumulate_defs (src_allocno, next_allocno); 1723 src_allocno->last_use_point 1724 = MAX (src_allocno->last_use_point, 1725 next_allocno->last_use_point); 1726 1727 if (next_allocno == start_allocno) 1728 break; 1729 next_allocno = m_allocnos[next_allocno->copy_dest]; 1730 } 1731 } 1732 } 1733 } 1734 } 1735 1736 // Record any relevant allocno-related information about the constraints 1737 // on INSN, which has already been extracted. 1738 void 1739 early_ra::record_constraints (rtx_insn *insn) 1740 { 1741 preprocess_constraints (insn); 1742 1743 int operand_matches[MAX_RECOG_OPERANDS]; 1744 for (int i = 0; i < recog_data.n_operands; ++i) 1745 operand_matches[i] = -1; 1746 1747 auto alts = get_preferred_alternatives (insn); 1748 bool any_ok = recog_data.n_alternatives == 0; 1749 1750 // The set of output operands that are earlyclobber in at least one 1751 // alternative. 1752 operand_mask earlyclobber_operands = 0; 1753 1754 // The set of output operands that are matched to inputs in at least 1755 // one alternative. 1756 operand_mask matched_operands = 0; 1757 1758 // The set of output operands that are not matched to inputs in at least 1759 // one alternative. 1760 operand_mask unmatched_operands = 0; 1761 1762 // The set of input operands that are matched to outputs in at least one 1763 // alternative, or that overlap with such an input if the output is not 1764 // earlyclobber. The latter part of the condition copes with things 1765 // like y = x * x, where the first x is tied to the destination, and where 1766 // y is not earlyclobber. 1767 operand_mask matches_operands = 0; 1768 1769 for (int altno = 0; altno < recog_data.n_alternatives; ++altno) 1770 { 1771 if (!(alts & ALTERNATIVE_BIT (altno))) 1772 continue; 1773 1774 auto *op_alt = &recog_op_alt[altno * recog_data.n_operands]; 1775 if (!likely_alternative_match_p (op_alt)) 1776 continue; 1777 1778 any_ok = true; 1779 1780 // Update the information for operand DEST_OPNO based on the constraint 1781 // information for operand SRC_OPNO. The numbers can be different for 1782 // swapped commutative operands. 1783 auto record_operand = [&](int src_opno, int dest_opno) 1784 { 1785 int matches = op_alt[src_opno].matches; 1786 // A matched earlyclobber cannot be used if the same operand value 1787 // occurs in an unmatched operand. E.g. for y = x * x, a matched 1788 // earlyclobber on the first input does not cover the second input. 1789 if (matches >= 0) 1790 { 1791 rtx op = recog_data.operand[dest_opno]; 1792 operand_mask overlaps = 0; 1793 for (int i = 0; i < recog_data.n_operands; ++i) 1794 if (i != dest_opno 1795 && !recog_data.is_operator[i] 1796 && recog_data.operand_type[i] != OP_OUT 1797 && reg_overlap_mentioned_p (op, recog_data.operand[i])) 1798 overlaps |= 1U << i; 1799 if (!op_alt[matches].earlyclobber || overlaps == 0) 1800 { 1801 operand_matches[dest_opno] = matches; 1802 matches_operands |= (1U << dest_opno) | overlaps; 1803 } 1804 } 1805 }; 1806 1807 auto reject = count_rejects (op_alt); 1808 for (int opno = 0; opno < recog_data.n_operands; ++opno) 1809 { 1810 operand_mask op_mask = operand_mask (1) << opno; 1811 1812 if (recog_data.operand_type[opno] != OP_IN) 1813 { 1814 if (reject == 0 && op_alt[opno].matched >= 0) 1815 matched_operands |= op_mask; 1816 else 1817 unmatched_operands |= op_mask; 1818 } 1819 1820 if (op_alt[opno].earlyclobber) 1821 earlyclobber_operands |= op_mask; 1822 1823 // Punt for now on scratches. If we wanted to handle them, 1824 // we'd need to create allocnos for them, like IRA does. 1825 rtx op = recog_data.operand[opno]; 1826 if (GET_CODE (op) == SCRATCH 1827 && reg_classes_intersect_p (op_alt[opno].cl, FP_REGS)) 1828 m_allocation_successful = false; 1829 1830 // Record filter information, which applies to the first register 1831 // in the operand. 1832 if (auto filters = alternative_register_filters (op_alt, opno)) 1833 if (auto range = get_allocno_subgroup (recog_data.operand[opno])) 1834 for (unsigned int fpr = range.start; fpr < 32; ++fpr) 1835 if (!test_register_filters (filters, fpr)) 1836 range.group->fpr_candidates &= ~(1U << (fpr - range.start)); 1837 1838 if (reject == 0) 1839 { 1840 // Record possible matched operands. 1841 record_operand (opno, opno); 1842 if (recog_data.constraints[opno][0] == '%') 1843 { 1844 record_operand (opno, opno + 1); 1845 record_operand (opno + 1, opno); 1846 } 1847 } 1848 } 1849 } 1850 1851 if (!any_ok) 1852 { 1853 if (dump_file && (dump_flags & TDF_DETAILS)) 1854 fprintf (dump_file, " -- no match\n"); 1855 m_allocation_successful = false; 1856 } 1857 1858 // Record if there is an output operand that is never earlyclobber and never 1859 // matched to an input. See the comment below for how this is used. 1860 rtx dest_op = NULL_RTX; 1861 for (int opno = 0; opno < recog_data.n_operands; ++opno) 1862 { 1863 auto op_mask = operand_mask (1) << opno; 1864 if (recog_data.operand_type[opno] == OP_OUT 1865 && (earlyclobber_operands & op_mask) == 0 1866 && (matched_operands & op_mask) == 0) 1867 { 1868 dest_op = recog_data.operand[opno]; 1869 break; 1870 } 1871 } 1872 1873 for (int opno = 0; opno < recog_data.n_operands; ++opno) 1874 { 1875 auto op_mask = operand_mask (1) << opno; 1876 rtx op = recog_data.operand[opno]; 1877 int matches = operand_matches[opno]; 1878 1879 // Punt for now on operands that already have a fixed choice of 1880 // register, since we don't have IRA's ability to find an alternative. 1881 // It's better if earlier passes don't create this kind of situation. 1882 if (REG_P (op) && FP_REGNUM_P (REGNO (op))) 1883 m_allocation_successful = false; 1884 1885 // Treat input operands as being earlyclobbered if an output is 1886 // sometimes earlyclobber and if the input never matches an output. 1887 // Do the same if there is an output that is always matched to an 1888 // input, and if this operand doesn't match that input. In both 1889 // cases, tying the input and the output would lead to an impossible 1890 // combination (or at least one that is difficult to reload). 1891 if (recog_data.operand_type[opno] != OP_OUT 1892 && ((earlyclobber_operands && matches < 0) 1893 || ((matched_operands & ~unmatched_operands) 1894 && !(matches_operands & op_mask)))) 1895 for (auto &allocno : get_allocno_subgroup (op).allocnos ()) 1896 if (allocno.end_point + 1 == m_current_point) 1897 allocno.is_earlyclobbered = true; 1898 1899 // Create copies between operands that can be tied. This (deliberately) 1900 // might add several copies to the same destination register; later code 1901 // can then choose between them based on other criteria. 1902 // 1903 // If there is an output operand that is never matched or earlyclobber, 1904 // and an input operand that never matches an output operand, create 1905 // a tentative copy between them. This allows hard register preferences 1906 // to be transmitted along the copy chains. 1907 if (matches >= 0) 1908 record_copy (recog_data.operand[matches], op); 1909 else if (dest_op && recog_data.operand_type[opno] == OP_IN) 1910 record_copy (dest_op, op); 1911 } 1912 } 1913 1914 // If FLAGS is DF_REF_AT_TOP, model the artificial uses and defs at the 1915 // start of the current basic block, otherwise model the artificial uses 1916 // and defs at the end of the basic block. This is done as part of a 1917 // backwards walk, so defs should be processed before uses. 1918 void 1919 early_ra::record_artificial_refs (unsigned int flags) 1920 { 1921 df_ref ref; 1922 1923 FOR_EACH_ARTIFICIAL_DEF (ref, m_current_bb->index) 1924 if ((DF_REF_FLAGS (ref) & DF_REF_AT_TOP) == flags 1925 && IN_RANGE (DF_REF_REGNO (ref), V0_REGNUM, V31_REGNUM)) 1926 record_fpr_def (DF_REF_REGNO (ref)); 1927 m_current_point += 1; 1928 1929 FOR_EACH_ARTIFICIAL_USE (ref, m_current_bb->index) 1930 if ((DF_REF_FLAGS (ref) & DF_REF_AT_TOP) == flags 1931 && IN_RANGE (DF_REF_REGNO (ref), V0_REGNUM, V31_REGNUM)) 1932 record_fpr_use (DF_REF_REGNO (ref)); 1933 m_current_point += 1; 1934 } 1935 1936 // Return true if: 1937 // 1938 // - X is a SUBREG, in which case it is a SUBREG of some REG Y 1939 // 1940 // - one 64-bit word of Y can be modified while preserving all other words 1941 // 1942 // - X refers to no more than one 64-bit word of Y 1943 // 1944 // - assigning FPRs to Y would put more than one 64-bit word in each FPR 1945 // 1946 // For example, this is true of: 1947 // 1948 // - (subreg:DI (reg:TI R) 0) and 1949 // - (subreg:DI (reg:TI R) 8) 1950 // 1951 // but is not true of: 1952 // 1953 // - (subreg:V2SI (reg:V2x2SI R) 0) or 1954 // - (subreg:V2SI (reg:V2x2SI R) 8). 1955 static bool 1956 allocno_assignment_is_rmw (rtx x) 1957 { 1958 if (partial_subreg_p (x)) 1959 { 1960 auto outer_mode = GET_MODE (x); 1961 auto inner_mode = GET_MODE (SUBREG_REG (x)); 1962 if (known_eq (REGMODE_NATURAL_SIZE (inner_mode), 0U + UNITS_PER_WORD) 1963 && known_lt (GET_MODE_SIZE (outer_mode), UNITS_PER_VREG)) 1964 { 1965 auto nregs = targetm.hard_regno_nregs (V0_REGNUM, inner_mode); 1966 if (maybe_ne (nregs * UNITS_PER_WORD, GET_MODE_SIZE (inner_mode))) 1967 return true; 1968 } 1969 } 1970 return false; 1971 } 1972 1973 // Model the register references in INSN as part of a backwards walk. 1974 void 1975 early_ra::record_insn_refs (rtx_insn *insn) 1976 { 1977 df_ref ref; 1978 1979 // Record all definitions, excluding partial call clobbers. 1980 FOR_EACH_INSN_DEF (ref, insn) 1981 if (IN_RANGE (DF_REF_REGNO (ref), V0_REGNUM, V31_REGNUM)) 1982 record_fpr_def (DF_REF_REGNO (ref)); 1983 else 1984 { 1985 rtx reg = DF_REF_REG (ref); 1986 auto range = get_allocno_subgroup (reg); 1987 for (auto &allocno : range.allocnos ()) 1988 { 1989 // Make sure that assigning to the DF_REF_REG clobbers the 1990 // whole of this allocno, not just some of it. 1991 if (allocno_assignment_is_rmw (reg)) 1992 { 1993 m_allocation_successful = false; 1994 if (dump_file && (dump_flags & TDF_DETAILS)) 1995 fprintf (dump_file, "read-modify-write of allocno %d", 1996 allocno.id); 1997 break; 1998 } 1999 2000 // If the destination is unused, record a momentary blip 2001 // in its live range. 2002 if (!bitmap_bit_p (m_live_allocnos, allocno.id)) 2003 record_allocno_use (&allocno); 2004 record_allocno_def (&allocno); 2005 } 2006 } 2007 m_current_point += 1; 2008 2009 // Model the call made by a call insn as a separate phase in the 2010 // evaluation of the insn. Any partial call clobbers happen at that 2011 // point, rather than in the definition or use phase of the insn. 2012 if (auto *call_insn = dyn_cast<rtx_call_insn *> (insn)) 2013 { 2014 function_abi abi = insn_callee_abi (call_insn); 2015 m_call_points[abi.id ()].safe_push (m_current_point); 2016 m_current_point += 1; 2017 } 2018 2019 // Record all uses. We can ignore READ_MODIFY_WRITE uses of plain subregs, 2020 // since we track the FPR-sized parts of them individually. 2021 FOR_EACH_INSN_USE (ref, insn) 2022 if (IN_RANGE (DF_REF_REGNO (ref), V0_REGNUM, V31_REGNUM)) 2023 record_fpr_use (DF_REF_REGNO (ref)); 2024 else if (!DF_REF_FLAGS_IS_SET (ref, DF_REF_READ_WRITE) 2025 || DF_REF_FLAGS_IS_SET (ref, DF_REF_STRICT_LOW_PART) 2026 || DF_REF_FLAGS_IS_SET (ref, DF_REF_ZERO_EXTRACT)) 2027 { 2028 auto range = get_allocno_subgroup (DF_REF_REG (ref)); 2029 for (auto &allocno : range.allocnos ()) 2030 record_allocno_use (&allocno); 2031 } 2032 m_current_point += 1; 2033 } 2034 2035 // ALLOCNO->is_strong_copy_src is true. See whether ALLOCNO heads a 2036 // natural chain that has an affinity with the same hard register at 2037 // both ends. 2038 bool 2039 early_ra::consider_strong_copy_src_chain (allocno_info *allocno) 2040 { 2041 auto *src_allocno = allocno; 2042 while (src_allocno->copy_dest != INVALID_ALLOCNO) 2043 { 2044 auto *dest_allocno = m_allocnos[src_allocno->copy_dest]; 2045 if (dest_allocno->start_point > src_allocno->end_point 2046 || dest_allocno->hard_regno != src_allocno->hard_regno) 2047 return false; 2048 gcc_checking_assert (dest_allocno->is_copy_dest); 2049 src_allocno = dest_allocno; 2050 } 2051 2052 while (allocno->copy_dest != INVALID_ALLOCNO) 2053 { 2054 allocno->is_strong_copy_src = 1; 2055 allocno = m_allocnos[allocno->copy_dest]; 2056 allocno->is_strong_copy_dest = 1; 2057 } 2058 return true; 2059 } 2060 2061 // ALLOCNO1 and ALLOCNO2 are linked in some way, and might end up being 2062 // chained together. See whether chaining them requires the containing 2063 // groups to have the same stride, or whether it requires them to have 2064 // different strides. Return 1 if they should have the same stride, 2065 // -1 if they should have different strides, or 0 if it doesn't matter. 2066 int 2067 early_ra::strided_polarity_pref (allocno_info *allocno1, 2068 allocno_info *allocno2) 2069 { 2070 if (allocno1->offset + 1 < allocno1->group_size 2071 && allocno2->offset + 1 < allocno2->group_size) 2072 { 2073 if (is_chain_candidate (allocno1 + 1, allocno2 + 1, ALL_REASONS)) 2074 return 1; 2075 else 2076 return -1; 2077 } 2078 2079 if (allocno1->offset > 0 && allocno2->offset > 0) 2080 { 2081 if (is_chain_candidate (allocno1 - 1, allocno2 - 1, ALL_REASONS)) 2082 return 1; 2083 else 2084 return -1; 2085 } 2086 2087 return 0; 2088 } 2089 2090 // Decide which groups should be strided. Also complete "strong" copy chains. 2091 void 2092 early_ra::find_strided_accesses () 2093 { 2094 // This function forms a graph of allocnos, linked by equivalences and 2095 // natural copy chains. It temporarily uses chain_next to record the 2096 // reverse of equivalence edges (related_allocno) and chain_prev to record 2097 // the reverse of copy edges (copy_dest). 2098 unsigned int allocno_info::*links[] = { 2099 &allocno_info::chain_next, 2100 &allocno_info::chain_prev, 2101 &allocno_info::copy_dest, 2102 &allocno_info::related_allocno 2103 }; 2104 2105 // Set up the temporary reverse edges. Check for strong copy chains. 2106 for (unsigned int i = m_allocnos.length (); i-- > 0; ) 2107 { 2108 auto *allocno1 = m_allocnos[i]; 2109 if (allocno1->copy_dest != INVALID_ALLOCNO) 2110 m_allocnos[allocno1->copy_dest]->chain_prev = allocno1->id; 2111 if (allocno1->related_allocno != INVALID_ALLOCNO) 2112 m_allocnos[allocno1->related_allocno]->chain_next = allocno1->id; 2113 2114 if (allocno1->is_strong_copy_src 2115 && !allocno1->is_copy_dest 2116 && !consider_strong_copy_src_chain (allocno1)) 2117 allocno1->is_strong_copy_src = false; 2118 } 2119 2120 // Partition the graph into cliques based on edges that have the following 2121 // properties: 2122 // 2123 // - the edge joins two allocnos whose groups have a free choice between 2124 // consecutive and strided allocations. 2125 // 2126 // - the two groups have a relative strided polarity preference (that is 2127 // they should make the same choice between consecutive and strided, 2128 // or they should make opposite choices). 2129 // 2130 // Assign relative polarities to each group connected in this way. 2131 // 2132 // The aim is to discover natural move-free striding choices, which will 2133 // often exist in carefully written ACLE code. 2134 unsigned int num_edges = m_allocnos.length () * ARRAY_SIZE (links); 2135 auto_sbitmap visited_edges (num_edges); 2136 bitmap_clear (visited_edges); 2137 2138 auto_vec<unsigned int, 32> worklist; 2139 for (unsigned int i = 0; i < num_edges; ++i) 2140 { 2141 if (!bitmap_set_bit (visited_edges, i)) 2142 continue; 2143 worklist.quick_push (i); 2144 while (!worklist.is_empty ()) 2145 { 2146 auto ei = worklist.pop (); 2147 auto *allocno1 = m_allocnos[ei / ARRAY_SIZE (links)]; 2148 auto ai2 = allocno1->*links[ei % ARRAY_SIZE (links)]; 2149 if (ai2 == INVALID_ALLOCNO) 2150 continue; 2151 2152 auto *allocno2 = m_allocnos[ai2]; 2153 auto *group1 = allocno1->group (); 2154 auto *group2 = allocno2->group (); 2155 if (!group1->has_flexible_stride || !group2->has_flexible_stride) 2156 continue; 2157 2158 int pref = strided_polarity_pref (allocno1, allocno2); 2159 if (pref == 0) 2160 continue; 2161 2162 for (auto *group : { group1, group2 }) 2163 for (auto &allocno : group->allocnos ()) 2164 for (unsigned int j = 0; j < ARRAY_SIZE (links); ++j) 2165 if (bitmap_set_bit (visited_edges, allocno.id * 4 + j)) 2166 worklist.safe_push (allocno.id * 4 + j); 2167 2168 if (group1->strided_polarity) 2169 group2->strided_polarity = group1->strided_polarity * pref; 2170 else if (group2->strided_polarity) 2171 group1->strided_polarity = group2->strided_polarity * pref; 2172 else 2173 { 2174 group1->strided_polarity = 1; 2175 group2->strided_polarity = pref; 2176 } 2177 } 2178 } 2179 2180 // Now look for edges between allocnos in multi-register groups where: 2181 // 2182 // - the two groups have a relative strided polarity preference (as above). 2183 // 2184 // - one group (G1) has a free choice between consecutive and strided 2185 // allocations. 2186 // 2187 // - the other group (G2) must use consecutive allocations. 2188 // 2189 // Update G1's individual preference for strided or consecutive allocations 2190 // based on G2. If the previous loop chose a polarity for G1, work out 2191 // whether it is better for polarity 1 or -1 to correspond to consecutive 2192 // allocation. 2193 int consecutive_pref = 0; 2194 for (unsigned int i = m_allocnos.length (); i-- > 0; ) 2195 { 2196 auto *allocno1 = m_allocnos[i]; 2197 for (auto link : links) 2198 { 2199 auto ai2 = allocno1->*link; 2200 if (ai2 == INVALID_ALLOCNO) 2201 continue; 2202 2203 auto *allocno2 = m_allocnos[ai2]; 2204 auto *group1 = allocno1->group (); 2205 auto *group2 = allocno2->group (); 2206 if (group1->has_flexible_stride == group2->has_flexible_stride) 2207 continue; 2208 2209 int pref = strided_polarity_pref (allocno1, allocno2); 2210 if (pref == 0) 2211 continue; 2212 2213 auto *group = (group1->has_flexible_stride ? group1 : group2); 2214 consecutive_pref += group->strided_polarity * pref; 2215 group->consecutive_pref += pref; 2216 } 2217 } 2218 2219 // If it doesn't matter whether polarity 1 or -1 corresponds to consecutive 2220 // allocation, arbitrarily pick 1. 2221 if (consecutive_pref == 0) 2222 consecutive_pref = 1; 2223 2224 // Record which multi-register groups should use strided allocations. 2225 // Clear out the temporary edges. 2226 for (unsigned int ai = 0; ai < m_allocnos.length (); ++ai) 2227 { 2228 auto *allocno = m_allocnos[ai]; 2229 allocno->chain_prev = INVALID_ALLOCNO; 2230 allocno->chain_next = INVALID_ALLOCNO; 2231 2232 if (allocno->offset != 0) 2233 continue; 2234 2235 auto *group = allocno->group (); 2236 if (!group->has_flexible_stride) 2237 continue; 2238 2239 bool make_strided = (group->strided_polarity 2240 ? (consecutive_pref * group->strided_polarity) < 0 2241 : group->consecutive_pref < 0); 2242 if (dump_file && (dump_flags & TDF_DETAILS)) 2243 fprintf (dump_file, "Allocno [%d:%d]: strided polarity %d," 2244 " consecutive pref %d, %s\n", 2245 allocno->id, allocno->id + group->size - 1, 2246 group->strided_polarity, group->consecutive_pref, 2247 make_strided ? "making strided" : "keeping consecutive"); 2248 if (!make_strided) 2249 continue; 2250 2251 // 2-register groups have a stride of 8 FPRs and must start in 2252 // registers matching the mask 0x17. 4-register groups have a stride 2253 // of 4 FPRs and must start in registers matching the mask 0x13. 2254 group->stride = group->size == 2 ? 8 : 4; 2255 gcc_checking_assert (group->fpr_candidates 2256 == (group->size == 2 ? 0x55555555 : 0x11111111)); 2257 group->fpr_candidates = (group->size == 2 ? 0xff00ff : 0xf000f); 2258 } 2259 } 2260 2261 // Compare the allocnos at *ALLOCNO1_PTR and *ALLOCNO2_PTR and return a <=> 2262 // result that puts allocnos in order of increasing FIELD. 2263 template<unsigned int early_ra::allocno_info::*field> 2264 int 2265 early_ra::cmp_increasing (const void *allocno1_ptr, const void *allocno2_ptr) 2266 { 2267 auto *allocno1 = *(allocno_info *const *) allocno1_ptr; 2268 auto *allocno2 = *(allocno_info *const *) allocno2_ptr; 2269 2270 if (allocno1->*field != allocno2->*field) 2271 return allocno1->*field < allocno2->*field ? -1 : 1; 2272 return (allocno1->id < allocno2->id ? -1 2273 : allocno1->id == allocno2->id ? 0 : 1); 2274 } 2275 2276 // Return true if we should consider chaining ALLOCNO1 onto the head 2277 // of ALLOCNO2. STRICTNESS says whether we should take copy-elision 2278 // heuristics into account, or whether we should just consider things 2279 // that matter for correctness. 2280 // 2281 // This is just a local test of the two allocnos; it doesn't guarantee 2282 // that chaining them would give a self-consistent system. 2283 bool 2284 early_ra::is_chain_candidate (allocno_info *allocno1, allocno_info *allocno2, 2285 test_strictness strictness) 2286 { 2287 if (allocno2->is_shared ()) 2288 return false; 2289 2290 while (allocno1->is_equiv) 2291 allocno1 = m_allocnos[allocno1->related_allocno]; 2292 2293 if (allocno2->start_point >= allocno1->end_point 2294 && !allocno2->is_equiv_to (allocno1->id)) 2295 return false; 2296 2297 if (allocno1->is_earlyclobbered 2298 && allocno1->end_point == allocno2->start_point + 1) 2299 return false; 2300 2301 if (strictness == ALL_REASONS && allocno2->is_copy_dest) 2302 { 2303 if (allocno1->copy_dest != allocno2->id) 2304 return false; 2305 if (allocno2->is_strong_copy_dest && !allocno1->is_strong_copy_src) 2306 return false; 2307 } 2308 return true; 2309 } 2310 2311 // We're trying to chain allocno ALLOCNO1 to a later allocno. 2312 // Rate how good a choice ALLOCNO2 would be, with higher being better. 2313 int 2314 early_ra::rate_chain (allocno_info *allocno1, allocno_info *allocno2) 2315 { 2316 int score = 0; 2317 if (allocno2->is_strong_copy_dest) 2318 score += 256; 2319 else if (allocno2->is_copy_dest) 2320 score += 128; 2321 2322 // Prefer well-aligned matches. 2323 auto *group1 = allocno1->group (); 2324 auto *group2 = allocno2->group (); 2325 if (group1->stride == 1 && group2->stride == 1) 2326 { 2327 unsigned int min_size = std::min (group1->color_rep ()->size, 2328 group2->color_rep ()->size); 2329 if ((group1->color_rep_offset + allocno1->offset) % min_size 2330 == (group2->color_rep_offset + allocno2->offset) % min_size) 2331 score += min_size; 2332 else 2333 score -= min_size; 2334 } 2335 return score; 2336 } 2337 2338 // Sort the chain_candidate_infos at ARG1 and ARG2 in order of decreasing 2339 // score. 2340 int 2341 early_ra::cmp_chain_candidates (const void *arg1, const void *arg2) 2342 { 2343 auto &candidate1 = *(const chain_candidate_info *) arg1; 2344 auto &candidate2 = *(const chain_candidate_info *) arg2; 2345 if (candidate1.score != candidate2.score) 2346 return candidate1.score > candidate2.score ? -1 : 1; 2347 2348 // Prefer to increase the gap between uses of the allocated register, 2349 // to give the scheduler more freedom. 2350 auto *allocno1 = candidate1.allocno; 2351 auto *allocno2 = candidate2.allocno; 2352 if (allocno1->start_point != allocno2->start_point) 2353 return allocno1->start_point < allocno2->start_point ? -1 : 1; 2354 2355 if (allocno1 != allocno2) 2356 return allocno1->id < allocno2->id ? -1 : 1; 2357 2358 return 0; 2359 } 2360 2361 // Join the chains of allocnos that start at HEADI1 and HEADI2. 2362 // HEADI1 is either empty or a single allocno. 2363 void 2364 early_ra::chain_allocnos (unsigned int &headi1, unsigned int &headi2) 2365 { 2366 if (headi1 == INVALID_ALLOCNO) 2367 headi1 = headi2; 2368 else if (headi2 == INVALID_ALLOCNO) 2369 headi2 = headi1; 2370 else 2371 { 2372 auto *head1 = m_allocnos[headi1]; 2373 auto *head2 = m_allocnos[headi2]; 2374 gcc_checking_assert (head1->chain_next == INVALID_ALLOCNO 2375 && head1->chain_prev == INVALID_ALLOCNO 2376 && head2->chain_prev == INVALID_ALLOCNO); 2377 2378 if (head1->is_equiv 2379 && m_allocnos[head1->related_allocno]->copy_dest == headi2) 2380 { 2381 head1->is_copy_dest = head2->is_copy_dest; 2382 head1->is_strong_copy_dest = head2->is_strong_copy_dest; 2383 m_allocnos[head1->related_allocno]->copy_dest = headi1; 2384 } 2385 head1->chain_next = headi2; 2386 head2->chain_prev = headi1; 2387 2388 headi2 = headi1; 2389 } 2390 } 2391 2392 // Add GROUP2's FPR information to GROUP1's, given that GROUP2 starts 2393 // OFFSET allocnos into GROUP2. 2394 void 2395 early_ra::merge_fpr_info (allocno_group_info *group1, 2396 allocno_group_info *group2, 2397 unsigned int offset) 2398 { 2399 group1->fpr_size = std::max (group1->fpr_size, group2->fpr_size); 2400 group1->fpr_candidates &= (group2->fpr_candidates 2401 >> (offset * group1->stride)); 2402 } 2403 2404 // Set the color representative of ALLOCNO's group to REP, such that ALLOCNO 2405 // ends being at allocno offset REP_OFFSET from the start of REP. 2406 void 2407 early_ra::set_single_color_rep (allocno_info *allocno, allocno_group_info *rep, 2408 unsigned int rep_offset) 2409 { 2410 auto *group = allocno->group (); 2411 if (group->m_color_rep == rep) 2412 return; 2413 2414 group->m_color_rep = rep; 2415 gcc_checking_assert (multiple_p (group->stride, rep->stride)); 2416 unsigned int factor = group->stride / rep->stride; 2417 gcc_checking_assert (rep_offset >= allocno->offset * factor); 2418 group->color_rep_offset = rep_offset - allocno->offset * factor; 2419 merge_fpr_info (rep, group, group->color_rep_offset); 2420 } 2421 2422 // REP1 and REP2 are color representatives. Change REP1's color representative 2423 // to REP2, with REP1 starting at allocno offset REP2_OFFSET into REP2. 2424 void 2425 early_ra::set_color_rep (allocno_group_info *rep1, allocno_group_info *rep2, 2426 unsigned int rep2_offset) 2427 { 2428 gcc_checking_assert (rep1 != rep2 2429 && rep2->m_color_rep == rep2 2430 && multiple_p (rep1->stride, rep2->stride)); 2431 2432 auto heads1 = rep1->chain_heads (); 2433 auto heads2 = rep2->chain_heads (); 2434 for (unsigned int i1 = 0; i1 < heads1.size (); ++i1) 2435 if (heads1[i1] != INVALID_ALLOCNO) 2436 { 2437 unsigned int i2 = rep2_offset + i1 * rep1->stride / rep2->stride; 2438 if (heads2[i2] == INVALID_ALLOCNO) 2439 heads2[i2] = heads1[i1]; 2440 else 2441 gcc_checking_assert (heads2[i2] == heads1[i1]); 2442 set_single_color_rep (m_allocnos[heads1[i1]], rep2, i2); 2443 } 2444 } 2445 2446 // Try to chain ALLOCNO1 to the head of the chain starting at ALLOCNO2. 2447 // Return true on success. 2448 bool 2449 early_ra::try_to_chain_allocnos (allocno_info *allocno1, 2450 allocno_info *allocno2) 2451 { 2452 auto *group1 = allocno1->group ()->color_rep (); 2453 auto *group2 = allocno2->group ()->color_rep (); 2454 2455 // Avoid trying to tie different subgroups of the same group. This can 2456 // happen if the parts of a register are defined and used piecemeal. 2457 if (group1 == group2) 2458 return false; 2459 2460 // The stride (in FPRs) between allocnos of each color representative. 2461 auto fpr_stride1 = group1->stride; 2462 auto fpr_stride2 = group2->stride; 2463 2464 // The offset (in FPRs) of each allocno group from its color representative. 2465 auto fpr_offset1 = allocno1->group ()->color_rep_offset * fpr_stride1; 2466 auto fpr_offset2 = allocno2->group ()->color_rep_offset * fpr_stride2; 2467 2468 // The offset (in FPRs) of each allocno from its color representative. 2469 fpr_offset1 += allocno1->offset * allocno1->group ()->stride; 2470 fpr_offset2 += allocno2->offset * allocno2->group ()->stride; 2471 2472 // The FPR overlap is in multiples of the larger stride. 2473 auto max_fpr_stride = std::max (fpr_stride1, fpr_stride2); 2474 auto min_fpr_offset = std::min (fpr_offset1, fpr_offset2); 2475 auto fpr_overlap_offset = ROUND_DOWN (min_fpr_offset, max_fpr_stride); 2476 2477 // The offset (in FPRs) of the start of the overlapping region from 2478 // each color representative. 2479 fpr_offset1 -= fpr_overlap_offset; 2480 fpr_offset2 -= fpr_overlap_offset; 2481 2482 // The number of FPRs in each color representative after the start 2483 // of the overlapping region. 2484 auto fpr_after1 = (group1->size - 1) * fpr_stride1 - fpr_offset1; 2485 auto fpr_after2 = (group2->size - 1) * fpr_stride2 - fpr_offset2; 2486 2487 auto min_fpr_after = std::min (fpr_after1, fpr_after2); 2488 2489 // The number of overlapping allocnos. 2490 auto allocno_overlap_size = min_fpr_after / max_fpr_stride + 1; 2491 2492 // The offset (in allocnos) of the overlapping region from the start 2493 // of each color representative. 2494 auto allocno_offset1 = fpr_offset1 / fpr_stride1; 2495 auto allocno_offset2 = fpr_offset2 / fpr_stride2; 2496 2497 // The stride (in allocnos) between overlapping allocnos. 2498 auto allocno_stride1 = max_fpr_stride / fpr_stride1; 2499 auto allocno_stride2 = max_fpr_stride / fpr_stride2; 2500 2501 // Reject combinations that are impossible to allocate. 2502 auto fprs1 = group1->fpr_candidates; 2503 auto fprs2 = group2->fpr_candidates; 2504 if (fpr_offset1 > fpr_offset2) 2505 fprs2 >>= (fpr_offset1 - fpr_offset2); 2506 else 2507 fprs1 >>= (fpr_offset2 - fpr_offset1); 2508 if ((fprs1 & fprs2) == 0) 2509 { 2510 if (dump_file && (dump_flags & TDF_DETAILS)) 2511 fprintf (dump_file, " - cannot chain %d->%d, no FPRs in common" 2512 " (%08x@%d and %08x@%d)\n", allocno1->id, allocno2->id, 2513 group1->fpr_candidates, fpr_offset1, 2514 group2->fpr_candidates, fpr_offset2); 2515 return false; 2516 } 2517 2518 // Check whether the chain can be formed. 2519 auto heads1 = group1->chain_heads (); 2520 auto heads2 = group2->chain_heads (); 2521 for (unsigned int i = 0; i < allocno_overlap_size; ++i) 2522 { 2523 auto headi1 = heads1[allocno_offset1 + i * allocno_stride1]; 2524 auto headi2 = heads2[allocno_offset2 + i * allocno_stride2]; 2525 if (headi1 != INVALID_ALLOCNO && headi2 != INVALID_ALLOCNO) 2526 { 2527 auto *head1 = m_allocnos[headi1]; 2528 auto *head2 = m_allocnos[headi2]; 2529 if (head1->chain_next != INVALID_ALLOCNO) 2530 return false; 2531 if (!is_chain_candidate (head1, head2, CORRECTNESS_ONLY)) 2532 return false; 2533 } 2534 } 2535 2536 if (dump_file && (dump_flags & TDF_DETAILS)) 2537 { 2538 fprintf (dump_file, " - chaining allocnos ["); 2539 for (unsigned int i = 0; i < allocno_overlap_size; ++i) 2540 fprintf (dump_file, "%s%d", i ? "," : "", 2541 heads1[allocno_offset1 + i * allocno_stride1]); 2542 fprintf (dump_file, "] and ["); 2543 for (unsigned int i = 0; i < allocno_overlap_size; ++i) 2544 fprintf (dump_file, "%s%d", i ? "," : "", 2545 heads2[allocno_offset2 + i * allocno_stride2]); 2546 fprintf (dump_file, "]\n"); 2547 } 2548 2549 // Chain the allocnos, updating the chain heads. 2550 for (unsigned int i = 0; i < allocno_overlap_size; ++i) 2551 chain_allocnos (heads1[allocno_offset1 + i * allocno_stride1], 2552 heads2[allocno_offset2 + i * allocno_stride2]); 2553 2554 // Pick a color representative for the merged groups. 2555 allocno_group_info *new_rep; 2556 if (allocno_offset1 == 0 2557 && group1->size == allocno_overlap_size * allocno_stride1 2558 && multiple_p (fpr_stride1, fpr_stride2)) 2559 { 2560 // The first group fits within the second. 2561 set_color_rep (group1, group2, allocno_offset2); 2562 new_rep = group2; 2563 } 2564 else if (allocno_offset2 == 0 2565 && group2->size == allocno_overlap_size * allocno_stride2 2566 && multiple_p (fpr_stride2, fpr_stride1)) 2567 { 2568 // The second group fits within the first. 2569 set_color_rep (group2, group1, allocno_offset1); 2570 new_rep = group1; 2571 } 2572 else 2573 { 2574 // We need a new group that is big enough to span both groups. 2575 // The new group always has an FPR stride of 1. 2576 auto max_fpr_offset = std::max (fpr_offset1, fpr_offset2); 2577 auto max_fpr_after = std::max (fpr_after1, fpr_after2); 2578 auto new_size = max_fpr_offset + max_fpr_after + 1; 2579 new_rep = create_allocno_group (INVALID_REGNUM, new_size); 2580 2581 set_color_rep (group1, new_rep, max_fpr_offset - fpr_offset1); 2582 set_color_rep (group2, new_rep, max_fpr_offset - fpr_offset2); 2583 } 2584 2585 if (dump_file && (dump_flags & TDF_DETAILS)) 2586 { 2587 fprintf (dump_file, " - new frontier ["); 2588 auto new_heads = new_rep->chain_heads (); 2589 for (unsigned int i = 0; i < new_heads.size (); ++i) 2590 { 2591 if (i) 2592 fprintf (dump_file, ","); 2593 if (new_heads[i] == INVALID_ALLOCNO) 2594 fprintf (dump_file, "-"); 2595 else 2596 fprintf (dump_file, "%d", new_heads[i]); 2597 } 2598 fprintf (dump_file, "]\n"); 2599 } 2600 2601 return true; 2602 } 2603 2604 // Create a color_info for color representative GROUP. 2605 void 2606 early_ra::create_color (allocno_group_info *group) 2607 { 2608 auto *color = region_allocate<color_info> (); 2609 color->id = m_colors.length (); 2610 color->hard_regno = FIRST_PSEUDO_REGISTER; 2611 color->group = group; 2612 2613 gcc_checking_assert (group->m_color_rep == group); 2614 group->has_color = true; 2615 group->color = m_colors.length (); 2616 2617 m_colors.safe_push (color); 2618 } 2619 2620 // Form allocnos into chains. Create colors for each resulting clique. 2621 void 2622 early_ra::form_chains () 2623 { 2624 if (dump_file && (dump_flags & TDF_DETAILS)) 2625 fprintf (dump_file, "\nChaining allocnos:\n"); 2626 2627 // Perform (modified) interval graph coloring. First sort by 2628 // increasing start point. 2629 m_sorted_allocnos.reserve (m_allocnos.length ()); 2630 m_sorted_allocnos.splice (m_allocnos); 2631 m_sorted_allocnos.qsort (cmp_increasing<&allocno_info::start_point>); 2632 2633 // During this phase, color representatives are only correct for 2634 // unprocessed allocno groups (where the color representative is 2635 // the group itself) and for groups that contain a current chain head. 2636 unsigned int ti = 0; 2637 auto_vec<chain_candidate_info> candidates; 2638 for (unsigned int hi = 0; hi < m_sorted_allocnos.length (); ++hi) 2639 { 2640 auto *allocno1 = m_sorted_allocnos[hi]; 2641 if (allocno1->chain_next != INVALID_ALLOCNO) 2642 continue; 2643 2644 // Record conflicts with direct uses for FPR hard registers. 2645 auto *group1 = allocno1->group (); 2646 for (unsigned int fpr = allocno1->offset; fpr < 32; ++fpr) 2647 if (fpr_conflicts_with_allocno_p (fpr, allocno1)) 2648 group1->fpr_candidates &= ~(1U << (fpr - allocno1->offset)); 2649 2650 // Record conflicts due to partially call-clobbered registers. 2651 // (Full clobbers are handled by the previous loop.) 2652 for (unsigned int abi_id = 0; abi_id < NUM_ABI_IDS; ++abi_id) 2653 if (call_in_range_p (abi_id, allocno1->start_point, 2654 allocno1->end_point)) 2655 { 2656 auto fprs = partial_fpr_clobbers (abi_id, group1->fpr_size); 2657 group1->fpr_candidates &= ~fprs >> allocno1->offset; 2658 } 2659 2660 if (allocno1->is_shared ()) 2661 { 2662 if (dump_file && (dump_flags & TDF_DETAILS)) 2663 fprintf (dump_file, " Allocno %d shares the same hard register" 2664 " as allocno %d\n", allocno1->id, 2665 allocno1->related_allocno); 2666 auto *allocno2 = m_allocnos[allocno1->related_allocno]; 2667 merge_fpr_info (allocno2->group (), group1, allocno2->offset); 2668 m_shared_allocnos.safe_push (allocno1); 2669 continue; 2670 } 2671 2672 // Find earlier allocnos (in processing order) that could be chained 2673 // to this one. 2674 candidates.truncate (0); 2675 for (unsigned int sci = ti; sci < hi; ++sci) 2676 { 2677 auto *allocno2 = m_sorted_allocnos[sci]; 2678 if (allocno2->chain_prev == INVALID_ALLOCNO) 2679 { 2680 if (!is_chain_candidate (allocno1, allocno2, ALL_REASONS)) 2681 continue; 2682 chain_candidate_info candidate; 2683 candidate.allocno = allocno2; 2684 candidate.score = rate_chain (allocno1, allocno2); 2685 candidates.safe_push (candidate); 2686 } 2687 else if (sci == ti) 2688 ++ti; 2689 } 2690 2691 // Sort the candidates by decreasing score. 2692 candidates.qsort (cmp_chain_candidates); 2693 if (dump_file && (dump_flags & TDF_DETAILS)) 2694 { 2695 fprintf (dump_file, " Chain candidates for %d:", allocno1->id); 2696 for (auto &candidate : candidates) 2697 fprintf (dump_file, " %d(%d)", candidate.allocno->id, 2698 candidate.score); 2699 fprintf (dump_file, "\n"); 2700 } 2701 2702 // Pick the first candidate that works. 2703 for (auto &candidate : candidates) 2704 if (try_to_chain_allocnos (allocno1, candidate.allocno)) 2705 break; 2706 } 2707 2708 // Create color_infos for each group. Make sure that each group's 2709 // color representative is up to date. 2710 for (unsigned int hi = m_sorted_allocnos.length (); hi-- > 0; ) 2711 { 2712 auto *allocno = m_sorted_allocnos[hi]; 2713 if (allocno->is_shared ()) 2714 continue; 2715 2716 auto *rep = allocno->group ()->color_rep (); 2717 if (rep->has_color) 2718 continue; 2719 2720 create_color (rep); 2721 auto heads = rep->chain_heads (); 2722 for (unsigned int i = 0; i < heads.size (); ++i) 2723 { 2724 unsigned int ai = heads[i]; 2725 while (ai != INVALID_ALLOCNO) 2726 { 2727 allocno = m_allocnos[ai]; 2728 set_single_color_rep (allocno, rep, i * rep->stride); 2729 ai = allocno->chain_next; 2730 } 2731 } 2732 } 2733 } 2734 2735 // Return true if the given FPR (starting at 0) conflicts with allocno 2736 // ALLOCNO. 2737 bool 2738 early_ra::fpr_conflicts_with_allocno_p (unsigned int fpr, 2739 allocno_info *allocno) 2740 { 2741 auto &ranges = m_fpr_ranges[fpr]; 2742 unsigned int start_i = 0; 2743 unsigned int end_i = ranges.length (); 2744 while (start_i < end_i) 2745 { 2746 unsigned int mid_i = (start_i + end_i) / 2; 2747 auto &range = ranges[mid_i]; 2748 if (allocno->end_point > range.start_point) 2749 start_i = mid_i + 1; 2750 else if (allocno->start_point < range.end_point) 2751 end_i = mid_i; 2752 else 2753 { 2754 if (range.allocno != allocno->id) 2755 return true; 2756 // The FPR is equivalent to ALLOCNO for this particular range. 2757 // See whether ALLOCNO conflicts with a neighboring range. 2758 if (mid_i > 0 2759 && ranges[mid_i - 1].start_point >= allocno->end_point) 2760 return true; 2761 if (mid_i + 1 < ranges.length () 2762 && ranges[mid_i + 1].end_point <= allocno->start_point) 2763 return true; 2764 return false; 2765 } 2766 } 2767 return false; 2768 } 2769 2770 // Return true if there is a call with ABI identifier ABI_ID in the inclusive 2771 // program point range [START_POINT, END_POINT]. 2772 bool 2773 early_ra::call_in_range_p (unsigned int abi_id, unsigned int start_point, 2774 unsigned int end_point) 2775 { 2776 auto &points = m_call_points[abi_id]; 2777 unsigned int start_i = 0; 2778 unsigned int end_i = points.length (); 2779 while (start_i < end_i) 2780 { 2781 unsigned int mid_i = (start_i + end_i) / 2; 2782 auto point = points[mid_i]; 2783 if (end_point > point) 2784 start_i = mid_i + 1; 2785 else if (start_point < point) 2786 end_i = mid_i; 2787 else 2788 return true; 2789 } 2790 return false; 2791 } 2792 2793 // Return the set of FPRs for which a value of size SIZE will be clobbered 2794 // by a call to a function with ABI identifier ABI_ID, but would not be 2795 // for some smaller size. The set therefore excludes FPRs that are 2796 // fully-clobbered, like V0 in the base ABI. 2797 unsigned int 2798 early_ra::partial_fpr_clobbers (unsigned int abi_id, fpr_size_info size) 2799 { 2800 auto &abi = function_abis[abi_id]; 2801 unsigned int clobbers = 0; 2802 machine_mode mode = (size == FPR_D ? V8QImode 2803 : size == FPR_Q ? V16QImode : VNx16QImode); 2804 for (unsigned int regno = V0_REGNUM; regno <= V31_REGNUM; ++regno) 2805 if (!abi.clobbers_full_reg_p (regno) 2806 && abi.clobbers_reg_p (mode, regno)) 2807 clobbers |= 1U << (regno - V0_REGNUM); 2808 return clobbers; 2809 } 2810 2811 // Process copies between pseudo registers and hard registers and update 2812 // the FPR preferences for the associated colors. 2813 void 2814 early_ra::process_copies () 2815 { 2816 for (auto © : m_allocno_copies) 2817 { 2818 auto *allocno = m_allocnos[copy.allocno]; 2819 auto *group = allocno->group (); 2820 auto offset = group->color_rep_offset + allocno->offset; 2821 if (offset > copy.fpr) 2822 continue; 2823 2824 unsigned int fpr = copy.fpr - offset; 2825 auto *color = m_colors[group->color_rep ()->color]; 2826 color->fpr_preferences[fpr] = MIN (color->fpr_preferences[fpr] 2827 + copy.weight, 127); 2828 color->num_fpr_preferences += copy.weight; 2829 } 2830 } 2831 2832 // Compare the colors at *COLOR1_PTR and *COLOR2_PTR and return a <=> 2833 // result that puts colors in allocation order. 2834 int 2835 early_ra::cmp_allocation_order (const void *color1_ptr, const void *color2_ptr) 2836 { 2837 auto *color1 = *(color_info *const *) color1_ptr; 2838 auto *color2 = *(color_info *const *) color2_ptr; 2839 2840 // Allocate bigger groups before smaller groups. 2841 if (color1->group->size != color2->group->size) 2842 return color1->group->size > color2->group->size ? -1 : 1; 2843 2844 // Allocate groups with stronger FPR preferences before groups with weaker 2845 // FPR preferences. 2846 if (color1->num_fpr_preferences != color2->num_fpr_preferences) 2847 return color1->num_fpr_preferences > color2->num_fpr_preferences ? -1 : 1; 2848 2849 return (color1->id < color2->id ? -1 2850 : color1->id == color2->id ? 0 : 1); 2851 } 2852 2853 // Allocate a register to each color. If we run out of registers, 2854 // give up on doing a full allocation of the FPR-based pseudos in the 2855 // region. 2856 void 2857 early_ra::allocate_colors () 2858 { 2859 if (dump_file && (dump_flags & TDF_DETAILS)) 2860 fprintf (dump_file, "\nAllocating registers:\n"); 2861 2862 auto_vec<color_info *> sorted_colors; 2863 sorted_colors.safe_splice (m_colors); 2864 sorted_colors.qsort (cmp_allocation_order); 2865 2866 for (unsigned int i = 0; i < 32; ++i) 2867 if (!crtl->abi->clobbers_full_reg_p (V0_REGNUM + i)) 2868 m_call_preserved_fprs |= 1U << i; 2869 2870 for (auto *color : sorted_colors) 2871 { 2872 unsigned int candidates = color->group->fpr_candidates; 2873 for (unsigned int i = 0; i < color->group->size; ++i) 2874 candidates &= ~(m_allocated_fprs >> i); 2875 unsigned int best = INVALID_REGNUM; 2876 int best_weight = 0; 2877 unsigned int best_recency = 0; 2878 for (unsigned int fpr = 0; fpr <= 32U - color->group->size; ++fpr) 2879 { 2880 if ((candidates & (1U << fpr)) == 0) 2881 continue; 2882 int weight = color->fpr_preferences[fpr]; 2883 unsigned int recency = 0; 2884 // Account for registers that the current function must preserve. 2885 for (unsigned int i = 0; i < color->group->size; ++i) 2886 { 2887 if (m_call_preserved_fprs & (1U << (fpr + i))) 2888 weight -= 1; 2889 recency = MAX (recency, m_fpr_recency[fpr + i]); 2890 } 2891 // Prefer higher-numbered registers in the event of a tie. 2892 // This should tend to keep lower-numbered registers free 2893 // for allocnos that require V0-V7 or V0-V15. 2894 if (best == INVALID_REGNUM 2895 || best_weight < weight 2896 || (best_weight == weight && recency <= best_recency)) 2897 { 2898 best = fpr; 2899 best_weight = weight; 2900 best_recency = recency; 2901 } 2902 } 2903 2904 if (best == INVALID_REGNUM) 2905 { 2906 m_allocation_successful = false; 2907 return; 2908 } 2909 2910 color->hard_regno = best + V0_REGNUM; 2911 if (dump_file && (dump_flags & TDF_DETAILS)) 2912 fprintf (dump_file, " Allocating [v%d:v%d] to color %d\n", 2913 best, best + color->group->size - 1, color->id); 2914 m_allocated_fprs |= ((1U << color->group->size) - 1) << best; 2915 } 2916 } 2917 2918 // See if ALLOCNO ends a subchain of single registers that can be split 2919 // off without affecting the rest of the chain, and without introducing 2920 // any moves. Return the start of the chain if so (which might be ALLOCNO 2921 // itself), otherwise return null. 2922 early_ra::allocno_info * 2923 early_ra::find_independent_subchain (allocno_info *allocno) 2924 { 2925 // Make sure ALLOCNO ends a natural subchain. 2926 if (auto *next_allocno = chain_next (allocno)) 2927 if (next_allocno->start_point + 1 >= allocno->end_point) 2928 return nullptr; 2929 2930 // Check the allocnos in the purported subchain and find the other end. 2931 for (;;) 2932 { 2933 auto *group = allocno->group (); 2934 if (group->m_color_rep == group) 2935 return nullptr; 2936 if (group->size != 1) 2937 return nullptr; 2938 2939 auto *prev_allocno = chain_prev (allocno); 2940 if (!prev_allocno || allocno->start_point + 1 < prev_allocno->end_point) 2941 return allocno; 2942 2943 allocno = prev_allocno; 2944 } 2945 } 2946 2947 // Search the colors starting at index FIRST_COLOR whose FPRs do not belong 2948 // to FPR_CONFLICTS. Return the first such color that has no group. If all 2949 // such colors have groups, instead return the color with the latest 2950 // (smallest) start point. 2951 early_ra::color_info * 2952 early_ra::find_oldest_color (unsigned int first_color, 2953 unsigned int fpr_conflicts) 2954 { 2955 color_info *best = nullptr; 2956 unsigned int best_start_point = ~0U; 2957 unsigned int best_recency = 0; 2958 for (unsigned int ci = first_color; ci < m_colors.length (); ++ci) 2959 { 2960 auto *color = m_colors[ci]; 2961 unsigned int fpr = color->hard_regno - V0_REGNUM; 2962 if (fpr_conflicts & (1U << fpr)) 2963 continue; 2964 unsigned int start_point = 0; 2965 if (color->group) 2966 { 2967 auto chain_head = color->group->chain_heads ()[0]; 2968 start_point = m_allocnos[chain_head]->start_point; 2969 } 2970 unsigned int recency = m_fpr_recency[fpr]; 2971 if (!best 2972 || best_start_point > start_point 2973 || (best_start_point == start_point && recency < best_recency)) 2974 { 2975 best = color; 2976 best_start_point = start_point; 2977 best_recency = recency; 2978 } 2979 } 2980 return best; 2981 } 2982 2983 // If there are some spare FPRs that can be reused without introducing saves, 2984 // restores, or moves, use them to "broaden" the allocation, in order to give 2985 // the scheduler more freedom. This is particularly useful for forming LDPs 2986 // and STPs. 2987 void 2988 early_ra::broaden_colors () 2989 { 2990 // Create dummy colors for every leftover FPR that can be used cheaply. 2991 unsigned int first_color = m_colors.length (); 2992 for (unsigned int fpr = 0; fpr < 32; ++fpr) 2993 if (((m_allocated_fprs | m_call_preserved_fprs) & (1U << fpr)) == 0) 2994 { 2995 auto *color = region_allocate<color_info> (); 2996 color->id = m_colors.length (); 2997 color->hard_regno = V0_REGNUM + fpr; 2998 color->group = nullptr; 2999 m_colors.safe_push (color); 3000 } 3001 3002 // Exit early if there are no spare FPRs. 3003 if (first_color == m_colors.length ()) 3004 return; 3005 3006 // Go through the allocnos in order, seeing if there is a subchain of 3007 // single-FPR allocnos that can be split off from the containingg clique. 3008 // Allocate such subchains to the new colors on an oldest-first basis. 3009 for (auto *allocno : m_sorted_allocnos) 3010 if (auto *start_allocno = find_independent_subchain (allocno)) 3011 { 3012 unsigned int fpr_conflicts = 0; 3013 auto *member = allocno; 3014 for (;;) 3015 { 3016 fpr_conflicts |= ~member->group ()->fpr_candidates; 3017 if (member == start_allocno) 3018 break; 3019 member = m_allocnos[member->chain_prev]; 3020 } 3021 3022 auto *color = find_oldest_color (first_color, fpr_conflicts); 3023 if (!color) 3024 continue; 3025 3026 if (!color->group) 3027 { 3028 auto *group = allocno->group (); 3029 color->group = group; 3030 group->color = color->id; 3031 group->chain_heads ()[0] = INVALID_ALLOCNO; 3032 } 3033 else 3034 { 3035 auto chain_head = color->group->chain_heads ()[0]; 3036 auto start_point = m_allocnos[chain_head]->start_point; 3037 if (start_point >= allocno->end_point) 3038 // Allocating to COLOR isn't viable, and it was the best 3039 // option available. 3040 continue; 3041 3042 auto *next_allocno = chain_next (allocno); 3043 if (!next_allocno || next_allocno->start_point <= start_point) 3044 // The current allocation gives at least as much scheduling 3045 // freedom as COLOR would. 3046 continue; 3047 } 3048 3049 // Unlink the chain. 3050 if (auto *next_allocno = chain_next (allocno)) 3051 next_allocno->chain_prev = start_allocno->chain_prev; 3052 if (auto *prev_allocno = chain_prev (start_allocno)) 3053 prev_allocno->chain_next = allocno->chain_next; 3054 3055 // Make the subchain use COLOR. 3056 allocno->chain_next = color->group->chain_heads ()[0]; 3057 if (dump_file && (dump_flags & TDF_DETAILS)) 3058 fprintf (dump_file, "Moving to optional color %d (register %s):", 3059 color->id, reg_names[color->hard_regno]); 3060 for (;;) 3061 { 3062 auto *group = allocno->group (); 3063 if (dump_file && (dump_flags & TDF_DETAILS)) 3064 fprintf (dump_file, " r%d", group->regno); 3065 group->m_color_rep = color->group; 3066 group->color_rep_offset = 0; 3067 if (allocno == start_allocno) 3068 break; 3069 allocno = m_allocnos[allocno->chain_prev]; 3070 } 3071 if (dump_file && (dump_flags & TDF_DETAILS)) 3072 fprintf (dump_file, "\n"); 3073 color->group->chain_heads ()[0] = start_allocno->id; 3074 } 3075 } 3076 3077 // Record the final choice of hard register for each allocno. 3078 void 3079 early_ra::finalize_allocation () 3080 { 3081 for (auto *color : m_colors) 3082 if (color->group) 3083 { 3084 unsigned int fpr = color->hard_regno - V0_REGNUM; 3085 for (unsigned int i = 0; i < color->group->size; ++i) 3086 m_fpr_recency[fpr + i] = m_current_region; 3087 } 3088 for (auto *allocno : m_allocnos) 3089 { 3090 if (allocno->is_shared ()) 3091 continue; 3092 auto *group = allocno->group (); 3093 auto *rep = group->color_rep (); 3094 auto rep_regno = m_colors[rep->color]->hard_regno; 3095 auto group_regno = rep_regno + group->color_rep_offset; 3096 allocno->hard_regno = group_regno + allocno->offset * group->stride; 3097 } 3098 for (auto *allocno : m_shared_allocnos) 3099 allocno->hard_regno = m_allocnos[allocno->related_allocno]->hard_regno; 3100 } 3101 3102 // Replace any allocno references in REFS with the allocated register. 3103 // INSN is the instruction that contains REFS. 3104 bool 3105 early_ra::replace_regs (rtx_insn *insn, df_ref refs) 3106 { 3107 bool changed = false; 3108 for (df_ref ref = refs; ref; ref = DF_REF_NEXT_LOC (ref)) 3109 { 3110 auto range = get_allocno_subgroup (DF_REF_REG (ref)); 3111 if (!range) 3112 continue; 3113 3114 auto new_regno = range.allocno (0)->hard_regno; 3115 if (new_regno == FIRST_PSEUDO_REGISTER) 3116 { 3117 // Reset a debug instruction if, after DCE, the only remaining 3118 // references to a register are in such instructions. 3119 gcc_assert (DEBUG_INSN_P (insn)); 3120 INSN_VAR_LOCATION_LOC (insn) = gen_rtx_UNKNOWN_VAR_LOC (); 3121 return true; 3122 } 3123 *DF_REF_LOC (ref) = gen_rtx_REG (GET_MODE (DF_REF_REG (ref)), new_regno); 3124 changed = true; 3125 } 3126 return changed; 3127 } 3128 3129 // Try to make INSN match its FPR-related constraints. If this needs 3130 // a source operand (SRC) to be copied to a destination operand (DEST) 3131 // before INSN, add the associated (DEST, SRC) pairs to MOVES. 3132 // 3133 // Return -1 on failure, otherwise return a ?/!-style reject count. 3134 // The reject count doesn't model the moves, just the internal alternative 3135 // preferences. 3136 int 3137 early_ra::try_enforce_constraints (rtx_insn *insn, 3138 vec<std::pair<int, int>> &moves) 3139 { 3140 if (!constrain_operands (0, get_preferred_alternatives (insn))) 3141 return -1; 3142 3143 // Pick the alternative with the lowest cost. 3144 int best = -1; 3145 auto alts = get_preferred_alternatives (insn); 3146 for (int altno = 0; altno < recog_data.n_alternatives; ++altno) 3147 { 3148 if (!(alts & ALTERNATIVE_BIT (altno))) 3149 continue; 3150 3151 auto *op_alt = &recog_op_alt[altno * recog_data.n_operands]; 3152 if (!likely_alternative_match_p (op_alt)) 3153 continue; 3154 3155 auto_vec<std::pair<int, int>, 4> new_moves; 3156 for (int opno = 0; opno < recog_data.n_operands; ++opno) 3157 { 3158 rtx op = recog_data.operand[opno]; 3159 if (REG_P (op) 3160 && FP_REGNUM_P (REGNO (op)) 3161 && op_alt[opno].matched >= 0) 3162 { 3163 rtx old_src = recog_data.operand[op_alt[opno].matched]; 3164 if (!operands_match_p (op, old_src)) 3165 { 3166 for (int i = 0; i < recog_data.n_operands; ++i) 3167 if (i != opno) 3168 { 3169 rtx other = recog_data.operand[i]; 3170 if (reg_overlap_mentioned_p (op, other)) 3171 { 3172 old_src = NULL_RTX; 3173 break; 3174 } 3175 } 3176 if (!old_src) 3177 continue; 3178 new_moves.safe_push ({ opno, op_alt[opno].matched }); 3179 } 3180 } 3181 } 3182 int cost = count_rejects (op_alt) + new_moves.length () * 7; 3183 if (best < 0 || cost < best) 3184 { 3185 best = cost; 3186 moves.truncate (0); 3187 moves.safe_splice (new_moves); 3188 } 3189 } 3190 return best; 3191 } 3192 3193 // Make INSN matches its FPR-related constraints. 3194 void 3195 early_ra::enforce_constraints (rtx_insn *insn) 3196 { 3197 extract_insn (insn); 3198 preprocess_constraints (insn); 3199 3200 // First try with the operands they are. 3201 auto_vec<std::pair<int, int>, 4> moves; 3202 int cost = try_enforce_constraints (insn, moves); 3203 3204 // Next try taking advantage of commutativity. 3205 for (int opno = 0; opno < recog_data.n_operands - 1; ++opno) 3206 if (recog_data.constraints[opno][0] == '%') 3207 { 3208 std::swap (*recog_data.operand_loc[opno], 3209 *recog_data.operand_loc[opno + 1]); 3210 std::swap (recog_data.operand[opno], 3211 recog_data.operand[opno + 1]); 3212 auto_vec<std::pair<int, int>, 4> swapped_moves; 3213 int swapped_cost = try_enforce_constraints (insn, swapped_moves); 3214 if (swapped_cost >= 0 && (cost < 0 || swapped_cost < cost)) 3215 { 3216 cost = swapped_cost; 3217 moves.truncate (0); 3218 moves.safe_splice (swapped_moves); 3219 } 3220 else 3221 { 3222 std::swap (*recog_data.operand_loc[opno], 3223 *recog_data.operand_loc[opno + 1]); 3224 std::swap (recog_data.operand[opno], 3225 recog_data.operand[opno + 1]); 3226 } 3227 } 3228 3229 // The allocation should ensure that there is at least one valid combination. 3230 // It's too late to back out now if not. 3231 gcc_assert (cost >= 0); 3232 for (int i = 0; i < recog_data.n_dups; ++i) 3233 { 3234 int dup_of = recog_data.dup_num[i]; 3235 rtx new_op = *recog_data.operand_loc[dup_of]; 3236 if (new_op != recog_data.operand[dup_of]) 3237 *recog_data.dup_loc[i] = copy_rtx (new_op); 3238 } 3239 for (auto move : moves) 3240 { 3241 int dest_opno = move.first; 3242 int src_opno = move.second; 3243 rtx dest = recog_data.operand[dest_opno]; 3244 rtx old_src = recog_data.operand[src_opno]; 3245 rtx new_src = lowpart_subreg (GET_MODE (old_src), dest, GET_MODE (dest)); 3246 emit_insn_before (gen_move_insn (new_src, old_src), insn); 3247 *recog_data.operand_loc[src_opno] = new_src; 3248 } 3249 } 3250 3251 // See whether INSN is an instruction that operates on multi-register vectors, 3252 // and if we have decided to make it use strided rather than consecutive 3253 // accesses. Update the pattern and return true if so. 3254 bool 3255 early_ra::maybe_convert_to_strided_access (rtx_insn *insn) 3256 { 3257 if (!NONJUMP_INSN_P (insn) || recog_memoized (insn) < 0) 3258 return false; 3259 3260 auto stride_type = get_attr_stride_type (insn); 3261 rtx pat = PATTERN (insn); 3262 rtx op; 3263 if (stride_type == STRIDE_TYPE_LD1_CONSECUTIVE) 3264 op = SET_DEST (pat); 3265 else if (stride_type == STRIDE_TYPE_ST1_CONSECUTIVE) 3266 op = XVECEXP (SET_SRC (pat), 0, 1); 3267 else 3268 return false; 3269 3270 auto range = get_allocno_subgroup (op); 3271 if (!range || range.group->stride == 1) 3272 return false; 3273 3274 gcc_assert (range.start == 0 && range.count == range.group->size); 3275 auto elt_mode = GET_MODE_INNER (GET_MODE (op)); 3276 auto single_mode = aarch64_full_sve_mode (elt_mode).require (); 3277 auto_vec<rtx, 4> regs; 3278 for (unsigned int i = 0; i < range.count; ++i) 3279 regs.quick_push (gen_rtx_REG (single_mode, range.allocno (i)->hard_regno)); 3280 3281 extract_insn (insn); 3282 if (stride_type == STRIDE_TYPE_LD1_CONSECUTIVE) 3283 { 3284 auto unspec = XINT (SET_SRC (pat), 1); 3285 if (range.count == 2) 3286 pat = gen_aarch64_strided2 (unspec, GET_MODE (op), regs[0], regs[1], 3287 recog_data.operand[1], 3288 recog_data.operand[2]); 3289 else 3290 pat = gen_aarch64_strided4 (unspec, GET_MODE (op), 3291 regs[0], regs[1], regs[2], regs[3], 3292 recog_data.operand[1], 3293 recog_data.operand[2]); 3294 } 3295 else if (stride_type == STRIDE_TYPE_ST1_CONSECUTIVE) 3296 { 3297 auto unspec = XINT (SET_SRC (pat), 1); 3298 if (range.count == 2) 3299 pat = gen_aarch64_strided2 (unspec, GET_MODE (op), 3300 recog_data.operand[0], 3301 recog_data.operand[2], regs[0], regs[1]); 3302 else 3303 pat = gen_aarch64_strided4 (unspec, GET_MODE (op), 3304 recog_data.operand[0], 3305 recog_data.operand[2], 3306 regs[0], regs[1], regs[2], regs[3]); 3307 // Ensure correct sharing for the source memory. 3308 // 3309 // ??? Why doesn't the generator get this right? 3310 XVECEXP (SET_SRC (pat), 0, XVECLEN (SET_SRC (pat), 0) - 1) 3311 = *recog_data.dup_loc[0]; 3312 } 3313 else 3314 gcc_unreachable (); 3315 PATTERN (insn) = pat; 3316 INSN_CODE (insn) = -1; 3317 df_insn_rescan (insn); 3318 return true; 3319 } 3320 3321 // We've successfully allocated the current region. Apply the allocation 3322 // to the instructions. 3323 void 3324 early_ra::apply_allocation () 3325 { 3326 for (auto *insn : m_dead_insns) 3327 set_insn_deleted (insn); 3328 3329 rtx_insn *prev; 3330 for (auto insn_range : m_insn_ranges) 3331 for (rtx_insn *insn = insn_range.first; 3332 insn != insn_range.second; 3333 insn = prev) 3334 { 3335 prev = PREV_INSN (insn); 3336 if (!INSN_P (insn)) 3337 continue; 3338 3339 bool changed = maybe_convert_to_strided_access (insn); 3340 changed |= replace_regs (insn, DF_INSN_DEFS (insn)); 3341 changed |= replace_regs (insn, DF_INSN_USES (insn)); 3342 if (changed && NONDEBUG_INSN_P (insn)) 3343 { 3344 if (GET_CODE (PATTERN (insn)) != USE 3345 && GET_CODE (PATTERN (insn)) != CLOBBER 3346 && !is_move_set (PATTERN (insn))) 3347 enforce_constraints (insn); 3348 3349 // A REG_EQUIV note establishes an equivalence throughout 3350 // the function, but here we're reusing hard registers for 3351 // multiple pseudo registers. We also no longer need REG_EQUIV 3352 // notes that record potential spill locations, since we've 3353 // allocated the pseudo register without spilling. 3354 rtx *ptr = ®_NOTES (insn); 3355 while (*ptr) 3356 if (REG_NOTE_KIND (*ptr) == REG_EQUIV) 3357 *ptr = XEXP (*ptr, 1); 3358 else 3359 ptr = &XEXP (*ptr, 1); 3360 } 3361 changed |= replace_regs (insn, DF_INSN_EQ_USES (insn)); 3362 if (changed) 3363 df_insn_rescan (insn); 3364 } 3365 3366 for (auto *insn : m_dead_insns) 3367 delete_insn (insn); 3368 } 3369 3370 // Try to allocate the current region. Update the instructions if successful. 3371 void 3372 early_ra::process_region () 3373 { 3374 for (auto *allocno : m_allocnos) 3375 { 3376 allocno->chain_next = INVALID_ALLOCNO; 3377 allocno->chain_prev = INVALID_ALLOCNO; 3378 } 3379 3380 if (dump_file && (dump_flags & TDF_DETAILS)) 3381 { 3382 dump_fpr_ranges (); 3383 dump_copies (); 3384 dump_allocnos (); 3385 } 3386 3387 find_strided_accesses (); 3388 3389 if (dump_file && (dump_flags & TDF_DETAILS)) 3390 dump_allocnos (); 3391 3392 form_chains (); 3393 3394 if (dump_file && (dump_flags & TDF_DETAILS)) 3395 dump_allocnos (); 3396 3397 process_copies (); 3398 3399 if (dump_file && (dump_flags & TDF_DETAILS)) 3400 dump_colors (); 3401 3402 allocate_colors (); 3403 if (!m_allocation_successful) 3404 return; 3405 3406 broaden_colors (); 3407 finalize_allocation (); 3408 3409 if (dump_file && (dump_flags & TDF_DETAILS)) 3410 { 3411 fprintf (dump_file, "\nAllocation successful\nFinal allocation:\n"); 3412 dump_allocnos (); 3413 dump_colors (); 3414 } 3415 3416 apply_allocation (); 3417 } 3418 3419 // Return true if INSN would become dead if we successfully allocate the 3420 // current region. 3421 bool 3422 early_ra::is_dead_insn (rtx_insn *insn) 3423 { 3424 rtx set = single_set (insn); 3425 if (!set) 3426 return false; 3427 3428 rtx dest = SET_DEST (set); 3429 auto dest_range = get_allocno_subgroup (dest); 3430 if (!dest_range) 3431 return false; 3432 3433 for (auto &allocno : dest_range.allocnos ()) 3434 if (bitmap_bit_p (m_live_allocnos, allocno.id)) 3435 return false; 3436 3437 if (side_effects_p (set)) 3438 return false; 3439 3440 /* If we can't delete dead exceptions and the insn throws, 3441 then the instruction is not dead. */ 3442 if (!cfun->can_delete_dead_exceptions 3443 && !insn_nothrow_p (insn)) 3444 return false; 3445 3446 return true; 3447 } 3448 3449 // Build up information about block BB. IS_ISOLATED is true if the 3450 // block is not part of a larger region. 3451 void 3452 early_ra::process_block (basic_block bb, bool is_isolated) 3453 { 3454 m_current_bb = bb; 3455 m_current_point += 1; 3456 m_current_bb_point = m_current_point; 3457 3458 // Process live-out FPRs. 3459 bitmap live_out = df_get_live_out (bb); 3460 for (unsigned int regno = V0_REGNUM; regno <= V31_REGNUM; ++regno) 3461 if (bitmap_bit_p (live_out, regno)) 3462 record_fpr_use (regno); 3463 3464 // Process live-out allocnos. We don't track individual FPR liveness 3465 // across block boundaries, so we have to assume that the whole pseudo 3466 // register is live. 3467 bitmap_iterator bi; 3468 unsigned int regno; 3469 EXECUTE_IF_AND_IN_BITMAP (df_get_live_out (bb), m_fpr_pseudos, 3470 FIRST_PSEUDO_REGISTER, regno, bi) 3471 { 3472 auto range = get_allocno_subgroup (regno_reg_rtx[regno]); 3473 for (auto &allocno : range.allocnos ()) 3474 record_allocno_use (&allocno); 3475 } 3476 3477 m_current_point += 1; 3478 3479 record_artificial_refs (0); 3480 3481 bool is_first = true; 3482 rtx_insn *start_insn = BB_END (bb); 3483 rtx_insn *insn; 3484 FOR_BB_INSNS_REVERSE (bb, insn) 3485 { 3486 if (!NONDEBUG_INSN_P (insn)) 3487 continue; 3488 3489 // CLOBBERs are used to prevent pseudos from being upwards exposed. 3490 // We can ignore them if allocation is successful. 3491 if (GET_CODE (PATTERN (insn)) == CLOBBER) 3492 { 3493 if (get_allocno_subgroup (XEXP (PATTERN (insn), 0))) 3494 m_dead_insns.safe_push (insn); 3495 continue; 3496 } 3497 3498 if (dump_file && (dump_flags & TDF_DETAILS)) 3499 { 3500 if (is_first) 3501 fprintf (dump_file, "\nBlock %d:\n", bb->index); 3502 fprintf (dump_file, "%6d:", m_current_point); 3503 pretty_printer rtl_slim_pp; 3504 rtl_slim_pp.buffer->stream = dump_file; 3505 print_insn (&rtl_slim_pp, insn, 1); 3506 pp_flush (&rtl_slim_pp); 3507 fprintf (dump_file, "\n"); 3508 } 3509 is_first = false; 3510 3511 if (is_dead_insn (insn)) 3512 { 3513 if (dump_file && (dump_flags & TDF_DETAILS)) 3514 fprintf (dump_file, "%14s -- dead\n", ""); 3515 m_dead_insns.safe_push (insn); 3516 } 3517 else 3518 { 3519 record_insn_refs (insn); 3520 rtx pat = PATTERN (insn); 3521 if (is_move_set (pat)) 3522 record_copy (SET_DEST (pat), SET_SRC (pat), true); 3523 else 3524 { 3525 extract_insn (insn); 3526 record_constraints (insn); 3527 } 3528 } 3529 3530 // See whether we have a complete region, with no remaining live 3531 // allocnos. 3532 if (is_isolated 3533 && bitmap_empty_p (m_live_allocnos) 3534 && m_live_fprs == 0 3535 && m_allocation_successful 3536 && !m_allocnos.is_empty ()) 3537 { 3538 rtx_insn *prev_insn = PREV_INSN (insn); 3539 m_insn_ranges.safe_push ({ start_insn, prev_insn }); 3540 process_region (); 3541 start_new_region (); 3542 is_first = true; 3543 start_insn = prev_insn; 3544 } 3545 } 3546 m_insn_ranges.safe_push ({ start_insn, BB_HEAD (bb) }); 3547 3548 record_artificial_refs (DF_REF_AT_TOP); 3549 3550 // Process live-in FPRs. 3551 bitmap live_in = df_get_live_in (bb); 3552 for (unsigned int regno = V0_REGNUM; regno <= V31_REGNUM; ++regno) 3553 if (bitmap_bit_p (live_in, regno) 3554 && (m_live_fprs & (1U << (regno - V0_REGNUM)))) 3555 record_fpr_def (regno); 3556 3557 // Process live-in allocnos. 3558 EXECUTE_IF_AND_IN_BITMAP (live_in, m_fpr_pseudos, 3559 FIRST_PSEUDO_REGISTER, regno, bi) 3560 { 3561 auto range = get_allocno_subgroup (regno_reg_rtx[regno]); 3562 for (auto &allocno : range.allocnos ()) 3563 if (bitmap_bit_p (m_live_allocnos, allocno.id)) 3564 record_allocno_def (&allocno); 3565 } 3566 3567 m_current_point += 1; 3568 3569 bitmap_clear (m_live_allocnos); 3570 m_live_fprs = 0; 3571 } 3572 3573 // Divide the function into regions, such that there no edges into or out 3574 // of the region have live "FPR pseudos". 3575 void 3576 early_ra::process_blocks () 3577 { 3578 auto_sbitmap visited (last_basic_block_for_fn (m_fn)); 3579 auto_sbitmap fpr_pseudos_live_out (last_basic_block_for_fn (m_fn)); 3580 auto_sbitmap fpr_pseudos_live_in (last_basic_block_for_fn (m_fn)); 3581 3582 bitmap_clear (visited); 3583 bitmap_clear (fpr_pseudos_live_out); 3584 bitmap_clear (fpr_pseudos_live_in); 3585 3586 // Record which blocks have live FPR pseudos on entry and exit. 3587 basic_block bb; 3588 FOR_EACH_BB_FN (bb, m_fn) 3589 { 3590 if (bitmap_intersect_p (df_get_live_out (bb), m_fpr_pseudos)) 3591 bitmap_set_bit (fpr_pseudos_live_out, bb->index); 3592 if (bitmap_intersect_p (df_get_live_in (bb), m_fpr_pseudos)) 3593 bitmap_set_bit (fpr_pseudos_live_in, bb->index); 3594 } 3595 3596 // This is incremented by 1 at the start of each region. 3597 m_current_region = 0; 3598 memset (m_fpr_recency, 0, sizeof (m_fpr_recency)); 3599 3600 struct stack_node { edge_iterator ei; basic_block bb; }; 3601 3602 auto_vec<stack_node, 32> stack; 3603 auto_vec<basic_block, 32> region; 3604 3605 // Go through the function in reverse postorder and process the region 3606 // containing each block. 3607 unsigned int n_blocks = df_get_n_blocks (DF_FORWARD); 3608 int *order = df_get_postorder (DF_FORWARD); 3609 for (unsigned int bbi = 0; bbi < n_blocks; ++bbi) 3610 { 3611 basic_block bb = BASIC_BLOCK_FOR_FN (m_fn, order[bbi]); 3612 if (bb->index < NUM_FIXED_BLOCKS) 3613 continue; 3614 3615 if (!bitmap_set_bit (visited, bb->index)) 3616 continue; 3617 3618 // Process forward edges before backward edges (so push backward 3619 // edges first). Build the region in an approximation of reverse 3620 // program order. 3621 if (bitmap_bit_p (fpr_pseudos_live_in, bb->index)) 3622 stack.quick_push ({ ei_start (bb->preds), nullptr }); 3623 if (bitmap_bit_p (fpr_pseudos_live_out, bb->index)) 3624 stack.quick_push ({ ei_start (bb->succs), bb }); 3625 else 3626 region.safe_push (bb); 3627 while (!stack.is_empty ()) 3628 { 3629 auto &node = stack.last (); 3630 if (ei_end_p (node.ei)) 3631 { 3632 if (node.bb) 3633 region.safe_push (node.bb); 3634 stack.pop (); 3635 continue; 3636 } 3637 edge e = ei_edge (node.ei); 3638 if (node.bb) 3639 { 3640 // A forward edge from a node that has not yet been added 3641 // to region. 3642 if (bitmap_bit_p (fpr_pseudos_live_in, e->dest->index) 3643 && bitmap_set_bit (visited, e->dest->index)) 3644 { 3645 stack.safe_push ({ ei_start (e->dest->preds), nullptr }); 3646 if (bitmap_bit_p (fpr_pseudos_live_out, e->dest->index)) 3647 stack.safe_push ({ ei_start (e->dest->succs), e->dest }); 3648 else 3649 region.safe_push (e->dest); 3650 } 3651 else 3652 ei_next (&node.ei); 3653 } 3654 else 3655 { 3656 // A backward edge from a node that has already been added 3657 // to the region. 3658 if (bitmap_bit_p (fpr_pseudos_live_out, e->src->index) 3659 && bitmap_set_bit (visited, e->src->index)) 3660 { 3661 if (bitmap_bit_p (fpr_pseudos_live_in, e->src->index)) 3662 stack.safe_push ({ ei_start (e->src->preds), nullptr }); 3663 stack.safe_push ({ ei_start (e->src->succs), e->src }); 3664 } 3665 else 3666 ei_next (&node.ei); 3667 } 3668 } 3669 3670 m_current_point = 2; 3671 start_new_region (); 3672 3673 if (region.is_empty ()) 3674 process_block (bb, true); 3675 else 3676 { 3677 if (dump_file && (dump_flags & TDF_DETAILS)) 3678 { 3679 fprintf (dump_file, "\nRegion (from %d):", bb->index); 3680 for (unsigned int j = 0; j < region.length (); ++j) 3681 fprintf (dump_file, " %d", region[j]->index); 3682 fprintf (dump_file, "\n"); 3683 } 3684 for (unsigned int j = 0; j < region.length (); ++j) 3685 { 3686 basic_block bb = region[j]; 3687 bool is_isolated 3688 = ((j == 0 && !bitmap_bit_p (fpr_pseudos_live_out, bb->index)) 3689 || (j == region.length () - 1 3690 && !bitmap_bit_p (fpr_pseudos_live_in, bb->index))); 3691 process_block (bb, is_isolated); 3692 } 3693 } 3694 region.truncate (0); 3695 3696 if (!m_allocnos.is_empty () && m_allocation_successful) 3697 process_region (); 3698 } 3699 } 3700 3701 // Run the pass on the current function. 3702 void 3703 early_ra::execute () 3704 { 3705 df_analyze (); 3706 3707 preprocess_insns (); 3708 propagate_pseudo_reg_info (); 3709 choose_fpr_pseudos (); 3710 if (bitmap_empty_p (m_fpr_pseudos)) 3711 return; 3712 3713 if (dump_file && (dump_flags & TDF_DETAILS)) 3714 dump_pseudo_regs (); 3715 3716 process_blocks (); 3717 df_verify (); 3718 } 3719 3720 class pass_early_ra : public rtl_opt_pass 3721 { 3722 public: 3723 pass_early_ra (gcc::context *ctxt) 3724 : rtl_opt_pass (pass_data_early_ra, ctxt) 3725 {} 3726 3727 // opt_pass methods: 3728 virtual bool gate (function *); 3729 virtual unsigned int execute (function *); 3730 }; 3731 3732 bool 3733 pass_early_ra::gate (function *) 3734 { 3735 // Require a vector ISA to be enabled. 3736 if (!TARGET_SIMD && !TARGET_SVE) 3737 return false; 3738 3739 if (aarch64_early_ra == AARCH64_EARLY_RA_NONE) 3740 return false; 3741 3742 if (aarch64_early_ra == AARCH64_EARLY_RA_STRIDED 3743 && !TARGET_STREAMING_SME2) 3744 return false; 3745 3746 return true; 3747 } 3748 3749 unsigned int 3750 pass_early_ra::execute (function *fn) 3751 { 3752 early_ra (fn).execute (); 3753 return 0; 3754 } 3755 3756 } // end namespace 3757 3758 // Create a new instance of the pass. 3759 rtl_opt_pass * 3760 make_pass_aarch64_early_ra (gcc::context *ctxt) 3761 { 3762 return new pass_early_ra (ctxt); 3763 } 3764