Hi,
Before thumb1_reorg, ARM backend uses peephole to save comparison
instructions when a flag setting move is found before branch instruction.
Since we are using thumb1_reog now, it can be extended to catch more
opportunities by searching flag setting move instruction before branch,
rather than only the exact one before branch. 
For example:

mov r0, r1
//other insns does not kill r0
branch if (r0 == 0)
//other insns

Tested on thumb1, is it OK?


2013-04-18  Bin Cheng  <bin.ch...@arm.com>

        * config/arm/arm.c (thumb1_reorg): Search for flag setting insn
        before branch in same basic block.  Check both src and dest of
        the move insn.
Index: gcc/config/arm/arm.c
===================================================================
--- gcc/config/arm/arm.c        (revision 197562)
+++ gcc/config/arm/arm.c        (working copy)
@@ -14026,6 +14026,7 @@ thumb1_reorg (void)
       rtx set, dest, src;
       rtx pat, op0;
       rtx prev, insn = BB_END (bb);
+      bool insn_clobbered = false;
 
       while (insn != BB_HEAD (bb) && DEBUG_INSN_P (insn))
        insn = PREV_INSN (insn);
@@ -14034,12 +14035,29 @@ thumb1_reorg (void)
       if (INSN_CODE (insn) != CODE_FOR_cbranchsi4_insn)
        continue;
 
-      /* Find the first non-note insn before INSN in basic block BB.  */
+      /* Get the register with which we are comparing.  */
+      pat = PATTERN (insn);
+      op0 = XEXP (XEXP (SET_SRC (pat), 0), 0);
+
+      /* Find the first flag setting insn before INSN in basic block BB.  */
       gcc_assert (insn != BB_HEAD (bb));
-      prev = PREV_INSN (insn);
-      while (prev != BB_HEAD (bb) && (NOTE_P (prev) || DEBUG_INSN_P (prev)))
-       prev = PREV_INSN (prev);
+      for (prev = PREV_INSN (insn);
+          (!insn_clobbered
+           && prev != BB_HEAD (bb)
+           && (NOTE_P (prev)
+               || DEBUG_INSN_P (prev)
+               || (GET_CODE (prev) == SET
+                   && get_attr_conds (prev) == CONDS_NOCOND)));
+          prev = PREV_INSN (prev))
+       {
+         if (reg_set_p (op0, prev))
+           insn_clobbered = true;
+       }
 
+      /* Skip if op0 is clobbered by insn other than prev. */
+      if (insn_clobbered)
+       continue;
+
       set = single_set (prev);
       if (!set)
        continue;
@@ -14050,12 +14068,9 @@ thumb1_reorg (void)
          || !low_register_operand (src, SImode))
        continue;
 
-      pat = PATTERN (insn);
-      op0 = XEXP (XEXP (SET_SRC (pat), 0), 0);
       /* Rewrite move into subtract of 0 if its operand is compared with ZERO
-        in INSN. Don't need to check dest since cprop_hardreg pass propagates
-        src into INSN.  */
-      if (REGNO (op0) == REGNO (src))
+        in INSN.  Both src and dest of the move insn are checked.  */
+      if (REGNO (op0) == REGNO (src) || REGNO (op0) == REGNO (dest))
        {
          dest = copy_rtx (dest);
          src = copy_rtx (src);

Reply via email to