[Bug tree-optimization/126301] Incorrect loop control for loops where latch preceeds loop

"cvs-commit at gcc dot gnu.org via Gcc-bugs" <[email protected]> Tue, 04 Aug 2026 14:33:46 +0000
Newsgroups gmane.comp.gcc.bugs
Message-ID <[email protected]/bugzilla/>
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=126301

--- Comment #2 from GCC Commits <cvs-commit at gcc dot gnu.org> ---
The master branch has been updated by Tamar Christina <[email protected]>:

https://gcc.gnu.org/g:f87736236260bee8512fbf2441494c71952da6ed

commit r17-2949-gf87736236260bee8512fbf2441494c71952da6ed
Author: Tamar Christina <[email protected]>
Date:   Tue Aug 4 15:31:02 2026 +0100

    vect: convert do-loop edges properly for
LOOP_VINFO_EARLY_BREAKS_VECT_PEELED [PR126301]

    The example

    char b[100];
    int c(int a) {
      unsigned d = 0;
      for (; d < a; ++d)
        {
          if (b[0] + b[d + 1])
            return 0;
        }
      return 1;
    }

    when compiled with a partial masked target, e.g. -march=armv9-a -O3
generates

            ptrue   p6.b, all
            whilelo p15.s, wzr, w3
            b       .L5
    .L11:
            ld1b    z31.s, p7/z, [x5, x1]
            add     z31.h, z31.h, z30.h
            uxth    z31.s, p6/m, z31.s
            cmpne   p7.s, p7/z, z31.s, #0
            b.any   .L4
    .L5:
            mov     x2, x1
            mov     p7.b, p15.b
            incw    x1
            whilelo p15.s, w1, w3
            b.any   .L11
            mov     w1, w2
            add     x3, x4, :lo12:.LANCHOR0
            b       .L8

    Warped BB rotation due to the incorrect profiles aside (different problem)
    this loop will exit one iteration early since the IV check (d < a) is
checked
    as (++d < a).

    This means that when branched to the scalar code we do 2 vector iterations
in
    the worst case rather than 1.

    This is due to the fact that the loop is essentially a do-while loop coming
into
    the vectorizer.  We detect this loop as a
LOOP_VINFO_EARLY_BREAKS_VECT_PEELED
    because it's the same form as a normal while-do loop but where we picked a
    different exit than the loop latch exit.

    Because of the versioning and other checks in the preheader we know that if
you
    reach the loop body you'll always do at least 1 iteration of the body (but
    possibly never the latch).  i.e. the d != 0 check is always true should you
get
    to the end of the pre-header.

    The codegen reflects this but because of the early IV exit check we never
get to
    the body.

    Alfie's patch to fix this changed the `d++ < a` check to the correct (d <
a)
    check, but due to how the control flow becomes we end up doing

    mask_1 = PHI <mask_0, next_mask>
    if (mask_1)

    and causes us to retest the mask, even though the mask generation which
happens
    in the pre-header has guaranteed that for the first iteration it's
non-empty.

    So we lose information because the check in the header is used by both the
value
    from the pre-header and the latch on loop back.

    Instead of doing that this patch just changed the control flow to reflect
that
    we can always execute the body at least once.  In effect it moves the IV
latch
    check to the end.

    This generates:

            ptrue   p6.b, all
            whilelo p7.s, wzr, w4
            b       .L4
            .p2align 2,,3
    .L11:
            whilelo p7.s, w1, w4
            b.none  .L15
    .L4:
            mov     x2, x1
            incw    x1
            ld1b    z31.s, p7/z, [x5, x1]
            add     z31.h, z31.h, z30.h
            uxth    z31.s, p6/m, z31.s
            cmpne   p7.s, p7/z, z31.s, #0
            b.none  .L11
    .L7:
            mov     w0, 0
            ret

    and when the profiles are fixed (PR117790) we'd get

            ptrue   p6.b, all
            whilelo p7.s, wzr, w5
            .p2align 5,,15
    .L4:
            mov     x2, x1
            incw    x1
            ld1b    z31.s, p7/z, [x3, x1]
            add     z31.h, z31.h, z30.h
            uxth    z31.s, p6/m, z31.s
            cmpne   p7.s, p7/z, z31.s, #0
            b.any   .L7
            whilelo p7.s, w1, w5
            b.any   .L4

    gcc/ChangeLog:

            PR tree-optimization/126301
            * tree-vect-loop-manip.cc (vect_use_loop_latch_condition_p): New.
            (vect_set_loop_condition_partial_vectors, vect_set_loop_condition):
Use
            it to rewrite latch and condition.
            (vect_set_loop_controls_directly): Adjust IV for do-loop
conversion.

    gcc/testsuite/ChangeLog:

            PR tree-optimization/126301
            * gcc.target/aarch64/sve/peeled.c: New test.
            * gcc.target/aarch64/sve/peeled1.c: New test.
            * gcc.target/aarch64/sve/peeled1_run.c: New test.
            * gcc.target/aarch64/sve/peeled2.c: New test.
            * gcc.target/aarch64/sve/peeled2_run.c: New test.
            * gcc.target/aarch64/sve/peeled_run.c: New test.