From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from mx0b-001b2d01.pphosted.com (mx0b-001b2d01.pphosted.com [148.163.158.5]) by sourceware.org (Postfix) with ESMTPS id 19B543858D1E for ; Mon, 26 Jun 2023 12:42:00 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 19B543858D1E 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 (m0353723.ppops.net [127.0.0.1]) by mx0a-001b2d01.pphosted.com (8.17.1.19/8.17.1.19) with ESMTP id 35QCHvgk008502; Mon, 26 Jun 2023 12:41:59 GMT DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=ibm.com; h=message-id : date : mime-version : subject : to : cc : references : from : in-reply-to : content-type : content-transfer-encoding; s=pp1; bh=xO4Ya5AIwNOQ9Kr+Zj8WvKgIoY9n5K8YI42EemiFCT8=; b=fkCZ1Gyv1pm0yCpqRxiLXCWiSuDayqoJmiyL85D0DmMztbkiRhL3G8zafQ62EFt6KGLs pBOIpor3NQi42lwEH9eYwquGJRGjm+HLqZBHEuXt6JKHoh0GDoJsO8KkzFQt53XK32zb 5JmEUZ08/+hbY5NBO4G0Fz7I9MyTO8onMchaR7My5NbEh2XJ8aqGHChvZWNocI4tij2u gc+GH9kUAWyisZXozGP2gl+cp9461bHSYoXhJUvdygaqlDrirZUcVn9GWuSmpheWsGk/ qRmjUa9Judf380qpVUS9gM3usezdzGCCwqQzXfNKHjXHODgDmp7GiI2XdN8GK4JY3fdo Xw== Received: from pps.reinject (localhost [127.0.0.1]) by mx0a-001b2d01.pphosted.com (PPS) with ESMTPS id 3rfaj6gtj3-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Mon, 26 Jun 2023 12:41:53 +0000 Received: from m0353723.ppops.net (m0353723.ppops.net [127.0.0.1]) by pps.reinject (8.17.1.5/8.17.1.5) with ESMTP id 35QCI9nF009016; Mon, 26 Jun 2023 12:40:48 GMT Received: from ppma04wdc.us.ibm.com (1a.90.2fa9.ip4.static.sl-reverse.com [169.47.144.26]) by mx0a-001b2d01.pphosted.com (PPS) with ESMTPS id 3rfaj6gr7r-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Mon, 26 Jun 2023 12:40:47 +0000 Received: from pps.filterd (ppma04wdc.us.ibm.com [127.0.0.1]) by ppma04wdc.us.ibm.com (8.17.1.19/8.17.1.19) with ESMTP id 35QCGHKl025152; Mon, 26 Jun 2023 12:40:18 GMT Received: from smtprelay05.wdc07v.mail.ibm.com ([9.208.129.117]) by ppma04wdc.us.ibm.com (PPS) with ESMTPS id 3rdr45jxqy-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Mon, 26 Jun 2023 12:40:18 +0000 Received: from smtpav05.wdc07v.mail.ibm.com (smtpav05.wdc07v.mail.ibm.com [10.39.53.232]) by smtprelay05.wdc07v.mail.ibm.com (8.14.9/8.14.9/NCO v10.0) with ESMTP id 35QCeHwc5767926 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-GCM-SHA384 bits=256 verify=OK); Mon, 26 Jun 2023 12:40:17 GMT Received: from smtpav05.wdc07v.mail.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id EA42C58059; Mon, 26 Jun 2023 12:40:16 +0000 (GMT) Received: from smtpav05.wdc07v.mail.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id 42DF458043; Mon, 26 Jun 2023 12:40:12 +0000 (GMT) Received: from [9.43.27.64] (unknown [9.43.27.64]) by smtpav05.wdc07v.mail.ibm.com (Postfix) with ESMTP; Mon, 26 Jun 2023 12:40:11 +0000 (GMT) Message-ID: Date: Mon, 26 Jun 2023 18:10:09 +0530 MIME-Version: 1.0 User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:102.0) Gecko/20100101 Thunderbird/102.11.2 Subject: [PING] [PATCH 3/4] ree: Improve functionality of ree pass for rs6000 target. Content-Language: en-US To: gcc-patches Cc: Jeff Law , Segher Boessenkool , Peter Bergner , Richard Biener References: From: Ajit Agarwal In-Reply-To: Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 7bit X-TM-AS-GCONF: 00 X-Proofpoint-ORIG-GUID: upoOeDc1M0nd3oqKbjyivY_OYzKaaPXi X-Proofpoint-GUID: wflNy5May0ExPwaIF2AbH3A2hrf2sFyY X-Proofpoint-Virus-Version: vendor=baseguard engine=ICAP:2.0.254,Aquarius:18.0.957,Hydra:6.0.591,FMLib:17.11.176.26 definitions=2023-06-26_09,2023-06-26_02,2023-05-22_02 X-Proofpoint-Spam-Details: rule=outbound_notspam policy=outbound score=0 impostorscore=0 spamscore=0 adultscore=0 mlxlogscore=999 suspectscore=0 priorityscore=1501 mlxscore=0 clxscore=1015 phishscore=0 bulkscore=0 lowpriorityscore=0 malwarescore=0 classifier=spam adjust=0 reason=mlx scancount=1 engine=8.12.0-2305260000 definitions=main-2306260108 X-Spam-Status: No, score=-12.5 required=5.0 tests=BAYES_00,DKIM_SIGNED,DKIM_VALID,DKIM_VALID_EF,GIT_PATCH_0,RCVD_IN_MSPIKE_H5,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 List-Id: All: Ok for trunk. Please review. Thanks & Regards Ajit On 07/06/23 3:55 pm, Ajit Agarwal via Gcc-patches wrote: > Hello All: > > This patch provide functionality to improve ree pass for rs6000 target. > Eliminated sign_extend/zero_extend/AND with varying constants. > > Bootstrapped and regtested on powerpc64-linux-gnu. > > Thanks & Regards > Ajit > > ree: Improve ree pass for rs6000 target > > For rs6000 target we see redundant zero and sign extension and done to improve > ree pass to eliminate such redundant zero and sign extension. Support of > zero_extend/sign_extend/AND. Also support of AND with extension with different > constants other than 1. > > 2023-06-07 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 | 476 ++++++++++++++++-- > gcc/rtl.h | 1 + > gcc/rtlanal.cc | 15 + > gcc/testsuite/g++.target/powerpc/sext-elim.C | 18 + > .../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, 524 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..dc6da21ec16 100644 > --- a/gcc/ree.cc > +++ b/gcc/ree.cc > @@ -253,6 +253,66 @@ 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); > + > + if (CONST_INT_P (src) > + && IN_RANGE (exact_log2 (UINTVAL (src)), 0, 7)) > + 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); > + > + if (CONST_INT_P (src) > + && IN_RANGE (exact_log2 (UINTVAL (src)), 0, 7)) > + return true; > + } > + else > + return false; > + } > + > + return false; > +} > + > /* Update or remove REG_EQUAL or REG_EQUIV notes for INSN. */ > > static bool > @@ -319,7 +379,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 +419,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 +542,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 +556,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 +773,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 +1040,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 +1081,6 @@ merge_def_and_ext (ext_cand *cand, rtx_insn *def_insn, ext_state *state) > return true; > } > } > - > return false; > } > > @@ -744,7 +1090,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 +1230,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 +1322,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 +1349,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 +1392,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 +1490,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 +1509,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 +1704,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 988691f5710..9278ec43d69 100644 > --- a/gcc/rtl.h > +++ b/gcc/rtl.h > @@ -3631,6 +3631,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 31707f3b90a..fa0e8741416 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..431696cf11e > --- /dev/null > +++ b/gcc/testsuite/g++.target/powerpc/sext-elim.C > @@ -0,0 +1,18 @@ > +/* { 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" } } */