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 RFC: stdio optimization [take 3]


[If anyone can offer the help I need on getting the C++ frontend to
expand the inline wrapper functions internally, I would really
appreciate it.  I can provide details if necessary.]



	Here is my latest version 3 of the stdio optimizations.  I've
made good progress eliminating the code for return values and adding
code for string[0]-> char/int parameter changes internally.  Thanks
Jeff for your pointers, I was able to eliminate most of the wrappers
in stdio-opt.h.

The inline functions I have to declare are now down to just the putc
macro wrapper and the fputc/fputs(stdout) wrappers (and I think I can
get rid of those last two also.)

One issue that drove me nuts was internal declarations for
fprintf/fputs/fputc which require FILE*.  I had originally thought
that faking FILE* with void* would work, and it did for the
__builtin_fprintf, etc, declarations.  But when creating internal
declarations for the non-builtin function names, I got conflicts with
the real decls.  Something like: "int (*)(void *, const char *, ...)"
conflicts with (or ambiguates) "int (*)(FILE *, const char *, ...)".

I tried solving this by having the internal decls omit the parameters,
and this worked for C and objC, but C++ complained that int (*)(...)
vs int (*)(anything) didn't match and it bombed out.

I ended up solving this by writing a hook which allows me to declare the
internal decls _after_ stdio.h defines FILE for me.  Its activated in
stdio-opt.h.  Essentially I first do "typedef FILE __gcc_builtin_FILE;"
This allows me to capture the definition of "FILE" even if its a macro.

Once I have this, I call a special builtin hook I wrote called
__builtin_initialize_FILE() which calls a gcc function to declare the
builtin decls for fprintf, etc, using __gcc_builtin_FILE* instead of
"FILE*".  This seems to work perfectly, note you don't have to run the
hook, just state it.  When gcc expands it at compile time the right
internal fprintf/fputs/fputc declarations are made and it emits no RTL
code.

The only glitch was that I had to wrap the call to
__builtin_initialize_FILE() in a function for syntax reasons.  In
order to have __builtin_initialize_FILE() expanded for all three
dialects of C, I had to make sure gcc actually emitted the wrapper
around it at the exact place its written in the code.  (I'm not sure
but it seemed like in some circumstances, c++ would wait until the end
of the module before emitting the code.  I guess to see whether it was
used or not.)  So I ended up making the wrapper function static.
Since the contents are empty, it won't add any/much space.

Its not too ugly, but if there is a better way to write a hook like
this, I'd love to know about it.

The patch, I'm happy to say, passes bootstrap and "make check". :-)

Now here are the current tasks:

1.  It still doesn't expand the inline wrapper functions for C++.  They
get emitted out of line and are called extern.  (Any help, C++ gurus?)

2.  I still need to make stdio-opt.h get included automatically.
Jeff's approach seems right to me, I can handle that.

3.  I think I can eliminate the need for the fputs/fputc stdout
wrapper functions using a similar trick to the FILE declaration.
I.e. get the address of stdout and pass it into the hook.  Then
dereference it and use it when transforming printf -> fputs/fputc.  In
fact, I can probably do a generic transformation of all printf ->
fprintf(stdout, ...) if this works.  I don't know if that last
transformation would improve speed or not.  I'll experiment with this
one and see.

4.  If the hook mechanism can be written better, I'd like to know.

5.  Run some benchmarks. :-)


Here's the patch:


