This fixes PR53676, extending SCEV analysis to analyze truncated operations by analyzing the operation on truncated operands instead.
Bootstrapped and tested on x86_64-unknown-linux-gnu, I plan to install this tomorrow. Richard. 2012-06-26 Richard Guenther <rguent...@suse.de> PR middle-end/53676 * tree-chrec.c (chrec_convert_1): Represent truncation to a type with undefined overflow as truncation to an unsigned type converted to the type with undefined overflow. * tree-scalar-evolution.c (interpret_rhs_expr): For computing the scalar evolution of a truncated widened operation avoid looking at the non-existing evolution of the widened operation result. * gcc.dg/tree-ssa/scev-6.c: New testcase. Index: gcc/tree-chrec.c =================================================================== *** gcc/tree-chrec.c (revision 188927) --- gcc/tree-chrec.c (working copy) *************** keep_cast: *** 1365,1370 **** --- 1365,1387 ---- res = fold_build2 (TREE_CODE (chrec), type, fold_convert (type, TREE_OPERAND (chrec, 0)), fold_convert (type, TREE_OPERAND (chrec, 1))); + /* Similar perform the trick that (signed char)((int)x + 2) can be + narrowed to (signed char)((unsigned char)x + 2). */ + else if (use_overflow_semantics + && TREE_CODE (chrec) == POLYNOMIAL_CHREC + && TREE_CODE (ct) == INTEGER_TYPE + && TREE_CODE (type) == INTEGER_TYPE + && TYPE_OVERFLOW_UNDEFINED (type) + && TYPE_PRECISION (type) < TYPE_PRECISION (ct)) + { + tree utype = unsigned_type_for (type); + res = build_polynomial_chrec (CHREC_VARIABLE (chrec), + fold_convert (utype, + CHREC_LEFT (chrec)), + fold_convert (utype, + CHREC_RIGHT (chrec))); + res = chrec_convert_1 (type, res, at_stmt, use_overflow_semantics); + } else res = fold_convert (type, chrec); Index: gcc/tree-scalar-evolution.c =================================================================== *** gcc/tree-scalar-evolution.c (revision 188927) --- gcc/tree-scalar-evolution.c (working copy) *************** interpret_rhs_expr (struct loop *loop, g *** 1634,1639 **** --- 1634,1640 ---- tree type, tree rhs1, enum tree_code code, tree rhs2) { tree res, chrec1, chrec2; + gimple def; if (get_gimple_rhs_class (code) == GIMPLE_SINGLE_RHS) { *************** interpret_rhs_expr (struct loop *loop, g *** 1759,1765 **** break; CASE_CONVERT: ! chrec1 = analyze_scalar_evolution (loop, rhs1); res = chrec_convert (type, chrec1, at_stmt); break; --- 1760,1788 ---- break; CASE_CONVERT: ! /* In case we have a truncation of a widened operation that in ! the truncated type has undefined overflow behavior analyze ! the operation done in an unsigned type of the same precision ! as the final truncation. We cannot derive a scalar evolution ! for the widened operation but for the truncated result. */ ! if (TREE_CODE (type) == INTEGER_TYPE ! && TREE_CODE (TREE_TYPE (rhs1)) == INTEGER_TYPE ! && TYPE_PRECISION (type) < TYPE_PRECISION (TREE_TYPE (rhs1)) ! && TYPE_OVERFLOW_UNDEFINED (type) ! && TREE_CODE (rhs1) == SSA_NAME ! && (def = SSA_NAME_DEF_STMT (rhs1)) ! && is_gimple_assign (def) ! && TREE_CODE_CLASS (gimple_assign_rhs_code (def)) == tcc_binary ! && TREE_CODE (gimple_assign_rhs2 (def)) == INTEGER_CST) ! { ! tree utype = unsigned_type_for (type); ! chrec1 = interpret_rhs_expr (loop, at_stmt, utype, ! gimple_assign_rhs1 (def), ! gimple_assign_rhs_code (def), ! gimple_assign_rhs2 (def)); ! } ! else ! chrec1 = analyze_scalar_evolution (loop, rhs1); res = chrec_convert (type, chrec1, at_stmt); break; Index: gcc/testsuite/gcc.dg/tree-ssa/scev-6.c =================================================================== *** gcc/testsuite/gcc.dg/tree-ssa/scev-6.c (revision 0) --- gcc/testsuite/gcc.dg/tree-ssa/scev-6.c (revision 0) *************** *** 0 **** --- 1,23 ---- + /* { dg-do run } */ + /* { dg-options "-O2 -fdump-tree-optimized" } */ + + int main() + { + int i; + signed char result = 0; + for (i = 0; i != 8000; ++i) + { + int tem = result; + tem = tem + 2; + result = tem; + } + if (__builtin_abs ((int)(signed char)((unsigned char ) result + 128)) != 0) + __builtin_abort (); + return 0; + } + + /* SCEV constant propagation should be able to compute the overall effect + of the loop. */ + + /* { dg-final { scan-tree-dump-not "abort" "optimized" } } */ + /* { dg-final { cleanup-tree-dump "optimized" } } */