https://gcc.gnu.org/g:81b7d7b827252fd93694812ccc751059b2c0d8e4

commit r17-3218-g81b7d7b827252fd93694812ccc751059b2c0d8e4
Author: Kyrylo Tkachov <[email protected]>
Date:   Mon Aug 10 01:15:59 2026 -0700

    aarch64: accept x8-x15 in aarch64_general_reg
    
    The peephole2 patterns that fuse a comparison and a subtraction into SUBS
    require their destination to satisfy aarch64_general_reg.  That predicate
    compares REGNO_REG_CLASS against GENERAL_REGS, but REGNO_REG_CLASS returns
    the smallest class holding the register, and since the SME2 support added
    W8_W11_REGS and W12_W15_REGS it does not return GENERAL_REGS for x8-x15.
    The peepholes therefore stop firing whenever the register allocator puts
    the difference in one of those eight registers:
    
      (set (reg:CC cc) (compare:CC (reg:DI x2) (reg:DI x5)))
      (set (reg:DI x9) (minus:DI (reg:DI x2) (reg:DI x5)))
    
      -     cmp     x2, x5
      +     subs    x9, x2, x5
    
    Test the register number instead.  The stack pointer is still rejected,
    which is what the predicate was added for.
    Bootstrapped and tested on aarch64-none-linux-gnu.
    Ok for trunk?
    Thanks,
    Kyrill
    
    gcc/ChangeLog:
    
            * config/aarch64/predicates.md (aarch64_general_reg): Test the
            register number rather than REGNO_REG_CLASS, which reports the
            W8_W11_REGS and W12_W15_REGS subclasses for x8-x15.
    
    gcc/testsuite/ChangeLog:
    
            * gcc.dg/rtl/aarch64/subs_general_reg.c: New test.
    
    Signed-off-by: Kyrylo Tkachov <[email protected]>

Diff:
---
 gcc/config/aarch64/predicates.md                   |  8 ++-
 .../gcc.dg/rtl/aarch64/subs_general_reg.c          | 70 ++++++++++++++++++++++
 2 files changed, 76 insertions(+), 2 deletions(-)

diff --git a/gcc/config/aarch64/predicates.md b/gcc/config/aarch64/predicates.md
index e2911a0bccdb..9d2613a9aeef 100644
--- a/gcc/config/aarch64/predicates.md
+++ b/gcc/config/aarch64/predicates.md
@@ -36,10 +36,14 @@
   (ior (match_code "symbol_ref")
        (match_operand 0 "register_operand")))
 
+;; True if OP is an allocated general register, i.e. x0-x30 but not the
+;; stack pointer.  REGNO_REG_CLASS returns the smallest class holding the
+;; register, and x8-x15 belong to the W8_W11_REGS and W12_W15_REGS
+;; subclasses, so it cannot be compared against GENERAL_REGS here.
 (define_predicate "aarch64_general_reg"
   (and (match_operand 0 "register_operand")
-       (match_test "REGNO_REG_CLASS (REGNO (op)) == STUB_REGS
-                   || REGNO_REG_CLASS (REGNO (op)) == GENERAL_REGS")))
+       (match_test "REG_P (op)
+                   && GP_REGNUM_P (REGNO (op))")))
 
 ;; Return true if OP a (const_int 0) operand.
 (define_predicate "const0_operand"
diff --git a/gcc/testsuite/gcc.dg/rtl/aarch64/subs_general_reg.c 
b/gcc/testsuite/gcc.dg/rtl/aarch64/subs_general_reg.c
new file mode 100644
index 000000000000..26d07a4233c6
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/rtl/aarch64/subs_general_reg.c
@@ -0,0 +1,70 @@
+/* { dg-do compile { target aarch64-*-* } } */
+/* { dg-options "-O2" } */
+
+/* The peephole2 patterns that build SUBS require the destination to satisfy
+   aarch64_general_reg.  Every allocatable general register must satisfy it,
+   including x8-x15, which REGNO_REG_CLASS reports as the W8_W11_REGS and
+   W12_W15_REGS subclasses rather than as GENERAL_REGS.  */
+
+int __RTL (startwith ("peephole2")) sub_compare_x2 ()
+{
+(function "sub_compare_x2"
+  (insn-chain
+    (block 2
+      (edge-from entry (flags "FALLTHRU"))
+      (cnote 3 [bb 2] NOTE_INSN_BASIC_BLOCK)
+      (cinsn 90 (set (reg:CC cc)
+                (compare:CC (reg:DI x2) (reg:DI x5))))
+      (cinsn 89 (set (reg:DI x2)
+                (minus:DI (reg:DI x2) (reg:DI x5))))
+      ;; Extra insns to avoid the above being deleted by DCE.
+      (cinsn 12 (use (reg/i:DI cc)))
+      (cinsn 11 (use (reg/i:DI x2)))
+      (edge-to exit (flags "FALLTHRU"))
+    ) ;; block 2
+  ) ;; insn-chain
+) ;; function "sub_compare_x2"
+}
+
+int __RTL (startwith ("peephole2")) sub_compare_x9 ()
+{
+(function "sub_compare_x9"
+  (insn-chain
+    (block 2
+      (edge-from entry (flags "FALLTHRU"))
+      (cnote 3 [bb 2] NOTE_INSN_BASIC_BLOCK)
+      (cinsn 90 (set (reg:CC cc)
+                (compare:CC (reg:DI x2) (reg:DI x5))))
+      (cinsn 89 (set (reg:DI x9)
+                (minus:DI (reg:DI x2) (reg:DI x5))))
+      ;; Extra insns to avoid the above being deleted by DCE.
+      (cinsn 12 (use (reg/i:DI cc)))
+      (cinsn 11 (use (reg/i:DI x9)))
+      (edge-to exit (flags "FALLTHRU"))
+    ) ;; block 2
+  ) ;; insn-chain
+) ;; function "sub_compare_x9"
+}
+
+int __RTL (startwith ("peephole2")) sub_compare_x13 ()
+{
+(function "sub_compare_x13"
+  (insn-chain
+    (block 2
+      (edge-from entry (flags "FALLTHRU"))
+      (cnote 3 [bb 2] NOTE_INSN_BASIC_BLOCK)
+      (cinsn 90 (set (reg:CC cc)
+                (compare:CC (reg:DI x2) (reg:DI x5))))
+      (cinsn 89 (set (reg:DI x13)
+                (minus:DI (reg:DI x2) (reg:DI x5))))
+      ;; Extra insns to avoid the above being deleted by DCE.
+      (cinsn 12 (use (reg/i:DI cc)))
+      (cinsn 11 (use (reg/i:DI x13)))
+      (edge-to exit (flags "FALLTHRU"))
+    ) ;; block 2
+  ) ;; insn-chain
+) ;; function "sub_compare_x13"
+}
+
+/* { dg-final { scan-assembler-times {subs\tx[0-9]+, x2, x5} 3 } } */
+/* { dg-final { scan-assembler-not {\tcmp\t} } } */

Reply via email to