OSDN Git Service

* alias.c, basic-block.h, cgraphunit.c, combine.c, domwalk.h,
[pf3gnuchains/gcc-fork.git] / gcc / tree-inline.c
index bb2af8d..f1d9c5a 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"
@@ -135,6 +136,7 @@ static void remap_block (tree *, inline_data *);
 static tree remap_decls (tree, inline_data *);
 static void copy_bind_expr (tree *, int *, inline_data *);
 static tree mark_local_for_remap_r (tree *, int *, void *);
+static void unsave_expr_1 (tree);
 static tree unsave_r (tree *, int *, void *);
 static void declare_inline_vars (tree bind_expr, tree vars);
 
@@ -182,7 +184,7 @@ remap_decl (tree decl, inline_data *id)
       walk_tree (&DECL_SIZE (t), copy_body_r, id, NULL);
       walk_tree (&DECL_SIZE_UNIT (t), copy_body_r, id, NULL);
 
-      /* If fields, do likewise for offset and qualifier. */
+      /* If fields, do likewise for offset and qualifier.  */
       if (TREE_CODE (t) == FIELD_DECL)
        {
          walk_tree (&DECL_FIELD_OFFSET (t), copy_body_r, id, NULL);
@@ -205,8 +207,7 @@ remap_decl (tree decl, inline_data *id)
            {
              tree member = remap_decl (TREE_VALUE (src), id);
 
-             if (TREE_PURPOSE (src))
-               abort ();
+             gcc_assert (!TREE_PURPOSE (src));
              members = tree_cons (NULL, member, members);
            }
          DECL_ANON_UNION_ELEMS (t) = nreverse (members);
@@ -325,7 +326,7 @@ remap_type (tree type, inline_data *id)
     case OFFSET_TYPE:
     default:
       /* Shouldn't have been thought variable sized.  */
-      abort ();
+      gcc_unreachable ();
     }
 
   walk_tree (&TYPE_SIZE (new), copy_body_r, id, NULL);
@@ -353,12 +354,9 @@ remap_decls (tree decls, inline_data *id)
         already declared somewhere else, so don't declare it here.  */
       if (!new_var || new_var == id->retvar)
        ;
-#ifdef ENABLE_CHECKING
-      else if (!DECL_P (new_var))
-       abort ();
-#endif
       else
        {
+         gcc_assert (DECL_P (new_var));
          TREE_CHAIN (new_var) = new_decls;
          new_decls = new_var;
        }
@@ -460,8 +458,7 @@ copy_body_r (tree *tp, int *walk_subtrees, void *data)
      what function they come from.  */
   if ((TREE_CODE (*tp) == VAR_DECL || TREE_CODE (*tp) == LABEL_DECL)
       && DECL_NAMESPACE_SCOPE_P (*tp))
-    if (! DECL_EXTERNAL (*tp) && ! TREE_STATIC (*tp))
-      abort ();
+    gcc_assert (DECL_EXTERNAL (*tp) || TREE_STATIC (*tp));
 #endif
 
   /* If this is a RETURN_EXPR, change it into a MODIFY_EXPR and a
@@ -503,17 +500,11 @@ copy_body_r (tree *tp, int *walk_subtrees, void *data)
 
       /* Remap the declaration.  */
       new_decl = remap_decl (*tp, id);
-      if (! new_decl)
-       abort ();
+      gcc_assert (new_decl);
       /* Replace this variable with the copy.  */
       STRIP_TYPE_NOPS (new_decl);
       *tp = new_decl;
     }
-#if 0
-  else if (nonstatic_local_decl_p (*tp)
-          && DECL_CONTEXT (*tp) != VARRAY_TREE (id->fns, 0))
-    abort ();
-#endif
   else if (TREE_CODE (*tp) == STATEMENT_LIST)
     copy_statement_list (tp);
   else if (TREE_CODE (*tp) == SAVE_EXPR)
@@ -535,8 +526,7 @@ copy_body_r (tree *tp, int *walk_subtrees, void *data)
        = splay_tree_lookup (id->decl_map,
                             (splay_tree_key) TREE_OPERAND (*tp, 0));
       /* We _must_ have seen the enclosing LABELED_BLOCK_EXPR.  */
-      if (! n)
-       abort ();
+      gcc_assert (n);
       *tp = copy_node (*tp);
       TREE_OPERAND (*tp, 0) = (tree) n->value;
     }
@@ -573,33 +563,6 @@ copy_body_r (tree *tp, int *walk_subtrees, void *data)
                }
            }
        }
