re PR middle-end/40021 (Revision 146817 miscompiled DAXPY in BLAS)
authorMichael Matz <matz@suse.de>
Wed, 6 May 2009 16:49:13 +0000 (16:49 +0000)
committerMichael Matz <matz@gcc.gnu.org>
Wed, 6 May 2009 16:49:13 +0000 (16:49 +0000)
        PR middle-end/40021
        * cfgexpand.c (maybe_cleanup_end_of_block): New static function.
        (expand_gimple_cond): Use it to cleanup CFG and superfluous jumps.

        * gfortran.dg/pr40021.f: New test.

From-SVN: r147186

gcc/ChangeLog
gcc/cfgexpand.c
gcc/testsuite/ChangeLog
gcc/testsuite/gfortran.dg/pr40021.f [new file with mode: 0644]

index fdb25f6..f6ec862 100644 (file)
@@ -1,3 +1,9 @@
+2009-05-06  Michael Matz  <matz@suse.de>
+
+       PR middle-end/40021
+       * cfgexpand.c (maybe_cleanup_end_of_block): New static function.
+       (expand_gimple_cond): Use it to cleanup CFG and superfluous jumps.
+
 2009-05-06  Rafael Avila de Espindola  <espindola@google.com>
 
        * Makefile.in (install-plugin): Fix srcdir handling.
index 03d0996..ab9464f 100644 (file)
@@ -1724,6 +1724,52 @@ label_rtx_for_bb (basic_block bb ATTRIBUTE_UNUSED)
 }
 
 
+/* A subroutine of expand_gimple_cond.  Given E, a fallthrough edge
+   of a basic block where we just expanded the conditional at the end,
+   possibly clean up the CFG and instruction sequence.  */
+
+static void
+maybe_cleanup_end_of_block (edge e)
+{
+  /* Special case: when jumpif decides that the condition is
+     trivial it emits an unconditional jump (and the necessary
+     barrier).  But we still have two edges, the fallthru one is
+     wrong.  purge_dead_edges would clean this up later.  Unfortunately
+     we have to insert insns (and split edges) before
+     find_many_sub_basic_blocks and hence before purge_dead_edges.
+     But splitting edges might create new blocks which depend on the
+     fact that if there are two edges there's no barrier.  So the
+     barrier would get lost and verify_flow_info would ICE.  Instead
+     of auditing all edge splitters to care for the barrier (which
+     normally isn't there in a cleaned CFG), fix it here.  */
+  if (BARRIER_P (get_last_insn ()))
+    {
+      basic_block bb = e->src;
+      rtx insn;
+      remove_edge (e);
+      /* Now, we have a single successor block, if we have insns to
+        insert on the remaining edge we potentially will insert
+        it at the end of this block (if the dest block isn't feasible)
+        in order to avoid splitting the edge.  This insertion will take
+        place in front of the last jump.  But we might have emitted
+        multiple jumps (conditional and one unconditional) to the
+        same destination.  Inserting in front of the last one then
+        is a problem.  See PR 40021.  We fix this by deleting all
+        jumps except the last unconditional one.  */
+      insn = PREV_INSN (get_last_insn ());
+      /* Make sure we have an unconditional jump.  Otherwise we're
+        confused.  */
+      gcc_assert (JUMP_P (insn) && !any_condjump_p (insn));
+      for (insn = PREV_INSN (insn); insn != BB_HEAD (bb);)
+       {
+         insn = PREV_INSN (insn);
+         if (JUMP_P (NEXT_INSN (insn)))
+           delete_insn (NEXT_INSN (insn));
+       }
+    }
+}
+
+
 /* A subroutine of expand_gimple_basic_block.  Expand one GIMPLE_COND.
    Returns a new basic block if we've terminated the current basic
    block and created a new one.  */
@@ -1767,19 +1813,7 @@ expand_gimple_cond (basic_block bb, gimple stmt)
       true_edge->goto_block = NULL;
       false_edge->flags |= EDGE_FALLTHRU;
       ggc_free (pred);
-      /* Special case: when jumpif decides that the condition is
-         trivial it emits an unconditional jump (and the necessary
-        barrier).  But we still have two edges, the fallthru one is
-        wrong.  purge_dead_edges would clean this up later.  Unfortunately
-        we have to insert insns (and split edges) before
-        find_many_sub_basic_blocks and hence before purge_dead_edges.
-        But splitting edges might create new blocks which depend on the
-        fact that if there are two edges there's no barrier.  So the
-        barrier would get lost and verify_flow_info would ICE.  Instead
-        of auditing all edge splitters to care for the barrier (which
-        normally isn't there in a cleaned CFG), fix it here.  */
-      if (BARRIER_P (get_last_insn ()))
-       remove_edge (false_edge);
+      maybe_cleanup_end_of_block (false_edge);
       return NULL;
     }
   if (true_edge->dest == bb->next_bb)
@@ -1796,8 +1830,7 @@ expand_gimple_cond (basic_block bb, gimple stmt)
       false_edge->goto_block = NULL;
       true_edge->flags |= EDGE_FALLTHRU;
       ggc_free (pred);
-      if (BARRIER_P (get_last_insn ()))
-       remove_edge (true_edge);
+      maybe_cleanup_end_of_block (true_edge);
       return NULL;
     }
 
index 2a770f2..b4abbed 100644 (file)
@@ -1,3 +1,7 @@
+2009-05-06  Michael Matz  <matz@suse.de>
+
+       * gfortran.dg/pr40021.f: New test.
+
 2009-05-06  Le-Chun Wu  <lcwu@google.com>
 
        * lib/plugin-support.exp: New file containing support procs for
diff --git a/gcc/testsuite/gfortran.dg/pr40021.f b/gcc/testsuite/gfortran.dg/pr40021.f
new file mode 100644 (file)
index 0000000..6d3f44d
--- /dev/null
@@ -0,0 +1,42 @@
+! { dg-do run { target i?86-*-* x86_64-*-* } }
+! { dg-require-effective-target ilp32 }
+! { dg-options "-O2 -ftree-vectorize -msse2 -mfpmath=sse -ffast-math" }
+        PROGRAM test
+        DOUBLE PRECISION DA
+        INTEGER I, N
+        DOUBLE PRECISION DX(9),DY(9)
+
+        EXTERNAL DAXPY
+        N=5
+        DA=1.0
+        DATA DX/-2, -1, -3, -4, 1, 2, 10, 15, 14/
+        DATA DY/0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0/
+        CALL DAXPY (N,DA,DX,DY)
+        DO 10 I = 1, N
+          if (DX(I).ne.DY(I)) call abort
+10      CONTINUE
+        STOP
+        END
+
+      SUBROUTINE DAXPY(N,DA,DX,DY)
+      DOUBLE PRECISION DA
+      INTEGER N
+      DOUBLE PRECISION DX(*),DY(*)
+      INTEGER I,IX,IY,M,MP1
+      INTRINSIC MOD
+      IF (N.LE.0) RETURN
+   20 M = MOD(N,4)
+      IF (M.EQ.0) GO TO 40
+      DO 30 I = 1,M
+          DY(I) = DY(I) + DA*DX(I)
+   30 CONTINUE
+      IF (N.LT.4) RETURN
+   40 MP1 = M + 1
+      DO 50 I = MP1,N,4
+          DY(I) = DY(I) + DA*DX(I)
+          DY(I+1) = DY(I+1) + DA*DX(I+1)
+          DY(I+2) = DY(I+2) + DA*DX(I+2)
+          DY(I+3) = DY(I+3) + DA*DX(I+3)
+   50 CONTINUE
+      RETURN
+      END