[RTL ifcvt] Transform (X == CST) ? -CST : Y into (X == CST) ? -X : Y when conditional...
authorKyrylo Tkachov <kyrylo.tkachov@arm.com>
Fri, 30 Sep 2016 08:28:09 +0000 (08:28 +0000)
committerKyrylo Tkachov <ktkachov@gcc.gnu.org>
Fri, 30 Sep 2016 08:28:09 +0000 (08:28 +0000)
        * ifcvt.c (noce_try_avoid_const_materialization): New function.
        (noce_process_if_block): Use it.

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

From-SVN: r240649

gcc/ChangeLog
gcc/ifcvt.c
gcc/testsuite/ChangeLog
gcc/testsuite/gcc.target/aarch64/ifcvt_avoid_const_materialization_1.c [new file with mode: 0644]

index 9be02e1d32278291436fc47dd182ad8a1c038696..8265a45f3cfb4d75f23ecc3354483bea8ec362a2 100644 (file)
@@ -1,3 +1,8 @@
+2016-09-30  Kyrylo Tkachov  <kyrylo.tkachov@arm.com>
+
+       * ifcvt.c (noce_try_avoid_const_materialization): New function.
+       (noce_process_if_block): Use it.
+
 2016-09-30  Martin Liska  <mliska@suse.cz>
 
        * doc/invoke.texi: Document asan-use-after-return that
index 24542f008485e6c28e068030fa301f2ce040efc1..203cfe98f82a49c35520a2cb16d2fa09d4c85c72 100644 (file)
@@ -1313,6 +1313,84 @@ noce_try_inverse_constants (struct noce_if_info *if_info)
   return false;
 }
 
+/* Try to avoid materializing a constant if we know it's in one of the
+   registers.  For example:
+   (X == CST) ? -CST : Y --> (X == CST) ? -X : Y.
+   Do this only if conditional negation is available.
+   Similar for bitwise NOT.  */
+
+static bool
+noce_try_avoid_const_materialization (struct noce_if_info *if_info)
+{
+  if (!noce_simple_bbs (if_info))
+    return false;
+
+  rtx cond = if_info->cond;
+  rtx a = if_info->a;
+  rtx b = if_info->b;
+  rtx_code code = GET_CODE (cond);
+  machine_mode mode = GET_MODE (if_info->x);
+
+  if (!(code == EQ || code == NE)
+      || !REG_P (XEXP (cond, 0))
+      || !REG_P (if_info->x)
+      || GET_MODE (XEXP (cond, 0)) != mode
+      || !CONST_INT_P (XEXP (cond, 1)))
+    return false;
+
+  rtx cst = XEXP (cond, 1);
+  if (cst == CONST0_RTX (mode))
+    return false;
+
+  rtx non_cst = XEXP (cond, 0);
+  rtx eq_side = code == EQ ? b : a;
+  if (!CONST_INT_P (eq_side))
+    return false;
+
+  HOST_WIDE_INT cstval = INTVAL (cst);
+  HOST_WIDE_INT eq_side_val = INTVAL (eq_side);
+
+  rtx_code op_code;
+  if (eq_side_val == ~cstval)
+    op_code = NOT;
+  else if (eq_side_val != HOST_WIDE_INT_MIN && (cstval == -eq_side_val))
+    op_code = NEG;
+  else
+    return false;
+
+  /* By the rules of the negcc/notcc optabs must happen when the COND is true,
+     in this case when register in COND is equal to CST so always set the
+     comparison to EQ.  */
+  if (code == NE)
+    {
+      a = non_cst;
+      cond = gen_rtx_fmt_ee (EQ, GET_MODE (cond), non_cst, cst);
+    }
+  else
+    b = non_cst;
+
+  start_sequence ();
+  rtx target
+    = emit_conditional_neg_or_complement (if_info->x, op_code, mode,
+                                          cond, a, b);
+  if (!target)
+    {
+      end_sequence ();
+      return false;
+    }
+
+  if (target != if_info->x)
+    noce_emit_move_insn (if_info->x, target);
+
+  rtx_insn *seq = end_ifcvt_sequence (if_info);
+  if (!seq)
+    return false;
+
+   emit_insn_before_setloc (seq, if_info->jump,
+                            INSN_LOCATION (if_info->insn_a));
+  if_info->transform_name = "noce_try_avoid_const_materialization";
+  return true;
+}
 
 /* Convert "if (test) x = a; else x = b", for A and B constant.
    Also allow A = y + c1, B = y + c2, with a common y between A
@@ -3606,6 +3684,8 @@ noce_process_if_block (struct noce_if_info *if_info)
     goto success;
   if (noce_try_inverse_constants (if_info))
     goto success;
+  if (noce_try_avoid_const_materialization (if_info))
+    goto success;
   if (!targetm.have_conditional_execution ()
       && noce_try_store_flag_constants (if_info))
     goto success;
index 7ea99619546582513ca516389be37c68776afc58..11fc7a8de85a61e519d7823c5fcff5bed873e134 100644 (file)
@@ -1,3 +1,7 @@
+2016-09-30  Kyrylo Tkachov  <kyrylo.tkachov@arm.com>
+
+       * gcc.target/aarch64/ifcvt_avoid_const_materialization_1.c: New test.
+
 2016-09-30  Richard Biener  <rguenther@suse.de>
 
        PR tree-optimization/77399
diff --git a/gcc/testsuite/gcc.target/aarch64/ifcvt_avoid_const_materialization_1.c b/gcc/testsuite/gcc.target/aarch64/ifcvt_avoid_const_materialization_1.c
new file mode 100644 (file)
index 0000000..b2a05ea
--- /dev/null
@@ -0,0 +1,22 @@
+/* { dg-do compile } */
+/* { dg-options "-O2" } */
+
+/* Check that we avoid moving the immediate into a register
+   if comparison has shown that the inverse or negated form is
+   already in one of the registers.  */
+
+int
+foo (int a, int b)
+{
+  return a == 5 ? -5 : b;
+}
+
+int
+bar (int a, int b)
+{
+  return a != 5 ? b : ~5;
+}
+
+/* { dg-final { scan-assembler-not "mov\\tw\[0-9\]+" } } */
+/* { dg-final { scan-assembler-times "csneg\\tw\[0-9\]+" 1 } } */
+/* { dg-final { scan-assembler-times "csinv\\tw\[0-9\]+" 1 } } */