OSDN Git Service

* gcc.c-torture/execute/stdarg-2.c (foo): Split multiple
[pf3gnuchains/gcc-fork.git] / gcc / tree-inline.c
index 7a80528..17f3937 100644 (file)
@@ -35,6 +35,7 @@ Boston, MA 02111-1307, USA.  */
 #include "integrate.h"
 #include "varray.h"
 #include "hashtab.h"
+#include "pointer-set.h"
 #include "splay-tree.h"
 #include "langhooks.h"
 #include "cgraph.h"
@@ -619,6 +620,16 @@ copy_body_r (tree *tp, int *walk_subtrees, void *data)
          TREE_OPERAND (*tp, 1) = TREE_OPERAND (*tp, 3);
          TREE_OPERAND (*tp, 3) = NULL_TREE;
        }
+
+      /* Variable substitution need not be simple.  In particular, the
+        INDIRECT_REF substitution above.  Make sure that TREE_CONSTANT
+        and friends are up-to-date.  */
+      else if (TREE_CODE (*tp) == ADDR_EXPR)
+       {
+         walk_tree (&TREE_OPERAND (*tp, 0), copy_body_r, id, NULL);
+         recompute_tree_invarant_for_addr_expr (*tp);
+         *walk_subtrees = 0;
+       }
     }
 
   /* Keep iterating.  */
@@ -878,7 +889,7 @@ declare_return_variable (inline_data *id, tree return_slot_addr,
                 DECL_STRUCT_FUNCTION (caller)->unexpanded_var_list);
 
   /* Do not have the rest of GCC warn about this variable as it should
-     not be visible to the user.   */
+     not be visible to the user.  */
   TREE_NO_WARNING (var) = 1;
 
   /* Build the use expr.  If the return type of the function was
@@ -930,7 +941,7 @@ inline_forbidden_p_1 (tree *nodep, int *walk_subtrees ATTRIBUTE_UNUSED,
          && !lookup_attribute ("always_inline", DECL_ATTRIBUTES (fn)))
        {
          inline_forbidden_reason
-           = N_("%Jfunction '%F' can never be inlined because it uses "
+           = N_("%Jfunction %qF can never be inlined because it uses "
                 "alloca (override using the always_inline attribute)");
          return node;
        }
@@ -942,7 +953,7 @@ inline_forbidden_p_1 (tree *nodep, int *walk_subtrees ATTRIBUTE_UNUSED,
       if (setjmp_call_p (t))
        {
          inline_forbidden_reason
-           = N_("%Jfunction '%F' can never be inlined because it uses setjmp");
+           = N_("%Jfunction %qF can never be inlined because it uses setjmp");
          return node;
        }
 
@@ -956,7 +967,7 @@ inline_forbidden_p_1 (tree *nodep, int *walk_subtrees ATTRIBUTE_UNUSED,
          case BUILT_IN_NEXT_ARG:
          case BUILT_IN_VA_END:
            inline_forbidden_reason
-             = N_("%Jfunction '%F' can never be inlined because it "
+             = N_("%Jfunction %qF can never be inlined because it "
                   "uses variable argument lists");
            return node;
 
@@ -967,14 +978,14 @@ inline_forbidden_p_1 (tree *nodep, int *walk_subtrees ATTRIBUTE_UNUSED,
               function calling __builtin_longjmp to be inlined into the
               function calling __builtin_setjmp, Things will Go Awry.  */
            inline_forbidden_reason
