From 18f988a06bd585a53af224091ef2e6a29074a511 Mon Sep 17 00:00:00 2001 From: "Kaveh R. Ghazi" Date: Sun, 7 Jan 2001 23:15:47 +0000 Subject: [PATCH] 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 --- gcc/ChangeLog | 13 +++ gcc/builtins.def | 1 + gcc/c-common.c | 104 +++++++++++++++++- gcc/c-decl.c | 2 +- gcc/extend.texi | 15 +-- gcc/testsuite/ChangeLog | 4 + .../gcc.c-torture/execute/stdio-opt-3.c | 65 +++++++++++ 7 files changed, 195 insertions(+), 9 deletions(-) create mode 100644 gcc/testsuite/gcc.c-torture/execute/stdio-opt-3.c diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 304c7dee3b0..a9c499a5b17 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,16 @@ +2001-01-07 Kaveh R. Ghazi + + * 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 * jump.c (simplejump_p): Recognize any single_set jump diff --git a/gcc/builtins.def b/gcc/builtins.def index ecb1991b4b1..cd715d9db96 100644 --- a/gcc/builtins.def +++ b/gcc/builtins.def @@ -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) diff --git a/gcc/c-common.c b/gcc/c-common.c index 3a76510428e..98d96e2a555 100644 --- a/gcc/c-common.c +++ b/gcc/c-common.c @@ -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 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 diff --git a/gcc/c-decl.c b/gcc/c-decl.c index 0a94db0e595..95272f97c07 100644 --- a/gcc/c-decl.c +++ b/gcc/c-decl.c @@ -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 diff --git a/gcc/extend.texi b/gcc/extend.texi index e893c67f15c..bee479a8f61 100644 --- a/gcc/extend.texi +++ b/gcc/extend.texi @@ -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 diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 0d53b9383be..87b4b6f6cec 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,7 @@ +2001-01-07 Kaveh R. Ghazi + + * gcc.c-torture/execute/stdio-opt-3.c: New test. + 2001-01-07 Jakub Jelinek * gcc.c-torture/compile/20010107-1.c: New test. diff --git a/gcc/testsuite/gcc.c-torture/execute/stdio-opt-3.c b/gcc/testsuite/gcc.c-torture/execute/stdio-opt-3.c new file mode 100644 index 00000000000..fb56a3ff540 --- /dev/null +++ b/gcc/testsuite/gcc.c-torture/execute/stdio-opt-3.c @@ -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 +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 -- 2.30.2