[RTL-ifcvt] Improve conditional select ops on immediates
authorKyrylo Tkachov <kyrylo.tkachov@arm.com>
Mon, 3 Aug 2015 08:14:42 +0000 (08:14 +0000)
committerKyrylo Tkachov <ktkachov@gcc.gnu.org>
Mon, 3 Aug 2015 08:14:42 +0000 (08:14 +0000)
* ifcvt.c (noce_try_store_flag_constants): Make logic of the case
when diff == STORE_FLAG_VALUE or diff == -STORE_FLAG_VALUE more
explicit.  Prefer to add the flag whenever possible.
(noce_process_if_block): Try noce_try_store_flag_constants before
noce_try_cmove.

* gcc.target/aarch64/csel_bfx_1.c: New test.
* gcc.target/aarch64/csel_imms_inc_1.c: Likewise.

From-SVN: r226491

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

index 3a3012a89e5ad8054ec5b1fdbdaae8014757c430..dac24ddd44f8995267fa3aa9b7a0e810b32de335 100644 (file)
@@ -1,3 +1,11 @@
+2015-08-03  Kyrylo Tkachov  <kyrylo.tkachov@arm.com>
+
+       * ifcvt.c (noce_try_store_flag_constants): Make logic of the case
+       when diff == STORE_FLAG_VALUE or diff == -STORE_FLAG_VALUE more
+       explicit.  Prefer to add the flag whenever possible.
+       (noce_process_if_block): Try noce_try_store_flag_constants before
+       noce_try_cmove.
+
 2015-08-03  Richard Biener  <rguenther@suse.de>
 
        * genmatch.c (struct sinfo, struct sinfo_hashmap_traits, sinfo_map_t):
