inline-10.c: New testcase.
* gcc.dg/tree-ssa/inline-10.c: New testcase. * gcc.dg/tree-ssa/inline-9.c: Disable partial inlining. * ipa-inline.h (clause_t): Turn into unsigned int. * ipa-inline-analysis.c (add_clause): Do more simplification. (and_predicates): Shortcut more cases. (predicates_equal_p): Move forward; check that clauses are properly ordered. (or_predicates): Shortcut more cases. (edge_execution_predicate): Rewrite as... (set_cond_stmt_execution_predicate): ... this function; handle __builtin_constant_p. (set_switch_stmt_execution_predicate): New . (compute_bb_predicates): New. (will_be_nonconstant_predicate): Update TODO. (estimate_function_body_sizes): Use compute_bb_predicates and free them later, always try to estimate if stmt is constant. (estimate_time_after_inlining, estimate_size_after_inlining): Gracefully handle optimized out edges. (read_predicate): Fix off by one error. From-SVN: r173190
This commit is contained in:
parent
7097b0410e
commit
b15c64ee1a
@ -1,3 +1,25 @@
|
||||
2011-04-29 Jan Hubicka <jh@suse.cz>
|
||||
|
||||
* gcc.dg/tree-ssa/inline-10.c: New testcase.
|
||||
* gcc.dg/tree-ssa/inline-9.c: Disable partial inlining.
|
||||
* ipa-inline.h (clause_t): Turn into unsigned int.
|
||||
* ipa-inline-analysis.c (add_clause): Do more simplification.
|
||||
(and_predicates): Shortcut more cases.
|
||||
(predicates_equal_p): Move forward; check that clauses are properly
|
||||
ordered.
|
||||
(or_predicates): Shortcut more cases.
|
||||
(edge_execution_predicate): Rewrite as...
|
||||
(set_cond_stmt_execution_predicate): ... this function; handle
|
||||
__builtin_constant_p.
|
||||
(set_switch_stmt_execution_predicate): New .
|
||||
(compute_bb_predicates): New.
|
||||
(will_be_nonconstant_predicate): Update TODO.
|
||||
(estimate_function_body_sizes): Use compute_bb_predicates
|
||||
and free them later, always try to estimate if stmt is constant.
|
||||
(estimate_time_after_inlining, estimate_size_after_inlining):
|
||||
Gracefully handle optimized out edges.
|
||||
(read_predicate): Fix off by one error.
|
||||
|
||||
2011-04-29 Nicola Pero <nicola.pero@meta-innovation.com>
|
||||
|
||||
* Makefile.in (ENABLE_MAINTAINER_RULES): New.
|
||||
|
@ -227,19 +227,20 @@ add_condition (struct inline_summary *summary, int operand_num,
|
||||
}
|
||||
|
||||
|
||||
/* Add clause CLAUSE into the predicate. */
|
||||
/* Add clause CLAUSE into the predicate P. */
|
||||
|
||||
static inline void
|
||||
add_clause (struct predicate *p, clause_t clause)
|
||||
{
|
||||
int i;
|
||||
int i2;
|
||||
int insert_here = -1;
|
||||
|
||||
/* True clause. */
|
||||
if (!clause)
|
||||
return;
|
||||
|
||||
/* Flase clause makes the whole predicate false. Kill the other variants. */
|
||||
/* False clause makes the whole predicate false. Kill the other variants. */
|
||||
if (clause == (1 << predicate_false_condition))
|
||||
{
|
||||
p->clause[0] = (1 << predicate_false_condition);
|
||||
@ -248,26 +249,46 @@ add_clause (struct predicate *p, clause_t clause)
|
||||
}
|
||||
if (false_predicate_p (p))
|
||||
return;
|
||||
gcc_assert (!(clause & (1 << predicate_false_condition)));
|
||||
for (i = 0; i < MAX_CLAUSES - 1; i++)
|
||||
|
||||
/* No one should be sily enough to add false into nontrivial clauses. */
|
||||
gcc_checking_assert (!(clause & (1 << predicate_false_condition)));
|
||||
|
||||
/* Look where to insert the clause. At the same time prune out
|
||||
clauses of P that are implied by the new clause and thus
|
||||
redundant. */
|
||||
for (i = 0, i2 = 0; i <= MAX_CLAUSES; i++)
|
||||
{
|
||||
if (p->clause[i] == clause)
|
||||
return;
|
||||
p->clause[i2] = p->clause[i];
|
||||
|
||||
if (!p->clause[i])
|
||||
break;
|
||||
if (p->clause[i] < clause && !insert_here)
|
||||
insert_here = i;
|
||||
|
||||
/* If p->clause[i] implies clause, there is nothing to add. */
|
||||
if ((p->clause[i] & clause) == p->clause[i])
|
||||
{
|
||||
/* We had nothing to add, none of clauses should've become redundant. */
|
||||
gcc_checking_assert (i == i2);
|
||||
return;
|
||||
}
|
||||
|
||||
if (p->clause[i] < clause && insert_here < 0)
|
||||
insert_here = i2;
|
||||
|
||||
/* If clause implies p->clause[i], then p->clause[i] becomes redundant.
|
||||
Otherwise the p->clause[i] has to stay. */
|
||||
if ((p->clause[i] & clause) != clause)
|
||||
i2++;
|
||||
}
|
||||
/* We run out of variants. Be conservative in positive direciton. */
|
||||
if (i == MAX_CLAUSES)
|
||||
/* We run out of variants. Be conservative in positive direction. */
|
||||
if (i2 == MAX_CLAUSES)
|
||||
return;
|
||||
/* Keep clauses ordered by index, so equivalence testing is easy. */
|
||||
p->clause[i + 1] = 0;
|
||||
/* Keep clauses in decreasing order. This makes equivalence testing easy. */
|
||||
p->clause[i2 + 1] = 0;
|
||||
if (insert_here >= 0)
|
||||
for (;i > insert_here; i--)
|
||||
p->clause[i] = p->clause[i - 1];
|
||||
for (;i2 > insert_here; i2--)
|
||||
p->clause[i2] = p->clause[i2 - 1];
|
||||
else
|
||||
insert_here = i;
|
||||
insert_here = i2;
|
||||
p->clause[insert_here] = clause;
|
||||
}
|
||||
|
||||
@ -280,7 +301,20 @@ and_predicates (struct predicate *p, struct predicate *p2)
|
||||
struct predicate out = *p;
|
||||
int i;
|
||||
|
||||
for (i = 0; p2->clause[i]; i++)
|
||||
/* Avoid busy work. */
|
||||
if (false_predicate_p (p2) || true_predicate_p (p))
|
||||
return *p2;
|
||||
if (false_predicate_p (p) || true_predicate_p (p2))
|
||||
return *p;
|
||||
|
||||
/* See how far predicates match. */
|
||||
for (i = 0; p->clause[i] && p->clause[i] == p2->clause[i]; i++)
|
||||
{
|
||||
gcc_checking_assert (i < MAX_CLAUSES);
|
||||
}
|
||||
|
||||
/* Combine the predicates rest. */
|
||||
for (; p2->clause[i]; i++)
|
||||
{
|
||||
gcc_checking_assert (i < MAX_CLAUSES);
|
||||
add_clause (&out, p2->clause[i]);
|
||||
@ -289,29 +323,6 @@ and_predicates (struct predicate *p, struct predicate *p2)
|
||||
}
|
||||
|
||||
|
||||
/* Return P | P2. */
|
||||
|
||||
static struct predicate
|
||||
or_predicates (struct predicate *p, struct predicate *p2)
|
||||
{
|
||||
struct predicate out = true_predicate ();
|
||||
int i,j;
|
||||
|
||||
/* If one of conditions is false, return the other. */
|
||||
if (false_predicate_p (p2))
|
||||
return *p;
|
||||
if (false_predicate_p (p))
|
||||
return *p2;
|
||||
for (i = 0; p->clause[i]; i++)
|
||||
for (j = 0; p2->clause[j]; j++)
|
||||
{
|
||||
gcc_checking_assert (i < MAX_CLAUSES && j < MAX_CLAUSES);
|
||||
add_clause (&out, p->clause[i] | p2->clause[j]);
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
|
||||
/* Return true if predicates are obviously equal. */
|
||||
|
||||
static inline bool
|
||||
@ -321,6 +332,8 @@ predicates_equal_p (struct predicate *p, struct predicate *p2)
|
||||
for (i = 0; p->clause[i]; i++)
|
||||
{
|
||||
gcc_checking_assert (i < MAX_CLAUSES);
|
||||
gcc_checking_assert (p->clause [i] > p->clause[i + 1]);
|
||||
gcc_checking_assert (!p2->clause[i] || p2->clause [i] > p2->clause[i + 1]);
|
||||
if (p->clause[i] != p2->clause[i])
|
||||
return false;
|
||||
}
|
||||
@ -328,6 +341,33 @@ predicates_equal_p (struct predicate *p, struct predicate *p2)
|
||||
}
|
||||
|
||||
|
||||
/* Return P | P2. */
|
||||
|
||||
static struct predicate
|
||||
or_predicates (struct predicate *p, struct predicate *p2)
|
||||
{
|
||||
struct predicate out = true_predicate ();
|
||||
int i,j;
|
||||
|
||||
/* Avoid busy work. */
|
||||
if (false_predicate_p (p2) || true_predicate_p (p))
|
||||
return *p;
|
||||
if (false_predicate_p (p) || true_predicate_p (p2))
|
||||
return *p2;
|
||||
if (predicates_equal_p (p, p2))
|
||||
return *p;
|
||||
|
||||
/* OK, combine the predicates. */
|
||||
for (i = 0; p->clause[i]; i++)
|
||||
for (j = 0; p2->clause[j]; j++)
|
||||
{
|
||||
gcc_checking_assert (i < MAX_CLAUSES && j < MAX_CLAUSES);
|
||||
add_clause (&out, p->clause[i] | p2->clause[j]);
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
|
||||
/* Having partial truth assignment in POSSIBLE_TRUTHS, return false if predicate P
|
||||
to be false. */
|
||||
|
||||
@ -885,50 +925,226 @@ eliminated_by_inlining_prob (gimple stmt)
|
||||
}
|
||||
|
||||
|
||||
/* Return predicate that must be true when is E executable. */
|
||||
/* If BB ends by a conditional we can turn into predicates, attach corresponding
|
||||
predicates to the CFG edges. */
|
||||
|
||||
static struct predicate
|
||||
edge_execution_predicate (struct ipa_node_params *info,
|
||||
struct inline_summary *summary,
|
||||
edge e)
|
||||
static void
|
||||
set_cond_stmt_execution_predicate (struct ipa_node_params *info,
|
||||
struct inline_summary *summary,
|
||||
basic_block bb)
|
||||
{
|
||||
struct predicate p = true_predicate ();
|
||||
gimple last;
|
||||
tree op;
|
||||
int index;
|
||||
enum tree_code code;
|
||||
enum tree_code code, inverted_code;
|
||||
edge e;
|
||||
edge_iterator ei;
|
||||
gimple set_stmt;
|
||||
tree op2;
|
||||
|
||||
if (e->src == ENTRY_BLOCK_PTR)
|
||||
return p;
|
||||
|
||||
last = last_stmt (e->src);
|
||||
/* TODO: handle switch. */
|
||||
last = last_stmt (bb);
|
||||
if (!last
|
||||
|| gimple_code (last) != GIMPLE_COND)
|
||||
return p;
|
||||
return;
|
||||
if (!is_gimple_ip_invariant (gimple_cond_rhs (last)))
|
||||
return p;
|
||||
return;
|
||||
op = gimple_cond_lhs (last);
|
||||
/* TODO: handle conditionals like
|
||||
var = op0 < 4;
|
||||
if (var != 0)
|
||||
and __bulitin_constant_p. */
|
||||
if (var != 0). */
|
||||
if (TREE_CODE (op) != SSA_NAME)
|
||||
return;
|
||||
if (SSA_NAME_IS_DEFAULT_DEF (op))
|
||||
{
|
||||
index = ipa_get_param_decl_index (info, SSA_NAME_VAR (op));
|
||||
if (index == -1)
|
||||
return;
|
||||
code = gimple_cond_code (last);
|
||||
inverted_code = invert_tree_comparison (code,
|
||||
HONOR_NANS (TYPE_MODE (TREE_TYPE (op))));
|
||||
|
||||
FOR_EACH_EDGE (e, ei, bb->succs)
|
||||
{
|
||||
struct predicate p = add_condition (summary,
|
||||
index,
|
||||
e->flags & EDGE_TRUE_VALUE
|
||||
? code : inverted_code,
|
||||
gimple_cond_rhs (last));
|
||||
e->aux = pool_alloc (edge_predicate_pool);
|
||||
*(struct predicate *)e->aux = p;
|
||||
}
|
||||
}
|
||||
|
||||
/* Special case
|
||||
if (builtin_constant_p (op))
|
||||
constant_code
|
||||
else
|
||||
nonconstant_code.
|
||||
Here we can predicate nonconstant_code. We can't
|
||||
really handle constant_code since we have no predicate
|
||||
for this and also the constant code is not known to be
|
||||
optimized away when inliner doen't see operand is constant.
|
||||
Other optimizers might think otherwise. */
|
||||
set_stmt = SSA_NAME_DEF_STMT (op);
|
||||
if (!gimple_call_builtin_p (set_stmt, BUILT_IN_CONSTANT_P)
|
||||
|| gimple_call_num_args (set_stmt) != 1)
|
||||
return;
|
||||
op2 = gimple_call_arg (set_stmt, 0);
|
||||
if (!SSA_NAME_IS_DEFAULT_DEF (op2))
|
||||
return;
|
||||
index = ipa_get_param_decl_index (info, SSA_NAME_VAR (op2));
|
||||
if (index == -1)
|
||||
return;
|
||||
if (gimple_cond_code (last) != NE_EXPR
|
||||
|| !integer_zerop (gimple_cond_rhs (last)))
|
||||
return;
|
||||
FOR_EACH_EDGE (e, ei, bb->succs)
|
||||
if (e->flags & EDGE_FALSE_VALUE)
|
||||
{
|
||||
struct predicate p = add_condition (summary,
|
||||
index,
|
||||
IS_NOT_CONSTANT,
|
||||
NULL);
|
||||
e->aux = pool_alloc (edge_predicate_pool);
|
||||
*(struct predicate *)e->aux = p;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* If BB ends by a switch we can turn into predicates, attach corresponding
|
||||
predicates to the CFG edges. */
|
||||
|
||||
static void
|
||||
set_switch_stmt_execution_predicate (struct ipa_node_params *info,
|
||||
struct inline_summary *summary,
|
||||
basic_block bb)
|
||||
{
|
||||
gimple last;
|
||||
tree op;
|
||||
int index;
|
||||
edge e;
|
||||
edge_iterator ei;
|
||||
size_t n;
|
||||
size_t case_idx;
|
||||
|
||||
last = last_stmt (bb);
|
||||
if (!last
|
||||
|| gimple_code (last) != GIMPLE_SWITCH)
|
||||
return;
|
||||
op = gimple_switch_index (last);
|
||||
if (TREE_CODE (op) != SSA_NAME
|
||||
|| !SSA_NAME_IS_DEFAULT_DEF (op))
|
||||
return p;
|
||||
return;
|
||||
index = ipa_get_param_decl_index (info, SSA_NAME_VAR (op));
|
||||
if (index == -1)
|
||||
return p;
|
||||
code = gimple_cond_code (last);
|
||||
return;
|
||||
|
||||
if (EDGE_TRUE_VALUE)
|
||||
code = invert_tree_comparison (code,
|
||||
HONOR_NANS (TYPE_MODE (TREE_TYPE (op))));
|
||||
FOR_EACH_EDGE (e, ei, bb->succs)
|
||||
{
|
||||
e->aux = pool_alloc (edge_predicate_pool);
|
||||
*(struct predicate *)e->aux = false_predicate ();
|
||||
}
|
||||
n = gimple_switch_num_labels(last);
|
||||
for (case_idx = 0; case_idx < n; ++case_idx)
|
||||
{
|
||||
tree cl = gimple_switch_label (last, case_idx);
|
||||
tree min, max;
|
||||
struct predicate p;
|
||||
|
||||
return add_condition (summary,
|
||||
index,
|
||||
gimple_cond_code (last),
|
||||
gimple_cond_rhs (last));
|
||||
e = find_edge (bb, label_to_block (CASE_LABEL (cl)));
|
||||
min = CASE_LOW (cl);
|
||||
max = CASE_HIGH (cl);
|
||||
|
||||
/* For default we might want to construct predicate that none
|
||||
of cases is met, but it is bit hard to do not having negations
|
||||
of conditionals handy. */
|
||||
if (!min && !max)
|
||||
p = true_predicate ();
|
||||
else if (!max)
|
||||
p = add_condition (summary, index,
|
||||
EQ_EXPR,
|
||||
min);
|
||||
else
|
||||
{
|
||||
struct predicate p1, p2;
|
||||
p1 = add_condition (summary, index,
|
||||
GE_EXPR,
|
||||
min);
|
||||
p2 = add_condition (summary, index,
|
||||
LE_EXPR,
|
||||
max);
|
||||
p = and_predicates (&p1, &p2);
|
||||
}
|
||||
*(struct predicate *)e->aux
|
||||
= or_predicates (&p, (struct predicate *)e->aux);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* For each BB in NODE attach to its AUX pointer predicate under
|
||||
which it is executable. */
|
||||
|
||||
static void
|
||||
compute_bb_predicates (struct cgraph_node *node,
|
||||
struct ipa_node_params *parms_info,
|
||||
struct inline_summary *summary)
|
||||
{
|
||||
struct function *my_function = DECL_STRUCT_FUNCTION (node->decl);
|
||||
bool done = false;
|
||||
basic_block bb;
|
||||
|
||||
FOR_EACH_BB_FN (bb, my_function)
|
||||
{
|
||||
set_cond_stmt_execution_predicate (parms_info, summary, bb);
|
||||
set_switch_stmt_execution_predicate (parms_info, summary, bb);
|
||||
}
|
||||
|
||||
/* Entry block is always executable. */
|
||||
ENTRY_BLOCK_PTR_FOR_FUNCTION (my_function)->aux = pool_alloc (edge_predicate_pool);
|
||||
*(struct predicate *)ENTRY_BLOCK_PTR_FOR_FUNCTION (my_function)->aux
|
||||
= true_predicate ();
|
||||
|
||||
/* A simple dataflow propagation of predicates forward in the CFG.
|
||||
TODO: work in reverse postorder. */
|
||||
while (!done)
|
||||
{
|
||||
done = true;
|
||||
FOR_EACH_BB_FN (bb, my_function)
|
||||
{
|
||||
struct predicate p = false_predicate ();
|
||||
edge e;
|
||||
edge_iterator ei;
|
||||
FOR_EACH_EDGE (e, ei, bb->preds)
|
||||
{
|
||||
if (e->src->aux)
|
||||
{
|
||||
struct predicate this_bb_predicate = *(struct predicate *)e->src->aux;
|
||||
if (e->aux)
|
||||
this_bb_predicate = and_predicates (&this_bb_predicate,
|
||||
(struct predicate *)e->aux);
|
||||
p = or_predicates (&p, &this_bb_predicate);
|
||||
if (true_predicate_p (&p))
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (false_predicate_p (&p))
|
||||
gcc_assert (!bb->aux);
|
||||
else
|
||||
{
|
||||
if (!bb->aux)
|
||||
{
|
||||
done = false;
|
||||
bb->aux = pool_alloc (edge_predicate_pool);
|
||||
*((struct predicate *)bb->aux) = p;
|
||||
}
|
||||
else if (!predicates_equal_p (&p, (struct predicate *)bb->aux))
|
||||
{
|
||||
done = false;
|
||||
*((struct predicate *)bb->aux) = p;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -956,7 +1172,8 @@ will_be_nonconstant_predicate (struct ipa_node_params *info,
|
||||
|
||||
/* What statments might be optimized away
|
||||
when their arguments are constant
|
||||
TODO: also trivial builtins, especially builtin_constant_p. */
|
||||
TODO: also trivial builtins.
|
||||
builtin_constant_p is already handled later. */
|
||||
if (gimple_code (stmt) != GIMPLE_ASSIGN
|
||||
&& gimple_code (stmt) != GIMPLE_COND
|
||||
&& gimple_code (stmt) != GIMPLE_SWITCH)
|
||||
@ -1050,23 +1267,19 @@ estimate_function_body_sizes (struct cgraph_node *node, bool early)
|
||||
account_size_time (info, 2 * INLINE_SIZE_SCALE, 0, &bb_predicate);
|
||||
|
||||
gcc_assert (my_function && my_function->cfg);
|
||||
if (parms_info)
|
||||
compute_bb_predicates (node, parms_info, info);
|
||||
FOR_EACH_BB_FN (bb, my_function)
|
||||
{
|
||||
edge e;
|
||||
edge_iterator ei;
|
||||
|
||||
freq = compute_call_stmt_bb_frequency (node->decl, bb);
|
||||
|
||||
/* TODO: Obviously predicates can be propagated down across CFG. */
|
||||
if (parms_info)
|
||||
{
|
||||
bb_predicate = false_predicate ();
|
||||
FOR_EACH_EDGE (e, ei, bb->preds)
|
||||
{
|
||||
struct predicate ep;
|
||||
ep = edge_execution_predicate (parms_info, info, e);
|
||||
bb_predicate = or_predicates (&ep, &bb_predicate);
|
||||
}
|
||||
if (bb->aux)
|
||||
bb_predicate = *(struct predicate *)bb->aux;
|
||||
else
|
||||
bb_predicate = false_predicate ();
|
||||
}
|
||||
else
|
||||
bb_predicate = true_predicate ();
|
||||
@ -1083,6 +1296,7 @@ estimate_function_body_sizes (struct cgraph_node *node, bool early)
|
||||
int this_size = estimate_num_insns (stmt, &eni_size_weights);
|
||||
int this_time = estimate_num_insns (stmt, &eni_time_weights);
|
||||
int prob;
|
||||
struct predicate will_be_nonconstant;
|
||||
|
||||
if (dump_file && (dump_flags & TDF_DETAILS))
|
||||
{
|
||||
@ -1127,9 +1341,15 @@ estimate_function_body_sizes (struct cgraph_node *node, bool early)
|
||||
gcc_assert (!gimple_call_cannot_inline_p (stmt));
|
||||
}
|
||||
|
||||
/* TODO: When conditional jump or swithc is known to be constant, but
|
||||
we did not translate it into the predicates, we really can account
|
||||
just maximum of the possible paths. */
|
||||
if (parms_info)
|
||||
will_be_nonconstant
|
||||
= will_be_nonconstant_predicate (parms_info, info,
|
||||
stmt, nonconstant_names);
|
||||
if (this_time || this_size)
|
||||
{
|
||||
struct predicate will_be_nonconstant;
|
||||
struct predicate p;
|
||||
|
||||
this_time *= freq;
|
||||
@ -1143,12 +1363,7 @@ estimate_function_body_sizes (struct cgraph_node *node, bool early)
|
||||
fprintf (dump_file, "\t\twill eliminated by inlining\n");
|
||||
|
||||
if (parms_info)
|
||||
{
|
||||
will_be_nonconstant
|
||||
= will_be_nonconstant_predicate (parms_info, info,
|
||||
stmt, nonconstant_names);
|
||||
p = and_predicates (&bb_predicate, &will_be_nonconstant);
|
||||
}
|
||||
p = and_predicates (&bb_predicate, &will_be_nonconstant);
|
||||
else
|
||||
p = true_predicate ();
|
||||
|
||||
@ -1174,6 +1389,21 @@ estimate_function_body_sizes (struct cgraph_node *node, bool early)
|
||||
}
|
||||
}
|
||||
}
|
||||
FOR_ALL_BB_FN (bb, my_function)
|
||||
{
|
||||
edge e;
|
||||
edge_iterator ei;
|
||||
|
||||
if (bb->aux)
|
||||
pool_free (edge_predicate_pool, bb->aux);
|
||||
bb->aux = NULL;
|
||||
FOR_EACH_EDGE (e, ei, bb->succs)
|
||||
{
|
||||
if (e->aux)
|
||||
pool_free (edge_predicate_pool, e->aux);
|
||||
e->aux = NULL;
|
||||
}
|
||||
}
|
||||
time = (time + CGRAPH_FREQ_BASE / 2) / CGRAPH_FREQ_BASE;
|
||||
if (time > MAX_TIME)
|
||||
time = MAX_TIME;
|
||||
@ -1677,12 +1907,17 @@ int
|
||||
estimate_time_after_inlining (struct cgraph_node *node,
|
||||
struct cgraph_edge *edge)
|
||||
{
|
||||
gcov_type time = inline_summary (node)->time + estimate_edge_time (edge);
|
||||
if (time < 0)
|
||||
time = 0;
|
||||
if (time > MAX_TIME)
|
||||
time = MAX_TIME;
|
||||
return time;
|
||||
struct inline_edge_summary *es = inline_edge_summary (edge);
|
||||
if (!es->predicate || !false_predicate_p (es->predicate))
|
||||
{
|
||||
gcov_type time = inline_summary (node)->time + estimate_edge_time (edge);
|
||||
if (time < 0)
|
||||
time = 0;
|
||||
if (time > MAX_TIME)
|
||||
time = MAX_TIME;
|
||||
return time;
|
||||
}
|
||||
return inline_summary (node)->time;
|
||||
}
|
||||
|
||||
|
||||
@ -1693,9 +1928,14 @@ int
|
||||
estimate_size_after_inlining (struct cgraph_node *node,
|
||||
struct cgraph_edge *edge)
|
||||
{
|
||||
int size = inline_summary (node)->size + estimate_edge_growth (edge);
|
||||
gcc_assert (size >= 0);
|
||||
return size;
|
||||
struct inline_edge_summary *es = inline_edge_summary (edge);
|
||||
if (!es->predicate || !false_predicate_p (es->predicate))
|
||||
{
|
||||
int size = inline_summary (node)->size + estimate_edge_growth (edge);
|
||||
gcc_assert (size >= 0);
|
||||
return size;
|
||||
}
|
||||
return inline_summary (node)->size;
|
||||
}
|
||||
|
||||
|
||||
@ -1826,8 +2066,8 @@ read_predicate (struct lto_input_block *ib)
|
||||
|
||||
do
|
||||
{
|
||||
gcc_assert (k <= MAX_CLAUSES);
|
||||
clause = out.clause[k++] = lto_input_uleb128 (ib);
|
||||
gcc_assert (k < MAX_CLAUSES);
|
||||
}
|
||||
while (clause);
|
||||
return out;
|
||||
|
@ -48,7 +48,7 @@ typedef VEC(condition,gc) *conditions;
|
||||
must be true in order for clause to be true. */
|
||||
|
||||
#define MAX_CLAUSES 8
|
||||
typedef int clause_t;
|
||||
typedef unsigned int clause_t;
|
||||
struct GTY(()) predicate
|
||||
{
|
||||
clause_t clause[MAX_CLAUSES + 1];
|
||||
|
38
gcc/testsuite/gcc.dg/tree-ssa/inline-10.c
Normal file
38
gcc/testsuite/gcc.dg/tree-ssa/inline-10.c
Normal file
@ -0,0 +1,38 @@
|
||||
/* { dg-do compile } */
|
||||
/* { dg-options "-Os -fdump-tree-optimized -fno-partial-inlining" } */
|
||||
void do_something1(void);
|
||||
void do_something2(void);
|
||||
void do_something3(void);
|
||||
void do_something4(void);
|
||||
void do_something5(void);
|
||||
void do_something_big(int);
|
||||
|
||||
int do_something (int size)
|
||||
{
|
||||
if (__builtin_constant_p (size))
|
||||
switch (size)
|
||||
{
|
||||
case 1:do_something1 (); break;
|
||||
case 2:do_something2 (); break;
|
||||
case 5:do_something1 (); do_something1 ();
|
||||
case 3:do_something3 (); break;
|
||||
case 4:do_something4 (); break;
|
||||
}
|
||||
else
|
||||
do_something_big (size);
|
||||
}
|
||||
extern int n;
|
||||
main()
|
||||
{
|
||||
do_something (2);
|
||||
do_something (3);
|
||||
do_something (5);
|
||||
do_something (70);
|
||||
}
|
||||
/* All calls should be inlined, except for do_something (5). */
|
||||
/* { dg-final { scan-tree-dump-not "do_something1" "optimized" } } */
|
||||
/* { dg-final { scan-tree-dump-times "do_something2" 1 "optimized" } } */
|
||||
/* { dg-final { scan-tree-dump-times "do_something3" 1 "optimized" } } */
|
||||
/* { dg-final { scan-tree-dump-times "do_something \\(5\\)" 1 "optimized" } } */
|
||||
/* { dg-final { scan-tree-dump-not "do_something \\(70\\)" "optimized" } } */
|
||||
/* { dg-final { cleanup-tree-dump "optimized" } } */
|
@ -1,5 +1,5 @@
|
||||
/* { dg-do compile } */
|
||||
/* { dg-options "-Os -fdump-tree-optimized" } */
|
||||
/* { dg-options "-Os -fdump-tree-optimized -fno-partial-inlining" } */
|
||||
|
||||
/* When optimizing for size, t should be inlined when it expands to one call only. */
|
||||
extern int q(int);
|
||||
|
Loading…
Reference in New Issue
Block a user