https://gcc.gnu.org/g:f311d59c4d45f5042029647c88966e2e48330adf

commit r17-4275-gf311d59c4d45f5042029647c88966e2e48330adf
Author: Stefan Schulze Frielinghaus <[email protected]>
Date:   Wed Sep 16 08:27:33 2026 +0200

    ira: Treat hard register constraints similarly as single reg class 
constraints
    
    Treat a hard register constraint the same way as a constraint associated
    a single register class for process_single_reg_class_operands().
    
    gcc/ChangeLog:
    
            * ira-lives.cc (single_reg_class): Compute regno in case of
            single reg class constraint or hard register constraint, and
            rename to ...
            (single_reg_class_regno): ... this.
            (single_reg_operand_class): Similarly as before and rename
            to ...
            (single_reg_operand_class_regno): ... this.
            (process_single_reg_class_operands): Utilize
            single_reg_operand_class_regno() and deal with regnos directly
            instead of single reg classes.
            (process_single_reg_class_operands): Rename to ...
            (process_single_reg_constrained_operands): ... this.
            (process_bb_node_lives): Refer to renamed function.
    
    gcc/testsuite/ChangeLog:
    
            * gcc.dg/asm-hard-reg-6.c: This patch would result in only one
            reload for alternative 1 in test_reg_reg which changes costing
            which in turn leads to choosing alternative 1 for which we
            didn't test.  Restore the old behaviour by choosing for GPR3 r4
            which results in two reloads in each alternative.
            * gcc.target/s390/asm-hard-reg-1.c: Similarly here we also
            compute a more precise conflicting register set which leads to
            choosing a different insn alternative for test_out_2.

Diff:
---
 gcc/ira-lives.cc                               | 95 +++++++++++++++-----------
 gcc/testsuite/gcc.dg/asm-hard-reg-6.c          |  4 +-
 gcc/testsuite/gcc.target/s390/asm-hard-reg-1.c |  4 +-
 3 files changed, 59 insertions(+), 44 deletions(-)

diff --git a/gcc/ira-lives.cc b/gcc/ira-lives.cc
index 9103b3e4ff29..7b9c03e91ad6 100644
--- a/gcc/ira-lives.cc
+++ b/gcc/ira-lives.cc
@@ -846,16 +846,16 @@ mark_hard_reg_early_clobbers (rtx_insn *insn, bool live_p)
 }
 
 /* Checks that CONSTRAINTS permits to use only one hard register.  If
-   it is so, the function returns the class of the hard register.
-   Otherwise it returns NO_REGS.  */
-static enum reg_class
-single_reg_class (const char *constraints, rtx op, rtx equiv_const)
+   it is so, the function returns the register.  Otherwise it returns -1.  */
+static int
+single_reg_class_regno (const char *constraints, rtx op, rtx equiv_const)
 {
   int c;
-  enum reg_class cl, next_cl;
+  int regno, next_regno;
+  enum reg_class next_cl;
   enum constraint_num cn;
 
-  cl = NO_REGS;
+  regno = -1;
   alternative_mask preferred = preferred_alternatives;
   while ((c = *constraints))
     {
@@ -867,7 +867,14 @@ single_reg_class (const char *constraints, rtx op, rtx 
equiv_const)
        switch (c)
          {
          case 'g':
-           return NO_REGS;
+           return -1;
+
+         case '{':
+           next_regno = decode_hard_reg_constraint (constraints);
+           if (regno >= 0 && regno != next_regno)
+             return -1;
+           regno = next_regno;
+           break;
 
          default:
            /* ??? Is this the best way to handle memory constraints?  */
@@ -876,21 +883,21 @@ single_reg_class (const char *constraints, rtx op, rtx 
equiv_const)
                || insn_extra_special_memory_constraint (cn)
                || insn_extra_relaxed_memory_constraint (cn)
                || insn_extra_address_constraint (cn))
-             return NO_REGS;
+             return -1;
            if (constraint_satisfied_p (op, cn)
                || (equiv_const != NULL_RTX
                    && CONSTANT_P (equiv_const)
                    && constraint_satisfied_p (equiv_const, cn)))
-             return NO_REGS;
+             return -1;
            next_cl = reg_class_for_constraint (cn);
            if (next_cl == NO_REGS)
              break;
-           if (cl == NO_REGS
-               ? ira_class_singleton[next_cl][GET_MODE (op)] < 0
-               : (ira_class_singleton[cl][GET_MODE (op)]
-                  != ira_class_singleton[next_cl][GET_MODE (op)]))
-             return NO_REGS;
-           cl = next_cl;
+           next_regno = ira_class_singleton[next_cl][GET_MODE (op)];
+           if (regno < 0
+               ? next_regno < 0
+               : regno != next_regno)
+             return -1;
+           regno = next_regno;
            break;
 
          case '0': case '1': case '2': case '3': case '4':
@@ -899,33 +906,32 @@ single_reg_class (const char *constraints, rtx op, rtx 
equiv_const)
              char *end;
              unsigned long dup = strtoul (constraints, &end, 10);
              constraints = end;
-             next_cl
-               = single_reg_class (recog_data.constraints[dup],
-                                   recog_data.operand[dup], NULL_RTX);
-             if (cl == NO_REGS
-                 ? ira_class_singleton[next_cl][GET_MODE (op)] < 0
-                 : (ira_class_singleton[cl][GET_MODE (op)]
-                    != ira_class_singleton[next_cl][GET_MODE (op)]))
-               return NO_REGS;
-             cl = next_cl;
+             next_regno
+               = single_reg_class_regno (recog_data.constraints[dup],
+                                         recog_data.operand[dup], NULL_RTX);
+             if (regno < 0
+                 ? next_regno < 0
+                 : regno != next_regno)
+               return -1;
+             regno = next_regno;
              continue;
            }
          }
       constraints += CONSTRAINT_LEN (c, constraints);
    }
