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 <[email protected]>
* config/aarch64/aarch64.md (*csinv3_utxw_insn): New.
* config/aarch64/iterators.md (neg_not_cs): New.
gcc/testsuite/ChangeLog:
2020-04-22 Alex Coplan <[email protected]>
* 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 "**" "" "" } } */