summaryrefslogtreecommitdiffstats
path: root/contrib/gcc/sched-ebb.c
diff options
context:
space:
mode:
authorobrien <obrien@FreeBSD.org>2002-02-01 18:16:02 +0000
committerobrien <obrien@FreeBSD.org>2002-02-01 18:16:02 +0000
commitc9ab9ae440a8066b2c2b85b157b1fdadcf09916a (patch)
tree086d9d6c8fbd4fc8fe4495059332f66bc0f8d12b /contrib/gcc/sched-ebb.c
parent2ecfd8bd04b63f335c1ec6295740a4bfd97a4fa6 (diff)
downloadFreeBSD-src-c9ab9ae440a8066b2c2b85b157b1fdadcf09916a.zip
FreeBSD-src-c9ab9ae440a8066b2c2b85b157b1fdadcf09916a.tar.gz
Enlist the FreeBSD-CURRENT users as testers of what is to become Gcc 3.1.0.
These bits are taken from the FSF anoncvs repo on 1-Feb-2002 08:20 PST.
Diffstat (limited to 'contrib/gcc/sched-ebb.c')
-rw-r--r--contrib/gcc/sched-ebb.c362
1 files changed, 362 insertions, 0 deletions
diff --git a/contrib/gcc/sched-ebb.c b/contrib/gcc/sched-ebb.c
new file mode 100644
index 0000000..31b5f3c
--- /dev/null
+++ b/contrib/gcc/sched-ebb.c
@@ -0,0 +1,362 @@
+/* Instruction scheduling pass.
+ Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998,
+ 1999, 2000, 2001 Free Software Foundation, Inc.
+ Contributed by Michael Tiemann (tiemann@cygnus.com) Enhanced by,
+ and currently maintained by, Jim Wilson (wilson@cygnus.com)
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 2, or (at your option) any later
+version.
+
+GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING. If not, write to the Free
+Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+02111-1307, USA. */
+
+#include "config.h"
+#include "system.h"
+#include "toplev.h"
+#include "rtl.h"
+#include "tm_p.h"
+#include "hard-reg-set.h"
+#include "basic-block.h"
+#include "regs.h"
+#include "function.h"
+#include "flags.h"
+#include "insn-config.h"
+#include "insn-attr.h"
+#include "except.h"
+#include "toplev.h"
+#include "recog.h"
+#include "cfglayout.h"
+#include "sched-int.h"
+
+/* The number of insns to be scheduled in total. */
+static int target_n_insns;
+/* The number of insns scheduled so far. */
+static int sched_n_insns;
+
+/* Implementations of the sched_info functions for region scheduling. */
+static void init_ready_list PARAMS ((struct ready_list *));
+static int can_schedule_ready_p PARAMS ((rtx));
+static int new_ready PARAMS ((rtx));
+static int schedule_more_p PARAMS ((void));
+static const char *print_insn PARAMS ((rtx, int));
+static int rank PARAMS ((rtx, rtx));
+static int contributes_to_priority PARAMS ((rtx, rtx));
+static void compute_jump_reg_dependencies PARAMS ((rtx, regset));
+static void schedule_ebb PARAMS ((rtx, rtx));
+
+/* Return nonzero if there are more insns that should be scheduled. */
+
+static int
+schedule_more_p ()
+{
+ return sched_n_insns < target_n_insns;
+}
+
+/* Add all insns that are initially ready to the ready list READY. Called
+ once before scheduling a set of insns. */
+
+static void
+init_ready_list (ready)
+ struct ready_list *ready;
+{
+ rtx prev_head = current_sched_info->prev_head;
+ rtx next_tail = current_sched_info->next_tail;
+ rtx insn;
+
+ target_n_insns = 0;
+ sched_n_insns = 0;
+
+#if 0
+ /* Print debugging information. */
+ if (sched_verbose >= 5)
+ debug_dependencies ();
+#endif
+
+ /* Initialize ready list with all 'ready' insns in target block.
+ Count number of insns in the target block being scheduled. */
+ for (insn = NEXT_INSN (prev_head); insn != next_tail; insn = NEXT_INSN (insn))
+ {
+ rtx next;
+
+ if (! INSN_P (insn))
+ continue;
+ next = NEXT_INSN (insn);
+
+ if (INSN_DEP_COUNT (insn) == 0
+ && (SCHED_GROUP_P (next) == 0 || ! INSN_P (next)))
+ ready_add (ready, insn);
+ if (!(SCHED_GROUP_P (insn)))
+ target_n_insns++;
+ }
+}
+
+/* Called after taking INSN from the ready list. Returns nonzero if this
+ insn can be scheduled, nonzero if we should silently discard it. */
+
+static int
+can_schedule_ready_p (insn)
+ rtx insn ATTRIBUTE_UNUSED;
+{
+ sched_n_insns++;
+ return 1;
+}
+
+/* Called after INSN has all its dependencies resolved. Return nonzero
+ if it should be moved to the ready list or the queue, or zero if we
+ should silently discard it. */
+static int
+new_ready (next)
+ rtx next ATTRIBUTE_UNUSED;
+{
+ return 1;
+}
+
+/* Return a string that contains the insn uid and optionally anything else
+ necessary to identify this insn in an output. It's valid to use a
+ static buffer for this. The ALIGNED parameter should cause the string
+ to be formatted so that multiple output lines will line up nicely. */
+
+static const char *
+print_insn (insn, aligned)
+ rtx insn;
+ int aligned ATTRIBUTE_UNUSED;
+{
+ static char tmp[80];
+
+ sprintf (tmp, "%4d", INSN_UID (insn));
+ return tmp;
+}
+
+/* Compare priority of two insns. Return a positive number if the second
+ insn is to be preferred for scheduling, and a negative one if the first
+ is to be preferred. Zero if they are equally good. */
+
+static int
+rank (insn1, insn2)
+ rtx insn1 ATTRIBUTE_UNUSED, insn2 ATTRIBUTE_UNUSED;
+{
+ return 0;
+}
+
+/* NEXT is an instruction that depends on INSN (a backward dependence);
+ return nonzero if we should include this dependence in priority
+ calculations. */
+
+static int
+contributes_to_priority (next, insn)
+ rtx next ATTRIBUTE_UNUSED, insn ATTRIBUTE_UNUSED;
+{
+ return 1;
+}
+
+/* INSN is a JUMP_INSN. Store the set of registers that must be considered
+ to be set by this jump in SET. */
+
+static void
+compute_jump_reg_dependencies (insn, set)
+ rtx insn;
+ regset set;
+{
+ basic_block b = BLOCK_FOR_INSN (insn);
+ edge e;
+ for (e = b->succ; e; e = e->succ_next)
+ if ((e->flags & EDGE_FALLTHRU) == 0)
+ {
+ bitmap_operation (set, set, e->dest->global_live_at_start,
+ BITMAP_IOR);
+ }
+}
+
+/* Used in schedule_insns to initialize current_sched_info for scheduling
+ regions (or single basic blocks). */
+
+static struct sched_info ebb_sched_info =
+{
+ init_ready_list,
+ can_schedule_ready_p,
+ schedule_more_p,
+ new_ready,
+ rank,
+ print_insn,
+ contributes_to_priority,
+ compute_jump_reg_dependencies,
+
+ NULL, NULL,
+ NULL, NULL,
+ 0, 1
+};
+
+/* Schedule a single extended basic block, defined by the boundaries HEAD
+ and TAIL. */
+
+static void
+schedule_ebb (head, tail)
+ rtx head, tail;
+{
+ int n_insns;
+ struct deps tmp_deps;
+
+ if (no_real_insns_p (head, tail))
+ return;
+
+ init_deps_global ();
+
+ /* Compute LOG_LINKS. */
+ init_deps (&tmp_deps);
+ sched_analyze (&tmp_deps, head, tail);
+ free_deps (&tmp_deps);
+
+ /* Compute INSN_DEPEND. */
+ compute_forward_dependences (head, tail);
+
+ /* Set priorities. */
+ n_insns = set_priorities (head, tail);
+
+ current_sched_info->prev_head = PREV_INSN (head);
+ current_sched_info->next_tail = NEXT_INSN (tail);
+
+ if (write_symbols != NO_DEBUG)
+ {
+ save_line_notes (0, head, tail);
+ rm_line_notes (head, tail);
+ }
+
+ /* rm_other_notes only removes notes which are _inside_ the
+ block---that is, it won't remove notes before the first real insn
+ or after the last real insn of the block. So if the first insn
+ has a REG_SAVE_NOTE which would otherwise be emitted before the
+ insn, it is redundant with the note before the start of the
+ block, and so we have to take it out. */
+ if (INSN_P (head))
+ {
+ rtx note;
+
+ for (note = REG_NOTES (head); note; note = XEXP (note, 1))
+ if (REG_NOTE_KIND (note) == REG_SAVE_NOTE)
+ {
+ remove_note (head, note);
+ note = XEXP (note, 1);
+ remove_note (head, note);
+ }
+ }
+
+ /* Remove remaining note insns from the block, save them in
+ note_list. These notes are restored at the end of
+ schedule_block (). */
+ rm_other_notes (head, tail);
+
+ current_sched_info->queue_must_finish_empty = 1;
+
+ schedule_block (-1, n_insns);
+
+ /* Sanity check: verify that all region insns were scheduled. */
+ if (sched_n_insns != n_insns)
+ abort ();
+ head = current_sched_info->head;
+ tail = current_sched_info->tail;
+
+ if (write_symbols != NO_DEBUG)
+ restore_line_notes (head, tail);
+
+ finish_deps_global ();
+}
+
+/* The one entry point in this file. DUMP_FILE is the dump file for
+ this pass. */
+
+void
+schedule_ebbs (dump_file)
+ FILE *dump_file;
+{
+ int i;
+
+ /* Taking care of this degenerate case makes the rest of
+ this code simpler. */
+ if (n_basic_blocks == 0)
+ return;
+
+ scope_to_insns_initialize ();
+
+ sched_init (dump_file);
+
+ current_sched_info = &ebb_sched_info;
+
+ allocate_reg_life_data ();
+ compute_bb_for_insn (get_max_uid ());
+
+ /* Schedule every region in the subroutine. */
+ for (i = 0; i < n_basic_blocks; i++)
+ {
+ rtx head = BASIC_BLOCK (i)->head;
+ rtx tail;
+
+ for (;;)
+ {
+ basic_block b = BASIC_BLOCK (i);
+ edge e;
+ tail = b->end;
+ if (i + 1 == n_basic_blocks
+ || GET_CODE (BLOCK_HEAD (i + 1)) == CODE_LABEL)
+ break;
+ for (e = b->succ; e; e = e->succ_next)
+ if ((e->flags & EDGE_FALLTHRU) != 0)
+ break;
+ if (! e)
+ break;
+ if (GET_CODE (tail) == JUMP_INSN)
+ {
+ rtx x = find_reg_note (tail, REG_BR_PROB, 0);
+ if (x)
+ {
+ int pred_val = INTVAL (XEXP (x, 0));
+ if (pred_val > REG_BR_PROB_BASE / 2)
+ break;
+ }
+ }
+
+ i++;
+ }
+
+ /* Blah. We should fix the rest of the code not to get confused by
+ a note or two. */
+ while (head != tail)
+ {
+ if (GET_CODE (head) == NOTE)
+ head = NEXT_INSN (head);
+ else if (GET_CODE (tail) == NOTE)
+ tail = PREV_INSN (tail);
+ else if (GET_CODE (head) == CODE_LABEL)
+ head = NEXT_INSN (head);
+ else
+ break;
+ }
+
+ schedule_ebb (head, tail);
+ }
+
+ /* It doesn't make much sense to try and update life information here - we
+ probably messed up even the flow graph. */
+
+ /* Reposition the prologue and epilogue notes in case we moved the
+ prologue/epilogue insns. */
+ if (reload_completed)
+ reposition_prologue_and_epilogue_notes (get_insns ());
+
+ if (write_symbols != NO_DEBUG)
+ rm_redundant_line_notes ();
+
+ scope_to_insns_finalize ();
+
+ sched_finish ();
+}
OpenPOWER on IntegriCloud