Commit f589a1ce by Martin Sebor Committed by Martin Sebor

PR tree-optimization/79327 - wrong code at -O2 and -fprintf-return-value

PR tree-optimization/79327 - wrong code at -O2 and -fprintf-return-value
gcc/ChangeLog:
	* gimple-ssa-sprintf.c (tree_digits): Avoid adding the base prefix
	when precision has resulted in leading zeros.
	(format_integer): Adjust the likely counter to assume an unknown
	argument that may be zero is non-zero.

gcc/testsuite/ChangeLog:
	* gcc.dg/tree-ssa/builtin-sprintf-warn-1.c: Adjust.
	* gcc/testsuite/gcc.dg/tree-ssa/builtin-sprintf-warn-13.c: New test.
	* gcc/testsuite/gcc.dg/tree-ssa/pr79327-2.c: Ditto.

From-SVN: r245173
parent 77095a6a
2017-02-03 Martin Sebor <msebor@redhat.com>
PR tree-optimization/79327
* gimple-ssa-sprintf.c (tree_digits): Avoid adding the base prefix
when precision has resulted in leading zeros.
(format_integer): Adjust the likely counter to assume an unknown
argument that may be zero is non-zero.
2017-02-03 Jason Merrill <jason@redhat.com>
PR c++/78689
......
......@@ -762,7 +762,9 @@ tree_digits (tree x, int base, HOST_WIDE_INT prec, bool plus, bool prefix)
res += prec < ndigs ? ndigs : prec;
if (prefix && absval)
/* Adjust a non-zero value for the base prefix, either hexadecimal,
or, unless precision has resulted in a leading zero, also octal. */
if (prefix && absval && (base == 16 || prec <= ndigs))
{
if (base == 8)
res += 1;
......@@ -1230,6 +1232,10 @@ format_integer (const directive &dir, tree arg)
of the format string by returning [-1, -1]. */
return fmtresult ();
/* True if the LIKELY counter should be adjusted upward from the MIN
counter to account for arguments with unknown values. */
bool likely_adjust = false;
fmtresult res;
/* Using either the range the non-constant argument is in, or its
......@@ -1259,6 +1265,14 @@ format_integer (const directive &dir, tree arg)
res.argmin = argmin;
res.argmax = argmax;
/* Set the adjustment for an argument whose range includes
zero since that doesn't include the octal or hexadecimal
base prefix. */
wide_int wzero = wi::zero (wi::get_precision (min));
if (wi::le_p (min, wzero, SIGNED)
&& !wi::neg_p (max))
likely_adjust = true;
}
else if (range_type == VR_ANTI_RANGE)
{
......@@ -1293,6 +1307,11 @@ format_integer (const directive &dir, tree arg)
if (!argmin)
{
/* Set the adjustment for an argument whose range includes
zero since that doesn't include the octal or hexadecimal
base prefix. */
likely_adjust = true;
if (TREE_CODE (argtype) == POINTER_TYPE)
{
argmin = build_int_cst (pointer_sized_int_node, 0);
......@@ -1345,7 +1364,24 @@ format_integer (const directive &dir, tree arg)
res.range.max = MAX (max1, max2);
}
res.range.likely = res.knownrange ? res.range.max : res.range.min;
/* Add the adjustment for an argument whose range includes zero
since it doesn't include the octal or hexadecimal base prefix. */
if (res.knownrange)
res.range.likely = res.range.max;
else
{
res.range.likely = res.range.min;
if (likely_adjust && maybebase && base != 10)
{
if (res.range.min == 1)
res.range.likely += base == 8 ? 1 : 2;
else if (res.range.min == 2
&& base == 16
&& (dir.width[0] == 2 || dir.prec[0] == 2))
++res.range.likely;
}
}
res.range.unlikely = res.range.max;
res.adjust_for_width_or_precision (dir.width, dirtype, base,
(sign | maybebase) + (base == 16));
......
2017-02-03 Martin Sebor <msebor@redhat.com>
PR tree-optimization/79327
* gcc.dg/tree-ssa/builtin-sprintf-warn-1.c: Adjust.
* gcc/testsuite/gcc.dg/tree-ssa/builtin-sprintf-warn-13.c: New test.
* gcc/testsuite/gcc.dg/tree-ssa/pr79327-2.c: Ditto.
2017-02-03 Jakub Jelinek <jakub@redhat.com>
Martin Sebor <msebor@redhat.com>
......
......@@ -1151,8 +1151,16 @@ void test_sprintf_chk_hh_nonconst (int w, int p, int a)
T (2, "% hhu", a); /* { dg-warning ". . flag used with .%u." } */
T (2, "% hhx", a); /* { dg-warning ". . flag used with .%x." } */
T (2, "%#hho", a);
T (2, "%#hhx", a);
/* The following results in between "0" and "0377" for -1. Although
the minimum output would fit, given the '#' flag the likely output
(i.e., for any non-zero argument) includes a leading zero followed
by one or more octal digits, which results in the terminating nul
being written past the end. Thus the "may write" warning. */
T (2, "%#hho", a); /* { dg-warning "may write a terminating nul" } */
/* Similar to the above, but the likely output of the directive for
a non-zero argument overflows. Thus the "writing X bytes" (as
opposed to "may write") warning. */
T (2, "%#hhx", a); /* { dg-warning "writing between 1 and 4 bytes" } */
T (3, "%0hhd", a);
T (3, "%1hhd", a);
......
/* PR tree-optimization/79327 - wrong code at -O2 and -fprintf-return-value
{ dg-compile }
{ dg-options "-O2 -fdump-tree-optimized" } */
#define CAT(s, n) s ## n
#define FAIL(line) CAT (failure_on_line_, line)
/* Emit a call to a function named failure_on_line_NNN when EXPR is false. */
#define ASSERT(expr) \
do { \
extern void FAIL (__LINE__)(void); \
if (!(expr)) FAIL (__LINE__)(); \
} while (0)
#define KEEP(line) CAT (keep_call_on_line_, line)
/* Emit a call to a function named keep_call_on_line_NNN when EXPR is true.
Used to verify that the expression need not be the only one that holds. */
#define ASSERT_MAYBE(expr) \
do { \
extern void KEEP (__LINE__)(void); \
if (expr) KEEP (__LINE__)(); \
} while (0)
void test_hho_cst (void)
{
ASSERT (1 == __builtin_snprintf (0, 0, "%#.1hho", 0));
ASSERT (2 == __builtin_snprintf (0, 0, "%#.2hho", 0));
ASSERT (2 == __builtin_snprintf (0, 0, "%#.1hho", 1));
ASSERT (2 == __builtin_snprintf (0, 0, "%#.2hho", 1));
ASSERT (3 == __builtin_snprintf (0, 0, "%#.3hho", 1));
}
int test_hho_var (int i)
{
int n = __builtin_snprintf (0, 0, "%#hho", i);
ASSERT (0 < n && n < 5);
ASSERT_MAYBE (1 == n);
ASSERT_MAYBE (2 == n);
ASSERT_MAYBE (3 == n);
ASSERT_MAYBE (4 == n);
return n;
}
int test_ho_var (int i)
{
int n = __builtin_snprintf (0, 0, "%#ho", i);
ASSERT (0 < n && n < 8);
ASSERT_MAYBE (1 == n);
ASSERT_MAYBE (2 == n);
ASSERT_MAYBE (3 == n);
ASSERT_MAYBE (4 == n);
ASSERT_MAYBE (5 == n);
ASSERT_MAYBE (6 == n);
ASSERT_MAYBE (7 == n);
return n;
}
int test_o_var (int i)
{
int n = __builtin_snprintf (0, 0, "%#o", i);
ASSERT (0 < n && n < 13);
ASSERT_MAYBE (1 == n);
ASSERT_MAYBE (2 == n);
ASSERT_MAYBE (3 == n);
ASSERT_MAYBE (4 == n);
ASSERT_MAYBE (5 == n);
ASSERT_MAYBE (6 == n);
ASSERT_MAYBE (7 == n);
ASSERT_MAYBE (8 == n);
ASSERT_MAYBE (9 == n);
ASSERT_MAYBE (10 == n);
ASSERT_MAYBE (11 == n);
ASSERT_MAYBE (12 == n);
return n;
}
void test_hhx_cst (void)
{
ASSERT (1 == __builtin_snprintf (0, 0, "%#.1hhx", 0));
ASSERT (2 == __builtin_snprintf (0, 0, "%#.2hhx", 0));
ASSERT (3 == __builtin_snprintf (0, 0, "%#.1hhx", 1));
ASSERT (4 == __builtin_snprintf (0, 0, "%#.2hhx", 1));
ASSERT (5 == __builtin_snprintf (0, 0, "%#.3hhx", 1));
}
int test_hhx_var (int i)
{
int n = __builtin_snprintf (0, 0, "%#hhx", i);
ASSERT (0 < n && n < 5);
ASSERT_MAYBE (1 == n);
ASSERT_MAYBE (2 == n);
ASSERT_MAYBE (3 == n);
ASSERT_MAYBE (4 == n);
return n;
}
void test_hx_cst (void)
{
ASSERT (1 == __builtin_snprintf (0, 0, "%#.1hx", 0));
ASSERT (2 == __builtin_snprintf (0, 0, "%#.2hx", 0));
ASSERT (3 == __builtin_snprintf (0, 0, "%#.1hx", 1));
ASSERT (4 == __builtin_snprintf (0, 0, "%#.2hx", 1));
ASSERT (5 == __builtin_snprintf (0, 0, "%#.3hx", 1));
}
int test_hx_var (int i)
{
int n = __builtin_snprintf (0, 0, "%#hx", i);
ASSERT (0 < n && n < 7);
ASSERT_MAYBE (1 == n);
ASSERT_MAYBE (2 == n);
ASSERT_MAYBE (3 == n);
ASSERT_MAYBE (4 == n);
ASSERT_MAYBE (5 == n);
ASSERT_MAYBE (6 == n);
return n;
}
int test_x_var (int i)
{
int n = __builtin_snprintf (0, 0, "%#x", i);
ASSERT (0 < n && n < 11);
ASSERT_MAYBE (1 == n);
ASSERT_MAYBE (2 == n);
ASSERT_MAYBE (3 == n);
ASSERT_MAYBE (4 == n);
ASSERT_MAYBE (5 == n);
ASSERT_MAYBE (6 == n);
ASSERT_MAYBE (7 == n);
ASSERT_MAYBE (8 == n);
ASSERT_MAYBE (9 == n);
ASSERT_MAYBE (10 == n);
return n;
}
/* { dg-final { scan-tree-dump-not "failure_on_line" "optimized"} }
{ dg-final { scan-tree-dump-times "keep_call_on_line" 43 "optimized"} } */
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment