When we try to predicate an insn in the scheduler, we must check whether the condition has been overwritten. The current code for that tries to look for an insn writing the condition register, then checking REG_DEP_TRUE deps. It fails in a situation as follows:
[A1] branch A1:A0 = some operation some other operation using A0 We'd predicate the last insn, even though the condition was overwritten by the middle one. The patch below uses a simpler strategy that should be correct. If the branch hasn't been scheduled, the condition register must have the right value (since an insn that's a candidate for predication is made to depend on the right setter). If the branch has been scheduled, and another insn after it clobbers the condition register, we cannot do predication. This affects only C6X, and I've tested it with a 4.5 c6x-elf toolchain so far. Will also give it a spin with 4.7. Ok? Bernd
* haifa-sched.c (recompute_todo_spec): Simplify and correct the code checking for a clobber of a condition register when deciding whether to predicate. Index: gcc/haifa-sched.c =================================================================== --- gcc/haifa-sched.c (revision 340434) +++ gcc/haifa-sched.c (working copy) @@ -1180,33 +1180,20 @@ recompute_todo_spec (rtx next) regno = REGNO (XEXP (cond, 0)); /* Find the last scheduled insn that modifies the condition register. - If we have a true dependency on it, it sets it to the correct value, - otherwise it must be a later insn scheduled in-between that clobbers - the condition. */ - FOR_EACH_VEC_ELT_REVERSE (rtx, scheduled_insns, i, prev) - { - sd_iterator_def sd_it; - dep_t dep; - HARD_REG_SET t; - bool found; - - find_all_hard_reg_sets (prev, &t); - if (!TEST_HARD_REG_BIT (t, regno)) - continue; + We can stop looking once we find the insn we depend on through the + REG_DEP_CONTROL; if the condition register isn't modified after it, + we know that it still has the right value. */ + if (QUEUE_INDEX (pro) == QUEUE_SCHEDULED) + FOR_EACH_VEC_ELT_REVERSE (rtx, scheduled_insns, i, prev) + { + HARD_REG_SET t; - found = false; - FOR_EACH_DEP (next, SD_LIST_RES_BACK, sd_it, dep) - { - if (DEP_PRO (dep) == prev && DEP_TYPE (dep) == REG_DEP_TRUE) - { - found = true; - break; - } - } - if (!found) - return HARD_DEP; - break; - } + find_all_hard_reg_sets (prev, &t); + if (TEST_HARD_REG_BIT (t, regno)) + return HARD_DEP; + if (prev == pro) + break; + } if (ORIG_PAT (next) == NULL_RTX) { ORIG_PAT (next) = PATTERN (next);