https://gcc.gnu.org/bugzilla/show_bug.cgi?id=62217
Bug ID: 62217
Summary: Extra iteration peeled during cunroll. Makes VRP warn.
Product: gcc
Version: 4.9.2
Status: UNCONFIRMED
Severity: normal
Priority: P3
Component: tree-optimization
Assignee: unassigned at gcc dot gnu.org
Reporter: kyukhin at gcc dot gnu.org
Suppose we have a test:
typedef struct { unsigned data; } s1;
s1 g_x[4];
extern void foo (s1 *x1, s1 *x2, int a, int b)
{
int i;
for(i = 0; i < a; i++)
if(i == b)
g_x[i] = *x1;
else
g_x[i] = *x2;
}
$ ./build-x86_64-linux/gcc/xgcc -B./build-x86_64-linux/gcc -O3 -Wall -S x1.c
x1.c: In function ‘foo’:
x1.c:9:10: warning: array subscript is above array bounds [-Warray-bounds]
g_x[i] = *x1;
^
Which come from second pass of VRP:
# i_14 = PHI <4(14)>
if (b_6(D) == 4)
goto <bb 17>;
else
goto <bb 18>;
<bb 17>:
g_x[4] = *x1_7(D);
i_11 = 5;
goto <bb 3>;
<bb 18>:
__builtin_unreachable ();
VRP checker fairly warns that g_x[4] is out-of-bounds mem ref.
This code was generated by tree-ssa-loop-ivcanon.c
I do not completely understand logic of cunroll pass,
however dumps say:
Loop 1 iterates at most 4 times.
...
x1.c:7:3: note: loop with 5 iterations completely unrolled
Last iteration exit edge was proved true.
Forced statement unreachable: g_x[i_14] = *x2_9(D);
In function `try_unroll_loop_completely' argument `maxiter'
equals to 4, which is correct. Then (through n_unroll var)
this value is passed to `gimple_duplicate_loop_to_header_edge'
routine, which perform the peeling. This routine as far
as I understand perform peel `n_unroll' copies from original
loop, resulting to (n_unroll+1) overall copies (including original
loop).
I think of 2 solutions:
- Reduce peel number by 1
- Improve remove_exits_and_undefined_stmts (), which correctly
insert `gcc_unreachable' for `false' part of the if-stmt on
5-th iteration.
It obviously don't warns, when limit is reduced:
./build-x86_64-linux/gcc/xgcc -B./build-x86_64-linux/gcc -O3 -Wall -msse3 -c
-m32 x1.c --param max-completely-peel-times=3