OSDN Git Service

Daily bump.
[pf3gnuchains/gcc-fork.git] / gcc / tree-inline.c
index 65ffd91..687ed95 100644 (file)
@@ -1,5 +1,5 @@
 /* Tree inlining.
-   Copyright 2001, 2002, 2003, 2004, 2005, 2006, 2007
+   Copyright 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008
    Free Software Foundation, Inc.
    Contributed by Alexandre Oliva <aoliva@redhat.com>
 
@@ -127,7 +127,6 @@ eni_weights eni_time_weights;
 /* Prototypes.  */
 
 static tree declare_return_variable (copy_body_data *, tree, tree, tree *);
-static tree copy_generic_body (copy_body_data *);
 static bool inlinable_function_p (tree);
 static void remap_block (tree *, copy_body_data *);
 static tree remap_decls (tree, copy_body_data *);
@@ -140,7 +139,6 @@ static void remap_save_expr (tree *, void *, int *);
 static void add_lexical_block (tree current_block, tree new_block);
 static tree copy_decl_to_var (tree, copy_body_data *);
 static tree copy_result_decl_to_var (tree, copy_body_data *);
-static tree copy_decl_no_change (tree, copy_body_data *);
 static tree copy_decl_maybe_to_var (tree, copy_body_data *);
 
 /* Insert a tree->tree mapping for ID.  Despite the name suggests
@@ -203,7 +201,7 @@ remap_ssa_name (tree name, copy_body_data *id)
           */
          if (id->entry_bb && is_gimple_reg (SSA_NAME_VAR (name))
              && TREE_CODE (SSA_NAME_VAR (name)) != PARM_DECL
-             && (id->entry_bb != EDGE_SUCC (ENTRY_BLOCK_PTR, 0)
+             && (id->entry_bb != EDGE_SUCC (ENTRY_BLOCK_PTR, 0)->dest
                  || EDGE_COUNT (id->entry_bb->preds) != 1))
            {
              block_stmt_iterator bsi = bsi_last (id->entry_bb);
@@ -409,6 +407,7 @@ tree
 remap_type (tree type, copy_body_data *id)
 {
   tree *node;
+  tree tmp;
 
   if (type == NULL)
     return type;
@@ -425,7 +424,11 @@ remap_type (tree type, copy_body_data *id)
       return type;
     }
 
-  return remap_type_1 (type, id);
+  id->remapping_type_depth++;
+  tmp = remap_type_1 (type, id);
+  id->remapping_type_depth--;
+
+  return tmp;
 }
 
 static tree
@@ -439,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;
        }
 
@@ -493,7 +496,7 @@ remap_block (tree *block, copy_body_data *id)
   fn = id->dst_fn;
 
   if (id->transform_lang_insert_block)
-    lang_hooks.decls.insert_block (new_block);
+    id->transform_lang_insert_block (new_block);
 
   /* Remember the remapped block.  */
   insert_decl_map (id, old_block, new_block);
@@ -696,11 +699,18 @@ copy_body_r (tree *tp, int *walk_subtrees, void *data)
              tree type = TREE_TYPE (TREE_TYPE (*n));
              new = unshare_expr (*n);
              old = *tp;
