OSDN Git Service

contrib/
[pf3gnuchains/gcc-fork.git] / gcc / tree-inline.c
index 3b77c0e..8ff784a 100644 (file)
@@ -129,7 +129,7 @@ static void unsave_expr_1 (tree);
 static tree unsave_r (tree *, int *, void *);
 static void declare_inline_vars (tree, tree);
 static void remap_save_expr (tree *, void *, int *);
-static void add_lexical_block (tree current_block, tree new_block);
+static void prepend_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_maybe_to_var (tree, copy_body_data *);
@@ -512,7 +512,10 @@ remap_blocks (tree block, copy_body_data *id)
   remap_block (&new_tree, id);
   gcc_assert (new_tree != block);
   for (t = BLOCK_SUBBLOCKS (block); t ; t = BLOCK_CHAIN (t))
-    add_lexical_block (new_tree, remap_blocks (t, id));
+    prepend_lexical_block (new_tree, remap_blocks (t, id));
+  /* Blocks are in arbitrary order, but make things slightly prettier and do
+     not swap order when producing a copy.  */
+  BLOCK_SUBBLOCKS (new_tree) = blocks_nreverse (BLOCK_SUBBLOCKS (new_tree));
   return new_tree;
 }
 
@@ -707,6 +710,7 @@ remap_gimple_op_r (tree *tp, int *walk_subtrees, void *data)
                    {
                      *tp = build1 (INDIRECT_REF, type, new_tree);
                      TREE_THIS_VOLATILE (*tp) = TREE_THIS_VOLATILE (old);
+                     TREE_NO_WARNING (*tp) = TREE_NO_WARNING (old);
                    }
                }
              *walk_subtrees = 0;
@@ -1026,6 +1030,7 @@ remap_gimple_stmt (gimple stmt, copy_body_data *id)
   gimple copy = NULL;
   struct walk_stmt_info wi;
   tree new_block;
+  bool skip_first = false;
 
   /* Begin by recognizing trees that we'll completely rewrite for the
      inlining context.  Our output for these trees is completely
@@ -1047,7 +1052,11 @@ remap_gimple_stmt (gimple stmt, copy_body_data *id)
         already been set (e.g. a recent "foo (&result_decl, ...)");
         just toss the entire GIMPLE_RETURN.  */
       if (retval && TREE_CODE (retval) != RESULT_DECL)
-       copy = gimple_build_assign (id->retvar, retval);
+        {
+         copy = gimple_build_assign (id->retvar, retval);
+         /* id->retvar is already substituted.  Skip it on later remapping.  */
+         skip_first = true;
+       }
       else
        return gimple_build_nop ();
     }
@@ -1213,7 +1222,10 @@ remap_gimple_stmt (gimple stmt, copy_body_data *id)
   /* Remap all the operands in COPY.  */
   memset (&wi, 0, sizeof (wi));
   wi.info = id;
-  walk_gimple_op (copy, remap_gimple_op_r, &wi); 
+  if (skip_first)
+    walk_tree (gimple_op_ptr (copy, 1), remap_gimple_op_r, &wi, NULL);
+  else
+    walk_gimple_op (copy, remap_gimple_op_r, &wi); 
 
   /* We have to handle EH region remapping of GIMPLE_RESX specially because
      the region number is not an operand.  */
