From patchwork Tue Sep 19 09:21:16 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ajit Agarwal X-Patchwork-Id: 1836568 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=Ig25q3yy; 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 4RqblV29nxz1ynZ for ; Tue, 19 Sep 2023 19:21:56 +1000 (AEST) Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 9044D385772F for ; Tue, 19 Sep 2023 09:21:47 +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 E550A3858D32 for ; Tue, 19 Sep 2023 09:21:25 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org E550A3858D32 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 Received: from pps.filterd (m0353727.ppops.net [127.0.0.1]) by mx0a-001b2d01.pphosted.com (8.17.1.19/8.17.1.19) with ESMTP id 38J8b9PZ017838; Tue, 19 Sep 2023 09:21:25 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=6KF/PYmqDxUGkZ12psSUo4/NgryPsoIBgTn3cgypXXs=; b=Ig25q3yyEYXQ2/Pa4Luzsx5TaNwicgIQRxcb57+OTer+dyTWJV0Pm+ImpuhcfMC71yE7 n6kiI6F653X2dynCkFjMekEvffk/TsC+rL3DQ8juh3xGfGt73UzRxwhBG2A0AK/rk9fZ QjedwulsrGqBppT46ihNNX+fGIwuX1PJn2xsOwymt86X8wCrLbz0SYY7MF6kLgVcI6PF r7zIsjDOsILHgu0Yvb0LZOg+klgTzqfRCHSJv/Irmo5uEsuGPwb1OuA0BvOhA9IKnkVk Jc4MQGUJdipU+wIZBOMyCWiFEc/8DyhtCZdVLWC6M7QMY0s5BojneUJtrRK3WSH6+tid ag== Received: from pps.reinject (localhost [127.0.0.1]) by mx0a-001b2d01.pphosted.com (PPS) with ESMTPS id 3t77n32chn-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Tue, 19 Sep 2023 09:21:24 +0000 Received: from m0353727.ppops.net (m0353727.ppops.net [127.0.0.1]) by pps.reinject (8.17.1.5/8.17.1.5) with ESMTP id 38J8bW9k021812; Tue, 19 Sep 2023 09:21:24 GMT Received: from ppma11.dal12v.mail.ibm.com (db.9e.1632.ip4.static.sl-reverse.com [50.22.158.219]) by mx0a-001b2d01.pphosted.com (PPS) with ESMTPS id 3t77n32cha-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Tue, 19 Sep 2023 09:21:24 +0000 Received: from pps.filterd (ppma11.dal12v.mail.ibm.com [127.0.0.1]) by ppma11.dal12v.mail.ibm.com (8.17.1.19/8.17.1.19) with ESMTP id 38J7sBb5016455; Tue, 19 Sep 2023 09:21:23 GMT Received: from smtprelay06.wdc07v.mail.ibm.com ([172.16.1.73]) by ppma11.dal12v.mail.ibm.com (PPS) with ESMTPS id 3t5sd1t9h4-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Tue, 19 Sep 2023 09:21:22 +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 38J9LMPH64356706 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-GCM-SHA384 bits=256 verify=OK); Tue, 19 Sep 2023 09:21:22 GMT Received: from smtpav05.dal12v.mail.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id E1B7458056; Tue, 19 Sep 2023 09:21:21 +0000 (GMT) Received: from smtpav05.dal12v.mail.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id C685658052; Tue, 19 Sep 2023 09:21:18 +0000 (GMT) Received: from [9.43.33.46] (unknown [9.43.33.46]) by smtpav05.dal12v.mail.ibm.com (Postfix) with ESMTP; Tue, 19 Sep 2023 09:21:18 +0000 (GMT) Message-ID: <9d06fa96-0a59-8e47-1869-d6e34a24163a@linux.ibm.com> Date: Tue, 19 Sep 2023 14:51:16 +0530 MIME-Version: 1.0 User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:102.0) Gecko/20100101 Thunderbird/102.15.0 Subject: [PATCH v2 3/4] Improve functionality of ree pass with various constants with AND operation. Content-Language: en-US References: <6854c0cd-9a9b-eb6d-5ea9-8999ec41b3eb@linux.ibm.com> To: gcc-patches Cc: Jeff Law , Vineet Gupta , Richard Biener , Peter Bergner , Segher Boessenkool From: Ajit Agarwal In-Reply-To: <6854c0cd-9a9b-eb6d-5ea9-8999ec41b3eb@linux.ibm.com> X-Forwarded-Message-Id: <6854c0cd-9a9b-eb6d-5ea9-8999ec41b3eb@linux.ibm.com> X-TM-AS-GCONF: 00 X-Proofpoint-GUID: -6ycPGtJ1Fa1_yaE4bDg5WcwrXZ1EZRU X-Proofpoint-ORIG-GUID: okSgdSio68omrRfWXTTNkpWVWq6kXq6o X-Proofpoint-Virus-Version: vendor=baseguard engine=ICAP:2.0.267,Aquarius:18.0.980,Hydra:6.0.601,FMLib:17.11.176.26 definitions=2023-09-19_03,2023-09-18_01,2023-05-22_02 X-Proofpoint-Spam-Details: rule=outbound_notspam policy=outbound score=0 impostorscore=0 bulkscore=0 clxscore=1015 spamscore=0 mlxscore=0 suspectscore=0 adultscore=0 priorityscore=1501 malwarescore=0 mlxlogscore=999 phishscore=0 lowpriorityscore=0 classifier=spam adjust=0 reason=mlx scancount=1 engine=8.12.0-2308100000 definitions=main-2309190076 X-Spam-Status: No, score=-12.9 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 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 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" } } */