This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]

Patch installed for builtin fprintf


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

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]