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.

Bootstrapped and tested on aarch64-none-linux-gnu.
Ok for trunk?
Thanks,
Kyrill

gcc/

        PR middle-end/109832
        * ccmp.cc (ccmp_tree_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.

Signed-off-by: Kyrylo Tkachov <[email protected]>
---
 gcc/ccmp.cc                               | 24 ++++++++++++
 gcc/testsuite/gcc.target/aarch64/ccmp_7.c | 46 +++++++++++++++++++++++
 2 files changed, 70 insertions(+)
 create mode 100644 gcc/testsuite/gcc.target/aarch64/ccmp_7.c

diff --git a/gcc/ccmp.cc b/gcc/ccmp.cc
index 1c540f641b2..9f7670bf58e 100644
--- a/gcc/ccmp.cc
+++ b/gcc/ccmp.cc
@@ -93,6 +93,25 @@ ccmp_tree_comparison_p (tree t, basic_block bb)
 
 typedef hash_map<tree, bool> ccmp_uniform_cache;
 
+/* Return true if AND/IOR tree T contains a comparison in BB.  */
+
+static bool
+ccmp_tree_has_comparison_p (tree t, basic_block bb)
+{
+  gimple *g = get_gimple_for_ssa_name (t);
+  if (!g || !is_gimple_assign (g))
+    return false;
+
+  tree_code code = gimple_assign_rhs_code (g);
+  if (TREE_CODE_CLASS (code) == tcc_comparison)
+    return gimple_bb (g) == bb;
+  if (code != BIT_AND_EXPR && code != BIT_IOR_EXPR)
+    return false;
+
+  return (ccmp_tree_has_comparison_p (gimple_assign_rhs1 (g), bb)
+         || ccmp_tree_has_comparison_p (gimple_assign_rhs2 (g), bb));
+}
+
 /* Return true if T is a CODE tree in BB whose leaves are comparisons.
    CACHE records results for logical SSA definitions.  */
 
@@ -368,6 +387,11 @@ expand_ccmp_expr (gimple *g, machine_mode mode)
   if (!ccmp_candidate_p (g, cache, true))
     return NULL_RTX;
 
+  basic_block bb = gimple_bb (g);
+  if (!ccmp_tree_has_comparison_p (gimple_assign_rhs1 (g), bb)
+      && !ccmp_tree_has_comparison_p (gimple_assign_rhs2 (g), bb))
+    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..29e269b854e
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/ccmp_7.c
@@ -0,0 +1,46 @@
+/* { 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);
+}
+
+/* One explicit comparison is enough to keep each chain profitable.  */
+
+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} 3 } } */
+/* { dg-final { scan-assembler-times {\torr\t} 5 } } */
-- 
2.50.1 (Apple Git-155)

Reply via email to