From: Martin Sebor Date: Tue, 3 Jan 2017 23:14:44 +0000 (-0700) Subject: PR tree-optimization/78696 - [7 Regression] -fprintf-return-value misoptimizes %... X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=5b4f088d0d203c56898f7957366255d33b6b41a6;p=gcc.git PR tree-optimization/78696 - [7 Regression] -fprintf-return-value misoptimizes %.Ng where N is greater than 10 gcc/ChangeLog: PR tree-optimization/78696 * gimple-ssa-sprintf.c (format_floating): Correct handling of precision. Use MPFR for %f for greater fidelity. Correct handling of %g. (pass_sprintf_length::compute_format_length): Set width and precision specified by asrerisk to void_node for vararg functions. (try_substitute_return_value): Adjust dump output. gcc/testsuite/ChangeLog: PR tree-optimization/78696 * gcc.dg/tree-ssa/builtin-sprintf-5.c: Remove incorrect test cases. * gcc.dg/tree-ssa/builtin-sprintf-warn-7.c: Correct off-by-1 errors. * gcc.dg/tree-ssa/builtin-sprintf-warn-9.c: New test. * gcc.dg/tree-ssa/builtin-sprintf.c: Add test cases. From-SVN: r244037 --- diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 179cd099e12..882856412e2 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,13 @@ +2017-01-03 Martin Sebor + + PR tree-optimization/78696 + * gimple-ssa-sprintf.c (format_floating): Correct handling of + precision. Use MPFR for %f for greater fidelity. Correct handling + of %g. + (pass_sprintf_length::compute_format_length): Set width and precision + specified by asrerisk to void_node for vararg functions. + (try_substitute_return_value): Adjust dump output. + 2017-01-03 David Edelsohn * doc/invoke.texi (RS6000 options): LRA is enabled by default. diff --git a/gcc/gimple-ssa-sprintf.c b/gcc/gimple-ssa-sprintf.c index 5bf0215cf1e..d468cd7f369 100644 --- a/gcc/gimple-ssa-sprintf.c +++ b/gcc/gimple-ssa-sprintf.c @@ -483,9 +483,11 @@ struct conversion_spec /* Numeric precision as in "%.32s". */ int precision; - /* Width specified via the '*' character. */ + /* Width specified via the '*' character. Need not be INTEGER_CST. + For vararg functions set to void_node. */ tree star_width; - /* Precision specified via the asterisk. */ + /* Precision specified via the asterisk. Need not be INTEGER_CST. + For vararg functions set to void_node. */ tree star_precision; /* Length modifier. */ @@ -1246,15 +1248,26 @@ get_mpfr_format_length (mpfr_ptr x, const char *flags, HOST_WIDE_INT prec, fmtstr[len + 5] = spec; fmtstr[len + 6] = '\0'; - /* Avoid passing negative precisions with larger magnitude to MPFR - to avoid exposing its bugs. (A negative precision is supposed - to be ignored.) */ - if (prec < 0) - prec = -1; + spec = TOUPPER (spec); + if (spec == 'E' || spec == 'F') + { + /* For %e, specify the precision explicitly since mpfr_sprintf + does its own thing just to be different (see MPFR bug 21088). */ + if (prec < 0) + prec = 6; + } + else + { + /* Avoid passing negative precisions with larger magnitude to MPFR + to avoid exposing its bugs. (A negative precision is supposed + to be ignored.) */ + if (prec < 0) + prec = -1; + } HOST_WIDE_INT p = prec; - if (TOUPPER (spec) == 'G') + if (spec == 'G') { /* For G/g, precision gives the maximum number of significant digits which is bounded by LDBL_MAX_10_EXP, or, for a 128 @@ -1287,7 +1300,8 @@ get_mpfr_format_length (mpfr_ptr x, const char *flags, HOST_WIDE_INT prec, } /* Return the number of bytes to format using the format specifier - SPEC the largest value in the real floating TYPE. */ + SPEC and the precision PREC the largest value in the real floating + TYPE. */ static unsigned HOST_WIDE_INT format_floating_max (tree type, char spec, HOST_WIDE_INT prec) @@ -1329,7 +1343,6 @@ format_floating (const conversion_spec &spec, HOST_WIDE_INT width, HOST_WIDE_INT prec) { tree type; - bool ldbl = false; switch (spec.modifier) { @@ -1340,12 +1353,10 @@ format_floating (const conversion_spec &spec, HOST_WIDE_INT width, case FMT_LEN_L: type = long_double_type_node; - ldbl = true; break; case FMT_LEN_ll: type = long_double_type_node; - ldbl = true; break; default: @@ -1355,95 +1366,94 @@ format_floating (const conversion_spec &spec, HOST_WIDE_INT width, /* The minimum and maximum number of bytes produced by the directive. */ fmtresult res; - /* Log10 of of the maximum number of exponent digits for the type. */ - int logexpdigs = 2; + /* The result is always bounded (though the range may be all of int). */ + res.bounded = true; - if (REAL_MODE_FORMAT (TYPE_MODE (type))->b == 2) - { - /* The base in which the exponent is represented should always - be 2 in GCC. */ + /* The minimum output as determined by flags. It's always at least 1. */ + int flagmin = (1 /* for the first digit */ + + (spec.get_flag ('+') | spec.get_flag (' ')) + + (prec == 0 && spec.get_flag ('#'))); - const double log10_2 = .30102999566398119521; - - /* Compute T_MAX_EXP for base 2. */ - int expdigs = REAL_MODE_FORMAT (TYPE_MODE (type))->emax * log10_2; - logexpdigs = ilog (expdigs, 10); + if (width == INT_MIN || prec == INT_MIN) + { + /* When either width or precision is specified but unknown + the upper bound is the maximum. Otherwise it will be + computed for each directive below. */ + res.range.max = HOST_WIDE_INT_MAX; } + else + res.range.max = HOST_WIDE_INT_M1U; switch (spec.specifier) { case 'A': case 'a': { - /* The minimum output is "0x.p+0". */ - res.range.min = 6 + (prec > 0 ? prec : 0); - res.range.max = (width == INT_MIN - ? HOST_WIDE_INT_MAX - : format_floating_max (type, 'a', prec)); - - /* The output of "%a" is fully specified only when precision - is explicitly specified and width isn't unknown. */ - res.bounded = INT_MIN != width && -1 < prec; + res.range.min = flagmin + 5 + (prec > 0 ? prec + 1 : 0); + if (res.range.max == HOST_WIDE_INT_M1U) + { + /* Compute the upper bound for -TYPE_MAX. */ + res.range.max = format_floating_max (type, 'a', prec); + } + break; } case 'E': case 'e': { - bool sign = spec.get_flag ('+') || spec.get_flag (' '); /* The minimum output is "[-+]1.234567e+00" regardless of the value of the actual argument. */ - res.range.min = (sign - + 1 /* unit */ + (prec < 0 ? 7 : prec ? prec + 1 : 0) + res.range.min = (flagmin + + (prec == INT_MIN + ? 0 : prec < 0 ? 7 : prec ? prec + 1 : 0) + 2 /* e+ */ + 2); - /* Unless width is uknown the maximum output is the minimum plus - sign (unless already included), plus the difference between - the minimum exponent of 2 and the maximum exponent for the type. */ - res.range.max = (width == INT_MIN - ? HOST_WIDE_INT_M1U - : res.range.min + !sign + logexpdigs - 2); - - /* "%e" is fully specified and the range of bytes is bounded - unless width is unknown. */ - res.bounded = INT_MIN != width; + + if (res.range.max == HOST_WIDE_INT_M1U) + { + /* MPFR uses a precision of 16 by default for some reason. + Set it to the C default of 6. */ + res.range.max = format_floating_max (type, 'e', + -1 == prec ? 6 : prec); + } break; } case 'F': case 'f': { - /* The minimum output is "1.234567" regardless of the value - of the actual argument. */ - res.range.min = 2 + (prec < 0 ? 6 : prec); - - /* Compute the maximum just once. */ - const HOST_WIDE_INT f_max[] = { - format_floating_max (double_type_node, 'f', prec), - format_floating_max (long_double_type_node, 'f', prec) - }; - res.range.max = width == INT_MIN ? HOST_WIDE_INT_MAX : f_max [ldbl]; - - /* "%f" is fully specified and the range of bytes is bounded - unless width is unknown. */ - res.bounded = INT_MIN != width; + /* The lower bound when precision isn't specified is 8 bytes + ("1.23456" since precision is taken to be 6). When precision + is zero, the lower bound is 1 byte (e.g., "1"). Otherwise, + when precision is greater than zero, then the lower bound + is 2 plus precision (plus flags). */ + res.range.min = (flagmin + + (prec != INT_MIN) /* for decimal point */ + + (prec == INT_MIN + ? 0 : prec < 0 ? 6 : prec ? prec : -1)); + + if (res.range.max == HOST_WIDE_INT_M1U) + { + /* Compute the upper bound for -TYPE_MAX. */ + res.range.max = format_floating_max (type, 'f', prec); + } break; } + case 'G': case 'g': { - /* The minimum is the same as for '%F'. */ - res.range.min = 1; - - /* Compute the maximum just once. */ - const HOST_WIDE_INT g_max[] = { - format_floating_max (double_type_node, 'g', prec), - format_floating_max (long_double_type_node, 'g', prec) - }; - res.range.max = width == INT_MIN ? HOST_WIDE_INT_MAX : g_max [ldbl]; - - /* "%g" is fully specified and the range of bytes is bounded - unless width is unknown. */ - res.bounded = INT_MIN != width; + /* The %g output depends on precision and the exponent of + the argument. Since the value of the argument isn't known + the lower bound on the range of bytes (not counting flags + or width) is 1. */ + res.range.min = flagmin; + if (res.range.max == HOST_WIDE_INT_M1U) + { + /* Compute the upper bound for -TYPE_MAX which should be + the lesser of %e and %f. */ + res.range.max = format_floating_max (type, 'g', prec); + } break; } @@ -1453,6 +1463,7 @@ format_floating (const conversion_spec &spec, HOST_WIDE_INT width, if (width > 0) { + /* If width has been specified use it to adjust the range. */ if (res.range.min < (unsigned)width) res.range.min = width; if (res.range.max < (unsigned)width) @@ -1469,9 +1480,9 @@ format_floating (const conversion_spec &spec, HOST_WIDE_INT width, static fmtresult format_floating (const conversion_spec &spec, tree arg) { - /* Set WIDTH to -1 when it's not specified, to INT_MIN when it is - specified by the asterisk to an unknown value, and otherwise to - a non-negative value corresponding to the specified width. */ + /* Set WIDTH to -1 when it's not specified, to HOST_WIDE_INT_MIN when + it is specified by the asterisk to an unknown value, and otherwise + to a non-negative value corresponding to the specified width. */ HOST_WIDE_INT width = -1; HOST_WIDE_INT prec = -1; @@ -1498,13 +1509,13 @@ format_floating (const conversion_spec &spec, tree arg) else if (spec.star_precision) { if (TREE_CODE (spec.star_precision) == INTEGER_CST) - prec = tree_to_shwi (spec.star_precision); - else { - /* FIXME: Handle non-constant precision. */ - res.range.min = res.range.max = HOST_WIDE_INT_M1U; - return res; + prec = tree_to_shwi (spec.star_precision); + if (prec < 0) + prec = -1; } + else + prec = INT_MIN; } else if (res.constant && TOUPPER (spec.specifier) != 'A') { @@ -1515,11 +1526,6 @@ format_floating (const conversion_spec &spec, tree arg) if (res.constant) { - /* Set up an array to easily iterate over. */ - unsigned HOST_WIDE_INT* const minmax[] = { - &res.range.min, &res.range.max - }; - /* Get the real type format desription for the target. */ const REAL_VALUE_TYPE *rvp = TREE_REAL_CST_PTR (arg); const real_format *rfmt = REAL_MODE_FORMAT (TYPE_MODE (TREE_TYPE (arg))); @@ -1541,26 +1547,42 @@ format_floating (const conversion_spec &spec, tree arg) *pfmt = '\0'; - for (int i = 0; i != sizeof minmax / sizeof *minmax; ++i) + { + /* Set up an array to easily iterate over below. */ + unsigned HOST_WIDE_INT* const minmax[] = { + &res.range.min, &res.range.max + }; + + for (int i = 0; i != sizeof minmax / sizeof *minmax; ++i) + { + /* Use the MPFR rounding specifier to round down in the first + iteration and then up. In most but not all cases this will + result in the same number of bytes. */ + char rndspec = "DU"[i]; + + /* Format it and store the result in the corresponding member + of the result struct. */ + unsigned HOST_WIDE_INT len + = get_mpfr_format_length (mpfrval, fmtstr, prec, + spec.specifier, rndspec); + if (0 < width && len < (unsigned)width) + len = width; + + *minmax[i] = len; + } + } + + /* Make sure the minimum is less than the maximum (MPFR rounding + in the call to mpfr_snprintf can result in the reverse. */ + if (res.range.max < res.range.min) { - /* Use the MPFR rounding specifier to round down in the first - iteration and then up. In most but not all cases this will - result in the same number of bytes. */ - char rndspec = "DU"[i]; - - /* Format it and store the result in the corresponding member - of the result struct. */ - unsigned HOST_WIDE_INT len - = get_mpfr_format_length (mpfrval, fmtstr, prec, - spec.specifier, rndspec); - if (0 < width && len < (unsigned)width) - len = width; - - *minmax[i] = len; + unsigned HOST_WIDE_INT tmp = res.range.min; + res.range.min = res.range.max; + res.range.max = tmp; } /* The range of output is known even if the result isn't bounded. */ - if (width == INT_MIN) + if (width == HOST_WIDE_INT_MIN) { res.knownrange = false; res.range.max = HOST_WIDE_INT_MAX; @@ -2420,10 +2442,10 @@ pass_sprintf_length::compute_format_length (call_info &info, { /* Similarly to the block above, this could be either a POSIX positional argument or a width, depending on what follows. */ - if (gimple_call_num_args (info.callstmt) <= argno) - return false; - - spec.star_width = gimple_call_arg (info.callstmt, argno++); + if (argno < gimple_call_num_args (info.callstmt)) + spec.star_width = gimple_call_arg (info.callstmt, argno++); + else + spec.star_width = void_node; ++pf; } @@ -2499,7 +2521,10 @@ pass_sprintf_length::compute_format_length (call_info &info, } else if ('*' == *pf) { - spec.star_width = gimple_call_arg (info.callstmt, argno++); + if (argno < gimple_call_num_args (info.callstmt)) + spec.star_width = gimple_call_arg (info.callstmt, argno++); + else + spec.star_width = void_node; ++pf; } else if ('\'' == *pf) @@ -2527,7 +2552,10 @@ pass_sprintf_length::compute_format_length (call_info &info, } else if ('*' == *pf) { - spec.star_precision = gimple_call_arg (info.callstmt, argno++); + if (argno < gimple_call_num_args (info.callstmt)) + spec.star_precision = gimple_call_arg (info.callstmt, argno++); + else + spec.star_precision = void_node; ++pf; } else @@ -2795,11 +2823,11 @@ try_substitute_return_value (gimple_stmt_iterator *gsi, fprintf (dump_file, " %s-bounds return value in range [%lu, %lu]%s.\n", inbounds, - (unsigned long)res.number_chars_min, - (unsigned long)res.number_chars_max, ign); + (unsigned long)res.number_chars_min - 1, + (unsigned long)res.number_chars_max - 1, ign); else fprintf (dump_file, " %s-bounds return value %lu%s.\n", - inbounds, (unsigned long)res.number_chars, ign); + inbounds, (unsigned long)res.number_chars - 1, ign); } } } diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 8155754f847..c12b94a85f9 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,43 @@ +2017-01-03 Martin Sebor + + PR tree-optimization/78696 + * gcc.dg/tree-ssa/builtin-sprintf-5.c: Remove incorrect test cases. + * gcc.dg/tree-ssa/builtin-sprintf-warn-7.c: Correct off-by-1 errors. + * gcc.dg/tree-ssa/builtin-sprintf-warn-9.c: New test. + * gcc.dg/tree-ssa/builtin-sprintf.c: Add test cases. + +2017-01-03 David Malcolm + + * gcc.dg/dg-test-1.c: Add tests of relative line specifications + with more than one digit. + * lib/gcc-dg.exp (process-message): Support more than one digit + in relative line specifications. + +2017-01-03 Jakub Jelinek + + PR tree-optimization/78965 + * gcc.dg/pr78965.c: New test. + + PR middle-end/78901 + * g++.dg/opt/pr78901.C: New test. + +2017-01-03 Janne Blomqvist + + PR fortran/78534 + PR fortran/66310 + * gfortran.dg/dependency_49.f90: Change scan-tree-dump-times + due to gfc_trans_string_copy change to avoid -Wstringop-overflow. + * gfortran.dg/repeat_4.f90: Use integers of kind C_SIZE_T. + * gfortran.dg/repeat_7.f90: New test for PR 66310. + * gfortran.dg/scan_2.f90: Handle potential cast in assignment. + * gfortran.dg/string_1.f90: Limit to ilp32 targets. + * gfortran.dg/string_1_lp64.f90: New test. + * gfortran.dg/string_3.f90: Limit to ilp32 targets. + * gfortran.dg/string_3_lp64.f90: New test. + * gfortran.dg/transfer_intrinsic_1.f90: Change + scan-tree-dump-times due to gfc_trans_string_copy change to + avoid -Wstringop-overflow. + 2017-01-02 Uros Bizjak PR target/78967 diff --git a/gcc/testsuite/gcc.dg/tree-ssa/builtin-sprintf-5.c b/gcc/testsuite/gcc.dg/tree-ssa/builtin-sprintf-5.c index c4489acb360..c915a351f53 100644 --- a/gcc/testsuite/gcc.dg/tree-ssa/builtin-sprintf-5.c +++ b/gcc/testsuite/gcc.dg/tree-ssa/builtin-sprintf-5.c @@ -21,6 +21,7 @@ FAIL (__LINE__)(value); \ } while (0) +/* Verify that EXPECT == snprintf(0, 0, ...). */ #define EQL(expect, ...) \ do { \ int n = __builtin_snprintf (0, 0, __VA_ARGS__); \ @@ -140,6 +141,7 @@ void test_arg_multiarg (int i, double d) EQL (16, "%*i %s", 12, i, "abc"); } +/* Verify that EXPECT == vsnprintf(0, 0, ...). */ #define EQLv(expect, fmt, va) \ do { \ int n = __builtin_vsnprintf (0, 0, fmt, va); \ @@ -149,9 +151,7 @@ void test_arg_multiarg (int i, double d) void test_va_int (__builtin_va_list va) { EQLv ( 2, "%02hhx", va); - EQLv ( 2, "%02.*hhx", va); EQLv ( 4, "%04hx", va); - EQLv ( 4, "%04.*hx", va); } void test_va_multiarg (__builtin_va_list va) diff --git a/gcc/testsuite/gcc.dg/tree-ssa/builtin-sprintf-warn-7.c b/gcc/testsuite/gcc.dg/tree-ssa/builtin-sprintf-warn-7.c index 0069348a75b..778725500bd 100644 --- a/gcc/testsuite/gcc.dg/tree-ssa/builtin-sprintf-warn-7.c +++ b/gcc/testsuite/gcc.dg/tree-ssa/builtin-sprintf-warn-7.c @@ -63,11 +63,14 @@ void test_floating_a_var (double x) T (0, "%.*a", INT_MIN, x); /* { dg-warning "writing between 6 and 24 bytes" } */ - T (0, "%.*a", INT_MAX, x); /* { dg-warning "writing between 2147483653 and 2147483658 bytes" } */ + /* Expected output is "0x0." followed by INT_MAX digits followed by + "p+" followed by 1 to four digits, with a byte count in the range + [3 + INT_MAX + 2 + 1, 3 + INT_MAX + 2 + 4]. */ + T (0, "%.*a", INT_MAX, x); /* { dg-warning "writing between 2147483654 and 2147483658 bytes" } */ T (0, "%*.*a", INT_MIN, INT_MIN, x); /* { dg-warning "writing 2147483648 bytes" } */ - T (0, "%*.*a", INT_MAX, INT_MAX, x); /* { dg-warning "writing between 2147483653 and 2147483658 bytes" } */ + T (0, "%*.*a", INT_MAX, INT_MAX, x); /* { dg-warning "writing between 2147483654 and 2147483658 bytes" } */ } void test_floating_e_cst (void) @@ -75,7 +78,7 @@ void test_floating_e_cst (void) T (0, "%*e", INT_MIN, 0.); /* { dg-warning "writing 2147483648 bytes" } */ T (0, "%*e", INT_MAX, 0.); /* { dg-warning "writing 2147483647 bytes" } */ - T (0, "%.*e", INT_MIN, 0.); /* { dg-warning "writing 5 bytes" } */ + T (0, "%.*e", INT_MIN, 0.); /* { dg-warning "writing 12 bytes" } */ T (0, "%.*e", INT_MAX, 0.); /* { dg-warning "writing 2147483653 bytes" } */ @@ -103,7 +106,7 @@ void test_floating_f_cst (void) T (0, "%*f", INT_MIN, 0.); /* { dg-warning "writing 2147483648 bytes" } */ T (0, "%*f", INT_MAX, 0.); /* { dg-warning "writing 2147483647 bytes" } */ - T (0, "%.*f", INT_MIN, 0.); /* { dg-warning "writing 1 byte" } */ + T (0, "%.*f", INT_MIN, 0.); /* { dg-warning "writing 8 byte" } */ T (0, "%.*f", INT_MAX, 0.); /* { dg-warning "writing 2147483649 bytes" } */ diff --git a/gcc/testsuite/gcc.dg/tree-ssa/builtin-sprintf-warn-9.c b/gcc/testsuite/gcc.dg/tree-ssa/builtin-sprintf-warn-9.c new file mode 100644 index 00000000000..c8c6405c7d1 --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/builtin-sprintf-warn-9.c @@ -0,0 +1,276 @@ +/* 78696 - -fprintf-return-value misoptimizes %.Ng where N is greater than 10 + Test to verify the correctness of ranges of output computed for floating + point directives. + { dg-do compile } + { dg-options "-O2 -Wformat -Wformat-length -ftrack-macro-expansion=0" } */ + +typedef __builtin_va_list va_list; + +char dst[1]; + +extern void sink (int, void*); + +/* Macro to test either width or precision specified by the asterisk + (but not both). */ +#define T1(fmt, a) sink (__builtin_sprintf (dst + 1, fmt, a, x), dst) + +/* Macro to test both width and precision specified by the asterisk. */ +#define T2(fmt, w, p) sink (__builtin_sprintf (dst + 1, fmt, w, p, x), dst) + +/* Macro to test vsprintf with both width and precision specified by + the asterisk. */ +#define T(fmt) sink (__builtin_vsprintf (dst + 1, fmt, va), dst) + +/* Exercise %a. */ +void test_a (int w, int p, double x) +{ + T1 ("%.*a", 0); /* { dg-warning "between 6 and 10 bytes" } */ + T1 ("%.*a", 1); /* { dg-warning "between 8 and 12 bytes" } */ + T1 ("%.*a", 2); /* { dg-warning "between 9 and 13 bytes" } */ + T1 ("%.*a", 99); /* { dg-warning "between 106 and 110 bytes" } */ + T1 ("%.*a", 199); /* { dg-warning "between 206 and 210 bytes" } */ + T1 ("%.*a", 1099); /* { dg-warning "between 1106 and 1110 bytes" } */ + + T1 ("%*.a", 0); /* { dg-warning "between 6 and 10 bytes" } */ + T1 ("%*.a", 1); /* { dg-warning "between 6 and 10 bytes" } */ + T1 ("%*.a", 3); /* { dg-warning "between 6 and 10 bytes" } */ + T1 ("%*.a", 6); /* { dg-warning "between 6 and 10 bytes" } */ + T1 ("%*.a", 7); /* { dg-warning "between 7 and 10 bytes" } */ + + T1 ("%*.a", w); /* { dg-warning "writing 6 or more bytes" } */ + T1 ("%*.0a", w); /* { dg-warning "writing 6 or more bytes" } */ + T1 ("%*.1a", w); /* { dg-warning "writing 8 or more bytes" } */ + T1 ("%*.2a", w); /* { dg-warning "writing 9 or more bytes" } */ + + T1 ("%.*a", p); /* { dg-warning "writing 6 or more bytes" } */ + T1 ("%1.*a", p); /* { dg-warning "writing 6 or more bytes" } */ + T1 ("%2.*a", p); /* { dg-warning "writing 6 or more bytes" } */ + T1 ("%3.*a", p); /* { dg-warning "writing 6 or more bytes" } */ + + T2 ("%*.*a", w, p); /* { dg-warning "writing 6 or more bytes" } */ + T2 ("%*.*a", w, p); /* { dg-warning "writing 6 or more bytes" } */ + T2 ("%*.*a", w, p); /* { dg-warning "writing 6 or more bytes" } */ +} + +/* Exercise %e. */ +void test_e (int w, int p, double x) +{ + T1 ("%.*e", 0); /* { dg-warning "between 5 and 7 bytes" } */ + T1 ("%.*e", 1); /* { dg-warning "between 7 and 9 bytes" } */ + T1 ("%.*e", 2); /* { dg-warning "between 8 and 10 bytes" } */ + T1 ("%.*e", 99); /* { dg-warning "between 105 and 107 bytes" } */ + T1 ("%.*e", 199); /* { dg-warning "between 205 and 207 bytes" } */ + T1 ("%.*e", 1099); /* { dg-warning "between 1105 and 1107 bytes" } */ + + T1 ("%*.e", 0); /* { dg-warning "between 5 and 7 bytes" } */ + T1 ("%*.e", 1); /* { dg-warning "between 5 and 7 bytes" } */ + T1 ("%*.e", 1); /* { dg-warning "between 5 and 7 bytes" } */ + T1 ("%*.e", 3); /* { dg-warning "between 5 and 7 bytes" } */ + T1 ("%*.e", 6); /* { dg-warning "between 6 and 7 bytes" } */ + T1 ("%*.e", 7); /* { dg-warning "writing 7 bytes" } */ + + T1 ("%*.e", w); /* { dg-warning "writing 5 or more bytes" } */ + T1 ("%*.0e", w); /* { dg-warning "writing 5 or more bytes" } */ + T1 ("%*.1e", w); /* { dg-warning "writing 7 or more bytes" } */ + T1 ("%*.2e", w); /* { dg-warning "writing 8 or more bytes" } */ + + T1 ("%.*e", p); /* { dg-warning "writing 5 or more bytes" } */ + T1 ("%1.*e", p); /* { dg-warning "writing 5 or more bytes" } */ + T1 ("%2.*e", p); /* { dg-warning "writing 5 or more bytes" } */ + T1 ("%3.*e", p); /* { dg-warning "writing 5 or more bytes" } */ + + T2 ("%*.*e", w, p); /* { dg-warning "writing 5 or more bytes" } */ + T2 ("%*.*e", w, p); /* { dg-warning "writing 5 or more bytes" } */ + T2 ("%*.*e", w, p); /* { dg-warning "writing 5 or more bytes" } */ +} + +/* Exercise %f. */ +void test_f (int w, int p, double x) +{ + T1 ("%.*f", 0); /* { dg-warning "between 1 and 310 bytes" } */ + T1 ("%.*f", 1); /* { dg-warning "between 3 and 312 bytes" } */ + T1 ("%.*f", 2); /* { dg-warning "between 4 and 313 bytes" } */ + T1 ("%.*f", 99); /* { dg-warning "between 101 and 410 bytes" } */ + T1 ("%.*f", 199); /* { dg-warning "between 201 and 510 bytes" } */ + T1 ("%.*f", 1099); /* { dg-warning "between 1101 and 1410 bytes" } */ + + T2 ("%*.*f", 0, 0); /* { dg-warning "between 1 and 310 bytes" } */ + T2 ("%*.*f", 1, 0); /* { dg-warning "between 1 and 310 bytes" } */ + T2 ("%*.*f", 2, 0); /* { dg-warning "between 2 and 310 bytes" } */ + T2 ("%*.*f", 3, 0); /* { dg-warning "between 3 and 310 bytes" } */ + T2 ("%*.*f", 310, 0); /* { dg-warning "writing 310 bytes" } */ + T2 ("%*.*f", 311, 0); /* { dg-warning "writing 311 bytes" } */ + T2 ("%*.*f", 312, 312); /* { dg-warning "between 314 and 623 bytes" } */ + T2 ("%*.*f", 312, 313); /* { dg-warning "between 315 and 624 bytes" } */ + + T1 ("%*.f", w); /* { dg-warning "writing 1 or more bytes" } */ + T1 ("%*.0f", w); /* { dg-warning "writing 1 or more bytes" } */ + T1 ("%*.1f", w); /* { dg-warning "writing 3 or more bytes" } */ + T1 ("%*.2f", w); /* { dg-warning "writing 4 or more bytes" } */ + + T1 ("%.*f", p); /* { dg-warning "writing 1 or more bytes" } */ + T1 ("%1.*f", p); /* { dg-warning "writing 1 or more bytes" } */ + T1 ("%2.*f", p); /* { dg-warning "writing 2 or more bytes" } */ + T1 ("%3.*f", p); /* { dg-warning "writing 3 or more bytes" } */ + + T2 ("%*.*f", w, p); /* { dg-warning "writing 1 or more bytes" } */ + T2 ("%*.*f", w, p); /* { dg-warning "writing 1 or more bytes" } */ + T2 ("%*.*f", w, p); /* { dg-warning "writing 1 or more bytes" } */ +} + +/* Exercise %g. The expected output is the lesser of %e and %f. */ +void test_g (double x) +{ + T1 ("%.*g", 0); /* { dg-warning "between 1 and 7 bytes" } */ + T1 ("%.*g", 1); /* { dg-warning "between 1 and 7 bytes" } */ + T1 ("%.*g", 2); /* { dg-warning "between 1 and 9 bytes" } */ + T1 ("%.*g", 99); /* { dg-warning "between 1 and 106 bytes" } */ + T1 ("%.*g", 199); /* { dg-warning "between 1 and 206 bytes" } */ + T1 ("%.*g", 1099); /* { dg-warning "between 1 and 310 bytes" } */ + + T2 ("%*.*g", 0, 0); /* { dg-warning "between 1 and 7 bytes" } */ + T2 ("%*.*g", 1, 0); /* { dg-warning "between 1 and 7 bytes" } */ + T2 ("%*.*g", 2, 0); /* { dg-warning "between 2 and 7 bytes" } */ + T2 ("%*.*g", 3, 0); /* { dg-warning "between 3 and 7 bytes" } */ + T2 ("%*.*g", 7, 0); /* { dg-warning "writing 7 bytes" } */ + T2 ("%*.*g", 310, 0); /* { dg-warning "writing 310 bytes" } */ + T2 ("%*.*g", 311, 0); /* { dg-warning "writing 311 bytes" } */ + T2 ("%*.*g", 312, 312); /* { dg-warning "writing 312 bytes" } */ + T2 ("%*.*g", 312, 313); /* { dg-warning "writing 312 bytes" } */ + T2 ("%*.*g", 333, 999); /* { dg-warning "writing 333 bytes" } */ +} + +/* Exercise %a. */ +void test_a_va (va_list va) +{ + T ("%.0a"); /* { dg-warning "between 6 and 10 bytes" } */ + T ("%.1a"); /* { dg-warning "between 8 and 12 bytes" } */ + T ("%.2a"); /* { dg-warning "between 9 and 13 bytes" } */ + T ("%.99a"); /* { dg-warning "between 106 and 110 bytes" } */ + T ("%.199a"); /* { dg-warning "between 206 and 210 bytes" } */ + T ("%.1099a"); /* { dg-warning "between 1106 and 1110 bytes" } */ + + T ("%0.a"); /* { dg-warning "between 6 and 10 bytes" } */ + T ("%1.a"); /* { dg-warning "between 6 and 10 bytes" } */ + T ("%3.a"); /* { dg-warning "between 6 and 10 bytes" } */ + T ("%6.a"); /* { dg-warning "between 6 and 10 bytes" } */ + T ("%7.a"); /* { dg-warning "between 7 and 10 bytes" } */ + + T ("%*.a"); /* { dg-warning "writing 6 or more bytes" } */ + T ("%*.0a"); /* { dg-warning "writing 6 or more bytes" } */ + T ("%*.1a"); /* { dg-warning "writing 8 or more bytes" } */ + T ("%*.2a"); /* { dg-warning "writing 9 or more bytes" } */ + + T ("%.*a"); /* { dg-warning "writing 6 or more bytes" } */ + T ("%1.*a"); /* { dg-warning "writing 6 or more bytes" } */ + T ("%2.*a"); /* { dg-warning "writing 6 or more bytes" } */ + T ("%6.*a"); /* { dg-warning "writing 6 or more bytes" } */ + T ("%9.*a"); /* { dg-warning "writing 9 or more bytes" } */ + + T ("%*.*a"); /* { dg-warning "writing 6 or more bytes" } */ +} + +/* Exercise %e. */ +void test_e_va (va_list va) +{ + T ("%e"); /* { dg-warning "between 12 and 14 bytes" } */ + T ("%+e"); /* { dg-warning "between 13 and 14 bytes" } */ + T ("% e"); /* { dg-warning "between 13 and 14 bytes" } */ + T ("%#e"); /* { dg-warning "between 12 and 14 bytes" } */ + T ("%#+e"); /* { dg-warning "between 13 and 14 bytes" } */ + T ("%# e"); /* { dg-warning "between 13 and 14 bytes" } */ + + T ("%.e"); /* { dg-warning "between 5 and 7 bytes" } */ + T ("%.0e"); /* { dg-warning "between 5 and 7 bytes" } */ + T ("%.1e"); /* { dg-warning "between 7 and 9 bytes" } */ + T ("%.2e"); /* { dg-warning "between 8 and 10 bytes" } */ + T ("%.99e"); /* { dg-warning "between 105 and 107 bytes" } */ + T ("%.199e"); /* { dg-warning "between 205 and 207 bytes" } */ + T ("%.1099e"); /* { dg-warning "between 1105 and 1107 bytes" } */ + + T ("%0.e"); /* { dg-warning "between 5 and 7 bytes" } */ + T ("%1.e"); /* { dg-warning "between 5 and 7 bytes" } */ + T ("%1.e"); /* { dg-warning "between 5 and 7 bytes" } */ + T ("%3.e"); /* { dg-warning "between 5 and 7 bytes" } */ + T ("%6.e"); /* { dg-warning "between 6 and 7 bytes" } */ + T ("%7.e"); /* { dg-warning "writing 7 bytes" } */ + + T ("%.*e"); /* { dg-warning "writing 5 or more bytes" } */ + T ("%1.*e"); /* { dg-warning "writing 5 or more bytes" } */ + T ("%6.*e"); /* { dg-warning "writing 6 or more bytes" } */ + T ("%9.*e"); /* { dg-warning "writing 9 or more bytes" } */ + + T ("%*.*e"); /* { dg-warning "writing 5 or more bytes" } */ +} + +/* Exercise %f. */ +void test_f_va (va_list va) +{ + T ("%f"); /* { dg-warning "between 8 and 317 bytes" } */ + T ("%+f"); /* { dg-warning "between 9 and 317 bytes" } */ + T ("% f"); /* { dg-warning "between 9 and 317 bytes" } */ + T ("%#f"); /* { dg-warning "between 8 and 317 bytes" } */ + T ("%+f"); /* { dg-warning "between 9 and 317 bytes" } */ + T ("% f"); /* { dg-warning "between 9 and 317 bytes" } */ + T ("%#+f"); /* { dg-warning "between 9 and 317 bytes" } */ + T ("%# f"); /* { dg-warning "between 9 and 317 bytes" } */ + + T ("%.f"); /* { dg-warning "between 1 and 310 bytes" } */ + T ("%.0f"); /* { dg-warning "between 1 and 310 bytes" } */ + T ("%.1f"); /* { dg-warning "between 3 and 312 bytes" } */ + T ("%.2f"); /* { dg-warning "between 4 and 313 bytes" } */ + T ("%.99f"); /* { dg-warning "between 101 and 410 bytes" } */ + T ("%.199f"); /* { dg-warning "between 201 and 510 bytes" } */ + T ("%.1099f"); /* { dg-warning "between 1101 and 1410 bytes" } */ + + T ("%0.0f"); /* { dg-warning "between 1 and 310 bytes" } */ + T ("%1.0f"); /* { dg-warning "between 1 and 310 bytes" } */ + T ("%2.0f"); /* { dg-warning "between 2 and 310 bytes" } */ + T ("%3.0f"); /* { dg-warning "between 3 and 310 bytes" } */ + T ("%310.0f"); /* { dg-warning "writing 310 bytes" } */ + T ("%311.0f"); /* { dg-warning "writing 311 bytes" } */ + T ("%312.312f"); /* { dg-warning "between 314 and 623 bytes" } */ + T ("%312.313f"); /* { dg-warning "between 315 and 624 bytes" } */ + + T ("%.*f"); /* { dg-warning "writing 1 or more bytes" } */ + T ("%1.*f"); /* { dg-warning "writing 1 or more bytes" } */ + T ("%3.*f"); /* { dg-warning "writing 3 or more bytes" } */ + + T ("%*.*f"); /* { dg-warning "writing 1 or more bytes" } */ +} + +/* Exercise %g. The expected output is the lesser of %e and %f. */ +void test_g_va (va_list va) +{ + T ("%g"); /* { dg-warning "between 1 and 13 bytes" } */ + T ("%+g"); /* { dg-warning "between 2 and 13 bytes" } */ + T ("% g"); /* { dg-warning "between 2 and 13 bytes" } */ + T ("%#g"); /* { dg-warning "between 1 and 13 bytes" } */ + T ("%#+g"); /* { dg-warning "between 2 and 13 bytes" } */ + T ("%# g"); /* { dg-warning "between 2 and 13 bytes" } */ + + T ("%.g"); /* { dg-warning "between 1 and 7 bytes" } */ + T ("%.0g"); /* { dg-warning "between 1 and 7 bytes" } */ + T ("%.1g"); /* { dg-warning "between 1 and 7 bytes" } */ + T ("%.2g"); /* { dg-warning "between 1 and 9 bytes" } */ + T ("%.99g"); /* { dg-warning "between 1 and 106 bytes" } */ + T ("%.199g"); /* { dg-warning "between 1 and 206 bytes" } */ + T ("%.1099g"); /* { dg-warning "between 1 and 310 bytes" } */ + + T ("%0.0g"); /* { dg-warning "between 1 and 7 bytes" } */ + T ("%1.0g"); /* { dg-warning "between 1 and 7 bytes" } */ + T ("%2.0g"); /* { dg-warning "between 2 and 7 bytes" } */ + T ("%3.0g"); /* { dg-warning "between 3 and 7 bytes" } */ + T ("%7.0g"); /* { dg-warning "writing 7 bytes" } */ + T ("%310.0g"); /* { dg-warning "writing 310 bytes" } */ + T ("%311.0g"); /* { dg-warning "writing 311 bytes" } */ + T ("%312.312g"); /* { dg-warning "writing 312 bytes" } */ + T ("%312.313g"); /* { dg-warning "writing 312 bytes" } */ + T ("%333.999g"); /* { dg-warning "writing 333 bytes" } */ + + T ("%.*g"); /* { dg-warning "writing 1 or more bytes" } */ + T ("%1.*g"); /* { dg-warning "writing 1 or more bytes" } */ + T ("%4.*g"); /* { dg-warning "writing 4 or more bytes" } */ + + T ("%*.*g"); /* { dg-warning "writing 1 or more bytes" } */ +} diff --git a/gcc/testsuite/gcc.dg/tree-ssa/builtin-sprintf.c b/gcc/testsuite/gcc.dg/tree-ssa/builtin-sprintf.c index 35a5bd0f060..96892c16425 100644 --- a/gcc/testsuite/gcc.dg/tree-ssa/builtin-sprintf.c +++ b/gcc/testsuite/gcc.dg/tree-ssa/builtin-sprintf.c @@ -56,9 +56,12 @@ checkv (const char *func, int line, int res, int min, int max, fail = 1; } - else + else if (min == max) __builtin_printf ("PASS: %s:%i: \"%s\" result %i: \"%s\"\n", func, line, fmt, n, dst); + else + __builtin_printf ("PASS: %s:%i: \"%s\" result %i in [%i, %i]: \"%s\"\n", + func, line, fmt, n, min, max, dst); } if (fail) @@ -75,7 +78,7 @@ check (const char *func, int line, int res, int min, int max, __builtin_va_end (va); } -char buffer[256]; +char buffer[4100]; char* volatile dst = buffer; char* ptr = buffer; @@ -415,6 +418,8 @@ test_a_double (double d) EQL ( 9, 10, "%.2a", 4.0); /* 0x8.00p-1 */ EQL (10, 11, "%.3a", 5.0); /* 0xa.000p-1 */ + EQL (11, 12, "%.*a", 4, 6.0); /* 0xc.0000p-1 */ + EQL (12, 13, "%.*a", 5, 7.0); /* 0xe.00000p-1 */ /* d is in [ 0, -DBL_MAX ] */ RNG ( 6, 10, 11, "%.0a", d); /* 0x0p+0 ... -0x2p+1023 */ RNG ( 6, 12, 13, "%.1a", d); /* 0x0p+0 ... -0x2.0p+1023 */ @@ -432,7 +437,7 @@ test_a_long_double (void) } static void __attribute__ ((noinline, noclone)) -test_e_double (void) +test_e_double (double d) { EQL (12, 13, "%e", 1.0e0); EQL (13, 14, "%e", -1.0e0); @@ -454,10 +459,34 @@ test_e_double (void) EQL (12, 13, "%e", 1.0e-1); EQL (12, 13, "%e", 1.0e-12); EQL (13, 14, "%e", 1.0e-123); + + RNG (12, 14, 15, "%e", d); + RNG ( 5, 7, 8, "%.e", d); + RNG ( 5, 7, 8, "%.0e", d); + RNG ( 7, 9, 10, "%.1e", d); + RNG ( 8, 10, 11, "%.2e", d); + RNG ( 9, 11, 12, "%.3e", d); + RNG (10, 12, 13, "%.4e", d); + RNG (11, 13, 14, "%.5e", d); + RNG (12, 14, 15, "%.6e", d); + RNG (13, 15, 16, "%.7e", d); + + RNG (4006, 4008, 4009, "%.4000e", d); + + RNG ( 5, 7, 8, "%.*e", 0, d); + RNG ( 7, 9, 10, "%.*e", 1, d); + RNG ( 8, 10, 11, "%.*e", 2, d); + RNG ( 9, 11, 12, "%.*e", 3, d); + RNG (10, 12, 13, "%.*e", 4, d); + RNG (11, 13, 14, "%.*e", 5, d); + RNG (12, 14, 15, "%.*e", 6, d); + RNG (13, 15, 16, "%.*e", 7, d); + + RNG (4006, 4008, 4009, "%.*e", 4000, d); } static void __attribute__ ((noinline, noclone)) -test_e_long_double (void) +test_e_long_double (long double d) { EQL (12, 13, "%Le", 1.0e0L); EQL (13, 14, "%Le", -1.0e0L); @@ -490,10 +519,32 @@ test_e_long_double (void) EQL ( 8, 9, "%.1Le", 1.0e-111L); EQL (19, 20, "%.12Le", 1.0e-112L); EQL (20, 21, "%.13Le", 1.0e-113L); + + /* The following correspond to the double results plus 1 for the upper + bound accounting for the four-digit exponent. */ + RNG (12, 15, 16, "%Le", d); /* 0.000000e+00 ... -1.189732e+4932 */ + RNG ( 5, 8, 9, "%.Le", d); + RNG ( 5, 9, 10, "%.0Le", d); + RNG ( 7, 10, 11, "%.1Le", d); /* 0.0e+00 ... -1.2e+4932 */ + RNG ( 8, 11, 12, "%.2Le", d); /* 0.00e+00 ... -1.19e+4932 */ + RNG ( 9, 12, 13, "%.3Le", d); + RNG (10, 13, 14, "%.4Le", d); + RNG (11, 14, 15, "%.5Le", d); + RNG (12, 15, 16, "%.6Le", d); /* same as plain "%Le" */ + RNG (13, 16, 17, "%.7Le", d); /* 0.0000000e+00 ... -1.1897315e+4932 */ + + RNG ( 5, 9, 10, "%.*Le", 0, d); + RNG ( 7, 10, 11, "%.*Le", 1, d); + RNG ( 8, 11, 12, "%.*Le", 2, d); + RNG ( 9, 12, 13, "%.*Le", 3, d); + RNG (10, 13, 14, "%.*Le", 4, d); + RNG (11, 14, 15, "%.*Le", 5, d); + RNG (12, 15, 16, "%.*Le", 6, d); + RNG (13, 16, 17, "%.*Le", 7, d); } static void __attribute__ ((noinline, noclone)) -test_f_double (void) +test_f_double (double d) { EQL ( 8, 9, "%f", 0.0e0); EQL ( 8, 9, "%f", 0.1e0); @@ -511,6 +562,8 @@ test_f_double (void) EQL ( 8, 9, "%f", 1.0e-1); EQL ( 8, 9, "%f", 1.0e-12); EQL ( 8, 9, "%f", 1.0e-123); + + RNG ( 8, 317, 318, "%f", d); } static void __attribute__ ((noinline, noclone)) @@ -534,6 +587,87 @@ test_f_long_double (void) EQL ( 8, 9, "%Lf", 1.0e-123L); } +static void __attribute__ ((noinline, noclone)) +test_g_double (double d) +{ + /* Numbers exactly representable in binary floating point. */ + EQL ( 1, 2, "%g", 0.0); + EQL ( 3, 4, "%g", 1.0 / 2); + EQL ( 4, 5, "%g", 1.0 / 4); + EQL ( 5, 6, "%g", 1.0 / 8); + EQL ( 6, 7, "%g", 1.0 / 16); + EQL ( 7, 8, "%g", 1.0 / 32); + EQL ( 8, 9, "%g", 1.0 / 64); + EQL ( 9, 10, "%g", 1.0 / 128); + EQL ( 10, 11, "%g", 1.0 / 256); + EQL ( 10, 11, "%g", 1.0 / 512); + + /* Numbers that are not exactly representable. */ + RNG ( 3, 8, 9, "%g", 0.1); + RNG ( 4, 8, 9, "%g", 0.12); + RNG ( 5, 8, 9, "%g", 0.123); + RNG ( 6, 8, 9, "%g", 0.1234); + RNG ( 7, 8, 9, "%g", 0.12345); + RNG ( 8, 8, 9, "%g", 0.123456); + + RNG ( 4, 7, 8, "%g", 0.123e+1); + EQL ( 8, 9, "%g", 0.123e+12); + RNG ( 9, 12, 13, "%g", 0.123e+134); + + RNG ( 1, 13, 14, "%g", d); + RNG ( 1, 7, 8, "%.g", d); + RNG ( 1, 7, 8, "%.0g", d); + RNG ( 1, 7, 8, "%.1g", d); + RNG ( 1, 9, 10, "%.2g", d); + RNG ( 1, 10, 11, "%.3g", d); + RNG ( 1, 11, 12, "%.4g", d); + RNG ( 1, 12, 13, "%.5g", d); + RNG ( 1, 13, 14, "%.6g", d); + RNG ( 1, 14, 15, "%.7g", d); + RNG ( 1, 15, 16, "%.8g", d); + + RNG ( 1,310,311, "%.9999g", d); + + RNG ( 1, 7, 8, "%.*g", 0, d); + RNG ( 1, 7, 8, "%.*g", 1, d); + RNG ( 1, 9, 10, "%.*g", 2, d); + RNG ( 1, 10, 11, "%.*g", 3, d); + RNG ( 1, 11, 12, "%.*g", 4, d); + RNG ( 1, 12, 13, "%.*g", 5, d); + RNG ( 1, 13, 14, "%.*g", 6, d); + RNG ( 1, 14, 15, "%.*g", 7, d); + RNG ( 1, 15, 16, "%.*g", 8, d); + RNG ( 1,310,311, "%.*g", 9999, d); +} + +static void __attribute__ ((noinline, noclone)) +test_g_long_double (void) +{ + /* Numbers exactly representable in binary floating point. */ + EQL ( 1, 2, "%Lg", 0.0L); + EQL ( 3, 4, "%Lg", 1.0L / 2); + EQL ( 4, 5, "%Lg", 1.0L / 4); + EQL ( 5, 6, "%Lg", 1.0L / 8); + EQL ( 6, 7, "%Lg", 1.0L / 16); + EQL ( 7, 8, "%Lg", 1.0L / 32); + EQL ( 8, 9, "%Lg", 1.0L / 64); + EQL ( 9, 10, "%Lg", 1.0L / 128); + EQL ( 10, 11, "%Lg", 1.0L / 256); + EQL ( 10, 11, "%Lg", 1.0L / 512); + + /* Numbers that are not exactly representable. */ + RNG ( 3, 8, 9, "%Lg", 0.1L); + RNG ( 4, 8, 9, "%Lg", 0.12L); + RNG ( 5, 8, 9, "%Lg", 0.123L); + RNG ( 6, 8, 9, "%Lg", 0.1234L); + RNG ( 7, 8, 9, "%Lg", 0.12345L); + RNG ( 8, 8, 9, "%Lg", 0.123456L); + + RNG ( 4, 7, 8, "%Lg", 0.123e+1L); + EQL ( 8, 9, "%Lg", 0.123e+12L); + RNG ( 9, 12, 13, "%Lg", 0.123e+134L); +} + static void __attribute__ ((noinline, noclone)) test_s (int i) { @@ -577,12 +711,14 @@ int main (void) test_x ('?', 0xdead, 0xdeadbeef); test_a_double (0.0); - test_e_double (); - test_f_double (); + test_e_double (0.0); + test_f_double (0.0); + test_g_double (0.0); test_a_long_double (); - test_e_long_double (); + test_e_long_double (0.0); test_f_long_double (); + test_g_long_double (); test_s (0);