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