OSDN Git Service

* cgraph.c (cgraph_mark_address_taken_node): No longer imply needed flag.
[pf3gnuchains/gcc-fork.git] / gcc / tree-inline.c
index aacd903..03b013c 100644 (file)
@@ -1,5 +1,5 @@
 /* Tree inlining.
-   Copyright 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009
+   Copyright 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010
    Free Software Foundation, Inc.
    Contributed by Alexandre Oliva <aoliva@redhat.com>
 
@@ -41,7 +41,6 @@ along with GCC; see the file COPYING3.  If not see
 #include "tree-mudflap.h"
 #include "tree-flow.h"
 #include "function.h"
-#include "ggc.h"
 #include "tree-flow.h"
 #include "diagnostic.h"
 #include "except.h"
@@ -102,10 +101,6 @@ along with GCC; see the file COPYING3.  If not see
      calls?  */
 
 
-/* Weights that estimate_num_insns uses for heuristics in inlining.  */
-
-eni_weights eni_inlining_weights;
-
 /* Weights that estimate_num_insns uses to estimate the size of the
    produced code.  */
 
@@ -171,6 +166,12 @@ insert_debug_decl_map (copy_body_data *id, tree key, tree value)
   *pointer_map_insert (id->debug_map, key) = value;
 }
 
+/* If nonzero, we're remapping the contents of inlined debug
+   statements.  If negative, an error has occurred, such as a
+   reference to a variable that isn't available in the inlined
+   context.  */
+static int processing_debug_stmt = 0;
+
 /* Construct new SSA name for old NAME. ID is the inline context.  */
 
 static tree
@@ -185,6 +186,12 @@ remap_ssa_name (tree name, copy_body_data *id)
   if (n)
     return unshare_expr (*n);
 
+  if (processing_debug_stmt)
+    {
+      processing_debug_stmt = -1;
+      return name;
+    }
+
   /* Do not set DEF_STMT yet as statement is not copied yet. We do that
      in copy_bb.  */
   new_tree = remap_decl (SSA_NAME_VAR (name), id);
