aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
Diffstat (limited to 'gcc')
-rw-r--r--gcc/ChangeLog13
-rw-r--r--gcc/ipa-cp.c97
-rw-r--r--gcc/ipa-fnsummary.c142
-rw-r--r--gcc/ipa-inline.c15
-rw-r--r--gcc/ipa-prop.h2
-rw-r--r--gcc/testsuite/ChangeLog4
-rw-r--r--gcc/testsuite/gcc.dg/ipa/inline-9.c23
7 files changed, 242 insertions, 54 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 348cc41..f35db51 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,16 @@
+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
diff --git a/gcc/ipa-cp.c b/gcc/ipa-cp.c
index 86c6253..8372dfa 100644
--- a/gcc/ipa-cp.c
+++ b/gcc/ipa-cp.c
@@ -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. */
diff --git a/gcc/ipa-fnsummary.c b/gcc/ipa-fnsummary.c
index 1187933..9d8e1a5 100644
--- a/gcc/ipa-fnsummary.c
+++ b/gcc/ipa-fnsummary.c
@@ -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);
diff --git a/gcc/ipa-inline.c b/gcc/ipa-inline.c
index e27859b..b5e0096 100644
--- a/gcc/ipa-inline.c
+++ b/gcc/ipa-inline.c
@@ -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)
diff --git a/gcc/ipa-prop.h b/gcc/ipa-prop.h
index 7eb96a0..9e85ef8 100644
--- a/gcc/ipa-prop.h
+++ b/gcc/ipa-prop.h
@@ -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 *);
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index 914f005..e0535b3 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -1,3 +1,7 @@
+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.
diff --git a/gcc/testsuite/gcc.dg/ipa/inline-9.c b/gcc/testsuite/gcc.dg/ipa/inline-9.c
new file mode 100644
index 0000000..4bf751b
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/ipa/inline-9.c
@@ -0,0 +1,23 @@
+/* { 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" } } */