diff options
Diffstat (limited to 'gcc/cse.c')
-rw-r--r-- | gcc/cse.c | 48 |
1 files changed, 44 insertions, 4 deletions
diff --git a/gcc/cse.c b/gcc/cse.c index 5bc6ce40c90..b5bcae2758d 100644 --- a/gcc/cse.c +++ b/gcc/cse.c @@ -1234,7 +1234,24 @@ insert_regs (rtx x, struct table_elt *classp, int modified) if (REG_P (classp->exp) && GET_MODE (classp->exp) == GET_MODE (x)) { - make_regs_eqv (regno, REGNO (classp->exp)); + unsigned c_regno = REGNO (classp->exp); + + gcc_assert (REGNO_QTY_VALID_P (c_regno)); + + /* Suppose that 5 is hard reg and 100 and 101 are + pseudos. Consider + + (set (reg:si 100) (reg:si 5)) + (set (reg:si 5) (reg:si 100)) + (set (reg:di 101) (reg:di 5)) + + We would now set REG_QTY (101) = REG_QTY (5), but the + entry for 5 is in SImode. When we use this later in + copy propagation, we get the register in wrong mode. */ + if (qty_table[REG_QTY (c_regno)].mode != GET_MODE (x)) + continue; + + make_regs_eqv (regno, c_regno); return 1; } @@ -3564,8 +3581,31 @@ fold_rtx (rtx x, rtx insn) if (offset >= 0 && (offset / GET_MODE_SIZE (GET_MODE (table)) < XVECLEN (table, 0))) - return XVECEXP (table, 0, - offset / GET_MODE_SIZE (GET_MODE (table))); + { + rtx label = XVECEXP + (table, 0, offset / GET_MODE_SIZE (GET_MODE (table))); + rtx set; + + /* If we have an insn that loads the label from + the jumptable into a reg, we don't want to set + the reg to the label, because this may cause a + reference to the label to remain after the + label is removed in some very obscure cases (PR + middle-end/18628). */ + if (!insn) + return label; + + set = single_set (insn); + + if (! set || SET_SRC (set) != x) + return x; + + /* If it's a jump, it's safe to reference the label. */ + if (SET_DEST (set) == pc_rtx) + return label; + + return x; + } } if (table_insn && JUMP_P (table_insn) && GET_CODE (PATTERN (table_insn)) == ADDR_DIFF_VEC) @@ -7329,7 +7369,7 @@ delete_trivially_dead_insns (rtx insns, int nreg) ndead++; } - if (find_reg_note (insn, REG_LIBCALL, NULL_RTX)) + if (in_libcall && find_reg_note (insn, REG_LIBCALL, NULL_RTX)) { in_libcall = 0; dead_libcall = 0; |