Consider this Fortran testcase:
integer (8) b, c
integer d
c = 10
d = 2
call e ((/ (b, b = j, c, d) /), 0_8, c, d + 0_8)
contains
subroutine e (a, f, g, h)
integer (8), dimension (:) :: a
integer (8) f, g, h
i = 1
do b = f, g, h
if (a (i) .ne. b) STOP
i = i + 1
end do
if (size (a) .ne. i - 1) STOP 2
end
end
which is a reduced example from the testsuite so not added as a new test.
This testcase starts the loop at i = 1, but no peeling needs to be done.
As a result the loop form looks like
BB 1:
i_0 = PHI <1(initial), i_1(latch)>;
if (<early-break-condition>)
...
else
goto BB 2;
BB 2:
i_1 = i_0 + 1;
if (<main-exit>)
goto BB 3;
goto BB 1;
BB 3:
i_2 = PHI <i_1(2)>;
Basically in the main IV exit we don't use the value *after* incrementing but
rather the value before incrementing.
At the moment during peeling we wipe away this information and replace in the
exit the value of i_1. This is incorrect and means we can no longer tell
which value of the IV we should actually be calculating for that exit.
This isn't triggered often on trunk because of an artificial inflation of the VF
which causes the main exist not be reached very often and such loops aren't
common. However with the scalar IV code this issue was brought to light.
This patch preserves the value of the LC PHI set during edge redirection. We
end up still creating the new PHI but it uses the correct value now. The reason
for still creating the duplicate PHI is because there are code outside of
peeling that today depends on the PHI node ordering. So this was a conservative
fix. The duplicate PHI gets elided later as it'll be unused.
Bootstrapped Regtested on aarch64-none-linux-gnu,
arm-none-linux-gnueabihf, x86_64-pc-linux-gnu
-m32, -m64 and no issues
Ok for master?
Thanks,
Tamar
gcc/ChangeLog:
* tree-vect-loop-manip.cc (slpeel_tree_duplicate_loop_to_edge_cfg): Fix
up PHI in exit nodes.
---
diff --git a/gcc/tree-vect-loop-manip.cc b/gcc/tree-vect-loop-manip.cc
index
20141dbc2e54d49bca00a2e75a6733d181e05ed1..96ca273c24680556f16cdc9e465f490d7fcdb8a4
100644
--- a/gcc/tree-vect-loop-manip.cc
+++ b/gcc/tree-vect-loop-manip.cc
@@ -1755,6 +1755,22 @@ slpeel_tree_duplicate_loop_to_edge_cfg (class loop
*loop, edge loop_exit,
new_arg = PHI_ARG_DEF_FROM_EDGE (from_phi,
loop_latch_edge (loop));
+ /* Some loops start at a non-zero index, which then require
+ during redirection to return i instead of i + 1. Edge
+ redirection already deals with this, but we need to make
+ sure we don't override the value it puts in for these
+ cases. */
+ imm_use_iterator imm_iter;
+ use_operand_p use_p;
+ tree from_def = PHI_RESULT (from_phi);
+ bool abnormal_exit_condition = false;
+ FOR_EACH_IMM_USE_FAST (use_p, imm_iter, from_def)
+ if (gimple_bb (USE_STMT (use_p)) == main_loop_exit_block)
+ {
+ abnormal_exit_condition = true;
+ break;
+ }
+
/* Check if we've already created a new phi node during edge
redirection and re-use it if so. Otherwise create a
LC PHI node to feed the merge PHI. */
@@ -1769,6 +1785,11 @@ slpeel_tree_duplicate_loop_to_edge_cfg (class loop
*loop, edge loop_exit,
new_arg = *res;
else
{
+ /* If we already found an LC PHI for the current PHI then
+ just re-use it. */
+ if (abnormal_exit_condition)
+ new_arg = from_def;
+
/* Create the LC PHI node for the exit. */
tree new_def = copy_ssa_name (new_arg);
gphi *lc_phi
@@ -1779,7 +1800,7 @@ slpeel_tree_duplicate_loop_to_edge_cfg (class loop *loop,
edge loop_exit,
/* Create the PHI node in the merge block merging the
main and early exit values. */
- tree new_res = copy_ssa_name (gimple_phi_result (from_phi));
+ tree new_res = copy_ssa_name (from_def);
gphi *lcssa_phi = create_phi_node (new_res, new_preheader);
edge main_e = single_succ_edge (main_loop_exit_block);
SET_PHI_ARG_DEF_ON_EDGE (lcssa_phi, main_e, new_arg);
--
diff --git a/gcc/tree-vect-loop-manip.cc b/gcc/tree-vect-loop-manip.cc
index 20141dbc2e54d49bca00a2e75a6733d181e05ed1..96ca273c24680556f16cdc9e465f490d7fcdb8a4 100644
--- a/gcc/tree-vect-loop-manip.cc
+++ b/gcc/tree-vect-loop-manip.cc
@@ -1755,6 +1755,22 @@ slpeel_tree_duplicate_loop_to_edge_cfg (class loop *loop, edge loop_exit,
new_arg = PHI_ARG_DEF_FROM_EDGE (from_phi,
loop_latch_edge (loop));
+ /* Some loops start at a non-zero index, which then require
+ during redirection to return i instead of i + 1. Edge
+ redirection already deals with this, but we need to make
+ sure we don't override the value it puts in for these
+ cases. */
+ imm_use_iterator imm_iter;
+ use_operand_p use_p;
+ tree from_def = PHI_RESULT (from_phi);
+ bool abnormal_exit_condition = false;
+ FOR_EACH_IMM_USE_FAST (use_p, imm_iter, from_def)
+ if (gimple_bb (USE_STMT (use_p)) == main_loop_exit_block)
+ {
+ abnormal_exit_condition = true;
+ break;
+ }
+
/* Check if we've already created a new phi node during edge
redirection and re-use it if so. Otherwise create a
LC PHI node to feed the merge PHI. */
@@ -1769,6 +1785,11 @@ slpeel_tree_duplicate_loop_to_edge_cfg (class loop *loop, edge loop_exit,
new_arg = *res;
else
{
+ /* If we already found an LC PHI for the current PHI then
+ just re-use it. */
+ if (abnormal_exit_condition)
+ new_arg = from_def;
+
/* Create the LC PHI node for the exit. */
tree new_def = copy_ssa_name (new_arg);
gphi *lc_phi
@@ -1779,7 +1800,7 @@ slpeel_tree_duplicate_loop_to_edge_cfg (class loop *loop, edge loop_exit,
/* Create the PHI node in the merge block merging the
main and early exit values. */
- tree new_res = copy_ssa_name (gimple_phi_result (from_phi));
+ tree new_res = copy_ssa_name (from_def);
gphi *lcssa_phi = create_phi_node (new_res, new_preheader);
edge main_e = single_succ_edge (main_loop_exit_block);
SET_PHI_ARG_DEF_ON_EDGE (lcssa_phi, main_e, new_arg);