builtins.c (target_percent_c): Export.

2014-12-03  Richard Biener  <rguenther@suse.de>

	* builtins.c (target_percent_c): Export.
	(fold_builtin_fprintf): Move to gimple-fold.c.
	(fold_builtin_2): Do not fold fprintf functions.
	(fold_builtin_3): Likewise.
	(fold_builtin_4): Remove.
	(fold_builtin_n): Do not call fold_builtin_4.
	* builtins.h (target_percent_c): Declare.
	* gimple-fold.c (gimple_fold_builtin_fprintf): Move from
	builtins.c and gimplify.
	(gimple_fold_builtin): Fold fprintf, fprintf_unlocked, vfprintf,
	fprintf_chk and vfprintf_chk here.

From-SVN: r218317
This commit is contained in:
Richard Biener 2014-12-03 14:08:07 +00:00 committed by Richard Biener
parent 2f35958cd5
commit edd7ae68b0
4 changed files with 149 additions and 164 deletions

View File

@ -1,3 +1,17 @@
2014-12-03 Richard Biener <rguenther@suse.de>
* builtins.c (target_percent_c): Export.
(fold_builtin_fprintf): Move to gimple-fold.c.
(fold_builtin_2): Do not fold fprintf functions.
(fold_builtin_3): Likewise.
(fold_builtin_4): Remove.
(fold_builtin_n): Do not call fold_builtin_4.
* builtins.h (target_percent_c): Declare.
* gimple-fold.c (gimple_fold_builtin_fprintf): Move from
builtins.c and gimplify.
(gimple_fold_builtin): Fold fprintf, fprintf_unlocked, vfprintf,
fprintf_chk and vfprintf_chk here.
2014-12-03 Martin Jambor <mjambor@suse.cz>
PR ipa/64153

View File

