The following fixes bogus SCEV analysis for expressions that are only executed conditionally [note: conditionally here doesn't include after a taken exit]. Basically we have to make sure further analysis does not attempt to use undefined overflow for expressions we don't know whether they are computed in the original source (for all loop iterations). This would result in bogus CHRECs as can be seen in this PR.
The solution is to re-write those expressions in a way so overflow behavior is well-defined. Bootstrapped and tested on x86_64-unknown-linux-gnu, applied to trunk. Richard. 2016-02-24 Richard Biener <rguent...@suse.de> Jakub Jelinek <ja...@redhat.com> PR middle-end/69760 * tree-scalar-evolution.c (interpret_rhs_expr): Re-write conditionally executed ops to well-defined overflow behavior. * gcc.dg/torture/pr69760.c: New testcase. Index: gcc/tree-scalar-evolution.c =================================================================== --- gcc/tree-scalar-evolution.c (revision 233634) +++ gcc/tree-scalar-evolution.c (working copy) @@ -1703,7 +1703,7 @@ static tree interpret_rhs_expr (struct loop *loop, gimple *at_stmt, tree type, tree rhs1, enum tree_code code, tree rhs2) { - tree res, chrec1, chrec2; + tree res, chrec1, chrec2, ctype; gimple *def; if (get_gimple_rhs_class (code) == GIMPLE_SINGLE_RHS) @@ -1798,30 +1798,63 @@ interpret_rhs_expr (struct loop *loop, g case PLUS_EXPR: chrec1 = analyze_scalar_evolution (loop, rhs1); chrec2 = analyze_scalar_evolution (loop, rhs2); - chrec1 = chrec_convert (type, chrec1, at_stmt); - chrec2 = chrec_convert (type, chrec2, at_stmt); + ctype = type; + /* When the stmt is conditionally executed re-write the CHREC + into a form that has well-defined behavior on overflow. */ + if (at_stmt + && INTEGRAL_TYPE_P (type) + && ! TYPE_OVERFLOW_WRAPS (type) + && ! dominated_by_p (CDI_DOMINATORS, loop->latch, + gimple_bb (at_stmt))) + ctype = unsigned_type_for (type); + chrec1 = chrec_convert (ctype, chrec1, at_stmt); + chrec2 = chrec_convert (ctype, chrec2, at_stmt); chrec1 = instantiate_parameters (loop, chrec1); chrec2 = instantiate_parameters (loop, chrec2); - res = chrec_fold_plus (type, chrec1, chrec2); + res = chrec_fold_plus (ctype, chrec1, chrec2); + if (type != ctype) + res = chrec_convert (type, res, at_stmt); break; case MINUS_EXPR: chrec1 = analyze_scalar_evolution (loop, rhs1); chrec2 = analyze_scalar_evolution (loop, rhs2); - chrec1 = chrec_convert (type, chrec1, at_stmt); - chrec2 = chrec_convert (type, chrec2, at_stmt); + ctype = type; + /* When the stmt is conditionally executed re-write the CHREC + into a form that has well-defined behavior on overflow. */ + if (at_stmt + && INTEGRAL_TYPE_P (type) + && ! TYPE_OVERFLOW_WRAPS (type) + && ! dominated_by_p (CDI_DOMINATORS, + loop->latch, gimple_bb (at_stmt))) + ctype = unsigned_type_for (type); + chrec1 = chrec_convert (ctype, chrec1, at_stmt); + chrec2 = chrec_convert (ctype, chrec2, at_stmt); chrec1 = instantiate_parameters (loop, chrec1); chrec2 = instantiate_parameters (loop, chrec2); - res = chrec_fold_minus (type, chrec1, chrec2); + res = chrec_fold_minus (ctype, chrec1, chrec2); + if (type != ctype) + res = chrec_convert (type, res, at_stmt); break; case NEGATE_EXPR: chrec1 = analyze_scalar_evolution (loop, rhs1); - chrec1 = chrec_convert (type, chrec1, at_stmt); + ctype = type; + /* When the stmt is conditionally executed re-write the CHREC + into a form that has well-defined behavior on overflow. */ + if (at_stmt + && INTEGRAL_TYPE_P (type) + && ! TYPE_OVERFLOW_WRAPS (type) + && ! dominated_by_p (CDI_DOMINATORS, + loop->latch, gimple_bb (at_stmt))) + ctype = unsigned_type_for (type); + chrec1 = chrec_convert (ctype, chrec1, at_stmt); /* TYPE may be integer, real or complex, so use fold_convert. */ chrec1 = instantiate_parameters (loop, chrec1); - res = chrec_fold_multiply (type, chrec1, - fold_convert (type, integer_minus_one_node)); + res = chrec_fold_multiply (ctype, chrec1, + fold_convert (ctype, integer_minus_one_node)); + if (type != ctype) + res = chrec_convert (type, res, at_stmt); break; case BIT_NOT_EXPR: @@ -1837,11 +1870,22 @@ interpret_rhs_expr (struct loop *loop, g case MULT_EXPR: chrec1 = analyze_scalar_evolution (loop, rhs1); chrec2 = analyze_scalar_evolution (loop, rhs2); - chrec1 = chrec_convert (type, chrec1, at_stmt); - chrec2 = chrec_convert (type, chrec2, at_stmt); + ctype = type; + /* When the stmt is conditionally executed re-write the CHREC + into a form that has well-defined behavior on overflow. */ + if (at_stmt + && INTEGRAL_TYPE_P (type) + && ! TYPE_OVERFLOW_WRAPS (type) + && ! dominated_by_p (CDI_DOMINATORS, + loop->latch, gimple_bb (at_stmt))) + ctype = unsigned_type_for (type); + chrec1 = chrec_convert (ctype, chrec1, at_stmt); + chrec2 = chrec_convert (ctype, chrec2, at_stmt); chrec1 = instantiate_parameters (loop, chrec1); chrec2 = instantiate_parameters (loop, chrec2); - res = chrec_fold_multiply (type, chrec1, chrec2); + res = chrec_fold_multiply (ctype, chrec1, chrec2); + if (type != ctype) + res = chrec_convert (type, res, at_stmt); break; case LSHIFT_EXPR: Index: gcc/testsuite/gcc.dg/torture/pr69760.c =================================================================== --- gcc/testsuite/gcc.dg/torture/pr69760.c (revision 0) +++ gcc/testsuite/gcc.dg/torture/pr69760.c (working copy) @@ -0,0 +1,50 @@ +/* PR tree-optimization/69760 */ +/* { dg-do run { target { { *-*-linux* *-*-gnu* } && mmap } } } */ +/* { dg-options "-O2" } */ + +#include <unistd.h> +#include <sys/mman.h> + +__attribute__((noinline, noclone)) void +test_func (double *a, int L, int m, int n, int N) +{ + int i, k; + for (i = 0; i < N; i++) + { + k = i - m; + if (k >= 0 && k < n) + a[L * k] = 0.0; + } +} + +int +main () +{ + char *p; + int L, m, n, N; + long l; + L = 10000000; + n = 4; + N = 100 * n; + long pgsz = sysconf(_SC_PAGESIZE); + if (pgsz < sizeof (double) || pgsz > L * sizeof (double)) + return 0; + p = mmap ((void *) 0, L * n * sizeof (double), PROT_NONE, + MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); + if (p == MAP_FAILED) + return 0; + if (mprotect (p, pgsz, PROT_READ | PROT_WRITE)) + return 0; + l = (L * sizeof (double)) / pgsz * pgsz; + if (mprotect (p + l, pgsz, PROT_READ | PROT_WRITE)) + return 0; + l = (2 * L * sizeof (double)) / pgsz * pgsz; + if (mprotect (p + l, pgsz, PROT_READ | PROT_WRITE)) + return 0; + l = (3 * L * sizeof (double)) / pgsz * pgsz; + if (mprotect (p + l, pgsz, PROT_READ | PROT_WRITE)) + return 0; + for (m = 0; m < N; m += n) + test_func ((double *) p, L, m, n, N); + return 0; +}