-  return cl;
+  return regno;
 }
 
 /* The function checks that operand OP_NUM of the current insn can use
    only one hard register.  If it is so, the function returns the
-   class of the hard register.  Otherwise it returns NO_REGS.  */
-static enum reg_class
-single_reg_operand_class (int op_num)
+   hard register.  Otherwise it returns -1.  */
+static int
+single_reg_operand_class_regno (int op_num)
 {
   if (op_num < 0 || recog_data.n_alternatives == 0)
-    return NO_REGS;
-  return single_reg_class (recog_data.constraints[op_num],
-                          recog_data.operand[op_num], NULL_RTX);
+    return -1;
+  return single_reg_class_regno (recog_data.constraints[op_num],
+                                recog_data.operand[op_num], NULL_RTX);
 }
 
 /* The function sets up hard register set *SET to hard registers which
@@ -989,9 +995,9 @@ ira_implicitly_set_insn_hard_regs (HARD_REG_SET *set,
    hard register and makes other currently living allocnos conflicting
    with the hard register.  */
 static void
-process_single_reg_class_operands (bool in_p, int freq)
+process_single_reg_constrained_operands (bool in_p, int freq)
 {
-  int i, regno;
+  int i, regno, hard_regno;
   unsigned int px;
   enum reg_class cl;
   rtx operand;
@@ -1006,8 +1012,8 @@ process_single_reg_class_operands (bool in_p, int freq)
       if (! in_p && recog_data.operand_type[i] != OP_OUT
          && recog_data.operand_type[i] != OP_INOUT)
        continue;
-      cl = single_reg_operand_class (i);
-      if (cl == NO_REGS)
+      hard_regno = single_reg_operand_class_regno (i);
+      if (hard_regno < 0)
        continue;
 
       operand_a = NULL;
@@ -1020,6 +1026,11 @@ process_single_reg_class_operands (bool in_p, int freq)
        {
          enum reg_class aclass;
 
+         cl = NO_REGS;
+         int nregs = hard_regno_nregs (hard_regno, recog_data.operand_mode[i]);
+         for (int j = 0; j < nregs; ++j)
+           cl = reg_class_superunion[cl][REGNO_REG_CLASS (hard_regno + j)];
+
          operand_a = ira_curr_regno_allocno_map[regno];
          aclass = ALLOCNO_CLASS (operand_a);
          if (ira_class_subset_p[cl][aclass])
@@ -1036,7 +1047,7 @@ process_single_reg_class_operands (bool in_p, int freq)
              poly_int64 offset;
 
              xmode = recog_data.operand_mode[i];
-             xregno = ira_class_singleton[cl][xmode];
+             xregno = hard_regno;
              gcc_assert (xregno >= 0);
              ymode = ALLOCNO_MODE (operand_a);
              offset = subreg_lowpart_offset (ymode, xmode);
@@ -1059,6 +1070,10 @@ process_single_reg_class_operands (bool in_p, int freq)
            }
        }
 
