From 68718e8e60209edc98771f54091d983eecd6f93c Mon Sep 17 00:00:00 2001 From: Jan Hubicka Date: Thu, 14 Nov 2019 12:41:55 +0000 Subject: [PATCH] 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 --- gcc/ChangeLog | 13 +++ gcc/ipa-cp.c | 97 +++++++++++++++---- gcc/ipa-fnsummary.c | 142 ++++++++++++++++++++-------- gcc/ipa-inline.c | 15 ++- gcc/ipa-prop.h | 2 + gcc/testsuite/ChangeLog | 4 + gcc/testsuite/gcc.dg/ipa/inline-9.c | 23 +++++ 7 files changed, 242 insertions(+), 54 deletions(-) create mode 100644 gcc/testsuite/gcc.dg/ipa/inline-9.c diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 348cc4107de..f35db511057 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,16 @@ +2019-11-14 Jan Hubicka + + * 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 * ipa-inline.c (want_inline_small_function_p): Use diff --git a/gcc/ipa-cp.c b/gcc/ipa-cp.c index 86c625355b6..8372dfaa771 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 11879335990..9d8e1a566e3 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 known_vals, + vec known_value_ranges, vec 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 known_vals = vNULL; + auto_vec known_value_ranges; vec 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 e27859ba5d3..b5e009696b7 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 7eb96a057fe..9e85ef8aace 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 914f00593ff..e0535b32247 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,7 @@ +2019-11-14 Jan Hubicka + + * gcc.dg/ipa/inline-9.c: New testcase. + 2019-11-14 Martin Liska * 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 00000000000..4bf751b5c38 --- /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" } } */ -- 2.30.2