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>
* 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,
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
parameter with the given INDEX. */
......@@ -2122,22 +2203,6 @@ propagate_bits_across_jump_function (cgraph_edge *cs, int idx,
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
edge CS with param of callee of PARAM_TYPE and update DEST_PLATS
accordingly. */
......
......@@ -316,6 +316,7 @@ static void
evaluate_conditions_for_known_args (struct cgraph_node *node,
bool inline_p,
vec<tree> known_vals,
vec<value_range> known_value_ranges,
vec<ipa_agg_value_set> known_aggs,
clause_t *ret_clause,
clause_t *ret_nonspec_clause)
......@@ -371,7 +372,9 @@ evaluate_conditions_for_known_args (struct cgraph_node *node,
val = NULL_TREE;
}
if (!val)
if (!val
&& (c->code == predicate::changed
|| c->code == predicate::is_not_constant))
{
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,
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)
{
nonspec_clause |= 1 << (i + predicate::first_dynamic_condition);
continue;
}
val = fold_unary (VIEW_CONVERT_EXPR, c->type, val);
for (j = 0; vec_safe_iterate (c->param_ops, j, &op); j++)
if (val && TYPE_SIZE (c->type) == TYPE_SIZE (TREE_TYPE (val)))
{
if (!val)
break;
if (!op->val[0])
val = fold_unary (op->code, op->type, val);
else if (!op->val[1])
val = fold_binary (op->code, op->type,
op->index ? op->val[0] : val,
op->index ? val : op->val[0]);
else if (op->index == 0)
val = fold_ternary (op->code, op->type,
val, op->val[0], op->val[1]);
else if (op->index == 1)
val = fold_ternary (op->code, op->type,
op->val[0], val, op->val[1]);
else if (op->index == 2)
val = fold_ternary (op->code, op->type,
op->val[0], op->val[1], val);
else
val = NULL_TREE;
if (c->type != TREE_TYPE (val))
val = fold_unary (VIEW_CONVERT_EXPR, c->type, val);
for (j = 0; vec_safe_iterate (c->param_ops, j, &op); j++)
{
if (!val)
break;
if (!op->val[0])
val = fold_unary (op->code, op->type, val);
else if (!op->val[1])
val = fold_binary (op->code, op->type,
op->index ? op->val[0] : val,
op->index ? val : op->val[0]);
else if (op->index == 0)
val = fold_ternary (op->code, op->type,
val, op->val[0], op->val[1]);
else if (op->index == 1)
val = fold_ternary (op->code, op->type,
op->val[0], val, op->val[1]);
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
? fold_binary_to_constant (c->code, boolean_type_node, val, c->val)
: NULL;
for (j = 0; vec_safe_iterate (c->param_ops, j, &op); j++)
{
if (vr.varying_p () || vr.undefined_p ())
break;
if (res && integer_zerop (res))
continue;
value_range res;
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);
nonspec_clause |= 1 << (i + predicate::first_dynamic_condition);
......@@ -449,6 +505,7 @@ evaluate_properties_for_edge (struct cgraph_edge *e, bool inline_p,
struct cgraph_node *callee = e->callee->ultimate_alias_target ();
class ipa_fn_summary *info = ipa_fn_summaries->get (callee);
vec<tree> known_vals = vNULL;
auto_vec<value_range, 32> known_value_ranges;
vec<ipa_agg_value_set> known_aggs = vNULL;
class ipa_edge_args *args;
......@@ -478,6 +535,8 @@ evaluate_properties_for_edge (struct cgraph_edge *e, bool inline_p,
if (count && (info->conds || known_vals_ptr))
known_vals.safe_grow_cleared (count);
if (count && info->conds)
known_value_ranges.safe_grow_cleared (count);
if (count && (info->conds || known_aggs_ptr))
known_aggs.safe_grow_cleared (count);
if (count && known_contexts_ptr)
......@@ -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,
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
gcc_assert (callee->thunk.thunk_p);
......@@ -534,7 +597,9 @@ evaluate_properties_for_edge (struct cgraph_edge *e, bool 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);
if (known_vals_ptr)
......@@ -657,6 +722,7 @@ ipa_fn_summary_t::duplicate (cgraph_node *src,
evaluate_conditions_for_known_args (dst, false,
known_vals,
vNULL,
vNULL,
&possible_truths,
/* We are going to specialize,
so ignore nonspec truths. */
......@@ -3358,8 +3424,9 @@ estimate_ipcp_clone_size_and_time (struct cgraph_node *node,
{
clause_t clause, nonspec_clause;
evaluate_conditions_for_known_args (node, false, known_vals, known_aggs,
&clause, &nonspec_clause);
/* TODO: Also pass known value ranges. */
evaluate_conditions_for_known_args (node, false, known_vals, vNULL,
known_aggs, &clause, &nonspec_clause);
ipa_call_context ctx (node, clause, nonspec_clause,
known_vals, known_contexts,
known_aggs, vNULL);
......@@ -3579,7 +3646,8 @@ ipa_merge_fn_summary_after_inlining (struct cgraph_edge *edge)
info->fp_expressions |= callee_info->fp_expressions;
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)
{
class ipa_edge_args *args = IPA_EDGE_REF (edge);
......
......@@ -1163,6 +1163,7 @@ edge_badness (struct cgraph_edge *edge, bool dump)
overall_growth = callee_info->growth;
#if 1
/* Look for inliner wrappers of the form:
inline_caller ()
......@@ -1214,6 +1215,7 @@ edge_badness (struct cgraph_edge *edge, bool dump)
overall_growth = caller_growth;
}
}
#endif
if (overall_growth > 0)
{
/* Strongly preffer functions with few callers that can be inlined
......@@ -2132,12 +2134,23 @@ inline_small_functions (void)
fprintf (dump_file, " Peeling recursion with depth %i\n", depth);
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);
add_new_edges_to_heap (&edge_heap, new_indirect_edges);
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;
if (where->inlined_to)
......
......@@ -1029,6 +1029,8 @@ ipa_polymorphic_call_context ipa_context_from_jfunc (ipa_node_params *,
cgraph_edge *,
int,
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 *,
cgraph_node *,
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>
* 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