This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
RFA: MN10300: Add redundant comparison elimination pass
- From: Nick Clifton <nickc at redhat dot com>
- To: rth at redhat dot com, law at redhat dot com, aoliva at redhat dot com
- Cc: gcc-patches at gcc dot gnu dot org
- Date: Wed, 10 Nov 2010 08:34:11 +0000
- Subject: RFA: MN10300: Add redundant comparison elimination pass
Hi Guys,
As Richard pointed out my previous patch (for LIW/SETLB) included a
separate feature which should have been submitted on its own. So here
it is - a machine reorg pass to eliminate redundant compares.
The scan could be improved to look further back through the
instruction stream for insns that set the EPSW register, but I am
leaving that for a future patch.
Tested without regressions on an mn10300-elf toolchain.
OK to apply ?
Cheers
Nick
gcc/ChangeLog
2010-11-10 Nick Clifton <nickc@redhat.com>
* config/mn10300/mn10300.c (scan_for_redundant_compares): New
function.
(mn10300_reorg): New function.
(TARGET_MACHINE_DEPENDENT_REORG): Define.
Index: gcc/config/mn10300/mn10300.c
===================================================================
--- gcc/config/mn10300/mn10300.c (revision 166474)
+++ gcc/config/mn10300/mn10300.c (working copy)
@@ -2403,6 +2403,128 @@
/* Extract the latency value from the timings attribute. */
return timings < 100 ? (timings % 10) : (timings % 100);
}
+
+static void
+scan_for_redundant_compares (void)
+{
+ rtx cur_insn;
+
+ /* Look for this sequence:
+
+ (set (reg X) (arith_op (...)))
+ (set (reg CC) (compare (reg X) (const_int 0)))
+ (set (pc) (if_then_else (EQ|NE (...)) (...) (...)))
+
+ And remove the compare as the flags in the
+ EPSW register will already be correctly set. */
+ for (cur_insn = get_insns (); cur_insn != NULL; cur_insn = NEXT_INSN (cur_insn))
+ {
+ rtx pattern;
+
+ if (! INSN_P (cur_insn))
+ continue;
+
+ pattern = PATTERN (cur_insn);
+
+ if (GET_CODE (pattern) == SET
+ && GET_CODE (SET_SRC (pattern)) == COMPARE
+ /* Paranoia checks: */
+ && REG_P (SET_DEST (pattern))
+ && REGNO (SET_DEST (pattern)) == CC_REG
+ && REG_P (XEXP (SET_SRC (pattern), 0))
+ /* Normal checks: */
+ && CONST_INT_P (XEXP (SET_SRC (pattern), 1))
+ && INTVAL (XEXP (SET_SRC (pattern), 1)) == 0)
+ {
+ rtx prev_insn, branch, condition;
+ unsigned int compare_reg;
+
+ /* FIXME: We should scan backwards until the first ESPW
+ setter or clobber insn is found (or the beginning of
+ the block). At the moment we just look back one insn. */
+ prev_insn = prev_nonnote_insn (cur_insn);
+
+ if (prev_insn == NULL || ! INSN_P (prev_insn))
+ continue;
+
+ /* An UNSPEC might be an LIW insn which will not set the
+ condition code flags in a way that we currently expect. */
+ if (GET_CODE (PATTERN (prev_insn)) == UNSPEC)
+ continue;
+
+ if (GET_CODE (PATTERN (prev_insn)) != PARALLEL
+ || XVECLEN (PATTERN (prev_insn), 0) != 2
+ || GET_CODE (XVECEXP (PATTERN (prev_insn), 0, 0)) != SET)
+ continue;
+
+ compare_reg = REGNO (XEXP (SET_SRC (pattern), 0));
+ pattern = XVECEXP (PATTERN (prev_insn), 0, 0);
+
+ if (! REG_P (SET_DEST (pattern))
+ || REGNO (SET_DEST (pattern)) != compare_reg)
+ continue;
+
+ branch = next_nonnote_insn (cur_insn);
+ if (branch == NULL || ! JUMP_P (branch)
+ || GET_CODE (PATTERN (branch)) != SET
+ || GET_CODE (SET_SRC (PATTERN (branch))) != IF_THEN_ELSE)
+ continue;
+ condition = XEXP (SET_SRC (PATTERN (branch)), 0);
+
+ switch (GET_CODE (condition))
+ {
+ case EQ:
+ case NE:
+ break;
+ default:
+ continue;
+ }
+
+ /* Adding 1 or 4 to an address register results in an
+ INC/INC4 instruction that doesn't set the flags. */
+ if (GET_CODE (SET_SRC (pattern)) == PLUS
+ && REG_P (SET_DEST (pattern))
+ && REGNO (SET_DEST (pattern)) >= FIRST_ADDRESS_REGNUM
+ && REGNO (SET_DEST (pattern)) <= LAST_ADDRESS_REGNUM
+ && REG_P (XEXP (SET_SRC (pattern), 0))
+ && REGNO (XEXP (SET_SRC (pattern), 0)) == REGNO (SET_DEST (pattern))
+ && CONST_INT_P (XEXP (SET_SRC (pattern), 1))
+ && (INTVAL (XEXP (SET_SRC (pattern), 1)) == 1
+ || INTVAL (XEXP (SET_SRC (pattern), 1)) == 4))
+ continue;
+
+ switch (GET_CODE (SET_SRC (pattern)))
+ {
+ case PLUS:
+ case MINUS:
+ case MULT:
+#if 0
+ /* Some alternatives in the AND pattern use EXTBU which does
+ not set the flags. Hence a CMP following an AND might be
+ needed. */
+ case AND:
+#endif
+ case XOR:
+ case NOT:
+ case ASHIFT:
+ case LSHIFTRT:
+ case ASHIFTRT:
+ delete_insn (cur_insn);
+ break;
+ default:
+ break;
+ }
+ }
+ }
+}
+
+/* Implements TARGET_MACHINE_DEPENDENT_REORG. */
+
+static void
+mn10300_reorg (void)
+{
+ scan_for_redundant_compares ();
+}
/* Initialize the GCC target structure. */
@@ -2481,4 +2603,7 @@
#undef TARGET_SCHED_ADJUST_COST
#define TARGET_SCHED_ADJUST_COST mn10300_adjust_sched_cost
+#undef TARGET_MACHINE_DEPENDENT_REORG
+#define TARGET_MACHINE_DEPENDENT_REORG mn10300_reorg
+
struct gcc_target targetm = TARGET_INITIALIZER;