static void set_nonzero_bits_and_sign_copies (rtx, rtx, void *);
static int cant_combine_insn_p (rtx);
static int can_combine_p (rtx, rtx, rtx, rtx, rtx *, rtx *);
-static int sets_function_arg_p (rtx);
static int combinable_i3pat (rtx, rtx *, rtx, rtx, int, rtx *);
static int contains_muldiv (rtx);
static rtx try_combine (rtx, rtx, rtx, int *);
FOR_EACH_BB (this_basic_block)
{
- for (insn = this_basic_block->head;
- insn != NEXT_INSN (this_basic_block->end);
+ for (insn = BB_HEAD (this_basic_block);
+ insn != NEXT_INSN (BB_END (this_basic_block));
insn = next ? next : NEXT_INSN (insn))
{
next = 0;
return 1;
}
\f
-/* Check if PAT is an insn - or a part of it - used to set up an
- argument for a function in a hard register. */
-
-static int
-sets_function_arg_p (rtx pat)
-{
- int i;
- rtx inner_dest;
-
- switch (GET_CODE (pat))
- {
- case INSN:
- return sets_function_arg_p (PATTERN (pat));
-
- case PARALLEL:
- for (i = XVECLEN (pat, 0); --i >= 0;)
- if (sets_function_arg_p (XVECEXP (pat, 0, i)))
- return 1;
-
- break;
-
- case SET:
- inner_dest = SET_DEST (pat);
- while (GET_CODE (inner_dest) == STRICT_LOW_PART
- || GET_CODE (inner_dest) == SUBREG
- || GET_CODE (inner_dest) == ZERO_EXTRACT)
- inner_dest = XEXP (inner_dest, 0);
-
- return (GET_CODE (inner_dest) == REG
- && REGNO (inner_dest) < FIRST_PSEUDO_REGISTER
- && FUNCTION_ARG_REGNO_P (REGNO (inner_dest)));
-
- default:
- break;
- }
-
- return 0;
-}
-
/* LOC is the location within I3 that contains its pattern or the component
of a PARALLEL of the pattern. We validate that it is valid for combining.
return 0;
}
+/* Adjust INSN after we made a change to its destination.
+
+ Changing the destination can invalidate notes that say something about
+ the results of the insn and a LOG_LINK pointing to the insn. */
+
+static void
+adjust_for_new_dest (rtx insn)
+{
+ rtx *loc;
+
+ /* For notes, be conservative and simply remove them. */
+ loc = ®_NOTES (insn);
+ while (*loc)
+ {
+ enum reg_note kind = REG_NOTE_KIND (*loc);
+ if (kind == REG_EQUAL || kind == REG_EQUIV)
+ *loc = XEXP (*loc, 1);
+ else
+ loc = &XEXP (*loc, 1);
+ }
+
+ /* The new insn will have a destination that was previously the destination
+ of an insn just above it. Call distribute_links to make a LOG_LINK from
+ the next use of that destination. */
+ distribute_links (gen_rtx_INSN_LIST (VOIDmode, insn, NULL_RTX));
+}
+
/* Try to combine the insns I1 and I2 into I3.
Here I1 and I2 appear earlier than I3.
I1 can be zero; then we combine just I2 into I3.
&& XEXP (SET_SRC (PATTERN (i3)), 1) == const0_rtx
&& rtx_equal_p (XEXP (SET_SRC (PATTERN (i3)), 0), i2dest))
{
-#ifdef EXTRA_CC_MODES
+#ifdef SELECT_CC_MODE
rtx *cc_use;
enum machine_mode compare_mode;
#endif
i2_is_used = 1;
-#ifdef EXTRA_CC_MODES
+#ifdef SELECT_CC_MODE
/* See if a COMPARE with the operand we substituted in should be done
with the mode that is currently being used. If not, do the same
processing we do in `subst' for a SET; namely, if the destination
{
newpat = XVECEXP (newpat, 0, 1);
insn_code_number = recog_for_combine (&newpat, i3, &new_i3_notes);
+
+ if (insn_code_number >= 0)
+ {
+ /* If we will be able to accept this, we have made a change to the
+ destination of I3. This requires us to do a few adjustments. */
+ PATTERN (i3) = newpat;
+ adjust_for_new_dest (i3);
+ }
}
/* If we were combining three insns and the result is a simple SET
rtx link;
/* If we will be able to accept this, we have made a change to the
- destination of I3. This can invalidate a LOG_LINKS pointing
- to I3. No other part of combine.c makes such a transformation.
-
- The new I3 will have a destination that was previously the
- destination of I1 or I2 and which was used in i2 or I3. Call
- distribute_links to make a LOG_LINK from the next use of
- that destination. */
-
+ destination of I3. This requires us to do a few adjustments. */
PATTERN (i3) = newpat;
- distribute_links (gen_rtx_INSN_LIST (VOIDmode, i3, NULL_RTX));
+ adjust_for_new_dest (i3);
/* I3 now uses what used to be its destination and which is
now I2's destination. That means we need a LOG_LINK from
for (insn = NEXT_INSN (i3);
insn && (this_basic_block->next_bb == EXIT_BLOCK_PTR
- || insn != this_basic_block->next_bb->head);
+ || insn != BB_HEAD (this_basic_block->next_bb));
insn = NEXT_INSN (insn))
{
if (INSN_P (insn) && reg_referenced_p (ni2dest, PATTERN (insn)))
SET_DEST (XVECEXP (PATTERN (i2), 0, i))))
for (temp = NEXT_INSN (i2);
temp && (this_basic_block->next_bb == EXIT_BLOCK_PTR
- || this_basic_block->head != temp);
+ || BB_HEAD (this_basic_block) != temp);
temp = NEXT_INSN (temp))
if (temp != i3 && INSN_P (temp))
for (link = LOG_LINKS (temp); link; link = XEXP (link, 1))
/* Simplify our comparison, if possible. */
new_code = simplify_comparison (old_code, &op0, &op1);
-#ifdef EXTRA_CC_MODES
+#ifdef SELECT_CC_MODE
/* If this machine has CC modes other than CCmode, check to see if we
need to use a different CC mode here. */
compare_mode = SELECT_CC_MODE (new_code, op0, op1);
-#endif /* EXTRA_CC_MODES */
-#if !defined (HAVE_cc0) && defined (EXTRA_CC_MODES)
+#ifndef HAVE_cc0
/* If the mode changed, we have to change SET_DEST, the mode in the
compare, and the mode in the place SET_DEST is used. If SET_DEST is
a hard register, just build new versions with the proper mode. If it
dest = new_dest;
}
}
-#endif
+#endif /* cc0 */
+#endif /* SELECT_CC_MODE */
/* If the code changed, we have to build a new comparison in
undobuf.other_insn. */
if (new_code != old_code)
{
+ int other_changed_previously = other_changed;
unsigned HOST_WIDE_INT mask;
SUBST (*cc_use, gen_rtx_fmt_ee (new_code, GET_MODE (*cc_use),
dest, const0_rtx));
+ other_changed = 1;
/* If the only change we made was to change an EQ into an NE or
vice versa, OP0 has only one bit that might be nonzero, and OP1
if (((old_code == NE && new_code == EQ)
|| (old_code == EQ && new_code == NE))
- && ! other_changed && op1 == const0_rtx
+ && ! other_changed_previously && op1 == const0_rtx
&& GET_MODE_BITSIZE (GET_MODE (op0)) <= HOST_BITS_PER_WIDE_INT
&& exact_log2 (mask = nonzero_bits (op0, GET_MODE (op0))) >= 0)
{
&& ! check_asm_operands (pat)))
{
PUT_CODE (*cc_use, old_code);
- other_insn = 0;
+ other_changed = 0;
op0 = gen_binary (XOR, GET_MODE (op0), op0, GEN_INT (mask));
}
}
-
- other_changed = 1;
}
if (other_changed)
{
if (tmode != inner_mode)
{
- if (in_dest)
+ /* We can't call gen_lowpart_for_combine in a DEST since we
+ always want a SUBREG (see below) and it would sometimes
+ return a new hard register. */
+ if (pos || in_dest)
{
- /* We can't call gen_lowpart_for_combine here since we always want
- a SUBREG and it would sometimes return a new hard register. */
HOST_WIDE_INT final_word = pos / BITS_PER_WORD;
if (WORDS_BIG_ENDIAN
apply_distributive_law (rtx x)
{
enum rtx_code code = GET_CODE (x);
+ enum rtx_code inner_code;
rtx lhs, rhs, other;
rtx tem;
- enum rtx_code inner_code;
- /* Distributivity is not true for floating point.
- It can change the value. So don't do it.
- -- rms and moshier@world.std.com. */
- if (FLOAT_MODE_P (GET_MODE (x)))
+ /* Distributivity is not true for floating point as it can change the
+ value. So we don't do it unless -funsafe-math-optimizations. */
+ if (FLOAT_MODE_P (GET_MODE (x))
+ && ! flag_unsafe_math_optimizations)
return x;
/* The outer operation can only be one of the following: */
&& code != PLUS && code != MINUS)
return x;
- lhs = XEXP (x, 0), rhs = XEXP (x, 1);
+ lhs = XEXP (x, 0);
+ rhs = XEXP (x, 1);
/* If either operand is a primitive we can't do anything, so get out
fast. */
else
{
FOR_EACH_BB (block)
- if (insn == block->head)
+ if (insn == BB_HEAD (block))
break;
if (block == EXIT_BLOCK_PTR)
{
if (! INSN_P (tem))
{
- if (tem == bb->head)
+ if (tem == BB_HEAD (bb))
break;
continue;
}
This might delete other dead insns recursively.
First set the pattern to something that won't use
any register. */
+ rtx old_notes = REG_NOTES (tem);
PATTERN (tem) = pc_rtx;
+ REG_NOTES (tem) = NULL;
- distribute_notes (REG_NOTES (tem), tem, tem,
- NULL_RTX);
+ distribute_notes (old_notes, tem, tem, NULL_RTX);
distribute_links (LOG_LINKS (tem));
PUT_CODE (tem, NOTE);
if (cc0_setter)
{
PATTERN (cc0_setter) = pc_rtx;
+ old_notes = REG_NOTES (cc0_setter);
+ REG_NOTES (cc0_setter) = NULL;
- distribute_notes (REG_NOTES (cc0_setter),
- cc0_setter, cc0_setter,
- NULL_RTX);
+ distribute_notes (old_notes, cc0_setter,
+ cc0_setter, NULL_RTX);
distribute_links (LOG_LINKS (cc0_setter));
PUT_CODE (cc0_setter, NOTE);
break;
}
- if (tem == bb->head)
+ if (tem == BB_HEAD (bb))
break;
}
{
if (! INSN_P (tem))
{
- if (tem == bb->head)
+ if (tem == BB_HEAD (bb))
{
SET_BIT (refresh_blocks,
this_basic_block->index);
}
\f
/* Similarly to above, distribute the LOG_LINKS that used to be present on
- I3, I2, and I1 to new locations. This is also called in one case to
- add a link pointing at I3 when I3's destination is changed. */
+ I3, I2, and I1 to new locations. This is also called to add a link
+ pointing at I3 when I3's destination is changed. */
static void
distribute_links (rtx links)
for (insn = NEXT_INSN (XEXP (link, 0));
(insn && (this_basic_block->next_bb == EXIT_BLOCK_PTR
- || this_basic_block->next_bb->head != insn));
+ || BB_HEAD (this_basic_block->next_bb) != insn));
insn = NEXT_INSN (insn))
if (INSN_P (insn) && reg_overlap_mentioned_p (reg, PATTERN (insn)))
{
place = insn;
break;
}
+ else if (INSN_P (insn) && reg_set_p (reg, insn))
+ break;
/* If we found a place to put the link, place it there unless there
is already a link to the same insn as LINK at that point. */