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  <ja...@redhat.com>
            Segher Boessenkool  <seg...@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.

--- 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);
+}

        Jakub

Reply via email to