OSDN Git Service

* builtins.c (is_valid_printf_arglist, expand_builtin_printf): New
authorghazi <ghazi@138bc75d-0d04-0410-961f-82ee72b054a4>
Tue, 19 Sep 2000 18:19:44 +0000 (18:19 +0000)
committerghazi <ghazi@138bc75d-0d04-0410-961f-82ee72b054a4>
Tue, 19 Sep 2000 18:19:44 +0000 (18:19 +0000)
functions.
(expand_builtin_fputs): Set `target' parameter for `expand_expr'.
(expand_builtin): Handle BUILT_IN_PUTCHAR, BUILT_IN_PUTS and
BUILT_IN_PRINTF.

* builtins.def (BUILT_IN_PUTCHAR, BUILT_IN_PUTS, BUILT_IN_PRINTF):
New entries.

* c-common.c (init_function_format_info): Handle __builtin_printf.
Set `check_function_format_ptr'.
(c_common_nodes_and_builtins): Set `puts_ftype' and
`printf_ftype'.  Declare __builtin_putchar, __builtin_puts,
__builtin_printf and printf.

* tree.c, tree.h (check_function_format_ptr): Declare.

testsuite:
* g++.old-deja/g++.other/virtual8.C: Declare printf correctly.

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

gcc/ChangeLog
gcc/builtins.c
gcc/builtins.def
gcc/c-common.c
gcc/testsuite/ChangeLog
gcc/testsuite/g++.old-deja/g++.other/virtual8.C
gcc/tree.c
gcc/tree.h

index 26a2801..35b1822 100644 (file)
@@ -1,3 +1,22 @@
+2000-09-19  Kaveh R. Ghazi  <ghazi@caip.rutgers.edu>
+
+       * builtins.c (is_valid_printf_arglist, expand_builtin_printf): New
+       functions.
+       (expand_builtin_fputs): Set `target' parameter for `expand_expr'.
+       (expand_builtin): Handle BUILT_IN_PUTCHAR, BUILT_IN_PUTS and
+       BUILT_IN_PRINTF.
+
+       * builtins.def (BUILT_IN_PUTCHAR, BUILT_IN_PUTS, BUILT_IN_PRINTF):
+       New entries.
+
+       * c-common.c (init_function_format_info): Handle __builtin_printf.
+       Set `check_function_format_ptr'.
+       (c_common_nodes_and_builtins): Set `puts_ftype' and
+       `printf_ftype'.  Declare __builtin_putchar, __builtin_puts,
+       __builtin_printf and printf.
+
+       * tree.c, tree.h (check_function_format_ptr): Declare.
+
 Tue 19-Sep-2000 18:26:57 BST  Neil Booth  <NeilB@earthling.net>
 
         * cppfiles.c (read_include_file): Take no special action for
index 2983b2b..0529723 100644 (file)
@@ -111,6 +111,8 @@ static rtx expand_builtin_strlen    PARAMS ((tree, rtx,
 static rtx expand_builtin_alloca       PARAMS ((tree, rtx));
 static rtx expand_builtin_ffs          PARAMS ((tree, rtx, rtx));
 static rtx expand_builtin_frame_address        PARAMS ((tree));
+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 tree stabilize_va_list          PARAMS ((tree, int));
 static rtx expand_builtin_expect       PARAMS ((tree, rtx));
@@ -2367,7 +2369,122 @@ expand_builtin_fputs (arglist, ignore)
   call_expr = build (CALL_EXPR, TREE_TYPE (TREE_TYPE (fn)),
                     call_expr, newarglist, NULL_TREE);
   TREE_SIDE_EFFECTS (call_expr) = 1;
-  return expand_expr (call_expr, NULL_RTX, VOIDmode, 0);
+  return expand_expr (call_expr, (ignore ? const0_rtx : NULL_RTX),
+                     VOIDmode, EXPAND_NORMAL);
+}
+
+/* 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. */
+  const int SAVE_pedantic = pedantic;
+  int diagnostic_occurred = 0;
+
+  /* If we can't check the format, be safe and return false. */
+  if (!check_function_format_ptr)
+    return 0;
+  
+  /* Set this to a known value so the user setting won't affect code
+     generation.  */
+  pedantic = 1;
+  /* Check to make sure there are no format specifier errors. */
+  check_function_format_ptr (&diagnostic_occurred,
+                            maybe_get_identifier("printf"),
+                            NULL_TREE, arglist);
+
+  /* Restore the value of `pedantic'. */
+  pedantic = SAVE_pedantic;
+
+  /* If calling `check_function_format_ptr' produces a warning, we
+     return false, otherwise we return true. */
+  return ! diagnostic_occurred;
+}
+
+/* If the arguments passed to printf are suitable for optimizations,
+   we attempt to transform the call. */
+static rtx
+expand_builtin_printf (arglist, ignore)
+     tree arglist;
+     int ignore;
+{
+  tree fn_putchar = built_in_decls[BUILT_IN_PUTCHAR],
+    fn_puts = built_in_decls[BUILT_IN_PUTS];
+  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)
+    return 0;
+
+  /* Verify the required arguments in the original call. */
+  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 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\n", call __builtin_puts(arg2). */
+  if (strcmp (TREE_STRING_POINTER (stripped_string), "%s\n") == 0)
+    {
+      arglist = TREE_CHAIN (arglist);
+      fn = fn_puts;
+    }
+  /* If the format specifier was "%c", call __builtin_putchar (arg2). */
+  else if (strcmp (TREE_STRING_POINTER (stripped_string), "%c") == 0)
+    {
+      arglist = TREE_CHAIN (arglist);
+      fn = fn_putchar;
+    }
+  else
+    {
+     /* We can't handle anything else with % args or %% ... yet. */
+      if (strchr (TREE_STRING_POINTER (stripped_string), '%'))
+       return 0;
+      
+      /* If the resulting constant string has a length of 1, call
+         putchar.  Note, TREE_STRING_LENGTH includes the terminating
+         NULL in its count.  */
+      if (TREE_STRING_LENGTH (stripped_string) == 2)
+        {
+         /* Given printf("c"), (where c is any one character,)
+             convert "c"[0] to an int and pass that to the replacement
+             function. */
+         arglist = build_int_2 (TREE_STRING_POINTER (stripped_string)[0], 0);
+         arglist = build_tree_list (NULL_TREE, arglist);
+         
+         fn = fn_putchar;
+        }
+      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;
+    }
+  
+  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, (ignore ? const0_rtx : NULL_RTX),
+                     VOIDmode, EXPAND_NORMAL);
 }
 
 /* Expand a call to __builtin_expect.  We return our argument and
@@ -2444,7 +2561,9 @@ expand_builtin (exp, target, subtarget, mode, ignore)
          || fcode == BUILT_IN_BCMP || fcode == BUILT_IN_BZERO
          || fcode == BUILT_IN_STRLEN || fcode == BUILT_IN_STRCPY
          || fcode == BUILT_IN_STRCMP || fcode == BUILT_IN_FFS
-         || fcode == BUILT_IN_FPUTC || fcode == BUILT_IN_FPUTS))
+         || fcode == BUILT_IN_PUTCHAR || fcode == BUILT_IN_PUTS
+         || fcode == BUILT_IN_PRINTF || fcode == BUILT_IN_FPUTC
+         || fcode == BUILT_IN_FPUTS))
     return expand_call (exp, target, ignore);
 
   switch (fcode)
@@ -2657,6 +2776,8 @@ expand_builtin (exp, target, subtarget, mode, ignore)
       emit_barrier ();
       return const0_rtx;
 
+    case BUILT_IN_PUTCHAR:
+    case BUILT_IN_PUTS:
     case BUILT_IN_FPUTC:
       break;
       
@@ -2666,6 +2787,12 @@ expand_builtin (exp, target, subtarget, mode, ignore)
        return target;
       break;
       
+    case BUILT_IN_PRINTF:
+      target = expand_builtin_printf (arglist, ignore);
+      if (target)
+       return target;
+      break;
+      
       /* Various hooks for the DWARF 2 __throw routine.  */
     case BUILT_IN_UNWIND_INIT:
       expand_builtin_unwind_init ();
