2 * Copyright 2015 Sven Verdoolaege
4 * Use of this software is governed by the MIT license
6 * Written by Sven Verdoolaege
9 #include "isl_map_private.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"
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
)
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
,
48 return isl_stat_error
;
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
;
60 /* Free all memory allocated for "c".
62 static void clustering_free(isl_ctx
*ctx
, struct isl_clustering
*c
)
67 for (i
= 0; i
< c
->n
; ++i
)
68 isl_sched_graph_free(ctx
, &c
->scc
[i
]);
71 for (i
= 0; i
< c
->n
; ++i
)
72 isl_sched_graph_free(ctx
, &c
->cluster
[i
]);
76 free(c
->scc_in_merge
);
79 /* Should we refrain from merging the cluster in "graph" with
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
];
123 prox
= is_non_empty_proximity(edge
);
130 if (bad_cluster(&c
->scc
[edge
->src
->scc
]) ||
131 bad_cluster(&c
->scc
[edge
->dst
->scc
]))
133 dist
= c
->scc_cluster
[edge
->dst
->scc
] -
134 c
->scc_cluster
[edge
->src
->scc
];
137 weight
= edge
->weight
;
138 if (best
< graph
->n_edge
) {
139 if (best_weight
> weight
)
141 if (best_weight
== weight
&& best_dist
<= dist
)
146 best_weight
= weight
;
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
;
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
],
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
;
221 for (i
= 0; i
< c
->n
; ++i
)
222 c
->scc_in_merge
[i
] = 0;
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
);
236 isl_die(ctx
, isl_error_internal
,
237 "expecting at least two nodes in component",
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
);
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
)
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
)
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
);
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
)
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
) {
307 if (!c
->scc_in_merge
[i
])
309 if (c
->scc_cluster
[i
] != i
)
311 space
= cluster_space(&c
->scc
[i
], i
);
312 domain
= isl_union_set_add_set(domain
, isl_set_universe(space
));
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
)
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
) {
334 if (!c
->scc_in_merge
[i
])
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
) {
343 struct isl_sched_node
*node
= &c
->scc
[i
].node
[j
];
345 ma
= isl_sched_node_extract_partial_schedule_multi_aff(
347 ma
= isl_multi_aff_set_tuple_id(ma
, isl_dim_out
,
349 map
= isl_map_from_multi_aff(ma
);
350 cluster_map
= isl_union_map_add_map(cluster_map
, 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
;
370 for (t
= isl_edge_first
; t
<= isl_edge_last
; ++t
) {
371 if (t
== isl_edge_condition
||
372 t
== isl_edge_conditional_validity
)
374 if (!isl_sched_edge_has_type(edge
, t
))
376 sc
= isl_schedule_constraints_add(sc
, t
,
377 isl_union_map_copy(umap
));
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
))
398 if (t
== isl_edge_condition
)
399 tagged
= isl_union_map_copy(edge
->tagged_condition
);
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
);
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
)
434 isl_union_map
*umap1
, *umap2
;
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
);
448 (!isl_sched_edge_is_condition(edge
) &&
449 !isl_sched_edge_is_conditional_validity(edge
)))
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
);
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
)
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
])
485 if (!scc_in_merge
[edge
->dst
->scc
])
487 sc
= collect_edge_constraints(edge
, cluster_map
, 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
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
;
512 domain
= collect_domain(ctx
, graph
, c
);
513 sc
= isl_schedule_constraints_on_domain(domain
);
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
);
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
)
543 for (i
= 0; i
< c
->n
; ++i
) {
545 struct isl_sched_graph
*scc
;
547 if (!c
->scc_in_merge
[i
])
550 nvar
= scc
->n_total_row
- scc
->band_start
;
553 for (j
= 0; j
< scc
->n
; ++j
) {
554 struct isl_sched_node
*node
= &scc
->node
[j
];
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
)
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
)
583 for (i
= 0; i
< c
->n
; ++i
) {
585 struct isl_sched_graph
*scc
;
587 if (!c
->scc_in_merge
[i
])
590 nvar
= scc
->n_total_row
- scc
->band_start
;
593 for (j
= 0; j
< scc
->n
; ++j
) {
594 struct isl_sched_node
*node
= &scc
->node
[j
];
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
) {
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
);
633 return isl_stat_error
;
634 maxvar
= limit_maxvar_to_slack(merge_graph
->maxvar
, max_slack
, c
);
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;
642 merge_graph
->maxvar
= maxvar
;
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
)
655 for (i
= graph
->band_start
; i
< graph
->n_total_row
; ++i
)
656 if (!graph
->node
[0].coincident
[i
])
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
)
678 for (i
= 0; i
< c
->n
; ++i
) {
679 if (!c
->scc_in_merge
[i
])
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
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
;
713 isl_multi_aff
*ma
, *ma2
;
715 scc_node
= isl_sched_graph_find_node(ctx
, &c
->scc
[node
->scc
],
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",
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
,
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
,
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
)
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
);
759 if (bounded
< 0 || !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
);
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
)
778 n
= isl_set_dim(set
, isl_dim_set
);
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
);
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
)
798 set
= isl_map_domain(isl_map_copy(map
));
799 single
= has_single_value(set
, pos
);
802 if (single
< 0 || single
)
805 set
= isl_map_range(isl_map_copy(map
));
806 single
= has_single_value(set
, pos
);
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
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
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
)
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
);
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
);
870 if (edge
->weight
>= 0)
871 bounded
= isl_bool_false
;
875 singular_i
= has_singular_src_or_dst(map
, i
);
880 bounded
= isl_bool_false
;
883 if (!bounded
&& i
>= n
&& edge
->weight
>= 0)
884 edge
->weight
-= graph
->max_weight
+ 1;
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
)
912 for (i
= 0; i
< graph
->n_edge
; ++i
) {
913 struct isl_sched_edge
*edge
= &graph
->edge
[i
];
916 if (!isl_sched_edge_is_proximity(edge
))
918 if (!c
->scc_in_merge
[edge
->src
->scc
])
920 if (!c
->scc_in_merge
[edge
->dst
->scc
])
922 if (c
->scc_cluster
[edge
->dst
->scc
] ==
923 c
->scc_cluster
[edge
->src
->scc
])
925 bounded
= has_bounded_distances(ctx
, edge
, graph
, c
,
927 if (bounded
< 0 || 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
)) {
965 ok
= ok_to_merge_coincident(c
, merge_graph
);
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
983 static __isl_give isl_mat
*node_transformation(isl_ctx
*ctx
,
984 struct isl_sched_node
*t_node
, struct isl_sched_node
*node
,
989 isl_size n_row
, n_col
;
992 n_param
= node
->nparam
;
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)
998 t
= isl_mat_alloc(ctx
, n_row
, n_col
);
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
);
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
)
1030 start
= graph
->band_start
;
1031 n
= graph
->n_total_row
- start
;
1033 n_new
= isl_mat_rows(t_node
->sched
);
1035 return isl_stat_error
;
1036 for (i
= 0; i
< graph
->n
; ++i
) {
1037 struct isl_sched_node
*node
= &graph
->node
[i
];
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
);
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
;
1051 graph
->n_total_row
+= n_new
;
1052 graph
->n_row
+= n_new
;
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
)
1074 for (i
= 0; i
< c
->n
; ++i
) {
1075 struct isl_sched_node
*node
;
1077 if (!c
->scc_in_merge
[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
);
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
;
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 };
1135 if (init_merge_graph(ctx
, graph
, c
, &merge_graph
) < 0)
1138 if (isl_sched_graph_compute_maxvar(&merge_graph
) < 0)
1140 if (adjust_maxvar_to_slack(ctx
, &merge_graph
,c
) < 0)
1142 if (isl_schedule_node_compute_wcc_band(ctx
, &merge_graph
) < 0)
1144 merged
= ok_to_merge(ctx
, graph
, c
, &merge_graph
);
1145 if (merged
&& merge(ctx
, c
, &merge_graph
) < 0)
1148 isl_sched_graph_free(ctx
, &merge_graph
);
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
)
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
])
1178 if (!scc_in_merge
[edge
->dst
->scc
])
1182 if (merge_edge
->weight
>= 0 && edge
->weight
< 0) {
1183 merge_edge
->weight
-= graph
->max_weight
+ 1;
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
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
)
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
;
1221 merged
= try_merge(ctx
, graph
, c
);
1223 return isl_stat_error
;
1224 if (!merged
&& edge_weight
== graph
->edge
[edge
].weight
)
1225 graph
->edge
[edge
].no_merge
= 1;
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
)
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
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
)
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
;
1285 for (i
= 0; i
< graph
->n
; ++i
) {
1289 if (graph
->node
[i
].cluster
!= pos
)
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
;
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
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
],
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
)
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
)
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
;
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
)
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
;
1390 isl_size n_in
, n_out
, n
;
1392 prox
= is_non_empty_proximity(edge
);
1394 return isl_stat_error
;
1397 if (bad_cluster(&c
->scc
[edge
->src
->scc
]) ||
1398 bad_cluster(&c
->scc
[edge
->dst
->scc
]))
1400 if (c
->scc_cluster
[edge
->dst
->scc
] ==
1401 c
->scc_cluster
[edge
->src
->scc
])
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
);
1425 return isl_stat_error
;
1428 if (edge
->weight
> graph
->max_weight
)
1429 graph
->max_weight
= edge
->weight
;
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
)
1451 isl_union_set_list
*filters
;
1453 if (graph
->scc
== 1)
1454 return isl_schedule_node_compute_finish_band(node
,
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
,
1467 node
= isl_schedule_node_grandparent(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
)
1494 struct isl_clustering c
;
1497 ctx
= isl_schedule_node_get_ctx(node
);
1499 if (clustering_init(ctx
, &c
, graph
) < 0)
1502 if (compute_weights(graph
, &c
) < 0)
1506 i
= find_proximity(graph
, &c
);
1509 if (i
>= graph
->n_edge
)
1511 if (merge_clusters_along_edge(ctx
, graph
, i
, &c
) < 0)
1515 if (extract_clusters(ctx
, graph
, &c
) < 0)
1518 node
= finish_bands_clustering(node
, graph
, &c
);
1520 clustering_free(ctx
, &c
);
1523 clustering_free(ctx
, &c
);
1524 return isl_schedule_node_free(node
);