Commit 18f988a0 by Kaveh R. Ghazi Committed by Kaveh Ghazi

builtins.def (BUILT_IN_FPRINTF): New entry.

	* builtins.def (BUILT_IN_FPRINTF): New entry.

	* c-common.c (c_expand_builtin_fprintf): New function.
	(init_function_format_info): Handle __builtin_fprintf.
	(c_common_nodes_and_builtins): Declare fprintf/__builtin_fprintf.
	(c_expand_builtin): Handle BUILT_IN_FPRINTF.

	* c-decl.c (duplicate_decls): Adjust comment.

	* extend.texi (fprintf): Document new builtin.

testsuite:
	* gcc.c-torture/execute/stdio-opt-3.c: New test.

From-SVN: r38788
parent 45b8ddb4
2001-01-07 Kaveh R. Ghazi <ghazi@caip.rutgers.edu>
* builtins.def (BUILT_IN_FPRINTF): New entry.
* c-common.c (c_expand_builtin_fprintf): New function.
(init_function_format_info): Handle __builtin_fprintf.
(c_common_nodes_and_builtins): Declare fprintf/__builtin_fprintf.
(c_expand_builtin): Handle BUILT_IN_FPRINTF.
* c-decl.c (duplicate_decls): Adjust comment.
* extend.texi (fprintf): Document new builtin.
2001-01-07 Richard Henderson <rth@redhat.com> 2001-01-07 Richard Henderson <rth@redhat.com>
* jump.c (simplejump_p): Recognize any single_set jump * jump.c (simplejump_p): Recognize any single_set jump
......
...@@ -79,6 +79,7 @@ DEF_BUILTIN(BUILT_IN_PRINTF) ...@@ -79,6 +79,7 @@ DEF_BUILTIN(BUILT_IN_PRINTF)
DEF_BUILTIN(BUILT_IN_FPUTC) DEF_BUILTIN(BUILT_IN_FPUTC)
DEF_BUILTIN(BUILT_IN_FPUTS) DEF_BUILTIN(BUILT_IN_FPUTS)
DEF_BUILTIN(BUILT_IN_FWRITE) DEF_BUILTIN(BUILT_IN_FWRITE)
DEF_BUILTIN(BUILT_IN_FPRINTF)
/* ISO C99 floating point unordered comparisons. */ /* ISO C99 floating point unordered comparisons. */
DEF_BUILTIN(BUILT_IN_ISGREATER) DEF_BUILTIN(BUILT_IN_ISGREATER)
......
...@@ -1951,6 +1951,8 @@ static int is_valid_printf_arglist PARAMS ((tree)); ...@@ -1951,6 +1951,8 @@ static int is_valid_printf_arglist PARAMS ((tree));
static rtx c_expand_builtin PARAMS ((tree, rtx, enum machine_mode, enum expand_modifier)); static rtx c_expand_builtin PARAMS ((tree, rtx, enum machine_mode, enum expand_modifier));
static rtx c_expand_builtin_printf PARAMS ((tree, rtx, enum machine_mode, static rtx c_expand_builtin_printf PARAMS ((tree, rtx, enum machine_mode,
enum expand_modifier, int)); enum expand_modifier, int));
static rtx c_expand_builtin_fprintf PARAMS ((tree, rtx, enum machine_mode,
enum expand_modifier, int));
/* Initialize the table of functions to perform format checking on. /* Initialize the table of functions to perform format checking on.
The ISO C functions are always checked (whether <stdio.h> is The ISO C functions are always checked (whether <stdio.h> is
...@@ -1976,6 +1978,8 @@ init_function_format_info () ...@@ -1976,6 +1978,8 @@ init_function_format_info ()
printf_format_type, 1, 2); printf_format_type, 1, 2);
record_function_format (get_identifier ("fprintf"), NULL_TREE, record_function_format (get_identifier ("fprintf"), NULL_TREE,
printf_format_type, 2, 3); printf_format_type, 2, 3);
record_function_format (get_identifier ("__builtin_fprintf"), NULL_TREE,
printf_format_type, 2, 3);
record_function_format (get_identifier ("sprintf"), NULL_TREE, record_function_format (get_identifier ("sprintf"), NULL_TREE,
printf_format_type, 2, 3); printf_format_type, 2, 3);
record_function_format (get_identifier ("scanf"), NULL_TREE, record_function_format (get_identifier ("scanf"), NULL_TREE,
...@@ -5127,7 +5131,7 @@ c_common_nodes_and_builtins () ...@@ -5127,7 +5131,7 @@ c_common_nodes_and_builtins ()
tree temp; tree temp;
tree memcpy_ftype, memset_ftype, strlen_ftype; tree memcpy_ftype, memset_ftype, strlen_ftype;
tree bzero_ftype, bcmp_ftype, puts_ftype, printf_ftype; tree bzero_ftype, bcmp_ftype, puts_ftype, printf_ftype;
tree fputs_ftype, fputc_ftype, fwrite_ftype; tree fputs_ftype, fputc_ftype, fwrite_ftype, fprintf_ftype;
tree endlink, int_endlink, double_endlink, unsigned_endlink; tree endlink, int_endlink, double_endlink, unsigned_endlink;
tree cstring_endlink, sizetype_endlink; tree cstring_endlink, sizetype_endlink;
tree ptr_ftype, ptr_ftype_unsigned; tree ptr_ftype, ptr_ftype_unsigned;
...@@ -5539,6 +5543,14 @@ c_common_nodes_and_builtins () ...@@ -5539,6 +5543,14 @@ c_common_nodes_and_builtins ()
tree_cons (NULL_TREE, const_string_type_node, tree_cons (NULL_TREE, const_string_type_node,
tree_cons (NULL_TREE, ptr_type_node, endlink))); tree_cons (NULL_TREE, ptr_type_node, endlink)));
/* Prototype for fprintf. */
fprintf_ftype
= build_function_type (integer_type_node,
tree_cons (NULL_TREE, ptr_type_node,
tree_cons (NULL_TREE,
const_string_type_node,
NULL_TREE)));
builtin_function ("__builtin_constant_p", default_function_type, builtin_function ("__builtin_constant_p", default_function_type,
BUILT_IN_CONSTANT_P, BUILT_IN_NORMAL, NULL_PTR); BUILT_IN_CONSTANT_P, BUILT_IN_NORMAL, NULL_PTR);
...@@ -5817,6 +5829,9 @@ c_common_nodes_and_builtins () ...@@ -5817,6 +5829,9 @@ c_common_nodes_and_builtins ()
builtin_function_2 ("__builtin_printf", "printf", builtin_function_2 ("__builtin_printf", "printf",
printf_ftype, printf_ftype, printf_ftype, printf_ftype,
BUILT_IN_PRINTF, BUILT_IN_FRONTEND, 1, 0, 0); BUILT_IN_PRINTF, BUILT_IN_FRONTEND, 1, 0, 0);
builtin_function_2 ("__builtin_fprintf", "fprintf",
fprintf_ftype, fprintf_ftype,
BUILT_IN_FPRINTF, BUILT_IN_FRONTEND, 1, 0, 0);
built_in_decls[BUILT_IN_FWRITE] = built_in_decls[BUILT_IN_FWRITE] =
builtin_function ("__builtin_fwrite", fwrite_ftype, builtin_function ("__builtin_fwrite", fwrite_ftype,
BUILT_IN_FWRITE, BUILT_IN_NORMAL, "fwrite"); BUILT_IN_FWRITE, BUILT_IN_NORMAL, "fwrite");
...@@ -6614,6 +6629,13 @@ c_expand_builtin (exp, target, tmode, modifier) ...@@ -6614,6 +6629,13 @@ c_expand_builtin (exp, target, tmode, modifier)
return target; return target;
break; break;
case BUILT_IN_FPRINTF:
target = c_expand_builtin_fprintf (arglist, target, tmode,
modifier, ignore);
if (target)
return target;
break;
default: /* just do library call, if unknown builtin */ default: /* just do library call, if unknown builtin */
error ("built-in function `%s' not currently supported", error ("built-in function `%s' not currently supported",
IDENTIFIER_POINTER (DECL_NAME (fndecl))); IDENTIFIER_POINTER (DECL_NAME (fndecl)));
...@@ -6752,6 +6774,86 @@ c_expand_builtin_printf (arglist, target, tmode, modifier, ignore) ...@@ -6752,6 +6774,86 @@ c_expand_builtin_printf (arglist, target, tmode, modifier, ignore)
tmode, modifier); tmode, modifier);
} }
/* If the arguments passed to fprintf are suitable for optimizations,
we attempt to transform the call. */
static rtx
c_expand_builtin_fprintf (arglist, target, tmode, modifier, ignore)
tree arglist;
rtx target;
enum machine_mode tmode;
enum expand_modifier modifier;
int ignore;
{
tree fn_fputc = built_in_decls[BUILT_IN_FPUTC],
fn_fputs = 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
......
...@@ -1511,7 +1511,7 @@ duplicate_decls (newdecl, olddecl, different_binding_level) ...@@ -1511,7 +1511,7 @@ duplicate_decls (newdecl, olddecl, different_binding_level)
oldtype = trytype; oldtype = trytype;
} }
/* Accept harmless mismatch in first argument type also. /* Accept harmless mismatch in first argument type also.
This is for ffs. */ This is for the ffs and fprintf builtins. */
if (TYPE_ARG_TYPES (TREE_TYPE (newdecl)) != 0 if (TYPE_ARG_TYPES (TREE_TYPE (newdecl)) != 0
&& TYPE_ARG_TYPES (oldtype) != 0 && TYPE_ARG_TYPES (oldtype) != 0
&& TREE_VALUE (TYPE_ARG_TYPES (newtype)) != 0 && TREE_VALUE (TYPE_ARG_TYPES (newtype)) != 0
......
...@@ -3376,6 +3376,7 @@ function as well. ...@@ -3376,6 +3376,7 @@ function as well.
@findex fabsf @findex fabsf
@findex fabsl @findex fabsl
@findex ffs @findex ffs
@findex fprintf
@findex fputs @findex fputs
@findex imaxabs @findex imaxabs
@findex index @findex index
...@@ -3447,13 +3448,13 @@ corresponding versions prefixed with @code{__builtin_}. ...@@ -3447,13 +3448,13 @@ corresponding versions prefixed with @code{__builtin_}.
The following ISO C89 functions are recognized as builtins unless The following ISO C89 functions are recognized as builtins unless
@samp{-fno-builtin} is specified: @code{abs}, @code{cos}, @code{fabs}, @samp{-fno-builtin} is specified: @code{abs}, @code{cos}, @code{fabs},
@code{fputs}, @code{labs}, @code{memcmp}, @code{memcpy}, @code{memset}, @code{fprintf}, @code{fputs}, @code{labs}, @code{memcmp}, @code{memcpy},
@code{printf}, @code{sin}, @code{sqrt}, @code{strcat}, @code{strchr}, @code{memset}, @code{printf}, @code{sin}, @code{sqrt}, @code{strcat},
@code{strcmp}, @code{strcpy}, @code{strcspn}, @code{strlen}, @code{strchr}, @code{strcmp}, @code{strcpy}, @code{strcspn},
@code{strncat}, @code{strncmp}, @code{strncpy}, @code{strpbrk}, @code{strlen}, @code{strncat}, @code{strncmp}, @code{strncpy},
@code{strrchr}, @code{strspn}, and @code{strstr}. All of these @code{strpbrk}, @code{strrchr}, @code{strspn}, and @code{strstr}. All
functions have corresponding versions prefixed with @code{__builtin_}, of these functions have corresponding versions prefixed with
except that the version for @code{sqrt} is called @code{__builtin_}, except that the version for @code{sqrt} is called
@code{__builtin_fsqrt}. @code{__builtin_fsqrt}.
GNU CC provides builtin versions of the ISO C99 floating point GNU CC provides builtin versions of the ISO C99 floating point
......
2001-01-07 Kaveh R. Ghazi <ghazi@caip.rutgers.edu>
* gcc.c-torture/execute/stdio-opt-3.c: New test.
2001-01-07 Jakub Jelinek <jakub@redhat.com> 2001-01-07 Jakub Jelinek <jakub@redhat.com>
* gcc.c-torture/compile/20010107-1.c: New test. * gcc.c-torture/compile/20010107-1.c: New test.
......
/* Copyright (C) 2001 Free Software Foundation.
Ensure all expected transformations of builtin fprintf occur and
that we honor side effects in the arguments.
Written by Kaveh R. Ghazi, 1/7/2001. */
#include <stdio.h>
extern int fprintf (FILE *, const char *, ...);
extern void abort(void);
int main()
{
FILE *s_array[] = {stdout, NULL}, **s_ptr = s_array;
const char *const s1 = "hello world";
const char *const s2[] = { s1, 0 }, *const*s3;
fprintf (*s_ptr, "%s", "hello");
fprintf (*s_ptr, "%s", "\n");
fprintf (*s_ptr, "%s", *s2);
s3 = s2;
fprintf (*s_ptr, "%s", *s3++);
if (s3 != s2+1 || *s3 != 0)
abort();
s3 = s2;
fprintf (*s_ptr++, "%s", *s3++);
if (s3 != s2+1 || *s3 != 0 || s_ptr != s_array+1 || *s_ptr != 0)
abort();
s_ptr = s_array;
fprintf (*s_ptr, "%c", '\n');
fprintf (*s_ptr, "%c", **s2);
s3 = s2;
fprintf (*s_ptr, "%c", **s3++);
if (s3 != s2+1 || *s3 != 0)
abort();
s3 = s2;
fprintf (*s_ptr++, "%c", **s3++);
if (s3 != s2+1 || *s3 != 0 || s_ptr != s_array+1 || *s_ptr != 0)
abort();
s_ptr = s_array;
fprintf (*s_ptr++, "hello world");
if (s_ptr != s_array+1 || *s_ptr != 0)
abort();
s_ptr = s_array;
fprintf (*s_ptr, "\n");
/* Test at least one instance of the __builtin_ style. We do this
to ensure that it works and that the prototype is correct. */
__builtin_fprintf (*s_ptr, "%s", "hello world\n");
return 0;
}
#ifdef __OPTIMIZE__
/* When optimizing, all the above cases should be transformed into
something else. So any remaining calls to the original function
should abort. */
static int
fprintf (FILE *stream, const char *string, ...)
{
abort();
}
#endif
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