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

Reply via email to