summaryrefslogtreecommitdiff
path: root/gcc/gimple-fold.c
diff options
context:
space:
mode:
authorrguenth <rguenth@138bc75d-0d04-0410-961f-82ee72b054a4>2014-12-03 14:08:07 +0000
committerrguenth <rguenth@138bc75d-0d04-0410-961f-82ee72b054a4>2014-12-03 14:08:07 +0000
commitaea88c7796f79fce4dfc9bfa9cc904ee35ca9fe2 (patch)
treec7f622237ef97db023009d3796ab4d7043f038cf /gcc/gimple-fold.c
parent0b6455f7241b8935aecc4b89fff31db08faab0d8 (diff)
downloadgcc-aea88c7796f79fce4dfc9bfa9cc904ee35ca9fe2.tar.gz
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. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@218317 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'gcc/gimple-fold.c')
-rw-r--r--gcc/gimple-fold.c140
1 files changed, 133 insertions, 7 deletions
diff --git a/gcc/gimple-fold.c b/gcc/gimple-fold.c
index bdc6088ec0e..3f1a11f6d4b 100644
--- a/gcc/gimple-fold.c
+++ b/gcc/gimple-fold.c
@@ -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:;
}