https://gcc.gnu.org/bugzilla/show_bug.cgi?id=114052
Richard Biener <rguenth at gcc dot gnu.org> changed: What |Removed |Added ---------------------------------------------------------------------------- CC| |hubicka at gcc dot gnu.org --- Comment #4 from Richard Biener <rguenth at gcc dot gnu.org> --- We enter cunroll with <bb 2> [local count: 10631108]: <bb 3> [local count: 284435276]: # RANGE [irange] int [0, 2] # counter_4 = PHI <counter_6(5), 0(2)> <bb 4> [local count: 1073741823]: if (counter_4 == 2) goto <bb 6>; [74.50%] else goto <bb 5>; [25.50%] <bb 6> [local count: 799937655]: goto <bb 4>; [100.00%] <bb 5> [local count: 273804168]: # RANGE [irange] int [1, 2] counter_6 = counter_4 + 1; # USE = nonlocal escaped null # CLB = nonlocal escaped null printf ("%i\n", counter_4); goto <bb 3>; [100.00%] and then we do Estimating # of iterations of loop 2 Loop 1 iterates at most 1 times. Loop 1 likely iterates at most 1 times. which is wrong. I think the issue is in record_nonwrapping_iv which in r6-7091-ge53d562a36ead2 got a fix not using ranges from not always executing stmts (but oddly enough gating only one end, and seemingly the wrong one?). In this case the inner endless loops makes the apparent post-dominated block with the increment actually _not_ execute. So that "always executed" thing is not properly implemented (we also expect the caller to pass "upper" as false). Similar case could be constructed by accessing an array with fixed bounds in the latch, the "simple" case int a[3]; int foo(void) { unsigned counter = 0; while (1) { if (counter >= 2) continue; printf("%i\n", a[++counter]); } return 0; } works because with -O2 we refuse unrolling due to code size growth: Loop 1 iterates at most 1 times. Loop 1 likely iterates at most 1 times. ... Not unrolling loop 1: it is not innermost and code would grow. That said, we do not handle possibly infinite subloops or calls that might not return as properly blocking any of the number-of-iteration-because-of-undefined-behavior heuristics. Interestingly enough the following also "works" (unrolling also increases code size, but we compute two iterations for this). void __attribute__((noipa)) bar (int i) { if (i == __INT_MAX__) while (1); } int a[3]; int foo(void) { int counter = __INT_MAX__ - 2; while (1) { bar (counter); printf("%i\n", counter++); } return 0; } this needs some investigation more in detail but the underlying issue is that we do not model inner loops or calls correctly here. Probably best done in infer_loop_bounds_from_undefined itself which walks BBs and stmts. I'll note it's tricky as even if (foo) bar (); ++counter; thus a conditional call should be a blocker for this. Honza - I guess IPA modref has done this kind of "walking" already, is there a place to copy / factor for this?