2 * Copyright 2021 Sven Verdoolaege
4 * Use of this software is governed by the MIT license
6 * Written by Sven Verdoolaege
12 #include <isl/schedule_node.h>
13 #include <isl/union_set.h>
15 #include "isl_hash_private.h"
16 #include "isl_scheduler_scc.h"
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.
24 * "graph" is the original schedule graph.
25 * "c" contains the clustering information.
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.
33 * "component" contains the component to which an SCC belongs,
34 * where the component is represented by the index of the first SCC
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.
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.
52 * "sorted" contains the (possibly) reordered local indices,
53 * sorted per component. Within each component, the original
54 * topological order is preserved.
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.
63 struct isl_scc_graph
{
65 struct isl_sched_graph
*graph
;
66 struct isl_clustering
*c
;
74 struct isl_hash_table
**edge_table
;
75 struct isl_hash_table
**reverse_edge_table
;
78 /* The source SCC of a collection of edges.
80 * "scc_graph" is the SCC graph containing the edges.
81 * "src" is the local index of the source SCC.
84 struct isl_scc_graph
*scc_graph
;
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.
92 static isl_stat
print_edge(void **entry
, void *user
)
97 fprintf(stderr
, "%d -> %d; ", *src
, *dst
);
102 /* Print some debugging information about "scc_graph".
104 * In particular, print the nodes and the edges (both forward and backward).
106 void isl_scc_graph_dump(struct isl_scc_graph
*scc_graph
)
114 ctx
= scc_graph
->ctx
;
115 for (i
= 0; i
< scc_graph
->n
; ++i
) {
117 fprintf(stderr
, ", ");
118 fprintf(stderr
, "%d", scc_graph
->graph_scc
[i
]);
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
]);
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
]);
130 fprintf(stderr
, "\n");
133 /* Free all memory allocated for "scc_graph" and return NULL.
135 struct isl_scc_graph
*isl_scc_graph_free(struct isl_scc_graph
*scc_graph
)
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
]);
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
]);
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
);
166 /* Return an encoding of the local SCC index "pos" in "scc_graph"
168 * In particular, return a pointer to the corresponding entry
169 * in scc_graph->graph_scc.
171 static void *isl_scc_graph_encode_local_index(struct isl_scc_graph
*scc_graph
,
174 return &scc_graph
->graph_scc
[pos
];
177 /* Return the local SCC index in "scc_graph" corresponding
178 * to the "data" encoding in the edge table.
180 static int isl_scc_graph_local_index(struct isl_scc_graph
*scc_graph
, int *data
)
182 return data
- &scc_graph
->graph_scc
[0];
185 /* isl_hash_table_find callback to check whether the given entry
186 * refers to an SCC encoded as "val".
188 static isl_bool
is_scc_node(const void *entry
, const void *val
)
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.
198 * The destination of the edge is encoded as a pointer
199 * to the corresponding entry in scc_graph->graph_scc.
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
)
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
);
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.
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.
224 static isl_bool
isl_scc_graph_remove_edge(struct isl_scc_graph
*scc_graph
,
228 struct isl_hash_table_entry
*edge_entry
;
230 edge_entry
= isl_scc_graph_find_edge(scc_graph
, scc_graph
->edge_table
,
232 if (edge_entry
== isl_hash_table_entry_none
)
233 return isl_bool_false
;
235 return isl_bool_error
;
237 ctx
= scc_graph
->ctx
;
238 isl_hash_table_remove(ctx
, scc_graph
->edge_table
[src
], edge_entry
);
240 return isl_bool_true
;
243 /* Internal data structure used by next_nodes.
245 * "scc_graph" is the SCC graph.
246 * "next" collects the next nodes.
247 * "n" is the number of next nodes already collected.
249 struct isl_extract_dst_data
{
250 struct isl_scc_graph
*scc_graph
;
255 /* Given an entry in the edge table, add the corresponding
256 * target local SCC index to data->next.
258 static isl_stat
extract_dst(void **entry
, void *user
)
261 struct isl_extract_dst_data
*data
= user
;
263 data
->next
[data
->n
++] = isl_scc_graph_local_index(data
->scc_graph
, dst
);
268 /* isl_sort callback for sorting integers in increasing order.
270 static int cmp_int(const void *a
, const void *b
, void *data
)
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.
283 static int *next_nodes(struct isl_scc_graph
*scc_graph
, int i
)
285 struct isl_extract_dst_data data
;
289 n_next
= scc_graph
->edge_table
[i
]->n
;
290 next
= isl_alloc_array(scc_graph
->ctx
, int, n_next
);
293 data
.scc_graph
= scc_graph
;
296 if (isl_hash_table_foreach(scc_graph
->ctx
, scc_graph
->edge_table
[i
],
297 &extract_dst
, &data
) < 0)
299 if (isl_sort(next
, n_next
, sizeof(int), &cmp_int
, NULL
) < 0)
307 /* Internal data structure for foreach_reachable.
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".
313 struct isl_foreach_reachable_data
{
314 struct isl_scc_graph
*scc_graph
;
315 isl_bool (*fn
)(int pos
, void *user
);
319 static isl_stat
foreach_reachable(struct isl_foreach_reachable_data
*data
,
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.
326 static isl_stat
recurse_foreach_reachable(void **entry
, void *user
)
328 struct isl_foreach_reachable_data
*data
= user
;
332 pos
= isl_scc_graph_local_index(data
->scc_graph
, *entry
);
333 more
= data
->fn(pos
, data
->user
);
335 return isl_stat_error
;
339 return foreach_reachable(data
, pos
);
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.
345 * Handle chains directly and recurse when an SCC has more than one
348 static isl_stat
foreach_reachable(struct isl_foreach_reachable_data
*data
,
352 struct isl_hash_table
**edge_table
= data
->scc_graph
->edge_table
;
354 while (edge_table
[pos
]->n
== 1) {
355 struct isl_hash_table_entry
*entry
;
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
);
362 return isl_stat_error
;
367 if (edge_table
[pos
]->n
== 0)
370 ctx
= data
->scc_graph
->ctx
;
371 return isl_hash_table_foreach(ctx
, edge_table
[pos
],
372 &recurse_foreach_reachable
, data
);
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.
378 * Descendants only need to be considered if no edge is removed.
380 static isl_bool
elim_or_next(int pos
, void *user
)
382 struct isl_edge_src
*data
= user
;
383 struct isl_scc_graph
*scc_graph
= data
->scc_graph
;
386 removed
= isl_scc_graph_remove_edge(scc_graph
, data
->src
, pos
);
387 return isl_bool_not(removed
);
390 /* Remove transitive edges from "scc_graph".
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".
406 static struct isl_scc_graph
*isl_scc_graph_reduce(
407 struct isl_scc_graph
*scc_graph
)
409 struct isl_edge_src elim_data
;
410 struct isl_foreach_reachable_data data
= {
411 .scc_graph
= scc_graph
,
417 elim_data
.scc_graph
= scc_graph
;
418 for (i
= scc_graph
->n
- 3; i
>= 0; --i
) {
422 n_next
= scc_graph
->edge_table
[i
]->n
;
425 next
= next_nodes(scc_graph
, i
);
427 return isl_scc_graph_free(scc_graph
);
430 for (j
= n_next
- 2; j
>= 0; --j
)
431 if (foreach_reachable(&data
, next
[j
]) < 0)
435 return isl_scc_graph_free(scc_graph
);
441 /* Add an edge to "edge_table" between the SCCs with local indices "src" and
442 * "dst" in "scc_graph".
444 * If the edge already appeared in the table, then it is simply overwritten
445 * with the same information.
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
)
450 struct isl_hash_table_entry
*edge_entry
;
453 isl_scc_graph_find_edge(scc_graph
, edge_table
, src
, dst
, 1);
455 return isl_stat_error
;
456 edge_entry
->data
= &scc_graph
->graph_scc
[dst
];
461 /* Add an edge from "dst" to data->src
462 * to data->scc_graph->reverse_edge_table.
464 static isl_stat
add_reverse(void **entry
, void *user
)
466 struct isl_edge_src
*data
= user
;
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
);
474 /* Add an (inverse) edge to scc_graph->reverse_edge_table
475 * for each edge in scc_graph->edge_table.
477 static struct isl_scc_graph
*isl_scc_graph_add_reverse_edges(
478 struct isl_scc_graph
*scc_graph
)
480 struct isl_edge_src data
;
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
);
496 /* Given an edge in the schedule graph, add an edge between
497 * the corresponding SCCs in "scc_graph", if they are distinct.
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
503 static isl_stat
add_scc_edge(void **entry
, void *user
)
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
;
513 return isl_scc_graph_add_edge(scc_graph
, scc_graph
->edge_table
,
517 /* Allocate an isl_scc_graph for ordering "n" SCCs of "graph"
518 * with clustering information in "c".
520 * The caller still needs to fill in the edges.
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
)
526 struct isl_scc_graph
*scc_graph
;
528 scc_graph
= isl_alloc_type(ctx
, struct isl_scc_graph
);
532 scc_graph
->ctx
= ctx
;
534 scc_graph
->graph
= graph
;
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
);
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
);
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.
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".
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.
575 struct isl_scc_graph
*isl_scc_graph_from_sched_graph(isl_ctx
*ctx
,
576 struct isl_sched_graph
*graph
, struct isl_clustering
*c
)
579 struct isl_scc_graph
*scc_graph
;
581 scc_graph
= isl_scc_graph_alloc(ctx
, graph
->scc
, graph
, c
);
585 for (i
= 0; i
< graph
->scc
; ++i
)
586 scc_graph
->graph_scc
[i
] = i
;
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
);
596 scc_graph
= isl_scc_graph_reduce(scc_graph
);
597 scc_graph
= isl_scc_graph_add_reverse_edges(scc_graph
);
602 /* Internal data structure for copy_edge.
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.
609 struct isl_copy_edge_data
{
610 struct isl_scc_graph
*scc_graph
;
611 struct isl_scc_graph
*sub
;
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.
624 static isl_stat
copy_edge(void **entry
, void *user
)
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
;
631 dst
= isl_scc_graph_local_index(data
->scc_graph
, *entry
);
632 if (scc_graph
->component
[dst
] != scc_graph
->component
[data
->src
])
635 sub_src
= scc_graph
->pos
[data
->src
];
636 sub_dst
= scc_graph
->pos
[dst
];
638 return isl_scc_graph_add_edge(sub
, sub
->edge_table
, sub_src
, sub_dst
);
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.
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.
652 static struct isl_scc_graph
*isl_scc_graph_sub(struct isl_scc_graph
*scc_graph
,
657 struct isl_scc_graph
*sub
;
658 struct isl_copy_edge_data data
;
663 ctx
= scc_graph
->ctx
;
664 sub
= isl_scc_graph_alloc(ctx
, n
, scc_graph
->graph
, scc_graph
->c
);
668 for (i
= 0; i
< n
; ++i
)
669 sub
->graph_scc
[i
] = scc_graph
->graph_scc
[pos
[i
]];
671 for (i
= 0; i
< n
; ++i
)
672 scc_graph
->pos
[pos
[i
]] = i
;
674 data
.scc_graph
= scc_graph
;
676 for (i
= 0; i
< n
; ++i
) {
678 if (isl_hash_table_foreach(ctx
, scc_graph
->edge_table
[pos
[i
]],
679 ©_edge
, &data
) < 0)
680 return isl_scc_graph_free(sub
);
683 sub
= isl_scc_graph_add_reverse_edges(sub
);
688 /* Return a union of universe domains corresponding to the nodes
689 * in the SCC with local index "pos".
691 static __isl_give isl_union_set
*isl_scc_graph_extract_local_scc(
692 struct isl_scc_graph
*scc_graph
, int pos
)
694 return isl_sched_graph_extract_scc(scc_graph
->ctx
, scc_graph
->graph
,
695 scc_graph
->graph_scc
[pos
]);
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
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
)
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
)));
716 return isl_union_set_list_add(list
, dom
);
719 /* add_scc_seq callback that, on successive calls, returns a sequence
720 * of local SCC indices starting at "first".
722 static int offset(int i
, void *user
)
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.
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
)
736 return add_scc_seq(scc_graph
, &offset
, &first
, n
, list
);
739 /* add_scc_seq callback that, on successive calls, returns the sequence
740 * of local SCC indices in "seq".
742 static int at(int i
, void *user
)
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.
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
)
756 return add_scc_seq(scc_graph
, &at
, seq
, n
, list
);
759 /* Extract out a list of filters for a sequence node that splits
760 * the graph along the SCC with local index "pos".
762 * The list contains (at most) three elements,
763 * the SCCs before "pos" (in the topological order),
765 * the SCCs after "pos".
767 static __isl_give isl_union_set_list
*extract_split_scc(
768 struct isl_scc_graph
*scc_graph
, int pos
)
771 isl_union_set_list
*filters
;
773 filters
= isl_union_set_list_alloc(scc_graph
->ctx
, 3);
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
);
784 /* Call isl_schedule_node_compute_finish_band on the cluster
785 * corresponding to the SCC with local index "pos".
787 * First obtain the corresponding SCC index in scc_graph->graph and
788 * then obtain the corresponding cluster.
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
,
794 struct isl_clustering
*c
= scc_graph
->c
;
797 cluster
= c
->scc_cluster
[scc_graph
->graph_scc
[pos
]];
798 return isl_schedule_node_compute_finish_band(node
,
799 &c
->cluster
[cluster
], 0);
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.
807 static __isl_give isl_schedule_node
*isl_scc_graph_chain(
808 struct isl_scc_graph
*scc_graph
, __isl_take isl_schedule_node
*node
)
812 isl_union_set_list
*filters
;
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
);
820 node
= isl_schedule_node_insert_sequence(node
, filters
);
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
);
831 /* Recursively call isl_scc_graph_decompose on a subgraph
832 * consisting of the "n" SCCs with local indices in "pos".
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.
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
)
841 struct isl_scc_graph
*sub
;
844 return isl_scc_graph_finish_band(scc_graph
, node
, pos
[0]);
846 sub
= isl_scc_graph_sub(scc_graph
, pos
, n
);
848 return isl_schedule_node_free(node
);
849 node
= isl_scc_graph_decompose(sub
, node
);
850 isl_scc_graph_free(sub
);
855 /* Initialize the component field of "scc_graph".
856 * Initially, each SCC belongs to its own single-element component.
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.
862 static void isl_scc_graph_init_component(struct isl_scc_graph
*scc_graph
)
866 for (i
= 0; i
< scc_graph
->n
; ++i
)
867 scc_graph
->component
[i
] = i
;
870 /* Set the component of "a" to be the same as that of "b" and
871 * return the original component of "a".
873 static int assign(int *component
, int a
, int b
)
878 component
[a
] = component
[b
];
882 /* Merge the components containing the SCCs with indices "a" and "b".
884 * If "a" and "b" already belong to the same component, then nothing
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.
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.
898 static void isl_scc_graph_merge_src_dst(struct isl_scc_graph
*scc_graph
,
901 int *component
= scc_graph
->component
;
903 while (component
[a
] != component
[b
]) {
904 if (component
[a
] < component
[b
])
905 b
= assign(component
, b
, a
);
907 a
= assign(component
, a
, b
);
911 /* Internal data structure for isl_scc_graph_merge_components.
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.
917 struct isl_merge_src_dst_data
{
918 struct isl_scc_graph
*scc_graph
;
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.
927 static isl_stat
merge_src_dst(void **entry
, void *user
)
929 struct isl_merge_src_dst_data
*data
= user
;
932 dst
= isl_scc_graph_local_index(data
->scc_graph
, *entry
);
933 if (dst
>= data
->end
)
936 isl_scc_graph_merge_src_dst(data
->scc_graph
, data
->src
, dst
);
941 /* Merge components of the "n" SCCs starting at "first" that are connected
944 static isl_stat
isl_scc_graph_merge_components(struct isl_scc_graph
*scc_graph
,
948 struct isl_merge_src_dst_data data
;
949 isl_ctx
*ctx
= scc_graph
->ctx
;
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
;
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.
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.
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.
986 static int isl_scc_graph_sort_components(struct isl_scc_graph
*scc_graph
,
991 int *component
= scc_graph
->component
;
992 int *size
= scc_graph
->size
;
993 int *pos
= scc_graph
->pos
;
994 int *sorted
= scc_graph
->sorted
;
998 for (i
= 0; i
< n
; ++i
) {
1000 if (component
[first
+ i
] == first
+ i
)
1003 component
[first
+ i
] = component
[component
[first
+ i
]];
1004 size
[component
[first
+ i
]]++;
1009 for (j
= 0; j
< n_component
; ++j
) {
1010 while (size
[first
+ i
] == 0)
1012 pos
[first
+ i
] = sum
;
1013 sum
+= size
[first
+ i
];
1014 size
[first
+ j
] = size
[first
+ i
++];
1016 for (i
= 0; i
< n
; ++i
)
1017 sorted
[pos
[component
[first
+ i
]]++] = first
+ i
;
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.
1031 static __isl_give isl_union_set_list
*extract_components(
1032 struct isl_scc_graph
*scc_graph
, int first
, int n_component
)
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
;
1041 filters
= isl_union_set_list_alloc(ctx
, n_component
);
1043 for (i
= 0; i
< n_component
; ++i
) {
1046 n
= size
[first
+ i
];
1047 filters
= isl_scc_graph_add_scc_indirect_seq(scc_graph
,
1048 &sorted
[sum
], n
, filters
);
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.
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.
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
)
1076 int *size
= scc_graph
->size
;
1077 int *sorted
= scc_graph
->sorted
;
1080 isl_union_set_list
*filters
;
1083 return isl_scc_graph_finish_band(scc_graph
, node
, first
);
1085 if (isl_scc_graph_merge_components(scc_graph
, first
, n
) < 0)
1086 return isl_schedule_node_free(node
);
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
);
1092 filters
= extract_components(scc_graph
, first
, n_component
);
1093 node
= isl_schedule_node_insert_set(node
, filters
);
1096 for (i
= 0; i
< n_component
; ++i
) {
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
);
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.
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
)
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
);
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.
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.
1135 static int best_split(struct isl_scc_graph
*scc_graph
)
1138 int split
= scc_graph
->n
;
1139 int split_score
= -1;
1141 for (i
= 0; i
< scc_graph
->n
; ++i
) {
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)
1148 if (split_score
>= n_fwd
+ n_bwd
)
1151 split_score
= n_fwd
+ n_bwd
;
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.
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.
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.
1176 __isl_give isl_schedule_node
*isl_scc_graph_decompose(
1177 struct isl_scc_graph
*scc_graph
, __isl_take isl_schedule_node
*node
)
1181 isl_union_set_list
*filters
;
1184 return isl_schedule_node_free(node
);
1186 split
= best_split(scc_graph
);
1188 if (split
== scc_graph
->n
)
1189 return isl_scc_graph_chain(scc_graph
, node
);
1191 filters
= extract_split_scc(scc_graph
, split
);
1192 node
= isl_schedule_node_insert_sequence(node
, filters
);
1194 isl_scc_graph_init_component(scc_graph
);
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
++);
1206 node
= isl_schedule_node_sequence_splice_children(node
);