aboutsummaryrefslogtreecommitdiff
path: root/gcc/cse.c
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/cse.c')
-rw-r--r--gcc/cse.c48
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;