isl_aff_val_on_domain: allow construction from NaN
[isl.git] / isl_scheduler_clustering.c
blob5cfa49c573f621c627ab5f9f0058d61c785465f3
1 /*
2 * Copyright 2015 Sven Verdoolaege
4 * Use of this software is governed by the MIT license
6 * Written by Sven Verdoolaege
7 */
9 #include "isl_map_private.h"
11 #include <isl/id.h>
12 #include <isl/schedule_node.h>
13 #include <isl/union_set.h>
15 #include "isl_mat_private.h"
16 #include "isl_scheduler_clustering.h"
17 #include "isl_seq.h"
18 #include "isl_tarjan.h"
20 /* Initialize the clustering data structure "c" from "graph".
22 * In particular, allocate memory, extract the SCCs from "graph"
23 * into c->scc, initialize scc_cluster and construct
24 * a band of schedule rows for each SCC.
25 * Within each SCC, there is only one SCC by definition.
26 * Each SCC initially belongs to a cluster containing only that SCC.
28 static isl_stat clustering_init(isl_ctx *ctx, struct isl_clustering *c,
29 struct isl_sched_graph *graph)
31 int i;
33 c->n = graph->scc;
34 c->scc = isl_calloc_array(ctx, struct isl_sched_graph, c->n);
35 c->cluster = isl_calloc_array(ctx, struct isl_sched_graph, c->n);
36 c->scc_cluster = isl_calloc_array(ctx, int, c->n);
37 c->scc_node = isl_calloc_array(ctx, int, c->n);
38 c->scc_in_merge = isl_calloc_array(ctx, int, c->n);
39 if (!c->scc || !c->cluster ||
40 !c->scc_cluster || !c->scc_node || !c->scc_in_merge)
41 return isl_stat_error;
43 for (i = 0; i < c->n; ++i) {
44 if (isl_sched_graph_extract_sub_graph(ctx, graph,
45 &isl_sched_node_scc_exactly,
46 &isl_sched_edge_scc_exactly,
47 i, &c->scc[i]) < 0)
48 return isl_stat_error;
49 c->scc[i].scc = 1;
50 if (isl_sched_graph_compute_maxvar(&c->scc[i]) < 0)
51 return isl_stat_error;
52 if (isl_schedule_node_compute_wcc_band(ctx, &c->scc[i]) < 0)
53 return isl_stat_error;
54 c->scc_cluster[i] = i;
57 return isl_stat_ok;
60 /* Free all memory allocated for "c".
62 static void clustering_free(isl_ctx *ctx, struct isl_clustering *c)
64 int i;
66 if (c->scc)
67 for (i = 0; i < c->n; ++i)
68 isl_sched_graph_free(ctx, &c->scc[i]);
69 free(c->scc);
70 if (c->cluster)
71 for (i = 0; i < c->n; ++i)
72 isl_sched_graph_free(ctx, &c->cluster[i]);
73 free(c->cluster);
74 free(c->scc_cluster);
75 free(c->scc_node);
76 free(c->scc_in_merge);
79 /* Should we refrain from merging the cluster in "graph" with
80 * any other cluster?
81 * In particular, is its current schedule band empty and incomplete.
83 static int bad_cluster(struct isl_sched_graph *graph)
85 return graph->n_row < graph->maxvar &&
86 graph->n_total_row == graph->band_start;
89 /* Is "edge" a proximity edge with a non-empty dependence relation?
91 static isl_bool is_non_empty_proximity(struct isl_sched_edge *edge)
93 if (!isl_sched_edge_is_proximity(edge))
94 return isl_bool_false;
95 return isl_bool_not(isl_map_plain_is_empty(edge->map));
98 /* Return the index of an edge in "graph" that can be used to merge
99 * two clusters in "c".
100 * Return graph->n_edge if no such edge can be found.
101 * Return -1 on error.
103 * In particular, return a proximity edge between two clusters
104 * that is not marked "no_merge" and such that neither of the
105 * two clusters has an incomplete, empty band.
107 * If there are multiple such edges, then try and find the most
108 * appropriate edge to use for merging. In particular, pick the edge
109 * with the greatest weight. If there are multiple of those,
110 * then pick one with the shortest distance between
111 * the two cluster representatives.
113 static int find_proximity(struct isl_sched_graph *graph,
114 struct isl_clustering *c)
116 int i, best = graph->n_edge, best_dist, best_weight;
118 for (i = 0; i < graph->n_edge; ++i) {
119 struct isl_sched_edge *edge = &graph->edge[i];
120 int dist, weight;
121 isl_bool prox;
123 prox = is_non_empty_proximity(edge);
124 if (prox < 0)
125 return -1;
126 if (!prox)
127 continue;
128 if (edge->no_merge)
129 continue;
130 if (bad_cluster(&c->scc[edge->src->scc]) ||
131 bad_cluster(&c->scc[edge->dst->scc]))
132 continue;
133 dist = c->scc_cluster[edge->dst->scc] -
134 c->scc_cluster[edge->src->scc];
135 if (dist == 0)
136 continue;
137 weight = edge->weight;
138 if (best < graph->n_edge) {
139 if (best_weight > weight)
140 continue;
141 if (best_weight == weight && best_dist <= dist)
142 continue;
144 best = i;
145 best_dist = dist;
146 best_weight = weight;
149 return best;
152 /* Internal data structure used in mark_merge_sccs.
154 * "graph" is the dependence graph in which a strongly connected
155 * component is constructed.
156 * "scc_cluster" maps each SCC index to the cluster to which it belongs.
157 * "src" and "dst" are the indices of the nodes that are being merged.
159 struct isl_mark_merge_sccs_data {
160 struct isl_sched_graph *graph;
161 int *scc_cluster;
162 int src;
163 int dst;
166 /* Check whether the cluster containing node "i" depends on the cluster
167 * containing node "j". If "i" and "j" belong to the same cluster,
168 * then they are taken to depend on each other to ensure that
169 * the resulting strongly connected component consists of complete
170 * clusters. Furthermore, if "i" and "j" are the two nodes that
171 * are being merged, then they are taken to depend on each other as well.
172 * Otherwise, check if there is a (conditional) validity dependence
173 * from node[j] to node[i], forcing node[i] to follow node[j].
175 static isl_bool cluster_follows(int i, int j, void *user)
177 struct isl_mark_merge_sccs_data *data = user;
178 struct isl_sched_graph *graph = data->graph;
179 int *scc_cluster = data->scc_cluster;
181 if (data->src == i && data->dst == j)
182 return isl_bool_true;
183 if (data->src == j && data->dst == i)
184 return isl_bool_true;
185 if (scc_cluster[graph->node[i].scc] == scc_cluster[graph->node[j].scc])
186 return isl_bool_true;
188 return isl_sched_graph_has_validity_edge(graph, &graph->node[j],
189 &graph->node[i]);
192 /* Mark all SCCs that belong to either of the two clusters in "c"
193 * connected by the edge in "graph" with index "edge", or to any
194 * of the intermediate clusters.
195 * The marking is recorded in c->scc_in_merge.
197 * The given edge has been selected for merging two clusters,
198 * meaning that there is at least a proximity edge between the two nodes.
199 * However, there may also be (indirect) validity dependences
200 * between the two nodes. When merging the two clusters, all clusters
201 * containing one or more of the intermediate nodes along the
202 * indirect validity dependences need to be merged in as well.
204 * First collect all such nodes by computing the strongly connected
205 * component (SCC) containing the two nodes connected by the edge, where
206 * the two nodes are considered to depend on each other to make
207 * sure they end up in the same SCC. Similarly, each node is considered
208 * to depend on every other node in the same cluster to ensure
209 * that the SCC consists of complete clusters.
211 * Then the original SCCs that contain any of these nodes are marked
212 * in c->scc_in_merge.
214 static isl_stat mark_merge_sccs(isl_ctx *ctx, struct isl_sched_graph *graph,
215 int edge, struct isl_clustering *c)
217 struct isl_mark_merge_sccs_data data;
218 struct isl_tarjan_graph *g;
219 int i;
221 for (i = 0; i < c->n; ++i)
222 c->scc_in_merge[i] = 0;
224 data.graph = graph;
225 data.scc_cluster = c->scc_cluster;
226 data.src = graph->edge[edge].src - graph->node;
227 data.dst = graph->edge[edge].dst - graph->node;
229 g = isl_tarjan_graph_component(ctx, graph->n, data.dst,
230 &cluster_follows, &data);
231 if (!g)
232 goto error;
234 i = g->op;
235 if (i < 3)
236 isl_die(ctx, isl_error_internal,
237 "expecting at least two nodes in component",
238 goto error);
239 if (g->order[--i] != -1)
240 isl_die(ctx, isl_error_internal,
241 "expecting end of component marker", goto error);
243 for (--i; i >= 0 && g->order[i] != -1; --i) {
244 int scc = graph->node[g->order[i]].scc;
245 c->scc_in_merge[scc] = 1;
248 isl_tarjan_graph_free(g);
249 return isl_stat_ok;
250 error:
251 isl_tarjan_graph_free(g);
252 return isl_stat_error;
255 /* Construct the identifier "cluster_i".
257 static __isl_give isl_id *cluster_id(isl_ctx *ctx, int i)
259 char name[40];
261 snprintf(name, sizeof(name), "cluster_%d", i);
262 return isl_id_alloc(ctx, name, NULL);
265 /* Construct the space of the cluster with index "i" containing
266 * the strongly connected component "scc".
268 * In particular, construct a space called cluster_i with dimension equal
269 * to the number of schedule rows in the current band of "scc".
271 static __isl_give isl_space *cluster_space(struct isl_sched_graph *scc, int i)
273 int nvar;
274 isl_space *space;
275 isl_id *id;
277 nvar = scc->n_total_row - scc->band_start;
278 space = isl_space_copy(scc->node[0].space);
279 space = isl_space_params(space);
280 space = isl_space_set_from_params(space);
281 space = isl_space_add_dims(space, isl_dim_set, nvar);
282 id = cluster_id(isl_space_get_ctx(space), i);
283 space = isl_space_set_tuple_id(space, isl_dim_set, id);
285 return space;
288 /* Collect the domain of the graph for merging clusters.
290 * In particular, for each cluster with first SCC "i", construct
291 * a set in the space called cluster_i with dimension equal
292 * to the number of schedule rows in the current band of the cluster.
294 static __isl_give isl_union_set *collect_domain(isl_ctx *ctx,
295 struct isl_sched_graph *graph, struct isl_clustering *c)
297 int i;
298 isl_space *space;
299 isl_union_set *domain;
301 space = isl_space_params_alloc(ctx, 0);
302 domain = isl_union_set_empty(space);
304 for (i = 0; i < graph->scc; ++i) {
305 isl_space *space;
307 if (!c->scc_in_merge[i])
308 continue;
309 if (c->scc_cluster[i] != i)
310 continue;
311 space = cluster_space(&c->scc[i], i);
312 domain = isl_union_set_add_set(domain, isl_set_universe(space));
315 return domain;
318 /* Construct a map from the original instances to the corresponding
319 * cluster instance in the current bands of the clusters in "c".
321 static __isl_give isl_union_map *collect_cluster_map(isl_ctx *ctx,
322 struct isl_sched_graph *graph, struct isl_clustering *c)
324 int i, j;
325 isl_space *space;
326 isl_union_map *cluster_map;
328 space = isl_space_params_alloc(ctx, 0);
329 cluster_map = isl_union_map_empty(space);
330 for (i = 0; i < graph->scc; ++i) {
331 int start, n;
332 isl_id *id;
334 if (!c->scc_in_merge[i])
335 continue;
337 id = cluster_id(ctx, c->scc_cluster[i]);
338 start = c->scc[i].band_start;
339 n = c->scc[i].n_total_row - start;
340 for (j = 0; j < c->scc[i].n; ++j) {
341 isl_multi_aff *ma;
342 isl_map *map;
343 struct isl_sched_node *node = &c->scc[i].node[j];
345 ma = isl_sched_node_extract_partial_schedule_multi_aff(
346 node, start, n);
347 ma = isl_multi_aff_set_tuple_id(ma, isl_dim_out,
348 isl_id_copy(id));
349 map = isl_map_from_multi_aff(ma);
350 cluster_map = isl_union_map_add_map(cluster_map, map);
352 isl_id_free(id);
355 return cluster_map;
358 /* Add "umap" to the schedule constraints "sc" of all types of "edge"
359 * that are not isl_edge_condition or isl_edge_conditional_validity.
361 static __isl_give isl_schedule_constraints *add_non_conditional_constraints(
362 struct isl_sched_edge *edge, __isl_keep isl_union_map *umap,
363 __isl_take isl_schedule_constraints *sc)
365 enum isl_edge_type t;
367 if (!sc)
368 return NULL;
370 for (t = isl_edge_first; t <= isl_edge_last; ++t) {
371 if (t == isl_edge_condition ||
372 t == isl_edge_conditional_validity)
373 continue;
374 if (!isl_sched_edge_has_type(edge, t))
375 continue;
376 sc = isl_schedule_constraints_add(sc, t,
377 isl_union_map_copy(umap));
380 return sc;
383 /* Add schedule constraints of types isl_edge_condition and
384 * isl_edge_conditional_validity to "sc" by applying "umap" to
385 * the domains of the wrapped relations in domain and range
386 * of the corresponding tagged constraints of "edge".
388 static __isl_give isl_schedule_constraints *add_conditional_constraints(
389 struct isl_sched_edge *edge, __isl_keep isl_union_map *umap,
390 __isl_take isl_schedule_constraints *sc)
392 enum isl_edge_type t;
393 isl_union_map *tagged;
395 for (t = isl_edge_condition; t <= isl_edge_conditional_validity; ++t) {
396 if (!isl_sched_edge_has_type(edge, t))
397 continue;
398 if (t == isl_edge_condition)
399 tagged = isl_union_map_copy(edge->tagged_condition);
400 else
401 tagged = isl_union_map_copy(edge->tagged_validity);
402 tagged = isl_union_map_zip(tagged);
403 tagged = isl_union_map_apply_domain(tagged,
404 isl_union_map_copy(umap));
405 tagged = isl_union_map_zip(tagged);
406 sc = isl_schedule_constraints_add(sc, t, tagged);
407 if (!sc)
408 return NULL;
411 return sc;
414 /* Given a mapping "cluster_map" from the original instances to
415 * the cluster instances, add schedule constraints on the clusters
416 * to "sc" corresponding to the original constraints represented by "edge".
418 * For non-tagged dependence constraints, the cluster constraints
419 * are obtained by applying "cluster_map" to the edge->map.
421 * For tagged dependence constraints, "cluster_map" needs to be applied
422 * to the domains of the wrapped relations in domain and range
423 * of the tagged dependence constraints. Pick out the mappings
424 * from these domains from "cluster_map" and construct their product.
425 * This mapping can then be applied to the pair of domains.
427 static __isl_give isl_schedule_constraints *collect_edge_constraints(
428 struct isl_sched_edge *edge, __isl_keep isl_union_map *cluster_map,
429 __isl_take isl_schedule_constraints *sc)
431 isl_union_map *umap;
432 isl_space *space;
433 isl_union_set *uset;
434 isl_union_map *umap1, *umap2;
436 if (!sc)
437 return NULL;
439 umap = isl_union_map_from_map(isl_map_copy(edge->map));
440 umap = isl_union_map_apply_domain(umap,
441 isl_union_map_copy(cluster_map));
442 umap = isl_union_map_apply_range(umap,
443 isl_union_map_copy(cluster_map));
444 sc = add_non_conditional_constraints(edge, umap, sc);
445 isl_union_map_free(umap);
447 if (!sc ||
448 (!isl_sched_edge_is_condition(edge) &&
449 !isl_sched_edge_is_conditional_validity(edge)))
450 return sc;
452 space = isl_space_domain(isl_map_get_space(edge->map));
453 uset = isl_union_set_from_set(isl_set_universe(space));
454 umap1 = isl_union_map_copy(cluster_map);
455 umap1 = isl_union_map_intersect_domain(umap1, uset);
456 space = isl_space_range(isl_map_get_space(edge->map));
457 uset = isl_union_set_from_set(isl_set_universe(space));
458 umap2 = isl_union_map_copy(cluster_map);
459 umap2 = isl_union_map_intersect_domain(umap2, uset);
460 umap = isl_union_map_product(umap1, umap2);
462 sc = add_conditional_constraints(edge, umap, sc);
464 isl_union_map_free(umap);
465 return sc;
468 /* Given a mapping "cluster_map" from the original instances to
469 * the cluster instances, add schedule constraints on the clusters
470 * to "sc" corresponding to all edges in "graph" between nodes that
471 * belong to SCCs that are marked for merging in "scc_in_merge".
473 static __isl_give isl_schedule_constraints *collect_constraints(
474 struct isl_sched_graph *graph, int *scc_in_merge,
475 __isl_keep isl_union_map *cluster_map,
476 __isl_take isl_schedule_constraints *sc)
478 int i;
480 for (i = 0; i < graph->n_edge; ++i) {
481 struct isl_sched_edge *edge = &graph->edge[i];
483 if (!scc_in_merge[edge->src->scc])
484 continue;
485 if (!scc_in_merge[edge->dst->scc])
486 continue;
487 sc = collect_edge_constraints(edge, cluster_map, sc);
490 return sc;
493 /* Construct a dependence graph for scheduling clusters with respect
494 * to each other and store the result in "merge_graph".
495 * In particular, the nodes of the graph correspond to the schedule
496 * dimensions of the current bands of those clusters that have been
497 * marked for merging in "c".
499 * First construct an isl_schedule_constraints object for this domain
500 * by transforming the edges in "graph" to the domain.
501 * Then initialize a dependence graph for scheduling from these
502 * constraints.
504 static isl_stat init_merge_graph(isl_ctx *ctx, struct isl_sched_graph *graph,
505 struct isl_clustering *c, struct isl_sched_graph *merge_graph)
507 isl_union_set *domain;
508 isl_union_map *cluster_map;
509 isl_schedule_constraints *sc;
510 isl_stat r;
512 domain = collect_domain(ctx, graph, c);
513 sc = isl_schedule_constraints_on_domain(domain);
514 if (!sc)
515 return isl_stat_error;
516 cluster_map = collect_cluster_map(ctx, graph, c);
517 sc = collect_constraints(graph, c->scc_in_merge, cluster_map, sc);
518 isl_union_map_free(cluster_map);
520 r = isl_sched_graph_init(merge_graph, sc);
522 isl_schedule_constraints_free(sc);
524 return r;
527 /* Compute the maximal number of remaining schedule rows that still need
528 * to be computed for the nodes that belong to clusters with the maximal
529 * dimension for the current band (i.e., the band that is to be merged).
530 * Only clusters that are about to be merged are considered.
531 * "maxvar" is the maximal dimension for the current band.
532 * "c" contains information about the clusters.
534 * Return the maximal number of remaining schedule rows or
535 * isl_size_error on error.
537 static isl_size compute_maxvar_max_slack(int maxvar, struct isl_clustering *c)
539 int i, j;
540 int max_slack;
542 max_slack = 0;
543 for (i = 0; i < c->n; ++i) {
544 int nvar;
545 struct isl_sched_graph *scc;
547 if (!c->scc_in_merge[i])
548 continue;
549 scc = &c->scc[i];
550 nvar = scc->n_total_row - scc->band_start;
551 if (nvar != maxvar)
552 continue;
553 for (j = 0; j < scc->n; ++j) {
554 struct isl_sched_node *node = &scc->node[j];
555 int slack;
557 if (isl_sched_node_update_vmap(node) < 0)
558 return isl_size_error;
559 slack = node->nvar - node->rank;
560 if (slack > max_slack)
561 max_slack = slack;
565 return max_slack;
568 /* If there are any clusters where the dimension of the current band
569 * (i.e., the band that is to be merged) is smaller than "maxvar" and
570 * if there are any nodes in such a cluster where the number
571 * of remaining schedule rows that still need to be computed
572 * is greater than "max_slack", then return the smallest current band
573 * dimension of all these clusters. Otherwise return the original value
574 * of "maxvar". Return isl_size_error in case of any error.
575 * Only clusters that are about to be merged are considered.
576 * "c" contains information about the clusters.
578 static isl_size limit_maxvar_to_slack(int maxvar, int max_slack,
579 struct isl_clustering *c)
581 int i, j;
583 for (i = 0; i < c->n; ++i) {
584 int nvar;
585 struct isl_sched_graph *scc;
587 if (!c->scc_in_merge[i])
588 continue;
589 scc = &c->scc[i];
590 nvar = scc->n_total_row - scc->band_start;
591 if (nvar >= maxvar)
592 continue;
593 for (j = 0; j < scc->n; ++j) {
594 struct isl_sched_node *node = &scc->node[j];
595 int slack;
597 if (isl_sched_node_update_vmap(node) < 0)
598 return isl_size_error;
599 slack = node->nvar - node->rank;
600 if (slack > max_slack) {
601 maxvar = nvar;
602 break;
607 return maxvar;
610 /* Adjust merge_graph->maxvar based on the number of remaining schedule rows
611 * that still need to be computed. In particular, if there is a node
612 * in a cluster where the dimension of the current band is smaller
613 * than merge_graph->maxvar, but the number of remaining schedule rows
614 * is greater than that of any node in a cluster with the maximal
615 * dimension for the current band (i.e., merge_graph->maxvar),
616 * then adjust merge_graph->maxvar to the (smallest) current band dimension
617 * of those clusters. Without this adjustment, the total number of
618 * schedule dimensions would be increased, resulting in a skewed view
619 * of the number of coincident dimensions.
620 * "c" contains information about the clusters.
622 * If the maximize_band_depth option is set and merge_graph->maxvar is reduced,
623 * then there is no point in attempting any merge since it will be rejected
624 * anyway. Set merge_graph->maxvar to zero in such cases.
626 static isl_stat adjust_maxvar_to_slack(isl_ctx *ctx,
627 struct isl_sched_graph *merge_graph, struct isl_clustering *c)
629 isl_size max_slack, maxvar;
631 max_slack = compute_maxvar_max_slack(merge_graph->maxvar, c);
632 if (max_slack < 0)
633 return isl_stat_error;
634 maxvar = limit_maxvar_to_slack(merge_graph->maxvar, max_slack, c);
635 if (maxvar < 0)
636 return isl_stat_error;
638 if (maxvar < merge_graph->maxvar) {
639 if (isl_options_get_schedule_maximize_band_depth(ctx))
640 merge_graph->maxvar = 0;
641 else
642 merge_graph->maxvar = maxvar;
645 return isl_stat_ok;
648 /* Return the number of coincident dimensions in the current band of "graph",
649 * where the nodes of "graph" are assumed to be scheduled by a single band.
651 static int get_n_coincident(struct isl_sched_graph *graph)
653 int i;
655 for (i = graph->band_start; i < graph->n_total_row; ++i)
656 if (!graph->node[0].coincident[i])
657 break;
659 return i - graph->band_start;
662 /* Should the clusters be merged based on the cluster schedule
663 * in the current (and only) band of "merge_graph", given that
664 * coincidence should be maximized?
666 * If the number of coincident schedule dimensions in the merged band
667 * would be less than the maximal number of coincident schedule dimensions
668 * in any of the merged clusters, then the clusters should not be merged.
670 static isl_bool ok_to_merge_coincident(struct isl_clustering *c,
671 struct isl_sched_graph *merge_graph)
673 int i;
674 int n_coincident;
675 int max_coincident;
677 max_coincident = 0;
678 for (i = 0; i < c->n; ++i) {
679 if (!c->scc_in_merge[i])
680 continue;
681 n_coincident = get_n_coincident(&c->scc[i]);
682 if (n_coincident > max_coincident)
683 max_coincident = n_coincident;
686 n_coincident = get_n_coincident(merge_graph);
688 return isl_bool_ok(n_coincident >= max_coincident);
691 /* Return the transformation on "node" expressed by the current (and only)
692 * band of "merge_graph" applied to the clusters in "c".
694 * First find the representation of "node" in its SCC in "c" and
695 * extract the transformation expressed by the current band.
696 * Then extract the transformation applied by "merge_graph"
697 * to the cluster to which this SCC belongs.
698 * Combine the two to obtain the complete transformation on the node.
700 * Note that the range of the first transformation is an anonymous space,
701 * while the domain of the second is named "cluster_X". The range
702 * of the former therefore needs to be adjusted before the two
703 * can be combined.
705 static __isl_give isl_map *extract_node_transformation(isl_ctx *ctx,
706 struct isl_sched_node *node, struct isl_clustering *c,
707 struct isl_sched_graph *merge_graph)
709 struct isl_sched_node *scc_node, *cluster_node;
710 int start, n;
711 isl_id *id;
712 isl_space *space;
713 isl_multi_aff *ma, *ma2;
715 scc_node = isl_sched_graph_find_node(ctx, &c->scc[node->scc],
716 node->space);
717 if (scc_node && !isl_sched_graph_is_node(&c->scc[node->scc], scc_node))
718 isl_die(ctx, isl_error_internal, "unable to find node",
719 return NULL);
720 start = c->scc[node->scc].band_start;
721 n = c->scc[node->scc].n_total_row - start;
722 ma = isl_sched_node_extract_partial_schedule_multi_aff(scc_node,
723 start, n);
724 space = cluster_space(&c->scc[node->scc], c->scc_cluster[node->scc]);
725 cluster_node = isl_sched_graph_find_node(ctx, merge_graph, space);
726 if (cluster_node && !isl_sched_graph_is_node(merge_graph, cluster_node))
727 isl_die(ctx, isl_error_internal, "unable to find cluster",
728 space = isl_space_free(space));
729 id = isl_space_get_tuple_id(space, isl_dim_set);
730 ma = isl_multi_aff_set_tuple_id(ma, isl_dim_out, id);
731 isl_space_free(space);
732 n = merge_graph->n_total_row;
733 ma2 = isl_sched_node_extract_partial_schedule_multi_aff(cluster_node,
734 0, n);
735 ma = isl_multi_aff_pullback_multi_aff(ma2, ma);
737 return isl_map_from_multi_aff(ma);
740 /* Give a set of distances "set", are they bounded by a small constant
741 * in direction "pos"?
742 * In practice, check if they are bounded by 2 by checking that there
743 * are no elements with a value greater than or equal to 3 or
744 * smaller than or equal to -3.
746 static isl_bool distance_is_bounded(__isl_keep isl_set *set, int pos)
748 isl_bool bounded;
749 isl_set *test;
751 if (!set)
752 return isl_bool_error;
754 test = isl_set_copy(set);
755 test = isl_set_lower_bound_si(test, isl_dim_set, pos, 3);
756 bounded = isl_set_is_empty(test);
757 isl_set_free(test);
759 if (bounded < 0 || !bounded)
760 return bounded;
762 test = isl_set_copy(set);
763 test = isl_set_upper_bound_si(test, isl_dim_set, pos, -3);
764 bounded = isl_set_is_empty(test);
765 isl_set_free(test);
767 return bounded;
770 /* Does the set "set" have a fixed (but possible parametric) value
771 * at dimension "pos"?
773 static isl_bool has_single_value(__isl_keep isl_set *set, int pos)
775 isl_size n;
776 isl_bool single;
778 n = isl_set_dim(set, isl_dim_set);
779 if (n < 0)
780 return isl_bool_error;
781 set = isl_set_copy(set);
782 set = isl_set_project_out(set, isl_dim_set, pos + 1, n - (pos + 1));
783 set = isl_set_project_out(set, isl_dim_set, 0, pos);
784 single = isl_set_is_singleton(set);
785 isl_set_free(set);
787 return single;
790 /* Does "map" have a fixed (but possible parametric) value
791 * at dimension "pos" of either its domain or its range?
793 static isl_bool has_singular_src_or_dst(__isl_keep isl_map *map, int pos)
795 isl_set *set;
796 isl_bool single;
798 set = isl_map_domain(isl_map_copy(map));
799 single = has_single_value(set, pos);
800 isl_set_free(set);
802 if (single < 0 || single)
803 return single;
805 set = isl_map_range(isl_map_copy(map));
806 single = has_single_value(set, pos);
807 isl_set_free(set);
809 return single;
812 /* Does the edge "edge" from "graph" have bounded dependence distances
813 * in the merged graph "merge_graph" of a selection of clusters in "c"?
815 * Extract the complete transformations of the source and destination
816 * nodes of the edge, apply them to the edge constraints and
817 * compute the differences. Finally, check if these differences are bounded
818 * in each direction.
820 * If the dimension of the band is greater than the number of
821 * dimensions that can be expected to be optimized by the edge
822 * (based on its weight), then also allow the differences to be unbounded
823 * in the remaining dimensions, but only if either the source or
824 * the destination has a fixed value in that direction.
825 * This allows a statement that produces values that are used by
826 * several instances of another statement to be merged with that
827 * other statement.
828 * However, merging such clusters will introduce an inherently
829 * large proximity distance inside the merged cluster, meaning
830 * that proximity distances will no longer be optimized in
831 * subsequent merges. These merges are therefore only allowed
832 * after all other possible merges have been tried.
833 * The first time such a merge is encountered, the weight of the edge
834 * is replaced by a negative weight. The second time (i.e., after
835 * all merges over edges with a non-negative weight have been tried),
836 * the merge is allowed.
838 static isl_bool has_bounded_distances(isl_ctx *ctx, struct isl_sched_edge *edge,
839 struct isl_sched_graph *graph, struct isl_clustering *c,
840 struct isl_sched_graph *merge_graph)
842 int i, n_slack;
843 isl_size n;
844 isl_bool bounded;
845 isl_map *map, *t;
846 isl_set *dist;
848 map = isl_map_copy(edge->map);
849 t = extract_node_transformation(ctx, edge->src, c, merge_graph);
850 map = isl_map_apply_domain(map, t);
851 t = extract_node_transformation(ctx, edge->dst, c, merge_graph);
852 map = isl_map_apply_range(map, t);
853 dist = isl_map_deltas(isl_map_copy(map));
855 bounded = isl_bool_true;
856 n = isl_set_dim(dist, isl_dim_set);
857 if (n < 0)
858 goto error;
859 n_slack = n - edge->weight;
860 if (edge->weight < 0)
861 n_slack -= graph->max_weight + 1;
862 for (i = 0; i < n; ++i) {
863 isl_bool bounded_i, singular_i;
865 bounded_i = distance_is_bounded(dist, i);
866 if (bounded_i < 0)
867 goto error;
868 if (bounded_i)
869 continue;
870 if (edge->weight >= 0)
871 bounded = isl_bool_false;
872 n_slack--;
873 if (n_slack < 0)
874 break;
875 singular_i = has_singular_src_or_dst(map, i);
876 if (singular_i < 0)
877 goto error;
878 if (singular_i)
879 continue;
880 bounded = isl_bool_false;
881 break;
883 if (!bounded && i >= n && edge->weight >= 0)
884 edge->weight -= graph->max_weight + 1;
885 isl_map_free(map);
886 isl_set_free(dist);
888 return bounded;
889 error:
890 isl_map_free(map);
891 isl_set_free(dist);
892 return isl_bool_error;
895 /* Should the clusters be merged based on the cluster schedule
896 * in the current (and only) band of "merge_graph"?
897 * "graph" is the original dependence graph, while "c" records
898 * which SCCs are involved in the latest merge.
900 * In particular, is there at least one proximity constraint
901 * that is optimized by the merge?
903 * A proximity constraint is considered to be optimized
904 * if the dependence distances are small.
906 static isl_bool ok_to_merge_proximity(isl_ctx *ctx,
907 struct isl_sched_graph *graph, struct isl_clustering *c,
908 struct isl_sched_graph *merge_graph)
910 int i;
912 for (i = 0; i < graph->n_edge; ++i) {
913 struct isl_sched_edge *edge = &graph->edge[i];
914 isl_bool bounded;
916 if (!isl_sched_edge_is_proximity(edge))
917 continue;
918 if (!c->scc_in_merge[edge->src->scc])
919 continue;
920 if (!c->scc_in_merge[edge->dst->scc])
921 continue;
922 if (c->scc_cluster[edge->dst->scc] ==
923 c->scc_cluster[edge->src->scc])
924 continue;
925 bounded = has_bounded_distances(ctx, edge, graph, c,
926 merge_graph);
927 if (bounded < 0 || bounded)
928 return bounded;
931 return isl_bool_false;
934 /* Should the clusters be merged based on the cluster schedule
935 * in the current (and only) band of "merge_graph"?
936 * "graph" is the original dependence graph, while "c" records
937 * which SCCs are involved in the latest merge.
939 * If the current band is empty, then the clusters should not be merged.
941 * If the band depth should be maximized and the merge schedule
942 * is incomplete (meaning that the dimension of some of the schedule
943 * bands in the original schedule will be reduced), then the clusters
944 * should not be merged.
946 * If the schedule_maximize_coincidence option is set, then check that
947 * the number of coincident schedule dimensions is not reduced.
949 * Finally, only allow the merge if at least one proximity
950 * constraint is optimized.
952 static isl_bool ok_to_merge(isl_ctx *ctx, struct isl_sched_graph *graph,
953 struct isl_clustering *c, struct isl_sched_graph *merge_graph)
955 if (merge_graph->n_total_row == merge_graph->band_start)
956 return isl_bool_false;
958 if (isl_options_get_schedule_maximize_band_depth(ctx) &&
959 merge_graph->n_total_row < merge_graph->maxvar)
960 return isl_bool_false;
962 if (isl_options_get_schedule_maximize_coincidence(ctx)) {
963 isl_bool ok;
965 ok = ok_to_merge_coincident(c, merge_graph);
966 if (ok < 0 || !ok)
967 return ok;
970 return ok_to_merge_proximity(ctx, graph, c, merge_graph);
973 /* Apply the schedule in "t_node" to the "n" rows starting at "first"
974 * of the schedule in "node" and return the result.
976 * That is, essentially compute
978 * T * N(first:first+n-1)
980 * taking into account the constant term and the parameter coefficients
981 * in "t_node".
983 static __isl_give isl_mat *node_transformation(isl_ctx *ctx,
984 struct isl_sched_node *t_node, struct isl_sched_node *node,
985 int first, int n)
987 int i, j;
988 isl_mat *t;
989 isl_size n_row, n_col;
990 int n_param, n_var;
992 n_param = node->nparam;
993 n_var = node->nvar;
994 n_row = isl_mat_rows(t_node->sched);
995 n_col = isl_mat_cols(node->sched);
996 if (n_row < 0 || n_col < 0)
997 return NULL;
998 t = isl_mat_alloc(ctx, n_row, n_col);
999 if (!t)
1000 return NULL;
1001 for (i = 0; i < n_row; ++i) {
1002 isl_seq_cpy(t->row[i], t_node->sched->row[i], 1 + n_param);
1003 isl_seq_clr(t->row[i] + 1 + n_param, n_var);
1004 for (j = 0; j < n; ++j)
1005 isl_seq_addmul(t->row[i],
1006 t_node->sched->row[i][1 + n_param + j],
1007 node->sched->row[first + j],
1008 1 + n_param + n_var);
1010 return t;
1013 /* Apply the cluster schedule in "t_node" to the current band
1014 * schedule of the nodes in "graph".
1016 * In particular, replace the rows starting at band_start
1017 * by the result of applying the cluster schedule in "t_node"
1018 * to the original rows.
1020 * The coincidence of the schedule is determined by the coincidence
1021 * of the cluster schedule.
1023 static isl_stat transform(isl_ctx *ctx, struct isl_sched_graph *graph,
1024 struct isl_sched_node *t_node)
1026 int i, j;
1027 isl_size n_new;
1028 int start, n;
1030 start = graph->band_start;
1031 n = graph->n_total_row - start;
1033 n_new = isl_mat_rows(t_node->sched);
1034 if (n_new < 0)
1035 return isl_stat_error;
1036 for (i = 0; i < graph->n; ++i) {
1037 struct isl_sched_node *node = &graph->node[i];
1038 isl_mat *t;
1040 t = node_transformation(ctx, t_node, node, start, n);
1041 node->sched = isl_mat_drop_rows(node->sched, start, n);
1042 node->sched = isl_mat_concat(node->sched, t);
1043 node->sched_map = isl_map_free(node->sched_map);
1044 if (!node->sched)
1045 return isl_stat_error;
1046 for (j = 0; j < n_new; ++j)
1047 node->coincident[start + j] = t_node->coincident[j];
1049 graph->n_total_row -= n;
1050 graph->n_row -= n;
1051 graph->n_total_row += n_new;
1052 graph->n_row += n_new;
1054 return isl_stat_ok;
1057 /* Merge the clusters marked for merging in "c" into a single
1058 * cluster using the cluster schedule in the current band of "merge_graph".
1059 * The representative SCC for the new cluster is the SCC with
1060 * the smallest index.
1062 * The current band schedule of each SCC in the new cluster is obtained
1063 * by applying the schedule of the corresponding original cluster
1064 * to the original band schedule.
1065 * All SCCs in the new cluster have the same number of schedule rows.
1067 static isl_stat merge(isl_ctx *ctx, struct isl_clustering *c,
1068 struct isl_sched_graph *merge_graph)
1070 int i;
1071 int cluster = -1;
1072 isl_space *space;
1074 for (i = 0; i < c->n; ++i) {
1075 struct isl_sched_node *node;
1077 if (!c->scc_in_merge[i])
1078 continue;
1079 if (cluster < 0)
1080 cluster = i;
1081 space = cluster_space(&c->scc[i], c->scc_cluster[i]);
1082 node = isl_sched_graph_find_node(ctx, merge_graph, space);
1083 isl_space_free(space);
1084 if (!node)
1085 return isl_stat_error;
1086 if (!isl_sched_graph_is_node(merge_graph, node))
1087 isl_die(ctx, isl_error_internal,
1088 "unable to find cluster",
1089 return isl_stat_error);
1090 if (transform(ctx, &c->scc[i], node) < 0)
1091 return isl_stat_error;
1092 c->scc_cluster[i] = cluster;
1095 return isl_stat_ok;
1098 /* Try and merge the clusters of SCCs marked in c->scc_in_merge
1099 * by scheduling the current cluster bands with respect to each other.
1101 * Construct a dependence graph with a space for each cluster and
1102 * with the coordinates of each space corresponding to the schedule
1103 * dimensions of the current band of that cluster.
1104 * Construct a cluster schedule in this cluster dependence graph and
1105 * apply it to the current cluster bands if it is applicable
1106 * according to ok_to_merge.
1108 * If the number of remaining schedule dimensions in a cluster
1109 * with a non-maximal current schedule dimension is greater than
1110 * the number of remaining schedule dimensions in clusters
1111 * with a maximal current schedule dimension, then restrict
1112 * the number of rows to be computed in the cluster schedule
1113 * to the minimal such non-maximal current schedule dimension.
1114 * Do this by adjusting merge_graph.maxvar.
1116 * Return isl_bool_true if the clusters have effectively been merged
1117 * into a single cluster.
1119 * Note that since the standard scheduling algorithm minimizes the maximal
1120 * distance over proximity constraints, the proximity constraints between
1121 * the merged clusters may not be optimized any further than what is
1122 * sufficient to bring the distances within the limits of the internal
1123 * proximity constraints inside the individual clusters.
1124 * It may therefore make sense to perform an additional translation step
1125 * to bring the clusters closer to each other, while maintaining
1126 * the linear part of the merging schedule found using the standard
1127 * scheduling algorithm.
1129 static isl_bool try_merge(isl_ctx *ctx, struct isl_sched_graph *graph,
1130 struct isl_clustering *c)
1132 struct isl_sched_graph merge_graph = { 0 };
1133 isl_bool merged;
1135 if (init_merge_graph(ctx, graph, c, &merge_graph) < 0)
1136 goto error;
1138 if (isl_sched_graph_compute_maxvar(&merge_graph) < 0)
1139 goto error;
1140 if (adjust_maxvar_to_slack(ctx, &merge_graph,c) < 0)
1141 goto error;
1142 if (isl_schedule_node_compute_wcc_band(ctx, &merge_graph) < 0)
1143 goto error;
1144 merged = ok_to_merge(ctx, graph, c, &merge_graph);
1145 if (merged && merge(ctx, c, &merge_graph) < 0)
1146 goto error;
1148 isl_sched_graph_free(ctx, &merge_graph);
1149 return merged;
1150 error:
1151 isl_sched_graph_free(ctx, &merge_graph);
1152 return isl_bool_error;
1155 /* Is there any edge marked "no_merge" between two SCCs that are
1156 * about to be merged (i.e., that are set in "scc_in_merge")?
1157 * "merge_edge" is the proximity edge along which the clusters of SCCs
1158 * are going to be merged.
1160 * If there is any edge between two SCCs with a negative weight,
1161 * while the weight of "merge_edge" is non-negative, then this
1162 * means that the edge was postponed. "merge_edge" should then
1163 * also be postponed since merging along the edge with negative weight should
1164 * be postponed until all edges with non-negative weight have been tried.
1165 * Replace the weight of "merge_edge" by a negative weight as well and
1166 * tell the caller not to attempt a merge.
1168 static int any_no_merge(struct isl_sched_graph *graph, int *scc_in_merge,
1169 struct isl_sched_edge *merge_edge)
1171 int i;
1173 for (i = 0; i < graph->n_edge; ++i) {
1174 struct isl_sched_edge *edge = &graph->edge[i];
1176 if (!scc_in_merge[edge->src->scc])
1177 continue;
1178 if (!scc_in_merge[edge->dst->scc])
1179 continue;
1180 if (edge->no_merge)
1181 return 1;
1182 if (merge_edge->weight >= 0 && edge->weight < 0) {
1183 merge_edge->weight -= graph->max_weight + 1;
1184 return 1;
1188 return 0;
1191 /* Merge the two clusters in "c" connected by the edge in "graph"
1192 * with index "edge" into a single cluster.
1193 * If it turns out to be impossible to merge these two clusters,
1194 * then mark the edge as "no_merge" such that it will not be
1195 * considered again.
1197 * First mark all SCCs that need to be merged. This includes the SCCs
1198 * in the two clusters, but it may also include the SCCs
1199 * of intermediate clusters.
1200 * If there is already a no_merge edge between any pair of such SCCs,
1201 * then simply mark the current edge as no_merge as well.
1202 * Likewise, if any of those edges was postponed by has_bounded_distances,
1203 * then postpone the current edge as well.
1204 * Otherwise, try and merge the clusters and mark "edge" as "no_merge"
1205 * if the clusters did not end up getting merged, unless the non-merge
1206 * is due to the fact that the edge was postponed. This postponement
1207 * can be recognized by a change in weight (from non-negative to negative).
1209 static isl_stat merge_clusters_along_edge(isl_ctx *ctx,
1210 struct isl_sched_graph *graph, int edge, struct isl_clustering *c)
1212 isl_bool merged;
1213 int edge_weight = graph->edge[edge].weight;
1215 if (mark_merge_sccs(ctx, graph, edge, c) < 0)
1216 return isl_stat_error;
1218 if (any_no_merge(graph, c->scc_in_merge, &graph->edge[edge]))
1219 merged = isl_bool_false;
1220 else
1221 merged = try_merge(ctx, graph, c);
1222 if (merged < 0)
1223 return isl_stat_error;
1224 if (!merged && edge_weight == graph->edge[edge].weight)
1225 graph->edge[edge].no_merge = 1;
1227 return isl_stat_ok;
1230 /* Does "node" belong to the cluster identified by "cluster"?
1232 static int node_cluster_exactly(struct isl_sched_node *node, int cluster)
1234 return node->cluster == cluster;
1237 /* Does "edge" connect two nodes belonging to the cluster
1238 * identified by "cluster"?
1240 static int edge_cluster_exactly(struct isl_sched_edge *edge, int cluster)
1242 return edge->src->cluster == cluster && edge->dst->cluster == cluster;
1245 /* Swap the schedule of "node1" and "node2".
1246 * Both nodes have been derived from the same node in a common parent graph.
1247 * Since the "coincident" field is shared with that node
1248 * in the parent graph, there is no need to also swap this field.
1250 static void swap_sched(struct isl_sched_node *node1,
1251 struct isl_sched_node *node2)
1253 isl_mat *sched;
1254 isl_map *sched_map;
1256 sched = node1->sched;
1257 node1->sched = node2->sched;
1258 node2->sched = sched;
1260 sched_map = node1->sched_map;
1261 node1->sched_map = node2->sched_map;
1262 node2->sched_map = sched_map;
1265 /* Copy the current band schedule from the SCCs that form the cluster
1266 * with index "pos" to the actual cluster at position "pos".
1267 * By construction, the index of the first SCC that belongs to the cluster
1268 * is also "pos".
1270 * The order of the nodes inside both the SCCs and the cluster
1271 * is assumed to be same as the order in the original "graph".
1273 * Since the SCC graphs will no longer be used after this function,
1274 * the schedules are actually swapped rather than copied.
1276 static isl_stat copy_partial(struct isl_sched_graph *graph,
1277 struct isl_clustering *c, int pos)
1279 int i, j;
1281 c->cluster[pos].n_total_row = c->scc[pos].n_total_row;
1282 c->cluster[pos].n_row = c->scc[pos].n_row;
1283 c->cluster[pos].maxvar = c->scc[pos].maxvar;
1284 j = 0;
1285 for (i = 0; i < graph->n; ++i) {
1286 int k;
1287 int s;
1289 if (graph->node[i].cluster != pos)
1290 continue;
1291 s = graph->node[i].scc;
1292 k = c->scc_node[s]++;
1293 swap_sched(&c->cluster[pos].node[j], &c->scc[s].node[k]);
1294 if (c->scc[s].maxvar > c->cluster[pos].maxvar)
1295 c->cluster[pos].maxvar = c->scc[s].maxvar;
1296 ++j;
1299 return isl_stat_ok;
1302 /* Is there a (conditional) validity dependence from node[j] to node[i],
1303 * forcing node[i] to follow node[j] or do the nodes belong to the same
1304 * cluster?
1306 static isl_bool node_follows_strong_or_same_cluster(int i, int j, void *user)
1308 struct isl_sched_graph *graph = user;
1310 if (graph->node[i].cluster == graph->node[j].cluster)
1311 return isl_bool_true;
1312 return isl_sched_graph_has_validity_edge(graph, &graph->node[j],
1313 &graph->node[i]);
1316 /* Extract the merged clusters of SCCs in "graph", sort them, and
1317 * store them in c->clusters. Update c->scc_cluster accordingly.
1319 * First keep track of the cluster containing the SCC to which a node
1320 * belongs in the node itself.
1321 * Then extract the clusters into c->clusters, copying the current
1322 * band schedule from the SCCs that belong to the cluster.
1323 * Do this only once per cluster.
1325 * Finally, topologically sort the clusters and update c->scc_cluster
1326 * to match the new scc numbering. While the SCCs were originally
1327 * sorted already, some SCCs that depend on some other SCCs may
1328 * have been merged with SCCs that appear before these other SCCs.
1329 * A reordering may therefore be required.
1331 static isl_stat extract_clusters(isl_ctx *ctx, struct isl_sched_graph *graph,
1332 struct isl_clustering *c)
1334 int i;
1336 for (i = 0; i < graph->n; ++i)
1337 graph->node[i].cluster = c->scc_cluster[graph->node[i].scc];
1339 for (i = 0; i < graph->scc; ++i) {
1340 if (c->scc_cluster[i] != i)
1341 continue;
1342 if (isl_sched_graph_extract_sub_graph(ctx, graph,
1343 &node_cluster_exactly,
1344 &edge_cluster_exactly, i, &c->cluster[i]) < 0)
1345 return isl_stat_error;
1346 c->cluster[i].src_scc = -1;
1347 c->cluster[i].dst_scc = -1;
1348 if (copy_partial(graph, c, i) < 0)
1349 return isl_stat_error;
1352 if (isl_sched_graph_detect_ccs(ctx, graph,
1353 &node_follows_strong_or_same_cluster) < 0)
1354 return isl_stat_error;
1355 for (i = 0; i < graph->n; ++i)
1356 c->scc_cluster[graph->node[i].scc] = graph->node[i].cluster;
1358 return isl_stat_ok;
1361 /* Compute weights on the proximity edges of "graph" that can
1362 * be used by find_proximity to find the most appropriate
1363 * proximity edge to use to merge two clusters in "c".
1364 * The weights are also used by has_bounded_distances to determine
1365 * whether the merge should be allowed.
1366 * Store the maximum of the computed weights in graph->max_weight.
1368 * The computed weight is a measure for the number of remaining schedule
1369 * dimensions that can still be completely aligned.
1370 * In particular, compute the number of equalities between
1371 * input dimensions and output dimensions in the proximity constraints.
1372 * The directions that are already handled by outer schedule bands
1373 * are projected out prior to determining this number.
1375 * Edges that will never be considered by find_proximity are ignored.
1377 static isl_stat compute_weights(struct isl_sched_graph *graph,
1378 struct isl_clustering *c)
1380 int i;
1382 graph->max_weight = 0;
1384 for (i = 0; i < graph->n_edge; ++i) {
1385 struct isl_sched_edge *edge = &graph->edge[i];
1386 struct isl_sched_node *src = edge->src;
1387 struct isl_sched_node *dst = edge->dst;
1388 isl_basic_map *hull;
1389 isl_bool prox;
1390 isl_size n_in, n_out, n;
1392 prox = is_non_empty_proximity(edge);
1393 if (prox < 0)
1394 return isl_stat_error;
1395 if (!prox)
1396 continue;
1397 if (bad_cluster(&c->scc[edge->src->scc]) ||
1398 bad_cluster(&c->scc[edge->dst->scc]))
1399 continue;
1400 if (c->scc_cluster[edge->dst->scc] ==
1401 c->scc_cluster[edge->src->scc])
1402 continue;
1404 hull = isl_map_affine_hull(isl_map_copy(edge->map));
1405 hull = isl_basic_map_transform_dims(hull, isl_dim_in, 0,
1406 isl_mat_copy(src->vmap));
1407 hull = isl_basic_map_transform_dims(hull, isl_dim_out, 0,
1408 isl_mat_copy(dst->vmap));
1409 hull = isl_basic_map_project_out(hull,
1410 isl_dim_in, 0, src->rank);
1411 hull = isl_basic_map_project_out(hull,
1412 isl_dim_out, 0, dst->rank);
1413 hull = isl_basic_map_remove_divs(hull);
1414 n_in = isl_basic_map_dim(hull, isl_dim_in);
1415 n_out = isl_basic_map_dim(hull, isl_dim_out);
1416 if (n_in < 0 || n_out < 0)
1417 hull = isl_basic_map_free(hull);
1418 hull = isl_basic_map_drop_constraints_not_involving_dims(hull,
1419 isl_dim_in, 0, n_in);
1420 hull = isl_basic_map_drop_constraints_not_involving_dims(hull,
1421 isl_dim_out, 0, n_out);
1422 n = isl_basic_map_n_equality(hull);
1423 isl_basic_map_free(hull);
1424 if (n < 0)
1425 return isl_stat_error;
1426 edge->weight = n;
1428 if (edge->weight > graph->max_weight)
1429 graph->max_weight = edge->weight;
1432 return isl_stat_ok;
1435 /* Call isl_schedule_node_compute_finish_band on each of the clusters in "c"
1436 * in their topological order. This order is determined by the scc
1437 * fields of the nodes in "graph".
1438 * Combine the results in a sequence expressing the topological order.
1440 * If there is only one cluster left, then there is no need to introduce
1441 * a sequence node. Also, in this case, the cluster necessarily contains
1442 * the SCC at position 0 in the original graph and is therefore also
1443 * stored in the first cluster of "c".
1445 static __isl_give isl_schedule_node *finish_bands_clustering(
1446 __isl_take isl_schedule_node *node, struct isl_sched_graph *graph,
1447 struct isl_clustering *c)
1449 int i;
1450 isl_ctx *ctx;
1451 isl_union_set_list *filters;
1453 if (graph->scc == 1)
1454 return isl_schedule_node_compute_finish_band(node,
1455 &c->cluster[0], 0);
1457 ctx = isl_schedule_node_get_ctx(node);
1459 filters = isl_sched_graph_extract_sccs(ctx, graph);
1460 node = isl_schedule_node_insert_sequence(node, filters);
1462 for (i = 0; i < graph->scc; ++i) {
1463 int j = c->scc_cluster[i];
1464 node = isl_schedule_node_grandchild(node, i, 0);
1465 node = isl_schedule_node_compute_finish_band(node,
1466 &c->cluster[j], 0);
1467 node = isl_schedule_node_grandparent(node);
1470 return node;
1473 /* Compute a schedule for a connected dependence graph by first considering
1474 * each strongly connected component (SCC) in the graph separately and then
1475 * incrementally combining them into clusters.
1476 * Return the updated schedule node.
1478 * Initially, each cluster consists of a single SCC, each with its
1479 * own band schedule. The algorithm then tries to merge pairs
1480 * of clusters along a proximity edge until no more suitable
1481 * proximity edges can be found. During this merging, the schedule
1482 * is maintained in the individual SCCs.
1483 * After the merging is completed, the full resulting clusters
1484 * are extracted and in finish_bands_clustering,
1485 * isl_schedule_node_compute_finish_band is called on each of them to integrate
1486 * the band into "node" and to continue the computation.
1488 * compute_weights initializes the weights that are used by find_proximity.
1490 __isl_give isl_schedule_node *isl_schedule_node_compute_wcc_clustering(
1491 __isl_take isl_schedule_node *node, struct isl_sched_graph *graph)
1493 isl_ctx *ctx;
1494 struct isl_clustering c;
1495 int i;
1497 ctx = isl_schedule_node_get_ctx(node);
1499 if (clustering_init(ctx, &c, graph) < 0)
1500 goto error;
1502 if (compute_weights(graph, &c) < 0)
1503 goto error;
1505 for (;;) {
1506 i = find_proximity(graph, &c);
1507 if (i < 0)
1508 goto error;
1509 if (i >= graph->n_edge)
1510 break;
1511 if (merge_clusters_along_edge(ctx, graph, i, &c) < 0)
1512 goto error;
1515 if (extract_clusters(ctx, graph, &c) < 0)
1516 goto error;
1518 node = finish_bands_clustering(node, graph, &c);
1520 clustering_free(ctx, &c);
1521 return node;
1522 error:
1523 clustering_free(ctx, &c);
1524 return isl_schedule_node_free(node);