@@ -199,11 +206,21 @@ remap_ssa_name (tree name, copy_body_data *id)
       && (TREE_CODE (SSA_NAME_VAR (name)) != RESULT_DECL
          || !id->transform_return_to_modify))
     {
+      struct ptr_info_def *pi;
       new_tree = make_ssa_name (new_tree, NULL);
       insert_decl_map (id, name, new_tree);
       SSA_NAME_OCCURS_IN_ABNORMAL_PHI (new_tree)
        = SSA_NAME_OCCURS_IN_ABNORMAL_PHI (name);
       TREE_TYPE (new_tree) = TREE_TYPE (SSA_NAME_VAR (new_tree));
+      /* At least IPA points-to info can be directly transferred.  */
+      if (id->src_cfun->gimple_df
+         && id->src_cfun->gimple_df->ipa_pta
+         && (pi = SSA_NAME_PTR_INFO (name))
+         && !pi->pt.anything)
+       {
+         struct ptr_info_def *new_pi = get_ptr_info (new_tree);
+         new_pi->pt = pi->pt;
+       }
       if (gimple_nop_p (SSA_NAME_DEF_STMT (name)))
        {
          /* By inlining function having uninitialized variable, we might
@@ -244,12 +261,6 @@ remap_ssa_name (tree name, copy_body_data *id)
   return new_tree;
 }
 
-/* If nonzero, we're remapping the contents of inlined debug
-   statements.  If negative, an error has occurred, such as a
-   reference to a variable that isn't available in the inlined
-   context.  */
-int processing_debug_stmt = 0;
-
 /* Remap DECL during the copying of the BLOCK tree for the function.  */
 
 tree
@@ -305,17 +316,7 @@ remap_decl (tree decl, copy_body_data *id)
          && (TREE_CODE (t) == VAR_DECL
              || TREE_CODE (t) == RESULT_DECL || TREE_CODE (t) == PARM_DECL))
        {
-          tree def = gimple_default_def (id->src_cfun, decl);
          get_var_ann (t);
-         if (TREE_CODE (decl) != PARM_DECL && def)
-           {
-             tree map = remap_ssa_name (def, id);
-             /* Watch out RESULT_DECLs whose SSA names map directly
-                to them.  */
-             if (TREE_CODE (map) == SSA_NAME
-                 && gimple_nop_p (SSA_NAME_DEF_STMT (map)))
-               set_default_def (t, map);
-           }
          add_referenced_var (t);
        }
       return t;
@@ -537,7 +538,6 @@ remap_decls (tree decls, VEC(tree,gc) **nonlocalized_list, copy_body_data *id)
   for (old_var = decls; old_var; old_var = TREE_CHAIN (old_var))
     {
       tree new_var;
-      tree origin_var = DECL_ORIGIN (old_var);
 
       if (can_be_nonlocal (old_var, id))
        {
@@ -549,7 +549,7 @@ remap_decls (tree decls, VEC(tree,gc) **nonlocalized_list, copy_body_data *id)
          if ((!optimize || debug_info_level > DINFO_LEVEL_TERSE)
              && !DECL_IGNORED_P (old_var)
              && nonlocalized_list)
-           VEC_safe_push (tree, gc, *nonlocalized_list, origin_var);
+           VEC_safe_push (tree, gc, *nonlocalized_list, old_var);
          continue;
        }
 
@@ -567,7 +567,7 @@ remap_decls (tree decls, VEC(tree,gc) **nonlocalized_list, copy_body_data *id)
          if ((!optimize || debug_info_level > DINFO_LEVEL_TERSE)
              && !DECL_IGNORED_P (old_var)
              && nonlocalized_list)
-           VEC_safe_push (tree, gc, *nonlocalized_list, origin_var);
+           VEC_safe_push (tree, gc, *nonlocalized_list, old_var);
        }
       else
        {
@@ -665,16 +665,30 @@ copy_bind_expr (tree *tp, int *walk_subtrees, copy_body_data *id)
     }
 
   if (BIND_EXPR_VARS (*tp))
-    /* This will remap a lot of the same decls again, but this should be
-       harmless.  */
-    BIND_EXPR_VARS (*tp) = remap_decls (BIND_EXPR_VARS (*tp), NULL, id);
+    {
+      tree t;
+
+      /* This will remap a lot of the same decls again, but this should be
+        harmless.  */
+      BIND_EXPR_VARS (*tp) = remap_decls (BIND_EXPR_VARS (*tp), NULL, id);
+      /* Also copy value-expressions.  */
+      for (t = BIND_EXPR_VARS (*tp); t; t = TREE_CHAIN (t))
+       if (TREE_CODE (t) == VAR_DECL
+           && DECL_HAS_VALUE_EXPR_P (t))
+         {
+           tree tem = DECL_VALUE_EXPR (t);
+           walk_tree (&tem, copy_tree_body_r, id, NULL);
+           SET_DECL_VALUE_EXPR (t, tem);
+         }
+    }
 }
 
 
 /* Create a new gimple_seq by remapping all the statements in BODY
    using the inlining information in ID.  */
 
-gimple_seq
+static gimple_seq
 remap_gimple_seq (gimple_seq body, copy_body_data *id)
 {
   gimple_stmt_iterator si;
@@ -1396,6 +1410,12 @@ remap_gimple_stmt (gimple stmt, copy_body_data *id)
                  default:
                    break;
                  }
+
+             /* Reset alias info if we didn't apply measures to
+                keep it valid over inlining by setting DECL_PT_UID.  */
+             if (!id->src_cfun->gimple_df
+                 || !id->src_cfun->gimple_df->ipa_pta)
+               gimple_call_reset_alias_info (copy);
            }
            break;
 
@@ -1655,6 +1675,7 @@ copy_bb (copy_body_data *id, basic_block bb, int frequency_scale,
                                   bb->frequency,
                                   copy_basic_block->frequency);
                        }
+                     stmt = cgraph_redirect_edge_call_stmt_to_callee (edge);
                    }
                  break;
 
