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 to add __builtin_printf -> fputs transformations


This patch adds two new __builtin_printf transformations.

printf("%s", foo) -> fputs(foo, stdout)
printf("string") -> fputs("string", stdout)  (where "string" contains no %)

In order for this to work, we have to capture the definition of stdout
as defined in stdio.h whether it is a macro or an explicit identifier.
To do this I created a special header installed by gcc called
stdio-opt.h and I arrange for stdio.h to include it as its last act.
(I envision this new file can also be used for future optimizations
such as capturing the putc macro, etc.)

The stdio-opt.h instantiates the new __builtin_initialize_stdout
function which expects one pointer type parameter.  This parameter is
captured internally and is assumed to be the FILE* stdout.  This tree
structure is then substituted whenever a __builtin_printf
transformation needs stdout.

But in order to write as valid C __builtin_initialize_stdout(stdout),
I had to encapsulate it inside a static function and I'm not entirely
happy with the fact that every module will get the extra empty
function definition.  Note, it is namespace clean.  Also note,
__builtin_initialize_stdout(stdout) only needs to be *compiled*, not
executed.  Finally, the static copy does go away at -O3.

I tried making the wrapper be static-inline and extern-inline, and it
works for C, but then the C++ front-end never sees stdout.  I assume
because it handles expanding unused inline functions differently
(i.e. doesn't do it,) but that's a total guess.

Preliminary tests indicate this mechanism works fine for C, C++ and
ObjC (with the above caveat that each module wastes a couple of bytes.
Perhaps gnu-ld or gnu-as are smart enough to delete unused static
functions?)  Anyway, I'm running a full bootstrap and tests now.

If anyone would like to suggest alternatives to
__builtin_initialize_stdout, I'm willing to consider them.  E.g. a
pragma might work, (#pragma initialize_stdout stdout), but I don't
know if it'll expand stdout when it's a macro.

Assuming no regressions and no alternatives, okay to install?

		Thanks,
		--Kaveh


2000-09-19  Kaveh R. Ghazi  <ghazi@caip.rutgers.edu>

	* ginclude/stdio-opt.h: New file.

	* Makefile.in (USER_H): Add ginclude/stdio-opt.h.
	(stmp-int-hdrs): Arrange for stdio.h to include stdio-opt.h.

	* builtins.c (expand_builtin_initialize_stdout): New function.
	(expand_builtin_printf): Add new transformations into fputs.
	(expand_builtin): Handle BUILT_IN_INITIALIZE_STDOUT.

	* builtins.def (BUILT_IN_INITIALIZE_STDOUT): New entry.

	* c-common.c (__builtin_initialize_stdout): Declare.

diff -rup orig/egcs-CVS20000919/gcc/Makefile.in egcs-CVS20000919/gcc/Makefile.in
--- orig/egcs-CVS20000919/gcc/Makefile.in	Mon Sep 18 23:20:29 2000
+++ egcs-CVS20000919/gcc/Makefile.in	Tue Sep 19 15:06:06 2000
@@ -159,6 +159,7 @@ INSTALL_HEADERS_DIR = @build_install_hea
 USER_H = $(srcdir)/ginclude/stdarg.h $(srcdir)/ginclude/stddef.h \
     $(srcdir)/ginclude/varargs.h $(srcdir)/ginclude/proto.h \
     $(srcdir)/ginclude/stdbool.h $(srcdir)/ginclude/iso646.h \
+    $(srcdir)/ginclude/stdio-opt.h \
     $(EXTRA_HEADERS) $(LANG_EXTRA_HEADERS)
 
 # Target to use whe installing assert.h.  Some systems may
@@ -1942,6 +1943,12 @@ stmp-int-hdrs: $(STMP_FIXINC) $(USER_H) 
 	  cp $(srcdir)/config/$(FLOAT_H) include/float.h && \
 	  chmod a+r include/float.h; \
 	else :; fi
+	if [ -f include/stdio.h ] ; then \
+	  echo '#include <stdio-opt.h>' >> include/stdio.h ; \
+	else \
+	  (echo '#include_next <stdio.h>' ; \
+	  echo '#include <stdio-opt.h>' ) > include/stdio.h ; \
+	fi
 # Install the README
 	rm -f include/README
 	cp $(srcdir)/README-fixinc include/README
diff -rup orig/egcs-CVS20000919/gcc/builtins.c egcs-CVS20000919/gcc/builtins.c
--- orig/egcs-CVS20000919/gcc/builtins.c	Tue Sep 19 14:14:35 2000
+++ egcs-CVS20000919/gcc/builtins.c	Tue Sep 19 16:25:38 2000
@@ -56,6 +56,9 @@ Boston, MA 02111-1307, USA.  */
 #define PAD_VARARGS_DOWN BYTES_BIG_ENDIAN
 #endif
 
+/* This will hold the tree node representing the captured stdout.  */
+static tree stdout_node = NULL_TREE;
+
 /* Define the names of the builtin function types and codes.  */
 const char *const built_in_class_names[4]
   = {"NOT_BUILT_IN", "BUILT_IN_FRONTEND", "BUILT_IN_MD", "BUILT_IN_NORMAL"};
@@ -114,6 +117,7 @@ static rtx expand_builtin_frame_address	
 static int is_valid_printf_arglist	PARAMS ((tree));
 static rtx expand_builtin_printf	PARAMS ((tree, int));
 static rtx expand_builtin_fputs		PARAMS ((tree, int));
+static void expand_builtin_initialize_stdout PARAMS ((tree));
 static tree stabilize_va_list		PARAMS ((tree, int));
 static rtx expand_builtin_expect	PARAMS ((tree, rtx));
 
@@ -2412,13 +2416,14 @@ expand_builtin_printf (arglist, ignore)
      int ignore;
 {
   tree fn_putchar = built_in_decls[BUILT_IN_PUTCHAR],
-    fn_puts = built_in_decls[BUILT_IN_PUTS];
+    fn_puts = built_in_decls[BUILT_IN_PUTS],
+    fn_fputs = built_in_decls[BUILT_IN_FPUTS];
   tree call_expr, fn;
   tree 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_putchar || !fn_puts)
+  if (!ignore || !fn_putchar || !fn_puts || !fn_fputs)
     return 0;
 
   /* Verify the required arguments in the original call. */
@@ -2454,6 +2459,16 @@ expand_builtin_printf (arglist, ignore)
       arglist = TREE_CHAIN (arglist);
       fn = fn_putchar;
     }
+  /* If the format specifier was "%s", call __builtin_fputs (arg2, stdout). */
+  else if (strcmp (TREE_STRING_POINTER (stripped_string), "%s") == 0
+	   && stdout_node)
+    {
+      tree string_arg = TREE_VALUE (TREE_CHAIN (arglist));
+
+      arglist = build_tree_list (NULL_TREE, stdout_node);
+      arglist = tree_cons (NULL_TREE, string_arg, arglist);
+      fn = fn_fputs;
+    }
   else
     {
      /* We can't handle anything else with % args or %% ... yet. */
@@ -2473,9 +2488,17 @@ expand_builtin_printf (arglist, ignore)
 	  
 	  fn = fn_putchar;
         }
+      /* At this point, we have a string constant with no "%", call
+         fputs if we have already captured stdout.  */
+      else if (stdout_node)
+        {
+	  tree string_arg = TREE_VALUE (arglist);
+	  
+	  arglist = build_tree_list (NULL_TREE, stdout_node);
+	  arglist = tree_cons (NULL_TREE, string_arg, arglist);
+	  fn = fn_fputs;
+	}
       else
-	/* 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;
     }
   
@@ -2487,6 +2510,18 @@ expand_builtin_printf (arglist, ignore)
 		      VOIDmode, EXPAND_NORMAL);
 }
 
+/* Save the tree node corresponding to stdout.  */
+static void
+expand_builtin_initialize_stdout (arglist)
+     tree arglist;
+{
+  if (arglist == 0
+      || (TREE_CODE (TREE_TYPE (TREE_VALUE (arglist))) != POINTER_TYPE))
+    abort ();
+
+  stdout_node = TREE_VALUE (arglist);
+}
+
 /* Expand a call to __builtin_expect.  We return our argument and
    emit a NOTE_INSN_EXPECTED_VALUE note.  */
 
@@ -2793,6 +2828,11 @@ expand_builtin (exp, target, subtarget, 
 	return target;
       break;
       
+    case BUILT_IN_INITIALIZE_STDOUT:
+      expand_builtin_initialize_stdout (arglist);
+      return const0_rtx;
+      break;
+
       /* Various hooks for the DWARF 2 __throw routine.  */
     case BUILT_IN_UNWIND_INIT:
       expand_builtin_unwind_init ();
diff -rup orig/egcs-CVS20000919/gcc/builtins.def egcs-CVS20000919/gcc/builtins.def
--- orig/egcs-CVS20000919/gcc/builtins.def	Tue Sep 19 14:14:36 2000
+++ egcs-CVS20000919/gcc/builtins.def	Tue Sep 19 15:06:06 2000
@@ -64,6 +64,7 @@ DEF_BUILTIN(BUILT_IN_PUTS)
 DEF_BUILTIN(BUILT_IN_PRINTF)
 DEF_BUILTIN(BUILT_IN_FPUTC)
 DEF_BUILTIN(BUILT_IN_FPUTS)
+DEF_BUILTIN(BUILT_IN_INITIALIZE_STDOUT)
 
   /* ISO C99 floating point unordered comparisons.  */
 DEF_BUILTIN(BUILT_IN_ISGREATER)
diff -rup orig/egcs-CVS20000919/gcc/c-common.c egcs-CVS20000919/gcc/c-common.c
--- orig/egcs-CVS20000919/gcc/c-common.c	Tue Sep 19 14:14:36 2000
+++ egcs-CVS20000919/gcc/c-common.c	Tue Sep 19 15:06:06 2000
@@ -4384,6 +4384,10 @@ c_common_nodes_and_builtins (cplus_mode,
     builtin_function ("__builtin_fputs", int_ftype_any,
 		      BUILT_IN_FPUTS, BUILT_IN_NORMAL, "fputs");
 
+  /* Initialize a node containing stdout as defined by stdio.h.  */
+  builtin_function ("__builtin_initialize_stdout", void_ftype_ptr,
+		    BUILT_IN_INITIALIZE_STDOUT, BUILT_IN_NORMAL, NULL_PTR);
+
   if (! no_builtins)
     {
       builtin_function ("abs", int_ftype_int, BUILT_IN_ABS,
diff -rup orig/egcs-CVS20000919/gcc/ginclude/stdio-opt.h egcs-CVS20000919/gcc/ginclude/stdio-opt.h
--- orig/egcs-CVS20000919/gcc/ginclude/stdio-opt.h	Tue Sep 19 15:08:38 2000
+++ egcs-CVS20000919/gcc/ginclude/stdio-opt.h	Tue Sep 19 17:58:51 2000
@@ -0,0 +1,46 @@
+/* Copyright (C) 2000 Free Software Foundation, Inc.
+
+This file is part of GNU CC.
+
+GNU CC is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU CC is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU CC; see the file COPYING.  If not, write to
+the Free Software Foundation, 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA.  */
+
+/* As a special exception, if you include this header file into source
+   files compiled by GCC, this header file does not by itself cause
+   the resulting executable to be covered by the GNU General Public
+   License.  This exception does not however invalidate any other
+   reasons why the executable file might be covered by the GNU General
+   Public License.  */
+
+/* The purpose of this file is to capture the definition of stdout
+   (which may be a macro) as a function parameter.  This is so that
+   gcc can make use of it for internal builtin transformations.  */
+
+#ifndef __GCC_STDIO_OPTIMIZE__
+#define __GCC_STDIO_OPTIMIZE__
+
+/* We capture the definition of stdout here, stdio.h may define it as
+   a macro or as its own identifier.  Either way, we catch it here.
+   It's used when transforming calls to printf into calls to fputs.
+   Note we only need to instantiate __builtin_initialize_stdout within
+   a function definition.  We don't have to actually execute it.  */
+
+static void
+__gcc_builtin_initialize_stdout (void)
+{
+  __builtin_initialize_stdout(stdout);
+}
+
+#endif /* ! __GCC_STDIO_OPTIMIZE__ */

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