Commit 18e720b3 by Bernd Schmidt Committed by Bernd Schmidt

Support scheduling across extended basic blocks

From-SVN: r38400
parent fd7bcd6f
2000-12-20 Bernd Schmidt <bernds@redhat.com> 2000-12-20 Bernd Schmidt <bernds@redhat.com>
* Makefile.in (OBJS): Add sched-ebb.o.
(sched-ebb.o): New rule.
(sched-vis.o): Depend on hard-reg-set.h and $(BASIC_BLOCK_H).
(haifa-sched.o): Depend on insn-flags.h.
* haifa-sched.c: Include "insn-flags.h".
(priority): Don't access BLOCK_NUM, use the new contributes_to_priority
callback.
* rtl.h (schedule_ebbs): Declare.
* sched-int.h (struct sched_info): Add new members
contributes_to_priority and compute_jump_reg_dependencies.
* sched-rgn.c (contributes_to_priority, compute_jump_reg_dependencies):
New functions.
(region_sched_info): Add them.
* sched-vis.c: Include "hard-reg-set.h" and "basic-block.h".
* sched-ebb.c: New file.
* sched-deps.c (sched_analyze_insn): Add code to handle JUMP_INSNs.
* flow.c (ior_reg_cond, and_reg_cond, elim_reg_cond): Properly * flow.c (ior_reg_cond, and_reg_cond, elim_reg_cond): Properly
handle all relational operators. handle all relational operators.
......
...@@ -738,7 +738,7 @@ OBJS = diagnostic.o version.o tree.o print-tree.o stor-layout.o fold-const.o \ ...@@ -738,7 +738,7 @@ OBJS = diagnostic.o version.o tree.o print-tree.o stor-layout.o fold-const.o \
mbchar.o splay-tree.o graph.o sbitmap.o resource.o hash.o predict.o \ mbchar.o splay-tree.o graph.o sbitmap.o resource.o hash.o predict.o \
lists.o ggc-common.o $(GGC) stringpool.o simplify-rtx.o ssa.o bb-reorder.o \ lists.o ggc-common.o $(GGC) stringpool.o simplify-rtx.o ssa.o bb-reorder.o \
sibcall.o conflict.o timevar.o ifcvt.o dominance.o dependence.o dce.o \ sibcall.o conflict.o timevar.o ifcvt.o dominance.o dependence.o dce.o \
sched-vis.o sched-deps.o sched-rgn.o hashtab.o sched-vis.o sched-deps.o sched-rgn.o sched-ebb.o hashtab.o
BACKEND = toplev.o libbackend.a BACKEND = toplev.o libbackend.a
...@@ -1457,15 +1457,18 @@ regmove.o : regmove.c $(CONFIG_H) system.h $(RTL_H) insn-config.h \ ...@@ -1457,15 +1457,18 @@ regmove.o : regmove.c $(CONFIG_H) system.h $(RTL_H) insn-config.h \
$(EXPR_H) insn-flags.h $(BASIC_BLOCK_H) toplev.h $(EXPR_H) insn-flags.h $(BASIC_BLOCK_H) toplev.h
haifa-sched.o : haifa-sched.c $(CONFIG_H) system.h $(RTL_H) sched-int.h \ haifa-sched.o : haifa-sched.c $(CONFIG_H) system.h $(RTL_H) sched-int.h \
$(BASIC_BLOCK_H) $(REGS_H) hard-reg-set.h flags.h insn-config.h function.h \ $(BASIC_BLOCK_H) $(REGS_H) hard-reg-set.h flags.h insn-config.h function.h \
$(INSN_ATTR_H) toplev.h $(RECOG_H) except.h $(INSN_ATTR_H) insn-flags.h toplev.h $(RECOG_H) except.h
sched-deps.o : haifa-sched.c $(CONFIG_H) system.h $(RTL_H) sched-int.h \ sched-deps.o : haifa-sched.c $(CONFIG_H) system.h $(RTL_H) sched-int.h \
$(BASIC_BLOCK_H) $(REGS_H) hard-reg-set.h flags.h insn-config.h function.h \ $(BASIC_BLOCK_H) $(REGS_H) hard-reg-set.h flags.h insn-config.h function.h \
$(INSN_ATTR_H) toplev.h $(RECOG_H) except.h $(INSN_ATTR_H) toplev.h $(RECOG_H) except.h
sched-rgn.o : haifa-sched.c $(CONFIG_H) system.h $(RTL_H) sched-int.h \ sched-rgn.o : haifa-sched.c $(CONFIG_H) system.h $(RTL_H) sched-int.h \
$(BASIC_BLOCK_H) $(REGS_H) hard-reg-set.h flags.h insn-config.h function.h \ $(BASIC_BLOCK_H) $(REGS_H) hard-reg-set.h flags.h insn-config.h function.h \
$(INSN_ATTR_H) toplev.h $(RECOG_H) except.h $(INSN_ATTR_H) toplev.h $(RECOG_H) except.h
sched-ebb.o : sched-ebb.c $(CONFIG_H) system.h $(RTL_H) sched-int.h \
$(BASIC_BLOCK_H) $(REGS_H) hard-reg-set.h flags.h insn-config.h function.h \
$(INSN_ATTR_H) toplev.h $(RECOG_H) except.h
sched-vis.o : sched-vis.c $(CONFIG_H) system.h $(RTL_H) sched-int.h \ sched-vis.o : sched-vis.c $(CONFIG_H) system.h $(RTL_H) sched-int.h \
$(INSN_ATTR_H) $(REGS_H) hard-reg-set.h $(BASIC_BLOCK_H) $(INSN_ATTR_H) $(REGS_H)
final.o : final.c $(CONFIG_H) system.h $(RTL_H) $(TREE_H) flags.h intl.h \ final.o : final.c $(CONFIG_H) system.h $(RTL_H) $(TREE_H) flags.h intl.h \
$(REGS_H) $(RECOG_H) conditions.h insn-config.h $(INSN_ATTR_H) function.h \ $(REGS_H) $(RECOG_H) conditions.h insn-config.h $(INSN_ATTR_H) function.h \
real.h output.h hard-reg-set.h insn-flags.h insn-codes.h gstab.h except.h \ real.h output.h hard-reg-set.h insn-flags.h insn-codes.h gstab.h except.h \
......
...@@ -144,6 +144,7 @@ the Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA ...@@ -144,6 +144,7 @@ the Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
#include "flags.h" #include "flags.h"
#include "insn-config.h" #include "insn-config.h"
#include "insn-attr.h" #include "insn-attr.h"
#include "insn-flags.h"
#include "except.h" #include "except.h"
#include "toplev.h" #include "toplev.h"
#include "recog.h" #include "recog.h"
...@@ -740,7 +741,7 @@ priority (insn) ...@@ -740,7 +741,7 @@ priority (insn)
next = XEXP (link, 0); next = XEXP (link, 0);
/* Critical path is meaningful in block boundaries only. */ /* Critical path is meaningful in block boundaries only. */
if (BLOCK_NUM (next) != BLOCK_NUM (insn)) if (! (*current_sched_info->contributes_to_priority) (next, insn))
continue; continue;
next_priority = insn_cost (insn, link, next) + priority (next); next_priority = insn_cost (insn, link, next) + priority (next);
......
...@@ -1754,6 +1754,7 @@ extern void dump_combine_total_stats PARAMS ((FILE *)); ...@@ -1754,6 +1754,7 @@ extern void dump_combine_total_stats PARAMS ((FILE *));
/* In sched.c. */ /* In sched.c. */
#ifdef BUFSIZ #ifdef BUFSIZ
extern void schedule_insns PARAMS ((FILE *)); extern void schedule_insns PARAMS ((FILE *));
extern void schedule_ebbs PARAMS ((FILE *));
#endif #endif
extern void fix_sched_param PARAMS ((const char *, const char *)); extern void fix_sched_param PARAMS ((const char *, const char *));
......
...@@ -913,6 +913,53 @@ sched_analyze_insn (deps, x, insn, loop_notes) ...@@ -913,6 +913,53 @@ sched_analyze_insn (deps, x, insn, loop_notes)
sched_analyze_2 (deps, XEXP (link, 0), insn); sched_analyze_2 (deps, XEXP (link, 0), insn);
} }
if (GET_CODE (insn) == JUMP_INSN)
{
rtx next, u, pending, pending_mem;
next = next_nonnote_insn (insn);
if (next && GET_CODE (next) == BARRIER)
{
for (i = 0; i < maxreg; i++)
{
for (u = deps->reg_last_sets[i]; u; u = XEXP (u, 1))
add_dependence (insn, XEXP (u, 0), REG_DEP_ANTI);
for (u = deps->reg_last_clobbers[i]; u; u = XEXP (u, 1))
add_dependence (insn, XEXP (u, 0), REG_DEP_ANTI);
for (u = deps->reg_last_uses[i]; u; u = XEXP (u, 1))
add_dependence (insn, XEXP (u, 0), REG_DEP_ANTI);
}
}
else
{
regset_head tmp;
INIT_REG_SET (&tmp);
(*current_sched_info->compute_jump_reg_dependencies) (insn, &tmp);
EXECUTE_IF_SET_IN_REG_SET
(&tmp, 0, i,
{
for (u = deps->reg_last_sets[i]; u; u = XEXP (u, 1))
add_dependence (insn, XEXP (u, 0), REG_DEP_ANTI);
deps->reg_last_uses[i]
= alloc_INSN_LIST (insn, deps->reg_last_uses[i]);
});
CLEAR_REG_SET (&tmp);
}
pending = deps->pending_write_insns;
pending_mem = deps->pending_write_mems;
while (pending)
{
add_dependence (insn, XEXP (pending, 0), 0);
pending = XEXP (pending, 1);
pending_mem = XEXP (pending_mem, 1);
}
for (u = deps->last_pending_memory_flush; u; u = XEXP (u, 1))
add_dependence (insn, XEXP (u, 0), REG_DEP_ANTI);
}
/* If there is a {LOOP,EHREGION}_{BEG,END} note in the middle of a basic /* If there is a {LOOP,EHREGION}_{BEG,END} note in the middle of a basic
block, then we must be sure that no instructions are scheduled across it. block, then we must be sure that no instructions are scheduled across it.
Otherwise, the reg_n_refs info (which depends on loop_depth) would Otherwise, the reg_n_refs info (which depends on loop_depth) would
......
/* Instruction scheduling pass.
Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998,
1999, 2000 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 GNU CC.
GNU CC 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.
GNU CC 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 GNU CC; see the file COPYING. If not, write to the Free
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 "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
};
/* 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.
FIXME: Probably the same thing should be done with REG_SAVE_NOTEs
referencing NOTE_INSN_SETJMP at the end of the block. */
if (INSN_P (head))
{
rtx note;
for (note = REG_NOTES (head); note; note = XEXP (note, 1))
if (REG_NOTE_KIND (note) == REG_SAVE_NOTE)
{
if (INTVAL (XEXP (note, 0)) != NOTE_INSN_SETJMP)
{
remove_note (head, note);
note = XEXP (note, 1);
remove_note (head, note);
}
else
note = XEXP (note, 1);
}
}
/* 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 (0, 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;
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 ();
sched_finish ();
}
...@@ -115,6 +115,13 @@ struct sched_info ...@@ -115,6 +115,13 @@ struct sched_info
static buffer for this. The ALIGNED parameter should cause the string static buffer for this. The ALIGNED parameter should cause the string
to be formatted so that multiple output lines will line up nicely. */ to be formatted so that multiple output lines will line up nicely. */
const char *(*print_insn) PARAMS ((rtx, int)); const char *(*print_insn) PARAMS ((rtx, int));
/* Return nonzero if an insn should be included in priority
calculations. */
int (*contributes_to_priority) PARAMS ((rtx, rtx));
/* Called when computing dependencies for a JUMP_INSN. This function
should store the set of registers that must be considered as set by
the jump in the regset. */
void (*compute_jump_reg_dependencies) PARAMS ((rtx, regset));
/* The boundaries of the set of insns to be scheduled. */ /* The boundaries of the set of insns to be scheduled. */
rtx prev_head, next_tail; rtx prev_head, next_tail;
......
...@@ -2042,6 +2042,8 @@ static int new_ready PARAMS ((rtx)); ...@@ -2042,6 +2042,8 @@ static int new_ready PARAMS ((rtx));
static int schedule_more_p PARAMS ((void)); static int schedule_more_p PARAMS ((void));
static const char *rgn_print_insn PARAMS ((rtx, int)); static const char *rgn_print_insn PARAMS ((rtx, int));
static int rgn_rank PARAMS ((rtx, rtx)); static int rgn_rank PARAMS ((rtx, rtx));
static int contributes_to_priority PARAMS ((rtx, rtx));
static void compute_jump_reg_dependencies PARAMS ((rtx, regset));
/* Return nonzero if there are more insns that should be scheduled. */ /* Return nonzero if there are more insns that should be scheduled. */
...@@ -2302,6 +2304,29 @@ rgn_rank (insn1, insn2) ...@@ -2302,6 +2304,29 @@ rgn_rank (insn1, insn2)
return 0; 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, insn;
{
return BLOCK_NUM (next) == BLOCK_NUM (insn);
}
/* 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 ATTRIBUTE_UNUSED;
regset set ATTRIBUTE_UNUSED;
{
/* Nothing to do here, since we postprocess jumps in
add_branch_dependences. */
}
/* Used in schedule_insns to initialize current_sched_info for scheduling /* Used in schedule_insns to initialize current_sched_info for scheduling
regions (or single basic blocks). */ regions (or single basic blocks). */
...@@ -2313,6 +2338,8 @@ static struct sched_info region_sched_info = ...@@ -2313,6 +2338,8 @@ static struct sched_info region_sched_info =
new_ready, new_ready,
rgn_rank, rgn_rank,
rgn_print_insn, rgn_print_insn,
contributes_to_priority,
compute_jump_reg_dependencies,
NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL,
......
...@@ -27,6 +27,8 @@ the Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA ...@@ -27,6 +27,8 @@ the Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
#include "rtl.h" #include "rtl.h"
#include "tm_p.h" #include "tm_p.h"
#include "regs.h" #include "regs.h"
#include "hard-reg-set.h"
#include "basic-block.h"
#include "insn-attr.h" #include "insn-attr.h"
#include "sched-int.h" #include "sched-int.h"
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment