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);