@ -195,7 +195,6 @@ static tree fold_builtin_0 (location_t, tree, bool);
static tree fold_builtin_1 (location_t, tree, tree, bool);
static tree fold_builtin_2 (location_t, tree, tree, tree, bool);
static tree fold_builtin_3 (location_t, tree, tree, tree, tree, bool);
static tree fold_builtin_4 (location_t, tree, tree, tree, tree, tree, bool);
static tree fold_builtin_varargs (location_t, tree, tree*, int, bool);
static tree fold_builtin_strpbrk (location_t, tree, tree, tree);
@ -213,14 +212,12 @@ static void maybe_emit_sprintf_chk_warning (tree, enum built_in_function);
static void maybe_emit_free_warning (tree);
static tree fold_builtin_object_size (tree, tree);
static tree fold_builtin_printf (location_t, tree, tree, tree, bool, enum built_in_function);
static tree fold_builtin_fprintf (location_t, tree, tree, tree, tree, bool,
enum built_in_function);
static unsigned HOST_WIDE_INT target_newline;
unsigned HOST_WIDE_INT target_percent;
static unsigned HOST_WIDE_INT target_c;
static unsigned HOST_WIDE_INT target_s;
static char target_percent_c[3];
char target_percent_c[3];
char target_percent_s[3];
static char target_percent_s_newline[4];
static tree do_mpfr_arg1 (tree, tree, int (*)(mpfr_ptr, mpfr_srcptr, mp_rnd_t),
@ -10481,12 +10478,6 @@ fold_builtin_2 (location_t loc, tree fndecl, tree arg0, tree arg1, bool ignore)
arg1, NULL_TREE, ignore, fcode);
break;
case BUILT_IN_FPRINTF:
case BUILT_IN_FPRINTF_UNLOCKED:
case BUILT_IN_VFPRINTF:
return fold_builtin_fprintf (loc, fndecl, arg0, arg1, NULL_TREE,
ignore, fcode);
case BUILT_IN_ATOMIC_ALWAYS_LOCK_FREE:
return fold_builtin_atomic_always_lock_free (arg0, arg1);
@ -10548,21 +10539,6 @@ fold_builtin_3 (location_t loc, tree fndecl,
return fold_builtin_printf (loc, fndecl, arg1, arg2, ignore, fcode);
break;
case BUILT_IN_FPRINTF:
case BUILT_IN_FPRINTF_UNLOCKED:
case BUILT_IN_VFPRINTF:
return fold_builtin_fprintf (loc, fndecl, arg0, arg1, arg2,
ignore, fcode);
case BUILT_IN_FPRINTF_CHK:
case BUILT_IN_VFPRINTF_CHK:
if (!validate_arg (arg1, INTEGER_TYPE)
|| TREE_SIDE_EFFECTS (arg1))
return NULL_TREE;
else
return fold_builtin_fprintf (loc, fndecl, arg0, arg2, NULL_TREE,
ignore, fcode);
case BUILT_IN_EXPECT:
return fold_builtin_expect (loc, arg0, arg1, arg2);
@ -10595,35 +10571,6 @@ fold_builtin_3 (location_t loc, tree fndecl,
return NULL_TREE;
}
/* Fold a call to built-in function FNDECL with 4 arguments, ARG0, ARG1,
ARG2, and ARG3. IGNORE is true if the result of the function call is
ignored. This function returns NULL_TREE if no simplification was
possible. */
static tree
fold_builtin_4 (location_t loc, tree fndecl,
tree arg0, tree arg1, tree arg2, tree arg3, bool ignore)
{
enum built_in_function fcode = DECL_FUNCTION_CODE (fndecl);
switch (fcode)
{
case BUILT_IN_FPRINTF_CHK:
case BUILT_IN_VFPRINTF_CHK:
if (!validate_arg (arg1, INTEGER_TYPE)
|| TREE_SIDE_EFFECTS (arg1))
return NULL_TREE;
else
return fold_builtin_fprintf (loc, fndecl, arg0, arg2, arg3,
ignore, fcode);
break;
default:
break;
}
return NULL_TREE;
}
/* Fold a call to built-in function FNDECL. ARGS is an array of NARGS
arguments. IGNORE is true if the result of the
function call is ignored. This function returns NULL_TREE if no
@ -10648,10 +10595,6 @@ fold_builtin_n (location_t loc, tree fndecl, tree *args, int nargs, bool ignore)
case 3:
ret = fold_builtin_3 (loc, fndecl, args[0], args[1], args[2], ignore);
break;
case 4:
ret = fold_builtin_4 (loc, fndecl, args[0], args[1], args[2], args[3],
ignore);
break;
default:
ret = fold_builtin_varargs (loc, fndecl, args, nargs, ignore);
break;
@ -11977,105 +11920,6 @@ fold_builtin_printf (location_t loc, tree fndecl, tree fmt,
return fold_convert_loc (loc, TREE_TYPE (TREE_TYPE (fndecl)), call);
}
/* Fold a call to the {,v}fprintf{,_unlocked} and __{,v}printf_chk builtins.
FP, FMT, and ARG are the arguments to the call. We don't fold calls with
more than 3 arguments, and ARG may be null in the 2-argument case.
Return NULL_TREE if no simplification was possible, otherwise return the
simplified form of the call as a tree. FCODE is the BUILT_IN_*
code of the function to be simplified. */
static tree
fold_builtin_fprintf (location_t loc, tree fndecl, tree fp,
tree fmt, tree arg, bool ignore,
enum built_in_function fcode)
{
tree fn_fputc, fn_fputs, call = NULL_TREE;
const char *fmt_str = NULL;
/* If the return value is used, don't do the transformation. */
if (! ignore)
return NULL_TREE;
/* Verify the required arguments in the original call. */
if (!validate_arg (fp, POINTER_TYPE))
return NULL_TREE;
if (!validate_arg (fmt, 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;
if (fcode == BUILT_IN_FPRINTF_UNLOCKED)
{
/* If we're using an unlocked function, assume the other
unlocked functions exist explicitly. */
fn_fputc = builtin_decl_explicit (BUILT_IN_FPUTC_UNLOCKED);
fn_fputs = builtin_decl_explicit (BUILT_IN_FPUTS_UNLOCKED);
}
else
{
fn_fputc = builtin_decl_implicit (BUILT_IN_FPUTC);
fn_fputs = builtin_decl_implicit (BUILT_IN_FPUTS);
}
if (!init_target_chars ())
return NULL_TREE;
/* If the format doesn't contain % args or %%, use strcpy. */
if (strchr (fmt_str, target_percent) == NULL)
{
if (fcode != BUILT_IN_VFPRINTF && fcode != BUILT_IN_VFPRINTF_CHK
&& arg)
return NULL_TREE;
/* If the format specifier was "", fprintf does nothing. */
if (fmt_str[0] == '\0')
{
/* If FP has side-effects, just wait until gimplification is
done. */
if (TREE_SIDE_EFFECTS (fp))
return NULL_TREE;
return build_int_cst (TREE_TYPE (TREE_TYPE (fndecl)), 0);
}
/* When "string" doesn't contain %, replace all cases of
fprintf (fp, string) with fputs (string, fp). The fputs
builtin will take care of special cases like length == 1. */
if (fn_fputs)
call = build_call_expr_loc (loc, fn_fputs, 2, fmt, fp);
}
/* The other optimizations can be done only on the non-va_list variants. */
else if (fcode == BUILT_IN_VFPRINTF || fcode == BUILT_IN_VFPRINTF_CHK)
return NULL_TREE;
/* If the format specifier was "%s", call __builtin_fputs (arg, fp). */
else if (strcmp (fmt_str, target_percent_s) == 0)
{
if (!arg || !validate_arg (arg, POINTER_TYPE))
return NULL_TREE;
if (fn_fputs)
call = build_call_expr_loc (loc, fn_fputs, 2, arg, fp);
}
/* If the format specifier was "%c", call __builtin_fputc (arg, fp). */
else if (strcmp (fmt_str, target_percent_c) == 0)
{
if (!arg || !validate_arg (arg, INTEGER_TYPE))
return NULL_TREE;
if (fn_fputc)
call = build_call_expr_loc (loc, fn_fputc, 2, arg, fp);
}
if (!call)
return NULL_TREE;
return fold_convert_loc (loc, TREE_TYPE (TREE_TYPE (fndecl)), call);
}
/* Initialize format string characters in the target charset. */
bool

View File

@ -91,5 +91,6 @@ extern const char *c_getstr (tree);
extern bool init_target_chars (void);
extern unsigned HOST_WIDE_INT target_percent;
extern char target_percent_s[3];
extern char target_percent_c[3];
#endif

View File

@ -2453,6 +2453,108 @@ gimple_fold_builtin_snprintf (gimple_stmt_iterator *gsi)
return false;
}
/* Fold a call to the {,v}fprintf{,_unlocked} and __{,v}printf_chk builtins.
FP, FMT, and ARG are the arguments to the call. We don't fold calls with
more than 3 arguments, and ARG may be null in the 2-argument case.
Return NULL_TREE if no simplification was possible, otherwise return the
simplified form of the call as a tree. FCODE is the BUILT_IN_*
code of the function to be simplified. */
static bool
gimple_fold_builtin_fprintf (gimple_stmt_iterator *gsi,
tree fp, tree fmt, tree arg,
enum built_in_function fcode)
{
gcall *stmt = as_a <gcall *> (gsi_stmt (*gsi));
tree fn_fputc, fn_fputs;
const char *fmt_str = NULL;
/* If the return value is used, don't do the transformation. */
if (gimple_call_lhs (stmt) != NULL_TREE)
return false;
/* Check whether the format is a literal string constant. */
fmt_str = c_getstr (fmt);
if (fmt_str == NULL)
return false;
if (fcode == BUILT_IN_FPRINTF_UNLOCKED)
{
/* If we're using an unlocked function, assume the other
unlocked functions exist explicitly. */
fn_fputc = builtin_decl_explicit (BUILT_IN_FPUTC_UNLOCKED);
fn_fputs = builtin_decl_explicit (BUILT_IN_FPUTS_UNLOCKED);
}
else
{
fn_fputc = builtin_decl_implicit (BUILT_IN_FPUTC);
fn_fputs = builtin_decl_implicit (BUILT_IN_FPUTS);
}
if (!init_target_chars ())
return false;
/* If the format doesn't contain % args or %%, use strcpy. */
if (strchr (fmt_str, target_percent) == NULL)
{
if (fcode != BUILT_IN_VFPRINTF && fcode != BUILT_IN_VFPRINTF_CHK
&& arg)
return false;
/* If the format specifier was "", fprintf does nothing. */
if (fmt_str[0] == '\0')
{
replace_call_with_value (gsi, NULL_TREE);
return true;
}
/* When "string" doesn't contain %, replace all cases of
fprintf (fp, string) with fputs (string, fp). The fputs
builtin will take care of special cases like length == 1. */
if (fn_fputs)
{
gcall *repl = gimple_build_call (fn_fputs, 2, fmt, fp);
replace_call_with_call_and_fold (gsi, repl);
return true;
}
}
/* The other optimizations can be done only on the non-va_list variants. */
else if (fcode == BUILT_IN_VFPRINTF || fcode == BUILT_IN_VFPRINTF_CHK)
return false;
/* If the format specifier was "%s", call __builtin_fputs (arg, fp). */
else if (strcmp (fmt_str, target_percent_s) == 0)
{
if (!arg || ! POINTER_TYPE_P (TREE_TYPE (arg)))
return false;
if (fn_fputs)
{
gcall *repl = gimple_build_call (fn_fputs, 2, arg, fp);
replace_call_with_call_and_fold (gsi, repl);
return true;
}
}
/* If the format specifier was "%c", call __builtin_fputc (arg, fp). */
else if (strcmp (fmt_str, target_percent_c) == 0)
{
if (!arg
|| ! useless_type_conversion_p (integer_type_node, TREE_TYPE (arg)))
return false;
if (fn_fputc)
{
gcall *repl = gimple_build_call (fn_fputc, 2, arg, fp);
replace_call_with_call_and_fold (gsi, repl);
return true;
}
}
return false;
}
/* Fold a call to __builtin_strlen with known length LEN. */
@ -2483,7 +2585,9 @@ gimple_fold_builtin (gimple_stmt_iterator *gsi)
if (avoid_folding_inline_builtin (callee))
return false;
switch (DECL_FUNCTION_CODE (callee))
unsigned n = gimple_call_num_args (stmt);
enum built_in_function fcode = DECL_FUNCTION_CODE (callee);
switch (fcode)
{
case BUILT_IN_BZERO:
return gimple_fold_builtin_memset (gsi, integer_zero_node,
@ -2506,7 +2610,7 @@ gimple_fold_builtin (gimple_stmt_iterator *gsi)
gimple_call_arg (stmt, 1), 3);
case BUILT_IN_SPRINTF_CHK:
case BUILT_IN_VSPRINTF_CHK:
return gimple_fold_builtin_sprintf_chk (gsi, DECL_FUNCTION_CODE (callee));
return gimple_fold_builtin_sprintf_chk (gsi, fcode);
case BUILT_IN_STRCAT_CHK:
return gimple_fold_builtin_strcat_chk (gsi);
case BUILT_IN_STRNCAT_CHK:
@ -2540,14 +2644,14 @@ gimple_fold_builtin (gimple_stmt_iterator *gsi)
gimple_call_arg (stmt, 1),
gimple_call_arg (stmt, 2),
gimple_call_arg (stmt, 3),
DECL_FUNCTION_CODE (callee));
fcode);
case BUILT_IN_STRCPY_CHK:
case BUILT_IN_STPCPY_CHK:
return gimple_fold_builtin_stxcpy_chk (gsi,
gimple_call_arg (stmt, 0),
gimple_call_arg (stmt, 1),
gimple_call_arg (stmt, 2),
DECL_FUNCTION_CODE (callee));
fcode);
case BUILT_IN_STRNCPY_CHK:
case BUILT_IN_STPNCPY_CHK:
return gimple_fold_builtin_stxncpy_chk (gsi,
@ -2555,15 +2659,37 @@ gimple_fold_builtin (gimple_stmt_iterator *gsi)
gimple_call_arg (stmt, 1),
gimple_call_arg (stmt, 2),
gimple_call_arg (stmt, 3),
DECL_FUNCTION_CODE (callee));
fcode);
case BUILT_IN_SNPRINTF_CHK:
case BUILT_IN_VSNPRINTF_CHK:
return gimple_fold_builtin_snprintf_chk (gsi,
DECL_FUNCTION_CODE (callee));
return gimple_fold_builtin_snprintf_chk (gsi, fcode);
case BUILT_IN_SNPRINTF:
return gimple_fold_builtin_snprintf (gsi);
case BUILT_IN_SPRINTF:
return gimple_fold_builtin_sprintf (gsi);
case BUILT_IN_FPRINTF:
case BUILT_IN_FPRINTF_UNLOCKED:
case BUILT_IN_VFPRINTF:
if (n == 2 || n == 3)
return gimple_fold_builtin_fprintf (gsi,
gimple_call_arg (stmt, 0),
gimple_call_arg (stmt, 1),
n == 3
? gimple_call_arg (stmt, 2)
: NULL_TREE,
fcode);
break;
case BUILT_IN_FPRINTF_CHK:
case BUILT_IN_VFPRINTF_CHK:
if (n == 3 || n == 4)
return gimple_fold_builtin_fprintf (gsi,
gimple_call_arg (stmt, 0),
gimple_call_arg (stmt, 2),
n == 4
? gimple_call_arg (stmt, 3)
: NULL_TREE,
fcode);
break;
default:;
}