Hi! As mentioned in the PR, the LSHIFT_EXPR computation of values that will need longest or shortest string is both incorrect (it shifts integer_one_node left, so for precisions above precision of integer it returns 0 (not to mention that it is invalid GENERIC, because the types of first operand and result have to match)) and unnecessary - every integral type already has TYPE_MIN_VALUE and TYPE_MAX_VALUE readily available.
Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk? Note, in the PR I've raised various further questions, Martin, can you look at them? 2016-11-29 Jakub Jelinek <ja...@redhat.com> PR tree-optimization/78586 * gimple-ssa-sprintf.c (format_integer): Use TYPE_MAX_VALUE or TYPE_MIN_VALUE or build_all_ones_cst instead of folding LSHIFT_EXPR. Don't build_int_cst min/max twice. Formatting fix. * gcc.c-torture/execute/pr78586.c: New test. --- gcc/gimple-ssa-sprintf.c.jj 2016-11-28 23:50:20.000000000 +0100 +++ gcc/gimple-ssa-sprintf.c 2016-11-29 15:54:17.605892667 +0100 @@ -1068,7 +1068,8 @@ format_integer (const conversion_spec &s tree argmin = NULL_TREE; tree argmax = NULL_TREE; - if (arg && TREE_CODE (arg) == SSA_NAME + if (arg + && TREE_CODE (arg) == SSA_NAME && TREE_CODE (argtype) == INTEGER_TYPE) { /* Try to determine the range of values of the integer argument @@ -1090,12 +1091,8 @@ format_integer (const conversion_spec &s the upper bound for %i but -3 for %u. */ if (wi::neg_p (min) && !wi::neg_p (max)) { - argmin = build_int_cst (argtype, wi::fits_uhwi_p (min) - ? min.to_uhwi () : min.to_shwi ()); - - argmax = build_int_cst (argtype, wi::fits_uhwi_p (max) - ? max.to_uhwi () : max.to_shwi ()); - + argmin = res.argmin; + argmax = res.argmax; int minbytes = format_integer (spec, res.argmin).range.min; int maxbytes = format_integer (spec, res.argmax).range.max; if (maxbytes < minbytes) @@ -1154,21 +1151,25 @@ format_integer (const conversion_spec &s int typeprec = TYPE_PRECISION (dirtype); int argprec = TYPE_PRECISION (argtype); - if (argprec < typeprec || POINTER_TYPE_P (argtype)) + if (argprec < typeprec) { - if (TYPE_UNSIGNED (argtype)) + if (POINTER_TYPE_P (argtype)) argmax = build_all_ones_cst (argtype); + else if (TYPE_UNSIGNED (argtype)) + argmax = TYPE_MAX_VALUE (argtype); else - argmax = fold_build2 (LSHIFT_EXPR, argtype, integer_one_node, - build_int_cst (integer_type_node, - argprec - 1)); + argmax = TYPE_MIN_VALUE (argtype); } else { - argmax = fold_build2 (LSHIFT_EXPR, dirtype, integer_one_node, - build_int_cst (integer_type_node, - typeprec - 1)); + if (POINTER_TYPE_P (dirtype)) + argmax = build_all_ones_cst (dirtype); + else if (TYPE_UNSIGNED (dirtype)) + argmax = TYPE_MAX_VALUE (dirtype); + else + argmax = TYPE_MIN_VALUE (dirtype); } + res.argmin = argmin; res.argmax = argmax; } --- gcc/testsuite/gcc.c-torture/execute/pr78586.c.jj 2016-11-29 16:11:35.283742461 +0100 +++ gcc/testsuite/gcc.c-torture/execute/pr78586.c 2016-11-29 16:11:16.000000000 +0100 @@ -0,0 +1,17 @@ +/* PR tree-optimization/78586 */ + +void +foo (unsigned long x) +{ + char a[30]; + unsigned long b = __builtin_sprintf (a, "%lu", x); + if (b != 4) + __builtin_abort (); +} + +int +main () +{ + foo (1000); + return 0; +} Jakub