index 2d97cc578453a0eb50f38180830950b41a76b140..1f2964651f8af7a430a3bd565e4d3bec0c542e5a 100644 (file)
@@ -1159,9 +1159,10 @@ noce_try_store_flag_constants (struct noce_if_info *if_info)
 {
   rtx target;
   rtx_insn *seq;
-  int reversep;
+  bool reversep;
   HOST_WIDE_INT itrue, ifalse, diff, tmp;
-  int normalize, can_reverse;
+  int normalize;
+  bool can_reverse;
   machine_mode mode;
 
   if (CONST_INT_P (if_info->a)
@@ -1170,6 +1171,7 @@ noce_try_store_flag_constants (struct noce_if_info *if_info)
       mode = GET_MODE (if_info->x);
       ifalse = INTVAL (if_info->a);
       itrue = INTVAL (if_info->b);
+      bool subtract_flag_p = false;
 
       diff = (unsigned HOST_WIDE_INT) itrue - ifalse;
       /* Make sure we can represent the difference between the two values.  */
@@ -1182,23 +1184,61 @@ noce_try_store_flag_constants (struct noce_if_info *if_info)
       can_reverse = (reversed_comparison_code (if_info->cond, if_info->jump)
                     != UNKNOWN);
 
-      reversep = 0;
+      reversep = false;
       if (diff == STORE_FLAG_VALUE || diff == -STORE_FLAG_VALUE)
-       normalize = 0;
+       {
+         normalize = 0;
+         /* We could collapse these cases but it is easier to follow the
+            diff/STORE_FLAG_VALUE combinations when they are listed
+            explicitly.  */
+
+         /* test ? 3 : 4
+            => 4 + (test != 0).  */
+         if (diff < 0 && STORE_FLAG_VALUE < 0)
+             reversep = false;
+         /* test ? 4 : 3
+            => can_reverse  | 4 + (test == 0)
+               !can_reverse | 3 - (test != 0).  */
+         else if (diff > 0 && STORE_FLAG_VALUE < 0)
+           {
+             reversep = can_reverse;
+             subtract_flag_p = !can_reverse;
+           }
+         /* test ? 3 : 4
+            => can_reverse  | 3 + (test == 0)
+               !can_reverse | 4 - (test != 0).  */
+         else if (diff < 0 && STORE_FLAG_VALUE > 0)
+           {
+             reversep = can_reverse;
+             subtract_flag_p = !can_reverse;
+           }
+         /* test ? 4 : 3
+            => 4 + (test != 0).  */
+         else if (diff > 0 && STORE_FLAG_VALUE > 0)
+           reversep = false;
+         else
+           gcc_unreachable ();
+       }
       else if (ifalse == 0 && exact_log2 (itrue) >= 0
               && (STORE_FLAG_VALUE == 1
                   || if_info->branch_cost >= 2))
        normalize = 1;
       else if (itrue == 0 && exact_log2 (ifalse) >= 0 && can_reverse
               && (STORE_FLAG_VALUE == 1 || if_info->branch_cost >= 2))
-       normalize = 1, reversep = 1;
+       {
+         normalize = 1;
+         reversep = true;
+       }
       else if (itrue == -1
               && (STORE_FLAG_VALUE == -1
                   || if_info->branch_cost >= 2))
        normalize = -1;
       else if (ifalse == -1 && can_reverse
               && (STORE_FLAG_VALUE == -1 || if_info->branch_cost >= 2))
-       normalize = -1, reversep = 1;
+       {
+         normalize = -1;
+         reversep = true;
+       }
       else if ((if_info->branch_cost >= 2 && STORE_FLAG_VALUE == -1)
               || if_info->branch_cost >= 3)
        normalize = -1;
@@ -1223,9 +1263,9 @@ noce_try_store_flag_constants (struct noce_if_info *if_info)
         =>   x = 3 + (test == 0);  */
       if (diff == STORE_FLAG_VALUE || diff == -STORE_FLAG_VALUE)
        {
-         target = expand_simple_binop (mode,
-                                       (diff == STORE_FLAG_VALUE
-                                        ? PLUS : MINUS),
+         /* 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);
        }
@@ -2731,13 +2771,14 @@ noce_process_if_block (struct noce_if_info *if_info)
     goto success;
   if (noce_try_abs (if_info))
     goto success;
+  if (!targetm.have_conditional_execution ()
+      && noce_try_store_flag_constants (if_info))
+    goto success;
   if (HAVE_conditional_move
       && noce_try_cmove (if_info))
     goto success;
   if (! targetm.have_conditional_execution ())
     {
-      if (noce_try_store_flag_constants (if_info))
-       goto success;
       if (noce_try_addcc (if_info))
        goto success;
       if (noce_try_store_flag_mask (if_info))
index 55bfb355cd850e7dba59100e131a2df08b7837f9..640289c2c4d1eaa40eea4b6bbb9f9dc0a26c3569 100644 (file)
@@ -1,3 +1,8 @@
+2015-08-03  Kyrylo Tkachov  <kyrylo.tkachov@arm.com>
+
+       * gcc.target/aarch64/csel_bfx_1.c: New test.
+       * gcc.target/aarch64/csel_imms_inc_1.c: Likewise.
+
 2015-08-02  Martin Sebor  <msebor@redhat.com>
 
         * g++.dg/Wframe-address-in-Wall.C: New test.
diff --git a/gcc/testsuite/gcc.target/aarch64/csel_bfx_1.c b/gcc/testsuite/gcc.target/aarch64/csel_bfx_1.c
new file mode 100644 (file)
index 0000000..c20597f
--- /dev/null
@@ -0,0 +1,11 @@
+/* { dg-do compile } */
+/* { dg-options "-save-temps -O2" } */
+
+int
+foo (int a, int b)
+{
+  return ((a & (1 << 25)) ? 5 : 4);
+}
+
+/* { dg-final { scan-assembler "ubfx\t\[xw\]\[0-9\]*.*" } } */
+/* { dg-final { scan-assembler-not "csel\tw\[0-9\]*.*" } } */
diff --git a/gcc/testsuite/gcc.target/aarch64/csel_imms_inc_1.c b/gcc/testsuite/gcc.target/aarch64/csel_imms_inc_1.c
new file mode 100644 (file)
index 0000000..2ae434d
--- /dev/null
@@ -0,0 +1,42 @@
+/* { dg-do run } */
+/* { dg-options "-save-temps -O2 -fno-inline" } */
+
+extern void abort (void);
+
+int
+fooinc (int x)
+{
+  if (x)
+    return 1025;
+  else
+    return 1026;
+}
+
+int
+fooinc2 (int x)
+{
+  if (x)
+    return 1026;
+  else
+    return 1025;
+}
+
+int
+main (void)
+{
+  if (fooinc (0) != 1026)
+    abort ();
+
+  if (fooinc (1) != 1025)
+    abort ();
+
+  if (fooinc2 (0) != 1025)
+    abort ();
+
+  if (fooinc2 (1) != 1026)
+    abort ();
+
+  return 0;
+}
+
+/* { dg-final { scan-assembler-not "csel\tw\[0-9\]*.*" } } */