Hi all, When we perform an addition but only use the result for a comparison, we can save an instruction.
Consider this function: int foo (int a, int b) { return ((a + b) == 0) ? 1 : 7; } Here is the original output: foo: add w0, w0, w1 cmp w0, wzr mov w1, 7 mov w0, 1 csel w0, w1, w0, ne ret Now we get this: foo: cmn w0, w1 mov w1, 7 mov w0, 1 csel w0, w1, w0, ne ret :) I added other testcases for this and also some for adds and subs, which were investigated as part of this work. OK for trunk? Cheers, Ian 2012-11-06 Ian Bolton <ian.bol...@arm.com> * gcc/config/aarch64/aarch64.md (*compare_neg<mode>): New pattern. * gcc/testsuite/gcc.target/aarch64/cmn.c: New test. * gcc/testsuite/gcc.target/aarch64/adds.c: New test. * gcc/testsuite/gcc.target/aarch64/subs.c: New test. ------------------------------------------------ diff --git a/gcc/config/aarch64/aarch64.md b/gcc/config/aarch64/aarch64.md index e6086a9..6935192 100644 --- a/gcc/config/aarch64/aarch64.md +++ b/gcc/config/aarch64/aarch64.md @@ -1310,6 +1310,17 @@ (set_attr "mode" "<MODE>")] ) +(define_insn "*compare_neg<mode>" + [(set (reg:CC CC_REGNUM) + (compare:CC + (match_operand:GPI 0 "register_operand" "r") + (neg:GPI (match_operand:GPI 1 "register_operand" "r"))))] + "" + "cmn\\t%<w>0, %<w>1" + [(set_attr "v8type" "alus") + (set_attr "mode" "<MODE>")] +) + (define_insn "*add_<shift>_<mode>" [(set (match_operand:GPI 0 "register_operand" "=rk") (plus:GPI (ASHIFT:GPI (match_operand:GPI 1 "register_operand" "r") diff --git a/gcc/testsuite/gcc.target/aarch64/adds.c b/gcc/testsuite/gcc.target/aarch64/adds.c new file mode 100644 index 0000000..aa42321 --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/adds.c @@ -0,0 +1,30 @@ +/* { dg-do compile } */ +/* { dg-options "-O2" } */ + +int z; +int +foo (int x, int y) +{ + int l = x + y; + if (l == 0) + return 5; + + /* { dg-final { scan-assembler "adds\tw\[0-9\]" } } */ + z = l ; + return 25; +} + +typedef long long s64; + +s64 zz; +s64 +foo2 (s64 x, s64 y) +{ + s64 l = x + y; + if (l < 0) + return 5; + + /* { dg-final { scan-assembler "adds\tx\[0-9\]" } } */ + zz = l ; + return 25; +} diff --git a/gcc/testsuite/gcc.target/aarch64/cmn.c b/gcc/testsuite/gcc.target/aarch64/cmn.c new file mode 100644 index 0000000..1f06f57 --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/cmn.c @@ -0,0 +1,24 @@ +/* { dg-do compile } */ +/* { dg-options "-O2" } */ + +int +foo (int a, int b) +{ + if (a + b) + return 5; + else + return 2; + /* { dg-final { scan-assembler "cmn\tw\[0-9\]" } } */ +} + +typedef long long s64; + +s64 +foo2 (s64 a, s64 b) +{ + if (a + b) + return 5; + else + return 2; + /* { dg-final { scan-assembler "cmn\tx\[0-9\]" } } */ +} diff --git a/gcc/testsuite/gcc.target/aarch64/subs.c b/gcc/testsuite/gcc.target/aarch64/subs.c new file mode 100644 index 0000000..2bf1975 --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/subs.c @@ -0,0 +1,30 @@ +/* { dg-do compile } */ +/* { dg-options "-O2" } */ + +int z; +int +foo (int x, int y) +{ + int l = x - y; + if (l == 0) + return 5; + + /* { dg-final { scan-assembler "subs\tw\[0-9\]" } } */ + z = l ; + return 25; +} + +typedef long long s64; + +s64 zz; +s64 +foo2 (s64 x, s64 y) +{ + s64 l = x - y; + if (l < 0) + return 5; + + /* { dg-final { scan-assembler "subs\tx\[0-9\]" } } */ + zz = l ; + return 25; +}