From: Ajit Agarwal <aagarwa1@linux.ibm.com>
To: gcc-patches <gcc-patches@gcc.gnu.org>
Cc: Jeff Law <jeffreyalaw@gmail.com>,
Segher Boessenkool <segher@kernel.crashing.org>,
Peter Bergner <bergner@linux.ibm.com>,
Richard Biener <richard.guenther@gmail.com>
Subject: [PING] [PATCH 3/4] ree: Improve functionality of ree pass for rs6000 target.
Date: Mon, 26 Jun 2023 18:10:09 +0530 [thread overview]
Message-ID: <f60606e0-01dc-31e9-9934-28316cf17948@linux.ibm.com> (raw)
In-Reply-To: <da977e26-f462-c0ec-e054-2cb415ad2493@linux.ibm.com>
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 <aagarwa1@linux.ibm.com>
>
> 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<rtx_insn *> *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<rtx_insn *> *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<rtx_insn *> *dest = XCNEWVEC (vec<rtx_insn *>, 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 <stddef.h>
> +
> +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" } } */
next prev parent reply other threads:[~2023-06-26 12:42 UTC|newest]
Thread overview: 5+ messages / expand[flat|nested] mbox.gz Atom feed top
2023-06-07 10:25 Ajit Agarwal
2023-06-26 12:40 ` Ajit Agarwal [this message]
2023-07-18 8:01 ` [PING^2] " Ajit Agarwal
2023-08-01 8:20 ` PING^3] " Ajit Agarwal
2023-08-21 6:45 ` [PING^4] " Ajit Agarwal
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=f60606e0-01dc-31e9-9934-28316cf17948@linux.ibm.com \
--to=aagarwa1@linux.ibm.com \
--cc=bergner@linux.ibm.com \
--cc=gcc-patches@gcc.gnu.org \
--cc=jeffreyalaw@gmail.com \
--cc=richard.guenther@gmail.com \
--cc=segher@kernel.crashing.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).