From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 76555 invoked by alias); 18 Sep 2019 12:41:31 -0000 Mailing-List: contact gcc-patches-help@gcc.gnu.org; run by ezmlm Precedence: bulk List-Id: List-Archive: List-Post: List-Help: Sender: gcc-patches-owner@gcc.gnu.org Received: (qmail 76491 invoked by uid 89); 18 Sep 2019 12:41:31 -0000 Authentication-Results: sourceware.org; auth=none X-Spam-SWARE-Status: No, score=-20.7 required=5.0 tests=AWL,BAYES_00,GIT_PATCH_0,GIT_PATCH_1,GIT_PATCH_2,GIT_PATCH_3,RCVD_IN_DNSWL_NONE,SPF_HELO_PASS,SPF_PASS autolearn=ham version=3.3.1 spammy=fbi, FBI, iv, op X-HELO: NAM05-CO1-obe.outbound.protection.outlook.com Received: from mail-eopbgr720116.outbound.protection.outlook.com (HELO NAM05-CO1-obe.outbound.protection.outlook.com) (40.107.72.116) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with ESMTP; Wed, 18 Sep 2019 12:41:26 +0000 ARC-Seal: i=1; a=rsa-sha256; s=arcselector9901; d=microsoft.com; cv=none; b=BGNCtOJXgQOyA9+eWN3daO/+W2hf8W9TMj2MsZ3Ec48ubr1wFETZAz7C6WP+RkI7Knm5fZpZqWcorm/zblIrxzsJZKnXPF2FMPGuun6lQnbrF9p/K33fVlNcEzVFLpd6sUZuWsf4hR3ZQPBfTS2bAfzIJDGP/ZFFqOzwhSc1g2zY2/oLZxCCoeFi5NdvSr2n8o2QoEbqsHofYFax71C3sJluBXIonyhJvYKlDTX/rY6wgRdFbHWXaloRM9ifnGgRiep/vpN4+DPR4nat2V0B+94v00rajzXd+NQOHfEnnM8lN/pIECFJOWGg6S2WLNkyQcNA/HgTnWduqyZOaEYXJQ== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=microsoft.com; s=arcselector9901; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck; bh=HRDYTs4IQvvzt+vhBw9/pkuahflRt3RAsSmSmtO3uU4=; b=IThj2EG8xqaJwPi6eydL3+EqChGza6e2owwEI9pn+JUB7YkE7vYoay+6Ups6FjAGOJpSwhFqWnUQr1txt14sH0vtdOtfOPJlvmCxF5y3TEqipZjETNoX70dBnvCFo4PNLSSEkdHyFpZQkmPRGYB1kJNGxJwl1UnUGOdRq4p7WmlsFMhbkJHkR1ETRNJgQ30Jb2x+HgVPF2YjeTrozvs2aIZkkovDUNO8xlbUXnmoR4+VnuM1O+IcnAdICiqWGth0cgxy9YAVs371gyPjdpUzao/+hEsIh+gl4xQt+i2ObCIa/L64SKrxaFJpXI/IZ3regz4/I8BzCyWTXZp7V3GmyA== ARC-Authentication-Results: i=1; mx.microsoft.com 1; spf=pass smtp.mailfrom=os.amperecomputing.com; dmarc=pass action=none header.from=os.amperecomputing.com; dkim=pass header.d=os.amperecomputing.com; arc=none DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=os.amperecomputing.com; s=selector2; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck; bh=HRDYTs4IQvvzt+vhBw9/pkuahflRt3RAsSmSmtO3uU4=; b=Rf+tb/hlv+pAjZw7anOe4A8N3Qiel7jSVHQLXk9KaIhgTsakJEmKw4GbsxmCRgWpJpNmbLEHSpiC94yVB7vSvZAE9Z9cFd3UGXwPu2bRN9xaEUQl2frOEMOt4yyR4ZPO05MUDnAyQ+c4i5g/GRZ4+b4EJ2o0x+lif/dCvTdYXVQ= Received: from BYAPR01MB4869.prod.exchangelabs.com (20.177.228.18) by BYAPR01MB4293.prod.exchangelabs.com (52.135.239.92) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.2263.15; Wed, 18 Sep 2019 12:41:22 +0000 Received: from BYAPR01MB4869.prod.exchangelabs.com ([fe80::a016:e802:d3d0:f1c7]) by BYAPR01MB4869.prod.exchangelabs.com ([fe80::a016:e802:d3d0:f1c7%3]) with mapi id 15.20.2284.009; Wed, 18 Sep 2019 12:41:22 +0000 From: Feng Xue OS To: Jan Hubicka CC: Martin Jambor , "gcc-patches@gcc.gnu.org" Subject: [PATCH V4] Generalized predicate/condition for parameter reference in IPA (PR ipa/91088) Date: Wed, 18 Sep 2019 12:41:00 -0000 Message-ID: References: ,<20190914171804.xept5u4gszujsp7r@kam.mff.cuni.cz> In-Reply-To: <20190914171804.xept5u4gszujsp7r@kam.mff.cuni.cz> authentication-results: spf=none (sender IP is ) smtp.mailfrom=fxue@os.amperecomputing.com; x-ms-oob-tlc-oobclassifiers: OLM:6430; received-spf: None (protection.outlook.com: os.amperecomputing.com does not designate permitted sender hosts) x-ms-exchange-senderadcheck: 1 x-ms-exchange-transport-forked: True Content-Type: text/plain; charset="iso-8859-1" Content-Transfer-Encoding: quoted-printable MIME-Version: 1.0 X-MS-Exchange-CrossTenant-mailboxtype: HOSTED X-MS-Exchange-CrossTenant-userprincipalname: VaybKM63GZhguOrTMZXv4LrUx1a/c8zO0Lrjqstzsk4jfWpwvS/4/aTXucwmhpjhU9NriGl0QM+Vc6mSVJtiqEDtaFeYMgTalGfGs9nsXy0= X-SW-Source: 2019-09/txt/msg01102.txt.bz2 >> + if (unmodified_parm_or_parm_agg_item (fbi, stmt, expr, index_p, &= size, >> + aggpos)) >> + { >> + tree type =3D TREE_TYPE (expr); >> + >> + /* Stop if found bit-field whose size does not equal any natural >> + integral type. */ >> + if (maybe_ne (tree_to_poly_int64 (TYPE_SIZE (type)), size)) >> + break; > Why is this needed? This is to exclude bit-field reference. Actually, the restrict is not requi= red, a TODO to remove it. Now I directly check bit-field attribute. >> - =3D add_condition (summary, index, size, &aggpos, this_cod= e, >> - unshare_expr_without_location >> - (gimple_cond_rhs (last))); >> + =3D add_condition (summary, index, type, &aggpos, this_cod= e, >> + gimple_cond_rhs (last), param_ops); > An why unsharing is no longer needed here? > It is importnat to avoid anything which reffers to function local blocks > to get into the global LTO stream. Do unsharing inside add_condition, since constants in param_ops also need t= o be unshared. >> + if (op1.code !=3D op2.code >> + || op1.val_is_rhs !=3D op2.val_is_rhs >> + || !vrp_operand_equal_p (op1.val, op2.val) > Why you need vrp_operand_equal_p instead of operand_equal_p here? op1.val and op2.val might be NULL_TREE. > Overall the patch looks very reasonable. We may end up with bit more > general expressions (i.e. supporting arithmetics involving more than one > operand). If you means more than one constant operand, I'v changed the patch to suppo= rt ternary operation. And if you means more than one parameter operand, this will involve much mo= re code change in ipa-fnsummary, it's better to let it be another TODO. > I see you also fixed a lot of typos in comments, please go head and > commit them separately as obvious. Removed. Thank for your comments. Feng --- diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi index 0e3693598e7..05b1bb97c6b 100644 --- a/gcc/doc/invoke.texi +++ b/gcc/doc/invoke.texi @@ -11943,6 +11943,13 @@ For switch exceeding this limit, IPA-CP will not c= onstruct cloning cost predicate, which is used to estimate cloning benefit, for default case of the switch statement. =20 +@item ipa-max-param-expr-ops +IPA-CP will analyze conditional statement that references some function +parameter to estimate benefit for cloning upon certain constant value. +But if number of operations in a parameter expression exceeds +@option{ipa-max-param-expr-ops}, the expression is treated as complicated +one, and is not handled by IPA analysis. + @item lto-partitions Specify desired number of partitions produced during WHOPR compilation. The number of partitions should exceed the number of CPUs used for compila= tion. diff --git a/gcc/ipa-fnsummary.c b/gcc/ipa-fnsummary.c index 1bf1806eaf8..c25e3395f59 100644 --- a/gcc/ipa-fnsummary.c +++ b/gcc/ipa-fnsummary.c @@ -331,6 +331,8 @@ evaluate_conditions_for_known_args (struct cgraph_node = *node, { tree val; tree res; + int j; + struct expr_eval_op *op; =20 /* We allow call stmt to have fewer arguments than the callee functi= on (especially for K&R style programs). So bound check here (we ass= ume @@ -382,7 +384,7 @@ evaluate_conditions_for_known_args (struct cgraph_node = *node, continue; } =20 - if (maybe_ne (tree_to_poly_int64 (TYPE_SIZE (TREE_TYPE (val))), c->s= ize)) + if (TYPE_SIZE (c->type) !=3D TYPE_SIZE (TREE_TYPE (val))) { clause |=3D 1 << (i + predicate::first_dynamic_condition); nonspec_clause |=3D 1 << (i + predicate::first_dynamic_condition); @@ -394,7 +396,30 @@ evaluate_conditions_for_known_args (struct cgraph_node= *node, continue; } =20 - val =3D fold_unary (VIEW_CONVERT_EXPR, TREE_TYPE (c->val), val); + val =3D fold_unary (VIEW_CONVERT_EXPR, c->type, val); + for (j =3D 0; vec_safe_iterate (c->param_ops, j, &op); j++) + { + if (!val) + break; + if (!op->val[0]) + val =3D fold_unary (op->code, op->type, val); + else if (!op->val[1]) + val =3D fold_binary (op->code, op->type, + op->index ? op->val[0] : val, + op->index ? val : op->val[0]); + else if (op->index =3D=3D 0) + val =3D fold_ternary (op->code, op->type, + val, op->val[0], op->val[1]); + else if (op->index =3D=3D 1) + val =3D fold_ternary (op->code, op->type, + op->val[0], val, op->val[1]); + else if (op->index =3D=3D 2) + val =3D fold_ternary (op->code, op->type, + op->val[0], op->val[1], val); + else + val =3D NULL_TREE; + } + res =3D val ? fold_binary_to_constant (c->code, boolean_type_node, val, c->val) : NULL; @@ -1157,6 +1182,127 @@ eliminated_by_inlining_prob (ipa_func_body_info *fb= i, gimple *stmt) } } =20 +/* Analyze EXPR if it represents a series of simple operations performed on + a function parameter and return true if so. FBI, STMT, EXPR, INDEX_P a= nd + AGGPOS have the same meaning like in unmodified_parm_or_parm_agg_item. + Type of the parameter or load from an aggregate via the parameter is + stored in *TYPE_P. Operations on the parameter are recorded to + PARAM_OPS_P if it is not NULL. */ + +static bool +decompose_param_expr (struct ipa_func_body_info *fbi, + gimple *stmt, tree expr, + int *index_p, tree *type_p, + struct agg_position_info *aggpos, + expr_eval_ops *param_ops_p =3D NULL) +{ + int op_limit =3D PARAM_VALUE (PARAM_IPA_MAX_PARAM_EXPR_OPS); + int op_count =3D 0; + + if (param_ops_p) + *param_ops_p =3D NULL; + + while (true) + { + expr_eval_op eval_op; + unsigned rhs_count; + unsigned cst_count =3D 0; + + if (unmodified_parm_or_parm_agg_item (fbi, stmt, expr, index_p, NULL, + aggpos)) + { + tree type =3D TREE_TYPE (expr); + + if (aggpos->agg_contents) + { + /* Stop if containing bit-field. */ + if (TREE_CODE (expr) =3D=3D BIT_FIELD_REF + || contains_bitfld_component_ref_p (expr)) + break; + } + + *type_p =3D type; + return true; + } + + if (TREE_CODE (expr) !=3D SSA_NAME || SSA_NAME_IS_DEFAULT_DEF (expr)) + break; + + if (!is_gimple_assign (stmt =3D SSA_NAME_DEF_STMT (expr))) + break; + + switch (gimple_assign_rhs_class (stmt)) + { + case GIMPLE_SINGLE_RHS: + expr =3D gimple_assign_rhs1 (stmt); + continue; + + case GIMPLE_UNARY_RHS: + rhs_count =3D 1; + break; + + case GIMPLE_BINARY_RHS: + rhs_count =3D 2; + break; + + case GIMPLE_TERNARY_RHS: + rhs_count =3D 3; + break; + + default: + goto fail; + } + + /* Stop if expression is too complex. */ + if (op_count++ =3D=3D op_limit) + break; + + if (param_ops_p) + { + eval_op.code =3D gimple_assign_rhs_code (stmt); + eval_op.type =3D TREE_TYPE (gimple_assign_lhs (stmt)); + eval_op.val[0] =3D NULL_TREE; + eval_op.val[1] =3D NULL_TREE; + } + + expr =3D NULL_TREE; + for (unsigned i =3D 0; i < rhs_count; i++) + { + tree op =3D gimple_op (stmt, i + 1); + + gcc_assert (op && !TYPE_P (op)); + if (is_gimple_ip_invariant (op)) + { + if (++cst_count =3D=3D rhs_count) + goto fail; + + eval_op.val[cst_count - 1] =3D op; + } + else if (!expr) + { + /* Found a non-constant operand, and record its index in rhs + operands. */ + eval_op.index =3D i; + expr =3D op; + } + else + { + /* Found more than one non-constant operands. */ + goto fail; + } + } + + if (param_ops_p) + vec_safe_insert (*param_ops_p, 0, eval_op); + } + + /* Failed to decompose, free resource and return. */ +fail: + if (param_ops_p) + vec_free (*param_ops_p); + + return false; +} =20 /* If BB ends by a conditional we can turn into predicates, attach corresp= onding predicates to the CFG edges. */ @@ -1167,15 +1313,15 @@ set_cond_stmt_execution_predicate (struct ipa_func_= body_info *fbi, basic_block bb) { gimple *last; - tree op; + tree op, op2; int index; - poly_int64 size; struct agg_position_info aggpos; enum tree_code code, inverted_code; edge e; edge_iterator ei; gimple *set_stmt; - tree op2; + tree param_type; + expr_eval_ops param_ops; =20 last =3D last_stmt (bb); if (!last || gimple_code (last) !=3D GIMPLE_COND) @@ -1183,10 +1329,9 @@ set_cond_stmt_execution_predicate (struct ipa_func_b= ody_info *fbi, if (!is_gimple_ip_invariant (gimple_cond_rhs (last))) return; op =3D gimple_cond_lhs (last); - /* TODO: handle conditionals like - var =3D op0 < 4; - if (var !=3D 0). */ - if (unmodified_parm_or_parm_agg_item (fbi, last, op, &index, &size, &agg= pos)) + + if (decompose_param_expr (fbi, last, op, &index, ¶m_type, &aggpos, + ¶m_ops)) { code =3D gimple_cond_code (last); inverted_code =3D invert_tree_comparison (code, HONOR_NANS (op)); @@ -1201,13 +1346,13 @@ set_cond_stmt_execution_predicate (struct ipa_func_= body_info *fbi, if (this_code !=3D ERROR_MARK) { predicate p - =3D add_condition (summary, index, size, &aggpos, this_code, - unshare_expr_without_location - (gimple_cond_rhs (last))); + =3D add_condition (summary, index, param_type, &aggpos, + this_code, gimple_cond_rhs (last), param_ops); e->aux =3D edge_predicate_pool.allocate (); *(predicate *) e->aux =3D p; } } + vec_free (param_ops); } =20 if (TREE_CODE (op) !=3D SSA_NAME) @@ -1230,12 +1375,11 @@ set_cond_stmt_execution_predicate (struct ipa_func_= body_info *fbi, || gimple_call_num_args (set_stmt) !=3D 1) return; op2 =3D gimple_call_arg (set_stmt, 0); - if (!unmodified_parm_or_parm_agg_item (fbi, set_stmt, op2, &index, &size, - &aggpos)) + if (!decompose_param_expr (fbi, set_stmt, op2, &index, ¶m_type, &agg= pos)) return; FOR_EACH_EDGE (e, ei, bb->succs) if (e->flags & EDGE_FALSE_VALUE) { - predicate p =3D add_condition (summary, index, size, &aggpos, + predicate p =3D add_condition (summary, index, param_type, &aggpos, predicate::is_not_constant, NULL_TREE); e->aux =3D edge_predicate_pool.allocate (); *(predicate *) e->aux =3D p; @@ -1254,19 +1398,21 @@ set_switch_stmt_execution_predicate (struct ipa_fun= c_body_info *fbi, gimple *lastg; tree op; int index; - poly_int64 size; struct agg_position_info aggpos; edge e; edge_iterator ei; size_t n; size_t case_idx; + tree param_type; + expr_eval_ops param_ops; =20 lastg =3D last_stmt (bb); if (!lastg || gimple_code (lastg) !=3D GIMPLE_SWITCH) return; gswitch *last =3D as_a (lastg); op =3D gimple_switch_index (last); - if (!unmodified_parm_or_parm_agg_item (fbi, last, op, &index, &size, &ag= gpos)) + if (!decompose_param_expr (fbi, last, op, &index, ¶m_type, &aggpos, + ¶m_ops)) return; =20 auto_vec > ranges; @@ -1294,15 +1440,15 @@ set_switch_stmt_execution_predicate (struct ipa_fun= c_body_info *fbi, max =3D CASE_HIGH (cl); =20 if (!max) - p =3D add_condition (summary, index, size, &aggpos, EQ_EXPR, - unshare_expr_without_location (min)); + p =3D add_condition (summary, index, param_type, &aggpos, EQ_EXPR, + min, param_ops); else { predicate p1, p2; - p1 =3D add_condition (summary, index, size, &aggpos, GE_EXPR, - unshare_expr_without_location (min)); - p2 =3D add_condition (summary, index, size, &aggpos, LE_EXPR, - unshare_expr_without_location (max)); + p1 =3D add_condition (summary, index, param_type, &aggpos, GE_EXPR, + min, param_ops); + p2 =3D add_condition (summary, index, param_type, &aggpos, LE_EXPR, + max, param_ops); p =3D p1 & p2; } *(class predicate *) e->aux @@ -1356,6 +1502,7 @@ set_switch_stmt_execution_predicate (struct ipa_func_= body_info *fbi, if (bound_count > bound_limit) { *(class predicate *) e->aux =3D true; + vec_free (param_ops); return; } =20 @@ -1385,16 +1532,16 @@ set_switch_stmt_execution_predicate (struct ipa_fun= c_body_info *fbi, tree max =3D ranges[i].second; =20 if (min =3D=3D max) - p_seg &=3D add_condition (summary, index, size, &aggpos, NE_EXPR, - unshare_expr_without_location (min)); + p_seg &=3D add_condition (summary, index, param_type, &aggpos, NE_EXPR, + min, param_ops); else { /* Do not create sub-predicate for range that is beyond low bound of switch index. */ if (wi::lt_p (vr_wmin, wi::to_wide (min), TYPE_SIGN (type))) { - p_seg &=3D add_condition (summary, index, size, &aggpos, LT_EXPR, - unshare_expr_without_location (min)); + p_seg &=3D add_condition (summary, index, param_type, &aggpos, + LT_EXPR, min, param_ops); p_all =3D p_all.or_with (summary->conds, p_seg); } =20 @@ -1406,14 +1553,16 @@ set_switch_stmt_execution_predicate (struct ipa_fun= c_body_info *fbi, break; } =20 - p_seg =3D add_condition (summary, index, size, &aggpos, GT_EXPR, - unshare_expr_without_location (max)); + p_seg =3D add_condition (summary, index, param_type, &aggpos, GT_EXPR, + max, param_ops); } } =20 p_all =3D p_all.or_with (summary->conds, p_seg); *(class predicate *) e->aux =3D p_all.or_with (summary->conds, *(class predicate *) e->aux); + + vec_free (param_ops); } =20 =20 @@ -1502,15 +1651,14 @@ will_be_nonconstant_expr_predicate (ipa_func_body_i= nfo *fbi, { tree parm; int index; - poly_int64 size; =20 while (UNARY_CLASS_P (expr)) expr =3D TREE_OPERAND (expr, 0); =20 - parm =3D unmodified_parm (fbi, NULL, expr, &size); + parm =3D unmodified_parm (fbi, NULL, expr, NULL); if (parm && (index =3D ipa_get_param_decl_index (fbi->info, parm)) >=3D = 0) - return add_condition (summary, index, size, NULL, predicate::changed, - NULL_TREE); + return add_condition (summary, index, TREE_TYPE (parm), NULL, + predicate::changed, NULL_TREE); if (is_gimple_min_invariant (expr)) return false; if (TREE_CODE (expr) =3D=3D SSA_NAME) @@ -1574,10 +1722,10 @@ will_be_nonconstant_predicate (struct ipa_func_body= _info *fbi, predicate p =3D true; ssa_op_iter iter; tree use; + tree param_type =3D NULL_TREE; predicate op_non_const; bool is_load; int base_index; - poly_int64 size; struct agg_position_info aggpos; =20 /* What statments might be optimized away @@ -1598,11 +1746,9 @@ will_be_nonconstant_predicate (struct ipa_func_body_= info *fbi, /* Loads can be optimized when the value is known. */ if (is_load) { - tree op; - gcc_assert (gimple_assign_single_p (stmt)); - op =3D gimple_assign_rhs1 (stmt); - if (!unmodified_parm_or_parm_agg_item (fbi, stmt, op, &base_index, &= size, - &aggpos)) + tree op =3D gimple_assign_rhs1 (stmt); + if (!decompose_param_expr (fbi, stmt, op, &base_index, ¶m_type, + &aggpos)) return p; } else @@ -1627,21 +1773,20 @@ will_be_nonconstant_predicate (struct ipa_func_body= _info *fbi, =20 if (is_load) op_non_const =3D - add_condition (summary, base_index, size, &aggpos, predicate::change= d, - NULL); + add_condition (summary, base_index, param_type, &aggpos, + predicate::changed, NULL_TREE); else op_non_const =3D false; FOR_EACH_SSA_TREE_OPERAND (use, stmt, iter, SSA_OP_USE) { - poly_int64 size; - tree parm =3D unmodified_parm (fbi, stmt, use, &size); + tree parm =3D unmodified_parm (fbi, stmt, use, NULL); int index; =20 if (parm && (index =3D ipa_get_param_decl_index (fbi->info, parm)) >= =3D 0) { if (index !=3D base_index) - p =3D add_condition (summary, index, size, NULL, predicate::changed, - NULL_TREE); + p =3D add_condition (summary, index, TREE_TYPE (parm), NULL, + predicate::changed, NULL_TREE); else continue; } @@ -1773,7 +1918,7 @@ param_change_prob (ipa_func_body_info *fbi, gimple *s= tmt, int i) return REG_BR_PROB_BASE; if (dump_file) { - fprintf (dump_file, " Analyzing param change probablity of "); + fprintf (dump_file, " Analyzing param change probability of "); print_generic_expr (dump_file, op, TDF_SLIM); fprintf (dump_file, "\n"); } @@ -3400,15 +3545,49 @@ inline_read_section (struct lto_file_decl_data *fil= e_data, const char *data, for (j =3D 0; j < count2; j++) { struct condition c; + unsigned int k, count3; c.operand_num =3D streamer_read_uhwi (&ib); - c.size =3D streamer_read_poly_uint64 (&ib); c.code =3D (enum tree_code) streamer_read_uhwi (&ib); + c.type =3D stream_read_tree (&ib, data_in); c.val =3D stream_read_tree (&ib, data_in); bp =3D streamer_read_bitpack (&ib); c.agg_contents =3D bp_unpack_value (&bp, 1); c.by_ref =3D bp_unpack_value (&bp, 1); if (c.agg_contents) c.offset =3D streamer_read_uhwi (&ib); + c.param_ops =3D NULL; + count3 =3D streamer_read_uhwi (&ib); + for (k =3D 0; k < count3; k++) + { + struct expr_eval_op op; + enum gimple_rhs_class rhs_class; + op.code =3D (enum tree_code) streamer_read_uhwi (&ib); + op.type =3D stream_read_tree (&ib, data_in); + switch (rhs_class =3D get_gimple_rhs_class (op.code)) + { + case GIMPLE_UNARY_RHS: + op.index =3D 0; + op.val[0] =3D NULL_TREE; + op.val[1] =3D NULL_TREE; + break; + + case GIMPLE_BINARY_RHS: + case GIMPLE_TERNARY_RHS: + bp =3D streamer_read_bitpack (&ib); + op.index =3D bp_unpack_value (&bp, 2); + op.val[0] =3D stream_read_tree (&ib, data_in); + if (rhs_class =3D=3D GIMPLE_BINARY_RHS) + op.val[1] =3D NULL_TREE; + else + op.val[1] =3D stream_read_tree (&ib, data_in); + break; + + default: + fatal_error (UNKNOWN_LOCATION, + "invalid fnsummary in LTO stream"); + } + vec_safe_push (c.param_ops, op); + } if (info) vec_safe_push (info->conds, c); } @@ -3554,9 +3733,12 @@ ipa_fn_summary_write (void) streamer_write_uhwi (ob, vec_safe_length (info->conds)); for (i =3D 0; vec_safe_iterate (info->conds, i, &c); i++) { + int j; + struct expr_eval_op *op; + streamer_write_uhwi (ob, c->operand_num); - streamer_write_poly_uint64 (ob, c->size); streamer_write_uhwi (ob, c->code); + stream_write_tree (ob, c->type, true); stream_write_tree (ob, c->val, true); bp =3D bitpack_create (ob->main_stream); bp_pack_value (&bp, c->agg_contents, 1); @@ -3564,6 +3746,21 @@ ipa_fn_summary_write (void) streamer_write_bitpack (&bp); if (c->agg_contents) streamer_write_uhwi (ob, c->offset); + streamer_write_uhwi (ob, vec_safe_length (c->param_ops)); + for (j =3D 0; vec_safe_iterate (c->param_ops, j, &op); j++) + { + streamer_write_uhwi (ob, op->code); + stream_write_tree (ob, op->type, true); + if (op->val[0]) + { + bp =3D bitpack_create (ob->main_stream); + bp_pack_value (&bp, op->index, 2); + streamer_write_bitpack (&bp); + stream_write_tree (ob, op->val[0], true); + if (op->val[1]) + stream_write_tree (ob, op->val[1], true); + } + } } streamer_write_uhwi (ob, vec_safe_length (info->size_time_table)); for (i =3D 0; vec_safe_iterate (info->size_time_table, i, &e); i++) diff --git a/gcc/ipa-predicate.c b/gcc/ipa-predicate.c index 8a9851a2040..b5e3cf44323 100644 --- a/gcc/ipa-predicate.c +++ b/gcc/ipa-predicate.c @@ -33,9 +33,36 @@ along with GCC; see the file COPYING3. If not see #include "fold-const.h" #include "tree-pretty-print.h" #include "gimple.h" +#include "gimplify.h" #include "data-streamer.h" =20 =20 +/* Check whether two set of operations have same effects. */ +static bool +expr_eval_ops_equal_p (expr_eval_ops ops1, expr_eval_ops ops2) +{ + if (ops1) + { + if (!ops2 || ops1->length () !=3D ops2->length ()) + return false; + + for (unsigned i =3D 0; i < ops1->length (); i++) + { + expr_eval_op &op1 =3D (*ops1)[i]; + expr_eval_op &op2 =3D (*ops2)[i]; + + if (op1.code !=3D op2.code + || op1.index !=3D op2.index + || !vrp_operand_equal_p (op1.val[0], op2.val[0]) + || !vrp_operand_equal_p (op1.val[1], op2.val[1]) + || !types_compatible_p (op1.type, op2.type)) + return false; + } + return true; + } + return !ops2; +} + /* Add clause CLAUSE into the predicate P. When CONDITIONS is NULL do not perform checking whether NEW_CLAUSE is obviously true. This is useful only when NEW_CLAUSE is known to be @@ -110,14 +137,16 @@ predicate::add_clause (conditions conditions, clause_= t new_clause) for (c2 =3D c1 + 1; c2 < num_conditions; c2++) if (new_clause & (1 << c2)) { - condition *cc1 =3D - &(*conditions)[c1 - predicate::first_dynamic_condition]; condition *cc2 =3D &(*conditions)[c2 - predicate::first_dynamic_condition]; if (cc1->operand_num =3D=3D cc2->operand_num - && cc1->val =3D=3D cc2->val + && vrp_operand_equal_p (cc1->val, cc2->val) && cc2->code !=3D is_not_constant - && cc2->code !=3D predicate::changed + && cc2->code !=3D changed + && expr_eval_ops_equal_p (cc1->param_ops, cc2->param_ops) + && cc2->agg_contents =3D=3D cc1->agg_contents + && cc2->by_ref =3D=3D cc1->by_ref + && types_compatible_p (cc2->type, cc1->type) && cc1->code =3D=3D invert_tree_comparison (cc2->code, HONOR_NANS (cc1->val))) return; @@ -300,6 +329,83 @@ dump_condition (FILE *f, conditions conditions, int co= nd) if (c->agg_contents) fprintf (f, "[%soffset: " HOST_WIDE_INT_PRINT_DEC "]", c->by_ref ? "ref " : "", c->offset); + + for (unsigned i =3D 0; i < vec_safe_length (c->param_ops); i++) + { + expr_eval_op &op =3D (*(c->param_ops))[i]; + const char *op_name =3D op_symbol_code (op.code); + + if (op_name =3D=3D op_symbol_code (ERROR_MARK)) + op_name =3D get_tree_code_name (op.code); + + fprintf (f, ",("); + + if (!op.val[0]) + { + switch (op.code) + { + case FLOAT_EXPR: + case FIX_TRUNC_EXPR: + case FIXED_CONVERT_EXPR: + case VIEW_CONVERT_EXPR: + CASE_CONVERT: + if (op.code =3D=3D VIEW_CONVERT_EXPR) + fprintf (f, "VCE"); + fprintf (f, "("); + print_generic_expr (f, op.type); + fprintf (f, ")" ); + break; + + default: + fprintf (f, "%s", op_name); + } + fprintf (f, " #"); + } + else if (!op.val[1]) + { + if (op.index) + { + print_generic_expr (f, op.val[0]); + fprintf (f, " %s #", op_name); + } + else + { + fprintf (f, "# %s ", op_name); + print_generic_expr (f, op.val[0]); + } + } + else + { + fprintf (f, "%s ", op_name); + switch (op.index) + { + case 0: + fprintf (f, "#, "); + print_generic_expr (f, op.val[0]); + fprintf (f, ", "); + print_generic_expr (f, op.val[1]); + break; + + case 1: + print_generic_expr (f, op.val[0]); + fprintf (f, ", #, "); + print_generic_expr (f, op.val[1]); + break; + + case 2: + print_generic_expr (f, op.val[0]); + fprintf (f, ", "); + print_generic_expr (f, op.val[1]); + fprintf (f, ", #"); + break; + + default: + fprintf (f, "*, *, *"); + } + } + fprintf (f, ")"); + } + if (c->code =3D=3D predicate::is_not_constant) { fprintf (f, " not constant"); @@ -462,8 +568,8 @@ predicate::remap_after_inlining (class ipa_fn_summary *= info, ap.by_ref =3D c->by_ref; cond_predicate =3D add_condition (info, operand_map[c->operand_num], - c->size, &ap, c->code, - c->val); + c->type, &ap, c->code, + c->val, c->param_ops); } } /* Fixed conditions remains same, construct single @@ -516,21 +622,23 @@ predicate::stream_out (struct output_block *ob) } =20 =20 -/* Add condition to condition list SUMMARY. OPERAND_NUM, SIZE, CODE and VAL - correspond to fields of condition structure. AGGPOS describes whether = the - used operand is loaded from an aggregate and where in the aggregate it = is. - It can be NULL, which means this not a load from an aggregate. */ +/* Add condition to condition list SUMMARY. OPERAND_NUM, TYPE, CODE, VAL = and + PARAM_OPS correspond to fields of condition structure. AGGPOS describes + whether the used operand is loaded from an aggregate and where in the + aggregate it is. It can be NULL, which means this not a load from an + aggregate. */ =20 predicate add_condition (class ipa_fn_summary *summary, int operand_num, - poly_int64 size, struct agg_position_info *aggpos, - enum tree_code code, tree val) + tree type, struct agg_position_info *aggpos, + enum tree_code code, tree val, expr_eval_ops param_ops) { - int i; + int i, j; struct condition *c; struct condition new_cond; HOST_WIDE_INT offset; bool agg_contents, by_ref; + expr_eval_op *op; =20 if (aggpos) { @@ -549,10 +657,11 @@ add_condition (class ipa_fn_summary *summary, int ope= rand_num, for (i =3D 0; vec_safe_iterate (summary->conds, i, &c); i++) { if (c->operand_num =3D=3D operand_num - && known_eq (c->size, size) && c->code =3D=3D code - && c->val =3D=3D val + && types_compatible_p (c->type, type) + && vrp_operand_equal_p (c->val, val) && c->agg_contents =3D=3D agg_contents + && expr_eval_ops_equal_p (c->param_ops, param_ops) && (!agg_contents || (c->offset =3D=3D offset && c->by_ref =3D=3D by_re= f))) return predicate::predicate_testing_cond (i); } @@ -562,11 +671,21 @@ add_condition (class ipa_fn_summary *summary, int ope= rand_num, =20 new_cond.operand_num =3D operand_num; new_cond.code =3D code; - new_cond.val =3D val; + new_cond.type =3D unshare_expr_without_location (type); + new_cond.val =3D val ? unshare_expr_without_location (val) : val; new_cond.agg_contents =3D agg_contents; new_cond.by_ref =3D by_ref; new_cond.offset =3D offset; - new_cond.size =3D size; + new_cond.param_ops =3D vec_safe_copy (param_ops); + + for (j =3D 0; vec_safe_iterate (new_cond.param_ops, j, &op); j++) + { + if (op->val[0]) + op->val[0] =3D unshare_expr_without_location (op->val[0]); + if (op->val[1]) + op->val[1] =3D unshare_expr_without_location (op->val[1]); + } + vec_safe_push (summary->conds, new_cond); =20 return predicate::predicate_testing_cond (i); diff --git a/gcc/ipa-predicate.h b/gcc/ipa-predicate.h index 237306dc9fe..4121218ac04 100644 --- a/gcc/ipa-predicate.h +++ b/gcc/ipa-predicate.h @@ -22,16 +22,36 @@ along with GCC; see the file COPYING3. If not see inlined into (i.e. known constant values of function parameters. =20 Conditions that are interesting for function body are collected into CO= NDS - vector. They are of simple for function_param OP VAL, where VAL is - IPA invariant. The conditions are then referred by predicates. */ + vector. They are of simple as kind of a mathematical transformation on + function parameter, T(function_param), in which the parameter occurs on= ly + once, and other operands are IPA invariant. The conditions are then + referred by predicates. */ + + +/* A simplified representation of tree node, for unary, binary and ternary + operation. Computations on parameter are decomposed to a series of this + kind of structure. */ +struct GTY(()) expr_eval_op +{ + /* Result type of expression. */ + tree type; + /* Constant operands in expression, there are at most two. */ + tree val[2]; + /* Index of parameter operand in expression. */ + unsigned index : 2; + /* Operation code of expression. */ + ENUM_BITFIELD(tree_code) code : 16; +}; + +typedef vec *expr_eval_ops; =20 struct GTY(()) condition { /* If agg_contents is set, this is the offset from which the used data w= as loaded. */ HOST_WIDE_INT offset; - /* Size of the access reading the data (or the PARM_DECL SSA_NAME). */ - poly_int64 size; + /* Type of the access reading the data (or the PARM_DECL SSA_NAME). */ + tree type; tree val; int operand_num; ENUM_BITFIELD(tree_code) code : 16; @@ -41,6 +61,9 @@ struct GTY(()) condition /* If agg_contents is set, this differentiates between loads from data passed by reference and by value. */ unsigned by_ref : 1; + /* A set of sequential operations on the parameter, which can be seen as + a mathmatical function on the parameter. */ + expr_eval_ops param_ops; }; =20 /* Information kept about parameter of call site. */ @@ -228,5 +251,6 @@ private: =20 void dump_condition (FILE *f, conditions conditions, int cond); predicate add_condition (class ipa_fn_summary *summary, int operand_num, - poly_int64 size, struct agg_position_info *aggpos, - enum tree_code code, tree val); + tree type, struct agg_position_info *aggpos, + enum tree_code code, tree val, + expr_eval_ops param_ops =3D NULL); diff --git a/gcc/params.def b/gcc/params.def index 5fe33976b37..103df3b5458 100644 --- a/gcc/params.def +++ b/gcc/params.def @@ -1129,6 +1129,12 @@ DEFPARAM (PARAM_IPA_MAX_SWITCH_PREDICATE_BOUNDS, "statement used during IPA functoin summary generation.", 5, 0, 0) =20 +DEFPARAM (PARAM_IPA_MAX_PARAM_EXPR_OPS, + "ipa-max-param-expr-ops", + "Maximum number of operations in a parameter expression that can " + "be handled by IPA analysis. ", + 10, 0, 0) + /* WHOPR partitioning configuration. */ =20 DEFPARAM (PARAM_LTO_PARTITIONS, diff --git a/gcc/testsuite/g++.dg/tree-ssa/ivopts-3.C b/gcc/testsuite/g++.d= g/tree-ssa/ivopts-3.C index 07ff1b770f8..cbb6c850baa 100644 --- a/gcc/testsuite/g++.dg/tree-ssa/ivopts-3.C +++ b/gcc/testsuite/g++.dg/tree-ssa/ivopts-3.C @@ -25,7 +25,7 @@ protected: double stuff; =20 public: - explicit MinimalVector ( int length ) { + __attribute__((noinline)) explicit MinimalVector ( int length ) { _pData =3D new double[length]; for (int i =3D 0; i < length; ++i) _pData[i] =3D 0.; } diff --git a/gcc/testsuite/gcc.dg/ipa/pr91088.c b/gcc/testsuite/gcc.dg/ipa/= pr91088.c new file mode 100644 index 00000000000..a81c59f98b1 --- /dev/null +++ b/gcc/testsuite/gcc.dg/ipa/pr91088.c @@ -0,0 +1,120 @@ +/* { dg-do compile } */ +/* { dg-options "-O3 -fdump-ipa-cp-details -fno-inline" } */ + +int foo(); + +#define large_code \ +do { \ + foo (); \ + foo (); \ + foo (); \ + foo (); \ + foo (); \ + foo (); \ + foo (); \ + foo (); \ + foo (); \ + foo (); \ + foo (); \ + foo (); \ + foo (); \ + foo (); \ + foo (); \ + foo (); \ + foo (); \ + foo (); \ + foo (); \ + foo (); \ + foo (); \ + foo (); \ + foo (); \ + foo (); \ + foo (); \ + foo (); \ + foo (); \ + foo (); \ + foo (); \ + foo (); \ + foo (); \ + foo (); \ + foo (); \ + foo (); \ + foo (); \ + foo (); \ + foo (); \ + foo (); \ + foo (); \ + foo (); \ +} while (1) + + +struct A +{ + char f1; + short f2 : 5; + int f3; +}; + +int callee1 (struct A a) +{ + if ((a.f2 + 7) & 17) + foo (); + + if ((1300 / (short)a.f3) =3D=3D 19) + large_code; + + return 1; +} + +int callee2 (short *p) +{ + if ((*p ^ 1) < 8) + large_code;=20=20=20=20=20=20 + + return 2; +} + +int callee3 (int v) +{ + if ((27 % ((1 - (char) v) * 3)) < 6) + { + large_code; + return v + 2; + } + else + return v + 1; +} + +int caller () +{ + struct A a; + short b; + + a.f2 =3D -7; + a.f3 =3D 68; + if (callee1 (a)) + foo (); + + a.f2 =3D 3; + a.f3 =3D 10; + if (callee1 (a)) + foo (); + + b =3D 9; + if (callee2 (&b)) + foo (); + + b =3D 2; + if (callee2 (&b)) + foo (); + + return callee3 (-5) + + callee3 (0);=20 +} + +/* { dg-final { scan-ipa-dump-times "Creating a specialized node of callee= 1" 1 "cp" } } */ +/* { dg-final { scan-ipa-dump-times "Creating a specialized node of callee= 2" 1 "cp" } } */ +/* { dg-final { scan-ipa-dump-times "Creating a specialized node of callee= 3" 1 "cp" } } */ +/* { dg-final { scan-ipa-dump "op0\\\[offset: 32],\\(\\(short int\\) #\\),= \\(\\(int\\) #\\),\\(1300 / #\\) =3D=3D 19" "cp" } } */ +/* { dg-final { scan-ipa-dump "op0\\\[ref offset: 0],\\(# \\^ 1\\) <" "cp"= } } */ +/* { dg-final { scan-ipa-dump "op0,\\(\\(char\\) #\\),\\(\\(int\\) #\\),\\= (1 - #\\),\\(# \\* 3\\),\\(27 % #\\) <" "cp" } } */ --=20 2.17.1