relax lower bound for infinite arguments in gimple-ssa-sprinf.c (PR 86274)

Message ID 96bd765a-6bf8-81ee-9b89-431d766da218@gmail.com
State New
Headers show
Series
  • relax lower bound for infinite arguments in gimple-ssa-sprinf.c (PR 86274)
Related show

Commit Message

Martin Sebor July 3, 2018, 10:50 p.m.
In computing the size of expected output for non-constant floating
arguments the sprintf pass doesn't consider the possibility that
the argument value may be not finite (i.e., it can be infinity or
NaN).  Infinities and NaNs are formatted as "inf" or "infinity"
and "nan".  As a result, any floating directive can produce as
few bytes on output as three for an non-finite argument, when
the least amount directives such as %f produce for finite
arguments is 8.

The attached patch adjusts the floating point code to correctly
reflect the lower bound.

Martin

Comments

Jeff Law July 4, 2018, 12:32 a.m. | #1
On 07/03/2018 04:50 PM, Martin Sebor wrote:
> In computing the size of expected output for non-constant floating

> arguments the sprintf pass doesn't consider the possibility that

> the argument value may be not finite (i.e., it can be infinity or

> NaN).  Infinities and NaNs are formatted as "inf" or "infinity"

> and "nan".  As a result, any floating directive can produce as

> few bytes on output as three for an non-finite argument, when

> the least amount directives such as %f produce for finite

> arguments is 8.

> 

> The attached patch adjusts the floating point code to correctly

> reflect the lower bound.

> 

> Martin

> 

> gcc-86274.diff

> 

> 

> PR tree-optimization/86274 - SEGFAULT when logging std::to_string(NAN)

> 

> gcc/ChangeLog:

> 

> 	PR tree-optimization/86274

> 	* gimple-ssa-sprintf.c (fmtresult::type_max_digits): Verify

> 	precondition.

> 	(format_floating): Correct handling of infinities and NaNs.

> 

> gcc/testsuite/ChangeLog:

> 

> 	PR tree-optimization/86274

> 	* gcc.dg/tree-ssa/builtin-sprintf-9.c: New test.

> 	* gcc.dg/tree-ssa/builtin-sprintf-warn-1.c: Adjust.

> 	* gcc.dg/tree-ssa/builtin-sprintf-warn-10.c: Same.

> 	* gcc.dg/tree-ssa/builtin-sprintf-warn-15.c: Same.

> 	* gcc.dg/tree-ssa/builtin-sprintf-warn-7.c: Same.

> 	* gcc.dg/tree-ssa/builtin-sprintf.c: Same.

> 	* gcc.dg/tree-ssa/pr83198.c: Same.

OK
jeff
Martin Sebor July 4, 2018, 2:22 a.m. | #2
Committed to trunk in r86274.  Jakub/Richard, can you please
also review and approve the corresponding fix for the release
branches?

Martin

On 07/03/2018 06:32 PM, Jeff Law wrote:
> On 07/03/2018 04:50 PM, Martin Sebor wrote:

>> In computing the size of expected output for non-constant floating

>> arguments the sprintf pass doesn't consider the possibility that

>> the argument value may be not finite (i.e., it can be infinity or

>> NaN).  Infinities and NaNs are formatted as "inf" or "infinity"

>> and "nan".  As a result, any floating directive can produce as

>> few bytes on output as three for an non-finite argument, when

>> the least amount directives such as %f produce for finite

>> arguments is 8.

>>

>> The attached patch adjusts the floating point code to correctly

>> reflect the lower bound.

>>

>> Martin

>>

>> gcc-86274.diff

>>

>>

>> PR tree-optimization/86274 - SEGFAULT when logging std::to_string(NAN)

>>

>> gcc/ChangeLog:

>>

>> 	PR tree-optimization/86274

>> 	* gimple-ssa-sprintf.c (fmtresult::type_max_digits): Verify

>> 	precondition.

>> 	(format_floating): Correct handling of infinities and NaNs.

>>

>> gcc/testsuite/ChangeLog:

>>

>> 	PR tree-optimization/86274

>> 	* gcc.dg/tree-ssa/builtin-sprintf-9.c: New test.

>> 	* gcc.dg/tree-ssa/builtin-sprintf-warn-1.c: Adjust.

>> 	* gcc.dg/tree-ssa/builtin-sprintf-warn-10.c: Same.

>> 	* gcc.dg/tree-ssa/builtin-sprintf-warn-15.c: Same.

>> 	* gcc.dg/tree-ssa/builtin-sprintf-warn-7.c: Same.

>> 	* gcc.dg/tree-ssa/builtin-sprintf.c: Same.

>> 	* gcc.dg/tree-ssa/pr83198.c: Same.

> OK

> jeff

>
Richard Biener July 4, 2018, 7:26 a.m. | #3
On Tue, 3 Jul 2018, Martin Sebor wrote:

> Committed to trunk in r86274.  Jakub/Richard, can you please

> also review and approve the corresponding fix for the release

> branches?


If it is a regression and the patch was approved for trunk it is
automatically OK for release branches without further review unless
you think it is too invasive.

Richard.

> Martin

> 

> On 07/03/2018 06:32 PM, Jeff Law wrote:

> > On 07/03/2018 04:50 PM, Martin Sebor wrote:

> > > In computing the size of expected output for non-constant floating

> > > arguments the sprintf pass doesn't consider the possibility that

> > > the argument value may be not finite (i.e., it can be infinity or

> > > NaN).  Infinities and NaNs are formatted as "inf" or "infinity"

> > > and "nan".  As a result, any floating directive can produce as

> > > few bytes on output as three for an non-finite argument, when

> > > the least amount directives such as %f produce for finite

> > > arguments is 8.

> > > 

> > > The attached patch adjusts the floating point code to correctly

> > > reflect the lower bound.

> > > 

> > > Martin

> > > 

> > > gcc-86274.diff

> > > 

> > > 

> > > PR tree-optimization/86274 - SEGFAULT when logging std::to_string(NAN)

> > > 

> > > gcc/ChangeLog:

> > > 

> > > 	PR tree-optimization/86274

> > > 	* gimple-ssa-sprintf.c (fmtresult::type_max_digits): Verify

> > > 	precondition.

> > > 	(format_floating): Correct handling of infinities and NaNs.

> > > 

> > > gcc/testsuite/ChangeLog:

> > > 

> > > 	PR tree-optimization/86274

> > > 	* gcc.dg/tree-ssa/builtin-sprintf-9.c: New test.

> > > 	* gcc.dg/tree-ssa/builtin-sprintf-warn-1.c: Adjust.

> > > 	* gcc.dg/tree-ssa/builtin-sprintf-warn-10.c: Same.

> > > 	* gcc.dg/tree-ssa/builtin-sprintf-warn-15.c: Same.

> > > 	* gcc.dg/tree-ssa/builtin-sprintf-warn-7.c: Same.

> > > 	* gcc.dg/tree-ssa/builtin-sprintf.c: Same.

> > > 	* gcc.dg/tree-ssa/pr83198.c: Same.

> > OK

> > jeff

> > 

> 

> 


-- 
Richard Biener <rguenther@suse.de>
SUSE LINUX GmbH, GF: Felix Imendoerffer, Jane Smithard, Graham Norton, HRB 21284 (AG Nuernberg)
Christophe Lyon July 4, 2018, 2:04 p.m. | #4
Hi,

On Wed, 4 Jul 2018 at 09:26, Richard Biener <rguenther@suse.de> wrote:
>

> On Tue, 3 Jul 2018, Martin Sebor wrote:

>

> > Committed to trunk in r86274.  Jakub/Richard, can you please

> > also review and approve the corresponding fix for the release

