OSDN Git Service

* trans.c (convert_with_check): Update call to real_2expN.
[pf3gnuchains/gcc-fork.git] / gcc / tree-inline.c
index d68190f..d49c3c8 100644 (file)
@@ -1,12 +1,13 @@
 /* Tree inlining.
-   Copyright 2001, 2002, 2003, 2004, 2005, 2006 Free Software Foundation, Inc.
+   Copyright 2001, 2002, 2003, 2004, 2005, 2006, 2007
+   Free Software Foundation, Inc.
    Contributed by Alexandre Oliva <aoliva@redhat.com>
 
 This file is part of GCC.
 
 GCC is free software; you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
-the Free Software Foundation; either version 2, or (at your option)
+the Free Software Foundation; either version 3, or (at your option)
 any later version.
 
 GCC is distributed in the hope that it will be useful,
@@ -15,9 +16,8 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 GNU General Public License for more details.
 
 You should have received a copy of the GNU General Public License
-along with GCC; see the file COPYING.  If not, write to
-the Free Software Foundation, 51 Franklin Street, Fifth Floor,
-Boston, MA 02110-1301, USA.  */
+along with GCC; see the file COPYING3.  If not see
+<http://www.gnu.org/licenses/>.  */
 
 #include "config.h"
 #include "system.h"
@@ -51,6 +51,8 @@ Boston, MA 02110-1301, USA.  */
 #include "ipa-prop.h"
 #include "value-prof.h"
 #include "tree-pass.h"
+#include "target.h"
+#include "integrate.h"
 
 /* I'm not real happy about this, but we need to handle gimple and
    non-gimple trees.  */
@@ -147,14 +149,12 @@ static tree copy_decl_maybe_to_var (tree, copy_body_data *);
 void
 insert_decl_map (copy_body_data *id, tree key, tree value)
 {
-  splay_tree_insert (id->decl_map, (splay_tree_key) key,
-                    (splay_tree_value) value);
+  *pointer_map_insert (id->decl_map, key) = value;
 
   /* Always insert an identity map as well.  If we see this same new
      node again, we won't want to duplicate it a second time.  */
   if (key != value)
-    splay_tree_insert (id->decl_map, (splay_tree_key) value,
-                      (splay_tree_value) value);
+    *pointer_map_insert (id->decl_map, value) = value;
 }
 
 /* Construct new SSA name for old NAME. ID is the inline context.  */
