Commit 868b8cda by Roger Sayle Committed by Roger Sayle

builtins.def (BUILT_IN_PRINTF, [...]): Changed from front-end builtins to normal…

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
parent 2a868ea4
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> 2003-07-24 Zdenek Dvorak <rakdver@atrey.karlin.mff.cuni.cz>
PR optimization/11631 PR optimization/11631
......
...@@ -90,6 +90,7 @@ static const char *c_getstr (tree); ...@@ -90,6 +90,7 @@ static const char *c_getstr (tree);
static rtx c_readstr (const char *, enum machine_mode); static rtx c_readstr (const char *, enum machine_mode);
static int target_char_cast (tree, char *); static int target_char_cast (tree, char *);
static rtx get_memory_rtx (tree); static rtx get_memory_rtx (tree);
static tree build_string_literal (int, const char *);
static int apply_args_size (void); static int apply_args_size (void);
static int apply_result_size (void); static int apply_result_size (void);
#if defined (HAVE_untyped_call) || defined (HAVE_untyped_return) #if defined (HAVE_untyped_call) || defined (HAVE_untyped_return)
...@@ -140,7 +141,9 @@ static rtx expand_builtin_strrchr (tree, rtx, enum machine_mode); ...@@ -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_alloca (tree, rtx);
static rtx expand_builtin_unop (enum machine_mode, tree, rtx, rtx, optab); static rtx expand_builtin_unop (enum machine_mode, tree, rtx, rtx, optab);
static rtx expand_builtin_frame_address (tree, tree); 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 rtx expand_builtin_sprintf (tree, rtx, enum machine_mode);
static tree stabilize_va_list (tree, int); static tree stabilize_va_list (tree, int);
static rtx expand_builtin_expect (tree, rtx); static rtx expand_builtin_expect (tree, rtx);
...@@ -820,10 +823,10 @@ expand_builtin_prefetch (tree arglist) ...@@ -820,10 +823,10 @@ expand_builtin_prefetch (tree arglist)
if ((! (*insn_data[(int) CODE_FOR_prefetch].operand[0].predicate) if ((! (*insn_data[(int) CODE_FOR_prefetch].operand[0].predicate)
(op0, (op0,
insn_data[(int) CODE_FOR_prefetch].operand[0].mode)) insn_data[(int) CODE_FOR_prefetch].operand[0].mode))
|| (GET_MODE(op0) != Pmode)) || (GET_MODE (op0) != Pmode))
{ {
#ifdef POINTERS_EXTEND_UNSIGNED #ifdef POINTERS_EXTEND_UNSIGNED
if (GET_MODE(op0) != Pmode) if (GET_MODE (op0) != Pmode)
op0 = convert_memory_address (Pmode, op0); op0 = convert_memory_address (Pmode, op0);
#endif #endif
op0 = force_reg (Pmode, op0); op0 = force_reg (Pmode, op0);
...@@ -2137,7 +2140,7 @@ expand_powi (rtx x, enum machine_mode mode, HOST_WIDE_INT n) ...@@ -2137,7 +2140,7 @@ expand_powi (rtx x, enum machine_mode mode, HOST_WIDE_INT n)
val = (n < 0) ? -n : n; val = (n < 0) ? -n : n;
memset (cache, 0, sizeof(cache)); memset (cache, 0, sizeof (cache));
cache[1] = x; cache[1] = x;
result = expand_powi_1 (mode, (n < 0) ? -n : n, cache); 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, ...@@ -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(). */ long, we attempt to transform this call into __builtin_fputc(). */
static rtx static rtx
expand_builtin_fputs (tree arglist, int ignore, int unlocked) expand_builtin_fputs (tree arglist, rtx target, bool unlocked)
{ {
tree len, fn; tree len, fn;
tree fn_fputc = unlocked ? implicit_built_in_decls[BUILT_IN_FPUTC_UNLOCKED] 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) ...@@ -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 /* If the return value is used, or the replacement _DECL isn't
initialized, don't do the transformation. */ initialized, don't do the transformation. */
if (!ignore || !fn_fputc || !fn_fwrite) if (target != const0_rtx || !fn_fputc || !fn_fwrite)
return 0; return 0;
/* Verify the arguments in the original call. */ /* Verify the arguments in the original call. */
...@@ -4330,8 +4333,7 @@ expand_builtin_fputs (tree arglist, int ignore, int unlocked) ...@@ -4330,8 +4333,7 @@ expand_builtin_fputs (tree arglist, int ignore, int unlocked)
} }
return expand_expr (build_function_call_expr (fn, arglist), return expand_expr (build_function_call_expr (fn, arglist),
(ignore ? const0_rtx : NULL_RTX), const0_rtx, VOIDmode, EXPAND_NORMAL);
VOIDmode, EXPAND_NORMAL);
} }
/* Expand a call to __builtin_expect. We return our argument and emit a /* Expand a call to __builtin_expect. We return our argument and emit a
...@@ -4551,6 +4553,227 @@ expand_builtin_cabs (tree arglist, rtx target) ...@@ -4551,6 +4553,227 @@ expand_builtin_cabs (tree arglist, rtx target)
return expand_complex_abs (mode, op0, target, 0); 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 /* Expand a call to sprintf with argument list ARGLIST. Return 0 if
a normal call should be emitted rather than expanding the function a normal call should be emitted rather than expanding the function
inline. If convenient, the result should be placed in TARGET with 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) ...@@ -4574,7 +4797,7 @@ expand_builtin_sprintf (tree arglist, rtx target, enum machine_mode mode)
if (! arglist) if (! arglist)
return 0; return 0;
fmt = TREE_VALUE (arglist); fmt = TREE_VALUE (arglist);
if (TREE_CODE (TREE_TYPE (dest)) != POINTER_TYPE) if (TREE_CODE (TREE_TYPE (fmt)) != POINTER_TYPE)
return 0; return 0;
arglist = TREE_CHAIN (arglist); arglist = TREE_CHAIN (arglist);
...@@ -4721,12 +4944,14 @@ expand_builtin (tree exp, rtx target, rtx subtarget, enum machine_mode mode, ...@@ -4721,12 +4944,14 @@ expand_builtin (tree exp, rtx target, rtx subtarget, enum machine_mode mode,
case BUILT_IN_FPUTC: case BUILT_IN_FPUTC:
case BUILT_IN_FPUTS: case BUILT_IN_FPUTS:
case BUILT_IN_FWRITE: case BUILT_IN_FWRITE:
case BUILT_IN_FPRINTF:
case BUILT_IN_PUTCHAR_UNLOCKED: case BUILT_IN_PUTCHAR_UNLOCKED:
case BUILT_IN_PUTS_UNLOCKED: case BUILT_IN_PUTS_UNLOCKED:
case BUILT_IN_PRINTF_UNLOCKED: case BUILT_IN_PRINTF_UNLOCKED:
case BUILT_IN_FPUTC_UNLOCKED: case BUILT_IN_FPUTC_UNLOCKED:
case BUILT_IN_FPUTS_UNLOCKED: case BUILT_IN_FPUTS_UNLOCKED:
case BUILT_IN_FWRITE_UNLOCKED: case BUILT_IN_FWRITE_UNLOCKED:
case BUILT_IN_FPRINTF_UNLOCKED:
case BUILT_IN_FLOOR: case BUILT_IN_FLOOR:
case BUILT_IN_FLOORF: case BUILT_IN_FLOORF:
case BUILT_IN_FLOORL: case BUILT_IN_FLOORL:
...@@ -5167,13 +5392,38 @@ expand_builtin (tree exp, rtx target, rtx subtarget, enum machine_mode mode, ...@@ -5167,13 +5392,38 @@ expand_builtin (tree exp, rtx target, rtx subtarget, enum machine_mode mode,
expand_builtin_trap (); expand_builtin_trap ();
return const0_rtx; 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: case BUILT_IN_FPUTS:
target = expand_builtin_fputs (arglist, ignore,/*unlocked=*/ 0); target = expand_builtin_fputs (arglist, target, false);
if (target) if (target)
return target; return target;
break; break;
case BUILT_IN_FPUTS_UNLOCKED: 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) if (target)
return target; return target;
break; break;
......
...@@ -70,9 +70,8 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA ...@@ -70,9 +70,8 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
DEF_BUILTIN (ENUM, NAME, BUILT_IN_NORMAL, TYPE, BT_LAST, \ DEF_BUILTIN (ENUM, NAME, BUILT_IN_NORMAL, TYPE, BT_LAST, \
false, false, false, ATTRS, true) false, false, false, ATTRS, true)
/* A fallback builtin is a builtin (like __builtin_puts) that falls /* 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 for which we should not introduce the non-`__builtin' variant of
the name. */ the name. */
#undef DEF_FALLBACK_BUILTIN #undef DEF_FALLBACK_BUILTIN
...@@ -124,21 +123,6 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA ...@@ -124,21 +123,6 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
DEF_BUILTIN (ENUM, NAME, BUILT_IN_NORMAL, TYPE, TYPE, \ DEF_BUILTIN (ENUM, NAME, BUILT_IN_NORMAL, TYPE, TYPE, \
true, true, !flag_isoc99, ATTRS, TARGET_C99_FUNCTIONS) 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, DEF_EXT_LIB_BUILTIN(BUILT_IN_ALLOCA,
"__builtin_alloca", "__builtin_alloca",
...@@ -769,7 +753,7 @@ DEF_GCC_BUILTIN(BUILT_IN_PREFETCH, ...@@ -769,7 +753,7 @@ DEF_GCC_BUILTIN(BUILT_IN_PREFETCH,
/* stdio.h builtins (without FILE *). */ /* stdio.h builtins (without FILE *). */
DEF_FRONT_END_LIB_BUILTIN(BUILT_IN_PRINTF, DEF_LIB_BUILTIN(BUILT_IN_PRINTF,
"__builtin_printf", "__builtin_printf",
BT_FN_INT_CONST_STRING_VAR, BT_FN_INT_CONST_STRING_VAR,
ATTR_FORMAT_PRINTF_1_2) ATTR_FORMAT_PRINTF_1_2)
...@@ -840,7 +824,7 @@ DEF_FALLBACK_BUILTIN(BUILT_IN_FWRITE, ...@@ -840,7 +824,7 @@ DEF_FALLBACK_BUILTIN(BUILT_IN_FWRITE,
"__builtin_fwrite", "__builtin_fwrite",
BT_FN_SIZE_CONST_PTR_SIZE_SIZE_PTR, BT_FN_SIZE_CONST_PTR_SIZE_SIZE_PTR,
ATTR_NOTHROW_NONNULL_1_4) ATTR_NOTHROW_NONNULL_1_4)
DEF_FRONT_END_LIB_BUILTIN(BUILT_IN_FPRINTF, DEF_LIB_BUILTIN(BUILT_IN_FPRINTF,
"__builtin_fprintf", "__builtin_fprintf",
BT_FN_INT_PTR_CONST_STRING_VAR, BT_FN_INT_PTR_CONST_STRING_VAR,
ATTR_FORMAT_PRINTF_2_3) ATTR_FORMAT_PRINTF_2_3)
...@@ -853,7 +837,7 @@ DEF_EXT_FALLBACK_BUILTIN(BUILT_IN_PUTCHAR_UNLOCKED, ...@@ -853,7 +837,7 @@ DEF_EXT_FALLBACK_BUILTIN(BUILT_IN_PUTCHAR_UNLOCKED,
DEF_EXT_FALLBACK_BUILTIN(BUILT_IN_PUTS_UNLOCKED, DEF_EXT_FALLBACK_BUILTIN(BUILT_IN_PUTS_UNLOCKED,
"__builtin_puts_unlocked", "__builtin_puts_unlocked",
BT_FN_INT_CONST_STRING, ATTR_NOTHROW_NONNULL_1) BT_FN_INT_CONST_STRING, ATTR_NOTHROW_NONNULL_1)
DEF_EXT_FRONT_END_LIB_BUILTIN(BUILT_IN_PRINTF_UNLOCKED, DEF_EXT_LIB_BUILTIN(BUILT_IN_PRINTF_UNLOCKED,
"__builtin_printf_unlocked", "__builtin_printf_unlocked",
BT_FN_INT_CONST_STRING_VAR, BT_FN_INT_CONST_STRING_VAR,
ATTR_FORMAT_PRINTF_1_2) ATTR_FORMAT_PRINTF_1_2)
...@@ -876,8 +860,9 @@ DEF_BUILTIN (BUILT_IN_FPUTS_UNLOCKED, ...@@ -876,8 +860,9 @@ DEF_BUILTIN (BUILT_IN_FPUTS_UNLOCKED,
true, true, true, ATTR_NOTHROW_NONNULL_1_2, true) true, true, true, ATTR_NOTHROW_NONNULL_1_2, true)
DEF_EXT_FALLBACK_BUILTIN(BUILT_IN_FWRITE_UNLOCKED, DEF_EXT_FALLBACK_BUILTIN(BUILT_IN_FWRITE_UNLOCKED,
"__builtin_fwrite_unlocked", "__builtin_fwrite_unlocked",
BT_FN_SIZE_CONST_PTR_SIZE_SIZE_PTR, ATTR_NOTHROW_NONNULL_1_4) BT_FN_SIZE_CONST_PTR_SIZE_SIZE_PTR,
DEF_EXT_FRONT_END_LIB_BUILTIN(BUILT_IN_FPRINTF_UNLOCKED, ATTR_NOTHROW_NONNULL_1_4)
DEF_EXT_LIB_BUILTIN(BUILT_IN_FPRINTF_UNLOCKED,
"__builtin_fprintf_unlocked", "__builtin_fprintf_unlocked",
BT_FN_INT_PTR_CONST_STRING_VAR, BT_FN_INT_PTR_CONST_STRING_VAR,
ATTR_FORMAT_PRINTF_2_3) ATTR_FORMAT_PRINTF_2_3)
......
...@@ -1175,14 +1175,6 @@ fix_string_type (tree value) ...@@ -1175,14 +1175,6 @@ fix_string_type (tree value)
return 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. /* Print a warning if a constant expression had overflow in folding.
Invoke this function on every expression that the language Invoke this function on every expression that the language
requires to be a constant expression. requires to be a constant expression.
...@@ -4053,20 +4045,6 @@ c_expand_expr (tree exp, rtx target, enum machine_mode tmode, int modifier) ...@@ -4053,20 +4045,6 @@ c_expand_expr (tree exp, rtx target, enum machine_mode tmode, int modifier)
} }
break; 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: case COMPOUND_LITERAL_EXPR:
{ {
/* Initialize the anonymous variable declared in the compound /* Initialize the anonymous variable declared in the compound
...@@ -4136,280 +4114,6 @@ c_staticp (tree exp) ...@@ -4136,280 +4114,6 @@ c_staticp (tree exp)
return 0; 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 /* Given a boolean expression ARG, return a tree representing an increment
or decrement (as indicated by CODE) of ARG. The front end must check for or decrement (as indicated by CODE) of ARG. The front end must check for
......
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