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]

Problem inlining in c++ (was Re: Patch to add __builtin_printf -> fputs transformations)


 > From: Richard Henderson <rth@cygnus.com>
 > 
 > On Tue, Sep 19, 2000 at 06:13:58PM -0400, Kaveh R. Ghazi wrote:
 > > The stdio-opt.h instantiates the new __builtin_initialize_stdout
 > > function which expects one pointer type parameter.
 > 
 > Another alternative is to look for an inline function
 > 
 >   static inline FILE * __builtin_stdout(void) { return stdout; }
 > 
 > If it is not defined, then the optimization is not performed.
 > If it is defined, then you transform to
 > 
 >   fputs("string", __builtin_stdout());

Doh!  Its always so obvious *after* you point it out. :-)


I went ahead and tried this style, and it works great for C and objc.
The generated assembly for small sample programs looks perfect.

However the C++ front end emits the __builtin_stdout function
out-of-line and issues a call to it when gathering the fputs args.
I used the exact same code in each of the front ends to set this up
but C++ is handling it differently.  (Note the C++ code works, its
just pessimized.)

This patch could go in and work just fine without the c++ bits, but
I'd like to get the opt working for all three C derivatives.  If
someone could please help out I'd really appreciate it, take a look at
c_builtin_stdout in c-decl.c and cp/decl.c from which I retrieve the
function call to __builtin_stdout.  The return value of these
functions is used as the FILE* argument when replacing printf with
fputs.  The rest of the patch is all framework.

		Thanks,
		--Kaveh



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 22:53:55 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	Wed Sep 20 17:25:13 2000
@@ -2412,13 +2412,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 +2455,18 @@ 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)
+    {
+      tree string_arg = TREE_VALUE (TREE_CHAIN (arglist));
+
+      /* If stdio.h wasn't included, this'll return 0.  */
+      if (!c_builtin_stdout_ptr || !(arglist = c_builtin_stdout_ptr()))
+	return 0;
+      arglist = build_tree_list (NULL_TREE, arglist);
+      arglist = tree_cons (NULL_TREE, string_arg, arglist);
+      fn = fn_fputs;
+    }
   else
     {
      /* We can't handle anything else with % args or %% ... yet. */
@@ -2473,10 +2486,19 @@ 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
-	/* 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;
+        {
+	  tree string_arg = TREE_VALUE (arglist);
+	  
+	  /* If stdio.h wasn't included, this'll return 0.  */
+	  if (!c_builtin_stdout_ptr || !(arglist = c_builtin_stdout_ptr()))
+	    return 0;
+	  arglist = build_tree_list (NULL_TREE, arglist);
+	  arglist = tree_cons (NULL_TREE, string_arg, arglist);
+	  fn = fn_fputs;
+	}
     }
   
   call_expr = build1 (ADDR_EXPR, build_pointer_type (TREE_TYPE (fn)), fn);
diff -rup orig/egcs-CVS20000919/gcc/c-decl.c egcs-CVS20000919/gcc/c-decl.c
--- orig/egcs-CVS20000919/gcc/c-decl.c	Tue Sep 19 10:43:23 2000
+++ egcs-CVS20000919/gcc/c-decl.c	Wed Sep 20 17:22:10 2000
@@ -310,6 +310,7 @@ static tree grokparms			PARAMS ((tree, i
 static void layout_array_type		PARAMS ((tree));
 static tree c_make_fname_decl           PARAMS ((tree, const char *, int));
 static void c_expand_body               PARAMS ((tree, int));
+static tree c_builtin_stdout            PARAMS ((void));
 
 /* C-specific option variables.  */
 
@@ -3235,6 +3236,9 @@ init_decl_processing ()
 		mark_binding_level);
   ggc_add_tree_root (&static_ctors, 1);
   ggc_add_tree_root (&static_dtors, 1);
+
+  /* Set the stdout retrieval function.  */
+  c_builtin_stdout_ptr = c_builtin_stdout;
 }
 
 /* Create the VAR_DECL for __FUNCTION__ etc. ID is the name to give the
@@ -7103,4 +7107,17 @@ c_expand_decl_stmt (t)
       && DECL_CONTEXT (decl) == current_function_decl
       && DECL_SAVED_TREE (decl))
     c_expand_body (decl, /*nested_p=*/1);
