aboutsummaryrefslogtreecommitdiff
path: root/gcc/sched-rgn.c
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/sched-rgn.c')
-rw-r--r--gcc/sched-rgn.c151
1 files changed, 151 insertions, 0 deletions
diff --git a/gcc/sched-rgn.c b/gcc/sched-rgn.c
index fb20721032b..ca1a2668817 100644
--- a/gcc/sched-rgn.c
+++ b/gcc/sched-rgn.c
@@ -142,6 +142,7 @@ static void find_single_block_region (void);
static void find_rgns (void);
static void find_trgns (void);
static void extend_rgns (int *, int *, sbitmap, int *);
+static void extend_trgns_to_sears (void);
static bool too_large (int, int *, int *);
extern void debug_live (int, int);
@@ -1164,6 +1165,149 @@ print_region_statistics (int *s1, int s1_sz, int *s2, int s2_sz)
}
}
+/* Extend treegions to Single-Entry Acyclic Regions (SEARs).
+ Larger regions can be formed by merging two treegions if
+ all incoming predecessor edges into a (child) treegion
+ have src basic blocks that are contained within a single
+ (parent) treegion.
+
+ This new region is referred to as a SEAR and is no longer
+ a treegion because the region now contains merge points
+ (i.e., the child treegions original root block). Tail
+ duplication assumes the use of treegions and must
+ therefore be done prior to calling this function. */
+
+static void
+extend_trgns_to_sears (void)
+{
+ bool merge;
+ int child_rgn, parent_rgn;
+ edge e;
+ edge_iterator ei;
+
+ for (child_rgn = 1; child_rgn < nr_regions; child_rgn++)
+ {
+ merge = true;
+ parent_rgn = -1;
+
+ FOR_EACH_EDGE (e, ei, BASIC_BLOCK (rgn_bb_table[RGN_BLOCKS (child_rgn)])->preds)
+ {
+ /* First parent treegion. Nothing to compare against. */
+ if(parent_rgn == -1)
+ {
+ parent_rgn = CONTAINING_RGN (e->src->index);
+
+ /* Can't merge with yourself. */
+ if (parent_rgn == child_rgn)
+ {
+ merge = false;
+ break;
+ }
+ continue;
+ }
+ /* Check to make sure this isn't a new parent. */
+ else if (parent_rgn != CONTAINING_RGN (e->src->index))
+ {
+ merge = false;
+ break;
+ }
+ }
+
+ /* If the child treegion has one unique parent then merge parent
+ and child treegions to form a SEAR. */
+ if(merge)
+ {
+ int bb, rgn_blocks, num_insns;
+ int parent_nr_blocks, child_nr_blocks;
+
+ parent_nr_blocks = RGN_NR_BLOCKS (parent_rgn);
+ child_nr_blocks = RGN_NR_BLOCKS (child_rgn);
+
+ /* Make sure the SEAR doesn't contain too many blocks. */
+ if ((parent_nr_blocks + child_nr_blocks)
+ > PARAM_VALUE (PARAM_MAX_SCHED_REGION_BLOCKS))
+ continue;
+
+ /* Calculate num_insns between parent and child. */
+ num_insns = 0;
+ rgn_blocks = RGN_BLOCKS (parent_rgn);
+ for (bb = 0; bb < parent_nr_blocks; bb++)
+ num_insns +=
+ (INSN_LUID (BB_END (BASIC_BLOCK (rgn_bb_table[rgn_blocks + bb])))
+ - INSN_LUID (BB_HEAD (BASIC_BLOCK (rgn_bb_table[rgn_blocks + bb]))));
+
+ rgn_blocks = RGN_BLOCKS (child_rgn);
+ for (bb = 0; bb < child_nr_blocks; bb++)
+ num_insns +=
+ (INSN_LUID (BB_END (BASIC_BLOCK (rgn_bb_table[rgn_blocks + bb])))
+ - INSN_LUID (BB_HEAD (BASIC_BLOCK (rgn_bb_table[rgn_blocks + bb]))));
+
+ /* Make sure the SEAR doesn't contain too many insns. */
+ if (num_insns > PARAM_VALUE (PARAM_MAX_SCHED_REGION_INSNS))
+ continue;
+
+ /* Update RGN_NR_BLOCKS, BLOCK_TO_BB, CONTAINING_RGN. */
+ RGN_NR_BLOCKS (parent_rgn) = parent_nr_blocks + child_nr_blocks;
+ for (bb = 0; bb < child_nr_blocks; bb++)
+ {
+ int child_block = rgn_bb_table[RGN_BLOCKS (child_rgn) + bb];
+
+ BLOCK_TO_BB (child_block) = parent_nr_blocks + bb;
+ CONTAINING_RGN (child_block) = parent_rgn;
+ }
+
+ /* If the child blocks are not located directly after the parent
+ blocks in rgn_bb_table then we need to adjust the rgn_bb_table. */
+ if((RGN_BLOCKS (parent_rgn) + parent_nr_blocks) != RGN_BLOCKS (child_rgn))
+ {
+ int idx;
+ int *child_blocks;
+
+ child_blocks = XNEWVEC (int, child_nr_blocks);
+ memcpy (child_blocks,
+ &rgn_bb_table[RGN_BLOCKS (child_rgn)],
+ child_nr_blocks * sizeof (int));
+
+ /* Relocate child blocks directly after parent blocks. */
+ idx = RGN_BLOCKS (parent_rgn) + parent_nr_blocks;
+ memmove (&(rgn_bb_table[idx + child_nr_blocks]),
+ &(rgn_bb_table[idx]),
+ (RGN_BLOCKS (child_rgn) - idx) * sizeof (int));
+
+ memcpy (&rgn_bb_table[idx],
+ child_blocks,
+ child_nr_blocks * sizeof (int));
+
+ free (child_blocks);
+
+ /* Adjust RGN_BLOCKS for all regions */
+ for(bb = parent_rgn + 1; bb < child_rgn; bb++)
+ RGN_BLOCKS (bb) += child_nr_blocks;
+ }
+
+ /* The child region has been merged. */
+ nr_regions--;
+
+ /* Adjust the rgn_table to remove child_rgn if it's not the
+ last region. */
+ if (child_rgn != nr_regions)
+ {
+ int rgn;
+ memmove (&(rgn_table[child_rgn]),
+ &(rgn_table[child_rgn+1]),
+ (nr_regions - child_rgn) * sizeof (region));
+
+ /* If child_rgn was not the last region we also need to update
+ the CONTAINING_RGN array for all later regions. */
+ for (rgn = parent_rgn + 1; rgn < nr_regions; rgn++)
+ for (bb = 0; bb < rgn_table[rgn].rgn_nr_blocks; bb++)
+ CONTAINING_RGN (rgn_bb_table[rgn_table[rgn].rgn_blocks + bb]) = rgn;
+ }
+ }
+ }
+ return;
+}
+
/* Extend regions.
DEGREE - Array of incoming edge count, considering only
the edges, that don't have their sources in formed regions yet.
@@ -3036,6 +3180,13 @@ init_regions (void)
{
/* Find treegions. */
find_trgns ();
+
+ /* Extend treegions to SEARs. */
+ extend_trgns_to_sears ();
+
+ if (sched_verbose >= 3)
+ debug_regions ();
+
}
else
{