From patchwork Tue Aug 1 08:20:21 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ajit Agarwal X-Patchwork-Id: 1815412 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@legolas.ozlabs.org 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=) Authentication-Results: legolas.ozlabs.org; dkim=pass (1024-bit key; unprotected) header.d=gcc.gnu.org header.i=@gcc.gnu.org header.a=rsa-sha256 header.s=default header.b=jqw8ya/B; dkim-atps=neutral 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 (P-384) server-digest SHA384) (No client certificate requested) by legolas.ozlabs.org (Postfix) with ESMTPS id 4RFSjl2sm5z1yZl for ; Tue, 1 Aug 2023 18:20:59 +1000 (AEST) Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 251133858C66 for ; Tue, 1 Aug 2023 08:20:57 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 251133858C66 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gcc.gnu.org; s=default; t=1690878057; bh=xOdYP2mQIdM4AN47mkBXDA/C6rWLXvGFArVKLRIYIAQ=; h=Date:Subject:References:To:In-Reply-To:List-Id:List-Unsubscribe: List-Archive:List-Post:List-Help:List-Subscribe:From:Reply-To: From; b=jqw8ya/BydZtWQYaZAlibVN2rS2N6Z8BtqQFJ7c0vAIUTUeMRbelwmVoJ72QEYFOJ He3nAtu/vftd54eIWwYTkowjJ9iNFW7jJ91ijw+gl5xs5Gbj7EMb9wn9LBKsvJxOvB Lusg6nFGlTnFkL/aRG1y/i+IvHE1Cquk5+F8g5W4= X-Original-To: gcc-patches@gcc.gnu.org Delivered-To: gcc-patches@gcc.gnu.org Received: from mx0b-001b2d01.pphosted.com (mx0b-001b2d01.pphosted.com [148.163.158.5]) by sourceware.org (Postfix) with ESMTPS id E5DF93858D28 for ; Tue, 1 Aug 2023 08:20:29 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org E5DF93858D28 Received: from pps.filterd (m0353725.ppops.net [127.0.0.1]) by mx0a-001b2d01.pphosted.com (8.17.1.19/8.17.1.19) with ESMTP id 3718BmvW022705; Tue, 1 Aug 2023 08:20:29 GMT Received: from pps.reinject (localhost [127.0.0.1]) by mx0a-001b2d01.pphosted.com (PPS) with ESMTPS id 3s6wpj10r8-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Tue, 01 Aug 2023 08:20:28 +0000 Received: from m0353725.ppops.net (m0353725.ppops.net [127.0.0.1]) by pps.reinject (8.17.1.5/8.17.1.5) with ESMTP id 3718BsvN023135; Tue, 1 Aug 2023 08:20:28 GMT Received: from ppma12.dal12v.mail.ibm.com (dc.9e.1632.ip4.static.sl-reverse.com [50.22.158.220]) by mx0a-001b2d01.pphosted.com (PPS) with ESMTPS id 3s6wpj10r1-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Tue, 01 Aug 2023 08:20:28 +0000 Received: from pps.filterd (ppma12.dal12v.mail.ibm.com [127.0.0.1]) by ppma12.dal12v.mail.ibm.com (8.17.1.19/8.17.1.19) with ESMTP id 3717jokB006073; Tue, 1 Aug 2023 08:20:27 GMT Received: from smtprelay03.dal12v.mail.ibm.com ([172.16.1.5]) by ppma12.dal12v.mail.ibm.com (PPS) with ESMTPS id 3s5d3sambj-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Tue, 01 Aug 2023 08:20:27 +0000 Received: from smtpav05.dal12v.mail.ibm.com (smtpav05.dal12v.mail.ibm.com [10.241.53.104]) by smtprelay03.dal12v.mail.ibm.com (8.14.9/8.14.9/NCO v10.0) with ESMTP id 3718KRZO7537314 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-GCM-SHA384 bits=256 verify=OK); Tue, 1 Aug 2023 08:20:27 GMT Received: from smtpav05.dal12v.mail.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id 040A658052; Tue, 1 Aug 2023 08:20:27 +0000 (GMT) Received: from smtpav05.dal12v.mail.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id CB3D75805D; Tue, 1 Aug 2023 08:20:23 +0000 (GMT) Received: from [9.43.51.76] (unknown [9.43.51.76]) by smtpav05.dal12v.mail.ibm.com (Postfix) with ESMTP; Tue, 1 Aug 2023 08:20:23 +0000 (GMT) Message-ID: <1e865494-bad6-1204-86b2-4cd0cd5bfce1@linux.ibm.com> Date: Tue, 1 Aug 2023 13:50:21 +0530 MIME-Version: 1.0 User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:102.0) Gecko/20100101 Thunderbird/102.12.0 Subject: PING^3] [PATCH 3/4] ree: Improve functionality of ree pass for rs6000 target. Content-Language: en-US References: <2ade0000-8132-4cb4-78a5-233be1ead4ab@linux.ibm.com> To: gcc-patches , Jeff Law , Richard Biener , Peter Bergner , Segher Boessenkool , Rashmi.Sridhar@ibm.com In-Reply-To: <2ade0000-8132-4cb4-78a5-233be1ead4ab@linux.ibm.com> X-Forwarded-Message-Id: <2ade0000-8132-4cb4-78a5-233be1ead4ab@linux.ibm.com> X-TM-AS-GCONF: 00 X-Proofpoint-ORIG-GUID: 8HNCd5Ij_KWDgQfOg1bMsFJo36nvGFtu X-Proofpoint-GUID: rJkcLs4-nF2DprlIIhrVWGBPTEBrOIud 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-08-01_03,2023-07-31_02,2023-05-22_02 X-Proofpoint-Spam-Details: rule=outbound_notspam policy=outbound score=0 suspectscore=0 impostorscore=0 adultscore=0 clxscore=1015 lowpriorityscore=0 mlxscore=0 malwarescore=0 priorityscore=1501 spamscore=0 bulkscore=0 mlxlogscore=999 phishscore=0 classifier=spam adjust=0 reason=mlx scancount=1 engine=8.12.0-2306200000 definitions=main-2308010072 X-Spam-Status: No, score=-12.5 required=5.0 tests=BAYES_00, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_EF, GIT_PATCH_0, KAM_MANYTO, 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 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+incoming=patchwork.ozlabs.org@gcc.gnu.org Sender: "Gcc-patches" Ping! -------- Forwarded Message -------- Subject: [PING^2] [PATCH 3/4] ree: Improve functionality of ree pass for rs6000 target. Date: Tue, 18 Jul 2023 13:31:27 +0530 From: Ajit Agarwal To: gcc-patches CC: Jeff Law , Richard Biener , Segher Boessenkool , Peter Bergner Ping^2. Please review. Thanks & Regards Ajit 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" } } */ From patchwork Mon Aug 21 06:45:19 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ajit Agarwal X-Patchwork-Id: 1823548 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@legolas.ozlabs.org Authentication-Results: legolas.ozlabs.org; dkim=pass (1024-bit key; unprotected) header.d=gcc.gnu.org header.i=@gcc.gnu.org header.a=rsa-sha256 header.s=default header.b=maQUh64P; 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 4RTjfq3Rytz1ybW for ; Mon, 21 Aug 2023 16:45:55 +1000 (AEST) Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 4897B385B51F for ; Mon, 21 Aug 2023 06:45:53 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 4897B385B51F DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gcc.gnu.org; s=default; t=1692600353; bh=t4+R6bMf4FIFmI/G5FiCqJJMGU8n+OzOGrIgKdsiNSM=; h=Date:Subject:References:To:Cc:In-Reply-To:List-Id: List-Unsubscribe:List-Archive:List-Post:List-Help:List-Subscribe: From:Reply-To:From; b=maQUh64PDUBSo8xy6uqrQyGZrqGWX0Oh6pFx6/V8QE4AG5++tkYgTNbNYR/n3eNU0 EpZ1JrMzWGiaiAAaXNi15OE9o8izjlAthCRKFAd0DdGhtfmaWnZ6LJRDsl84o/+652 xW0i9cAyHw01EtcOUY4rkD1kLS72fkfuPMwxjgUg= X-Original-To: gcc-patches@gcc.gnu.org Delivered-To: gcc-patches@gcc.gnu.org Received: from mx0b-001b2d01.pphosted.com (mx0b-001b2d01.pphosted.com [148.163.158.5]) by sourceware.org (Postfix) with ESMTPS id 24EF93858291 for ; Mon, 21 Aug 2023 06:45:30 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 24EF93858291 Received: from pps.filterd (m0353725.ppops.net [127.0.0.1]) by mx0a-001b2d01.pphosted.com (8.17.1.19/8.17.1.19) with ESMTP id 37L68ert020118; Mon, 21 Aug 2023 06:45:29 GMT Received: from pps.reinject (localhost [127.0.0.1]) by mx0a-001b2d01.pphosted.com (PPS) with ESMTPS id 3sm1t5145e-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Mon, 21 Aug 2023 06:45:29 +0000 Received: from m0353725.ppops.net (m0353725.ppops.net [127.0.0.1]) by pps.reinject (8.17.1.5/8.17.1.5) with ESMTP id 37L6iB7f008007; Mon, 21 Aug 2023 06:45:28 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 3sm1t51456-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Mon, 21 Aug 2023 06:45:28 +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 37L6KH6O005703; Mon, 21 Aug 2023 06:45:28 GMT Received: from smtprelay04.dal12v.mail.ibm.com ([172.16.1.6]) by ppma11.dal12v.mail.ibm.com (PPS) with ESMTPS id 3skas1g0sp-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Mon, 21 Aug 2023 06:45:28 +0000 Received: from smtpav05.wdc07v.mail.ibm.com (smtpav05.wdc07v.mail.ibm.com [10.39.53.232]) by smtprelay04.dal12v.mail.ibm.com (8.14.9/8.14.9/NCO v10.0) with ESMTP id 37L6jRWr22217404 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-GCM-SHA384 bits=256 verify=OK); Mon, 21 Aug 2023 06:45:27 GMT Received: from smtpav05.wdc07v.mail.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id 2447558053; Mon, 21 Aug 2023 06:45:27 +0000 (GMT) Received: from smtpav05.wdc07v.mail.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id 4ABF558043; Mon, 21 Aug 2023 06:45:21 +0000 (GMT) Received: from [9.43.86.76] (unknown [9.43.86.76]) by smtpav05.wdc07v.mail.ibm.com (Postfix) with ESMTP; Mon, 21 Aug 2023 06:45:20 +0000 (GMT) Message-ID: <8b994705-9e75-f2b7-4858-f45da8e5a9d6@linux.ibm.com> Date: Mon, 21 Aug 2023 12:15:19 +0530 MIME-Version: 1.0 User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:102.0) Gecko/20100101 Thunderbird/102.14.0 Subject: [PING^4] [PATCH 3/4] ree: Improve functionality of ree pass for rs6000 target. Content-Language: en-US References: <1e865494-bad6-1204-86b2-4cd0cd5bfce1@linux.ibm.com> To: gcc-patches Cc: Jeff Law , Richard Biener , Segher Boessenkool , Peter Bergner , Rashmi.Sridhar@ibm.com In-Reply-To: <1e865494-bad6-1204-86b2-4cd0cd5bfce1@linux.ibm.com> X-Forwarded-Message-Id: <1e865494-bad6-1204-86b2-4cd0cd5bfce1@linux.ibm.com> X-TM-AS-GCONF: 00 X-Proofpoint-GUID: vJwZueRaKRAqPpTEYvI8brg5gjzPvW8u X-Proofpoint-ORIG-GUID: hyDm4h4No2NV7N0JWBJlrMq18o8jOuWY X-Proofpoint-Virus-Version: vendor=baseguard engine=ICAP:2.0.267,Aquarius:18.0.957,Hydra:6.0.601,FMLib:17.11.176.26 definitions=2023-08-20_15,2023-08-18_01,2023-05-22_02 X-Proofpoint-Spam-Details: rule=outbound_notspam policy=outbound score=0 impostorscore=0 clxscore=1015 phishscore=0 spamscore=0 adultscore=0 mlxlogscore=999 lowpriorityscore=0 suspectscore=0 malwarescore=0 mlxscore=0 bulkscore=0 priorityscore=1501 classifier=spam adjust=0 reason=mlx scancount=1 engine=8.12.0-2306200000 definitions=main-2308210060 X-Spam-Status: No, score=-12.6 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 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+incoming=patchwork.ozlabs.org@gcc.gnu.org Sender: "Gcc-patches" Ping! -------- Forwarded Message -------- Subject: PING^3] [PATCH 3/4] ree: Improve functionality of ree pass for rs6000 target. Date: Tue, 1 Aug 2023 13:50:21 +0530 From: Ajit Agarwal To: gcc-patches , Jeff Law , Richard Biener , Peter Bergner , Segher Boessenkool , Rashmi.Sridhar@ibm.com Ping! -------- Forwarded Message -------- Subject: [PING^2] [PATCH 3/4] ree: Improve functionality of ree pass for rs6000 target. Date: Tue, 18 Jul 2023 13:31:27 +0530 From: Ajit Agarwal To: gcc-patches CC: Jeff Law , Richard Biener , Segher Boessenkool , Peter Bergner Ping^2. Please review. Thanks & Regards Ajit 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" } } */