Skip to content

Commit

Permalink
graphite: Extend SCoP detection dump output
Browse files Browse the repository at this point in the history
Extend dump output to make understanding why Graphite rejects to
include a loop in a SCoP easier (for GCC developers).

gcc/ChangeLog:

	* graphite-scop-detection.cc (scop_detection::can_represent_loop):
	Output reason for failure to dump file.
	(scop_detection::harmful_loop_in_region): Likewise.
	(scop_detection::graphite_can_represent_expr): Likewise.
	(scop_detection::stmt_has_simple_data_refs_p): Likewise.
	(scop_detection::stmt_simple_for_scop_p): Likewise.
	(print_sese_loop_numbers): New function.
	(scop_detection::add_scop): Use from here.

gcc/testsuite/ChangeLog:

	* gcc.dg/graphite/scop-22a.c: New test.
  • Loading branch information
Frederik Harwath committed May 18, 2022
1 parent 65851d6 commit 21e2bc9
Show file tree
Hide file tree
Showing 2 changed files with 219 additions and 21 deletions.
184 changes: 163 additions & 21 deletions gcc/graphite-scop-detection.cc
Original file line number Diff line number Diff line change
Expand Up @@ -69,12 +69,27 @@ class debug_printer
fprintf (output.dump_file, "%d", i);
return output;
}

friend debug_printer &
operator<< (debug_printer &output, const char *s)
{
fprintf (output.dump_file, "%s", s);
return output;
}

friend debug_printer &
operator<< (debug_printer &output, gimple* stmt)
{
print_gimple_stmt (output.dump_file, stmt, 0, TDF_VOPS | TDF_MEMSYMS);
return output;
}

friend debug_printer &
operator<< (debug_printer &output, tree t)
{
print_generic_expr (output.dump_file, t, TDF_SLIM);
return output;
}
} dp;

#define DEBUG_PRINT(args) do \
Expand Down Expand Up @@ -506,6 +521,27 @@ scop_detection::merge_sese (sese_l first, sese_l second) const
return combined;
}

/* Print the loop numbers of the loops contained in SESE to FILE. */

static void
print_sese_loop_numbers (FILE *file, sese_l sese)
{
bool first_loop = true;
for (loop_p nest = sese.entry->dest->loop_father; nest; nest = nest->next)
{
if (!loop_in_sese_p (nest, sese))
break;

for (auto loop : loops_list (cfun, LI_INCLUDE_ROOT, nest))
{
gcc_assert (loop_in_sese_p (loop, sese));

fprintf (file, "%s%d", first_loop ? "" : ", ", loop->num);
first_loop = false;
}
}
}

/* Build scop outer->inner if possible. */

void
Expand All @@ -519,6 +555,10 @@ scop_detection::build_scop_depth (loop_p loop)
if (! next
|| harmful_loop_in_region (next))
{
if (next)
DEBUG_PRINT (dp << "[scop-detection] Discarding SCoP on loops ";
print_sese_loop_numbers (dump_file, next);
dp << " because of harmful loops\n");
if (s)
add_scop (s);
build_scop_depth (loop);
Expand Down Expand Up @@ -560,14 +600,63 @@ scop_detection::can_represent_loop (loop_p loop, sese_l scop)
|| !single_pred_p (loop->latch)
|| exit->src != single_pred (loop->latch)
|| !empty_block_p (loop->latch))
return false;
{
DEBUG_PRINT (dp << "[can_represent_loop-fail] Loop shape unsupported.\n");
return false;
}

bool edge_irreducible = (loop_preheader_edge (loop)->flags
& EDGE_IRREDUCIBLE_LOOP);
if (edge_irreducible)
{
DEBUG_PRINT (dp << "[can_represent_loop-fail] "
"Loop is not a natural loop.\n");
return false;
}

bool niter_is_unconditional = number_of_iterations_exit (loop,
single_exit (loop),
&niter_desc, false);

if (!niter_is_unconditional)
{
DEBUG_PRINT (dp << "[can_represent_loop-fail] "
"Loop niter not unconditional.\n"
"Condition: " << niter_desc.assumptions << "\n");
return false;
}

