OSDN Git Service

* trans.c (convert_with_check): Update call to real_2expN.
[pf3gnuchains/gcc-fork.git] / gcc / tree-inline.c
index 2a350cc..d49c3c8 100644 (file)
@@ -7,7 +7,7 @@ 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,
@@ -16,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"
@@ -52,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.  */
@@ -341,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);
@@ -428,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,
@@ -586,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;
 
@@ -641,8 +643,7 @@ 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
@@ -814,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:
@@ -1268,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
@@ -1849,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
@@ -1894,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);
@@ -2011,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
@@ -2020,6 +2092,7 @@ 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:
@@ -2085,6 +2158,7 @@ estimate_num_insns_1 (tree *tp, int *walk_subtrees, void *data)
     case MINUS_EXPR:
     case MULT_EXPR:
 
+    case FIXED_CONVERT_EXPR:
     case FIX_TRUNC_EXPR:
 
     case NEGATE_EXPR:
@@ -2309,27 +2383,6 @@ init_inline_once (void)
   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)
@@ -2515,6 +2568,7 @@ expand_call_inline (basic_block bb, tree stmt, tree *tp, void *data)
   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, t, fn, bb);
 
@@ -2820,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
     {
@@ -2836,13 +2886,20 @@ optimize_inline_calls (tree fn)
        gcc_assert (e->inline_failed);
     }
 #endif
+  
+  /* 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 ();
   if (current_function_has_nonlocal_label)
     make_nonlocal_label_edges ();