graphite.c (dot_all_scops_1): Remove unused checks.
2008-09-29 Tobias Grosser <grosser@fim.uni-passau.de> * graphite.c (dot_all_scops_1): Remove unused checks. SCoPs always have exit and entry. (new_scop): Take entry and exit edge to define new SCoP. (sd_region_p): New structure used during SCoP detection. (move_scops): Delete. (move_sd_regions): New. (scopdet_info): Change the definition from edges back to basic_blocks. (scopdet_edge_info): Work on basic_blocks and rename to scopdet_basic_block_info. (split_difficult_bb): At the moment removed. We should later add it at another place. (build_scops_1): Work on basic_blocks. (bb_in_sd_region): New. (find_single_entry_edge): New. (find_single_exit_edge): New. (create_single_entry_edge): New. (sd_region_without_exit): New. (create_single_exit_edge): New. (unmark_exit_edges): New. (mark_exit_edges): New. (create_sese_edges): New. (build_graphite_scops): New. (build_scops): Make SCoPs SESE. (limit_scops): Use the new functions. From-SVN: r140746
This commit is contained in:
parent
e53c26770b
commit
a61e3d2a29
|
@ -1,3 +1,30 @@
|
|||
2008-09-29 Tobias Grosser <grosser@fim.uni-passau.de>
|
||||
|
||||
* graphite.c (dot_all_scops_1): Remove unused checks. SCoPs always have
|
||||
exit and entry.
|
||||
(new_scop): Take entry and exit edge to define new SCoP.
|
||||
(sd_region_p): New structure used during SCoP detection.
|
||||
(move_scops): Delete.
|
||||
(move_sd_regions): New.
|
||||
(scopdet_info): Change the definition from edges back to basic_blocks.
|
||||
(scopdet_edge_info): Work on basic_blocks and rename to
|
||||
scopdet_basic_block_info.
|
||||
(split_difficult_bb): At the moment removed. We should later
|
||||
add it at another place.
|
||||
(build_scops_1): Work on basic_blocks.
|
||||
(bb_in_sd_region): New.
|
||||
(find_single_entry_edge): New.
|
||||
(find_single_exit_edge): New.
|
||||
(create_single_entry_edge): New.
|
||||
(sd_region_without_exit): New.
|
||||
(create_single_exit_edge): New.
|
||||
(unmark_exit_edges): New.
|
||||
(mark_exit_edges): New.
|
||||
(create_sese_edges): New.
|
||||
(build_graphite_scops): New.
|
||||
(build_scops): Make SCoPs SESE.
|
||||
(limit_scops): Use the new functions.
|
||||
|
||||
2008-09-29 Hans-Peter Nilsson <hp@axis.com>
|
||||
|
||||
* config/cris/cris.h (IRA_COVER_CLASSES): Define.
|
||||
|
|
598
gcc/graphite.c
598
gcc/graphite.c
|
@ -566,8 +566,8 @@ dot_all_scops_1 (FILE *file)
|
|||
/* Select color for SCoP. */
|
||||
for (i = 0; VEC_iterate (scop_p, current_scops, i, scop); i++)
|
||||
if (bb_in_scop_p (bb, scop)
|
||||
|| (SESE_EXIT (SCOP_REGION (scop)) && SCOP_EXIT (scop) == bb)
|
||||
|| (SESE_ENTRY (SCOP_REGION (scop)) && SCOP_ENTRY (scop) == bb))
|
||||
|| (SCOP_EXIT (scop) == bb)
|
||||
|| (SCOP_ENTRY (scop) == bb))
|
||||
{
|
||||
switch (i % 17)
|
||||
{
|
||||
|
@ -631,16 +631,12 @@ dot_all_scops_1 (FILE *file)
|
|||
if (!bb_in_scop_p (bb, scop))
|
||||
fprintf (file, " (");
|
||||
|
||||
if (SESE_ENTRY (SCOP_REGION (scop))
|
||||
&& SESE_EXIT (SCOP_REGION (scop))
|
||||
&& bb == SCOP_ENTRY (scop)
|
||||
if (bb == SCOP_ENTRY (scop)
|
||||
&& bb == SCOP_EXIT (scop))
|
||||
fprintf (file, " %d*# ", bb->index);
|
||||
else if (SESE_ENTRY (SCOP_REGION (scop))
|
||||
&& bb == SCOP_ENTRY (scop))
|
||||
else if (bb == SCOP_ENTRY (scop))
|
||||
fprintf (file, " %d* ", bb->index);
|
||||
else if (SESE_EXIT (SCOP_REGION (scop))
|
||||
&& bb == SCOP_EXIT (scop))
|
||||
else if (bb == SCOP_EXIT (scop))
|
||||
fprintf (file, " %d# ", bb->index);
|
||||
else
|
||||
fprintf (file, " %d ", bb->index);
|
||||
|
@ -649,7 +645,6 @@ dot_all_scops_1 (FILE *file)
|
|||
fprintf (file, ")");
|
||||
|
||||
fprintf (file, "</TD></TR>\n");
|
||||
|
||||
part_of_scop = true;
|
||||
}
|
||||
|
||||
|
@ -731,7 +726,7 @@ block_before_scop (scop_p scop)
|
|||
static bool
|
||||
loop_affine_expr (basic_block scop_entry, struct loop *loop, tree expr)
|
||||
{
|
||||
int n = scop_entry->loop_father->num;
|
||||
int n = loop->num;
|
||||
tree scev = analyze_scalar_evolution (loop, expr);
|
||||
|
||||
scev = instantiate_scev (scop_entry, loop, scev);
|
||||
|
@ -913,13 +908,15 @@ free_graphite_bb (struct graphite_bb *gbb)
|
|||
/* Creates a new scop starting with ENTRY. */
|
||||
|
||||
static scop_p
|
||||
new_scop (edge entry)
|
||||
new_scop (edge entry, edge exit)
|
||||
{
|
||||
scop_p scop = XNEW (struct scop);
|
||||
|
||||
gcc_assert (entry && exit);
|
||||
|
||||
SCOP_REGION (scop) = XNEW (struct sese);
|
||||
SESE_ENTRY (SCOP_REGION (scop)) = entry;
|
||||
SESE_EXIT (SCOP_REGION (scop)) = NULL;
|
||||
SESE_EXIT (SCOP_REGION (scop)) = exit;
|
||||
SCOP_BBS (scop) = VEC_alloc (graphite_bb_p, heap, 3);
|
||||
SCOP_OLDIVS (scop) = VEC_alloc (name_tree, heap, 3);
|
||||
SCOP_BBS_B (scop) = BITMAP_ALLOC (NULL);
|
||||
|
@ -1012,28 +1009,66 @@ get_bb_type (basic_block bb, struct loop *last_loop)
|
|||
dom = get_dominated_by (CDI_DOMINATORS, bb);
|
||||
nb_dom = VEC_length (basic_block, dom);
|
||||
VEC_free (basic_block, heap, dom);
|
||||
|
||||
if (nb_dom == 0)
|
||||
return GBB_LAST;
|
||||
|
||||
nb_suc = VEC_length (edge, bb->succs);
|
||||
|
||||
if (nb_dom == 1 && nb_suc == 1)
|
||||
return GBB_SIMPLE;
|
||||
|
||||
return GBB_COND_HEADER;
|
||||
}
|
||||
|
||||
/* A SCoP detection region, defined using bbs as borders.
|
||||
All control flow touching this region, comes in passing basic_block ENTRY and
|
||||
leaves passing basic_block EXIT. By using bbs instead of edges for the
|
||||
borders we are able to represent also regions that do not have a single
|
||||
entry or exit edge.
|
||||
But as they have a single entry basic_block and a single exit basic_block, we
|
||||
are able to generate for every sd_region a single entry and exit edge.
|
||||
|
||||
1 2
|
||||
\ /
|
||||
3 <- entry
|
||||
|
|
||||
4
|
||||
/ \ This region contains: {3, 4, 5, 6, 7, 8}
|
||||
5 6
|
||||
| |
|
||||
7 8
|
||||
\ /
|
||||
9 <- exit */
|
||||
|
||||
|
||||
typedef struct sd_region_p
|
||||
{
|
||||
/* The entry bb dominates all bbs in the sd_region. It is part of the
|
||||
region. */
|
||||
basic_block entry;
|
||||
|
||||
/* The exit bb postdominates all bbs in the sd_region, but is not
|
||||
part of the region. */
|
||||
basic_block exit;
|
||||
} sd_region;
|
||||
|
||||
DEF_VEC_O(sd_region);
|
||||
DEF_VEC_ALLOC_O(sd_region, heap);
|
||||
|
||||
|
||||
/* Moves the scops from SOURCE to TARGET and clean up SOURCE. */
|
||||
|
||||
static void
|
||||
move_scops (VEC (scop_p, heap) **source, VEC (scop_p, heap) **target)
|
||||
move_sd_regions (VEC (sd_region, heap) **source, VEC (sd_region, heap) **target)
|
||||
{
|
||||
scop_p s;
|
||||
sd_region *s;
|
||||
int i;
|
||||
|
||||
for (i = 0; VEC_iterate (scop_p, *source, i, s); i++)
|
||||
VEC_safe_push (scop_p, heap, *target, s);
|
||||
for (i = 0; VEC_iterate (sd_region, *source, i, s); i++)
|
||||
VEC_safe_push (sd_region, heap, *target, s);
|
||||
|
||||
VEC_free (scop_p, heap, *source);
|
||||
VEC_free (sd_region, heap, *source);
|
||||
}
|
||||
|
||||
/* Store information needed by scopdet_* functions. */
|
||||
|
@ -1041,10 +1076,10 @@ move_scops (VEC (scop_p, heap) **source, VEC (scop_p, heap) **target)
|
|||
struct scopdet_info
|
||||
{
|
||||
/* Where the last open scop would stop if the current BB is harmful. */
|
||||
edge last;
|
||||
basic_block last;
|
||||
|
||||
/* Where the next scop would start if the current BB is harmful. */
|
||||
edge next;
|
||||
basic_block next;
|
||||
|
||||
/* The bb or one of its children contains open loop exits. That means
|
||||
loop exit nodes that are not surrounded by a loop dominated by bb. */
|
||||
|
@ -1054,30 +1089,24 @@ struct scopdet_info
|
|||
bool difficult;
|
||||
};
|
||||
|
||||
static struct scopdet_info build_scops_1 (edge, VEC (scop_p, heap) **,
|
||||
|
||||
static struct scopdet_info build_scops_1 (basic_block, VEC (sd_region, heap) **,
|
||||
loop_p);
|
||||
|
||||
/* Checks, if a bb can be added to a SCoP. */
|
||||
/* Calculates BB infos. If bb is difficult we add valid SCoPs dominated by BB
|
||||
to SCOPS. TYPE is the gbb_type of BB. */
|
||||
|
||||
static struct scopdet_info
|
||||
scopdet_edge_info (edge ee,
|
||||
VEC (scop_p, heap) **scops, gbb_type type, gimple *stmt)
|
||||
|
||||
scopdet_basic_block_info (basic_block bb, VEC (sd_region, heap) **scops,
|
||||
gbb_type type)
|
||||
{
|
||||
basic_block bb = ee->dest;
|
||||
struct loop *loop = bb->loop_father;
|
||||
struct scopdet_info result;
|
||||
basic_block scop_entry;
|
||||
gimple stmt;
|
||||
|
||||
if (VEC_length (scop_p, *scops) != 0)
|
||||
scop_entry = block_before_scop (VEC_last (scop_p, *scops));
|
||||
else if (loop->header)
|
||||
scop_entry = loop->header;
|
||||
else
|
||||
scop_entry = ENTRY_BLOCK_PTR;
|
||||
|
||||
*stmt = harmful_stmt_in_bb (scop_entry, bb);
|
||||
result.difficult = (*stmt != NULL);
|
||||
/* XXX: ENTRY_BLOCK_PTR could be optimized in later steps. */
|
||||
stmt = harmful_stmt_in_bb (ENTRY_BLOCK_PTR, bb);
|
||||
result.difficult = (stmt != NULL);
|
||||
result.last = NULL;
|
||||
|
||||
switch (type)
|
||||
|
@ -1085,44 +1114,42 @@ scopdet_edge_info (edge ee,
|
|||
case GBB_LAST:
|
||||
result.next = NULL;
|
||||
result.exits = false;
|
||||
result.last = ee;
|
||||
result.last = bb;
|
||||
break;
|
||||
|
||||
case GBB_SIMPLE:
|
||||
result.next = single_succ_edge (bb);
|
||||
result.next = single_succ (bb);
|
||||
result.exits = false;
|
||||
result.last = ee;
|
||||
result.last = bb;
|
||||
break;
|
||||
|
||||
case GBB_LOOP_SING_EXIT_HEADER:
|
||||
{
|
||||
VEC (scop_p, heap) *tmp_scops = VEC_alloc (scop_p, heap, 3);
|
||||
VEC (sd_region, heap) *tmp_scops = VEC_alloc (sd_region, heap,3);
|
||||
struct scopdet_info sinfo;
|
||||
|
||||
sinfo = build_scops_1 (ee, &tmp_scops, loop);
|
||||
|
||||
result.last = single_exit (bb->loop_father);
|
||||
|
||||
if (single_succ_p (result.last->dest)
|
||||
&& get_bb_type (result.last->dest, loop) == GBB_SIMPLE)
|
||||
result.next = single_succ_edge (result.last->dest);
|
||||
else
|
||||
result.next = split_block (result.last->dest, NULL);
|
||||
sinfo = build_scops_1 (bb, &tmp_scops, loop);
|
||||
|
||||
result.last = single_exit (bb->loop_father)->src;
|
||||
result.next = single_exit (bb->loop_father)->dest;
|
||||
|
||||
/* If we do not dominate result.next, remove it. It's either
|
||||
the EXIT_BLOCK_PTR, or another bb dominates it and will
|
||||
call the scop detection for this bb. */
|
||||
if (!dominated_by_p (CDI_DOMINATORS, result.next->dest, bb))
|
||||
result.next = NULL;
|
||||
if (!dominated_by_p (CDI_DOMINATORS, result.next, bb))
|
||||
result.next = NULL;
|
||||
|
||||
if (result.last->loop_father != loop)
|
||||
result.next = NULL;
|
||||
|
||||
if (TREE_CODE (number_of_latch_executions (loop))
|
||||
== SCEV_NOT_KNOWN)
|
||||
result.difficult = true;
|
||||
|
||||
if (sinfo.difficult)
|
||||
move_scops (&tmp_scops, scops);
|
||||
move_sd_regions (&tmp_scops, scops);
|
||||
else
|
||||
free_scops (tmp_scops);
|
||||
VEC_free (sd_region, heap, tmp_scops);
|
||||
|
||||
result.exits = false;
|
||||
result.difficult |= sinfo.difficult;
|
||||
|
@ -1131,37 +1158,36 @@ scopdet_edge_info (edge ee,
|
|||
|
||||
case GBB_LOOP_MULT_EXIT_HEADER:
|
||||
{
|
||||
/* XXX: Handle loop nests with the same header. */
|
||||
/* XXX: For now we just do not join loops with multiple exits. If the
|
||||
exits lead to the same bb it may be possible to join the loop. */
|
||||
VEC (scop_p, heap) *tmp_scops = VEC_alloc (scop_p, heap, 3);
|
||||
VEC (sd_region, heap) *tmp_scops = VEC_alloc (sd_region, heap, 3);
|
||||
VEC (edge, heap) *exits = get_loop_exit_edges (loop);
|
||||
edge e;
|
||||
int i;
|
||||
build_scops_1 (ee, &tmp_scops, loop);
|
||||
build_scops_1 (bb, &tmp_scops, loop);
|
||||
|
||||
/* XXX: Use 'e->src' ot better 'bb'? */
|
||||
for (i = 0; VEC_iterate (edge, exits, i, e); i++)
|
||||
if (dominated_by_p (CDI_DOMINATORS, e->dest, e->src)
|
||||
&& e->dest->loop_father == loop_outer (loop))
|
||||
build_scops_1 (e, &tmp_scops, e->dest->loop_father);
|
||||
&& e->src->loop_father == loop)
|
||||
build_scops_1 (e->dest, &tmp_scops, e->dest->loop_father);
|
||||
|
||||
result.next = NULL;
|
||||
result.last = NULL;
|
||||
result.difficult = true;
|
||||
result.exits = false;
|
||||
move_scops (&tmp_scops, scops);
|
||||
move_sd_regions (&tmp_scops, scops);
|
||||
VEC_free (edge, heap, exits);
|
||||
break;
|
||||
}
|
||||
case GBB_COND_HEADER:
|
||||
{
|
||||
VEC (scop_p, heap) *tmp_scops = VEC_alloc (scop_p, heap, 3);
|
||||
VEC (sd_region, heap) *tmp_scops = VEC_alloc (sd_region, heap, 3);
|
||||
struct scopdet_info sinfo;
|
||||
VEC (basic_block, heap) *dominated;
|
||||
int i;
|
||||
basic_block dom_bb;
|
||||
basic_block last_bb = NULL;
|
||||
edge last_e = NULL;
|
||||
edge e;
|
||||
result.exits = false;
|
||||
|
||||
|
@ -1197,7 +1223,6 @@ scopdet_edge_info (edge ee,
|
|||
if (!last_bb)
|
||||
{
|
||||
last_bb = e->dest;
|
||||
last_e = e;
|
||||
}
|
||||
|
||||
if (e->dest != last_bb)
|
||||
|
@ -1212,7 +1237,7 @@ scopdet_edge_info (edge ee,
|
|||
continue;
|
||||
}
|
||||
|
||||
sinfo = build_scops_1 (e, &tmp_scops, loop);
|
||||
sinfo = build_scops_1 (e->dest, &tmp_scops, loop);
|
||||
|
||||
result.exits |= sinfo.exits;
|
||||
result.last = sinfo.last;
|
||||
|
@ -1221,15 +1246,12 @@ scopdet_edge_info (edge ee,
|
|||
/* Checks, if all branches end at the same point.
|
||||
If that is true, the condition stays joinable.
|
||||
Have a look at the example above. */
|
||||
if (sinfo.last && single_succ_p (sinfo.last->dest))
|
||||
if (sinfo.last && single_succ_p (sinfo.last))
|
||||
{
|
||||
basic_block next_tmp = single_succ (sinfo.last->dest);
|
||||
basic_block next_tmp = single_succ (sinfo.last);
|
||||
|
||||
if (!last_bb)
|
||||
{
|
||||
last_bb = next_tmp;
|
||||
last_e = single_succ_edge (sinfo.last->dest);
|
||||
}
|
||||
|
||||
if (next_tmp != last_bb)
|
||||
result.difficult = true;
|
||||
|
@ -1244,11 +1266,11 @@ scopdet_edge_info (edge ee,
|
|||
/* Only return a next pointer if we dominate this pointer.
|
||||
Otherwise it will be handled by the bb dominating it. */
|
||||
if (dominated_by_p (CDI_DOMINATORS, last_bb, bb) && last_bb != bb)
|
||||
result.next = last_e;
|
||||
result.next = last_bb;
|
||||
else
|
||||
result.next = NULL;
|
||||
|
||||
move_scops (&tmp_scops, scops);
|
||||
VEC_free (sd_region, heap, tmp_scops);
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -1268,15 +1290,10 @@ scopdet_edge_info (edge ee,
|
|||
if (single_pred_p (dom_bb) && single_pred (dom_bb) == bb)
|
||||
continue;
|
||||
|
||||
if (single_pred_p (dom_bb))
|
||||
e = single_pred_edge (dom_bb);
|
||||
else
|
||||
e = split_block (dom_bb, NULL);
|
||||
|
||||
if (loop_depth (loop) > loop_depth (dom_bb->loop_father))
|
||||
sinfo = build_scops_1 (e, &tmp_scops, loop_outer (loop));
|
||||
sinfo = build_scops_1 (dom_bb, &tmp_scops, loop_outer (loop));
|
||||
else
|
||||
sinfo = build_scops_1 (e, &tmp_scops, loop);
|
||||
sinfo = build_scops_1 (dom_bb, &tmp_scops, loop);
|
||||
|
||||
|
||||
result.exits |= sinfo.exits;
|
||||
|
@ -1287,7 +1304,7 @@ scopdet_edge_info (edge ee,
|
|||
VEC_free (basic_block, heap, dominated);
|
||||
|
||||
result.next = NULL;
|
||||
move_scops (&tmp_scops, scops);
|
||||
move_sd_regions (&tmp_scops, scops);
|
||||
|
||||
break;
|
||||
}
|
||||
|
@ -1299,61 +1316,14 @@ scopdet_edge_info (edge ee,
|
|||
return result;
|
||||
}
|
||||
|
||||
/* Split EXIT before STMT when STMT is non NULL. */
|
||||
|
||||
static edge
|
||||
split_difficult_bb (basic_block exit, edge *last, gimple stmt)
|
||||
{
|
||||
if (stmt && VEC_length (edge, exit->preds) == 1)
|
||||
{
|
||||
edge e;
|
||||
|
||||
if (stmt == gsi_stmt (gsi_after_labels (exit)))
|
||||
stmt = NULL;
|
||||
else
|
||||
{
|
||||
gimple_stmt_iterator gsi = gsi_for_stmt (stmt);
|
||||
gsi_prev (&gsi);
|
||||
stmt = gsi_stmt (gsi);
|
||||
}
|
||||
|
||||
e = split_block (exit, stmt);
|
||||
set_immediate_dominator (CDI_DOMINATORS, e->dest, e->src);
|
||||
set_immediate_dominator (CDI_POST_DOMINATORS, e->src, e->dest);
|
||||
exit = e->dest;
|
||||
|
||||
if (last)
|
||||
*last = e;
|
||||
|
||||
return e;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* End SCOP with edge EXIT. */
|
||||
|
||||
static void
|
||||
end_scop (scop_p scop, edge exit, bool split_entry)
|
||||
{
|
||||
if (split_entry
|
||||
&& !single_pred_p (SCOP_ENTRY (scop))
|
||||
&& exit->dest->loop_father == SCOP_ENTRY (scop)->loop_father)
|
||||
SESE_ENTRY (SCOP_REGION (scop)) = split_block (SCOP_ENTRY (scop), NULL);
|
||||
|
||||
SESE_EXIT (SCOP_REGION (scop)) = exit;
|
||||
}
|
||||
|
||||
/* Creates the SCoPs and writes entry and exit points for every SCoP. */
|
||||
|
||||
static struct scopdet_info
|
||||
build_scops_1 (edge start, VEC (scop_p, heap) **scops, loop_p loop)
|
||||
build_scops_1 (basic_block current, VEC (sd_region, heap) **scops, loop_p loop)
|
||||
{
|
||||
edge current = start;
|
||||
|
||||
bool in_scop = false;
|
||||
scop_p open_scop = NULL;
|
||||
gimple stmt;
|
||||
sd_region open_scop;
|
||||
struct scopdet_info sinfo;
|
||||
|
||||
/* Initialize result. */
|
||||
|
@ -1362,30 +1332,26 @@ build_scops_1 (edge start, VEC (scop_p, heap) **scops, loop_p loop)
|
|||
result.difficult = false;
|
||||
result.next = NULL;
|
||||
result.last = NULL;
|
||||
open_scop.entry = NULL;
|
||||
|
||||
/* Loop over the dominance tree. If we meet a difficult bb, close
|
||||
the current SCoP. Loop and condition header start a new layer,
|
||||
and can only be added if all bbs in deeper layers are simple. */
|
||||
while (current != NULL)
|
||||
{
|
||||
sinfo = scopdet_edge_info (current, scops,
|
||||
get_bb_type (current->dest, loop), &stmt);
|
||||
sinfo = scopdet_basic_block_info (current, scops, get_bb_type (current,
|
||||
loop));
|
||||
|
||||
if (!in_scop && !(sinfo.exits || sinfo.difficult))
|
||||
{
|
||||
open_scop = new_scop (current);
|
||||
|
||||
VEC_safe_push (scop_p, heap, *scops, open_scop);
|
||||
open_scop.entry = current;
|
||||
open_scop.exit = NULL;
|
||||
in_scop = true;
|
||||
}
|
||||
else if (in_scop && (sinfo.exits || sinfo.difficult))
|
||||
{
|
||||
edge exit = split_difficult_bb (current->dest, &sinfo.last, stmt);
|
||||
|
||||
if (!exit)
|
||||
exit = current;
|
||||
|
||||
end_scop (open_scop, exit, sinfo.difficult);
|
||||
open_scop.exit = current;
|
||||
VEC_safe_push (sd_region, heap, *scops, &open_scop);
|
||||
in_scop = false;
|
||||
}
|
||||
|
||||
|
@ -1395,56 +1361,333 @@ build_scops_1 (edge start, VEC (scop_p, heap) **scops, loop_p loop)
|
|||
current = sinfo.next;
|
||||
}
|
||||
|
||||
/* Finish the SCOP, if it is left open. The exit is the bb, that
|
||||
postdominates sinfo.last. If no such bb exists, we use info.last
|
||||
or delete the scop. */
|
||||
/* Try to close open_scop, if we are still in an open SCoP. */
|
||||
if (in_scop)
|
||||
{
|
||||
int i;
|
||||
edge e;
|
||||
|
||||
for (i = 0; VEC_iterate (edge, sinfo.last->dest->succs, i, e); i++)
|
||||
if (dominated_by_p (CDI_POST_DOMINATORS, sinfo.last->dest, e->dest))
|
||||
{
|
||||
edge exit = split_difficult_bb (e->dest, &sinfo.last, stmt);
|
||||
for (i = 0; VEC_iterate (edge, sinfo.last->succs, i, e); i++)
|
||||
if (dominated_by_p (CDI_POST_DOMINATORS, sinfo.last, e->dest))
|
||||
open_scop.exit = e->dest;
|
||||
|
||||
if (exit)
|
||||
end_scop (open_scop, exit, sinfo.difficult);
|
||||
else
|
||||
end_scop (open_scop, e, sinfo.difficult);
|
||||
if (!open_scop.exit && open_scop.entry != sinfo.last)
|
||||
open_scop.exit = sinfo.last;
|
||||
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (SCOP_ENTRY (open_scop) != sinfo.last->dest)
|
||||
{
|
||||
edge exit = split_difficult_bb (sinfo.last->dest, NULL, stmt);
|
||||
|
||||
if (exit)
|
||||
end_scop (open_scop, exit, sinfo.difficult);
|
||||
else
|
||||
end_scop (open_scop, sinfo.last, sinfo.difficult);
|
||||
}
|
||||
else
|
||||
{
|
||||
VEC_pop (scop_p, *scops);
|
||||
free_scop (open_scop);
|
||||
}
|
||||
if (open_scop.exit)
|
||||
VEC_safe_push (sd_region, heap, *scops, &open_scop);
|
||||
|
||||
}
|
||||
|
||||
done:
|
||||
result.last = sinfo.last;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/* Checks if a bb is contained in REGION. */
|
||||
|
||||
static bool
|
||||
bb_in_sd_region (basic_block bb, sd_region *region)
|
||||
{
|
||||
return dominated_by_p (CDI_DOMINATORS, bb, region->entry)
|
||||
&& !(dominated_by_p (CDI_DOMINATORS, bb, region->exit)
|
||||
&& !dominated_by_p (CDI_DOMINATORS, region->entry,
|
||||
region->exit));
|
||||
}
|
||||
|
||||
/* Returns the single entry edge of REGION, if it does not exits NULL. */
|
||||
|
||||
static edge
|
||||
find_single_entry_edge (sd_region *region)
|
||||
{
|
||||
edge e;
|
||||
edge_iterator ei;
|
||||
edge entry = NULL;
|
||||
|
||||
FOR_EACH_EDGE (e, ei, region->entry->preds)
|
||||
if (!bb_in_sd_region (e->src, region))
|
||||
{
|
||||
if (entry)
|
||||
{
|
||||
entry = NULL;
|
||||
break;
|
||||
}
|
||||
|
||||
else
|
||||
entry = e;
|
||||
}
|
||||
|
||||
return entry;
|
||||
}
|
||||
|
||||
/* Returns the single exit edge of REGION, if it does not exits NULL. */
|
||||
|
||||
static edge
|
||||
find_single_exit_edge (sd_region *region)
|
||||
{
|
||||
edge e;
|
||||
edge_iterator ei;
|
||||
edge exit = NULL;
|
||||
|
||||
FOR_EACH_EDGE (e, ei, region->exit->preds)
|
||||
if (bb_in_sd_region (e->src, region))
|
||||
{
|
||||
if (exit)
|
||||
{
|
||||
exit = NULL;
|
||||
break;
|
||||
}
|
||||
|
||||
else
|
||||
exit = e;
|
||||
}
|
||||
|
||||
return exit;
|
||||
}
|
||||
|
||||
/* Create a single entry edge for REGION. */
|
||||
|
||||
static void
|
||||
create_single_entry_edge (sd_region *region)
|
||||
{
|
||||
if (find_single_entry_edge (region))
|
||||
return;
|
||||
|
||||
/* There are multiple predecessors for bb_3
|
||||
|
||||
| 1 2
|
||||
| | /
|
||||
| |/
|
||||
| 3 <- entry
|
||||
| |\
|
||||
| | |
|
||||
| 4 ^
|
||||
| | |
|
||||
| |/
|
||||
| 5
|
||||
|
||||
There are two edges (1->3, 2->3), that point from outside into the region,
|
||||
and another one (5->3), a loop latch, lead to bb_3.
|
||||
|
||||
We split bb_3.
|
||||
|
||||
| 1 2
|
||||
| | /
|
||||
| |/
|
||||
|3.0
|
||||
| |\ (3.0 -> 3.1) = single entry edge
|
||||
|3.1 | <- entry
|
||||
| | |
|
||||
| | |
|
||||
| 4 ^
|
||||
| | |
|
||||
| |/
|
||||
| 5
|
||||
|
||||
If the loop is part of the SCoP, we have to redirect the loop latches.
|
||||
|
||||
| 1 2
|
||||
| | /
|
||||
| |/
|
||||
|3.0
|
||||
| | (3.0 -> 3.1) = entry edge
|
||||
|3.1 <- entry
|
||||
| |\
|
||||
| | |
|
||||
| 4 ^
|
||||
| | |
|
||||
| |/
|
||||
| 5 */
|
||||
|
||||
if (region->entry->loop_father->header != region->entry
|
||||
|| dominated_by_p (CDI_DOMINATORS,
|
||||
loop_latch_edge (region->entry->loop_father)->src,
|
||||
region->exit))
|
||||
{
|
||||
edge forwarder = split_block_after_labels (region->entry);
|
||||
region->entry = forwarder->dest;
|
||||
}
|
||||
else
|
||||
/* This case is never executed, as the loop headers seem always to have a
|
||||
single edge pointing from outside into the loop. */
|
||||
gcc_unreachable ();
|
||||
|
||||
#ifdef ENABLE_CHECKING
|
||||
gcc_assert (find_single_entry_edge (region));
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Check if the sd_region, mentioned in EDGE, has no exit bb. */
|
||||
|
||||
static bool
|
||||
sd_region_without_exit (edge e)
|
||||
{
|
||||
sd_region *r = (sd_region *) e->aux;
|
||||
|
||||
if (r)
|
||||
return r->exit == NULL;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Create a single exit edge for REGION. */
|
||||
|
||||
static void
|
||||
create_single_exit_edge (sd_region *region)
|
||||
{
|
||||
edge e;
|
||||
edge_iterator ei;
|
||||
edge forwarder = NULL;
|
||||
basic_block exit;
|
||||
|
||||
if (find_single_exit_edge (region))
|
||||
return;
|
||||
|
||||
/* We create a forwarder bb (5) for all edges leaving this region
|
||||
(3->5, 4->5). All other edges leading to the same bb, are moved
|
||||
to a new bb (6). If these edges where part of another region (2->5)
|
||||
we update the region->exit pointer, of this region.
|
||||
|
||||
To identify which edge belongs to which region we depend on the e->aux
|
||||
pointer in every edge. It points to the region of the edge or to NULL,
|
||||
if the edge is not part of any region.
|
||||
|
||||
1 2 3 4 1->5 no region, 2->5 region->exit = 5,
|
||||
\| |/ 3->5 region->exit = NULL, 4->5 region->exit = NULL
|
||||
5 <- exit
|
||||
|
||||
changes to
|
||||
|
||||
1 2 3 4 1->6 no region, 2->6 region->exit = 6,
|
||||
| | \/ 3->5 no region, 4->5 no region,
|
||||
| | 5
|
||||
\| / 5->6 region->exit = 6
|
||||
6
|
||||
|
||||
Now there is only a single exit edge (5->6). */
|
||||
exit = region->exit;
|
||||
region->exit = NULL;
|
||||
forwarder = make_forwarder_block (exit, &sd_region_without_exit, NULL);
|
||||
|
||||
/* Unmark the edges, that are no longer exit edges. */
|
||||
FOR_EACH_EDGE (e, ei, forwarder->src->preds)
|
||||
if (e->aux)
|
||||
e->aux = NULL;
|
||||
|
||||
/* Mark the new exit edge. */
|
||||
single_succ_edge (forwarder->src)->aux = region;
|
||||
|
||||
/* Update the exit bb of all regions, where exit edges lead to
|
||||
forwarder->dest. */
|
||||
FOR_EACH_EDGE (e, ei, forwarder->dest->preds)
|
||||
if (e->aux)
|
||||
((sd_region *) e->aux)->exit = forwarder->dest;
|
||||
|
||||
#ifdef ENABLE_CHECKING
|
||||
gcc_assert (find_single_exit_edge (region));
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Unmark the exit edges of all REGIONS.
|
||||
See comment in "create_single_exit_edge". */
|
||||
|
||||
static void
|
||||
unmark_exit_edges (VEC (sd_region, heap) *regions)
|
||||
{
|
||||
int i;
|
||||
sd_region *s;
|
||||
edge e;
|
||||
edge_iterator ei;
|
||||
|
||||
for (i = 0; VEC_iterate (sd_region, regions, i, s); i++)
|
||||
FOR_EACH_EDGE (e, ei, s->exit->preds)
|
||||
e->aux = NULL;
|
||||
}
|
||||
|
||||
|
||||
/* Mark the exit edges of all REGIONS.
|
||||
See comment in "create_single_exit_edge". */
|
||||
|
||||
static void
|
||||
mark_exit_edges (VEC (sd_region, heap) *regions)
|
||||
{
|
||||
int i;
|
||||
sd_region *s;
|
||||
edge e;
|
||||
edge_iterator ei;
|
||||
|
||||
for (i = 0; VEC_iterate (sd_region, regions, i, s); i++)
|
||||
FOR_EACH_EDGE (e, ei, s->exit->preds)
|
||||
if (bb_in_sd_region (e->src, s))
|
||||
e->aux = s;
|
||||
}
|
||||
|
||||
|
||||
/* Create for all scop regions a single entry and a single exit edge. */
|
||||
|
||||
static void
|
||||
create_sese_edges (VEC (sd_region, heap) *regions)
|
||||
{
|
||||
int i;
|
||||
sd_region *s;
|
||||
|
||||
|
||||
for (i = 0; VEC_iterate (sd_region, regions, i, s); i++)
|
||||
create_single_entry_edge (s);
|
||||
|
||||
mark_exit_edges (regions);
|
||||
|
||||
for (i = 0; VEC_iterate (sd_region, regions, i, s); i++)
|
||||
create_single_exit_edge (s);
|
||||
|
||||
unmark_exit_edges (regions);
|
||||
|
||||
#ifdef ENABLE_CHECKING
|
||||
verify_loop_structure ();
|
||||
verify_dominators (CDI_DOMINATORS);
|
||||
verify_ssa (false);
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Create graphite SCoPs from an array of scop detection regions. */
|
||||
|
||||
static void
|
||||
build_graphite_scops (VEC (sd_region, heap) *scop_regions)
|
||||
{
|
||||
int i;
|
||||
sd_region *s;
|
||||
|
||||
for (i = 0; VEC_iterate (sd_region, scop_regions, i, s); i++)
|
||||
{
|
||||
edge entry = find_single_entry_edge (s);
|
||||
edge exit = find_single_exit_edge (s);
|
||||
scop_p scop = new_scop (entry, exit);
|
||||
VEC_safe_push (scop_p, heap, current_scops, scop);
|
||||
|
||||
/* Are there overlapping SCoPs? */
|
||||
#ifdef ENABLE_CHECKING
|
||||
{
|
||||
int j;
|
||||
sd_region *s2;
|
||||
|
||||
for (j = 0; VEC_iterate (sd_region, scop_regions, j, s2); j++)
|
||||
if (s != s2)
|
||||
gcc_assert (!bb_in_sd_region (s->entry, s2));
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
/* Find static control parts. */
|
||||
|
||||
static void
|
||||
build_scops (void)
|
||||
{
|
||||
struct loop *loop = current_loops->tree_root;
|
||||
build_scops_1 (single_succ_edge (ENTRY_BLOCK_PTR), ¤t_scops, loop);
|
||||
VEC (sd_region, heap) *tmp_scops = VEC_alloc (sd_region, heap, 3);
|
||||
|
||||
build_scops_1 (single_succ (ENTRY_BLOCK_PTR), &tmp_scops, loop);
|
||||
create_sese_edges (tmp_scops);
|
||||
build_graphite_scops (tmp_scops);
|
||||
}
|
||||
|
||||
/* Gather the basic blocks belonging to the SCOP. */
|
||||
|
@ -4702,13 +4945,14 @@ graphite_apply_transformations (scop_p scop)
|
|||
This is necessary as scalar evolution and parameter detection need a
|
||||
outermost loop to initialize parameters correctly.
|
||||
|
||||
TODO: FIX scalar evolution and parameter detection to allow mor flexible
|
||||
TODO: FIX scalar evolution and parameter detection to allow more flexible
|
||||
SCoP frontiers. */
|
||||
|
||||
static void
|
||||
limit_scops (void)
|
||||
{
|
||||
VEC (scop_p, heap) *new_scops = VEC_alloc (scop_p, heap, 3);
|
||||
VEC (sd_region, heap) *tmp_scops = VEC_alloc (sd_region, heap, 3);
|
||||
|
||||
int i;
|
||||
scop_p scop;
|
||||
|
||||
|
@ -4722,14 +4966,18 @@ limit_scops (void)
|
|||
for (j = 0; VEC_iterate (loop_p, SCOP_LOOP_NEST (scop), j, loop); j++)
|
||||
if (!loop_in_scop_p (loop_outer (loop), scop))
|
||||
{
|
||||
scop_p n_scop = new_scop (loop_preheader_edge (loop));
|
||||
end_scop (n_scop, single_exit (loop), false);
|
||||
VEC_safe_push (scop_p, heap, new_scops, n_scop);
|
||||
sd_region open_scop;
|
||||
open_scop.entry = loop_preheader_edge (loop)->dest;
|
||||
open_scop.exit = single_exit (loop)->dest;
|
||||
VEC_safe_push (sd_region, heap, tmp_scops, &open_scop);
|
||||
}
|
||||
}
|
||||
|
||||
free_scops (current_scops);
|
||||
current_scops = new_scops;
|
||||
current_scops = VEC_alloc (scop_p, heap, 3);
|
||||
|
||||
create_sese_edges (tmp_scops);
|
||||
build_graphite_scops (tmp_scops);
|
||||
}
|
||||
|
||||
/* Perform a set of linear transforms on the loops of the current
|
||||
|
|
Loading…
Reference in New Issue