/* Perform instruction reorganizations for delay slot filling.
Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998,
- 1999, 2000 Free Software Foundation, Inc.
+ 1999, 2000, 2001, 2002 Free Software Foundation, Inc.
Contributed by Richard Kenner (kenner@vlsi1.ultra.nyu.edu).
Hacked by Michael Tiemann (tiemann@cygnus.com).
based on the condition code of the previous insn.
The HP-PA can conditionally nullify insns, providing a similar
- effect to the ARM, differing mostly in which insn is "in charge". */
+ effect to the ARM, differing mostly in which insn is "in charge". */
#include "config.h"
#include "system.h"
static int
insn_references_resource_p (insn, res, include_delayed_effects)
- register rtx insn;
- register struct resources *res;
+ rtx insn;
+ struct resources *res;
int include_delayed_effects;
{
struct resources insn_res;
static int
insn_sets_resource_p (insn, res, include_delayed_effects)
- register rtx insn;
- register struct resources *res;
+ rtx insn;
+ struct resources *res;
int include_delayed_effects;
{
struct resources insn_sets;
rtx list;
int length;
{
- register int i = 1;
- register rtx li;
+ int i = 1;
+ rtx li;
int had_barrier = 0;
/* Allocate the rtvec to hold the insns and the SEQUENCE. */
We will put the BARRIER back in later. */
if (NEXT_INSN (insn) && GET_CODE (NEXT_INSN (insn)) == BARRIER)
{
- delete_insn (NEXT_INSN (insn));
+ delete_related_insns (NEXT_INSN (insn));
last = get_last_insn ();
had_barrier = 1;
}
for (li = list; li; li = XEXP (li, 1), i++)
{
rtx tem = XEXP (li, 0);
- rtx note;
+ rtx note, next;
/* Show that this copy of the insn isn't deleted. */
INSN_DELETED_P (tem) = 0;
PREV_INSN (tem) = XVECEXP (seq, 0, i - 1);
NEXT_INSN (XVECEXP (seq, 0, i - 1)) = tem;
- /* Remove any REG_DEAD notes because we can't rely on them now
- that the insn has been moved. */
- for (note = REG_NOTES (tem); note; note = XEXP (note, 1))
- if (REG_NOTE_KIND (note) == REG_DEAD)
- XEXP (note, 0) = const0_rtx;
+ for (note = REG_NOTES (tem); note; note = next)
+ {
+ next = XEXP (note, 1);
+ switch (REG_NOTE_KIND (note))
+ {
+ case REG_DEAD:
+ /* Remove any REG_DEAD notes because we can't rely on them now
+ that the insn has been moved. */
+ remove_note (tem, note);
+ break;
+
+ case REG_LABEL:
+ /* Keep the label reference count up to date. */
+ if (GET_CODE (XEXP (note, 0)) == CODE_LABEL)
+ LABEL_NUSES (XEXP (note, 0)) ++;
+ break;
+
+ default:
+ break;
+ }
+ }
}
NEXT_INSN (XVECEXP (seq, 0, length)) = NEXT_INSN (seq_insn);
list, and rebuild the delay list if non-empty. */
prev = PREV_INSN (seq_insn);
trial = XVECEXP (seq, 0, 0);
- delete_insn (seq_insn);
+ delete_related_insns (seq_insn);
add_insn_after (trial, prev);
if (GET_CODE (trial) == JUMP_INSN
annul flag. */
if (delay_list)
trial = emit_delay_sequence (trial, delay_list, XVECLEN (seq, 0) - 2);
- else
+ else if (GET_CODE (trial) == JUMP_INSN
+ || GET_CODE (trial) == CALL_INSN
+ || GET_CODE (trial) == INSN)
INSN_ANNULLED_BRANCH_P (trial) = 0;
INSN_FROM_TARGET_P (insn) = 0;
if (GET_CODE (trial) == NOTE)
trial = prev_nonnote_insn (trial);
if (sets_cc0_p (PATTERN (trial)) != 1
- || FIND_REG_INC_NOTE (trial, 0))
+ || FIND_REG_INC_NOTE (trial, NULL_RTX))
return;
if (PREV_INSN (NEXT_INSN (trial)) == trial)
- delete_insn (trial);
+ delete_related_insns (trial);
else
delete_from_delay_slot (trial);
}
}
#endif
- delete_insn (insn);
+ delete_related_insns (insn);
}
\f
/* Counters for delay-slot filling. */
static rtx
optimize_skip (insn)
- register rtx insn;
+ rtx insn;
{
- register rtx trial = next_nonnote_insn (insn);
+ rtx trial = next_nonnote_insn (insn);
rtx next_trial = next_active_insn (trial);
rtx delay_list = 0;
rtx target_label;
|| GET_CODE (PATTERN (trial)) == SEQUENCE
|| recog_memoized (trial) < 0
|| (! eligible_for_annul_false (insn, 0, trial, flags)
- && ! eligible_for_annul_true (insn, 0, trial, flags)))
+ && ! eligible_for_annul_true (insn, 0, trial, flags))
+ || can_throw_internal (trial))
return 0;
/* There are two cases where we are just executing one insn (we assume
delay_list = add_to_delay_list (trial, NULL_RTX);
next_trial = next_active_insn (trial);
update_block (trial, trial);
- delete_insn (trial);
+ delete_related_insns (trial);
/* Also, if we are targeting an unconditional
branch, thread our jump to the target of that branch. Don't
|| (GET_CODE (XEXP (src, 2)) == LABEL_REF
&& XEXP (XEXP (src, 2), 0) == target))
&& XEXP (src, 1) == pc_rtx)
- return gen_rtx_fmt_ee (reverse_condition (GET_CODE (XEXP (src, 0))),
- GET_MODE (XEXP (src, 0)),
- XEXP (XEXP (src, 0), 0), XEXP (XEXP (src, 0), 1));
+ {
+ enum rtx_code rev;
+ rev = reversed_comparison_code (XEXP (src, 0), insn);
+ if (rev != UNKNOWN)
+ return gen_rtx_fmt_ee (rev, GET_MODE (XEXP (src, 0)),
+ XEXP (XEXP (src, 0), 0),
+ XEXP (XEXP (src, 0), 1));
+ }
return 0;
}
if (trial == thread)
thread = next_active_insn (thread);
- delete_insn (trial);
+ delete_related_insns (trial);
INSN_FROM_TARGET_P (next_to_match) = 0;
}
else
else
{
update_block (XEXP (merged_insns, 0), thread);
- delete_insn (XEXP (merged_insns, 0));
+ delete_related_insns (XEXP (merged_insns, 0));
}
}
fill_simple_delay_slots (non_jumps_p)
int non_jumps_p;
{
- register rtx insn, pat, trial, next_trial;
- register int i;
+ rtx insn, pat, trial, next_trial;
+ int i;
int num_unfilled_slots = unfilled_slots_next - unfilled_slots_base;
struct resources needed, set;
int slots_to_fill, slots_filled;
&& GET_CODE (trial) == JUMP_INSN
&& simplejump_p (trial)
&& eligible_for_delay (insn, slots_filled, trial, flags)
- && no_labels_between_p (insn, trial))
+ && no_labels_between_p (insn, trial)
+ && ! can_throw_internal (trial))
{
rtx *tmp;
slots_filled++;
tmp++;
/* Remove the unconditional jump from consideration for delay slot
- filling and unthread it. */
+ filling and unthread it. */
if (*tmp == trial)
*tmp = 0;
{
/* Can't separate set of cc0 from its use. */
&& ! (reg_mentioned_p (cc0_rtx, pat) && ! sets_cc0_p (pat))
#endif
- )
+ && ! can_throw_internal (trial))
{
trial = try_split (pat, trial, 1);
next_trial = prev_nonnote_insn (trial);
delay_list = gen_rtx_INSN_LIST (VOIDmode,
trial, delay_list);
update_block (trial, trial);
- delete_insn (trial);
+ delete_related_insns (trial);
if (slots_to_fill == ++slots_filled)
break;
continue;
int i = 2;
- try {
+ try {
f();
i = 3;
} catch (...) {}
-
+
return i;
Even though `i' is a local variable, we must be sure not
Presumably, we should also check to see if we could get
back to this function via `setjmp'. */
- && !can_throw_internal (insn)
+ && ! can_throw_internal (insn)
&& (GET_CODE (insn) != JUMP_INSN
|| ((condjump_p (insn) || condjump_in_parallel_p (insn))
&& ! simplejump_p (insn)
break;
/* See if we have a resource problem before we try to
- split. */
+ split. */
if (GET_CODE (pat) != SEQUENCE
&& ! insn_references_resource_p (trial, &set, 1)
&& ! insn_sets_resource_p (trial, &set, 1)
#endif
&& ! (maybe_never && may_trap_p (pat))
&& (trial = try_split (pat, trial, 0))
- && eligible_for_delay (insn, slots_filled, trial, flags))
+ && eligible_for_delay (insn, slots_filled, trial, flags)
+ && ! can_throw_internal(trial))
{
next_trial = next_nonnote_insn (trial);
delay_list = add_to_delay_list (trial, delay_list);
link_cc0_insns (trial);
#endif
- delete_insn (trial);
+ delete_related_insns (trial);
if (slots_to_fill == ++slots_filled)
break;
continue;
#endif
&& ! (maybe_never && may_trap_p (PATTERN (next_trial)))
&& (next_trial = try_split (PATTERN (next_trial), next_trial, 0))
- && eligible_for_delay (insn, slots_filled, next_trial, flags))
+ && eligible_for_delay (insn, slots_filled, next_trial, flags)
+ && ! can_throw_internal (trial))
{
rtx new_label = next_active_insn (next_trial);
/* Don't want to mess with cc0 here. */
&& ! reg_mentioned_p (cc0_rtx, pat)
#endif
- )
+ && ! can_throw_internal (trial))
{
trial = try_split (pat, trial, 1);
if (ELIGIBLE_FOR_EPILOGUE_DELAY (trial, slots_filled))
current_function_epilogue_delay_list);
mark_end_of_function_resources (trial, 1);
update_block (trial, trial);
- delete_insn (trial);
+ delete_related_insns (trial);
/* Clear deleted bit so final.c will output the insn. */
INSN_DELETED_P (trial) = 0;
&& ! (reg_mentioned_p (cc0_rtx, pat)
&& (! own_thread || ! sets_cc0_p (pat)))
#endif
- )
+ && ! can_throw_internal (trial))
{
rtx prior_insn;
new_thread = thread;
}
- delete_insn (trial);
+ delete_related_insns (trial);
}
else
{
starting point of this thread. */
if (own_thread)
{
+ rtx note;
+
update_block (trial, thread);
if (trial == thread)
{
if (new_thread == trial)
new_thread = thread;
}
- delete_insn (trial);
+
+ /* We are moving this insn, not deleting it. We must
+ temporarily increment the use count on any referenced
+ label lest it be deleted by delete_related_insns. */
+ note = find_reg_note (trial, REG_LABEL, 0);
+ /* REG_LABEL could be NOTE_INSN_DELETED_LABEL too. */
+ if (note && GET_CODE (XEXP (note, 0)) == CODE_LABEL)
+ LABEL_NUSES (XEXP (note, 0))++;
+
+ delete_related_insns (trial);
+
+ if (note && GET_CODE (XEXP (note, 0)) == CODE_LABEL)
+ LABEL_NUSES (XEXP (note, 0))--;
}
else
new_thread = next_active_insn (trial);
/* If this is the `true' thread, we will want to follow the jump,
so we can only do this if we have taken everything up to here. */
if (thread_if_true && trial == new_thread)
- delay_list
- = steal_delay_list_from_target (insn, condition, PATTERN (trial),
- delay_list, &set, &needed,
- &opposite_needed, slots_to_fill,
- pslots_filled, &must_annul,
- &new_thread);
+ {
+ delay_list
+ = steal_delay_list_from_target (insn, condition, PATTERN (trial),
+ delay_list, &set, &needed,
+ &opposite_needed, slots_to_fill,
+ pslots_filled, &must_annul,
+ &new_thread);
+ /* If we owned the thread and are told that it branched
+ elsewhere, make sure we own the thread at the new location. */
+ if (own_thread && trial != new_thread)
+ own_thread = own_thread_p (new_thread, new_thread, 0);
+ }
else if (! thread_if_true)
delay_list
= steal_delay_list_from_fallthrough (insn, condition,
trial = new_thread;
pat = PATTERN (trial);
- if (GET_CODE (trial) != INSN || GET_CODE (pat) != SET
- || ! eligible_for_delay (insn, 0, trial, flags))
+ if (GET_CODE (trial) != INSN
+ || GET_CODE (pat) != SET
+ || ! eligible_for_delay (insn, 0, trial, flags)
+ || can_throw_internal (trial))
return 0;
dest = SET_DEST (pat), src = SET_SRC (pat);
if (recog_memoized (ninsn) < 0
|| (extract_insn (ninsn), ! constrain_operands (1)))
{
- delete_insn (ninsn);
+ delete_related_insns (ninsn);
return 0;
}
if (new_thread == trial)
new_thread = thread;
}
- delete_insn (trial);
+ delete_related_insns (trial);
}
else
new_thread = next_active_insn (trial);
static void
fill_eager_delay_slots ()
{
- register rtx insn;
- register int i;
+ rtx insn;
+ int i;
int num_unfilled_slots = unfilled_slots_next - unfilled_slots_base;
for (i = 0; i < num_unfilled_slots; i++)
relax_delay_slots (first)
rtx first;
{
- register rtx insn, next, pat;
- register rtx trial, delay_insn, target_label;
+ rtx insn, next, pat;
+ rtx trial, delay_insn, target_label;
/* Look at every JUMP_INSN and see if we can improve it. */
for (insn = first; insn; insn = next)
if (target_label != JUMP_LABEL (insn))
reorg_redirect_jump (insn, target_label);
- /* See if this jump branches around a unconditional jump.
+ /* See if this jump branches around an unconditional jump.
If so, invert this jump and point it to the target of the
second jump. */
if (next && GET_CODE (next) == JUMP_INSN
if (invert_jump (insn, label, 1))
{
- delete_insn (next);
+ delete_related_insns (next);
next = insn;
}
--LABEL_NUSES (label);
if (--LABEL_NUSES (target_label) == 0)
- delete_insn (target_label);
+ delete_related_insns (target_label);
continue;
}
INSN_FROM_TARGET_P (XVECEXP (pat, 0, i)) = 0;
trial = PREV_INSN (insn);
- delete_insn (insn);
+ delete_related_insns (insn);
emit_insn_after (pat, trial);
delete_scheduled_jump (delay_insn);
continue;
insn, redirect the jump to the following insn process again. */
trial = next_active_insn (target_label);
if (trial && GET_CODE (PATTERN (trial)) != SEQUENCE
- && redundant_insn (trial, insn, 0))
+ && redundant_insn (trial, insn, 0)
+ && ! can_throw_internal (trial))
{
rtx tmp;
INSN_FROM_TARGET_P (XVECEXP (pat, 0, i)) = 0;
trial = PREV_INSN (insn);
- delete_insn (insn);
+ delete_related_insns (insn);
emit_insn_after (pat, trial);
delete_scheduled_jump (delay_insn);
continue;
&& XVECLEN (pat, 0) == 2
&& rtx_equal_p (PATTERN (next), PATTERN (XVECEXP (pat, 0, 1))))
{
- delete_insn (insn);
+ delete_related_insns (insn);
continue;
}
INSN_FROM_TARGET_P (slot) = ! INSN_FROM_TARGET_P (slot);
}
- delete_insn (next);
+ delete_related_insns (next);
next = insn;
}
if (old_label && --LABEL_NUSES (old_label) == 0)
- delete_insn (old_label);
+ delete_related_insns (old_label);
continue;
}
}
{
rtx prev = PREV_INSN (insn);
- delete_insn (insn);
+ delete_related_insns (insn);
for (i = 1; i < XVECLEN (pat, 0); i++)
prev = emit_insn_after (PATTERN (XVECEXP (pat, 0, i)), prev);
/* Now delete REAL_RETURN_LABEL if we never used it. Then try to fill any
new delay slots we have created. */
if (--LABEL_NUSES (real_return_label) == 0)
- delete_insn (real_return_label);
+ delete_related_insns (real_return_label);
fill_simple_delay_slots (1);
fill_simple_delay_slots (0);
if (GET_CODE (insn) == INSN && GET_CODE (PATTERN (insn)) == USE
&& INSN_P (XEXP (PATTERN (insn), 0)))
- next = delete_insn (insn);
+ next = delete_related_insns (insn);
}
/* If we made an end of function label, indicate that it is now
safe to delete it by undoing our prior adjustment to LABEL_NUSES.
If it is now unused, delete it. */
if (end_of_function_label && --LABEL_NUSES (end_of_function_label) == 0)
- delete_insn (end_of_function_label);
+ delete_related_insns (end_of_function_label);
#ifdef HAVE_return
if (HAVE_return && end_of_function_label != 0)
/* It is not clear why the line below is needed, but it does seem to be. */
unfilled_firstobj = (rtx *) obstack_alloc (&unfilled_slots_obstack, 0);
- /* Reposition the prologue and epilogue notes in case we moved the
- prologue/epilogue insns. */
- reposition_prologue_and_epilogue_notes (first);
-
if (file)
{
- register int i, j, need_comma;
+ int i, j, need_comma;
int total_delay_slots[MAX_DELAY_HISTOGRAM + 1];
int total_annul_slots[MAX_DELAY_HISTOGRAM + 1];