> > branches?

>

> If it is a regression and the patch was approved for trunk it is

> automatically OK for release branches without further review unless

> you think it is too invasive.

>

> Richard.

>

> > Martin

> >

> > On 07/03/2018 06:32 PM, Jeff Law wrote:

> > > On 07/03/2018 04:50 PM, Martin Sebor wrote:

> > > > In computing the size of expected output for non-constant floating

> > > > arguments the sprintf pass doesn't consider the possibility that

> > > > the argument value may be not finite (i.e., it can be infinity or

> > > > NaN).  Infinities and NaNs are formatted as "inf" or "infinity"

> > > > and "nan".  As a result, any floating directive can produce as

> > > > few bytes on output as three for an non-finite argument, when

> > > > the least amount directives such as %f produce for finite

> > > > arguments is 8.

> > > >

> > > > The attached patch adjusts the floating point code to correctly

> > > > reflect the lower bound.

> > > >

> > > > Martin

> > > >

> > > > gcc-86274.diff

> > > >

> > > >

> > > > PR tree-optimization/86274 - SEGFAULT when logging std::to_string(NAN)

> > > >

> > > > gcc/ChangeLog:

> > > >

> > > >   PR tree-optimization/86274

> > > >   * gimple-ssa-sprintf.c (fmtresult::type_max_digits): Verify

> > > >   precondition.

> > > >   (format_floating): Correct handling of infinities and NaNs.

> > > >

> > > > gcc/testsuite/ChangeLog:

> > > >

> > > >   PR tree-optimization/86274

> > > >   * gcc.dg/tree-ssa/builtin-sprintf-9.c: New test.


I've noticed a failure with this new test (on arm and aarch64, but
I've seen other targets are affected on gcc-testresults):
gcc.dg/tree-ssa/builtin-sprintf-9.c: dump file does not exist
UNRESOLVED: gcc.dg/tree-ssa/builtin-sprintf-9.c scan-tree-dump-times
optimized" "call_made_in_true_branch_" 6"

The test is compiled with -fdump-tree-optimized

Christophe

> > > >   * gcc.dg/tree-ssa/builtin-sprintf-warn-1.c: Adjust.

> > > >   * gcc.dg/tree-ssa/builtin-sprintf-warn-10.c: Same.

> > > >   * gcc.dg/tree-ssa/builtin-sprintf-warn-15.c: Same.

> > > >   * gcc.dg/tree-ssa/builtin-sprintf-warn-7.c: Same.

> > > >   * gcc.dg/tree-ssa/builtin-sprintf.c: Same.

> > > >   * gcc.dg/tree-ssa/pr83198.c: Same.

> > > OK

> > > jeff

> > >

> >

> >

>

> --

> Richard Biener <rguenther@suse.de>

> SUSE LINUX GmbH, GF: Felix Imendoerffer, Jane Smithard, Graham Norton, HRB 21284 (AG Nuernberg)
Martin Sebor July 4, 2018, 7:02 p.m. | #5
On 07/04/2018 08:04 AM, Christophe Lyon wrote:
> Hi,

>

> On Wed, 4 Jul 2018 at 09:26, Richard Biener <rguenther@suse.de> wrote:

>>

>> On Tue, 3 Jul 2018, Martin Sebor wrote:

>>

>>> Committed to trunk in r86274.  Jakub/Richard, can you please

>>> also review and approve the corresponding fix for the release

>>> branches?

>>

>> If it is a regression and the patch was approved for trunk it is

>> automatically OK for release branches without further review unless

>> you think it is too invasive.


Will do.  Thanks for clarifying.


>

> I've noticed a failure with this new test (on arm and aarch64, but

> I've seen other targets are affected on gcc-testresults):

> gcc.dg/tree-ssa/builtin-sprintf-9.c: dump file does not exist

> UNRESOLVED: gcc.dg/tree-ssa/builtin-sprintf-9.c scan-tree-dump-times

> optimized" "call_made_in_true_branch_" 6"

>

> The test is compiled with -fdump-tree-optimized


Thanks.  There was a typo in the dg-final directive in the test
and I missed the UNRESOLVED result among all the others that
have recently started showing up.  I fixed the typo in r262419
and raised bug 86405 for the unresolved tests.

Martin

Patch

PR tree-optimization/86274 - SEGFAULT when logging std::to_string(NAN)

gcc/ChangeLog:

	PR tree-optimization/86274
	* gimple-ssa-sprintf.c (fmtresult::type_max_digits): Verify
	precondition.
	(format_floating): Correct handling of infinities and NaNs.

gcc/testsuite/ChangeLog:

	PR tree-optimization/86274
	* gcc.dg/tree-ssa/builtin-sprintf-9.c: New test.
	* gcc.dg/tree-ssa/builtin-sprintf-warn-1.c: Adjust.
	* gcc.dg/tree-ssa/builtin-sprintf-warn-10.c: Same.
	* gcc.dg/tree-ssa/builtin-sprintf-warn-15.c: Same.
	* gcc.dg/tree-ssa/builtin-sprintf-warn-7.c: Same.
	* gcc.dg/tree-ssa/builtin-sprintf.c: Same.
	* gcc.dg/tree-ssa/pr83198.c: Same.

Index: gcc/gimple-ssa-sprintf.c
===================================================================
--- gcc/gimple-ssa-sprintf.c	(revision 262312)
+++ gcc/gimple-ssa-sprintf.c	(working copy)
@@ -781,15 +781,19 @@  unsigned
 fmtresult::type_max_digits (tree type, int base)
 {
   unsigned prec = TYPE_PRECISION (type);
-  if (base == 8)
-    return (prec + 2) / 3;
+  switch (base)
+    {
+    case 8:
+      return (prec + 2) / 3;
+    case 10:
+      /* Decimal approximation: yields 3, 5, 10, and 20 for precision
+	 of 8, 16, 32, and 64 bits.  */
+      return prec * 301 / 1000 + 1;
+    case 16:
+      return prec / 4;
+    }
 
-  if (base == 16)
-    return prec / 4;
-
-  /* Decimal approximation: yields 3, 5, 10, and 20 for precision
-     of 8, 16, 32, and 64 bits.  */
-  return prec * 301 / 1000 + 1;
+  gcc_unreachable ();
 }
 
 static bool
@@ -1759,6 +1763,11 @@  format_floating (const directive &dir, const HOST_
   unsigned flagmin = (1 /* for the first digit */
 		      + (dir.get_flag ('+') | dir.get_flag (' ')));
 
+  /* The minimum is 3 for "inf" and "nan" for all specifiers, plus 1
+     for the plus sign/space with the '+' and ' ' flags, respectively,
+     unless reduced below.  */
+  res.range.min = 2 + flagmin;
+
   /* When the pound flag is set the decimal point is included in output
      regardless of precision.  Whether or not a decimal point is included
      otherwise depends on the specification and precision.  */
@@ -1775,14 +1784,13 @@  format_floating (const directive &dir, const HOST_
 	else if (dir.prec[0] > 0)
 	  minprec = dir.prec[0] + !radix /* decimal point */;
 
-	res.range.min = (2 /* 0x */
-			 + flagmin
-			 + radix
-			 + minprec
-			 + 3 /* p+0 */);
+	res.range.likely = (2 /* 0x */
+			    + flagmin
+			    + radix
+			    + minprec
+			    + 3 /* p+0 */);
 
 	res.range.max = format_floating_max (type, 'a', prec[1]);
-	res.range.likely = res.range.min;
 
 	/* The unlikely maximum accounts for the longest multibyte
 	   decimal point character.  */
@@ -1800,15 +1808,14 @@  format_floating (const directive &dir, const HOST_
 	   non-zero, decimal point.  */
 	HOST_WIDE_INT minprec = prec[0] ? prec[0] + !radix : 0;
 
-	/* The minimum output is "[-+]1.234567e+00" regardless
+	/* The likely minimum output is "[-+]1.234567e+00" regardless
 	   of the value of the actual argument.  */
-	res.range.min = (flagmin
-			 + radix
-			 + minprec
-			 + 2 /* e+ */ + 2);
+	res.range.likely = (flagmin
+			    + radix
+			    + minprec
+			    + 2 /* e+ */ + 2);
 
 	res.range.max = format_floating_max (type, 'e', prec[1]);
-	res.range.likely = res.range.min;
 
 	/* The unlikely maximum accounts for the longest multibyte
 	   decimal point character.  */
@@ -1827,12 +1834,15 @@  format_floating (const directive &dir, const HOST_
 	   decimal point.  */
 	HOST_WIDE_INT minprec = prec[0] ? prec[0] + !radix : 0;
 
-	/* 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 + radix + minprec;
+	/* For finite numbers (i.e., not infinity or NaN) 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).
+	   But in all cases, the lower bound is no greater than 3.  */
+	unsigned HOST_WIDE_INT min = flagmin + radix + minprec;
+	if (min < res.range.min)
+	  res.range.min = min;
 
 	/* Compute the upper bound for -TYPE_MAX.  */
 	res.range.max = format_floating_max (type, 'f', prec[1]);
@@ -1842,7 +1852,7 @@  format_floating (const directive &dir, const HOST_
 	if (dir.prec[0] < 0 && dir.prec[1] > 0)
 	  res.range.likely = 3;
 	else
-	  res.range.likely = res.range.min;
+	  res.range.likely = min;
 
 	/* The unlikely maximum accounts for the longest multibyte
 	   decimal point character.  */
@@ -1860,7 +1870,9 @@  format_floating (const directive &dir, const HOST_
 	   the lower bound on the range of bytes (not counting flags
 	   or width) is 1 plus radix (i.e., either "0" or "0." for
 	   "%g" and "%#g", respectively, with a zero argument).  */
-	res.range.min = flagmin + radix;
+	unsigned HOST_WIDE_INT min = flagmin + radix;
+	if (min < res.range.min)
+	  res.range.min = min;
 
 	char spec = 'g';
 	HOST_WIDE_INT maxprec = dir.prec[1];
@@ -1992,6 +2004,32 @@  format_floating (const directive &dir, tree arg, v
   const REAL_VALUE_TYPE *rvp = TREE_REAL_CST_PTR (arg);
   const real_format *rfmt = REAL_MODE_FORMAT (TYPE_MODE (TREE_TYPE (arg)));
 
+  if (!real_isfinite (rvp))
+    {
+      /* The format for Infinity and NaN is "[-]inf"/"[-]infinity"
+	 and "[-]nan" with the choice being implementation-defined
+	 but not locale dependent.  */
+      bool sign = dir.get_flag ('+') || real_isneg (rvp);
+      res.range.min = 3 + sign;
+
+      res.range.likely = res.range.min;
+      res.range.max = res.range.min;
+      /* The inlikely maximum is "[-/+]infinity" or "[-/+]nan".  */
+      res.range.unlikely = sign + (real_isinf (rvp) ? 8 : 3);
+
+      /* The range for infinity and NaN is known unless either width
+	 or precision is unknown.  Width has the same effect regardless
+	 of whether the argument is finite.  Precision is either ignored
+	 (e.g., Glibc) or can have an effect on the short vs long format
+	 such as inf/infinity (e.g., Solaris).  */
+      res.knownrange = dir.known_width_and_precision ();
+
+      /* Adjust the range for width but ignore precision.  */
+      res.adjust_for_width_or_precision (dir.width);
+
+      return res;
+    }
+
   char fmtstr [40];
   char *pfmt = fmtstr;
 
Index: gcc/testsuite/gcc.dg/torture/builtin-sprintf.c
===================================================================
--- gcc/testsuite/gcc.dg/torture/builtin-sprintf.c	(nonexistent)
+++ gcc/testsuite/gcc.dg/torture/builtin-sprintf.c	(working copy)
@@ -0,0 +1,29 @@ 
+/* PR tree-optimization/86274 - SEGFAULT when logging std::to_string(NAN)
+   { dg-do run }
+   { dg-options "-O2 -Wall" } */
+
+#define X        "0xdeadbeef"
+#define nan(x)   __builtin_nan (x)
+
+volatile double nan_0 = nan ("0");
+volatile double nan_x = nan (X);
+
+int main (void)
+{
+  char buf[80];
+
+  /* Verify that folded results match those of the library calls.  */
+  int cst_n_0 = __builtin_sprintf (buf, "%g", nan ("0"));
+  int cst_n_x = __builtin_sprintf (buf, "%g", nan (X));
+
+  int var_n_0 = __builtin_sprintf (buf, "%g", nan_0);
+  int var_n_x = __builtin_sprintf (buf, "%g", nan_x);
+
+  if (cst_n_0 != var_n_0)
+    __builtin_abort ();
+
+  if (cst_n_x != var_n_x)
+    __builtin_abort ();
+
+  return 0;
+}
Index: gcc/testsuite/gcc.dg/tree-ssa/builtin-sprintf-9.c
===================================================================
--- gcc/testsuite/gcc.dg/tree-ssa/builtin-sprintf-9.c	(nonexistent)
+++ gcc/testsuite/gcc.dg/tree-ssa/builtin-sprintf-9.c	(working copy)
@@ -0,0 +1,90 @@ 
+/* PR tree-optimization/86274 - SEGFAULT when logging std::to_string(NAN)
+   { dg-do compile }
+   { dg-options "-O2 -Wall -fdump-tree-optimized" }  */
+
+typedef __SIZE_TYPE__ size_t;
+extern int sprintf (char*, const char*, ...);
+extern int snprintf (char*, size_t, const char*, ...);
+
+#define CAT(x, y) x ## y
+#define CONCAT(x, y) CAT (x, y)
+#define FAILNAME(name) CONCAT (call_ ## name ##_on_line_, __LINE__)
+
+#define FAIL(name) do {				\
+    extern void FAILNAME (name) (void);		\
+    FAILNAME (name)();				\
+  } while (0)
+
+/* Macro to emit a call to funcation named
+     call_in_true_branch_not_eliminated_on_line_NNN()
+   for each expression that's expected to fold to false but that
+   GCC does not fold.  The dg-final scan-tree-dump-time directive
+   at the bottom of the test verifies that no such call appears
+   in output.  */
+#define ELIM(expr)							\
+  if ((expr)) FAIL (in_true_branch_not_eliminated); else (void)0
+
+/* Macro to emit a call to a function named
+     call_made_in_{true,false}_branch_on_line_NNN()
+   for each call that's expected to be retained.  The dg-final
+   scan-tree-dump-time directive at the bottom of the test verifies
+   that the expected number of both kinds of calls appears in output
+   (a pair for each line with the invocation of the KEEP() macro.  */
+#define KEEP(expr)				\
+  if (expr)					\
+    FAIL (made_in_true_branch);			\
+  else						\
+    FAIL (made_in_false_branch)
+
+extern void sink (int, ...);
+#define sink(...) sink (0, __VA_ARGS__)
+
+#define WARN(N, expr)				\
+  do {						\
+    char a[N];					\
+    expr;					\
+    sink (a);					\
+  } while (0)
+
+
+void test_elim (double x)
+{
+  ELIM (snprintf (0, 0, "%a", x) < 3);
+  ELIM (snprintf (0, 0, "%e", x) < 3);
+  ELIM (snprintf (0, 0, "%f", x) < 3);
+  ELIM (snprintf (0, 0, "%g", x) < 1);
+
+  /* Verify that snprintf knows that NaN cannot result in fewer
+     than three characters on output.  */
+  const double nan  = __builtin_nan ("0");
+  ELIM (snprintf (0, 0, "%a", nan) < 3);
+  ELIM (snprintf (0, 0, "%e", nan) < 3);
+  ELIM (snprintf (0, 0, "%f", nan) < 3);
+  ELIM (snprintf (0, 0, "%g", nan) < 3);
+}
+
+void test_keep (int p, double x)
+{
+  KEEP (snprintf (0, 0, "%a", x) == 3);
+  KEEP (snprintf (0, 0, "%e", x) == 3);
+
+  KEEP (snprintf (0, 0, "%f", x) == 3);
+  KEEP (snprintf (0, 0, "%.*f", p, x) < 3);
+
+  KEEP (snprintf (0, 0, "%g", x) == 1);
+  KEEP (snprintf (0, 0, "%g", x) == 3);
+}
+
+void test_warn_sprintf_f (double x)
+{
+  WARN (4, sprintf (a, "%a", x));   /* { dg-warning "between 3 and 24 bytes" } */
+  WARN (4, sprintf (a, "%e", x));   /* { dg-warning "between 3 and 14 bytes" } */
+  WARN (4, sprintf (a, "%f", x));   /* { dg-warning "between 3 and 317 bytes" } */
+  WARN (4, sprintf (a, "%g", x));   /* { dg-warning "between 1 and 13 bytes" } */
+}
+
+
+/* { dg-final { scan-tree-dump-times "call_in_true_branch_not_eliminated_" 0 "optimized" } }
+   { dg-final { scan-tree-dump-times "call_made_in_true_branch_" 6" optimized" } }
+   { dg-final { scan-tree-dump-times "call_made_in_false_branch_" 6 "optimized" } }
+ */
Index: gcc/testsuite/gcc.dg/tree-ssa/builtin-sprintf-warn-1.c
===================================================================
--- gcc/testsuite/gcc.dg/tree-ssa/builtin-sprintf-warn-1.c	(revision 262312)
+++ gcc/testsuite/gcc.dg/tree-ssa/builtin-sprintf-warn-1.c	(working copy)
@@ -1377,7 +1377,8 @@  void test_sprintf_chk_e_nonconst (int w, int p, do
   T (-1, "%*.*E",  w, p, d);
   T (-1, "%*.*lE", w, p, d);
 
-  T ( 0, "%E",          d);           /* { dg-warning "writing between 12 and 14 bytes into a region of size 0" } */
+  /* The least number of bytes %E can produce is 3 for "inf" and "nan".  */
+  T ( 0, "%E",          d);           /* { dg-warning "writing between 3 and 14 bytes into a region of size 0" } */
   T ( 0, "%e",          d);           /* { dg-warning "into a region" } */
   T ( 1, "%E",          d);           /* { dg-warning "into a region" } */
   T ( 1, "%e",          d);           /* { dg-warning "into a region" } */
@@ -1389,22 +1390,22 @@  void test_sprintf_chk_e_nonconst (int w, int p, do
   T (14, "%E",          d);
   T (14, "%e",          d);
 
-  T ( 0, "%+E",         d);           /* { dg-warning "writing between 13 and 14 bytes into a region of size 0" } */
-  T ( 0, "%-e",         d);           /* { dg-warning "writing between 12 and 14 bytes into a region of size 0" } */
-  T ( 0, "% E",         d);           /* { dg-warning "writing between 13 and 14 bytes into a region of size 0" } */
+  T ( 0, "%+E",         d);           /* { dg-warning "writing between 4 and 14 bytes into a region of size 0" } */
+  T ( 0, "%-e",         d);           /* { dg-warning "writing between 3 and 14 bytes into a region of size 0" } */
+  T ( 0, "% E",         d);           /* { dg-warning "writing between 4 and 14 bytes into a region of size 0" } */
 
-  /* The range of output of "%.0e" is between 5 and 7 bytes (not counting
+  /* The range of output of "%.0e" is between 3 and 7 bytes (not counting
      the terminating NUL.  */
-  T ( 5, "%.0e",        d);           /* { dg-warning "writing a terminating nul past the end" } */
+  T ( 5, "%.0e",        d);           /* { dg-warning "may write a terminating nul past the end" } */
   T ( 6, "%.0e",        d);           /* 1e+00 */
 
-  /* The range of output of "%.1e" is between 7 and 9 bytes (not counting
+  /* The range of output of "%.1e" is between 3 and 9 bytes (not counting
      the terminating NUL.  */
-  T ( 7, "%.1e",        d);           /* { dg-warning "writing a terminating nul past the end" } */
+  T ( 7, "%.1e",        d);           /* { dg-warning "may write a terminating nul past the end" } */
   T ( 8, "%.1e",        d);
 
-  T ( 0, "%*e",      0, d);           /* { dg-warning "writing between 12 and 14 bytes into a region of size 0" } */
-  T ( 0, "%*e",      w, d);           /* { dg-warning "writing 12 or more bytes into a region of size 0|writing between 12 and \[0-9\]+ bytes into a region of size 0" } */
+  T ( 0, "%*e",      0, d);           /* { dg-warning "writing between 3 and 14 bytes into a region of size 0" } */
+  T ( 0, "%*e",      w, d);           /* { dg-warning "writing 3 or more bytes into a region of size 0|writing between 3 and \[0-9\]+ bytes into a region of size 0" } */
 }
 
 void test_sprintf_chk_f_nonconst (double d)
Index: gcc/testsuite/gcc.dg/tree-ssa/builtin-sprintf-warn-10.c
===================================================================
--- gcc/testsuite/gcc.dg/tree-ssa/builtin-sprintf-warn-10.c	(revision 262312)
+++ gcc/testsuite/gcc.dg/tree-ssa/builtin-sprintf-warn-10.c	(working copy)
@@ -25,60 +25,60 @@  extern void sink (int, void*);
 /* 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 3 and 10 bytes" } */
+  T1 ("%.*a", 1);     /* { dg-warning "between 3 and 12 bytes" } */
+  T1 ("%.*a", 2);     /* { dg-warning "between 3 and 13 bytes" } */
+  T1 ("%.*a", 99);    /* { dg-warning "between 3 and 110 bytes" } */
+  T1 ("%.*a", 199);   /* { dg-warning "between 3 and 210 bytes" } */
+  T1 ("%.*a", 1099);  /* { dg-warning "between 3 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", 0);     /* { dg-warning "between 3 and 10 bytes" } */
+  T1 ("%*.a", 1);     /* { dg-warning "between 3 and 10 bytes" } */
+  T1 ("%*.a", 3);     /* { dg-warning "between 3 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 between 6 and 2147483648 bytes" } */
-  T1 ("%*.0a", w);    /* { dg-warning "writing between 6 and 2147483648 bytes" } */
-  T1 ("%*.1a", w);    /* { dg-warning "writing between 8 and 2147483648 bytes" } */
-  T1 ("%*.2a", w);    /* { dg-warning "writing between 9 and 2147483648 bytes" } */
+  T1 ("%*.a", w);     /* { dg-warning "writing between 3 and 2147483648 bytes" } */
+  T1 ("%*.0a", w);    /* { dg-warning "writing between 3 and 2147483648 bytes" } */
+  T1 ("%*.1a", w);    /* { dg-warning "writing between 3 and 2147483648 bytes" } */
+  T1 ("%*.2a", w);    /* { dg-warning "writing between 3 and 2147483648 bytes" } */
 
-  T1 ("%.*a",  p);    /* { dg-warning "writing between 6 and 2147483658 bytes" } */
-  T1 ("%1.*a", p);    /* { dg-warning "writing between 6 and 2147483658 bytes" } */
-  T1 ("%2.*a", p);    /* { dg-warning "writing between 6 and 2147483658 bytes" } */
-  T1 ("%3.*a", p);    /* { dg-warning "writing between 6 and 2147483658 bytes" } */
+  T1 ("%.*a",  p);    /* { dg-warning "writing between 3 and 2147483658 bytes" } */
+  T1 ("%1.*a", p);    /* { dg-warning "writing between 3 and 2147483658 bytes" } */
+  T1 ("%2.*a", p);    /* { dg-warning "writing between 3 and 2147483658 bytes" } */
+  T1 ("%3.*a", p);    /* { dg-warning "writing between 3 and 2147483658 bytes" } */
 
-  T2 ("%*.*a", w, p); /* { dg-warning "writing between 6 and 2147483658 bytes" } */
+  T2 ("%*.*a", w, p); /* { dg-warning "writing between 3 and 2147483658 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 3 and 7 bytes" } */
+  T1 ("%.*e", 1);     /* { dg-warning "between 3 and 9 bytes" } */
+  T1 ("%.*e", 2);     /* { dg-warning "between 3 and 10 bytes" } */
+  T1 ("%.*e", 99);    /* { dg-warning "between 3 and 107 bytes" } */
+  T1 ("%.*e", 199);   /* { dg-warning "between 3 and 207 bytes" } */
+  T1 ("%.*e", 1099);  /* { dg-warning "between 3 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", 0);     /* { dg-warning "between 3 and 7 bytes" } */
+  T1 ("%*.e", 1);     /* { dg-warning "between 3 and 7 bytes" } */
+  T1 ("%*.e", 1);     /* { dg-warning "between 3 and 7 bytes" } */
+  T1 ("%*.e", 3);     /* { dg-warning "between 3 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 between 5 and 2147483648 bytes" } */
-  T1 ("%*.0e", w);    /* { dg-warning "writing between 5 and 2147483648 bytes" } */
-  T1 ("%*.1e", w);    /* { dg-warning "writing between 7 and 2147483648 bytes" } */
-  T1 ("%*.2e", w);    /* { dg-warning "writing between 8 and 2147483648 bytes" } */
+  T1 ("%*.e", w);     /* { dg-warning "writing between 3 and 2147483648 bytes" } */
+  T1 ("%*.0e", w);    /* { dg-warning "writing between 3 and 2147483648 bytes" } */
+  T1 ("%*.1e", w);    /* { dg-warning "writing between 3 and 2147483648 bytes" } */
+  T1 ("%*.2e", w);    /* { dg-warning "writing between 3 and 2147483648 bytes" } */
 
-  T1 ("%.*e",  p);    /* { dg-warning "writing between 5 and 2147483655 bytes" } */
-  T1 ("%1.*e", p);    /* { dg-warning "writing between 5 and 2147483655 bytes" } */
-  T1 ("%2.*e", p);    /* { dg-warning "writing between 5 and 2147483655 bytes" } */
-  T1 ("%3.*e", p);    /* { dg-warning "writing between 5 and 2147483655 bytes" } */
+  T1 ("%.*e",  p);    /* { dg-warning "writing between 3 and 2147483655 bytes" } */
+  T1 ("%1.*e", p);    /* { dg-warning "writing between 3 and 2147483655 bytes" } */
+  T1 ("%2.*e", p);    /* { dg-warning "writing between 3 and 2147483655 bytes" } */
+  T1 ("%3.*e", p);    /* { dg-warning "writing between 3 and 2147483655 bytes" } */
 
-  T2 ("%*.*e", w, p); /* { dg-warning "writing between 5 and 2147483655 bytes" } */
+  T2 ("%*.*e", w, p); /* { dg-warning "writing between 3 and 2147483655 bytes" } */
 }
 
 /* Exercise %f.  */
@@ -86,10 +86,10 @@  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" } */
+  T1 ("%.*f", 2);           /* { dg-warning "between 3 and 313 bytes" } */
+  T1 ("%.*f", 99);          /* { dg-warning "between 3 and 410 bytes" } */
+  T1 ("%.*f", 199);         /* { dg-warning "between 3 and 510 bytes" } */
+  T1 ("%.*f", 1099);        /* { dg-warning "between 3 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" } */
@@ -97,13 +97,13 @@  void test_f (int w, int p, double x)
   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" } */
+  T2 ("%*.*f", 312, 312);   /* { dg-warning "between 312 and 623 bytes" } */
+  T2 ("%*.*f", 312, 313);   /* { dg-warning "between 312 and 624 bytes" } */
 
   T1 ("%*.f", w);           /* { dg-warning "writing between 1 and 2147483648 bytes" } */
   T1 ("%*.0f", w);          /* { dg-warning "writing between 1 and 2147483648 bytes" } */
   T1 ("%*.1f", w);          /* { dg-warning "writing between 3 and 2147483648 bytes" } */
-  T1 ("%*.2f", w);          /* { dg-warning "writing between 4 and 2147483648 bytes" } */
+  T1 ("%*.2f", w);          /* { dg-warning "writing between 3 and 2147483648 bytes" } */
 
   T1 ("%.*f",  p);          /* { dg-warning "writing between 1 and 2147483958 bytes" } */
   T1 ("%1.*f", p);          /* { dg-warning "writing between 1 and 2147483958 bytes" } */
@@ -138,85 +138,85 @@  void test_g (double x)
 /* 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 ("%.0a");       /* { dg-warning "between 3 and 10 bytes" } */
+  T ("%.1a");       /* { dg-warning "between 3 and 12 bytes" } */
+  T ("%.2a");       /* { dg-warning "between 3 and 13 bytes" } */
+  T ("%.99a");      /* { dg-warning "between 3 and 110 bytes" } */
+  T ("%.199a");     /* { dg-warning "between 3 and 210 bytes" } */
+  T ("%.1099a");    /* { dg-warning "between 3 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 ("%0.a");       /* { dg-warning "between 3 and 10 bytes" } */
+  T ("%1.a");       /* { dg-warning "between 3 and 10 bytes" } */
+  T ("%3.a");       /* { dg-warning "between 3 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 between 6 and 2147483648 bytes" } */
-  T ("%*.0a");      /* { dg-warning "writing between 6 and 2147483648 bytes" } */
-  T ("%*.1a");      /* { dg-warning "writing between 8 and 2147483648 bytes" } */
-  T ("%*.2a");      /* { dg-warning "writing between 9 and 2147483648 bytes" } */
+  T ("%*.a");       /* { dg-warning "writing between 3 and 2147483648 bytes" } */
+  T ("%*.0a");      /* { dg-warning "writing between 3 and 2147483648 bytes" } */
+  T ("%*.1a");      /* { dg-warning "writing between 3 and 2147483648 bytes" } */
+  T ("%*.2a");      /* { dg-warning "writing between 3 and 2147483648 bytes" } */
 
-  T ("%.*a");       /* { dg-warning "writing between 6 and 2147483658 bytes" } */
-  T ("%1.*a");      /* { dg-warning "writing between 6 and 2147483658 bytes" } */
-  T ("%2.*a");      /* { dg-warning "writing between 6 and 2147483658 bytes" } */
+  T ("%.*a");       /* { dg-warning "writing between 3 and 2147483658 bytes" } */
+  T ("%1.*a");      /* { dg-warning "writing between 3 and 2147483658 bytes" } */
+  T ("%2.*a");      /* { dg-warning "writing between 3 and 2147483658 bytes" } */
   T ("%6.*a");      /* { dg-warning "writing between 6 and 2147483658 bytes" } */
   T ("%9.*a");      /* { dg-warning "writing between 9 and 2147483658 bytes" } */
 
-  T ("%*.*a");      /* { dg-warning "writing between 6 and 2147483658 bytes" } */
+  T ("%*.*a");      /* { dg-warning "writing between 3 and 2147483658 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 3 and 14 bytes" } */
+  T ("%+e");        /* { dg-warning "between 4 and 14 bytes" } */
+  T ("% e");        /* { dg-warning "between 4 and 14 bytes" } */
+  T ("%#e");        /* { dg-warning "between 3 and 14 bytes" } */
+  T ("%#+e");       /* { dg-warning "between 4 and 14 bytes" } */
+  T ("%# e");       /* { dg-warning "between 4 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 ("%.e");        /* { dg-warning "between 3 and 7 bytes" } */
+  T ("%.0e");       /* { dg-warning "between 3 and 7 bytes" } */
+  T ("%.1e");       /* { dg-warning "between 3 and 9 bytes" } */
+  T ("%.2e");       /* { dg-warning "between 3 and 10 bytes" } */
+  T ("%.99e");      /* { dg-warning "between 3 and 107 bytes" } */
+  T ("%.199e");     /* { dg-warning "between 3 and 207 bytes" } */
+  T ("%.1099e");    /* { dg-warning "between 3 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 ("%0.e");       /* { dg-warning "between 3 and 7 bytes" } */
+  T ("%1.e");       /* { dg-warning "between 3 and 7 bytes" } */
+  T ("%1.e");       /* { dg-warning "between 3 and 7 bytes" } */
+  T ("%3.e");       /* { dg-warning "between 3 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 between 5 and 2147483655 bytes" } */
-  T ("%1.*e");      /* { dg-warning "writing between 5 and 2147483655 bytes" } */
+  T ("%.*e");       /* { dg-warning "writing between 3 and 2147483655 bytes" } */
+  T ("%1.*e");      /* { dg-warning "writing between 3 and 2147483655 bytes" } */
   T ("%6.*e");      /* { dg-warning "writing between 6 and 2147483655 bytes" } */
   T ("%9.*e");      /* { dg-warning "writing between 9 and 2147483655 bytes" } */
 
-  T ("%*.*e");      /* { dg-warning "writing between 5 and 2147483655 bytes" } */
+  T ("%*.*e");      /* { dg-warning "writing between 3 and 2147483655 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 3 and 317 bytes" } */
+  T ("%+f");        /* { dg-warning "between 4 and 317 bytes" } */
+  T ("% f");        /* { dg-warning "between 4 and 317 bytes" } */
+  T ("%#f");        /* { dg-warning "between 3 and 317 bytes" } */
+  T ("%+f");        /* { dg-warning "between 4 and 317 bytes" } */
+  T ("% f");        /* { dg-warning "between 4 and 317 bytes" } */
+  T ("%#+f");       /* { dg-warning "between 4 and 317 bytes" } */
+  T ("%# f");       /* { dg-warning "between 4 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 ("%.2f");       /* { dg-warning "between 3 and 313 bytes" } */
+  T ("%.99f");      /* { dg-warning "between 3 and 410 bytes" } */
+  T ("%.199f");     /* { dg-warning "between 3 and 510 bytes" } */
+  T ("%.1099f");    /* { dg-warning "between 3 and 1410 bytes" } */
 
   T ("%0.0f");      /* { dg-warning "between 1 and 310 bytes" } */
   T ("%1.0f");      /* { dg-warning "between 1 and 310 bytes" } */
@@ -224,8 +224,8 @@  void test_f_va (va_list va)
   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 ("%312.312f");  /* { dg-warning "between 312 and 623 bytes" } */
+  T ("%312.313f");  /* { dg-warning "between 312 and 624 bytes" } */
 
   T ("%.*f");       /* { dg-warning "writing between 1 and 2147483958 bytes" } */
   T ("%1.*f");      /* { dg-warning "writing between 1 and 2147483958 bytes" } */
Index: gcc/testsuite/gcc.dg/tree-ssa/builtin-sprintf-warn-15.c
===================================================================
--- gcc/testsuite/gcc.dg/tree-ssa/builtin-sprintf-warn-15.c	(revision 262312)
+++ gcc/testsuite/gcc.dg/tree-ssa/builtin-sprintf-warn-15.c	(working copy)
@@ -71,14 +71,14 @@  void test_unknown_width_floating (int w, double d)
   T ( 7, "%*a", w, d);
   T (21, "%*a", w, 3.141);
 
-  T (12, "%*e",  w, d);    /* { dg-warning "writing a terminating nul" } */
-  T (12, "%#*e", w, d);    /* { dg-warning "writing a terminating nul" } */
+  T (12, "%*e",  w, d);    /* { dg-warning "may write a terminating nul" } */
+  T (12, "%#*e", w, d);    /* { dg-warning "may write a terminating nul" } */
   T (13, "%*e",  w, d);
   T (13, "%#*e", w, d);
   T (13, "%*e",  w, 3.141);
 
-  T ( 8, "%*f",  w, d);   /* { dg-warning "writing a terminating nul" } */
-  T ( 8, "%#*f", w, d);   /* { dg-warning "writing a terminating nul" } */
+  T ( 8, "%*f",  w, d);   /* { dg-warning "may write a terminating nul" } */
+  T ( 8, "%#*f", w, d);   /* { dg-warning "may write a terminating nul" } */
   T ( 9, "%*f",  w, d);
   T ( 9, "%#*f", w, d);
   T ( 9, "%*f",  w, 3.141);
@@ -106,20 +106,20 @@  void test_unknown_precision_integer (int p, int i,
 
 void test_unknown_precision_floating (int p, double d)
 {
-  T ( 0, "%.*a", R (-1, 0), d); /* { dg-warning "between 6 and 24 " } */
-  T ( 6, "%.*a", R (-1, 0), d); /* { dg-warning "writing a terminating nul" } */
+  T ( 0, "%.*a", R (-1, 0), d); /* { dg-warning "between 3 and 24 " } */
+  T ( 6, "%.*a", R (-1, 0), d); /* { dg-warning "may write a terminating nul" } */
   T ( 7, "%.*a", R (-1, 0), d);
   T ( 7, "%.*a", p, d);
   T (21, "%.*a", p, 3.141);
 
-  T ( 0, "%.*e",  R (-1, 0), d); /* { dg-warning "between 5 and 14 " } */
-  T ( 0, "%.*e",  R (-1, 6), d); /* { dg-warning "between 5 and 14 " } */
-  T ( 5, "%.*e",  R (-1, 6), d); /* { dg-warning "writing a terminating nul" } */
+  T ( 0, "%.*e",  R (-1, 0), d); /* { dg-warning "between 3 and 14 " } */
+  T ( 0, "%.*e",  R (-1, 6), d); /* { dg-warning "between 3 and 14 " } */
+  T ( 5, "%.*e",  R (-1, 6), d); /* { dg-warning "may write a terminating nul" } */
   T ( 6, "%.*e",  R (-1, 6), d);
-  /* "%.0e", 0.0 results in 5 bytes: "0e+00"  */
-  T ( 5, "%.*e",  p, d);      /* { dg-warning "writing a terminating nul" } */
-  /* "%#.0e", 0.0 results in 6 bytes: "0.e+00"  */
-  T ( 6, "%#.*e", p, d);      /* { dg-warning "writing a terminating nul" } */
+  /* "%.0e", 0.0 results in 3 or 5 bytes: "inf"/"nan" or "0e+00"  */
+  T ( 5, "%.*e",  p, d);      /* { dg-warning "may write a terminating nul" } */
+  /* "%#.0e", 0.0 results in 3 or 6 bytes: "inf"/"nan" or "0.e+00"  */
+  T ( 6, "%#.*e", p, d);      /* { dg-warning "may write a terminating nul" } */
   T ( 6, "%.*e",  p, d);
   T ( 6, "%.*e",  p, 3.141);
   T ( 6, "%#.*e", p, 3.141);  /* { dg-warning "writing a terminating nul" } */
@@ -183,10 +183,10 @@  void test_unknown_width_and_precision_floating (in
   T ( 7, "%*.*a", w, p, d);
   T (21, "%*.*a", w, p, 3.141);
 
-  /* "%0.0e", 0.0 results in 5 bytes: "0e+00"  */
-  T ( 5, "%*.*e",  w, p, d);   /* { dg-warning "writing a terminating nul" } */
-  /* "%#0.0e", 0.0 results in 6 bytes: "0.e+00"  */
-  T ( 6, "%#*.*e", w, p, d);   /* { dg-warning "writing a terminating nul" } */
+  /* "%0.0e", 0.0 results in 3 or 5 bytes: "inf"/"nan" or "0e+00"  */
+  T ( 5, "%*.*e",  w, p, d);   /* { dg-warning "may write a terminating nul" } */
+  /* "%#0.0e", 0.0 results in 3 or 6 bytes: "inf"/"nan" or "0.e+00"  */
+  T ( 6, "%#*.*e", w, p, d);   /* { dg-warning "may write a terminating nul" } */
   T ( 6, "%*.*e",  w, p, d);
   T ( 6, "%*.*e",  w, p, 3.141);
   T ( 6, "%#*.*e", w, p, 3.141);/* { dg-warning "writing a terminating nul" } */
Index: gcc/testsuite/gcc.dg/tree-ssa/builtin-sprintf-warn-7.c
===================================================================
--- gcc/testsuite/gcc.dg/tree-ssa/builtin-sprintf-warn-7.c	(revision 262312)
+++ gcc/testsuite/gcc.dg/tree-ssa/builtin-sprintf-warn-7.c	(working copy)
@@ -71,16 +71,16 @@  void test_floating_a_var (double x)
   T (0, "%*a",  INT_MIN, x);     /* { dg-warning "writing 2147483648 bytes" } */
   T (0, "%*a",  INT_MAX, x);     /* { dg-warning "writing 2147483647 bytes" } */
 
-  T (0, "%.*a", INT_MIN, x);     /* { dg-warning "writing between 6 and 24 bytes" } */
+  T (0, "%.*a", INT_MIN, x);     /* { dg-warning "writing between 3 and 24 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_MAX, x);     /* { dg-warning "writing between 3 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 2147483654 and 2147483658 bytes" } */
+  T (0, "%*.*a", INT_MAX, INT_MAX, x);   /* { dg-warning "writing between 2147483647 and 2147483658 bytes" } */
 }
 
 void test_floating_e_cst (void)
@@ -102,13 +102,13 @@  void test_floating_e_var (double x)
   T (0, "%*e",  INT_MIN, x);     /* { dg-warning "writing 2147483648 bytes" } */
   T (0, "%*e",  INT_MAX, x);     /* { dg-warning "writing 2147483647 bytes" } */
 
-  T (0, "%.*e", INT_MIN, x);     /* { dg-warning "writing between 12 and 14 bytes" } */
+  T (0, "%.*e", INT_MIN, x);     /* { dg-warning "writing between 3 and 14 bytes" } */
 
-  T (0, "%.*e", INT_MAX, x);     /* { dg-warning "writing between 2147483653 and 2147483655 bytes" } */
+  T (0, "%.*e", INT_MAX, x);     /* { dg-warning "writing between 3 and 2147483655 bytes" } */
 
   T (0, "%*.*e", INT_MIN, INT_MIN, x);   /* { dg-warning "writing 2147483648 bytes" } */
 
-  T (0, "%*.*e", INT_MAX, INT_MAX, x);   /* { dg-warning "writing between 2147483653 and 2147483655 bytes" } */
+  T (0, "%*.*e", INT_MAX, INT_MAX, x);   /* { dg-warning "writing between 2147483647 and 2147483655 bytes" } */
 }
 
 void test_floating_f_cst (void)
@@ -130,13 +130,13 @@  void test_floating_f_var (double x)
   T (0, "%*f",  INT_MIN, x);     /* { dg-warning "writing 2147483648 bytes" } */
   T (0, "%*f",  INT_MAX, x);     /* { dg-warning "writing 2147483647 bytes" } */
 
-  T (0, "%.*f", INT_MIN, x);     /* { dg-warning "writing between 8 and 317 bytes" } */
+  T (0, "%.*f", INT_MIN, x);     /* { dg-warning "writing between 3 and 317 bytes" } */
 
-  T (0, "%.*f", INT_MAX, x);     /* { dg-warning "writing between 2147483649 and 2147483958 bytes" } */
+  T (0, "%.*f", INT_MAX, x);     /* { dg-warning "writing between 3 and 2147483958 bytes" } */
 
   T (0, "%*.*f", INT_MIN, INT_MIN, x);   /* { dg-warning "writing 2147483648 bytes" } */
 
-  T (0, "%*.*f", INT_MAX, INT_MAX, x);   /* { dg-warning "writing between 2147483649 and 2147483958 bytes" } */
+  T (0, "%*.*f", INT_MAX, INT_MAX, x);   /* { dg-warning "writing between 2147483647 and 2147483958 bytes" } */
 }
 
 void test_floating_g_cst (void)
Index: gcc/testsuite/gcc.dg/tree-ssa/builtin-sprintf.c
===================================================================
--- gcc/testsuite/gcc.dg/tree-ssa/builtin-sprintf.c	(revision 262312)
+++ gcc/testsuite/gcc.dg/tree-ssa/builtin-sprintf.c	(working copy)
@@ -479,12 +479,12 @@  test_a_double (double d)
   RNG (11, 16, 17, "%.*a", 4, 6.0); /* 0xc.0000p-1 */
   RNG (12, 17, 18, "%.*a", 5, 7.0); /* 0xe.00000p-1 */
 	                            /* d is in [ 0, -DBL_MAX ] */
-  RNG ( 6, 10, 11, "%.0a", d);      /* 0x0p+0 ... -0x2p+1023 */
+  RNG ( 3, 10, 11, "%.0a", d);      /* inf/nan or 0x0p+0 ... -0x2p+1023 */
   /* %a is poorly specified and allows for implementations divergence:
      some (such as Glibc) trim redundant trailing zeros after decimal
      point and others (e.g., Solaris) don't.  */
-  RNG ( 8, 30, 31, "%.1a", d);      /* 0x0.0p+0  ... -0x2.0...0p+1023 */
-  RNG ( 9, 30, 31, "%.2a", d);      /* 0x0.00p+0 ... -0x2.00...0p+1023 */
+  RNG ( 3, 30, 31, "%.1a", d);      /* inf or 0x0.0p+0  ... -0x2.0...0p+1023 */
+  RNG ( 3, 30, 31, "%.2a", d);      /* inf or 0x0.00p+0 ... -0x2.00...0p+1023 */
 }
 
 static void __attribute__ ((noinline, noclone))
@@ -522,29 +522,32 @@  test_e_double (double d)
   RNG (12, 17, 18, "%e",  1.0e-12);
   RNG (13, 18, 19, "%e",  1.0e-123);
 
-  RNG (12, 19, 20, "%e",   d);
-  RNG ( 5, 11, 12, "%.e",  d);
-  RNG ( 5, 12, 13, "%.0e", d);
-  RNG ( 7, 14, 15, "%.1e", d);
-  RNG ( 8, 15, 16, "%.2e", d);
-  RNG ( 9, 16, 17, "%.3e", d);
-  RNG (10, 17, 18, "%.4e", d);
-  RNG (11, 18, 19, "%.5e", d);
-  RNG (12, 19, 20, "%.6e", d);
-  RNG (13, 20, 21, "%.7e", d);
+  RNG ( 3, 19, 20, "%e",   d);
+  RNG ( 3, 11, 12, "%.e",  d);
+  RNG ( 3, 12, 13, "%.0e", d);
+  RNG ( 3, 14, 15, "%.1e", d);
+  RNG ( 3, 15, 16, "%.2e", d);
+  RNG ( 3, 16, 17, "%.3e", d);
+  RNG ( 3, 17, 18, "%.4e", d);
+  RNG ( 3, 18, 19, "%.5e", d);
+  RNG ( 3, 19, 20, "%.6e", d);
+  RNG ( 3, 20, 21, "%.7e", d);
 
-  RNG (4006, 4013, 4014, "%.4000e", d);
+  RNG ( 3, 4013, 4014, "%.4000e", d);
 
-  RNG ( 5,  7,  8, "%.*e", 0, d);
-  RNG ( 7, 14, 15, "%.*e", 1, d);
-  RNG ( 8, 15, 16, "%.*e", 2, d);
-  RNG ( 9, 16, 17, "%.*e", 3, d);
-  RNG (10, 17, 18, "%.*e", 4, d);
-  RNG (11, 18, 19, "%.*e", 5, d);
-  RNG (12, 19, 20, "%.*e", 6, d);
-  RNG (13, 20, 21, "%.*e", 7, d);
+  RNG ( 3,  7,  8, "%.*e", 0, d);
+  RNG ( 3, 14, 15, "%.*e", 1, d);
+  RNG ( 3, 15, 16, "%.*e", 2, d);
+  RNG ( 3, 16, 17, "%.*e", 3, d);
+  RNG ( 3, 17, 18, "%.*e", 4, d);
+  RNG ( 3, 18, 19, "%.*e", 5, d);
+  RNG ( 3, 19, 20, "%.*e", 6, d);
+  RNG ( 3, 20, 21, "%.*e", 7, d);
 
-  RNG (4006, 4013, 4014, "%.*e", 4000, d);
+  RNG ( 3, 4013, 4014, "%.*e",  4000, d);
+  RNG ( 4, 4013, 4014, "%+.*e", 4000, d);
+  RNG ( 4, 4013, 4014, "% .*e", 4000, d);
+  RNG ( 3, 4013, 4014, "%#.*e", 4000, d);
 }
 
 static void __attribute__ ((noinline, noclone))
@@ -584,26 +587,27 @@  test_e_long_double (long double d)
   RNG (20, 26, 27, "%.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, 20, 21, "%Le", d);    /* 0.000000e+00 ...  -1.189732e+4932 */
-  RNG ( 5,  8,  9, "%.Le", d);
-  RNG ( 5,  9, 10, "%.0Le", d);
-  RNG ( 7, 15, 16, "%.1Le", d);  /* 0.0e+00      ...  -1.2e+4932 */
-  RNG ( 8, 16, 17, "%.2Le", d);  /* 0.00e+00     ...  -1.19e+4932 */
-  RNG ( 9, 17, 18, "%.3Le", d);
-  RNG (10, 18, 19, "%.4Le", d);
-  RNG (11, 19, 20, "%.5Le", d);
-  RNG (12, 20, 21, "%.6Le", d);  /* same as plain "%Le" */
-  RNG (13, 21, 22, "%.7Le", d);  /* 0.0000000e+00 ... -1.1897315e+4932 */
+     bound accounting for the four-digit exponent.  The lower bound is
+     for inf/nan.  */
+  RNG ( 3, 20, 21, "%Le", d);    /* inf or 0.000000e+00 ...  -1.189732e+4932 */
+  RNG ( 3,  8,  9, "%.Le", d);
+  RNG ( 3,  9, 10, "%.0Le", d);
+  RNG ( 3, 15, 16, "%.1Le", d);  /* inf or 0.0e+00      ...  -1.2e+4932 */
+  RNG ( 3, 16, 17, "%.2Le", d);  /* inf or 0.00e+00     ...  -1.19e+4932 */
+  RNG ( 3, 17, 18, "%.3Le", d);
+  RNG ( 3, 18, 19, "%.4Le", d);
+  RNG ( 3, 19, 20, "%.5Le", d);
+  RNG ( 3, 20, 21, "%.6Le", d);  /* same as plain "%Le" */
+  RNG ( 3, 21, 22, "%.7Le", d);  /* inf or 0.0000000e+00 ... -1.1897315e+4932 */
 
-  RNG ( 5,  9, 10, "%.*Le", 0, d);
-  RNG ( 7, 15, 16, "%.*Le", 1, d);
-  RNG ( 8, 16, 17, "%.*Le", 2, d);
-  RNG ( 9, 17, 18, "%.*Le", 3, d);
-  RNG (10, 18, 19, "%.*Le", 4, d);
-  RNG (11, 19, 20, "%.*Le", 5, d);
-  RNG (12, 20, 21, "%.*Le", 6, d);
-  RNG (13, 21, 22, "%.*Le", 7, d);
+  RNG ( 3,  9, 10, "%.*Le", 0, d);
+  RNG ( 3, 15, 16, "%.*Le", 1, d);
+  RNG ( 3, 16, 17, "%.*Le", 2, d);
+  RNG ( 3, 17, 18, "%.*Le", 3, d);
+  RNG ( 3, 18, 19, "%.*Le", 4, d);
+  RNG ( 3, 19, 20, "%.*Le", 5, d);
+  RNG ( 3, 20, 21, "%.*Le", 6, d);
+  RNG ( 3, 21, 22, "%.*Le", 7, d);
 }
 
 static void __attribute__ ((noinline, noclone))
@@ -626,7 +630,10 @@  test_f_double (double d)
   RNG (  8,  13,  14, "%f", 1.0e-12);
   RNG (  8,  13,  14, "%f", 1.0e-123);
 
-  RNG (  8, 322, 323, "%f", d);
+  RNG (  3, 322, 323, "%f",  d);
+  RNG (  4, 322, 323, "%+f", d);
+  RNG (  4, 322, 323, "% f", d);
+  RNG (  3, 322, 323, "%#f", d);
 }
 
 static void __attribute__ ((noinline, noclone))
Index: gcc/testsuite/gcc.dg/tree-ssa/pr83198.c
===================================================================
--- gcc/testsuite/gcc.dg/tree-ssa/pr83198.c	(revision 262312)
+++ gcc/testsuite/gcc.dg/tree-ssa/pr83198.c	(working copy)
@@ -7,10 +7,14 @@  void bar (void);
 void link_error (void);
 
 void
-foo (char *x)
+foo (char *x, double y)
 {
+  /* The expected result should not be constant but rather that
+     of the %f directive with an unknown argument, i.e., at least
+     [3, 317] (but in reality [3, 322] when taking into account
+     that the decimal point can be up to MB_LEN_MAX bytes long).  */
   int a = __builtin_sprintf (x, "%f", 1.0Q);
-  if (a < 8)
+  if (a < 3)
     link_error ();
   if (a > 13)
     bar ();
@@ -18,6 +22,6 @@  void
     link_error ();
 }
 
-/* Verify we don't optimize return value to [8, 13].  */
+/* Verify we don't optimize return value to [3, 13].  */
 /* { dg-final { scan-tree-dump-not "link_error \\(\\);" "optimized" } } */
 /* { dg-final { scan-tree-dump "bar \\(\\);" "optimized" } } */