-      else if (TREE_CODE (*tp) == ADDR_EXPR
-              && (lang_hooks.tree_inlining.auto_var_in_fn_p
-                  (TREE_OPERAND (*tp, 0), fn)))
-       {
-         /* Get rid of &* from inline substitutions.  It can occur when
-            someone takes the address of a parm or return slot passed by
-            invisible reference.  */
-         tree decl = TREE_OPERAND (*tp, 0), value;
-         splay_tree_node n;
-
-         n = splay_tree_lookup (id->decl_map, (splay_tree_key) decl);
-         if (n)
-           {
-             value = (tree) n->value;
-             if (TREE_CODE (value) == INDIRECT_REF)
-               {
-                 if  (!lang_hooks.types_compatible_p
-                      (TREE_TYPE (*tp), TREE_TYPE (TREE_OPERAND (value, 0))))
-                   *tp = fold_convert (TREE_TYPE (*tp),
-                                       TREE_OPERAND (value, 0));
-                 else
-                   *tp = TREE_OPERAND (value, 0);
-
-                 return copy_body_r (tp, walk_subtrees, data);
-               }
-           }
-       }
       else if (TREE_CODE (*tp) == INDIRECT_REF)
        {
          /* Get rid of *& from inline substitutions that can happen when a
@@ -634,10 +597,8 @@ copy_body_r (tree *tp, int *walk_subtrees, void *data)
              for (node = id->node->next_clone; node; node = node->next_clone)
                {
                  edge = cgraph_edge (node, old_node);
-                 if (edge)
-                   edge->call_expr = *tp;
-                 else
-                   abort ();
+                 gcc_assert (edge);
+                 edge->call_expr = *tp;
                }
            }
          else
@@ -659,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.  */
@@ -717,7 +688,7 @@ setup_one_parameter (inline_data *id, tree p, tree value, tree fn,
 
   /* Make an equivalent VAR_DECL.  Note that we must NOT remap the type
      here since the type of this decl must be visible to the calling
-     function. */
+     function.  */
   var = copy_decl_for_inlining (p, fn, VARRAY_TREE (id->fns, 0));
 
   /* Register the VAR_DECL as the equivalent for the PARM_DECL;
@@ -819,11 +790,10 @@ initialize_inlined_parameters (inline_data *id, tree args, tree static_chain,
   if (p)
     {
       /* No static chain?  Seems like a bug in tree-nested.c.  */
-      if (!static_chain)
-       abort ();
+      gcc_assert (static_chain);
 
-       setup_one_parameter (id, p, static_chain, fn, &init_stmts, &vars,
-                           &gimplify_init_stmts_p);
+      setup_one_parameter (id, p, static_chain, fn, &init_stmts, &vars,
+                          &gimplify_init_stmts_p);
     }
 
   if (gimplify_init_stmts_p)
@@ -861,22 +831,23 @@ declare_return_variable (inline_data *id, tree return_slot_addr,
       return NULL_TREE;
     }
 
-  /* If there was a return slot, then the return value the the
+  /* If there was a return slot, then the return value is the
      dereferenced address of that object.  */
   if (return_slot_addr)
     {
       /* The front end shouldn't have used both return_slot_addr and
         a modify expression.  */
-      if (modify_dest)
-       abort ();
-      var = build_fold_indirect_ref (return_slot_addr);
+      gcc_assert (!modify_dest);
+      if (DECL_BY_REFERENCE (result))
+       var = return_slot_addr;
+      else
+       var = build_fold_indirect_ref (return_slot_addr);
       use = NULL;
       goto done;
     }
 
   /* All types requiring non-trivial constructors should have been handled.  */
-  if (TREE_ADDRESSABLE (callee_type))
-    abort ();
+  gcc_assert (!TREE_ADDRESSABLE (callee_type));
 
   /* Attempt to avoid creating a new temporary variable.  */
   if (modify_dest)
@@ -909,8 +880,7 @@ declare_return_variable (inline_data *id, tree return_slot_addr,
        }
     }
 
-  if (TREE_CODE (TYPE_SIZE_UNIT (callee_type)) != INTEGER_CST)
-    abort ();
+  gcc_assert (TREE_CODE (TYPE_SIZE_UNIT (callee_type)) == INTEGER_CST);
 
   var = copy_decl_for_inlining (result, callee, caller);
   DECL_SEEN_IN_BIND_EXPR_P (var) = 1;
@@ -919,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
@@ -1024,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);
 
@@ -1190,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;
@@ -1198,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))
@@ -1233,7 +1188,6 @@ estimate_num_insns_1 (tree *tp, int *walk_subtrees, void *data)
     case STATEMENT_LIST:
     case ERROR_MARK:
     case NON_LVALUE_EXPR:
-    case ENTRY_VALUE_EXPR:
     case FDESC_EXPR:
     case VA_ARG_EXPR:
     case TRY_CATCH_EXPR:
@@ -1383,7 +1337,7 @@ estimate_num_insns_1 (tree *tp, int *walk_subtrees, void *data)
       }
     default:
       /* Abort here se we know we don't miss any nodes.  */
-      abort ();
+      gcc_unreachable ();
     }
   return NULL;
 }
@@ -1505,8 +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.  */
-      if (!dest->needed)
-       abort ();
+      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;
@@ -1523,7 +1476,8 @@ expand_call_inline (tree *tp, int *walk_subtrees, void *data)
        }
       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 ("called from here");