niter = number_of_latch_executions (loop);
if (!niter)
{
DEBUG_PRINT (dp << "[can_represent_loop-fail] Loop niter unknown.\n");
return false;
}
if (!niter_desc.control.no_overflow)
{
DEBUG_PRINT (dp << "[can_represent_loop-fail] Loop niter can overflow.\n");
return false;
}

return !(loop_preheader_edge (loop)->flags & EDGE_IRREDUCIBLE_LOOP)
&& number_of_iterations_exit (loop, single_exit (loop), &niter_desc, false)
&& niter_desc.control.no_overflow
&& (niter = number_of_latch_executions (loop))
&& !chrec_contains_undetermined (niter)
&& graphite_can_represent_expr (scop, loop, niter);
bool undetermined_coefficients = chrec_contains_undetermined (niter);
if (undetermined_coefficients)
{
DEBUG_PRINT (dp << "[can_represent_loop-fail] "
"Loop niter chrec contains undetermined "
"coefficients.\n");
return false;
}

bool can_represent_expr = graphite_can_represent_expr (scop, loop, niter);
if (!can_represent_expr)
{
DEBUG_PRINT (dp << "[can_represent_loop-fail] "
<< "Loop niter expression cannot be represented: "
<< niter << "\n");
return false;
}

return true;
}

/* Return true when BEGIN is the preheader edge of a loop with a single exit
Expand Down Expand Up @@ -640,6 +729,13 @@ scop_detection::add_scop (sese_l s)

scops.safe_push (s);
DEBUG_PRINT (dp << "[scop-detection] Adding SCoP: "; print_sese (dump_file, s));

if (dump_file && dump_flags & TDF_DETAILS)
{
fprintf (dump_file, "Loops in SCoP: ");
print_sese_loop_numbers (dump_file, s);
fprintf (dump_file, "\n");
}
}

/* Return true when a statement in SCOP cannot be represented by Graphite. */
Expand All @@ -665,7 +761,12 @@ scop_detection::harmful_loop_in_region (sese_l scop) const

/* The basic block should not be part of an irreducible loop. */
if (bb->flags & BB_IRREDUCIBLE_LOOP)
return true;
{
DEBUG_PRINT (dp << "[scop-detection-fail] Found bb in irreducible "
"loop.\n");

return true;
}

/* Check for unstructured control flow: CFG not generated by structured
if-then-else. */
Expand All @@ -676,7 +777,11 @@ scop_detection::harmful_loop_in_region (sese_l scop) const
FOR_EACH_EDGE (e, ei, bb->succs)
if (!dominated_by_p (CDI_POST_DOMINATORS, bb, e->dest)
&& !dominated_by_p (CDI_DOMINATORS, e->dest, bb))
return true;
{
DEBUG_PRINT (dp << "[scop-detection-fail] Found unstructured "
"control flow.\n");
return true;
}
}

/* Collect all loops in the current region. */
Expand All @@ -688,7 +793,11 @@ scop_detection::harmful_loop_in_region (sese_l scop) const
for (gimple_stmt_iterator gsi = gsi_start_bb (bb);
!gsi_end_p (gsi); gsi_next (&gsi))
if (!stmt_simple_for_scop_p (scop, gsi_stmt (gsi), bb))
return true;
{
DEBUG_PRINT (dp << "[scop-detection-fail] "
"Found harmful statement.\n");
return true;
}

for (basic_block dom = first_dom_son (CDI_DOMINATORS, bb);
dom;
Expand Down Expand Up @@ -731,9 +840,10 @@ scop_detection::harmful_loop_in_region (sese_l scop) const
&& ! loop_nest_has_data_refs (loop))
{
DEBUG_PRINT (dp << "[scop-detection-fail] loop_" << loop->num
<< "does not have any data reference.\n");
<< " does not have any data reference.\n");
return true;
}
DEBUG_PRINT (dp << "[scop-detection] loop_" << loop->num << " is harmless.\n");
}

return false;
Expand Down Expand Up @@ -922,7 +1032,21 @@ scop_detection::graphite_can_represent_expr (sese_l scop, loop_p loop,
tree expr)
{
tree scev = cached_scalar_evolution_in_region (scop, loop, expr);
return graphite_can_represent_scev (scop, scev);
bool can_represent = graphite_can_represent_scev (scop, scev);

if (!can_represent)
{
if (dump_file)
{
fprintf (dump_file,
"[graphite_can_represent_expr] Cannot represent scev \"");
print_generic_expr (dump_file, scev, TDF_SLIM);
fprintf (dump_file, "\" of expression ");
print_generic_expr (dump_file, expr, TDF_SLIM);
fprintf (dump_file, " in loop %d\n", loop->num);
}
}
return can_represent;
}