diff -rup orig/egcs-CVS20000104/gcc/Makefile.in egcs-CVS20000104/gcc/Makefile.in
--- orig/egcs-CVS20000104/gcc/Makefile.in	Thu Dec 30 07:46:38 1999
+++ egcs-CVS20000104/gcc/Makefile.in	Tue Jan  4 16:18:06 2000
@@ -148,6 +148,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
@@ -1500,7 +1501,7 @@ expr.o : expr.c $(CONFIG_H) system.h $(R
 builtins.o : builtins.c $(CONFIG_H) system.h $(RTL_H) $(TREE_H) flags.h \
    function.h $(REGS_H) insn-flags.h insn-codes.h $(EXPR_H) insn-config.h \
    $(RECOG_H) output.h typeclass.h hard-reg-set.h toplev.h hard-reg-set.h \
-   except.h
+   except.h ggc.h
 calls.o : calls.c $(CONFIG_H) system.h $(RTL_H) $(TREE_H) flags.h $(EXPR_H) \
    insn-flags.h $(REGS_H) toplev.h output.h function.h
 expmed.o : expmed.c $(CONFIG_H) system.h $(RTL_H) $(TREE_H) flags.h  \
diff -rup orig/egcs-CVS20000104/gcc/builtins.c egcs-CVS20000104/gcc/builtins.c
--- orig/egcs-CVS20000104/gcc/builtins.c	Tue Jan  4 11:12:08 2000
+++ egcs-CVS20000104/gcc/builtins.c	Wed Jan  5 05:14:40 2000
@@ -38,6 +38,7 @@ Boston, MA 02111-1307, USA.  */
 #include "typeclass.h"
 #include "defaults.h"
 #include "toplev.h"
+#include "ggc.h"
 #include "tm_p.h"
 
 #define CALLED_AS_BUILT_IN(NODE) \
@@ -82,6 +83,15 @@ static rtx expand_builtin_strlen	PROTO((
 static rtx expand_builtin_alloca	PROTO((tree, rtx));
 static rtx expand_builtin_ffs		PROTO((tree, rtx, rtx));
 static rtx expand_builtin_frame_address	PROTO((tree));
+static rtx expand_builtin_fputc		PROTO((tree));
+static rtx expand_builtin_fputs		PROTO((tree, int));
+static rtx expand_builtin_printf	PROTO((tree, int));
+static rtx expand_builtin_fprintf	PROTO((tree, int));
+static rtx expand_builtin_sprintf	PROTO((tree, int));
+static void expand_builtin_initialize_FILE PROTO((void));
+static tree call_get_decl		PROTO((const char *));
+static void build_extern_function_decl	PROTO((tree *, const char *));
+static int is_valid_printf_arglist	PROTO((tree));
 static tree stabilize_va_list		PROTO((tree, int));
 
 /* Return the alignment in bits of EXP, a pointer valued expression.
@@ -1431,10 +1441,9 @@ expand_builtin_memcpy (arglist)
 /* Expand expression EXP, which is a call to the strcpy builtin.  Return 0
    if we failed the caller should emit a normal call.  */
 static rtx
-expand_builtin_strcpy (exp)
-     tree exp;
+expand_builtin_strcpy (arglist)
+     tree arglist;
 {
-  tree arglist = TREE_OPERAND (exp, 1);
   rtx result;
 
   if (arglist == 0
@@ -2238,6 +2247,505 @@ expand_builtin_ffs (arglist, target, sub
     abort ();
   return target;
 }
+
+static const char *const fputc_via_putc = "__gcc_builtin_fputc_via_putc";
+static const char *const printf_via_fputs = "__gcc_builtin_printf_via_fputs";
+static const char *const printf_via_fputc = "__gcc_builtin_printf_via_fputc";
+
+/* This function calls get_decl_p on the argument and returns the
+   result.  FNAME should be the literal name of an inline function for
+   which we want to find the FUNCTION_DECL. */
+static tree
+call_get_decl (fname)
+  const char *fname;
+{
+  tree id = maybe_get_identifier (fname), fndecl = NULL_TREE;
+  
+  /* Only call `get_decl_p' if it has been set by the language front end. */
+  if (get_decl_p)
+    {
+      /* If our inline replacement hasn't been defined for some
+	 reason, don't do the optimization.  */
+      if (!id)
+	{
+#ifdef TEST_STDIO_OPTS
+	  warning ("Could not find a definition for `%s'", fname);
+#endif
+	  return 0;
+	}
+      
+      fndecl = get_decl_p (id);
+#ifdef TEST_STDIO_OPTS
+      if (!fndecl)
+	warning ("Could not find the FUNCTION_DECL for `%s'", fname);
+#endif
+    }
+
+  return fndecl;
+}
+
+/* Create a FUNCTION_DECL to call an extern int function. */
+static void
+build_extern_function_decl (fn, name)
+  tree *fn;
+  const char *name;
+{
+  tree fntype;
+  
+  /* This was copied from except.c, I don't know if all this is
+     necessary in this context or not.  */
+  *fn = get_identifier (name);
+  push_obstacks_nochange ();
+  end_temporary_allocation ();
+  fntype = build_pointer_type (integer_type_node);
+  fntype = build_function_type (fntype, NULL_TREE);
+  *fn = build_decl (FUNCTION_DECL, *fn, fntype);
+  ggc_add_tree_root (fn, 1);
+  DECL_EXTERNAL (*fn) = 1;
+  TREE_PUBLIC (*fn) = 1;
+  DECL_ARTIFICIAL (*fn) = 1;
+  make_decl_rtl (*fn, NULL_PTR, 1);
+  assemble_external (*fn);
+  pop_obstacks ();
+}
+
+/* If we are not optimizing for size, we attempt to transform fputc()
+   into the expansion of the putc() macro which should be contained in
+   an inline function defined for us and named in `fputc_via_putc'. */
+static rtx
+expand_builtin_fputc (arglist)
+  tree arglist;
+{
+  tree call_expr;
+  static tree fn;
+
+  /* If -Os or -O0, then don't do this. */
+  if (optimize_size || !optimize)
+    return 0;
+
+  /* Try to lookup the replacement function's FUNCTION_DECL.  If we
+     don't find it, return zero to indicate we failed to optimize.
+     Once we've found it, don't do the lookup again. */
+  if (!fn && ! (fn = call_get_decl (fputc_via_putc)))
+    return 0;
+  
+  /* Verify the arguments in the original call to fputc. */
+  if (arglist == 0
+      || (TREE_CODE (TREE_TYPE (TREE_VALUE (arglist))) != INTEGER_TYPE)
+      || TREE_CHAIN (arglist) == 0
+      || (TREE_CODE (TREE_TYPE (TREE_VALUE (TREE_CHAIN (arglist))))
+	  != POINTER_TYPE))
+    return 0;
+  
+#ifdef TEST_STDIO_OPTS
+  warning ("Converted fputc(char, FILE*) -> putc(char, FILE*)");
+#endif
+  
+  call_expr = build1 (ADDR_EXPR, build_pointer_type (TREE_TYPE (fn)), fn);
+  call_expr = build (CALL_EXPR, TREE_TYPE (TREE_TYPE (fn)),
+		     call_expr, arglist, NULL_TREE);
+  TREE_SIDE_EFFECTS (call_expr) = 1;
+  return expand_expr (call_expr, NULL_RTX, VOIDmode, 0);
+}
+
+/* If the string passed to fputs is a constant and is one character
+   long, we attempt to transform this call into __builtin_fputc(). */
+static rtx
+expand_builtin_fputs (arglist, ignore)
+  tree arglist;
+  int ignore;
+{
+  tree call_expr, len, stripped_string, newparm;
+  static tree fn;
+
+  /* If the return value is used, don't do the transformation. */
+  if (!ignore)
+    return 0;
+
+  /* Try to lookup the replacement function's FUNCTION_DECL.  If we
+     don't find it, return zero to indicate we failed to optimize.
+     Once we've found it, don't do the lookup again. */
+  if (!fn && ! (fn = call_get_decl ("__builtin_fputc")))
+    return 0;
+
+  /* Verify the arguments in the original call to fputs. */
+  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;
+
+  /* Get the length of the string passed to fputs. */
+  len = c_strlen (TREE_VALUE (arglist));
+  
+  /* If the length != 1, punt. */
+  if (len == 0 || TREE_INT_CST_LOW (len) != 1)
+    return 0;
+
+  stripped_string = TREE_VALUE (arglist);
+  STRIP_NOPS (stripped_string);
+  if (stripped_string && TREE_CODE (stripped_string) == ADDR_EXPR)
+    stripped_string = TREE_OPERAND (stripped_string, 0);
+
+  newparm = build_int_2 (TREE_STRING_POINTER (stripped_string)[0], 0);
+  TREE_VALUE (arglist) = newparm;
+
+#ifdef TEST_STDIO_OPTS
+  warning ("Converted fputs(one-char-string, FILE*) -> fputc(char, FILE*)");
+#endif
+
+  call_expr = build1 (ADDR_EXPR, build_pointer_type (TREE_TYPE (fn)), fn);
+  call_expr = build (CALL_EXPR, TREE_TYPE (TREE_TYPE (fn)),
+		     call_expr, arglist, NULL_TREE);
+  TREE_SIDE_EFFECTS (call_expr) = 1;
+  return expand_expr (call_expr, NULL_RTX, VOIDmode, 0);
+}
+
+/* Check an arglist to *printf for problems.  The arglist should start
+   at the format specifier, with the remaining arguments immediately
+   following it. */
+static int
+is_valid_printf_arglist (arglist)
+  tree arglist;
+{
+  /* Save this value so we can restore it later. */
+  int SAVE_check_diagnostics_silently = check_diagnostics_silently;
+
+  /* If we can't check the format, be safe and return false. */
+  if (!check_function_format_p)
+    return 0;
+  
+  /* Don't be noisy when calling `check_function_format_p'. */
+  check_diagnostics_silently = 1;
+  diagnostic_occurred = 0;
+
+  /* Check to make sure there are no format specifier errors. */
+  check_function_format_p (maybe_get_identifier("printf"), NULL_TREE, arglist);
+
+  /* Restore the value of `check_diagnostics_silently'. */
+  check_diagnostics_silently = SAVE_check_diagnostics_silently;
+
+  /* If calling `check_function_format_p' produces a warning, we
+     return false, otherwise we return true. */
+  return ! diagnostic_occurred;
+}
+
+/* If the string passed to printf can be resolved at compile time,
+   then pass it to fputs/fputc/putc.
+
+   Also handle these format specifiers:
+   "%s\n" -> puts
+   "%s" -> fputs
+   "%c" -> fputc/putc.  */
+static rtx
+expand_builtin_printf (arglist, ignore)
+  tree arglist;
+  int ignore;
+{
+  static tree fn_s, fn_c, fn_p;
+  tree call_expr, fn;
+  tree format_arg, stripped_string;
+
+  /* If the return value is used, don't do the transformation. */
+  if (!ignore)
+    return 0;
+
+  /* Try to lookup the replacement function's FUNCTION_DECL.  If we
+     don't find it, return zero to indicate we failed to optimize.
+     Once we've found it, don't do the lookup again. */
+  if (!fn_s && ! (fn_s = call_get_decl (printf_via_fputs)))
+    return 0;
+  if (!fn_c && ! (fn_c = call_get_decl (printf_via_fputc)))
+    return 0;
+  /* Static lookup, only done once. */
+  if (fn_p == NULL_TREE)
+    build_extern_function_decl (&fn_p, "puts");
+
+  /* Verify the required arguments in the original call to printf. */
+  if (arglist == 0
+      || (TREE_CODE (TREE_TYPE (TREE_VALUE (arglist))) != POINTER_TYPE))
+    return 0;
+  
+  /* Check the specifier vs. the parameters. */
+  if (!is_valid_printf_arglist (arglist))
+    return 0;
+  
+  format_arg = TREE_VALUE (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 was "%s\n", call puts(arg2). */
+  if (strcmp (TREE_STRING_POINTER (stripped_string), "%s\n") == 0)
+    {
+      arglist = TREE_CHAIN (arglist);
+      fn = fn_p;
+#ifdef TEST_STDIO_OPTS
+      warning ("Converted printf(\"%%s\\n\", string) -> puts(string)");
+#endif
+    }
+  /* If -O0, then don't do this.  All the remaining transformations
+     require inline replacements. */
+  else if (!optimize)
+    return 0;
+  /* If the format specifier was "%s", call __builtin_fputs (arg2, stdout). */
+  else if (strcmp (TREE_STRING_POINTER (stripped_string), "%s") == 0)
+    {
+      arglist = TREE_CHAIN (arglist);
+      fn = fn_s;
+#ifdef TEST_STDIO_OPTS
+      warning ("Converted printf(\"%%s\", string) -> fputs(string, stdout)");
+#endif
+    }
+  /* If the format specifier was "%c", call __builtin_fputc (arg2, stdout). */
+  else if (strcmp (TREE_STRING_POINTER (stripped_string), "%c") == 0)
+    {
+      arglist = TREE_CHAIN (arglist);
+      fn = fn_c;
+#ifdef TEST_STDIO_OPTS
+      warning ("Converted printf(\"%%c\", char) -> fputc(char, stdout)");
+#endif
+    }
+  else
+    {
+      /* We can't handle anything else with % args or %% right now. */
+      if (strchr (TREE_STRING_POINTER (stripped_string), '%'))
+	return 0;
+      
+      /* If the resulting constant string has a length of 1, call fputc,
+	 otherwise call fputs. */
+      if (strlen (TREE_STRING_POINTER (stripped_string)) == 1)
+        {
+	  /* Given printf(string), convert string[0] to an int and
+             pass that to the replacement function. */
+	  tree newparm =
+	    build_int_2 (TREE_STRING_POINTER (stripped_string)[0], 0);
+	  
+	  TREE_VALUE (arglist) = newparm;
+	  
+	  fn = fn_c;
+#ifdef TEST_STDIO_OPTS
+	  warning ("Converted printf(one-char-string) -> fputc(char, stdout)");
+#endif
+        }
+      else
+        {
+	  fn = fn_s;
+#ifdef TEST_STDIO_OPTS
+	  warning ("Converted printf(string) -> fputs(string, stdout)");
+#endif
+        }
+    }
+  
+  call_expr = build1 (ADDR_EXPR, build_pointer_type (TREE_TYPE (fn)), fn);
+  call_expr = build (CALL_EXPR, TREE_TYPE (TREE_TYPE (fn)),
+		     call_expr, arglist, NULL_TREE);
+  TREE_SIDE_EFFECTS (call_expr) = 1;
+  return expand_expr (call_expr, NULL_RTX, VOIDmode, 0);
+}
+
+/* If the string passed to fprintf can be resolved at compile time,
+   then pass it to fputs/fputc/putc.
+
+   Also handle these format specifiers:
+   "%s" -> fputs
+   "%c" -> fputc/putc.  */
+static rtx
+expand_builtin_fprintf (arglist, ignore)
+  tree arglist;
+  int ignore;
+{
+  static tree fn_s, fn_c;
+  tree call_expr, fn;
+  tree format_arg, stripped_string;
+
+  /* If the return value is used, don't do the transformation. */
+  if (!ignore)
+    return 0;
+
+  /* Try to lookup the replacement function's FUNCTION_DECL.  If we
+     don't find it, return zero to indicate we failed to optimize.
+     Once we've found it, don't do the lookup again. */
+  if (!fn_s && ! (fn_s = call_get_decl ("__builtin_fputs")))
+    return 0;
+  if (!fn_c && ! (fn_c = call_get_decl ("__builtin_fputc")))
+    return 0;
+
+  /* Verify the required arguments in the original call to fprintf. */
+  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 was "%s", call __builtin_fputs (arg3, arg1). */
+  if (strcmp (TREE_STRING_POINTER (stripped_string), "%s") == 0)
+    {
+      tree newarglist;
+      
+      newarglist = TREE_CHAIN (TREE_CHAIN (arglist));
+      TREE_CHAIN (newarglist) = arglist;
+      TREE_CHAIN (TREE_CHAIN (newarglist)) = 0;
+      arglist = newarglist;
+
+      fn = fn_s;
+#ifdef TEST_STDIO_OPTS
+      warning ("Converted fprintf(FILE*, \"%%s\", string) -> fputs(string, FILE*)");
+#endif
+    }
+  /* If the format specifier was "%c", call __builtin_fputc (arg3, arg1). */
+  else if (strcmp (TREE_STRING_POINTER (stripped_string), "%c") == 0)
+    {
+      tree newarglist;
+      
+      newarglist = TREE_CHAIN (TREE_CHAIN (arglist));
+      TREE_CHAIN (newarglist) = arglist;
+      TREE_CHAIN (TREE_CHAIN (newarglist)) = 0;
+      arglist = newarglist;
+
+      fn = fn_c;
+#ifdef TEST_STDIO_OPTS
+      warning ("Converted fprintf(FILE*, \"%%c\", char) -> fputc(char, FILE*)");
+#endif
+    }
+  else
+    {
+      tree newarglist;
+      
+      /* We can't handle anything else with % args or %% right now. */
+      if (strchr (TREE_STRING_POINTER (stripped_string), '%'))
+	return 0;
+      
+      /* The arguments of fputc/fputs should be the first and second
+         args of fprintf reversed. */
+      newarglist = TREE_CHAIN (arglist);
+      TREE_CHAIN (newarglist) = arglist;
+      TREE_CHAIN (TREE_CHAIN (newarglist)) = 0;
+      arglist = newarglist;
+
+      /* If the resulting constant string has a length of 1, call fputc,
+	 otherwise call fputs. */
+      if (strlen (TREE_STRING_POINTER (stripped_string)) == 1)
+        {
+	  tree newparm =
+	    build_int_2 (TREE_STRING_POINTER (stripped_string)[0], 0);
+	  TREE_VALUE (arglist) = newparm;
+
+	  fn = fn_c;
+
+#ifdef TEST_STDIO_OPTS
+	  warning ("Converted fprintf(FILE*, one-char-string) -> fputc(char, FILE*)");
+#endif
+        }
+      else
+        {
+	  fn = fn_s;
+#ifdef TEST_STDIO_OPTS
+	  warning ("Converted fprintf(FILE*, string) -> fputs(string, FILE*)");
+#endif
+        }
+    }
+  
+  call_expr = build1 (ADDR_EXPR, build_pointer_type (TREE_TYPE (fn)), fn);
+  call_expr = build (CALL_EXPR, TREE_TYPE (TREE_TYPE (fn)),
+		     call_expr, arglist, NULL_TREE);
+  TREE_SIDE_EFFECTS (call_expr) = 1;
+  return expand_expr (call_expr, NULL_RTX, VOIDmode, 0);
+}
+
+/* If the string passed to sprintf can be resolved at compile time,
+   then pass it to memcpy.
+
+   Also handle these format specifiers:
+   "%s"  */
+static rtx
+expand_builtin_sprintf (arglist, ignore)
+  tree arglist;
+  int ignore;
+{
+  static tree fn;
+  tree call_expr;
+  tree format_arg, stripped_string;
+
+  /* If the return value is used, don't do the transformation. */
+  if (!ignore)
+    return 0;
+
+  /* Try to lookup the replacement function's FUNCTION_DECL.  If we
+     don't find it, return zero to indicate we failed to optimize.
+     Once we've found it, don't do the lookup again. */
+  if (!fn && ! (fn = call_get_decl ("__builtin_strcpy")))
+    return 0;
+
+  /* Verify the required arguments in the original call to sprintf. */
+  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 was "%s", call __builtin_strcpy (arg1, arg3). */
+  if (strcmp (TREE_STRING_POINTER (stripped_string), "%s") == 0)
+    {
+      TREE_CHAIN (arglist) = TREE_CHAIN (TREE_CHAIN (arglist));
+
+#ifdef TEST_STDIO_OPTS
+      warning ("Converted sprintf(buf, \"%%s\", string) -> __builtin_strcpy(buf, string)");
+#endif
+    }
+  else
+    {
+      /* We can't handle anything else with % args or %% right now. */
+      if (strchr (TREE_STRING_POINTER (stripped_string), '%'))
+	return 0;
+  
+#ifdef TEST_STDIO_OPTS
+      warning ("Converted sprintf(buf, string) -> __builtin_strcpy(buf, string)");
+#endif
+    }
+
+  call_expr = build1 (ADDR_EXPR, build_pointer_type (TREE_TYPE (fn)), fn);
+  call_expr = build (CALL_EXPR, TREE_TYPE (TREE_TYPE (fn)),
+		     call_expr, arglist, NULL_TREE);
+  TREE_SIDE_EFFECTS (call_expr) = 1;
+  return expand_expr (call_expr, NULL_RTX, VOIDmode, 0);
+}
+
+static void
+expand_builtin_initialize_FILE ()
+{
+#ifdef TEST_STDIO_OPTS
+  fprintf (stderr, "In expand_builtin_initialize_FILE <%p>\n",
+	   initialize_file_nodes_p);
+#endif
+
+  /* This function should never be called unless the following is
+     properly initialized. */
+  initialize_file_nodes_p();
+}
 
 /* Expand an expression EXP that calls a built-in function,
    with result going to TARGET if that's convenient
@@ -2269,7 +2777,10 @@ expand_builtin (exp, target, subtarget, 
 	  || fcode == BUILT_IN_FSQRT || fcode == BUILT_IN_MEMSET
 	  || fcode == BUILT_IN_MEMCPY || fcode == BUILT_IN_MEMCMP
 	  || fcode == BUILT_IN_STRLEN || fcode == BUILT_IN_STRCPY
-	  || fcode == BUILT_IN_STRCMP || fcode == BUILT_IN_FFS))
+	  || fcode == BUILT_IN_STRCMP || fcode == BUILT_IN_FFS
+	  || fcode == BUILT_IN_FPUTC || fcode == BUILT_IN_FPUTS
+	  || fcode == BUILT_IN_PRINTF || fcode == BUILT_IN_FPRINTF
+	  || fcode == BUILT_IN_SPRINTF))
     return expand_call (exp, target, ignore);
 
   switch (fcode)
@@ -2388,7 +2899,7 @@ expand_builtin (exp, target, subtarget, 
       break;
 
     case BUILT_IN_STRCPY:
-      target = expand_builtin_strcpy (exp);
+      target = expand_builtin_strcpy (arglist);
       if (target)
 	return target;
       break;
@@ -2473,6 +2984,41 @@ expand_builtin (exp, target, subtarget, 
 	error ("__builtin_trap not supported by this target");
       emit_barrier ();
       return const0_rtx;
+
+    case BUILT_IN_FPUTC:
+      target = expand_builtin_fputc (arglist);
+      if (target)
+	return target;
+      break;
+
+    case BUILT_IN_FPUTS:
+      target = expand_builtin_fputs (arglist, ignore);
+      if (target)
+	return target;
+      break;
+
+    case BUILT_IN_PRINTF:
+      target = expand_builtin_printf (arglist, ignore);
+      if (target)
+	return target;
+      break;
+      
+    case BUILT_IN_FPRINTF:
+      target = expand_builtin_fprintf (arglist, ignore);
+      if (target)
+	return target;
+      break;
+      
+    case BUILT_IN_SPRINTF:
+      target = expand_builtin_sprintf (arglist, ignore);
+      if (target)
+	return target;
+      break;
+
+    case BUILT_IN_INITIALIZE_FILE:
+      expand_builtin_initialize_FILE ();
+      return const0_rtx;
+      break;
 
       /* Various hooks for the DWARF 2 __throw routine.  */
     case BUILT_IN_UNWIND_INIT:
diff -rup orig/egcs-CVS20000104/gcc/c-common.c egcs-CVS20000104/gcc/c-common.c
--- orig/egcs-CVS20000104/gcc/c-common.c	Tue Jan  4 07:46:42 2000
+++ egcs-CVS20000104/gcc/c-common.c	Wed Jan  5 05:16:14 2000
@@ -1314,10 +1314,18 @@ init_function_format_info ()
 			  printf_format_type, 2, 0);
   record_function_format (get_identifier ("strftime"), NULL_TREE,
 			  strftime_format_type, 3, 0);
+  record_function_format (get_identifier ("__builtin_printf"), NULL_TREE,
+			  printf_format_type, 1, 2);
+  record_function_format (get_identifier ("__builtin_fprintf"), NULL_TREE,
+			  printf_format_type, 2, 3);
+  record_function_format (get_identifier ("__builtin_sprintf"), NULL_TREE,
+			  printf_format_type, 2, 3);
 
   record_international_format (get_identifier ("gettext"), NULL_TREE, 1);
   record_international_format (get_identifier ("dgettext"), NULL_TREE, 2);
   record_international_format (get_identifier ("dcgettext"), NULL_TREE, 2);
+
+  check_function_format_p = check_function_format;
 }
 
 /* Record information for argument format checking.  FUNCTION_IDENT is
@@ -3508,6 +3516,7 @@ c_common_nodes_and_builtins (cplus_mode,
     int cplus_mode, no_builtins, no_nonansi_builtins;
 {
   tree temp;
+  tree printf_ftype, sprintf_ftype;
   tree memcpy_ftype, memset_ftype, strlen_ftype;
   tree endlink, int_endlink, double_endlink, unsigned_endlink;
   tree sizetype_endlink;
@@ -3632,6 +3641,20 @@ c_common_nodes_and_builtins (cplus_mode,
 							    sizetype,
 							    endlink))));
 
+  /* Prototype for printf. */
+  printf_ftype
+    = build_function_type (integer_type_node,
+			   tree_cons (NULL_TREE, const_string_type_node,
+				      NULL_TREE));
+
+  /* Prototype for sprintf. */
+  sprintf_ftype
+    = build_function_type (integer_type_node,
+			   tree_cons (NULL_TREE, string_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);
 
@@ -3778,6 +3801,12 @@ c_common_nodes_and_builtins (cplus_mode,
 		    BUILT_IN_COS, BUILT_IN_NORMAL, "cos");
   builtin_function ("__builtin_cosl", ldouble_ftype_ldouble,
 		    BUILT_IN_COS, BUILT_IN_NORMAL, "cosl");
+  builtin_function ("__builtin_printf", printf_ftype, 
+		    BUILT_IN_PRINTF, BUILT_IN_FRONTEND, "printf");
+  builtin_function ("__builtin_sprintf", sprintf_ftype, 
+		    BUILT_IN_SPRINTF, BUILT_IN_FRONTEND, "sprintf");
+  builtin_function ("__builtin_initialize_FILE", void_ftype,
+		    BUILT_IN_INITIALIZE_FILE, BUILT_IN_NORMAL, NULL_PTR);
 
   if (! no_builtins)
     {
@@ -3821,6 +3850,10 @@ c_common_nodes_and_builtins (cplus_mode,
 			BUILT_IN_NORMAL, NULL_PTR);
       builtin_function ("cosl", ldouble_ftype_ldouble, BUILT_IN_COS,
 			BUILT_IN_NORMAL, NULL_PTR);
+      builtin_function ("printf", printf_ftype, 
+			BUILT_IN_PRINTF, BUILT_IN_FRONTEND, NULL_PTR);
+      builtin_function ("sprintf", sprintf_ftype, 
+			BUILT_IN_SPRINTF, BUILT_IN_FRONTEND, NULL_PTR);
 
       /* Declare these functions volatile
 	 to avoid spurious "control drops through" warnings.  */
@@ -3871,6 +3904,78 @@ c_common_nodes_and_builtins (cplus_mode,
   /* ??? Perhaps there's a better place to do this.  But it is related
      to __builtin_va_arg, so it isn't that off-the-wall.  */
   lang_type_promotes_to = simple_type_promotes_to;
+}
+
+#ifndef GCC_FILE_TYPE
+#define GCC_FILE_TYPE "__gcc_builtin_FILE"
+#endif
+
+/* Like c_common_nodes_and_builtins, but declare nodes and builtins
+   requiring a type `FILE'. */
+void
+c_common_file_nodes_and_builtins (no_builtins)
+     int no_builtins;
+{
+  tree fputc_ftype, fputs_ftype, fprintf_ftype;
+  tree endlink = void_list_node;
+
+#ifdef TEST_STDIO_OPTS
+  warning ("Initializing FILE stuff");
+#endif
+  
+  /* No front end should call this function without setting the following. */
+  if (!get_decl_p)
+    abort();
+  
+  /* Get the node for a FILE. */
+  file_type_node =
+    TREE_TYPE (get_decl_p (maybe_get_identifier (GCC_FILE_TYPE)));
+
+  /* Get the node for a FILE*. */
+  file_ptr_type_node = build_pointer_type (file_type_node);
+  
+  /* Prototype for builtin_fputc. */
+  fputc_ftype
+    = build_function_type (integer_type_node,
+			   tree_cons (NULL_TREE, integer_type_node,
+				      tree_cons (NULL_TREE,
+						 file_ptr_type_node,
+						 endlink)));
+
+  /* Prototype for builtin_fputs. */
+  fputs_ftype
+    = build_function_type (integer_type_node,
+			   tree_cons (NULL_TREE, const_string_type_node,
+				      tree_cons (NULL_TREE,
+						 file_ptr_type_node,
+						 endlink)));
+
+  /* Prototype for fprintf. */
+  fprintf_ftype
+    = build_function_type (integer_type_node,
+			   tree_cons (NULL_TREE, file_ptr_type_node,
+				      tree_cons (NULL_TREE,
+						 const_string_type_node,
+						 NULL_TREE)));
+
+  /* We're really inside __builtin_initialize_FILE(), so declare these
+     at the top level. */
+  builtin_function_top_level ("__builtin_fputc", fputc_ftype, 
+			      BUILT_IN_FPUTC, BUILT_IN_FRONTEND, "fputc");
+  builtin_function_top_level ("__builtin_fputs", fputs_ftype, 
+			      BUILT_IN_FPUTS, BUILT_IN_FRONTEND, "fputs");
+  builtin_function_top_level ("__builtin_fprintf", fprintf_ftype,
+			      BUILT_IN_FPRINTF, BUILT_IN_FRONTEND, "fprintf");
+
+  if (! no_builtins)
+    {
+      builtin_function_top_level ("fputc", fputc_ftype, BUILT_IN_FPUTC,
+				  BUILT_IN_FRONTEND, NULL_PTR);
+      builtin_function_top_level ("fputs", fputs_ftype, BUILT_IN_FPUTS,
+				  BUILT_IN_FRONTEND, NULL_PTR);
+      builtin_function_top_level ("fprintf", fprintf_ftype, BUILT_IN_FPRINTF,
+				  BUILT_IN_FRONTEND, NULL_PTR);
+    }
 }
 
 tree
diff -rup orig/egcs-CVS20000104/gcc/c-common.h egcs-CVS20000104/gcc/c-common.h
--- orig/egcs-CVS20000104/gcc/c-common.h	Sun Oct 31 20:26:54 1999
+++ egcs-CVS20000104/gcc/c-common.h	Wed Jan  5 05:15:51 2000
@@ -45,6 +45,9 @@ enum c_tree_index
     CTI_INT_FTYPE_INT,
     CTI_PTR_FTYPE_SIZETYPE,
     
+    CTI_FILE_TYPE,
+    CTI_FILE_PTR_TYPE,
+
     CTI_MAX
 };
 
@@ -73,6 +76,9 @@ extern tree c_global_trees[CTI_MAX];
 #define int_ftype_int			c_global_trees[CTI_INT_FTYPE_INT]
 #define ptr_ftype_sizetype		c_global_trees[CTI_PTR_FTYPE_SIZETYPE]
 
+#define file_type_node			c_global_trees[CTI_FILE_TYPE]
+#define file_ptr_type_node		c_global_trees[CTI_FILE_PTR_TYPE]
+
 extern void declare_function_name		PROTO((void));
 extern void decl_attributes			PROTO((tree, tree, tree));
 extern void init_function_format_info		PROTO((void));
@@ -116,6 +122,7 @@ extern tree type_for_size			PROTO((unsig
 /* Build tree nodes and builtin functions common to both C and C++ language
    frontends.  */
 extern void c_common_nodes_and_builtins		PROTO((int, int, int));
+extern void c_common_file_nodes_and_builtins	PROTO((int));
 
 extern tree build_va_arg			PROTO((tree, tree));
 
diff -rup orig/egcs-CVS20000104/gcc/c-decl.c egcs-CVS20000104/gcc/c-decl.c
--- orig/egcs-CVS20000104/gcc/c-decl.c	Sat Dec  4 07:41:14 1999
+++ egcs-CVS20000104/gcc/c-decl.c	Wed Jan  5 05:16:31 2000
@@ -291,6 +291,7 @@ static tree grokdeclarator		PROTO((tree,
 					       int));
 static tree grokparms			PROTO((tree, int));
 static void layout_array_type		PROTO((tree));
+static void initialize_file_nodes	PROTO((void));
 
 /* C-specific option variables.  */
 
@@ -3047,6 +3048,7 @@ init_decl_processing ()
     = TREE_TYPE (IDENTIFIER_GLOBAL_VALUE (get_identifier (PTRDIFF_TYPE)));
 
   c_common_nodes_and_builtins (0, flag_no_builtin, flag_no_nonansi_builtin);
+  initialize_file_nodes_p = initialize_file_nodes;
 
   endlink = void_list_node;
   ptr_ftype_void = build_function_type (ptr_type_node, endlink);
@@ -3153,6 +3155,24 @@ builtin_function (name, type, function_c
 
   return decl;
 }
+
+/* Like builtin_function, except that it ensures we are at the top level. */
+tree
+builtin_function_top_level (name, type, function_code, class, library_name)
+     const char *name;
+     tree type;
+     int function_code;
+     enum built_in_class class;
+     const char *library_name;
+{
+  register tree t;
+  register struct binding_level *b = current_binding_level;
+
+  current_binding_level = global_binding_level;
+  t = builtin_function (name, type, function_code, class, library_name);
+  current_binding_level = b;
+  return t;
+}
 
 /* Called when a declaration is seen that contains no names to declare.
    If its type is a reference to a structure, union or enum inherited
@@ -6939,4 +6959,10 @@ lang_mark_tree (t)
     }
   else if (TYPE_P (t) && TYPE_LANG_SPECIFIC (t))
     ggc_mark (TYPE_LANG_SPECIFIC (t));
+}
+
+static void
+initialize_file_nodes()
+{
+  c_common_file_nodes_and_builtins (flag_no_builtin);
 }
diff -rup orig/egcs-CVS20000104/gcc/c-lex.c egcs-CVS20000104/gcc/c-lex.c
--- orig/egcs-CVS20000104/gcc/c-lex.c	Thu Dec  2 07:35:58 1999
+++ egcs-CVS20000104/gcc/c-lex.c	Tue Jan  4 16:18:06 2000
@@ -168,6 +168,7 @@ static int readescape			PROTO((int *));
 static void parse_float			PROTO((PTR));
 static void extend_token_buffer_to	PROTO((int));
 static int read_line_number		PROTO((int *));
+static tree get_decl			PROTO((tree));
 
 /* Do not insert generated code into the source, instead, include it.
    This allows us to build gcc automatically even for targets that
@@ -257,6 +258,8 @@ init_parse (filename)
   init_lex ();
   init_pragma ();
 
+  get_decl_p = get_decl;
+  
   return filename;
 }
 
@@ -2453,4 +2456,11 @@ set_yydebug (value)
 #else
   warning ("YYDEBUG not defined.");
 #endif
+}
+
+static tree
+get_decl (identifier)
+  tree identifier;
+{
+  return IDENTIFIER_GLOBAL_VALUE (identifier);
 }
diff -rup orig/egcs-CVS20000104/gcc/cp/decl.c egcs-CVS20000104/gcc/cp/decl.c
--- orig/egcs-CVS20000104/gcc/cp/decl.c	Tue Jan  4 07:47:02 2000
+++ egcs-CVS20000104/gcc/cp/decl.c	Wed Jan  5 05:16:40 2000
@@ -182,6 +182,7 @@ static tree get_atexit_node PROTO((void)
 static tree get_dso_handle_node PROTO((void));
 static tree start_cleanup_fn PROTO((void));
 static void end_cleanup_fn PROTO((void));
+static void initialize_file_nodes	PROTO((void));
 
 #if defined (DEBUG_CP_BINDING_LEVELS)
 static void indent PROTO((void));
@@ -6189,6 +6190,8 @@ init_decl_processing ()
     = build_pointer_type (build_qualified_type (void_type_node,
 						TYPE_QUAL_CONST));
   c_common_nodes_and_builtins (1, flag_no_builtin, flag_no_nonansi_builtin);
+  initialize_file_nodes_p = initialize_file_nodes;
+
   lang_type_promotes_to = convert_type_from_ellipsis;
 
   void_ftype_ptr
@@ -6437,6 +6440,24 @@ builtin_function (name, type, code, clas
   DECL_FUNCTION_CODE (decl) = code;
   return decl;
 }
+
+/* Like builtin_function, except that it ensures we are at the top level. */
+tree
+builtin_function_top_level (name, type, code, class, libname)
+     const char *name;
+     tree type;
+     int code;
+     enum built_in_class class;
+     const char *libname;
+{
+  tree decl = define_function (name, type,
+			       (void (*) PROTO((tree)))pushdecl_top_level,
+			       libname);
+  DECL_BUILT_IN_CLASS (decl) = class;
+  DECL_FUNCTION_CODE (decl) = code;
+
+  return decl;
+}
 
 /* When we call finish_struct for an anonymous union, we create
    default copy constructors and such.  But, an anonymous union
@@ -14538,4 +14559,10 @@ lang_mark_tree (t)
 	   TYPE_LANG_SPECIFIC is really just a tree.  */
 	ggc_mark_tree ((tree) lt);
     }
+}
+
+static void
+initialize_file_nodes()
+{
+  c_common_file_nodes_and_builtins (flag_no_builtin);
 }
diff -rup orig/egcs-CVS20000104/gcc/cp/lex.c egcs-CVS20000104/gcc/cp/lex.c
--- orig/egcs-CVS20000104/gcc/cp/lex.c	Wed Dec 15 22:54:13 1999
+++ egcs-CVS20000104/gcc/cp/lex.c	Tue Jan  4 16:18:06 2000
@@ -92,6 +92,7 @@ static int read_line_number PROTO((int *
 static int token_getch PROTO ((void));
 static void token_put_back PROTO ((int));
 static void mark_impl_file_chain PROTO ((void *));
+static tree get_decl PROTO ((tree));
 
 /* Given a file name X, return the nondirectory portion.
    Keep in mind that X can be computed more than once.  */
@@ -928,6 +929,9 @@ init_parse (filename)
   ggc_add_tree_root (&filename_times, 1);
   ggc_add_root (&impl_file_chain, 1, sizeof (impl_file_chain),
 		mark_impl_file_chain);
+
+  get_decl_p = get_decl;
+  
   return filename;
 }
 
@@ -4889,4 +4893,11 @@ cp_type_qual_from_rid (rid)
 
   my_friendly_abort (0);
   return TYPE_UNQUALIFIED;
+}
+
+static tree
+get_decl (identifier)
+  tree identifier;
+{
+  return IDENTIFIER_GLOBAL_VALUE (identifier);
 }
diff -rup orig/egcs-CVS20000104/gcc/diagnostic.c egcs-CVS20000104/gcc/diagnostic.c
--- orig/egcs-CVS20000104/gcc/diagnostic.c	Mon Dec 27 11:50:46 1999
+++ egcs-CVS20000104/gcc/diagnostic.c	Tue Jan  4 16:18:07 2000
@@ -478,6 +478,12 @@ int
 count_error (warningp)
      int warningp;
 {
+  if (check_diagnostics_silently)
+    {
+      diagnostic_occurred = 1;
+      return 0;
+    }
+
   if (warningp && inhibit_warnings)
     return 0;
 
diff -rup orig/egcs-CVS20000104/gcc/ginclude/stdio-opt.h egcs-CVS20000104/gcc/ginclude/stdio-opt.h
--- orig/egcs-CVS20000104/gcc/ginclude/stdio-opt.h	Wed Jan  5 05:18:57 2000
+++ egcs-CVS20000104/gcc/ginclude/stdio-opt.h	Tue Jan  4 16:18:07 2000
@@ -0,0 +1,87 @@
+/* Copyright (C) 1999 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 provide inline replacements for
+   certain stdio functions when we detect they are optimizable.  We
+   need the definition of stdout when replacing printf with fputs or
+   fputc.  We need to capture the macro definition of putc to use when
+   replacing fputc.  We also need to capture the definition of FILE,
+   which may be a macro, in a typedef so that gcc can make use of it
+   for internal declarations.  */
+
+#ifndef __GCC_STDIO_OPTIMIZE__
+#define __GCC_STDIO_OPTIMIZE__
+
+#include <stdio.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+/* We capture the definition of FILE here in case stdio.h defined it
+   as a macro.  Internally we can use __gcc_builtin_FILE to declare
+   functions, like fprintf, fputs and fputc, which rely on FILE. */
+typedef FILE __gcc_builtin_FILE;
+
+static void
+__gcc_builtin_initialize_FILE (void)
+{
+  /* This function is a hook to call into gcc and create internal
+     declarations for anything relying on the definition of FILE. */
+  __builtin_initialize_FILE ();
+}
+
+#if ! defined(__OPTIMIZE_SIZE__) && defined (putc)
+/* We convert fputc -> putc when !optimize_size.  Only do this if putc
+   is a macro. */
+extern __inline__ int
+__gcc_builtin_fputc_via_putc (int c, FILE *stream)
+{
+  return putc (c, stream);
+}
+#endif /* ! __OPTIMIZE_SIZE__ && putc */
+
+/* We use this to transform `printf(string)' or `printf("%s", string)'.
+   We need this as an inline to get the definition of stdout. */
+extern __inline__ int
+__gcc_builtin_printf_via_fputs (const char *string)
+{
+  return __builtin_fputs (string, stdout);
+}
+
+/* We use this to transform `printf("%c", char)' at compile time.
+   We need this as an inline to get the definition of stdout. */
+extern __inline__ int
+__gcc_builtin_printf_via_fputc (int c)
+{
+  return __builtin_fputc (c, stdout);
+}
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* ! __GCC_STDIO_OPTIMIZE__ */
diff -rup orig/egcs-CVS20000104/gcc/toplev.c egcs-CVS20000104/gcc/toplev.c
--- orig/egcs-CVS20000104/gcc/toplev.c	Fri Dec 24 15:46:36 1999
+++ egcs-CVS20000104/gcc/toplev.c	Tue Jan  4 16:18:07 2000
@@ -1180,6 +1180,14 @@ target_options [] = TARGET_OPTIONS;
 
 /* Options controlling warnings */
 
+/* When nonzero, check for warnings/errors but do so silently.  This
+   is different from inhibit_warnings, which avoids incrementing
+   warningcount/errorcount at all. */
+int check_diagnostics_silently = 0;
+
+/* When checking diagnostics silently, set this if a diagnostic occured. */
+int diagnostic_occurred = 0;
+
 /* Don't print warning messages.  -w.  */
 
 int inhibit_warnings = 0;
diff -rup orig/egcs-CVS20000104/gcc/toplev.h egcs-CVS20000104/gcc/toplev.h
--- orig/egcs-CVS20000104/gcc/toplev.h	Fri Dec 24 15:46:37 1999
+++ egcs-CVS20000104/gcc/toplev.h	Tue Jan  4 16:18:07 2000
@@ -131,6 +131,8 @@ extern void note_deferral_of_defined_inl
 extern int errorcount;
 extern int warningcount;
 extern int sorrycount;
+extern int check_diagnostics_silently;
+extern int diagnostic_occurred;
 
 extern const char *progname;
 #endif /* __GCC_TOPLEV_H */
diff -rup orig/egcs-CVS20000104/gcc/tree.c egcs-CVS20000104/gcc/tree.c
--- orig/egcs-CVS20000104/gcc/tree.c	Mon Dec 27 07:46:26 1999
+++ egcs-CVS20000104/gcc/tree.c	Tue Jan  4 16:18:07 2000
@@ -243,6 +243,21 @@ static int next_decl_uid;
 /* Unique id for next type created.  */
 static int next_type_uid = 1;
 
+/* Pointer to function to check the format of printf, etc.  This is
+   used in builtins.c. */
+
+void (*check_function_format_p) PROTO ((tree, tree, tree)) = 0;
+
+/* Pointer to function which, when given an identifier, returns a
+   *_DECL from a language dependent location in the tree. */
+
+tree (*get_decl_p) PROTO ((tree)) = 0;
+
+/* Pointer to function which will initialize common nodes and builtin
+   functions relating to FILE type. */
+  
+void (*initialize_file_nodes_p) PROTO ((void)) = 0;
+
 /* The language-specific function for alias analysis.  If NULL, the
    language does not do any special alias analysis.  */
 int (*lang_get_alias_set) PROTO((tree));
diff -rup orig/egcs-CVS20000104/gcc/tree.h egcs-CVS20000104/gcc/tree.h
--- orig/egcs-CVS20000104/gcc/tree.h	Tue Jan  4 07:46:48 2000
+++ egcs-CVS20000104/gcc/tree.h	Tue Jan  4 16:18:07 2000
@@ -115,6 +115,12 @@ enum built_in_function
   BUILT_IN_SETJMP,
   BUILT_IN_LONGJMP,
   BUILT_IN_TRAP,
+  BUILT_IN_FPUTC,
+  BUILT_IN_FPUTS,
+  BUILT_IN_PRINTF,
+  BUILT_IN_FPRINTF,
+  BUILT_IN_SPRINTF,
+  BUILT_IN_INITIALIZE_FILE,
 
   /* Various hooks for the DWARF 2 __throw routine.  */
   BUILT_IN_UNWIND_INIT,
@@ -2064,6 +2070,25 @@ extern const char * const language_strin
 extern tree builtin_function			PROTO((const char *, tree, int,
 						       enum built_in_class,
 						       const char *));
+
+/* As above, except do so at the top level.  */
+extern tree builtin_function_top_level		PROTO((const char *, tree, int,
+						       enum built_in_class,
+						       const char *));
+
+/* Pointer to function to check the format of printf, etc.  This is
+   used in builtins.c. */
+extern void (*check_function_format_p) PROTO ((tree, tree, tree));
+
+/* Pointer to function which, when given an identifier, returns a
+   *_DECL from a language dependent location in the tree. */
+
+extern tree (*get_decl_p) PROTO ((tree));
+
+/* Pointer to function which will initialize common nodes and builtin
+   functions relating to FILE type. */
+  
+extern void (*initialize_file_nodes_p) PROTO ((void));
 
 /* In tree.c */
 extern char *perm_calloc			PROTO((int, long));

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