https://gcc.gnu.org/g:af73c8bf5168848275bf909ee44fbb8f4973438f
commit r13-9726-gaf73c8bf5168848275bf909ee44fbb8f4973438f Author: Vladimir N. Makarov <vmaka...@redhat.com> Date: Thu May 29 15:26:30 2025 -0400 [LRA]: Backporting solutions for PR112918 and PR113354 to solve PR99015 Patches for PR112918 and PR11354 depend on each other and can not be clearly applied to gcc-13 branch. So patches were modified and combined. gcc/ChangeLog: PR rtl-optimization/99015 * lra-constraints.cc (enough_allocatable_hard_regs_p): Extract from in_class_p. (in_class_p): Use it with added conditions. (process_alt_operands): Try to change class too. (curr_insn_transform): Pass true to in_class_p for reg operand win. Spill pseudo only used in the insn if the corresponding operand does not require hard register anymore. Diff: --- gcc/lra-constraints.cc | 124 ++++++++++++++++++++++++++++++------------------- 1 file changed, 75 insertions(+), 49 deletions(-) diff --git a/gcc/lra-constraints.cc b/gcc/lra-constraints.cc index 21f05df0d618..2d31fcc9b4f2 100644 --- a/gcc/lra-constraints.cc +++ b/gcc/lra-constraints.cc @@ -233,6 +233,41 @@ get_reg_class (int regno) return NO_REGS; } +/* Return true if REG_CLASS has enough allocatable hard regs to keep value of + REG_MODE. */ +static bool +enough_allocatable_hard_regs_p (enum reg_class reg_class, + enum machine_mode reg_mode) +{ + int i, j, hard_regno, class_size, nregs; + + if (hard_reg_set_subset_p (reg_class_contents[reg_class], lra_no_alloc_regs)) + return false; + class_size = ira_class_hard_regs_num[reg_class]; + for (i = 0; i < class_size; i++) + { + hard_regno = ira_class_hard_regs[reg_class][i]; + nregs = hard_regno_nregs (hard_regno, reg_mode); + if (nregs == 1) + return true; + for (j = 0; j < nregs; j++) + if (TEST_HARD_REG_BIT (lra_no_alloc_regs, hard_regno + j) + || ! TEST_HARD_REG_BIT (reg_class_contents[reg_class], + hard_regno + j)) + break; + if (j >= nregs) + return true; + } + return false; +} + +/* True if C is a non-empty register class that has too few registers + to be safely used as a reload target class. */ +#define SMALL_REGISTER_CLASS_P(C) \ + (ira_class_hard_regs_num [(C)] == 1 \ + || (ira_class_hard_regs_num [(C)] >= 1 \ + && targetm.class_likely_spilled_p (C))) + /* Return true if REG satisfies (or will satisfy) reg class constraint CL. Use elimination first if REG is a hard register. If REG is a reload pseudo created by this constraints pass, assume that it will @@ -252,7 +287,6 @@ in_class_p (rtx reg, enum reg_class cl, enum reg_class *new_class, enum reg_class rclass, common_class; machine_mode reg_mode; rtx src; - int class_size, hard_regno, nregs, i, j; int regno = REGNO (reg); if (new_class != NULL) @@ -291,26 +325,11 @@ in_class_p (rtx reg, enum reg_class cl, enum reg_class *new_class, common_class = ira_reg_class_subset[rclass][cl]; if (new_class != NULL) *new_class = common_class; - if (hard_reg_set_subset_p (reg_class_contents[common_class], - lra_no_alloc_regs)) - return false; - /* Check that there are enough allocatable regs. */ - class_size = ira_class_hard_regs_num[common_class]; - for (i = 0; i < class_size; i++) - { - hard_regno = ira_class_hard_regs[common_class][i]; - nregs = hard_regno_nregs (hard_regno, reg_mode); - if (nregs == 1) - return true; - for (j = 0; j < nregs; j++) - if (TEST_HARD_REG_BIT (lra_no_alloc_regs, hard_regno + j) - || ! TEST_HARD_REG_BIT (reg_class_contents[common_class], - hard_regno + j)) - break; - if (j >= nregs) - return true; - } - return false; + return (enough_allocatable_hard_regs_p (common_class, reg_mode) + /* Do not permit reload insn operand matching (new_class == NULL + case) if the new class is too small. */ + && (new_class != NULL || common_class == rclass + || !SMALL_REGISTER_CLASS_P (common_class))); } } @@ -914,13 +933,6 @@ operands_match_p (rtx x, rtx y, int y_hard_regno) && GET_MODE_SIZE (MODE).is_constant () \ && !targetm.cannot_force_const_mem (MODE, X)) -/* True if C is a non-empty register class that has too few registers - to be safely used as a reload target class. */ -#define SMALL_REGISTER_CLASS_P(C) \ - (ira_class_hard_regs_num [(C)] == 1 \ - || (ira_class_hard_regs_num [(C)] >= 1 \ - && targetm.class_likely_spilled_p (C))) - /* If REG is a reload pseudo, try to make its class satisfying CL. */ static void narrow_reload_pseudo_class (rtx reg, enum reg_class cl) @@ -2058,6 +2070,7 @@ process_alt_operands (int only_alternative) int curr_alt_dont_inherit_ops_num; /* Numbers of operands whose reload pseudos should not be inherited. */ int curr_alt_dont_inherit_ops[MAX_RECOG_OPERANDS]; + bool curr_alt_class_change_p; rtx op; /* The register when the operand is a subreg of register, otherwise the operand itself. */ @@ -2133,6 +2146,7 @@ process_alt_operands (int only_alternative) } reject += static_reject; early_clobbered_regs_num = 0; + curr_alt_class_change_p = false; for (nop = 0; nop < n_operands; nop++) { @@ -2157,6 +2171,7 @@ process_alt_operands (int only_alternative) bool scratch_p; machine_mode mode; enum constraint_num cn; + bool class_change_p = false; opalt_num = nalt * n_operands + nop; if (curr_static_id->operand_alternative[opalt_num].anything_ok) @@ -2524,9 +2539,16 @@ process_alt_operands (int only_alternative) (this_alternative_exclude_start_hard_regs, hard_regno[nop])) win = true; - else if (hard_regno[nop] < 0 - && in_class_p (op, this_alternative, NULL)) - win = true; + else if (hard_regno[nop] < 0) + { + if (in_class_p (op, this_alternative, NULL)) + win = true; + else if (in_class_p (op, this_alternative, NULL, true)) + { + class_change_p = true; + win = true; + } + } } break; } @@ -2541,6 +2563,15 @@ process_alt_operands (int only_alternative) if (win) { this_alternative_win = true; + if (class_change_p) + { + curr_alt_class_change_p = true; + if (lra_dump_file != NULL) + fprintf (lra_dump_file, + " %d Narrowing class: reject+=3\n", + nop); + reject += 3; + } if (operand_reg[nop] != NULL_RTX) { if (hard_regno[nop] >= 0) @@ -2569,7 +2600,7 @@ process_alt_operands (int only_alternative) reject++; } if (in_class_p (operand_reg[nop], - this_costly_alternative, NULL)) + this_costly_alternative, NULL, true)) { if (lra_dump_file != NULL) fprintf @@ -3250,7 +3281,7 @@ process_alt_operands (int only_alternative) best_reload_sum = reload_sum; goal_alt_number = nalt; } - if (losers == 0) + if (losers == 0 && !curr_alt_class_change_p) /* Everything is satisfied. Do not process alternatives anymore. */ break; @@ -4355,7 +4386,7 @@ curr_insn_transform (bool check_only_p) if (REG_P (reg) && (regno = REGNO (reg)) >= FIRST_PSEUDO_REGISTER) { - bool ok_p = in_class_p (reg, goal_alt[i], &new_class); + bool ok_p = in_class_p (reg, goal_alt[i], &new_class, true); if (new_class != NO_REGS && get_reg_class (regno) != new_class) { @@ -4435,23 +4466,18 @@ curr_insn_transform (bool check_only_p) { if (goal_alt[i] == NO_REGS && REG_P (op) - /* When we assign NO_REGS it means that we will not - assign a hard register to the scratch pseudo by - assigment pass and the scratch pseudo will be - spilled. Spilled scratch pseudos are transformed - back to scratches at the LRA end. */ - && ira_former_scratch_operand_p (curr_insn, i) - && ira_former_scratch_p (REGNO (op))) + && (regno = REGNO (op)) >= FIRST_PSEUDO_REGISTER + /* We assigned a hard register to the pseudo in the past but now + decided to spill it for the insn. If the pseudo is used only + in this insn, it is better to spill it here as we free hard + registers for other pseudos referenced in the insn. The most + common case of this is a scratch register which will be + transformed to scratch back at the end of LRA. */ + && lra_get_regno_hard_regno (regno) >= 0 + && bitmap_single_bit_set_p (&lra_reg_info[regno].insn_bitmap)) { - int regno = REGNO (op); lra_change_class (regno, NO_REGS, " Change to", true); - if (lra_get_regno_hard_regno (regno) >= 0) - /* We don't have to mark all insn affected by the - spilled pseudo as there is only one such insn, the - current one. */ - reg_renumber[regno] = -1; - lra_assert (bitmap_single_bit_set_p - (&lra_reg_info[REGNO (op)].insn_bitmap)); + reg_renumber[regno] = -1; } /* We can do an optional reload. If the pseudo got a hard reg, we might improve the code through inheritance. If