re PR middle-end/62090 (ice in compute_may_aliases)
2014-08-14 Richard Biener <rguenther@suse.de> PR tree-optimization/62090 * builtins.c (fold_builtin_sprintf): Move to gimple-fold.c. (fold_builtin_2): Do not fold sprintf. (fold_builtin_3): Likewise. * gimple-fold.c (gimple_fold_builtin_sprintf): New function moved from builtins.c. (gimple_fold_builtin): Fold sprintf. * gcc.dg/pr62090.c: New testcase. From-SVN: r213951
This commit is contained in:
parent
121bc7dc36
commit
35770bb20f
5 changed files with 160 additions and 95 deletions
|
@ -1,3 +1,13 @@
|
|||
2014-08-14 Richard Biener <rguenther@suse.de>
|
||||
|
||||
PR tree-optimization/62090
|
||||
* builtins.c (fold_builtin_sprintf): Move to gimple-fold.c.
|
||||
(fold_builtin_2): Do not fold sprintf.
|
||||
(fold_builtin_3): Likewise.
|
||||
* gimple-fold.c (gimple_fold_builtin_sprintf): New function
|
||||
moved from builtins.c.
|
||||
(gimple_fold_builtin): Fold sprintf.
|
||||
|
||||
2014-08-14 Richard Biener <rguenther@suse.de>
|
||||
|
||||
PR rtl-optimization/62079
|
||||
|
|
|
@ -190,7 +190,6 @@ static tree fold_builtin_strrchr (location_t, tree, tree, tree);
|
|||
static tree fold_builtin_strncat (location_t, tree, tree, tree);
|
||||
static tree fold_builtin_strspn (location_t, tree, tree);
|
||||
static tree fold_builtin_strcspn (location_t, tree, tree);
|
||||
static tree fold_builtin_sprintf (location_t, tree, tree, tree, int);
|
||||
static tree fold_builtin_snprintf (location_t, tree, tree, tree, tree, int);
|
||||
|
||||
static rtx expand_builtin_object_size (tree);
|
||||
|
@ -10234,9 +10233,6 @@ fold_builtin_2 (location_t loc, tree fndecl, tree arg0, tree arg1, bool ignore)
|
|||
case BUILT_IN_VA_START:
|
||||
break;
|
||||
|
||||
case BUILT_IN_SPRINTF:
|
||||
return fold_builtin_sprintf (loc, arg0, arg1, NULL_TREE, ignore);
|
||||
|
||||
case BUILT_IN_OBJECT_SIZE:
|
||||
return fold_builtin_object_size (arg0, arg1);
|
||||
|
||||
|
@ -10313,9 +10309,6 @@ fold_builtin_3 (location_t loc, tree fndecl,
|
|||
case BUILT_IN_MEMCMP:
|
||||
return fold_builtin_memcmp (loc, arg0, arg1, arg2);;
|
||||
|
||||
case BUILT_IN_SPRINTF:
|
||||
return fold_builtin_sprintf (loc, arg0, arg1, arg2, ignore);
|
||||
|
||||
case BUILT_IN_SNPRINTF:
|
||||
return fold_builtin_snprintf (loc, arg0, arg1, arg2, NULL_TREE, ignore);
|
||||
|
||||
|
@ -11237,94 +11230,6 @@ fold_builtin_next_arg (tree exp, bool va_start_p)
|
|||
}
|
||||
|
||||
|
||||
/* Simplify a call to the sprintf builtin with arguments DEST, FMT, and ORIG.
|
||||
ORIG may be null if this is a 2-argument call. We don't attempt to
|
||||
simplify calls with more than 3 arguments.
|
||||
|
||||
Return NULL_TREE if no simplification was possible, otherwise return the
|
||||
simplified form of the call as a tree. If IGNORED is true, it means that
|
||||
the caller does not use the returned value of the function. */
|
||||
|
||||
static tree
|
||||
fold_builtin_sprintf (location_t loc, tree dest, tree fmt,
|
||||
tree orig, int ignored)
|
||||
{
|
||||
tree call, retval;
|
||||
const char *fmt_str = NULL;
|
||||
|
||||
/* Verify the required arguments in the original call. We deal with two
|
||||
types of sprintf() calls: 'sprintf (str, fmt)' and
|
||||
'sprintf (dest, "%s", orig)'. */
|
||||
if (!validate_arg (dest, POINTER_TYPE)
|
||||
|| !validate_arg (fmt, POINTER_TYPE))
|
||||
return NULL_TREE;
|
||||
if (orig && !validate_arg (orig, POINTER_TYPE))
|
||||
return NULL_TREE;
|
||||
|
||||
/* Check whether the format is a literal string constant. */
|
||||
fmt_str = c_getstr (fmt);
|
||||
if (fmt_str == NULL)
|
||||
return NULL_TREE;
|
||||
|
||||
call = NULL_TREE;
|
||||
retval = NULL_TREE;
|
||||
|
||||
if (!init_target_chars ())
|
||||
return NULL_TREE;
|
||||
|
||||
/* If the format doesn't contain % args or %%, use strcpy. */
|
||||
if (strchr (fmt_str, target_percent) == NULL)
|
||||
{
|
||||
tree fn = builtin_decl_implicit (BUILT_IN_STRCPY);
|
||||
|
||||
if (!fn)
|
||||
return NULL_TREE;
|
||||
|
||||
/* Don't optimize sprintf (buf, "abc", ptr++). */
|
||||
if (orig)
|
||||
return NULL_TREE;
|
||||
|
||||
/* Convert sprintf (str, fmt) into strcpy (str, fmt) when
|
||||
'format' is known to contain no % formats. */
|
||||
call = build_call_expr_loc (loc, fn, 2, dest, fmt);
|
||||
if (!ignored)
|
||||
retval = build_int_cst (integer_type_node, strlen (fmt_str));
|
||||
}
|
||||
|
||||
/* If the format is "%s", use strcpy if the result isn't used. */
|
||||
else if (fmt_str && strcmp (fmt_str, target_percent_s) == 0)
|
||||
{
|
||||
tree fn;
|
||||
fn = builtin_decl_implicit (BUILT_IN_STRCPY);
|
||||
|
||||
if (!fn)
|
||||
return NULL_TREE;
|
||||
|
||||
/* Don't crash on sprintf (str1, "%s"). */
|
||||
if (!orig)
|
||||
return NULL_TREE;
|
||||
|
||||
/* Convert sprintf (str1, "%s", str2) into strcpy (str1, str2). */
|
||||
if (!ignored)
|
||||
{
|
||||
retval = c_strlen (orig, 1);
|
||||
if (!retval || TREE_CODE (retval) != INTEGER_CST)
|
||||
return NULL_TREE;
|
||||
}
|
||||
call = build_call_expr_loc (loc, fn, 2, dest, orig);
|
||||
}
|
||||
|
||||
if (call && retval)
|
||||
{
|
||||
retval = fold_convert_loc
|
||||
(loc, TREE_TYPE (TREE_TYPE (builtin_decl_implicit (BUILT_IN_SPRINTF))),
|
||||
retval);
|
||||
return build2 (COMPOUND_EXPR, TREE_TYPE (retval), call, retval);
|
||||
}
|
||||
else
|
||||
return call;
|
||||
}
|
||||
|
||||
/* Simplify a call to the snprintf builtin with arguments DEST, DESTSIZE,
|
||||
FMT, and ORIG. ORIG may be null if this is a 3-argument call. We don't
|
||||
attempt to simplify calls with more than 4 arguments.
|
||||
|
|
|
@ -2143,6 +2143,132 @@ gimple_fold_builtin_sprintf_chk (gimple_stmt_iterator *gsi,
|
|||
return true;
|
||||
}
|
||||
|
||||
/* Simplify a call to the sprintf builtin with arguments DEST, FMT, and ORIG.
|
||||
ORIG may be null if this is a 2-argument call. We don't attempt to
|
||||
simplify calls with more than 3 arguments.
|
||||
|
||||
Return NULL_TREE if no simplification was possible, otherwise return the
|
||||
simplified form of the call as a tree. If IGNORED is true, it means that
|
||||
the caller does not use the returned value of the function. */
|
||||
|
||||
static bool
|
||||
gimple_fold_builtin_sprintf (gimple_stmt_iterator *gsi)
|
||||
{
|
||||
gimple stmt = gsi_stmt (*gsi);
|
||||
tree dest = gimple_call_arg (stmt, 0);
|
||||
tree fmt = gimple_call_arg (stmt, 1);
|
||||
tree orig = NULL_TREE;
|
||||
const char *fmt_str = NULL;
|
||||
|
||||
/* Verify the required arguments in the original call. We deal with two
|
||||
types of sprintf() calls: 'sprintf (str, fmt)' and
|
||||
'sprintf (dest, "%s", orig)'. */
|
||||
if (gimple_call_num_args (stmt) > 3)
|
||||
return false;
|
||||
|
||||
if (gimple_call_num_args (stmt) == 3)
|
||||
orig = gimple_call_arg (stmt, 2);
|
||||
|
||||
/* Check whether the format is a literal string constant. */
|
||||
fmt_str = c_getstr (fmt);
|
||||
if (fmt_str == NULL)
|
||||
return false;
|
||||
|
||||
if (!init_target_chars ())
|
||||
return false;
|
||||
|
||||
/* If the format doesn't contain % args or %%, use strcpy. */
|
||||
if (strchr (fmt_str, target_percent) == NULL)
|
||||
{
|
||||
tree fn = builtin_decl_implicit (BUILT_IN_STRCPY);
|
||||
|
||||
if (!fn)
|
||||
return false;
|
||||
|
||||
/* Don't optimize sprintf (buf, "abc", ptr++). */
|
||||
if (orig)
|
||||
return false;
|
||||
|
||||
/* Convert sprintf (str, fmt) into strcpy (str, fmt) when
|
||||
'format' is known to contain no % formats. */
|
||||
gimple_seq stmts = NULL;
|
||||
gimple repl = gimple_build_call (fn, 2, dest, fmt);
|
||||
gimple_seq_add_stmt_without_update (&stmts, repl);
|
||||
if (gimple_call_lhs (stmt))
|
||||
{
|
||||
repl = gimple_build_assign (gimple_call_lhs (stmt),
|
||||
build_int_cst (integer_type_node,
|
||||
strlen (fmt_str)));
|
||||
gimple_seq_add_stmt_without_update (&stmts, repl);
|
||||
gsi_replace_with_seq_vops (gsi, stmts);
|
||||
/* gsi now points at the assignment to the lhs, get a
|
||||
stmt iterator to the memcpy call.
|
||||
??? We can't use gsi_for_stmt as that doesn't work when the
|
||||
CFG isn't built yet. */
|
||||
gimple_stmt_iterator gsi2 = *gsi;
|
||||
gsi_prev (&gsi2);
|
||||
fold_stmt (&gsi2);
|
||||
}
|
||||
else
|
||||
{
|
||||
gsi_replace_with_seq_vops (gsi, stmts);
|
||||
fold_stmt (gsi);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/* If the format is "%s", use strcpy if the result isn't used. */
|
||||
else if (fmt_str && strcmp (fmt_str, target_percent_s) == 0)
|
||||
{
|
||||
tree fn;
|
||||
fn = builtin_decl_implicit (BUILT_IN_STRCPY);
|
||||
|
||||
if (!fn)
|
||||
return false;
|
||||
|
||||
/* Don't crash on sprintf (str1, "%s"). */
|
||||
if (!orig)
|
||||
return false;
|
||||
|
||||
tree len = NULL_TREE;
|
||||
if (gimple_call_lhs (stmt))
|
||||
{
|
||||
len = c_strlen (orig, 1);
|
||||
if (!len)
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Convert sprintf (str1, "%s", str2) into strcpy (str1, str2). */
|
||||
gimple_seq stmts = NULL;
|
||||
gimple repl = gimple_build_call (fn, 2, dest, orig);
|
||||
gimple_seq_add_stmt_without_update (&stmts, repl);
|
||||
if (gimple_call_lhs (stmt))
|
||||
{
|
||||
if (!useless_type_conversion_p (integer_type_node, TREE_TYPE (len)))
|
||||
len = fold_convert (integer_type_node, len);
|
||||
repl = gimple_build_assign (gimple_call_lhs (stmt), len);
|
||||
gimple_seq_add_stmt_without_update (&stmts, repl);
|
||||
gsi_replace_with_seq_vops (gsi, stmts);
|
||||
/* gsi now points at the assignment to the lhs, get a
|
||||
stmt iterator to the memcpy call.
|
||||
??? We can't use gsi_for_stmt as that doesn't work when the
|
||||
CFG isn't built yet. */
|
||||
gimple_stmt_iterator gsi2 = *gsi;
|
||||
gsi_prev (&gsi2);
|
||||
fold_stmt (&gsi2);
|
||||
}
|
||||
else
|
||||
{
|
||||
gsi_replace_with_seq_vops (gsi, stmts);
|
||||
fold_stmt (gsi);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/* Fold a call to __builtin_strlen with known length LEN. */
|
||||
|
||||
|
@ -2349,6 +2475,8 @@ gimple_fold_builtin (gimple_stmt_iterator *gsi)
|
|||
case BUILT_IN_SPRINTF_CHK:
|
||||
case BUILT_IN_VSPRINTF_CHK:
|
||||
return gimple_fold_builtin_sprintf_chk (gsi, DECL_FUNCTION_CODE (callee));
|
||||
case BUILT_IN_SPRINTF:
|
||||
return gimple_fold_builtin_sprintf (gsi);
|
||||
default:;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,3 +1,8 @@
|
|||
2014-08-14 Richard Biener <rguenther@suse.de>
|
||||
|
||||
PR tree-optimization/62090
|
||||
* gcc.dg/pr62090.c: New testcase.
|
||||
|
||||
2014-08-14 Richard Biener <rguenther@suse.de>
|
||||
|
||||
PR rtl-optimization/62079
|
||||
|
|
17
gcc/testsuite/gcc.dg/pr62090.c
Normal file
17
gcc/testsuite/gcc.dg/pr62090.c
Normal file
|
@ -0,0 +1,17 @@
|
|||
/* { dg-do compile } */
|
||||
/* { dg-options "-O2" } */
|
||||
|
||||
long a;
|
||||
int *b;
|
||||
extern __inline __attribute__ ((__always_inline__))
|
||||
__attribute__ ((__gnu_inline__)) int sprintf (int *p1, char *p2, ...)
|
||||
{
|
||||
a = __builtin_object_size (0, 0);
|
||||
return __builtin___sprintf_chk (0, 0, a, p2, __builtin_va_arg_pack ());
|
||||
}
|
||||
|
||||
void
|
||||
log_bad_request ()
|
||||
{
|
||||
b += sprintf (0, "foo");
|
||||
}
|
Loading…
Add table
Reference in a new issue