[PATCH 6/6] ccmp: Put a constant comparison at the head of a chain

<[email protected]>
Newsgroups gmane.comp.gcc.patches
Message-ID <[email protected]>
From: Kyrylo Tkachov <[email protected]>

Only the first comparison in a conditional-compare sequence is plain.  On
AArch64, FCMP accepts zero directly but FCCMP does not.  For example, with
-O2 -ffinite-math-only:

  int
  f (double a, double b, double c, double d, double e)
  {
    return (e < 0.0) & (a < b) & (c < d);
  }

The normal expansion order materialises zero:

	fcmp	d0, d1
	movi	d31, #0
	fccmp	d2, d3, 0, mi
	fccmp	d4, d31, 0, mi
	cset	w0, mi

Putting the zero comparison first removes that materialisation:

	fcmp	d4, #0.0
	fccmp	d0, d1, 0, mi
	fccmp	d2, d3, 0, mi
	cset	w0, mi

For a root that joins a constant leaf to a uniform tree, build one complete
constant-first alternative.  Use it only if the normal order fails or the
target costs show that the complete alternative is cheaper.  Keep the normal
order when the costs are equal.  Trying at most one extra order keeps the
additional target expansion linear and needs no arbitrary threshold.

The tests also cover integer immediates and verify that an equal-cost small
immediate does not displace a more useful large constant.

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

gcc/

	* ccmp.cc (expand_ccmp_constant_first): New function.
	(expand_ccmp_expr): Cost one constant-first root alternative.

gcc/testsuite/

	* gcc.target/aarch64/ccmp_8.c: New test.

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

diff --git a/gcc/ccmp.cc b/gcc/ccmp.cc
index 9f7670bf58e..00aa32f74a4 100644
--- a/gcc/ccmp.cc
+++ b/gcc/ccmp.cc
@@ -374,6 +374,38 @@ expand_ccmp_expr_1 (gimple *g, rtx_insn **prep_seq, rtx_insn **gen_seq,
     }
 }
 
+/* Try to put a constant leaf of root G before its uniform tree operand.
+   Return the resulting comparison and set PREP_SEQ and GEN_SEQ, or return
+   NULL_RTX if the root has no such leaf or expansion fails.  */
+
+static rtx
+expand_ccmp_constant_first (gimple *g, ccmp_uniform_cache &cache,
+			    rtx_insn **prep_seq, rtx_insn **gen_seq)
+{
+  tree_code code = gimple_assign_rhs_code (g);
+  basic_block bb = gimple_bb (g);
+  tree leaf = gimple_assign_rhs1 (g);
+  tree tree_op = gimple_assign_rhs2 (g);
+  if (!ccmp_tree_comparison_p (leaf, bb))
+    std::swap (leaf, tree_op);
+  if (ccmp_tree_comparison_p (tree_op, bb))
+    return NULL_RTX;
+
+  gimple *leaf_stmt = get_gimple_for_ssa_name (leaf);
+  if (!leaf_stmt
+      || !CONSTANT_CLASS_P (gimple_assign_rhs2 (leaf_stmt))
+      || !ccmp_uniform_chain_p (tree_op, code, bb, cache))
+    return NULL_RTX;
+
+  rtx_code rcode;
+  tree rhs1, rhs2;
+  get_compare_parts (leaf, &rcode, &rhs1, &rhs2);
+  rtx prev = targetm.gen_ccmp_first (prep_seq, gen_seq, rcode, rhs1, rhs2);
+  if (!prev)
+    return NULL_RTX;
+  return expand_ccmp_chain (tree_op, code, prev, prep_seq, gen_seq);
+}
+
 /* Main entry to expand conditional compare statement G.
    Return NULL_RTX if G is not a legal candidate or expand fail.
    Otherwise return the target.  */
@@ -397,6 +429,24 @@ expand_ccmp_expr (gimple *g, machine_mode mode)
   rtx_insn *prep_seq = NULL, *gen_seq = NULL;
   tmp = expand_ccmp_expr_1 (g, &prep_seq, &gen_seq, cache);
 
+  rtx_insn *constant_prep = NULL, *constant_gen = NULL;
+  rtx constant = expand_ccmp_constant_first (g, cache, &constant_prep,
+					     &constant_gen);
+  if (constant)
+    {
+      int speed_p = optimize_insn_for_speed_p ();
+      unsigned constant_cost = seq_cost (constant_prep, speed_p);
+      constant_cost += seq_cost (constant_gen, speed_p);
+      if (!tmp
+	  || constant_cost < (seq_cost (prep_seq, speed_p)
+			      + seq_cost (gen_seq, speed_p)))
+	{
+	  tmp = constant;
+	  prep_seq = constant_prep;
+	  gen_seq = constant_gen;
+	}
+    }
+
   if (tmp)
     {
       insn_code icode;
diff --git a/gcc/testsuite/gcc.target/aarch64/ccmp_8.c b/gcc/testsuite/gcc.target/aarch64/ccmp_8.c
new file mode 100644
index 00000000000..12fb0299e7d
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/ccmp_8.c
@@ -0,0 +1,80 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -ffinite-math-only" } */
+/* { dg-final { check-function-bodies "**" "" } } */
+
+/* A plain comparison accepts constants that a conditional comparison can
+   reject.  Compare the complete sequence costs before moving a constant
+   comparison ahead of a uniform chain.  */
+
+/*
+** fp_first:
+**	fcmp	d4, #0\.0
+**	fccmp	d0, d1, 0, mi
+**	fccmp	d2, d3, 0, mi
+**	cset	w0, mi
+**	ret
+*/
+int
+fp_first (double a, double b, double c, double d, double e)
+{
+  return (e < 0.0) & (a < b) & (c < d);
+}
+
+/*
+** fp_last:
+**	fcmp	d4, #0\.0
+**	fccmp	d2, d3, 0, mi
+**	fccmp	d0, d1, 0, mi
+**	cset	w0, mi
+**	ret
+*/
+int
+fp_last (double a, double b, double c, double d, double e)
+{
+  return (a < b) & (c < d) & (e < 0.0);
+}
+
+/*
+** int_first:
+**	cmp	w4, 100
+**	ccmp	w0, w1, 0, eq
+**	ccmp	w2, w3, 0, lt
+**	cset	w0, lt
+**	ret
+*/
+int
+int_first (int a, int b, int c, int d, int e)
+{
+  return (e == 100) & (a < b) & (c < d);
+}
+
+/*
+** int_last:
+**	cmp	w4, 100
+**	ccmp	w2, w3, 0, eq
+**	ccmp	w0, w1, 0, lt
+**	cset	w0, lt
+**	ret
+*/
+int
+int_last (int a, int b, int c, int d, int e)
+{
+  return (a < b) & (c < d) & (e == 100);
+}
+
+/* Keep the large constant first when the root leaf is a cheaper CCMP
+   immediate.  */
+
+/*
+** int_two_constants:
+**	cmp	w0, 100
+**	ccmp	w1, w2, 0, eq
+**	ccmp	w3, 3, 0, lt
+**	cset	w0, eq
+**	ret
+*/
+int
+int_two_constants (int a, int b, int c, int d)
+{
+  return (a == 100) & (b < c) & (d == 3);
+}
-- 
2.50.1 (Apple Git-155)
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.