-             = N_("%Jfunction '%F' can never be inlined because "
+             = N_("%Jfunction %qF can never be inlined because "
                   "it uses setjmp-longjmp exception handling");
            return node;
 
          case BUILT_IN_NONLOCAL_GOTO:
            /* Similarly.  */
            inline_forbidden_reason
-             = N_("%Jfunction '%F' can never be inlined because "
+             = N_("%Jfunction %qF can never be inlined because "
                   "it uses non-local goto");
            return node;
 
@@ -983,20 +994,6 @@ inline_forbidden_p_1 (tree *nodep, int *walk_subtrees ATTRIBUTE_UNUSED,
          }
       break;
 
-    case BIND_EXPR:
-      for (t = BIND_EXPR_VARS (node); t ; t = TREE_CHAIN (t))
-       {
-          /* We cannot inline functions that contain other functions.  */
-         if (TREE_CODE (t) == FUNCTION_DECL && DECL_INITIAL (t))
-           {
-             inline_forbidden_reason
-               = N_("%Jfunction '%F' can never be inlined "
-                    "because it contains a nested function");
-             return node;
-           }
-       }
-      break;
-
     case GOTO_EXPR:
       t = TREE_OPERAND (node, 0);
 
@@ -1007,7 +1004,7 @@ inline_forbidden_p_1 (tree *nodep, int *walk_subtrees ATTRIBUTE_UNUSED,
       if (TREE_CODE (t) != LABEL_DECL)
        {
          inline_forbidden_reason
-           = N_("%Jfunction '%F' can never be inlined "
+           = N_("%Jfunction %qF can never be inlined "
                 "because it contains a computed goto");
          return node;
        }
@@ -1021,7 +1018,7 @@ inline_forbidden_p_1 (tree *nodep, int *walk_subtrees ATTRIBUTE_UNUSED,
             because we cannot remap the destination label used in the
             function that is performing the non-local goto.  */
          inline_forbidden_reason
-           = N_("%Jfunction '%F' can never be inlined "
+           = N_("%Jfunction %qF can never be inlined "
                 "because it receives a non-local goto");
          return node;
        }
@@ -1043,7 +1040,7 @@ inline_forbidden_p_1 (tree *nodep, int *walk_subtrees ATTRIBUTE_UNUSED,
        if (variably_modified_type_p (TREE_TYPE (t), NULL))
          {
            inline_forbidden_reason
-             = N_("%Jfunction '%F' can never be inlined "
+             = N_("%Jfunction %qF can never be inlined "
                   "because it uses variable sized variables");
            return node;
          }
@@ -1149,7 +1146,7 @@ estimate_num_insns_1 (tree *tp, int *walk_subtrees, void *data)
   int *count = data;
   tree x = *tp;
 
-  if (TYPE_P (x) || DECL_P (x))
+  if (IS_TYPE_OR_DECL_P (x))
     {
       *walk_subtrees = 0;
       return NULL;
@@ -1157,8 +1154,7 @@ estimate_num_insns_1 (tree *tp, int *walk_subtrees, void *data)
   /* Assume that constants and references counts nothing.  These should
      be majorized by amount of operations among them we count later
      and are common target of CSE and similar optimizations.  */
-  else if (TREE_CODE_CLASS (TREE_CODE (x)) == 'c'
-          || TREE_CODE_CLASS (TREE_CODE (x)) == 'r')
+  else if (CONSTANT_CLASS_P (x) || REFERENCE_CLASS_P (x))
     return NULL;
 
   switch (TREE_CODE (x))
@@ -1463,7 +1459,7 @@ expand_call_inline (tree *tp, int *walk_subtrees, void *data)
          where previous inlining turned indirect call into direct call by
          constant propagating arguments.  In all other cases we hit a bug
          (incorrect node sharing is most common reason for missing edges.  */
-      gcc_assert (dest->needed);
+      gcc_assert (dest->needed || !flag_unit_at_a_time);
       cgraph_create_edge (id->node, dest, t)->inline_failed
        = N_("originally indirect function call not considered for inlining");
       goto egress;
@@ -1475,14 +1471,15 @@ expand_call_inline (tree *tp, int *walk_subtrees, void *data)
     {
       if (lookup_attribute ("always_inline", DECL_ATTRIBUTES (fn)))
        {
-         sorry ("%Jinlining failed in call to '%F': %s", fn, fn, reason);
+         sorry ("%Jinlining failed in call to %qF: %s", fn, fn, reason);
          sorry ("called from here");
        }
       else if (warn_inline && DECL_DECLARED_INLINE_P (fn)
               && !DECL_IN_SYSTEM_HEADER (fn)
-              && strlen (reason))
+              && strlen (reason)
+              && !lookup_attribute ("noinline", DECL_ATTRIBUTES (fn)))
        {
-         warning ("%Jinlining failed in call to '%F': %s", fn, fn, reason);
+         warning ("%Jinlining failed in call to %qF: %s", fn, fn, reason);
          warning ("called from here");
        }
       goto egress;
@@ -1881,7 +1878,7 @@ save_body (tree fn, tree *arg_copy, tree *sc_copy)
 #define WALK_SUBTREE(NODE)                             \
   do                                                   \
     {                                                  \
-      result = walk_tree (&(NODE), func, data, htab);  \
+      result = walk_tree (&(NODE), func, data, pset);  \
       if (result)                                      \
        return result;                                  \
     }                                                  \
@@ -1892,7 +1889,8 @@ save_body (tree fn, tree *arg_copy, tree *sc_copy)
    value are as for walk_tree.  */
 
 static tree
-walk_type_fields (tree type, walk_tree_fn func, void *data, void *htab)
+walk_type_fields (tree type, walk_tree_fn func, void *data,
+                 struct pointer_set_t *pset)
 {
   tree result = NULL_TREE;
 
@@ -1910,7 +1908,7 @@ walk_type_fields (tree type, walk_tree_fn func, void *data, void *htab)
       if (POINTER_TYPE_P (TREE_TYPE (type))
          && POINTER_TYPE_P (TREE_TYPE (TREE_TYPE (type)))
          && POINTER_TYPE_P (TREE_TYPE (TREE_TYPE (TREE_TYPE (type))))
-         && !htab)
+         && !pset)
        {
          result = walk_tree_without_duplicates (&TREE_TYPE (type),
                                                 func, data);
@@ -1975,13 +1973,12 @@ walk_type_fields (tree type, walk_tree_fn func, void *data, void *htab)
 /* Apply FUNC to all the sub-trees of TP in a pre-order traversal.  FUNC is
    called with the DATA and the address of each sub-tree.  If FUNC returns a
    non-NULL value, the traversal is aborted, and the value returned by FUNC
-   is returned.  If HTAB is non-NULL it is used to record the nodes visited,
+   is returned.  If PSET is non-NULL it is used to record the nodes visited,
    and to avoid visiting a node more than once.  */
 
 tree
-walk_tree (tree *tp, walk_tree_fn func, void *data, void *htab_)
+walk_tree (tree *tp, walk_tree_fn func, void *data, struct pointer_set_t *pset)
 {
-  htab_t htab = (htab_t) htab_;
   enum tree_code code;
   int walk_subtrees;
   tree result;
@@ -1999,17 +1996,10 @@ walk_tree (tree *tp, walk_tree_fn func, void *data, void *htab_)
   if (!*tp)
     return NULL_TREE;
 
-  if (htab)
-    {
-      void **slot;
-
-      /* Don't walk the same tree twice, if the user has requested
-         that we avoid doing so.  */
-      slot = htab_find_slot (htab, *tp, INSERT);
-      if (*slot)
-       return NULL_TREE;
-      *slot = *tp;
-    }
+  /* Don't walk the same tree twice, if the user has requested
+     that we avoid doing so.  */
+  if (pset && pointer_set_insert (pset, *tp))
+    return NULL_TREE;
 
   /* Call the function.  */
   walk_subtrees = 1;
@@ -2033,7 +2023,7 @@ walk_tree (tree *tp, walk_tree_fn func, void *data, void *htab_)
     }
 
   result = lang_hooks.tree_inlining.walk_subtrees (tp, &walk_subtrees, func,
-                                                  data, htab);
+                                                  data, pset);
   if (result || ! walk_subtrees)
     return result;
 
@@ -2057,7 +2047,7 @@ walk_tree (tree *tp, walk_tree_fn func, void *data, void *htab_)
       if (result || !walk_subtrees)
        return NULL_TREE;
 
-      result = walk_type_fields (*type_p, func, data, htab_);
+      result = walk_type_fields (*type_p, func, data, pset);
       if (result)
        return result;
 
@@ -2128,7 +2118,7 @@ walk_tree (tree *tp, walk_tree_fn func, void *data, void *htab_)
   /* If this is a type, walk the needed fields in the type.  */
   else if (TYPE_P (*tp))
     {
-      result = walk_type_fields (*tp, func, data, htab_);
+      result = walk_type_fields (*tp, func, data, pset);
       if (result)
        return result;
     }
@@ -2231,11 +2221,11 @@ tree
 walk_tree_without_duplicates (tree *tp, walk_tree_fn func, void *data)
 {
   tree result;
-  htab_t htab;
+  struct pointer_set_t *pset;
 
-  htab = htab_create (37, htab_hash_pointer, htab_eq_pointer, NULL);
-  result = walk_tree (tp, func, data, htab);
-  htab_delete (htab);
+  pset = pointer_set_create ();
+  result = walk_tree (tp, func, data, pset);
+  pointer_set_destroy (pset);
   return result;
 }
 
@@ -2248,7 +2238,6 @@ copy_tree_r (tree *tp, int *walk_subtrees, void *data ATTRIBUTE_UNUSED)
 
   /* We make copies of most nodes.  */
   if (IS_EXPR_CODE_CLASS (TREE_CODE_CLASS (code))
-      || TREE_CODE_CLASS (code) == 'c'
       || code == TREE_LIST
       || code == TREE_VEC
       || code == TYPE_DECL)
@@ -2278,9 +2267,11 @@ copy_tree_r (tree *tp, int *walk_subtrees, void *data ATTRIBUTE_UNUSED)
        BIND_EXPR_BLOCK (*tp) = NULL_TREE;
     }
 
-  else if (TREE_CODE_CLASS (code) == 't')
+  else if (TREE_CODE_CLASS (code) == tcc_type)
+    *walk_subtrees = 0;
+  else if (TREE_CODE_CLASS (code) == tcc_declaration)
     *walk_subtrees = 0;
-  else if (TREE_CODE_CLASS (code) == 'd')
+  else if (TREE_CODE_CLASS (code) == tcc_constant)
     *walk_subtrees = 0;
   else
     gcc_assert (code != STATEMENT_LIST);