Hi all,
For the testcase in the patch we were generating an extra neg instruction:
cmp w0, wzr
csneg w0, w0, w0, ge
neg w0, w0
ret
instead of the optimal:
cmp w0, wzr
csneg w0, w0, w0, lt
ret
The reason is that combine tries to merge the operation into a negation of an
abs.
I considered teaching combine not to do that but it would require telling it
that it shouldn't
do it if there is a conditional negate instruction. There's no optab for that
though :(
Also, we already advertise that we have an abs optab, even though we expand to
a compare and
a csneg anyway. This patch was the cleanest way I could do this. We just match
the neg of an abs
and generate the same csneg sequence as for normal abs, just with the
comparison condition inverted.
Bootstrapped and tested on aarch64.
Ok for trunk?
Thanks,
Kyrill
2015-07-13 Kyrylo Tkachov <[email protected]>
* config/aarch64/aarch64.md (*absneg2<mode>_insn): New
define_and_split.
2015-07-13 Kyrylo Tkachov <[email protected]>
* gcc.target/aarch64/neg-abs_1.c: New test.
commit 7527a76d25067ce4a5426e563e162487604ac6c1
Author: Kyrylo Tkachov <[email protected]>
Date: Thu Jul 9 16:54:23 2015 +0100
[AArch64] Handle -|x| case using a single csneg
diff --git a/gcc/config/aarch64/aarch64.md b/gcc/config/aarch64/aarch64.md
index e6d0764..6664d1a 100644
--- a/gcc/config/aarch64/aarch64.md
+++ b/gcc/config/aarch64/aarch64.md
@@ -2333,6 +2333,29 @@ (define_expand "abs<mode>2"
}
)
+;; Combine will try merging (c > 0 ? -x : x) into (-|x|). This isn't a good
+;; idea if the target has a conditional negate instruction and no integer
+;; abs instruction, but the midend doesn't have an optab for conditional neg
+;; and we advertise an optab for abs, so match that case here and emit the
+;; optimal CSNEG variant.
+(define_insn_and_split "*absneg2<mode>_insn"
+ [(set (match_operand:GPI 0 "register_operand" "=r")
+ (neg:GPI
+ (abs:GPI (match_operand:GPI 1 "register_operand" "r"))))]
+ ""
+ "#"
+ ""
+ [(const_int 0)]
+ {
+ rtx ccreg = aarch64_gen_compare_reg (LT, operands[1], const0_rtx);
+ rtx x = gen_rtx_GE (VOIDmode, ccreg, const0_rtx);
+ emit_insn (gen_csneg3<mode>_insn (operands[0], x, operands[1],
+ operands[1]));
+ DONE;
+ }
+ [(set_attr "type" "csel")]
+)
+
(define_insn "neg<mode>2"
[(set (match_operand:GPI 0 "register_operand" "=r,w")
(neg:GPI (match_operand:GPI 1 "register_operand" "r,w")))]
diff --git a/gcc/testsuite/gcc.target/aarch64/neg-abs_1.c b/gcc/testsuite/gcc.target/aarch64/neg-abs_1.c
new file mode 100644
index 0000000..cb2a387
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/neg-abs_1.c
@@ -0,0 +1,17 @@
+/* { dg-do compile } */
+/* { dg-options "-save-temps -O2" } */
+
+int
+f1 (int x)
+{
+ return x < 0 ? x : -x;
+}
+
+long long
+f2 (long long x)
+{
+ return x < 0 ? x : -x;
+}
+
+/* { dg-final { scan-assembler-not "\tneg\tw\[0-9\]*.*" } } */
+/* { dg-final { scan-assembler-not "\tneg\tx\[0-9\]*.*" } } */