diff --git a/gnu/dist/gcc/jump.c b/gnu/dist/gcc/jump.c index ff4680c76622..b42d97f37fab 100644 --- a/gnu/dist/gcc/jump.c +++ b/gnu/dist/gcc/jump.c @@ -862,7 +862,12 @@ jump_optimize (f, cross_jump, noop_moves, after_regscan) && ! reg_referenced_between_p (temp1, p, NEXT_INSN (temp3)) && ! reg_set_between_p (temp1, p, temp3) && (GET_CODE (SET_SRC (temp4)) == CONST_INT - || ! modified_between_p (SET_SRC (temp4), p, temp2))) + || ! modified_between_p (SET_SRC (temp4), p, temp2)) + /* Verify that registers used by the jump are not clobbered + by the instruction being moved. */ + && ! regs_set_between_p (PATTERN (temp), + PREV_INSN (temp2), + NEXT_INSN (temp2))) { emit_insn_after_with_line_notes (PATTERN (temp2), p, temp2); delete_insn (temp2); @@ -960,6 +965,11 @@ jump_optimize (f, cross_jump, noop_moves, after_regscan) NEXT_INSN (temp2)) && ! reg_set_between_p (temp1, insert_after, temp) && ! modified_between_p (SET_SRC (temp4), insert_after, temp) + /* Verify that registers used by the jump are not clobbered + by the instruction being moved. */ + && ! regs_set_between_p (PATTERN (temp), + PREV_INSN (temp3), + NEXT_INSN (temp3)) && invert_jump (temp, JUMP_LABEL (insn))) { emit_insn_after_with_line_notes (PATTERN (temp3), diff --git a/gnu/dist/gcc/rtl.h b/gnu/dist/gcc/rtl.h index 4aa25b2ee0d8..798172b61380 100644 --- a/gnu/dist/gcc/rtl.h +++ b/gnu/dist/gcc/rtl.h @@ -973,6 +973,7 @@ extern int reg_referenced_p PROTO((rtx, rtx)); extern int reg_used_between_p PROTO((rtx, rtx, rtx)); extern int reg_referenced_between_p PROTO((rtx, rtx, rtx)); extern int reg_set_between_p PROTO((rtx, rtx, rtx)); +extern int regs_set_between_p PROTO((rtx, rtx, rtx)); extern int modified_between_p PROTO((rtx, rtx, rtx)); extern int no_labels_between_p PROTO((rtx, rtx)); extern int modified_in_p PROTO((rtx, rtx)); diff --git a/gnu/dist/gcc/rtlanal.c b/gnu/dist/gcc/rtlanal.c index 221b3fae4c13..fd26f6a100be 100644 --- a/gnu/dist/gcc/rtlanal.c +++ b/gnu/dist/gcc/rtlanal.c @@ -499,6 +499,52 @@ reg_set_p (reg, insn) return reg_set_flag; } +/* Similar to reg_set_between_p, but check all registers in X. Return 0 + only if none of them are modified between START and END. Do not + consider non-registers one way or the other. */ + +int +regs_set_between_p (x, start, end) + rtx x; + rtx start, end; +{ + enum rtx_code code = GET_CODE (x); + char *fmt; + int i, j; + + switch (code) + { + case CONST_INT: + case CONST_DOUBLE: + case CONST: + case SYMBOL_REF: + case LABEL_REF: + case PC: + case CC0: + return 0; + + case REG: + return reg_set_between_p (x, start, end); + + default: + break; + } + + fmt = GET_RTX_FORMAT (code); + for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--) + { + if (fmt[i] == 'e' && regs_set_between_p (XEXP (x, i), start, end)) + return 1; + + else if (fmt[i] == 'E') + for (j = XVECLEN (x, i) - 1; j >= 0; j--) + if (regs_set_between_p (XVECEXP (x, i, j), start, end)) + return 1; + } + + return 0; +} + /* Similar to reg_set_between_p, but check all registers in X. Return 0 only if none of them are modified between START and END. Return 1 if X contains a MEM; this routine does not perform any memory aliasing. */