aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichael Matz <matz@suse.de>2009-05-06 16:49:13 +0000
committerMichael Matz <matz@gcc.gnu.org>2009-05-06 16:49:13 +0000
commit529ff44101de7c912c138994b03c7ec199ff5e93 (patch)
treee95e93d5d2478bbf0f22d4f48c411f8243fe28ba
parent8ba50c2c9ec505d42da79ff3ec32c3a74ab91c7c (diff)
downloadgcc-529ff44101de7c912c138994b03c7ec199ff5e93.zip
gcc-529ff44101de7c912c138994b03c7ec199ff5e93.tar.gz
gcc-529ff44101de7c912c138994b03c7ec199ff5e93.tar.bz2
re PR middle-end/40021 (Revision 146817 miscompiled DAXPY in BLAS)
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
-rw-r--r--gcc/ChangeLog6
-rw-r--r--gcc/cfgexpand.c63
-rw-r--r--gcc/testsuite/ChangeLog4
-rw-r--r--gcc/testsuite/gfortran.dg/pr40021.f42
4 files changed, 100 insertions, 15 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index fdb25f6..f6ec862 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -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.
diff --git a/gcc/cfgexpand.c b/gcc/cfgexpand.c
index 03d0996..ab9464f 100644
--- a/gcc/cfgexpand.c
+++ b/gcc/cfgexpand.c
@@ -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;
}
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index 2a770f2..b4abbed 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -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
index 0000000..6d3f44d
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/pr40021.f
@@ -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