From patchwork Wed Nov 10 12:44:47 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Richard Sandiford X-Patchwork-Id: 47400 Return-Path: X-Original-To: patchwork@sourceware.org Delivered-To: patchwork@sourceware.org Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 0CE003857814 for ; Wed, 10 Nov 2021 12:45:58 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 0CE003857814 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gcc.gnu.org; s=default; t=1636548358; bh=Nb6Foz3zRcY+F8LVC+uGQwZ3Rly+zoMJCp+a38TFHLs=; h=To:Subject:Date:List-Id:List-Unsubscribe:List-Archive:List-Post: List-Help:List-Subscribe:From:Reply-To:From; b=RMd6U5BjePh2Z/3RNf7mzYsE8XHaXPsd1LvhyNXlz3bqji1oiXSkR4wd11tB0jrGi DLOkNTAZIBrc4OZ5msHUiVytblAwrIb8P4S5aSBFBiBPGrW5THI5SPALhaMY7xeqbZ 3n47jeDFmW8pYd+zpoVyvl8b+1uxwzlx2qkBcrJw= X-Original-To: gcc-patches@gcc.gnu.org Delivered-To: gcc-patches@gcc.gnu.org Received: from foss.arm.com (foss.arm.com [217.140.110.172]) by sourceware.org (Postfix) with ESMTP id 4721E3858032 for ; Wed, 10 Nov 2021 12:44:49 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.1 sourceware.org 4721E3858032 Received: from usa-sjc-imap-foss1.foss.arm.com (unknown [10.121.207.14]) by usa-sjc-mx-foss1.foss.arm.com (Postfix) with ESMTP id EB39A101E for ; Wed, 10 Nov 2021 04:44:48 -0800 (PST) Received: from localhost (unknown [10.32.98.88]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPSA id 91B753F5A1 for ; Wed, 10 Nov 2021 04:44:48 -0800 (PST) To: gcc-patches@gcc.gnu.org Mail-Followup-To: gcc-patches@gcc.gnu.org, richard.sandiford@arm.com Subject: [PATCH 2/5] gimple-match: Add a gimple_extract_op function Date: Wed, 10 Nov 2021 12:44:47 +0000 Message-ID: User-Agent: Gnus/5.13 (Gnus v5.13) Emacs/26.3 (gnu/linux) MIME-Version: 1.0 X-Spam-Status: No, score=-12.4 required=5.0 tests=BAYES_00, GIT_PATCH_0, KAM_DMARC_STATUS, SPF_HELO_NONE, SPF_PASS, TXREP autolearn=ham autolearn_force=no version=3.4.4 X-Spam-Checker-Version: SpamAssassin 3.4.4 (2020-01-24) on server2.sourceware.org X-BeenThere: gcc-patches@gcc.gnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Gcc-patches mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-Patchwork-Original-From: Richard Sandiford via Gcc-patches From: Richard Sandiford Reply-To: Richard Sandiford Errors-To: gcc-patches-bounces+patchwork=sourceware.org@gcc.gnu.org Sender: "Gcc-patches" code_helper and gimple_match_op seem like generally useful ways of summing up a gimple_assign or gimple_call (or gimple_cond). This patch adds a gimple_extract_op function that can be used for that. Tested on aarch64-linux-gnu and x86_64-linux-gnu. OK to install? Richard gcc/ * gimple-match.h (gimple_extract_op): Declare. * gimple-match.c (gimple_extract): New function, extracted from... (gimple_simplify): ...here. (gimple_extract_op): New function. --- gcc/gimple-match-head.c | 261 +++++++++++++++++++++++----------------- gcc/gimple-match.h | 1 + 2 files changed, 149 insertions(+), 113 deletions(-) diff --git a/gcc/gimple-match-head.c b/gcc/gimple-match-head.c index 9d88b2f8551..4c6e0883ba4 100644 --- a/gcc/gimple-match-head.c +++ b/gcc/gimple-match-head.c @@ -890,12 +890,29 @@ try_conditional_simplification (internal_fn ifn, gimple_match_op *res_op, return true; } -/* The main STMT based simplification entry. It is used by the fold_stmt - and the fold_stmt_to_constant APIs. */ +/* Common subroutine of gimple_extract_op and gimple_simplify. Try to + describe STMT in RES_OP. Return: -bool -gimple_simplify (gimple *stmt, gimple_match_op *res_op, gimple_seq *seq, - tree (*valueize)(tree), tree (*top_valueize)(tree)) + - -1 if extraction failed + - otherwise, 0 if no simplification should take place + - otherwise, the number of operands for a GIMPLE_ASSIGN or GIMPLE_COND + - otherwise, -2 for a GIMPLE_CALL + + Before recording an operand, call: + + - VALUEIZE_CONDITION for a COND_EXPR condition + - VALUEIZE_NAME if the rhs of a GIMPLE_ASSIGN is an SSA_NAME + - VALUEIZE_OP for every other top-level operand + + Each routine takes a tree argument and returns a tree. */ + +template +inline int +gimple_extract (gimple *stmt, gimple_match_op *res_op, + ValueizeOp valueize_op, + ValueizeCondition valueize_condition, + ValueizeName valueize_name) { switch (gimple_code (stmt)) { @@ -911,100 +928,53 @@ gimple_simplify (gimple *stmt, gimple_match_op *res_op, gimple_seq *seq, || code == VIEW_CONVERT_EXPR) { tree op0 = TREE_OPERAND (gimple_assign_rhs1 (stmt), 0); - bool valueized = false; - op0 = do_valueize (op0, top_valueize, valueized); - res_op->set_op (code, type, op0); - return (gimple_resimplify1 (seq, res_op, valueize) - || valueized); + res_op->set_op (code, type, valueize_op (op0)); + return 1; } else if (code == BIT_FIELD_REF) { tree rhs1 = gimple_assign_rhs1 (stmt); - tree op0 = TREE_OPERAND (rhs1, 0); - bool valueized = false; - op0 = do_valueize (op0, top_valueize, valueized); + tree op0 = valueize_op (TREE_OPERAND (rhs1, 0)); res_op->set_op (code, type, op0, TREE_OPERAND (rhs1, 1), TREE_OPERAND (rhs1, 2), REF_REVERSE_STORAGE_ORDER (rhs1)); - if (res_op->reverse) - return valueized; - return (gimple_resimplify3 (seq, res_op, valueize) - || valueized); + return res_op->reverse ? 0 : 3; } - else if (code == SSA_NAME - && top_valueize) + else if (code == SSA_NAME) { tree op0 = gimple_assign_rhs1 (stmt); - tree valueized = top_valueize (op0); + tree valueized = valueize_name (op0); if (!valueized || op0 == valueized) - return false; + return -1; res_op->set_op (TREE_CODE (op0), type, valueized); - return true; + return 0; } break; case GIMPLE_UNARY_RHS: { tree rhs1 = gimple_assign_rhs1 (stmt); - bool valueized = false; - rhs1 = do_valueize (rhs1, top_valueize, valueized); - res_op->set_op (code, type, rhs1); - return (gimple_resimplify1 (seq, res_op, valueize) - || valueized); + res_op->set_op (code, type, valueize_op (rhs1)); + return 1; } case GIMPLE_BINARY_RHS: { - tree rhs1 = gimple_assign_rhs1 (stmt); - tree rhs2 = gimple_assign_rhs2 (stmt); - bool valueized = false; - rhs1 = do_valueize (rhs1, top_valueize, valueized); - rhs2 = do_valueize (rhs2, top_valueize, valueized); + tree rhs1 = valueize_op (gimple_assign_rhs1 (stmt)); + tree rhs2 = valueize_op (gimple_assign_rhs2 (stmt)); res_op->set_op (code, type, rhs1, rhs2); - return (gimple_resimplify2 (seq, res_op, valueize) - || valueized); + return 2; } case GIMPLE_TERNARY_RHS: { - bool valueized = false; tree rhs1 = gimple_assign_rhs1 (stmt); - /* If this is a COND_EXPR first try to simplify an - embedded GENERIC condition. */ - if (code == COND_EXPR) - { - if (COMPARISON_CLASS_P (rhs1)) - { - tree lhs = TREE_OPERAND (rhs1, 0); - tree rhs = TREE_OPERAND (rhs1, 1); - lhs = do_valueize (lhs, top_valueize, valueized); - rhs = do_valueize (rhs, top_valueize, valueized); - gimple_match_op res_op2 (res_op->cond, TREE_CODE (rhs1), - TREE_TYPE (rhs1), lhs, rhs); - if ((gimple_resimplify2 (seq, &res_op2, valueize) - || valueized) - && res_op2.code.is_tree_code ()) - { - valueized = true; - if (TREE_CODE_CLASS ((enum tree_code) res_op2.code) - == tcc_comparison) - rhs1 = build2 (res_op2.code, TREE_TYPE (rhs1), - res_op2.ops[0], res_op2.ops[1]); - else if (res_op2.code == SSA_NAME - || res_op2.code == INTEGER_CST - || res_op2.code == VECTOR_CST) - rhs1 = res_op2.ops[0]; - else - valueized = false; - } - } - } - tree rhs2 = gimple_assign_rhs2 (stmt); - tree rhs3 = gimple_assign_rhs3 (stmt); - rhs1 = do_valueize (rhs1, top_valueize, valueized); - rhs2 = do_valueize (rhs2, top_valueize, valueized); - rhs3 = do_valueize (rhs3, top_valueize, valueized); + if (code == COND_EXPR && COMPARISON_CLASS_P (rhs1)) + rhs1 = valueize_condition (rhs1); + else + rhs1 = valueize_op (rhs1); + tree rhs2 = valueize_op (gimple_assign_rhs2 (stmt)); + tree rhs3 = valueize_op (gimple_assign_rhs3 (stmt)); res_op->set_op (code, type, rhs1, rhs2, rhs3); - return (gimple_resimplify3 (seq, res_op, valueize) - || valueized); + return 3; } default: gcc_unreachable (); @@ -1018,7 +988,6 @@ gimple_simplify (gimple *stmt, gimple_match_op *res_op, gimple_seq *seq, && gimple_call_num_args (stmt) >= 1 && gimple_call_num_args (stmt) <= 5) { - bool valueized = false; combined_fn cfn; if (gimple_call_internal_p (stmt)) cfn = as_combined_fn (gimple_call_internal_fn (stmt)); @@ -1026,17 +995,17 @@ gimple_simplify (gimple *stmt, gimple_match_op *res_op, gimple_seq *seq, { tree fn = gimple_call_fn (stmt); if (!fn) - return false; + return -1; - fn = do_valueize (fn, top_valueize, valueized); + fn = valueize_op (fn); if (TREE_CODE (fn) != ADDR_EXPR || TREE_CODE (TREE_OPERAND (fn, 0)) != FUNCTION_DECL) - return false; + return -1; tree decl = TREE_OPERAND (fn, 0); if (DECL_BUILT_IN_CLASS (decl) != BUILT_IN_NORMAL || !gimple_builtin_call_types_compatible_p (stmt, decl)) - return false; + return -1; cfn = as_combined_fn (DECL_FUNCTION_CODE (decl)); } @@ -1044,56 +1013,122 @@ gimple_simplify (gimple *stmt, gimple_match_op *res_op, gimple_seq *seq, unsigned int num_args = gimple_call_num_args (stmt); res_op->set_op (cfn, TREE_TYPE (gimple_call_lhs (stmt)), num_args); for (unsigned i = 0; i < num_args; ++i) - { - tree arg = gimple_call_arg (stmt, i); - res_op->ops[i] = do_valueize (arg, top_valueize, valueized); - } - if (internal_fn_p (cfn) - && try_conditional_simplification (as_internal_fn (cfn), - res_op, seq, valueize)) - return true; - switch (num_args) - { - case 1: - return (gimple_resimplify1 (seq, res_op, valueize) - || valueized); - case 2: - return (gimple_resimplify2 (seq, res_op, valueize) - || valueized); - case 3: - return (gimple_resimplify3 (seq, res_op, valueize) - || valueized); - case 4: - return (gimple_resimplify4 (seq, res_op, valueize) - || valueized); - case 5: - return (gimple_resimplify5 (seq, res_op, valueize) - || valueized); - default: - gcc_unreachable (); - } + res_op->ops[i] = valueize_op (gimple_call_arg (stmt, i)); + return -2; } break; case GIMPLE_COND: { - tree lhs = gimple_cond_lhs (stmt); - tree rhs = gimple_cond_rhs (stmt); - bool valueized = false; - lhs = do_valueize (lhs, top_valueize, valueized); - rhs = do_valueize (rhs, top_valueize, valueized); + tree lhs = valueize_op (gimple_cond_lhs (stmt)); + tree rhs = valueize_op (gimple_cond_rhs (stmt)); res_op->set_op (gimple_cond_code (stmt), boolean_type_node, lhs, rhs); - return (gimple_resimplify2 (seq, res_op, valueize) - || valueized); + return 2; } default: break; } - return false; + return -1; } +/* Try to describe STMT in RES_OP, returning true on success. + For GIMPLE_CONDs, describe the condition that is being tested. + For GIMPLE_ASSIGNs, describe the rhs of the assignment. + For GIMPLE_CALLs, describe the call. */ + +bool +gimple_extract_op (gimple *stmt, gimple_match_op *res_op) +{ + auto nop = [](tree op) { return op; }; + return gimple_extract (stmt, res_op, nop, nop, nop) != -1; +} + +/* The main STMT based simplification entry. It is used by the fold_stmt + and the fold_stmt_to_constant APIs. */ + +bool +gimple_simplify (gimple *stmt, gimple_match_op *res_op, gimple_seq *seq, + tree (*valueize)(tree), tree (*top_valueize)(tree)) +{ + bool valueized = false; + auto valueize_op = [&](tree op) + { + return do_valueize (op, top_valueize, valueized); + }; + auto valueize_condition = [&](tree op) -> tree + { + bool cond_valueized = false; + tree lhs = do_valueize (TREE_OPERAND (op, 0), top_valueize, + cond_valueized); + tree rhs = do_valueize (TREE_OPERAND (op, 1), top_valueize, + cond_valueized); + gimple_match_op res_op2 (res_op->cond, TREE_CODE (op), + TREE_TYPE (op), lhs, rhs); + if ((gimple_resimplify2 (seq, &res_op2, valueize) + || cond_valueized) + && res_op2.code.is_tree_code ()) + { + if (TREE_CODE_CLASS ((tree_code) res_op2.code) == tcc_comparison) + { + valueized = true; + return build2 (res_op2.code, TREE_TYPE (op), + res_op2.ops[0], res_op2.ops[1]); + } + else if (res_op2.code == SSA_NAME + || res_op2.code == INTEGER_CST + || res_op2.code == VECTOR_CST) + { + valueized = true; + return res_op2.ops[0]; + } + } + return valueize_op (op); + }; + auto valueize_name = [&](tree op) + { + return top_valueize ? top_valueize (op) : op; + }; + + int res = gimple_extract (stmt, res_op, valueize_op, valueize_condition, + valueize_name); + if (res == -1) + return false; + + if (res == -2) + { + combined_fn cfn = combined_fn (res_op->code); + if (internal_fn_p (cfn) + && try_conditional_simplification (as_internal_fn (cfn), + res_op, seq, valueize)) + return true; + res = res_op->num_ops; + } + + switch (res) + { + case 0: + return valueized; + case 1: + return (gimple_resimplify1 (seq, res_op, valueize) + || valueized); + case 2: + return (gimple_resimplify2 (seq, res_op, valueize) + || valueized); + case 3: + return (gimple_resimplify3 (seq, res_op, valueize) + || valueized); + case 4: + return (gimple_resimplify4 (seq, res_op, valueize) + || valueized); + case 5: + return (gimple_resimplify5 (seq, res_op, valueize) + || valueized); + default: + gcc_unreachable (); + } +} /* Helper for the autogenerated code, valueize OP. */ diff --git a/gcc/gimple-match.h b/gcc/gimple-match.h index 2d4ea476076..15a0f584db7 100644 --- a/gcc/gimple-match.h +++ b/gcc/gimple-match.h @@ -333,6 +333,7 @@ gimple_simplified_result_is_gimple_val (const gimple_match_op *op) extern tree (*mprts_hook) (gimple_match_op *); +bool gimple_extract_op (gimple *, gimple_match_op *); bool gimple_simplify (gimple *, gimple_match_op *, gimple_seq *, tree (*)(tree), tree (*)(tree)); tree maybe_push_res_to_seq (gimple_match_op *, gimple_seq *,