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
This commit is contained in:
Kaveh R. Ghazi 2001-01-07 23:15:47 +00:00 committed by Kaveh Ghazi
parent 45b8ddb491
commit 18f988a06b
7 changed files with 195 additions and 9 deletions

View File

@ -1,3 +1,16 @@
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>
* jump.c (simplejump_p): Recognize any single_set jump

View File

@ -79,6 +79,7 @@ DEF_BUILTIN(BUILT_IN_PRINTF)
DEF_BUILTIN(BUILT_IN_FPUTC)
DEF_BUILTIN(BUILT_IN_FPUTS)
DEF_BUILTIN(BUILT_IN_FWRITE)
DEF_BUILTIN(BUILT_IN_FPRINTF)
/* ISO C99 floating point unordered comparisons. */
DEF_BUILTIN(BUILT_IN_ISGREATER)

View File

@ -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_printf PARAMS ((tree, rtx, enum machine_mode,
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.
The ISO C functions are always checked (whether <stdio.h> is
@ -1976,6 +1978,8 @@ init_function_format_info ()
printf_format_type, 1, 2);
record_function_format (get_identifier ("fprintf"), NULL_TREE,
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,
printf_format_type, 2, 3);
record_function_format (get_identifier ("scanf"), NULL_TREE,
@ -5127,7 +5131,7 @@ c_common_nodes_and_builtins ()
tree temp;
tree memcpy_ftype, memset_ftype, strlen_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 cstring_endlink, sizetype_endlink;
tree ptr_ftype, ptr_ftype_unsigned;
@ -5539,6 +5543,14 @@ c_common_nodes_and_builtins ()
tree_cons (NULL_TREE, const_string_type_node,
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,
BUILT_IN_CONSTANT_P, BUILT_IN_NORMAL, NULL_PTR);
@ -5817,6 +5829,9 @@ c_common_nodes_and_builtins ()
builtin_function_2 ("__builtin_printf", "printf",
printf_ftype, printf_ftype,
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] =
builtin_function ("__builtin_fwrite", fwrite_ftype,
BUILT_IN_FWRITE, BUILT_IN_NORMAL, "fwrite");
@ -6614,6 +6629,13 @@ c_expand_builtin (exp, target, tmode, modifier)
return target;
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 */
error ("built-in function `%s' not currently supported",
IDENTIFIER_POINTER (DECL_NAME (fndecl)));
@ -6751,6 +6773,86 @@ c_expand_builtin_printf (arglist, target, tmode, modifier, ignore)
(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 (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

View File

@ -1511,7 +1511,7 @@ duplicate_decls (newdecl, olddecl, different_binding_level)
oldtype = trytype;
}
/* 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
&& TYPE_ARG_TYPES (oldtype) != 0
&& TREE_VALUE (TYPE_ARG_TYPES (newtype)) != 0

View File

@ -3376,6 +3376,7 @@ function as well.
@findex fabsf
@findex fabsl
@findex ffs
@findex fprintf
@findex fputs
@findex imaxabs
@findex index
@ -3447,13 +3448,13 @@ corresponding versions prefixed with @code{__builtin_}.
The following ISO C89 functions are recognized as builtins unless
@samp{-fno-builtin} is specified: @code{abs}, @code{cos}, @code{fabs},
@code{fputs}, @code{labs}, @code{memcmp}, @code{memcpy}, @code{memset},
@code{printf}, @code{sin}, @code{sqrt}, @code{strcat}, @code{strchr},
@code{strcmp}, @code{strcpy}, @code{strcspn}, @code{strlen},
@code{strncat}, @code{strncmp}, @code{strncpy}, @code{strpbrk},
@code{strrchr}, @code{strspn}, and @code{strstr}. All of these
functions have corresponding versions prefixed with @code{__builtin_},
except that the version for @code{sqrt} is called
@code{fprintf}, @code{fputs}, @code{labs}, @code{memcmp}, @code{memcpy},
@code{memset}, @code{printf}, @code{sin}, @code{sqrt}, @code{strcat},
@code{strchr}, @code{strcmp}, @code{strcpy}, @code{strcspn},
@code{strlen}, @code{strncat}, @code{strncmp}, @code{strncpy},
@code{strpbrk}, @code{strrchr}, @code{strspn}, and @code{strstr}. All
of these functions have corresponding versions prefixed with
@code{__builtin_}, except that the version for @code{sqrt} is called
@code{__builtin_fsqrt}.
GNU CC provides builtin versions of the ISO C99 floating point

View File

@ -1,3 +1,7 @@
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>
* gcc.c-torture/compile/20010107-1.c: New test.

View File

@ -0,0 +1,65 @@
/* 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