tree-ssa-loop-ch.c [plain text]
#include "config.h"
#include "system.h"
#include "coretypes.h"
#include "tm.h"
#include "tree.h"
#include "rtl.h"
#include "tm_p.h"
#include "hard-reg-set.h"
#include "basic-block.h"
#include "output.h"
#include "diagnostic.h"
#include "tree-flow.h"
#include "tree-dump.h"
#include "tree-pass.h"
#include "timevar.h"
#include "cfgloop.h"
#include "tree-inline.h"
#include "flags.h"
#include "tree-inline.h"
static bool
should_duplicate_loop_header_p (basic_block header, struct loop *loop,
int *limit)
{
block_stmt_iterator bsi;
tree last;
if (header->aux)
return false;
gcc_assert (EDGE_COUNT (header->succs) > 0);
if (EDGE_COUNT (header->succs) == 1)
return false;
if (flow_bb_inside_loop_p (loop, EDGE_SUCC (header, 0)->dest)
&& flow_bb_inside_loop_p (loop, EDGE_SUCC (header, 1)->dest))
return false;
if (header != loop->header && EDGE_COUNT (header->preds) >= 2)
return false;
last = last_stmt (header);
if (TREE_CODE (last) != COND_EXPR)
return false;
for (bsi = bsi_start (header); !bsi_end_p (bsi); bsi_next (&bsi))
{
last = bsi_stmt (bsi);
if (TREE_CODE (last) == LABEL_EXPR)
continue;
if (get_call_expr_in (last))
return false;
*limit -= estimate_num_insns (last);
if (*limit < 0)
return false;
}
return true;
}
static bool
do_while_loop_p (struct loop *loop)
{
tree stmt = last_stmt (loop->latch);
if (stmt
&& TREE_CODE (stmt) != LABEL_EXPR)
return false;
stmt = last_and_only_stmt (loop->header);
if (stmt
&& TREE_CODE (stmt) == COND_EXPR)
return false;
return true;
}
static void
copy_loop_headers (void)
{
struct loops *loops;
unsigned i;
struct loop *loop;
basic_block header;
edge exit;
basic_block *bbs;
unsigned n_bbs;
loops = tree_loop_optimizer_init (dump_file);
if (!loops)
return;
rewrite_into_loop_closed_ssa ();
loops->state &= ~LOOPS_HAVE_MARKED_IRREDUCIBLE_REGIONS;
#ifdef ENABLE_CHECKING
verify_loop_structure (loops);
#endif
bbs = xmalloc (sizeof (basic_block) * n_basic_blocks);
for (i = 1; i < loops->num; i++)
{
int limit = 20;
loop = loops->parray[i];
if (!loop)
continue;
header = loop->header;
if (do_while_loop_p (loop))
continue;
exit = NULL;
n_bbs = 0;
while (should_duplicate_loop_header_p (header, loop, &limit))
{
if (flow_bb_inside_loop_p (loop, EDGE_SUCC (header, 0)->dest))
exit = EDGE_SUCC (header, 0);
else
exit = EDGE_SUCC (header, 1);
bbs[n_bbs++] = header;
header = exit->dest;
}
if (!exit)
continue;
if (dump_file && (dump_flags & TDF_DETAILS))
fprintf (dump_file,
"Duplicating header of the loop %d up to edge %d->%d.\n",
loop->num, exit->src->index, exit->dest->index);
if (EDGE_COUNT (exit->dest->preds) > 1)
exit = EDGE_SUCC (loop_split_edge_with (exit, NULL), 0);
if (!tree_duplicate_sese_region (loop_preheader_edge (loop), exit,
bbs, n_bbs, NULL))
{
fprintf (dump_file, "Duplication failed.\n");
continue;
}
loop_split_edge_with (loop_preheader_edge (loop), NULL);
loop_split_edge_with (loop_latch_edge (loop), NULL);
}
free (bbs);
#ifdef ENABLE_CHECKING
verify_loop_closed_ssa ();
#endif
loop_optimizer_finalize (loops, NULL);
}
static bool
gate_ch (void)
{
return flag_tree_ch != 0;
}
struct tree_opt_pass pass_ch =
{
"ch",
gate_ch,
copy_loop_headers,
NULL,
NULL,
0,
TV_TREE_CH,
PROP_cfg | PROP_ssa,
0,
0,
0,
TODO_cleanup_cfg | TODO_dump_func
| TODO_verify_ssa,
0
};