> -----Original Message-----
> From: [email protected] <[email protected]>
> Sent: 12 August 2026 10:42
> To: [email protected]
> Cc: Tamar Christina <[email protected]>; Wilco Dijkstra
> <[email protected]>; Alex Coplan <[email protected]>;
> [email protected]; Alice Carlotti <[email protected]>;
> Kyrylo Tkachov <[email protected]>
> Subject: [PATCH] aarch64: accept x8-x15 in aarch64_general_reg
> 
> From: Kyrylo Tkachov <[email protected]>
> 
> 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]>
> ---
>  gcc/config/aarch64/predicates.md              |  9 ++-
>  .../gcc.dg/rtl/aarch64/subs_general_reg.c     | 70 +++++++++++++++++++
>  2 files changed, 77 insertions(+), 2 deletions(-)
>  create mode 100644 gcc/testsuite/gcc.dg/rtl/aarch64/subs_general_reg.c
> 
> diff --git a/gcc/config/aarch64/predicates.md
> b/gcc/config/aarch64/predicates.md
> index e2911a0bccd..eff83c0231f 100644
> --- a/gcc/config/aarch64/predicates.md
> +++ b/gcc/config/aarch64/predicates.md
> @@ -36,10 +36,15 @@
>    (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)
> +                 && HARD_REGISTER_P (op)
> +                 && GP_REGNUM_P (REGNO (op))")))

Looks sensible to me, but isn't the HARD_REGISTER_P redundant?
GP_REGNUM_P already specifically checks for a reg numbers belong
to the hard register range?

So I think we can drop that.

But LGTM.

Thanks,
Tamr

> 
>  ;; 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 00000000000..26d07a4233c
> --- /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} } } */
> --
> 2.50.1 (Apple Git-155)

Reply via email to