This patch is the main bulk of this submission. It modifies the compare
combining part of try_combine(), adding a call of
CANONICALIZE_COMPARISON into the entire logic.
Also, instead of testing for XEXP(SET_SRC(PATTERN(i3)),1) == const0_rtx
at the top, it now allows CONST_INT_P(XEXP(SET_SRC(PATTERN(i3)),1)),
tries to adjust it by simplify_compare_const() from the last patch, and
then tests if op1 == const0_rtx. This is a small improvement in some cases.
(if you remove the call to simplify_compare_const(), and if
CANONICALIZE_COMPARISON is not defined for the target, then this entire
patch should be an 'idempotent patch', nothing should be changed to the
effective combine results)
One issue that I would like to RFC, is the use of
CANONICALIZE_COMPARISON here; I'm afraid I might be abusing it. Since
added_sets_2 is set here, the value of i2src/op0 is needed afterwards.
This might not be conformant to the description of
CANONICALIZE_COMPARISON in the internals manual, which doesn't say it
can't trash op0 under arbitrary conditions while only preserving the
comparison result.
OTOH, I don't see another suitable macro/hook (with a close enough
meaning), and the current definitions of CANONICALIZE_COMPARISON across
the targets do not seem to clash with my use here. Does this macro use
look okay, or does this justify creating a new one?
Thanks,
Chung-Lin
Index: combine.c
===================================================================
--- combine.c (revision 172860)
+++ combine.c (working copy)
@@ -3046,58 +3047,89 @@
if (i1 == 0 && added_sets_2 && GET_CODE (PATTERN (i3)) == SET
&& GET_CODE (SET_SRC (PATTERN (i3))) == COMPARE
- && XEXP (SET_SRC (PATTERN (i3)), 1) == const0_rtx
+ && CONST_INT_P (XEXP (SET_SRC (PATTERN (i3)), 1))
&& rtx_equal_p (XEXP (SET_SRC (PATTERN (i3)), 0), i2dest))
{
-#ifdef SELECT_CC_MODE
- rtx *cc_use;
- enum machine_mode compare_mode;
-#endif
+ rtx newpat_dest;
+ rtx *cc_use_loc = NULL, cc_use_insn = NULL_RTX;
+ rtx op0 = i2src, op1 = XEXP (SET_SRC (PATTERN (i3)), 1);
+ enum machine_mode compare_mode, orig_compare_mode;
+ enum rtx_code compare_code = UNKNOWN, orig_compare_code = UNKNOWN;
newpat = PATTERN (i3);
- SUBST (XEXP (SET_SRC (newpat), 0), i2src);
+ newpat_dest = SET_DEST (newpat);
+ compare_mode = orig_compare_mode = GET_MODE (newpat_dest);
- i2_is_used = 1;
-
-#ifdef SELECT_CC_MODE
- /* See if a COMPARE with the operand we substituted in should be done
- with the mode that is currently being used. If not, do the same
- processing we do in `subst' for a SET; namely, if the destination
- is used only once, try to replace it with a register of the proper
- mode and also replace the COMPARE. */
if (undobuf.other_insn == 0
- && (cc_use = find_single_use (SET_DEST (newpat), i3,
- &undobuf.other_insn))
- && ((compare_mode = SELECT_CC_MODE (GET_CODE (*cc_use),
- i2src, const0_rtx))
- != GET_MODE (SET_DEST (newpat))))
+ && (cc_use_loc = find_single_use (SET_DEST (newpat), i3,
+ &cc_use_insn)))
{
- if (can_change_dest_mode (SET_DEST (newpat), added_sets_2,
- compare_mode))
+ compare_code = orig_compare_code = GET_CODE (*cc_use_loc);
+ compare_code = simplify_compare_const (compare_code,
+ op0, &op1);
+#ifdef CANONICALIZE_COMPARISON
+ CANONICALIZE_COMPARISON (compare_code, op0, op1);
+#endif
+ }
+
+ /* Do the rest only if op1 is const0_rtx, which may be the
+ result of simplification. */
+ if (op1 == const0_rtx)
+ {
+ if (cc_use_loc)
{
- unsigned int regno = REGNO (SET_DEST (newpat));
- rtx new_dest;
-
- if (regno < FIRST_PSEUDO_REGISTER)
- new_dest = gen_rtx_REG (compare_mode, regno);
- else
+#ifdef SELECT_CC_MODE
+ enum machine_mode new_mode
+ = SELECT_CC_MODE (compare_code, op0, op1);
+ if (new_mode != orig_compare_mode
+ && can_change_dest_mode (SET_DEST (newpat),
+ added_sets_2, new_mode))
{
- SUBST_MODE (regno_reg_rtx[regno], compare_mode);
- new_dest = regno_reg_rtx[regno];
+ unsigned int regno = REGNO (newpat_dest);
+ compare_mode = new_mode;
+ if (regno < FIRST_PSEUDO_REGISTER)
+ newpat_dest = gen_rtx_REG (compare_mode, regno);
+ else
+ {
+ SUBST_MODE (regno_reg_rtx[regno], compare_mode);
+ newpat_dest = regno_reg_rtx[regno];
+ }
}
+#endif
+ /* Cases for modifying the CC-using comparison. */
+ if (compare_code != orig_compare_code
+ /* ??? Do we need to verify the zero rtx? */
+ && XEXP (*cc_use_loc, 1) == const0_rtx)
+ {
+ /* Replace cc_use_loc with entire new RTX. */
+ SUBST (*cc_use_loc,
+ gen_rtx_fmt_ee (compare_code, compare_mode,
+ newpat_dest, const0_rtx));
+ undobuf.other_insn = cc_use_insn;
+ }
+ else if (compare_mode != orig_compare_mode)
+ {
+ /* Just replace the CC reg with a new mode. */
+ SUBST (XEXP (*cc_use_loc, 0), newpat_dest);
+ undobuf.other_insn = cc_use_insn;
+ }
+ }
- SUBST (SET_DEST (newpat), new_dest);
- SUBST (XEXP (*cc_use, 0), new_dest);
- SUBST (SET_SRC (newpat),
- gen_rtx_COMPARE (compare_mode, i2src, const0_rtx));
- }
- else
- undobuf.other_insn = 0;
+ /* Create new reg:CC if the CC mode has been altered. */
+ if (compare_mode != orig_compare_mode)
+ SUBST (SET_DEST (newpat), newpat_dest);
+ /* This is always done to propagate i2src into newpat. */
+ SUBST (SET_SRC (newpat),
+ gen_rtx_COMPARE (compare_mode, op0, op1));
+ /* Create new version of i2pat if needed. */
+ if (! rtx_equal_p (i2src, op0))
+ i2pat = gen_rtx_SET (VOIDmode, i2dest, op0);
+ i2_is_used = 1;
}
-#endif
}
- else
#endif
+
+ if (i2_is_used == 0)
{
/* It is possible that the source of I2 or I1 may be performing
an unneeded operation, such as a ZERO_EXTEND of something