OSDN Git Service

* builtins.c (is_valid_printf_arglist, expand_builtin_printf):
authorghazi <ghazi@138bc75d-0d04-0410-961f-82ee72b054a4>
Fri, 6 Oct 2000 14:59:56 +0000 (14:59 +0000)
committerghazi <ghazi@138bc75d-0d04-0410-961f-82ee72b054a4>
Fri, 6 Oct 2000 14:59:56 +0000 (14:59 +0000)
Move functions from here ...

* c-common.c (is_valid_printf_arglist, c_expand_builtin_printf):
... to here.
(c_expand_builtin): New function.
(init_function_format_info): Don't set `check_function_format_ptr'.
(c_common_nodes_and_builtins): Set built_in_class type for
printf/__builtin_printf to BUILT_IN_FRONTEND.
(c_expand_expr): Handle CALL_EXPRs that are front-end builtins.

* c-common.h (build_function_call): Declare.

* expr.c (expand_expr): Pass builtins with class BUILT_IN_FRONTEND
to `lang_expand_expr' rather than `expand_builtin'.

* tree.c (check_function_format_ptr): Delete.

* tree.h (check_function_format_ptr): Likewise.

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

gcc/ChangeLog
gcc/builtins.c
gcc/c-common.c
gcc/c-common.h
gcc/expr.c
gcc/tree.c
gcc/tree.h

index f4abd13..c98f4d9 100644 (file)
@@ -1,3 +1,25 @@
+2000-10-06  Kaveh R. Ghazi  <ghazi@caip.rutgers.edu>
+
+       * builtins.c (is_valid_printf_arglist, expand_builtin_printf):
+       Move functions from here ...
+
+       * c-common.c (is_valid_printf_arglist, c_expand_builtin_printf):
+       ... to here.
+       (c_expand_builtin): New function.
+       (init_function_format_info): Don't set `check_function_format_ptr'.
+       (c_common_nodes_and_builtins): Set built_in_class type for
+       printf/__builtin_printf to BUILT_IN_FRONTEND.
+       (c_expand_expr): Handle CALL_EXPRs that are front-end builtins.
+
+       * c-common.h (build_function_call): Declare.
+
+       * expr.c (expand_expr): Pass builtins with class BUILT_IN_FRONTEND
+       to `lang_expand_expr' rather than `expand_builtin'.
+
+       * tree.c (check_function_format_ptr): Delete.
+
+       * tree.h (check_function_format_ptr): Likewise.
+
 2000-10-06  Hans-Peter Nilsson  <hp@bitrange.com>
 
        * dwarf2out.c (build_cfa_loc): Correct to use DW_OP_regx or
index 187164a..e2acada 100644 (file)
@@ -111,8 +111,6 @@ 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));
@@ -2398,120 +2396,6 @@ expand_builtin_fputs (arglist, ignore)
                      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
    emit a NOTE_INSN_EXPECTED_VALUE note.  */
 
@@ -2814,12 +2698,6 @@ 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 4e63025..2d2ab47 100644 (file)
@@ -1550,6 +1550,10 @@ static int maybe_read_dollar_number              PARAMS ((int *, const char **, int,
 static void finish_dollar_format_checking      PARAMS ((int *));
 
 static void check_format_types PARAMS ((int *, format_wanted_type *));
+static int is_valid_printf_arglist PARAMS ((tree));
+static rtx c_expand_builtin (tree, rtx, enum machine_mode, enum expand_modifier);
+static rtx c_expand_builtin_printf 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
@@ -1615,8 +1619,6 @@ 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
@@ -4388,7 +4390,7 @@ c_common_nodes_and_builtins (cplus_mode, no_builtins, no_nonansi_builtins)
     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");
+                   BUILT_IN_PRINTF, BUILT_IN_FRONTEND, "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
@@ -4450,7 +4452,7 @@ c_common_nodes_and_builtins (cplus_mode, no_builtins, no_nonansi_builtins)
       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);
+                       BUILT_IN_FRONTEND, 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
@@ -5028,6 +5030,20 @@ c_expand_expr (exp, target, tmode, modifier)
       }
       break;
       
+    case CALL_EXPR:
+      {
+       if (TREE_CODE (TREE_OPERAND (exp, 0)) == ADDR_EXPR
+           && (TREE_CODE (TREE_OPERAND (TREE_OPERAND (exp, 0), 0))
+               == FUNCTION_DECL)
+           && DECL_BUILT_IN (TREE_OPERAND (TREE_OPERAND (exp, 0), 0))
+           && (DECL_BUILT_IN_CLASS (TREE_OPERAND (TREE_OPERAND (exp, 0), 0))
+               == BUILT_IN_FRONTEND))
+         return c_expand_builtin (exp, target, tmode, modifier);
+       else
+         abort();
+      }
+      break;
+
     default:
       abort ();
     }
