From: Kyrylo Tkachov <[email protected]>
The conditional-compare expander accepts a plain boolean as a comparison
against zero. This is useful when a chain also contains an explicit
comparison. It is harmful when every leaf is a boolean. For example:
_Bool
f (_Bool x, _Bool y)
{
return x || y;
}
AArch64 emitted:
and w1, w1, 255
tst w0, 255
ccmp w1, 0, 0, eq
cset w0, ne
After this patch it emits one bitwise operation:
orr w0, w0, w1
Require at least one explicit comparison in a conditional-compare tree.
Mixed boolean and comparison chains remain accepted. Every statement of a
candidate has a leaf operand, so the candidate is a chain and the check
walks it with a loop.
Bootstrapped and tested on aarch64-none-linux-gnu.
Ok for trunk?
Thanks,
Kyrill
gcc/
PR middle-end/109832
* ccmp.cc (ccmp_has_comparison_p): New function.
(expand_ccmp_expr): Reject an all-boolean tree.
gcc/testsuite/
PR middle-end/109832
* gcc.target/aarch64/ccmp_7.c: New test.
* gcc.target/aarch64/ccmp_9.c: Likewise.
Signed-off-by: Kyrylo Tkachov <[email protected]>
---
gcc/ccmp.cc | 34 ++++++++++++++++++++
gcc/testsuite/gcc.target/aarch64/ccmp_7.c | 38 +++++++++++++++++++++++
gcc/testsuite/gcc.target/aarch64/ccmp_9.c | 14 +++++++++
3 files changed, 86 insertions(+)
create mode 100644 gcc/testsuite/gcc.target/aarch64/ccmp_7.c
create mode 100644 gcc/testsuite/gcc.target/aarch64/ccmp_9.c
diff --git a/gcc/ccmp.cc b/gcc/ccmp.cc
index 0564ccf34bf..d35e05ec375 100644
--- a/gcc/ccmp.cc
+++ b/gcc/ccmp.cc
@@ -90,6 +90,35 @@ ccmp_tree_comparison_p (tree t, basic_block bb)
If all checks OK in expand_ccmp_expr, it emits insns in prep_seq, then
insns in gen_seq. */
+/* Return true if candidate G in BB has a comparison to fold into the
+ condition flags. Every statement of a candidate has a leaf operand, so
+ the candidate is a chain and this walks it down to its innermost
+ statement. A leaf that has a defining statement is a comparison, the
+ other leaves are booleans that expand to a comparison against zero. */
+
+static bool
+ccmp_has_comparison_p (gimple *g, basic_block bb)
+{
+ do
+ {
+ tree op0 = gimple_assign_rhs1 (g);
+ tree op1 = gimple_assign_rhs2 (g);
+ bool leaf0 = ccmp_tree_comparison_p (op0, bb);
+ bool leaf1 = ccmp_tree_comparison_p (op1, bb);
+
+ gcc_checking_assert (leaf0 || leaf1);
+
+ if ((leaf0 && get_gimple_for_ssa_name (op0))
+ || (leaf1 && get_gimple_for_ssa_name (op1)))
+ return true;
+
+ g = get_gimple_for_ssa_name (leaf0 ? op1 : op0);
+ }
+ while (g);
+
+ return false;
+}
+
/* Check whether G is a potential conditional compare candidate; OUTER is true
if
G is the outer most AND/IOR. */
static bool
@@ -294,6 +323,11 @@ expand_ccmp_expr (gimple *g, machine_mode mode)
if (!ccmp_candidate_p (g, true))
return NULL_RTX;
+ /* A conditional compare folds a comparison into the flags. Without a
+ comparison to fold the bitwise operation is cheaper. */
+ if (!ccmp_has_comparison_p (g, gimple_bb (g)))
+ return NULL_RTX;
+
last = get_last_insn ();
rtx_insn *prep_seq = NULL, *gen_seq = NULL;
diff --git a/gcc/testsuite/gcc.target/aarch64/ccmp_7.c
b/gcc/testsuite/gcc.target/aarch64/ccmp_7.c
new file mode 100644
index 00000000000..d9c75eb6b0b
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/ccmp_7.c
@@ -0,0 +1,38 @@
+/* { dg-do compile } */
+/* { dg-options "-O2" } */
+/* PR middle-end/109832 */
+
+/* A conditional compare folds a comparison into the flags. When the operands
+ are plain booleans there is no comparison to fold and the bitwise operation
+ is cheaper, so no conditional compare should be formed. */
+
+_Bool
+bool_ior (_Bool x, _Bool y)
+{
+ return x || y;
+}
+
+_Bool
+bool_and (_Bool x, _Bool y)
+{
+ return x && y;
+}
+
+extern _Bool t (void);
+
+_Bool
+bool_call_ior (void)
+{
+ _Bool x = t ();
+ _Bool y = t ();
+ return x | y;
+}
+
+_Bool
+bool_ior_tree (_Bool a, _Bool b, _Bool c, _Bool d)
+{
+ return (a | b) | (c | d);
+}
+
+/* { dg-final { scan-assembler-not {\tccmp\t} } } */
+/* { dg-final { scan-assembler-times {\torr\tw[0-9]+, w[0-9]+, w[0-9]+} 5 } }
*/
diff --git a/gcc/testsuite/gcc.target/aarch64/ccmp_9.c
b/gcc/testsuite/gcc.target/aarch64/ccmp_9.c
new file mode 100644
index 00000000000..4f95ddf53c1
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/ccmp_9.c
@@ -0,0 +1,14 @@
+/* { dg-do compile } */
+/* { dg-options "-O2" } */
+/* PR middle-end/109832 */
+
+/* One explicit comparison is enough for a chain to be worth a conditional
+ compare, so the boolean operands become a compare against zero. */
+
+int
+bool_and_cmp_tree (_Bool a, _Bool b, _Bool c, int x, int y)
+{
+ return ((a & b) & c) & (x < y);
+}
+
+/* { dg-final { scan-assembler-times {\tccmp\t} 1 } } */
--
2.50.1 (Apple Git-155)