#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"
#include "target.h"
static int target_n_insns;
static int sched_n_insns;
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 *ebb_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 basic_block schedule_ebb PARAMS ((rtx, rtx));
static basic_block fix_basic_block_boundaries PARAMS ((basic_block, basic_block, rtx, rtx));
static void add_missing_bbs PARAMS ((rtx, basic_block, basic_block));
static int
schedule_more_p ()
{
return sched_n_insns < target_n_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
if (sched_verbose >= 5)
debug_dependencies ();
#endif
for (insn = NEXT_INSN (prev_head); insn != next_tail; insn = NEXT_INSN (insn))
{
if (INSN_DEP_COUNT (insn) == 0)
ready_add (ready, insn);
target_n_insns++;
}
}
static int
can_schedule_ready_p (insn)
rtx insn ATTRIBUTE_UNUSED;
{
sched_n_insns++;
return 1;
}
static int
new_ready (next)
rtx next ATTRIBUTE_UNUSED;
{
return 1;
}
static const char *
ebb_print_insn (insn, aligned)
rtx insn;
int aligned ATTRIBUTE_UNUSED;
{
static char tmp[80];
sprintf (tmp, "%4d", INSN_UID (insn));
return tmp;
}
static int
rank (insn1, insn2)
rtx insn1, insn2;
{
basic_block bb1 = BLOCK_FOR_INSN (insn1);
basic_block bb2 = BLOCK_FOR_INSN (insn2);
if (bb1->count > bb2->count
|| bb1->frequency > bb2->frequency)
return -1;
if (bb1->count < bb2->count
|| bb1->frequency < bb2->frequency)
return 1;
return 0;
}
static int
contributes_to_priority (next, insn)
rtx next ATTRIBUTE_UNUSED, insn ATTRIBUTE_UNUSED;
{
return 1;
}
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);
}
}
static struct sched_info ebb_sched_info =
{
init_ready_list,
can_schedule_ready_p,
schedule_more_p,
new_ready,
rank,
ebb_print_insn,
contributes_to_priority,
compute_jump_reg_dependencies,
NULL, NULL,
NULL, NULL,
0, 1
};
static void
add_missing_bbs (before, first, last)
rtx before;
basic_block first, last;
{
for (; last != first->prev_bb; last = last->prev_bb)
{
before = emit_note_before (NOTE_INSN_BASIC_BLOCK, before);
NOTE_BASIC_BLOCK (before) = last;
last->head = before;
last->end = before;
update_bb_for_insn (last);
}
}
static basic_block
fix_basic_block_boundaries (bb, last, head, tail)
basic_block bb, last;
rtx head, tail;
{
rtx insn = head;
rtx last_inside = bb->head;
rtx aftertail = NEXT_INSN (tail);
head = bb->head;
for (; insn != aftertail; insn = NEXT_INSN (insn))
{
if (GET_CODE (insn) == CODE_LABEL)
abort ();
if (inside_basic_block_p (insn))
{
if (!last_inside)
{
rtx note;
if (GET_CODE (insn) == CODE_LABEL)
{
note = emit_note_after (NOTE_INSN_BASIC_BLOCK, insn);
head = insn;
last_inside = note;
}
else
{
note = emit_note_before (NOTE_INSN_BASIC_BLOCK, insn);
head = note;
last_inside = insn;
}
}
else
last_inside = insn;
}
if (control_flow_insn_p (insn) || (insn == tail && last_inside))
{
basic_block curr_bb = BLOCK_FOR_INSN (insn);
rtx note;
if (!control_flow_insn_p (insn))
curr_bb = last;
if (bb == last->next_bb)
{
edge f;
rtx h;
f = bb->prev_bb->succ;
while (f && !(f->flags & EDGE_FALLTHRU))
f = f->succ_next;
if (f)
{
last = curr_bb = split_edge (f);
h = curr_bb->head;
curr_bb->head = head;
curr_bb->end = insn;
delete_insn (h);
}
else
{
rtx next = next_nonnote_insn (insn);
delete_insn_chain (head, insn);
if (GET_CODE (next) == BARRIER)
{
emit_barrier_after (prev_nonnote_insn (head));
delete_insn (next);
}
insn = NULL;
}
}
else
{
curr_bb->head = head;
curr_bb->end = insn;
add_missing_bbs (curr_bb->head, bb, curr_bb->prev_bb);
}
note = GET_CODE (head) == CODE_LABEL ? NEXT_INSN (head) : head;
NOTE_BASIC_BLOCK (note) = curr_bb;
update_bb_for_insn (curr_bb);
bb = curr_bb->next_bb;
last_inside = NULL;
if (!insn)
break;
}
}
add_missing_bbs (last->next_bb->head, bb, last);
return bb->prev_bb;
}
static basic_block
schedule_ebb (head, tail)
rtx head, tail;
{
int n_insns;
basic_block b;
struct deps tmp_deps;
basic_block first_bb = BLOCK_FOR_INSN (head);
basic_block last_bb = BLOCK_FOR_INSN (tail);
if (no_real_insns_p (head, tail))
return BLOCK_FOR_INSN (tail);
init_deps_global ();
init_deps (&tmp_deps);
sched_analyze (&tmp_deps, head, tail);
free_deps (&tmp_deps);
compute_forward_dependences (head, tail);
if (targetm.sched.dependencies_evaluation_hook)
targetm.sched.dependencies_evaluation_hook (head, tail);
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);
}
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);
}
}
rm_other_notes (head, tail);
current_sched_info->queue_must_finish_empty = 1;
schedule_block (-1, n_insns);
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);
b = fix_basic_block_boundaries (first_bb, last_bb, head, tail);
finish_deps_global ();
return b;
}
void
schedule_ebbs (dump_file)
FILE *dump_file;
{
basic_block bb;
if (n_basic_blocks == 0)
return;
sched_init (dump_file);
current_sched_info = &ebb_sched_info;
allocate_reg_life_data ();
compute_bb_for_insn ();
FOR_EACH_BB (bb)
{
rtx head = bb->head;
rtx tail;
for (;;)
{
edge e;
tail = bb->end;
if (bb->next_bb == EXIT_BLOCK_PTR
|| GET_CODE (bb->next_bb->head) == CODE_LABEL)
break;
for (e = bb->succ; e; e = e->succ_next)
if ((e->flags & EDGE_FALLTHRU) != 0)
break;
if (! e)
break;
if (e->probability < REG_BR_PROB_BASE / 2)
break;
bb = bb->next_bb;
}
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;
}
bb = schedule_ebb (head, tail);
}
if (reload_completed)
reposition_prologue_and_epilogue_notes (get_insns ());
if (write_symbols != NO_DEBUG)
rm_redundant_line_notes ();
sched_finish ();
}