/* Perform instruction reorganizations for delay slot filling.
- Copyright (C) 1992, 93, 94, 95, 96, 1997 Free Software Foundation, Inc.
+ Copyright (C) 1992, 93, 94, 95, 96, 97, 1998 Free Software Foundation, Inc.
Contributed by Richard Kenner (kenner@vlsi1.ultra.nyu.edu).
Hacked by Michael Tiemann (tiemann@cygnus.com).
effect to the ARM, differing mostly in which insn is "in charge". */
#include "config.h"
-#include <stdio.h>
+#include "system.h"
#include "rtl.h"
+#include "expr.h"
#include "insn-config.h"
#include "conditions.h"
#include "hard-reg-set.h"
static int resource_conflicts_p PROTO((struct resources *,
struct resources *));
static int insn_references_resource_p PROTO((rtx, struct resources *, int));
-static int insn_sets_resources_p PROTO((rtx, struct resources *, int));
+static int insn_sets_resource_p PROTO((rtx, struct resources *, int));
static rtx find_end_label PROTO((void));
-static rtx emit_delay_sequence PROTO((rtx, rtx, int, int));
+static rtx emit_delay_sequence PROTO((rtx, rtx, int));
static rtx add_to_delay_list PROTO((rtx, rtx));
static void delete_from_delay_slot PROTO((rtx));
static void delete_scheduled_jump PROTO((rtx));
static void update_reg_unused_notes PROTO((rtx, rtx));
static void update_live_status PROTO((rtx, rtx));
static rtx next_insn_no_annul PROTO((rtx));
+static rtx find_dead_or_set_registers PROTO ((rtx, struct resources *, rtx *,
+ int, struct resources,
+ struct resources));
static void mark_target_live_regs PROTO((rtx, struct resources *));
-static void fill_simple_delay_slots PROTO((rtx, int));
+static void fill_simple_delay_slots PROTO((int));
static rtx fill_slots_from_thread PROTO((rtx, rtx, rtx, rtx, int, int,
- int, int, int, int *));
-static void fill_eager_delay_slots PROTO((rtx));
+ int, int, int *, rtx));
+static void fill_eager_delay_slots PROTO((void));
static void relax_delay_slots PROTO((rtx));
static void make_return_insns PROTO((rtx));
static int redirect_with_delay_slots_safe_p PROTO ((rtx, rtx, rtx));
static int redirect_with_delay_list_safe_p PROTO ((rtx, rtx, rtx));
\f
/* Given X, some rtl, and RES, a pointer to a `struct resource', mark
- which resources are references by the insn. If INCLUDE_CALLED_ROUTINE
+ which resources are references by the insn. If INCLUDE_DELAYED_EFFECTS
is TRUE, resources used by the called routine will be included for
CALL_INSNs. */
/* No special processing, just speed up. */
mark_referenced_resources (PATTERN (x), res, include_delayed_effects);
return;
+
+ default:
+ break;
}
/* Process each sub-expression and flag what it needs. */
}
}
\f
-/* Given X, a part of an insn, and a pointer to a `struct resource', RES,
- indicate which resources are modified by the insn. If INCLUDE_CALLED_ROUTINE
- is nonzero, also mark resources potentially set by the called routine.
+/* Given X, a part of an insn, and a pointer to a `struct resource',
+ RES, indicate which resources are modified by the insn. If
+ INCLUDE_DELAYED_EFFECTS is nonzero, also mark resources potentially
+ set by the called routine.
If IN_DEST is nonzero, it means we are inside a SET. Otherwise,
objects are being referenced instead of set.
for (i = 0; i < HARD_REGNO_NREGS (REGNO (x), GET_MODE (x)); i++)
SET_HARD_REG_BIT (res->regs, REGNO (x) + i);
return;
+
+ default:
+ break;
}
/* Process each sub-expression and flag what it needs. */
}
/* Return TRUE if any resource marked in RES, a `struct resources', is
- referenced by INSN. If INCLUDE_CALLED_ROUTINE is set, return if the called
+ referenced by INSN. If INCLUDE_DELAYED_EFFECTS is set, return if the called
routine is using those resources.
We compute this by computing all the resources referenced by INSN and
}
/* Return TRUE if INSN modifies resources that are marked in RES.
- INCLUDE_CALLED_ROUTINE is set if the actions of that routine should be
+ INCLUDE_DELAYED_EFFECTS is set if the actions of that routine should be
included. CC0 is only modified if it is explicitly set; see comments
in front of mark_set_resources for details. */
Returns the SEQUENCE that replaces INSN. */
static rtx
-emit_delay_sequence (insn, list, length, avail)
+emit_delay_sequence (insn, list, length)
rtx insn;
rtx list;
int length;
- int avail;
{
register int i = 1;
register rtx li;
int had_barrier = 0;
- /* Allocate the the rtvec to hold the insns and the SEQUENCE. */
+ /* Allocate the rtvec to hold the insns and the SEQUENCE. */
rtvec seqv = rtvec_alloc (length + 1);
- rtx seq = gen_rtx (SEQUENCE, VOIDmode, seqv);
+ rtx seq = gen_rtx_SEQUENCE (VOIDmode, seqv);
rtx seq_insn = make_insn_raw (seq);
rtx first = get_insns ();
rtx last = get_last_insn ();
if (tinfo)
tinfo->block = -1;
- return gen_rtx (INSN_LIST, VOIDmode, insn, NULL_RTX);
+ return gen_rtx_INSN_LIST (VOIDmode, insn, NULL_RTX);
}
/* Otherwise this must be an INSN_LIST. Add INSN to the end of the
return delay_list;
}
\f
-/* Delete INSN from the the delay slot of the insn that it is in. This may
+/* Delete INSN from the delay slot of the insn that it is in. This may
produce an insn without anything in its delay slots. */
static void
/* If there are any delay insns, remit them. Otherwise clear the
annul flag. */
if (delay_list)
- trial = emit_delay_sequence (trial, delay_list, XVECLEN (seq, 0) - 2, 0);
+ trial = emit_delay_sequence (trial, delay_list, XVECLEN (seq, 0) - 2);
else
INSN_ANNULLED_BRANCH_P (trial) = 0;
next = JUMP_LABEL (insn);
else
return 0;
+
+ default:
+ break;
}
}
if (XEXP (condition, 1) == const0_rtx)
return 1;
break;
+
+ default:
+ break;
}
/* Predict backward branches usually take, forward branches usually not. If
|| (GET_CODE (XEXP (src, 2)) == LABEL_REF
&& XEXP (XEXP (src, 2), 0) == target))
&& XEXP (src, 1) == pc_rtx)
- return gen_rtx (reverse_condition (GET_CODE (XEXP (src, 0))),
- GET_MODE (XEXP (src, 0)),
- XEXP (XEXP (src, 0), 0), XEXP (XEXP (src, 0), 1));
+ 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));
return 0;
}
redirect_with_delay_slots_safe_p (jump, newlabel, seq)
rtx jump, newlabel, seq;
{
- int flags, slots, i;
+ int flags, i;
rtx pat = PATTERN (seq);
/* Make sure all the delay slots of this jump would still
INSN_FROM_TARGET_P (next_to_match) = 0;
}
else
- merged_insns = gen_rtx (INSN_LIST, VOIDmode, trial, merged_insns);
+ merged_insns = gen_rtx_INSN_LIST (VOIDmode, trial, merged_insns);
if (++slot_number == num_slots)
break;
INSN_FROM_TARGET_P (next_to_match) = 0;
}
else
- merged_insns = gen_rtx (INSN_LIST, SImode, dtrial,
- merged_insns);
+ merged_insns = gen_rtx_INSN_LIST (SImode, dtrial,
+ merged_insns);
if (++slot_number == num_slots)
break;
/* If all insns in the delay slot have been matched and we were previously
annulling the branch, we need not any more. In that case delete all the
- merged insns. Also clear the INSN_FROM_TARGET_P bit of each insn the
+ merged insns. Also clear the INSN_FROM_TARGET_P bit of each insn in
the delay list so that we know that it isn't only being used at the
target. */
if (slot_number == num_slots && annul_p)
if (GET_CODE (XVECEXP (pat, 0, 0)) == CALL_INSN)
return 0;
- /* If this this is an INSN or JUMP_INSN with delayed effects, it
+ /* If this is an INSN or JUMP_INSN with delayed effects, it
is hard to track the resource needs properly, so give up. */
#ifdef INSN_SETS_ARE_DELAYED
if (INSN_FROM_TARGET_P (insn))
return;
- emit_insn_before (gen_rtx (USE, VOIDmode, insn), where);
+ emit_insn_before (gen_rtx_USE (VOIDmode, insn), where);
/* INSN might be making a value live in a block where it didn't use to
be. So recompute liveness information for this block. */
update_reg_unused_notes (insn, redundant_insn)
rtx insn, redundant_insn;
{
- rtx p, link, next;
+ rtx link, next;
for (link = REG_NOTES (insn); link; link = next)
{
break;
}
}
+
+ default:
+ break;
}
if (GET_CODE (this_jump_insn) == JUMP_INSN)
int b = -1;
int i;
struct target_info *tinfo;
- rtx insn, next;
+ rtx insn;
rtx jump_insn = 0;
rtx jump_target;
HARD_REG_SET scratch;
struct resources set, needed;
- int jump_count = 0;
/* Handle end of function. */
if (target == 0)
through FINAL_SEQUENCE. */
static void
-fill_simple_delay_slots (first, non_jumps_p)
- rtx first;
+fill_simple_delay_slots (non_jumps_p)
int non_jumps_p;
{
register rtx insn, pat, trial, next_trial;
- register int i, j;
+ register int i;
int num_unfilled_slots = unfilled_slots_next - unfilled_slots_base;
struct resources needed, set;
int slots_to_fill, slots_filled;
tail, of the list. */
update_reg_dead_notes (trial, insn);
- delay_list = gen_rtx (INSN_LIST, VOIDmode,
- trial, delay_list);
+ delay_list = gen_rtx_INSN_LIST (VOIDmode,
+ trial, delay_list);
update_block (trial, trial);
delete_insn (trial);
if (slots_to_fill == ++slots_filled)
NULL, 1, 1,
own_thread_p (JUMP_LABEL (insn),
JUMP_LABEL (insn), 0),
- 0, slots_to_fill, &slots_filled);
+ slots_to_fill, &slots_filled,
+ delay_list);
if (delay_list)
unfilled_slots_base[i]
- = emit_delay_sequence (insn, delay_list,
- slots_filled, slots_to_fill);
+ = emit_delay_sequence (insn, delay_list, slots_filled);
if (slots_to_fill == slots_filled)
unfilled_slots_base[i] = 0;
insns we find on the head of the list. */
current_function_epilogue_delay_list
- = gen_rtx (INSN_LIST, VOIDmode, trial,
- current_function_epilogue_delay_list);
+ = gen_rtx_INSN_LIST (VOIDmode, trial,
+ current_function_epilogue_delay_list);
mark_referenced_resources (trial, &end_of_function_needs, 1);
update_block (trial, trial);
delete_insn (trial);
static rtx
fill_slots_from_thread (insn, condition, thread, opposite_thread, likely,
- thread_if_true, own_thread, own_opposite_thread,
- slots_to_fill, pslots_filled)
+ thread_if_true, own_thread,
+ slots_to_fill, pslots_filled, delay_list)
rtx insn;
rtx condition;
rtx thread, opposite_thread;
int likely;
int thread_if_true;
- int own_thread, own_opposite_thread;
+ int own_thread;
int slots_to_fill, *pslots_filled;
+ rtx delay_list;
{
rtx new_thread;
- rtx delay_list = 0;
struct resources opposite_needed, set, needed;
rtx trial;
int lose = 0;
/* If our thread is the end of subroutine, we can't get any delay
insns from that. */
if (thread == 0)
- return 0;
+ return delay_list;
/* If this is an unconditional branch, nothing is needed at the
opposite thread. Otherwise, compute what is needed there. */
/* If TRIAL is redundant with some insn before INSN, we don't
actually need to add it to the delay list; we can merely pretend
we did. */
- if (prior_insn = redundant_insn (trial, insn, delay_list))
+ if ((prior_insn = redundant_insn (trial, insn, delay_list)))
{
fix_reg_dead_note (prior_insn, insn);
if (own_thread)
delay_list = add_to_delay_list (temp, delay_list);
+ mark_set_resources (trial, &opposite_needed, 0, 1);
+
if (slots_to_fill == ++(*pslots_filled))
{
/* Even though we have filled all the slots, we
&& ! insn_sets_resource_p (new_thread, &needed, 1)
&& ! insn_references_resource_p (new_thread,
&set, 1)
- && redundant_insn (new_thread, insn, delay_list))
- new_thread = next_active_insn (new_thread);
+ && (prior_insn
+ = redundant_insn (new_thread, insn,
+ delay_list)))
+ {
+ /* We know we do not own the thread, so no need
+ to call update_block and delete_insn. */
+ fix_reg_dead_note (prior_insn, insn);
+ update_reg_unused_notes (prior_insn, new_thread);
+ new_thread = next_active_insn (new_thread);
+ }
break;
}
{
/* 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)
+ if (thread_if_true && trial == new_thread
+ && ! insn_references_resource_p (XVECEXP (PATTERN (trial), 0, 0),
+ &opposite_needed, 0))
delay_list
= steal_delay_list_from_target (insn, condition, PATTERN (trial),
delay_list, &set, &needed,
the negated constant. Otherwise, reverse the sense of the
arithmetic. */
if (GET_CODE (other) == CONST_INT)
- new_arith = gen_rtx (GET_CODE (src), GET_MODE (src), dest,
- negate_rtx (GET_MODE (src), other));
+ new_arith = gen_rtx_fmt_ee (GET_CODE (src), GET_MODE (src), dest,
+ negate_rtx (GET_MODE (src), other));
else
- new_arith = gen_rtx (GET_CODE (src) == PLUS ? MINUS : PLUS,
- GET_MODE (src), dest, other);
+ new_arith = gen_rtx_fmt_ee (GET_CODE (src) == PLUS ? MINUS : PLUS,
+ GET_MODE (src), dest, other);
- ninsn = emit_insn_after (gen_rtx (SET, VOIDmode, dest, new_arith),
+ ninsn = emit_insn_after (gen_rtx_SET (VOIDmode, dest, new_arith),
insn);
if (recog_memoized (ninsn) < 0
if safe. */
static void
-fill_eager_delay_slots (first)
- rtx first;
+fill_eager_delay_slots ()
{
register rtx insn;
register int i;
delay_list
= fill_slots_from_thread (insn, condition, insn_at_target,
fallthrough_insn, prediction == 2, 1,
- own_target, own_fallthrough,
- slots_to_fill, &slots_filled);
+ own_target,
+ slots_to_fill, &slots_filled, delay_list);
if (delay_list == 0 && own_fallthrough)
{
delay_list
= fill_slots_from_thread (insn, condition, fallthrough_insn,
insn_at_target, 0, 0,
- own_fallthrough, own_target,
- slots_to_fill, &slots_filled);
+ own_fallthrough,
+ slots_to_fill, &slots_filled,
+ delay_list);
}
}
else
delay_list
= fill_slots_from_thread (insn, condition, fallthrough_insn,
insn_at_target, 0, 0,
- own_fallthrough, own_target,
- slots_to_fill, &slots_filled);
+ own_fallthrough,
+ slots_to_fill, &slots_filled,
+ delay_list);
if (delay_list == 0)
delay_list
= fill_slots_from_thread (insn, condition, insn_at_target,
next_active_insn (insn), 0, 1,
- own_target, own_fallthrough,
- slots_to_fill, &slots_filled);
+ own_target,
+ slots_to_fill, &slots_filled,
+ delay_list);
}
if (delay_list)
unfilled_slots_base[i]
- = emit_delay_sequence (insn, delay_list,
- slots_filled, slots_to_fill);
+ = emit_delay_sequence (insn, delay_list, slots_filled);
if (slots_to_fill == slots_filled)
unfilled_slots_base[i] = 0;
if (--LABEL_NUSES (real_return_label) == 0)
delete_insn (real_return_label);
- fill_simple_delay_slots (first, 1);
- fill_simple_delay_slots (first, 0);
+ fill_simple_delay_slots (1);
+ fill_simple_delay_slots (0);
}
#endif
\f
start_of_epilogue_needs = end_of_function_needs;
- while (epilogue_insn = next_nonnote_insn (epilogue_insn))
+ while ((epilogue_insn = next_nonnote_insn (epilogue_insn)))
mark_set_resources (epilogue_insn, &end_of_function_needs, 0, 1);
/* Show we haven't computed an end-of-function label yet. */
reorg_pass_number < MAX_REORG_PASSES;
reorg_pass_number++)
{
- fill_simple_delay_slots (first, 1);
- fill_simple_delay_slots (first, 0);
- fill_eager_delay_slots (first);
+ fill_simple_delay_slots (1);
+ fill_simple_delay_slots (0);
+ fill_eager_delay_slots ();
relax_delay_slots (first);
}
continue;
pred_flags = get_jump_flags (insn, JUMP_LABEL (insn));
- REG_NOTES (insn) = gen_rtx (EXPR_LIST, REG_BR_PRED,
- GEN_INT (pred_flags), REG_NOTES (insn));
+ REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_BR_PRED,
+ GEN_INT (pred_flags),
+ REG_NOTES (insn));
}
}
#endif /* DELAY_SLOTS */