summaryrefslogtreecommitdiff
path: root/gcc/ipa-inline-analysis.c
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/ipa-inline-analysis.c')
-rw-r--r--gcc/ipa-inline-analysis.c88
1 files changed, 85 insertions, 3 deletions
diff --git a/gcc/ipa-inline-analysis.c b/gcc/ipa-inline-analysis.c
index ba6221e41fd..304f9f5d7cc 100644
--- a/gcc/ipa-inline-analysis.c
+++ b/gcc/ipa-inline-analysis.c
@@ -2257,6 +2257,77 @@ array_index_predicate (struct inline_summary *info,
return p;
}
+/* For a typical usage of __builtin_expect (a<b, 1), we
+ may introduce an extra relation stmt:
+ With the builtin, we have
+ t1 = a <= b;
+ t2 = (long int) t1;
+ t3 = __builtin_expect (t2, 1);
+ if (t3 != 0)
+ goto ...
+ Without the builtin, we have
+ if (a<=b)
+ goto...
+ This affects the size/time estimation and may have
+ an impact on the earlier inlining.
+ Here find this pattern and fix it up later. */
+
+static gimple
+find_foldable_builtin_expect (basic_block bb)
+{
+ gimple_stmt_iterator bsi;
+
+ for (bsi = gsi_start_bb (bb); !gsi_end_p (bsi); gsi_next (&bsi))
+ {
+ gimple stmt = gsi_stmt (bsi);
+ if (gimple_call_builtin_p (stmt, BUILT_IN_EXPECT))
+ {
+ tree var = gimple_call_lhs (stmt);
+ tree arg = gimple_call_arg (stmt, 0);
+ use_operand_p use_p;
+ gimple use_stmt;
+ bool match = false;
+ bool done = false;
+
+ if (!var || !arg)
+ continue;
+ gcc_assert (TREE_CODE (var) == SSA_NAME);
+
+ while (TREE_CODE (arg) == SSA_NAME)
+ {
+ gimple stmt_tmp = SSA_NAME_DEF_STMT (arg);
+ if (!is_gimple_assign (stmt_tmp))
+ break;
+ switch (gimple_assign_rhs_code (stmt_tmp))
+ {
+ case LT_EXPR:
+ case LE_EXPR:
+ case GT_EXPR:
+ case GE_EXPR:
+ case EQ_EXPR:
+ case NE_EXPR:
+ match = true;
+ done = true;
+ break;
+ case NOP_EXPR:
+ break;
+ default:
+ done = true;
+ break;
+ }
+ if (done)
+ break;
+ arg = gimple_assign_rhs1 (stmt_tmp);
+ }
+
+ if (match && single_imm_use (var, &use_p, &use_stmt)
+ && gimple_code (use_stmt) == GIMPLE_COND)
+ return use_stmt;
+ }
+ }
+ return NULL;
+}
+
/* Compute function body size parameters for NODE.
When EARLY is true, we compute only simple summaries without
non-trivial predicates to drive the early inliner. */
@@ -2280,6 +2351,7 @@ estimate_function_body_sizes (struct cgraph_node *node, bool early)
int nblocks, n;
int *order;
predicate array_index = true_predicate ();
+ gimple fix_builtin_expect_stmt;
info->conds = NULL;
info->entry = NULL;
@@ -2360,6 +2432,8 @@ estimate_function_body_sizes (struct cgraph_node *node, bool early)
}
}
+ fix_builtin_expect_stmt = find_foldable_builtin_expect (bb);
+
for (bsi = gsi_start_bb (bb); !gsi_end_p (bsi); gsi_next (&bsi))
{
gimple stmt = gsi_stmt (bsi);
@@ -2368,6 +2442,14 @@ estimate_function_body_sizes (struct cgraph_node *node, bool early)
int prob;
struct predicate will_be_nonconstant;
+ /* This relation stmt should be folded after we remove
+ buildin_expect call. Adjust the cost here. */
+ if (stmt == fix_builtin_expect_stmt)
+ {
+ this_size--;
+ this_time--;
+ }
+
if (dump_file && (dump_flags & TDF_DETAILS))
{
fprintf (dump_file, " ");
@@ -2739,12 +2821,12 @@ const pass_data pass_data_inline_parameters =
class pass_inline_parameters : public gimple_opt_pass
{
public:
- pass_inline_parameters(gcc::context *ctxt)
- : gimple_opt_pass(pass_data_inline_parameters, ctxt)
+ pass_inline_parameters (gcc::context *ctxt)
+ : gimple_opt_pass (pass_data_inline_parameters, ctxt)
{}
/* opt_pass methods: */
- opt_pass * clone () { return new pass_inline_parameters (ctxt_); }
+ opt_pass * clone () { return new pass_inline_parameters (m_ctxt); }
unsigned int execute () {
return compute_inline_parameters_for_current ();
}