From patchwork Fri Jul 12 11:24:00 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Feng Xue OS X-Patchwork-Id: 1131315 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (mailfrom) smtp.mailfrom=gcc.gnu.org (client-ip=209.132.180.131; helo=sourceware.org; envelope-from=gcc-patches-return-504992-incoming=patchwork.ozlabs.org@gcc.gnu.org; receiver=) Authentication-Results: ozlabs.org; dmarc=none (p=none dis=none) header.from=os.amperecomputing.com Authentication-Results: ozlabs.org; dkim=pass (1024-bit key; unprotected) header.d=gcc.gnu.org header.i=@gcc.gnu.org header.b="AgJ57sim"; dkim=fail reason="signature verification failed" (1024-bit key; unprotected) header.d=os.amperecomputing.com header.i=@os.amperecomputing.com header.b="kHPycjY8"; 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 45lVvR0s4vz9sBF for ; Fri, 12 Jul 2019 21:24:50 +1000 (AEST) DomainKey-Signature: a=rsa-sha1; c=nofws; d=gcc.gnu.org; h=list-id :list-unsubscribe:list-archive:list-post:list-help:sender:from :to:subject:date:message-id:content-type :content-transfer-encoding:mime-version; q=dns; s=default; b=TqF W+ErwqYMTrSalKwEX2UW/oVukMcDrpSkBMNDGjqUvMWySwhk4FtjitXcHDFgG/7n NFDFl7LW4ANn9ZI1vmclS0mSUkYRZfsoBlCX6c9LqbiRtLlMZ3/FDSA/FHa5JMfE AIrqeiMdAqTUOqtWjT+GDI8jDrDSUohHyu/zrA/o= 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:from :to:subject:date:message-id:content-type :content-transfer-encoding:mime-version; s=default; bh=oeGOZa8Re RIV/hXvYNzZW0TbXRI=; b=AgJ57simTSjjJXT+L51OsyUlGrz4mFcFQG0isfOZa puwq9eIHGcEET60A9PYThRmVPsW4V/xuNKciSA+wMJQXWCtBWF5P1SE/sWw5T79O l+YKjV12Hmip5e/dFf+FJMk8fEosOy805pmrh6Xi1AUjO4VfPWwxKLgYhydDmyZJ ps= Received: (qmail 70066 invoked by alias); 12 Jul 2019 11:24:37 -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 69463 invoked by uid 89); 12 Jul 2019 11:24:23 -0000 Authentication-Results: sourceware.org; auth=none X-Spam-SWARE-Status: No, score=-25.9 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=formal X-HELO: NAM04-BN3-obe.outbound.protection.outlook.com Received: from mail-eopbgr680116.outbound.protection.outlook.com (HELO NAM04-BN3-obe.outbound.protection.outlook.com) (40.107.68.116) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with ESMTP; Fri, 12 Jul 2019 11:24:04 +0000 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=os.amperecomputing.com; s=selector1; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck; bh=gxFaa7DWJ84YnKcO5duYZDcwAJRA3PWkPkmVEEcxFd4=; b=kHPycjY8L0l6+o72p4x+Zr7Fwhjij4J1mjFU7rkJH+NaN476EVw5m9OJZRneX1VR+vKl3XOQvhs519WcyV/xD9ew+WjtM/UFPLeGnEETiQNGKRHOGqqmgbjf0iILfFt7oK9PQF7fZ1JbWLMxZ7oIxMLazFYq6umE0iXOM9WAQgI= Received: from BYAPR01MB4869.prod.exchangelabs.com (20.177.228.18) by BYAPR01MB4726.prod.exchangelabs.com (20.177.224.150) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.2052.19; Fri, 12 Jul 2019 11:24:00 +0000 Received: from BYAPR01MB4869.prod.exchangelabs.com ([fe80::55d3:fd08:5931:781]) by BYAPR01MB4869.prod.exchangelabs.com ([fe80::55d3:fd08:5931:781%6]) with mapi id 15.20.2052.020; Fri, 12 Jul 2019 11:24:00 +0000 From: Feng Xue OS To: "gcc-patches@gcc.gnu.org" , Jan Hubicka , Martin Jambor Subject: [PATCH] Generalized predicate/condition for parameter reference in IPA (PR ipa/91088) Date: Fri, 12 Jul 2019 11:24:00 +0000 Message-ID: authentication-results: spf=none (sender IP is ) smtp.mailfrom=fxue@os.amperecomputing.com; x-ms-oob-tlc-oobclassifiers: OLM:8882; received-spf: None (protection.outlook.com: os.amperecomputing.com does not designate permitted sender hosts) x-ms-exchange-senderadcheck: 1 MIME-Version: 1.0 X-MS-Exchange-CrossTenant-mailboxtype: HOSTED X-MS-Exchange-CrossTenant-userprincipalname: fxue@os.amperecomputing.com Current IPA-cp only generates cost-evaluating predicate for conditional statement like "if (param cmp const_val)", it is too simple and conservative. This patch generalizes the process to handle the form as T(param), a mathematical transformation on the function parameter, in which the parameter occurs once, and other operands are constant value. Feng ---- diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 3d92250b520..0110446e09e 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,25 @@ +2019-07-12 Feng Xue + + PR ipa/91088 + * ipa-predicat.h (struct expr_eval_op): New struct. + (expr_eval_ops): New typedef. + (struct condition): Add param_ops member. + (add_condition): Add param_ops parameter. + * ipa-predicat.c (expr_eval_ops_equal_p): New function. + (predicate::add_clause): Add param_ops comparison. + (dump_condition): Add debug dump for param_ops. + (remap_after_inlining): Add param_ops argument to call to + add_condition. + (add_condition): Add parameter param_ops. + * ipa-fnsummary.c (evaluate_conditions_for_known_args): Fold + parameter expressions using param_ops. + (decompose_param_expr): New function. + (set_cond_stmt_execution_predicate): Use call to decompose_param_expr + to replace call to unmodified_parm_or_parm_agg_item. + (set_switch_stmt_execution_predicate): Likewise. + (inline_read_section): Read param_ops from summary stream. + (ipa_fn_summary_write): Write param_ops to summary stream. + 2019-07-11 Sunil K Pandey PR target/90980 diff --git a/gcc/ipa-fnsummary.c b/gcc/ipa-fnsummary.c index 09986211a1d..faf8bd39090 100644 --- a/gcc/ipa-fnsummary.c +++ b/gcc/ipa-fnsummary.c @@ -301,9 +301,9 @@ set_hint_predicate (predicate **p, predicate new_predicate) } -/* Compute what conditions may or may not hold given invormation about +/* Compute what conditions may or may not hold given information about parameters. RET_CLAUSE returns truths that may hold in a specialized copy, - whie RET_NONSPEC_CLAUSE returns truths that may hold in an nonspecialized + while RET_NONSPEC_CLAUSE returns truths that may hold in an nonspecialized copy when called in a given context. It is a bitmask of conditions. Bit 0 means that condition is known to be false, while bit 1 means that condition may or may not be true. These differs - for example NOT_INLINED condition @@ -336,6 +336,8 @@ evaluate_conditions_for_known_args (struct cgraph_node *node, { tree val; tree res; + int j; + struct expr_eval_op *op; /* We allow call stmt to have fewer arguments than the callee function (especially for K&R style programs). So bound check here (we assume @@ -399,7 +401,18 @@ evaluate_conditions_for_known_args (struct cgraph_node *node, continue; } - val = fold_unary (VIEW_CONVERT_EXPR, TREE_TYPE (c->val), val); + for (j = 0; vec_safe_iterate (c->param_ops, j, &op); j++) + { + if (!op->val) + val = fold_unary (op->code, op->type, val); + else if (op->val_is_rhs) + val = fold_binary_to_constant (op->code, op->type, val, op->val); + else + val = fold_binary_to_constant (op->code, op->type, op->val, val); + if (!val) + break; + } + res = val ? fold_binary_to_constant (c->code, boolean_type_node, val, c->val) : NULL; @@ -1177,6 +1190,105 @@ eliminated_by_inlining_prob (ipa_func_body_info *fbi, gimple *stmt) } } +/* Flatten a tree expression on parameter into a set of sequential operations. + we only handle expression that is a mathematical transformation on the + parameter, and in the expression, parameter occurs only once, and other + operands are IPA invariant. */ + +static bool +decompose_param_expr (struct ipa_func_body_info *fbi, + gimple *stmt, tree expr, + int *index_p, HOST_WIDE_INT *size_p, + struct agg_position_info *aggpos, + expr_eval_ops *param_ops_p) +{ + if (param_ops_p) + *param_ops_p = NULL; + + while (true) + { + gimple_rhs_class rhs_class; + expr_eval_op eval_op; + + if (unmodified_parm_or_parm_agg_item (fbi, stmt, expr, index_p, + size_p, aggpos)) + { + if (param_ops_p) + { + /* Find use of parameter, add a convert operation to describe + result type, which may not be same as parameter type. */ + eval_op.val_is_rhs = false; + eval_op.val = NULL_TREE; + eval_op.code = VIEW_CONVERT_EXPR; + eval_op.type = TREE_TYPE (expr); + + vec_safe_insert (*param_ops_p, 0, eval_op); + } + return true; + } + + if (TREE_CODE (expr) != SSA_NAME || SSA_NAME_IS_DEFAULT_DEF (expr)) + break; + + if (!is_gimple_assign (stmt = SSA_NAME_DEF_STMT (expr))) + break; + + rhs_class = gimple_assign_rhs_class (stmt); + + if (rhs_class == GIMPLE_SINGLE_RHS) + expr = gimple_assign_rhs1 (stmt); + else if (rhs_class == GIMPLE_UNARY_RHS) + { + expr = gimple_assign_rhs1 (stmt); + + if (param_ops_p) + { + eval_op.val_is_rhs = false; + eval_op.val = NULL_TREE; + eval_op.code = gimple_assign_rhs_code (stmt); + eval_op.type = TREE_TYPE (expr); + + vec_safe_insert (*param_ops_p, 0, eval_op); + } + } + else if (rhs_class == GIMPLE_BINARY_RHS) + { + tree op1 = gimple_assign_rhs1 (stmt); + tree op2 = gimple_assign_rhs2 (stmt); + + if (is_gimple_ip_invariant (op1)) + { + eval_op.val_is_rhs = false; + eval_op.val = op1; + expr = op2; + } + else if (is_gimple_ip_invariant (op2)) + { + eval_op.val_is_rhs = true; + eval_op.val = op2; + expr = op1; + } + else + break; + + if (param_ops_p) + { + eval_op.code = gimple_assign_rhs_code (stmt); + eval_op.type = TREE_TYPE (expr); + + vec_safe_insert (*param_ops_p, 0, eval_op); + } + } + else + break; + } + + /* Failed to decompose, free resource and return. */ + if (param_ops_p) + vec_free (*param_ops_p); + + return false; +} /* If BB ends by a conditional we can turn into predicates, attach corresponding predicates to the CFG edges. */ @@ -1196,6 +1308,7 @@ set_cond_stmt_execution_predicate (struct ipa_func_body_info *fbi, edge_iterator ei; gimple *set_stmt; tree op2; + expr_eval_ops param_ops; last = last_stmt (bb); if (!last || gimple_code (last) != GIMPLE_COND) @@ -1203,10 +1316,8 @@ set_cond_stmt_execution_predicate (struct ipa_func_body_info *fbi, if (!is_gimple_ip_invariant (gimple_cond_rhs (last))) return; op = gimple_cond_lhs (last); - /* TODO: handle conditionals like - var = op0 < 4; - if (var != 0). */ - if (unmodified_parm_or_parm_agg_item (fbi, last, op, &index, &size, &aggpos)) + + if (decompose_param_expr (fbi, last, op, &index, &size, &aggpos, ¶m_ops)) { code = gimple_cond_code (last); inverted_code = invert_tree_comparison (code, HONOR_NANS (op)); @@ -1222,13 +1333,13 @@ set_cond_stmt_execution_predicate (struct ipa_func_body_info *fbi, { predicate p = add_condition (summary, index, size, &aggpos, this_code, - unshare_expr_without_location - (gimple_cond_rhs (last))); + gimple_cond_rhs (last), param_ops); e->aux = edge_predicate_pool.allocate (); *(predicate *) e->aux = p; } } } + vec_free (param_ops); if (TREE_CODE (op) != SSA_NAME) return; @@ -1240,7 +1351,7 @@ set_cond_stmt_execution_predicate (struct ipa_func_body_info *fbi, Here we can predicate nonconstant_code. We can't really handle constant_code since we have no predicate for this and also the constant code is not known to be - optimized away when inliner doen't see operand is constant. + optimized away when inliner doesn't see operand is constant. Other optimizers might think otherwise. */ if (gimple_cond_code (last) != NE_EXPR || !integer_zerop (gimple_cond_rhs (last))) @@ -1250,8 +1361,7 @@ set_cond_stmt_execution_predicate (struct ipa_func_body_info *fbi, || gimple_call_num_args (set_stmt) != 1) return; op2 = 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, &size, &aggpos, NULL)) return; FOR_EACH_EDGE (e, ei, bb->succs) if (e->flags & EDGE_FALSE_VALUE) { @@ -1280,13 +1390,15 @@ set_switch_stmt_execution_predicate (struct ipa_func_body_info *fbi, edge_iterator ei; size_t n; size_t case_idx; + expr_eval_ops param_ops; lastg = last_stmt (bb); if (!lastg || gimple_code (lastg) != GIMPLE_SWITCH) return; gswitch *last = as_a (lastg); op = gimple_switch_index (last); - if (!unmodified_parm_or_parm_agg_item (fbi, last, op, &index, &size, &aggpos)) + if (!decompose_param_expr (fbi, last, op, &index, &size, &aggpos, + ¶m_ops)) return; FOR_EACH_EDGE (e, ei, bb->succs) @@ -1312,19 +1424,20 @@ set_switch_stmt_execution_predicate (struct ipa_func_body_info *fbi, p = true; else if (!max) p = add_condition (summary, index, size, &aggpos, EQ_EXPR, - unshare_expr_without_location (min)); + min, param_ops); else { predicate p1, p2; p1 = add_condition (summary, index, size, &aggpos, GE_EXPR, - unshare_expr_without_location (min)); + min, param_ops); p2 = add_condition (summary, index, size, &aggpos, LE_EXPR, - unshare_expr_without_location (max)); + max, param_ops); p = p1 & p2; } *(class predicate *) e->aux = p.or_with (summary->conds, *(class predicate *) e->aux); } + vec_free (param_ops); } @@ -1491,7 +1604,7 @@ will_be_nonconstant_predicate (struct ipa_func_body_info *fbi, HOST_WIDE_INT size; struct agg_position_info aggpos; - /* What statments might be optimized away + /* What statements might be optimized away when their arguments are constant. */ if (gimple_code (stmt) != GIMPLE_ASSIGN && gimple_code (stmt) != GIMPLE_COND @@ -1539,7 +1652,7 @@ will_be_nonconstant_predicate (struct ipa_func_body_info *fbi, if (is_load) op_non_const = add_condition (summary, base_index, size, &aggpos, predicate::changed, - NULL); + NULL_TREE); else op_non_const = false; FOR_EACH_SSA_TREE_OPERAND (use, stmt, iter, SSA_OP_USE) @@ -3333,6 +3446,7 @@ inline_read_section (struct lto_file_decl_data *file_data, const char *data, for (j = 0; j < count2; j++) { struct condition c; + unsigned int k, count3; c.operand_num = streamer_read_uhwi (&ib); c.size = streamer_read_uhwi (&ib); c.code = (enum tree_code) streamer_read_uhwi (&ib); @@ -3342,6 +3456,18 @@ inline_read_section (struct lto_file_decl_data *file_data, const char *data, c.by_ref = bp_unpack_value (&bp, 1); if (c.agg_contents) c.offset = streamer_read_uhwi (&ib); + c.param_ops = NULL; + count3 = streamer_read_uhwi (&ib); + for (k = 0; k < count3; k++) + { + struct expr_eval_op op; + op.code = (enum tree_code) streamer_read_uhwi (&ib); + bp = streamer_read_bitpack (&ib); + op.val_is_rhs = bp_unpack_value (&bp, 1); + op.val = stream_read_tree (&ib, data_in); + op.type = stream_read_tree (&ib, data_in); + vec_safe_push (c.param_ops, op); + } if (info) vec_safe_push (info->conds, c); } @@ -3490,6 +3616,9 @@ ipa_fn_summary_write (void) streamer_write_uhwi (ob, vec_safe_length (info->conds)); for (i = 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_uhwi (ob, c->size); streamer_write_uhwi (ob, c->code); @@ -3500,6 +3629,16 @@ 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 = 0; vec_safe_iterate (c->param_ops, j, &op); j++) + { + streamer_write_uhwi (ob, op->code); + bp = bitpack_create (ob->main_stream); + bp_pack_value (&bp, op->val_is_rhs, 1); + streamer_write_bitpack (&bp); + stream_write_tree (ob, op->val, true); + stream_write_tree (ob, op->type, true); + } } streamer_write_uhwi (ob, vec_safe_length (info->size_time_table)); for (i = 0; vec_safe_iterate (info->size_time_table, i, &e); i++) diff --git a/gcc/ipa-predicate.c b/gcc/ipa-predicate.c index 49622e9cd33..537dd81685f 100644 --- a/gcc/ipa-predicate.c +++ b/gcc/ipa-predicate.c @@ -33,9 +33,35 @@ 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" +/* 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 () != ops2->length ()) + return false; + + for (unsigned i = 0; i < ops1->length (); i++) + { + expr_eval_op &op1 = (*ops1)[i]; + expr_eval_op &op2 = (*ops2)[i]; + + if (op1.code != op2.code + || op1.val_is_rhs != op2.val_is_rhs + || !vrp_operand_equal_p (op1.val, op2.val) + || 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 +136,13 @@ predicate::add_clause (conditions conditions, clause_t new_clause) for (c2 = c1 + 1; c2 < num_conditions; c2++) if (new_clause & (1 << c2)) { - condition *cc1 = - &(*conditions)[c1 - predicate::first_dynamic_condition]; condition *cc2 = &(*conditions)[c2 - predicate::first_dynamic_condition]; if (cc1->operand_num == cc2->operand_num - && cc1->val == cc2->val + && vrp_operand_equal_p (cc1->val, cc2->val) && cc2->code != is_not_constant - && cc2->code != predicate::changed + && cc2->code != changed + && expr_eval_ops_equal_p (cc1->param_ops, cc2->param_ops) && cc1->code == invert_tree_comparison (cc2->code, HONOR_NANS (cc1->val))) return; @@ -300,6 +325,46 @@ dump_condition (FILE *f, conditions conditions, int cond) if (c->agg_contents) fprintf (f, "[%soffset: " HOST_WIDE_INT_PRINT_DEC "]", c->by_ref ? "ref " : "", c->offset); + + for (unsigned i = 1; i < vec_safe_length (c->param_ops); i++) + { + expr_eval_op &op = (*(c->param_ops))[i]; + const char *op_name = op_symbol_code (op.code); + + if (op_name == op_symbol_code (ERROR_MARK)) + op_name = get_tree_code_name (op.code); + + fprintf (f, ":("); + + if (!op.val) + { + switch (op.code) + { + case VIEW_CONVERT_EXPR: + CASE_CONVERT: + fprintf (f, "("); + print_generic_expr (f, op.type); + fprintf (f, ")" ); + break; + + default: + fprintf (f, "%s ", op_name); + } + fprintf (f, "@%u", i); + } + else if (op.val_is_rhs) + { + fprintf (f, "@%u %s ", i, op_name); + print_generic_expr (f, op.val); + } + else + { + print_generic_expr (f, op.val); + fprintf (f, " %s @%u", op_name, i); + } + fprintf (f, ")"); + } + if (c->code == predicate::is_not_constant) { fprintf (f, " not constant"); @@ -338,8 +403,8 @@ dump_clause (FILE *f, conditions conds, clause_t clause) } -/* Dump THIS to F. CONDS a vector of conditions used when evauating - predicats. When NL is true new line is output at the end of dump. */ +/* Dump THIS to F. CONDS a vector of conditions used when evaluating + predicates. When NL is true new line is output at the end of dump. */ void predicate::dump (FILE *f, conditions conds, bool nl) const @@ -389,7 +454,7 @@ predicate::remap_after_duplication (clause_t possible_truths) INFO is ipa_fn_summary of function we are adding predicate into, CALLEE_INFO is summary of function predicate P is from. OPERAND_MAP is array giving - callee formal IDs the caller formal IDs. POSSSIBLE_TRUTHS is clausule of all + callee formal IDs the caller formal IDs. POSSSIBLE_TRUTHS is clause of all callee conditions that may be true in caller context. TOPLEV_PREDICATE is predicate under which callee is executed. OFFSET_MAP is an array of of offsets that need to be added to conditions, negative offset means that @@ -463,7 +528,7 @@ predicate::remap_after_inlining (class ipa_fn_summary *info, cond_predicate = add_condition (info, operand_map[c->operand_num], c->size, &ap, c->code, - c->val); + c->val, c->param_ops); } } /* Fixed conditions remains same, construct single @@ -516,21 +581,23 @@ predicate::stream_out (struct output_block *ob) } -/* 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, SIZE, 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. */ predicate add_condition (class ipa_fn_summary *summary, int operand_num, HOST_WIDE_INT size, struct agg_position_info *aggpos, - enum tree_code code, tree val) + 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; if (aggpos) { @@ -551,8 +618,9 @@ add_condition (class ipa_fn_summary *summary, int operand_num, if (c->operand_num == operand_num && c->size == size && c->code == code - && c->val == val + && vrp_operand_equal_p (c->val, val) && c->agg_contents == agg_contents + && expr_eval_ops_equal_p (c->param_ops, param_ops) && (!agg_contents || (c->offset == offset && c->by_ref == by_ref))) return predicate::predicate_testing_cond (i); } @@ -562,11 +630,17 @@ add_condition (class ipa_fn_summary *summary, int operand_num, new_cond.operand_num = operand_num; new_cond.code = code; - new_cond.val = val; + new_cond.val = val ? unshare_expr_without_location (val) : val; new_cond.agg_contents = agg_contents; new_cond.by_ref = by_ref; new_cond.offset = offset; new_cond.size = size; + new_cond.param_ops = vec_safe_copy (param_ops); + + for (j = 0; vec_safe_iterate (new_cond.param_ops, j, &op); j++) + if (op->val) + op->val = unshare_expr_without_location (op->val); + vec_safe_push (summary->conds, new_cond); return predicate::predicate_testing_cond (i); diff --git a/gcc/ipa-predicate.h b/gcc/ipa-predicate.h index c2adba30551..f00a64f3a59 100644 --- a/gcc/ipa-predicate.h +++ b/gcc/ipa-predicate.h @@ -22,8 +22,28 @@ along with GCC; see the file COPYING3. If not see inlined into (i.e. known constant values of function parameters. Conditions that are interesting for function body are collected into CONDS - 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 only + once, and other operands are IPA invariant. The conditions are then + referred by predicates. */ + + +/* A simplified representation of tree node, only for unary and binary + operation. A tree expression is flattened to a vector of this kind + of structure. */ +struct GTY(()) expr_eval_op +{ + /* Operation code of expression. */ + ENUM_BITFIELD(tree_code) code : 16; + /* For binary expression, the below constant operand is rhs or lhs. */ + unsigned val_is_rhs : 1; + /* For binary expression, this is a constant value. */ + tree val; + /* Result type of expression. */ + tree type; +}; + +typedef vec *expr_eval_ops; struct GTY(()) condition { @@ -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 sequential operations on the parameter, which can be seen as + a mathmatical function on the parameter. */ + expr_eval_ops param_ops; }; /* Information kept about parameter of call site. */ @@ -58,7 +81,7 @@ struct inline_param_summary typedef vec *conditions; -/* Predicates are used to repesent function parameters (such as runtime) +/* Predicates are used to represent function parameters (such as runtime) which depend on a context function is called in. Predicates are logical formulas in conjunctive-disjunctive form consisting @@ -229,4 +252,5 @@ private: void dump_condition (FILE *f, conditions conditions, int cond); predicate add_condition (class ipa_fn_summary *summary, int operand_num, HOST_WIDE_INT size, struct agg_position_info *aggpos, - enum tree_code code, tree val); + enum tree_code code, tree val, + expr_eval_ops param_ops = NULL); diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 6c40496db9c..39886498305 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,8 @@ +2019-07-12 Feng Xue + + PR ipa/91088 + * gcc.dg/ipa/pr91088.c: New test. + 2019-07-11 Sunil K Pandey PR target/90980 diff --git a/gcc/testsuite/gcc.dg/ipa/pr91088.c b/gcc/testsuite/gcc.dg/ipa/pr91088.c new file mode 100644 index 00000000000..1cbf0d2fa23 --- /dev/null +++ b/gcc/testsuite/gcc.dg/ipa/pr91088.c @@ -0,0 +1,29 @@ +/* { dg-do compile } */ +/* { dg-options "-O3 -fdump-ipa-cp-details -fdump-ipa-fnsummary-details -fno-inline" } */ + +int foo(); + +int callee(int v) +{ + if ((27 % ((1 - v) * 3)) < 6) + { + foo(); + foo(); + foo(); + foo(); + foo(); + foo(); + foo(); + foo(); + foo(); + } + else + return 1; +} + +int caller() +{ + return callee (-5); +} + +/* { dg-final { scan-ipa-dump "Creating a specialized node of callee" "cp" } } */