Hi all,

The noce_convert_multiple_sets transformation in ifcvt is supposed to handle 
things like:
     if (x > y)
       { i = a; j = b; }

transforming them into conditional moves.
However it currently is rather conservative in that it allows only simple 
reg-to-reg moves.
In the testcase in this patch the two inner moves actually contain a simple 
sugreg like so:

(insn 51 68 52 6 (set (reg/v:SI 118 [ posD.2788 ])
        (subreg:SI (reg:DI 125 [ ivtmp.4D.2805 ]) 0)) x.c:12 49 {*movsi_aarch64}
     (expr_list:REG_DEAD (reg/v:SI 122 [ iD.2789 ])
        (nil)))

(insn 52 51 69 6 (set (reg/v:SI 116 [ mincostD.2787 ])
        (reg/v:SI 119 [ minD.2786 ])) x.c:12 49 {*movsi_aarch64}
     (expr_list:REG_DEAD (reg/v:SI 119 [ minD.2786 ])
        (nil)))

noce_convert_multiple_sets can handle these just fine when emitting the 
conditional moves.
The gating function bb_ok_for_noce_multiple_sets just needs to allow it through.
This patch does that by relaxing the check a bit to allow simple register 
subregs.
Note that noce_convert_multiple_sets calls recog on the result of the 
conditional move generation
and bails out if something has gone wrong, so this shouldn't result in any 
unrecognisable instructions
being emitted.

With this patch I see 3 more cases being if-converted in SPECINT 2006 with no 
regression in the overall score
(or any individual sub-benchmarks).

Bootstrapped and tested on arm, aarch64 and x86_64.

Ok for trunk?

Thanks,
Kyrill


2016-06-14  Kyrylo Tkachov  <kyrylo.tkac...@arm.com>

    * ifcvt.c (bb_ok_for_noce_multiple_sets): Allow simple lowpart
    register subregs in SET_SRC.

2016-06-14  Kyrylo Tkachov  <kyrylo.tkac...@arm.com>

    * gcc.target/aarch64/ifcvt_multiple_sets_subreg_1.c: New test.
diff --git a/gcc/ifcvt.c b/gcc/ifcvt.c
index 4a277db7dcc4cd467299419b21bae0f2a2b42926..fd2951673fb6bd6d9e5d52cdb88765434a603fb6 100644
--- a/gcc/ifcvt.c
+++ b/gcc/ifcvt.c
@@ -3339,9 +3339,15 @@ bb_ok_for_noce_convert_multiple_sets (basic_block test_bb,
       rtx src = SET_SRC (set);
 
       /* We can possibly relax this, but for now only handle REG to REG
-	 moves.  This avoids any issues that might come from introducing
-	 loads/stores that might violate data-race-freedom guarantees.  */
-      if (!(REG_P (src) && REG_P (dest)))
+	 (including subreg) moves.  This avoids any issues that might come
+	 from introducing loads/stores that might violate data-race-freedom
+	 guarantees.  */
+      if (!REG_P (dest))
+	return false;
+
+      if (!(REG_P (src)
+	   || (GET_CODE (src) == SUBREG && REG_P (SUBREG_REG (src))
+	       && subreg_lowpart_p (src))))
 	return false;
 
       /* Destination must be appropriate for a conditional write.  */
diff --git a/gcc/testsuite/gcc.target/aarch64/ifcvt_multiple_sets_subreg_1.c b/gcc/testsuite/gcc.target/aarch64/ifcvt_multiple_sets_subreg_1.c
new file mode 100644
index 0000000000000000000000000000000000000000..ac6ffdcf8de0d0f18274378f6c21b760f19781a4
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/ifcvt_multiple_sets_subreg_1.c
@@ -0,0 +1,30 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-rtl-ce1" } */
+
+/* Check that the inner if is transformed into CSELs.  */
+
+int
+foo (int *x, int *z, int a)
+{
+  int b = 0;
+  int c = 0;
+  int d = 0;
+  int i;
+
+  for (i = 0; i < a; i++)
+    {
+      if (x[i] < c)
+	{
+	  b = z[i];
+	  if (c < b)
+	    {
+	      c = b;
+	      d = i;
+	    }
+	}
+    }
+
+  return c + d;
+}
+
+/* { dg-final { scan-rtl-dump "if-conversion succeeded through noce_convert_multiple_sets" "ce1" } } */

Reply via email to