#include "config.h"
#include "system.h"
#include "coretypes.h"
#include "tm.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 "params.h"
#include "sched-int.h"
#include "target.h"
#if !defined (HAVE_conditional_execution) && defined (ENABLE_CHECKING)
#define CHECK_DEAD_NOTES 1
#else
#define CHECK_DEAD_NOTES 0
#endif
#ifdef INSN_SCHEDULING
#define INSN_REF_COUNT(INSN) (h_i_d[INSN_UID (INSN)].ref_count)
#define FED_BY_SPEC_LOAD(insn) (h_i_d[INSN_UID (insn)].fed_by_spec_load)
#define IS_LOAD_INSN(insn) (h_i_d[INSN_UID (insn)].is_load_insn)
static int nr_inter, nr_spec;
static int is_cfg_nonregular (void);
static bool sched_is_disabled_for_current_region_p (void);
typedef struct
{
int rgn_nr_blocks;
int rgn_blocks;
}
region;
static int nr_regions;
static region *rgn_table;
static int *rgn_bb_table;
static int *block_to_bb;
static int *containing_rgn;
#define RGN_NR_BLOCKS(rgn) (rgn_table[rgn].rgn_nr_blocks)
#define RGN_BLOCKS(rgn) (rgn_table[rgn].rgn_blocks)
#define BLOCK_TO_BB(block) (block_to_bb[block])
#define CONTAINING_RGN(block) (containing_rgn[block])
void debug_regions (void);
static void find_single_block_region (void);
static void find_rgns (void);
static bool too_large (int, int *, int *);
extern void debug_live (int, int);
static int current_nr_blocks;
static int current_blocks;
#define BB_TO_BLOCK(bb) (rgn_bb_table[current_blocks + (bb)])
typedef struct
{
basic_block *first_member;
int nr_members;
}
bblst;
typedef struct
{
char is_valid;
char is_speculative;
int src_prob;
bblst split_bbs;
bblst update_bbs;
}
candidate;
static candidate *candidate_table;
static basic_block *bblst_table;
static int bblst_size, bblst_last;
#define IS_VALID(src) ( candidate_table[src].is_valid )
#define IS_SPECULATIVE(src) ( candidate_table[src].is_speculative )
#define SRC_PROB(src) ( candidate_table[src].src_prob )
static int target_bb;
typedef struct
{
edge *first_member;
int nr_members;
}
edgelst;
static edge *edgelst_table;
static int edgelst_last;
static void extract_edgelst (sbitmap, edgelst *);
static void split_edges (int, int, edgelst *);
static void compute_trg_info (int);
void debug_candidate (int);
void debug_candidates (int);
static sbitmap *dom;
#define IS_RGN_ENTRY(bb) (!bb)
#define IS_DOMINATED(bb_src, bb_trg) \
( TEST_BIT (dom[bb_src], bb_trg) )
static float *prob;
#define GET_SRC_PROB(bb_src, bb_trg) ((int) (100.0 * (prob[bb_src] / \
prob[bb_trg])))
typedef sbitmap edgeset;
static int rgn_nr_edges;
static edge *rgn_edges;
#define EDGE_TO_BIT(edge) ((int)(size_t)(edge)->aux)
#define SET_EDGE_TO_BIT(edge,nr) ((edge)->aux = (void *)(size_t)(nr))
static edgeset *pot_split;
static edgeset *ancestor_edges;
static void compute_dom_prob_ps (int);
#define INSN_PROBABILITY(INSN) (SRC_PROB (BLOCK_TO_BB (BLOCK_NUM (INSN))))
#define IS_SPECULATIVE_INSN(INSN) (IS_SPECULATIVE (BLOCK_TO_BB (BLOCK_NUM (INSN))))
#define INSN_BB(INSN) (BLOCK_TO_BB (BLOCK_NUM (INSN)))
#define MIN_PROBABILITY 40
static int check_live_1 (int, rtx);
static void update_live_1 (int, rtx);
static int check_live (rtx, int);
static void update_live (rtx, int);
static void set_spec_fed (rtx);
static int is_pfree (rtx, int, int);
static int find_conditional_protection (rtx, int);
static int is_conditionally_protected (rtx, int, int);
static int is_prisky (rtx, int, int);
static int is_exception_free (rtx, int, int);
static bool sets_likely_spilled (rtx);
static void sets_likely_spilled_1 (rtx, rtx, void *);
static void add_branch_dependences (rtx, rtx);
static void compute_block_backward_dependences (int);
void debug_dependencies (void);
static void init_regions (void);
static void schedule_region (int);
static rtx concat_INSN_LIST (rtx, rtx);
static void concat_insn_mem_list (rtx, rtx, rtx *, rtx *);
static void propagate_deps (int, struct deps *);
static void free_pending_lists (void);
static int
is_cfg_nonregular (void)
{
basic_block b;
rtx insn;
RTX_CODE code;
if (nonlocal_goto_handler_labels)
return 1;
if (forced_labels)
return 1;
if (current_function_has_computed_jump)
return 1;
if (current_function_has_exception_handlers ())
return 1;
FOR_EACH_BB (b)
for (insn = BB_HEAD (b); ; insn = NEXT_INSN (insn))
{
code = GET_CODE (insn);
if (INSN_P (insn) && code != JUMP_INSN)
{
rtx note = find_reg_note (insn, REG_LABEL, NULL_RTX);
if (note
&& ! (JUMP_P (NEXT_INSN (insn))
&& find_reg_note (NEXT_INSN (insn), REG_LABEL,
XEXP (note, 0))))
return 1;
}
if (insn == BB_END (b))
break;
}
FOR_EACH_BB (b)
{
if (EDGE_COUNT (b->preds) == 0
|| (EDGE_PRED (b, 0)->src == b
&& EDGE_COUNT (b->preds) == 1))
return 1;
}
return 0;
}
static void
extract_edgelst (sbitmap set, edgelst *el)
{
int i;
edgelst_last = 0;
el->first_member = &edgelst_table[edgelst_last];
el->nr_members = 0;
EXECUTE_IF_SET_IN_SBITMAP (set, 0, i,
{
edgelst_table[edgelst_last++] = rgn_edges[i];
el->nr_members++;
});
}
void
debug_regions (void)
{
int rgn, bb;
fprintf (sched_dump, "\n;; ------------ REGIONS ----------\n\n");
for (rgn = 0; rgn < nr_regions; rgn++)
{
fprintf (sched_dump, ";;\trgn %d nr_blocks %d:\n", rgn,
rgn_table[rgn].rgn_nr_blocks);
fprintf (sched_dump, ";;\tbb/block: ");
for (bb = 0; bb < rgn_table[rgn].rgn_nr_blocks; bb++)
{
current_blocks = RGN_BLOCKS (rgn);
gcc_assert (bb == BLOCK_TO_BB (BB_TO_BLOCK (bb)));
fprintf (sched_dump, " %d/%d ", bb, BB_TO_BLOCK (bb));
}
fprintf (sched_dump, "\n\n");
}
}
static void
find_single_block_region (void)
{
basic_block bb;
nr_regions = 0;
FOR_EACH_BB (bb)
{
rgn_bb_table[nr_regions] = bb->index;
RGN_NR_BLOCKS (nr_regions) = 1;
RGN_BLOCKS (nr_regions) = nr_regions;
CONTAINING_RGN (bb->index) = nr_regions;
BLOCK_TO_BB (bb->index) = 0;
nr_regions++;
}
}
static bool
too_large (int block, int *num_bbs, int *num_insns)
{
(*num_bbs)++;
(*num_insns) += (INSN_LUID (BB_END (BASIC_BLOCK (block)))
- INSN_LUID (BB_HEAD (BASIC_BLOCK (block))));
return ((*num_bbs > PARAM_VALUE (PARAM_MAX_SCHED_REGION_BLOCKS))
|| (*num_insns > PARAM_VALUE (PARAM_MAX_SCHED_REGION_INSNS)));
}
#define UPDATE_LOOP_RELATIONS(blk, hdr) \
{ \
if (max_hdr[blk] == -1) \
max_hdr[blk] = hdr; \
else if (dfs_nr[max_hdr[blk]] > dfs_nr[hdr]) \
RESET_BIT (inner, hdr); \
else if (dfs_nr[max_hdr[blk]] < dfs_nr[hdr]) \
{ \
RESET_BIT (inner,max_hdr[blk]); \
max_hdr[blk] = hdr; \
} \
}
static void
find_rgns (void)
{
int *max_hdr, *dfs_nr, *degree;
char no_loops = 1;
int node, child, loop_head, i, head, tail;
int count = 0, sp, idx = 0;
edge_iterator current_edge;
edge_iterator *stack;
int num_bbs, num_insns, unreachable;
int too_large_failure;
basic_block bb;
sbitmap header;
sbitmap inner;
sbitmap in_queue;
sbitmap in_stack;
max_hdr = xmalloc (last_basic_block * sizeof (int));
dfs_nr = xcalloc (last_basic_block, sizeof (int));
stack = xmalloc (n_edges * sizeof (edge_iterator));
inner = sbitmap_alloc (last_basic_block);
sbitmap_ones (inner);
header = sbitmap_alloc (last_basic_block);
sbitmap_zero (header);
in_queue = sbitmap_alloc (last_basic_block);
sbitmap_zero (in_queue);
in_stack = sbitmap_alloc (last_basic_block);
sbitmap_zero (in_stack);
for (i = 0; i < last_basic_block; i++)
max_hdr[i] = -1;
#define EDGE_PASSED(E) (ei_end_p ((E)) || ei_edge ((E))->aux)
#define SET_EDGE_PASSED(E) (ei_edge ((E))->aux = ei_edge ((E)))
current_edge = ei_start (EDGE_SUCC (ENTRY_BLOCK_PTR, 0)->dest->succs);
sp = -1;
while (1)
{
if (EDGE_PASSED (current_edge))
{
while (sp >= 0 && EDGE_PASSED (current_edge))
{
current_edge = stack[sp--];
node = ei_edge (current_edge)->src->index;
gcc_assert (node != ENTRY_BLOCK);
child = ei_edge (current_edge)->dest->index;
gcc_assert (child != EXIT_BLOCK);
RESET_BIT (in_stack, child);
if (max_hdr[child] >= 0 && TEST_BIT (in_stack, max_hdr[child]))
UPDATE_LOOP_RELATIONS (node, max_hdr[child]);
ei_next (¤t_edge);
}
if (sp < 0 && EDGE_PASSED (current_edge))
break;
continue;
}
node = ei_edge (current_edge)->src->index;
gcc_assert (node != ENTRY_BLOCK);
SET_BIT (in_stack, node);
dfs_nr[node] = ++count;
child = ei_edge (current_edge)->dest->index;
if (child == EXIT_BLOCK)
{
SET_EDGE_PASSED (current_edge);
ei_next (¤t_edge);
continue;
}
if (TEST_BIT (in_stack, child))
{
no_loops = 0;
SET_BIT (header, child);
UPDATE_LOOP_RELATIONS (node, child);
SET_EDGE_PASSED (current_edge);
ei_next (¤t_edge);
continue;
}
if (dfs_nr[child])
{
if (max_hdr[child] >= 0 && TEST_BIT (in_stack, max_hdr[child]))
UPDATE_LOOP_RELATIONS (node, max_hdr[child]);
SET_EDGE_PASSED (current_edge);
ei_next (¤t_edge);
continue;
}
stack[++sp] = current_edge;
SET_EDGE_PASSED (current_edge);
current_edge = ei_start (ei_edge (current_edge)->dest->succs);
}
FOR_ALL_BB (bb)
{
edge_iterator ei;
edge e;
FOR_EACH_EDGE (e, ei, bb->succs)
e->aux = NULL;
}
unreachable = 0;
FOR_EACH_BB (bb)
if (dfs_nr[bb->index] == 0)
{
unreachable = 1;
break;
}
degree = dfs_nr;
FOR_EACH_BB (bb)
degree[bb->index] = EDGE_COUNT (bb->preds);
if (!unreachable)
{
int *queue;
if (no_loops)
SET_BIT (header, 0);
queue = xmalloc (n_basic_blocks * sizeof (int));
FOR_EACH_BB (bb)
{
if (TEST_BIT (header, bb->index) && TEST_BIT (inner, bb->index))
{
edge e;
edge_iterator ei;
basic_block jbb;
FOR_EACH_BB (jbb)
{
if (bb->index == max_hdr[jbb->index] && bb != jbb)
{
if (!dominated_by_p (CDI_DOMINATORS, jbb, bb))
break;
}
}
if (jbb != EXIT_BLOCK_PTR)
continue;
head = tail = -1;
too_large_failure = 0;
loop_head = max_hdr[bb->index];
FOR_EACH_EDGE (e, ei, bb->succs)
if (e->dest != EXIT_BLOCK_PTR)
--degree[e->dest->index];
num_bbs = 1;
num_insns = (INSN_LUID (BB_END (bb))
- INSN_LUID (BB_HEAD (bb)));
if (no_loops)
{
FOR_EACH_BB (jbb)
if (EDGE_COUNT (jbb->succs) == 1
&& EDGE_SUCC (jbb, 0)->dest == EXIT_BLOCK_PTR)
{
queue[++tail] = jbb->index;
SET_BIT (in_queue, jbb->index);
if (too_large (jbb->index, &num_bbs, &num_insns))
{
too_large_failure = 1;
break;
}
}
}
else
{
edge e;
FOR_EACH_EDGE (e, ei, bb->preds)
{
if (e->src == ENTRY_BLOCK_PTR)
continue;
node = e->src->index;
if (max_hdr[node] == loop_head && node != bb->index)
{
queue[++tail] = node;
SET_BIT (in_queue, node);
if (too_large (node, &num_bbs, &num_insns))
{
too_large_failure = 1;
break;
}
}
}
}
while (head < tail && !too_large_failure)
{
edge e;
child = queue[++head];
FOR_EACH_EDGE (e, ei, BASIC_BLOCK (child)->preds)
{
node = e->src->index;
if (e->src == ENTRY_BLOCK_PTR
|| max_hdr[node] != loop_head)
{
tail = -1;
break;
}
else if (!TEST_BIT (in_queue, node) && node != bb->index)
{
queue[++tail] = node;
SET_BIT (in_queue, node);
if (too_large (node, &num_bbs, &num_insns))
{
too_large_failure = 1;
break;
}
}
}
}
if (tail >= 0 && !too_large_failure)
{
degree[bb->index] = -1;
rgn_bb_table[idx] = bb->index;
RGN_NR_BLOCKS (nr_regions) = num_bbs;
RGN_BLOCKS (nr_regions) = idx++;
CONTAINING_RGN (bb->index) = nr_regions;
BLOCK_TO_BB (bb->index) = count = 0;
while (tail >= 0)
{
if (head < 0)
head = tail;
child = queue[head];
if (degree[child] == 0)
{
edge e;
degree[child] = -1;
rgn_bb_table[idx++] = child;
BLOCK_TO_BB (child) = ++count;
CONTAINING_RGN (child) = nr_regions;
queue[head] = queue[tail--];
FOR_EACH_EDGE (e, ei, BASIC_BLOCK (child)->succs)
if (e->dest != EXIT_BLOCK_PTR)
--degree[e->dest->index];
}
else
--head;
}
++nr_regions;
}
}
}
free (queue);
}
FOR_EACH_BB (bb)
if (degree[bb->index] >= 0)
{
rgn_bb_table[idx] = bb->index;
RGN_NR_BLOCKS (nr_regions) = 1;
RGN_BLOCKS (nr_regions) = idx++;
CONTAINING_RGN (bb->index) = nr_regions++;
BLOCK_TO_BB (bb->index) = 0;
}
free (max_hdr);
free (dfs_nr);
free (stack);
sbitmap_free (header);
sbitmap_free (inner);
sbitmap_free (in_queue);
sbitmap_free (in_stack);
}
static void
compute_dom_prob_ps (int bb)
{
int pred_bb;
int nr_out_edges, nr_rgn_out_edges;
edge_iterator in_ei, out_ei;
edge in_edge, out_edge;
prob[bb] = 0.0;
if (IS_RGN_ENTRY (bb))
{
SET_BIT (dom[bb], 0);
prob[bb] = 1.0;
return;
}
sbitmap_ones (dom[bb]);
FOR_EACH_EDGE (in_edge, in_ei, BASIC_BLOCK (BB_TO_BLOCK (bb))->preds)
{
if (in_edge->src == ENTRY_BLOCK_PTR)
continue;
pred_bb = BLOCK_TO_BB (in_edge->src->index);
sbitmap_a_and_b (dom[bb], dom[bb], dom[pred_bb]);
sbitmap_a_or_b (ancestor_edges[bb],
ancestor_edges[bb], ancestor_edges[pred_bb]);
SET_BIT (ancestor_edges[bb], EDGE_TO_BIT (in_edge));
sbitmap_a_or_b (pot_split[bb], pot_split[bb], pot_split[pred_bb]);
nr_out_edges = 0;
nr_rgn_out_edges = 0;
FOR_EACH_EDGE (out_edge, out_ei, in_edge->src->succs)
{
++nr_out_edges;
if (out_edge->dest != EXIT_BLOCK_PTR
&& CONTAINING_RGN (out_edge->dest->index)
!= CONTAINING_RGN (BB_TO_BLOCK (bb)))
++nr_rgn_out_edges;
SET_BIT (pot_split[bb], EDGE_TO_BIT (out_edge));
}
nr_out_edges -= nr_rgn_out_edges;
if (nr_rgn_out_edges > 0)
prob[bb] += 0.9 * prob[pred_bb] / nr_out_edges;
else
prob[bb] += prob[pred_bb] / nr_out_edges;
}
SET_BIT (dom[bb], bb);
sbitmap_difference (pot_split[bb], pot_split[bb], ancestor_edges[bb]);
if (sched_verbose >= 2)
fprintf (sched_dump, ";; bb_prob(%d, %d) = %3d\n", bb, BB_TO_BLOCK (bb),
(int) (100.0 * prob[bb]));
}
static void
split_edges (int bb_src, int bb_trg, edgelst *bl)
{
sbitmap src = sbitmap_alloc (pot_split[bb_src]->n_bits);
sbitmap_copy (src, pot_split[bb_src]);
sbitmap_difference (src, src, pot_split[bb_trg]);
extract_edgelst (src, bl);
sbitmap_free (src);
}
static void
compute_trg_info (int trg)
{
candidate *sp;
edgelst el;
int i, j, k, update_idx;
basic_block block;
edge_iterator ei;
edge e;
el.nr_members = 0;
el.first_member = 0;
sp = candidate_table + trg;
sp->is_valid = 1;
sp->is_speculative = 0;
sp->src_prob = 100;
for (i = trg + 1; i < current_nr_blocks; i++)
{
sp = candidate_table + i;
sp->is_valid = IS_DOMINATED (i, trg);
if (sp->is_valid)
{
sp->src_prob = GET_SRC_PROB (i, trg);
sp->is_valid = (sp->src_prob >= MIN_PROBABILITY);
}
if (sp->is_valid)
{
split_edges (i, trg, &el);
sp->is_speculative = (el.nr_members) ? 1 : 0;
if (sp->is_speculative && !flag_schedule_speculative)
sp->is_valid = 0;
}
if (sp->is_valid)
{
sp->split_bbs.first_member = &bblst_table[bblst_last];
sp->split_bbs.nr_members = el.nr_members;
for (j = 0; j < el.nr_members; bblst_last++, j++)
bblst_table[bblst_last] = el.first_member[j]->dest;
sp->update_bbs.first_member = &bblst_table[bblst_last];
update_idx = 0;
for (j = 0; j < el.nr_members; j++)
{
block = el.first_member[j]->src;
FOR_EACH_EDGE (e, ei, block->succs)
{
if (!(e->dest->flags & BB_VISITED))
{
for (k = 0; k < el.nr_members; k++)
if (e == el.first_member[k])
break;
if (k >= el.nr_members)
{
bblst_table[bblst_last++] = e->dest;
e->dest->flags |= BB_VISITED;
update_idx++;
}
}
}
}
sp->update_bbs.nr_members = update_idx;
FOR_ALL_BB (block)
block->flags &= ~BB_VISITED;
gcc_assert (bblst_last <= bblst_size);
}
else
{
sp->split_bbs.nr_members = sp->update_bbs.nr_members = 0;
sp->is_speculative = 0;
sp->src_prob = 0;
}
}
}
void
debug_candidate (int i)
{
if (!candidate_table[i].is_valid)
return;
if (candidate_table[i].is_speculative)
{
int j;
fprintf (sched_dump, "src b %d bb %d speculative \n", BB_TO_BLOCK (i), i);
fprintf (sched_dump, "split path: ");
for (j = 0; j < candidate_table[i].split_bbs.nr_members; j++)
{
int b = candidate_table[i].split_bbs.first_member[j]->index;
fprintf (sched_dump, " %d ", b);
}
fprintf (sched_dump, "\n");
fprintf (sched_dump, "update path: ");
for (j = 0; j < candidate_table[i].update_bbs.nr_members; j++)
{
int b = candidate_table[i].update_bbs.first_member[j]->index;
fprintf (sched_dump, " %d ", b);
}
fprintf (sched_dump, "\n");
}
else
{
fprintf (sched_dump, " src %d equivalent\n", BB_TO_BLOCK (i));
}
}
void
debug_candidates (int trg)
{
int i;
fprintf (sched_dump, "----------- candidate table: target: b=%d bb=%d ---\n",
BB_TO_BLOCK (trg), trg);
for (i = trg + 1; i < current_nr_blocks; i++)
debug_candidate (i);
}
static int
check_live_1 (int src, rtx x)
{
int i;
int regno;
rtx reg = SET_DEST (x);
if (reg == 0)
return 1;
while (GET_CODE (reg) == SUBREG || GET_CODE (reg) == ZERO_EXTRACT
|| GET_CODE (reg) == SIGN_EXTRACT
|| GET_CODE (reg) == STRICT_LOW_PART)
reg = XEXP (reg, 0);
if (GET_CODE (reg) == PARALLEL)
{
int i;
for (i = XVECLEN (reg, 0) - 1; i >= 0; i--)
if (XEXP (XVECEXP (reg, 0, i), 0) != 0)
if (check_live_1 (src, XEXP (XVECEXP (reg, 0, i), 0)))
return 1;
return 0;
}
if (!REG_P (reg))
return 1;
regno = REGNO (reg);
if (regno < FIRST_PSEUDO_REGISTER && global_regs[regno])
{
return 0;
}
else
{
if (regno < FIRST_PSEUDO_REGISTER)
{
int j = hard_regno_nregs[regno][GET_MODE (reg)];
while (--j >= 0)
{
for (i = 0; i < candidate_table[src].split_bbs.nr_members; i++)
{
basic_block b = candidate_table[src].split_bbs.first_member[i];
if (REGNO_REG_SET_P (b->global_live_at_start, regno + j))
{
return 0;
}
}
}
}
else
{
for (i = 0; i < candidate_table[src].split_bbs.nr_members; i++)
{
basic_block b = candidate_table[src].split_bbs.first_member[i];
if (REGNO_REG_SET_P (b->global_live_at_start, regno))
{
return 0;
}
}
}
}
return 1;
}
static void
update_live_1 (int src, rtx x)
{
int i;
int regno;
rtx reg = SET_DEST (x);
if (reg == 0)
return;
while (GET_CODE (reg) == SUBREG || GET_CODE (reg) == ZERO_EXTRACT
|| GET_CODE (reg) == SIGN_EXTRACT
|| GET_CODE (reg) == STRICT_LOW_PART)
reg = XEXP (reg, 0);
if (GET_CODE (reg) == PARALLEL)
{
int i;
for (i = XVECLEN (reg, 0) - 1; i >= 0; i--)
if (XEXP (XVECEXP (reg, 0, i), 0) != 0)
update_live_1 (src, XEXP (XVECEXP (reg, 0, i), 0));
return;
}
if (!REG_P (reg))
return;
regno = REGNO (reg);
if (regno >= FIRST_PSEUDO_REGISTER || !global_regs[regno])
{
if (regno < FIRST_PSEUDO_REGISTER)
{
int j = hard_regno_nregs[regno][GET_MODE (reg)];
while (--j >= 0)
{
for (i = 0; i < candidate_table[src].update_bbs.nr_members; i++)
{
basic_block b = candidate_table[src].update_bbs.first_member[i];
SET_REGNO_REG_SET (b->global_live_at_start, regno + j);
}
}
}
else
{
for (i = 0; i < candidate_table[src].update_bbs.nr_members; i++)
{
basic_block b = candidate_table[src].update_bbs.first_member[i];
SET_REGNO_REG_SET (b->global_live_at_start, regno);
}
}
}
}
static int
check_live (rtx insn, int src)
{
if (GET_CODE (PATTERN (insn)) == SET
|| GET_CODE (PATTERN (insn)) == CLOBBER)
return check_live_1 (src, PATTERN (insn));
else if (GET_CODE (PATTERN (insn)) == PARALLEL)
{
int j;
for (j = XVECLEN (PATTERN (insn), 0) - 1; j >= 0; j--)
if ((GET_CODE (XVECEXP (PATTERN (insn), 0, j)) == SET
|| GET_CODE (XVECEXP (PATTERN (insn), 0, j)) == CLOBBER)
&& !check_live_1 (src, XVECEXP (PATTERN (insn), 0, j)))
return 0;
return 1;
}
return 1;
}
static void
update_live (rtx insn, int src)
{
if (GET_CODE (PATTERN (insn)) == SET
|| GET_CODE (PATTERN (insn)) == CLOBBER)
update_live_1 (src, PATTERN (insn));
else if (GET_CODE (PATTERN (insn)) == PARALLEL)
{
int j;
for (j = XVECLEN (PATTERN (insn), 0) - 1; j >= 0; j--)
if (GET_CODE (XVECEXP (PATTERN (insn), 0, j)) == SET
|| GET_CODE (XVECEXP (PATTERN (insn), 0, j)) == CLOBBER)
update_live_1 (src, XVECEXP (PATTERN (insn), 0, j));
}
}
#define IS_REACHABLE(bb_from, bb_to) \
(bb_from == bb_to \
|| IS_RGN_ENTRY (bb_from) \
|| (TEST_BIT (ancestor_edges[bb_to], \
EDGE_TO_BIT (EDGE_PRED (BASIC_BLOCK (BB_TO_BLOCK (bb_from)), 0)))))
static void
set_spec_fed (rtx load_insn)
{
rtx link;
for (link = INSN_DEPEND (load_insn); link; link = XEXP (link, 1))
if (GET_MODE (link) == VOIDmode)
FED_BY_SPEC_LOAD (XEXP (link, 0)) = 1;
}
static int
find_conditional_protection (rtx insn, int load_insn_bb)
{
rtx link;
for (link = INSN_DEPEND (insn); link; link = XEXP (link, 1))
{
rtx next = XEXP (link, 0);
if ((CONTAINING_RGN (BLOCK_NUM (next)) ==
CONTAINING_RGN (BB_TO_BLOCK (load_insn_bb)))
&& IS_REACHABLE (INSN_BB (next), load_insn_bb)
&& load_insn_bb != INSN_BB (next)
&& GET_MODE (link) == VOIDmode
&& (JUMP_P (next)
|| find_conditional_protection (next, load_insn_bb)))
return 1;
}
return 0;
}
static int
is_conditionally_protected (rtx load_insn, int bb_src, int bb_trg)
{
rtx link;
for (link = LOG_LINKS (load_insn); link; link = XEXP (link, 1))
{
rtx insn1 = XEXP (link, 0);
if (GET_MODE (link) != VOIDmode
|| JUMP_P (insn1))
continue;
if (INSN_BB (insn1) == bb_src
|| (CONTAINING_RGN (BLOCK_NUM (insn1))
!= CONTAINING_RGN (BB_TO_BLOCK (bb_src)))
|| (!IS_REACHABLE (bb_trg, INSN_BB (insn1))
&& !IS_REACHABLE (INSN_BB (insn1), bb_trg)))
continue;
if (find_conditional_protection (insn1, bb_src))
return 1;
return is_conditionally_protected (insn1, bb_src, bb_trg);
}
return 0;
}
static int
is_pfree (rtx load_insn, int bb_src, int bb_trg)
{
rtx back_link;
candidate *candp = candidate_table + bb_src;
if (candp->split_bbs.nr_members != 1)
return 0;
for (back_link = LOG_LINKS (load_insn);
back_link; back_link = XEXP (back_link, 1))
{
rtx insn1 = XEXP (back_link, 0);
if (GET_MODE (back_link) == VOIDmode)
{
rtx fore_link;
for (fore_link = INSN_DEPEND (insn1);
fore_link; fore_link = XEXP (fore_link, 1))
{
rtx insn2 = XEXP (fore_link, 0);
if (GET_MODE (fore_link) == VOIDmode)
{
if (haifa_classify_insn (insn2) != PFREE_CANDIDATE)
continue;
if (INSN_BB (insn2) == bb_trg)
return 1;
if (*(candp->split_bbs.first_member) == BLOCK_FOR_INSN (insn2))
return 1;
}
}
}
}
return 0;
}
static int
is_prisky (rtx load_insn, int bb_src, int bb_trg)
{
if (FED_BY_SPEC_LOAD (load_insn))
return 1;
if (LOG_LINKS (load_insn) == NULL)
return 1;
if (is_conditionally_protected (load_insn, bb_src, bb_trg))
return 1;
return 0;
}
static int
is_exception_free (rtx insn, int bb_src, int bb_trg)
{
int insn_class = haifa_classify_insn (insn);
switch (insn_class)
{
case TRAP_FREE:
return 1;
case TRAP_RISKY:
return 0;
default:;
}
if (!flag_schedule_speculative_load)
return 0;
IS_LOAD_INSN (insn) = 1;
switch (insn_class)
{
case IFREE:
return (1);
case IRISKY:
return 0;
case PFREE_CANDIDATE:
if (is_pfree (insn, bb_src, bb_trg))
return 1;
case PRISKY_CANDIDATE:
if (!flag_schedule_speculative_load_dangerous
|| is_prisky (insn, bb_src, bb_trg))
return 0;
break;
default:;
}
return flag_schedule_speculative_load_dangerous;
}
static int sched_target_n_insns;
static int target_n_insns;
static int sched_n_insns;
static int last_was_jump;
static void init_ready_list (struct ready_list *);
static int can_schedule_ready_p (rtx);
static int new_ready (rtx);
static int schedule_more_p (void);
static const char *rgn_print_insn (rtx, int);
static int rgn_rank (rtx, rtx);
static int contributes_to_priority (rtx, rtx);
static void compute_jump_reg_dependencies (rtx, regset, regset, regset);
static int
schedule_more_p (void)
{
return ! last_was_jump && sched_target_n_insns < target_n_insns;
}
static void
init_ready_list (struct ready_list *ready)
{
rtx prev_head = current_sched_info->prev_head;
rtx next_tail = current_sched_info->next_tail;
int bb_src;
rtx insn;
target_n_insns = 0;
sched_target_n_insns = 0;
sched_n_insns = 0;
last_was_jump = 0;
if (sched_verbose >= 5)
debug_dependencies ();
if (current_nr_blocks > 1)
{
candidate_table = xmalloc (current_nr_blocks * sizeof (candidate));
bblst_last = 0;
bblst_size = (current_nr_blocks - target_bb) * rgn_nr_edges;
bblst_table = xmalloc (bblst_size * sizeof (basic_block));
edgelst_last = 0;
edgelst_table = xmalloc (rgn_nr_edges * sizeof (edge));
compute_trg_info (target_bb);
}
for (insn = NEXT_INSN (prev_head); insn != next_tail; insn = NEXT_INSN (insn))
{
if (INSN_DEP_COUNT (insn) == 0)
{
ready_add (ready, insn);
if (targetm.sched.adjust_priority)
INSN_PRIORITY (insn) =
targetm.sched.adjust_priority (insn, INSN_PRIORITY (insn));
}
target_n_insns++;
}
for (bb_src = target_bb + 1; bb_src < current_nr_blocks; bb_src++)
if (IS_VALID (bb_src))
{
rtx src_head;
rtx src_next_tail;
rtx tail, head;
get_block_head_tail (BB_TO_BLOCK (bb_src), &head, &tail);
src_next_tail = NEXT_INSN (tail);
src_head = head;
for (insn = src_head; insn != src_next_tail; insn = NEXT_INSN (insn))
{
if (! INSN_P (insn))
continue;
if (!CANT_MOVE (insn)
&& (!IS_SPECULATIVE_INSN (insn)
|| ((recog_memoized (insn) < 0
|| min_insn_conflict_delay (curr_state,
insn, insn) <= 3)
&& check_live (insn, bb_src)
&& is_exception_free (insn, bb_src, target_bb))))
if (INSN_DEP_COUNT (insn) == 0)
{
ready_add (ready, insn);
if (targetm.sched.adjust_priority)
INSN_PRIORITY (insn) =
targetm.sched.adjust_priority (insn, INSN_PRIORITY (insn));
}
}
}
}
static int
can_schedule_ready_p (rtx insn)
{
if (JUMP_P (insn))
last_was_jump = 1;
if (INSN_BB (insn) != target_bb)
{
basic_block b1;
if (IS_SPECULATIVE_INSN (insn))
{
if (!check_live (insn, INSN_BB (insn)))
return 0;
update_live (insn, INSN_BB (insn));
if (IS_LOAD_INSN (insn) || FED_BY_SPEC_LOAD (insn))
set_spec_fed (insn);
nr_spec++;
}
nr_inter++;
b1 = BLOCK_FOR_INSN (insn);
if (insn == BB_HEAD (b1) && insn == BB_END (b1))
{
rtx note = emit_note_after (NOTE_INSN_DELETED, insn);
BB_HEAD (b1) = note;
BB_END (b1) = note;
}
else if (insn == BB_END (b1))
{
BB_END (b1) = PREV_INSN (insn);
}
else if (insn == BB_HEAD (b1))
{
BB_HEAD (b1) = NEXT_INSN (insn);
}
}
else
{
sched_target_n_insns++;
}
sched_n_insns++;
return 1;
}
static int
new_ready (rtx next)
{
if (INSN_BB (next) != target_bb
&& (!IS_VALID (INSN_BB (next))
|| CANT_MOVE (next)
|| (IS_SPECULATIVE_INSN (next)
&& ((recog_memoized (next) >= 0
&& min_insn_conflict_delay (curr_state, next, next) > 3)
|| !check_live (next, INSN_BB (next))
|| !is_exception_free (next, INSN_BB (next), target_bb)))))
return 0;
return 1;
}
static const char *
rgn_print_insn (rtx insn, int aligned)
{
static char tmp[80];
if (aligned)
sprintf (tmp, "b%3d: i%4d", INSN_BB (insn), INSN_UID (insn));
else
{
if (current_nr_blocks > 1 && INSN_BB (insn) != target_bb)
sprintf (tmp, "%d/b%d", INSN_UID (insn), INSN_BB (insn));
else
sprintf (tmp, "%d", INSN_UID (insn));
}
return tmp;
}
static int
rgn_rank (rtx insn1, rtx insn2)
{
if (INSN_BB (insn1) != INSN_BB (insn2))
{
int spec_val, prob_val;
if ((INSN_BB (insn2) == target_bb) && (INSN_BB (insn1) != target_bb))
return 1;
if ((INSN_BB (insn1) == target_bb) && (INSN_BB (insn2) != target_bb))
return -1;
spec_val = IS_SPECULATIVE_INSN (insn1) - IS_SPECULATIVE_INSN (insn2);
if (spec_val)
return spec_val;
prob_val = INSN_PROBABILITY (insn2) - INSN_PROBABILITY (insn1);
if (prob_val)
return prob_val;
}
return 0;
}
static int
contributes_to_priority (rtx next, rtx insn)
{
return BLOCK_NUM (next) == BLOCK_NUM (insn);
}
static void
compute_jump_reg_dependencies (rtx insn ATTRIBUTE_UNUSED,
regset cond_exec ATTRIBUTE_UNUSED,
regset used ATTRIBUTE_UNUSED,
regset set ATTRIBUTE_UNUSED)
{
}
static struct sched_info region_sched_info =
{
init_ready_list,
can_schedule_ready_p,
schedule_more_p,
new_ready,
rgn_rank,
rgn_print_insn,
contributes_to_priority,
compute_jump_reg_dependencies,
NULL, NULL,
NULL, NULL,
0, 0, 0
};
static bool
sets_likely_spilled (rtx pat)
{
bool ret = false;
note_stores (pat, sets_likely_spilled_1, &ret);
return ret;
}
static void
sets_likely_spilled_1 (rtx x, rtx pat, void *data)
{
bool *ret = (bool *) data;
if (GET_CODE (pat) == SET
&& REG_P (x)
&& REGNO (x) < FIRST_PSEUDO_REGISTER
&& CLASS_LIKELY_SPILLED_P (REGNO_REG_CLASS (REGNO (x))))
*ret = true;
}
static void
add_branch_dependences (rtx head, rtx tail)
{
rtx insn, last;
insn = tail;
last = 0;
while (CALL_P (insn)
|| JUMP_P (insn)
|| (NONJUMP_INSN_P (insn)
&& (GET_CODE (PATTERN (insn)) == USE
|| GET_CODE (PATTERN (insn)) == CLOBBER
|| can_throw_internal (insn)
#ifdef HAVE_cc0
|| sets_cc0_p (PATTERN (insn))
#endif
|| (!reload_completed
&& sets_likely_spilled (PATTERN (insn)))))
|| NOTE_P (insn))
{
if (!NOTE_P (insn))
{
if (last != 0 && !find_insn_list (insn, LOG_LINKS (last)))
{
add_dependence (last, insn, REG_DEP_ANTI);
INSN_REF_COUNT (insn)++;
}
CANT_MOVE (insn) = 1;
last = insn;
}
if (insn == head)
break;
insn = PREV_INSN (insn);
}
insn = last;
if (insn != 0)
while (insn != head)
{
insn = prev_nonnote_insn (insn);
if (INSN_REF_COUNT (insn) != 0)
continue;
add_dependence (last, insn, REG_DEP_ANTI);
INSN_REF_COUNT (insn) = 1;
}
}
static struct deps *bb_deps;
static rtx
concat_INSN_LIST (rtx copy, rtx old)
{
rtx new = old;
for (; copy ; copy = XEXP (copy, 1))
new = alloc_INSN_LIST (XEXP (copy, 0), new);
return new;
}
static void
concat_insn_mem_list (rtx copy_insns, rtx copy_mems, rtx *old_insns_p,
rtx *old_mems_p)
{
rtx new_insns = *old_insns_p;
rtx new_mems = *old_mems_p;
while (copy_insns)
{
new_insns = alloc_INSN_LIST (XEXP (copy_insns, 0), new_insns);
new_mems = alloc_EXPR_LIST (VOIDmode, XEXP (copy_mems, 0), new_mems);
copy_insns = XEXP (copy_insns, 1);
copy_mems = XEXP (copy_mems, 1);
}
*old_insns_p = new_insns;
*old_mems_p = new_mems;
}
static void
propagate_deps (int bb, struct deps *pred_deps)
{
basic_block block = BASIC_BLOCK (BB_TO_BLOCK (bb));
edge_iterator ei;
edge e;
FOR_EACH_EDGE (e, ei, block->succs)
{
struct deps *succ_deps;
int reg;
if (e->dest == EXIT_BLOCK_PTR
|| CONTAINING_RGN (block->index) != CONTAINING_RGN (e->dest->index)
|| BLOCK_TO_BB (e->dest->index) <= bb)
continue;
succ_deps = bb_deps + BLOCK_TO_BB (e->dest->index);
EXECUTE_IF_SET_IN_REG_SET (&pred_deps->reg_last_in_use, 0, reg,
{
struct deps_reg *pred_rl = &pred_deps->reg_last[reg];
struct deps_reg *succ_rl = &succ_deps->reg_last[reg];
succ_rl->uses = concat_INSN_LIST (pred_rl->uses, succ_rl->uses);
succ_rl->sets = concat_INSN_LIST (pred_rl->sets, succ_rl->sets);
succ_rl->clobbers = concat_INSN_LIST (pred_rl->clobbers,
succ_rl->clobbers);
succ_rl->uses_length += pred_rl->uses_length;
succ_rl->clobbers_length += pred_rl->clobbers_length;
});
IOR_REG_SET (&succ_deps->reg_last_in_use, &pred_deps->reg_last_in_use);
concat_insn_mem_list (pred_deps->pending_read_insns,
pred_deps->pending_read_mems,
&succ_deps->pending_read_insns,
&succ_deps->pending_read_mems);
concat_insn_mem_list (pred_deps->pending_write_insns,
pred_deps->pending_write_mems,
&succ_deps->pending_write_insns,
&succ_deps->pending_write_mems);
succ_deps->last_pending_memory_flush
= concat_INSN_LIST (pred_deps->last_pending_memory_flush,
succ_deps->last_pending_memory_flush);
succ_deps->pending_lists_length += pred_deps->pending_lists_length;
succ_deps->pending_flush_length += pred_deps->pending_flush_length;
succ_deps->last_function_call
= concat_INSN_LIST (pred_deps->last_function_call,
succ_deps->last_function_call);
succ_deps->sched_before_next_call
= concat_INSN_LIST (pred_deps->sched_before_next_call,
succ_deps->sched_before_next_call);
}
bb_deps[bb].pending_read_insns = pred_deps->pending_read_insns;
bb_deps[bb].pending_read_mems = pred_deps->pending_read_mems;
bb_deps[bb].pending_write_insns = pred_deps->pending_write_insns;
bb_deps[bb].pending_write_mems = pred_deps->pending_write_mems;
pred_deps->pending_read_insns = 0;
pred_deps->pending_read_mems = 0;
pred_deps->pending_write_insns = 0;
pred_deps->pending_write_mems = 0;
}
static void
compute_block_backward_dependences (int bb)
{
rtx head, tail;
struct deps tmp_deps;
tmp_deps = bb_deps[bb];
get_block_head_tail (BB_TO_BLOCK (bb), &head, &tail);
sched_analyze (&tmp_deps, head, tail);
add_branch_dependences (head, tail);
if (current_nr_blocks > 1)
propagate_deps (bb, &tmp_deps);
free_deps (&tmp_deps);
}
static void
free_pending_lists (void)
{
int bb;
for (bb = 0; bb < current_nr_blocks; bb++)
{
free_INSN_LIST_list (&bb_deps[bb].pending_read_insns);
free_INSN_LIST_list (&bb_deps[bb].pending_write_insns);
free_EXPR_LIST_list (&bb_deps[bb].pending_read_mems);
free_EXPR_LIST_list (&bb_deps[bb].pending_write_mems);
}
}
void
debug_dependencies (void)
{
int bb;
fprintf (sched_dump, ";; --------------- forward dependences: ------------ \n");
for (bb = 0; bb < current_nr_blocks; bb++)
{
rtx head, tail;
rtx next_tail;
rtx insn;
get_block_head_tail (BB_TO_BLOCK (bb), &head, &tail);
next_tail = NEXT_INSN (tail);
fprintf (sched_dump, "\n;; --- Region Dependences --- b %d bb %d \n",
BB_TO_BLOCK (bb), bb);
fprintf (sched_dump, ";; %7s%6s%6s%6s%6s%6s%14s\n",
"insn", "code", "bb", "dep", "prio", "cost",
"reservation");
fprintf (sched_dump, ";; %7s%6s%6s%6s%6s%6s%14s\n",
"----", "----", "--", "---", "----", "----",
"-----------");
for (insn = head; insn != next_tail; insn = NEXT_INSN (insn))
{
rtx link;
if (! INSN_P (insn))
{
int n;
fprintf (sched_dump, ";; %6d ", INSN_UID (insn));
if (NOTE_P (insn))
{
n = NOTE_LINE_NUMBER (insn);
if (n < 0)
fprintf (sched_dump, "%s\n", GET_NOTE_INSN_NAME (n));
else
{
expanded_location xloc;
NOTE_EXPANDED_LOCATION (xloc, insn);
fprintf (sched_dump, "line %d, file %s\n",
xloc.line, xloc.file);
}
}
else
fprintf (sched_dump, " {%s}\n", GET_RTX_NAME (GET_CODE (insn)));
continue;
}
fprintf (sched_dump,
";; %s%5d%6d%6d%6d%6d%6d ",
(SCHED_GROUP_P (insn) ? "+" : " "),
INSN_UID (insn),
INSN_CODE (insn),
INSN_BB (insn),
INSN_DEP_COUNT (insn),
INSN_PRIORITY (insn),
insn_cost (insn, 0, 0));
if (recog_memoized (insn) < 0)
fprintf (sched_dump, "nothing");
else
print_reservation (sched_dump, insn);
fprintf (sched_dump, "\t: ");
for (link = INSN_DEPEND (insn); link; link = XEXP (link, 1))
fprintf (sched_dump, "%d ", INSN_UID (XEXP (link, 0)));
fprintf (sched_dump, "\n");
}
}
fprintf (sched_dump, "\n");
}
static bool
sched_is_disabled_for_current_region_p (void)
{
int bb;
for (bb = 0; bb < current_nr_blocks; bb++)
if (!(BASIC_BLOCK (BB_TO_BLOCK (bb))->flags & BB_DISABLE_SCHEDULE))
return false;
return true;
}
static void
schedule_region (int rgn)
{
basic_block block;
edge_iterator ei;
edge e;
int bb;
int rgn_n_insns = 0;
int sched_rgn_n_insns = 0;
current_nr_blocks = RGN_NR_BLOCKS (rgn);
current_blocks = RGN_BLOCKS (rgn);
if (sched_is_disabled_for_current_region_p ())
return;
init_deps_global ();
bb_deps = xmalloc (sizeof (struct deps) * current_nr_blocks);
for (bb = 0; bb < current_nr_blocks; bb++)
init_deps (bb_deps + bb);
for (bb = 0; bb < current_nr_blocks; bb++)
compute_block_backward_dependences (bb);
for (bb = current_nr_blocks - 1; bb >= 0; bb--)
{
rtx head, tail;
get_block_head_tail (BB_TO_BLOCK (bb), &head, &tail);
compute_forward_dependences (head, tail);
if (targetm.sched.dependencies_evaluation_hook)
targetm.sched.dependencies_evaluation_hook (head, tail);
}
for (bb = 0; bb < current_nr_blocks; bb++)
{
rtx head, tail;
get_block_head_tail (BB_TO_BLOCK (bb), &head, &tail);
rgn_n_insns += set_priorities (head, tail);
}
if (current_nr_blocks > 1)
{
prob = xmalloc ((current_nr_blocks) * sizeof (float));
dom = sbitmap_vector_alloc (current_nr_blocks, current_nr_blocks);
sbitmap_vector_zero (dom, current_nr_blocks);
rgn_nr_edges = 0;
FOR_EACH_BB (block)
{
if (CONTAINING_RGN (block->index) != rgn)
continue;
FOR_EACH_EDGE (e, ei, block->succs)
SET_EDGE_TO_BIT (e, rgn_nr_edges++);
}
rgn_edges = xmalloc (rgn_nr_edges * sizeof (edge));
rgn_nr_edges = 0;
FOR_EACH_BB (block)
{
if (CONTAINING_RGN (block->index) != rgn)
continue;
FOR_EACH_EDGE (e, ei, block->succs)
rgn_edges[rgn_nr_edges++] = e;
}
pot_split = sbitmap_vector_alloc (current_nr_blocks, rgn_nr_edges);
sbitmap_vector_zero (pot_split, current_nr_blocks);
ancestor_edges = sbitmap_vector_alloc (current_nr_blocks, rgn_nr_edges);
sbitmap_vector_zero (ancestor_edges, current_nr_blocks);
for (bb = 0; bb < current_nr_blocks; bb++)
compute_dom_prob_ps (bb);
}
for (bb = 0; bb < current_nr_blocks; bb++)
{
rtx head, tail;
int b = BB_TO_BLOCK (bb);
get_block_head_tail (b, &head, &tail);
if (no_real_insns_p (head, tail))
continue;
current_sched_info->prev_head = PREV_INSN (head);
current_sched_info->next_tail = NEXT_INSN (tail);
if (write_symbols != NO_DEBUG)
{
save_line_notes (b, 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);
target_bb = bb;
current_sched_info->queue_must_finish_empty
= current_nr_blocks > 1 && !flag_schedule_interblock;
schedule_block (b, rgn_n_insns);
sched_rgn_n_insns += sched_n_insns;
if (head == BB_HEAD (BASIC_BLOCK (b)))
BB_HEAD (BASIC_BLOCK (b)) = current_sched_info->head;
if (tail == BB_END (BASIC_BLOCK (b)))
BB_END (BASIC_BLOCK (b)) = current_sched_info->tail;
if (current_nr_blocks > 1)
{
free (candidate_table);
free (bblst_table);
free (edgelst_table);
}
}
gcc_assert (sched_rgn_n_insns == rgn_n_insns);
if (write_symbols != NO_DEBUG)
{
for (bb = 0; bb < current_nr_blocks; bb++)
{
rtx head, tail;
get_block_head_tail (BB_TO_BLOCK (bb), &head, &tail);
restore_line_notes (head, tail);
}
}
free_pending_lists ();
finish_deps_global ();
free (bb_deps);
if (current_nr_blocks > 1)
{
FOR_EACH_BB (block)
{
if (CONTAINING_RGN (block->index) != rgn)
continue;
FOR_EACH_EDGE (e, ei, block->succs)
e->aux = NULL;
}
free (prob);
sbitmap_vector_free (dom);
sbitmap_vector_free (pot_split);
sbitmap_vector_free (ancestor_edges);
free (rgn_edges);
}
}
static int *deaths_in_region;
static void
init_regions (void)
{
sbitmap blocks;
int rgn;
nr_regions = 0;
rgn_table = xmalloc ((n_basic_blocks) * sizeof (region));
rgn_bb_table = xmalloc ((n_basic_blocks) * sizeof (int));
block_to_bb = xmalloc ((last_basic_block) * sizeof (int));
containing_rgn = xmalloc ((last_basic_block) * sizeof (int));
if (reload_completed
|| n_basic_blocks == 1
|| !flag_schedule_interblock
|| is_cfg_nonregular ())
{
find_single_block_region ();
}
else
{
calculate_dominance_info (CDI_DOMINATORS);
find_rgns ();
if (sched_verbose >= 3)
debug_regions ();
free_dominance_info (CDI_DOMINATORS);
}
if (CHECK_DEAD_NOTES)
{
blocks = sbitmap_alloc (last_basic_block);
deaths_in_region = xmalloc (sizeof (int) * nr_regions);
for (rgn = 0; rgn < nr_regions; rgn++)
{
int b;
sbitmap_zero (blocks);
for (b = RGN_NR_BLOCKS (rgn) - 1; b >= 0; --b)
SET_BIT (blocks, rgn_bb_table[RGN_BLOCKS (rgn) + b]);
deaths_in_region[rgn] = count_or_remove_death_notes (blocks, 1);
}
sbitmap_free (blocks);
}
else
count_or_remove_death_notes (NULL, 1);
}
void
schedule_insns (FILE *dump_file)
{
sbitmap large_region_blocks, blocks;
int rgn;
int any_large_regions;
basic_block bb;
if (n_basic_blocks == 0)
return;
nr_inter = 0;
nr_spec = 0;
sched_init (dump_file);
init_regions ();
current_sched_info = ®ion_sched_info;
for (rgn = 0; rgn < nr_regions; rgn++)
schedule_region (rgn);
allocate_reg_life_data ();
compute_bb_for_insn ();
any_large_regions = 0;
large_region_blocks = sbitmap_alloc (last_basic_block);
sbitmap_zero (large_region_blocks);
FOR_EACH_BB (bb)
SET_BIT (large_region_blocks, bb->index);
blocks = sbitmap_alloc (last_basic_block);
sbitmap_zero (blocks);
for (rgn = 0; rgn < nr_regions; rgn++)
if (RGN_NR_BLOCKS (rgn) > 1)
any_large_regions = 1;
else
{
SET_BIT (blocks, rgn_bb_table[RGN_BLOCKS (rgn)]);
RESET_BIT (large_region_blocks, rgn_bb_table[RGN_BLOCKS (rgn)]);
}
update_life_info (blocks, UPDATE_LIFE_LOCAL,
(reload_completed ? PROP_DEATH_NOTES
: PROP_DEATH_NOTES | PROP_REG_INFO));
if (any_large_regions)
{
update_life_info (large_region_blocks, UPDATE_LIFE_GLOBAL,
PROP_DEATH_NOTES | PROP_REG_INFO);
}
if (CHECK_DEAD_NOTES)
{
for (rgn = 0; rgn < nr_regions; rgn++)
if (RGN_NR_BLOCKS (rgn) == 1)
{
sbitmap_zero (blocks);
SET_BIT (blocks, rgn_bb_table[RGN_BLOCKS (rgn)]);
gcc_assert (deaths_in_region[rgn]
== count_or_remove_death_notes (blocks, 0));
}
free (deaths_in_region);
}
if (reload_completed)
reposition_prologue_and_epilogue_notes (get_insns ());
if (write_symbols != NO_DEBUG)
rm_redundant_line_notes ();
if (sched_verbose)
{
if (reload_completed == 0 && flag_schedule_interblock)
{
fprintf (sched_dump,
"\n;; Procedure interblock/speculative motions == %d/%d \n",
nr_inter, nr_spec);
}
else
gcc_assert (nr_inter <= 0);
fprintf (sched_dump, "\n\n");
}
free (rgn_table);
free (rgn_bb_table);
free (block_to_bb);
free (containing_rgn);
sched_finish ();
sbitmap_free (blocks);
sbitmap_free (large_region_blocks);
}
#endif