index 40ae59c..7220cf9 100644 (file)
@@ -59,6 +59,9 @@ DEF_BUILTIN(BUILT_IN_LONGJMP)
 DEF_BUILTIN(BUILT_IN_TRAP)
 
   /* Stdio builtins.  */
+DEF_BUILTIN(BUILT_IN_PUTCHAR)
+DEF_BUILTIN(BUILT_IN_PUTS)
+DEF_BUILTIN(BUILT_IN_PRINTF)
 DEF_BUILTIN(BUILT_IN_FPUTC)
 DEF_BUILTIN(BUILT_IN_FPUTS)
 
index 5ede422..fec74eb 100644 (file)
@@ -1566,6 +1566,8 @@ init_function_format_info ()
       /* Functions from ISO/IEC 9899:1990.  */
       record_function_format (get_identifier ("printf"), NULL_TREE,
                              printf_format_type, 1, 2);
+      record_function_format (get_identifier ("__builtin_printf"), NULL_TREE,
+                             printf_format_type, 1, 2);
       record_function_format (get_identifier ("fprintf"), NULL_TREE,
                              printf_format_type, 2, 3);
       record_function_format (get_identifier ("sprintf"), NULL_TREE,
@@ -1608,6 +1610,8 @@ init_function_format_info ()
       record_international_format (get_identifier ("dgettext"), NULL_TREE, 2);
       record_international_format (get_identifier ("dcgettext"), NULL_TREE, 2);
     }