+      HARD_REG_SET hard_regs;
+      CLEAR_HARD_REG_SET (hard_regs);
+      add_to_hard_reg_set (&hard_regs, recog_data.operand_mode[i], hard_regno);
+
       EXECUTE_IF_SET_IN_SPARSESET (objects_live, px)
         {
          ira_object_t obj = ira_object_id_map[px];
@@ -1068,8 +1083,8 @@ process_single_reg_class_operands (bool in_p, int freq)
              /* We could increase costs of A instead of making it
                 conflicting with the hard register.  But it works worse
                 because it will be spilled in reload in anyway.  */
-             OBJECT_CONFLICT_HARD_REGS (obj) |= reg_class_contents[cl];
-             OBJECT_TOTAL_CONFLICT_HARD_REGS (obj) |= reg_class_contents[cl];
+             OBJECT_CONFLICT_HARD_REGS (obj) |= hard_regs;
+             OBJECT_TOTAL_CONFLICT_HARD_REGS (obj) |= hard_regs;
            }
        }
     }
@@ -1540,7 +1555,7 @@ process_bb_node_lives (ira_loop_tree_node_t 
loop_tree_node)
          preferred_alternatives = ira_setup_alts (insn);
          process_register_constraint_filters ();
          process_dependent_filters ();
-         process_single_reg_class_operands (false, freq);
+         process_single_reg_constrained_operands (false, freq);
 
          if (call_p)
            {
@@ -1618,7 +1633,7 @@ process_bb_node_lives (ira_loop_tree_node_t 
loop_tree_node)
          FOR_EACH_INSN_USE (use, insn)
            mark_ref_live (use);
 
-         process_single_reg_class_operands (true, freq);
+         process_single_reg_constrained_operands (true, freq);
 
          set_p = mark_hard_reg_early_clobbers (insn, true);
 
diff --git a/gcc/testsuite/gcc.dg/asm-hard-reg-6.c 
b/gcc/testsuite/gcc.dg/asm-hard-reg-6.c
index c87a8116a869..b42b4d2c198a 100644
--- a/gcc/testsuite/gcc.dg/asm-hard-reg-6.c
+++ b/gcc/testsuite/gcc.dg/asm-hard-reg-6.c
@@ -36,8 +36,8 @@
 #elif defined (__s390__)
 # define GPR1 "{r0}"
 # define GPR2 "{r1}"
-# define GPR3 "{r2}"
-/* { dg-final { scan-assembler-times "foo\t%r0,%r2" 1 { target { s390*-*-* } } 
} } */
+# define GPR3 "{r4}"
+/* { dg-final { scan-assembler-times "foo\t%r0,%r4" 1 { target { s390*-*-* } } 
} } */
 /* { dg-final { scan-assembler-times "bar\t%r1,0\\(%r3\\)" 1 { target { 
s390*-*-* } } } } */
 #elif defined (__x86_64__)
 # define GPR1 "{eax}"
diff --git a/gcc/testsuite/gcc.target/s390/asm-hard-reg-1.c 
b/gcc/testsuite/gcc.target/s390/asm-hard-reg-1.c
index 671c0ede6efa..53ac46eb40c8 100644
--- a/gcc/testsuite/gcc.target/s390/asm-hard-reg-1.c
+++ b/gcc/testsuite/gcc.target/s390/asm-hard-reg-1.c
@@ -75,8 +75,8 @@ test_out_1 (void)
 ** test_out_2:
 **     lgr     (%r[0-9]+),%r2
 **     foo     %r2
-**     ark     (%r[0-9]+),\1,%r2
-**     lgfr    %r2,\2
+**     ar      %r2,\1
+**     lgfr    %r2,%r2
 **     br      %r14
 */

Reply via email to