-             *tp = fold_indirect_ref_1 (type, new);
+             *tp = gimple_fold_indirect_ref (new);
              if (! *tp)
                {
                  if (TREE_CODE (new) == ADDR_EXPR)
-                   *tp = TREE_OPERAND (new, 0);
+                   {
+                     *tp = fold_indirect_ref_1 (type, new);
+                     /* ???  We should either assert here or build
+                        a VIEW_CONVERT_EXPR instead of blindly leaking
+                        incompatible types to our IL.  */
+                     if (! *tp)
+                       *tp = TREE_OPERAND (new, 0);
+                   }
                  else
                    {
                      *tp = build1 (INDIRECT_REF, type, new);
@@ -716,9 +726,10 @@ copy_body_r (tree *tp, int *walk_subtrees, void *data)
         tweak some special cases.  */
       copy_tree_r (tp, walk_subtrees, NULL);
 
-      /* Global variables we didn't seen yet needs to go into referenced
-        vars.  */
-      if (gimple_in_ssa_p (cfun) && TREE_CODE (*tp) == VAR_DECL)
+      /* Global variables we haven't seen yet needs to go into referenced
+        vars.  If not referenced from types only.  */
+      if (gimple_in_ssa_p (cfun) && TREE_CODE (*tp) == VAR_DECL
+         && id->remapping_type_depth == 0)
        add_referenced_var (*tp);
        
       /* If EXPR has block defined, map it to newly constructed block.
@@ -760,7 +771,7 @@ copy_body_r (tree *tp, int *walk_subtrees, void *data)
         and friends are up-to-date.  */
       else if (TREE_CODE (*tp) == ADDR_EXPR)
        {
-         int invariant = TREE_INVARIANT (*tp);
+         int invariant = is_gimple_min_invariant (*tp);
          walk_tree (&TREE_OPERAND (*tp, 0), copy_body_r, id, NULL);
          /* Handle the case where we substituted an INDIRECT_REF
             into the operand of the ADDR_EXPR.  */
@@ -770,7 +781,7 @@ copy_body_r (tree *tp, int *walk_subtrees, void *data)
            recompute_tree_invariant_for_addr_expr (*tp);
          /* If this used to be invariant, but is not any longer,
             then regimplification is probably needed.  */
-         if (invariant && !TREE_INVARIANT (*tp))
+         if (invariant && !is_gimple_min_invariant (*tp))
            id->regimplify = true;
          *walk_subtrees = 0;
        }
@@ -1266,7 +1277,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;
@@ -1381,7 +1392,7 @@ copy_cfg_body (copy_body_data * id, gcov_type count, int frequency,
 /* Make a copy of the body of FN so that it can be inserted inline in
    another function.  */
 
-static tree
+tree
 copy_generic_body (copy_body_data *id)
 {
   tree body;
@@ -1437,7 +1448,16 @@ setup_one_parameter (copy_body_data *id, tree p, tree value, tree fn,
   if (value
       && value != error_mark_node
       && !useless_type_conversion_p (TREE_TYPE (p), TREE_TYPE (value)))
-    rhs = fold_build1 (NOP_EXPR, TREE_TYPE (p), value);
+    {
+      if (fold_convertible_p (TREE_TYPE (p), value))
+       rhs = fold_build1 (NOP_EXPR, TREE_TYPE (p), value);
+      else
+       /* ???  For valid (GIMPLE) programs we should not end up here.
+          Still if something has gone wrong and we end up with truly
+          mismatched types here, fall back to using a VIEW_CONVERT_EXPR
+          to not leak invalid GIMPLE to the following passes.  */
+       rhs = fold_build1 (VIEW_CONVERT_EXPR, TREE_TYPE (p), value);
+    }
 
   /* If the parameter is never assigned to, has no SSA_NAMEs created,
      we may not need to create a new variable here at all.  Instead, we may
@@ -1719,6 +1739,7 @@ declare_return_variable (copy_body_data *id, tree return_slot, tree modify_dest,
        {
          var = return_slot;
          gcc_assert (TREE_CODE (var) != SSA_NAME);
+         TREE_ADDRESSABLE (var) |= TREE_ADDRESSABLE (result);
        }
       if ((TREE_CODE (TREE_TYPE (result)) == COMPLEX_TYPE
            || TREE_CODE (TREE_TYPE (result)) == VECTOR_TYPE)
@@ -1790,9 +1811,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.  */
@@ -1876,7 +1897,6 @@ inline_forbidden_p_1 (tree *nodep, int *walk_subtrees ATTRIBUTE_UNUSED,
            /* We cannot inline functions that take a variable number of
               arguments.  */
          case BUILT_IN_VA_START:
-         case BUILT_IN_STDARG_START:
          case BUILT_IN_NEXT_ARG:
          case BUILT_IN_VA_END:
            inline_forbidden_reason
@@ -2020,7 +2040,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
@@ -2199,6 +2219,7 @@ estimate_num_insns_1 (tree *tp, int *walk_subtrees, void *data)
     case COMPOUND_EXPR:
     case BIND_EXPR:
     case WITH_CLEANUP_EXPR:
+    case PAREN_EXPR:
     case NOP_EXPR:
     case CONVERT_EXPR:
     case VIEW_CONVERT_EXPR:
@@ -2212,7 +2233,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:
@@ -2242,6 +2262,7 @@ estimate_num_insns_1 (tree *tp, int *walk_subtrees, void *data)
     case COMPLEX_CST:
     case VECTOR_CST:
     case STRING_CST:
+    case PREDICT_EXPR:
       *walk_subtrees = 0;
       return NULL;
 
@@ -2386,9 +2407,12 @@ estimate_num_insns_1 (tree *tp, int *walk_subtrees, void *data)
       break;
 
     case SWITCH_EXPR:
-      /* TODO: Cost of a switch should be derived from the number of
-        branches.  */
-      d->count += d->weights->switch_cost;
+      /* Take into account cost of the switch + guess 2 conditional jumps for
+         each case label.  
+
+        TODO: once the switch expansion logic is sufficiently separated, we can
+        do better job on estimating cost of the switch.  */
+      d->count += TREE_VEC_LENGTH (SWITCH_LABELS (x)) * 2;
       break;
 
     /* Few special cases of expensive operations.  This is useful
@@ -2408,6 +2432,11 @@ estimate_num_insns_1 (tree *tp, int *walk_subtrees, void *data)
     case CALL_EXPR:
       {
        tree decl = get_callee_fndecl (x);
+       tree addr = CALL_EXPR_FN (x);
+       tree funtype = TREE_TYPE (addr);
+
+       gcc_assert (POINTER_TYPE_P (funtype));
+       funtype = TREE_TYPE (funtype);
 
        if (decl && DECL_BUILT_IN_CLASS (decl) == BUILT_IN_MD)
          cost = d->weights->target_builtin_call_cost;
@@ -2430,21 +2459,34 @@ estimate_num_insns_1 (tree *tp, int *walk_subtrees, void *data)
              break;
            }
 
+       if (decl)
+         funtype = TREE_TYPE (decl);
+
        /* Our cost must be kept in sync with cgraph_estimate_size_after_inlining
-          that does use function declaration to figure out the arguments.  */
-       if (!decl)
+          that does use function declaration to figure out the arguments. 
+
+          When we deal with function with no body nor prototype, base estimates on
+          actual parameters of the call expression.  Otherwise use either the actual
+          arguments types or function declaration for more precise answer.  */
+       if (decl && DECL_ARGUMENTS (decl))
+         {
+           tree arg;
+           for (arg = DECL_ARGUMENTS (decl); arg; arg = TREE_CHAIN (arg))
+             d->count += estimate_move_cost (TREE_TYPE (arg));
+         }
+       else if (funtype && prototype_p (funtype))
+         {
+           tree t;
+           for (t = TYPE_ARG_TYPES (funtype); t; t = TREE_CHAIN (t))
+             d->count += estimate_move_cost (TREE_VALUE (t));
+         }
+       else
          {
            tree a;
            call_expr_arg_iterator iter;
            FOR_EACH_CALL_EXPR_ARG (a, iter, x)
              d->count += estimate_move_cost (TREE_TYPE (a));
          }
-       else
-         {
-           tree arg;
-           for (arg = DECL_ARGUMENTS (decl); arg; arg = TREE_CHAIN (arg))
-             d->count += estimate_move_cost (TREE_TYPE (arg));
-         }
 
        d->count += cost;
        break;
@@ -2517,13 +2559,11 @@ init_inline_once (void)
   eni_inlining_weights.call_cost = PARAM_VALUE (PARAM_INLINE_CALL_COST);
   eni_inlining_weights.target_builtin_call_cost = 1;
   eni_inlining_weights.div_mod_cost = 10;
-  eni_inlining_weights.switch_cost = 1;
   eni_inlining_weights.omp_cost = 40;
 
   eni_size_weights.call_cost = 1;
   eni_size_weights.target_builtin_call_cost = 1;
   eni_size_weights.div_mod_cost = 1;
-  eni_size_weights.switch_cost = 10;
   eni_size_weights.omp_cost = 40;
 
   /* Estimating time for call is difficult, since we have no idea what the
@@ -2533,7 +2573,6 @@ init_inline_once (void)
   eni_time_weights.call_cost = 10;
   eni_time_weights.target_builtin_call_cost = 10;
   eni_time_weights.div_mod_cost = 10;
-  eni_time_weights.switch_cost = 4;
   eni_time_weights.omp_cost = 40;
 }
 
@@ -2559,7 +2598,7 @@ expand_call_inline (basic_block bb, tree stmt, tree *tp, void *data)
 {
   copy_body_data *id;
   tree t;
-  tree use_retvar;
+  tree retvar, use_retvar;
   tree fn;
   struct pointer_map_t *st;
   tree return_slot;
@@ -2761,9 +2800,27 @@ expand_call_inline (basic_block bb, tree stmt, tree *tp, void *data)
   else
     modify_dest = NULL;
 
+  /* If we are inlining a call to the C++ operator new, we don't want
+     to use type based alias analysis on the return value.  Otherwise
+     we may get confused if the compiler sees that the inlined new
+     function returns a pointer which was just deleted.  See bug
+     33407.  */
+  if (DECL_IS_OPERATOR_NEW (fn))
+    {
+      return_slot = NULL;
+      modify_dest = NULL;
+    }
+
   /* Declare the return variable for the function.  */
-  declare_return_variable (id, return_slot,
-                          modify_dest, &use_retvar);
+  retvar = declare_return_variable (id, return_slot,
+                                   modify_dest, &use_retvar);
+
+  if (DECL_IS_OPERATOR_NEW (fn))
+    {
+      gcc_assert (TREE_CODE (retvar) == VAR_DECL
+                 && POINTER_TYPE_P (TREE_TYPE (retvar)));
+      DECL_NO_TBAA_P (retvar) = 1;
+    }
 
   /* This is it.  Duplicate the callee body.  Assume callee is
      pre-gimplified.  Note that we must not alter the caller
@@ -2773,16 +2830,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.  */
@@ -2810,15 +2867,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.  */
@@ -2901,11 +2958,17 @@ fold_marked_statements (int first, struct pointer_set_t *statements)
          if (pointer_set_contains (statements, bsi_stmt (bsi)))
            {
              tree old_stmt = bsi_stmt (bsi);
+             tree old_call = get_call_expr_in (old_stmt);
+
              if (fold_stmt (bsi_stmt_ptr (bsi)))
                {
                  update_stmt (bsi_stmt (bsi));
-                 if (maybe_clean_or_replace_eh_stmt (old_stmt, bsi_stmt (bsi)))
-                    tree_purge_dead_eh_edges (BASIC_BLOCK (first));
+                 if (old_call)
+                   cgraph_update_edges_for_call_stmt (old_stmt, old_call,
+                                                      bsi_stmt (bsi));
+                 if (maybe_clean_or_replace_eh_stmt (old_stmt,
+                                                     bsi_stmt (bsi)))
+                   tree_purge_dead_eh_edges (BASIC_BLOCK (first));
                }
            }
       }
@@ -2958,7 +3021,7 @@ optimize_inline_calls (tree fn)
   id.transform_call_graph_edges = CB_CGE_DUPLICATE;
   id.transform_new_cfg = false;
   id.transform_return_to_modify = true;
-  id.transform_lang_insert_block = false;
+  id.transform_lang_insert_block = NULL;
   id.statements_to_fold = pointer_set_create ();
 
   push_gimplify_context ();
@@ -3013,36 +3076,6 @@ optimize_inline_calls (tree fn)
          | (profile_status != PROFILE_ABSENT ? TODO_rebuild_frequencies : 0));
 }
 
-/* FN is a function that has a complete body, and CLONE is a function whose
-   body is to be set to a copy of FN, mapping argument declarations according
-   to the ARG_MAP splay_tree.  */
-
-void
-clone_body (tree clone, tree fn, void *arg_map)
-{
-  copy_body_data id;
-
-  /* Clone the body, as if we were making an inline call.  But, remap the
-     parameters in the callee to the parameters of caller.  */
-  memset (&id, 0, sizeof (id));
-  id.src_fn = fn;
-  id.dst_fn = clone;
-  id.src_cfun = DECL_STRUCT_FUNCTION (fn);
-  id.decl_map = (struct pointer_map_t *)arg_map;
-
-  id.copy_decl = copy_decl_no_change;
-  id.transform_call_graph_edges = CB_CGE_DUPLICATE;
-  id.transform_new_cfg = true;
-  id.transform_return_to_modify = false;
-  id.transform_lang_insert_block = true;
-
-  /* We're not inside any EH region.  */
-  id.eh_region = -1;
-
-  /* Actually copy the body.  */
-  append_to_statement_list_force (copy_generic_body (&id), &DECL_SAVED_TREE (clone));
-}
-
 /* Passed to walk_tree.  Copies the node pointed to, if appropriate.  */
 
 tree
@@ -3263,7 +3296,7 @@ unsave_expr_now (tree expr)
   id.transform_call_graph_edges = CB_CGE_DUPLICATE;
   id.transform_new_cfg = false;
   id.transform_return_to_modify = false;
-  id.transform_lang_insert_block = false;
+  id.transform_lang_insert_block = NULL;
 
   /* Walk the tree once to find local labels.  */
   walk_tree_without_duplicates (&expr, mark_local_for_remap_r, &id);
@@ -3306,9 +3339,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)
@@ -3409,7 +3440,7 @@ copy_result_decl_to_var (tree decl, copy_body_data *id)
 }
 
 
-static tree
+tree
 copy_decl_no_change (tree decl, copy_body_data *id)
 {
   tree copy;
@@ -3545,7 +3576,7 @@ tree_function_versioning (tree old_decl, tree new_decl, varray_type tree_map,
     = update_clones ? CB_CGE_MOVE_CLONES : CB_CGE_MOVE;
   id.transform_new_cfg = true;
   id.transform_return_to_modify = false;
-  id.transform_lang_insert_block = false;
+  id.transform_lang_insert_block = NULL;
 
   current_function_decl = new_decl;
   old_entry_block = ENTRY_BLOCK_PTR_FOR_FUNCTION
@@ -3581,19 +3612,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.  */
@@ -3658,5 +3688,7 @@ build_duplicate_type (tree type)
 
   pointer_map_destroy (id.decl_map);
 
+  TYPE_CANONICAL (type) = type;
+
   return type;
 }