[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" } } */