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
This commit is contained in:
Michael Matz 2009-05-06 16:49:13 +00:00 committed by Michael Matz
parent 8ba50c2c9e
commit 529ff44101
4 changed files with 100 additions and 15 deletions

View 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> 2009-05-06 Rafael Avila de Espindola <espindola@google.com>
* Makefile.in (install-plugin): Fix srcdir handling. * Makefile.in (install-plugin): Fix srcdir handling.

View 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. /* A subroutine of expand_gimple_basic_block. Expand one GIMPLE_COND.
Returns a new basic block if we've terminated the current basic Returns a new basic block if we've terminated the current basic
block and created a new one. */ block and created a new one. */
@ -1767,19 +1813,7 @@ expand_gimple_cond (basic_block bb, gimple stmt)
true_edge->goto_block = NULL; true_edge->goto_block = NULL;
false_edge->flags |= EDGE_FALLTHRU; false_edge->flags |= EDGE_FALLTHRU;
ggc_free (pred); ggc_free (pred);
/* Special case: when jumpif decides that the condition is maybe_cleanup_end_of_block (false_edge);
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);
return NULL; return NULL;
} }
if (true_edge->dest == bb->next_bb) if (true_edge->dest == bb->next_bb)
@ -1796,8 +1830,7 @@ expand_gimple_cond (basic_block bb, gimple stmt)
false_edge->goto_block = NULL; false_edge->goto_block = NULL;
true_edge->flags |= EDGE_FALLTHRU; true_edge->flags |= EDGE_FALLTHRU;
ggc_free (pred); ggc_free (pred);
if (BARRIER_P (get_last_insn ())) maybe_cleanup_end_of_block (true_edge);
remove_edge (true_edge);
return NULL; return NULL;
} }

View 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> 2009-05-06 Le-Chun Wu <lcwu@google.com>
* lib/plugin-support.exp: New file containing support procs for * lib/plugin-support.exp: New file containing support procs for

View File

@ -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