/* Return true if the data references of STMT can be represented by Graphite.
Expand All @@ -938,15 +1062,24 @@ scop_detection::stmt_has_simple_data_refs_p (sese_l scop, gimple *stmt)

auto_vec<data_reference_p> drs;
if (! graphite_find_data_references_in_stmt (nest, loop, stmt, &drs))
return false;
{
DEBUG_PRINT (dp << "[stmt_has_simple_data_refs_p] "
"Unanalyzable statement.\n");
return false;
}

int j;
data_reference_p dr;
FOR_EACH_VEC_ELT (drs, j, dr)
{
for (unsigned i = 0; i < DR_NUM_DIMENSIONS (dr); ++i)
if (! graphite_can_represent_scev (scop, DR_ACCESS_FN (dr, i)))
return false;
{
DEBUG_PRINT (dp << "[stmt_has_simple_data_refs_p] "
"Cannot represent access function SCEV: "
<< DR_ACCESS_FN (dr, i) << "\n");
return false;
}
}

return true;
Expand Down Expand Up @@ -1027,14 +1160,23 @@ scop_detection::stmt_simple_for_scop_p (sese_l scop, gimple *stmt,
for (unsigned i = 0; i < 2; ++i)
{
tree op = gimple_op (stmt, i);
if (!graphite_can_represent_expr (scop, loop, op)
/* We can only constrain on integer type. */
|| ! INTEGRAL_TYPE_P (TREE_TYPE (op)))
if (!graphite_can_represent_expr (scop, loop, op))
{
DEBUG_PRINT (dump_printf_loc (MSG_MISSED_OPTIMIZATION, stmt,
"[scop-detection-fail] "
"Graphite cannot represent cond "
"stmt operator expression.\n"));
DEBUG_PRINT (dp << op << "\n");
return false;
}

if (! INTEGRAL_TYPE_P (TREE_TYPE (op)))
{
DEBUG_PRINT (dp << "[scop-detection-fail] "
<< "Graphite cannot represent stmt:\n";
print_gimple_stmt (dump_file, stmt, 0,
TDF_VOPS | TDF_MEMSYMS));
DEBUG_PRINT (dump_printf_loc (MSG_MISSED_OPTIMIZATION, stmt,
"[scop-detection-fail] "
"Graphite cannot represent cond "
"statement operator. "
"Type must be integral.\n"));
return false;
}
}
Expand Down
56 changes: 56 additions & 0 deletions gcc/testsuite/gcc.dg/graphite/scop-22a.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
/* { dg-require-effective-target size32plus } */
double u[1782225];

void foo(int N, int *res)
{
int i, j;
double a, b;
double sum = 0.0;

for (j = 3; j < N; j = j * j)
{
sum += a + b;
}

/* Next two loops form first SCoP */
for (i = 0; i < N; i++)
sum += u[i];

for (i = 0; i < N; i++)
{
a = u[i];
u[i] = i * i;
b = u[i];
sum += a + b;
}

for (j = 3; j < N; j = j * j)
{
sum += a + b;
}

for (j = 3; j < N; j = j * j)
{
sum += a + b;
}

/* Next two loop-nests form second SCoP */
for (i = 0; i < N; i++)
sum += u[i];

for (i = 0; i < N; i++)
for (j = 0; j < N; j++)
{
a = u[i];
u[i] = i * i;
b = u[j];
sum += a + b;
}

*res = sum + N;
}

/* { dg-final { scan-tree-dump-times "number of SCoPs: 2" 1 "graphite"} } */
/* { dg-final { scan-tree-dump-times "Loops in SCoP" 2 "graphite"} } */
/* { dg-final { scan-tree-dump "Loops in SCoP: 2, 3" "graphite"} } */
/* { dg-final { scan-tree-dump "Loops in SCoP: 6, 7, 8" "graphite"} } */

0 comments on commit 21e2bc9

Please sign in to comment.