On Mon, 27 Oct 2025, Tamar Christina wrote:

> > -----Original Message-----
> > From: Richard Biener <[email protected]>
> > Sent: 27 October 2025 13:37
> > To: Tamar Christina <[email protected]>
> > Cc: [email protected]; nd <[email protected]>; [email protected]
> > Subject: Re: [PATCH][vect]: Fix LCSSA wiring during peeling of multiple-exit
> > loops
> > 
> > On Sat, 25 Oct 2025, Tamar Christina wrote:
> > 
> > > Arg..
> > >
> > > Just noticed a typo..
> > >
> > > BB 3:
> > >   i_2 = PHI <i_1(2)>
> > >
> > > Should be
> > >
> > >
> > > BB 3:
> > >   i_2 = PHI <i_0(2)>
> > >
> > > Rest is OK. Sorry about that
> > >
> > > ________________________________
> > > From: Tamar Christina
> > > Sent: Saturday, October 25, 2025 10:52 AM
> > > To: [email protected] <[email protected]>
> > > Cc: nd <[email protected]>; [email protected] <[email protected]>;
> > [email protected] <[email protected]>
> > > Subject: [PATCH][vect]: Fix LCSSA wiring during peeling of multiple-exit 
> > > loops
> > >
> > > 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..96ca273c24680556f16c
> > dc9e465f490d7fcdb8a4 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;
> > > +                     }
> > > +
> > 
> > I'm a bit confused - isn't this exactly what 'peeled_iters'
> > (aka LOOP_VINFO_EARLY_BREAKS_VECT_PEELED) is about?  That is,
> > this loop is supposed to handle the main exit (and creating
> > all required merge PHIs and eventually missing LC PHIs), so
> > your patch suggests we put in the "wrong" result, but you
> > leave the old 'peeled_iters' code around, even using the
> > original 'caching' (but then for the wrong value?).
> > 
> 
> No, peeled_iters means we want the value at the start of the vector iteration.
> This issue is that we want the value at the end of the vector iteration - 
> <offset>.
> 
> So they aren't the same.  In a normal loop, this adjustment is calculated by
> vect_update_ivs_after_vectorizer through niters because it has the right PHI 
> node
> it doesn't use the incorrect final value of i to adjust the count.
> 
> > At the same time the 2nd loop filling the alternate exit cases
> > is always correct?
> 
> Yes, because alternate exits always restart the loop from the start, so the 
> reduction
> for it takes you before you do any adjustment at all for i.

So I belive the logic

                  /* When the vector loop is peeled then we need to use 
the
                     value at start of the loop, otherwise the main loop 
exit
                     should use the final iter value.  */
                  tree new_arg;
                  if (peeled_iters)
                    new_arg = gimple_phi_result (from_phi);
                  else
                    new_arg = PHI_ARG_DEF_FROM_EDGE (from_phi,
                                                     loop_latch_edge 
(loop));

for !peeled_iters is correct.  In this place we are looking for the
initial value to use for the epilog loop - but in this case this
value is different from the actual live value computed by the testcase.
Note there is in general no way to associate the LC PHI [def] with
the IV in the loop header if it is neither the PHI result nor the
latch value - as it is in this case.  Instead the LC PHI is for
an alltogether different "IV" (but a related, offsetted one).

And I see '5' being used as the continuation value via
vect_update_ivs_after_vectorizer, so that seems correct.

So, I can't really see what is wrong here?  The vectorized code
also looks OK.  It should be possible to set up a C testcase for
this, like

 int i = 1, j;
 do
   {
     if (...) abort ();
     j = i + 1;
   }
 while (...);
 ... use i ...

Richard.

> > 
> > Does the issue show with the fortran testcase on current trunk?
> > 
> 
> Yes, the codegen on trunk today is wrong, but the main exit would never be 
> reached
> because of the increased VF.  So the tests "passes" because it takes the 
> early exit.
> 
> Thanks,
> Tamar
> 
> > Thanks,
> > Richard.
> > 
> > >                    /* 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);
> > >
> > >
> > > --
> > >
> > 
> > --
> > Richard Biener <[email protected]>
> > SUSE Software Solutions Germany GmbH,
> > Frankenstrasse 146, 90461 Nuernberg, Germany;
> > GF: Ivo Totev, Andrew McDonald, Werner Knoblich; (HRB 36809, AG
> > Nuernberg)
> 

-- 
Richard Biener <[email protected]>
SUSE Software Solutions Germany GmbH,
Frankenstrasse 146, 90461 Nuernberg, Germany;
GF: Ivo Totev, Andrew McDonald, Werner Knoblich; (HRB 36809, AG Nuernberg)

Reply via email to