OSDN Git Service

* builtins.def (BUILT_IN_FPRINTF): New entry.
authorghazi <ghazi@138bc75d-0d04-0410-961f-82ee72b054a4>
Sun, 7 Jan 2001 23:15:47 +0000 (23:15 +0000)
committerghazi <ghazi@138bc75d-0d04-0410-961f-82ee72b054a4>
Sun, 7 Jan 2001 23:15:47 +0000 (23:15 +0000)
* 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.

git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@38788 138bc75d-0d04-0410-961f-82ee72b054a4

gcc/ChangeLog
gcc/builtins.def
gcc/c-common.c
gcc/c-decl.c
gcc/extend.texi
gcc/testsuite/ChangeLog
gcc/testsuite/gcc.c-torture/execute/stdio-opt-3.c [new file with mode: 0644]

index 304c7de..a9c499a 100644 (file)
@@ -1,3 +1,16 @@
+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.
+
 2001-01-07  Richard Henderson  <rth@redhat.com>
 
        * jump.c (simplejump_p): Recognize any single_set jump
index ecb1991..cd715d9 100644 (file)
@@ -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)
index 3a76510..98d96e2 100644 (file)
@@ -1951,6 +1951,8 @@ static int is_valid_printf_arglist PARAMS ((tree));
 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, modifier)
        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)));
@@ -6751,6 +6773,86 @@ c_expand_builtin_printf (arglist, target, tmode, modifier, ignore)
                      (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),
+                     (ignore ? const0_rtx : target),
+                     tmode, modifier);
+}
 \f
 
 /* Given a boolean expression ARG, return a tree representing an increment
index 0a94db0..95272f9 100644 (file)
@@ -1511,7 +1511,7 @@ duplicate_decls (newdecl, olddecl, different_binding_level)
                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
index e893c67..bee479a 100644 (file)
@@ -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 @code{__builtin_}.
 
 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
index 0d53b93..87b4b6f 100644 (file)
@@ -1,3 +1,7 @@
+2001-01-07  Kaveh R. Ghazi  <ghazi@caip.rutgers.edu>
+
+       * gcc.c-torture/execute/stdio-opt-3.c: New test.
+
 2001-01-07  Jakub Jelinek  <jakub@redhat.com>
 
        * gcc.c-torture/compile/20010107-1.c: New test.
diff --git a/gcc/testsuite/gcc.c-torture/execute/stdio-opt-3.c b/gcc/testsuite/gcc.c-torture/execute/stdio-opt-3.c
new file mode 100644 (file)
index 0000000..fb56a3f
--- /dev/null
@@ -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