@@ -5112,3 +5128,176 @@ add_c_tree_codes ()
          c_tree_code_name,
          (LAST_C_TREE_CODE - (int)LAST_AND_UNUSED_TREE_CODE) * sizeof (char *));
 }
+
+#define CALLED_AS_BUILT_IN(NODE) \
+   (!strncmp (IDENTIFIER_POINTER (DECL_NAME (NODE)), "__builtin_", 10))
+
+static rtx
+c_expand_builtin (exp, target, tmode, modifier)
+     tree exp;
+     rtx target;
+     enum machine_mode tmode;
+     enum expand_modifier modifier;
+{
+  tree type = TREE_TYPE (exp);
+  tree fndecl = TREE_OPERAND (TREE_OPERAND (exp, 0), 0);
+  tree arglist = TREE_OPERAND (exp, 1);
+  enum built_in_function fcode = DECL_FUNCTION_CODE (fndecl);
+  enum tree_code code = TREE_CODE (exp);
+  const int ignore = (target == const0_rtx
+                     || ((code == NON_LVALUE_EXPR || code == NOP_EXPR
+                          || code == CONVERT_EXPR || code == REFERENCE_EXPR
+                          || code == COND_EXPR)
+                         && TREE_CODE (type) == VOID_TYPE));
+
+  if (! optimize && ! CALLED_AS_BUILT_IN (fndecl))
+    return expand_call (exp, target, ignore);
+
+  switch (fcode)
+    {
+    case BUILT_IN_PRINTF:
+      target = c_expand_builtin_printf (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)));
+    }
+
+  /* The switch statement above can drop through to cause the function
+     to be called normally.  */
+  return expand_call (exp, target, ignore);
+}
+
+/* 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;
+
+  /* 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 (&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
+c_expand_builtin_printf (arglist, target, tmode, modifier, ignore)
+     tree arglist;
+     rtx target;
+     enum machine_mode tmode;
+     enum expand_modifier modifier;
+     int ignore;
+{
+  tree fn_putchar = built_in_decls[BUILT_IN_PUTCHAR],
+    fn_puts = built_in_decls[BUILT_IN_PUTS];
+  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_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;
+        }
+      /* If the resulting constant was "string\n", call
+         __builtin_puts("string").  Ensure "string" has at least one
+         character besides the trailing \n.  Note, TREE_STRING_LENGTH
+         includes the terminating NULL in its count.  */
+      else if (TREE_STRING_LENGTH (stripped_string) > 2
+              && TREE_STRING_POINTER (stripped_string)
+              [TREE_STRING_LENGTH (stripped_string) - 2] == '\n')
+        {
+         /* Create a NULL-terminated string that's one char shorter
+            than the original, stripping off the trailing '\n'.  */
+         const int newlen = TREE_STRING_LENGTH (stripped_string) - 1;
+         char *newstr = (char *) alloca (newlen);
+         memcpy (newstr, TREE_STRING_POINTER (stripped_string), newlen - 1);
+         newstr[newlen - 1] = 0;
+         
+         arglist = build_string (newlen, newstr);
+         TREE_TYPE (arglist) = 
+           build_type_variant (char_array_type_node, 1, 0);
+         arglist = build_tree_list (NULL_TREE, arglist);
+         fn = fn_puts;
+       }
+      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;
+    }
+  
+  return expand_expr (build_function_call (fn, arglist),
+                     (ignore ? const0_rtx : target),
+                     tmode, modifier);
+}
index bb9eee7..24db762 100644 (file)
@@ -683,6 +683,8 @@ extern tree c_add_case_label                    PARAMS ((splay_tree,
                                                         tree, tree,
                                                         tree));
 
+extern tree build_function_call                        PARAMS ((tree, tree));
+
 #ifdef RTX_CODE
 
 extern struct rtx_def *c_expand_expr            PARAMS ((tree, rtx,
index ee68dff..c36d61f 100644 (file)
@@ -7163,7 +7163,13 @@ expand_expr (exp, target, tmode, modifier)
          && (TREE_CODE (TREE_OPERAND (TREE_OPERAND (exp, 0), 0))
              == FUNCTION_DECL)
          && DECL_BUILT_IN (TREE_OPERAND (TREE_OPERAND (exp, 0), 0)))
-       return expand_builtin (exp, target, subtarget, tmode, ignore);
+        {
+         if (DECL_BUILT_IN_CLASS (TREE_OPERAND (TREE_OPERAND (exp, 0), 0))
+             == BUILT_IN_FRONTEND)
+           return (*lang_expand_expr) (exp, original_target, tmode, modifier);
+         else
+           return expand_builtin (exp, target, subtarget, tmode, ignore);
+       }
 
       /* If this call was expanded already by preexpand_calls,
         just return the result we got.  */
index 8def9fd..6eafd91 100644 (file)
@@ -246,10 +246,6 @@ 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 74c566c..c00fafd 100644 (file)
@@ -2446,9 +2446,6 @@ 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));