@@ -163,13 +163,13 @@ static tree
 remap_ssa_name (tree name, copy_body_data *id)
 {
   tree new;
-  splay_tree_node n;
+  tree *n;
 
   gcc_assert (TREE_CODE (name) == SSA_NAME);
 
-  n = splay_tree_lookup (id->decl_map, (splay_tree_key) name);
+  n = (tree *) pointer_map_contains (id->decl_map, name);
   if (n)
-    return (tree) n->value;
+    return *n;
 
   /* Do not set DEF_STMT yet as statement is not copied yet. We do that
      in copy_bb.  */
@@ -206,7 +206,7 @@ remap_ssa_name (tree name, copy_body_data *id)
 tree
 remap_decl (tree decl, copy_body_data *id)
 {
-  splay_tree_node n;
+  tree *n;
   tree fn;
 
   /* We only remap local variables in the current function.  */
@@ -214,7 +214,7 @@ remap_decl (tree decl, copy_body_data *id)
 
   /* See if we have remapped this declaration.  */
 
-  n = splay_tree_lookup (id->decl_map, (splay_tree_key) decl);
+  n = (tree *) pointer_map_contains (id->decl_map, decl);
 
   /* If we didn't already have an equivalent for this declaration,
      create one now.  */
@@ -267,22 +267,22 @@ remap_decl (tree decl, copy_body_data *id)
       return t;
     }
 
-  return unshare_expr ((tree) n->value);
+  return unshare_expr (*n);
 }
 
 static tree
 remap_type_1 (tree type, copy_body_data *id)
 {
-  splay_tree_node node;
+  tree *node;
   tree new, t;
 
   if (type == NULL)
     return type;
 
   /* See if we have remapped this type.  */
-  node = splay_tree_lookup (id->decl_map, (splay_tree_key) type);
+  node = (tree *) pointer_map_contains (id->decl_map, type);
   if (node)
-    return (tree) node->value;
+    return *node;
 
   /* The type only needs remapping if it's variably modified.  */
   if (! variably_modified_type_p (type, id->src_fn))
@@ -342,6 +342,7 @@ remap_type_1 (tree type, copy_body_data *id)
     {
     case INTEGER_TYPE:
     case REAL_TYPE:
+    case FIXED_POINT_TYPE:
     case ENUMERAL_TYPE:
     case BOOLEAN_TYPE:
       t = TYPE_MIN_VALUE (new);
@@ -395,15 +396,15 @@ remap_type_1 (tree type, copy_body_data *id)
 tree
 remap_type (tree type, copy_body_data *id)
 {
-  splay_tree_node node;
+  tree *node;
 
   if (type == NULL)
     return type;
 
   /* See if we have remapped this type.  */
-  node = splay_tree_lookup (id->decl_map, (splay_tree_key) type);
+  node = (tree *) pointer_map_contains (id->decl_map, type);
   if (node)
-    return (tree) node->value;
+    return *node;
 
   /* The type only needs remapping if it's variably modified.  */
   if (! variably_modified_type_p (type, id->src_fn))
@@ -429,7 +430,7 @@ remap_decls (tree decls, copy_body_data *id)
       /* We can not chain the local static declarations into the unexpanded_var_list
          as we can't duplicate them or break one decl rule.  Go ahead and link
          them into unexpanded_var_list.  */
-      if (!lang_hooks.tree_inlining.auto_var_in_fn_p (old_var, id->src_fn)
+      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,
@@ -587,7 +588,7 @@ copy_body_r (tree *tp, int *walk_subtrees, void *data)
      variables.  We don't want to copy static variables; there's only
      one of those, no matter how many times we inline the containing
      function.  Similarly for globals from an outer function.  */
-  else if (lang_hooks.tree_inlining.auto_var_in_fn_p (*tp, fn))
+  else if (auto_var_in_fn_p (*tp, fn))
     {
       tree new_decl;
 
@@ -642,19 +643,18 @@ copy_body_r (tree *tp, int *walk_subtrees, void *data)
         discarding.  */
       if (TREE_CODE (*tp) == GIMPLE_MODIFY_STMT
          && GIMPLE_STMT_OPERAND (*tp, 0) == GIMPLE_STMT_OPERAND (*tp, 1)
-         && (lang_hooks.tree_inlining.auto_var_in_fn_p
-             (GIMPLE_STMT_OPERAND (*tp, 0), fn)))
+         && (auto_var_in_fn_p (GIMPLE_STMT_OPERAND (*tp, 0), fn)))
        {
          /* Some assignments VAR = VAR; don't generate any rtl code
             and thus don't count as variable modification.  Avoid
             keeping bogosities like 0 = 0.  */
          tree decl = GIMPLE_STMT_OPERAND (*tp, 0), value;
-         splay_tree_node n;
+         tree *n;
 
-         n = splay_tree_lookup (id->decl_map, (splay_tree_key) decl);
+         n = (tree *) pointer_map_contains (id->decl_map, decl);
          if (n)
            {
-             value = (tree) n->value;
+             value = *n;
              STRIP_TYPE_NOPS (value);
              if (TREE_CONSTANT (value) || TREE_READONLY_DECL_P (value))
                {
@@ -668,9 +668,9 @@ copy_body_r (tree *tp, int *walk_subtrees, void *data)
          /* Get rid of *& from inline substitutions that can happen when a
             pointer argument is an ADDR_EXPR.  */
          tree decl = TREE_OPERAND (*tp, 0);
-         splay_tree_node n;
+         tree *n;
 
-         n = splay_tree_lookup (id->decl_map, (splay_tree_key) decl);
+         n = (tree *) pointer_map_contains (id->decl_map, decl);
          if (n)
            {
              tree new;
@@ -681,8 +681,8 @@ copy_body_r (tree *tp, int *walk_subtrees, void *data)
                 build_fold_indirect_ref wouldn't strip the INDIRECT_REF,
                 but we absolutely rely on that.  As fold_indirect_ref
                 does other useful transformations, try that first, though.  */
-             tree type = TREE_TYPE (TREE_TYPE ((tree)n->value));
-             new = unshare_expr ((tree)n->value);
+             tree type = TREE_TYPE (TREE_TYPE (*n));
+             new = unshare_expr (*n);
              old = *tp;
              *tp = fold_indirect_ref_1 (type, new);
              if (! *tp)
@@ -717,11 +717,11 @@ copy_body_r (tree *tp, int *walk_subtrees, void *data)
          new_block = id->block;
          if (TREE_BLOCK (*tp))
            {
-             splay_tree_node n;
-             n = splay_tree_lookup (id->decl_map,
-                                    (splay_tree_key) TREE_BLOCK (*tp));
+             tree *n;
+             n = (tree *) pointer_map_contains (id->decl_map,
+                                                TREE_BLOCK (*tp));
              gcc_assert (n);
-             new_block = (tree) n->value;
+             new_block = *n;
            }
          TREE_BLOCK (*tp) = new_block;
        }
@@ -732,7 +732,7 @@ copy_body_r (tree *tp, int *walk_subtrees, void *data)
            (NULL_TREE,
             id->eh_region_offset + TREE_INT_CST_LOW (TREE_OPERAND (*tp, 0)));
 
-      if (!GIMPLE_TUPLE_P (*tp))
+      if (!GIMPLE_TUPLE_P (*tp) && TREE_CODE (*tp) != OMP_CLAUSE)
        TREE_TYPE (*tp) = remap_type (TREE_TYPE (*tp), id);
 
       /* The copied TARGET_EXPR has never been expanded, even if the
@@ -777,8 +777,13 @@ copy_bb (copy_body_data *id, basic_block bb, int frequency_scale, int count_scal
   copy_basic_block = create_basic_block (NULL, (void *) 0,
                                          (basic_block) bb->prev_bb->aux);
   copy_basic_block->count = bb->count * count_scale / REG_BR_PROB_BASE;
-  copy_basic_block->frequency = (bb->frequency
+
+  /* We are going to rebuild frequencies from scratch.  These values have just
+     small importance to drive canonicalize_loop_headers.  */
+  copy_basic_block->frequency = ((gcov_type)bb->frequency
                                     * frequency_scale / REG_BR_PROB_BASE);
+  if (copy_basic_block->frequency > BB_FREQ_MAX)
+    copy_basic_block->frequency = BB_FREQ_MAX;
   copy_bsi = bsi_start (copy_basic_block);
 
   for (bsi = bsi_start (bb);
@@ -810,9 +815,59 @@ copy_bb (copy_body_data *id, basic_block bb, int frequency_scale, int count_scal
             into multiple statements, we need to process all of them.  */
          while (!bsi_end_p (copy_bsi))
            {
-             stmt = bsi_stmt (copy_bsi);
+             tree *stmtp = bsi_stmt_ptr (copy_bsi);
+             tree stmt = *stmtp;
              call = get_call_expr_in (stmt);
 
+             if (call && CALL_EXPR_VA_ARG_PACK (call) && id->call_expr)
+               {
+                 /* __builtin_va_arg_pack () should be replaced by
+                    all arguments corresponding to ... in the caller.  */
+                 tree p, *argarray, new_call, *call_ptr;
+                 int nargs = call_expr_nargs (id->call_expr);
+
+                 for (p = DECL_ARGUMENTS (id->src_fn); p; p = TREE_CHAIN (p))
+                   nargs--;
+
+                 argarray = (tree *) alloca ((nargs + call_expr_nargs (call))
+                                             * sizeof (tree));
+
+                 memcpy (argarray, CALL_EXPR_ARGP (call),
+                         call_expr_nargs (call) * sizeof (*argarray));
+                 memcpy (argarray + call_expr_nargs (call),
+                         CALL_EXPR_ARGP (id->call_expr)
+                         + (call_expr_nargs (id->call_expr) - nargs),
+                         nargs * sizeof (*argarray));
+
+                 new_call = build_call_array (TREE_TYPE (call),
+                                              CALL_EXPR_FN (call),
+                                              nargs + call_expr_nargs (call),
+                                              argarray);
+                 /* Copy all CALL_EXPR flags, locus and block, except
+                    CALL_EXPR_VA_ARG_PACK flag.  */
+                 CALL_EXPR_STATIC_CHAIN (new_call)
+                   = CALL_EXPR_STATIC_CHAIN (call);
+                 CALL_EXPR_TAILCALL (new_call) = CALL_EXPR_TAILCALL (call);
+                 CALL_EXPR_RETURN_SLOT_OPT (new_call)
+                   = CALL_EXPR_RETURN_SLOT_OPT (call);
+                 CALL_FROM_THUNK_P (new_call) = CALL_FROM_THUNK_P (call);
+                 CALL_CANNOT_INLINE_P (new_call)
+                   = CALL_CANNOT_INLINE_P (call);
+                 TREE_NOTHROW (new_call) = TREE_NOTHROW (call);
+                 SET_EXPR_LOCUS (new_call, EXPR_LOCUS (call));
+                 TREE_BLOCK (new_call) = TREE_BLOCK (call);
+
+                 call_ptr = stmtp;
+                 if (TREE_CODE (*call_ptr) == GIMPLE_MODIFY_STMT)
+                   call_ptr = &GIMPLE_STMT_OPERAND (*call_ptr, 1);
+                 if (TREE_CODE (*call_ptr) == WITH_SIZE_EXPR)
+                   call_ptr = &TREE_OPERAND (*call_ptr, 0);
+                 gcc_assert (*call_ptr == call);
+                 *call_ptr = new_call;
+                 stmt = *stmtp;
+                 update_stmt (stmt);
+               }
+
              /* Statements produced by inlining can be unfolded, especially
                 when we constant propagated some operands.  We can't fold
                 them right now for two reasons:
@@ -839,7 +894,7 @@ 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, true);
+                                          REG_BR_PROB_BASE, 1, edge->frequency, true);
                      break;
 
                    case CB_CGE_MOVE_CLONES:
@@ -868,7 +923,20 @@ copy_bb (copy_body_data *id, basic_block bb, int frequency_scale, int count_scal
              gcc_assert (lookup_stmt_eh_region_fn (id->src_cfun, orig_stmt)
                          != 0);
 
-             if (tree_could_throw_p (stmt))
+             if (tree_could_throw_p (stmt)
+                 /* When we are cloning for inlining, we are supposed to
+                    construct a clone that calls precisely the same functions
+                    as original.  However IPA optimizers might've proved
+                    earlier some function calls as non-trapping that might
+                    render some basic blocks dead that might become
+                    unreachable.
+
+                    We can't update SSA with unreachable blocks in CFG and thus
+                    we prevent the scenario by preserving even the "dead" eh
+                    edges until the point they are later removed by
+                    fixup_cfg pass.  */
+                 || (id->transform_call_graph_edges == CB_CGE_MOVE_CLONES
+                     && lookup_stmt_eh_region_fn (id->src_cfun, orig_stmt) > 0))
                {
                  int region = lookup_stmt_eh_region_fn (id->src_cfun, orig_stmt);
                  /* Add an entry for the copied tree in the EH hashtable.
@@ -1100,7 +1168,6 @@ initialize_cfun (tree new_fndecl, tree callee_fndecl, gcov_type count,
   new_cfun->unexpanded_var_list = NULL;
   new_cfun->cfg = NULL;
   new_cfun->decl = new_fndecl /*= copy_node (callee_fndecl)*/;
-  new_cfun->ib_boundaries_block = NULL;
   DECL_STRUCT_FUNCTION (new_fndecl) = new_cfun;
   push_cfun (new_cfun);
   init_empty_tree_cfg ();
@@ -1188,7 +1255,7 @@ copy_cfg_body (copy_body_data * id, gcov_type count, int frequency,
       new->aux = bb;
     }
 
-  last = n_basic_blocks;
+  last = last_basic_block;
   /* Now that we've duplicated the blocks, duplicate their edges.  */
   FOR_ALL_BB_FN (bb, cfun_to_copy)
     copy_edges_for_bb (bb, count_scale);
@@ -1202,7 +1269,7 @@ copy_cfg_body (copy_body_data * id, gcov_type count, int frequency,
     }
   /* Zero out AUX fields of newly created block during EH edge
      insertion. */
-  for (; last < n_basic_blocks; last++)
+  for (; last < last_basic_block; last++)
     BASIC_BLOCK (last)->aux = NULL;
   entry_block_map->aux = NULL;
   exit_block_map->aux = NULL;
@@ -1252,7 +1319,7 @@ self_inlining_addr_expr (tree value, tree fn)
 
   var = get_base_address (TREE_OPERAND (value, 0));
 
-  return var && lang_hooks.tree_inlining.auto_var_in_fn_p (var, fn);
+  return var && auto_var_in_fn_p (var, fn);
 }
 
 static void
@@ -1262,10 +1329,15 @@ setup_one_parameter (copy_body_data *id, tree p, tree value, tree fn,
   tree init_stmt;
   tree var;
   tree var_sub;
-  tree rhs = value ? fold_convert (TREE_TYPE (p), value) : NULL;
+  tree rhs = value;
   tree def = (gimple_in_ssa_p (cfun)
              ? gimple_default_def (id->src_cfun, p) : NULL);
 
+  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 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
      be able to just use the argument value.  */
@@ -1279,7 +1351,8 @@ setup_one_parameter (copy_body_data *id, tree p, tree value, tree fn,
         It is not big deal to prohibit constant propagation here as
         we will constant propagate in DOM1 pass anyway.  */
       if (is_gimple_min_invariant (value)
-         && lang_hooks.types_compatible_p (TREE_TYPE (value), TREE_TYPE (p))
+         && useless_type_conversion_p (TREE_TYPE (p),
+                                                TREE_TYPE (value))
          /* We have to be very careful about ADDR_EXPR.  Make sure
             the base variable isn't a local variable of the inlined
             function, e.g., when doing recursive inlining, direct or
@@ -1381,13 +1454,13 @@ setup_one_parameter (copy_body_data *id, tree p, tree value, tree fn,
       if (def && gimple_in_ssa_p (cfun) && is_gimple_reg (p))
        {
          def = remap_ssa_name (def, id);
-          init_stmt = build2 (GIMPLE_MODIFY_STMT, TREE_TYPE (var), def, rhs);
+          init_stmt = build_gimple_modify_stmt (def, rhs);
          SSA_NAME_DEF_STMT (def) = init_stmt;
          SSA_NAME_IS_DEFAULT_DEF (def) = 0;
          set_default_def (var, NULL);
        }
       else
-        init_stmt = build2 (GIMPLE_MODIFY_STMT, TREE_TYPE (var), var, rhs);
+        init_stmt = build_gimple_modify_stmt (var, rhs);
 
       /* If we did not create a gimple value and we did not create a gimple
         cast of a gimple value, then we will need to gimplify INIT_STMTS
@@ -1425,36 +1498,27 @@ setup_one_parameter (copy_body_data *id, tree p, tree value, tree fn,
 }
 
 /* Generate code to initialize the parameters of the function at the
-   top of the stack in ID from the ARGS (presented as a TREE_LIST).  */
+   top of the stack in ID from the CALL_EXPR EXP.  */
 
 static void
-initialize_inlined_parameters (copy_body_data *id, tree args, tree static_chain,
+initialize_inlined_parameters (copy_body_data *id, tree exp,
                               tree fn, basic_block bb)
 {
   tree parms;
   tree a;
   tree p;
   tree vars = NULL_TREE;
-  int argnum = 0;
+  call_expr_arg_iterator iter;
+  tree static_chain = CALL_EXPR_STATIC_CHAIN (exp);
 
   /* Figure out what the parameters are.  */
   parms = DECL_ARGUMENTS (fn);
 
   /* Loop through the parameter declarations, replacing each with an
      equivalent VAR_DECL, appropriately initialized.  */
-  for (p = parms, a = args; p;
-       a = a ? TREE_CHAIN (a) : a, p = TREE_CHAIN (p))
-    {
-      tree value;
-
-      ++argnum;
-
-      /* Find the initializer.  */
-      value = lang_hooks.tree_inlining.convert_parm_for_inlining
-             (p, a ? TREE_VALUE (a) : NULL_TREE, fn, argnum);
-
-      setup_one_parameter (id, p, value, fn, bb, &vars);
-    }
+  for (p = parms, a = first_call_expr_arg (exp, &iter); p;
+       a = next_call_expr_arg (&iter), p = TREE_CHAIN (p))
+    setup_one_parameter (id, p, a, fn, bb, &vars);
 
   /* Initialize the static chain.  */
   p = DECL_STRUCT_FUNCTION (fn)->static_chain_decl;
@@ -1566,7 +1630,7 @@ declare_return_variable (copy_body_data *id, tree return_slot, tree modify_dest,
       bool use_it = false;
 
       /* We can't use MODIFY_DEST if there's type promotion involved.  */
-      if (!lang_hooks.types_compatible_p (caller_type, callee_type))
+      if (!useless_type_conversion_p (callee_type, caller_type))
        use_it = false;
 
       /* ??? If we're assigning to a variable sized type, then we must
@@ -1630,7 +1694,7 @@ declare_return_variable (copy_body_data *id, tree return_slot, tree modify_dest,
   /* Build the use expr.  If the return type of the function was
      promoted, convert it back to the expected type.  */
   use = var;
-  if (!lang_hooks.types_compatible_p (TREE_TYPE (var), caller_type))
+  if (!useless_type_conversion_p (caller_type, TREE_TYPE (var)))
     use = fold_convert (caller_type, var);
     
   STRIP_USELESS_TYPE_CONVERSION (use);
@@ -1836,18 +1900,44 @@ static bool
 inlinable_function_p (tree fn)
 {
   bool inlinable = true;
+  bool do_warning;
+  tree always_inline;
 
   /* If we've already decided this function shouldn't be inlined,
      there's no need to check again.  */
   if (DECL_UNINLINABLE (fn))
     return false;
 
-  /* See if there is any language-specific reason it cannot be
-     inlined.  (It is important that this hook be called early because
-     in C++ it may result in template instantiation.)
-     If the function is not inlinable for language-specific reasons,
-     it is left up to the langhook to explain why.  */
-  inlinable = !lang_hooks.tree_inlining.cannot_inline_tree_fn (&fn);
+  /* We only warn for functions declared `inline' by the user.  */
+  do_warning = (warn_inline
+               && DECL_INLINE (fn)
+               && DECL_DECLARED_INLINE_P (fn)
+               && !DECL_IN_SYSTEM_HEADER (fn));
+
+  always_inline = lookup_attribute ("always_inline", DECL_ATTRIBUTES (fn));
+
+  if (flag_really_no_inline
+      && always_inline == NULL)
+    {
+      if (do_warning)
+        warning (OPT_Winline, "function %q+F can never be inlined because it "
+                 "is suppressed using -fno-inline", fn);
+      inlinable = false;
+    }
+
+  /* Don't auto-inline anything that might not be bound within
+     this unit of translation.  */
+  else if (!DECL_DECLARED_INLINE_P (fn)
+          && DECL_REPLACEABLE_P (fn))
+    inlinable = false;
+
+  else if (!function_attribute_inlinable_p (fn))
+    {
+      if (do_warning)
+        warning (OPT_Winline, "function %q+F can never be inlined because it "
+                 "uses attributes conflicting with inlining", fn);
+      inlinable = false;
+    }
 
   /* If we don't have the function body available, we can't inline it.
      However, this should not be recorded since we also get here for
@@ -1881,14 +1971,8 @@ inlinable_function_p (tree fn)
         about functions that would for example call alloca.  But since
         this a property of the function, just one warning is enough.
         As a bonus we can now give more details about the reason why a
-        function is not inlinable.
-        We only warn for functions declared `inline' by the user.  */
-      bool do_warning = (warn_inline
-                        && DECL_INLINE (fn)
-                        && DECL_DECLARED_INLINE_P (fn)
-                        && !DECL_IN_SYSTEM_HEADER (fn));
-
-      if (lookup_attribute ("always_inline", DECL_ATTRIBUTES (fn)))
+        function is not inlinable.  */
+      if (always_inline)
        sorry (inline_forbidden_reason, fn);
       else if (do_warning)
        warning (OPT_Winline, inline_forbidden_reason, fn);
@@ -1971,6 +2055,7 @@ estimate_num_insns_1 (tree *tp, int *walk_subtrees, void *data)
     case BIND_EXPR:
     case WITH_CLEANUP_EXPR:
     case NOP_EXPR:
+    case CONVERT_EXPR:
     case VIEW_CONVERT_EXPR:
     case SAVE_EXPR:
     case ADDR_EXPR:
@@ -1997,6 +2082,7 @@ estimate_num_insns_1 (tree *tp, int *walk_subtrees, void *data)
     case OMP_CLAUSE:
     case OMP_RETURN:
     case OMP_CONTINUE:
+    case OMP_SECTIONS_SWITCH:
       break;
 
     /* We don't account constants for now.  Assume that the cost is amortized
@@ -2006,12 +2092,18 @@ estimate_num_insns_1 (tree *tp, int *walk_subtrees, void *data)
     case IDENTIFIER_NODE:
     case INTEGER_CST:
     case REAL_CST:
+    case FIXED_CST:
     case COMPLEX_CST:
     case VECTOR_CST:
     case STRING_CST:
       *walk_subtrees = 0;
       return NULL;
 
+      /* CHANGE_DYNAMIC_TYPE_EXPR explicitly expands to nothing.  */
+    case CHANGE_DYNAMIC_TYPE_EXPR:
+      *walk_subtrees = 0;
+      return NULL;
+
     /* Try to estimate the cost of assignments.  We have three cases to
        deal with:
        1) Simple assignments to registers;
@@ -2062,9 +2154,11 @@ estimate_num_insns_1 (tree *tp, int *walk_subtrees, void *data)
     case VEC_COND_EXPR:
 
     case PLUS_EXPR:
+    case POINTER_PLUS_EXPR:
     case MINUS_EXPR:
     case MULT_EXPR:
 
+    case FIXED_CONVERT_EXPR:
     case FIX_TRUNC_EXPR:
 
     case NEGATE_EXPR:
@@ -2108,8 +2202,6 @@ estimate_num_insns_1 (tree *tp, int *walk_subtrees, void *data)
     case UNEQ_EXPR:
     case LTGT_EXPR:
 
-    case CONVERT_EXPR:
-
     case CONJ_EXPR:
 
     case PREDECREMENT_EXPR:
@@ -2130,8 +2222,11 @@ estimate_num_insns_1 (tree *tp, int *walk_subtrees, void *data)
     case VEC_WIDEN_MULT_LO_EXPR:
     case VEC_UNPACK_HI_EXPR:
     case VEC_UNPACK_LO_EXPR:
-    case VEC_PACK_MOD_EXPR:
+    case VEC_UNPACK_FLOAT_HI_EXPR:
+    case VEC_UNPACK_FLOAT_LO_EXPR:
+    case VEC_PACK_TRUNC_EXPR:
     case VEC_PACK_SAT_EXPR:
+    case VEC_PACK_FIX_TRUNC_EXPR:
 
     case WIDEN_MULT_EXPR:
 
@@ -2167,7 +2262,6 @@ estimate_num_insns_1 (tree *tp, int *walk_subtrees, void *data)
     case CALL_EXPR:
       {
        tree decl = get_callee_fndecl (x);
-       tree arg;
 
        cost = d->weights->call_cost;
        if (decl && DECL_BUILT_IN_CLASS (decl) == BUILT_IN_NORMAL)
@@ -2190,11 +2284,14 @@ estimate_num_insns_1 (tree *tp, int *walk_subtrees, void *data)
           that does use function declaration to figure out the arguments.  */
        if (!decl)
          {
-           for (arg = TREE_OPERAND (x, 1); arg; arg = TREE_CHAIN (arg))
-             d->count += estimate_move_cost (TREE_TYPE (TREE_VALUE (arg)));
+           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));
          }
@@ -2223,7 +2320,7 @@ estimate_num_insns_1 (tree *tp, int *walk_subtrees, void *data)
 }
 
 /* Estimate number of instructions that will be created by expanding EXPR.
-   WEIGHTS contains weigths attributed to various constructs.  */
+   WEIGHTS contains weights attributed to various constructs.  */
 
 int
 estimate_num_insns (tree expr, eni_weights *weights)
@@ -2279,34 +2376,13 @@ init_inline_once (void)
   /* Estimating time for call is difficult, since we have no idea what the
      called function does.  In the current uses of eni_time_weights,
      underestimating the cost does less harm than overestimating it, so
-     we choose a rather small walue here.  */
+     we choose a rather small value here.  */
   eni_time_weights.call_cost = 10;
   eni_time_weights.div_mod_cost = 10;
   eni_time_weights.switch_cost = 4;
   eni_time_weights.omp_cost = 40;
 }
 
-typedef struct function *function_p;
-
-DEF_VEC_P(function_p);
-DEF_VEC_ALLOC_P(function_p,heap);
-
-/* Initialized with NOGC, making this poisonous to the garbage collector.  */
-static VEC(function_p,heap) *cfun_stack;
-
-void
-push_cfun (struct function *new_cfun)
-{
-  VEC_safe_push (function_p, heap, cfun_stack, cfun);
-  cfun = new_cfun;
-}
-
-void
-pop_cfun (void)
-{
-  cfun = VEC_pop (function_p, cfun_stack);
-}
-
 /* Install new lexical TREE_BLOCK underneath 'current_block'.  */
 static void
 add_lexical_block (tree current_block, tree new_block)
@@ -2331,8 +2407,7 @@ expand_call_inline (basic_block bb, tree stmt, tree *tp, void *data)
   tree t;
   tree use_retvar;
   tree fn;
-  splay_tree st;
-  tree args;
+  struct pointer_map_t *st;
   tree return_slot;
   tree modify_dest;
   location_t saved_location;
@@ -2400,8 +2475,14 @@ expand_call_inline (basic_block bb, tree stmt, tree *tp, void *data)
          (incorrect node sharing is most common reason for missing edges.  */
       gcc_assert (dest->needed || !flag_unit_at_a_time);
       cgraph_create_edge (id->dst_node, dest, stmt,
-                         bb->count, bb->loop_depth)->inline_failed
+                         bb->count, CGRAPH_FREQ_BASE,
+                         bb->loop_depth)->inline_failed
        = N_("originally indirect function call not considered for inlining");
+      if (dump_file)
+       {
+          fprintf (dump_file, "Created new direct edge to %s",
+                   cgraph_node_name (dest));
+       }
       goto egress;
     }
 
@@ -2481,18 +2562,15 @@ expand_call_inline (basic_block bb, tree stmt, tree *tp, void *data)
   /* Local declarations will be replaced by their equivalents in this
      map.  */
   st = id->decl_map;
-  id->decl_map = splay_tree_new (splay_tree_compare_pointers,
-                                NULL, NULL);
-
-  /* Initialize the parameters.  */
-  args = TREE_OPERAND (t, 1);
+  id->decl_map = pointer_map_create ();
 
   /* Record the function we are about to inline.  */
   id->src_fn = fn;
   id->src_node = cg_edge->callee;
   id->src_cfun = DECL_STRUCT_FUNCTION (fn);
+  id->call_expr = t;
 
-  initialize_inlined_parameters (id, args, TREE_OPERAND (t, 2), fn, bb);
+  initialize_inlined_parameters (id, t, fn, bb);
 
   if (DECL_INITIAL (fn))
     add_lexical_block (id->block, remap_blocks (DECL_INITIAL (fn), id));
@@ -2551,7 +2629,7 @@ expand_call_inline (basic_block bb, tree stmt, tree *tp, void *data)
     }
 
   /* Clean up.  */
-  splay_tree_delete (id->decl_map);
+  pointer_map_destroy (id->decl_map);
   id->decl_map = st;
 
   /* If the inlined function returns a result that we care about,
@@ -2676,6 +2754,75 @@ fold_marked_statements (int first, struct pointer_set_t *statements)
       }
 }
 
+/* Return true if BB has at least one abnormal outgoing edge.  */
+
+static inline bool
+has_abnormal_outgoing_edge_p (basic_block bb)
+{
+  edge e;
+  edge_iterator ei;
+
+  FOR_EACH_EDGE (e, ei, bb->succs)
+    if (e->flags & EDGE_ABNORMAL)
+      return true;
+
+  return false;
+}
+
+/* When a block from the inlined function contains a call with side-effects
+   in the middle gets inlined in a function with non-locals labels, the call
+   becomes a potential non-local goto so we need to add appropriate edge.  */
+
+static void
+make_nonlocal_label_edges (void)
+{
+  block_stmt_iterator bsi;
+  basic_block bb;
+
+  FOR_EACH_BB (bb)
+    {
+      for (bsi = bsi_start (bb); !bsi_end_p (bsi); bsi_next (&bsi))
+       {
+         tree stmt = bsi_stmt (bsi);
+         if (tree_can_make_abnormal_goto (stmt))
+           {
+             if (stmt == bsi_stmt (bsi_last (bb)))
+               {
+                 if (!has_abnormal_outgoing_edge_p (bb))
+                   make_abnormal_goto_edges (bb, true);
+               }
+             else
+               {
+                 edge e = split_block (bb, stmt);
+                 bb = e->src;
+                 make_abnormal_goto_edges (bb, true);
+               }
+             break;
+           }
+
+         /* Update PHIs on nonlocal goto receivers we (possibly)
+            just created new edges into.  */
+         if (TREE_CODE (stmt) == LABEL_EXPR
+             && gimple_in_ssa_p (cfun))
+           {
+             tree target = LABEL_EXPR_LABEL (stmt);
+             if (DECL_NONLOCAL (target))
+               {
+                 tree phi;
+
+                 for (phi = phi_nodes (bb); phi; phi = PHI_CHAIN (phi))
+                   {
+                     gcc_assert (SSA_NAME_OCCURS_IN_ABNORMAL_PHI
+                                 (PHI_RESULT (phi)));
+                     mark_sym_for_renaming
+                       (SSA_NAME_VAR (PHI_RESULT (phi)));
+                   }
+               }
+           }
+       }
+    }
+}
+
 /* Expand calls to inline functions in the body of FN.  */
 
 unsigned int
@@ -2713,6 +2860,10 @@ optimize_inline_calls (tree fn)
 
   push_gimplify_context ();
 
+  /* We make no attempts to keep dominance info up-to-date.  */
+  free_dominance_info (CDI_DOMINATORS);
+  free_dominance_info (CDI_POST_DOMINATORS);
+
   /* Reach the trees by walking over the CFG, and note the
      enclosing basic-blocks in the call edges.  */
   /* We walk the blocks going forward, because inlined function bodies
@@ -2723,10 +2874,6 @@ optimize_inline_calls (tree fn)
     gimple_expand_calls_inline (bb, &id);
 
   pop_gimplify_context (NULL);
-  /* Renumber the (code) basic_blocks consecutively.  */
-  compact_blocks ();
-  /* Renumber the lexical scoping (non-code) blocks consecutively.  */
-  number_blocks (fn);
 
 #ifdef ENABLE_CHECKING
     {
@@ -2739,27 +2886,30 @@ optimize_inline_calls (tree fn)
        gcc_assert (e->inline_failed);
     }
 #endif
-  /* We need to rescale frequencies again to peak at REG_BR_PROB_BASE
-     as inlining loops might increase the maximum.  */
-  if (ENTRY_BLOCK_PTR->count)
-    counts_to_freqs ();
+  
+  /* Fold the statements before compacting/renumbering the basic blocks.  */
+  fold_marked_statements (last, id.statements_to_fold);
+  pointer_set_destroy (id.statements_to_fold);
+  
+  /* Renumber the (code) basic_blocks consecutively.  */
+  compact_blocks ();
+  /* Renumber the lexical scoping (non-code) blocks consecutively.  */
+  number_blocks (fn);
 
   /* We are not going to maintain the cgraph edges up to date.
      Kill it so it won't confuse us.  */
   cgraph_node_remove_callees (id.dst_node);
 
-  fold_marked_statements (last, id.statements_to_fold);
-  pointer_set_destroy (id.statements_to_fold);
   fold_cond_expr_cond ();
-  /* We make no attempts to keep dominance info up-to-date.  */
-  free_dominance_info (CDI_DOMINATORS);
-  free_dominance_info (CDI_POST_DOMINATORS);
+  if (current_function_has_nonlocal_label)
+    make_nonlocal_label_edges ();
   /* It would be nice to check SSA/CFG/statement consistency here, but it is
      not possible yet - the IPA passes might make various functions to not
      throw and they don't care to proactively update local EH info.  This is
      done later in fixup_cfg pass that also execute the verification.  */
   return (TODO_update_ssa | TODO_cleanup_cfg
-         | (gimple_in_ssa_p (cfun) ? TODO_remove_unused_locals : 0));
+         | (gimple_in_ssa_p (cfun) ? TODO_remove_unused_locals : 0)
+         | (profile_status != PROFILE_ABSENT ? TODO_rebuild_frequencies : 0));
 }
 
 /* FN is a function that has a complete body, and CLONE is a function whose
@@ -2777,7 +2927,7 @@ clone_body (tree clone, tree fn, void *arg_map)
   id.src_fn = fn;
   id.dst_fn = clone;
   id.src_cfun = DECL_STRUCT_FUNCTION (fn);
-  id.decl_map = (splay_tree)arg_map;
+  id.decl_map = (struct pointer_map_t *)arg_map;
 
   id.copy_decl = copy_decl_no_change;
   id.transform_call_graph_edges = CB_CGE_DUPLICATE;
@@ -2871,12 +3021,12 @@ copy_tree_r (tree *tp, int *walk_subtrees, void *data ATTRIBUTE_UNUSED)
 static void
 remap_save_expr (tree *tp, void *st_, int *walk_subtrees)
 {
-  splay_tree st = (splay_tree) st_;
-  splay_tree_node n;
+  struct pointer_map_t *st = (struct pointer_map_t *) st_;
+  tree *n;
   tree t;
 
   /* See if we already encountered this SAVE_EXPR.  */
-  n = splay_tree_lookup (st, (splay_tree_key) *tp);
+  n = (tree *) pointer_map_contains (st, *tp);
 
   /* If we didn't already remap this SAVE_EXPR, do so now.  */
   if (!n)
@@ -2884,15 +3034,15 @@ remap_save_expr (tree *tp, void *st_, int *walk_subtrees)
       t = copy_node (*tp);
 
       /* Remember this SAVE_EXPR.  */
-      splay_tree_insert (st, (splay_tree_key) *tp, (splay_tree_value) t);
+      *pointer_map_insert (st, *tp) = t;
       /* Make sure we don't remap an already-remapped SAVE_EXPR.  */
-      splay_tree_insert (st, (splay_tree_key) t, (splay_tree_value) t);
+      *pointer_map_insert (st, t) = t;
     }
   else
     {
       /* We've already walked into this SAVE_EXPR; don't do it again.  */
       *walk_subtrees = 0;
-      t = (tree) n->value;
+      t = *n;
     }
 
   /* Replace this SAVE_EXPR with the copy.  */
@@ -2957,19 +3107,19 @@ static tree
 unsave_r (tree *tp, int *walk_subtrees, void *data)
 {
   copy_body_data *id = (copy_body_data *) data;
-  splay_tree st = id->decl_map;
-  splay_tree_node n;
+  struct pointer_map_t *st = id->decl_map;
+  tree *n;
 
   /* Only a local declaration (variable or label).  */
   if ((TREE_CODE (*tp) == VAR_DECL && !TREE_STATIC (*tp))
       || TREE_CODE (*tp) == LABEL_DECL)
     {
       /* Lookup the declaration.  */
-      n = splay_tree_lookup (st, (splay_tree_key) *tp);
+      n = (tree *) pointer_map_contains (st, *tp);
 
       /* If it's there, remap it.  */
       if (n)
-       *tp = (tree) n->value;
+       *tp = *n;
     }
 
   else if (TREE_CODE (*tp) == STATEMENT_LIST)
@@ -3006,7 +3156,7 @@ unsave_expr_now (tree expr)
   memset (&id, 0, sizeof (id));
   id.src_fn = current_function_decl;
   id.dst_fn = current_function_decl;
-  id.decl_map = splay_tree_new (splay_tree_compare_pointers, NULL, NULL);
+  id.decl_map = pointer_map_create ();
 
   id.copy_decl = copy_decl_no_change;
   id.transform_call_graph_edges = CB_CGE_DUPLICATE;
@@ -3021,7 +3171,7 @@ unsave_expr_now (tree expr)
   walk_tree (&expr, unsave_r, &id, NULL);
 
   /* Clean up.  */
-  splay_tree_delete (id.decl_map);
+  pointer_map_destroy (id.decl_map);
 
   return expr;
 }
@@ -3124,6 +3274,7 @@ copy_decl_to_var (tree decl, copy_body_data *id)
   TREE_READONLY (copy) = TREE_READONLY (decl);
   TREE_THIS_VOLATILE (copy) = TREE_THIS_VOLATILE (decl);
   DECL_GIMPLE_REG_P (copy) = DECL_GIMPLE_REG_P (decl);
+  DECL_NO_TBAA_P (copy) = DECL_NO_TBAA_P (decl);
 
   return copy_decl_for_dup_finish (id, decl, copy);
 }
@@ -3150,6 +3301,7 @@ copy_result_decl_to_var (tree decl, copy_body_data *id)
     {
       TREE_ADDRESSABLE (copy) = TREE_ADDRESSABLE (decl);
       DECL_GIMPLE_REG_P (copy) = DECL_GIMPLE_REG_P (decl);
+      DECL_NO_TBAA_P (copy) = DECL_NO_TBAA_P (decl);
     }
 
   return copy_decl_for_dup_finish (id, decl, copy);
@@ -3280,7 +3432,7 @@ tree_function_versioning (tree old_decl, tree new_decl, varray_type tree_map,
       id.statements_to_fold = pointer_set_create ();
     }
   
-  id.decl_map = splay_tree_new (splay_tree_compare_pointers, NULL, NULL);
+  id.decl_map = pointer_map_create ();
   id.src_fn = old_decl;
   id.dst_fn = new_decl;
   id.src_node = old_version_node;
@@ -3357,7 +3509,7 @@ tree_function_versioning (tree old_decl, tree new_decl, varray_type tree_map,
   number_blocks (new_decl);
 
   /* Clean up.  */
-  splay_tree_delete (id.decl_map);
+  pointer_map_destroy (id.decl_map);
   if (!update_clones)
     {
       fold_marked_statements (0, id.statements_to_fold);
@@ -3398,11 +3550,11 @@ build_duplicate_type (tree type)
   id.src_fn = current_function_decl;
   id.dst_fn = current_function_decl;
   id.src_cfun = cfun;
-  id.decl_map = splay_tree_new (splay_tree_compare_pointers, NULL, NULL);
+  id.decl_map = pointer_map_create ();
 
   type = remap_type_1 (type, &id);
 
-  splay_tree_delete (id.decl_map);
+  pointer_map_destroy (id.decl_map);
 
   return type;
 }