@@ -1677,9 +1698,8 @@ copy_bb (copy_body_data *id, basic_block bb, int frequency_scale,
              /* Constant propagation on argument done during inlining
                 may create new direct call.  Produce an edge for it.  */
              if ((!edge
-                  || (edge->indirect_call
+                  || (edge->indirect_inlining_edge
                       && id->transform_call_graph_edges == CB_CGE_MOVE_CLONES))
-                 && is_gimple_call (stmt)
                  && (fn = gimple_call_fndecl (stmt)) != NULL)
                {
                  struct cgraph_node *dest = cgraph_node (fn);
@@ -1691,6 +1711,7 @@ copy_bb (copy_body_data *id, basic_block bb, int frequency_scale,
                     other cases we hit a bug (incorrect node sharing is the
                     most common reason for missing edges).  */
                  gcc_assert (dest->needed || !dest->analyzed
+                             || dest->address_taken
                              || !id->src_node->analyzed);
                  if (id->transform_call_graph_edges == CB_CGE_MOVE_CLONES)
                    cgraph_create_edge_including_clones
@@ -2003,7 +2024,6 @@ initialize_cfun (tree new_fndecl, tree callee_fndecl, gcov_type count)
   cfun->last_verified = src_cfun->last_verified;
   cfun->va_list_gpr_size = src_cfun->va_list_gpr_size;
   cfun->va_list_fpr_size = src_cfun->va_list_fpr_size;
-  cfun->function_frequency = src_cfun->function_frequency;
   cfun->has_nonlocal_label = src_cfun->has_nonlocal_label;
   cfun->stdarg = src_cfun->stdarg;
   cfun->dont_save_pending_sizes_p = src_cfun->dont_save_pending_sizes_p;
@@ -2154,6 +2174,12 @@ copy_debug_stmt (gimple stmt, copy_body_data *id)
       gcc_assert (TREE_CODE (*n) == VAR_DECL);
       t = *n;
     }
+  else if (TREE_CODE (t) == VAR_DECL
+          && !TREE_STATIC (t)
+          && gimple_in_ssa_p (cfun)
+          && !pointer_map_contains (id->decl_map, t)
+          && !var_ann (t))
+    /* T is a non-localized variable.  */;
   else
     walk_tree (&t, remap_gimple_op_r, &wi, NULL);
 
@@ -2540,9 +2566,16 @@ declare_return_variable (copy_body_data *id, tree return_slot, tree modify_dest)
   tree caller = id->dst_fn;
   tree result = DECL_RESULT (callee);
   tree callee_type = TREE_TYPE (result);
-  tree caller_type = TREE_TYPE (TREE_TYPE (callee));
+  tree caller_type;
   tree var, use;
 
+  /* Handle type-mismatches in the function declaration return type
+     vs. the call expression.  */
+  if (modify_dest)
+    caller_type = TREE_TYPE (modify_dest);
+  else
+    caller_type = TREE_TYPE (TREE_TYPE (callee));
+
   /* We don't need to do anything for functions that don't return
      anything.  */
   if (!result || VOID_TYPE_P (callee_type))
@@ -2718,39 +2751,6 @@ has_label_address_in_static_1 (tree *nodep, int *walk_subtrees, void *fnp)
   return NULL_TREE;
 }
 
-/* Callback through walk_tree.  Determine if we've got an aggregate
-   type that we can't support; return non-null if so.  */
-
-static tree
-cannot_copy_type_1 (tree *nodep, int *walk_subtrees ATTRIBUTE_UNUSED,
-                    void *data ATTRIBUTE_UNUSED)
-{
-  tree t, node = *nodep;
-
-  if (TREE_CODE (node) == RECORD_TYPE || TREE_CODE (node) == UNION_TYPE)
-    {
-      /* We cannot inline a function of the form
-
-          void F (int i) { struct S { int ar[i]; } s; }
-
-        Attempting to do so produces a catch-22.
-        If walk_tree examines the TYPE_FIELDS chain of RECORD_TYPE/
-        UNION_TYPE nodes, then it goes into infinite recursion on a
-        structure containing a pointer to its own type.  If it doesn't,
-        then the type node for S doesn't get adjusted properly when
-        F is inlined.
-
-        ??? This is likely no longer true, but it's too late in the 4.0
-        cycle to try to find out.  This should be checked for 4.1.  */
-      for (t = TYPE_FIELDS (node); t; t = TREE_CHAIN (t))
-       if (variably_modified_type_p (TREE_TYPE (t), NULL))
-         return node;
-    }
-
-  return NULL_TREE;
-}
-
-
 /* Determine if the function can be copied.  If so return NULL.  If
    not return a string describng the reason for failure.  */
 
@@ -2793,16 +2793,6 @@ copy_forbidden (struct function *fun, tree fndecl)
                      "address of local label in a static variable");
          goto fail;
        }
-
-      if (!TREE_STATIC (decl) && !DECL_EXTERNAL (decl)
-         && variably_modified_type_p (TREE_TYPE (decl), NULL)
-         && walk_tree_without_duplicates (&TREE_TYPE (decl),
-                                          cannot_copy_type_1, NULL))
-       {
-         reason = G_("function %q+F can never be copied "
-                     "because it uses variable sized variables");
-         goto fail;
-       }
     }
 
  fail:
