+/* Copy the PHIs. All blocks and edges are copied, some blocks
+ was possibly split and new outgoing EH edges inserted.
+ BB points to the block of original function and AUX pointers links
+ the original and newly copied blocks. */
+
+static void
+copy_phis_for_bb (basic_block bb, copy_body_data *id)
+{
+ basic_block new_bb = bb->aux;
+ edge_iterator ei;
+ tree phi;
+
+ for (phi = phi_nodes (bb); phi; phi = PHI_CHAIN (phi))
+ {
+ tree res = PHI_RESULT (phi);
+ tree new_res = res;
+ tree new_phi;
+ edge new_edge;
+
+ if (is_gimple_reg (res))
+ {
+ walk_tree (&new_res, copy_body_r, id, NULL);
+ SSA_NAME_DEF_STMT (new_res)
+ = new_phi = create_phi_node (new_res, new_bb);
+ FOR_EACH_EDGE (new_edge, ei, new_bb->preds)
+ {
+ edge old_edge = find_edge (new_edge->src->aux, bb);
+ tree arg = PHI_ARG_DEF_FROM_EDGE (phi, old_edge);
+ tree new_arg = arg;
+
+ walk_tree (&new_arg, copy_body_r, id, NULL);
+ gcc_assert (new_arg);
+ /* With return slot optimization we can end up with
+ non-gimple (foo *)&this->m, fix that here. */
+ if (TREE_CODE (new_arg) != SSA_NAME
+ && TREE_CODE (new_arg) != FUNCTION_DECL
+ && !is_gimple_val (new_arg))
+ {
+ tree stmts = NULL_TREE;
+ new_arg = force_gimple_operand (new_arg, &stmts,
+ true, NULL);
+ bsi_insert_on_edge_immediate (new_edge, stmts);
+ }
+ add_phi_arg (new_phi, new_arg, new_edge);
+ }
+ }
+ }
+}
+
+/* Wrapper for remap_decl so it can be used as a callback. */
+static tree
+remap_decl_1 (tree decl, void *data)
+{
+ return remap_decl (decl, (copy_body_data *) data);
+}
+
+/* Build struct function and associated datastructures for the new clone
+ NEW_FNDECL to be build. CALLEE_FNDECL is the original */
+
+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);
+ int count_scale, frequency_scale;
+
+ if (ENTRY_BLOCK_PTR_FOR_FUNCTION (src_cfun)->count)
+ count_scale = (REG_BR_PROB_BASE * count
+ / ENTRY_BLOCK_PTR_FOR_FUNCTION (src_cfun)->count);
+ else
+ count_scale = 1;
+
+ if (ENTRY_BLOCK_PTR_FOR_FUNCTION (src_cfun)->frequency)
+ frequency_scale = (REG_BR_PROB_BASE * frequency
+ /
+ ENTRY_BLOCK_PTR_FOR_FUNCTION (src_cfun)->frequency);
+ else
+ frequency_scale = count_scale;
+
+ /* Register specific tree functions. */
+ tree_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);
+ init_empty_tree_cfg ();
+
+ ENTRY_BLOCK_PTR->count =
+ (ENTRY_BLOCK_PTR_FOR_FUNCTION (src_cfun)->count * count_scale /
+ REG_BR_PROB_BASE);
+ ENTRY_BLOCK_PTR->frequency =
+ (ENTRY_BLOCK_PTR_FOR_FUNCTION (src_cfun)->frequency *
+ frequency_scale / REG_BR_PROB_BASE);
+ EXIT_BLOCK_PTR->count =
+ (EXIT_BLOCK_PTR_FOR_FUNCTION (src_cfun)->count * count_scale /
+ REG_BR_PROB_BASE);
+ EXIT_BLOCK_PTR->frequency =
+ (EXIT_BLOCK_PTR_FOR_FUNCTION (src_cfun)->frequency *
+ frequency_scale / REG_BR_PROB_BASE);
+ if (src_cfun->eh)
+ init_eh_for_function ();
+
+ if (src_cfun->gimple_df)
+ {
+ init_tree_ssa (cfun);
+ cfun->gimple_df->in_ssa_p = true;
+ init_ssa_operands ();
+ }
+ pop_cfun ();
+}
+
+/* Make a copy of the body of FN so that it can be inserted inline in
+ another function. Walks FN via CFG, returns new fndecl. */
+
+static tree
+copy_cfg_body (copy_body_data * id, gcov_type count, int frequency,
+ basic_block entry_block_map, basic_block exit_block_map)
+{
+ tree callee_fndecl = id->src_fn;
+ /* Original cfun for the callee, doesn't change. */
+ struct function *src_cfun = DECL_STRUCT_FUNCTION (callee_fndecl);
+ struct function *cfun_to_copy;
+ basic_block bb;
+ tree new_fndecl = NULL;
+ int count_scale, frequency_scale;
+ int last;
+
+ if (ENTRY_BLOCK_PTR_FOR_FUNCTION (src_cfun)->count)
+ count_scale = (REG_BR_PROB_BASE * count
+ / ENTRY_BLOCK_PTR_FOR_FUNCTION (src_cfun)->count);
+ else
+ count_scale = 1;
+
+ if (ENTRY_BLOCK_PTR_FOR_FUNCTION (src_cfun)->frequency)
+ frequency_scale = (REG_BR_PROB_BASE * frequency
+ /
+ ENTRY_BLOCK_PTR_FOR_FUNCTION (src_cfun)->frequency);
+ else
+ frequency_scale = count_scale;
+
+ /* Register specific tree functions. */
+ tree_register_cfg_hooks ();
+
+ /* Must have a CFG here at this point. */
+ gcc_assert (ENTRY_BLOCK_PTR_FOR_FUNCTION
+ (DECL_STRUCT_FUNCTION (callee_fndecl)));
+
+ cfun_to_copy = id->src_cfun = DECL_STRUCT_FUNCTION (callee_fndecl);
+
+
+ ENTRY_BLOCK_PTR_FOR_FUNCTION (cfun_to_copy)->aux = entry_block_map;
+ EXIT_BLOCK_PTR_FOR_FUNCTION (cfun_to_copy)->aux = exit_block_map;
+ entry_block_map->aux = ENTRY_BLOCK_PTR_FOR_FUNCTION (cfun_to_copy);
+ exit_block_map->aux = EXIT_BLOCK_PTR_FOR_FUNCTION (cfun_to_copy);
+
+ /* Duplicate any exception-handling regions. */
+ if (cfun->eh)
+ {
+ id->eh_region_offset
+ = duplicate_eh_regions (cfun_to_copy, remap_decl_1, id,
+ 0, id->eh_region);
+ }
+ /* Use aux pointers to map the original blocks to copy. */
+ FOR_EACH_BB_FN (bb, cfun_to_copy)
+ {
+ basic_block new = copy_bb (id, bb, frequency_scale, count_scale);
+ bb->aux = new;
+ new->aux = bb;
+ }
+
+ 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, exit_block_map);
+ if (gimple_in_ssa_p (cfun))
+ FOR_ALL_BB_FN (bb, cfun_to_copy)
+ copy_phis_for_bb (bb, id);
+ FOR_ALL_BB_FN (bb, cfun_to_copy)
+ {
+ ((basic_block)bb->aux)->aux = NULL;
+ bb->aux = NULL;
+ }
+ /* Zero out AUX fields of newly created block during EH edge
+ insertion. */
+ for (; last < last_basic_block; last++)
+ BASIC_BLOCK (last)->aux = NULL;
+ entry_block_map->aux = NULL;
+ exit_block_map->aux = NULL;
+
+ return new_fndecl;
+}
+
+/* Make a copy of the body of FN so that it can be inserted inline in
+ another function. */
+
+tree
+copy_generic_body (copy_body_data *id)
+{
+ tree body;
+ tree fndecl = id->src_fn;
+
+ body = DECL_SAVED_TREE (fndecl);
+ walk_tree (&body, copy_body_r, id, NULL);
+
+ return body;
+}
+
+static tree
+copy_body (copy_body_data *id, gcov_type count, int frequency,
+ basic_block entry_block_map, basic_block exit_block_map)
+{
+ tree fndecl = id->src_fn;
+ tree body;
+
+ /* If this body has a CFG, walk CFG and copy. */
+ gcc_assert (ENTRY_BLOCK_PTR_FOR_FUNCTION (DECL_STRUCT_FUNCTION (fndecl)));
+ body = copy_cfg_body (id, count, frequency, entry_block_map, exit_block_map);
+
+ return body;
+}
+
+/* Return true if VALUE is an ADDR_EXPR of an automatic variable
+ defined in function FN, or of a data member thereof. */
+
+static bool
+self_inlining_addr_expr (tree value, tree fn)
+{
+ tree var;
+
+ if (TREE_CODE (value) != ADDR_EXPR)
+ return false;
+
+ var = get_base_address (TREE_OPERAND (value, 0));
+
+ return var && auto_var_in_fn_p (var, fn);
+}
+
+static void
+setup_one_parameter (copy_body_data *id, tree p, tree value, tree fn,
+ basic_block bb, tree *vars)
+{
+ tree init_stmt;
+ tree var;
+ 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)))
+ {
+ 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
+ be able to just use the argument value. */
+ if (TREE_READONLY (p)
+ && !TREE_ADDRESSABLE (p)
+ && value && !TREE_SIDE_EFFECTS (value)
+ && !def)
+ {
+ /* We may produce non-gimple trees by adding NOPs or introduce
+ invalid sharing when operand is not really constant.
+ 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)
+ && 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
+ mutually-recursive or whatever, which is why we don't
+ just test whether fn == current_function_decl. */
+ && ! self_inlining_addr_expr (value, fn))
+ {
+ insert_decl_map (id, p, value);
+ return;
+ }
+ }
+
+ /* Make an equivalent VAR_DECL. Note that we must NOT remap the type
+ here since the type of this decl must be visible to the calling
+ function. */
+ var = copy_decl_to_var (p, id);
+ if (gimple_in_ssa_p (cfun) && TREE_CODE (var) == VAR_DECL)
+ {
+ get_var_ann (var);
+ add_referenced_var (var);
+ }
+
+ /* Register the VAR_DECL as the equivalent for the PARM_DECL;
+ that way, when the PARM_DECL is encountered, it will be
+ automatically replaced by the VAR_DECL. */
+ insert_decl_map (id, p, var);
+
+ /* Declare this new variable. */
+ TREE_CHAIN (var) = *vars;
+ *vars = var;
+
+ /* Make gimplifier happy about this variable. */
+ DECL_SEEN_IN_BIND_EXPR_P (var) = 1;
+
+ /* Even if P was TREE_READONLY, the new VAR should not be.
+ In the original code, we would have constructed a
+ temporary, and then the function body would have never
+ changed the value of P. However, now, we will be
+ constructing VAR directly. The constructor body may
+ change its value multiple times as it is being
+ constructed. Therefore, it must not be TREE_READONLY;
+ the back-end assumes that TREE_READONLY variable is
+ assigned to only once. */
+ if (TYPE_NEEDS_CONSTRUCTING (TREE_TYPE (p)))
+ TREE_READONLY (var) = 0;
+
+ /* If there is no setup required and we are in SSA, take the easy route
+ replacing all SSA names representing the function parameter by the
+ SSA name passed to function.
+
+ We need to construct map for the variable anyway as it might be used
+ in different SSA names when parameter is set in function.
+
+ FIXME: This usually kills the last connection in between inlined
+ function parameter and the actual value in debug info. Can we do
+ better here? If we just inserted the statement, copy propagation
+ would kill it anyway as it always did in older versions of GCC.
+
+ 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)
+ && (TREE_CODE (rhs) == SSA_NAME
+ || is_gimple_min_invariant (rhs))
+ && !SSA_NAME_OCCURS_IN_ABNORMAL_PHI (def))
+ {
+ insert_decl_map (id, def, rhs);
+ return;
+ }
+
+ /* 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))
+ {
+ gcc_assert (!value || !TREE_SIDE_EFFECTS (value));
+ return;
+ }
+
+ /* Initialize this VAR_DECL from the equivalent argument. Convert
+ the argument to the proper type in case it was promoted. */
+ if (value)
+ {
+ block_stmt_iterator bsi = bsi_last (bb);
+
+ if (rhs == error_mark_node)
+ {
+ insert_decl_map (id, p, var);
+ return;
+ }
+
+ STRIP_USELESS_TYPE_CONVERSION (rhs);
+
+ /* We want to use GIMPLE_MODIFY_STMT, not INIT_EXPR here so that we
+ keep our trees in gimple form. */
+ if (def && gimple_in_ssa_p (cfun) && is_gimple_reg (p))
+ {
+ def = remap_ssa_name (def, id);
+ 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 = 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
+ at the end. Note that is_gimple_cast only checks the outer
+ tree code, not its operand. Thus the explicit check that its
+ operand is a gimple value. */
+ if ((!is_gimple_val (rhs)
+ && (!is_gimple_cast (rhs)
+ || !is_gimple_val (TREE_OPERAND (rhs, 0))))
+ || !is_gimple_reg (var))
+ {
+ tree_stmt_iterator i;
+
+ push_gimplify_context ();
+ gimplify_stmt (&init_stmt);
+ if (gimple_in_ssa_p (cfun)
+ && init_stmt && TREE_CODE (init_stmt) == STATEMENT_LIST)
+ {
+ /* The replacement can expose previously unreferenced
+ variables. */
+ for (i = tsi_start (init_stmt); !tsi_end_p (i); tsi_next (&i))
+ find_new_referenced_vars (tsi_stmt_ptr (i));
+ }
+ pop_gimplify_context (NULL);
+ }
+
+ /* If VAR represents a zero-sized variable, it's possible that the
+ assignment statment may result in no gimple statements. */
+ if (init_stmt)
+ bsi_insert_after (&bsi, init_stmt, BSI_NEW_STMT);
+ if (gimple_in_ssa_p (cfun))
+ for (;!bsi_end_p (bsi); bsi_next (&bsi))
+ mark_symbols_for_renaming (bsi_stmt (bsi));
+ }
+}
+
+/* Generate code to initialize the parameters of the function at the
+ top of the stack in ID from the CALL_EXPR EXP. */
+
+static void
+initialize_inlined_parameters (copy_body_data *id, tree exp,
+ tree fn, basic_block bb)
+{
+ tree parms;
+ tree a;
+ tree p;
+ tree vars = NULL_TREE;
+ 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 = 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;
+ gcc_assert (fn != current_function_decl);
+ if (p)