+}
+
+/* Retrieve the value of __builtin_stdout and return the result as a
+   function call to an inline function.  */
+tree
+c_builtin_stdout()
+{
+  tree decl, id = maybe_get_identifier("__builtin_stdout");
+
+  if (!id || !(decl = IDENTIFIER_GLOBAL_VALUE(id)))
+    return NULL_TREE;
+  
+  return build_function_call (decl, NULL_TREE);
 }
diff -rup orig/egcs-CVS20000919/gcc/cp/decl.c egcs-CVS20000919/gcc/cp/decl.c
--- orig/egcs-CVS20000919/gcc/cp/decl.c	Tue Sep 19 10:43:39 2000
+++ egcs-CVS20000919/gcc/cp/decl.c	Wed Sep 20 17:25:30 2000
@@ -176,6 +176,7 @@ static tree check_special_function_retur
 static tree push_cp_library_fn PARAMS ((enum tree_code, tree));
 static tree build_cp_library_fn PARAMS ((tree, enum tree_code, tree));
 static void store_parm_decls PARAMS ((tree));
+static tree c_builtin_stdout PARAMS ((void));
 
 #if defined (DEBUG_CP_BINDING_LEVELS)
 static void indent PARAMS ((void));
@@ -6694,6 +6695,9 @@ init_decl_processing ()
 
   ggc_add_tree_root (&current_lang_name, 1);
   ggc_add_tree_root (&static_aggregates, 1);
+
+  /* Set the stdout retrieval function.  */
+  c_builtin_stdout_ptr = c_builtin_stdout;
 }
 
 /* Create the VAR_DECL for __FUNCTION__ etc. ID is the name to give the
@@ -14745,4 +14749,17 @@ lang_mark_tree (t)
 	   TYPE_LANG_SPECIFIC is really just a tree.  */
 	ggc_mark_tree ((tree) lt);
     }
+}
+
+/* Retrieve the value of __builtin_stdout and return the result as a
+   function call to an inline function.  */
+tree
+c_builtin_stdout()
+{
+  tree call_expr, decl, id = maybe_get_identifier("__builtin_stdout");
+
+  if (!id || !(decl = IDENTIFIER_GLOBAL_VALUE(id)))
+    return NULL_TREE;
+
+  return build_function_call (decl, NULL_TREE);
 }
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	Wed Sep 20 16:19:53 2000
+++ egcs-CVS20000919/gcc/ginclude/stdio-opt.h	Wed Sep 20 16:34:55 2000
@@ -0,0 +1,41 @@
+/* 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 by
+   wrapping an inline function around it.  We use stdout e.g. when
+   transforming calls to printf into calls to fputs.  */
+
+static __inline__ FILE * __builtin_stdout(void) { return stdout; }
+
+#endif /* ! __GCC_STDIO_OPTIMIZE__ */
diff -rup orig/egcs-CVS20000919/gcc/tree.c egcs-CVS20000919/gcc/tree.c
--- orig/egcs-CVS20000919/gcc/tree.c	Tue Sep 19 14:14:40 2000
+++ egcs-CVS20000919/gcc/tree.c	Wed Sep 20 16:09:42 2000
@@ -250,6 +250,10 @@ static int next_type_uid = 1;
    used by the backend, e.g. builtins.c.  */
 void (*check_function_format_ptr) PARAMS ((int *, tree, tree, tree)) = 0;
 
+/* Pointer to function used for retrieving stdout from a front end.
+   This is used by the backend, e.g. builtins.c.  */
+tree (*c_builtin_stdout_ptr) PARAMS ((void)) = 0;
+
 /* Here is how primitive or already-canonicalized types' hash
    codes are made.  */
 #define TYPE_HASH(TYPE) ((unsigned long) (TYPE) & 0777777)
diff -rup orig/egcs-CVS20000919/gcc/tree.h egcs-CVS20000919/gcc/tree.h
--- orig/egcs-CVS20000919/gcc/tree.h	Tue Sep 19 14:14:42 2000
+++ egcs-CVS20000919/gcc/tree.h	Wed Sep 20 16:09:36 2000
@@ -2444,6 +2444,10 @@ extern tree builtin_function			PARAMS ((
 /* Pointer to function to check the format of printf, etc.  This is
    used by the backend, e.g. builtins.c.  */
 extern void (*check_function_format_ptr) PARAMS ((int *, tree, tree, tree));
+
+/* Pointer to function used for retrieving stdout from a front end.
+   This is used by the backend, e.g. builtins.c.  */
+extern tree (*c_builtin_stdout_ptr) PARAMS ((void));
 
 /* In tree.c */
 extern char *perm_calloc			PARAMS ((int, long));

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