+
+  check_function_format_ptr = check_function_format;
 }
 
 /* Record information for argument format checking.  FUNCTION_IDENT is
@@ -4006,7 +4010,7 @@ c_common_nodes_and_builtins (cplus_mode, no_builtins, no_nonansi_builtins)
 {
   tree temp;
   tree memcpy_ftype, memset_ftype, strlen_ftype;
-  tree bzero_ftype, bcmp_ftype;
+  tree bzero_ftype, bcmp_ftype, puts_ftype, printf_ftype;
   tree endlink, int_endlink, double_endlink, unsigned_endlink;
   tree sizetype_endlink;
   tree ptr_ftype, ptr_ftype_unsigned;
@@ -4162,6 +4166,18 @@ c_common_nodes_and_builtins (cplus_mode, no_builtins, no_nonansi_builtins)
                                                 traditional_cptr_type_node,
                                                 traditional_len_endlink)));
 
+  /* Prototype for puts.  */
+  puts_ftype
+    = build_function_type (integer_type_node,
+                          tree_cons (NULL_TREE, const_string_type_node,
+                                     endlink));
+
+  /* Prototype for printf.  */
+  printf_ftype
+    = build_function_type (integer_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);
 
@@ -4348,6 +4364,14 @@ c_common_nodes_and_builtins (cplus_mode, no_builtins, no_nonansi_builtins)
                    BUILT_IN_COS, BUILT_IN_NORMAL, "cos");
   builtin_function ("__builtin_cosl", ldouble_ftype_ldouble,
                    BUILT_IN_COS, BUILT_IN_NORMAL, "cosl");
+  built_in_decls[BUILT_IN_PUTCHAR] =
+    builtin_function ("__builtin_putchar", int_ftype_int,
+                     BUILT_IN_PUTCHAR, BUILT_IN_NORMAL, "putchar");
+  built_in_decls[BUILT_IN_PUTS] =
+    builtin_function ("__builtin_puts", puts_ftype,
+                     BUILT_IN_PUTS, BUILT_IN_NORMAL, "puts");
+  builtin_function ("__builtin_printf", printf_ftype,
+                   BUILT_IN_PRINTF, BUILT_IN_NORMAL, "printf");
   /* We declare these without argument so that the initial declaration
      for these identifiers is a builtin.  That allows us to redeclare
      them later with argument without worrying about the explicit
@@ -4402,6 +4426,8 @@ c_common_nodes_and_builtins (cplus_mode, no_builtins, no_nonansi_builtins)
                        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_NORMAL, NULL_PTR);
       /* We declare these without argument so that the initial
          declaration for these identifiers is a builtin.  That allows
          us to redeclare them later with argument without worrying
index 34c2553..d32659b 100644 (file)
@@ -1,3 +1,7 @@
+2000-09-19  Kaveh R. Ghazi  <ghazi@caip.rutgers.edu>
+
+       * g++.old-deja/g++.other/virtual8.C: Declare printf correctly.
+
 2000-09-19  Richard Henderson  <rth@cygnus.com>
 
        * gcc.dg/compare2.c (case 10): XFAIL.
index 9f32ca0..32c8e54 100644 (file)
@@ -1,4 +1,4 @@
-extern "C" void printf (const char*, ...);
+extern "C" int printf (const char*, ...);
 
 struct A
 {
index 3f8d7c6..ef27a78 100644 (file)
@@ -246,6 +246,10 @@ 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 by the backend, e.g. builtins.c.  */
+void (*check_function_format_ptr) PARAMS ((int *, tree, tree, tree)) = 0;
+
 /* Here is how primitive or already-canonicalized types' hash
    codes are made.  */
 #define TYPE_HASH(TYPE) ((unsigned long) (TYPE) & 0777777)
index 2c5ad0a..f55b4b6 100644 (file)
@@ -2441,6 +2441,9 @@ extern const char * const language_string;
 extern tree builtin_function                   PARAMS ((const char *, tree, int,
                                                       enum built_in_class,
                                                       const char *));
+/* 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));
 \f
 /* In tree.c */
 extern char *perm_calloc                       PARAMS ((int, long));