@@ -1609,9 +1563,8 @@ expand_call_inline (tree *tp, int *walk_subtrees, void *data)
   DECL_CONTEXT (id->ret_label) = VARRAY_TREE (id->fns, 0);
   insert_decl_map (id, id->ret_label, id->ret_label);
 
-  if (! DECL_INITIAL (fn)
-      || TREE_CODE (DECL_INITIAL (fn)) != BLOCK)
-    abort ();
+  gcc_assert (DECL_INITIAL (fn));
+  gcc_assert (TREE_CODE (DECL_INITIAL (fn)) == BLOCK);
 
   /* Find the lhs to which the result of this call is assigned.  */
   modify_dest = tsi_stmt (id->tsi);
@@ -1749,7 +1702,7 @@ expand_calls_inline (tree *stmt_p, inline_data *id)
 
     case COMPOUND_EXPR:
       /* We're gimple.  We should have gotten rid of all these.  */
-      abort ();
+      gcc_unreachable ();
 
     case RETURN_EXPR:
       stmt_p = &TREE_OPERAND (stmt, 0);
@@ -1841,8 +1794,7 @@ optimize_inline_calls (tree fn)
 
       /* Double check that we inlined everything we are supposed to inline.  */
       for (e = id.node->callees; e; e = e->next_callee)
-       if (!e->inline_failed)
-         abort ();
+       gcc_assert (e->inline_failed);
     }
 #endif
 }
@@ -1926,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;                                  \
     }                                                  \
@@ -1937,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;
 
@@ -1946,7 +1899,7 @@ walk_type_fields (tree type, walk_tree_fn func, void *data, void *htab)
     case POINTER_TYPE:
     case REFERENCE_TYPE:
       /* We have to worry about mutually recursive pointers.  These can't
-        be written in C.  They can in Ada.  It's pathlogical, but
+        be written in C.  They can in Ada.  It's pathological, but
         there's an ACATS test (c38102a) that checks it.  Deal with this
         by checking if we're pointing to another pointer, that one
         points to another pointer, that one does too, and we have no htab.
@@ -1955,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);
@@ -1989,7 +1942,7 @@ walk_type_fields (tree type, walk_tree_fn func, void *data, void *htab)
 
     case ARRAY_TYPE:
       /* Don't follow this nodes's type if a pointer for fear that we'll
-        have infinite recursion.  Those types are uninteresting anyway. */
+        have infinite recursion.  Those types are uninteresting anyway.  */
       if (!POINTER_TYPE_P (TREE_TYPE (type))
          && TREE_CODE (TREE_TYPE (type)) != OFFSET_TYPE)
        WALK_SUBTREE (TREE_TYPE (type));
@@ -2020,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;
@@ -2044,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;
@@ -2078,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;
 
@@ -2102,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;
 
@@ -2173,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;
     }
@@ -2276,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;
 }
 
@@ -2293,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)
@@ -2323,13 +2267,14 @@ 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) == 'd')
+  else if (TREE_CODE_CLASS (code) == tcc_declaration)
     *walk_subtrees = 0;
- else if (code == STATEMENT_LIST)
-    abort ();
-
+  else if (TREE_CODE_CLASS (code) == tcc_constant)
+    *walk_subtrees = 0;
+  else
+    gcc_assert (code != STATEMENT_LIST);
   return NULL_TREE;
 }
 
@@ -2395,6 +2340,31 @@ mark_local_for_remap_r (tree *tp, int *walk_subtrees ATTRIBUTE_UNUSED,
   return NULL_TREE;
 }
 
+/* Perform any modifications to EXPR required when it is unsaved.  Does
+   not recurse into EXPR's subtrees.  */
+
+static void
+unsave_expr_1 (tree expr)
+{
+  switch (TREE_CODE (expr))
+    {
+    case TARGET_EXPR:
+      /* Don't mess with a TARGET_EXPR that hasn't been expanded.
+         It's OK for this to happen if it was part of a subtree that
+         isn't immediately expanded, such as operand 2 of another
+         TARGET_EXPR.  */
+      if (TREE_OPERAND (expr, 1))
+       break;
+
+      TREE_OPERAND (expr, 1) = TREE_OPERAND (expr, 3);
+      TREE_OPERAND (expr, 3) = NULL_TREE;
+      break;
+
+    default:
+      break;
+    }
+}
+
 /* Called via walk_tree when an expression is unsaved.  Using the
    splay_tree pointed to by ST (which is really a `splay_tree'),
    remaps all local declarations to appropriate replacements.  */
@@ -2436,11 +2406,11 @@ unsave_r (tree *tp, int *walk_subtrees, void *data)
   return NULL_TREE;
 }
 
-/* Default lang hook for "unsave_expr_now".  Copies everything in EXPR and
-   replaces variables, labels and SAVE_EXPRs local to EXPR.  */
+/* Copies everything in EXPR and replaces variables, labels
+   and SAVE_EXPRs local to EXPR.  */
 
 tree
-lhd_unsave_expr_now (tree expr)
+unsave_expr_now (tree expr)
 {
   inline_data id;