rtx_insn *insn = chain->insn;
class insn_chain *new_chain;
- /* If INSN references CC0, put our insns in front of the insn that sets
- CC0. This is always safe, since the only way we could be passed an
- insn that references CC0 is for a restore, and doing a restore earlier
- isn't a problem. We do, however, assume here that CALL_INSNs don't
- reference CC0. Guard against non-INSN's like CODE_LABEL. */
-
- if (HAVE_cc0 && (NONJUMP_INSN_P (insn) || JUMP_P (insn))
- && before_p
- && reg_referenced_p (cc0_rtx, PATTERN (insn)))
- chain = chain->prev, insn = chain->insn;
-
new_chain = new_insn_chain ();
if (before_p)
{
i2 = PREV_INSN (i2);
}
- /* Don't allow the insn after a compare to be shared by
- cross-jumping unless the compare is also shared. */
- if (HAVE_cc0 && ninsns && reg_mentioned_p (cc0_rtx, last1)
- && ! sets_cc0_p (last1))
- last1 = afterlast1, last2 = afterlast2, last_dir = afterlast_dir, ninsns--;
-
/* Include preceding notes and labels in the cross-jump. One,
this may bring us to the head of the blocks as requested above.
Two, it keeps line number notes as matched as may be. */
i2 = NEXT_INSN (i2);
}
- /* Don't allow a compare to be shared by cross-jumping unless the insn
- after the compare is also shared. */
- if (HAVE_cc0 && ninsns && reg_mentioned_p (cc0_rtx, last1)
- && sets_cc0_p (last1))
- last1 = beforelast1, last2 = beforelast2, ninsns--;
-
if (ninsns)
{
*f1 = last1;
cond = get_condition (jump, &move_before, true, false);
if (cond == NULL_RTX)
- {
- if (HAVE_cc0 && reg_mentioned_p (cc0_rtx, jump))
- move_before = prev_nonnote_nondebug_insn (jump);
- else
- move_before = jump;
- }
+ move_before = jump;
for (ix = 0; ix < nedges; ix++)
if (EDGE_SUCC (bb, ix)->dest == EXIT_BLOCK_PTR_FOR_FN (cfun))
jump = BB_END (final_dest_bb);
cond = get_condition (jump, &move_before, true, false);
if (cond == NULL_RTX)
- {
- if (HAVE_cc0 && reg_mentioned_p (cc0_rtx, jump))
- move_before = prev_nonnote_nondebug_insn (jump);
- else
- move_before = jump;
- }
+ move_before = jump;
}
do
/* Try again, using a different insertion point. */
move_before = jump;
- /* Don't try moving before a cc0 user, as that may invalidate
- the cc0. */
- if (HAVE_cc0 && reg_mentioned_p (cc0_rtx, jump))
- break;
-
continue;
}
/* For the unmerged insns, try a different insertion point. */
move_before = jump;
- /* Don't try moving before a cc0 user, as that may invalidate
- the cc0. */
- if (HAVE_cc0 && reg_mentioned_p (cc0_rtx, jump))
- break;
-
for (ix = 0; ix < nedges; ix++)
currptr[ix] = headptr[ix] = nextptr[ix];
}
try_redirect_by_replacing_jump (edge e, basic_block target, bool in_cfglayout)
{
basic_block src = e->src;
- rtx_insn *insn = BB_END (src), *kill_from;
+ rtx_insn *insn = BB_END (src);
rtx set;
int fallthru = 0;
if (!set || side_effects_p (set))
return NULL;
- /* In case we zap a conditional jump, we'll need to kill
- the cc0 setter too. */
- kill_from = insn;
- if (HAVE_cc0 && reg_mentioned_p (cc0_rtx, PATTERN (insn))
- && only_sets_cc0_p (PREV_INSN (insn)))
- kill_from = PREV_INSN (insn);
-
/* See if we can create the fallthru edge. */
if (in_cfglayout || can_fallthru (src, target))
{
/* Selectively unlink whole insn chain. */
if (in_cfglayout)
{
- delete_insn_chain (kill_from, BB_END (src), false);
+ delete_insn_chain (insn, BB_END (src), false);
remove_barriers_from_footer (src);
}
else
- delete_insn_chain (kill_from, PREV_INSN (BB_HEAD (target)),
- false);
+ delete_insn_chain (insn, PREV_INSN (BB_HEAD (target)), false);
}
/* If this already is simplejump, redirect it. */
INSN_UID (insn), INSN_UID (BB_END (src)));
- delete_insn_chain (kill_from, insn, false);
+ delete_insn_chain (insn, insn, false);
/* Recognize a tablejump that we are converting to a
simple jump and remove its associated CODE_LABEL
If PLOC is nonzero, *PLOC is set to the insn containing the single use.
- If DEST is cc0_rtx, we look only at the next insn. In that case, we don't
- care about REG_DEAD notes or LOG_LINKS.
-
Otherwise, we find the single use by finding an insn that has a
LOG_LINKS pointing at INSN and has a REG_DEAD note for DEST. If DEST is
only referenced once in that insn, we know that it must be the first
rtx *result;
struct insn_link *link;
- if (dest == cc0_rtx)
- {
- next = NEXT_INSN (insn);
- if (next == 0
- || (!NONJUMP_INSN_P (next) && !JUMP_P (next)))
- return 0;
-
- result = find_single_use_1 (dest, &PATTERN (next));
- if (result && ploc)
- *ploc = next;
- return result;
- }
-
if (!REG_P (dest))
return 0;
goto retry;
}
- /* Do the same for an insn that explicitly references CC0. */
- if (HAVE_cc0 && NONJUMP_INSN_P (insn)
- && (prev = prev_nonnote_insn (insn)) != 0
- && NONJUMP_INSN_P (prev)
- && sets_cc0_p (PATTERN (prev))
- && GET_CODE (PATTERN (insn)) == SET
- && reg_mentioned_p (cc0_rtx, SET_SRC (PATTERN (insn))))
- {
- if ((next = try_combine (insn, prev, NULL, NULL,
- &new_direct_jump_p,
- last_combined_insn)) != 0)
- goto retry;
-
- FOR_EACH_LOG_LINK (nextlinks, prev)
- if ((next = try_combine (insn, prev, nextlinks->insn,
- NULL, &new_direct_jump_p,
- last_combined_insn)) != 0)
- goto retry;
- }
-
- /* Finally, see if any of the insns that this insn links to
- explicitly references CC0. If so, try this insn, that insn,
- and its predecessor if it sets CC0. */
- if (HAVE_cc0)
- {
- FOR_EACH_LOG_LINK (links, insn)
- if (NONJUMP_INSN_P (links->insn)
- && GET_CODE (PATTERN (links->insn)) == SET
- && reg_mentioned_p (cc0_rtx, SET_SRC (PATTERN (links->insn)))
- && (prev = prev_nonnote_insn (links->insn)) != 0
- && NONJUMP_INSN_P (prev)
- && sets_cc0_p (PATTERN (prev))
- && (next = try_combine (insn, links->insn,
- prev, NULL, &new_direct_jump_p,
- last_combined_insn)) != 0)
- goto retry;
- }
-
/* Try combining an insn with two different insns whose results it
uses. */
if (max_combine >= 3)
&& find_reg_note (i2, REG_DEAD,
SUBREG_REG (SET_DEST (set1))))
&& !modified_between_p (SET_DEST (set1), i2, i3)
- && (!HAVE_cc0 || !reg_referenced_p (cc0_rtx, set0))
/* If I3 is a jump, ensure that set0 is a jump so that
we do not create invalid RTL. */
&& (!JUMP_P (i3) || SET_DEST (set0) == pc_rtx)
&& find_reg_note (i2, REG_DEAD,
SUBREG_REG (SET_DEST (set0))))
&& !modified_between_p (SET_DEST (set0), i2, i3)
- && (!HAVE_cc0 || !reg_referenced_p (cc0_rtx, set1))
/* If I3 is a jump, ensure that set1 is a jump so that
we do not create invalid RTL. */
&& (!JUMP_P (i3) || SET_DEST (set1) == pc_rtx)
break;
case SET:
- /* If SET_DEST is CC0 and SET_SRC is not an operand, a COMPARE, or a
- ZERO_EXTRACT, the most likely reason why this doesn't match is that
- we need to put the operand into a register. So split at that
- point. */
-
- if (SET_DEST (x) == cc0_rtx
- && GET_CODE (SET_SRC (x)) != COMPARE
- && GET_CODE (SET_SRC (x)) != ZERO_EXTRACT
- && !OBJECT_P (SET_SRC (x))
- && ! (GET_CODE (SET_SRC (x)) == SUBREG
- && OBJECT_P (SUBREG_REG (SET_SRC (x)))))
- return &SET_SRC (x);
-
/* See if we can split SET_SRC as it stands. */
split = find_split_point (&SET_SRC (x), insn, true);
if (split && split != &SET_SRC (x))
from in the outside mode, and that may be invalid
if it is an fp reg copied in integer mode.
- We allow two exceptions to this: It is valid if
+ We allow an exception to this: It is valid if
it is inside another SUBREG and the mode of that
SUBREG and the mode of the inside of TO is
- tieable and it is valid if X is a SET that copies
- FROM to CC0. */
+ tieable. */
if (GET_CODE (to) == SUBREG
&& !targetm.modes_tieable_p (GET_MODE (to),
GET_MODE (SUBREG_REG (to)))
&& ! (code == SUBREG
&& (targetm.modes_tieable_p
- (GET_MODE (x), GET_MODE (SUBREG_REG (to)))))
- && (!HAVE_cc0
- || (! (code == SET
- && i == 1
- && XEXP (x, 0) == cc0_rtx))))
+ (GET_MODE (x), GET_MODE (SUBREG_REG (to))))))
return gen_rtx_CLOBBER (VOIDmode, const0_rtx);
if (code == SUBREG
src = SET_SRC (x), dest = SET_DEST (x);
}
- /* If we have (set (cc0) (subreg ...)), we try to remove the subreg
- in SRC. */
- if (dest == cc0_rtx
- && partial_subreg_p (src)
- && subreg_lowpart_p (src))
- {
- rtx inner = SUBREG_REG (src);
- machine_mode inner_mode = GET_MODE (inner);
-
- /* Here we make sure that we don't have a sign bit on. */
- if (val_signbit_known_clear_p (GET_MODE (src),
- nonzero_bits (inner, inner_mode)))
- {
- SUBST (SET_SRC (x), inner);
- src = SET_SRC (x);
- }
- }
-
/* If we have (set FOO (subreg:M (mem:N BAR) 0)) with M wider than N, this
would require a paradoxical subreg. Replace the subreg with a
zero_extend to avoid the reload that would otherwise be required.
/* Verify that it was the set, and not a clobber that
modified the register.
- CC0 targets must be careful to maintain setter/user
- pairs. If we cannot delete the setter due to side
+ If we cannot delete the setter due to side
effects, mark the user with an UNUSED note instead
of deleting it. */
if (set != 0 && ! side_effects_p (SET_SRC (set))
- && rtx_equal_p (XEXP (note, 0), inner_dest)
- && (!HAVE_cc0
- || (! reg_mentioned_p (cc0_rtx, SET_SRC (set))
- || ((cc0_setter = prev_cc0_setter (tem_insn)) != NULL
- && sets_cc0_p (PATTERN (cc0_setter)) > 0))))
+ && rtx_equal_p (XEXP (note, 0), inner_dest))
{
/* Move the notes and links of TEM_INSN elsewhere.
This might delete other dead insns recursively.
sets[i].rtl = 0;
}
}
-
- /* If setting CC0, record what it was set to, or a constant, if it
- is equivalent to a constant. If it is being set to a floating-point
- value, make a COMPARE with the appropriate constant of 0. If we
- don't do this, later code can interpret this as a test against
- const0_rtx, which can cause problems if we try to put it into an
- insn as a floating-point operand. */
- if (dest == cc0_rtx)
- {
- this_insn_cc0 = src_const && mode != VOIDmode ? src_const : src;
- this_insn_cc0_mode = mode;
- if (FLOAT_MODE_P (mode))
- this_insn_cc0 = gen_rtx_COMPARE (VOIDmode, this_insn_cc0,
- CONST0_RTX (mode));
- }
}
/* Now enter all non-volatile source expressions in the hash table
if (HAVE_cc0 && NONDEBUG_INSN_P (insn))
{
- /* If the previous insn sets CC0 and this insn no
- longer references CC0, delete the previous insn.
- Here we use fact that nothing expects CC0 to be
- valid over an insn, which is true until the final
- pass. */
- rtx_insn *prev_insn;
- rtx tem;
-
- prev_insn = prev_nonnote_nondebug_insn (insn);
- if (prev_insn && NONJUMP_INSN_P (prev_insn)
- && (tem = single_set (prev_insn)) != NULL_RTX
- && SET_DEST (tem) == cc0_rtx
- && ! reg_mentioned_p (cc0_rtx, PATTERN (insn)))
- delete_insn (prev_insn);
-
/* If this insn is not the last insn in the basic
block, it will be PREV_INSN(insn) in the next
iteration. If we recorded any CC0-related
set_live_p (rtx set, rtx_insn *insn ATTRIBUTE_UNUSED, /* Only used with HAVE_cc0. */
int *counts)
{
- rtx_insn *tem;
-
if (set_noop_p (set))
- ;
-
- else if (GET_CODE (SET_DEST (set)) == CC0
- && !side_effects_p (SET_SRC (set))
- && ((tem = next_nonnote_nondebug_insn (insn)) == NULL_RTX
- || !INSN_P (tem)
- || !reg_referenced_p (cc0_rtx, PATTERN (tem))))
return false;
- else if (!is_dead_reg (SET_DEST (set), counts)
- || side_effects_p (SET_SRC (set)))
+
+ if (!is_dead_reg (SET_DEST (set), counts)
+ || side_effects_p (SET_SRC (set)))
return true;
+
return false;
}
rtx pc_rtx;
rtx ret_rtx;
rtx simple_return_rtx;
-rtx cc0_rtx;
/* Marker used for denoting an INSN, which should never be accessed (i.e.,
this pointer should normally never be dereferenced), but is required to be
if (insn && NONJUMP_INSN_P (insn) && GET_CODE (PATTERN (insn)) == SEQUENCE)
insn = as_a <rtx_sequence *> (PATTERN (insn))->insn (0);
- if (insn && INSN_P (insn) && reg_mentioned_p (cc0_rtx, PATTERN (insn)))
- return insn;
-
return 0;
}
pc_rtx = gen_rtx_fmt_ (PC, VOIDmode);
ret_rtx = gen_rtx_fmt_ (RETURN, VOIDmode);
simple_return_rtx = gen_rtx_fmt_ (SIMPLE_RETURN, VOIDmode);
- cc0_rtx = gen_rtx_fmt_ (CC0, VOIDmode);
invalid_insn_rtx = gen_rtx_INSN (VOIDmode,
/*prev_insn=*/NULL,
/*next_insn=*/NULL,
? " (no unique first use)" : "");
continue;
}
- if (HAVE_cc0 && reg_referenced_p (cc0_rtx, PATTERN (closest_use)))
- {
- if (dump_file)
- fprintf (dump_file, "Reg %d: closest user uses cc0\n",
- regno);
- continue;
- }
bitmap_set_bit (interesting, regno);
/* If we get here, we know closest_use is a non-NULL insn
if (INSN_P (x))
x = PATTERN (x);
- if (GET_CODE (x) == SET && SET_DEST (x) == cc0_rtx)
- return 1;
if (GET_CODE (x) == PARALLEL)
{
int i;
int sets_cc0 = 0;
int other_things = 0;
for (i = XVECLEN (x, 0) - 1; i >= 0; i--)
- {
- if (GET_CODE (XVECEXP (x, 0, i)) == SET
- && SET_DEST (XVECEXP (x, 0, i)) == cc0_rtx)
- sets_cc0 = 1;
- else if (GET_CODE (XVECEXP (x, 0, i)) == SET)
- other_things = 1;
- }
+ if (GET_CODE (XVECEXP (x, 0, i)) == SET)
+ other_things = 1;
return ! sets_cc0 ? 0 : other_things ? -1 : 1;
}
return 0;
if (CALL_P (curr_insn))
no_output_reloads_p = true;
- if (HAVE_cc0 && reg_referenced_p (cc0_rtx, PATTERN (curr_insn)))
- no_input_reloads_p = true;
- if (HAVE_cc0 && reg_set_p (cc0_rtx, PATTERN (curr_insn)))
- no_output_reloads_p = true;
-
n_operands = curr_static_id->n_operands;
n_alternatives = curr_static_id->n_alternatives;
case PC: return pc_rtx;
case RETURN: return ret_rtx;
case SIMPLE_RETURN: return simple_return_rtx;
- case CC0: return cc0_rtx;
case REG:
return consolidate_reg (x);
if (JUMP_P (insn) || CALL_P (insn))
no_output_reloads = 1;
- if (HAVE_cc0 && reg_referenced_p (cc0_rtx, PATTERN (insn)))
- no_input_reloads = 1;
- if (HAVE_cc0 && reg_set_p (cc0_rtx, PATTERN (insn)))
- no_output_reloads = 1;
-
/* The eliminated forms of any secondary memory locations are per-insn, so
clear them out here. */
return label;
}
-
-/* INSN uses CC0 and is being moved into a delay slot. Set up REG_CC_SETTER
- and REG_CC_USER notes so we can find it. */
-
-static void
-link_cc0_insns (rtx_insn *insn)
-{
- rtx user = next_nonnote_insn (insn);
-
- if (NONJUMP_INSN_P (user) && GET_CODE (PATTERN (user)) == SEQUENCE)
- user = XVECEXP (PATTERN (user), 0, 0);
-
- add_reg_note (user, REG_CC_SETTER, insn);
- add_reg_note (insn, REG_CC_USER, user);
-}
\f
/* Insns which have delay slots that have not yet been filled. */
static void
delete_scheduled_jump (rtx_insn *insn)
{
- /* Delete the insn that sets cc0 for us. On machines without cc0, we could
- delete the insn that sets the condition code, but it is hard to find it.
- Since this case is rare anyway, don't bother trying; there would likely
- be other insns that became dead anyway, which we wouldn't know to
- delete. */
-
- if (HAVE_cc0 && reg_mentioned_p (cc0_rtx, insn))
- {
- rtx note = find_reg_note (insn, REG_CC_SETTER, NULL_RTX);
-
- /* If a reg-note was found, it points to an insn to set CC0. This
- insn is in the delay list of some other insn. So delete it from
- the delay list it was in. */
- if (note)
- {
- if (! FIND_REG_INC_NOTE (XEXP (note, 0), NULL_RTX)
- && sets_cc0_p (PATTERN (XEXP (note, 0))) == 1)
- delete_from_delay_slot (as_a <rtx_insn *> (XEXP (note, 0)));
- }
- else
- {
- /* The insn setting CC0 is our previous insn, but it may be in
- a delay slot. It will be the last insn in the delay slot, if
- it is. */
- rtx_insn *trial = previous_insn (insn);
- if (NOTE_P (trial))
- trial = prev_nonnote_insn (trial);
- if (sets_cc0_p (PATTERN (trial)) != 1
- || FIND_REG_INC_NOTE (trial, NULL_RTX))
- return;
- if (PREV_INSN (NEXT_INSN (trial)) == trial)
- delete_related_insns (trial);
- else
- delete_from_delay_slot (trial);
- }
- }
-
delete_related_insns (insn);
}
\f
target_main = XVECEXP (PATTERN (target), 0, 0);
if (resource_conflicts_p (&needed, &set)
- || (HAVE_cc0 && reg_mentioned_p (cc0_rtx, ipat))
/* The insn requiring the delay may not set anything needed or set by
INSN. */
|| insn_sets_resource_p (target_main, &needed, true)
true)
&& ! insn_sets_resource_p (trial, &needed, true)
/* Can't separate set of cc0 from its use. */
- && (!HAVE_cc0 || ! (reg_mentioned_p (cc0_rtx, pat) && ! sets_cc0_p (pat)))
&& ! can_throw_internal (trial))
{
trial = try_split (pat, trial, 1);
&& ! insn_references_resource_p (trial, &set, true)
&& ! insn_sets_resource_p (trial, &set, true)
&& ! insn_sets_resource_p (trial, &needed, true)
- && (!HAVE_cc0 && ! (reg_mentioned_p (cc0_rtx, pat) && ! sets_cc0_p (pat)))
+ && !HAVE_cc0
&& ! (maybe_never && may_trap_or_fault_p (pat))
&& (trial = try_split (pat, trial, 0))
&& eligible_for_delay (insn, slots_filled, trial, flags)
{
next_trial = next_nonnote_insn (trial);
add_to_delay_list (trial, &delay_list);
- if (HAVE_cc0 && reg_mentioned_p (cc0_rtx, pat))
- link_cc0_insns (trial);
delete_related_insns (trial);
if (slots_to_fill == ++slots_filled)
&& ! insn_references_resource_p (next_trial, &set, true)
&& ! insn_sets_resource_p (next_trial, &set, true)
&& ! insn_sets_resource_p (next_trial, &needed, true)
- && (!HAVE_cc0 || ! reg_mentioned_p (cc0_rtx, PATTERN (next_trial)))
&& ! (maybe_never && may_trap_or_fault_p (PATTERN (next_trial)))
&& (next_trial = try_split (PATTERN (next_trial), next_trial, 0))
&& eligible_for_delay (insn, slots_filled, next_trial, flags)
if (! insn_references_resource_p (trial, &set, true)
&& ! insn_sets_resource_p (trial, filter_flags ? &fset : &set, true)
&& ! insn_sets_resource_p (trial, &needed, true)
- /* If we're handling sets to the flags register specially, we
- only allow an insn into a delay-slot, if it either:
- - doesn't set the flags register,
- - the "set" of the flags register isn't used (clobbered),
- - insns between the delay-slot insn and the trial-insn
- as accounted in "set", have not affected the flags register. */
- && (! filter_flags
- || ! insn_sets_resource_p (trial, &flags_res, true)
- || find_regno_note (trial, REG_UNUSED, targetm.flags_regnum)
- || ! TEST_HARD_REG_BIT (set.regs, targetm.flags_regnum))
- && (!HAVE_cc0 || (! (reg_mentioned_p (cc0_rtx, pat)
- && (! own_thread || ! sets_cc0_p (pat)))))
&& ! can_throw_internal (trial))
{
rtx_insn *prior_insn;
must_annul = 1;
winner:
- if (HAVE_cc0 && reg_mentioned_p (cc0_rtx, pat))
- link_cc0_insns (trial);
-
/* If we own this thread, delete the insn. If this is the
destination of a branch, show that a basic block status
may have been updated. In any case, mark the new
{
rtx note, next;
- if (HAVE_cc0 && reg_referenced_p (cc0_rtx, PATTERN (insn)))
- {
- rtx_insn *prev = prev_nonnote_insn (insn);
- /* We assume that at this stage
- CC's are always set explicitly
- and always immediately before the jump that
- will use them. So if the previous insn
- exists to set the CC's, delete it
- (unless it performs auto-increments, etc.). */
- if (prev && NONJUMP_INSN_P (prev)
- && sets_cc0_p (PATTERN (prev)))
- {
- if (sets_cc0_p (PATTERN (prev)) > 0
- && ! side_effects_p (PATTERN (prev)))
- delete_computation (prev);
- else
- /* Otherwise, show that cc0 won't be used. */
- add_reg_note (prev, REG_UNUSED, cc0_rtx);
- }
- }
-
for (note = REG_NOTES (insn); note; note = next)
{
next = XEXP (note, 1);
#define CONSTM1_RTX(MODE) (const_tiny_rtx[3][(int) (MODE)])
extern GTY(()) rtx pc_rtx;
-extern GTY(()) rtx cc0_rtx;
extern GTY(()) rtx ret_rtx;
extern GTY(()) rtx simple_return_rtx;
extern GTY(()) rtx_insn *invalid_insn_rtx;
unsigned int regno, end_regno;
unsigned int i;
- /* Can't use cc0_rtx below since this file is used by genattrtab.c. */
- if (GET_CODE (x) == CC0)
- return 1;
-
gcc_assert (REG_P (x));
regno = REGNO (x);
/* Set nonzero when we find something of interest. */
rtx x = 0;
- /* If comparison with cc0, import actual comparison from compare
- insn. */
- if (op0 == cc0_rtx)
- {
- if ((prev = prev_nonnote_insn (prev)) == 0
- || !NONJUMP_INSN_P (prev)
- || (set = single_set (prev)) == 0
- || SET_DEST (set) != cc0_rtx)
- return 0;
-
- op0 = SET_SRC (set);
- op1 = CONST0_RTX (GET_MODE (op0));
- if (earliest)
- *earliest = prev;
- }
-
/* If this is a COMPARE, pick up the two things being compared. */
if (GET_CODE (op0) == COMPARE)
{