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

<[email protected]>
Newsgroups gmane.comp.gcc.patches
Message-ID <[email protected]>
From: Kyrylo Tkachov <[email protected]>

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]>
---
 gcc/config/aarch64/aarch64-simd.md            |  2 +-
 .../gcc.target/aarch64/cmpdi-neg-1.c          | 58 +++++++++++++++++++
 2 files changed, 59 insertions(+), 1 deletion(-)
 create mode 100644 gcc/testsuite/gcc.target/aarch64/cmpdi-neg-1.c

diff --git a/gcc/config/aarch64/aarch64-simd.md b/gcc/config/aarch64/aarch64-simd.md
index aa6c1fa0735..12861333b22 100644
--- a/gcc/config/aarch64/aarch64-simd.md
+++ b/gcc/config/aarch64/aarch64-simd.md
@@ -7945,7 +7945,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 00000000000..cfe0eb0ac0b
--- /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" } } */
-- 
2.50.1 (Apple Git-155)
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.