diff mbox

[committed] Fix can_combine_p (PR target/80125)

Message ID 20170321145404.GV11094@tucnak
State New
Headers show

Commit Message

Jakub Jelinek March 21, 2017, 2:54 p.m. UTC
Hi!

As mentioned in the PR, combiner sometimes artificially splits a parallel
into two instructions, the first one not really in the insn stream, both
with the same uid and PREV_INSN (i1) == 0 and NEXT_INSN (i1) == i2.
In that case, calling reg_used_between_p (x, y, i1) crashes the compiler,
because it doesn't find i1 by walking from y forward.

Furthermore, the (succ2 && reg_used_between_p (dest, succ, succ2))
test has been already present, so no need to duplicate it.

Bootstrapped/regtested on powerpc64le-linux, approved on IRC by Segher,
committed to trunk.

2017-03-21  Jakub Jelinek  <jakub@redhat.com>
	    Segher Boessenkool  <segher@kernel.crashing.org>

	PR target/80125
	* combine.c (can_combine_p): Revert the 2017-03-20 change, only
	check reg_used_between_p between insn and one of succ or succ2
	depending on if succ is artificial insn not inserted into insn
	stream.

	* gcc.target/powerpc/pr80125.c: New test.


	Jakub
diff mbox

Patch

--- gcc/combine.c.jj	2017-03-21 07:57:01.000000000 +0100
+++ gcc/combine.c	2017-03-21 11:02:51.170746744 +0100
@@ -1954,15 +1954,20 @@  can_combine_p (rtx_insn *insn, rtx_insn
       /* Don't substitute into a non-local goto, this confuses CFG.  */
       || (JUMP_P (i3) && find_reg_note (i3, REG_NON_LOCAL_GOTO, NULL_RTX))
       /* Make sure that DEST is not used after INSN but before SUCC, or
-	 between SUCC and SUCC2.  */
-      || (succ && reg_used_between_p (dest, insn, succ))
-      || (succ2 && reg_used_between_p (dest, succ, succ2))
-      /* Make sure that DEST is not used after SUCC but before I3.  */
+	 after SUCC and before SUCC2, or after SUCC2 but before I3.  */
       || (!all_adjacent
 	  && ((succ2
 	       && (reg_used_between_p (dest, succ2, i3)
 		   || reg_used_between_p (dest, succ, succ2)))
-	      || (!succ2 && succ && reg_used_between_p (dest, succ, i3))))
+	      || (!succ2 && succ && reg_used_between_p (dest, succ, i3))
+	      || (succ
+		  /* SUCC and SUCC2 can be split halves from a PARALLEL; in
+		     that case SUCC is not in the insn stream, so use SUCC2
+		     instead for this test.  */
+		  && reg_used_between_p (dest, insn,
+					 succ2
+					 && INSN_UID (succ) == INSN_UID (succ2)
+					 ? succ2 : succ))))
       /* Make sure that the value that is to be substituted for the register
 	 does not use any registers whose values alter in between.  However,
 	 If the insns are adjacent, a use can't cross a set even though we
--- gcc/testsuite/gcc.target/powerpc/pr80125.c.jj	2017-03-21 10:23:31.409808224 +0100
+++ gcc/testsuite/gcc.target/powerpc/pr80125.c	2017-03-21 10:22:23.000000000 +0100
@@ -0,0 +1,23 @@ 
+/* PR target/80125 */
+/* { dg-do compile } */
+/* { dg-options "-O2 -maltivec" } */
+
+#include <altivec.h>
+
+int a[1];
+
+void
+foo ()
+{
+  vector int b, e, f, g, h, j, n;
+  vector unsigned c, d;
+  f = vec_sums (h, b);
+  vector int i = vec_mergel (f, g);
+  vector int k = vec_mergel (i, j);
+  vector int l = vec_sl (k, c);
+  vector int m = vec_sl (l, d);
+  vector char o;
+  vector int p = vec_perm (m, n, o);
+  e = vec_sra (p, c);
+  vec_st (e, 0, a);
+}