ipa-cp.c (ipcp_print_edge_profiles): Test for node->analyzed rather than for DECL_SAV...
[gcc.git] / gcc / tree-inline.c
index 091a45a1439277adbcc091ada2bf30035d41003e..b5eb033588e429c08d6e7c6322891a5c213ba880 100644 (file)
@@ -192,7 +192,7 @@ remap_ssa_name (tree name, copy_body_data *id)
          /* By inlining function having uninitialized variable, we might
             extend the lifetime (variable might get reused).  This cause
             ICE in the case we end up extending lifetime of SSA name across
-            abnormal edge, but also increase register presure.
+            abnormal edge, but also increase register pressure.
 
             We simply initialize all uninitialized vars by 0 except for case
             we are inlining to very first BB.  We can avoid this for all
@@ -442,14 +442,14 @@ remap_decls (tree decls, copy_body_data *id)
     {
       tree new_var;
 
-      /* We can not chain the local static declarations into the unexpanded_var_list
+      /* We can not chain the local static declarations into the local_decls
          as we can't duplicate them or break one decl rule.  Go ahead and link
-         them into unexpanded_var_list.  */
+         them into local_decls.  */
       if (!auto_var_in_fn_p (old_var, id->src_fn)
          && !DECL_EXTERNAL (old_var))
        {
-         cfun->unexpanded_var_list = tree_cons (NULL_TREE, old_var,
-                                                cfun->unexpanded_var_list);
+         cfun->local_decls = tree_cons (NULL_TREE, old_var,
+                                                cfun->local_decls);
          continue;
        }
 
