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

Reply via email to