[RTL-ifcvt] Allow PLUS+immediate expression in noce_try_store_flag_constants
authorKyrylo Tkachov <kyrylo.tkachov@arm.com>
Thu, 13 Aug 2015 17:06:14 +0000 (17:06 +0000)
committerKyrylo Tkachov <ktkachov@gcc.gnu.org>
Thu, 13 Aug 2015 17:06:14 +0000 (17:06 +0000)
* ifcvt.c (noce_try_store_flag_constants): Handle PLUS-immediate
expressions in A and B.

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

From-SVN: r226869

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

index 477335dfb600df51f1caf3a2be9ed9dc24e09168..f3262e5452ef13865b9ffda0010763fd304d7b7c 100644 (file)
@@ -1,3 +1,8 @@
+2015-08-13  Kyrylo Tkachov  <kyrylo.tkachov@arm.com>
+
+       * ifcvt.c (noce_try_store_flag_constants): Handle PLUS-immediate
+       expressions in A and B.
+
 2015-08-13  Richard Biener  <rguenther@suse.de>
 
        * tree.c (nonnull_arg_p): Move from ...
index 9b6f6821ce6f0a81269a6e77530a1ce4c9827d8f..a46efec605958453db941896262306f10fc937b0 100644 (file)
@@ -1152,7 +1152,9 @@ noce_try_store_flag (struct noce_if_info *if_info)
     }
 }
 
-/* Convert "if (test) x = a; else x = b", for A and B constant.  */
+/* 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
+   and B.  */
 
 static int
 noce_try_store_flag_constants (struct noce_if_info *if_info)
@@ -1163,14 +1165,31 @@ noce_try_store_flag_constants (struct noce_if_info *if_info)
   HOST_WIDE_INT itrue, ifalse, diff, tmp;
   int normalize;
   bool can_reverse;
-  machine_mode mode;
+  machine_mode mode = GET_MODE (if_info->x);;
+  rtx common = NULL_RTX;
+
+  rtx a = if_info->a;
+  rtx b = if_info->b;
+
+  /* Handle cases like x := test ? y + 3 : y + 4.  */
+  if (GET_CODE (a) == PLUS
+      && GET_CODE (b) == PLUS
+      && CONST_INT_P (XEXP (a, 1))
+      && CONST_INT_P (XEXP (b, 1))
+      && rtx_equal_p (XEXP (a, 0), XEXP (b, 0))
+      && noce_operand_ok (XEXP (a, 0))
+      && if_info->branch_cost >= 2)
+    {
+      common = XEXP (a, 0);
+      a = XEXP (a, 1);
+      b = XEXP (b, 1);
+    }
 
-  if (CONST_INT_P (if_info->a)
-      && CONST_INT_P (if_info->b))
+  if (CONST_INT_P (a)
+      && CONST_INT_P (b))
     {
-      mode = GET_MODE (if_info->x);
-      ifalse = INTVAL (if_info->a);
-      itrue = INTVAL (if_info->b);
+      ifalse = INTVAL (a);
+      itrue = INTVAL (b);
       bool subtract_flag_p = false;
 
       diff = (unsigned HOST_WIDE_INT) itrue - ifalse;
@@ -1203,6 +1222,11 @@ noce_try_store_flag_constants (struct noce_if_info *if_info)
            {
              reversep = can_reverse;
              subtract_flag_p = !can_reverse;
+             /* If we need to subtract the flag and we have PLUS-immediate
+                A and B then it is unlikely to be beneficial to play tricks
+                here.  */
+             if (subtract_flag_p && common)
+               return FALSE;
            }
          /* test ? 3 : 4
             => can_reverse  | 3 + (test == 0)
@@ -1211,6 +1235,11 @@ noce_try_store_flag_constants (struct noce_if_info *if_info)
            {
              reversep = can_reverse;
              subtract_flag_p = !can_reverse;
+             /* If we need to subtract the flag and we have PLUS-immediate
+                A and B then it is unlikely to be beneficial to play tricks
+                here.  */
+             if (subtract_flag_p && common)
+               return FALSE;
            }
          /* test ? 4 : 3
             => 4 + (test != 0).  */
