re PR tree-optimization/87074 (Unroll and jam bug: O3 result differ from O2)

Fix PR87074

	PR tree-optimization/87074
	* gimple-loop-jam.c (unroll_jam_possible_p): Check loop exit
	PHIs for outer-loop uses.

testsuite/
	* gcc.dg/pr87074.c: New test.

From-SVN: r264029
This commit is contained in:
Michael Matz 2018-09-01 17:22:05 +00:00 committed by Michael Matz
parent c8a4f039fc
commit 395552b520
4 changed files with 64 additions and 2 deletions

View File

@ -1,3 +1,9 @@
2018-09-01 Michael Matz <matz@suse.de>
PR tree-optimization/87074
* gimple-loop-jam.c (unroll_jam_possible_p): Check loop exit
PHIs for outer-loop uses.
2018-09-01 Gerald Pfeifer <gerald@pfeifer.com> 2018-09-01 Gerald Pfeifer <gerald@pfeifer.com>
* doc/install.texi (Prerequisites): Adjust link mpfr.org. * doc/install.texi (Prerequisites): Adjust link mpfr.org.

View File

@ -161,7 +161,7 @@ bb_prevents_fusion_p (basic_block bb)
gimple_stmt_iterator gsi; gimple_stmt_iterator gsi;
/* BB is duplicated by outer unrolling and then all N-1 first copies /* BB is duplicated by outer unrolling and then all N-1 first copies
move into the body of the fused inner loop. If BB exits the outer loop move into the body of the fused inner loop. If BB exits the outer loop
the last copy still doess so, and the first N-1 copies are cancelled the last copy still does so, and the first N-1 copies are cancelled
by loop unrolling, so also after fusion it's the exit block. by loop unrolling, so also after fusion it's the exit block.
But there might be other reasons that prevent fusion: But there might be other reasons that prevent fusion:
* stores or unknown side-effects prevent fusion * stores or unknown side-effects prevent fusion
@ -227,6 +227,33 @@ unroll_jam_possible_p (struct loop *outer, struct loop *loop)
|| !expr_invariant_in_loop_p (outer, niter.niter)) || !expr_invariant_in_loop_p (outer, niter.niter))
return false; return false;
/* If the inner loop produces any values that are used inside the
outer loop (except the virtual op) then it can flow
back (perhaps indirectly) into the inner loop. This prevents
fusion: without fusion the value at the last iteration is used,
with fusion the value after the initial iteration is used.
If all uses are outside the outer loop this doesn't prevent fusion;
the value of the last iteration is still used (and the values from
all intermediate iterations are dead). */
gphi_iterator psi;
for (psi = gsi_start_phis (single_exit (loop)->dest);
!gsi_end_p (psi); gsi_next (&psi))
{
imm_use_iterator imm_iter;
use_operand_p use_p;
tree op = gimple_phi_result (psi.phi ());
if (virtual_operand_p (op))
continue;
FOR_EACH_IMM_USE_FAST (use_p, imm_iter, op)
{
gimple *use_stmt = USE_STMT (use_p);
if (!is_gimple_debug (use_stmt)
&& flow_bb_inside_loop_p (outer, gimple_bb (use_stmt)))
return false;
}
}
/* And check blocks belonging to just outer loop. */ /* And check blocks belonging to just outer loop. */
bbs = XNEWVEC (basic_block, n_basic_blocks_for_fn (cfun)); bbs = XNEWVEC (basic_block, n_basic_blocks_for_fn (cfun));
n = get_loop_body_with_size (outer, bbs, n_basic_blocks_for_fn (cfun)); n = get_loop_body_with_size (outer, bbs, n_basic_blocks_for_fn (cfun));
@ -245,7 +272,6 @@ unroll_jam_possible_p (struct loop *outer, struct loop *loop)
body would be the after-iter value of the first body) if it's over body would be the after-iter value of the first body) if it's over
an associative and commutative operation. We wouldn't an associative and commutative operation. We wouldn't
be able to handle unknown cycles. */ be able to handle unknown cycles. */
gphi_iterator psi;
for (psi = gsi_start_phis (loop->header); !gsi_end_p (psi); gsi_next (&psi)) for (psi = gsi_start_phis (loop->header); !gsi_end_p (psi); gsi_next (&psi))
{ {
affine_iv iv; affine_iv iv;

View File

@ -1,3 +1,8 @@
2018-09-01 Michael Matz <matz@suse.de>
PR tree-optimization/87074
* gcc.dg/pr87074.c: New test.
2018-08-31 Richard Biener <rguenther@suse.de> 2018-08-31 Richard Biener <rguenther@suse.de>
PR tree-optimization/87168 PR tree-optimization/87168

View File

@ -0,0 +1,25 @@
/* { dg-do run } */
/* { dg-options "-O3 -floop-unroll-and-jam --param unroll-jam-min-percent=0" } */
long b;
unsigned c[5];
unsigned long long d = 3;
int e, f, g;
void h() {
for (; f < 11; f++) {
b = g;
for (e = 0; e < 5; e++) {
c[e] = e - b - (c[e] >> 5);
g = c[e];
}
}
if (c[0])
d = 0;
}
extern void abort(void);
int main() {
h();
if (d != 0)
abort ();
}