From patchwork Fri Nov 10 07:09:02 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ajit Agarwal X-Patchwork-Id: 1862350 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@legolas.ozlabs.org Authentication-Results: legolas.ozlabs.org; dkim=pass (2048-bit key; unprotected) header.d=ibm.com header.i=@ibm.com header.a=rsa-sha256 header.s=pp1 header.b=eeoscsaC; dkim-atps=neutral Authentication-Results: legolas.ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=gcc.gnu.org (client-ip=2620:52:3:1:0:246e:9693:128c; helo=server2.sourceware.org; envelope-from=gcc-patches-bounces+incoming=patchwork.ozlabs.org@gcc.gnu.org; receiver=patchwork.ozlabs.org) Received: from server2.sourceware.org (server2.sourceware.org [IPv6:2620:52:3:1:0:246e:9693:128c]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (secp384r1) server-digest SHA384) (No client certificate requested) by legolas.ozlabs.org (Postfix) with ESMTPS id 4SRVPC5JdGz1yRF for ; Fri, 10 Nov 2023 18:11:43 +1100 (AEDT) Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 464A73857359 for ; Fri, 10 Nov 2023 07:11:39 +0000 (GMT) X-Original-To: gcc-patches@gcc.gnu.org Delivered-To: gcc-patches@gcc.gnu.org Received: from mx0a-001b2d01.pphosted.com (mx0a-001b2d01.pphosted.com [148.163.156.1]) by sourceware.org (Postfix) with ESMTPS id 7D2D53858C2B for ; Fri, 10 Nov 2023 07:11:24 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 7D2D53858C2B Authentication-Results: sourceware.org; dmarc=none (p=none dis=none) header.from=linux.ibm.com Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=linux.ibm.com ARC-Filter: OpenARC Filter v1.0.0 sourceware.org 7D2D53858C2B Authentication-Results: server2.sourceware.org; arc=none smtp.remote-ip=148.163.156.1 ARC-Seal: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1699600288; cv=none; b=kr9Nm+C9pxYh1UsHwoOU8YOhvkDeAfgyqvTj1NRvqmLOyU+KFTK/3joyg/1BT0bNb2Z2c+3uLQY4E6rlnl8PpLKwgpcpGcTsfNEm8EhYvW0MuD0hzD8PT7bkFlHwY6ieQBBMZ4bHETI6HaRLN1a33CwamgQ4P/TFZX/wEDyt38A= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1699600288; c=relaxed/simple; bh=LVoexCZNXXCjDiBq83vD/djb2uJjA3hblhCjEkPHT+4=; h=DKIM-Signature:Message-ID:Date:MIME-Version:Subject:To:From; b=kIitHJ15cnYWu3VoRCJs+GH1RV3DhmLtzyWJYsCWpkmI87VhW6SgJ1gxsNR/+HuRuAh9VThoyzoxJep0fd/YvTthCDJiRrO/1G/CTEFqepmquSZRi/IwS/vN3cJSWMSrHRIhB90uzztrP7QBVDROLmLYwMT2ZveFCZyoqLKuutA= ARC-Authentication-Results: i=1; server2.sourceware.org Received: from pps.filterd (m0353729.ppops.net [127.0.0.1]) by mx0a-001b2d01.pphosted.com (8.17.1.19/8.17.1.19) with ESMTP id 3AA6kRSR007220; Fri, 10 Nov 2023 07:11:23 GMT DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=ibm.com; h=message-id : date : mime-version : subject : references : to : cc : from : in-reply-to : content-type : content-transfer-encoding; s=pp1; bh=k8k28LMwEYrBGvTP/NGk4bNb3cS6l10lKpo+Gss2h6g=; b=eeoscsaCHPg4SUJaX6ZsZBbjLnbzxglw2vuuKAHDNFp5oTK1TRcJmuQNhFgpYvzyiumK zyJ/YZOisMGO3xUGY19Eup6RvPpTtzPk3xT64crb9oD+m0Er0BpxZKYnOExClvJURXxy ZlRftKg2WzIqtW5Xn8Y0em4HBGeO/7bUYTdcTvaZsytNDAYIeznqBJ+Oo7s12iIEHwTA Kt34bubq/UhAhxHzuD7PphnJg421+cpiMA/ygjg6/HvPO+9IqvdTt+KONKB2C+OxECBu AplvsXuVjqZR6qJ9iHmmaRjdT4c6ovvnxvmiuPpbWpC0JlNDxpEoOWWan3/jTW/Y/0v8 Pw== Received: from pps.reinject (localhost [127.0.0.1]) by mx0a-001b2d01.pphosted.com (PPS) with ESMTPS id 3u9f4ht1jk-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Fri, 10 Nov 2023 07:11:20 +0000 Received: from m0353729.ppops.net (m0353729.ppops.net [127.0.0.1]) by pps.reinject (8.17.1.5/8.17.1.5) with ESMTP id 3AA6kYuW008644; Fri, 10 Nov 2023 07:09:59 GMT Received: from ppma23.wdc07v.mail.ibm.com (5d.69.3da9.ip4.static.sl-reverse.com [169.61.105.93]) by mx0a-001b2d01.pphosted.com (PPS) with ESMTPS id 3u9f4hswxr-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Fri, 10 Nov 2023 07:09:57 +0000 Received: from pps.filterd (ppma23.wdc07v.mail.ibm.com [127.0.0.1]) by ppma23.wdc07v.mail.ibm.com (8.17.1.19/8.17.1.19) with ESMTP id 3AA43P3G014309; Fri, 10 Nov 2023 07:09:06 GMT Received: from smtprelay06.wdc07v.mail.ibm.com ([172.16.1.73]) by ppma23.wdc07v.mail.ibm.com (PPS) with ESMTPS id 3u7w229a4h-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Fri, 10 Nov 2023 07:09:06 +0000 Received: from smtpav05.dal12v.mail.ibm.com (smtpav05.dal12v.mail.ibm.com [10.241.53.104]) by smtprelay06.wdc07v.mail.ibm.com (8.14.9/8.14.9/NCO v10.0) with ESMTP id 3AA796ET15467034 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-GCM-SHA384 bits=256 verify=OK); Fri, 10 Nov 2023 07:09:06 GMT Received: from smtpav05.dal12v.mail.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id F1A3558052; Fri, 10 Nov 2023 07:09:05 +0000 (GMT) Received: from smtpav05.dal12v.mail.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id 154AD5806D; Fri, 10 Nov 2023 07:09:03 +0000 (GMT) Received: from [9.43.64.36] (unknown [9.43.64.36]) by smtpav05.dal12v.mail.ibm.com (Postfix) with ESMTP; Fri, 10 Nov 2023 07:09:02 +0000 (GMT) Message-ID: <6c3e359d-d8f8-4267-af0e-5b144687ef94@linux.ibm.com> Date: Fri, 10 Nov 2023 12:39:02 +0530 MIME-Version: 1.0 User-Agent: Mozilla Thunderbird Subject: [PING ^1] [PATCH v2 3/4] Improve functionality of ree pass with various constants with AND operation. Content-Language: en-US References: <10b5f1a3-4f89-4b59-b4a1-b7fdebbf9149@linux.ibm.com> To: gcc-patches Cc: Jeff Law , Vineet Gupta , Richard Biener , Segher Boessenkool , Peter Bergner From: Ajit Agarwal In-Reply-To: <10b5f1a3-4f89-4b59-b4a1-b7fdebbf9149@linux.ibm.com> X-Forwarded-Message-Id: <10b5f1a3-4f89-4b59-b4a1-b7fdebbf9149@linux.ibm.com> X-TM-AS-GCONF: 00 X-Proofpoint-ORIG-GUID: MWGnlJubypG1rpQqTK_rVRKLBD8i-kan X-Proofpoint-GUID: gchGGB7VPtvAFNd8WsdKe1pcZ-Slt6ij X-Proofpoint-Virus-Version: vendor=baseguard engine=ICAP:2.0.272,Aquarius:18.0.987,Hydra:6.0.619,FMLib:17.11.176.26 definitions=2023-11-10_03,2023-11-09_01,2023-05-22_02 X-Proofpoint-Spam-Details: rule=outbound_notspam policy=outbound score=0 priorityscore=1501 lowpriorityscore=0 mlxlogscore=999 phishscore=0 adultscore=0 clxscore=1015 bulkscore=0 spamscore=0 impostorscore=0 mlxscore=0 malwarescore=0 suspectscore=0 classifier=spam adjust=0 reason=mlx scancount=1 engine=8.12.0-2311060000 definitions=main-2311100059 X-Spam-Status: No, score=-12.7 required=5.0 tests=BAYES_00, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_EF, GIT_PATCH_0, RCVD_IN_MSPIKE_H4, RCVD_IN_MSPIKE_WL, SPF_HELO_NONE, SPF_PASS, TXREP, T_SCC_BODY_TEXT_LINE autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on server2.sourceware.org X-BeenThere: gcc-patches@gcc.gnu.org X-Mailman-Version: 2.1.30 Precedence: list List-Id: Gcc-patches mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: gcc-patches-bounces+incoming=patchwork.ozlabs.org@gcc.gnu.org ping! -------- Forwarded Message -------- Subject: [PING ^0] [PATCH v2 3/4] Improve functionality of ree pass with various constants with AND operation. Date: Sun, 15 Oct 2023 18:28:51 +0530 From: Ajit Agarwal To: gcc-patches CC: Jeff Law , Vineet Gupta , Richard Biener , Segher Boessenkool , Peter Bergner , Kewen.Lin Hello All: Please review. In this patch I have different modes and constants that are supported in ree pass for sign and zero extension eliminations. Please review and update with your comments so that it will be committed in trunk. Thanks & Regards Ajit -------- Forwarded Message -------- Subject: [PATCH v2 3/4] Improve functionality of ree pass with various constants with AND operation. Date: Tue, 19 Sep 2023 14:51:16 +0530 From: Ajit Agarwal To: gcc-patches CC: Jeff Law , Vineet Gupta , Richard Biener , Peter Bergner , Segher Boessenkool Hello Jeff: This patch eliminates redundant zero and sign extension with ree pass for rs6000 target. Bootstrapped and regtested for powerpc64-linux-gnu. Thanks & Regards Ajit ree: Improve ree pass For rs6000 target we see redundant zero and sign extension and ree pass s improved to eliminate such redundant zero and sign extension. Support of zero_extend/sign_extend/AND. 2023-09-04 Ajit Kumar Agarwal gcc/ChangeLog: * ree.cc (eliminate_across_bbs_p): Add checks to enable extension elimination across and within basic blocks. (def_arith_p): New function to check definition has arithmetic operation. (combine_set_extension): Modification to incorporate AND and current zero_extend and sign_extend instruction. (merge_def_and_ext): Add calls to eliminate_across_bbs_p and zero_extend sign_extend and AND instruction. (rtx_is_zext_p): New function. (feasible_cfg): New function. * rtl.h (reg_used_set_between_p): Add prototype. * rtlanal.cc (reg_used_set_between_p): New function. gcc/testsuite/ChangeLog: * g++.target/powerpc/zext-elim.C: New testcase. * g++.target/powerpc/zext-elim-1.C: New testcase. * g++.target/powerpc/zext-elim-2.C: New testcase. * g++.target/powerpc/sext-elim.C: New testcase. --- gcc/ree.cc | 487 ++++++++++++++++-- gcc/rtl.h | 1 + gcc/rtlanal.cc | 15 + gcc/testsuite/g++.target/powerpc/sext-elim.C | 17 + .../g++.target/powerpc/zext-elim-1.C | 19 + .../g++.target/powerpc/zext-elim-2.C | 11 + gcc/testsuite/g++.target/powerpc/zext-elim.C | 30 ++ 7 files changed, 534 insertions(+), 46 deletions(-) create mode 100644 gcc/testsuite/g++.target/powerpc/sext-elim.C create mode 100644 gcc/testsuite/g++.target/powerpc/zext-elim-1.C create mode 100644 gcc/testsuite/g++.target/powerpc/zext-elim-2.C create mode 100644 gcc/testsuite/g++.target/powerpc/zext-elim.C diff --git a/gcc/ree.cc b/gcc/ree.cc index fc04249fa84..931b9b08821 100644 --- a/gcc/ree.cc +++ b/gcc/ree.cc @@ -253,6 +253,77 @@ struct ext_cand static int max_insn_uid; +/* Return TRUE if OP can be considered a zero extension from one or + more sub-word modes to larger modes up to a full word. + + For example (and:DI (reg) (const_int X)) + + Depending on the value of X could be considered a zero extension + from QI, HI and SI to larger modes up to DImode. */ + +static bool +rtx_is_zext_p (rtx insn) +{ + if (GET_CODE (insn) == AND) + { + rtx set = XEXP (insn, 0); + if (REG_P (set)) + { + rtx src = XEXP (insn, 1); + machine_mode m_mode = GET_MODE (set); + + if (CONST_INT_P (src) + && (INTVAL (src) == 1 + || (m_mode == QImode && INTVAL (src) == 0x7) + || (m_mode == QImode && INTVAL (src) == 0x0000007F) + || (m_mode == HImode && INTVAL (src) == 0x00007FFF) + || (m_mode == SImode && INTVAL (src) == 0x007FFFFF))) + return true; + + } + else + return false; + } + + return false; +} +/* Return TRUE if OP can be considered a zero extension from one or + more sub-word modes to larger modes up to a full word. + + For example (and:DI (reg) (const_int X)) + + Depending on the value of X could be considered a zero extension + from QI, HI and SI to larger modes up to DImode. */ + +static bool +rtx_is_zext_p (rtx_insn *insn) +{ + rtx body = single_set (insn); + + if (GET_CODE (body) == SET && GET_CODE (SET_SRC (body)) == AND) + { + rtx set = XEXP (SET_SRC (body), 0); + + if (REG_P (set) && GET_MODE (SET_DEST (body)) == GET_MODE (set)) + { + rtx src = XEXP (SET_SRC (body), 1); + machine_mode m_mode = GET_MODE (set); + + if (CONST_INT_P (src) + && (INTVAL (src) == 1 + || (m_mode == QImode && INTVAL (src) == 0x7) + || (m_mode == QImode && INTVAL (src) == 0x0000007F) + || (m_mode == HImode && INTVAL (src) == 0x00007FFF) + || (m_mode == SImode && INTVAL (src) == 0x007FFFFF))) + return true; + } + else + return false; + } + + return false; +} + /* Update or remove REG_EQUAL or REG_EQUIV notes for INSN. */ static bool @@ -319,7 +390,7 @@ combine_set_extension (ext_cand *cand, rtx_insn *curr_insn, rtx *orig_set) { rtx orig_src = SET_SRC (*orig_set); machine_mode orig_mode = GET_MODE (SET_DEST (*orig_set)); - rtx new_set; + rtx new_set = NULL_RTX; rtx cand_pat = single_set (cand->insn); /* If the extension's source/destination registers are not the same @@ -359,27 +430,41 @@ combine_set_extension (ext_cand *cand, rtx_insn *curr_insn, rtx *orig_set) else if (GET_CODE (orig_src) == cand->code) { /* Here is a sequence of two extensions. Try to merge them. */ - rtx temp_extension - = gen_rtx_fmt_e (cand->code, cand->mode, XEXP (orig_src, 0)); + rtx temp_extension = NULL_RTX; + if (GET_CODE (SET_SRC (cand_pat)) == AND) + temp_extension + = gen_rtx_AND (cand->mode, XEXP (orig_src, 0), XEXP (orig_src, 1)); + else + temp_extension + = gen_rtx_fmt_e (cand->code, cand->mode, XEXP (orig_src, 0)); rtx simplified_temp_extension = simplify_rtx (temp_extension); if (simplified_temp_extension) temp_extension = simplified_temp_extension; + new_set = gen_rtx_SET (new_reg, temp_extension); } else if (GET_CODE (orig_src) == IF_THEN_ELSE) { /* Only IF_THEN_ELSE of phi-type copies are combined. Otherwise, - in general, IF_THEN_ELSE should not be combined. */ - return false; + in general, IF_THEN_ELSE should not be combined. Relaxed + cases with IF_THEN_ELSE across basic blocls */ + return true; } else { /* This is the normal case. */ - rtx temp_extension + rtx temp_extension = NULL_RTX; + + if (GET_CODE (SET_SRC (cand_pat)) == AND) + temp_extension + = gen_rtx_AND (cand->mode, orig_src, XEXP (SET_SRC (cand_pat), 1)); + else + temp_extension = gen_rtx_fmt_e (cand->code, cand->mode, orig_src); rtx simplified_temp_extension = simplify_rtx (temp_extension); if (simplified_temp_extension) temp_extension = simplified_temp_extension; + new_set = gen_rtx_SET (new_reg, temp_extension); } @@ -468,12 +553,13 @@ get_defs (rtx_insn *insn, rtx reg, vec *dest) FOR_EACH_INSN_USE (use, insn) { if (GET_CODE (DF_REF_REG (use)) == SUBREG) - return NULL; + return NULL; if (REGNO (DF_REF_REG (use)) == REGNO (reg)) break; } - gcc_assert (use != NULL); + if (use == NULL) + return NULL; ref_chain = DF_REF_CHAIN (use); @@ -481,9 +567,9 @@ get_defs (rtx_insn *insn, rtx reg, vec *dest) { /* Problem getting some definition for this instruction. */ if (ref_link->ref == NULL) - return NULL; + return NULL; if (DF_REF_INSN_INFO (ref_link->ref) == NULL) - return NULL; + return NULL; /* As global regs are assumed to be defined at each function call dataflow can report a call_insn as being a definition of REG. But we can't do anything with that in this pass so proceed only @@ -698,6 +784,258 @@ get_sub_rtx (rtx_insn *def_insn) return sub_rtx; } +/* Return TRUE if reaching definition of def_insn source operand + has has arithmetic peration like ASHIFT and LSHIFTRT. If TRUE + don't eliminate sign extension */ + +static bool +def_arith_p (rtx_insn *insn, rtx orig_src) +{ + if (!REG_P (orig_src)) + return true; + + vec *dest = XCNEWVEC (vec, 4); + if (!get_defs (insn, orig_src, dest)) + return false; + + int i; + rtx_insn *def_insn; + bool has_arith = false; + + FOR_EACH_VEC_ELT (*dest, i, def_insn) + { + rtx def_set = single_set (def_insn); + + if (!def_set) + { + has_arith = true; + break; + } + + if (DEBUG_INSN_P (def_insn)) + continue; + + /* Return True for following rtl insn. + set (reg x), (ashift ( ...) + set (reg x), (lshiftrt (....) */ + + if ((GET_CODE (PATTERN (def_insn)) == SET + && (GET_CODE (SET_SRC (def_set)) == ASHIFT + || GET_CODE (SET_SRC (def_set)) == LSHIFTRT))) + { + has_arith = true; + break; + } + + /* Return TRUE for following rtl insn. + set (reg x) , (plus(ashift ( ....) + set (reg x), (plus(lshiftrt (....) */ + + if (GET_CODE (PATTERN (def_insn)) == SET + && (GET_RTX_CLASS (GET_CODE (SET_SRC (def_set))) == RTX_BIN_ARITH + || GET_RTX_CLASS (GET_CODE (SET_SRC (def_set))) == RTX_COMM_ARITH)) + { + rtx src = XEXP (SET_SRC (def_set),0); + + if (GET_CODE (src) == LSHIFTRT + || GET_CODE (src) == ASHIFT) + { + has_arith = true; + break; + } + } + } + XDELETEVEC (dest); + return has_arith; +} + +/* Return TRUE if the cfg has following properties. + bb1 + |\ + | \ + | bb2 + | / + bb3 + + whereas bb1 has IF_THEN_ELSE and bb2 has the definition and bb3 has + zero/sign/AND extensions. */ + +static bool +feasible_cfg (ext_cand *cand, rtx_insn *def_insn) +{ + basic_block bb = BLOCK_FOR_INSN (cand->insn); + edge fallthru_edge; + edge e; + edge_iterator ei; + + FOR_EACH_EDGE (e, ei, bb->preds) + { + rtx_insn *insn = BB_END (e->src) ? PREV_INSN (BB_END (e->src)) : NULL; + + if (insn == NULL) + continue; + + if (DEBUG_INSN_P (insn)) + continue; + + rtx set = single_set (insn); + + /* Block has IF_THEN_ELSE */ + if (insn && set + && GET_CODE (set) == SET && SET_SRC (set) + && GET_CODE (SET_SRC (set)) == IF_THEN_ELSE) + { + if (e->dest == bb) + { + basic_block jump_block = e->dest; + if (jump_block != bb) + return false; + } + else + { + /* def_insn block has single successor and fall through + edge target are the block for cand insn. */ + if (single_succ_p (e->dest)) + { + fallthru_edge = single_succ_edge (e->dest); + if (BB_END (fallthru_edge->dest) + && bb != fallthru_edge->dest) + return false; + } + } + } + } + + /* def_insn block has single successor and fall through + edge target are the block for cand insn. */ + if (single_succ_p (BLOCK_FOR_INSN (def_insn))) + { + fallthru_edge = single_succ_edge (BLOCK_FOR_INSN (def_insn)); + if (BB_END (fallthru_edge->dest) + && bb != fallthru_edge->dest) + return false; + } + else + return false; + + return true; +} + +/* Return TRUE if the candidate extension INSN and def_insn are + feasible for extension elimination. + + Things to consider: + + cfg properties are feasible for extension elimination. + + sign_extend with def insn as PLUS and the reaching definition + of def_insn are not ASHIFT and LSHIFTRT. + + zero_extend with def insn as XOR/IOR and the reachin definition + of def_insn are not ASHIFT and LSHIFTRT. + + The destination register of the extension insn must not be + used or set between the def_insn and cand->insn exclusive. + + AND with zero extension properties has USE and the register + of cand insn are same as register of USE operand. */ + +static bool +eliminate_across_bbs_p (ext_cand *cand, rtx_insn *def_insn) +{ + basic_block bb = BLOCK_FOR_INSN (cand->insn); + + if (!feasible_cfg (cand, def_insn)) + return false; + + rtx cand_set = single_set(cand->insn); + /* The destination register of the extension insn must not be + used or set between the def_insn and cand->insn exclusive. */ + if (INSN_CHAIN_CODE_P (GET_CODE (def_insn)) + && INSN_CHAIN_CODE_P (cand->code)) + if ((cand->code == ZERO_EXTEND) + && REG_P (SET_DEST (cand_set)) && NEXT_INSN (def_insn) + && reg_used_set_between_p(SET_DEST (cand_set), def_insn, cand->insn)) + return false; + + if (cand->code == ZERO_EXTEND + && (bb != BLOCK_FOR_INSN (def_insn) + || DF_INSN_LUID (def_insn) > DF_INSN_LUID (cand->insn))) + return false; + + if (rtx_is_zext_p (cand->insn)) + { + if (GET_CODE (PATTERN (BB_END (bb))) != USE) + return false; + + if (REGNO (XEXP (PATTERN (BB_END (bb)), 0)) != REGNO (SET_DEST (cand->expr))) + return false; + } + + rtx set = single_set (def_insn); + + if (!set) + return false; + + if (cand->code == SIGN_EXTEND + && GET_CODE (set) == SET) + { + rtx orig_src = SET_SRC (set); + machine_mode ext_src_mode; + + ext_src_mode = GET_MODE (XEXP (SET_SRC (cand->expr), 0)); + + if (GET_MODE (SET_DEST (set)) != ext_src_mode) + return false; + + if (GET_CODE (orig_src) != PLUS) + return false; + + if (!REG_P (XEXP (orig_src, 0))) + return false; + + if (!REG_P (XEXP (orig_src,1))) + return false; + + if (GET_CODE (orig_src) == PLUS) + { + bool def_src1 + = def_arith_p (def_insn, + XEXP (SET_SRC (set), 0)); + bool def_src2 + = def_arith_p (def_insn, + XEXP (SET_SRC (set), 1)); + + if (def_src1 || def_src2) + return false; + } + } + + if (cand->code == ZERO_EXTEND + && GET_CODE (set) == SET) + { + if (GET_CODE (SET_SRC (set)) != XOR + && GET_CODE (SET_SRC (set)) != IOR) + return false; + + if (GET_CODE (SET_SRC (set)) == XOR + || GET_CODE (SET_SRC (set)) == IOR) + { + bool def_src1 + = def_arith_p (def_insn, + XEXP (SET_SRC (set), 0)); + bool def_src2 + = def_arith_p (def_insn, + XEXP (SET_SRC (set), 1)); + + if (def_src1 || def_src2) + return false; + } + } + + return true; +} + /* Merge the DEF_INSN with an extension. Calls combine_set_extension on the SET pattern. */ @@ -713,12 +1051,32 @@ merge_def_and_ext (ext_cand *cand, rtx_insn *def_insn, ext_state *state) if (sub_rtx == NULL) return false; - if (GET_MODE (SET_DEST (*sub_rtx)) == ext_src_mode - || ((state->modified[INSN_UID (def_insn)].kind - == (cand->code == ZERO_EXTEND + bool copy_needed + = (REGNO (SET_DEST (cand->expr)) != REGNO (XEXP (SET_SRC (cand->expr), 0))); + + bool feasible = eliminate_across_bbs_p (cand, def_insn); + + if (!feasible) return false; + + /* Combine zero_extend/sign_extend/AND and if sign_extend and + mode of DEST and SRC are different. */ + + bool is_zext = rtx_is_zext_p (cand->insn) + || cand->code == ZERO_EXTEND + || cand->code == SIGN_EXTEND; + + bool do_elimination = !copy_needed + && is_zext + && (cand->code == SIGN_EXTEND + || GET_MODE (SET_DEST (*sub_rtx)) != ext_src_mode); + + if (((do_elimination + && state->modified[INSN_UID (def_insn)].kind == EXT_MODIFIED_NONE)) + || ((state->modified[INSN_UID (def_insn)].kind + == (cand->code == ZERO_EXTEND ? EXT_MODIFIED_ZEXT : EXT_MODIFIED_SEXT)) - && state->modified[INSN_UID (def_insn)].mode - == ext_src_mode)) + && state->modified[INSN_UID (def_insn)].mode + == ext_src_mode)) { if (GET_MODE_UNIT_SIZE (GET_MODE (SET_DEST (*sub_rtx))) >= GET_MODE_UNIT_SIZE (cand->mode)) @@ -734,7 +1092,6 @@ merge_def_and_ext (ext_cand *cand, rtx_insn *def_insn, ext_state *state) return true; } } - return false; } @@ -744,7 +1101,9 @@ merge_def_and_ext (ext_cand *cand, rtx_insn *def_insn, ext_state *state) static inline rtx get_extended_src_reg (rtx src) { - while (GET_CODE (src) == SIGN_EXTEND || GET_CODE (src) == ZERO_EXTEND) + while (GET_CODE (src) == SIGN_EXTEND + || GET_CODE (src) == ZERO_EXTEND + || rtx_is_zext_p (src)) src = XEXP (src, 0); gcc_assert (REG_P (src)); return src; @@ -882,8 +1241,7 @@ combine_reaching_defs (ext_cand *cand, const_rtx set_pat, ext_state *state) /* The destination register of the extension insn must not be used or set between the def_insn and cand->insn exclusive. */ - if (reg_used_between_p (SET_DEST (set), def_insn, cand->insn) - || reg_set_between_p (SET_DEST (set), def_insn, cand->insn)) + if (reg_used_set_between_p (SET_DEST (set), def_insn, cand->insn)) return false; /* We must be able to copy between the two registers. Generate, @@ -975,10 +1333,8 @@ combine_reaching_defs (ext_cand *cand, const_rtx set_pat, ext_state *state) used or set between the def_insn2 and def_insn exclusive. Likewise for the other reg, i.e. check both reg1 and reg2 in the above comment. */ - if (reg_used_between_p (SET_DEST (set), def_insn2, def_insn) - || reg_set_between_p (SET_DEST (set), def_insn2, def_insn) - || reg_used_between_p (src_reg, def_insn2, def_insn) - || reg_set_between_p (src_reg, def_insn2, def_insn)) + if (reg_used_set_between_p (SET_DEST (set), def_insn2, def_insn) + || reg_used_set_between_p (src_reg, def_insn2, def_insn)) break; state->defs_list[0] = def_insn2; @@ -1004,15 +1360,17 @@ combine_reaching_defs (ext_cand *cand, const_rtx set_pat, ext_state *state) cand->mode = mode; } - merge_successful = true; - + merge_successful = false; /* Go through the defs vector and try to merge all the definitions in this vector. */ state->modified_list.truncate (0); FOR_EACH_VEC_ELT (state->defs_list, defs_ix, def_insn) { if (merge_def_and_ext (cand, def_insn, state)) - state->modified_list.safe_push (def_insn); + { + merge_successful = true; + state->modified_list.safe_push (def_insn); + } else { merge_successful = false; @@ -1045,34 +1403,71 @@ combine_reaching_defs (ext_cand *cand, const_rtx set_pat, ext_state *state) definitions could be merged. */ if (apply_change_group ()) { - if (dump_file) - fprintf (dump_file, "All merges were successful.\n"); + if (state->modified_list.length() == 0) + return false; + + rtx_insn *insn = state->modified_list[0]; + + if ((cand->code == ZERO_EXTEND || cand->code == SIGN_EXTEND) + && GET_CODE (PATTERN (insn)) == SET + && GET_CODE (SET_SRC (PATTERN (insn))) != XOR + && GET_CODE (SET_SRC (PATTERN (insn))) != PLUS + && GET_CODE (SET_SRC (PATTERN (insn))) != IOR) + return false; + + if (dump_file) + fprintf (dump_file, "All merges were successful.\n"); FOR_EACH_VEC_ELT (state->modified_list, i, def_insn) { ext_modified *modified = &state->modified[INSN_UID (def_insn)]; if (modified->kind == EXT_MODIFIED_NONE) modified->kind = (cand->code == ZERO_EXTEND ? EXT_MODIFIED_ZEXT - : EXT_MODIFIED_SEXT); + : EXT_MODIFIED_SEXT); if (copy_needed) modified->do_not_reextend = 1; } return true; } - else - { - /* Changes need not be cancelled explicitly as apply_change_group - does it. Print list of definitions in the dump_file for debug - purposes. This extension cannot be deleted. */ - if (dump_file) - { - fprintf (dump_file, - "Merge cancelled, non-mergeable definitions:\n"); - FOR_EACH_VEC_ELT (state->modified_list, i, def_insn) - print_rtl_single (dump_file, def_insn); - } - } + else + { + if (state->modified_list.length() == 0) + return false; + + rtx_insn *insn = state->modified_list[0]; + + if ((cand->code == ZERO_EXTEND || cand->code == SIGN_EXTEND) + && GET_CODE (PATTERN (insn)) == SET + && GET_CODE (SET_SRC (PATTERN (insn))) != XOR + && GET_CODE (SET_SRC (PATTERN (insn))) != PLUS + && GET_CODE (SET_SRC (PATTERN (insn))) != IOR) + return false; + + if (cand->code == ZERO_EXTEND || cand->code == SIGN_EXTEND) + { + FOR_EACH_VEC_ELT (state->modified_list, i, def_insn) + { + ext_modified *modified = &state->modified[INSN_UID (def_insn)]; + if (modified->kind == EXT_MODIFIED_NONE) + modified->kind = (cand->code == ZERO_EXTEND ? EXT_MODIFIED_ZEXT + : EXT_MODIFIED_SEXT); + + modified->do_not_reextend = 1; + } + return true; + } + /* Changes need not be cancelled explicitly as apply_change_group + does it. Print list of definitions in the dump_file for debug + purposes. This extension cannot be deleted. */ + if (dump_file) + { + fprintf (dump_file, + "Merge cancelled, non-mergeable definitions:\n"); + FOR_EACH_VEC_ELT (state->modified_list, i, def_insn) + print_rtl_single (dump_file, def_insn); + } + } } else { @@ -1106,7 +1501,7 @@ add_removable_extension (const_rtx expr, rtx_insn *insn, mode = GET_MODE (dest); if (REG_P (dest) - && (code == SIGN_EXTEND || code == ZERO_EXTEND) + && (code == SIGN_EXTEND || code == ZERO_EXTEND || rtx_is_zext_p (src)) && REG_P (XEXP (src, 0))) { rtx reg = XEXP (src, 0); @@ -1125,7 +1520,7 @@ add_removable_extension (const_rtx expr, rtx_insn *insn, fprintf (dump_file, "Cannot eliminate extension:\n"); print_rtl_single (dump_file, insn); fprintf (dump_file, " because it can operate on uninitialized" - " data\n"); + " data\n"); } return; } @@ -1320,8 +1715,8 @@ find_and_remove_re (void) if (REG_P (XEXP (SET_SRC (set), 0)) && (REGNO (SET_DEST (set)) != REGNO (XEXP (SET_SRC (set), 0)))) { - reinsn_copy_list.safe_push (curr_cand->insn); - reinsn_copy_list.safe_push (state.defs_list[0]); + reinsn_copy_list.safe_push (curr_cand->insn); + reinsn_copy_list.safe_push (state.defs_list[0]); } reinsn_del_list.safe_push (curr_cand->insn); state.modified[INSN_UID (curr_cand->insn)].deleted = 1; diff --git a/gcc/rtl.h b/gcc/rtl.h index 0e9491b89b4..f47e41b9037 100644 --- a/gcc/rtl.h +++ b/gcc/rtl.h @@ -3636,6 +3636,7 @@ extern int count_occurrences (const_rtx, const_rtx, int); extern bool reg_referenced_p (const_rtx, const_rtx); extern bool reg_used_between_p (const_rtx, const rtx_insn *, const rtx_insn *); extern bool reg_set_between_p (const_rtx, const rtx_insn *, const rtx_insn *); +extern bool reg_used_set_between_p (rtx, rtx_insn *, rtx_insn *); extern int commutative_operand_precedence (rtx); extern bool swap_commutative_operands_p (rtx, rtx); extern bool modified_between_p (const_rtx, const rtx_insn *, const rtx_insn *); diff --git a/gcc/rtlanal.cc b/gcc/rtlanal.cc index 8b48fc243a1..d971777c630 100644 --- a/gcc/rtlanal.cc +++ b/gcc/rtlanal.cc @@ -1134,6 +1134,21 @@ no_labels_between_p (const rtx_insn *beg, const rtx_insn *end) return true; } +/* The register reg of the extension to_insn must not be + used or set between the from_insn and to_insn exclusive. */ + +bool +reg_used_set_between_p (rtx reg, + rtx_insn *from_insn, + rtx_insn *to_insn) +{ + if (reg_used_between_p (reg, from_insn, to_insn) + || reg_set_between_p (reg, from_insn, to_insn)) + return true; + + return false; +} + /* Return true if register REG is used in an insn between FROM_INSN and TO_INSN (exclusive of those two). */ diff --git a/gcc/testsuite/g++.target/powerpc/sext-elim.C b/gcc/testsuite/g++.target/powerpc/sext-elim.C new file mode 100644 index 00000000000..36fef0b7a2f --- /dev/null +++ b/gcc/testsuite/g++.target/powerpc/sext-elim.C @@ -0,0 +1,17 @@ +/* { dg-do compile { target { powerpc*-*-* } } } */ +/* { dg-require-effective-target lp64 } */ +/* { dg-require-effective-target powerpc_p9vector_ok } */ +/* { dg-options "-mcpu=power9 -O2 -free" } */ + +unsigned long c2l(unsigned char* p) +{ + unsigned long res = *p + *(p+1); + return res; +} + +long c2sl(signed char* p) +{ + long res = *p + *(p+1); + return res; +} +/* { dg-final { scan-assembler-not "extsw" } } */ diff --git a/gcc/testsuite/g++.target/powerpc/zext-elim-1.C b/gcc/testsuite/g++.target/powerpc/zext-elim-1.C new file mode 100644 index 00000000000..bc6cc0eb3ca --- /dev/null +++ b/gcc/testsuite/g++.target/powerpc/zext-elim-1.C @@ -0,0 +1,19 @@ +/* { dg-do compile { target { powerpc*-*-* } } } */ +/* { dg-require-effective-target lp64 } */ +/* { dg-require-effective-target powerpc_p9vector_ok } */ +/* { dg-options "-mcpu=power9 -O2 -free" } */ + +extern unsigned char magic1[256]; + +unsigned int hash(const unsigned char inp[4]) +{ + const unsigned long long INIT = 0x1ULL; + unsigned long long h1 = INIT; + h1 = magic1[((unsigned long long)inp[0]) ^ h1]; + h1 = magic1[((unsigned long long)inp[1]) ^ h1]; + h1 = magic1[((unsigned long long)inp[2]) ^ h1]; + h1 = magic1[((unsigned long long)inp[3]) ^ h1]; + return h1; +} + +/* { dg-final { scan-assembler-not "rlwinm" } } */ diff --git a/gcc/testsuite/g++.target/powerpc/zext-elim-2.C b/gcc/testsuite/g++.target/powerpc/zext-elim-2.C new file mode 100644 index 00000000000..4e72925104f --- /dev/null +++ b/gcc/testsuite/g++.target/powerpc/zext-elim-2.C @@ -0,0 +1,11 @@ +/* { dg-do compile { target { powerpc*-*-* } } } */ +/* { dg-require-effective-target lp64 } */ +/* { dg-require-effective-target powerpc_p9vector_ok } */ +/* { dg-options "-mcpu=power9 -O2 -free" } */ + +unsigned char g(unsigned char t[], unsigned char v) +{ + return (t[v & 0x7f] & 0x7f) | (v & 0x80); +} + +/* { dg-final { scan-assembler-times "rlwinm" 2 } } */ diff --git a/gcc/testsuite/g++.target/powerpc/zext-elim.C b/gcc/testsuite/g++.target/powerpc/zext-elim.C new file mode 100644 index 00000000000..56eabbe0c19 --- /dev/null +++ b/gcc/testsuite/g++.target/powerpc/zext-elim.C @@ -0,0 +1,30 @@ +/* { dg-do compile { target { powerpc*-*-* } } } */ +/* { dg-require-effective-target lp64 } */ +/* { dg-require-effective-target powerpc_p9vector_ok } */ +/* { dg-options "-mcpu=power9 -O2 -free" } */ + +#include + +bool foo (int a, int b) +{ + if (a > 2) + return false; + + if (b < 10) + return true; + + return true; +} + +int bar (int a, int b) +{ + if (a > 2) + return 0; + + if (b < 10) + return 1; + + return 0; +} + +/* { dg-final { scan-assembler-not "rldicl" } } */