@@ -3288,12 +3278,89 @@ estimate_num_insns (gimple stmt, eni_weights *weights)
        if (decl && DECL_BUILT_IN_CLASS (decl) == BUILT_IN_NORMAL)
          switch (DECL_FUNCTION_CODE (decl))
            {
+           /* Builtins that expand to constants.  */
            case BUILT_IN_CONSTANT_P:
-             return 0;
            case BUILT_IN_EXPECT:
+           case BUILT_IN_OBJECT_SIZE:
+           case BUILT_IN_UNREACHABLE:
+           /* Simple register moves or loads from stack.  */
+           case BUILT_IN_RETURN_ADDRESS:
+           case BUILT_IN_EXTRACT_RETURN_ADDR:
+           case BUILT_IN_FROB_RETURN_ADDR:
+           case BUILT_IN_RETURN:
+           case BUILT_IN_AGGREGATE_INCOMING_ADDRESS:
+           case BUILT_IN_FRAME_ADDRESS:
+           case BUILT_IN_VA_END:
+           case BUILT_IN_STACK_SAVE:
+           case BUILT_IN_STACK_RESTORE:
+           /* Exception state returns or moves registers around.  */
+           case BUILT_IN_EH_FILTER:
+           case BUILT_IN_EH_POINTER:
+           case BUILT_IN_EH_COPY_VALUES:
              return 0;
 
-           /* Prefetch instruction is not expensive.  */
+           /* builtins that are not expensive (that is they are most probably
+              expanded inline into resonably simple code).  */
+           case BUILT_IN_ABS:
+           case BUILT_IN_ALLOCA:
+           case BUILT_IN_BSWAP32:
+           case BUILT_IN_BSWAP64:
+           case BUILT_IN_CLZ:
+           case BUILT_IN_CLZIMAX:
+           case BUILT_IN_CLZL:
+           case BUILT_IN_CLZLL:
+           case BUILT_IN_CTZ:
+           case BUILT_IN_CTZIMAX:
+           case BUILT_IN_CTZL:
+           case BUILT_IN_CTZLL:
+           case BUILT_IN_FFS:
+           case BUILT_IN_FFSIMAX:
+           case BUILT_IN_FFSL:
+           case BUILT_IN_FFSLL:
+           case BUILT_IN_IMAXABS:
+           case BUILT_IN_FINITE:
+           case BUILT_IN_FINITEF:
+           case BUILT_IN_FINITEL:
+           case BUILT_IN_FINITED32:
+           case BUILT_IN_FINITED64:
+           case BUILT_IN_FINITED128:
+           case BUILT_IN_FPCLASSIFY:
+           case BUILT_IN_ISFINITE:
+           case BUILT_IN_ISINF_SIGN:
+           case BUILT_IN_ISINF:
+           case BUILT_IN_ISINFF:
+           case BUILT_IN_ISINFL:
+           case BUILT_IN_ISINFD32:
+           case BUILT_IN_ISINFD64:
+           case BUILT_IN_ISINFD128:
+           case BUILT_IN_ISNAN:
+           case BUILT_IN_ISNANF:
+           case BUILT_IN_ISNANL:
+           case BUILT_IN_ISNAND32:
+           case BUILT_IN_ISNAND64:
+           case BUILT_IN_ISNAND128:
+           case BUILT_IN_ISNORMAL:
+           case BUILT_IN_ISGREATER:
+           case BUILT_IN_ISGREATEREQUAL:
+           case BUILT_IN_ISLESS:
+           case BUILT_IN_ISLESSEQUAL:
+           case BUILT_IN_ISLESSGREATER:
+           case BUILT_IN_ISUNORDERED:
+           case BUILT_IN_VA_ARG_PACK:
+           case BUILT_IN_VA_ARG_PACK_LEN:
+           case BUILT_IN_VA_COPY:
+           case BUILT_IN_TRAP:
+           case BUILT_IN_SAVEREGS:
+           case BUILT_IN_POPCOUNTL:
+           case BUILT_IN_POPCOUNTLL:
+           case BUILT_IN_POPCOUNTIMAX:
+           case BUILT_IN_POPCOUNT:
+           case BUILT_IN_PARITYL:
+           case BUILT_IN_PARITYLL:
+           case BUILT_IN_PARITYIMAX:
+           case BUILT_IN_PARITY:
+           case BUILT_IN_LABS:
+           case BUILT_IN_LLABS:
            case BUILT_IN_PREFETCH:
              cost = weights->target_builtin_call_cost;
              break;
@@ -3486,7 +3553,7 @@ get_indirect_callee_fndecl (struct cgraph_node *node, gimple stmt)
   struct cgraph_edge *cs;
 
   cs = cgraph_edge (node, stmt);
-  if (cs)
+  if (cs && !cs->indirect_unknown_callee)
     return cs->callee->decl;
 
   return NULL_TREE;
@@ -3569,7 +3636,7 @@ expand_call_inline (basic_block bb, gimple stmt, copy_body_data *id)
       /* If this call was originally indirect, we do not want to emit any
         inlining related warnings or sorry messages because there are no
         guarantees regarding those.  */
-      if (cg_edge->indirect_call)
+      if (cg_edge->indirect_inlining_edge)
        goto egress;
 
       if (lookup_attribute ("always_inline", DECL_ATTRIBUTES (fn))
@@ -3752,12 +3819,9 @@ expand_call_inline (basic_block bb, gimple stmt, copy_body_data *id)
             cg_edge->frequency * REG_BR_PROB_BASE / CGRAPH_FREQ_BASE,
             bb, return_block);
 
-  /* Reset the escaped and callused solutions.  */
+  /* Reset the escaped solution.  */
   if (cfun->gimple_df)
-    {
-      pt_solution_reset (&cfun->gimple_df->escaped);
-      pt_solution_reset (&cfun->gimple_df->callused);
-    }
+    pt_solution_reset (&cfun->gimple_df->escaped);
 
   /* Clean up.  */
   if (id->debug_map)
@@ -4540,6 +4604,8 @@ copy_decl_to_var (tree decl, copy_body_data *id)
 
   copy = build_decl (DECL_SOURCE_LOCATION (id->dst_fn),
                     VAR_DECL, DECL_NAME (decl), type);
+  if (DECL_PT_UID_SET_P (decl))
+    SET_DECL_PT_UID (copy, DECL_PT_UID (decl));
   TREE_ADDRESSABLE (copy) = TREE_ADDRESSABLE (decl);
   TREE_READONLY (copy) = TREE_READONLY (decl);
   TREE_THIS_VOLATILE (copy) = TREE_THIS_VOLATILE (decl);
@@ -4565,6 +4631,8 @@ copy_result_decl_to_var (tree decl, copy_body_data *id)
 
   copy = build_decl (DECL_SOURCE_LOCATION (id->dst_fn),
                     VAR_DECL, DECL_NAME (decl), type);
+  if (DECL_PT_UID_SET_P (decl))
+    SET_DECL_PT_UID (copy, DECL_PT_UID (decl));
   TREE_READONLY (copy) = TREE_READONLY (decl);
   TREE_THIS_VOLATILE (copy) = TREE_THIS_VOLATILE (decl);
   if (!DECL_BY_REFERENCE (decl))
@@ -4857,6 +4925,8 @@ tree_function_versioning (tree old_decl, tree new_decl,
     (DECL_STRUCT_FUNCTION (old_decl));
   initialize_cfun (new_decl, old_decl,
                   old_entry_block->count);
+  DECL_STRUCT_FUNCTION (new_decl)->gimple_df->ipa_pta
+    = id.src_cfun->gimple_df->ipa_pta;
   push_cfun (DECL_STRUCT_FUNCTION (new_decl));
 
   /* Copy the function's static chain.  */
@@ -4968,6 +5038,8 @@ tree_function_versioning (tree old_decl, tree new_decl,
   pointer_set_destroy (id.statements_to_fold);
   fold_cond_expr_cond ();
   delete_unreachable_blocks_update_callgraph (&id);
+  if (id.dst_node->analyzed)
+    cgraph_rebuild_references ();
   update_ssa (TODO_update_ssa);
   free_dominance_info (CDI_DOMINATORS);
   free_dominance_info (CDI_POST_DOMINATORS);
@@ -5094,7 +5166,7 @@ tree_can_inline_p (struct cgraph_edge *e)
        return false;
     }
 #endif
-  tree caller, callee;
+  tree caller, callee, lhs;
 
   caller = e->caller->decl;
   callee = e->callee->decl;
@@ -5120,8 +5192,16 @@ tree_can_inline_p (struct cgraph_edge *e)
       return false;
     }
 
+  /* Do not inline calls where we cannot triviall work around mismatches
+     in argument or return types.  */
   if (e->call_stmt
-      && !gimple_check_call_args (e->call_stmt))
+      && ((DECL_RESULT (callee)
+          && !DECL_BY_REFERENCE (DECL_RESULT (callee))
+          && (lhs = gimple_call_lhs (e->call_stmt)) != NULL_TREE
+          && !useless_type_conversion_p (TREE_TYPE (DECL_RESULT (callee)),
+                                         TREE_TYPE (lhs))
+          && !fold_convertible_p (TREE_TYPE (DECL_RESULT (callee)), lhs))
+         || !gimple_check_call_args (e->call_stmt)))
     {
       e->inline_failed = CIF_MISMATCHED_ARGUMENTS;
       gimple_call_set_cannot_inline (e->call_stmt, true);