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)