[gcc r17-3424] aarch64: let the negated 64-bit compare take a zero in the general registers

Kyrylo Tkachov via Gcc-cvs <[email protected]>
Newsgroups gmane.comp.gcc.cvs
Message-ID <[email protected]>
https://gcc.gnu.org/g:455658cadf15cc5adb94df9852524fe0b49a3e89

commit r17-3424-g455658cadf15cc5adb94df9852524fe0b49a3e89
Author: Kyrylo Tkachov <[email protected]>
Date:   Mon Aug 10 00:38:52 2026 +0200

    aarch64: let the negated 64-bit compare take a zero in the general registers
    
    aarch64_cm<optab>di has a general register alternative, but its second
    operand only accepts a register there, while the predicate also allows a
    constant zero.  A comparison against zero therefore has no general
    register alternative and the value is moved through a vector register.
    
    Accept the zero in that alternative.  The split already builds the
    comparison with aarch64_gen_compare_reg, which handles a zero operand.
    
      long f (long x) { return -(long) (x == 0); }
    
    aarch64 -O2:
    
      before                          after
        fmov  d31, x0                   cmp    x0, 0
        cmeq  d31, d31, #0              csetm  x0, eq
        fmov  x0, d31
    
    The two moves cross the general and vector register files, which is the
    expensive part.  The vector alternatives are unchanged, so a comparison
    whose operands are already in vector registers still uses cmeq.
    
    Constant time selection code in OpenSSL, Botan and libgcrypt builds masks
    this way.
    
    Bootstrapped and tested on aarch64-none-linux-gnu.
    
    gcc/ChangeLog:
    
            * config/aarch64/aarch64-simd.md (aarch64_cm<optab>di): Accept a
            zero second operand in the general register alternative.
    
    gcc/testsuite/ChangeLog:
    
            * gcc.target/aarch64/cmpdi-neg-1.c: New test.
    
    Signed-off-by: Kyrylo Tkachov <[email protected]>

Diff:
---
 gcc/config/aarch64/aarch64-simd.md             |  2 +-
 gcc/testsuite/gcc.target/aarch64/cmpdi-neg-1.c | 58 ++++++++++++++++++++++++++
 2 files changed, 59 insertions(+), 1 deletion(-)

diff --git a/gcc/config/aarch64/aarch64-simd.md b/gcc/config/aarch64/aarch64-simd.md
index e6fe3bd96274..ae562ae5b6bc 100644
--- a/gcc/config/aarch64/aarch64-simd.md
+++ b/gcc/config/aarch64/aarch64-simd.md
@@ -7977,7 +7977,7 @@
 	(neg:DI
 	  (COMPARISONS:DI
 	    (match_operand:DI 1 "register_operand" "w,w,r")
-	    (match_operand:DI 2 "aarch64_simd_reg_or_zero" "w,ZDz,r")
+	    (match_operand:DI 2 "aarch64_simd_reg_or_zero" "w,ZDz,rZ")
 	  )))
      (clobber (reg:CC CC_REGNUM))]
   "TARGET_SIMD"
diff --git a/gcc/testsuite/gcc.target/aarch64/cmpdi-neg-1.c b/gcc/testsuite/gcc.target/aarch64/cmpdi-neg-1.c
new file mode 100644
index 000000000000..cfe0eb0ac0bd
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/cmpdi-neg-1.c
@@ -0,0 +1,58 @@
+/* { dg-do compile } */
+/* { dg-options "-O2" } */
+/* { dg-final { check-function-bodies "**" "" "" } } */
+
+/* A 64-bit comparison against zero whose result is negated has to stay in
+   the general registers.  Before, only the vector alternative accepted the
+   zero, so the value was moved to and from a vector register.  */
+
+/*
+** f1:
+**	cmp	x0, 0
+**	csetm	x0, eq
+**	ret
+*/
+long
+f1 (long x)
+{
+  return -(long) (x == 0);
+}
+
+/*
+** f2:
+**	cmp	x0, 0
+**	csetm	x0, ne
+**	ret
+*/
+long
+f2 (long x)
+{
+  return -(long) (x != 0);
+}
+
+/*
+** f3:
+**	cmp	x0, 0
+**	csetm	x0, le
+**	ret
+*/
+long
+f3 (long x)
+{
+  return -(long) (x <= 0);
+}
+
+/*
+** f4:
+**	cmp	x0, x1
+**	csetm	x0, eq
+**	ret
+*/
+long
+f4 (long x, long y)
+{
+  return -(long) (x == y);
+}
+
+/* { dg-final { scan-assembler-not "\\tfmov\\t" } } */
+/* { dg-final { scan-assembler-not "\\tcmeq\\t" } } */
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.