Commit 68718e8e by Jan Hubicka

Support for value ranges in IPA predicates


        * ipa-cp.c (ipa_vr_operation_and_type_effects): Move up in file.
	(ipa_value_range_from_jfunc): New function.
	* ipa-fnsummary.c (evaluate_conditions_for_known_args): Add
	known_value_ranges parameter; use it to evalulate conditions.
	(evaluate_properties_for_edge): Compute known value ranges.
	(ipa_fn_summary_t::duplicate): Update use of
	evaluate_conditions_for_known_args.
	(estimate_ipcp_clone_size_and_time): Likewise.
	(ipa_merge_fn_summary_after_inlining): Likewise.
	* ipa-prop.h (ipa_value_range_from_jfunc): Declare.

        * gcc.dg/ipa/inline-9.c: New testcase.

From-SVN: r278220
parent afeb8875
2019-11-14 Jan Hubicka <hubicka@ucw.cz>
* ipa-cp.c (ipa_vr_operation_and_type_effects): Move up in file.
(ipa_value_range_from_jfunc): New function.
* ipa-fnsummary.c (evaluate_conditions_for_known_args): Add
known_value_ranges parameter; use it to evalulate conditions.
(evaluate_properties_for_edge): Compute known value ranges.
(ipa_fn_summary_t::duplicate): Update use of
evaluate_conditions_for_known_args.
(estimate_ipcp_clone_size_and_time): Likewise.
(ipa_merge_fn_summary_after_inlining): Likewise.
* ipa-prop.h (ipa_value_range_from_jfunc): Declare.
2019-11-14 Martin Liska <mliska@suse.cz> 2019-11-14 Martin Liska <mliska@suse.cz>
* ipa-inline.c (want_inline_small_function_p): Use * ipa-inline.c (want_inline_small_function_p): Use
...@@ -1473,6 +1473,87 @@ ipa_context_from_jfunc (ipa_node_params *info, cgraph_edge *cs, int csidx, ...@@ -1473,6 +1473,87 @@ ipa_context_from_jfunc (ipa_node_params *info, cgraph_edge *cs, int csidx,
return ctx; return ctx;
} }
/* Emulate effects of unary OPERATION and/or conversion from SRC_TYPE to
DST_TYPE on value range in SRC_VR and store it to DST_VR. Return true if
the result is a range or an anti-range. */
static bool
ipa_vr_operation_and_type_effects (value_range *dst_vr,
value_range *src_vr,
enum tree_code operation,
tree dst_type, tree src_type)
{
range_fold_unary_expr (dst_vr, operation, dst_type, src_vr, src_type);
if (dst_vr->varying_p () || dst_vr->undefined_p ())
return false;
return true;
}
/* Determine value_range of JFUNC given that INFO describes the caller node or
the one it is inlined to, CS is the call graph edge corresponding to JFUNC
and PARM_TYPE of the parameter. */
value_range
ipa_value_range_from_jfunc (ipa_node_params *info, cgraph_edge *cs,
ipa_jump_func *jfunc, tree parm_type)
{
value_range vr;
return vr;
if (jfunc->m_vr)
ipa_vr_operation_and_type_effects (&vr,
jfunc->m_vr,
NOP_EXPR, parm_type,
jfunc->m_vr->type ());
if (vr.singleton_p ())
return vr;
if (jfunc->type == IPA_JF_PASS_THROUGH)
{
int idx;
ipcp_transformation *sum
= ipcp_get_transformation_summary (cs->caller->inlined_to
? cs->caller->inlined_to
: cs->caller);
if (!sum || !sum->m_vr)
return vr;
idx = ipa_get_jf_pass_through_formal_id (jfunc);
if (!(*sum->m_vr)[idx].known)
return vr;
tree vr_type = ipa_get_type (info, idx);
value_range srcvr (wide_int_to_tree (vr_type, (*sum->m_vr)[idx].min),
wide_int_to_tree (vr_type, (*sum->m_vr)[idx].max),
(*sum->m_vr)[idx].type);
enum tree_code operation = ipa_get_jf_pass_through_operation (jfunc);
if (TREE_CODE_CLASS (operation) == tcc_unary)
{
value_range res;
if (ipa_vr_operation_and_type_effects (&res,
&srcvr,
operation, parm_type,
vr_type))
vr.intersect (res);
}
else
{
value_range op_res, res;
tree op = ipa_get_jf_pass_through_operand (jfunc);
value_range op_vr (op, op);
range_fold_binary_expr (&op_res, operation, vr_type, &srcvr, &op_vr);
if (ipa_vr_operation_and_type_effects (&res,
&op_res,
NOP_EXPR, parm_type,
vr_type))
vr.intersect (res);
}
}
return vr;
}
/* See if NODE is a clone with a known aggregate value at a given OFFSET of a /* See if NODE is a clone with a known aggregate value at a given OFFSET of a
parameter with the given INDEX. */ parameter with the given INDEX. */
...@@ -2122,22 +2203,6 @@ propagate_bits_across_jump_function (cgraph_edge *cs, int idx, ...@@ -2122,22 +2203,6 @@ propagate_bits_across_jump_function (cgraph_edge *cs, int idx,
return dest_lattice->set_to_bottom (); return dest_lattice->set_to_bottom ();
} }
/* Emulate effects of unary OPERATION and/or conversion from SRC_TYPE to
DST_TYPE on value range in SRC_VR and store it to DST_VR. Return true if
the result is a range or an anti-range. */
static bool
ipa_vr_operation_and_type_effects (value_range *dst_vr,
value_range *src_vr,
enum tree_code operation,
tree dst_type, tree src_type)
{
range_fold_unary_expr (dst_vr, operation, dst_type, src_vr, src_type);
if (dst_vr->varying_p () || dst_vr->undefined_p ())
return false;
return true;
}
/* Propagate value range across jump function JFUNC that is associated with /* Propagate value range across jump function JFUNC that is associated with
edge CS with param of callee of PARAM_TYPE and update DEST_PLATS edge CS with param of callee of PARAM_TYPE and update DEST_PLATS
accordingly. */ accordingly. */
......
...@@ -316,6 +316,7 @@ static void ...@@ -316,6 +316,7 @@ static void
evaluate_conditions_for_known_args (struct cgraph_node *node, evaluate_conditions_for_known_args (struct cgraph_node *node,
bool inline_p, bool inline_p,
vec<tree> known_vals, vec<tree> known_vals,
vec<value_range> known_value_ranges,
vec<ipa_agg_value_set> known_aggs, vec<ipa_agg_value_set> known_aggs,
clause_t *ret_clause, clause_t *ret_clause,
clause_t *ret_nonspec_clause) clause_t *ret_nonspec_clause)
...@@ -371,7 +372,9 @@ evaluate_conditions_for_known_args (struct cgraph_node *node, ...@@ -371,7 +372,9 @@ evaluate_conditions_for_known_args (struct cgraph_node *node,
val = NULL_TREE; val = NULL_TREE;
} }
if (!val) if (!val
&& (c->code == predicate::changed
|| c->code == predicate::is_not_constant))
{ {
clause |= 1 << (i + predicate::first_dynamic_condition); clause |= 1 << (i + predicate::first_dynamic_condition);
nonspec_clause |= 1 << (i + predicate::first_dynamic_condition); nonspec_clause |= 1 << (i + predicate::first_dynamic_condition);
...@@ -383,48 +386,101 @@ evaluate_conditions_for_known_args (struct cgraph_node *node, ...@@ -383,48 +386,101 @@ evaluate_conditions_for_known_args (struct cgraph_node *node,
continue; continue;
} }
if (TYPE_SIZE (c->type) != TYPE_SIZE (TREE_TYPE (val)))
{
clause |= 1 << (i + predicate::first_dynamic_condition);
nonspec_clause |= 1 << (i + predicate::first_dynamic_condition);
continue;
}
if (c->code == predicate::is_not_constant) if (c->code == predicate::is_not_constant)
{ {
nonspec_clause |= 1 << (i + predicate::first_dynamic_condition); nonspec_clause |= 1 << (i + predicate::first_dynamic_condition);
continue; continue;
} }
val = fold_unary (VIEW_CONVERT_EXPR, c->type, val); if (val && TYPE_SIZE (c->type) == TYPE_SIZE (TREE_TYPE (val)))
for (j = 0; vec_safe_iterate (c->param_ops, j, &op); j++)
{ {
if (!val) if (c->type != TREE_TYPE (val))
break; val = fold_unary (VIEW_CONVERT_EXPR, c->type, val);
if (!op->val[0]) for (j = 0; vec_safe_iterate (c->param_ops, j, &op); j++)
val = fold_unary (op->code, op->type, val); {
else if (!op->val[1]) if (!val)
val = fold_binary (op->code, op->type, break;
op->index ? op->val[0] : val, if (!op->val[0])
op->index ? val : op->val[0]); val = fold_unary (op->code, op->type, val);
else if (op->index == 0) else if (!op->val[1])
val = fold_ternary (op->code, op->type, val = fold_binary (op->code, op->type,
val, op->val[0], op->val[1]); op->index ? op->val[0] : val,
else if (op->index == 1) op->index ? val : op->val[0]);
val = fold_ternary (op->code, op->type, else if (op->index == 0)
op->val[0], val, op->val[1]); val = fold_ternary (op->code, op->type,
else if (op->index == 2) val, op->val[0], op->val[1]);
val = fold_ternary (op->code, op->type, else if (op->index == 1)
op->val[0], op->val[1], val); val = fold_ternary (op->code, op->type,
else op->val[0], val, op->val[1]);
val = NULL_TREE; else if (op->index == 2)
val = fold_ternary (op->code, op->type,
op->val[0], op->val[1], val);
else
val = NULL_TREE;
}
res = val
? fold_binary_to_constant (c->code, boolean_type_node, val, c->val)
: NULL;
if (res && integer_zerop (res))
continue;
if (res && integer_onep (res))
{
clause |= 1 << (i + predicate::first_dynamic_condition);
nonspec_clause |= 1 << (i + predicate::first_dynamic_condition);
continue;
}
} }
if (c->operand_num < (int) known_value_ranges.length ()
&& !c->agg_contents
&& !known_value_ranges[c->operand_num].undefined_p ()
&& !known_value_ranges[c->operand_num].varying_p ()
&& TYPE_SIZE (c->type)
== TYPE_SIZE (known_value_ranges[c->operand_num].type ())
&& (!val || TREE_CODE (val) != INTEGER_CST))
{
value_range vr = known_value_ranges[c->operand_num];
if (!useless_type_conversion_p (c->type, vr.type ()))
{
value_range res;
range_fold_unary_expr (&res, NOP_EXPR,
c->type, &vr, vr.type ());
vr = res;
}
tree type = c->type;
res = val for (j = 0; vec_safe_iterate (c->param_ops, j, &op); j++)
? fold_binary_to_constant (c->code, boolean_type_node, val, c->val) {
: NULL; if (vr.varying_p () || vr.undefined_p ())
break;
if (res && integer_zerop (res)) value_range res;
continue; if (!op->val[0])
range_fold_unary_expr (&res, op->code, op->type, &vr, type);
else if (!op->val[1])
{
value_range op0 (op->val[0], op->val[0]);
range_fold_binary_expr (&res, op->code, op->type,
op->index ? &op0 : &vr,
op->index ? &vr : &op0);
}
else
gcc_unreachable ();
type = op->type;
vr = res;
}
if (!vr.varying_p () && !vr.undefined_p ())
{
value_range res;
value_range val_vr (c->val, c->val);
range_fold_binary_expr (&res, c->code, boolean_type_node,
&vr,
&val_vr);
if (res.zero_p ())
continue;
}
}
clause |= 1 << (i + predicate::first_dynamic_condition); clause |= 1 << (i + predicate::first_dynamic_condition);
nonspec_clause |= 1 << (i + predicate::first_dynamic_condition); nonspec_clause |= 1 << (i + predicate::first_dynamic_condition);
...@@ -449,6 +505,7 @@ evaluate_properties_for_edge (struct cgraph_edge *e, bool inline_p, ...@@ -449,6 +505,7 @@ evaluate_properties_for_edge (struct cgraph_edge *e, bool inline_p,
struct cgraph_node *callee = e->callee->ultimate_alias_target (); struct cgraph_node *callee = e->callee->ultimate_alias_target ();
class ipa_fn_summary *info = ipa_fn_summaries->get (callee); class ipa_fn_summary *info = ipa_fn_summaries->get (callee);
vec<tree> known_vals = vNULL; vec<tree> known_vals = vNULL;
auto_vec<value_range, 32> known_value_ranges;
vec<ipa_agg_value_set> known_aggs = vNULL; vec<ipa_agg_value_set> known_aggs = vNULL;
class ipa_edge_args *args; class ipa_edge_args *args;
...@@ -478,6 +535,8 @@ evaluate_properties_for_edge (struct cgraph_edge *e, bool inline_p, ...@@ -478,6 +535,8 @@ evaluate_properties_for_edge (struct cgraph_edge *e, bool inline_p,
if (count && (info->conds || known_vals_ptr)) if (count && (info->conds || known_vals_ptr))
known_vals.safe_grow_cleared (count); known_vals.safe_grow_cleared (count);
if (count && info->conds)
known_value_ranges.safe_grow_cleared (count);
if (count && (info->conds || known_aggs_ptr)) if (count && (info->conds || known_aggs_ptr))
known_aggs.safe_grow_cleared (count); known_aggs.safe_grow_cleared (count);
if (count && known_contexts_ptr) if (count && known_contexts_ptr)
...@@ -512,6 +571,10 @@ evaluate_properties_for_edge (struct cgraph_edge *e, bool inline_p, ...@@ -512,6 +571,10 @@ evaluate_properties_for_edge (struct cgraph_edge *e, bool inline_p,
known_aggs[i] = ipa_agg_value_set_from_jfunc (caller_parms_info, known_aggs[i] = ipa_agg_value_set_from_jfunc (caller_parms_info,
caller, &jf->agg); caller, &jf->agg);
if (info->conds)
known_value_ranges[i]
= ipa_value_range_from_jfunc (caller_parms_info, e, jf,
ipa_get_type (callee_pi, i));
} }
else else
gcc_assert (callee->thunk.thunk_p); gcc_assert (callee->thunk.thunk_p);
...@@ -534,7 +597,9 @@ evaluate_properties_for_edge (struct cgraph_edge *e, bool inline_p, ...@@ -534,7 +597,9 @@ evaluate_properties_for_edge (struct cgraph_edge *e, bool inline_p,
} }
evaluate_conditions_for_known_args (callee, inline_p, evaluate_conditions_for_known_args (callee, inline_p,
known_vals, known_aggs, clause_ptr, known_vals,
known_value_ranges,
known_aggs, clause_ptr,
nonspec_clause_ptr); nonspec_clause_ptr);
if (known_vals_ptr) if (known_vals_ptr)
...@@ -657,6 +722,7 @@ ipa_fn_summary_t::duplicate (cgraph_node *src, ...@@ -657,6 +722,7 @@ ipa_fn_summary_t::duplicate (cgraph_node *src,
evaluate_conditions_for_known_args (dst, false, evaluate_conditions_for_known_args (dst, false,
known_vals, known_vals,
vNULL, vNULL,
vNULL,
&possible_truths, &possible_truths,
/* We are going to specialize, /* We are going to specialize,
so ignore nonspec truths. */ so ignore nonspec truths. */
...@@ -3358,8 +3424,9 @@ estimate_ipcp_clone_size_and_time (struct cgraph_node *node, ...@@ -3358,8 +3424,9 @@ estimate_ipcp_clone_size_and_time (struct cgraph_node *node,
{ {
clause_t clause, nonspec_clause; clause_t clause, nonspec_clause;
evaluate_conditions_for_known_args (node, false, known_vals, known_aggs, /* TODO: Also pass known value ranges. */
&clause, &nonspec_clause); evaluate_conditions_for_known_args (node, false, known_vals, vNULL,
known_aggs, &clause, &nonspec_clause);
ipa_call_context ctx (node, clause, nonspec_clause, ipa_call_context ctx (node, clause, nonspec_clause,
known_vals, known_contexts, known_vals, known_contexts,
known_aggs, vNULL); known_aggs, vNULL);
...@@ -3579,7 +3646,8 @@ ipa_merge_fn_summary_after_inlining (struct cgraph_edge *edge) ...@@ -3579,7 +3646,8 @@ ipa_merge_fn_summary_after_inlining (struct cgraph_edge *edge)
info->fp_expressions |= callee_info->fp_expressions; info->fp_expressions |= callee_info->fp_expressions;
if (callee_info->conds) if (callee_info->conds)
evaluate_properties_for_edge (edge, true, &clause, NULL, NULL, NULL, NULL); evaluate_properties_for_edge (edge, true, &clause,
NULL, NULL, NULL, NULL);
if (ipa_node_params_sum && callee_info->conds) if (ipa_node_params_sum && callee_info->conds)
{ {
class ipa_edge_args *args = IPA_EDGE_REF (edge); class ipa_edge_args *args = IPA_EDGE_REF (edge);
......
...@@ -1163,6 +1163,7 @@ edge_badness (struct cgraph_edge *edge, bool dump) ...@@ -1163,6 +1163,7 @@ edge_badness (struct cgraph_edge *edge, bool dump)
overall_growth = callee_info->growth; overall_growth = callee_info->growth;
#if 1
/* Look for inliner wrappers of the form: /* Look for inliner wrappers of the form:
inline_caller () inline_caller ()
...@@ -1214,6 +1215,7 @@ edge_badness (struct cgraph_edge *edge, bool dump) ...@@ -1214,6 +1215,7 @@ edge_badness (struct cgraph_edge *edge, bool dump)
overall_growth = caller_growth; overall_growth = caller_growth;
} }
} }
#endif
if (overall_growth > 0) if (overall_growth > 0)
{ {
/* Strongly preffer functions with few callers that can be inlined /* Strongly preffer functions with few callers that can be inlined
...@@ -2132,12 +2134,23 @@ inline_small_functions (void) ...@@ -2132,12 +2134,23 @@ inline_small_functions (void)
fprintf (dump_file, " Peeling recursion with depth %i\n", depth); fprintf (dump_file, " Peeling recursion with depth %i\n", depth);
gcc_checking_assert (!callee->inlined_to); gcc_checking_assert (!callee->inlined_to);
int old_size = ipa_size_summaries->get (where)->size;
sreal old_time = ipa_fn_summaries->get (where)->time;
inline_call (edge, true, &new_indirect_edges, &overall_size, true); inline_call (edge, true, &new_indirect_edges, &overall_size, true);
add_new_edges_to_heap (&edge_heap, new_indirect_edges); add_new_edges_to_heap (&edge_heap, new_indirect_edges);
reset_edge_caches (edge->callee); reset_edge_caches (edge->callee);
update_callee_keys (&edge_heap, where, updated_nodes); /* If caller's size and time increased we do not need to update
all edges becuase badness is not going to decrease. */
if (old_size <= ipa_size_summaries->get (where)->size
&& old_time <= ipa_fn_summaries->get (where)->time
&& 0)
update_callee_keys (&edge_heap, edge->callee, updated_nodes);
else
update_callee_keys (&edge_heap, where, updated_nodes);
} }
where = edge->caller; where = edge->caller;
if (where->inlined_to) if (where->inlined_to)
......
...@@ -1029,6 +1029,8 @@ ipa_polymorphic_call_context ipa_context_from_jfunc (ipa_node_params *, ...@@ -1029,6 +1029,8 @@ ipa_polymorphic_call_context ipa_context_from_jfunc (ipa_node_params *,
cgraph_edge *, cgraph_edge *,
int, int,
ipa_jump_func *); ipa_jump_func *);
value_range ipa_value_range_from_jfunc (ipa_node_params *, cgraph_edge *,
ipa_jump_func *, tree);
ipa_agg_value_set ipa_agg_value_set_from_jfunc (ipa_node_params *, ipa_agg_value_set ipa_agg_value_set_from_jfunc (ipa_node_params *,
cgraph_node *, cgraph_node *,
ipa_agg_jump_function *); ipa_agg_jump_function *);
......
2019-11-14 Jan Hubicka <jh@suse.cz>
* gcc.dg/ipa/inline-9.c: New testcase.
2019-11-14 Martin Liska <mliska@suse.cz> 2019-11-14 Martin Liska <mliska@suse.cz>
* c-c++-common/asan/memcmp-1.c: Update expected backtrace. * c-c++-common/asan/memcmp-1.c: Update expected backtrace.
......
/* { dg-options "-Os -fdump-ipa-inline" } */
int foo (void);
int test(int a)
{
if (a>100)
{
foo();
foo();
foo();
foo();
foo();
foo();
foo();
foo();
}
}
int
main()
{
for (int i=0;i<100;i++)
test(i);
}
/* { dg-final { scan-tree-dump "Inlined 1 calls" "inline" } } */
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment