This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
Patch installed for builtin fprintf
- To: gcc-patches at gcc dot gnu dot org
- Subject: Patch installed for builtin fprintf
- From: "Kaveh R. Ghazi" <ghazi at caip dot rutgers dot edu>
- Date: Sun, 7 Jan 2001 18:28:20 -0500 (EST)
- Cc: mark at codesourcery dot com
I've installed my patch to create builtin fprintf. It was approved by
Mark Mitchell.
I updated the patch to work within the more current builtins setup,
added fprintf to the builtins list in extend.texi and added a
testcase. Below is the final result.
Note: some issues remain, most strangely that C++ builtins don't work.
But that is systemic to all C++ builtins, (the C testcase for this
builtin works fine.) I'll look into the C++ problems and see what I
can determine. Also, the void* vs FILE* prototype clash remains in
C++, but until builtins work at all in C++ that one is moot. There's
no harm to fixing that later. So in the mean time there was no reason
not to install this one.
I rebootstrapped the following on solaris2.7 with no regressions.
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.
testsuite:
* gcc.c-torture/execute/stdio-opt-3.c: New test.
diff -rup orig/egcs-CVS20010107/gcc/builtins.def egcs-CVS20010107/gcc/builtins.def
--- orig/egcs-CVS20010107/gcc/builtins.def Fri Jan 5 16:26:05 2001
+++ egcs-CVS20010107/gcc/builtins.def Sun Jan 7 08:16:17 2001
@@ -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 -rup orig/egcs-CVS20010107/gcc/c-common.c egcs-CVS20010107/gcc/c-common.c
--- orig/egcs-CVS20010107/gcc/c-common.c Sun Jan 7 07:25:39 2001
+++ egcs-CVS20010107/gcc/c-common.c Sun Jan 7 08:33:00 2001
@@ -1951,6 +1951,8 @@ static int is_valid_printf_arglist PARAM
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, mo
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)));
@@ -6745,6 +6767,86 @@ c_expand_builtin_printf (arglist, target
/* 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 (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),
diff -rup orig/egcs-CVS20010107/gcc/c-decl.c egcs-CVS20010107/gcc/c-decl.c
--- orig/egcs-CVS20010107/gcc/c-decl.c Fri Jan 5 07:26:19 2001
+++ egcs-CVS20010107/gcc/c-decl.c Sun Jan 7 08:16:17 2001
@@ -1511,7 +1511,7 @@ duplicate_decls (newdecl, olddecl, diffe
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 -rup orig/egcs-CVS20010107/gcc/extend.texi egcs-CVS20010107/gcc/extend.texi
--- orig/egcs-CVS20010107/gcc/extend.texi Sun Jan 7 07:25:42 2001
+++ egcs-CVS20010107/gcc/extend.texi Sun Jan 7 08:23:43 2001
@@ -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 @co
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 -rup orig/egcs-CVS20010107/gcc/testsuite/gcc.c-torture/execute/stdio-opt-3.c egcs-CVS20010107/gcc/testsuite/gcc.c-torture/execute/stdio-opt-3.c
--- orig/egcs-CVS20010107/gcc/testsuite/gcc.c-torture/execute/stdio-opt-3.c Sun Jan 7 08:25:12 2001
+++ egcs-CVS20010107/gcc/testsuite/gcc.c-torture/execute/stdio-opt-3.c Sun Jan 7 08:37:38 2001
@@ -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