aboutsummaryrefslogtreecommitdiff
path: root/gcc/cse.c
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/cse.c')
-rw-r--r--gcc/cse.c145
1 files changed, 129 insertions, 16 deletions
diff --git a/gcc/cse.c b/gcc/cse.c
index e9f6c2f4724..769e22d8e10 100644
--- a/gcc/cse.c
+++ b/gcc/cse.c
@@ -864,10 +864,12 @@ init_cse_reg_info (unsigned int nregs)
}
/* Reallocate the table with NEW_SIZE entries. */
- cse_reg_info_table = xrealloc (cse_reg_info_table,
- (sizeof (struct cse_reg_info)
- * new_size));
+ if (cse_reg_info_table)
+ free (cse_reg_info_table);
+ cse_reg_info_table = xmalloc (sizeof (struct cse_reg_info)
+ * new_size);
cse_reg_info_table_size = new_size;
+ cse_reg_info_table_first_uninitialized = 0;
}
/* Do we have all of the first NREGS entries initialized? */
@@ -1232,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;
}
@@ -3562,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)
@@ -4900,6 +4942,9 @@ cse_insn (rtx insn, rtx libcall_insn)
rtx src_eqv_here;
rtx src_const = 0;
rtx src_related = 0;
+ /* APPLE LOCAL begin cse of ZERO/SIGN EXTEND */
+ rtx zero_sign_extended_src = NULL_RTX;
+ /* APPLE LOCAL end cse of ZERO/SIGN EXTEND */
struct table_elt *src_const_elt = 0;
int src_cost = MAX_COST;
int src_eqv_cost = MAX_COST;
@@ -5033,7 +5078,35 @@ cse_insn (rtx insn, rtx libcall_insn)
REG_NOTE. */
if (!sets[i].src_volatile)
+ /* APPLE LOCAL begin cse of ZERO/SIGN EXTEND */
+ {
elt = lookup (src, sets[i].src_hash, mode);
+ if (!elt
+ && (GET_CODE(src) == ZERO_EXTEND || GET_CODE(src) == SIGN_EXTEND)
+ && GET_CODE (XEXP (src, 0)) == MEM)
+ {
+ unsigned mem_hash;
+ rtx nsrc = XEXP (src, 0);
+ enum machine_mode nmode = GET_MODE(nsrc);
+ do_not_record = 0;
+ hash_arg_in_memory = 0;
+ mem_hash = HASH (nsrc, nmode);
+ elt = lookup (nsrc, mem_hash, nmode);
+ if (elt)
+ {
+ sets[i].src = nsrc;
+ sets[i].src_hash = mem_hash;
+ sets[i].src_volatile = do_not_record;
+ sets[i].src_in_memory = hash_arg_in_memory;
+ zero_sign_extended_src = src;
+ src = nsrc;
+ mode = GET_MODE (src) == VOIDmode ? GET_MODE (dest) : GET_MODE (src);
+ sets[i].mode = mode;
+ src_folded = fold_rtx (src, insn);
+ }
+ }
+ }
+ /* APPLE LOCAL end cse of ZERO/SIGN EXTEND */
sets[i].src_elt = elt;
@@ -5062,6 +5135,26 @@ cse_insn (rtx insn, rtx libcall_insn)
for (p = elt->first_same_value; p; p = p->next_same_value)
if (p->is_const)
{
+ /* APPLE LOCAL begin cse of ZERO/SIGN EXTEND */
+ /* If we're looking at a MEM under a SIGN/ZERO_EXTEND,
+ constants match only if the high bits match. */
+ if (zero_sign_extended_src)
+ {
+ rtx truncated_const, trial;
+ truncated_const = gen_rtx_TRUNCATE (
+ GET_MODE (XEXP (zero_sign_extended_src, 0)),
+ copy_rtx (p->exp));
+ if (GET_CODE (zero_sign_extended_src) == ZERO_EXTEND)
+ trial = gen_rtx_ZERO_EXTEND (
+ GET_MODE (zero_sign_extended_src), truncated_const);
+ else
+ trial = gen_rtx_SIGN_EXTEND (
+ GET_MODE (zero_sign_extended_src), truncated_const);
+ trial = fold_rtx (trial, NULL_RTX);
+ if (!rtx_equal_p (trial, p->exp))
+ continue;
+ }
+ /* APPLE LOCAL end cse of ZERO/SIGN EXTEND */
src_const = p->exp;
src_const_elt = elt;
break;
@@ -5437,6 +5530,18 @@ cse_insn (rtx insn, rtx libcall_insn)
&& preferable (src_related_cost, src_related_regcost,
src_elt_cost, src_elt_regcost) <= 0)
trial = copy_rtx (src_related), src_related_cost = MAX_COST;
+ /* APPLE LOCAL begin cse of ZERO/SIGN EXTEND */
+ else if (zero_sign_extended_src)
+ {
+ trial = GET_CODE(zero_sign_extended_src) == ZERO_EXTEND
+ ? gen_rtx_ZERO_EXTEND (GET_MODE(zero_sign_extended_src),
+ copy_rtx (elt->exp))
+ : gen_rtx_SIGN_EXTEND (GET_MODE(zero_sign_extended_src),
+ copy_rtx (elt->exp));
+ elt = elt->next_same_value;
+ src_elt_cost = MAX_COST;
+ }
+ /* APPLE LOCAL end cse of ZERO/SIGN EXTEND */
else
{
trial = copy_rtx (elt->exp);
@@ -5527,6 +5632,11 @@ cse_insn (rtx insn, rtx libcall_insn)
}
src = SET_SRC (sets[i].rtl);
+ /* APPLE LOCAL begin cse of ZERO/SIGN EXTEND */
+ if (zero_sign_extended_src
+ && (GET_CODE (src) == GET_CODE (zero_sign_extended_src)))
+ src = XEXP (src, 0);
+ /* APPLE LOCAL end cse of ZERO/SIGN EXTEND */
/* In general, it is good to have a SET with SET_SRC == SET_DEST.
However, there is an important exception: If both are registers
@@ -5603,7 +5713,11 @@ cse_insn (rtx insn, rtx libcall_insn)
&& ! (GET_CODE (src_const) == CONST
&& GET_CODE (XEXP (src_const, 0)) == MINUS
&& GET_CODE (XEXP (XEXP (src_const, 0), 0)) == LABEL_REF
- && GET_CODE (XEXP (XEXP (src_const, 0), 1)) == LABEL_REF))
+ /* APPLE LOCAL begin cse of ZERO/SIGN EXTEND */
+ && (GET_CODE (XEXP (XEXP (src_const, 0), 1)) == LABEL_REF
+ || rtx_equal_p ((XEXP (XEXP (src_const, 0), 1)),
+ const0_rtx))))
+ /* APPLE LOCAL end */
{
/* We only want a REG_EQUAL note if src_const != src. */
if (! rtx_equal_p (src, src_const))
@@ -7282,8 +7396,9 @@ delete_trivially_dead_insns (rtx insns, int nreg)
timevar_push (TV_DELETE_TRIVIALLY_DEAD);
/* First count the number of times each register is used. */
counts = xcalloc (nreg, sizeof (int));
- for (insn = next_real_insn (insns); insn; insn = next_real_insn (insn))
- count_reg_usage (insn, counts, 1);
+ for (insn = insns; insn; insn = NEXT_INSN (insn))
+ if (INSN_P (insn))
+ count_reg_usage (insn, counts, 1);
/* Go from the last insn to the first and delete insns that only set unused
registers or copy a register to itself. As we delete an insn, remove
@@ -7292,15 +7407,13 @@ delete_trivially_dead_insns (rtx insns, int nreg)
The first jump optimization pass may leave a real insn as the last
insn in the function. We must not skip that insn or we may end
up deleting code that is not really dead. */
- insn = get_last_insn ();
- if (! INSN_P (insn))
- insn = prev_real_insn (insn);
-
- for (; insn; insn = prev)
+ for (insn = get_last_insn (); insn; insn = prev)
{
int live_insn = 0;
- prev = prev_real_insn (insn);
+ prev = PREV_INSN (insn);
+ if (!INSN_P (insn))
+ continue;
/* Don't delete any insns that are part of a libcall block unless
we can delete the whole libcall block.
@@ -7328,7 +7441,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;