@@ -1232,7 +1244,7 @@ static basic_block
 copy_bb (copy_body_data *id, basic_block bb, int frequency_scale,
          gcov_type count_scale)
 {
-  gimple_stmt_iterator gsi, copy_gsi;
+  gimple_stmt_iterator gsi, copy_gsi, seq_gsi;
   basic_block copy_basic_block;
   tree decl;
 
@@ -1263,6 +1275,7 @@ copy_bb (copy_body_data *id, basic_block bb, int frequency_scale,
        continue;
 
       gimple_duplicate_stmt_histograms (cfun, stmt, id->src_cfun, orig_stmt);
+      seq_gsi = copy_gsi;
 
       /* With return slot optimization we can end up with
         non-gimple (foo *)&this->m, fix that here.  */
@@ -1271,21 +1284,31 @@ copy_bb (copy_body_data *id, basic_block bb, int frequency_scale,
          && !is_gimple_val (gimple_assign_rhs1 (stmt)))
        {
          tree new_rhs;
-         new_rhs = force_gimple_operand_gsi (&copy_gsi,
+         new_rhs = force_gimple_operand_gsi (&seq_gsi,
                                              gimple_assign_rhs1 (stmt),
                                              true, NULL, true, GSI_SAME_STMT);
          gimple_assign_set_rhs1 (stmt, new_rhs);
+         id->regimplify = false;
        }
-      else if (id->regimplify)
-       gimple_regimplify_operands (stmt, &copy_gsi);
 
-      gsi_insert_after (&copy_gsi, stmt, GSI_NEW_STMT);
+      gsi_insert_after (&seq_gsi, stmt, GSI_NEW_STMT);
+
+      if (id->regimplify)
+       gimple_regimplify_operands (stmt, &seq_gsi);
+
+      /* If copy_basic_block has been empty at the start of this iteration,
+        call gsi_start_bb again to get at the newly added statements.  */
+      if (gsi_end_p (copy_gsi))
+       copy_gsi = gsi_start_bb (copy_basic_block);
+      else
+       gsi_next (&copy_gsi);
 
       /* Process the new statement.  The call to gimple_regimplify_operands
         possibly turned the statement into multiple statements, we
         need to process all of them.  */
-      while (!gsi_end_p (copy_gsi))
+      do
        {
+         stmt = gsi_stmt (copy_gsi);
          if (is_gimple_call (stmt)
              && gimple_call_va_arg_pack_p (stmt)
              && id->gimple_call)
@@ -1331,6 +1354,7 @@ copy_bb (copy_body_data *id, basic_block bb, int frequency_scale,
              gimple_call_set_lhs (new_call, gimple_call_lhs (stmt));
 
              gsi_replace (&copy_gsi, new_call, false);
+             gimple_set_bb (stmt, NULL);
              stmt = new_call;
            }
          else if (is_gimple_call (stmt)
@@ -1374,6 +1398,7 @@ copy_bb (copy_body_data *id, basic_block bb, int frequency_scale,
            {
              struct cgraph_node *node;
              struct cgraph_edge *edge;
+             int flags;
 
              switch (id->transform_call_graph_edges)
                {
@@ -1405,6 +1430,13 @@ copy_bb (copy_body_data *id, basic_block bb, int frequency_scale,
              default:
                gcc_unreachable ();
                }
+
+             flags = gimple_call_flags (stmt);
+
+             if (flags & ECF_MAY_BE_ALLOCA)
+               cfun->calls_alloca = true;
+             if (flags & ECF_RETURNS_TWICE)
+               cfun->calls_setjmp = true;
            }
 
          /* If you think we can abort here, you are wrong.
@@ -1458,6 +1490,7 @@ copy_bb (copy_body_data *id, basic_block bb, int frequency_scale,
 
          gsi_next (&copy_gsi);
        }
+      while (!gsi_end_p (copy_gsi));
 
       copy_gsi = gsi_last_bb (copy_basic_block);
     }
@@ -1692,8 +1725,6 @@ static void
 initialize_cfun (tree new_fndecl, tree callee_fndecl, gcov_type count,
                 int frequency)
 {
-  struct function *new_cfun
-     = (struct function *) ggc_alloc_cleared (sizeof (struct function));
   struct function *src_cfun = DECL_STRUCT_FUNCTION (callee_fndecl);
   gcov_type count_scale, frequency_scale;
 
@@ -1712,14 +1743,36 @@ initialize_cfun (tree new_fndecl, tree callee_fndecl, gcov_type count,
 
   /* Register specific tree functions.  */
   gimple_register_cfg_hooks ();
-  *new_cfun = *DECL_STRUCT_FUNCTION (callee_fndecl);
-  new_cfun->funcdef_no = get_next_funcdef_no ();
-  VALUE_HISTOGRAMS (new_cfun) = 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;
-  push_cfun (new_cfun);
+
+  /* Get clean struct function.  */
+  push_struct_function (new_fndecl);
+
+  /* We will rebuild these, so just sanity check that they are empty.  */
+  gcc_assert (VALUE_HISTOGRAMS (cfun) == NULL);
+  gcc_assert (cfun->local_decls == NULL);
+  gcc_assert (cfun->cfg == NULL);
+  gcc_assert (cfun->decl == new_fndecl);
+
+  /* Copy items we preserve during clonning.  */
+  cfun->static_chain_decl = src_cfun->static_chain_decl;
+  cfun->nonlocal_goto_save_area = src_cfun->nonlocal_goto_save_area;
+  cfun->function_end_locus = src_cfun->function_end_locus;
+  cfun->curr_properties = src_cfun->curr_properties;
+  cfun->last_verified = src_cfun->last_verified;
+  if (src_cfun->ipa_transforms_to_apply)
+    cfun->ipa_transforms_to_apply = VEC_copy (ipa_opt_pass, heap,
+                                             src_cfun->ipa_transforms_to_apply);
+  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;
+  cfun->after_inlining = src_cfun->after_inlining;
+  cfun->returns_struct = src_cfun->returns_struct;
+  cfun->returns_pcc_struct = src_cfun->returns_pcc_struct;
+  cfun->after_tree_profile = src_cfun->after_tree_profile;
+
   init_empty_tree_cfg ();
 
   ENTRY_BLOCK_PTR->count =
@@ -1864,40 +1917,32 @@ self_inlining_addr_expr (tree value, tree fn)
 static void
 insert_init_stmt (basic_block bb, gimple init_stmt)
 {
-  gimple_stmt_iterator si = gsi_last_bb (bb);
-  gimple_stmt_iterator i;
-  gimple_seq seq = gimple_seq_alloc ();
-  struct gimplify_ctx gctx;
-
-  push_gimplify_context (&gctx);
-
-  i = gsi_start (seq);
-  gimple_regimplify_operands (init_stmt, &i);
-
-  if (init_stmt
-      && !gimple_seq_empty_p (seq))
-    {
-      /* The replacement can expose previously unreferenced
-        variables.  */
-      if (gimple_in_ssa_p (cfun))
-        for (i = gsi_start (seq); !gsi_end_p (i); gsi_next (&i))
-         find_new_referenced_vars (gsi_stmt (i));
-
-      /* Insert the gimplified sequence needed for INIT_STMT
-        after SI.  INIT_STMT will be inserted after SEQ.  */
-      gsi_insert_seq_after (&si, seq, GSI_NEW_STMT);
-     }
-
-  pop_gimplify_context (NULL);
-
   /* If VAR represents a zero-sized variable, it's possible that the
      assignment statement may result in no gimple statements.  */
   if (init_stmt)
-    gsi_insert_after (&si, init_stmt, GSI_NEW_STMT);
+    {
+      gimple_stmt_iterator si = gsi_last_bb (bb);
 
-  if (gimple_in_ssa_p (cfun))
-    for (;!gsi_end_p (si); gsi_next (&si))
-      mark_symbols_for_renaming (gsi_stmt (si));
+      /* We can end up with init statements that store to a non-register
+         from a rhs with a conversion.  Handle that here by forcing the
+        rhs into a temporary.  gimple_regimplify_operands is not
+        prepared to do this for us.  */
+      if (!is_gimple_reg (gimple_assign_lhs (init_stmt))
+         && is_gimple_reg_type (TREE_TYPE (gimple_assign_lhs (init_stmt)))
+         && gimple_assign_rhs_class (init_stmt) == GIMPLE_UNARY_RHS)
+       {
+         tree rhs = build1 (gimple_assign_rhs_code (init_stmt),
+                            gimple_expr_type (init_stmt),
+                            gimple_assign_rhs1 (init_stmt));
+         rhs = force_gimple_operand_gsi (&si, rhs, true, NULL_TREE, false,
+                                         GSI_NEW_STMT);
+         gimple_assign_set_rhs_code (init_stmt, TREE_CODE (rhs));
+         gimple_assign_set_rhs1 (init_stmt, rhs);
+       }
+      gsi_insert_after (&si, init_stmt, GSI_NEW_STMT);
+      gimple_regimplify_operands (init_stmt, &si);
+      mark_symbols_for_renaming (init_stmt);
+    }
 }
 
 /* Initialize parameter P with VALUE.  If needed, produce init statement
@@ -2003,6 +2048,7 @@ setup_one_parameter (copy_body_data *id, tree p, tree value, tree fn,
      We might want to introduce a notion that single SSA_NAME might
      represent multiple variables for purposes of debugging. */
   if (gimple_in_ssa_p (cfun) && rhs && def && is_gimple_reg (p)
+      && optimize
       && (TREE_CODE (rhs) == SSA_NAME
          || is_gimple_min_invariant (rhs))
       && !SSA_NAME_OCCURS_IN_ABNORMAL_PHI (def))
@@ -2013,7 +2059,7 @@ setup_one_parameter (copy_body_data *id, tree p, tree value, tree fn,
 
   /* If the value of argument is never used, don't care about initializing
      it.  */
-  if (gimple_in_ssa_p (cfun) && !def && is_gimple_reg (p))
+  if (optimize && gimple_in_ssa_p (cfun) && !def && is_gimple_reg (p))
     {
       gcc_assert (!value || !TREE_SIDE_EFFECTS (value));
       return NULL;
@@ -2276,13 +2322,7 @@ declare_return_variable (copy_body_data *id, tree return_slot, tree modify_dest,
 bool
 tree_inlinable_function_p (tree fn)
 {
-  bool ret = inlinable_function_p (fn);
-
-  if (getenv ("TUPLES_INLINE"))
-    fprintf (stderr, "Function %s is %sinlinable\n", get_name (fn),
-            ret ? "" : "not ");
-
-  return ret;
+  return inlinable_function_p (fn);
 }
 
 static const char *inline_forbidden_reason;
@@ -2554,6 +2594,7 @@ inlinable_function_p (tree fn)
   /* We only warn for functions declared `inline' by the user.  */
   do_warning = (warn_inline
                && DECL_DECLARED_INLINE_P (fn)
+               && !DECL_NO_INLINE_WARNING_P (fn)
                && !DECL_IN_SYSTEM_HEADER (fn));
 
   always_inline = lookup_attribute ("always_inline", DECL_ATTRIBUTES (fn));
@@ -2581,12 +2622,6 @@ inlinable_function_p (tree 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
-     forward declared inline functions.  Therefore, return at once.  */
-  if (!gimple_body (fn))
-    return false;
-
   else if (inline_forbidden_p (fn))
     {
       /* See if we should warn about uninlinable functions.  Previously,
@@ -3009,16 +3044,10 @@ count_insns_seq (gimple_seq seq, eni_weights *weights)
 /* Install new lexical TREE_BLOCK underneath 'current_block'.  */
 
 static void
-add_lexical_block (tree current_block, tree new_block)
+prepend_lexical_block (tree current_block, tree new_block)
 {
-  tree *blk_p;
-
-  /* Walk to the last sub-block.  */
-  for (blk_p = &BLOCK_SUBBLOCKS (current_block);
-       *blk_p;
-       blk_p = &BLOCK_CHAIN (*blk_p))
-    ;
-  *blk_p = new_block;
+  BLOCK_CHAIN (new_block) = BLOCK_SUBBLOCKS (current_block);
+  BLOCK_SUBBLOCKS (current_block) = new_block;
   BLOCK_SUPERCONTEXT (new_block) = current_block;
 }
 
@@ -3089,7 +3118,7 @@ expand_call_inline (basic_block bb, gimple stmt, copy_body_data *id)
      gimple_body.  */
   if (!DECL_INITIAL (fn)
       && DECL_ABSTRACT_ORIGIN (fn)
-      && gimple_body (DECL_ABSTRACT_ORIGIN (fn)))
+      && gimple_has_body_p (DECL_ABSTRACT_ORIGIN (fn)))
     fn = DECL_ABSTRACT_ORIGIN (fn);
 
   /* Objective C and fortran still calls tree_rest_of_compilation directly.
@@ -3199,7 +3228,7 @@ expand_call_inline (basic_block bb, gimple stmt, copy_body_data *id)
   id->block = make_node (BLOCK);
   BLOCK_ABSTRACT_ORIGIN (id->block) = fn;
   BLOCK_SOURCE_LOCATION (id->block) = input_location;
-  add_lexical_block (gimple_block (stmt), id->block);
+  prepend_lexical_block (gimple_block (stmt), id->block);
 
   /* Local declarations will be replaced by their equivalents in this
      map.  */
@@ -3225,7 +3254,7 @@ expand_call_inline (basic_block bb, gimple stmt, copy_body_data *id)
   initialize_inlined_parameters (id, stmt, fn, bb);
 
   if (DECL_INITIAL (fn))
-    add_lexical_block (id->block, remap_blocks (DECL_INITIAL (fn), id));
+    prepend_lexical_block (id->block, remap_blocks (DECL_INITIAL (fn), id));
 
   /* Return statements in the function body will be replaced by jumps
      to the RET_LABEL.  */
@@ -3277,26 +3306,31 @@ expand_call_inline (basic_block bb, gimple stmt, copy_body_data *id)
       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
-     function in any way before this point, as this CALL_EXPR may be
-     a self-referential call; if we're calling ourselves, we need to
-     duplicate our body before altering anything.  */
-  copy_body (id, bb->count, bb->frequency, bb, return_block);
-
   /* Add local vars in this inlined callee to caller.  */
   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->local_decls = tree_cons (NULL_TREE, var,
-                                              cfun->local_decls);
+       {
+         if (var_ann (var) && referenced_var_check_and_insert (var))
+           cfun->local_decls = tree_cons (NULL_TREE, var,
+                                          cfun->local_decls);
+       }
       else
-       cfun->local_decls = tree_cons (NULL_TREE, remap_decl (var, id),
-                                              cfun->local_decls);
+        {
+         cfun->local_decls = tree_cons (NULL_TREE, remap_decl (var, id),
+                                                 cfun->local_decls);
+       }
     }
 
+  /* This is it.  Duplicate the callee body.  Assume callee is
+     pre-gimplified.  Note that we must not alter the caller
+     function in any way before this point, as this CALL_EXPR may be
+     a self-referential call; if we're calling ourselves, we need to
+     duplicate our body before altering anything.  */
+  copy_body (id, bb->count, bb->frequency, bb, return_block);
+
   /* Clean up.  */
   pointer_map_destroy (id->decl_map);
   id->decl_map = st;
@@ -4112,7 +4146,7 @@ copy_arguments_for_versioning (tree orig_parm, copy_body_data * id,
         *parg = new_tree;
        parg = &TREE_CHAIN (new_tree);
       }
-    else
+    else if (!pointer_map_contains (id->decl_map, arg))
       {
        /* Make an equivalent VAR_DECL.  If the argument was used
           as temporary variable later in function, the uses will be
@@ -4192,6 +4226,12 @@ tree_function_versioning (tree old_decl, tree new_decl, varray_type tree_map,
   old_version_node = cgraph_node (old_decl);
   new_version_node = cgraph_node (new_decl);
 
+  /* Output the inlining info for this abstract function, since it has been
+     inlined.  If we don't do this now, we can lose the information about the
+     variables in the function when the blocks get blown away as soon as we
+     remove the cgraph node.  */
+  (*debug_hooks->outlining_inline_function) (old_decl);
+
   DECL_ARTIFICIAL (new_decl) = 1;
   DECL_ABSTRACT_ORIGIN (new_decl) = DECL_ORIGIN (old_decl);
 
@@ -4235,16 +4275,6 @@ tree_function_versioning (tree old_decl, tree new_decl, varray_type tree_map,
     DECL_STRUCT_FUNCTION (new_decl)->static_chain_decl =
       copy_static_chain (DECL_STRUCT_FUNCTION (old_decl)->static_chain_decl,
                         &id);
-  /* Copy the function's arguments.  */
-  if (DECL_ARGUMENTS (old_decl) != NULL_TREE)
-    DECL_ARGUMENTS (new_decl) =
-      copy_arguments_for_versioning (DECL_ARGUMENTS (old_decl), &id,
-                                    args_to_skip, &vars);
-  
-  DECL_INITIAL (new_decl) = remap_blocks (DECL_INITIAL (id.src_fn), &id);
-  
-  /* Renumber the lexical scoping (non-code) blocks consecutively.  */
-  number_blocks (id.dst_fn);
   
   /* If there's a tree_map, prepare for substitution.  */
   if (tree_map)
@@ -4279,6 +4309,16 @@ tree_function_versioning (tree old_decl, tree new_decl, varray_type tree_map,
              VEC_safe_push (gimple, heap, init_stmts, init);
          }
       }
+  /* Copy the function's arguments.  */
+  if (DECL_ARGUMENTS (old_decl) != NULL_TREE)
+    DECL_ARGUMENTS (new_decl) =
+      copy_arguments_for_versioning (DECL_ARGUMENTS (old_decl), &id,
+                                    args_to_skip, &vars);
+  
+  DECL_INITIAL (new_decl) = remap_blocks (DECL_INITIAL (id.src_fn), &id);
+  
+  /* Renumber the lexical scoping (non-code) blocks consecutively.  */
+  number_blocks (id.dst_fn);
   
   declare_inline_vars (DECL_INITIAL (new_decl), vars);
   if (DECL_STRUCT_FUNCTION (old_decl)->local_decls != NULL_TREE)