diff options
author | Michael Matz <matz@suse.de> | 2009-05-06 16:49:13 +0000 |
---|---|---|
committer | Michael Matz <matz@gcc.gnu.org> | 2009-05-06 16:49:13 +0000 |
commit | 529ff44101de7c912c138994b03c7ec199ff5e93 (patch) | |
tree | e95e93d5d2478bbf0f22d4f48c411f8243fe28ba | |
parent | 8ba50c2c9ec505d42da79ff3ec32c3a74ab91c7c (diff) | |
download | gcc-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/ChangeLog | 6 | ||||
-rw-r--r-- | gcc/cfgexpand.c | 63 | ||||
-rw-r--r-- | gcc/testsuite/ChangeLog | 4 | ||||
-rw-r--r-- | gcc/testsuite/gfortran.dg/pr40021.f | 42 |
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 |