Home | History | Annotate | Line # | Download | only in dist
      1 /*
      2  * Copyright 2021      Sven Verdoolaege
      3  *
      4  * Use of this software is governed by the MIT license
      5  *
      6  * Written by Sven Verdoolaege
      7  */
      8 
      9 #include <stdio.h>
     10 
     11 #include <isl/ctx.h>
     12 #include <isl/schedule_node.h>
     13 #include <isl/union_set.h>
     14 
     15 #include "isl_hash_private.h"
     16 #include "isl_scheduler_scc.h"
     17 #include "isl_sort.h"
     18 
     19 /* Internal data structure for ordering the SCCs of "graph",
     20  * where each SCC i consists of the single cluster determined
     21  * by c->scc_cluster[i].  The nodes in this cluster all have
     22  * their "scc" field set to i.
     23  *
     24  * "graph" is the original schedule graph.
     25  * "c" contains the clustering information.
     26  *
     27  * "n" is the number of SCCs in the isl_scc_graph, which may be
     28  * a subset of those in "graph".
     29  * "graph_scc" maps the local index of an SCC in this isl_scc_graph
     30  * to the corresponding index in "graph", i.e, the index of c->scc_cluster.
     31  * The entries of "graph_scc" are kept in topological order.
     32  *
     33  * "component" contains the component to which an SCC belongs,
     34  * where the component is represented by the index of the first SCC
     35  * in the component.
     36  * The index of this first SCC is always smaller than or equal
     37  * to the index of the SCC itself.
     38  * This field is initialized by isl_scc_graph_init_component and
     39  * used by detect_components.
     40  * During construction, "component" may also contain the index
     41  * of some other SCC in the component, but then it is necessarily
     42  * smaller than the index of the current SCC and the first SCC
     43  * can be reached by recursively looking up "component".
     44  * "size" contains the number of elements in the components
     45  * indexed by a component sequence number.
     46  *
     47  * "pos" is used locally inside isl_scc_graph_sort_components
     48  * to store the position of the next SCC within a component.
     49  * It is also used inside isl_scc_graph_sub to map
     50  * the position in the original graph to the position in the subgraph.
     51  *
     52  * "sorted" contains the (possibly) reordered local indices,
     53  * sorted per component.  Within each component, the original
     54  * topological order is preserved.
     55  *
     56  * "edge_table" contains "n" edge tables, one for each SCC
     57  * in this isl_scc_graph.  Each table contains the local indices
     58  * of the SCCs that depend on this SCC.  These local indices
     59  * are encoded as pointers to the corresponding entry in "graph_scc".
     60  * The value stored at that location is the global SCC index.
     61  * "reverse_edge_table" contains the inverse edges.
     62  */
     63 struct isl_scc_graph {
     64 	isl_ctx *ctx;
     65 	struct isl_sched_graph *graph;
     66 	struct isl_clustering *c;
     67 
     68 	int n;
     69 	int *graph_scc;
     70 	int *component;
     71 	int *size;
     72 	int *pos;
     73 	int *sorted;
     74 	struct isl_hash_table **edge_table;
     75 	struct isl_hash_table **reverse_edge_table;
     76 };
     77 
     78 /* The source SCC of a collection of edges.
     79  *
     80  * "scc_graph" is the SCC graph containing the edges.
     81  * "src" is the local index of the source SCC.
     82  */
     83 struct isl_edge_src {
     84 	struct isl_scc_graph *scc_graph;
     85 	int src;
     86 };
     87 
     88 /* isl_hash_table_foreach callback for printing an edge
     89  * between "src" and the node identified by "entry".
     90  * The edge is printed in terms of the global SCC indices.
     91  */
     92 static isl_stat print_edge(void **entry, void *user)
     93 {
     94 	int *dst = *entry;
     95 	int *src = user;
     96 
     97 	fprintf(stderr, "%d -> %d; ", *src, *dst);
     98 
     99 	return isl_stat_ok;
    100 }
    101 
    102 /* Print some debugging information about "scc_graph".
    103  *
    104  * In particular, print the nodes and the edges (both forward and backward).
    105  */
    106 void isl_scc_graph_dump(struct isl_scc_graph *scc_graph)
    107 {
    108 	int i;
    109 	isl_ctx *ctx;
    110 
    111 	if (!scc_graph)
    112 		return;
    113 
    114 	ctx = scc_graph->ctx;
    115 	for (i = 0; i < scc_graph->n; ++i) {
    116 		if (i)
    117 			fprintf(stderr, ", ");
    118 		fprintf(stderr, "%d", scc_graph->graph_scc[i]);
    119 	}
    120 	fprintf(stderr, "\n");
    121 	for (i = 0; i < scc_graph->n; ++i) {
    122 		isl_hash_table_foreach(ctx, scc_graph->edge_table[i],
    123 			&print_edge, &scc_graph->graph_scc[i]);
    124 	}
    125 	fprintf(stderr, "\n");
    126 	for (i = 0; i < scc_graph->n; ++i) {
    127 		isl_hash_table_foreach(ctx, scc_graph->reverse_edge_table[i],
    128 			&print_edge, &scc_graph->graph_scc[i]);
    129 	}
    130 	fprintf(stderr, "\n");
    131 }
    132 
    133 /* Free all memory allocated for "scc_graph" and return NULL.
    134  */
    135 struct isl_scc_graph *isl_scc_graph_free(struct isl_scc_graph *scc_graph)
    136 {
    137 	int i;
    138 	isl_ctx *ctx;
    139 
    140 	if (!scc_graph)
    141 		return NULL;
    142 
    143 	ctx = scc_graph->ctx;
    144 	if (scc_graph->edge_table) {
    145 		for (i = 0; i < scc_graph->n; ++i)
    146 			isl_hash_table_free(ctx, scc_graph->edge_table[i]);
    147 	}
    148 	if (scc_graph->reverse_edge_table) {
    149 		for (i = 0; i < scc_graph->n; ++i)
    150 			isl_hash_table_free(ctx,
    151 					    scc_graph->reverse_edge_table[i]);
    152 	}
    153 
    154 	free(scc_graph->graph_scc);
    155 	free(scc_graph->component);
    156 	free(scc_graph->size);
    157 	free(scc_graph->pos);
    158 	free(scc_graph->sorted);
    159 	free(scc_graph->edge_table);
    160 	free(scc_graph->reverse_edge_table);
    161 	isl_ctx_deref(scc_graph->ctx);
    162 	free(scc_graph);
    163 	return NULL;
    164 }
    165 
    166 /* Return an encoding of the local SCC index "pos" in "scc_graph"
    167  * as a pointer.
    168  * In particular, return a pointer to the corresponding entry
    169  * in scc_graph->graph_scc.
    170  */
    171 static void *isl_scc_graph_encode_local_index(struct isl_scc_graph *scc_graph,
    172 	int pos)
    173 {
    174 	return &scc_graph->graph_scc[pos];
    175 }
    176 
    177 /* Return the local SCC index in "scc_graph" corresponding
    178  * to the "data" encoding in the edge table.
    179  */
    180 static int isl_scc_graph_local_index(struct isl_scc_graph *scc_graph, int *data)
    181 {
    182 	return data - &scc_graph->graph_scc[0];
    183 }
    184 
    185 /* isl_hash_table_find callback to check whether the given entry
    186  * refers to an SCC encoded as "val".
    187  */
    188 static isl_bool is_scc_node(const void *entry, const void *val)
    189 {
    190 	return entry == val;
    191 }
    192 
    193 /* Return the edge from local SCC index "src" to local SCC index "dst"
    194  * in "edge_table" of "scc_graph", creating one if "reserve" is set.
    195  * If "reserve" is not set, then return isl_hash_table_entry_none
    196  * if there is no such edge.
    197  *
    198  * The destination of the edge is encoded as a pointer
    199  * to the corresponding entry in scc_graph->graph_scc.
    200  */
    201 struct isl_hash_table_entry *isl_scc_graph_find_edge(
    202 	struct isl_scc_graph *scc_graph, struct isl_hash_table **edge_table,
    203 	int src, int dst, int reserve)
    204 {
    205 	isl_ctx *ctx;
    206 	uint32_t hash;
    207 	void *val;
    208 
    209 	ctx = scc_graph->ctx;
    210 	hash = isl_hash_builtin(isl_hash_init(), dst);
    211 	val = isl_scc_graph_encode_local_index(scc_graph, dst);
    212 	return isl_hash_table_find(ctx, edge_table[src], hash,
    213 					&is_scc_node, val, reserve);
    214 }
    215 
    216 /* Remove the edge between the SCCs with local indices "src" and
    217  * "dst" in "scc_graph", if it exits.
    218  * Return isl_bool_true if this is the case.
    219  *
    220  * The edge is only removed from scc_graph->edge_table.
    221  * scc_graph->reverse_edge_table is assumed to be empty
    222  * when this function is called.
    223  */
    224 static isl_bool isl_scc_graph_remove_edge(struct isl_scc_graph *scc_graph,
    225 	int src, int dst)
    226 {
    227 	isl_ctx *ctx;
    228 	struct isl_hash_table_entry *edge_entry;
    229 
    230 	edge_entry = isl_scc_graph_find_edge(scc_graph, scc_graph->edge_table,
    231 						src, dst, 0);
    232 	if (edge_entry == isl_hash_table_entry_none)
    233 		return isl_bool_false;
    234 	if (!edge_entry)
    235 		return isl_bool_error;
    236 
    237 	ctx = scc_graph->ctx;
    238 	isl_hash_table_remove(ctx, scc_graph->edge_table[src], edge_entry);
    239 
    240 	return isl_bool_true;
    241 }
    242 
    243 /* Internal data structure used by next_nodes.
    244  *
    245  * "scc_graph" is the SCC graph.
    246  * "next" collects the next nodes.
    247  * "n" is the number of next nodes already collected.
    248  */
    249 struct isl_extract_dst_data {
    250 	struct isl_scc_graph *scc_graph;
    251 	int *next;
    252 	int n;
    253 };
    254 
    255 /* Given an entry in the edge table, add the corresponding
    256  * target local SCC index to data->next.
    257  */
    258 static isl_stat extract_dst(void **entry, void *user)
    259 {
    260 	int *dst = *entry;
    261 	struct isl_extract_dst_data *data = user;
    262 
    263 	data->next[data->n++] = isl_scc_graph_local_index(data->scc_graph, dst);
    264 
    265 	return isl_stat_ok;
    266 }
    267 
    268 /* isl_sort callback for sorting integers in increasing order.
    269  */
    270 static int cmp_int(const void *a, const void *b, void *data)
    271 {
    272 	const int *i1 = a;
    273 	const int *i2 = b;
    274 
    275 	return *i1 - *i2;
    276 }
    277 
    278 /* Return the local indices of the SCCs in "scc_graph"
    279  * for which there is an edge from the SCC with local index "i".
    280  * The indices are returned in increasing order,
    281  * i.e., in the original topological order.
    282  */
    283 static int *next_nodes(struct isl_scc_graph *scc_graph, int i)
    284 {
    285 	struct isl_extract_dst_data data;
    286 	int n_next;
    287 	int *next;
    288 
    289 	n_next = scc_graph->edge_table[i]->n;
    290 	next = isl_alloc_array(scc_graph->ctx, int, n_next);
    291 	if (!next)
    292 		return NULL;
    293 	data.scc_graph = scc_graph;
    294 	data.next = next;
    295 	data.n = 0;
    296 	if (isl_hash_table_foreach(scc_graph->ctx, scc_graph->edge_table[i],
    297 			&extract_dst, &data) < 0)
    298 		goto error;
    299 	if (isl_sort(next, n_next, sizeof(int), &cmp_int, NULL) < 0)
    300 		goto error;
    301 	return next;
    302 error:
    303 	free(next);
    304 	return NULL;
    305 }
    306 
    307 /* Internal data structure for foreach_reachable.
    308  *
    309  * "scc_graph" is the SCC graph being visited.
    310  * "fn" is the function that needs to be called on each reachable node.
    311  * "user" is the user argument to "fn".
    312  */
    313 struct isl_foreach_reachable_data {
    314 	struct isl_scc_graph *scc_graph;
    315 	isl_bool (*fn)(int pos, void *user);
    316 	void *user;
    317 };
    318 
    319 static isl_stat foreach_reachable(struct isl_foreach_reachable_data *data,
    320 	int pos);
    321 
    322 /* isl_hash_table_foreach callback for calling data->fn on each SCC
    323  * reachable from the SCC encoded in "entry",
    324  * continuing from an SCC as long as data->fn returns isl_bool_true.
    325  */
    326 static isl_stat recurse_foreach_reachable(void **entry, void *user)
    327 {
    328 	struct isl_foreach_reachable_data *data = user;
    329 	int pos;
    330 	isl_bool more;
    331 
    332 	pos = isl_scc_graph_local_index(data->scc_graph, *entry);
    333 	more = data->fn(pos, data->user);
    334 	if (more < 0)
    335 		return isl_stat_error;
    336 	if (!more)
    337 		return isl_stat_ok;
    338 
    339 	return foreach_reachable(data, pos);
    340 }
    341 
    342 /* Call data->fn on each SCC reachable from the SCC with local index "pos",
    343  * continuing from an SCC as long as data->fn returns isl_bool_true.
    344  *
    345  * Handle chains directly and recurse when an SCC has more than one
    346  * outgoing edge.
    347  */
    348 static isl_stat foreach_reachable(struct isl_foreach_reachable_data *data,
    349 	int pos)
    350 {
    351 	isl_ctx *ctx;
    352 	struct isl_hash_table **edge_table = data->scc_graph->edge_table;
    353 
    354 	while (edge_table[pos]->n == 1) {
    355 		struct isl_hash_table_entry *entry;
    356 		isl_bool more;
    357 
    358 		entry = isl_hash_table_first(edge_table[pos]);
    359 		pos = isl_scc_graph_local_index(data->scc_graph, entry->data);
    360 		more = data->fn(pos, data->user);
    361 		if (more < 0)
    362 			return isl_stat_error;
    363 		if (!more)
    364 			return isl_stat_ok;
    365 	}
    366 
    367 	if (edge_table[pos]->n == 0)
    368 		return isl_stat_ok;
    369 
    370 	ctx = data->scc_graph->ctx;
    371 	return isl_hash_table_foreach(ctx, edge_table[pos],
    372 					&recurse_foreach_reachable, data);
    373 }
    374 
    375 /* If there is an edge from data->src to "pos", then remove it.
    376  * Return isl_bool_true if descendants of "pos" still need to be considered.
    377  *
    378  * Descendants only need to be considered if no edge is removed.
    379  */
    380 static isl_bool elim_or_next(int pos, void *user)
    381 {
    382 	struct isl_edge_src *data = user;
    383 	struct isl_scc_graph *scc_graph = data->scc_graph;
    384 	isl_bool removed;
    385 
    386 	removed = isl_scc_graph_remove_edge(scc_graph, data->src, pos);
    387 	return isl_bool_not(removed);
    388 }
    389 
    390 /* Remove transitive edges from "scc_graph".
    391  *
    392  * Consider the SCC nodes "i" in reverse topological order.
    393  * If there is more than one edge emanating from a node,
    394  * then eliminate the edges to those nodes that can also be reached
    395  * through an edge to a node with a smaller index.
    396  * In particular, consider all but the last next nodes "next[j]"
    397  * in reverse topological order.  If any node "k" can be reached
    398  * from such a node for which there is also an edge from "i"
    399  * then this edge can be removed because this node can also
    400  * be reached from "i" through the edge to "next[j]".
    401  * If such an edge is removed, then any further descendant of "k"
    402  * does not need to be considered since these were already considered
    403  * for a previous "next[j]" equal to "k", or "k" is the last next node,
    404  * in which case there is no further node with an edge from "i".
    405  */
    406 static struct isl_scc_graph *isl_scc_graph_reduce(
    407 	struct isl_scc_graph *scc_graph)
    408 {
    409 	struct isl_edge_src elim_data;
    410 	struct isl_foreach_reachable_data data = {
    411 		.scc_graph = scc_graph,
    412 		.fn = &elim_or_next,
    413 		.user = &elim_data,
    414 	};
    415 	int i, j;
    416 
    417 	elim_data.scc_graph = scc_graph;
    418 	for (i = scc_graph->n - 3; i >= 0; --i) {
    419 		int *next;
    420 		int n_next;
    421 
    422 		n_next = scc_graph->edge_table[i]->n;
    423 		if (n_next <= 1)
    424 			continue;
    425 		next = next_nodes(scc_graph, i);
    426 		if (!next)
    427 			return isl_scc_graph_free(scc_graph);
    428 
    429 		elim_data.src = i;
    430 		for (j = n_next - 2; j >= 0; --j)
    431 			if (foreach_reachable(&data, next[j]) < 0)
    432 				break;
    433 		free(next);
    434 		if (j >= 0)
    435 			return isl_scc_graph_free(scc_graph);
    436 	}
    437 
    438 	return scc_graph;
    439 }
    440 
    441 /* Add an edge to "edge_table" between the SCCs with local indices "src" and
    442  * "dst" in "scc_graph".
    443  *
    444  * If the edge already appeared in the table, then it is simply overwritten
    445  * with the same information.
    446  */
    447 static isl_stat isl_scc_graph_add_edge(struct isl_scc_graph *scc_graph,
    448 	struct isl_hash_table **edge_table, int src, int dst)
    449 {
    450 	struct isl_hash_table_entry *edge_entry;
    451 
    452 	edge_entry =
    453 		isl_scc_graph_find_edge(scc_graph, edge_table, src, dst, 1);
    454 	if (!edge_entry)
    455 		return isl_stat_error;
    456 	edge_entry->data = &scc_graph->graph_scc[dst];
    457 
    458 	return isl_stat_ok;
    459 }
    460 
    461 /* Add an edge from "dst" to data->src
    462  * to data->scc_graph->reverse_edge_table.
    463  */
    464 static isl_stat add_reverse(void **entry, void *user)
    465 {
    466 	struct isl_edge_src *data = user;
    467 	int dst;
    468 
    469 	dst = isl_scc_graph_local_index(data->scc_graph, *entry);
    470 	return isl_scc_graph_add_edge(data->scc_graph,
    471 			data->scc_graph->reverse_edge_table, dst, data->src);
    472 }
    473 
    474 /* Add an (inverse) edge to scc_graph->reverse_edge_table
    475  * for each edge in scc_graph->edge_table.
    476  */
    477 static struct isl_scc_graph *isl_scc_graph_add_reverse_edges(
    478 	struct isl_scc_graph *scc_graph)
    479 {
    480 	struct isl_edge_src data;
    481 	isl_ctx *ctx;
    482 
    483 	if (!scc_graph)
    484 		return NULL;
    485 
    486 	ctx = scc_graph->ctx;
    487 	data.scc_graph = scc_graph;
    488 	for (data.src = 0; data.src < scc_graph->n; ++data.src) {
    489 		if (isl_hash_table_foreach(ctx, scc_graph->edge_table[data.src],
    490 				&add_reverse, &data) < 0)
    491 			return isl_scc_graph_free(scc_graph);
    492 	}
    493 	return scc_graph;
    494 }
    495 
    496 /* Given an edge in the schedule graph, add an edge between
    497  * the corresponding SCCs in "scc_graph", if they are distinct.
    498  *
    499  * This function is used to create edges in the original isl_scc_graph.
    500  * where the local SCC indices are equal to the corresponding global
    501  * indices.
    502  */
    503 static isl_stat add_scc_edge(void **entry, void *user)
    504 {
    505 	struct isl_sched_edge *edge = *entry;
    506 	struct isl_scc_graph *scc_graph = user;
    507 	int src = edge->src->scc;
    508 	int dst = edge->dst->scc;
    509 
    510 	if (src == dst)
    511 		return isl_stat_ok;
    512 
    513 	return isl_scc_graph_add_edge(scc_graph, scc_graph->edge_table,
    514 					src, dst);
    515 }
    516 
    517 /* Allocate an isl_scc_graph for ordering "n" SCCs of "graph"
    518  * with clustering information in "c".
    519  *
    520  * The caller still needs to fill in the edges.
    521  */
    522 static struct isl_scc_graph *isl_scc_graph_alloc(isl_ctx *ctx, int n,
    523 	struct isl_sched_graph *graph, struct isl_clustering *c)
    524 {
    525 	int i;
    526 	struct isl_scc_graph *scc_graph;
    527 
    528 	scc_graph = isl_alloc_type(ctx, struct isl_scc_graph);
    529 	if (!scc_graph)
    530 		return NULL;
    531 
    532 	scc_graph->ctx = ctx;
    533 	isl_ctx_ref(ctx);
    534 	scc_graph->graph = graph;
    535 	scc_graph->c = c;
    536 
    537 	scc_graph->n = n;
    538 	scc_graph->graph_scc = isl_alloc_array(ctx, int, n);
    539 	scc_graph->component = isl_alloc_array(ctx, int, n);
    540 	scc_graph->size = isl_alloc_array(ctx, int, n);
    541 	scc_graph->pos = isl_alloc_array(ctx, int, n);
    542 	scc_graph->sorted = isl_alloc_array(ctx, int, n);
    543 	scc_graph->edge_table =
    544 		isl_calloc_array(ctx, struct isl_hash_table *, n);
    545 	scc_graph->reverse_edge_table =
    546 		isl_calloc_array(ctx, struct isl_hash_table *, n);
    547 	if (!scc_graph->graph_scc || !scc_graph->component ||
    548 	    !scc_graph->size || !scc_graph->pos || !scc_graph->sorted ||
    549 	    !scc_graph->edge_table || !scc_graph->reverse_edge_table)
    550 		return isl_scc_graph_free(scc_graph);
    551 
    552 	for (i = 0; i < n; ++i) {
    553 		scc_graph->edge_table[i] = isl_hash_table_alloc(ctx, 2);
    554 		scc_graph->reverse_edge_table[i] = isl_hash_table_alloc(ctx, 2);
    555 		if (!scc_graph->edge_table[i] ||
    556 		    !scc_graph->reverse_edge_table[i])
    557 			return isl_scc_graph_free(scc_graph);
    558 	}
    559 
    560 	return scc_graph;
    561 }
    562 
    563 /* Construct an isl_scc_graph for ordering the SCCs of "graph",
    564  * where each SCC i consists of the single cluster determined
    565  * by c->scc_cluster[i].  The nodes in this cluster all have
    566  * their "scc" field set to i.
    567  *
    568  * The initial isl_scc_graph has as many SCCs as "graph" and
    569  * their local indices are the same as their indices in "graph".
    570  *
    571  * Add edges between different SCCs for each (conditional) validity edge
    572  * between nodes in those SCCs, remove transitive edges and
    573  * construct the inverse edges from the remaining forward edges.
    574  */
    575 struct isl_scc_graph *isl_scc_graph_from_sched_graph(isl_ctx *ctx,
    576 	struct isl_sched_graph *graph, struct isl_clustering *c)
    577 {
    578 	int i;
    579 	struct isl_scc_graph *scc_graph;
    580 
    581 	scc_graph = isl_scc_graph_alloc(ctx, graph->scc, graph, c);
    582 	if (!scc_graph)
    583 		return NULL;
    584 
    585 	for (i = 0; i < graph->scc; ++i)
    586 		scc_graph->graph_scc[i] = i;
    587 
    588 	if (isl_hash_table_foreach(ctx, graph->edge_table[isl_edge_validity],
    589 					&add_scc_edge, scc_graph) < 0)
    590 		return isl_scc_graph_free(scc_graph);
    591 	if (isl_hash_table_foreach(ctx,
    592 			    graph->edge_table[isl_edge_conditional_validity],
    593 			    &add_scc_edge, scc_graph) < 0)
    594 		return isl_scc_graph_free(scc_graph);
    595 
    596 	scc_graph = isl_scc_graph_reduce(scc_graph);
    597 	scc_graph = isl_scc_graph_add_reverse_edges(scc_graph);
    598 
    599 	return scc_graph;
    600 }
    601 
    602 /* Internal data structure for copy_edge.
    603  *
    604  * "scc_graph" is the original graph.
    605  * "sub" is the subgraph to which edges are being copied.
    606  * "src" is the local index in "scc_graph" of the source of the edges
    607  * currently being copied.
    608  */
    609 struct isl_copy_edge_data {
    610 	struct isl_scc_graph *scc_graph;
    611 	struct isl_scc_graph *sub;
    612 	int src;
    613 };
    614 
    615 /* isl_hash_table_foreach callback for copying the edge
    616  * from data->src to the node identified by "entry"
    617  * to data->sub, provided the two nodes belong to the same component.
    618  * Note that by construction, there are no edges between different components
    619  * in the region handled by detect_components, but there may
    620  * be edges to nodes outside this region.
    621  * The components therefore need to be initialized for all nodes
    622  * in isl_scc_graph_init_component.
    623  */
    624 static isl_stat copy_edge(void **entry, void *user)
    625 {
    626 	struct isl_copy_edge_data *data = user;
    627 	struct isl_scc_graph *scc_graph = data->scc_graph;
    628 	struct isl_scc_graph *sub = data->sub;
    629 	int dst, sub_dst, sub_src;
    630 
    631 	dst = isl_scc_graph_local_index(data->scc_graph, *entry);
    632 	if (scc_graph->component[dst] != scc_graph->component[data->src])
    633 		return isl_stat_ok;
    634 
    635 	sub_src = scc_graph->pos[data->src];
    636 	sub_dst = scc_graph->pos[dst];
    637 
    638 	return isl_scc_graph_add_edge(sub, sub->edge_table, sub_src, sub_dst);
    639 }
    640 
    641 /* Construct a subgraph of "scc_graph" for the components
    642  * consisting of the "n" SCCs with local indices in "pos".
    643  * These SCCs have the same value in scc_graph->component and
    644  * this value is different from that of any other SCC.
    645  *
    646  * The forward edges with source and destination in the component
    647  * are copied from "scc_graph".
    648  * The local index in the subgraph corresponding to a local index
    649  * in "scc_graph" is stored in scc_graph->pos for use by copy_edge().
    650  * The inverse edges are constructed directly from the forward edges.
    651  */
    652 static struct isl_scc_graph *isl_scc_graph_sub(struct isl_scc_graph *scc_graph,
    653 	int *pos, int n)
    654 {
    655 	int i;
    656 	isl_ctx *ctx;
    657 	struct isl_scc_graph *sub;
    658 	struct isl_copy_edge_data data;
    659 
    660 	if (!scc_graph)
    661 		return NULL;
    662 
    663 	ctx = scc_graph->ctx;
    664 	sub = isl_scc_graph_alloc(ctx, n, scc_graph->graph, scc_graph->c);
    665 	if (!sub)
    666 		return sub;
    667 
    668 	for (i = 0; i < n; ++i)
    669 		sub->graph_scc[i] = scc_graph->graph_scc[pos[i]];
    670 
    671 	for (i = 0; i < n; ++i)
    672 		scc_graph->pos[pos[i]] = i;
    673 
    674 	data.scc_graph = scc_graph;
    675 	data.sub = sub;
    676 	for (i = 0; i < n; ++i) {
    677 		data.src = pos[i];
    678 		if (isl_hash_table_foreach(ctx, scc_graph->edge_table[pos[i]],
    679 				&copy_edge, &data) < 0)
    680 			return isl_scc_graph_free(sub);
    681 	}
    682 
    683 	sub = isl_scc_graph_add_reverse_edges(sub);
    684 
    685 	return sub;
    686 }
    687 
    688 /* Return a union of universe domains corresponding to the nodes
    689  * in the SCC with local index "pos".
    690  */
    691 static __isl_give isl_union_set *isl_scc_graph_extract_local_scc(
    692 	struct isl_scc_graph *scc_graph, int pos)
    693 {
    694 	return isl_sched_graph_extract_scc(scc_graph->ctx, scc_graph->graph,
    695 					scc_graph->graph_scc[pos]);
    696 }
    697 
    698 /* Construct a filter corresponding to a sequence of "n" local SCC indices
    699  * determined by successive calls to "el",
    700  * add this filter to "list" and
    701  * return the result.
    702  */
    703 static __isl_give isl_union_set_list *add_scc_seq(
    704 	struct isl_scc_graph *scc_graph,
    705 	int (*el)(int i, void *user), void *user, int n,
    706 	__isl_take isl_union_set_list *list)
    707 {
    708 	int i;
    709 	isl_union_set *dom;
    710 
    711 	dom = isl_union_set_empty_ctx(scc_graph->ctx);
    712 	for (i = 0; i < n; ++i)
    713 		dom = isl_union_set_union(dom,
    714 		    isl_scc_graph_extract_local_scc(scc_graph, el(i, user)));
    715 
    716 	return isl_union_set_list_add(list, dom);
    717 }
    718 
    719 /* add_scc_seq callback that, on successive calls, returns a sequence
    720  * of local SCC indices starting at "first".
    721  */
    722 static int offset(int i, void *user)
    723 {
    724 	int *first = user;
    725 
    726 	return *first + i;
    727 }
    728 
    729 /* Construct a filter corresponding to a sequence of "n" local SCC indices
    730  * starting at "first", add this filter to "list" and return the result.
    731  */
    732 static __isl_give isl_union_set_list *isl_scc_graph_add_scc_seq(
    733 	struct isl_scc_graph *scc_graph, int first, int n,
    734 	__isl_take isl_union_set_list *list)
    735 {
    736 	return add_scc_seq(scc_graph, &offset, &first, n, list);
    737 }
    738 
    739 /* add_scc_seq callback that, on successive calls, returns the sequence
    740  * of local SCC indices in "seq".
    741  */
    742 static int at(int i, void *user)
    743 {
    744 	int *seq = user;
    745 
    746 	return seq[i];
    747 }
    748 
    749 /* Construct a filter corresponding to the sequence of "n" local SCC indices
    750  * stored in "seq", add this filter to "list" and return the result.
    751  */
    752 static __isl_give isl_union_set_list *isl_scc_graph_add_scc_indirect_seq(
    753 	struct isl_scc_graph *scc_graph, int *seq, int n,
    754 	__isl_take isl_union_set_list *list)
    755 {
    756 	return add_scc_seq(scc_graph, &at, seq, n, list);
    757 }
    758 
    759 /* Extract out a list of filters for a sequence node that splits
    760  * the graph along the SCC with local index "pos".
    761  *
    762  * The list contains (at most) three elements,
    763  * the SCCs before "pos" (in the topological order),
    764  * "pos" itself, and
    765  * the SCCs after "pos".
    766  */
    767 static __isl_give isl_union_set_list *extract_split_scc(
    768 	struct isl_scc_graph *scc_graph, int pos)
    769 {
    770 	isl_union_set *dom;
    771 	isl_union_set_list *filters;
    772 
    773 	filters = isl_union_set_list_alloc(scc_graph->ctx, 3);
    774 	if (pos > 0)
    775 		filters = isl_scc_graph_add_scc_seq(scc_graph, 0, pos, filters);
    776 	dom = isl_scc_graph_extract_local_scc(scc_graph, pos);
    777 	filters = isl_union_set_list_add(filters, dom);
    778 	if (pos + 1 < scc_graph->n)
    779 		filters = isl_scc_graph_add_scc_seq(scc_graph,
    780 				pos + 1, scc_graph->n - (pos + 1), filters);
    781 	return filters;
    782 }
    783 
    784 /* Call isl_schedule_node_compute_finish_band on the cluster
    785  * corresponding to the SCC with local index "pos".
    786  *
    787  * First obtain the corresponding SCC index in scc_graph->graph and
    788  * then obtain the corresponding cluster.
    789  */
    790 static __isl_give isl_schedule_node *isl_scc_graph_finish_band(
    791 	struct isl_scc_graph *scc_graph, __isl_take isl_schedule_node *node,
    792 	int pos)
    793 {
    794 	struct isl_clustering *c = scc_graph->c;
    795 	int cluster;
    796 
    797 	cluster = c->scc_cluster[scc_graph->graph_scc[pos]];
    798 	return isl_schedule_node_compute_finish_band(node,
    799 						&c->cluster[cluster], 0);
    800 }
    801 
    802 /* Given that the SCCs in "scc_graph" form a chain,
    803  * call isl_schedule_node_compute_finish_band on each of the clusters
    804  * in scc_graph->c and update "node" to arrange for them to be executed
    805  * in topological order.
    806  */
    807 static __isl_give isl_schedule_node *isl_scc_graph_chain(
    808 	struct isl_scc_graph *scc_graph, __isl_take isl_schedule_node *node)
    809 {
    810 	int i;
    811 	isl_union_set *dom;
    812 	isl_union_set_list *filters;
    813 
    814 	filters = isl_union_set_list_alloc(scc_graph->ctx, scc_graph->n);
    815 	for (i = 0; i < scc_graph->n; ++i) {
    816 		dom = isl_scc_graph_extract_local_scc(scc_graph, i);
    817 		filters = isl_union_set_list_add(filters, dom);
    818 	}
    819 
    820 	node = isl_schedule_node_insert_sequence(node, filters);
    821 
    822 	for (i = 0; i < scc_graph->n; ++i) {
    823 		node = isl_schedule_node_grandchild(node, i, 0);
    824 		node = isl_scc_graph_finish_band(scc_graph, node, i);
    825 		node = isl_schedule_node_grandparent(node);
    826 	}
    827 
    828 	return node;
    829 }
    830 
    831 /* Recursively call isl_scc_graph_decompose on a subgraph
    832  * consisting of the "n" SCCs with local indices in "pos".
    833  *
    834  * If this component contains only a single SCC,
    835  * then there is no need for a further recursion and
    836  * isl_schedule_node_compute_finish_band can be called directly.
    837  */
    838 static __isl_give isl_schedule_node *recurse(struct isl_scc_graph *scc_graph,
    839 	int *pos, int n, __isl_take isl_schedule_node *node)
    840 {
    841 	struct isl_scc_graph *sub;
    842 
    843 	if (n == 1)
    844 		return isl_scc_graph_finish_band(scc_graph, node, pos[0]);
    845 
    846 	sub = isl_scc_graph_sub(scc_graph, pos, n);
    847 	if (!sub)
    848 		return isl_schedule_node_free(node);
    849 	node = isl_scc_graph_decompose(sub, node);
    850 	isl_scc_graph_free(sub);
    851 
    852 	return node;
    853 }
    854 
    855 /* Initialize the component field of "scc_graph".
    856  * Initially, each SCC belongs to its own single-element component.
    857  *
    858  * Note that the SCC on which isl_scc_graph_decompose performs a split
    859  * also needs to be assigned a component because the components
    860  * are also used in copy_edge to extract a subgraph.
    861  */
    862 static void isl_scc_graph_init_component(struct isl_scc_graph *scc_graph)
    863 {
    864 	int i;
    865 
    866 	for (i = 0; i < scc_graph->n; ++i)
    867 		scc_graph->component[i] = i;
    868 }
    869 
    870 /* Set the component of "a" to be the same as that of "b" and
    871  * return the original component of "a".
    872  */
    873 static int assign(int *component, int a, int b)
    874 {
    875 	int t;
    876 
    877 	t = component[a];
    878 	component[a] = component[b];
    879 	return t;
    880 }
    881 
    882 /* Merge the components containing the SCCs with indices "a" and "b".
    883  *
    884  * If "a" and "b" already belong to the same component, then nothing
    885  * needs to be done.
    886  * Otherwise, make sure both point to the same component.
    887  * In particular, use the SCC in the component entries with the smallest index.
    888  * If the other SCC was the first of its component then the entire
    889  * component now (eventually) points to the other component.
    890  * Otherwise, the earlier parts of the component still need
    891  * to be merged with the other component.
    892  *
    893  * At each stage, either a or b is replaced by either a or b itself,
    894  * in which case the merging terminates because a and b already
    895  * point to the same component, or an SCC index with a smaller value.
    896  * This ensures the merging terminates at some point.
    897  */
    898 static void isl_scc_graph_merge_src_dst(struct isl_scc_graph *scc_graph,
    899 	int a, int b)
    900 {
    901 	int *component = scc_graph->component;
    902 
    903 	while (component[a] != component[b]) {
    904 		if (component[a] < component[b])
    905 			b = assign(component, b, a);
    906 		else
    907 			a = assign(component, a, b);
    908 	}
    909 }
    910 
    911 /* Internal data structure for isl_scc_graph_merge_components.
    912  *
    913  * "scc_graph" is the SCC graph containing the edges.
    914  * "src" is the local index of the source SCC.
    915  * "end" is the local index beyond the sequence being considered.
    916  */
    917 struct isl_merge_src_dst_data {
    918 	struct isl_scc_graph *scc_graph;
    919 	int src;
    920 	int end;
    921 };
    922 
    923 /* isl_hash_table_foreach callback for merging the components
    924  * of data->src and the node represented by "entry", provided
    925  * it is within the sequence being considered.
    926  */
    927 static isl_stat merge_src_dst(void **entry, void *user)
    928 {
    929 	struct isl_merge_src_dst_data *data = user;
    930 	int dst;
    931 
    932 	dst = isl_scc_graph_local_index(data->scc_graph, *entry);
    933 	if (dst >= data->end)
    934 		return isl_stat_ok;
    935 
    936 	isl_scc_graph_merge_src_dst(data->scc_graph, data->src, dst);
    937 
    938 	return isl_stat_ok;
    939 }
    940 
    941 /* Merge components of the "n" SCCs starting at "first" that are connected
    942  * by an edge.
    943  */
    944 static isl_stat isl_scc_graph_merge_components(struct isl_scc_graph *scc_graph,
    945 	int first, int n)
    946 {
    947 	int i;
    948 	struct isl_merge_src_dst_data data;
    949 	isl_ctx *ctx = scc_graph->ctx;
    950 
    951 	data.scc_graph = scc_graph;
    952 	data.end = first + n;
    953 	for (i = 0; i < n; ++i) {
    954 		data.src = first + i;
    955 		if (isl_hash_table_foreach(ctx, scc_graph->edge_table[data.src],
    956 				&merge_src_dst, &data) < 0)
    957 			return isl_stat_error;
    958 	}
    959 
    960 	return isl_stat_ok;
    961 }
    962 
    963 /* Sort the "n" local SCC indices starting at "first" according
    964  * to component, store them in scc_graph->sorted and
    965  * return the number of components.
    966  * The sizes of the components are stored in scc_graph->size.
    967  * Only positions starting at "first" are used within
    968  * scc_graph->sorted and scc_graph->size.
    969  *
    970  * The representation of the components is first normalized.
    971  * The normalization ensures that each SCC in a component
    972  * points to the first SCC in the component, whereas
    973  * before this function is called, some SCCs may only point
    974  * to some other SCC in the component with a smaller index.
    975  *
    976  * Internally, the sizes of the components are first stored
    977  * at indices corresponding to the first SCC in the component.
    978  * They are subsequently moved into consecutive positions
    979  * while reordering the local indices.
    980  * This reordering is performed by first determining the position
    981  * of the first SCC in each component and
    982  * then putting the "n" local indices in the right position
    983  * according to the component, preserving the topological order
    984  * within each component.
    985  */
    986 static int isl_scc_graph_sort_components(struct isl_scc_graph *scc_graph,
    987 	int first, int n)
    988 {
    989 	int i, j;
    990 	int sum;
    991 	int *component = scc_graph->component;
    992 	int *size = scc_graph->size;
    993 	int *pos = scc_graph->pos;
    994 	int *sorted = scc_graph->sorted;
    995 	int n_component;
    996 
    997 	n_component = 0;
    998 	for (i = 0; i < n; ++i) {
    999 		size[first + i] = 0;
   1000 		if (component[first + i] == first + i)
   1001 			n_component++;
   1002 		else
   1003 			component[first + i] = component[component[first + i]];
   1004 		size[component[first + i]]++;
   1005 	}
   1006 
   1007 	sum = first;
   1008 	i = 0;
   1009 	for (j = 0; j < n_component; ++j) {
   1010 		while (size[first + i] == 0)
   1011 			++i;
   1012 		pos[first + i] = sum;
   1013 		sum += size[first + i];
   1014 		size[first + j] = size[first + i++];
   1015 	}
   1016 	for (i = 0; i < n; ++i)
   1017 		sorted[pos[component[first + i]]++] = first + i;
   1018 
   1019 	return n_component;
   1020 }
   1021 
   1022 /* Extract out a list of filters for a set node that splits up
   1023  * the graph into "n_component" components.
   1024  * "first" is the initial position in "scc_graph" where information
   1025  * about the components is stored.
   1026  * In particular, the first "n_component" entries of scc_graph->size
   1027  * at this position contain the number of SCCs in each component.
   1028  * The entries of scc_graph->sorted starting at "first"
   1029  * contain the local indices of the SCC in those components.
   1030  */
   1031 static __isl_give isl_union_set_list *extract_components(
   1032 	struct isl_scc_graph *scc_graph, int first, int n_component)
   1033 {
   1034 	int i;
   1035 	int sum;
   1036 	int *size = scc_graph->size;
   1037 	int *sorted = scc_graph->sorted;
   1038 	isl_ctx *ctx = scc_graph->ctx;
   1039 	isl_union_set_list *filters;
   1040 
   1041 	filters = isl_union_set_list_alloc(ctx, n_component);
   1042 	sum = first;
   1043 	for (i = 0; i < n_component; ++i) {
   1044 		int n;
   1045 
   1046 		n = size[first + i];
   1047 		filters = isl_scc_graph_add_scc_indirect_seq(scc_graph,
   1048 			&sorted[sum], n, filters);
   1049 		sum += n;
   1050 	}
   1051 
   1052 	return filters;
   1053 }
   1054 
   1055 /* Detect components in the subgraph consisting of the "n" SCCs
   1056  * with local index starting at "first" and further decompose them,
   1057  * calling isl_schedule_node_compute_finish_band on each
   1058  * of the corresponding clusters.
   1059  *
   1060  * If there is only one SCC, then isl_schedule_node_compute_finish_band
   1061  * can be called directly.
   1062  * Otherwise, determine the components and rearrange the local indices
   1063  * according to component, but preserving the topological order within
   1064  * each component, in scc_graph->sorted.  The sizes of the components
   1065  * are stored in scc_graph->size.
   1066  * If there is only one component, it can be further decomposed
   1067  * directly by a call to recurse().
   1068  * Otherwise, introduce a set node separating the components and
   1069  * call recurse() on each component separately.
   1070  */
   1071 static __isl_give isl_schedule_node *detect_components(
   1072 	struct isl_scc_graph *scc_graph, int first, int n,
   1073 	__isl_take isl_schedule_node *node)
   1074 {
   1075 	int i;
   1076 	int *size = scc_graph->size;
   1077 	int *sorted = scc_graph->sorted;
   1078 	int n_component;
   1079 	int sum;
   1080 	isl_union_set_list *filters;
   1081 
   1082 	if (n == 1)
   1083 		return isl_scc_graph_finish_band(scc_graph, node, first);
   1084 
   1085 	if (isl_scc_graph_merge_components(scc_graph, first, n) < 0)
   1086 		return isl_schedule_node_free(node);
   1087 
   1088 	n_component = isl_scc_graph_sort_components(scc_graph, first, n);
   1089 	if (n_component == 1)
   1090 		return recurse(scc_graph, &sorted[first], n, node);
   1091 
   1092 	filters = extract_components(scc_graph, first, n_component);
   1093 	node = isl_schedule_node_insert_set(node, filters);
   1094 
   1095 	sum = first;
   1096 	for (i = 0; i < n_component; ++i) {
   1097 		int n;
   1098 
   1099 		n = size[first + i];
   1100 		node = isl_schedule_node_grandchild(node, i, 0);
   1101 		node = recurse(scc_graph, &sorted[sum], n, node);
   1102 		node = isl_schedule_node_grandparent(node);
   1103 		sum += n;
   1104 	}
   1105 
   1106 	return node;
   1107 }
   1108 
   1109 /* Given a sequence node "node", where the filter at position "child"
   1110  * represents the "n" SCCs with local index starting at "first",
   1111  * detect components in this subgraph and further decompose them,
   1112  * calling isl_schedule_node_compute_finish_band on each
   1113  * of the corresponding clusters.
   1114  */
   1115 static __isl_give isl_schedule_node *detect_components_at(
   1116 	struct isl_scc_graph *scc_graph, int first, int n,
   1117 	__isl_take isl_schedule_node *node, int child)
   1118 {
   1119 	node = isl_schedule_node_grandchild(node, child, 0);
   1120 	node = detect_components(scc_graph, first, n, node);
   1121 	node = isl_schedule_node_grandparent(node);
   1122 
   1123 	return node;
   1124 }
   1125 
   1126 /* Return the local index of an SCC on which to split "scc_graph".
   1127  * Return scc_graph->n if no suitable split SCC can be found.
   1128  *
   1129  * In particular, look for an SCC that is involved in the largest number
   1130  * of edges.  Splitting the graph on such an SCC has the highest chance
   1131  * of exposing independent SCCs in the remaining part(s).
   1132  * There is no point in splitting a chain of nodes,
   1133  * so return scc_graph->n if the entire graph forms a chain.
   1134  */
   1135 static int best_split(struct isl_scc_graph *scc_graph)
   1136 {
   1137 	int i;
   1138 	int split = scc_graph->n;
   1139 	int split_score = -1;
   1140 
   1141 	for (i = 0; i < scc_graph->n; ++i) {
   1142 		int n_fwd, n_bwd;
   1143 
   1144 		n_fwd = scc_graph->edge_table[i]->n;
   1145 		n_bwd = scc_graph->reverse_edge_table[i]->n;
   1146 		if (n_fwd <= 1 && n_bwd <= 1)
   1147 			continue;
   1148 		if (split_score >= n_fwd + n_bwd)
   1149 			continue;
   1150 		split = i;
   1151 		split_score = n_fwd + n_bwd;
   1152 	}
   1153 
   1154 	return split;
   1155 }
   1156 
   1157 /* Call isl_schedule_node_compute_finish_band on each of the clusters
   1158  * in scc_graph->c and update "node" to arrange for them to be executed
   1159  * in an order possibly involving set nodes that generalizes
   1160  * the topological order determined by the scc fields of the nodes
   1161  * in scc_graph->graph.
   1162  *
   1163  * First try and find a suitable SCC on which to split the graph.
   1164  * If no such SCC can be found then the graph forms a chain and
   1165  * it is handled as such.
   1166  * Otherwise, break up the graph into (at most) three parts,
   1167  * the SCCs before the selected SCC (in the topological order),
   1168  * the selected SCC itself, and
   1169  * the SCCs after the selected SCC.
   1170  * The first and last part (if they exist) are decomposed recursively and
   1171  * the three parts are combined in a sequence.
   1172  *
   1173  * Since the outermost node of the recursive pieces may also be a sequence,
   1174  * these potential sequence nodes are spliced into the top-level sequence node.
   1175  */
   1176 __isl_give isl_schedule_node *isl_scc_graph_decompose(
   1177 	struct isl_scc_graph *scc_graph, __isl_take isl_schedule_node *node)
   1178 {
   1179 	int i;
   1180 	int split;
   1181 	isl_union_set_list *filters;
   1182 
   1183 	if (!scc_graph)
   1184 		return isl_schedule_node_free(node);
   1185 
   1186 	split = best_split(scc_graph);
   1187 
   1188 	if (split == scc_graph->n)
   1189 		return isl_scc_graph_chain(scc_graph, node);
   1190 
   1191 	filters = extract_split_scc(scc_graph, split);
   1192 	node = isl_schedule_node_insert_sequence(node, filters);
   1193 
   1194 	isl_scc_graph_init_component(scc_graph);
   1195 
   1196 	i = 0;
   1197 	if (split > 0)
   1198 		node = detect_components_at(scc_graph, 0, split, node, i++);
   1199 	node = isl_schedule_node_grandchild(node, i++, 0);
   1200 	node = isl_scc_graph_finish_band(scc_graph, node, split);
   1201 	node = isl_schedule_node_grandparent(node);
   1202 	if (split + 1 < scc_graph->n)
   1203 		node = detect_components_at(scc_graph,
   1204 			    split + 1, scc_graph->n - (split + 1), node, i++);
   1205 
   1206 	node = isl_schedule_node_sequence_splice_children(node);
   1207 
   1208 	return node;
   1209 }
   1210