beginning of basic blocks that have been scheduled. */
\f
#include "config.h"
-#include <stdio.h>
-#if HAVE_STDLIB_H
-#include <stdlib.h>
-#endif
+#include "system.h"
#include "rtl.h"
#include "basic-block.h"
#include "regs.h"
#include "insn-config.h"
#include "insn-attr.h"
+#ifndef INSN_SCHEDULING
+void
+schedule_insns (dump_file)
+ FILE *dump_file ATTRIBUTE_UNUSED;
+{
+}
+#else /* INSN_SCHEDULING -- rest of file */
+
extern char *reg_known_equiv_p;
extern rtx *reg_known_value;
-#ifdef INSN_SCHEDULING
/* Arrays set up by scheduling for the same respective purposes as
similar-named arrays set up by flow analysis. We work with these
arrays during the scheduling pass so we can compare values against
The transition (R->S) is implemented in the scheduling loop in
`schedule_block' when the best insn to schedule is chosen.
The transition (R->Q) is implemented in `schedule_select' when an
- insn is found to to have a function unit conflict with the already
+ insn is found to have a function unit conflict with the already
committed insns.
The transitions (P->R and P->Q) are implemented in `schedule_insn' as
insns move from the ready list to the scheduled list.
static void sched_analyze_insn PROTO((rtx, rtx, rtx));
static int sched_analyze PROTO((rtx, rtx));
static void sched_note_set PROTO((int, rtx, int));
-static int rank_for_schedule PROTO((rtx *, rtx *));
+static int rank_for_schedule PROTO((const GENERIC_PTR, const GENERIC_PTR));
static void swap_sort PROTO((rtx *, int));
static void queue_insn PROTO((rtx, int));
static int birthing_insn_p PROTO((rtx));
/* Main entry point of this file. */
void schedule_insns PROTO((FILE *));
-
-#endif /* INSN_SCHEDULING */
\f
#define SIZE_FOR_MODE(X) (GET_MODE_SIZE (GET_MODE (X)))
return;
}
\f
-#ifndef INSN_SCHEDULING
-void
-schedule_insns (dump_file)
- FILE *dump_file;
-{
-}
-#else
#ifndef __GNUC__
#define __inline
#endif
/* Add a pair of fake REG_NOTEs which we will later
convert back into a NOTE_INSN_SETJMP note. See
- reemit_notes for why we use a pair of of NOTEs. */
+ reemit_notes for why we use a pair of NOTEs. */
REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_DEAD,
GEN_INT (0),
|| NOTE_LINE_NUMBER (insn) == NOTE_INSN_LOOP_END
|| NOTE_LINE_NUMBER (insn) == NOTE_INSN_EH_REGION_BEG
|| NOTE_LINE_NUMBER (insn) == NOTE_INSN_EH_REGION_END
+ || NOTE_LINE_NUMBER (insn) == NOTE_INSN_RANGE_START
+ || NOTE_LINE_NUMBER (insn) == NOTE_INSN_RANGE_END
|| (NOTE_LINE_NUMBER (insn) == NOTE_INSN_SETJMP
&& GET_CODE (PREV_INSN (insn)) != CALL_INSN)))
{
static int
rank_for_schedule (x, y)
- rtx *x, *y;
+ const GENERIC_PTR x;
+ const GENERIC_PTR y;
{
- rtx tmp = *y;
- rtx tmp2 = *x;
+ rtx tmp = *(rtx *)y;
+ rtx tmp2 = *(rtx *)x;
rtx link;
int tmp_class, tmp2_class;
int value;
#endif
&& regno != STACK_POINTER_REGNUM)
{
- /* ??? It is perhaps a dead_or_set_p bug that it does
- not check for REG_UNUSED notes itself. This is necessary
- for the case where the SET_DEST is a subreg of regno, as
- dead_or_set_p handles subregs specially. */
- if (! all_needed && ! dead_or_set_p (insn, x)
- && ! find_reg_note (insn, REG_UNUSED, x))
+ if (! all_needed && ! dead_or_set_p (insn, x))
{
/* Check for the case where the register dying partially
overlaps the register set by this insn. */
return;
case SUBREG:
+ attach_deaths (SUBREG_REG (x), insn,
+ set_p && ((GET_MODE_SIZE (GET_MODE (SUBREG_REG (x)))
+ <= UNITS_PER_WORD)
+ || (GET_MODE_SIZE (GET_MODE (SUBREG_REG (x)))
+ == GET_MODE_SIZE (GET_MODE ((x))))));
+ return;
+
case STRICT_LOW_PART:
- /* These two cases preserve the value of SET_P, so handle them
- separately. */
- attach_deaths (XEXP (x, 0), insn, set_p);
+ attach_deaths (XEXP (x, 0), insn, 0);
return;
case ZERO_EXTRACT:
case SIGN_EXTRACT:
- /* This case preserves the value of SET_P for the first operand, but
- clears it for the other two. */
- attach_deaths (XEXP (x, 0), insn, set_p);
+ attach_deaths (XEXP (x, 0), insn, 0);
attach_deaths (XEXP (x, 1), insn, 0);
attach_deaths (XEXP (x, 2), insn, 0);
return;
else if (NOTE_LINE_NUMBER (insn) != NOTE_INSN_SETJMP
&& NOTE_LINE_NUMBER (insn) != NOTE_INSN_LOOP_BEG
&& NOTE_LINE_NUMBER (insn) != NOTE_INSN_LOOP_END
+ && NOTE_LINE_NUMBER (insn) != NOTE_INSN_RANGE_START
+ && NOTE_LINE_NUMBER (insn) != NOTE_INSN_RANGE_END
&& NOTE_LINE_NUMBER (insn) != NOTE_INSN_EH_REGION_BEG
&& NOTE_LINE_NUMBER (insn) != NOTE_INSN_EH_REGION_END)
{
reg_pending_sets_all = 0;
clear_units ();
+#if 0
+ /* We used to have code to avoid getting parameters moved from hard
+ argument registers into pseudos.
+
+ However, it was removed when it proved to be of marginal benefit and
+ caused problems because of different notions of what the "head" insn
+ was. */
+
/* Remove certain insns at the beginning from scheduling,
by advancing HEAD. */
head = NEXT_INSN (head);
}
}
+#endif
/* Don't include any notes or labels at the beginning of the
basic block, or notes at the ends of basic blocks. */
if (GET_CODE (dest) == REG)
{
+ /* If the original insn already used this register, we may not add new
+ notes for it. One example for a split that needs this test is
+ when a multi-word memory access with register-indirect addressing
+ is split into multiple memory accesses with auto-increment and
+ one adjusting add instruction for the address register. */
+ if (reg_referenced_p (dest, PATTERN (orig_insn)))
+ return;
for (tem = last; tem != insn; tem = PREV_INSN (tem))
{
if (GET_RTX_CLASS (GET_CODE (tem)) == 'i'
remember how far we can cut back the stack on exit. */
/* Allocate data for this pass. See comments, above,
- for what these vectors do. */
- insn_luid = (int *) alloca (max_uid * sizeof (int));
- insn_priority = (int *) alloca (max_uid * sizeof (int));
- insn_tick = (int *) alloca (max_uid * sizeof (int));
- insn_costs = (short *) alloca (max_uid * sizeof (short));
- insn_units = (short *) alloca (max_uid * sizeof (short));
- insn_blockage = (unsigned int *) alloca (max_uid * sizeof (unsigned int));
- insn_ref_count = (int *) alloca (max_uid * sizeof (int));
+ for what these vectors do.
+
+ We use xmalloc instead of alloca, because max_uid can be very large
+ when there is a lot of function inlining. If we used alloca, we could
+ exceed stack limits on some hosts for some inputs. */
+ insn_luid = (int *) xmalloc (max_uid * sizeof (int));
+ insn_priority = (int *) xmalloc (max_uid * sizeof (int));
+ insn_tick = (int *) xmalloc (max_uid * sizeof (int));
+ insn_costs = (short *) xmalloc (max_uid * sizeof (short));
+ insn_units = (short *) xmalloc (max_uid * sizeof (short));
+ insn_blockage = (unsigned int *) xmalloc (max_uid * sizeof (unsigned int));
+ insn_ref_count = (int *) xmalloc (max_uid * sizeof (int));
if (reload_completed == 0)
{
{
rtx line;
- line_note = (rtx *) alloca (max_uid * sizeof (rtx));
+ line_note = (rtx *) xmalloc (max_uid * sizeof (rtx));
bzero ((char *) line_note, max_uid * sizeof (rtx));
line_note_head = (rtx *) alloca (n_basic_blocks * sizeof (rtx));
bzero ((char *) line_note_head, n_basic_blocks * sizeof (rtx));
}
}
+ free (insn_luid);
+ free (insn_priority);
+ free (insn_tick);
+ free (insn_costs);
+ free (insn_units);
+ free (insn_blockage);
+ free (insn_ref_count);
+
+ if (write_symbols != NO_DEBUG)
+ free (line_note);
+
if (reload_completed == 0)
{
FREE_REG_SET (bb_dead_regs);