Skip to content

Commit 544ca30

Browse files
ivbound: Introduce loop versioning pass for potentially overflowing IV's
Finds loops with potentially overflowing IV's and versions the loop with a constant bound such that the bounded loop can have improved optimizations. Signed-off-by: Michiel Derhaeg <michiel@synopsys.com>
1 parent 6785461 commit 544ca30

22 files changed

Lines changed: 657 additions & 5 deletions

gcc/Makefile.in

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1501,6 +1501,7 @@ OBJS = \
15011501
gimple-harden-control-flow.o \
15021502
gimple-laddress.o \
15031503
gimple-loop-interchange.o \
1504+
tree-ssa-loop-ivbound.o \
15041505
gimple-loop-jam.o \
15051506
gimple-loop-versioning.o \
15061507
gimple-low.o \

gcc/common.opt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3378,6 +3378,10 @@ fversion-loops-for-strides
33783378
Common Var(flag_version_loops_for_strides) Optimization
33793379
Version loops based on whether indices have a stride of one.
33803380

3381+
fversion-loops-for-iv-overflow
3382+
Common Var(flag_version_loops_for_iv_overflow) Optimization
3383+
Version loops to guard against induction variable overflow.
3384+
33813385
funwind-tables
33823386
Common Var(flag_unwind_tables) Optimization
33833387
Just generate unwind tables for exception handling.

gcc/passes.def

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -286,6 +286,10 @@ along with GCC; see the file COPYING3. If not see
286286
NEXT_PASS (pass_loop_split);
287287
NEXT_PASS (pass_scev_cprop);
288288
NEXT_PASS (pass_loop_versioning);
289+
NEXT_PASS (pass_iv_bound_versioning);
290+
PUSH_INSERT_PASSES_WITHIN (pass_iv_bound_versioning)
291+
NEXT_PASS (pass_vrp, false);
292+
POP_INSERT_PASSES ()
289293
NEXT_PASS (pass_loop_jam);
290294
/* All unswitching, final value replacement and splitting can expose
291295
empty loops. Remove them now. */

gcc/testsuite/gcc.dg/ivbound-1.c

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
/* { dg-do compile } */
2+
/* { dg-options "-O2 -fversion-loops-for-iv-overflow -fdump-tree-ivbound-details" } */
3+
4+
void
5+
test_unsigned_iv (unsigned int *arr, unsigned int n)
6+
{
7+
for (unsigned int i = 0; i < n; i++)
8+
arr[i] = i;
9+
}
10+
11+
/* { dg-final { scan-tree-dump "candidate for versioning" "ivbound" } } */
12+
/* { dg-final { scan-tree-dump "Successfully versioned loop" "ivbound" } } */

gcc/testsuite/gcc.dg/ivbound-10.c

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
/* { dg-do compile } */
2+
/* { dg-options "-O2 -fversion-loops-for-iv-overflow -fdump-tree-ivbound-details" } */
3+
4+
void
5+
test_unsigned_char_iv (unsigned char *arr, unsigned char n)
6+
{
7+
for (unsigned char i = 0; i < n; i++)
8+
arr[i] = i;
9+
}
10+
11+
/* { dg-final { scan-tree-dump "candidate for versioning" "ivbound" } } */
12+
/* { dg-final { scan-tree-dump "Successfully versioned loop" "ivbound" } } */

gcc/testsuite/gcc.dg/ivbound-11.c

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
/* { dg-do compile } */
2+
/* { dg-options "-O2 -fversion-loops-for-iv-overflow -fdump-tree-ivbound-details" } */
3+
4+
void
5+
test_decrementing_iv (unsigned int *arr, unsigned int n)
6+
{
7+
for (unsigned int i = n; i > 0; i--)
8+
arr[i - 1] = i;
9+
}
10+
11+
/* { dg-final { scan-tree-dump-not "Successfully versioned loop" "ivbound" } } */

gcc/testsuite/gcc.dg/ivbound-12.c

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
/* { dg-do compile } */
2+
/* { dg-options "-O2 -fversion-loops-for-iv-overflow -fdump-tree-ivbound-details" } */
3+
4+
void
5+
test_pointer_iv (int *start, int *end)
6+
{
7+
for (int *p = start; p < end; p++)
8+
*p = 0;
9+
}
10+
11+
/* { dg-final { scan-tree-dump-not "Found unsigned IV in loop" "ivbound" } } */

gcc/testsuite/gcc.dg/ivbound-13.c

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
/* { dg-do compile } */
2+
/* { dg-options "-O2 -fversion-loops-for-iv-overflow -fdump-tree-ivbound-details" } */
3+
4+
void
5+
test_nested_different_bounds (unsigned int *arr, unsigned int n, unsigned int m)
6+
{
7+
for (unsigned int i = 0; i < n; i++)
8+
for (unsigned int j = 0; j < m; j++)
9+
arr[i * m + j] = i + j;
10+
}
11+
12+
/* Both bounds (n, m) are invariant to both loops, so we can hoist. */
13+
/* { dg-final { scan-tree-dump "Hoisting versioning from loop" "ivbound" } } */
14+
/* { dg-final { scan-tree-dump "Successfully versioned loop" "ivbound" } } */

gcc/testsuite/gcc.dg/ivbound-14.c

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
/* { dg-do compile } */
2+
/* { dg-options "-O2 -fversion-loops-for-iv-overflow -fdump-tree-ivbound-details" } */
3+
4+
void
5+
test_inner_bound_not_invariant (unsigned int *arr, unsigned int n)
6+
{
7+
for (unsigned int i = 0; i < n; i++)
8+
for (unsigned int j = 0; j < i; j++) /* bound 'i' varies with outer loop */
9+
arr[i * n + j] = i + j;
10+
}
11+
12+
/* Inner loop's bound is not invariant to outer, cannot hoist to outer. */
13+
/* { dg-final { scan-tree-dump "Successfully versioned loop" "ivbound" } } */

gcc/testsuite/gcc.dg/ivbound-15.c

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
/* { dg-do compile } */
2+
/* { dg-options "-O2 -fversion-loops-for-iv-overflow -fdump-tree-ivbound-details" } */
3+
4+
void
5+
test_outer_signed_inner_unsigned (int *arr, int n, unsigned int m)
6+
{
7+
for (int i = 0; i < n; i++) /* signed - no versioning needed */
8+
for (unsigned int j = 0; j < m; j++) /* unsigned - needs versioning */
9+
arr[i * m + j] = i + j;
10+
}
11+
12+
/* Inner loop needs versioning. Bound 'm' is invariant to outer, so hoist. */
13+
/* { dg-final { scan-tree-dump "Successfully versioned loop" "ivbound" } } */
14+
/* { dg-final { scan-tree-dump "Hoisting versioning from loop" "ivbound" } } */

0 commit comments

Comments
 (0)