@@ -1249,6 +1278,15 @@ noce_try_store_flag_constants (struct noce_if_info *if_info)
        }
 
       start_sequence ();
+
+      /* If we have x := test ? x + 3 : x + 4 then move the original
+        x out of the way while we store flags.  */
+      if (common && rtx_equal_p (common, if_info->x))
+       {
+         common = gen_reg_rtx (mode);
+         noce_emit_move_insn (common, if_info->x);
+       }
+
       target = noce_emit_store_flag (if_info, if_info->x, reversep, normalize);
       if (! target)
        {
@@ -1260,13 +1298,27 @@ noce_try_store_flag_constants (struct noce_if_info *if_info)
         =>   x = 3 + (test == 0);  */
       if (diff == STORE_FLAG_VALUE || diff == -STORE_FLAG_VALUE)
        {
+         /* Add the common part now.  This may allow combine to merge this
+            with the store flag operation earlier into some sort of conditional
+            increment/decrement if the target allows it.  */
+         if (common)
+           target = expand_simple_binop (mode, PLUS,
+                                          target, common,
+                                          target, 0, OPTAB_WIDEN);
+
          /* Always use ifalse here.  It should have been swapped with itrue
             when appropriate when reversep is true.  */
          target = expand_simple_binop (mode, subtract_flag_p ? MINUS : PLUS,
                                        gen_int_mode (ifalse, mode), target,
                                        if_info->x, 0, OPTAB_WIDEN);
        }
-
+      /* Other cases are not beneficial when the original A and B are PLUS
+        expressions.  */
+      else if (common)
+       {
+         end_sequence ();
+         return FALSE;
+       }
       /* if (test) x = 8; else x = 0;
         =>   x = (test != 0) << 3;  */
       else if (ifalse == 0 && (tmp = exact_log2 (itrue)) >= 0)
index ef2d567f64eb7b054811a6fa797573e28715a26d..4561032457bcec1fff4746d7121520ade4c7cf77 100644 (file)
@@ -1,3 +1,7 @@
+2015-08-13  Kyrylo Tkachov  <kyrylo.tkachov@arm.com>
+
+       * gcc.target/aarch64/cinc_common_1.c: New test.
+
 2015-08-13  Paolo Carlini  <paolo.carlini@oracle.com>
 
        PR c++/53421
diff --git a/gcc/testsuite/gcc.target/aarch64/cinc_common_1.c b/gcc/testsuite/gcc.target/aarch64/cinc_common_1.c
new file mode 100644 (file)
index 0000000..d041263
--- /dev/null
@@ -0,0 +1,64 @@
+/* { dg-do run } */
+/* { dg-options "-save-temps -O2 -fno-inline" } */
+
+extern void abort (void);
+
+int
+foosi (int x)
+{
+  return x > 100 ? x - 2 : x - 1;
+}
+
+int
+barsi (int x)
+{
+  return x > 100 ? x + 4 : x + 3;
+}
+
+long
+foodi (long x)
+{
+  return x > 100 ? x - 2 : x - 1;
+}
+
+long
+bardi (long x)
+{
+  return x > 100 ? x + 4 : x + 3;
+}
+
+/* { dg-final { scan-assembler-times "cs?inc\tw\[0-9\]*" 2 } } */
+/* { dg-final { scan-assembler-times "cs?inc\tx\[0-9\]*" 2 } } */
+
+int
+main (void)
+{
+  if (foosi (105) != 103)
+    abort ();
+
+  if (foosi (95) != 94)
+    abort ();
+
+  if (barsi (105) != 109)
+    abort ();
+
+  if (barsi (95) != 98)
+    abort ();
+
+  if (foodi (105) != 103)
+    abort ();
+
+  if (foodi (95) != 94)
+    abort ();
+
+  if (bardi (105) != 109)
+    abort ();
+
+  if (bardi (95) != 98)
+    abort ();
+
+  return 0;
+}
+
+/* { dg-final { scan-assembler-not "csel\tx\[0-9\]*.*" } } */
+/* { dg-final { scan-assembler-not "csel\tw\[0-9\]*.*" } } */