@@ -671,7 +671,7 @@ copy_body_r (tree *tp, int *walk_subtrees, void *data)
            {
              value = *n;
              STRIP_TYPE_NOPS (value);
-             if (TREE_CONSTANT (value) || TREE_READONLY_DECL_P (value))
+             if (TREE_CONSTANT (value) || TREE_READONLY (value))
                {
                  *tp = build_empty_stmt ();
                  return copy_body_r (tp, walk_subtrees, data);
@@ -715,6 +715,7 @@ copy_body_r (tree *tp, int *walk_subtrees, void *data)
                    {
                      *tp = build1 (INDIRECT_REF, type, new);
                      TREE_THIS_VOLATILE (*tp) = TREE_THIS_VOLATILE (old);
+                     TREE_SIDE_EFFECTS (*tp) = TREE_SIDE_EFFECTS (old);
                    }
                }
              *walk_subtrees = 0;
@@ -795,7 +796,8 @@ copy_body_r (tree *tp, int *walk_subtrees, void *data)
    later  */
 
 static basic_block
-copy_bb (copy_body_data *id, basic_block bb, int frequency_scale, int count_scale)
+copy_bb (copy_body_data *id, basic_block bb, int frequency_scale,
+         gcov_type count_scale)
 {
   block_stmt_iterator bsi, copy_bsi;
   basic_block copy_basic_block;
@@ -949,7 +951,7 @@ copy_bb (copy_body_data *id, basic_block bb, int frequency_scale, int count_scal
                pointer_set_insert (id->statements_to_fold, stmt);
              /* We're duplicating a CALL_EXPR.  Find any corresponding
                 callgraph edges and update or duplicate them.  */
-             if (call && (decl = get_callee_fndecl (call)))
+             if (call)
                {
                  struct cgraph_node *node;
                  struct cgraph_edge *edge;
@@ -960,7 +962,8 @@ copy_bb (copy_body_data *id, basic_block bb, int frequency_scale, int count_scal
                      edge = cgraph_edge (id->src_node, orig_stmt);
                      if (edge)
                        cgraph_clone_edge (edge, id->dst_node, stmt,
-                                          REG_BR_PROB_BASE, 1, edge->frequency, true);
+                                          REG_BR_PROB_BASE, 1,
+                                          edge->frequency, true);
                      break;
 
                    case CB_CGE_MOVE_CLONES:
@@ -969,8 +972,8 @@ copy_bb (copy_body_data *id, basic_block bb, int frequency_scale, int count_scal
                           node = node->next_clone)
                        {
                          edge = cgraph_edge (node, orig_stmt);
-                         gcc_assert (edge);
-                         cgraph_set_call_stmt (edge, stmt);
+                         if (edge)
+                           cgraph_set_call_stmt (edge, stmt);
                        }
                      /* FALLTHRU */
 
@@ -1108,7 +1111,7 @@ update_ssa_across_abnormal_edges (basic_block bb, basic_block ret_bb,
    accordingly.  Edges will be taken care of later.  Assume aux
    pointers to point to the copies of each BB.  */
 static void
-copy_edges_for_bb (basic_block bb, int count_scale, basic_block ret_bb)
+copy_edges_for_bb (basic_block bb, gcov_type count_scale, basic_block ret_bb)
 {
   basic_block new_bb = (basic_block) bb->aux;
   edge_iterator ei;
@@ -1199,7 +1202,7 @@ copy_edges_for_bb (basic_block bb, int count_scale, basic_block ret_bb)
 static void
 copy_phis_for_bb (basic_block bb, copy_body_data *id)
 {
-  basic_block new_bb = bb->aux;
+  basic_block const new_bb = (basic_block) bb->aux;
   edge_iterator ei;
   tree phi;
 
@@ -1217,7 +1220,7 @@ copy_phis_for_bb (basic_block bb, copy_body_data *id)
            = new_phi = create_phi_node (new_res, new_bb);
          FOR_EACH_EDGE (new_edge, ei, new_bb->preds)
            {
-             edge old_edge = find_edge (new_edge->src->aux, bb);
+             edge const old_edge = find_edge ((basic_block) new_edge->src->aux, bb);
              tree arg = PHI_ARG_DEF_FROM_EDGE (phi, old_edge);
              tree new_arg = arg;
 
@@ -1257,7 +1260,7 @@ initialize_cfun (tree new_fndecl, tree callee_fndecl, gcov_type count,
   struct function *new_cfun
      = (struct function *) ggc_alloc_cleared (sizeof (struct function));
   struct function *src_cfun = DECL_STRUCT_FUNCTION (callee_fndecl);
-  int count_scale, frequency_scale;
+  gcov_type count_scale, frequency_scale;
 
   if (ENTRY_BLOCK_PTR_FOR_FUNCTION (src_cfun)->count)
     count_scale = (REG_BR_PROB_BASE * count
@@ -1277,7 +1280,7 @@ initialize_cfun (tree new_fndecl, tree callee_fndecl, gcov_type count,
   *new_cfun = *DECL_STRUCT_FUNCTION (callee_fndecl);
   new_cfun->funcdef_no = get_next_funcdef_no ();
   VALUE_HISTOGRAMS (new_cfun) = NULL;
-  new_cfun->unexpanded_var_list = NULL;
+  new_cfun->local_decls = NULL;
   new_cfun->cfg = NULL;
   new_cfun->decl = new_fndecl /*= copy_node (callee_fndecl)*/;
   DECL_STRUCT_FUNCTION (new_fndecl) = new_cfun;
@@ -1301,7 +1304,7 @@ initialize_cfun (tree new_fndecl, tree callee_fndecl, gcov_type count,
 
   if (src_cfun->gimple_df)
     {
-      init_tree_ssa ();
+      init_tree_ssa (cfun);
       cfun->gimple_df->in_ssa_p = true;
       init_ssa_operands ();
     }
@@ -1321,7 +1324,7 @@ copy_cfg_body (copy_body_data * id, gcov_type count, int frequency,
   struct function *cfun_to_copy;
   basic_block bb;
   tree new_fndecl = NULL;
-  int count_scale, frequency_scale;
+  gcov_type count_scale, frequency_scale;
   int last;
 
   if (ENTRY_BLOCK_PTR_FOR_FUNCTION (src_cfun)->count)
@@ -1440,7 +1443,6 @@ setup_one_parameter (copy_body_data *id, tree p, tree value, tree fn,
 {
   tree init_stmt;
   tree var;
-  tree var_sub;
   tree rhs = value;
   tree def = (gimple_in_ssa_p (cfun)
              ? gimple_default_def (id->src_cfun, p) : NULL);
@@ -1496,23 +1498,10 @@ setup_one_parameter (copy_body_data *id, tree p, tree value, tree fn,
       add_referenced_var (var);
     }
 
-  /* See if the frontend wants to pass this by invisible reference.  If
-     so, our new VAR_DECL will have REFERENCE_TYPE, and we need to
-     replace uses of the PARM_DECL with dereferences.  */
-  if (TREE_TYPE (var) != TREE_TYPE (p)
-      && POINTER_TYPE_P (TREE_TYPE (var))
-      && TREE_TYPE (TREE_TYPE (var)) == TREE_TYPE (p))
-    {
-      insert_decl_map (id, var, var);
-      var_sub = build_fold_indirect_ref (var);
-    }
-  else
-    var_sub = var;
-
   /* Register the VAR_DECL as the equivalent for the PARM_DECL;
      that way, when the PARM_DECL is encountered, it will be
      automatically replaced by the VAR_DECL.  */
-  insert_decl_map (id, p, var_sub);
+  insert_decl_map (id, p, var);
 
   /* Declare this new variable.  */
   TREE_CHAIN (var) = *vars;
@@ -1572,7 +1561,7 @@ setup_one_parameter (copy_body_data *id, tree p, tree value, tree fn,
 
       if (rhs == error_mark_node)
        {
-         insert_decl_map (id, p, var_sub);
+         insert_decl_map (id, p, var);
          return;
        }
 
@@ -1602,8 +1591,9 @@ setup_one_parameter (copy_body_data *id, tree p, tree value, tree fn,
          || !is_gimple_reg (var))
        {
           tree_stmt_iterator i;
+          struct gimplify_ctx gctx;
 
-         push_gimplify_context ();
+         push_gimplify_context (&gctx);
          gimplify_stmt (&init_stmt);
          if (gimple_in_ssa_p (cfun)
               && init_stmt && TREE_CODE (init_stmt) == STATEMENT_LIST)
@@ -1617,7 +1607,7 @@ setup_one_parameter (copy_body_data *id, tree p, tree value, tree fn,
        }
 
       /* If VAR represents a zero-sized variable, it's possible that the
-        assignment statment may result in no gimple statements.  */
+        assignment statement may result in no gimple statements.  */
       if (init_stmt)
         bsi_insert_after (&bsi, init_stmt, BSI_NEW_STMT);
       if (gimple_in_ssa_p (cfun))
@@ -1811,9 +1801,9 @@ declare_return_variable (copy_body_data *id, tree return_slot, tree modify_dest,
     }
 
   DECL_SEEN_IN_BIND_EXPR_P (var) = 1;
-  DECL_STRUCT_FUNCTION (caller)->unexpanded_var_list
+  DECL_STRUCT_FUNCTION (caller)->local_decls
     = tree_cons (NULL_TREE, var,
-                DECL_STRUCT_FUNCTION (caller)->unexpanded_var_list);
+                DECL_STRUCT_FUNCTION (caller)->local_decls);
 
   /* Do not have the rest of GCC warn about this variable as it should
      not be visible to the user.  */
@@ -2040,7 +2030,7 @@ inline_forbidden_p (tree fndecl)
          goto egress;
       }
 
-  for (step = fun->unexpanded_var_list; step; step = TREE_CHAIN (step))
+  for (step = fun->local_decls; step; step = TREE_CHAIN (step))
     {
       tree decl = TREE_VALUE (step);
       if (TREE_CODE (decl) == VAR_DECL
@@ -2185,7 +2175,7 @@ struct eni_data
 static tree
 estimate_num_insns_1 (tree *tp, int *walk_subtrees, void *data)
 {
-  struct eni_data *d = data;
+  struct eni_data *const d = (struct eni_data *) data;
   tree x = *tp;
   unsigned cost;
 
@@ -2220,8 +2210,7 @@ estimate_num_insns_1 (tree *tp, int *walk_subtrees, void *data)
     case BIND_EXPR:
     case WITH_CLEANUP_EXPR:
     case PAREN_EXPR:
-    case NOP_EXPR:
-    case CONVERT_EXPR:
+    CASE_CONVERT:
     case VIEW_CONVERT_EXPR:
     case SAVE_EXPR:
     case ADDR_EXPR:
@@ -2233,7 +2222,6 @@ estimate_num_insns_1 (tree *tp, int *walk_subtrees, void *data)
     case EH_FILTER_EXPR:
     case STATEMENT_LIST:
     case ERROR_MARK:
-    case NON_LVALUE_EXPR:
     case FDESC_EXPR:
     case VA_ARG_EXPR:
     case TRY_CATCH_EXPR:
@@ -2494,6 +2482,7 @@ estimate_num_insns_1 (tree *tp, int *walk_subtrees, void *data)
       }
 
     case OMP_PARALLEL:
+    case OMP_TASK:
     case OMP_FOR:
     case OMP_SECTIONS:
     case OMP_SINGLE:
@@ -2592,6 +2581,20 @@ add_lexical_block (tree current_block, tree new_block)
   BLOCK_SUPERCONTEXT (new_block) = current_block;
 }
 
+/* Fetch callee declaration from the call graph edge going from NODE and
+   associated with STMR call statement.  Return NULL_TREE if not found.  */
+static tree
+get_indirect_callee_fndecl (struct cgraph_node *node, tree stmt)
+{
+  struct cgraph_edge *cs;
+
+  cs = cgraph_edge (node, stmt);
+  if (cs)
+    return cs->callee->decl;
+
+  return NULL_TREE;
+}
+
 /* If *TP is a CALL_EXPR, replace it with its inline expansion.  */
 
 static bool
@@ -2633,7 +2636,11 @@ expand_call_inline (basic_block bb, tree stmt, tree *tp, void *data)
      If we cannot, then there is no hope of inlining the function.  */
   fn = get_callee_fndecl (t);
   if (!fn)
-    goto egress;
+    {
+      fn = get_indirect_callee_fndecl (id->dst_node, stmt);
+      if (!fn)
+       goto egress;
+    }
 
   /* Turn forward declarations into real ones.  */
   fn = cgraph_node (fn)->decl;
@@ -2684,6 +2691,12 @@ expand_call_inline (basic_block bb, tree stmt, tree *tp, void *data)
      inlining.  */
   if (!cgraph_inline_p (cg_edge, &reason))
     {
+      /* 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)
+       goto egress;
+
       if (lookup_attribute ("always_inline", DECL_ATTRIBUTES (fn))
          /* Avoid warnings during early inline pass. */
          && (!flag_unit_at_a_time || cgraph_global_info_ready))
@@ -2831,16 +2844,16 @@ expand_call_inline (basic_block bb, tree stmt, tree *tp, void *data)
   copy_body (id, bb->count, bb->frequency, bb, return_block);
 
   /* Add local vars in this inlined callee to caller.  */
-  t_step = id->src_cfun->unexpanded_var_list;
+  t_step = id->src_cfun->local_decls;
   for (; t_step; t_step = TREE_CHAIN (t_step))
     {
       var = TREE_VALUE (t_step);
       if (TREE_STATIC (var) && !TREE_ASM_WRITTEN (var))
-       cfun->unexpanded_var_list = tree_cons (NULL_TREE, var,
-                                              cfun->unexpanded_var_list);
+       cfun->local_decls = tree_cons (NULL_TREE, var,
+                                              cfun->local_decls);
       else
-       cfun->unexpanded_var_list = tree_cons (NULL_TREE, remap_decl (var, id),
-                                              cfun->unexpanded_var_list);
+       cfun->local_decls = tree_cons (NULL_TREE, remap_decl (var, id),
+                                              cfun->local_decls);
     }
 
   /* Clean up.  */
@@ -2868,15 +2881,15 @@ expand_call_inline (basic_block bb, tree stmt, tree *tp, void *data)
       if (TREE_CODE (stmt) == GIMPLE_MODIFY_STMT
          && TREE_CODE (GIMPLE_STMT_OPERAND (stmt, 0)) == SSA_NAME)
        {
-         tree name = TREE_OPERAND (stmt, 0);
-         tree var = SSA_NAME_VAR (TREE_OPERAND (stmt, 0));
+         tree name = GIMPLE_STMT_OPERAND (stmt, 0);
+         tree var = SSA_NAME_VAR (GIMPLE_STMT_OPERAND (stmt, 0));
          tree def = gimple_default_def (cfun, var);
 
          /* If the variable is used undefined, make this name undefined via
             move.  */
          if (def)
            {
-             TREE_OPERAND (stmt, 1) = def;
+             GIMPLE_STMT_OPERAND (stmt, 1) = def;
              update_stmt (stmt);
            }
          /* Otherwise make this variable undefined.  */
@@ -2999,6 +3012,8 @@ optimize_inline_calls (tree fn)
   tree prev_fn;
   basic_block bb;
   int last = n_basic_blocks;
+  struct gimplify_ctx gctx;
+
   /* There is no point in performing inlining if errors have already
      occurred -- and we might crash if we try to inline invalid
      code.  */
@@ -3025,7 +3040,7 @@ optimize_inline_calls (tree fn)
   id.transform_lang_insert_block = NULL;
   id.statements_to_fold = pointer_set_create ();
 
-  push_gimplify_context ();
+  push_gimplify_context (&gctx);
 
   /* We make no attempts to keep dominance info up-to-date.  */
   free_dominance_info (CDI_DOMINATORS);
@@ -3340,9 +3355,7 @@ declare_inline_vars (tree block, tree vars)
     {
       DECL_SEEN_IN_BIND_EXPR_P (t) = 1;
       gcc_assert (!TREE_STATIC (t) && !TREE_ASM_WRITTEN (t));
-      cfun->unexpanded_var_list =
-       tree_cons (NULL_TREE, t,
-                  cfun->unexpanded_var_list);
+      cfun->local_decls = tree_cons (NULL_TREE, t, cfun->local_decls);
     }
 
   if (block)
@@ -3604,7 +3617,7 @@ tree_function_versioning (tree old_decl, tree new_decl, varray_type tree_map,
   if (tree_map)
     for (i = 0; i < VARRAY_ACTIVE_SIZE (tree_map); i++)
       {
-       replace_info = VARRAY_GENERIC_PTR (tree_map, i);
+       replace_info = (struct ipa_replace_map *) VARRAY_GENERIC_PTR (tree_map, i);
        if (replace_info->replace_p)
          insert_decl_map (&id, replace_info->old_tree,
                           replace_info->new_tree);
@@ -3615,19 +3628,18 @@ tree_function_versioning (tree old_decl, tree new_decl, varray_type tree_map,
   /* Renumber the lexical scoping (non-code) blocks consecutively.  */
   number_blocks (id.dst_fn);
   
-  if (DECL_STRUCT_FUNCTION (old_decl)->unexpanded_var_list != NULL_TREE)
+  if (DECL_STRUCT_FUNCTION (old_decl)->local_decls != NULL_TREE)
     /* Add local vars.  */
-    for (t_step = DECL_STRUCT_FUNCTION (old_decl)->unexpanded_var_list;
+    for (t_step = DECL_STRUCT_FUNCTION (old_decl)->local_decls;
         t_step; t_step = TREE_CHAIN (t_step))
       {
        tree var = TREE_VALUE (t_step);
        if (TREE_STATIC (var) && !TREE_ASM_WRITTEN (var))
-         cfun->unexpanded_var_list = tree_cons (NULL_TREE, var,
-                                                cfun->unexpanded_var_list);
+         cfun->local_decls = tree_cons (NULL_TREE, var, cfun->local_decls);
        else
-         cfun->unexpanded_var_list =
+         cfun->local_decls =
            tree_cons (NULL_TREE, remap_decl (var, &id),
-                      cfun->unexpanded_var_list);
+                      cfun->local_decls);
       }
   
   /* Copy the Function's body.  */
@@ -3696,3 +3708,34 @@ build_duplicate_type (tree type)
 
   return type;
 }
+
+/* Return whether it is safe to inline a function because it used different
+   target specific options or different optimization options.  */
+bool
+tree_can_inline_p (tree caller, tree callee)
+{
+  /* Don't inline a function with a higher optimization level than the
+     caller, or with different space constraints (hot/cold functions).  */
+  tree caller_tree = DECL_FUNCTION_SPECIFIC_OPTIMIZATION (caller);
+  tree callee_tree = DECL_FUNCTION_SPECIFIC_OPTIMIZATION (callee);
+
+  if (caller_tree != callee_tree)
+    {
+      struct cl_optimization *caller_opt
+       = TREE_OPTIMIZATION ((caller_tree)
+                            ? caller_tree
+                            : optimization_default_node);
+
+      struct cl_optimization *callee_opt
+       = TREE_OPTIMIZATION ((callee_tree)
+                            ? callee_tree
+                            : optimization_default_node);
+
+      if ((caller_opt->optimize > callee_opt->optimize)
+         || (caller_opt->optimize_size != callee_opt->optimize_size))
+       return false;
+    }
+
+  /* Allow the backend to decide if inlining is ok.  */
+  return targetm.target_option.can_inline_p (caller, callee);
+}