aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRoger Sayle <roger@eyesopen.com>2003-07-24 21:04:12 +0000
committerRoger Sayle <sayle@gcc.gnu.org>2003-07-24 21:04:12 +0000
commit868b8cda7b2c89629d7c642db03dae1e913fdd3c (patch)
treeb05c49149bd1ed00301b62af2657b2f3d047bc0d
parent2a868ea448b0730a00817462c13182b1c1d52c22 (diff)
downloadgcc-868b8cda7b2c89629d7c642db03dae1e913fdd3c.zip
gcc-868b8cda7b2c89629d7c642db03dae1e913fdd3c.tar.gz
gcc-868b8cda7b2c89629d7c642db03dae1e913fdd3c.tar.bz2
builtins.def (BUILT_IN_PRINTF, [...]): Changed from front-end builtins to normal builtins, using DEF_LIB_BUILTIN.
* builtins.def (BUILT_IN_PRINTF, BUILT_IN_FPRINTF): Changed from front-end builtins to normal builtins, using DEF_LIB_BUILTIN. (BUILT_IN_PRINTF_UNLOCKED, BUILT_IN_FPRINTF_UNLOCKED): Changed from front-end to normal builtins, using DEF_EXT_LIB_BUILTIN. (DEF_FRONT_END_LIB_BUILTIN): Delete. (DEF_EXT_FRONT_END_LIB_BUILTIN): Delete. (BUILT_IN_FWRITE_UNLOCKED): Wrap long line. * builtins.c (build_string_literal): New function to construct a char* pointer to a string literal. (expand_builtin_fputs): Change 2nd argument from "int ignore" to "rtx target" to be consistent with other expand_builtin_* functions. Change 3rd argument from "int unlocked" to "bool unlocked". (expand_builtin_printf): Rewrite of c_expand_builtin_printf from c-common.c to avoid front-end dependencies. Optimize printf("") as a no-op when the result isn't required. Handle embedded NULs in format string. (expand_builtin_fprintf): A rewrite of c_expand_builtin_fprintf from c-common.c to avoid front-end dependencies. Likewise, optimize fprintf(fp,"") as a no-op when the result isn't required, evaluating fp for side-effects. Handle embedded NULs in format string. (expand_builtin_sprintf): Fix typo. (expand_builtin): Don't expand BUILT_IN_FPRINT{,_UNLOCKED} when not optimizing. Adjust calls of expand_builtin_fputs to match the API change. Expand BUILT_IN_PRINTF and BUILT_IN_PRINTF_UNLOCKED using expand_builtin_printf. Likewise, expand BUILT_IN_FPRINTF_UNLOCKED and BUILT_IN_FPRINTF using expand_builtin_fprintf. * c-common.c (is_valid_printf_arglist): Delete. (c_expand_builtin): Delete. (c_expand_builtin_printf): Moved to builtins.c. Delete. (c_expand_builtin_fprintf): Moved to builtins.c. Delete. (c_expand_expr): No longer treat CALL_EXPRs specially. (CALLED_AS_BUILT_IN): Delete. From-SVN: r69760
-rw-r--r--gcc/ChangeLog37
-rw-r--r--gcc/builtins.c272
-rw-r--r--gcc/builtins.def53
-rw-r--r--gcc/c-common.c296
4 files changed, 317 insertions, 341 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 0a4b1a3..4a68dfb 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,40 @@
+2003-07-24 Roger Sayle <roger@eyesopen.com>
+
+ * builtins.def (BUILT_IN_PRINTF, BUILT_IN_FPRINTF): Changed from
+ front-end builtins to normal builtins, using DEF_LIB_BUILTIN.
+ (BUILT_IN_PRINTF_UNLOCKED, BUILT_IN_FPRINTF_UNLOCKED): Changed
+ from front-end to normal builtins, using DEF_EXT_LIB_BUILTIN.
+ (DEF_FRONT_END_LIB_BUILTIN): Delete.
+ (DEF_EXT_FRONT_END_LIB_BUILTIN): Delete.
+ (BUILT_IN_FWRITE_UNLOCKED): Wrap long line.
+
+ * builtins.c (build_string_literal): New function to construct
+ a char* pointer to a string literal.
+ (expand_builtin_fputs): Change 2nd argument from "int ignore" to
+ "rtx target" to be consistent with other expand_builtin_* functions.
+ Change 3rd argument from "int unlocked" to "bool unlocked".
+ (expand_builtin_printf): Rewrite of c_expand_builtin_printf from
+ c-common.c to avoid front-end dependencies. Optimize printf("")
+ as a no-op when the result isn't required. Handle embedded NULs
+ in format string.
+ (expand_builtin_fprintf): A rewrite of c_expand_builtin_fprintf
+ from c-common.c to avoid front-end dependencies. Likewise, optimize
+ fprintf(fp,"") as a no-op when the result isn't required, evaluating
+ fp for side-effects. Handle embedded NULs in format string.
+ (expand_builtin_sprintf): Fix typo.
+ (expand_builtin): Don't expand BUILT_IN_FPRINT{,_UNLOCKED} when not
+ optimizing. Adjust calls of expand_builtin_fputs to match the API
+ change. Expand BUILT_IN_PRINTF and BUILT_IN_PRINTF_UNLOCKED using
+ expand_builtin_printf. Likewise, expand BUILT_IN_FPRINTF_UNLOCKED
+ and BUILT_IN_FPRINTF using expand_builtin_fprintf.
+
+ * c-common.c (is_valid_printf_arglist): Delete.
+ (c_expand_builtin): Delete.
+ (c_expand_builtin_printf): Moved to builtins.c. Delete.
+ (c_expand_builtin_fprintf): Moved to builtins.c. Delete.
+ (c_expand_expr): No longer treat CALL_EXPRs specially.
+ (CALLED_AS_BUILT_IN): Delete.
+
2003-07-24 Zdenek Dvorak <rakdver@atrey.karlin.mff.cuni.cz>
PR optimization/11631
diff --git a/gcc/builtins.c b/gcc/builtins.c
index 0a44edf..a8c1d47 100644
--- a/gcc/builtins.c
+++ b/gcc/builtins.c
@@ -90,6 +90,7 @@ static const char *c_getstr (tree);
static rtx c_readstr (const char *, enum machine_mode);
static int target_char_cast (tree, char *);
static rtx get_memory_rtx (tree);
+static tree build_string_literal (int, const char *);
static int apply_args_size (void);
static int apply_result_size (void);
#if defined (HAVE_untyped_call) || defined (HAVE_untyped_return)
@@ -140,7 +141,9 @@ static rtx expand_builtin_strrchr (tree, rtx, enum machine_mode);
static rtx expand_builtin_alloca (tree, rtx);
static rtx expand_builtin_unop (enum machine_mode, tree, rtx, rtx, optab);
static rtx expand_builtin_frame_address (tree, tree);
-static rtx expand_builtin_fputs (tree, int, int);
+static rtx expand_builtin_fputs (tree, rtx, bool);
+static rtx expand_builtin_printf (tree, rtx, enum machine_mode, bool);
+static rtx expand_builtin_fprintf (tree, rtx, enum machine_mode, bool);
static rtx expand_builtin_sprintf (tree, rtx, enum machine_mode);
static tree stabilize_va_list (tree, int);
static rtx expand_builtin_expect (tree, rtx);
@@ -820,10 +823,10 @@ expand_builtin_prefetch (tree arglist)
if ((! (*insn_data[(int) CODE_FOR_prefetch].operand[0].predicate)
(op0,
insn_data[(int) CODE_FOR_prefetch].operand[0].mode))
- || (GET_MODE(op0) != Pmode))
+ || (GET_MODE (op0) != Pmode))
{
#ifdef POINTERS_EXTEND_UNSIGNED
- if (GET_MODE(op0) != Pmode)
+ if (GET_MODE (op0) != Pmode)
op0 = convert_memory_address (Pmode, op0);
#endif
op0 = force_reg (Pmode, op0);
@@ -2137,7 +2140,7 @@ expand_powi (rtx x, enum machine_mode mode, HOST_WIDE_INT n)
val = (n < 0) ? -n : n;
- memset (cache, 0, sizeof(cache));
+ memset (cache, 0, sizeof (cache));
cache[1] = x;
result = expand_powi_1 (mode, (n < 0) ? -n : n, cache);
@@ -4258,7 +4261,7 @@ expand_builtin_unop (enum machine_mode target_mode, tree arglist, rtx target,
long, we attempt to transform this call into __builtin_fputc(). */
static rtx
-expand_builtin_fputs (tree arglist, int ignore, int unlocked)
+expand_builtin_fputs (tree arglist, rtx target, bool unlocked)
{
tree len, fn;
tree fn_fputc = unlocked ? implicit_built_in_decls[BUILT_IN_FPUTC_UNLOCKED]
@@ -4268,7 +4271,7 @@ expand_builtin_fputs (tree arglist, int ignore, int unlocked)
/* If the return value is used, or the replacement _DECL isn't
initialized, don't do the transformation. */
- if (!ignore || !fn_fputc || !fn_fwrite)
+ if (target != const0_rtx || !fn_fputc || !fn_fwrite)
return 0;
/* Verify the arguments in the original call. */
@@ -4330,8 +4333,7 @@ expand_builtin_fputs (tree arglist, int ignore, int unlocked)
}
return expand_expr (build_function_call_expr (fn, arglist),
- (ignore ? const0_rtx : NULL_RTX),
- VOIDmode, EXPAND_NORMAL);
+ const0_rtx, VOIDmode, EXPAND_NORMAL);
}
/* Expand a call to __builtin_expect. We return our argument and emit a
@@ -4551,6 +4553,227 @@ expand_builtin_cabs (tree arglist, rtx target)
return expand_complex_abs (mode, op0, target, 0);
}
+/* Create a new constant string literal and return a char* pointer to it.
+ The STRING_CST value is the LEN characters at STR. */
+static tree
+build_string_literal (int len, const char *str)
+{
+ tree t, elem, index, type;
+
+ t = build_string (len, str);
+ elem = build_type_variant (char_type_node, 1, 0);
+ index = build_index_type (build_int_2 (len - 1, 0));
+ type = build_array_type (elem, index);
+ TREE_TYPE (t) = type;
+ TREE_CONSTANT (t) = 1;
+ TREE_READONLY (t) = 1;
+ TREE_STATIC (t) = 1;
+
+ type = build_pointer_type (type);
+ t = build1 (ADDR_EXPR, type, t);
+
+ type = build_pointer_type (elem);
+ t = build1 (NOP_EXPR, type, t);
+ return t;
+}
+
+/* Expand a call to printf or printf_unlocked with argument list ARGLIST.
+ Return 0 if a normal call should be emitted rather than transforming
+ the function inline. If convenient, the result should be placed in
+ TARGET with mode MODE. UNLOCKED indicates this is a printf_unlocked
+ call. */
+static rtx
+expand_builtin_printf (tree arglist, rtx target, enum machine_mode mode,
+ bool unlocked)
+{
+ tree fn_putchar = unlocked
+ ? implicit_built_in_decls[BUILT_IN_PUTCHAR_UNLOCKED]
+ : implicit_built_in_decls[BUILT_IN_PUTCHAR];
+ tree fn_puts = unlocked ? implicit_built_in_decls[BUILT_IN_PUTS_UNLOCKED]
+ : implicit_built_in_decls[BUILT_IN_PUTS];
+ const char *fmt_str;
+ tree fn, fmt, arg;
+
+ /* If the return value is used, don't do the transformation. */
+ if (target != const0_rtx)
+ return 0;
+
+ /* Verify the required arguments in the original call. */
+ if (! arglist)
+ return 0;
+ fmt = TREE_VALUE (arglist);
+ if (TREE_CODE (TREE_TYPE (fmt)) != POINTER_TYPE)
+ return 0;
+ arglist = TREE_CHAIN (arglist);
+
+ /* Check whether the format is a literal string constant. */
+ fmt_str = c_getstr (fmt);
+ if (fmt_str == NULL)
+ return 0;
+
+ /* If the format specifier was "%s\n", call __builtin_puts(arg). */
+ if (strcmp (fmt_str, "%s\n") == 0)
+ {
+ if (! arglist
+ || TREE_CODE (TREE_TYPE (TREE_VALUE (arglist))) != POINTER_TYPE
+ || TREE_CHAIN (arglist))
+ return 0;
+ fn = fn_puts;
+ }
+ /* If the format specifier was "%c", call __builtin_putchar(arg). */
+ else if (strcmp (fmt_str, "%c") == 0)
+ {
+ if (! arglist
+ || TREE_CODE (TREE_TYPE (TREE_VALUE (arglist))) != INTEGER_TYPE
+ || TREE_CHAIN (arglist))
+ return 0;
+ fn = fn_putchar;
+ }
+ else
+ {
+ /* We can't handle anything else with % args or %% ... yet. */
+ if (strchr (fmt_str, '%'))
+ return 0;
+
+ if (arglist)
+ return 0;
+
+ /* If the format specifier was "", printf does nothing. */
+ if (fmt_str[0] == '\0')
+ return const0_rtx;
+ /* If the format specifier has length of 1, call putchar. */
+ if (fmt_str[1] == '\0')
+ {
+ /* Given printf("c"), (where c is any one character,)
+ convert "c"[0] to an int and pass that to the replacement
+ function. */
+ arg = build_int_2 (fmt_str[0], 0);
+ arglist = build_tree_list (NULL_TREE, arg);
+ fn = fn_putchar;
+ }
+ else
+ {
+ /* If the format specifier was "string\n", call puts("string"). */
+ size_t len = strlen (fmt_str);
+ if (fmt_str[len - 1] == '\n')
+ {
+ /* Create a NUL-terminalted string that's one char shorter
+ than the original, stripping off the trailing '\n'. */
+ char *newstr = (char *) alloca (len);
+ memcpy (newstr, fmt_str, len - 1);
+ newstr[len - 1] = 0;
+
+ arg = build_string_literal (len, newstr);
+ arglist = build_tree_list (NULL_TREE, arg);
+ fn = fn_puts;
+ }
+ else
+ /* We'd like to arrange to call fputs(string,stdout) here,
+ but we need stdout and don't have a way to get it yet. */
+ return 0;
+ }
+ }
+
+ if (!fn)
+ return 0;
+ return expand_expr (build_function_call_expr (fn, arglist),
+ target, mode, EXPAND_NORMAL);
+}
+
+/* Expand a call to fprintf or fprintf_unlocked with argument list ARGLIST.
+ Return 0 if a normal call should be emitted rather than transforming
+ the function inline. If convenient, the result should be placed in
+ TARGET with mode MODE. UNLOCKED indicates this is a fprintf_unlocked
+ call. */
+static rtx
+expand_builtin_fprintf (tree arglist, rtx target, enum machine_mode mode,
+ bool unlocked)
+{
+ tree fn_fputc = unlocked ? implicit_built_in_decls[BUILT_IN_FPUTC_UNLOCKED]
+ : implicit_built_in_decls[BUILT_IN_FPUTC];
+ tree fn_fputs = unlocked ? implicit_built_in_decls[BUILT_IN_FPUTS_UNLOCKED]
+ : implicit_built_in_decls[BUILT_IN_FPUTS];
+ const char *fmt_str;
+ tree fn, fmt, fp, arg;
+
+ /* If the return value is used, don't do the transformation. */
+ if (target != const0_rtx)
+ return 0;
+
+ /* Verify the required arguments in the original call. */
+ if (! arglist)
+ return 0;
+ fp = TREE_VALUE (arglist);
+ if (TREE_CODE (TREE_TYPE (fp)) != POINTER_TYPE)
+ return 0;
+ arglist = TREE_CHAIN (arglist);
+ if (! arglist)
+ return 0;
+ fmt = TREE_VALUE (arglist);
+ if (TREE_CODE (TREE_TYPE (fmt)) != POINTER_TYPE)
+ return 0;
+ arglist = TREE_CHAIN (arglist);
+
+ /* Check whether the format is a literal string constant. */
+ fmt_str = c_getstr (fmt);
+ if (fmt_str == NULL)
+ return 0;
+
+ /* If the format specifier was "%s", call __builtin_fputs(arg,fp). */
+ if (strcmp (fmt_str, "%s") == 0)
+ {
+ if (! arglist
+ || TREE_CODE (TREE_TYPE (TREE_VALUE (arglist))) != POINTER_TYPE
+ || TREE_CHAIN (arglist))
+ return 0;
+ arg = TREE_VALUE (arglist);
+ arglist = build_tree_list (NULL_TREE, fp);
+ arglist = tree_cons (NULL_TREE, arg, arglist);
+ fn = fn_fputs;
+ }
+ /* If the format specifier was "%c", call __builtin_fputc(arg,fp). */
+ else if (strcmp (fmt_str, "%c") == 0)
+ {
+ if (! arglist
+ || TREE_CODE (TREE_TYPE (TREE_VALUE (arglist))) != INTEGER_TYPE
+ || TREE_CHAIN (arglist))
+ return 0;
+ arg = TREE_VALUE (arglist);
+ arglist = build_tree_list (NULL_TREE, fp);
+ arglist = tree_cons (NULL_TREE, arg, arglist);
+ fn = fn_fputc;
+ }
+ else
+ {
+ /* We can't handle anything else with % args or %% ... yet. */
+ if (strchr (fmt_str, '%'))
+ return 0;
+
+ if (arglist)
+ return 0;
+
+ /* If the format specifier was "", fprintf does nothing. */
+ if (fmt_str[0] == '\0')
+ {
+ /* Evaluate and ignore FILE* argument for side-effects. */
+ expand_expr (fp, const0_rtx, VOIDmode, EXPAND_NORMAL);
+ return const0_rtx;
+ }
+
+ /* When "string" doesn't contain %, replace all cases of
+ fprintf(stream,string) with fputs(string,stream). The fputs
+ builtin will take care of special cases like length == 1. */
+ arglist = build_tree_list (NULL_TREE, fp);
+ arglist = tree_cons (NULL_TREE, fmt, arglist);
+ fn = fn_fputs;
+ }
+
+ if (!fn)
+ return 0;
+ return expand_expr (build_function_call_expr (fn, arglist),
+ target, mode, EXPAND_NORMAL);
+}
+
/* Expand a call to sprintf with argument list ARGLIST. Return 0 if
a normal call should be emitted rather than expanding the function
inline. If convenient, the result should be placed in TARGET with
@@ -4574,7 +4797,7 @@ expand_builtin_sprintf (tree arglist, rtx target, enum machine_mode mode)
if (! arglist)
return 0;
fmt = TREE_VALUE (arglist);
- if (TREE_CODE (TREE_TYPE (dest)) != POINTER_TYPE)
+ if (TREE_CODE (TREE_TYPE (fmt)) != POINTER_TYPE)
return 0;
arglist = TREE_CHAIN (arglist);
@@ -4721,12 +4944,14 @@ expand_builtin (tree exp, rtx target, rtx subtarget, enum machine_mode mode,
case BUILT_IN_FPUTC:
case BUILT_IN_FPUTS:
case BUILT_IN_FWRITE:
+ case BUILT_IN_FPRINTF:
case BUILT_IN_PUTCHAR_UNLOCKED:
case BUILT_IN_PUTS_UNLOCKED:
case BUILT_IN_PRINTF_UNLOCKED:
case BUILT_IN_FPUTC_UNLOCKED:
case BUILT_IN_FPUTS_UNLOCKED:
case BUILT_IN_FWRITE_UNLOCKED:
+ case BUILT_IN_FPRINTF_UNLOCKED:
case BUILT_IN_FLOOR:
case BUILT_IN_FLOORF:
case BUILT_IN_FLOORL:
@@ -5167,13 +5392,38 @@ expand_builtin (tree exp, rtx target, rtx subtarget, enum machine_mode mode,
expand_builtin_trap ();
return const0_rtx;
+ case BUILT_IN_PRINTF:
+ target = expand_builtin_printf (arglist, target, mode, false);
+ if (target)
+ return target;
+ break;
+
+ case BUILT_IN_PRINTF_UNLOCKED:
+ target = expand_builtin_printf (arglist, target, mode, true);
+ if (target)
+ return target;
+ break;
+
case BUILT_IN_FPUTS:
- target = expand_builtin_fputs (arglist, ignore,/*unlocked=*/ 0);
+ target = expand_builtin_fputs (arglist, target, false);
if (target)
return target;
break;
+
case BUILT_IN_FPUTS_UNLOCKED:
- target = expand_builtin_fputs (arglist, ignore,/*unlocked=*/ 1);
+ target = expand_builtin_fputs (arglist, target, true);
+ if (target)
+ return target;
+ break;
+
+ case BUILT_IN_FPRINTF:
+ target = expand_builtin_fprintf (arglist, target, mode, false);
+ if (target)
+ return target;
+ break;
+
+ case BUILT_IN_FPRINTF_UNLOCKED:
+ target = expand_builtin_fprintf (arglist, target, mode, true);
if (target)
return target;
break;
diff --git a/gcc/builtins.def b/gcc/builtins.def
index 0eaba88..e05795d 100644
--- a/gcc/builtins.def
+++ b/gcc/builtins.def
@@ -70,9 +70,8 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
DEF_BUILTIN (ENUM, NAME, BUILT_IN_NORMAL, TYPE, BT_LAST, \
false, false, false, ATTRS, true)
-
/* A fallback builtin is a builtin (like __builtin_puts) that falls
- back to the corresopnding library function if necessary -- but
+ back to the corresponding library function if necessary -- but
for which we should not introduce the non-`__builtin' variant of
the name. */
#undef DEF_FALLBACK_BUILTIN
@@ -124,21 +123,6 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
DEF_BUILTIN (ENUM, NAME, BUILT_IN_NORMAL, TYPE, TYPE, \
true, true, !flag_isoc99, ATTRS, TARGET_C99_FUNCTIONS)
-/* Like DEF_LIB_BUILTIN, except that the function is expanded in the
- front-end. */
-#undef DEF_FRONT_END_LIB_BUILTIN
-#define DEF_FRONT_END_LIB_BUILTIN(ENUM, NAME, TYPE, ATTRS) \
- DEF_BUILTIN (ENUM, NAME, BUILT_IN_FRONTEND, TYPE, TYPE, \
- true, true, false, ATTRS, true)
-
-/* Like DEF_FRONT_END_LIB_BUILTIN, except that the function is not one
- that is specified by ANSI/ISO C. So, when we're being fully
- conformant we ignore the version of these builtins that does not
- begin with __builtin. */
-#undef DEF_EXT_FRONT_END_LIB_BUILTIN
-#define DEF_EXT_FRONT_END_LIB_BUILTIN(ENUM, NAME, TYPE, ATTRS) \
- DEF_BUILTIN (ENUM, NAME, BUILT_IN_FRONTEND, TYPE, TYPE, \
- true, true, true, ATTRS, true)
DEF_EXT_LIB_BUILTIN(BUILT_IN_ALLOCA,
"__builtin_alloca",
@@ -769,10 +753,10 @@ DEF_GCC_BUILTIN(BUILT_IN_PREFETCH,
/* stdio.h builtins (without FILE *). */
-DEF_FRONT_END_LIB_BUILTIN(BUILT_IN_PRINTF,
- "__builtin_printf",
- BT_FN_INT_CONST_STRING_VAR,
- ATTR_FORMAT_PRINTF_1_2)
+DEF_LIB_BUILTIN(BUILT_IN_PRINTF,
+ "__builtin_printf",
+ BT_FN_INT_CONST_STRING_VAR,
+ ATTR_FORMAT_PRINTF_1_2)
DEF_LIB_BUILTIN(BUILT_IN_PUTCHAR,
"__builtin_putchar",
BT_FN_INT_INT,
@@ -840,10 +824,10 @@ DEF_FALLBACK_BUILTIN(BUILT_IN_FWRITE,
"__builtin_fwrite",
BT_FN_SIZE_CONST_PTR_SIZE_SIZE_PTR,
ATTR_NOTHROW_NONNULL_1_4)
-DEF_FRONT_END_LIB_BUILTIN(BUILT_IN_FPRINTF,
- "__builtin_fprintf",
- BT_FN_INT_PTR_CONST_STRING_VAR,
- ATTR_FORMAT_PRINTF_2_3)
+DEF_LIB_BUILTIN(BUILT_IN_FPRINTF,
+ "__builtin_fprintf",
+ BT_FN_INT_PTR_CONST_STRING_VAR,
+ ATTR_FORMAT_PRINTF_2_3)
/* stdio unlocked builtins (without FILE *). */
@@ -853,10 +837,10 @@ DEF_EXT_FALLBACK_BUILTIN(BUILT_IN_PUTCHAR_UNLOCKED,
DEF_EXT_FALLBACK_BUILTIN(BUILT_IN_PUTS_UNLOCKED,
"__builtin_puts_unlocked",
BT_FN_INT_CONST_STRING, ATTR_NOTHROW_NONNULL_1)
-DEF_EXT_FRONT_END_LIB_BUILTIN(BUILT_IN_PRINTF_UNLOCKED,
- "__builtin_printf_unlocked",
- BT_FN_INT_CONST_STRING_VAR,
- ATTR_FORMAT_PRINTF_1_2)
+DEF_EXT_LIB_BUILTIN(BUILT_IN_PRINTF_UNLOCKED,
+ "__builtin_printf_unlocked",
+ BT_FN_INT_CONST_STRING_VAR,
+ ATTR_FORMAT_PRINTF_1_2)
/* stdio unlocked builtins (with FILE *). */
@@ -876,11 +860,12 @@ DEF_BUILTIN (BUILT_IN_FPUTS_UNLOCKED,
true, true, true, ATTR_NOTHROW_NONNULL_1_2, true)
DEF_EXT_FALLBACK_BUILTIN(BUILT_IN_FWRITE_UNLOCKED,
"__builtin_fwrite_unlocked",
- BT_FN_SIZE_CONST_PTR_SIZE_SIZE_PTR, ATTR_NOTHROW_NONNULL_1_4)
-DEF_EXT_FRONT_END_LIB_BUILTIN(BUILT_IN_FPRINTF_UNLOCKED,
- "__builtin_fprintf_unlocked",
- BT_FN_INT_PTR_CONST_STRING_VAR,
- ATTR_FORMAT_PRINTF_2_3)
+ BT_FN_SIZE_CONST_PTR_SIZE_SIZE_PTR,
+ ATTR_NOTHROW_NONNULL_1_4)
+DEF_EXT_LIB_BUILTIN(BUILT_IN_FPRINTF_UNLOCKED,
+ "__builtin_fprintf_unlocked",
+ BT_FN_INT_PTR_CONST_STRING_VAR,
+ ATTR_FORMAT_PRINTF_2_3)
/* ISO C99 floating point unordered comparisons. */
DEF_GCC_BUILTIN(BUILT_IN_ISGREATER,
diff --git a/gcc/c-common.c b/gcc/c-common.c
index 685ec2c..2e985c2 100644
--- a/gcc/c-common.c
+++ b/gcc/c-common.c
@@ -1175,14 +1175,6 @@ fix_string_type (tree value)
return value;
}
-static int is_valid_printf_arglist (tree);
-static rtx c_expand_builtin (tree, rtx, enum machine_mode,
- enum expand_modifier);
-static rtx c_expand_builtin_printf (tree, rtx, enum machine_mode,
- enum expand_modifier, int, int);
-static rtx c_expand_builtin_fprintf (tree, rtx, enum machine_mode,
- enum expand_modifier, int, int);
-
/* Print a warning if a constant expression had overflow in folding.
Invoke this function on every expression that the language
requires to be a constant expression.
@@ -4053,20 +4045,6 @@ c_expand_expr (tree exp, rtx target, enum machine_mode tmode, int modifier)
}
break;
- case CALL_EXPR:
- {
- if (TREE_CODE (TREE_OPERAND (exp, 0)) == ADDR_EXPR
- && (TREE_CODE (TREE_OPERAND (TREE_OPERAND (exp, 0), 0))
- == FUNCTION_DECL)
- && DECL_BUILT_IN (TREE_OPERAND (TREE_OPERAND (exp, 0), 0))
- && (DECL_BUILT_IN_CLASS (TREE_OPERAND (TREE_OPERAND (exp, 0), 0))
- == BUILT_IN_FRONTEND))
- return c_expand_builtin (exp, target, tmode, modifier);
- else
- abort ();
- }
- break;
-
case COMPOUND_LITERAL_EXPR:
{
/* Initialize the anonymous variable declared in the compound
@@ -4135,280 +4113,6 @@ c_staticp (tree exp)
return 1;
return 0;
}
-
-#define CALLED_AS_BUILT_IN(NODE) \
- (!strncmp (IDENTIFIER_POINTER (DECL_NAME (NODE)), "__builtin_", 10))
-
-static rtx
-c_expand_builtin (tree exp, rtx target, enum machine_mode tmode,
- enum expand_modifier modifier)
-{
- tree type = TREE_TYPE (exp);
- tree fndecl = TREE_OPERAND (TREE_OPERAND (exp, 0), 0);
- tree arglist = TREE_OPERAND (exp, 1);
- enum built_in_function fcode = DECL_FUNCTION_CODE (fndecl);
- enum tree_code code = TREE_CODE (exp);
- const int ignore = (target == const0_rtx
- || ((code == NON_LVALUE_EXPR || code == NOP_EXPR
- || code == CONVERT_EXPR || code == REFERENCE_EXPR
- || code == COND_EXPR)
- && TREE_CODE (type) == VOID_TYPE));
-
- if (! optimize && ! CALLED_AS_BUILT_IN (fndecl))
- return expand_call (exp, target, ignore);
-
- switch (fcode)
- {
- case BUILT_IN_PRINTF:
- target = c_expand_builtin_printf (arglist, target, tmode,
- modifier, ignore, /*unlocked=*/ 0);
- if (target)
- return target;
- break;
-
- case BUILT_IN_PRINTF_UNLOCKED:
- target = c_expand_builtin_printf (arglist, target, tmode,
- modifier, ignore, /*unlocked=*/ 1);
- if (target)
- return target;
- break;
-
- case BUILT_IN_FPRINTF:
- target = c_expand_builtin_fprintf (arglist, target, tmode,
- modifier, ignore, /*unlocked=*/ 0);
- if (target)
- return target;
- break;
-
- case BUILT_IN_FPRINTF_UNLOCKED:
- target = c_expand_builtin_fprintf (arglist, target, tmode,
- modifier, ignore, /*unlocked=*/ 1);
- if (target)
- return target;
- break;
-
- default: /* just do library call, if unknown builtin */
- error ("built-in function `%s' not currently supported",
- IDENTIFIER_POINTER (DECL_NAME (fndecl)));
- }
-
- /* The switch statement above can drop through to cause the function
- to be called normally. */
- return expand_call (exp, target, ignore);
-}
-
-/* Check an arglist to *printf for problems. The arglist should start
- at the format specifier, with the remaining arguments immediately
- following it. */
-static int
-is_valid_printf_arglist (tree arglist)
-{
- /* Save this value so we can restore it later. */
- const int SAVE_pedantic = pedantic;
- int diagnostic_occurred = 0;
- tree attrs;
-
- /* Set this to a known value so the user setting won't affect code
- generation. */
- pedantic = 1;
- /* Check to make sure there are no format specifier errors. */
- attrs = tree_cons (get_identifier ("format"),
- tree_cons (NULL_TREE,
- get_identifier ("printf"),
- tree_cons (NULL_TREE,
- integer_one_node,
- tree_cons (NULL_TREE,
- build_int_2 (2, 0),
- NULL_TREE))),
- NULL_TREE);
- check_function_format (&diagnostic_occurred, attrs, arglist);
-
- /* Restore the value of `pedantic'. */
- pedantic = SAVE_pedantic;
-
- /* If calling `check_function_format_ptr' produces a warning, we
- return false, otherwise we return true. */
- return ! diagnostic_occurred;
-}
-
-/* If the arguments passed to printf are suitable for optimizations,
- we attempt to transform the call. */
-static rtx
-c_expand_builtin_printf (tree arglist, rtx target, enum machine_mode tmode,
- enum expand_modifier modifier, int ignore,
- int unlocked)
-{
- tree fn_putchar = unlocked ?
- implicit_built_in_decls[BUILT_IN_PUTCHAR_UNLOCKED] : implicit_built_in_decls[BUILT_IN_PUTCHAR];
- tree fn_puts = unlocked ?
- implicit_built_in_decls[BUILT_IN_PUTS_UNLOCKED] : implicit_built_in_decls[BUILT_IN_PUTS];
- tree fn, format_arg, stripped_string;
-
- /* If the return value is used, or the replacement _DECL isn't
- initialized, don't do the transformation. */
- if (!ignore || !fn_putchar || !fn_puts)
- return 0;
-
- /* Verify the required arguments in the original call. */
- if (arglist == 0
- || (TREE_CODE (TREE_TYPE (TREE_VALUE (arglist))) != POINTER_TYPE))
- return 0;
-
- /* Check the specifier vs. the parameters. */
- if (!is_valid_printf_arglist (arglist))
- return 0;
-
- format_arg = TREE_VALUE (arglist);
- stripped_string = format_arg;
- STRIP_NOPS (stripped_string);
- if (stripped_string && TREE_CODE (stripped_string) == ADDR_EXPR)
- stripped_string = TREE_OPERAND (stripped_string, 0);
-
- /* If the format specifier isn't a STRING_CST, punt. */
- if (TREE_CODE (stripped_string) != STRING_CST)
- return 0;
-
- /* OK! We can attempt optimization. */
-
- /* If the format specifier was "%s\n", call __builtin_puts(arg2). */
- if (strcmp (TREE_STRING_POINTER (stripped_string), "%s\n") == 0)
- {
- arglist = TREE_CHAIN (arglist);
- fn = fn_puts;
- }
- /* If the format specifier was "%c", call __builtin_putchar (arg2). */
- else if (strcmp (TREE_STRING_POINTER (stripped_string), "%c") == 0)
- {
- arglist = TREE_CHAIN (arglist);
- fn = fn_putchar;
- }
- else
- {
- /* We can't handle anything else with % args or %% ... yet. */
- if (strchr (TREE_STRING_POINTER (stripped_string), '%'))
- return 0;
-
- /* If the resulting constant string has a length of 1, call
- putchar. Note, TREE_STRING_LENGTH includes the terminating
- NULL in its count. */
- if (TREE_STRING_LENGTH (stripped_string) == 2)
- {
- /* Given printf("c"), (where c is any one character,)
- convert "c"[0] to an int and pass that to the replacement
- function. */
- arglist = build_int_2 (TREE_STRING_POINTER (stripped_string)[0], 0);
- arglist = build_tree_list (NULL_TREE, arglist);
-
- fn = fn_putchar;
- }
- /* If the resulting constant was "string\n", call
- __builtin_puts("string"). Ensure "string" has at least one
- character besides the trailing \n. Note, TREE_STRING_LENGTH
- includes the terminating NULL in its count. */
- else if (TREE_STRING_LENGTH (stripped_string) > 2
- && TREE_STRING_POINTER (stripped_string)
- [TREE_STRING_LENGTH (stripped_string) - 2] == '\n')
- {
- /* Create a NULL-terminated string that's one char shorter
- than the original, stripping off the trailing '\n'. */
- const int newlen = TREE_STRING_LENGTH (stripped_string) - 1;
- char *newstr = alloca (newlen);
- memcpy (newstr, TREE_STRING_POINTER (stripped_string), newlen - 1);
- newstr[newlen - 1] = 0;
-
- arglist = fix_string_type (build_string (newlen, newstr));
- arglist = build_tree_list (NULL_TREE, arglist);
- fn = fn_puts;
- }
- else
- /* We'd like to arrange to call fputs(string) here, but we
- need stdout and don't have a way to get it ... yet. */
- return 0;
- }
-
- return expand_expr (build_function_call (fn, arglist),
- (ignore ? const0_rtx : target),
- tmode, modifier);
-}
-
-/* If the arguments passed to fprintf are suitable for optimizations,
- we attempt to transform the call. */
-static rtx
-c_expand_builtin_fprintf (tree arglist, rtx target, enum machine_mode tmode,
- enum expand_modifier modifier, int ignore,
- int unlocked)
-{
- tree fn_fputc = unlocked ?
- implicit_built_in_decls[BUILT_IN_FPUTC_UNLOCKED] : implicit_built_in_decls[BUILT_IN_FPUTC];
- tree fn_fputs = unlocked ?
- implicit_built_in_decls[BUILT_IN_FPUTS_UNLOCKED] : implicit_built_in_decls[BUILT_IN_FPUTS];
- tree fn, format_arg, stripped_string;
-
- /* If the return value is used, or the replacement _DECL isn't
- initialized, don't do the transformation. */
- if (!ignore || !fn_fputc || !fn_fputs)
- return 0;
-
- /* Verify the required arguments in the original call. */
- if (arglist == 0
- || (TREE_CODE (TREE_TYPE (TREE_VALUE (arglist))) != POINTER_TYPE)
- || (TREE_CHAIN (arglist) == 0)
- || (TREE_CODE (TREE_TYPE (TREE_VALUE (TREE_CHAIN (arglist)))) !=
- POINTER_TYPE))
- return 0;
-
- /* Check the specifier vs. the parameters. */
- if (!is_valid_printf_arglist (TREE_CHAIN (arglist)))
- return 0;
-
- format_arg = TREE_VALUE (TREE_CHAIN (arglist));
- stripped_string = format_arg;
- STRIP_NOPS (stripped_string);
- if (stripped_string && TREE_CODE (stripped_string) == ADDR_EXPR)
- stripped_string = TREE_OPERAND (stripped_string, 0);
-
- /* If the format specifier isn't a STRING_CST, punt. */
- if (TREE_CODE (stripped_string) != STRING_CST)
- return 0;
-
- /* OK! We can attempt optimization. */
-
- /* If the format specifier was "%s", call __builtin_fputs(arg3, arg1). */
- if (strcmp (TREE_STRING_POINTER (stripped_string), "%s") == 0)
- {
- tree newarglist = build_tree_list (NULL_TREE, TREE_VALUE (arglist));
- arglist = tree_cons (NULL_TREE,
- TREE_VALUE (TREE_CHAIN (TREE_CHAIN (arglist))),
- newarglist);
- fn = fn_fputs;
- }
- /* If the format specifier was "%c", call __builtin_fputc (arg3, arg1). */
- else if (strcmp (TREE_STRING_POINTER (stripped_string), "%c") == 0)
- {
- tree newarglist = build_tree_list (NULL_TREE, TREE_VALUE (arglist));
- arglist = tree_cons (NULL_TREE,
- TREE_VALUE (TREE_CHAIN (TREE_CHAIN (arglist))),
- newarglist);
- fn = fn_fputc;
- }
- else
- {
- /* We can't handle anything else with % args or %% ... yet. */
- if (strchr (TREE_STRING_POINTER (stripped_string), '%'))
- return 0;
-
- /* When "string" doesn't contain %, replace all cases of
- fprintf(stream,string) with fputs(string,stream). The fputs
- builtin will take take of special cases like length==1. */
- arglist = tree_cons (NULL_TREE, TREE_VALUE (TREE_CHAIN (arglist)),
- build_tree_list (NULL_TREE, TREE_VALUE (arglist)));
- fn = fn_fputs;
- }
-
- return expand_expr (build_function_call (fn, arglist),
- (ignore ? const0_rtx : target),
- tmode, modifier);
-}
/* Given a boolean expression ARG, return a tree representing an increment