re PR rtl-optimization/64081 (r217828 prevents RTL loop unroll)
gcc/ PR rtl-optimization/64081 * loop-iv.c (def_pred_latch_p): New function. (latch_dominating_def): Allow specific cases with non-single definitions. (iv_get_reaching_def): Likewise. (check_complex_exit_p): New function. (check_simple_exit): Use check_complex_exit_p to allow certain cases with exits not executing on any iteration. gcc/testsuite/ PR rtl-optimization/64081 * gcc.dg/pr64081.c: New test. From-SVN: r219842
This commit is contained in:
parent
ff6a32a98e
commit
dfd3a76cae
@ -1,3 +1,14 @@
|
||||
2015-01-19 Igor Zamyatin <igor.zamyatin@intel.com>
|
||||
|
||||
PR rtl-optimization/64081
|
||||
* loop-iv.c (def_pred_latch_p): New function.
|
||||
(latch_dominating_def): Allow specific cases with non-single
|
||||
definitions.
|
||||
(iv_get_reaching_def): Likewise.
|
||||
(check_complex_exit_p): New function.
|
||||
(check_simple_exit): Use check_complex_exit_p to allow certain cases
|
||||
with exits not executing on any iteration.
|
||||
|
||||
2015-01-19 Jakub Jelinek <jakub@redhat.com>
|
||||
|
||||
* common.opt (fgraphite): Fix a typo.
|
||||
|
129
gcc/loop-iv.c
129
gcc/loop-iv.c
@ -332,34 +332,72 @@ iv_analysis_loop_init (struct loop *loop)
|
||||
check_iv_ref_table_size ();
|
||||
}
|
||||
|
||||
/* Return true if D_REF is defined in an immediate predecessor of the
|
||||
current loop's latch block. Otherwise return false. */
|
||||
|
||||
static bool
|
||||
def_pred_latch_p (df_ref d_ref)
|
||||
{
|
||||
basic_block bb = DF_REF_BB (d_ref);
|
||||
edge_iterator ei;
|
||||
edge e;
|
||||
|
||||
FOR_EACH_EDGE (e, ei, current_loop->latch->preds)
|
||||
{
|
||||
if (e->src == bb)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Finds the definition of REG that dominates loop latch and stores
|
||||
it to DEF. Returns false if there is not a single definition
|
||||
dominating the latch. If REG has no definition in loop, DEF
|
||||
dominating the latch or all defs are same and they are on different
|
||||
predecessors of loop latch. If REG has no definition in loop, DEF
|
||||
is set to NULL and true is returned. */
|
||||
|
||||
static bool
|
||||
latch_dominating_def (rtx reg, df_ref *def)
|
||||
{
|
||||
df_ref single_rd = NULL, adef;
|
||||
unsigned regno = REGNO (reg);
|
||||
unsigned regno = REGNO (reg), def_num = 0;
|
||||
struct df_rd_bb_info *bb_info = DF_RD_BB_INFO (current_loop->latch);
|
||||
|
||||
for (adef = DF_REG_DEF_CHAIN (regno); adef; adef = DF_REF_NEXT_REG (adef))
|
||||
{
|
||||
/* Initialize this to true for the very first iteration when
|
||||
SINGLE_RD is NULL. */
|
||||
bool def_pred_latch = true;
|
||||
|
||||
if (!bitmap_bit_p (df->blocks_to_analyze, DF_REF_BBNO (adef))
|
||||
|| !bitmap_bit_p (&bb_info->out, DF_REF_ID (adef)))
|
||||
continue;
|
||||
|
||||
/* More than one reaching definition. */
|
||||
/* More than one reaching definition is ok in case definitions are
|
||||
in predecessors of latch block and those definitions are the same.
|
||||
Probably this could be relaxed and check for sub-dominance instead
|
||||
predecessor. */
|
||||
def_num++;
|
||||
if (single_rd)
|
||||
return false;
|
||||
|
||||
if (!just_once_each_iteration_p (current_loop, DF_REF_BB (adef)))
|
||||
return false;
|
||||
{
|
||||
if (!(def_pred_latch = def_pred_latch_p (adef))
|
||||
|| !rtx_equal_p (PATTERN (DF_REF_INSN (single_rd)),
|
||||
PATTERN (DF_REF_INSN (adef))))
|
||||
return false;
|
||||
}
|
||||
|
||||
single_rd = adef;
|
||||
}
|
||||
|
||||
/* If we have single definition it has to be executed on each iteration. */
|
||||
if ((def_num == 1) && single_rd
|
||||
&& !just_once_each_iteration_p (current_loop, DF_REF_BB (single_rd)))
|
||||
return false;
|
||||
|
||||
/* Make sure all preds contain definitions. */
|
||||
if (def_num != EDGE_COUNT (current_loop->latch->preds))
|
||||
return false;
|
||||
|
||||
*def = single_rd;
|
||||
return true;
|
||||
}
|
||||
@ -369,10 +407,10 @@ latch_dominating_def (rtx reg, df_ref *def)
|
||||
static enum iv_grd_result
|
||||
iv_get_reaching_def (rtx_insn *insn, rtx reg, df_ref *def)
|
||||
{
|
||||
df_ref use, adef;
|
||||
df_ref use, adef = NULL;
|
||||
basic_block def_bb, use_bb;
|
||||
rtx_insn *def_insn;
|
||||
bool dom_p;
|
||||
bool dom_p, dom_latch_p = false;
|
||||
|
||||
*def = NULL;
|
||||
if (!simple_reg_p (reg))
|
||||
@ -387,11 +425,26 @@ iv_get_reaching_def (rtx_insn *insn, rtx reg, df_ref *def)
|
||||
if (!DF_REF_CHAIN (use))
|
||||
return GRD_INVARIANT;
|
||||
|
||||
/* More than one reaching def. */
|
||||
if (DF_REF_CHAIN (use)->next)
|
||||
return GRD_INVALID;
|
||||
|
||||
adef = DF_REF_CHAIN (use)->ref;
|
||||
/* Having more than one reaching def is ok once all defs are in blocks which
|
||||
are latch's predecessors. */
|
||||
if (DF_REF_CHAIN (use)->next)
|
||||
{
|
||||
df_link* defs;
|
||||
unsigned int def_num = 0;
|
||||
|
||||
for (defs = DF_REF_CHAIN (use); defs; defs = defs->next)
|
||||
{
|
||||
if (!def_pred_latch_p (defs->ref))
|
||||
return GRD_INVALID;
|
||||
def_num++;
|
||||
}
|
||||
/* Make sure all preds contain definitions. */
|
||||
if (def_num != EDGE_COUNT (current_loop->latch->preds))
|
||||
return GRD_INVALID;
|
||||
|
||||
dom_latch_p = true;
|
||||
}
|
||||
|
||||
/* We do not handle setting only part of the register. */
|
||||
if (DF_REF_FLAGS (adef) & DF_REF_READ_WRITE)
|
||||
@ -414,8 +467,8 @@ iv_get_reaching_def (rtx_insn *insn, rtx reg, df_ref *def)
|
||||
|
||||
/* The definition does not dominate the use. This is still OK if
|
||||
this may be a use of a biv, i.e. if the def_bb dominates loop
|
||||
latch. */
|
||||
if (just_once_each_iteration_p (current_loop, def_bb))
|
||||
latch or all defs are in latch's predecessors. */
|
||||
if (dom_latch_p || just_once_each_iteration_p (current_loop, def_bb))
|
||||
return GRD_MAYBE_BIV;
|
||||
|
||||
return GRD_INVALID;
|
||||
@ -2928,6 +2981,49 @@ fail:
|
||||
return;
|
||||
}
|
||||
|
||||
/* Return true if LOOP has a complex exit, but is still good for further
|
||||
analysis. Return false otherwise. BB is LOOP's exit block. */
|
||||
|
||||
static bool
|
||||
check_complex_exit_p (struct loop* loop, basic_block bb)
|
||||
{
|
||||
edge e;
|
||||
basic_block pred, exit;
|
||||
|
||||
if (EDGE_COUNT (bb->preds) > 1)
|
||||
return false;
|
||||
|
||||
e = EDGE_PRED (bb, 0);
|
||||
|
||||
pred = e->src;
|
||||
if (EDGE_COUNT (pred->succs) != 2)
|
||||
return false;
|
||||
|
||||
/* Predecessor must be tested (at least) once during any iteration. */
|
||||
if (!dominated_by_p (CDI_DOMINATORS, loop->latch, pred))
|
||||
return false;
|
||||
|
||||
if (EDGE_SUCC (pred, 0)->dest == bb)
|
||||
exit = EDGE_SUCC (pred, 1)->dest;
|
||||
else
|
||||
exit = EDGE_SUCC (pred, 0)->dest;
|
||||
|
||||
/* Check that EXIT is really loop exit. */
|
||||
if (flow_bb_inside_loop_p (loop, exit))
|
||||
{
|
||||
edge_iterator eei;
|
||||
edge ee;
|
||||
|
||||
FOR_EACH_EDGE (ee, eei, exit->succs)
|
||||
{
|
||||
if (!flow_bb_inside_loop_p (loop, ee->dest))
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
/* Checks whether E is a simple exit from LOOP and stores its description
|
||||
into DESC. */
|
||||
|
||||
@ -2947,7 +3043,8 @@ check_simple_exit (struct loop *loop, edge e, struct niter_desc *desc)
|
||||
return;
|
||||
|
||||
/* It must be tested (at least) once during any iteration. */
|
||||
if (!dominated_by_p (CDI_DOMINATORS, loop->latch, exit_bb))
|
||||
if (!dominated_by_p (CDI_DOMINATORS, loop->latch, exit_bb)
|
||||
&& !check_complex_exit_p (loop, exit_bb))
|
||||
return;
|
||||
|
||||
/* It must end in a simple conditional jump. */
|
||||
|
@ -1,3 +1,8 @@
|
||||
2014-01-19 Igor Zamyatin <igor.zamyatin@intel.com>
|
||||
|
||||
PR rtl-optimization/64081
|
||||
* gcc.dg/pr64081.c: New test.
|
||||
|
||||
2015-01-19 Tejas Belagod <tejas.belagod@arm.com>
|
||||
|
||||
PR target/63971
|
||||
|
41
gcc/testsuite/gcc.dg/pr64081.c
Normal file
41
gcc/testsuite/gcc.dg/pr64081.c
Normal file
@ -0,0 +1,41 @@
|
||||
/* PR rtl-optimization/64081 */
|
||||
/* { dg-do compile } */
|
||||
/* { dg-options "-O2 -funroll-loops -fdump-rtl-loop2_unroll" } */
|
||||
|
||||
long token;
|
||||
long *data;
|
||||
long *arr1;
|
||||
long *arr2;
|
||||
|
||||
int main (int argc, const char* argv[])
|
||||
{
|
||||
unsigned long i;
|
||||
static long pos, start, count;
|
||||
static int dir;
|
||||
|
||||
pos = 0;
|
||||
dir = 1;
|
||||
|
||||
for (i = 0; i < argc; i++)
|
||||
{
|
||||
start = pos;
|
||||
for (count = 0; count <= 400; count++)
|
||||
{
|
||||
if (token == data[pos])
|
||||
break;
|
||||
if (dir == 1)
|
||||
pos = arr1[pos];
|
||||
else
|
||||
pos = arr2[pos];
|
||||
if (pos == -1)
|
||||
{
|
||||
pos = start;
|
||||
dir = !dir;
|
||||
}
|
||||
}
|
||||
}
|
||||
return pos + dir;
|
||||
}
|
||||
|
||||
/* { dg-final { scan-rtl-dump "loop unrolled 7 times" "loop2_unroll" } } */
|
||||
/* { dg-final { cleanup-rtl-dump "loop*" } } */
|
Loading…
x
Reference in New Issue
Block a user