diff options
Diffstat (limited to 'gcc/sched-rgn.c')
-rw-r--r-- | gcc/sched-rgn.c | 34 |
1 files changed, 29 insertions, 5 deletions
diff --git a/gcc/sched-rgn.c b/gcc/sched-rgn.c index 12f2e66832b..b340bd532e4 100644 --- a/gcc/sched-rgn.c +++ b/gcc/sched-rgn.c @@ -320,16 +320,40 @@ is_cfg_nonregular (void) FOR_EACH_BB (b) FOR_BB_INSNS (b, insn) { - /* Check for labels referred to but (at least not directly) as - jump targets. */ - if (INSN_P (insn) - && find_reg_note (insn, REG_LABEL_OPERAND, NULL_RTX)) - return 1; + rtx note, next, set, dest; /* If this function has a computed jump, then we consider the cfg not well structured. */ if (JUMP_P (insn) && computed_jump_p (insn)) return 1; + + if (!INSN_P (insn)) + continue; + + note = find_reg_note (insn, REG_LABEL_OPERAND, NULL_RTX); + if (note == NULL_RTX) + continue; + + /* For that label not to be seen as a referred-to label, this + must be a single-set which is feeding a jump *only*. This + could be a conditional jump with the label split off for + machine-specific reasons or a casesi/tablejump. */ + next = next_nonnote_insn (insn); + if (next == NULL_RTX + || !JUMP_P (next) + || (JUMP_LABEL (next) != XEXP (note, 0) + && find_reg_note (next, REG_LABEL_TARGET, + XEXP (note, 0)) == NULL_RTX) + || BLOCK_FOR_INSN (insn) != BLOCK_FOR_INSN (next)) + return 1; + + set = single_set (insn); + if (set == NULL_RTX) + return 1; + + dest = SET_DEST (set); + if (!REG_P (dest) || !dead_or_set_p (next, dest)) + return 1; } /* Unreachable loops with more than one basic block are detected |