-/* See if statement might disappear after inlining. We are not terribly
- sophisficated, basically looking for simple abstraction penalty wrappers. */
-
-static bool
-likely_eliminated_by_inlining_p (gimple stmt)
-{
- enum gimple_code code = gimple_code (stmt);
- switch (code)
- {
- case GIMPLE_RETURN:
- return true;
- case GIMPLE_ASSIGN:
- if (gimple_num_ops (stmt) != 2)
- return false;
-
- /* Casts of parameters, loads from parameters passed by reference
- and stores to return value or parameters are probably free after
- inlining. */
- if (gimple_assign_rhs_code (stmt) == CONVERT_EXPR
- || gimple_assign_rhs_code (stmt) == NOP_EXPR
- || gimple_assign_rhs_code (stmt) == VIEW_CONVERT_EXPR
- || gimple_assign_rhs_class (stmt) == GIMPLE_SINGLE_RHS)
- {
- tree rhs = gimple_assign_rhs1 (stmt);
- tree lhs = gimple_assign_lhs (stmt);
- tree inner_rhs = rhs;
- tree inner_lhs = lhs;
- bool rhs_free = false;
- bool lhs_free = false;
-
- while (handled_component_p (inner_lhs) || TREE_CODE (inner_lhs) == INDIRECT_REF)
- inner_lhs = TREE_OPERAND (inner_lhs, 0);
- while (handled_component_p (inner_rhs)
- || TREE_CODE (inner_rhs) == ADDR_EXPR || TREE_CODE (inner_rhs) == INDIRECT_REF)
- inner_rhs = TREE_OPERAND (inner_rhs, 0);
-
-
- if (TREE_CODE (inner_rhs) == PARM_DECL
- || (TREE_CODE (inner_rhs) == SSA_NAME
- && SSA_NAME_IS_DEFAULT_DEF (inner_rhs)
- && TREE_CODE (SSA_NAME_VAR (inner_rhs)) == PARM_DECL))
- rhs_free = true;
- if (rhs_free && is_gimple_reg (lhs))
- lhs_free = true;
- if (((TREE_CODE (inner_lhs) == PARM_DECL
- || (TREE_CODE (inner_lhs) == SSA_NAME
- && SSA_NAME_IS_DEFAULT_DEF (inner_lhs)
- && TREE_CODE (SSA_NAME_VAR (inner_lhs)) == PARM_DECL))
- && inner_lhs != lhs)
- || TREE_CODE (inner_lhs) == RESULT_DECL
- || (TREE_CODE (inner_lhs) == SSA_NAME
- && TREE_CODE (SSA_NAME_VAR (inner_lhs)) == RESULT_DECL))
- lhs_free = true;
- if (lhs_free && (is_gimple_reg (rhs) || is_gimple_min_invariant (rhs)))
- rhs_free = true;
- if (lhs_free && rhs_free)
- return true;
- }
- return false;
- default:
- return false;
- }
-}
-
-/* Compute function body size parameters for NODE. */
-
-static void
-estimate_function_body_sizes (struct cgraph_node *node)
-{
- gcov_type time = 0;
- gcov_type time_inlining_benefit = 0;
- int size = 0;
- int size_inlining_benefit = 0;
- basic_block bb;
- gimple_stmt_iterator bsi;
- struct function *my_function = DECL_STRUCT_FUNCTION (node->decl);
- tree arg;
- int freq;
- tree funtype = TREE_TYPE (node->decl);
- bitmap must_not_throw = must_not_throw_labels ();
-
- if (dump_file)
- {
- fprintf (dump_file, "Analyzing function body size: %s\n", cgraph_node_name (node));
- }
-
- gcc_assert (my_function && my_function->cfg);
- FOR_EACH_BB_FN (bb, my_function)
- {
- freq = compute_call_stmt_bb_frequency (node->decl, bb);
- for (bsi = gsi_start_bb (bb); !gsi_end_p (bsi); gsi_next (&bsi))
- {
- int this_size = estimate_num_insns (gsi_stmt (bsi), &eni_size_weights);
- int this_time = estimate_num_insns (gsi_stmt (bsi), &eni_time_weights);
-
- /* MUST_NOT_THROW is usually handled by runtime calling terminate and stopping
- stacking unwinding. However when there is local cleanup that can resume
- to MUST_NOT_THROW then we generate explicit handler containing
- std::terminate () call.
-
- Because inlining of function can introduce new cleanup region, prior
- inlining we keep std::terinate () calls for every MUST_NOT_THROW containing
- function call. Wast majority of these will be eliminated after inlining
- and crossjumping will inify possible duplicated calls. So ignore
- the handlers for function body estimates. */
- if (gimple_code (gsi_stmt (bsi)) == GIMPLE_LABEL
- && bitmap_bit_p (must_not_throw,
- LABEL_DECL_UID (gimple_label_label (gsi_stmt (bsi)))))
- {
- if (dump_file)
- fprintf (dump_file, " MUST_NOT_THROW landing pad. Ignoring whole BB.\n");
- }
- if (dump_file)
- {
- fprintf (dump_file, " freq:%6i size:%3i time:%3i ", freq, this_size, this_time);
- print_gimple_stmt (dump_file, gsi_stmt (bsi), 0, 0);
- }
- this_time *= freq;
- time += this_time;
- size += this_size;
- if (likely_eliminated_by_inlining_p (gsi_stmt (bsi)))
- {
- size_inlining_benefit += this_size;
- time_inlining_benefit += this_time;
- if (dump_file)
- fprintf (dump_file, " Likely eliminated\n");
- }
- gcc_assert (time >= 0);
- gcc_assert (size >= 0);
- }
- }
- time = (time + CGRAPH_FREQ_BASE / 2) / CGRAPH_FREQ_BASE;
- time_inlining_benefit = ((time_inlining_benefit + CGRAPH_FREQ_BASE / 2)
- / CGRAPH_FREQ_BASE);
- if (dump_file)
- {
- fprintf (dump_file, "Overall function body time: %i-%i size: %i-%i\n",
- (int)time, (int)time_inlining_benefit,
- size, size_inlining_benefit);
- }
- time_inlining_benefit += eni_time_weights.call_cost;
- size_inlining_benefit += eni_size_weights.call_cost;
- if (!VOID_TYPE_P (TREE_TYPE (funtype)))
- {
- int cost = estimate_move_cost (TREE_TYPE (funtype));
- time_inlining_benefit += cost;
- size_inlining_benefit += cost;
- }
- for (arg = DECL_ARGUMENTS (node->decl); arg; arg = TREE_CHAIN (arg))
- {
- int cost = estimate_move_cost (TREE_TYPE (arg));
- time_inlining_benefit += cost;
- size_inlining_benefit += cost;
- }
- if (time_inlining_benefit > MAX_TIME)
- time_inlining_benefit = MAX_TIME;
- if (time > MAX_TIME)
- time = MAX_TIME;
- inline_summary (node)->self_time = time;
- inline_summary (node)->self_size = size;
- if (dump_file)
- {
- fprintf (dump_file, "With function call overhead time: %i-%i size: %i-%i\n",
- (int)time, (int)time_inlining_benefit,
- size, size_inlining_benefit);
- }
- inline_summary (node)->time_inlining_benefit = time_inlining_benefit;
- inline_summary (node)->size_inlining_benefit = size_inlining_benefit;
- BITMAP_FREE (must_not_throw);
-}
-