Hello, The attached patch adds an optimization to the AArch64 backend to catch additional cases where we can use csinv and csneg.
Given the C code: unsigned long long inv(unsigned a, unsigned b, unsigned c) { return a ? b : ~c; } Prior to this patch, AArch64 GCC at -O2 generates: inv: cmp w0, 0 mvn w2, w2 csel w0, w1, w2, ne ret and after applying the patch, we get: inv: cmp w0, 0 csinv w0, w1, w2, ne ret The new pattern also catches the optimization for the symmetric case where the body of foo reads a ? ~b : c. Similarly, with the following code: unsigned long long neg(unsigned a, unsigned b, unsigned c) { return a ? b : -c; } GCC at -O2 previously gave: neg: cmp w0, 0 neg w2, w2 csel w0, w1, w2, ne but now gives: neg: cmp w0, 0 csneg w0, w1, w2, ne ret with the corresponding code for the symmetric case as above. Testing: - New regression test which checks all four of these cases. - Full bootstrap and regression on aarch64-linux. Thanks, Alex --- gcc/ChangeLog: 2020-04-24 Alex Coplan <alex.cop...@arm.com> * config/aarch64/aarch64.md (*csinv3_utxw_insn): New. * config/aarch64/iterators.md (neg_not_cs): New. gcc/testsuite/ChangeLog: 2020-04-22 Alex Coplan <alex.cop...@arm.com> * gcc.target/aarch64/csinv-neg.c: New test.
diff --git a/gcc/config/aarch64/aarch64.md b/gcc/config/aarch64/aarch64.md index c7c4d1dd519..2f7367c0b1a 100644 --- a/gcc/config/aarch64/aarch64.md +++ b/gcc/config/aarch64/aarch64.md @@ -4390,6 +4390,19 @@ [(set_attr "type" "csel")] ) +(define_insn "*csinv3_uxtw_insn" + [(set (match_operand:DI 0 "register_operand" "=r") + (if_then_else:DI + (match_operand 1 "aarch64_comparison_operation" "") + (zero_extend:DI + (match_operand:SI 2 "aarch64_reg_or_zero" "rZ")) + (zero_extend:DI + (NEG_NOT:SI (match_operand:SI 3 "register_operand" "r")))))] + "" + "cs<neg_not_cs>\\t%w0, %w2, %w3, %m1" + [(set_attr "type" "csel")] +) + ;; If X can be loaded by a single CNT[BHWD] instruction, ;; ;; A = UMAX (B, X) diff --git a/gcc/config/aarch64/iterators.md b/gcc/config/aarch64/iterators.md index 8e434389e59..a568cf21b99 100644 --- a/gcc/config/aarch64/iterators.md +++ b/gcc/config/aarch64/iterators.md @@ -1932,6 +1932,9 @@ ;; Operation names for negate and bitwise complement. (define_code_attr neg_not_op [(neg "neg") (not "not")]) +;; csinv, csneg insn suffixes. +(define_code_attr neg_not_cs [(neg "neg") (not "inv")]) + ;; Similar, but when the second operand is inverted. (define_code_attr nlogical [(and "bic") (ior "orn") (xor "eon")]) diff --git a/gcc/testsuite/gcc.target/aarch64/csinv-neg.c b/gcc/testsuite/gcc.target/aarch64/csinv-neg.c new file mode 100644 index 00000000000..4636f3e0906 --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/csinv-neg.c @@ -0,0 +1,54 @@ +/* { dg-do compile } */ +/* { dg-options "-O2" } */ + +/* +** inv1: +** cmp w0, 0 +** csinv w0, w1, w2, ne +** ret +*/ +unsigned long long +inv1(unsigned a, unsigned b, unsigned c) +{ + return a ? b : ~c; +} + +/* +** inv2: +** cmp w0, 0 +** csinv w0, w2, w1, eq +** ret +*/ +unsigned long long +inv2(unsigned a, unsigned b, unsigned c) +{ + return a ? ~b : c; +} + +/* +** neg1: +** cmp w0, 0 +** csneg w0, w1, w2, ne +** ret +*/ +unsigned long long +neg1(unsigned a, unsigned b, unsigned c) +{ + return a ? b : -c; +} + + +/* +** neg2: +** cmp w0, 0 +** csneg w0, w2, w1, eq +** ret +*/ +unsigned long long +neg2(unsigned a, unsigned b, unsigned c) +{ + return a ? -b : c; +} + + +/* { dg-final { check-function-bodies "**" "" "" } } */