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

Reply via email to