From patchwork Wed Apr 19 18:00:30 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ajit Agarwal X-Patchwork-Id: 68036 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 ED04C3858002 for ; Wed, 19 Apr 2023 18:01:11 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org ED04C3858002 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gcc.gnu.org; s=default; t=1681927272; bh=WjqbKIfxNoTi51nGHW8hticHdLCk9viQAsNJlAfogEM=; h=Date:To:Cc:Subject:List-Id:List-Unsubscribe:List-Archive: List-Post:List-Help:List-Subscribe:From:Reply-To:From; b=Ikom/qkota4+536OY/U//OsRgq9a8LN69N3h+T0yR/38ZscHbgqK+29hwQ+EZQswZ /Y39t8A31kTZV7TbiT+f3A3341R8/0IWMGjiA5M5L9DL6TatiGqmrF/TtUYJ+FDlva V3lBDwwrPVrnU/U6qNuON15K18IbQAEhT60TjMOU= 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 312FC3858D33 for ; Wed, 19 Apr 2023 18:00:41 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 312FC3858D33 Received: from pps.filterd (m0353728.ppops.net [127.0.0.1]) by mx0a-001b2d01.pphosted.com (8.17.1.19/8.17.1.19) with ESMTP id 33JHos2s023953; Wed, 19 Apr 2023 18:00:40 GMT Received: from pps.reinject (localhost [127.0.0.1]) by mx0a-001b2d01.pphosted.com (PPS) with ESMTPS id 3q20emv8am-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Wed, 19 Apr 2023 18:00:39 +0000 Received: from m0353728.ppops.net (m0353728.ppops.net [127.0.0.1]) by pps.reinject (8.17.1.5/8.17.1.5) with ESMTP id 33JEZWnq011553; Wed, 19 Apr 2023 18:00:38 GMT Received: from ppma05wdc.us.ibm.com (1b.90.2fa9.ip4.static.sl-reverse.com [169.47.144.27]) by mx0a-001b2d01.pphosted.com (PPS) with ESMTPS id 3q20emv89q-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Wed, 19 Apr 2023 18:00:38 +0000 Received: from pps.filterd (ppma05wdc.us.ibm.com [127.0.0.1]) by ppma05wdc.us.ibm.com (8.17.1.19/8.17.1.19) with ESMTP id 33JHxYHM015441; Wed, 19 Apr 2023 18:00:36 GMT Received: from smtprelay03.dal12v.mail.ibm.com ([9.208.130.98]) by ppma05wdc.us.ibm.com (PPS) with ESMTPS id 3pykj7fux1-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Wed, 19 Apr 2023 18:00:36 +0000 Received: from smtpav06.wdc07v.mail.ibm.com (smtpav06.wdc07v.mail.ibm.com [10.39.53.233]) by smtprelay03.dal12v.mail.ibm.com (8.14.9/8.14.9/NCO v10.0) with ESMTP id 33JI0Zvl9306624 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-GCM-SHA384 bits=256 verify=OK); Wed, 19 Apr 2023 18:00:35 GMT Received: from smtpav06.wdc07v.mail.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id 3355B58056; Wed, 19 Apr 2023 18:00:35 +0000 (GMT) Received: from smtpav06.wdc07v.mail.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id EAA4658067; Wed, 19 Apr 2023 18:00:31 +0000 (GMT) Received: from [9.43.84.11] (unknown [9.43.84.11]) by smtpav06.wdc07v.mail.ibm.com (Postfix) with ESMTP; Wed, 19 Apr 2023 18:00:31 +0000 (GMT) Message-ID: <12889922-0160-a036-7dbf-1d208e353f82@linux.ibm.com> Date: Wed, 19 Apr 2023 23:30:30 +0530 MIME-Version: 1.0 User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:102.0) Gecko/20100101 Thunderbird/102.9.1 Content-Language: en-US To: gcc-patches Cc: Jeff Law , Segher Boessenkool , Peter Bergner , Jakub Jelinek , Richard Biener Subject: [PATCH v3 3/4] ree: Main functionality to Improve ree pass for rs6000 target X-TM-AS-GCONF: 00 X-Proofpoint-GUID: g5xjyMOU543f7OTvGqcAR5PPT7rQAMPz X-Proofpoint-ORIG-GUID: kZXZXYCRnaQURMZA1XIuVRpgKn7O1ejS X-Proofpoint-Virus-Version: vendor=baseguard engine=ICAP:2.0.254,Aquarius:18.0.942,Hydra:6.0.573,FMLib:17.11.170.22 definitions=2023-04-19_12,2023-04-18_01,2023-02-09_01 X-Proofpoint-Spam-Details: rule=outbound_notspam policy=outbound score=0 priorityscore=1501 malwarescore=0 mlxscore=0 lowpriorityscore=0 spamscore=0 phishscore=0 mlxlogscore=999 adultscore=0 bulkscore=0 suspectscore=0 clxscore=1015 impostorscore=0 classifier=spam adjust=0 reason=mlx scancount=1 engine=8.12.0-2303200000 definitions=main-2304190155 X-Spam-Status: No, score=-12.1 required=5.0 tests=BAYES_00, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_EF, GIT_PATCH_0, 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.29 Precedence: list List-Id: Gcc-patches mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-Patchwork-Original-From: Ajit Agarwal via Gcc-patches From: Ajit Agarwal Reply-To: Ajit Agarwal Errors-To: gcc-patches-bounces+patchwork=sourceware.org@gcc.gnu.org Sender: "Gcc-patches" Hello All: This is patch-3 to improve ree pass for rs6000 target. Main functionality routines to imprve ree pass. Bootstrapped and regtested on powerpc64-gnu-linux. 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. 2023-04-19 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. (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 | 451 ++++++++++++++++-- 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 ++ 5 files changed, 482 insertions(+), 47 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 413aec7c8eb..053db2e8ff3 100644 --- a/gcc/ree.cc +++ b/gcc/ree.cc @@ -253,6 +253,71 @@ struct ext_cand static int max_insn_uid; +bool +reg_used_set_between_p (rtx set, rtx_insn *def_insn, rtx_insn *insn) +{ + if (reg_used_between_p (set, def_insn, insn) + || reg_set_between_p (set, def_insn, insn)) + return true; + + 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 unsigned int +rtx_is_zext_p (rtx insn) +{ + if (GET_CODE (insn) == AND) + { + rtx set = XEXP (insn, 0); + if (REG_P (set)) + { + if (XEXP (insn, 1) == const1_rtx) + return 1; + } + else + return 0; + } + + return 0; +} + +/* 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 unsigned int +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)) + { + if (XEXP (SET_SRC (body), 1) == const1_rtx) + return 1; + } + else + return 0; + } + + return 0; +} + /* Update or remove REG_EQUAL or REG_EQUIV notes for INSN. */ static bool @@ -319,7 +384,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 +424,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 +547,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 +561,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 @@ -500,7 +580,6 @@ get_defs (rtx_insn *insn, rtx reg, vec *dest) return ref_chain; } - /* Get all the reaching uses of an instruction. The uses are desired for REG set in INSN. Return use list or NULL if a use is missing or irregular. */ @@ -698,6 +777,226 @@ get_sub_rtx (rtx_insn *def_insn) return sub_rtx; } +/* Check if the def insn is ASHIFT and LSHIFTRT. + Inputs: insn for which def has to be checked. + source operand rtx. + Output: True or false if def has arithmetic + peration like ASHIFT and LSHIFTRT. */ + +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; + + /* checks 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; + } + + /* checks 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; +} + +/* Find feasibility of extension elimination + across basic blocks. + Input: candiate to check the feasibility. + def_insn of candidate. + Output: Returns true or false if feasible or not. */ + +static bool +eliminate_across_bbs_p (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); + + 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) + { + 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 + || e->dest != fallthru_edge->dest)) + return false; + } + else + return false; + } + else return false; + } + else + { + 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; + } + } + } + } + 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; + + 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 +1012,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 +1053,6 @@ merge_def_and_ext (ext_cand *cand, rtx_insn *def_insn, ext_state *state) return true; } } - return false; } @@ -744,7 +1062,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 +1202,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 +1294,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 +1321,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 +1364,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 +1462,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 +1481,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; } @@ -1321,7 +1677,7 @@ find_and_remove_re (void) && (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 (state.defs_list[0]); } reinsn_del_list.safe_push (curr_cand->insn); state.modified[INSN_UID (curr_cand->insn)].deleted = 1; @@ -1368,9 +1724,10 @@ find_and_remove_re (void) reinsn_list.release (); XDELETEVEC (state.modified); - if (dump_file && num_re_opportunities > 0) + if (dump_file && num_re_opportunities > 0) { fprintf (dump_file, "Elimination opportunities = %d realized = %d\n", num_re_opportunities, num_realized); + } } /* Find and remove redundant extensions. */ 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" } } */