[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.