From patchwork Tue Nov 12 13:03:32 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jan Hubicka X-Patchwork-Id: 1193521 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=gcc.gnu.org (client-ip=209.132.180.131; helo=sourceware.org; envelope-from=gcc-patches-return-513105-incoming=patchwork.ozlabs.org@gcc.gnu.org; receiver=) Authentication-Results: ozlabs.org; dmarc=none (p=none dis=none) header.from=ucw.cz Authentication-Results: ozlabs.org; dkim=pass (1024-bit key; unprotected) header.d=gcc.gnu.org header.i=@gcc.gnu.org header.b="EXumx1xy"; dkim-atps=neutral Received: from sourceware.org (server1.sourceware.org [209.132.180.131]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 47C7Gv2bH2z9s7T for ; Wed, 13 Nov 2019 00:03:49 +1100 (AEDT) DomainKey-Signature: a=rsa-sha1; c=nofws; d=gcc.gnu.org; h=list-id :list-unsubscribe:list-archive:list-post:list-help:sender:date :from:to:subject:message-id:mime-version:content-type; q=dns; s= default; b=EfCWGTlGrkcqGicF1Ywg+hVydlRt74vQBEv2xvM9F+kD57PjQynVF eW8fFXC+9Kpf76GSennoT6qa3HrAedi5AcTpdUJILBlq6rO24vc4vOT4t8Hr3RL+ y28skZgFoP0H5XOQxM6Pkhr5p60oPMyzcG9loKjZvh4itMGvjXPdaA= DKIM-Signature: v=1; a=rsa-sha1; c=relaxed; d=gcc.gnu.org; h=list-id :list-unsubscribe:list-archive:list-post:list-help:sender:date :from:to:subject:message-id:mime-version:content-type; s= default; bh=AnDjDr/j5fqUx+H+u3dWRDJjURQ=; b=EXumx1xybT8Res1OWXzc LABKZcagvHQYqJCFkWsnMa47+BwsjD+Yq6y1cjhuVHYSk9Os3IcIgS6biT5moK+D xFhB6Mt9mnmf2Rya7OXdOdNCC+/om+vwZo07uQbH4w8FRa8Ag6wmh3UxdLhMCF65 FyIgP0PFtbZ/y19iw532l8M= Received: (qmail 81564 invoked by alias); 12 Nov 2019 13:03:41 -0000 Mailing-List: contact gcc-patches-help@gcc.gnu.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Archive: List-Post: List-Help: Sender: gcc-patches-owner@gcc.gnu.org Delivered-To: mailing list gcc-patches@gcc.gnu.org Received: (qmail 81555 invoked by uid 89); 12 Nov 2019 13:03:41 -0000 Authentication-Results: sourceware.org; auth=none X-Spam-SWARE-Status: No, score=-12.5 required=5.0 tests=AWL, BAYES_00, GIT_PATCH_1, GIT_PATCH_2, GIT_PATCH_3, KAM_ASCII_DIVIDERS autolearn=ham version=3.3.1 spammy=sk:ultimat X-HELO: nikam.ms.mff.cuni.cz Received: from nikam.ms.mff.cuni.cz (HELO nikam.ms.mff.cuni.cz) (195.113.20.16) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with ESMTP; Tue, 12 Nov 2019 13:03:35 +0000 Received: by nikam.ms.mff.cuni.cz (Postfix, from userid 16202) id DF4002805EE; Tue, 12 Nov 2019 14:03:32 +0100 (CET) Date: Tue, 12 Nov 2019 14:03:32 +0100 From: Jan Hubicka To: gcc-patches@gcc.gnu.org, mjambor@suse.cz, rguenther@suse.de Subject: Use known value ranges while evaluating ipa predicates Message-ID: <20191112130332.b5dyohbxz7s4k4op@kam.mff.cuni.cz> MIME-Version: 1.0 Content-Disposition: inline User-Agent: NeoMutt/20170113 (1.7.2) Hi, this implements use of value ranges in ipa-predicates so inliner know when some tests are going to be removed (especially NULL pointer checks). Bootstrapped/regtested x86_64-linux. Martin, I would apprechiate if you look on the patch. Honza * 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. Index: ipa-cp.c =================================================================== --- ipa-cp.c (revision 278094) +++ ipa-cp.c (working copy) @@ -1459,6 +1459,87 @@ ipa_context_from_jfunc (ipa_node_params 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 ((*sum->m_vr)[idx].type, + wide_int_to_tree (vr_type, (*sum->m_vr)[idx].min), + wide_int_to_tree (vr_type, (*sum->m_vr)[idx].max)); + + 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; +} + /* If checking is enabled, verify that no lattice is in the TOP state, i.e. not bottom, not containing a variable component and without any known value at the same time. */ @@ -1936,22 +2017,6 @@ propagate_bits_across_jump_function (cgr 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. */ Index: ipa-fnsummary.c =================================================================== --- ipa-fnsummary.c (revision 278094) +++ ipa-fnsummary.c (working copy) @@ -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, @@ -372,7 +373,9 @@ evaluate_conditions_for_known_args (stru 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); @@ -384,48 +387,101 @@ evaluate_conditions_for_known_args (stru 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 (VR_RANGE, 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 (VR_RANGE, 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); @@ -450,6 +506,7 @@ evaluate_properties_for_edge (struct cgr 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; @@ -477,6 +534,8 @@ evaluate_properties_for_edge (struct cgr 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) @@ -505,14 +564,18 @@ evaluate_properties_for_edge (struct cgr else if (inline_p && !es->param[i].change_prob) known_vals[i] = error_mark_node; - if (known_contexts_ptr) - (*known_contexts_ptr)[i] - = ipa_context_from_jfunc (caller_parms_info, e, i, jf); - /* TODO: When IPA-CP starts propagating and merging aggregate jump - functions, use its knowledge of the caller too, just like the - scalar case above. */ - known_aggs[i] = &jf->agg; - } + if (known_contexts_ptr) + (*known_contexts_ptr)[i] + = ipa_context_from_jfunc (caller_parms_info, e, i, jf); + /* TODO: When IPA-CP starts propagating and merging aggregate jump + functions, use its knowledge of the caller too, just like the + scalar case above. */ + known_aggs[i] = &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 cgr } 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 evaluate_conditions_for_known_args (dst, false, known_vals, vNULL, + vNULL, &possible_truths, /* We are going to specialize, so ignore nonspec truths. */ @@ -3355,8 +3424,9 @@ estimate_ipcp_clone_size_and_time (struc { 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); @@ -3576,7 +3646,8 @@ ipa_merge_fn_summary_after_inlining (str 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); Index: ipa-prop.h =================================================================== --- ipa-prop.h (revision 278094) +++ ipa-prop.h (working copy) @@ -918,6 +918,8 @@ ipa_polymorphic_call_context ipa_context cgraph_edge *, int, ipa_jump_func *); +value_range ipa_value_range_from_jfunc (ipa_node_params *, cgraph_edge *, + ipa_jump_func *, tree); void ipa_dump_param (FILE *, class ipa_node_params *info, int i); void ipa_release_body_info (struct ipa_func_body_info *); tree ipa_get_callee_param_type (struct cgraph_edge *e, int i); Index: testsuite/gcc.dg/ipa/inline-9.c =================================================================== --- testsuite/gcc.dg/ipa/inline-9.c (nonexistent) +++ testsuite/gcc.dg/ipa/inline-9.c (working copy) @@ -0,0 +1,21 @@ +/* { dg-options "-Os -fdump-ipa-inline" } */ +int test(int a) +{ + if (a>100) + { + foo(); + foo(); + foo(); + foo(); + foo(); + foo(); + foo(); + foo(); + } +} +main() +{ + for (int i=0;i<100;i++) + test(i); +} +/* { dg-final { scan-tree-dump "Inlined 1 calls" "inline" } } */