From: Ajit Agarwal <aagarwa1@linux.ibm.com>
To: Jeff Law <jeffreyalaw@gmail.com>, gcc-patches <gcc-patches@gcc.gnu.org>
Cc: Richard Biener <richard.guenther@gmail.com>,
Peter Bergner <bergner@linux.ibm.com>,
Segher Boessenkool <segher@kernel.crashing.org>
Subject: [PATCH 3/4] Improve functionality of ree pass.
Date: Mon, 4 Sep 2023 13:27:42 +0530 [thread overview]
Message-ID: <1bb09ed3-460d-c9c1-0d36-6a8ad2557728@linux.ibm.com> (raw)
Hello Jeff:
This patch eliminates redundant zero and sign extension with ree pass for rs6000
target.
Bootstrapped and regtested for powerpc64-linux-gnu.
Thanks & Regards
Ajit
ree: Improve ree pass
For rs6000 target we see redundant zero and sign extension and ree pass
s improved to eliminate such redundant zero and sign extension. Support of
zero_extend/sign_extend/AND.
2023-09-04 Ajit Kumar Agarwal <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 | 487 ++++++++++++++++--
gcc/rtl.h | 1 +
gcc/rtlanal.cc | 15 +
gcc/testsuite/g++.target/powerpc/sext-elim.C | 17 +
.../g++.target/powerpc/zext-elim-1.C | 19 +
.../g++.target/powerpc/zext-elim-2.C | 11 +
gcc/testsuite/g++.target/powerpc/zext-elim.C | 30 ++
7 files changed, 534 insertions(+), 46 deletions(-)
create mode 100644 gcc/testsuite/g++.target/powerpc/sext-elim.C
create mode 100644 gcc/testsuite/g++.target/powerpc/zext-elim-1.C
create mode 100644 gcc/testsuite/g++.target/powerpc/zext-elim-2.C
create mode 100644 gcc/testsuite/g++.target/powerpc/zext-elim.C
diff --git a/gcc/ree.cc b/gcc/ree.cc
index fc04249fa84..931b9b08821 100644
--- a/gcc/ree.cc
+++ b/gcc/ree.cc
@@ -253,6 +253,77 @@ struct ext_cand
static int max_insn_uid;
+/* Return TRUE if OP can be considered a zero extension from one or
+ more sub-word modes to larger modes up to a full word.
+
+ For example (and:DI (reg) (const_int X))
+
+ Depending on the value of X could be considered a zero extension
+ from QI, HI and SI to larger modes up to DImode. */
+
+static bool
+rtx_is_zext_p (rtx insn)
+{
+ if (GET_CODE (insn) == AND)
+ {
+ rtx set = XEXP (insn, 0);
+ if (REG_P (set))
+ {
+ rtx src = XEXP (insn, 1);
+ machine_mode m_mode = GET_MODE (set);
+
+ if (CONST_INT_P (src)
+ && (INTVAL (src) == 1
+ || (m_mode == QImode && INTVAL (src) == 0x7)
+ || (m_mode == QImode && INTVAL (src) == 0x0000007F)
+ || (m_mode == HImode && INTVAL (src) == 0x00007FFF)
+ || (m_mode == SImode && INTVAL (src) == 0x007FFFFF)))
+ return true;
+
+ }
+ else
+ return false;
+ }
+
+ return false;
+}
+/* Return TRUE if OP can be considered a zero extension from one or
+ more sub-word modes to larger modes up to a full word.
+
+ For example (and:DI (reg) (const_int X))
+
+ Depending on the value of X could be considered a zero extension
+ from QI, HI and SI to larger modes up to DImode. */
+
+static bool
+rtx_is_zext_p (rtx_insn *insn)
+{
+ rtx body = single_set (insn);
+
+ if (GET_CODE (body) == SET && GET_CODE (SET_SRC (body)) == AND)
+ {
+ rtx set = XEXP (SET_SRC (body), 0);
+
+ if (REG_P (set) && GET_MODE (SET_DEST (body)) == GET_MODE (set))
+ {
+ rtx src = XEXP (SET_SRC (body), 1);
+ machine_mode m_mode = GET_MODE (set);
+
+ if (CONST_INT_P (src)
+ && (INTVAL (src) == 1
+ || (m_mode == QImode && INTVAL (src) == 0x7)
+ || (m_mode == QImode && INTVAL (src) == 0x0000007F)
+ || (m_mode == HImode && INTVAL (src) == 0x00007FFF)
+ || (m_mode == SImode && INTVAL (src) == 0x007FFFFF)))
+ return true;
+ }
+ else
+ return false;
+ }
+
+ return false;
+}
+
/* Update or remove REG_EQUAL or REG_EQUIV notes for INSN. */
static bool
@@ -319,7 +390,7 @@ combine_set_extension (ext_cand *cand, rtx_insn *curr_insn, rtx *orig_set)
{
rtx orig_src = SET_SRC (*orig_set);
machine_mode orig_mode = GET_MODE (SET_DEST (*orig_set));
- rtx new_set;
+ rtx new_set = NULL_RTX;
rtx cand_pat = single_set (cand->insn);
/* If the extension's source/destination registers are not the same
@@ -359,27 +430,41 @@ combine_set_extension (ext_cand *cand, rtx_insn *curr_insn, rtx *orig_set)
else if (GET_CODE (orig_src) == cand->code)
{
/* Here is a sequence of two extensions. Try to merge them. */
- rtx temp_extension
- = gen_rtx_fmt_e (cand->code, cand->mode, XEXP (orig_src, 0));
+ rtx temp_extension = NULL_RTX;
+ if (GET_CODE (SET_SRC (cand_pat)) == AND)
+ temp_extension
+ = gen_rtx_AND (cand->mode, XEXP (orig_src, 0), XEXP (orig_src, 1));
+ else
+ temp_extension
+ = gen_rtx_fmt_e (cand->code, cand->mode, XEXP (orig_src, 0));
rtx simplified_temp_extension = simplify_rtx (temp_extension);
if (simplified_temp_extension)
temp_extension = simplified_temp_extension;
+
new_set = gen_rtx_SET (new_reg, temp_extension);
}
else if (GET_CODE (orig_src) == IF_THEN_ELSE)
{
/* Only IF_THEN_ELSE of phi-type copies are combined. Otherwise,
- in general, IF_THEN_ELSE should not be combined. */
- return false;
+ in general, IF_THEN_ELSE should not be combined. Relaxed
+ cases with IF_THEN_ELSE across basic blocls */
+ return true;
}
else
{
/* This is the normal case. */
- rtx temp_extension
+ rtx temp_extension = NULL_RTX;
+
+ if (GET_CODE (SET_SRC (cand_pat)) == AND)
+ temp_extension
+ = gen_rtx_AND (cand->mode, orig_src, XEXP (SET_SRC (cand_pat), 1));
+ else
+ temp_extension
= gen_rtx_fmt_e (cand->code, cand->mode, orig_src);
rtx simplified_temp_extension = simplify_rtx (temp_extension);
if (simplified_temp_extension)
temp_extension = simplified_temp_extension;
+
new_set = gen_rtx_SET (new_reg, temp_extension);
}
@@ -468,12 +553,13 @@ get_defs (rtx_insn *insn, rtx reg, vec<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 +567,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 +784,258 @@ get_sub_rtx (rtx_insn *def_insn)
return sub_rtx;
}
+/* Return TRUE if reaching definition of def_insn source operand
+ has has arithmetic peration like ASHIFT and LSHIFTRT. If TRUE
+ don't eliminate sign extension */
+
+static bool
+def_arith_p (rtx_insn *insn, rtx orig_src)
+{
+ if (!REG_P (orig_src))
+ return true;
+
+ vec<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 +1051,32 @@ merge_def_and_ext (ext_cand *cand, rtx_insn *def_insn, ext_state *state)
if (sub_rtx == NULL)
return false;
- if (GET_MODE (SET_DEST (*sub_rtx)) == ext_src_mode
- || ((state->modified[INSN_UID (def_insn)].kind
- == (cand->code == ZERO_EXTEND
+ bool copy_needed
+ = (REGNO (SET_DEST (cand->expr)) != REGNO (XEXP (SET_SRC (cand->expr), 0)));
+
+ bool feasible = eliminate_across_bbs_p (cand, def_insn);
+
+ if (!feasible) return false;
+
+ /* Combine zero_extend/sign_extend/AND and if sign_extend and
+ mode of DEST and SRC are different. */
+
+ bool is_zext = rtx_is_zext_p (cand->insn)
+ || cand->code == ZERO_EXTEND
+ || cand->code == SIGN_EXTEND;
+
+ bool do_elimination = !copy_needed
+ && is_zext
+ && (cand->code == SIGN_EXTEND
+ || GET_MODE (SET_DEST (*sub_rtx)) != ext_src_mode);
+
+ if (((do_elimination
+ && state->modified[INSN_UID (def_insn)].kind == EXT_MODIFIED_NONE))
+ || ((state->modified[INSN_UID (def_insn)].kind
+ == (cand->code == ZERO_EXTEND
? EXT_MODIFIED_ZEXT : EXT_MODIFIED_SEXT))
- && state->modified[INSN_UID (def_insn)].mode
- == ext_src_mode))
+ && state->modified[INSN_UID (def_insn)].mode
+ == ext_src_mode))
{
if (GET_MODE_UNIT_SIZE (GET_MODE (SET_DEST (*sub_rtx)))
>= GET_MODE_UNIT_SIZE (cand->mode))
@@ -734,7 +1092,6 @@ merge_def_and_ext (ext_cand *cand, rtx_insn *def_insn, ext_state *state)
return true;
}
}
-
return false;
}
@@ -744,7 +1101,9 @@ merge_def_and_ext (ext_cand *cand, rtx_insn *def_insn, ext_state *state)
static inline rtx
get_extended_src_reg (rtx src)
{
- while (GET_CODE (src) == SIGN_EXTEND || GET_CODE (src) == ZERO_EXTEND)
+ while (GET_CODE (src) == SIGN_EXTEND
+ || GET_CODE (src) == ZERO_EXTEND
+ || rtx_is_zext_p (src))
src = XEXP (src, 0);
gcc_assert (REG_P (src));
return src;
@@ -882,8 +1241,7 @@ combine_reaching_defs (ext_cand *cand, const_rtx set_pat, ext_state *state)
/* The destination register of the extension insn must not be
used or set between the def_insn and cand->insn exclusive. */
- if (reg_used_between_p (SET_DEST (set), def_insn, cand->insn)
- || reg_set_between_p (SET_DEST (set), def_insn, cand->insn))
+ if (reg_used_set_between_p (SET_DEST (set), def_insn, cand->insn))
return false;
/* We must be able to copy between the two registers. Generate,
@@ -975,10 +1333,8 @@ combine_reaching_defs (ext_cand *cand, const_rtx set_pat, ext_state *state)
used or set between the def_insn2 and def_insn exclusive.
Likewise for the other reg, i.e. check both reg1 and reg2
in the above comment. */
- if (reg_used_between_p (SET_DEST (set), def_insn2, def_insn)
- || reg_set_between_p (SET_DEST (set), def_insn2, def_insn)
- || reg_used_between_p (src_reg, def_insn2, def_insn)
- || reg_set_between_p (src_reg, def_insn2, def_insn))
+ if (reg_used_set_between_p (SET_DEST (set), def_insn2, def_insn)
+ || reg_used_set_between_p (src_reg, def_insn2, def_insn))
break;
state->defs_list[0] = def_insn2;
@@ -1004,15 +1360,17 @@ combine_reaching_defs (ext_cand *cand, const_rtx set_pat, ext_state *state)
cand->mode = mode;
}
- merge_successful = true;
-
+ merge_successful = false;
/* Go through the defs vector and try to merge all the definitions
in this vector. */
state->modified_list.truncate (0);
FOR_EACH_VEC_ELT (state->defs_list, defs_ix, def_insn)
{
if (merge_def_and_ext (cand, def_insn, state))
- state->modified_list.safe_push (def_insn);
+ {
+ merge_successful = true;
+ state->modified_list.safe_push (def_insn);
+ }
else
{
merge_successful = false;
@@ -1045,34 +1403,71 @@ combine_reaching_defs (ext_cand *cand, const_rtx set_pat, ext_state *state)
definitions could be merged. */
if (apply_change_group ())
{
- if (dump_file)
- fprintf (dump_file, "All merges were successful.\n");
+ if (state->modified_list.length() == 0)
+ return false;
+
+ rtx_insn *insn = state->modified_list[0];
+
+ if ((cand->code == ZERO_EXTEND || cand->code == SIGN_EXTEND)
+ && GET_CODE (PATTERN (insn)) == SET
+ && GET_CODE (SET_SRC (PATTERN (insn))) != XOR
+ && GET_CODE (SET_SRC (PATTERN (insn))) != PLUS
+ && GET_CODE (SET_SRC (PATTERN (insn))) != IOR)
+ return false;
+
+ if (dump_file)
+ fprintf (dump_file, "All merges were successful.\n");
FOR_EACH_VEC_ELT (state->modified_list, i, def_insn)
{
ext_modified *modified = &state->modified[INSN_UID (def_insn)];
if (modified->kind == EXT_MODIFIED_NONE)
modified->kind = (cand->code == ZERO_EXTEND ? EXT_MODIFIED_ZEXT
- : EXT_MODIFIED_SEXT);
+ : EXT_MODIFIED_SEXT);
if (copy_needed)
modified->do_not_reextend = 1;
}
return true;
}
- else
- {
- /* Changes need not be cancelled explicitly as apply_change_group
- does it. Print list of definitions in the dump_file for debug
- purposes. This extension cannot be deleted. */
- if (dump_file)
- {
- fprintf (dump_file,
- "Merge cancelled, non-mergeable definitions:\n");
- FOR_EACH_VEC_ELT (state->modified_list, i, def_insn)
- print_rtl_single (dump_file, def_insn);
- }
- }
+ else
+ {
+ if (state->modified_list.length() == 0)
+ return false;
+
+ rtx_insn *insn = state->modified_list[0];
+
+ if ((cand->code == ZERO_EXTEND || cand->code == SIGN_EXTEND)
+ && GET_CODE (PATTERN (insn)) == SET
+ && GET_CODE (SET_SRC (PATTERN (insn))) != XOR
+ && GET_CODE (SET_SRC (PATTERN (insn))) != PLUS
+ && GET_CODE (SET_SRC (PATTERN (insn))) != IOR)
+ return false;
+
+ if (cand->code == ZERO_EXTEND || cand->code == SIGN_EXTEND)
+ {
+ FOR_EACH_VEC_ELT (state->modified_list, i, def_insn)
+ {
+ ext_modified *modified = &state->modified[INSN_UID (def_insn)];
+ if (modified->kind == EXT_MODIFIED_NONE)
+ modified->kind = (cand->code == ZERO_EXTEND ? EXT_MODIFIED_ZEXT
+ : EXT_MODIFIED_SEXT);
+
+ modified->do_not_reextend = 1;
+ }
+ return true;
+ }
+ /* Changes need not be cancelled explicitly as apply_change_group
+ does it. Print list of definitions in the dump_file for debug
+ purposes. This extension cannot be deleted. */
+ if (dump_file)
+ {
+ fprintf (dump_file,
+ "Merge cancelled, non-mergeable definitions:\n");
+ FOR_EACH_VEC_ELT (state->modified_list, i, def_insn)
+ print_rtl_single (dump_file, def_insn);
+ }
+ }
}
else
{
@@ -1106,7 +1501,7 @@ add_removable_extension (const_rtx expr, rtx_insn *insn,
mode = GET_MODE (dest);
if (REG_P (dest)
- && (code == SIGN_EXTEND || code == ZERO_EXTEND)
+ && (code == SIGN_EXTEND || code == ZERO_EXTEND || rtx_is_zext_p (src))
&& REG_P (XEXP (src, 0)))
{
rtx reg = XEXP (src, 0);
@@ -1125,7 +1520,7 @@ add_removable_extension (const_rtx expr, rtx_insn *insn,
fprintf (dump_file, "Cannot eliminate extension:\n");
print_rtl_single (dump_file, insn);
fprintf (dump_file, " because it can operate on uninitialized"
- " data\n");
+ " data\n");
}
return;
}
@@ -1320,8 +1715,8 @@ find_and_remove_re (void)
if (REG_P (XEXP (SET_SRC (set), 0))
&& (REGNO (SET_DEST (set)) != REGNO (XEXP (SET_SRC (set), 0))))
{
- reinsn_copy_list.safe_push (curr_cand->insn);
- reinsn_copy_list.safe_push (state.defs_list[0]);
+ reinsn_copy_list.safe_push (curr_cand->insn);
+ reinsn_copy_list.safe_push (state.defs_list[0]);
}
reinsn_del_list.safe_push (curr_cand->insn);
state.modified[INSN_UID (curr_cand->insn)].deleted = 1;
diff --git a/gcc/rtl.h b/gcc/rtl.h
index 0e9491b89b4..f47e41b9037 100644
--- a/gcc/rtl.h
+++ b/gcc/rtl.h
@@ -3636,6 +3636,7 @@ extern int count_occurrences (const_rtx, const_rtx, int);
extern bool reg_referenced_p (const_rtx, const_rtx);
extern bool reg_used_between_p (const_rtx, const rtx_insn *, const rtx_insn *);
extern bool reg_set_between_p (const_rtx, const rtx_insn *, const rtx_insn *);
+extern bool reg_used_set_between_p (rtx, rtx_insn *, rtx_insn *);
extern int commutative_operand_precedence (rtx);
extern bool swap_commutative_operands_p (rtx, rtx);
extern bool modified_between_p (const_rtx, const rtx_insn *, const rtx_insn *);
diff --git a/gcc/rtlanal.cc b/gcc/rtlanal.cc
index 8b48fc243a1..d971777c630 100644
--- a/gcc/rtlanal.cc
+++ b/gcc/rtlanal.cc
@@ -1134,6 +1134,21 @@ no_labels_between_p (const rtx_insn *beg, const rtx_insn *end)
return true;
}
+/* The register reg of the extension to_insn must not be
+ used or set between the from_insn and to_insn exclusive. */
+
+bool
+reg_used_set_between_p (rtx reg,
+ rtx_insn *from_insn,
+ rtx_insn *to_insn)
+{
+ if (reg_used_between_p (reg, from_insn, to_insn)
+ || reg_set_between_p (reg, from_insn, to_insn))
+ return true;
+
+ return false;
+}
+
/* Return true if register REG is used in an insn between
FROM_INSN and TO_INSN (exclusive of those two). */
diff --git a/gcc/testsuite/g++.target/powerpc/sext-elim.C b/gcc/testsuite/g++.target/powerpc/sext-elim.C
new file mode 100644
index 00000000000..36fef0b7a2f
--- /dev/null
+++ b/gcc/testsuite/g++.target/powerpc/sext-elim.C
@@ -0,0 +1,17 @@
+/* { dg-do compile { target { powerpc*-*-* } } } */
+/* { dg-require-effective-target lp64 } */
+/* { dg-require-effective-target powerpc_p9vector_ok } */
+/* { dg-options "-mcpu=power9 -O2 -free" } */
+
+unsigned long c2l(unsigned char* p)
+{
+ unsigned long res = *p + *(p+1);
+ return res;
+}
+
+long c2sl(signed char* p)
+{
+ long res = *p + *(p+1);
+ return res;
+}
+/* { dg-final { scan-assembler-not "extsw" } } */
diff --git a/gcc/testsuite/g++.target/powerpc/zext-elim-1.C b/gcc/testsuite/g++.target/powerpc/zext-elim-1.C
new file mode 100644
index 00000000000..bc6cc0eb3ca
--- /dev/null
+++ b/gcc/testsuite/g++.target/powerpc/zext-elim-1.C
@@ -0,0 +1,19 @@
+/* { dg-do compile { target { powerpc*-*-* } } } */
+/* { dg-require-effective-target lp64 } */
+/* { dg-require-effective-target powerpc_p9vector_ok } */
+/* { dg-options "-mcpu=power9 -O2 -free" } */
+
+extern unsigned char magic1[256];
+
+unsigned int hash(const unsigned char inp[4])
+{
+ const unsigned long long INIT = 0x1ULL;
+ unsigned long long h1 = INIT;
+ h1 = magic1[((unsigned long long)inp[0]) ^ h1];
+ h1 = magic1[((unsigned long long)inp[1]) ^ h1];
+ h1 = magic1[((unsigned long long)inp[2]) ^ h1];
+ h1 = magic1[((unsigned long long)inp[3]) ^ h1];
+ return h1;
+}
+
+/* { dg-final { scan-assembler-not "rlwinm" } } */
diff --git a/gcc/testsuite/g++.target/powerpc/zext-elim-2.C b/gcc/testsuite/g++.target/powerpc/zext-elim-2.C
new file mode 100644
index 00000000000..4e72925104f
--- /dev/null
+++ b/gcc/testsuite/g++.target/powerpc/zext-elim-2.C
@@ -0,0 +1,11 @@
+/* { dg-do compile { target { powerpc*-*-* } } } */
+/* { dg-require-effective-target lp64 } */
+/* { dg-require-effective-target powerpc_p9vector_ok } */
+/* { dg-options "-mcpu=power9 -O2 -free" } */
+
+unsigned char g(unsigned char t[], unsigned char v)
+{
+ return (t[v & 0x7f] & 0x7f) | (v & 0x80);
+}
+
+/* { dg-final { scan-assembler-times "rlwinm" 2 } } */
diff --git a/gcc/testsuite/g++.target/powerpc/zext-elim.C b/gcc/testsuite/g++.target/powerpc/zext-elim.C
new file mode 100644
index 00000000000..56eabbe0c19
--- /dev/null
+++ b/gcc/testsuite/g++.target/powerpc/zext-elim.C
@@ -0,0 +1,30 @@
+/* { dg-do compile { target { powerpc*-*-* } } } */
+/* { dg-require-effective-target lp64 } */
+/* { dg-require-effective-target powerpc_p9vector_ok } */
+/* { dg-options "-mcpu=power9 -O2 -free" } */
+
+#include <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" } } */
--
2.39.3
next reply other threads:[~2023-09-04 7:57 UTC|newest]
Thread overview: 6+ messages / expand[flat|nested] mbox.gz Atom feed top
2023-09-04 7:57 Ajit Agarwal [this message]
2023-09-12 7:20 ` [PING ^0][PATCH " Ajit Agarwal
2023-09-19 9:21 ` [PATCH v2 3/4] Improve functionality of ree pass with various constants with AND operation Ajit Agarwal
2023-10-15 12:58 ` [PING ^0] " Ajit Agarwal
2023-11-10 7:09 ` [PING ^1] " Ajit Agarwal
2023-11-27 4:43 ` [PING ^2] " 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=1bb09ed3-460d-c9c1-0d36-6a8ad2557728@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).