Hi,
The attached patch fixes the deficits mentioned in PR 83831 which is
about unused bclr, bnot and bset instructions.
For some simple cases, the combine pass can successfully fuse a load-
modify-store insn sequence into an insn that operates on a memory
directly. However, in some cases where it thinks it's too complex, it
will not try to combine the insns.
What I'm doing here is similar to what I've been doing on SH in the
split1 pass after combine -- manually walking the insns up/down
(limited to the BB) to find the def/use and fuse 3 insns into 1, if
it's possible to do so.
For that I've copy-pasted some of the RTL utility functions from SH. I
will propose folding and moving those into rtl.h / rtlanal.c during
next stage 1.
With that patch, I get a code size decrease of about 1 KByte on a
larger application.
The attached patch is the version for GCC 8 (trunk). I've posted
versions for GCC 6 and GCC 7 in the PR. All 3 patches have been tested
with
"make -k check" on rx-sim for c and c++
with no new failures.
OK for trunk?
Cheers,
Oleg
gcc/ChangeLog:
PR target/83831
* config/rx/rx-protos.h (rx_reg_dead_or_unused_after_insn,
rx_copy_reg_dead_or_unused_notes, rx_fuse_in_memory_bitop): New
declarations.
(set_of_reg): New struct.
(rx_find_set_of_reg, rx_find_use_of_reg): New functions.
* config/rx/rx.c (rx_reg_dead_or_unused_after_insn,
rx_copy_reg_dead_or_unused_notes, rx_fuse_in_memory_bitop): New
functions.
* config/rx/rx.md (andsi3, iorsi3, xorsi3): Convert to insn_and_split.
Split into bitclr, bitset, bitinvert patterns if appropriate.
(*bitset, *bitinvert, *bitclr): Convert to named insn_and_split and
use rx_fuse_in_memory_bitop.
(*bitset_in_memory, *bitinvert_in_memory, *bitclr_in_memory): Convert
to named insn, correct maximum insn length.
gcc/testsuite/ChangeLog:
PR target/83831
* gcc.target/rx/pr83831.c: New tests.Index: gcc/config/rx/rx-protos.h
===
--- gcc/config/rx/rx-protos.h (revision 257549)
+++ gcc/config/rx/rx-protos.h (working copy)
@@ -63,6 +63,112 @@
extern void rx_split_cbranch (machine_mode, enum rtx_code,
rtx, rtx, rtx);
extern machine_mode rx_select_cc_mode (enum rtx_code, rtx, rtx);
+
+extern bool rx_reg_dead_or_unused_after_insn (const rtx_insn* i, int regno);
+extern void rx_copy_reg_dead_or_unused_notes (rtx reg, const rtx_insn* src,
+ rtx_insn* dst);
+
+extern bool rx_fuse_in_memory_bitop (rtx* operands, rtx_insn* curr_insn,
+ rtx (*gen_insn)(rtx, rtx));
+
+/* Result value of rx_find_set_of_reg. */
+struct set_of_reg
+{
+ /* The insn where sh_find_set_of_reg stopped looking.
+ Can be NULL_RTX if the end of the insn list was reached. */
+ rtx_insn* insn;
+
+ /* The set rtx of the specified reg if found, NULL_RTX otherwise. */
+ const_rtx set_rtx;
+
+ /* The set source rtx of the specified reg if found, NULL_RTX otherwise.
+ Usually, this is the most interesting return value. */
+ rtx set_src;
+};
+
+/* FIXME: Copy-pasta from SH. Move to rtl.h.
+ Given a reg rtx and a start insn, try to find the insn that sets
+ the specified reg by using the specified insn stepping function,
+ such as 'prev_nonnote_nondebug_insn_bb'. When the insn is found,
+ try to extract the rtx of the reg set. */
+template inline set_of_reg
+rx_find_set_of_reg (rtx reg, rtx_insn* insn, F stepfunc,
+ bool ignore_reg_reg_copies = false)
+{
+ set_of_reg result;
+ result.insn = insn;
+ result.set_rtx = NULL_RTX;
+ result.set_src = NULL_RTX;
+
+ if (!REG_P (reg) || insn == NULL_RTX)
+return result;
+
+ for (rtx_insn* i = stepfunc (insn); i != NULL_RTX; i = stepfunc (i))
+{
+ if (BARRIER_P (i))
+ break;
+ if (!INSN_P (i) || DEBUG_INSN_P (i))
+ continue;
+ if (reg_set_p (reg, i))
+ {
+ if (CALL_P (i))
+ break;
+
+ result.insn = i;
+ result.set_rtx = set_of (reg, i);
+
+ if (result.set_rtx == NULL_RTX || GET_CODE (result.set_rtx) != SET)
+ break;
+
+ result.set_src = XEXP (result.set_rtx, 1);
+
+ if (ignore_reg_reg_copies && REG_P (result.set_src))
+ {
+ reg = result.set_src;
+ continue;
+ }
+ if (ignore_reg_reg_copies && SUBREG_P (result.set_src)
+ && REG_P (SUBREG_REG (result.set_src)))
+ {
+ reg = SUBREG_REG (result.set_src);
+ continue;
+ }
+
+ break;
+ }
+}
+
+ /* If the searched reg is found inside a (mem (post_inc:SI (reg))), set_of
+ will return NULL and set_rtx will be NULL.
+ In this case report a 'not found'. result.insn will always be non-null
+ at this point, so no need to check it. */
+ if (result.set_src != NULL && result.set_rtx == NULL)
+result.set_src = NULL;
+
+ return result;
+}
+
+/* FIXME: Move to rtlh.h. */
+template inline rtx_insn*
+rx_find_use_of_reg (rtx reg, rtx_insn* insn, F