https://gcc.gnu.org/bugzilla/show_bug.cgi?id=65855
--- Comment #4 from Richard Biener <rguenth at gcc dot gnu.org> --- match.pd now has the desired simplification. So we run into (chrec_apply (varying_loop = 1 ) (chrec = {1, +, {2, +, 1}_1}_1) (x = (long unsigned int) n_3(D) + 18446744073709551615) (res = scev_not_known)) the question is if we can handle this kind of CHREC in chrec_apply generally or not. { x, +, { y, +, C}_N }_N specifically. I suppose it's simply x + y*X + C*X*(X+1)/2. Now the question is whether it's generally profitable to handle this. We'll see. I have a patch that produces (chrec_apply (varying_loop = 1 ) (chrec = {1, +, {2, +, 1}_1}_1) (x = (long unsigned int) n_3(D) + 18446744073709551615) (res = (((long unsigned int) n_3(D) * ((long unsigned int) n_3(D) + 18446744073709551615)) /[ex] 2 + (uint64_t) n_3(D) * 2) + 18446744073709551615)) but that's somehow off. Index: gcc/tree-chrec.c =================================================================== --- gcc/tree-chrec.c (revision 229233) +++ gcc/tree-chrec.c (working copy) @@ -602,19 +602,37 @@ chrec_apply (unsigned var, switch (TREE_CODE (chrec)) { case POLYNOMIAL_CHREC: - if (evolution_function_is_affine_p (chrec)) + if (CHREC_VARIABLE (chrec) != var) + return build_polynomial_chrec + (CHREC_VARIABLE (chrec), + chrec_apply (var, CHREC_LEFT (chrec), x), + chrec_apply (var, CHREC_RIGHT (chrec), x)); + else if (evolution_function_is_affine_p (chrec)) { - if (CHREC_VARIABLE (chrec) != var) - return build_polynomial_chrec - (CHREC_VARIABLE (chrec), - chrec_apply (var, CHREC_LEFT (chrec), x), - chrec_apply (var, CHREC_RIGHT (chrec), x)); - /* "{a, +, b} (x)" -> "a + b*x". */ x = chrec_convert_rhs (type, x, NULL); res = chrec_fold_multiply (TREE_TYPE (x), CHREC_RIGHT (chrec), x); res = chrec_fold_plus (type, CHREC_LEFT (chrec), res); } + else if (evolution_function_is_affine_p (CHREC_RIGHT (chrec)) + && CHREC_VARIABLE (CHREC_RIGHT (chrec)) == var) + { + /* "{a, +, {b, +, c} } (x)" -> "a + b*x + c*x*(x+1)/2". */ + tree chrecr = CHREC_RIGHT (chrec); + x = chrec_convert_rhs (type, x, NULL); + /* c*x*(x+1)/2 */ + res = chrec_fold_plus (type, x, build_int_cst (type, 1)); + res = chrec_fold_multiply (type, res, x); + res = fold_build2 (EXACT_DIV_EXPR, type, res, + build_int_cst (type, 2)); + res = chrec_fold_multiply (type, CHREC_RIGHT (chrecr), res); + /* + b*x */ + res = chrec_fold_plus (type, res, + chrec_fold_multiply (type, x, + CHREC_LEFT (chrecr))); + /* + a */ + res = chrec_fold_plus (type, res, CHREC_LEFT (chrec)); + } else if (TREE_CODE (x) == INTEGER_CST && tree_int_cst_sgn (x) == 1) /* testsuite/.../ssa-chrec-38.c. */ produces 76 for n == 11 and 298 for n == 23. Testcase that works with SCCP disabled: extern void abort (void); typedef __UINT64_TYPE__ uint64_t; typedef __UINT32_TYPE__ uint32_t; uint64_t __attribute__((noinline,noclone)) triangle(uint32_t n) { uint64_t t = 0; for (uint64_t i=1;i<=n;i++) t += i; return t; } int main() { uint64_t t11 = triangle (11); uint64_t t23 = triangle (23); if (t11 != 66 || t23 != 276) abort (); return 0; }